pari-2.11.2/0000755000175000017500000000000013461316051011156 5ustar billbillpari-2.11.2/COPYING0000644000175000017500000004325412141040641012212 0ustar billbill GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. pari-2.11.2/examples/0000755000175000017500000000000013461316051012774 5ustar billbillpari-2.11.2/examples/bench.gp0000644000175000017500000000022212314242551014376 0ustar billbill{ u=v=p=q=1; for (k=1, 2000, [u,v] = [v,u+v]; p *= v; q = lcm(q,v); if (k%50 == 0, print(k, " ", log(p)/log(q)) ) ) } pari-2.11.2/examples/pari-mt.c0000644000175000017500000000276113036414401014513 0ustar billbill#include /* Include PARI headers */ GEN my_worker(GEN d, long l) { return l==1 ? Z_factor(d) : det(d); } int main(void) { long i; GEN M,N1,N2, F1,F2,D; GEN input, output; struct pari_mt pt; GEN done, worker; long workid, pending; entree ep_worker={"_worker",0,(void*)my_worker,14,"GL",""}; /* Initialize the main PARI stack and global objects (gen_0, etc.) Postpone initialization of parallelism */ pari_init_opts(8000000,500000,INIT_JMPm | INIT_SIGm | INIT_DFTm | INIT_noIMTm); /* Add my_worker function to gp */ pari_add_function(&ep_worker); /* Initialize parallelism, now that my_worker is registered */ pari_mt_init(); /* Compute in the main PARI stack */ N1 = addis(int2n(256), 1); /* 2^256 + 1 */ N2 = subis(int2n(193), 1); /* 2^193 - 1 */ M = mathilbert(80); /* Create input and output vectors */ input = mkvec3(N1,N2,M); output = cgetg(4,t_VEC); /* Initialize parallel evaluation of my_worker */ worker = strtofunction("_worker"); mt_queue_start(&pt, worker); for (i=1; i<=3 || pending; i++) { /* submit job (input) */ mt_queue_submit(&pt, i, i<=3? mkvec2(gel(input,i),i<=2 ? gen_1: gen_2): NULL); /* get result (output) */ done = mt_queue_get(&pt, &workid, &pending); if (done) gel(output,workid) = done; } /* end parallelism */ mt_queue_end(&pt); F1 = gel(output,1); F2 = gel(output,2); D = gel(output,3); pari_printf("F1=%Ps\nF2=%Ps\nlog(D)=%Ps\n", F1, F2, glog(D,3)); pari_close(); return 0; } pari-2.11.2/examples/openmp.c0000644000175000017500000000240511636712103014437 0ustar billbill#include /* Include PARI headers */ #include /* Include OpenMP headers */ #define MAXTHREADS 3 /* Max number of parallel threads */ int main(void) { GEN M,N1,N2, F1,F2,D; struct pari_thread pth[MAXTHREADS]; int numth = omp_get_max_threads(), i; /* Initialise the main PARI stack and global objects (gen_0, etc.) */ pari_init(4000000,500000); if (numth > MAXTHREADS) { numth = MAXTHREADS; omp_set_num_threads(numth); } /* Compute in the main PARI stack */ N1 = addis(int2n(256), 1); /* 2^256 + 1 */ N2 = subis(int2n(193), 1); /* 2^193 - 1 */ M = mathilbert(80); /*Allocate pari thread structures */ for (i = 1; i < numth; i++) pari_thread_alloc(&pth[i],4000000,NULL); #pragma omp parallel { int this_th = omp_get_thread_num(); if (this_th) (void)pari_thread_start(&pth[this_th]); #pragma omp sections { #pragma omp section { F1 = factor(N1); } #pragma omp section { F2 = factor(N2); } #pragma omp section { D = det(M); } } /* omp sections */ if (this_th) pari_thread_close(); } /* omp parallel */ pari_printf("F1=%Ps\nF2=%Ps\nlog(D)=%Ps\n", F1, F2, glog(D,3)); for (i = 1; i < numth; i++) pari_thread_free(&pth[i]); return 0; } pari-2.11.2/examples/rho.gp0000644000175000017500000000144111636712103014114 0ustar billbillrho1(n)= { my(x = 2,y = 5); while(gcd(y-x,n) == 1, x = (x^2+1)%n; y = (y^2+1)%n; y = (y^2+1)%n ); gcd(n, y-x); } rho2(n)= { my(m = rho1(n)); if (isprime(m), print(m), rho2(m)); if (isprime(n/m), print(n/m), rho2(n/m)); } rho(n)= { my(m = factor(n,0)); print(m); m = m[,1]; n = m[#m]; if (!isprime(n), rho2(n)); } rhobrent(n)= { my(x,y,x1,k,l,p,c,g); x1 = x = y = 2; k = l = p = 1; c = 0; while (1, x=(x^2+1)%n; p=(p*(x1-x))%n; c++; if (c==20, if (gcd(p,n)>1, break); y = x; c = 0 ); k--; if (!k, if (gcd(p,n)>1, break); x1 = x; k = l; l <<= 1; for (j=1,k, x = (x^2+1)%n); y = x; c = 0 ) ); until (g != 1, y = (y^2+1)%n; g = gcd(x1-y,n) ); if (g==n, error("algorithm fails")); g; } pari-2.11.2/examples/cl.gp0000644000175000017500000000525512314242551013730 0ustar billbillrgcd(a,b)= { [a,b] = [abs(a), abs(b)]; while (b > 0.01, [a,b] = [b,a%b]); a; } global(nf, km, m, clh, R, areg, re, res, mreg); f(a,b, nf,v,ind)= { my(u, vreg); my(n = idealnorm(nf, a + b*variable(nf.pol))); my(mv = vectorv(#v)); forprime (p=2, #ind, my (l = valuation(n,p)); if (l, my(cp, j = ind[p]); n /= p^l; cp = v[j][2]; while((a+b*cp)%p, j++; cp = v[j][2] ); mv[j] = l ) ); if (n!=1, return); my (r1 = nf.sign[1]); /* found a relation */ vreg = vectorv(#re,j, u = a+b*re[j]; if (j<=r1, abs(u), norm(u)) ); mreg = concat(mreg, log(vreg)); m = concat(m, mv); areg = concat(areg, a+b*t); print1("(" res++ ": " a "," b ")"); } clareg(pol, plim=19, lima=50, extra=5)= { my(coreg,lireg,r1,ind,fa,co,a,b,mh,ms,mhs,mregh); nf=nfinit(pol); pol=nf.pol; re = nf.roots; r1=nf.sign[1]; if (nf.index > 1, /* power basis <==> index = 1 */ error("sorry, the case 'index>1' is not implemented") ); printf("discriminant = %s, signature = %s\n", nf.disc, nf.sign); lireg = sum(i=1,2, nf.sign[i]); /* r1 + r2 */ ind=vector(plim); v=[]; forprime(p=2,plim, my (w = factormod(pol,p)); my (e = w[,2]); my (find = 0); for(l=1,#e, fa = lift(w[l,1]); if (poldegree(fa) == 1, if (!find, find=1; ind[p]=#v+1); v = concat(v, [[p,-polcoeff(fa,0),e[l]]]) ) ) ); co = #v+extra; res=0; print("need ", co, " relations"); areg=[]~; mreg = m = [;]; a=1; b=1; f(0,1, nf,v,ind); while (reslima, b++; a=1) ); print(" "); mh=mathnf(m); ms=matsize(mh); if (ms[1]!=ms[2], print("not enough relations for class group: matrix size = ",ms); return ); mhs = matsnf(mh,4); clh = prod(i=1,#mhs, mhs[i]); printf("class number = %s, class group = %s\n", clh, mhs); areg=Mat(areg); km=matkerint(m); mregh=mreg*km; if (lireg==1, R = 1 , coreg = #mregh; if (coreg < lireg-1, print("not enough relations for regulator: matsize = ", matsize(mregh)); R = "(not given)"; , mreg1 = mregh[1 .. lireg-1, ]; R = 0; for(j=lireg-1,coreg, a = matdet(mreg1[, j-lireg+2 .. j]); R = rgcd(a,R) ) ) ); print("regulator = " R); } check(lim=200) = { my(r1,r2,pol,z,Res,fa); [r1,r2] = nf.sign; pol = nf.pol; z = 2^r1 * (2*Pi)^r2 / sqrt(abs(nf.disc)) / nfrootsof1(nf)[1]; Res = 1.; \\ Res (Zeta_K,s=1) ~ z * h * R forprime (q=2,lim, fa = factormod(pol,q,1)[,1]; Res *= (q-1)/q / prod(i=1, #fa, 1 - q^(-fa[i])) ); z * clh * R / Res; } fu() = vector(#km, k, factorback(concat(areg, km[,k]))); pari-2.11.2/examples/taylor.gp0000644000175000017500000000340613326135265014647 0ustar billbill\\ adapted from an original idea by Ilya Zakharevich \\ generate an RGB color triple from a "magnitude" between 0 and 255 \\ (low = close to a cold blue, high = close to a hot red). \\ To generate simple colormaps. rgb(mag) = { my(x = mag/255., B, G, R); B = min(max(4*(0.75-x), 0), 1); R = min(max(4*(x-0.25), 0), 1); G = min(max(4*abs(x-0.5)-1, 0), 1); return (floor([R, G, B]*255)); } default(graphcolormap, concat(["white","black","blue"], vector(25,i,rgb(10*i)))); default(graphcolors, vector(25,i,i+2)); \\ plot Taylor polynomials of f, \\ of index first + i*step <= ordlim, for x in [xmin,xmax]. plot_taylor(f, xmin=-5, xmax=5, ordlim=16, first=1, step=1) = { my(T,s,t,w,h,dw,dh,cw,ch,gh, extrasize = 0.6); my(Taylor_array); default(seriesprecision,ordlim+1); T = f('q); ordlim = (ordlim-first)\step + first; Taylor_array = vector(ordlim+1); forstep(i=ordlim+1, 1, -1, T += O('q^(1 + first + (i-1)*step)); Taylor_array[i] = truncate(T) ); t = plothsizes(); w=floor(t[1]*0.9)-2; dw=floor(t[1]*0.05)+1; cw=t[5]; h=floor(t[2]*0.9)-2; dh=floor(t[2]*0.05)+1; ch=t[6]; plotinit(2, w+2*dw, h+2*dh); plotinit(3, w, floor(h/1.2)); \\ few points (but Recursive!), to determine bounding box s = plotrecth(3, x=xmin,xmax, f(x), "Recursive|no_X_axis|no_Y_axis|no_Frame", 16); gh=s[4]-s[3]; plotinit(3, w, h); plotscale(3, s[1], s[2], s[3]-gh*extrasize/2, s[4]+gh*extrasize/2); plotrecth(3, x=xmin,xmax, subst(Taylor_array, 'q, x), "no_Rescale"); plotclip(3); plotcopy(3, 2, dw, dh); plotmove(2, floor(dw+w/2-15*cw), floor(dh/2)); plotstring(2, "Multiple Taylor Approximations"); plotdraw(2); } \p9 plot_taylor(sin) plot_taylor(exp,-3,3) plot_taylor(x->besselk(2,x), 1,5) plot_taylor(x->1/(1+x^2), -1.2,1.2) pari-2.11.2/examples/extgcd.c0000644000175000017500000000162112314242551014415 0ustar billbill#include /* GP;install("extgcd", "GG&&", "gcdex", "./libextgcd.so"); */ /* return d = gcd(a,b), sets u, v such that au + bv = gcd(a,b) */ GEN extgcd(GEN A, GEN B, GEN *U, GEN *V) { pari_sp av = avma; GEN ux = gen_1, vx = gen_0, a = A, b = B; if (typ(a) != t_INT) pari_err_TYPE("extgcd",a); if (typ(b) != t_INT) pari_err_TYPE("extgcd",b); if (signe(a) < 0) { a = negi(a); ux = negi(ux); } while (!gequal0(b)) { GEN r, q = dvmdii(a, b, &r), v = vx; vx = subii(ux, mulii(q, vx)); ux = v; a = b; b = r; } *U = ux; *V = diviiexact( subii(a, mulii(A,ux)), B ); gerepileall(av, 3, &a, U, V); return a; } int main() { GEN x, y, d, u, v; pari_init(1000000,2); printf("x = "); x = gp_read_stream(stdin); printf("y = "); y = gp_read_stream(stdin); d = extgcd(x, y, &u, &v); pari_printf("gcd = %Ps\nu = %Ps\nv = %Ps\n", d, u, v); pari_close(); return 0; } pari-2.11.2/examples/lucas.gp0000644000175000017500000000012512314242551014430 0ustar billbilllucas(p) = { my(u = 4, q = 1<

\\ \\ Description: Compute class number of imaginary quadratic field \\ analytically \\ \\ File: classno.gp \\ \\ Original Author: Fernando Rodriguez-Villegas \\ villegas@math.utexas.edu \\ University of Texas at Austin \\ \\ Created: Fri Mar 26 1999 \\----------------------------------------------------------------- \\ Class number h(-d), -d fundamental. \\ Adjust constant cc for accuracy, default at least 9 decimal places. cl(d, cc = 5) = { my(q0,sd,c, s = 0, q = 1); if (!isfundamental(-d), error("Discriminant not fundamental")); sd = sqrt(d); q0 = exp(-2*Pi/sd); c = -4*Pi/sd; for (n=1, ceil(sd*cc), my(t); q *= q0; t = 1/(1-q); s += kronecker(-d,n) * q * t * (1 + c*t*n) ); if (d==3, s *= 3, d==4, s *= 2); -2*s; } pari-2.11.2/examples/thread.c0000644000175000017500000000336213201017466014413 0ustar billbill#include /* Include PARI headers */ #include /* Include POSIX threads headers */ void * mydet(void *arg) { GEN F, M; /* Set up thread stack and get thread parameter */ M = pari_thread_start((struct pari_thread*) arg); F = det(M); /* Free memory used by the thread */ pari_thread_close(); return (void*)F; } void * myfactor(void *arg) /* same principle */ { GEN F, N; N = pari_thread_start((struct pari_thread*) arg); F = factor(N); pari_thread_close(); return (void*)F; } int main(void) { GEN M,N1,N2, F1,F2,D; pthread_t th1, th2, th3; /* POSIX-thread variables */ struct pari_thread pth1, pth2, pth3; /* pari thread variables */ /* Initialise the main PARI stack and global objects (gen_0, etc.) */ pari_init(4000000,500000); /* Compute in the main PARI stack */ N1 = addis(int2n(256), 1); /* 2^256 + 1 */ N2 = subis(int2n(193), 1); /* 2^193 - 1 */ M = mathilbert(80); /* Sync with main thread */ pari_thread_sync(); /* Allocate pari thread structures */ pari_thread_alloc(&pth1,4000000,N1); pari_thread_alloc(&pth2,4000000,N2); pari_thread_alloc(&pth3,4000000,M); /* pthread_create() and pthread_join() are standard POSIX-thread * functions to start and get the result of threads. */ pthread_create(&th1,NULL, &myfactor, (void*)&pth1); pthread_create(&th2,NULL, &myfactor, (void*)&pth2); pthread_create(&th3,NULL, &mydet, (void*)&pth3); /* Start 3 threads */ pthread_join(th1,(void*)&F1); pthread_join(th2,(void*)&F2); pthread_join(th3,(void*)&D); /* Wait for termination, get the results */ pari_printf("F1=%Ps\nF2=%Ps\nlog(D)=%Ps\n", F1, F2, glog(D,3)); pari_thread_free(&pth1); pari_thread_free(&pth2); pari_thread_free(&pth3); /* clean up */ return 0; } pari-2.11.2/examples/squfof.gp0000644000175000017500000000205712314242551014632 0ustar billbill\\ return one non-trivial divisor of n > 1 using Shanks's SQUFOF squfof(n) = { my (p, D, d, a, b, b1, f, g, l, bb, gs); if (isprime(n) || issquare(n, &n), return(n)); p = factor(n,0)[1,1]; if (p != n, return(p)); if (n%4==1, D = n; d = sqrtint(D); b = (((d-1)\2) << 1) + 1 , D = n << 2; d = sqrtint(D); b = (d\2) << 1 ); f = Qfb(1, b, (b^2-D)>>2); l = sqrtint(d); q = []; lq = 0; i = 0; while (1, i++; f = qfbred(f, 3, D, d); a = component(f, 1); if (!(i%2) && issquare(a, &as), my(j = 1); while (j<=lq, if (as == q[j], break); j++ ); if (j > lq, break) ); if (abs(a) <= l, q = concat(q, abs(a)); print(q); lq++; ) ); print("i = ", i); print(f); bb = component(f, 2); gs = gcd([as, bb, D]); if (gs > 1, return (gs)); f = Qfb(as, -bb, as*component(f,3)); g = qfbred(f, 3, D, d); b = component(g, 2); until (b1 == b, b1 = b; g = qfbred(g, 3, D, d); b = component(g, 2); ); a = abs(component(g, 1)); if (a % 2, a, a>>1); } pari-2.11.2/examples/EXPLAIN0000644000175000017500000001111013036414401014005 0ustar billbillThis directory contains: * Inputrc: an example of .inputrc file for the readline library. * A generic Makefile for PARI programs, adapted to your system by Configure. * the C program extgcd.c using the Pari library described in Chapter 4 of the users' manual. To build it, run: make TARGET=extgcd * the C program minigp.c using the Pari library to implement a basic GP interpretor (Need readline). To build it, run make TARGET=minigp EXTRALIBS=-lreadline * the C program pari-mt.c using the Pari library interface for parallel computation. To build it, run make TARGET=pari-mt * the C program thread.c using the Pari library in a multi-threaded context, POSIX threads version, as described in Appendix D of the users' manual. This requires that PARI is Configured with --enable-tls. To build it, run make TARGET=thread EXTRALIBS=-lpthread * the C program openmp.c using the Pari library in a multi-threaded context, OpenMP version, as described in Appendix D of the users' manual. This requires that PARI is Configured with --enable-tls. To build it, run make TARGET=openmp EXTRACFLAGS=-fopenmp * Several examples of complete GP programs. The rest of this file gives a brief description of these programs. They should be read into GP by the command \r file. -- bench.gp: This program computes the first 1000 terms of the Fibonacci sequence, the product p of successive terms, and the lowest common multiple q. It outputs the ratio log(p)/log(q) every 50 terms, which tends to Pi^2/6 as k tends to infinity. The name bench.gp comes from the fact that this program is one (among many) examples where GP/PARI performs orders of magnitude faster than systems such as Maple or Mathematica. (Try it!) -- cl.gp: Written entirely in the GP language without using bnfinit, the programs included in this file computes the class number, the structure of the class group and a system of fundamental units of a general number field. It sometimes fail to give an answer and works only if nfinit finds a power basis. Evidently it is less powerful, less reliable and much slower than bnfinit, but it is given as an example of a sophisticated use of GP. The first thing to do is to call clareg(pol, {limp=19},{lima=50},{extra=5}) where pol is the monic irreducible polynomial defining the number field, limp is the prime factor base limit (try values between 19 and 113), lima is another search limit (try 50 or 100) and extra is the number of desired extra relations (try 2 to 10). Default values are provided, so that you need only supply pol. The program prints the number of relations that it needs, and tries to find them. If you see that it slows down too much before succeeding, abort and try other values. If it succeeds, it will print the class number, class group and regulator. These are tentative values. Then use check({lim = 100}) to check if the value is consistent with the value of the L-series (the value returned should be close to 1). Finally, fu() (no parameters) returns a family of units which generates the unit group (you must extract a system of fundamental units yourself). -- classno.gp: a simple function to compute analytically the class number of imaginary quadratic fields (written by Fernando Rodriguez Villegas) -- contfrac.gp: period(D) computes period of continued fraction for sqrt(D) [slower than quadregulator, which does a bit more work, but is written in C!] (written by Igor Schein) -- lucas.gp: The function lucas(p) defined in this file performs the Lucas-Lehmer primality test on the Mersenne number 2^p-1. If the result is 1, the Mersenne number is prime, otherwise not. -- rho.gp: a simple implementation of Pollard's rho method. The function rho(n) outputs the complete factorization of n in the same format as factor. -- squfof.gp: This defines a function squfof of a positive integer variable n, which may allow you to factor the number n. SQUFOF is a nice factoring method invented in the 70's by Dan Shanks for factoring integers, and is reasonably fast for numbers having up to 15 or 16 digits. The squfof program given here is a crude implementation, which prints out some intermediate information as it goes along. The final result is some factor of the number to be factored. -- taylor.gp: the function plot_taylor(f,xmin,xmax, ordlim, first,step) plots the Taylor polynomials T_i (truncated series expansion of order i) of the function f in the interval [xmin,xmax]; i goes from first to ordlim in increments of steps. Sensible default values are provided for all arguments (adapted from an original idea by Ilya Zakharevich). A few examples are provided, together with a simple colormap generator pari-2.11.2/examples/contfrac.gp0000644000175000017500000000036011636712103015122 0ustar billbillperiod(D) = { my(u,v,j,r,s); if (type(D) != "t_INT" || D < 2, return(-1)); u = sqrtint(D); v = D-u^2; if (!v, return(0)); s = v; r = u; j = 0; until (u == r && v == s, u = (r+u)\v * v - u; v = (D-u^2)\v; j++; ); j; } pari-2.11.2/examples/minigp.c0000644000175000017500000000275213201017466014431 0ustar billbill#include #include #include #include #include jmp_buf env; int gp_is_interactive(void) { return pari_infile == stdin; } void gp_err_recover(long numerr) { longjmp(env, numerr); } void gp_quit(long exitcode) { exit(exitcode); } entree functions_gp[]={ {"quit",0,(void*)gp_quit,11,"vD0,L,","quit({status = 0}): quit, return to the system with exit status 'status'."}, {NULL,0,NULL,0,NULL,NULL}}; #define col(a) term_get_color(NULL, a) int main(int argc, char **argv) { pari_init(8000000,500000); pari_add_module(functions_gp); cb_pari_err_recover = gp_err_recover; cb_pari_is_interactive = gp_is_interactive; cb_pari_quit = gp_quit; sd_colors("lightbg",d_INITRC); pari_printf("Welcome to minigp!\n"); gp_load_gprc(); (void)setjmp(env); while(1) { GEN z; const char *prompt = gp_format_prompt(GP_DATA->prompt); char *in = readline(prompt); pari_timer T; long time; if (!in) break; if (!*in) continue; add_history(in); gp_echo_and_log(prompt,in); timer_start(&T); z = gp_read_str(in); time = timer_delay(&T); pari_add_hist(z, time); if (z != gnil && in[strlen(in)-1] != ';') { pari_printf("%s%%%lu = %s",col(c_HIST),pari_nb_hist(),col(c_OUTPUT)); output(z); pari_puts(col(c_NONE)); } if (GP_DATA->chrono && time) pari_printf("time = %s\n", gp_format_time(time) ); free(in); avma = pari_mainstack->top; } return 0; } pari-2.11.2/Configure0000755000175000017500000001406013201017466013026 0ustar billbill#! /bin/sh # # This file is part of the PARI/GP package. # # PARI/GP is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation. It is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY WHATSOEVER. # # Check the License for details. You should have received a copy of it, along # with the package; see the file 'COPYING'. If not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Configuration file for GP/PARI. Run Configure --help for Usage. # # Perl's Configure and GNU autoconfig were of much help in writing these files. # $Id$ TOP=`pwd` MAKE=${MAKE:-make} config_dir=config data_dir=data doc_dir=doc examples_dir=examples misc_dir=misc src_dir=src desc_dir=src/desc case "$RUNTEST" in /*);; */*) RUNTEST="$TOP/$RUNTEST";; esac cd $config_dir # Process options, initialize . ./get_head # do we need head -n # or head -# ? . ./version echo "Configuring pari-$pari_release_verbose $patchlevel_verbose" command_line0="$0 $@" . ./get_config_options ####################### CONFIGURE - SHELL ################################### . ./get_nl # how to get echo without \n ? (for config questions) . ./get_PATH # We might need the following : echo Looking for some tools first ... _tools_list='gzip cc gcc ld perl zcat' pathspace=`echo $PATH | sed -e "s/$dir_sep/ /g" | sed -e 's,\\\\,/,g'` for file in $_tools_list; do x=`./locate $file '' $pathspace` eval $file=$x case $x in # support also DOS filesystems (hard drive prepended) ?:/*|/*) echo ..."$file is $x";; *) echo ..."I could not find $file." >&2;; esac done if test -z "$zcat" -a -n "$gzip"; then zcat="$gzip -dc"; fi ####################### CONFIGURE - ARCHITECTURE ############################ . ./get_archos # arch, osname config_log="$TOP/config-$arch-$osname$$.log" cat > $config_log<< EOT This file contains messages produced while configuring pari-$pari_release $patchlevel_verbose to aid debugging if Configure makes a mistake. Command line was > $command_line0 EOT exec 5>> $config_log ####################### CONFIGURE - COMPILATION ############################# # $_cc_list (includes 'optimization'), extraflag . ./get_cc # . ./get_mt # doubleformat, sizeof_long . ./get_double_format # asmarch, pretty . ./get_kernel # _dl_list, DLCFLAGS, update CFLAGS . ./get_dlcflags # $_ld_list . ./get_ld # $_dlld_list . ./get_dlld # $_perl_list . ./get_perl ####################### CONFIGURE - LIBC #################################### . ./get_libc # $_has_list, RT_LIBS, DL_LIBS ####################### CONFIGURE - LIBRARIES ############################### # Looking for libraries: gmp, X11, fltk, Qt, readline echo Checking for optional libraries and headers... # $_gmp_list if test "$kernlvl1" = "gmp"; then . ./get_gmp fi # $_graphic_list . ./get_graphic_lib # $_readline_list (includes 'readline') case "$without_readline" in yes);; *) . ./get_readline esac ############################################################################# case $kernlvl1 in gmp) libpari_base=pari-gmp;; none) libpari_base=pari;; esac case $enable_tls in yes) libpari_base="${libpari_base}-tls" esac if test `expr $VersionMinor % 2` = 0; then libpari_base=$libpari_base-$version fi ####################### CONFIGURE - MAKE #################################### . ./get_install # $_install_list . ./get_objdir # objdir, cdobjdir . ./get_static # static # For dynamic linking, before and after installing runpath=\"$libdir\" LDDYN="-lpari" # get_modld needs $includedir from get_install, static, and LDDYN . ./get_modld # $_modld_list # Which copy, SHELL ? case "$osname" in os2) ln_s=cp; make_sh=sh;; *) ln_s="ln -s"; make_sh="/bin/sh";; esac ####################### CONFIGURE - CLEANUP ################################# rm -f gmon.out # created by Configure -pg rm -f *.gcno *.gcda # created by Configure -gcov ####################### CONFIGURE - SPIT #################################### . ./get_tests #_test_list # Now spit out the results cat << EOT ========================================================================== EOT cd "$TOP" if test ! -d $objdir; then mkdir -p $objdir; fi rm -f $objdir/config.log; mv $config_log $objdir/config.log dflt_conf_file=$objdir/$dflt_conf_file cat > $dflt_conf_file << EOT # Config file for Pari $release -- $pretty EOT case "$osname" in os2|mingw) shell_q='"'; echo "shell_q='\"'" >> $dflt_conf_file;; *) shell_q="'"; echo "shell_q=\"'\"" >> $dflt_conf_file;; esac for variable in\ pari_release pari_release_verbose version libpari_base static objdir\ arch asmarch osname pretty\ kernlvl0 kernlvl1 RT_LIBS DL_LIBS MT_LIBS LIBS\ dir_sep runpath runpathprefix LDDYN RUNTEST\ ln_s make_sh\ sizeof_long doubleformat\ thread_engine enable_tls\ runtime_perl\ $_tools_list\ $_test_list\ $_install_list\ $_perl_list\ $_cc_list\ $_ld_list\ $_dl_list\ $_dlld_list\ $_graphic_list\ $_modld_list\ $_readline_list\ $_gmp_list\ $_has_list; do eval "echo $variable=\'"'$'"$variable\'" \>\> $dflt_conf_file done . $config_dir/extract_files # Building... cat << EOT ========================================================================== EOT if test -n "$tune"; then echo "Building and tuning PARI (this may take a while)" echo (cd $objdir; rm -f parilvl1.h pariinl.h;\ $MAKE tune && tune -t > tune.h.new && mv tune.h.new tune.h && cat tune.h\ && rm -f parilvl1.h pariinl.h && $MAKE gp) else echo $n "Shall we try to build pari $version.$patch ($status) now (y/n)? $c" dflt=n; rep='y n'; . $config_dir/myread fi mkobjdir=`$config_dir/objdir` cdobjdir= if test "$objdir" != "$mkobjdir"; then cdobjdir="cd $objdir; " fi case $ans in y) if (cd $objdir; $MAKE gp); then echo $n "Shall we install the files where they belong (y/n)? $c" dflt=n; rep='y n'; . $config_dir/myread case $ans in y) $MAKE install;; n) echo "Ok. Type \"${cdobjdir}make install\" when you are ready";; esac fi;; n) echo "Ok. Type \"${cdobjdir}make install\" when you are ready";; esac echo 'Bye !' pari-2.11.2/README0000644000175000017500000000670613326135265012055 0ustar billbillThis is PARI/GP, version 2.11.x (*). PARI/GP Number Theory-oriented Computer Algebra System Copyright (C) 2000-2018 The PARI Group, Bordeaux. ========================================================================== To get started, run cd doc; tex INSTALL.tex and have a look at the file INSTALL.dvi, extracted verbatim from Appendix A of the User Manual. (Or pdftex INSTALL.tex if PDF files are more convenient.) If you are in a hurry, look at the ASCII file 'INSTALL' but a lot of information is missing there. Once 'Configure' has been run, 'make doc' typesets separate user's manual for GP and libpari, a tutorial and reference card in directory doc. The file NEW contains new features with respect to previous stable versions. The file COMPAT warns about incompatible changes. See the files CHANGES* for a terse description of successive patches. For the adventurous: to check out bleeding-edge development versions of PARI/GP, see the file README-git. Afterwards, you're on your own. ========================================================================== There are three mailing lists devoted to the PARI/GP package, and most feedback should be directed to those. They are: * pari-announce: to announce major version changes. You can't write to this one, but you should probably subscribe. * pari-dev: for everything related to the development of PARI, including suggestions, technical questions, bug reports or patch submissions. * pari-users: for everything else. To subscribe, send empty messages respectively to pari-announce-request@pari.math.u-bordeaux.fr pari-users-request@pari.math.u-bordeaux.fr pari-dev-request@pari.math.u-bordeaux.fr with a Subject: containing the word "subscribe". If you are not a member of any of those lists and do not want to become one, you can write to us at pari@math.u-bordeaux.fr We may forward your mail to the lists above and will definitely try to correct faulty behaviour, if necessary. But we cannot promise that you will get an individual answer. Last but not least, PARI home page can be found at http://pari.math.u-bordeaux.fr/ Thanks for your support, and have fun ! ======================================================================== PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. (*) Version numbers have the shape: MAJOR.MINOR.patchlevel.status. The status increases through {alpha, beta, release}. New features are introduced during the `alpha' phase, tested during `beta', and declared stable when `release' is reached. The MAJOR version number will not change for a while. The MINOR version number increases by 2 when a new status cycle starts (as soon as a 'release' version is out): odd numbers are reserved for 'released' versions, even ones for alpha/beta phase. The patchlevel goes up each time we feel an upgrade is necessary (improvement or bugfix). 'Release' versions may be updated with further patchlevels if important bugs need to be fixed before the next cycle reaches completion. pari-2.11.2/doc/0000755000175000017500000000000013461316051011723 5ustar billbillpari-2.11.2/doc/appa.tex0000644000175000017500000006636313326135265013412 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \appendix{Installation Guide for the UNIX Versions} \def\tocwrite#1{} \section{Required tools} Compiling PARI requires an \kbd{ANSI C} or a \kbd{C++} compiler. If you do not have one, we suggest that you obtain the \kbd{gcc/g++} compiler. As for all GNU software mentioned afterwards, you can find the most convenient site to fetch \kbd{gcc} at the address $$\url{http://www.gnu.org/order/ftp.html}$$ % (On Mac OS X, this is also provided in the \kbd{Xcode} tool suite; or the lightweight ``Command-line tools for \kbd{Xcode}''.) You can certainly compile PARI with a different compiler, but the PARI kernel takes advantage of optimizations provided by \kbd{gcc}. This results in at least 20\% speedup on most architectures. \misctitle{Optional libraries and programs} The following programs and libraries are useful in conjunction with \kbd{gp}, but not mandatory. In any case, get them before proceeding if you want the functionalities they provide. All of them are free. The download page on our website $$ \url{http://pari.math.u-bordeaux.fr/download.html} $$ contains pointers on how to get these. \item GNU \kbd{MP} library. This provides an alternative multiprecision kernel, which is faster than PARI's native one, but unfortunately binary incompatible, so the resulting PARI library SONAME is libpari-gmp. \item GNU \kbd{readline} library. This provides line editing under \kbd{gp}, an automatic context-dependent completion, and an editable history of commands. \item GNU \kbd{emacs} and the \tet{PariEmacs} package. The \kbd{gp} calculator can be run in an Emacs buffer, with all the obvious advantages if you are familiar with this editor. Note that \kbd{readline} is still useful in this case since it provides a better automatic completion than is provided by Emacs's GP-mode. \item GNU \kbd{gzip/gunzip/gzcat} package enables \kbd{gp} to read compressed data. \item \kbd{perl} provides extended online help (full text from the manual) about functions and concepts. The script handling this online help can be used under \kbd{gp} or independently. \section{Compiling the library and the \kbd{gp} calculator} \subsec{Basic configuration} Type \kbd{./Configure} \noindent in the toplevel directory. This attempts to configure PARI/GP without outside help. Note that if you want to install the end product in some nonstandard place, you can use the \kbd{--prefix} option, as in \kbd{./Configure --prefix=}\var{/an/exotic/directory} \noindent (the default prefix is \kbd{/usr/local}). For example, to build a package for a Linux distribution, you may want to use \kbd{./Configure --prefix=/usr} This phase extracts some files and creates a \var{build directory}, names \kbd{O}\var{osname}\kbd{-}\var{arch}, where the object files and executables will be built. The \var{osname} and \var{arch} components depends on your architecture and operating system, thus you can build PARI/GP for several different machines from the same source tree (the builds are independent and can be done simultaneously). Decide whether you agree with what \kbd{Configure} printed on your screen, in particular the architecture, compiler and optimization flags. Look for messages prepended by \kbd{\#\#\#}, which report genuine problems. Look especially for the \kbd{gmp}, \kbd{readline} and \kbd{X11} libraries, and the \kbd{perl} and \kbd{gunzip} (or \kbd{zcat}) binaries. If anything should have been found and was not, consider that \kbd{Configure} failed and follow the instructions in section~3. The \kbd{Configure} run creates a file \kbd{config.log} in the build directory, which contains debugging information --- in particular, all messages from compilers --- that may help diagnose problems. This file is erased and recreated from scratch each time \kbd{Configure} is run. \subsec{Advanced configuration} \kbd{Configure} accepts many other flags, and you may use any number of them to build quite a complicated configuration command. See \kbd{Configure --help} for a complete list. In particular, there are sets of flags related to GNU MP (\kbd{--with-gmp*}) and GNU readline library (\kbd{--with-readline*}). Here, we focus on the non-obvious ones: \kbd{--tune}: fine tunes the library for the host used for compilation. This adjusts thresholds by running a large number of comparative tests and creates a file \kbd{tune.h} in the build directory, that will be used from now on, overriding the ones in \kbd{src/kernel/none/} and \kbd{src/kernel/gmp/}. It will take a while: about 30 minutes. Expect a small performance boost, perhaps a 10\% speed increase compared to default settings. If you are using GMP, tune it first, then PARI. Make sure you tune PARI on the machine that will actually run your computations. Do not use a heavily loaded machine for tunings. You may speed up the compilation by using a parallel make: \bprog env MAKE="make -j4" Configure --tune @eprog \kbd{--graphic=}\var{lib}: enables a particular graphic library. The default is \kbd{X11} on most platforms, but PARI can use \kbd{Qt}, \kbd{fltk} or \kbd{win32} (GDI), or even dump a \kbd{ps} or \kbd{svg} file and open it using an external viewer. \kbd{--time=}\var{function}: chooses a timing function. The default usually works fine, however you can use a different one that better fits your needs. PARI can use \kbd{getrusage}, \kbd{clock\_gettime}, \kbd{times} or \kbd{ftime} as timing functions. (Not all timing functions are available on all platforms.) The three first functions give timings in terms of CPU usage of the current task, approximating the complexity of the algorithm. The last one, \kbd{ftime}, gives timings in terms of absolute (wall-clock) time. Moreover, the \kbd{clock\_gettime} function is more precise, but much slower (at the time of this writing), than \kbd{getrusage} or \kbd{times}. \kbd{--with-runtime-perl=}\var{perl}: absolute path to the runtime \kbd{perl} binary to be used by the \kbd{gphelp} and \kbd{tex2mail} scripts. Defaults to the path found by \kbd{Configure} on the build host (usually \kbd{/usr/bin/perl}). For cross-compiling builds, when the target and build hosts have mismatched configurations; suggested values are \kbd{/usr/bin/env perl}: the first \kbd{perl} executable found in user's \kbd{PATH}, \kbd{/usr/bin/perl}: \kbd{perl}'s standard location. The remaining options are specific to parallel programming. We provide an \emph{Introduction to parallel GP programming} in the file \kbd{doc/parallel.dvi}, and to multi-threaded \kbd{libpari} programs in Appendix~D. Beware that these options change the library ABI: \kbd{--mt=}\var{engine}: specify the engine used for parallel computations. Supported value are \item single: (default) no parallellism. \item pthread: use POSIX threads. This is well-suited for multi-core systems. Setting this option also set \kbd{--enable-tls}, see below. This option requires the pthread library. For benchmarking, it is often useful to set \kbd{--time=ftime} so that GP report wall-clock instead of the sum of the time spent by each thread. \item mpi: use the MPI interface to parallelism. This allows to take advantage of clusters using MPI. This option requires a MPI library. It is usually necessary to set the environment variable \kbd{CC} to \kbd{mpicc}. \kbd{--enable-tls}: build the thread-safe version of the library. Implied by \kbd{--mt=pthread}. This tends to slow down the \emph{shared} library \kbd{libpari.so} by about $15\%$, so you probably want to use the static library \kbd{libpari.a} instead. \subsec{Compilation} To compile the \kbd{gp} binary and build the documentation, type \kbd{make all} \noindent To only compile the \kbd{gp} binary, type \kbd{make gp} \noindent in the toplevel directory. If your \kbd{make} program supports parallel make, you can speed up the process by going to the build directory that \kbd{Configure} created and doing a parallel make here, for instance \kbd{make -j4} with GNU make. It should even work from the toplevel directory. \subsec{Basic tests} To test the binary, type \kbd{make bench}. This runs a quick series of tests, for a few seconds on modern machines. In many cases, this will also build a different binary (named \kbd{gp-sta} or \kbd{gp-dyn}) linked in a slightly different way and run the tests with both. (In exotic configurations, one may pass all the tests while the other fails and we want to check for this.) To test only the default binary, use \kbd{make dobench} which starts the bench immediately. If a \kbd{[BUG]} message shows up, something went wrong. The testing utility directs you to files containing the differences between the test output and the expected results. Have a look and decide for yourself if something is amiss. If it looks like a bug in the Pari system, we would appreciate a report, see the last section. \subsec{Cross-compiling} When cross-compiling, you can set the environment variable \kbd{RUNTEST} to a program that is able to run the target binaries, e.g. an emulator. It will be used for both the \kbd{Configure} tests and \kbd{make bench}. \section{Troubleshooting and fine tuning} In case the default \kbd{Configure} run fails miserably, try \kbd{./Configure -a} \noindent (interactive mode) and answer all the questions: there are about 30 of them, and default answers are provided. If you accept all default answers, \kbd{Configure} will fail just the same, so be wary. In any case, we would appreciate a bug report (see the last section). \subsec{Installation directories} The precise default destinations are as follows: the \kbd{gp} binary, the scripts \kbd{gphelp} and \kbd{tex2mail} go to \kbd{\$prefix/bin}. The pari library goes to \kbd{\$prefix/lib} and include files to \kbd{\$prefix/include/pari}. Other system-dependent data go to \kbd{\$prefix/lib/pari}. Architecture independent files go to various subdirectories of \kbd{\$share\_prefix}, which defaults to \kbd{\$prefix/share}, and can be specified via the \kbd{--share-prefix} argument. Man pages go into \kbd{\$share\_prefix/man}, and other system-independent data under \kbd{\$share\_prefix/pari}: documentation, sample GP scripts and C code, extra packages like \kbd{elldata} or \kbd{galdata}. \noindent You can also set directly \kbd{--bindir} (executables), \kbd{--libdir} (library), \kbd{--includedir} (include files), \kbd{--mandir} (manual pages), \kbd{--datadir} (other architecture-independent data), and finally \kbd{--sysdatadir} (other architecture-dependent data). \subsec{Environment variables} \kbd{Configure} lets the following environment variable override the defaults if set: \kbd{CC}: C compiler. \kbd{DLLD}: Dynamic library linker. \kbd{LD}: Static linker. \noindent For instance, \kbd{Configure} may avoid \kbd{/bin/cc} on some architectures due to various problems which may have been fixed in your version of the compiler. You can try \kbd{env CC=cc Configure} \noindent and compare the benches. Also, if you insist on using a \kbd{C++} compiler and run into trouble with a fussy \kbd{g++}, try to use \kbd{g++ -fpermissive}. \noindent The contents of the following variables are \emph{appended} to the values computed by \kbd{Configure}: \kbd{CFLAGS}: Flags for \kbd{CC}. \kbd{CPPFLAGS}: Flags for \kbd{CC} (preprocessor). \kbd{LDFLAGS}: Flags for \kbd{LD}. \noindent The contents of the following variables are \emph{prepended} to the values computed by \kbd{Configure}: \kbd{C\_INCLUDE\_PATH} is prepended to the list of directories searched for include files. Note that adding \kbd{-I} flags to \kbd{CFLAGS} is not enough since \kbd{Configure} sometimes relies on finding the include files and parsing them, and it does not parse \kbd{CFLAGS} at this time. \kbd{LIBRARY\_PATH} is prepended to the list of directories searched for libraries. \noindent You may disable inlining by adding \kbd{-DDISABLE\_INLINE} to \kbd{CFLAGS}, and prevent the use of the \kbd{volatile} keyword with \kbd{-DDISABLE\_VOLATILE}. \subsec{Debugging/profiling}: If you also want to debug the PARI library, \kbd{Configure -g} \noindent creates a directory \kbd{O$xxx$.dbg} containing a special \kbd{Makefile} ensuring that the \kbd{gp} and PARI library built there is suitable for debugging. If you want to profile \kbd{gp} or the library, using \kbd{gprof} for instance, \kbd{Configure -pg} \noindent will create an \kbd{O$xxx$.prf} directory where a suitable version of PARI can be built. The \kbd{gp} binary built above with \kbd{make all} or \kbd{make gp} is optimized. If you have run \kbd{Configure -g} or \kbd{-pg} and want to build a special purpose binary, you can \kbd{cd} to the \kbd{.dbg} or \kbd{.prf} directory and type \kbd{make gp} there. You can also invoke \kbd{make gp.dbg} or \kbd{make gp.prf} directly from the toplevel. \subsec{Multiprecision kernel} The kernel can be specified via the \kbd{--kernel=\emph{fully\_qualified\_kernel\_name}} \noindent switch. The PARI kernel consists of two levels: Level 0 (operation on words) and Level 1 (operation on multi-precision integers and reals), which can take the following values. Level 0: \kbd{auto} (as detected), \kbd{none} (portable C) or one of the assembler micro-kernels \bprog alpha hppa hppa64 ia64 ix86 x86_64 m68k ppc ppc64 sparcv7 sparcv8_micro sparcv8_super @eprog Level 1: \kbd{auto} (as detected), \kbd{none} (native code only), or \kbd{gmp} \noindent\item A fully qualified kernel name is of the form \kbd{\var{Level0}-\var{Level1}}, the default value being \kbd{auto-auto}. \noindent\item A \emph{name} not containing a dash '\kbd{-}' is an alias for a fully qualified kernel name. An alias stands for \kbd{\emph{name}-none}, but \kbd{gmp} stands for \kbd{auto-gmp}. \subsec{Problems related to readline} \kbd{Configure} does not try very hard to find the \kbd{readline} library and include files. If they are not in a standard place, it will not find them. You can invoke \kbd{Configure} with one of the following arguments: \kbd{--with-readline[=\emph{prefix to \kbd{lib/libreadline}.xx and \kbd{include/readline.h}}]} \kbd{--with-readline-lib=\emph{path to \kbd{libreadline}.xx}} \kbd{--with-readline-include=\emph{path to \kbd{readline.h}}} \misctitle{Known problems} \item on Linux: Linux distributions have separate \kbd{readline} and \kbd{readline-devel} packages. You need both of them installed to compile gp with readline support. If only \kbd{readline} is installed, \kbd{Configure} will complain. \kbd{Configure} may also complain about a missing libncurses.so, in which case, you have to install the \kbd{ncurses-devel} package (some distributions let you install \kbd{readline-devel} without \kbd{ncurses-devel}, which is a bug in their package dependency handling). \item on OS X.4 or higher: these systems comes equipped with a fake \kbd{readline}, which is not sufficient for our purpose. As a result, gp is built without readline support. Since \kbd{readline} is not trivial to install in this environment, a step by step solution can be found in the PARI FAQ, see $$ \url{http://pari.math.u-bordeaux.fr/}. $$ \subsec{Testing} \subsubsec{Known problems} if \kbd{BUG} shows up in \kbd{make bench} \item If when running \kbd{gp-dyn}, you get a message of the form \kbd{ld.so: warning: libpari.so.$xxx$ has older revision than expected $xxx$} \noindent (possibly followed by more errors), you already have a dynamic PARI library installed \emph{and} a broken local configuration. Either remove the old library or unset the \kbd{LD\_LIBRARY\_PATH} environment variable. Try to disable this variable in any case if anything \emph{very} wrong occurs with the \kbd{gp-dyn} binary, like an Illegal Instruction on startup. It does not affect \kbd{gp-sta}. \item Some implementations of the \kbd{diff} utility (on HPUX for instance) output \kbd{No differences encountered} or some similar message instead of the expected empty input, thus producing a spurious \kbd{[BUG]} message. \subsubsec{Some more testing} [{\sl Optional\/}] You can test \kbd{gp} in compatibility mode with \kbd{make test-compat}. If you want to test the graphic routines, use \kbd{make test-ploth}. You will have to click on the mouse button after seeing each image. There will be eight of them, probably shown twice (try to resize at least one of them as a further test). The \kbd{make bench}, \kbd{make test-compat} and \kbd{make test-ploth} runs all produce a Postscript file \kbd{pari.ps} in \kbd{O$xxx$} which you can send to a Postscript printer. The output should bear some similarity to the screen images. \subsubsec{Heavy-duty testing} [{\sl Optional\/}] There are a few extra tests which should be useful only for developers. \kbd{make test-kernel} checks whether the low-level kernel seems to work, and provides simple diagnostics if it does not. Only useful if \kbd{make bench} fails horribly, e.g.~things like \kbd{1+1} do not work. \kbd{make test-all} runs all available test suites. Thorough, but slow. Some of the tests require extra packages (\kbd{elldata}, \kbd{galdata}, etc.) to be available. If you want to test such an extra package \emph{before} \kbd{make install} (which would install it to its final location, where \kbd{gp} expects to find it), run \bprog env GP_DATA_DIR=$PWD/data make test-all @eprog\noindent from the PARI toplevel directory, otherwise the test will fail. \kbd{make test-io} tests writing to and reading from files. It requires a working \kbd{system()} command (fails on Windows + MingW). \kbd{make test-time} tests absolute and relative timers. This test has a tendency to fail when the machine is heavily loaded or if the granularity of the chosen system timer is bigger than 2ms. Try it a few times before reporting a problem. \kbd{make test-install} tests the GP function \kbd{install}. This may not be available on your platform, triggering an error message (``not yet available for this architecture''). The implementation may be broken on your platform triggering an error or a crash when an install'ed function is used. \section{Installation} When everything looks fine, type \kbd{make install} \noindent You may have to do this with superuser privileges, depending on the target directories. (Tip for MacOS X beginners: use \kbd{sudo make install}.) In this case, it is advised to type \kbd{make all} first to avoid running unnecessary commands as \kbd{root}. \misctitle{Caveat} Install directories are created honouring your \kbd{umask} settings: if your umask is too restrictive, e.g.~\kbd{077}, the installed files will not be world-readable. (Beware that running \kbd{sudo} may change your user umask.) This installs in the directories chosen at \kbd{Configure} time the default \kbd{gp} executable (probably \kbd{gp-dyn}) under the name \kbd{gp}, the default PARI library (probably \kbd{libpari.so}), the necessary include files, the manual pages, the documentation and help scripts. To save on disk space, you can manually \kbd{gzip} some of the documentation files if you wish: \kbd{usersch*.tex} and all \kbd{dvi} files (assuming your \kbd{xdvi} knows how to deal with compressed files); the online-help system can handle it. \subsec{Static binaries and libraries} By default, if a dynamic library \kbd{libpari.so} can be built, the \kbd{gp} binary we install is \kbd{gp-dyn}, pointing to \kbd{libpari.so}. On the other hand, we can build a \kbd{gp} binary into which the \kbd{libpari} is statically linked (the library code is copied into the binary); that binary is not independent of the machine it was compiled on, and may still refer to other dynamic libraries than \kbd{libpari}. You may want to compile your own programs in the same way, using the static \kbd{libpari.a} instead of \kbd{libpari.so}. By default this static library \kbd{libpari.a} is not created. If you want it as well, use the target \kbd{make install-lib-sta}. You can install a statically linked \kbd{gp} with the target \kbd{make install-bin-sta}. As a rule, programs linked statically (with \kbd{libpari.a}) may be slightly faster (about 5\% gain, possibly up to 20\% when using \kbd{pthreads}), but use more disk space and take more time to compile. They are also harder to upgrade: you will have to recompile them all instead of just installing the new dynamic library. On the other hand, there is no risk of breaking them by installing a new pari library. \subsec{Extra packages} The following optional packages endow PARI with some extra capabilities: \item \kbd{elldata}: This package contains the elliptic curves in John Cremona's database. It is needed by the functions \kbd{ellidentify}, \kbd{ellsearch}, \kbd{forell} and can be used by \kbd{ellinit} to initialize a curve given by its standard code. \item \kbd{galdata}: The default \kbd{polgalois} function can only compute Galois groups of polynomials of degree less or equal to 7. Install this package if you want to handle polynomials of degree bigger than 7 (and less than 11). \item \kbd{seadata}: This package contains the database of modular polynomials extracted from the ECHIDNA databases and computed by David R. Kohel. It is used to speed up the functions \kbd{ellap}, \kbd{ellcard} and \kbd{ellgroup} for primes larger than $10^{20}$. \item \kbd{galpol}: This package contains the GALPOL database of polynomials defining Galois extensions of the rationals, accessed by \kbd{galoisgetpol}. \medskip To install package \emph{pack}, you need to fetch the separate archive: \emph{pack}\kbd{.tgz} which you can download from the \kbd{pari} server. Copy the archive in the PARI toplevel directory, then extract its contents; these will go to \kbd{data/\emph{pack}/}. Typing \kbd{make install} installs all such packages. \subsec{The \kbd{GPRC} file} Copy the file \kbd{misc/gprc.dft} (or \kbd{gprc.dos} if you are using \kbd{GP.EXE}) to \kbd{\$HOME/.gprc}. Modify it to your liking. For instance, if you are not using an ANSI terminal, remove control characters from the \kbd{prompt} variable. You can also enable colors. If desired, read \kbd{\$datadir/misc/gpalias} from the \kbd{gprc} file, which provides some common shortcuts to lengthy names; fix the path in gprc first. (Unless you tampered with this via Configure, \kbd{datadir} is \kbd{\$prefix/share/pari}.) If you have superuser privileges and want to provide system-wide defaults, copy your customized \kbd{.gprc} file to \kbd{/etc/gprc}. In older versions, \kbd{gphelp} was hidden in pari lib directory and was not meant to be used from the shell prompt, but not anymore. If gp complains it cannot find \kbd{gphelp}, check whether your \kbd{.gprc} (or the system-wide \kbd{gprc}) does contain explicit paths. If so, correct them according to the current \kbd{misc/gprc.dft}. \section{Getting Started} \subsec{Printable Documentation} Building gp with \kbd{make all} also builds its documentation. You can also type directly \kbd{make doc}. In any case, you need a working (plain) \TeX\ installation. After that, the \kbd{doc} directory contains various \kbd{dvi} files: \kbd{libpari.dvi} (manual for the PARI library), \kbd{users.dvi} (manual for the \kbd{gp} calculator), \kbd{tutorial.dvi} (a tutorial), and \kbd{refcard.dvi} (a reference card for GP). You can send these files to your favorite printer in the usual way, probably via \kbd{dvips}. The reference card is also provided as a \kbd{PostScript} document, which may be easier to print than its \kbd{dvi} equivalent (it is in Landscape orientation and assumes A4 paper size). \noindent If \kbd{pdftex} is part of your \TeX\ setup, you can produce these documents in PDF format, which may be more convenient for online browsing (the manual is complete with hyperlinks); type \kbd{make docpdf} \noindent All these documents are available online from PARI home page (see the last section). \subsec{C programming} Once all libraries and include files are installed, you can link your C programs to the PARI library. A sample makefile \kbd{examples/Makefile} is provided to illustrate the use of the various libraries. Type \kbd{make all} in the \kbd{examples} directory to see how they perform on the \kbd{extgcd.c} program, which is commented in the manual. This should produce a statically linked binary \kbd{extgcd-sta} (standalone), a dynamically linked binary \kbd{extgcd-dyn} (loads libpari at runtime) and a shared library \kbd{libextgcd}, which can be used from \kbd{gp} to \kbd{install} your new \kbd{extgcd} command. The standalone binary should be bulletproof, but the other two may fail for various reasons. If when running \kbd{extgcd-dyn}, you get a message of the form ``DLL not found'', then stick to statically linked binaries or look at your system documentation to see how to indicate at linking time where the required DLLs may be found! (E.g.~on Windows, you will need to move \kbd{libpari.dll} somewhere in your \kbd{PATH}.) \subsec{GP scripts} Several complete sample GP programs are also given in the \kbd{examples} directory, for example Shanks's SQUFOF factoring method, the Pollard rho factoring method, the Lucas-Lehmer primality test for Mersenne numbers and a simple general class group and fundamental unit algorithm. See the file \kbd{examples/EXPLAIN} for some explanations. \subsec{The PARI Community} PARI's home page at the address $$\url{http://pari.math.u-bordeaux.fr/}$$ % maintains an archive of mailing lists dedicated to PARI, documentation (including Frequently Asked Questions), a download area and our Bug Tracking System (BTS). Bug reports should be submitted online to the BTS, which may be accessed from the navigation bar on the home page or directly at $$\url{http://pari.math.u-bordeaux.fr/Bugs/}$$ % Further information can be found at that address but, to report a configuration problem, make sure to include the relevant \kbd{*.dif} files in the \kbd{O$xxx$} directory and the file \kbd{pari.cfg}. \smallskip There are a number of mailing lists devoted to PARI/GP, and most feedback should be directed there. Instructions and archives can be consulted at $$ \url{http://pari.math.u-bordeaux.fr/lists-index.html} $$ % The most important are: \item \kbd{pari-announce} (\emph{read-only}): to announce major version changes. You cannot write to this one, but you should probably subscribe. \item \kbd{pari-dev}: for everything related to the development of PARI, including suggestions, technical questions or patch submissions. Bug reports can be discussed here, but as a rule it is better to submit them directly to the BTS. \item \kbd{pari-users}: for everything else. \noindent You may send an email to the last two without being subscribed. To subscribe, send an message respectively to \def\@{@} \bprog pari-announce-request@@pari.math.u-bordeaux.fr pari-users-request@@pari.math.u-bordeaux.fr pari-dev-request@@pari.math.u-bordeaux.fr @eprog\noindent with the word \kbd{subscribe} in the \kbd{Subject:}. You can also write to us at the address \bprog pari@@math.u-bordeaux.fr @eprog\noindent but we cannot promise you will get an individual answer. \smallskip If you have used PARI in the preparation of a paper, please cite it in the following form (BibTeX format): \bprog @@preamble{\usepackage{url}} @@manual{PARI2, organization = "{The PARI~Group}", title = "{PARI/GP version @vers}", year = 2018, address = "Bordeaux", note = "available from \url{http://pari.math.u-bordeaux.fr/}" } @eprog \smallskip \noindent In any case, if you like this software, we would be indebted if you could send us an email message giving us some information about yourself and what you use PARI for. \medskip {\bf Good luck and enjoy!} \vfill\eject pari-2.11.2/doc/usersch2.tex0000644000175000017500000041514213447371554014227 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \chapter{The gp Calculator} \section{Introduction} Originally, \tet{gp} was designed as a debugging device for the PARI system library. Over the years, it has become a powerful user-friendly stand-alone calculator. The mathematical functions available in PARI and \kbd{gp} are described in the next chapter. In the present one, we describe the specific use of the \kbd{gp} programmable calculator. \emacs If you have GNU Emacs and use the PariEmacs package, you can work in a special Emacs shell, described in \secref{se:emacs}. Specific features of this Emacs shell are indicated by an EMACS sign in the left margin. We briefly mention at this point GNU TeXmacs (\url{http://www.texmacs.org/}), a free wysiwyg editing platform that allows to embed an entire gp session in a document, and provides a nice alternative to PariEmacs. \subsec{Startup} To start the calculator, the general command line syntax is: \kbd{gp [-D \var{key}=\var{val}] [\var{files}]} \noindent where items within brackets are optional. The [\var{files}] argument is a list of files written in the GP scripting language, which will be loaded on startup. There can be any number of arguments of the form \kbd{-D \var{key}=\var{val}}, setting some internal parameters of \kbd{gp}, or \var{defaults}: each sets the default \var{key} to the value \var{val}. See \secref{se:defaults} below for a list and explanation of all defaults. These defaults can be changed by adding parameters to the input line as above, or interactively during a \kbd{gp} session, or in a preferences file also known as \tet{gprc}. If a \idx{preferences file} (to be discussed in \secref{se:gprc}) is found, \kbd{gp} then reads it and executes the commands it contains. This provides an easy way to customize \kbd{gp}. The \var{files} argument is processed right after the \kbd{gprc}. A copyright banner then appears which includes the version number, and a lot of useful technical information. After the copyright, the computer writes the top-level help information, some initial defaults, and then waits after printing its prompt, which is '\kbd{?~}' by default . Whether extended on-line help and line editing are available or not is indicated in this \kbd{gp} banner, between the version number and the copyright message. Consider investigating the matter with the person who installed \kbd{gp} if they are not. Do this as well if there is no mention of the GMP kernel. \subsec{Getting help} To get help, type a \kbd{?} and hit return. A menu appears, describing the main categories of available functions and how to get more detailed help. If you now type \kbd{?$n$} with $n = 1, 2, \dots$, you get the list of commands corresponding to category $n$ and simultaneously to Section $3.n$ of this manual. If you type \kbd{?}\var{functionname} where \var{functionname} is the name of a PARI function, you will get a short explanation of this function. If extended help (see \secref{se:exthelp}) is available on your system, you can double or triple the \kbd{?} sign to get much more: respectively the complete description of the function (e.g.~\kbd{??sqrt}), or a list of \kbd{gp} functions relevant to your query (e.g.~ \kbd{???"elliptic curve"} or \kbd{???"quadratic field"}). If \kbd{gp} was properly installed (see Appendix~A), a line editor is available to correct the command line, get automatic completions, and so on. See \secref{se:readline} or \kbd{??readline} for a short summary of the line editor's commands. If you type \kbd{?\bs} you will get a short description of the metacommands (keyboard shortcuts). Finally, typing \kbd{?.} will return the list of available (pre-defined) member functions. These are functions attached to specific kind of objects, used to retrieve easily some information from complicated structures (you can define your own but they won't be shown here). We will soon describe these commands in more detail. More generally, commands starting with the symbols \b\ or \kbd{?}, are not computing commands, but are metacommands which allow you to exchange information with \kbd{gp}. The available metacommands can be divided into default setting commands (explained below) and simple commands (or keyboard shortcuts, to be dealt with in \secref{se:meta}). \subsec{Input} Just type in an instruction, e.g. \kbd{1 + 1}, or \kbd{Pi}. No action is undertaken until you hit the \kbd{} key. Then computation starts, and a result is eventually printed. To suppress printing of the result, end the expression with a \kbd{;} sign. Note that many systems use \kbd{;} to indicate end of input. Not so in \kbd{gp}: a final semicolon means the result should not be printed. (Which is certainly useful if it occupies several screens.) \subsec{Interrupt, Quit} Typing \kbd{quit} at the prompt ends the session and exits \kbd{gp}. At any point you can type \kbd{Ctrl-C} (that is press simultaneously the \kbd{Control} and \kbd{C} keys): the current computation is interrupted and control given back to you at the \kbd{gp} prompt, together with a message like \bprog *** at top-level: gcd(a,b) *** ^-------- *** gcd: user interrupt after 236 ms. @eprog\noindent telling you how much time elapsed since the last command was typed in and in which GP function the computation was aborted. It does not mean that that much time was spent in the function, only that the evaluator was busy processing that specific function when you stopped it. \section{The general gp input line} The \kbd{gp} calculator uses a purely interpreted language GP. The structure of this language is reminiscent of LISP with a functional notation, \kbd{f(x,y)} rather than \kbd{(f x y)}: all programming constructs, such as \kbd{if}, \kbd{while,} etc\dots are functions\footnote{*}{Not exactly, since not all their arguments need be evaluated. For instance it would be stupid to evaluate both branches of an \kbd{if} statement: since only one will apply, only this one is evaluated.}, and the main loop does not really execute, but rather evaluates (sequences of) expressions. Of course, it is by no means a true LISP, and has been strongly influenced by C and Perl since then. \subsec{Introduction} User interaction with a \kbd{gp} session proceeds as follows. First, one types a sequence of characters at the \kbd{gp} prompt; see \secref{se:readline} for a description of the line editor. When you hit the \kbd{} key, \kbd{gp} gets your input, evaluates it, then prints the result and assigns it to an ``history'' array. More precisely, the input is case-sensitive and, outside of character strings, blanks are completely ignored. Inputs are either metacommands or sequences of expressions. Metacommands are shortcuts designed to alter gp's internal state, such as the working precision or general verbosity level; we shall describe them in \secref{se:meta}, and ignore them for the time being. The evaluation of a sequence of instructions proceeds in two phases: your input is first digested (byte-compiled) to a bytecode suitable for fast evaluation, in particular loop bodies are compiled only once but a priori evaluated many times; then the bytecode is evaluated. An \idx{expression}\sidx{expression sequence} is formed by combining constants, variables, operator symbols, functions and control statements. It is evaluated using the conventions about operator priorities and left to right associativity. An expression always has a value, which can be any PARI object: \bprog ? 1 + 1 %1 = 2 \\@com an ordinary integer ? x %2 = x \\@com a polynomial of degree 1 in the unknown \kbd{x} ? print("Hello") Hello \\@com \kbd{void} return value, 'Hello' printed as side effect ? f(x) = x^2 %4 = (x)->x^2 \\@com a user function @eprog \noindent In the third example, \kbd{Hello} is printed as a side effect, but is not the return value. The \kbd{print} command is a \emph{procedure}, which conceptually returns nothing. But in fact procedures return a special \kbd{void} object, meant to be ignored (but which evaluates to $0$ in a numeric context, and stored as $0$ in the history or results). The final example assigns to the variable \kbd{f} the function $x\mapsto x^2$, the alternative form \kbd{f = x->x\pow2} achieving the same effect; the return value of a function definition is, unsurprisingly, a function object (of type \typ{CLOSURE}). Several expressions are combined on a single line by separating them with semicolons ('\kbd{;}'). Such an expression sequence will be called a \var{seq}. A \var{seq} also has a value, which is the value of the last expression in the sequence. Under \kbd{gp}, the value of the \var{seq}, and only this last value, becomes an history entry. The values of the other expressions in the \var{seq} are discarded after the execution of the \var{seq} is complete, except of course if they were assigned into variables. In addition, the value of the \var{seq} is printed if the line does not end with a semicolon \kbd{;}. \subsec{The gp history of results} This is not to be confused with the history of your \emph{commands}, maintained by \kbd{readline}. The \kbd{gp} history contains the \emph{results} they produced, in sequence. The successive elements of the history array are called \kbd{\%1}, \kbd{\%2}, \dots As a shortcut, the latest computed expression can also be called \kbd{\%}, the previous one \kbd{\%`}, the one before that \kbd{\%``} and so on. When you suppress the printing of the result with a semicolon, it is still stored in the history, but its history number will not appear either. It is a better idea to assign it to a variable for later use than to mentally recompute what its number is. Of course, on the next line, you may just use \kbd{\%}. The time used to compute that history entry is also stored as part of the entry and can be recovered using the \kbd{\%\#} operator: \kbd{\%\#1}, \kbd{\%\#2}, \kbd{\%\#`}; \kbd{\%\#} by itself returns the time needed to compute the last result (the one returned by \kbd{\%}). \misctitle{Remark} The history ``array'' is in fact better thought of as a queue: its size is limited to 5000 entries by default, after which \kbd{gp} starts forgetting the initial entries. So \kbd{\%1} becomes unavailable as \kbd{gp} prints \kbd{\%5001}. You can modify the history size using \tet{histsize}. \subsec{Special editing characters}\sidx{editing characters} A GP program can of course have more than one line. Since your commands are executed as soon as you have finished typing them, there must be a way to tell \kbd{gp} to wait for the next line or lines of input before doing anything. There are three ways of doing this. The first one is to use the \idx{backslash character} \kbd{\bs} at the end of the line that you are typing, just before hitting \kbd{}. This tells \kbd{gp} that what you will write on the next line is the physical continuation of what you have just written. In other words, it makes \kbd{gp} forget your newline character. You can type a \kbd{\bs} anywhere. It is interpreted as above only if (apart from ignored whitespace characters) it is immediately followed by a newline. For example, you can type \bprog ? 3 + \ 4 @eprog \noindent instead of typing \kbd{3 + 4}. The second one is a variation on the first, and is mostly useful when defining a user function (see \secref{se:user_defined}): since an equal sign can never end a valid expression, \kbd{gp} disregards a newline immediately following an \kbd{=}. \bprog ? a = 123 %1 = 123 @eprog The third one is in general much more useful, and uses braces \kbd{\obr} and \kbd{\cbr}.\sidx{brace characters} An opening brace \kbd{\obr} signals that you are typing a multi-line command, and newlines are ignored until you type a closing brace \kbd{\cbr}. There are two important, but easily obeyed, restrictions: first, braces do not nest; second, inside an open brace-close brace pair, all input lines are concatenated, suppressing any newlines. Thus, all newlines should occur after a semicolon (\kbd{;}), a comma (\kbd{,}) or an operator (for clarity's sake, never split an identifier over two lines in this way). For instance, the following program \bprog { a = b b = c } @eprog \noindent would silently produce garbage, since this is interpreted as \kbd{a=bb=c} which assigns the value of \kbd{c} to both \kbd{bb} and \kbd{a}. It should have been written \bprog { a = b; b = c; } @eprog \section{The PARI types} \noindent We see here how to input values of the different data types known to PARI. Recall that blanks are ignored in any expression which is not a string (see below). \misctitle{A note on efficiency} The following types are provided for convenience, not for speed: \typ{INTMOD}, \typ{FRAC}, \typ{PADIC}, \typ{QUAD}, \typ{POLMOD}, \typ{RFRAC}. Indeed, they always perform a reduction of some kind after each basic operation, even though it is usually more efficient to perform a single reduction at the end of some complex computation. For instance, in a convolution product $\sum_{i+j = n} x_i y_j$ in $\Z/N\Z$ --- common when multiplying polynomials! ---, it is quite wasteful to perform $n$ reductions modulo $N$. In short, basic individual operations on these types are fast, but recursive objects with such components could be handled more efficiently: programming with libpari will save large constant factors here, compared to GP. \subsec{Integers (\typ{INT})}% \sidx{integer}\kbdsidx{t_INT} After an (optional) leading \kbd{+} or \kbd{-}, type in the decimal digits of your integer. No decimal point! \bprog ? 1234567 %1 = 1234567 ? -3 %2 = -3 ? 1. \\@com oops, not an integer %3 = 1.000000000000000000000000000 @eprog Integers can be input in hexadecimal notation by prefixing them with \kbd{0x}; hexadecimal digits ($a, \dots, f$) can be input either in lowercase or in uppercase: \bprog ? 0xF %4 = 15 ? 0x1abcd %5 = 109517 @eprog Integers can also be input in binary by prefixing them with \kbd{0b}: \bprog ? 0b010101 %6 = 21 @eprog \subsec{Real numbers (\typ{REAL})}% \sidx{real number}\kbdsidx{t_REAL} Real numbers are represented (approximately) in a floating point system, internally in base 2, but converted to base 10 for input / output purposes. A \typ{REAL} object has a given \emph{accuracy} (or \emph{precision}) $\ell \geq 0$; it comprises \item a sign $s$: $+1$, $-1$ or $0$; \item a mantissa $m$: a multiprecision integer, $0\leq m < 10^\ell$; \item an exponent $e$: a small integer in $[-E,E]$, where $E \approx 2^B \log_{10} 2$, and $B = 32$ on a 32-bit machine and 64 otherwise. This data may represent any real number $x$ such that $$|x - s m 10^e| < 10^{e-\ell}.$$ We consider that a \typ{REAL} with sign $s = 0$ has accuracy $\ell = 0$, so that its mantissa is useless, but it still has an exponent $e$ and acts like a machine epsilon for all accuracies $< e$. After an (optional) leading \kbd{+} or \kbd{-}, type a number with a decimal point. Leading zeroes may be omitted, up to the decimal point, but trailing zeroes are important: your \typ{REAL} is assigned an internal precision, which is the supremum of the input precision, one more than the number of decimal digits input, and the default \tet{realprecision}. For example, if the default precision is 28 digits, typing \kbd{2.} yields a precision of 28 digits, but \kbd{2.0\dots0} with 45 zeros gives a number with internal precision at least 45, although less may be printed. You can also use scientific notation with the letter \kbd{E} or \kbd{e}. As usual, \kbd{e$n$} is interpreted as $\times 10^n$ for all integers $n$. Since the result is converted to a \typ{REAL}, you may often omit the decimal point in this case: \kbd{6.02 E 23} or \kbd{1e-5} are fine, but \kbd{e10} is not. By definition, \kbd{0.E $n$} returns a real $0$ of exponent $n$, whereas \kbd{0.} returns a real 0 ``of default precision'' (of exponent $-\tet{realprecision}$), see \secref{se:whatzero}, behaving like the machine epsilon for the current default accuracy: any float of smaller absolute value is indistinguishable from $0$. \misctitle{Note on output formats} A zero real number is printed in \kbd{e} format as $0.Exx$ where $xx$ is the (usually negative) \emph{decimal} exponent of the number (cf.~\secref{se:whatzero}). This allows the user to check the accuracy of that particular zero. When the integer part of a real number $x$ is not known exactly because the exponent of $x$ is greater than the internal precision, the real number is printed in \kbd{e} format. \misctitle{Technical note} The internal \emph{precision} is actually expressed in bits and can be viewed and manipulated globally in interactive use via \kbd{realprecision} (decimal digits, as explained above; shortcut \kbd{\bs p}) or \kbd{realbitprecision} (bits; shortcut \kbd{\bs ps}), the latter allowing finer granularity. See \secref{se:trans} for details. In programs we advise to leave this global variable alone and adapt precision locally for a given sequence of computations using \tet{localbitprec}. \subsec{Intmods (\typ{INTMOD})}% \sidx{intmod}\kbdsidx{t_INTMOD} To create the image of the integer $a$ in $\Z/b\Z$ (for some non-zero integer $b$), type \kbd{Mod(a,b)}; \emph{not} \kbd{a\%b}. Internally, all operations are done on integer representatives belonging to $[0,b-1]$. Note that this type is available for convenience, not for speed: each elementary operation involves a reduction modulo $b$. If $x$ is a \typ{INTMOD} \kbd{Mod(a,b)}, the following member function is defined: \kbd{x.mod}: return the modulus \kbd{b}. \subsec{Rational numbers (\typ{FRAC})}% \sidx{rational number}\kbdsidx{t_FRAC} All fractions are automatically reduced to lowest terms, so it is impossible to work with reducible fractions. To enter $n/m$ just type it as written. As explained in \secref{se:gdiv}, floating point division is \emph{not} performed, only reduction to lowest terms.\label{se:FRAC} Note that rational computation are almost never the fastest method to proceed: in the PARI implementation, each elementary operation involves computing a gcd. It is generally a little more efficient to cancel denominators and work with integers only: \bprog ? P = Pol( vector(10^3,i, 1/i) ); \\@com big polynomial with small rational coeffs ? P^2 time = 1,392 ms. ? c = content(P); c^2 * (P/c)^2; \\@com same computation in integers time = 1,116 ms. @eprog\noindent And much more efficient (but harder to setup) to use homomorphic imaging schemes and modular computations. As the simple example below indicates, if you only need modular information, it is very worthwhile to work with \typ{INTMOD}s directly, rather than deal with \typ{FRAC}s all the way through: \bprog ? p = nextprime(10^7); ? sum(i=1, 10^5, 1/i) % p time = 13,288 ms. %1 = 2759492 ? sum(i=1, 10^5, Mod(1/i, p)) time = 60 ms. %2 = Mod(2759492, 10000019) @eprog\noindent \subsec{Finite field elements (\typ{FFELT})}% \sidx{finite field element}\kbdsidx{t_FFELT} Let $T\in\F_p[X]$ be a monic irreducible polynomial defining your finite field over $\F_p$, for instance obtained using \tet{ffinit}. Then the \tet{ffgen} function creates a generator of the finite field as an $\F_p$-algebra, namely the class of $X$ in $\F_p[X]/(T)$, from which you can build all other elements. For instance, to create the field $\F_{2^8}$, we write \bprog ? T = ffinit(2, 8); ? y = ffgen(T, 'y); ? y^0 \\ the unit element in the field %3 = 1 ? y^8 %4 = y^6 + y^5 + y^4 + y^3 + y + 1 @eprog\noindent The second (optional) parameter to \tet{ffgen} is only used to display the result; it is customary to use the name of the variable we assign the generator to. If \kbd{g} is a \typ{FFELT}, the following member functions are defined: \kbd{g.pol}: the polynomial (with reduced integer coefficients) expressing \kbd{g} in term of the field generator. \kbd{g.p}: the characteristic of the finite field. \kbd{g.f}: the dimension of the definition field over its prime field; the cardinality of the definition field is thus $p^f$. \kbd{g.mod}: the minimal polynomial (with reduced integer coefficients) of the field generator. \subsec{Complex numbers (\typ{COMPLEX})}% \sidx{complex number}\kbdsidx{t_COMPLEX} To enter $x+iy$, type \kbd{x + I*y}. (That's \kbd{I}, \emph{not} \kbd{i}!) The letter \tet{I} stands for $\sqrt{-1}$. The ``real'' and ``imaginary'' parts $x$ and $y$ can be of type \typ{INT}, \typ{REAL}, \typ{INTMOD}, \typ{FRAC}, or \typ{PADIC}. \subsec{$p$-adic numbers (\typ{PADIC}):}% \sidx{p-adic number}\label{se:padic}\kbdsidx{t_PADIC} Typing \kbd{O($p$\pow $k$)}, where $p$ is a prime and $k$ is an integer, yields a $p$-adic $0$ of accuracy~$k$, representing any $p$-adic number whose valuation is $\geq k$. To input a general non-0 $p$-adic number, write a suitably precise rational or integer approximation and add \kbd{O($p$\pow $k$)} to it. For example, you can type in the $7$-adic number \bprog 2*7^(-1) + 3 + 4*7 + 2*7^2 + O(7^3) @eprog\noindent exactly as shown, or equivalently as \kbd{905/7 + O(7\pow3)}. Note that it is not checked whether $p$ is indeed prime but results are undefined if this is not the case: you can try to work on $10$-adics if you want, but disasters will happen as soon as you do something non-trivial. For instance: \bprog ? t = 2 * (1/10 + O(10^5)); ? lift(t) %2 = 2/10 \\ not reduced (invalid t_FRAC) ? factor(x^2-t) *** at top-level: factor(x^2-%1) *** ^-------------- *** factor: impossible inverse in Fl_inv: Mod(2, 10000). @eprog\noindent Note that \kbd{O(25)} is not the same as \kbd{O(5\pow 2)}; you want the latter! If $a$ is a \typ{PADIC}, the following member functions are defined: \kbd{a.mod}: returns the modulus $p^k$. \kbd{a.p}: returns $p$. Note that this type is available for convenience, not for speed: internally, \typ{PADIC}s are stored as $p$-adic units modulo some $p^k$. Each elementary operation involves updating $p^k$ (multiplying or dividing by powers of $p$) and a reduction mod $p^k$. In particular, additions are slow. \bprog ? n = 1+O(2^20); for (i=1,10^6, n++) time = 841 ms. ? n = Mod(1,2^20); for (i=1,10^6, n++) time = 441 ms. ? n = 1; for (i=1,10^6, n++) time = 328 ms. @eprog\noindent The penalty attached to maintaining $p^k$ decreases steeply as $p$ increases (and updates become rare). But \typ{INTMOD}s remain at least 25\% more efficient. (On the other hand, they do not allow denominators!) % n = 1+O(1009^2); for (i=1,10^6, n++) % n = Mod(1,1009^2); for (i=1,10^6, n++) \subsec{Quadratic numbers (\typ{QUAD})}% \sidx{quadratic number}\kbdsidx{t_QUAD} This type is used to work in the quadratic order of \emph{discriminant} \kbd{d}, where \kbd{d} is a non-square integer congruent to $0$ or $1$ (modulo $4$). The command \bprog w = quadgen(d,'w) @eprog\noindent assigns to \kbd{w} the ``canonical'' generator for the integer basis of the order of discriminant $d$, i.e.~$w=\sqrt{d}/2$ if $d\equiv 0 \mod 4$, and $w=(1+\sqrt{d})/2$ if $d\equiv 1 \mod 4$ and set its name to \kbd{w}. The name \kbd{'w} is used for printing and we advise to store it in a variable of the same name. Beware, two \typ{QUAD}s with different discriminants can be printed in the same way and not be equal; however, \kbd{gp} will refuse to add or multiply them for example, so use different names for different discriminants. Since the order is $\Z + \kbd{w}\Z$, any other element can be input as \kbd{z = $x$+$y$*w} for some integers $x$ and $y$. In fact, you may work in its fraction field $\Q(\sqrt{d})$ and use \typ{FRAC} values for $x$ and $y$. The member function \kbd{z.disc} retrieves the discriminant $d$; $x$ and $y$ are obtained via \kbd{real(z)} and \kbd{imag(z)} respectively. \subsec{Polmods (\typ{POLMOD})}% \sidx{polmod}\kbdsidx{t_POLMOD} Exactly as for intmods, to enter $x \mod y$ (where $x$ and $y$ are polynomials), type \kbd{Mod(x,y)}, not \kbd{x\%y}. Note that when $y$ is an irreducible polynomial in one variable, polmods whose modulus is $y$ are simply algebraic numbers in the finite extension defined by the polynomial $y$. This allows us to work easily in \idx{number field}s, finite extensions of the $p$-adic field $\Q_p$, or \idx{finite field}s. Note that this type is available for convenience, not for speed: each elementary operation involves a reduction modulo $y$. If $p$ is a \typ{POLMOD}, the following member functions are defined: \kbd{p.pol}: return a representative of the polynomial class of minimal degree. \kbd{p.mod}: return the modulus. \label{se:rempolmod} \misctitle{Important remark}\sidx{variable (priority)} Mathematically, the variables\sidx{variable} occurring in a polmod are not free variables. But internally, a congruence class in $R[t]/(y)$ is represented by its representative of lowest degree, which is a \typ{POL} in $R[t]$, and computations occur with polynomials in the variable $t$. PARI will not recognize that \kbd{Mod(y, y\pow2 + 1)} is ``the same'' as \kbd{Mod(x, x\pow2 + 1)}, since \kbd{x} and \kbd{y} are different variables. To avoid inconsistencies, polmods must use the same variable in internal operations (i.e.~between polmods) and variables of lower priority for external operations, typically between a polynomial and a polmod. See \secref{se:priority} for a definition of ``priority'' and a discussion of (PARI's idea of) multivariate polynomial arithmetic. For instance: \bprog ? Mod(x, x^2+ 1) + Mod(x, x^2 + 1) %1 = Mod(2*x, x^2 + 1) \\@com $2i$ (or $-2i$), with $i^2=-1$ ? x + Mod(y, y^2 + 1) %2 = x + Mod(y, y^2 + 1) \\@com in $\Q(i)[x]$ ? y + Mod(x, x^2 + 1) %3 = Mod(x + y, x^2 + 1) \\@com in $\Q(y)[i]$ @eprog\noindent The first two are straightforward, but the last one may not be what you want: \kbd{y} is treated here as a numerical parameter, not as a polynomial variable. If the main variables are the same, it is allowed to mix \typ{POL} and \typ{POLMOD}s. The result is the expected \typ{POLMOD}. For instance \bprog ? x + Mod(x, x^2 + 1) %1 = Mod(2*x, x^2 + 1) @eprog \subsec{Polynomials (\typ{POL})}% \sidx{polynomial}\label{se:pol}\kbdsidx{t_POL} Type the polynomial in a natural way, not forgetting to put a ``$*$'' between a coefficient and a formal variable; \bprog ? 1 + 2*x + 3*x^2 %1 = 3*x^2 + 2*x + 1 @eprog\noindent This assumes that \kbd{x} is still a ''free variable''. \bprog ? x = 1; 1 + 2*x + 3*x^2 %2 = 6 @eprog\noindent generates an integer, not a polynomial! It is good practice to never assign values to polynomial variables to avoid the above problem, but a foolproof construction is available using \kbd{'x} instead of~\kbd{x}: \kbd{'x} is a constant evaluating to the free variable with name \kbd{x}, independently of the current value of~\kbd{x}. \bprog ? x = 1; 1 + 2*'x + 3*'x^2 %3 = 1 + 2*x + 3*x^2 ? x = 'x; 1 + 2*x + 3*x^2 %4 = 1 + 2*x + 3*x^2 @eprog\noindent You may also use the functions \kbd{Pol} or \kbd{Polrev}: \bprog ? Pol([1,2,3]) \\@com \kbd{Pol} creates a polynomial in \kbd{x} by default %1 = x^2 + 2*x + 3 ? Polrev([1,2,3]) %2 = 3*x^2 + 2*x + 1 ? Pol([1,2,3], 'y) \\@com we use \kbd{'y}, safer than \kbd{y} %3 = y^2 + 2*y + 3 @eprog\noindent The latter two are much more efficient constructors than an explicit summation (the latter is quadratic in the degree, the former linear): \bprog ? for (i=1, 10^4, Polrev( vector(100, i,i) ) ) time = 124ms ? for (i=1, 10^4, sum(i = 1, 100, (i+1) * 'x^i) ) time = 3,985ms @eprog Polynomials are always printed as \emph{univariate} polynomials, with monomials sorted by decreasing degree: \bprog ? (x+y+1)^2 %1 = x^2 + (2*y + 2)*x + (y^2 + 2*y + 1) @eprog\noindent (Univariate polynomial in \kbd{x} whose coefficients are polynomials in \kbd{y}.) See \secref{se:varsymb} for valid variable names, and a discussion of multivariate polynomial rings. \subsec{Power series (\typ{SER})}% \sidx{power series}\kbdsidx{t_SER}\label{se:series} Typing \kbd{O(X\pow $k$)}, where $k$ is an integer, yields an $X$-adic $0$ of accuracy~$k$, representing any power series in \kbd{X} whose valuation is $\geq k$. Of course, \kbd{X} can be replaced by any other variable name! To input a general non-0 power series, type in a polynomial or rational function (in \kbd{X}, say), and add \kbd{O(X\pow $k$)} to it. The discussion in the \typ{POL} section about variables remains valid; a constructor \tet{Ser} replaces \tet{Pol} and \tet{Polrev}. \misctitle{Caveat} Power series with inexact coefficients sometimes have a non-intuitive behavior: if $k$ significant terms are requested, an inexact zero is counted as significant, even if it is the coefficient of lowest degree. This means that useful higher order terms may be disregarded. If a series with a zero leading coefficient must be inverted, then as a desperation measure that coefficient is discarded, and a warning is issued: \bprog ? C = 0. + y + O(y^2); ? 1/C *** _/_: Warning: normalizing a series with 0 leading term. %2 = y^-1 + O(1) @eprog\noindent The last output could be construed as a bug since it is a priori impossible to deduce such a result from the input ($0.$ represents any sufficiently small real number). But it was thought more useful to try and go on with an approximate computation than to raise an early exception. If the series precision is insufficient, errors may occur (mostly division by $0$), which could have been avoided by a better global understanding of the computation: \bprog ? A = 1/(y + 0.); B = 1. + O(y); ? B * denominator(A) %2 = 0.E-28 + O(y) ? A/B *** _/_: Warning: normalizing a series with 0 leading term. %3 = 1.000000000000000000000000000*y^-1 + O(1) ? A*B *** _*_: Warning: normalizing a series with 0 leading term. %4 = 1.000000000000000000000000000*y^-1 + O(1) @eprog \subsec{Rational functions (\typ{RFRAC})}% \sidx{rational function}\kbdsidx{t_RFRAC} As for fractions, all rational functions are automatically reduced to lowest terms. All that was said about fractions in \secref{se:FRAC} remains valid here. \subsec{Binary quadratic forms of positive or negative discriminant (\typ{QFR} and \typ{QFI})}% \sidx{binary quadratic form}\kbdsidx{t_QFR}\kbdsidx{t_QFI} These are input using the function \kbd{Qfb}. For example \kbd{Qfb(1,2,3)} creates the binary form $q = x^2+2xy+3y^2$. It is imaginary (of internal type \typ{QFI}) since its discriminant $2^2 - 4\times 3 = -8$ is negative. Although imaginary forms could be positive or negative definite, only positive definite forms are implemented. The discriminant can be retrieved via \kbd{poldisc}. The individual components are obtained via either of \bprog [a,b,c] = Vec(q); a = component(q,1); b = component(q,2); c = component(q,3); @eprog In the case of forms with positive discriminant (\typ{QFR}), you may add an optional fourth component (related to the regulator, more precisely to Shanks and Lenstra's distance), which must be a real number. See also the function \kbd{qfbprimeform} which creates a prime form of given discriminant. \subsec{Row and column vectors (\typ{VEC} and \typ{COL})}% \sidx{row vector}\sidx{column vector}\kbdsidx{t_VEC}\kbdsidx{t_COL} To enter a row vector, type the components separated by commas ``\kbd{,}'', and enclosed between brackets ``\kbd{[}$\,$'' and ``$\,$\kbd{]}'', e.g.~\kbd{[1,2,3]}. To enter a column vector, type the vector horizontally, and add a tilde ``\til'' to transpose. \kbd{[ ]} yields the empty (row) vector. The function \tet{Vec} can be used to transform any object into a vector (see Chapter~3). The construction $[i..j]$, where $i \leq j$ are two integers returns the vector $[i, i+1,\dots, j-1, j]$ \bprog ? [1,2,3] %1 = [1, 2, 3] ? [-2..3] %2 = [-2, -1, 0, 1, 2, 3] @eprog Let the variable $v$ contain a (row or column) vector: \item \kbd{v[m]} refers to its $m$-th entry; you can assign any value to \kbd{v[m]}, i.e.~write something like $v[m]=\var{expr}$. \item \kbd{v[i..j]}, where $i \leq j$, returns the vector slice containing elements $v[i],\dots, v[j]$; you can \emph{not} assign a result to \kbd{v[i..j]}. \item \kbd{v[\pow i]} returns the vector whose $i$-th entry has been removed; you can \emph{not} assign a result to \kbd{v[\pow i]}. \noindent In the last two constructions \kbd{v[i..j]} and \kbd{v[\pow i]}, $i$ and $j$ are allowed to be negative integers, in which case, we start counting from the end of the vector: e.g., $-1$ is the index of the last element. \bprog ? v = [1,2,3,4]; ? v[2..4] %2 = [2, 3, 4] ? v[^3] %3 = [1, 2, 4] ? v[^-1] %3 = [1, 2, 3] ? v[-3..-1] %4 = [2, 3, 4] @eprog \misctitle{Remark} \tet{vector} is the standard constructor for row vectors whose $i$-th entry is given by a simple function of $i$; \tet{vectorv} is similar for column vectors: \bprog ? vector(10, i, i^2+1) %1 = [2, 5, 10, 17, 26, 37, 50, 65, 82, 101] @eprog The functions \tet{Vec} and \tet{Col} convert objects to row and column vectors respectively (as well as \tet{Vecrev} and \tet{Colrev}, which revert the indexing): \bprog ? T = poltchebi(5) \\ 5-th Chebyshev polynomial %1 = 16*x^5 - 20*x^3 + 5*x ? Vec(T) %2 = [16, 0, -20, 0, 5, 0] \\ coefficients of T ? Vecrev(T) %3 = [0, 5, 0, -20, 0, 16] \\ ... in reverse order @eprog \misctitle{Remark} For $v$ a \typ{VEC}, \typ{COL}, \typ{LIST} or \typ{MAT}, the alternative set-notations \bprog [g(x) | x <- v, f(x)] [x | x <- v, f(x)] [g(x) | x <- v] @eprog\noindent are available as shortcuts for \bprog apply(g, select(f, Vec(v))) select(f, Vec(v)) apply(g, Vec(v)) @eprog\noindent respectively, and may serve as \typ{VEC} constructors: \bprog ? [ p | p <- primes(10), isprime(p+2) ] %2 = [3, 5, 11, 17, 29] @eprog\noindent returns the primes $p$ (among the first 10 primes) such that $(p, p+2)$ is a twin pair; \bprog ? [ p^2 | p <- primes(10), p % 4 == 1 ] %1 = [25, 169, 289, 841] @eprog\noindent returns the squares of the primes congruent to $1$ modulo $4$, where $p$ runs among the first 10 primes. \subsec{Matrices (\typ{MAT})}% \sidx{matrix}\kbdsidx{t_MAT} To enter a matrix, type the components row by row, the components being separated by commas ``\kbd{,}'', the rows by semicolons ``\kbd{;}'', and everything enclosed in brackets ``\kbd{[}$\,$'' and ``$\,$\kbd{]}'', e.g. \kbd{[x,y; z,t; u,v]}. \kbd{[;]} yields an empty ($0 \times 0$) matrix. The function \tet{Mat} transforms any object into a matrix, and \tet{matrix} creates matrices whose $(i,j)$-th entry is described by a function $f(i,j)$: \bprog ? Mat(1) %1 = [1] ? matrix(2,2, i,j, 2*i+j) %2 = [3 4] [5 6] @eprog \noindent Let the variable $M$ contain a matrix, and let $i,j,k,l$ denote four integers: \item \kbd{M[i,j]} refers to its $(i,j)$-th entry; you can assign any result to \kbd{M[i,j]}. \item \kbd{M[i,]} refers to its $i$-th row; you can assign a \typ{VEC} of the right dimension to \kbd{M[i,]}. \item \kbd{M[,j]} refers to its $j$-th column; you can assign a \typ{COL} of the right dimension to \kbd{M[,j]}. \noindent \emph{But} \kbd{M[i]} is meaningless and triggers an error. The ``range'' $i..j$ and ``caret'' \kbd{\pow}$c$ notations are available as for vectors; you can not \emph{assign} to any of these: \item \kbd{M[i..j, k..l]}, $i\leq j$, $k\leq l$, returns the submatrix built from the rows $i$ to $j$ and columns $k$ to $l$ of $M$. \item \kbd{M[i..j,]} returns the submatrix built from the rows $i$ to $j$ of $M$. \item \kbd{M[,i..j]} returns the submatrix built from the columns $i$ to $j$ of $M$. \item \kbd{M[i..j, \pow k]}, $i\leq j$, returns the submatrix built from the rows $i$ to $j$ and column $k$ removed. \item \kbd{M[\pow k,]} returns the submatrix with row $k$ removed. \item \kbd{M[,\pow k]} returns the submatrix with column $k$ removed. \noindent Finally, \item \kbd{M[i..j, k]} returns the \typ{COL} built from the $k$-th column (entries $i$ to $j$). \item \kbd{M[\pow i, k]} returns the \typ{COL} built from the $k$-th column (entry $i$ removed). \item \kbd{M[k, i..j]} returns the \typ{VEC} built from the $k$-th row (entries $i$ to $j$). \item \kbd{M[k, \pow i]} returns the \typ{VEC} built from the $k$-th row (entry $i$ removed). \bprog ? M = [1,2,3;4,5,6;7,8,9]; ? M[1..2, 2..3] %2 = [2 3] [5 6] ? M[1..2,] %3 = [1 2 3] [4 5 6] ? M[,2..3] %4 = [2 3] [5 6] [8 9] @eprog All this is recursive, so if \kbd{M} is a matrix of matrices of \dots, an expression such as \kbd{M[1,1][,3][4] = 1} is perfectly valid (and actually identical to \kbd{M[1,1][4,3] = 1}), assuming that all matrices along the way have compatible dimensions. \misctitle{Technical note (design flaw)} Matrices are internally represented as a vector of columns. All matrices with $0$ columns are thus represented by the same object (internally, an empty vector), and there is no way to distinguish between them. Thus it is not possible to create or represent matrices with zero columns and an actual nonzero number of rows. The empty matrix \kbd{[;]} is handled as though it had an arbitrary number of rows, exactly as many as needed for the current computation to make sense: \bprog ? [1,2,3; 4,5,6] * [;] %1 = [;] @eprog\noindent The empty matrix on the first line is understood as a $3\times 0$ matrix, and the result as a $2\times 0$ matrix. On the other hand, it is possible to create matrices with a given positive number of columns, each of which has zero rows, e.g.~using \kbd{Mat} as above or using the \kbd{matrix} function. Note that although the internal representation is essentially the same, a row vector of column vectors is \emph{not} a matrix; for example, multiplication will not work in the same way. It is easy to go from one representation to the other using \tet{Vec} / \tet{Mat}, though: \bprog ? [1,2,3;4,5,6] %1 = [1 2 3] [4 5 6] ? Vec(%) %2 = [[1, 4]~, [2, 5]~, [3, 6]~] ? Mat(%) %3 = [1 2 3] [4 5 6] @eprog \subsec{Lists (\typ{LIST})}% \sidx{list}\kbdsidx{t_LIST} Lists can be input directly, as in \kbd{List([1,2,3,4])}; but in most cases, one creates an empty list, then appends elements using \kbd{listput}: \bprog ? a = List(); listput(a,1); listput(a,2); ? a %2 = List([1, 2]) @eprog\noindent Elements can be accessed directly as with the vector types described above. \subsec{Strings (\typ{STR})}% \sidx{string}\sidx{character string}\kbdsidx{t_STR} To enter a string, enclose it between double quotes \kbd{"}, like this: \kbd{"this is a string"}. The function \kbd{Str} can be used to transform any object into a string. \subsec{Small vectors (\typ{VECSMALL})}% \kbdsidx{t_VECSMALL} This is an internal type, used to code in an efficient way vectors containing only small integers, such as permutations. Most \kbd{gp} functions will refuse to operate on these objects. \subsec{Functions (\typ{CLOSURE})}% \kbdsidx{t_CLOSURE} We will explain this at length in \secref{se:user_defined}. For the time being, suffice it to say that functions can be assigned to variables, as any other object, and the following equivalent basic forms are available to create new ones \bprog f = (x,y) -> x^2 + y^2 f(x,y) = x^2 + y^2 @eprog \subsec{Error contexts (\typ{ERROR})}% \kbdsidx{t_ERROR} An object of this type is created whenever an error occurs: it contains some information about the error and the error context. Usually, an appropriate error is printed immediately, the computation is aborted, and GP enters the ``break loop'': \bprog ? 1/0; 1 + 1 *** at top-level: 1/0;1+1 *** ^------ *** _/_: division by a non-invertible object *** Break loop: type 'break' to go back to the GP prompt @eprog\noindent Here the computation is aborted as soon as we try to evaluate $1/0$, and $1 + 1$ is never executed. Exceptions can be trapped using \tet{iferr}, however: we can evaluate some expression and either recover an ordinary result (no error occurred), or an exception (an error did occur). \bprog ? i = Mod(6,12); iferr(1/i, E, print(E)); 1 + 1 error("impossible inverse modulo: Mod(6, 12).") %1 = 2 @eprog\noindent One can ignore the exception, print it as above, or extract non trivial information from the error context: \bprog ? i = Mod(6,12); iferr(1/i, E, print(component(E,1))); Mod(6, 12) @eprog\noindent We can also rethrow the exception: \kbd{error(E)}. \subsec{Infinity (\typ{INFINITY})}% \kbdsidx{t_INFINITY} There are only two objects of this type \kbd{+oo} and \kbd{-oo}, representing $\pm\infty$. This type only contain only two elements \kbd{oo} and \kbd{-oo}, They are used in functions sur as \kbd{intnum} or \kbd{polrootsreal}, to encode infinite real intervals. These objects can only be negated and compared to real numbers (\typ{INT}, \typ{REAL}, \typ{FRAC}), but not included in any computation, i.e.~\kbd{1+oo} is an error, not kbd{oo} again. \section{GP operators}\label{se:operators} \noindent Loosely speaking, an \idx{operator} is a function, usually attached to basic arithmetic operations, whose name contains only non-alphanumeric characters. For instance \kbd{+} or \kbd{-}, but also \kbd{=} or \kbd{+=}, or even \kbd{[ ]} (the selection operator). As all functions, operators take arguments, and return a value; \emph{assignment} operators also have side effects: besides returning a value, they change the value of some variable. Each operator has a fixed and unchangeable priority, which means that, in a given expression, the operations with the highest priority is performed first. Unless mentioned otherwise, operators at the same priority level are left-associative (performed from left to right), unless they are assignments, in which case they are right-associative. Anything enclosed between parenthesis is considered a complete subexpression, and is resolved recursively, independently of the surrounding context. For instance, \bprog a + b + c --> (a + b) + c \\@com left-associative a = b = c --> a = (b = c) \\@com right-associative @eprog\noindent Assuming that \var{op}$_1$, \var{op}$_2$, \var{op}$_3$ are binary operators with increasing priorities (think of \kbd{+}, \kbd{*}, \kbd{\pow}), $$ x~\var{op}_1~y~\var{op}_2~z~\var{op}_2~x~\var{op}_3~y $$ is equivalent to $$ x~\var{op}_1~((y~\var{op}_2~z)~\var{op}_2~ (x~\var{op}_3~y)).$$ GP contains many different operators, either unary (having only one argument) or binary, plus a few special selection operators. Unary operators are defined as either \emph{prefix} or \emph{postfix}, meaning that they respectively precede (\var{op}~$x$) and follow ($x$~\var{op}) their single argument. Some symbols are syntactically correct in both positions, like \kbd{!}, but then represent different operators: the \kbd{!} symbol represents the negation and factorial operators when in prefix and postfix position respectively. Binary operators all use the (infix) syntax $x$~\var{op}~$y$. Most operators are standard (\kbd{+}, \kbd{\%}, \kbd{=}), some are borrowed from the C language (\kbd{++}, \kbd{<<}), and a few are specific to GP (\kbd{\bs}, \kbd{\#}). Beware that some GP operators differ slightly from their C counterparts. For instance, GP's postfix \kbd{++} returns the \emph{new} value, like the prefix \kbd{++} of~C, and the binary shifts \kbd{<<}, \kbd{>>} have a priority which is different from (higher than) that of their C counterparts. When in doubt, just surround everything by parentheses; besides, your code will be more legible. \noindent Here is the list of available operators, ordered by decreasing \idx{priority}, binary and left-associative unless mentioned otherwise. An expression is an \tev{lvalue} if something can be assigned to it. (The name comes from left-value, to the left of a \kbd{=} operator; e.g. \kbd{x}, or \kbd{v[1]} are lvalues, but \kbd{x + 1} is not.) \def\point#1{\noindent\item #1\hfill\break\indent\strut} \point{Priority 14} % \kbd{:} as in \kbd{x:small}, is used to indicate to the GP2C compiler that the variable on the left-hand side always contains objects of the type specified on the right hand-side (here, a small integer) in order to produce more efficient or more readable C code. This is ignored by GP. % \point{Priority 13} \kbd{( )} is the function call operator. If $f$ is a closure and \var{args} is a comma-separated list of arguments (possibly empty), $f\kbd{(\var{args})}$ evaluates $f$ on those arguments. \point{Priority 12} % \kbd{++} and \kbd{--} (unary, postfix): if $x$ is an \tet{lvalue}, \kbd{$x$++} assigns the value $x+1$ to $x$, then returns the new value of $x$. This corresponds to the C statement \kbd{++$x$}: there is no prefix \kbd{++} operator in GP. \kbd{$x$--} does the same with $x-1$. These operators are not associative, i.e. \kbd{x++++} is invalid, since \kbd{x++} is not an lvalue. \point{Priority 11} % \kbd{.}\var{member} (unary, postfix): \kbd{$x$.\var{member}} extracts \var{member} from structure $x$ (see~\secref{se:member}). \kbd{[ ]} is the selection operator. \kbd{$x$[$i$]} returns the $i$-th component of vector $x$; \kbd{$x$[$i$,$j$]}, \kbd{$x$[,$j$]} and \kbd{$x$[$i$,]} respectively return the entry of coordinates $(i,j)$, the $j$-th column, and the $i$-th row of matrix $x$. If the assignment operator (\kbd{=}) immediately follows a sequence of selections, it assigns its right hand side to the selected component. E.g \kbd{x[1][1] = 0} is valid; but beware that \kbd{(x[1])[1] = 0} is not (because the parentheses force the complete evaluation of \kbd{x[1]}, and the result is not modifiable). \point{Priority 10} % \kbd{'} (unary, postfix): derivative with respect to the main variable. If $f$ is a function (\typ{CLOSURE}), $f'$ is allowed and defines a new function, which will perform \idx{numerical derivation} when evaluated at a scalar $x$; this is defined as $(f(x+\varepsilon) - f(x-\varepsilon)) / 2\varepsilon$ for a suitably small epsilon depending on current precision. \bprog ? (x^2 + y*x + y^2)' \\@com derive with respect to main variable \kbd{x} %1 = 2*x + y ? SIN = cos' %2 = cos' ? SIN(Pi/6) \\@com numerical derivation %3 = -0.5000000000000000000000000000 ? cos'(Pi/6) \\@com works directly: no need for intermediate \kbd{SIN} %4 = -0.5000000000000000000000000000 @eprog \strut\kbd{\til} (unary, postfix): vector/matrix transpose. \kbd{!} (unary, postfix): factorial. $x\kbd{!}=x(x-1)\cdots 1$. \kbd{!} (unary, prefix): logical \var{not}. \kbd{!$x$} returns $1$ if $x$ is equal to $0$ (specifically, if \kbd{gequal0($x$)==1}), and $0$ otherwise. \point{Priority 9} % \kbd{\#} (unary, prefix): cardinality; \kbd{\#$x$} returns \kbd{length($x$)}. \point{Priority 8} % \kbd{\pow}: powering. This operator is right associative: \kbd{2 \pow 3\pow 4} is understood as \kbd{2 \pow (3\pow 4)}. \point{Priority 7} % \kbd{+}, \kbd{-} (unary, prefix): \kbd{-} toggles the sign of its argument, \kbd{+} has no effect whatsoever. \point{Priority 6} % \kbd{*}: multiplication. \kbd{/}: exact division (\kbd{3/2} yields $3/2$, not $1.5$). \kbd{\bs}, \kbd{\%}: Euclidean quotient and remainder, i.e.~if $x = qy + r$, then $\kbd{x \b{ } y} = q$, $\kbd{x\%y} = r$. If $x$ and $y$ are scalars, then $q$ is an integer and $r$ satisfies $0\le r < |y|$; if $x$ and $y$ are polynomials, then $q$ and $r$ are polynomials such that $\deg r< \deg y$ and the leading terms of $r$ and $x$ have the same sign. \kbd{\bs/}: rounded Euclidean quotient for integers (rounded towards $+\infty$ when the exact quotient would be a half-integer). \kbd{<<}, \kbd{>>}: left and right binary shift. By definition, \kbd{x<0$, and $\kbd{truncate}(x 2^{-n})$ otherwise. Right shift is defined by \kbd{x>>n}$~=~$\kbd{x<<(-n)}. \point{Priority 5} % \kbd{+}, \kbd{-}: addition/subtraction. \point{Priority 4} % \kbd{<}, \kbd{>}, \kbd{<=}, \kbd{>=}: the usual comparison operators, returning 1 for \kbd{true} and 0 for \kbd{false}. For instance, \kbd{x<=1} returns $1$ if $x\le 1$ and $0$ otherwise. \kbd{<>}, \kbd{!=}: test for (exact) inequality. \kbd{==}: test for (exact) equality. \typ{QFR} having the same coefficients but a different distance component are tested as equal. \kbd{===}: test whether two objects are identical component-wise. This is stricter than \kbd{==}: for instance, the integer 0, a 0 polynomial or a vector with 0 entries, are all tested equal by \kbd{==}, but they are not identical. \point{Priority 3} % \kbd{\&\&}: logical \var{and}. \kbd{||}: logical (inclusive) \var{or}. Any sequence of logical \var{or} and \var{and} operations is evaluated from left to right, and aborted as soon as the final truth value is known. Thus, for instance, \bprog x == 0 || test(1/x) @eprog\noindent will never produce an error since \kbd{test(1/x)} is not even evaluated when the first test is true (hence the final truth value is true). Similarly \bprog type(p) == "t_INT" && isprime(p) @eprog\noindent does not evaluate \kbd{isprime(p)} if \kbd{p} is not an integer. \point{Priority 2} % \kbd{=} (assignment, \var{lvalue} \kbd{=} \var{expr}). The result of \kbd{x~=~$y$} is the value of the expression~$y$, which is also assigned to the variable~\kbd{x}. This assignment operator is right-associative. This is \emph{not} the equality test operator; a statement like \kbd{x~=~1} is always true (i.e.~non-zero), and sets \kbd{x} to~1; the equality test would be \kbd{x == 1}. The right hand side of the assignment operator is evaluated before the left hand side. It is crucial that the left hand-side be an \var{lvalue} there, it avoids ambiguities in expressions like \kbd{1 + x = 1}. The latter evaluates as \kbd{1 + (x = 1)}, not as \kbd{(1 + x) = 1}, even though the priority of \kbd{=} is lower than the priority of \kbd{+}: \kbd{1 + x} is not an lvalue. If the expression cannot be parsed in a way where the left hand side is an lvalue, raise an error. \bprog ? x + 1 = 1 *** syntax error, unexpected '=', expecting $end or ';': x+1=1 *** ^-- @eprog\noindent Assignment to all variables is a deep copy: after $x = y$, modifying a component of $y$ will \emph{not} change $x$. To globals it is a full copy to the heap. Space used by local objects in local variables is released when they go out of scope or when the value changes in local scope. Assigning a value to a vector or matrix entry allocates room for that entry only (on the heap). \leavevmode \kbd{\var{op}=}, where \var{op} is any binary operator among \kbd{+}, \kbd{-}, \kbd{*}, \kbd{\%}, \kbd{/}, \kbd{\bs}, \kbd{\bs/}, \kbd{<<}, or \kbd{>>} (composed assignment \var{lvalue} \var{op}\kbd{=} \var{expr}). The expression \kbd{x~\var{op}=~$y$} assigns $(\kbd{x}~\var{op}~y)$ to~\kbd{x}, and returns the new value of~\kbd{x}. The result is \emph{not} an \tev{lvalue}; thus \bprog (x += 2) = 3 @eprog\noindent is invalid. These assignment operators are right-associative: \bprog ? x = 'x; x += x *= 2 %1 = 3*x @eprog \point{Priority 1} \kbd{->} (function definition): \kbd{(\var{vars})->\var{expr}} returns a function object, of type \typ{CLOSURE}. \misctitle{Remark} Use the \var{op}\kbd{=} operators as often as possible since they make complex assignments more legible. Compare \bprog v[i+j-1] = v[i+j-1] + 1 --> v[i+j-1]++ M[i,i+j] = M[i,i+j] * 2 --> M[i,i+j] *= 2 @eprog \misctitle{Remark about efficiency} the operators \kbd{++} and \kbd{--} are usually a little more efficient than their expended counterpart: \bprog ? N = 10^7; ? i = 0; for(k = 1, N, i=i+1) time = 949 ms. ? i = 0; for(k = 1, N, i++) time = 933 ms. @eprog\noindent On the other hand, this is not the case for the \var{op}\kbd{=} operators which may even be a little less efficient: \bprog ? i = 0; for(k = 1, N, i=i+10) time = 949 ms. ? i = 0; for(k = 1, N, i+=10) time = 1,064 ms. @eprog \section{Variables and symbolic expressions}\sidx{variable}\label{se:varsymb} In this section we use \emph{variable} in the standard mathematical sense, symbols representing algebraically independent elements used to build rings of polynomials and power series, and explain the all-important concept of \emph{variable priority}. In the next \secref{se:scope}, we shall no longer consider only free variables, but adopt the viewpoint of computer programming and assign values to these symbols: (bound) variables are names attached to values in a given scope. \subsec{Variable names}\label{se:varname} A valid name starts with a letter, followed by any number of keyword characters: \kbd{\_} or alphanumeric characters ([\kbd{A-Za-z0-9}]). The built-in function names are reserved and cannot be used; see the list with \b{c}, including the constants \kbd{Pi}, \kbd{Euler}, \kbd{Catalan}, $\kbd{I}=\sqrt{-1}$ and $\kbd{oo} = \infty$. GP names are case sensitive. For instance, the symbol \kbd{i} is perfectly safe to use, and will not be mistaken for $\kbd{I} = \sqrt{-1}$; analogously, \kbd{o} is not synonymous to \kbd{O}. In GP you can use up to 16383 variable names (up to 65535 on 64-bit machines). If you ever need thousands of variables and this becomes a serious limitation, you should probably be using vectors instead: e.g. instead of variables \kbd{X1}, \kbd{X2}, \kbd{X3}, \dots, you might equally well store their values in \kbd{X[1]}, \kbd{X[2]}, \kbd{X[3]}, \dots \subsec{Variables and polynomials}\sidx{free variable} The quote operator \kbd{'t} registers a new \emph{free variable} with the interpreter, which will be written as \kbd{t}, and evaluates to a monomial of degree $1$ in the said variable. \misctitle{Caveat} For reasons of backward compatibility, there is no such thing as an ``unbound'' (uninitialized) variable in GP. If you use a valid variable name in an expression, \kbd{t} say, for the first time \emph{before} assigning a value into it, it is interpreted as \kbd{'t} rather than raising an exception. One should not rely on this feature in serious programs, which would otherwise break if some unexpected assignment (e.g. \kbd{t = 1}) occurs: use \kbd{'t} directly or \kbd{t = 't} first, then \kbd{t}. A statement like \kbd{t = 't} in effect restores \kbd{t} as a free variable. % \bprog ? t = 't; t^2 + 1 %1 = t^2 + 1 ? t = 2; t^2 + 1 %2 = 5 ? %1 %3 = t^2 + 1 ? eval(%1) %4 = 5 @eprog\noindent In the above, we initialize \kbd{t} to a monomial, then bind it to $2$. Assigning a value to a polynomial variable does not affect previous expressions involving it; to take into account the new variable's value, one must force a new evaluation, using the function \kbd{eval} (see \secref{se:eval}). \misctitle{Caveat2} The use of an explicit quote operator avoids the following kind of problems: \bprog ? t = 't; p = t^2 + 1; subst(p, t, 2) %1 = 5 ? t = 2; ? subst(p, t, 3) \\@com \kbd{t} is no longer free: it evaluates to 2 *** at top-level: subst(p,t,3) *** ^---- *** variable name expected. ? subst(p, 't, 3) \\ OK %3 = 10 @eprog \subsec{Variable priorities, multivariate objects}\sidx{variable (priority)}\label{se:priority} A multivariate polynomial in PARI is just a polynomial (in one variable), whose coefficients are themselves polynomials, arbitrary but for the fact that they do not involve the main variable. (PARI currently has no sparse representation for polynomials, listing only non-zero monomials.) All computations are then done formally on the coefficients as if the polynomial was univariate. This is not symmetrical. So if I enter \kbd{'x + 'y} in a clean session, what happens? This is understood as $$ x^1 + (y^1 + 0*y^0)*x^0 \in (\Z[y])[x] $$ but how do we know that $x$ is ``more important'' than $y$ ? Why not $y^1 + x*y^0$, which is the same mathematical entity after all? The answer is that variables are ordered implicitly by the interpreter: when a new identifier (e.g~$x$, or $y$ as above) is input, the corresponding variable is registered as having a strictly lower priority than any variable in use at this point\footnote{*}{This is not strictly true: the variables $x$ and $y$ are predefined, and satisfy $x > y$. Variables of higher priority than $x$ can be created using \tet{varhigher}.}% . To see the ordering used by \kbd{gp} at any given time, type \kbd{variable()}.\kbdsidx{variable} Given such an ordering, multivariate polynomials are stored so that the variable with the highest priority is the main variable. And so on, recursively, until all variables are exhausted. A different storage pattern (which could only be obtained via \kbd{libpari} programming and low-level constructors) would produce an invalid object, and eventually a disaster. In any case, if you are working with expressions involving several variables and want to have them ordered in a specific manner in the internal representation just described, the simplest is just to write down the variables one after the other under \kbd{gp} before starting any real computations. You may also define variables from your \tet{gprc} to have a consistent ordering of common variable names in all your \kbd{gp} sessions, e.g read in a file \kbd{variables.gp} containing \bprog 'x; 'y; 'z; 't; 'a; @eprog\noindent There is no way to change the priority of existing variables, but you may always create new ones with well-defined priorities using \kbd{varhigher} or \kbd{varlower}. \misctitle{Important note} PARI allows Euclidean division of multivariate polynomials, but assumes that the computation takes place in the fraction field of the coefficient ring (if it is not an integral domain, the result will a priori not make sense). This can become tricky. For instance assume $x$ has highest priority, then $y$: \bprog ? x % y %1 = 0 ? y % x %2 = y \\@com these two take place in $\Q(y)[x]$ ? x * Mod(1,y) %3 = Mod(1, y)*x \\@com in $(\Q(y)/y\Q(y))[x] \sim \Q[x]$ ? Mod(x,y) %4 = 0 @eprog \noindent In the last example, the division by $y$ takes place in $\Q(y)[x]$, hence the \kbd{Mod} object is a coset in $(\Q(y)[x]) / (y\Q(y)[x])$, which is the null ring since $y$ is invertible! So be very wary of variable ordering when your computations involve implicit divisions and many variables. This also affects functions like \tet{numerator}/\tet{denominator} or \tet{content}: \bprog ? denominator(x / y) %1 = 1 ? denominator(y / x) %2 = x ? content(x / y) %3 = 1/y ? content(y / x) %4 = y ? content(2 / x) %5 = 2 @eprog \noindent Can you see why? Hint: $x/y = (1/y) * x$ is in $\Q(y)[x]$ and denominator is taken with respect to $\Q(y)(x)$; $y/x = (y*x^0) / x$ is in $\Q(y)(x)$ so $y$ is invertible in the coefficient ring. On the other hand, $2/x$ involves a single variable and the coefficient ring is simply $\Z$. These problems arise because the variable ordering defines an \emph{implicit} variable with respect to which division takes place. This is the price to pay to allow \kbd{\%} and \kbd{/} operators on polynomials instead of requiring a more cumbersome \kbd{divrem($x$, $y$, \var{var})} (which also exists). Unfortunately, in some functions like \tet{content} and \tet{denominator}, there is no way to set explicitly a main variable like in \tet{divrem} and remove the dependence on implicit orderings. This will hopefully be corrected in future versions. \subsec{Multivariate power series} Just like multivariate polynomials, power series are fundamentally single-variable objects. It is awkward to handle many variables at once, since PARI's implementation cannot handle multivariate error terms like $O(x^i y^j)$. (It can handle the polynomial $O(y^j) \times x^i$ which is a very different thing, see below.) The basic assumption in our model is that if variable $x$ has higher priority than $y$, then $y$ does not depend on $x$: setting $y$ to a function of $x$ after some computations with bivariate power series does not make sense a priori. This is because implicit constants in expressions like $O(x^i)$ depend on $y$ (whereas in $O(y^j)$ they can not depend on $x$). For instance \bprog ? O(x) * y %1 = O(x) ? O(y) * x %2 = O(y)*x @eprog\noindent Here is a more involved example: \bprog ? A = 1/x^2 + 1 + O(x); B = 1/x + 1 + O(x^3); ? subst(z*A, z, B) %2 = x^-3 + x^-2 + x^-1 + 1 + O(x) ? B * A %3 = x^-3 + x^-2 + x^-1 + O(1) ? z * A %4 = z*x^-2 + z + O(x) @eprog\noindent The discrepancy between \kbd{\%2} and \kbd{\%3} is surprising. Why does \kbd{\%2} contain a spurious constant term, which cannot be deduced from the input? Well, we ignored the rule that forbids to substitute an expression involving high-priority variables to a low-priority variable. The result \kbd{\%4} is correct according to our rules since the implicit constant in $O(x)$ may depend on $z$. It is obviously wrong if $z$ is allowed to have negative valuation in $x$. Of course, the correct error term should be $O(xz)$, but this is not possible in PARI. \section{Variables and Scope}\sidx{variable scope}\label{se:scope} This section is rather technical, and strives to explain potentially confusing concepts. Skip to the last subsection for practical advice, if the next discussion does not make sense to you. After learning about user functions, study the example in \secref{se:bewarescope} then come back. \misctitle{Definitions} % rather not make it a section to allow for ??my A \emph{scope} is an enclosing context where names and values are attached. A user's function body, the body of a loop, an individual command line, all define scopes; the whole program defines the \emph{global} scope. The argument of \tet{eval} is evaluated in the enclosing scope. Variables are bound to values within a given scope. This is traditionally implemented in two different ways: \item\sidx{lexical scoping} lexical (or static) scoping: the binding makes sense within a given block of program text. The value is private to the block and may not be accessed from outside. Where to find the value is determined at compile time. \item\sidx{dynamic scoping} dynamic scoping: introducing a local variable, say \kbd{x}, pushes a new value on a stack attached to the name \kbd{x} (possibly empty at this point), which is popped out when the control flow leaves the scope. Evaluating \kbd{x} in any context, possibly outside of the given block, always yields the top value on this dynamic stack. GP implements both lexical and dynamic scoping, using the keywords% \footnote{*}{The names are borrowed from the \tet{Perl} scripting language.} \tet{my} (lexical) and \tet{local} (dynamic): \bprog x = 0; f() = x g() = my(x = 1); f() h() = local(x = 1); f() @eprog\noindent The function \kbd{g} returns 0 since the global \kbd{x} binding is unaffected by the introduction of a private variable of the same name in \kbd{g}. On the other hand, \kbd{h} returns 1; when it calls \kbd{f()}, the binding stack for the \kbd{x} identifier contains two items: the global binding to 0, and the binding to 1 introduced in \kbd{h}, which is still present on the stack since the control flow has not left \kbd{h} yet. \subsec{Scoping rules} Named parameters in a function definition, as well as all loop indices\footnote{**}{ More generally, in all iterative constructs which use a variable name (\kbd{for}, \kbd{prod}, \kbd{sum}, \kbd{vector}, \kbd{matrix}, \kbd{plot}, etc.) the given variable is lexically scoped to the construct's body.}, have lexical scope within the function body and the loop body respectively. \bprog p = 0; forprime (p = 2, 11, print(p)); p \\ prints 0 at the end x = 0; f(x) = x++; f(1) \\ returns 2, and leave global x unaffected (= 0) @eprog\noindent If you exit the loop prematurely, e.g.~using the \kbd{break} statement, you must save the loop index in another variable since its value prior the loop will be restored upon exit. For instance \bprog for(i = 1, n, if (ok(i), break); ); if (i > n, return(failure)); @eprog\noindent is incorrect, since the value of $i$ tested by the $(i > n)$ is quite unrelated to the loop index. One ugly workaround is \bprog for(i = 1, n, if (ok(i), isave = i; break); ); if (isave > n, return(failure)); @eprog\noindent But it is usually more natural to wrap the loop in a user function and use \kbd{return} instead of \kbd{break}: \bprog try() = { for(i = 1, n, if (ok(i), return (i)); ); 0 \\ failure } @eprog A list of variables can be lexically or dynamically scoped (to the block between the declaration and the end of the innermost enclosing scope) using a \kbd{my} or \kbd{local} declaration: \bprog for (i = 1, 10, my(x, y, z, i2 = i^2); \\ temps needed within the loop body ... ) @eprog\noindent Note how the declaration can include (optional) initial values, \kbd{i2 = i\pow 2} in the above. Variables for which no explicit default value is given in the declaration are initialized to $0$. It would be more natural to initialize them to free variables, but this would break backward compatibility. To obtain this behavior, you may explicitly use the quoting operator: \bprog my(x = 'x, y = 'y, z = 'z); @eprog\noindent A more complicated example: \bprog for (i = 1, 3, print("main loop"); my(x = i); \\ local to the outermost loop for (j = 1, 3, my (y = x^2); \\ local to the innermost loop print (y + y^2); x++; ) ) @eprog\noindent When we leave the loops, the values of \kbd{x}, \kbd{y}, \kbd{i}, \kbd{j} are the same as before they were started. Note that \tet{eval} is evaluated in the given scope, and can access values of lexical variables: \bprog ? x = 1; ? my(x = 0); eval("x") %2 = 0 \\@com we see the local \kbd{x} scoped to this command line, not the global one @eprog Variables dynamically scoped using \kbd{local} should more appropriately be called \emph{temporary values} since they are in fact local to the function declaring them \emph{and} any subroutine called from within. In practice, you almost certainly want true private variables, hence should use almost exclusively \kbd{my}. We strongly recommended to explicitly scope (lexically) all variables to the smallest possible block. Should you forget this, in expressions involving such ``rogue'' variables, the value used will be the one which happens to be on top of the value stack at the time of the call; which depends on the whole calling context in a non-trivial way. This is in general \emph{not} what you want. \section{User defined functions}\sidx{user defined functions} \label{se:user_defined} The most important thing to understand about user-defined functions is that they are ordinary GP objects, bound to variables just like any other object. Those variables are subject to scoping rules as any other: while you can define all your functions in global scope, it is usually possible and cleaner to lexically scope your private helper functions to the block of text where they will be needed. Whenever gp meets a construction of the form \kbd{expr(\var{argument list})} and the expression \kbd{expr} evaluates to a function (an object of type \typ{CLOSURE}), the function is called with the proper arguments. For instance, constructions like \kbd{funcs[i](x)} are perfectly valid, assuming \kbd{funcs} is an array of functions. \subsec{Defining a function}\label{se:userfundef} A user function is defined as follows: \kbd{(\var{list of formal variables}) -> \var{seq}}. \noindent The list of formal variables is a comma-separated list of \emph{distinct} variable names and allowed to be empty. It there is a single formal variable, the parentheses are optional. This list corresponds to the list of parameters you will supply to your function when calling it. In most cases you want to assign a function to a variable immediately, as in \bprog R = (x,y) -> sqrt( x^2+y^2 ); sq = x -> x^2; \\@com or equivalently \kbd{(x) -> x\pow2} @eprog\noindent but it is quite possible to define (a priori short-lived) anonymous functions. The trailing semicolon is not part of the definition, but as usual prevents \kbd{gp} from printing the result of the evaluation, i.e. the function object. The construction \kbd{f(\var{list of formal variables}) = \var{seq}} \noindent is available as an alias for \kbd{f = (\var{list of formal variables}) -> \var{seq}} \noindent Using that syntax, it is not possible to define anonymous functions (obviously), and the above two examples become: \bprog R(x,y) = sqrt( x^2+y^2 ); sq(x) = x^2; @eprog\noindent The semicolon serves the same purpose as above: preventing the printing of the resulting function object; compare \bprog ? sq(x) = x^2; \\@com no output ? sq(x) = x^2 \\@com print the result: a function object %2 = (x)->x^2 @eprog\noindent Of course, the sequence \var{seq} can be arbitrarily complicated, in which case it will look better written on consecutive lines, with properly scoped variables: \bprog { f(x0, x1, @dots) = my(t0, t1, @dots); \\@com variables lexically scoped to the function body @dots } @eprog \noindent Note that the following variant would also work: \bprog f(x0, x1, @dots) = { my(t0, t1, @dots); \\@com variables lexically scoped to the function body @dots } @eprog \noindent (the first newline is disregarded due to the preceding \kbd{=} sign, and the others because of the enclosing braces). The \tet{my} statements can actually occur anywhere within the function body, scoping the variables to more restricted blocks than the whole function body. Arguments are passed by value, not as variables: modifying a function's argument in the function body is allowed, but does not modify its value in the calling scope. In fact, a \emph{copy} of the actual parameter is assigned to the formal parameter when the function is called. (This is not litteraly true: a form of copy-on-write is implemented so an object is not duplicated unless modified in the function.) Formal parameters are lexically scoped to the function body. It is not allowed to use the same variable name for different parameters of your function: \bprog ? f(x,x) = 1 *** variable declared twice: f(x,x)=1 *** ^---- @eprog \misctitle{Functions taking an unlimited number of arguments} A function taking an unlimited number of arguments is called \emph{variadic}. To create such a function, use the syntax \kbd{(\var{list of formal variables}, \var{var}[..]) -> \var{seq}} \noindent The parameter \var{var} is replaced by a vector containing all the remaining arguments. \bprog ? f(c[..]) = sum(i=1,#c,c[i]); ? f(1,2,3) %1 = 6 ? sep(s,v[..]) = for(i=1,#v-1,print1(v[i],s)); if (#v, print(v[#v])); ? sep(":", 1, 2, 3) 1:2:3 @eprog \misctitle{Finishing touch} You can add a specific help message for your function using \kbd{addhelp}, but the online help system already handles it. By default \kbd{?\var{name}} will print the definition of the function \var{name}: the list of arguments, as well as their default values, the text of \var{seq} as you input it. Just as \b{c} prints the list of all built-in commands, \b{u} outputs the list of all user-defined functions. \misctitle{Backward compatibility (lexical scope)} Lexically scoped variables were introduced in version~2.4.2. Before that, the formal parameters were dynamically scoped. If your script depends on this behavior, you may use the following trick: replace the initial \kbd{f(x) =} \ by \bprog f(x_orig) = local(x = x_orig) @eprog \misctitle{Backward compatibility (disjoint namespaces)} Before version 2.4.2, variables and functions lived in disjoint namespaces and it was not possible to have a variable and a function share the same name. Hence the need for a \kbd{kill} function allowing to reuse symbols. This is no longer the case. There is now no distinction between variable and function names: we have PARI objects (functions of type \typ{CLOSURE}, or more mundane mathematical entities, like \typ{INT}, etc.) and variables bound to them. There is nothing wrong with the following sequence of assignments: \bprog ? f = 1 \\@com assigns the integer 1 to \kbd{f} %1 = 1; ? f() = 1 \\@com a function with a constant value %2 = ()->1 ? f = x^2 \\@com \kbd{f} now holds a polynomial %3 = x^2 ? f(x) = x^2 \\@com \dots and now a polynomial function %4 = (x)->x^2 ? g(fun) = fun(Pi);\\@com a function taking a function as argument ? g(cos) %6 = -1.000000000000000000000000000 @eprog\noindent Previously used names can be recycled as above: you are just redefining the variable. The previous definition is lost of course. \misctitle{Important technical note} Built-in functions are a special case since they are read-only (you cannot overwrite their default meaning), and they use features not available to user functions, in particular pointer arguments. In the present version \vers{}, it is possible to assign a built-in function to a variable, or to use a built-in function name to create an anonymous function, but some special argument combinations may not be available: \bprog ? issquare(9, &e) %1 = 1 ? e %2 = 3 ? g = issquare; ? g(9) %4 = 1 ? g(9, &e) \\@com pointers are not implemented for user functions *** unexpected &: g(9,&e) *** ^--- @eprog \subsec{Function call, Default arguments} You may now call your function, as in \kbd{f(1,2)}, supplying values for the formal variables. The number of parameters actually supplied may be \emph{less} than the number of formal variables in the function definition. An uninitialized formal variable is given an implicit default value of (the integer)~0, i.e. after the definition \bprog f(x, y) = ... @eprog\noindent you may call \kbd{f(1, 2)}, supplying values for the two formal parameters, or for example \settabs\+\indent&xxxxxxxxx& equivalent to xxxx &\cr \+& \kbd{f(2)} & equivalent to &\kbd{f(2,0)},\cr \+& \kbd{f()} & & \kbd{f(0,0)},\cr \+& \kbd{f(,3)} & &\kbd{f(0,3)}. (``Empty argument'' trick)\cr \noindent This \emph{implicit} default value of $0$, is actually deprecated and setting \bprog default(strictargs, 1) @eprog\noindent allows to disable it (see \secref{se:def,strictargs}).\kbdsidx{strictargs} The recommended practice is to \emph{explicitly} set a default value: in the function definition, you can append \kbd{=}\var{expr} to a formal parameter, to give that variable a default value. The expression gets evaluated the moment the function is called, and may involve the preceding function parameters: a default value for $x_i$ may involve $x_j$ for $j < i$. For instance, after \bprog f(x = 1, y = 2, z = y+1) = .... @eprog\noindent typing in \kbd{f(3,4)} would give you \kbd{f(3,4,5)}. In the rare case when you want to set some far away argument, and leave the defaults in between as they stand, use the ``empty argument'' trick: \kbd{f(6,,1)} would yield \kbd{f(6,2,1)}. Of course, \kbd{f()} by itself yields \kbd{f(1,2,3)} as was to be expected. In short, the argument list is filled with user supplied values, in order. A comma or closing parenthesis, where a value should have been, signals we must use a default value. When no input arguments are left, the defaults are used instead to fill in remaining formal parameters. A final example: \bprog f(x, y=2, z=3) = print(x, ":", y, ":", z); @eprog \noindent defines a function which prints its arguments (at most three of them), separated by colons. \bprog ? f(6,7) 6:7:3 ? f(,5) 0:5:3 ? f() 0:2:3 @eprog\noindent If \kbd{strictargs} is set (recommended), $x$ is now a mandatory argument, and the above becomes: \bprog ? default(strictargs,1) ? f(6,7) 6:7:3 ? f(,5) *** at top-level: f(,5) *** ^----- *** in function f: x,y=2,z=3 *** ^--------- *** missing mandatory argument 'x' in user function. @eprog \misctitle{Example} We conclude with an amusing example, intended to illustrate both user-defined functions and the power of the \kbd{sumalt} function. Although the \idx{Riemann zeta-function} is included (as \kbd{zeta}) among the standard functions, let us assume that we want to check other implementations. Since we are highly interested in the critical strip, we use the classical formula $$ (2^{1-s} - 1)\zeta(s) = \sum_{n\geq 1} (-1)^n n^{-s}, \qquad\Re s > 0.$$ The implementation is obvious:\sidx{zeta function} \bprog ZETA(s) = sumalt(n=1, (-1)^n*n^(-s)) / (2^(1-s) - 1) @eprog \noindent Note that \kbd{n} is automatically lexically scoped to the \kbd{sumalt} ``loop'', so that it is unnecessary to add a \kbd{my(n)} declaration to the function body. Surprisingly, this gives very good accuracy in a larger region than expected: \bprog ? check = z -> ZETA(z) / zeta(z); ? check(2) %1 = 1.000000000000000000000000000 ? check(200) %2 = 1.000000000000000000000000000 ? check(0) %3 = 0.9999999999999999999999999994 ? check(-5) %4 = 1.00000000000000007549266557 ? check(-11) %5 = 0.9999752641047824902660847745 ? check(1/2+14.134*I) \\@com very close to a non-trivial zero %6 = 1.000000000000000000003747432 + 7.62329066 E-21*I ? check(-1+10*I) %7 = 1.000000000000000000000002511 + 2.989950968 E-24*I @eprog\noindent Now wait a minute; not only are we summing a series which is certainly no longer alternating (it has complex coefficients), but we are also way outside of the region of convergence, and still get decent results! No programming mistake this time: \kbd{sumalt} is a ``magic'' function\footnote{*}{\kbd{sumalt} is heuristic, but its use can be rigorously justified for a given function, in particular our $\zeta(s)$ formula. Indeed, Peter Borwein (\emph{An efficient algorithm for the Riemann zeta function}, CMS Conf.~Proc.~{\bf 27} (2000), pp.~29--34) proved that the formula used in \kbd{sumalt} with $n$ terms computes $(1-2^{1-s})\zeta(s)$ with a relative error of the order of $(3+\sqrt{8})^{-n}|\Gamma(s)|^{-1}$.}, providing very good convergence acceleration; in effect, we are computing the analytic continuation of our original function. To convince ourselves that \kbd{sumalt} is a non-trivial implementation, let us try a simpler example: \bprog ? sum(n=1, 10^7, (-1)^n/n, 0.) / (-log(2)) \\@com approximates the well-known formula time = 7,417 ms. %1 = 0.9999999278652515622893405457 ? sumalt(n=1, (-1)^n/n) / (-log(2)) \\@com accurate and fast time = 0 ms. %2 = 1.000000000000000000000000000 @eprog\noindent No, we are not using a powerful simplification tool here, only numerical computations. Remember, PARI is not a computer algebra system! \subsec{Beware scopes}\label{se:bewarescope} Be extra careful with the scopes of variables. What is wrong with the following definition? \bprog FirstPrimeDiv(x) = { my(p); forprime(p=2, x, if (x%p == 0, break)); p } ? FirstPrimeDiv(10) %1 = 0 @eprog\noindent \misctitle{Hint} The function body is equivalent to \bprog { my(newp = 0); forprime(p=2, x, if (x%p == 0, break)); newp } @eprog\noindent \misctitle{Detailed explanation} The index \kbd{p} in the \kbd{forprime} loop is lexically scoped to the loop and is not visible to the outside world. Hence, it will not survive the \kbd{break} statement. More precisely, at this point the loop index is restored to its preceding value. The initial \kbd{my(p)}, although well-meant, adds to the confusion: it indeed scopes \kbd{p} to the function body, with initial value $0$, but the \kbd{forprime} loop introduces \emph{another} variable, unfortunately also called \kbd{p}, scoped to the loop body, which shadows the one we wanted. So we always return $0$, since the value of the \kbd{p} scoped to the function body never changes and is initially $0$. To sum up, the routine returns the \kbd{p} declared local to it, not the one which was local to \kbd{forprime} and ran through consecutive prime numbers. Here is a corrected version: \bprog ? FirstPrimeDiv(x) = forprime(p=2, x, if (x%p == 0, return(p))) @eprog \subsec{Recursive functions} Recursive functions\sidx{recursion} can easily be written as long as one pays proper attention to variable scope. Here is an example, used to retrieve the coefficient array of a multivariate polynomial (a non-trivial task due to PARI's unsophisticated representation for those objects): \sidx{multivariate polynomial} \bprog coeffs(P, nbvar) = { if (type(P) != "t_POL", for (i=1, nbvar, P = [P]); return (P) ); vector(poldegree(P)+1, i, coeffs(polcoeff(P, i-1), nbvar-1)) } @eprog \noindent If $P$ is a polynomial in $k$ variables, show that after the assignment {\tt v = coeffs(P,k)}, the coefficient of $x_1^{n_1}\dots x_k^{n_k}$ in P is given by {\tt v[$n_1$+1][\dots][$n_k$+1]}. The operating system automatically limits the \idx{recursion depth}: \sidx{deep recursion} \bprog ? dive(n) = dive(n+1) ? dive(0); *** [...] at: dive(n+1) *** ^--------- *** in function dive: dive(n+1) *** ^--------- \\@com (last 2 lines repeated 19 times) *** deep recursion. @eprog\noindent There is no way to increase the recursion limit (which may be different on your machine) from within \kbd{gp}. To increase it before launching \kbd{gp}, you can use \tet{ulimit} or \tet{limit}, depending on your shell, and raise the process available stack space (increase \tet{stacksize}). \subsec{Function which take functions as parameters} This is done as follows: \bprog ? calc(f, x) = f(x) ? calc(sin, Pi) %2 = -5.04870979 E-29 ? g(x) = x^2; ? calc(g, 3) %4 = 9 @eprog \noindent If we do not need \kbd{g} elsewhere, we should use an anonymous function here, \kbd{calc(x->x\pow 2, 3)}. Here is a variation: \bprog ? funs = [cos, sin, tan, x->x^3+1]; \\@com an array of functions ? call(i, x) = funs[i](x) @eprog\noindent evaluates the appropriate function on argument \kbd{x}, provided $1\leq i\leq 4$. Finally, a more useful example: \bprog APPLY(f, v) = vector(#v, i, f(v[i])) @eprog\noindent applies the function \kbd{f} to every element in the vector \kbd{v}. (The built-in function \kbd{apply} is more powerful since it also applies to lists and matrices.) \subsec{Defining functions within a function} Defining a single function is easy: \bprog init(x) = (add = y -> x+y); @eprog\noindent Basically, we are defining a global variable \kbd{add} whose value is the function \kbd{y->x+y}. The parentheses were added for clarity and are not mandatory. \bprog ? init(5); ? add(2) %2 = 7 @eprog\noindent A more refined approach is to avoid global variables and \emph{return} the function: \bprog init(x) = y -> x+y add = init(5) @eprog\noindent Then \kbd{add(2)} still returns 7, as expected! Of course, if \kbd{add} is in global scope, there is no gain, but we can lexically scope it to the place where it is useful: \bprog my ( add = init(5) ); @eprog How about multiple functions then? We can use the last idea and return a vector of functions, but if we insist on global variables? The first idea \bprog init(x) = add(y) = x+y; mul(y) = x*y; @eprog \noindent does not work since in the construction \kbd{f() = }\var{seq}, the function body contains everything until the end of the expression. Hence executing \kbd{init} defines the wrong function \kbd{add} (itself defining a function \kbd{mul}). The way out is to use parentheses for grouping, so that enclosed subexpressions will be evaluated independently: \bprog ? init(x) = ( add(y) = x+y ); ( mul(y) = x*y ); ? init(5); ? add(2) %3 = 7 ? mul(3) %4 = 15 @eprog\noindent This defines two global functions which have access to the lexical variables private to \kbd{init}! The following would work in exactly the same way: \bprog ? init5() = my(x = 5); ( add(y) = x+y ); ( mul(y) = x*y ); @eprog \subsec{Closures as Objects} Contrary to what you might think after the preceding examples, GP's closures may not be used to simulate true ``objects'', with private and public parts and methods to access and manipulate them. In fact, closures indeed incorporate an existing context (they may access lexical variables that existed at the time of their definition), but then may not change it. More precisely, they access a copy, which they are welcome to change, but a further function call still accesses the original context, as it existed at the time the function was defined: \bprog init() = { my(count = 0); inc()=count++; dec()=count--; } ? inc() %1 = 1 ? inc() %2 = 1 ? inc() %3 = 1 @eprog \section{Member functions}\sidx{member functions} \label{se:member} Member functions use the `dot' notation to retrieve information from complicated structures. The built-in structures are \tev{bid}, \tev{ell}, \tev{galois}, \tev{ff}, \tev{nf}, \tev{bnf}, \tev{bnr} and \tev{prid}, which will be described at length in Chapter~3. The syntax \kbd{structure.member} is taken to mean: retrieve \kbd{member} from \kbd{structure}, e.g.~\kbd{E.j} returns the $j$-invariant of the elliptic curve \kbd{E}, or outputs an error message if \kbd{E} is not a proper \tev{ell} structure. To define your own member functions, use the syntax \ \kbd{\var{var}.\var{member} = \var{seq}}, \noindent where the formal variable \var{var} is scoped to the function body \var{seq}. This is of course reminiscent of a user function with a single formal variable \var{var}. For instance, the current implementation of the \kbd{ell} type is a vector, the $j$-invariant being the thirteenth component. It could be implemented as \bprog x.j = { if (type(x) != "t_VEC" || #x < 14, error("not an elliptic curve: " x)); x[13] } @eprog\noindent As for user functions, you can redefine your member functions simply by typing new definitions. On the other hand, as a safety measure, you cannot redefine the built-in member functions, so attempting to redefine \kbd{x.j} as above would in fact produce an error; you would have to call it e.g.~\kbd{x.myj} in order for \kbd{gp} to accept it. \misctitle{Rationale} In most cases, member functions are simple accessors of the form \bprog x.a = x[1]; x.b = x[2]; x.c = x[3]; @eprog\noindent where \kbd{x} is a vector containing relevant data. There are at least three alternative approaches to the above member functions: 1) hardcode \kbd{x[1]}, etc. in the program text, 2) define constant global variables \kbd{AINDEX = 1}, \kbd{BINDEX = 2} and hardcode \kbd{x[AINDEX]}, 3) user functions \kbd{a(x) = x[1]} and so on. Even if 2) improves on 1), these solutions are neither elegant nor flexible, and they scale badly. 3) is a genuine possibility, but the main advantage of member functions is that their namespace is independent from the variables (and functions) namespace, hence we can use very short identifiers without risk. The $j$-invariant is a good example: it would clearly not be a good idea to define \kbd{j(E) = E[13]}, because clashes with loop indices are likely. Beware that there is no guarantee that a built-in member function \emph{is} a simple accessor and it could involve a computation. Thus you should not use them on a constant object in tight loops: store them in a variable before the loop. \misctitle{Note} Typing \b{um} will output all user-defined member functions. \misctitle{Member function names} A valid name starts with a letter followed by any number of keyword characters: \kbd{\_} or alphanumeric characters ([\kbd{A-Za-z0-9}]). The built-in member function names are reserved and cannot be used (see the list with \kbd{?.}). Finally, names starting with \kbd{e} or \kbd{E} followed by a digit are forbidden, due to a clash with the floating point exponent notation: we understand \kbd{1.e2} as $100.000\dots$, not as extracting member \kbd{e2} of object \kbd{1}. \section{Strings and Keywords}\sidx{string}\sidx{keyword} \label{se:strings} \subsec{Strings} GP variables can hold values of type character string (internal type \typ{STR}). This section describes how they are actually used, as well as some convenient tricks (automatic concatenation and expansion, keywords) valid in string context. As explained above, the general way to input a string is to enclose characters between quotes~\kbd{"}. This is the only input construct where whitespace characters are significant: the string will contain the exact number of spaces you typed in. Besides, you can ``escape'' characters by putting a \kbd{\bs} just before them; the translation is as follows \bprog \e: \n: \t: @eprog For any other character $x$, \b{$x$} is expanded to $x$. In particular, the only way to put a \kbd{"} into a string is to escape it. Thus, for instance, \kbd{"\bs"a\bs""} would produce the string whose content is ``a''. This is definitely \emph{not} the same thing as typing \kbd{"a"}, whose content is merely the one-letter string a. You can concatenate two strings using the \tet{concat} function. If either argument is a string, the other is automatically converted to a string if necessary (it will be evaluated first). \bprog ? concat("ex", 1+1) %1 = "ex2" ? a = 2; b = "ex"; concat(b, a) %2 = "ex2" ? concat(a, b) %3 = "2ex" @eprog Some functions expect strings for some of their arguments: \tet{print} would be an obvious example, \tet{Str} is a less obvious but useful one (see the end of this section for a complete list). While typing in such an argument, you will be said to be in \tev{string context}. The rest of this section is devoted to special syntactical tricks which can be used with such arguments (and only here; you will get an error message if you try these outside of string context): \item Writing two strings alongside one another will just concatenate them, producing a longer string. Thus it is equivalent to type in \kbd{"a " "b"} or \kbd{"a b"}. A little tricky point in the first expression: the first whitespace is enclosed between quotes, and so is part of a string; while the second (before the \kbd{"b"}) is completely optional and \kbd{gp} actually suppresses it, as it would with any number of whitespace characters at this point (i.e.~outside of any string). \item If you insert any expression when a string is expected, it gets ``expanded'': it is evaluated as a standard GP expression, and the final result (as would have been printed if you had typed it by itself) is then converted to a string, as if you had typed it directly. For instance \kbd{"a" 1+1 "b"} is equivalent to \kbd{"a2b"}: three strings get created, the middle one being the expansion of \kbd{1+1}, and these are then concatenated according to the rule described above. Another tricky point here: assume you did not assign a value to \kbd{aaa} in a GP expression before. Then typing \kbd{aaa} by itself in a string context will actually produce the correct output (i.e.~the string whose content is aaa), but in a fortuitous way. This \kbd{aaa} gets expanded to the monomial of degree one in the variable \kbd{aaa}, which is of course printed as \kbd{aaa}, and thus will expand to the three letters you were expecting. \misctitle{Warning} Expression involving strings are not handled in a special way; even in string context, the largest possible expression is evaluated, hence \kbd{print("a"[1])} is incorrect since \kbd{"a"} is not an object whose first component can be extracted. On the other hand \kbd{print("a", [1])} is correct (two distinct argument, each converted to a string), and so is \kbd{print("a" 1)} (since \kbd{"a"1} is not a valid expression, only \kbd{"a"} gets expanded, then \kbd{1}, and the result is concatenated as explained above). \subsec{Keywords} Since there are cases where expansion is not desirable, we now distinguish between ``Keywords'' and ``Strings''. String is what has been described so far. Keywords are special relatives of Strings which are automatically assumed to be quoted, whether you actually type in the quotes or not. Thus expansion is never performed on them. They get concatenated, though. The analyzer supplies automatically the quotes you have ``forgotten'' and treats Keywords just as normal strings otherwise. For instance, if you type \kbd{"a"b+b} in Keyword context, you will get the string whose contents are ab+b. In String context, on the other hand, you would get a2\kbd{*}b. All GP functions have prototypes (described in Chapter~3 below) which specify the types of arguments they expect: either generic PARI objects (GEN), or strings, or keywords, or unevaluated expression sequences. In the keyword case, only a very small set of words will actually be meaningful (the \kbd{default} function is a prominent example). \misctitle{Reference} The arguments of the following functions are processed in string context: \settabs\+\indent&\cr \+&\tet{Str}\cr \+&\tet{addhelp} (second argument)\cr \+&\tet{default} (second argument)\cr \+&\tet{error}\cr \+&\tet{extern}\cr \+&\tet{plotstring} (second argument)\cr \+&\tet{plotterm} (first argument)\cr \+&\tet{read} and \tet{readvec}\cr \+&\tet{system}\cr \+&all the \tet{print}\var{xxx} functions\cr \+&all the \tet{write}\var{xxx} functions\cr \noindent The arguments of the following functions are processed as keywords: \+&\tet{alias}\cr \+&\tet{default} (first argument)\cr \+&\tet{install} (all arguments but the last)\cr \+&\tet{trap} (first argument)\cr \+&\tet{whatnow}\cr \subsec{Useful example} The function \kbd{Str} converts its arguments into strings and concatenate them. Coupled with \tet{eval}, it is very powerful. The following example creates generic matrices\sidx{generic matrix}\sidx{matrix}: \bprog ? genmat(u,v,s="x") = matrix(u,v,i,j, eval( Str(s,i,j) )) ? genmat(2,3) + genmat(2,3,"m") %1 = [x11 + m11 x12 + m12 x13 + m13] [x21 + m21 x22 + m22 x23 + m23] @eprog \section{Errors and error recovery} \subsec{Errors} Your input program is first compiled to a more efficient bytecode; then the latter is evaluated, calling appropriate functions from the PARI library. Accordingly, there are two kind of errors: syntax errors produced by the compiler, and runtime errors produced by the PARI library either by the evaluator itself, or in a mathematical function. Both kinds are fatal to your computation: \kbd{gp} will report the error and perform some cleanup (restore variables modified while evaluating the erroneous command, close open files, reclaim unused memory, etc.). At this point, the default is to return to the usual prompt, but if the \kbd{recover} option (\secref{se:def,recover}) is off then \kbd{gp} exits immediately. This can be useful for batch-mode operation to make untrapped errors fatal. When reporting a \emph{syntax error}, \kbd{gp} gives meaningful context by copying (part of) the expression it was trying to compile, indicating where the error occurred with a caret \kbd{\pow-}, as in \bprog ? factor() *** too few arguments: factor() *** ^- ? 1+ *** syntax error, unexpected $end: 1+ *** ^- @eprog\noindent possibly enlarged to a full arrow given enough trailing context \bprog ? if (isprime(1+, do_something()) *** syntax error, unexpected ',': if(isprime(1+,do_something())) *** ^---------------- @eprog\noindent These error messages may be mysterious, because \kbd{gp} cannot guess what you were trying to do, and the error may occur once \kbd{gp} has been sidetracked. The first error is straightforward: \kbd{factor} has one mandatory argument, which is missing. The other two are simple typos involving an ill-formed addition \kbd{1 + } missing its second operand. The error messages differ because the parsing context is slightly different: in the first case we reach the end of input (\kbd{\$end}) while still expecting a token, and in the second one, we received an unexpected token (the comma). Here is a more complicated one: \bprog ? factor(x *** syntax error, unexpected $end, expecting )-> or ',' or ')': factor(x *** ^- @eprog\noindent The error is a missing parenthesis, but from \kbd{gp}'s point of view, you might as well have intended to give further arguments to \kbd{factor} (this is possible and useful, see the description of the function). In fact \kbd{gp} expected either a closing parenthesis, or a second argument separated from the first by a comma. And this is essentially what the error message says: we reached the end of the input (\kbd{\$end}) while expecting a \kbd{')'} or a \kbd{','}. Actually, a third possibility is mentioned in the error message \kbd{)->}, which could never be valid in the above context, but a subexpression like \kbd{(x)->sin(x)}, defining an inline closure would be valid, and the parser is not clever enough to rule that out, so we get the same message as in \bprog ? (x *** syntax error, unexpected $end, expecting )-> or ',' or ')': (x *** ^- @eprog\noindent where all three proposed continuations would be valid. \emph{Runtime errors} from the evaluator are nicer because they answer a correctly worded query, otherwise the bytecode compiler would have protested first; here is a slightly pathological case: \bprog ? if (siN(x) < eps, do_something()) *** at top-level: if(siN(x)}). You can type in a \kbd{gp} command, which is evaluated when you hit the \kbd{} key, and the result is printed as during the main \kbd{gp} loop, except that no history of results is kept. Then the break loop prompt reappears and you can type further commands as long as you do not exit the loop. If you are using readline, the history of commands is kept, and line editing is available as usual. If you type in a command that results in an error, you are sent back to the break loop prompt: errors do \var{not} terminate the loop. To get out of a break loop, you can use \tet{next}, \tet{break}, \tet{return}, or type \kbd{C-d} (\kbd{EOF}), any of which will let \kbd{gp} perform its usual cleanup, and send you back to the \kbd{gp} prompt. Note that \kbd{C-d} is slightly dangerous, since typing it \emph{twice} will not only send you back to the \kbd{gp} prompt, but to your shell prompt! (Since \kbd{C-d} at the \kbd{gp} prompt exits the gp session.) If the break loop was started by a user interrupt \kbd{Control-C}, and not by an error, inputting an empty line, i.e hitting the \kbd{} key at the \kbd{break>} prompt, resumes the temporarily interrupted computation. A single empty line has no effect in case of a fatal error, to avoid getting get out of the loop prematurely, thereby losing valuable debugging data. Any of \tet{next}, \tet{break}, \tet{return}, or \kbd{C-d} will abort the computation and send you back to the \kbd{gp} prompt as above. Break loops are useful as a debugging tool. You may inspect the values of \kbd{gp} variables to understand why an error occurred, or change \kbd{gp}'s state in the middle of a computation (increase debugging level, start storing results in a log file, set variables to different values\dots): hit \kbd{C-c}, type in your modifications, then let the computation go on as explained above. A break loop looks like this: \bprog ? v = 0; 1/v *** at top-level: v=0;1/v *** ^-- *** _/_: impossible inverse in gdiv: 0. *** Break loop (type 'break' to go back to the GP prompt) break> @eprog \noindent So the standard error message is printed first. The \kbd{break>} at the bottom is a prompt, and hitting \kbd{v} then \kbd{}, we see: \bprog break> v 0 @eprog\noindent explaining the problem. We could have typed any \kbd{gp} command, not only the name of a variable, of course. Lexically-scoped variables are accessible to the evaluator during the break loop: \bprog ? for(v = -2, 2, print(1/v)) -1/2 -1 *** at top-level: for(v=-2,2,print(1/v)) *** ^---- *** _/_: impossible inverse in gdiv: 0. *** Break loop (type 'break' to go back to the GP prompt) break> v 0 @eprog\noindent Even though loop indices are automatically lexically scoped and no longer exist when the break loop is run, enough debugging information is retained in the bytecode to reconstruct the evaluation context. Of course, when the error occurs in a nested chain of user function calls, lexically scoped variables are available only in the corresponding frame: \bprog ? f(x) = 1/x; ? g(x) = for(i = 1, 10, f(x+i)); ? for(j = -5,5, g(j)) *** at top-level: for(j=-5,5,g(j)) *** ^----- *** in function g: for(i=1,10,f(x+i)) *** ^------- *** in function f: 1/x *** ^-- *** _/_: impossible inverse in gdiv: 0. *** Break loop: type 'break' to go back to GP prompt break> [i,j,x] \\ @com the $x$ in $f$'s body. [i, j, 0] break> dbg_up \\ @com go up one frame *** at top-level: for(j=-5,5,g(j)) *** ^----- *** in function g: for(i=1,10,f(x+i)) *** ^------- break> [i,j,x] \\ @com the $x$ in $g$'s body, $i$ in the for loop. [5, j, -5] @eprog The following GP commands are available during a break loop to help debugging: \tet{dbg_up}$(n)$: go up $n$ frames, as seen above. \tet{dbg_down}$(n)$: go down $n$ frames, cancelling previous \kbd{dbg\_up}'s. \tet{dbg_x}$(t)$: examine $t$, as \kbd{\bs x} but more flexible. \tet{dbg_err}$()$: returns the current error context \typ{ERROR}. The error components often provide useful additional information: \bprog ? O(2) + O(3) *** at top-level: O(2)+O(3) *** ^----- *** _+_: inconsistent addition t_PADIC + t_PADIC. *** Break loop: type 'break' to go back to GP prompt break> E = dbg_err() error("inconsistent addition t_PADIC + t_PADIC.") break> Vec(E) ["e_OP", "+", O(2), O(3)] @eprog \misctitle{Note} The debugger is enabled by default, and fires up as soon as a runtime error occurs. If you do not like this behavior, you may disable it by setting the default \tet{breakloop} to 0 in for \kbd{gprc}. A runtime error will send you back to the prompt. Note that the break loop is automatically disabled when running \kbd{gp} in non interactive mode, i.e.~when the program's standard input is not attached to a terminal. \misctitle{Technical Note} When you enter a break loop due to a PARI stack overflow, the PARI stack is reset so that you can run commands. Otherwise the stack would immediately overflow again! Still, as explained above, you do not lose the value of any \kbd{gp} variable in the process. \subsec{Protecting code} The expression \kbd{iferr(\var{statements}, ERR, \var{recovery})} \noindent evaluates and returns the value of \var{statements}, unless an error occurs during the evaluation in which case the value of \var{recovery} is returned. As in an if/else clause, with the difference that \var{statements} has been partially evaluated, with possible side effects. We shall give a lot more details about the \kbd{ERR} argument shortly; it is the name of a variable, lexically scoped to the \var{recovery} expression sequence, whose value is set by the exception handler to help the recovery code decide what to do about the error. For instance one can define a fault tolerant inversion function as follows: \bprog ? inv(x) = iferr(1/x, ERR, "oo") \\ ERR is unused... ? for (i=-1,1, print(inv(i))) -1 oo 1 @eprog\noindent Protected codes can be nested without adverse effect. Let's now see how \kbd{ERR} can be used; as written, \kbd{inv} is too tolerant: \bprog ? inv("blah") %2 = "oo" @eprog Let's improve it by checking that we caught a ``division by 0'' exception, and not an unrelated one like the type error \kbd{1 / "blah"}. \bprog ? inv2(x) = { iferr(1/x, ERR, if (errname(ERR) != "e_INV", error(ERR)); "oo") } ? inv2(0) %3 = "oo" \\ as before ? inv2("blah") *** at top-level: inv2("blah") *** ^------------ *** in function inv2: ...f(errname(ERR)!="e_INV",error(ERR));"oo") *** ^----------------- *** error: forbidden division t_INT / t_STR. @eprog\noindent In the \kbd{inv2("blah")} example, the error type was not expected, so we rethrow the exception: \kbd{error(ERR)} triggers the original error that we mistakenly trapped. Since the recovery code should always check whether the error is the one expected, this construction is very common and can be simplified to \bprog ? inv3(x) = iferr(1/x, ERR, "oo", errname(ERR) == "e_INV") @eprog\noindent More generally \kbd{iferr(\var{statements}, ERR, \var{recovery}, \var{predicate})} \noindent only catches the exception if \var{predicate} (allowed to check various things about \kbd{ERR}, not only its name) is non-zero. Rather than trapping everything, then rethrowing whatever we do not like, we advise to only trap errors of a specific kind, as above. Of course, sometimes, one just want to trap \emph{everything} because we do not know what to expect. The following function check whether \tet{install} works correctly in your \kbd{gp}: \bprog broken_install() = { \\ can we install? iferr(install(addii,GG), ERR, return ("OS")); \\ can we use the installed function? iferr(if (addii(1,1) != 2, return("BROKEN")), ERR, return("USE")); return (0); } @eprog \noindent The function returns \kbd{OS} if the operating system does not support \kbd{install}, \kbd{USE} if using an installed function triggers an error, \kbd{BROKEN} if the installed function did not behave as expected, and 0 if everything works. The \kbd{ERR} formal parameter contains more useful data than just the error name, which we recovered using \kbd{errname(ERR)}. In fact, a \typ{ERROR} object usually has extra components, which can be accessed as \kbd{component(ERR,1)}, \kbd{component(ERR,2)}, and so on. Or globally by casting the error to a \typ{VEC}: \kbd{Vec(ERR)} returns the vector of all components at once. See \secref{se:iferr} for the list of all exception types, and the corresponding contents of \kbd{ERR}. \section{Interfacing GP with other languages} \noindent The PARI library was meant to be interfaced with C programs. This specific use is dealt with extensively in the \emph{User's guide to the PARI library}. Of course, \kbd{gp} itself provides a convenient interpreter to execute rather intricate scripts (see \secref{se:programming}). Scripts, when properly written, tend to be shorter and clearer than C programs, and are certainly easier to write, maintain or debug. You don't need to deal with memory management, garbage collection, pointers, declarations, and so on. Because of their intrinsic simplicity, they are more robust as well. They are unfortunately somewhat slower. Thus their use will remain complementary: it is suggested that you test and debug your algorithms using scripts, before actually coding them in C if speed is paramount. The GP2C compiler often eases this part. The \kbd{install} command (see~\secref{se:install}) efficiently imports foreign functions for use under \kbd{gp}, which can of course be written using other libraries than PARI. Thus you may code only critical parts of your program in C, and still maintain most of the program as a GP script. We are aware of three PARI-related Free Software packages to embed PARI in other languages. We \emph{neither endorse nor support} any of them, but you may want to give them a try if you are familiar with the languages they are based on. The first is the Python-based SAGE system (\url{http://sagemath.org/}). The second is the \tet{Math::Pari} Perl module (see any CPAN mirror), written by Ilya Zakharevich. Finally, Michael Stoll and Sam Steingold have integrated PARI into \tet{CLISP} (\url{http://clisp.cons.org/}), a Common Lisp implementation. These provide interfaces to \kbd{gp} functions for use in \kbd{python}, \kbd{perl}, or \kbd{Lisp}\sidx{Perl}\sidx{Python}\sidx{Lisp} programs, respectively. \section{Defaults}\sidx{defaults} \label{se:defaults} \noindent There are many internal variables in \kbd{gp}, defining how the system will behave in certain situations, unless a specific override has been given. Most of them are a matter of basic customization (colors, prompt) and will be set once and for all in your \idx{preferences file} (see \secref{se:gprc}), but some of them are useful interactively (set timer on, increase precision, etc.). The function used to manipulate these values is called \kbd{default}, which is described in \secref{se:default}. The basic syntax is \kbd{default(\var{def}, \var{value})}, \noindent which sets the default \var{def} to \var{value}. In interactive use, most of these can be abbreviated using \kbd{gp} metacommands (mostly, starting with \b), which we shall describe in the next section. Available defaults are described in the reference guide, \secref{se:gp_defaults}, the most important one being \tet{parisizemax}. Just be aware that typing \kbd{default} by itself will list all of them, as well as their current values (see \b{d}). \misctitle{Note} The suffixes \kbd{k}, \kbd{M} or \kbd{G} can be appended to a \var{value} which is a numeric argument, with the effect of multiplying it by $10^3$, $10^6$ and $10^9$ respectively. Case is not taken into account there, so for instance \kbd{30k} and \kbd{30K} both stand for $30000$. This is mostly useful to modify or set the defaults \kbd{parisize} and \kbd{parisizemax} which typically involve a lot of trailing zeroes. \misctitle{(somewhat technical) Note} As we saw in \secref{se:strings}, the second argument to \kbd{default} is subject to string context expansion, which means you can use run-time values. In other words, something like \bprog a = 3; default(logfile, "file" a ".log") @eprog logs the output in \kbd{file3.log}. Some special defaults, corresponding to file names and prompts, expand further the resulting value at the time they are set. Two kinds of expansions may be performed: \item \teb{time expansion}: the string is sent through the library function \tet{strftime}. This means that \kbd{\%}\var{char} combinations have a special meaning, usually related to the time and date. For instance, \kbd{\%H} = hour (24-hour clock) and \kbd{\%M} = minute [00,59] (on a Unix system, you can try \kbd{man strftime} at your shell prompt to get a complete list). This is applied to \kbd{prompt} and \kbd{logfile}. For instance, \kbd{default(prompt,"(\%H:\%M) ? ")} \noindent will prepend the time of day, in the form \kbd{(\var{hh}:\var{mm})} to \kbd{gp}'s usual prompt. \item \teb{environment expansion}: When the string contains a sequence of the form \kbd{\$\var{SOMEVAR}}, e.g.~\kbd{\$HOME}, the environment is searched and if \var{SOMEVAR} is defined, the sequence is replaced by the corresponding value. Also the \kbd{\til} symbol has the same meaning as in many shells~--- \kbd{\til} by itself stands for your home directory, and \kbd{\til{}user} is expanded to \kbd{user}'s home directory. This is applied to all file names\sidx{filename}. \label{se:envir} \section{Simple metacommands}\label{se:meta} \noindent Simple metacommands are meant as shortcuts and should not be used in GP scripts (see \secref{se:programming}). Beware that these, as all of \kbd{gp} input, are \emph{case sensitive}. For example, \b{Q} is not identical to \b{q}. Two kinds of arguments are allowed: numbers (denoted $n$ below) and names (denoted \var{filename} below); braces are used to denote optional arguments, , e.g.~$\{n\}$ means that a numeric argument is expected but can be omitted. Names can be optionally surrounded by double quotes and in this case can contain whitespace, e.g. \kbd{"a b"} and are treated as ordinary character strings, see \secref{se:strings} for details. Whitespace (or spaces) between the metacommand and its arguments and within unquoted arguments is optional. (This can cause problems with \b{w}, when you insist on having a file name whose first character is a digit, and with \b{r} or \b{w}, if the file name itself contains a space. In such cases, just quote filenames or use the underlying \tet{read} or \tet{write} function). \subseckbd{?$\{\var{command}\}$} The \kbd{gp} on-line help interface. If you type \kbd{?$n$} where $n$ is a number from 1 to 11, you will get the list of functions in Section $3.n$ of the manual (the list of sections being obtained by simply typing \kbd{?}). \label{se:exthelp} These names are in general not informative enough. More details can be obtained by typing \kbd{?\var{function}}, which gives a short explanation of the function's calling convention and effects. Of course, to have complete information, read Chapter 3 of this manual (the source code is at your disposal as well, though a trifle less readable). If the line before the copyright message indicates that extended help is available (this means \kbd{perl} is present on your system and the PARI distribution was correctly installed), you can add more \kbd{?} signs for extended functionality: \kbd{??~\var{keyword}} yields the function description as it stands in this manual, usually in Chapter~2 or~3. If you're not satisfied with the default chapter chosen, you can impose a given chapter by ending the keyword with \kbd{@} followed by the chapter number, e.g.~\kbd{??~Hello@2} will look in Chapter~2 for section heading \kbd{Hello} (which doesn't exist, by the way). All operators (e.g.~\kbd{+}, \kbd{\&\&}, etc.) are accepted by this extended help, as well as a few other keywords describing key \kbd{gp} concepts, e.g.~\kbd{readline} (the line editor), \kbd{integer}, \kbd{nf} (``number field'' as used in most algebraic number theory computations), \kbd{ell} (elliptic curves), etc. In case of conflicts between \emph{function} and \emph{default} names (e.g \tet{log}, \tet{simplify}), the function has higher priority. To get the \emph{default} help, use \bprog ?? default(log) ?? default(simplify) @eprog \kbd{???~\var{pattern}} produces a list of sections in Chapter~3 of the manual related to your query. As before, if \var{pattern} ends by \kbd{@} followed by a chapter number, that chapter is searched instead; you also have the option to append a simple \kbd{@} (without a chapter number) to browse through the whole manual. If your query contains dangerous characters (e.g \kbd{?} or blanks) it is advisable to enclose it within double quotes, as for GP strings (e.g \kbd{???~"elliptic curve"}). Note that extended help is more powerful than the short help, since it knows about operators as well: you can type \kbd{??~*} or \kbd{??~\&\&}, whereas a single \kbd{?} would just yield a not too helpful \bprog &&: unknown identifier. @eprog\noindent message. Also, you can ask for extended help on section number~$n$ in Chapter~3, just by typing \kbd{??~$n$} (where \kbd{?$n$} would yield merely a list of functions). Finally, a few key concepts in \kbd{gp} are documented in this way: metacommands (e.g \kbd{??~"??"}), defaults (e.g \kbd{??~default(log)}) not to be mistaken with \kbd{??~log} (the natural logarithm) and type names (e.g \typ{INT} or \kbd{integer}), as well as various miscellaneous keywords such as \kbd{edit} (short summary of line editor commands), \kbd{operator}, \kbd{member}, \kbd{"user defined"}, \kbd{nf}, \kbd{ell}, \dots Last but not least: \kbd{??} without argument will open a \kbd{dvi} previewer (\kbd{xdvi} by default, \kbd{\$GPXDVI} if it is defined in your environment) containing the full user's manual. \kbd{??tutorial} and \kbd{??refcard} do the same with the \idx{tutorial} and \idx{reference card} respectively. \misctitle{Technical note} This functionality is provided by an external \kbd{perl} script that you are free to use outside any \kbd{gp} session (and modify to your liking, if you are perl-knowledgeable). It is called \tet{gphelp}, lies in the \kbd{doc} subdirectory of your distribution (just make sure you run \kbd{Configure} first, see Appendix~A) and is really two programs in one. The one which is used from within \kbd{gp} is \kbd{gphelp} which runs \TeX\ on a selected part of this manual, then opens a previewer. \kbd{gphelp -detex} is a text mode equivalent, which looks often nicer especially on a colour-capable terminal (see \kbd{misc/gprc.dft} for examples). The default \kbd{help} selects which help program will be used from within \kbd{gp}. You are welcome to improve this help script, or write new ones (and we would like to know about it so that we may include them in future distributions). By the way, outside of \kbd{gp} you can give more than one keyword as argument to \kbd{gphelp}. \subseckbd{/*...*/} A comment. Everything between the stars is ignored by \kbd{gp}. These comments can span any number of lines. \subseckbd{\bs\bs} A one-line comment. The rest of the line is ignored by \kbd{gp}. \subsec{\b{a} $\{n\}$} Prints the object number $n$ ($\%n$) in raw format. If the number $n$ is omitted, print the latest computed object ($\%$). \label{se:history} \subsec{\b{c}}\sidx{available commands} Prints the list of all available hardcoded functions under \kbd{gp}, not including operators written as special symbols (see \secref{se:operators}). More information can be obtained using the \kbd{?} metacommand (see above). For user-defined functions / member functions, see \b{u} and \b{um}. \subsec{\b{d}} Prints the \idx{defaults} as described in the previous section (shortcut for \kbd{default()}, see \secref{se:default}). \subsec{\b{e} $\{n\}$} Switches the \tet{echo} mode on (1) or off (0). If $n$ is explicitly given, set echo to $n$. \subsec{\b{g} $\{n\}$} Sets the debugging level \tet{debug} to the non-negative integer $n$. \subsec{\b{gf} $\{n\}$} Sets the file usage debugging level \tet{debugfiles} to the non-negative integer $n$. \subsec{\b{gm} $\{n\}$} Sets the memory debugging level \tet{debugmem} to the non-negative integer $n$. \subsec{\b{h} $\{m$\kbd{-}$n\}$} Outputs some debugging info about the hashtable. If the argument is a number $n$, outputs the contents of cell $n$. Ranges can be given in the form $m$\kbd{-}$n$ (from cell $m$ to cell $n$, \$ = last cell). If a function name is given instead of a number or range, outputs info on the internal structure of the hash cell this function occupies (a \kbd{struct entree} in C). If the range is reduced to a dash ('\kbd{-}'), outputs statistics about hash cell usage. \subsec{\b{l} $\{$\var{logfile}$\}$} Switches \tet{log} mode on and off. If a \var{logfile} argument is given, change the default logfile name to \var{logfile} and switch log mode on. \subsec{\b{m}} As \b{a}, but using prettymatrix format. \subsec{\b{o} $\{n\}$} Sets \tet{output} mode to $n$ ($0$: raw, $1$: prettymatrix, $3$: external prettyprint). \subsec{\b{p} $\{n\}$} Sets \tet{realprecision} to $n$ decimal digits. Prints its current value if $n$ is omitted. \subsec{\b{pb} $\{n\}$} Sets \tet{realbitprecision} to $n$ bits. Prints its current value if $n$ is omitted. \subsec{\b{ps} $\{n\}$} Sets \tet{seriesprecision} to $n$ significant terms. Prints its current value if $n$ is omitted. \subsec{\b{q}} Quits the \kbd{gp} session and returns to the system. Shortcut for \tet{quit}\kbd{()} (see \secref{se:quit}). \subsec{\b{r} $\{$\var{filename}$\}$} Reads into \kbd{gp} all the commands contained in the named file as if they had been typed from the keyboard, one line after the other. Can be used in combination with the \b{w} command (see below). Related but not equivalent to the function \kbd{read} (see \secref{se:read}); in particular, if the file contains more than one line of input, there will be one history entry for each of them, whereas \kbd{read} would only record the last one. If \var{filename} is omitted, re-read the previously used input file (fails if no file has ever been successfully read in the current session). If a \kbd{gp} \tet{binary file} (see \secref{se:writebin}) is read using this command, it is silently loaded, without cluttering the history. Assuming \kbd{gp} figures how to decompress files on your machine, this command accepts compressed files in \tet{compress}ed (\kbd{.Z}) or \tet{gzip}ped (\kbd{.gz} or \kbd{.z}) format. They will be uncompressed on the fly as \kbd{gp} reads them, without changing the files themselves. \subsec{\b{s}} Prints the state of the PARI \tev{stack} and \tev{heap}. This is used primarily as a debugging device for PARI. \subsec{\b{t}} Prints the \idx{internal longword format} of all the PARI types. The detailed bit or byte format of the initial codeword(s) is explained in Chapter~4, but its knowledge is not necessary for a \kbd{gp} user. \subsec{\b{u}} Prints the definitions of all user-defined functions. \subsec{\b{um}} Prints the definitions of all user-defined member functions. \subsec{\b{v}} Prints the \idx{version number} and implementation architecture (680x0, Sparc, Alpha, other) of the \kbd{gp} executable you are using. \subsec{\b{w} $\{n\}$ $\{$\var{filename}$\}$} Writes the object number $n$ ( $\%n$ ) into the named file, in raw format. If the number $n$ is omitted, writes the latest computed object ( $\%$ ). If \var{filename} is omitted, appends to \kbd{logfile} (the GP function \tet{write} is a trifle more powerful, as you can have arbitrary file names). \subsec{\b{x} $\{n\}$} Prints the complete tree with addresses and contents (in hexadecimal) of the \idx{internal representation} of the object number $n$ ( $\%n$ ). If the number $n$ is omitted, uses the latest computed object in \kbd{gp}. As for \b{s}, this is used primarily as a debugging device for PARI, and the format should be self-explanatory. The underlying GP function \tet{dbg_x} is more versatile, since it can be applied to other objects than history entries. \subsec{\b{y} $\{n\}$} Switches \kbd{simplify} on (1) or off (0). If $n$ is explicitly given, set simplify to $n$. \subseckbd{\#} Switches the \kbd{timer} on or off. \subseckbd{\#\#} Prints the time taken by the latest computation. Useful when you forgot to turn on the \kbd{timer}. \section{The preferences file}\sidx{startup}\sidx{preferences file} \label{se:gprc} This file, called \tet{gprc} in the sequel, is used to modify or extend \kbd{gp} default behavior, in all \kbd{gp} sessions: e.g customize \kbd{default} values or load common user functions and aliases. \kbd{gp} opens the \kbd{gprc} file and processes the commands in there, \emph{before} doing anything else, e.g.~creating the PARI stack. If the file does not exist or cannot be read, \kbd{gp} will proceed to the initialization phase at once, eventually emitting a prompt. If any explicit command line switches are given, they override the values read from the preferences file. \subsec{Syntax} The syntax in the \kbd{gprc} file (and valid in this file only) is simple-minded, but should be sufficient for most purposes. The file is read line by line; as usual, white space is ignored unless surrounded by quotes and the standard multiline constructions using braces, \kbd{\bs}, or \kbd{=} are available (multiline comments between \kbd{/*~\dots~*/} are also recognized). \subsubsec{Preprocessor:} Two types of lines are first dealt with by a preprocessor: \item comments are removed. This applies to all text surrounded by \kbd{/*~\dots~*/} as well as to everything following \kbd{\bs\bs} on a given line. \item lines starting with \kbd{\#if} \var{boolean} are treated as comments if \var{boolean} evaluates to \kbd{false}, and read normally otherwise. The condition can be negated using either \kbd{\#if not} (or \kbd{\#if !}). If the rest of the current line is empty, the test applies to the next line (same behavior as \kbd{=} under \kbd{gp}). The following tests can be performed: \kbd{EMACS}: \kbd{true} if \kbd{gp} is running in an Emacs or TeXmacs shell (see \secref{se:emacs}). \kbd{READL}: \kbd{true} if \kbd{gp} is compiled with \kbd{readline} support (see \secref{se:readline}). \kbd{VERSION} \var{op} \var{number}: where \var{op} is in the set $\{ \kbd{>}, \kbd{<}, \kbd{<=}, \kbd{>=} \}$, and \var{number} is a PARI version number of the form \var{Major}.\var{Minor}.\var{patch}, where the last two components can be omitted (i.e.~$1$ is understood as version $1.0.0$). This is \kbd{true} if \kbd{gp}'s version number satisfies the required inequality. \kbd{BITS\_IN\_LONG} \kbd{==} \var{number}: \var{number} is $32$ (resp.~$64$). This is \kbd{true} if \kbd{gp} was built for a 32-bit (resp.~64-bit) architecture. \subsubsec{Commands:} After preprocessing, the remaining lines are executed as sequence of expressions (as usual, separated by \kbd{;} if necessary). Only two kinds of expressions are recognized: \item \var{default} \kbd{=} \var{value}, where \var{default} is one of the available defaults (see \secref{se:defaults}), which will be set to \var{value} on actual startup. Don't forget the quotes around strings (e.g.~for \kbd{prompt} or \kbd{help}). \item \kbd{read "\var{some\_GP\_file}"} where \kbd{\var{some\_GP\_file}} is a regular GP script this time, which will be read just before \kbd{gp} prompts you for commands, but after initializing the defaults. In particular, file input is delayed until the \kbd{gprc} has been fully loaded. This is the right place to input files containing \kbd{alias} commands, or your favorite macros. \noindent For instance you could set your prompt in the following portable way: \bprog \\ self modifying prompt looking like @com\hbox{\rm(18:03) \key{gp}\kbd{ >}} prompt = "(%H:%M) \e[1mgp\e[m > " \\ readline wants non-printing characters to be braced between ^A/^B pairs #if READL prompt = "(%H:%M) ^A\e[1m^Bgp^A\e[m^B > " \\ escape sequences not supported under emacs #if EMACS prompt = "(%H:%M) gp > " @eprog \noindent Note that any of the last two lines could be broken in the following way \bprog #if EMACS prompt = "(%H:%M) gp > " @eprog \noindent since the preprocessor directive applies to the next line if the current one is empty. A sample \kbd{gprc} file called \kbd{misc/gprc.dft} is provided in the standard distribution. It is a good idea to have a look at it and customize it to your needs. Since this file does not use multiline constructs, here is one (note the terminating \kbd{;} to separate the expressions): \bprog #if VERSION > 2.2.3 { read "my_scripts"; \\ syntax errors in older versions new_galois_format = 1; \\ default introduced in 2.2.4 } #if ! EMACS { colors = "9, 5, no, no, 4, 1, 2"; help = "gphelp -detex -ch 4 -cb 0 -cu 2"; } @eprog \subsec{The gprc location} When \kbd{gp} is started, it looks for a customization file, or \kbd{gprc} in the following places (in this order, only the first one found will be loaded): \noindent\item \kbd{gp} checks whether the environment variable \tet{GPRC} is set. On Unix, this can be done with something like: \smallskip \settabs\+\indent&\kbd{GPRC=/my/dir/anyname; export GPRC}\quad&\cr \+&\kbd{GPRC=/my/dir/anyname; export GPRC}\quad&in \kbd{sh} syntax (for instance in your \kbd{.profile}),\cr \+&\kbd{setenv GPRC /my/dir/anyname} &in \kbd{csh} syntax (in your \kbd{.login} or \kbd{.cshrc} file).\cr \+&\kbd{env GPRC=/my/dir/anyname gp} &on the command line launching \kbd{gp}.\cr \noindent If so, the file named by \kbd{\$GPRC} is the \kbd{gprc}. \noindent\item If \kbd{GPRC} is not set, and if the environment variable \kbd{HOME} is defined, \kbd{gp} then tries \kbd{\$HOME/.gprc} on a Unix system \kbd{\$HOME\bs gprc.txt} on a DOS, OS/2, or Windows system. \noindent\item If no gprc was found among the user files mentioned above we look for \kbd{/etc/gprc} for a system-wide gprc file (you will need root privileges to set up such a file yourself). \noindent\item Finally, we look in pari's \kbd{datadir} for a file named \kbd{.gprc} on a Unix system \kbd{gprc.txt} on a DOS, OS/2, or Windows system. If you are using our Windows installer, this is where the default preferences file is written. \noindent Note that on Unix systems, the \kbd{gprc}'s default name starts with a '.' and thus is hidden to regular \kbd{ls} commands; you need to type \kbd{ls -a} to list it. \section{Using readline} \sidx{line editor}\sidx{completion} This very useful library provides line editing and contextual completion to \kbd{gp}. You are encouraged to read the \kbd{readline} user manual, but we describe basic usage here. \misctitle{A (too) short introduction to readline}\label{se:readline} In the following, \kbd{C-} stands for ``the \kbd{Control} key combined with another'' and the same for \kbd{M-} with the \kbd{Meta} key; generally \kbd{C-} combinations act on characters, while the \kbd{M-} ones operate on words. The \kbd{Meta} key might be called \kbd{Alt} on some keyboards, will display a black diamond on most others, and can safely be replaced by \kbd{Esc} in any case. Typing any ordinary key inserts text where the cursor stands, the arrow keys enabling you to move in the line. There are many more movement commands, which will be familiar to the Emacs user, for instance \kbd{C-a}/\kbd{C-e} will take you to the start/end of the line, \kbd{M-b}/\kbd{M-f} move the cursor backward/forward by a word, etc. Just press the \kbd{} key at any point to send your command to \kbd{gp}. All the commands you type at the \kbd{gp} prompt are stored in a history, a multiline command being saved as a single concatenated line. The Up and Down arrows (or \kbd{C-p}/\kbd{C-n}) will move you through the history, \kbd{M-<}/\kbd{M->} sending you to the start/end of the history. \kbd{C-r}/\kbd{C-s} will start an incremental backward/forward search. You can kill text (\kbd{C-k} kills till the end of line, \kbd{M-d} to the end of current word) which you can then yank back using the \kbd{C-y} key (\kbd{M-y} will rotate the kill-ring). \kbd{C-\_} will undo your last changes incrementally (\kbd{M-r} undoes all changes made to the current line). \kbd{C-t} and \kbd{M-t} will transpose the character (word) preceding the cursor and the one under the cursor. Keeping the \kbd{M-} key down while you enter an integer (a minus sign meaning reverse behavior) gives an argument to your next readline command (for instance \kbd{M-- C-k} will kill text back to the start of line). If you prefer \idx{Vi}--style editing, \kbd{M-C-j} will toggle you to Vi mode. Of course you can change all these default bindings. For that you need to create a file named \kbd{.inputrc} in your home directory. For instance (notice the embedding conditional in case you would want specific bindings for \kbd{gp}): % \bprog $if Pari-GP set show-all-if-ambiguous "\C-h": backward-delete-char "\e\C-h": backward-kill-word "\C-xd": dump-functions (: "\C-v()\C-b" #@com can be annoying when copy-pasting! [: "\C-v[]\C-b" $endif @eprog \noindent\kbd{C-x C-r} will re-read this init file, incorporating any changes made to it during the current session. \misctitle{Note} By default, \kbd{(} and \kbd{[} are bound to the function \kbd{pari-matched-insert} which, if ``electric parentheses'' are enabled (default: off) will automatically insert the matching closure (respectively \kbd{)} and \kbd{]}). This behavior can be toggled on and off by giving the numeric argument $-2$ to \kbd{(} (\kbd{M--2(}), which is useful if you want, e.g to copy-paste some text into the calculator. If you do not want a toggle, you can use \kbd{M--0} / \kbd{M--1} to specifically switch it on or off). \misctitle{Note} In some versions of readline (2.1 for instance), the \kbd{Alt} or \kbd{Meta} key can give funny results (output 8-bit accented characters for instance). If you do not want to fall back to the \kbd{Esc} combination, put the following two lines in your \kbd{.inputrc}: % \bprog set convert-meta on set output-meta off @eprog \misctitle{Command completion and online help} Hitting \kbd{} will complete words for you. This mechanism is context-dependent: \kbd{gp} will strive to only give you meaningful completions in a given context (it will fail sometimes, but only under rare and restricted conditions). For instance, shortly after a \kbd{\til}, we expect a user name, then a path to some file. Directly after \kbd{default(} has been typed, we would expect one of the \kbd{default} keywords. After a '.', we expect a member keyword. And generally of course, we expect any GP symbol which may be found in the hashing lists: functions (both yours and GP's), and variables. If, at any time, only one completion is meaningful, \kbd{gp} will provide it together with \item an ending comma if we are completing a default, \item a pair of parentheses if we are completing a function name. In that case hitting \kbd{} again will provide the argument list as given by the online help. (Recall that you can always undo the effect of the preceding keys by hitting \kbd{C-\_}; this applies here.) Otherwise, hitting \kbd{} once more will give you the list of possible completions. Just experiment with this mechanism as often as possible, you will probably find it very convenient. For instance, you can obtain \kbd{default(seriesprecision,10)}, just by hitting \kbd{defse10}, which saves 18 keystrokes (out of 27). Hitting \kbd{M-h} will give you the usual short online help concerning the word directly beneath the cursor, \kbd{M-H} will yield the extended help corresponding to the \kbd{help} default program (usually opens a \idx{dvi} previewer, or runs a primitive tex-to-ASCII program). None of these disturb the line you were editing. \section{GNU Emacs and PariEmacs} \label{se:emacs} If you install the PariEmacs package (see Appendix A), you may use \kbd{gp} as a subprocess in \idx{Emacs}. You then need to include in your \kbd{.emacs} file the following lines: \bprog (autoload 'gp-mode "pari" nil t) (autoload 'gp-script-mode "pari" nil t) (autoload 'gp "pari" nil t) (autoload 'gpman "pari" nil t) (setq auto-mode-alist (cons '("\\.gp$" . gp-script-mode) auto-mode-alist)) @eprog \noindent which autoloads functions from the PariEmacs package and ensures that file with the \kbd{.gp} suffix are edited in gp-script mode. Once this is done, under GNU Emacs if you type \kbd{M-x gp} (where as usual \kbd{M} is the \kbd{Meta} key), a special shell will be started launching \kbd{gp} with the default stack size and prime limit. You can then work as usual under \kbd{gp}, but with all the facilities of an advanced text editor. See the PariEmacs documentation for customizations, menus, etc. \newpage pari-2.11.2/doc/translations0000644000175000017500000001140113326135265014372 0ustar billbillreadline @se:readline@2 edit @se:readline@2 ? @?@2 ?? @?@2 \\ @\bs\bs@2 \a @\b{a}@2 \b @\b{b}@2 \c @\b{c}@2 \d @\b{d}@2 \e @\b{e}@2 \g @\b{g}@2 \gf @\b{gf}@2 \gm @\b{gm}@2 \h @\b{h}@2 \k @\b{k}@2 \l @\b{l}@2 \m @\b{m}@2 \p @\b{p}@2 \o @\b{o}@2 \ps @\b{ps}@2 \q @\b{q}@2 \r @\b{r}@2 \s @\b{s}@2 \t @\b{t}@2 \u @\b{u}@2 \um @\b{um}@2 \v @\b{v}@2 \w @\b{w}@2 \x @\b{x}@2 \y @\b{y}@2 # @\#@2 ## @\#\#@2 operator @GP operators@2 and @GP operators@2 or @GP operators@2 not @GP operators@2 INT @Integers@2 integer @Integers@2 REAL @Real numbers@2 real number @Real numbers@2 INTMOD @Integermods@2 intmod @Integermods@2 FRAC @Rational numbers@2 fraction @Rational numbers@2 rational @Rational numbers@2 COMPLEX @Complex numbers@2 complex @Complex numbers@2 PADIC @$p$-adic numbers@2 padic @$p$-adic numbers@2 QUAD @Quadratic numbers@2 quadratic @Quadratic numbers@2 POLMOD @Polmods@2 polmod @Polmods@2 POL @Polynomials@2 polynomial @Polynomials@2 SER @Power series@2 RFRAC @Rational functions@2 QFR @Binary quadratic forms of positive or negative discriminant@2 QFI @Binary quadratic forms of positive or negative discriminant@2 VEC @Row and column vectors@2 COL @Row and column vectors@2 MAT @Matrices@2 LIST @Lists@2 STR @Strings@2 VECSMALL @Small vectors@2 ERROR @Error contexts@2 e_SYNTAX @iferr@ e_BUG @iferr@ e_ALARM @iferr@ e_FILE @iferr@ e_MISC @iferr@ e_FLAG @iferr@ e_IMPL @iferr@ e_ARCH @iferr@ e_PACKAGE @iferr@ e_NOTFUNC @iferr@ e_PREC @iferr@ e_TYPE @iferr@ e_DIM @iferr@ e_VAR @iferr@ e_PRIORITY @iferr@ e_USER @iferr@ e_STACK @iferr@ e_OVERFLOW @iferr@ e_DOMAIN @iferr@ e_COMPONENT @iferr@ e_MAXPRIME @iferr@ e_CONSTPOL @iferr@ e_IRREDPOL @iferr@ e_COPRIME @iferr@ e_PRIME @iferr@ e_MODULUS @iferr@ e_ROOTS0 @iferr@ e_OP @iferr@ e_TYPE2 @iferr@ e_INV @iferr@ e_MEM @iferr@ e_SQRTN @iferr@ local @Variables and Scope@2 my @Variables and Scope@2 user defined @User defined functions@2 user defined function @User defined functions@2 member function @Member functions@2 member @Member functions@2 \ @\bs \/ @\bs/ ^ @\pow ~ @mattranspose % @\% << @shift >> @shift min @max emacs @Using GP under GNU Emacs@2 Emacs @Using GP under GNU Emacs@2 0 @Functions and Operations Available in PARI and GP 1 @Programming in GP: control statements 2 @Standard monadic or dyadic operators 3 @Conversions and similar elementary functions or commands 4 @Combinatorics 5 @Arithmetic functions 6 @Polynomials and power series 7 @Vectors, matrices, linear algebra and sets 8 @Transcendental functions 9 @Sums, products, integrals and similar functions 10 @General number fields 11 @Associative and central simple algebras 12 @Elliptic curves 13 @$L$-functions 14 @Modular forms 15 @Modular symbols 16 @Plotting functions ell @Elliptic curves mf @Modular forms nf @Number field structures bnf @Number field structures bnr @Number field structures rnf @Relative extensions ideal @Algebraic numbers and ideals idele @Algebraic numbers and ideals modulus @Class field theory CFT @Class field theory bid @Class field theory prototype @GP prototypes, parser codes@5 Lmath @Data structures describing $L$ and theta functions Ldata @Data structures describing $L$ and theta functions Linit @Data structures describing $L$ and theta functions L-function @Data structures describing $L$ and theta functions character @Dirichlet characters pari-2.11.2/doc/parimacro.tex0000644000175000017500000003176313326135265014442 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \catcode`\@=11 % % GENERAL FORMATTING % \newif\ifSUBSECTOC\SUBSECTOCtrue \newif\ifSUBSECDOT\SUBSECDOTtrue \newif\ifGPHELP \newif\ifPDF \newread\std \def\checkfile#1{\def\@stdfile{#1}\openin\std=#1\relax} \long\def\@ifundef#1#2#3{\expandafter\ifx\csname #1\endcsname\relax#2\else#3\fi} % do we come from gphelp ? \@ifundef{fromgphelp}{\GPHELPfalse}{\GPHELPtrue} \ifGPHELP %YES \overfullrule=0pt \else %NO \magnification=\magstephalf \PDFfalse \ifx\pdfoutput\undefined \else \ifnum\pdfoutput<1 \else \PDFtrue \fi \fi \fi % if paricfg.tex is there (Configure succeeded), input it, otherwise use % default values \checkfile{paricfg.tex} \ifeof\std \checkfile{doc/paricfg.tex} \fi \ifeof\std \ifGPHELP\else% OK for gphelp to use default values \message{paricfg.tex not found. You should run Configure.} \fi \def\vers{2.0.x} \def\includedir{/usr/local/include/pari} \def\libdir{/usr/local/lib} \else \input\@stdfile \fi \font\chaptertitlefont=cmr12 scaled \magstep1 \font\chaptertitlebf=cmbx10 scaled \magstep2 \font\sectiontitlebf=cmbx12 \font\seventt=cmtt8 scaled 875 \scriptfont\ttfam=\seventt % we should really set the \hyphenchar etc first \parskip=6pt plus 3pt minus 1.5pt %\overfullrule=0pt %% %% TABLE OF CONTENTS %% \newwrite\toc \def\tableofcontents{\begintitle \openin\std=\jobname.toc \ifeof\std \else \begingroup \centerline{\bf Table of Contents}\medskip \parskip=0pt plus 1pt \parindent=0pt \catcode`\_=11 % make _ an ordinary char (frequent in function names) \catcode`\@=11 % make @ an ordinary char (appears in \_ expansion) \obeylines\input\jobname.toc \endgroup \fi \openout\toc=\jobname.toc \endtitle} %% %% CROSS REFERENCING & INDEX %% \newif\ifsecondpass \newwrite\out \newwrite\aux \newwrite\index \ifGPHELP % disable crossreferences \def\condwrite#1#2{} \def\idx#1{#1} \def\toindex#1{} \def\tocwrite#1{} \def\label#1{} \def\gphelpref#1{[Label: {\tt #1}]} \def\gphelpsecref#1{Section~\gphelpref{#1}} \def\ref{\let\do=\gphelpref\doverb} \def\secref{\let\do=\gphelpsecref\doverb} \else % none of the following is needed by gphelp \def\typeout#1{\immediate\write\out{#1}} \def\@namedef#1{\expandafter\def\csname#1\endcsname} \def\newlabel#1#2{\@ifundef{r@#1}{}{\message{Label `#1' multiply defined}}\global\@namedef{r@#1}{#2}} \openin\std=\jobname.std \ifeof\std \secondpassfalse \typeout{FIRST PASS} \openout\index=\jobname.idx \let\condwrite=\write \else \secondpasstrue \typeout{SECOND PASS} \let\immediate\relax \def\condwrite#1#2{} \fi %default font for index entry \def\f@nt{rm} %% \toindex{#1} = put #1 in index; use font \f@nt, indicate \pageno. %% If PDF, associate the page to a unique integer (\pdfdestcntr). \ifPDF \def\toindex#1{\putdest \immediate\condwrite\index{!#1!\f@nt!\the\pageno!\number\pdfdestcntr}} \else \def\toindex#1{% \immediate\condwrite\index{!#1!\f@nt!\the\pageno!}} \fi \checkfile{\jobname.aux} \ifeof\std \message{No aux file.} \else \input\@stdfile% input aux file if present \fi % \ref, \label. We need an auxiliary file written during first pass \openout\aux=\jobname.aux \ifx\inputlineno\undefined \let\on@line\empty \else \def\on@line{ on input line \the\inputlineno} \fi \def\@errundef#1{\typeout{Reference `#1' on page \the\pageno \space undefined\on@line}} \def\@car#1#2\@nil{#1} \def\@cdr#1#2\@nil{#2} \def\@ref {\expandafter\@cdr\@temp \@nil\null} \def\@cref{\expandafter\@car\@temp \@nil\null} \def\label#1{\immediate\write\aux{\string \newlabel{#1}{{\the\chapno}{\currentlabel}}}} \def\ref#1{\@ifundef{r@#1} {{\bf ??}\@errundef{#1}} {\edef\@temp{\csname r@#1\endcsname}% \def\lbl{\@ref}\def\chp{\@cref}% \ifx\chp{\the\chapno}\lbl\else\chp.\lbl\fi}} \def\secref#1{Section~\ref{#1}} \fi % end of non-gphelp section %% %% VERBATIM MODE %% % \doverb: setup verbatim mode for the first argument, and execute \do{\arg} \def\setupverb{\def\do##1{\catcode`##1=12}\dospecials \catcode`\ =10% standard space \catcode`\f=13% to break ugly ligatures as in nf{}init, use \EFF instead } % f won't produce any ligature if catcode 13, e.g in verbatim mode (cf above). { \let\GDEF=\gdef \global\let\EFF=f \catcode`\f=13 \GDEFf{\EFF{}}} \begingroup \catcode`<=1\catcode`\{=12 \catcode`>=2\catcode`\}=12 \gdef\d@verb<% \def\next{##1}<\gdef\@va<##1>\endgroup% \do<\@va>>% \@va is the verbatim argument \next> % \gdef\d@verbb<% \def\next{##1}{##2}<\gdef\@va<##1>\gdef\@vb<##2>\endgroup% \do<\@va><\@vb>>% \@vxxx are the verbatim arguments \next> % \gdef\d@verbbb<% \def\next{##1}{##2}{##3}<\gdef\@va<##1>\gdef\@vb<##2>\gdef\@vc<##3>\endgroup% \do<\@va><\@vb><\@vc>>% \@vxxx are the verbatim arguments \next> % \endgroup \def\doverb {\begingroup\setupverb\d@verb} \def\doverbb{\begingroup\setupverb\d@verbb} % make ',' active to allow automatic glue between function arguments, see \fun \def\doverbbbcomma{\begingroup\catcode`\,=13\setupverb\d@verbbb} \def\func@mma{,\hskip 0.5em plus 0.6em minus 0.3em} {\catcode`\,=13\gdef,{\func@mma}} % argument (silently) goes to index \def\sidx{\gdef\f@nt{rm}\let\do=\toindex\doverb} % \rm \def\kbdsidx{\gdef\f@nt{tt}\let\do=\toindex\doverb}% \tt \def\varsidx{\gdef\f@nt{it}\let\do=\toindex\doverb}% \tt % argument printed + sent to index \def\@idx#1{#1\toindex{#1}} \def\idx{\gdef\f@nt{rm}\let\do=\@idx\doverb} % to index + set up as key (keyword) \def\@keyidx#1{{\bf\@idx{#1}}} \def\teb{\gdef\f@nt{tt}\let\do=\@keyidx\doverb} % to index + set up as kbd (verbatim) \def\@kbdidx#1{{\tt\@idx{#1}}} \def\tet{\gdef\f@nt{tt}\let\do=\@kbdidx\doverb} \def\@url#1{\hbox{\tt#1}} \def\url{\let\do=\@url\doverb} % to index + set up as var (variable) \def\@kbdvar#1{{\it\@idx{#1}\/}} \def\tev{\gdef\f@nt{it}\let\do=\@kbdvar\doverb} \def\@synt#1#2{\gdef\f@nt{tt}\toindex{#1} The library syntax is \key{#1}({\tt #2})} \def\synt{\let\do=\@synt\doverb} % function prototypes \def\funno#1#2#3{\tolerance 1000% \noindent{\tt#1 #2(#3)}\catcode`\,=12\penalty-100{}} % no index \def\@fun#1#2#3{\gdef\f@nt{tt}\toindex{#2}\funno{#1}{#2}{#3}} \def\fun{\let\do=\@fun\doverbbbcomma} \def\@doc#1#2{\gdef\f@nt{tt}\toindex{#1}\noindent{\tt#2}} \def\doc{\let\do=\@doc\doverbb} %% %% SECTIONS %% \newcount\appno \newcount\chapno \newcount\secno \newcount\subsecno \newcount\subsubsecno \def\newpage{\hbox{}\vfill\eject} %Table of contents. cf TeXBook Exercise 21.10 \def\tocwrite#1{{\let\the=0\edef\next{\condwrite\toc{#1}}\next}} \let\putchapdest\relax \let\sectionhook\relax \def\title#1#2{% \ifodd\pageno\else\newpage\fi \tocwrite{{\bf #1 #2\string\dotfill\the\pageno}} \ifGPHELP\else \putchapdest \centerline{\chaptertitlefont #1}\medskip \fi \centerline{\let\bf\chaptertitlebf \chaptertitlefont #2}\vskip1cm} \def\sectitle#1{% \ifGPHELP\else% \vskip 0pt plus 54pt\penalty-600% good break \vskip 24pt plus -45pt minus 9pt\fi% \putchapdest% \tocwrite{{\hskip0.5cm#1\string\dotfill\the\pageno}}% \leftline{\sectionhook{\sectiontitlebf #1}.} \penalty10000 % impossible break \smallskip}% whatever follows will add a \parskip \def\subsectitle#1{% \ifGPHELP\else% \vskip 0pt plus 45pt\penalty-300 \vskip 6pt plus -42pt minus 3pt\fi% \ifSUBSECTOC\tocwrite{{\sevenrm \hskip1cm#1\string\dotfill\the\pageno}}\fi% \sectionhook\noindent{\bf#1}.} \def\subsubsectitle#1{% a \parskip is being added anyway by \noindent \ifGPHELP\else% \par\vskip 0pt plus 39pt\penalty-200 \vskip 0pt plus -37pt minus 1.5pt\fi% \sectionhook\noindent{\bf#1}.} \ifGPHELP \let\maketitle\relax \else \def\maketitle{% \ifnum\chapno=0 \currentlabel. \else \number\chapno.\currentlabel\ \fi} \fi \def\misctitle#1{\par\vskip 0pt plus 66pt\penalty-400 \vskip 3pt plus -64pt minus 1.5pt\noindent{\bf #1.}} % Chapter headings occupy two lines in the manual (only one in % INSTALL.tex and gphelp-extracted bits). Syntax requirement: After calling % \chapter{...} and possibly \label{...} etc, an empty line _must_ follow % before the first paragraph of text or section heading begins. [GN] \def\chapter#1#2\par{ \secno=0\global\advance\chapno by 1 \title{Chapter \number\chapno:}{#1}#2\noindent\ignorespaces} \def\appendix#1\par{ \chapno=0 \secno=0\global\advance\appno by 1 \def\applet{\ifcase\appno\or A\or B\or C\or D\or E\or F\or G\fi} \title{Appendix \applet:}{#1}\noindent\ignorespaces} \def\section#1{% \subsecno=0\global\advance\secno by 1% \gdef\currentlabel{\number\secno}% \sectitle{\maketitle#1}} \def\subsec#1{ \subsubsecno=0\global\advance\subsecno by 1 \gdef\currentlabel{\number\secno.\number\subsecno} \subsectitle{\maketitle#1}} \def\subsubsec#1{ \global\advance\subsubsecno by 1 \gdef\currentlabel{\number\secno.\number\subsecno.\number\subsubsecno} \subsubsectitle{\maketitle#1}} \def\annotepar#1{\noindent\llap{#1:\ \ }} \def\emacs{\annotepar{EMACS}} \def\subseckbd#1{\subsec{\kbd{#1}}} % % General purpose % \def\begintitle{ \begingroup\nopagenumbers \font\mine=cmb10 scaled 1893 \hbox{} } \def\authors{ \centerline{The PARI Group} \vskip 1.truecm \centerline{Institut de Math\'ematiques de Bordeaux, UMR 5251 du CNRS.} \centerline{Universit\'e de Bordeaux, 351 Cours de la Lib\'eration} \centerline{F-33405 TALENCE Cedex, FRANCE} \centerline{\tt e-mail: pari@math.u-bordeaux.fr} \vskip 1.5truecm \centerline{\sectiontitlebf Home Page:} \centerline{\kbd{http://pari.math.u-bordeaux.fr/}} \vskip 2.truecm } \def\copyrightpage{ \begintitle \vskip 14cm \noindent Copyright \copyright\ 2000--2018 The PARI Group \medskip\par \noindent Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. \medskip\par \noindent Permission is granted to copy and distribute modified versions, or translations, of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. \bigskip\par \noindent PARI/GP is Copyright \copyright\ 2000--2018 The PARI Group \medskip\par \noindent PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. \endtitle } \def\endtitle{\newpage\endgroup} % fraktur font \newfam\euffam \font\teneuf=eufm10 \font\eighteuf=eufm8 \font\seveneuf=eufm7 \textfont\euffam=\teneuf \scriptfont\euffam=\eighteuf \scriptscriptfont\euffam=\seveneuf \def\goth#1{{\fam\euffam#1}} \def\kbd#1{{\tt #1}} \def\key#1{{\bf #1}} \def\emph#1{{\it #1\/}} \def\var#1{\hbox{\it #1\/}} \def\floor#1{\left\lfloor #1 \right\rfloor} \def\ceil#1{\left\lceil #1 \right\rceil} \def\round#1{\left\lfloor #1 \right\rceil} \def\fl{\var{f\kern0pt lag}} \def\Cl{\text{Cl}} \def\gcd{\text{gcd}} \def\lcm{\text{lcm}} \def\Norm{\text{Norm}} \def\Hom{\text{Hom}} \def\Frob{\text{Frob}} \def\Id{\text{Id}} \def\disc{\text{disc}} \def\item{$\bullet$~} %\def\nmid{\not\mid} % Ugly \def\bs{{\char'134}} \def\obr{{\char'173}} \def\cbr{{\char'175}} \def\pow{\^{}\hskip0pt} \def\til{\raise-0.3em\hbox{\~{}}} \def\b#1{{\tt \bs#1}} \def\mod{\,{\rm mod}\,} \def\text#1{{\rm#1}} \def\dfrac#1#2{{{#1}\over{#2}}} \def\binom#1#2{\pmatrix{{#1}\cr{#2}}} \def\Bbb#1{{\bf #1}} {\catcode`\_=11 \gdef\typ#1{\kbd{t_#1}}} \def\Z{\Bbb Z} \def\Q{\Bbb Q} \def\F{\Bbb F} \def\P{\Bbb P} \def\R{\Bbb R} \def\C{\Bbb C} \def\dotfill{\leaders\hbox to 3truemm{\hfil.\hfil}\hfill} \def\B{\kbd{BITS\_IN\_LONG}} \def\op{{\it op\/}} % verbatim mode % @ made active: assume verbatim text doesn't contain it \newif\ifnopar {\catcode`\^=13\global\let^=\pow\obeyspaces\global\let \ } \def\ttverb{% \nopartrue \catcode`\_=12% \catcode`\$=12% \catcode`\\=12% \catcode`\{=12% \catcode`\}=12% \catcode`\&=12% \catcode`\#=12% \catcode`\%=12% \catcode`\^=13% \catcode`\~=13\def~{{\til}}% \catcode`\@=0% \def\par{\futurelet\next\dopars}% \def\dopars{% \ifnopar \noparfalse% \else% treat two consecutive \par specialy \ifx\next\par \vskip4pt plus 1pt\nopartrue% \else \leavevmode\endgraf\fi\fi}% \obeyspaces\obeylines\tt} % back to normalcy \def\unverb{% \catcode`\\=0% \catcode`\{=1% \catcode`\}=2% \catcode`\$=3% \catcode`\&=4% \catcode`\#=6% \catcode`\^=7% \catcode`\_=8% \catcode`\^^I=10} \def\bprog{\begingroup% \vskip 0pt plus 1pt% \leavevmode\parskip=0pt plus 1pt% \interlinepenalty2000\clubpenalty9000\widowpenalty9000% \ttverb} \def\bprogfile#1{\bprog\input#1\eprog} \def\eprog{\endgroup\par} {\obeylines \gdef\com{\begingroup\unverb\comstart} \gdef\comstart#1^^M{\it#1\endgroup } % newline after @endgroup is important } % comments \def\Ccom{\begingroup\unverb\Ccomstart} \def\Ccomstart#1*/{\rm#1\endgroup*/} \ifPDF \input pdfmacs.tex \fi \catcode`\@=12 pari-2.11.2/doc/pdfmacs.tex0000644000175000017500000001206013036414401014055 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License %% Modifications to parimacro.tex to be run through pdftex instead of %% tex. Code now includes some pdf-specific code for hyperlinks. %% %% Cliff Bergman (cbergman@iastate.edu) Jan. 2000. %% % %% Set the document info \pdfoutput = 1 \pdfinfo { /Title (\TITLE) /Creator (pdfTeX) /Producer (PARI, pari@math.u-bordeaux.fr) /Author (C. Batut, K. Belabas, D. Bernardi, H. Cohen, M. Olivier) /Subject (Number Theory) } % \pdfcatalog {/PageMode /UseOutlines} % \catcode`\@=11 %% Now we redefine several of the macros so as to provide hyperlinks. % % Colors % %% We use TeX's grouping mechanism to make \currentcolor into a stack. % \def\pushcolor#1{\bgroup\pdfsetcolor{#1}} \def\popcolor{\egroup\pdfsetcolor{\currentcolor}} \def\pdfsetcolor#1{\let\currentcolor=#1\pdfliteral{#1 k}} % % % % Maybe somebody with a better eye would like to pick nicer ones. See % % the file plain/misc/pdfcolor.tex in the pdftex distribution. % % \def\Red{0 1 1 0} \def\Blue{1 1 0 0} \def\Green{1 0 1 0} \def\Black{0 0 0 1} \def\textcolor{\Black} \def\linkcolor{\Red} \def\emacscolor{\Green} \def\unixcolor{\Blue} \let\currentcolor=\textcolor \pdfsetcolor{\textcolor} % %% Bookmarks. These turned out to be a pain. In order to get nested %% bookmarks, Acrobat requires that each entry declare the number of %% subentries in advance. We do this by counting the subentries (the %% main entries are the chapters, subentries are the sections) during %% the first pass and writing them to the aux file as a macro. Then the %% bookmark entry is created on the second pass. % These keep track of the number of sections in each chapter and appendix. \newtoks\numsectok \numsectok={\or} \newtoks\numsecapptok \numsecapptok={\or} % Append #1 to the token list given in #2, separated by \or. #1 is % expanded first (needed by \numsecs) \def\append#1#2{\toks0=\expandafter{#1 \or }% \edef\act{\global\noexpand#2={\the#2 \the\toks0}}\act} \def\writesecnumbers{ % Append the number of sections to the last appendix to the toks reg. \append{\the\secno}\numsecapptok % Write the definitions of (\numsecs and \numsecapp) to the aux file. \write\aux{ \def\string\numsecs\string##1{% \string\ifcase \string##1 \the\numsectok 0 \string\else 0 \string\fi} \def\string\numsecsapp\string##1{% \string\ifcase \string##1 \the\numsecapptok 0 \string\else 0 \string\fi}}} % % Hyperlink destinations will simply be of the form: pdf@nnn, where nnn % is obtained from a new counter. \newcount\pdfdestcntr \pdfdestcntr=0 % \putdest creates a pdf destination. Currently, the destination view % is 'xyz' which means no change from the existing zoom factor. \def\putdest{\global\advance\pdfdestcntr by 1% \pdfdest name {pdf@\number\pdfdestcntr} xyz } %% It turns out that I also need a different counter for these %% destinations since they are only computed on the second pass. \newcount\pdfchapcntr \pdfchapcntr=0 \def\putchapdest{\global\advance\pdfchapcntr by1% \pdfdest name {pdfchap@\number\pdfchapcntr} fitbh } \def\chapter#1#2\par{ \ifnum\chapno=0 \else \append{\the\secno}\numsectok \fi \secno=0\global\advance\chapno by 1 \title{Chapter \number\chapno:}{#1}#2\noindent\ignorespaces \ifsecondpass \pdfoutline goto name {pdfchap@\number\pdfchapcntr} count -\numsecs\chapno {\number\chapno\ #1} \fi } \def\appendix#1{ \ifnum\appno=0 \append{\the\secno}\numsectok \else \append{\the\secno}\numsecapptok \fi \chapno=0 \global\secno=0\global\advance\appno by 1 \def\applet{\ifcase\appno\or A\or B\or C\or D\or E\or F\or G\fi} \title{Appendix \applet:}{#1}\noindent\ignorespaces \ifsecondpass \pdfoutline goto name {pdfchap@\number\pdfchapcntr} count -\numsecsapp\appno {\applet\ #1} \fi} \def\section#1{ \subsecno=0\global\advance\secno by 1 \gdef\currentlabel{\number\secno} \sectitle{\maketitle{#1}} \ifsecondpass \pdfoutline goto name {pdfchap@\number\pdfchapcntr} {\number\chapno.\number\secno\ #1} \fi } % %% FIXME: should use \[push|pop]color and not use explicitly \textcolor %% (cf install() in Chapter 3) \def\@restore{\endgraf \global\let\par\endgraf \pdfsetcolor{\textcolor}} \def\unix{\global\let\par\@restore\pdfsetcolor{\unixcolor}\annotepar{UNIX}} \def\emacs{\global\let\par\@restore\pdfsetcolor{\emacscolor}\annotepar{EMACS}} %% labels and symbolic cross-refs. For this we use the parameter to %% build the symbolic pdf destination. \@ifundef{pdfstartlink}{\global\let\pdfstartlink\pdfannotlink}{} \def\label#1{\immediate\write\aux{\string \newlabel{#1}{{\the\chapno}{\currentlabel}}} \pdfdest name {pdf@lab#1} xyz} \def\ref#1{\@ifundef{r@#1} {{\bf ??}\@errundef{#1}} {\edef\@temp{\csname r@#1\endcsname}% \def\lbl{\@ref}\def\chp{\@cref}% \pdfjumpref{#1}{\ifx\chp{\the\chapno}\lbl\else\chp.\lbl\fi}}} \def\pdfjumpref#1#2{\pdfstartlink attr {/Border [ 0 0 0 ] /H /O} goto name {pdf@lab#1}\pushcolor{\linkcolor}#2\popcolor\pdfendlink} pari-2.11.2/doc/usersch3.tex0000644000175000017500000445011713461305062014220 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \chapter{Functions and Operations Available in PARI and GP} \label{se:functions} The functions and operators available in PARI and in the GP/PARI calculator are numerous and ever-expanding. Here is a description of the ones available in version \vers. It should be noted that many of these functions accept quite different types as arguments, but others are more restricted. The list of acceptable types will be given for each function or class of functions. Except when stated otherwise, it is understood that a function or operation which should make natural sense is legal. On the other hand, many routines list explicit preconditions for some of their argument, e.g. $p$ is a prime number, or $q$ is a positive definite quadratic form. For reasons of efficiency, all trust the user input and only perform minimal sanity checks. When a precondition is not satisfied, any of the following may occur: a regular exception is raised, the PARI stack overflows, a \kbd{SIGSEGV} or \kbd{SIGBUS} signal is generated, or we enter an infinite loop. The function can also quietly return a mathematically meaningless result: junk in, junk out. In this chapter, we will describe the functions according to a rough classification. The general entry looks something like: \key{foo}$(x,\{\fl=0\})$: short description. The library syntax is \kbd{GEN foo(GEN x, long fl = 0)}. \noindent This means that the GP function \kbd{foo} has one mandatory argument $x$, and an optional one, $\fl$, whose default value is 0. (The $\{\}$ should not be typed, it is just a convenient notation we will use throughout to denote optional arguments.) That is, you can type \kbd{foo(x,2)}, or \kbd{foo(x)}, which is then understood to mean \kbd{foo(x,0)}. As well, a comma or closing parenthesis, where an optional argument should have been, signals to GP it should use the default. Thus, the syntax \kbd{foo(x,)} is also accepted as a synonym for our last expression. When a function has more than one optional argument, the argument list is filled with user supplied values, in order. When none are left, the defaults are used instead. Thus, assuming that \kbd{foo}'s prototype had been $$\hbox{% \key{foo}$(\{x=1\},\{y=2\},\{z=3\})$,% }$$ typing in \kbd{foo(6,4)} would give you \kbd{foo(6,4,3)}. In the rare case when you want to set some far away argument, and leave the defaults in between as they stand, you can use the ``empty arg'' trick alluded to above: \kbd{foo(6,,1)} would yield \kbd{foo(6,2,1)}. By the way, \kbd{foo()} by itself yields \kbd{foo(1,2,3)} as was to be expected. In this rather special case of a function having no mandatory argument, you can even omit the $()$: a standalone \kbd{foo} would be enough (though we do not recommend it for your scripts, for the sake of clarity). In defining GP syntax, we strove to put optional arguments at the end of the argument list (of course, since they would not make sense otherwise), and in order of decreasing usefulness so that, most of the time, you will be able to ignore them. Finally, an optional argument (between braces) followed by a star, like $\{\var{x}\}*$, means that any number of such arguments (possibly none) can be given. This is in particular used by the various \kbd{print} routines. \misctitle{Flags} A \tev{flag} is an argument which, rather than conveying actual information to the routine, instructs it to change its default behavior, e.g.~return more or less information. All such flags are optional, and will be called \fl\ in the function descriptions to follow. There are two different kind of flags \item generic: all valid values for the flag are individually described (``If \fl\ is equal to $1$, then\dots''). \item binary:\sidx{binary flag} use customary binary notation as a compact way to represent many toggles with just one integer. Let $(p_0,\dots,p_n)$ be a list of switches (i.e.~of properties which take either the value $0$ or~$1$), the number $2^3 + 2^5 = 40$ means that $p_3$ and $p_5$ are set (that is, set to $1$), and none of the others are (that is, they are set to $0$). This is announced as ``The binary digits of $\fl$ mean 1: $p_0$, 2: $p_1$, 4: $p_2$'', and so on, using the available consecutive powers of~$2$. \misctitle{Mnemonics for binary flags} Numeric flags as mentioned above are obscure, error-prone, and quite rigid: should the authors want to adopt a new flag numbering scheme, it would break backward compatibility. The only advantage of explicit numeric values is that they are fast to type, so their use is only advised when using the calculator \kbd{gp}. As an alternative, one can replace a binary flag by a character string containing symbolic identifiers (mnemonics). In the function description, mnemonics corresponding to the various toggles are given after each of them. They can be negated by prepending \kbd{no\_} to the mnemonic, or by removing such a prefix. These toggles are grouped together using any punctuation character (such as ',' or ';'). For instance (taken from description of $\tet{ploth}(X=a,b,\var{expr},\{\fl=0\},\{n=0\})$) \centerline{Binary digits of flags mean: $1=\kbd{Parametric}$, $2=\kbd{Recursive}$, \dots} \noindent so that, instead of $1$, one could use the mnemonic \kbd{"Parametric; no\_Recursive"}, or simply \kbd{"Parametric"} since \kbd{Recursive} is unset by default (default value of $\fl$ is $0$, i.e.~everything unset). People used to the bit-or notation in languages like C may also use the form \kbd{"Parametric | no\_Recursive"}. \misctitle{Pointers} \varsidx{pointer} If a parameter in the function prototype is prefixed with a \& sign, as in \key{foo}$(x,\&e)$ \noindent it means that, besides the normal return value, the function may assign a value to $e$ as a side effect. When passing the argument, the \& sign has to be typed in explicitly. As of version \vers, this \tev{pointer} argument is optional for all documented functions, hence the \& will always appear between brackets as in \kbd{Z\_issquare}$(x,\{\&e\})$. \misctitle{About library programming} The \var{library} function \kbd{foo}, as defined at the beginning of this section, is seen to have two mandatory arguments, $x$ and \fl: no function seen in the present chapter has been implemented so as to accept a variable number of arguments, so all arguments are mandatory when programming with the library (usually, variants are provided corresponding to the various flag values). We include an \kbd{= default value} token in the prototype to signal how a missing argument should be encoded. Most of the time, it will be a \kbd{NULL} pointer, or -1 for a variable number. Refer to the \emph{User's Guide to the PARI library} for general background and details. \section{Programming in GP: control statements} \sidx{programming}\label{se:programming} A number of control statements are available in GP. They are simpler and have a syntax slightly different from their C counterparts, but are quite powerful enough to write any kind of program. Some of them are specific to GP, since they are made for number theorists. As usual, $X$ will denote any simple variable name, and \var{seq} will always denote a sequence of expressions, including the empty sequence. \misctitle{Caveat} In constructs like \bprog for (X = a,b, seq) @eprog\noindent the variable \kbd{X} is lexically scoped to the loop, leading to possibly unexpected behavior: \bprog n = 5; for (n = 1, 10, if (something_nice(), break); ); \\ @com at this point \kbd{n} is 5 ! @eprog\noindent If the sequence \kbd{seq} modifies the loop index, then the loop is modified accordingly: \bprog ? for (n = 1, 10, n += 2; print(n)) 3 6 9 12 @eprog \subsec{break$(\{n=1\})$}\kbdsidx{break}\label{se:break} Interrupts execution of current \var{seq}, and immediately exits from the $n$ innermost enclosing loops, within the current function call (or the top level loop); the integer $n$ must be positive. If $n$ is greater than the number of enclosing loops, all enclosing loops are exited. \subsec{breakpoint$()$}\kbdsidx{breakpoint}\label{se:breakpoint} Interrupt the program and enter the breakloop. The program continues when the breakloop is exited. \bprog ? f(N,x)=my(z=x^2+1);breakpoint();gcd(N,z^2+1-z); ? f(221,3) *** at top-level: f(221,3) *** ^-------- *** in function f: my(z=x^2+1);breakpoint();gcd(N,z *** ^-------------------- *** Break loop: type to continue; 'break' to go back to GP break> z 10 break> %2 = 13 @eprog \subsec{dbg\_down$(\{n=1\})$}\kbdsidx{dbg_down}\label{se:dbg_down} (In the break loop) go down n frames. This allows to cancel a previous call to \kbd{dbg\_up}. \subsec{dbg\_err$()$}\kbdsidx{dbg_err}\label{se:dbg_err} In the break loop, return the error data of the current error, if any. See \tet{iferr} for details about error data. Compare: \bprog ? iferr(1/(Mod(2,12019)^(6!)-1),E,Vec(E)) %1 = ["e_INV", "Fp_inv", Mod(119, 12019)] ? 1/(Mod(2,12019)^(6!)-1) *** at top-level: 1/(Mod(2,12019)^(6!)- *** ^-------------------- *** _/_: impossible inverse in Fp_inv: Mod(119, 12019). *** Break loop: type 'break' to go back to GP prompt break> Vec(dbg_err()) ["e_INV", "Fp_inv", Mod(119, 12019)] @eprog \subsec{dbg\_up$(\{n=1\})$}\kbdsidx{dbg_up}\label{se:dbg_up} (In the break loop) go up n frames. This allows to inspect data of the parent function. To cancel a \tet{dbg_up} call, use \tet{dbg_down} \subsec{dbg\_x$(A,\{n\})$}\kbdsidx{dbg_x}\label{se:dbg_x} Print the inner structure of \kbd{A}, complete if \kbd{n} is omitted, up to level \kbd{n} otherwise. This is useful for debugging. This is similar to \b{x} but does not require \kbd{A} to be an history entry. In particular, it can be used in the break loop. \subsec{for$(X=a,b,\var{seq})$}\kbdsidx{for}\label{se:for} Evaluates \var{seq}, where the formal variable $X$ goes from $a$ to $b$. Nothing is done if $a>b$. $a$ and $b$ must be in $\R$. If $b$ is set to \kbd{+oo}, the loop will not stop; it is expected that the caller will break out of the loop itself at some point, using \kbd{break} or \kbd{return}. \subsec{forcomposite$(n=a,\{b\},\var{seq})$}\kbdsidx{forcomposite}\label{se:forcomposite} Evaluates \var{seq}, where the formal variable $n$ ranges over the composite numbers between the non-negative real numbers $a$ to $b$, including $a$ and $b$ if they are composite. Nothing is done if $a>b$. \bprog ? forcomposite(n = 0, 10, print(n)) 4 6 8 9 10 @eprog\noindent Omitting $b$ means we will run through all composites $\geq a$, starting an infinite loop; it is expected that the user will break out of the loop himself at some point, using \kbd{break} or \kbd{return}. Note that the value of $n$ cannot be modified within \var{seq}: \bprog ? forcomposite(n = 2, 10, n = []) *** at top-level: forcomposite(n=2,10,n=[]) *** ^--- *** index read-only: was changed to []. @eprog \subsec{fordiv$(n,X,\var{seq})$}\kbdsidx{fordiv}\label{se:fordiv} Evaluates \var{seq}, where the formal variable $X$ ranges through the divisors of $n$ (see \tet{divisors}, which is used as a subroutine). It is assumed that \kbd{factor} can handle $n$, without negative exponents. Instead of $n$, it is possible to input a factorization matrix, i.e. the output of \kbd{factor(n)}. This routine uses \kbd{divisors} as a subroutine, then loops over the divisors. In particular, if $n$ is an integer, divisors are sorted by increasing size. To avoid storing all divisors, possibly using a lot of memory, the following (much slower) routine loops over the divisors using essentially constant space: \bprog FORDIV(N)= { my(P, E); P = factor(N); E = P[,2]; P = P[,1]; forvec( v = vector(#E, i, [0,E[i]]), X = factorback(P, v) \\ ... ); } ? for(i=1,10^5, FORDIV(i)) time = 3,445 ms. ? for(i=1,10^5, fordiv(i, d, )) time = 490 ms. @eprog \subsec{fordivfactored$(n,X,\var{seq})$}\kbdsidx{fordivfactored}\label{se:fordivfactored} Evaluates \var{seq}, where the formal variable $X$ ranges through $[d, \kbd{factor}(d)]$, where $d$ is a divisors of $n$ (see \tet{divisors}, which is used as a subroutine). Note that such a pair is accepted as argument to all multiplicative functions. It is assumed that \kbd{factor} can handle $n$, without negative exponents. Instead of $n$, it is possible to input a factorization matrix, i.e. the output of \kbd{factor(n)}. This routine uses \kbd{divisors}$(,1)$ as a subroutine, then loops over the divisors. In particular, if $n$ is an integer, divisors are sorted by increasing size. This function is particularly useful when $n$ is hard to factor and one must evaluate multiplicative function on its divisors: we avoid refactoring each divisor in turn. It also provides a small speedup when $n$ is easy to factor; compare \bprog ? A = 10^8; B = A + 10^5; ? for (n = A, B, fordiv(n, d, eulerphi(d))); time = 2,091 ms. ? for (n = A, B, fordivfactored(n, d, eulerphi(d))); time = 1,298 ms. \\ avoid refactoring the divisors ? forfactored (n = A, B, fordivfactored(n, d, eulerphi(d))); time = 1,270 ms. \\ also avoid factoring the consecutive n's ! @eprog \subsec{forell$(E,a,b,\var{seq},\{\fl=0\})$}\kbdsidx{forell}\label{se:forell} Evaluates \var{seq}, where the formal variable $E = [\var{name}, M, G]$ ranges through all elliptic curves of conductors from $a$ to $b$. In this notation \var{name} is the curve name in Cremona's elliptic curve database, $M$ is the minimal model, $G$ is a $\Z$-basis of the free part of the Mordell-Weil group $E(\Q)$. If flag is non-zero, select only the first curve in each isogeny class. \bprog ? forell(E, 1, 500, my([name,M,G] = E); \ if (#G > 1, print(name))) 389a1 433a1 446d1 ? c = 0; forell(E, 1, 500, c++); c \\ number of curves %2 = 2214 ? c = 0; forell(E, 1, 500, c++, 1); c \\ number of isogeny classes %3 = 971 @eprog\noindent The \tet{elldata} database must be installed and contain data for the specified conductors. \synt{forell}{void *data, long (*f)(void*,GEN), long a, long b, long flag}. \subsec{forfactored$(N=a,b,\var{seq})$}\kbdsidx{forfactored}\label{se:forfactored} Evaluates \var{seq}, where the formal variable $N$ is $[n, \kbd{factor}(n)]$ and $n$ goes from $a$ to $b$; $a$ and $b$ must be integers. Nothing is done if $a>b$. This function is only implemented for $|a|, |b| < 2^{64}$ ($2^{32}$ on a 32-bit machine). It uses a sieve and runs in time $O(\sqrt{b} + b-a)$. It should be at least 3 times faster than regular factorization as long as the interval length $b-a$ is much larger than $\sqrt{b}$ and get relatively faster as the bounds increase. The function slows down dramatically if $\kbd{primelimit} < \sqrt{b}$. \bprog ? B = 10^9; ? for (N = B, B+10^6, factor(N)) time = 4,538 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 1,031 ms. ? B = 10^11; ? for (N = B, B+10^6, factor(N)) time = 15,575 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 2,375 ms. ? B = 10^14; ? for (N = B, B+10^6, factor(N)) time = 1min, 4,948 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 58,601 ms. @eprog\noindent The last timing is with the default \kbd{primelimit} (500000) which is much less than $\sqrt{B+10^6}$; it goes down to \kbd{26,750ms} if \kbd{primelimit} gets bigger than that bound. In any case $\sqrt{B+10^6}$ is much larger than the interval length $10^6$ so \kbd{forfactored} gets relatively slower for that reason as well. Note that all PARI multiplicative functions accept the \kbd{[n,fan]} argument natively: \bprog ? s = 0; forfactored(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 6,001 ms. %1 = 6393738650 ? s = 0; for(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 28,398 ms. \\ slower, we must factor N. Twice. %2 = 6393738650 @eprog The following loops over the fundamental dicriminants less than $X$: \bprog ? X = 10^8; ? forfactored(d=1,X, if (isfundamental(d),)); time = 34,030 ms. ? for(d=1,X, if (isfundamental(d),)) time = 1min, 24,225 ms. @eprog \subsec{forpart$(X=k,\var{seq},\{a=k\},\{n=k\})$}\kbdsidx{forpart}\label{se:forpart} Evaluate \var{seq} over the partitions $X=[x_1,\dots x_n]$ of the integer $k$, i.e.~increasing sequences $x_1\leq x_2\dots \leq x_n$ of sum $x_1+\dots + x_n=k$. By convention, $0$ admits only the empty partition and negative numbers have no partitions. A partition is given by a \typ{VECSMALL}, where parts are sorted in nondecreasing order. The partitions are listed by increasing size and in lexicographic order when sizes are equal: \bprog ? forpart(X=4, print(X)) Vecsmall([4]) Vecsmall([1, 3]) Vecsmall([2, 2]) Vecsmall([1, 1, 2]) Vecsmall([1, 1, 1, 1]) @eprog\noindent Optional parameters $n$ and $a$ are as follows: \item $n=\var{nmax}$ (resp. $n=[\var{nmin},\var{nmax}]$) restricts partitions to length less than $\var{nmax}$ (resp. length between $\var{nmin}$ and $nmax$), where the \emph{length} is the number of nonzero entries. \item $a=\var{amax}$ (resp. $a=[\var{amin},\var{amax}]$) restricts the parts to integers less than $\var{amax}$ (resp. between $\var{amin}$ and $\var{amax}$). By default, parts are positive and we remove zero entries unless $amin\leq0$, in which case we fix the size $\#X = \var{nmax}$: \bprog \\ at most 3 non-zero parts, all <= 4 ? forpart(v=5,print(Vec(v)), 4, 3) [1, 4] [2, 3] [1, 1, 3] [1, 2, 2] \\ between 2 and 4 parts less than 5, fill with zeros ? forpart(v=5,print(Vec(v)),[0,5],[2,4]) [0, 0, 1, 4] [0, 0, 2, 3] [0, 1, 1, 3] [0, 1, 2, 2] [1, 1, 1, 2] \\ no partitions of 1 with 2 to 4 non-zero parts ? forpart(v=1,print(v),[0,5],[2,4]) ? @eprog\noindent The behavior is unspecified if $X$ is modified inside the loop. \synt{forpart}{void *data, long (*call)(void*,GEN), long k, GEN a, GEN n}. \subsec{forperm$(a,p,\var{seq})$}\kbdsidx{forperm}\label{se:forperm} Evaluates \var{seq}, where the formal variable $p$ goes through some permutations given by a \typ{VECSMALL}. If $a$ is a positive integer then $P$ goes through the permutations of $\{1, 2, ..., a\}$ in lexicographic order and if $a$ is a small vector then $p$ goes through the (multi)permutations lexicographically larger than or equal to $a$. \bprog ? forperm(3, p, print(p)) Vecsmall([1, 2, 3]) Vecsmall([1, 3, 2]) Vecsmall([2, 1, 3]) Vecsmall([2, 3, 1]) Vecsmall([3, 1, 2]) Vecsmall([3, 2, 1]) @eprog\noindent When $a$ is itself a \typ{VECSMALL} or a \typ{VEC} then $p$ iterates through multipermutations \bprog ? forperm([2,1,1,3], p, print(p)) Vecsmall([2, 1, 1, 3]) Vecsmall([2, 1, 3, 1]) Vecsmall([2, 3, 1, 1]) Vecsmall([3, 1, 1, 2]) Vecsmall([3, 1, 2, 1]) Vecsmall([3, 2, 1, 1]) @eprog\noindent \subsec{forprime$(p=a,\{b\},\var{seq})$}\kbdsidx{forprime}\label{se:forprime} Evaluates \var{seq}, where the formal variable $p$ ranges over the prime numbers between the real numbers $a$ to $b$, including $a$ and $b$ if they are prime. More precisely, the value of $p$ is incremented to \kbd{nextprime($p$ + 1)}, the smallest prime strictly larger than $p$, at the end of each iteration. Nothing is done if $a>b$. \bprog ? forprime(p = 4, 10, print(p)) 5 7 @eprog\noindent Setting $b$ to \kbd{+oo} means we will run through all primes $\geq a$, starting an infinite loop; it is expected that the caller will break out of the loop itself at some point, using \kbd{break} or \kbd{return}. Note that the value of $p$ cannot be modified within \var{seq}: \bprog ? forprime(p = 2, 10, p = []) *** at top-level: forprime(p=2,10,p=[]) *** ^--- *** prime index read-only: was changed to []. @eprog \subsec{forprimestep$(p=a,b,q,\var{seq})$}\kbdsidx{forprimestep}\label{se:forprimestep} Evaluates \var{seq}, where the formal variable $p$ ranges over the prime numbers $p$ in an arithmetic progression in $[a,b]$: $q$ is either an integer ($p \equiv a \pmod{q}$) or an intmod \kbd{Mod(c,N)} and we restrict to that congruence class. Nothing is done if $a>b$. \bprog ? forprimestep(p = 4, 30, 5, print(p)) 19 29 ? forprimestep(p = 4, 30, Mod(1,5), print(p)) 11 @eprog\noindent Setting $b$ to \kbd{+oo} means we will run through all primes $\geq a$, starting an infinite loop; it is expected that the caller will break out of the loop itself at some point, using \kbd{break} or \kbd{return}. The current implementation restricts the modulus of the arithmetic progression to an unsigned long (64 or 32 bits). \bprog ? forprimestep(p=2,oo,2^64,print(p)) *** at top-level: forprimestep(p=2,oo,2^64,print(p)) *** ^---------------------------------- *** forprimestep: overflow in t_INT-->ulong assignment. @eprog Note that the value of $p$ cannot be modified within \var{seq}: \bprog ? forprimestep(p = 2, 10, 3, p = []) *** at top-level: forprimestep(p=2,10,3,p=[]) *** ^--- *** prime index read-only: was changed to []. @eprog \subsec{forsquarefree$(N=a,b,\var{seq})$}\kbdsidx{forsquarefree}\label{se:forsquarefree} Evaluates \var{seq}, where the formal variable $N$ is $[n, \kbd{factor}(n)]$ and $n$ goes through squarefree integers from $a$ to $b$; $a$ and $b$ must be integers of the same sign. Nothing is done if $a>b$. \bprog ? forsquarefree(N=2,10,print(N)) [2, Mat([2, 1])] [3, Mat([3, 1])] [5, Mat([5, 1])] [6, [2, 1; 3, 1]] [7, Mat([7, 1])] [10, [2, 1; 5, 1]] \\ negative numbers are allowed as well ? forsquarefree(N=-10,-3,print(N)) [-10, [-1, 1; 2, 1; 5, 1]] [-7, [-1, 1; 7, 1]] [-6, [-1, 1; 2, 1; 3, 1]] [-5, [-1, 1; 5, 1]] [-3, [-1, 1; 3, 1]] \\ but not bounds of different signs ? forsquarefree(N=-3,3,print(N)) *** at top-level: forsquarefree(N=-3,3,print(N)) *** ^------------------------------ *** forsquarefree: incorrect type in forsquarefree [!= signs] (t_VEC). @eprog This function is only implemented for $|a|, |b| < 2^{64}$ ($2^{32}$ on a 32-bit machine). It uses a sieve and runs in time $O(\sqrt{b} + b-a)$. It should be at least 5 times faster than regular factorization as long as the interval length $b-a$ is much larger than $\sqrt{b}$ and get relatively faster as the bounds increase. The function slows down dramatically if $\kbd{primelimit} < \sqrt{b}$. It is comparable to \kbd{forfactored}, but about $\zeta(2) = \pi^2/6$ times faster due to the relative density of squarefree integers. \bprog ? B = 10^9; ? for (N = B, B+10^6, factor(N)) time = 4,392 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 915 ms. ? forsquarefree (N = B, B+10^6, [n,fan] = N) time = 532 ms. ? B = 10^11; ? for (N = B, B+10^6, factor(N)) time = 13,053 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 1,976 ms. ? forsquarefree (N = B, B+10^6, [n,fan] = N) time = 1,245 ms. ? B = 10^14; ? for (N = B, B+10^6, factor(N)) time = 50,612 ms. ? forsquarefree (N = B, B+10^6, [n,fan] = N) time = 46,309 ms. @eprog\noindent The last timing is with the default \kbd{primelimit} (500000) which is much less than $\sqrt{B+10^6}$; it goes down to \kbd{20,396ms} if \kbd{primelimit} gets bigger than that bound. In any case $\sqrt{B+10^6}$ is much larger than the interval length $10^6$ so \kbd{forsquarefree} gets relatively slower for that reason as well. Note that all PARI multiplicative functions accept the \kbd{[n,fan]} argument natively: \bprog ? s = 0; forsquarefree(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 3,788 ms. %1 = 6393738650 ? s = 0; for(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 28,630 ms. \\ slower, we must factor N. Twice. %2 = 6393738650 @eprog The following loops over the fundamental dicriminants less than $X$: \bprog ? X = 10^8; ? for(d=1,X, if (isfundamental(d),)) time = 1min, 29,066 ms. ? forfactored(d=1,X, if (isfundamental(d),)); time = 42,387 ms. ? forsquarefree(d=1,X, D = quaddisc(d); if (D <= X, )); time = 32,479 ms. @eprog\noindent Note that in the last loop, the fundamental discriminants $D$ are not evaluated in order (since \kbd{quaddisc(d)} for squarefree $d$ is either $d$ or $4d$). This is the price we pay for a faster evaluation, and the set of numbers we run through is the same. We can run through negative fundamental discriminants in the same way \bprog ? forsquarefree(d=-X,-1, D = quaddisc(d); if (D >= -X, )); @eprog \subsec{forstep$(X=a,b,s,\var{seq})$}\kbdsidx{forstep}\label{se:forstep} Evaluates \var{seq}, where the formal variable $X$ goes from $a$ to $b$ in increments of $s$. Nothing is done if $s>0$ and $a>b$ or if $s<0$ and $a$), 2 (\typ{GEN}): a numerical limit $l$ bounding the allowed range, 3 (\kbd{GEN}): the index $x$. It satisfies $x$ \var{op} $l$. \item \kbd{"e\_DOMAIN"}. An argument is not in the function's domain. \var{E} has five components, 1 (\typ{STR}): the function name, 2 (\typ{STR}): the mathematical name of the out-of-domain argument 3 (\typ{STR}): an operator $\var{op}$ describing the domain error, 4 (\typ{GEN}): the numerical limit $l$ describing the domain error, 5 (\kbd{GEN}): the out-of-domain argument $x$. The argument satisfies $x$ \var{op} $l$, which prevents it from belonging to the function's domain. \item \kbd{"e\_MAXPRIME"}. A function using the precomputed list of prime numbers ran out of primes. \var{E} has one component, 1 (\typ{INT}): the requested prime bound, which overflowed \kbd{primelimit} or $0$ (bound is unknown). \item \kbd{"e\_MEM"}. A call to \tet{pari_malloc} or \tet{pari_realloc} failed. \var{E} has no component. \item \kbd{"e\_OVERFLOW"}. An object in function $s$ becomes too large to be represented within PARI's hardcoded limits. (As in \kbd{2\pow2\pow2\pow10} or \kbd{exp(1e100)}, which overflow in \kbd{lg} and \kbd{expo}.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_PREC"}. Function $s$ fails because input accuracy is too low. (As in \kbd{floor(1e100)} at default accuracy.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_STACK"}. The PARI stack overflows. \var{E} has no component. \misctitle{Errors triggered intentionally} \item \kbd{"e\_ALARM"}. A timeout, generated by the \tet{alarm} function. \var{E} has one component (\typ{STR}): the error message to print. \item \kbd{"e\_USER"}. A user error, as triggered by \tet{error}($g_1,\dots,g_n)$. \var{E} has one component, 1 (\typ{VEC}): the vector of $n$ arguments given to \kbd{error}. \misctitle{Mathematical errors} \item \kbd{"e\_CONSTPOL"}. An argument of function $s$ is a constant polynomial, which does not make sense. (As in \kbd{galoisinit(Pol(1))}.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_COPRIME"}. Function $s$ expected coprime arguments, and did receive $x,y$, which were not. \var{E} has three component, 1 (\typ{STR}): the function name $s$, 2: the argument $x$, 3: the argument $y$. \item \kbd{"e\_INV"}. Tried to invert a non-invertible object $x$ in function $s$. \var{E} has two components, 1 (\typ{STR}): the function name $s$, 2: the non-invertible $x$. If $x = \kbd{Mod}(a,b)$ is a \typ{INTMOD} and $a$ is not $0$ mod $b$, this allows to factor the modulus, as \kbd{gcd}$(a,b)$ is a non-trivial divisor of $b$. \item \kbd{"e\_IRREDPOL"}. Function $s$ expected an irreducible polynomial, and did receive $T$, which was not. (As in \kbd{nfinit(x\pow2-1)}.) \var{E} has two component, 1 (\typ{STR}): the function name $s$, 2 (\typ{POL}): the polynomial $x$. \item \kbd{"e\_MISC"}. Generic uncategorized error. \var{E} has one component (\typ{STR}): the error message to print. \item \kbd{"e\_MODULUS"}. moduli $x$ and $y$ submitted to function $s$ are inconsistent. As in \bprog nfalgtobasis(nfinit(t^3-2), Mod(t,t^2+1) @eprog\noindent \var{E} has three component, 1 (\typ{STR}): the function $s$, 2: the argument $x$, 3: the argument $x$. \item \kbd{"e\_PRIME"}. Function $s$ expected a prime number, and did receive $p$, which was not. (As in \kbd{idealprimedec(nf, 4)}.) \var{E} has two component, 1 (\typ{STR}): the function name $s$, 2: the argument $p$. \item \kbd{"e\_ROOTS0"}. An argument of function $s$ is a zero polynomial, and we need to consider its roots. (As in \kbd{polroots(0)}.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_SQRTN"}. Trying to compute an $n$-th root of $x$, which does not exist, in function $s$. (As in \kbd{sqrt(Mod(-1,3))}.) \var{E} has two components, 1 (\typ{STR}): the function name $s$, 2: the argument $x$. \subsec{next$(\{n=1\})$}\kbdsidx{next}\label{se:next} Interrupts execution of current $seq$, resume the next iteration of the innermost enclosing loop, within the current function call (or top level loop). If $n$ is specified, resume at the $n$-th enclosing loop. If $n$ is bigger than the number of enclosing loops, all enclosing loops are exited. \subsec{return$(\{x=0\})$}\kbdsidx{return}\label{se:return} Returns from current subroutine, with result $x$. If $x$ is omitted, return the \kbd{(void)} value (return no result, like \kbd{print}). \subsec{until$(a,\var{seq})$}\kbdsidx{until}\label{se:until} Evaluates \var{seq} until $a$ is not equal to 0 (i.e.~until $a$ is true). If $a$ is initially not equal to 0, \var{seq} is evaluated once (more generally, the condition on $a$ is tested \emph{after} execution of the \var{seq}, not before as in \kbd{while}). \subsec{while$(a,\var{seq})$}\kbdsidx{while}\label{se:while} While $a$ is non-zero, evaluates the expression sequence \var{seq}. The test is made \emph{before} evaluating the $seq$, hence in particular if $a$ is initially equal to zero the \var{seq} will not be evaluated at all. \section{Programming in GP: other specific functions} \label{se:gp_program} In addition to the general PARI functions, it is necessary to have some functions which will be of use specifically for \kbd{gp}, though a few of these can be accessed under library mode. Before we start describing these, we recall the difference between \emph{strings} and \emph{keywords} (see \secref{se:strings}): the latter don't get expanded at all, and you can type them without any enclosing quotes. The former are dynamic objects, where everything outside quotes gets immediately expanded. \subsec{Strprintf$(\var{fmt},\{x\}*)$}\kbdsidx{Strprintf}\label{se:Strprintf} Returns a string built from the remaining arguments according to the format fmt. The format consists of ordinary characters (not \%), printed unchanged, and conversions specifications. See \kbd{printf}. %\syn{NO} \subsec{addhelp$(\var{sym},\var{str})$}\kbdsidx{addhelp}\label{se:addhelp} Changes the help message for the symbol \kbd{sym}. The string \var{str} is expanded on the spot and stored as the online help for \kbd{sym}. It is recommended to document global variables and user functions in this way, although \kbd{gp} will not protest if you don't. You can attach a help text to an alias, but it will never be shown: aliases are expanded by the \kbd{?} help operator and we get the help of the symbol the alias points to. Nothing prevents you from modifying the help of built-in PARI functions. But if you do, we would like to hear why you needed it! Without \tet{addhelp}, the standard help for user functions consists of its name and definition. \bprog gp> f(x) = x^2; gp> ?f f = (x)->x^2 @eprog\noindent Once addhelp is applied to $f$, the function code is no longer included. It can still be consulted by typing the function name: \bprog gp> addhelp(f, "Square") gp> ?f Square gp> f %2 = (x)->x^2 @eprog The library syntax is \fun{void}{addhelp}{const char *sym, const char *str}. \subsec{alarm$(\{s = 0\},\{\var{code}\})$}\kbdsidx{alarm}\label{se:alarm} If \var{code} is omitted, trigger an \var{e\_ALARM} exception after $s$ seconds, cancelling any previously set alarm; stop a pending alarm if $s = 0$ or is omitted. Otherwise, if $s$ is positive, the function evaluates \var{code}, aborting after $s$ seconds. The return value is the value of \var{code} if it ran to completion before the alarm timeout, and a \typ{ERROR} object otherwise. \bprog ? p = nextprime(10^25); q = nextprime(10^26); N = p*q; ? E = alarm(1, factor(N)); ? type(E) %3 = "t_ERROR" ? print(E) %4 = error("alarm interrupt after 964 ms.") ? alarm(10, factor(N)); \\ enough time %5 = [ 10000000000000000000000013 1] [100000000000000000000000067 1] @eprog\noindent Here is a more involved example: the function \kbd{timefact(N,sec)} below tries to factor $N$ and gives up after \var{sec} seconds, returning a partial factorization. \bprog \\ Time-bounded partial factorization default(factor_add_primes,1); timefact(N,sec)= { F = alarm(sec, factor(N)); if (type(F) == "t_ERROR", factor(N, 2^24), F); } @eprog\noindent We either return the factorization directly, or replace the \typ{ERROR} result by a simple bounded factorization \kbd{factor(N, 2\pow 24)}. Note the \tet{factor_add_primes} trick: any prime larger than $2^{24}$ discovered while attempting the initial factorization is stored and remembered. When the alarm rings, the subsequent bounded factorization finds it right away. \misctitle{Caveat} It is not possible to set a new alarm \emph{within} another \kbd{alarm} code: the new timer erases the parent one. The library syntax is \fun{GEN}{gp_alarm}{long s, GEN code = NULL}. \subsec{alias$(\var{newsym},\var{sym})$}\kbdsidx{alias}\label{se:alias} Defines the symbol \var{newsym} as an alias for the symbol \var{sym}: \bprog ? alias("det", "matdet"); ? det([1,2;3,4]) %1 = -2 @eprog\noindent You are not restricted to ordinary functions, as in the above example: to alias (from/to) member functions, prefix them with `\kbd{\_.}'; to alias operators, use their internal name, obtained by writing \kbd{\_} in lieu of the operators argument: for instance, \kbd{\_!} and \kbd{!\_} are the internal names of the factorial and the logical negation, respectively. \bprog ? alias("mod", "_.mod"); ? alias("add", "_+_"); ? alias("_.sin", "sin"); ? mod(Mod(x,x^4+1)) %2 = x^4 + 1 ? add(4,6) %3 = 10 ? Pi.sin %4 = 0.E-37 @eprog Alias expansion is performed directly by the internal GP compiler. Note that since alias is performed at compilation-time, it does not require any run-time processing, however it only affects GP code compiled \emph{after} the alias command is evaluated. A slower but more flexible alternative is to use variables. Compare \bprog ? fun = sin; ? g(a,b) = intnum(t=a,b,fun(t)); ? g(0, Pi) %3 = 2.0000000000000000000000000000000000000 ? fun = cos; ? g(0, Pi) %5 = 1.8830410776607851098 E-39 @eprog\noindent with \bprog ? alias(fun, sin); ? g(a,b) = intnum(t=a,b,fun(t)); ? g(0,Pi) %2 = 2.0000000000000000000000000000000000000 ? alias(fun, cos); \\ Oops. Does not affect *previous* definition! ? g(0,Pi) %3 = 2.0000000000000000000000000000000000000 ? g(a,b) = intnum(t=a,b,fun(t)); \\ Redefine, taking new alias into account ? g(0,Pi) %5 = 1.8830410776607851098 E-39 @eprog A sample alias file \kbd{misc/gpalias} is provided with the standard distribution. The library syntax is \fun{void}{alias0}{const char *newsym, const char *sym}. \subsec{allocatemem$(\{s=0\})$}\kbdsidx{allocatemem}\label{se:allocatemem} This special operation changes the stack size \emph{after} initialization. The argument $s$ must be a non-negative integer. If $s > 0$, a new stack of at least $s$ bytes is allocated. We may allocate more than $s$ bytes if $s$ is way too small, or for alignment reasons: the current formula is $\max(16*\ceil{s/16}, 500032)$ bytes. If $s=0$, the size of the new stack is twice the size of the old one. This command is much more useful if \tet{parisizemax} is non-zero, and we describe this case first. With \kbd{parisizemax} enabled, there are three sizes of interest: \item a virtual stack size, \tet{parisizemax}, which is an absolute upper limit for the stack size; this is set by \kbd{default(parisizemax, ...)}. \item the desired typical stack size, \tet{parisize}, that will grow as needed, up to \tet{parisizemax}; this is set by \kbd{default(parisize, ...)}. \item the current stack size, which is less that \kbd{parisizemax}, typically equal to \kbd{parisize} but possibly larger and increasing dynamically as needed; \kbd{allocatemem} allows to change that one explicitly. The \kbd{allocatemem} command forces stack usage to increase temporarily (up to \kbd{parisizemax} of course); for instance if you notice using \kbd{\bs gm2} that we seem to collect garbage a lot, e.g. \bprog ? \gm2 debugmem = 2 ? default(parisize,"32M") *** Warning: new stack size = 32000000 (30.518 Mbytes). ? bnfinit('x^2+10^30-1) *** bnfinit: collecting garbage in hnffinal, i = 1. *** bnfinit: collecting garbage in hnffinal, i = 2. *** bnfinit: collecting garbage in hnffinal, i = 3. @eprog\noindent and so on for hundred of lines. Then, provided the \tet{breakloop} default is set, you can interrupt the computation, type \kbd{allocatemem(100*10\pow6)} at the break loop prompt, then let the computation go on by typing \kbd{}. Back at the \kbd{gp} prompt, the desired stack size of \kbd{parisize} is restored. Note that changing either \kbd{parisize} or \kbd{parisizemax} at the break loop prompt would interrupt the computation, contrary to the above. In most cases, \kbd{parisize} will increase automatically (up to \kbd{parisizemax}) and there is no need to perform the above maneuvers. But that the garbage collector is sufficiently efficient that a given computation can still run without increasing the stack size, albeit very slowly due to the frequent garbage collections. \misctitle{Deprecated: when \kbd{parisizemax} is unset} This is currently still the default behavior in order not to break backward compatibility. The rest of this section documents the behavior of \kbd{allocatemem} in that (deprecated) situation: it becomes a synonym for \kbd{default(parisize,...)}. In that case, there is no notion of a virtual stack, and the stack size is always equal to \kbd{parisize}. If more memory is needed, the PARI stack overflows, aborting the computation. Thus, increasing \kbd{parisize} via \kbd{allocatemem} or \kbd{default(parisize,...)} before a big computation is important. Unfortunately, either must be typed at the \kbd{gp} prompt in interactive usage, or left by itself at the start of batch files. They cannot be used meaningfully in loop-like constructs, or as part of a larger expression sequence, e.g \bprog allocatemem(); x = 1; \\@com This will not set \kbd{x}! @eprog\noindent In fact, all loops are immediately exited, user functions terminated, and the rest of the sequence following \kbd{allocatemem()} is silently discarded, as well as all pending sequences of instructions. We just go on reading the next instruction sequence from the file we are in (or from the user). In particular, we have the following possibly unexpected behavior: in \bprog read("file.gp"); x = 1 @eprog\noindent were \kbd{file.gp} contains an \kbd{allocatemem} statement, the \kbd{x = 1} is never executed, since all pending instructions in the current sequence are discarded. The reason for these unfortunate side-effects is that, with \kbd{parisizemax} disabled, increasing the stack size physically moves the stack, so temporary objects created during the current expression evaluation are not correct anymore. (In particular byte-compiled expressions, which are allocated on the stack.) To avoid accessing obsolete pointers to the old stack, this routine ends by a \kbd{longjmp}. The library syntax is \fun{void}{gp_allocatemem}{GEN s = NULL}. \subsec{apply$(f, A)$}\kbdsidx{apply}\label{se:apply} Apply the \typ{CLOSURE} \kbd{f} to the entries of \kbd{A}. If \kbd{A} is a scalar, return \kbd{f(A)}. If \kbd{A} is a polynomial or power series, apply \kbd{f} on all coefficients. If \kbd{A} is a vector or list, return the elements $f(x)$ where $x$ runs through \kbd{A}. If \kbd{A} is a matrix, return the matrix whose entries are the $f(\kbd{A[i,j]})$. \bprog ? apply(x->x^2, [1,2,3,4]) %1 = [1, 4, 9, 16] ? apply(x->x^2, [1,2;3,4]) %2 = [1 4] [9 16] ? apply(x->x^2, 4*x^2 + 3*x+ 2) %3 = 16*x^2 + 9*x + 4 @eprog\noindent Note that many functions already act componentwise on vectors or matrices, but they almost never act on lists; in this case, \kbd{apply} is a good solution: \bprog ? L = List([Mod(1,3), Mod(2,4)]); ? lift(L) *** at top-level: lift(L) *** ^------- *** lift: incorrect type in lift. ? apply(lift, L); %2 = List([1, 2]) @eprog \misctitle{Remark} For $v$ a \typ{VEC}, \typ{COL}, \typ{LIST} or \typ{MAT}, the alternative set-notations \bprog [g(x) | x <- v, f(x)] [x | x <- v, f(x)] [g(x) | x <- v] @eprog\noindent are available as shortcuts for \bprog apply(g, select(f, Vec(v))) select(f, Vec(v)) apply(g, Vec(v)) @eprog\noindent respectively: \bprog ? L = List([Mod(1,3), Mod(2,4)]); ? [ lift(x) | x<-L ] %2 = [1, 2] @eprog \synt{genapply}{void *E, GEN (*fun)(void*,GEN), GEN a}. \subsec{call$(f, A)$}\kbdsidx{call}\label{se:call} $A=[a_1,\dots, a_n]$ being a vector and $f$ being a function, returns the evaluation of $f(a_1,\dots,a_n)$. $f$ can also be the name of a built-in GP function. If $\# A =1$, \tet{call}($f,A$) = \tet{apply}($f,A$)[1]. If $f$ is variadic, the variadic arguments must grouped in a vector in the last component of $A$. This function is useful \item when writing a variadic function, to call another one: \bprog fprintf(file,format,args[..]) = write(file,call(Strprintf,[format,args])) @eprog \item when dealing with function arguments with unspecified arity The function below implements a global memoization interface: \bprog memo=Map(); memoize(f,A[..])= { my(res); if(!mapisdefined(memo, [f,A], &res), res = call(f,A); mapput(memo,[f,A],res)); res; } @eprog for example: \bprog ? memoize(factor,2^128+1) %3 = [59649589127497217,1;5704689200685129054721,1] ? ## *** last result computed in 76 ms. ? memoize(factor,2^128+1) %4 = [59649589127497217,1;5704689200685129054721,1] ? ## *** last result computed in 0 ms. ? memoize(ffinit,3,3) %5 = Mod(1,3)*x^3+Mod(1,3)*x^2+Mod(1,3)*x+Mod(2,3) ? fibo(n)=if(n==0,0,n==1,1,memoize(fibo,n-2)+memoize(fibo,n-1)); ? fibo(100) %7 = 354224848179261915075 @eprog \item to call operators through their internal names without using \kbd{alias} \bprog matnbelts(M) = call("_*_",matsize(M)) @eprog The library syntax is \fun{GEN}{call0}{GEN f, GEN A}. \subsec{default$(\{\var{key}\},\{\var{val}\})$}\kbdsidx{default}\label{se:default} Returns the default corresponding to keyword \var{key}. If \var{val} is present, sets the default to \var{val} first (which is subject to string expansion first). Typing \kbd{default()} (or \b{d}) yields the complete default list as well as their current values. See \secref{se:defaults} for an introduction to GP defaults, \secref{se:gp_defaults} for a list of available defaults, and \secref{se:meta} for some shortcut alternatives. Note that the shortcuts are meant for interactive use and usually display more information than \kbd{default}. The library syntax is \fun{GEN}{default0}{const char *key = NULL, const char *val = NULL}. \subsec{errname$(E)$}\kbdsidx{errname}\label{se:errname} Returns the type of the error message \kbd{E} as a string. The library syntax is \fun{GEN}{errname}{GEN E}. \subsec{error$(\{\var{str}\}*)$}\kbdsidx{error}\label{se:error} Outputs its argument list (each of them interpreted as a string), then interrupts the running \kbd{gp} program, returning to the input prompt. For instance \bprog error("n = ", n, " is not squarefree!") @eprog\noindent % \syn{NO} \subsec{extern$(\var{str})$}\kbdsidx{extern}\label{se:extern} The string \var{str} is the name of an external command (i.e.~one you would type from your UNIX shell prompt). This command is immediately run and its output fed into \kbd{gp}, just as if read from a file. The library syntax is \fun{GEN}{gpextern}{const char *str}. \subsec{externstr$(\var{str})$}\kbdsidx{externstr}\label{se:externstr} The string \var{str} is the name of an external command (i.e.~one you would type from your UNIX shell prompt). This command is immediately run and its output is returned as a vector of GP strings, one component per output line. The library syntax is \fun{GEN}{externstr}{const char *str}. \subsec{fileclose$(n)$}\kbdsidx{fileclose}\label{se:fileclose} Close the file descriptor $n$, created via \kbd{fileopen} or \kbd{fileextern}. Finitely many files can be opened at a given time, closing them recycles file descriptors and avoids running out of them: \bprog ? n = 0; while(n++, fileopen("/tmp/test", "w")) *** at top-level: n=0;while(n++,fileopen("/tmp/test","w")) *** ^-------------------------- *** fileopen: error opening requested file: `/tmp/test'. *** Break loop: type 'break' to go back to GP prompt break> n 65533 @eprog\noindent This is a limitation of the operating system and does not depend on PARI: if you open too many files in \kbd{gp} without closing them, the operating system will also prevent unrelated applications from opening files. Independently, your operating system (e.g. Windows) may prevent other applications from accessing or deleting your file while it is opened by \kbd{gp}. Quitting \kbd{gp} implicitly calls this function on all opened file descriptors. On files opened for writing, this function also forces a write of all buffered data to the file system and completes all pending write operations. This function is implicitly called for all open file descriptors when exiting \kbd{gp} but it is cleaner and safer to call it explicitly, for instance in case of a \kbd{gp} crash or general system failure, which could cause data loss. \bprog ? n = fileopen("./here"); ? while(l = fileread(n), print(l)); ? fileclose(n); ? n = fileopen("./there", "w"); ? for (i = 1, 100, filewrite(n, i^2+1)) ? fileclose(n) @eprog Until a \kbd{fileclose}, there is no guarantee that the file on disk contains all the expected data from previous \kbd{filewrite}s. (And even then the operating system may delay the actual write to hardware.) Closing a file twice raises an exception: \bprog ? n = fileopen("/tmp/test"); ? fileclose(n) ? fileclose(n) *** at top-level: fileclose(n) *** ^------------ *** fileclose: invalid file descriptor 0 @eprog The library syntax is \fun{void}{gp_fileclose}{long n}. \subsec{fileextern$(\var{str})$}\kbdsidx{fileextern}\label{se:fileextern} The string \var{str} is the name of an external command, i.e.~one you would type from your UNIX shell prompt. This command is immediately run and the function returns a file descriptor attached to the command output as if it were read from a file. \bprog ? n = fileextern("ls -l"); ? while(l = filereadstr(n), print(l)) ? fileclose(n) @eprog\noindent If the \kbd{secure} default is set, this function will raise en exception. The library syntax is \fun{long}{gp_fileextern}{const char *str}. \subsec{fileflush$(\{n\})$}\kbdsidx{fileflush}\label{se:fileflush} Flushes the file descriptor $n$, created via \kbd{fileopen} or \kbd{fileextern}. On files opened for writing, this function forces a write of all buffered data to the file system and completes all pending write operations. This function is implicitly called by \kbd{fileclose} but you may want to call it explicitly at synchronization points, for instance after writing a large result to file and before printing diagnostics on screen. (In order to be sure that the file contains the expected content on inspection.) If $n$ is omitted, flush all descriptors to output streams. \bprog ? n = fileopen("./here", "w"); ? for (i = 1, 10^5, \ filewrite(n, i^2+1); \ if (i % 10000 == 0, fileflush(n))) @eprog Until a \kbd{fileflush} or \kbd{fileclose}, there is no guarantee that the file contains all the expected data from previous \kbd{filewrite}s. The library syntax is \fun{void}{gp_fileflush0}{GEN n = NULL}. But the direct and more specific variant \fun{void}{gp_fileflush}{long n} is also available. \subsec{fileopen$(\var{path}, \var{mode})$}\kbdsidx{fileopen}\label{se:fileopen} Open the file pointed to by 'path' and return a file descriptor which can be used with other file functions. The mode can be \item \kbd{"r"} (default): open for reading; allow \kbd{fileread} and \kbd{filereadstr}. \item \kbd{"w"}: open for writing, discarding existing content; allow \kbd{filewrite}, \kbd{filewrite1}. \item \kbd{"a"}: open for writing, appending to existing content; same operations allowed as \kbd{"w"}. Eventually, the file should be closed and the descriptor recycled using \kbd{fileclose}. \bprog ? n = fileopen("./here"); \\ "r" by default ? while (l = filereadstr(n), print(l)) \\ print successive lines ? fileclose(n) \\ done @eprog\noindent In \emph{read} mode, raise an exception if the file does not exist or the user does not have read permission. In \emph{write} mode, raise an exception if the file cannot be written to. Trying to read or write to a file that was not opend with the right mode raises an exception. \bprog ? n = fileopen("./read", "r"); ? filewrite(n, "test") \\ not open for writing *** at top-level: filewrite(n,"test") *** ^------------------- *** filewrite: invalid file descriptor 0 @eprog The library syntax is \fun{long}{gp_fileopen}{const char *path, const char *mode}. \subsec{fileread$(n)$}\kbdsidx{fileread}\label{se:fileread} Read a logical line from the file attached to the descriptor $n$, opened for reading with \kbd{fileopen}. Return 0 at end of file. A logical line is a full command as it is prepared by gp's preprocessor (skipping blanks and comments or assembling multiline commands between braces) before being fed to the interpreter. The function \kbd{filereadstr} would read a \emph{raw} line exactly as input, up to the next carriage return \kbd{\bs n}. Compare raw lines \bprog ? n = fileopen("examples/bench.gp"); ? while(l = filereadstr(n), print(l)); { u=v=p=q=1; for (k=1, 2000, [u,v] = [v,u+v]; p *= v; q = lcm(q,v); if (k%50 == 0, print(k, " ", log(p)/log(q)) ) ) } @eprog\noindent and logical lines \bprog ? n = fileopen("examples/bench.gp"); ? while(l = fileread(n), print(l)); u=v=p=q=1;for(k=1,2000,[u,v]=[v,u+v];p*=v;q=lcm(q,v);[...] @eprog The library syntax is \fun{GEN}{gp_fileread}{long n}. \subsec{filereadstr$(n)$}\kbdsidx{filereadstr}\label{se:filereadstr} Read a raw line from the file attached to the descriptor $n$, opened for reading with \kbd{fileopen}, discarding the terminating newline. In other words the line is read exactly as input, up to the next carriage return \kbd{\bs n}. By comparison, \kbd{fileread} would read a logical line, as assembled by gp's preprocessor (skipping blanks and comments for instance). The library syntax is \fun{GEN}{gp_filereadstr}{long n}. \subsec{filewrite$(n, s)$}\kbdsidx{filewrite}\label{se:filewrite} Write the string $s$ to the file attached to descriptor $n$, ending with a newline. The file must have been opened with \kbd{fileopen} in \kbd{"w"} or \kbd{"a"} mode. There is no guarantee that $s$ is completely written to disk until \kbd{fileclose$(n)$} is executed, which is automatic when quitting \kbd{gp}. If the newline is not desired, use \kbd{filewrite1}. \misctitle{Variant} The high-level function \kbd{write} is expensive when many consecutive writes are expected because it cannot use buffering. The low-level interface \kbd{fileopen} / \kbd{filewrite} / \kbd{fileclose} is more efficient: \bprog ? f = "/tmp/bigfile"; ? for (i = 1, 10^5, write(f, i^2+1)) time = 240 ms. ? v = vector(10^5, i, i^2+1); time = 10 ms. \\ computing the values is fast ? write("/tmp/bigfile2",v) time = 12 ms. \\ writing them in one operation is fast ? n = fileopen("/tmp/bigfile", "w"); ? for (i = 1, 10^5, filewrite(n, i^2+1)) time = 24 ms. \\ low-level write is ten times faster ? fileclose(n); @eprog\noindent In the final example, the file needs not be in a consistent state until the ending \kbd{fileclose} is evaluated, e.g. some lines might be half-written or not present at all even though the corresponding \kbd{filewrite} was executed already. Both a single high-level \kbd{write} and a succession of low-level \kbd{filewrite}s achieve the same efficiency, but the latter is often more natural. In fact, concatenating naively the entries to be written is quadratic in the number of entries, hence much more expensive than the original write operations: \bprog ? v = []; for (i = 1, 10^5, v = concat(v,i)) time = 1min, 41,456 ms. @eprog The library syntax is \fun{void}{gp_filewrite}{long n, const char *s}. \subsec{filewrite1$(n, s)$}\kbdsidx{filewrite1}\label{se:filewrite1} Write the string $s$ to the file attached to descriptor $n$. The file must have been opened with \kbd{fileopen} in \kbd{"w"} or \kbd{"a"} mode. If you want to append a newline at the end of $s$, you can use \kbd{Str(s,"\bs n")} or \kbd{filewrite}. The library syntax is \fun{void}{gp_filewrite1}{long n, const char *s}. \subsec{fold$(f, A)$}\kbdsidx{fold}\label{se:fold} Apply the \typ{CLOSURE} \kbd{f} of arity $2$ to the entries of \kbd{A}, in order to return \kbd{f(\dots f(f(A[1],A[2]),A[3])\dots ,A[\#A])}. \bprog ? fold((x,y)->x*y, [1,2,3,4]) %1 = 24 ? fold((x,y)->[x,y], [1,2,3,4]) %2 = [[[1, 2], 3], 4] ? fold((x,f)->f(x), [2,sqr,sqr,sqr]) %3 = 256 ? fold((x,y)->(x+y)/(1-x*y),[1..5]) %4 = -9/19 ? bestappr(tan(sum(i=1,5,atan(i)))) %5 = -9/19 @eprog The library syntax is \fun{GEN}{fold0}{GEN f, GEN A}. Also available is \fun{GEN}{genfold}{void *E, GEN (*fun)(void*,GEN, GEN), GEN A}. \subsec{getabstime$()$}\kbdsidx{getabstime}\label{se:getabstime} Returns the CPU time (in milliseconds) elapsed since \kbd{gp} startup. This provides a reentrant version of \kbd{gettime}: \bprog my (t = getabstime()); ... print("Time: ", getabstime() - t); @eprog For a version giving wall-clock time, see \tet{getwalltime}. The library syntax is \fun{long}{getabstime}{}. \subsec{getenv$(s)$}\kbdsidx{getenv}\label{se:getenv} Return the value of the environment variable \kbd{s} if it is defined, otherwise return 0. The library syntax is \fun{GEN}{gp_getenv}{const char *s}. \subsec{getheap$()$}\kbdsidx{getheap}\label{se:getheap} Returns a two-component row vector giving the number of objects on the heap and the amount of memory they occupy in long words. Useful mainly for debugging purposes. The library syntax is \fun{GEN}{getheap}{}. \subsec{getrand$()$}\kbdsidx{getrand}\label{se:getrand} Returns the current value of the seed used by the pseudo-random number generator \tet{random}. Useful mainly for debugging purposes, to reproduce a specific chain of computations. The returned value is technical (reproduces an internal state array), and can only be used as an argument to \tet{setrand}. The library syntax is \fun{GEN}{getrand}{}. \subsec{getstack$()$}\kbdsidx{getstack}\label{se:getstack} Returns the current value of $\kbd{top}-\kbd{avma}$, i.e.~the number of bytes used up to now on the stack. Useful mainly for debugging purposes. The library syntax is \fun{long}{getstack}{}. \subsec{gettime$()$}\kbdsidx{gettime}\label{se:gettime} Returns the CPU time (in milliseconds) used since either the last call to \kbd{gettime}, or to the beginning of the containing GP instruction (if inside \kbd{gp}), whichever came last. For a reentrant version, see \tet{getabstime}. For a version giving wall-clock time, see \tet{getwalltime}. The library syntax is \fun{long}{gettime}{}. \subsec{getwalltime$()$}\kbdsidx{getwalltime}\label{se:getwalltime} Returns the time (in milliseconds) elapsed since 00:00:00 UTC Thursday 1, January 1970 (the Unix epoch). \bprog my (t = getwalltime()); ... print("Time: ", getwalltime() - t); @eprog The library syntax is \fun{GEN}{getwalltime}{}. \subsec{global$(\var{list} \var{of} \var{variables})$}\kbdsidx{global}\label{se:global} Obsolete. Scheduled for deletion. % \syn{NO} \subsec{inline$(x,...,z)$}\kbdsidx{inline}\label{se:inline} (Experimental) declare $x,\ldots, z$ as inline variables. Such variables behave like lexically scoped variable (see my()) but with unlimited scope. It is however possible to exit the scope by using \kbd{uninline()}. When used in a GP script, it is recommended to call \kbd{uninline()} before the script's end to avoid inline variables leaking outside the script. \subsec{input$()$}\kbdsidx{input}\label{se:input} Reads a string, interpreted as a GP expression, from the input file, usually standard input (i.e.~the keyboard). If a sequence of expressions is given, the result is the result of the last expression of the sequence. When using this instruction, it is useful to prompt for the string by using the \kbd{print1} function. Note that in the present version 2.19 of \kbd{pari.el}, when using \kbd{gp} under GNU Emacs (see \secref{se:emacs}) one \emph{must} prompt for the string, with a string which ends with the same prompt as any of the previous ones (a \kbd{"? "} will do for instance). The library syntax is \fun{GEN}{gp_input}{}. \subsec{install$(\var{name},\var{code},\{\var{gpname}\},\{\var{lib}\})$}\kbdsidx{install}\label{se:install} Loads from dynamic library \var{lib} the function \var{name}. Assigns to it the name \var{gpname} in this \kbd{gp} session, with \emph{prototype} \var{code} (see below). If \var{gpname} is omitted, uses \var{name}. If \var{lib} is omitted, all symbols known to \kbd{gp} are available: this includes the whole of \kbd{libpari.so} and possibly others (such as \kbd{libc.so}). Most importantly, \kbd{install} gives you access to all non-static functions defined in the PARI library. For instance, the function \bprog GEN addii(GEN x, GEN y) @eprog\noindent adds two PARI integers, and is not directly accessible under \kbd{gp} (it is eventually called by the \kbd{+} operator of course): \bprog ? install("addii", "GG") ? addii(1, 2) %1 = 3 @eprog\noindent It also allows to add external functions to the \kbd{gp} interpreter. For instance, it makes the function \tet{system} obsolete: \bprog ? install(system, vs, sys,/*omitted*/) ? sys("ls gp*") gp.c gp.h gp_rl.c @eprog\noindent This works because \kbd{system} is part of \kbd{libc.so}, which is linked to \kbd{gp}. It is also possible to compile a shared library yourself and provide it to gp in this way: use \kbd{gp2c}, or do it manually (see the \kbd{modules\_build} variable in \kbd{pari.cfg} for hints). Re-installing a function will print a warning and update the prototype code if needed. However, it will not reload a symbol from the library, even if the latter has been recompiled. \misctitle{Prototype} We only give a simplified description here, covering most functions, but there are many more possibilities. The full documentation is available in \kbd{libpari.dvi}, see \bprog ??prototype @eprog \item First character \kbd{i}, \kbd{l}, \kbd{v} : return type int / long / void. (Default: \kbd{GEN}) \item One letter for each mandatory argument, in the same order as they appear in the argument list: \kbd{G} (\kbd{GEN}), \kbd{\&} (\kbd{GEN*}), \kbd{L} (\kbd{long}), \kbd{s} (\kbd{char *}), \kbd{n} (variable). \item \kbd{p} to supply \kbd{realprecision} (usually \kbd{long prec} in the argument list), \kbd{P} to supply \kbd{seriesprecision} (usually \kbd{long precdl}). \noindent We also have special constructs for optional arguments and default values: \item \kbd{DG} (optional \kbd{GEN}, \kbd{NULL} if omitted), \item \kbd{D\&} (optional \kbd{GEN*}, \kbd{NULL} if omitted), \item \kbd{Dn} (optional variable, $-1$ if omitted), For instance the prototype corresponding to \bprog long issquareall(GEN x, GEN *n = NULL) @eprog\noindent is \kbd{lGD\&}. \misctitle{Caution} This function may not work on all systems, especially when \kbd{gp} has been compiled statically. In that case, the first use of an installed function will provoke a Segmentation Fault (this should never happen with a dynamically linked executable). If you intend to use this function, please check first on some harmless example such as the one above that it works properly on your machine. The library syntax is \fun{void}{gpinstall}{const char *name, const char *code, const char *gpname, const char *lib}. \subsec{kill$(\var{sym})$}\kbdsidx{kill}\label{se:kill} Restores the symbol \kbd{sym} to its ``undefined'' status, and deletes any help messages attached to \kbd{sym} using \kbd{addhelp}. Variable names remain known to the interpreter and keep their former priority: you cannot make a variable ``less important" by killing it! \bprog ? z = y = 1; y %1 = 1 ? kill(y) ? y \\ restored to ``undefined'' status %2 = y ? variable() %3 = [x, y, z] \\ but the variable name y is still known, with y > z ! @eprog\noindent For the same reason, killing a user function (which is an ordinary variable holding a \typ{CLOSURE}) does not remove its name from the list of variable names. If the symbol is attached to a variable --- user functions being an important special case ---, one may use the \idx{quote} operator \kbd{a = 'a} to reset variables to their starting values. However, this will not delete a help message attached to \kbd{a}, and is also slightly slower than \kbd{kill(a)}. \bprog ? x = 1; addhelp(x, "foo"); x %1 = 1 ? x = 'x; x \\ same as 'kill', except we don't delete help. %2 = x ? ?x foo @eprog\noindent On the other hand, \kbd{kill} is the only way to remove aliases and installed functions. \bprog ? alias(fun, sin); ? kill(fun); ? install(addii, GG); ? kill(addii); @eprog The library syntax is \fun{void}{kill0}{const char *sym}. \subsec{listcreate$(\{n\})$}\kbdsidx{listcreate}\label{se:listcreate} This function is obsolete, use \kbd{List}. Creates an empty list. This routine used to have a mandatory argument, which is now ignored (for backward compatibility). % \syn{NO} \subsec{listinsert$(L,x,n)$}\kbdsidx{listinsert}\label{se:listinsert} Inserts the object $x$ at position $n$ in $L$ (which must be of type \typ{LIST}). This has complexity $O(\#L - n + 1)$: all the remaining elements of \var{list} (from position $n+1$ onwards) are shifted to the right. The library syntax is \fun{GEN}{listinsert}{GEN L, GEN x, long n}. \subsec{listkill$(L)$}\kbdsidx{listkill}\label{se:listkill} Obsolete, retained for backward compatibility. Just use \kbd{L = List()} instead of \kbd{listkill(L)}. In most cases, you won't even need that, e.g. local variables are automatically cleared when a user function returns. The library syntax is \fun{void}{listkill}{GEN L}. \subsec{listpop$(\var{list},\{n\})$}\kbdsidx{listpop}\label{se:listpop} Removes the $n$-th element of the list \var{list} (which must be of type \typ{LIST}). If $n$ is omitted, or greater than the list current length, removes the last element. If the list is already empty, do nothing. This runs in time $O(\#L - n + 1)$. The library syntax is \fun{void}{listpop0}{GEN list, long n}. \subsec{listput$(\var{list},x,\{n\})$}\kbdsidx{listput}\label{se:listput} Sets the $n$-th element of the list \var{list} (which must be of type \typ{LIST}) equal to $x$. If $n$ is omitted, or greater than the list length, appends $x$. The function returns the inserted element. \bprog ? L = List(); ? listput(L, 1) %2 = 1 ? listput(L, 2) %3 = 2 ? L %4 = List([1, 2]) @eprog You may put an element into an occupied cell (not changing the list length), but it is easier to use the standard \kbd{list[n] = x} construct. \bprog ? listput(L, 3, 1) \\ insert at position 1 %5 = 3 ? L %6 = List([3, 2]) ? L[2] = 4 \\ simpler %7 = List([3, 4]) ? L[10] = 1 \\ can't insert beyond the end of the list *** at top-level: L[10]=1 *** ^------ *** non-existent component: index > 2 ? listput(L, 1, 10) \\ but listput can %8 = 1 ? L %9 = List([3, 2, 1]) @eprog This function runs in time $O(\#L)$ in the worst case (when the list must be reallocated), but in time $O(1)$ on average: any number of successive \kbd{listput}s run in time $O(\#L)$, where $\#L$ denotes the list \emph{final} length. The library syntax is \fun{GEN}{listput0}{GEN list, GEN x, long n}. \subsec{listsort$(L,\{\fl=0\})$}\kbdsidx{listsort}\label{se:listsort} Sorts the \typ{LIST} \var{list} in place, with respect to the (somewhat arbitrary) universal comparison function \tet{cmp}. In particular, the ordering is the same as for sets and \tet{setsearch} can be used on a sorted list. \bprog ? L = List([1,2,4,1,3,-1]); listsort(L); L %1 = List([-1, 1, 1, 2, 3, 4]) ? setsearch(L, 4) %2 = 6 ? setsearch(L, -2) %3 = 0 @eprog\noindent This is faster than the \kbd{vecsort} command since the list is sorted in place: no copy is made. No value returned. If $\fl$ is non-zero, suppresses all repeated coefficients. The library syntax is \fun{void}{listsort}{GEN L, long flag}. \subsec{localbitprec$(p)$}\kbdsidx{localbitprec}\label{se:localbitprec} Set the real precision to $p$ bits in the dynamic scope. All computations are performed as if \tet{realbitprecision} was $p$: transcendental constants (e.g.~\kbd{Pi}) and conversions from exact to floating point inexact data use $p$ bits, as well as iterative routines implicitly using a floating point accuracy as a termination criterion (e.g.~\tet{solve} or \tet{intnum}). But \kbd{realbitprecision} itself is unaffected and is ``unmasked'' when we exit the dynamic (\emph{not} lexical) scope. In effect, this is similar to \bprog my(bit = default(realbitprecision)); default(realbitprecision,p); ... default(realbitprecision, bit); @eprog\noindent but is both less cumbersome, cleaner (no need to manipulate a global variable, which in fact never changes and is only temporarily masked) and more robust: if the above computation is interrupted or an exception occurs, \kbd{realbitprecision} will not be restored as intended. Such \kbd{localbitprec} statements can be nested, the innermost one taking precedence as expected. Beware that \kbd{localbitprec} follows the semantic of \tet{local}, not \tet{my}: a subroutine called from \kbd{localbitprec} scope uses the local accuracy: \bprog ? f()=bitprecision(1.0); ? f() %2 = 128 ? localbitprec(1000); f() %3 = 1024 @eprog\noindent Note that the bit precision of \emph{data} (\kbd{1.0} in the above example) increases by steps of 64 (32 on a 32-bit machine) so we get $1024$ instead of the expected $1000$; \kbd{localbitprec} bounds the relative error exactly as specified in functions that support that granularity (e.g.~\kbd{lfun}), and rounded to the next multiple of 64 (resp.~32) everywhere else. \misctitle{Warning} Changing \kbd{realbitprecision} or \kbd{realprecision} in programs is deprecated in favor of \kbd{localbitprec} and \kbd{localprec}. Think about the \kbd{realprecision} and \kbd{realbitprecision} defaults as interactive commands for the \kbd{gp} interpreter, best left out of GP programs. Indeed, the above rules imply that mixing both constructs yields surprising results: \bprog ? \p38 ? localprec(19); default(realprecision,1000); Pi %1 = 3.141592653589793239 ? \p realprecision = 1001 significant digits (1000 digits displayed) @eprog\noindent Indeed, \kbd{realprecision} itself is ignored within \kbd{localprec} scope, so \kbd{Pi} is computed to a low accuracy. And when we leave the \kbd{localprec} scope, \kbd{realprecision} only regains precedence, it is not ``restored'' to the original value. %\syn{NO} \subsec{localprec$(p)$}\kbdsidx{localprec}\label{se:localprec} Set the real precision to $p$ in the dynamic scope. All computations are performed as if \tet{realprecision} was $p$: transcendental constants (e.g.~\kbd{Pi}) and conversions from exact to floating point inexact data use $p$ decimal digits, as well as iterative routines implicitly using a floating point accuracy as a termination criterion (e.g.~\tet{solve} or \tet{intnum}). But \kbd{realprecision} itself is unaffected and is ``unmasked'' when we exit the dynamic (\emph{not} lexical) scope. In effect, this is similar to \bprog my(prec = default(realprecision)); default(realprecision,p); ... default(realprecision, prec); @eprog\noindent but is both less cumbersome, cleaner (no need to manipulate a global variable, which in fact never changes and is only temporarily masked) and more robust: if the above computation is interrupted or an exception occurs, \kbd{realprecision} will not be restored as intended. Such \kbd{localprec} statements can be nested, the innermost one taking precedence as expected. Beware that \kbd{localprec} follows the semantic of \tet{local}, not \tet{my}: a subroutine called from \kbd{localprec} scope uses the local accuracy: \bprog ? f()=precision(1.); ? f() %2 = 38 ? localprec(19); f() %3 = 19 @eprog\noindent \misctitle{Warning} Changing \kbd{realprecision} itself in programs is now deprecated in favor of \kbd{localprec}. Think about the \kbd{realprecision} default as an interactive command for the \kbd{gp} interpreter, best left out of GP programs. Indeed, the above rules imply that mixing both constructs yields surprising results: \bprog ? \p38 ? localprec(19); default(realprecision,100); Pi %1 = 3.141592653589793239 ? \p realprecision = 115 significant digits (100 digits displayed) @eprog\noindent Indeed, \kbd{realprecision} itself is ignored within \kbd{localprec} scope, so \kbd{Pi} is computed to a low accuracy. And when we leave \kbd{localprec} scope, \kbd{realprecision} only regains precedence, it is not ``restored'' to the original value. %\syn{NO} \subsec{mapdelete$(M,x)$}\kbdsidx{mapdelete}\label{se:mapdelete} Removes $x$ from the domain of the map $M$. \bprog ? M = Map(["a",1; "b",3; "c",7]); ? mapdelete(M,"b"); ? Mat(M) ["a" 1] ["c" 7] @eprog The library syntax is \fun{void}{mapdelete}{GEN M, GEN x}. \subsec{mapget$(M,x)$}\kbdsidx{mapget}\label{se:mapget} Returns the image of $x$ by the map $M$. \bprog ? M=Map(["a",23;"b",43]); ? mapget(M,"a") %2 = 23 ? mapget(M,"b") %3 = 43 @eprog\noindent Raises an exception when the key $x$ is not present in $M$. \bprog ? mapget(M,"c") *** at top-level: mapget(M,"c") *** ^------------- *** mapget: non-existent component in mapget: index not in map @eprog The library syntax is \fun{GEN}{mapget}{GEN M, GEN x}. \subsec{mapisdefined$(M,x,\{\&z\})$}\kbdsidx{mapisdefined}\label{se:mapisdefined} Returns true ($1$) if \kbd{x} has an image by the map $M$, false ($0$) otherwise. If \kbd{z} is present, set \kbd{z} to the image of $x$, if it exists. \bprog ? M1 = Map([1, 10; 2, 20]); ? mapisdefined(M1,3) %1 = 0 ? mapisdefined(M1, 1, &z) %2 = 1 ? z %3 = 10 @eprog \bprog ? M2 = Map(); N = 19; ? for (a=0, N-1, mapput(M2, a^3%N, a)); ? {for (a=0, N-1, if (mapisdefined(M2, a, &b), printf("%d is the cube of %d mod %d\n",a,b,N)));} 0 is the cube of 0 mod 19 1 is the cube of 11 mod 19 7 is the cube of 9 mod 19 8 is the cube of 14 mod 19 11 is the cube of 17 mod 19 12 is the cube of 15 mod 19 18 is the cube of 18 mod 19 @eprog The library syntax is \fun{GEN}{mapisdefined}{GEN M, GEN x, GEN *z = NULL}. \subsec{mapput$(M,x,y)$}\kbdsidx{mapput}\label{se:mapput} Associates $x$ to $y$ in the map $M$. The value $y$ can be retrieved with \tet{mapget}. \bprog ? M = Map(); ? mapput(M, "foo", 23); ? mapput(M, 7718, "bill"); ? mapget(M, "foo") %4 = 23 ? mapget(M, 7718) %5 = "bill" ? Vec(M) \\ keys %6 = [7718, "foo"] ? Mat(M) %7 = [ 7718 "bill"] ["foo" 23] @eprog The library syntax is \fun{void}{mapput}{GEN M, GEN x, GEN y}. \subsec{print$(\{\var{str}\}*)$}\kbdsidx{print}\label{se:print} Outputs its arguments in raw format ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. \bprog ? m = matid(2); ? print(m) \\ raw format [1, 0; 0, 1] ? printp(m) \\ prettymatrix format [1 0] [0 1] @eprog %\syn{NO} \subsec{print1$(\{\var{str}\}*)$}\kbdsidx{print1}\label{se:print1} Outputs its arguments in raw format, without ending with a newline. Note that you can still embed newlines within your strings, using the \b{n} notation~! The arguments are converted to strings following the rules in \secref{se:strings}. %\syn{NO} \subsec{printf$(\var{fmt},\{x\}*)$}\kbdsidx{printf}\label{se:printf} This function is based on the C library command of the same name. It prints its arguments according to the format \var{fmt}, which specifies how subsequent arguments are converted for output. The format is a character string composed of zero or more directives: \item ordinary characters (not \kbd{\%}), printed unchanged, \item conversions specifications (\kbd{\%} followed by some characters) which fetch one argument from the list and prints it according to the specification. More precisely, a conversion specification consists in a \kbd{\%}, one or more optional flags (among \kbd{\#}, \kbd{0}, \kbd{-}, \kbd{+}, ` '), an optional decimal digit string specifying a minimal field width, an optional precision in the form of a period (`\kbd{.}') followed by a decimal digit string, and the conversion specifier (among \kbd{d},\kbd{i}, \kbd{o}, \kbd{u}, \kbd{x},\kbd{X}, \kbd{p}, \kbd{e},\kbd{E}, \kbd{f}, \kbd{g},\kbd{G}, \kbd{s}). \misctitle{The flag characters} The character \kbd{\%} is followed by zero or more of the following flags: \item \kbd{\#}: the value is converted to an ``alternate form''. For \kbd{o} conversion (octal), a \kbd{0} is prefixed to the string. For \kbd{x} and \kbd{X} conversions (hexa), respectively \kbd{0x} and \kbd{0X} are prepended. For other conversions, the flag is ignored. \item \kbd{0}: the value should be zero padded. For \kbd{d}, \kbd{i}, \kbd{o}, \kbd{u}, \kbd{x}, \kbd{X} \kbd{e}, \kbd{E}, \kbd{f}, \kbd{F}, \kbd{g}, and \kbd{G} conversions, the value is padded on the left with zeros rather than blanks. (If the \kbd{0} and \kbd{-} flags both appear, the \kbd{0} flag is ignored.) \item \kbd{-}: the value is left adjusted on the field boundary. (The default is right justification.) The value is padded on the right with blanks, rather than on the left with blanks or zeros. A \kbd{-} overrides a \kbd{0} if both are given. \item \kbd{` '} (a space): a blank is left before a positive number produced by a signed conversion. \item \kbd{+}: a sign (+ or -) is placed before a number produced by a signed conversion. A \kbd{+} overrides a space if both are used. \misctitle{The field width} An optional decimal digit string (whose first digit is non-zero) specifying a \emph{minimum} field width. If the value has fewer characters than the field width, it is padded with spaces on the left (or right, if the left-adjustment flag has been given). In no case does a small field width cause truncation of a field; if the value is wider than the field width, the field is expanded to contain the conversion result. Instead of a decimal digit string, one may write \kbd{*} to specify that the field width is given in the next argument. \misctitle{The precision} An optional precision in the form of a period (`\kbd{.}') followed by a decimal digit string. This gives the number of digits to appear after the radix character for \kbd{e}, \kbd{E}, \kbd{f}, and \kbd{F} conversions, the maximum number of significant digits for \kbd{g} and \kbd{G} conversions, and the maximum number of characters to be printed from an \kbd{s} conversion. Instead of a decimal digit string, one may write \kbd{*} to specify that the field width is given in the next argument. \misctitle{The length modifier} This is ignored under \kbd{gp}, but necessary for \kbd{libpari} programming. Description given here for completeness: \item \kbd{l}: argument is a \kbd{long} integer. \item \kbd{P}: argument is a \kbd{GEN}. \misctitle{The conversion specifier} A character that specifies the type of conversion to be applied. \item \kbd{d}, \kbd{i}: a signed integer. \item \kbd{o}, \kbd{u}, \kbd{x}, \kbd{X}: an unsigned integer, converted to unsigned octal (\kbd{o}), decimal (\kbd{u}) or hexadecimal (\kbd{x} or \kbd{X}) notation. The letters \kbd{abcdef} are used for \kbd{x} conversions; the letters \kbd{ABCDEF} are used for \kbd{X} conversions. \item \kbd{e}, \kbd{E}: the (real) argument is converted in the style \kbd{[ -]d.ddd e[ -]dd}, where there is one digit before the decimal point, and the number of digits after it is equal to the precision; if the precision is missing, use the current \kbd{realprecision} for the total number of printed digits. If the precision is explicitly 0, no decimal-point character appears. An \kbd{E} conversion uses the letter \kbd{E} rather than \kbd{e} to introduce the exponent. \item \kbd{f}, \kbd{F}: the (real) argument is converted in the style \kbd{[ -]ddd.ddd}, where the number of digits after the decimal point is equal to the precision; if the precision is missing, use the current \kbd{realprecision} for the total number of printed digits. If the precision is explicitly 0, no decimal-point character appears. If a decimal point appears, at least one digit appears before it. \item \kbd{g}, \kbd{G}: the (real) argument is converted in style \kbd{e} or \kbd{f} (or \kbd{E} or \kbd{F} for \kbd{G} conversions) \kbd{[ -]ddd.ddd}, where the total number of digits printed is equal to the precision; if the precision is missing, use the current \kbd{realprecision}. If the precision is explicitly 0, it is treated as 1. Style \kbd{e} is used when the decimal exponent is $< -4$, to print \kbd{0.}, or when the integer part cannot be decided given the known significant digits, and the \kbd{f} format otherwise. \item \kbd{c}: the integer argument is converted to an unsigned char, and the resulting character is written. \item \kbd{s}: convert to a character string. If a precision is given, no more than the specified number of characters are written. \item \kbd{p}: print the address of the argument in hexadecimal (as if by \kbd{\%\#x}). \item \kbd{\%}: a \kbd{\%} is written. No argument is converted. The complete conversion specification is \kbd{\%\%}. \noindent Examples: \bprog ? printf("floor: %d, field width 3: %3d, with sign: %+3d\n", Pi, 1, 2); floor: 3, field width 3: 1, with sign: +2 ? printf("%.5g %.5g %.5g\n",123,123/456,123456789); 123.00 0.26974 1.2346 e8 ? printf("%-2.5s:%2.5s:%2.5s\n", "P", "PARI", "PARIGP"); P :PARI:PARIG \\ min field width and precision given by arguments ? x = 23; y=-1/x; printf("x=%+06.2f y=%+0*.*f\n", x, 6, 2, y); x=+23.00 y=-00.04 \\ minimum fields width 5, pad left with zeroes ? for (i = 2, 5, printf("%05d\n", 10^i)) 00100 01000 10000 100000 \\@com don't truncate fields whose length is larger than the minimum width ? printf("%.2f |%06.2f|", Pi,Pi) 3.14 | 3.14| @eprog\noindent All numerical conversions apply recursively to the entries of vectors and matrices: \bprog ? printf("%4d", [1,2,3]); [ 1, 2, 3] ? printf("%5.2f", mathilbert(3)); [ 1.00 0.50 0.33] [ 0.50 0.33 0.25] [ 0.33 0.25 0.20] @eprog \misctitle{Technical note} Our implementation of \tet{printf} deviates from the C89 and C99 standards in a few places: \item whenever a precision is missing, the current \kbd{realprecision} is used to determine the number of printed digits (C89: use 6 decimals after the radix character). \item in conversion style \kbd{e}, we do not impose that the exponent has at least two digits; we never write a \kbd{+} sign in the exponent; 0 is printed in a special way, always as \kbd{0.E\var{exp}}. \item in conversion style \kbd{f}, we switch to style \kbd{e} if the exponent is greater or equal to the precision. \item in conversion \kbd{g} and \kbd{G}, we do not remove trailing zeros from the fractional part of the result; nor a trailing decimal point; 0 is printed in a special way, always as \kbd{0.E\var{exp}}. %\syn{NO} \subsec{printp$(\{\var{str}\}*)$}\kbdsidx{printp}\label{se:printp} Outputs its arguments in prettymatrix format, ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. \bprog ? m = matid(2); ? print(m) \\ raw format [1, 0; 0, 1] ? printp(m) \\ prettymatrix format [1 0] [0 1] @eprog %\syn{NO} \subsec{printsep$(\var{sep},\{\var{str}\}*)$}\kbdsidx{printsep}\label{se:printsep} Outputs its arguments in raw format, ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. Successive entries are separated by \var{sep}: \bprog ? printsep(":", 1,2,3,4) 1:2:3:4 @eprog %\syn{NO} \subsec{printsep1$(\var{sep},\{\var{str}\}*)$}\kbdsidx{printsep1}\label{se:printsep1} Outputs its arguments in raw format, without ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. Successive entries are separated by \var{sep}: \bprog ? printsep1(":", 1,2,3,4);print("|") 1:2:3:4| @eprog %\syn{NO} \subsec{printtex$(\{\var{str}\}*)$}\kbdsidx{printtex}\label{se:printtex} Outputs its arguments in \TeX\ format. This output can then be used in a \TeX\ manuscript. The arguments are converted to strings following the rules in \secref{se:strings}. The printing is done on the standard output. If you want to print it to a file you should use \kbd{writetex} (see there). Another possibility is to enable the \tet{log} default (see~\secref{se:defaults}). You could for instance do:\sidx{logfile} % \bprog default(logfile, "new.tex"); default(log, 1); printtex(result); @eprog %\syn{NO} \subsec{quit$(\{\var{status} = 0\})$}\kbdsidx{quit}\label{se:quit} Exits \kbd{gp} and return to the system with exit status \kbd{status}, a small integer. A non-zero exit status normally indicates abnormal termination. (Note: the system actually sees only \kbd{status} mod $256$, see your man pages for \kbd{exit(3)} or \kbd{wait(2)}). \subsec{read$(\{\var{filename}\})$}\kbdsidx{read}\label{se:read} Reads in the file \var{filename} (subject to string expansion). If \var{filename} is omitted, re-reads the last file that was fed into \kbd{gp}. The return value is the result of the last expression evaluated. If a GP \tet{binary file} is read using this command (see \secref{se:writebin}), the file is loaded and the last object in the file is returned. In case the file you read in contains an \tet{allocatemem} statement (to be generally avoided), you should leave \kbd{read} instructions by themselves, and not part of larger instruction sequences. \misctitle{Variants} \kbd{readvec} allows to read a whole file at once; \kbd{fileopen} followed by either \kbd{fileread} (evaluated lines) or \kbd{filereadstr} (lines as non-evaluated strings) allows to read a file one line at a time. The library syntax is \fun{GEN}{gp_read_file}{const char *filename}. \subsec{readstr$(\{\var{filename}\})$}\kbdsidx{readstr}\label{se:readstr} Reads in the file \var{filename} and return a vector of GP strings, each component containing one line from the file. If \var{filename} is omitted, re-reads the last file that was fed into \kbd{gp}. The library syntax is \fun{GEN}{readstr}{const char *filename}. \subsec{readvec$(\{\var{filename}\})$}\kbdsidx{readvec}\label{se:readvec} Reads in the file \var{filename} (subject to string expansion). If \var{filename} is omitted, re-reads the last file that was fed into \kbd{gp}. The return value is a vector whose components are the evaluation of all sequences of instructions contained in the file. For instance, if \var{file} contains \bprog 1 2 3 @eprog\noindent then we will get: \bprog ? \r a %1 = 1 %2 = 2 %3 = 3 ? read(a) %4 = 3 ? readvec(a) %5 = [1, 2, 3] @eprog In general a sequence is just a single line, but as usual braces and \kbd{\bs} may be used to enter multiline sequences. The library syntax is \fun{GEN}{gp_readvec_file}{const char *filename}. The underlying library function \fun{GEN}{gp_readvec_stream}{FILE *f} is usually more flexible. \subsec{select$(f, A, \{\fl = 0\})$}\kbdsidx{select}\label{se:select} We first describe the default behavior, when $\fl$ is 0 or omitted. Given a vector or list \kbd{A} and a \typ{CLOSURE} \kbd{f}, \kbd{select} returns the elements $x$ of \kbd{A} such that $f(x)$ is non-zero. In other words, \kbd{f} is seen as a selection function returning a boolean value. \bprog ? select(x->isprime(x), vector(50,i,i^2+1)) %1 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] ? select(x->(x<100), %) %2 = [2, 5, 17, 37] @eprog\noindent returns the primes of the form $i^2+1$ for some $i\leq 50$, then the elements less than 100 in the preceding result. The \kbd{select} function also applies to a matrix \kbd{A}, seen as a vector of columns, i.e. it selects columns instead of entries, and returns the matrix whose columns are the selected ones. \misctitle{Remark} For $v$ a \typ{VEC}, \typ{COL}, \typ{LIST} or \typ{MAT}, the alternative set-notations \bprog [g(x) | x <- v, f(x)] [x | x <- v, f(x)] [g(x) | x <- v] @eprog\noindent are available as shortcuts for \bprog apply(g, select(f, Vec(v))) select(f, Vec(v)) apply(g, Vec(v)) @eprog\noindent respectively: \bprog ? [ x | x <- vector(50,i,i^2+1), isprime(x) ] %1 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] @eprog \noindent If $\fl = 1$, this function returns instead the \emph{indices} of the selected elements, and not the elements themselves (indirect selection): \bprog ? V = vector(50,i,i^2+1); ? select(x->isprime(x), V, 1) %2 = Vecsmall([1, 2, 4, 6, 10, 14, 16, 20, 24, 26, 36, 40]) ? vecextract(V, %) %3 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] @eprog\noindent The following function lists the elements in $(\Z/N\Z)^*$: \bprog ? invertibles(N) = select(x->gcd(x,N) == 1, [1..N]) @eprog \noindent Finally \bprog ? select(x->x, M) @eprog\noindent selects the non-0 entries in \kbd{M}. If the latter is a \typ{MAT}, we extract the matrix of non-0 columns. Note that \emph{removing} entries instead of selecting them just involves replacing the selection function \kbd{f} with its negation: \bprog ? select(x->!isprime(x), vector(50,i,i^2+1)) @eprog \synt{genselect}{void *E, long (*fun)(void*,GEN), GEN a}. Also available is \fun{GEN}{genindexselect}{void *E, long (*fun)(void*, GEN), GEN a}, corresponding to $\fl = 1$. \subsec{self$()$}\kbdsidx{self}\label{se:self} Return the calling function or closure as a \typ{CLOSURE} object. This is useful for defining anonymous recursive functions. \bprog ? (n->if(n==0,1,n*self()(n-1)))(5) %1 = 120 @eprog The library syntax is \fun{GEN}{pari_self}{}. \subsec{setrand$(n)$}\kbdsidx{setrand}\label{se:setrand} Reseeds the random number generator using the seed $n$. No value is returned. The seed is a small positive integer $0 < n < 2^{64}$ used to generate deterministically a suitable state array. All gp session start by an implicit \kbd{setrand(1)}, so resetting the seed to this value allows to replay all computations since the session start. Alternatively, running a randomized computation starting by \kbd{setrand}($n$) twice with the same $n$ will generate the exact same output. In the other direction, including a call to \kbd{setrand(getwalltime())} from your gprc will cause GP to produce different streams of random numbers in each session. (Unix users may want to use \kbd{/dev/urandom} instead of \kbd{getwalltime}.) For debugging purposes, one can also record a particular random state using \kbd{getrand} (the value is encoded as a huge integer) and feed it to \kbd{setrand}: \bprog ? state = getrand(); \\ record seed ... ? setrand(state); \\ we can now replay the exact same computations @eprog The library syntax is \fun{void}{setrand}{GEN n}. \subsec{system$(\var{str})$}\kbdsidx{system}\label{se:system} \var{str} is a string representing a system command. This command is executed, its output written to the standard output (this won't get into your logfile), and control returns to the PARI system. This simply calls the C \kbd{system} command. The library syntax is \fun{void}{gpsystem}{const char *str}. \subsec{trap$(\{e\}, \{\var{rec}\}, \var{seq})$}\kbdsidx{trap}\label{se:trap} This function is obsolete, use \tet{iferr}, which has a nicer and much more powerful interface. For compatibility's sake we now describe the \emph{obsolete} function \tet{trap}. This function tries to evaluate \var{seq}, trapping runtime error $e$, that is effectively preventing it from aborting computations in the usual way; the recovery sequence \var{rec} is executed if the error occurs and the evaluation of \var{rec} becomes the result of the command. If $e$ is omitted, all exceptions are trapped. See \secref{se:errorrec} for an introduction to error recovery under \kbd{gp}. \bprog ? \\@com trap division by 0 ? inv(x) = trap (e_INV, INFINITY, 1/x) ? inv(2) %1 = 1/2 ? inv(0) %2 = INFINITY @eprog\noindent Note that \var{seq} is effectively evaluated up to the point that produced the error, and the recovery sequence is evaluated starting from that same context, it does not "undo" whatever happened in the other branch (restore the evaluation context): \bprog ? x = 1; trap (, /* recover: */ x, /* try: */ x = 0; 1/x) %1 = 0 @eprog \misctitle{Note} The interface is currently not adequate for trapping individual exceptions. In the current version \vers, the following keywords are recognized, but the name list will be expanded and changed in the future (all library mode errors can be trapped: it's a matter of defining the keywords to \kbd{gp}): \kbd{e\_ALARM}: alarm time-out \kbd{e\_ARCH}: not available on this architecture or operating system \kbd{e\_STACK}: the PARI stack overflows \kbd{e\_INV}: impossible inverse \kbd{e\_IMPL}: not yet implemented \kbd{e\_OVERFLOW}: all forms of arithmetic overflow, including length or exponent overflow (when a larger value is supplied than the implementation can handle). \kbd{e\_SYNTAX}: syntax error \kbd{e\_MISC}: miscellaneous error \kbd{e\_TYPE}: wrong type \kbd{e\_USER}: user error (from the \kbd{error} function) The library syntax is \fun{GEN}{trap0}{const char *e = NULL, GEN rec = NULL, GEN seq = NULL}. \subsec{type$(x)$}\kbdsidx{type}\label{se:type} This is useful only under \kbd{gp}. Returns the internal type name of the PARI object $x$ as a string. Check out existing type names with the metacommand \b{t}. For example \kbd{type(1)} will return "\typ{INT}". The library syntax is \fun{GEN}{type0}{GEN x}. The macro \kbd{typ} is usually simpler to use since it returns a \kbd{long} that can easily be matched with the symbols \typ{*}. The name \kbd{type} was avoided since it is a reserved identifier for some compilers. \subsec{uninline$()$}\kbdsidx{uninline}\label{se:uninline} (Experimental) Exit the scope of all current \kbd{inline} variables. \subsec{version$()$}\kbdsidx{version}\label{se:version} Returns the current version number as a \typ{VEC} with three integer components (major version number, minor version number and patchlevel); if your sources were obtained through our version control system, this will be followed by further more precise arguments, including e.g.~a~\kbd{git} \emph{commit hash}. This function is present in all versions of PARI following releases 2.3.4 (stable) and 2.4.3 (testing). Unless you are working with multiple development versions, you probably only care about the 3 first numeric components. In any case, the \kbd{lex} function offers a clever way to check against a particular version number, since it will compare each successive vector entry, numerically or as strings, and will not mind if the vectors it compares have different lengths: \bprog if (lex(version(), [2,3,5]) >= 0, \\ code to be executed if we are running 2.3.5 or more recent. , \\ compatibility code ); @eprog\noindent On a number of different machines, \kbd{version()} could return either of \bprog %1 = [2, 3, 4] \\ released version, stable branch %1 = [2, 4, 3] \\ released version, testing branch %1 = [2, 6, 1, 15174, ""505ab9b"] \\ development @eprog In particular, if you are only working with released versions, the first line of the gp introductory message can be emulated by \bprog [M,m,p] = version(); printf("GP/PARI CALCULATOR Version %s.%s.%s", M,m,p); @eprog\noindent If you \emph{are} working with many development versions of PARI/GP, the 4th and/or 5th components can be profitably included in the name of your logfiles, for instance. \misctitle{Technical note} For development versions obtained via \kbd{git}, the 4th and 5th components are liable to change eventually, but we document their current meaning for completeness. The 4th component counts the number of reachable commits in the branch (analogous to \kbd{svn}'s revision number), and the 5th is the \kbd{git} commit hash. In particular, \kbd{lex} comparison still orders correctly development versions with respect to each others or to released versions (provided we stay within a given branch, e.g. \kbd{master})! The library syntax is \fun{GEN}{pari_version}{}. \subsec{warning$(\{\var{str}\}*)$}\kbdsidx{warning}\label{se:warning} Outputs the message ``user warning'' and the argument list (each of them interpreted as a string). If colors are enabled, this warning will be in a different color, making it easy to distinguish. \bprog warning(n, " is very large, this might take a while.") @eprog % \syn{NO} \subsec{whatnow$(\var{key})$}\kbdsidx{whatnow}\label{se:whatnow} If keyword \var{key} is the name of a function that was present in GP version 1.39.15, outputs the new function name and syntax, if it changed at all. Functions that where introduced since then, then modified are also recognized. \bprog ? whatnow("mu") New syntax: mu(n) ===> moebius(n) moebius(x): Moebius function of x. ? whatnow("sin") This function did not change @eprog When a function was removed and the underlying functionality is not available under a compatible interface, no equivalent is mentioned: \bprog ? whatnow("buchfu") This function no longer exists @eprog\noindent (The closest equivalent would be to set \kbd{K = bnfinit(T)} then access \kbd{K.fu}.) \subsec{write$(\var{filename},\{\var{str}\}*)$}\kbdsidx{write}\label{se:write} Writes (appends) to \var{filename} the remaining arguments, and appends a newline (same output as \kbd{print}). \misctitle{Variant} The high-level function \kbd{write} is expensive when many consecutive writes are expected because it cannot use buffering. The low-level interface \kbd{fileopen} / \kbd{filewrite} / \kbd{fileclose} is more efficient. %\syn{NO} \subsec{write1$(\var{filename},\{\var{str}\}*)$}\kbdsidx{write1}\label{se:write1} Writes (appends) to \var{filename} the remaining arguments without a trailing newline (same output as \kbd{print1}). %\syn{NO} \subsec{writebin$(\var{filename},\{x\})$}\kbdsidx{writebin}\label{se:writebin} Writes (appends) to \var{filename} the object $x$ in binary format. This format is not human readable, but contains the exact internal structure of $x$, and is much faster to save/load than a string expression, as would be produced by \tet{write}. The binary file format includes a magic number, so that such a file can be recognized and correctly input by the regular \tet{read} or \b{r} function. If saved objects refer to polynomial variables that are not defined in the new session, they will be displayed as \kbd{t$n$} for some integer $n$ (the attached variable number). Installed functions and history objects can not be saved via this function. If $x$ is omitted, saves all user variables from the session, together with their names. Reading such a ``named object'' back in a \kbd{gp} session will set the corresponding user variable to the saved value. E.g after \bprog x = 1; writebin("log") @eprog\noindent reading \kbd{log} into a clean session will set \kbd{x} to $1$. The relative variables priorities (see \secref{se:priority}) of new variables set in this way remain the same (preset variables retain their former priority, but are set to the new value). In particular, reading such a session log into a clean session will restore all variables exactly as they were in the original one. Just as a regular input file, a binary file can be compressed using \tet{gzip}, provided the file name has the standard \kbd{.gz} extension.\sidx{binary file} In the present implementation, the binary files are architecture dependent and compatibility with future versions of \kbd{gp} is not guaranteed. Hence binary files should not be used for long term storage (also, they are larger and harder to compress than text files). The library syntax is \fun{void}{gpwritebin}{const char *filename, GEN x = NULL}. \subsec{writetex$(\var{filename},\{\var{str}\}*)$}\kbdsidx{writetex}\label{se:writetex} As \kbd{write}, in \TeX\ format. %\syn{NO} \section{Parallel programming} These function are only available if PARI was configured using \kbd{Configure --mt=\dots}. Two multithread interfaces are supported: \item POSIX threads \item Message passing interface (MPI) As a rule, POSIX threads are well-suited for single systems, while MPI is used by most clusters. However the parallel GP interface does not depend on the chosen multithread interface: a properly written GP program will work identically with both. \subsec{parapply$(f, x)$}\kbdsidx{parapply}\label{se:parapply} Parallel evaluation of \kbd{f} on the elements of \kbd{x}. The function \kbd{f} must not access global variables or variables declared with local(), and must be free of side effects. \bprog parapply(factor,[2^256 + 1, 2^193 - 1]) @eprog factors $2^{256} + 1$ and $2^{193} - 1$ in parallel. \bprog { my(E = ellinit([1,3]), V = vector(12,i,randomprime(2^200))); parapply(p->ellcard(E,p), V) } @eprog computes the order of $E(\F_p)$ for $12$ random primes of $200$ bits. The library syntax is \fun{GEN}{parapply}{GEN f, GEN x}. \subsec{pareval$(x)$}\kbdsidx{pareval}\label{se:pareval} Parallel evaluation of the elements of \kbd{x}, where \kbd{x} is a vector of closures. The closures must be of arity $0$, must not access global variables or variables declared with \kbd{local} and must be free of side effects. The library syntax is \fun{GEN}{pareval}{GEN x}. \subsec{parfor$(i=a,\{b\},\var{expr1},\{r\},\{\var{expr2}\})$}\kbdsidx{parfor}\label{se:parfor} Evaluates in parallel the expression \kbd{expr1} in the formal argument $i$ running from $a$ to $b$. If $b$ is set to \kbd{+oo}, the loop runs indefinitely. If $r$ and \kbd{expr2} are present, the expression \kbd{expr2} in the formal variables $r$ and $i$ is evaluated with $r$ running through all the different results obtained for \kbd{expr1} and $i$ takes the corresponding argument. The computations of \kbd{expr1} are \emph{started} in increasing order of $i$; otherwise said, the computation for $i=c$ is started after those for $i=1, \ldots, c-1$ have been started, but before the computation for $i=c+1$ is started. Notice that the order of \emph{completion}, that is, the order in which the different $r$ become available, may be different; \kbd{expr2} is evaluated sequentially on each $r$ as it appears. The following example computes the sum of the squares of the integers from $1$ to $10$ by computing the squares in parallel and is equivalent to \kbd{parsum (i=1, 10, i\^{}2)}: \bprog ? s=0; ? parfor (i=1, 10, i^2, r, s=s+r) ? s %3 = 385 @eprog More precisely, apart from a potentially different order of evaluation due to the parallelism, the line containing \kbd{parfor} is equivalent to \bprog ? my (r); for (i=1, 10, r=i^2; s=s+r) @eprog The sequentiality of the evaluation of \kbd{expr2} ensures that the variable \kbd{s} is not modified concurrently by two different additions, although the order in which the terms are added is non-deterministic. It is allowed for \kbd{expr2} to exit the loop using \kbd{break}/\kbd{next}/\kbd{return}. If that happens for $i=c$, then the evaluation of \kbd{expr1} and \kbd{expr2} is continued for all values $i 0$, notify when \kbd{parisize} changes (within the boundaries set by \kbd{parisizemax}); \item $\kbd{debugmem} > 1$, indicate any important garbage collection and the function it is taking place in; \item $\kbd{debugmem} > 2$, indicate the creation/destruction of ``blocks'' (or clones); expect lots of messages. \noindent {\bf Important Note:} if you are running a version compiled for debugging (see Appendix~A) and $\kbd{debugmem} > 1$, \kbd{gp} will further regularly print information on memory usage, notifying whenever stack usage goes up or down by 1 MByte. This functionality is disabled on non-debugging builds as it noticeably slows down the performance. The default value is \kbd{1}. \subsec{echo}\kbdsidx{echo}\label{se:def,echo} This default can be 0 (off), 1 (on) or 2 (on, raw). When \kbd{echo} mode is on, each command is reprinted before being executed. This can be useful when reading a file with the \b{r} or \kbd{read} commands. For example, it is turned on at the beginning of the test files used to check whether \kbd{gp} has been built correctly (see \b{e}). When \kbd{echo} is set to 1 the input is cleaned up, removing white space and comments and uniting multi-line input. When set to 2 (raw), the input is written as-is, without any pre-processing. The default value is \kbd{0} (no echo). \subsec{factor\_add\_primes}\kbdsidx{def,factor_add_primes}\label{se:def,factor_add_primes} This toggle is either 1 (on) or 0 (off). If on, the integer factorization machinery calls \tet{addprimes} on prime factors that were difficult to find (larger than $2^{24}$), so they are automatically tried first in other factorizations. If a routine is performing (or has performed) a factorization and is interrupted by an error or via Control-C, this lets you recover the prime factors already found. The downside is that a huge \kbd{addprimes} table unrelated to the current computations will slow down arithmetic functions relying on integer factorization; one should then empty the table using \tet{removeprimes}. The default value is \kbd{0}. \subsec{factor\_proven}\kbdsidx{def,factor_proven}\label{se:def,factor_proven} This toggle is either 1 (on) or 0 (off). By default, the factors output by the integer factorization machinery are only pseudo-primes, not proven primes. If this toggle is set, a primality proof is done for each factor and all results depending on integer factorization are fully proven. This flag does not affect partial factorization when it is explicitly requested. It also does not affect the private table managed by \tet{addprimes}: its entries are included as is in factorizations, without being tested for primality. The default value is \kbd{0}. \subsec{format}\kbdsidx{format}\label{se:def,format} Of the form x$.n$, where x (conversion style) is a letter in $\{\kbd{e},\kbd{f},\kbd{g}\}$, and $n$ (precision) is an integer; this affects the way real numbers are printed: \item If the conversion style is \kbd{e}, real numbers are printed in \idx{scientific format}, always with an explicit exponent, e.g.~\kbd{3.3 E-5}. \item In style \kbd{f}, real numbers are generally printed in \idx{fixed floating point format} without exponent, e.g.~\kbd{0.000033}. A large real number, whose integer part is not well defined (not enough significant digits), is printed in style~\kbd{e}. For instance \kbd{10.\pow 100} known to ten significant digits is always printed in style \kbd{e}. \item In style \kbd{g}, non-zero real numbers are printed in \kbd{f} format, except when their decimal exponent is $< -4$, in which case they are printed in \kbd{e} format. Real zeroes (of arbitrary exponent) are printed in \kbd{e} format. The precision $n$ is the number of significant digits printed for real numbers, except if $n<0$ where all the significant digits will be printed (initial default 28, or 38 for 64-bit machines). For more powerful formatting possibilities, see \tet{printf} and \tet{Strprintf}. The default value is \kbd{"g.28"} and \kbd{"g.38"} on 32-bit and 64-bit machines, respectively. \subsec{graphcolormap}\kbdsidx{graphcolormap}\label{se:def,graphcolormap} A vector of colors, to be used by hi-res graphing routines. Its length is arbitrary, but it must contain at least 3 entries: the first 3 colors are used for background, frame/ticks and axes respectively. All colors in the colormap may be freely used in \tet{plotcolor} calls. A color is either given as in the default by character strings or by an RGB code. For valid color names, see the standard \kbd{rgb.txt} file in X11 distributions, where we restrict to lowercase letters and remove all whitespace from color names. An RGB code is a vector with 3 integer entries between 0 and 255 or a \kbd{\#} followed by 6 hexadecimal digits. For instance \kbd{[250, 235, 215]}, \kbd{"\#faebd7"} and \kbd{"antiquewhite"} all represent the same color. The default value is [\kbd{"white"}, \kbd{"black"}, \kbd{"blue"}, \kbd{"violetred"}, \kbd{"red"}, \kbd{"green"}, \kbd{"grey"}, \kbd{"gainsboro"}]. \subsec{graphcolors}\kbdsidx{graphcolors}\label{se:def,graphcolors} Entries in the \tet{graphcolormap} that will be used to plot multi-curves. The successive curves are drawn in colors \kbd{graphcolormap[graphcolors[1]]}, \kbd{graphcolormap[graphcolors[2]]}, \dots cycling when the \kbd{graphcolors} list is exhausted. The default value is \kbd{[4,5]}. \subsec{help}\kbdsidx{help}\label{se:def,help} Name of the external help program to use from within \kbd{gp} when extended help is invoked, usually through a \kbd{??} or \kbd{???} request (see \secref{se:exthelp}), or \kbd{M-H} under readline (see \secref{se:readline}). The default value is the path to the \kbd{gphelp} script we install. \subsec{histfile}\kbdsidx{histfile}\label{se:def,histfile} Name of a file where \kbd{gp} will keep a history of all \emph{input} commands (results are omitted). If this file exists when the value of \kbd{histfile} changes, it is read in and becomes part of the session history. Thus, setting this default in your gprc saves your readline history between sessions. Setting this default to the empty string \kbd{""} changes it to \kbd{$<$undefined$>$}. Note that, by default, the number of history entries saved is not limited: set \kbd{history-size} in readline's \kbd{.inputrc} to limit the file size. The default value is \kbd{$<$undefined$>$} (no history file). \subsec{histsize}\kbdsidx{histsize}\label{se:def,histsize} \kbd{gp} keeps a history of the last \kbd{histsize} results computed so far, which you can recover using the \kbd{\%} notation (see \secref{se:history}). When this number is exceeded, the oldest values are erased. Tampering with this default is the only way to get rid of the ones you do not need anymore. The default value is \kbd{5000}. \subsec{lines}\kbdsidx{lines}\label{se:def,lines} If set to a positive value, \kbd{gp} prints at most that many lines from each result, terminating the last line shown with \kbd{[+++]} if further material has been suppressed. The various \kbd{print} commands (see \secref{se:gp_program}) are unaffected, so you can always type \kbd{print(\%)} or \b{a} to view the full result. If the actual screen width cannot be determined, a ``line'' is assumed to be 80 characters long. The default value is \kbd{0}. \subsec{linewrap}\kbdsidx{linewrap}\label{se:def,linewrap} If set to a positive value, \kbd{gp} wraps every single line after printing that many characters. The default value is \kbd{0} (unset). \subsec{log}\kbdsidx{log}\label{se:def,log} This can be either 0 (off) or 1, 2, 3 (on, see below for the various modes). When logging mode is turned on, \kbd{gp} opens a log file, whose exact name is determined by the \kbd{logfile} default. Subsequently, all the commands and results will be written to that file (see \b{l}). In case a file with this precise name already existed, it will not be erased: your data will be \emph{appended} at the end. The specific positive values of \kbd{log} have the following meaning 1: plain logfile 2: emit color codes to the logfile (if \kbd{colors} is set). 3: write LaTeX output to the logfile (can be further customized using \tet{TeXstyle}). The default value is \kbd{0}. \subsec{logfile}\kbdsidx{logfile}\label{se:def,logfile} Name of the log file to be used when the \kbd{log} toggle is on. Environment and time expansion are performed. The default value is \kbd{"pari.log"}. \subsec{nbthreads}\kbdsidx{nbthreads}\label{se:def,nbthreads} This default is specific to the \emph{parallel} version of PARI and gp (built via \kbd{Configure --mt=prthread} or \kbd{mpi}) and is ignored otherwise. In parallel mode, it governs the number of threads to use for parallel computing. The exact meaning and default value depend on the \kbd{mt} engine used: \item \kbd{single}: not used (always a single thread). \item \kbd{pthread}: number of threads (unlimited, default: number of cores) \item \kbd{mpi}: number of MPI processes to use (limited to the number allocated by \kbd{mpirun}, default: use all allocated processes). See also \kbd{threadsize} and \kbd{threadsizemax}. \subsec{new\_galois\_format}\kbdsidx{def,new_galois_format}\label{se:def,new_galois_format} This toggle is either 1 (on) or 0 (off). If on, the \tet{polgalois} command will use a different, more consistent, naming scheme for Galois groups. This default is provided to ensure that scripts can control this behavior and do not break unexpectedly. The default value is \kbd{0}. This value will change to $1$ (set) in the next major version. \subsec{output}\kbdsidx{output}\label{se:def,output} There are three possible values: 0 (=~\var{raw}), 1 (=~\var{prettymatrix}), or 3 (=~\var{external} \var{prettyprint}). This means that, independently of the default \kbd{format} for reals which we explained above, you can print results in three ways: \item \tev{raw format}, i.e.~a format which is equivalent to what you input, including explicit multiplication signs, and everything typed on a line instead of two dimensional boxes. This can have several advantages, for instance it allows you to pick the result with a mouse or an editor, and to paste it somewhere else. \item \tev{prettymatrix format}: this is identical to raw format, except that matrices are printed as boxes instead of horizontally. This is prettier, but takes more space and cannot be used for input. Column vectors are still printed horizontally. \item \tev{external prettyprint}: pipes all \kbd{gp} output in TeX format to an external prettyprinter, according to the value of \tet{prettyprinter}. The default script (\tet{tex2mail}) converts its input to readable two-dimensional text. Independently of the setting of this default, an object can be printed in any of the three formats at any time using the commands \b{a} and \b{m} and \b{B} respectively. The default value is \kbd{1} (\var{prettymatrix}). \subsec{parisize}\kbdsidx{parisize}\label{se:def,parisize} \kbd{gp}, and in fact any program using the PARI library, needs a \tev{stack} in which to do its computations; \kbd{parisize} is the stack size, in bytes. It is recommended to increase this default using a \tet{gprc}, to the value you believe PARI should be happy with, given your typical computation. We strongly recommend to also set \tet{parisizemax} to a much larger value in your \kbd{gprc}, about what you believe your machine can stand: PARI will then try to fit its computations within about \kbd{parisize} bytes, but will increase the stack size if needed (up to \kbd{parisizemax}). Once the memory intensive computation is over, PARI will restore the stack size to the originally requested \kbd{parisize}. The default value is 4M, resp.~8M on a 32-bit, resp.~64-bit machine. \subsec{parisizemax}\kbdsidx{parisizemax}\label{se:def,parisizemax} \kbd{gp}, and in fact any program using the PARI library, needs a \tev{stack} in which to do its computations. If non-zero, \tet{parisizemax} is the maximum size the stack can grow to, in bytes. If zero, the stack will not automatically grow, and will be limited to the value of \kbd{parisize}. When \kbd{parisizemax} is set, PARI tries to fit its computations within about \kbd{parisize} bytes, but will increase the stack size if needed, roughly doubling it each time (up to \kbd{parisizemax} of course!) and printing a message such as \kbd{Warning: increasing stack size to} \var{some value}. Once the memory intensive computation is over, PARI will restore the stack size to the originally requested \kbd{parisize} without printing further messages. We \emph{strongly} recommend to set \tet{parisizemax} permanently to a large non-zero value in your \tet{gprc}, about what you believe your machine can stand. It is possible to increase or decrease \kbd{parisizemax} inside a running \kbd{gp} session, just use \kbd{default} as usual. The default value is $0$, for backward compatibility reasons. \subsec{path}\kbdsidx{path}\label{se:def,path} This is a list of directories, separated by colons ':' (semicolons ';' in the DOS world, since colons are preempted for drive names). When asked to read a file whose name is not given by an absolute path (does not start with \kbd{/}, \kbd{./} or \kbd{../}), \kbd{gp} will look for it in these directories, in the order they were written in \kbd{path}. Here, as usual, \kbd{.} means the current directory, and \kbd{..} its immediate parent. Environment expansion is performed. The default value is \kbd{".:\til:\til/gp"} on UNIX systems, \kbd{".;C:\bs;C:\bs GP"} on DOS, OS/2 and Windows, and \kbd{"."} otherwise. \subsec{plothsizes}\kbdsidx{plothsizes}\label{se:def,plothsizes} If the graphic driver allows it, the array contains the size of the terminal, the size of the font, the size of the ticks. \subsec{prettyprinter}\kbdsidx{prettyprinter}\label{se:def,prettyprinter} The name of an external prettyprinter to use when \kbd{output} is~3 (alternate prettyprinter). Note that the default \tet{tex2mail} looks much nicer than the built-in ``beautified format'' ($\kbd{output} = 2$). The default value is \kbd{"tex2mail -TeX -noindent -ragged -by\_par"}. \subsec{primelimit}\kbdsidx{primelimit}\label{se:def,primelimit} \kbd{gp} precomputes a list of all primes less than \kbd{primelimit} at initialization time, and can build fast sieves on demand to quickly iterate over primes up to the \emph{square} of \kbd{primelimit}. These are used by many arithmetic functions, usually for trial division purposes. The maximal value is $2^{32} - 2049$ (resp $2^{64} - 2049$) on a 32-bit (resp.~64-bit) machine, but values beyond $10^8$, allowing to iterate over primes up to $10^{16}$, do not seem useful. Since almost all arithmetic functions eventually require some table of prime numbers, PARI guarantees that the first 6547 primes, up to and including 65557, are precomputed, even if \kbd{primelimit} is $1$. This default is only used on startup: changing it will not recompute a new table. \misctitle{Deprecated feature} \kbd{primelimit} was used in some situations by algebraic number theory functions using the \tet{nf_PARTIALFACT} flag (\tet{nfbasis}, \tet{nfdisc}, \tet{nfinit}, \dots): this assumes that all primes $p > \kbd{primelimit}$ have a certain property (the equation order is $p$-maximal). This is never done by default, and must be explicitly set by the user of such functions. Nevertheless, these functions now provide a more flexible interface, and their use of the global default \kbd{primelimit} is deprecated. \misctitle{Deprecated feature} \kbd{factor(N, 0)} was used to partially factor integers by removing all prime factors $\leq$ \kbd{primelimit}. Don't use this, supply an explicit bound: \kbd{factor(N, bound)}, which avoids relying on an unpredictable global variable. The default value is \kbd{500k}. \subsec{prompt}\kbdsidx{prompt}\label{se:def,prompt} A string that will be printed as prompt. Note that most usual escape sequences are available there: \b{e} for Esc, \b{n} for Newline, \dots, \kbd{\bs\bs} for \kbd{\bs}. Time expansion is performed. This string is sent through the library function \tet{strftime} (on a Unix system, you can try \kbd{man strftime} at your shell prompt). This means that \kbd{\%} constructs have a special meaning, usually related to the time and date. For instance, \kbd{\%H} = hour (24-hour clock) and \kbd{\%M} = minute [00,59] (use \kbd{\%\%} to get a real \kbd{\%}). If you use \kbd{readline}, escape sequences in your prompt will result in display bugs. If you have a relatively recent \kbd{readline} (see the comment at the end of \secref{se:def,colors}), you can brace them with special sequences (\kbd{\bs[} and \kbd{\bs]}), and you will be safe. If these just result in extra spaces in your prompt, then you'll have to get a more recent \kbd{readline}. See the file \kbd{misc/gprc.dft} for an example. \emacs {\bf Caution}: PariEmacs needs to know about the prompt pattern to separate your input from previous \kbd{gp} results, without ambiguity. It is not a trivial problem to adapt automatically this regular expression to an arbitrary prompt (which can be self-modifying!). See PariEmacs's documentation. The default value is \kbd{"? "}. \subsec{prompt\_cont}\kbdsidx{def,prompt_cont}\label{se:def,prompt_cont} A string that will be printed to prompt for continuation lines (e.g. in between braces, or after a line-terminating backslash). Everything that applies to \kbd{prompt} applies to \kbd{prompt\_cont} as well. The default value is \kbd{""}. \subsec{psfile}\kbdsidx{psfile}\label{se:def,psfile} This default is obsolete, use one of plotexport, plothexport or plothrawexport functions and write the result to file. \subsec{readline}\kbdsidx{readline}\label{se:def,readline} Switches readline line-editing facilities on and off. This may be useful if you are running \kbd{gp} in a Sun \tet{cmdtool}, which interacts badly with readline. Of course, until readline is switched on again, advanced editing features like automatic completion and editing history are not available. The default value is \kbd{1}. \subsec{realbitprecision}\kbdsidx{realbitprecision}\label{se:def,realbitprecision} The number of significant bits used to convert exact inputs given to transcendental functions (see \secref{se:trans}), or to create absolute floating point constants (input as \kbd{1.0} or \kbd{Pi} for instance). Unless you tamper with the \tet{format} default, this is also the number of significant bits used to print a \typ{REAL} number; \kbd{format} will override this latter behavior, and allow you to have a large internal precision while outputting few digits for instance. Note that most PARI's functions currently handle precision on a word basis (by increments of 32 or 64 bits), hence bit precision may be a little larger than the number of bits you expected. For instance to get 10 bits of precision, you need one word of precision which, on a 64-bit machine, correspond to 64 bits. To make things even more confusing, this internal bit accuracy is converted to decimal digits when printing floating point numbers: now 64 bits correspond to 19 printed decimal digits ($19 < \log_{10}(2^{64}) < 20$). The value returned when typing \kbd{default(realbitprecision)} is the internal number of significant bits, not the number of printed decimal digits: \bprog ? default(realbitprecision, 10) ? \pb realbitprecision = 64 significant bits ? default(realbitprecision) %1 = 64 ? \p realprecision = 3 significant digits ? default(realprecision) %2 = 19 @eprog\noindent Note that \tet{realprecision} and \kbd{\bs p} allow to view and manipulate the internal precision in decimal digits. The default value is \kbd{128}, resp.~\kbd{96}, on a 64-bit, resp~.32-bit, machine. \subsec{realprecision}\kbdsidx{realprecision}\label{se:def,realprecision} The number of significant digits used to convert exact inputs given to transcendental functions (see \secref{se:trans}), or to create absolute floating point constants (input as \kbd{1.0} or \kbd{Pi} for instance). Unless you tamper with the \tet{format} default, this is also the number of significant digits used to print a \typ{REAL} number; \kbd{format} will override this latter behavior, and allow you to have a large internal precision while outputting few digits for instance. Note that PARI's internal precision works on a word basis (by increments of 32 or 64 bits), hence may be a little larger than the number of decimal digits you expected. For instance to get 2 decimal digits you need one word of precision which, on a 64-bit machine, actually gives you 19 digits ($19 < \log_{10}(2^{64}) < 20$). The value returned when typing \kbd{default(realprecision)} is the internal number of significant digits, not the number of printed digits: \bprog ? default(realprecision, 2) realprecision = 19 significant digits (2 digits displayed) ? default(realprecision) %1 = 19 @eprog The default value is \kbd{38}, resp.~\kbd{28}, on a 64-bit, resp.~32-bit, machine. \subsec{recover}\kbdsidx{recover}\label{se:def,recover} This toggle is either 1 (on) or 0 (off). If you change this to $0$, any error becomes fatal and causes the gp interpreter to exit immediately. Can be useful in batch job scripts. The default value is \kbd{1}. \subsec{secure}\kbdsidx{secure}\label{se:def,secure} This toggle is either 1 (on) or 0 (off). If on, the \tet{system} and \tet{extern} command are disabled. These two commands are potentially dangerous when you execute foreign scripts since they let \kbd{gp} execute arbitrary UNIX commands. \kbd{gp} will ask for confirmation before letting you (or a script) unset this toggle. The default value is \kbd{0}. \subsec{seriesprecision}\kbdsidx{seriesprecision}\label{se:def,seriesprecision} Number of significant terms when converting a polynomial or rational function to a power series (see~\b{ps}). The default value is \kbd{16}. \subsec{simplify}\kbdsidx{simplify}\label{se:def,simplify} This toggle is either 1 (on) or 0 (off). When the PARI library computes something, the type of the result is not always the simplest possible. The only type conversions which the PARI library does automatically are rational numbers to integers (when they are of type \typ{FRAC} and equal to integers), and similarly rational functions to polynomials (when they are of type \typ{RFRAC} and equal to polynomials). This feature is useful in many cases, and saves time, but can be annoying at times. Hence you can disable this and, whenever you feel like it, use the function \kbd{simplify} (see Chapter 3) which allows you to simplify objects to the simplest possible types recursively (see~\b{y}). \sidx{automatic simplification} The default value is \kbd{1}. \subsec{sopath}\kbdsidx{sopath}\label{se:def,sopath} This is a list of directories, separated by colons ':' (semicolons ';' in the DOS world, since colons are preempted for drive names). When asked to \tet{install} an external symbol from a shared library whose name is not given by an absolute path (does not start with \kbd{/}, \kbd{./} or \kbd{../}), \kbd{gp} will look for it in these directories, in the order they were written in \kbd{sopath}. Here, as usual, \kbd{.} means the current directory, and \kbd{..} its immediate parent. Environment expansion is performed. The default value is \kbd{""}, corresponding to an empty list of directories: \tet{install} will use the library name as input (and look in the current directory if the name is not an absolute path). \subsec{strictargs}\kbdsidx{strictargs}\label{se:def,strictargs} This toggle is either 1 (on) or 0 (off). If on, all arguments to \emph{new} user functions are mandatory unless the function supplies an explicit default value. Otherwise arguments have the default value $0$. In this example, \bprog fun(a,b=2)=a+b @eprog \kbd{a} is mandatory, while \kbd{b} is optional. If \kbd{strictargs} is on: \bprog ? fun() *** at top-level: fun() *** ^----- *** in function fun: a,b=2 *** ^----- *** missing mandatory argument 'a' in user function. @eprog This applies to functions defined while \kbd{strictargs} is on. Changing \kbd{strictargs} does not affect the behavior of previously defined functions. The default value is \kbd{0}. \subsec{strictmatch}\kbdsidx{strictmatch}\label{se:def,strictmatch} Obsolete. This toggle is now a no-op. \subsec{threadsize}\kbdsidx{threadsize}\label{se:def,threadsize} This default is specific to the \emph{parallel} version of PARI and gp (built via \kbd{Configure --mt=prthread} or \kbd{mpi}) and is ignored otherwise. In parallel mode, each thread allocates its own private \tev{stack} for its computations, see \kbd{parisize}. This value determines the size in bytes of the stacks of each thread, so the total memory allocated will be $\kbd{parisize}+\kbd{nbthreads}\times\kbd{threadsize}$. If set to $0$, the value used is the same as \kbd{parisize}. It is not easy to estimate reliably a sufficient value for this parameter because PARI itself will parallelize computations and we recommend to not set this value explicitly unless it solves a specific problem for you. For instance if you see frequent messages of the form \bprog *** Warning: not enough memory, new thread stack 10000002048 @eprog (Meaning that \kbd{threadsize} had to be temporarily increased.) On the other hand we strongly recommend to set \kbd{parisizemax} and \kbd{threadsizemax} to a non-zero value. The default value is $0$. \subsec{threadsizemax}\kbdsidx{threadsizemax}\label{se:def,threadsizemax} This default is specific to the \emph{parallel} version of PARI and gp (built via \kbd{Configure --mt=pthread} or \kbd{mpi}) and is ignored otherwise. In parallel mode, each threads allocates its own private \tev{stack} for its computations, see \kbd{parisize} and \kbd{parisizemax}. The values of \kbd{threadsize} and \kbd{threadsizemax} determine the usual and maximal size in bytes of the stacks of each thread, so the total memory allocated will be between $\kbd{parisize}+\kbd{nbthreads}\times\kbd{threadsize}$. and $\kbd{parisizemax}+\kbd{nbthreads}\times\kbd{threadsizemax}$. If set to $0$, the value used is the same as \kbd{threadsize}. We strongy recommend to set both \kbd{parisizemax} and \kbd{threadsizemax} to a non-zero value. The default value is $0$. \subsec{timer}\kbdsidx{timer}\label{se:def,timer} This toggle is either 1 (on) or 0 (off). Every instruction sequence in the gp calculator (anything ended by a newline in your input) is timed, to some accuracy depending on the hardware and operating system. When \tet{timer} is on, each such timing is printed immediately before the output as follows: \bprog ? factor(2^2^7+1) time = 108 ms. \\ this line omitted if 'timer' is 0 %1 = [ 59649589127497217 1] [5704689200685129054721 1] @eprog\noindent (See also \kbd{\#} and \kbd{\#\#}.) The time measured is the user \idx{CPU time}, \emph{not} including the time for printing the results. If the time is negligible ($< 1$ ms.), nothing is printed: in particular, no timing should be printed when defining a user function or an alias, or installing a symbol from the library. The default value is \kbd{0} (off). \section{Standard monadic or dyadic operators} \subseckbd{+$/$-} The expressions \kbd{+}$x$ and \kbd{-}$x$ refer to monadic operators (the first does nothing, the second negates $x$). The library syntax is \fun{GEN}{gneg}{GEN x} for \kbd{-}$x$. \subseckbd{+} The expression $x$ \kbd{+} $y$ is the \idx{sum} of $x$ and $y$. Addition between a scalar type $x$ and a \typ{COL} or \typ{MAT} $y$ returns respectively $[y[1] + x, y[2],\dots]$ and $y + x \text{Id}$. Other additions between a scalar type and a vector or a matrix, or between vector/matrices of incompatible sizes are forbidden. The library syntax is \fun{GEN}{gadd}{GEN x, GEN y}. \subseckbd{-} The expression $x$ \kbd{-} $y$ is the \idx{difference} of $x$ and $y$. Subtraction between a scalar type $x$ and a \typ{COL} or \typ{MAT} $y$ returns respectively $[y[1] - x, y[2],\dots]$ and $y - x \text{Id}$. Other subtractions between a scalar type and a vector or a matrix, or between vector/matrices of incompatible sizes are forbidden. The library syntax is \fun{GEN}{gsub}{GEN x, GEN y} for $x$ \kbd{-} $y$. \subseckbd{*} The expression $x$ \kbd{*} $y$ is the \idx{product} of $x$ and $y$. Among the prominent impossibilities are multiplication between vector/matrices of incompatible sizes, between a \typ{INTMOD} or \typ{PADIC} Restricted to scalars, \kbd{*} is commutative; because of vector and matrix operations, it is not commutative in general. Multiplication between two \typ{VEC}s or two \typ{COL}s is not allowed; to take the \idx{scalar product} of two vectors of the same length, transpose one of the vectors (using the operator \kbd{\til} or the function \kbd{mattranspose}, see \secref{se:linear_algebra}) and multiply a line vector by a column vector: \bprog ? a = [1,2,3]; ? a * a *** at top-level: a*a *** ^-- *** _*_: forbidden multiplication t_VEC * t_VEC. ? a * a~ %2 = 14 @eprog If $x,y$ are binary quadratic forms, compose them; see also \kbd{qfbnucomp} and \kbd{qfbnupow}. If $x,y$ are \typ{VECSMALL} of the same length, understand them as permutations and compose them. The library syntax is \fun{GEN}{gmul}{GEN x, GEN y} for $x$ \kbd{*} $y$. Also available is \fun{GEN}{gsqr}{GEN x} for $x$ \kbd{*} $x$. \subseckbd{/} The expression $x$ \kbd{/} $y$ is the \idx{quotient} of $x$ and $y$. In addition to the impossibilities for multiplication, note that if the divisor is a matrix, it must be an invertible square matrix, and in that case the result is $x*y^{-1}$. Furthermore note that the result is as exact as possible: in particular, division of two integers always gives a rational number (which may be an integer if the quotient is exact) and \emph{not} the Euclidean quotient (see $x$ \kbd{\bs} $y$ for that), and similarly the quotient of two polynomials is a rational function in general. To obtain the approximate real value of the quotient of two integers, add \kbd{0.} to the result; to obtain the approximate $p$-adic value of the quotient of two integers, add \kbd{O(p\pow k)} to the result; finally, to obtain the \idx{Taylor series} expansion of the quotient of two polynomials, add \kbd{O(X\pow k)} to the result or use the \kbd{taylor} function (see \secref{se:taylor}). \label{se:gdiv} The library syntax is \fun{GEN}{gdiv}{GEN x, GEN y} for $x$ \kbd{/} $y$. \subseckbd{\bs} The expression \kbd{$x$ \bs\ $y$} is the \idx{Euclidean quotient} of $x$ and $y$. If $y$ is a real scalar, this is defined as \kbd{floor($x$/$y$)} if $y > 0$, and \kbd{ceil($x$/$y$)} if $y < 0$ and the division is not exact. Hence the remainder \kbd{$x$ - ($x$\bs$y$)*$y$} is in $[0, |y|[$. Note that when $y$ is an integer and $x$ a polynomial, $y$ is first promoted to a polynomial of degree $0$. When $x$ is a vector or matrix, the operator is applied componentwise. The library syntax is \fun{GEN}{gdivent}{GEN x, GEN y} for $x$ \kbd{\bs} $y$. \subseckbd{\bs/} The expression $x$ \b{/} $y$ evaluates to the rounded \idx{Euclidean quotient} of $x$ and $y$. This is the same as \kbd{$x$ \bs\ $y$} except for scalar division: the quotient is such that the corresponding remainder is smallest in absolute value and in case of a tie the quotient closest to $+\infty$ is chosen (hence the remainder would belong to $]{-}|y|/2, |y|/2]$). When $x$ is a vector or matrix, the operator is applied componentwise. The library syntax is \fun{GEN}{gdivround}{GEN x, GEN y} for $x$ \b{/} $y$. \subseckbd{\%} The expression \kbd{$x$ \% $y$} evaluates to the modular \idx{Euclidean remainder} of $x$ and $y$, which we now define. When $x$ or $y$ is a non-integral real number, \kbd{$x$\%$y$} is defined as \kbd{$x$ - ($x$\bs$y$)*$y$}. Otherwise, if $y$ is an integer, this is the smallest non-negative integer congruent to $x$ modulo $y$. (This actually coincides with the previous definition if and only if $x$ is an integer.) If $y$ is a polynomial, this is the polynomial of smallest degree congruent to $x$ modulo $y$. For instance: \bprog ? (1/2) % 3 %1 = 2 ? 0.5 % 3 %2 = 0.5000000000000000000000000000 ? (1/2) % 3.0 %3 = 1/2 @eprog Note that when $y$ is an integer and $x$ a polynomial, $y$ is first promoted to a polynomial of degree $0$. When $x$ is a vector or matrix, the operator is applied componentwise. The library syntax is \fun{GEN}{gmod}{GEN x, GEN y} for $x$ \kbd{\%} $y$. \subseckbd{\pow} The expression $x\hbox{\kbd{\pow}}n$ is \idx{powering}. \item If the exponent $n$ is an integer, then exact operations are performed using binary (left-shift) powering techniques. If $x$ is a $p$-adic number, its precision will increase if $v_p(n) > 0$. Powering a binary quadratic form (types \typ{QFI} and \typ{QFR}) returns a representative of the class, which is always reduced if the input was. (In particular, \kbd{x \pow 1} returns $x$ itself, whether it is reduced or not.) PARI is able to rewrite the multiplication $x * x$ of two \emph{identical} objects as $x^2$, or $\kbd{sqr}(x)$. Here, identical means the operands are two different labels referencing the same chunk of memory; no equality test is performed. This is no longer true when more than two arguments are involved. \item If the exponent $n$ is not an integer, powering is treated as the transcendental function $\exp(n\log x)$, and in particular acts componentwise on vector or matrices, even square matrices ! (See \secref{se:trans}.) \item As an exception, if the exponent is a rational number $p/q$ and $x$ an integer modulo a prime or a $p$-adic number, return a solution $y$ of $y^q=x^p$ if it exists. Currently, $q$ must not have large prime factors. Beware that \bprog ? Mod(7,19)^(1/2) %1 = Mod(11, 19) /* is any square root */ ? sqrt(Mod(7,19)) %2 = Mod(8, 19) /* is the smallest square root */ ? Mod(7,19)^(3/5) %3 = Mod(1, 19) ? %3^(5/3) %4 = Mod(1, 19) /* Mod(7,19) is just another cubic root */ @eprog \item If the exponent is a negative integer, an \idx{inverse} must be computed. For non-invertible \typ{INTMOD} $x$, this will fail and implicitly exhibit a non trivial factor of the modulus: \bprog ? Mod(4,6)^(-1) *** at top-level: Mod(4,6)^(-1) *** ^----- *** _^_: impossible inverse modulo: Mod(2, 6). @eprog\noindent (Here, a factor 2 is obtained directly. In general, take the gcd of the representative and the modulus.) This is most useful when performing complicated operations modulo an integer $N$ whose factorization is unknown. Either the computation succeeds and all is well, or a factor $d$ is discovered and the computation may be restarted modulo $d$ or $N/d$. For non-invertible \typ{POLMOD} $x$, the behavior is the same: \bprog ? Mod(x^2, x^3-x)^(-1) *** at top-level: Mod(x^2,x^3-x)^(-1) *** ^----- *** _^_: impossible inverse in RgXQ_inv: Mod(x^2, x^3 - x). @eprog\noindent Note that the underlying algorihm (subresultant) assumes the base ring is a domain: \bprog ? a = Mod(3*y^3+1, 4); b = y^6+y^5+y^4+y^3+y^2+y+1; c = Mod(a,b); ? c^(-1) *** at top-level: Mod(a,b)^(-1) *** ^----- *** _^_: impossible inverse modulo: Mod(2, 4). @eprog\noindent In fact $c$ is invertible, but $\Z/4\Z$ is not a domain and the algorithm fails. It is possible for the algorithm to succeed in such situations and any returned result will be correct, but chances are an error will occur first. In this specific case, one should work with $2$-adics. In general, one can also try the following approach \bprog ? inversemod(a, b) = { my(m, v = variable(b)); m = polsylvestermatrix(polrecip(a), polrecip(b)); m = matinverseimage(m, matid(#m)[,1]); Polrev(m[1..poldegree(b)], v); } ? inversemod(a,b) %2 = Mod(2,4)*y^5 + Mod(3,4)*y^3 + Mod(1,4)*y^2 + Mod(3,4)*y + Mod(2,4) @eprog\noindent This is not guaranteed to work either since \kbd{matinverseimage} must also invert pivots. See \secref{se:linear_algebra}. For a \typ{MAT} $x$, the matrix is expected to be square and invertible, except in the special case \kbd{x\pow(-1)} which returns a left inverse if one exists (rectangular $x$ with full column rank). \bprog ? x = Mat([1;2]) %1 = [1] [2] ? x^(-1) %2 = [1 0] @eprog The library syntax is \fun{GEN}{gpow}{GEN x, GEN n, long prec} for $x\hbox{\kbd{\pow}}n$. \subsec{cmp$(x,y)$}\kbdsidx{cmp}\label{se:cmp} Gives the result of a comparison between arbitrary objects $x$ and $y$ (as $-1$, $0$ or $1$). The underlying order relation is transitive, the function returns $0$ if and only if $x~\kbd{===}~y$. It has no mathematical meaning but satisfies the following properties when comparing entries of the same type: \item two \typ{INT}s compare as usual (i.e. \kbd{cmp}$(x,y) < 0$ if and only if $x < y$); \item two \typ{VECSMALL}s of the same length compare lexicographically; \item two \typ{STR}s compare lexicographically. In case all components are equal up to the smallest length of the operands, the more complex is considered to be larger. More precisely, the longest is the largest; when lengths are equal, we have matrix $>$ vector $>$ scalar. For example: \bprog ? cmp(1, 2) %1 = -1 ? cmp(2, 1) %2 = 1 ? cmp(1, 1.0) \\ note that 1 == 1.0, but (1===1.0) is false. %3 = -1 ? cmp(x + Pi, []) %4 = -1 @eprog\noindent This function is mostly useful to handle sorted lists or vectors of arbitrary objects. For instance, if $v$ is a vector, the construction \kbd{vecsort(v, cmp)} is equivalent to \kbd{Set(v)}. The library syntax is \fun{GEN}{cmp_universal}{GEN x, GEN y}. \subsec{divrem$(x,y,\{v\})$}\kbdsidx{divrem}\label{se:divrem} Creates a column vector with two components, the first being the Euclidean quotient (\kbd{$x$ \bs\ $y$}), the second the Euclidean remainder (\kbd{$x$ - ($x$\bs$y$)*$y$}), of the division of $x$ by $y$. This avoids the need to do two divisions if one needs both the quotient and the remainder. If $v$ is present, and $x$, $y$ are multivariate polynomials, divide with respect to the variable $v$. Beware that \kbd{divrem($x$,$y$)[2]} is in general not the same as \kbd{$x$ \% $y$}; no GP operator corresponds to it: \bprog ? divrem(1/2, 3)[2] %1 = 1/2 ? (1/2) % 3 %2 = 2 ? divrem(Mod(2,9), 3)[2] *** at top-level: divrem(Mod(2,9),3)[2 *** ^-------------------- *** forbidden division t_INTMOD \ t_INT. ? Mod(2,9) % 6 %3 = Mod(2,3) @eprog The library syntax is \fun{GEN}{divrem}{GEN x, GEN y, long v = -1} where \kbd{v} is a variable number. Also available is \fun{GEN}{gdiventres}{GEN x, GEN y} when $v$ is not needed. \subsec{lex$(x,y)$}\kbdsidx{lex}\label{se:lex} Gives the result of a lexicographic comparison between $x$ and $y$ (as $-1$, $0$ or $1$). This is to be interpreted in quite a wide sense: It is admissible to compare objects of different types (scalars, vectors, matrices), provided the scalars can be compared, as well as vectors/matrices of different lengths. The comparison is recursive. In case all components are equal up to the smallest length of the operands, the more complex is considered to be larger. More precisely, the longest is the largest; when lengths are equal, we have matrix $>$ vector $>$ scalar. For example: \bprog ? lex([1,3], [1,2,5]) %1 = 1 ? lex([1,3], [1,3,-1]) %2 = -1 ? lex([1], [[1]]) %3 = -1 ? lex([1], [1]~) %4 = 0 @eprog The library syntax is \fun{GEN}{lexcmp}{GEN x, GEN y}. \subsec{max$(x,y)$}\kbdsidx{max}\label{se:max} Creates the maximum of $x$ and $y$ when they can be compared. The library syntax is \fun{GEN}{gmax}{GEN x, GEN y}. \subsec{min$(x,y)$}\kbdsidx{min}\label{se:min} Creates the minimum of $x$ and $y$ when they can be compared. The library syntax is \fun{GEN}{gmin}{GEN x, GEN y}. \subsec{powers$(x,n,\{\var{x0}\})$}\kbdsidx{powers}\label{se:powers} For non-negative $n$, return the vector with $n+1$ components $[1,x,\dots,x^n]$ if \kbd{x0} is omitted, and $[x_0, x_0*x, ..., x_0*x^n]$ otherwise. \bprog ? powers(Mod(3,17), 4) %1 = [Mod(1, 17), Mod(3, 17), Mod(9, 17), Mod(10, 17), Mod(13, 17)] ? powers(Mat([1,2;3,4]), 3) %2 = [[1, 0; 0, 1], [1, 2; 3, 4], [7, 10; 15, 22], [37, 54; 81, 118]] ? powers(3, 5, 2) %3 = [2, 6, 18, 54, 162, 486] @eprog\noindent When $n < 0$, the function returns the empty vector \kbd{[]}. The library syntax is \fun{GEN}{gpowers0}{GEN x, long n, GEN x0 = NULL}. Also available is \fun{GEN}{gpowers}{GEN x, long n} when \kbd{x0} is \kbd{NULL}. \subsec{shift$(x,n)$}\kbdsidx{shift}\label{se:shift} Shifts $x$ componentwise left by $n$ bits if $n\ge0$ and right by $|n|$ bits if $n<0$. May be abbreviated as $x$ \kbd{<<} $n$ or $x$ \kbd{>>} $(-n)$. A left shift by $n$ corresponds to multiplication by $2^n$. A right shift of an integer $x$ by $|n|$ corresponds to a Euclidean division of $x$ by $2^{|n|}$ with a remainder of the same sign as $x$, hence is not the same (in general) as $x \kbd{\bs} 2^n$. The library syntax is \fun{GEN}{gshift}{GEN x, long n}. \subsec{shiftmul$(x,n)$}\kbdsidx{shiftmul}\label{se:shiftmul} Multiplies $x$ by $2^n$. The difference with \kbd{shift} is that when $n<0$, ordinary division takes place, hence for example if $x$ is an integer the result may be a fraction, while for shifts Euclidean division takes place when $n<0$ hence if $x$ is an integer the result is still an integer. The library syntax is \fun{GEN}{gmul2n}{GEN x, long n}. \subsec{sign$(x)$}\kbdsidx{sign}\label{se:sign} \idx{sign} ($0$, $1$ or $-1$) of $x$, which must be of type integer, real or fraction; \typ{QUAD} with positive discriminants and \typ{INFINITY} are also supported. The library syntax is \fun{GEN}{gsigne}{GEN x}. \subsec{vecmax$(x,\{\&v\})$}\kbdsidx{vecmax}\label{se:vecmax} If $x$ is a vector or a matrix, returns the largest entry of $x$, otherwise returns a copy of $x$. Error if $x$ is empty. If $v$ is given, set it to the index of a largest entry (indirect maximum), when $x$ is a vector. If $x$ is a matrix, set $v$ to coordinates $[i,j]$ such that $x[i,j]$ is a largest entry. This flag is ignored if $x$ is not a vector or matrix. \bprog ? vecmax([10, 20, -30, 40]) %1 = 40 ? vecmax([10, 20, -30, 40], &v); v %2 = 4 ? vecmax([10, 20; -30, 40], &v); v %3 = [2, 2] @eprog The library syntax is \fun{GEN}{vecmax0}{GEN x, GEN *v = NULL}. When $v$ is not needed, the function \fun{GEN}{vecmax}{GEN x} is also available. \subsec{vecmin$(x,\{\&v\})$}\kbdsidx{vecmin}\label{se:vecmin} If $x$ is a vector or a matrix, returns the smallest entry of $x$, otherwise returns a copy of $x$. Error if $x$ is empty. If $v$ is given, set it to the index of a smallest entry (indirect minimum), when $x$ is a vector. If $x$ is a matrix, set $v$ to coordinates $[i,j]$ such that $x[i,j]$ is a smallest entry. This is ignored if $x$ is not a vector or matrix. \bprog ? vecmin([10, 20, -30, 40]) %1 = -30 ? vecmin([10, 20, -30, 40], &v); v %2 = 3 ? vecmin([10, 20; -30, 40], &v); v %3 = [2, 1] @eprog The library syntax is \fun{GEN}{vecmin0}{GEN x, GEN *v = NULL}. When $v$ is not needed, the function \fun{GEN}{vecmin}{GEN x} is also available. \subsec{Comparison and Boolean operators}\sidx{Boolean operators} The six standard \idx{comparison operators} \kbd{<=}, \kbd{<}, \kbd{>=}, \kbd{>}, \kbd{==}, \kbd{!=} are available in GP. The result is 1 if the comparison is true, 0 if it is false. The operator \kbd{==} is quite liberal : for instance, the integer 0, a 0 polynomial, and a vector with 0 entries are all tested equal. The extra operator \kbd{===} tests whether two objects are identical and is much stricter than \kbd{==} : objects of different type or length are never identical. For the purpose of comparison, \typ{STR} objects are compared using the standard lexicographic order, and comparing them to objects of a different type raises an exception. GP accepts \kbd{<>} as a synonym for \kbd{!=}. On the other hand, \kbd{=} is definitely \emph{not} a synonym for \kbd{==}: it is the assignment statement. The standard boolean operators \kbd{||} (\idx{inclusive or}), \kbd{\&\&} (\idx{and})\sidx{or} and \kbd{!} (\idx{not}) are also available. \section{Conversions and similar elementary functions or commands} \label{se:conversion} \noindent Many of the conversion functions are rounding or truncating operations. In this case, if the argument is a rational function, the result is the Euclidean quotient of the numerator by the denominator, and if the argument is a vector or a matrix, the operation is done componentwise. This will not be restated for every function. \subsec{Col$(x, \{n\})$}\kbdsidx{Col}\label{se:Col} Transforms the object $x$ into a column vector. The dimension of the resulting vector can be optionally specified via the extra parameter $n$. If $n$ is omitted or $0$, the dimension depends on the type of $x$; the vector has a single component, except when $x$ is \item a vector or a quadratic form (in which case the resulting vector is simply the initial object considered as a row vector), \item a polynomial or a power series. In the case of a polynomial, the coefficients of the vector start with the leading coefficient of the polynomial, while for power series only the significant coefficients are taken into account, but this time by increasing order of degree. In this last case, \kbd{Vec} is the reciprocal function of \kbd{Pol} and \kbd{Ser} respectively, \item a matrix (the column of row vector comprising the matrix is returned), \item a character string (a vector of individual characters is returned). In the last two cases (matrix and character string), $n$ is meaningless and must be omitted or an error is raised. Otherwise, if $n$ is given, $0$ entries are appended at the end of the vector if $n > 0$, and prepended at the beginning if $n < 0$. The dimension of the resulting vector is $|n|$. See ??Vec for examples. The library syntax is \fun{GEN}{gtocol0}{GEN x, long n}. \fun{GEN}{gtocol}{GEN x} is also available. \subsec{Colrev$(x, \{n\})$}\kbdsidx{Colrev}\label{se:Colrev} As $\kbd{Col}(x, -n)$, then reverse the result. In particular, \kbd{Colrev} is the reciprocal function of \kbd{Polrev}: the coefficients of the vector start with the constant coefficient of the polynomial and the others follow by increasing degree. The library syntax is \fun{GEN}{gtocolrev0}{GEN x, long n}. \fun{GEN}{gtocolrev}{GEN x} is also available. \subsec{List$(\{x=[\,]\})$}\kbdsidx{List}\label{se:List} Transforms a (row or column) vector $x$ into a list, whose components are the entries of $x$. Similarly for a list, but rather useless in this case. For other types, creates a list with the single element $x$. Note that, except when $x$ is omitted, this function creates a small memory leak; so, either initialize all lists to the empty list, or use them sparingly. The library syntax is \fun{GEN}{gtolist}{GEN x = NULL}. The variant \fun{GEN}{mklist}{void} creates an empty list. \subsec{Map$(\{x\})$}\kbdsidx{Map}\label{se:Map} A ``Map'' is an associative array, or dictionary: a data type composed of a collection of (\emph{key}, \emph{value}) pairs, such that each key appears just once in the collection. This function converts the matrix $[a_1,b_1;a_2,b_2;\dots;a_n,b_n]$ to the map $a_i\mapsto b_i$. \bprog ? M = Map(factor(13!)); ? mapget(M,3) %2 = 5 @eprog\noindent If the argument $x$ is omitted, creates an empty map, which may be filled later via \tet{mapput}. The library syntax is \fun{GEN}{gtomap}{GEN x = NULL}. \subsec{Mat$(\{x=[\,]\})$}\kbdsidx{Mat}\label{se:Mat} Transforms the object $x$ into a matrix. If $x$ is already a matrix, a copy of $x$ is created. If $x$ is a row (resp. column) vector, this creates a 1-row (resp. 1-column) matrix, \emph{unless} all elements are column (resp.~row) vectors of the same length, in which case the vectors are concatenated sideways and the attached big matrix is returned. If $x$ is a binary quadratic form, creates the attached $2\times 2$ matrix. Otherwise, this creates a $1\times 1$ matrix containing $x$. \bprog ? Mat(x + 1) %1 = [x + 1] ? Vec( matid(3) ) %2 = [[1, 0, 0]~, [0, 1, 0]~, [0, 0, 1]~] ? Mat(%) %3 = [1 0 0] [0 1 0] [0 0 1] ? Col( [1,2; 3,4] ) %4 = [[1, 2], [3, 4]]~ ? Mat(%) %5 = [1 2] [3 4] ? Mat(Qfb(1,2,3)) %6 = [1 1] [1 3] @eprog The library syntax is \fun{GEN}{gtomat}{GEN x = NULL}. \subsec{Mod$(a,b)$}\kbdsidx{Mod}\label{se:Mod} In its basic form, creates an intmod or a polmod $(a \mod b)$; $b$ must be an integer or a polynomial. We then obtain a \typ{INTMOD} and a \typ{POLMOD} respectively: \bprog ? t = Mod(2,17); t^8 %1 = Mod(1, 17) ? t = Mod(x,x^2+1); t^2 %2 = Mod(-1, x^2+1) @eprog\noindent If $a \% b$ makes sense and yields a result of the appropriate type (\typ{INT} or scalar/\typ{POL}), the operation succeeds as well: \bprog ? Mod(1/2, 5) %3 = Mod(3, 5) ? Mod(7 + O(3^6), 3) %4 = Mod(1, 3) ? Mod(Mod(1,12), 9) %5 = Mod(1, 3) ? Mod(1/x, x^2+1) %6 = Mod(-1, x^2+1) ? Mod(exp(x), x^4) %7 = Mod(1/6*x^3 + 1/2*x^2 + x + 1, x^4) @eprog If $a$ is a complex object, ``base change'' it to $\Z/b\Z$ or $K[x]/(b)$, which is equivalent to, but faster than, multiplying it by \kbd{Mod(1,b)}: \bprog ? Mod([1,2;3,4], 2) %8 = [Mod(1, 2) Mod(0, 2)] [Mod(1, 2) Mod(0, 2)] ? Mod(3*x+5, 2) %9 = Mod(1, 2)*x + Mod(1, 2) ? Mod(x^2 + y*x + y^3, y^2+1) %10 = Mod(1, y^2 + 1)*x^2 + Mod(y, y^2 + 1)*x + Mod(-y, y^2 + 1) @eprog This function is not the same as $x$ \kbd{\%} $y$, the result of which has no knowledge of the intended modulus $y$. Compare \bprog ? x = 4 % 5; x + 1 %1 = 5 ? x = Mod(4,5); x + 1 %2 = Mod(0,5) @eprog Note that such ``modular'' objects can be lifted via \tet{lift} or \tet{centerlift}. The modulus of a \typ{INTMOD} or \typ{POLMOD} $z$ can be recovered via \kbd{$z$.mod}. The library syntax is \fun{GEN}{gmodulo}{GEN a, GEN b}. \subsec{Pol$(t,\{v='x\})$}\kbdsidx{Pol}\label{se:Pol} Transforms the object $t$ into a polynomial with main variable $v$. If $t$ is a scalar, this gives a constant polynomial. If $t$ is a power series with non-negative valuation or a rational function, the effect is similar to \kbd{truncate}, i.e.~we chop off the $O(X^k)$ or compute the Euclidean quotient of the numerator by the denominator, then change the main variable of the result to $v$. The main use of this function is when $t$ is a vector: it creates the polynomial whose coefficients are given by $t$, with $t[1]$ being the leading coefficient (which can be zero). It is much faster to evaluate \kbd{Pol} on a vector of coefficients in this way, than the corresponding formal expression $a_n X^n + \dots + a_0$, which is evaluated naively exactly as written (linear versus quadratic time in $n$). \tet{Polrev} can be used if one wants $x[1]$ to be the constant coefficient: \bprog ? Pol([1,2,3]) %1 = x^2 + 2*x + 3 ? Polrev([1,2,3]) %2 = 3*x^2 + 2*x + 1 @eprog\noindent The reciprocal function of \kbd{Pol} (resp.~\kbd{Polrev}) is \kbd{Vec} (resp.~ \kbd{Vecrev}). \bprog ? Vec(Pol([1,2,3])) %1 = [1, 2, 3] ? Vecrev( Polrev([1,2,3]) ) %2 = [1, 2, 3] @eprog\noindent \misctitle{Warning} This is \emph{not} a substitution function. It will not transform an object containing variables of higher priority than~$v$. \bprog ? Pol(x + y, y) *** at top-level: Pol(x+y,y) *** ^---------- *** Pol: variable must have higher priority in gtopoly. @eprog The library syntax is \fun{GEN}{gtopoly}{GEN t, long v = -1} where \kbd{v} is a variable number. \subsec{Polrev$(t,\{v='x\})$}\kbdsidx{Polrev}\label{se:Polrev} Transform the object $t$ into a polynomial with main variable $v$. If $t$ is a scalar, this gives a constant polynomial. If $t$ is a power series, the effect is identical to \kbd{truncate}, i.e.~it chops off the $O(X^k)$. The main use of this function is when $t$ is a vector: it creates the polynomial whose coefficients are given by $t$, with $t[1]$ being the constant term. \tet{Pol} can be used if one wants $t[1]$ to be the leading coefficient: \bprog ? Polrev([1,2,3]) %1 = 3*x^2 + 2*x + 1 ? Pol([1,2,3]) %2 = x^2 + 2*x + 3 @eprog The reciprocal function of \kbd{Pol} (resp.~\kbd{Polrev}) is \kbd{Vec} (resp.~ \kbd{Vecrev}). The library syntax is \fun{GEN}{gtopolyrev}{GEN t, long v = -1} where \kbd{v} is a variable number. \subsec{Qfb$(a,b,c,\{D=0.\})$}\kbdsidx{Qfb}\label{se:Qfb} Creates the binary quadratic form\sidx{binary quadratic form} $ax^2+bxy+cy^2$. If $b^2-4ac>0$, initialize \idx{Shanks}' distance function to $D$. Negative definite forms are not implemented, use their positive definite counterpart instead. The library syntax is \fun{GEN}{Qfb0}{GEN a, GEN b, GEN c, GEN D = NULL, long prec}. Also available are \fun{GEN}{qfi}{GEN a, GEN b, GEN c} (assumes $b^2-4ac<0$) and \fun{GEN}{qfr}{GEN a, GEN b, GEN c, GEN D} (assumes $b^2-4ac>0$). \subsec{Ser$(s,\{v='x\},\{d=\var{seriesprecision}\})$}\kbdsidx{Ser}\label{se:Ser} Transforms the object $s$ into a power series with main variable $v$ ($x$ by default) and precision (number of significant terms) equal to $d \geq 0$ ($d = \kbd{seriesprecision}$ by default). If $s$ is a scalar, this gives a constant power series in $v$ with precision \kbd{d}. If $s$ is a polynomial, the polynomial is truncated to $d$ terms if needed \bprog ? \ps seriesprecision = 16 significant terms ? Ser(1) \\ 16 terms by default %1 = 1 + O(x^16) ? Ser(1, 'y, 5) %2 = 1 + O(y^5) ? Ser(x^2,, 5) %3 = x^2 + O(x^7) ? T = polcyclo(100) %4 = x^40 - x^30 + x^20 - x^10 + 1 ? Ser(T, 'x, 11) %5 = 1 - x^10 + O(x^11) @eprog\noindent The function is more or less equivalent with multiplication by $1 + O(v^d)$ in theses cases, only faster. For the remaining types, vectors and power series, we first explain what occurs if $d$ is omitted. In this case, the function uses exactly the amount of information given in the input: \item If $s$ is already a power series in $v$, we return it verbatim; \item If $s$ is a vector, the coefficients of the vector are understood to be the coefficients of the power series starting from the constant term (as in \tet{Polrev}$(x)$); in other words we convert \typ{VEC} / \typ{COL} to the power series whose significant terms are exactly given by the vector entries. On the other hand, if $d$ is explicitly given, we abide by its value and return a series, truncated or extended with zeros as needed, with $d$ significant terms. \bprog ? v = [1,2,3]; ? Ser(v, t) \\ 3 terms: seriesprecision is ignored! %7 = 1 + 2*t + 3*t^2 + O(t^3) ? Ser(v, t, 7) \\ 7 terms as explicitly requested %8 = 1 + 2*t + 3*t^2 + O(t^7) ? s = 1+x+O(x^2); ? Ser(s) %10 = 1 + x + O(x^2) \\ 2 terms: seriesprecision is ignored ? Ser(s, x, 7) \\ extend to 7 terms %11 = 1 + x + O(x^7) ? Ser(s, x, 1) \\ truncate to 1 term %12 = 1 + O(x) @eprog\noindent The warning given for \kbd{Pol} also applies here: this is not a substitution function. The library syntax is \fun{GEN}{Ser0}{GEN s, long v = -1, GEN d = NULL, long precdl} where \kbd{v} is a variable number. \subsec{Set$(\{x=[\,]\})$}\kbdsidx{Set}\label{se:Set} Converts $x$ into a set, i.e.~into a row vector, with strictly increasing entries with respect to the (somewhat arbitrary) universal comparison function \tet{cmp}. Standard container types \typ{VEC}, \typ{COL}, \typ{LIST} and \typ{VECSMALL} are converted to the set with corresponding elements. All others are converted to a set with one element. \bprog ? Set([1,2,4,2,1,3]) %1 = [1, 2, 3, 4] ? Set(x) %2 = [x] ? Set(Vecsmall([1,3,2,1,3])) %3 = [1, 2, 3] @eprog The library syntax is \fun{GEN}{gtoset}{GEN x = NULL}. \subsec{Str$(\{x\}*)$}\kbdsidx{Str}\label{se:Str} Converts its argument list into a single character string (type \typ{STR}, the empty string if $x$ is omitted). To recover an ordinary \kbd{GEN} from a string, apply \kbd{eval} to it. The arguments of \kbd{Str} are evaluated in string context, see \secref{se:strings}. \bprog ? x2 = 0; i = 2; Str(x, i) %1 = "x2" ? eval(%) %2 = 0 @eprog\noindent This function is mostly useless in library mode. Use the pair \tet{strtoGEN}/\tet{GENtostr} to convert between \kbd{GEN} and \kbd{char*}. The latter returns a malloced string, which should be freed after usage. %\syn{NO} \subsec{Strchr$(x)$}\kbdsidx{Strchr}\label{se:Strchr} Converts $x$ to a string, translating each integer into a character. \bprog ? Strchr(97) %1 = "a" ? Vecsmall("hello world") %2 = Vecsmall([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]) ? Strchr(%) %3 = "hello world" @eprog The library syntax is \fun{GEN}{Strchr}{GEN x}. \subsec{Strexpand$(\{x\}*)$}\kbdsidx{Strexpand}\label{se:Strexpand} Converts its argument list into a single character string (type \typ{STR}, the empty string if $x$ is omitted). Then perform \idx{environment expansion}, see \secref{se:envir}. This feature can be used to read \idx{environment variable} values. \bprog ? Strexpand("$HOME/doc") %1 = "/home/pari/doc" @eprog The individual arguments are read in string context, see \secref{se:strings}. %\syn{NO} \subsec{Strtex$(\{x\}*)$}\kbdsidx{Strtex}\label{se:Strtex} Translates its arguments to TeX format, and concatenates the results into a single character string (type \typ{STR}, the empty string if $x$ is omitted). The individual arguments are read in string context, see \secref{se:strings}. %\syn{NO} \subsec{Vec$(x, \{n\})$}\kbdsidx{Vec}\label{se:Vec} Transforms the object $x$ into a row vector. The dimension of the resulting vector can be optionally specified via the extra parameter $n$. If $n$ is omitted or $0$, the dimension depends on the type of $x$; the vector has a single component, except when $x$ is \item a vector or a quadratic form: returns the initial object considered as a row vector, \item a polynomial or a power series: returns a vector consisting of the coefficients. In the case of a polynomial, the coefficients of the vector start with the leading coefficient of the polynomial, while for power series only the significant coefficients are taken into account, but this time by increasing order of degree. In particular the valuation is ignored (which makes the function useful for series of negative valuation): \bprog ? Vec(3*x^2 + x) %1 = [3, 1, 0] ? Vec(x^2 + 3*x^3 + O(x^5)) %2 = [1, 3, 0] ? Vec(x^-2 + 3*x^-1 + O(x)) %3 = [1, 3, 0] @eprog\noindent \kbd{Vec} is the reciprocal function of \kbd{Pol} for a polynomial and of \kbd{Ser} for power series of valuation $0$. \item a matrix: returns the vector of columns comprising the matrix, \bprog ? m = [1,2,3;4,5,6] %4 = [1 2 3] [4 5 6] ? Vec(m) %5 = [[1, 4]~, [2, 5]~, [3, 6]~] @eprog \item a character string: returns the vector of individual characters, \bprog ? Vec("PARI") %6 = ["P", "A", "R", "I"] @eprog \item a map: returns the vector of the domain of the map, \item an error context (\typ{ERROR}): returns the error components, see \tet{iferr}. In the last four cases (matrix, character string, map, error), $n$ is meaningless and must be omitted or an error is raised. Otherwise, if $n$ is given, $0$ entries are appended at the end of the vector if $n > 0$, and prepended at the beginning if $n < 0$. The dimension of the resulting vector is $|n|$. This allows to write a conversion function for series that takes positive valuations into account: \bprog ? serVec(s) = Vec(s, -serprec(s,variable(s))); ? Vec(x^2 + 3*x^3 + O(x^5)) %2 = [0, 0, 1, 3, 0] @eprog (That function is not intended for series of negative valuation.) The library syntax is \fun{GEN}{gtovec0}{GEN x, long n}. \fun{GEN}{gtovec}{GEN x} is also available. \subsec{Vecrev$(x, \{n\})$}\kbdsidx{Vecrev}\label{se:Vecrev} As $\kbd{Vec}(x, -n)$, then reverse the result. In particular, \kbd{Vecrev} is the reciprocal function of \kbd{Polrev}: the coefficients of the vector start with the constant coefficient of the polynomial and the others follow by increasing degree. The library syntax is \fun{GEN}{gtovecrev0}{GEN x, long n}. \fun{GEN}{gtovecrev}{GEN x} is also available. \subsec{Vecsmall$(x, \{n\})$}\kbdsidx{Vecsmall}\label{se:Vecsmall} Transforms the object $x$ into a row vector of type \typ{VECSMALL}. The dimension of the resulting vector can be optionally specified via the extra parameter $n$. This acts as \kbd{Vec}$(x,n)$, but only on a limited set of objects: the result must be representable as a vector of small integers. If $x$ is a character string, a vector of individual characters in ASCII encoding is returned (\tet{Strchr} yields back the character string). The library syntax is \fun{GEN}{gtovecsmall0}{GEN x, long n}. \fun{GEN}{gtovecsmall}{GEN x} is also available. \subsec{binary$(x)$}\kbdsidx{binary}\label{se:binary} Outputs the vector of the binary digits of $|x|$. Here $x$ can be an integer, a real number (in which case the result has two components, one for the integer part, one for the fractional part) or a vector/matrix. \bprog ? binary(10) %1 = [1, 0, 1, 0] ? binary(3.14) %2 = [[1, 1], [0, 0, 1, 0, 0, 0, [...]] ? binary([1,2]) %3 = [[1], [1, 0]] @eprog\noindent By convention, $0$ has no digits: \bprog ? binary(0) %4 = [] @eprog The library syntax is \fun{GEN}{binaire}{GEN x}. \subsec{bitand$(x,y)$}\kbdsidx{bitand}\label{se:bitand} Bitwise \tet{and} \sidx{bitwise and}of two integers $x$ and $y$, that is the integer $$\sum_i (x_i~\kbd{and}~y_i) 2^i$$ Negative numbers behave $2$-adically, i.e.~the result is the $2$-adic limit of \kbd{bitand}$(x_n,y_n)$, where $x_n$ and $y_n$ are non-negative integers tending to $x$ and $y$ respectively. (The result is an ordinary integer, possibly negative.) \bprog ? bitand(5, 3) %1 = 1 ? bitand(-5, 3) %2 = 3 ? bitand(-5, -3) %3 = -7 @eprog The library syntax is \fun{GEN}{gbitand}{GEN x, GEN y}. Also available is \fun{GEN}{ibitand}{GEN x, GEN y}, which returns the bitwise \emph{and} of $|x|$ and $|y|$, two integers. \subsec{bitneg$(x,\{n=-1\})$}\kbdsidx{bitneg}\label{se:bitneg} \idx{bitwise negation} of an integer $x$, truncated to $n$ bits, $n\geq 0$, that is the integer $$\sum_{i=0}^{n-1} \kbd{not}(x_i) 2^i.$$ The special case $n=-1$ means no truncation: an infinite sequence of leading $1$ is then represented as a negative number. See \secref{se:bitand} for the behavior for negative arguments. The library syntax is \fun{GEN}{gbitneg}{GEN x, long n}. \subsec{bitnegimply$(x,y)$}\kbdsidx{bitnegimply}\label{se:bitnegimply} Bitwise negated imply of two integers $x$ and $y$ (or \kbd{not} $(x \Rightarrow y)$), that is the integer $$\sum (x_i~\kbd{and not}(y_i)) 2^i$$ See \secref{se:bitand} for the behavior for negative arguments. The library syntax is \fun{GEN}{gbitnegimply}{GEN x, GEN y}. Also available is \fun{GEN}{ibitnegimply}{GEN x, GEN y}, which returns the bitwise negated imply of $|x|$ and $|y|$, two integers. \subsec{bitor$(x,y)$}\kbdsidx{bitor}\label{se:bitor} \sidx{bitwise inclusive or}bitwise (inclusive) \tet{or} of two integers $x$ and $y$, that is the integer $$\sum (x_i~\kbd{or}~y_i) 2^i$$ See \secref{se:bitand} for the behavior for negative arguments. The library syntax is \fun{GEN}{gbitor}{GEN x, GEN y}. Also available is \fun{GEN}{ibitor}{GEN x, GEN y}, which returns the bitwise \emph{ir} of $|x|$ and $|y|$, two integers. \subsec{bitprecision$(x,\{n\})$}\kbdsidx{bitprecision}\label{se:bitprecision} The function behaves differently according to whether $n$ is present and positive or not. If $n$ is missing, the function returns the (floating point) precision in bits of the PARI object $x$. If $x$ is an exact object, the function returns \kbd{+oo}. \bprog ? bitprecision(exp(1e-100)) %1 = 512 \\ 512 bits ? bitprecision( [ exp(1e-100), 0.5 ] ) %2 = 128 \\ minimal accuracy among components ? bitprecision(2 + x) %3 = +oo \\ exact object @eprog If $n$ is present and positive, the function creates a new object equal to $x$ with the new bit-precision roughly $n$. In fact, the smallest multiple of 64 (resp.~32 on a 32-bit machine) larger than or equal to $n$. For $x$ a vector or a matrix, the operation is done componentwise; for series and polynomials, the operation is done coefficientwise. For real $x$, $n$ is the number of desired significant \emph{bits}. If $n$ is smaller than the precision of $x$, $x$ is truncated, otherwise $x$ is extended with zeros. For exact or non-floating point types, no change. \bprog ? bitprecision(Pi, 10) \\ actually 64 bits ~ 19 decimal digits %1 = 3.141592653589793239 ? bitprecision(1, 10) %2 = 1 ? bitprecision(1 + O(x), 10) %3 = 1 + O(x) ? bitprecision(2 + O(3^5), 10) %4 = 2 + O(3^5) @eprog\noindent The library syntax is \fun{GEN}{bitprecision0}{GEN x, long n}. \subsec{bittest$(x,n)$}\kbdsidx{bittest}\label{se:bittest} Outputs the $n^{\text{th}}$ bit of $x$ starting from the right (i.e.~the coefficient of $2^n$ in the binary expansion of $x$). The result is 0 or 1. \bprog ? bittest(7, 0) %1 = 1 \\ the bit 0 is 1 ? bittest(7, 2) %2 = 1 \\ the bit 2 is 1 ? bittest(7, 3) %3 = 0 \\ the bit 3 is 0 @eprog\noindent See \secref{se:bitand} for the behavior at negative arguments. The library syntax is \fun{GEN}{gbittest}{GEN x, long n}. For a \typ{INT} $x$, the variant \fun{long}{bittest}{GEN x, long n} is generally easier to use, and if furthermore $n\ge 0$ the low-level function \fun{ulong}{int_bit}{GEN x, long n} returns \kbd{bittest(abs(x),n)}. \subsec{bitxor$(x,y)$}\kbdsidx{bitxor}\label{se:bitxor} Bitwise (exclusive) \tet{or} \sidx{bitwise exclusive or}of two integers $x$ and $y$, that is the integer $$\sum (x_i~\kbd{xor}~y_i) 2^i$$ See \secref{se:bitand} for the behavior for negative arguments. The library syntax is \fun{GEN}{gbitxor}{GEN x, GEN y}. Also available is \fun{GEN}{ibitxor}{GEN x, GEN y}, which returns the bitwise \emph{xor} of $|x|$ and $|y|$, two integers. \subsec{ceil$(x)$}\kbdsidx{ceil}\label{se:ceil} Ceiling of $x$. When $x$ is in $\R$, the result is the smallest integer greater than or equal to $x$. Applied to a rational function, $\kbd{ceil}(x)$ returns the Euclidean quotient of the numerator by the denominator. The library syntax is \fun{GEN}{gceil}{GEN x}. \subsec{centerlift$(x,\{v\})$}\kbdsidx{centerlift}\label{se:centerlift} Same as \tet{lift}, except that \typ{INTMOD} and \typ{PADIC} components are lifted using centered residues: \item for a \typ{INTMOD} $x\in \Z/n\Z$, the lift $y$ is such that $-n/20$), the result is undefined and an error occurs if $e$ was not given. \misctitle{Important remark} Contrary to the other truncation functions, this function operates on every coefficient at every level of a PARI object. For example $$\text{truncate}\left(\dfrac{2.4*X^2-1.7}{X}\right)=2.4*X,$$ whereas $$\text{round}\left(\dfrac{2.4*X^2-1.7}{X}\right)=\dfrac{2*X^2-2}{X}.$$ An important use of \kbd{round} is to get exact results after an approximate computation, when theory tells you that the coefficients must be integers. The library syntax is \fun{GEN}{round0}{GEN x, GEN *e = NULL}. Also available are \fun{GEN}{grndtoi}{GEN x, long *e} and \fun{GEN}{ground}{GEN x}. \subsec{serchop$(s,\{n=0\})$}\kbdsidx{serchop}\label{se:serchop} Remove all terms of degree strictly less than $n$ in series $s$. When the series contains no terms of degree $< n$, return $O(x^n)$. \bprog ? s = 1/x + x + 2*x^2 + O(x^3); ? serchop(s) %2 = x + 2*x^3 + O(x^3) ? serchop(s, 2) %3 = 2*x^2 + O(x^3) ? serchop(s, 100) %4 = O(x^100) @eprog The library syntax is \fun{GEN}{serchop}{GEN s, long n}. \subsec{serprec$(x,v)$}\kbdsidx{serprec}\label{se:serprec} Returns the absolute precision of $x$ with respect to power series in the variable $v$; this is the minimum precision of the components of $x$. The result is \tet{+oo} if $x$ is an exact object (as a series in $v$): \bprog ? serprec(x + O(y^2), y) %1 = 2 ? serprec(x + 2, x) %2 = +oo ? serprec(2 + x + O(x^2), y) %3 = +oo @eprog The library syntax is \fun{GEN}{gpserprec}{GEN x, long v} where \kbd{v} is a variable number. Also available is \fun{long}{serprec}{GEN x, GEN p}, which returns \tet{LONG_MAX} if $x = 0$, otherwise the series precision as a \kbd{long} integer. \subsec{simplify$(x)$}\kbdsidx{simplify}\label{se:simplify} This function simplifies $x$ as much as it can. Specifically, a complex or quadratic number whose imaginary part is the integer 0 (i.e.~not \kbd{Mod(0,2)} or \kbd{0.E-28}) is converted to its real part, and a polynomial of degree $0$ is converted to its constant term. Simplifications occur recursively. This function is especially useful before using arithmetic functions, which expect integer arguments: \bprog ? x = 2 + y - y %1 = 2 ? isprime(x) *** at top-level: isprime(x) *** ^---------- *** isprime: not an integer argument in an arithmetic function ? type(x) %2 = "t_POL" ? type(simplify(x)) %3 = "t_INT" @eprog Note that GP results are simplified as above before they are stored in the history. (Unless you disable automatic simplification with \b{y}, that is.) In particular \bprog ? type(%1) %4 = "t_INT" @eprog The library syntax is \fun{GEN}{simplify}{GEN x}. \subsec{sizebyte$(x)$}\kbdsidx{sizebyte}\label{se:sizebyte} Outputs the total number of bytes occupied by the tree representing the PARI object $x$. The library syntax is \fun{long}{gsizebyte}{GEN x}. Also available is \fun{long}{gsizeword}{GEN x} returning a number of \emph{words}. \subsec{sizedigit$(x)$}\kbdsidx{sizedigit}\label{se:sizedigit} This function is DEPRECATED, essentially meaningless, and provided for backwards compatibility only. Don't use it! outputs a quick upper bound for the number of decimal digits of (the components of) $x$, off by at most $1$. More precisely, for a positive integer $x$, it computes (approximately) the ceiling of $$\kbd{floor}(1 + \log_2 x) \log_{10}2,$$ To count the number of decimal digits of a positive integer $x$, use \kbd{\#digits(x)}. To estimate (recursively) the size of $x$, use \kbd{normlp(x)}. The library syntax is \fun{long}{sizedigit}{GEN x}. \subsec{truncate$(x,\{\&e\})$}\kbdsidx{truncate}\label{se:truncate} Truncates $x$ and sets $e$ to the number of error bits. When $x$ is in $\R$, this means that the part after the decimal point is chopped away, $e$ is the binary exponent of the difference between the original and the truncated value (the ``fractional part''). If the exponent of $x$ is too large compared to its precision (i.e.~$e>0$), the result is undefined and an error occurs if $e$ was not given. The function applies componentwise on vector / matrices; $e$ is then the maximal number of error bits. If $x$ is a rational function, the result is the ``integer part'' (Euclidean quotient of numerator by denominator) and $e$ is not set. Note a very special use of \kbd{truncate}: when applied to a power series, it transforms it into a polynomial or a rational function with denominator a power of $X$, by chopping away the $O(X^k)$. Similarly, when applied to a $p$-adic number, it transforms it into an integer or a rational number by chopping away the $O(p^k)$. The library syntax is \fun{GEN}{trunc0}{GEN x, GEN *e = NULL}. The following functions are also available: \fun{GEN}{gtrunc}{GEN x} and \fun{GEN}{gcvtoi}{GEN x, long *e}. \subsec{valuation$(x,p)$}\kbdsidx{valuation}\label{se:valuation} Computes the highest exponent of $p$ dividing $x$. If $p$ is of type integer, $x$ must be an integer, an intmod whose modulus is divisible by $p$, a fraction, a $q$-adic number with $q=p$, or a polynomial or power series in which case the valuation is the minimum of the valuation of the coefficients. If $p$ is of type polynomial, $x$ must be of type polynomial or rational function, and also a power series if $x$ is a monomial. Finally, the valuation of a vector, complex or quadratic number is the minimum of the component valuations. If $x=0$, the result is \kbd{+oo} if $x$ is an exact object. If $x$ is a $p$-adic numbers or power series, the result is the exponent of the zero. Any other type combinations gives an error. The library syntax is \fun{GEN}{gpvaluation}{GEN x, GEN p}. Also available is \fun{long}{gvaluation}{GEN x, GEN p}, which returns \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer. \subsec{varhigher$(\var{name},\{v\})$}\kbdsidx{varhigher}\label{se:varhigher} Return a variable \emph{name} whose priority is higher than the priority of $v$ (of all existing variables if $v$ is omitted). This is a counterpart to \tet{varlower}. \bprog ? Pol([x,x], t) *** at top-level: Pol([x,x],t) *** ^------------ *** Pol: incorrect priority in gtopoly: variable x <= t ? t = varhigher("t", x); ? Pol([x,x], t) %3 = x*t + x @eprog\noindent This routine is useful since new GP variables directly created by the interpreter always have lower priority than existing GP variables. When some basic objects already exist in a variable that is incompatible with some function requirement, you can now create a new variable with a suitable priority instead of changing variables in existing objects: \bprog ? K = nfinit(x^2+1); ? rnfequation(K,y^2-2) *** at top-level: rnfequation(K,y^2-2) *** ^-------------------- *** rnfequation: incorrect priority in rnfequation: variable y >= x ? y = varhigher("y", x); ? rnfequation(K, y^2-2) %3 = y^4 - 2*y^2 + 9 @eprog\noindent \misctitle{Caution 1} The \emph{name} is an arbitrary character string, only used for display purposes and need not be related to the GP variable holding the result, nor to be a valid variable name. In particular the \emph{name} can not be used to retrieve the variable, it is not even present in the parser's hash tables. \bprog ? x = varhigher("#"); ? x^2 %2 = #^2 @eprog \misctitle{Caution 2} There are a limited number of variables and if no existing variable with the given display name has the requested priority, the call to \kbd{varhigher} uses up one such slot. Do not create new variables in this way unless it's absolutely necessary, reuse existing names instead and choose sensible priority requirements: if you only need a variable with higher priority than $x$, state so rather than creating a new variable with highest priority. \bprog \\ quickly use up all variables ? n = 0; while(1,varhigher("tmp"); n++) *** at top-level: n=0;while(1,varhigher("tmp");n++) *** ^------------------- *** varhigher: no more variables available. *** Break loop: type 'break' to go back to GP prompt break> n 65510 \\ infinite loop: here we reuse the same 'tmp' ? n = 0; while(1,varhigher("tmp", x); n++) @eprog The library syntax is \fun{GEN}{varhigher}{const char *name, long v = -1} where \kbd{v} is a variable number. \subsec{variable$(\{x\})$}\kbdsidx{variable}\label{se:variable} Gives the main variable of the object $x$ (the variable with the highest priority used in $x$), and $p$ if $x$ is a $p$-adic number. Return $0$ if $x$ has no variable attached to it. \bprog ? variable(x^2 + y) %1 = x ? variable(1 + O(5^2)) %2 = 5 ? variable([x,y,z,t]) %3 = x ? variable(1) %4 = 0 @eprog\noindent The construction \bprog if (!variable(x),...) @eprog\noindent can be used to test whether a variable is attached to $x$. If $x$ is omitted, returns the list of user variables known to the interpreter, by order of decreasing priority. (Highest priority is initially $x$, which come first until \tet{varhigher} is used.) If \kbd{varhigher} or \kbd{varlower} are used, it is quite possible to end up with different variables (with different priorities) printed in the same way: they will then appear multiple times in the output: \bprog ? varhigher("y"); ? varlower("y"); ? variable() %4 = [y, x, y] @eprog\noindent Using \kbd{v = variable()} then \kbd{v[1]}, \kbd{v[2]}, etc.~allows to recover and use existing variables. The library syntax is \fun{GEN}{gpolvar}{GEN x = NULL}. However, in library mode, this function should not be used for $x$ non-\kbd{NULL}, since \tet{gvar} is more appropriate. Instead, for $x$ a $p$-adic (type \typ{PADIC}), $p$ is $gel(x,2)$; otherwise, use \fun{long}{gvar}{GEN x} which returns the variable number of $x$ if it exists, \kbd{NO\_VARIABLE} otherwise, which satisfies the property $\kbd{varncmp}(\kbd{NO\_VARIABLE}, v) > 0$ for all valid variable number $v$, i.e. it has lower priority than any variable. \subsec{variables$(\{x\})$}\kbdsidx{variables}\label{se:variables} Returns the list of all variables occuring in object $x$ (all user variables known to the interpreter if $x$ is omitted), sorted by decreasing priority. \bprog ? variables([x^2 + y*z + O(t), a+x]) %1 = [x, y, z, t, a] @eprog\noindent The construction \bprog if (!variables(x),...) @eprog\noindent can be used to test whether a variable is attached to $x$. If \kbd{varhigher} or \kbd{varlower} are used, it is quite possible to end up with different variables (with different priorities) printed in the same way: they will then appear multiple times in the output: \bprog ? y1 = varhigher("y"); ? y2 = varlower("y"); ? variables(y*y1*y2) %4 = [y, y, y] @eprog The library syntax is \fun{GEN}{variables_vec}{GEN x = NULL}. Also available is \fun{GEN}{variables_vecsmall}{GEN x} which returns the (sorted) variable numbers instead of the attached monomials of degree 1. \subsec{varlower$(\var{name},\{v\})$}\kbdsidx{varlower}\label{se:varlower} Return a variable \emph{name} whose priority is lower than the priority of $v$ (of all existing variables if $v$ is omitted). This is a counterpart to \tet{varhigher}. New GP variables directly created by the interpreter always have lower priority than existing GP variables, but it is not easy to check whether an identifier is currently unused, so that the corresponding variable has the expected priority when it's created! Thus, depending on the session history, the same command may fail or succeed: \bprog ? t; z; \\ now t > z ? rnfequation(t^2+1,z^2-t) *** at top-level: rnfequation(t^2+1,z^ *** ^-------------------- *** rnfequation: incorrect priority in rnfequation: variable t >= t @eprog\noindent Restart and retry: \bprog ? z; t; \\ now z > t ? rnfequation(t^2+1,z^2-t) %2 = z^4 + 1 @eprog\noindent It is quite annoying for package authors, when trying to define a base ring, to notice that the package may fail for some users depending on their session history. The safe way to do this is as follows: \bprog ? z; t; \\ In new session: now z > t ... ? t = varlower("t", 'z); ? rnfequation(t^2+1,z^2-2) %2 = z^4 - 2*z^2 + 9 ? variable() %3 = [x, y, z, t] @eprog \bprog ? t; z; \\ In new session: now t > z ... ? t = varlower("t", 'z); \\ create a new variable, still printed "t" ? rnfequation(t^2+1,z^2-2) %2 = z^4 - 2*z^2 + 9 ? variable() %3 = [x, y, t, z, t] @eprog\noindent Now both constructions succeed. Note that in the first case, \kbd{varlower} is essentially a no-op, the existing variable $t$ has correct priority. While in the second case, two different variables are displayed as \kbd{t}, one with higher priority than $z$ (created in the first line) and another one with lower priority (created by \kbd{varlower}). \misctitle{Caution 1} The \emph{name} is an arbitrary character string, only used for display purposes and need not be related to the GP variable holding the result, nor to be a valid variable name. In particular the \emph{name} can not be used to retrieve the variable, it is not even present in the parser's hash tables. \bprog ? x = varlower("#"); ? x^2 %2 = #^2 @eprog \misctitle{Caution 2} There are a limited number of variables and if no existing variable with the given display name has the requested priority, the call to \kbd{varlower} uses up one such slot. Do not create new variables in this way unless it's absolutely necessary, reuse existing names instead and choose sensible priority requirements: if you only need a variable with higher priority than $x$, state so rather than creating a new variable with highest priority. \bprog \\ quickly use up all variables ? n = 0; while(1,varlower("x"); n++) *** at top-level: n=0;while(1,varlower("x");n++) *** ^------------------- *** varlower: no more variables available. *** Break loop: type 'break' to go back to GP prompt break> n 65510 \\ infinite loop: here we reuse the same 'tmp' ? n = 0; while(1,varlower("tmp", x); n++) @eprog The library syntax is \fun{GEN}{varlower}{const char *name, long v = -1} where \kbd{v} is a variable number. \section{Combinatorics}\label{se:combinat} Permutations are represented in gp as \typ{VECSMALL}s and can be input directly as \kbd{Vecsmall([1,3,2,4])} or obtained from the iterator \kbd{forperm}: \bprog ? forperm(3, p, print(p)) \\ iterate through S_3 Vecsmall([1, 2, 3]) Vecsmall([1, 3, 2]) Vecsmall([2, 1, 3]) Vecsmall([2, 3, 1]) Vecsmall([3, 1, 2]) Vecsmall([3, 2, 1]) @eprog Permutations can be multiplied via \kbd{*}, raised to some power using \kbd{\pow}, inverted using \kbd{\pow(-1)}, conjugated as \kbd{p * q * p\pow(-1)}. Their order and signature is available via \kbd{permorder} and \kbd{permsign}. \subsec{binomial$(x,\{k\})$}\kbdsidx{binomial}\label{se:binomial} \idx{binomial coefficient} $\binom{x}{k}$. Here $k$ must be an integer, but $x$ can be any PARI object. \bprog ? binomial(4,2) %1 = 6 ? n = 4; vector(n+1, k, binomial(n,k-1)) %2 = [1, 4, 6, 4, 1] @eprog\noindent The argument $k$ may be omitted if $x = n$ is a non-negative integer; in this case, return the vector with $n+1$ components whose $k+1$-th entry is \kbd{binomial}$(n,k)$ \bprog ? binomial(4) %3 = [1, 4, 6, 4, 1] @eprog The library syntax is \fun{GEN}{binomial0}{GEN x, GEN k = NULL}. \subsec{fibonacci$(x)$}\kbdsidx{fibonacci}\label{se:fibonacci} $x^{\text{th}}$ Fibonacci number. The library syntax is \fun{GEN}{fibo}{long x}. \subsec{hammingweight$(x)$}\kbdsidx{hammingweight}\label{se:hammingweight} If $x$ is a \typ{INT}, return the binary Hamming weight of $|x|$. Otherwise $x$ must be of type \typ{POL}, \typ{VEC}, \typ{COL}, \typ{VECSMALL}, or \typ{MAT} and the function returns the number of non-zero coefficients of $x$. \bprog ? hammingweight(15) %1 = 4 ? hammingweight(x^100 + 2*x + 1) %2 = 3 ? hammingweight([Mod(1,2), 2, Mod(0,3)]) %3 = 2 ? hammingweight(matid(100)) %4 = 100 @eprog The library syntax is \fun{long}{hammingweight}{GEN x}. \subsec{numbpart$(n)$}\kbdsidx{numbpart}\label{se:numbpart} Gives the number of unrestricted partitions of $n$, usually called $p(n)$ in the literature; in other words the number of nonnegative integer solutions to $a+2b+3c+\cdots=n$. $n$ must be of type integer and $n<10^{15}$ (with trivial values $p(n) = 0$ for $n < 0$ and $p(0) = 1$). The algorithm uses the Hardy-Ramanujan-Rademacher formula. To explicitly enumerate them, see \tet{partitions}. The library syntax is \fun{GEN}{numbpart}{GEN n}. \subsec{numtoperm$(n,k)$}\kbdsidx{numtoperm}\label{se:numtoperm} Generates the $k$-th permutation (as a row vector of length $n$) of the numbers $1$ to $n$. The number $k$ is taken modulo $n!\,$, i.e.~inverse function of \tet{permtonum}. The numbering used is the standard lexicographic ordering, starting at $0$. The library syntax is \fun{GEN}{numtoperm}{long n, GEN k}. \subsec{partitions$(k,\{a=k\},\{n=k\})$}\kbdsidx{partitions}\label{se:partitions} Returns the vector of partitions of the integer $k$ as a sum of positive integers (parts); for $k < 0$, it returns the empty set \kbd{[]}, and for $k = 0$ the trivial partition (no parts). A partition is given by a \typ{VECSMALL}, where parts are sorted in nondecreasing order: \bprog ? partitions(3) %1 = [Vecsmall([3]), Vecsmall([1, 2]), Vecsmall([1, 1, 1])] @eprog\noindent correspond to $3$, $1+2$ and $1+1+1$. The number of (unrestricted) partitions of $k$ is given by \tet{numbpart}: \bprog ? #partitions(50) %1 = 204226 ? numbpart(50) %2 = 204226 @eprog \noindent Optional parameters $n$ and $a$ are as follows: \item $n=\var{nmax}$ (resp. $n=[\var{nmin},\var{nmax}]$) restricts partitions to length less than $\var{nmax}$ (resp. length between $\var{nmin}$ and $nmax$), where the \emph{length} is the number of nonzero entries. \item $a=\var{amax}$ (resp. $a=[\var{amin},\var{amax}]$) restricts the parts to integers less than $\var{amax}$ (resp. between $\var{amin}$ and $\var{amax}$). \bprog ? partitions(4, 2) \\ parts bounded by 2 %1 = [Vecsmall([2, 2]), Vecsmall([1, 1, 2]), Vecsmall([1, 1, 1, 1])] ? partitions(4,, 2) \\ at most 2 parts %2 = [Vecsmall([4]), Vecsmall([1, 3]), Vecsmall([2, 2])] ? partitions(4,[0,3], 2) \\ at most 2 parts %3 = [Vecsmall([4]), Vecsmall([1, 3]), Vecsmall([2, 2])] @eprog\noindent By default, parts are positive and we remove zero entries unless $amin\leq0$, in which case $nmin$ is ignored and we fix $\#X = \var{nmax}$: \bprog ? partitions(4, [0,3]) \\ parts between 0 and 3 %1 = [Vecsmall([0, 0, 1, 3]), Vecsmall([0, 0, 2, 2]),\ Vecsmall([0, 1, 1, 2]), Vecsmall([1, 1, 1, 1])] ? partitions(1, [0,3], [2,4]) \\ no partition with 2 to 4 non-zero parts %2 = [] @eprog The library syntax is \fun{GEN}{partitions}{long k, GEN a = NULL, GEN n = NULL}. \subsec{permorder$(x)$}\kbdsidx{permorder}\label{se:permorder} Given a permutation $x$ on $n$ elements, return its order. \bprog ? p = Vecsmall([3,1,4,2,5]); ? p^2 %2 = Vecsmall([4,3,2,1,5]) ? p^4 %3 = Vecsmall([1,2,3,4,5]) ? permorder(p) %4 = 4 @eprog The library syntax is \fun{long}{permorder}{GEN x}. \subsec{permsign$(x)$}\kbdsidx{permsign}\label{se:permsign} Given a permutation $x$ on $n$ elements, return its signature. \bprog ? p = Vecsmall([3,1,4,2,5]); ? permsign(p) %2 = -1 ? permsign(p^2) %3 = 1 @eprog The library syntax is \fun{long}{permsign}{GEN x}. \subsec{permtonum$(x)$}\kbdsidx{permtonum}\label{se:permtonum} Given a permutation $x$ on $n$ elements, gives the number $k$ such that $x=\kbd{numtoperm(n,k)}$, i.e.~inverse function of \tet{numtoperm}. The numbering used is the standard lexicographic ordering, starting at $0$. The library syntax is \fun{GEN}{permtonum}{GEN x}. \subsec{stirling$(n,k,\{\fl=1\})$}\kbdsidx{stirling}\label{se:stirling} \idx{Stirling number} of the first kind $s(n,k)$ ($\fl=1$, default) or of the second kind $S(n,k)$ (\fl=2), where $n$, $k$ are non-negative integers. The former is $(-1)^{n-k}$ times the number of permutations of $n$ symbols with exactly $k$ cycles; the latter is the number of ways of partitioning a set of $n$ elements into $k$ non-empty subsets. Note that if all $s(n,k)$ are needed, it is much faster to compute $$\sum_k s(n,k) x^k = x(x-1)\dots(x-n+1).$$ Similarly, if a large number of $S(n,k)$ are needed for the same $k$, one should use $$\sum_n S(n,k) x^n = \dfrac{x^k}{(1-x)\dots(1-kx)}.$$ (Should be implemented using a divide and conquer product.) Here are simple variants for $n$ fixed: \bprog /* list of s(n,k), k = 1..n */ vecstirling(n) = Vec( factorback(vector(n-1,i,1-i*'x)) ) /* list of S(n,k), k = 1..n */ vecstirling2(n) = { my(Q = x^(n-1), t); vector(n, i, t = divrem(Q, x-i); Q=t[1]; simplify(t[2])); } /* Bell numbers, B_n = B[n+1] = sum(k = 0, n, S(n,k)), n = 0..N */ vecbell(N)= { my (B = vector(N+1)); B[1] = B[2] = 1; for (n = 2, N, my (C = binomial(n-1)); B[n+1] = sum(k = 1, n, C[k]*B[k]); ); B; } @eprog The library syntax is \fun{GEN}{stirling}{long n, long k, long flag}. Also available are \fun{GEN}{stirling1}{ulong n, ulong k} ($\fl=1$) and \fun{GEN}{stirling2}{ulong n, ulong k} ($\fl=2$). \section{Arithmetic functions}\label{se:arithmetic} These functions are by definition functions whose natural domain of definition is either $\Z$ (or $\Z_{>0}$). The way these functions are used is completely different from transcendental functions in that there are no automatic type conversions: in general only integers are accepted as arguments. An integer argument $N$ can be given in the following alternate formats: \item \typ{MAT}: its factorization \kbd{fa = factor($N$)}, \item \typ{VEC}: a pair \kbd{[$N$, fa]} giving both the integer and its factorization. This allows to compute different arithmetic functions at a given $N$ while factoring the latter only once. \bprog ? N = 10!; faN = factor(N); ? eulerphi(N) %2 = 829440 ? eulerphi(faN) %3 = 829440 ? eulerphi(S = [N, faN]) %4 = 829440 ? sigma(S) %5 = 15334088 @eprog \subsec{Arithmetic functions and the factoring engine} All arithmetic functions in the narrow sense of the word~--- Euler's totient\sidx{Euler totient function} function, the \idx{Moebius} function, the sums over divisors or powers of divisors etc.--- call, after trial division by small primes, the same versatile factoring machinery described under \kbd{factorint}. It includes \idx{Shanks SQUFOF}, \idx{Pollard Rho}, \idx{ECM} and \idx{MPQS} stages, and has an early exit option for the functions \teb{moebius} and (the integer function underlying) \teb{issquarefree}. This machinery relies on a fairly strong probabilistic primality test, see \kbd{ispseudoprime}, but you may also set \bprog default(factor_proven, 1) @eprog\noindent to ensure that all tentative factorizations are fully proven. This should not slow down PARI too much, unless prime numbers with hundreds of decimal digits occur frequently in your application. \subsec{Orders in finite groups and Discrete Logarithm functions} \label{se:DLfun} The following functions compute the order of an element in a finite group: \kbd{ellorder} (the rational points on an elliptic curve defined over a finite field), \kbd{fforder} (the multiplicative group of a finite field), \kbd{znorder} (the invertible elements in $\Z/n\Z$). The following functions compute discrete logarithms in the same groups (whenever this is meaningful) \kbd{elllog}, \kbd{fflog}, \kbd{znlog}. All such functions allow an optional argument specifying an integer $N$, representing the order of the group. (The \emph{order} functions also allows any non-zero multiple of the order, with a minor loss of efficiency.) That optional argument follows the same format as given above: \item \typ{INT}: the integer $N$, \item \typ{MAT}: the factorization \kbd{fa = factor($N$)}, \item \typ{VEC}: this is the preferred format and provides both the integer $N$ and its factorization in a two-component vector \kbd{[$N$, fa]}. When the group is fixed and many orders or discrete logarithms will be computed, it is much more efficient to initialize this data once and for all and pass it to the relevant functions, as in \bprog ? p = nextprime(10^40); ? v = [p-1, factor(p-1)]; \\ data for discrete log & order computations ? znorder(Mod(2,p), v) %3 = 500000000000000000000000000028 ? g = znprimroot(p); ? znlog(2, g, v) %5 = 543038070904014908801878611374 @eprog \subsec{Dirichlet characters}\label{se:dirichletchar} The finite abelian group $G = (\Z/N\Z)^*$ can be written $G = \oplus_{i\leq n} (\Z/d_i\Z) g_i$, with $d_n \mid \dots \mid d_2 \mid d_1$ (SNF condition), all $d_i > 0$, and $\prod_i d_i = \phi(N)$. The SNF condition makes the $d_i$ unique, but the generators $g_i$, of respective order $d_i$, are definitely not unique. The $\oplus$ notation means that all elements of $G$ can be written uniquely as $\prod_i g_i^{n_i}$ where $n_i \in \Z/d_i\Z$. The $g_i$ are the so-called \tev{SNF generators} of $G$. \item a \tev{character} on the abelian group $\oplus (\Z/d_j\Z) g_j$ is given by a row vector $\chi = [a_1,\ldots,a_n]$ of integers $0\leq a_i < d_i$ such that $\chi(g_j) = e(a_j / d_j)$ for all $j$, with the standard notation $e(x) := \exp(2i\pi x)$. In other words, $\chi(\prod g_j^{n_j}) = e(\sum a_j n_j / d_j)$. This will be generalized to more general abelian groups in later sections (Hecke characters), but in the present case of $(\Z/N\Z)^*$, there is a useful alternate convention : namely, it is not necessary to impose the SNF condition and we can use Chinese reminders instead. If $N = \prod p^{e_p}$ is the factorization of $N$ into primes, the so-called \tev{Conrey generators} of $G$ are the generators of the $(\Z/p^{e_p}\Z)^*$ lifted to $(\Z/N\Z)^*$ by requesting that they be congruent to $1$ modulo $N/p^{e_p}$ (for $p$ odd we take the smallest positive primitive root mod $p^2$, and for $p = 2$ we take $-1$ if $e_2 > 1$ and additionally $5$ if $e_2 > 2$). We can again write $G = \oplus_{i\leq n} (\Z/D_i\Z) G_i$, where again $\prod_i D_i = \phi(N)$. These generators don't satisfy the SNF condition in general since their orders are now $(p-1)p^{e_p-1}$ for $p$ odd; for $p = 2$, the generator $-1$ has order $2$ and $5$ has order $2^{e_2-2}$ $(e_2 > 2)$. Nevertheless, any $m\in (\Z/N\Z)^*$ can be uniquely decomposed as $\prod G_i^{m_i}$ for some $m_i$ modulo $D_i$ and we can define a character by $\chi(G_j) = e(m_j / D_j)$ for all $j$. \item The \emph{column vector} of the $m_j$, $0 \leq m_j < D_j$ is called the \tev{Conrey logarithm} of $m$ (discrete logarithm in terms of the Conrey generators). Note that discrete logarithms in PARI/GP are always expressed as \typ{COL}s. \item The attached character is called the \tev{Conrey character} attached to $m$. To sum up a Dirichlet character can be defined by a \typ{INT} (the Conrey label $m$), a \typ{COL} (the Conrey logarithm of $m$, in terms of the Conrey generators) or a \typ{VEC} (in terms of the SNF generators). The \typ{COL} format, i.e. Conrey logarithms, is the preferred (fastest) representation. Concretely, this works as follows: \kbd{G = znstar(N, 1)} initializes $(\Z/N\Z)^*$, which must be given as first arguments to all functions handling Dirichlet characters. \kbd{znconreychar} transforms \typ{INT} and \typ{COL} to a SNF character. \kbd{znconreylog} transforms \typ{INT} and \typ{VEC} to a Conrey logarithm. \kbd{znconreyexp} transforms \typ{VEC} and \typ{COL} to a Conrey label. Also available are \kbd{charconj}, \kbd{chardiv}, \kbd{charmul}, \kbd{charker}, \kbd{chareval}, \kbd{charorder}, \kbd{zncharinduce}, \kbd{znconreyconductor} (also computes the primitive character attached to the input character). The prefix \kbd{char} indicates that the function applies to all characters, the prefix \kbd{znchar} that it is specific to Dirichlet characters (on $(\Z/N\Z)^*$) and the prefix \kbd{znconrey} that it is specific to Conrey representation. \subsec{addprimes$(\{x=[\,]\})$}\kbdsidx{addprimes}\label{se:addprimes} Adds the integers contained in the vector $x$ (or the single integer $x$) to a special table of ``user-defined primes'', and returns that table. Whenever \kbd{factor} is subsequently called, it will trial divide by the elements in this table. If $x$ is empty or omitted, just returns the current list of extra primes. The entries in $x$ must be primes: there is no internal check, even if the \tet{factor_proven} default is set. To remove primes from the list use \kbd{removeprimes}. The library syntax is \fun{GEN}{addprimes}{GEN x = NULL}. \subsec{bestappr$(x, \{B\})$}\kbdsidx{bestappr}\label{se:bestappr} Using variants of the extended Euclidean algorithm, returns a rational approximation $a/b$ to $x$, whose denominator is limited by $B$, if present. If $B$ is omitted, return the best approximation affordable given the input accuracy; if you are looking for true rational numbers, presumably approximated to sufficient accuracy, you should first try that option. Otherwise, $B$ must be a positive real scalar (impose $0 < b \leq B$). \item If $x$ is a \typ{REAL} or a \typ{FRAC}, this function uses continued fractions. \bprog ? bestappr(Pi, 100) %1 = 22/7 ? bestappr(0.1428571428571428571428571429) %2 = 1/7 ? bestappr([Pi, sqrt(2) + 'x], 10^3) %3 = [355/113, x + 1393/985] @eprog By definition, $a/b$ is the best rational approximation to $x$ if $|b x - a| < |v x - u|$ for all integers $(u,v)$ with $0 < v \leq B$. (Which implies that $n/d$ is a convergent of the continued fraction of $x$.) \item If $x$ is a \typ{INTMOD} modulo $N$ or a \typ{PADIC} of precision $N = p^k$, this function performs rational modular reconstruction modulo $N$. The routine then returns the unique rational number $a/b$ in coprime integers $|a| < N/2B$ and $b\leq B$ which is congruent to $x$ modulo $N$. Omitting $B$ amounts to choosing it of the order of $\sqrt{N/2}$. If rational reconstruction is not possible (no suitable $a/b$ exists), returns $[]$. \bprog ? bestappr(Mod(18526731858, 11^10)) %1 = 1/7 ? bestappr(Mod(18526731858, 11^20)) %2 = [] ? bestappr(3 + 5 + 3*5^2 + 5^3 + 3*5^4 + 5^5 + 3*5^6 + O(5^7)) %2 = -1/3 @eprog\noindent In most concrete uses, $B$ is a prime power and we performed Hensel lifting to obtain $x$. The function applies recursively to components of complex objects (polynomials, vectors, \dots). If rational reconstruction fails for even a single entry, return $[]$. The library syntax is \fun{GEN}{bestappr}{GEN x, GEN B = NULL}. \subsec{bestapprPade$(x, \{B\})$}\kbdsidx{bestapprPade}\label{se:bestapprPade} Using variants of the extended Euclidean algorithm (Pad\'{e} approximants), returns a rational function approximation $a/b$ to $x$, whose denominator is limited by $B$, if present. If $B$ is omitted, return the best approximation affordable given the input accuracy; if you are looking for true rational functions, presumably approximated to sufficient accuracy, you should first try that option. Otherwise, $B$ must be a non-negative real (impose $0 \leq \text{degree}(b) \leq B$). \item If $x$ is a \typ{POLMOD} modulo $N$ this function performs rational modular reconstruction modulo $N$. The routine then returns the unique rational function $a/b$ in coprime polynomials, with $\text{degree}(b)\leq B$ and $\text{degree}(a)$ minimal, which is congruent to $x$ modulo $N$. Omitting $B$ amounts to choosing it equal to the floor of $\text{degree}(N) / 2$. If rational reconstruction is not possible (no suitable $a/b$ exists), returns $[]$. \bprog ? T = Mod(x^3 + x^2 + x + 3, x^4 - 2); ? bestapprPade(T) %2 = (2*x - 1)/(x - 1) ? U = Mod(1 + x + x^2 + x^3 + x^5, x^9); ? bestapprPade(U) \\ internally chooses B = 4 %3 = [] ? bestapprPade(U, 5) \\ with B = 5, a solution exists %4 = (2*x^4 + x^3 - x - 1)/(-x^5 + x^3 + x^2 - 1) @eprog \item If $x$ is a \typ{SER}, we implicitly convert the input to a \typ{POLMOD} modulo $N = t^k$ where $k$ is the series absolute precision. \bprog ? T = 1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + O(t^7); \\ mod t^7 ? bestapprPade(T) %1 = 1/(-t + 1) @eprog \item If $x$ is a \typ{RFRAC}, we implicitly convert the input to a \typ{POLMOD} modulo $N = t^k$ where $k = 2B + 1$. If $B$ was omitted, we return $x$: \bprog ? T = (4*t^2 + 2*t + 3)/(t+1)^10; ? bestapprPade(T,1) %2 = [] \\ impossible ? bestapprPade(T,2) %3 = 27/(337*t^2 + 84*t + 9) ? bestapprPade(T,3) %4 = (4253*t - 3345)/(-39007*t^3 - 28519*t^2 - 8989*t - 1115) @eprog\noindent The function applies recursively to components of complex objects (polynomials, vectors, \dots). If rational reconstruction fails for even a single entry, return $[]$. The library syntax is \fun{GEN}{bestapprPade}{GEN x, long B}. \subsec{bezout$(x,y)$}\kbdsidx{bezout}\label{se:bezout} Deprecated alias for \kbd{gcdext} The library syntax is \fun{GEN}{gcdext0}{GEN x, GEN y}. \subsec{bigomega$(x)$}\kbdsidx{bigomega}\label{se:bigomega} Number of prime divisors of the integer $|x|$ counted with multiplicity: \bprog ? factor(392) %1 = [2 3] [7 2] ? bigomega(392) %2 = 5; \\ = 3+2 ? omega(392) %3 = 2; \\ without multiplicity @eprog The library syntax is \fun{long}{bigomega}{GEN x}. \subsec{charconj$(\var{cyc},\var{chi})$}\kbdsidx{charconj}\label{se:charconj} Let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. This function returns the conjugate character. \bprog ? cyc = [15,5]; chi = [1,1]; ? charconj(cyc, chi) %2 = [14, 4] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charconj(bnf, [1]) %5 = [2] @eprog\noindent For Dirichlet characters (when \kbd{cyc} is \kbd{znstar(q,1)}), characters in Conrey representation are available, see \secref{se:dirichletchar} or \kbd{??character}: \bprog ? G = znstar(8, 1); \\ (Z/8Z)^* ? charorder(G, 3) \\ Conrey label %2 = 2 ? chi = znconreylog(G, 3); ? charorder(G, chi) \\ Conrey logarithm %4 = 2 @eprog The library syntax is \fun{GEN}{charconj0}{GEN cyc, GEN chi}. Also available is \fun{GEN}{charconj}{GEN cyc, GEN chi}, when \kbd{cyc} is known to be a vector of elementary divisors and \kbd{chi} a compatible character (no checks). \subsec{chardiv$(\var{cyc}, a,b)$}\kbdsidx{chardiv}\label{se:chardiv} Let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $a = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. Given two characters $a$ and $b$, return the character $a / b = a \overline{b}$. \bprog ? cyc = [15,5]; a = [1,1]; b = [2,4]; ? chardiv(cyc, a,b) %2 = [14, 2] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? chardiv(bnf, [1], [2]) %5 = [2] @eprog\noindent For Dirichlet characters on $(\Z/N\Z)^*$, additional representations are available (Conrey labels, Conrey logarithm), see \secref{se:dirichletchar} or \kbd{??character}. If the two characters are in the same format, the result is given in the same format, otherwise a Conrey logarithm is used. \bprog ? G = znstar(100, 1); ? G.cyc %2 = [20, 2] ? a = [10, 1]; \\ usual representation for characters ? b = 7; \\ Conrey label; ? c = znconreylog(G, 11); \\ Conrey log ? chardiv(G, b,b) %6 = 1 \\ Conrey label ? chardiv(G, a,b) %7 = [0, 5]~ \\ Conrey log ? chardiv(G, a,c) %7 = [0, 14]~ \\ Conrey log @eprog The library syntax is \fun{GEN}{chardiv0}{GEN cyc, GEN a, GEN b}. Also available is \fun{GEN}{chardiv}{GEN cyc, GEN a, GEN b}, when \kbd{cyc} is known to be a vector of elementary divisors and $a, b$ are compatible characters (no checks). \subsec{chareval$(G, \var{chi}, x, \{z\})$}\kbdsidx{chareval}\label{se:chareval} Let $G$ be an abelian group structure affording a discrete logarithm method, e.g $G = \kbd{znstar}(N, 1)$ for $(\Z/N\Z)^*$ or a \kbd{bnr} structure, let $x$ be an element of $G$ and let \var{chi} be a character of $G$ (see the note below for details). This function returns the value of \var{chi} at $x$. \misctitle{Note on characters} Let $K$ be some field. If $G$ is an abelian group, let $\chi: G \to K^*$ be a character of finite order and let $o$ be a multiple of the character order such that $\chi(n) = \zeta^{c(n)}$ for some fixed $\zeta\in K^*$ of multiplicative order $o$ and a unique morphism $c: G \to (\Z/o\Z,+)$. Our usual convention is to write $$G = (\Z/o_1\Z) g_1 \oplus \cdots \oplus (\Z/o_d\Z) g_d$$ for some generators $(g_i)$ of respective order $d_i$, where the group has exponent $o := \text{lcm}_i o_i$. Since $\zeta^o = 1$, the vector $(c_i)$ in $\prod (\Z/o_i\Z)$ defines a character $\chi$ on $G$ via $\chi(g_i) = \zeta^{c_i (o/o_i)}$ for all $i$. Classical Dirichlet characters have values in $K = \C$ and we can take $\zeta = \exp(2i\pi/o)$. \misctitle{Note on Dirichlet characters} In the special case where \var{bid} is attached to $G = (\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}), the Dirichlet character \var{chi} can be written in one of the usual 3 formats: a \typ{VEC} in terms of \kbd{bid.gen} as above, a \typ{COL} in terms of the Conrey generators, or a \typ{INT} (Conrey label); see \secref{se:dirichletchar} or \kbd{??character}. The character value is encoded as follows, depending on the optional argument $z$: \item If $z$ is omitted: return the rational number $c(x)/o$ for $x$ coprime to $q$, where we normalize $0\leq c(x) < o$. If $x$ can not be mapped to the group (e.g. $x$ is not coprime to the conductor of a Dirichlet or Hecke character) we return the sentinel value $-1$. \item If $z$ is an integer $o$, then we assume that $o$ is a multiple of the character order and we return the integer $c(x)$ when $x$ belongs to the group, and the sentinel value $-1$ otherwise. \item $z$ can be of the form $[\var{zeta}, o]$, where \var{zeta} is an $o$-th root of $1$ and $o$ is a multiple of the character order. We return $\zeta^{c(x)}$ if $x$ belongs to the group, and the sentinel value $0$ otherwise. (Note that this coincides with the usual extension of Dirichlet characters to $\Z$, or of Hecke characters to general ideals.) \item Finally, $z$ can be of the form $[\var{vzeta}, o]$, where \var{vzeta} is a vector of powers $\zeta^0, \dots, \zeta^{o-1}$ of some $o$-th root of $1$ and $o$ is a multiple of the character order. As above, we return $\zeta^{c(x)}$ after a table lookup. Or the sentinel value $0$. The library syntax is \fun{GEN}{chareval}{GEN G, GEN chi, GEN x, GEN z = NULL}. \subsec{chargalois$(\var{cyc},\{\var{ORD}\})$}\kbdsidx{chargalois}\label{se:chargalois} Let \var{cyc} represent a finite abelian group by its elementary divisors (any object which has a \kbd{.cyc} method is also allowed, i.e. the output of \kbd{znstar} or \kbd{bnrinit}). Return a list of representatives for the Galois orbits of complex characters of $G$. If \kbd{ORD} is present, select characters depending on their orders: \item if \kbd{ORD} is a \typ{INT}, restrict to orders less than this bound; \item if \kbd{ORD} is a \typ{VEC} or \typ{VECSMALL}, restrict to orders in the list. \bprog ? G = znstar(96); ? #chargalois(G) \\ 16 orbits of characters mod 96 %2 = 16 ? #chargalois(G,4) \\ order less than 4 %3 = 12 ? chargalois(G,[1,4]) \\ order 1 or 4; 5 orbits %4 = [[0, 0, 0], [2, 0, 0], [2, 1, 0], [2, 0, 1], [2, 1, 1]] @eprog\noindent Given a character $\chi$, of order $n$ (\kbd{charorder(G,chi)}), the elements in its orbit are the $\phi(n)$ characters $\chi^i$, $(i,n)=1$. The library syntax is \fun{GEN}{chargalois}{GEN cyc, GEN ORD = NULL}. \subsec{charker$(\var{cyc},\var{chi})$}\kbdsidx{charker}\label{se:charker} Let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. This function returns the kernel of $\chi$, as a matrix $K$ in HNF which is a left-divisor of \kbd{matdiagonal(d)}. Its columns express in terms of the $g_j$ the generators of the subgroup. The determinant of $K$ is the kernel index. \bprog ? cyc = [15,5]; chi = [1,1]; ? charker(cyc, chi) %2 = [15 12] [ 0 1] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charker(bnf, [1]) %5 = [3] @eprog\noindent Note that for Dirichlet characters (when \kbd{cyc} is \kbd{znstar(q, 1)}), characters in Conrey representation are available, see \secref{se:dirichletchar} or \kbd{??character}. \bprog ? G = znstar(8, 1); \\ (Z/8Z)^* ? charker(G, 1) \\ Conrey label for trivial character %2 = [1 0] [0 1] @eprog The library syntax is \fun{GEN}{charker0}{GEN cyc, GEN chi}. Also available is \fun{GEN}{charker}{GEN cyc, GEN chi}, when \kbd{cyc} is known to be a vector of elementary divisors and \kbd{chi} a compatible character (no checks). \subsec{charmul$(\var{cyc}, a,b)$}\kbdsidx{charmul}\label{se:charmul} Let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $a = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. Given two characters $a$ and $b$, return the product character $ab$. \bprog ? cyc = [15,5]; a = [1,1]; b = [2,4]; ? charmul(cyc, a,b) %2 = [3, 0] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charmul(bnf, [1], [2]) %5 = [0] @eprog\noindent For Dirichlet characters on $(\Z/N\Z)^*$, additional representations are available (Conrey labels, Conrey logarithm), see \secref{se:dirichletchar} or \kbd{??character}. If the two characters are in the same format, their product is given in the same format, otherwise a Conrey logarithm is used. \bprog ? G = znstar(100, 1); ? G.cyc %2 = [20, 2] ? a = [10, 1]; \\ usual representation for characters ? b = 7; \\ Conrey label; ? c = znconreylog(G, 11); \\ Conrey log ? charmul(G, b,b) %6 = 49 \\ Conrey label ? charmul(G, a,b) %7 = [0, 15]~ \\ Conrey log ? charmul(G, a,c) %7 = [0, 6]~ \\ Conrey log @eprog The library syntax is \fun{GEN}{charmul0}{GEN cyc, GEN a, GEN b}. Also available is \fun{GEN}{charmul}{GEN cyc, GEN a, GEN b}, when \kbd{cyc} is known to be a vector of elementary divisors and $a, b$ are compatible characters (no checks). \subsec{charorder$(\var{cyc},\var{chi})$}\kbdsidx{charorder}\label{se:charorder} Let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. This function returns the order of the character \kbd{chi}. \bprog ? cyc = [15,5]; chi = [1,1]; ? charorder(cyc, chi) %2 = 15 ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charorder(bnf, [1]) %5 = 3 @eprog\noindent For Dirichlet characters (when \kbd{cyc} is \kbd{znstar(q, 1)}), characters in Conrey representation are available, see \secref{se:dirichletchar} or \kbd{??character}: \bprog ? G = znstar(100, 1); \\ (Z/100Z)^* ? charorder(G, 7) \\ Conrey label %2 = 4 @eprog The library syntax is \fun{GEN}{charorder0}{GEN cyc, GEN chi}. Also available is \fun{GEN}{charorder}{GEN cyc, GEN chi}, when \kbd{cyc} is known to be a vector of elementary divisors and \kbd{chi} a compatible character (no checks). \subsec{charpow$(\var{cyc}, a,n)$}\kbdsidx{charpow}\label{se:charpow} Let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $a = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. Given $n\in \Z$ and a character $a$, return the character $a^n$. \bprog ? cyc = [15,5]; a = [1,1]; ? charpow(cyc, a, 3) %2 = [3, 3] ? charpow(cyc, a, 5) %2 = [5, 0] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charpow(bnf, [1], 3) %5 = [0] @eprog\noindent For Dirichlet characters on $(\Z/N\Z)^*$, additional representations are available (Conrey labels, Conrey logarithm), see \secref{se:dirichletchar} or \kbd{??character} and the output uses the same format as the input. \bprog ? G = znstar(100, 1); ? G.cyc %2 = [20, 2] ? a = [10, 1]; \\ standard representation for characters ? b = 7; \\ Conrey label; ? c = znconreylog(G, 11); \\ Conrey log ? charpow(G, a,3) %6 = [10, 1] \\ standard representation ? charpow(G, b,3) %7 = 43 \\ Conrey label ? charpow(G, c,3) %8 = [1, 8]~ \\ Conrey log @eprog The library syntax is \fun{GEN}{charpow0}{GEN cyc, GEN a, GEN n}. Also available is \fun{GEN}{charpow}{GEN cyc, GEN a, GEN n}, when \kbd{cyc} is known to be a vector of elementary divisors (no check). \subsec{chinese$(x,\{y\})$}\kbdsidx{chinese}\label{se:chinese} If $x$ and $y$ are both intmods or both polmods, creates (with the same type) a $z$ in the same residue class as $x$ and in the same residue class as $y$, if it is possible. \bprog ? chinese(Mod(1,2), Mod(2,3)) %1 = Mod(5, 6) ? chinese(Mod(x,x^2-1), Mod(x+1,x^2+1)) %2 = Mod(-1/2*x^2 + x + 1/2, x^4 - 1) @eprog\noindent This function also allows vector and matrix arguments, in which case the operation is recursively applied to each component of the vector or matrix. \bprog ? chinese([Mod(1,2),Mod(1,3)], [Mod(1,5),Mod(2,7)]) %3 = [Mod(1, 10), Mod(16, 21)] @eprog\noindent For polynomial arguments in the same variable, the function is applied to each coefficient; if the polynomials have different degrees, the high degree terms are copied verbatim in the result, as if the missing high degree terms in the polynomial of lowest degree had been \kbd{Mod(0,1)}. Since the latter behavior is usually \emph{not} the desired one, we propose to convert the polynomials to vectors of the same length first: \bprog ? P = x+1; Q = x^2+2*x+1; ? chinese(P*Mod(1,2), Q*Mod(1,3)) %4 = Mod(1, 3)*x^2 + Mod(5, 6)*x + Mod(3, 6) ? chinese(Vec(P,3)*Mod(1,2), Vec(Q,3)*Mod(1,3)) %5 = [Mod(1, 6), Mod(5, 6), Mod(4, 6)] ? Pol(%) %6 = Mod(1, 6)*x^2 + Mod(5, 6)*x + Mod(4, 6) @eprog If $y$ is omitted, and $x$ is a vector, \kbd{chinese} is applied recursively to the components of $x$, yielding a residue belonging to the same class as all components of $x$. Finally $\kbd{chinese}(x,x) = x$ regardless of the type of $x$; this allows vector arguments to contain other data, so long as they are identical in both vectors. The library syntax is \fun{GEN}{chinese}{GEN x, GEN y = NULL}. \fun{GEN}{chinese1}{GEN x} is also available. \subsec{content$(x,\{D\})$}\kbdsidx{content}\label{se:content} Computes the gcd of all the coefficients of $x$, when this gcd makes sense. This is the natural definition if $x$ is a polynomial (and by extension a power series) or a vector/matrix. This is in general a weaker notion than the \emph{ideal} generated by the coefficients: \bprog ? content(2*x+y) %1 = 1 \\ = gcd(2,y) over Q[y] @eprog If $x$ is a scalar, this simply returns the absolute value of $x$ if $x$ is rational (\typ{INT} or \typ{FRAC}), and either $1$ (inexact input) or $x$ (exact input) otherwise; the result should be identical to \kbd{gcd(x, 0)}. The content of a rational function is the ratio of the contents of the numerator and the denominator. In recursive structures, if a matrix or vector \emph{coefficient} $x$ appears, the gcd is taken not with $x$, but with its content: \bprog ? content([ [2], 4*matid(3) ]) %1 = 2 @eprog\noindent The content of a \typ{VECSMALL} is computed assuming the entries are signed integers. The optional argument $D$ allows to control over which ring we compute and get a more predictable behaviour: \item $1$: we only consider the underlying $\Q$-structure and the denominator is a (positive) rational number \item a simple variable, say \kbd{'x}: all entries are considered as rational functions in $K(x)$ for some field $K$ and the content is an element of $K$. \bprog ? f = x + 1/y + 1/2; ? content(f) \\ as a t_POL in x %2 = 1/(2*y) ? content(f, 1) \\ Q-content %3 = 1/2 ? content(f, y) \\ as a rational function in y %4 = 1/2 ? g = x^2*y + y^2*x; ? content(g, x) %6 = y ? content(g, y) %7 = x @eprog The library syntax is \fun{GEN}{content0}{GEN x, GEN D = NULL}. \subsec{contfrac$(x,\{b\},\{\var{nmax}\})$}\kbdsidx{contfrac}\label{se:contfrac} Returns the row vector whose components are the partial quotients of the \idx{continued fraction} expansion of $x$. In other words, a result $[a_0,\dots,a_n]$ means that $x \approx a_0+1/(a_1+\dots+1/a_n)$. The output is normalized so that $a_n \neq 1$ (unless we also have $n = 0$). The number of partial quotients $n+1$ is limited by \kbd{nmax}. If \kbd{nmax} is omitted, the expansion stops at the last significant partial quotient. \bprog ? \p19 realprecision = 19 significant digits ? contfrac(Pi) %1 = [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2] ? contfrac(Pi,, 3) \\ n = 2 %2 = [3, 7, 15] @eprog\noindent $x$ can also be a rational function or a power series. If a vector $b$ is supplied, the numerators are equal to the coefficients of $b$, instead of all equal to $1$ as above; more precisely, $x \approx (1/b_0)(a_0+b_1/(a_1+\dots+b_n/a_n))$; for a numerical continued fraction ($x$ real), the $a_i$ are integers, as large as possible; if $x$ is a rational function, they are polynomials with $\deg a_i = \deg b_i + 1$. The length of the result is then equal to the length of $b$, unless the next partial quotient cannot be reliably computed, in which case the expansion stops. This happens when a partial remainder is equal to zero (or too small compared to the available significant digits for $x$ a \typ{REAL}). A direct implementation of the numerical continued fraction \kbd{contfrac(x,b)} described above would be \bprog \\ "greedy" generalized continued fraction cf(x, b) = { my( a= vector(#b), t ); x *= b[1]; for (i = 1, #b, a[i] = floor(x); t = x - a[i]; if (!t || i == #b, break); x = b[i+1] / t; ); a; } @eprog\noindent There is some degree of freedom when choosing the $a_i$; the program above can easily be modified to derive variants of the standard algorithm. In the same vein, although no builtin function implements the related \idx{Engel expansion} (a special kind of \idx{Egyptian fraction} decomposition: $x = 1/a_1 + 1/(a_1a_2) + \dots$ ), it can be obtained as follows: \bprog \\ n terms of the Engel expansion of x engel(x, n = 10) = { my( u = x, a = vector(n) ); for (k = 1, n, a[k] = ceil(1/u); u = u*a[k] - 1; if (!u, break); ); a } @eprog \misctitle{Obsolete hack} (don't use this): if $b$ is an integer, \var{nmax} is ignored and the command is understood as \kbd{contfrac($x,, b$)}. The library syntax is \fun{GEN}{contfrac0}{GEN x, GEN b = NULL, long nmax}. Also available are \fun{GEN}{gboundcf}{GEN x, long nmax}, \fun{GEN}{gcf}{GEN x} and \fun{GEN}{gcf2}{GEN b, GEN x}. \subsec{contfracpnqn$(x, \{n=-1\})$}\kbdsidx{contfracpnqn}\label{se:contfracpnqn} When $x$ is a vector or a one-row matrix, $x$ is considered as the list of partial quotients $[a_0,a_1,\dots,a_n]$ of a rational number, and the result is the 2 by 2 matrix $[p_n,p_{n-1};q_n,q_{n-1}]$ in the standard notation of continued fractions, so $p_n/q_n=a_0+1/(a_1+\dots+1/a_n)$. If $x$ is a matrix with two rows $[b_0,b_1,\dots,b_n]$ and $[a_0,a_1,\dots,a_n]$, this is then considered as a generalized continued fraction and we have similarly $p_n/q_n=(1/b_0)(a_0+b_1/(a_1+\dots+b_n/a_n))$. Note that in this case one usually has $b_0=1$. If $n \geq 0$ is present, returns all convergents from $p_0/q_0$ up to $p_n/q_n$. (All convergents if $x$ is too small to compute the $n+1$ requested convergents.) \bprog ? a = contfrac(Pi,10) %1 = [3, 7, 15, 1, 292, 1, 1, 1, 3] ? allpnqn(x) = contfracpnqn(x,#x) \\ all convergents ? allpnqn(a) %3 = [3 22 333 355 103993 104348 208341 312689 1146408] [1 7 106 113 33102 33215 66317 99532 364913] ? contfracpnqn(a) \\ last two convergents %4 = [1146408 312689] [ 364913 99532] ? contfracpnqn(a,3) \\ first three convergents %5 = [3 22 333 355] [1 7 106 113] @eprog The library syntax is \fun{GEN}{contfracpnqn}{GEN x, long n}. also available is \fun{GEN}{pnqn}{GEN x} for $n = -1$. \subsec{core$(n,\{\fl=0\})$}\kbdsidx{core}\label{se:core} If $n$ is an integer written as $n=df^2$ with $d$ squarefree, returns $d$. If $\fl$ is non-zero, returns the two-element row vector $[d,f]$. By convention, we write $0 = 0 \times 1^2$, so \kbd{core(0, 1)} returns $[0,1]$. The library syntax is \fun{GEN}{core0}{GEN n, long flag}. Also available are \fun{GEN}{core}{GEN n} ($\fl = 0$) and \fun{GEN}{core2}{GEN n} ($\fl = 1$) \subsec{coredisc$(n,\{\fl=0\})$}\kbdsidx{coredisc}\label{se:coredisc} A \emph{fundamental discriminant} is an integer of the form $t\equiv 1 \mod 4$ or $4t \equiv 8,12 \mod 16$, with $t$ squarefree (i.e.~$1$ or the discriminant of a quadratic number field). Given a non-zero integer $n$, this routine returns the (unique) fundamental discriminant $d$ such that $n=df^2$, $f$ a positive rational number. If $\fl$ is non-zero, returns the two-element row vector $[d,f]$. If $n$ is congruent to 0 or 1 modulo 4, $f$ is an integer, and a half-integer otherwise. By convention, \kbd{coredisc(0, 1))} returns $[0,1]$. Note that \tet{quaddisc}$(n)$ returns the same value as \kbd{coredisc}$(n)$, and also works with rational inputs $n\in\Q^*$. The library syntax is \fun{GEN}{coredisc0}{GEN n, long flag}. Also available are \fun{GEN}{coredisc}{GEN n} ($\fl = 0$) and \fun{GEN}{coredisc2}{GEN n} ($\fl = 1$) \subsec{dirdiv$(x,y)$}\kbdsidx{dirdiv}\label{se:dirdiv} $x$ and $y$ being vectors of perhaps different lengths but with $y[1]\neq 0$ considered as \idx{Dirichlet series}, computes the quotient of $x$ by $y$, again as a vector. The library syntax is \fun{GEN}{dirdiv}{GEN x, GEN y}. \subsec{direuler$(p=a,b,\var{expr},\{c\})$}\kbdsidx{direuler}\label{se:direuler} Computes the \idx{Dirichlet series} attached to the \idx{Euler product} of expression \var{expr} as $p$ ranges through the primes from $a$ to $b$. \var{expr} must be a polynomial or rational function in another variable than $p$ (say $X$) and $\var{expr}(X)$ is understood as the local factor $\var{expr}(p^{-s})$. The series is output as a vector of coefficients. If $c$ is omitted, output the first $b$ coefficients of the series; otherwise, output the first $c$ coefficients. The following command computes the \teb{sigma} function, attached to $\zeta(s)\zeta(s-1)$: \bprog ? direuler(p=2, 10, 1/((1-X)*(1-p*X))) %1 = [1, 3, 4, 7, 6, 12, 8, 15, 13, 18] ? direuler(p=2, 10, 1/((1-X)*(1-p*X)), 5) \\ fewer terms %2 = [1, 3, 4, 7, 6] @eprog\noindent Setting $c < b$ is useless (the same effect would be achieved by setting $b = c)$. If $c > b$, the computed coefficients are ``missing'' Euler factors: \bprog ? direuler(p=2, 10, 1/((1-X)*(1-p*X)), 15) \\ more terms, no longer = sigma ! %3 = [1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 0, 28, 0, 24, 24] @eprog \synt{direuler}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN b} \subsec{dirmul$(x,y)$}\kbdsidx{dirmul}\label{se:dirmul} $x$ and $y$ being vectors of perhaps different lengths representing the \idx{Dirichlet series} $\sum_n x_n n^{-s}$ and $\sum_n y_n n^{-s}$, computes the product of $x$ by $y$, again as a vector. \bprog ? dirmul(vector(10,n,1), vector(10,n,moebius(n))) %1 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] @eprog\noindent The product length is the minimum of $\kbd{\#}x\kbd{*}v(y)$ and $\kbd{\#}y\kbd{*}v(x)$, where $v(x)$ is the index of the first non-zero coefficient. \bprog ? dirmul([0,1], [0,1]); %2 = [0, 0, 0, 1] @eprog The library syntax is \fun{GEN}{dirmul}{GEN x, GEN y}. \subsec{divisors$(x,\{\fl=0\})$}\kbdsidx{divisors}\label{se:divisors} Creates a row vector whose components are the divisors of $x$. The factorization of $x$ (as output by \tet{factor}) can be used instead. If $\fl = 1$, return pairs $[d, \kbd{factor}(d)]$. By definition, these divisors are the products of the irreducible factors of $n$, as produced by \kbd{factor(n)}, raised to appropriate powers (no negative exponent may occur in the factorization). If $n$ is an integer, they are the positive divisors, in increasing order. \bprog ? divisors(12) %1 = [1, 2, 3, 4, 6, 12] ? divisors(12, 1) \\ include their factorization %2 = [[1, matrix(0,2)], [2, Mat([2, 1])], [3, Mat([3, 1])], [4, Mat([2, 2])], [6, [2, 1; 3, 1]], [12, [2, 2; 3, 1]]] ? divisors(x^4 + 2*x^3 + x^2) \\ also works for polynomials %3 = [1, x, x^2, x + 1, x^2 + x, x^3 + x^2, x^2 + 2*x + 1, x^3 + 2*x^2 + x, x^4 + 2*x^3 + x^2] @eprog The library syntax is \fun{GEN}{divisors0}{GEN x, long flag}. The functions \fun{GEN}{divisors}{GEN N} ($\fl = 0$) and \fun{GEN}{divisors_factored}{GEN N} ($\fl = 1$) are also available. \subsec{divisorslenstra$(N, r, s)$}\kbdsidx{divisorslenstra}\label{se:divisorslenstra} Given three integers $N > s > r \geq 0$ such that $(r,s) = 1$ and $s^3 > N$, find all divisors $d$ of $N$ such that $d \equiv r \pmod{s}$. There are at most $11$ such divisors (Lenstra). \bprog ? N = 245784; r = 19; s = 65 ; ? divisorslenstra(N, r, s) %2 = [19, 84, 539, 1254, 3724, 245784] ? [ d | d <- divisors(N), d % s == r] %3 = [19, 84, 539, 1254, 3724, 245784] @eprog\noindent When the preconditions are not met, the result is undefined: \bprog ? N = 4484075232; r = 7; s = 1303; s^3 > N %4 = 0 ? divisorslenstra(N, r, s) ? [ d | d <- divisors(N), d % s == r ] %6 = [7, 2613, 9128, 19552, 264516, 3407352, 344928864] @eprog\noindent (Divisors were missing but $s^3 < N$.) The library syntax is \fun{GEN}{divisorslenstra}{GEN N, GEN r, GEN s}. \subsec{eulerphi$(x)$}\kbdsidx{eulerphi}\label{se:eulerphi} Euler's $\phi$ (totient)\sidx{Euler totient function} function of the integer $|x|$, in other words $|(\Z/x\Z)^*|$. \bprog ? eulerphi(40) %1 = 16 @eprog\noindent According to this definition we let $\phi(0) := 2$, since $\Z^* = \{-1,1\}$; this is consistent with \kbd{znstar(0)}: we have \kbd{znstar$(n)$.no = eulerphi(n)} for all $n\in\Z$. The library syntax is \fun{GEN}{eulerphi}{GEN x}. \subsec{factor$(x,\{D\})$}\kbdsidx{factor}\label{se:factor} Factor $x$ over domain $D$; if $D$ is omitted, it is determined from $x$. For instance, if $x$ is an integer, it is factored in $\Z$, if it is a polynomial with rational coefficients, it is factored in $\Q[x]$, etc., see below for details. The result is a two-column matrix: the first contains the irreducibles dividing $x$ (rational or Gaussian primes, irreducible polynomials), and the second the exponents. By convention, $0$ is factored as $0^1$. \misctitle{$x \in \Q$} See \tet{factorint} for the algorithms used. The factorization includes the unit $-1$ when $x < 0$ and all other factors are positive; a denominator is factored with negative exponents. The factors are sorted in increasing order. \bprog ? factor(-7/106) %1 = [-1 1] [ 2 -1] [ 7 1] [53 -1] @eprog\noindent By convention, $1$ is factored as \kbd{matrix(0,2)} (the empty factorization, printed as \kbd{[;]}). Large rational ``primes'' $ > 2^{64}$ in the factorization are in fact \var{pseudoprimes} (see \kbd{ispseudoprime}), a priori not rigorously proven primes. Use \kbd{isprime} to prove primality of these factors, as in \bprog ? fa = factor(2^2^7 + 1) %1 = [59649589127497217 1] [5704689200685129054721 1] ? isprime( fa[,1] ) %2 = [1, 1]~ \\ both entries are proven primes @eprog\noindent Another possibility is to globally set the default \tet{factor_proven}, which will perform a rigorous primality proof for each pseudoprime factor but will slow down PARI. A \typ{INT} argument $D$ can be added, meaning that we look only for prime factors $p < D$. The limit $D$ must be non-negative. In this case, all but the last factor are proven primes, but the remaining factor may actually be a proven composite! If the remaining factor is less than $D^2$, then it is prime. \bprog ? factor(2^2^7 +1, 10^5) %3 = [340282366920938463463374607431768211457 1] @eprog\noindent \misctitle{Deprecated feature} Setting $D=0$ is the same as setting it to $\kbd{primelimit} + 1$. \smallskip This routine uses trial division and perfect power tests, and should not be used for huge values of $D$ (at most $10^9$, say): \kbd{factorint(, 1 + 8)} will in general be faster. The latter does not guarantee that all small prime factors are found, but it also finds larger factors and in a more efficient way. \bprog ? F = (2^2^7 + 1) * 1009 * (10^5+3); factor(F, 10^5) \\ fast, incomplete time = 0 ms. %4 = [1009 1] [34029257539194609161727850866999116450334371 1] ? factor(F, 10^9) \\ slow time = 3,260 ms. %6 = [1009 1] [100003 1] [340282366920938463463374607431768211457 1] ? factorint(F, 1+8) \\ much faster and all small primes were found time = 8 ms. %7 = [1009 1] [100003 1] [340282366920938463463374607431768211457 1] ? factor(F) \\ complete factorization time = 60 ms. %8 = [1009 1] [100003 1] [59649589127497217 1] [5704689200685129054721 1] @eprog\noindent Setting $D = I$ will factor in the Gaussian integers $\Z[i]$: \misctitle{$x \in \Q(i)$} The factorization is performed with Gaussian primes in $\Z[i]$ and includes Gaussian units in $\{\pm1, \pm i\}$; factors are sorted by increasing norm. Except for a possible leading unit, the Gaussian factors are normalized: rational factors are positive and irrational factors have positive imaginary part (a canonical represneta. Unless \tet{factor_proven} is set, large factors are actually pseudoprimes, not proven primes; a rational factor is prime if less than $2^{64}$ and an irrational one if its norm is less than $2^{64}$. \bprog ? factor(5*I) %1 = [ 2 + I 1] [1 + 2*I 1] @eprog\noindent One can force the factorization of a rational number by setting the domain $D = I$: \bprog ? factor(-5, I) %2 = [ I 1] [ 2 + I 1] [1 + 2*I 1] ? factorback(%) %3 = -5 @eprog \misctitle{Univariate polynomials and rational functions} PARI can factor univariate polynomials in $K[t]$. The following base fields $K$ are currently supported: $\Q$, $\R$, $\C$, $\Q_p$, finite fields and number fields. See \tet{factormod} and \tet{factorff} for the algorithms used over finite fields and \tet{nffactor} for the algorithms over number fields. The irreducible factors are sorted by increasing degree and normalized: they are monic except when $K = \Q$ where they are primitive in $\Z[t]$. The content is \emph{not} included in the factorization, in particular \kbd{factorback} will in general recover the original $x$ only up to multiplication by an element of $K^*$: when $K\neq\Q$, this scalar is \kbd{pollead}$(x)$ (since irreducible factors are monic); and when $K = \Q$ you can either ask for the $\Q$-content explicitly of use factorback: \bprog ? P = t^2 + 5*t/2 + 1; F = factor(P) %1 = [t + 2 1] [2*t + 1 1] ? content(P, 1) \\ Q-content %2 = 1/2 ? pollead(factorback(F)) / pollead(P) %3 = 2 @eprog You can specify $K$ using the optional ``domain'' argument $D$ as follows \item $K = \Q$ : $D$ a rational number (\typ{INT} or \typ{FRAC}), \item $K = \Z/p\Z$ with $p$ prime : $D$ a \typ{INTMOD} modulo $p$; factoring modulo a non-prime number is not supported. \item $K = \F_q$ : $D$ a \typ{FFELT} encoding the finite field; you can also use a \typ{POLMOD} of \typ{INTMOD} modulo a prime $p$ but this is usualy less convenient; \item $K = \Q[X]/(T)$ a number field : $D$ a \typ{POLMOD} modulo $T$, \item $K = \Q(i)$ (alternate syntax for special case): $D = I$, \item $K = \Q(w)$ a quadratic number field (alternate syntax for special case): $D$ a \typ{QUAD}, \item $K = \R$ : $D$ a real number (\typ{REAL}); truncate the factorization at accuracy \kbd{precision}$(D)$. If $x$ is inexact and \kbd{precision}$(x)$ is less than \kbd{precision}$(D)$, then the precision of $x$ is used instead. \item $K = \C$ : $D$ a complex number with a \typ{REAL} component, e.g. \kbd{I * 1.}; truncate the factorization as for $K = \R$, \item $K = \Q_p$ : $D$ a \typ{PADIC}; truncate the factorization at $p$-adic accuracy \kbd{padicprec}$(D)$, possibly less if $x$ is inexact with insufficient $p$-adic accuracy; \bprog ? T = x^2+1; ? factor(T, 1); \\ over Q ? factor(T, Mod(1,3)) \\ over F_3 ? factor(T, ffgen(ffinit(3,2,'t))^0) \\ over F_{3^2} ? factor(T, Mod(Mod(1,3), t^2+t+2)) \\ over F_{3^2}, again ? factor(T, O(3^6)) \\ over Q_3, precision 6 ? factor(T, 1.) \\ over R, current precision ? factor(T, I*1.) \\ over C ? factor(T, Mod(1, y^3-2)) \\ over Q(2^{1/3}) @eprog\noindent In most cases, it is possible and simpler to call a specialized variant rather than use the above scheme: \bprog ? factormod(T, 3) \\ over F_3 ? factormod(T, [t^2+t+2, 3]) \\ over F_{3^2} ? factormod(T, ffgen(3^2, 't)) \\ over F_{3^2} ? factorpadic(T, 3,6) \\ over Q_3, precision 6 ? nffactor(y^3-2, T) \\ over Q(2^{1/3}) ? polroots(T) \\ over C ? polrootsreal(T) \\ over R (real polynomial) @eprog It is also possible to let the routine use the smallest field containing all coefficients, taking into account quotient structures induced by \typ{INTMOD}s and \typ{POLMOD}s (e.g.~if a coefficient in $\Z/n\Z$ is known, all rational numbers encountered are first mapped to $\Z/n\Z$; different moduli will produce an error): \bprog ? T = x^2+1; ? factor(T); \\ over Q ? factor(T*Mod(1,3)) \\ over F_3 ? factor(T*ffgen(ffinit(3,2,'t))^0) \\ over F_{3^2} ? factor(T*Mod(Mod(1,3), t^2+t+2)) \\ over F_{3^2}, again ? factor(T*(1 + O(3^6)) \\ over Q_3, precision 6 ? factor(T*1.) \\ over R, current precision ? factor(T*(1.+0.*I)) \\ over C ? factor(T*Mod(1, y^3-2)) \\ over Q(2^{1/3}) @eprog\noindent Multiplying by a suitable field element equal to $1 \in K$ in this way is error-prone and is not recommanded. Factoring existing polynomials with obvious fields of coefficients is fine, the domain argument $D$ should be used instead ad hoc conversions. \misctitle{Note on inexact polynomials} Polynomials with inexact coefficients (e.g. floating point or $p$-adic numbers) are first rounded to an exact representation, then factored to (potentially) infinite accuracy and we return a truncated approximation of that virtual factorization. To avoid pitfalls, we advise to only factor \emph{exact} polynomials: \bprog ? factor(x^2-1+O(2^2)) \\ rounded to x^2 + 3, irreducible in Q_2 %1 = [(1 + O(2^2))*x^2 + O(2^2)*x + (1 + 2 + O(2^2)) 1] ? factor(x^2-1+O(2^3)) \\ rounded to x^2 + 7, reducible ! %2 = [ (1 + O(2^3))*x + (1 + 2 + O(2^3)) 1] [(1 + O(2^3))*x + (1 + 2^2 + O(2^3)) 1] ? factor(x^2-1, O(2^2)) \\ no ambiguity now %3 = [ (1 + O(2^2))*x + (1 + O(2^2)) 1] [(1 + O(2^2))*x + (1 + 2 + O(2^2)) 1] @eprog \misctitle{Note about inseparable polynomials} Polynomials with inexact coefficients are considered to be squarefree: indeed, there exist a squarefree polynomial arbitrarily close to the input, and they cannot be distinguished at the input accuracy. This means that irreducible factors are repeated according to their apparent multiplicity. On the contrary, using a specialized function such as \kbd{factorpadic} with an \emph{exact} rational input yields the correct multiplicity when the (now exact) input is not separable. Compare: \bprog ? factor(z^2 + O(5^2))) %1 = [(1 + O(5^2))*z + O(5^2) 1] [(1 + O(5^2))*z + O(5^2) 1] ? factor(z^2, O(5^2)) %2 = [1 + O(5^2))*z + O(5^2) 2] @eprog \misctitle{Multivariate polynomials and rational functions} PARI recursively factors \emph{multivariate} polynomials in $K[t_1,\dots, t_d]$ for the same fields $K$ as above and the argument $D$ is used in the same way to specify $K$. The irreducible factors are sorted by their main variable (least priority first) then by increasing degree. \bprog ? factor(x^2 + y^2, Mod(1,5)) %1 = [ x + Mod(2, 5)*y 1] [Mod(1, 5)*x + Mod(3, 5)*y 1] ? factor(x^2 + y^2, O(5^2)) %2 = [ (1 + O(5^2))*x + (O(5^2)*y^2 + (2 + 5 + O(5^2))*y + O(5^2)) 1] [(1 + O(5^2))*x + (O(5^2)*y^2 + (3 + 3*5 + O(5^2))*y + O(5^2)) 1] ? lift(%) %3 = [ x + 7*y 1] [x + 18*y 1] @eprog\noindent Note that the implementation does not really support inexact real fields ($\R$ or $\C$) and usually misses factors even if the input is exact: \bprog ? factor(x^2 + y^2, I) \\ over Q(i) %4 = [x - I*y 1] [x + I*y 1] ? factor(x^2 + y^2, I*1.) \\ over C %5 = [x^2 + y^2 1] @eprog The library syntax is \fun{GEN}{factor0}{GEN x, GEN D = NULL}. \fun{GEN}{factor}{GEN x} \fun{GEN}{boundfact}{GEN x, ulong lim}. \subsec{factorback$(f,\{e\})$}\kbdsidx{factorback}\label{se:factorback} Gives back the factored object corresponding to a factorization. The integer $1$ corresponds to the empty factorization. If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being integral), and the corresponding factorization is the product of the $f[i]^{e[i]}$. If not, and $f$ is vector, it is understood as in the preceding case with $e$ a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a regular factorization, as produced with any \kbd{factor} command. A few examples: \bprog ? factor(12) %1 = [2 2] [3 1] ? factorback(%) %2 = 12 ? factorback([2,3], [2,1]) \\ 2^3 * 3^1 %3 = 12 ? factorback([5,2,3]) %4 = 30 @eprog The library syntax is \fun{GEN}{factorback2}{GEN f, GEN e = NULL}. Also available is \fun{GEN}{factorback}{GEN f} (case $e = \kbd{NULL}$). \subsec{factorcantor$(x,p)$}\kbdsidx{factorcantor}\label{se:factorcantor} This function is obsolete, use factormod. The library syntax is \fun{GEN}{factmod}{GEN x, GEN p}. \subsec{factorff$(x,\{p\},\{a\})$}\kbdsidx{factorff}\label{se:factorff} Obsolete, kept for backward compatibility: use factormod. The library syntax is \fun{GEN}{factorff}{GEN x, GEN p = NULL, GEN a = NULL}. \subsec{factorial$(x)$}\kbdsidx{factorial}\label{se:factorial} Factorial of $x$. The expression $x!$ gives a result which is an integer, while $\kbd{factorial}(x)$ gives a real number. The library syntax is \fun{GEN}{mpfactr}{long x, long prec}. \fun{GEN}{mpfact}{long x} returns $x!$ as a \typ{INT}. \subsec{factorint$(x,\{\fl=0\})$}\kbdsidx{factorint}\label{se:factorint} Factors the integer $n$ into a product of pseudoprimes (see \kbd{ispseudoprime}), using a combination of the \idx{Shanks SQUFOF} and \idx{Pollard Rho} method (with modifications due to Brent), \idx{Lenstra}'s \idx{ECM} (with modifications by Montgomery), and \idx{MPQS} (the latter adapted from the \idx{LiDIA} code with the kind permission of the LiDIA maintainers), as well as a search for pure powers. The output is a two-column matrix as for \kbd{factor}: the first column contains the ``prime'' divisors of $n$, the second one contains the (positive) exponents. By convention $0$ is factored as $0^1$, and $1$ as the empty factorization; also the divisors are by default not proven primes if they are larger than $2^{64}$, they only failed the BPSW compositeness test (see \tet{ispseudoprime}). Use \kbd{isprime} on the result if you want to guarantee primality or set the \tet{factor_proven} default to $1$. Entries of the private prime tables (see \tet{addprimes}) are also included as is. This gives direct access to the integer factoring engine called by most arithmetical functions. \fl\ is optional; its binary digits mean 1: avoid MPQS, 2: skip first stage ECM (we may still fall back to it later), 4: avoid Rho and SQUFOF, 8: don't run final ECM (as a result, a huge composite may be declared to be prime). Note that a (strong) probabilistic primality test is used; thus composites might not be detected, although no example is known. You are invited to play with the flag settings and watch the internals at work by using \kbd{gp}'s \tet{debug} default parameter (level 3 shows just the outline, 4 turns on time keeping, 5 and above show an increasing amount of internal details). The library syntax is \fun{GEN}{factorint}{GEN x, long flag}. \subsec{factormod$(f,\{D\},\{\fl=0\})$}\kbdsidx{factormod}\label{se:factormod} Factors the polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. The coefficients of $f$ must be operation-compatible with the corresponding finite field. The result is a two-column matrix, the first column being the irreducible polynomials dividing $f$, and the second the exponents. By convention, the $0$ polynomial factors as $0^1$; a non-zero constant polynomial has empty factorization, a $0\times 2$ matrix. The irreducible factors are ordered by increasing degree and the result is canonical: it will not change across multiple calls or sessions. \bprog ? factormod(x^2 + 1, 3) \\ over F_3 %1 = [Mod(1, 3)*x^2 + Mod(1, 3) 1] ? liftall( factormod(x^2 + 1, [3, t^2+1]) ) \\ over F_9 %2 = [ x + t 1] [x + 2*t 1] ? t = ffgen(t^2+Mod(1,3)); factormod(x^2 + t^0) \\ same using t_FFELT %3 = [ x + t 1] [x + 2*t 1] ? factormod(x^2+Mod(1,3)) %4 = [Mod(1, 3)*x^2 + Mod(1, 3) 1] ? liftall( factormod(x^2 + Mod(Mod(1,3),y^2+1)) ) %5 = [ x + y 1] [x + 2*y 1] @eprog If $\fl$ is non-zero, outputs only the \emph{degrees} of the irreducible polynomials (for example to compute an $L$-function). By convention, a constant polynomial (including the $0$ polynomial) has empty factorization. The degrees appear in increasing order but need not correspond to the ordering with $\fl =0$ when multiplicities are present. \bprog ? f = x^3 + 2*x^2 + x + 2; ? factormod(f, 5) \\ (x+2)^2 * (x+3) %1 = [Mod(1, 5)*x + Mod(2, 5) 2] [Mod(1, 5)*x + Mod(3, 5) 1] ? factormod(f, 5, 1) \\ (deg 1) * (deg 1)^2 %2 = [1 1] [1 2] @eprog The library syntax is \fun{GEN}{factormod0}{GEN f, GEN D = NULL, long flag}. \subsec{factormodDDF$(f,\{D\})$}\kbdsidx{factormodDDF}\label{se:factormodDDF} Distinct-degree factorization of the squarefree polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. This is somewhat faster than full factorization. The coefficients of $f$ must be operation-compatible with the corresponding finite field. The result is a two-column matrix: \item the first column contains monic (squarefree) pairwise coprime polynomials dividing $f$, all of whose irreducible factors have degree $d$; \item the second column contains the degrees of the irreducible factors. The factors are ordered by increasing degree and the result is canonical: it will not change across multiple calls or sessions. \bprog ? f = (x^2 + 1) * (x^2-1); ? factormodSQF(f,3) \\ squarefree over F_3 %2 = [Mod(1, 3)*x^4 + Mod(2, 3) 1] ? factormodDDF(f, 3) %3 = [Mod(1, 3)*x^2 + Mod(2, 3) 1] \\ two degree 1 factors [Mod(1, 3)*x^2 + Mod(1, 3) 2] \\ irred of degree 2 ? for(i=1,10^5,factormodDDF(f,3)) time = 424 ms. ? for(i=1,10^5,factormod(f,3)) \\ full factorization is slower time = 464 ms. ? liftall( factormodDDF(x^2 + 1, [3, t^2+1]) ) \\ over F_9 %6 = [x^2 + 1 1] \\ product of two degree 1 factors ? t = ffgen(t^2+Mod(1,3)); factormodDDF(x^2 + t^0) \\ same using t_FFELT %7 = [x^2 + 1 1] ? factormodDDF(x^2-Mod(1,3)) %8 = [Mod(1, 3)*x^2 + Mod(2, 3) 1] @eprog The library syntax is \fun{GEN}{factormodDDF}{GEN f, GEN D = NULL}. \subsec{factormodSQF$(f,\{D\})$}\kbdsidx{factormodSQF}\label{se:factormodSQF} Squarefree factorization of the polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. This is somewhat faster than full factorization. The coefficients of $f$ must be operation-compatible with the corresponding finite field. The result is a two-column matrix: \item the first column contains monic squarefree pairwise coprime polynomials dividing $f$; \item the second column contains the power to which the polynomial in column $1$ divides $f$; The factors are ordered by increasing degree and the result is canonical: it will not change across multiple calls or sessions. \bprog ? f = (x^2 + 1)^3 * (x^2-1)^2; ? factormodSQF(f, 3) \\ over F_3 %1 = [Mod(1, 3)*x^2 + Mod(2, 3) 2] [Mod(1, 3)*x^2 + Mod(1, 3) 3] ? for(i=1,10^5,factormodSQF(f,3)) time = 192 ms. ? for(i=1,10^5,factormod(f,3)) \\ full factorization is slower time = 409 ms. ? liftall( factormodSQF((x^2 + 1)^3, [3, t^2+1]) ) \\ over F_9 %4 = [x^2 + 1 3] ? t = ffgen(t^2+Mod(1,3)); factormodSQF((x^2 + t^0)^3) \\ same using t_FFELT %5 = [x^2 + 1 3] ? factormodSQF(x^8 + x^7 + x^6 + x^2 + x + Mod(1,2)) %6 = [ Mod(1, 2)*x + Mod(1, 2) 2] [Mod(1, 2)*x^2 + Mod(1, 2)*x + Mod(1, 2) 3] @eprog The library syntax is \fun{GEN}{factormodSQF}{GEN f, GEN D = NULL}. \subsec{ffcompomap$(f, g)$}\kbdsidx{ffcompomap}\label{se:ffcompomap} Let $k$, $l$, $m$ be three finite fields and $f$ a (partial) map from $l$ to $m$ and $g$ a (partial) map from $k$ to $l$, return the (partial) map $f \circ g$ from $k$ to $m$. \bprog a = ffgen([3,5],'a); b = ffgen([3,10],'b); c = ffgen([3,20],'c); m = ffembed(a, b); n = ffembed(b, c); rm = ffinvmap(m); rn = ffinvmap(n); nm = ffcompomap(n,m); ffmap(n,ffmap(m,a)) == ffmap(nm, a) %5 = 1 ffcompomap(rm, rn) == ffinvmap(nm) %6 = 1 @eprog The library syntax is \fun{GEN}{ffcompomap}{GEN f, GEN g}. \subsec{ffembed$(a, b)$}\kbdsidx{ffembed}\label{se:ffembed} Given two finite fields elements $a$ and $b$, return a \var{map} embedding the definition field of $a$ to the definition field of $b$. Assume that the latter contains the former. \bprog ? a = ffgen([3,5],'a); ? b = ffgen([3,10],'b); ? m = ffembed(a, b); ? A = ffmap(m, a); ? minpoly(A) == minpoly(a) %5 = 1 @eprog The library syntax is \fun{GEN}{ffembed}{GEN a, GEN b}. \subsec{ffextend$(a, P, \{v\})$}\kbdsidx{ffextend}\label{se:ffextend} Extend the field $K$ of definition of $a$ by a root of the polynomial $P\in K[X]$ assumed to be irreducible over $K$. Return $[r, m]$ where $r$ is a root of $P$ in the extension field $L$ and $m$ is a map from $K$ to $L$, see \kbd{ffmap}. If $v$ is given, the variable name is used to display the generator of $L$, else the name of the variable of $P$ is used. A generator of $L$ can be recovered using $b=ffgen(r)$. The image of $P$ in $L[X]$ can be recovered using $PL=ffmap(m,P)$. \bprog ? a = ffgen([3,5],'a); ? P = x^2-a; polisirreducible(P) %2 = 1 ? [r,m] = ffextend(a, P, 'b); ? r %3 = b^9+2*b^8+b^7+2*b^6+b^4+1 ? subst(ffmap(m, P), x, r) %4 = 0 ? ffgen(r) %5 = b @eprog The library syntax is \fun{GEN}{ffextend}{GEN a, GEN P, long v = -1} where \kbd{v} is a variable number. \subsec{fffrobenius$(m,\{n=1\})$}\kbdsidx{fffrobenius}\label{se:fffrobenius} Return the $n$-th power of the Frobenius map over the field of definition of $m$. \bprog ? a = ffgen([3,5],'a); ? f = fffrobenius(a); ? ffmap(f,a) == a^3 %3 = 1 ? g = fffrobenius(a, 5); ? ffmap(g,a) == a %5 = 1 ? h = fffrobenius(a, 2); ? h == ffcompomap(f,f) %7 = 1 @eprog The library syntax is \fun{GEN}{fffrobenius}{GEN m, long n}. \subsec{ffgen$(k,\{v = 'x\})$}\kbdsidx{ffgen}\label{se:ffgen} Return a generator for the finite field $k$ as a \typ{FFELT}. The field $k$ can be given by \item its order $q$ \item the pair $[p,f]$ where $q=p^f$ \item a monic irreducible polynomial with \typ{INTMOD} coefficients modulo a prime. \item a \typ{FFELT} belonging to $k$. If \kbd{v} is given, the variable name is used to display $g$, else the variable of the polynomial or the \typ{FFELT} is used, else $x$ is used. When only the order is specified, the function uses the polynomial generated by \kbd{ffinit} and is deterministic: two calls to the function with the same parameters will always give the same generator. For efficiency, the characteristic is not checked to be prime; similarly if a polynomial is given, we do not check whether it is irreducible. To obtain a multiplicative generator, call \kbd{ffprimroot} on the result. \bprog ? g = ffgen(16, 't); ? g.mod \\ recover the underlying polynomial. %2 = t^4+t^3+t^2+t+1 ? g.p \\ recover the characteristic %3 = 2 ? fforder(g) \\ g is not a multiplicative generator %4 = 5 ? a = ffprimroot(g) \\ recover a multiplicative generator %5 = t^3+t^2+t ? fforder(a) %6 = 15 @eprog The library syntax is \fun{GEN}{ffgen}{GEN k, long v = -1} where \kbd{v} is a variable number. To create a generator for a prime finite field, the function \fun{GEN}{p_to_GEN}{GEN p, long v} returns \kbd{ffgen(p,v)\^{}0}. \subsec{ffinit$(p,n,\{v='x\})$}\kbdsidx{ffinit}\label{se:ffinit} Computes a monic polynomial of degree $n$ which is irreducible over $\F_p$, where $p$ is assumed to be prime. This function uses a fast variant of Adleman and Lenstra's algorithm. It is useful in conjunction with \tet{ffgen}; for instance if \kbd{P = ffinit(3,2)}, you can represent elements in $\F_{3^2}$ in term of \kbd{g = ffgen(P,'t)}. This can be abbreviated as \kbd{g = ffgen(3\pow2, 't)}, where the defining polynomial $P$ can be later recovered as \kbd{g.mod}. The library syntax is \fun{GEN}{ffinit}{GEN p, long n, long v = -1} where \kbd{v} is a variable number. \subsec{ffinvmap$(m)$}\kbdsidx{ffinvmap}\label{se:ffinvmap} $m$ being a map from $K$ to $L$ two finite fields, return the partial map $p$ from $L$ to $K$ such that for all $k\in K$, $p(m(k))=k$. \bprog ? a = ffgen([3,5],'a); ? b = ffgen([3,10],'b); ? m = ffembed(a, b); ? p = ffinvmap(m); ? u = random(a); ? v = ffmap(m, u); ? ffmap(p, v^2+v+2) == u^2+u+2 %7 = 1 ? ffmap(p, b) %8 = [] @eprog The library syntax is \fun{GEN}{ffinvmap}{GEN m}. \subsec{fflog$(x,g,\{o\})$}\kbdsidx{fflog}\label{se:fflog} Discrete logarithm of the finite field element $x$ in base $g$, i.e.~an $e$ in $\Z$ such that $g^e = o$. If present, $o$ represents the multiplicative order of $g$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord} is the order of $g$. It may be set as a side effect of calling \tet{ffprimroot}. If no $o$ is given, assume that $g$ is a primitive root. The result is undefined if $e$ does not exist. This function uses \item a combination of generic discrete log algorithms (see \tet{znlog}) \item a cubic sieve index calculus algorithm for large fields of degree at least $5$. \item Coppersmith's algorithm for fields of characteristic at most $5$. \bprog ? t = ffgen(ffinit(7,5)); ? o = fforder(t) %2 = 5602 \\@com \emph{not} a primitive root. ? fflog(t^10,t) %3 = 10 ? fflog(t^10,t, o) %4 = 10 ? g = ffprimroot(t, &o); ? o \\ order is 16806, bundled with its factorization matrix %6 = [16806, [2, 1; 3, 1; 2801, 1]] ? fforder(g, o) %7 = 16806 ? fflog(g^10000, g, o) %8 = 10000 @eprog The library syntax is \fun{GEN}{fflog}{GEN x, GEN g, GEN o = NULL}. \subsec{ffmap$(m, x)$}\kbdsidx{ffmap}\label{se:ffmap} Given a (partial) map $m$ between two finite fields, return the image of $x$ by $m$. The function is applied recursively to the component of vectors, matrices and polynomials. If $m$ is a partial map that is not defined at $x$, return $[]$. \bprog ? a = ffgen([3,5],'a); ? b = ffgen([3,10],'b); ? m = ffembed(a, b); ? P = x^2+a*x+1; ? Q = ffmap(m,P); ? ffmap(m,poldisc(P)) == poldisc(Q) %6 = 1 @eprog The library syntax is \fun{GEN}{ffmap}{GEN m, GEN x}. \subsec{ffnbirred$(q,n,\{\var{fl}=0\})$}\kbdsidx{ffnbirred}\label{se:ffnbirred} Computes the number of monic irreducible polynomials over $\F_q$ of degree exactly $n$, ($\fl=0$ or omitted) or at most $n$ ($\fl=1$). The library syntax is \fun{GEN}{ffnbirred0}{GEN q, long n, long fl}. Also available are \fun{GEN}{ffnbirred}{GEN q, long n} (for $\fl=0$) and \fun{GEN}{ffsumnbirred}{GEN q, long n} (for $\fl=1$). \subsec{fforder$(x,\{o\})$}\kbdsidx{fforder}\label{se:fforder} Multiplicative order of the finite field element $x$. If $o$ is present, it represents a multiple of the order of the element, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[N, factor(N)]}, where \kbd{N} is the cardinality of the multiplicative group of the underlying finite field. \bprog ? t = ffgen(ffinit(nextprime(10^8), 5)); ? g = ffprimroot(t, &o); \\@com o will be useful! ? fforder(g^1000000, o) time = 0 ms. %5 = 5000001750000245000017150000600250008403 ? fforder(g^1000000) time = 16 ms. \\@com noticeably slower, same result of course %6 = 5000001750000245000017150000600250008403 @eprog The library syntax is \fun{GEN}{fforder}{GEN x, GEN o = NULL}. \subsec{ffprimroot$(x, \{\&o\})$}\kbdsidx{ffprimroot}\label{se:ffprimroot} Return a primitive root of the multiplicative group of the definition field of the finite field element $x$ (not necessarily the same as the field generated by $x$). If present, $o$ is set to a vector \kbd{[ord, fa]}, where \kbd{ord} is the order of the group and \kbd{fa} its factorization \kbd{factor(ord)}. This last parameter is useful in \tet{fflog} and \tet{fforder}, see \secref{se:DLfun}. \bprog ? t = ffgen(ffinit(nextprime(10^7), 5)); ? g = ffprimroot(t, &o); ? o[1] %3 = 100000950003610006859006516052476098 ? o[2] %4 = [2 1] [7 2] [31 1] [41 1] [67 1] [1523 1] [10498781 1] [15992881 1] [46858913131 1] ? fflog(g^1000000, g, o) time = 1,312 ms. %5 = 1000000 @eprog The library syntax is \fun{GEN}{ffprimroot}{GEN x, GEN *o = NULL}. \subsec{gcd$(x,\{y\})$}\kbdsidx{gcd}\label{se:gcd} Creates the greatest common divisor of $x$ and $y$. If you also need the $u$ and $v$ such that $x*u + y*v = \gcd(x,y)$, use the \tet{gcdext} function. $x$ and $y$ can have rather quite general types, for instance both rational numbers. If $y$ is omitted and $x$ is a vector, returns the $\text{gcd}$ of all components of $x$, i.e.~this is equivalent to \kbd{content(x)}. When $x$ and $y$ are both given and one of them is a vector/matrix type, the GCD is again taken recursively on each component, but in a different way. If $y$ is a vector, resp.~matrix, then the result has the same type as $y$, and components equal to \kbd{gcd(x, y[i])}, resp.~\kbd{gcd(x, y[,i])}. Else if $x$ is a vector/matrix the result has the same type as $x$ and an analogous definition. Note that for these types, \kbd{gcd} is not commutative. The algorithm used is a naive \idx{Euclid} except for the following inputs: \item integers: use modified right-shift binary (``plus-minus'' variant). \item univariate polynomials with coefficients in the same number field (in particular rational): use modular gcd algorithm. \item general polynomials: use the \idx{subresultant algorithm} if coefficient explosion is likely (non modular coefficients). If $u$ and $v$ are polynomials in the same variable with \emph{inexact} coefficients, their gcd is defined to be scalar, so that \bprog ? a = x + 0.0; gcd(a,a) %1 = 1 ? b = y*x + O(y); gcd(b,b) %2 = y ? c = 4*x + O(2^3); gcd(c,c) %3 = 4 @eprog\noindent A good quantitative check to decide whether such a gcd ``should be'' non-trivial, is to use \tet{polresultant}: a value close to $0$ means that a small deformation of the inputs has non-trivial gcd. You may also use \tet{gcdext}, which does try to compute an approximate gcd $d$ and provides $u$, $v$ to check whether $u x + v y$ is close to $d$. The library syntax is \fun{GEN}{ggcd0}{GEN x, GEN y = NULL}. Also available are \fun{GEN}{ggcd}{GEN x, GEN y}, if \kbd{y} is not \kbd{NULL}, and \fun{GEN}{content}{GEN x}, if $\kbd{y} = \kbd{NULL}$. \subsec{gcdext$(x,y)$}\kbdsidx{gcdext}\label{se:gcdext} Returns $[u,v,d]$ such that $d$ is the gcd of $x,y$, $x*u+y*v=\gcd(x,y)$, and $u$ and $v$ minimal in a natural sense. The arguments must be integers or polynomials. \sidx{extended gcd} \sidx{Bezout relation} \bprog ? [u, v, d] = gcdext(32,102) %1 = [16, -5, 2] ? d %2 = 2 ? gcdext(x^2-x, x^2+x-2) %3 = [-1/2, 1/2, x - 1] @eprog If $x,y$ are polynomials in the same variable and \emph{inexact} coefficients, then compute $u,v,d$ such that $x*u+y*v = d$, where $d$ approximately divides both and $x$ and $y$; in particular, we do not obtain \kbd{gcd(x,y)} which is \emph{defined} to be a scalar in this case: \bprog ? a = x + 0.0; gcd(a,a) %1 = 1 ? gcdext(a,a) %2 = [0, 1, x + 0.E-28] ? gcdext(x-Pi, 6*x^2-zeta(2)) %3 = [-6*x - 18.8495559, 1, 57.5726923] @eprog\noindent For inexact inputs, the output is thus not well defined mathematically, but you obtain explicit polynomials to check whether the approximation is close enough for your needs. The library syntax is \fun{GEN}{gcdext0}{GEN x, GEN y}. \subsec{hilbert$(x,y,\{p\})$}\kbdsidx{hilbert}\label{se:hilbert} \idx{Hilbert symbol} of $x$ and $y$ modulo the prime $p$, $p=0$ meaning the place at infinity (the result is undefined if $p\neq 0$ is not prime). It is possible to omit $p$, in which case we take $p = 0$ if both $x$ and $y$ are rational, or one of them is a real number. And take $p = q$ if one of $x$, $y$ is a \typ{INTMOD} modulo $q$ or a $q$-adic. (Incompatible types will raise an error.) The library syntax is \fun{long}{hilbert}{GEN x, GEN y, GEN p = NULL}. \subsec{isfundamental$(D)$}\kbdsidx{isfundamental}\label{se:isfundamental} True (1) if $D$ is equal to 1 or to the discriminant of a quadratic field, false (0) otherwise. $D$ can be input in factored form as for arithmetic functions: \bprog ? isfundamental(factor(-8)) %1 = 1 \\ count fundamental discriminants up to 10^8 ? c = 0; forfactored(d = 1, 10^8, if (isfundamental(d), c++)); c time = 40,840 ms. %2 = 30396325 ? c = 0; for(d = 1, 10^8, if (isfundamental(d), c++)); c time = 1min, 33,593 ms. \\ slower ! %3 = 30396325 @eprog The library syntax is \fun{long}{isfundamental}{GEN D}. \subsec{ispolygonal$(x,s,\{\&N\})$}\kbdsidx{ispolygonal}\label{se:ispolygonal} True (1) if the integer $x$ is an s-gonal number, false (0) if not. The parameter $s > 2$ must be a \typ{INT}. If $N$ is given, set it to $n$ if $x$ is the $n$-th $s$-gonal number. \bprog ? ispolygonal(36, 3, &N) %1 = 1 ? N @eprog The library syntax is \fun{long}{ispolygonal}{GEN x, GEN s, GEN *N = NULL}. \subsec{ispower$(x,\{k\},\{\&n\})$}\kbdsidx{ispower}\label{se:ispower} If $k$ is given, returns true (1) if $x$ is a $k$-th power, false (0) if not. What it means to be a $k$-th power depends on the type of $x$; see \tet{issquare} for details. If $k$ is omitted, only integers and fractions are allowed for $x$ and the function returns the maximal $k \geq 2$ such that $x = n^k$ is a perfect power, or 0 if no such $k$ exist; in particular \kbd{ispower(-1)}, \kbd{ispower(0)}, and \kbd{ispower(1)} all return $0$. If a third argument $\&n$ is given and $x$ is indeed a $k$-th power, sets $n$ to a $k$-th root of $x$. \noindent For a \typ{FFELT} \kbd{x}, instead of omitting \kbd{k} (which is not allowed for this type), it may be natural to set \bprog k = (x.p ^ x.f - 1) / fforder(x) @eprog The library syntax is \fun{long}{ispower}{GEN x, GEN k = NULL, GEN *n = NULL}. Also available is \fun{long}{gisanypower}{GEN x, GEN *pty} ($k$ omitted). \subsec{ispowerful$(x)$}\kbdsidx{ispowerful}\label{se:ispowerful} True (1) if $x$ is a powerful integer, false (0) if not; an integer is powerful if and only if its valuation at all primes dividing $x$ is greater than 1. \bprog ? ispowerful(50) %1 = 0 ? ispowerful(100) %2 = 1 ? ispowerful(5^3*(10^1000+1)^2) %3 = 1 @eprog The library syntax is \fun{long}{ispowerful}{GEN x}. \subsec{isprime$(x,\{\fl=0\})$}\kbdsidx{isprime}\label{se:isprime} True (1) if $x$ is a prime number, false (0) otherwise. A prime number is a positive integer having exactly two distinct divisors among the natural numbers, namely 1 and itself. This routine proves or disproves rigorously that a number is prime, which can be very slow when $x$ is indeed a large prime integer. For instance a $1000$ digits prime should require 15 to 30 minutes with default algorithms. Use \tet{ispseudoprime} to quickly check for compositeness. Use \tet{primecert} in order to obtain a primality proof instead of a yes/no answer; see also \kbd{factor}. The function accepts vector/matrices arguments, and is then applied componentwise. If $\fl=0$, use a combination of \item Baillie-Pomerance-Selfridge-Wagstaff compositeness test (see \tet{ispseudoprime}), \item Selfridge ``$p-1$'' test if $x-1$ is smooth enough, \item Adleman-Pomerance-Rumely-Cohen-Lenstra (APRCL) for general medium-sized $x$ (less than 1500 bits), \item Atkin-Morain's Elliptic Curve Primality Prover (ECPP) for general large $x$. If $\fl=1$, use Selfridge-Pocklington-Lehmer ``$p-1$'' test; this requires partially factoring various auxilliary integers and is likely to be very slow. If $\fl=2$, use APRCL only. If $\fl=3$, use ECPP only. The library syntax is \fun{GEN}{gisprime}{GEN x, long flag}. \subsec{isprimepower$(x,\{\&n\})$}\kbdsidx{isprimepower}\label{se:isprimepower} If $x = p^k$ is a prime power ($p$ prime, $k > 0$), return $k$, else return 0. If a second argument $\&n$ is given and $x$ is indeed the $k$-th power of a prime $p$, sets $n$ to $p$. The library syntax is \fun{long}{isprimepower}{GEN x, GEN *n = NULL}. \subsec{ispseudoprime$(x,\{\fl\})$}\kbdsidx{ispseudoprime}\label{se:ispseudoprime} True (1) if $x$ is a strong pseudo prime (see below), false (0) otherwise. If this function returns false, $x$ is not prime; if, on the other hand it returns true, it is only highly likely that $x$ is a prime number. Use \tet{isprime} (which is of course much slower) to prove that $x$ is indeed prime. The function accepts vector/matrices arguments, and is then applied componentwise. If $\fl = 0$, checks whether $x$ has no small prime divisors (up to $101$ included) and is a Baillie-Pomerance-Selfridge-Wagstaff pseudo prime. Such a pseudo prime passes a Rabin-Miller test for base $2$, followed by a Lucas test for the sequence $(P,1)$, where $P \geq 3$ is the smallest odd integer such that $P^2 - 4$ is not a square mod $x$. (Technically, we are using an ``almost extra strong Lucas test'' that checks whether $V_n$ is $\pm 2$, without computing $U_n$.) There are no known composite numbers passing the above test, although it is expected that infinitely many such numbers exist. In particular, all composites $\leq 2^{64}$ are correctly detected (checked using \url{http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html}). If $\fl > 0$, checks whether $x$ is a strong Miller-Rabin pseudo prime for $\fl$ randomly chosen bases (with end-matching to catch square roots of $-1$). The library syntax is \fun{GEN}{gispseudoprime}{GEN x, long flag}. \subsec{ispseudoprimepower$(x,\{\&n\})$}\kbdsidx{ispseudoprimepower}\label{se:ispseudoprimepower} If $x = p^k$ is a pseudo-prime power ($p$ pseudo-prime as per \tet{ispseudoprime}, $k > 0$), return $k$, else return 0. If a second argument $\&n$ is given and $x$ is indeed the $k$-th power of a prime $p$, sets $n$ to $p$. More precisely, $k$ is always the largest integer such that $x = n^k$ for some integer $n$ and, when $n \leq 2^{64}$ the function returns $k > 0$ if and only if $n$ is indeed prime. When $n > 2^{64}$ is larger than the threshold, the function may return $1$ even though $n$ is composite: it only passed an \kbd{ispseudoprime(n)} test. The library syntax is \fun{long}{ispseudoprimepower}{GEN x, GEN *n = NULL}. \subsec{issquare$(x,\{\&n\})$}\kbdsidx{issquare}\label{se:issquare} True (1) if $x$ is a square, false (0) if not. What ``being a square'' means depends on the type of $x$: all \typ{COMPLEX} are squares, as well as all non-negative \typ{REAL}; for exact types such as \typ{INT}, \typ{FRAC} and \typ{INTMOD}, squares are numbers of the form $s^2$ with $s$ in $\Z$, $\Q$ and $\Z/N\Z$ respectively. \bprog ? issquare(3) \\ as an integer %1 = 0 ? issquare(3.) \\ as a real number %2 = 1 ? issquare(Mod(7, 8)) \\ in Z/8Z %3 = 0 ? issquare( 5 + O(13^4) ) \\ in Q_13 %4 = 0 @eprog If $n$ is given, a square root of $x$ is put into $n$. \bprog ? issquare(4, &n) %1 = 1 ? n %2 = 2 @eprog For polynomials, either we detect that the characteristic is 2 (and check directly odd and even-power monomials) or we assume that $2$ is invertible and check whether squaring the truncated power series for the square root yields the original input. For \typ{POLMOD} $x$, we only support \typ{POLMOD}s of \typ{INTMOD}s encoding finite fields, assuming without checking that the intmod modulus $p$ is prime and that the polmod modulus is irreducible modulo $p$. \bprog ? issquare(Mod(Mod(2,3), x^2+1), &n) %1 = 1 ? n %2 = Mod(Mod(2, 3)*x, Mod(1, 3)*x^2 + Mod(1, 3)) @eprog The library syntax is \fun{long}{issquareall}{GEN x, GEN *n = NULL}. Also available is \fun{long}{issquare}{GEN x}. Deprecated GP-specific functions \fun{GEN}{gissquare}{GEN x} and \fun{GEN}{gissquareall}{GEN x, GEN *pt} return \kbd{gen\_0} and \kbd{gen\_1} instead of a boolean value. \subsec{issquarefree$(x)$}\kbdsidx{issquarefree}\label{se:issquarefree} True (1) if $x$ is squarefree, false (0) if not. Here $x$ can be an integer or a polynomial with coefficients in an integral domain. \bprog ? issquarefree(12) %1 = 0 ? issquarefree(6) %2 = 1 ? issquarefree(x^3+x^2) %3 = 0 ? issquarefree(Mod(1,4)*(x^2+x+1)) \\ Z/4Z is not a domain ! *** at top-level: issquarefree(Mod(1,4)*(x^2+x+1)) *** ^-------------------------------- *** issquarefree: impossible inverse in Fp_inv: Mod(2, 4). @eprog\noindent A polynomial is declared squarefree if \kbd{gcd}$(x,x')$ is $1$. In particular a non-zero polynomial with inexact coefficients is considered to be squarefree. Note that this may be inconsistent with \kbd{factor}, which first rounds the input to some exact approximation before factoring in the apropriate domain; this is correct when the input is not close to an inseparable polynomial (the resultant of $x$ and $x'$ is not close to $0$). An integer can be input in factored form as in arithmetic functions. \bprog ? issquarefree(factor(6)) %1 = 1 \\ count squarefree integers up to 10^8 ? c = 0; for(d = 1, 10^8, if (issquarefree(d), c++)); c time = 3min, 2,590 ms. %2 = 60792694 ? c = 0; forfactored(d = 1, 10^8, if (issquarefree(d), c++)); c time = 45,348 ms. \\ faster ! %3 = 60792694 @eprog The library syntax is \fun{long}{issquarefree}{GEN x}. \subsec{istotient$(x,\{\&N\})$}\kbdsidx{istotient}\label{se:istotient} True (1) if $x = \phi(n)$ for some integer $n$, false (0) if not. \bprog ? istotient(14) %1 = 0 ? istotient(100) %2 = 0 @eprog If $N$ is given, set $N = n$ as well. \bprog ? istotient(4, &n) %1 = 1 ? n %2 = 10 @eprog The library syntax is \fun{long}{istotient}{GEN x, GEN *N = NULL}. \subsec{kronecker$(x,y)$}\kbdsidx{kronecker}\label{se:kronecker} \idx{Kronecker symbol} $(x|y)$, where $x$ and $y$ must be of type integer. By definition, this is the extension of \idx{Legendre symbol} to $\Z \times \Z$ by total multiplicativity in both arguments with the following special rules for $y = 0, -1$ or $2$: \item $(x|0) = 1$ if $|x| = 1$ and $0$ otherwise. \item $(x|-1) = 1$ if $x \geq 0$ and $-1$ otherwise. \item $(x|2) = 0$ if $x$ is even and $1$ if $x = 1,-1 \mod 8$ and $-1$ if $x=3,-3 \mod 8$. The library syntax is \fun{long}{kronecker}{GEN x, GEN y}. \subsec{lcm$(x,\{y\})$}\kbdsidx{lcm}\label{se:lcm} Least common multiple of $x$ and $y$, i.e.~such that $\lcm(x,y)*\gcd(x,y) = x*y$, up to units. If $y$ is omitted and $x$ is a vector, returns the $\text{lcm}$ of all components of $x$. For integer arguments, return the non-negative \text{lcm}. When $x$ and $y$ are both given and one of them is a vector/matrix type, the LCM is again taken recursively on each component, but in a different way. If $y$ is a vector, resp.~matrix, then the result has the same type as $y$, and components equal to \kbd{lcm(x, y[i])}, resp.~\kbd{lcm(x, y[,i])}. Else if $x$ is a vector/matrix the result has the same type as $x$ and an analogous definition. Note that for these types, \kbd{lcm} is not commutative. Note that \kbd{lcm(v)} is quite different from \bprog l = v[1]; for (i = 1, #v, l = lcm(l, v[i])) @eprog\noindent Indeed, \kbd{lcm(v)} is a scalar, but \kbd{l} may not be (if one of the \kbd{v[i]} is a vector/matrix). The computation uses a divide-conquer tree and should be much more efficient, especially when using the GMP multiprecision kernel (and more subquadratic algorithms become available): \bprog ? v = vector(10^5, i, random); ? lcm(v); time = 546 ms. ? l = v[1]; for (i = 1, #v, l = lcm(l, v[i])) time = 4,561 ms. @eprog The library syntax is \fun{GEN}{glcm0}{GEN x, GEN y = NULL}. \subsec{logint$(x,b,\{\&z\})$}\kbdsidx{logint}\label{se:logint} Return the largest integer $e$ so that $b^e \leq x$, where the parameters $b > 1$ and $x > 0$ are both integers. If the parameter $z$ is present, set it to $b^e$. \bprog ? logint(1000, 2) %1 = 9 ? 2^9 %2 = 512 ? logint(1000, 2, &z) %3 = 9 ? z %4 = 512 @eprog\noindent The number of digits used to write $b$ in base $x$ is \kbd{1 + logint(x,b)}: \bprog ? #digits(1000!, 10) %5 = 2568 ? logint(1000!, 10) %6 = 2567 @eprog\noindent This function may conveniently replace \bprog floor( log(x) / log(b) ) @eprog\noindent which may not give the correct answer since PARI does not guarantee exact rounding. The library syntax is \fun{long}{logint0}{GEN x, GEN b, GEN *z = NULL}. \subsec{moebius$(x)$}\kbdsidx{moebius}\label{se:moebius} \idx{Moebius} $\mu$-function of $|x|$; $x$ must be a non-zero integer. The library syntax is \fun{long}{moebius}{GEN x}. \subsec{nextprime$(x)$}\kbdsidx{nextprime}\label{se:nextprime} Finds the smallest pseudoprime (see \tet{ispseudoprime}) greater than or equal to $x$. $x$ can be of any real type. Note that if $x$ is a pseudoprime, this function returns $x$ and not the smallest pseudoprime strictly larger than $x$. To rigorously prove that the result is prime, use \kbd{isprime}. The library syntax is \fun{GEN}{nextprime}{GEN x}. \subsec{numdiv$(x)$}\kbdsidx{numdiv}\label{se:numdiv} Number of divisors of $|x|$. $x$ must be of type integer. The library syntax is \fun{GEN}{numdiv}{GEN x}. \subsec{omega$(x)$}\kbdsidx{omega}\label{se:omega} Number of distinct prime divisors of $|x|$. $x$ must be of type integer. \bprog ? factor(392) %1 = [2 3] [7 2] ? omega(392) %2 = 2; \\ without multiplicity ? bigomega(392) %3 = 5; \\ = 3+2, with multiplicity @eprog The library syntax is \fun{long}{omega}{GEN x}. \subsec{precprime$(x)$}\kbdsidx{precprime}\label{se:precprime} Finds the largest pseudoprime (see \tet{ispseudoprime}) less than or equal to $x$. $x$ can be of any real type. Returns 0 if $x\le1$. Note that if $x$ is a prime, this function returns $x$ and not the largest prime strictly smaller than $x$. To rigorously prove that the result is prime, use \kbd{isprime}. The library syntax is \fun{GEN}{precprime}{GEN x}. \subsec{prime$(n)$}\kbdsidx{prime}\label{se:prime} The $n^{\text{th}}$ prime number \bprog ? prime(10^9) %1 = 22801763489 @eprog\noindent Uses checkpointing and a naive $O(n)$ algorithm. Will need about 30 minutes for $n$ up to $10^{11}$; make sure to start gp with \kbd{primelimit} at least $\sqrt{p_n}$, e.g. the value $\sqrt{n\log (n\log n)}$ is guaranteed to be sufficient. The library syntax is \fun{GEN}{prime}{long n}. \subsec{primecert$(N, \{\fl=0\})$}\kbdsidx{primecert}\label{se:primecert} If N is a prime, return a PARI Primality Certificate for the prime $N$, as described below. Otherwise, return 0. A Primality Certificate $c$ can be checked using \tet{primecertisvalid}$(c)$. If $\fl = 0$ (default), return an ECPP certificate (Atkin-Morain) A PARI ECPP Primality Certificate for the prime $N$ is either a prime integer $N < 2^{64}$ or a vector \kbd{C} of length $\ell$ whose $i$th component \kbd{C[i]} is a vector of length $5$ containing $N_i$, $t_i$, $s_i$, $a_i$, $P_i$ (in that order) where $N_1 = N$. It is said to be valid if for each $i = 1, \ldots, \ell$, all of the following conditions are satisfied \item $N_i$ is a positive integer \item $t_i$ is an integer such that $t_i < 4N_i^2$ \item $s_i$ is a positive integer which divides $m_i$ where $m_i = N_i + 1 - t_i$ \item If we set $q_i = \dfrac{m_i}{s_i}$, then \quad\item $q_i > (N_i^{1/4}+1)^2$ \quad\item $q_i = N_{i+1}$ if $1 \leq i < l$ \quad\item $q_\ell \leq 2^{64}$ is prime \item $a_i$ is an integer \quad\item \kbd{P[i]} is a vector of length $2$ representing the affine point $P_i = (x_i, y_i)$ on the elliptic curve $E: y^2 = x^3 + a_ix + b_i$ modulo $N_i$ where $b_i = y_i^2 - x_i^3 - a_ix_i$ satisfying the following: \quad\item $m_i P_i = \infty$ \quad\item $s_i P_i \neq \infty$ \misctitle{Theorem} If $N$ is an integer and there exist positive integers $m, q$ and a point $P$ on the elliptic curve $E: y^2 = x^3 + ax + b$ defined modulo $N$ such that $q > (N^{1/4} + 1)^2$, $q$ is a prime divisor of $m$, $mP = \infty$ and $\dfrac{m}{q}P \neq \infty$, then $N$ is prime. Using the above theorem, the data in the vector \kbd{C} can be used to certify the primality of $N$ assuming $q_\ell$ is prime. \bprog ? primecert(10^35 + 69) %1 = [[100000000000000000000000000000000069, 5468679110354 52074, 2963504668391148, 0, [60737979324046450274283740674 208692, 24368673584839493121227731392450025]], [3374383076 4501150277, -11610830419, 734208843, 0, [26740412374402652 72 4, 6367191119818901665]], [45959444779, 299597, 2331, 0 , [18022351516, 9326882 51]]] ? primecert(nextprime(2^64)) %2 = [[18446744073709551629, -8423788454, 160388, 1, [1059 8342506117936052, 2225259013356795550]]] ? primecert(6) %3 = 0 ? primecert(41) %4 = 41 @eprog\smallskip If $\fl = 1$ (very slow), return an $N-1$ certificate (Pocklington Lehmer) A PARI $N-1$ Primality Certificate for the prime $N$ is either a prime integer $N < 2^{64}$ or a pair $[N, C]$, where $C$ is a vector with $\ell$ elements which are either a single integer $p_i < 2^{64}$ or a triple $[p_i,a_i,C_i]$ with $p_i > 2^{64}$ satisfying the following properties: \item $p_i$ is a prime divisor of $N - 1$; \item $a_i$ is an integer such that $a_i^{N-1} \equiv 1 \pmod{N}$ and $a_i^{(N-1)/p_i} - 1$ is coprime with $N$; \item $C_i$ is an $N-1$ Primality Certificate for $p_i$ \item The product $F$ of the $p_i^{v_{p_i}(N-1)}$ is strictly larger than $N^{1/3}$. Provided that all $p_i$ are indeed primes, this implies that any divisor of $N$ is congruent to $1$ modulo $F$. \item The Billhart, Lehmer, Selfridge criterion is satisfied: when we write $N = 1 + c_1 F + c_2 F^2$ in base $F$ the polynomial $1 + c_1 X + c_2 X^2$ is irreducible over $\Z$, i.e. $c_1^2 - 4c_2$ is not a square. This implies that $N$ is prime. This algorithm requires factoring partially $p-1$ for various prime integers $p$ with an unfactored parted $\leq p^{2/3}$ and this may be exceedingly slow compared to the default. The algorithm fails if one of the pseudo-prime factors is not prime, which is exceedingly unlikely and well worth a bug report. Note that if you monitor the algorithm at a high enough debug level, you may see warnings about untested integers being declared primes. This is normal: we ask for partial factorizations (sufficient to prove primality if the unfactored part is not too large), and \kbd{factor} warns us that the cofactor hasn't been tested. It may or may not be tested later, and may or may not be prime. This does not affect the validity of the whole Primality Certificate. The library syntax is \fun{GEN}{primecert}{GEN N, long flag}. \subsec{primecertexport$(\var{cert}, \{\var{format} = 0\})$}\kbdsidx{primecertexport}\label{se:primecertexport} Returns a string suitable for print/write to display a primality certificate from \tet{primecert}, the format of which depends on the value of \kbd{format}: \item 0 (default): Human-readable format. \item 1: Primo format 4. \item 2: MAGMA format. Currently, only ECPP Primality Certificates are supported. \bprog ? cert = primecert(10^35+69); ? s = primecertexport(cert); \\ Human-readable ? print(s) [1] N = 100000000000000000000000000000000069 t = 546867911035452074 s = 2963504668391148 a4 = 0 D = -3 m = 99999999999999999453132088964547996 q = 33743830764501150277 E = [0, 1] P = [21567861682493263464353543707814204, 49167839501923147849639425291163552] [2] N = 33743830764501150277 t = -11610830419 s = 734208843 a4 = 0 D = -3 m = 33743830776111980697 q = 45959444779 E = [0, 25895956964997806805] P = [29257172487394218479, 3678591960085668324] \\ Primo format ? s = primecertexport(cert,1); write("cert.out", s); \\ Magma format, write to file ? s = primecertexport(cert,2); write("cert.m", s); ? cert = primecert(10^35+69, 1); \\ N-1 certificate *** at top-level: primecertexport(cert) *** ^--------------------- *** primecertexport: sorry, N-1 certificate is not yet implemented. @eprog The library syntax is \fun{GEN}{primecertexport}{GEN cert, long format}. \subsec{primecertisvalid$(\var{cert})$}\kbdsidx{primecertisvalid}\label{se:primecertisvalid} Verifies if cert is a valid PARI ECPP Primality certificate, as described in \kbd{??primecert}. \bprog ? cert = primecert(10^35 + 69) %1 = [[100000000000000000000000000000000069, 5468679110354 52074, 2963504668391148, 0, [60737979324046450274283740674 208692, 24368673584839493121227731392450025]], [3374383076 4501150277, -11610830419, 734208843, 0, [26740412374402652 72 4, 6367191119818901665]], [45959444779, 299597, 2331, 0 , [18022351516, 9326882 51]]] ? primecertisvalid(cert) %2 = 1 ? cert[1][1]++; \\ random perturbation ? primecertisvalid(cert) %4 = 0 \\ no longer valid ? primecertisvalid(primecert(6)) %5 = 0 @eprog The library syntax is \fun{long}{primecertisvalid}{GEN cert}. \subsec{primepi$(x)$}\kbdsidx{primepi}\label{se:primepi} The prime counting function. Returns the number of primes $p$, $p \leq x$. \bprog ? primepi(10) %1 = 4; ? primes(5) %2 = [2, 3, 5, 7, 11] ? primepi(10^11) %3 = 4118054813 @eprog\noindent Uses checkpointing and a naive $O(x)$ algorithm; make sure to start gp with \kbd{primelimit} at least $\sqrt{x}$. The library syntax is \fun{GEN}{primepi}{GEN x}. \subsec{primes$(n)$}\kbdsidx{primes}\label{se:primes} Creates a row vector whose components are the first $n$ prime numbers. (Returns the empty vector for $n \leq 0$.) A \typ{VEC} $n = [a,b]$ is also allowed, in which case the primes in $[a,b]$ are returned \bprog ? primes(10) \\ the first 10 primes %1 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] ? primes([0,29]) \\ the primes up to 29 %2 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] ? primes([15,30]) %3 = [17, 19, 23, 29] @eprog The library syntax is \fun{GEN}{primes0}{GEN n}. \subsec{qfbclassno$(D,\{\fl=0\})$}\kbdsidx{qfbclassno}\label{se:qfbclassno} Ordinary class number of the quadratic order of discriminant $D$, for ``small'' values of $D$. \item if $D > 0$ or $\fl = 1$, use a $O(|D|^{1/2})$ algorithm (compute $L(1,\chi_D)$ with the approximate functional equation). This is slower than \tet{quadclassunit} as soon as $|D| \approx 10^2$ or so and is not meant to be used for large $D$. \item if $D < 0$ and $\fl = 0$ (or omitted), use a $O(|D|^{1/4})$ algorithm (Shanks's baby-step/giant-step method). It should be faster than \tet{quadclassunit} for small values of $D$, say $|D| < 10^{18}$. \misctitle{Important warning} In the latter case, this function only implements part of \idx{Shanks}'s method (which allows to speed it up considerably). It gives unconditionnally correct results for $|D| < 2\cdot 10^{10}$, but may give incorrect results for larger values if the class group has many cyclic factors. We thus recommend to double-check results using the function \kbd{quadclassunit}, which is about 2 to 3 times slower in the range $|D| \in [10^{10}, 10^{18}]$, assuming GRH. We currently have no counter-examples but they should exist: we would appreciate a bug report if you find one. \misctitle{Warning} Contrary to what its name implies, this routine does not compute the number of classes of binary primitive forms of discriminant $D$, which is equal to the \emph{narrow} class number. The two notions are the same when $D < 0$ or the fundamental unit $\varepsilon$ has negative norm; when $D > 0$ and $N\varepsilon > 0$, the number of classes of forms is twice the ordinary class number. This is a problem which we cannot fix for backward compatibility reasons. Use the following routine if you are only interested in the number of classes of forms: \bprog QFBclassno(D) = qfbclassno(D) * if (D < 0 || norm(quadunit(D)) < 0, 1, 2) @eprog\noindent Here are a few examples: \bprog ? qfbclassno(400000028) \\ D > 0: slow time = 3,140 ms. %1 = 1 ? quadclassunit(400000028).no time = 20 ms. \\@com{ much faster, assume GRH} %2 = 1 ? qfbclassno(-400000028) \\ D < 0: fast enough time = 0 ms. %3 = 7253 ? quadclassunit(-400000028).no time = 0 ms. %4 = 7253 @eprog\noindent See also \kbd{qfbhclassno}. The library syntax is \fun{GEN}{qfbclassno0}{GEN D, long flag}. \subsec{qfbcompraw$(x,y)$}\kbdsidx{qfbcompraw}\label{se:qfbcompraw} \idx{composition} of the binary quadratic forms $x$ and $y$, without \idx{reduction} of the result. This is useful e.g.~to compute a generating element of an ideal. The result is undefined if $x$ and $y$ do not have the same discriminant. The library syntax is \fun{GEN}{qfbcompraw}{GEN x, GEN y}. \subsec{qfbhclassno$(x)$}\kbdsidx{qfbhclassno}\label{se:qfbhclassno} \idx{Hurwitz class number} of $x$, when $x$ is non-negative and congruent to 0 or 3 modulo 4, and $0$ for other values. For $x > 5\cdot 10^5$, we assume the GRH, and use \kbd{quadclassunit} with default parameters. \bprog ? qfbhclassno(1) \\ not 0 or 3 mod 4 %1 = 0 ? qfbhclassno(3) %2 = 1/3 ? qfbhclassno(4) %3 = 1/2 ? qfbhclassno(23) %4 = 3 @eprog The library syntax is \fun{GEN}{hclassno}{GEN x}. \subsec{qfbnucomp$(x,y,L)$}\kbdsidx{qfbnucomp}\label{se:qfbnucomp} \idx{composition} of the primitive positive definite binary quadratic forms $x$ and $y$ (type \typ{QFI}) using the NUCOMP and NUDUPL algorithms of \idx{Shanks}, \`a la Atkin. $L$ is any positive constant, but for optimal speed, one should take $L=|D/4|^{1/4}$, i.e. \kbd{sqrtnint(abs(D)>>2,4)}, where $D$ is the common discriminant of $x$ and $y$. When $x$ and $y$ do not have the same discriminant, the result is undefined. The current implementation is slower than the generic routine for small $D$, and becomes faster when $D$ has about $45$ bits. The library syntax is \fun{GEN}{nucomp}{GEN x, GEN y, GEN L}. Also available is \fun{GEN}{nudupl}{GEN x, GEN L} when $x=y$. \subsec{qfbnupow$(x,n,\{L\})$}\kbdsidx{qfbnupow}\label{se:qfbnupow} $n$-th power of the primitive positive definite binary quadratic form $x$ using \idx{Shanks}'s NUCOMP and NUDUPL algorithms; if set, $L$ should be equal to \kbd{sqrtnint(abs(D)>>2,4)}, where $D < 0$ is the discriminant of $x$. The current implementation is slower than the generic routine for small discriminant $D$, and becomes faster for $D \approx 2^{45}$. The library syntax is \fun{GEN}{nupow}{GEN x, GEN n, GEN L = NULL}. \subsec{qfbpowraw$(x,n)$}\kbdsidx{qfbpowraw}\label{se:qfbpowraw} $n$-th power of the binary quadratic form $x$, computed without doing any \idx{reduction} (i.e.~using \kbd{qfbcompraw}). Here $n$ must be non-negative and $n<2^{31}$. The library syntax is \fun{GEN}{qfbpowraw}{GEN x, long n}. \subsec{qfbprimeform$(x,p)$}\kbdsidx{qfbprimeform}\label{se:qfbprimeform} Prime binary quadratic form of discriminant $x$ whose first coefficient is $p$, where $|p|$ is a prime number. By abuse of notation, $p = \pm 1$ is also valid and returns the unit form. Returns an error if $x$ is not a quadratic residue mod $p$, or if $x < 0$ and $p < 0$. (Negative definite \typ{QFI} are not implemented.) In the case where $x>0$, the ``distance'' component of the form is set equal to zero according to the current precision. The library syntax is \fun{GEN}{primeform}{GEN x, GEN p, long prec}. \subsec{qfbred$(x,\{\fl=0\},\{d\},\{\var{isd}\},\{\var{sd}\})$}\kbdsidx{qfbred}\label{se:qfbred} Reduces the binary quadratic form $x$ (updating Shanks's distance function if $x$ is indefinite). The binary digits of $\fl$ are toggles meaning \quad 1: perform a single \idx{reduction} step \quad 2: don't update \idx{Shanks}'s distance The arguments $d$, \var{isd}, \var{sd}, if present, supply the values of the discriminant, $\floor{\sqrt{d}}$, and $\sqrt{d}$ respectively (no checking is done of these facts). If $d<0$ these values are useless, and all references to Shanks's distance are irrelevant. The library syntax is \fun{GEN}{qfbred0}{GEN x, long flag, GEN d = NULL, GEN isd = NULL, GEN sd = NULL}. Also available are \fun{GEN}{redimag}{GEN x} (for definite $x$), \noindent and for indefinite forms: \fun{GEN}{redreal}{GEN x} \fun{GEN}{rhoreal}{GEN x} (= \kbd{qfbred(x,1)}), \fun{GEN}{redrealnod}{GEN x, GEN isd} (= \kbd{qfbred(x,2,,isd)}), \fun{GEN}{rhorealnod}{GEN x, GEN isd} (= \kbd{qfbred(x,3,,isd)}). \subsec{qfbredsl2$(x,\{\var{data}\})$}\kbdsidx{qfbredsl2}\label{se:qfbredsl2} Reduction of the (real or imaginary) binary quadratic form $x$, return $[y,g]$ where $y$ is reduced and $g$ in $\text{SL}(2,\Z)$ is such that $g \cdot x = y$; \var{data}, if present, must be equal to $[D, \kbd{sqrtint}(D)]$, where $D > 0$ is the discriminant of $x$. In case $x$ is a \typ{QFR}, the distance component is unaffected. The library syntax is \fun{GEN}{qfbredsl2}{GEN x, GEN data = NULL}. \subsec{qfbsolve$(Q,p)$}\kbdsidx{qfbsolve}\label{se:qfbsolve} Solve the equation $Q(x,y)=p$ over the integers, where $Q$ is a binary quadratic form and $p$ a prime number. Return $[x,y]$ as a two-components vector, or zero if there is no solution. Note that this function returns only one solution and not all the solutions. Let $D = \disc Q$. The algorithm used runs in probabilistic polynomial time in $p$ (through the computation of a square root of $D$ modulo $p$); it is polynomial time in $D$ if $Q$ is imaginary, but exponential time if $Q$ is real (through the computation of a full cycle of reduced forms). In the latter case, note that \tet{bnfisprincipal} provides a solution in heuristic subexponential time in $D$ assuming the GRH. The library syntax is \fun{GEN}{qfbsolve}{GEN Q, GEN p}. \subsec{quadclassunit$(D,\{\fl=0\},\{\var{tech}=[\,]\})$}\kbdsidx{quadclassunit}\label{se:quadclassunit} \idx{Buchmann-McCurley}'s sub-exponential algorithm for computing the class group of a quadratic order of discriminant $D$. This function should be used instead of \tet{qfbclassno} or \tet{quadregula} when $D<-10^{25}$, $D>10^{10}$, or when the \emph{structure} is wanted. It is a special case of \tet{bnfinit}, which is slower, but more robust. The result is a vector $v$ whose components should be accessed using member functions: \item \kbd{$v$.no}: the class number \item \kbd{$v$.cyc}: a vector giving the structure of the class group as a product of cyclic groups; \item \kbd{$v$.gen}: a vector giving generators of those cyclic groups (as binary quadratic forms). \item \kbd{$v$.reg}: the regulator, computed to an accuracy which is the maximum of an internal accuracy determined by the program and the current default (note that once the regulator is known to a small accuracy it is trivial to compute it to very high accuracy, see the tutorial). The $\fl$ is obsolete and should be left alone. In older versions, it supposedly computed the narrow class group when $D>0$, but this did not work at all; use the general function \tet{bnfnarrow}. Optional parameter \var{tech} is a row vector of the form $[c_1, c_2]$, where $c_1 \leq c_2$ are non-negative real numbers which control the execution time and the stack size, see \ref{se:GRHbnf}. The parameter is used as a threshold to balance the relation finding phase against the final linear algebra. Increasing the default $c_1$ means that relations are easier to find, but more relations are needed and the linear algebra will be harder. The default value for $c_1$ is $0$ and means that it is taken equal to $c_2$. The parameter $c_2$ is mostly obsolete and should not be changed, but we still document it for completeness: we compute a tentative class group by generators and relations using a factorbase of prime ideals $\leq c_1 (\log |D|)^2$, then prove that ideals of norm $\leq c_2 (\log |D|)^2$ do not generate a larger group. By default an optimal $c_2$ is chosen, so that the result is provably correct under the GRH --- a famous result of Bach states that $c_2 = 6$ is fine, but it is possible to improve on this algorithmically. You may provide a smaller $c_2$, it will be ignored (we use the provably correct one); you may provide a larger $c_2$ than the default value, which results in longer computing times for equally correct outputs (under GRH). The library syntax is \fun{GEN}{quadclassunit0}{GEN D, long flag, GEN tech = NULL, long prec}. If you really need to experiment with the \var{tech} parameter, it is usually more convenient to use \fun{GEN}{Buchquad}{GEN D, double c1, double c2, long prec}. If only the class number is needed, \fun{GEN}{quadclassno}{GEN D} will be faster (still assuming the GRH), but will not provide the group structure. For negative $D$, $|D| < 10^{20}$, \tet{qfbclassno} should be faster but may return a wrong result. \subsec{quaddisc$(x)$}\kbdsidx{quaddisc}\label{se:quaddisc} Discriminant of the \'etale algebra $\Q(\sqrt{x})$, where $x\in\Q^*$. This is the same as \kbd{coredisc}$(d)$ where $d$ is the integer square-free part of $x$, so x=$d f^2$ with $f\in \Q^*$ and $d\in\Z$. This returns $0$ for $x = 0$, $1$ for $x$ square and the discriminant of the quadratic field $\Q(\sqrt{x})$ otherwise. \bprog ? quaddisc(7) %1 = 28 ? quaddisc(-7) %2 = -7 @eprog The library syntax is \fun{GEN}{quaddisc}{GEN x}. \subsec{quadgen$(D,\{v = 'w\})$}\kbdsidx{quadgen}\label{se:quadgen} Creates the quadratic number\sidx{omega} $\omega=(a+\sqrt{D})/2$ where $a=0$ if $D\equiv0\mod4$, $a=1$ if $D\equiv1\mod4$, so that $(1,\omega)$ is an integral basis for the quadratic order of discriminant $D$. $D$ must be an integer congruent to 0 or 1 modulo 4, which is not a square. If \var{v} is given, the variable name is used to display $g$ else 'w' is used. \bprog ? w = quadgen(5, 'w); w^2 - w - 1 %1 = 0 ? w = quadgen(0, 'w) *** at top-level: w=quadgen(0) *** ^---------- *** quadgen: domain error in quadpoly: issquare(disc) = 1 @eprog The library syntax is \fun{GEN}{quadgen0}{GEN D, long v = -1} where \kbd{v} is a variable number. When \var{v} does not matter, the function \fun{GEN}{quadgen}{GEN D} is also available. \subsec{quadhilbert$(D)$}\kbdsidx{quadhilbert}\label{se:quadhilbert} Relative equation defining the \idx{Hilbert class field} of the quadratic field of discriminant $D$. If $D < 0$, uses complex multiplication (\idx{Schertz}'s variant). If $D > 0$ \idx{Stark units} are used and (in rare cases) a vector of extensions may be returned whose compositum is the requested class field. See \kbd{bnrstark} for details. The library syntax is \fun{GEN}{quadhilbert}{GEN D, long prec}. \subsec{quadpoly$(D,\{v='x\})$}\kbdsidx{quadpoly}\label{se:quadpoly} Creates the ``canonical'' quadratic polynomial (in the variable $v$) corresponding to the discriminant $D$, i.e.~the minimal polynomial of $\kbd{quadgen}(D)$. $D$ must be an integer congruent to 0 or 1 modulo 4, which is not a square. \bprog ? quadpoly(5,'y) %1 = y^2 - y - 1 ? quadpoly(0,'y) *** at top-level: quadpoly(0,'y) *** ^-------------- *** quadpoly: domain error in quadpoly: issquare(disc) = 1 @eprog The library syntax is \fun{GEN}{quadpoly0}{GEN D, long v = -1} where \kbd{v} is a variable number. \subsec{quadray$(D,f)$}\kbdsidx{quadray}\label{se:quadray} Relative equation for the ray class field of conductor $f$ for the quadratic field of discriminant $D$ using analytic methods. A \kbd{bnf} for $x^2 - D$ is also accepted in place of $D$. For $D < 0$, uses the $\sigma$ function and Schertz's method. For $D>0$, uses Stark's conjecture, and a vector of relative equations may be returned. See \tet{bnrstark} for more details. The library syntax is \fun{GEN}{quadray}{GEN D, GEN f, long prec}. \subsec{quadregulator$(x)$}\kbdsidx{quadregulator}\label{se:quadregulator} Regulator of the quadratic field of positive discriminant $x$. Returns an error if $x$ is not a discriminant (fundamental or not) or if $x$ is a square. See also \kbd{quadclassunit} if $x$ is large. The library syntax is \fun{GEN}{quadregulator}{GEN x, long prec}. \subsec{quadunit$(D,\{v = 'w\})$}\kbdsidx{quadunit}\label{se:quadunit} Fundamental unit\sidx{fundamental units} $u$ of the real quadratic field $\Q(\sqrt D)$ where $D$ is the positive discriminant of the field. If $D$ is not a fundamental discriminant, this probably gives the fundamental unit of the corresponding order. $D$ must be an integer congruent to 0 or 1 modulo 4, which is not a square; the result is a quadratic number (see \secref{se:quadgen}). If \var{v} is given, the variable name is used to display $u$ else 'w' is used. The library syntax is \fun{GEN}{quadunit0}{GEN D, long v = -1} where \kbd{v} is a variable number. When \var{v} does not matter, the function \fun{GEN}{quadunit}{GEN D} is also available. \subsec{ramanujantau$(n)$}\kbdsidx{ramanujantau}\label{se:ramanujantau} Compute the value of Ramanujan's tau function at an individual $n$, assuming the truth of the GRH (to compute quickly class numbers of imaginary quadratic fields using \tet{quadclassunit}). Algorithm in $\tilde{O}(n^{1/2})$ using $O(\log n)$ space. If all values up to $N$ are required, then $$\sum \tau(n)q^n = q \prod_{n\geq 1} (1-q^n)^{24}$$ will produce them in time $\tilde{O}(N)$, against $\tilde{O}(N^{3/2})$ for individual calls to \kbd{ramanujantau}; of course the space complexity then becomes $\tilde{O}(N)$. \bprog ? tauvec(N) = Vec(q*eta(q + O(q^N))^24); ? N = 10^4; v = tauvec(N); time = 26 ms. ? ramanujantau(N) %3 = -482606811957501440000 ? w = vector(N, n, ramanujantau(n)); \\ much slower ! time = 13,190 ms. ? v == w %4 = 1 @eprog The library syntax is \fun{GEN}{ramanujantau}{GEN n}. \subsec{randomprime$(\{N = 2^{31}\})$}\kbdsidx{randomprime}\label{se:randomprime} Returns a strong pseudo prime (see \tet{ispseudoprime}) in $[2,N-1]$. A \typ{VEC} $N = [a,b]$ is also allowed, with $a \leq b$ in which case a pseudo prime $a \leq p \leq b$ is returned; if no prime exists in the interval, the function will run into an infinite loop. If the upper bound is less than $2^{64}$ the pseudo prime returned is a proven prime. The library syntax is \fun{GEN}{randomprime}{GEN N = NULL}. \subsec{removeprimes$(\{x=[\,]\})$}\kbdsidx{removeprimes}\label{se:removeprimes} Removes the primes listed in $x$ from the prime number table. In particular \kbd{removeprimes(addprimes())} empties the extra prime table. $x$ can also be a single integer. List the current extra primes if $x$ is omitted. The library syntax is \fun{GEN}{removeprimes}{GEN x = NULL}. \subsec{sigma$(x,\{k=1\})$}\kbdsidx{sigma}\label{se:sigma} Sum of the $k^{\text{th}}$ powers of the positive divisors of $|x|$. $x$ and $k$ must be of type integer. The library syntax is \fun{GEN}{sumdivk}{GEN x, long k}. Also available is \fun{GEN}{sumdiv}{GEN n}, for $k = 1$. \subsec{sqrtint$(x)$}\kbdsidx{sqrtint}\label{se:sqrtint} Returns the integer square root of $x$, i.e. the largest integer $y$ such that $y^2 \leq x$, where $x$ a non-negative integer. \bprog ? N = 120938191237; sqrtint(N) %1 = 347761 ? sqrt(N) %2 = 347761.68741970412747602130964414095216 @eprog The library syntax is \fun{GEN}{sqrtint}{GEN x}. \subsec{sqrtnint$(x,n)$}\kbdsidx{sqrtnint}\label{se:sqrtnint} Returns the integer $n$-th root of $x$, i.e. the largest integer $y$ such that $y^n \leq x$, where $x$ is a non-negative integer. \bprog ? N = 120938191237; sqrtnint(N, 5) %1 = 164 ? N^(1/5) %2 = 164.63140849829660842958614676939677391 @eprog\noindent The special case $n = 2$ is \tet{sqrtint} The library syntax is \fun{GEN}{sqrtnint}{GEN x, long n}. \subsec{sumdedekind$(h,k)$}\kbdsidx{sumdedekind}\label{se:sumdedekind} Returns the \idx{Dedekind sum} attached to the integers $h$ and $k$, corresponding to a fast implementation of \bprog s(h,k) = sum(n = 1, k-1, (n/k)*(frac(h*n/k) - 1/2)) @eprog The library syntax is \fun{GEN}{sumdedekind}{GEN h, GEN k}. \subsec{sumdigits$(n,\{B=10\})$}\kbdsidx{sumdigits}\label{se:sumdigits} Sum of digits in the integer $|n|$, when written in base $B > 1$. \bprog ? sumdigits(123456789) %1 = 45 ? sumdigits(123456789, 2) %1 = 16 @eprog\noindent Note that the sum of bits in $n$ is also returned by \tet{hammingweight}. This function is much faster than \kbd{vecsum(digits(n,B))} when $B$ is $10$ or a power of $2$, and only slightly faster in other cases. The library syntax is \fun{GEN}{sumdigits0}{GEN n, GEN B = NULL}. Also available is \fun{GEN}{sumdigits}{GEN n}, for $B = 10$. \subsec{znchar$(D)$}\kbdsidx{znchar}\label{se:znchar} Given a datum $D$ describing a group $(\Z/N\Z)^*$ and a Dirichlet character $\chi$, return the pair \kbd{[G, chi]}, where \kbd{G} is \kbd{znstar(N, 1)}) and \kbd{chi} is a GP character. The following possibilities for $D$ are supported \item a non-zero \typ{INT} congruent to $0,1$ modulo $4$, return the real character modulo $D$ given by the Kronecker symbol $(D/.)$; \item a \typ{INTMOD} \kbd{Mod(m, N)}, return the Conrey character modulo $N$ of index $m$ (see \kbd{znconreylog}). \item a modular form space as per \kbd{mfinit}$([N,k,\chi])$ or a modular form for such a space, return the underlying Dirichlet character $\chi$ (which may be defined modulo a divisor of $N$ but need not be primitive). In the remaining cases, \kbd{G} is initialized by \kbd{znstar(N, 1)}. \item a pair \kbd{[G, chi]}, where \kbd{chi} is a standard GP Dirichlet character $c = (c_j)$ on \kbd{G} (generic character \typ{VEC} or Conrey characters \typ{COL} or \typ{INT}); given generators $G = \oplus (\Z/d_j\Z) g_j$, $\chi(g_j) = e(c_j/d_j)$. \item a pair \kbd{[G, chin]}, where \kbd{chin} is a \emph{normalized} representation $[n, \tilde{c}]$ of the Dirichlet character $c$; $\chi(g_j) = e(\tilde{c}_j / n)$ where $n$ is minimal (order of $\chi$). \bprog ? [G,chi] = znchar(-3); ? G.cyc %2 = [2] ? chareval(G, chi, 2) %3 = 1/2 ? kronecker(-3,2) %4 = -1 ? znchartokronecker(G,chi) %5 = -3 ? mf = mfinit([28, 5/2, Mod(2,7)]); [f] = mfbasis(mf); ? [G,chi] = znchar(mf); [G.mod, chi] %7 = [7, [2]~] ? [G,chi] = znchar(f); chi %8 = [28, [0, 2]~] @eprog The library syntax is \fun{GEN}{znchar}{GEN D}. \subsec{zncharconductor$(G,\var{chi})$}\kbdsidx{zncharconductor}\label{se:zncharconductor} Let \var{G} be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$ (see \secref{se:dirichletchar} or \kbd{??character}). Return the conductor of \kbd{chi}: \bprog ? G = znstar(126000, 1); ? zncharconductor(G,11) \\ primitive %2 = 126000 ? zncharconductor(G,1) \\ trivial character, not primitive! %3 = 1 ? zncharconductor(G,1009) \\ character mod 5^3 %4 = 125 @eprog The library syntax is \fun{GEN}{zncharconductor}{GEN G, GEN chi}. \subsec{znchardecompose$(G, \var{chi}, Q)$}\kbdsidx{znchardecompose}\label{se:znchardecompose} Let $N = \prod_p p^{e_p}$ and a Dirichlet character $\chi$, we have a decomposition $\chi = \prod_p \chi_p$ into character modulo $N$ where the conductor of $\chi_p$ divides $p^{e_p}$; it equals $p^{e_p}$ for all $p$ if and only if $\chi$ is primitive. Given a \var{znstar} G describing a group $(\Z/N\Z)^*$, a Dirichlet character \kbd{chi} and an integer $Q$, return $\prod_{p \mid (Q,N)} \chi_p$. For instance, if $Q = p$ is a prime divisor of $N$, the function returns $\chi_p$ (as a character modulo $N$), given as a Conrey character (\typ{COL}). \bprog ? G = znstar(40, 1); ? G.cyc %2 = [4, 2, 2] ? chi = [2, 1, 1]; ? chi2 = znchardecompose(G, chi, 2) %4 = [1, 1, 0]~ ? chi5 = znchardecompose(G, chi, 5) %5 = [0, 0, 2]~ ? znchardecompose(G, chi, 3) %6 = [0, 0, 0]~ ? c = charmul(G, chi2, chi5) %7 = [1, 1, 2]~ \\ t_COL: in terms of Conrey generators ! ? znconreychar(G,c) %8 = [2, 1, 1] \\ t_VEC: in terms of SNF generators @eprog The library syntax is \fun{GEN}{znchardecompose}{GEN G, GEN chi, GEN Q}. \subsec{znchargauss$(G, \var{chi}, \{a=1\})$}\kbdsidx{znchargauss}\label{se:znchargauss} Given a Dirichlet character $\chi$ on $G = (\Z/N\Z)^*$ (see \kbd{znchar}), return the complex Gauss sum $$g(\chi,a) = \sum_{n = 1}^N \chi(n) e(a n/N)$$ \bprog ? [G,chi] = znchar(-3); \\ quadratic Gauss sum: I*sqrt(3) ? znchargauss(G,chi) %2 = 1.7320508075688772935274463415058723670*I ? [G,chi] = znchar(5); ? znchargauss(G,chi) \\ sqrt(5) %2 = 2.2360679774997896964091736687312762354 ? G = znstar(300,1); chi = [1,1,12]~; ? znchargauss(G,chi) / sqrt(300) - exp(2*I*Pi*11/25) \\ = 0 %4 = 2.350988701644575016 E-38 + 1.4693679385278593850 E-39*I ? lfuntheta([G,chi], 1) \\ = 0 %5 = -5.79[...] E-39 - 2.71[...] E-40*I @eprog The library syntax is \fun{GEN}{znchargauss}{GEN G, GEN chi, GEN a = NULL, long bitprec}. \subsec{zncharinduce$(G, \var{chi}, N)$}\kbdsidx{zncharinduce}\label{se:zncharinduce} Let $G$ be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}) and let \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{bid.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. Let $N$ be a multiple of $q$, return the character modulo $N$ extending \kbd{chi}. As usual for arithmetic functions, the new modulus $N$ can be given as a \typ{INT}, via a factorization matrix or a pair \kbd{[N, factor(N)]}, or by \kbd{znstar(N,1)}. \bprog ? G = znstar(4, 1); ? chi = znconreylog(G,1); \\ trivial character mod 4 ? zncharinduce(G, chi, 80) \\ now mod 80 %3 = [0, 0, 0]~ ? zncharinduce(G, 1, 80) \\ same using directly Conrey label %4 = [0, 0, 0]~ ? G2 = znstar(80, 1); ? zncharinduce(G, 1, G2) \\ same %4 = [0, 0, 0]~ ? chi = zncharinduce(G, 3, G2) \\ extend the non-trivial character mod 4 %5 = [1, 0, 0]~ ? [G0,chi0] = znchartoprimitive(G2, chi); ? G0.mod %7 = 4 ? chi0 %8 = [1]~ @eprog\noindent Here is a larger example: \bprog ? G = znstar(126000, 1); ? label = 1009; ? chi = znconreylog(G, label) %3 = [0, 0, 0, 14, 0]~ ? [G0,chi0] = znchartoprimitive(G, label); \\ works also with 'chi' ? G0.mod %5 = 125 ? chi0 \\ primitive character mod 5^3 attached to chi %6 = [14]~ ? G0 = znstar(N0, 1); ? zncharinduce(G0, chi0, G) \\ induce back %8 = [0, 0, 0, 14, 0]~ ? znconreyexp(G, %) %9 = 1009 @eprog The library syntax is \fun{GEN}{zncharinduce}{GEN G, GEN chi, GEN N}. \subsec{zncharisodd$(G, \var{chi})$}\kbdsidx{zncharisodd}\label{se:zncharisodd} Let $G$ be attached to $(\Z/N\Z)^*$ (as per \kbd{G = znstar(N,1)}) and let \kbd{chi} be a Dirichlet character on $(\Z/N\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{G.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. Return $1$ if and only if \kbd{chi}$(-1) = -1$ and $0$ otherwise. \bprog ? G = znstar(8, 1); ? zncharisodd(G, 1) \\ trivial character %2 = 0 ? zncharisodd(G, 3) %3 = 1 ? chareval(G, 3, -1) %4 = 1/2 @eprog The library syntax is \fun{long}{zncharisodd}{GEN G, GEN chi}. \subsec{znchartokronecker$(G, \var{chi}, \{\fl=0\})$}\kbdsidx{znchartokronecker}\label{se:znchartokronecker} Let $G$ be attached to $(\Z/N\Z)^*$ (as per \kbd{G = znstar(N,1)}) and let \kbd{chi} be a Dirichlet character on $(\Z/N\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{bid.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. If $\fl = 0$, return the discriminant $D$ if \kbd{chi} is real equal to the Kronecker symbol $(D/.)$ and $0$ otherwise. The discriminant $D$ is fundamental if and only if \kbd{chi} is primitive. If $\fl = 1$, return the fundamental discriminant attached to the corresponding primitive character. \bprog ? G = znstar(8,1); CHARS = [1,3,5,7]; \\ Conrey labels ? apply(t->znchartokronecker(G,t), CHARS) %2 = [4, -8, 8, -4] ? apply(t->znchartokronecker(G,t,1), CHARS) %3 = [1, -8, 8, -4] @eprog The library syntax is \fun{GEN}{znchartokronecker}{GEN G, GEN chi, long flag}. \subsec{znchartoprimitive$(G,\var{chi})$}\kbdsidx{znchartoprimitive}\label{se:znchartoprimitive} Let \var{G} be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$, of conductor $q_0 \mid q$. \bprog ? G = znstar(126000, 1); ? [G0,chi0] = znchartoprimitive(G,11) ? G0.mod %3 = 126000 ? chi0 %4 = 11 ? [G0,chi0] = znchartoprimitive(G,1);\\ trivial character, not primitive! ? G0.mod %6 = 1 ? chi0 %7 = []~ ? [G0,chi0] = znchartoprimitive(G,1009) ? G0.mod %4 = 125 ? chi0 %5 = [14]~ @eprog\noindent Note that \kbd{znconreyconductor} is more efficient since it can return $\chi_0$ and its conductor $q_0$ without needing to initialize $G_0$. (The price to pay is a more cryptic format and the need to initalize $G_0$ later but the can be done once for all characters of conductor $q_0$.) The library syntax is \fun{GEN}{znchartoprimitive}{GEN G, GEN chi}. \subsec{znconreychar$(G,m)$}\kbdsidx{znconreychar}\label{se:znconreychar} Given a \var{znstar} $G$ attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}), this function returns the Dirichlet character attached to $m \in (\Z/q\Z)^*$ via Conrey's logarithm, which establishes a ``canonical'' bijection between $(\Z/q\Z)^*$ and its dual. Let $q = \prod_p p^{e_p}$ be the factorization of $q$ into distinct primes. For all odd $p$ with $e_p > 0$, let $g_p$ be the element in $(\Z/q\Z)^*$ which is \item congruent to $1$ mod $q/p^{e_p}$, \item congruent mod $p^{e_p}$ to the smallest positive integer that generates $(\Z/p^2\Z)^*$. For $p = 2$, we let $g_4$ (if $2^{e_2} \geq 4$) and $g_8$ (if furthermore ($2^{e_2} \geq 8$) be the elements in $(\Z/q\Z)^*$ which are \item congruent to $1$ mod $q/2^{e_2}$, \item $g_4 = -1 \mod 2^{e_2}$, \item $g_8 = 5 \mod 2^{e_2}$. Then the $g_p$ (and the extra $g_4$ and $g_8$ if $2^{e_2}\geq 2$) are independent generators of $(\Z/q\Z)^*$, i.e. every $m$ in $(\Z/q\Z)^*$ can be written uniquely as $\prod_p g_p^{m_p}$, where $m_p$ is defined modulo the order $o_p$ of $g_p$ and $p \in S_q$, the set of prime divisors of $q$ together with $4$ if $4 \mid q$ and $8$ if $8 \mid q$. Note that the $g_p$ are in general \emph{not} SNF generators as produced by \kbd{znstar} whenever $\omega(q) \geq 2$, although their number is the same. They however allow to handle the finite abelian group $(\Z/q\Z)^*$ in a fast and elegant way. (Which unfortunately does not generalize to ray class groups or Hecke characters.) The Conrey logarithm of $m$ is the vector $(m_p)_{p\in S_q}$, obtained via \tet{znconreylog}. The Conrey character $\chi_q(m,\cdot)$ attached to $m$ mod $q$ maps each $g_p$, $p\in S_q$ to $e(m_p / o_p)$, where $e(x) = \exp(2i\pi x)$. This function returns the Conrey character expressed in the standard PARI way in terms of the SNF generators \kbd{G.gen}. \bprog ? G = znstar(8,1); ? G.cyc %2 = [2, 2] \\ Z/2 x Z/2 ? G.gen %3 = [7, 3] ? znconreychar(G,1) \\ 1 is always the trivial character %4 = [0, 0] ? znconreychar(G,2) \\ 2 is not coprime to 8 !!! *** at top-level: znconreychar(G,2) *** ^----------------- *** znconreychar: elements not coprime in Zideallog: 2 8 *** Break loop: type 'break' to go back to GP prompt break> ? znconreychar(G,3) %5 = [0, 1] ? znconreychar(G,5) %6 = [1, 1] ? znconreychar(G,7) %7 = [1, 0] @eprog\noindent We indeed get all 4 characters of $(\Z/8\Z)^*$. For convenience, we allow to input the \emph{Conrey logarithm} of $m$ instead of $m$: \bprog ? G = znstar(55, 1); ? znconreychar(G,7) %2 = [7, 0] ? znconreychar(G, znconreylog(G,7)) %3 = [7, 0] @eprog The library syntax is \fun{GEN}{znconreychar}{GEN G, GEN m}. \subsec{znconreyconductor$(G,\var{chi}, \{\&\var{chi0}\})$}\kbdsidx{znconreyconductor}\label{se:znconreyconductor} Let \var{G} be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{bid.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. Return the conductor of \kbd{chi}, as the \typ{INT} \kbd{bid.mod} if \kbd{chi} is primitive, and as a pair \kbd{[N, faN]} (with \kbd{faN} the factorization of $N$) otherwise. If \kbd{chi0} is present, set it to the Conrey logarithm of the attached primitive character. \bprog ? G = znstar(126000, 1); ? znconreyconductor(G,11) \\ primitive %2 = 126000 ? znconreyconductor(G,1) \\ trivial character, not primitive! %3 = [1, matrix(0,2)] ? N0 = znconreyconductor(G,1009, &chi0) \\ character mod 5^3 %4 = [125, Mat([5, 3])] ? chi0 %5 = [14]~ ? G0 = znstar(N0, 1); \\ format [N,factor(N)] accepted ? znconreyexp(G0, chi0) %7 = 9 ? znconreyconductor(G0, chi0) \\ now primitive, as expected %8 = 125 @eprog\noindent The group \kbd{G0} is not computed as part of \kbd{znconreyconductor} because it needs to be computed only once per conductor, not once per character. The library syntax is \fun{GEN}{znconreyconductor}{GEN G, GEN chi, GEN *chi0 = NULL}. \subsec{znconreyexp$(G, \var{chi})$}\kbdsidx{znconreyexp}\label{se:znconreyexp} Given a \var{znstar} $G$ attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}), this function returns the Conrey exponential of the character \var{chi}: it returns the integer $m \in (\Z/q\Z)^*$ such that \kbd{znconreylog(G, $m$)} is \var{chi}. The character \var{chi} is given either as a \item \typ{VEC}: in terms of the generators \kbd{G.gen}; \item \typ{COL}: a Conrey logarithm. \bprog ? G = znstar(126000, 1) ? znconreylog(G,1) %2 = [0, 0, 0, 0, 0]~ ? znconreyexp(G,%) %3 = 1 ? G.cyc \\ SNF generators %4 = [300, 12, 2, 2, 2] ? chi = [100, 1, 0, 1, 0]; \\ some random character on SNF generators ? znconreylog(G, chi) \\ in terms of Conrey generators %6 = [0, 3, 3, 0, 2]~ ? znconreyexp(G, %) \\ apply to a Conrey log %7 = 18251 ? znconreyexp(G, chi) \\ ... or a char on SNF generators %8 = 18251 ? znconreychar(G,%) %9 = [100, 1, 0, 1, 0] @eprog The library syntax is \fun{GEN}{znconreyexp}{GEN G, GEN chi}. \subsec{znconreylog$(G,m)$}\kbdsidx{znconreylog}\label{se:znconreylog} Given a \var{znstar} attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}), this function returns the Conrey logarithm of $m \in (\Z/q\Z)^*$. Let $q = \prod_p p^{e_p}$ be the factorization of $q$ into distinct primes, where we assume $e_2 = 0$ or $e_2 \geq 2$. (If $e_2 = 1$, we can ignore $2$ from the factorization, as if we replaced $q$ by $q/2$, since $(\Z/q\Z)^* \sim (\Z/(q/2)\Z)^*$.) For all odd $p$ with $e_p > 0$, let $g_p$ be the element in $(\Z/q\Z)^*$ which is \item congruent to $1$ mod $q/p^{e_p}$, \item congruent mod $p^{e_p}$ to the smallest positive integer that generates $(\Z/p^2\Z)^*$. For $p = 2$, we let $g_4$ (if $2^{e_2} \geq 4$) and $g_8$ (if furthermore ($2^{e_2} \geq 8$) be the elements in $(\Z/q\Z)^*$ which are \item congruent to $1$ mod $q/2^{e_2}$, \item $g_4 = -1 \mod 2^{e_2}$, \item $g_8 = 5 \mod 2^{e_2}$. Then the $g_p$ (and the extra $g_4$ and $g_8$ if $2^{e_2}\geq 2$) are independent generators of $\Z/q\Z^*$, i.e. every $m$ in $(\Z/q\Z)^*$ can be written uniquely as $\prod_p g_p^{m_p}$, where $m_p$ is defined modulo the order $o_p$ of $g_p$ and $p \in S_q$, the set of prime divisors of $q$ together with $4$ if $4 \mid q$ and $8$ if $8 \mid q$. Note that the $g_p$ are in general \emph{not} SNF generators as produced by \kbd{znstar} whenever $\omega(q) \geq 2$, although their number is the same. They however allow to handle the finite abelian group $(\Z/q\Z)^*$ in a fast and elegant way. (Which unfortunately does not generalize to ray class groups or Hecke characters.) The Conrey logarithm of $m$ is the vector $(m_p)_{p\in S_q}$. The inverse function \tet{znconreyexp} recovers the Conrey label $m$ from a character. \bprog ? G = znstar(126000, 1); ? znconreylog(G,1) %2 = [0, 0, 0, 0, 0]~ ? znconreyexp(G, %) %3 = 1 ? znconreylog(G,2) \\ 2 is not coprime to modulus !!! *** at top-level: znconreylog(G,2) *** ^----------------- *** znconreylog: elements not coprime in Zideallog: 2 126000 *** Break loop: type 'break' to go back to GP prompt break> ? znconreylog(G,11) \\ wrt. Conrey generators %4 = [0, 3, 1, 76, 4]~ ? log11 = ideallog(,11,G) \\ wrt. SNF generators %5 = [178, 3, -75, 1, 0]~ @eprog\noindent For convenience, we allow to input the ordinary discrete log of $m$, $\kbd{ideallog(,m,bid)}$, which allows to convert discrete logs from \kbd{bid.gen} generators to Conrey generators. \bprog ? znconreylog(G, log11) %7 = [0, 3, 1, 76, 4]~ @eprog\noindent We also allow a character (\typ{VEC}) on \kbd{bid.gen} and return its representation on the Conrey generators. \bprog ? G.cyc %8 = [300, 12, 2, 2, 2] ? chi = [10,1,0,1,1]; ? znconreylog(G, chi) %10 = [1, 3, 3, 10, 2]~ ? n = znconreyexp(G, chi) %11 = 84149 ? znconreychar(G, n) %12 = [10, 1, 0, 1, 1] @eprog The library syntax is \fun{GEN}{znconreylog}{GEN G, GEN m}. \subsec{zncoppersmith$(P, N, X, \{B=N\})$}\kbdsidx{zncoppersmith}\label{se:zncoppersmith} $N$ being an integer and $P\in \Z[X]$, finds all integers $x$ with $|x| \leq X$ such that $$\gcd(N, P(x)) \geq B,$$ using \idx{Coppersmith}'s algorithm, a famous application of the \idx{LLL} algorithm. The parameter $X$ must be smaller than $\exp(\log^2 B / (\deg(P) \log N))$: for $B = N$, this means $X < N^{1/\deg(P)}$. Some $x$ larger than $X$ may be returned if you are very lucky. The smaller $B$ (or the larger $X$), the slower the routine will be. The strength of Coppersmith method is the ability to find roots modulo a general \emph{composite} $N$: if $N$ is a prime or a prime power, \tet{polrootsmod} or \tet{polrootspadic} will be much faster. We shall now present two simple applications. The first one is finding non-trivial factors of $N$, given some partial information on the factors; in that case $B$ must obviously be smaller than the largest non-trivial divisor of $N$. \bprog setrand(1); \\ to make the example reproducible [a,b] = [10^30, 10^31]; D = 20; p = randomprime([a,b]); q = randomprime([a,b]); N = p*q; \\ assume we know 0) p | N; 1) p in [a,b]; 2) the last D digits of p p0 = p % 10^D; ? L = zncoppersmith(10^D*x + p0, N, b \ 10^D, a) time = 1ms. %6 = [738281386540] ? gcd(L[1] * 10^D + p0, N) == p %7 = 1 @eprog\noindent and we recovered $p$, faster than by trying all possibilities $ x < 10^{11}$. The second application is an attack on RSA with low exponent, when the message $x$ is short and the padding $P$ is known to the attacker. We use the same RSA modulus $N$ as in the first example: \bprog setrand(1); P = random(N); \\ known padding e = 3; \\ small public encryption exponent X = floor(N^0.3); \\ N^(1/e - epsilon) x0 = random(X); \\ unknown short message C = lift( (Mod(x0,N) + P)^e ); \\ known ciphertext, with padding P zncoppersmith((P + x)^3 - C, N, X) \\ result in 244ms. %14 = [2679982004001230401] ? %[1] == x0 %15 = 1 @eprog\noindent We guessed an integer of the order of $10^{18}$, almost instantly. The library syntax is \fun{GEN}{zncoppersmith}{GEN P, GEN N, GEN X, GEN B = NULL}. \subsec{znlog$(x,g,\{o\})$}\kbdsidx{znlog}\label{se:znlog} This functions allows two distinct modes of operation depending on $g$: \item if $g$ is the output of \tet{znstar} (with initialization), we compute the discrete logarithm of $x$ with respect to the generators contained in the structure. See \tet{ideallog} for details. \item else $g$ is an explicit element in $(\Z/N\Z)^*$, we compute the discrete logarithm of $x$ in $(\Z/N\Z)^*$ in base $g$. The rest of this entry describes the latter possibility. The result is $[]$ when $x$ is not a power of $g$, though the function may also enter an infinite loop in this case. If present, $o$ represents the multiplicative order of $g$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord} is the order of $g$. This provides a definite speedup when the discrete log problem is simple: \bprog ? p = nextprime(10^4); g = znprimroot(p); o = [p-1, factor(p-1)]; ? for(i=1,10^4, znlog(i, g, o)) time = 163 ms. ? for(i=1,10^4, znlog(i, g)) time = 200 ms. \\ a little slower @eprog The result is undefined if $g$ is not invertible mod $N$ or if the supplied order is incorrect. This function uses \item a combination of generic discrete log algorithms (see below). \item in $(\Z/N\Z)^*$ when $N$ is prime: a linear sieve index calculus method, suitable for $N < 10^{50}$, say, is used for large prime divisors of the order. The generic discrete log algorithms are: \item Pohlig-Hellman algorithm, to reduce to groups of prime order $q$, where $q | p-1$ and $p$ is an odd prime divisor of $N$, \item Shanks baby-step/giant-step ($q < 2^{32}$ is small), \item Pollard rho method ($q > 2^{32}$). The latter two algorithms require $O(\sqrt{q})$ operations in the group on average, hence will not be able to treat cases where $q > 10^{30}$, say. In addition, Pollard rho is not able to handle the case where there are no solutions: it will enter an infinite loop. \bprog ? g = znprimroot(101) %1 = Mod(2,101) ? znlog(5, g) %2 = 24 ? g^24 %3 = Mod(5, 101) ? G = znprimroot(2 * 101^10) %4 = Mod(110462212541120451003, 220924425082240902002) ? znlog(5, G) %5 = 76210072736547066624 ? G^% == 5 %6 = 1 ? N = 2^4*3^2*5^3*7^4*11; g = Mod(13, N); znlog(g^110, g) %7 = 110 ? znlog(6, Mod(2,3)) \\ no solution %8 = [] @eprog\noindent For convenience, $g$ is also allowed to be a $p$-adic number: \bprog ? g = 3+O(5^10); znlog(2, g) %1 = 1015243 ? g^% %2 = 2 + O(5^10) @eprog The library syntax is \fun{GEN}{znlog0}{GEN x, GEN g, GEN o = NULL}. The function \fun{GEN}{znlog}{GEN x, GEN g, GEN o} is also available \subsec{znorder$(x,\{o\})$}\kbdsidx{znorder}\label{se:znorder} $x$ must be an integer mod $n$, and the result is the order of $x$ in the multiplicative group $(\Z/n\Z)^*$. Returns an error if $x$ is not invertible. The parameter o, if present, represents a non-zero multiple of the order of $x$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord = eulerphi(n)} is the cardinality of the group. The library syntax is \fun{GEN}{znorder}{GEN x, GEN o = NULL}. Also available is \fun{GEN}{order}{GEN x}. \subsec{znprimroot$(n)$}\kbdsidx{znprimroot}\label{se:znprimroot} Returns a primitive root (generator) of $(\Z/n\Z)^*$, whenever this latter group is cyclic ($n = 4$ or $n = 2p^k$ or $n = p^k$, where $p$ is an odd prime and $k \geq 0$). If the group is not cyclic, the result is undefined. If $n$ is a prime power, then the smallest positive primitive root is returned. This may not be true for $n = 2p^k$, $p$ odd. Note that this function requires factoring $p-1$ for $p$ as above, in order to determine the exact order of elements in $(\Z/n\Z)^*$: this is likely to be costly if $p$ is large. The library syntax is \fun{GEN}{znprimroot}{GEN n}. \subsec{znstar$(n,\{\fl=0\})$}\kbdsidx{znstar}\label{se:znstar} Gives the structure of the multiplicative group $(\Z/n\Z)^*$. The output $G$ depends on the value of \fl: \item $\fl = 0$ (default), an abelian group structure $[h,d,g]$, where $h = \phi(n)$ is the order (\kbd{G.no}), $d$ (\kbd{G.cyc}) is a $k$-component row-vector $d$ of integers $d_i$ such that $d_i>1$, $d_i \mid d_{i-1}$ for $i \ge 2$ and $$ (\Z/n\Z)^* \simeq \prod_{i=1}^k (\Z/d_i\Z), $$ and $g$ (\kbd{G.gen}) is a $k$-component row vector giving generators of the image of the cyclic groups $\Z/d_i\Z$. \item $\fl = 1$ the result is a \kbd{bid} structure; this allows computing discrete logarithms using \tet{znlog} (also in the non-cyclic case!). \bprog ? G = znstar(40) %1 = [16, [4, 2, 2], [Mod(17, 40), Mod(21, 40), Mod(11, 40)]] ? G.no \\ eulerphi(40) %2 = 16 ? G.cyc \\ cycle structure %3 = [4, 2, 2] ? G.gen \\ generators for the cyclic components %4 = [Mod(17, 40), Mod(21, 40), Mod(11, 40)] ? apply(znorder, G.gen) %5 = [4, 2, 2] @eprog\noindent For user convenience, we define \kbd{znstar(0)} as \kbd{[2, [2], [-1]]}, corresponding to $\Z^*$, but $\fl = 1$ is not implemented in this trivial case. The library syntax is \fun{GEN}{znstar0}{GEN n, long flag}. \section{Polynomials and power series} We group here all functions which are specific to polynomials or power series. Many other functions which can be applied on these objects are described in the other sections. Also, some of the functions described here can be applied to other types. \subsec{O$(p\hbox{\kbd{\pow}}e)$}\kbdsidx{O}\label{se:O} If $p$ is an integer greater than $2$, returns a $p$-adic $0$ of precision $e$. In all other cases, returns a power series zero with precision given by $e v$, where $v$ is the $X$-adic valuation of $p$ with respect to its main variable. The library syntax is \fun{GEN}{ggrando}{}. \fun{GEN}{zeropadic}{GEN p, long e} for a $p$-adic and \fun{GEN}{zeroser}{long v, long e} for a power series zero in variable $v$. \subsec{bezoutres$(A,B,\{v\})$}\kbdsidx{bezoutres}\label{se:bezoutres} Deprecated alias for \kbd{polresultantext} The library syntax is \fun{GEN}{polresultantext0}{GEN A, GEN B, long v = -1} where \kbd{v} is a variable number. \subsec{deriv$(x,\{v\})$}\kbdsidx{deriv}\label{se:deriv} Derivative of $x$ with respect to the main variable if $v$ is omitted, and with respect to $v$ otherwise. The derivative of a scalar type is zero, and the derivative of a vector or matrix is done componentwise. One can use $x'$ as a shortcut if the derivative is with respect to the main variable of $x$. By definition, the main variable of a \typ{POLMOD} is the main variable among the coefficients from its two polynomial components (representative and modulus); in other words, assuming a polmod represents an element of $R[X]/(T(X))$, the variable $X$ is a mute variable and the derivative is taken with respect to the main variable used in the base ring $R$. The library syntax is \fun{GEN}{deriv}{GEN x, long v = -1} where \kbd{v} is a variable number. \subsec{diffop$(x,v,d,\{n=1\})$}\kbdsidx{diffop}\label{se:diffop} Let $v$ be a vector of variables, and $d$ a vector of the same length, return the image of $x$ by the $n$-power ($1$ if n is not given) of the differential operator $D$ that assumes the value \kbd{d[i]} on the variable \kbd{v[i]}. The value of $D$ on a scalar type is zero, and $D$ applies componentwise to a vector or matrix. When applied to a \typ{POLMOD}, if no value is provided for the variable of the modulus, such value is derived using the implicit function theorem. Some examples: This function can be used to differentiate formal expressions: If $E=\exp(X^2)$ then we have $E'=2*X*E$. We can derivate $X*exp(X^2)$ as follow: \bprog ? diffop(E*X,[X,E],[1,2*X*E]) %1 = (2*X^2 + 1)*E @eprog Let \kbd{Sin} and \kbd{Cos} be two function such that $\kbd{Sin}^2+\kbd{Cos}^2=1$ and $\kbd{Cos}'=-\kbd{Sin}$. We can differentiate $\kbd{Sin}/\kbd{Cos}$ as follow, PARI inferring the value of $\kbd{Sin}'$ from the equation: \bprog ? diffop(Mod('Sin/'Cos,'Sin^2+'Cos^2-1),['Cos],[-'Sin]) %1 = Mod(1/Cos^2, Sin^2 + (Cos^2 - 1)) @eprog Compute the Bell polynomials (both complete and partial) via the Faa di Bruno formula: \bprog Bell(k,n=-1)= { my(var(i)=eval(Str("X",i))); my(x,v,dv); v=vector(k,i,if(i==1,'E,var(i-1))); dv=vector(k,i,if(i==1,'X*var(1)*'E,var(i))); x=diffop('E,v,dv,k)/'E; if(n<0,subst(x,'X,1),polcoeff(x,n,'X)) } @eprog The library syntax is \fun{GEN}{diffop0}{GEN x, GEN v, GEN d, long n}. For $n=1$, the function \fun{GEN}{diffop}{GEN x, GEN v, GEN d} is also available. \subsec{eval$(x)$}\kbdsidx{eval}\label{se:eval} Replaces in $x$ the formal variables by the values that have been assigned to them after the creation of $x$. This is mainly useful in GP, and not in library mode. Do not confuse this with substitution (see \kbd{subst}). If $x$ is a character string, \kbd{eval($x$)} executes $x$ as a GP command, as if directly input from the keyboard, and returns its output. \bprog ? x1 = "one"; x2 = "two"; ? n = 1; eval(Str("x", n)) %2 = "one" ? f = "exp"; v = 1; ? eval(Str(f, "(", v, ")")) %4 = 2.7182818284590452353602874713526624978 @eprog\noindent Note that the first construct could be implemented in a simpler way by using a vector \kbd{x = ["one","two"]; x[n]}, and the second by using a closure \kbd{f = exp; f(v)}. The final example is more interesting: \bprog ? genmat(u,v) = matrix(u,v,i,j, eval( Str("x",i,j) )); ? genmat(2,3) \\ generic 2 x 3 matrix %2 = [x11 x12 x13] [x21 x22 x23] @eprog A syntax error in the evaluation expression raises an \kbd{e\_SYNTAX} exception, which can be trapped as usual: \bprog ? 1a *** syntax error, unexpected variable name, expecting $end or ';': 1a *** ^- ? E(expr) = { iferr(eval(expr), e, print("syntax error"), errname(e) == "e_SYNTAX"); } ? E("1+1") %1 = 2 ? E("1a") syntax error @eprog \synt{geval}{GEN x}. \subsec{factorpadic$(\var{pol},p,r)$}\kbdsidx{factorpadic}\label{se:factorpadic} $p$-adic factorization of the polynomial \var{pol} to precision $r$, the result being a two-column matrix as in \kbd{factor}. Note that this is not the same as a factorization over $\Z/p^r\Z$ (polynomials over that ring do not form a unique factorization domain, anyway), but approximations in $\Q/p^r\Z$ of the true factorization in $\Q_p[X]$. \bprog ? factorpadic(x^2 + 9, 3,5) %1 = [(1 + O(3^5))*x^2 + O(3^5)*x + (3^2 + O(3^5)) 1] ? factorpadic(x^2 + 1, 5,3) %2 = [ (1 + O(5^3))*x + (2 + 5 + 2*5^2 + O(5^3)) 1] [(1 + O(5^3))*x + (3 + 3*5 + 2*5^2 + O(5^3)) 1] @eprog\noindent The factors are normalized so that their leading coefficient is a power of $p$. The method used is a modified version of the \idx{round 4} algorithm of \idx{Zassenhaus}. If \var{pol} has inexact \typ{PADIC} coefficients, this is not always well-defined; in this case, the polynomial is first made integral by dividing out the $p$-adic content, then lifted to $\Z$ using \tet{truncate} coefficientwise. Hence we actually factor exactly a polynomial which is only $p$-adically close to the input. To avoid pitfalls, we advise to only factor polynomials with exact rational coefficients. \synt{factorpadic}{GEN f,GEN p, long r} . The function \kbd{factorpadic0} is deprecated, provided for backward compatibility. \subsec{intformal$(x,\{v\})$}\kbdsidx{intformal}\label{se:intformal} \idx{formal integration} of $x$ with respect to the variable $v$ (wrt. the main variable if $v$ is omitted). Since PARI cannot represent logarithmic or arctangent terms, any such term in the result will yield an error: \bprog ? intformal(x^2) %1 = 1/3*x^3 ? intformal(x^2, y) %2 = y*x^2 ? intformal(1/x) *** at top-level: intformal(1/x) *** ^-------------- *** intformal: domain error in intformal: residue(series, pole) != 0 @eprog The argument $x$ can be of any type. When $x$ is a rational function, we assume that the base ring is an integral domain of characteristic zero. By definition, the main variable of a \typ{POLMOD} is the main variable among the coefficients from its two polynomial components (representative and modulus); in other words, assuming a polmod represents an element of $R[X]/(T(X))$, the variable $X$ is a mute variable and the integral is taken with respect to the main variable used in the base ring $R$. In particular, it is meaningless to integrate with respect to the main variable of \kbd{x.mod}: \bprog ? intformal(Mod(1,x^2+1), 'x) *** intformal: incorrect priority in intformal: variable x = x @eprog The library syntax is \fun{GEN}{integ}{GEN x, long v = -1} where \kbd{v} is a variable number. \subsec{padicappr$(\var{pol},a)$}\kbdsidx{padicappr}\label{se:padicappr} Vector of $p$-adic roots of the polynomial \var{pol} congruent to the $p$-adic number $a$ modulo $p$, and with the same $p$-adic precision as $a$. The number $a$ can be an ordinary $p$-adic number (type \typ{PADIC}, i.e.~an element of $\Z_p$) or can be an integral element of a finite \emph{unramified} extension $\Q_p[X]/(T)$ of $\Q_p$, given as a \typ{POLMOD} \kbd{Mod}$(A,T)$ at least one of whose coefficients is a \typ{PADIC} and $T$ irreducible modulo $p$. In this case, the result is the vector of roots belonging to the same extension of $\Q_p$ as $a$. The polynomial \var{pol} should have exact coefficients; if not, its coefficients are first rounded to $\Q$ or $\Q[X]/(T)$ and this is the polynomial whose roots we consider. The library syntax is \fun{GEN}{padicappr}{GEN pol, GEN a}. Also available is \fun{GEN}{Zp_appr}{GEN f, GEN a} when $a$ is a \typ{PADIC}. \subsec{padicfields$(p, N, \{\fl=0\})$}\kbdsidx{padicfields}\label{se:padicfields} Returns a vector of polynomials generating all the extensions of degree $N$ of the field $\Q_p$ of $p$-adic rational numbers; $N$ is allowed to be a 2-component vector $[n,d]$, in which case we return the extensions of degree $n$ and discriminant $p^d$. The list is minimal in the sense that two different polynomials generate non-isomorphic extensions; in particular, the number of polynomials is the number of classes of non-isomorphic extensions. If $P$ is a polynomial in this list, $\alpha$ is any root of $P$ and $K = \Q_p(\alpha)$, then $\alpha$ is the sum of a uniformizer and a (lift of a) generator of the residue field of $K$; in particular, the powers of $\alpha$ generate the ring of $p$-adic integers of $K$. If $\fl = 1$, replace each polynomial $P$ by a vector $[P, e, f, d, c]$ where $e$ is the ramification index, $f$ the residual degree, $d$ the valuation of the discriminant, and $c$ the number of conjugate fields. If $\fl = 2$, only return the \emph{number} of extensions in a fixed algebraic closure (Krasner's formula), which is much faster. The library syntax is \fun{GEN}{padicfields0}{GEN p, GEN N, long flag}. Also available is \fun{GEN}{padicfields}{GEN p, long n, long d, long flag}, which computes extensions of $\Q_p$ of degree $n$ and discriminant $p^d$. \subsec{polchebyshev$(n,\{\fl=1\},\{a='x\})$}\kbdsidx{polchebyshev}\label{se:polchebyshev} Returns the $n^{\text{th}}$ \idx{Chebyshev} polynomial of the first kind $T_n$ ($\fl=1$) or the second kind $U_n$ ($\fl=2$), evaluated at $a$ (\kbd{'x} by default). Both series of polynomials satisfy the 3-term relation $$ P_{n+1} = 2xP_n - P_{n-1}, $$ and are determined by the initial conditions $U_0 = T_0 = 1$, $T_1 = x$, $U_1 = 2x$. In fact $T_n' = n U_{n-1}$ and, for all complex numbers $z$, we have $T_n(\cos z) = \cos (nz)$ and $U_{n-1}(\cos z) = \sin(nz)/\sin z$. If $n \geq 0$, then these polynomials have degree $n$. For $n < 0$, $T_n$ is equal to $T_{-n}$ and $U_n$ is equal to $-U_{-2-n}$. In particular, $U_{-1} = 0$. The library syntax is \fun{GEN}{polchebyshev_eval}{long n, long flag, GEN a = NULL}. Also available are \fun{GEN}{polchebyshev}{long n, long flag, long v}, \fun{GEN}{polchebyshev1}{long n, long v} and \fun{GEN}{polchebyshev2}{long n, long v} for $T_n$ and $U_n$ respectively. \subsec{polclass$(D, \{\var{inv} = 0\}, \{x = 'x\})$}\kbdsidx{polclass}\label{se:polclass} Return a polynomial in $\Z[x]$ generating the Hilbert class field for the imaginary quadratic discriminant $D$. If $inv$ is 0 (the default), use the modular $j$-function and return the classical Hilbert polynomial, otherwise use a class invariant. The following invariants correspond to the different values of $inv$, where $f$ denotes Weber's function \kbd{weber}, and $w_{p,q}$ the double eta quotient given by $w_{p,q} = \dfrac{ \eta(x/p)\*\eta(x/q) }{ \eta(x)\*\eta(x/{pq}) }$ The invariants $w_{p,q}$ are not allowed unless they satisfy the following technical conditions ensuring they do generate the Hilbert class field and not a strict subfield: \item if $p\neq q$, we need them both non-inert, prime to the conductor of $\Z[\sqrt{D}]$. Let $P, Q$ be prime ideals above $p$ and $q$; if both are unramified, we further require that $P^{\pm 1} Q^{\pm 1}$ be all distinct in the class group of $\Z[\sqrt{D}]$; if both are ramified, we require that $PQ \neq 1$ in the class group. \item if $p = q$, we want it split and prime to the conductor and the prime ideal above it must have order $\neq 1, 2, 4$ in the class group. \noindent Invariants are allowed under the additional conditions on $D$ listed below. \item 0 : $j$ \item 1 : $f$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 2 : $f^2$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 3 : $f^3$, $D = 1 \mod 8$; \item 4 : $f^4$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 5 : $\gamma_2= j^{1/3}$, $D = 1,2 \mod 3$; \item 6 : $w_{2,3}$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 8 : $f^8$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 9 : $w_{3,3}$, $D = 1 \mod 2$ and $D = 1,2 \mod 3$; \item 10: $w_{2,5}$, $D \neq 60 \mod 80$ and $D = 1,2 \mod 3$; \item 14: $w_{2,7}$, $D = 1 \mod 8$; \item 15: $w_{3,5}$, $D = 1,2 \mod 3$; \item 21: $w_{3,7}$, $D = 1 \mod 2$ and $21$ does not divide $D$ \item 23: $w_{2,3}^2$, $D = 1,2 \mod 3$; \item 24: $w_{2,5}^2$, $D = 1,2 \mod 3$; \item 26: $w_{2,13}$, $D \neq 156 \mod 208$; \item 27: $w_{2,7}^2$, $D\neq 28 \mod 112$; \item 28: $w_{3,3}^2$, $D = 1,2 \mod 3$; \item 35: $w_{5,7}$, $D = 1,2 \mod 3$; \item 39: $w_{3,13}$, $D = 1 \mod 2$ and $D = 1,2 \mod 3$; The algorithm for computing the polynomial does not use the floating point approach, which would evaluate a precise modular function in a precise complex argument. Instead, it relies on a faster Chinese remainder based approach modulo small primes, in which the class invariant is only defined algebraically by the modular polynomial relating the modular function to $j$. So in fact, any of the several roots of the modular polynomial may actually be the class invariant, and more precise assertions cannot be made. For instance, while \kbd{polclass(D)} returns the minimal polynomial of $j(\tau)$ with $\tau$ (any) quadratic integer for the discriminant $D$, the polynomial returned by \kbd{polclass(D, 5)} can be the minimal polynomial of any of $\gamma_2 (\tau)$, $\zeta_3 \gamma_2 (\tau)$ or $\zeta_3^2 \gamma_2 (\tau)$, the three roots of the modular polynomial $j = \gamma_2^3$, in which $j$ has been specialised to $j (\tau)$. The modular polynomial is given by $j = {(f^{24}-16)^3 \over f^{24}}$ for Weber's function $f$. For the double eta quotients of level $N = p q$, all functions are covered such that the modular curve $X_0^+ (N)$, the function field of which is generated by the functions invariant under $\Gamma^0 (N)$ and the Fricke--Atkin--Lehner involution, is of genus $0$ with function field generated by (a power of) the double eta quotient $w$. This ensures that the full Hilbert class field (and not a proper subfield) is generated by class invariants from these double eta quotients. Then the modular polynomial is of degree $2$ in $j$, and of degree $\psi (N) = (p+1)(q+1)$ in $w$. \bprog ? polclass(-163) %1 = x + 262537412640768000 ? polclass(-51, , 'z) %2 = z^2 + 5541101568*z + 6262062317568 ? polclass(-151,1) x^7 - x^6 + x^5 + 3*x^3 - x^2 + 3*x + 1 @eprog The library syntax is \fun{GEN}{polclass}{GEN D, long inv, long x = -1} where \kbd{x} is a variable number. \subsec{polcoef$(x,n,\{v\})$}\kbdsidx{polcoef}\label{se:polcoef} Coefficient of degree $n$ of the polynomial $x$, with respect to the main variable if $v$ is omitted, with respect to $v$ otherwise. If $n$ is greater than the degree, the result is zero. Naturally applies to scalars (polynomial of degree $0$), as well as to rational functions whose denominator is a monomial. It also applies to power series: if $n$ is less than the valuation, the result is zero. If it is greater than the largest significant degree, then an error message is issued. The library syntax is \fun{GEN}{polcoef}{GEN x, long n, long v = -1} where \kbd{v} is a variable number. \subsec{polcoeff$(x,n,\{v\})$}\kbdsidx{polcoeff}\label{se:polcoeff} Deprecated alias for polcoef. The library syntax is \fun{GEN}{polcoeff0}{GEN x, long n, long v = -1} where \kbd{v} is a variable number. \subsec{polcyclo$(n,\{a = 'x\})$}\kbdsidx{polcyclo}\label{se:polcyclo} $n$-th cyclotomic polynomial, evaluated at $a$ (\kbd{'x} by default). The integer $n$ must be positive. Algorithm used: reduce to the case where $n$ is squarefree; to compute the cyclotomic polynomial, use $\Phi_{np}(x)=\Phi_n(x^p)/\Phi(x)$; to compute it evaluated, use $\Phi_n(x) = \prod_{d\mid n} (x^d-1)^{\mu(n/d)}$. In the evaluated case, the algorithm assumes that $a^d - 1$ is either $0$ or invertible, for all $d\mid n$. If this is not the case (the base ring has zero divisors), use \kbd{subst(polcyclo(n),x,a)}. The library syntax is \fun{GEN}{polcyclo_eval}{long n, GEN a = NULL}. The variant \fun{GEN}{polcyclo}{long n, long v} returns the $n$-th cyclotomic polynomial in variable $v$. \subsec{polcyclofactors$(f)$}\kbdsidx{polcyclofactors}\label{se:polcyclofactors} Returns a vector of polynomials, whose product is the product of distinct cyclotomic polynomials dividing $f$. \bprog ? f = x^10+5*x^8-x^7+8*x^6-4*x^5+8*x^4-3*x^3+7*x^2+3; ? v = polcyclofactors(f) %2 = [x^2 + 1, x^2 + x + 1, x^4 - x^3 + x^2 - x + 1] ? apply(poliscycloprod, v) %3 = [1, 1, 1] ? apply(poliscyclo, v) %4 = [4, 3, 10] @eprog\noindent In general, the polynomials are products of cyclotomic polynomials and not themselves irreducible: \bprog ? g = x^8+2*x^7+6*x^6+9*x^5+12*x^4+11*x^3+10*x^2+6*x+3; ? polcyclofactors(g) %2 = [x^6 + 2*x^5 + 3*x^4 + 3*x^3 + 3*x^2 + 2*x + 1] ? factor(%[1]) %3 = [ x^2 + x + 1 1] [x^4 + x^3 + x^2 + x + 1 1] @eprog The library syntax is \fun{GEN}{polcyclofactors}{GEN f}. \subsec{poldegree$(x,\{v\})$}\kbdsidx{poldegree}\label{se:poldegree} Degree of the polynomial $x$ in the main variable if $v$ is omitted, in the variable $v$ otherwise. The degree of $0$ is \kbd{-oo}. The degree of a non-zero scalar is $0$. Finally, when $x$ is a non-zero polynomial or rational function, returns the ordinary degree of $x$. Raise an error otherwise. The library syntax is \fun{GEN}{gppoldegree}{GEN x, long v = -1} where \kbd{v} is a variable number. Also available is \fun{long}{poldegree}{GEN x, long v}, which returns \tet{-LONG_MAX} if $x = 0$ and the degree as a \kbd{long} integer. \subsec{poldisc$(\var{pol},\{v\})$}\kbdsidx{poldisc}\label{se:poldisc} Discriminant of the polynomial \var{pol} in the main variable if $v$ is omitted, in $v$ otherwise. Uses a modular algorithm over $\Z$ or $\Q$, and the \idx{subresultant algorithm} otherwise. \bprog ? T = x^4 + 2*x+1; ? poldisc(T) %2 = -176 ? poldisc(T^2) %3 = 0 @eprog For convenience, the function also applies to types \typ{QUAD} and \typ{QFI}/\typ{QFR}: \bprog ? z = 3*quadgen(8) + 4; ? poldisc(z) %2 = 8 ? q = Qfb(1,2,3); ? poldisc(q) %4 = -8 @eprog The library syntax is \fun{GEN}{poldisc0}{GEN pol, long v = -1} where \kbd{v} is a variable number. \subsec{poldiscfactors$(T,\{\fl=0\})$}\kbdsidx{poldiscfactors}\label{se:poldiscfactors} Given a polynomial $T$ with integer coefficients, return $[D, \var{faD}]$ where $D$ is the discriminant of $T$ and \var{faD} is a cheap partial factorization of $|D|$: entries in its first column are coprime and not perfect powers but need not be primes. The factors are obtained by a combination of trial division, testing for perfect powers, factorizations in coprimes, and computing Euclidean remainder sequences for $(T,T')$ modulo composite factors $d$ of $D$ (which is likely to produce $0$-divisors in $\Z/d\Z$). If \fl\ is $1$, finish the factorization using \kbd{factorint}. \bprog ? T = x^3 - 6021021*x^2 + 12072210077769*x - 8092423140177664432; ? [D,faD] = poldiscfactors(T); print(faD); D [3, 3; 7, 2; 373, 2; 500009, 2; 24639061, 2] %2 = -27937108625866859018515540967767467 ? T = x^3 + 9*x^2 + 27*x - 125014250689643346789780229390526092263790263725; ? [D,faD] = poldiscfactors(T); print(faD) [2, 6; 3, 3; 125007125141751093502187, 4] ? [D,faD] = poldiscfactors(T, 1); print(faD) [2, 6; 3, 3; 500009, 12; 1000003, 4] @eprog The library syntax is \fun{GEN}{poldiscfactors}{GEN T, long flag}. \subsec{poldiscreduced$(f)$}\kbdsidx{poldiscreduced}\label{se:poldiscreduced} Reduced discriminant vector of the (integral, monic) polynomial $f$. This is the vector of elementary divisors of $\Z[\alpha]/f'(\alpha)\Z[\alpha]$, where $\alpha$ is a root of the polynomial $f$. The components of the result are all positive, and their product is equal to the absolute value of the discriminant of~$f$. The library syntax is \fun{GEN}{reduceddiscsmith}{GEN f}. \subsec{polgraeffe$(f)$}\kbdsidx{polgraeffe}\label{se:polgraeffe} Returns the \idx{Graeffe} transform $g$ of $f$, such that $g(x^2) = f(x) f(-x)$. The library syntax is \fun{GEN}{polgraeffe}{GEN f}. \subsec{polhensellift$(A, B, p, e)$}\kbdsidx{polhensellift}\label{se:polhensellift} Given a prime $p$, an integral polynomial $A$ whose leading coefficient is a $p$-unit, a vector $B$ of integral polynomials that are monic and pairwise relatively prime modulo $p$, and whose product is congruent to $A/\text{lc}(A)$ modulo $p$, lift the elements of $B$ to polynomials whose product is congruent to $A$ modulo $p^e$. More generally, if $T$ is an integral polynomial irreducible mod $p$, and $B$ is a factorization of $A$ over the finite field $\F_p[t]/(T)$, you can lift it to $\Z_p[t]/(T, p^e)$ by replacing the $p$ argument with $[p,T]$: \bprog ? { T = t^3 - 2; p = 7; A = x^2 + t + 1; B = [x + (3*t^2 + t + 1), x + (4*t^2 + 6*t + 6)]; r = polhensellift(A, B, [p, T], 6) } %1 = [x + (20191*t^2 + 50604*t + 75783), x + (97458*t^2 + 67045*t + 41866)] ? liftall( r[1] * r[2] * Mod(Mod(1,p^6),T) ) %2 = x^2 + (t + 1) @eprog The library syntax is \fun{GEN}{polhensellift}{GEN A, GEN B, GEN p, long e}. \subsec{polhermite$(n,\{a='x\})$}\kbdsidx{polhermite}\label{se:polhermite} $n^{\text{th}}$ \idx{Hermite} polynomial $H_n$ evaluated at $a$ (\kbd{'x} by default), i.e. $$ H_n(x) = (-1)^n\*e^{x^2} \dfrac{d^n}{dx^n}e^{-x^2}.$$ The library syntax is \fun{GEN}{polhermite_eval}{long n, GEN a = NULL}. The variant \fun{GEN}{polhermite}{long n, long v} returns the $n$-th Hermite polynomial in variable $v$. \subsec{polinterpolate$(X,\{Y\},\{t = 'x\},\{\&e\})$}\kbdsidx{polinterpolate}\label{se:polinterpolate} Given the data vectors $X$ and $Y$ of the same length $n$ ($X$ containing the $x$-coordinates, and $Y$ the corresponding $y$-coordinates), this function finds the \idx{interpolating polynomial} $P$ of minimal degree passing through these points and evaluates it at~$t$. If $Y$ is omitted, the polynomial $P$ interpolates the $(i,X[i])$. If present, $e$ will contain an error estimate on the returned value. The library syntax is \fun{GEN}{polint}{GEN X, GEN Y = NULL, GEN t = NULL, GEN *e = NULL}. \subsec{poliscyclo$(f)$}\kbdsidx{poliscyclo}\label{se:poliscyclo} Returns 0 if $f$ is not a cyclotomic polynomial, and $n > 0$ if $f = \Phi_n$, the $n$-th cyclotomic polynomial. \bprog ? poliscyclo(x^4-x^2+1) %1 = 12 ? polcyclo(12) %2 = x^4 - x^2 + 1 ? poliscyclo(x^4-x^2-1) %3 = 0 @eprog The library syntax is \fun{long}{poliscyclo}{GEN f}. \subsec{poliscycloprod$(f)$}\kbdsidx{poliscycloprod}\label{se:poliscycloprod} Returns 1 if $f$ is a product of cyclotomic polynomial, and $0$ otherwise. \bprog ? f = x^6+x^5-x^3+x+1; ? poliscycloprod(f) %2 = 1 ? factor(f) %3 = [ x^2 + x + 1 1] [x^4 - x^2 + 1 1] ? [ poliscyclo(T) | T <- %[,1] ] %4 = [3, 12] ? polcyclo(3) * polcyclo(12) %5 = x^6 + x^5 - x^3 + x + 1 @eprog The library syntax is \fun{long}{poliscycloprod}{GEN f}. \subsec{polisirreducible$(\var{pol})$}\kbdsidx{polisirreducible}\label{se:polisirreducible} \var{pol} being a polynomial (univariate in the present version \vers), returns 1 if \var{pol} is non-constant and irreducible, 0 otherwise. Irreducibility is checked over the smallest base field over which \var{pol} seems to be defined. The library syntax is \fun{long}{isirreducible}{GEN pol}. \subsec{pollead$(x,\{v\})$}\kbdsidx{pollead}\label{se:pollead} Leading coefficient of the polynomial or power series $x$. This is computed with respect to the main variable of $x$ if $v$ is omitted, with respect to the variable $v$ otherwise. The library syntax is \fun{GEN}{pollead}{GEN x, long v = -1} where \kbd{v} is a variable number. \subsec{pollegendre$(n,\{a='x\})$}\kbdsidx{pollegendre}\label{se:pollegendre} $n^{\text{th}}$ \idx{Legendre polynomial} evaluated at $a$ (\kbd{'x} by default). The library syntax is \fun{GEN}{pollegendre_eval}{long n, GEN a = NULL}. To obtain the $n$-th Legendre polynomial in variable $v$, use \fun{GEN}{pollegendre}{long n, long v}. \subsec{polmodular$(L, \{\var{inv} = 0\}, \{x = 'x\}, \{y = 'y\}, \{\var{derivs} = 0\})$}\kbdsidx{polmodular}\label{se:polmodular} Return the modular polynomial of prime level $L$ in variables $x$ and $y$ for the modular function specified by \kbd{inv}. If \kbd{inv} is 0 (the default), use the modular $j$ function, if \kbd{inv} is 1 use the Weber-$f$ function, and if \kbd{inv} is 5 use $\gamma_2 = \sqrt[3]{j}$. See \kbd{polclass} for the full list of invariants. If $x$ is given as \kbd{Mod(j, p)} or an element $j$ of a finite field (as a \typ{FFELT}), then return the modular polynomial of level $L$ evaluated at $j$. If $j$ is from a finite field and \kbd{derivs} is non-zero, then return a triple where the last two elements are the first and second derivatives of the modular polynomial evaluated at $j$. \bprog ? polmodular(3) %1 = x^4 + (-y^3 + 2232*y^2 - 1069956*y + 36864000)*x^3 + ... ? polmodular(7, 1, , 'J) %2 = x^8 - J^7*x^7 + 7*J^4*x^4 - 8*J*x + J^8 ? polmodular(7, 5, 7*ffgen(19)^0, 'j) %3 = j^8 + 4*j^7 + 4*j^6 + 8*j^5 + j^4 + 12*j^2 + 18*j + 18 ? polmodular(7, 5, Mod(7,19), 'j) %4 = Mod(1, 19)*j^8 + Mod(4, 19)*j^7 + Mod(4, 19)*j^6 + ... ? u = ffgen(5)^0; T = polmodular(3,0,,'j)*u; ? polmodular(3, 0, u,'j,1) %6 = [j^4 + 3*j^2 + 4*j + 1, 3*j^2 + 2*j + 4, 3*j^3 + 4*j^2 + 4*j + 2] ? subst(T,x,u) %7 = j^4 + 3*j^2 + 4*j + 1 ? subst(T',x,u) %8 = 3*j^2 + 2*j + 4 ? subst(T'',x,u) %9 = 3*j^3 + 4*j^2 + 4*j + 2 @eprog The library syntax is \fun{GEN}{polmodular}{long L, long inv, GEN x = NULL, long y = -1, long derivs} where \kbd{y} is a variable number. \subsec{polrecip$(\var{pol})$}\kbdsidx{polrecip}\label{se:polrecip} Reciprocal polynomial of \var{pol}, i.e.~the coefficients are in reverse order. \var{pol} must be a polynomial. The library syntax is \fun{GEN}{polrecip}{GEN pol}. \subsec{polresultant$(x,y,\{v\},\{\fl=0\})$}\kbdsidx{polresultant}\label{se:polresultant} Resultant of the two polynomials $x$ and $y$ with exact entries, with respect to the main variables of $x$ and $y$ if $v$ is omitted, with respect to the variable $v$ otherwise. The algorithm assumes the base ring is a domain. If you also need the $u$ and $v$ such that $x*u + y*v = \text{Res}(x,y)$, use the \tet{polresultantext} function. If $\fl=0$ (default), uses the algorithm best suited to the inputs, either the \idx{subresultant algorithm} (Lazard/Ducos variant, generic case), a modular algorithm (inputs in $\Q[X]$) or Sylvester's matrix (inexact inputs). If $\fl=1$, uses the determinant of Sylvester's matrix instead; this should always be slower than the default. If $x$ or $y$ are multivariate with a huge \emph{polynomial} content, it is advisable to remove it before calling this function. Compare: \bprog ? a = polcyclo(7) * ((t+1)/(t+2))^100; ? b = polcyclo(11)* ((t+2)/(t+3))^100); ? polresultant(a,b); time = 3,833 ms. ? ca = content(a); cb = content(b); \ polresultant(a/ca,b/cb)*ca^poldegree(b)*cb*poldegree(a); \\ instantaneous @eprog\noindent The function only removes rational denominators and does not compute automatically the content because it is generically small and potentially \emph{very} expensive (e.g. in multivariate contexts). The choice is yours, depending on your application. The library syntax is \fun{GEN}{polresultant0}{GEN x, GEN y, long v = -1, long flag} where \kbd{v} is a variable number. \subsec{polresultantext$(A,B,\{v\})$}\kbdsidx{polresultantext}\label{se:polresultantext} Finds polynomials $U$ and $V$ such that $A*U + B*V = R$, where $R$ is the resultant of $U$ and $V$ with respect to the main variables of $A$ and $B$ if $v$ is omitted, and with respect to $v$ otherwise. Returns the row vector $[U,V,R]$. The algorithm used (subresultant) assumes that the base ring is a domain. \bprog ? A = x*y; B = (x+y)^2; ? [U,V,R] = polresultantext(A, B) %2 = [-y*x - 2*y^2, y^2, y^4] ? A*U + B*V %3 = y^4 ? [U,V,R] = polresultantext(A, B, y) %4 = [-2*x^2 - y*x, x^2, x^4] ? A*U+B*V %5 = x^4 @eprog The library syntax is \fun{GEN}{polresultantext0}{GEN A, GEN B, long v = -1} where \kbd{v} is a variable number. Also available is \fun{GEN}{polresultantext}{GEN x, GEN y}. \subsec{polroots$(T)$}\kbdsidx{polroots}\label{se:polroots} Complex roots of the polynomial $T$, given as a column vector where each root is repeated according to its multiplicity. The precision is given as for transcendental functions: in GP it is kept in the variable \kbd{realprecision} and is transparent to the user, but it must be explicitly given as a second argument in library mode. The algorithm used is a modification of Sch\"onhage\sidx{Sch\"onage}'s root-finding algorithm, due to and originally implemented by Gourdon. It is guaranteed to converge; if furthermore $T$ has rational coefficients, roots are guaranteed to the required relative accuracy. The library syntax is \fun{GEN}{roots}{GEN T, long prec}. \subsec{polrootsbound$(T, \{\var{tau} = 0.01\})$}\kbdsidx{polrootsbound}\label{se:polrootsbound} Return a sharp upper bound $B$ for the modulus of the largest complex root of the polynomial $T$ with complex coefficients with relative error $\tau$. More precisely, we have $|z| \leq B$ for all roots and there exist one root such that $|z_0| \geq B \exp(-2\tau)$. Much faster than either polroots or polrootsreal. \bprog ? T=poltchebi(500); ? vecmax(abs(polroots(T))) time = 5,706 ms. %2 = 0.99999506520185816611184481744870013191 ? vecmax(abs(polrootsreal(T))) time = 1,972 ms. %3 = 0.99999506520185816611184481744870013191 ? polrootsbound(T) time = 217 ms. %4 = 1.0098792554165905155 ? polrootsbound(T, log(2)/2) \\ allow a factor 2, much faster time = 51 ms. %5 = 1.4065759938190154354 ? polrootsbound(T, 1e-4) time = 504 ms. %6 = 1.0000920717983847741 ? polrootsbound(T, 1e-6) time = 810 ms. %7 = 0.9999960628901692905 ? polrootsbound(T, 1e-10) time = 1,351 ms. %8 = 0.9999950652993869760 @eprog The library syntax is \fun{GEN}{polrootsbound}{GEN T, GEN tau = NULL}. \subsec{polrootsff$(x,\{p\},\{a\})$}\kbdsidx{polrootsff}\label{se:polrootsff} Obsolete, kept for backward compatibility: use factormod. The library syntax is \fun{GEN}{polrootsff}{GEN x, GEN p = NULL, GEN a = NULL}. \subsec{polrootsmod$(f,\{D\})$}\kbdsidx{polrootsmod}\label{se:polrootsmod} Vector of roots of the polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. \noindent Multiple roots are \emph{not} repeated. \bprog ? polrootsmod(x^2-1,2) %1 = [Mod(1, 2)]~ ? polrootsmod(x^2+1,3) %2 = []~ ? polrootsmod(x^2+1, [3,y^2+1]) %3 = [Mod(Mod(1, 3)*y, Mod(1, 3)*y^2 + Mod(1, 3)), Mod(Mod(2, 3)*y, Mod(1, 3)*y^2 + Mod(1, 3))]~ ? polrootsmod(x^2 + Mod(1,3)) %4 = []~ ? liftall( polrootsmod(x^2 + Mod(Mod(1,3),y^2+1)) ) %5 = [y, 2*y]~ ? t = ffgen(y^2+Mod(1,3)); polrootsmod(x^2 + t^0) %6 = [y, 2*y]~ @eprog The library syntax is \fun{GEN}{polrootsmod}{GEN f, GEN D = NULL}. \subsec{polrootspadic$(x,p,r)$}\kbdsidx{polrootspadic}\label{se:polrootspadic} Vector of $p$-adic roots of the polynomial \var{pol}, given to $p$-adic precision $r$; the integer $p$ is assumed to be a prime. Multiple roots are \emph{not} repeated. Note that this is not the same as the roots in $\Z/p^r\Z$, rather it gives approximations in $\Z/p^r\Z$ of the true roots living in $\Q_p$. \bprog ? polrootspadic(x^3 - x^2 + 64, 2, 5) %1 = [2^3 + O(2^5), 2^3 + 2^4 + O(2^5), 1 + O(2^5)]~ @eprog If \var{pol} has inexact \typ{PADIC} coefficients, this is not always well-defined; in this case, the polynomial is first made integral by dividing out the $p$-adic content, then lifted to $\Z$ using \tet{truncate} coefficientwise. Hence the roots given are approximations of the roots of an exact polynomial which is $p$-adically close to the input. To avoid pitfalls, we advise to only factor polynomials with exact rational coefficients. The library syntax is \fun{GEN}{rootpadic}{GEN x, GEN p, long r}. \subsec{polrootsreal$(T, \{\var{ab}\})$}\kbdsidx{polrootsreal}\label{se:polrootsreal} Real roots of the polynomial $T$ with real coefficients, multiple roots being included according to their multiplicity. If the polynomial does not have rational coefficients, it is first rescaled and rounded. The roots are given to a relative accuracy of \kbd{realprecision}. If argument \var{ab} is present, it must be a vector $[a,b]$ with two components (of type \typ{INT}, \typ{FRAC} or \typ{INFINITY}) and we restrict to roots belonging to that closed interval. \bprog ? \p9 ? polrootsreal(x^2-2) %1 = [-1.41421356, 1.41421356]~ ? polrootsreal(x^2-2, [1,+oo]) %2 = [1.41421356]~ ? polrootsreal(x^2-2, [2,3]) %3 = []~ ? polrootsreal((x-1)*(x-2), [2,3]) %4 = [2.00000000]~ @eprog\noindent The algorithm used is a modification of Uspensky's method (relying on Descartes's rule of sign), following Rouillier and Zimmerman's article ``Efficient isolation of a polynomial real roots'' (\url{http://hal.inria.fr/inria-00072518/}). Barring bugs, it is guaranteed to converge and to give the roots to the required accuracy. \misctitle{Remark} If the polynomial $T$ is of the form $Q(x^h)$ for some $h\geq 2$ and \var{ab} is omitted, the routine will apply the algorithm to $Q$ (restricting to non-negative roots when $h$ is even), then take $h$-th roots. On the other hand, if you want to specify \var{ab}, you should apply the routine to $Q$ yourself and a suitable interval $[a',b']$ using approximate $h$-th roots adapted to your problem: the function will not perform this change of variables if \var{ab} is present. The library syntax is \fun{GEN}{realroots}{GEN T, GEN ab = NULL, long prec}. \subsec{polsturm$(T,\{\var{ab}\})$}\kbdsidx{polsturm}\label{se:polsturm} Number of distinct real roots of the real polynomial \var{T}. If the argument \var{ab} is present, it must be a vector $[a,b]$ with two real components (of type \typ{INT}, \typ{REAL}, \typ{FRAC} or \typ{INFINITY}) and we count roots belonging to that closed interval. If possible, you should stick to exact inputs, that is avoid \typ{REAL}s in $T$ and the bounds $a,b$: the result is then guaranteed and we use a fast algorithm (Uspensky's method, relying on Descartes's rule of sign, see \tet{polrootsreal}). Otherwise, the polynomial is rescaled and rounded first and the result may be wrong due to that initial error. If only $a$ or $b$ is inexact, on the other hand, the interval is first thickened using rational endpoints and the result remains guaranteed unless there exist a root \emph{very} close to a non-rational endpoint (which may be missed or unduly included). \bprog ? T = (x-1)*(x-2)*(x-3); ? polsturm(T) %2 = 3 ? polsturm(T, [-oo,2]) %3 = 2 ? polsturm(T, [1/2,+oo]) %4 = 3 ? polsturm(T, [1, Pi]) \\ Pi inexact: not recommended ! %5 = 3 ? polsturm(T*1., [0, 4]) \\ T*1. inexact: not recommended ! %6 = 3 ? polsturm(T^2, [0, 4]) \\ not squarefree: roots are not repeated! %7 = 3 @eprog %\syn{NO} The library syntax is \fun{long}{RgX_sturmpart}{GEN T, GEN ab} or \fun{long}{sturm}{GEN T} (for the case \kbd{ab = NULL}). The function \fun{long}{sturmpart}{GEN T, GEN a, GEN b} is obsolete and deprecated. \subsec{polsubcyclo$(n,d,\{v='x\})$}\kbdsidx{polsubcyclo}\label{se:polsubcyclo} Gives polynomials (in variable $v$) defining the sub-Abelian extensions of degree $d$ of the cyclotomic field $\Q(\zeta_n)$, where $d\mid \phi(n)$. If there is exactly one such extension the output is a polynomial, else it is a vector of polynomials, possibly empty. To get a vector in all cases, use \kbd{concat([], polsubcyclo(n,d))}. The function \tet{galoissubcyclo} allows to specify exactly which sub-Abelian extension should be computed. The library syntax is \fun{GEN}{polsubcyclo}{long n, long d, long v = -1} where \kbd{v} is a variable number. \subsec{polsylvestermatrix$(x,y)$}\kbdsidx{polsylvestermatrix}\label{se:polsylvestermatrix} Forms the Sylvester matrix corresponding to the two polynomials $x$ and $y$, where the coefficients of the polynomials are put in the columns of the matrix (which is the natural direction for solving equations afterwards). The use of this matrix can be essential when dealing with polynomials with inexact entries, since polynomial Euclidean division doesn't make much sense in this case. The library syntax is \fun{GEN}{sylvestermatrix}{GEN x, GEN y}. \subsec{polsym$(x,n)$}\kbdsidx{polsym}\label{se:polsym} Creates the column vector of the \idx{symmetric powers} of the roots of the polynomial $x$ up to power $n$, using Newton's formula. The library syntax is \fun{GEN}{polsym}{GEN x, long n}. \subsec{poltchebi$(n,\{v='x\})$}\kbdsidx{poltchebi}\label{se:poltchebi} Deprecated alias for \kbd{polchebyshev} The library syntax is \fun{GEN}{polchebyshev1}{long n, long v = -1} where \kbd{v} is a variable number. \subsec{polzagier$(n,m)$}\kbdsidx{polzagier}\label{se:polzagier} Creates Zagier's polynomial $P_n^{(m)}$ used in the functions \kbd{sumalt} and \kbd{sumpos} (with $\fl=1$), see ``Convergence acceleration of alternating series'', Cohen et al., \emph{Experiment.~Math.}, vol.~9, 2000, pp.~3--12. If $m < 0$ or $m \ge n$, $P_n^{(m)} = 0$. We have $P_n := P_n^{(0)}$ is $T_n(2x-1)$, where $T_n$ is the Legendre polynomial of the second kind. For $n > m > 0$, $P_n^{(m)}$ is the $m$-th difference with step $2$ of the sequence $n^{m+1}P_n$; in this case, it satisfies $$2 P_n^{(m)}(sin^2 t) = \dfrac{d^{m+1}}{dt^{m+1}}(\sin(2t)^m \sin(2(n-m)t)).$$ %@article {MR2001m:11222, % AUTHOR = {Cohen, Henri and Rodriguez Villegas, Fernando and Zagier, Don}, % TITLE = {Convergence acceleration of alternating series}, % JOURNAL = {Experiment. Math.}, % VOLUME = {9}, % YEAR = {2000}, % NUMBER = {1}, % PAGES = {3--12}, %} The library syntax is \fun{GEN}{polzag}{long n, long m}. \subsec{serconvol$(x,y)$}\kbdsidx{serconvol}\label{se:serconvol} Convolution (or \idx{Hadamard product}) of the two power series $x$ and $y$; in other words if $x=\sum a_k*X^k$ and $y=\sum b_k*X^k$ then $\kbd{serconvol}(x,y)=\sum a_k*b_k*X^k$. The library syntax is \fun{GEN}{convol}{GEN x, GEN y}. \subsec{serlaplace$(x)$}\kbdsidx{serlaplace}\label{se:serlaplace} $x$ must be a power series with non-negative exponents or a polynomial. If $x=\sum (a_k/k!)*X^k$ then the result is $\sum a_k*X^k$. The library syntax is \fun{GEN}{laplace}{GEN x}. \subsec{serreverse$(s)$}\kbdsidx{serreverse}\label{se:serreverse} Reverse power series of $s$, i.e. the series $t$ such that $t(s) = x$; $s$ must be a power series whose valuation is exactly equal to one. \bprog ? \ps 8 ? t = serreverse(tan(x)) %2 = x - 1/3*x^3 + 1/5*x^5 - 1/7*x^7 + O(x^8) ? tan(t) %3 = x + O(x^8) @eprog The library syntax is \fun{GEN}{serreverse}{GEN s}. \subsec{subst$(x,y,z)$}\kbdsidx{subst}\label{se:subst} Replace the simple variable $y$ by the argument $z$ in the ``polynomial'' expression $x$. Every type is allowed for $x$, but if it is not a genuine polynomial (or power series, or rational function), the substitution will be done as if the scalar components were polynomials of degree zero. In particular, beware that: \bprog ? subst(1, x, [1,2; 3,4]) %1 = [1 0] [0 1] ? subst(1, x, Mat([0,1])) *** at top-level: subst(1,x,Mat([0,1]) *** ^-------------------- *** subst: forbidden substitution by a non square matrix. @eprog\noindent If $x$ is a power series, $z$ must be either a polynomial, a power series, or a rational function. Finally, if $x$ is a vector, matrix or list, the substitution is applied to each individual entry. Use the function \kbd{substvec} to replace several variables at once, or the function \kbd{substpol} to replace a polynomial expression. The library syntax is \fun{GEN}{gsubst}{GEN x, long y, GEN z} where \kbd{y} is a variable number. \subsec{substpol$(x,y,z)$}\kbdsidx{substpol}\label{se:substpol} Replace the ``variable'' $y$ by the argument $z$ in the ``polynomial'' expression $x$. Every type is allowed for $x$, but the same behavior as \kbd{subst} above apply. The difference with \kbd{subst} is that $y$ is allowed to be any polynomial here. The substitution is done moding out all components of $x$ (recursively) by $y - t$, where $t$ is a new free variable of lowest priority. Then substituting $t$ by $z$ in the resulting expression. For instance \bprog ? substpol(x^4 + x^2 + 1, x^2, y) %1 = y^2 + y + 1 ? substpol(x^4 + x^2 + 1, x^3, y) %2 = x^2 + y*x + 1 ? substpol(x^4 + x^2 + 1, (x+1)^2, y) %3 = (-4*y - 6)*x + (y^2 + 3*y - 3) @eprog The library syntax is \fun{GEN}{gsubstpol}{GEN x, GEN y, GEN z}. Further, \fun{GEN}{gdeflate}{GEN T, long v, long d} attempts to write $T(x)$ in the form $t(x^d)$, where $x=$\kbd{pol\_x}$(v)$, and returns \kbd{NULL} if the substitution fails (for instance in the example \kbd{\%2} above). \subsec{substvec$(x,v,w)$}\kbdsidx{substvec}\label{se:substvec} $v$ being a vector of monomials of degree 1 (variables), $w$ a vector of expressions of the same length, replace in the expression $x$ all occurrences of $v_i$ by $w_i$. The substitutions are done simultaneously; more precisely, the $v_i$ are first replaced by new variables in $x$, then these are replaced by the $w_i$: \bprog ? substvec([x,y], [x,y], [y,x]) %1 = [y, x] ? substvec([x,y], [x,y], [y,x+y]) %2 = [y, x + y] \\ not [y, 2*y] @eprog The library syntax is \fun{GEN}{gsubstvec}{GEN x, GEN v, GEN w}. \subsec{sumformal$(f,\{v\})$}\kbdsidx{sumformal}\label{se:sumformal} \idx{formal sum} of the polynomial expression $f$ with respect to the main variable if $v$ is omitted, with respect to the variable $v$ otherwise; it is assumed that the base ring has characteristic zero. In other words, considering $f$ as a polynomial function in the variable $v$, returns $F$, a polynomial in $v$ vanishing at $0$, such that $F(b) - F(a) = sum_{v = a+1}^b f(v)$: \bprog ? sumformal(n) \\ 1 + ... + n %1 = 1/2*n^2 + 1/2*n ? f(n) = n^3+n^2+1; ? F = sumformal(f(n)) \\ f(1) + ... + f(n) %3 = 1/4*n^4 + 5/6*n^3 + 3/4*n^2 + 7/6*n ? sum(n = 1, 2000, f(n)) == subst(F, n, 2000) %4 = 1 ? sum(n = 1001, 2000, f(n)) == subst(F, n, 2000) - subst(F, n, 1000) %5 = 1 ? sumformal(x^2 + x*y + y^2, y) %6 = y*x^2 + (1/2*y^2 + 1/2*y)*x + (1/3*y^3 + 1/2*y^2 + 1/6*y) ? x^2 * y + x * sumformal(y) + sumformal(y^2) == % %7 = 1 @eprog The library syntax is \fun{GEN}{sumformal}{GEN f, long v = -1} where \kbd{v} is a variable number. \subsec{taylor$(x,t,\{d=\var{seriesprecision}\})$}\kbdsidx{taylor}\label{se:taylor} Taylor expansion around $0$ of $x$ with respect to the simple variable $t$. $x$ can be of any reasonable type, for example a rational function. Contrary to \tet{Ser}, which takes the valuation into account, this function adds $O(t^d)$ to all components of $x$. \bprog ? taylor(x/(1+y), y, 5) %1 = (y^4 - y^3 + y^2 - y + 1)*x + O(y^5) ? Ser(x/(1+y), y, 5) *** at top-level: Ser(x/(1+y),y,5) *** ^---------------- *** Ser: main variable must have higher priority in gtoser. @eprog The library syntax is \fun{GEN}{tayl}{GEN x, long t, long precdl} where \kbd{t} is a variable number. \subsec{thue$(\var{tnf},a,\{\var{sol}\})$}\kbdsidx{thue}\label{se:thue} Returns all solutions of the equation $P(x,y)=a$ in integers $x$ and $y$, where \var{tnf} was created with $\kbd{thueinit}(P)$. If present, \var{sol} must contain the solutions of $\Norm(x)=a$ modulo units of positive norm in the number field defined by $P$ (as computed by \kbd{bnfisintnorm}). If there are infinitely many solutions, an error is issued. It is allowed to input directly the polynomial $P$ instead of a \var{tnf}, in which case, the function first performs \kbd{thueinit(P,0)}. This is very wasteful if more than one value of $a$ is required. If \var{tnf} was computed without assuming GRH (flag $1$ in \tet{thueinit}), then the result is unconditional. Otherwise, it depends in principle of the truth of the GRH, but may still be unconditionally correct in some favorable cases. The result is conditional on the GRH if $a\neq \pm 1$ and $P$ has a single irreducible rational factor, whose attached tentative class number $h$ and regulator $R$ (as computed assuming the GRH) satisfy \item $h > 1$, \item $R/0.2 > 1.5$. Here's how to solve the Thue equation $x^{13} - 5y^{13} = - 4$: \bprog ? tnf = thueinit(x^13 - 5); ? thue(tnf, -4) %1 = [[1, 1]] @eprog\noindent In this case, one checks that \kbd{bnfinit(x\pow13 -5).no} is $1$. Hence, the only solution is $(x,y) = (1,1)$ and the result is unconditional. On the other hand: \bprog ? P = x^3-2*x^2+3*x-17; tnf = thueinit(P); ? thue(tnf, -15) %2 = [[1, 1]] \\ a priori conditional on the GRH. ? K = bnfinit(P); K.no %3 = 3 ? K.reg %4 = 2.8682185139262873674706034475498755834 @eprog This time the result is conditional. All results computed using this particular \var{tnf} are likewise conditional, \emph{except} for a right-hand side of $\pm 1$. The above result is in fact correct, so we did not just disprove the GRH: \bprog ? tnf = thueinit(x^3-2*x^2+3*x-17, 1 /*unconditional*/); ? thue(tnf, -15) %4 = [[1, 1]] @eprog Note that reducible or non-monic polynomials are allowed: \bprog ? tnf = thueinit((2*x+1)^5 * (4*x^3-2*x^2+3*x-17), 1); ? thue(tnf, 128) %2 = [[-1, 0], [1, 0]] @eprog\noindent Reducible polynomials are in fact much easier to handle. \misctitle{Note} When $P$ is irreducible without a real root, the default strategy is to use brute force enumeration in time $|a|^{1/\deg P}$ and avoid computing a touch \var{bnf} attached to $P$, see \kbd{thueinit}. Besides reusing a quantity you might need for other purposes, the default argument \emph{sol} can also be used to use a different strategy and prove that there are no solutions; of course you need to compute a \var{bnf} on you own to obtain \emph{sol}. If there \emph{are} solutions this won't help unless $P$ is quadratic, since the enumeration will be performed in any case. The library syntax is \fun{GEN}{thue}{GEN tnf, GEN a, GEN sol = NULL}. \subsec{thueinit$(P,\{\fl=0\})$}\kbdsidx{thueinit}\label{se:thueinit} Initializes the \var{tnf} corresponding to $P$, a non-constant univariate polynomial with integer coefficients. The result is meant to be used in conjunction with \tet{thue} to solve Thue equations $P(X / Y)Y^{\deg P} = a$, where $a$ is an integer. Accordingly, $P$ must either have at least two distinct irreducible factors over $\Q$, or have one irreducible factor $T$ with degree $>2$ or two conjugate complex roots: under these (necessary and sufficient) conditions, the equation has finitely many integer solutions. \bprog ? S = thueinit(t^2+1); ? thue(S, 5) %2 = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]] ? S = thueinit(t+1); *** at top-level: thueinit(t+1) *** ^------------- *** thueinit: domain error in thueinit: P = t + 1 @eprog\noindent The hardest case is when $\deg P > 2$ and $P$ is irreducible with at least one real root. The routine then uses Bilu-Hanrot's algorithm. If $\fl$ is non-zero, certify results unconditionally. Otherwise, assume \idx{GRH}, this being much faster of course. In the latter case, the result may still be unconditionally correct, see \tet{thue}. For instance in most cases where $P$ is reducible (not a pure power of an irreducible), \emph{or} conditional computed class groups are trivial \emph{or} the right hand side is $\pm1$, then results are unconditional. \misctitle{Note} The general philosophy is to disprove the existence of large solutions then to enumerate bounded solutions naively. The implementation will overflow when there exist huge solutions and the equation has degree $> 2$ (the quadratic imaginary case is special, since we can stick to \kbd{bnfisintnorm}, there are no fundamental units): \bprog ? thue(t^3+2, 10^30) *** at top-level: L=thue(t^3+2,10^30) *** ^----------------- *** thue: overflow in thue (SmallSols): y <= 80665203789619036028928. ? thue(x^2+2, 10^30) \\ quadratic case much easier %1 = [[-1000000000000000, 0], [1000000000000000, 0]] @eprog \misctitle{Note} It is sometimes possible to circumvent the above, and in any case obtain an important speed-up, if you can write $P = Q(x^d)$ for some $d > 1$ and $Q$ still satisfying the \kbd{thueinit} hypotheses. You can then solve the equation attached to $Q$ then eliminate all solutions $(x,y)$ such that either $x$ or $y$ is not a $d$-th power. \bprog ? thue(x^4+1, 10^40); \\ stopped after 10 hours ? filter(L,d) = my(x,y); [[x,y] | v<-L, ispower(v[1],d,&x)&&ispower(v[2],d,&y)]; ? L = thue(x^2+1, 10^40); ? filter(L, 2) %4 = [[0, 10000000000], [10000000000, 0]] @eprog\noindent The last 2 commands use less than 20ms. \misctitle{Note} When $P$ is irreducible without a real root, the equation can be solved unconditionnally in time $|a|^{1/\deg P}$. When this latter quantity is huge and the equation has no solutions, this fact may still be ascertained via arithmetic conditions but this now implies solving norm equations, computing a \var{bnf} and possibly assuming the GRH. When there is no real root, the code does not compute a \var{bnf} (with certification if $\fl = 1$) if it expects this to be an ``easy'' computation (because the result would only be used for huge values of $a$). See \kbd{thue} for a way to compute an expensive \var{bnf} on your own and still get a result where this default cheap strategy fails. The library syntax is \fun{GEN}{thueinit}{GEN P, long flag, long prec}. \section{Vectors, matrices, linear algebra and sets} \label{se:linear_algebra} Note that most linear algebra functions operating on subspaces defined by generating sets (such as \tet{mathnf}, \tet{qflll}, etc.) take matrices as arguments. As usual, the generating vectors are taken to be the \emph{columns} of the given matrix. Since PARI does not have a strong typing system, scalars live in unspecified commutative base rings. It is very difficult to write robust linear algebra routines in such a general setting. We thus assume that the base ring is a domain and work over its field of fractions. If the base ring is \emph{not} a domain, one gets an error as soon as a non-zero pivot turns out to be non-invertible. Some functions, e.g.~\kbd{mathnf} or \kbd{mathnfmod}, specifically assume that the base ring is $\Z$. \subsec{algdep$(z,k,\{\fl=0\})$}\kbdsidx{algdep}\label{se:algdep} \sidx{algebraic dependence} $z$ being real/complex, or $p$-adic, finds a polynomial (in the variable \kbd{'x}) of degree at most $k$, with integer coefficients, having $z$ as approximate root. Note that the polynomial which is obtained is not necessarily the ``correct'' one. In fact it is not even guaranteed to be irreducible. One can check the closeness either by a polynomial evaluation (use \tet{subst}), or by computing the roots of the polynomial given by \kbd{algdep} (use \tet{polroots} or \tet{polrootspadic}). Internally, \tet{lindep}$([1,z,\ldots,z^k], \fl)$ is used. A non-zero value of $\fl$ may improve on the default behavior if the input number is known to a \emph{huge} accuracy, and you suspect the last bits are incorrect: if $\fl > 0$ the computation is done with an accuracy of $\fl$ decimal digits; to get meaningful results, the parameter $\fl$ should be smaller than the number of correct decimal digits in the input. But default values are usually sufficient, so try without $\fl$ first: \bprog ? \p200 ? z = 2^(1/6)+3^(1/5); ? algdep(z, 30); \\ right in 280ms ? algdep(z, 30, 100); \\ wrong in 169ms ? algdep(z, 30, 170); \\ right in 288ms ? algdep(z, 30, 200); \\ wrong in 320ms ? \p250 ? z = 2^(1/6)+3^(1/5); \\ recompute to new, higher, accuracy ! ? algdep(z, 30); \\ right in 329ms ? algdep(z, 30, 200); \\ right in 324ms ? \p500 ? algdep(2^(1/6)+3^(1/5), 30); \\ right in 677ms ? \p1000 ? algdep(2^(1/6)+3^(1/5), 30); \\ right in 1.5s @eprog\noindent The changes in \kbd{realprecision} only affect the quality of the initial approximation to $2^{1/6} + 3^{1/5}$, \kbd{algdep} itself uses exact operations. The size of its operands depend on the accuracy of the input of course: more accurate input means slower operations. Proceeding by increments of 5 digits of accuracy, \kbd{algdep} with default flag produces its first correct result at 195 digits, and from then on a steady stream of correct results: \bprog \\ assume T contains the correct result, for comparison forstep(d=100, 250, 5, localprec(d);\ print(d, " ", algdep(2^(1/6)+3^(1/5),30) == T)) @eprog The above example is the test case studied in a 2000 paper by Borwein and Lisonek: Applications of integer relation algorithms, \emph{Discrete Math.}, {\bf 217}, p.~65--82. The version of PARI tested there was 1.39, which succeeded reliably from precision 265 on, in about 200 as much time as the current version. The library syntax is \fun{GEN}{algdep0}{GEN z, long k, long flag}. Also available is \fun{GEN}{algdep}{GEN z, long k} ($\fl=0$). \subsec{bestapprnf$(V,T,\{\var{rootT}\})$}\kbdsidx{bestapprnf}\label{se:bestapprnf} $T$ being an integral polynomial and $V$ being a scalar, vector, or matrix with complex coefficients, return a reasonable approximation of $V$ with polmods modulo $T$. $T$ can also be any number field structure, in which case the minimal polynomial attached to the structure (\kbd{$T$}.pol) is used. The \var{rootT} argument, if present, must be an element of \kbd{polroots($T$)} (or \kbd{$T$}.pol), i.e.~a complex root of $T$ fixing an embedding of $\Q[x]/(T)$ into $\C$. \bprog ? bestapprnf(sqrt(5), polcyclo(5)) %1 = Mod(-2*x^3 - 2*x^2 - 1, x^4 + x^3 + x^2 + x + 1) ? bestapprnf(sqrt(5), polcyclo(5), exp(4*I*Pi/5)) %2 = Mod(2*x^3 + 2*x^2 + 1, x^4 + x^3 + x^2 + x + 1) @eprog\noindent When the output has huge rational coefficients, try to increase the working \kbd{realbitprecision}: if the answer does not stabilize, consider that the reconstruction failed. Beware that if $T$ is not Galois over $\Q$, some embeddings may not allow to reconstruct $V$: \bprog ? T = x^3-2; vT = polroots(T); z = 3*2^(1/3)+1; ? bestapprnf(z, T, vT[1]) %2 = Mod(3*x + 1, x^3 - 2) ? bestapprnf(z, T, vT[2]) %3 = 4213714286230872/186454048314072 \\ close to 3*2^(1/3) + 1 @eprog The library syntax is \fun{GEN}{bestapprnf}{GEN V, GEN T, GEN rootT = NULL, long prec}. \subsec{charpoly$(A,\{v='x\},\{\fl=5\})$}\kbdsidx{charpoly}\label{se:charpoly} \idx{characteristic polynomial} of $A$ with respect to the variable $v$, i.e.~determinant of $v*I-A$ if $A$ is a square matrix. \bprog ? charpoly([1,2;3,4]); %1 = x^2 - 5*x - 2 ? charpoly([1,2;3,4],, 't) %2 = t^2 - 5*t - 2 @eprog\noindent If $A$ is not a square matrix, the function returns the characteristic polynomial of the map ``multiplication by $A$'' if $A$ is a scalar: \bprog ? charpoly(Mod(x+2, x^3-2)) %1 = x^3 - 6*x^2 + 12*x - 10 ? charpoly(I) %2 = x^2 + 1 ? charpoly(quadgen(5)) %3 = x^2 - x - 1 ? charpoly(ffgen(ffinit(2,4))) %4 = Mod(1, 2)*x^4 + Mod(1, 2)*x^3 + Mod(1, 2)*x^2 + Mod(1, 2)*x + Mod(1, 2) @eprog The value of $\fl$ is only significant for matrices, and we advise to stick to the default value. Let $n$ be the dimension of $A$. If $\fl=0$, same method (Le Verrier's) as for computing the adjoint matrix, i.e.~using the traces of the powers of $A$. Assumes that $n!$ is invertible; uses $O(n^4)$ scalar operations. If $\fl=1$, uses Lagrange interpolation which is usually the slowest method. Assumes that $n!$ is invertible; uses $O(n^4)$ scalar operations. If $\fl=2$, uses the Hessenberg form. Assumes that the base ring is a field. Uses $O(n^3)$ scalar operations, but suffers from coefficient explosion unless the base field is finite or $\R$. If $\fl=3$, uses Berkowitz's division free algorithm, valid over any ring (commutative, with unit). Uses $O(n^4)$ scalar operations. If $\fl=4$, $x$ must be integral. Uses a modular algorithm: Hessenberg form for various small primes, then Chinese remainders. If $\fl=5$ (default), uses the ``best'' method given $x$. This means we use Berkowitz unless the base ring is $\Z$ (use $\fl=4$) or a field where coefficient explosion does not occur, e.g.~a finite field or the reals (use $\fl=2$). The library syntax is \fun{GEN}{charpoly0}{GEN A, long v = -1, long flag} where \kbd{v} is a variable number. Also available are \fun{GEN}{charpoly}{GEN x, long v} ($\fl=5$), \fun{GEN}{caract}{GEN A, long v} ($\fl=1$), \fun{GEN}{carhess}{GEN A, long v} ($\fl=2$), \fun{GEN}{carberkowitz}{GEN A, long v} ($\fl=3$) and \fun{GEN}{caradj}{GEN A, long v, GEN *pt}. In this last case, if \var{pt} is not \kbd{NULL}, \kbd{*pt} receives the address of the adjoint matrix of $A$ (see \tet{matadjoint}), so both can be obtained at once. \subsec{concat$(x,\{y\})$}\kbdsidx{concat}\label{se:concat} Concatenation of $x$ and $y$. If $x$ or $y$ is not a vector or matrix, it is considered as a one-dimensional vector. All types are allowed for $x$ and $y$, but the sizes must be compatible. Note that matrices are concatenated horizontally, i.e.~the number of rows stays the same. Using transpositions, one can concatenate them vertically, but it is often simpler to use \tet{matconcat}. \bprog ? x = matid(2); y = 2*matid(2); ? concat(x,y) %2 = [1 0 2 0] [0 1 0 2] ? concat(x~,y~)~ %3 = [1 0] [0 1] [2 0] [0 2] ? matconcat([x;y]) %4 = [1 0] [0 1] [2 0] [0 2] @eprog\noindent To concatenate vectors sideways (i.e.~to obtain a two-row or two-column matrix), use \tet{Mat} instead, or \tet{matconcat}: \bprog ? x = [1,2]; ? y = [3,4]; ? concat(x,y) %3 = [1, 2, 3, 4] ? Mat([x,y]~) %4 = [1 2] [3 4] ? matconcat([x;y]) %5 = [1 2] [3 4] @eprog Concatenating a row vector to a matrix having the same number of columns will add the row to the matrix (top row if the vector is $x$, i.e.~comes first, and bottom row otherwise). The empty matrix \kbd{[;]} is considered to have a number of rows compatible with any operation, in particular concatenation. (Note that this is \emph{not} the case for empty vectors \kbd{[~]} or \kbd{[~]\til}.) If $y$ is omitted, $x$ has to be a row vector or a list, in which case its elements are concatenated, from left to right, using the above rules. \bprog ? concat([1,2], [3,4]) %1 = [1, 2, 3, 4] ? a = [[1,2]~, [3,4]~]; concat(a) %2 = [1 3] [2 4] ? concat([1,2; 3,4], [5,6]~) %3 = [1 2 5] [3 4 6] ? concat([%, [7,8]~, [1,2,3,4]]) %5 = [1 2 5 7] [3 4 6 8] [1 2 3 4] @eprog The library syntax is \fun{GEN}{gconcat}{GEN x, GEN y = NULL}. \fun{GEN}{gconcat1}{GEN x} is a shortcut for \kbd{gconcat(x,NULL)}. \subsec{forqfvec$(v,q,b,\var{expr})$}\kbdsidx{forqfvec}\label{se:forqfvec} $q$ being a square and symmetric integral matrix representing a positive definite quadratic form, evaluate \kbd{expr} for all vector $v$ such that $q(v)\leq b$. The formal variable $v$ runs through all such vectors in turn. \bprog ? forqfvec(v, [3,2;2,3], 3, print(v)) [0, 1]~ [1, 0]~ [-1, 1]~ @eprog The library syntax is \fun{void}{forqfvec0}{GEN v, GEN q = NULL, GEN b}. The following function is also available: \fun{void}{forqfvec}{void *E, long (*fun)(void *, GEN, GEN, double), GEN q, GEN b}: Evaluate \kbd{fun(E,w,v,m)} on all $v$ such that $q(v) 0$ the computation is done with an accuracy of $\fl$ decimal digits. To get meaningful results in the latter case, the parameter $\fl$ should be smaller than the number of correct decimal digits in the input. \bprog ? lindep([sqrt(2), sqrt(3), sqrt(2)+sqrt(3)]) %1 = [-1, -1, 1]~ @eprog If $v$ is $p$-adic, $\fl$ is ignored and the algorithm LLL-reduces a suitable (dual) lattice. \bprog ? lindep([1, 2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)]) %2 = [1, -2]~ @eprog If $v$ is a matrix (or a vector of column vectors, or a vector of row vectors), $\fl$ is ignored and the function returns a non trivial kernel vector if one exists, else an empty vector. \bprog ? lindep([1,2,3;4,5,6;7,8,9]) %3 = [1, -2, 1]~ ? lindep([[1,0], [2,0]]) %4 = [2, -1]~ ? lindep([[1,0], [0,1]]) %5 = []~ @eprog If $v$ contains polynomials or power series over some base field, finds a linear relation with coefficients in the field. \bprog ? lindep([x*y, x^2 + y, x^2*y + x*y^2, 1]) %4 = [y, y, -1, -y^2]~ @eprog\noindent For better control, it is preferable to use \typ{POL} rather than \typ{SER} in the input, otherwise one gets a linear combination which is $t$-adically small, but not necessarily $0$. Indeed, power series are first converted to the minimal absolute accuracy occurring among the entries of $v$ (which can cause some coefficients to be ignored), then truncated to polynomials: \bprog ? v = [t^2+O(t^4), 1+O(t^2)]; L=lindep(v) %1 = [1, 0]~ ? v*L %2 = t^2+O(t^4) \\ small but not 0 @eprog The library syntax is \fun{GEN}{lindep0}{GEN v, long flag}. \subsec{matadjoint$(M,\{\fl=0\})$}\kbdsidx{matadjoint}\label{se:matadjoint} \idx{adjoint matrix} of $M$, i.e.~a matrix $N$ of cofactors of $M$, satisfying $M*N=\det(M)*\Id$. $M$ must be a (non-necessarily invertible) square matrix of dimension $n$. If $\fl$ is 0 or omitted, we try to use Leverrier-Faddeev's algorithm, which assumes that $n!$ invertible. If it fails or $\fl = 1$, compute $T = \kbd{charpoly}(M)$ independently first and return $(-1)^{n-1} (T(x)-T(0))/x$ evaluated at $M$. \bprog ? a = [1,2,3;3,4,5;6,7,8] * Mod(1,4); %2 = [Mod(1, 4) Mod(2, 4) Mod(3, 4)] [Mod(3, 4) Mod(0, 4) Mod(1, 4)] [Mod(2, 4) Mod(3, 4) Mod(0, 4)] @eprog\noindent Both algorithms use $O(n^4)$ operations in the base ring, and are usually slower than computing the characteristic polynomial or the inverse of $M$ directly. The library syntax is \fun{GEN}{matadjoint0}{GEN M, long flag}. Also available are \fun{GEN}{adj}{GEN x} (\fl=0) and \fun{GEN}{adjsafe}{GEN x} (\fl=1). \subsec{matcompanion$(x)$}\kbdsidx{matcompanion}\label{se:matcompanion} The left companion matrix to the non-zero polynomial $x$. The library syntax is \fun{GEN}{matcompanion}{GEN x}. \subsec{matconcat$(v)$}\kbdsidx{matconcat}\label{se:matconcat} Returns a \typ{MAT} built from the entries of $v$, which may be a \typ{VEC} (concatenate horizontally), a \typ{COL} (concatenate vertically), or a \typ{MAT} (concatenate vertically each column, and concatenate vertically the resulting matrices). The entries of $v$ are always considered as matrices: they can themselves be \typ{VEC} (seen as a row matrix), a \typ{COL} seen as a column matrix), a \typ{MAT}, or a scalar (seen as an $1 \times 1$ matrix). \bprog ? A=[1,2;3,4]; B=[5,6]~; C=[7,8]; D=9; ? matconcat([A, B]) \\ horizontal %1 = [1 2 5] [3 4 6] ? matconcat([A, C]~) \\ vertical %2 = [1 2] [3 4] [7 8] ? matconcat([A, B; C, D]) \\ block matrix %3 = [1 2 5] [3 4 6] [7 8 9] @eprog\noindent If the dimensions of the entries to concatenate do not match up, the above rules are extended as follows: \item each entry $v_{i,j}$ of $v$ has a natural length and height: $1 \times 1$ for a scalar, $1 \times n$ for a \typ{VEC} of length $n$, $n \times 1$ for a \typ{COL}, $m \times n$ for an $m\times n$ \typ{MAT} \item let $H_i$ be the maximum over $j$ of the lengths of the $v_{i,j}$, let $L_j$ be the maximum over $i$ of the heights of the $v_{i,j}$. The dimensions of the $(i,j)$-th block in the concatenated matrix are $H_i \times L_j$. \item a scalar $s = v_{i,j}$ is considered as $s$ times an identity matrix of the block dimension $\min (H_i,L_j)$ \item blocks are extended by 0 columns on the right and 0 rows at the bottom, as needed. \bprog ? matconcat([1, [2,3]~, [4,5,6]~]) \\ horizontal %4 = [1 2 4] [0 3 5] [0 0 6] ? matconcat([1, [2,3], [4,5,6]]~) \\ vertical %5 = [1 0 0] [2 3 0] [4 5 6] ? matconcat([B, C; A, D]) \\ block matrix %6 = [5 0 7 8] [6 0 0 0] [1 2 9 0] [3 4 0 9] ? U=[1,2;3,4]; V=[1,2,3;4,5,6;7,8,9]; ? matconcat(matdiagonal([U, V])) \\ block diagonal %7 = [1 2 0 0 0] [3 4 0 0 0] [0 0 1 2 3] [0 0 4 5 6] [0 0 7 8 9] @eprog The library syntax is \fun{GEN}{matconcat}{GEN v}. \subsec{matdet$(x,\{\fl=0\})$}\kbdsidx{matdet}\label{se:matdet} Determinant of the square matrix $x$. If $\fl=0$, uses an appropriate algorithm depending on the coefficients: \item integer entries: modular method due to Dixon, Pernet and Stein. \item real or $p$-adic entries: classical Gaussian elimination using maximal pivot. \item intmod entries: classical Gaussian elimination using first non-zero pivot. \item other cases: Gauss-Bareiss. If $\fl=1$, uses classical Gaussian elimination with appropriate pivoting strategy (maximal pivot for real or $p$-adic coefficients). This is usually worse than the default. The library syntax is \fun{GEN}{det0}{GEN x, long flag}. Also available are \fun{GEN}{det}{GEN x} ($\fl=0$), \fun{GEN}{det2}{GEN x} ($\fl=1$) and \fun{GEN}{ZM_det}{GEN x} for integer entries. \subsec{matdetint$(B)$}\kbdsidx{matdetint}\label{se:matdetint} Let $B$ be an $m\times n$ matrix with integer coefficients. The \emph{determinant} $D$ of the lattice generated by the columns of $B$ is the square root of $\det(B^T B)$ if $B$ has maximal rank $m$, and $0$ otherwise. This function uses the Gauss-Bareiss algorithm to compute a positive \emph{multiple} of $D$. When $B$ is square, the function actually returns $D = |\det B|$. This function is useful in conjunction with \kbd{mathnfmod}, which needs to know such a multiple. If the rank is maximal and the matrix non-square, you can obtain $D$ exactly using \bprog matdet( mathnfmod(B, matdetint(B)) ) @eprog\noindent Note that as soon as one of the dimensions gets large ($m$ or $n$ is larger than 20, say), it will often be much faster to use \kbd{mathnf(B, 1)} or \kbd{mathnf(B, 4)} directly. The library syntax is \fun{GEN}{detint}{GEN B}. \subsec{matdetmod$(x,d)$}\kbdsidx{matdetmod}\label{se:matdetmod} Given a matrix $x$ with \typ{INT} entries and $d$ an arbitrary positive integer, return the determinant of $x$ modulo $d$. \bprog ? A = [4,2,3; 4,5,6; 7,8,9] ? matdetmod(A,27) %2 = 9 @eprog Note that using the generic function \kbd{matdet} on a matrix with \typ{INTMOD} entries uses Gaussian reduction and will fail in general when the modulus is not prime. \bprog ? matdet(A * Mod(1,27)) *** at top-level: matdet(A*Mod(1,27)) *** ^------------------ *** matdet: impossible inverse in Fl_inv: Mod(3, 27). @eprog The library syntax is \fun{GEN}{matdetmod}{GEN x, GEN d}. \subsec{matdiagonal$(x)$}\kbdsidx{matdiagonal}\label{se:matdiagonal} $x$ being a vector, creates the diagonal matrix whose diagonal entries are those of $x$. \bprog ? matdiagonal([1,2,3]); %1 = [1 0 0] [0 2 0] [0 0 3] @eprog\noindent Block diagonal matrices are easily created using \tet{matconcat}: \bprog ? U=[1,2;3,4]; V=[1,2,3;4,5,6;7,8,9]; ? matconcat(matdiagonal([U, V])) %1 = [1 2 0 0 0] [3 4 0 0 0] [0 0 1 2 3] [0 0 4 5 6] [0 0 7 8 9] @eprog The library syntax is \fun{GEN}{diagonal}{GEN x}. \subsec{mateigen$(x,\{\fl=0\})$}\kbdsidx{mateigen}\label{se:mateigen} Returns the (complex) eigenvectors of $x$ as columns of a matrix. If $\fl=1$, return $[L,H]$, where $L$ contains the eigenvalues and $H$ the corresponding eigenvectors; multiple eigenvalues are repeated according to the eigenspace dimension (which may be less than the eigenvalue multiplicity in the characteristic polynomial). This function first computes the characteristic polynomial of $x$ and approximates its complex roots $(\lambda_i)$, then tries to compute the eigenspaces as kernels of the $x - \lambda_i$. This algorithm is ill-conditioned and is likely to miss kernel vectors if some roots of the characteristic polynomial are close, in particular if it has multiple roots. \bprog ? A = [13,2; 10,14]; mateigen(A) %1 = [-1/2 2/5] [ 1 1] ? [L,H] = mateigen(A, 1); ? L %3 = [9, 18] ? H %4 = [-1/2 2/5] [ 1 1] @eprog\noindent For symmetric matrices, use \tet{qfjacobi} instead; for Hermitian matrices, compute \bprog A = real(x); B = imag(x); y = matconcat([A, -B; B, A]); @eprog\noindent and apply \kbd{qfjacobi} to $y$. The library syntax is \fun{GEN}{mateigen}{GEN x, long flag, long prec}. Also available is \fun{GEN}{eigen}{GEN x, long prec} ($\fl = 0$) \subsec{matfrobenius$(M,\{\fl\},\{v='x\})$}\kbdsidx{matfrobenius}\label{se:matfrobenius} Returns the Frobenius form of the square matrix \kbd{M}. If $\fl=1$, returns only the elementary divisors as a vector of polynomials in the variable \kbd{v}. If $\fl=2$, returns a two-components vector [F,B] where \kbd{F} is the Frobenius form and \kbd{B} is the basis change so that $M=B^{-1}FB$. The library syntax is \fun{GEN}{matfrobenius}{GEN M, long flag, long v = -1} where \kbd{v} is a variable number. \subsec{mathess$(x)$}\kbdsidx{mathess}\label{se:mathess} Returns a matrix similar to the square matrix $x$, which is in upper Hessenberg form (zero entries below the first subdiagonal). The library syntax is \fun{GEN}{hess}{GEN x}. \subsec{mathilbert$(n)$}\kbdsidx{mathilbert}\label{se:mathilbert} $x$ being a \kbd{long}, creates the \idx{Hilbert matrix}of order $x$, i.e.~the matrix whose coefficient ($i$,$j$) is $1/ (i+j-1)$. The library syntax is \fun{GEN}{mathilbert}{long n}. \subsec{mathnf$(M,\{\fl=0\})$}\kbdsidx{mathnf}\label{se:mathnf} Let $R$ be a Euclidean ring, equal to $\Z$ or to $K[X]$ for some field $K$. If $M$ is a (not necessarily square) matrix with entries in $R$, this routine finds the \emph{upper triangular} \idx{Hermite normal form} of $M$. If the rank of $M$ is equal to its number of rows, this is a square matrix. In general, the columns of the result form a basis of the $R$-module spanned by the columns of $M$. The values of $\fl$ are: \item 0 (default): only return the Hermite normal form $H$ \item 1 (complete output): return $[H,U]$, where $H$ is the Hermite normal form of $M$, and $U$ is a transformation matrix such that $MU=[0|H]$. The matrix $U$ belongs to $\text{GL}(R)$. When $M$ has a large kernel, the entries of $U$ are in general huge. \noindent For these two values, we use a naive algorithm, which behaves well in small dimension only. Larger values correspond to different algorithms, are restricted to \emph{integer} matrices, and all output the unimodular matrix $U$. From now on all matrices have integral entries. \item $\fl=4$, returns $[H,U]$ as in ``complete output'' above, using a variant of \idx{LLL} reduction along the way. The matrix $U$ is provably small in the $L_2$ sense, and often close to optimal; but the reduction is in general slow, although provably polynomial-time. If $\fl=5$, uses Batut's algorithm and output $[H,U,P]$, such that $H$ and $U$ are as before and $P$ is a permutation of the rows such that $P$ applied to $MU$ gives $H$. This is in general faster than $\fl=4$ but the matrix $U$ is usually worse; it is heuristically smaller than with the default algorithm. When the matrix is dense and the dimension is large (bigger than 100, say), $\fl = 4$ will be fastest. When $M$ has maximal rank, then \bprog H = mathnfmod(M, matdetint(M)) @eprog\noindent will be even faster. You can then recover $U$ as $M^{-1}H$. \bprog ? M = matrix(3,4,i,j,random([-5,5])) %1 = [ 0 2 3 0] [-5 3 -5 -5] [ 4 3 -5 4] ? [H,U] = mathnf(M, 1); ? U %3 = [-1 0 -1 0] [ 0 5 3 2] [ 0 3 1 1] [ 1 0 0 0] ? H %5 = [19 9 7] [ 0 9 1] [ 0 0 1] ? M*U %6 = [0 19 9 7] [0 0 9 1] [0 0 0 1] @eprog For convenience, $M$ is allowed to be a \typ{VEC}, which is then automatically converted to a \typ{MAT}, as per the \tet{Mat} function. For instance to solve the generalized extended gcd problem, one may use \bprog ? v = [116085838, 181081878, 314252913,10346840]; ? [H,U] = mathnf(v, 1); ? U %2 = [ 103 -603 15 -88] [-146 13 -1208 352] [ 58 220 678 -167] [-362 -144 381 -101] ? v*U %3 = [0, 0, 0, 1] @eprog\noindent This also allows to input a matrix as a \typ{VEC} of \typ{COL}s of the same length (which \kbd{Mat} would concatenate to the \typ{MAT} having those columns): \bprog ? v = [[1,0,4]~, [3,3,4]~, [0,-4,-5]~]; mathnf(v) %1 = [47 32 12] [ 0 1 0] [ 0 0 1] @eprog The library syntax is \fun{GEN}{mathnf0}{GEN M, long flag}. Also available are \fun{GEN}{hnf}{GEN M} ($\fl=0$) and \fun{GEN}{hnfall}{GEN M} ($\fl=1$). To reduce \emph{huge} relation matrices (sparse with small entries, say dimension $400$ or more), you can use the pair \kbd{hnfspec} / \kbd{hnfadd}. Since this is quite technical and the calling interface may change, they are not documented yet. Look at the code in \kbd{basemath/hnf\_snf.c}. \subsec{mathnfmod$(x,d)$}\kbdsidx{mathnfmod}\label{se:mathnfmod} If $x$ is a (not necessarily square) matrix of maximal rank with integer entries, and $d$ is a multiple of the (non-zero) determinant of the lattice spanned by the columns of $x$, finds the \emph{upper triangular} \idx{Hermite normal form} of $x$. If the rank of $x$ is equal to its number of rows, the result is a square matrix. In general, the columns of the result form a basis of the lattice spanned by the columns of $x$. Even when $d$ is known, this is in general slower than \kbd{mathnf} but uses much less memory. The library syntax is \fun{GEN}{hnfmod}{GEN x, GEN d}. \subsec{mathnfmodid$(x,d)$}\kbdsidx{mathnfmodid}\label{se:mathnfmodid} Outputs the (upper triangular) \idx{Hermite normal form} of $x$ concatenated with the diagonal matrix with diagonal $d$. Assumes that $x$ has integer entries. Variant: if $d$ is an integer instead of a vector, concatenate $d$ times the identity matrix. \bprog ? m=[0,7;-1,0;-1,-1] %1 = [ 0 7] [-1 0] [-1 -1] ? mathnfmodid(m, [6,2,2]) %2 = [2 1 1] [0 1 0] [0 0 1] ? mathnfmodid(m, 10) %3 = [10 7 3] [ 0 1 0] [ 0 0 1] @eprog The library syntax is \fun{GEN}{hnfmodid}{GEN x, GEN d}. \subsec{mathouseholder$(Q,v)$}\kbdsidx{mathouseholder}\label{se:mathouseholder} \sidx{Householder transform}applies a sequence $Q$ of Householder transforms, as returned by \kbd{matqr}$(M,1)$ to the vector or matrix $v$. The library syntax is \fun{GEN}{mathouseholder}{GEN Q, GEN v}. \subsec{matid$(n)$}\kbdsidx{matid}\label{se:matid} Creates the $n\times n$ identity matrix. The library syntax is \fun{GEN}{matid}{long n}. \subsec{matimage$(x,\{\fl=0\})$}\kbdsidx{matimage}\label{se:matimage} Gives a basis for the image of the matrix $x$ as columns of a matrix. A priori the matrix can have entries of any type. If $\fl=0$, use standard Gauss pivot. If $\fl=1$, use \kbd{matsupplement} (much slower: keep the default flag!). The library syntax is \fun{GEN}{matimage0}{GEN x, long flag}. Also available is \fun{GEN}{image}{GEN x} ($\fl=0$). \subsec{matimagecompl$(x)$}\kbdsidx{matimagecompl}\label{se:matimagecompl} Gives the vector of the column indices which are not extracted by the function \kbd{matimage}, as a permutation (\typ{VECSMALL}). Hence the number of components of \kbd{matimagecompl(x)} plus the number of columns of \kbd{matimage(x)} is equal to the number of columns of the matrix $x$. The library syntax is \fun{GEN}{imagecompl}{GEN x}. \subsec{matimagemod$(x,d,\&U)$}\kbdsidx{matimagemod}\label{se:matimagemod} Gives a Howell basis (unique representation for submodules of~$(\Z/d\Z)^n$) for the image of the matrix $x$ modulo $d$ as columns of a matrix $H$. The matrix $x$ must have \typ{INT} entries, and $d$ can be an arbitrary positive integer. If $U$ is present, set it to a matrix such that~$AU = H$. \bprog ? A = [2,1;0,2]; ? matimagemod(A,6,&U) %2 = [1 0] [0 2] ? U %3 = [5 1] [3 4] ? (A*U)%6 %4 = [1 0] [0 2] @eprog \misctitle{Caveat} In general the number of columns of the Howell form is not the minimal number of generators of the submodule. Example: \bprog ? matimagemod([1;2],4) %5 = [2 1] [0 2] @eprog \misctitle{Caveat 2} In general the matrix $U$ is not invertible, even if~$A$ and~$H$ have the same size. Example: \bprog ? matimagemod([4,1;0,4],8,&U) %6 = [2 1] [0 4] ? U %7 = [0 0] [2 1] @eprog The library syntax is \fun{GEN}{matimagemod}{GEN x, GEN d, GEN *U = NULL}. \subsec{matindexrank$(M)$}\kbdsidx{matindexrank}\label{se:matindexrank} $M$ being a matrix of rank $r$, returns a vector with two \typ{VECSMALL} components $y$ and $z$ of length $r$ giving a list of rows and columns respectively (starting from 1) such that the extracted matrix obtained from these two vectors using $\tet{vecextract}(M,y,z)$ is invertible. The vectors $y$ and $z$ are sorted in increasing order. The library syntax is \fun{GEN}{indexrank}{GEN M}. \subsec{matintersect$(x,y)$}\kbdsidx{matintersect}\label{se:matintersect} $x$ and $y$ being two matrices with the same number of rows each of whose columns are independent, finds a basis of the $\Q$-vector space equal to the intersection of the spaces spanned by the columns of $x$ and $y$ respectively. The faster function \tet{idealintersect} can be used to intersect fractional ideals (projective $\Z_K$ modules of rank $1$); the slower but much more general function \tet{nfhnf} can be used to intersect general $\Z_K$-modules. The library syntax is \fun{GEN}{intersect}{GEN x, GEN y}. \subsec{matinverseimage$(x,y)$}\kbdsidx{matinverseimage}\label{se:matinverseimage} Given a matrix $x$ and a column vector or matrix $y$, returns a preimage $z$ of $y$ by $x$ if one exists (i.e such that $x z = y$), an empty vector or matrix otherwise. The complete inverse image is $z + \text{Ker} x$, where a basis of the kernel of $x$ may be obtained by \kbd{matker}. \bprog ? M = [1,2;2,4]; ? matinverseimage(M, [1,2]~) %2 = [1, 0]~ ? matinverseimage(M, [3,4]~) %3 = []~ \\@com no solution ? matinverseimage(M, [1,3,6;2,6,12]) %4 = [1 3 6] [0 0 0] ? matinverseimage(M, [1,2;3,4]) %5 = [;] \\@com no solution ? K = matker(M) %6 = [-2] [1] @eprog The library syntax is \fun{GEN}{inverseimage}{GEN x, GEN y}. \subsec{matinvmod$(x,d)$}\kbdsidx{matinvmod}\label{se:matinvmod} Computes a left inverse of the matrix~$x$ modulo~$d$. The matrix $x$ must have \typ{INT} entries, and $d$ can be an arbitrary positive integer. \bprog ? A = [3,1,2;1,2,1;3,1,1]; ? U = matinvmod(A,6) %2 = [1 1 3] [2 3 5] [1 0 5] ? (U*A)%6 %3 = [1 0 0] [0 1 0] [0 0 1] ? matinvmod(A,5) *** at top-level: matinvmod(A,5) *** ^-------------- *** matinvmod: impossible inverse in gen_inv: 0. @eprog The library syntax is \fun{GEN}{matinvmod}{GEN x, GEN d}. \subsec{matisdiagonal$(x)$}\kbdsidx{matisdiagonal}\label{se:matisdiagonal} Returns true (1) if $x$ is a diagonal matrix, false (0) if not. The library syntax is \fun{GEN}{isdiagonal}{GEN x}. \subsec{matker$(x,\{\fl=0\})$}\kbdsidx{matker}\label{se:matker} Gives a basis for the kernel of the matrix $x$ as columns of a matrix. The matrix can have entries of any type, provided they are compatible with the generic arithmetic operations ($+$, $\times$ and $/$). If $x$ is known to have integral entries, set $\fl=1$. The library syntax is \fun{GEN}{matker0}{GEN x, long flag}. Also available are \fun{GEN}{ker}{GEN x} ($\fl=0$), \fun{GEN}{ZM_ker}{GEN x} ($\fl=1$). \subsec{matkerint$(x,\{\fl=0\})$}\kbdsidx{matkerint}\label{se:matkerint} Gives an \idx{LLL}-reduced $\Z$-basis for the lattice equal to the kernel of the matrix $x$ with rational entries. \fl is deprecated, kept for backward compatibility. The library syntax is \fun{GEN}{matkerint0}{GEN x, long flag}. Use directly \fun{GEN}{kerint}{GEN x} if $x$ is known to have integer entries, and \tet{Q_primpart} first otherwise. \subsec{matkermod$(x,d,\&\var{im})$}\kbdsidx{matkermod}\label{se:matkermod} Gives a Howell basis (unique representation for submodules of~$(\Z/d\Z)^n$, cf. \kbd{matimagemod}) for the kernel of the matrix $x$ modulo $d$ as columns of a matrix. The matrix $x$ must have \typ{INT} entries, and $d$ can be an arbitrary positive integer. If $im$ is present, set it to a basis of the image of~$x$ (which is computed on the way). \bprog ? A = [1,2,3;5,1,4] %1 = [1 2 3] [5 1 4] ? K = matkermod(A,6) %2 = [2 1] [2 1] [0 3] ? (A*K)%6 %3 = [0 0] [0 0] @eprog The library syntax is \fun{GEN}{matkermod}{GEN x, GEN d, GEN *im = NULL}. \subsec{matmuldiagonal$(x,d)$}\kbdsidx{matmuldiagonal}\label{se:matmuldiagonal} Product of the matrix $x$ by the diagonal matrix whose diagonal entries are those of the vector $d$. Equivalent to, but much faster than $x*\kbd{matdiagonal}(d)$. The library syntax is \fun{GEN}{matmuldiagonal}{GEN x, GEN d}. \subsec{matmultodiagonal$(x,y)$}\kbdsidx{matmultodiagonal}\label{se:matmultodiagonal} Product of the matrices $x$ and $y$ assuming that the result is a diagonal matrix. Much faster than $x*y$ in that case. The result is undefined if $x*y$ is not diagonal. The library syntax is \fun{GEN}{matmultodiagonal}{GEN x, GEN y}. \subsec{matpascal$(n,\{q\})$}\kbdsidx{matpascal}\label{se:matpascal} Creates as a matrix the lower triangular \idx{Pascal triangle} of order $x+1$ (i.e.~with binomial coefficients up to $x$). If $q$ is given, compute the $q$-Pascal triangle (i.e.~using $q$-binomial coefficients). The library syntax is \fun{GEN}{matqpascal}{long n, GEN q = NULL}. Also available is \fun{GEN}{matpascal}{GEN x}. \subsec{matpermanent$(x)$}\kbdsidx{matpermanent}\label{se:matpermanent} Permanent of the square matrix $x$ using Ryser's formula in Gray code order. \bprog ? n = 20; m = matrix(n,n,i,j, i!=j); ? matpermanent(m) %2 = 895014631192902121 ? n! * sum(i=0,n, (-1)^i/i!) %3 = 895014631192902121 @eprog\noindent This function runs in time $O(2^n n)$ for a matrix of size $n$ and is not implemented for $n$ large. The library syntax is \fun{GEN}{matpermanent}{GEN x}. \subsec{matqr$(M,\{\fl=0\})$}\kbdsidx{matqr}\label{se:matqr} Returns $[Q,R]$, the \idx{QR-decomposition} of the square invertible matrix $M$ with real entries: $Q$ is orthogonal and $R$ upper triangular. If $\fl=1$, the orthogonal matrix is returned as a sequence of Householder transforms: applying such a sequence is stabler and faster than multiplication by the corresponding $Q$ matrix.\sidx{Householder transform} More precisely, if \bprog [Q,R] = matqr(M); [q,r] = matqr(M, 1); @eprog\noindent then $r = R$ and \kbd{mathouseholder}$(q, M)$ is (close to) $R$; furthermore \bprog mathouseholder(q, matid(#M)) == Q~ @eprog\noindent the inverse of $Q$. This function raises an error if the precision is too low or $x$ is singular. The library syntax is \fun{GEN}{matqr}{GEN M, long flag, long prec}. \subsec{matrank$(x)$}\kbdsidx{matrank}\label{se:matrank} Rank of the matrix $x$. The library syntax is \fun{long}{rank}{GEN x}. \subsec{matrix$(m,\{n=m\},\{X\},\{Y\},\{\var{expr}=0\})$}\kbdsidx{matrix}\label{se:matrix} Creation of the $m\times n$ matrix whose coefficients are given by the expression \var{expr}. There are two formal parameters in \var{expr}, the first one ($X$) corresponding to the rows, the second ($Y$) to the columns, and $X$ goes from 1 to $m$, $Y$ goes from 1 to $n$. If one of the last 3 parameters is omitted, fill the matrix with zeroes. If $n$ is omitted, return a square $m \times m$ matrix. %\syn{NO} \subsec{matrixqz$(A,\{p=0\})$}\kbdsidx{matrixqz}\label{se:matrixqz} $A$ being an $m\times n$ matrix in $M_{m,n}(\Q)$, let $\text{Im}_\Q A$ (resp.~$\text{Im}_\Z A$) the $\Q$-vector space (resp.~the $\Z$-module) spanned by the columns of $A$. This function has varying behavior depending on the sign of $p$: If $p \geq 0$, $A$ is assumed to have maximal rank $n\leq m$. The function returns a matrix $B\in M_{m,n}(\Z)$, with $\text{Im}_\Q B = \text{Im}_\Q A$, such that the GCD of all its $n\times n$ minors is coprime to $p$; in particular, if $p = 0$ (default), this GCD is $1$. \bprog ? minors(x) = vector(#x[,1], i, matdet(x[^i,])); ? A = [3,1/7; 5,3/7; 7,5/7]; minors(A) %1 = [4/7, 8/7, 4/7] \\ determinants of all 2x2 minors ? B = matrixqz(A) %2 = [3 1] [5 2] [7 3] ? minors(%) %3 = [1, 2, 1] \\ B integral with coprime minors @eprog If $p=-1$, returns the HNF basis of the lattice $\Z^n \cap \text{Im}_\Z A$. If $p=-2$, returns the HNF basis of the lattice $\Z^n \cap \text{Im}_\Q A$. \bprog ? matrixqz(A,-1) %4 = [8 5] [4 3] [0 1] ? matrixqz(A,-2) %5 = [2 -1] [1 0] [0 1] @eprog The library syntax is \fun{GEN}{matrixqz0}{GEN A, GEN p = NULL}. \subsec{matsize$(x)$}\kbdsidx{matsize}\label{se:matsize} $x$ being a vector or matrix, returns a row vector with two components, the first being the number of rows (1 for a row vector), the second the number of columns (1 for a column vector). The library syntax is \fun{GEN}{matsize}{GEN x}. \subsec{matsnf$(X,\{\fl=0\})$}\kbdsidx{matsnf}\label{se:matsnf} If $X$ is a (singular or non-singular) matrix outputs the vector of \idx{elementary divisors} of $X$, i.e.~the diagonal of the \idx{Smith normal form} of $X$, normalized so that $d_n \mid d_{n-1} \mid \ldots \mid d_1$. The binary digits of \fl\ mean: 1 (complete output): if set, outputs $[U,V,D]$, where $U$ and $V$ are two unimodular matrices such that $UXV$ is the diagonal matrix $D$. Otherwise output only the diagonal of $D$. If $X$ is not a square matrix, then $D$ will be a square diagonal matrix padded with zeros on the left or the top. 2 (generic input): if set, allows polynomial entries, in which case the input matrix must be square. Otherwise, assume that $X$ has integer coefficients with arbitrary shape. 4 (cleanup): if set, cleans up the output. This means that elementary divisors equal to $1$ will be deleted, i.e.~outputs a shortened vector $D'$ instead of $D$. If complete output was required, returns $[U',V',D']$ so that $U'XV' = D'$ holds. If this flag is set, $X$ is allowed to be of the form `vector of elementary divisors' or $[U,V,D]$ as would normally be output with the cleanup flag unset. The library syntax is \fun{GEN}{matsnf0}{GEN X, long flag}. \subsec{matsolve$(M,B)$}\kbdsidx{matsolve}\label{se:matsolve} Let $M$ be a left-invertible matrix and $B$ a column vector such that there exists a solution $X$ to the system of linear equations $MX = B$; return the (unique) solution $X$. This has the same effect as, but is faster, than $M^{-1}*B$. Uses Dixon $p$-adic lifting method if $M$ and $B$ are integral and Gaussian elimination otherwise. When there is no solution, the function returns an $X$ such that $MX - B$ is non-zero although it has at least $\#M$ zero entries: \bprog ? M = [1,2;3,4;5,6]; ? B = [4,6,8]~; X = matsolve(M, B) %2 = [-2, 3]~ ? M*X == B %3 = 1 ? B = [1,2,4]~; X = matsolve(M, [1,2,4]~) %4 = [0, 1/2]~ ? M*X - B %5 = [0, 0, -1]~ @eprog\noindent Raises an exception if $M$ is not left-invertible, even if there is a solution: \bprog ? M = [1,1;1,1]; matsolve(M, [1,1]~) *** at top-level: matsolve(M,[1,1]~) *** ^------------------ *** matsolve: impossible inverse in gauss: [1, 1; 1, 1]. @eprog\noindent The function also works when $B$ is a matrix and we return the unique matrix solution $X$ provided it exists. The library syntax is \fun{GEN}{gauss}{GEN M, GEN B}. For integral input, the function \fun{GEN}{ZM_gauss}{GEN M,GEN B} is also available. \subsec{matsolvemod$(M,D,B,\{\fl=0\})$}\kbdsidx{matsolvemod}\label{se:matsolvemod} $M$ being any integral matrix, $D$ a column vector of non-negative integer moduli, and $B$ an integral column vector, gives an integer solution to the system of congruences $\sum_i m_{i,j}x_j\equiv b_i\pmod{d_i}$ if one exists, otherwise returns zero. Shorthand notation: $B$ (resp.~$D$) can be given as a single integer, in which case all the $b_i$ (resp.~$d_i$) above are taken to be equal to $B$ (resp.~$D$). \bprog ? M = [1,2;3,4]; ? matsolvemod(M, [3,4]~, [1,2]~) %2 = [10, 0]~ ? matsolvemod(M, 3, 1) \\ M X = [1,1]~ over F_3 %3 = [2, 1]~ ? matsolvemod(M, [3,0]~, [1,2]~) \\ x + 2y = 1 (mod 3), 3x + 4y = 2 (in Z) %4 = [6, -4]~ @eprog If $\fl=1$, all solutions are returned in the form of a two-component row vector $[x,u]$, where $x$ is an integer solution to the system of congruences and $u$ is a matrix whose columns give a basis of the homogeneous system (so that all solutions can be obtained by adding $x$ to any linear combination of columns of $u$). If no solution exists, returns zero. The library syntax is \fun{GEN}{matsolvemod}{GEN M, GEN D, GEN B, long flag}. Also available are \fun{GEN}{gaussmodulo}{GEN M, GEN D, GEN B} ($\fl=0$) and \fun{GEN}{gaussmodulo2}{GEN M, GEN D, GEN B} ($\fl=1$). \subsec{matsupplement$(x)$}\kbdsidx{matsupplement}\label{se:matsupplement} Assuming that the columns of the matrix $x$ are linearly independent (if they are not, an error message is issued), finds a square invertible matrix whose first columns are the columns of $x$, i.e.~supplement the columns of $x$ to a basis of the whole space. \bprog ? matsupplement([1;2]) %1 = [1 0] [2 1] @eprog Raises an error if $x$ has 0 columns, since (due to a long standing design bug), the dimension of the ambient space (the number of rows) is unknown in this case: \bprog ? matsupplement(matrix(2,0)) *** at top-level: matsupplement(matrix *** ^-------------------- *** matsupplement: sorry, suppl [empty matrix] is not yet implemented. @eprog The library syntax is \fun{GEN}{suppl}{GEN x}. \subsec{mattranspose$(x)$}\kbdsidx{mattranspose}\label{se:mattranspose} Transpose of $x$ (also $x\til$). This has an effect only on vectors and matrices. The library syntax is \fun{GEN}{gtrans}{GEN x}. \subsec{minpoly$(A,\{v='x\})$}\kbdsidx{minpoly}\label{se:minpoly} \idx{minimal polynomial} of $A$ with respect to the variable $v$., i.e. the monic polynomial $P$ of minimal degree (in the variable $v$) such that $P(A) = 0$. The library syntax is \fun{GEN}{minpoly}{GEN A, long v = -1} where \kbd{v} is a variable number. \subsec{norml2$(x)$}\kbdsidx{norml2}\label{se:norml2} Square of the $L^2$-norm of $x$. More precisely, if $x$ is a scalar, $\kbd{norml2}(x)$ is defined to be the square of the complex modulus of $x$ (real \typ{QUAD}s are not supported). If $x$ is a polynomial, a (row or column) vector or a matrix, \kbd{norml2($x$)} is defined recursively as $\sum_i \kbd{norml2}(x_i)$, where $(x_i)$ run through the components of $x$. In particular, this yields the usual $\sum |x_i|^2$ (resp.~$\sum |x_{i,j}|^2$) if $x$ is a polynomial or vector (resp.~matrix) with complex components. \bprog ? norml2( [ 1, 2, 3 ] ) \\ vector %1 = 14 ? norml2( [ 1, 2; 3, 4] ) \\ matrix %2 = 30 ? norml2( 2*I + x ) %3 = 5 ? norml2( [ [1,2], [3,4], 5, 6 ] ) \\ recursively defined %4 = 91 @eprog The library syntax is \fun{GEN}{gnorml2}{GEN x}. \subsec{normlp$(x,\{p=\var{oo}\})$}\kbdsidx{normlp}\label{se:normlp} $L^p$-norm of $x$; sup norm if $p$ is omitted or \kbd{+oo}. More precisely, if $x$ is a scalar, \kbd{normlp}$(x, p)$ is defined to be \kbd{abs}$(x)$. If $x$ is a polynomial, a (row or column) vector or a matrix: \item if $p$ is omitted or \kbd{+oo}, then \kbd{normlp($x$)} is defined recursively as $\max_i \kbd{normlp}(x_i))$, where $(x_i)$ run through the components of~$x$. In particular, this yields the usual sup norm if $x$ is a polynomial or vector with complex components. \item otherwise, \kbd{normlp($x$, $p$)} is defined recursively as $(\sum_i \kbd{normlp}^p(x_i,p))^{1/p}$. In particular, this yields the usual $(\sum |x_i|^p)^{1/p}$ if $x$ is a polynomial or vector with complex components. \bprog ? v = [1,-2,3]; normlp(v) \\ vector %1 = 3 ? normlp(v, +oo) \\ same, more explicit %2 = 3 ? M = [1,-2;-3,4]; normlp(M) \\ matrix %3 = 4 ? T = (1+I) + I*x^2; normlp(T) %4 = 1.4142135623730950488016887242096980786 ? normlp([[1,2], [3,4], 5, 6]) \\ recursively defined %5 = 6 ? normlp(v, 1) %6 = 6 ? normlp(M, 1) %7 = 10 ? normlp(T, 1) %8 = 2.4142135623730950488016887242096980786 @eprog The library syntax is \fun{GEN}{gnormlp}{GEN x, GEN p = NULL, long prec}. \subsec{qfauto$(G,\{\var{fl}\})$}\kbdsidx{qfauto}\label{se:qfauto} $G$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, outputs the automorphism group of the associate lattice. Since this requires computing the minimal vectors, the computations can become very lengthy as the dimension grows. $G$ can also be given by an \kbd{qfisominit} structure. See \kbd{qfisominit} for the meaning of \var{fl}. The output is a two-components vector $[o,g]$ where $o$ is the group order and $g$ is the list of generators (as a vector). For each generator $H$, the equality $G={^t}H\*G\*H$ holds. The interface of this function is experimental and will likely change in the future. This function implements an algorithm of Plesken and Souvignier, following Souvignier's implementation. The library syntax is \fun{GEN}{qfauto0}{GEN G, GEN fl = NULL}. The function \fun{GEN}{qfauto}{GEN G, GEN fl} is also available where $G$ is a vector of \kbd{zm} matrices. \subsec{qfautoexport$(\var{qfa},\{\fl\})$}\kbdsidx{qfautoexport}\label{se:qfautoexport} \var{qfa} being an automorphism group as output by \tet{qfauto}, export the underlying matrix group as a string suitable for (no flags or $\fl=0$) GAP or ($\fl=1$) Magma. The following example computes the size of the matrix group using GAP: \bprog ? G = qfauto([2,1;1,2]) %1 = [12, [[-1, 0; 0, -1], [0, -1; 1, 1], [1, 1; 0, -1]]] ? s = qfautoexport(G) %2 = "Group([[-1, 0], [0, -1]], [[0, -1], [1, 1]], [[1, 1], [0, -1]])" ? extern("echo \"Order("s");\" | gap -q") %3 = 12 @eprog The library syntax is \fun{GEN}{qfautoexport}{GEN qfa, long flag}. \subsec{qfbil$(x,y,\{q\})$}\kbdsidx{qfbil}\label{se:qfbil} This function is obsolete, use \kbd{qfeval}. The library syntax is \fun{GEN}{qfbil}{GEN x, GEN y, GEN q = NULL}. \subsec{qfeval$(\{q\},x,\{y\})$}\kbdsidx{qfeval}\label{se:qfeval} Evaluate the quadratic form $q$ (given by a symmetric matrix) at the vector $x$; if $y$ is present, evaluate the polar form at $(x,y)$; if $q$ omitted, use the standard Euclidean scalar product, corresponding to the identity matrix. Roughly equivalent to \kbd{x\til * q * y}, but a little faster and more convenient (does not distinguish between column and row vectors): \bprog ? x = [1,2,3]~; y = [-1,3,1]~; q = [1,2,3;2,2,-1;3,-1,9]; ? qfeval(q,x,y) %2 = 23 ? for(i=1,10^6, qfeval(q,x,y)) time = 661ms ? for(i=1,10^6, x~*q*y) time = 697ms @eprog\noindent The speedup is noticeable for the quadratic form, compared to \kbd{x\til * q * x}, since we save almost half the operations: \bprog ? for(i=1,10^6, qfeval(q,x)) time = 487ms @eprog\noindent The special case $q = \text{Id}$ is handled faster if we omit $q$ altogether: \bprog ? qfeval(,x,y) %6 = 8 ? q = matid(#x); ? for(i=1,10^6, qfeval(q,x,y)) time = 529 ms. ? for(i=1,10^6, qfeval(,x,y)) time = 228 ms. ? for(i=1,10^6, x~*y) time = 274 ms. @eprog We also allow \typ{MAT}s of compatible dimensions for $x$, and return \kbd{x\til * q * x} in this case as well: \bprog ? M = [1,2,3;4,5,6;7,8,9]; qfeval(,M) \\ Gram matrix %5 = [66 78 90] [78 93 108] [90 108 126] ? q = [1,2,3;2,2,-1;3,-1,9]; ? for(i=1,10^6, qfeval(q,M)) time = 2,008 ms. ? for(i=1,10^6, M~*q*M) time = 2,368 ms. ? for(i=1,10^6, qfeval(,M)) time = 1,053 ms. ? for(i=1,10^6, M~*M) time = 1,171 ms. @eprog If $q$ is a \typ{QFI} or \typ{QFR}, it is implicitly converted to the attached symmetric \typ{MAT}. This is done more efficiently than by direct conversion, since we avoid introducing a denominator $2$ and rational arithmetic: \bprog ? q = Qfb(2,3,4); x = [2,3]; ? qfeval(q, x) %2 = 62 ? Q = Mat(q) %3 = [ 2 3/2] [3/2 4] ? qfeval(Q, x) %4 = 62 ? for (i=1, 10^6, qfeval(q,x)) time = 758 ms. ? for (i=1, 10^6, qfeval(Q,x)) time = 1,110 ms. @eprog Finally, when $x$ is a \typ{MAT} with \emph{integral} coefficients, we allow a \typ{QFI} or \typ{QFR} for $q$ and return the binary quadratic form $q \circ M$. Again, the conversion to \typ{MAT} is less efficient in this case: \bprog ? q = Qfb(2,3,4); Q = Mat(q); x = [1,2;3,4]; ? qfeval(q, x) %2 = Qfb(47, 134, 96) ? qfeval(Q,x) %3 = [47 67] [67 96] ? for (i=1, 10^6, qfeval(q,x)) time = 701 ms. ? for (i=1, 10^6, qfeval(Q,x)) time = 1,639 ms. @eprog The library syntax is \fun{GEN}{qfeval0}{GEN q = NULL, GEN x, GEN y = NULL}. \subsec{qfgaussred$(q)$}\kbdsidx{qfgaussred}\label{se:qfgaussred} \idx{decomposition into squares} of the quadratic form represented by the symmetric matrix $q$. The result is a matrix whose diagonal entries are the coefficients of the squares, and the off-diagonal entries on each line represent the bilinear forms. More precisely, if $(a_{ij})$ denotes the output, one has $$ q(x) = \sum_i a_{ii} (x_i + \sum_{j \neq i} a_{ij} x_j)^2 $$ \bprog ? qfgaussred([0,1;1,0]) %1 = [1/2 1] [-1 -1/2] @eprog\noindent This means that $2xy = (1/2)(x+y)^2 - (1/2)(x-y)^2$. Singular matrices are supported, in which case some diagonal coefficients will vanish: \bprog ? qfgaussred([1,1;1,1]) %1 = [1 1] [1 0] @eprog\noindent This means that $x^2 + 2xy + y^2 = (x+y)^2$. The library syntax is \fun{GEN}{qfgaussred}{GEN q}. \fun{GEN}{qfgaussred_positive}{GEN q} assumes that $q$ is positive definite and is a little faster; returns \kbd{NULL} if a vector with negative norm occurs (non positive matrix or too many rounding errors). \subsec{qfisom$(G,H,\{\var{fl}\},\{\var{grp}\})$}\kbdsidx{qfisom}\label{se:qfisom} $G$, $H$ being square and symmetric matrices with integer entries representing positive definite quadratic forms, return an invertible matrix $S$ such that $G={^t}S\*H\*S$. This defines a isomorphism between the corresponding lattices. Since this requires computing the minimal vectors, the computations can become very lengthy as the dimension grows. See \kbd{qfisominit} for the meaning of \var{fl}. If \var{grp} is given it must be the automorphism group of $H$. It will be used to speed up the computation. $G$ can also be given by an \kbd{qfisominit} structure which is preferable if several forms $H$ need to be compared to $G$. This function implements an algorithm of Plesken and Souvignier, following Souvignier's implementation. The library syntax is \fun{GEN}{qfisom0}{GEN G, GEN H, GEN fl = NULL, GEN grp = NULL}. Also available is \fun{GEN}{qfisom}{GEN G, GEN H, GEN fl, GEN grp} where $G$ is a vector of \kbd{zm}, and $H$ is a \kbd{zm}, and $grp$ is either \kbd{NULL} or a vector of \kbd{zm}. \subsec{qfisominit$(G,\{\var{fl}\},\{m\})$}\kbdsidx{qfisominit}\label{se:qfisominit} $G$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, return an \kbd{isom} structure allowing to compute isomorphisms between $G$ and other quadratic forms faster. The interface of this function is experimental and will likely change in future release. If present, the optional parameter \var{fl} must be a \typ{VEC} with two components. It allows to specify the invariants used, which can make the computation faster or slower. The components are \item \kbd{fl[1]} Depth of scalar product combination to use. \item \kbd{fl[2]} Maximum level of Bacher polynomials to use. If present, $m$ must be the set of vectors of norm up to the maximal of the diagonal entry of $G$, either as a matrix or as given by \kbd{qfminim}. Otherwise this function computes the minimal vectors so it become very lengthy as the dimension of $G$ grows. The library syntax is \fun{GEN}{qfisominit0}{GEN G, GEN fl = NULL, GEN m = NULL}. Also available is \fun{GEN}{qfisominit}{GEN F, GEN fl} where $F$ is a vector of \kbd{zm}. \subsec{qfjacobi$(A)$}\kbdsidx{qfjacobi}\label{se:qfjacobi} Apply Jacobi's eigenvalue algorithm to the real symmetric matrix $A$. This returns $[L, V]$, where \item $L$ is the vector of (real) eigenvalues of $A$, sorted in increasing order, \item $V$ is the corresponding orthogonal matrix of eigenvectors of $A$. \bprog ? \p19 ? A = [1,2;2,1]; mateigen(A) %1 = [-1 1] [ 1 1] ? [L, H] = qfjacobi(A); ? L %3 = [-1.000000000000000000, 3.000000000000000000]~ ? H %4 = [ 0.7071067811865475245 0.7071067811865475244] [-0.7071067811865475244 0.7071067811865475245] ? norml2( (A-L[1])*H[,1] ) \\ approximate eigenvector %5 = 9.403954806578300064 E-38 ? norml2(H*H~ - 1) %6 = 2.350988701644575016 E-38 \\ close to orthogonal @eprog The library syntax is \fun{GEN}{jacobi}{GEN A, long prec}. \subsec{qflll$(x,\{\fl=0\})$}\kbdsidx{qflll}\label{se:qflll} \idx{LLL} algorithm applied to the \emph{columns} of the matrix $x$. The columns of $x$ may be linearly dependent. The result is a unimodular transformation matrix $T$ such that $x \cdot T$ is an LLL-reduced basis of the lattice generated by the column vectors of $x$. Note that if $x$ is not of maximal rank $T$ will not be square. The LLL parameters are $(0.51,0.99)$, meaning that the Gram-Schmidt coefficients for the final basis satisfy $|\mu_{i,j}| \leq 0.51$, and the Lov\'{a}sz's constant is $0.99$. If $\fl=0$ (default), assume that $x$ has either exact (integral or rational) or real floating point entries. The matrix is rescaled, converted to integers and the behavior is then as in $\fl = 1$. If $\fl=1$, assume that $x$ is integral. Computations involving Gram-Schmidt vectors are approximate, with precision varying as needed (Lehmer's trick, as generalized by Schnorr). Adapted from Nguyen and Stehl\'e's algorithm and Stehl\'e's code (\kbd{fplll-1.3}). If $\fl=2$, $x$ should be an integer matrix whose columns are linearly independent. Returns a partially reduced basis for $x$, using an unpublished algorithm by Peter Montgomery: a basis is said to be \emph{partially reduced} if $|v_i \pm v_j| \geq |v_i|$ for any two distinct basis vectors $v_i, \, v_j$. This is faster than $\fl=1$, esp. when one row is huge compared to the other rows (knapsack-style), and should quickly produce relatively short vectors. The resulting basis is \emph{not} LLL-reduced in general. If LLL reduction is eventually desired, avoid this partial reduction: applying LLL to the partially reduced matrix is significantly \emph{slower} than starting from a knapsack-type lattice. If $\fl=4$, as $\fl=1$, returning a vector $[K, T]$ of matrices: the columns of $K$ represent a basis of the integer kernel of $x$ (not LLL-reduced in general) and $T$ is the transformation matrix such that $x\cdot T$ is an LLL-reduced $\Z$-basis of the image of the matrix $x$. If $\fl=5$, case as case $4$, but $x$ may have polynomial coefficients. If $\fl=8$, same as case $0$, but $x$ may have polynomial coefficients. The library syntax is \fun{GEN}{qflll0}{GEN x, long flag}. Also available are \fun{GEN}{lll}{GEN x} ($\fl=0$), \fun{GEN}{lllint}{GEN x} ($\fl=1$), and \fun{GEN}{lllkerim}{GEN x} ($\fl=4$). \subsec{qflllgram$(G,\{\fl=0\})$}\kbdsidx{qflllgram}\label{se:qflllgram} Same as \kbd{qflll}, except that the matrix $G = \kbd{x\til * x}$ is the Gram matrix of some lattice vectors $x$, and not the coordinates of the vectors themselves. In particular, $G$ must now be a square symmetric real matrix, corresponding to a positive quadratic form (not necessarily definite: $x$ needs not have maximal rank). The result is a unimodular transformation matrix $T$ such that $x \cdot T$ is an LLL-reduced basis of the lattice generated by the column vectors of $x$. See \tet{qflll} for further details about the LLL implementation. If $\fl=0$ (default), assume that $G$ has either exact (integral or rational) or real floating point entries. The matrix is rescaled, converted to integers and the behavior is then as in $\fl = 1$. If $\fl=1$, assume that $G$ is integral. Computations involving Gram-Schmidt vectors are approximate, with precision varying as needed (Lehmer's trick, as generalized by Schnorr). Adapted from Nguyen and Stehl\'e's algorithm and Stehl\'e's code (\kbd{fplll-1.3}). $\fl=4$: $G$ has integer entries, gives the kernel and reduced image of $x$. $\fl=5$: same as $4$, but $G$ may have polynomial coefficients. The library syntax is \fun{GEN}{qflllgram0}{GEN G, long flag}. Also available are \fun{GEN}{lllgram}{GEN G} ($\fl=0$), \fun{GEN}{lllgramint}{GEN G} ($\fl=1$), and \fun{GEN}{lllgramkerim}{GEN G} ($\fl=4$). \subsec{qfminim$(x,\{b\},\{m\},\{\fl=0\})$}\kbdsidx{qfminim}\label{se:qfminim} $x$ being a square and symmetric matrix representing a positive definite quadratic form, this function deals with the vectors of $x$ whose norm is less than or equal to $b$, enumerated using the Fincke-Pohst algorithm, storing at most $m$ vectors (no limit if $m$ is omitted). The function searches for the minimal non-zero vectors if $b$ is omitted. The behavior is undefined if $x$ is not positive definite (a ``precision too low'' error is most likely, although more precise error messages are possible). The precise behavior depends on $\fl$. If $\fl=0$ (default), returns at most $2m$ vectors. The result is a three-component vector, the first component being the number of vectors enumerated (which may be larger than $2m$), the second being the maximum norm found, and the last vector is a matrix whose columns are found vectors, only one being given for each pair $\pm v$ (at most $m$ such pairs, unless $m$ was omitted). The vectors are returned in no particular order. If $\fl=1$, ignores $m$ and returns $[N,v]$, where $v$ is a non-zero vector of length $N \leq b$, or $[]$ if no non-zero vector has length $\leq b$. If no explicit $b$ is provided, return a vector of smallish norm (smallest vector in an LLL-reduced basis). In these two cases, $x$ must have \emph{integral} entries. The implementation uses low precision floating point computations for maximal speed, which gives incorrect result when $x$ has large entries. (The condition is checked in the code and the routine raises an error if large rounding errors occur.) A more robust, but much slower, implementation is chosen if the following flag is used: If $\fl=2$, $x$ can have non integral real entries. In this case, if $b$ is omitted, the ``minimal'' vectors only have approximately the same norm. If $b$ is omitted, $m$ is an upper bound for the number of vectors that will be stored and returned, but all minimal vectors are nevertheless enumerated. If $m$ is omitted, all vectors found are stored and returned; note that this may be a huge vector! \bprog ? x = matid(2); ? qfminim(x) \\@com 4 minimal vectors of norm 1: $\pm[0,1]$, $\pm[1,0]$ %2 = [4, 1, [0, 1; 1, 0]] ? { x = [4, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1, 0,-1, 0, 0, 0,-2; 2, 4,-2,-2, 0,-2, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1, 0, 1,-1,-1; 0,-2, 4, 0,-2, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 0, 0, 1,-1,-1, 0, 0; 0,-2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1,-1, 0, 1,-1, 1, 0; 0, 0,-2, 0, 4, 0, 0, 0, 1,-1, 0, 0, 1, 0, 0, 0,-2, 0, 0,-1, 1, 1, 0, 0; -2, -2,0, 0, 0, 4,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,-1, 1, 1; 0, 0, 0, 0, 0,-2, 4,-2, 0, 0, 0, 0, 0, 1, 0, 0, 0,-1, 0, 0, 0, 1,-1, 0; 0, 0, 0, 0, 0, 0,-2, 4, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1,-1,-1, 0, 1, 0; 0, 0, 0, 0, 1,-1, 0, 0, 4, 0,-2, 0, 1, 1, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0,-1, 0, 0, 0, 0, 4, 0, 0, 1, 1,-1, 1, 0, 0, 0, 1, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 4,-2, 0,-1, 0, 0, 0,-1, 0,-1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 4,-1, 1, 0, 0,-1, 1, 0, 1, 1, 1,-1, 0; 1, 0,-1, 1, 1, 0, 0,-1, 1, 1, 0,-1, 4, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1,-1; -1,-1, 1,-1, 0, 0, 1, 0, 1, 1,-1, 1, 0, 4, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1; 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 1, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 1, 0, 4, 0, 0, 0, 0, 1, 1, 0, 0; 0, 0, 1, 0,-2, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 4, 1, 1, 1, 0, 0, 1, 1; 1, 0, 0, 1, 0, 0,-1, 0, 1, 0,-1, 1, 1, 0, 0, 0, 1, 4, 0, 1, 1, 0, 1, 0; 0, 0, 0,-1, 0, 1, 0,-1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 4, 0, 1, 1, 0, 1; -1, -1,1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0, 1, 0, 0, 1, 1, 0, 4, 0, 0, 1, 1; 0, 0,-1, 1, 1, 0, 0,-1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 4, 1, 0, 1; 0, 1,-1,-1, 1,-1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 4, 0, 1; 0,-1, 0, 1, 0, 1,-1, 1, 0, 1, 0,-1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 4, 1; -2,-1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 4]; } ? qfminim(x,,0) \\ the Leech lattice has 196560 minimal vectors of norm 4 time = 648 ms. %4 = [196560, 4, [;]] ? qfminim(x,,0,2); \\ safe algorithm. Slower and unnecessary here. time = 18,161 ms. %5 = [196560, 4.000061035156250000, [;]] @eprog\noindent\sidx{Leech lattice}\sidx{minimal vector} In the last example, we store 0 vectors to limit memory use. All minimal vectors are nevertheless enumerated. Provided \kbd{parisize} is about 50MB, \kbd{qfminim(x)} succeeds in 2.5 seconds. The library syntax is \fun{GEN}{qfminim0}{GEN x, GEN b = NULL, GEN m = NULL, long flag, long prec}. Also available are \fun{GEN}{minim}{GEN x, GEN b = NULL, GEN m = NULL} ($\fl=0$), \fun{GEN}{minim2}{GEN x, GEN b = NULL, GEN m = NULL} ($\fl=1$). \fun{GEN}{minim_raw}{GEN x, GEN b = NULL, GEN m = NULL} (do not perform LLL reduction on x and return \kbd{NULL} on accuracy error). \subsec{qfnorm$(x,\{q\})$}\kbdsidx{qfnorm}\label{se:qfnorm} This function is obsolete, use \kbd{qfeval}. The library syntax is \fun{GEN}{qfnorm}{GEN x, GEN q = NULL}. \subsec{qforbits$(G,V)$}\kbdsidx{qforbits}\label{se:qforbits} Return the orbits of $V$ under the action of the group of linear transformation generated by the set $G$. It is assumed that $G$ contains minus identity, and only one vector in $\{v, -v\}$ should be given. If $G$ does not stabilize $V$, the function return $0$. In the example below, we compute representatives and lengths of the orbits of the vectors of norm $\leq 3$ under the automorphisms of the lattice $A_1^6$. \bprog ? Q=matid(6); G=qfauto(Q); V=qfminim(Q,3); ? apply(x->[x[1],#x],qforbits(G,V)) %2 = [[[0,0,0,0,0,1]~,6],[[0,0,0,0,1,-1]~,30],[[0,0,0,1,-1,-1]~,80]] @eprog The library syntax is \fun{GEN}{qforbits}{GEN G, GEN V}. \subsec{qfparam$(G, \var{sol}, \{\fl = 0\})$}\kbdsidx{qfparam}\label{se:qfparam} Coefficients of binary quadratic forms that parametrize the solutions of the ternary quadratic form $G$, using the particular solution~\var{sol}. \fl is optional and can be 1, 2, or 3, in which case the \fl-th form is reduced. The default is \fl=0 (no reduction). \bprog ? G = [1,0,0;0,1,0;0,0,-34]; ? M = qfparam(G, qfsolve(G)) %2 = [ 3 -10 -3] [-5 -6 5] [ 1 0 1] @eprog Indeed, the solutions can be parametrized as $$(3x^2 - 10xy - 3y^2)^2 + (-5x^2 - 6xy + 5y^2)^2 -34(x^2 + y^2)^2 = 0.$$ \bprog ? v = y^2 * M*[1,x/y,(x/y)^2]~ %3 = [3*x^2 - 10*y*x - 3*y^2, -5*x^2 - 6*y*x + 5*y^2, -x^2 - y^2]~ ? v~*G*v %4 = 0 @eprog The library syntax is \fun{GEN}{qfparam}{GEN G, GEN sol, long flag}. \subsec{qfperfection$(G)$}\kbdsidx{qfperfection}\label{se:qfperfection} $G$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, outputs the perfection rank of the form. That is, gives the rank of the family of the $s$ symmetric matrices $v_iv_i^t$, where $s$ is half the number of minimal vectors and the $v_i$ ($1\le i\le s$) are the minimal vectors. Since this requires computing the minimal vectors, the computations can become very lengthy as the dimension of $x$ grows. The library syntax is \fun{GEN}{perf}{GEN G}. \subsec{qfrep$(q,B,\{\fl=0\})$}\kbdsidx{qfrep}\label{se:qfrep} $q$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, count the vectors representing successive integers. \item If $\fl = 0$, count all vectors. Outputs the vector whose $i$-th entry, $1 \leq i \leq B$ is half the number of vectors $v$ such that $q(v)=i$. \item If $\fl = 1$, count vectors of even norm. Outputs the vector whose $i$-th entry, $1 \leq i \leq B$ is half the number of vectors such that $q(v) = 2i$. \bprog ? q = [2, 1; 1, 3]; ? qfrep(q, 5) %2 = Vecsmall([0, 1, 2, 0, 0]) \\ 1 vector of norm 2, 2 of norm 3, etc. ? qfrep(q, 5, 1) %3 = Vecsmall([1, 0, 0, 1, 0]) \\ 1 vector of norm 2, 0 of norm 4, etc. @eprog\noindent This routine uses a naive algorithm based on \tet{qfminim}, and will fail if any entry becomes larger than $2^{31}$ (or $2^{63}$). The library syntax is \fun{GEN}{qfrep0}{GEN q, GEN B, long flag}. \subsec{qfsign$(x)$}\kbdsidx{qfsign}\label{se:qfsign} Returns $[p,m]$ the signature of the quadratic form represented by the symmetric matrix $x$. Namely, $p$ (resp.~$m$) is the number of positive (resp.~negative) eigenvalues of $x$. The result is computed using Gaussian reduction. The library syntax is \fun{GEN}{qfsign}{GEN x}. \subsec{qfsolve$(G)$}\kbdsidx{qfsolve}\label{se:qfsolve} Given a square symmetric matrix $G$ of dimension $n \geq 1$, solve over $\Q$ the quadratic equation $X^tGX = 0$. The matrix $G$ must have rational coefficients. The solution might be a single non-zero vector (vectorv) or a matrix (whose columns generate a totally isotropic subspace). If no solution exists, returns an integer, that can be a prime $p$ such that there is no local solution at $p$, or $-1$ if there is no real solution, or $-2$ if $n = 2$ and $-\det G$ is positive but not a square (which implies there is a real solution, but no local solution at some $p$ dividing $\det G$). \bprog ? G = [1,0,0;0,1,0;0,0,-34]; ? qfsolve(G) %1 = [-3, -5, 1]~ ? qfsolve([1,0; 0,2]) %2 = -1 \\ no real solution ? qfsolve([1,0,0;0,3,0; 0,0,-2]) %3 = 3 \\ no solution in Q_3 ? qfsolve([1,0; 0,-2]) %4 = -2 \\ no solution, n = 2 @eprog The library syntax is \fun{GEN}{qfsolve}{GEN G}. \subsec{seralgdep$(s,p,r)$}\kbdsidx{seralgdep}\label{se:seralgdep} \sidx{algebraic dependence} finds a linear relation between powers $(1,s, \dots, s^p)$ of the series $s$, with polynomial coefficients of degree $\leq r$. In case no relation is found, return $0$. \bprog ? s = 1 + 10*y - 46*y^2 + 460*y^3 - 5658*y^4 + 77740*y^5 + O(y^6); ? seralgdep(s, 2, 2) %2 = -x^2 + (8*y^2 + 20*y + 1) ? subst(%, x, s) %3 = O(y^6) ? seralgdep(s, 1, 3) %4 = (-77*y^2 - 20*y - 1)*x + (310*y^3 + 231*y^2 + 30*y + 1) ? seralgdep(s, 1, 2) %5 = 0 @eprog\noindent The series main variable must not be $x$, so as to be able to express the result as a polynomial in $x$. The library syntax is \fun{GEN}{seralgdep}{GEN s, long p, long r}. \subsec{setbinop$(f,X,\{Y\})$}\kbdsidx{setbinop}\label{se:setbinop} The set whose elements are the f(x,y), where x,y run through X,Y. respectively. If $Y$ is omitted, assume that $X = Y$ and that $f$ is symmetric: $f(x,y) = f(y,x)$ for all $x,y$ in $X$. \bprog ? X = [1,2,3]; Y = [2,3,4]; ? setbinop((x,y)->x+y, X,Y) \\ set X + Y %2 = [3, 4, 5, 6, 7] ? setbinop((x,y)->x-y, X,Y) \\ set X - Y %3 = [-3, -2, -1, 0, 1] ? setbinop((x,y)->x+y, X) \\ set 2X = X + X %2 = [2, 3, 4, 5, 6] @eprog The library syntax is \fun{GEN}{setbinop}{GEN f, GEN X, GEN Y = NULL}. \subsec{setintersect$(x,y)$}\kbdsidx{setintersect}\label{se:setintersect} Intersection of the two sets $x$ and $y$ (see \kbd{setisset}). If $x$ or $y$ is not a set, the result is undefined. The library syntax is \fun{GEN}{setintersect}{GEN x, GEN y}. \subsec{setisset$(x)$}\kbdsidx{setisset}\label{se:setisset} Returns true (1) if $x$ is a set, false (0) if not. In PARI, a set is a row vector whose entries are strictly increasing with respect to a (somewhat arbitrary) universal comparison function. To convert any object into a set (this is most useful for vectors, of course), use the function \kbd{Set}. \bprog ? a = [3, 1, 1, 2]; ? setisset(a) %2 = 0 ? Set(a) %3 = [1, 2, 3] @eprog The library syntax is \fun{long}{setisset}{GEN x}. \subsec{setminus$(x,y)$}\kbdsidx{setminus}\label{se:setminus} Difference of the two sets $x$ and $y$ (see \kbd{setisset}), i.e.~set of elements of $x$ which do not belong to $y$. If $x$ or $y$ is not a set, the result is undefined. The library syntax is \fun{GEN}{setminus}{GEN x, GEN y}. \subsec{setsearch$(S,x,\{\fl=0\})$}\kbdsidx{setsearch}\label{se:setsearch} Determines whether $x$ belongs to the set $S$ (see \kbd{setisset}). We first describe the default behavior, when $\fl$ is zero or omitted. If $x$ belongs to the set $S$, returns the index $j$ such that $S[j]=x$, otherwise returns 0. \bprog ? T = [7,2,3,5]; S = Set(T); ? setsearch(S, 2) %2 = 1 ? setsearch(S, 4) \\ not found %3 = 0 ? setsearch(T, 7) \\ search in a randomly sorted vector %4 = 0 \\ WRONG ! @eprog\noindent If $S$ is not a set, we also allow sorted lists with respect to the \tet{cmp} sorting function, without repeated entries, as per \tet{listsort}$(L,1)$; otherwise the result is undefined. \bprog ? L = List([1,4,2,3,2]); setsearch(L, 4) %1 = 0 \\ WRONG ! ? listsort(L, 1); L \\ sort L first %2 = List([1, 2, 3, 4]) ? setsearch(L, 4) %3 = 4 \\ now correct @eprog\noindent If $\fl$ is non-zero, this function returns the index $j$ where $x$ should be inserted, and $0$ if it already belongs to $S$. This is meant to be used for dynamically growing (sorted) lists, in conjunction with \kbd{listinsert}. \bprog ? L = List([1,5,2,3,2]); listsort(L,1); L %1 = List([1,2,3,5]) ? j = setsearch(L, 4, 1) \\ 4 should have been inserted at index j %2 = 4 ? listinsert(L, 4, j); L %3 = List([1, 2, 3, 4, 5]) @eprog The library syntax is \fun{long}{setsearch}{GEN S, GEN x, long flag}. \subsec{setunion$(x,y)$}\kbdsidx{setunion}\label{se:setunion} Union of the two sets $x$ and $y$ (see \kbd{setisset}). If $x$ or $y$ is not a set, the result is undefined. The library syntax is \fun{GEN}{setunion}{GEN x, GEN y}. \subsec{trace$(x)$}\kbdsidx{trace}\label{se:trace} This applies to quite general $x$. If $x$ is not a matrix, it is equal to the sum of $x$ and its conjugate, except for polmods where it is the trace as an algebraic number. For $x$ a square matrix, it is the ordinary trace. If $x$ is a non-square matrix (but not a vector), an error occurs. The library syntax is \fun{GEN}{gtrace}{GEN x}. \subsec{vecextract$(x,y,\{z\})$}\kbdsidx{vecextract}\label{se:vecextract} Extraction of components of the vector or matrix $x$ according to $y$. In case $x$ is a matrix, its components are the \emph{columns} of $x$. The parameter $y$ is a component specifier, which is either an integer, a string describing a range, or a vector. If $y$ is an integer, it is considered as a mask: the binary bits of $y$ are read from right to left, but correspond to taking the components from left to right. For example, if $y=13=(1101)_2$ then the components 1,3 and 4 are extracted. If $y$ is a vector (\typ{VEC}, \typ{COL} or \typ{VECSMALL}), which must have integer entries, these entries correspond to the component numbers to be extracted, in the order specified. If $y$ is a string, it can be \item a single (non-zero) index giving a component number (a negative index means we start counting from the end). \item a range of the form \kbd{"$a$..$b$"}, where $a$ and $b$ are indexes as above. Any of $a$ and $b$ can be omitted; in this case, we take as default values $a = 1$ and $b = -1$, i.e.~ the first and last components respectively. We then extract all components in the interval $[a,b]$, in reverse order if $b < a$. In addition, if the first character in the string is \kbd{\pow}, the complement of the given set of indices is taken. If $z$ is not omitted, $x$ must be a matrix. $y$ is then the \emph{row} specifier, and $z$ the \emph{column} specifier, where the component specifier is as explained above. \bprog ? v = [a, b, c, d, e]; ? vecextract(v, 5) \\@com mask %1 = [a, c] ? vecextract(v, [4, 2, 1]) \\@com component list %2 = [d, b, a] ? vecextract(v, "2..4") \\@com interval %3 = [b, c, d] ? vecextract(v, "-1..-3") \\@com interval + reverse order %4 = [e, d, c] ? vecextract(v, "^2") \\@com complement %5 = [a, c, d, e] ? vecextract(matid(3), "2..", "..") %6 = [0 1 0] [0 0 1] @eprog The range notations \kbd{v[i..j]} and \kbd{v[\pow i]} (for \typ{VEC} or \typ{COL}) and \kbd{M[i..j, k..l]} and friends (for \typ{MAT}) implement a subset of the above, in a simpler and \emph{faster} way, hence should be preferred in most common situations. The following features are not implemented in the range notation: \item reverse order, \item omitting either $a$ or $b$ in \kbd{$a$..$b$}. The library syntax is \fun{GEN}{extract0}{GEN x, GEN y, GEN z = NULL}. \subsec{vecprod$(v)$}\kbdsidx{vecprod}\label{se:vecprod} Return the product of the components of the vector $v$. Return $1$ on an empty vector. \bprog ? vecprod([1,2,3]) %1 = 6 ? vecprod([]) %2 = 1 @eprog The library syntax is \fun{GEN}{vecprod}{GEN v}. \subsec{vecsearch$(v,x,\{\var{cmpf}\})$}\kbdsidx{vecsearch}\label{se:vecsearch} Determines whether $x$ belongs to the sorted vector or list $v$: return the (positive) index where $x$ was found, or $0$ if it does not belong to $v$. If the comparison function cmpf is omitted, we assume that $v$ is sorted in increasing order, according to the standard comparison function \kbd{lex}, thereby restricting the possible types for $x$ and the elements of $v$ (integers, fractions, reals, and vectors of such). We also transparently allow a \typ{VECSMALL} $x$ in this case, for the natural ordering of the integers. If \kbd{cmpf} is present, it is understood as a comparison function and we assume that $v$ is sorted according to it, see \tet{vecsort} for how to encode comparison functions. \bprog ? v = [1,3,4,5,7]; ? vecsearch(v, 3) %2 = 2 ? vecsearch(v, 6) %3 = 0 \\ not in the list ? vecsearch([7,6,5], 5) \\ unsorted vector: result undefined %4 = 0 @eprog\noindent Note that if we are sorting with respect to a key which is expensive to compute (e.g. a discriminant), one should rather precompute all keys, sort that vector and search in the vector of keys, rather than searching in the original vector with respect to a comparison function. By abuse of notation, $x$ is also allowed to be a matrix, seen as a vector of its columns; again by abuse of notation, a \typ{VEC} is considered as part of the matrix, if its transpose is one of the matrix columns. \bprog ? v = vecsort([3,0,2; 1,0,2]) \\ sort matrix columns according to lex order %1 = [0 2 3] [0 2 1] ? vecsearch(v, [3,1]~) %2 = 3 ? vecsearch(v, [3,1]) \\ can search for x or x~ %3 = 3 ? vecsearch(v, [1,2]) %4 = 0 \\ not in the list @eprog\noindent The library syntax is \fun{long}{vecsearch}{GEN v, GEN x, GEN cmpf = NULL}. \subsec{vecsort$(x,\{\var{cmpf}\},\{\fl=0\})$}\kbdsidx{vecsort}\label{se:vecsort} Sorts the vector $x$ in ascending order, using a mergesort method. $x$ must be a list, vector or matrix (seen as a vector of its columns). Note that mergesort is stable, hence the initial ordering of ``equal'' entries (with respect to the sorting criterion) is not changed. If \kbd{cmpf} is omitted, we use the standard comparison function \kbd{lex}, thereby restricting the possible types for the elements of $x$ (integers, fractions or reals and vectors of those). We also transparently allow a \typ{VECSMALL} $x$ in this case, for the standard ordering on the integers. If \kbd{cmpf} is present, it is understood as a comparison function and we sort according to it. The following possibilities exist: \item an integer $k$: sort according to the value of the $k$-th subcomponents of the components of~$x$. \item a vector: sort lexicographically according to the components listed in the vector. For example, if $\kbd{cmpf}=\kbd{[2,1,3]}$, sort with respect to the second component, and when these are equal, with respect to the first, and when these are equal, with respect to the third. \item a comparison function: \typ{CLOSURE} with two arguments $x$ and $y$, and returning a real number which is $<0$, $>0$ or $=0$ if $xy$ or $x=y$ respectively. \item a key: \typ{CLOSURE} with one argument $x$ and returning the value $f(x)$ with respect to which we sort. \bprog ? vecsort([3,0,2; 1,0,2]) \\ sort columns according to lex order %1 = [0 2 3] [0 2 1] ? vecsort(v, (x,y)->y-x) \\@com reverse sort ? vecsort(v, (x,y)->abs(x)-abs(y)) \\@com sort by increasing absolute value ? vecsort(v, abs) \\@com sort by increasing absolute value, using key ? cmpf(x,y) = my(dx = poldisc(x), dy = poldisc(y)); abs(dx) - abs(dy); ? v = [x^2+1, x^3-2, x^4+5*x+1] vecsort(v, cmpf) \\@com comparison function ? vecsort(v, x->abs(poldisc(x))) \\@com key @eprog\noindent The \kbd{abs} and \kbd{cmpf} examples show how to use a named function instead of an anonymous function. It is preferable to use a \var{key} whenever possible rather than include it in the comparison function as above since the key is evaluated $O(n)$ times instead of $O(n\log n)$, where $n$ is the number of entries. A direct approach is also possible and equivalent to using a sorting key: \bprog ? T = [abs(poldisc(x)) | x<-v]; ? perm = vecsort(T,,1); \\@com indirect sort ? vecextract(v, perm) @eprog\noindent This also provides the vector $T$ of all keys, which is interesting for instance in later \tet{vecsearch} calls: it is more efficient to sort $T$ (\kbd{T = vecextract(T, perm)}) then search for a key in $T$ rather than to search in $v$ using a comparison function or a key. Note also that \tet{mapisdefined} is often easier to use and faster than \kbd{vecsearch}. \noindent The binary digits of \fl\ mean: \item 1: indirect sorting of the vector $x$, i.e.~if $x$ is an $n$-component vector, returns a permutation of $[1,2,\dots,n]$ which applied to the components of $x$ sorts $x$ in increasing order. For example, \kbd{vecextract(x, vecsort(x,,1))} is equivalent to \kbd{vecsort(x)}. \item 4: use descending instead of ascending order. \item 8: remove ``duplicate'' entries with respect to the sorting function (keep the first occurring entry). For example: \bprog ? vecsort([Pi,Mod(1,2),z], (x,y)->0, 8) \\@com make everything compare equal %1 = [3.141592653589793238462643383] ? vecsort([[2,3],[0,1],[0,3]], 2, 8) %2 = [[0, 1], [2, 3]] @eprog The library syntax is \fun{GEN}{vecsort0}{GEN x, GEN cmpf = NULL, long flag}. \subsec{vecsum$(v)$}\kbdsidx{vecsum}\label{se:vecsum} Return the sum of the components of the vector $v$. Return $0$ on an empty vector. \bprog ? vecsum([1,2,3]) %1 = 6 ? vecsum([]) %2 = 0 @eprog The library syntax is \fun{GEN}{vecsum}{GEN v}. \subsec{vector$(n,\{X\},\{\var{expr}=0\})$}\kbdsidx{vector}\label{se:vector} Creates a row vector (type \typ{VEC}) with $n$ components whose components are the expression \var{expr} evaluated at the integer points between 1 and $n$. If one of the last two arguments is omitted, fill the vector with zeroes. \bprog ? vector(3,i, 5*i) %1 = [5, 10, 15] ? vector(3) %2 = [0, 0, 0] @eprog The variable $X$ is lexically scoped to each evaluation of \var{expr}. Any change to $X$ within \var{expr} does not affect subsequent evaluations, it still runs 1 to $n$. A local change allows for example different indexing: \bprog vector(10, i, i=i-1; f(i)) \\ i = 0, ..., 9 vector(10, i, i=2*i; f(i)) \\ i = 2, 4, ..., 20 @eprog\noindent This per-element scope for $X$ differs from \kbd{for} loop evaluations, as the following example shows: \bprog n = 3 v = vector(n); vector(n, i, i++) ----> [2, 3, 4] v = vector(n); for (i = 1, n, v[i] = i++) ----> [2, 0, 4] @eprog\noindent %\syn{NO} \subsec{vectorsmall$(n,\{X\},\{\var{expr}=0\})$}\kbdsidx{vectorsmall}\label{se:vectorsmall} Creates a row vector of small integers (type \typ{VECSMALL}) with $n$ components whose components are the expression \var{expr} evaluated at the integer points between 1 and $n$. If one of the last two arguments is omitted, fill the vector with zeroes. %\syn{NO} \subsec{vectorv$(n,\{X\},\{\var{expr}=0\})$}\kbdsidx{vectorv}\label{se:vectorv} As \tet{vector}, but returns a column vector (type \typ{COL}). %\syn{NO} \section{Transcendental functions}\label{se:trans} Since the values of transcendental functions cannot be exactly represented, these functions will always return an inexact object: a real number, a complex number, a $p$-adic number or a power series. All these objects have a certain finite precision. As a general rule, which of course in some cases may have exceptions, transcendental functions operate in the following way: \item If the argument is either a real number or an inexact complex number (like \kbd{1.0 + I} or \kbd{Pi*I} but not \kbd{2 - 3*I}), then the computation is done with the precision of the argument. In the example below, we see that changing the precision to $50$ digits does not matter, because $x$ only had a precision of $19$ digits. \bprog ? \p 15 realprecision = 19 significant digits (15 digits displayed) ? x = Pi/4 %1 = 0.785398163397448 ? \p 50 realprecision = 57 significant digits (50 digits displayed) ? sin(x) %2 = 0.7071067811865475244 @eprog Note that even if the argument is real, the result may be complex (e.g.~$\text{acos}(2.0)$ or $\text{acosh}(0.0)$). See each individual function help for the definition of the branch cuts and choice of principal value. \item If the argument is either an integer, a rational, an exact complex number or a quadratic number, it is first converted to a real or complex number using the current \idx{precision}, which can be view and manipulated using the defaults \tet{realprecision} (in decimal digits) or \tet{realbitprecision} (in bits). This precision can be changed indifferently \item in decimal digits: use \b{p} or \kbd{default(realprecision,...)}. \item in bits: use \b{pb} or \kbd{default(realbitprecision,...)}. After this conversion, the computation proceeds as above for real or complex arguments. In library mode, the \kbd{realprecision} does not matter; instead the precision is taken from the \kbd{prec} parameter which every transcendental function has. As in \kbd{gp}, this \kbd{prec} is not used when the argument to a function is already inexact. Note that the argument \var{prec} stands for the length in words of a real number, including codewords. Hence we must have $\var{prec} \geq 3$. (Some functions allow a \kbd{bitprec} argument instead which allow finer granularity.) Some accuracies attainable on 32-bit machines cannot be attained on 64-bit machines for parity reasons. For example the default \kbd{gp} accuracy is 28 decimal digits on 32-bit machines, corresponding to \var{prec} having the value 5, but this cannot be attained on 64-bit machines. \item If the argument is a polmod (representing an algebraic number), then the function is evaluated for every possible complex embedding of that algebraic number. A column vector of results is returned, with one component for each complex embedding. Therefore, the number of components equals the degree of the \typ{POLMOD} modulus. \item If the argument is an intmod or a $p$-adic, at present only a few functions like \kbd{sqrt} (square root), \kbd{sqr} (square), \kbd{log}, \kbd{exp}, powering, \kbd{teichmuller} (Teichm\"uller character) and \kbd{agm} (arithmetic-geometric mean) are implemented. Note that in the case of a $2$-adic number, $\kbd{sqr}(x)$ may not be identical to $x*x$: for example if $x = 1+O(2^5)$ and $y = 1+O(2^5)$ then $x*y = 1+O(2^5)$ while $\kbd{sqr}(x) = 1+O(2^6)$. Here, $x * x$ yields the same result as $\kbd{sqr}(x)$ since the two operands are known to be \emph{identical}. The same statement holds true for $p$-adics raised to the power $n$, where $v_p(n) > 0$. \misctitle{Remark} If we wanted to be strictly consistent with the PARI philosophy, we should have $x*y = (4 \mod 8)$ and $\kbd{sqr}(x) = (4 \mod 32)$ when both $x$ and $y$ are congruent to $2$ modulo $4$. However, since intmod is an exact object, PARI assumes that the modulus must not change, and the result is hence $(0\, \mod\, 4)$ in both cases. On the other hand, $p$-adics are not exact objects, hence are treated differently. \item If the argument is a polynomial, a power series or a rational function, it is, if necessary, first converted to a power series using the current series precision, held in the default \tet{seriesprecision}. This precision (the number of significant terms) can be changed using \b{ps} or \kbd{default(seriesprecision,...)}. Then the Taylor series expansion of the function around $X=0$ (where $X$ is the main variable) is computed to a number of terms depending on the number of terms of the argument and the function being computed. Under \kbd{gp} this again is transparent to the user. When programming in library mode, however, it is \emph{strongly} advised to perform an explicit conversion to a power series first, as in \bprog x = gtoser(x, gvar(x), seriesprec) @eprog\noindent where the number of significant terms \kbd{seriesprec} can be specified explicitly. If you do not do this, a global variable \kbd{precdl} is used instead, to convert polynomials and rational functions to a power series with a reasonable number of terms; tampering with the value of this global variable is \emph{deprecated} and strongly discouraged. \item If the argument is a vector or a matrix, the result is the componentwise evaluation of the function. In particular, transcendental functions on square matrices, which are not implemented in the present version \vers, will have a different name if they are implemented some day. \subseckbd{\pow} If $y$ is not of type integer, \kbd{x\pow y} has the same effect as \kbd{exp(y*log(x))}. It can be applied to $p$-adic numbers as well as to the more usual types.\sidx{powering} The library syntax is \fun{GEN}{gpow}{GEN x, GEN n, long prec} for $x\hbox{\kbd{\pow}}n$. \subsec{Catalan}\kbdsidx{Catalan}\label{se:Catalan} Catalan's constant $G = \sum_{n>=0}\dfrac{(-1)^n}{(2n+1)^2}=0.91596\cdots$. Note that \kbd{Catalan} is one of the few reserved names which cannot be used for user variables. The library syntax is \fun{GEN}{mpcatalan}{long prec}. \subsec{Euler}\kbdsidx{Euler}\label{se:Euler} Euler's constant $\gamma=0.57721\cdots$. Note that \kbd{Euler} is one of the few reserved names which cannot be used for user variables. The library syntax is \fun{GEN}{mpeuler}{long prec}. \subsec{I}\kbdsidx{I}\label{se:I} The complex number $\sqrt{-1}$. The library syntax is \fun{GEN}{gen_I}{}. \subsec{Pi}\kbdsidx{Pi}\label{se:Pi} The constant $\pi$ ($3.14159\cdots$). Note that \kbd{Pi} is one of the few reserved names which cannot be used for user variables. The library syntax is \fun{GEN}{mppi}{long prec}. \subsec{abs$(x)$}\kbdsidx{abs}\label{se:abs} Absolute value of $x$ (modulus if $x$ is complex). Rational functions are not allowed. Contrary to most transcendental functions, an exact argument is \emph{not} converted to a real number before applying \kbd{abs} and an exact result is returned if possible. \bprog ? abs(-1) %1 = 1 ? abs(3/7 + 4/7*I) %2 = 5/7 ? abs(1 + I) %3 = 1.414213562373095048801688724 @eprog\noindent If $x$ is a polynomial, returns $-x$ if the leading coefficient is real and negative else returns $x$. For a power series, the constant coefficient is considered instead. The library syntax is \fun{GEN}{gabs}{GEN x, long prec}. \subsec{acos$(x)$}\kbdsidx{acos}\label{se:acos} Principal branch of $\cos^{-1}(x) = -i \log (x + i\sqrt{1-x^2})$. In particular, $\Re(\text{acos}(x))\in [0,\pi]$ and if $x\in \R$ and $|x|>1$, then $\text{acos}(x)$ is complex. The branch cut is in two pieces: $]-\infty,-1]$ , continuous with quadrant II, and $[1,+\infty[$, continuous with quadrant IV. We have $\text{acos}(x) = \pi/2 - \text{asin}(x)$ for all $x$. The library syntax is \fun{GEN}{gacos}{GEN x, long prec}. \subsec{acosh$(x)$}\kbdsidx{acosh}\label{se:acosh} Principal branch of $\cosh^{-1}(x) = 2 \log(\sqrt{(x+1)/2} + \sqrt{(x-1)/2})$. In particular, $\Re(\text{acosh}(x))\geq 0$ and $\Im(\text{acosh}(x))\in ]-\pi,\pi]$; if $x\in \R$ and $x<1$, then $\text{acosh}(x)$ is complex. The library syntax is \fun{GEN}{gacosh}{GEN x, long prec}. \subsec{agm$(x,y)$}\kbdsidx{agm}\label{se:agm} Arithmetic-geometric mean of $x$ and $y$. In the case of complex or negative numbers, the optimal AGM is returned (the largest in absolute value over all choices of the signs of the square roots). $p$-adic or power series arguments are also allowed. Note that a $p$-adic agm exists only if $x/y$ is congruent to 1 modulo $p$ (modulo 16 for $p=2$). $x$ and $y$ cannot both be vectors or matrices. The library syntax is \fun{GEN}{agm}{GEN x, GEN y, long prec}. \subsec{arg$(x)$}\kbdsidx{arg}\label{se:arg} Argument of the complex number $x$, such that $-\pi < \arg(x) \le \pi$. The library syntax is \fun{GEN}{garg}{GEN x, long prec}. \subsec{asin$(x)$}\kbdsidx{asin}\label{se:asin} Principal branch of $\sin^{-1}(x) = -i \log(ix + \sqrt{1 - x^2})$. In particular, $\Re(\text{asin}(x))\in [-\pi/2,\pi/2]$ and if $x\in \R$ and $|x|>1$ then $\text{asin}(x)$ is complex. The branch cut is in two pieces: $]-\infty,-1]$, continuous with quadrant II, and $[1,+\infty[$ continuous with quadrant IV. The function satisfies $i \text{asin}(x) = \text{asinh}(ix)$. The library syntax is \fun{GEN}{gasin}{GEN x, long prec}. \subsec{asinh$(x)$}\kbdsidx{asinh}\label{se:asinh} Principal branch of $\sinh^{-1}(x) = \log(x + \sqrt{1+x^2})$. In particular $\Im(\text{asinh}(x))\in [-\pi/2,\pi/2]$. The branch cut is in two pieces: $]-i \infty ,-i]$, continuous with quadrant III and $[+i,+i \infty[$, continuous with quadrant I. The library syntax is \fun{GEN}{gasinh}{GEN x, long prec}. \subsec{atan$(x)$}\kbdsidx{atan}\label{se:atan} Principal branch of $\text{tan}^{-1}(x) = \log ((1+ix)/(1-ix)) / 2i$. In particular the real part of $\text{atan}(x)$ belongs to $]-\pi/2,\pi/2[$. The branch cut is in two pieces: $]-i\infty,-i[$, continuous with quadrant IV, and $]i,+i \infty[$ continuous with quadrant II. The function satisfies $\text{atan}(x) = -i\text{atanh}(ix)$ for all $x\neq \pm i$. The library syntax is \fun{GEN}{gatan}{GEN x, long prec}. \subsec{atanh$(x)$}\kbdsidx{atanh}\label{se:atanh} Principal branch of $\text{tanh}^{-1}(x) = \log ((1+x)/(1-x)) / 2$. In particular the imaginary part of $\text{atanh}(x)$ belongs to $[-\pi/2,\pi/2]$; if $x\in \R$ and $|x|>1$ then $\text{atanh}(x)$ is complex. The library syntax is \fun{GEN}{gatanh}{GEN x, long prec}. \subsec{bernfrac$(x)$}\kbdsidx{bernfrac}\label{se:bernfrac} Bernoulli number\sidx{Bernoulli numbers} $B_x$, where $B_0=1$, $B_1=-1/2$, $B_2=1/6$,\dots, expressed as a rational number. The argument $x$ should be of type integer. The library syntax is \fun{GEN}{bernfrac}{long x}. \subsec{bernpol$(n, \{v = 'x\})$}\kbdsidx{bernpol}\label{se:bernpol} \idx{Bernoulli polynomial} $B_n$ in variable $v$. \bprog ? bernpol(1) %1 = x - 1/2 ? bernpol(3) %2 = x^3 - 3/2*x^2 + 1/2*x @eprog The library syntax is \fun{GEN}{bernpol}{long n, long v = -1} where \kbd{v} is a variable number. \subsec{bernreal$(x)$}\kbdsidx{bernreal}\label{se:bernreal} Bernoulli number\sidx{Bernoulli numbers} $B_x$, as \kbd{bernfrac}, but $B_x$ is returned as a real number (with the current precision). The library syntax is \fun{GEN}{bernreal}{long x, long prec}. \subsec{bernvec$(x)$}\kbdsidx{bernvec}\label{se:bernvec} This routine is obsolete, kept for backward compatibility only. The library syntax is \fun{GEN}{bernvec}{long x}. \subsec{besselh1$(\var{nu},x)$}\kbdsidx{besselh1}\label{se:besselh1} $H^1$-Bessel function of index \var{nu} and argument $x$. The library syntax is \fun{GEN}{hbessel1}{GEN nu, GEN x, long prec}. \subsec{besselh2$(\var{nu},x)$}\kbdsidx{besselh2}\label{se:besselh2} $H^2$-Bessel function of index \var{nu} and argument $x$. The library syntax is \fun{GEN}{hbessel2}{GEN nu, GEN x, long prec}. \subsec{besseli$(\var{nu},x)$}\kbdsidx{besseli}\label{se:besseli} $I$-Bessel function of index \var{nu} and argument $x$. If $x$ converts to a power series, the initial factor $(x/2)^\nu/\Gamma(\nu+1)$ is omitted (since it cannot be represented in PARI when $\nu$ is not integral). The library syntax is \fun{GEN}{ibessel}{GEN nu, GEN x, long prec}. \subsec{besselj$(\var{nu},x)$}\kbdsidx{besselj}\label{se:besselj} $J$-Bessel function of index \var{nu} and argument $x$. If $x$ converts to a power series, the initial factor $(x/2)^\nu/\Gamma(\nu+1)$ is omitted (since it cannot be represented in PARI when $\nu$ is not integral). The library syntax is \fun{GEN}{jbessel}{GEN nu, GEN x, long prec}. \subsec{besseljh$(n,x)$}\kbdsidx{besseljh}\label{se:besseljh} $J$-Bessel function of half integral index. More precisely, $\kbd{besseljh}(n,x)$ computes $J_{n+1/2}(x)$ where $n$ must be of type integer, and $x$ is any element of $\C$. In the present version \vers, this function is not very accurate when $x$ is small. The library syntax is \fun{GEN}{jbesselh}{GEN n, GEN x, long prec}. \subsec{besselk$(\var{nu},x)$}\kbdsidx{besselk}\label{se:besselk} $K$-Bessel function of index \var{nu} and argument $x$. The library syntax is \fun{GEN}{kbessel}{GEN nu, GEN x, long prec}. \subsec{besseln$(\var{nu},x)$}\kbdsidx{besseln}\label{se:besseln} $N$-Bessel function of index \var{nu} and argument $x$. The library syntax is \fun{GEN}{nbessel}{GEN nu, GEN x, long prec}. \subsec{cos$(x)$}\kbdsidx{cos}\label{se:cos} Cosine of $x$. The library syntax is \fun{GEN}{gcos}{GEN x, long prec}. \subsec{cosh$(x)$}\kbdsidx{cosh}\label{se:cosh} Hyperbolic cosine of $x$. The library syntax is \fun{GEN}{gcosh}{GEN x, long prec}. \subsec{cotan$(x)$}\kbdsidx{cotan}\label{se:cotan} Cotangent of $x$. The library syntax is \fun{GEN}{gcotan}{GEN x, long prec}. \subsec{cotanh$(x)$}\kbdsidx{cotanh}\label{se:cotanh} Hyperbolic cotangent of $x$. The library syntax is \fun{GEN}{gcotanh}{GEN x, long prec}. \subsec{dilog$(x)$}\kbdsidx{dilog}\label{se:dilog} Principal branch of the dilogarithm of $x$, i.e.~analytic continuation of the power series $\log_2(x)=\sum_{n\ge1}x^n/n^2$. The library syntax is \fun{GEN}{dilog}{GEN x, long prec}. \subsec{eint1$(x,\{n\})$}\kbdsidx{eint1}\label{se:eint1} Exponential integral $\int_x^\infty \dfrac{e^{-t}}{t}\,dt = \kbd{incgam}(0, x)$, where the latter expression extends the function definition from real $x > 0$ to all complex $x \neq 0$. If $n$ is present, we must have $x > 0$; the function returns the $n$-dimensional vector $[\kbd{eint1}(x),\dots,\kbd{eint1}(nx)]$. Contrary to other transcendental functions, and to the default case ($n$ omitted), the values are correct up to a bounded \emph{absolute}, rather than relative, error $10^{-n}$, where $n$ is \kbd{precision}$(x)$ if $x$ is a \typ{REAL} and defaults to \kbd{realprecision} otherwise. (In the most important application, to the computation of $L$-functions via approximate functional equations, those values appear as weights in long sums and small individual relative errors are less useful than controlling the absolute error.) This is faster than repeatedly calling \kbd{eint1($i$ * x)}, but less precise. The library syntax is \fun{GEN}{veceint1}{GEN x, GEN n = NULL, long prec}. Also available is \fun{GEN}{eint1}{GEN x, long prec}. \subsec{erfc$(x)$}\kbdsidx{erfc}\label{se:erfc} Complementary error function, analytic continuation of $(2/\sqrt\pi)\int_x^\infty e^{-t^2}\,dt = \kbd{incgam}(1/2,x^2)/\sqrt\pi$, where the latter expression extends the function definition from real $x$ to all complex $x \neq 0$. The library syntax is \fun{GEN}{gerfc}{GEN x, long prec}. \subsec{eta$(z,\{\fl=0\})$}\kbdsidx{eta}\label{se:eta} Variants of \idx{Dedekind}'s $\eta$ function. If $\fl = 0$, return $\prod_{n=1}^\infty(1-q^n)$, where $q$ depends on $x$ in the following way: \item $q = e^{2i\pi x}$ if $x$ is a \emph{complex number} (which must then have positive imaginary part); notice that the factor $q^{1/24}$ is missing! \item $q = x$ if $x$ is a \typ{PADIC}, or can be converted to a \emph{power series} (which must then have positive valuation). If $\fl$ is non-zero, $x$ is converted to a complex number and we return the true $\eta$ function, $q^{1/24}\prod_{n=1}^\infty(1-q^n)$, where $q = e^{2i\pi x}$. The library syntax is \fun{GEN}{eta0}{GEN z, long flag, long prec}. Also available is \fun{GEN}{trueeta}{GEN x, long prec} ($\fl=1$). \subsec{exp$(x)$}\kbdsidx{exp}\label{se:exp} Exponential of $x$. $p$-adic arguments with positive valuation are accepted. The library syntax is \fun{GEN}{gexp}{GEN x, long prec}. For a \typ{PADIC} $x$, the function \fun{GEN}{Qp_exp}{GEN x} is also available. \subsec{expm1$(x)$}\kbdsidx{expm1}\label{se:expm1} Return $\exp(x)-1$, computed in a way that is also accurate when the real part of $x$ is near $0$. A naive direct computation would suffer from catastrophic cancellation; PARI's direct computation of $\exp(x)$ alleviates this well known problem at the expense of computing $\exp(x)$ to a higher accuracy when $x$ is small. Using \kbd{expm1} is recommended instead: \bprog ? default(realprecision, 10000); x = 1e-100; ? a = expm1(x); time = 4 ms. ? b = exp(x)-1; time = 4 ms. ? default(realprecision, 10040); x = 1e-100; ? c = expm1(x); \\ reference point ? abs(a-c)/c \\ relative error in expm1(x) %7 = 1.4027986153764843997 E-10019 ? abs(b-c)/c \\ relative error in exp(x)-1 %8 = 1.7907031188259675794 E-9919 @eprog\noindent As the example above shows, when $x$ is near $0$, \kbd{expm1} is more accurate than \kbd{exp(x)-1}. The library syntax is \fun{GEN}{gexpm1}{GEN x, long prec}. \subsec{gamma$(s)$}\kbdsidx{gamma}\label{se:gamma} For $s$ a complex number, evaluates Euler's gamma function \sidx{gamma-function} $$\Gamma(s)=\int_0^\infty t^{s-1}\exp(-t)\,dt.$$ Error if $s$ is a non-positive integer, where $\Gamma$ has a pole. For $s$ a \typ{PADIC}, evaluates the Morita gamma function at $s$, that is the unique continuous $p$-adic function on the $p$-adic integers extending $\Gamma_p(k)=(-1)^k \prod_{j 0$. The library syntax is \fun{GEN}{glambertW}{GEN y, long prec}. \subsec{lngamma$(x)$}\kbdsidx{lngamma}\label{se:lngamma} Principal branch of the logarithm of the gamma function of $x$. This function is analytic on the complex plane with non-positive integers removed, and can have much larger arguments than \kbd{gamma} itself. For $x$ a power series such that $x(0)$ is not a pole of \kbd{gamma}, compute the Taylor expansion. (PARI only knows about regular power series and can't include logarithmic terms.) \bprog ? lngamma(1+x+O(x^2)) %1 = -0.57721566490153286060651209008240243104*x + O(x^2) ? lngamma(x+O(x^2)) *** at top-level: lngamma(x+O(x^2)) *** ^----------------- *** lngamma: domain error in lngamma: valuation != 0 ? lngamma(-1+x+O(x^2)) *** lngamma: Warning: normalizing a series with 0 leading term. *** at top-level: lngamma(-1+x+O(x^2)) *** ^-------------------- *** lngamma: domain error in intformal: residue(series, pole) != 0 @eprog The library syntax is \fun{GEN}{glngamma}{GEN x, long prec}. \subsec{log$(x)$}\kbdsidx{log}\label{se:log} Principal branch of the natural logarithm of $x \in \C^*$, i.e.~such that $\Im(\log(x))\in{} ]-\pi,\pi]$. The branch cut lies along the negative real axis, continuous with quadrant 2, i.e.~such that $\lim_{b\to 0^+} \log (a+bi) = \log a$ for $a \in\R^*$. The result is complex (with imaginary part equal to $\pi$) if $x\in \R$ and $x < 0$. In general, the algorithm uses the formula $$\log(x) \approx {\pi\over 2\text{agm}(1, 4/s)} - m \log 2, $$ if $s = x 2^m$ is large enough. (The result is exact to $B$ bits provided $s > 2^{B/2}$.) At low accuracies, the series expansion near $1$ is used. $p$-adic arguments are also accepted for $x$, with the convention that $\log(p)=0$. Hence in particular $\exp(\log(x))/x$ is not in general equal to 1 but to a $(p-1)$-th root of unity (or $\pm1$ if $p=2$) times a power of $p$. The library syntax is \fun{GEN}{glog}{GEN x, long prec}. For a \typ{PADIC} $x$, the function \fun{GEN}{Qp_log}{GEN x} is also available. \subsec{log1p$(x)$}\kbdsidx{log1p}\label{se:log1p} Return $\log(1+x)$, computed in a way that is also accurate when the real part of $x$ is near $0$. This is the reciprocal function of \kbd{expm1}$(x) = \exp(x)-1$. \bprog ? default(realprecision, 10000); x = Pi*1e-100; ? (expm1(log1p(x)) - x) / x %2 = -7.668242895059371866 E-10019 ? (log1p(expm1(x)) - x) / x %3 = -7.668242895059371866 E-10019 @eprog\noindent When $x$ is small, this function is both faster and more accurate than $\log(1+x)$: \bprog ? \p38 ? x = 1e-20; ? localprec(100); c = log1p(x); \\ reference point ? a = log1p(x); abs((a - c)/c) %6 = 0.E-38 ? b = log(1+x); abs((b - c)/c) \\ slightly less accurate %7 = 1.5930919111324522770 E-38 ? for (i=1,10^5,log1p(x)) time = 81 ms. ? for (i=1,10^5,log(1+x)) time = 100 ms. \\ slower, too @eprog The library syntax is \fun{GEN}{glog1p}{GEN x, long prec}. \subsec{polylog$(m,x,\{\fl=0\})$}\kbdsidx{polylog}\label{se:polylog} One of the different polylogarithms, depending on \fl: If $\fl=0$ or is omitted: $m^\text{th}$ polylogarithm of $x$, i.e.~analytic continuation of the power series $\text{Li}_m(x)=\sum_{n\ge1}x^n/n^m$ ($x < 1$). Uses the functional equation linking the values at $x$ and $1/x$ to restrict to the case $|x|\leq 1$, then the power series when $|x|^2\le1/2$, and the power series expansion in $\log(x)$ otherwise. Using $\fl$, computes a modified $m^\text{th}$ polylogarithm of $x$. We use Zagier's notations; let $\Re_m$ denote $\Re$ or $\Im$ depending on whether $m$ is odd or even: If $\fl=1$: compute $\tilde D_m(x)$, defined for $|x|\le1$ by $$\Re_m\left(\sum_{k=0}^{m-1} \dfrac{(-\log|x|)^k}{k!}\text{Li}_{m-k}(x) +\dfrac{(-\log|x|)^{m-1}}{m!}\log|1-x|\right).$$ If $\fl=2$: compute $D_m(x)$, defined for $|x|\le1$ by $$\Re_m\left(\sum_{k=0}^{m-1}\dfrac{(-\log|x|)^k}{k!}\text{Li}_{m-k}(x) -\dfrac{1}{2}\dfrac{(-\log|x|)^m}{m!}\right).$$ If $\fl=3$: compute $P_m(x)$, defined for $|x|\le1$ by $$\Re_m\left(\sum_{k=0}^{m-1}\dfrac{2^kB_k}{k!}(\log|x|)^k\text{Li}_{m-k}(x) -\dfrac{2^{m-1}B_m}{m!}(\log|x|)^m\right).$$ These three functions satisfy the functional equation $f_m(1/x) = (-1)^{m-1}f_m(x)$. The library syntax is \fun{GEN}{polylog0}{long m, GEN x, long flag, long prec}. Also available is \fun{GEN}{gpolylog}{long m, GEN x, long prec} (\fl = 0). \subsec{psi$(x)$}\kbdsidx{psi}\label{se:psi} The $\psi$-function of $x$, i.e.~the logarithmic derivative $\Gamma'(x)/\Gamma(x)$. The library syntax is \fun{GEN}{gpsi}{GEN x, long prec}. \subsec{sin$(x)$}\kbdsidx{sin}\label{se:sin} Sine of $x$. The library syntax is \fun{GEN}{gsin}{GEN x, long prec}. \subsec{sinc$(x)$}\kbdsidx{sinc}\label{se:sinc} Cardinal sine of $x$, i.e. $\sin(x)/x$ if $x\neq 0$, $1$ otherwise. Note that this function also allows to compute $$(1-\cos(x)) / x^2 = \kbd{sinc}(x/2)^2 / 2$$ accurately near $x = 0$. The library syntax is \fun{GEN}{gsinc}{GEN x, long prec}. \subsec{sinh$(x)$}\kbdsidx{sinh}\label{se:sinh} Hyperbolic sine of $x$. The library syntax is \fun{GEN}{gsinh}{GEN x, long prec}. \subsec{sqr$(x)$}\kbdsidx{sqr}\label{se:sqr} Square of $x$. This operation is not completely straightforward, i.e.~identical to $x * x$, since it can usually be computed more efficiently (roughly one-half of the elementary multiplications can be saved). Also, squaring a $2$-adic number increases its precision. For example, \bprog ? (1 + O(2^4))^2 %1 = 1 + O(2^5) ? (1 + O(2^4)) * (1 + O(2^4)) %2 = 1 + O(2^4) @eprog\noindent Note that this function is also called whenever one multiplies two objects which are known to be \emph{identical}, e.g.~they are the value of the same variable, or we are computing a power. \bprog ? x = (1 + O(2^4)); x * x %3 = 1 + O(2^5) ? (1 + O(2^4))^4 %4 = 1 + O(2^6) @eprog\noindent (note the difference between \kbd{\%2} and \kbd{\%3} above). The library syntax is \fun{GEN}{gsqr}{GEN x}. \subsec{sqrt$(x)$}\kbdsidx{sqrt}\label{se:sqrt} Principal branch of the square root of $x$, defined as $\sqrt{x} = \exp(\log x / 2)$. In particular, we have $\text{Arg}(\text{sqrt}(x))\in{} ]-\pi/2, \pi/2]$, and if $x\in \R$ and $x<0$, then the result is complex with positive imaginary part. Intmod a prime $p$, \typ{PADIC} and \typ{FFELT} are allowed as arguments. In the first 2 cases (\typ{INTMOD}, \typ{PADIC}), the square root (if it exists) which is returned is the one whose first $p$-adic digit is in the interval $[0,p/2]$. For other arguments, the result is undefined. The library syntax is \fun{GEN}{gsqrt}{GEN x, long prec}. For a \typ{PADIC} $x$, the function \fun{GEN}{Qp_sqrt}{GEN x} is also available. \subsec{sqrtn$(x,n,\{\&z\})$}\kbdsidx{sqrtn}\label{se:sqrtn} Principal branch of the $n$th root of $x$, i.e.~such that $\text{Arg}(\text{sqrtn}(x))\in{} ]-\pi/n, \pi/n]$. Intmod a prime and $p$-adics are allowed as arguments. If $z$ is present, it is set to a suitable root of unity allowing to recover all the other roots. If it was not possible, z is set to zero. In the case this argument is present and no $n$th root exist, $0$ is returned instead of raising an error. \bprog ? sqrtn(Mod(2,7), 2) %1 = Mod(3, 7) ? sqrtn(Mod(2,7), 2, &z); z %2 = Mod(6, 7) ? sqrtn(Mod(2,7), 3) *** at top-level: sqrtn(Mod(2,7),3) *** ^----------------- *** sqrtn: nth-root does not exist in gsqrtn. ? sqrtn(Mod(2,7), 3, &z) %2 = 0 ? z %3 = 0 @eprog The following script computes all roots in all possible cases: \bprog sqrtnall(x,n)= { my(V,r,z,r2); r = sqrtn(x,n, &z); if (!z, error("Impossible case in sqrtn")); if (type(x) == "t_INTMOD" || type(x)=="t_PADIC", r2 = r*z; n = 1; while (r2!=r, r2*=z;n++)); V = vector(n); V[1] = r; for(i=2, n, V[i] = V[i-1]*z); V } addhelp(sqrtnall,"sqrtnall(x,n):compute the vector of nth-roots of x"); @eprog\noindent The library syntax is \fun{GEN}{gsqrtn}{GEN x, GEN n, GEN *z = NULL, long prec}. If $x$ is a \typ{PADIC}, the function \fun{GEN}{Qp_sqrtn}{GEN x, GEN n, GEN *z} is also available. \subsec{tan$(x)$}\kbdsidx{tan}\label{se:tan} Tangent of $x$. The library syntax is \fun{GEN}{gtan}{GEN x, long prec}. \subsec{tanh$(x)$}\kbdsidx{tanh}\label{se:tanh} Hyperbolic tangent of $x$. The library syntax is \fun{GEN}{gtanh}{GEN x, long prec}. \subsec{teichmuller$(x,\{\var{tab}\})$}\kbdsidx{teichmuller}\label{se:teichmuller} Teichm\"uller character of the $p$-adic number $x$, i.e. the unique $(p-1)$-th root of unity congruent to $x / p^{v_p(x)}$ modulo $p$. If $x$ is of the form $[p,n]$, for a prime $p$ and integer $n$, return the lifts to $\Z$ of the images of $i + O(p^n)$ for $i = 1, \dots, p-1$, i.e. all roots of $1$ ordered by residue class modulo $p$. Such a vector can be fed back to \kbd{teichmuller}, as the optional argument \kbd{tab}, to speed up later computations. \bprog ? z = teichmuller(2 + O(101^5)) %1 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) ? z^100 %2 = 1 + O(101^5) ? T = teichmuller([101, 5]); ? teichmuller(2 + O(101^5), T) %4 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) @eprog\noindent As a rule of thumb, if more than $$p \,/\, 2(\log_2(p) + \kbd{hammingweight}(p))$$ values of \kbd{teichmuller} are to be computed, then it is worthwile to initialize: \bprog ? p = 101; n = 100; T = teichmuller([p,n]); \\ instantaneous ? for(i=1,10^3, vector(p-1, i, teichmuller(i+O(p^n), T))) time = 60 ms. ? for(i=1,10^3, vector(p-1, i, teichmuller(i+O(p^n)))) time = 1,293 ms. ? 1 + 2*(log(p)/log(2) + hammingweight(p)) %8 = 22.316[...] @eprog\noindent Here the precompuation induces a speedup by a factor $1293/ 60 \approx 21.5$. \misctitle{Caveat} If the accuracy of \kbd{tab} (the argument $n$ above) is lower than the precision of $x$, the \emph{former} is used, i.e. the cached value is not refined to higher accuracy. It the accuracy of \kbd{tab} is larger, then the precision of $x$ is used: \bprog ? Tlow = teichmuller([101, 2]); \\ lower accuracy ! ? teichmuller(2 + O(101^5), Tlow) %10 = 2 + 83*101 + O(101^5) \\ no longer a root of 1 ? Thigh = teichmuller([101, 10]); \\ higher accuracy ? teichmuller(2 + O(101^5), Thigh) %12 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) @eprog The library syntax is \fun{GEN}{teichmuller}{GEN x, GEN tab = NULL}. Also available are the functions \fun{GEN}{teich}{GEN x} (\kbd{tab} is \kbd{NULL}) as well as \fun{GEN}{teichmullerinit}{long p, long n}. \subsec{theta$(q,z)$}\kbdsidx{theta}\label{se:theta} Jacobi sine theta-function $$ \theta_1(z, q) = 2q^{1/4} \sum_{n\geq 0} (-1)^n q^{n(n+1)} \sin((2n+1)z).$$ The library syntax is \fun{GEN}{theta}{GEN q, GEN z, long prec}. \subsec{thetanullk$(q,k)$}\kbdsidx{thetanullk}\label{se:thetanullk} $k$-th derivative at $z=0$ of $\kbd{theta}(q,z)$. The library syntax is \fun{GEN}{thetanullk}{GEN q, long k, long prec}. \fun{GEN}{vecthetanullk}{GEN q, long k, long prec} returns the vector of all $\dfrac{d^i\theta}{dz^i}(q,0)$ for all odd $i = 1, 3, \dots, 2k-1$. \fun{GEN}{vecthetanullk_tau}{GEN tau, long k, long prec} returns \kbd{vecthetanullk\_tau} at $q = \exp(2i\pi \kbd{tau})$. \subsec{weber$(x,\{\fl=0\})$}\kbdsidx{weber}\label{se:weber} One of Weber's three $f$ functions. If $\fl=0$, returns $$f(x)=\exp(-i\pi/24)\cdot\eta((x+1)/2)\,/\,\eta(x) \quad\hbox{such that}\quad j=(f^{24}-16)^3/f^{24}\,,$$ where $j$ is the elliptic $j$-invariant (see the function \kbd{ellj}). If $\fl=1$, returns $$f_1(x)=\eta(x/2)\,/\,\eta(x)\quad\hbox{such that}\quad j=(f_1^{24}+16)^3/f_1^{24}\,.$$ Finally, if $\fl=2$, returns $$f_2(x)=\sqrt{2}\eta(2x)\,/\,\eta(x)\quad\hbox{such that}\quad j=(f_2^{24}+16)^3/f_2^{24}.$$ Note the identities $f^8=f_1^8+f_2^8$ and $ff_1f_2=\sqrt2$. The library syntax is \fun{GEN}{weber0}{GEN x, long flag, long prec}. Also available are \fun{GEN}{weberf}{GEN x, long prec}, \fun{GEN}{weberf1}{GEN x, long prec} and \fun{GEN}{weberf2}{GEN x, long prec}. \subsec{zeta$(s)$}\kbdsidx{zeta}\label{se:zeta} For $s \neq 1$ a complex number, Riemann's zeta function \sidx{Riemann zeta-function} $\zeta(s)=\sum_{n\ge1}n^{-s}$, computed using the \idx{Euler-Maclaurin} summation formula, except when $s$ is of type integer, in which case it is computed using Bernoulli numbers\sidx{Bernoulli numbers} for $s\le0$ or $s>0$ and even, and using modular forms for $s>0$ and odd. Power series are also allowed: \bprog ? zeta(2) - Pi^2/6 %1 = 0.E-38 ? zeta(1+x+O(x^3)) %2 = 1.0000000000000000000000000000000000000*x^-1 + \ 0.57721566490153286060651209008240243104 + O(x) @eprog For $s\neq 1$ a $p$-adic number, Kubota-Leopoldt zeta function at $s$, that is the unique continuous $p$-adic function on the $p$-adic integers that interpolates the values of $(1 - p^{-k}) \zeta(k)$ at negative integers $k$ such that $k \equiv 1 \pmod{p-1}$ (resp. $k$ is odd) if $p$ is odd (resp. $p = 2$). Power series are not allowed in this case. \bprog ? zeta(-3+O(5^10)) %1 = 4*5^-1 + 4 + 3*5 + 4*5^3 + 4*5^5 + 4*5^7 + O(5^9))))) ? (1-5^3) * zeta(-3) %2 = -1.0333333333333333333333333333333333333 ? bestappr(%) %3 = -31/30 ? zeta(-3+O(5^10)) - (-31/30) %4 = O(5^9) @eprog The library syntax is \fun{GEN}{gzeta}{GEN s, long prec}. \subsec{zetahurwitz$(s,x,\{\var{der}=0\})$}\kbdsidx{zetahurwitz}\label{se:zetahurwitz} Hurwitz zeta function $\zeta(s,x)=\sum_{n\ge0}(n+x)^{-s}$ and analytically continued, with $s\ne1$ and $x$ not a negative or zero integer. Note that $\zeta(s,1) = \zeta(s)$. $s$ can also be a polynomial, rational function, or power series. If \kbd{der} is positive, compute the \kbd{der}'th derivative with respect to $s$. Note that the derivative with respect to $x$ is simply $-s\zeta(s+1,x)$. \bprog ? zetahurwitz(Pi,Pi) %1 = 0.056155444497585099925180502385781494484 ? zetahurwitz(2,1) - zeta(2) %2 = -2.350988701644575016 E-38 ? zetahurwitz(Pi,3) - (zeta(Pi)-1-1/2^Pi) %3 = -2.2040519077917890774 E-39 ? zetahurwitz(-7/2,1) - zeta(-7/2) %4 = -2.295887403949780289 E-41 ? zetahurwitz(-2.3,Pi+I*log(2)) %5 = -5.1928369229555125820137832704455696057\ - 6.1349660138824147237884128986232049582*I ? zetahurwitz(-1+x^2+O(x^3),1) %6 = -0.083333333333333333333333333333333333333\ - 0.16542114370045092921391966024278064276*x^2 + O(x^3) ? zetahurwitz(1+x+O(x^4),2) %7 = 1.0000000000000000000000000000000000000*x^-1\ - 0.42278433509846713939348790991759756896\ + 0.072815845483676724860586375874901319138*x + O(x^2) ? zetahurwitz(2,1,2) \\ zeta''(2) %8 = 1.9892802342989010234208586874215163815 @eprog The library syntax is \fun{GEN}{zetahurwitz}{GEN s, GEN x, long der, long bitprec}. \subsec{zetamult$(s, \{T\})$}\kbdsidx{zetamult}\label{se:zetamult} For $s$ a vector of positive integers such that $s[1] \geq 2$, returns the multiple zeta value (MZV) $$\zeta(s_1,\dots, s_k) = \sum_{n_1>\dots>n_k>0} n_1^{-s_1}\dots n_k^{-s_k}.$$ \bprog ? zetamult([2,1]) - zeta(3) \\ Euler's identity %1 = 0.E-38 @eprog\noindent If the bit precision is $B$, this function runs in time $\tilde{O}(k B^2)$. If $T$ is provided, it must be the output of \kbd{zetamultinit}$(w)$ for some $w \geq s_1 + \dots + s_k$ and will provide a small speed up, usually about 10\%. \bprog ? T = zetamultinit(20); s = [2,1,1,1,1,1,1,1,1]; ? for(i=1,10^3, zetamult(s)) time = 373 ms. ? for(i=1,10^3, zetamult(s, T)) \\ faster time = 279 ms. ? zetamult(vector(10,i,2), T) %4 = 1.7165384749821433018378232207719985786 E-10 ? zetamult(vector(11,i,2), T) \\ overshoot *** at top-level: zetamult(vector(11,i *** ^-------------------- *** zetamult: domain error in zetamult: weight > 20 @eprog In addition to the above format (\kbd{avec}), the function also accepts an internal binary format \kbd{evec} (each $s_i$ is replaced by $s_i$ bits, all of them 0 but the last one), and an \kbd{index} format (if $e$ is the positive integer attached the \kbd{evec} vector of bits, the index is the integer $e + 2^{k-2}$). The function \kbd{zetamultconvert} allows to pass from one format to the other; the function \kbd{zetamultall} computes simultaneously all MZVs of weight $\sum_{i\leq k} s_i$ up to $n$. The library syntax is \fun{GEN}{zetamult0}{GEN s, GEN T = NULL, long prec}. Also available is \fun{GEN}{zetamult}{GEN avec, long prec}. \subsec{zetamultall$(n)$}\kbdsidx{zetamultall}\label{se:zetamultall} List of all multiple zeta values for weight $s_1 + \dots + s_k$ up to $n$. The function returns a vector with $2^{n-1}-1$ components whose $i$-th entry is the MZV of \kbd{index} $i$ (see \kbd{zetamult}). \bprog ? z = zetamultall(5); ? z[10] %2 = 0.22881039760335375976874614894168879193 ? zetamultconvert(10) \\ convert index 10 to avec %3 = Vecsmall([3, 2]) ? zetamult(%) %4 = 0.22881039760335375976874614894168879193 ? zetamult(10) %5 = 0.22881039760335375976874614894168879193 @eprog\noindent If the bit precision is $B$, this function runs in time $O(2^n n B^2)$ for an output of size $O(2^n B)$. The library syntax is \fun{GEN}{zetamultall}{long n, long prec}. \subsec{zetamultconvert$(a,\{\var{fl}=1\})$}\kbdsidx{zetamultconvert}\label{se:zetamultconvert} \kbd{a} being either an \kbd{evec}, \kbd{avec}, or index \kbd{m}, converts into \kbd{evec} (\kbd{fl=0}), \kbd{avec} (\kbd{fl=1}, default), or index \kbd{m} (\kbd{fl=2}); see \kbd{zetamult} for explanations. \bprog ? zetamultconvert(10) %1 = Vecsmall([3, 2]) ? zetamultconvert(13) %2 = Vecsmall([2, 2, 1]) ? zetamultconvert(10, 0) %3 = Vecsmall([0, 0, 1, 0, 1]) ? zetamultconvert(13, 0) %4 = Vecsmall([0, 1, 0, 1, 1]) @eprog\noindent The last two lines imply that $[3,2]$ and $[2,2,1]$ are dual (reverse order of bits and swap $0$ and $1$ in \kbd{evec} form). Hence they have the same zeta value: \bprog ? zetamult([3,2]) %5 = 0.22881039760335375976874614894168879193 ? zetamult([2,2,1]) %6 = 0.22881039760335375976874614894168879193 @eprog The library syntax is \fun{GEN}{zetamultconvert}{GEN a, long fl}. \subsec{zetamultinit$(\var{maxw})$}\kbdsidx{zetamultinit}\label{se:zetamultinit} Initialize data (depending on the precision) used to compute multiple zeta values at integral points $s = [s_1,\dots,s_k]$ for any $s_1 + \dots + s_k \leq \var{maxw}$. The corresponding data is inexpensive to compute or store and provides a small speedup (usually about 10\%) when multiple values are to be computed at a given accuracy. \bprog ? for(i = 1, 2^12-1, zetamult(i)) time = 1,413 ms ? T = zetamultinit(13); \\ instantaneous ? for(i = 1, 2^12-1, zetamult(i, T)) \\ used cached data time = 1,315 ms ? zetamultall(12); \\ much faster ! time = 27 ms ? T=zetamultinit(102); sizebyte(T) \\ small even for huge weights time = 5 ms. %5 = 1440504 ? for(i = 1, 2^5, zetamult(2^100+i)) time = 633 ms. ? for(i = 1, 2^5, zetamult(2^100+i, T)) time = 550 ms. @eprog\noindent For small weights, \kbd{zetamultall} will be much more efficient; but it is not an option when the weight gets large. The library syntax is \fun{GEN}{zetamultinit}{long maxw, long prec}. \section{Sums, products, integrals and similar functions} \label{se:sums} Although the \kbd{gp} calculator is programmable, it is useful to have a number of preprogrammed loops, including sums, products, and a certain number of recursions. Also, a number of functions from numerical analysis like numerical integration and summation of series will be described here. One of the parameters in these loops must be the control variable, hence a simple variable name. In the descriptions, the letter $X$ will always denote any simple variable name, and represents the formal parameter used in the function. The expression to be summed, integrated, etc. is any legal PARI expression, including of course expressions using loops. \misctitle{Library mode} Since it is easier to program directly the loops in library mode, these functions are mainly useful for GP programming. On the other hand, numerical routines code a function (to be integrated, summed, etc.) with two parameters named \bprog GEN (*eval)(void*,GEN) void *E; \\ context: eval(E, x) must evaluate your function at x. @eprog\noindent see the Libpari manual for details. \misctitle{Numerical integration}\sidx{numerical integration} Starting with version 2.2.9 the ``double exponential'' univariate integration method is implemented in \tet{intnum} and its variants. Romberg integration is still available under the name \kbd{intnumromb}, but superseded. It is possible to compute numerically integrals to thousands of decimal places in reasonable time, as long as the integrand is regular. It is also reasonable to compute numerically integrals in several variables, although more than two becomes lengthy. The integration domain may be non-compact, and the integrand may have reasonable singularities at endpoints. To use \kbd{intnum}, you must split the integral into a sum of subintegrals where the function has no singularities except at the endpoints. Polynomials in logarithms are not considered singular, and neglecting these logs, singularities are assumed to be algebraic (asymptotic to $C(x-a)^{-\alpha}$ for some $\alpha > -1$ when $x$ is close to $a$), or to correspond to simple discontinuities of some (higher) derivative of the function. For instance, the point $0$ is a singularity of $\text{abs}(x)$. See also the discrete summation methods below, sharing the prefix \kbd{sum}. \subsec{asympnum$(\var{expr},\{k=20\},\{\var{alpha} = 1\})$}\kbdsidx{asympnum}\label{se:asympnum} Asymptotic expansion of \var{expr}, corresponding to a sequence $u(n)$, assuming it has the shape $$u(n) \approx \sum_{i \geq 0} a_i n^{-i\alpha}$$ with rational coefficients $a_i$ with reasonable height; the algorithm is heuristic and performs repeated calls to limitnum, with \kbd{k} and \kbd{alpha} are as in \kbd{limitnum} \bprog ? f(n) = n! / (n^n*exp(-n)*sqrt(n)); ? asympnum(f) %2 = [] \\ failure ! ? l = limitnum(f) %3 = 2.5066282746310005024157652848110452530 ? asympnum(n->f(n)/l) \\ normalize %4 = [1, 1/12, 1/288, -139/51840] @eprog\noindent and we indeed get a few terms of Stirling's expansion. Note that it helps to normalize with a limit computed to higher accuracy: \bprog ? \p100 ? L = limitnum(f) ? \p38 ? asympnum(n->f(n)/L) \\ we get more terms! %6 = [1, 1/12, 1/288, -139/51840, -571/2488320, 163879/209018880,\ 5246819/75246796800, -534703531/902961561600] @eprog\noindent If \kbd{alpha} is not an integer, loss of accuracy is expected, so it should be precomputed to double accuracy, say: \bprog ? \p38 ? asympnum(n->-log(1-1/n^Pi),,Pi) %1 = [0, 1, 1/2, 1/3] ? asympnum(n->-log(1-1/sqrt(n)),,1/2) %2 = [0, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, \ 1/13, 1/14, 1/15, 1/16, 1/17, 1/18, 1/19, 1/20, 1/21, 1/22] ? localprec(100); a = Pi; ? asympnum(n->-log(1-1/n^a),,a) \\ better ! %4 = [0, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12] @eprog \synt{asympnum}{void *E, GEN (*u)(void *,GEN,long), long muli, GEN alpha, long prec}, where \kbd{u(E, n, prec)} must return $u(n)$ in precision \kbd{prec}. Also available is \fun{GEN}{asympnum0}{GEN u, long muli, GEN alpha, long prec}, where $u$ must be a vector of sufficient length as above. \subsec{contfraceval$(\var{CF},t,\{\var{lim}=-1\})$}\kbdsidx{contfraceval}\label{se:contfraceval} Given a continued fraction \kbd{CF} output by \kbd{contfracinit}, evaluate the first \kbd{lim} terms of the continued fraction at \kbd{t} (all terms if \kbd{lim} is negative or omitted; if positive, \kbd{lim} must be less than or equal to the length of \kbd{CF}. The library syntax is \fun{GEN}{contfraceval}{GEN CF, GEN t, long lim}. \subsec{contfracinit$(M,\{\var{lim} = -1\})$}\kbdsidx{contfracinit}\label{se:contfracinit} Given $M$ representing the power series $S=\sum_{n\ge0} M[n+1]z^n$, transform it into a continued fraction; restrict to $n\leq \kbd{lim}$ if latter is non-negative. $M$ can be a vector, a power series, a polynomial, or a rational function. The result is a 2-component vector $[A,B]$ such that $S = M[1] / (1+A[1]z+B[1]z^2/(1+A[2]z+B[2]z^2/(1+...1/(1+A[lim/2]z))))$. Does not work if any coefficient of $M$ vanishes, nor for series for which certain partial denominators vanish. The library syntax is \fun{GEN}{contfracinit}{GEN M, long lim}. \subsec{derivnum$(X=a,\var{expr},\{\var{ind}=1\})$}\kbdsidx{derivnum}\label{se:derivnum} Numerical derivation of \var{expr} with respect to $X$ at $X=a$. The order of derivation is 1 by default. \bprog ? derivnum(x=0, sin(exp(x))) - cos(1) %1 = 0.E-38 @eprog A clumsier approach, which would not work in library mode, is \bprog ? f(x) = sin(exp(x)) ? f'(0) - cos(1) %2 = 0.E-38 @eprog \item When $a$ is a numerical type (integer, rational number, real number or \typ{COMPLEX} of such), performs numerical derivation. \item When $a$ is a (polynomial, rational function or) power series, compute \kbd{derivnum(t=a,f)} as $f'(a) = (f(a))'/a'$: \bprog ? derivnum(x = 1 + t, sqrt(x)) %1 = 1/2 - 1/4*t + 3/16*t^2 - 5/32*t^3 + ... + O(t^16) ? derivnum(x = 1/(1 + t), sqrt(x)) %2 = 1/2 + 1/4*t - 1/16*t^2 + 1/32*t^3 + ... + O(t^16) ? derivnum(x = 1 + t + O(t^17), sqrt(x)) %3 = 1/2 - 1/4*t + 3/16*t^2 - 5/32*t^3 + ... + O(t^16) @eprog If the parameter \var{ind} is present, it can be \item a non-negative integer $m$, in which case we return $f^{(m)}(x)$; \item or a vector of orders, in which case we return the vector of derivatives. \bprog ? derivnum(x = 0, exp(sin(x)), 16) \\ 16-th derivative %1 = -52635599.000000000000000000000000000000 ? round( derivnum(x = 0, exp(sin(x)), [0..13]) ) \\ 0-13-th derivatives %2 = [1, 1, 1, 0, -3, -8, -3, 56, 217, 64, -2951, -12672, 5973, 309376] @eprog \synt{derivfunk}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN ind, long prec}. Also available is \fun{GEN}{derivfun}{void *E, GEN (*eval)(void *, GEN), GEN a, long prec}. If $a$ is a numerical type (\typ{INT}, \typ{FRAC}, \typ{REAL} or \typ{COMPLEX} of such, we have \fun{GEN}{derivnumk}{void *E, GEN (*eval)(void *, GEN, long), GEN a, GEN ind, long prec} and \fun{GEN}{derivnum}{void *E, GEN (*eval)(void *, GEN, long prec), GEN a, long prec} \subsec{intcirc$(X=a,R,\var{expr},\{\var{tab}\})$}\kbdsidx{intcirc}\label{se:intcirc} Numerical integration of $(2i\pi)^{-1}\var{expr}$ with respect to $X$ on the circle $|X-a| = R$. In other words, when \var{expr} is a meromorphic function, sum of the residues in the corresponding disk; \var{tab} is as in \kbd{intnum}, except that if computed with \kbd{intnuminit} it should be with the endpoints \kbd{[-1, 1]}. \bprog ? \p105 ? intcirc(s=1, 0.5, zeta(s)) - 1 time = 496 ms. %1 = 1.2883911040127271720 E-101 + 0.E-118*I @eprog \synt{intcirc}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN R,GEN tab, long prec}. \subsec{intfuncinit$(t=a,b,f,\{m=0\})$}\kbdsidx{intfuncinit}\label{se:intfuncinit} Initialize tables for use with integral transforms (such as Fourier, Laplace or Mellin transforms) in order to compute $$ \int_a^b f(t) k(t,z) \, dt $$ for some kernel $k(t,z)$. The endpoints $a$ and $b$ are coded as in \kbd{intnum}, $f$ is the function to which the integral transform is to be applied and the non-negative integer $m$ is as in \kbd{intnum}: multiply the number of sampling points roughly by $2^m$, hopefully increasing the accuracy. This function is particularly useful when the function $f$ is hard to compute, such as a gamma product. \misctitle{Limitation} the endpoints $a$ and $b$ must be at infinity, with the same asymptotic behavior. Oscillating types are not supported. This is easily overcome by integrating vectors of functions, see example below. \misctitle{Examples} \item numerical Fourier transform $$F(z) = \int_{-\infty}^{+\infty} f(t)e^{-2i\pi z t}\, dt. $$ First the easy case, assume that $f$ decrease exponentially: \bprog f(t) = exp(-t^2); A = [-oo,1]; B = [+oo,1]; \p200 T = intfuncinit(t = A,B , f(t)); F(z) = { my(a = -2*I*Pi*z); intnum(t = A,B, exp(a*t), T); } ? F(1) - sqrt(Pi)*exp(-Pi^2) %1 = -1.3... E-212 @eprog\noindent Now the harder case, $f$ decrease slowly: we must specify the oscillating behavior. Thus, we cannot precompute usefully since everything depends on the point we evaluate at: \bprog f(t) = 1 / (1+ abs(t)); \p200 \\ Fourier cosine transform FC(z) = { my(a = 2*Pi*z); intnum(t = [-oo, a*I], [+oo, a*I], cos(a*t)*f(t)); } FC(1) @eprog \item Fourier coefficients: we must integrate over a period, but \kbd{intfuncinit} does not support finite endpoints. The solution is to integrate a vector of functions ! \bprog FourierSin(f, T, k) = \\ first k sine Fourier coeffs { my (w = 2*Pi/T); my (v = vector(k+1)); intnum(t = -T/2, T/2, my (z = exp(I*w*t)); v[1] = z; for (j = 2, k, v[j] = v[j-1]*z); f(t) * imag(v)) * 2/T; } FourierSin(t->sin(2*t), 2*Pi, 10) @eprog\noindent The same technique can be used instead of \kbd{intfuncinit} to integrate $f(t) k(t,z)$ whenever the list of $z$-values is known beforehand. Note that the above code includes an unrelated optimization: the $\sin(j w t)$ are computed as imaginary parts of $\exp(i j w t)$ and the latter by successive multiplications. \item numerical Mellin inversion $$F(z) = (2i\pi)^{-1} \int_{c -i\infty}^{c+i\infty} f(s)z^{-s}\, ds = (2\pi)^{-1} \int_{-\infty}^{+\infty} f(c + i t)e^{-\log z(c + it)}\, dt. $$ We take $c = 2$ in the program below: \bprog f(s) = gamma(s)^3; \\ f(c+it) decrease as exp(-3Pi|t|/2) c = 2; \\ arbitrary A = [-oo,3*Pi/2]; B = [+oo,3*Pi/2]; T = intfuncinit(t=A,B, f(c + I*t)); F(z) = { my (a = -log(z)); intnum(t=A,B, exp(a*I*t), T)*exp(a*c) / (2*Pi); } @eprog \synt{intfuncinit}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b,long m, long prec}. \subsec{intnum$(X=a,b,\var{expr},\{\var{tab}\})$}\kbdsidx{intnum}\label{se:intnum} Numerical integration of \var{expr} on $]a,b[$ with respect to $X$, using the double-exponential method, and thus $O(D\log D)$ evaluation of the integrand in precision $D$. The integrand may have values belonging to a vector space over the real numbers; in particular, it can be complex-valued or vector-valued. But it is assumed that the function is regular on $]a,b[$. If the endpoints $a$ and $b$ are finite and the function is regular there, the situation is simple: \bprog ? intnum(x = 0,1, x^2) %1 = 0.3333333333333333333333333333 ? intnum(x = 0,Pi/2, [cos(x), sin(x)]) %2 = [1.000000000000000000000000000, 1.000000000000000000000000000] @eprog\noindent An endpoint equal to $\pm\infty$ is coded as \kbd{+oo} or \kbd{-oo}, as expected: \bprog ? intnum(x = 1,+oo, 1/x^2) %3 = 1.000000000000000000000000000 @eprog\noindent In basic usage, it is assumed that the function does not decrease exponentially fast at infinity: \bprog ? intnum(x=0,+oo, exp(-x)) *** at top-level: intnum(x=0,+oo,exp(- *** ^-------------------- *** exp: overflow in expo(). @eprog\noindent We shall see in a moment how to avoid that last problem, after describing the last \emph{optional} argument \var{tab}. \misctitle{The \var{tab} argument} The routine uses weights $w_i$, which are mostly independent of the function being integrated, evaluated at many sampling points $x_i$ and approximates the integral by $\sum w_i f(x_i)$. If \var{tab} is \item a non-negative integer $m$, we multiply the number of sampling points by $2^m$, hopefully increasing accuracy. Note that the running time increases roughly by a factor $2^m$. One may try consecutive values of $m$ until they give the same value up to an accepted error. \item a set of integration tables containing precomputed $x_i$ and $w_i$ as output by \tet{intnuminit}. This is useful if several integrations of the same type are performed (on the same kind of interval and functions, for a given accuracy): we skip a precomputation of $O(D\log D)$ elementary functions in accuracy $D$, whose running time has the same order of magnitude as the evaluation of the integrand. This is in particular useful for multivariate integrals. \misctitle{Specifying the behavior at endpoints} This is done as follows. An endpoint $a$ is either given as such (a scalar, real or complex, \kbd{oo} or \kbd{-oo} for $\pm\infty$), or as a two component vector $[a,\alpha]$, to indicate the behavior of the integrand in a neighborhood of $a$. If $a$ is finite, the code $[a,\alpha]$ means the function has a singularity of the form $(x-a)^{\alpha}$, up to logarithms. (If $\alpha \ge 0$, we only assume the function is regular, which is the default assumption.) If a wrong singularity exponent is used, the result will lose decimals: \bprog ? c = -9/10; ? intnum(x=0, 1, x^c) \\@com assume $x^{-9/10}$ is regular at 0 %1 = 9.9999839078827082322596783301939063944 ? intnum(x=[0,c], 1, x^c) \\@com no, it's not %2 = 10.000000000000000000000000000000000000 ? intnum(x=[0,c/2], 1, x^c) \\@com using a wrong exponent is bad %3 = 9.9999999997122749095442279375719919769 @eprog If $a$ is $\pm\infty$, which is coded as \kbd{+oo} or \kbd{-oo}, the situation is more complicated, and $[\pm\kbd{oo},\alpha]$ means: \item $\alpha=0$ (or no $\alpha$ at all, i.e. simply $\pm\kbd{oo}$) assumes that the integrand tends to zero moderately quickly, at least as $O(x^{-2})$ but not exponentially fast. \item $\alpha>0$ assumes that the function tends to zero exponentially fast approximately as $\exp(-\alpha x)$. This includes oscillating but quickly decreasing functions such as $\exp(-x)\sin(x)$. \bprog ? intnum(x=0, +oo, exp(-2*x)) *** at top-level: intnum(x=0,+oo,exp(- *** ^-------------------- *** exp: exponent (expo) overflow ? intnum(x=0, [+oo, 2], exp(-2*x)) \\@com OK! %1 = 0.50000000000000000000000000000000000000 ? intnum(x=0, [+oo, 3], exp(-2*x)) \\@com imprecise exponent, still OK ! %2 = 0.50000000000000000000000000000000000000 ? intnum(x=0, [+oo, 10], exp(-2*x)) \\@com wrong exponent $\Rightarrow$ disaster %3 = 0.49999999999952372962457451698256707393 @eprog\noindent As the last exemple shows, the exponential decrease rate \emph{must} be indicated to avoid overflow, but the method is robust enough for a rough guess to be acceptable. \item $\alpha<-1$ assumes that the function tends to $0$ slowly, like $x^{\alpha}$. Here the algorithm is less robust and it is essential to give a sharp $\alpha$, unless $\alpha \le -2$ in which case we use the default algorithm as if $\alpha$ were missing (or equal to $0$). \bprog ? intnum(x=1, +oo, x^(-3/2)) \\ default %1 = 1.9999999999999999999999999999646391207 ? intnum(x=1, [+oo,-3/2], x^(-3/2)) \\ precise decrease rate %2 = 2.0000000000000000000000000000000000000 ? intnum(x=1, [+oo,-11/10], x^(-3/2)) \\ worse than default %3 = 2.0000000000000000000000000089298011973 @eprog \smallskip The last two codes are reserved for oscillating functions. Let $k > 0$ real, and $g(x)$ a non-oscillating function tending slowly to $0$ (e.g. like a negative power of $x$), then \item $\alpha=k * I$ assumes that the function behaves like $\cos(kx)g(x)$. \item $\alpha=-k* I$ assumes that the function behaves like $\sin(kx)g(x)$. \noindent Here it is critical to give the exact value of $k$. If the oscillating part is not a pure sine or cosine, one must expand it into a Fourier series, use the above codings, and sum the resulting contributions. Otherwise you will get nonsense. Note that $\cos(kx)$, and similarly $\sin(kx)$, means that very function, and not a translated version such as $\cos(kx+a)$. \misctitle{Note} If $f(x)=\cos(kx)g(x)$ where $g(x)$ tends to zero exponentially fast as $\exp(-\alpha x)$, it is up to the user to choose between $[\pm\kbd{oo},\alpha]$ and $[\pm\kbd{oo},k* I]$, but a good rule of thumb is that if the oscillations are weaker than the exponential decrease, choose $[\pm\kbd{oo},\alpha]$, otherwise choose $[\pm\kbd{oo},k*I]$, although the latter can reasonably be used in all cases, while the former cannot. To take a specific example, in most inverse Mellin transforms, the integrand is a product of an exponentially decreasing and an oscillating factor. If we choose the oscillating type of integral we perhaps obtain the best results, at the expense of having to recompute our functions for a different value of the variable $z$ giving the transform, preventing us to use a function such as \kbd{intfuncinit}. On the other hand using the exponential type of integral, we obtain less accurate results, but we skip expensive recomputations. See \kbd{intfuncinit} for more explanations. \misctitle{Power series limits} The limits $a$ and $b$ can be power series of non-negative valuation, giving a power series expansion for the integral -- provided it exists. \bprog ? intnum(t=0,X + O(X^3), exp(t)) %4 = 1.000...*X - 0.5000...*X^2 + O(X^3) ? bestappr( intnum(t=0,X + O(X^17), exp(t)) )- exp(X) + 1 %5 = O(X^17) @eprog\noindent The valuation of the limit cannot be negative since $\int_0^{1/X}(1+t^2)^{-1}\, dt = \pi/2 - \kbd{sign}(X)+O(X^2)$. Polynomials and rational functions are also allowed and converted to power series using current \kbd{seriesprecision}: \bprog ? bestappr( intnum(t=1,1+X, 1/t) ) %6 = X - 1/2*X^2 + 1/3*X^3 - 1/4*X^4 + [...] + 1/15*X^15 + O(X^16) @eprog\noindent The function does not work if the integral is singular with the constant coefficient of the series as limit: \bprog ? intnum(t=X^2+O(X^4),1, 1/sqrt(t)) %8 = 2.000... - 6.236608109630992528 E28*X^2 + O(X^4) @eprog\noindent however you can use \bprog ? intnum(t=[X^2+O(X^4),-1/2],1, 1/sqrt(t)) %10 = 2.000000000000000000000000000-2.000000000000000000000000000*X^2+O(X^4) @eprog\noindent whis is translated internally to \bprog ? intnum(t=[0,-1/2],1, 1/sqrt(t))-intnum(t=[0,-1/2],X^2+O(X^4), 1/sqrt(t)) @eprog\noindent For this form the argument \var{tab} can be used only as an integer, not a table precomputed by \kbd{intnuminit}. \smallskip We shall now see many examples to get a feeling for what the various parameters achieve. All examples below assume precision is set to $115$ decimal digits. We first type \bprog ? \p 115 @eprog \misctitle{Apparent singularities} In many cases, apparent singularities can be ignored. For instance, if $f(x) = 1 /(\exp(x)-1) - \exp(-x)/x$, then $\int_0^\infty f(x)\,dx=\gamma$, Euler's constant \kbd{Euler}. But \bprog ? f(x) = 1/(exp(x)-1) - exp(-x)/x ? intnum(x = 0, [oo,1], f(x)) - Euler %1 = 0.E-115 @eprog\noindent But close to $0$ the function $f$ is computed with an enormous loss of accuracy, and we are in fact lucky that it get multiplied by weights which are sufficiently close to $0$ to hide this: \bprog ? f(1e-200) %2 = -3.885337784451458142 E84 @eprog A more robust solution is to define the function differently near special points, e.g. by a Taylor expansion \bprog ? F = truncate( f(t + O(t^10)) ); \\@com expansion around t = 0 ? poldegree(F) %4 = 7 ? g(x) = if (x > 1e-18, f(x), subst(F,t,x)); \\@com note that $7 \cdot 18 > 105$ ? intnum(x = 0, [oo,1], g(x)) - Euler %2 = 0.E-115 @eprog\noindent It is up to the user to determine constants such as the $10^{-18}$ and $10$ used above. \misctitle{True singularities} With true singularities the result is worse. For instance \bprog ? intnum(x = 0, 1, x^(-1/2)) - 2 %1 = -3.5... E-68 \\@com only $68$ correct decimals ? intnum(x = [0,-1/2], 1, x^(-1/2)) - 2 %2 = 0.E-114 \\@com better @eprog \misctitle{Oscillating functions} \bprog ? intnum(x = 0, oo, sin(x) / x) - Pi/2 %1 = 16.19.. \\@com nonsense ? intnum(x = 0, [oo,1], sin(x)/x) - Pi/2 %2 = -0.006.. \\@com bad ? intnum(x = 0, [oo,-I], sin(x)/x) - Pi/2 %3 = 0.E-115 \\@com perfect ? intnum(x = 0, [oo,-I], sin(2*x)/x) - Pi/2 \\@com oops, wrong $k$ %4 = 0.06... ? intnum(x = 0, [oo,-2*I], sin(2*x)/x) - Pi/2 %5 = 0.E-115 \\@com perfect ? intnum(x = 0, [oo,-I], sin(x)^3/x) - Pi/4 %6 = -0.0008... \\@com bad ? sin(x)^3 - (3*sin(x)-sin(3*x))/4 %7 = O(x^17) @eprog\noindent We may use the above linearization and compute two oscillating integrals with endpoints \kbd{[oo, -I]} and \kbd{[oo, -3*I]} respectively, or notice the obvious change of variable, and reduce to the single integral ${1\over 2}\int_0^\infty \sin(x)/x\,dx$. We finish with some more complicated examples: \bprog ? intnum(x = 0, [oo,-I], (1-cos(x))/x^2) - Pi/2 %1 = -0.0003... \\@com bad ? intnum(x = 0, 1, (1-cos(x))/x^2) \ + intnum(x = 1, oo, 1/x^2) - intnum(x = 1, [oo,I], cos(x)/x^2) - Pi/2 %2 = 0.E-115 \\@com perfect ? intnum(x = 0, [oo, 1], sin(x)^3*exp(-x)) - 0.3 %3 = -7.34... E-55 \\@com bad ? intnum(x = 0, [oo,-I], sin(x)^3*exp(-x)) - 0.3 %4 = 8.9... E-103 \\@com better. Try higher $m$ ? tab = intnuminit(0,[oo,-I], 1); \\@com double number of sampling points ? intnum(x = 0, oo, sin(x)^3*exp(-x), tab) - 0.3 %6 = 0.E-115 \\@com perfect @eprog \misctitle{Warning} Like \tet{sumalt}, \kbd{intnum} often assigns a reasonable value to diverging integrals. Use these values at your own risk! For example: \bprog ? intnum(x = 0, [oo, -I], x^2*sin(x)) %1 = -2.0000000000... @eprog\noindent Note the formula $$ \int_0^\infty \sin(x)/x^s\,dx = \cos(\pi s/2) \Gamma(1-s)\;, $$ a priori valid only for $0 < \Re(s) < 2$, but the right hand side provides an analytic continuation which may be evaluated at $s = -2$\dots \misctitle{Multivariate integration} Using successive univariate integration with respect to different formal parameters, it is immediate to do naive multivariate integration. But it is important to use a suitable \kbd{intnuminit} to precompute data for the \emph{internal} integrations at least! For example, to compute the double integral on the unit disc $x^2+y^2\le1$ of the function $x^2+y^2$, we can write \bprog ? tab = intnuminit(-1,1); ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab),tab) - Pi/2 %2 = -7.1... E-115 \\@com OK @eprog\noindent The first \var{tab} is essential, the second optional. Compare: \bprog ? tab = intnuminit(-1,1); time = 4 ms. ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2)); time = 3,092 ms. \\@com slow ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab), tab); time = 252 ms. \\@com faster ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab)); time = 261 ms. \\@com the \emph{internal} integral matters most @eprog \synt{intnum}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b,GEN tab, long prec}, where an omitted \var{tab} is coded as \kbd{NULL}. \subsec{intnumgauss$(X=a,b,\var{expr},\{\var{tab}\})$}\kbdsidx{intnumgauss}\label{se:intnumgauss} Numerical integration of \var{expr} on the compact interval $[a,b]$ with respect to $X$ using Gauss-Legendre quadrature; \kbd{tab} is either omitted or precomputed with \kbd{intnumgaussinit}. As a convenience, it can be an integer $n$ in which case we call \kbd{intnumgaussinit}$(n)$ and use $n$-point quadrature. \bprog ? test(n, b = 1) = T=intnumgaussinit(n);\ intnumgauss(x=-b,b, 1/(1+x^2),T) - 2*atan(b); ? test(0) \\ default %1 = -9.490148553624725335 E-22 ? test(40) %2 = -6.186629001816965717 E-31 ? test(50) %3 = -1.1754943508222875080 E-38 ? test(50, 2) \\ double interval length %4 = -4.891779568527713636 E-21 ? test(90, 2) \\ n must almost be doubled as well! %5 = -9.403954806578300064 E-38 @eprog\noindent On the other hand, we recommend to split the integral and change variables rather than increasing $n$ too much: \bprog ? f(x) = 1/(1+x^2); ? b = 100; ? intnumgauss(x=0,1, f(x)) + intnumgauss(x=1,1/b, f(1/x)*(-1/x^2)) - atan(b) %3 = -1.0579449157400587572 E-37 @eprog The library syntax is \fun{GEN}{intnumgauss0}{GEN X, GEN b, GEN expr, GEN tab = NULL, long prec}. \subsec{intnumgaussinit$(\{n\})$}\kbdsidx{intnumgaussinit}\label{se:intnumgaussinit} Initialize tables for $n$-point Gauss-Legendre integration of a smooth function $f$ lon a compact interval $[a,b]$ at current \kbd{realprecision}. If $n$ is omitted, make a default choice $n \approx \kbd{realprecision}$, suitable for analytic functions on $[-1,1]$. The error is bounded by $$ \dfrac{(b-a)^{2n+1} (n!)^4}{(2n+1)[(2n)!]^3} f^{(2n)} (\xi) , \qquad a < \xi < b $$ so, if the interval length increases, $n$ should be increased as well. \bprog ? T = intnumgaussinit(); ? intnumgauss(t=-1,1,exp(t), T) - exp(1)+exp(-1) %1 = -5.877471754111437540 E-39 ? intnumgauss(t=-10,10,exp(t), T) - exp(10)+exp(-10) %2 = -8.358367809712546836 E-35 ? intnumgauss(t=-1,1,1/(1+t^2), T) - Pi/2 %3 = -9.490148553624725335 E-22 ? T = intnumgaussinit(50); ? intnumgauss(t=-1,1,1/(1+t^2), T) - Pi/2 %5 = -1.1754943508222875080 E-38 ? intnumgauss(t=-5,5,1/(1+t^2), T) - 2*atan(5) %6 = -1.2[...]E-8 @eprog On the other hand, we recommend to split the integral and change variables rather than increasing $n$ too much, see \tet{intnumgauss}. The library syntax is \fun{GEN}{intnumgaussinit}{long n, long prec}. \subsec{intnuminit$(a,b,\{m=0\})$}\kbdsidx{intnuminit}\label{se:intnuminit} Initialize tables for integration from $a$ to $b$, where $a$ and $b$ are coded as in \kbd{intnum}. Only the compactness, the possible existence of singularities, the speed of decrease or the oscillations at infinity are taken into account, and not the values. For instance {\tt intnuminit(-1,1)} is equivalent to {\tt intnuminit(0,Pi)}, and {\tt intnuminit([0,-1/2],oo)} is equivalent to {\tt intnuminit([-1,-1/2], -oo)}; on the other hand, the order matters and {\tt intnuminit([0,-1/2], [1,-1/3])} is \emph{not} equivalent to {\tt intnuminit([0,-1/3], [1,-1/2])} ! If $m$ is present, it must be non-negative and we multiply the default number of sampling points by $2^m$ (increasing the running time by a similar factor). The result is technical and liable to change in the future, but we document it here for completeness. Let $x=\phi(t)$, $t\in ]-\infty,\infty[$ be an internally chosen change of variable, achieving double exponential decrease of the integrand at infinity. The integrator \kbd{intnum} will compute $$ h \sum_{|n| < N} \phi'(nh) F(\phi(nh)) $$ for some integration step $h$ and truncation parameter $N$. In basic use, let \bprog [h, x0, w0, xp, wp, xm, wm] = intnuminit(a,b); @eprog \item $h$ is the integration step \item $x_0 = \phi(0)$ and $w_0 = \phi'(0)$, \item \var{xp} contains the $\phi(nh)$, $0 < n < N$, \item \var{xm} contains the $\phi(nh)$, $0 < -n < N$, or is empty. \item \var{wp} contains the $\phi'(nh)$, $0 < n < N$, \item \var{wm} contains the $\phi'(nh)$, $0 < -n < N$, or is empty. The arrays \var{xm} and \var{wm} are left empty when $\phi$ is an odd function. In complicated situations when non-default behavior is specified at end points, \kbd{intnuminit} may return up to $3$ such arrays, corresponding to a splitting of up to $3$ integrals of basic type. If the functions to be integrated later are of the form $F = f(t) k(t,z)$ for some kernel $k$ (e.g. Fourier, Laplace, Mellin, \dots), it is useful to also precompute the values of $f(\phi(nh))$, which is accomplished by \tet{intfuncinit}. The hard part is to determine the behavior of $F$ at endpoints, depending on $z$. The library syntax is \fun{GEN}{intnuminit}{GEN a, GEN b, long m, long prec}. \subsec{intnumromb$(X=a,b,\var{expr},\{\fl=0\})$}\kbdsidx{intnumromb}\label{se:intnumromb} Numerical integration of \var{expr} (smooth in $]a,b[$), with respect to $X$. Suitable for low accuracy; if \var{expr} is very regular (e.g. analytic in a large region) and high accuracy is desired, try \tet{intnum} first. Set $\fl=0$ (or omit it altogether) when $a$ and $b$ are not too large, the function is smooth, and can be evaluated exactly everywhere on the interval $[a,b]$. If $\fl=1$, uses a general driver routine for doing numerical integration, making no particular assumption (slow). $\fl=2$ is tailored for being used when $a$ or $b$ are infinite using the change of variable $t = 1/X$. One \emph{must} have $ab>0$, and in fact if for example $b=+\infty$, then it is preferable to have $a$ as large as possible, at least $a\ge1$. If $\fl=3$, the function is allowed to be undefined at $a$ (but right continuous) or $b$ (left continuous), for example the function $\sin(x)/x$ between $x=0$ and $1$. The user should not require too much accuracy: \tet{realprecision} about 30 decimal digits (\tet{realbitprecision} about 100 bits) is OK, but not much more. In addition, analytical cleanup of the integral must have been done: there must be no singularities in the interval or at the boundaries. In practice this can be accomplished with a change of variable. Furthermore, for improper integrals, where one or both of the limits of integration are plus or minus infinity, the function must decrease sufficiently rapidly at infinity, which can often be accomplished through integration by parts. Finally, the function to be integrated should not be very small (compared to the current precision) on the entire interval. This can of course be accomplished by just multiplying by an appropriate constant. Note that \idx{infinity} can be represented with essentially no loss of accuracy by an appropriate huge number. However beware of real underflow when dealing with rapidly decreasing functions. For example, in order to compute the $\int_0^\infty e^{-x^2}\,dx$ to 28 decimal digits, then one can set infinity equal to 10 for example, and certainly not to \kbd{1e1000}. \synt{intnumromb_bitprec}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN b, long flag, long bitprec}, where $\kbd{eval}(x, E)$ returns the value of the function at $x$. You may store any additional information required by \kbd{eval} in $E$, or set it to \kbd{NULL}. The historical variant \synt{intnumromb}{\dots, long prec}, where \kbd{prec} is expressed in words, not bits, is obsolete and should no longer be used. \subsec{laurentseries$(f, \{M = \var{seriesprecision}\}, \{x='x\})$}\kbdsidx{laurentseries}\label{se:laurentseries} Expand $f$ as a Laurent series around $x = 0$ to order $M$. This function computes $f(x + O(x^n))$ until $n$ is large enough: it must be possible to evaluate $f$ on a power series with $0$ constant term. \bprog ? laurentseries(t->sin(t)/(1-cos(t)), 5) %1 = 2*x^-1 - 1/6*x - 1/360*x^3 - 1/15120*x^5 + O(x^6) ? laurentseries(log) *** at top-level: laurentseries(log) *** ^------------------ *** in function laurentseries: log *** ^--- *** log: domain error in log: series valuation != 0 @eprog Note that individual Laurent coefficients of order $\leq M$ can be retrieved from $s = \kbd{laurentseries}(f,M)$ via \kbd{polcoeff(s,i)} for any $i \leq M$. The series $s$ may occasionally be more precise that the required $O(x^{M+1})$. With respect to successive calls to \tet{derivnum}, \kbd{laurentseries} is both faster and more precise: \bprog ? laurentseries(t->log(3+t),1) %1 = 1.0986122886681096913952452369225257047 + 1/3*x - 1/18*x^2 + O(x^3) ? derivnum(t=0,log(3+t),1) %2 = 0.33333333333333333333333333333333333333 ? derivnum(t=0,log(3+t),2) %3 = -0.11111111111111111111111111111111111111 ? f = x->sin(exp(x)); ? polcoeff(laurentseries(x->f(x+2), 1), 1) %5 = 3.3129294231043339804683687620360224365 ? exp(2) * cos(exp(2)); %6 = 3.3129294231043339804683687620360224365 ? derivnum(x = 2, f(x)) %7 = 3.3129294231043339804683687620360224364 \\ 1 ulp off ? default(realprecision,115); ? for(i=1,10^4, laurentseries(x->f(x+2),1)) time = 279 ms. ? for(i=1,10^4, derivnum(x=2,f(x))) \\ ... and slower time = 1,134 ms. @eprog \synt{laurentseries}{void *E, GEN (*f)(void*,GEN,long), long M, long v, long prec}. \subsec{limitnum$(\var{expr},\{k = 20\},\{\var{alpha}=1\})$}\kbdsidx{limitnum}\label{se:limitnum} Lagrange-Zagier numerical extrapolation of \var{expr}, corresponding to a sequence $u_n$, either given by a closure \kbd{n->u(n)} or by a vector of values I.e., assuming that $u_n$ tends to a finite limit $\ell$, try to determine $\ell$. This routine is purely numerical and heuristic, thus may or may not work on your examples; $k$ is ignored if $u$ is given by a vector, and otherwise is a multiplier such that we extrapolate from $u(kn)$. Assume that $u_n$ has an asymptotic expansion in $n^{-\alpha}$ : $$u_n = \ell + \sum_{i\geq 1} a_i n^{-i\alpha}$$ for some $a_i$. \bprog ? limitnum(n -> n*sin(1/n)) %1 = 1.0000000000000000000000000000000000000 ? limitnum(n -> (1+1/n)^n) - exp(1) %2 = 0.E-37 ? limitnum(n -> 2^(4*n+1)*(n!)^4 / (2*n)! /(2*n+1)! ) %3 = 3.1415926535897932384626433832795028842 ? Pi %4 = 3.1415926535897932384626433832795028842 @eprog\noindent If $u_n$ is given by a vector, it must be long enough for the extrapolation to make sense: at least $k$ times the current \kbd{realprecision}. The preferred format is thus a closure, although it becomes inconvenient when $u_n$ cannot be directly computed in time polynomial in $\log n$, for instance if it is defined as a sum or by induction. In that case, passing a vector of values is the best option. It usually pays off to interpolate $u(kn)$ for some $k > 1$: \bprog ? limitnum(vector(10,n,(1+1/n)^n)) *** ^-------------------- *** limitnum: non-existent component in limitnum: index < 20 \\ at this accuracy, we must have at least 20 values ? limitnum(vector(20,n,(1+1/n)^n)) - exp(1) %5 = -2.05... E-20 ? limitnum(vector(20,n, m=10*n;(1+1/m)^m)) - exp(1) \\ better accuracy %6 = 0.E-37 ? v = vector(20); s = 0; ? for(i=1,#v, s += 1/i; v[i]= s - log(i)); ? limitnum(v) - Euler %9 = -1.6... E-19 ? V = vector(200); s = 0; ? for(i=1,#V, s += 1/i; V[i]= s); ? v = vector(#V \ 10, i, V[10*i] - log(10*i)); ? limitnum(v) - Euler %13 = 6.43... E-29 @eprog \synt{limitnum}{void *E, GEN (*u)(void *,GEN,long), long muli, GEN alpha, long prec}, where \kbd{u(E, n, prec)} must return $u(n)$ in precision \kbd{prec}. Also available is \fun{GEN}{limitnum0}{GEN u, long muli, GEN alpha, long prec}, where $u$ must be a vector of sufficient length as above. \subsec{prod$(X=a,b,\var{expr},\{x=1\})$}\kbdsidx{prod}\label{se:prod} Product of expression \var{expr}, initialized at $x$, the formal parameter $X$ going from $a$ to $b$. As for \kbd{sum}, the main purpose of the initialization parameter $x$ is to force the type of the operations being performed. For example if it is set equal to the integer 1, operations will start being done exactly. If it is set equal to the real $1.$, they will be done using real numbers having the default precision. If it is set equal to the power series $1+O(X^k)$ for a certain $k$, they will be done using power series of precision at most $k$. These are the three most common initializations. \noindent As an extreme example, compare \bprog ? prod(i=1, 100, 1 - X^i); \\@com this has degree $5050$ !! time = 128 ms. ? prod(i=1, 100, 1 - X^i, 1 + O(X^101)) time = 8 ms. %2 = 1 - X - X^2 + X^5 + X^7 - X^12 - X^15 + X^22 + X^26 - X^35 - X^40 + \ X^51 + X^57 - X^70 - X^77 + X^92 + X^100 + O(X^101) @eprog\noindent Of course, in this specific case, it is faster to use \tet{eta}, which is computed using Euler's formula. \bprog ? prod(i=1, 1000, 1 - X^i, 1 + O(X^1001)); time = 589 ms. ? \ps1000 seriesprecision = 1000 significant terms ? eta(X) - % time = 8ms. %4 = O(X^1001) @eprog \synt{produit}{GEN a, GEN b, char *expr, GEN x}. \subsec{prodeuler$(X=a,b,\var{expr})$}\kbdsidx{prodeuler}\label{se:prodeuler} Product of expression \var{expr}, initialized at 1. (i.e.~to a \emph{real} number equal to 1 to the current \kbd{realprecision}), the formal parameter $X$ ranging over the prime numbers between $a$ and $b$.\sidx{Euler product} \synt{prodeuler}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b, long prec}. \subsec{prodeulerrat$(F,\{s=1\},\{a=2\})$}\kbdsidx{prodeulerrat}\label{se:prodeulerrat} $\prod_{p\ge a, p prime}F(p^s)$, where $F$ is a rational function. \bprog ? prodeulerrat(1+1/q^3,1) %1 = 1.1815649490102569125693997341604542605 ? zeta(3)/zeta(6) %2 = 1.1815649490102569125693997341604542606 @eprog The library syntax is \fun{GEN}{prodeulerrat}{GEN F, GEN s = NULL, long a, long prec}. \subsec{prodinf$(X=a,\var{expr},\{\fl=0\})$}\kbdsidx{prodinf}\label{se:prodinf} \idx{infinite product} of expression \var{expr}, the formal parameter $X$ starting at $a$. The evaluation stops when the relative error of the expression minus 1 is less than the default precision. In particular, non-convergent products result in infinite loops. The expressions must always evaluate to an element of $\C$. If $\fl=1$, do the product of the ($1+\var{expr}$) instead. \synt{prodinf}{void *E, GEN (*eval)(void*,GEN), GEN a, long prec} ($\fl=0$), or \tet{prodinf1} with the same arguments ($\fl=1$). \subsec{prodnumrat$(F,a)$}\kbdsidx{prodnumrat}\label{se:prodnumrat} $\prod_{n\ge a}F(n)$, where $F-1$ is a rational function of degree less than or equal to $-2$. \bprog ? prodnumrat(1+1/x^2,1) %1 = 3.6760779103749777206956974920282606665 @eprog The library syntax is \fun{GEN}{prodnumrat}{GEN F, long a, long prec}. \subsec{solve$(X=a,b,\var{expr})$}\kbdsidx{solve}\label{se:solve} Find a real root of expression \var{expr} between $a$ and $b$, under the condition $\var{expr}(X=a) * \var{expr}(X=b) \le 0$. (You will get an error message \kbd{roots must be bracketed in solve} if this does not hold.) This routine uses Brent's method and can fail miserably if \var{expr} is not defined in the whole of $[a,b]$ (try \kbd{solve(x=1, 2, tan(x))}). \synt{zbrent}{void *E,GEN (*eval)(void*,GEN),GEN a,GEN b,long prec}. \subsec{solvestep$(X=a,b,\var{step},\var{expr},\{\fl=0\})$}\kbdsidx{solvestep}\label{se:solvestep} Find zeros of a continuous function in the real interval $[a,b]$ by naive interval splitting. This function is heuristic and may or may not find the intended zeros. Binary digits of \fl\ mean \item 1: return as soon as one zero is found, otherwise return all zeros found; \item 2: refine the splitting until at least one zero is found (may loop indefinitely if there are no zeros); \item 4: do a multiplicative search (we must have $a > 0$ and $\var{step} > 1$), otherwise an additive search; \var{step} is the multiplicative or additive step. \item 8: refine the splitting until at least one zero is very close to an integer. \bprog ? solvestep(X=0,10,1,sin(X^2),1) %1 = 1.7724538509055160272981674833411451828 ? solvestep(X=1,12,2,besselj(4,X),4) %2 = [7.588342434..., 11.064709488...] @eprog\noindent \synt{solvestep}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b, GEN step,long flag,long prec}. \subsec{sum$(X=a,b,\var{expr},\{x=0\})$}\kbdsidx{sum}\label{se:sum} Sum of expression \var{expr}, initialized at $x$, the formal parameter going from $a$ to $b$. As for \kbd{prod}, the initialization parameter $x$ may be given to force the type of the operations being performed. \noindent As an extreme example, compare \bprog ? sum(i=1, 10^4, 1/i); \\@com rational number: denominator has $4345$ digits. time = 236 ms. ? sum(i=1, 5000, 1/i, 0.) time = 8 ms. %2 = 9.787606036044382264178477904 @eprog % \syn{NO} \subsec{sumalt$(X=a,\var{expr},\{\fl=0\})$}\kbdsidx{sumalt}\label{se:sumalt} Numerical summation of the series \var{expr}, which should be an \idx{alternating series} $(-1)^k a_k$, the formal variable $X$ starting at $a$. Use an algorithm of Cohen, Villegas and Zagier (\emph{Experiment. Math.} {\bf 9} (2000), no.~1, 3--12). If $\fl=0$, assuming that the $a_k$ are the moments of a positive measure on $[0,1]$, the relative error is $O(3+\sqrt8)^{-n}$ after using $a_k$ for $k\leq n$. If \kbd{realprecision} is $p$, we thus set $n = \log(10)p/\log(3+\sqrt8)\approx 1.3 p$; besides the time needed to compute the $a_k$, $k\leq n$, the algorithm overhead is negligible: time $O(p^2)$ and space $O(p)$. If $\fl=1$, use a variant with more complicated polynomials, see \tet{polzagier}. If the $a_k$ are the moments of $w(x)dx$ where $w$ (or only $xw(x^2)$) is a smooth function extending analytically to the whole complex plane, convergence is in $O(14.4^{-n})$. If $xw(x^2)$ extends analytically to a smaller region, we still have exponential convergence, with worse constants. Usually faster when the computation of $a_k$ is expensive. If \kbd{realprecision} is $p$, we thus set $n = \log(10)p/\log(14.4)\approx 0.86 p$; besides the time needed to compute the $a_k$, $k\leq n$, the algorithm overhead is \emph{not} negligible: time $O(p^3)$ and space $O(p^2)$. Thus, even if the analytic conditions for rigorous use are met, this variant is only worthwile if the $a_k$ are hard to compute, at least $O(p^2)$ individually on average: otherwise we gain a small constant factor (1.5, say) in the number of needed $a_k$ at the expense of a large overhead. The conditions for rigorous use are hard to check but the routine is best used heuristically: even divergent alternating series can sometimes be summed by this method, as well as series which are not exactly alternating (see for example \secref{se:user_defined}). It should be used to try and guess the value of an infinite sum. (However, see the example at the end of \secref{se:userfundef}.) If the series already converges geometrically, \tet{suminf} is often a better choice: \bprog ? \p28 ? sumalt(i = 1, -(-1)^i / i) - log(2) time = 0 ms. %1 = -2.524354897 E-29 ? suminf(i = 1, -(-1)^i / i) \\@com Had to hit \kbd{C-C} *** at top-level: suminf(i=1,-(-1)^i/i) *** ^------ *** suminf: user interrupt after 10min, 20,100 ms. ? \p1000 ? sumalt(i = 1, -(-1)^i / i) - log(2) time = 90 ms. %2 = 4.459597722 E-1002 ? sumalt(i = 0, (-1)^i / i!) - exp(-1) time = 670 ms. %3 = -4.03698781490633483156497361352190615794353338591897830587 E-944 ? suminf(i = 0, (-1)^i / i!) - exp(-1) time = 110 ms. %4 = -8.39147638 E-1000 \\ @com faster and more accurate @eprog \synt{sumalt}{void *E, GEN (*eval)(void*,GEN),GEN a,long prec}. Also available is \tet{sumalt2} with the same arguments ($\fl = 1$). \subsec{sumdiv$(n,X,\var{expr})$}\kbdsidx{sumdiv}\label{se:sumdiv} Sum of expression \var{expr} over the positive divisors of $n$. This function is a trivial wrapper essentially equivalent to \bprog D = divisors(n); for (i = 1, #D, X = D[i]; eval(expr)) @eprog\noindent (except that \kbd{X} is lexically scoped to the \kbd{sumdiv} loop). If \var{expr} is a multiplicative function, use \tet{sumdivmult}. %\syn{NO} \subsec{sumdivmult$(n,d,\var{expr})$}\kbdsidx{sumdivmult}\label{se:sumdivmult} Sum of \emph{multiplicative} expression \var{expr} over the positive divisors $d$ of $n$. Assume that \var{expr} evaluates to $f(d)$ where $f$ is multiplicative: $f(1) = 1$ and $f(ab) = f(a)f(b)$ for coprime $a$ and $b$. %\syn{NO} \subsec{sumeulerrat$(F,\{s=1\},\{a=2\})$}\kbdsidx{sumeulerrat}\label{se:sumeulerrat} $\sum_{p\ge a, p prime}F(p^s)$, where $F$ is a rational function. \bprog ? sumeulerrat(1/q) %1 = 0.45224742004106549850654336483224793418 @eprog The library syntax is \fun{GEN}{sumeulerrat}{GEN F, GEN s = NULL, long a, long prec}. \subsec{suminf$(X=a,\var{expr})$}\kbdsidx{suminf}\label{se:suminf} \idx{infinite sum} of expression \var{expr}, the formal parameter $X$ starting at $a$. The evaluation stops when the relative error of the expression is less than the default precision for 3 consecutive evaluations. The expressions must always evaluate to a complex number. If the series converges slowly, make sure \kbd{realprecision} is low (even 28 digits may be too much). In this case, if the series is alternating or the terms have a constant sign, \tet{sumalt} and \tet{sumpos} should be used instead. \bprog ? \p28 ? suminf(i = 1, -(-1)^i / i) \\@com Had to hit \kbd{C-C} *** at top-level: suminf(i=1,-(-1)^i/i) *** ^------ *** suminf: user interrupt after 10min, 20,100 ms. ? sumalt(i = 1, -(-1)^i / i) - log(2) time = 0 ms. %1 = -2.524354897 E-29 @eprog \synt{suminf}{void *E, GEN (*eval)(void*,GEN), GEN a, long prec}. \subsec{sumnum$(n=a,f,\{\var{tab}\})$}\kbdsidx{sumnum}\label{se:sumnum} Numerical summation of $f(n)$ at high accuracy using Euler-MacLaurin, the variable $n$ taking values from $a$ to $+\infty$, where $f$ is assumed to have positive values and is a $C^\infty$ function; \kbd{a} must be an integer and \kbd{tab}, if given, is the output of \kbd{sumnuminit}. The latter precomputes abscissas and weights, speeding up the computation; it also allows to specify the behavior at infinity via \kbd{sumnuminit([+oo, asymp])}. \bprog ? \p500 ? z3 = zeta(3); ? sumpos(n = 1, n^-3) - z3 time = 2,332 ms. %2 = 2.438468843 E-501 ? sumnum(n = 1, n^-3) - z3 \\ here slower than sumpos time = 2,752 ms. %3 = 0.E-500 @eprog \misctitle{Complexity} The function $f$ will be evaluated at $O(D \log D)$ real arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. The routine is geared towards slowly decreasing functions: if $f$ decreases exponentially fast, then one of \kbd{suminf} or \kbd{sumpos} should be preferred. If $f$ satisfies the stronger hypotheses required for Monien summation, i.e. if $f(1/z)$ is holomorphic in a complex neighbourhood of $[0,1]$, then \tet{sumnummonien} will be faster since it only requires $O(D/\log D)$ evaluations: \bprog ? sumnummonien(n = 1, 1/n^3) - z3 time = 1,985 ms. %3 = 0.E-500 @eprog\noindent The \kbd{tab} argument precomputes technical data not depending on the expression being summed and valid for a given accuracy, speeding up immensely later calls: \bprog ? tab = sumnuminit(); time = 2,709 ms. ? sumnum(n = 1, 1/n^3, tab) - z3 \\ now much faster than sumpos time = 40 ms. %5 = 0.E-500 ? tabmon = sumnummonieninit(); \\ Monien summation allows precomputations too time = 1,781 ms. ? sumnummonien(n = 1, 1/n^3, tabmon) - z3 time = 2 ms. %7 = 0.E-500 @eprog\noindent The speedup due to precomputations becomes less impressive when the function $f$ is expensive to evaluate, though: \bprog ? sumnum(n = 1, lngamma(1+1/n)/n, tab); time = 14,180 ms. ? sumnummonien(n = 1, lngamma(1+1/n)/n, tabmon); \\ fewer evaluations time = 717 ms. @eprog \misctitle{Behaviour at infinity} By default, \kbd{sumnum} assumes that \var{expr} decreases slowly at infinity, but at least like $O(n^{-2})$. If the function decreases like $n^{\alpha}$ for some $-2 < \alpha < -1$, then it must be indicated via \bprog tab = sumnuminit([+oo, alpha]); /* alpha < 0 slow decrease */ @eprog\noindent otherwise loss of accuracy is expected. If the functions decreases quickly, like $\exp(-\alpha n)$ for some $\alpha > 0$, then it must be indicated via \bprog tab = sumnuminit([+oo, alpha]); /* alpha > 0 exponential decrease */ @eprog\noindent otherwise exponent overflow will occur. \bprog ? sumnum(n=1,2^-n) *** at top-level: sumnum(n=1,2^-n) *** ^---- *** _^_: overflow in expo(). ? tab = sumnuminit([+oo,log(2)]); sumnum(n=1,2^-n, tab) %1 = 1.000[...] @eprog As a shortcut, one can also input \bprog sumnum(n = [a, asymp], f) @eprog\noindent instead of \bprog tab = sumnuminit(asymp); sumnum(n = a, f, tab) @eprog \misctitle{Further examples} \bprog ? \p200 ? sumnum(n = 1, n^(-2)) - zeta(2) \\ accurate, fast time = 200 ms. %1 = -2.376364457868949779 E-212 ? sumpos(n = 1, n^(-2)) - zeta(2) \\ even faster time = 96 ms. %2 = 0.E-211 ? sumpos(n=1,n^(-4/3)) - zeta(4/3) \\ now much slower time = 13,045 ms. %3 = -9.980730723049589073 E-210 ? sumnum(n=1,n^(-4/3)) - zeta(4/3) \\ fast but inaccurate time = 365 ms. %4 = -9.85[...]E-85 ? sumnum(n=[1,-4/3],n^(-4/3)) - zeta(4/3) \\ with decrease rate, now accurate time = 416 ms. %5 = -4.134874156691972616 E-210 ? tab = sumnuminit([+oo,-4/3]); time = 196 ms. ? sumnum(n=1, n^(-4/3), tab) - zeta(4/3) \\ faster with precomputations time = 216 ms. %5 = -4.134874156691972616 E-210 ? sumnum(n=1,-log(n)*n^(-4/3), tab) - zeta'(4/3) time = 321 ms. %7 = 7.224147951921607329 E-210 @eprog Note that in the case of slow decrease ($\alpha < 0$), the exact decrease rate must be indicated, while in the case of exponential decrease, a rough value will do. In fact, for exponentially decreasing functions, \kbd{sumnum} is given for completeness and comparison purposes only: one of \kbd{suminf} or \kbd{sumpos} should always be preferred. \bprog ? sumnum(n=[1, 1], 2^-n) \\ pretend we decrease as exp(-n) time = 240 ms. %8 = 1.000[...] \\ perfect ? sumpos(n=1, 2^-n) %9 = 1.000[...] \\ perfect and instantaneous @eprog \misctitle{Beware cancellation} The function $f(n)$ is evaluated for huge values of $n$, so beware of cancellation in the evaluation: \bprog ? f(n) = 2 - 1/n - 2*n*log(1+1/n); \\ result is O(1/n^2) ? z = -2 + log(2*Pi) - Euler; ? sumnummonien(n=1, f(n)) - z time = 149 ms. %12 = 0.E-212 \\ perfect ? sumnum(n=1, f(n)) - z time = 116 ms. %13 = -948.216[...] \\ junk @eprog\noindent As \kbd{sumnum(n=1, print(n))} shows, we evaluate $f(n)$ for $n > 1e233$ and our implementation of $f$ suffers from massive cancellation since we are summing two terms of the order of $O(1)$ for a result in $O(1/n^2)$. You can either rewrite your sum so that individual terms are evaluated without cancellation or locally replace $f(n)$ by an accurate asymptotic expansion: \bprog ? F = truncate( f(1/x + O(x^30)) ); ? sumnum(n=1, if(n > 1e7, subst(F,x,1/n), f(n))) - z %15 = 1.1 E-212 \\ now perfect @eprog \synt{sumnum}{(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec)} where an omitted \var{tab} is coded as \kbd{NULL}. \subsec{sumnumap$(n=a,f,\{\var{tab}\})$}\kbdsidx{sumnumap}\label{se:sumnumap} Numerical summation of $f(n)$ at high accuracy using Abel-Plana, the variable $n$ taking values from $a$ to $+\infty$, where $f$ is holomorphic in the right half-place $\Re(z) > a$; \kbd{a} must be an integer and \kbd{tab}, if given, is the output of \kbd{sumnumapinit}. The latter precomputes abscissas and weights, speeding up the computation; it also allows to specify the behavior at infinity via \kbd{sumnumapinit([+oo, asymp])}. \bprog ? \p500 ? z3 = zeta(3); ? sumpos(n = 1, n^-3) - z3 time = 2,332 ms. %2 = 2.438468843 E-501 ? sumnumap(n = 1, n^-3) - z3 \\ here slower than sumpos time = 2,565 ms. %3 = 0.E-500 @eprog \misctitle{Complexity} The function $f$ will be evaluated at $O(D \log D)$ real arguments and $O(D)$ complex arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. The routine is geared towards slowly decreasing functions: if $f$ decreases exponentially fast, then one of \kbd{suminf} or \kbd{sumpos} should be preferred. The default algorithm \kbd{sumnum} is usually a little \emph{slower} than \kbd{sumnumap} but its initialization function \kbd{sumnuminit} becomes much faster as \kbd{realprecision} increases. If $f$ satisfies the stronger hypotheses required for Monien summation, i.e. if $f(1/z)$ is holomorphic in a complex neighbourhood of $[0,1]$, then \tet{sumnummonien} will be faster since it only requires $O(D/\log D)$ evaluations: \bprog ? sumnummonien(n = 1, 1/n^3) - z3 time = 1,128 ms. %3 = 0.E-500 @eprog\noindent The \kbd{tab} argument precomputes technical data not depending on the expression being summed and valid for a given accuracy, speeding up immensely later calls: \bprog ? tab = sumnumapinit(); time = 2,567 ms. ? sumnumap(n = 1, 1/n^3, tab) - z3 \\ now much faster than sumpos time = 39 ms. %5 = 0.E-500 ? tabmon = sumnummonieninit(); \\ Monien summation allows precomputations too time = 1,125 ms. ? sumnummonien(n = 1, 1/n^3, tabmon) - z3 time = 2 ms. %7 = 0.E-500 @eprog\noindent The speedup due to precomputations becomes less impressive when the function $f$ is expensive to evaluate, though: \bprog ? sumnumap(n = 1, lngamma(1+1/n)/n, tab); time = 10,762 ms. ? sumnummonien(n = 1, lngamma(1+1/n)/n, tabmon); \\ fewer evaluations time = 205 ms. @eprog \misctitle{Behaviour at infinity} By default, \kbd{sumnumap} assumes that \var{expr} decreases slowly at infinity, but at least like $O(n^{-2})$. If the function decreases like $n^{\alpha}$ for some $-2 < \alpha < -1$, then it must be indicated via \bprog tab = sumnumapinit([+oo, alpha]); /* alpha < 0 slow decrease */ @eprog\noindent otherwise loss of accuracy is expected. If the functions decreases quickly, like $\exp(-\alpha n)$ for some $\alpha > 0$, then it must be indicated via \bprog tab = sumnumapinit([+oo, alpha]); /* alpha > 0 exponential decrease */ @eprog\noindent otherwise exponent overflow will occur. \bprog ? sumnumap(n=1,2^-n) *** at top-level: sumnumap(n=1,2^-n) *** ^---- *** _^_: overflow in expo(). ? tab = sumnumapinit([+oo,log(2)]); sumnumap(n=1,2^-n, tab) %1 = 1.000[...] @eprog As a shortcut, one can also input \bprog sumnumap(n = [a, asymp], f) @eprog\noindent instead of \bprog tab = sumnumapinit(asymp); sumnumap(n = a, f, tab) @eprog \misctitle{Further examples} \bprog ? \p200 ? sumnumap(n = 1, n^(-2)) - zeta(2) \\ accurate, fast time = 169 ms. %1 = -4.752728915737899559 E-212 ? sumpos(n = 1, n^(-2)) - zeta(2) \\ even faster time = 79 ms. %2 = 0.E-211 ? sumpos(n=1,n^(-4/3)) - zeta(4/3) \\ now much slower time = 10,518 ms. %3 = -9.980730723049589073 E-210 ? sumnumap(n=1,n^(-4/3)) - zeta(4/3) \\ fast but inaccurate time = 309 ms. %4 = -2.57[...]E-78 ? sumnumap(n=[1,-4/3],n^(-4/3)) - zeta(4/3) \\ decrease rate: now accurate time = 329 ms. %6 = -5.418110963941205497 E-210 ? tab = sumnumapinit([+oo,-4/3]); time = 160 ms. ? sumnumap(n=1, n^(-4/3), tab) - zeta(4/3) \\ faster with precomputations time = 175 ms. %5 = -5.418110963941205497 E-210 ? sumnumap(n=1,-log(n)*n^(-4/3), tab) - zeta'(4/3) time = 258 ms. %7 = 9.125239518216767153 E-210 @eprog Note that in the case of slow decrease ($\alpha < 0$), the exact decrease rate must be indicated, while in the case of exponential decrease, a rough value will do. In fact, for exponentially decreasing functions, \kbd{sumnumap} is given for completeness and comparison purposes only: one of \kbd{suminf} or \kbd{sumpos} should always be preferred. \bprog ? sumnumap(n=[1, 1], 2^-n) \\ pretend we decrease as exp(-n) time = 240 ms. %8 = 1.000[...] \\ perfect ? sumpos(n=1, 2^-n) %9 = 1.000[...] \\ perfect and instantaneous @eprog \synt{sumnumap}{(void *E, GEN (*eval)(void*,GEN), GEN a, GEN tab, long prec)} where an omitted \var{tab} is coded as \kbd{NULL}. \subsec{sumnumapinit$(\{\var{asymp}\})$}\kbdsidx{sumnumapinit}\label{se:sumnumapinit} Initialize tables for Abel--Plana summation of a series $\sum f(n)$, where $f$ is holomorphic in a right half-plane. If given, \kbd{asymp} is of the form $[\kbd{+oo}, \alpha]$, as in \tet{intnum} and indicates the decrease rate at infinity of functions to be summed. A positive $\alpha > 0$ encodes an exponential decrease of type $\exp(-\alpha n)$ and a negative $-2 < \alpha < -1$ encodes a slow polynomial decrease of type $n^{\alpha}$. \bprog ? \p200 ? sumnumap(n=1, n^-2); time = 163 ms. ? tab = sumnumapinit(); time = 160 ms. ? sumnum(n=1, n^-2, tab); \\ faster time = 7 ms. ? tab = sumnumapinit([+oo, log(2)]); \\ decrease like 2^-n time = 164 ms. ? sumnumap(n=1, 2^-n, tab) - 1 time = 36 ms. %5 = 3.0127431466707723218 E-282 ? tab = sumnumapinit([+oo, -4/3]); \\ decrease like n^(-4/3) time = 166 ms. ? sumnumap(n=1, n^(-4/3), tab); time = 181 ms. @eprog The library syntax is \fun{GEN}{sumnumapinit}{GEN asymp = NULL, long prec}. \subsec{sumnuminit$(\{\var{asymp}\})$}\kbdsidx{sumnuminit}\label{se:sumnuminit} Initialize tables for Euler--MacLaurin delta summation of a series with positive terms. If given, \kbd{asymp} is of the form $[\kbd{+oo}, \alpha]$, as in \tet{intnum} and indicates the decrease rate at infinity of functions to be summed. A positive $\alpha > 0$ encodes an exponential decrease of type $\exp(-\alpha n)$ and a negative $-2 < \alpha < -1$ encodes a slow polynomial decrease of type $n^{\alpha}$. \bprog ? \p200 ? sumnum(n=1, n^-2); time = 200 ms. ? tab = sumnuminit(); time = 188 ms. ? sumnum(n=1, n^-2, tab); \\ faster time = 8 ms. ? tab = sumnuminit([+oo, log(2)]); \\ decrease like 2^-n time = 200 ms. ? sumnum(n=1, 2^-n, tab) time = 44 ms. ? tab = sumnuminit([+oo, -4/3]); \\ decrease like n^(-4/3) time = 200 ms. ? sumnum(n=1, n^(-4/3), tab); time = 221 ms. @eprog The library syntax is \fun{GEN}{sumnuminit}{GEN asymp = NULL, long prec}. \subsec{sumnumlagrange$(n=a,f,\{\var{tab}\})$}\kbdsidx{sumnumlagrange}\label{se:sumnumlagrange} Numerical summation of $f(n)$ from $n=a$ to $+\infty$ using Lagrange summation; $a$ must be an integer, and the optional argument \kbd{tab} is the output of \kbd{sumnumlagrangeinit}. By default, the program assumes that the $N$th remainder has an asymptotic expansion in integral powers of $1/N$. If not, initialize \kbd{tab} using \kbd{sumnumlagrangeinit(al)}, where the asymptotic expansion of the remainder is integral powers of $1/N^{al}$; $al$ can be equal to $1$ (default), $1/2$, $1/3$, or $1/4$, and also equal to $2$, but in this latter case it is the $N$th remainder minus one half of the last summand which has an asymptotic expansion in integral powers of $1/N^2$. \bprog ? \p1000 ? z3 = zeta(3); ? sumpos(n = 1, n^-3) - z3 time = 8,088 ms. %2 = -2.08[...] E-1001 ? sumnumlagrange(n = 1, n^-3) - z3 \\ much faster than sumpos time = 40 ms. %3 = 0.E-1001 ? tab = sumnumlagrangeinit(2); time = 20 ms. ? sumnumlagrange(n = 1, n^-3, tab) - z3 time = 4 ms. /* even faster */ %5 = 0.E-1001 ? \p115 ? tab = sumnumlagrangeinit([1/3,1/3]); time = 316 ms. ? sumnumlagrange(n = 1, n^-(7/3), tab) - zeta(7/3) time = 24 ms. %7 = 0.E-115 ? sumnumlagrange(n = 1, n^(-2/3) - 3*(n^(1/3)-(n-1)^(1/3)), tab) - zeta(2/3) time = 32 ms. %8 = 1.0151767349262596893 E-115 @eprog \misctitle{Complexity} The function $f$ is evaluated at $O(D)$ integer arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. \synt{sumnumlagrange}{(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec)} where an omitted \var{tab} is coded as \kbd{NULL}. \subsec{sumnumlagrangeinit$(\{\var{asymp}\}, \{\var{c1}\})$}\kbdsidx{sumnumlagrangeinit}\label{se:sumnumlagrangeinit} Initialize tables for Lagrange summation of a series. By default, assume that the remainder $R(n) = \sum_{m \geq n} f(m)$ has an asymptotic expansion $$R(n) = \sum_{m \geq n} f(n) \approx \sum_{i\geq 1} a_i / n^i$$ at infinity. The argument \kbd{asymp} allows to specify different expansions: \item a real number $\beta$ means $$ R(n) = n^{-\beta} \sum_{i\geq 1} a_i / n^i $$ \item a \typ{CLOSURE} $g$ means $$R(n) = g(n) \sum_{i\geq 1} a_i / n^i$$ (The preceding case corresponds to $g(n) = n^{-\beta}$.) \item a pair $[\alpha,\beta]$ where $\beta$ is as above and $\alpha\in \{2, 1, 1/2, 1/3, 1/4\}$. We let $R_2(n) = R(n) - f(n)/2$ and $R_\alpha(n) = R(n)$ for $\alpha\neq 2$. Then $$R_\alpha(n) = g(n) \sum_{i\geq 1} a_i / n^{i\alpha}$$ Note that the initialization times increase considerable for the $\alpha$ is this list ($1/4$ being the slowest). The constant $c1$ is technical and computed by the program, but can be set by the user: the number of interpolation steps will be chosen close to $c1\cdot B$, where $B$ is the bit accuracy. \bprog ? \p2000 ? sumnumlagrange(n=1, n^-2); time = 173 ms. ? tab = sumnumlagrangeinit(); time = 172 ms. ? sumnumlagrange(n=1, n^-2, tab); time = 4 ms. ? \p115 ? sumnumlagrange(n=1, n^(-4/3)) - zeta(4/3); %1 = -0.1093[...] \\ junk: expansion in n^(1/3) time = 84 ms. ? tab = sumnumlagrangeinit([1/3,0]); \\ alpha = 1/3 time = 336 ms. ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) time = 84 ms. %3 = 1.0151767349262596893 E-115 \\ now OK ? tab = sumnumlagrangeinit(1/3); \\ alpha = 1, beta = 1/3: much faster time = 3ms ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) \\ ... but wrong %5 = -0.273825[...] \\ junk ! ? tab = sumnumlagrangeinit(-2/3); \\ alpha = 1, beta = -2/3 time = 3ms ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) %6 = 2.030353469852519379 E-115 \\ now OK @eprog\noindent in The final example with $\zeta(4/3)$, the remainder $R_1(n)$ is of the form $n^{-1/3} \sum_{i\geq 0} a_i / n^i$, i.e. $n^{2/3} \sum_{i\geq 1} a_i / n^i$. The explains the wrong result for $\beta = 1/3$ and the correction with $\beta = -2/3$. The library syntax is \fun{GEN}{sumnumlagrangeinit}{GEN asymp = NULL, GEN c1 = NULL, long prec}. \subsec{sumnummonien$(n=a,f,\{\var{tab}\})$}\kbdsidx{sumnummonien}\label{se:sumnummonien} Numerical summation $\sum_{n\geq a} f(n)$ at high accuracy, the variable $n$ taking values from the integer $a$ to $+\infty$ using Monien summation, which assumes that $f(1/z)$ has a complex analytic continuation in a (complex) neighbourhood of the segment $[0,1]$. The function $f$ is evaluated at $O(D / \log D)$ real arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. By default, assume that $f(n) = O(n^{-2})$ and has a non-zero asymptotic expansion $$f(n) = \sum_{i\geq 2} a_i n^{-i}$$ at infinity. To handle more complicated behaviors and allow time-saving precomputations (for a given \kbd{realprecision}), see \kbd{sumnummonieninit}. The library syntax is \fun{GEN}{sumnummonien0}{GEN n, GEN f, GEN tab = NULL, long prec}. \subsec{sumnummonieninit$(\{\var{asymp}\},\{w\},\{\var{n0} = 1\})$}\kbdsidx{sumnummonieninit}\label{se:sumnummonieninit} Initialize tables for Monien summation of a series $\sum_{n\geq n_0} f(n)$ where $f(1/z)$ has a complex analytic continuation in a (complex) neighbourhood of the segment $[0,1]$. By default, assume that $f(n) = O(n^{-2})$ and has a non-zero asymptotic expansion $$f(n) = \sum_{i\geq 2} a_i / n^i$$ at infinity. Note that the sum starts at $i = 2$! The argument \kbd{asymp} allows to specify different expansions: \item a real number $\beta > 0$ means $$f(n) = \sum_{i\geq 1} a_i / n^{i + \beta}$$ (Now the summation starts at $1$.) \item a vector $[\alpha,\beta]$ of reals, where we must have $\alpha > 0$ and $\alpha + \beta > 1$ to ensure convergence, means that $$f(n) = \sum_{i\geq 1} a_i / n^{\alpha i + \beta}$$ Note that $\kbd{asymp} = [1, \beta]$ is equivalent to $\kbd{asymp}=\beta$. \bprog ? \p57 ? s = sumnum(n = 1, sin(1/sqrt(n)) / n); \\ reference point ? \p38 ? sumnummonien(n = 1, sin(1/sqrt(n)) / n) - s %2 = -0.001[...] \\ completely wrong ? t = sumnummonieninit(1/2); \\ f(n) = sum_i 1 / n^(i+1/2) ? sumnummonien(n = 1, sin(1/sqrt(n)) / n, t) - s %3 = 0.E-37 \\ now correct @eprog\noindent (As a matter of fact, in the above summation, the result given by \kbd{sumnum} at \kbd{\bs p38} is slighly incorrect, so we had to increase the accuracy to \kbd{\bs p57}.) The argument $w$ is used to sum expressions of the form $$ \sum_{n\geq n_0} f(n) w(n),$$ for varying $f$ \emph{as above}, and fixed weight function $w$, where we further assume that the auxiliary sums $$g_w(m) = \sum_{n\geq n_0} w(n) / n^{\alpha m + \beta} $$ converge for all $m\geq 1$. Note that for non-negative integers $k$, and weight $w(n) = (\log n)^k$, the function $g_w(m) = \zeta^{(k)}(\alpha m + \beta)$ has a simple expression; for general weights, $g_w$ is computed using \kbd{sumnum}. The following variants are available \item an integer $k \geq 0$, to code $w(n) = (\log n)^k$; \item a \typ{CLOSURE} computing the values $w(n)$, where we assume that $w(n) = O(n^\epsilon)$ for all $\epsilon > 0$; \item a vector $[w, \kbd{fast}]$, where $w$ is a closure as above and \kbd{fast} is a scalar; we assume that $w(n) = O(n^{\kbd{fast}+\epsilon})$; note that $\kbd{w} = [w, 0]$ is equivalent to $\kbd{w} = w$. Note that if $w$ decreases exponentially, \kbd{suminf} should be used instead. The subsequent calls to \kbd{sumnummonien} \emph{must} use the same value of $n_0$ as was used here. \bprog ? \p300 ? sumnummonien(n = 1, n^-2*log(n)) + zeta'(2) time = 328 ms. %1 = -1.323[...]E-6 \\ completely wrong, f does not satisfy hypotheses ! ? tab = sumnummonieninit(, 1); \\ codes w(n) = log(n) time = 3,993 ms. ? sumnummonien(n = 1, n^-2, tab) + zeta'(2) time = 41 ms. %3 = -5.562684646268003458 E-309 \\ now perfect ? tab = sumnummonieninit(, n->log(n)); \\ generic, slower time = 9,808 ms. ? sumnummonien(n = 1, n^-2, tab) + zeta'(2) time = 40 ms. %5 = -5.562684646268003458 E-309 \\ identical result @eprog The library syntax is \fun{GEN}{sumnummonieninit}{GEN asymp = NULL, GEN w = NULL, GEN n0 = NULL, long prec}. \subsec{sumnumrat$(F,a)$}\kbdsidx{sumnumrat}\label{se:sumnumrat} $\sum_{n\geq a}F(n)$, where $F$ is a rational function of degree less than or equal to $-2$ and where poles of $F$ at integers $\geq a$ are omitted from the summation. The argument $a$ must be a \typ{INT} or \kbd{-oo}. \bprog ? sumnumrat(1/(x^2+1)^2,0) %1 = 1.3068369754229086939178621382829073480 ? sumnumrat(1/x^2, -oo) \\ value at x=0 is discarded %2 = 3.2898681336964528729448303332920503784 ? 2*zeta(2) %3 = 3.2898681336964528729448303332920503784 @eprog\noindent When $\deg F = -1$, we define $$\sum_{-\infty}^{\infty} F(n) := \sum_{n\geq 0} (F(n) + F(-1-n)):$$ \bprog ? sumnumrat(1/x, -oo) %4 = 0.E-38 @eprog The library syntax is \fun{GEN}{sumnumrat}{GEN F, GEN a, long prec}. \subsec{sumpos$(X=a,\var{expr},\{\fl=0\})$}\kbdsidx{sumpos}\label{se:sumpos} Numerical summation of the series \var{expr}, which must be a series of terms having the same sign, the formal variable $X$ starting at $a$. The algorithm used is Van Wijngaarden's trick for converting such a series into an alternating one, then we use \tet{sumalt}. For regular functions, the function \kbd{sumnum} is in general much faster once the initializations have been made using \kbd{sumnuminit}. The routine is heuristic and assumes that \var{expr} is more or less a decreasing function of $X$. In particular, the result will be completely wrong if \var{expr} is 0 too often. We do not check either that all terms have the same sign. As \tet{sumalt}, this function should be used to try and guess the value of an infinite sum. If $\fl=1$, use \kbd{sumalt}$(,1)$ instead of \kbd{sumalt}$(,0)$, see \secref{se:sumalt}. Requiring more stringent analytic properties for rigorous use, but allowing to compute fewer series terms. To reach accuracy $10^{-p}$, both algorithms require $O(p^2)$ space; furthermore, assuming the terms decrease polynomially (in $O(n^{-C})$), both need to compute $O(p^2)$ terms. The \kbd{sumpos}$(,1)$ variant has a smaller implied constant (roughly 1.5 times smaller). Since the \kbd{sumalt}$(,1)$ overhead is now small compared to the time needed to compute series terms, this last variant should be about 1.5 faster. On the other hand, the achieved accuracy may be much worse: as for \tet{sumalt}, since conditions for rigorous use are hard to check, the routine is best used heuristically. \synt{sumpos}{void *E, GEN (*eval)(void*,GEN),GEN a,long prec}. Also available is \tet{sumpos2} with the same arguments ($\fl = 1$). \section{General number fields} In this section, we describe functions related to general number fields. Functions related to quadratic number fields are found in \secref{se:arithmetic} (Arithmetic functions). \subsec{Number field structures} %GPHELPskip Let $K = \Q[X] / (T)$ a number field, $\Z_K$ its ring of integers, $T\in\Z[X]$ is monic. Three basic number field structures can be attached to $K$ in GP: \item $\tev{nf}$ denotes a number field, i.e.~a data structure output by \tet{nfinit}. This contains the basic arithmetic data attached to the number field: signature, maximal order (given by a basis \kbd{nf.zk}), discriminant, defining polynomial $T$, etc. \item $\tev{bnf}$ denotes a ``Buchmann's number field'', i.e.~a data structure output by \tet{bnfinit}. This contains $\var{nf}$ and the deeper invariants of the field: units $U(K)$, class group $\Cl(K)$, as well as technical data required to solve the two attached discrete logarithm problems. \item $\tev{bnr}$ denotes a ``ray number field'', i.e.~a data structure output by \kbd{bnrinit}, corresponding to the ray class group structure of the field, for some modulus $f$. It contains a \var{bnf}, the modulus $f$, the ray class group $\Cl_f(K)$ and data attached to the discrete logarithm problem therein. \subsec{Algebraic numbers and ideals} %GPHELPskip \noindent An \tev{algebraic number} belonging to $K = \Q[X]/(T)$ is given as \item a \typ{INT}, \typ{FRAC} or \typ{POL} (implicitly modulo $T$), or \item a \typ{POLMOD} (modulo $T$), or \item a \typ{COL}~\kbd{v} of dimension $N = [K:\Q]$, representing the element in terms of the computed integral basis, as \kbd{sum(i = 1, N,~v[i] * nf.zk[i])}. Note that a \typ{VEC} will not be recognized. \medskip \noindent An \tev{ideal} is given in any of the following ways: \item an algebraic number in one of the above forms, defining a principal ideal. \item a prime ideal, i.e.~a 5-component vector in the format output by \kbd{idealprimedec} or \kbd{idealfactor}. \item a \typ{MAT}, square and in Hermite Normal Form (or at least upper triangular with non-negative coefficients), whose columns represent a $\Z$-basis of the ideal. One may use \kbd{idealhnf} to convert any ideal to the last (preferred) format. \item an \emph{extended ideal} \sidx{ideal (extended)} is a 2-component vector $[I, t]$, where $I$ is an ideal as above and $t$ is an algebraic number, representing the ideal $(t)I$. This is useful whenever \tet{idealred} is involved, implicitly working in the ideal class group, while keeping track of principal ideals. The following multiplicative ideal operations update the principal part: \kbd{idealmul}, \kbd{idealsqr}, \kbd{idealinv}, \kbd{idealpow} and \kbd{idealred}; e.g.~using \kbd{idealmul} on $[I,t]$, $[J,u]$, we obtain $[IJ, tu]$. In all other functions, the extended part is silently discarded, e.g.~using \kbd{idealadd} with the above input produces $I+J$. The ``principal part'' $t$ in an extended ideal may be represented in any of the above forms, and \emph{also} as a factorization matrix (in terms of number field elements, not ideals!), possibly the empty factorization matrix \kbd{factor(1)} representing $1$; the empty matrix \kbd{[;]} is also accepted as a synonym for $1$. When $t$ is such a factorization matrix, elements stay in factored form, or \tev{famat} for \emph{fa}ctorization \emph{mat}rix, which is a convenient way to avoid coefficient explosion. To recover the conventional expanded form, try \tet{nffactorback}; but many functions already accept \var{famat}s as input, for instance \tet{ideallog}, so expanding huge elements should never be necessary. \subsec{Finite abelian groups} %GPHELPskip A finite abelian group $G$ in user-readable format is given by its Smith Normal Form as a pair $[h,d]$ or triple $[h,d,g]$. Here $h$ is the cardinality of $G$, $(d_i)$ is the vector of elementary divisors, and $(g_i)$ is a vector of generators. In short, $G = \oplus_{i\leq n} (\Z/d_i\Z) g_i$, with $d_n \mid \dots \mid d_2 \mid d_1$ and $\prod d_i = h$. This information can also be retrieved as $G.\kbd{no}$, $G.\kbd{cyc}$ and $G.\kbd{gen}$. \item a \tev{character} on the abelian group $\oplus (\Z/d_j\Z) g_j$ is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$. \item given such a structure, a \tev{subgroup} $H$ is input as a square matrix in HNF, whose columns express generators of $H$ on the given generators $g_i$. Note that the determinant of that matrix is equal to the index $(G:H)$. \subsec{Relative extensions} %GPHELPskip We now have a look at data structures attached to relative extensions of number fields $L/K$, and to projective $\Z_K$-modules. When defining a relative extension $L/K$, the $\var{nf}$ attached to the base field $K$ must be defined by a variable having a lower priority (see \secref{se:priority}) than the variable defining the extension. For example, you may use the variable name $y$ to define the base field $K$, and $x$ to define the relative extension $L/K$. \subsubsec{Basic definitions}\label{se:ZKmodules} %GPHELPskip \item $\tev{rnf}$ denotes a relative number field, i.e.~a data structure output by \kbd{rnfinit}, attached to the extension $L/K$. The \var{nf} attached to be base field $K$ is \kbd{rnf.nf}. \item A \emph{relative matrix} is an $m\times n$ matrix whose entries are elements of $K$, in any form. Its $m$ columns $A_j$ represent elements in $K^n$. \item An \tev{ideal list} is a row vector of fractional ideals of the number field $\var{nf}$. \item A \tev{pseudo-matrix} is a 2-component row vector $(A,I)$ where $A$ is a relative $m\times n$ matrix and $I$ an ideal list of length $n$. If $I = \{\goth{a}_1,\dots, \goth{a}_n\}$ and the columns of $A$ are $(A_1,\dots, A_n)$, this data defines the torsion-free (projective) $\Z_K$-module $\goth{a}_1 A_1\oplus \goth{a}_n A_n$. \item An \tev{integral pseudo-matrix} is a 3-component row vector w$(A,I,J)$ where $A = (a_{i,j})$ is an $m\times n$ relative matrix and $I = (\goth{b}_1,\dots, \goth{b}_m)$, $J = (\goth{a}_1,\dots, \goth{a}_n)$ are ideal lists, such that $a_{i,j} \in \goth{b}_i \goth{a}_j^{-1}$ for all $i,j$. This data defines two abstract projective $\Z_K$-modules $N = \goth{a}_1\omega_1\oplus \cdots\oplus \goth{a}_n\omega_n $ in $K^n$, $P = \goth{b}_1\eta_1\oplus \cdots\oplus \goth{b}_m\eta_m$ in $K^m$, and a $\Z_K$-linear map $f:N\to P$ given by $$ f(\sum \alpha_j\omega_j) = \sum_i \Big(a_{i,j}\alpha_j\Big) \eta_i.$$ This data defines the $\Z_K$-module $M = P/f(N)$. \item Any \emph{projective} $\Z_K$-module\varsidx{projective module} $M$ of finite type in $K^m$ can be given by a pseudo matrix $(A,I)$. \item An arbitrary $\Z_K$ modules of finite type in $K^m$, with non-trivial torsion, is given by an integral pseudo-matrix $(A,I,J)$ \subsubsec{Pseudo-bases, determinant} %GPHELPskip \item The pair $(A,I)$ is a \tev{pseudo-basis} of the module it generates if the $\goth{a}_j$ are non-zero, and the $A_j$ are $K$-linearly independent. We call $n$ the \emph{size} of the pseudo-basis. If $A$ is a relative matrix, the latter condition means it is square with non-zero determinant; we say that it is in Hermite Normal Form\sidx{Hermite normal form} (HNF) if it is upper triangular and all the elements of the diagonal are equal to 1. \item For instance, the relative integer basis \kbd{rnf.zk} is a pseudo-basis $(A,I)$ of $\Z_L$, where $A = \kbd{rnf.zk[1]}$ is a vector of elements of $L$, which are $K$-linearly independent. Most \var{rnf} routines return and handle $\Z_K$-modules contained in $L$ (e.g.~$\Z_L$-ideals) via a pseudo-basis $(A',I')$, where $A'$ is a relative matrix representing a vector of elements of $L$ in terms of the fixed basis \kbd{rnf.zk[1]} \item The \emph{determinant} of a pseudo-basis $(A,I)$ is the ideal equal to the product of the determinant of $A$ by all the ideals of $I$. The determinant of a pseudo-matrix is the determinant of any pseudo-basis of the module it generates. \subsec{Class field theory}\label{se:CFT} A $\tev{modulus}$, in the sense of class field theory, is a divisor supported on the non-complex places of $K$. In PARI terms, this means either an ordinary ideal $I$ as above (no Archimedean component), or a pair $[I,a]$, where $a$ is a vector with $r_1$ $\{0,1\}$-components, corresponding to the infinite part of the divisor. More precisely, the $i$-th component of $a$ corresponds to the real embedding attached to the $i$-th real root of \kbd{K.roots}. (That ordering is not canonical, but well defined once a defining polynomial for $K$ is chosen.) For instance, \kbd{[1, [1,1]]} is a modulus for a real quadratic field, allowing ramification at any of the two places at infinity, and nowhere else. A \tev{bid} or ``big ideal'' is a structure output by \kbd{idealstar} needed to compute in $(\Z_K/I)^*$, where $I$ is a modulus in the above sense. It is a finite abelian group as described above, supplemented by technical data needed to solve discrete log problems. Finally we explain how to input ray number fields (or \var{bnr}), using class field theory. These are defined by a triple $A$, $B$, $C$, where the defining set $[A,B,C]$ can have any of the following forms: $[\var{bnr}]$, $[\var{bnr},\var{subgroup}]$, $[\var{bnr},\var{character}]$, $[\var{bnf},\var{mod}]$, $[\var{bnf},\var{mod},\var{subgroup}]$. The last two forms are kept for backward compatibility, but no longer serve any real purpose (see example below); no newly written function will accept them. \item $\var{bnf}$ is as output by \kbd{bnfinit}, where units are mandatory unless the modulus is trivial; \var{bnr} is as output by \kbd{bnrinit}. This is the ground field $K$. \item \emph{mod} is a modulus $\goth{f}$, as described above. \item \emph{subgroup} a subgroup of the ray class group modulo $\goth{f}$ of $K$. As described above, this is input as a square matrix expressing generators of a subgroup of the ray class group \kbd{\var{bnr}.clgp} on the given generators. The corresponding \var{bnr} is the subfield of the ray class field of $K$ modulo $\goth{f}$, fixed by the given subgroup. \bprog ? K = bnfinit(y^2+1); ? bnr = bnrinit(K, 13) ? %.clgp %3 = [36, [12, 3]] ? bnrdisc(bnr); \\ discriminant of the full ray class field ? bnrdisc(bnr, [3,1;0,1]); \\ discriminant of cyclic cubic extension of K ? bnrconductor(bnr, [3,1]); \\ conductor of chi: g1->zeta_12^3, g2->zeta_3 @eprog\noindent We could have written directly \bprog ? bnrdisc(K, 13); ? bnrdisc(K, 13, [3,1;0,1]); @eprog\noindent avoiding one \tet{bnrinit}, but this would actually be slower since the \kbd{bnrinit} is called internally anyway. And now twice! \subsec{General use} All the functions which are specific to relative extensions, number fields, Buchmann's number fields, Buchmann's number rays, share the prefix \kbd{rnf}, \kbd{nf}, \kbd{bnf}, \kbd{bnr} respectively. They take as first argument a number field of that precise type, respectively output by \kbd{rnfinit}, \kbd{nfinit}, \kbd{bnfinit}, and \kbd{bnrinit}. However, and even though it may not be specified in the descriptions of the functions below, it is permissible, if the function expects a $\var{nf}$, to use a $\var{bnf}$ instead, which contains much more information. On the other hand, if the function requires a \kbd{bnf}, it will \emph{not} launch \kbd{bnfinit} for you, which is a costly operation. Instead, it will give you a specific error message. In short, the types $$ \kbd{nf} \leq \kbd{bnf} \leq \kbd{bnr}$$ are ordered, each function requires a minimal type to work properly, but you may always substitute a larger type. The data types corresponding to the structures described above are rather complicated. Thus, as we already have seen it with elliptic curves, GP provides ``member functions'' to retrieve data from these structures (once they have been initialized of course). The relevant types of number fields are indicated between parentheses: \smallskip \sidx{member functions} \settabs\+xxxxxxx&(\var{bnr},x&\var{bnf},x&nf\hskip2pt&)x&: &\cr \+\tet{bid} &(\var{bnr}&&&)&: & bid ideal structure.\cr \+\tet{bnf} &(\var{bnr},& \var{bnf}&&)&: & Buchmann's number field.\cr \+\tet{clgp} &(\var{bnr},& \var{bnf}&&)&: & classgroup. This one admits the following three subclasses:\cr \+ \quad \tet{cyc} &&&&&: & \quad cyclic decomposition (SNF)\sidx{Smith normal form}.\cr \+ \quad \kbd{gen}\sidx{gen (member function)} &&&&&: & \quad generators.\cr \+ \quad \tet{no} &&&&&: & \quad number of elements.\cr \+\tet{diff} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the different ideal.\cr \+\tet{codiff}&(\var{bnr},& \var{bnf},& \var{nf}&)&: & the codifferent (inverse of the different in the ideal group).\cr \+\tet{disc} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & discriminant.\cr \+\tet{fu} &(\var{bnr},& \var{bnf}&&)&: & \idx{fundamental units}.\cr \+\tet{index} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & \idx{index} of the power order in the ring of integers.\cr \+\tet{mod} &(\var{bnr}&&&)&: & modulus.\cr \+\tet{nf} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & number field.\cr \+\tet{pol} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & defining polynomial.\cr \+\tet{r1} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the number of real embeddings.\cr \+\tet{r2} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the number of pairs of complex embeddings.\cr \+\tet{reg} &(\var{bnr},& \var{bnf}&&)&: & regulator.\cr \+\tet{roots}&(\var{bnr},& \var{bnf},& \var{nf}&)&: & roots of the polynomial generating the field.\cr \+\tet{sign} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & signature $[r1,r2]$.\cr \+\tet{t2} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the $T_2$ matrix (see \kbd{nfinit}).\cr \+\tet{tu} &(\var{bnr},& \var{bnf}&&)&: & a generator for the torsion units.\cr \+\tet{zk} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & integral basis, i.e.~a $\Z$-basis of the maximal order.\cr \+\tet{zkst} &(\var{bnr}&&&)&: & structure of $(\Z_K/m)^*$.\cr The member functions \kbd{.codiff}, \kbd{.t2} and \kbd{.zk} perform a computation and are relatively expensive in large degree: move them out of tight loops and store them in variables. \misctitle{Deprecated} The following member functions are still available, but deprecated and should not be used in new scripts : \+\tet{futu} &(\var{bnr},& \var{bnf},&&)&: & $[u_1,...,u_r,w]$, $(u_i)$ is a vector of fundamental units,\cr \+&&&&&& $w$ generates the torsion units.\cr \+\tet{tufu} &(\var{bnr},& \var{bnf},&&)&: & $[w,u_1,...,u_r]$, $(u_i)$ is a vector of fundamental units,\cr \+&&&&&& $w$ generates the torsion units.\cr For instance, assume that $\var{bnf} = \kbd{bnfinit}(\var{pol})$, for some polynomial. Then \kbd{\var{bnf}.clgp} retrieves the class group, and \kbd{\var{bnf}.clgp.no} the class number. If we had set $\var{bnf} = \kbd{nfinit}(\var{pol})$, both would have output an error message. All these functions are completely recursive, thus for instance \kbd{\var{bnr}.bnf.nf.zk} will yield the maximal order of \var{bnr}, which you could get directly with a simple \kbd{\var{bnr}.zk}. \subsec{Class group, units, and the GRH}\label{se:GRHbnf} Some of the functions starting with \kbd{bnf} are implementations of the sub-exponential algorithms for finding class and unit groups under \idx{GRH}, due to Hafner-McCurley, \idx{Buchmann} and Cohen-Diaz-Olivier. The general call to the functions concerning class groups of general number fields (i.e.~excluding \kbd{quadclassunit}) involves a polynomial $P$ and a technical vector $$\var{tech} = [c_1, c_2, \var{nrpid} ],$$ where the parameters are to be understood as follows: $P$ is the defining polynomial for the number field, which must be in $\Z[X]$, irreducible and monic. In fact, if you supply a non-monic polynomial at this point, \kbd{gp} issues a warning, then \emph{transforms your polynomial} so that it becomes monic. The \kbd{nfinit} routine will return a different result in this case: instead of \kbd{res}, you get a vector \kbd{[res,Mod(a,Q)]}, where \kbd{Mod(a,Q) = Mod(X,P)} gives the change of variables. In all other routines, the variable change is simply lost. The \var{tech} interface is obsolete and you should not tamper with these parameters. Indeed, from version 2.4.0 on, \item the results are always rigorous under \idx{GRH} (before that version, they relied on a heuristic strengthening, hence the need for overrides). \item the influence of these parameters on execution time and stack size is marginal. They \emph{can} be useful to fine-tune and experiment with the \kbd{bnfinit} code, but you will be better off modifying all tuning parameters in the C code (there are many more than just those three). We nevertheless describe it for completeness. The numbers $c_1 \leq c_2$ are non-negative real numbers. By default they are chosen so that the result is correct under GRH. For $i = 1,2$, let $B_i = c_i(\log |d_K|)^2$, and denote by $S(B)$ the set of maximal ideals of $K$ whose norm is less than $B$. We want $S(B_1)$ to generate $\Cl(K)$ and hope that $S(B_2)$ can be \emph{proven} to generate $\Cl(K)$. More precisely, $S(B_1)$ is a factorbase used to compute a tentative $\Cl(K)$ by generators and relations. We then check explicitly, using essentially \kbd{bnfisprincipal}, that the elements of $S(B_2)$ belong to the span of $S(B_1)$. Under the assumption that $S(B_2)$ generates $\Cl(K)$, we are done. User-supplied $c_i$ are only used to compute initial guesses for the bounds $B_i$, and the algorithm increases them until one can \emph{prove} under GRH that $S(B_2)$ generates $\Cl(K)$. A uniform result of Bach says that $c_2 = 12$ is always suitable, but this bound is very pessimistic and a direct algorithm due to Belabas-Diaz-Friedman is used to check the condition, assuming GRH. The default values are $c_1 = c_2 = 0$. When $c_1$ is equal to $0$ the algorithm takes it equal to $c_2$. $\var{nrpid}$ is the maximal number of small norm relations attached to each ideal in the factor base. Set it to $0$ to disable the search for small norm relations. Otherwise, reasonable values are between 4 and 20. The default is 4. \misctitle{Warning} Make sure you understand the above! By default, most of the \kbd{bnf} routines depend on the correctness of the GRH. In particular, any of the class number, class group structure, class group generators, regulator and fundamental units may be wrong, independently of each other. Any result computed from such a \kbd{bnf} may be wrong. The only guarantee is that the units given generate a subgroup of finite index in the full unit group. You must use \kbd{bnfcertify} to certify the computations unconditionally. \misctitle{Remarks} You do not need to supply the technical parameters (under the library you still need to send at least an empty vector, coded as \kbd{NULL}). However, should you choose to set some of them, they \emph{must} be given in the requested order. For example, if you want to specify a given value of \var{nrpid}, you must give some values as well for $c_1$ and $c_2$, and provide a vector $[c_1,c_2,\var{nrpid}]$. Note also that you can use an $\var{nf}$ instead of $P$, which avoids recomputing the integral basis and analogous quantities. \subsec{bnfcertify$(\var{bnf},\{\fl = 0\})$}\kbdsidx{bnfcertify}\label{se:bnfcertify} $\var{bnf}$ being as output by \kbd{bnfinit}, checks whether the result is correct, i.e.~whether it is possible to remove the assumption of the Generalized Riemann Hypothesis\sidx{GRH}. It is correct if and only if the answer is 1. If it is incorrect, the program may output some error message, or loop indefinitely. You can check its progress by increasing the debug level. The \var{bnf} structure must contain the fundamental units: \bprog ? K = bnfinit(x^3+2^2^3+1); bnfcertify(K) *** at top-level: K=bnfinit(x^3+2^2^3+1);bnfcertify(K) *** ^------------- *** bnfcertify: missing units in bnf. ? K = bnfinit(x^3+2^2^3+1, 1); \\ include units ? bnfcertify(K) %3 = 1 @eprog If flag is present, only certify that the class group is a quotient of the one computed in bnf (much simpler in general); likewise, the computed units may form a subgroup of the full unit group. In this variant, the units are no longer needed: \bprog ? K = bnfinit(x^3+2^2^3+1); bnfcertify(K, 1) %4 = 1 @eprog The library syntax is \fun{long}{bnfcertify0}{GEN bnf, long flag}. Also available is \fun{GEN}{bnfcertify}{GEN bnf} ($\fl=0$). \subsec{bnfcompress$(\var{bnf})$}\kbdsidx{bnfcompress}\label{se:bnfcompress} Computes a compressed version of \var{bnf} (from \tet{bnfinit}), a ``small Buchmann's number field'' (or \var{sbnf} for short) which contains enough information to recover a full $\var{bnf}$ vector very rapidly, but which is much smaller and hence easy to store and print. Calling \kbd{bnfinit} on the result recovers a true \kbd{bnf}, in general different from the original. Note that an \tev{snbf} is useless for almost all purposes besides storage, and must be converted back to \tev{bnf} form before use; for instance, no \kbd{nf*}, \kbd{bnf*} or member function accepts them. An \var{sbnf} is a 12 component vector $v$, as follows. Let \kbd{bnf} be the result of a full \kbd{bnfinit}, complete with units. Then $v[1]$ is \kbd{bnf.pol}, $v[2]$ is the number of real embeddings \kbd{bnf.sign[1]}, $v[3]$ is \kbd{bnf.disc}, $v[4]$ is \kbd{bnf.zk}, $v[5]$ is the list of roots \kbd{bnf.roots}, $v[7]$ is the matrix $\kbd{W} = \kbd{bnf[1]}$, $v[8]$ is the matrix $\kbd{matalpha}=\kbd{bnf[2]}$, $v[9]$ is the prime ideal factor base \kbd{bnf[5]} coded in a compact way, and ordered according to the permutation \kbd{bnf[6]}, $v[10]$ is the 2-component vector giving the number of roots of unity and a generator, expressed on the integral basis, $v[11]$ is the list of fundamental units, expressed on the integral basis, $v[12]$ is a vector containing the algebraic numbers alpha corresponding to the columns of the matrix \kbd{matalpha}, expressed on the integral basis. All the components are exact (integral or rational), except for the roots in $v[5]$. The library syntax is \fun{GEN}{bnfcompress}{GEN bnf}. \subsec{bnfdecodemodule$(\var{nf},m)$}\kbdsidx{bnfdecodemodule}\label{se:bnfdecodemodule} If $m$ is a module as output in the first component of an extension given by \kbd{bnrdisclist}, outputs the true module. \bprog ? K = bnfinit(x^2+23); L = bnrdisclist(K, 10); s = L[2] %1 = [[[Vecsmall([8]), Vecsmall([1])], [[0, 0, 0]]], [[Vecsmall([9]), Vecsmall([1])], [[0, 0, 0]]]] ? bnfdecodemodule(K, s[1][1]) %2 = [2 0] [0 1] ? bnfdecodemodule(K,s[2][1]) %3 = [2 1] [0 1] @eprog The library syntax is \fun{GEN}{decodemodule}{GEN nf, GEN m}. \subsec{bnfinit$(P,\{\fl=0\},\{\var{tech}=[\,]\})$}\kbdsidx{bnfinit}\label{se:bnfinit} Initializes a \kbd{bnf} structure. Used in programs such as \kbd{bnfisprincipal}, \kbd{bnfisunit} or \kbd{bnfnarrow}. By default, the results are conditional on the GRH, see \ref{se:GRHbnf}. The result is a 10-component vector \var{bnf}. This implements \idx{Buchmann}'s sub-exponential algorithm for computing the class group, the regulator and a system of \idx{fundamental units} of the general algebraic number field $K$ defined by the irreducible polynomial $P$ with integer coefficients. If the precision becomes insufficient, \kbd{gp} does not strive to compute the units by default ($\fl=0$). When $\fl=1$, we insist on finding the fundamental units exactly. Be warned that this can take a very long time when the coefficients of the fundamental units on the integral basis are very large. If the fundamental units are simply too large to be represented in this form, an error message is issued. They could be obtained using the so-called compact representation of algebraic numbers as a formal product of algebraic integers. The latter is implemented internally but not publicly accessible yet. $\var{tech}$ is a technical vector (empty by default, see \ref{se:GRHbnf}). Careful use of this parameter may speed up your computations, but it is mostly obsolete and you should leave it alone. \smallskip The components of a \var{bnf} or \var{sbnf} are technical and never used by the casual user. In fact: \emph{never access a component directly, always use a proper member function.} However, for the sake of completeness and internal documentation, their description is as follows. We use the notations explained in the book by H. Cohen, \emph{A Course in Computational Algebraic Number Theory}, Graduate Texts in Maths \key{138}, Springer-Verlag, 1993, Section 6.5, and subsection 6.5.5 in particular. $\var{bnf}[1]$ contains the matrix $W$, i.e.~the matrix in Hermite normal form giving relations for the class group on prime ideal generators $(\goth{p}_i)_{1\le i\le r}$. $\var{bnf}[2]$ contains the matrix $B$, i.e.~the matrix containing the expressions of the prime ideal factorbase in terms of the $\goth{p}_i$. It is an $r\times c$ matrix. $\var{bnf}[3]$ contains the complex logarithmic embeddings of the system of fundamental units which has been found. It is an $(r_1+r_2)\times(r_1+r_2-1)$ matrix. $\var{bnf}[4]$ contains the matrix $M''_C$ of Archimedean components of the relations of the matrix $(W|B)$. $\var{bnf}[5]$ contains the prime factor base, i.e.~the list of prime ideals used in finding the relations. $\var{bnf}[6]$ used to contain a permutation of the prime factor base, but has been obsoleted. It contains a dummy $0$. $\var{bnf}[7]$ or \kbd{\var{bnf}.nf} is equal to the number field data $\var{nf}$ as would be given by \kbd{nfinit}. $\var{bnf}[8]$ is a vector containing the classgroup \kbd{\var{bnf}.clgp} as a finite abelian group, the regulator \kbd{\var{bnf}.reg}, a $1$ (used to contain an obsolete ``check number''), the number of roots of unity and a generator \kbd{\var{bnf}.tu}, the fundamental units \kbd{\var{bnf}.fu}. $\var{bnf}[9]$ is a 3-element row vector used in \tet{bnfisprincipal} only and obtained as follows. Let $D = U W V$ obtained by applying the \idx{Smith normal form} algorithm to the matrix $W$ (= $\var{bnf}[1]$) and let $U_r$ be the reduction of $U$ modulo $D$. The first elements of the factorbase are given (in terms of \kbd{bnf.gen}) by the columns of $U_r$, with Archimedean component $g_a$; let also $GD_a$ be the Archimedean components of the generators of the (principal) ideals defined by the \kbd{bnf.gen[i]\pow bnf.cyc[i]}. Then $\var{bnf}[9]=[U_r, g_a, GD_a]$. $\var{bnf}[10]$ is by default unused and set equal to 0. This field is used to store further information about the field as it becomes available, which is rarely needed, hence would be too expensive to compute during the initial \kbd{bnfinit} call. For instance, the generators of the principal ideals \kbd{bnf.gen[i]\pow bnf.cyc[i]} (during a call to \tet{bnrisprincipal}), or those corresponding to the relations in $W$ and $B$ (when the \kbd{bnf} internal precision needs to be increased). The library syntax is \fun{GEN}{bnfinit0}{GEN P, long flag, GEN tech = NULL, long prec}. Also available is \fun{GEN}{Buchall}{GEN P, long flag, long prec}, corresponding to \kbd{tech = NULL}, where \kbd{flag} is either $0$ (default) or \tet{nf_FORCE} (insist on finding fundamental units). The function \fun{GEN}{Buchall_param}{GEN P, double c1, double c2, long nrpid, long flag, long prec} gives direct access to the technical parameters. \subsec{bnfisintnorm$(\var{bnf},x)$}\kbdsidx{bnfisintnorm}\label{se:bnfisintnorm} Computes a complete system of solutions (modulo units of positive norm) of the absolute norm equation $\Norm(a)=x$, where $a$ is an integer in $\var{bnf}$. If $\var{bnf}$ has not been certified, the correctness of the result depends on the validity of \idx{GRH}. See also \tet{bnfisnorm}. The library syntax is \fun{GEN}{bnfisintnorm}{GEN bnf, GEN x}. The function \fun{GEN}{bnfisintnormabs}{GEN bnf, GEN a} returns a complete system of solutions modulo units of the absolute norm equation $|\Norm(x)| = |a|$. As fast as \kbd{bnfisintnorm}, but solves the two equations $\Norm(x) = \pm a$ simultaneously. \subsec{bnfisnorm$(\var{bnf},x,\{\fl=1\})$}\kbdsidx{bnfisnorm}\label{se:bnfisnorm} Tries to tell whether the rational number $x$ is the norm of some element y in $\var{bnf}$. Returns a vector $[a,b]$ where $x=Norm(a)*b$. Looks for a solution which is an $S$-unit, with $S$ a certain set of prime ideals containing (among others) all primes dividing $x$. If $\var{bnf}$ is known to be \idx{Galois}, set $\fl=0$ (in this case, $x$ is a norm iff $b=1$). If $\fl$ is non zero the program adds to $S$ the following prime ideals, depending on the sign of $\fl$. If $\fl>0$, the ideals of norm less than $\fl$. And if $\fl<0$ the ideals dividing $\fl$. Assuming \idx{GRH}, the answer is guaranteed (i.e.~$x$ is a norm iff $b=1$), if $S$ contains all primes less than $12\log(\disc(\var{Bnf}))^2$, where $\var{Bnf}$ is the Galois closure of $\var{bnf}$. See also \tet{bnfisintnorm}. The library syntax is \fun{GEN}{bnfisnorm}{GEN bnf, GEN x, long flag}. \subsec{bnfisprincipal$(\var{bnf},x,\{\fl=1\})$}\kbdsidx{bnfisprincipal}\label{se:bnfisprincipal} $\var{bnf}$ being the \sidx{principal ideal} number field data output by \kbd{bnfinit}, and $x$ being an ideal, this function tests whether the ideal is principal or not. The result is more complete than a simple true/false answer and solves general discrete logarithm problem. Assume the class group is $\oplus (\Z/d_i\Z)g_i$ (where the generators $g_i$ and their orders $d_i$ are respectively given by \kbd{bnf.gen} and \kbd{bnf.cyc}). The routine returns a row vector $[e,t]$, where $e$ is a vector of exponents $0 \leq e_i < d_i$, and $t$ is a number field element such that $$ x = (t) \prod_i g_i^{e_i}.$$ For \emph{given} $g_i$ (i.e. for a given \kbd{bnf}), the $e_i$ are unique, and $t$ is unique modulo units. In particular, $x$ is principal if and only if $e$ is the zero vector. Note that the empty vector, which is returned when the class number is $1$, is considered to be a zero vector (of dimension $0$). \bprog ? K = bnfinit(y^2+23); ? K.cyc %2 = [3] ? K.gen %3 = [[2, 0; 0, 1]] \\ a prime ideal above 2 ? P = idealprimedec(K,3)[1]; \\ a prime ideal above 3 ? v = bnfisprincipal(K, P) %5 = [[2]~, [3/4, 1/4]~] ? idealmul(K, v[2], idealfactorback(K, K.gen, v[1])) %6 = [3 0] [0 1] ? % == idealhnf(K, P) %7 = 1 @eprog \noindent The binary digits of \fl mean: \item $1$: If set, outputs $[e,t]$ as explained above, otherwise returns only $e$, which is much easier to compute. The following idiom only tests whether an ideal is principal: \bprog is_principal(bnf, x) = !bnfisprincipal(bnf,x,0); @eprog \item $2$: It may not be possible to recover $t$, given the initial accuracy to which the \kbd{bnf} structure was computed. In that case, a warning is printed and $t$ is set equal to the empty vector \kbd{[]\til}. If this bit is set, increase the precision and recompute needed quantities until $t$ can be computed. Warning: setting this may induce \emph{lengthy} computations. The library syntax is \fun{GEN}{bnfisprincipal0}{GEN bnf, GEN x, long flag}. Instead of the above hardcoded numerical flags, one should rather use an or-ed combination of the symbolic flags \tet{nf_GEN} (include generators, possibly a place holder if too difficult) and \tet{nf_FORCE} (insist on finding the generators). \subsec{bnfissunit$(\var{bnf},\var{sfu},x)$}\kbdsidx{bnfissunit}\label{se:bnfissunit} $\var{bnf}$ being output by \kbd{bnfinit}, \var{sfu} by \kbd{bnfsunit}, gives the column vector of exponents of $x$ on the fundamental $S$-units and the roots of unity, in the following order: the fundamental units~\var{bnf.fu}, the root of unity~\var{bnf.tu}, and the $S$-units~\var{sfu[1]}. If $x$ is not an $S$-unit, outputs an empty vector. \bprog ? bnf = bnfinit(x^4 - x^3 + 4*x^2 + 3*x + 9, 1); ? bnf.sign %2 = [0, 2] ? S = idealprimedec(bnf,5); #S %3 = 2 ? sfu = bnfsunit(bnf,S); ? sfu[1] %5 = [-5/6*x^3 + 4/3*x^2 - 4/3*x - 3/2, 5] ? u = [10,-40,24,11]~; ? bnfissunit(bnf,sfu,u) %7 = [1, Mod(2, 6), 2, 0]~ ? bnfissunit(bnf,sfu,3) %8 = []~ @eprog The library syntax is \fun{GEN}{bnfissunit}{GEN bnf, GEN sfu, GEN x}. \subsec{bnfisunit$(\var{bnf},x)$}\kbdsidx{bnfisunit}\label{se:bnfisunit} \var{bnf} being the number field data output by \kbd{bnfinit} and $x$ being an algebraic number (type integer, rational or polmod), this outputs the decomposition of $x$ on the fundamental units and the roots of unity if $x$ is a unit, the empty vector otherwise. More precisely, if $u_1$,\dots,$u_r$ are the fundamental units, and $\zeta$ is the generator of the group of roots of unity (\kbd{bnf.tu}), the output is a vector $[x_1,\dots,x_r,x_{r+1}]$ such that $x=u_1^{x_1}\cdots u_r^{x_r}\cdot\zeta^{x_{r+1}}$. The $x_i$ are integers for $i\le r$ and is an integer modulo the order of $\zeta$ for $i=r+1$. Note that \var{bnf} need not contain the fundamental unit explicitly: \bprog ? setrand(1); bnf = bnfinit(x^2-x-100000); ? bnf.fu *** at top-level: bnf.fu *** ^-- *** _.fu: missing units in .fu. ? u = [119836165644250789990462835950022871665178127611316131167, \ 379554884019013781006303254896369154068336082609238336]~; ? bnfisunit(bnf, u) %3 = [-1, Mod(0, 2)]~ @eprog\noindent The given $u$ is the inverse of the fundamental unit implicitly stored in \var{bnf}. In this case, the fundamental unit was not computed and stored in algebraic form since the default accuracy was too low. (Re-run the command at \bs g1 or higher to see such diagnostics.) The library syntax is \fun{GEN}{bnfisunit}{GEN bnf, GEN x}. \subsec{bnflog$(\var{bnf}, l)$}\kbdsidx{bnflog}\label{se:bnflog} Let \var{bnf} be a \var{bnf} structure attached to the number field $F$ and let $l$ be a prime number (hereafter denoted $\ell$ for typographical reasons). Return the logarithmic $\ell$-class group $\widetilde{Cl}_F$ of $F$. This is an abelian group, conjecturally finite (known to be finite if $F/\Q$ is abelian). The function returns if and only if the group is indeed finite (otherwise it would run into an infinite loop). Let $S = \{ \goth{p}_1,\dots, \goth{p}_k\}$ be the set of $\ell$-adic places (maximal ideals containing $\ell$). The function returns $[D, G(\ell), G']$, where \item $D$ is the vector of elementary divisors for $\widetilde{Cl}_F$. \item $G(\ell)$ is the vector of elementary divisors for the (conjecturally finite) abelian group $$\widetilde{\Cl}(\ell) = \{ \goth{a} = \sum_{i \leq k} a_i \goth{p}_i :~\deg_F \goth{a} = 0\},$$ where the $\goth{p}_i$ are the $\ell$-adic places of $F$; this is a subgroup of $\widetilde{\Cl}$. \item $G'$ is the vector of elementary divisors for the $\ell$-Sylow $Cl'$ of the $S$-class group of $F$; the group $\widetilde{\Cl}$ maps to $Cl'$ with a simple co-kernel. The library syntax is \fun{GEN}{bnflog}{GEN bnf, GEN l}. \subsec{bnflogdegree$(\var{nf}, A, l)$}\kbdsidx{bnflogdegree}\label{se:bnflogdegree} Let \var{nf} be a \var{nf} structure attached to a number field $F$, and let $l$ be a prime number (hereafter denoted $\ell$). The $\ell$-adified group of id\`{e}les of $F$ quotiented by the group of logarithmic units is identified to the $\ell$-group of logarithmic divisors $\oplus \Z_\ell [\goth{p}]$, generated by the maximal ideals of $F$. The \emph{degree} map $\deg_F$ is additive with values in $\Z_\ell$, defined by $\deg_F \goth{p} = \tilde{f}_{\goth{p}} \deg_\ell p$, where the integer $\tilde{f}_{\goth{p}}$ is as in \tet{bnflogef} and $\deg_\ell p$ is $\log_\ell p$ for $p\neq \ell$, $\log_\ell (1 + \ell)$ for $p = \ell\neq 2$ and $\log_\ell (1 + 2^2)$ for $p = \ell = 2$. Let $A = \prod \goth{p}^{n_{\goth{p}}}$ be an ideal and let $\tilde{A} = \sum n_\goth{p} [\goth{p}]$ be the attached logarithmic divisor. Return the exponential of the $\ell$-adic logarithmic degree $\deg_F A$, which is a natural number. The library syntax is \fun{GEN}{bnflogdegree}{GEN nf, GEN A, GEN l}. \subsec{bnflogef$(\var{nf},\var{pr})$}\kbdsidx{bnflogef}\label{se:bnflogef} Let \var{nf} be a \var{nf} structure attached to a number field $F$ and let \var{pr} be a \var{prid} structure attached to a maximal ideal $\goth{p} / p$. Return $[\tilde{e}(F_\goth{p} / \Q_p), \tilde{f}(F_\goth{p} / \Q_p)]$ the logarithmic ramification and residue degrees. Let $\Q_p^c/\Q_p$ be the cyclotomic $\Z_p$-extension, then $\tilde{e} = [F_\goth{p} \colon F_\goth{p} \cap \Q_p^c]$ and $\tilde{f} = [F_\goth{p} \cap \Q_p^c \colon \Q_p]$. Note that $\tilde{e}\tilde{f} = e(\goth{p}/p) f(\goth{p}/p)$, where $e(\goth{p}/p)$ and $f(\goth{p}/p)$ denote the usual ramification and residue degrees. \bprog ? F = nfinit(y^6 - 3*y^5 + 5*y^3 - 3*y + 1); ? bnflogef(F, idealprimedec(F,2)[1]) %2 = [6, 1] ? bnflogef(F, idealprimedec(F,5)[1]) %3 = [1, 2] @eprog The library syntax is \fun{GEN}{bnflogef}{GEN nf, GEN pr}. \subsec{bnfnarrow$(\var{bnf})$}\kbdsidx{bnfnarrow}\label{se:bnfnarrow} \var{bnf} being as output by \kbd{bnfinit}, computes the narrow class group of \var{bnf}. The output is a 3-component row vector $v$ analogous to the corresponding class group component \kbd{\var{bnf}.clgp}: the first component is the narrow class number \kbd{$v$.no}, the second component is a vector containing the SNF\sidx{Smith normal form} cyclic components \kbd{$v$.cyc} of the narrow class group, and the third is a vector giving the generators of the corresponding \kbd{$v$.gen} cyclic groups. Note that this function is a special case of \kbd{bnrinit}; the \var{bnf} need not contain fundamental units. The library syntax is \fun{GEN}{bnfnarrow}{GEN bnf}. \subsec{bnfsignunit$(\var{bnf})$}\kbdsidx{bnfsignunit}\label{se:bnfsignunit} $\var{bnf}$ being as output by \kbd{bnfinit}, this computes an $r_1\times(r_1+r_2-1)$ matrix having $\pm1$ components, giving the signs of the real embeddings of the fundamental units. The following functions compute generators for the totally positive units: \bprog /* exponents of totally positive units generators on bnf.tufu */ tpuexpo(bnf)= { my(K, S = bnfsignunit(bnf), [m,n] = matsize(S)); \\ m = bnf.r1, n = r1+r2-1 S = matrix(m,n, i,j, if (S[i,j] < 0, 1,0)); S = concat(vectorv(m,i,1), S); \\ add sign(-1) K = matker(S * Mod(1,2)); if (K, mathnfmodid(lift(K), 2), 2*matid(n+1)) } /* totally positive fundamental units */ tpu(bnf)= { my(ex = tpuexpo(bnf)[,2..-1]); \\ remove ex[,1], corresponds to 1 or -1 vector(#ex, i, nffactorback(bnf, bnf.tufu, ex[,i])); } @eprog The library syntax is \fun{GEN}{signunits}{GEN bnf}. \subsec{bnfsunit$(\var{bnf},S)$}\kbdsidx{bnfsunit}\label{se:bnfsunit} Computes the fundamental $S$-units of the number field $\var{bnf}$ (output by \kbd{bnfinit}), where $S$ is a list of prime ideals (output by \kbd{idealprimedec}). The output is a vector $v$ with 6 components. $v[1]$ gives a minimal system of (integral) generators of the $S$-unit group modulo the unit group. $v[2]$ contains technical data needed by \kbd{bnfissunit}. $v[3]$ is an empty vector (used to give the logarithmic embeddings of the generators in $v[1]$ in version 2.0.16). $v[4]$ is the $S$-regulator (this is the product of the regulator, the determinant of $v[2]$ and the natural logarithms of the norms of the ideals in $S$). $v[5]$ gives the $S$-class group structure, in the usual format (a row vector whose three components give in order the $S$-class number, the cyclic components and the generators). $v[6]$ is a copy of $S$. The library syntax is \fun{GEN}{bnfsunit}{GEN bnf, GEN S, long prec}. \subsec{bnrL1$(\var{bnr}, \{H\}, \{\fl=0\})$}\kbdsidx{bnrL1}\label{se:bnrL1} Let \var{bnr} be the number field data output by \kbd{bnrinit} and \var{H} be a square matrix defining a congruence subgroup of the ray class group corresponding to \var{bnr} (the trivial congruence subgroup if omitted). This function returns, for each \idx{character} $\chi$ of the ray class group which is trivial on $H$, the value at $s = 1$ (or $s = 0$) of the abelian $L$-function attached to $\chi$. For the value at $s = 0$, the function returns in fact for each $\chi$ a vector $[r_\chi, c_\chi]$ where $$L(s, \chi) = c \cdot s^r + O(s^{r + 1})$$ \noindent near $0$. The argument \fl\ is optional, its binary digits mean 1: compute at $s = 0$ if unset or $s = 1$ if set, 2: compute the primitive $L$-function attached to $\chi$ if unset or the $L$-function with Euler factors at prime ideals dividing the modulus of \var{bnr} removed if set (that is $L_S(s, \chi)$, where $S$ is the set of infinite places of the number field together with the finite prime ideals dividing the modulus of \var{bnr}), 3: return also the character if set. \bprog K = bnfinit(x^2-229); bnr = bnrinit(K,1); bnrL1(bnr) @eprog\noindent returns the order and the first non-zero term of $L(s, \chi)$ at $s = 0$ where $\chi$ runs through the characters of the class group of $K = \Q(\sqrt{229})$. Then \bprog bnr2 = bnrinit(K,2); bnrL1(bnr2,,2) @eprog\noindent returns the order and the first non-zero terms of $L_S(s, \chi)$ at $s = 0$ where $\chi$ runs through the characters of the class group of $K$ and $S$ is the set of infinite places of $K$ together with the finite prime $2$. Note that the ray class group modulo $2$ is in fact the class group, so \kbd{bnrL1(bnr2,0)} returns the same answer as \kbd{bnrL1(bnr,0)}. This function will fail with the message \bprog *** bnrL1: overflow in zeta_get_N0 [need too many primes]. @eprog\noindent if the approximate functional equation requires us to sum too many terms (if the discriminant of $K$ is too large). The library syntax is \fun{GEN}{bnrL1}{GEN bnr, GEN H = NULL, long flag, long prec}. \subsec{bnrchar$(\var{bnr},g,\{v\})$}\kbdsidx{bnrchar}\label{se:bnrchar} Returns all characters $\chi$ on \kbd{bnr.clgp} such that $\chi(g_i) = e(v_i)$, where $e(x) = \exp(2i\pi x)$. If $v$ is omitted, returns all characters that are trivial on the $g_i$. Else the vectors $g$ and $v$ must have the same length, the $g_i$ must be ideals in any form, and each $v_i$ is a rational number whose denominator must divide the order of $g_i$ in the ray class group. For convenience, the vector of the $g_i$ can be replaced by a matrix whose columns give their discrete logarithm, as given by \kbd{bnrisprincipal}; this allows to specify abstractly a subgroup of the ray class group. \bprog ? bnr = bnrinit(bnfinit(x), [160,[1]], 1); /* (Z/160Z)^* */ ? bnr.cyc %2 = [8, 4, 2] ? g = bnr.gen; ? bnrchar(bnr, g, [1/2,0,0]) %4 = [[4, 0, 0]] \\ a unique character ? bnrchar(bnr, [g[1],g[3]]) \\ all characters trivial on g[1] and g[3] %5 = [[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 0, 0]] ? bnrchar(bnr, [1,0,0;0,1,0;0,0,2]) %6 = [[0, 0, 1], [0, 0, 0]] \\ characters trivial on given subgroup @eprog The library syntax is \fun{GEN}{bnrchar}{GEN bnr, GEN g, GEN v = NULL}. \subsec{bnrclassno$(A,\{B\},\{C\})$}\kbdsidx{bnrclassno}\label{se:bnrclassno} Let $A$, $B$, $C$ define a class field $L$ over a ground field $K$ (of type \kbd{[\var{bnr}]}, \kbd{[\var{bnr}, \var{subgroup}]}, or \kbd{[\var{bnf}, \var{modulus}]}, or \kbd{[\var{bnf}, \var{modulus},\var{subgroup}]}, \secref{se:CFT}); this function returns the relative degree $[L:K]$. In particular if $A$ is a \var{bnf} (with units), and $B$ a modulus, this function returns the corresponding ray class number modulo $B$. One can input the attached \var{bid} (with generators if the subgroup $C$ is non trivial) for $B$ instead of the module itself, saving some time. This function is faster than \kbd{bnrinit} and should be used if only the ray class number is desired. See \tet{bnrclassnolist} if you need ray class numbers for all moduli less than some bound. The library syntax is \fun{GEN}{bnrclassno0}{GEN A, GEN B = NULL, GEN C = NULL}. Also available is \fun{GEN}{bnrclassno}{GEN bnf,GEN f} to compute the ray class number modulo~$f$. \subsec{bnrclassnolist$(\var{bnf},\var{list})$}\kbdsidx{bnrclassnolist}\label{se:bnrclassnolist} $\var{bnf}$ being as output by \kbd{bnfinit}, and \var{list} being a list of moduli (with units) as output by \kbd{ideallist} or \kbd{ideallistarch}, outputs the list of the class numbers of the corresponding ray class groups. To compute a single class number, \tet{bnrclassno} is more efficient. \bprog ? bnf = bnfinit(x^2 - 2); ? L = ideallist(bnf, 100, 2); ? H = bnrclassnolist(bnf, L); ? H[98] %4 = [1, 3, 1] ? l = L[1][98]; ids = vector(#l, i, l[i].mod[1]) %5 = [[98, 88; 0, 1], [14, 0; 0, 7], [98, 10; 0, 1]] @eprog The weird \kbd{l[i].mod[1]}, is the first component of \kbd{l[i].mod}, i.e. the finite part of the conductor. (This is cosmetic: since by construction the Archimedean part is trivial, I do not want to see it). This tells us that the ray class groups modulo the ideals of norm 98 (printed as \kbd{\%5}) have respectively order $1$, $3$ and $1$. Indeed, we may check directly: \bprog ? bnrclassno(bnf, ids[2]) %6 = 3 @eprog The library syntax is \fun{GEN}{bnrclassnolist}{GEN bnf, GEN list}. \subsec{bnrconductor$(A,\{B\},\{C\},\{\fl=0\})$}\kbdsidx{bnrconductor}\label{se:bnrconductor} Conductor $f$ of the subfield of a ray class field as defined by $[A,B,C]$ (of type \kbd{[\var{bnr}]}, \kbd{[\var{bnr}, \var{subgroup}]}, \kbd{[\var{bnf}, \var{modulus}]} or \kbd{[\var{bnf}, \var{modulus}, \var{subgroup}]}, \secref{se:CFT}) If $\fl = 0$, returns $f$. If $\fl = 1$, returns $[f, Cl_f, H]$, where $Cl_f$ is the ray class group modulo $f$, as a finite abelian group; finally $H$ is the subgroup of $Cl_f$ defining the extension. If $\fl = 2$, returns $[f, \var{bnr}(f), H]$, as above except $Cl_f$ is replaced by a \kbd{bnr} structure, as output by $\tet{bnrinit}(,f)$, without generators unless the input contained a \var{bnr} with generators. In place of a subgroup $H$, this function also accepts a character \kbd{chi} $=(a_j)$, expressed as usual in terms of the generators \kbd{bnr.gen}: $\chi(g_j) = \exp(2i\pi a_j / d_j)$, where $g_j$ has order $d_j = \kbd{bnr.cyc[j]}$. In which case, the function returns respectively If $\fl = 0$, the conductor $f$ of $\text{Ker} \chi$. If $\fl = 1$, $[f, Cl_f, \chi_f]$, where $\chi_f$ is $\chi$ expressed on the minimal ray class group, whose modulus is the conductor. If $\fl = 2$, $[f, \var{bnr}(f), \chi_f]$. The library syntax is \fun{GEN}{bnrconductor0}{GEN A, GEN B = NULL, GEN C = NULL, long flag}. Also available is \fun{GEN}{bnrconductor}{GEN bnr, GEN H, long flag} \subsec{bnrconductorofchar$(\var{bnr},\var{chi})$}\kbdsidx{bnrconductorofchar}\label{se:bnrconductorofchar} This function is obsolete, use \tev{bnrconductor}. The library syntax is \fun{GEN}{bnrconductorofchar}{GEN bnr, GEN chi}. \subsec{bnrdisc$(A,\{B\},\{C\},\{\fl=0\})$}\kbdsidx{bnrdisc}\label{se:bnrdisc} $A$, $B$, $C$ defining a class field $L$ over a ground field $K$ (of type \kbd{[\var{bnr}]}, \kbd{[\var{bnr}, \var{subgroup}]}, \kbd{[\var{bnr}, \var{character}]}, \kbd{[\var{bnf}, \var{modulus}]} or \kbd{[\var{bnf}, \var{modulus}, \var{subgroup}]}, \secref{se:CFT}), outputs data $[N,r_1,D]$ giving the discriminant and signature of $L$, depending on the binary digits of \fl: \item 1: if this bit is unset, output absolute data related to $L/\Q$: $N$ is the absolute degree $[L:\Q]$, $r_1$ the number of real places of $L$, and $D$ the discriminant of $L/\Q$. Otherwise, output relative data for $L/K$: $N$ is the relative degree $[L:K]$, $r_1$ is the number of real places of $K$ unramified in $L$ (so that the number of real places of $L$ is equal to $r_1$ times $N$), and $D$ is the relative discriminant ideal of $L/K$. \item 2: if this bit is set and if the modulus is not the conductor of $L$, only return 0. The library syntax is \fun{GEN}{bnrdisc0}{GEN A, GEN B = NULL, GEN C = NULL, long flag}. \subsec{bnrdisclist$(\var{bnf},\var{bound},\{\var{arch}\})$}\kbdsidx{bnrdisclist}\label{se:bnrdisclist} $\var{bnf}$ being as output by \kbd{bnfinit} (with units), computes a list of discriminants of Abelian extensions of the number field by increasing modulus norm up to bound \var{bound}. The ramified Archimedean places are given by \var{arch}; all possible values are taken if \var{arch} is omitted. The alternative syntax $\kbd{bnrdisclist}(\var{bnf},\var{list})$ is supported, where \var{list} is as output by \kbd{ideallist} or \kbd{ideallistarch} (with units), in which case \var{arch} is disregarded. The output $v$ is a vector, where $v[k]$ is itself a vector $w$, whose length is the number of ideals of norm $k$. \item We consider first the case where \var{arch} was specified. Each component of $w$ corresponds to an ideal $m$ of norm $k$, and gives invariants attached to the ray class field $L$ of $\var{bnf}$ of conductor $[m, \var{arch}]$. Namely, each contains a vector $[m,d,r,D]$ with the following meaning: $m$ is the prime ideal factorization of the modulus, $d = [L:\Q]$ is the absolute degree of $L$, $r$ is the number of real places of $L$, and $D$ is the factorization of its absolute discriminant. We set $d = r = D = 0$ if $m$ is not the finite part of a conductor. \item If \var{arch} was omitted, all $t = 2^{r_1}$ possible values are taken and a component of $w$ has the form $[m, [[d_1,r_1,D_1], \dots, [d_t,r_t,D_t]]]$, where $m$ is the finite part of the conductor as above, and $[d_i,r_i,D_i]$ are the invariants of the ray class field of conductor $[m,v_i]$, where $v_i$ is the $i$-th Archimedean component, ordered by inverse lexicographic order; so $v_1 = [0,\dots,0]$, $v_2 = [1,0\dots,0]$, etc. Again, we set $d_i = r_i = D_i = 0$ if $[m,v_i]$ is not a conductor. Finally, each prime ideal $pr = [p,\alpha,e,f,\beta]$ in the prime factorization $m$ is coded as the integer $p\cdot n^2+(f-1)\cdot n+(j-1)$, where $n$ is the degree of the base field and $j$ is such that \kbd{pr = idealprimedec(\var{nf},p)[j]}. \noindent $m$ can be decoded using \tet{bnfdecodemodule}. Note that to compute such data for a single field, either \tet{bnrclassno} or \tet{bnrdisc} are (much) more efficient. The library syntax is \fun{GEN}{bnrdisclist0}{GEN bnf, GEN bound, GEN arch = NULL}. \subsec{bnrgaloisapply$(\var{bnr}, \var{mat}, H)$}\kbdsidx{bnrgaloisapply}\label{se:bnrgaloisapply} Apply the automorphism given by its matrix \var{mat} to the congruence subgroup $H$ given as a HNF matrix. The matrix \var{mat} can be computed with \tet{bnrgaloismatrix}. The library syntax is \fun{GEN}{bnrgaloisapply}{GEN bnr, GEN mat, GEN H}. \subsec{bnrgaloismatrix$(\var{bnr},\var{aut})$}\kbdsidx{bnrgaloismatrix}\label{se:bnrgaloismatrix} Return the matrix of the action of the automorphism \var{aut} of the base field \kbd{bnf.nf} on the generators of the ray class field \kbd{bnr.gen}. \var{aut} can be given as a polynomial, an algebraic number, or a vector of automorphisms or a Galois group as output by \kbd{galoisinit}, in which case a vector of matrices is returned (in the later case, only for the generators \kbd{aut.gen}). See \kbd{bnrisgalois} for an example. The library syntax is \fun{GEN}{bnrgaloismatrix}{GEN bnr, GEN aut}. When $aut$ is a polynomial or an algebraic number, \fun{GEN}{bnrautmatrix}{GEN bnr, GEN aut} is available. \subsec{bnrinit$(\var{bnf},f,\{\fl=0\})$}\kbdsidx{bnrinit}\label{se:bnrinit} $\var{bnf}$ is as output by \kbd{bnfinit} (including fundamental units), $f$ is a modulus, initializes data linked to the ray class group structure corresponding to this module, a so-called \kbd{bnr} structure. One can input the attached \var{bid} with generators for $f$ instead of the module itself, saving some time. (As in \tet{idealstar}, the finite part of the conductor may be given by a factorization into prime ideals, as produced by \tet{idealfactor}.) The following member functions are available on the result: \kbd{.bnf} is the underlying \var{bnf}, \kbd{.mod} the modulus, \kbd{.bid} the \kbd{bid} structure attached to the modulus; finally, \kbd{.clgp}, \kbd{.no}, \kbd{.cyc}, \kbd{.gen} refer to the ray class group (as a finite abelian group), its cardinality, its elementary divisors, its generators (only computed if $\fl = 1$). The last group of functions are different from the members of the underlying \var{bnf}, which refer to the class group; use \kbd{\var{bnr}.bnf.\var{xxx}} to access these, e.g.~\kbd{\var{bnr}.bnf.cyc} to get the cyclic decomposition of the class group. They are also different from the members of the underlying \var{bid}, which refer to $(\Z_K/f)^*$; use \kbd{\var{bnr}.bid.\var{xxx}} to access these, e.g.~\kbd{\var{bnr}.bid.no} to get $\phi(f)$. If $\fl=0$ (default), the generators of the ray class group are not computed, which saves time. Hence \kbd{\var{bnr}.gen} would produce an error. If $\fl=1$, as the default, except that generators are computed. The library syntax is \fun{GEN}{bnrinit0}{GEN bnf, GEN f, long flag}. Instead the above hardcoded numerical flags, one should rather use \fun{GEN}{Buchray}{GEN bnf, GEN module, long flag} where flag is an or-ed combination of \kbd{nf\_GEN} (include generators) and \kbd{nf\_INIT} (if omitted, return just the cardinality of the ray class group and its structure), possibly 0. \subsec{bnrisconductor$(A,\{B\},\{C\})$}\kbdsidx{bnrisconductor}\label{se:bnrisconductor} Fast variant of \kbd{bnrconductor}$(A,B,C)$; $A$, $B$, $C$ represent an extension of the base field, given by class field theory (see~\secref{se:CFT}). Outputs 1 if this modulus is the conductor, and 0 otherwise. This is slightly faster than \kbd{bnrconductor} when the character or subgroup is not primitive. The library syntax is \fun{long}{bnrisconductor0}{GEN A, GEN B = NULL, GEN C = NULL}. \subsec{bnrisgalois$(\var{bnr}, \var{gal}, H)$}\kbdsidx{bnrisgalois}\label{se:bnrisgalois} Check whether the class field attached to the subgroup $H$ is Galois over the subfield of \kbd{bnr.nf} fixed by the group \var{gal}, which can be given as output by \tet{galoisinit}, or as a matrix or a vector of matrices as output by \kbd{bnrgaloismatrix}, the second option being preferable, since it saves the recomputation of the matrices. Note: The function assumes that the ray class field attached to bnr is Galois, which is not checked. In the following example, we lists the congruence subgroups of subextension of degree at most $3$ of the ray class field of conductor $9$ which are Galois over the rationals. \bprog K=bnfinit(a^4-3*a^2+253009); G=galoisinit(K); B=bnrinit(K,9,1); L1=[H|H<-subgrouplist(B,3), bnrisgalois(B,G,H)] ## M=bnrgaloismatrix(B,G) L2=[H|H<-subgrouplist(B,3), bnrisgalois(B,M,H)] ## @eprog The second computation is much faster since \kbd{bnrgaloismatrix(B,G)} is computed only once. The library syntax is \fun{long}{bnrisgalois}{GEN bnr, GEN gal, GEN H}. \subsec{bnrisprincipal$(\var{bnr},x,\{\fl=1\})$}\kbdsidx{bnrisprincipal}\label{se:bnrisprincipal} Let \var{bnr} be the ray class group data output by \kbd{bnrinit}$(,,1)$ and let $x$ be an ideal in any form, coprime to the modulus $f = \kbd{bnr.mod}$. Solves the discrete logarithm problem in the ray class group, with respect to the generators \kbd{bnr.gen}, in a way similar to \tet{bnfisprincipal}. If $x$ is not coprime to the modulus of \var{bnr} the result is undefined. If $\fl = 1$, returns a 2-component vector $v$ where $v[1]$ is the vector of components of $x$ on the ray class group generators, $v[2]$ is an element $\alpha$ congruent to $1~\text{mod}^* f$ such that $x = \alpha \prod_i g_i^{x_i}$. If $\fl=0$, outputs only $v_1$. In that case, \var{bnr} need not contain the ray class group generators, i.e.~it may be created with \kbd{bnrinit}$(,,0)$; in that case, although \kbd{bnr.gen} is undefined, we can still define canonical generators attached to the \kbd{bnr} and compute with respect to them. \bprog ? K = bnfinit(x^2 - 30); bnr = bnrinit(K, [4, [1,1]]); ? bnr.clgp \\ ray class group is isomorphic to Z/4 x Z/2 x Z/2 %2 = [16, [4, 2, 2]] ? P = idealprimedec(K, 3)[1]; \\ a prime ideal above 3 ? bnrisprincipal(bnr,P) %4 = [[1, 0, 0]~, 1] ? bnrisprincipal(bnr,P, 0) \\ omit the principal part %4 = [1, 0, 0]~ @eprog The library syntax is \fun{GEN}{bnrisprincipal}{GEN bnr, GEN x, long flag}. Instead of hardcoded numerical flags, one should rather use \fun{GEN}{isprincipalray}{GEN bnr, GEN x} for $\kbd{flag} = 0$, and if you want generators: \bprog bnrisprincipal(bnr, x, nf_GEN) @eprog \subsec{bnrrootnumber$(\var{bnr},\var{chi},\{\fl=0\})$}\kbdsidx{bnrrootnumber}\label{se:bnrrootnumber} If $\chi=\var{chi}$ is a \idx{character} over \var{bnr}, not necessarily primitive, let $L(s,\chi) = \sum_{id} \chi(id) N(id)^{-s}$ be the attached \idx{Artin L-function}. Returns the so-called \idx{Artin root number}, i.e.~the complex number $W(\chi)$ of modulus 1 such that % $$\Lambda(1-s,\chi) = W(\chi) \Lambda(s,\overline{\chi})$$ % \noindent where $\Lambda(s,\chi) = A(\chi)^{s/2}\gamma_\chi(s) L(s,\chi)$ is the enlarged L-function attached to $L$. You can set $\fl=1$ if the character is known to be primitive. Example: \bprog bnf = bnfinit(x^2 - x - 57); bnr = bnrinit(bnf, [7,[1,1]]); bnrrootnumber(bnr, [2,1]) @eprog\noindent returns the root number of the character $\chi$ of $\Cl_{7\infty_1\infty_2}(\Q(\sqrt{229}))$ defined by $\chi(g_1^ag_2^b) = \zeta_1^{2a}\zeta_2^b$. Here $g_1, g_2$ are the generators of the ray-class group given by \kbd{bnr.gen} and $\zeta_1 = e^{2i\pi/N_1}, \zeta_2 = e^{2i\pi/N_2}$ where $N_1, N_2$ are the orders of $g_1$ and $g_2$ respectively ($N_1=6$ and $N_2=3$ as \kbd{bnr.cyc} readily tells us). The library syntax is \fun{GEN}{bnrrootnumber}{GEN bnr, GEN chi, long flag, long prec}. \subsec{bnrstark$(\var{bnr},\{\var{subgroup}\})$}\kbdsidx{bnrstark}\label{se:bnrstark} \var{bnr} being as output by \kbd{bnrinit}, finds a relative equation for the class field corresponding to the modulus in \var{bnr} and the given congruence subgroup (as usual, omit $\var{subgroup}$ if you want the whole ray class group). The main variable of \var{bnr} must not be $x$, and the ground field and the class field must be totally real. When the base field is $\Q$, the vastly simpler \tet{galoissubcyclo} is used instead. Here is an example: \bprog bnf = bnfinit(y^2 - 3); bnr = bnrinit(bnf, 5); bnrstark(bnr) @eprog\noindent returns the ray class field of $\Q(\sqrt{3})$ modulo $5$. Usually, one wants to apply to the result one of \bprog rnfpolredabs(bnf, pol, 16) \\@com compute a reduced relative polynomial rnfpolredabs(bnf, pol, 16 + 2) \\@com compute a reduced absolute polynomial @eprog The routine uses \idx{Stark units} and needs to find a suitable auxiliary conductor, which may not exist when the class field is not cyclic over the base. In this case \kbd{bnrstark} is allowed to return a vector of polynomials defining \emph{independent} relative extensions, whose compositum is the requested class field. It was decided that it was more useful to keep the extra information thus made available, hence the user has to take the compositum herself. Even if it exists, the auxiliary conductor may be so large that later computations become unfeasible. (And of course, Stark's conjecture may simply be wrong.) In case of difficulties, try \tet{rnfkummer}: \bprog ? bnr = bnrinit(bnfinit(y^8-12*y^6+36*y^4-36*y^2+9,1), 2); ? bnrstark(bnr) *** at top-level: bnrstark(bnr) *** ^------------- *** bnrstark: need 3919350809720744 coefficients in initzeta. *** Computation impossible. ? lift( rnfkummer(bnr) ) time = 24 ms. %2 = x^2 + (1/3*y^6 - 11/3*y^4 + 8*y^2 - 5) @eprog The library syntax is \fun{GEN}{bnrstark}{GEN bnr, GEN subgroup = NULL, long prec}. \subsec{dirzetak$(\var{nf},b)$}\kbdsidx{dirzetak}\label{se:dirzetak} Gives as a vector the first $b$ coefficients of the \idx{Dedekind} zeta function of the number field $\var{nf}$ considered as a \idx{Dirichlet series}. The library syntax is \fun{GEN}{dirzetak}{GEN nf, GEN b}. \subsec{factornf$(x,t)$}\kbdsidx{factornf}\label{se:factornf} This function is obsolete, use \kbd{nffactor}. factorization of the univariate polynomial $x$ over the number field defined by the (univariate) polynomial $t$. $x$ may have coefficients in $\Q$ or in the number field. The algorithm reduces to factorization over $\Q$ (\idx{Trager}'s trick). The direct approach of \tet{nffactor}, which uses \idx{van Hoeij}'s method in a relative setting, is in general faster. The main variable of $t$ must be of \emph{lower} priority than that of $x$ (see \secref{se:priority}). However if non-rational number field elements occur (as polmods or polynomials) as coefficients of $x$, the variable of these polmods \emph{must} be the same as the main variable of $t$. For example \bprog ? factornf(x^2 + Mod(y, y^2+1), y^2+1); ? factornf(x^2 + y, y^2+1); \\@com these two are OK ? factornf(x^2 + Mod(z,z^2+1), y^2+1) *** at top-level: factornf(x^2+Mod(z,z *** ^-------------------- *** factornf: inconsistent data in rnf function. ? factornf(x^2 + z, y^2+1) *** at top-level: factornf(x^2+z,y^2+1 *** ^-------------------- *** factornf: incorrect variable in rnf function. @eprog The library syntax is \fun{GEN}{polfnf}{GEN x, GEN t}. \subsec{galoischardet$(\var{gal}, \var{chi}, \{o=1\})$}\kbdsidx{galoischardet}\label{se:galoischardet} Let $G$ be the group attached to the \kbd{galoisinit} structure~\var{gal}, and let $\chi$ be the character of some representation $\rho$ of the group $G$, where a polynomial variable is to be interpreted as an $o$-th root of 1. For instance, if \kbd{[T,o] = galoischartable(gal)} the characters $\chi$ are input as the columns of \kbd{T}. Return the degree-$1$ character $\det\rho$ as the list of $\det \rho(g)$, where $g$ runs through representatives of the conjugacy classes in \kbd{galoisconjclasses(gal)}, with the same ordering. \bprog ? P = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; ? polgalois(P) %2 = [10, 1, 1, "D(5) = 5:2"] ? K = nfsplitting(P); ? gal = galoisinit(K); \\ dihedral of order 10 ? [T,o] = galoischartable(gal); ? chi = T[,1]; \\ trivial character ? galoischardet(gal, chi, o) %7 = [1, 1, 1, 1]~ ? [galoischardet(gal, T[,i], o) | i <- [1..#T]] \\ all characters %8 = [[1, 1, 1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~] @eprog The library syntax is \fun{GEN}{galoischardet}{GEN gal, GEN chi, long o}. \subsec{galoischarpoly$(\var{gal}, \var{chi}, \{o=1\})$}\kbdsidx{galoischarpoly}\label{se:galoischarpoly} Let $G$ be the group attached to the \kbd{galoisinit} structure~\var{gal}, and let $\chi$ be the character of some representation $\rho$ of the group $G$, where a polynomial variable is to be interpreted as an $o$-th root of 1, e.g., if \kbd{[T,o] = galoischartable(gal)} and $\chi$ is a column of \kbd{T}. Return the list of characteristic polynomials $\det(1 - \rho(g)T)$, where $g$ runs through representatives of the conjugacy classes in \kbd{galoisconjclasses(gal)}, with the same ordering. \bprog ? T = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; ? polgalois(T) %2 = [10, 1, 1, "D(5) = 5:2"] ? K = nfsplitting(T); ? gal = galoisinit(K); \\ dihedral of order 10 ? [T,o] = galoischartable(gal); ? o %5 = 5 ? galoischarpoly(gal, T[,1], o) \\ T[,1] is the trivial character %6 = [-x + 1, -x + 1, -x + 1, -x + 1]~ ? galoischarpoly(gal, T[,3], o) %7 = [x^2 - 2*x + 1, x^2 + (y^3 + y^2 + 1)*x + 1, -x^2 + 1, x^2 + (-y^3 - y^2)*x + 1]~ @eprog The library syntax is \fun{GEN}{galoischarpoly}{GEN gal, GEN chi, long o}. \subsec{galoischartable$(\var{gal})$}\kbdsidx{galoischartable}\label{se:galoischartable} Compute the character table of~$G$, where~$G$ is the underlying group of the \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed to be a \typ{VEC} of permutations that is closed under products. Let~$N$ be the number of conjugacy classes of~$G$. Return a \typ{VEC}~$[M,\var{e}]$ where $e \geq 1$ is an integer and $M$ is a square \typ{MAT} of size~$N$ giving the character table of~$G$. \item Each column corresponds to an irreducible character; the characters are ordered by increasing dimension and the first column is the trivial character (hence contains only $1$'s). \item Each row corresponds to a conjugacy class; the conjugacy classes are ordered as specified by \kbd{galoisconjclasses(gal)}, in particular the first row corresponds to the identity and gives the dimension $\chi(1)$ of the irreducible representation attached to the successive characters $\chi$. The value $M[i,j]$ of the character $j$ at the conjugacy class $i$ is represented by a polynomial in \kbd{y} whose variable should be interpreted as an $e$-th root of unity, i.e. as the lift of \bprog Mod(y, polcyclo(e,'y)) @eprog\noindent (Note that $M$ is the transpose of the usual orientation for character tables.) The integer $e$ divides the exponent of the group $G$ and is chosen as small as posible; for instance $e = 1$ when the characters are all defined over $\Q$, as is the case for $S_n$. Examples: \bprog ? K = nfsplitting(x^4+x+1); ? gal = galoisinit(K); ? [M,e] = galoischartable(gal); ? M~ \\ take the transpose to get the usual orientation %4 = [1 1 1 1 1] [1 -1 -1 1 1] [2 0 0 -1 2] [3 -1 1 0 -1] [3 1 -1 0 -1] ? e %5 = 1 ? {G = [Vecsmall([1, 2, 3, 4, 5]), Vecsmall([1, 5, 4, 3, 2]), Vecsmall([2, 1, 5, 4, 3]), Vecsmall([2, 3, 4, 5, 1]), Vecsmall([3, 2, 1, 5, 4]), Vecsmall([3, 4, 5, 1, 2]), Vecsmall([4, 3, 2, 1, 5]), Vecsmall([4, 5, 1, 2, 3]), Vecsmall([5, 1, 2, 3, 4]), Vecsmall([5, 4, 3, 2, 1])];} \\G = D10 ? [M,e] = galoischartable(G); ? M~ %8 = [1 1 1 1] [1 -1 1 1] [2 0 -y^3 - y^2 - 1 y^3 + y^2] [2 0 y^3 + y^2 -y^3 - y^2 - 1] ? e %9 = 5 @eprog The library syntax is \fun{GEN}{galoischartable}{GEN gal}. \subsec{galoisconjclasses$(\var{gal})$}\kbdsidx{galoisconjclasses}\label{se:galoisconjclasses} \var{gal} being output by \kbd{galoisinit}, return the list of conjugacy classes of the underlying group. The ordering of the classes is consistent with \kbd{galoischartable} and the trivial class comes first. \bprog ? G = galoisinit(x^6+108); ? galoisidentify(G) %2 = [6, 1] \\ S_3 ? S = galoisconjclasses(G) %3 = [[Vecsmall([1,2,3,4,5,6])], [Vecsmall([3,1,2,6,4,5]),Vecsmall([2,3,1,5,6,4])], [Vecsmall([6,5,4,3,2,1]),Vecsmall([5,4,6,2,1,3]), Vecsmall([4,6,5,1,3,2])]] ? [[permorder(c[1]),#c] | c <- S ] %4 = [[1,1], [3,2], [2,3]] @eprog\noindent This command also accepts subgroups returned by \kbd{galoissubgroups}: \bprog ? subs = galoissubgroups(G); H = subs[5]; ? galoisidentify(H) %2 = [2, 1] \\ Z/2 ? S = galoisconjclasses(subgroups_of_G[5]); ? [[permorder(c[1]),#c] | c <- S ] %4 = [[1,1], [2,1]] @eprog\noindent The library syntax is \fun{GEN}{galoisconjclasses}{GEN gal}. \subsec{galoisexport$(\var{gal},\{\fl\})$}\kbdsidx{galoisexport}\label{se:galoisexport} \var{gal} being be a Galois group as output by \tet{galoisinit}, export the underlying permutation group as a string suitable for (no flags or $\fl=0$) GAP or ($\fl=1$) Magma. The following example compute the index of the underlying abstract group in the GAP library: \bprog ? G = galoisinit(x^6+108); ? s = galoisexport(G) %2 = "Group((1, 2, 3)(4, 5, 6), (1, 4)(2, 6)(3, 5))" ? extern("echo \"IdGroup("s");\" | gap -q") %3 = [6, 1] ? galoisidentify(G) %4 = [6, 1] @eprog\noindent This command also accepts subgroups returned by \kbd{galoissubgroups}. To \emph{import} a GAP permutation into gp (for \tet{galoissubfields} for instance), the following GAP function may be useful: \bprog PermToGP := function(p, n) return Permuted([1..n],p); end; gap> p:= (1,26)(2,5)(3,17)(4,32)(6,9)(7,11)(8,24)(10,13)(12,15)(14,27) (16,22)(18,28)(19,20)(21,29)(23,31)(25,30) gap> PermToGP(p,32); [ 26, 5, 17, 32, 2, 9, 11, 24, 6, 13, 7, 15, 10, 27, 12, 22, 3, 28, 20, 19, 29, 16, 31, 8, 30, 1, 14, 18, 21, 25, 23, 4 ] @eprog The library syntax is \fun{GEN}{galoisexport}{GEN gal, long flag}. \subsec{galoisfixedfield$(\var{gal},\var{perm},\{\fl\},\{v=y\})$}\kbdsidx{galoisfixedfield}\label{se:galoisfixedfield} \var{gal} being be a Galois group as output by \tet{galoisinit} and \var{perm} an element of $\var{gal}.group$, a vector of such elements or a subgroup of \var{gal} as returned by galoissubgroups, computes the fixed field of \var{gal} by the automorphism defined by the permutations \var{perm} of the roots $\var{gal}.roots$. $P$ is guaranteed to be squarefree modulo $\var{gal}.p$. If no flags or $\fl=0$, output format is the same as for \tet{nfsubfield}, returning $[P,x]$ such that $P$ is a polynomial defining the fixed field, and $x$ is a root of $P$ expressed as a polmod in $\var{gal}.pol$. If $\fl=1$ return only the polynomial $P$. If $\fl=2$ return $[P,x,F]$ where $P$ and $x$ are as above and $F$ is the factorization of $\var{gal}.pol$ over the field defined by $P$, where variable $v$ ($y$ by default) stands for a root of $P$. The priority of $v$ must be less than the priority of the variable of $\var{gal}.pol$ (see \secref{se:priority}). In this case, $P$ is also expressed in the variable $v$ for compatibility with $F$. Example: \bprog ? G = galoisinit(x^4+1); ? galoisfixedfield(G,G.group[2],2) %2 = [y^2 - 2, Mod(- x^3 + x, x^4 + 1), [x^2 - y*x + 1, x^2 + y*x + 1]] @eprog\noindent computes the factorization $x^4+1=(x^2-\sqrt{2}x+1)(x^2+\sqrt{2}x+1)$ The library syntax is \fun{GEN}{galoisfixedfield}{GEN gal, GEN perm, long flag, long v = -1} where \kbd{v} is a variable number. \subsec{galoisgetgroup$(a,\{b\})$}\kbdsidx{galoisgetgroup}\label{se:galoisgetgroup} Query the \kbd{galpol} package for a group of order $a$ with index $b$ in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and Eamonn O'Brien. The current version of \kbd{galpol} supports groups of order $a\leq 143$. If $b$ is omitted, return the number of isomorphism classes of groups of order $a$. The library syntax is \fun{GEN}{galoisgetgroup}{long a, long b}. Also available is \fun{GEN}{galoisnbpol}{long a} when $b$ is omitted. \subsec{galoisgetname$(a,b)$}\kbdsidx{galoisgetname}\label{se:galoisgetname} Query the \kbd{galpol} package for a string describing the group of order $a$ with index $b$ in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and Eamonn O'Brien. The strings were generated using the GAP4 function \kbd{StructureDescription}. It is possible for different groups to have the same name. The command below outputs the names of all abstract groups of order 12: \bprog ? N = galoisgetgroup(12); \\ # of abstract groups of order 12 ? for(i=1, N, print(i,". ",galoisgetname(12,i))) 1. C3 : C4 2. C12 3. A4 4. D12 5. C6 x C2 @eprog\noindent The current version of \kbd{galpol} supports groups of order $a\leq 143$. The library syntax is \fun{GEN}{galoisgetname}{long a, long b}. \subsec{galoisgetpol$(a,\{b\},\{s\})$}\kbdsidx{galoisgetpol}\label{se:galoisgetpol} Query the \kbd{galpol} package for a polynomial with Galois group isomorphic to GAP4(a,b), totally real if $s=1$ (default) and totally complex if $s=2$. The current version of \kbd{galpol} supports groups of order $a\leq 143$. The output is a vector [\kbd{pol}, \kbd{den}] where \item \kbd{pol} is the polynomial of degree $a$ \item \kbd{den} is the denominator of \kbd{nfgaloisconj(pol)}. Pass it as an optional argument to \tet{galoisinit} or \tet{nfgaloisconj} to speed them up: \bprog ? [pol,den] = galoisgetpol(64,4,1); ? G = galoisinit(pol); time = 352ms ? galoisinit(pol, den); \\ passing 'den' speeds up the computation time = 264ms ? % == %` %4 = 1 \\ same answer @eprog If $b$ and $s$ are omitted, return the number of isomorphism classes of groups of order $a$. The library syntax is \fun{GEN}{galoisgetpol}{long a, long b, long s}. Also available is \fun{GEN}{galoisnbpol}{long a} when $b$ and $s$ are omitted. \subsec{galoisidentify$(\var{gal})$}\kbdsidx{galoisidentify}\label{se:galoisidentify} \var{gal} being be a Galois group as output by \tet{galoisinit}, output the isomorphism class of the underlying abstract group as a two-components vector $[o,i]$, where $o$ is the group order, and $i$ is the group index in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and Eamonn O'Brien. This command also accepts subgroups returned by \kbd{galoissubgroups}. The current implementation is limited to degree less or equal to $127$. Some larger ``easy'' orders are also supported. The output is similar to the output of the function \kbd{IdGroup} in GAP4. Note that GAP4 \kbd{IdGroup} handles all groups of order less than $2000$ except $1024$, so you can use \tet{galoisexport} and GAP4 to identify large Galois groups. The library syntax is \fun{GEN}{galoisidentify}{GEN gal}. \subsec{galoisinit$(\var{pol},\{\var{den}\})$}\kbdsidx{galoisinit}\label{se:galoisinit} Computes the Galois group and all necessary information for computing the fixed fields of the Galois extension $K/\Q$ where $K$ is the number field defined by $\var{pol}$ (monic irreducible polynomial in $\Z[X]$ or a number field as output by \tet{nfinit}). The extension $K/\Q$ must be Galois with Galois group ``weakly'' super-solvable, see below; returns 0 otherwise. Hence this permits to quickly check whether a polynomial of order strictly less than $36$ is Galois or not. The algorithm used is an improved version of the paper ``An efficient algorithm for the computation of Galois automorphisms'', Bill Allombert, Math.~Comp, vol.~73, 245, 2001, pp.~359--375. A group $G$ is said to be ``weakly'' super-solvable if there exists a normal series $\{1\} = H_0 \triangleleft H_1 \triangleleft \cdots \triangleleft H_{n-1} \triangleleft H_n$ such that each $H_i$ is normal in $G$ and for $i 0$ be a positive integer. Return $1$ if the fractional ideal $A = B^n$ is an $n$-th power and $0$ otherwise. If the argument $B$ is present, set it to the $n$-th root of $A$, in HNF. \bprog ? K = nfinit(x^3 - 2); ? A = [46875, 30966, 9573; 0, 3, 0; 0, 0, 3]; ? idealispower(K, A, 3, &B) %3 = 1 ? B %4 = [75 22 41] [ 0 1 0] [ 0 0 1] ? A = [9375, 2841, 198; 0, 3, 0; 0, 0, 3]; ? idealispower(K, A, 3) %5 = 0 @eprog\noindent The library syntax is \fun{long}{idealispower}{GEN nf, GEN A, long n, GEN *B = NULL}. \subsec{ideallist$(\var{nf},\var{bound},\{\fl=4\})$}\kbdsidx{ideallist}\label{se:ideallist} Computes the list of all ideals of norm less or equal to \var{bound} in the number field \var{nf}. The result is a row vector with exactly \var{bound} components. Each component is itself a row vector containing the information about ideals of a given norm, in no specific order, depending on the value of $\fl$: The possible values of $\fl$ are: \quad 0: give the \var{bid} attached to the ideals, without generators. \quad 1: as 0, but include the generators in the \var{bid}. \quad 2: in this case, \var{nf} must be a \var{bnf} with units. Each component is of the form $[\var{bid},U]$, where \var{bid} is as case 0 and $U$ is a vector of discrete logarithms of the units. More precisely, it gives the \kbd{ideallog}s with respect to \var{bid} of \kbd{bnf.tufu}. This structure is technical, and only meant to be used in conjunction with \tet{bnrclassnolist} or \tet{bnrdisclist}. \quad 3: as 2, but include the generators in the \var{bid}. \quad 4: give only the HNF of the ideal. \bprog ? nf = nfinit(x^2+1); ? L = ideallist(nf, 100); ? L[1] %3 = [[1, 0; 0, 1]] \\@com A single ideal of norm 1 ? #L[65] %4 = 4 \\@com There are 4 ideals of norm 4 in $\Z[i]$ @eprog If one wants more information, one could do instead: \bprog ? nf = nfinit(x^2+1); ? L = ideallist(nf, 100, 0); ? l = L[25]; vector(#l, i, l[i].clgp) %3 = [[20, [20]], [16, [4, 4]], [20, [20]]] ? l[1].mod %4 = [[25, 18; 0, 1], []] ? l[2].mod %5 = [[5, 0; 0, 5], []] ? l[3].mod %6 = [[25, 7; 0, 1], []] @eprog\noindent where we ask for the structures of the $(\Z[i]/I)^*$ for all three ideals of norm $25$. In fact, for all moduli with finite part of norm $25$ and trivial Archimedean part, as the last 3 commands show. See \tet{ideallistarch} to treat general moduli. The library syntax is \fun{GEN}{ideallist0}{GEN nf, long bound, long flag}. \subsec{ideallistarch$(\var{nf},\var{list},\var{arch})$}\kbdsidx{ideallistarch}\label{se:ideallistarch} \var{list} is a vector of vectors of bid's, as output by \tet{ideallist} with flag $0$ to $3$. Return a vector of vectors with the same number of components as the original \var{list}. The leaves give information about moduli whose finite part is as in original list, in the same order, and Archimedean part is now \var{arch} (it was originally trivial). The information contained is of the same kind as was present in the input; see \tet{ideallist}, in particular the meaning of \fl. \bprog ? bnf = bnfinit(x^2-2); ? bnf.sign %2 = [2, 0] \\@com two places at infinity ? L = ideallist(bnf, 100, 0); ? l = L[98]; vector(#l, i, l[i].clgp) %4 = [[42, [42]], [36, [6, 6]], [42, [42]]] ? La = ideallistarch(bnf, L, [1,1]); \\@com add them to the modulus ? l = La[98]; vector(#l, i, l[i].clgp) %6 = [[168, [42, 2, 2]], [144, [6, 6, 2, 2]], [168, [42, 2, 2]]] @eprog Of course, the results above are obvious: adding $t$ places at infinity will add $t$ copies of $\Z/2\Z$ to $(\Z_K/f)^*$. The following application is more typical: \bprog ? L = ideallist(bnf, 100, 2); \\@com units are required now ? La = ideallistarch(bnf, L, [1,1]); ? H = bnrclassnolist(bnf, La); ? H[98]; %4 = [2, 12, 2] @eprog The library syntax is \fun{GEN}{ideallistarch}{GEN nf, GEN list, GEN arch}. \subsec{ideallog$(\{\var{nf}\},x,\var{bid})$}\kbdsidx{ideallog}\label{se:ideallog} $\var{nf}$ is a number field, \var{bid} is as output by \kbd{idealstar(nf, D, \dots)} and $x$ a non-necessarily integral element of \var{nf} which must have valuation equal to 0 at all prime ideals in the support of $\kbd{D}$. This function computes the discrete logarithm of $x$ on the generators given in \kbd{\var{bid}.gen}. In other words, if $g_i$ are these generators, of orders $d_i$ respectively, the result is a column vector of integers $(x_i)$ such that $0\le x_i1$). The components of \kbd{pr} should be accessed by member functions: \kbd{pr.p}, \kbd{pr.e}, \kbd{pr.f}, and \kbd{pr.gen} (returns the vector $[p,a]$): \bprog ? K = nfinit(x^3-2); ? P = idealprimedec(K, 5); ? #P \\ 2 primes above 5 in Q(2^(1/3)) %3 = 2 ? [p1,p2] = P; ? [p1.e, p1.f] \\ the first is unramified of degree 1 %5 = [1, 1] ? [p2.e, p2.f] \\ the second is unramified of degree 2 %6 = [1, 2] ? p1.gen %7 = [5, [2, 1, 0]~] ? nfbasistoalg(K, %[2]) \\ a uniformizer for p1 %8 = Mod(x + 2, x^3 - 2) ? #idealprimedec(K, 5, 1) \\ restrict to f = 1 %9 = 1 \\ now only p1 @eprog The library syntax is \fun{GEN}{idealprimedec_limit_f}{GEN nf, GEN p, long f}. \subsec{idealprincipalunits$(\var{nf},\var{pr},k)$}\kbdsidx{idealprincipalunits}\label{se:idealprincipalunits} Given a prime ideal in \tet{idealprimedec} format, returns the multiplicative group $(1 + \var{pr}) / (1 + \var{pr}^k)$ as an abelian group. This function is much faster than \tet{idealstar} when the norm of \var{pr} is large, since it avoids (useless) work in the multiplicative group of the residue field. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K,2)[1]; ? G = idealprincipalunits(K, P, 20); ? G.cyc %4 = [512, 256, 4] \\ Z/512 x Z/256 x Z/4 ? G.gen %5 = [[-1, -2]~, 1021, [0, -1]~] \\ minimal generators of given order @eprog The library syntax is \fun{GEN}{idealprincipalunits}{GEN nf, GEN pr, long k}. \subsec{idealramgroups$(\var{nf},\var{gal},\var{pr})$}\kbdsidx{idealramgroups}\label{se:idealramgroups} Let $K$ be the number field defined by \var{nf} and assume that $K/\Q$ is Galois with Galois group $G$ given by \kbd{gal=galoisinit(nf)}. Let \var{pr} be the prime ideal $\goth{P}$ in prid format. This function returns a vector $g$ of subgroups of \kbd{gal} as follow: \item \kbd{g[1]} is the decomposition group of $\goth{P}$, \item \kbd{g[2]} is $G_0(\goth{P})$, the inertia group of $\goth{P}$, and for $i\geq 2$, \item \kbd{g[i]} is $G_{i-2}(\goth{P})$, the $i-2$-th \idx{ramification group} of $\goth{P}$. \noindent The length of $g$ is the number of non-trivial groups in the sequence, thus is $0$ if $e=1$ and $f=1$, and $1$ if $f>1$ and $e=1$. The following function computes the cardinality of a subgroup of $G$, as given by the components of $g$: \bprog card(H) =my(o=H[2]); prod(i=1,#o,o[i]); @eprog \bprog ? nf=nfinit(x^6+3); gal=galoisinit(nf); pr=idealprimedec(nf,3)[1]; ? g = idealramgroups(nf, gal, pr); ? apply(card,g) %3 = [6, 6, 3, 3, 3] \\ cardinalities of the G_i @eprog \bprog ? nf=nfinit(x^6+108); gal=galoisinit(nf); pr=idealprimedec(nf,2)[1]; ? iso=idealramgroups(nf,gal,pr)[2] %5 = [[Vecsmall([2, 3, 1, 5, 6, 4])], Vecsmall([3])] ? nfdisc(galoisfixedfield(gal,iso,1)) %6 = -3 @eprog\noindent The field fixed by the inertia group of $2$ is not ramified at $2$. The library syntax is \fun{GEN}{idealramgroups}{GEN nf, GEN gal, GEN pr}. \subsec{idealred$(\var{nf},I,\{v=0\})$}\kbdsidx{idealred}\label{se:idealred} \idx{LLL} reduction of the ideal $I$ in the number field $K$ attached to \var{nf}, along the direction $v$. The $v$ parameter is best left omitted, but if it is present, it must be an $\kbd{nf.r1} + \kbd{nf.r2}$-component vector of \emph{non-negative} integers. (What counts is the relative magnitude of the entries: if all entries are equal, the effect is the same as if the vector had been omitted.) This function finds an $a\in K^*$ such that $J = (a)I$ is ``small'' and integral (see the end for technical details). The result is the Hermite normal form of the ``reduced'' ideal $J$. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K,5)[1]; ? idealred(K, P) %3 = [1 0] [0 1] @eprog\noindent More often than not, a \idx{principal ideal} yields the unit ideal as above. This is a quick and dirty way to check if ideals are principal, but it is not a necessary condition: a non-trivial result does not prove that the ideal is non-principal. For guaranteed results, see \kbd{bnfisprincipal}, which requires the computation of a full \kbd{bnf} structure. If the input is an extended ideal $[I,s]$, the output is $[J, sa]$; in this way, one keeps track of the principal ideal part: \bprog ? idealred(K, [P, 1]) %5 = [[1, 0; 0, 1], [2, -1]~] @eprog\noindent meaning that $P$ is generated by $[2, -1]~$. The number field element in the extended part is an algebraic number in any form \emph{or} a factorization matrix (in terms of number field elements, not ideals!). In the latter case, elements stay in factored form, which is a convenient way to avoid coefficient explosion; see also \tet{idealpow}. \misctitle{Technical note} The routine computes an LLL-reduced basis for the lattice $I^{-1}$ equipped with the quadratic form $$|| x ||_v^2 = \sum_{i=1}^{r_1+r_2} 2^{v_i}\varepsilon_i|\sigma_i(x)|^2,$$ where as usual the $\sigma_i$ are the (real and) complex embeddings and $\varepsilon_i = 1$, resp.~$2$, for a real, resp.~complex place. The element $a$ is simply the first vector in the LLL basis. The only reason you may want to try to change some directions and set some $v_i\neq 0$ is to randomize the elements found for a fixed ideal, which is heuristically useful in index calculus algorithms like \tet{bnfinit} and \tet{bnfisprincipal}. \misctitle{Even more technical note} In fact, the above is a white lie. We do not use $||\cdot||_v$ exactly but a rescaled rounded variant which gets us faster and simpler LLLs. There's no harm since we are not using any theoretical property of $a$ after all, except that it belongs to $I^{-1}$ and that $a I$ is ``expected to be small''. The library syntax is \fun{GEN}{idealred0}{GEN nf, GEN I, GEN v = NULL}. \subsec{idealredmodpower$(\var{nf},x,n,\{B=\var{primelimit}\})$}\kbdsidx{idealredmodpower}\label{se:idealredmodpower} Let \var{nf} be a number field, $x$ an ideal in \var{nf} and $n > 0$ be a positive integer. Return a number field element $b$ such that $x b^n = v$ is small. If $x$ is integral, then $v$ is also integral. More precisely, \kbd{idealnumden} reduces the problem to $x$ integral. Then, factoring out the prime ideals dividing a rational prime $p \leq B$, we rewrite $x = I J^n$ where the ideals $I$ and $J$ are both integral and $I$ is $B$-smooth. Then we return a small element $b$ in $J^{-1}$. The bound $B$ avoids a costly complete factorization of $x$; as soon as the $n$-core of $x$ is $B$-smooth (i.e., as soon as $I$ is $n$-power free), then $J$ is as large as possible and so is the expected reduction. \bprog ? T = x^6+108; nf = nfinit(T); a = Mod(x,T); ? setrand(1); u = (2*a^2+a+3)*random(2^1000*x^6)^6; ? sizebyte(u) %3 = 4864 ? b = idealredmodpower(nf,u,2); ? v2 = nfeltmul(nf,u, nfeltpow(nf,b,2)) %5 = [34, 47, 15, 35, 9, 3]~ ? b = idealredmodpower(nf,u,6); ? v6 = nfeltmul(nf,u, nfeltpow(nf,b,6)) %7 = [3, 0, 2, 6, -7, 1]~ @eprog\noindent The last element \kbd{v6}, obtained by reducing modulo $6$-th powers instead of squares, looks smaller than \kbd{v2} but its norm is actually a little larger: \bprog ? idealnorm(nf,v2) %8 = 81309 ? idealnorm(nf,v6) %9 = 731781 @eprog The library syntax is \fun{GEN}{idealredmodpower}{GEN nf, GEN x, ulong n, ulong B}. \subsec{idealstar$(\{\var{nf}\},N,\{\fl=1\})$}\kbdsidx{idealstar}\label{se:idealstar} Outputs a \kbd{bid} structure, necessary for computing in the finite abelian group $G = (\Z_K/N)^*$. Here, \var{nf} is a number field and $N$ is a \var{modulus}: either an ideal in any form, or a row vector whose first component is an ideal and whose second component is a row vector of $r_1$ 0 or 1. Ideals can also be given by a factorization into prime ideals, as produced by \tet{idealfactor}. This \var{bid} is used in \tet{ideallog} to compute discrete logarithms. It also contains useful information which can be conveniently retrieved as \kbd{\var{bid}.mod} (the modulus), \kbd{\var{bid}.clgp} ($G$ as a finite abelian group), \kbd{\var{bid}.no} (the cardinality of $G$), \kbd{\var{bid}.cyc} (elementary divisors) and \kbd{\var{bid}.gen} (generators). If $\fl=1$ (default), the result is a \kbd{bid} structure without generators: they are well defined but not explicitly computed, which saves time. If $\fl=2$, as $\fl=1$, but including generators. If $\fl=0$, only outputs $(\Z_K/N)^*$ as an abelian group, i.e as a 3-component vector $[h,d,g]$: $h$ is the order, $d$ is the vector of SNF\sidx{Smith normal form} cyclic components and $g$ the corresponding generators. If \var{nf} is omitted, we take it to be the rational number fields, $N$ must be an integer and we return the structure of $(\Z/N\Z)^*$. In other words \kbd{idealstar(, N, flag)} is short for \bprog idealstar(nfinit(x), N, flag) @eprog\noindent but faster. The alternative syntax \kbd{znstar(N, flag)} is also available for an analogous effect but, due to an unfortunate historical oversight, the default value of \kbd{flag} is different in the two functions (\kbd{znstar} does not initialize by default, you probably want \kbd{znstar(N,1)}). The library syntax is \fun{GEN}{idealstar0}{GEN nf = NULL, GEN N, long flag}. Instead the above hardcoded numerical flags, one should rather use \fun{GEN}{Idealstar}{GEN nf, GEN ideal, long flag}, where \kbd{flag} is an or-ed combination of \tet{nf_GEN} (include generators) and \tet{nf_INIT} (return a full \kbd{bid}, not a group), possibly $0$. This offers one more combination: gen, but no init. \subsec{idealtwoelt$(\var{nf},x,\{a\})$}\kbdsidx{idealtwoelt}\label{se:idealtwoelt} Computes a two-element representation of the ideal $x$ in the number field $\var{nf}$, combining a random search and an approximation theorem; $x$ is an ideal in any form (possibly an extended ideal, whose principal part is ignored) \item When called as \kbd{idealtwoelt(nf,x)}, the result is a row vector $[a,\alpha]$ with two components such that $x=a\Z_K+\alpha\Z_K$ and $a$ is chosen to be the positive generator of $x\cap\Z$, unless $x$ was given as a principal ideal in which case we may choose $a = 0$. The algorithm uses a fast lazy factorization of $x\cap \Z$ and runs in randomized polynomial time. \bprog ? K = nfinit(t^5-23); ? x = idealhnf(K, t^2*(t+1), t^3*(t+1)) %2 = \\ some random ideal of norm 552*23 [552 23 23 529 23] [ 0 23 0 0 0] [ 0 0 1 0 0] [ 0 0 0 1 0] [ 0 0 0 0 1] ? [a,alpha] = idealtwoelt(K, x) %3 = [552, [23, 0, 1, 0, 0]~] ? nfbasistoalg(K, alpha) %4 = Mod(t^2 + 23, t^5 - 23) @eprog \item When called as \kbd{idealtwoelt(nf,x,a)} with an explicit non-zero $a$ supplied as third argument, the function assumes that $a \in x$ and returns $\alpha\in x$ such that $x = a\Z_K + \alpha\Z_K$. Note that we must factor $a$ in this case, and the algorithm is generally slower than the default variant and gives larger generators: \bprog ? alpha2 = idealtwoelt(K, x, 552) %5 = [-161, -161, -183, -207, 0]~ ? idealhnf(K, 552, alpha2) == x %6 = 1 @eprog\noindent Note that, in both cases, the return value is \emph{not} recognized as an ideal by GP functions; one must use \kbd{idealhnf} as above to recover a valid ideal structure from the two-element representation. The library syntax is \fun{GEN}{idealtwoelt0}{GEN nf, GEN x, GEN a = NULL}. Also available are \fun{GEN}{idealtwoelt}{GEN nf, GEN x} and \fun{GEN}{idealtwoelt2}{GEN nf, GEN x, GEN a}. \subsec{idealval$(\var{nf},x,\var{pr})$}\kbdsidx{idealval}\label{se:idealval} Gives the valuation of the ideal $x$ at the prime ideal \var{pr} in the number field $\var{nf}$, where \var{pr} is in \kbd{idealprimedec} format. The valuation of the $0$ ideal is \kbd{+oo}. The library syntax is \fun{GEN}{gpidealval}{GEN nf, GEN x, GEN pr}. Also available is \fun{long}{idealval}{GEN nf, GEN x, GEN pr}, which returns \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer. \subsec{matalgtobasis$(\var{nf},x)$}\kbdsidx{matalgtobasis}\label{se:matalgtobasis} This function is deprecated, use \kbd{apply}. $\var{nf}$ being a number field in \kbd{nfinit} format, and $x$ a (row or column) vector or matrix, apply \tet{nfalgtobasis} to each entry of $x$. The library syntax is \fun{GEN}{matalgtobasis}{GEN nf, GEN x}. \subsec{matbasistoalg$(\var{nf},x)$}\kbdsidx{matbasistoalg}\label{se:matbasistoalg} This function is deprecated, use \kbd{apply}. $\var{nf}$ being a number field in \kbd{nfinit} format, and $x$ a (row or column) vector or matrix, apply \tet{nfbasistoalg} to each entry of $x$. The library syntax is \fun{GEN}{matbasistoalg}{GEN nf, GEN x}. \subsec{modreverse$(z)$}\kbdsidx{modreverse}\label{se:modreverse} Let $z = \kbd{Mod(A, T)}$ be a polmod, and $Q$ be its minimal polynomial, which must satisfy $\text{deg}(Q) = \text{deg}(T)$. Returns a ``reverse polmod'' \kbd{Mod(B, Q)}, which is a root of $T$. This is quite useful when one changes the generating element in algebraic extensions: \bprog ? u = Mod(x, x^3 - x -1); v = u^5; ? w = modreverse(v) %2 = Mod(x^2 - 4*x + 1, x^3 - 5*x^2 + 4*x - 1) @eprog\noindent which means that $x^3 - 5x^2 + 4x -1$ is another defining polynomial for the cubic field $$\Q(u) = \Q[x]/(x^3 - x - 1) = \Q[x]/(x^3 - 5x^2 + 4x - 1) = \Q(v),$$ and that $u \to v^2 - 4v + 1$ gives an explicit isomorphism. From this, it is easy to convert elements between the $A(u)\in \Q(u)$ and $B(v)\in \Q(v)$ representations: \bprog ? A = u^2 + 2*u + 3; subst(lift(A), 'x, w) %3 = Mod(x^2 - 3*x + 3, x^3 - 5*x^2 + 4*x - 1) ? B = v^2 + v + 1; subst(lift(B), 'x, v) %4 = Mod(26*x^2 + 31*x + 26, x^3 - x - 1) @eprog If the minimal polynomial of $z$ has lower degree than expected, the routine fails \bprog ? u = Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1) ? modreverse(u) *** modreverse: domain error in modreverse: deg(minpoly(z)) < 4 *** Break loop: type 'break' to go back to GP prompt break> Vec( dbg_err() ) \\ ask for more info ["e_DOMAIN", "modreverse", "deg(minpoly(z))", "<", 4, Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1)] break> minpoly(u) x^2 - 8 @eprog The library syntax is \fun{GEN}{modreverse}{GEN z}. \subsec{newtonpoly$(x,p)$}\kbdsidx{newtonpoly}\label{se:newtonpoly} Gives the vector of the slopes of the Newton polygon of the polynomial $x$ with respect to the prime number $p$. The $n$ components of the vector are in decreasing order, where $n$ is equal to the degree of $x$. Vertical slopes occur iff the constant coefficient of $x$ is zero and are denoted by \kbd{+oo}. The library syntax is \fun{GEN}{newtonpoly}{GEN x, GEN p}. \subsec{nfalgtobasis$(\var{nf},x)$}\kbdsidx{nfalgtobasis}\label{se:nfalgtobasis} Given an algebraic number $x$ in the number field $\var{nf}$, transforms it to a column vector on the integral basis \kbd{\var{nf}.zk}. \bprog ? nf = nfinit(y^2 + 4); ? nf.zk %2 = [1, 1/2*y] ? nfalgtobasis(nf, [1,1]~) %3 = [1, 1]~ ? nfalgtobasis(nf, y) %4 = [0, 2]~ ? nfalgtobasis(nf, Mod(y, y^2+4)) %5 = [0, 2]~ @eprog This is the inverse function of \kbd{nfbasistoalg}. The library syntax is \fun{GEN}{algtobasis}{GEN nf, GEN x}. \subsec{nfbasis$(T)$}\kbdsidx{nfbasis}\label{se:nfbasis} Let $T(X)$ be an irreducible polynomial with integral coefficients. This function returns an \idx{integral basis} of the number field defined by $T$, that is a $\Z$-basis of its maximal order. The basis elements are given as elements in $\Q[X]/(T)$: \bprog ? nfbasis(x^2 + 1) %1 = [1, x] @eprog This function uses a modified version of the \idx{round 4} algorithm, due to David \idx{Ford}, Sebastian \idx{Pauli} and Xavier \idx{Roblot}. \misctitle{Local basis, orders maximal at certain primes} Obtaining the maximal order is hard: it requires factoring the discriminant $D$ of $T$. Obtaining an order which is maximal at a finite explicit set of primes is easy, but it may then be a strict suborder of the maximal order. To specify that we are interested in a given set of places only, we can replace the argument $T$ by an argument $[T,\var{listP}]$, where \var{listP} encodes the primes we are interested in: it must be a factorization matrix, a vector of integers or a single integer. \item Vector: we assume that it contains distinct \emph{prime} numbers. \item Matrix: we assume that it is a two-column matrix of a (partial) factorization of $D$; namely the first column contains distinct \emph{primes} and the second one the valuation of $D$ at each of these primes. \item Integer $B$: this is replaced by the vector of primes up to $B$. Note that the function will use at least $O(B)$ time: a small value, about $10^5$, should be enough for most applications. Values larger than $2^{32}$ are not supported. In all these cases, the primes may or may not divide the discriminant $D$ of $T$. The function then returns a $\Z$-basis of an order whose index is not divisible by any of these prime numbers. The result is actually a global integral basis if all prime divisors of the \emph{field} discriminant are included! Note that \kbd{nfinit} has built-in support for such a check: \bprog ? K = nfinit([T, listP]); ? nfcertify(K) \\ we computed an actual maximal order %2 = []; @eprog\noindent The first line initializes a number field structure incorporating \kbd{nfbasis([T, listP]} in place of a proven integral basis. The second line certifies that the resulting structure is correct. This allows to create an \kbd{nf} structure attached to the number field $K = \Q[X]/(T)$, when the discriminant of $T$ cannot be factored completely, whereas the prime divisors of $\disc K$ are known. Of course, if \var{listP} contains a single prime number $p$, the function returns a local integral basis for $\Z_p[X]/(T)$: \bprog ? nfbasis(x^2+x-1001) %1 = [1, 1/3*x - 1/3] ? nfbasis( [x^2+x-1001, [2]] ) %2 = [1, x] @eprog \misctitle{The Buchmann-Lenstra algorithm} We now complicate the picture: it is in fact allowed to include \emph{composite} numbers instead of primes in \kbd{listP} (Vector or Matrix case), provided they are pairwise coprime. The result will still be a correct integral basis \emph{if} the field discriminant factors completely over the actual primes in the list. Adding a composite $C$ such that $C^2$ \emph{divides} $D$ may help because when we consider $C$ as a prime and run the algorithm, two good things can happen: either we succeed in proving that no prime dividing $C$ can divide the index (without actually needing to find those primes), or the computation exhibits a non-trivial zero divisor, thereby factoring $C$ and we go on with the refined factorization. (Note that including a $C$ such that $C^2$ does not divide $D$ is useless.) If neither happen, then the computed basis need not generate the maximal order. Here is an example: \bprog ? B = 10^5; ? P = factor(poldisc(T), B)[,1]; \\ primes <= B dividing D + cofactor ? basis = nfbasis([T, listP]) ? disc = nfdisc([T, listP]) @eprog\noindent We obtain the maximal order and its discriminant if the field discriminant factors completely over the primes less than $B$ (together with the primes contained in the \tet{addprimes} table). This can be tested as follows: \bprog check = factor(disc, B); lastp = check[-1..-1,1]; if (lastp > B && !setsearch(addprimes(), lastp), warning("nf may be incorrect!")) @eprog\noindent This is a sufficient but not a necessary condition, hence the warning, instead of an error. N.B. \kbd{lastp} is the last entry in the first column of the \kbd{check} matrix, i.e. the largest prime dividing \kbd{nf.disc} if $\leq B$ or if it belongs to the prime table. The function \tet{nfcertify} speeds up and automates the above process: \bprog ? B = 10^5; ? nf = nfinit([T, B]); ? nfcertify(nf) %3 = [] \\ nf is unconditionally correct ? basis = nf.zk; ? disc = nf.disc; @eprog \synt{nfbasis}{GEN T, GEN *d, GEN listP = NULL}, which returns the order basis, and where \kbd{*d} receives the order discriminant. \subsec{nfbasistoalg$(\var{nf},x)$}\kbdsidx{nfbasistoalg}\label{se:nfbasistoalg} Given an algebraic number $x$ in the number field \var{nf}, transforms it into \typ{POLMOD} form. \bprog ? nf = nfinit(y^2 + 4); ? nf.zk %2 = [1, 1/2*y] ? nfbasistoalg(nf, [1,1]~) %3 = Mod(1/2*y + 1, y^2 + 4) ? nfbasistoalg(nf, y) %4 = Mod(y, y^2 + 4) ? nfbasistoalg(nf, Mod(y, y^2+4)) %5 = Mod(y, y^2 + 4) @eprog This is the inverse function of \kbd{nfalgtobasis}. The library syntax is \fun{GEN}{basistoalg}{GEN nf, GEN x}. \subsec{nfcertify$(\var{nf})$}\kbdsidx{nfcertify}\label{se:nfcertify} $\var{nf}$ being as output by \kbd{nfinit}, checks whether the integer basis is known unconditionally. This is in particular useful when the argument to \kbd{nfinit} was of the form $[T, \kbd{listP}]$, specifying a finite list of primes when $p$-maximality had to be proven, or a list of coprime integers to which Buchmann-Lenstra algorithm was to be applied. The function returns a vector of coprime composite integers. If this vector is empty, then \kbd{nf.zk} and \kbd{nf.disc} are correct. Otherwise, the result is dubious. In order to obtain a certified result, one must completely factor each of the given integers, then \kbd{addprime} each of their prime factors, then check whether \kbd{nfdisc(nf.pol)} is equal to \kbd{nf.disc}. The library syntax is \fun{GEN}{nfcertify}{GEN nf}. \subsec{nfcompositum$(\var{nf},P,Q,\{\fl=0\})$}\kbdsidx{nfcompositum}\label{se:nfcompositum} Let \var{nf} be a number field structure attached to the field $K$ and let \sidx{compositum} $P$ and $Q$ be squarefree polynomials in $K[X]$ in the same variable. Outputs the simple factors of the \'etale $K$-algebra $A = K[X, Y] / (P(X), Q(Y))$. The factors are given by a list of polynomials $R$ in $K[X]$, attached to the number field $K[X]/ (R)$, and sorted by increasing degree (with respect to lexicographic ordering for factors of equal degrees). Returns an error if one of the polynomials is not squarefree. Note that it is more efficient to reduce to the case where $P$ and $Q$ are irreducible first. The routine will not perform this for you, since it may be expensive, and the inputs are irreducible in most applications anyway. In this case, there will be a single factor $R$ if and only if the number fields defined by $P$ and $Q$ are linearly disjoint (their intersection is $K$). The binary digits of $\fl$ mean 1: outputs a vector of 4-component vectors $[R,a,b,k]$, where $R$ ranges through the list of all possible compositums as above, and $a$ (resp. $b$) expresses the root of $P$ (resp. $Q$) as an element of $K[X]/(R)$. Finally, $k$ is a small integer such that $b + ka = X$ modulo $R$. 2: assume that $P$ and $Q$ define number fields that are linearly disjoint: both polynomials are irreducible and the corresponding number fields have no common subfield besides $K$. This allows to save a costly factorization over $K$. In this case return the single simple factor instead of a vector with one element. A compositum is often defined by a complicated polynomial, which it is advisable to reduce before further work. Here is an example involving the field $K(\zeta_5, 5^{1/10})$, $K=\Q(\sqrt{5})$: \bprog ? K = nfinit(y^2-5); ? L = nfcompositum(K, x^5 - y, polcyclo(5), 1); \\@com list of $[R,a,b,k]$ ? [R, a] = L[1]; \\@com pick the single factor, extract $R,a$ (ignore $b,k$) ? lift(R) \\@com defines the compositum %4 = x^10 + (-5/2*y + 5/2)*x^9 + (-5*y + 20)*x^8 + (-20*y + 30)*x^7 + \ (-45/2*y + 145/2)*x^6 + (-71/2*y + 121/2)*x^5 + (-20*y + 60)*x^4 + \ (-25*y + 5)*x^3 + 45*x^2 + (-5*y + 15)*x + (-2*y + 6) ? a^5 - y \\@com a fifth root of $y$ %5 = 0 ? [T, X] = rnfpolredbest(K, R, 1); ? lift(T) \\@com simpler defining polynomial for $K[x]/(R)$ %7 = x^10 + (-11/2*y + 25/2) ? liftall(X) \\ @com root of $R$ in $K[x]/(T(x))$ %8 = (3/4*y + 7/4)*x^7 + (-1/2*y - 1)*x^5 + 1/2*x^2 + (1/4*y - 1/4) ? a = subst(a.pol, 'x, X); \\@com \kbd{a} in the new coordinates ? liftall(a) %10 = (-3/4*y - 7/4)*x^7 - 1/2*x^2 ? a^5 - y %11 = 0 @eprog The main variables of $P$ and $Q$ must be the same and have higher priority than that of \var{nf} (see~\kbd{varhigher} and~\kbd{varlower}). The library syntax is \fun{GEN}{nfcompositum}{GEN nf, GEN P, GEN Q, long flag}. \subsec{nfdetint$(\var{nf},x)$}\kbdsidx{nfdetint}\label{se:nfdetint} Given a pseudo-matrix $x$, computes a non-zero ideal contained in (i.e.~multiple of) the determinant of $x$. This is particularly useful in conjunction with \kbd{nfhnfmod}. The library syntax is \fun{GEN}{nfdetint}{GEN nf, GEN x}. \subsec{nfdisc$(T)$}\kbdsidx{nfdisc}\label{se:nfdisc} \idx{field discriminant} of the number field defined by the integral, preferably monic, irreducible polynomial $T(X)$. Returns the discriminant of the number field $\Q[X]/(T)$, using the Round $4$ algorithm. \misctitle{Local discriminants, valuations at certain primes} As in \kbd{nfbasis}, the argument $T$ can be replaced by $[T,\var{listP}]$, where \kbd{listP} is as in \kbd{nfbasis}: a vector of pairwise coprime integers (usually distinct primes), a factorization matrix, or a single integer. In that case, the function returns the discriminant of an order whose basis is given by \kbd{nfbasis(T,listP)}, which need not be the maximal order, and whose valuation at a prime entry in \kbd{listP} is the same as the valuation of the field discriminant. In particular, if \kbd{listP} is $[p]$ for a prime $p$, we can return the $p$-adic discriminant of the maximal order of $\Z_p[X]/(T)$, as a power of $p$, as follows: \bprog ? padicdisc(T,p) = p^valuation(nfdisc([T,[p]]), p); ? nfdisc(x^2 + 6) %2 = -24 ? padicdisc(x^2 + 6, 2) %3 = 8 ? padicdisc(x^2 + 6, 3) %4 = 3 @eprog\noindent The following function computes the discriminant of the maximal order under the assumption that $P$ is a vector of prime numbers containing (at least) all prime divisors of the field discriminant: \bprog globaldisc(T, P) = { my (D = nfdisc([T, P])); sign(D) * factorback(P, [valuation(D,p) | p <-P]); } ? globaldisc(x^2 + 6, [2, 3, 5]) %1 = -24 @eprog \synt{nfdisc}{GEN T} (\kbd{listP = NULL}). Also available is \fun{GEN}{nfbasis}{GEN T, GEN *d, GEN listP = NULL}, which returns the order basis, and where \kbd{*d} receives the order discriminant. \subsec{nfeltadd$(\var{nf},x,y)$}\kbdsidx{nfeltadd}\label{se:nfeltadd} Given two elements $x$ and $y$ in \var{nf}, computes their sum $x+y$ in the number field $\var{nf}$. \bprog ? nf = nfinit(1+x^2); ? nfeltadd(nf, 1, x) \\ 1 + I %2 = [1, 1]~ @eprog The library syntax is \fun{GEN}{nfadd}{GEN nf, GEN x, GEN y}. \subsec{nfeltdiv$(\var{nf},x,y)$}\kbdsidx{nfeltdiv}\label{se:nfeltdiv} Given two elements $x$ and $y$ in \var{nf}, computes their quotient $x/y$ in the number field $\var{nf}$. The library syntax is \fun{GEN}{nfdiv}{GEN nf, GEN x, GEN y}. \subsec{nfeltdiveuc$(\var{nf},x,y)$}\kbdsidx{nfeltdiveuc}\label{se:nfeltdiveuc} Given two elements $x$ and $y$ in \var{nf}, computes an algebraic integer $q$ in the number field $\var{nf}$ such that the components of $x-qy$ are reasonably small. In fact, this is functionally identical to \kbd{round(nfdiv(\var{nf},x,y))}. The library syntax is \fun{GEN}{nfdiveuc}{GEN nf, GEN x, GEN y}. \subsec{nfeltdivmodpr$(\var{nf},x,y,\var{pr})$}\kbdsidx{nfeltdivmodpr}\label{se:nfeltdivmodpr} This function is obsolete, use \kbd{nfmodpr}. Given two elements $x$ and $y$ in \var{nf} and \var{pr} a prime ideal in \kbd{modpr} format (see \tet{nfmodprinit}), computes their quotient $x / y$ modulo the prime ideal \var{pr}. The library syntax is \fun{GEN}{nfdivmodpr}{GEN nf, GEN x, GEN y, GEN pr}. This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. \subsec{nfeltdivrem$(\var{nf},x,y)$}\kbdsidx{nfeltdivrem}\label{se:nfeltdivrem} Given two elements $x$ and $y$ in \var{nf}, gives a two-element row vector $[q,r]$ such that $x=qy+r$, $q$ is an algebraic integer in $\var{nf}$, and the components of $r$ are reasonably small. The library syntax is \fun{GEN}{nfdivrem}{GEN nf, GEN x, GEN y}. \subsec{nfeltembed$(\var{nf},x,\{\var{pl}\})$}\kbdsidx{nfeltembed}\label{se:nfeltembed} Given an element $x$ in the number field \var{nf}, return the (real or) complex embeddings of $x$ specified by optional argument \var{pl}, at the current \kbd{realprecision}: \item \var{pl} omitted: return the vector of embeddings at all $r_1+r_2$ places; \item \var{pl} an integer between $1$ and $r_1+r_2$: return the $i$-th embedding of $x$, attached to the $i$-th root of \kbd{nf.pol}, i.e. \kbd{nf.roots$[i]$}; \item \var{pl} a vector or \typ{VECSMALL}: return the vector of embeddings; the $i$-th entry gives the embedding at the place attached to the $\var{pl}[i]$-th real root of \kbd{nf.pol}. \bprog ? nf = nfinit('y^3 - 2); ? nf.sign %2 = [1, 1] ? nfeltembed(nf, 'y) %3 = [1.25992[...], -0.62996[...] + 1.09112[...]*I]] ? nfeltembed(nf, 'y, 1) %4 = 1.25992[...] ? nfeltembed(nf, 'y, 3) \\ there are only 2 arch. places *** at top-level: nfeltembed(nf,'y,3) *** ^----------------- *** nfeltembed: domain error in nfeltembed: index > 2 @eprog The library syntax is \fun{GEN}{nfeltembed}{GEN nf, GEN x, GEN pl = NULL, long prec}. \subsec{nfeltmod$(\var{nf},x,y)$}\kbdsidx{nfeltmod}\label{se:nfeltmod} Given two elements $x$ and $y$ in \var{nf}, computes an element $r$ of $\var{nf}$ of the form $r=x-qy$ with $q$ and algebraic integer, and such that $r$ is small. This is functionally identical to $$\kbd{x - nfmul(\var{nf},round(nfdiv(\var{nf},x,y)),y)}.$$ The library syntax is \fun{GEN}{nfmod}{GEN nf, GEN x, GEN y}. \subsec{nfeltmul$(\var{nf},x,y)$}\kbdsidx{nfeltmul}\label{se:nfeltmul} Given two elements $x$ and $y$ in \var{nf}, computes their product $x*y$ in the number field $\var{nf}$. The library syntax is \fun{GEN}{nfmul}{GEN nf, GEN x, GEN y}. \subsec{nfeltmulmodpr$(\var{nf},x,y,\var{pr})$}\kbdsidx{nfeltmulmodpr}\label{se:nfeltmulmodpr} This function is obsolete, use \kbd{nfmodpr}. Given two elements $x$ and $y$ in \var{nf} and \var{pr} a prime ideal in \kbd{modpr} format (see \tet{nfmodprinit}), computes their product $x*y$ modulo the prime ideal \var{pr}. The library syntax is \fun{GEN}{nfmulmodpr}{GEN nf, GEN x, GEN y, GEN pr}. This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. \subsec{nfeltnorm$(\var{nf},x)$}\kbdsidx{nfeltnorm}\label{se:nfeltnorm} Returns the absolute norm of $x$. The library syntax is \fun{GEN}{nfnorm}{GEN nf, GEN x}. \subsec{nfeltpow$(\var{nf},x,k)$}\kbdsidx{nfeltpow}\label{se:nfeltpow} Given an element $x$ in \var{nf}, and a positive or negative integer $k$, computes $x^k$ in the number field $\var{nf}$. The library syntax is \fun{GEN}{nfpow}{GEN nf, GEN x, GEN k}. \fun{GEN}{nfinv}{GEN nf, GEN x} correspond to $k = -1$, and \fun{GEN}{nfsqr}{GEN nf,GEN x} to $k = 2$. \subsec{nfeltpowmodpr$(\var{nf},x,k,\var{pr})$}\kbdsidx{nfeltpowmodpr}\label{se:nfeltpowmodpr} This function is obsolete, use \kbd{nfmodpr}. Given an element $x$ in \var{nf}, an integer $k$ and a prime ideal \var{pr} in \kbd{modpr} format (see \tet{nfmodprinit}), computes $x^k$ modulo the prime ideal \var{pr}. The library syntax is \fun{GEN}{nfpowmodpr}{GEN nf, GEN x, GEN k, GEN pr}. This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. \subsec{nfeltreduce$(\var{nf},a,\var{id})$}\kbdsidx{nfeltreduce}\label{se:nfeltreduce} Given an ideal \var{id} in Hermite normal form and an element $a$ of the number field $\var{nf}$, finds an element $r$ in $\var{nf}$ such that $a-r$ belongs to the ideal and $r$ is small. The library syntax is \fun{GEN}{nfreduce}{GEN nf, GEN a, GEN id}. \subsec{nfeltreducemodpr$(\var{nf},x,\var{pr})$}\kbdsidx{nfeltreducemodpr}\label{se:nfeltreducemodpr} This function is obsolete, use \kbd{nfmodpr}. Given an element $x$ of the number field $\var{nf}$ and a prime ideal \var{pr} in \kbd{modpr} format compute a canonical representative for the class of $x$ modulo \var{pr}. The library syntax is \fun{GEN}{nfreducemodpr}{GEN nf, GEN x, GEN pr}. This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. \subsec{nfeltsign$(\var{nf},x,\{\var{pl}\})$}\kbdsidx{nfeltsign}\label{se:nfeltsign} Given an element $x$ in the number field \var{nf}, returns the signs of the real embeddings of $x$ specified by optional argument \var{pl}: \item \var{pl} omitted: return the vector of signs at all $r_1$ real places; \item \var{pl} an integer between $1$ and $r_1$: return the sign of the $i$-th embedding of $x$, attached to the $i$-th real root of \kbd{nf.pol}, i.e. \kbd{nf.roots$[i]$}; \item \var{pl} a vector or \typ{VECSMALL}: return the vector of signs; the $i$-th entry gives the sign at the real place attached to the $\var{pl}[i]$-th real root of \kbd{nf.pol}. \bprog ? nf = nfinit(polsubcyclo(11,5,'y)); \\ Q(cos(2 pi/11)) ? nf.sign %2 = [5, 0] ? x = Mod('y, nf.pol); ? nfeltsign(nf, x) %4 = [-1, -1, -1, 1, 1] ? nfeltsign(nf, x, 1) %5 = -1 ? nfeltsign(nf, x, [1..4]) %6 = [-1, -1, -1, 1] ? nfeltsign(nf, x, 6) \\ there are only 5 real embeddings *** at top-level: nfeltsign(nf,x,6) *** ^----------------- *** nfeltsign: domain error in nfeltsign: index > 5 @eprog The library syntax is \fun{GEN}{nfeltsign}{GEN nf, GEN x, GEN pl = NULL}. \subsec{nfelttrace$(\var{nf},x)$}\kbdsidx{nfelttrace}\label{se:nfelttrace} Returns the absolute trace of $x$. The library syntax is \fun{GEN}{nftrace}{GEN nf, GEN x}. \subsec{nfeltval$(\var{nf},x,\var{pr},\{\&y\})$}\kbdsidx{nfeltval}\label{se:nfeltval} Given an element $x$ in \var{nf} and a prime ideal \var{pr} in the format output by \kbd{idealprimedec}, computes the valuation $v$ at \var{pr} of the element $x$. The valuation of $0$ is \kbd{+oo}. \bprog ? nf = nfinit(x^2 + 1); ? P = idealprimedec(nf, 2)[1]; ? nfeltval(nf, x+1, P) %3 = 1 @eprog\noindent This particular valuation can also be obtained using \kbd{idealval(\var{nf},x,\var{pr})}, since $x$ is then converted to a principal ideal. If the $y$ argument is present, sets $y = x \tau^v$, where $\tau$ is a fixed ``anti-uniformizer'' for \var{pr}: its valuation at \var{pr} is $-1$; its valuation is $0$ at other prime ideals dividing \kbd{\var{pr}.p} and nonnegative at all other primes. In other words $y$ is the part of $x$ coprime to \var{pr}. If $x$ is an algebraic integer, so is $y$. \bprog ? nfeltval(nf, x+1, P, &y); y %4 = [0, 1]~ @eprog For instance if $x = \prod_i x_i^{e_i}$ is known to be coprime to \var{pr}, where the $x_i$ are algebraic integers and $e_i\in\Z$ then, if $v_i = \kbd{nfeltval}(\var{nf}, x_i, \var{pr}, \&y_i)$, we still have $x = \prod_i y_i^{e_i}$, where the $y_i$ are still algebraic integers but now all of them are coprime to \var{pr}. They can then be mapped to the residue field of \var{pr} more efficiently than if the product had been expanded beforehand: we can reduce mod \var{pr} after each ring operation. The library syntax is \fun{GEN}{gpnfvalrem}{GEN nf, GEN x, GEN pr, GEN *y = NULL}. Also available are \fun{long}{nfvalrem}{GEN nf, GEN x, GEN pr, GEN *y = NULL}, which returns \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer, and \fun{long}{nfval}{GEN nf, GEN x, GEN pr}, which only returns the valuation ($y = \kbd{NULL}$). \subsec{nffactor$(\var{nf},T)$}\kbdsidx{nffactor}\label{se:nffactor} Factorization of the univariate polynomial $T$ over the number field $\var{nf}$ given by \kbd{nfinit}; $T$ has coefficients in $\var{nf}$ (i.e.~either scalar, polmod, polynomial or column vector). The factors are sorted by increasing degree. The main variable of $\var{nf}$ must be of \emph{lower} priority than that of $T$, see \secref{se:priority}. However if the polynomial defining the number field occurs explicitly in the coefficients of $T$ as modulus of a \typ{POLMOD} or as a \typ{POL} coefficient, its main variable must be \emph{the same} as the main variable of $T$. For example, \bprog ? nf = nfinit(y^2 + 1); ? nffactor(nf, x^2 + y); \\@com OK ? nffactor(nf, x^2 + Mod(y, y^2+1)); \\ @com OK ? nffactor(nf, x^2 + Mod(z, z^2+1)); \\ @com WRONG @eprog It is possible to input a defining polynomial for \var{nf} instead, but this is in general less efficient since parts of an \kbd{nf} structure will then be computed internally. This is useful in two situations: when you do not need the \kbd{nf} elsewhere, or when you cannot initialize an \kbd{nf} due to integer factorization difficulties when attempting to compute the field discriminant and maximal order. In all cases, the function runs in polynomial time using Belabas's variant of \idx{van Hoeij}'s algorithm, which copes with hundreds of modular factors. \misctitle{Caveat} \kbd{nfinit([T, listP])} allows to compute in polynomial time a conditional \var{nf} structure, which sets \kbd{nf.zk} to an order which is not guaranteed to be maximal at all primes. Always either use \kbd{nfcertify} first (which may not run in polynomial time) or make sure to input \kbd{nf.pol} instead of the conditional \var{nf}: \kbd{nffactor} is able to recover in polynomial time in this case, instead of potentially missing a factor. The library syntax is \fun{GEN}{nffactor}{GEN nf, GEN T}. \subsec{nffactorback$(\var{nf},f,\{e\})$}\kbdsidx{nffactorback}\label{se:nffactorback} Gives back the \var{nf} element corresponding to a factorization. The integer $1$ corresponds to the empty factorization. If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being integral), and the corresponding factorization is the product of the $f[i]^{e[i]}$. If not, and $f$ is vector, it is understood as in the preceding case with $e$ a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a regular factorization matrix. \bprog ? nf = nfinit(y^2+1); ? nffactorback(nf, [3, y+1, [1,2]~], [1, 2, 3]) %2 = [12, -66]~ ? 3 * (I+1)^2 * (1+2*I)^3 %3 = 12 - 66*I @eprog The library syntax is \fun{GEN}{nffactorback}{GEN nf, GEN f, GEN e = NULL}. \subsec{nffactormod$(\var{nf},Q,\var{pr})$}\kbdsidx{nffactormod}\label{se:nffactormod} This routine is obsolete, use \kbd{nfmodpr} and \kbd{factormod}. Factors the univariate polynomial $Q$ modulo the prime ideal \var{pr} in the number field $\var{nf}$. The coefficients of $Q$ belong to the number field (scalar, polmod, polynomial, even column vector) and the main variable of $\var{nf}$ must be of lower priority than that of $Q$ (see \secref{se:priority}). The prime ideal \var{pr} is either in \tet{idealprimedec} or (preferred) \tet{modprinit} format. The coefficients of the polynomial factors are lifted to elements of \var{nf}: \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K, 3)[1]; ? nffactormod(K, x^2 + y*x + 18*y+1, P) %3 = [x + (2*y + 1) 1] [x + (2*y + 2) 1] ? P = nfmodprinit(K, P); \\ convert to nfmodprinit format ? nffactormod(K, x^2 + y*x + 18*y+1) %5 = [x + (2*y + 1) 1] [x + (2*y + 2) 1] @eprog\noindent Same result, of course, here about 10\% faster due to the precomputation. The library syntax is \fun{GEN}{nffactormod}{GEN nf, GEN Q, GEN pr}. \subsec{nfgaloisapply$(\var{nf},\var{aut},x)$}\kbdsidx{nfgaloisapply}\label{se:nfgaloisapply} Let $\var{nf}$ be a number field as output by \kbd{nfinit}, and let \var{aut} be a \idx{Galois} automorphism of $\var{nf}$ expressed by its image on the field generator (such automorphisms can be found using \kbd{nfgaloisconj}). The function computes the action of the automorphism \var{aut} on the object $x$ in the number field; $x$ can be a number field element, or an ideal (possibly extended). Because of possible confusion with elements and ideals, other vector or matrix arguments are forbidden. \bprog ? nf = nfinit(x^2+1); ? L = nfgaloisconj(nf) %2 = [-x, x]~ ? aut = L[1]; /* the non-trivial automorphism */ ? nfgaloisapply(nf, aut, x) %4 = Mod(-x, x^2 + 1) ? P = idealprimedec(nf,5); /* prime ideals above 5 */ ? nfgaloisapply(nf, aut, P[2]) == P[1] %6 = 0 \\ !!!! ? idealval(nf, nfgaloisapply(nf, aut, P[2]), P[1]) %7 = 1 @eprog\noindent The surprising failure of the equality test (\kbd{\%7}) is due to the fact that although the corresponding prime ideals are equal, their representations are not. (A prime ideal is specified by a uniformizer, and there is no guarantee that applying automorphisms yields the same elements as a direct \kbd{idealprimedec} call.) The automorphism can also be given as a column vector, representing the image of \kbd{Mod(x, nf.pol)} as an algebraic number. This last representation is more efficient and should be preferred if a given automorphism must be used in many such calls. \bprog ? nf = nfinit(x^3 - 37*x^2 + 74*x - 37); ? aut = nfgaloisconj(nf)[2]; \\ @com an automorphism in basistoalg form %2 = -31/11*x^2 + 1109/11*x - 925/11 ? AUT = nfalgtobasis(nf, aut); \\ @com same in algtobasis form %3 = [16, -6, 5]~ ? v = [1, 2, 3]~; nfgaloisapply(nf, aut, v) == nfgaloisapply(nf, AUT, v) %4 = 1 \\ @com same result... ? for (i=1,10^5, nfgaloisapply(nf, aut, v)) time = 463 ms. ? for (i=1,10^5, nfgaloisapply(nf, AUT, v)) time = 343 ms. \\ @com but the latter is faster @eprog The library syntax is \fun{GEN}{galoisapply}{GEN nf, GEN aut, GEN x}. \subsec{nfgaloisconj$(\var{nf},\{\fl=0\},\{d\})$}\kbdsidx{nfgaloisconj}\label{se:nfgaloisconj} $\var{nf}$ being a number field as output by \kbd{nfinit}, computes the conjugates of a root $r$ of the non-constant polynomial $x=\var{nf}[1]$ expressed as polynomials in $r$. This also makes sense when the number field is not \idx{Galois} since some conjugates may lie in the field. $\var{nf}$ can simply be a polynomial. If no flags or $\fl=0$, use a combination of flag $4$ and $1$ and the result is always complete. There is no point whatsoever in using the other flags. If $\fl=1$, use \kbd{nfroots}: a little slow, but guaranteed to work in polynomial time. If $\fl=4$, use \kbd{galoisinit}: very fast, but only applies to (most) Galois fields. If the field is Galois with weakly super-solvable Galois group (see \tet{galoisinit}), return the complete list of automorphisms, else only the identity element. If present, $d$ is assumed to be a multiple of the least common denominator of the conjugates expressed as polynomial in a root of \var{pol}. This routine can only compute $\Q$-automorphisms, but it may be used to get $K$-automorphism for any base field $K$ as follows: \bprog rnfgaloisconj(nfK, R) = \\ K-automorphisms of L = K[X] / (R) { my(polabs, N,al,S, ala,k, vR); R *= Mod(1, nfK.pol); \\ convert coeffs to polmod elts of K vR = variable(R); al = Mod(variable(nfK.pol),nfK.pol); [polabs,ala,k] = rnfequation(nfK, R, 1); Rt = if(k==0,R,subst(R,vR,vR-al*k)); N = nfgaloisconj(polabs) % Rt; \\ Q-automorphisms of L S = select(s->subst(Rt, vR, Mod(s,Rt)) == 0, N); if (k==0, S, apply(s->subst(s,vR,vR+k*al)-k*al,S)); } K = nfinit(y^2 + 7); rnfgaloisconj(K, x^4 - y*x^3 - 3*x^2 + y*x + 1) \\ K-automorphisms of L @eprog The library syntax is \fun{GEN}{galoisconj0}{GEN nf, long flag, GEN d = NULL, long prec}. Use directly \fun{GEN}{galoisconj}{GEN nf, GEN d}, corresponding to $\fl = 0$, the others only have historical interest. \subsec{nfgrunwaldwang$(\var{nf},\var{Lpr},\var{Ld},\var{pl},\{v='x\})$}\kbdsidx{nfgrunwaldwang}\label{se:nfgrunwaldwang} Given \var{nf} a number field in \var{nf} or \var{bnf} format, a \typ{VEC} \var{Lpr} of primes of \var{nf} and a \typ{VEC} \var{Ld} of positive integers of the same length, a \typ{VECSMALL} \var{pl} of length $r_1$ the number of real places of \var{nf}, computes a polynomial with coefficients in \var{nf} defining a cyclic extension of \var{nf} of minimal degree satisfying certain local conditions: \item at the prime~$Lpr[i]$, the extension has local degree a multiple of~$Ld[i]$; \item at the $i$-th real place of \var{nf}, it is complex if $pl[i]=-1$ (no condition if $pl[i]=0$). The extension has degree the LCM of the local degrees. Currently, the degree is restricted to be a prime power for the search, and to be prime for the construction because of the \kbd{rnfkummer} restrictions. When \var{nf} is $\Q$, prime integers are accepted instead of \kbd{prid} structures. However, their primality is not checked and the behavior is undefined if you provide a composite number. \misctitle{Warning} If the number field \var{nf} does not contain the $n$-th roots of unity where $n$ is the degree of the extension to be computed, triggers the computation of the \var{bnf} of $nf(\zeta_n)$, which may be costly. \bprog ? nf = nfinit(y^2-5); ? pr = idealprimedec(nf,13)[1]; ? pol = nfgrunwaldwang(nf, [pr], [2], [0,-1], 'x) %3 = x^2 + Mod(3/2*y + 13/2, y^2 - 5) @eprog The library syntax is \fun{GEN}{nfgrunwaldwang}{GEN nf, GEN Lpr, GEN Ld, GEN pl, long v = -1} where \kbd{v} is a variable number. \subsec{nfhilbert$(\var{nf},a,b,\{\var{pr}\})$}\kbdsidx{nfhilbert}\label{se:nfhilbert} If \var{pr} is omitted, compute the global quadratic \idx{Hilbert symbol} $(a,b)$ in $\var{nf}$, that is $1$ if $x^2 - a y^2 - b z^2$ has a non trivial solution $(x,y,z)$ in $\var{nf}$, and $-1$ otherwise. Otherwise compute the local symbol modulo the prime ideal \var{pr}, as output by \kbd{idealprimedec}. The library syntax is \fun{long}{nfhilbert0}{GEN nf, GEN a, GEN b, GEN pr = NULL}. Also available is \fun{long}{nfhilbert}{GEN bnf,GEN a,GEN b} (global quadratic Hilbert symbol). \subsec{nfhnf$(\var{nf},x,\{\fl=0\})$}\kbdsidx{nfhnf}\label{se:nfhnf} Given a pseudo-matrix $(A,I)$, finds a pseudo-basis $(B,J)$ in \idx{Hermite normal form} of the module it generates. If $\fl$ is non-zero, also return the transformation matrix $U$ such that $AU = [0|B]$. The library syntax is \fun{GEN}{nfhnf0}{GEN nf, GEN x, long flag}. Also available: \fun{GEN}{nfhnf}{GEN nf, GEN x} ($\fl = 0$). \fun{GEN}{rnfsimplifybasis}{GEN bnf, GEN x} simplifies the pseudo-basis $x = (A,I)$, returning a pseudo-basis $(B,J)$. The ideals in the list $J$ are integral, primitive and either trivial (equal to the full ring of integer) or non-principal. \subsec{nfhnfmod$(\var{nf},x,\var{detx})$}\kbdsidx{nfhnfmod}\label{se:nfhnfmod} Given a pseudo-matrix $(A,I)$ and an ideal \var{detx} which is contained in (read integral multiple of) the determinant of $(A,I)$, finds a pseudo-basis in \idx{Hermite normal form} of the module generated by $(A,I)$. This avoids coefficient explosion. \var{detx} can be computed using the function \kbd{nfdetint}. The library syntax is \fun{GEN}{nfhnfmod}{GEN nf, GEN x, GEN detx}. \subsec{nfinit$(\var{pol},\{\fl=0\})$}\kbdsidx{nfinit}\label{se:nfinit} \var{pol} being a non-constant, preferably monic, irreducible polynomial in $\Z[X]$, initializes a \emph{number field} structure (\kbd{nf}) attached to the field $K$ defined by \var{pol}. As such, it's a technical object passed as the first argument to most \kbd{nf}\var{xxx} functions, but it contains some information which may be directly useful. Access to this information via \emph{member functions} is preferred since the specific data organization given below may change in the future. Currently, \kbd{nf} is a row vector with 9 components: $\var{nf}[1]$ contains the polynomial \var{pol} (\kbd{\var{nf}.pol}). $\var{nf}[2]$ contains $[r1,r2]$ (\kbd{\var{nf}.sign}, \kbd{\var{nf}.r1}, \kbd{\var{nf}.r2}), the number of real and complex places of $K$. $\var{nf}[3]$ contains the discriminant $d(K)$ (\kbd{\var{nf}.disc}) of $K$. $\var{nf}[4]$ contains the index of $\var{nf}[1]$ (\kbd{\var{nf}.index}), i.e.~$[\Z_K : \Z[\theta]]$, where $\theta$ is any root of $\var{nf}[1]$. $\var{nf}[5]$ is a vector containing 7 matrices $M$, $G$, \var{roundG}, $T$, $MD$, $TI$, $MDI$ useful for certain computations in the number field $K$. \quad\item $M$ is the $(r1+r2)\times n$ matrix whose columns represent the numerical values of the conjugates of the elements of the integral basis. \quad\item $G$ is an $n\times n$ matrix such that $T2 = {}^t G G$, where $T2$ is the quadratic form $T_2(x) = \sum |\sigma(x)|^2$, $\sigma$ running over the embeddings of $K$ into $\C$. \quad\item \var{roundG} is a rescaled copy of $G$, rounded to nearest integers. \quad\item $T$ is the $n\times n$ matrix whose coefficients are $\text{Tr}(\omega_i\omega_j)$ where the $\omega_i$ are the elements of the integral basis. Note also that $\det(T)$ is equal to the discriminant of the field $K$. Also, when understood as an ideal, the matrix $T^{-1}$ generates the codifferent ideal. \quad\item The columns of $MD$ (\kbd{\var{nf}.diff}) express a $\Z$-basis of the different of $K$ on the integral basis. \quad\item $TI$ is equal to the primitive part of $T^{-1}$, which has integral coefficients. \quad\item Finally, $MDI$ is a two-element representation (for faster ideal product) of $d(K)$ times the codifferent ideal (\kbd{\var{nf}.disc$*$\var{nf}.codiff}, which is an integral ideal). $MDI$ is only used in \tet{idealinv}. $\var{nf}[6]$ is the vector containing the $r1+r2$ roots (\kbd{\var{nf}.roots}) of $\var{nf}[1]$ corresponding to the $r1+r2$ embeddings of the number field into $\C$ (the first $r1$ components are real, the next $r2$ have positive imaginary part). $\var{nf}[7]$ is an integral basis for $\Z_K$ (\kbd{\var{nf}.zk}) expressed on the powers of~$\theta$. Its first element is guaranteed to be $1$. This basis is LLL-reduced with respect to $T_2$ (strictly speaking, it is a permutation of such a basis, due to the condition that the first element be $1$). $\var{nf}[8]$ is the $n\times n$ integral matrix expressing the power basis in terms of the integral basis, and finally $\var{nf}[9]$ is the $n\times n^2$ matrix giving the multiplication table of the integral basis. If a non monic polynomial is input, \kbd{nfinit} will transform it into a monic one, then reduce it (see $\fl=3$). It is allowed, though not very useful given the existence of \tet{nfnewprec}, to input a \var{nf} or a \var{bnf} instead of a polynomial. It is also allowed to input a \var{rnf}, in which case an \kbd{nf} structure attached to the absolute defining polynomial \kbd{polabs} is returned (\fl is then ignored). \bprog ? nf = nfinit(x^3 - 12); \\ initialize number field Q[X] / (X^3 - 12) ? nf.pol \\ defining polynomial %2 = x^3 - 12 ? nf.disc \\ field discriminant %3 = -972 ? nf.index \\ index of power basis order in maximal order %4 = 2 ? nf.zk \\ integer basis, lifted to Q[X] %5 = [1, x, 1/2*x^2] ? nf.sign \\ signature %6 = [1, 1] ? factor(abs(nf.disc )) \\ determines ramified primes %7 = [2 2] [3 5] ? idealfactor(nf, 2) %8 = [[2, [0, 0, -1]~, 3, 1, [0, 1, 0]~] 3] \\ @com $\goth{p}_2^3$ @eprog \misctitle{Huge discriminants, helping nfdisc} In case \var{pol} has a huge discriminant which is difficult to factor, it is hard to compute from scratch the maximal order. The special input format $[\var{pol}, B]$ is also accepted where \var{pol} is a polynomial as above and $B$ has one of the following forms \item an integer basis, as would be computed by \tet{nfbasis}: a vector of polynomials with first element $1$. This is useful if the maximal order is known in advance. \item an argument \kbd{listP} which specifies a list of primes (see \tet{nfbasis}). Instead of the maximal order, \kbd{nfinit} then computes an order which is maximal at these particular primes as well as the primes contained in the private prime table (see \tet{addprimes}). The result is unconditionaly correct when the discriminant \kbd{nf.disc} factors completely over this set of primes. The function \tet{nfcertify} automates this: \bprog ? pol = polcompositum(x^5 - 101, polcyclo(7))[1]; ? nf = nfinit( [pol, 10^3] ); ? nfcertify(nf) %3 = [] @eprog\noindent A priori, \kbd{nf.zk} defines an order which is only known to be maximal at all primes $\leq 10^3$ (no prime $\leq 10^3$ divides \kbd{nf.index}). The certification step proves the correctness of the computation. Had it failed, that particular \kbd{nf} structure could not have been trusted and may have caused routines using it to fail randomly. One particular function that remains trustworthy in all cases is \kbd{idealprimedec} when applied to a prime included in the above list of primes or, more generally, a prime not dividing any entry in \kbd{nfcertify} output. \medskip If $\fl=2$: \var{pol} is changed into another polynomial $P$ defining the same number field, which is as simple as can easily be found using the \tet{polredbest} algorithm, and all the subsequent computations are done using this new polynomial. In particular, the first component of the result is the modified polynomial. If $\fl=3$, apply \kbd{polredbest} as in case 2, but outputs $[\var{nf},\kbd{Mod}(a,P)]$, where $\var{nf}$ is as before and $\kbd{Mod}(a,P)=\kbd{Mod}(x,\var{pol})$ gives the change of variables. This is implicit when \var{pol} is not monic: first a linear change of variables is performed, to get a monic polynomial, then \kbd{polredbest}. The library syntax is \fun{GEN}{nfinit0}{GEN pol, long flag, long prec}. Also available are \fun{GEN}{nfinit}{GEN x, long prec} ($\fl = 0$), \fun{GEN}{nfinitred}{GEN x, long prec} ($\fl = 2$), \fun{GEN}{nfinitred2}{GEN x, long prec} ($\fl = 3$). Instead of the above hardcoded numerical flags in \kbd{nfinit0}, one should rather use \fun{GEN}{nfinitall}{GEN x, long flag, long prec}, where \fl\ is an or-ed combination of \item \tet{nf_RED}: find a simpler defining polynomial, \item \tet{nf_ORIG}: if \tet{nf_RED} set, also return the change of variable, \item \tet{nf_ROUND2}: \emph{Deprecated}. Slow down the routine by using an obsolete normalization algorithm (do not use this one!), \item \tet{nf_PARTIALFACT}: \emph{Deprecated}. Lazy factorization of the polynomial discriminant. Result is conditional unless \kbd{nfcertify} can certify it. \subsec{nfisideal$(\var{nf},x)$}\kbdsidx{nfisideal}\label{se:nfisideal} Returns 1 if $x$ is an ideal in the number field $\var{nf}$, 0 otherwise. The library syntax is \fun{long}{isideal}{GEN nf, GEN x}. \subsec{nfisincl$(f,g)$}\kbdsidx{nfisincl}\label{se:nfisincl} Let $f$ and $g$ define number fields, where $f$ and $g$ are irreducible polynomials in $\Q[X]$ and \var{nf} structures as output by \kbd{nfinit}. Tests whether the number field $f$ is conjugate to a subfield of the field $g$. If they are not, the output is the integer 0. If they are, the output is a vector of polynomials, each polynomial $a$ representing an embedding i.e.~being such that $g\mid f\circ a$. If either $f$ or $g$ is not irreducible, the result is undefined. \bprog ? T = x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10; ? U = x^3 + 3*x^2 + 3*x - 2 ? v = nfisincl(U, T); %2 = [24/179*x^5-27/179*x^4+80/179*x^3-234/179*x^2+380/179*x+94/179] ? subst(U, x, Mod(v[1],T)) %3 = Mod(0, x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10) ? #nfisincl(x^2+1, T) \\ two embeddings %4 = 2 \\ same result with nf structures ? nfisincl(U, L = nfinit(T)) == v %5 = 1 ? nfisincl(K = nfinit(U), T) == v %6 = 1 ? nfisincl(K, L) == v %7 = 1 \\ comparative bench: an nf is a little faster, esp. for the subfield ? B = 10^3; ? for (i=1, B, nfisincl(U,T)) time = 712 ms. ? for (i=1, B, nfisincl(K,T)) time = 485 ms. ? for (i=1, B, nfisincl(U,L)) time = 704 ms. ? for (i=1, B, nfisincl(K,L)) time = 465 ms. @eprog\noindent Using an \var{nf} structure for the potential subfield is faster if the structure is already available. On the other hand, the gain in \kbd{nfisincl} is usually not sufficient to make it worthwhile to initialize only for that purpose. \bprog ? for (i=1, B, nfinit(U)) time = 308 ms. @eprog The library syntax is \fun{GEN}{nfisincl}{GEN f, GEN g}. \subsec{nfisisom$(f,g)$}\kbdsidx{nfisisom}\label{se:nfisisom} As \tet{nfisincl}, but tests for isomorphism. More efficient if $f$ or $g$ is a number field structure. \bprog ? f = x^6 + 30*x^5 + 495*x^4 + 1870*x^3 + 16317*x^2 - 22560*x + 59648; ? g = x^6 + 42*x^5 + 999*x^4 + 8966*x^3 + 36117*x^2 + 21768*x + 159332; ? h = x^6 + 30*x^5 + 351*x^4 + 2240*x^3 + 10311*x^2 + 35466*x + 58321; ? #nfisisom(f,g) \\ two isomorphisms %3 = 2 ? nfisisom(f,h) \\ not isomorphic %4 = 0 \\ comparative bench ? K = nfinit(f); L = nfinit(g); B = 10^3; ? for (i=1, B, nfisisom(f,g)) time = 6,124 ms. ? for (i=1, B, nfisisom(K,g)) time = 3,356 ms. ? for (i=1, B, nfisisom(f,L)) time = 3,204 ms. ? for (i=1, B, nfisisom(K,L)) time = 3,173 ms. @eprog\noindent The function is usually very fast when the fields are non-isomorphic, whenever the fields can be distinguished via a simple invariant such as degree, signature or discriminant. It may be slower when the fields share all invariants, but still faster than computing actual isomorphisms: \bprog \\ usually very fast when the answer is 'no': ? for (i=1, B, nfisisom(f,h)) time = 32 ms. \\ but not always ? u = x^6 + 12*x^5 + 6*x^4 - 377*x^3 - 714*x^2 + 5304*x + 15379 ? v = x^6 + 12*x^5 + 60*x^4 + 166*x^3 + 708*x^2 + 6600*x + 23353 ? nfisisom(u,v) %13 = 0 ? polsturm(u) == polsturm(v) %14 = 1 ? nfdisc(u) == nfdisc(v) %15 = 1 ? for(i=1,B, nfisisom(u,v)) time = 1,821 ms. ? K = nfinit(u); L = nfinit(v); ? for(i=1,B, nfisisom(K,v)) time = 232 ms. @eprog The library syntax is \fun{GEN}{nfisisom}{GEN f, GEN g}. \subsec{nfislocalpower$(\var{nf},\var{pr},a,n)$}\kbdsidx{nfislocalpower}\label{se:nfislocalpower} Let \var{nf} be a \var{nf} structure attached to a number field $K$, let $a \in K$ and let \var{pr} be a \var{prid} structure attached to a maximal ideal $v$. Return $1$ if $a$ is an $n$-th power in the completed local field $K_v$, and $0$ otherwise. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K,2)[1]; \\ the ramified prime above 2 ? nfislocalpower(K,P,-1, 2) \\ -1 is a square %3 = 1 ? nfislocalpower(K,P,-1, 4) \\ ... but not a 4-th power %4 = 0 ? nfislocalpower(K,P,2, 2) \\ 2 is not a square %5 = 0 ? Q = idealprimedec(K,5)[1]; \\ a prime above 5 ? nfislocalpower(K,Q, [0, 32]~, 30) \\ 32*I is locally a 30-th power %7 = 1 @eprog The library syntax is \fun{long}{nfislocalpower}{GEN nf, GEN pr, GEN a, GEN n}. \subsec{nfkermodpr$(\var{nf},x,\var{pr})$}\kbdsidx{nfkermodpr}\label{se:nfkermodpr} This function is obsolete, use \kbd{nfmodpr}. Kernel of the matrix $a$ in $\Z_K/\var{pr}$, where \var{pr} is in \key{modpr} format (see \kbd{nfmodprinit}). The library syntax is \fun{GEN}{nfkermodpr}{GEN nf, GEN x, GEN pr}. This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nfM\_to\_FqM}, then work there. \subsec{nfmodpr$(\var{nf},x,\var{pr})$}\kbdsidx{nfmodpr}\label{se:nfmodpr} Map $x$ to a \typ{FFELT} in the residue field modulo \var{pr}. The argument \var{pr} is either a maximal ideal in \kbd{idealprimedec} format or, preferably, a \var{modpr} structure from \tet{nfmodprinit}. The function \tet{nfmodprlift} allows to lift back to $\Z_K$. Note that the function applies to number field elements and not to vector / matrices / polynomials of such. Use \kbd{apply} to convert recursive structures. \bprog ? K = nfinit(y^3-250); ? P = idealprimedec(K, 5)[2]; ? modP = nfmodprinit(K,P); ? K.zk %4 = [1, 1/5*y, 1/25*y^2] ? apply(t->nfmodpr(K,t,modP), K.zk) %5 = [1, y, 2*y + 1] @eprog The library syntax is \fun{GEN}{nfmodpr}{GEN nf, GEN x, GEN pr}. \subsec{nfmodprinit$(\var{nf},\var{pr})$}\kbdsidx{nfmodprinit}\label{se:nfmodprinit} Transforms the prime ideal \var{pr} into \tet{modpr} format necessary for all operations modulo \var{pr} in the number field \var{nf}. The functions \tet{nfmodpr} and \tet{nfmodprlift} allow to project to and lift from the residue field. The library syntax is \fun{GEN}{nfmodprinit}{GEN nf, GEN pr}. \subsec{nfmodprlift$(\var{nf},x,\var{pr})$}\kbdsidx{nfmodprlift}\label{se:nfmodprlift} Lift the \typ{FFELT} $x$ (from \tet{nfmodpr}) in the residue field modulo \var{pr} to the ring of integers. Vectors and matrices are also supported. For polynomials, use \kbd{apply} and the present function. The argument \var{pr} is either a maximal ideal in \kbd{idealprimedec} format or, preferably, a \var{modpr} structure from \tet{nfmodprinit}. There are no compatibility checks to try and decide whether $x$ is attached the same residue field as defined by \var{pr}: the result is undefined if not. The function \tet{nfmodpr} allows to reduce to the residue field. \bprog ? K = nfinit(y^3-250); ? P = idealprimedec(K, 5)[2]; ? modP = nfmodprinit(K,P); ? K.zk %4 = [1, 1/5*y, 1/25*y^2] ? apply(t->nfmodpr(K,t,modP), K.zk) %5 = [1, y, 2*y + 1] ? nfmodprlift(K, %, modP) %6 = [1, 1/5*y, 2/5*y + 1] ? nfeltval(K, %[3] - K.zk[3], P) %7 = 1 @eprog The library syntax is \fun{GEN}{nfmodprlift}{GEN nf, GEN x, GEN pr}. \subsec{nfnewprec$(\var{nf})$}\kbdsidx{nfnewprec}\label{se:nfnewprec} Transforms the number field $\var{nf}$ into the corresponding data using current (usually larger) precision. This function works as expected if \var{nf} is in fact a \var{bnf} or a \var{bnr} (update structure to current precision) but may be quite slow: many generators of principal ideals have to be computed; note that in this latter case, the \var{bnf} must contain fundamental units. The library syntax is \fun{GEN}{nfnewprec}{GEN nf, long prec}. See also \fun{GEN}{bnfnewprec}{GEN bnf, long prec} and \fun{GEN}{bnrnewprec}{GEN bnr, long prec}. \subsec{nfpolsturm$(\var{nf}, T, \{\var{pl}\})$}\kbdsidx{nfpolsturm}\label{se:nfpolsturm} Given a polynomial $T$ with coefficients in the number field \var{nf}, returns the number of real roots of the $s(T)$ where $s$ runs through the real embeddings of the field specified by optional argument \var{pl}: \item \var{pl} omitted: all $r_1$ real places; \item \var{pl} an integer between $1$ and $r_1$: the embedding attached to the $i$-th real root of \kbd{nf.pol}, i.e. \kbd{nf.roots$[i]$}; \item \var{pl} a vector or \typ{VECSMALL}: the embeddings attached to the $\var{pl}[i]$-th real roots of \kbd{nf.pol}. \bprog ? nf = nfinit('y^2 - 2); ? nf.sign %2 = [2, 0] ? nf.roots %3 = [-1.414..., 1.414...] ? T = x^2 + 'y; ? nfpolsturm(nf, T, 1) \\ subst(T,y,sqrt(2)) has two real roots %5 = 2 ? nfpolsturm(nf, T, 2) \\ subst(T,y,-sqrt(2)) has no real root %6 = 0 ? nfpolsturm(nf, T) \\ all embeddings together %7 = [2, 0] ? nfpolsturm(nf, T, [2,1]) \\ second then first embedding %8 = [0, 2] ? nfpolsturm(nf, x^3) \\ number of distinct roots ! %9 = [1, 1] ? nfpolsturm(nf, x, 6) \\ there are only 2 real embeddings ! *** at top-level: nfpolsturm(nf,x,6) *** ^----------------- *** nfpolsturm: domain error in nfpolsturm: index > 2 @eprog The library syntax is \fun{GEN}{nfpolsturm}{GEN nf, GEN T, GEN pl = NULL}. \subsec{nfroots$(\{\var{nf}\},x)$}\kbdsidx{nfroots}\label{se:nfroots} Roots of the polynomial $x$ in the number field $\var{nf}$ given by \kbd{nfinit} without multiplicity (in $\Q$ if $\var{nf}$ is omitted). $x$ has coefficients in the number field (scalar, polmod, polynomial, column vector). The main variable of $\var{nf}$ must be of lower priority than that of $x$ (see \secref{se:priority}). However if the coefficients of the number field occur explicitly (as polmods) as coefficients of $x$, the variable of these polmods \emph{must} be the same as the main variable of $t$ (see \kbd{nffactor}). It is possible to input a defining polynomial for \var{nf} instead, but this is in general less efficient since parts of an \kbd{nf} structure will then be computed internally. This is useful in two situations: when you do not need the \kbd{nf} elsewhere, or when you cannot initialize an \kbd{nf} due to integer factorization difficulties when attempting to compute the field discriminant and maximal order. \misctitle{Caveat} \kbd{nfinit([T, listP])} allows to compute in polynomial time a conditional \var{nf} structure, which sets \kbd{nf.zk} to an order which is not guaranteed to be maximal at all primes. Always either use \kbd{nfcertify} first (which may not run in polynomial time) or make sure to input \kbd{nf.pol} instead of the conditional \var{nf}: \kbd{nfroots} is able to recover in polynomial time in this case, instead of potentially missing a factor. The library syntax is \fun{GEN}{nfroots}{GEN nf = NULL, GEN x}. See also \fun{GEN}{nfrootsQ}{GEN x}, corresponding to $\kbd{nf} = \kbd{NULL}$. \subsec{nfrootsof1$(\var{nf})$}\kbdsidx{nfrootsof1}\label{se:nfrootsof1} Returns a two-component vector $[w,z]$ where $w$ is the number of roots of unity in the number field \var{nf}, and $z$ is a primitive $w$-th root of unity. \bprog ? K = nfinit(polcyclo(11)); ? nfrootsof1(K) %2 = [22, [0, 0, 0, 0, 0, -1, 0, 0, 0, 0]~] ? z = nfbasistoalg(K, %[2]) \\ in algebraic form %3 = Mod(-x^5, x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) ? [lift(z^11), lift(z^2)] \\ proves that the order of z is 22 %4 = [-1, -x^9 - x^8 - x^7 - x^6 - x^5 - x^4 - x^3 - x^2 - x - 1] @eprog This function guesses the number $w$ as the gcd of the $\#k(v)^*$ for unramified $v$ above odd primes, then computes the roots in \var{nf} of the $w$-th cyclotomic polynomial: the algorithm is polynomial time with respect to the field degree and the bitsize of the multiplication table in \var{nf} (both of them polynomially bounded in terms of the size of the discriminant). Fields of degree up to $100$ or so should require less than one minute. The library syntax is \fun{GEN}{rootsof1}{GEN nf}. Also available is \fun{GEN}{rootsof1_kannan}{GEN nf}, that computes all algebraic integers of $T_2$ norm equal to the field degree (all roots of $1$, by Kronecker's theorem). This is in general a little faster than the default when there \emph{are} roots of $1$ in the field (say twice faster), but can be much slower (say, \emph{days} slower), since the algorithm is a priori exponential in the field degree. \subsec{nfsnf$(\var{nf},x,\{\fl=0\})$}\kbdsidx{nfsnf}\label{se:nfsnf} Given a torsion $\Z_K$-module $x$ attached to the square integral invertible pseudo-matrix $(A,I,J)$, returns an ideal list $D=[d_1,\dots,d_n]$ which is the \idx{Smith normal form} of $x$. In other words, $x$ is isomorphic to $\Z_K/d_1\oplus\cdots\oplus\Z_K/d_n$ and $d_i$ divides $d_{i-1}$ for $i\ge2$. If $\fl$ is non-zero return $[D,U,V]$, where $UAV$ is the identity. See \secref{se:ZKmodules} for the definition of integral pseudo-matrix; briefly, it is input as a 3-component row vector $[A,I,J]$ where $I = [b_1,\dots,b_n]$ and $J = [a_1,\dots,a_n]$ are two ideal lists, and $A$ is a square $n\times n$ matrix with columns $(A_1,\dots,A_n)$, seen as elements in $K^n$ (with canonical basis $(e_1,\dots,e_n)$). This data defines the $\Z_K$ module $x$ given by $$ (b_1e_1\oplus\cdots\oplus b_ne_n) / (a_1A_1\oplus\cdots\oplus a_nA_n) \enspace, $$ The integrality condition is $a_{i,j} \in b_i a_j^{-1}$ for all $i,j$. If it is not satisfied, then the $d_i$ will not be integral. Note that every finitely generated torsion module is isomorphic to a module of this form and even with $b_i=Z_K$ for all $i$. The library syntax is \fun{GEN}{nfsnf0}{GEN nf, GEN x, long flag}. Also available: \fun{GEN}{nfsnf}{GEN nf, GEN x} ($\fl = 0$). \subsec{nfsolvemodpr$(\var{nf},a,b,P)$}\kbdsidx{nfsolvemodpr}\label{se:nfsolvemodpr} This function is obsolete, use \kbd{nfmodpr}. Let $P$ be a prime ideal in \key{modpr} format (see \kbd{nfmodprinit}), let $a$ be a matrix, invertible over the residue field, and let $b$ be a column vector or matrix. This function returns a solution of $a\cdot x = b$; the coefficients of $x$ are lifted to \var{nf} elements. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K, 3)[1]; ? P = nfmodprinit(K, P); ? a = [y+1, y; y, 0]; b = [1, y]~ ? nfsolvemodpr(K, a,b, P) %5 = [1, 2]~ @eprog The library syntax is \fun{GEN}{nfsolvemodpr}{GEN nf, GEN a, GEN b, GEN P}. This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nfM\_to\_FqM}, then work there. \subsec{nfsplitting$(P,\{d\})$}\kbdsidx{nfsplitting}\label{se:nfsplitting} Defining polynomial over~$\Q$ for the splitting field of \var{P}, that is the smallest field over which $P$ is totally split. If $P$ can also be given by a~\kbd{nf} structure, which is more efficient. If $d$ is given, it must be a multiple of the splitting field degree. Note that if $P$ is reducible the splitting field degree can be smaller than the degree of $P$. \bprog ? K = nfinit(x^3-2); ? nfsplitting(K) %2 = x^6 + 108 ? nfsplitting(x^8-2) %3 = x^16 + 272*x^8 + 64 ? S = nfsplitting(x^6-8) // reducible %4 = x^4+2*x^2+4 ? lift(nfroots(subst(S,x,a),x^6-8)) %5 = [-a,a,-1/2*a^3-a,-1/2*a^3,1/2*a^3,1/2*a^3+a] @eprog \noindent Specifying the degree of the splitting field can make the computation faster. \bprog ? nfsplitting(x^17-123); time = 3,607 ms. ? poldegree(%) %2 = 272 ? nfsplitting(x^17-123,272); time = 150 ms. ? nfsplitting(x^17-123,273); *** nfsplitting: Warning: ignoring incorrect degree bound 273 time = 3,611 ms. @eprog \noindent The complexity of the algorithm is polynomial in the degree $d$ of the splitting field and the bitsize of $T$; if $d$ is large the result will likely be unusable, e.g. \kbd{nfinit} will not be an option: \bprog ? nfsplitting(x^6-x-1) [... degree 720 polynomial deleted ...] time = 11,020 ms. @eprog The library syntax is \fun{GEN}{nfsplitting}{GEN P, GEN d = NULL}. \subsec{nfsubfields$(\var{pol},\{d=0\})$}\kbdsidx{nfsubfields}\label{se:nfsubfields} Finds all subfields of degree $d$ of the number field defined by the (monic, integral) polynomial \var{pol} (all subfields if $d$ is null or omitted). The result is a vector of subfields, each being given by $[g,h]$, where $g$ is an absolute equation and $h$ expresses one of the roots of $g$ in terms of the root $x$ of the polynomial defining $\var{nf}$. This routine uses J.~Kl\"uners's algorithm in the general case, and B.~Allombert's \tet{galoissubfields} when \var{nf} is Galois (with weakly supersolvable Galois group).\sidx{Galois}\sidx{subfield} The library syntax is \fun{GEN}{nfsubfields}{GEN pol, long d}. \subsec{polcompositum$(P,Q,\{\fl=0\})$}\kbdsidx{polcompositum}\label{se:polcompositum} \sidx{compositum} $P$ and $Q$ being squarefree polynomials in $\Z[X]$ in the same variable, outputs the simple factors of the \'etale $\Q$-algebra $A = \Q(X, Y) / (P(X), Q(Y))$. The factors are given by a list of polynomials $R$ in $\Z[X]$, attached to the number field $\Q(X)/ (R)$, and sorted by increasing degree (with respect to lexicographic ordering for factors of equal degrees). Returns an error if one of the polynomials is not squarefree. Note that it is more efficient to reduce to the case where $P$ and $Q$ are irreducible first. The routine will not perform this for you, since it may be expensive, and the inputs are irreducible in most applications anyway. In this case, there will be a single factor $R$ if and only if the number fields defined by $P$ and $Q$ are linearly disjoint (their intersection is $\Q$). Assuming $P$ is irreducible (of smaller degree than $Q$ for efficiency), it is in general much faster to proceed as follows \bprog nf = nfinit(P); L = nffactor(nf, Q)[,1]; vector(#L, i, rnfequation(nf, L[i])) @eprog\noindent to obtain the same result. If you are only interested in the degrees of the simple factors, the \kbd{rnfequation} instruction can be replaced by a trivial \kbd{poldegree(P) * poldegree(L[i])}. The binary digits of $\fl$ mean 1: outputs a vector of 4-component vectors $[R,a,b,k]$, where $R$ ranges through the list of all possible compositums as above, and $a$ (resp. $b$) expresses the root of $P$ (resp. $Q$) as an element of $\Q(X)/(R)$. Finally, $k$ is a small integer such that $b + ka = X$ modulo $R$. 2: assume that $P$ and $Q$ define number fields which are linearly disjoint: both polynomials are irreducible and the corresponding number fields have no common subfield besides $\Q$. This allows to save a costly factorization over $\Q$. In this case return the single simple factor instead of a vector with one element. A compositum is often defined by a complicated polynomial, which it is advisable to reduce before further work. Here is an example involving the field $\Q(\zeta_5, 5^{1/5})$: \bprog ? L = polcompositum(x^5 - 5, polcyclo(5), 1); \\@com list of $[R,a,b,k]$ ? [R, a] = L[1]; \\@com pick the single factor, extract $R,a$ (ignore $b,k$) ? R \\@com defines the compositum %3 = x^20 + 5*x^19 + 15*x^18 + 35*x^17 + 70*x^16 + 141*x^15 + 260*x^14\ + 355*x^13 + 95*x^12 - 1460*x^11 - 3279*x^10 - 3660*x^9 - 2005*x^8 \ + 705*x^7 + 9210*x^6 + 13506*x^5 + 7145*x^4 - 2740*x^3 + 1040*x^2 \ - 320*x + 256 ? a^5 - 5 \\@com a fifth root of $5$ %4 = 0 ? [T, X] = polredbest(R, 1); ? T \\@com simpler defining polynomial for $\Q[x]/(R)$ %6 = x^20 + 25*x^10 + 5 ? X \\ @com root of $R$ in $\Q[y]/(T(y))$ %7 = Mod(-1/11*x^15 - 1/11*x^14 + 1/22*x^10 - 47/22*x^5 - 29/11*x^4 + 7/22,\ x^20 + 25*x^10 + 5) ? a = subst(a.pol, 'x, X) \\@com \kbd{a} in the new coordinates %8 = Mod(1/11*x^14 + 29/11*x^4, x^20 + 25*x^10 + 5) ? a^5 - 5 %9 = 0 @eprog\noindent In the above example, $x^5-5$ and the $5$-th cyclotomic polynomial are irreducible over $\Q$; they have coprime degrees so define linearly disjoint extensions and we could have started by \bprog ? [R,a] = polcompositum(x^5 - 5, polcyclo(5), 3); \\@com $[R,a,b,k]$ @eprog The library syntax is \fun{GEN}{polcompositum0}{GEN P, GEN Q, long flag}. Also available are \fun{GEN}{compositum}{GEN P, GEN Q} ($\fl = 0$) and \fun{GEN}{compositum2}{GEN P, GEN Q} ($\fl = 1$). \subsec{polgalois$(T)$}\kbdsidx{polgalois}\label{se:polgalois} \idx{Galois} group of the non-constant polynomial $T\in\Q[X]$. In the present version \vers, $T$ must be irreducible and the degree $d$ of $T$ must be less than or equal to 7. If the \tet{galdata} package has been installed, degrees 8, 9, 10 and 11 are also implemented. By definition, if $K = \Q[x]/(T)$, this computes the action of the Galois group of the Galois closure of $K$ on the $d$ distinct roots of $T$, up to conjugacy (corresponding to different root orderings). The output is a 4-component vector $[n,s,k,name]$ with the following meaning: $n$ is the cardinality of the group, $s$ is its signature ($s=1$ if the group is a subgroup of the alternating group $A_d$, $s=-1$ otherwise) and name is a character string containing name of the transitive group according to the GAP 4 transitive groups library by Alexander Hulpke. $k$ is more arbitrary and the choice made up to version~2.2.3 of PARI is rather unfortunate: for $d > 7$, $k$ is the numbering of the group among all transitive subgroups of $S_d$, as given in ``The transitive groups of degree up to eleven'', G.~Butler and J.~McKay, \emph{Communications in Algebra}, vol.~11, 1983, pp.~863--911 (group $k$ is denoted $T_k$ there). And for $d \leq 7$, it was ad hoc, so as to ensure that a given triple would denote a unique group. Specifically, for polynomials of degree $d\leq 7$, the groups are coded as follows, using standard notations \smallskip In degree 1: $S_1=[1,1,1]$. \smallskip In degree 2: $S_2=[2,-1,1]$. \smallskip In degree 3: $A_3=C_3=[3,1,1]$, $S_3=[6,-1,1]$. \smallskip In degree 4: $C_4=[4,-1,1]$, $V_4=[4,1,1]$, $D_4=[8,-1,1]$, $A_4=[12,1,1]$, $S_4=[24,-1,1]$. \smallskip In degree 5: $C_5=[5,1,1]$, $D_5=[10,1,1]$, $M_{20}=[20,-1,1]$, $A_5=[60,1,1]$, $S_5=[120,-1,1]$. \smallskip In degree 6: $C_6=[6,-1,1]$, $S_3=[6,-1,2]$, $D_6=[12,-1,1]$, $A_4=[12,1,1]$, $G_{18}=[18,-1,1]$, $S_4^-=[24,-1,1]$, $A_4\times C_2=[24,-1,2]$, $S_4^+=[24,1,1]$, $G_{36}^-=[36,-1,1]$, $G_{36}^+=[36,1,1]$, $S_4\times C_2=[48,-1,1]$, $A_5=PSL_2(5)=[60,1,1]$, $G_{72}=[72,-1,1]$, $S_5=PGL_2(5)=[120,-1,1]$, $A_6=[360,1,1]$, $S_6=[720,-1,1]$. \smallskip In degree 7: $C_7=[7,1,1]$, $D_7=[14,-1,1]$, $M_{21}=[21,1,1]$, $M_{42}=[42,-1,1]$, $PSL_2(7)=PSL_3(2)=[168,1,1]$, $A_7=[2520,1,1]$, $S_7=[5040,-1,1]$. \smallskip This is deprecated and obsolete, but for reasons of backward compatibility, we cannot change this behavior yet. So you can use the default \tet{new_galois_format} to switch to a consistent naming scheme, namely $k$ is always the standard numbering of the group among all transitive subgroups of $S_n$. If this default is in effect, the above groups will be coded as: \smallskip In degree 1: $S_1=[1,1,1]$. \smallskip In degree 2: $S_2=[2,-1,1]$. \smallskip In degree 3: $A_3=C_3=[3,1,1]$, $S_3=[6,-1,2]$. \smallskip In degree 4: $C_4=[4,-1,1]$, $V_4=[4,1,2]$, $D_4=[8,-1,3]$, $A_4=[12,1,4]$, $S_4=[24,-1,5]$. \smallskip In degree 5: $C_5=[5,1,1]$, $D_5=[10,1,2]$, $M_{20}=[20,-1,3]$, $A_5=[60,1,4]$, $S_5=[120,-1,5]$. \smallskip In degree 6: $C_6=[6,-1,1]$, $S_3=[6,-1,2]$, $D_6=[12,-1,3]$, $A_4=[12,1,4]$, $G_{18}=[18,-1,5]$, $A_4\times C_2=[24,-1,6]$, $S_4^+=[24,1,7]$, $S_4^-=[24,-1,8]$, $G_{36}^-=[36,-1,9]$, $G_{36}^+=[36,1,10]$, $S_4\times C_2=[48,-1,11]$, $A_5=PSL_2(5)=[60,1,12]$, $G_{72}=[72,-1,13]$, $S_5=PGL_2(5)=[120,-1,14]$, $A_6=[360,1,15]$, $S_6=[720,-1,16]$. \smallskip In degree 7: $C_7=[7,1,1]$, $D_7=[14,-1,2]$, $M_{21}=[21,1,3]$, $M_{42}=[42,-1,4]$, $PSL_2(7)=PSL_3(2)=[168,1,5]$, $A_7=[2520,1,6]$, $S_7=[5040,-1,7]$. \smallskip \misctitle{Warning} The method used is that of resolvent polynomials and is sensitive to the current precision. The precision is updated internally but, in very rare cases, a wrong result may be returned if the initial precision was not sufficient. The library syntax is \fun{GEN}{polgalois}{GEN T, long prec}. To enable the new format in library mode, set the global variable \tet{new_galois_format} to $1$. \subsec{polred$(T,\{\fl=0\})$}\kbdsidx{polred}\label{se:polred} This function is \emph{deprecated}, use \tet{polredbest} instead. Finds polynomials with reasonably small coefficients defining subfields of the number field defined by $T$. One of the polynomials always defines $\Q$ (hence has degree $1$), and another always defines the same number field as $T$ if $T$ is irreducible. All $T$ accepted by \tet{nfinit} are also allowed here; in particular, the format \kbd{[T, listP]} is recommended, e.g. with $\kbd{listP} = 10^5$ or a vector containing all ramified primes. Otherwise, the maximal order of $\Q[x]/(T)$ must be computed. The following binary digits of $\fl$ are significant: 1: Possibly use a suborder of the maximal order. The primes dividing the index of the order chosen are larger than \tet{primelimit} or divide integers stored in the \tet{addprimes} table. This flag is \emph{deprecated}, the \kbd{[T, listP]} format is more flexible. 2: gives also elements. The result is a two-column matrix, the first column giving primitive elements defining these subfields, the second giving the corresponding minimal polynomials. \bprog ? M = polred(x^4 + 8, 2) %1 = [ 1 x - 1] [ 1/2*x^2 + 1 x^2 - 2*x + 3] [-1/2*x^2 + 1 x^2 - 2*x + 3] [ 1/2*x^2 x^2 + 2] [ 1/4*x^3 x^4 + 2] ? minpoly(Mod(M[2,1], x^4+8)) %2 = x^2 + 2 @eprog \synt{polred}{GEN T} ($\fl = 0$). Also available is \fun{GEN}{polred2}{GEN T} ($\fl = 2$). The function \kbd{polred0} is deprecated, provided for backward compatibility. \subsec{polredabs$(T,\{\fl=0\})$}\kbdsidx{polredabs}\label{se:polredabs} Returns a canonical defining polynomial $P$ for the number field $\Q[X]/(T)$ defined by $T$, such that the sum of the squares of the modulus of the roots (i.e.~the $T_2$-norm) is minimal. Different $T$ defining isomorphic number fields will yield the same $P$. All $T$ accepted by \tet{nfinit} are also allowed here, e.g. non-monic polynomials, or pairs \kbd{[T, listP]} specifying that a non-maximal order may be used. For convenience, any number field structure (\var{nf}, \var{bnf},\dots) can also be used instead of $T$. \bprog ? polredabs(x^2 + 16) %1 = x^2 + 1 ? K = bnfinit(x^2 + 16); polredabs(K) %2 = x^2 + 1 @eprog \misctitle{Warning 1} Using a \typ{POL} $T$ requires computing and fully factoring the discriminant $d_K$ of the maximal order which may be very hard. You can use the format \kbd{[T, listP]}, where \kbd{listP} encodes a list of known coprime divisors of $\disc(T)$ (see \kbd{??nfbasis}), to help the routine, thereby replacing this part of the algorithm by a polynomial time computation But this may only compute a suborder of the maximal order, when the divisors are not squarefree or do not include all primes dividing $d_K$. The routine attempts to certify the result independently of this order computation as per \tet{nfcertify}: we try to prove that the computed order is maximal. If the certification fails, the routine then fully factors the integers returned by \kbd{nfcertify}. You can use \tet{polredbest} or \kbd{polredabs(,16)} to avoid this factorization step; in both cases, the result is no longer canonical. \misctitle{Warning 2} Apart from the factorization of the discriminant of $T$, this routine runs in polynomial time for a \emph{fixed} degree. But the complexity is exponential in the degree: this routine may be exceedingly slow when the number field has many subfields, hence a lot of elements of small $T_2$-norm. If you do not need a canonical polynomial, the function \tet{polredbest} is in general much faster (it runs in polynomial time), and tends to return polynomials with smaller discriminants. The binary digits of $\fl$ mean 1: outputs a two-component row vector $[P,a]$, where $P$ is the default output and \kbd{Mod(a, P)} is a root of the original $T$. 4: gives \emph{all} polynomials of minimal $T_2$ norm; of the two polynomials $P(x)$ and $\pm P(-x)$, only one is given. 16: Possibly use a suborder of the maximal order, \emph{without} attempting to certify the result as in Warning 1: we always return a polynomial and never $0$. The result is a priori not canonical. \bprog ? T = x^16 - 136*x^14 + 6476*x^12 - 141912*x^10 + 1513334*x^8 \ - 7453176*x^6 + 13950764*x^4 - 5596840*x^2 + 46225 ? T1 = polredabs(T); T2 = polredbest(T); ? [ norml2(polroots(T1)), norml2(polroots(T2)) ] %3 = [88.0000000, 120.000000] ? [ sizedigit(poldisc(T1)), sizedigit(poldisc(T2)) ] %4 = [75, 67] @eprog The precise definition of the output of \tet{polredabs} is as follows. \item Consider the finite list of characteristic polynomials of primitive elements of~$K$ that are in~$\Z_K$ and minimal for the~$T_2$ norm; now remove from the list the polynomials whose discriminant do not have minimal absolute value. Note that this condition is restricted to the original list of polynomials with minimal $T_2$ norm and does not imply that the defining polynomial for the field with smallest discriminant belongs to the list ! \item To a polynomial $P(x) = x^n + \dots + a_n \in \R[x]$ we attach the sequence $S(P)$ given by $|a_1|, a_1, \dots, |a_n|, a_n$. Order the polynomials $P$ by the lexicographic order on the coefficient vectors $S(P)$. Then the output of \tet{polredabs} is the smallest polynomial in the above list for that order. In other words, the monic polynomial which is lexicographically smallest with respect to the absolute values of coefficients, favouring negative coefficients to break ties, i.e. choosing $x^3-2$ rather than $x^3+2$. The library syntax is \fun{GEN}{polredabs0}{GEN T, long flag}. Instead of the above hardcoded numerical flags, one should use an or-ed combination of \item \tet{nf_PARTIALFACT}: possibly use a suborder of the maximal order, \emph{without} attempting to certify the result. \item \tet{nf_ORIG}: return $[P, a]$, where \kbd{Mod(a, P)} is a root of $T$. \item \tet{nf_RAW}: return $[P, b]$, where \kbd{Mod(b, T)} is a root of $P$. The algebraic integer $b$ is the raw result produced by the small vectors enumeration in the maximal order; $P$ was computed as the characteristic polynomial of \kbd{Mod(b, T)}. \kbd{Mod(a, P)} as in \tet{nf_ORIG} is obtained with \tet{modreverse}. \item \tet{nf_ADDZK}: if $r$ is the result produced with some of the above flags (of the form $P$ or $[P,c]$), return \kbd{[r,zk]}, where \kbd{zk} is a $\Z$-basis for the maximal order of $\Q[X]/(P)$. \item \tet{nf_ALL}: return a vector of results of the above form, for all polynomials of minimal $T_2$-norm. \subsec{polredbest$(T,\{\fl=0\})$}\kbdsidx{polredbest}\label{se:polredbest} Finds a polynomial with reasonably small coefficients defining the same number field as $T$. All $T$ accepted by \tet{nfinit} are also allowed here (e.g. non-monic polynomials, \kbd{nf}, \kbd{bnf}, \kbd{[T,Z\_K\_basis]}). Contrary to \tet{polredabs}, this routine runs in polynomial time, but it offers no guarantee as to the minimality of its result. This routine computes an LLL-reduced basis for an order in $\Q[X]/(T)$, then examines small linear combinations of the basis vectors, computing their characteristic polynomials. It returns the \emph{separable} polynomial $P$ of smallest discriminant, the one with lexicographically smallest \kbd{abs(Vec(P))} in case of ties. This is a good candidate for subsequent number field computations since it guarantees that the denominators of algebraic integers, when expressed in the power basis, are reasonably small. With no claim of minimality, though. It can happen that iterating this functions yields better and better polynomials, until it stabilizes: \bprog ? \p5 ? P = X^12+8*X^8-50*X^6+16*X^4-3069*X^2+625; ? poldisc(P)*1. %2 = 1.2622 E55 ? P = polredbest(P); ? poldisc(P)*1. %4 = 2.9012 E51 ? P = polredbest(P); ? poldisc(P)*1. %6 = 8.8704 E44 @eprog\noindent In this example, the initial polynomial $P$ is the one returned by \tet{polredabs}, and the last one is stable. If $\fl = 1$: outputs a two-component row vector $[P,a]$, where $P$ is the default output and \kbd{Mod(a, P)} is a root of the original $T$. \bprog ? [P,a] = polredbest(x^4 + 8, 1) %1 = [x^4 + 2, Mod(x^3, x^4 + 2)] ? charpoly(a) %2 = x^4 + 8 @eprog\noindent In particular, the map $\Q[x]/(T) \to \Q[x]/(P)$, $x\mapsto \kbd{Mod(a,P)}$ defines an isomorphism of number fields, which can be computed as \bprog subst(lift(Q), 'x, a) @eprog\noindent if $Q$ is a \typ{POLMOD} modulo $T$; \kbd{b = modreverse(a)} returns a \typ{POLMOD} giving the inverse of the above map (which should be useless since $\Q[x]/(P)$ is a priori a better representation for the number field and its elements). The library syntax is \fun{GEN}{polredbest}{GEN T, long flag}. \subsec{polredord$(x)$}\kbdsidx{polredord}\label{se:polredord} This function is obsolete, use polredbest. The library syntax is \fun{GEN}{polredord}{GEN x}. \subsec{poltschirnhaus$(x)$}\kbdsidx{poltschirnhaus}\label{se:poltschirnhaus} Applies a random Tschirnhausen transformation to the polynomial $x$, which is assumed to be non-constant and separable, so as to obtain a new equation for the \'etale algebra defined by $x$. This is for instance useful when computing resolvents, hence is used by the \kbd{polgalois} function. The library syntax is \fun{GEN}{tschirnhaus}{GEN x}. \subsec{rnfalgtobasis$(\var{rnf},x)$}\kbdsidx{rnfalgtobasis}\label{se:rnfalgtobasis} Expresses $x$ on the relative integral basis. Here, $\var{rnf}$ is a relative number field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an element of $L$ in absolute form, i.e. expressed as a polynomial or polmod with polmod coefficients, \emph{not} on the relative integral basis. The library syntax is \fun{GEN}{rnfalgtobasis}{GEN rnf, GEN x}. \subsec{rnfbasis$(\var{bnf},M)$}\kbdsidx{rnfbasis}\label{se:rnfbasis} Let $K$ the field represented by \var{bnf}, as output by \kbd{bnfinit}. $M$ is a projective $\Z_K$-module of rank $n$ ($M\otimes K$ is an $n$-dimensional $K$-vector space), given by a pseudo-basis of size $n$. The routine returns either a true $\Z_K$-basis of $M$ (of size $n$) if it exists, or an $n+1$-element generating set of $M$ if not. It is allowed to use a monic irreducible polynomial $P$ in $K[X]$ instead of $M$, in which case, $M$ is defined as the ring of integers of $K[X]/(P)$, viewed as a $\Z_K$-module. The library syntax is \fun{GEN}{rnfbasis}{GEN bnf, GEN M}. \subsec{rnfbasistoalg$(\var{rnf},x)$}\kbdsidx{rnfbasistoalg}\label{se:rnfbasistoalg} Computes the representation of $x$ as a polmod with polmods coefficients. Here, $\var{rnf}$ is a relative number field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an element of $L$ expressed on the relative integral basis. The library syntax is \fun{GEN}{rnfbasistoalg}{GEN rnf, GEN x}. \subsec{rnfcharpoly$(\var{nf},T,a,\{\var{var}='x\})$}\kbdsidx{rnfcharpoly}\label{se:rnfcharpoly} Characteristic polynomial of $a$ over $\var{nf}$, where $a$ belongs to the algebra defined by $T$ over $\var{nf}$, i.e.~$\var{nf}[X]/(T)$. Returns a polynomial in variable $v$ ($x$ by default). \bprog ? nf = nfinit(y^2+1); ? rnfcharpoly(nf, x^2+y*x+1, x+y) %2 = x^2 + Mod(-y, y^2 + 1)*x + 1 @eprog The library syntax is \fun{GEN}{rnfcharpoly}{GEN nf, GEN T, GEN a, long var = -1} where \kbd{var} is a variable number. \subsec{rnfconductor$(\var{bnf},T)$}\kbdsidx{rnfconductor}\label{se:rnfconductor} Given a \var{bnf} structure attached to a number field $K$, as produced by \kbd{bnfinit}, and $T$ a monic irreducible polynomial in $K[x]$ defining an \idx{Abelian extension} $L = K[x]/(T)$, computes the class field theory conductor of this Abelian extension. The result is a 3-component vector $[\var{conductor},\var{bnr},\var{subgroup}]$, where \var{conductor} is the conductor of the extension given as a 2-component row vector $[f_0,f_\infty]$, \var{bnr} is the attached \kbd{bnr} structure and \var{subgroup} is a matrix in HNF defining the subgroup of the ray class group on the ray class group generators \kbd{bnr.gen}. \misctitle{Huge discriminants, helping rnfdisc} the format $[T,B]$ is also accepted instead of $T$ and computes the conductor of the extension provided it factors completely over prime divisors of rational primes $p < B$, see \kbd{??rnfinit}: the valuation of $f_0$ is then correct at all prime ideals $\goth{p}$ above a rational prime $p < B$ but may be incorrect at other primes. The library syntax is \fun{GEN}{rnfconductor}{GEN bnf, GEN T}. \subsec{rnfdedekind$(\var{nf},\var{pol},\{\var{pr}\},\{\fl=0\})$}\kbdsidx{rnfdedekind}\label{se:rnfdedekind} Given a number field $K$ coded by $\var{nf}$ and a monic polynomial $P\in \Z_K[X]$, irreducible over $K$ and thus defining a relative extension $L$ of $K$, applies \idx{Dedekind}'s criterion to the order $\Z_K[X]/(P)$, at the prime ideal \var{pr}. It is possible to set \var{pr} to a vector of prime ideals (test maximality at all primes in the vector), or to omit altogether, in which case maximality at \emph{all} primes is tested; in this situation \fl\ is automatically set to $1$. The default historic behavior (\fl\ is 0 or omitted and \var{pr} is a single prime ideal) is not so useful since \kbd{rnfpseudobasis} gives more information and is generally not that much slower. It returns a 3-component vector $[\var{max}, \var{basis}, v]$: \item \var{basis} is a pseudo-basis of an enlarged order $O$ produced by Dedekind's criterion, containing the original order $\Z_K[X]/(P)$ with index a power of \var{pr}. Possibly equal to the original order. \item \var{max} is a flag equal to 1 if the enlarged order $O$ could be proven to be \var{pr}-maximal and to 0 otherwise; it may still be maximal in the latter case if \var{pr} is ramified in $L$, \item $v$ is the valuation at \var{pr} of the order discriminant. If \fl\ is non-zero, on the other hand, we just return $1$ if the order $\Z_K[X]/(P)$ is \var{pr}-maximal (resp.~maximal at all relevant primes, as described above), and $0$ if not. This is much faster than the default, since the enlarged order is not computed. \bprog ? nf = nfinit(y^2-3); P = x^3 - 2*y; ? pr3 = idealprimedec(nf,3)[1]; ? rnfdedekind(nf, P, pr3) %3 = [1, [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, 1]], 8] ? rnfdedekind(nf, P, pr3, 1) %4 = 1 @eprog\noindent In this example, \kbd{pr3} is the ramified ideal above $3$, and the order generated by the cube roots of $y$ is already \kbd{pr3}-maximal. The order-discriminant has valuation $8$. On the other hand, the order is not maximal at the prime above 2: \bprog ? pr2 = idealprimedec(nf,2)[1]; ? rnfdedekind(nf, P, pr2, 1) %6 = 0 ? rnfdedekind(nf, P, pr2) %7 = [0, [[2, 0, 0; 0, 1, 0; 0, 0, 1], [[1, 0; 0, 1], [1, 0; 0, 1], [1, 1/2; 0, 1/2]]], 2] @eprog The enlarged order is not proven to be \kbd{pr2}-maximal yet. In fact, it is; it is in fact the maximal order: \bprog ? B = rnfpseudobasis(nf, P) %8 = [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, [1, 1/2; 0, 1/2]], [162, 0; 0, 162], -1] ? idealval(nf,B[3], pr2) %9 = 2 @eprog\noindent It is possible to use this routine with non-monic $P = \sum_{i\leq n} a_i X^i \in \Z_K[X]$ if $\fl = 1$; in this case, we test maximality of Dedekind's order generated by $$1, a_n \alpha, a_n\alpha^2 + a_{n-1}\alpha, \dots, a_n\alpha^{n-1} + a_{n-1}\alpha^{n-2} + \cdots + a_1\alpha.$$ The routine will fail if $P$ is $0$ on the projective line over the residue field $\Z_K/\kbd{pr}$ (FIXME). The library syntax is \fun{GEN}{rnfdedekind}{GEN nf, GEN pol, GEN pr = NULL, long flag}. \subsec{rnfdet$(\var{nf},M)$}\kbdsidx{rnfdet}\label{se:rnfdet} Given a pseudo-matrix $M$ over the maximal order of $\var{nf}$, computes its determinant. The library syntax is \fun{GEN}{rnfdet}{GEN nf, GEN M}. \subsec{rnfdisc$(\var{nf},T)$}\kbdsidx{rnfdisc}\label{se:rnfdisc} Given an \var{nf} structure attached to a number field $K$, as output by \kbd{nfinit}, and a monic irreducible polynomial $T\in K[x]$ defining a relative extension $L = K[x]/(T)$, compute the relative discriminant of $L$. This is a vector $[D,d]$, where $D$ is the relative ideal discriminant and $d$ is the relative discriminant considered as an element of $K^*/{K^*}^2$. The main variable of $\var{nf}$ \emph{must} be of lower priority than that of $T$, see \secref{se:priority}. \misctitle{Huge discriminants, helping rnfdisc} the format $[T,B]$ is also accepted instead of $T$ and computes an order which is maximal at all $p < B$, see \kbd{??rnfinit}: the valuation of $D$ is then correct at all prime ideals $\goth{p}$ above a rational prime $p < B$ but may be incorrect at other primes. The library syntax is \fun{GEN}{rnfdiscf}{GEN nf, GEN T}. \subsec{rnfeltabstorel$(\var{rnf},x)$}\kbdsidx{rnfeltabstorel}\label{se:rnfeltabstorel} Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an element of $L$ expressed as a polynomial modulo the absolute equation \kbd{\var{rnf}.pol}, or in terms of the absolute $\Z$-basis for $\Z_L$ if \var{rnf} contains one (as in \kbd{rnfinit(nf,pol,1)}, or after a call to \kbd{nfinit(rnf)}). Computes $x$ as an element of the relative extension $L/K$ as a polmod with polmod coefficients. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.polabs %2 = x^4 + 1 ? rnfeltabstorel(L, Mod(x, L.polabs)) %3 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltabstorel(L, 1/3) %4 = 1/3 ? rnfeltabstorel(L, Mod(x, x^2-y)) %5 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltabstorel(L, [0,0,0,1]~) \\ Z_L not initialized yet *** at top-level: rnfeltabstorel(L,[0, *** ^-------------------- *** rnfeltabstorel: incorrect type in rnfeltabstorel, apply nfinit(rnf). ? nfinit(L); \\ initialize now ? rnfeltabstorel(L, [0,0,0,1]~) %6 = Mod(Mod(y, y^2 + 1)*x, x^2 + Mod(-y, y^2 + 1)) @eprog The library syntax is \fun{GEN}{rnfeltabstorel}{GEN rnf, GEN x}. \subsec{rnfeltdown$(\var{rnf},x,\{\fl=0\})$}\kbdsidx{rnfeltdown}\label{se:rnfeltdown} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$ expressed as a polynomial or polmod with polmod coefficients (or as a \typ{COL} on \kbd{nfinit(rnf).zk}), computes $x$ as an element of $K$ as a \typ{POLMOD} if $\fl = 0$ and as a \typ{COL} otherwise. If $x$ is not in $K$, a domain error occurs. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltdown(L, Mod(x^2, L.pol)) %3 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(x^2, L.pol), 1) %4 = [0, 1]~ ? rnfeltdown(L, Mod(y, x^2-y)) %5 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(y,K.pol)) %6 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(x, L.pol)) *** at top-level: rnfeltdown(L,Mod(x,x *** ^-------------------- *** rnfeltdown: domain error in rnfeltdown: element not in the base field ? rnfeltdown(L, Mod(y, x^2-y), 1) \\ as a t_COL %7 = [0, 1]~ ? rnfeltdown(L, [0,1,0,0]~) \\ not allowed without absolute nf struct *** rnfeltdown: incorrect type in rnfeltdown (t_COL). ? nfinit(L); \\ add absolute nf structure to L ? rnfeltdown(L, [0,1,0,0]~) \\ now OK %8 = Mod(y, y^2 + 1) @eprog\noindent If we had started with \kbd{L = rnfinit(K, x\pow2-y, 1)}, then the final would have worked directly. The library syntax is \fun{GEN}{rnfeltdown0}{GEN rnf, GEN x, long flag}. Also available is \fun{GEN}{rnfeltdown}{GEN rnf, GEN x} ($\fl = 0$). \subsec{rnfeltnorm$(\var{rnf},x)$}\kbdsidx{rnfeltnorm}\label{se:rnfeltnorm} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$, returns the relative norm $N_{L/K}(x)$ as an element of $K$. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? rnfeltnorm(L, Mod(x, L.pol)) %2 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltnorm(L, 2) %3 = 4 ? rnfeltnorm(L, Mod(x, x^2-y)) @eprog The library syntax is \fun{GEN}{rnfeltnorm}{GEN rnf, GEN x}. \subsec{rnfeltreltoabs$(\var{rnf},x)$}\kbdsidx{rnfeltreltoabs}\label{se:rnfeltreltoabs} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$ expressed as a polynomial or polmod with polmod coefficients, computes $x$ as an element of the absolute extension $L/\Q$ as a polynomial modulo the absolute equation \kbd{\var{rnf}.pol}. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltreltoabs(L, Mod(x, L.pol)) %3 = Mod(x, x^4 + 1) ? rnfeltreltoabs(L, Mod(y, x^2-y)) %4 = Mod(x^2, x^4 + 1) ? rnfeltreltoabs(L, Mod(y,K.pol)) %5 = Mod(x^2, x^4 + 1) @eprog The library syntax is \fun{GEN}{rnfeltreltoabs}{GEN rnf, GEN x}. \subsec{rnfelttrace$(\var{rnf},x)$}\kbdsidx{rnfelttrace}\label{se:rnfelttrace} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$, returns the relative trace $Tr_{L/K}(x)$ as an element of $K$. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? rnfelttrace(L, Mod(x, L.pol)) %2 = 0 ? rnfelttrace(L, 2) %3 = 4 ? rnfelttrace(L, Mod(x, x^2-y)) @eprog The library syntax is \fun{GEN}{rnfelttrace}{GEN rnf, GEN x}. \subsec{rnfeltup$(\var{rnf},x,\{\fl=0\})$}\kbdsidx{rnfeltup}\label{se:rnfeltup} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $K$, computes $x$ as an element of the absolute extension $L/\Q$. As a \typ{POLMOD} modulo \kbd{\var{rnf}.pol} if $\fl = 0$ and as a \typ{COL} on the absolute field integer basis if $\fl = 1$. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltup(L, Mod(y, K.pol)) %3 = Mod(x^2, x^4 + 1) ? rnfeltup(L, y) %4 = Mod(x^2, x^4 + 1) ? rnfeltup(L, [1,2]~) \\ in terms of K.zk %5 = Mod(2*x^2 + 1, x^4 + 1) ? rnfeltup(L, y, 1) \\ in terms of nfinit(L).zk %6 = [0, 1, 0, 0]~ ? rnfeltup(L, [1,2]~, 1) %7 = [1, 2, 0, 0]~ @eprog The library syntax is \fun{GEN}{rnfeltup0}{GEN rnf, GEN x, long flag}. \subsec{rnfequation$(\var{nf},\var{pol},\{\fl=0\})$}\kbdsidx{rnfequation}\label{se:rnfequation} Given a number field $\var{nf}$ as output by \kbd{nfinit} (or simply a polynomial) and a polynomial \var{pol} with coefficients in $\var{nf}$ defining a relative extension $L$ of $\var{nf}$, computes an absolute equation of $L$ over $\Q$. The main variable of $\var{nf}$ \emph{must} be of lower priority than that of \var{pol} (see \secref{se:priority}). Note that for efficiency, this does not check whether the relative equation is irreducible over $\var{nf}$, but only if it is squarefree. If it is reducible but squarefree, the result will be the absolute equation of the \'etale algebra defined by \var{pol}. If \var{pol} is not squarefree, raise an \kbd{e\_DOMAIN} exception. \bprog ? rnfequation(y^2+1, x^2 - y) %1 = x^4 + 1 ? T = y^3-2; rnfequation(nfinit(T), (x^3-2)/(x-Mod(y,T))) %2 = x^6 + 108 \\ Galois closure of Q(2^(1/3)) @eprog If $\fl$ is non-zero, outputs a 3-component row vector $[z,a,k]$, where \item $z$ is the absolute equation of $L$ over $\Q$, as in the default behavior, \item $a$ expresses as a \typ{POLMOD} modulo $z$ a root $\alpha$ of the polynomial defining the base field $\var{nf}$, \item $k$ is a small integer such that $\theta = \beta+k\alpha$ is a root of $z$, where $\beta$ is a root of $\var{pol}$. It is guaranteed that $k=0$ whenever $\Q(\beta) = L$. \bprog ? T = y^3-2; pol = x^2 +x*y + y^2; ? [z,a,k] = rnfequation(T, pol, 1); ? z %3 = x^6 + 108 ? subst(T, y, a) %4 = 0 ? alpha= Mod(y, T); ? beta = Mod(x*Mod(1,T), pol); ? subst(z, x, beta + k*alpha) %7 = 0 @eprog The library syntax is \fun{GEN}{rnfequation0}{GEN nf, GEN pol, long flag}. Also available are \fun{GEN}{rnfequation}{GEN nf, GEN pol} ($\fl = 0$) and \fun{GEN}{rnfequation2}{GEN nf, GEN pol} ($\fl = 1$). \subsec{rnfhnfbasis$(\var{bnf},x)$}\kbdsidx{rnfhnfbasis}\label{se:rnfhnfbasis} Given $\var{bnf}$ as output by \kbd{bnfinit}, and either a polynomial $x$ with coefficients in $\var{bnf}$ defining a relative extension $L$ of $\var{bnf}$, or a pseudo-basis $x$ of such an extension, gives either a true $\var{bnf}$-basis of $L$ in upper triangular Hermite normal form, if it exists, and returns $0$ otherwise. The library syntax is \fun{GEN}{rnfhnfbasis}{GEN bnf, GEN x}. \subsec{rnfidealabstorel$(\var{rnf},x)$}\kbdsidx{rnfidealabstorel}\label{se:rnfidealabstorel} Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an ideal of the absolute extension $L/\Q$. Returns the relative pseudo-matrix in HNF giving the ideal $x$ considered as an ideal of the relative extension $L/K$, i.e.~as a $\Z_K$-module. Let \kbd{Labs} be an (absolute) \kbd{nf} structure attached to $L$, obtained via \kbd{Labs = nfinit(rnf))}. Then \kbd{rnf} ``knows'' about \kbd{Labs} and $x$ may be given in any format attached to \kbd{Labs}, e.g. a prime ideal or an ideal in HNF wrt. \kbd{Labs.zk}: \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); Labs = nfinit(rnf); ? m = idealhnf(Labs, 17, x^3+2); \\ some ideal in HNF wrt. Labs.zk ? B = rnfidealabstorel(rnf, m) %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] \\ pseudo-basis for m as Z_K-module ? A = rnfidealreltoabs(rnf, B) %4 = [17, x^2 + 4, x + 8, x^3 + 8*x^2] \\ Z-basis for m in Q[x]/(rnf.polabs) ? mathnf(matalgtobasis(Labs, A)) == m %5 = 1 @eprog\noindent If on the other hand, we do not have a \kbd{Labs} at hand, because it would be too expensive to compute, but we nevertheless have a $\Z$-basis for $x$, then we can use the function with this basis as argument. The entries of $x$ may be given either modulo \kbd{rnf.polabs} (absolute form, possibly lifted) or modulo \kbd{rnf.pol} (relative form as \typ{POLMOD}s): \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? rnfidealabstorel(rnf, [17, x^2 + 4, x + 8, x^3 + 8*x^2]) %2 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] ? rnfidealabstorel(rnf, Mod([17, y + 4, x + 8, y*x + 8*y], x^2-y)) %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] @eprog The library syntax is \fun{GEN}{rnfidealabstorel}{GEN rnf, GEN x}. \subsec{rnfidealdown$(\var{rnf},x)$}\kbdsidx{rnfidealdown}\label{se:rnfidealdown} Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an ideal of $L$, given either in relative form or by a $\Z$-basis of elements of $L$ (see \secref{se:rnfidealabstorel}). This function returns the ideal of $K$ below $x$, i.e.~the intersection of $x$ with $K$. The library syntax is \fun{GEN}{rnfidealdown}{GEN rnf, GEN x}. \subsec{rnfidealfactor$(\var{rnf},x)$}\kbdsidx{rnfidealfactor}\label{se:rnfidealfactor} Factor into prime ideal powers the ideal $x$ in the attached absolute number field $L = \kbd{nfinit}(\var{rnf})$. The output format is similar to the \kbd{factor} function, and the prime ideals are represented in the form output by the \kbd{idealprimedec} function for $L$. \bprog ? rnf = rnfinit(nfinit(y^2+1), x^2-y+1); ? rnfidealfactor(rnf, y+1) \\ P_2^2 %2 = [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 2] ? rnfidealfactor(rnf, x) \\ P_2 %3 = [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 1] ? L = nfinit(rnf); ? id = idealhnf(L, idealhnf(L, 25, (x+1)^2)); ? idealfactor(L, id) == rnfidealfactor(rnf, id) %6 = 1 @eprog\noindent Note that ideals of the base field $K$ must be explicitly lifted to $L$ via \kbd{rnfidealup} before they can be factored. The library syntax is \fun{GEN}{rnfidealfactor}{GEN rnf, GEN x}. \subsec{rnfidealhnf$(\var{rnf},x)$}\kbdsidx{rnfidealhnf}\label{se:rnfidealhnf} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being a relative ideal (which can be, as in the absolute case, of many different types, including of course elements), computes the HNF pseudo-matrix attached to $x$, viewed as a $\Z_K$-module. The library syntax is \fun{GEN}{rnfidealhnf}{GEN rnf, GEN x}. \subsec{rnfidealmul$(\var{rnf},x,y)$}\kbdsidx{rnfidealmul}\label{se:rnfidealmul} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ and $y$ being ideals of the relative extension $L/K$ given by pseudo-matrices, outputs the ideal product, again as a relative ideal. The library syntax is \fun{GEN}{rnfidealmul}{GEN rnf, GEN x, GEN y}. \subsec{rnfidealnormabs$(\var{rnf},x)$}\kbdsidx{rnfidealnormabs}\label{se:rnfidealnormabs} Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a relative ideal (which can be, as in the absolute case, of many different types, including of course elements). This function computes the norm of the $x$ considered as an ideal of the absolute extension $L/\Q$. This is identical to \bprog idealnorm(rnf, rnfidealnormrel(rnf,x)) @eprog\noindent but faster. The library syntax is \fun{GEN}{rnfidealnormabs}{GEN rnf, GEN x}. \subsec{rnfidealnormrel$(\var{rnf},x)$}\kbdsidx{rnfidealnormrel}\label{se:rnfidealnormrel} Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a relative ideal (which can be, as in the absolute case, of many different types, including of course elements). This function computes the relative norm of $x$ as an ideal of $K$ in HNF. The library syntax is \fun{GEN}{rnfidealnormrel}{GEN rnf, GEN x}. \subsec{rnfidealprimedec$(\var{rnf},\var{pr})$}\kbdsidx{rnfidealprimedec}\label{se:rnfidealprimedec} Let \var{rnf} be a relative number field extension $L/K$ as output by \kbd{rnfinit}, and \var{pr} a maximal ideal of $K$ (\var{prid}), this function completes the \var{rnf} with a \var{nf} structure attached to $L$ (see \secref{se:rnfinit}) and returns the prime ideal decomposition of \var{pr} in $L/K$. \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^3+y+1); ? P = idealprimedec(K, 2)[1]; ? S = rnfidealprimedec(rnf, P); ? #S %4 = 1 @eprog The argument \var{pr} is also allowed to be a prime number $p$, in which case the function returns a pair of vectors \kbd{[SK,SL]}, where \kbd{SK} contains the primes of $K$ above $p$ and \kbd{SL}$[i]$ is the vector of primes of $L$ above \kbd{SK}$[i]$. \bprog ? [SK,SL] = rnfidealprimedec(rnf, 5); ? [#SK, vector(#SL,i,#SL[i])] %6 = [2, [2, 2]] @eprog The library syntax is \fun{GEN}{rnfidealprimedec}{GEN rnf, GEN pr}. \subsec{rnfidealreltoabs$(\var{rnf},x,\{\fl=0\})$}\kbdsidx{rnfidealreltoabs}\label{se:rnfidealreltoabs} Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a relative ideal, given as a $\Z_K$-module by a pseudo matrix $[A,I]$. This function returns the ideal $x$ as an absolute ideal of $L/\Q$. If $\fl = 0$, the result is given by a vector of \typ{POLMOD}s modulo \kbd{rnf.pol} forming a $\Z$-basis; if $\fl = 1$, it is given in HNF in terms of the fixed $\Z$-basis for $\Z_L$, see \secref{se:rnfinit}. \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? P = idealprimedec(K,2)[1]; ? P = rnfidealup(rnf, P) %3 = [2, x^2 + 1, 2*x, x^3 + x] ? Prel = rnfidealhnf(rnf, P) %4 = [[1, 0; 0, 1], [[2, 1; 0, 1], [2, 1; 0, 1]]] ? rnfidealreltoabs(rnf,Prel) %5 = [2, x^2 + 1, 2*x, x^3 + x] ? rnfidealreltoabs(rnf,Prel,1) %6 = [2 1 0 0] [0 1 0 0] [0 0 2 1] [0 0 0 1] @eprog The reason why we do not return by default ($\fl = 0$) the customary HNF in terms of a fixed $\Z$-basis for $\Z_L$ is precisely because a \var{rnf} does not contain such a basis by default. Completing the structure so that it contains a \var{nf} structure for $L$ is polynomial time but costly when the absolute degree is large, thus it is not done by default. Note that setting $\fl = 1$ will complete the \var{rnf}. The library syntax is \fun{GEN}{rnfidealreltoabs0}{GEN rnf, GEN x, long flag}. Also available is \fun{GEN}{rnfidealreltoabs}{GEN rnf, GEN x} ($\fl = 0$). \subsec{rnfidealtwoelt$(\var{rnf},x)$}\kbdsidx{rnfidealtwoelt}\label{se:rnfidealtwoelt} $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an ideal of the relative extension $L/K$ given by a pseudo-matrix, gives a vector of two generators of $x$ over $\Z_L$ expressed as polmods with polmod coefficients. The library syntax is \fun{GEN}{rnfidealtwoelement}{GEN rnf, GEN x}. \subsec{rnfidealup$(\var{rnf},x,\{\fl=0\})$}\kbdsidx{rnfidealup}\label{se:rnfidealup} Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an ideal of $K$. This function returns the ideal $x\Z_L$ as an absolute ideal of $L/\Q$, in the form of a $\Z$-basis. If $\fl = 0$, the result is given by a vector of polynomials (modulo \kbd{rnf.pol}); if $\fl = 1$, it is given in HNF in terms of the fixed $\Z$-basis for $\Z_L$, see \secref{se:rnfinit}. \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? P = idealprimedec(K,2)[1]; ? rnfidealup(rnf, P) %3 = [2, x^2 + 1, 2*x, x^3 + x] ? rnfidealup(rnf, P,1) %4 = [2 1 0 0] [0 1 0 0] [0 0 2 1] [0 0 0 1] @eprog The reason why we do not return by default ($\fl = 0$) the customary HNF in terms of a fixed $\Z$-basis for $\Z_L$ is precisely because a \var{rnf} does not contain such a basis by default. Completing the structure so that it contains a \var{nf} structure for $L$ is polynomial time but costly when the absolute degree is large, thus it is not done by default. Note that setting $\fl = 1$ will complete the \var{rnf}. The library syntax is \fun{GEN}{rnfidealup0}{GEN rnf, GEN x, long flag}. Also available is \fun{GEN}{rnfidealup}{GEN rnf, GEN x} ($\fl = 0$). \subsec{rnfinit$(\var{nf},T,\{\fl=0\})$}\kbdsidx{rnfinit}\label{se:rnfinit} Given an \var{nf} structure attached to a number field $K$, as output by \kbd{nfinit}, and a monic irreducible polynomial $T$ in $K[x]$ defining a relative extension $L = K[x]/(T)$, this computes data to work in $L/K$ The main variable of $T$ must be of higher priority (see \secref{se:priority}) than that of $\var{nf}$, and the coefficients of $T$ must be in $K$. The result is a row vector, whose components are technical. We let $m = [K:\Q]$ the degree of the base field, $n = [L:K]$ the relative degree, $r_1$ and $r_2$ the number of real and complex places of $K$. Access to this information via \emph{member functions} is preferred since the specific data organization specified below will change in the future. If $\fl = 1$, add an \var{nf} structure attached to $L$ to \var{rnf}. This is likely to be very expensive if the absolute degree $mn$ is large, but fixes an integer basis for $\Z_L$ as a $\Z$-module and allows to input and output elements of $L$ in absolute form: as \typ{COL} for elements, as \typ{MAT} in HNF for ideals, as \kbd{prid} for prime ideals. Without such a call, elements of $L$ are represented as \typ{POLMOD}, etc. Note that a subsequent \kbd{nfinit}$(\var{rnf})$ will also explicitly add such a component, and so will the following functions \kbd{rnfidealmul}, \kbd{rnfidealtwoelt}, \kbd{rnfidealprimedec}, \kbd{rnfidealup} (with flag 1) and \kbd{rnfidealreltoabs} (with flag 1). The absolute \var{nf} structure attached to $L$ can be recovered using \kbd{nfinit(rnf)}. $\var{rnf}[1]$(\kbd{rnf.pol}) contains the relative polynomial $T$. $\var{rnf}[2]$ contains the integer basis $[A,d]$ of $K$, as (integral) elements of $L/\Q$. More precisely, $A$ is a vector of polynomial with integer coefficients, $d$ is a denominator, and the integer basis is given by $A/d$. $\var{rnf}[3]$ (\kbd{rnf.disc}) is a two-component row vector $[\goth{d}(L/K),s]$ where $\goth{d}(L/K)$ is the relative ideal discriminant of $L/K$ and $s$ is the discriminant of $L/K$ viewed as an element of $K^*/(K^*)^2$, in other words it is the output of \kbd{rnfdisc}. $\var{rnf}[4]$(\kbd{rnf.index}) is the ideal index $\goth{f}$, i.e.~such that $d(T)\Z_K=\goth{f}^2\goth{d}(L/K)$. $\var{rnf}[5]$ is currently unused. $\var{rnf}[6]$ is currently unused. $\var{rnf}[7]$ (\kbd{rnf.zk}) is the pseudo-basis $(A,I)$ for the maximal order $\Z_L$ as a $\Z_K$-module: $A$ is the relative integral pseudo basis expressed as polynomials (in the variable of $T$) with polmod coefficients in $\var{nf}$, and the second component $I$ is the ideal list of the pseudobasis in HNF. $\var{rnf}[8]$ is the inverse matrix of the integral basis matrix, with coefficients polmods in $\var{nf}$. $\var{rnf}[9]$ is currently unused. $\var{rnf}[10]$ (\kbd{rnf.nf}) is $\var{nf}$. $\var{rnf}[11]$ is an extension of \kbd{rnfequation(K, T, 1)}. Namely, a vector $[P, a, k, \kbd{K.pol}, T]$ describing the \emph{absolute} extension $L/\Q$: $P$ is an absolute equation, more conveniently obtained as \kbd{rnf.polabs}; $a$ expresses the generator $\alpha = y \mod \kbd{K.pol}$ of the number field $K$ as an element of $L$, i.e.~a polynomial modulo the absolute equation $P$; $k$ is a small integer such that, if $\beta$ is an abstract root of $T$ and $\alpha$ the generator of $K$ given above, then $P(\beta + k\alpha) = 0$. It is guaranteed that $k = 0$ if $\Q(\beta) = L$. \misctitle{Caveat} Be careful if $k\neq0$ when dealing simultaneously with absolute and relative quantities since $L = \Q(\beta + k\alpha) = K(\alpha)$, and the generator chosen for the absolute extension is not the same as for the relative one. If this happens, one can of course go on working, but we advise to change the relative polynomial so that its root becomes $\beta + k \alpha$. Typical GP instructions would be \bprog [P,a,k] = rnfequation(K, T, 1); if (k, T = subst(T, x, x - k*Mod(y, K.pol))); L = rnfinit(K, T); @eprog $\var{rnf}[12]$ is by default unused and set equal to 0. This field is used to store further information about the field as it becomes available (which is rarely needed, hence would be too expensive to compute during the initial \kbd{rnfinit} call). \misctitle{Huge discriminants, helping rnfdisc} When $T$ has a discriminant which is difficult to factor, it is hard to compute $\Z_L$. As in \kbd{nfinit}, the special input format $[T,B]$ is also accepted, where $T$ is a polynomial as above and $B$ is an integer. Instead of $\Z_L$, this produces an order which is maximal at all primes less than $B$. The result is actually a complete and correct \var{rnf} structure if all prime divisors of the relative ideal discriminant divide a rational prime less than $B$. In general, the order may not be maximal at primes $\goth{p} | p $ for $p \geq B$ such that $\goth{p}^2$ divides the relative ideal discriminant. The library syntax is \fun{GEN}{rnfinit0}{GEN nf, GEN T, long flag}. Also available is \fun{GEN}{rnfinit}{GEN nf,GEN T} ($\fl = 0$). \subsec{rnfisabelian$(\var{nf},T)$}\kbdsidx{rnfisabelian}\label{se:rnfisabelian} $T$ being a relative polynomial with coefficients in \var{nf}, return 1 if it defines an abelian extension, and 0 otherwise. \bprog ? K = nfinit(y^2 + 23); ? rnfisabelian(K, x^3 - 3*x - y) %2 = 1 @eprog The library syntax is \fun{long}{rnfisabelian}{GEN nf, GEN T}. \subsec{rnfisfree$(\var{bnf},x)$}\kbdsidx{rnfisfree}\label{se:rnfisfree} Given $\var{bnf}$ as output by \kbd{bnfinit}, and either a polynomial $x$ with coefficients in $\var{bnf}$ defining a relative extension $L$ of $\var{bnf}$, or a pseudo-basis $x$ of such an extension, returns true (1) if $L/\var{bnf}$ is free, false (0) if not. The library syntax is \fun{long}{rnfisfree}{GEN bnf, GEN x}. \subsec{rnfislocalcyclo$(\var{rnf})$}\kbdsidx{rnfislocalcyclo}\label{se:rnfislocalcyclo} Let \var{rnf} be a relative number field extension $L/K$ as output by \kbd{rnfinit} whose degree $[L:K]$ is a power of a prime $\ell$. Return $1$ if the $\ell$-extension is locally cyclotomic (locally contained in the cyclotomic $\Z_\ell$-extension of $K_v$ at all places $v | \ell$), and $0$ if not. \bprog ? K = nfinit(y^2 + y + 1); ? L = rnfinit(K, x^3 - y); /* = K(zeta_9), globally cyclotomic */ ? rnfislocalcyclo(L) %3 = 1 \\ we expect 3-adic continuity by Krasner's lemma ? vector(5, i, rnfislocalcyclo(rnfinit(K, x^3 - y + 3^i))) %5 = [0, 1, 1, 1, 1] @eprog The library syntax is \fun{long}{rnfislocalcyclo}{GEN rnf}. \subsec{rnfisnorm$(T,a,\{\fl=0\})$}\kbdsidx{rnfisnorm}\label{se:rnfisnorm} Similar to \kbd{bnfisnorm} but in the relative case. $T$ is as output by \tet{rnfisnorminit} applied to the extension $L/K$. This tries to decide whether the element $a$ in $K$ is the norm of some $x$ in the extension $L/K$. The output is a vector $[x,q]$, where $a = \Norm(x)*q$. The algorithm looks for a solution $x$ which is an $S$-integer, with $S$ a list of places of $K$ containing at least the ramified primes, the generators of the class group of $L$, as well as those primes dividing $a$. If $L/K$ is Galois, then this is enough; otherwise, $\fl$ is used to add more primes to $S$: all the places above the primes $p \leq \fl$ (resp.~$p|\fl$) if $\fl>0$ (resp.~$\fl<0$). The answer is guaranteed (i.e.~$a$ is a norm iff $q = 1$) if the field is Galois, or, under \idx{GRH}, if $S$ contains all primes less than $12\log^2\left|\disc(M)\right|$, where $M$ is the normal closure of $L/K$. If \tet{rnfisnorminit} has determined (or was told) that $L/K$ is \idx{Galois}, and $\fl \neq 0$, a Warning is issued (so that you can set $\fl = 1$ to check whether $L/K$ is known to be Galois, according to $T$). Example: \bprog bnf = bnfinit(y^3 + y^2 - 2*y - 1); p = x^2 + Mod(y^2 + 2*y + 1, bnf.pol); T = rnfisnorminit(bnf, p); rnfisnorm(T, 17) @eprog\noindent checks whether $17$ is a norm in the Galois extension $\Q(\beta) / \Q(\alpha)$, where $\alpha^3 + \alpha^2 - 2\alpha - 1 = 0$ and $\beta^2 + \alpha^2 + 2\alpha + 1 = 0$ (it is). The library syntax is \fun{GEN}{rnfisnorm}{GEN T, GEN a, long flag}. \subsec{rnfisnorminit$(\var{pol},\var{polrel},\{\fl=2\})$}\kbdsidx{rnfisnorminit}\label{se:rnfisnorminit} Let $K$ be defined by a root of \var{pol}, and $L/K$ the extension defined by the polynomial \var{polrel}. As usual, \var{pol} can in fact be an \var{nf}, or \var{bnf}, etc; if \var{pol} has degree $1$ (the base field is $\Q$), polrel is also allowed to be an \var{nf}, etc. Computes technical data needed by \tet{rnfisnorm} to solve norm equations $Nx = a$, for $x$ in $L$, and $a$ in $K$. If $\fl = 0$, do not care whether $L/K$ is Galois or not. If $\fl = 1$, $L/K$ is assumed to be Galois (unchecked), which speeds up \tet{rnfisnorm}. If $\fl = 2$, let the routine determine whether $L/K$ is Galois. The library syntax is \fun{GEN}{rnfisnorminit}{GEN pol, GEN polrel, long flag}. \subsec{rnfkummer$(\var{bnr},\{\var{subgp}\},\{d=0\})$}\kbdsidx{rnfkummer}\label{se:rnfkummer} \var{bnr} being as output by \kbd{bnrinit}, finds a relative equation for the class field corresponding to the module in \var{bnr} and the given congruence subgroup (the full ray class field if \var{subgp} is omitted). If $d$ is positive, outputs the list of all relative equations of degree $d$ contained in the ray class field defined by \var{bnr}, with the \emph{same} conductor as $(\var{bnr}, \var{subgp})$. \misctitle{Warning} This routine only works for subgroups of prime index. It uses Kummer theory, adjoining necessary roots of unity (it needs to compute a tough \kbd{bnfinit} here), and finds a generator via Hecke's characterization of ramification in Kummer extensions of prime degree. If your extension does not have prime degree, for the time being, you have to split it by hand as a tower / compositum of such extensions. The library syntax is \fun{GEN}{rnfkummer}{GEN bnr, GEN subgp = NULL, long d, long prec}. \subsec{rnflllgram$(\var{nf},\var{pol},\var{order})$}\kbdsidx{rnflllgram}\label{se:rnflllgram} Given a polynomial \var{pol} with coefficients in \var{nf} defining a relative extension $L$ and a suborder \var{order} of $L$ (of maximal rank), as output by \kbd{rnfpseudobasis}$(\var{nf},\var{pol})$ or similar, gives $[[\var{neworder}],U]$, where \var{neworder} is a reduced order and $U$ is the unimodular transformation matrix. The library syntax is \fun{GEN}{rnflllgram}{GEN nf, GEN pol, GEN order, long prec}. \subsec{rnfnormgroup$(\var{bnr},\var{pol})$}\kbdsidx{rnfnormgroup}\label{se:rnfnormgroup} \var{bnr} being a big ray class field as output by \kbd{bnrinit} and \var{pol} a relative polynomial defining an \idx{Abelian extension}, computes the norm group (alias Artin or Takagi group) corresponding to the Abelian extension of $\var{bnf}=$\kbd{bnr.bnf} defined by \var{pol}, where the module corresponding to \var{bnr} is assumed to be a multiple of the conductor (i.e.~\var{pol} defines a subextension of bnr). The result is the HNF defining the norm group on the given generators of \kbd{bnr.gen}. Note that neither the fact that \var{pol} defines an Abelian extension nor the fact that the module is a multiple of the conductor is checked. The result is undefined if the assumption is not correct, but the function will return the empty matrix \kbd{[;]} if it detects a problem; it may also not detect the problem and return a wrong result. The library syntax is \fun{GEN}{rnfnormgroup}{GEN bnr, GEN pol}. \subsec{rnfpolred$(\var{nf},\var{pol})$}\kbdsidx{rnfpolred}\label{se:rnfpolred} This function is obsolete: use \tet{rnfpolredbest} instead. Relative version of \kbd{polred}. Given a monic polynomial \var{pol} with coefficients in $\var{nf}$, finds a list of relative polynomials defining some subfields, hopefully simpler and containing the original field. In the present version \vers, this is slower and less efficient than \kbd{rnfpolredbest}. \misctitle{Remark} this function is based on an incomplete reduction theory of lattices over number fields, implemented by \kbd{rnflllgram}, which deserves to be improved. The library syntax is \fun{GEN}{rnfpolred}{GEN nf, GEN pol, long prec}. \subsec{rnfpolredabs$(\var{nf},\var{pol},\{\fl=0\})$}\kbdsidx{rnfpolredabs}\label{se:rnfpolredabs} Relative version of \kbd{polredabs}. Given an irreducible monic polynomial \var{pol} with coefficients in $\var{nf}$, finds a canonical relative polynomial defining the same field, hopefully with small coefficients. Note that the equation is only canonical for a fixed \var{nf}, using a different defining polynomial in the \var{nf} structure will produce a different relative equation. The binary digits of $\fl$ correspond to $1$: add information to convert elements to the new representation, $2$: absolute polynomial, instead of relative, $16$: possibly use a suborder of the maximal order. More precisely: 0: default, return $P$ 1: returns $[P,a]$ where $P$ is the default output and $a$, a \typ{POLMOD} modulo $P$, is a root of \var{pol}. 2: returns \var{Pabs}, an absolute, instead of a relative, polynomial. This polynomial is canonical and does not depend on the \var{nf} structure. Same as but faster than \bprog polredabs(rnfequation(nf, pol)) @eprog 3: returns $[\var{Pabs},a,b]$, where \var{Pabs} is an absolute polynomial as above, $a$, $b$ are \typ{POLMOD} modulo \var{Pabs}, roots of \kbd{nf.pol} and \var{pol} respectively. 16: possibly use a suborder of the maximal order. This is slower than the default when the relative discriminant is smooth, and much faster otherwise. In this case the result is no longer canonical; see \secref{se:polredabs}. \misctitle{Warning} The complexity of \kbd{rnfpolredabs} is exponential in the absolute degree. The function \tet{rnfpolredbest} runs in polynomial time, and tends to return polynomials with smaller discriminants. The library syntax is \fun{GEN}{rnfpolredabs}{GEN nf, GEN pol, long flag}. \subsec{rnfpolredbest$(\var{nf},\var{pol},\{\fl=0\})$}\kbdsidx{rnfpolredbest}\label{se:rnfpolredbest} Relative version of \kbd{polredbest}. Given a monic polynomial \var{pol} with coefficients in $\var{nf}$, finds a simpler relative polynomial $P$ defining the same field. As opposed to \tet{rnfpolredabs} this function does not return a \emph{smallest} (canonical) polynomial with respect to some measure, but it does run in polynomial time. The binary digits of $\fl$ correspond to $1$: add information to convert elements to the new representation, $2$: absolute polynomial, instead of relative. More precisely: 0: default, return $P$ 1: returns $[P,a]$ where $P$ is the default output and $a$, a \typ{POLMOD} modulo $P$, is a root of \var{pol}. 2: returns \var{Pabs}, an absolute, instead of a relative, polynomial. Same as but faster than \bprog rnfequation(nf, rnfpolredbest(nf,pol)) @eprog 3: returns $[\var{Pabs},a,b]$, where \var{Pabs} is an absolute polynomial as above, $a$, $b$ are \typ{POLMOD} modulo \var{Pabs}, roots of \kbd{nf.pol} and \var{pol} respectively. \bprog ? K = nfinit(y^3-2); pol = x^2 +x*y + y^2; ? [P, a] = rnfpolredbest(K,pol,1); ? P %3 = x^2 - x + Mod(y - 1, y^3 - 2) ? a %4 = Mod(Mod(2*y^2+3*y+4,y^3-2)*x + Mod(-y^2-2*y-2,y^3-2), x^2 - x + Mod(y-1,y^3-2)) ? subst(K.pol,y,a) %5 = 0 ? [Pabs, a, b] = rnfpolredbest(K,pol,3); ? Pabs %7 = x^6 - 3*x^5 + 5*x^3 - 3*x + 1 ? a %8 = Mod(-x^2+x+1, x^6-3*x^5+5*x^3-3*x+1) ? b %9 = Mod(2*x^5-5*x^4-3*x^3+10*x^2+5*x-5, x^6-3*x^5+5*x^3-3*x+1) ? subst(K.pol,y,a) %10 = 0 ? substvec(pol,[x,y],[a,b]) %11 = 0 @eprog The library syntax is \fun{GEN}{rnfpolredbest}{GEN nf, GEN pol, long flag}. \subsec{rnfpseudobasis$(\var{nf},T)$}\kbdsidx{rnfpseudobasis}\label{se:rnfpseudobasis} Given an \var{nf} structure attached to a number field $K$, as output by \kbd{nfinit}, and a monic irreducible polynomial $T$ in $K[x]$ defining a relative extension $L = K[x]/(T)$, computes the relative discriminant of $L$ and a pseudo-basis $(A,J)$ for the maximal order $\Z_L$ viewed as a $\Z_K$-module. This is output as a vector $[A,J,D,d]$, where $D$ is the relative ideal discriminant and $d$ is the relative discriminant considered as an element of $K^*/{K^*}^2$. \bprog ? K = nfinit(y^2+1); ? [A,J,D,d] = rnfpseudobasis(K, x^2+y); ? A %3 = [1 0] [0 1] ? J %4 = [1, 1] ? D %5 = [0, -4]~ ? d %6 = [0, -1]~ @eprog \misctitle{Huge discriminants, helping rnfdisc} the format $[T,B]$ is also accepted instead of $T$ and produce an order which is maximal at all primes $p < B$, see \kbd{??rnfinit}. \bprog ? p = 585403248812100232206609398101; ? q = 711171340236468512951957953369; ? T = x^2 + 3*(p*q)^2; ? [A,J,D,d] = V = rnfpseudobasis(K, T); D time = 22,178 ms. %10 = [3 0] [0 3] ? [A,J,D,d] = W = rnfpseudobasis(K, [T,100]); D time = 5 ms. %11 = [3 0] [0 3] ? V == W %12 = 1 @eprog\noindent In this example, the results are identical since $D \cap \Z$ factors over primes less than $100$. Had it not been the case, the order would have been guaranteed maximal at primes $\goth{p} | p $ for $p \leq 100$ only (and might not have been maximal at any maximal ideal $\goth{p}$ such that $\goth{p}^2$ dividing $D$. The library syntax is \fun{GEN}{rnfpseudobasis}{GEN nf, GEN T}. \subsec{rnfsteinitz$(\var{nf},x)$}\kbdsidx{rnfsteinitz}\label{se:rnfsteinitz} Given a number field $\var{nf}$ as output by \kbd{nfinit} and either a polynomial $x$ with coefficients in $\var{nf}$ defining a relative extension $L$ of $\var{nf}$, or a pseudo-basis $x$ of such an extension as output for example by \kbd{rnfpseudobasis}, computes another pseudo-basis $(A,I)$ (not in HNF in general) such that all the ideals of $I$ except perhaps the last one are equal to the ring of integers of $\var{nf}$, and outputs the four-component row vector $[A,I,D,d]$ as in \kbd{rnfpseudobasis}. The name of this function comes from the fact that the ideal class of the last ideal of $I$, which is well defined, is the \idx{Steinitz class} of the $\Z_K$-module $\Z_L$ (its image in $SK_0(\Z_K)$). The library syntax is \fun{GEN}{rnfsteinitz}{GEN nf, GEN x}. \subsec{subgrouplist$(\var{bnr},\{\var{bound}\},\{\fl=0\})$}\kbdsidx{subgrouplist}\label{se:subgrouplist} \var{bnr} being as output by \kbd{bnrinit} or a list of cyclic components of a finite Abelian group $G$, outputs the list of subgroups of $G$. Subgroups are given as HNF left divisors of the SNF matrix corresponding to $G$. If $\fl=0$ (default) and \var{bnr} is as output by \kbd{bnrinit}, gives only the subgroups whose modulus is the conductor. Otherwise, the modulus is not taken into account. If \var{bound} is present, and is a positive integer, restrict the output to subgroups of index less than \var{bound}. If \var{bound} is a vector containing a single positive integer $B$, then only subgroups of index exactly equal to $B$ are computed. For instance \bprog ? subgrouplist([6,2]) %1 = [[6, 0; 0, 2], [2, 0; 0, 2], [6, 3; 0, 1], [2, 1; 0, 1], [3, 0; 0, 2], [1, 0; 0, 2], [6, 0; 0, 1], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] ? subgrouplist([6,2],3) \\@com index less than 3 %2 = [[2, 1; 0, 1], [1, 0; 0, 2], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] ? subgrouplist([6,2],[3]) \\@com index 3 %3 = [[3, 0; 0, 1]] ? bnr = bnrinit(bnfinit(x), [120,[1]], 1); ? L = subgrouplist(bnr, [8]); @eprog\noindent In the last example, $L$ corresponds to the 24 subfields of $\Q(\zeta_{120})$, of degree $8$ and conductor $120\infty$ (by setting \fl, we see there are a total of $43$ subgroups of degree $8$). \bprog ? vector(#L, i, galoissubcyclo(bnr, L[i])) @eprog\noindent will produce their equations. (For a general base field, you would have to rely on \tet{bnrstark}, or \tet{rnfkummer}.) The library syntax is \fun{GEN}{subgrouplist0}{GEN bnr, GEN bound = NULL, long flag}. \section{Associative and central simple algebras} This section collects functions related to associative algebras and central simple algebras (CSA) over number fields. \subsec{Basic definitions} %GPHELPskip Let $A$ be a finite-dimensional unital associative algebra over a field $K$. The algebra $A$ is \emph{central} if its center is $K$ and it is \emph{simple} if it has no nontrivial two-sided ideals. We provide functions to handle associative algebras of finite dimension over~$\Q$ or~$\F_p$. We represent them by the left multiplication table on a basis over the prime subfield; the function \kbd{algtableinit} creates the object representing an associative algebra. We also provide functions to handle central simple algebras over a number field $K$. We represent them either by the left multiplication table on a basis over the center $K$ or by a cyclic algebra (see below); the function~\kbd{alginit} creates the object representing a central simple algebra. The set of elements of an algebra~$A$ that annihilate every simple left $A$-module is a two-sided ideal, called the \emph{Jacobson radical} of~$A$. If the Jacobson radical is trivial, the algebra is \emph{semisimple}: it is isomorphic to a direct product of simple algebras. The dimension of a CSA over its center $K$ is always a square $d^2$ and the integer $d$ is called the \emph{degree} of the algebra over~$K$. A CSA over a field~$K$ is always isomorphic to~$M_k(D)$ for some integer~$k$ and some central division algebra~$D$ of degree~$e$: the integer~$e$ is the \emph{index} of the algebra. Let $L/K$ be a cyclic extension of degree $d$, let $\sigma$ be a generator of $\text{Gal}(L/K)$ and let $b\in K^*$. Then the \emph{cyclic algebra} $(L/K,\sigma,b)$ is the algebra $\bigoplus_{i=0}^{d-1}x^iL$ with $x^d=b$ and $\ell x=x\sigma(\ell)$ for all~$\ell\in L$. The algebra $(L/K,\sigma,b)$ is a central simple $K$-algebra of degree~$d$, and it is an $L$-vector space. Left multiplication is $L$-linear and induces a $K$-algebra isomorphism $(L/K,\sigma,b)\otimes_K L\to M_d(L)$. Let $K$ be a nonarchimedean local field with uniformizer $\pi$, and let $L/K$ be the unique unramified extension of degree $d$. Then every central simple algebra $A$ of degree $d$ over $K$ is isomorphic to $(L/K, \Frob, \pi^h)$ for some integer $h$. The element $h/d\in \Q/\Z$ is called the \emph{Hasse invariant} of $A$. \subsec{Orders} %GPHELPskip Let~$A$ be an algebra of finite dimension over~$\Q$. An \emph{order} in~$A$ is a finitely generated $\Z$-submodule~${\cal O}$ such that~$\Q{\cal O} = A$, that is also a subring with unit. By default the data computed by~\kbd{alginit} contains a~$\Z$-basis of a maximal order~${\cal O}_0$. We define natural orders in central simple algebras defined by a cyclic algebra or by a multiplication table over the center. Let~$A = (L/K,\sigma,b) = \bigoplus_{i=0}^{d-1}x^iL$ be a cyclic algebra over a number field~$K$ of degree~$n$ with ring of integers~$\Z_K$. Let~$\Z_L$ be the ring of integers of~$L$, and assume that~$b$ is integral. Then the submodule~${\cal O} = \bigoplus_{i=0}^{d-1}x^i\Z_L$ is an order in~$A$, called the \emph{natural order}. Let~$\omega_0,\dots,\omega_{nd-1}$ be a~$\Z$-basis of~$\Z_L$. The \emph{natural basis} of~${\cal O}$ is~$b_0,\dots,b_{nd^2-1}$ where~$b_i = x^{i/(nd)}\omega_{(i \mod nd)}$. Now let~$A$ be a central simple algebra of degree~$d$ over a number field~$K$ of degree~$n$ with ring of integers~$\Z_K$. Let~$e_0,\dots,e_{d^2-1}$ be a basis of~$A$ over~$K$ and assume that the left multiplication table of~$A$ on~$(e_i)$ is integral. Then the submodule~${\cal O} = \bigoplus_{i=0}^{d^2-1}\Z_K e_i$ is an order in~$A$, called the \emph{natural order}. Let~$\omega_0,\dots,\omega_{n-1}$ be a~$\Z$-basis of~$\Z_K$. The \emph{natural basis} of~${\cal O}$ is~$b_0,\dots,b_{nd^2-1}$ where~$b_i = \omega_{(i \mod n)}e_{i/n}$. \subsec{Lattices} %GPHELPskip We also provide functions to handle full lattices in algebras over~$\Q$. A full lattice~$J\subset A$ is represented by a $2$-component \typ{VEC}~$[I,t]$ representing~$J = tI$, where \item $I$ is an integral nonsingular upper-triangular matrix representing a sublattice of~${\cal O}_0$ expressed on the integral basis, and \item $t\in\Q_{>0}$ is a \typ{INT} or \typ{FRAC}. For the sake of efficiency you should use matrices~$I$ that are primitive and in Hermite Normal Form; this makes the representation unique. No GP function uses this property, but all GP functions return lattices in this form. The prefix for lattice functions is \kbd{alglat}. \subsec{GP conventions} %GPHELPskip As with number fields, we represent elements of central simple algebras in two ways, called the \emph{algebraic representation} and the \emph{basis representation}, and you can convert betweeen the two with the functions \kbd{algalgtobasis} and \kbd{algbasistoalg}. In every central simple algebra object, we store a~$\Z$-basis of an order~${\cal O}_0$, and the basis representation is simply a \typ{COL} with coefficients in~$\Q$ expressing the element in that basis. If no maximal order was computed by~\kbd{alginit}, then~${\cal O}_0$ is the natural order. If a maximal order was computed, then~${\cal O}_0$ is a maximal order containing the natural order. For a cyclic algebra~$A = (L/K,\sigma,b)$, the algebraic representation is a \typ{COL} with coefficients in~$L$ representing the element in the decomposition~$A = \bigoplus_{i=0}^{d-1}x^iL$. For a central simple algebra defined by a multiplication table over its center~$K$ on a basis~$(e_i)$, the algebraic representation is a \typ{COL} with coefficients in~$K$ representing the element on the basis~$(e_i)$. \misctitle{Warning} The coefficients in the decomposition~$A = \bigoplus_{i=0}^{d-1}x^iL$ are not the same as those in the decomposition~$A = \bigoplus_{i=0}^{d-1}Lx^i$! The $i$-th coefficients are related by conjugating by~$x^i$, which on~$L$ amounts to acting by~$\sigma^i$. \misctitle{Warning} For a central simple algebra over $\Q$ defined by a multiplication table, we cannot distinguish between the basis and the algebraic representations from the size of the vectors. The behavior is then to always interpret the column vector as a basis representation if the coefficients are \typ{INT} or \typ{FRAC}, and as an algebraic representation if the coefficients are \typ{POL} or \typ{POLMOD}. \subsec{algadd$(\var{al},x,y)$}\kbdsidx{algadd}\label{se:algadd} Given two elements $x$ and $y$ in \var{al}, computes their sum $x+y$ in the algebra~\var{al}. \bprog ? A = alginit(nfinit(y),[-1,1]); ? algadd(A,[1,0]~,[1,2]~) %2 = [2, 2]~ @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algadd}{GEN al, GEN x, GEN y}. \subsec{algalgtobasis$(\var{al},x)$}\kbdsidx{algalgtobasis}\label{se:algalgtobasis} Given an element \var{x} in the central simple algebra \var{al} output by \tet{alginit}, transforms it to a column vector on the integral basis of \var{al}. This is the inverse function of \tet{algbasistoalg}. \bprog ? A = alginit(nfinit(y^2-5),[2,y]); ? algalgtobasis(A,[y,1]~) %2 = [0, 2, 0, -1, 2, 0, 0, 0]~ ? algbasistoalg(A,algalgtobasis(A,[y,1]~)) %3 = [Mod(Mod(y, y^2 - 5), x^2 - 2), 1]~ @eprog The library syntax is \fun{GEN}{algalgtobasis}{GEN al, GEN x}. \subsec{algaut$(\var{al})$}\kbdsidx{algaut}\label{se:algaut} Given a cyclic algebra $\var{al} = (L/K,\sigma,b)$ output by \tet{alginit}, returns the automorphism $\sigma$. \bprog ? nf = nfinit(y); ? p = idealprimedec(nf,7)[1]; ? p2 = idealprimedec(nf,11)[1]; ? A = alginit(nf,[3,[[p,p2],[1/3,2/3]],[0]]); ? algaut(A) %5 = -1/3*x^2 + 1/3*x + 26/3 @eprog The library syntax is \fun{GEN}{algaut}{GEN al}. \subsec{algb$(\var{al})$}\kbdsidx{algb}\label{se:algb} Given a cyclic algebra $\var{al} = (L/K,\sigma,b)$ output by \tet{alginit}, returns the element $b\in K$. \bprog nf = nfinit(y); ? p = idealprimedec(nf,7)[1]; ? p2 = idealprimedec(nf,11)[1]; ? A = alginit(nf,[3,[[p,p2],[1/3,2/3]],[0]]); ? algb(A) %5 = Mod(-77, y) @eprog The library syntax is \fun{GEN}{algb}{GEN al}. \subsec{algbasis$(\var{al})$}\kbdsidx{algbasis}\label{se:algbasis} Given a central simple algebra \var{al} output by \tet{alginit}, returns a $\Z$-basis of the order~${\cal O}_0$ stored in \var{al} with respect to the natural order in \var{al}. It is a maximal order if one has been computed. \bprog A = alginit(nfinit(y), [-1,-1]); ? algbasis(A) %2 = [1 0 0 1/2] [0 1 0 1/2] [0 0 1 1/2] [0 0 0 1/2] @eprog The library syntax is \fun{GEN}{algbasis}{GEN al}. \subsec{algbasistoalg$(\var{al},x)$}\kbdsidx{algbasistoalg}\label{se:algbasistoalg} Given an element \var{x} in the central simple algebra \var{al} output by \tet{alginit}, transforms it to its algebraic representation in \var{al}. This is the inverse function of \tet{algalgtobasis}. \bprog ? A = alginit(nfinit(y^2-5),[2,y]); ? z = algbasistoalg(A,[0,1,0,0,2,-3,0,0]~); ? liftall(z) %3 = [(-1/2*y - 2)*x + (-1/4*y + 5/4), -3/4*y + 7/4]~ ? algalgtobasis(A,z) %4 = [0, 1, 0, 0, 2, -3, 0, 0]~ @eprog The library syntax is \fun{GEN}{algbasistoalg}{GEN al, GEN x}. \subsec{algcenter$(\var{al})$}\kbdsidx{algcenter}\label{se:algcenter} If \var{al} is a table algebra output by \tet{algtableinit}, returns a basis of the center of the algebra~\var{al} over its prime field ($\Q$ or $\F_p$). If \var{al} is a central simple algebra output by \tet{alginit}, returns the center of~\var{al}, which is stored in \var{al}. A simple example: the $2\times 2$ upper triangular matrices over $\Q$, generated by $I_2$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, such that $a^2 = 0$, $ab = a$, $ba = 0$, $b^2 = b$: the diagonal matrices form the center. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algcenter(A) \\ = (I_2) %3 = [1] [0] [0] @eprog An example in the central simple case: \bprog ? nf = nfinit(y^3-y+1); ? A = alginit(nf, [-1,-1]); ? algcenter(A).pol %3 = y^3 - y + 1 @eprog The library syntax is \fun{GEN}{algcenter}{GEN al}. \subsec{algcentralproj$(\var{al},z,\{\var{maps}=0\})$}\kbdsidx{algcentralproj}\label{se:algcentralproj} Given a table algebra \var{al} output by \tet{algtableinit} and a \typ{VEC} $\var{z}=[z_1,\dots,z_n]$ of orthogonal central idempotents, returns a \typ{VEC} $[al_1,\dots,al_n]$ of algebras such that $al_i = z_i\, al$. If $\var{maps}=1$, each $al_i$ is a \typ{VEC} $[quo,proj,lift]$ where \var{quo} is the quotient algebra, \var{proj} is a \typ{MAT} representing the projection onto this quotient and \var{lift} is a \typ{MAT} representing a lift. A simple example: $\F_2\times \F_4$, generated by~$1=(1,1)$, $e=(1,0)$ and~$x$ such that~$x^2+x+1=0$. We have~$e^2=e$, $x^2=x+1$ and~$ex=0$. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? e = [0,1,0]~; ? e2 = algsub(A,[1,0,0]~,e); ? [a,a2] = algcentralproj(A,[e,e2]); ? algdim(a) %6 = 1 ? algdim(a2) %7 = 2 @eprog The library syntax is \fun{GEN}{alg_centralproj}{GEN al, GEN z, long maps}. \subsec{algchar$(\var{al})$}\kbdsidx{algchar}\label{se:algchar} Given an algebra \var{al} output by \tet{alginit} or \tet{algtableinit}, returns the characteristic of \var{al}. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,13); ? algchar(A) %3 = 13 @eprog The library syntax is \fun{GEN}{algchar}{GEN al}. \subsec{algcharpoly$(\var{al},b,\{v='x\},\{\var{abs}=0\})$}\kbdsidx{algcharpoly}\label{se:algcharpoly} Given an element $b$ in \var{al}, returns its characteristic polynomial as a polynomial in the variable $v$. If \var{al} is a table algebra output by \tet{algtableinit} or if $abs=1$, returns the absolute characteristic polynomial of \var{b}, which is an element of $\F_p[v]$ or~$\Q[v]$; if \var{al} is a central simple algebra output by \tet{alginit} and $abs=0$, returns the reduced characteristic polynomial of \var{b}, which is an element of~$K[v]$ where~$K$ is the center of \var{al}. \bprog ? al = alginit(nfinit(y), [-1,-1]); \\ (-1,-1)_Q ? algcharpoly(al, [0,1]~) %2 = x^2 + 1 ? algcharpoly(al, [0,1]~,,1) %3 = x^4 + 2*x^2 + 1 ? nf = nfinit(y^2-5); ? al = alginit(nf,[-1,y]); ? a = [y,1+x]~*Mod(1,y^2-5)*Mod(1,x^2+1); ? P = lift(algcharpoly(al,a)) %7 = x^2 - 2*y*x + (-2*y + 5) ? algcharpoly(al,a,,1) %8 = x^8 - 20*x^6 - 80*x^5 + 110*x^4 + 800*x^3 + 1500*x^2 - 400*x + 25 ? lift(P*subst(P,y,-y)*Mod(1,y^2-5))^2 %9 = x^8 - 20*x^6 - 80*x^5 + 110*x^4 + 800*x^3 + 1500*x^2 - 400*x + 25 @eprog Also accepts a square matrix with coefficients in \var{al}. The library syntax is \fun{GEN}{algcharpoly}{GEN al, GEN b, long v = -1, long abs} where \kbd{v} is a variable number. \subsec{algdegree$(\var{al})$}\kbdsidx{algdegree}\label{se:algdegree} Given a central simple algebra \var{al} output by \tet{alginit}, returns the degree of \var{al}. \bprog ? nf = nfinit(y^3-y+1); ? A = alginit(nf, [-1,-1]); ? algdegree(A) %3 = 2 @eprog The library syntax is \fun{long}{algdegree}{GEN al}. \subsec{algdim$(\var{al},\{\var{abs}=0\})$}\kbdsidx{algdim}\label{se:algdim} If \var{al} is a table algebra output by \tet{algtableinit} or if~$abs=1$, returns the dimension of \var{al} over its prime subfield ($\Q$ or $\F_p$). If~\var{al} is a central simple algebra output by \tet{alginit} and~$abs=0$, returns the dimension of \var{al} over its center. \bprog ? nf = nfinit(y^3-y+1); ? A = alginit(nf, [-1,-1]); ? algdim(A) %3 = 4 ? algdim(A,1) %4 = 12 @eprog The library syntax is \fun{long}{algdim}{GEN al, long abs}. \subsec{algdisc$(\var{al})$}\kbdsidx{algdisc}\label{se:algdisc} Given a central simple algebra \var{al} output by \tet{alginit}, computes the discriminant of the order ${\cal O}_0$ stored in \var{al}, that is the determinant of the trace form $\rm{Tr} : {\cal O}_0\times {\cal O}_0 \to \Z$. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-3,1-y]); ? [PR,h] = alghassef(A) %3 = [[[2, [2, 0]~, 1, 2, 1], [3, [3, 0]~, 1, 2, 1]], Vecsmall([0, 1])] ? n = algdegree(A); ? D = algdim(A,1); ? h = vector(#h, i, n - gcd(n,h[i])); ? n^D * nf.disc^(n^2) * idealnorm(nf, idealfactorback(nf,PR,h))^n %4 = 12960000 ? algdisc(A) %5 = 12960000 @eprog The library syntax is \fun{GEN}{algdisc}{GEN al}. \subsec{algdivl$(\var{al},x,y)$}\kbdsidx{algdivl}\label{se:algdivl} Given two elements $x$ and $y$ in \var{al}, computes their left quotient $x\backslash y$ in the algebra \var{al}: an element $z$ such that $xz=y$ (such an element is not unique when $x$ is a zerodivisor). If~$x$ is invertible, this is the same as $x^{-1}y$. Assumes that $y$ is left divisible by $x$ (i.e. that $z$ exists). Also accepts matrices with coefficients in~\var{al}. The library syntax is \fun{GEN}{algdivl}{GEN al, GEN x, GEN y}. \subsec{algdivr$(\var{al},x,y)$}\kbdsidx{algdivr}\label{se:algdivr} Given two elements $x$ and $y$ in \var{al}, returns $xy^{-1}$. Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algdivr}{GEN al, GEN x, GEN y}. \subsec{alggroup$(\var{gal}, \{p=0\})$}\kbdsidx{alggroup}\label{se:alggroup} Initializes the group algebra~$K[G]$ over~$K=\Q$ ($p$ omitted) or~$\F_p$ where~$G$ is the underlying group of the \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed to be a \typ{VEC} of permutations that is closed under products. Example: \bprog ? K = nfsplitting(x^3-x+1); ? gal = galoisinit(K); ? al = alggroup(gal); ? algissemisimple(al) %4 = 1 ? G = [Vecsmall([1,2,3]), Vecsmall([1,3,2])]; ? al2 = alggroup(G, 2); ? algissemisimple(al2) %8 = 0 @eprog The library syntax is \fun{GEN}{alggroup}{GEN gal, GEN p = NULL}. \subsec{alggroupcenter$(\var{gal},\{p=0\},\{\&\var{cc}\})$}\kbdsidx{alggroupcenter}\label{se:alggroupcenter} Initializes the center~$Z(K[G])$ of the group algebra~$K[G]$ over~$K=\Q$ ($p = 0$ or omitted) or~$\F_p$ where~$G$ is the underlying group of the \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed to be a \typ{VEC} of permutations that is closed under products. Sets~\var{cc} to a \typ{VEC}~$[\var{elts},\var{conjclass},\var{rep},\var{flag}]$ where~\var{elts} is a sorted \typ{VEC} containing the list of elements of~$G$, \var{conjclass} is a \typ{VECSMALL} of the same length as~\var{elts} containing the index of the conjugacy class of the corresponding element (an integer between $1$ and the number of conjugacy classes), and~\var{rep} is a \typ{VECSMALL} of length the number of conjugacy classes giving for each conjugacy class the index in~\var{elts} of a representative of this conjugacy class. Finally \var{flag} is $1$ if and only if the permutation representation of $G$ is transitive, in which case the $i$-th element of \var{elts} is characterized by $g[1] = i$; this is always the case when \var{gal} is a \kbd{galoisinit} structure. The basis of~$Z(K[G])$ as output consists of the indicator functions of the conjugacy classes in the ordering given by~\var{cc}. Example: \bprog ? K = nfsplitting(x^4+x+1); ? gal = galoisinit(K); \\ S4 ? al = alggroupcenter(gal,,&cc); ? algiscommutative(al) %4 = 1 ? #cc[3] \\ number of conjugacy classes of S4 %5 = 5 ? gal = [Vecsmall([1,2,3]),Vecsmall([1,3,2])]; \\ C2 ? al = alggroupcenter(gal,,&cc); ? cc[3] %8 = Vecsmall([1, 2]) ? cc[4] %9 = 0 @eprog The library syntax is \fun{GEN}{alggroupcenter}{GEN gal, GEN p = NULL, GEN *cc = NULL}. \subsec{alghasse$(\var{al},\var{pl})$}\kbdsidx{alghasse}\label{se:alghasse} Given a central simple algebra \var{al} output by \tet{alginit} and a prime ideal or an integer between $1$ and $r_1+r_2$, returns a \typ{FRAC} $h$ : the local Hasse invariant of \var{al} at the place specified by \var{pl}. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? alghasse(A, 1) %3 = 1/2 ? alghasse(A, 2) %4 = 0 ? alghasse(A, idealprimedec(nf,2)[1]) %5 = 1/2 ? alghasse(A, idealprimedec(nf,5)[1]) %6 = 0 @eprog The library syntax is \fun{GEN}{alghasse}{GEN al, GEN pl}. \subsec{alghassef$(\var{al})$}\kbdsidx{alghassef}\label{se:alghassef} Given a central simple algebra \var{al} output by \tet{alginit}, returns a \typ{VEC} $[\kbd{PR}, h_f]$ describing the local Hasse invariants at the finite places of the center: \kbd{PR} is a \typ{VEC} of primes and $h_f$ is a \typ{VECSMALL} of integers modulo the degree $d$ of \var{al}. The Hasse invariant of~\var{al} at the primes outside~\kbd{PR} is~$0$, but~\kbd{PR} can include primes at which the Hasse invariant is~$0$. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,2*y-1]); ? [PR,hf] = alghassef(A); ? PR %4 = [[19, [10, 2]~, 1, 1, [-8, 2; 2, -10]], [2, [2, 0]~, 1, 2, 1]] ? hf %5 = Vecsmall([1, 0]) @eprog The library syntax is \fun{GEN}{alghassef}{GEN al}. \subsec{alghassei$(\var{al})$}\kbdsidx{alghassei}\label{se:alghassei} Given a central simple algebra \var{al} output by \tet{alginit}, returns a \typ{VECSMALL} $h_i$ of $r_1$ integers modulo the degree $d$ of \var{al}, where $r_1$ is the number of real places of the center: the local Hasse invariants of \var{al} at infinite places. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? alghassei(A) %3 = Vecsmall([1, 0]) @eprog The library syntax is \fun{GEN}{alghassei}{GEN al}. \subsec{algindex$(\var{al},\{\var{pl}\})$}\kbdsidx{algindex}\label{se:algindex} Returns the index of the central simple algebra~$A$ over~$K$ (as output by alginit), that is the degree~$e$ of the unique central division algebra~$D$ over $K$ such that~$A$ is isomorphic to some matrix algebra~$M_k(D)$. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case return the local index at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algindex(A, 1) %3 = 2 ? algindex(A, 2) %4 = 1 ? algindex(A, idealprimedec(nf,2)[1]) %5 = 2 ? algindex(A, idealprimedec(nf,5)[1]) %6 = 1 ? algindex(A) %7 = 2 @eprog The library syntax is \fun{long}{algindex}{GEN al, GEN pl = NULL}. \subsec{alginit$(B, C, \{v\}, \{\var{maxord} = 1\})$}\kbdsidx{alginit}\label{se:alginit} Initializes the central simple algebra defined by data $B$, $C$ and variable $v$, as follows. \item (multiplication table) $B$ is the base number field $K$ in \tet{nfinit} form, $C$ is a ``multiplication table'' over $K$. As a $K$-vector space, the algebra is generated by a basis $(e_1 = 1,\dots, e_n)$; the table is given as a \typ{VEC} of $n$ matrices in $M_n(K)$, giving the left multiplication by the basis elements~$e_i$, in the given basis. Assumes that $e_1= 1$, that the multiplication table is integral, and that $(\bigoplus_{i=1}^nK e_i,C)$ describes a central simple algebra over $K$. \bprog { mi = [0,-1,0, 0; 1, 0,0, 0; 0, 0,0,-1; 0, 0,1, 0]; mj = [0, 0,-1,0; 0, 0, 0,1; 1, 0, 0,0; 0,-1, 0,0]; mk = [0, 0, 0, 0; 0, 0,-1, 0; 0, 1, 0, 0; 1, 0, 0,-1]; A = alginit(nfinit(y), [matid(4), mi,mj,mk], 0); } @eprog represents (in a complicated way) the quaternion algebra $(-1,-1)_\Q$. See below for a simpler solution. \item (cyclic algebra) $B$ is an \kbd{rnf} structure attached to a cyclic number field extension $L/K$ of degree $d$, $C$ is a \typ{VEC} \kbd{[sigma,b]} with 2 components: \kbd{sigma} is a \typ{POLMOD} representing an automorphism generating $\text{Gal}(L/K)$, $b$ is an element in $K^*$. This represents the cyclic algebra~$(L/K,\sigma,b)$. Currently the element $b$ has to be integral. \bprog ? Q = nfinit(y); T = polcyclo(5, 'x); F = rnfinit(Q, T); ? A = alginit(F, [Mod(x^2,T), 3]); @eprog defines the cyclic algebra $(L/\Q, \sigma, 3)$, where $L = \Q(\zeta_5)$ and $\sigma:\zeta\mapsto\zeta^2$ generates $\text{Gal}(L/\Q)$. \item (quaternion algebra, special case of the above) $B$ is an \kbd{nf} structure attached to a number field $K$, $C = [a,b]$ is a vector containing two elements of $K^*$ with $a$ not a square in $K$, returns the quaternion algebra $(a,b)_K$. The variable $v$ (\kbd{'x} by default) must have higher priority than the variable of $K$\kbd{.pol} and is used to represent elements in the splitting field $L = K[x]/(x^2-a)$. \bprog ? Q = nfinit(y); A = alginit(Q, [-1,-1]); \\@com $(-1,-1)_\Q$ @eprog \item (algebra/$K$ defined by local Hasse invariants) $B$ is an \kbd{nf} structure attached to a number field $K$, $C = [d, [\kbd{PR},h_f], h_i]$ is a triple containing an integer $d > 1$, a pair $[\kbd{PR}, h_f]$ describing the Hasse invariants at finite places, and $h_i$ the Hasse invariants at archimedean (real) places. A local Hasse invariant belongs to $(1/d)\Z/\Z \subset \Q/\Z$, and is given either as a \typ{FRAC} (lift to $(1/d)\Z$), a \typ{INT} or \typ{INTMOD} modulo $d$ (lift to $\Z/d\Z$); a whole vector of local invariants can also be given as a \typ{VECSMALL}, whose entries are handled as \typ{INT}s. \kbd{PR} is a list of prime ideals (\kbd{prid} structures), and $h_f$ is a vector of the same length giving the local invariants at those maximal ideals. The invariants at infinite real places are indexed by the real roots $K$\kbd{.roots}: if the Archimedean place $v$ is attached to the $j$-th root, the value of $h_v$ is given by $h_i[j]$, must be $0$ or $1/2$ (or~$d/2$ modulo~$d$), and can be nonzero only if~$d$ is even. By class field theory, provided the local invariants $h_v$ sum to $0$, up to Brauer equivalence, there is a unique central simple algebra over $K$ with given local invariants and trivial invariant elsewhere. In particular, up to isomorphism, there is a unique such algebra $A$ of degree $d$. We realize $A$ as a cyclic algebra through class field theory. The variable $v$ (\kbd{'x} by default) must have higher priority than the variable of $K$\kbd{.pol} and is used to represent elements in the (cyclic) splitting field extension $L/K$ for $A$. \bprog ? nf = nfinit(y^2+1); ? PR = idealprimedec(nf,5); #PR %2 = 2 ? hi = []; ? hf = [PR, [1/3,-1/3]]; ? A = alginit(nf, [3,hf,hi]); ? algsplittingfield(A).pol %6 = x^3 - 21*x + 7 @eprog \item (matrix algebra, toy example) $B$ is an \kbd{nf} structure attached to a number field $K$, $C = d$ is a positive integer. Returns a cyclic algebra isomorphic to the matrix algebra $M_d(K)$. In all cases, this function computes a maximal order for the algebra by default, which may require a lot of time. Setting $maxord = 0$ prevents this computation. The pari object representing such an algebra $A$ is a \typ{VEC} with the following data: \item A splitting field $L$ of $A$ of the same degree over $K$ as $A$, in \kbd{rnfinit} format, accessed with \kbd{algsplittingfield}. \item The Hasse invariants at the real places of $K$, accessed with \kbd{alghassei}. \item The Hasse invariants of $A$ at the finite primes of $K$ that ramify in the natural order of $A$, accessed with \kbd{alghassef}. \item A basis of an order ${\cal O}_0$ expressed on the basis of the natural order, accessed with \kbd{algbasis}. \item A basis of the natural order expressed on the basis of ${\cal O}_0$, accessed with \kbd{alginvbasis}. \item The left multiplication table of ${\cal O}_0$ on the previous basis, accessed with \kbd{algmultable}. \item The characteristic of $A$ (always $0$), accessed with \kbd{algchar}. \item The absolute traces of the elements of the basis of ${\cal O}_0$. \item If $A$ was constructed as a cyclic algebra~$(L/K,\sigma,b)$ of degree $d$, a \typ{VEC} $[\sigma,\sigma^2,\dots,\sigma^{d-1}]$. The function \kbd{algaut} returns $\sigma$. \item If $A$ was constructed as a cyclic algebra~$(L/K,\sigma,b)$, the element $b$, accessed with \kbd{algb}. \item If $A$ was constructed with its multiplication table $mt$ over $K$, the \typ{VEC} of \typ{MAT} $mt$, accessed with \kbd{algrelmultable}. \item If $A$ was constructed with its multiplication table $mt$ over $K$, a \typ{VEC} with three components: a \typ{COL} representing an element of $A$ generating the splitting field $L$ as a maximal subfield of $A$, a \typ{MAT} representing an $L$-basis ${\cal B}$ of $A$ expressed on the $\Z$-basis of ${\cal O}_0$, and a \typ{MAT} representing the $\Z$-basis of ${\cal O}_0$ expressed on ${\cal B}$. This data is accessed with \kbd{algsplittingdata}. The library syntax is \fun{GEN}{alginit}{GEN B, GEN C, long v = -1, long maxord} where \kbd{v} is a variable number. \subsec{alginv$(\var{al},x)$}\kbdsidx{alginv}\label{se:alginv} Given an element $x$ in \var{al}, computes its inverse $x^{-1}$ in the algebra \var{al}. Assumes that $x$ is invertible. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? alginv(A,[1,1,0,0]~) %2 = [1/2, 1/2, 0, 0]~ @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{alginv}{GEN al, GEN x}. \subsec{alginvbasis$(\var{al})$}\kbdsidx{alginvbasis}\label{se:alginvbasis} Given an central simple algebra \var{al} output by \tet{alginit}, returns a $\Z$-basis of the natural order in \var{al} with respect to the order~${\cal O}_0$ stored in \var{al}. \bprog A = alginit(nfinit(y), [-1,-1]); ? alginvbasis(A) %2 = [1 0 0 -1] [0 1 0 -1] [0 0 1 -1] [0 0 0 2] @eprog The library syntax is \fun{GEN}{alginvbasis}{GEN al}. \subsec{algisassociative$(\var{mt},p=0)$}\kbdsidx{algisassociative}\label{se:algisassociative} Returns 1 if the multiplication table \kbd{mt} is suitable for \kbd{algtableinit(mt,p)}, 0 otherwise. More precisely, \kbd{mt} should be a \typ{VEC} of $n$ matrices in $M_n(K)$, giving the left multiplications by the basis elements $e_1, \dots, e_n$ (structure constants). We check whether the first basis element $e_1$ is $1$ and $e_i(e_je_k) = (e_ie_j)e_k$ for all $i,j,k$. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? algisassociative(mt) %2 = 1 @eprog May be used to check a posteriori an algebra: we also allow \kbd{mt} as output by \tet{algtableinit} ($p$ is ignored in this case). The library syntax is \fun{GEN}{algisassociative}{GEN mt, GEN p}. \subsec{algiscommutative$(\var{al})$}\kbdsidx{algiscommutative}\label{se:algiscommutative} \var{al} being a table algebra output by \tet{algtableinit} or a central simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is commutative. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algiscommutative(A) %3 = 0 ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? algiscommutative(A) %6 = 1 @eprog The library syntax is \fun{GEN}{algiscommutative}{GEN al}. \subsec{algisdivision$(\var{al},\{\var{pl}\})$}\kbdsidx{algisdivision}\label{se:algisdivision} Given a central simple algebra \var{al} output by \tet{alginit}, tests whether \var{al} is a division algebra. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case tests whether \var{al} is locally a division algebra at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algisdivision(A, 1) %3 = 1 ? algisdivision(A, 2) %4 = 0 ? algisdivision(A, idealprimedec(nf,2)[1]) %5 = 1 ? algisdivision(A, idealprimedec(nf,5)[1]) %6 = 0 ? algisdivision(A) %7 = 1 @eprog The library syntax is \fun{GEN}{algisdivision}{GEN al, GEN pl = NULL}. \subsec{algisdivl$(\var{al},x,y,\{\&z\})$}\kbdsidx{algisdivl}\label{se:algisdivl} Given two elements $x$ and $y$ in \var{al}, tests whether $y$ is left divisible by $x$, that is whether there exists~$z$ in \var{al} such that~$xz=y$, and sets $z$ to this element if it exists. \bprog ? A = alginit(nfinit(y), [-1,1]); ? algisdivl(A,[x+2,-x-2]~,[x,1]~) %2 = 0 ? algisdivl(A,[x+2,-x-2]~,[-x,x]~,&z) %3 = 1 ? z %4 = [Mod(-2/5*x - 1/5, x^2 + 1), 0]~ @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algisdivl}{GEN al, GEN x, GEN y, GEN *z = NULL}. \subsec{algisinv$(\var{al},x,\{\&\var{ix}\})$}\kbdsidx{algisinv}\label{se:algisinv} Given an element $x$ in \var{al}, tests whether $x$ is invertible, and sets $ix$ to the inverse of $x$. \bprog ? A = alginit(nfinit(y), [-1,1]); ? algisinv(A,[-1,1]~) %2 = 0 ? algisinv(A,[1,2]~,&ix) %3 = 1 ? ix %4 = [Mod(Mod(-1/3, y), x^2 + 1), Mod(Mod(2/3, y), x^2 + 1)]~ @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algisinv}{GEN al, GEN x, GEN *ix = NULL}. \subsec{algisramified$(\var{al},\{\var{pl}\})$}\kbdsidx{algisramified}\label{se:algisramified} Given a central simple algebra \var{al} output by \tet{alginit}, tests whether \var{al} is ramified, i.e. not isomorphic to a matrix algebra over its center. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case tests whether \var{al} is locally ramified at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algisramified(A, 1) %3 = 1 ? algisramified(A, 2) %4 = 0 ? algisramified(A, idealprimedec(nf,2)[1]) %5 = 1 ? algisramified(A, idealprimedec(nf,5)[1]) %6 = 0 ? algisramified(A) %7 = 1 @eprog The library syntax is \fun{GEN}{algisramified}{GEN al, GEN pl = NULL}. \subsec{algissemisimple$(\var{al})$}\kbdsidx{algissemisimple}\label{se:algissemisimple} \var{al} being a table algebra output by \tet{algtableinit} or a central simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is semisimple. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algissemisimple(A) %3 = 0 ? m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; \\ quaternion algebra (-1,-1) ? m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; ? m_k=[0,0,0,-1;0,0,-1,0;0,1,0,0;1,0,0,0]; ? mt = [matid(4), m_i, m_j, m_k]; ? A = algtableinit(mt); ? algissemisimple(A) %9 = 1 @eprog The library syntax is \fun{GEN}{algissemisimple}{GEN al}. \subsec{algissimple$(\var{al}, \{\var{ss} = 0\})$}\kbdsidx{algissimple}\label{se:algissimple} \var{al} being a table algebra output by \tet{algtableinit} or a central simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is simple. If $\var{ss}=1$, assumes that the algebra~\var{al} is semisimple without testing it. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); \\ matrices [*,*; 0,*] ? algissimple(A) %3 = 0 ? algissimple(A,1) \\ incorrectly assume that A is semisimple %4 = 1 ? m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; ? m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; ? m_k=[0,0,0,-1;0,0,b,0;0,1,0,0;1,0,0,0]; ? mt = [matid(4), m_i, m_j, m_k]; ? A = algtableinit(mt); \\ quaternion algebra (-1,-1) ? algissimple(A) %10 = 1 ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); \\ direct product F_4 x F_2 ? algissimple(A) %13 = 0 @eprog The library syntax is \fun{GEN}{algissimple}{GEN al, long ss}. \subsec{algissplit$(\var{al},\{\var{pl}\})$}\kbdsidx{algissplit}\label{se:algissplit} Given a central simple algebra \var{al} output by \tet{alginit}, tests whether~\var{al} is split, i.e. isomorphic to a matrix algebra over its center. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case tests whether \var{al} is locally split at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algissplit(A, 1) %3 = 0 ? algissplit(A, 2) %4 = 1 ? algissplit(A, idealprimedec(nf,2)[1]) %5 = 0 ? algissplit(A, idealprimedec(nf,5)[1]) %6 = 1 ? algissplit(A) %7 = 0 @eprog The library syntax is \fun{GEN}{algissplit}{GEN al, GEN pl = NULL}. \subsec{alglatadd$(\var{al},\var{lat1},\var{lat2},\{\&\var{ptinter}\})$}\kbdsidx{alglatadd}\label{se:alglatadd} Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the sum~$lat1 + lat2$. If \var{ptinter} is present, set it to the intersection~$lat1 \cap lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? latsum = alglatadd(al,lat1,lat2,&latinter); ? matdet(latsum[1]) %5 = 4 ? matdet(latinter[1]) %6 = 64 @eprog The library syntax is \fun{GEN}{alglatadd}{GEN al, GEN lat1, GEN lat2, GEN *ptinter = NULL}. \subsec{alglatcontains$(\var{al},\var{lat},x,\{\&\var{ptc}\})$}\kbdsidx{alglatcontains}\label{se:alglatcontains} Given an algebra \var{al}, a lattice \var{lat} and \var{x} in~\var{al}, tests whether~$x\in lat$. If~\var{ptc} is present, sets it to the~\typ{COL} of coordinates of~$x$ in the basis of~\var{lat}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a1 = [1,-1,0,1,2,0,1,2]~; ? lat1 = alglathnf(al,a1); ? alglatcontains(al,lat1,a1,&c) %4 = 1 ? c %5 = [-1, -2, -1, 1, 2, 0, 1, 1]~ @eprog The library syntax is \fun{GEN}{alglatcontains}{GEN al, GEN lat, GEN x, GEN *ptc = NULL}. \subsec{alglatelement$(\var{al},\var{lat},c)$}\kbdsidx{alglatelement}\label{se:alglatelement} Given an algebra \var{al}, a lattice \var{lat} and a~\typ{COL}~\var{c}, returns the element of~\var{al} whose coordinates on the \Z-basis of~\var{lat} are given by~\var{c}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a1 = [1,-1,0,1,2,0,1,2]~; ? lat1 = alglathnf(al,a1); ? c = [1..8]~; ? elt = alglatelement(al,lat1,c); ? alglatcontains(al,lat1,elt,&c2) %6 = 1 ? c==c2 %7 = 1 @eprog The library syntax is \fun{GEN}{alglatelement}{GEN al, GEN lat, GEN c}. \subsec{alglathnf$(\var{al},m,\{d=0\})$}\kbdsidx{alglathnf}\label{se:alglathnf} Given an algebra \var{al} and a matrix \var{m} with columns representing elements of \var{al}, returns the lattice $L$ generated by the columns of \var{m}. If provided, \var{d} must be a rational number such that $L$ contains \var{d} times the natural basis of~\var{al}. The argument \var{m} is also allowed to be a \typ{VEC} of \typ{MAT}, in which case \var{m} is replaced by the concatenation of the matrices, or a \typ{COL}, in which case \var{m} is replaced by its left multiplication table as an element of \var{al}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a = [1,1,-1/2,1,1/3,-1,1,1]~; ? mt = algtomatrix(al,a,1); ? lat = alglathnf(al,mt); ? lat[2] %5 = 1/6 @eprog The library syntax is \fun{GEN}{alglathnf}{GEN al, GEN m, GEN d}. \subsec{alglatindex$(\var{al},\var{lat1},\var{lat2})$}\kbdsidx{alglatindex}\label{se:alglatindex} Given an algebra~\var{al} and two lattices~\var{lat1} and~\var{lat2} in~\var{al}, computes the generalized index of~\var{lat1} relative to~\var{lat2}, i.e.~$|lat2/lat1\cap lat2|/|lat1/lat1\cap lat2|$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? alglatindex(al,lat1,lat2) %4 = 1 ? lat1==lat2 %5 = 0 @eprog The library syntax is \fun{GEN}{alglatindex}{GEN al, GEN lat1, GEN lat2}. \subsec{alglatinter$(\var{al},\var{lat1},\var{lat2},\{\&\var{ptsum}\})$}\kbdsidx{alglatinter}\label{se:alglatinter} Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the intersection~$lat1\cap lat2$. If \var{ptsum} is present, sets it to the sum~$lat1 + lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? latinter = alglatinter(al,lat1,lat2,&latsum); ? matdet(latsum[1]) %5 = 4 ? matdet(latinter[1]) %6 = 64 @eprog The library syntax is \fun{GEN}{alglatinter}{GEN al, GEN lat1, GEN lat2, GEN *ptsum = NULL}. \subsec{alglatlefttransporter$(\var{al},\var{lat1},\var{lat2})$}\kbdsidx{alglatlefttransporter}\label{se:alglatlefttransporter} Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the left transporter from \var{lat1} to~\var{lat2}, i.e. the set of~$x\in al$ such that~$x\cdot lat1 \subset lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,-1,0,1,2,0,5,2]~); ? lat2 = alglathnf(al,[0,1,-2,-1,0,0,3,1]~); ? tr = alglatlefttransporter(al,lat1,lat2); ? a = alglatelement(al,tr,[0,0,0,0,0,0,1,0]~); ? alglatsubset(al,alglatmul(al,a,lat1),lat2) %6 = 1 ? alglatsubset(al,alglatmul(al,lat1,a),lat2) %7 = 0 @eprog The library syntax is \fun{GEN}{alglatlefttransporter}{GEN al, GEN lat1, GEN lat2}. \subsec{alglatmul$(\var{al},\var{lat1},\var{lat2})$}\kbdsidx{alglatmul}\label{se:alglatmul} Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the lattice generated by the products of elements of~\var{lat1} and~\var{lat2}. One of \var{lat1} and \var{lat2} is also allowed to be an element of~\var{al}; in this case, computes the product of the element and the lattice. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a1 = [1,-1,0,1,2,0,1,2]~; ? a2 = [0,1,2,-1,0,0,3,1]~; ? lat1 = alglathnf(al,a1); ? lat2 = alglathnf(al,a2); ? lat3 = alglatmul(al,lat1,lat2); ? matdet(lat3[1]) %7 = 29584 ? lat3 == alglathnf(al, algmul(al,a1,a2)) %8 = 0 ? lat3 == alglatmul(al, lat1, a2) %9 = 0 ? lat3 == alglatmul(al, a1, lat2) %10 = 0 @eprog The library syntax is \fun{GEN}{alglatmul}{GEN al, GEN lat1, GEN lat2}. \subsec{alglatrighttransporter$(\var{al},\var{lat1},\var{lat2})$}\kbdsidx{alglatrighttransporter}\label{se:alglatrighttransporter} Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the right transporter from \var{lat1} to~\var{lat2}, i.e. the set of~$x\in al$ such that~$lat1\cdot x \subset lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,matdiagonal([1,3,7,1,2,8,5,2])); ? lat2 = alglathnf(al,matdiagonal([5,3,8,1,9,8,7,1])); ? tr = alglatrighttransporter(al,lat1,lat2); ? a = alglatelement(al,tr,[0,0,0,0,0,0,0,1]~); ? alglatsubset(al,alglatmul(al,lat1,a),lat2) %6 = 1 ? alglatsubset(al,alglatmul(al,a,lat1),lat2) %7 = 0 @eprog The library syntax is \fun{GEN}{alglatrighttransporter}{GEN al, GEN lat1, GEN lat2}. \subsec{alglatsubset$(\var{al},\var{lat1},\var{lat2},\{\&\var{ptindex}\})$}\kbdsidx{alglatsubset}\label{se:alglatsubset} Given an algebra~\var{al} and two lattices~\var{lat1} and~\var{lat2} in~\var{al}, tests whether~$lat1\subset lat2$. If it is true and \var{ptindex} is present, sets it to the index of~\var{lat1} in~\var{lat2}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? alglatsubset(al,lat1,lat2) %4 = 0 ? latsum = alglatadd(al,lat1,lat2); ? alglatsubset(al,lat1,latsum,&index) %6 = 1 ? index %7 = 4 @eprog The library syntax is \fun{GEN}{alglatsubset}{GEN al, GEN lat1, GEN lat2, GEN *ptindex = NULL}. \subsec{algmakeintegral$(\var{mt},\{\var{maps}=0\})$}\kbdsidx{algmakeintegral}\label{se:algmakeintegral} \var{mt} being a multiplication table over $\Q$ in the same format as the input of \tet{algtableinit}, computes an integral multiplication table for an isomorphic algebra. When $\var{maps}=1$, returns a \typ{VEC} $[\var{mt2},\var{S},\var{T}]$ where \var{S} and \var{T} are matrices respectively representing the map from the algebra defined by \var{mt} to the one defined by \var{mt2} and its inverse. \bprog ? mt = [matid(2),[0,-1/4;1,0]]; ? algtableinit(mt); *** at top-level: algtableinit(mt) *** ^---------------- *** algtableinit: domain error in algtableinit: denominator(mt) != 1 ? mt2 = algmakeintegral(mt); ? al = algtableinit(mt2); ? algisassociative(al) %4 = 1 @eprog The library syntax is \fun{GEN}{algmakeintegral}{GEN mt, long maps}. \subsec{algmul$(\var{al},x,y)$}\kbdsidx{algmul}\label{se:algmul} Given two elements $x$ and $y$ in \var{al}, computes their product $xy$ in the algebra~\var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algmul(A,[1,1,0,0]~,[0,0,2,1]~) %2 = [2, 3, 5, -4]~ @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algmul}{GEN al, GEN x, GEN y}. \subsec{algmultable$(\var{al})$}\kbdsidx{algmultable}\label{se:algmultable} Returns a multiplication table of \var{al} over its prime subfield ($\Q$ or $\F_p$), as a \typ{VEC} of \typ{MAT}: the left multiplication tables of basis elements. If \var{al} was output by \tet{algtableinit}, returns the multiplication table used to define \var{al}. If \var{al} was output by \tet{alginit}, returns the multiplication table of the order~${\cal O}_0$ stored in \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? M = algmultable(A); ? #M %3 = 4 ? M[1] \\ multiplication by e_1 = 1 %4 = [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] ? M[2] %5 = [0 -1 1 0] [1 0 1 1] [0 0 1 1] [0 0 -2 -1] @eprog The library syntax is \fun{GEN}{algmultable}{GEN al}. \subsec{algneg$(\var{al},x)$}\kbdsidx{algneg}\label{se:algneg} Given an element $x$ in \var{al}, computes its opposite $-x$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algneg(A,[1,1,0,0]~) %2 = [-1, -1, 0, 0]~ @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algneg}{GEN al, GEN x}. \subsec{algnorm$(\var{al},x,\{\var{abs}=0\})$}\kbdsidx{algnorm}\label{se:algnorm} Given an element \var{x} in \var{al}, computes its norm. If \var{al} is a table algebra output by \tet{algtableinit} or if $abs=1$, returns the absolute norm of \var{x}, which is an element of $\F_p$ of~$\Q$; if \var{al} is a central simple algebra output by \tet{alginit} and $abs=0$ (default), returns the reduced norm of \var{x}, which is an element of the center of \var{al}. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,19); ? algnorm(A,[0,-2,3]~) %3 = 18 ? nf = nfinit(y^2-5); ? B = alginit(nf,[-1,y]); ? b = [x,1]~; ? n = algnorm(B,b) %7 = Mod(-y + 1, y^2 - 5) ? algnorm(B,b,1) %8 = 16 ? nfeltnorm(nf,n)^algdegree(B) %9 = 16 @eprog Also accepts a square matrix with coefficients in \var{al}. The library syntax is \fun{GEN}{algnorm}{GEN al, GEN x, long abs}. \subsec{algpoleval$(\var{al},T,b)$}\kbdsidx{algpoleval}\label{se:algpoleval} Given an element $b$ in \var{al} and a polynomial $T$ in $K[X]$, computes~$T(b)$ in~\var{al}. Also accepts as input a \typ{VEC}~$[b,mb]$ where~$mb$ is the left multiplication table of~$b$. \bprog ? nf = nfinit(y^2-5); ? al = alginit(nf,[y,-1]); ? b = [1..8]~; ? pol = algcharpoly(al,b,,1); ? algpoleval(al,pol,b)==0 %5 = 1 ? mb = algtomatrix(al,b,1); ? algpoleval(al,pol,[b,mb])==0 %7 = 1 @eprog The library syntax is \fun{GEN}{algpoleval}{GEN al, GEN T, GEN b}. \subsec{algpow$(\var{al},x,n)$}\kbdsidx{algpow}\label{se:algpow} Given an element $x$ in \var{al} and an integer $n$, computes the power $x^n$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algpow(A,[1,1,0,0]~,7) %2 = [8, -8, 0, 0]~ @eprog Also accepts a square matrix with coefficients in \var{al}. The library syntax is \fun{GEN}{algpow}{GEN al, GEN x, GEN n}. \subsec{algprimesubalg$(\var{al})$}\kbdsidx{algprimesubalg}\label{se:algprimesubalg} \var{al} being the output of \tet{algtableinit} representing a semisimple algebra of positive characteristic, returns a basis of the prime subalgebra of~\var{al}. The prime subalgebra of~\var{al} is the subalgebra fixed by the Frobenius automorphism of the center of \var{al}. It is abstractly isomorphic to a product of copies of $\F_p$. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? algprimesubalg(A) %3 = [1 0] [0 1] [0 0] @eprog The library syntax is \fun{GEN}{algprimesubalg}{GEN al}. \subsec{algquotient$(\var{al},I,\{\var{maps}=0\})$}\kbdsidx{algquotient}\label{se:algquotient} \var{al} being a table algebra output by \tet{algtableinit} and \var{I} being a basis of a two-sided ideal of \var{al} represented by a matrix, returns the quotient $\var{al}/\var{I}$. When $\var{maps}=1$, returns a \typ{VEC} $[\var{al}/\var{I},\var{proj},\var{lift}]$ where \var{proj} and \var{lift} are matrices respectively representing the projection map and a section of it. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? AQ = algquotient(A,[0;1;0]); ? algdim(AQ) %4 = 2 @eprog The library syntax is \fun{GEN}{alg_quotient}{GEN al, GEN I, long maps}. \subsec{algradical$(\var{al})$}\kbdsidx{algradical}\label{se:algradical} \var{al} being a table algebra output by \tet{algtableinit}, returns a basis of the Jacobson radical of the algebra \var{al} over its prime field ($\Q$ or $\F_p$). Here is an example with $A = \Q[x]/(x^2)$, with the basis~$(1,x)$: \bprog ? mt = [matid(2),[0,0;1,0]]; ? A = algtableinit(mt); ? algradical(A) \\ = (x) %3 = [0] [1] @eprog Another one with $2\times 2$ upper triangular matrices over $\Q$, with basis $I_2$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, such that $a^2 = 0$, $ab = a$, $ba = 0$, $b^2 = b$: \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algradical(A) \\ = (a) %6 = [0] [1] [0] @eprog The library syntax is \fun{GEN}{algradical}{GEN al}. \subsec{algramifiedplaces$(\var{al})$}\kbdsidx{algramifiedplaces}\label{se:algramifiedplaces} Given a central simple algebra \var{al} output by \tet{alginit}, returns a \typ{VEC} containing the list of places of the center of \var{al} that are ramified in \var{al}. Each place is described as an integer between~$1$ and~$r_1$ or as a prime ideal. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algramifiedplaces(A) %3 = [1, [2, [2, 0]~, 1, 2, 1]] @eprog The library syntax is \fun{GEN}{algramifiedplaces}{GEN al}. \subsec{algrandom$(\var{al},b)$}\kbdsidx{algrandom}\label{se:algrandom} Given an algebra \var{al} and an integer \var{b}, returns a random element in \var{al} with coefficients in~$[-b,b]$. The library syntax is \fun{GEN}{algrandom}{GEN al, GEN b}. \subsec{algrelmultable$(\var{al})$}\kbdsidx{algrelmultable}\label{se:algrelmultable} Given a central simple algebra \var{al} output by \tet{alginit} defined by a multiplication table over its center (a number field), returns this multiplication table. \bprog ? nf = nfinit(y^3-5); a = y; b = y^2; ? {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} ? {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} ? {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} ? mt = [matid(4), m_i, m_j, m_k]; ? A = alginit(nf,mt,'x); ? M = algrelmultable(A); ? M[2] == m_i %8 = 1 ? M[3] == m_j %9 = 1 ? M[4] == m_k %10 = 1 @eprog The library syntax is \fun{GEN}{algrelmultable}{GEN al}. \subsec{algsimpledec$(\var{al},\{\var{maps}=0\})$}\kbdsidx{algsimpledec}\label{se:algsimpledec} \var{al} being the output of \tet{algtableinit}, returns a \typ{VEC} $[J,[\var{al}_1,\var{al}_2,\dots,\var{al}_n]]$ where $J$ is a basis of the Jacobson radical of \var{al} and~$\var{al}/J$ is isomorphic to the direct product of the simple algebras~$\var{al}_i$. When $\var{maps}=1$, each~$\var{al}_i$ is replaced with a \typ{VEC} $[\var{al}_i,\var{proj}_i,\var{lift}_i]$ where $\var{proj}_i$ and~$\var{lift}_i$ are matrices respectively representing the projection map~$\var{al} \to \var{al}_i$ and a section of it. Modulo~$J$, the images of the $\var{lift}_i$ form a direct sum in~$\var{al}/J$, so that the images of~$1\in\var{al}_i$ under~$\var{lift}_i$ are central primitive idempotents of~$\var{al}/J$. The factors are sorted by increasing dimension, then increasing dimension of the center. This ensures that the ordering of the isomorphism classes of the factors is deterministic over finite fields, but not necessarily over~$\Q$. The library syntax is \fun{GEN}{algsimpledec}{GEN al, long maps}. \subsec{algsplit$(\var{al},\{v='x\})$}\kbdsidx{algsplit}\label{se:algsplit} If \var{al} is a table algebra over~$\F_p$ output by \tet{algtableinit} that represents a simple algebra, computes an isomorphism between \var{al} and a matrix algebra~$M_d(\F_{p^n})$ where~$N = nd^2$ is the dimension of~\var{al}. Returns a \typ{VEC}~$[map,mapi]$, where: \item \var{map} is a \typ{VEC} of~$N$ matrices of size~$d\times d$ with \typ{FFELT} coefficients using the variable~\var{v}, representing the image of the basis of~\var{al} under the isomorphism. \item \var{mapi} is an~$N\times N$ matrix with \typ{INT} coefficients, representing the image in \var{al} by the inverse isomorphism of the basis~$(b_i)$ of~$M_d(\F_p[\alpha])$ (where~$\alpha$ has degree~$n$ over~$\F_p$) defined as follows: let~$E_{i,j}$ be the matrix having all coefficients~$0$ except the~$(i,j)$-th coefficient equal to~$1$, and define $$b_i = E_{((i-1)/nd)+1, ((i-1)/n \mod d)+1} \alpha^{(i-1)\mod n}.$$ Example: \bprog ? al0 = alginit(nfinit(y^2+7), [-1,-1]); ? al = algtableinit(algmultable(al0), 3); \\ isomorphic to M_2(F_9) ? [map,mapi] = algsplit(al, 'a); ? x = [1,2,1,0,0,0,0,0]~; fx = map*x %4 = [2*a 0] [ 0 2] ? y = [0,0,0,0,1,0,0,1]~; fy = map*y %5 = [1 2*a] [2 a + 2] ? map*algmul(al,x,y) == fx*fy %6 = 1 ? map*mapi[,6] %7 = [0 0] [a 0] @eprog \misctitle{Warning} If~\var{al} is not simple, \kbd{algsplit(al)} can trigger an error, but can also run into an infinite loop. Example: \bprog ? al = alginit(nfinit(y),[-1,-1]); \\ ramified at 2 ? al2 = algtableinit(algmultable(al),2); \\ maximal order modulo 2 ? algsplit(al2); \\ not semisimple, infinite loop @eprog The library syntax is \fun{GEN}{algsplit}{GEN al, long v = -1} where \kbd{v} is a variable number. \subsec{algsplittingdata$(\var{al})$}\kbdsidx{algsplittingdata}\label{se:algsplittingdata} Given a central simple algebra \var{al} output by \tet{alginit} defined by a multiplication table over its center~$K$ (a number field), returns data stored to compute a splitting of \var{al} over an extension. This data is a \typ{VEC} \kbd{[t,Lbas,Lbasinv]} with $3$ components: \item an element $t$ of \var{al} such that $L=K(t)$ is a maximal subfield of \var{al}; \item a matrix \kbd{Lbas} expressing a $L$-basis of \var{al} (given an $L$-vector space structure by multiplication on the right) on the integral basis of \var{al}; \item a matrix \kbd{Lbasinv} expressing the integral basis of \var{al} on the previous $L$-basis. \bprog ? nf = nfinit(y^3-5); a = y; b = y^2; ? {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} ? {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} ? {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} ? mt = [matid(4), m_i, m_j, m_k]; ? A = alginit(nf,mt,'x); ? [t,Lb,Lbi] = algsplittingdata(A); ? t %8 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]~; ? matsize(Lb) %9 = [12, 2] ? matsize(Lbi) %10 = [2, 12] @eprog The library syntax is \fun{GEN}{algsplittingdata}{GEN al}. \subsec{algsplittingfield$(\var{al})$}\kbdsidx{algsplittingfield}\label{se:algsplittingfield} Given a central simple algebra \var{al} output by \tet{alginit}, returns an \kbd{rnf} structure: the splitting field of \var{al} that is stored in \var{al}, as a relative extension of the center. \bprog nf = nfinit(y^3-5); a = y; b = y^2; {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} mt = [matid(4), m_i, m_j, m_k]; A = alginit(nf,mt,'x); algsplittingfield(A).pol %8 = x^2 - y @eprog The library syntax is \fun{GEN}{algsplittingfield}{GEN al}. \subsec{algsqr$(\var{al},x)$}\kbdsidx{algsqr}\label{se:algsqr} Given an element $x$ in \var{al}, computes its square $x^2$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algsqr(A,[1,0,2,0]~) %2 = [-3, 0, 4, 0]~ @eprog Also accepts a square matrix with coefficients in \var{al}. The library syntax is \fun{GEN}{algsqr}{GEN al, GEN x}. \subsec{algsub$(\var{al},x,y)$}\kbdsidx{algsub}\label{se:algsub} Given two elements $x$ and $y$ in \var{al}, computes their difference $x-y$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algsub(A,[1,1,0,0]~,[1,0,1,0]~) %2 = [0, 1, -1, 0]~ @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algsub}{GEN al, GEN x, GEN y}. \subsec{algsubalg$(\var{al},B)$}\kbdsidx{algsubalg}\label{se:algsubalg} \var{al} being a table algebra output by \tet{algtableinit} and \var{B} being a basis of a subalgebra of~\var{al} represented by a matrix, computes an algebra~\var{al2} isomorphic to \var{B}. Returns $[\var{al2},\var{B2}]$ where \var{B2} is a possibly different basis of the subalgebra \var{al2}, with respect to which the multiplication table of \var{al2} is defined. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? B = algsubalg(A,[1,0; 0,0; 0,1]); ? algdim(A) %4 = 3 ? algdim(B[1]) %5 = 2 ? m = matcompanion(x^4+1); ? mt = [m^i | i <- [0..3]]; ? al = algtableinit(mt); ? B = [1,0;0,0;0,1/2;0,0]; ? al2 = algsubalg(al,B); ? algdim(al2[1]) ? al2[2] %13 = [1 0] [0 0] [0 1] [0 0] @eprog The library syntax is \fun{GEN}{algsubalg}{GEN al, GEN B}. \subsec{algtableinit$(\var{mt}, \{p=0\})$}\kbdsidx{algtableinit}\label{se:algtableinit} Initializes the associative algebra over $K = \Q$ ($p$ omitted) or $\F_p$ defined by the multiplication table \var{mt}. As a $K$-vector space, the algebra is generated by a basis $(e_1 = 1, e_2, \dots, e_n)$; the table is given as a \typ{VEC} of $n$ matrices in $M_n(K)$, giving the left multiplication by the basis elements $e_i$, in the given basis. Assumes that $e_1=1$, that $K e_1\oplus \dots\oplus K e_n]$ describes an associative algebra over $K$, and in the case $K=\Q$ that the multiplication table is integral. If the algebra is already known to be central and simple, then the case $K = \F_p$ is useless, and one should use \tet{alginit} directly. The point of this function is to input a finite dimensional $K$-algebra, so as to later compute its radical, then to split the quotient algebra as a product of simple algebras over $K$. The pari object representing such an algebra $A$ is a \typ{VEC} with the following data: \item The characteristic of $A$, accessed with \kbd{algchar}. \item The multiplication table of $A$, accessed with \kbd{algmultable}. \item The traces of the elements of the basis. A simple example: the $2\times 2$ upper triangular matrices over $\Q$, generated by $I_2$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, such that $a^2 = 0$, $ab = a$, $ba = 0$, $b^2 = b$: \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algradical(A) \\ = (a) %6 = [0] [1] [0] ? algcenter(A) \\ = (I_2) %7 = [1] [0] [0] @eprog The library syntax is \fun{GEN}{algtableinit}{GEN mt, GEN p = NULL}. \subsec{algtensor$(\var{al1},\var{al2},\{\var{maxord}=1\})$}\kbdsidx{algtensor}\label{se:algtensor} Given two algebras \var{al1} and \var{al2}, computes their tensor product. Computes a maximal order by default. Prevent this computation by setting $\var{maxord}=0$. Currently only implemented for cyclic algebras of coprime degree over the same center~$K$, and the tensor product is over~$K$. The library syntax is \fun{GEN}{algtensor}{GEN al1, GEN al2, long maxord}. \subsec{algtomatrix$(\var{al},x,\{\var{abs}=1\})$}\kbdsidx{algtomatrix}\label{se:algtomatrix} Given an element \var{x} in \var{al}, returns the image of \var{x} under a homomorphism to a matrix algebra. If \var{al} is a table algebra output by \kbd{algtableinit} or if~$abs=1$, returns the left multiplication table on the integral basis; if \var{al} is a central simple algebra and~$abs=0$, returns~$\phi(x)$ where~$\phi : A\otimes_K L \to M_d(L)$ (where $d$ is the degree of the algebra and $L$ is an extension of $L$ with~$[L:K]=d$) is an isomorphism stored in~\var{al}. Also accepts a square matrix with coefficients in~\var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algtomatrix(A,[0,0,0,2]~) %2 = [Mod(x + 1, x^2 + 1) Mod(Mod(1, y)*x + Mod(-1, y), x^2 + 1)] [Mod(x + 1, x^2 + 1) Mod(-x + 1, x^2 + 1)] ? algtomatrix(A,[0,1,0,0]~,1) %2 = [0 -1 1 0] [1 0 1 1] [0 0 1 1] [0 0 -2 -1] ? algtomatrix(A,[0,x]~,1) %3 = [-1 0 0 -1] [-1 0 1 0] [-1 -1 0 -1] [ 2 0 0 1] @eprog Also accepts matrices with coefficients in \var{al}. The library syntax is \fun{GEN}{algtomatrix}{GEN al, GEN x, long abs}. \subsec{algtrace$(\var{al},x,\{\var{abs}=0\})$}\kbdsidx{algtrace}\label{se:algtrace} Given an element \var{x} in \var{al}, computes its trace. If \var{al} is a table algebra output by \tet{algtableinit} or if $abs=1$, returns the absolute trace of \var{x}, which is an element of $\F_p$ or~$\Q$; if \var{al} is the output of \tet{alginit} and $abs=0$ (default), returns the reduced trace of \var{x}, which is an element of the center of \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algtrace(A,[5,0,0,1]~) %2 = 11 ? algtrace(A,[5,0,0,1]~,1) %3 = 22 ? nf = nfinit(y^2-5); ? A = alginit(nf,[-1,y]); ? a = [1+x+y,2*y]~*Mod(1,y^2-5)*Mod(1,x^2+1); ? t = algtrace(A,a) %7 = Mod(2*y + 2, y^2 - 5) ? algtrace(A,a,1) %8 = 8 ? algdegree(A)*nfelttrace(nf,t) %9 = 8 @eprog Also accepts a square matrix with coefficients in \var{al}. The library syntax is \fun{GEN}{algtrace}{GEN al, GEN x, long abs}. \subsec{algtype$(\var{al})$}\kbdsidx{algtype}\label{se:algtype} Given an algebra \var{al} output by \tet{alginit} or by \tet{algtableinit}, returns an integer indicating the type of algebra: \item $0$: not a valid algebra. \item $1$: table algebra output by \tet{algtableinit}. \item $2$: central simple algebra output by \tet{alginit} and represented by a multiplication table over its center. \item $3$: central simple algebra output by \tet{alginit} and represented by a cyclic algebra. \bprog ? algtype([]) %1 = 0 ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? algtype(A) %4 = 1 ? nf = nfinit(y^3-5); ? a = y; b = y^2; ? {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} ? {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} ? {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} ? mt = [matid(4), m_i, m_j, m_k]; ? A = alginit(nf,mt,'x); ? algtype(A) %12 = 2 ? A = alginit(nfinit(y), [-1,-1]); ? algtype(A) %14 = 3 @eprog The library syntax is \fun{long}{algtype}{GEN al}. \section{Elliptic curves} \subsec{Elliptic curve structures} %GPHELPskip An elliptic curve is given by a Weierstrass model\sidx{Weierstrass equation} $$ y^2+a_1xy+a_3y=x^3+a_2x^2+a_4x+a_6, $$ whose discriminant is non-zero. Affine points on \kbd{E} are represented as two-component vectors \kbd{[x,y]}; the point at infinity, i.e.~the identity element of the group law, is represented by the one-component vector \kbd{[0]}. Given a vector of coefficients $[a_1,a_2,a_3,a_4,a_6]$, the function \tet{ellinit} initializes and returns an \tev{ell} structure. An additional optional argument allows to specify the base field in case it cannot be inferred from the curve coefficients. This structure contains data needed by elliptic curve related functions, and is generally passed as a first argument. Expensive data are skipped on initialization: they will be dynamically computed when (and if) needed, and then inserted in the structure. The precise layout of the \tev{ell} structure is left undefined and should never be used directly. The following \idx{member functions} are available, depending on the underlying domain. \subsubsec{All domains} %GPHELPskip \item \tet{a1}, \tet{a2}, \tet{a3}, \tet{a4}, \tet{a6}: coefficients of the elliptic curve. \item \tet{b2}, \tet{b4}, \tet{b6}, \tet{b8}: $b$-invariants of the curve; in characteristic $\neq 2$, for $Y = 2y + a_1x+a3$, the curve equation becomes $$ Y^2 = 4 x^3 + b_2 x^2 + 2b_4 x + b_6 =: g(x). $$ \item \tet{c4}, \tet{c6}: $c$-invariants of the curve; in characteristic $\neq 2,3$, for $X = x + b_2/12$ and $Y = 2y + a_1x+a3$, the curve equation becomes $$ Y^2 = 4 X^3 - (c_4/12) X - (c_6/216). $$ \item \tet{disc}: discriminant of the curve. This is only required to be non-zero, not necessarily a unit. \item \tet{j}: $j$-invariant of the curve. \noindent These are used as follows: \bprog ? E = ellinit([0,0,0, a4,a6]); ? E.b4 %2 = 2*a4 ? E.disc %3 = -64*a4^3 - 432*a6^2 @eprog \subsubsec{Curves over $\C$} %GPHELPskip This in particular includes curves defined over $\Q$. All member functions in this section return data, as it is currently stored in the structure, if present; and otherwise compute it to the default accuracy, that was fixed \emph{at the time of ellinit} (via a \typ{REAL} $D$ domain argument, or \kbd{realprecision} by default). The function \tet{ellperiods} allows to recompute (and cache) the following data to \emph{current} \kbd{realprecision}. \item \tet{area}: volume of the complex lattice defining $E$. \item \tet{roots} is a vector whose three components contain the complex roots of the right hand side $g(x)$ of the attached $b$-model $Y^2 = g(x)$. If the roots are all real, they are ordered by decreasing value. If only one is real, it is the first component. \item \tet{omega}: $[\omega_1,\omega_2]$, periods forming a basis of the complex lattice defining $E$. The first component $\omega_1$ is the (positive) real period, in other words the integral of the N\'eron differential $dx/(2y+a_1x+a_3)$ over the connected component of the identity component of $E(\R)$. The second component $\omega_2$ is a complex period, such that $\tau=\dfrac{\omega_1}{\omega_2}$ belongs to Poincar\'e's half-plane (positive imaginary part); not necessarily to the standard fundamental domain. It is normalized so that $\Im(\omega_2) < 0$ and either $\Re(\omega_2) = 0$, when \kbd{E.disc > 0} ($E(\R)$ has two connected components), or $\Re(\omega_2) = \omega_1/2$ \item \tet{eta} is a row vector containing the quasi-periods $\eta_1$ and $\eta_2$ such that $\eta_i = 2\zeta(\omega_i/2)$, where $\zeta$ is the Weierstrass zeta function attached to the period lattice; see \tet{ellzeta}. In particular, the Legendre relation holds: $\eta_2\omega_1 - \eta_1\omega_2 = 2\pi i$. \misctitle{Warning} As for the orientation of the basis of the period lattice, beware that many sources use the inverse convention where $\omega_2/\omega_1$ has positive imaginary part and our $\omega_2$ is the negative of theirs. Our convention $\tau = \omega_1/\omega_2$ ensures that the action of $\text{PSL}_2$ is the natural one: $$[a,b;c,d]\cdot\tau = (a\tau+b)/(c\tau+d) = (a \omega_1 + b\omega_2)/(c\omega_1 + d\omega_2),$$ instead of a twisted one. (Our $tau$ is $-1/\tau$ in the above inverse convention.) \subsubsec{Curves over $\Q_p$} %GPHELPskip We advise to input a model defined over $\Q$ for such curves. In any case, if you input an approximate model with \typ{PADIC} coefficients, it will be replaced by a lift to $\Q$ (an exact model ``close'' to the one that was input) and all quantities will then be computed in terms of this lifted model. For the time being only curves with multiplicative reduction (split or non-split), i.e. $v_p(j) < 0$, are supported by non-trivial functions. In this case the curve is analytically isomorphic to $\bar{\Q}_p^*/q^\Z := E_q(\bar{\Q}_p)$, for some $p$-adic integer $q$ (the Tate period). In particular, we have $j(q) = j(E)$. \item \tet{p} is the residual characteristic \item \tet{roots} is a vector with a single component, equal to the $p$-adic root $e_1$ of the right hand side $g(x)$ of the attached $b$-model $Y^2 = g(x)$. The point $(e_1,0)$ corresponds to $-1 \in \bar{\Q}_p^*/q^\Z$ under the Tate parametrization. \item \tet{tate} returns $[u^2,u,q,[a,b],L, Ei]$ in the notation of Henniart-Mestre (CRAS t. 308, p.~391--395, 1989): $q$ is as above, $u\in \Q_p(\sqrt{-c_6})$ is such that $\phi^* dx/(2y + a_1x+a3) = u dt/t$, where $\phi: E_q\to E$ is an isomorphism (well defined up to sign) and $dt/t$ is the canonical invariant differential on the Tate curve; $u^2\in\Q_p$ does not depend on $\phi$. (Technicality: if $u\not\in\Q_p$, it is stored as a quadratic \typ{POLMOD}.) The parameters $[a,b]$ satisfy $4u^2 b \cdot \text{agm}(\sqrt{a/b},1)^2 = 1$ as in Theorem~2 (\emph{loc.~cit.}). \kbd{Ei} describes the sequence of 2-isogenous curves (with kernel generated by $[0,0]$) $E_i: y^2=x(x+A_i)(x+A_i-B_i)$ converging quadratically towards the singular curve $E_\infty$. Finally, $L$ is Mazur-Tate-Teitelbaum's ${\cal L}$-invariant, equal to $\log_p q / v_p(q)$. \subsubsec{Curves over $\F_q$} %GPHELPskip \item \tet{p} is the characteristic of $\F_q$. \item \tet{no} is $\#E(\F_q)$. \item \tet{cyc} gives the cycle structure of $E(\F_q)$. \item \tet{gen} returns the generators of $E(\F_q)$. \item \tet{group} returns $[\kbd{no},\kbd{cyc},\kbd{gen}]$, i.e. $E(\F_q)$ as an abelian group structure. \subsubsec{Curves over $\Q$} %GPHELPskip All functions should return a correct result, whether the model is minimal or not, but it is a good idea to stick to minimal models whenever $\gcd(c_4,c_6)$ is easy to factor (minor speed-up). The construction \bprog E = ellminimalmodel(E0, &v) @eprog\noindent replaces the original model $E_0$ by a minimal model $E$, and the variable change $v$ allows to go between the two models: \bprog ellchangepoint(P0, v) ellchangepointinv(P, v) @eprog\noindent respectively map the point $P_0$ on $E_0$ to its image on $E$, and the point $P$ on $E$ to its pre-image on $E_0$. A few routines --- namely \tet{ellgenerators}, \tet{ellidentify}, \tet{ellsearch}, \tet{forell} --- require the optional package \tet{elldata} (John Cremona's database) to be installed. In that case, the function \tet{ellinit} will allow alternative inputs, e.g.~\kbd{ellinit("11a1")}. Functions using this package need to load chunks of a large database in memory and require at least 2MB stack to avoid stack overflows. \item \tet{gen} returns the generators of $E(\Q)$, if known (from John Cremona's database) \subsubsec{Curves over number fields} %GPHELPskip \item \tet{nf} return the \var{nf} structure attached to the number field over which $E$ is defined. \item \tet{bnf} return the \var{bnf} structure attached to the number field over which $E$ is defined or raise an error (if only an \var{nf} is available). \item \tet{omega}, \tet{eta}, \tet{area}: vectors of complex periods, quasi-periods and lattice areas attached to the complex embeddings of $E$, in the same order as \kbd{E.nf.roots}. \subsec{Reduction} %GPHELPskip Let $E$ be a curve defined over $\Q_p$ given by a $p$-integral model; if the curve has good reduction at $p$, we may define its reduction $\tilde{E}$ over the finite field $\F_p$: \bprog ? E = ellinit([-3,1], O(5^10)); \\ @com $E/\Q_5$ ? Et = ellinit(E, 5) ? ellcard(Et) \\ @com $\tilde{E}/\F_5$ has 7 points %3 = 7 ? ellinit(E, 7) *** at top-level: ellinit(E,7) *** ^------------ *** ellinit: inconsistent moduli in ellinit: 5 != 7 @eprog\noindent Likewise, if a curve is defined over a number field $K$ and $\goth{p}$ is a maximal ideal with finite residue field $\F_q$, we define the reduction $\tilde{E}/\F_q$ provided $E$ has good reduction at $\goth{p}$. $E/\Q$ is an important special case: \bprog ? E = ellinit([-3,1]); ? factor(E.disc) %2 = [2 4] [3 4] ? Et = ellinit(E, 5); ? ellcard(Et) \\ @com $\tilde{E} / \F_5$ has 7 points %4 = 7 ? ellinit(E, 3) \\ bad reduction at 3 %5 = [] @eprog\noindent General number fields are similar: \bprog ? K = nfinit(x^2+1); E = ellinit([x,x+1], K); ? idealfactor(K, E.disc) \\ three primes of bad reduction %2 = [ [2, [1, 1]~, 2, 1, [1, -1; 1, 1]] 10] [ [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] 2] [[5, [2, 1]~, 1, 1, [-2, -1; 1, -2]] 2] ? P = idealprimedec(K, 3); \\ a prime of good reduction ? idealnorm(K, P) %4 = 9 ? Et = ellinit(E, P); ? ellcard(Et) \\ @com $\tilde{E} / \F_9$ has 4 points %6 = 4 @eprog\noindent If the model is not locally minimal at $\goth{p}$, the above will fail: \kbd{elllocalred} and \kbd{ellchangecurve} allow to reduce to that case. Some functions such as \kbd{ellap}, \kbd{ellcard}, \kbd{ellgroup} and \kbd{ellissupersingular} even implicitly replace the given equation by a local minimal model and consider the group of non-singular points $\tilde{E}^{ns}$ so they make sense even when the curve has bad reduction. \subsec{ellL1$(E, \{r = 0\})$}\kbdsidx{ellL1}\label{se:ellL1} Returns the value at $s=1$ of the derivative of order $r$ of the $L$-function of the elliptic curve $E$. \bprog ? E = ellinit("11a1"); \\ order of vanishing is 0 ? ellL1(E) %2 = 0.2538418608559106843377589233 ? E = ellinit("389a1"); \\ order of vanishing is 2 ? ellL1(E) %4 = -5.384067311837218089235032414 E-29 ? ellL1(E, 1) %5 = 0 ? ellL1(E, 2) %6 = 1.518633000576853540460385214 @eprog\noindent The main use of this function, after computing at \emph{low} accuracy the order of vanishing using \tet{ellanalyticrank}, is to compute the leading term at \emph{high} accuracy to check (or use) the Birch and Swinnerton-Dyer conjecture: \bprog ? \p18 realprecision = 18 significant digits ? E = ellinit("5077a1"); ellanalyticrank(E) time = 8 ms. %1 = [3, 10.3910994007158041] ? \p200 realprecision = 202 significant digits (200 digits displayed) ? ellL1(E, 3) time = 104 ms. %3 = 10.3910994007158041387518505103609170697263563756570092797@com$[\dots]$ @eprog The library syntax is \fun{GEN}{ellL1_bitprec}{GEN E, long r, long bitprec}. \subsec{elladd$(E,\var{z1},\var{z2})$}\kbdsidx{elladd}\label{se:elladd} Sum of the points $z1$ and $z2$ on the elliptic curve corresponding to $E$. The library syntax is \fun{GEN}{elladd}{GEN E, GEN z1, GEN z2}. \subsec{ellak$(E,n)$}\kbdsidx{ellak}\label{se:ellak} Computes the coefficient $a_n$ of the $L$-function of the elliptic curve $E/\Q$, i.e.~coefficients of a newform of weight 2 by the modularity theorem (\idx{Taniyama-Shimura-Weil conjecture}). $E$ must be an \kbd{ell} structure over $\Q$ as output by \kbd{ellinit}. $E$ must be given by an integral model, not necessarily minimal, although a minimal model will make the function faster. \bprog ? E = ellinit([1,-1,0,4,3]); ? ellak(E, 10) %2 = -3 ? e = ellchangecurve(E, [1/5,0,0,0]); \\ made not minimal at 5 ? ellak(e, 10) \\ wasteful but works %3 = -3 ? E = ellminimalmodel(e); \\ now minimal ? ellak(E, 5) %5 = -3 @eprog\noindent If the model is not minimal at a number of bad primes, then the function will be slower on those $n$ divisible by the bad primes. The speed should be comparable for other $n$: \bprog ? for(i=1,10^6, ellak(E,5)) time = 699 ms. ? for(i=1,10^6, ellak(e,5)) \\ 5 is bad, markedly slower time = 1,079 ms. ? for(i=1,10^5,ellak(E,5*i)) time = 1,477 ms. ? for(i=1,10^5,ellak(e,5*i)) \\ still slower but not so much on average time = 1,569 ms. @eprog The library syntax is \fun{GEN}{akell}{GEN E, GEN n}. \subsec{ellan$(E,n)$}\kbdsidx{ellan}\label{se:ellan} Computes the vector of the first $n$ Fourier coefficients $a_k$ corresponding to the elliptic curve $E$ defined over a number field. If $E$ is defined over $\Q$, the curve may be given by an arbitrary model, not necessarily minimal, although a minimal model will make the function faster. Over a more general number field, the model must be locally minimal at all primes above $2$ and $3$. The library syntax is \fun{GEN}{ellan}{GEN E, long n}. Also available is \fun{GEN}{ellanQ_zv}{GEN e, long n}, which returns a \typ{VECSMALL} instead of a \typ{VEC}, saving on memory. \subsec{ellanalyticrank$(E, \{\var{eps}\})$}\kbdsidx{ellanalyticrank}\label{se:ellanalyticrank} Returns the order of vanishing at $s=1$ of the $L$-function of the elliptic curve $E$ and the value of the first non-zero derivative. To determine this order, it is assumed that any value less than \kbd{eps} is zero. If \kbd{eps} is omitted, $2^{-b/2}$ is used, where $b$ is the current bit precision. \bprog ? E = ellinit("11a1"); \\ rank 0 ? ellanalyticrank(E) %2 = [0, 0.2538418608559106843377589233] ? E = ellinit("37a1"); \\ rank 1 ? ellanalyticrank(E) %4 = [1, 0.3059997738340523018204836835] ? E = ellinit("389a1"); \\ rank 2 ? ellanalyticrank(E) %6 = [2, 1.518633000576853540460385214] ? E = ellinit("5077a1"); \\ rank 3 ? ellanalyticrank(E) %8 = [3, 10.39109940071580413875185035] @eprog The library syntax is \fun{GEN}{ellanalyticrank_bitprec}{GEN E, GEN eps = NULL, long bitprec}. \subsec{ellap$(E,\{p\})$}\kbdsidx{ellap}\label{se:ellap} Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached to an elliptic curve $E/K$. If the field $K = \F_q$ is finite, return the trace of Frobenius $t$, defined by the equation $\#E(\F_q) = q+1 - t$. For other fields of definition and $p$ defining a finite residue field $\F_q$, return the trace of Frobenius for the reduction of $E$: the argument $p$ is best left omitted if $K = \Q_\ell$ (else we must have $p = \ell$) and must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) with residue field $\F_q$ otherwise. The equation need not be minimal or even integral at $p$; of course, a minimal model will be more efficient. For a number field $K$, the trace of Frobenius is the $a_p$ coefficient in the Euler product defining the curve $L$-series, whence the function name: $$L(E/K,s) = \prod_{\text{bad}\ p} (1-a_p (Np)^{-s})^{-1} \prod_{\text{good}\ p} (1-a_p (Np)^{-s} + (Np)^{1-2s})^{-1}. $$ When the characteristic of the finite field is large, the availability of the \kbd{seadata} package will speed up the computation. \bprog ? E = ellinit([0,1]); \\ y^2 = x^3 + 0.x + 1, defined over Q ? ellap(E, 7) \\ 7 necessary here %2 = -4 \\ #E(F_7) = 7+1-(-4) = 12 ? ellcard(E, 7) %3 = 12 \\ OK ? E = ellinit([0,1], 11); \\ defined over F_11 ? ellap(E) \\ no need to repeat 11 %4 = 0 ? ellap(E, 11) \\ ... but it also works %5 = 0 ? ellgroup(E, 13) \\ ouch, inconsistent input! *** at top-level: ellap(E,13) *** ^----------- *** ellap: inconsistent moduli in Rg_to_Fp: 11 13 ? a = ffgen(ffinit(11,3), 'a); \\ defines F_q := F_{11^3} ? E = ellinit([a+1,a]); \\ y^2 = x^3 + (a+1)x + a, defined over F_q ? ellap(E) %8 = -3 @eprog If the curve is defined over a more general number field than $\Q$, the maximal ideal $p$ must be explicitly given in \kbd{idealprimedec} format. There is no assumption of local minimality at $p$. \bprog ? K = nfinit(a^2+1); E = ellinit([1+a,0,1,0,0], K); ? fa = idealfactor(K, E.disc) %2 = [ [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] 1] [[13, [5, 1]~, 1, 1, [-5, -1; 1, -5]] 2] ? ellap(E, fa[1,1]) %3 = -1 \\ non-split multiplicative reduction ? ellap(E, fa[2,1]) %4 = 1 \\ split multiplicative reduction ? P17 = idealprimedec(K,17)[1]; ? ellap(E, P17) %6 = 6 \\ good reduction ? E2 = ellchangecurve(E, [17,0,0,0]); ? ellap(E2, P17) %8 = 6 \\ same, starting from a non-miminal model ? P3 = idealprimedec(K,3)[1]; ? ellap(E, P3) \\ OK: E is minimal at P3 %10 = -2 ? E3 = ellchangecurve(E, [3,0,0,0]); ? ellap(E3, P3) \\ not integral at P3 *** at top-level: ellap(E3,P3) *** ^------------ *** ellap: impossible inverse in Rg_to_ff: Mod(0, 3). @eprog \misctitle{Algorithms used} If $E/\F_q$ has CM by a principal imaginary quadratic order we use a fast explicit formula (involving essentially Kronecker symbols and Cornacchia's algorithm), in $O(\log q)^2$ bit operations. Otherwise, we use Shanks-Mestre's baby-step/giant-step method, which runs in time $\tilde{O}(q^{1/4})$ using $\tilde{O}(q^{1/4})$ storage, hence becomes unreasonable when $q$ has about 30~digits. Above this range, the \tet{SEA} algorithm becomes available, heuristically in $\tilde{O}(\log q)^4$, and primes of the order of 200~digits become feasible. In small characteristic we use Mestre's (p=2), Kohel's (p=3,5,7,13), Satoh-Harley (all in $\tilde{O}(p^{2}\*n^2)$) or Kedlaya's (in $\tilde{O}(p\*n^3)$) algorithms. The library syntax is \fun{GEN}{ellap}{GEN E, GEN p = NULL}. \subsec{ellbil$(E,\var{z1},\var{z2})$}\kbdsidx{ellbil}\label{se:ellbil} Deprecated alias for \kbd{ellheight(E,P,Q)}. The library syntax is \fun{GEN}{bilhell}{GEN E, GEN z1, GEN z2, long prec}. \subsec{ellbsd$(E)$}\kbdsidx{ellbsd}\label{se:ellbsd} The object $E$ being an elliptic curve over a number field, returns a real number $c$ such that the BSD conjecture predicts that $L_{E}^{(r)}(1)/r! = c\*R\*S$ where $r$ is the rank, $R$ the regulator and $S$ the cardinal of the Tate-Shafarevich group. \bprog ? e = ellinit([0,-1,1,-10,-20]); \\ rank 0 ? ellbsd(e) %2 = 0.25384186085591068433775892335090946105 ? lfun(e,1) %3 = 0.25384186085591068433775892335090946104 ? e = ellinit([0,0,1,-1,0]); \\ rank 1 ? P = ellheegner(e); ? ellbsd(e)*ellheight(e,P) %6 = 0.30599977383405230182048368332167647445 ? lfun(e,1,1) %7 = 0.30599977383405230182048368332167647445 ? e = ellinit([1+a,0,1,0,0],nfinit(a^2+1)); \\ rank 0 ? ellbsd(e) %9 = 0.42521832235345764503001271536611593310 ? lfun(e,1) %10 = 0.42521832235345764503001271536611593309 @eprog The library syntax is \fun{GEN}{ellbsd}{GEN E, long prec}. \subsec{ellcard$(E,\{p\})$}\kbdsidx{ellcard}\label{se:ellcard} Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached to an elliptic curve $E/K$. If $K = \F_q$ is finite, return the order of the group $E(\F_q)$. \bprog ? E = ellinit([-3,1], 5); ellcard(E) %1 = 7 ? t = ffgen(3^5,'t); E = ellinit([t,t^2+1]); ellcard(E) %2 = 217 @eprog\noindent For other fields of definition and $p$ defining a finite residue field $\F_q$, return the order of the reduction of $E$: the argument $p$ is best left omitted if $K = \Q_\ell$ (else we must have $p = \ell$) and must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) with residue field $\F_q$ otherwise. The equation need not be minimal or even integral at $p$; of course, a minimal model will be more efficient. The function considers the group of non-singular points of the reduction of a minimal model of the curve at $p$, so also makes sense when the curve has bad reduction. \bprog ? E = ellinit([-3,1]); ? factor(E.disc) %2 = [2 4] [3 4] ? ellcard(E, 5) \\ as above ! %3 = 7 ? ellcard(E, 2) \\ additive reduction %4 = 2 @eprog When the characteristic of the finite field is large, the availability of the \kbd{seadata} package will speed the computation. See also \tet{ellap} for the list of implemented algorithms. The library syntax is \fun{GEN}{ellcard}{GEN E, GEN p = NULL}. Also available is \fun{GEN}{ellcard}{GEN E, GEN p} where $p$ is not \kbd{NULL}. \subsec{ellchangecurve$(E,v)$}\kbdsidx{ellchangecurve}\label{se:ellchangecurve} Changes the data for the elliptic curve $E$ by changing the coordinates using the vector \kbd{v=[u,r,s,t]}, i.e.~if $x'$ and $y'$ are the new coordinates, then $x=u^2x'+r$, $y=u^3y'+su^2x'+t$. $E$ must be an \kbd{ell} structure as output by \kbd{ellinit}. The special case $v = 1$ is also used instead of $[1,0,0,0]$ to denote the trivial coordinate change. The library syntax is \fun{GEN}{ellchangecurve}{GEN E, GEN v}. \subsec{ellchangepoint$(x,v)$}\kbdsidx{ellchangepoint}\label{se:ellchangepoint} Changes the coordinates of the point or vector of points $x$ using the vector \kbd{v=[u,r,s,t]}, i.e.~if $x'$ and $y'$ are the new coordinates, then $x=u^2x'+r$, $y=u^3y'+su^2x'+t$ (see also \kbd{ellchangecurve}). \bprog ? E0 = ellinit([1,1]); P0 = [0,1]; v = [1,2,3,4]; ? E = ellchangecurve(E0, v); ? P = ellchangepoint(P0,v) %3 = [-2, 3] ? ellisoncurve(E, P) %4 = 1 ? ellchangepointinv(P,v) %5 = [0, 1] @eprog The library syntax is \fun{GEN}{ellchangepoint}{GEN x, GEN v}. The reciprocal function \fun{GEN}{ellchangepointinv}{GEN x, GEN ch} inverts the coordinate change. \subsec{ellchangepointinv$(x,v)$}\kbdsidx{ellchangepointinv}\label{se:ellchangepointinv} Changes the coordinates of the point or vector of points $x$ using the inverse of the isomorphism attached to \kbd{v=[u,r,s,t]}, i.e.~if $x'$ and $y'$ are the old coordinates, then $x=u^2x'+r$, $y=u^3y'+su^2x'+t$ (inverse of \kbd{ellchangepoint}). \bprog ? E0 = ellinit([1,1]); P0 = [0,1]; v = [1,2,3,4]; ? E = ellchangecurve(E0, v); ? P = ellchangepoint(P0,v) %3 = [-2, 3] ? ellisoncurve(E, P) %4 = 1 ? ellchangepointinv(P,v) %5 = [0, 1] \\ we get back P0 @eprog The library syntax is \fun{GEN}{ellchangepointinv}{GEN x, GEN v}. \subsec{ellconvertname$(\var{name})$}\kbdsidx{ellconvertname}\label{se:ellconvertname} Converts an elliptic curve name, as found in the \tet{elldata} database, from a string to a triplet $[\var{conductor}, \var{isogeny class}, \var{index}]$. It will also convert a triplet back to a curve name. Examples: \bprog ? ellconvertname("123b1") %1 = [123, 1, 1] ? ellconvertname(%) %2 = "123b1" @eprog The library syntax is \fun{GEN}{ellconvertname}{GEN name}. \subsec{elldivpol$(E,n,\{v='x\})$}\kbdsidx{elldivpol}\label{se:elldivpol} $n$-division polynomial $f_n$ for the curve $E$ in the variable $v$. In standard notation, for any affine point $P = (X,Y)$ on the curve, we have $$[n]P = (\phi_n(P)\psi_n(P) : \omega_n(P) : \psi_n(P)^3)$$ for some polynomials $\phi_n,\omega_n,\psi_n$ in $\Z[a_1,a_2,a_3,a_4,a_6][X,Y]$. We have $f_n(X) = \psi_n(X)$ for $n$ odd, and $f_n(X) = \psi_n(X,Y) (2Y + a_1X+a_3)$ for $n$ even. We have $$ f_1 = 1,\quad f_2 = 4X^3 + b_2X^2 + 2b_4 X + b_6, \quad f_3 = 3 X^4 + b_2 X^3 + 3b_4 X^2 + 3 b_6 X + b8, $$ $$ f_4 = f_2(2X^6 + b_2 X^5 + 5b_4 X^4 + 10 b_6 X^3 + 10 b_8 X^2 + (b_2b_8-b_4b_6)X + (b_8b_4 - b_6^2)), \dots $$ For $n \geq 2$, the roots of $f_n$ are the $X$-coordinates of points in $E[n]$. The library syntax is \fun{GEN}{elldivpol}{GEN E, long n, long v = -1} where \kbd{v} is a variable number. \subsec{elleisnum$(w,k,\{\fl=0\})$}\kbdsidx{elleisnum}\label{se:elleisnum} $k$ being an even positive integer, computes the numerical value of the Eisenstein series of weight $k$ at the lattice $w$, as given by \tet{ellperiods}, namely $$ (2i \pi/\omega_2)^k \Big(1 + 2/\zeta(1-k) \sum_{n\geq 1} n^{k-1}q^n / (1-q^n)\Big), $$ where $q = \exp(2i\pi \tau)$ and $\tau:=\omega_1/\omega_2$ belongs to the complex upper half-plane. It is also possible to directly input $w = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit}. \bprog ? w = ellperiods([1,I]); ? elleisnum(w, 4) %2 = 2268.8726415508062275167367584190557607 ? elleisnum(w, 6) %3 = -3.977978632282564763 E-33 ? E = ellinit([1, 0]); ? elleisnum(E, 4, 1) %5 = -47.999999999999999999999999999999999998 @eprog When \fl\ is non-zero and $k=4$ or 6, returns the elliptic invariants $g_2$ or $g_3$, such that $$y^2 = 4x^3 - g_2 x - g_3$$ is a Weierstrass equation for $E$. The library syntax is \fun{GEN}{elleisnum}{GEN w, long k, long flag, long prec}. \subsec{elleta$(w)$}\kbdsidx{elleta}\label{se:elleta} Returns the quasi-periods $[\eta_1,\eta_2]$ attached to the lattice basis $\var{w} = [\omega_1, \omega_2]$. Alternatively, \var{w} can be an elliptic curve $E$ as output by \kbd{ellinit}, in which case, the quasi periods attached to the period lattice basis \kbd{$E$.omega} (namely, \kbd{$E$.eta}) are returned. \bprog ? elleta([1, I]) %1 = [3.141592653589793238462643383, 9.424777960769379715387930149*I] @eprog The library syntax is \fun{GEN}{elleta}{GEN w, long prec}. \subsec{ellformaldifferential$(E, \{n=\var{seriesprecision}\}, \{t = 'x\})$}\kbdsidx{ellformaldifferential}\label{se:ellformaldifferential} Let $\omega := dx / (2y+a_1x+a_3)$ be the invariant differential form attached to the model $E$ of some elliptic curve (\kbd{ellinit} form), and $\eta := x(t)\omega$. Return $n$ terms (\tet{seriesprecision} by default) of $f(t),g(t)$ two power series in the formal parameter $t=-x/y$ such that $\omega = f(t) dt$, $\eta = g(t) dt$: $$f(t) = 1+a_1 t + (a_1^2 + a_2) t^2 + \dots,\quad g(t) = t^{-2} +\dots $$ \bprog ? E = ellinit([-1,1/4]); [f,g] = ellformaldifferential(E,7,'t); ? f %2 = 1 - 2*t^4 + 3/4*t^6 + O(t^7) ? g %3 = t^-2 - t^2 + 1/2*t^4 + O(t^5) @eprog The library syntax is \fun{GEN}{ellformaldifferential}{GEN E, long precdl, long n = -1} where \kbd{n} is a variable number. \subsec{ellformalexp$(E, \{n = \var{seriesprecision}\}, \{z = 'x\})$}\kbdsidx{ellformalexp}\label{se:ellformalexp} The elliptic formal exponential \kbd{Exp} attached to $E$ is the isomorphism from the formal additive law to the formal group of $E$. It is normalized so as to be the inverse of the elliptic logarithm (see \tet{ellformallog}): $\kbd{Exp} \circ L = \Id$. Return $n$ terms of this power series: \bprog ? E=ellinit([-1,1/4]); Exp = ellformalexp(E,10,'z) %1 = z + 2/5*z^5 - 3/28*z^7 + 2/15*z^9 + O(z^11) ? L = ellformallog(E,10,'t); ? subst(Exp,z,L) %3 = t + O(t^11) @eprog The library syntax is \fun{GEN}{ellformalexp}{GEN E, long precdl, long n = -1} where \kbd{n} is a variable number. \subsec{ellformallog$(E, \{n = \var{seriesprecision}\}, \{v = 'x\})$}\kbdsidx{ellformallog}\label{se:ellformallog} The formal elliptic logarithm is a series $L$ in $t K[[t]]$ such that $d L = \omega = dx / (2y + a_1x + a_3)$, the canonical invariant differential attached to the model $E$. It gives an isomorphism from the formal group of $E$ to the additive formal group. \bprog ? E = ellinit([-1,1/4]); L = ellformallog(E, 9, 't) %1 = t - 2/5*t^5 + 3/28*t^7 + 2/3*t^9 + O(t^10) ? [f,g] = ellformaldifferential(E,8,'t); ? L' - f %3 = O(t^8) @eprog The library syntax is \fun{GEN}{ellformallog}{GEN E, long precdl, long n = -1} where \kbd{n} is a variable number. \subsec{ellformalpoint$(E, \{n = \var{seriesprecision}\}, \{v = 'x\})$}\kbdsidx{ellformalpoint}\label{se:ellformalpoint} If $E$ is an elliptic curve, return the coordinates $x(t), y(t)$ in the formal group of the elliptic curve $E$ in the formal parameter $t = -x/y$ at $\infty$: $$ x = t^{-2} -a_1 t^{-1} - a_2 - a_3 t + \dots $$ $$ y = - t^{-3} -a_1 t^{-2} - a_2t^{-1} -a_3 + \dots $$ Return $n$ terms (\tet{seriesprecision} by default) of these two power series, whose coefficients are in $\Z[a_1,a_2,a_3,a_4,a_6]$. \bprog ? E = ellinit([0,0,1,-1,0]); [x,y] = ellformalpoint(E,8,'t); ? x %2 = t^-2 - t + t^2 - t^4 + 2*t^5 + O(t^6) ? y %3 = -t^-3 + 1 - t + t^3 - 2*t^4 + O(t^5) ? E = ellinit([0,1/2]); ellformalpoint(E,7) %4 = [x^-2 - 1/2*x^4 + O(x^5), -x^-3 + 1/2*x^3 + O(x^4)] @eprog The library syntax is \fun{GEN}{ellformalpoint}{GEN E, long precdl, long n = -1} where \kbd{n} is a variable number. \subsec{ellformalw$(E, \{n = \var{seriesprecision}\}, \{t = 'x\})$}\kbdsidx{ellformalw}\label{se:ellformalw} Return the formal power series $w$ attached to the elliptic curve $E$, in the variable $t$: $$ w(t) = t^3 + a_1 t^4 + (a_2 + a_1^2) t^5 + \cdots + O(t^{n+3}),$$ which is the formal expansion of $-1/y$ in the formal parameter $t := -x/y$ at $\infty$ (take $n = \tet{seriesprecision}$ if $n$ is omitted). The coefficients of $w$ belong to $\Z[a_1,a_2,a_3,a_4,a_6]$. \bprog ? E=ellinit([3,2,-4,-2,5]); ellformalw(E, 5, 't) %1 = t^3 + 3*t^4 + 11*t^5 + 35*t^6 + 101*t^7 + O(t^8) @eprog The library syntax is \fun{GEN}{ellformalw}{GEN E, long precdl, long n = -1} where \kbd{n} is a variable number. \subsec{ellfromeqn$(P)$}\kbdsidx{ellfromeqn}\label{se:ellfromeqn} Given a genus $1$ plane curve, defined by the affine equation $f(x,y) = 0$, return the coefficients $[a_1,a_2,a_3,a_4,a_6]$ of a Weierstrass equation for its Jacobian. This allows to recover a Weierstrass model for an elliptic curve given by a general plane cubic or by a binary quartic or biquadratic model. The function implements the $f \mapsto f^*$ formulae of Artin, Tate and Villegas (Advances in Math. 198 (2005), pp. 366--382). In the example below, the function is used to convert between twisted Edwards coordinates and Weierstrass coordinates. \bprog ? e = ellfromeqn(a*x^2+y^2 - (1+d*x^2*y^2)) %1 = [0, -a - d, 0, -4*d*a, 4*d*a^2 + 4*d^2*a] ? E = ellinit(ellfromeqn(y^2-x^2 - 1 +(121665/121666*x^2*y^2)),2^255-19); ? isprime(ellcard(E) / 8) %3 = 1 @eprog The elliptic curve attached to the sum of two cubes is given by \bprog ? ellfromeqn(x^3+y^3 - a) %1 = [0, 0, -9*a, 0, -27*a^2] @eprog \misctitle{Congruent number problem:} Let $n$ be an integer, if $a^2+b^2=c^2$ and $a\*b=2\*n$, then by substituting $b$ by $2\*n/a$ in the first equation, we get $((a^2+(2\*n/a)^2)-c^2)\*a^2 = 0$. We set $x=a$, $y=a\*c$. \bprog ? En = ellfromeqn((x^2 + (2*n/x)^2 - (y/x)^2)*x^2) %1 = [0, 0, 0, -16*n^2, 0] @eprog For example $23$ is congruent since the curve has a point of infinite order, namely: \bprog ? ellheegner( ellinit(subst(En, n, 23)) ) %2 = [168100/289, 68053440/4913] @eprog The library syntax is \fun{GEN}{ellfromeqn}{GEN P}. \subsec{ellfromj$(j)$}\kbdsidx{ellfromj}\label{se:ellfromj} Returns the coefficients $[a_1,a_2,a_3,a_4,a_6]$ of a fixed elliptic curve with $j$-invariant $j$. The library syntax is \fun{GEN}{ellfromj}{GEN j}. \subsec{ellgenerators$(E)$}\kbdsidx{ellgenerators}\label{se:ellgenerators} If $E$ is an elliptic curve over the rationals, return a $\Z$-basis of the free part of the \idx{Mordell-Weil group} attached to $E$. This relies on the \tet{elldata} database being installed and referencing the curve, and so is only available for curves over $\Z$ of small conductors. If $E$ is an elliptic curve over a finite field $\F_q$ as output by \tet{ellinit}, return a minimal set of generators for the group $E(\F_q)$. \misctitle{Caution} when the group is not cyclic, of shape $\Z/d_1\Z \times \Z/d_2\Z$ with $d_2\mid d_1$, the points $[P,Q]$ returned by ellgenerators need not have order $d_1$ and $d_2$: it is true that $P$ has order $d_1$, but we only know that $Q$ is a generator of $E(\F_q)/

$ and that the Weil pairing $w(P,Q)$ has order $d_2$, see \kbd{??ellgroup}. If you need generators $[P,R]$ with $R$ of order $d_2$, find $x$ such that $R = Q-[x]P$ has order $d_2$ by solving the discrete logarithm problem $[d_2]Q = [x]([d_2]P)$ in a cyclic group of order $d_1/d_2$. This will be very expensive if $d_1/d_2$ has a large prime factor. The library syntax is \fun{GEN}{ellgenerators}{GEN E}. \subsec{ellglobalred$(E)$}\kbdsidx{ellglobalred}\label{se:ellglobalred} Let $E$ be an \kbd{ell} structure as output by \kbd{ellinit} attached to an elliptic curve defined over a number field. This function calculates the arithmetic conductor and the global \idx{Tamagawa number} $c$. The result $[N,v,c,F,L]$ is slightly different if $E$ is defined over $\Q$ (domain $D = 1$ in \kbd{ellinit}) or over a number field (domain $D$ is a number field structure, including \kbd{nfinit(x)} representing $\Q$ !): \item $N$ is the arithmetic conductor of the curve, \item $v$ is an obsolete field, left in place for backward compatibility. If $E$ is defined over $\Q$, $v$ gives the coordinate change for $E$ to the standard minimal integral model (\tet{ellminimalmodel} provides it in a cheaper way); if $E$ is defined over another number field, $v$ gives a coordinate change to an integral model (\tet{ellintegralmodel} provides it in a cheaper way). \item $c$ is the product of the local Tamagawa numbers $c_p$, a quantity which enters in the \idx{Birch and Swinnerton-Dyer conjecture}, \item $F$ is the factorization of $N$, \item $L$ is a vector, whose $i$-th entry contains the local data at the $i$-th prime ideal divisor of $N$, i.e. \kbd{L[i] = elllocalred(E,F[i,1])}. If $E$ is defined over $\Q$, the local coordinate change has been deleted and replaced by a 0; if $E$ is defined over another number field the local coordinate change to a local minimal model is given relative to the integral model afforded by $v$ (so either start from an integral model so that $v$ be trivial, or apply $v$ first). The library syntax is \fun{GEN}{ellglobalred}{GEN E}. \subsec{ellgroup$(E,\{p\},\{\fl\})$}\kbdsidx{ellgroup}\label{se:ellgroup} Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached to an elliptic curve $E/K$. We first describle the function when the field $K = \F_q$ is finite, it computes the structure of the finite abelian group $E(\F_q)$: \item if $\fl = 0$, return the structure $[]$ (trivial group) or $[d_1]$ (non-trivial cyclic group) or $[d_1,d_2]$ (non-cyclic group) of $E(\F_q) \sim \Z/d_1\Z \times \Z/d_2\Z$, with $d_2\mid d_1$. \item if $\fl = 1$, return a triple $[h,\var{cyc},\var{gen}]$, where $h$ is the curve cardinality, \var{cyc} gives the group structure as a product of cyclic groups (as per $\fl = 0$). More precisely, if $d_2 > 1$, the output is $[d_1d_2, [d_1,d_2], [P,Q]]$ where $P$ is of order $d_1$ and $[P,Q]$ generates the curve. \misctitle{Caution} It is not guaranteed that $Q$ has order $d_2$, which in the worst case requires an expensive discrete log computation. Only that \kbd{ellweilpairing}$(E, P, Q, d_1)$ has order $d_2$. For other fields of definition and $p$ defining a finite residue field $\F_q$, return the structure of the reduction of $E$: the argument $p$ is best left omitted if $K = \Q_\ell$ (else we must have $p = \ell$) and must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) with residue field $\F_q$ otherwise. The curve is allowed to have bad reduction at $p$ and in this case we consider the (cyclic) group of non-singular points for the reduction of a minimal model at $p$. If $\fl = 0$, the equation not be minimal or even integral at $p$; of course, a minimal model will be more efficient. If $\fl = 1$, the requested generators depend on the model, which must then be minimal at $p$, otherwise an exception is thrown. Use \kbd{ellintegralmodel} and/or \kbd{ellocalred} first to reduce to this case. \bprog ? E = ellinit([0,1]); \\ y^2 = x^3 + 0.x + 1, defined over Q ? ellgroup(E, 7) %2 = [6, 2] \\ Z/6 x Z/2, non-cyclic ? E = ellinit([0,1] * Mod(1,11)); \\ defined over F_11 ? ellgroup(E) \\ no need to repeat 11 %4 = [12] ? ellgroup(E, 11) \\ ... but it also works %5 = [12] ? ellgroup(E, 13) \\ ouch, inconsistent input! *** at top-level: ellgroup(E,13) *** ^-------------- *** ellgroup: inconsistent moduli in Rg_to_Fp: 11 13 ? ellgroup(E, 7, 1) %6 = [12, [6, 2], [[Mod(2, 7), Mod(4, 7)], [Mod(4, 7), Mod(4, 7)]]] @eprog\noindent Let us now consider curves of bad reduction, in this case we return the structure of the (cyclic) group of non-singular points, satisfying $\#E_{ns}(\F_p) = p - a_p$: \bprog ? E = ellinit([0,5]); ? ellgroup(E, 5, 1) %2 = [5, [5], [[Mod(4, 5), Mod(2, 5)]]] ? ellap(E, 5) %3 = 0 \\ additive reduction at 5 ? E = ellinit([0,-1,0,35,0]); ? ellgroup(E, 5, 1) %5 = [4, [4], [[Mod(2, 5), Mod(2, 5)]]] ? ellap(E, 5) %6 = 1 \\ split multiplicative reduction at 5 ? ellgroup(E, 7, 1) %7 = [8, [8], [[Mod(3, 7), Mod(5, 7)]]] ? ellap(E, 7) %8 = -1 \\ non-split multiplicative reduction at 7 @eprog The library syntax is \fun{GEN}{ellgroup0}{GEN E, GEN p = NULL, long flag}. Also available is \fun{GEN}{ellgroup}{GEN E, GEN p}, corresponding to \fl = 0. \subsec{ellheegner$(E)$}\kbdsidx{ellheegner}\label{se:ellheegner} Let $E$ be an elliptic curve over the rationals, assumed to be of (analytic) rank $1$. This returns a non-torsion rational point on the curve, whose canonical height is equal to the product of the elliptic regulator by the analytic Sha. This uses the Heegner point method, described in Cohen GTM 239; the complexity is proportional to the product of the square root of the conductor and the height of the point (thus, it is preferable to apply it to strong Weil curves). \bprog ? E = ellinit([-157^2,0]); ? u = ellheegner(E); print(u[1], "\n", u[2]) 69648970982596494254458225/166136231668185267540804 538962435089604615078004307258785218335/67716816556077455999228495435742408 ? ellheegner(ellinit([0,1])) \\ E has rank 0 ! *** at top-level: ellheegner(E=ellinit *** ^-------------------- *** ellheegner: The curve has even analytic rank. @eprog The library syntax is \fun{GEN}{ellheegner}{GEN E}. \subsec{ellheight$(E,P,\{Q\})$}\kbdsidx{ellheight}\label{se:ellheight} Global N\'eron-Tate height $h(P)$ of the point $P$ on the elliptic curve $E$, defined over $\Q$ or a number field, using the same normalization as Cremona's \emph{Algorithms for modular elliptic curves}. $E$ must be an \kbd{ell} as output by \kbd{ellinit}; it needs not be given by a minimal model although the computation will be faster if it is. The height of a torsion point is exactly 0, else a positive real number. If the argument $Q$ is present, computes the value of the bilinear form $(h(P+Q)-h(P-Q)) / 4$. The library syntax is \fun{GEN}{ellheight0}{GEN E, GEN P, GEN Q = NULL, long prec}. Also available is \fun{GEN}{ellheight}{GEN E, GEN P, long prec} ($Q$ omitted). \subsec{ellheightmatrix$(E,x)$}\kbdsidx{ellheightmatrix}\label{se:ellheightmatrix} $x$ being a vector of points, this function outputs the Gram matrix of $x$ with respect to the N\'eron-Tate height, in other words, the $(i,j)$ component of the matrix is equal to \kbd{ellbil($E$,x[$i$],x[$j$])}. The rank of this matrix, at least in some approximate sense, gives the rank of the set of points, and if $x$ is a basis of the \idx{Mordell-Weil group} of $E$, its determinant is equal to the regulator of $E$. Note our height normalization follows Cremona's \emph{Algorithms for modular elliptic curves}: this matrix should be divided by 2 to be in accordance with, e.g., Silverman's normalizations. The library syntax is \fun{GEN}{ellheightmatrix}{GEN E, GEN x, long prec}. \subsec{ellidentify$(E)$}\kbdsidx{ellidentify}\label{se:ellidentify} Look up the elliptic curve $E$, defined by an arbitrary model over $\Q$, in the \tet{elldata} database. Return \kbd{[[N, M, G], C]} where $N$ is the curve name in Cremona's elliptic curve database, $M$ is the minimal model, $G$ is a $\Z$-basis of the free part of the \idx{Mordell-Weil group} $E(\Q)$ and $C$ is the change of coordinates change, suitable for \kbd{ellchangecurve}. The library syntax is \fun{GEN}{ellidentify}{GEN E}. \subsec{ellinit$(x,\{D=1\})$}\kbdsidx{ellinit}\label{se:ellinit} Initialize an \tet{ell} structure, attached to the elliptic curve $E$. $E$ is either \item a $5$-component vector $[a_1,a_2,a_3,a_4,a_6]$ defining the elliptic curve with Weierstrass equation $$ Y^2 + a_1 XY + a_3 Y = X^3 + a_2 X^2 + a_4 X + a_6, $$ \item a $2$-component vector $[a_4,a_6]$ defining the elliptic curve with short Weierstrass equation $$ Y^2 = X^3 + a_4 X + a_6, $$ \item a character string in Cremona's notation, e.g. \kbd{"11a1"}, in which case the curve is retrieved from the \tet{elldata} database if available. The optional argument $D$ describes the domain over which the curve is defined: \item the \typ{INT} $1$ (default): the field of rational numbers $\Q$. \item a \typ{INT} $p$, where $p$ is a prime number: the prime finite field $\F_p$. \item an \typ{INTMOD} \kbd{Mod(a, p)}, where $p$ is a prime number: the prime finite field $\F_p$. \item a \typ{FFELT}, as returned by \tet{ffgen}: the corresponding finite field $\F_q$. \item a \typ{PADIC}, $O(p^n)$: the field $\Q_p$, where $p$-adic quantities will be computed to a relative accuracy of $n$ digits. We advise to input a model defined over $\Q$ for such curves. In any case, if you input an approximate model with \typ{PADIC} coefficients, it will be replaced by a lift to $\Q$ (an exact model ``close'' to the one that was input) and all quantities will then be computed in terms of this lifted model, at the given accuracy. \item a \typ{REAL} $x$: the field $\C$ of complex numbers, where floating point quantities are by default computed to a relative accuracy of \kbd{precision}$(x)$. If no such argument is given, the value of \kbd{realprecision} at the time \kbd{ellinit} is called will be used. \item a number field $K$, given by a \kbd{nf} or \kbd{bnf} structure; a \kbd{bnf} is required for \kbd{ellminimalmodel}. \item a prime ideal $\goth{p}$, given by a \kbd{prid} structure; valid if $x$ is a curve defined over a number field $K$ and the equation is integral and minimal at $\goth{p}$. This argument $D$ is indicative: the curve coefficients are checked for compatibility, possibly changing $D$; for instance if $D = 1$ and an \typ{INTMOD} is found. If inconsistencies are detected, an error is raised: \bprog ? ellinit([1 + O(5), 1], O(7)); *** at top-level: ellinit([1+O(5),1],O *** ^-------------------- *** ellinit: inconsistent moduli in ellinit: 7 != 5 @eprog\noindent If the curve coefficients are too general to fit any of the above domain categories, only basic operations, such as point addition, will be supported later. If the curve (seen over the domain $D$) is singular, fail and return an empty vector $[]$. \bprog ? E = ellinit([0,0,0,0,1]); \\ y^2 = x^3 + 1, over Q ? E = ellinit([0,1]); \\ the same curve, short form ? E = ellinit("36a1"); \\ sill the same curve, Cremona's notations ? E = ellinit([0,1], 2) \\ over F2: singular curve %4 = [] ? E = ellinit(['a4,'a6] * Mod(1,5)); \\ over F_5[a4,a6], basic support ! @eprog\noindent The result of \tet{ellinit} is an \tev{ell} structure. It contains at least the following information in its components: % $$ a_1,a_2,a_3,a_4,a_6,b_2,b_4,b_6,b_8,c_4,c_6,\Delta,j.$$ % All are accessible via member functions. In particular, the discriminant is \kbd{$E$.disc}, and the $j$-invariant is \kbd{$E$.j}. \bprog ? E = ellinit([a4, a6]); ? E.disc %2 = -64*a4^3 - 432*a6^2 ? E.j %3 = -6912*a4^3/(-4*a4^3 - 27*a6^2) @eprog Further components contain domain-specific data, which are in general dynamic: only computed when needed, and then cached in the structure. \bprog ? E = ellinit([2,3], 10^60+7); \\ E over F_p, p large ? ellap(E) time = 4,440 ms. %2 = -1376268269510579884904540406082 ? ellcard(E); \\ now instantaneous ! time = 0 ms. ? ellgenerators(E); time = 5,965 ms. ? ellgenerators(E); \\ second time instantaneous time = 0 ms. @eprog See the description of member functions related to elliptic curves at the beginning of this section. The library syntax is \fun{GEN}{ellinit}{GEN x, GEN D = NULL, long prec}. \subsec{ellintegralmodel$(E,\{\&v\})$}\kbdsidx{ellintegralmodel}\label{se:ellintegralmodel} Let $E$ be an \kbd{ell} structure over a number field $K$ or $\Q_p$. This function returns an integral model. If $v$ is present, sets $v = [u,0,0,0]$ to the corresponding change of variable: the return value is identical to that of \kbd{ellchangecurve(E, v)}. \bprog ? e = ellinit([1/17,1/42]); ? e = ellintegralmodel(e,&v); ? e[1..5] %3 = [0, 0, 0, 15287762448, 3154568630095008] ? v %4 = [1/714, 0, 0, 0] @eprog The library syntax is \fun{GEN}{ellintegralmodel}{GEN E, GEN *v = NULL}. \subsec{ellisdivisible$(E,P,n,\{\&Q\})$}\kbdsidx{ellisdivisible}\label{se:ellisdivisible} Given $E/K$ a number field and $P$ in $E(K)$ return $1$ if $P = [n]R$ for some $R$ in $E(K)$ and set $Q$ to one such $R$; and return $0$ otherwise. The integer $n \geq 0$ may be given as \kbd{ellxn(E,n)}, if many points need to be tested. \bprog ? K = nfinit(polcyclo(11,t)); ? E = ellinit([0,-1,1,0,0], K); ? P = [0,0]; ? ellorder(E,P) %4 = 5 ? ellisdivisible(E,P,5, &Q) %5 = 1 ? lift(Q) %6 = [-t^7-t^6-t^5-t^4+1, -t^9-2*t^8-2*t^7-3*t^6-3*t^5-2*t^4-2*t^3-t^2-1] ? ellorder(E, Q) %7 = 25 @eprog\noindent The algebraic complexity of the underlying algorithm is in $O(n^4)$, so it is advisable to first factor $n$, then use a chain of checks attached to the prime divisors of $n$: the function will do it itself unless $n$ is given in \kbd{ellxn} form. The library syntax is \fun{long}{ellisdivisible}{GEN E, GEN P, GEN n, GEN *Q = NULL}. \subsec{ellisogeny$(E, G, \{\var{only\_image} = 0\}, \{x = 'x\}, \{y = 'y\})$}\kbdsidx{ellisogeny}\label{se:ellisogeny} Given an elliptic curve $E$, a finite subgroup $G$ of $E$ is given either as a generating point $P$ (for a cyclic $G$) or as a polynomial whose roots vanish on the $x$-coordinates of the non-zero elements of $G$ (general case and more efficient if available). This function returns the $[a_1,a_2,a_3,a_4,a_6]$ invariants of the quotient elliptic curve $E/G$ and (if \var{only\_image} is zero (the default)) a vector of rational functions $[f, g, h]$ such that the isogeny $E \to E/G$ is given by $(x,y) \mapsto (f(x)/h(x)^2, g(x,y)/h(x)^3)$. \bprog ? E = ellinit([0,1]); ? elltors(E) %2 = [6, [6], [[2, 3]]] ? ellisogeny(E, [2,3], 1) \\ Weierstrass model for E/

%3 = [0, 0, 0, -135, -594] ? ellisogeny(E,[-1,0]) %4 = [[0,0,0,-15,22], [x^3+2*x^2+4*x+3, y*x^3+3*y*x^2-2*y, x+1]] @eprog The library syntax is \fun{GEN}{ellisogeny}{GEN E, GEN G, long only_image, long x = -1, long y = -1} where \kbd{x}, \kbd{y} are variable numbers. \subsec{ellisogenyapply$(f, g)$}\kbdsidx{ellisogenyapply}\label{se:ellisogenyapply} Given an isogeny of elliptic curves $f:E'\to E$ (being the result of a call to \tet{ellisogeny}), apply $f$ to $g$: \item if $g$ is a point $P$ in the domain of $f$, return the image $f(P)$; \item if $g:E''\to E'$ is a compatible isogeny, return the composite isogeny $f \circ g: E''\to E$. \bprog ? one = ffgen(101, 't)^0; ? E = ellinit([6, 53, 85, 32, 34] * one); ? P = [84, 71] * one; ? ellorder(E, P) %4 = 5 ? [F, f] = ellisogeny(E, P); \\ f: E->F = E/

? ellisogenyapply(f, P) %6 = [0] ? F = ellinit(F); ? Q = [89, 44] * one; ? ellorder(F, Q) %9 = 2 ? [G, g] = ellisogeny(F, Q); \\ g: F->G = F/ ? gof = ellisogenyapply(g, f); \\ gof: E -> G @eprog The library syntax is \fun{GEN}{ellisogenyapply}{GEN f, GEN g}. \subsec{ellisomat$(E, \{p=0\}, \{\var{fl}=0\})$}\kbdsidx{ellisomat}\label{se:ellisomat} Given an elliptic curve $E$ defined over a number field, compute representatives of the isomorphism classes of elliptic curves $\Q$-isogenous to $E$. The function returns a vector $[L,M]$ where $L$ is a list of triples $[E_i, f_i, g_i]$, where $E_i$ is an elliptic curve in $[a_4,a_6]$ form, $f_i: E \to E_i$ is a rational isogeny, $g_i: E_i \to E$ is the dual isogeny of $f_i$, and $M$ is the matrix such that $M_{i,j}$ is the degree of the isogeny between $E_i$ and $E_j$. Furthermore the first curve $E_1$ is isomorphic to $E$ by $f_1$. If the flag $\var{fl}=1$, the $f_i$ and $g_i$ are not computed, which saves time, and $L$ is the list of the curves $E_i$. If $p$ is set, it must be a prime number; in this which case only isogenies of degree a power of $p$ are considered. Over a number field, the possible isogeny degrees are determined by Billerey algorithm. As a consequence, CM curves over a number field are not fully supported. \bprog ? E = ellinit("14a1"); ? [L,M] = ellisomat(E); ? LE = apply(x->x[1], L) \\ list of curves %3 = [[215/48,-5291/864],[-675/16,6831/32],[-8185/48,-742643/864], [-1705/48,-57707/864],[-13635/16,306207/32],[-131065/48,-47449331/864]] ? L[2][2] \\ isogeny f_2 %4 = [x^3+3/4*x^2+19/2*x-311/12, 1/2*x^4+(y+1)*x^3+(y-4)*x^2+(-9*y+23)*x+(55*y+55/2),x+1/3] ? L[2][3] \\ dual isogeny g_2 %5 = [1/9*x^3-1/4*x^2-141/16*x+5613/64, -1/18*x^4+(1/27*y-1/3)*x^3+(-1/12*y+87/16)*x^2+(49/16*y-48)*x +(-3601/64*y+16947/512),x-3/4] ? apply(E->ellidentify(ellinit(E))[1][1], LE) %6 = ["14a1","14a4","14a3","14a2","14a6","14a5"] ? M %7 = [1 3 3 2 6 6] [3 1 9 6 2 18] [3 9 1 6 18 2] [2 6 6 1 3 3] [6 2 18 3 1 9] [6 18 2 3 9 1] @eprog The library syntax is \fun{GEN}{ellisomat}{GEN E, long p, long fl}. \subsec{ellisoncurve$(E,z)$}\kbdsidx{ellisoncurve}\label{se:ellisoncurve} Gives 1 (i.e.~true) if the point $z$ is on the elliptic curve $E$, 0 otherwise. If $E$ or $z$ have imprecise coefficients, an attempt is made to take this into account, i.e.~an imprecise equality is checked, not a precise one. It is allowed for $z$ to be a vector of points in which case a vector (of the same type) is returned. The library syntax is \fun{GEN}{ellisoncurve}{GEN E, GEN z}. Also available is \fun{int}{oncurve}{GEN E, GEN z} which does not accept vectors of points. \subsec{ellisotree$(E)$}\kbdsidx{ellisotree}\label{se:ellisotree} Given an elliptic curve $E$ defined over $\Q$ or a set of $\Q$-isogenous curves as given by \kbd{ellisomat}, return a pair $[L,M]$ where \item $L$ lists the minimal models of the isomorphism classes of elliptic curves $\Q$-isogenous to $E$ (or in the set of isogenous curves), \item $M$ is the adjacency matrix of the prime degree isogenies tree: there is an edge from $E_i$ to $E_j$ if there is an isogeny $E_i \to E_j$ of prime degree such that the N\'eron differential forms are preserved. \bprog ? E = ellinit("14a1"); ? [L,M] = ellisotree(E); ? M %3 = [0 0 3 2 0 0] [3 0 0 0 2 0] [0 0 0 0 0 2] [0 0 0 0 0 3] [0 0 0 3 0 0] [0 0 0 0 0 0] ? [L2,M2] = ellisotree(ellisomat(E,2,1)); %4 = [0 2] [0 0] ? [L3,M3] = ellisotree(ellisomat(E,3,1)); ? M3 %6 = [0 0 3] [3 0 0] [0 0 0] @eprog\noindent Compare with the result of \kbd{ellisomat}. \bprog ? [L,M]=ellisomat(E,,1); ? M %7 = [1 3 3 2 6 6] [3 1 9 6 2 18] [3 9 1 6 18 2] [2 6 6 1 3 3] [6 2 18 3 1 9] [6 18 2 3 9 1] @eprog The library syntax is \fun{GEN}{ellisotree}{GEN E}. \subsec{ellissupersingular$(E,\{p\})$}\kbdsidx{ellissupersingular}\label{se:ellissupersingular} Return 1 if the elliptic curve $E$ defined over a number field, $\Q_p$ or a finite field is supersingular at $p$, and $0$ otherwise. If the curve is defined over a number field, $p$ must be explicitly given, and must be a prime number, resp.~a maximal ideal, if the curve is defined over $\Q$, resp.~a general number field: we return $1$ if and only if $E$ has supersingular good reduction at $p$. Alternatively, $E$ can be given by its $j$-invariant in a finite field. In this case $p$ must be omitted. \bprog ? setrand(1); \\ make the choice of g deterministic ? g = ffprimroot(ffgen(7^5)) %1 = 4*x^4 + 5*x^3 + 6*x^2 + 5*x + 6 ? [g^n | n <- [1 .. 7^5 - 1], ellissupersingular(g^n)] %2 = [6] ? K = nfinit(y^3-2); P = idealprimedec(K, 2)[1]; ? E = ellinit([y,1], K); ? ellissupersingular(E, P) %5 = 1 ? Q = idealprimedec(K,5)[1]; ? ellissupersingular(E, Q) %6 = 0 @eprog The library syntax is \fun{GEN}{ellissupersingular}{GEN E, GEN p = NULL}. Also available is \fun{int}{elljissupersingular}{GEN j} where $j$ is a $j$-invariant of a curve over a finite field. \subsec{ellj$(x)$}\kbdsidx{ellj}\label{se:ellj} Elliptic $j$-invariant. $x$ must be a complex number with positive imaginary part, or convertible into a power series or a $p$-adic number with positive valuation. The library syntax is \fun{GEN}{jell}{GEN x, long prec}. \subsec{elllocalred$(E,\{p\})$}\kbdsidx{elllocalred}\label{se:elllocalred} Calculates the \idx{Kodaira} type of the local fiber of the elliptic curve $E$ at $p$. $E$ must be an \kbd{ell} structure as output by \kbd{ellinit}, over $\Q_\ell$ ($p$ better left omitted, else equal to $\ell$) over $\Q$ ($p$ a rational prime) or a number field $K$ ($p$ a maximal ideal given by a \kbd{prid} structure). The result is a 4-component vector $[f,kod,v,c]$. Here $f$ is the exponent of $p$ in the arithmetic conductor of $E$, and $kod$ is the Kodaira type which is coded as follows: 1 means good reduction (type I$_0$), 2, 3 and 4 mean types II, III and IV respectively, $4+\nu$ with $\nu>0$ means type I$_\nu$; finally the opposite values $-1$, $-2$, etc.~refer to the starred types I$_0^*$, II$^*$, etc. The third component $v$ is itself a vector $[u,r,s,t]$ giving the coordinate changes done during the local reduction; $u = 1$ if and only if the given equation was already minimal at $p$. Finally, the last component $c$ is the local \idx{Tamagawa number} $c_p$. The library syntax is \fun{GEN}{elllocalred}{GEN E, GEN p = NULL}. \subsec{elllog$(E,P,G,\{o\})$}\kbdsidx{elllog}\label{se:elllog} Given two points $P$ and $G$ on the elliptic curve $E/\F_q$, returns the discrete logarithm of $P$ in base $G$, i.e. the smallest non-negative integer $n$ such that $P = [n]G$. See \tet{znlog} for the limitations of the underlying discrete log algorithms. If present, $o$ represents the order of $G$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[N, factor(N)]}, where $N$ is the order of $G$. If no $o$ is given, assume that $G$ generates the curve. The function also assumes that $P$ is a multiple of $G$. \bprog ? a = ffgen(ffinit(2,8),'a); ? E = ellinit([a,1,0,0,1]); \\ over F_{2^8} ? x = a^3; y = ellordinate(E,x)[1]; ? P = [x,y]; G = ellmul(E, P, 113); ? ord = [242, factor(242)]; \\ P generates a group of order 242. Initialize. ? ellorder(E, G, ord) %4 = 242 ? e = elllog(E, P, G, ord) %5 = 15 ? ellmul(E,G,e) == P %6 = 1 @eprog The library syntax is \fun{GEN}{elllog}{GEN E, GEN P, GEN G, GEN o = NULL}. \subsec{elllseries$(E,s,\{A=1\})$}\kbdsidx{elllseries}\label{se:elllseries} This function is deprecated, use \kbd{lfun(E,s)} instead. $E$ being an elliptic curve, given by an arbitrary model over $\Q$ as output by \kbd{ellinit}, this function computes the value of the $L$-series of $E$ at the (complex) point $s$. This function uses an $O(N^{1/2})$ algorithm, where $N$ is the conductor. The optional parameter $A$ fixes a cutoff point for the integral and is best left omitted; the result must be independent of $A$, up to \kbd{realprecision}, so this allows to check the function's accuracy. The library syntax is \fun{GEN}{elllseries}{GEN E, GEN s, GEN A = NULL, long prec}. \subsec{ellminimaldisc$(E)$}\kbdsidx{ellminimaldisc}\label{se:ellminimaldisc} $E$ being an elliptic curve defined over a number field output by \kbd{ellinit}, return the minimal discriminant ideal of E. The library syntax is \fun{GEN}{ellminimaldisc}{GEN E}. \subsec{ellminimalmodel$(E,\{\&v\})$}\kbdsidx{ellminimalmodel}\label{se:ellminimalmodel} Let $E$ be an \kbd{ell} structure over a number field $K$. This function determines whether $E$ admits a global minimal integral model. If so, it returns it and sets $v = [u,r,s,t]$ to the corresponding change of variable: the return value is identical to that of \kbd{ellchangecurve(E, v)}. Else return the (non-principal) Weierstrass class of $E$, i.e. the class of $\prod \goth{p}^{(v_{\goth{p}}{\Delta} - \delta_{\goth{p}}) / 12}$ where $\Delta = \kbd{E.disc}$ is the model's discriminant and $\goth{p} ^ \delta_{\goth{p}}$ is the local minimal discriminant. This function requires either that $E$ be defined over the rational field $\Q$ (with domain $D = 1$ in \kbd{ellinit}), in which case a global minimal model always exists, or over a number field given by a \var{bnf} structure. The Weierstrass class is given in \kbd{bnfisprincipal} format, i.e. in terms of the \kbd{K.gen} generators. The resulting model has integral coefficients and is everywhere minimal, the coefficients $a_1$ and $a_3$ are reduced modulo $2$ (in terms of the fixed integral basis \kbd{K.zk}) and $a_2$ is reduced modulo $3$. Over $\Q$, we further require that $a_1$ and $a_3$ be $0$ or $1$, that $a_2$ be $0$ or $\pm 1$ and that $u > 0$ in the change of variable: both the model and the change of variable $v$ are then unique.\sidx{minimal model} \bprog ? e = ellinit([6,6,12,55,233]); \\ over Q ? E = ellminimalmodel(e, &v); ? E[1..5] %3 = [0, 0, 0, 1, 1] ? v %4 = [2, -5, -3, 9] @eprog \bprog ? K = bnfinit(a^2-65); \\ over a non-principal number field ? K.cyc %2 = [2] ? u = Mod(8+a, K.pol); ? E = ellinit([1,40*u+1,0,25*u^2,0], K); ? ellminimalmodel(E) \\ no global minimal model exists over Z_K %6 = [1]~ @eprog The library syntax is \fun{GEN}{ellminimalmodel}{GEN E, GEN *v = NULL}. \subsec{ellminimaltwist$(E, \{\fl=0\})$}\kbdsidx{ellminimaltwist}\label{se:ellminimaltwist} Let $E$ be an elliptic curve defined over $\Q$, return a discriminant $D$ such that the twist of $E$ by $D$ is minimal among all possible quadratic twists, i.e. if $\fl=0$, its minimal model has minimal discriminant, or if $\fl=1$, it has minimal conductor. In the example below, we find a curve with $j$-invariant $3$ and minimal conductor. \bprog ? E = ellminimalmodel(ellinit(ellfromj(3))); ? ellglobalred(E)[1] %2 = 357075 ? D = ellminimaltwist(E,1) %3 = -15 ? E2 = ellminimalmodel(ellinit(elltwist(E,D))); ? ellglobalred(E2)[1] %5 = 14283 @eprog In the example below, $\fl=0$ and $\fl=1$ give different results. \bprog ? E = ellinit([1,0]); ? D0 = ellminimaltwist(E,0) %7 = 1 ? D1 = ellminimaltwist(E,1) %8 = 8 ? E0 = ellminimalmodel(ellinit(elltwist(E,D0))); ? [E0.disc, ellglobalred(E0)[1]] %10 = [-64, 64] ? E1 = ellminimalmodel(ellinit(elltwist(E,D1))); ? [E1.disc, ellglobalred(E1)[1]] %12 = [-4096, 32] @eprog The library syntax is \fun{GEN}{ellminimaltwist0}{GEN E, long flag}. Also available are \fun{GEN}{ellminimaltwist}{E} for $\fl=0$, and \fun{GEN}{ellminimaltwistcond}{E} for $\fl=1$. \subsec{ellmoddegree$(e)$}\kbdsidx{ellmoddegree}\label{se:ellmoddegree} $e$ being an elliptic curve defined over $\Q$ output by \kbd{ellinit}, compute the modular degree of $e$ divided by the square of the Manin constant $c$. It is conjectured that $c = 1$ for the strong Weil curve in the isogeny class (optimal quotient of $J_0(N)$) and this can be proven using \kbd{ellweilcurve} when the conductor $N$ is moderate. \bprog ? E = ellinit("11a1"); \\ from Cremona table: strong Weil curve and c = 1 ? [v,smith] = ellweilcurve(E); smith \\ proof of the above %2 = [[1, 1], [5, 1], [1, 1/5]] ? ellmoddegree(E) %3 = 1 ? [ellidentify(e)[1][1] | e<-v] %4 = ["11a1", "11a2", "11a3"] ? ellmoddegree(ellinit("11a2")) %5 = 5 ? ellmoddegree(ellinit("11a3")) %6 = 1/5 @eprog\noindent The modular degree of \kbd{11a1} is $1$ (because \kbd{ellweilcurve} or Cremona's table prove that the Manin constant is $1$ for this curve); the output of \kbd{ellweilcurve} also proves that the Manin constants of \kbd{11a2} and \kbd{11a3} are 1 and 5 respectively, so the actual modular degree of both \kbd{11a2} and \kbd{11a3} is 5. The library syntax is \fun{GEN}{ellmoddegree}{GEN e}. \subsec{ellmodulareqn$(N,\{x\},\{y\})$}\kbdsidx{ellmodulareqn}\label{se:ellmodulareqn} Given a prime $N < 500$, return a vector $[P,t]$ where $P(x,y)$ is a modular equation of level $N$, i.e.~a bivariate polynomial with integer coefficients; $t$ indicates the type of this equation: either \emph{canonical} ($t = 0$) or \emph{Atkin} ($t = 1$). This function requires the \kbd{seadata} package and its only use is to give access to the package contents. See \tet{polmodular} for a more general and more flexible function. Let $j$ be the $j$-invariant function. The polynomial $P$ satisfies the functional equation, $$ P(f,j) = P(f \mid W_N, j \mid W_N) = 0 $$ for some modular function $f = f_N$ (hand-picked for each fixed $N$ to minimize its size, see below), where $W_N(\tau) = -1 / (N\*\tau)$ is the Atkin-Lehner involution. These two equations allow to compute the values of the classical modular polynomial $\Phi_N$, such that $\Phi_N(j(\tau), j(N\tau)) = 0$, while being much smaller than the latter. More precisely, we have $j(W_N(\tau)) = j(N\*\tau)$; the function $f$ is invariant under $\Gamma_0(N)$ and also satisfies \item for Atkin type: $f \mid W_N = f$; \item for canonical type: let $s = 12/\gcd(12,N-1)$, then $f \mid W_N = N^s / f$. In this case, $f$ has a simple definition: $f(\tau) = N^s \* \big(\eta(N\*\tau) / \eta(\tau) \big)^{2\*s}$, where $\eta$ is Dedekind's eta function. The following GP function returns values of the classical modular polynomial by eliminating $f_N(\tau)$ in the above functional equation, for $N\leq 31$ or $N\in\{41,47,59,71\}$. \bprog classicaleqn(N, X='X, Y='Y)= { my([P,t] = ellmodulareqn(N), Q, d); if (poldegree(P,'y) > 2, error("level unavailable in classicaleqn")); if (t == 0, \\ Canonical my(s = 12/gcd(12,N-1)); Q = 'x^(N+1) * substvec(P,['x,'y],[N^s/'x,Y]); d = N^(s*(2*N+1)) * (-1)^(N+1); , \\ Atkin Q = subst(P,'y,Y); d = (X-Y)^(N+1)); polresultant(subst(P,'y,X), Q) / d; } @eprog The library syntax is \fun{GEN}{ellmodulareqn}{long N, long x = -1, long y = -1} where \kbd{x}, \kbd{y} are variable numbers. \subsec{ellmul$(E,z,n)$}\kbdsidx{ellmul}\label{se:ellmul} Computes $[n]z$, where $z$ is a point on the elliptic curve $E$. The exponent $n$ is in $\Z$, or may be a complex quadratic integer if the curve $E$ has complex multiplication by $n$ (if not, an error message is issued). \bprog ? Ei = ellinit([1,0]); z = [0,0]; ? ellmul(Ei, z, 10) %2 = [0] \\ unsurprising: z has order 2 ? ellmul(Ei, z, I) %3 = [0, 0] \\ Ei has complex multiplication by Z[i] ? ellmul(Ei, z, quadgen(-4)) %4 = [0, 0] \\ an alternative syntax for the same query ? Ej = ellinit([0,1]); z = [-1,0]; ? ellmul(Ej, z, I) *** at top-level: ellmul(Ej,z,I) *** ^-------------- *** ellmul: not a complex multiplication in ellmul. ? ellmul(Ej, z, 1+quadgen(-3)) %6 = [1 - w, 0] @eprog The simple-minded algorithm for the CM case assumes that we are in characteristic $0$, and that the quadratic order to which $n$ belongs has small discriminant. The library syntax is \fun{GEN}{ellmul}{GEN E, GEN z, GEN n}. \subsec{ellneg$(E,z)$}\kbdsidx{ellneg}\label{se:ellneg} Opposite of the point $z$ on elliptic curve $E$. The library syntax is \fun{GEN}{ellneg}{GEN E, GEN z}. \subsec{ellnonsingularmultiple$(E,P)$}\kbdsidx{ellnonsingularmultiple}\label{se:ellnonsingularmultiple} Given an elliptic curve $E/\Q$ (more precisely, a model defined over $\Q$ of a curve) and a rational point $P \in E(\Q)$, returns the pair $[R,n]$, where $n$ is the least positive integer such that $R := [n]P$ has good reduction at every prime. More precisely, its image in a minimal model is everywhere non-singular. \bprog ? e = ellinit("57a1"); P = [2,-2]; ? ellnonsingularmultiple(e, P) %2 = [[1, -1], 2] ? e = ellinit("396b2"); P = [35, -198]; ? [R,n] = ellnonsingularmultiple(e, P); ? n %5 = 12 @eprog The library syntax is \fun{GEN}{ellnonsingularmultiple}{GEN E, GEN P}. \subsec{ellorder$(E,z,\{o\})$}\kbdsidx{ellorder}\label{se:ellorder} Gives the order of the point $z$ on the elliptic curve $E$, defined over a finite field or a number field. Return (the impossible value) zero if the point has infinite order. \bprog ? E = ellinit([-157^2,0]); \\ the "157-is-congruent" curve ? P = [2,2]; ellorder(E, P) %2 = 2 ? P = ellheegner(E); ellorder(E, P) \\ infinite order %3 = 0 ? K = nfinit(polcyclo(11,t)); E=ellinit("11a3", K); T = elltors(E); ? ellorder(E, T.gen[1]) %5 = 25 ? E = ellinit(ellfromj(ffgen(5^10))); ? ellcard(E) %7 = 9762580 ? P = random(E); ellorder(E, P) %8 = 4881290 ? p = 2^160+7; E = ellinit([1,2], p); ? N = ellcard(E) %9 = 1461501637330902918203686560289225285992592471152 ? o = [N, factor(N)]; ? for(i=1,100, ellorder(E,random(E))) time = 260 ms. @eprog The parameter $o$, is now mostly useless, and kept for backward compatibility. If present, it represents a non-zero multiple of the order of $z$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord} is the cardinality of the curve. It is no longer needed since PARI is now able to compute it over large finite fields (was restricted to small prime fields at the time this feature was introduced), \emph{and} caches the result in $E$ so that it is computed and factored only once. Modifying the last example, we see that including this extra parameter provides no improvement: \bprog ? o = [N, factor(N)]; ? for(i=1,100, ellorder(E,random(E),o)) time = 260 ms. @eprog The library syntax is \fun{GEN}{ellorder}{GEN E, GEN z, GEN o = NULL}. The obsolete form \fun{GEN}{orderell}{GEN e, GEN z} should no longer be used. \subsec{ellordinate$(E,x)$}\kbdsidx{ellordinate}\label{se:ellordinate} Gives a 0, 1 or 2-component vector containing the $y$-coordinates of the points of the curve $E$ having $x$ as $x$-coordinate. The library syntax is \fun{GEN}{ellordinate}{GEN E, GEN x, long prec}. \subsec{ellpadicL$(E, p, n, \{s = 0\}, \{r = 0\}, \{D = 1\})$}\kbdsidx{ellpadicL}\label{se:ellpadicL} Returns the value (or $r$-th derivative) on a character $\chi^s$ of $\Z_p^*$ of the $p$-adic $L$-function of the elliptic curve $E/\Q$, twisted by $D$, given modulo $p^n$. \misctitle{Characters} The set of continuous characters of $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$ is identified to $\Z_p^*$ via the cyclotomic character $\chi$ with values in $\overline{\Q_p}^*$. Denote by $\tau:\Z_p^*\to\Z_p^*$ the Teichm\"uller character, with values in the $(p-1)$-th roots of $1$ for $p\neq 2$, and $\{-1,1\}$ for $p = 2$; finally, let $\langle\chi\rangle =\chi \tau^{-1}$, with values in $1 + 2p\Z_p$. In GP, the continuous character of $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$ given by $\langle\chi\rangle^{s_1} \tau^{s_2}$ is represented by the pair of integers $s=(s_1,s_2)$, with $s_1 \in \Z_p$ and $s_2 \bmod p-1$ for $p > 2$, (resp. mod $2$ for $p = 2$); $s$ may be also an integer, representing $(s,s)$ or $\chi^s$. \misctitle{The $p$-adic $L$ function} The $p$-adic $L$ function $L_p$ is defined on the set of continuous characters of $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$, as $\int_{\Z_p^*} \chi^s d \mu$ for a certain $p$-adic distribution $\mu$ on $\Z_p^*$. The derivative is given by $$L_p^{(r)}(E, \chi^s) = \int_{\Z_p^*} \log_p^r(a) \chi^s(a) d\mu(a).$$ More precisely: \item When $E$ has good supersingular reduction, $L_p$ takes its values in $D := H^1_{dR}(E/\Q)\otimes_\Q \Q_p$ and satisfies $$(1-p^{-1} F)^{-2} L_p(E, \chi^0)= (L(E,1) / \Omega) \cdot \omega$$ where $F$ is the Frobenius, $L(E,1)$ is the value of the complex $L$ function at $1$, $\omega$ is the N\'eron differential and $\Omega$ the attached period on $E(\R)$. Here, $\chi^0$ represents the trivial character. The function returns the components of $L_p^{(r)}(E,\chi^s)$ in the basis $(\omega, F \omega)$. \item When $E$ has ordinary good reduction, this method only defines the projection of $L_p(E,\chi^s)$ on the $\alpha$-eigenspace, where $\alpha$ is the unit eigenvalue for $F$. This is what the function returns. We have $$(1- \alpha^{-1})^{-2} L_{p,\alpha}(E,\chi^0)= L(E,1) / \Omega.$$ Two supersingular examples: \bprog ? cxL(e) = bestappr( ellL1(e) / e.omega[1] ); ? e = ellinit("17a1"); p=3; \\ supersingular, a3 = 0 ? L = ellpadicL(e,p,4); ? F = [0,-p;1,ellap(e,p)]; \\ Frobenius matrix in the basis (omega,F(omega)) ? (1-p^(-1)*F)^-2 * L / cxL(e) %5 = [1 + O(3^5), O(3^5)]~ \\ [1,0]~ ? e = ellinit("116a1"); p=3; \\ supersingular, a3 != 0~ ? L = ellpadicL(e,p,4); ? F = [0,-p; 1,ellap(e,p)]; ? (1-p^(-1)*F)^-2*L~ / cxL(e) %9 = [1 + O(3^4), O(3^5)]~ @eprog Good ordinary reduction: \bprog ? e = ellinit("17a1"); p=5; ap = ellap(e,p) %1 = -2 \\ ordinary ? L = ellpadicL(e,p,4) %2 = 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^4) ? al = padicappr(x^2 - ap*x + p, ap + O(p^7))[1]; ? (1-al^(-1))^(-2) * L / cxL(e) %4 = 1 + O(5^4) @eprog Twist and Teichm\"uller: \bprog ? e = ellinit("17a1"); p=5; \\ ordinary \\ 2nd derivative at tau^1, twist by -7 ? ellpadicL(e, p, 4, [0,1], 2, -7) %2 = 2*5^2 + 5^3 + O(5^4) @eprog We give an example of non split multiplicative reduction (see \tet{ellpadicbsd} for more examples). \bprog ? e=ellinit("15a1"); p=3; n=5; ? L = ellpadicL(e,p,n) %2 = 2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5) ? (1 - ellap(e,p))^(-1) * L / cxL(e) %3 = 1 + O(3^5) @eprog This function is a special case of \tet{mspadicL} and it also appears as the first term of \tet{mspadicseries}: \bprog ? e = ellinit("17a1"); p=5; ? L = ellpadicL(e,p,4) %2 = 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^4) ? [M,phi] = msfromell(e, 1); ? Mp = mspadicinit(M, p, 4); ? mu = mspadicmoments(Mp, phi); ? mspadicL(mu) %6 = 4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + O(5^6) ? mspadicseries(mu) %7 = (4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + O(5^6)) + (3 + 3*5 + 5^2 + 5^3 + O(5^4))*x + (2 + 3*5 + 5^2 + O(5^3))*x^2 + (3 + 4*5 + 4*5^2 + O(5^3))*x^3 + (3 + 2*5 + O(5^2))*x^4 + O(x^5) @eprog\noindent These are more cumbersome than \kbd{ellpadicL} but allow to compute at different characters, or successive derivatives, or to twist by a quadratic character essentially for the cost of a single call to \kbd{ellpadicL} due to precomputations. The library syntax is \fun{GEN}{ellpadicL}{GEN E, GEN p, long n, GEN s = NULL, long r, GEN D = NULL}. \subsec{ellpadicbsd$(E, p, n, \{D = 1\})$}\kbdsidx{ellpadicbsd}\label{se:ellpadicbsd} Given an elliptic curve $E$ over $\Q$, its quadratic twist $E_D$ and a prime number $p$, this function is a $p$-adic analog of the complex functions \tet{ellanalyticrank} and \tet{ellbsd}. It calls \kbd{ellpadicL} with initial accuracy $p^n$ and may increase it internally; it returns a vector $[r, L_p]$ where \item $L_p$ is a $p$-adic number (resp. a pair of $p$-adic numbers if $E$ has good supersingular reduction) defined modulo $p^N$, conjecturally equal to $R_p S$, where $R_p$ is the $p$-adic regulator as given by \tet{ellpadicregulator} (in the basis $(\omega, F \omega)$) and $S$ is the cardinal of the Tate-Shafarevich group for the quadratic twist $E_D$. \item $r$ is an upper bound for the analytic rank of the $p$-adic $L$-function attached to $E_D$: we know for sure that the $i$-th derivative of $L_p(E_D,.)$ at $\chi^0$ is $O(p^N)$ for all $i < r$ and that its $r$-th derivative is non-zero; it is expected that the true analytic rank is equal to the rank of the Mordell-Weil group $E_D(\Q)$, plus $1$ if the reduction of $E_D$ at $p$ is split multiplicative; if $r = 0$, then both the analytic rank and the Mordell-Weil rank are unconditionnally $0$. Recall that the $p$-adic BSD conjecture (Mazur, Tate, Teitelbaum, Bernardi, Perrin-Riou) predicts an explicit link between $R_p S$ and $$(1-p^{-1} F)^{-2} \cdot L_p^{(r)}(E_D, \chi^0) / r! $$ where $r$ is the analytic rank of the $p$-adic $L$-function attached to $E_D$ and $F$ is the Frobenius on $H^1_{dR}$; see \tet{ellpadicL} for definitions. \bprog ? E = ellinit("11a1"); p = 7; n = 5; \\ good ordinary ? ellpadicbsd(E, 7, 5) \\ rank 0, %2 = [0, 1 + O(7^5)] ? E = ellinit("91a1"); p = 7; n = 5; \\ non split multiplicative ? [r,Lp] = ellpadicbsd(E, p, n) %5 = [1, 2*7 + 6*7^2 + 3*7^3 + 7^4 + O(7^5)] ? R = ellpadicregulator(E, p, n, E.gen) %6 = 2*7 + 6*7^2 + 3*7^3 + 7^4 + 5*7^5 + O(7^6) ? sha = Lp/R %7 = 1 + O(7^4) ? E = ellinit("91b1"); p = 7; n = 5; \\ split multiplicative ? [r,Lp] = ellpadicbsd(E, p, n) %9 = [2, 2*7 + 7^2 + 5*7^3 + O(7^4)] ? ellpadicregulator(E, p, n, E.gen) %10 = 2*7 + 7^2 + 5*7^3 + 6*7^4 + 2*7^5 + O(7^6) ? [rC, LC] = ellanalyticrank(E); ? [r, rC] %12 = [2, 1] \\ r = rC+1 because of split multiplicative reduction ? E = ellinit("53a1"); p = 5; n = 5; \\ supersingular ? [r, Lp] = ellpadicbsd(E, p, n); ? r %15 = 1 ? Lp %16 = [3*5 + 2*5^2 + 2*5^5 + O(5^6), \ 5 + 3*5^2 + 4*5^3 + 2*5^4 + 5^5 + O(5^6)] ? R = ellpadicregulator(E, p, n, E.gen) %17 = [3*5 + 2*5^2 + 2*5^5 + O(5^6), 5 + 3*5^2 + 4*5^3 + 2*5^4 + O(5^5)] \\ expect Lp = R*#Sha, hence (conjecturally) #Sha = 1 ? E = ellinit("84a1"); p = 11; n = 6; D = -443; ? [r,Lp] = ellpadicbsd(E, 11, 6, D) \\ Mordell-Weil rank 0, no regulator %19 = [0, 3 + 2*11 + O(11^6)] ? lift(Lp) \\ expected cardinal for Sha is 5^2 %20 = 25 ? ellpadicbsd(E, 3, 12, D) \\ at 3 %21 = [1, 1 + 2*3 + 2*3^2 + O(3^8)] ? ellpadicbsd(E, 7, 8, D) \\ and at 7 %22 = [0, 4 + 3*7 + O(7^8)] @eprog The library syntax is \fun{GEN}{ellpadicbsd}{GEN E, GEN p, long n, GEN D = NULL}. \subsec{ellpadicfrobenius$(E,p,n)$}\kbdsidx{ellpadicfrobenius}\label{se:ellpadicfrobenius} If $p>2$ is a prime and $E$ is an elliptic curve on $\Q$ with good reduction at $p$, return the matrix of the Frobenius endomorphism $\varphi$ on the crystalline module $D_p(E)= \Q_p \otimes H^1_{dR}(E/\Q)$ with respect to the basis of the given model $(\omega, \eta=x\*\omega)$, where $\omega = dx/(2\*y+a_1\*x+a_3)$ is the invariant differential. The characteristic polynomial of $\varphi$ is $x^2 - a_p\*x + p$. The matrix is computed to absolute $p$-adic precision $p^n$. \bprog ? E = ellinit([1,-1,1,0,0]); ? F = ellpadicfrobenius(E,5,3); ? lift(F) %3 = [120 29] [ 55 5] ? charpoly(F) %4 = x^2 + O(5^3)*x + (5 + O(5^3)) ? ellap(E, 5) %5 = 0 @eprog The library syntax is \fun{GEN}{ellpadicfrobenius}{GEN E, long p, long n}. \subsec{ellpadicheight$(E,p,n, P,\{Q\})$}\kbdsidx{ellpadicheight}\label{se:ellpadicheight} Cyclotomic $p$-adic height of the rational point $P$ on the elliptic curve $E$ (defined over $\Q$), given to $n$ $p$-adic digits. If the argument $Q$ is present, computes the value of the bilinear form $(h(P+Q)-h(P-Q)) / 4$. Let $D := H^1_{dR}(E) \otimes_\Q \Q_p$ be the $\Q_p$ vector space spanned by $\omega$ (invariant differential $dx/(2y+a_1x+a3)$ related to the given model) and $\eta = x \omega$. Then the cyclotomic $p$-adic height $h_E$ associates to $P\in E(\Q)$ an element $f \omega + g \eta$ in $D$. This routine returns the vector $[f, g]$ to $n$ $p$-adic digits. If $P\in E(\Q)$ is in the kernel of reduction mod $p$ and if its reduction at all finite places is non singular, then $g = -(\log_E P)^2$, where $\log_E$ is the logarithm for the formal group of $E$ at $p$. If furthermore the model is of the form $Y^2 = X^3 + a X + b$ and $P = (x,y)$, then $$ f = \log_p(\kbd{denominator}(x)) - 2 \log_p(\sigma(P))$$ where $\sigma(P)$ is given by \kbd{ellsigma}$(E,P)$. Recall (\emph{Advanced topics in the arithmetic of elliptic curves}, Theorem~3.2) that the local height function over the complex numbers is of the form $$ \lambda(z) = -\log (|\kbd{E.disc}|) / 6 + \Re(z \eta(z)) - 2 \log( \sigma(z)). $$ (N.B. our normalization for local and global heights is twice that of Silverman's). \bprog ? E = ellinit([1,-1,1,0,0]); P = [0,0]; ? ellpadicheight(E,5,3, P) %2 = [3*5 + 5^2 + 2*5^3 + O(5^4), 5^2 + 4*5^4 + O(5^5)] ? E = ellinit("11a1"); P = [5,5]; \\ torsion point ? ellpadicheight(E,19,6, P) %4 = [0, 0] ? E = ellinit([0,0,1,-4,2]); P = [-2,1]; ? ellpadicheight(E,3,3, P) %6 = [2*3^2 + 2*3^3 + 3^4 + O(3^5), 2*3^2 + 3^4 + O(3^5)] ? ellpadicheight(E,3,5, P, elladd(E,P,P)) %7 = [3^2 + 2*3^3 + O(3^7), 3^2 + 3^3 + 2*3^4 + 3^5 + O(3^7)] @eprog \item When $E$ has good ordinary reduction at $p$ or non split multiplicative reduction, the ``canonical'' $p$-adic height is given by \bprog s2 = ellpadics2(E,p,n); ellpadicheight(E, p, n, P) * [1,-s2]~ @eprog\noindent Since $s_2$ does not depend on $P$, it is preferable to compute it only once: \bprog ? E = ellinit("5077a1"); p = 5; n = 7; \\ rank 3 ? s2 = ellpadics2(E,p,n); ? M = ellpadicheightmatrix(E,p, n, E.gen) * [1,-s2]~; ? matdet(M) \\ p-adic regulator on the points in E.gen %4 = 5 + 5^2 + 4*5^3 + 2*5^4 + 2*5^5 + 2*5^6 + O(5^7) @eprog \item When $E$ has split multiplicative reduction at $p$ (Tate curve), the ``canonical'' $p$-adic height is given by \bprog Ep = ellinit(E[1..5], O(p^(n))); \\ E seen as a Tate curve over Qp [u2,u,q] = Ep.tate; ellpadicheight(E, p, n, P) * [1,-s2 + 1/log(q)/u2]]~ @eprog\noindent where $s_2$ is as above. For example, \bprog ? E = ellinit("91b1"); P =[-1, 3]; p = 7; n = 5; ? Ep = ellinit(E[1..5], O(p^(n))); ? s2 = ellpadics2(E,p,n); ? [u2,u,q] = Ep.tate; ? H = ellpadicheight(E,p, n, P) * [1,-s2 + 1/log(q)/u2]~ %5 = 2*7 + 7^2 + 5*7^3 + 6*7^4 + 2*7^5 + O(7^6) @eprog These normalizations are chosen so that $p$-adic BSD conjectures are easy to state, see \tet{ellpadicbsd}. The library syntax is \fun{GEN}{ellpadicheight0}{GEN E, GEN p, long n, GEN P, GEN Q = NULL}. \subsec{ellpadicheightmatrix$(E,p,n,Q)$}\kbdsidx{ellpadicheightmatrix}\label{se:ellpadicheightmatrix} $Q$ being a vector of points, this function returns the ``Gram matrix'' $[F,G]$ of the cyclotomic $p$-adic height $h_E$ with respect to the basis $(\omega, \eta)$ of $D=H^1_{dR}(E) \otimes_\Q \Q_p$ given to $n$ $p$-adic digits. In other words, if \kbd{ellpadicheight}$(E,p,n, Q[i],Q[j]) = [f,g]$, corresponding to $f \omega + g \eta$ in $D$, then $F[i,j] = f$ and $G[i,j] = g$. \bprog ? E = ellinit([0,0,1,-7,6]); Q = [[-2,3],[-1,3]]; p = 5; n = 5; ? [F,G] = ellpadicheightmatrix(E,p,n,Q); ? lift(F) \\ p-adic entries, integral approximation for readability %3 = [2364 3100] [3100 3119] ? G %4 = [25225 46975] [46975 61850] ? [F,G] * [1,-ellpadics2(E,p,n)]~ %5 = [4 + 2*5 + 4*5^2 + 3*5^3 + O(5^5) 4*5^2 + 4*5^3 + 5^4 + O(5^5)] [ 4*5^2 + 4*5^3 + 5^4 + O(5^5) 4 + 3*5 + 4*5^2 + 4*5^3 + 5^4 + O(5^5)] @eprog The library syntax is \fun{GEN}{ellpadicheightmatrix}{GEN E, GEN p, long n, GEN Q}. \subsec{ellpadiclog$(E,p,n,P)$}\kbdsidx{ellpadiclog}\label{se:ellpadiclog} Given $E$ defined over $K = \Q$ or $\Q_p$ and $P = [x,y]$ on $E(K)$ in the kernel of reduction mod $p$, let $t(P) = -x/y$ be the formal group parameter; this function returns $L(t)$, where $L$ denotes the formal logarithm (mapping the formal group of $E$ to the additive formal group) attached to the canonical invariant differential: $dL = dx/(2y + a_1x + a_3)$. \bprog ? E = ellinit([0,0,1,-4,2]); P = [-2,1]; ? ellpadiclog(E,2,10,P) %2 = 2 + 2^3 + 2^8 + 2^9 + 2^10 + O(2^11) ? E = ellinit([17,42]); ? p=3; Ep = ellinit(E,p); \\ E mod p ? P=[114,1218]; ellorder(Ep,P) \\ the order of P on (E mod p) is 2 %5 = 2 ? Q = ellmul(E,P,2) \\ we need a point of the form 2*P %6 = [200257/7056, 90637343/592704] ? ellpadiclog(E,3,10,Q) %7 = 3 + 2*3^2 + 3^3 + 3^4 + 3^5 + 3^6 + 2*3^8 + 3^9 + 2*3^10 + O(3^11) @eprog The library syntax is \fun{GEN}{ellpadiclog}{GEN E, GEN p, long n, GEN P}. \subsec{ellpadicregulator$(E,p,n,S)$}\kbdsidx{ellpadicregulator}\label{se:ellpadicregulator} Let $E/\Q$ be an elliptic curve. Return the determinant of the Gram matrix of the vector of points $S=(S_1,\cdots, S_r)$ with respect to the ``canonical'' cyclotomic $p$-adic height on $E$, given to $n$ ($p$-adic) digits. When $E$ has ordinary reduction at $p$, this is the expected Gram deteterminant in $\Q_p$. In the case of supersingular reduction of $E$ at $p$, the definition requires care: the regulator $R$ is an element of $D := H^1_{dR}(E) \otimes_\Q \Q_p$, which is a two-dimensional $\Q_p$-vector space spanned by $\omega$ and $\eta = x \omega$ (which are defined over $\Q$) or equivalently but now over $\Q_p$ by $\omega$ and $F\omega$ where $F$ is the Frobenius endomorphism on $D$ as defined in \kbd{ellpadicfrobenius}. On $D$ we define the cyclotomic height $h_E = f \omega + g \eta$ (see \tet{ellpadicheight}) and a canonical alternating bilinear form $[.,.]_D$ such that $[\omega, \eta]_D = 1$. For any $\nu \in D$, we can define a height $h_\nu := [ h_E, \nu ]_D$ from $E(\Q)$ to $\Q_p$ and $\langle \cdot, \cdot \rangle_\nu$ the attached bilinear form. In particular, if $h_E = f \omega + g\eta$, then $h_\eta = [ h_E, \eta ]_D$ = f and $h_\omega = [ h_E, \omega ]_D = - g$ hence $h_E = h_\eta \omega - h_\omega \eta$. Then, $R$ is the unique element of $D$ such that $$[\omega,\nu]_D^{r-1} [R, \nu]_D = \det(\langle S_i, S_j \rangle_{\nu})$$ for all $\nu \in D$ not in $\Q_p \omega$. The \kbd{ellpadicregulator} function returns $R$ in the basis $(\omega, F\omega)$, which was chosen so that $p$-adic BSD conjectures are easy to state, see \kbd{ellpadicbsd}. Note that by definition $$[R, \eta]_D = \det(\langle S_i, S_j \rangle_{\eta})$$ and $$[R, \omega+\eta]_D =\det(\langle S_i, S_j \rangle_{\omega+\eta}).$$ The library syntax is \fun{GEN}{ellpadicregulator}{GEN E, GEN p, long n, GEN S}. \subsec{ellpadics2$(E,p,n)$}\kbdsidx{ellpadics2}\label{se:ellpadics2} If $p>2$ is a prime and $E/\Q$ is an elliptic curve with ordinary good reduction at $p$, returns the slope of the unit eigenvector of \kbd{ellpadicfrobenius(E,p,n)}, i.e., the action of Frobenius $\varphi$ on the crystalline module $D_p(E)= \Q_p \otimes H^1_{dR}(E/\Q)$ in the basis of the given model $(\omega, \eta=x\*\omega)$, where $\omega$ is the invariant differential $dx/(2\*y+a_1\*x+a_3)$. In other words, $\eta + s_2\omega$ is an eigenvector for the unit eigenvalue of $\varphi$. \bprog ? e=ellinit([17,42]); ? ellpadics2(e,13,4) %2 = 10 + 2*13 + 6*13^3 + O(13^4) @eprog This slope is the unique $c \in 3^{-1}\Z_p$ such that the odd solution $\sigma(t) = t + O(t^2)$ of $$ - d(\dfrac{1}{\sigma} \dfrac{d \sigma}{\omega}) = (x(t) + c) \omega$$ is in $t\Z_p[[t]]$. It is equal to $b_2/12 - E_2/12$ where $E_2$ is the value of the Katz $p$-adic Eisenstein series of weight 2 on $(E,\omega)$. This is used to construct a canonical $p$-adic height when $E$ has good ordinary reduction at $p$ as follows \bprog s2 = ellpadics2(E,p,n); h(E,p,n, P, s2) = ellpadicheight(E, [p,[1,-s2]],n, P); @eprog\noindent Since $s_2$ does not depend on the point $P$, we compute it only once. The library syntax is \fun{GEN}{ellpadics2}{GEN E, GEN p, long n}. \subsec{ellperiods$(w, \{\fl = 0\})$}\kbdsidx{ellperiods}\label{se:ellperiods} Let $w$ describe a complex period lattice ($w = [w_1,w_2]$ or an \kbd{ellinit} structure). Returns normalized periods $[W_1,W_2]$ generating the same lattice such that $\tau := W_1/W_2$ has positive imaginary part and lies in the standard fundamental domain for $\text{SL}_2(\Z)$. If $\fl = 1$, the function returns $[[W_1,W_2], [\eta_1,\eta_2]]$, where $\eta_1$ and $\eta_2$ are the quasi-periods attached to $[W_1,W_2]$, satisfying $\eta_2 W_1 - \eta_1 W_2 = 2 i \pi$. The output of this function is meant to be used as the first argument given to ellwp, ellzeta, ellsigma or elleisnum. Quasi-periods are needed by ellzeta and ellsigma only. \bprog ? L = ellperiods([1,I],1); ? [w1,w2] = L[1]; [e1,e2] = L[2]; ? e2*w1 - e1*w2 %3 = 6.2831853071795864769252867665590057684*I ? ellzeta(L, 1/2 + 2*I) %4 = 1.5707963... - 6.283185307...*I ? ellzeta([1,I], 1/2 + 2*I) \\ same but less efficient %4 = 1.5707963... - 6.283185307...*I @eprog The library syntax is \fun{GEN}{ellperiods}{GEN w, long flag, long prec}. \subsec{ellpointtoz$(E,P)$}\kbdsidx{ellpointtoz}\label{se:ellpointtoz} If $E/\C \simeq \C/\Lambda$ is a complex elliptic curve ($\Lambda = \kbd{E.omega}$), computes a complex number $z$, well-defined modulo the lattice $\Lambda$, corresponding to the point $P$; i.e.~such that $P = [\wp_\Lambda(z),\wp'_\Lambda(z)]$ satisfies the equation $$y^2 = 4x^3 - g_2 x - g_3,$$ where $g_2$, $g_3$ are the elliptic invariants. If $E$ is defined over $\R$ and $P\in E(\R)$, we have more precisely, $0 \leq \Re(t) < w1$ and $0 \leq \Im(t) < \Im(w2)$, where $(w1,w2)$ are the real and complex periods of $E$. \bprog ? E = ellinit([0,1]); P = [2,3]; ? z = ellpointtoz(E, P) %2 = 3.5054552633136356529375476976257353387 ? ellwp(E, z) %3 = 2.0000000000000000000000000000000000000 ? ellztopoint(E, z) - P %4 = [2.548947057811923643 E-57, 7.646841173435770930 E-57] ? ellpointtoz(E, [0]) \\ the point at infinity %5 = 0 @eprog If $E$ is defined over a general number field, the function returns the values corresponding to the various complex embeddings of the curve and of the point, in the same order as \kbd{E.nf.roots}: \bprog ? E=ellinit([-22032-15552*x,0], nfinit(x^2-2)); ? P=[-72*x-108,0]; ? ellisoncurve(E,P) %3 = 1 ? ellpointtoz(E,P) %4 = [-0.52751724240790530394437835702346995884*I, -0.090507650025885335533571758708283389896*I] ? E.nf.roots %5 = [-1.4142135623730950488016887242096980786, \\ x-> -sqrt(2) 1.4142135623730950488016887242096980786] \\ x-> sqrt(2) @eprog If $E/\Q_p$ has multiplicative reduction, then $E/\bar{\Q_p}$ is analytically isomorphic to $\bar{\Q}_p^*/q^\Z$ (Tate curve) for some $p$-adic integer $q$. The behavior is then as follows: \item If the reduction is split ($E.\kbd{tate[2]}$ is a \typ{PADIC}), we have an isomorphism $\phi: E(\Q_p) \simeq \Q_p^*/q^\Z$ and the function returns $\phi(P)\in \Q_p$. \item If the reduction is \emph{not} split ($E.\kbd{tate[2]}$ is a \typ{POLMOD}), we only have an isomorphism $\phi: E(K) \simeq K^*/q^\Z$ over the unramified quadratic extension $K/\Q_p$. In this case, the output $\phi(P)\in K$ is a \typ{POLMOD}. \bprog ? E = ellinit([0,-1,1,0,0], O(11^5)); P = [0,0]; ? [u2,u,q] = E.tate; type(u) \\ split multiplicative reduction %2 = "t_PADIC" ? ellmul(E, P, 5) \\ P has order 5 %3 = [0] ? z = ellpointtoz(E, [0,0]) %4 = 3 + 11^2 + 2*11^3 + 3*11^4 + 6*11^5 + 10*11^6 + 8*11^7 + O(11^8) ? z^5 %5 = 1 + O(11^9) ? E = ellinit(ellfromj(1/4), O(2^6)); x=1/2; y=ellordinate(E,x)[1]; ? z = ellpointtoz(E,[x,y]); \\ t_POLMOD of t_POL with t_PADIC coeffs ? liftint(z) \\ lift all p-adics %8 = Mod(8*u + 7, u^2 + 437) @eprog The library syntax is \fun{GEN}{zell}{GEN E, GEN P, long prec}. \subsec{ellpow$(E,z,n)$}\kbdsidx{ellpow}\label{se:ellpow} Deprecated alias for \kbd{ellmul}. The library syntax is \fun{GEN}{ellmul}{GEN E, GEN z, GEN n}. \subsec{ellratpoints$(E,h,\{\fl=0\})$}\kbdsidx{ellratpoints}\label{se:ellratpoints} $E$ being an integral model of elliptic curve , return a vector containing the affine rational points on the curve of naive height less than $h$. If $\fl=1$, stop as soon as a point is found; return either an empty vector or a vector containing a single point. See \kbd{hyperellratpoints} for how $h$ can be specified. \bprog ? E=ellinit([-25,1]); ? ellratpoints(E,10) %2 = [[-5,1],[-5,-1],[-3,7],[-3,-7],[-1,5],[-1,-5], [0,1],[0,-1],[5,1],[5,-1],[7,13],[7,-13]] ? ellratpoints(E,10,1) %3 = [[-5,1]] @eprog The library syntax is \fun{GEN}{ellratpoints}{GEN E, GEN h, long flag}. \subsec{ellrootno$(E,\{p\})$}\kbdsidx{ellrootno}\label{se:ellrootno} $E$ being an \kbd{ell} structure over $\Q$ as output by \kbd{ellinit}, this function computes the local root number of its $L$-series at the place $p$ (at the infinite place if $p = 0$). If $p$ is omitted, return the global root number and in this case the curve can also be defined over a number field. Note that the global root number is the sign of the functional equation and conjecturally is the parity of the rank of the \idx{Mordell-Weil group}. The equation for $E$ needs not be minimal at $p$, but if the model is already minimal the function will run faster. The library syntax is \fun{long}{ellrootno}{GEN E, GEN p = NULL}. \subsec{ellsea$(E,\{\var{tors}=0\})$}\kbdsidx{ellsea}\label{se:ellsea} Let $E$ be an \var{ell} structure as output by \kbd{ellinit}, defined over a finite field $\F_q$. This low-level function computes the order of the group $E(\F_q)$ using the SEA algorithm; compared to the high-level function \kbd{ellcard}, which includes SEA among its choice of algorithms, the \kbd{tors} argument allows to speed up a search for curves having almost prime order and whose quadratic twist may also have almost prime order. When \kbd{tors} is set to a non-zero value, the function returns $0$ as soon as it detects that the order has a small prime factor not dividing \kbd{tors}; SEA considers modular polynomials of increasing prime degree $\ell$ and we return $0$ as soon as we hit an $\ell$ (coprime to \kbd{tors}) dividing $\#E(\F_q)$: \bprog ? ellsea(ellinit([1,1], 2^56+3477), 1) %1 = 72057594135613381 ? forprime(p=2^128,oo, q = ellcard(ellinit([1,1],p)); if(isprime(q),break)) time = 6,571 ms. ? forprime(p=2^128,oo, q = ellsea(ellinit([1,1],p),1);if(isprime(q),break)) time = 522 ms. @eprog\noindent In particular, set \kbd{tors} to $1$ if you want a curve with prime order, to $2$ if you want to allow a cofactor which is a power of two (e.g. for Edwards's curves), etc. The early exit on bad curves yields a massive speedup compared to running the cardinal algorithm to completion. When \kbd{tors} is negative, similar checks are performed for the quadratic twist of the curve. The following function returns a curve of prime order over $\F_p$. \bprog cryptocurve(p) = { while(1, my(E, N, j = Mod(random(p), p)); E = ellinit(ellfromj(j)); N = ellsea(E, 1); if (!N, continue); if (isprime(N), return(E)); \\ try the quadratic twist for free if (isprime(2*p+2 - N), return(ellinit(elltwist(E)))); ); } ? p = randomprime([2^255, 2^256]); ? E = cryptocurve(p); \\ insist on prime order %2 = 47,447ms @eprog\noindent The same example without early abort (using \kbd{ellcard(E)} instead of \kbd{ellsea(E, 1)}) runs for about 5 minutes before finding a suitable curve. The availability of the \kbd{seadata} package will speed up the computation, and is strongly recommended. The generic function \kbd{ellcard} should be preferred when you only want to compute the cardinal of a given curve without caring about it having almost prime order: \item If the characteristic is too small ($p \leq 7$) or the field cardinality is tiny ($q \leq 523$) the generic algorithm \kbd{ellcard} is used instead and the \kbd{tors} argument is ignored. (The reason for this is that SEA is not implemented for $p \leq 7$ and that if $q \leq 523$ it is likely to run into an infinite loop.) \item If the field cardinality is smaller than about $2^{50}$, the generic algorithm will be faster. \item Contrary to \kbd{ellcard}, \kbd{ellsea} does not store the computed cardinality in $E$. The library syntax is \fun{GEN}{ellsea}{GEN E, long tors}. \subsec{ellsearch$(N)$}\kbdsidx{ellsearch}\label{se:ellsearch} This function finds all curves in the \tet{elldata} database satisfying the constraint defined by the argument $N$: \item if $N$ is a character string, it selects a given curve, e.g. \kbd{"11a1"}, or curves in the given isogeny class, e.g. \kbd{"11a"}, or curves with given conductor, e.g. \kbd{"11"}; \item if $N$ is a vector of integers, it encodes the same constraints as the character string above, according to the \tet{ellconvertname} correspondance, e.g. \kbd{[11,0,1]} for \kbd{"11a1"}, \kbd{[11,0]} for \kbd{"11a"} and \kbd{[11]} for \kbd{"11"}; \item if $N$ is an integer, curves with conductor $N$ are selected. If $N$ codes a full curve name, for instance \kbd{"11a1"} or \kbd{[11,0,1]}, the output format is $[N, [a_1,a_2,a_3,a_4,a_6], G]$ where $[a_1,a_2,a_3,a_4,a_6]$ are the coefficients of the Weierstrass equation of the curve and $G$ is a $\Z$-basis of the free part of the \idx{Mordell-Weil group} attached to the curve. \bprog ? ellsearch("11a3") %1 = ["11a3", [0, -1, 1, 0, 0], []] ? ellsearch([11,0,3]) %2 = ["11a3", [0, -1, 1, 0, 0], []] @eprog\noindent If $N$ is not a full curve name, then the output is a vector of all matching curves in the above format: \bprog ? ellsearch("11a") %1 = [["11a1", [0, -1, 1, -10, -20], []], ["11a2", [0, -1, 1, -7820, -263580], []], ["11a3", [0, -1, 1, 0, 0], []]] ? ellsearch("11b") %2 = [] @eprog The library syntax is \fun{GEN}{ellsearch}{GEN N}. Also available is \fun{GEN}{ellsearchcurve}{GEN N} that only accepts complete curve names (as \typ{STR}). \subsec{ellsigma$(L,\{z='x\},\{\fl=0\})$}\kbdsidx{ellsigma}\label{se:ellsigma} Computes the value at $z$ of the Weierstrass $\sigma$ function attached to the lattice $L$ as given by \tet{ellperiods}$(,1)$: including quasi-periods is useful, otherwise there are recomputed from scratch for each new $z$. $$ \sigma(z, L) = z \prod_{\omega\in L^*} \left(1 - \dfrac{z}{\omega}\right)e^{\dfrac{z}{\omega} + \dfrac{z^2}{2\omega^2}}.$$ It is also possible to directly input $L = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit} ($L = \kbd{E.omega}$). \bprog ? w = ellperiods([1,I], 1); ? ellsigma(w, 1/2) %2 = 0.47494937998792065033250463632798296855 ? E = ellinit([1,0]); ? ellsigma(E) \\ at 'x, implicitly at default seriesprecision %4 = x + 1/60*x^5 - 1/10080*x^9 - 23/259459200*x^13 + O(x^17) @eprog If $\fl=1$, computes an arbitrary determination of $\log(\sigma(z))$. The library syntax is \fun{GEN}{ellsigma}{GEN L, GEN z = NULL, long flag, long prec}. \subsec{ellsub$(E,\var{z1},\var{z2})$}\kbdsidx{ellsub}\label{se:ellsub} Difference of the points $z1$ and $z2$ on the elliptic curve corresponding to $E$. The library syntax is \fun{GEN}{ellsub}{GEN E, GEN z1, GEN z2}. \subsec{elltamagawa$(E)$}\kbdsidx{elltamagawa}\label{se:elltamagawa} The object $E$ being an elliptic curve over a number field, returns the global Tamagawa number of the curve (including the factor at infinite places). \bprog ? e = ellinit([1, -1, 1, -3002, 63929]); \\ curve "90c6" from elldata ? elltamagawa(e) %2 = 288 ? [elllocalred(e,p)[4] | p<-[2,3,5]] %3 = [6, 4, 6] ? vecprod(%) \\ since e.disc > 0 the factor at infinity is 2 %4 = 144 @eprog The library syntax is \fun{GEN}{elltamagawa}{GEN E}. \subsec{elltaniyama$(E, \{d = \var{seriesprecision}\})$}\kbdsidx{elltaniyama}\label{se:elltaniyama} Computes the modular parametrization of the elliptic curve $E/\Q$, where $E$ is an \kbd{ell} structure as output by \kbd{ellinit}. This returns a two-component vector $[u,v]$ of power series, given to $d$ significant terms (\tet{seriesprecision} by default), characterized by the following two properties. First the point $(u,v)$ satisfies the equation of the elliptic curve. Second, let $N$ be the conductor of $E$ and $\Phi: X_0(N)\to E$ be a modular parametrization; the pullback by $\Phi$ of the N\'eron differential $du/(2v+a_1u+a_3)$ is equal to $2i\pi f(z)dz$, a holomorphic differential form. The variable used in the power series for $u$ and $v$ is $x$, which is implicitly understood to be equal to $\exp(2i\pi z)$. The algorithm assumes that $E$ is a \emph{strong} \idx{Weil curve} and that the Manin constant is equal to 1: in fact, $f(x) = \sum_{n > 0} \kbd{ellan}(E, n) x^n$. The library syntax is \fun{GEN}{elltaniyama}{GEN E, long precdl}. \subsec{elltatepairing$(E, P, Q, m)$}\kbdsidx{elltatepairing}\label{se:elltatepairing} Computes the Tate pairing of the two points $P$ and $Q$ on the elliptic curve $E$. The point $P$ must be of $m$-torsion. The library syntax is \fun{GEN}{elltatepairing}{GEN E, GEN P, GEN Q, GEN m}. \subsec{elltors$(E)$}\kbdsidx{elltors}\label{se:elltors} If $E$ is an elliptic curve defined over a number field or a finite field, outputs the torsion subgroup of $E$ as a 3-component vector \kbd{[t,v1,v2]}, where \kbd{t} is the order of the torsion group, \kbd{v1} gives the structure of the torsion group as a product of cyclic groups (sorted by decreasing order), and \kbd{v2} gives generators for these cyclic groups. $E$ must be an \kbd{ell} structure as output by \kbd{ellinit}. \bprog ? E = ellinit([-1,0]); ? elltors(E) %1 = [4, [2, 2], [[0, 0], [1, 0]]] @eprog\noindent Here, the torsion subgroup is isomorphic to $\Z/2\Z \times \Z/2\Z$, with generators $[0,0]$ and $[1,0]$. The library syntax is \fun{GEN}{elltors}{GEN E}. \subsec{elltwist$(E,\{P\})$}\kbdsidx{elltwist}\label{se:elltwist} Returns the coefficients $[a_1,a_2,a_3,a_4,a_6]$ of the twist of the elliptic curve $E$ by the quadratic extension of the coefficient ring defined by $P$ (when $P$ is a polynomial) or \kbd{quadpoly(P)} when $P$ is an integer. If $E$ is defined over a finite field, then $P$ can be omitted, in which case a random model of the unique non-trivial twist is returned. If $E$ is defined over a number field, the model should be replaced by a minimal model (if one exists). Example: Twist by discriminant $-3$: \bprog ? elltwist(ellinit([0,a2,0,a4,a6]),-3) %1 = [0,-3*a2,0,9*a4,-27*a6] @eprog Twist by the Artin-Shreier extension given by $x^2+x+T$ in characteristic $2$: \bprog ? lift(elltwist(ellinit([a1,a2,a3,a4,a6]*Mod(1,2)),x^2+x+T)) %1 = [a1,a2+a1^2*T,a3,a4,a6+a3^2*T] @eprog Twist of an elliptic curve defined over a finite field: \bprog ? E=ellinit([1,7]*Mod(1,19));lift(elltwist(E)) %1 = [0,0,0,11,12] @eprog The library syntax is \fun{GEN}{elltwist}{GEN E, GEN P = NULL}. \subsec{ellweilcurve$(E, \{\&\var{ms}\})$}\kbdsidx{ellweilcurve}\label{se:ellweilcurve} If $E'$ is an elliptic curve over $\Q$, let $L_{E'}$ be the sub-$\Z$-module of $\Hom_{\Gamma_0(N)}(\Delta,\Q)$ attached to $E'$ (It is given by $x[3]$ if $[M,x] = \kbd{msfromell}(E')$.) On the other hand, if $N$ is the conductor of $E$ and $f$ is the modular form for $\Gamma_0(N)$ attached to $E$, let $L_f$ be the lattice of the $f$-component of $\Hom_{\Gamma_0(N)}(\Delta,\Q)$ given by the elements $\phi$ such that $\phi(\{0,\gamma^{-1} 0\}) \in \Z$ for all $\gamma \in \Gamma_0(N)$ (see \tet{mslattice}). Let $E'$ run through the isomorphism classes of elliptic curves isogenous to $E$ as given by \kbd{ellisomat} (and in the same order). This function returns a pair \kbd{[vE,vS]} where \kbd{vE} contains minimal models for the $E'$ and \kbd{vS} contains the list of Smith invariants for the lattices $L_{E'}$ in $L_f$. The function also accepts the output of \kbd{ellisomat}, i.e. the isogeny class. If the optional argument \kbd{ms} is present, it contains the output of \kbd{msfromell(vE, 0)}, i.e. the new modular symbol space $M$ of level $N$ and a vector of triples $[x^+,x^-, L]$ attached to each curve $E'$. In particular, the strong Weil curve amongst the curves isogenous to $E$ is the one whose Smith invariants are $[c,c]$, where $c$ is the Manin constant, conjecturally equal to $1$. \bprog ? E = ellinit("11a3"); ? [vE, vS] = ellweilcurve(E); ? [n] = [ i | i<-[1..#vS], vS[i]==[1,1] ] \\ lattice with invariant [1,1] %3 = [2] ? ellidentify(vE[n]) \\ ... corresponds to strong Weil curve %4 = [["11a1", [0, -1, 1, -10, -20], []], [1, 0, 0, 0]] ? [vE, vS] = ellweilcurve(E, &ms); \\ vE,vS are as above ? [M, vx] = ms; msdim(M) \\ ... but ms contains more information %6 = 3 ? #vx %7 = 3 ? vx[1] %8 = [[1/25, -1/10, -1/10]~, [0, 1/2, -1/2]~, [1/25,0; -3/5,1; 2/5,-1]] ? forell(E, 11,11, print(msfromell(ellinit(E[1]), 1)[2])) [1/5, -1/2, -1/2]~ [1, -5/2, -5/2]~ [1/25, -1/10, -1/10]~ @eprog\noindent The last example prints the modular symbols $x^+$ in $M^+$ attached to the curves \kbd{11a1}, \kbd{11a2} and \kbd{11a3}. The library syntax is \fun{GEN}{ellweilcurve}{GEN E, GEN *ms = NULL}. \subsec{ellweilpairing$(E, P, Q, m)$}\kbdsidx{ellweilpairing}\label{se:ellweilpairing} Computes the Weil pairing of the two points of $m$-torsion $P$ and $Q$ on the elliptic curve $E$. The library syntax is \fun{GEN}{ellweilpairing}{GEN E, GEN P, GEN Q, GEN m}. \subsec{ellwp$(w,\{z='x\},\{\fl=0\})$}\kbdsidx{ellwp}\label{se:ellwp} Computes the value at $z$ of the Weierstrass $\wp$ function attached to the lattice $w$ as given by \tet{ellperiods}. It is also possible to directly input $w = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit} ($w = \kbd{E.omega}$). \bprog ? w = ellperiods([1,I]); ? ellwp(w, 1/2) %2 = 6.8751858180203728274900957798105571978 ? E = ellinit([1,1]); ? ellwp(E, 1/2) %4 = 3.9413112427016474646048282462709151389 @eprog\noindent One can also compute the series expansion around $z = 0$: \bprog ? E = ellinit([1,0]); ? ellwp(E) \\ 'x implicitly at default seriesprecision %5 = x^-2 - 1/5*x^2 + 1/75*x^6 - 2/4875*x^10 + O(x^14) ? ellwp(E, x + O(x^12)) \\ explicit precision %6 = x^-2 - 1/5*x^2 + 1/75*x^6 + O(x^9) @eprog Optional \fl\ means 0 (default): compute only $\wp(z)$, 1: compute $[\wp(z),\wp'(z)]$. For instance, the Dickson elliptic functions \var{sm} and \var{sn} can be implemented as follows \bprog smcm(z) = { my(a, b, E = ellinit([0,-1/(4*27)])); \\ ell. invariants (g2,g3)=(0,1/27) [a,b] = ellwp(E, z, 1); [6*a / (1-3*b), (3*b+1)/(3*b-1)]; } ? [s,c] = smcm(0.5); ? s %2 = 0.4898258757782682170733218609 ? c %3 = 0.9591820206453842491187464098 ? s^3+c^3 %4 = 1.000000000000000000000000000 ? smcm('x + O('x^11)) %5 = [x - 1/6*x^4 + 2/63*x^7 - 13/2268*x^10 + O(x^11), 1 - 1/3*x^3 + 1/18*x^6 - 23/2268*x^9 + O(x^10)] @eprog The library syntax is \fun{GEN}{ellwp0}{GEN w, GEN z = NULL, long flag, long prec}. For $\fl = 0$, we also have \fun{GEN}{ellwp}{GEN w, GEN z, long prec}, and \fun{GEN}{ellwpseries}{GEN E, long v, long precdl} for the power series in variable $v$. \subsec{ellxn$(E,n,\{v='x\})$}\kbdsidx{ellxn}\label{se:ellxn} In standard notation, for any affine point $P = (v,w)$ on the curve $E$, we have $$[n]P = (\phi_n(P)\psi_n(P) : \omega_n(P) : \psi_n(P)^3)$$ for some polynomials $\phi_n,\omega_n,\psi_n$ in $\Z[a_1,a_2,a_3,a_4,a_6][v,w]$. This function returns $[\phi_n(P),\psi_n(P)^2]$, which give the numerator and denominator of the abscissa of $[n]P$ and depend only on $v$. \bprog ? E = ellinit([17,42]); ? T = ellxn(E, 2, 'X) %2 = [X^4 - 34*X^2 - 336*X + 289, 4*X^3 + 68*X + 168] ? P = [114,1218]; ellmul(E,P,2) %3 = [200257/7056, 90637343/592704] ? [x,y] = subst(T,'X,P[1]) \\ substitute P[1] in ellxn(E,2) %4 = [168416137, 5934096] \\ numerator and denominator of 2*P ? x/y \\ check we find ellmul(e,P,2)[1] %5 = 200257/7056 @eprog The library syntax is \fun{GEN}{ellxn}{GEN E, long n, long v = -1} where \kbd{v} is a variable number. \subsec{ellzeta$(w,\{z='x\})$}\kbdsidx{ellzeta}\label{se:ellzeta} Computes the value at $z$ of the Weierstrass $\zeta$ function attached to the lattice $w$ as given by \tet{ellperiods}$(,1)$: including quasi-periods is useful, otherwise there are recomputed from scratch for each new $z$. $$ \zeta(z, L) = \dfrac{1}{z} + z^2\sum_{\omega\in L^*} \dfrac{1}{\omega^2(z-\omega)}.$$ It is also possible to directly input $w = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit} ($w = \kbd{E.omega}$). The quasi-periods of $\zeta$, such that $$\zeta(z + a\omega_1 + b\omega_2) = \zeta(z) + a\eta_1 + b\eta_2 $$ for integers $a$ and $b$ are obtained as $\eta_i = 2\zeta(\omega_i/2)$. Or using directly \tet{elleta}. \bprog ? w = ellperiods([1,I],1); ? ellzeta(w, 1/2) %2 = 1.5707963267948966192313216916397514421 ? E = ellinit([1,0]); ? ellzeta(E, E.omega[1]/2) %4 = 0.84721308479397908660649912348219163647 @eprog\noindent One can also compute the series expansion around $z = 0$ (the quasi-periods are useless in this case): \bprog ? E = ellinit([0,1]); ? ellzeta(E) \\ at 'x, implicitly at default seriesprecision %4 = x^-1 + 1/35*x^5 - 1/7007*x^11 + O(x^15) ? ellzeta(E, x + O(x^20)) \\ explicit precision %5 = x^-1 + 1/35*x^5 - 1/7007*x^11 + 1/1440257*x^17 + O(x^18) @eprog\noindent The library syntax is \fun{GEN}{ellzeta}{GEN w, GEN z = NULL, long prec}. \subsec{ellztopoint$(E,z)$}\kbdsidx{ellztopoint}\label{se:ellztopoint} $E$ being an \var{ell} as output by \kbd{ellinit}, computes the coordinates $[x,y]$ on the curve $E$ corresponding to the complex or $p$-adic parameter $z$. Hence this is the inverse function of \kbd{ellpointtoz}. \item If $E$ is defined over a $p$-adic field and has multiplicative reduction, then $z$ is understood as an element on the Tate curve $\bar{Q}_p^* / q^\Z$. \bprog ? E = ellinit([0,-1,1,0,0], O(11^5)); ? [u2,u,q] = E.tate; type(u) %2 = "t_PADIC" \\ split multiplicative reduction ? z = ellpointtoz(E, [0,0]) %3 = 3 + 11^2 + 2*11^3 + 3*11^4 + 6*11^5 + 10*11^6 + 8*11^7 + O(11^8) ? ellztopoint(E,z) %4 = [O(11^9), O(11^9)] ? E = ellinit(ellfromj(1/4), O(2^6)); x=1/2; y=ellordinate(E,x)[1]; ? z = ellpointtoz(E,[x,y]); \\ non-split: t_POLMOD with t_PADIC coefficients ? P = ellztopoint(E, z); ? P[1] \\ y coordinate is analogous, more complicated %8 = Mod(O(2^4)*x + (2^-1 + O(2^5)), x^2 + (1 + 2^2 + 2^4 + 2^5 + O(2^7))) @eprog \item If $E$ is defined over the complex numbers (for instance over $\Q$), $z$ is understood as a complex number in $\C/\Lambda_E$. If the short Weierstrass equation is $y^2 = 4x^3 - g_2x - g_3$, then $[x,y]$ represents the Weierstrass $\wp$-function\sidx{Weierstrass $\wp$-function} and its derivative. For a general Weierstrass equation we have $$x = \wp(z) - b_2/12,\quad y = \wp'(z)/2 - (a_1 x + a_3)/2.$$ If $z$ is in the lattice defining $E$ over $\C$, the result is the point at infinity $[0]$. \bprog ? E = ellinit([0,1]); P = [2,3]; ? z = ellpointtoz(E, P) %2 = 3.5054552633136356529375476976257353387 ? ellwp(E, z) %3 = 2.0000000000000000000000000000000000000 ? ellztopoint(E, z) - P %4 = [2.548947057811923643 E-57, 7.646841173435770930 E-57] ? ellztopoint(E, 0) %5 = [0] \\ point at infinity @eprog The library syntax is \fun{GEN}{pointell}{GEN E, GEN z, long prec}. \subsec{genus2red$(\var{PQ},\{p\})$}\kbdsidx{genus2red}\label{se:genus2red} Let $PQ$ be a polynomial $P$, resp. a vector $[P,Q]$ of polynomials, with rational coefficients. Determines the reduction at $p > 2$ of the (proper, smooth) genus~2 curve $C/\Q$, defined by the hyperelliptic equation $y^2 = P(x)$, resp. $y^2 + Q(x)*y = P(x)$. (The special fiber $X_p$ of the minimal regular model $X$ of $C$ over $\Z$.) If $p$ is omitted, determines the reduction type for all (odd) prime divisors of the discriminant. \noindent This function was rewritten from an implementation of Liu's algorithm by Cohen and Liu (1994), \kbd{genus2reduction-0.3}, see \url{http://www.math.u-bordeaux.fr/~liu/G2R/}. \misctitle{CAVEAT} The function interface may change: for the time being, it returns $[N,\var{FaN}, T, V]$ where $N$ is either the local conductor at $p$ or the global conductor, \var{FaN} is its factorization, $y^2 = T$ defines a minimal model over $\Z[1/2]$ and $V$ describes the reduction type at the various considered~$p$. Unfortunately, the program is not complete for $p = 2$, and we may return the odd part of the conductor only: this is the case if the factorization includes the (impossible) term $2^{-1}$; if the factorization contains another power of $2$, then this is the exact local conductor at $2$ and $N$ is the global conductor. \bprog ? default(debuglevel, 1); ? genus2red(x^6 + 3*x^3 + 63, 3) (potential) stable reduction: [1, []] reduction at p: [III{9}] page 184, [3, 3], f = 10 %1 = [59049, Mat([3, 10]), x^6 + 3*x^3 + 63, [3, [1, []], ["[III{9}] page 184", [3, 3]]]] ? [N, FaN, T, V] = genus2red(x^3-x^2-1, x^2-x); \\ X_1(13), global reduction p = 13 (potential) stable reduction: [5, [Mod(0, 13), Mod(0, 13)]] reduction at p: [I{0}-II-0] page 159, [], f = 2 ? N %3 = 169 ? FaN %4 = Mat([13, 2]) \\ in particular, good reduction at 2 ! ? T %5 = x^6 + 58*x^5 + 1401*x^4 + 18038*x^3 + 130546*x^2 + 503516*x + 808561 ? V %6 = [[13, [5, [Mod(0, 13), Mod(0, 13)]], ["[I{0}-II-0] page 159", []]]] @eprog\noindent We now first describe the format of the vector $V = V_p$ in the case where $p$ was specified (local reduction at~$p$): it is a triple $[p, \var{stable}, \var{red}]$. The component $\var{stable} = [\var{type}, \var{vecj}]$ contains information about the stable reduction after a field extension; depending on \var{type}s, the stable reduction is \item 1: smooth (i.e. the curve has potentially good reduction). The Jacobian $J(C)$ has potentially good reduction. \item 2: an elliptic curve $E$ with an ordinary double point; \var{vecj} contains $j$ mod $p$, the modular invariant of $E$. The (potential) semi-abelian reduction of $J(C)$ is the extension of an elliptic curve (with modular invariant $j$ mod $p$) by a torus. \item 3: a projective line with two ordinary double points. The Jacobian $J(C)$ has potentially multiplicative reduction. \item 4: the union of two projective lines crossing transversally at three points. The Jacobian $J(C)$ has potentially multiplicative reduction. \item 5: the union of two elliptic curves $E_1$ and $E_2$ intersecting transversally at one point; \var{vecj} contains their modular invariants $j_1$ and $j_2$, which may live in a quadratic extension of $\F_p$ and need not be distinct. The Jacobian $J(C)$ has potentially good reduction, isomorphic to the product of the reductions of $E_1$ and $E_2$. \item 6: the union of an elliptic curve $E$ and a projective line which has an ordinary double point, and these two components intersect transversally at one point; \var{vecj} contains $j$ mod $p$, the modular invariant of $E$. The (potential) semi-abelian reduction of $J(C)$ is the extension of an elliptic curve (with modular invariant $j$ mod $p$) by a torus. \item 7: as in type 6, but the two components are both singular. The Jacobian $J(C)$ has potentially multiplicative reduction. The component $\var{red} = [\var{NUtype}, \var{neron}]$ contains two data concerning the reduction at $p$ without any ramified field extension. The \var{NUtype} is a \typ{STR} describing the reduction at $p$ of $C$, following Namikawa-Ueno, \emph{The complete classification of fibers in pencils of curves of genus two}, Manuscripta Math., vol. 9, (1973), pages 143-186. The reduction symbol is followed by the corresponding page number or page range in this article. The second datum \var{neron} is the group of connected components (over an algebraic closure of $\F_p$) of the N\'eron model of $J(C)$, given as a finite abelian group (vector of elementary divisors). \smallskip If $p = 2$, the \var{red} component may be omitted altogether (and replaced by \kbd{[]}, in the case where the program could not compute it. When $p$ was not specified, $V$ is the vector of all $V_p$, for all considered $p$. \misctitle{Notes about Namikawa-Ueno types} \item A lower index is denoted between braces: for instance, \kbd{[I\obr2\cbr-II-5]} means \kbd{[I\_2-II-5]}. \item If $K$ and $K'$ are Kodaira symbols for singular fibers of elliptic curves, then \kbd{[$K$-$K'$-m]} and \kbd{[$K'$-$K$-m]} are the same. We define a total ordering on Kodaira symbol by fixing $\kbd{I} < \kbd{I*} < \kbd{II} < \kbd{II*}, \dots$. If the reduction type is the same, we order by the number of components, e.g. $\kbd{I}_2 < \kbd{I}_4$, etc. Then we normalize our output so that $K \leq K'$. \item \kbd{[$K$-$K'$-$-1$]} is \kbd{[$K$-$K'$-$\alpha$]} in the notation of Namikawa-Ueno. \item The figure \kbd{[2I\_0-m]} in Namikawa-Ueno, page 159, must be denoted by \kbd{[2I\_0-(m+1)]}. The library syntax is \fun{GEN}{genus2red}{GEN PQ, GEN p = NULL}. \subsec{hyperellcharpoly$(X)$}\kbdsidx{hyperellcharpoly}\label{se:hyperellcharpoly} $X$ being a non-singular hyperelliptic curve defined over a finite field, return the characteristic polynomial of the Frobenius automorphism. $X$ can be given either by a squarefree polynomial $P$ such that $X: y^2 = P(x)$ or by a vector $[P,Q]$ such that $X: y^2 + Q(x)\*y = P(x)$ and $Q^2+4\*P$ is squarefree. The library syntax is \fun{GEN}{hyperellcharpoly}{GEN X}. \subsec{hyperellpadicfrobenius$(Q,p,n)$}\kbdsidx{hyperellpadicfrobenius}\label{se:hyperellpadicfrobenius} Let $X$ be the curve defined by $y^2=Q(x)$, where $Q$ is a polynomial of degree $d$ over $\Q$ and $p\ge d$ a prime such that $X$ has good reduction at $p$ return the matrix of the Frobenius endomorphism $\varphi$ on the crystalline module $D_p(X) = \Q_p \otimes H^1_{dR}(X/\Q)$ with respect to the basis of the given model $(\omega, x\*\omega,\ldots,x^{g-1}\*\omega)$, where $\omega = dx/(2\*y)$ is the invariant differential, where $g$ is the genus of $X$ (either $d=2\*g+1$ or $d=2\*g+2$). The characteristic polynomial of $\varphi$ is the numerator of the zeta-function of the reduction of the curve $X$ modulo $p$. The matrix is computed to absolute $p$-adic precision $p^n$. The library syntax is \fun{GEN}{hyperellpadicfrobenius}{GEN Q, ulong p, long n}. \subsec{hyperellratpoints$(X,h,\{\fl=0\})$}\kbdsidx{hyperellratpoints}\label{se:hyperellratpoints} $X$ being a non-singular hyperelliptic curve given by an integral model, return a vector containing the affine rational points on the curve of naive height less than $h$. If $\fl=1$, stop as soon as a point is found; return either an empty vector or a vector containing a single point. $X$ is given either by a squarefree polynomial $P$ such that $X: y^2=P(x)$ or by a vector $[P,Q]$ such that $X: y^2+Q(x)\*y=P(x)$ and $Q^2+4\*P$ is squarefree. \noindent The parameter $h$ can be \item an integer $H$: find the points $[n/d,y]$ whose abscissas $x = n/d$ have naive height (= $\max(|n|, d)$) less than $H$; \item a vector $[N,D]$ with $D\leq N$: find the points $[n/d,y]$ with $|n| \leq N$, $d \leq D$. \item a vector $[N,[D_1,D_2]]$ with $D_1 k_1 + 1$. \item [Analytic continuation] $L(s)$ has a meromorphic continuation to the whole complex plane with finitely many poles. \item [Functional equation] There exist an integer $k$, a complex number $\epsilon$ (usually of modulus~$1$), and an attached sequence $a^*$ defining both an $L$-function $L(a^*,s)$ satisfying the above two assumptions and a completed function $\Lambda(a^*,s) = N^{s/2}\gamma_A(s) \cdot L(a^*,s)$, such that $$\Lambda(a,k-s) = \epsilon \Lambda(a^*,s)$$ for all regular points. More often than not in number theory we have $a^* = \overline{a}$ (which forces $|\epsilon| = 1$), but this needs not be the case. If $a$ is a real sequence and $a = a^*$, we say that $L$ is \emph{self-dual}. We do not assume that the $a_n$ are multiplicative, nor equivalently that $L(s)$ has an Euler product. \misctitle{Remark} Of course, $a$ determines the $L$-function, but the (redundant) datum $a,a^*, A, N, k, \epsilon$ describes the situation in a form more suitable for fast computations; knowing the polar part $r$ of $\Lambda(s)$ (a rational function such that $\Lambda-r$ is holomorphic) is also useful. A subset of these, including only finitely many $a_n$-values will still completely determine $L$ (in suitable families), and we provide routines to try and compute missing invariants from whatever information is available. \misctitle{Important Caveat} The implementation assumes that the implied constants in the $O_\epsilon$ are small. In our generic framework, it is impossible to return proven results without more detailed information about the $L$ function. The intended use of the $L$-function package is not to prove theorems, but to experiment and formulate conjectures, so all numerical results should be taken with a grain of salt. One can always increase \kbd{realbitprecision} and recompute: the difference estimates the actual absolute error in the original output. \misctitle{Note} The requested precision has a major impact on runtimes. Because of this, most $L$-function routines, in particular \kbd{lfun} itself, specify the requested precision in \emph{bits}, not in decimal digits. This is transparent for the user once \tet{realprecision} or \tet{realbitprecision} are set. We advise to manipulate precision via \tet{realbitprecision} as it allows finer granularity: \kbd{realprecision} increases by increments of 64 bits, i.e. 19 decimal digits at a time. \subsec{Theta functions} Given an $L$-function as above, we define an attached theta function via Mellin inversion: for any positive real $t > 0$, we let $$ \theta(a,t) := \dfrac{1}{2\pi i}\int_{\Re(s) = c} t^{-s} \Lambda(s)\, ds $$ where $c$ is any positive real number $c > k_1+1$ such that $c + \Re(a) > 0$ for all $a\in A$. In fact, we have $$\theta(a,t) = \sum_{n\geq 1} a_n K(nt/N^{1/2}) \quad\text{where}\quad K(t) := \dfrac{1}{2\pi i}\int_{\Re(s) = c} t^{-s} \gamma_A(s)\, ds.$$ Note that this function is analytic and actually makes sense for complex $t$, such that $\Re(t^{2/d}) > 0$, i.e. in a cone containing the positive real half-line. The functional equation for $\Lambda$ translates into $$ \theta(a,1/t) - \epsilon t^k\theta(a^*,t) = P_\Lambda(t), $$ where $P_\Lambda$ is an explicit polynomial in $t$ and $\log t$ given by the Taylor development of the polar part of $\Lambda$: there are no $\log$'s if all poles are simple, and $P = 0$ if $\Lambda$ is entire. The values $\theta(t)$ are generally easier to compute than the $L(s)$, and this functional equation provides a fast way to guess possible values for missing invariants in the $L$-function definition. \subsec{Data structures describing $L$ and theta functions} We have 3 levels of description: \item an \tet{Lmath} is an arbitrary description of the underlying mathematical situation (to which e.g., we associate the $a_p$ as traces of Frobenius elements); this is done via constructors to be described in the subsections below. \item an \tet{Ldata} is a computational description of situation, containing the complete datum ($a,a^*,A,k,N,\epsilon,r$). Where $a$ and $a^*$ describe the coefficients (given $n,b$ we must be able to compute $[a_1,\dots,a_n]$ with bit accuracy $b$), $A$ describes the Euler factor, the (classical) weight is $k$, $N$ is the conductor, and $r$ describes the polar part of $L(s)$. This is obtained via the function \tet{lfuncreate}. N.B. For motivic $L$-functions, the motivic weight $w$ is $w = k-1$; but we also support non-motivic $L$-functions. \misctitle{Design problem} All components of an \kbd{Ldata} should be given exactly since the accuracy to which they must be computed is not bounded a priori; but this is not always possible, in particular for $\epsilon$ and $r$. \item an \tet{Linit} contains an \kbd{Ldata} and everything needed for fast \emph{numerical} computations. It specifies the functions to be considered (either $L^{(j)}(s)$ or $\theta^{(j)}(t)$ for derivatives of order $j \leq m$, where $m$ is now fixed) and specifies a \emph{domain} which limits the range of arguments ($t$ or $s$, respectively to certain cones and rectangular regions) and the output accuracy. This is obtained via the functions \tet{lfuninit} or \tet{lfunthetainit}. All the functions which are specific to $L$ or theta functions share the prefix \kbd{lfun}. They take as first argument either an \kbd{Lmath}, an \kbd{Ldata}, or an \kbd{Linit}. If a single value is to be computed, this makes no difference, but when many values are needed (e.g. for plots or when searching for zeros), one should first construct an \kbd{Linit} attached to the search range and use it in all subsequent calls. If you attempt to use an \kbd{Linit} outside the range for which it was initialized, a warning is issued, because the initialization is performed again, a major inefficiency: \bprog ? Z = lfuncreate(1); \\ Riemann zeta ? L = lfuninit(Z, [1/2, 0, 100]); \\ zeta(1/2+it), |t| < 100 ? lfun(L, 1/2) \\ OK, within domain %3 = -1.4603545088095868128894991525152980125 ? lfun(L, 0) \\ not on critical line ! *** lfun: Warning: lfuninit: insufficient initialization. %4 = -0.50000000000000000000000000000000000000 ? lfun(L, 1/2, 1) \\ attempt first derivative ! *** lfun: Warning: lfuninit: insufficient initialization. %5 = -3.9226461392091517274715314467145995137 @eprog For many $L$-functions, passing from \kbd{Lmath} to an \kbd{Ldata} is inexpensive: in that case one may use \kbd{lfuninit} directly from the \kbd{Lmath} even when evaluations in different domains are needed. The above example could equally have skipped the \kbd{lfuncreate}: \bprog ? L = lfuninit(1, [1/2, 0, 100]); \\ zeta(1/2+it), |t| < 100 @eprog\noindent In fact, when computing a single value, you can even skip \kbd{lfuninit}: \bprog ? L = lfun(1, 1/2, 1); \\ zeta'(1/2) ? L = lfun(1, 1+x+O(x^5)); \\ first 5 terms of Taylor development at 1 @eprog\noindent Both give the desired results with no warning. \misctitle{Complexity} The implementation requires $O(N(|t|+1))^{1/2}$ coefficients $a_n$ to evaluate $L$ of conductor $N$ at $s = \sigma + i t$. We now describe the available high-level constructors, for built-in $L$ functions. \subsec{Dirichlet $L$-functions} %GPHELPskip Given a Dirichlet character $\chi:(\Z/N\Z)^*\to \C$, we let $$L(\chi, s) = \sum_{n\geq 1} \chi(n) n^{-s}.$$ Only primitive characters are supported. Given a fundamental discriminant $D$, the function $L((D/.), s)$, for the quadratic Kronecker symbol, is encoded by the \typ{INT} $D$. This includes Riemann $\zeta$ function via the special case $D = 1$. More general characters can be represented in a variety of ways: \item via Conrey notation (see \tet{znconreychar}): $\chi_N(m,\cdot)$ is given as the \typ{INTMOD} \kbd{Mod(m,N)}. \item via a \var{znstar} structure describing the abelian group $(\Z/N\Z)^*$, where the character is given in terms of the \var{znstar} generators: \bprog ? G = znstar(100, 1); \\ (Z/100Z)^* ? G.cyc \\ ~ Z/20 . g1 + Z/2 . g2 for some generators g1 and g2 %2 = [20, 2] ? G.gen %3 = [77, 51] ? chi = [a, b] \\ maps g1 to e(a/20) and g2 to e(b/2); e(x) = exp(2ipi x) @eprog\noindent More generally, let $(\Z/N\Z)^* = \oplus (\Z/d_i\Z) g_i$ be given via a \var{znstar} structure $G$ (\kbd{G.cyc} gives the $d_i$ and \kbd{G.gen} the $g_i$). A \tev{character} $\chi$ on $G$ is given by a row vector $v = [a_1,\ldots,a_n]$ such that $\chi(\prod g_i^{n_i}) = \exp(2\pi i\sum a_i n_i / d_i)$. The pair $[G, v]$ encodes the \emph{primitive} character attached to $\chi$. \item in fact, this construction $[G, m]$ describing a character is more general: $m$ is also allowed to be a Conrey index as seen above, or a Conrey logarithm (see \tet{znconreylog}), and the latter format is actually the fastest one. \item it is also possible to view Dirichlet characters as Hecke characters over $K = \Q$ (see below), for a modulus $[N, [1]]$ but this is both more complicated and less efficient. In all cases, a non-primitive character is replaced by the attached primitive character. \subsec{Hecke $L$-functions} %GPHELPskip The Dedekind zeta function of a number field $K = \Q[X]/(T)$ is encoded either by the defining polynomial $T$, or any absolute number fields structure (preferably at least a \var{bnf}). Given a finite order Hecke character $\chi: Cl_f(K)\to \C$, we let $$L(\chi, s) = \sum_{A \subset O_K} \chi(A)\, \left(N_{K/\Q}A\right)^{-s}.$$ Let $Cl_f(K) = \oplus (\Z/d_i\Z) g_i$ given by a \var{bnr} structure with generators: the $d_i$ are given by \kbd{K.cyc} and the $g_i$ by \kbd{K.gen}. A \tev{character} $\chi$ on the ray class group is given by a row vector $v = [a_1,\ldots,a_n]$ such that $\chi(\prod g_i^{n_i}) = \exp(2\pi i\sum a_i n_i / d_i)$. The pair $[\var{bnr}, v]$ encodes the \emph{primitive} character attached to $\chi$. \bprog ? K = bnfinit(x^2-60); ? Cf = bnrinit(K, [7, [1,1]], 1); \\ f = 7 oo_1 oo_2 ? Cf.cyc %3 = [6, 2, 2] ? Cf.gen %4 = [[2, 1; 0, 1], [22, 9; 0, 1], [-6, 7]~] ? lfuncreate([Cf, [1,0,0]]); \\@com $\chi(g_1) = \zeta_6$, $\chi(g_2)=\chi(g_3)=1$ @eprog \noindent Dirichlet characters on $(\Z/N\Z)^*$ are a special case, where $K = \Q$: \bprog ? Q = bnfinit(x); ? Cf = bnrinit(Q, [100, [1]]); \\ for odd characters on (Z/100Z)* @eprog\noindent For even characters, replace by \kbd{bnrinit(K, N)}. Note that the simpler direct construction in the previous section will be more efficient. \subsec{Artin $L$ functions} %GPHELPskip Given a Galois number field $N/\Q$ with group $G = \kbd{galoisinit}(N)$, a representation $\rho$ of $G$ over the cyclotomic field $\Q(\zeta_n)$ is specified by the matrices giving the images of $\kbd{G.gen}$ by $\rho$. The corresponding Artin $L$ function is created using \tet{lfunartin}. \bprog P = quadhilbert(-47); \\ degree 5, Galois group D_5 N = nfinit(nfsplitting(P)); \\ Galois closure G = galoisinit(N); [s,t] = G.gen; \\ order 5 and 2 L = lfunartin(N,G, [[a,0;0,a^-1],[0,1;1,0]], 5); \\ irr. degree 2 @eprog\noindent In the above, the polynomial variable (here \kbd{a}) represents $\zeta_5 := \exp(2i\pi/5)$ and the two matrices give the images of $s$ and $t$. Here, priority of \kbd{a} must be lower than the priority of \kbd{x}. \subsec{$L$-functions of algebraic varieties} %GPHELPskip $L$-function of elliptic curves over number fields are supported. \bprog ? E = ellinit([1,1]); ? L = lfuncreate(E); \\ L-function of E/Q ? E2 = ellinit([1,a], nfinit(a^2-2)); ? L2 = lfuncreate(E2); \\ L-function of E/Q(sqrt(2)) @eprog $L$-function of hyperelliptic genus-$2$ curve can be created with \kbd{lfungenus2}. To create the $L$ function of the curve $y^2+(x^3+x^2+1)y = x^2+x$: \bprog ? L = lfungenus2([x^2+x, x^3+x^2+1]); @eprog Currently, the model needs to be minimal at $2$, and if the conductor is even, its valuation at $2$ might be incorrect (a warning is issued). \subsec{Eta quotients / Modular forms} %GPHELPskip An eta quotient is created by applying \tet{lfunetaquo} to a matrix with 2 columns $[m, r_m]$ representing $$ f(\tau) := \prod_m \eta(m\tau)^{r_m}. $$ It is currently assumed that $f$ is a self-dual cuspidal form on $\Gamma_0(N)$ for some $N$. For instance, the $L$-function $\sum \tau(n) n^{-s}$ attached to Ramanujan's $\Delta$ function is encoded as follows \bprog ? L = lfunetaquo(Mat([1,24])); ? lfunan(L, 100) \\ first 100 values of tau(n) @eprog More general modular forms defined by modular symbols will be added later. \subsec{Low-level Ldata format} %GPHELPskip When no direct constructor is available, you can still input an $L$ function directly by supplying $[a, a^*,A, k, N, \epsilon, r]$ to \kbd{lfuncreate} (see \kbd{??lfuncreate} for details). It is \emph{strongly} suggested to first check consistency of the created $L$-function: \bprog ? L = lfuncreate([a, as, A, k, N, eps, r]); ? lfuncheckfeq(L) \\ check functional equation @eprog \subsec{lfun$(L,s,\{D=0\})$}\kbdsidx{lfun}\label{se:lfun} Compute the L-function value $L(s)$, or if \kbd{D} is set, the derivative of order \kbd{D} at $s$. The parameter \kbd{L} is either an Lmath, an Ldata (created by \kbd{lfuncreate}, or an Linit (created by \kbd{lfuninit}), preferrably the latter if many values are to be computed. The argument $s$ is also allowed to be a power series; for instance, if $s = \alpha + x + O(x^n)$, the function returns the Taylor expansion of order $n$ around $\alpha$. The result is given with absolute error less than $2^{-B}$, where $B = \text{realbitprecision}$. \misctitle{Caveat} The requested precision has a major impact on runtimes. It is advised to manipulate precision via \tet{realbitprecision} as explained above instead of \tet{realprecision} as the latter allows less granularity: \kbd{realprecision} increases by increments of 64 bits, i.e. 19 decimal digits at a time. \bprog ? lfun(x^2+1, 2) \\ Lmath: Dedekind zeta for Q(i) at 2 %1 = 1.5067030099229850308865650481820713960 ? L = lfuncreate(ellinit("5077a1")); \\ Ldata: Hasse-Weil zeta function ? lfun(L, 1+x+O(x^4)) \\ zero of order 3 at the central point %3 = 0.E-58 - 5.[...] E-40*x + 9.[...] E-40*x^2 + 1.7318[...]*x^3 + O(x^4) \\ Linit: zeta(1/2+it), |t| < 100, and derivative ? L = lfuninit(1, [100], 1); ? T = lfunzeros(L, [1,25]); %5 = [14.134725[...], 21.022039[...]] ? z = 1/2 + I*T[1]; ? abs( lfun(L, z) ) %7 = 8.7066865533412207420780392991125136196 E-39 ? abs( lfun(L, z, 1) ) %8 = 0.79316043335650611601389756527435211412 \\ simple zero @eprog The library syntax is \fun{GEN}{lfun0}{GEN L, GEN s, long D, long bitprec}. \subsec{lfunabelianrelinit$(\var{bnfL},\var{bnfK},\var{polrel},\var{sdom},\{\var{der}=0\})$}\kbdsidx{lfunabelianrelinit}\label{se:lfunabelianrelinit} Returns the \kbd{Linit} structure attached to the Dedekind zeta function of the number field $L$ (see \tet{lfuninit}), given a subfield $K$ such that $L/K$ is abelian. Here \kbd{polrel} defines $L$ over $K$, as usual with the priority of the variable of \kbd{bnfK} lower than that of \kbd{polrel}. \kbd{sdom} and \kbd{der} are as in \kbd{lfuninit}. \bprog ? D = -47; K = bnfinit(y^2-D); ? rel = quadhilbert(D); T = rnfequation(K.pol, rel); \\ degree 10 ? L = lfunabelianrelinit(T,K,rel, [2,0,0]); \\ at 2 time = 84 ms. ? lfun(L, 2) %4 = 1.0154213394402443929880666894468182650 ? lfun(T, 2) \\ using parisize > 300MB time = 652 ms. %5 = 1.0154213394402443929880666894468182656 @eprog\noindent As the example shows, using the (abelian) relative structure is more efficient than a direct computation. The difference becomes drastic as the absolute degree increases while the subfield degree remains constant. The library syntax is \fun{GEN}{lfunabelianrelinit}{GEN bnfL, GEN bnfK, GEN polrel, GEN sdom, long der, long bitprec}. \subsec{lfunan$(L,n)$}\kbdsidx{lfunan}\label{se:lfunan} Compute the first $n$ terms of the Dirichlet series attached to the $L$-function given by \kbd{L} (\kbd{Lmath}, \kbd{Ldata} or \kbd{Linit}). \bprog ? lfunan(1, 10) \\ Riemann zeta %1 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ? lfunan(5, 10) \\ Dirichlet L-function for kronecker(5,.) %2 = [1, -1, -1, 1, 0, 1, -1, -1, 1, 0] @eprog The library syntax is \fun{GEN}{lfunan}{GEN L, long n, long prec}. \subsec{lfunartin$(\var{nf},\var{gal},\var{rho},n)$}\kbdsidx{lfunartin}\label{se:lfunartin} Returns the \kbd{Ldata} structure attached to the Artin $L$-function provided by the representation $\rho$ of the Galois group of the extension $K/\Q$, defined over the cyclotomic field $\Q(\zeta_n)$, where \var{nf} is the nfinit structure attached to $K$, \var{gal} is the galoisinit structure attached to $K/\Q$, and \var{rho} is given either \item by the values of its character on the conjugacy classes (see \kbd{galoisconjclasses} and \kbd{galoischartable}) \item or by the matrices that are the images of the generators \kbd{\var{gal}.gen}. Cyclotomic numbers in \kbd{rho} are represented by polynomials, whose variable is understood as the complex number $\exp(2\*i\*\pi/n)$. In the following example we build the Artin $L$-functions attached to the two irreducible degree $2$ representations of the dihedral group $D_{10}$ defined over $\Q(\zeta_5)$, for the extension $H/\Q$ where $H$ is the Hilbert class field of $\Q(\sqrt{-47})$. We show numerically some identities involving Dedekind $\zeta$ functions and Hecke $L$ series. \bprog ? P = quadhilbert(-47) %1 = x^5 + 2*x^4 + 2*x^3 + x^2 - 1 ? N = nfinit(nfsplitting(P)); ? G = galoisinit(N); \\ D_10 ? [T,n] = galoischartable(G); ? T \\ columns give the irreducible characters %5 = [1 1 2 2] [1 -1 0 0] [1 1 -y^3 - y^2 - 1 y^3 + y^2] [1 1 y^3 + y^2 -y^3 - y^2 - 1] ? n %6 = 5 ? L2 = lfunartin(N,G, T[,2], n); ? L3 = lfunartin(N,G, T[,3], n); ? L4 = lfunartin(N,G, T[,4], n); ? s = 1 + x + O(x^4); ? lfun(-47,s) - lfun(L2,s) %11 ~ 0 ? lfun(1,s)*lfun(-47,s)*lfun(L3,s)^2*lfun(L4,s)^2 - lfun(N,s) %12 ~ 0 ? lfun(1,s)*lfun(L3,s)*lfun(L4,s) - lfun(P,s) %13 ~ 0 ? bnr = bnrinit(bnfinit(x^2+47),1,1); ? bnr.cyc %15 = [5] \\ Z/5Z: 4 non-trivial ray class characters ? lfun([bnr,[1]], s) - lfun(L3, s) %16 ~ 0 ? lfun([bnr,[2]], s) - lfun(L4, s) %17 ~ 0 ? lfun([bnr,[3]], s) - lfun(L3, s) %18 ~ 0 ? lfun([bnr,[4]], s) - lfun(L4, s) %19 ~ 0 @eprog The first identity identifies the non-trivial abelian character with $(-47,\cdot)$; the second is the factorization of the regular representation of $D_{10}$; the third is the factorization of the natural representation of $D_{10}\subset S_5$; and the final four are the expressions of the degree $2$ representations as induced from degree $1$ representations. The library syntax is \fun{GEN}{lfunartin}{GEN nf, GEN gal, GEN rho, long n, long bitprec}. \subsec{lfuncheckfeq$(L,\{t\})$}\kbdsidx{lfuncheckfeq}\label{se:lfuncheckfeq} Given the data attached to an $L$-function (\kbd{Lmath}, \kbd{Ldata} or \kbd{Linit}), check whether the functional equation is satisfied. This is most useful for an \kbd{Ldata} constructed ``by hand'', via \kbd{lfuncreate}, to detect mistakes. If the function has poles, the polar part must be specified. The routine returns a bit accuracy $b$ such that $|w - \hat{w}| < 2^{b}$, where $w$ is the root number contained in \kbd{data}, and $$\hat{w} = \theta(1/t) t^{-k} / \overline{\theta}(t)$$ is a computed value derived from the assumed functional equation. If the parameter $t$ is omitted, we try random samples on the real line in the segment $[1, 1.25]$. Of course, a large negative value of the order of \kbd{realbitprecision} is expected but if $\overline{\theta}$ is very small all over the sampled segment, you should first increase \kbd{realbitprecision} by $-\log_2 |\overline{\theta}(t)|$ (which is positive if $\theta$ is small) to get a meaningful result. If $t$ is given, it should be close to the unit disc for efficiency and such that $\overline{\theta}(t) \neq 0$. We then check the functional equation at that $t$. Again, if $\overline{\theta}(t)$ is very small, you should first increase \kbd{realbitprecision} to get a useful result. \bprog ? \pb 128 \\ 128 bits of accuracy ? default(realbitprecision) %1 = 128 ? L = lfuncreate(1); \\ Riemann zeta ? lfuncheckfeq(L) %3 = -124 @eprog\noindent i.e. the given data is consistent to within 4 bits for the particular check consisting of estimating the root number from all other given quantities. Checking away from the unit disc will either fail with a precision error, or give disappointing results (if $\theta(1/t)$ is large it will be computed with a large absolute error) \bprog ? lfuncheckfeq(L, 2+I) %4 = -115 ? lfuncheckfeq(L,10) *** at top-level: lfuncheckfeq(L,10) *** ^------------------ *** lfuncheckfeq: precision too low in lfuncheckfeq. @eprog The library syntax is \fun{long}{lfuncheckfeq}{GEN L, GEN t = NULL, long bitprec}. \subsec{lfunconductor$(L,\{\var{ab}=[1,10000]\},\{\fl=0\})$}\kbdsidx{lfunconductor}\label{se:lfunconductor} Compute the conductor of the given $L$-function (if the structure contains a conductor, it is ignored); $\kbd{ab} = [a,b]$ is the interval where we expect to find the conductor; it may be given as a single scalar $b$, in which case we look in $[1,b]$. Increasing \kbd{ab} slows down the program but gives better accuracy for the result. If \kbd{flag} is $0$ (default), give either the conductor found as an integer, or a vector (possibly empty) of conductors found. If \kbd{flag} is $1$, same but give the computed floating point approximations to the conductors found, without rounding to integers. It \kbd{flag} is $2$, give all the conductors found, even those far from integers. \misctitle{Caveat} This is a heuristic program and the result is not proven in any way: \bprog ? L = lfuncreate(857); \\ Dirichlet L function for kronecker(857,.) ? \p19 realprecision = 19 significant digits ? lfunconductor(L) %2 = [17, 857] ? lfunconductor(L,,1) \\ don't round %3 = [16.99999999999999999, 857.0000000000000000] ? \p38 realprecision = 38 significant digits ? lfunconductor(L) %4 = 857 @eprog \misctitle{Note} This program should only be used if the primes dividing the conductor are unknown, which is rare. If they are known, a direct search through possible prime exponents using \kbd{lfuncheckfeq} will be more efficient and rigorous: \bprog ? E = ellinit([0,0,0,4,0]); /* Elliptic curve y^2 = x^3+4x */ ? E.disc \\ |disc E| = 2^12 %2 = -4096 \\ create Ldata by hand. Guess that root number is 1 and conductor N ? L(N) = lfuncreate([n->ellan(E,n), 0, [0,1], 2, N, 1]); ? fordiv(E.disc, d, print(d,": ",lfuncheckfeq(L(d)))) 1: 0 2: 0 4: -1 8: -2 16: -3 32: -127 64: -3 128: -2 256: -2 512: -1 1024: -1 2048: 0 4096: 0 ? lfunconductor(L(1)) \\ lfunconductor ignores conductor = 1 in Ldata ! %5 = 32 @eprog\noindent The above code assumed that root number was $1$; had we set it to $-1$, none of the \kbd{lfuncheckfeq} values would have been acceptable: \bprog ? L2(N) = lfuncreate([n->ellan(E,n), 0, [0,1], 2, N, -1]); ? [ lfuncheckfeq(L2(d)) | d<-divisors(E.disc) ] %7 = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, -1, -1] @eprog The library syntax is \fun{GEN}{lfunconductor}{GEN L, GEN ab = NULL, long 10000], long bitprec}. \subsec{lfuncost$(L,\{\var{sdom}\},\{\var{der}=0\})$}\kbdsidx{lfuncost}\label{se:lfuncost} Estimate the cost of running \kbd{lfuninit(L,sdom,der)} at current bit precision. Returns $[t,b]$, to indicate that $t$ coefficients $a_n$ will be computed, as well as $t$ values of \tet{gammamellininv}, all at bit accuracy $b$. A subsequent call to \kbd{lfun} at $s$ evaluates a polynomial of degree $t$ at $\exp(h s)$ for some real parameter $h$, at the same bit accuracy $b$. If $L$ is already an \kbd{Linit}, then \var{sdom} and \var{der} are ignored and are best left omitted; the bit accuracy is also inferred from $L$: in short we get an estimate of the cost of using that particular \kbd{Linit}. \bprog ? \pb 128 ? lfuncost(1, [100]) \\ for zeta(1/2+I*t), |t| < 100 %1 = [7, 242] \\ 7 coefficients, 242 bits ? lfuncost(1, [1/2, 100]) \\ for zeta(s) in the critical strip, |Im s| < 100 %2 = [7, 246] \\ now 246 bits ? lfuncost(1, [100], 10) \\ for zeta(1/2+I*t), |t| < 100 %3 = [8, 263] \\ 10th derivative increases the cost by a small amount ? lfuncost(1, [10^5]) %3 = [158, 113438] \\ larger imaginary part: huge accuracy increase ? L = lfuncreate(polcyclo(5)); \\ Dedekind zeta for Q(zeta_5) ? lfuncost(L, [100]) \\ at s = 1/2+I*t), |t| < 100 %5 = [11457, 582] ? lfuncost(L, [200]) \\ twice higher %6 = [36294, 1035] ? lfuncost(L, [10^4]) \\ much higher: very costly ! %7 = [70256473, 45452] ? \pb 256 ? lfuncost(L, [100]); \\ doubling bit accuracy %8 = [17080, 710] @eprog\noindent In fact, some $L$ functions can be factorized algebraically by the \kbd{lfuninit} call, e.g. the Dedekind zeta function of abelian fields, leading to much faster evaluations than the above upper bounds. In that case, the function returns a vector of costs as above for each individual function in the product actually evaluated: \bprog ? L = lfuncreate(polcyclo(5)); \\ Dedekind zeta for Q(zeta_5) ? lfuncost(L, [100]) \\ a priori cost %2 = [11457, 582] ? L = lfuninit(L, [100]); \\ actually perform all initializations ? lfuncost(L) %4 = [[16, 242], [16, 242], [7, 242]] @eprog\noindent The Dedekind function of this abelian quartic field is the product of four Dirichlet $L$-functions attached to the trivial character, a non-trivial real character and two complex conjugate characters. The non-trivial characters happen to have the same conductor (hence same evaluation costs), and correspond to two evaluations only since the two conjugate characters are evaluated simultaneously. For a total of three $L$-functions evaluations, which explains the three components above. Note that the actual cost is much lower than the a priori cost in this case. The library syntax is \fun{GEN}{lfuncost0}{GEN L, GEN sdom = NULL, long der, long bitprec}. Also available is \fun{GEN}{lfuncost}{GEN L, GEN dom, long der, long bitprec} when $L$ is \emph{not} an \kbd{Linit}; the return value is a \typ{VECSMALL} in this case. \subsec{lfuncreate$(\var{obj})$}\kbdsidx{lfuncreate}\label{se:lfuncreate} This low-level routine creates \tet{Ldata} structures, needed by \var{lfun} functions, describing an $L$-function and its functional equation. You are urged to use a high-level constructor when one is available, and this function accepts them, see \kbd{??lfun}: \bprog ? L = lfuncreate(1); \\ Riemann zeta ? L = lfuncreate(5); \\ Dirichlet L-function for quadratic character (5/.) ? L = lfuncreate(x^2+1); \\ Dedekind zeta for Q(i) ? L = lfuncreate(ellinit([0,1])); \\ L-function of E/Q: y^2=x^3+1 @eprog\noindent One can then use, e.g., \kbd{Lfun(L,s)} to directly evaluate the respective $L$-functions at $s$, or \kbd{lfuninit(L, [c,w,h]} to initialize computations in the rectangular box $\Re(s-c) \leq w$, $\Im(s) \leq h$. We now describe the low-level interface, used to input non-builtin $L$-functions. The input is now a $6$ or $7$ component vector $V=[a, astar, Vga, k, N, eps, poles]$, whose components are as follows: \item \kbd{V[1]=a} encodes the Dirichlet series coefficients $(a_n)$. The preferred format is a closure of arity 1: \kbd{n->vector(n,i,a(i))} giving the vector of the first $n$ coefficients. The closure is allowed to return a vector of more than $n$ coefficients (only the first $n$ will be considered) or even less than $n$, in which case loss of accuracy will occur and a warning that \kbd{\#an} is less than expected is issued. This allows to precompute and store a fixed large number of Dirichlet coefficients in a vector $v$ and use the closure \kbd{n->v}, which does not depend on $n$. As a shorthand for this latter case, you can input the vector $v$ itself instead of the closure. \bprog ? z = lfuncreate([n->vector(n,i,1), 1, [0], 1, 1, 1, 1]); \\ Riemann zeta ? lfun(z,2) - Pi^2/6 %2 = -5.877471754111437540 E-39 @eprog A second format is limited to $L$-functions affording an Euler product. It is a closure of arity 2 \kbd{(p,d)->F(p)} giving the local factor $L_p(X)$ at $p$ as a rational function, to be evaluated at $p^{-s}$ as in \kbd{direuler}; $d$ is set to \kbd{logint}$(n,p)$ + 1, where $n$ is the total number of Dirichlet coefficients $(a_1,\dots,a_n)$ that will be computed. In other words, the smallest integer $d$ such that $p^d > n$. This parameter $d$ allows to compute only part of $L_p$ when $p$ is large and $L_p$ expensive to compute: any polynomial (or \typ{SER}) congruent to $L_p$ modulo $X^d$ is acceptable since only the coefficients of $X^0, \dots, X^{d-1}$ are needed to expand the Dirichlet series. The closure can of course ignore this parameter: \bprog ? z = lfuncreate([(p,d)->1/(1-x), 1, [0], 1, 1, 1, 1]); \\ Riemann zeta ? lfun(z,2) - Pi^2/6 %4 = -5.877471754111437540 E-39 @eprog\noindent One can describe separately the generic local factors coefficients and the bad local factors by setting $\kbd{dir} = [F, L_{bad}]$, were $L_{bad} = [[p_1,L_{p_1}], \dots,[p_k,L_{p_k}]]$, where $F$ describes the generic local factors as above, except that when $p = p_i$ for some $i \leq k$, the coefficient $a_p$ is directly set to $L_{p_i}$ instead of calling $F$. \bprog N = 15; E = ellinit([1, 1, 1, -10, -10]); \\ = "15a1" F(p,d) = 1 / (1 - ellap(E,p)*'x + p*'x^2); Lbad = [[3, 1/(1+'x)], [5, 1/(1-'x)]]; L = lfuncreate([[F,Lbad], 0, [0,1], 2, N, ellrootno(E)]); @eprog\noindent Of course, in this case, \kbd{lfuncreate(E)} is preferable! \item \kbd{V[2]=astar} is the Dirichlet series coefficients of the dual function, encoded as \kbd{a} above. The sentinel values $0$ and $1$ may be used for the special cases where $a = a^*$ and $a = \overline{a^*}$, respectively. \item \kbd{V[3]=Vga} is the vector of $\alpha_j$ such that the gamma factor of the $L$-function is equal to $$\gamma_A(s)=\prod_{1\le j\le d}\Gamma_{\R}(s+\alpha_j),$$ where $\Gamma_{\R}(s)=\pi^{-s/2}\Gamma(s/2)$. This same syntax is used in the \kbd{gammamellininv} functions. In particular the length $d$ of \kbd{Vga} is the degree of the $L$-function. In the present implementation, the $\alpha_j$ are assumed to be exact rational numbers. However when calling theta functions with \emph{complex} (as opposed to real) arguments, determination problems occur which may give wrong results when the $\alpha_j$ are not integral. \item \kbd{V[4]=k} is a positive integer $k$. The functional equation relates values at $s$ and $k-s$. For instance, for an Artin $L$-series such as a Dedekind zeta function we have $k = 1$, for an elliptic curve $k = 2$, and for a modular form, $k$ is its weight. For motivic $L$-functions, the \emph{motivic} weight $w$ is $w = k-1$. By default we assume that $a_n = O_\epsilon(n^{k_1+\epsilon})$, where $k_1 = w$ and even $k_1 = w/2$ when the $L$ function has no pole (Ramanujan-Petersson). If this is not the case, you can replace the $k$ argument by a vector $[k,k_1]$, where $k_1$ is the upper bound you can assume. \item \kbd{V[5]=N} is the conductor, an integer $N\ge1$, such that $\Lambda(s)=N^{s/2}\gamma_A(s)L(s)$ with $\gamma_A(s)$ as above. \item \kbd{V[6]=eps} is the root number $\varepsilon$, i.e., the complex number (usually of modulus $1$) such that $\Lambda(a, k-s) = \varepsilon \Lambda(a^*, s)$. \item The last optional component \kbd{V[7]=poles} encodes the poles of the $L$ or $\Lambda$-functions, and is omitted if they have no poles. A polar part is given by a list of $2$-component vectors $[\beta,P_{\beta}(x)]$, where $\beta$ is a pole and the power series $P_{\beta}(x)$ describes the attached polar part, such that $L(s) - P_\beta(s-\beta)$ is holomorphic in a neighbourhood of $\beta$. For instance $P_\beta = r/x+O(1)$ for a simple pole at $\beta$ or $r_1/x^2+r_2/x+O(1)$ for a double pole. The type of the list describing the polar part allows to distinguish between $L$ and $\Lambda$: a \typ{VEC} is attached to $L$, and a \typ{COL} is attached to $\Lambda$. Unless $a = \overline{a^*}$ (coded by \kbd{astar} equal to $0$ or $1$), it is mandatory to specify the polar part of $\Lambda$ rather than those of $L$ since the poles of $L^*$ cannot be infered from the latter ! Whereas the functional equation allows to deduce the polar part of $\Lambda^*$ from the polar part of $\Lambda$. Finally, if $a = \overline{a^*}$, we allow a shortcut to describe the frequent situation where $L$ has at most simple pole, at $s = k$, with residue $r$ a complex scalar: you may then input $\kbd{poles} = r$. This value $r$ can be set to $0$ if unknown and it will be computed. The library syntax is \fun{GEN}{lfuncreate}{GEN obj}. \subsec{lfundiv$(\var{L1},\var{L2})$}\kbdsidx{lfundiv}\label{se:lfundiv} Creates the \kbd{Ldata} structure (without initialization) corresponding to the quotient of the Dirichlet series $L_1$ and $L_2$ given by \kbd{L1} and \kbd{L2}. Assume that $v_z(L_1) \geq v_z(L_2)$ at all complex numbers $z$: the construction may not create new poles, nor increase the order of existing ones. The library syntax is \fun{GEN}{lfundiv}{GEN L1, GEN L2, long bitprec}. \subsec{lfunetaquo$(M)$}\kbdsidx{lfunetaquo}\label{se:lfunetaquo} Returns the \kbd{Ldata} structure attached to the $L$ function attached to the modular form $z\mapsto \prod_{i=1}^n \eta(M_{i,1}\*z)^{M_{i,2}}$ It is currently assumed that $f$ is a self-dual cuspidal form on $\Gamma_0(N)$ for some $N$. For instance, the $L$-function $\sum \tau(n) n^{-s}$ attached to Ramanujan's $\Delta$ function is encoded as follows \bprog ? L = lfunetaquo(Mat([1,24])); ? lfunan(L, 100) \\ first 100 values of tau(n) @eprog\noindent For convenience, a \typ{VEC} is also accepted instead of a factorization matrix with a single row: \bprog ? L = lfunetaquo([1,24]); \\ same as above @eprog The library syntax is \fun{GEN}{lfunetaquo}{GEN M}. \subsec{lfungenus2$(F)$}\kbdsidx{lfungenus2}\label{se:lfungenus2} Returns the \kbd{Ldata} structure attached to the $L$ function attached to the genus-2 curve defined by $y^2=F(x)$ or $y^2+Q(x)\*y=P(x)$ if $F=[P,Q]$. Currently, the model needs to be minimal at 2, and if the conductor is even, its valuation at $2$ might be incorrect (a warning is issued). The library syntax is \fun{GEN}{lfungenus2}{GEN F}. \subsec{lfunhardy$(L,t)$}\kbdsidx{lfunhardy}\label{se:lfunhardy} Variant of the Hardy $Z$-function given by \kbd{L}, used for plotting or locating zeros of $L(k/2+it)$ on the critical line. The precise definition is as follows: if as usual $k/2$ is the center of the critical strip, $d$ is the degree, $\alpha_j$ the entries of \kbd{Vga} giving the gamma factors, and $\varepsilon$ the root number, then if we set $s = k/2+it = \rho e^{i\theta}$ and $E=(d(k/2-1)+\sum_{1\le j\le d}\alpha_j)/2$, the computed function at $t$ is equal to $$Z(t) = \varepsilon^{-1/2}\Lambda(s) \cdot |s|^{-E}e^{dt\theta/2}\;,$$ which is a real function of $t$ for self-dual $\Lambda$, vanishing exactly when $L(k/2+it)$ does on the critical line. The normalizing factor $|s|^{-E}e^{dt\theta/2}$ compensates the exponential decrease of $\gamma_A(s)$ as $t\to\infty$ so that $Z(t) \approx 1$. \bprog ? T = 100; \\ maximal height ? L = lfuninit(1, [T]); \\ initialize for zeta(1/2+it), |t|= 1 %1 = 15 ? lfunthetacost(L, 1 + I); \\ cost for theta(1+I). Domain error ! *** at top-level: lfunthetacost(1,1+I) *** ^-------------------- *** lfunthetacost: domain error in lfunthetaneed: arg t > 0.785 ? lfunthetacost(L, 1 + I/2) \\ for theta(1+I/2). %2 = 23 ? lfunthetacost(L, 1 + I/2, 10) \\ for theta^((10))(1+I/2). %3 = 24 ? lfunthetacost(L, [2, 1/10]) \\ cost for theta(t), |t| >= 2, |arg(t)| < 1/10 %4 = 8 ? L = lfuncreate( ellinit([1,1]) ); ? lfunthetacost(L) \\ for t >= 1 %6 = 2471 @eprog The library syntax is \fun{long}{lfunthetacost0}{GEN L, GEN tdom = NULL, long m, long bitprec}. \subsec{lfunthetainit$(L,\{\var{tdom}\},\{m=0\})$}\kbdsidx{lfunthetainit}\label{se:lfunthetainit} Initalization function for evaluating the $m$-th derivative of theta functions with argument $t$ in domain \var{tdom}. By default (\var{tdom} omitted), $t$ is real, $t \geq 1$. Otherwise, \var{tdom} may be \item a positive real scalar $\rho$: $t$ is real, $t \geq \rho$. \item a non-real complex number: compute at this particular $t$; this allows to compute $\theta(z)$ for any complex $z$ satisfying $|z|\geq |t|$ and $|\arg z| \leq |\arg t|$; we must have $|2 \arg z / d| < \pi/2$, where $d$ is the degree of the $\Gamma$ factor. \item a pair $[\rho,\alpha]$: assume that $|t| \geq \rho$ and $|\arg t| \leq \alpha$; we must have $|2\alpha / d| < \pi/2$, where $d$ is the degree of the $\Gamma$ factor. \bprog ? \p500 ? L = lfuncreate(1); \\ Riemann zeta ? t = 1+I/2; ? lfuntheta(L, t); \\ direct computation time = 30 ms. ? T = lfunthetainit(L, 1+I/2); time = 30 ms. ? lfuntheta(T, t); \\ instantaneous @eprog\noindent The $T$ structure would allow to quickly compute $\theta(z)$ for any $z$ in the cone delimited by $t$ as explained above. On the other hand \bprog ? lfuntheta(T,I) *** at top-level: lfuntheta(T,I) *** ^-------------- *** lfuntheta: domain error in lfunthetaneed: arg t > 0.785398163397448 @eprog The initialization is equivalent to \bprog ? lfunthetainit(L, [abs(t), arg(t)]) @eprog The library syntax is \fun{GEN}{lfunthetainit}{GEN L, GEN tdom = NULL, long m, long bitprec}. \subsec{lfuntwist$(L,\var{chi})$}\kbdsidx{lfuntwist}\label{se:lfuntwist} Creates the Ldata structure (without initialization) corresponding to the twist of L by the primitive character attached to the Dirichlet character \kbd{chi}. The conductor of the character must be coprime to the conductor of the L-function $L$. The library syntax is \fun{GEN}{lfuntwist}{GEN L, GEN chi}. \subsec{lfunzeros$(L,\var{lim},\{\var{divz}=8\})$}\kbdsidx{lfunzeros}\label{se:lfunzeros} \kbd{lim} being either a positive upper limit or a non-empty real interval inside $[0,+\infty[$, computes an ordered list of zeros of $L(s)$ on the critical line up to the given upper limit or in the given interval. Use a naive algorithm which may miss some zeros: it assumes that two consecutive zeros at height $T \geq 1$ differ at least by $2\pi/\omega$, where $$\omega := \kbd{divz} \cdot \big(d\log(T/2\pi) +d+ 2\log(N/(\pi/2)^d)\big).$$ To use a finer search mesh, set divz to some integral value larger than the default (= 8). \bprog ? lfunzeros(1, 30) \\ zeros of Rieman zeta up to height 30 %1 = [14.134[...], 21.022[...], 25.010[...]] ? #lfunzeros(1, [100,110]) \\ count zeros with 100 <= Im(s) <= 110 %2 = 4 @eprog\noindent The algorithm also assumes that all zeros are simple except possibly on the real axis at $s = k/2$ and that there are no poles in the search interval. (The possible zero at $s = k/2$ is repeated according to its multiplicity.) Should you pass an \kbd{Linit} argument to the function, beware that the algorithm needs at least \bprog L = lfuninit(Ldata, [T+1]) @eprog\noindent where $T$ is the upper bound of the interval defined by \kbd{lim}: this allows to detect zeros near $T$. Make sure that your \kbd{Linit} domain contains this one, i.e. a domain $[1,T+1]$ is fine but $[0, T]$ is not! The algorithm assumes that a multiple zero at $s = k / 2$ has order less than or equal to the maximal derivation order allowed by the \kbd{Linit}. You may increase that value in the \kbd{Linit} but this is costly: only do it for zeros of low height or in \kbd{lfunorderzero} instead. The library syntax is \fun{GEN}{lfunzeros}{GEN L, GEN lim, long divz, long bitprec}. \section{Modular forms} This section describes routines for working with modular forms and modular form spaces. \subsec{Modular form spaces} %GPHELPskip These structures are initialized by the \kbd{mfinit} command; supported modular form \emph{spaces} with corresponding flags are the following: \item The full modular form space $M_k(\Gamma_0(N),\chi)$, where $k$ is an integer or a half-integer and $\chi$ a Dirichlet character modulo $N$ (flag $4$, the default). \item The cuspidal space $S_k(\Gamma_0(N),\chi)$ (flag $1$). \item The Eisenstein space ${\cal E}_k(\Gamma_0(N),\chi)$ (flag $3$), so that $M_k={\cal E}_k\oplus S_k$. \item The new space $S_k^{\text{new}}(\Gamma_0(N),\chi)$ (flag $0$). \item The old space $S_k^{\text{old}}(\Gamma_0(N),\chi)$ (flag $2$), so that $S_k=S_k^{\text{new}}\oplus S_k^{\text{old}}$. These resulting \kbd{mf} structure contains a basis of modular forms, which is accessed by the function \kbd{mfbasis}; the elements of this basis have Fourier coefficients in the cyclotomic field $\Q(\chi)$. These coefficients are given algebraically, as rational numbers or \typ{POLMOD}s. The member function \kbd{mf.mod} recovers the modulus used to define $\Q(\chi)$, which is a cyclotomic polynomial $\Phi_n(t)$. When needed, the elements of $\Q(\chi)$ are considered to be canonically embedded into $\C$ via $\kbd{Mod}(t,\Phi_n(t)) \mapsto \exp(2i\pi/n)$. The basis of eigenforms for the new space is obtained by the function \kbd{mfeigenbasis}: the elements of this basis now have Fourier coefficients in a relative field extension of $\Q(\chi)$. Note that if the space is larger than the new space (i.e. is the cuspidal or full space) we nevertheless obtain only the eigenbasis for the new space. \subsec{Generalized modular forms} %GPHELPskip A modular form is represented in a special internal format giving the possibility to compute an arbitrary number of terms of its Fourier coefficients at infinity $[a(0),a(1),...,a(n)]$ using the function \kbd{mfcoefs}. These coefficients are given algebraically, as rational numbers or \typ{POLMOD}s. The member function \kbd{f.mod} recovers the modulus used in the coefficients of $f$, which will be the same as for $k = \Q(\chi)$ (a cyclotomic polynomial), or define a number field extension $K/k$. Modular forms are obtained either directly from other mathematical objects, e.g., elliptic curves, or by a specific formula, e.g., Eisenstein series or Ramanujan's Delta function, or by applying standard operators to existing forms (Hecke operators, Rankin--Cohen brackets, \dots). A function \kbd{mfparams} is provided so that one can recover the level, weight, character and field of definition corresponding to a given modular form. A number of creation functions and operations are provided. It is however important to note that strictly speaking some of these operations create objects which are \emph{not} modular forms: typical examples are derivation or integration of modular forms, the Eisenstein series $E_2$, eta quotients, or quotients of modular forms. These objects are nonetheless very important in the theory, so are not considered as errors; however the user must be aware that no attempt is made to check that the objects that he handles are really modular. When the documentation of a function does not state that it applies to generalized modular forms, then the output is undefined if the input is not a true modular form. \subsec{getcache$()$}\kbdsidx{getcache}\label{se:getcache} Returns information about various auto-growing caches. For each ressource, we report its name, its size, the number of cache misses (since the last extension), the largest cache miss and the size of the cache in bytes. The caches are initially empty, then set automatically to a small inexpensive default value, then grow on demand up to some maximal value. Their size never decreases, they are only freed on exit. The current caches are \item Hurwitz class numbers $H(D)$ for $|D| \leq N$, computed in time $O(N^{3/2})$ using $O(N)$ space. \item Factorizations of small integers up to $N$, computed in time $O(N^{1+\varepsilon})$ using $O(N\log N)$ space. \item Divisors of small integers up to $N$, computed in time $O(N^{1+\varepsilon})$ using $O(N\log N)$ space. \item Primitive dihedral forms of weight $1$ and level up to $N$, computed in time $O(N^{2+\varepsilon})$ and space $O(N^2)$. \bprog ? getcache() \\ on startup, all caches are empty %1 = [ "Factors" 0 0 0 0] ["Divisors" 0 0 0 0] [ "H" 0 0 0 0] ["Dihedral" 0 0 0 0] ? mfdim([500,1,0],0); \\ non-trivial computation time = 540 ms. ? getcache() %3 = [ "Factors" 50000 0 0 4479272] ["Divisors" 50000 1 100000 5189808] [ "H" 50000 0 0 400008] ["Dihedral" 1000 0 0 2278208] @eprog The library syntax is \fun{GEN}{getcache}{}. \subsec{lfunmf$(\var{mf},\{F\})$}\kbdsidx{lfunmf}\label{se:lfunmf} If $F$ is a modular form in \kbd{mf}, output the L-functions corresponding to its $[\Q(F):\Q(\chi)]$ complex embeddings, ready for use with the \kbd{lfun} package. If $F$ is omitted, output the $L$-functions attached to all eigenforms in the new space; the result is a vector whose length is the number of Galois orbits of newforms. Each entry contains the vector of $L$-functions corresponding to the $d$ complex embeddings of an orbit of dimension $d$ over $\Q(\chi)$. \bprog ? mf = mfinit([35,2],0);mffields(mf) %1 = [y, y^2 - y - 4] ? f = mfeigenbasis(mf)[2]; mfparams(f) \\ orbit of dimension two %2 = [35, 2, 1, y^2 - y - 4] ? [L1,L2] = lfunmf(mf, f); \\ Two L-functions ? lfun(L1,1) %4 = 0.81018461849460161754947375433874745585 ? lfun(L2,1) %5 = 0.46007635204895314548435893464149369804 ? [ lfun(L,1) | L <- concat(lfunmf(mf)) ] %6 = [0.70291..., 0.81018..., 0.46007...] @eprog\noindent The \kbd{concat} instruction concatenates the vectors corresponding to the various (here two) orbits, so that we obtain the vector of all the $L$-functions attached to eigenforms. The library syntax is \fun{GEN}{lfunmf}{GEN mf, GEN F = NULL, long bitprec}. \subsec{mfDelta$()$}\kbdsidx{mfDelta}\label{se:mfDelta} Mf structure corresponding to the Ramanujan Delta function $\Delta$. \bprog ? mfcoefs(mfDelta(),4) %1 = [0, 1, -24, 252, -1472] @eprog The library syntax is \fun{GEN}{mfDelta}{}. \subsec{mfEH$(k)$}\kbdsidx{mfEH}\label{se:mfEH} $k$ being in $1/2+\Z$, returns the Cohen-Eisenstein series $H_k$ of weight $k$ on $\Gamma_0(4)$. \bprog ? H = mfEH(13/2); mfcoefs(H,4) %1 = [691/32760, -1/252, 0, 0, -2017/252] @eprog The coefficients of $H$ are given by the Cohen-Hurwitz function $H(k-1/2,N)$ and can be obtained for moderately large values of $N$ (the algorithm uses $\tilde{O}(N)$ time): \bprog ? mfcoef(H,10^5+1) time = 55 ms. %2 = -12514802881532791504208348 ? mfcoef(H,10^7+1) time = 6,044 ms. %3 = -1251433416009877455212672599325104476 @eprog The library syntax is \fun{GEN}{mfEH}{GEN k}. \subsec{mfEk$(k)$}\kbdsidx{mfEk}\label{se:mfEk} Mf structure corresponding to the standard Eisenstein series $E_k$. \bprog ? mfcoefs(mfEk(8),4) %1 = [1, 480, 61920, 1050240, 7926240] @eprog The library syntax is \fun{GEN}{mfEk}{long k}. \subsec{mfTheta$(\{\var{psi}=1\})$}\kbdsidx{mfTheta}\label{se:mfTheta} The unary theta function corresponding to the primitive Dirichlet character $\psi$, hence of weight $1/2$ if $\psi$ is even, of weight $3/2$ if $\psi$ is odd. \bprog ? Ser(mfcoefs(mfTheta(),30)) %1 = 1 + 2*x + 2*x^4 + 2*x^9 + 2*x^16 + 2*x^25 + O(x^31) ? Ser(mfcoefs(mfTheta(8),30)) %2 = 2*x - 2*x^9 - 2*x^25 + O(x^31) ? Ser(mfcoefs(mfTheta(-8),30)) %3 = 2*x + 6*x^9 - 10*x^25 + O(x^31) @eprog The library syntax is \fun{GEN}{mfTheta}{GEN psi = NULL}. \subsec{mfatkin$(\var{mfatk},F)$}\kbdsidx{mfatkin}\label{se:mfatkin} Given a \kbd{mfatk} output by \kbd{mfatk = mfatkininit(mf,Q)} and a modular form $F$ belonging to the pace \kbd{mf}, returns the modular form $C*F|W_Q$, which has \kbd{polmod} coefficients in $\Q(F)$; \kbd{mfatk[3]} gives the constant $C$, and \kbd{mfatk[1]} gives the modular form space to which $F|W_Q$ belongs (or is set to $0$ if it is \kbd{mf}). \bprog ? mf = mfinit([35,2],0); vecF = mfbasis(mf); F = vecF[1]; ? mfcoefs(F, 4) %2 = [0, 3, -1, 0, 3] ? mfatk = mfatkininit(mf,7); ? wF = mfatkin(mfatk, F); mfcoefs(wF, 4) %4 = [0, 1, -1, -2, 7] ? mfatk = mfatkininit(mf,35); ? wF = mfatkin(mfatk, F); mfcoefs(wF, 4) %6 = [0, -3, 1, 0, -3] @eprog The library syntax is \fun{GEN}{mfatkin}{GEN mfatk, GEN F}. \subsec{mfatkineigenvalues$(\var{mf},Q)$}\kbdsidx{mfatkineigenvalues}\label{se:mfatkineigenvalues} Given a modular form space \kbd{mf} of integral weight $k$ and a primitive divisor $Q$ of the level $N$ of \kbd{mf}, outputs the Atkin--Lehner eigenvalues of $w_Q$ on the new space, grouped by orbit. If $\chi$ is a (trivial or) quadratic character defined modulo $N/Q$, the result is rounded and the eigenvalues are $\pm i^k$. \bprog ? mf = mfinit([35,2],0); mffields(mf) %1 = [y, y^2 - y - 4] \\ two orbits, dimension 1 and 2 ? mfatkineigenvalues(mf,5) %2 = [[1], [-1, -1]] ? mf = mfinit([12,7,Mod(3,4)],0); ? mfatkineigenvalues(mf,3) %4 = [[I, -I, -I, I, I, -I]] \\ one orbit @eprog If you want the eigenvalues on a larger space than the new space, e.g. the full space, you can directly call \kbd{[mfB,M,C]=mfatkininit} and compute the eigenvalues as the roots of the characteristic polynomial of $M/C$, i.e. by dividing the roots of \kbd{charpoly(M)} by $C$. Note that the characteristic polynomial is computed exactly since $M$ has coefficients in $\Q(\chi)$, whereas $C$ may be given by a complex number. If the coefficients of the characteristic polynomial are polmods modulo $T$ they must be embedded to $\C$ first using \kbd{subst(lift(), t, exp(2*I*Pi/n))}, when $T$ is \kbd{poliscyclo(n)}; note that $T = \kbd{mf.mod}$. The library syntax is \fun{GEN}{mfatkineigenvalues}{GEN mf, long Q, long prec}. \subsec{mfatkininit$(\var{mf},Q)$}\kbdsidx{mfatkininit}\label{se:mfatkininit} Given a modular form space with parameters $N,k,\chi$ and a primitive divisor $Q$ of the level $N$, initializes data necessary for working with the Atkin--Lehner operator $W_Q$, for now only the function \kbd{mfatkin}. We write $\chi \sim \chi_Q \chi_{N/Q}$ where the two characters are primitive with (coprime) conductors dividing $Q$ and $N/Q$ respectively. For $F\in M_k(\Gamma_0(N),\chi)$, the form $F | W_Q$ still has level $N$ and weight $k$ but its Nebentypus may no longer be $\chi$: it becomes $\overline{\chi_Q} \chi_{N/Q})$ if $k$ is integral and $\overline{\chi_Q} \chi_{N/Q})(4Q/\cdot)$ if not. The result is a technical 4-component vector \kbd{[mfB, CM, C, mf]}, where \item \kbd{mfB} encodes the modular form space to which $F|W_Q$ belongs when $F \in M_k(\Gamma_0(N), \chi)$: an \kbd{mfinit} corresponding to a new Nebentypus or the integer $0$ when the character does not change. This does not depend on $F$. \item \kbd{CM} is the matrix of $W_Q$ on the bases of \kbd{mf} and \kbd{mfB} multiplied by a normalizing constant $C(k,\chi,Q)$. This matrix has polmod coefficients in $\Q(\chi)$. \item \kbd{C} is the complex constant $C(k,\chi,Q)$. For $k$ integral, let $A(k,\chi, Q) = Q^{\varepsilon}/g(\chi_Q)$, where $\varepsilon = 0$ for $k$ even and $1/2$ for $k$ odd and where $g(\chi_Q)$ is the Gauss sum attached to $\chi_Q$). (A similar, more complicated, definition holds in half-integral weight depending on the parity of $k - 1/2$.) Then if $M$ denotes the matrix of $W_Q$ on the bases of \kbd{mf} and \kbd{mfB}, $A \cdot M$ has coefficients in $\Q(\chi)$. If $A$ is rational, we let $C = 1$ and $C = A$ as a floating point complex number otherwise, and finally $\kbd{MC} := M \cdot C$. \bprog ? mf=mfinit([32,4],0); [mfB,MC,C]=mfatkininit(mf,32); MC %1 = [5/16 11/2 55/8] [ 1/8 0 -5/4] [1/32 -1/4 11/16] ? C %2 = 1 ? mf=mfinit([32,4,8],0); [mfB,MC,C]=mfatkininit(mf,32); MC %3 = [ 1/8 -7/4] [-1/16 -1/8] ? C %4 = 0.35355339059327376220042218105242451964 ? algdep(C,2) \\ C = 1/sqrt(8) %5 = 8*x^2 - 1 @eprog The library syntax is \fun{GEN}{mfatkininit}{GEN mf, long Q, long prec}. \subsec{mfbasis$(\var{NK},\{\var{space}=4\})$}\kbdsidx{mfbasis}\label{se:mfbasis} If $NK=[N,k,\var{CHI}]$ as in \kbd{mfinit}, gives a basis of the corresponding subspace of $M_k(\Gamma_0(N),\chi)$. $NK$ can also be the output of \kbd{mfinit}, in which case \kbd{space} can be omitted. To obtain the eigenforms, use \kbd{mfeigenbasis}. If \kbd{space} is a full space $M_k$, the output is the union of first, a basis of the space of Eisenstein series, and second, a basis of the cuspidal space. \bprog ? see(L) = apply(f->mfcoefs(f,3), L); ? mf = mfinit([35,2],0); ? see( mfbasis(mf) ) %2 = [[0, 3, -1, 0], [0, -1, 9, -8], [0, 0, -8, 10]] ? see( mfeigenbasis(mf) ) %3 = [[0, 1, 0, 1], [Mod(0, z^2 - z - 4), Mod(1, z^2 - z - 4), \ Mod(-z, z^2 - z - 4), Mod(z - 1, z^2 - z - 4)]] ? mf = mfinit([35,2]); ? see( mfbasis(mf) ) %5 = [[1/6, 1, 3, 4], [1/4, 1, 3, 4], [17/12, 1, 3, 4], \ [0, 3, -1, 0], [0, -1, 9, -8], [0, 0, -8, 10]] ? see( mfbasis([48,4],0) ) %6 = [[0, 3, 0, -3], [0, -3, 0, 27], [0, 2, 0, 30]] @eprog The library syntax is \fun{GEN}{mfbasis}{GEN NK, long space}. \subsec{mfbd$(F,d)$}\kbdsidx{mfbd}\label{se:mfbd} $F$ being a generalized modular form, return $B(d)(F)$, where $B(d)$ is the expanding operator $\tau\mapsto d\tau$. \bprog ? D2=mfbd(mfDelta(),2); mfcoefs(D2, 6) %1 = [0, 0, 1, 0, -24, 0, 252] @eprog The library syntax is \fun{GEN}{mfbd}{GEN F, long d}. \subsec{mfbracket$(F,G,\{m=0\})$}\kbdsidx{mfbracket}\label{se:mfbracket} Compute the $m$-th Rankin--Cohen bracket of the generalized modular forms $F$ and $G$. \bprog ? E4 = mfEk(4); E6 = mfEk(6); ? D1 = mfbracket(E4,E4,2); mfcoefs(D1,5)/4800 %2 = [0, 1, -24, 252, -1472, 4830] ? D2 = mfbracket(E4,E6,1); mfcoefs(D2,10)/(-3456) %3 = [0, 1, -24, 252, -1472, 4830] @eprog The library syntax is \fun{GEN}{mfbracket}{GEN F, GEN G, long m}. \subsec{mfcoef$(F,n)$}\kbdsidx{mfcoef}\label{se:mfcoef} Compute the $n$-th Fourier coefficient of the generalized modular form $F$. Note that this is the $n+1$-st component of the vector \kbd{mfcoefs(F,n)} as well as the second component of \kbd{mfcoefs(F,1,n)}. \bprog ? mfcoef(mfDelta(),10) %1 = -115920 @eprog The library syntax is \fun{GEN}{mfcoef}{GEN F, long n}. \subsec{mfcoefs$(F,n,\{d = 1\})$}\kbdsidx{mfcoefs}\label{se:mfcoefs} Compute the vector of Fourier coefficients $[a[0],a[d],...,a[nd]]$ of the generalized modular form $F$; $d$ must be positive and $d = 1$ by default. \bprog ? D = mfDelta(); ? mfcoefs(D,10) %2 = [0, 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920] ? mfcoefs(D,5,2) %3 = [0, -24, -1472, -6048, 84480, -115920] ? mfcoef(D,10) %4 = -115920 @eprog\noindent This function also applies when $F$ is a modular form space as output by \kbd{mfinit}; it then returns the matrix whose columns give the Fourier expansions of the elements of \kbd{mfbasis}$(F)$: \bprog ? mf = mfinit([1,12]); ? mfcoefs(mf,5) %2 = [691/65520 0] [ 1 1] [ 2049 -24] [ 177148 252] [ 4196353 -1472] [ 48828126 4830] @eprog The library syntax is \fun{GEN}{mfcoefs}{GEN F, long n, long d}. \subsec{mfconductor$(\var{mf},F)$}\kbdsidx{mfconductor}\label{se:mfconductor} \kbd{mf} being output by \kbd{mfinit} for the cuspidal space and $F$ a modular form, gives the smallest level on which $F$ is defined. \bprog ? mf=mfinit([96,6],1); vF = mfbasis(mf); mfdim(mf) %1 = 72 ? vector(10,i, mfconductor(mf, vF[i])) %2 = [3, 6, 12, 24, 48, 96, 4, 8, 12, 16] @eprog The library syntax is \fun{long}{mfconductor}{GEN mf, GEN F}. \subsec{mfcosets$(N)$}\kbdsidx{mfcosets}\label{se:mfcosets} List of right cosets of $\Gamma_0(N) \bs \Gamma$, i.e., matrices $\gamma_j \in \Gamma$ such that $\Gamma = \bigsqcup_j \Gamma_0(N) \gamma_j$. The $\gamma_j$ are chosen in the form $[a,b;c,d]$ with $c\mid N$. $N$ can be either a positive integer or a modular form space. \bprog ? mfcosets(4) %1 = [[0, -1; 1, 0], [1, 0; 1, 1], [0, -1; 1, 2], [0, -1; 1, 3],\ [1, 0; 2, 1], [1, 0; 4, 1]] @eprog \misctitle{Warning} in the present implementation, the trivial coset is represented by $[1,0;N,1]$ and is the last in the list. The library syntax is \fun{GEN}{mfcosets}{GEN N}. \subsec{mfcuspisregular$(\var{NK}, \var{cusp})$}\kbdsidx{mfcuspisregular}\label{se:mfcuspisregular} In the space defined by \kbd{NK = [N,k,CHI]} or \kbd{NK = mf}, determine if \kbd{cusp} in canonical format (oo or denominator dividing $N$) is regular or not. \bprog ? mfcuspisregular([4,3,-4],1/2) %1 = 0 @eprog The library syntax is \fun{long}{mfcuspisregular}{GEN NK, GEN cusp}. \subsec{mfcusps$(N)$}\kbdsidx{mfcusps}\label{se:mfcusps} List of cusps of $\Gamma_0(N)$ in the form $a/b$ with $b\mid N$. $N$ can be either an integer of a modular form space. \bprog ? mfcusps(24) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/8, 1/12, 1/24] @eprog The library syntax is \fun{GEN}{mfcusps}{GEN N}. \subsec{mfcuspval$(\var{mf},F,\var{cusp})$}\kbdsidx{mfcuspval}\label{se:mfcuspval} Valuation of modular form $F$ in the space \kbd{mf} at \kbd{cusp}, which can be either $\infty$ or any rational number, and the result is either a rational number or $\infty$ if $F$ is zero. If $\Q(F) \neq \Q(\chi)$, return the vector of valuations attached to the $[\Q(F):\Q(chi)]$ complex embeddings of $F$. \bprog ? T=mfTheta();mf=mfinit([12,1/2]);mfcusps(12) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/12] ? apply(x->mfcuspval(mf,T,x),%1) %2 = [0, 1/4, 0, 0, 1/4, 0] ? mf=mfinit([12,6,12],1);F=mfbasis(mf)[5]; ? apply(x->mfcuspval(mf,F,x),%1) %4 = [1/12, 1/6, 1/2, 2/3, 1/2, 2] ? mf=mfinit([12,3,-4],1);F=mfbasis(mf)[1]; ? apply(x->mfcuspval(mf,F,x),%1) %6 = [1/12, 1/6, 1/4, 2/3, 1/2, 1] ? mf = mfinit([625,2],0); [F] = mfeigenbasis(mf); mfparams(F) %7 = [625, 2, 1, y^2 - y - 1] \\ [Q(F):Q(chi)] = poldegree(y^2-y-1) ? mfcuspval(mf, F, 1/25) %8 = [1, 2] \\ one conjugate has valuation 1, and the other is 2 ? mfcuspval(mf, F, 1/5) %9 = [1/25, 1/25] @eprog The library syntax is \fun{GEN}{mfcuspval}{GEN mf, GEN F, GEN cusp, long bitprec}. \subsec{mfcuspwidth$(N, \var{cusp})$}\kbdsidx{mfcuspwidth}\label{se:mfcuspwidth} Width of \kbd{cusp} in $\Gamma_0(N)$, $N$ being either an integer or a modular form space. \bprog ? mfcusps(12) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/12] ? [mfcuspwidth(12,c) | c <- mfcusps(12)] %2 = [12, 3, 4, 3, 1, 1] ? mfcuspwidth(12, oo) %3 = 1 @eprog The library syntax is \fun{long}{mfcuspwidth}{GEN N, GEN cusp}. \subsec{mfderiv$(F,\{m=1\})$}\kbdsidx{mfderiv}\label{se:mfderiv} $m$-th formal derivative of the power series corresponding to the generalized modular form $F$, with respect to the differential operator $qd/dq$ (default $m=1$). \bprog ? D=mfDelta(); ? mfcoefs(D, 4) %2 = [0, 1, -24, 252, -1472] ? mfcoefs(mfderiv(D), 4) %3 = [0, 1, -48, 756, -5888] @eprog The library syntax is \fun{GEN}{mfderiv}{GEN F, long m}. \subsec{mfderivE2$(F,\{m=1\})$}\kbdsidx{mfderivE2}\label{se:mfderivE2} Compute the Serre derivative $(q.d/dq)F - kE_2F/12$ of the generalized modular form $F$, which has weight $k+2$; if $F$ is a true modular form, then its Serre derivative is also modular. If $m>1$, compute the $m$-th iterate, of weight $k + 2m$. \bprog ? mfcoefs(mfderivE2(mfEk(4)),5)*(-3) %1 = [1, -504, -16632, -122976, -532728] ? mfcoefs(mfEk(6),5) %2 = [1, -504, -16632, -122976, -532728] @eprog The library syntax is \fun{GEN}{mfderivE2}{GEN F, long m}. \subsec{mfdescribe$(F,\{\&G\})$}\kbdsidx{mfdescribe}\label{se:mfdescribe} Gives a human-readable description of $F$, which is either a modular form space or a generalized modular form. If the address of $G$ is given, puts into $G$ the vector of parameters of the outmost operator defining $F$ (the empty vector if $F$ is a leaf or a modular form space). \bprog ? E1 = mfeisenstein(4,-3,-4); mfdescribe(E1) %1 = "F_4(-3, -4)" ? E2 = mfeisenstein(3,5,-7); mfdescribe(E2) %2 = "F_3(5, -7)" ? E3 = mfderivE2(mfmul(E1,E2), 3); mfdescribe(E3,&G) %3 = "DERE2^3(MUL(F_4(-3, -4), F_3(5, -7)))" ? mfdescribe(G[1][1]) %4 = "MUL(F_4(-3, -4), F_3(5, -7))" ? G[2] %5 = 3 ? for (i = 0, 4, mf = mfinit([37,4],i); print(mfdescribe(mf))); S_4^new(G_0(37, 1)) S_4(G_0(37, 1)) S_4^old(G_0(37, 1)) E_4(G_0(37, 1)) M_4(G_0(37, 1)) @eprog The library syntax is \fun{GEN}{mfdescribe}{GEN F, GEN *G = NULL}. \subsec{mfdim$(\var{NK},\{\var{space}=4\})$}\kbdsidx{mfdim}\label{se:mfdim} If $NK=[N,k,\var{CHI}]$ as in \kbd{mfinit}, gives the dimension of the corresponding subspace of $M_k(\Gamma_0(N),\chi)$. $NK$ can also be the output of \kbd{mfinit}, in which case space must be omitted. The subspace is described by the small integer \kbd{space}: $0$ for the newspace $S_k^{\text{new}}(\Gamma_0(N),\chi)$, $1$ for the cuspidal space $S_k$, $2$ for the oldspace $S_k^{\text{old}}$, $3$ for the space of Eisenstein series $E_k$ and $4$ for the full space $M_k$. \misctitle{Wildcards} As in \kbd{mfinit}, \var{CHI} may be the wildcard 0 (all Galois orbits of characters); in this case, the output is a vector of $[\var{order}, \var{conrey}, \var{dim}, \var{dimdih}]$ corresponding to the non-trivial spaces, where \item \var{order} is the order of the character, \item \var{conrey} its Conrey label from which the character may be recovered via \kbd{znchar}$(\var{conrey})$, \item \var{dim} the dimension of the corresponding space, \item \var{dimdih} the dimension of the subspace of dihedral forms corresponding to Hecke characters if $k = 1$ (this is not implemented for the old space and set to $-1$ for the time being) and 0 otherwise. The spaces are sorted by increasing order of the character; the characters are taken up to Galois conjugation and the Conrey number is the minimal one among Galois conjugates. In weight $1$, this is only implemented when the space is 0 (newspace), 1 (cusp space), 2(old space) or 3(Eisenstein series). \misctitle{Wildcards for sets of characters} \var{CHI} may be a set of characters, and we return the set of $[\var{dim},\var{dimdih}]$. \misctitle{Wildcard for $M_k(\Gamma_1(N))$} Additionally, the wildcard $\var{CHI} = -1$ is available in which case we output the total dimension of the corresponding subspace of $M_k(\Gamma_1(N))$. In weight $1$, this is not implemented when the space is 4 (fullspace). \bprog ? mfdim([23,2], 0) \\ new space %1 = 2 ? mfdim([96,6], 0) %2 = 10 ? mfdim([10^9,4], 3) \\ Eisenstein space %1 = 40000 ? mfdim([10^9+7,4], 3) %2 = 2 ? mfdim([68,1,-1],0) %3 = 3 ? mfdim([68,1,0],0) %4 = [[2, Mod(67, 68), 1, 1], [4, Mod(47, 68), 1, 1]] ? mfdim([124,1,0],0) %5 = [[6, Mod(67, 124), 2, 0]] @eprog This last example shows that there exists a nondihedral form of weight 1 in level 124. The library syntax is \fun{GEN}{mfdim}{GEN NK, long space}. \subsec{mfdiv$(F,G)$}\kbdsidx{mfdiv}\label{se:mfdiv} Given two generalized modular forms $F$ and $G$, compute $F/G$ assuming that the quotient will not have poles at infinity. If this is the case, use \kbd{mfshift} before doing the division. \bprog ? D = mfDelta(); \\ Delta ? H = mfpow(mfEk(4), 3); ? J = mfdiv(H, D) *** at top-level: J=mfdiv(H,mfdeltac *** ^-------------------- *** mfdiv: domain error in mfdiv: ord(G) > ord(F) ? J = mfdiv(H, mfshift(D,1)); ? mfcoefs(J, 4) %4 = [1, 744, 196884, 21493760, 864299970] @eprog The library syntax is \fun{GEN}{mfdiv}{GEN F, GEN G}. \subsec{mfeigenbasis$(\var{mf})$}\kbdsidx{mfeigenbasis}\label{se:mfeigenbasis} Vector of the eigenforms for the space \kbd{mf}. The initial basis of forms computed by \kbd{mfinit} before splitting is also available via \kbd{mfbasis}. \bprog ? mf = mfinit([26,2],0); ? see(L) = for(i=1,#L,print(mfcoefs(L[i],6))); ? see( mfeigenbasis(mf) ) [0, 1, -1, 1, 1, -3, -1] [0, 1, 1, -3, 1, -1, -3] ? see( mfbasis(mf) ) [0, 2, 0, -2, 2, -4, -4] [0, -2, -4, 10, -2, 0, 8] @eprog The eigenforms are internally expressed as (algebraic) linear combinations of \kbd{mfbasis(mf)} and it is very inefficient to compute many coefficients of those forms individually: you should rather use \kbd{mfcoefs(mf)} to expand the basis once and for all, then multiply by \kbd{mftobasis(mf,f)} for the forms you're interested in: \bprog ? mf = mfinit([96,6],0); B = mfeigenbasis(mf); #B %1 = 8; ? vector(#B, i, mfcoefs(B[i],1000)); \\ expanded individually: slow time = 7,881 ms. ? M = mfcoefs(mf, 1000); \\ initialize once time = 982 ms. ? vector(#B, i, M * mftobasis(mf,B[i])); \\ then expand: much faster time = 623 ms. @eprog When the eigenforms are defined over an extension field of $\Q(\chi)$ for a non-rational character, their coefficients are hard to read and you may want to lift them or to express them in an absolute number field. In the construction below $T$ defines $\Q(f)$ over $\Q$, $a$ is the image of the generator \kbd{Mod}$(t, t^2+t+1)$ of $\Q(\chi)$ in $\Q(f)$ and $y - ka$ is the image of the root $y$ of \kbd{f.mod}: \bprog ? mf = mfinit([31, 2, Mod(25,31)], 0); [f] = mfeigenbasis(mf); ? f.mod %2 = Mod(1, t^2 + t + 1)*y^2 + Mod(2*t + 2, t^2 + t + 1) ? v = liftpol(mfcoefs(f,5)) %3 = [0, 1, (-t - 1)*y - 1, t*y + (t + 1), (2*t + 2)*y + 1, t] ? [T,a,k] = rnfequation(mf.mod, f.mod, 1) %4 = [y^4 + 2*y^2 + 4, Mod(-1/2*y^2 - 1, y^4 + 2*y^2 + 4), 0] ? liftpol(substvec(v, [t,y], [a, y-k*a])) %5 = [0, 1, 1/2*y^3 - 1, -1/2*y^3 - 1/2*y^2 - y, -y^3 + 1, -1/2*y^2 - 1] @eprog\noindent Beware that the meaning of $y$ has changed in the last line is different: it now represents of root of $T$, no longer of \kbd{f.mod} (the notions coincide if $k = 0$ as here but it will not always be the case). This can be avoided with an extra variable substitution, for instance \bprog ? [T,a,k] = rnfequation(mf.mod, subst(f.mod,'y,'x), 1) %6 = [x^4 + 2*x^2 + 4, Mod(-1/2*x^2 - 1, x^4 + 2*x^2 + 4), 0] ? liftpol(substvec(v, [t,y], [a, x-k*a])) %7 = [0, 1, 1/2*x^3 - 1, -1/2*x^3 - 1/2*x^2 - x, -x^3 + 1, -1/2*x^2 - 1] @eprog The library syntax is \fun{GEN}{mfeigenbasis}{GEN mf}. \subsec{mfeigensearch$(\var{NK},\{\var{AP}\})$}\kbdsidx{mfeigensearch}\label{se:mfeigensearch} Search for a normalized rational eigen cuspform with quadratic character given restrictions on a few initial coefficients. The meaning of the parameters is as follows: \item \kbd{NK} governs the limits of the search: it is of the form $[N,k]$: search for given level $N$, weight $k$ and quadratic character; note that the character $(D/.)$ is uniquely determined by $(N,k)$. The level $N$ can be replaced by a vector of allowed levels. \item \kbd{AP} is the search criterion, which can be omitted: a list of pairs $[\ldots, [p,a_p], \ldots]$, where $p$ is a prime number and $a_p$ is either a \typ{INT} (the $p$-th Fourier coefficient must match $a_p$ exactly) or a \typ{INTMOD} \kbd{Mod}$(a,b)$ (the $p$-th coefficient must be congruent to $a$ modulo $b$). The result is a vector of newforms $f$ matching the search criteria, sorted by increasing level then increasing $|D|$. \bprog ? #mfeigensearch([[1..80],2], [[2,2],[3,-1]]) %1 = 1 ? #mfeigensearch([[1..80],2], [[2,2],[5,2]]) %2 = 1 ? v = mfeigensearch([[1..20],2], [[3,Mod(2,3)],[7,Mod(5,7)]]); #v %3 = 1 ? F=v[1]; [mfparams(F)[1], mfcoefs(F,15)] %4 = [11, [0, 1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1]] @eprog The library syntax is \fun{GEN}{mfeigensearch}{GEN NK, GEN AP = NULL}. \subsec{mfeisenstein$(k,\{\var{CHI1}\},\{\var{CHI2}\})$}\kbdsidx{mfeisenstein}\label{se:mfeisenstein} Create the Eisenstein series $E_k(\chi_1,\chi_2)$, where $k \geq 1$, $\chi_i$ are Dirichlet characters and an omitted character is considered as trivial. \bprog ? CHI = Mod(3,4); ? E = mfeisenstein(3, CHI); ? mfcoefs(E, 6) %2 = [-1/4, 1, 1, -8, 1, 26, -8] ? CHI2 = Mod(4,5); ? mfcoefs(mfeisenstein(3,CHI,CHI2), 6) %3 = [0, 1, -1, -10, 1, 25, 10] ? mfcoefs(mfeisenstein(4,CHI,CHI), 6) %4 = [0, 1, 0, -28, 0, 126, 0] ? mfcoefs(mfeisenstein(4), 6) %5 = [1/240, 1, 9, 28, 73, 126, 252] @eprog\noindent Note that \kbd{meisenstein}$(k)$ is 0 for $k$ odd and $-B_{k}/(2k) \cdot E_k$ for $k$ even, where $$E_k(q) = 1 - (2k/B_k)\sum_{n\geq 1} \sigma_{k-1}(n) q^n$$ is the standard Eisenstein series. In other words it is normalized so that its linear coefficient is $1$. The library syntax is \fun{GEN}{mfeisenstein}{long k, GEN CHI1 = NULL, GEN CHI2 = NULL}. \subsec{mfembed$(f,\{v\})$}\kbdsidx{mfembed}\label{se:mfembed} Let $f$ be a generalized modular form with parameters $[N,k,\chi,P]$ (see \kbd{mfparams}, we denote $\Q(\chi)$ the subfield of $\C$ generated by the values of $\chi$ and $\Q(f)$ the field of definition of $f$. In this context $\Q(\chi)$ has a single canonical complex embeding given by $s: \kbd{Mod(t, polcyclo(n,t))} \mapsto \exp(2i\pi/n)$ and the number field $\Q(f)$ has $[\Q(f):\Q(\chi)]$ induced embeddings attached to the complex roots of the polynomial $s(P)$. If $\Q(f)$ is stricly larger than $\Q(\chi)$ we only allow an $f$ which is an eigenform, produced by \kbd{mfeigenbasis}. This function is meant to create embeddings of $\Q(f)$ and/or apply them to the object $v$, typically a vector of Fourier coefficients of $f$ from \kbd{mfcoefs}. \item If $v$ is omitted and $f$ is a modular form as above, we return the embedding of $\Q(\chi)$ if $\Q(\chi) = \Q(f)$ and a vector containing $[\Q(f):\Q(\chi)]$ embeddings of $\Q(f)$ otherwise. \item If $v$ is given, it must be a scalar in $\Q(f)$, or a vector/matrix of such, we apply the embeddings coefficientwise and return either a single result if $\Q(f) = \Q(\chi)$ and a vector of $[\Q(f):\Q(\chi)]$ results otherwise. \item Finally $f$ can be replaced by a single embedding produced by \kbd{mfembed}$(f)$ ($v$ was omitted) and we apply that particular embedding to $v$. \bprog ? mf = mfinit([35,2,Mod(11,35)], 0); ? [f] = mfbasis(mf); ? f.mod \\@com $\Q(\chi) = \Q(\zeta_3)$ %3 = t^2 + t + 1 ? v = mfcoefs(f,5); lift(v) \\@com coefficients in $\Q(\chi)$ %4 = [0, 2, -2*t - 2, 2*t, 2*t, -2*t - 2] ? mfembed(f, v) \\ single embedding %5 = [0, 2, -1 - 1.7320...*I, -1 + 1.73205...*I, -1 + 1.7320...*I, ...] ? [F] = mfeigenbasis(mf); ? mffields(mf) %7 = [y^2 + Mod(-2*t, t^2 + t + 1)] \\@com $[\Q(f):\Q(\chi)] = 2$ ? V = liftpol( mfcoefs(F,5) ); %8 = [0, 1, y + (-t - 1), (t + 1)*y + t, (-2*t - 2)*y + t, -t - 1] ? vall = mfembed(F, V); #vall %9 = 2 \\ 2 embeddings, both applied to V ? vall[1] \\ the first %10 = [0, 1, -1.2071... - 2.0907...*I, 0.2071... - 0.3587...*I, ...] ? vall[2] \\ and the second one %11 = [0, 1, 0.2071... + 0.3587...*I, -1.2071... + 2.0907...*I, ...] ? vE = mfembed(F); #vE \\ same 2 embeddings %12 = 2 ? mfembed(vE[1], V) \\ apply first embedding to V %13 = [0, 1, -1.2071... - 2.0907...*I, 0.2071... - 0.3587...*I, ...] @eprog For convenience, we also allow a modular form space from \kbd{mfinit} instead of $f$, corresponding to the single embedding of $\Q(\chi)$. \bprog ? [mfB,MC,C] = mfatkininit(mf,7); MC \\@com coefs in $\Q(\chi)$ %13 = [ Mod(2/7*t, t^2 + t + 1) Mod(-1/7*t - 2/7, t^2 + t + 1)] [Mod(-1/7*t - 2/7, t^2 + t + 1) Mod(2/7*t, t^2 + t + 1)] ? C \\ normalizing constant %14 = 0.33863... - 0.16787*I ? M = mfembed(mf, MC) / C \\ the true matrix for the action of w_7 [-0.6294... + 0.4186...*I -0.3625... - 0.5450...*I] [-0.3625... - 0.5450...*I -0.6294... + 0.4186...*I] ? exponent(M*conj(M) - 1) \\ M * conj(M) is close to 1 %16 = -126 @eprog The library syntax is \fun{GEN}{mfembed0}{GEN f, GEN v = NULL, long prec}. \subsec{mfeval$(\var{mf},F,\var{vtau})$}\kbdsidx{mfeval}\label{se:mfeval} Computes the numerical value of the modular form $F$, belonging to \var{mf}, at the complex number \kbd{vtau} or the vector \kbd{vtau} of complex numbers in the completed upper-half plane. The result is given with absolute error less than $2^{-B}$, where $B = \text{realbitprecision}$. If the field of definition $\Q(F)$ is larger than $\Q(\chi)$ then $F$ may be embedded into $\C$ in $d=[\Q(F):\Q(\chi)]$ ways, in which case a vector of the $d$ results is returned. \bprog ? mf = mfinit([11,2],0); F = mfbasis(mf)[1]; mfparams(F) %1 = [11, 2, 1, y] \\ Q(F) = Q(chi) = Q ? mfeval(mf,F,I/2) %2 = 0.039405471130100890402470386372028382117 ? mf = mfinit([35,2],0); F = mfeigenbasis(mf)[2]; mfparams(F) %3 = [35, 2, 1, y^2 - y - 4] \\ [Q(F) : Q(chi)] = 2 ? mfeval(mf,F,I/2) %4 = [0.045..., 0.0385...] \\ sigma_1(F) and sigma_2(F) at I/2 ? mf = mfinit([12,4],1); F = mfbasis(mf)[1]; ? mfeval(mf, F, 0.318+10^(-7)*I) %6 = 3.379... E-21 + 6.531... E-21*I \\ instantaneous ! @eprog\noindent In order to maximize the imaginary part of the argument, the function computes $(f \mid_k \gamma)(\gamma^{-1}\cdot\tau)$ for a suitable $\gamma$ not necessarily in $\Gamma_0(N)$ (in which case $f \mid \gamma$ is evaluated using \kbd{mfslashexpansion}). \bprog ? T = mfTheta(); mf = mfinit(T); mfeval(mf,T,[0,1/2,1,oo]) %1 = [1/2 - 1/2*I, 0, 1/2 - 1/2*I, 1] @eprog The library syntax is \fun{GEN}{mfeval}{GEN mf, GEN F, GEN vtau, long bitprec}. \subsec{mffields$(\var{mf})$}\kbdsidx{mffields}\label{se:mffields} Given \kbd{mf} as output by \kbd{mfinit} with parameters $(N,k,\chi)$, returns the vector of polynomials defining each Galois orbit of newforms over $\Q(\chi)$. \bprog ? mf = mfinit([35,2],0); mffields(mf) %1 = [y, y^2 - y - 4] @eprog\noindent Here the character is trivial so $\Q(\chi) = \Q)$ and there are 3 newforms: one is rational (corresponding to $y$), the other two are conjugate and defined over the quadratic field $\Q[y]/(y^2-y-4)$. \bprog ? [G,chi] = znchar(Mod(3,35)); ? zncharconductor(G,chi) %2 = 35 ? charorder(G,chi) %3 = 12 ? mf = mfinit([35, 2, [G,chi]],0); mffields(mf) %4 = [y, y] @eprog Here the character is primitive of order 12 and the two newforms are defined over $\Q(\chi) = \Q(\zeta_{12})$. \bprog ? mf = mfinit([35, 2, Mod(13,35)],0); mffields(mf) %3 = [y^2 + Mod(5*t, t^2 + 1)] @eprog This time the character has order 4 and there are two conjugate newforms over $\Q(\chi) = Q(i)$. The library syntax is \fun{GEN}{mffields}{GEN mf}. \subsec{mffromell$(E)$}\kbdsidx{mffromell}\label{se:mffromell} $E$ being an elliptic curve defined over $Q$ given by an integral model in \kbd{ellinit} format, computes a 3-component vector \kbd{[mf,F,v]}, where $F$ is the newform corresponding to $E$ by modularity, \kbd{mf} is the newspace to which $F$ belongs, and \kbd{v} gives the coefficients of $F$ on \kbd{mfbasis(mf)}. \bprog ? E = ellinit("26a1"); ? [mf,F,co] = mffromell(E); ? co %2 = [3/4, 1/4]~ ? mfcoefs(F, 5) %3 = [0, 1, -1, 1, 1, -3] ? ellan(E, 5) %4 = [1, -1, 1, 1, -3] @eprog The library syntax is \fun{GEN}{mffromell}{GEN E}. \subsec{mffrometaquo$(\var{eta},\{\fl=0\})$}\kbdsidx{mffrometaquo}\label{se:mffrometaquo} Modular form corresponding to the eta quotient matrix \kbd{eta}. If the valuation $v$ at infinity is fractional, return $0$. If the eta quotient is not holomorphic but simply meromorphic, return $0$ if \kbd{flag=0}, return the eta quotient (divided by $q$ to the power $-v$ if $v < 0$, i.e., with valuation $0$) if flag is set. \bprog ? mffrometaquo(Mat([1,1]),1) %1 = 0 ? mfcoefs(mffrometaquo(Mat([1,24])),6) %2 = [0, 1, -24, 252, -1472, 4830, -6048] ? mfcoefs(mffrometaquo([1,1;23,1]),10) %3 = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0] ? F = mffrometaquo([1,2;2,-1]); mfparams(F) %4 = [16,1/2,1,y] ? mfcoefs(F,10) %5 = [1, -2, 0, 0, 2, 0, 0, 0, 0, -2, 0] ? mffrometaquo(Mat([1,-24])) %6 = 0 ? f = mffrometaquo(Mat([1,-24]),1); mfcoefs(f,6) %7 = [1, 24, 324, 3200, 25650, 176256, 1073720] @eprog\noindent For convenience, a \typ{VEC} is also accepted instead of a factorization matrix with a single row: \bprog ? f = mffrometaquo([1,24]); \\ also valid @eprog The library syntax is \fun{GEN}{mffrometaquo}{GEN eta, long flag}. \subsec{mffromlfun$(L)$}\kbdsidx{mffromlfun}\label{se:mffromlfun} Let $L$ being an $L$-function in any of the \kbd{lfun} formats representing a self-dual modular form (for instance an eigenform). Return \kbd{[NK,space,v]} when \kbd{mf = mfinit(NK,space)} is the modular form space containing the form and \kbd{mftobasis(mf, v)} will represent it on the space basis. If $L$ has rational coefficients, this will be enough to recognize the modular form in \var{mf}: \bprog ? L = lfuncreate(x^2+1); ? lfunan(L,10) %2 = [1, 1, 0, 1, 2, 0, 0, 1, 1, 2] ? [NK,space,v] = mffromlfun(L); NK %4 = [4, 1, -4] ? mf=mfinit(NK,space); w = mftobasis(mf,v) %5 = [1.0000000000000000000000000000000000000]~ ? [f] = mfbasis(mf); mfcoefs(f,10) \\ includes a_0 ! %6 = [1/4, 1, 1, 0, 1, 2, 0, 0, 1, 1, 2] @eprog If $L$ has inexact complex coefficients, one can for instance compute an eigenbasis for \var{mf} and check whether one of the attached $L$-function is reasonably close to $L$. In the example, we cheat by producing the $L$ function from an eigenform in a known space, but the function does not use this information: \bprog ? mf = mfinit([32,6,Mod(5,32)],0); ? [poldegree(K) | K<-mffields(mf)] %2 = [19] \\ one orbit, [Q(F) : Q(chi)] = 19 ? L = lfunmf(mf)[1][1]; \\ one of the 19 L-functions attached to F ? lfunan(L,3) %4 = [1, 5.654... - 0.1812...*I, -7.876... - 19.02...*I] ? [NK,space,v] = mffromlfun(L); NK %5 = [32, 6, Mod(5, 32)] ? vL = concat(lfunmf(mf)); \\ L functions for all cuspidal eigenforms ? an = lfunan(L,10); ? for (i = 1, #vL, if (normlp(lfunan(vL[i],10) - an, oo) < 1e-10, print(i))); 1 @eprog The library syntax is \fun{GEN}{mffromlfun}{GEN L, long prec}. \subsec{mffromqf$(Q,\{P\})$}\kbdsidx{mffromqf}\label{se:mffromqf} $Q$ being an even integral positive definite quadratic form and $P$ a homogeneous spherical polynomial for $Q$, computes a 3-component vector $[\var{mf},F,v]$, where $F$ is the theta function corresponding to $(Q,P)$, \var{mf} is the corresponding space of modular forms (from \kbd{mfinit}), and $v$ gives the coefficients of $F$ on \kbd{mfbasis(mf)}. \bprog ? [mf,F,v] = mffromqf(2*matid(10)); v %1 = [64/5, 4/5, 32/5]~ ? mfcoefs(F, 5) %2 = [1, 20, 180, 960, 3380, 8424] ? mfcoef(F, 10000) \\ number of ways of writing 10000 as sum of 10 squares %3 = 128205250571893636 ? mfcoefs(F, 10000); \\ fast ! time = 220ms ? [mf,F,v] = mffromqf([2,0;0,2],x^4-6*x^2*y^2+y^4); ? mfcoefs(F,10) %6 = [0, 4, -16, 0, 64, -56, 0, 0, -256, 324, 224] ? mfcoef(F,100000) \\ instantaneous %7 = 41304367104 @eprog Odd dimensions are supported, corresponding to forms of half-integral weight: \bprog ? [mf,F,v] = mffromqf(2*matid(3)); ? mfisequal(F, mfpow(mfTheta(),3)) %2 = 1 ? mfcoefs(F, 32) \\ illustrate Legendre's 3-square theorem %3 = [ 1, 6, 12, 8, 6, 24, 24, 0, 12, 30, 24, 24, 8, 24, 48, 0, 6, 48, 36, 24,24, 48, 24, 0, 24, 30, 72, 32, 0, 72, 48, 0, 12] @eprog The library syntax is \fun{GEN}{mffromqf}{GEN Q, GEN P = NULL}. \subsec{mfgaloistype$(\var{NK},\{F\})$}\kbdsidx{mfgaloistype}\label{se:mfgaloistype} \kbd{NK} being either \kbd{[N,1,CHI]} or an \kbd{mf} output by \kbd{mfinit} in weight $1$, gives the vector of types of Galois representations attached to each cuspidal eigenform, unless the modular form \kbd{F} is specified, in which case only for \kbd{F} (note that it is not tested whether \kbd{F} belongs to the correct modular form space, nor whether it is a cuspidal eigenform). Types $A_4$, $S_4$, $A_5$ are represented by minus their cardinality $-12$, $-24$, or $-60$, and type $D_n$ is represented by its cardinality, the integer $2n$: \bprog ? mfgaloistype([124,1, Mod(67,124)]) \\ A4 %1 = [-12] ? mfgaloistype([148,1, Mod(105,148)]) \\ S4 %2 = [-24] ? mfgaloistype([633,1, Mod(71,633)]) \\ D10, A5 %3 = [10, -60] ? mfgaloistype([239,1, -239]) \\ D6, D10, D30 %4 = [6, 10, 30] ? mfgaloistype([71,1, -71]) %5 = [14] ? mf = mfinit([239,1, -239],0); F = mfeigenbasis(mf)[2]; ? mfgaloistype(mf, F) %7 = 10 @eprog The library syntax is \fun{GEN}{mfgaloistype}{GEN NK, GEN F = NULL}. \subsec{mfhecke$(\var{mf},F,n)$}\kbdsidx{mfhecke}\label{se:mfhecke} $F$ being a modular form in modular form space \var{mf}, returns $T(n)F$, where $T(n)$ is the $n$-th Hecke operator. \misctitle{Warning} If $F$ is of level $MK*M*mftobasis(mf2,x),BE) %1 = [[1, 0, 0, 1, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0]~,\ [0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -3, 0, 0]~ ? EI1 = mflinear(mf, E1); EI2=mflinear(mf, E2); @eprog\noindent These are the two eigenfunctions in the space \kbd{mf}, the first (resp., second) will have Shimura image a multiple of $BE[1]$ (resp., $BE[2]$). The function \kbd{mfkohneneigenbasis} does this directly. The library syntax is \fun{GEN}{mfkohnenbijection}{GEN mf}. \subsec{mfkohneneigenbasis$(\var{mf},\var{bij})$}\kbdsidx{mfkohneneigenbasis}\label{se:mfkohneneigenbasis} \kbd{mf} being a cuspidal space of half-integral weight $k\ge3/2$ and \kbd{bij} being the output of \kbd{mfkohnenbijection(mf)}, outputs a $3$-component vector \kbd{[mf0,BNEW,BEIGEN]}, where \kbd{BNEW} and \kbd{BEIGEN} are two matrices whose columns are the coefficients of a basis of the Kohnen new space and of the eigenforms on the basis of \kbd{mf} respectively, and \kbd{mf0} is the corresponding new space of integral weight $2k-1$. \bprog ? mf=mfinit([44,5/2],1);bij=mfkohnenbijection(mf); ? [mf0,BN,BE]=mfkohneneigenbasis(mf,bij); ? BN~ %2 = [2 0 0 -2 2 0 -8] [2 0 0 4 14 0 -32] ? BE~ %3 = [Mod(1, y^2 - 3) Mod(0, y^2 - 3) Mod(0, y^2 - 3) Mod(y - 1, y^2 - 3)\ Mod(2*y + 1, y^2 - 3) Mod(0, y^2 - 3) Mod(-4*y - 4, y^2 - 3)] ? lift(mfcoefs(mf,20)*BE[,1]) %4 = [0, 1, 0, 0, y - 1, 2*y + 1, 0, 0, 0, -4*y - 4, 0, 0,\ -5*y + 3, 0, 0, 0, -6, 0, 0, 0, 7*y + 9]~ @eprog The library syntax is \fun{GEN}{mfkohneneigenbasis}{GEN mf, GEN bij}. \subsec{mflinear$(\var{vF},v)$}\kbdsidx{mflinear}\label{se:mflinear} \kbd{vF} being a vector of generalized modular forms and \kbd{v} a vector of coefficients of same length, compute the linear combination of the entries of \kbd{vF} with coefficients \kbd{v}. \misctitle{Note} Use this in particular to subtract two forms $F$ and $G$ (with $vF=[F,G]$ and $v=[1,-1]$), or to multiply an form by a scalar $\lambda$ (with $vF=[F]$ and $v=[\lambda]$). \bprog ? D = mfDelta(); G = mflinear([D],[-3]); ? mfcoefs(G,4) %2 = [0, -3, 72, -756, 4416] @eprog For user convenience, we allow \item a modular form space \kbd{mf} as a \kbd{vF} argument, which is understood as \kbd{mfbasis(mf)}; \item in this case, we also allow a modular form $f$ as $v$, which is understood as \kbd{mftobasis}$(\var{mf}, f)$. \bprog ? T = mfpow(mfTheta(),7); F = mfShimura(T,-3); \\ Shimura lift for D=-3 ? mfcoefs(F,8) %2 = [-5/9, 280, 9240, 68320, 295960, 875280, 2254560, 4706240, 9471000] ? mf = mfinit(F); G = mflinear(mf,F); ? mfcoefs(G,8) %4 = [-5/9, 280, 9240, 68320, 295960, 875280, 2254560, 4706240, 9471000] @eprog\noindent This last construction allows to replace a general modular form by a simpler linear combination of basis functions, which is often more efficient: \bprog ? T10=mfpow(mfTheta(),10); mfcoef(T10, 10^4) \\ direct evaluation time = 399 ms. %5 = 128205250571893636 ? mf=mfinit(T10); F=mflinear(mf,T10); \\ instantaneous ? mfcoef(F, 10^4) \\ after linearization time = 67 ms. %7 = 128205250571893636 @eprog The library syntax is \fun{GEN}{mflinear}{GEN vF, GEN v}. \subsec{mfmanin$(\var{FS})$}\kbdsidx{mfmanin}\label{se:mfmanin} Given the modular symbol $FS$ associated to an eigenform $F$ by \kbd{mfsymbol(mf,F)}, computes the even and odd special polynomials as well as the even and odd periods $\omega^+$ and $\omega^-$ as a vector $[[P^+,P^-],[\omega^+,\omega^-,r]]$, where $r=\Im(\omega^+\overline{\omega^-})/$. If $F$ has several embeddings into $\C$, give the vector of results corresponding to each embedding. \bprog ? D=mfDelta(); mf=mfinit(D); DS=mfsymbol(mf,D); ? [pols,oms]=mfmanin(DS); pols %2 = [[4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x],\ [-36*x^10 + 691*x^8 - 2073*x^6 + 2073*x^4 - 691*x^2 + 36]] ? oms %3 = [0.018538552324740326472516069364750571812,\ -0.00033105361053212432521308691198949874026*I, 4096/691] ? mf=mfinit([11,2],0); F=mfeigenbasis(mf)[1]; FS=mfsymbol(mf,F); ? [pols,oms]=mfmanin(FS);pols %5 = [[0, 0, 0, 1, 1, 0, 0, -1, -1, 0, 0, 0],\ [2, 0, 10, 5, -5, -10, -10, -5, 5, 10, 0, -2]] ? oms[3] %6 = 24/5 @eprog The library syntax is \fun{GEN}{mfmanin}{GEN FS, long bitprec}. \subsec{mfmul$(F,G)$}\kbdsidx{mfmul}\label{se:mfmul} Multiply the two generalized modular forms $F$ and $G$. \bprog ? E4 = mfEk(4); G = mfmul(mfmul(E4,E4),E4); ? mfcoefs(G, 4) %2 = [1, 720, 179280, 16954560, 396974160] ? mfcoefs(mfpow(E4,3), 4) %3 = [1, 720, 179280, 16954560, 396974160] @eprog The library syntax is \fun{GEN}{mfmul}{GEN F, GEN G}. \subsec{mfnumcusps$(N)$}\kbdsidx{mfnumcusps}\label{se:mfnumcusps} Number of cusps of $\Gamma_0(N)$ \bprog ? mfnumcusps(24) %1 = 8 ? mfcusps(24) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/8, 1/12, 1/24] @eprog The library syntax is \fun{GEN}{mfnumcusps}{GEN N}. \subsec{mfparams$(F)$}\kbdsidx{mfparams}\label{se:mfparams} If $F$ is a modular form space, returns \kbd{[N,k,CHI,space]}, level, weight, character, and space code. If $F$ is a generalized modular form, returns \kbd{[N,k,CHI,P]}, where $P$ is the (polynomial giving the) field of definition of $F$: in that case the level $N$ may be a multiple of the level of $F$ and the polynomial $P$ may define a larger field than $\Q(F)$. If you want the true level of $F$ from this result, use \kbd{mfconductor(mfinit(F),F)}. The polynomial $P$ defines an extension of $\Q(\chi) = \Q[t]/(\Phi(t))$ for the cyclotomic polynomial of order $f(\chi)$; it has coefficients in that number field (polmods in $t$). In contrast with \kbd{mfparams(f)[4]} which always gives the polynomial $P$ defining the relative extension $\Q(f)/\Q(\chi)$, the member function \kbd{$f$.mod} returns the polynomial used to define $\Q(f)$ over $\Q$ (either a cyclotomic polynomial or a polynomial with cyclotomic coefficients). \bprog ? E1 = mfeisenstein(4,-3,-4); E2 = mfeisenstein(3,5,-7); E3 = mfmul(E1,E2); ? apply(mfparams, [E1,E2,E3]) %2 = [[12, 4, 12, y], [35, 3, -35, y], [420, 7, -420, y]] ? mf = mfinit([36,2,Mod(13,36)],0); [f] = mfeigenbasis(mf); mfparams(mf) %3 = [36, 2, Mod(13, 36), 0] ? mfparams(f) %4 = [36, 2, Mod(13, 36), y] ? f.mod %5 = t^2 + t + 1 ? mf = mfinit([36,4,Mod(13,36)],0); [f] = mfeigenbasis(mf); ? mfparams(f) %7 = [36, 4, Mod(13, 36), y^3 + Mod(2*t - 2, t^2 + t + 1)*y^2 + Mod(-4*t + 6, t^2+t+1)*y + Mod(10*t - 1, t^2+t+1)] @eprog The library syntax is \fun{GEN}{mfparams}{GEN F}. \subsec{mfperiodpol$(\var{mf},f,\{\fl=0\})$}\kbdsidx{mfperiodpol}\label{se:mfperiodpol} Period polynomial of the cuspidal part of the form $f$, in other words $\int_0^{i\infty}(X-\tau)^{k-2}f(\tau)\,d\tau$. If \kbd{flag} is $0$, ordinary period polynomial. If it is $1$ or $-1$, even or odd part of that polynomial. $f$ can also be the modular symbol output by \kbd{mfsymbol}(mf,f). \bprog ? D = mfDelta(); mf = mfinit(D,0); ? PP = mfperiodpol(mf, D, -1); PP/=polcoeff(PP, 1); bestappr(PP) %1 = x^9 - 25/4*x^7 + 21/2*x^5 - 25/4*x^3 + x ? PM = mfperiodpol(mf, D, 1); PM/=polcoeff(PM, 0); bestappr(PM) %2 = -x^10 + 691/36*x^8 - 691/12*x^6 + 691/12*x^4 - 691/36*x^2 + 1 @eprog The library syntax is \fun{GEN}{mfperiodpol}{GEN mf, GEN f, long flag, long bitprec}. \subsec{mfperiodpolbasis$(k,\{\fl=0\})$}\kbdsidx{mfperiodpolbasis}\label{se:mfperiodpolbasis} Basis of period polynomials for weight k. If flag=1 or $-1$, basis of odd or even period polynomials. \bprog ? mfperiodpolbasis(12,1) %1 = [x^8 - 3*x^6 + 3*x^4 - x^2, x^10 - 1] ? mfperiodpolbasis(12,-1) %2 = [4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x] @eprog The library syntax is \fun{GEN}{mfperiodpolbasis}{long k, long flag}. \subsec{mfpetersson$(\var{fs},\{\var{gs}\})$}\kbdsidx{mfpetersson}\label{se:mfpetersson} Petersson scalar product of the modular forms $f$ and $g$ belonging to the same modular form space \kbd{mf}, given by the corresponding ``modular symbols'' \kbd{fs} and \kbd{gs} output by \kbd{mfsymbol} (also in weight $1$ and half-integral weight, where symbols do not exist). If \kbd{gs} is omitted it is understood to be equal to \kbd{fs}. The scalar product is normalized by the factor $1/[\Gamma:\Gamma_0(N)]$. Note that $f$ and $g$ can both be noncuspidal, in which case the program returns an error if the product is divergent. If the fields of definition $\Q(f)$ and $\Q(g)$ are equal to $\Q(\chi)$ the result is a scalar. If $[\Q(f):\Q(\chi)]=d>1$ and $[\Q(g):\Q(\chi)]=e>1$ the result is a $d\times e$ matrix corresponding to all the embeddings of $f$ and $g$. In the intermediate cases $d=1$ or $e=1$ the result is a row or column vector. \bprog ? D=mfDelta(); mf=mfinit(D); DS=mfsymbol(mf,D); mfpetersson(DS) %1 = 1.0353620568043209223478168122251645932 E-6 ? mf=mfinit([11,6],0);B=mfeigenbasis(mf);BS=vector(#B,i,mfsymbol(mf,B[i])); ? mfpetersson(BS[1]) %3 = 1.6190120685220988139111708455305245466 E-5 ? mfpetersson(BS[1],BS[2]) %4 = [-3.826479006582967148 E-42 - 2.801547395385577002 E-41*I,\ 1.6661127341163336125 E-41 + 1.1734725972345985061 E-41*I,\ 0.E-42 - 6.352626992842664490 E-41*I]~ ? mfpetersson(BS[2]) %5 = [ 2.7576133733... E-5 2.0... E-42 6.3... E-43 ] [ -4.1... E-42 6.77837030070... E-5 3.3...E-42 ] [ -6.32...E-43 3.6... E-42 2.27268958069... E-5] ? mf=mfinit([23,2],0); F=mfeigenbasis(mf)[1]; FS=mfsymbol(mf,F); ? mfpetersson(FS) %5 = [0.0039488965740025031688548076498662860143 -3.56 ... E-40] [ -3.5... E-40 0.0056442542987647835101583821368582485396] @eprog Noncuspidal example: \bprog ? E1=mfeisenstein(5,1,-3);E2=mfeisenstein(5,-3,1); ? mf=mfinit([12,5,-3]); cusps=mfcusps(12); ? apply(x->mfcuspval(mf,E1,x),cusps) %3 = [0, 0, 1, 0, 1, 1] ? apply(x->mfcuspval(mf,E2,x),cusps) %4 = [1/3, 1/3, 0, 1/3, 0, 0] ? E1S=mfsymbol(mf,E1);E2S=mfsymbol(mf,E2); ? mfpetersson(E1S,E2S) %6 = -1.884821671646... E-5 - 1.9... E-43*I @eprog Weight 1 and 1/2-integral weight example: \bprog ? mf=mfinit([23,1,-23],1);F=mfbasis(mf)[1];FS=mfsymbol(mf,F); ? mfpetersson(mf,FS) %2 = 0.035149946790370230814006345508484787443 ? mf=mfinit([4,9/2],1);F=mfbasis(mf)[1];FS=mfsymbol(mf,F); ? mfpetersson(FS) %4 = 0.00015577084407139192774373662467908966030 @eprog The library syntax is \fun{GEN}{mfpetersson}{GEN fs, GEN gs = NULL}. \subsec{mfpow$(F,n)$}\kbdsidx{mfpow}\label{se:mfpow} Compute $F^n$, where $n$ is an integer and $F$ is a generalized modular form: \bprog ? G = mfpow(mfEk(4), 3); \\ E4^3 ? mfcoefs(G, 4) %2 = [1, 720, 179280, 16954560, 396974160] @eprog The library syntax is \fun{GEN}{mfpow}{GEN F, long n}. \subsec{mfsearch$(\var{NK},V,\{\var{space}\})$}\kbdsidx{mfsearch}\label{se:mfsearch} \kbd{NK} being of the form \kbd{[N,k]} with $k$ possibly half-integral, search for a modular form with rational coefficients, of weight $k$ and level $N$, whose initial coefficients $a(0)$,... are equal to $V$; \kbd{space} specifies the modular form spaces in which to search, in \kbd{mfinit} or \kbd{mfdim} notation. The output is a list of matching forms with that given level and weight. Note that the character is of the form $(D/.)$, where $D$ is a (positive or negative) fundamental discriminant dividing $N$. The forms are sorted by increasing $|D|$. The parameter $N$ can be replaced by a vector of allowed levels, in which case the list of forms is sorted by increasing level, then increasing $|D|$. If a form is found at level $N$, any multiple of $N$ with the same $D$ is not considered. Some useful possibilities are \item \kbd{[$N_1$..$N_2$]}: all levels between $N_1$ and $N_2$, endpoints included; \item \kbd{$F$ * [$N_1$..$N_2$]}: same but levels divisible by $F$; \item \kbd{divisors}$(N_0)$: all levels dividing $N_0$. Note that this is different from \kbd{mfeigensearch}, which only searches for rational eigenforms. \bprog ? F = mfsearch([[1..40], 2], [0,1,2,3,4], 1); #F %1 = 3 ? [ mfparams(f) | f <- F ] %2 = [[38, 2, 1, y], [40, 2, 8, y], [40, 2, 40, y]] ? mfcoefs(F[1],10) %3 = [0, 1, 2, 3, 4, -5, -8, 1, -7, -5, 7] @eprog The library syntax is \fun{GEN}{mfsearch}{GEN NK, GEN V, long space}. \subsec{mfshift$(F,s)$}\kbdsidx{mfshift}\label{se:mfshift} Divide the generalized modular form $F$ by $q^s$, omitting the remainder if there is one. One can have $s<0$. \bprog ? D=mfDelta(); mfcoefs(mfshift(D,1), 4) %1 = [1, -24, 252, -1472, 4830] ? mfcoefs(mfshift(D,2), 4) %2 = [-24, 252, -1472, 4830, -6048] ? mfcoefs(mfshift(D,-1), 4) %3 = [0, 0, 1, -24, 252] @eprog The library syntax is \fun{GEN}{mfshift}{GEN F, long s}. \subsec{mfshimura$(\var{mf}, F, \{D = 1\})$}\kbdsidx{mfshimura}\label{se:mfshimura} $F$ being a modular form of half-integral weight $k\geq 3/2$ and $D$ a (not necessarily fundamental) discriminant of suitable sign, returns the Shimura lift $G$ of weight $2k-1$ corresponding to $D$. The sign of $D$ should be equal to $(-1)^{k-1/2}\epsilon$, where $\epsilon=1$ if $\chi$ is defined modulo $N/4$, $\epsilon=-1$ if $(-4/.)\chi$ is defined modulo $N/4$ (and error otherwise). This function returns $[\var{mf2},G,v]$ where \var{mf2} is a modular form space containing $G$ and $v$ expresses $G$ in terms of \kbd{mfbasis}$(\var{mf2})$; so that $G$ is \kbd{mflinear}$(\var{mf2},v)$. By extension, we allow $D$ to be a positive squarefree integer, but in that case if $(-1)^{k-1/2}\epsilon\cdot D$ is not a discriminant, the Kohnen $+$-space will in general not be sent to level $N/4$ but only $N/2$. \bprog ? F = mfpow(mfTheta(), 7); mf = mfinit(F); ? [mf2, G, v] = mfshimura(mf, F, -3); mfcoefs(G,5) %2 = [-5/9, 280, 9240, 68320, 295960, 875280] ? mfparams(G) %3 = [1, 6, 1, y] ? mfparams(mf2) %4 = [2, 6, 1, 4] \\ it may happen that G has lower level than expected ? v %5 = [280, 0]~ ? mfcoefs(mf2, 5) %6 = [-1/504 -1/504] [ 1 0] [ 33 1] [ 244 0] [ 1057 33] [ 3126 0] ? mf = mfinit([60,5/2],1); F = mflinear(mf,mfkohnenbasis(mf)[,1]); ? mfparams(mfshimura(mf,F,1)[2]) %8 = [15, 4, 1, y] ? mfparams(mfshimura(mf,F,6)[2]) %9 = [30, 4, 1, y] @eprog The library syntax is \fun{GEN}{mfshimura}{GEN mf, GEN F, long D}. \subsec{mfslashexpansion$(\var{mf},f,g,n,\var{flrat},\{\&\var{params}\})$}\kbdsidx{mfslashexpansion}\label{se:mfslashexpansion} Let \var{mf} be a modular form space in leven $N$, $f$ a modular form belonging to \var{mf} and let $g$ be in $M_2^+(Q)$. This function computes the Fourier expansion of $f|_k g$ to $n$ terms. We first describe the behaviour when \kbd{flrat} is 0: the result is a vector $v$ of floating point complex numbers such that $$f|_k g(\tau) = q^\alpha \sum_{m\ge0} v[m+1] q^{m/w},$$ where $q = e(\tau)$, $w$ is the width of the cusp $g(i\infty)$ (namely $(N/(c^2,N)$ if $g$ is integral) and $\alpha$ is a rational number. If \kbd{params} is given, it is set to the parameters $[\alpha,w, \kbd{matid}(2)]$. If \kbd{flrat} is 1, the program tries to rationalize the expression, i.e., to express the coefficients as rational numbers or polmods. We write $g = \lambda \cdot M \cdot A$ where $\lambda \in \Q^*$, $M\in \text{SL}_2(\Z)$ and $A = [a,b;0,d]$ is upper triangular, integral and primitive with $a > 0$, $d > 0$ and $0 \leq b < d$. Let $\alpha$ and $w$ by the parameters attached to the expansion of $F := f |_k M$ as above, i.e. $$ F(\tau) = q^\alpha \sum_{m\ge0} v[m+1] q^{m/w}.$$ The function returns the expansion $v$ of $F = f |_k M$ and sets the parameters to $[\alpha, w, A]$. Finally, the desired expansion is $(a/d)^{k/2} F(\tau + b/d)$. The latter is identical to the returned expansion when $A$ is the identity, i.e. when $g\in \text{PSL}_2(\Z)$. If this is not the case, the expansion differs from $v$ by the multiplicative constant $(a/d)^{k/2} e(\alpha b/(dw))$ and a twist by a root of unity $q^{1/w} \to e(b/(dw)) q^{1/w}$. The complications introduced by this extra matrix $A$ allow to recognize the coefficients in a much smaller cyclotomic field, hence to obtain a simpler description overall. (Note that this rationalization step may result in an error if the program cannot perform it.) \bprog ? mf = mfinit([32,4],0); f = mfbasis(mf)[1]; ? mfcoefs(f, 10) %2 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 47, 0] ? mfatk = mfatkininit(mf,32); mfcoefs(mfatkin(mfatk,f),10) / mfatk[3] %3 = [0, 1, 0, 16, 0, 22, 0, 32, 0, -27, 0] ? mfatk[3] \\ here normalizing constant C = 1, but need in general %4 = 1 ? mfslashexpansion(mf,f,[0,-1;1,0],10,1,¶ms) * 32^(4/2) %5 = [0, 1, 0, 16, 0, 22, 0, 32, 0, -27, 0] ? params %6 = [0, 32, [1, 0; 0, 1]] ? mf = mfinit([12,8],0); f = mfbasis(mf)[1]; ? mfslashexpansion(mf,f,[1,0;2,1],7,0) %7 = [0, 0, 0, 0.6666666... + 0.E-38*I, 0, -3.999999... + 6.92820...*I, 0,\ -11.99999999... - 20.78460969...*I] ? mfslashexpansion(mf,f,[1,0;2,1],7,1, ¶ms) %8 = [0, 0, 0, 2/3, 0, Mod(8*t, t^2+t+1), 0, Mod(-24*t-24, t^2+t+1)] ? params %9 = [0, 3, [1, 0; 0, 1]] @eprog If $[\Q(f):\Q(\chi)]>1$, the coefficients may be polynomials in $y$, where $y$ is any root of the polynomial giving the field of definition of $f$ (\kbd{f.mod} or \kbd{mfparams(f)[4]}). \bprog ? mf=mfinit([23,2],0);f=mfeigenbasis(mf)[1]; ? mfcoefs(f,5) %1 = [Mod(0, y^2 - y - 1), Mod(1, y^2 - y - 1), Mod(-y, y^2 - y - 1),\ Mod(2*y - 1, y^2 - y - 1), Mod(y - 1, y^2 - y - 1), Mod(-2*y, y^2 - y - 1)] ? mfslashexpansion(mf,f,[1,0;0,1],5,1) %2 = [0, 1, -y, 2*y - 1, y - 1, -2*y] ? mfslashexpansion(mf,f,[0,-1;1,0],5,1) %3 = [0, -1/23, 1/23*y, -2/23*y + 1/23, -1/23*y + 1/23, 2/23*y] @eprog The library syntax is \fun{GEN}{mfslashexpansion}{GEN mf, GEN f, GEN g, long n, long flrat, GEN *params = NULL, long prec}. \subsec{mfspace$(\var{mf},\{f\})$}\kbdsidx{mfspace}\label{se:mfspace} Identify the modular space \var{mf}, resp.~the modular form $f$ in \var{mf} if present, as the flag given to \kbd{mfinit}. Returns 0 (newspace), 1 (cuspidal space), 2 (old space), 3 (Eisenstein space) or 4 (full space). \bprog ? mf = mfinit([1,12],1); mfspace(mf) %1 = 1 ? mfspace(mf, mfDelta()) %2 = 0 \\ new space @eprog\noindent This function returns $-1$ when the form $f$ is modular but does not belong to the space. \bprog ? mf = mfinit([1,2]; mfspace(mf, mfEk(2)) %3 = -1 @eprog When $f$ is not modular and is for instance only quasi-modular, the function returns nonsense: \bprog ? M6 = mfinit([1,6]); ? dE4 = mfderiv(mfEk(4)); \\ not modular ! ? mfspace(M6,dE4) \\ asserts (wrongly) that E4' belongs to new space %3 = 0 @eprog The library syntax is \fun{long}{mfspace}{GEN mf, GEN f = NULL}. \subsec{mfsplit$(\var{mf},\{\var{dimlim}=0\},\{\fl=0\})$}\kbdsidx{mfsplit}\label{se:mfsplit} \kbd{mf} from \kbd{mfinit} with integral weight containing the new space (either the new space itself or the cuspidal space or the full space), and preferably the newspace itself for efficiency, split the space into Galois orbits of eigenforms of the newspace, satisfying various restrictions. The functions returns $[vF, vK]$, where $vF$ gives (Galois orbit of) eigenforms and $vK$ is a list of polynomials defining each Galois orbit. The eigenforms are given in \kbd{mftobasis} format, i.e. as a matrix whose columns give the forms with respect to \kbd{mfbasis(mf)}. If \kbd{dimlim} is set, only the Galois orbits of dimension $\leq \kbd{dimlim}$ are computed (i.e. the rational eigenforms if $\kbd{dimlim} = 1$ and the character is real). This can considerably speed up the function when a Galois orbit is defined over a large field. \kbd{flag} speeds up computations when the dimension is large: if $flag=d>0$, when the dimension of the eigenspace is $>d$, only the Galois polynomial is computed. Note that the function \kbd{mfeigenbasis} returns all eigenforms in an easier to use format (as modular forms which can be input as is in other functions); \kbd{mfsplit} is only useful when you can restrict to orbits of small dimensions, e.g. rational eigenforms. \bprog ? mf=mfinit([11,2],0); f=mfeigenbasis(mf)[1]; mfcoefs(f,16) %1 = [0, 1, -2, -1, ...] ? mf=mfinit([23,2],0); f=mfeigenbasis(mf)[1]; mfcoefs(f,16) %2 = [Mod(0, z^2 - z - 1), Mod(1, z^2 - z - 1), Mod(-z, z^2 - z - 1), ...] ? mf=mfinit([179,2],0); apply(poldegree, mffields(mf)) %3 = [1, 3, 11] ? mf=mfinit([719,2],0); ? [vF,vK] = mfsplit(mf, 5); \\ fast when restricting to small orbits time = 192 ms. ? #vF \\ a single orbit %5 = 1 ? poldegree(vK[1]) \\ of dimension 5 %6 = 5 ? [vF,vK] = mfsplit(mf); \\ general case is slow time = 2,104 ms. ? apply(poldegree,vK) %8 = [5, 10, 45] \\ because degree 45 is large... @eprog The library syntax is \fun{GEN}{mfsplit}{GEN mf, long dimlim, long flag}. \subsec{mfsturm$(\var{NK})$}\kbdsidx{mfsturm}\label{se:mfsturm} Gives the Sturm bound for modular forms on $\Gamma_0(N)$ and weight $k$, i.e., an upper bound for the order of the zero at infinity of a nonzero form. \kbd{NK} is either \item a pair $[N,k]$, \item or the output of \tet{mfinit} in which case the exact upper bound is returned. \bprog ? NK = [96,6]; mfsturm(NK) %1 = 97 ? mf=mfinit(NK,1); mfsturm(mf) %2 = 76 ? mfdim(NK,0) \\ new space %3 = 72 @eprog The library syntax is \fun{long}{mfsturm}{GEN NK}. \subsec{mfsymbol$(\var{mf},f)$}\kbdsidx{mfsymbol}\label{se:mfsymbol} Initialize data for working with all period polynomials of the modular form $f$: this is essential for efficiency for functions such as \kbd{mfsymboleval}, \kbd{mfmanin}, and \kbd{mfpetersson}. An \kbd{mfsymbol} contains an \kbd{mf} structure and can always be used whenever an \kbd{mf} would be needed. \bprog ? mf=mfinit([23,2],0);F=mfeigenbasis(mf)[1]; ? FS=mfsymbol(mf,F); ? mfsymboleval(FS,[0,oo]) %3 = [8.762565143790690142 E-39 + 0.0877907874...*I, -5.617375463602574564 E-39 + 0.0716801031...*I] ? mfpetersson(FS) %4 = [0.0039488965740025031688548076498662860143 1.2789721111175127425 E-40] [1.2630501762985554269 E-40 0.0056442542987647835101583821368582485396] @eprog\noindent By abuse of language, initialize data for working with \kbd{mfpetersson} in weight $1$ and half-integral weight (where no symbol exist); the \kbd{mf} argument may be an \kbd{mfsymbol} attached to a form on the space, which avoids recomputing data independent of the form. \bprog ? mf=mfinit([12,9/2],1); F=mfbasis(mf); ? fs=mfsymbol(mf,F[1]); time = 476 ms ? mfpetersson(fs) %2 = 1.9722437519492014682047692073275406145 E-5 ? f2s = mfsymbol(mf,F[2]); time = 484 ms. ? mfpetersson(f2s) %4 = 1.2142222531326333658647877864573002476 E-5 ? gs = mfsymbol(fs,F[2]); \\ re-use existing symbol, a little faster time = 430 ms. ? mfpetersson(gs) == %4 \\ same value %6 = 1 @eprog For simplicity, we also allow \kbd{mfsymbol(f)} instead of \kbd{mfsymbol(mfinit(f), f)}: The library syntax is \fun{GEN}{mfsymbol}{GEN mf, GEN f = NULL, long bitprec}. \subsec{mfsymboleval$(\var{fs},\var{path},\{\var{ga}=\var{id}\})$}\kbdsidx{mfsymboleval}\label{se:mfsymboleval} Evaluation of the modular symbol $fs$ (corresponding to the modular form $f$) output by \kbd{mfsymbol} on the given path \kbd{path}, where \kbd{path} is either a vector $[s_1,s_2]$ or an integral matrix $[a,b;c,d]$ representing the path $[a/c,b/d]$. In both cases $s_1$ or $s_2$ (or $a/c$ or $b/d$) can also be elements of the upper half-plane. To avoid possibly lengthy \kbd{mfsymbol} computations, the program also accepts $fs$ of the form \kbd{[mf,F]}, but in that case $s_1$ and $s_2$ are limited to \kbd{oo} and elements of the upper half-plane. The result is the polynomial equal to $\int_{s_1}^{s_2}(X-\tau)^{k-2}F(\tau)\,d\tau$, the integral being computed along a geodesic joining $s_1$ and $s_2$. If \kbd{ga} in $GL_2^+(\Q)$ is given, replace $F$ by $F|_{k}\gamma$. Note that if the integral diverges, the result will be a rational function. If the field of definition $\Q(f)$ is larger than $\Q(\chi)$ then $f$ can be embedded into $\C$ in $d=[\Q(f):\Q(\chi)]$ ways, in which case a vector of the $d$ results is returned. \bprog ? mf=mfinit([35,2],1);f=mfbasis(mf)[1];fs=mfsymbol(mf,f); ? mfsymboleval(fs,[0,oo]) %1 = 0.31404011074188471664161704390256378537*I ? mfsymboleval(fs,[1,3;2,5]) %2 = -0.1429696291... - 0.2619975641...*I ? mfsymboleval(fs,[I,2*I]) %3 = 0.00088969563028739893631700037491116258378*I ? E2=mfEk(2);E22=mflinear([E2,mfbd(E2,2)],[1,-2]);mf=mfinit(E22); ? E2S = mfsymbol(mf,E22); ? mfsymboleval(E2S,[0,1]) %6 = (-1.00000...*x^2 + 1.00000...*x - 0.50000...)/(x^2 - x) @eprog The rational function which is given in case the integral diverges is easy to interpret. For instance: \bprog ? E4=mfEk(4);mf=mfinit(E4);ES=mfsymbol(mf,E4); ? mfsymboleval(ES,[I,oo]) %2 = 1/3*x^3 - 0.928067...*I*x^2 - 0.833333...*x + 0.234978...*I ? mfsymboleval(ES,[0,I]) %3 = (-0.234978...*I*x^3 - 0.833333...*x^2 + 0.928067...*I*x + 0.333333...)/x @eprog\noindent \kbd{mfsymboleval(ES,[a,oo])} is the limit as $T\to\infty$ of $$\int_a^{iT}(X-\tau)^{k-2}F(\tau)\,d\tau + a(0)(X-iT)^{k-1}/(k-1)\;,$$ where $a(0)$ is the $0$th coefficient of $F$ at infinity. Similarly, \kbd{mfsymboleval(ES,[0,a])} is the limit as $T\to\infty$ of $$\int_{i/T}^a(X-\tau)^{k-2}F(\tau)\,d\tau+b(0)(1+iTX)^{k-1}/(k-1)\;,$$ where $b(0)$ is the $0$th coefficient of $F|_{k} S$ at infinity. The library syntax is \fun{GEN}{mfsymboleval}{GEN fs, GEN path, GEN ga = NULL, long bitprec}. \subsec{mftaylor$(F,n,\{\var{flreal}=0\})$}\kbdsidx{mftaylor}\label{se:mftaylor} $F$ being a form in $M_k(SL_2(\Bbb Z))$, computes the first $n+1$ canonical Taylor expansion of $F$ around $\tau=I$. If \kbd{flreal=0}, computes only an algebraic equivalence class. If \kbd{flreal} is set, compute $p_n$ such that for $\tau$ close enough to $I$ we have $$f(\tau)=(2I/(\tau+I))^k\sum_{n>=0}p_n((\tau-I)/(\tau+I))^n\;.$$ \bprog ? D=mfDelta(); ? mftaylor(D,8) %2 = [1/1728, 0, -1/20736, 0, 1/165888, 0, 1/497664, 0, -11/3981312] @eprog The library syntax is \fun{GEN}{mftaylor}{GEN F, long n, long flreal, long prec}. \subsec{mftobasis$(\var{mf},F,\{\fl=0\})$}\kbdsidx{mftobasis}\label{se:mftobasis} Coefficients of the form $F$ on the basis given by \kbd{mfbasis(mf)}. A $q$-expansion or vector of coefficients can also be given instead of $F$, but in this case an error message may occur if the expansion is too short. An error message is also given if $F$ does not belong to the modular form space. If \kbd{flag} is set, instead of error messages the output is an affine space of solutions if a $q$-expansion or vector of coefficients is given, or the empty column otherwise. \bprog ? mf = mfinit([26,2],0); mfdim(mf) %1 = 2 ? F = mflinear(mf,[a,b]); mftobasis(mf,F) %2 = [a, b]~ @eprog A $q$-expansion or vector of coefficients can also be given instead of $F$. \bprog ? Th = 1 + 2*sum(n=1, 8, q^(n^2), O(q^80)); ? mf = mfinit([4,5,Mod(3,4)]); ? mftobasis(mf, Th^10) %3 = [64/5, 4/5, 32/5]~ @eprog If $F$ does not belong to the corresponding space, the result is incorrect and simply matches the coefficients of $F$ up to some bound, and the function may either return an empty column or an error message. If \kbd{flag} is set, there are no error messages, and the result is an empty column if $F$ is a modular form; if $F$ is supplied via a series or vector of coefficients which does not contain enough information to force a unique (potential) solution, the function returns $[v,K]$ where $v$ is a solution and $K$ is a matrix of maximal rank describing the affine space of potential solutions $v + K\cdot x$. \bprog ? mf = mfinit([4,12],1); ? mftobasis(mf, q-24*q^2+O(q^3), 1) %2 = [[43/64, -63/8, 800, 21/64]~, [1, 0; 24, 0; 2048, 768; -1, 0]] ? mftobasis(mf, [0,1,-24,252], 1) %3 = [[1, 0, 1472, 0]~, [0; 0; 768; 0]] ? mftobasis(mf, [0,1,-24,252,-1472], 1) %4 = [1, 0, 0, 0]~ \\ now uniquely determined ? mftobasis(mf, [0,1,-24,252,-1472,0], 1) %5 = [1, 0, 0, 0]~ \\ wrong result: no such form exists ? mfcoefs(mflinear(mf,%), 5) \\ double check %6 = [0, 1, -24, 252, -1472, 4830] ? mftobasis(mf, [0,1,-24,252,-1472,0]) *** at top-level: mftobasis(mf,[0,1, *** ^-------------------- *** mftobasis: domain error in mftobasis: form does not belong to space ? mftobasis(mf, mfEk(10)) *** at top-level: mftobasis(mf,mfEk( *** ^-------------------- *** mftobasis: domain error in mftobasis: form does not belong to space ? mftobasis(mf, mfEk(10), 1) %7 = []~ @eprog The library syntax is \fun{GEN}{mftobasis}{GEN mf, GEN F, long flag}. \subsec{mftocoset$(N,M,\var{Lcosets})$}\kbdsidx{mftocoset}\label{se:mftocoset} $M$ being a matrix in $SL_2(Z)$ and \kbd{Lcosets} being \kbd{mfcosets(N)}, a list of right cosets of $\Gamma_0(N)$, find the coset to which $M$ belongs. The output is a pair $[\gamma,i]$ such that $M = \gamma \kbd{Lcosets}[i]$, $\gamma\in\Gamma_0(N)$. \bprog ? N = 4; L = mfcosets(N); ? mftocoset(N, [1,1;2,3], L) %2 = [[-1, 1; -4, 3], 5] @eprog The library syntax is \fun{GEN}{mftocoset}{long N, GEN M, GEN Lcosets}. \subsec{mftonew$(\var{mf},F)$}\kbdsidx{mftonew}\label{se:mftonew} \kbd{mf} being being a full or cuspidal space with parameters $[N,k,\chi]$ and $F$ a cusp form in that space, returns a vector of 3-component vectors $[M,d,G]$, where $f(\chi)\mid M\mid N$, $d\mid N/M$, and $G$ is a form in $S_k^{\text{new}}(\Gamma_0(M),\chi)$ such that $F$ is equal to the sum of the $B(d)(G)$ over all these 3-component vectors. \bprog ? mf = mfinit([96,6],1); F = mfbasis(mf)[60]; s = mftonew(mf,F); #s %1 = 1 ? [M,d,G] = s[1]; [M,d] %2 = [48, 2] ? mfcoefs(F,10) %3 = [0, 0, -160, 0, 0, 0, 0, 0, 0, 0, -14400] ? mfcoefs(G,10) %4 = [0, 0, -160, 0, 0, 0, 0, 0, 0, 0, -14400] @eprog The library syntax is \fun{GEN}{mftonew}{GEN mf, GEN F}. \subsec{mftraceform$(\var{NK},\{\var{space}=0\})$}\kbdsidx{mftraceform}\label{se:mftraceform} If $NK=[N,k,CHI,.]$ as in \kbd{mfinit} with $k$ integral, gives the trace form in the corresponding subspace of $S_k(\Gamma_0(N),\chi)$. The supported values for \kbd{space} are 0: the newspace (default), 1: the full cuspidal space. \bprog ? F = mftraceform([23,2]); mfcoefs(F,16) %1 = [0, 2, -1, 0, -1, -2, -5, 2, 0, 4, 6, -6, 5, 6, 4, -10, -3] ? F = mftraceform([23,1,-23]); mfcoefs(F,16) %2 = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0, -1] @eprog The library syntax is \fun{GEN}{mftraceform}{GEN NK, long space}. \subsec{mftwist$(F,D)$}\kbdsidx{mftwist}\label{se:mftwist} $F$ being a generalized modular form, returns the twist of $F$ by the integer $D$, i.e., the form $G$ such that \kbd{mfcoef(G,n)=}$(D/n)$\kbd{mfcoef(F,n)}, where $(D/n)$ is the Kronecker symbol. \bprog ? mf = mfinit([11,2],0); F = mfbasis(mf)[1]; mfcoefs(F, 5) %1 = [0, 1, -2, -1, 2, 1] ? G = mftwist(F,-3); mfcoefs(G, 5) %2 = [0, 1, 2, 0, 2, -1] ? mf2 = mfinit([99,2],0); mftobasis(mf2, G) %3 = [1/3, 0, 1/3, 0]~ @eprog\noindent Note that twisting multiplies the level by $D^2$. In particular it is not an involution: \bprog ? H = mftwist(G,-3); mfcoefs(H, 5) %4 = [0, 1, -2, 0, 2, 1] ? mfparams(G) %5 = [99, 2, 1, y] @eprog The library syntax is \fun{GEN}{mftwist}{GEN F, GEN D}. \section{Modular symbols} Let $\Delta := \text{Div}^0(\P^1(\Q))$ be the abelian group of divisors of degree $0$ on the rational projective line. The standard $\text{GL}(2,\Q)$ action on $\P^1(\Q)$ via homographies naturally extends to $\Delta$. Given \item $G$ a finite index subgroup of $\text{SL}(2,\Z)$, \item a field $F$ and a finite dimensional representation $V/F$ of $\text{GL}(2,\Q)$, \noindent we consider the space of \emph{modular symbols} $M := \Hom_G(\Delta, V)$. This finite dimensional $F$-vector space is a $G$-module, canonically isomorphic to $H^1_c(X(G), V)$, and allows to compute modular forms for $G$. Currently, we only support the groups $\Gamma_0(N)$ ($N > 0$ an integer) and the representations $V_k = \Q[X,Y]_{k-2}$ ($k \geq 2$ an integer) over $\Q$. We represent a space of modular symbols by an \var{ms} structure, created by the function \tet{msinit}. It encodes basic data attached to the space: chosen $\Z[G]$-generators $(g_i)$ for $\Delta$ (and relations among those) and an $F$-basis of $M$. A modular symbol $s$ is thus given either in terms of this fixed basis, or as a collection of values $s(g_i)$ satisfying certain relations. A subspace of $M$ (e.g. the cuspidal or Eisenstein subspaces, the new or old modular symbols, etc.) is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix whose columns form an $F$-basis of the subspace. \subsec{msatkinlehner$(M,Q,\{H\})$}\kbdsidx{msatkinlehner}\label{se:msatkinlehner} Let $M$ be a full modular symbol space of level $N$, as given by \kbd{msinit}, let $Q \mid N$, $(Q,N/Q) = 1$, and let $H$ be a subspace stable under the Atkin-Lehner involution $w_Q$. Return the matrix of $w_Q$ acting on $H$ ($M$ if omitted). \bprog ? M = msinit(36,2); \\ M_2(Gamma_0(36)) ? w = msatkinlehner(M,4); w^2 == 1 %2 = 1 ? #w \\ involution acts on a 13-dimensional space %3 = 13 ? M = msinit(36,2, -1); \\ M_2(Gamma_0(36))^- ? w = msatkinlehner(M,4); w^2 == 1 %5 = 1 ? #w %6 = 4 @eprog The library syntax is \fun{GEN}{msatkinlehner}{GEN M, long Q, GEN H = NULL}. \subsec{mscuspidal$(M, \{\fl=0\})$}\kbdsidx{mscuspidal}\label{se:mscuspidal} $M$ being a full modular symbol space, as given by \kbd{msinit}, return its cuspidal part $S$. If $\fl = 1$, return $[S,E]$ its decomposition into cuspidal and Eisenstein parts. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. \bprog ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ ? [S,E] = mscuspidal(M, 1); ? E[1] \\ 2-dimensional %3 = [0 -10] [0 -15] [0 -3] [1 0] ? S[1] \\ 1-dimensional %4 = [ 3] [30] [ 6] [-8] @eprog The library syntax is \fun{GEN}{mscuspidal}{GEN M, long flag}. \subsec{msdim$(M)$}\kbdsidx{msdim}\label{se:msdim} $M$ being a full modular symbol space or subspace, for instance as given by \kbd{msinit} or \kbd{mscuspidal}, return its dimension as a $\Q$-vector space. \bprog ? M = msinit(11,4); msdim(M) %1 = 6 ? M = msinit(11,4,1); msdim(M) %2 = 4 \\ dimension of the '+' part ? [S,E] = mscuspidal(M,1); ? [msdim(S), msdim(E)] %4 = [2, 2] @eprog\noindent Note that \kbd{mfdim([N,k])} is going to be much faster if you only need the dimension of the space and not really to work with it. This function is only useful to quickly check the dimension of an existing space. The library syntax is \fun{long}{msdim}{GEN M}. \subsec{mseisenstein$(M)$}\kbdsidx{mseisenstein}\label{se:mseisenstein} $M$ being a full modular symbol space, as given by \kbd{msinit}, return its Eisenstein subspace. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. This is the same basis as given by the second component of \kbd{mscuspidal}$(M, 1)$. \bprog ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ ? E = mseisenstein(M); ? E[1] \\ 2-dimensional %3 = [0 -10] [0 -15] [0 -3] [1 0] ? E == mscuspidal(M,1)[2] %4 = 1 @eprog The library syntax is \fun{GEN}{mseisenstein}{GEN M}. \subsec{mseval$(M,s,\{p\})$}\kbdsidx{mseval}\label{se:mseval} Let $\Delta:=\text{Div}^0(\P^1 (\Q))$. Let $M$ be a full modular symbol space, as given by \kbd{msinit}, let $s$ be a modular symbol from $M$, i.e. an element of $\Hom_G(\Delta, V)$, and let $p=[a,b] \in \Delta$ be a path between two elements in $\P^1(\Q)$, return $s(p)\in V$. The path extremities $a$ and $b$ may be given as \typ{INT}, \typ{FRAC} or $\kbd{oo} = (1:0)$; it is also possible to describe the path by a $2 \times 2$ integral matrix whose columns give the two cusps. The symbol $s$ is either \item a \typ{COL} coding a modular symbol in terms of the fixed basis of $\Hom_G(\Delta,V)$ chosen in $M$; if $M$ was initialized with a non-zero \emph{sign} ($+$ or $-$), then either the basis for the full symbol space or the $\pm$-part can be used (the dimension being used to distinguish the two). \item a \typ{MAT} whose columns encode modular symbols as above. This is much faster than evaluating individual symbols on the same path $p$ independently. \item a \typ{VEC} $(v_i)$ of elements of $V$, where the $v_i = s(g_i)$ give the image of the generators $g_i$ of $\Delta$, see \tet{mspathgens}. We assume that $s$ is a proper symbol, i.e.~that the $v_i$ satisfy the \kbd{mspathgens} relations. If $p$ is omitted, convert a single symbol $s$ to the second form: a vector of the $s(g_i)$. A \typ{MAT} is converted to a vector of such. \bprog ? M = msinit(2,8,1); \\ M_8(Gamma_0(2))^+ ? g = mspathgens(M)[1] %2 = [[+oo, 0], [0, 1]] ? N = msnew(M)[1]; #N \\ Q-basis of new subspace, dimension 1 %3 = 1 ? s = N[,1] \\ t_COL representation %4 = [-3, 6, -8]~ ? S = mseval(M, s) \\ t_VEC representation %5 = [64*x^6-272*x^4+136*x^2-8, 384*x^5+960*x^4+192*x^3-672*x^2-432*x-72] ? mseval(M,s, g[1]) %6 = 64*x^6 - 272*x^4 + 136*x^2 - 8 ? mseval(M,S, g[1]) %7 = 64*x^6 - 272*x^4 + 136*x^2 - 8 @eprog\noindent Note that the symbol should have values in $V = \Q[x,y]_{k-2}$, we return the de-homogenized values corresponding to $y = 1$ instead. The library syntax is \fun{GEN}{mseval}{GEN M, GEN s, GEN p = NULL}. \subsec{msfromcusp$(M, c)$}\kbdsidx{msfromcusp}\label{se:msfromcusp} Returns the modular symbol attached to the cusp $c$, where $M$ is a modular symbol space of level $N$, attached to $G = \Gamma_0(N)$. The cusp $c$ in $\P^1(\Q)/G$ is given either as \kbd{oo} ($=(1:0)$) or as a rational number $a/b$ ($=(a:b)$). The attached symbol maps the path $[b] - [a] \in \text{Div}^0 (\P^1(\Q))$ to $E_c(b) - E_c(a)$, where $E_c(r)$ is $0$ when $r \neq c$ and $X^{k-2} \mid \gamma_r$ otherwise, where $\gamma_r \cdot r = (1:0)$. These symbols span the Eisenstein subspace of $M$. \bprog ? M = msinit(2,8); \\ M_8(Gamma_0(2)) ? E = mseisenstein(M); ? E[1] \\ two-dimensional %3 = [0 -10] [0 -15] [0 -3] [1 0] ? s = msfromcusp(M,oo) %4 = [0, 0, 0, 1]~ ? mseval(M, s) %5 = [1, 0] ? s = msfromcusp(M,1) %6 = [-5/16, -15/32, -3/32, 0]~ ? mseval(M,s) %7 = [-x^6, -6*x^5 - 15*x^4 - 20*x^3 - 15*x^2 - 6*x - 1] @eprog In case $M$ was initialized with a non-zero \emph{sign}, the symbol is given in terms of the fixed basis of the whole symbol space, not the $+$ or $-$ part (to which it need not belong). \bprog ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ ? E = mseisenstein(M); ? E[1] \\ still two-dimensional, in a smaller space %3 = [ 0 -10] [ 0 3] [-1 0] ? s = msfromcusp(M,oo) \\ in terms of the basis for M_8(Gamma_0(2)) ! %4 = [0, 0, 0, 1]~ ? mseval(M, s) \\ same symbol as before %5 = [1, 0] @eprog The library syntax is \fun{GEN}{msfromcusp}{GEN M, GEN c}. \subsec{msfromell$(E, \{\var{sign}=0\})$}\kbdsidx{msfromell}\label{se:msfromell} Let $E/\Q$ be an elliptic curve of conductor $N$. For $\varepsilon = \pm1$, we define the (cuspidal, new) modular symbol $x^\varepsilon$ in $H^1_c(X_0(N),\Q)^\varepsilon$ attached to $E$. For all primes $p$ not dividing $N$ we have $T_p(x^\varepsilon) = a_p x^\varepsilon$, where $a_p = p+1-\#E(\F_p)$. Let $\Omega^+ = \kbd{E.omega[1]}$ be the real period of $E$ (integration of the N\'eron differential $dx/(2y+a_1x+a3)$ on the connected component of $E(\R)$, i.e.~the generator of $H_1(E,\Z)^+$) normalized by $\Omega^+>0$. Let $i\Omega^-$ the integral on a generator of $H_1(E,\Z)^-$ with $\Omega^- \in \R_{>0}$. If $c_\infty$ is the number of connected components of $E(\R)$, $\Omega^-$ is equal to $(-2/c_\infty) \times \kbd{imag(E.omega[2])}$. The complex modular symbol is defined by $$F: \delta \to 2i\pi \int_{\delta} f(z) dz$$ The modular symbols $x^\varepsilon$ are normalized so that $ F = x^+ \Omega^+ + x^- i\Omega^-$. In particular, we have $$ x^+([0]-[\infty]) = L(E,1) / \Omega^+,$$ which defines $x^{\pm}$ unless $L(E,1)=0$. Furthermore, for all fundamental discriminants $D$ such that $\varepsilon \cdot D > 0$, we also have $$\sum_{0\leq a<|D|} (D|a) x^\varepsilon([a/|D|]-[\infty]) = L(E,(D|.),1) / \Omega^{\varepsilon},$$ where $(D|.)$ is the Kronecker symbol. The period $\Omega^-$ is also $2/c_\infty \times$ the real period of the twist $E^{(-4)} = \kbd{elltwist(E,-4)}$. This function returns the pair $[M, x]$, where $M$ is \kbd{msinit}$(N,2)$ and $x$ is $x^{\var{sign}}$ as above when $\var{sign}= \pm1$, and $x = [x^+,x^-, L_E]$ when \var{sign} is $0$, where $L_E$ is a matrix giving the canonical $\Z$-lattice attached to $E$ in the sense of \kbd{mslattice} applied to $\Q x^+ + \Q x^-$. Explicitly, it is generated by $(x^{+},x^{-})$ when $E(\R)$ has two connected components and by $(x^{+} - x^{-},2x^-)$ otherwise. The modular symbols $x^\pm$ are given as a \typ{COL} (in terms of the fixed basis of $\Hom_G(\Delta,\Q)$ chosen in $M$). \bprog ? E=ellinit([0,-1,1,-10,-20]); \\ X_0(11) ? [M,xp]= msfromell(E,1); ? xp %3 = [1/5, -1/2, -1/2]~ ? [M,x]= msfromell(E); ? x \\ x^+, x^- and L_E %5 = [[1/5, -1/2, -1/2]~, [0, 1/2, -1/2]~, [1/5, 0; -1, 1; 0, -1]] ? p = 23; (mshecke(M,p) - ellap(E,p))*x[1] %6 = [0, 0, 0]~ \\ true at all primes, including p = 11; same for x[2] ? (mshecke(M,p) - ellap(E,p))*x[3] == 0 %7 = 1 @eprog \noindent Instead of a single curve $E$, one may use instead a vector of \emph{isogenous} curves. The function then returns $M$ and the vector of attached modular symbols. The library syntax is \fun{GEN}{msfromell}{GEN E, long sign}. \subsec{msfromhecke$(M, v, \{H\})$}\kbdsidx{msfromhecke}\label{se:msfromhecke} Given a msinit $M$ and a vector $v$ of pairs $[p, P]$ (where $p$ is prime and $P$ is a polynomial with integer coefficients), return a basis of all modular symbols such that $P(T_p)(s) = 0$. If $H$ is present, it must be a Hecke-stable subspace and we restrict to $s \in H$. When $T_p$ has a rational eigenvalue and $P(x) = x-a_p$ has degree $1$, we also accept the integer $a_p$ instead of $P$. \bprog ? E = ellinit([0,-1,1,-10,-20]) \\11a1 ? ellap(E,2) %2 = -2 ? ellap(E,3) %3 = -1 ? M = msinit(11,2); ? S = msfromhecke(M, [[2,-2],[3,-1]]) %5 = [ 1 1] [-5 0] [ 0 -5] ? mshecke(M, 2, S) %6 = [-2 0] [ 0 -2] ? M = msinit(23,4); ? S = msfromhecke(M, [[5, x^4-14*x^3-244*x^2+4832*x-19904]]); ? factor( charpoly(mshecke(M,5,S)) ) %9 = [x^4 - 14*x^3 - 244*x^2 + 4832*x - 19904 2] @eprog The library syntax is \fun{GEN}{msfromhecke}{GEN M, GEN v, GEN H = NULL}. \subsec{msgetlevel$(M)$}\kbdsidx{msgetlevel}\label{se:msgetlevel} $M$ being a full modular symbol space, as given by \kbd{msinit}, return its level $N$. The library syntax is \fun{long}{msgetlevel}{GEN M}. \subsec{msgetsign$(M)$}\kbdsidx{msgetsign}\label{se:msgetsign} $M$ being a full modular symbol space, as given by \kbd{msinit}, return its sign: $\pm1$ or 0 (unset). \bprog ? M = msinit(11,4, 1); ? msgetsign(M) %2 = 1 ? M = msinit(11,4); ? msgetsign(M) %4 = 0 @eprog The library syntax is \fun{long}{msgetsign}{GEN M}. \subsec{msgetweight$(M)$}\kbdsidx{msgetweight}\label{se:msgetweight} $M$ being a full modular symbol space, as given by \kbd{msinit}, return its weight $k$. \bprog ? M = msinit(11,4); ? msgetweight(M) %2 = 4 @eprog The library syntax is \fun{long}{msgetweight}{GEN M}. \subsec{mshecke$(M,p,\{H\})$}\kbdsidx{mshecke}\label{se:mshecke} $M$ being a full modular symbol space, as given by \kbd{msinit}, $p$ being a prime number, and $H$ being a Hecke-stable subspace ($M$ if omitted) return the matrix of $T_p$ acting on $H$ ($U_p$ if $p$ divides $N$). Result is undefined if $H$ is not stable by $T_p$ (resp.~$U_p$). \bprog ? M = msinit(11,2); \\ M_2(Gamma_0(11)) ? T2 = mshecke(M,2) %2 = [3 0 0] [1 -2 0] [1 0 -2] ? M = msinit(11,2, 1); \\ M_2(Gamma_0(11))^+ ? T2 = mshecke(M,2) %4 = [ 3 0] [-1 -2] ? N = msnew(M)[1] \\ Q-basis of new cuspidal subspace %5 = [-2] [-5] ? p = 1009; mshecke(M, p, N) \\ action of T_1009 on N %6 = [-10] ? ellap(ellinit("11a1"), p) %7 = -10 @eprog The library syntax is \fun{GEN}{mshecke}{GEN M, long p, GEN H = NULL}. \subsec{msinit$(G, V, \{\var{sign}=0\})$}\kbdsidx{msinit}\label{se:msinit} Given $G$ a finite index subgroup of $\text{SL}(2,\Z)$ and a finite dimensional representation $V$ of $\text{GL}(2,\Q)$, creates a space of modular symbols, the $G$-module $\Hom_G(\text{Div}^0(\P^1 (\Q)), V)$. This is canonically isomorphic to $H^1_c(X(G), V)$, and allows to compute modular forms for $G$. If \emph{sign} is present and non-zero, it must be $\pm1$ and we consider the subspace defined by $\text{Ker} (\sigma - \var{sign})$, where $\sigma$ is induced by \kbd{[-1,0;0,1]}. Currently the only supported groups are the $\Gamma_0(N)$, coded by the integer $N > 0$. The only supported representation is $V_k = \Q[X,Y]_{k-2}$, coded by the integer $k \geq 2$. \bprog ? M = msinit(11,2); msdim(M) \\ Gamma0(11), weight 2 %1 = 3 ? mshecke(M,2) \\ T_2 acting on M %2 = [3 1 1] [0 -2 0] [0 0 -2] ? msstar(M) \\ * involution %3 = [1 0 0] [0 0 1] [0 1 0] ? Mp = msinit(11,2, 1); msdim(Mp) \\ + part %4 = 2 ? mshecke(Mp,2) \\ T_2 action on M^+ %5 = [3 2] [0 -2] ? msstar(Mp) %6 = [1 0] [0 1] @eprog The library syntax is \fun{GEN}{msinit}{GEN G, GEN V, long sign}. \subsec{msissymbol$(M,s)$}\kbdsidx{msissymbol}\label{se:msissymbol} $M$ being a full modular symbol space, as given by \kbd{msinit}, check whether $s$ is a modular symbol attached to $M$. If $A$ is a matrix, check whether its columns represent modular symbols and return a $0-1$ vector. \bprog ? M = msinit(7,8, 1); \\ M_8(Gamma_0(7))^+ ? A = msnew(M)[1]; ? s = A[,1]; ? msissymbol(M, s) %4 = 1 ? msissymbol(M, A) %5 = [1, 1, 1] ? S = mseval(M,s); ? msissymbol(M, S) %7 = 1 ? [g,R] = mspathgens(M); g %8 = [[+oo, 0], [0, 1/2], [1/2, 1]] ? #R \\ 3 relations among the generators g_i %9 = 3 ? T = S; T[3]++; \\ randomly perturb S(g_3) ? msissymbol(M, T) %11 = 0 \\ no longer satisfies the relations @eprog The library syntax is \fun{GEN}{msissymbol}{GEN M, GEN s}. \subsec{mslattice$(M, \{H\})$}\kbdsidx{mslattice}\label{se:mslattice} Let $\Delta:=\text{Div}^0(\P^1(\Q))$ and $V_k = \Q[x,y]_{k-2}$. Let $M$ be a full modular symbol space, as given by \kbd{msinit} and let $H$ be a subspace, e.g. as given by \kbd{mscuspidal}. This function returns a canonical $\Z$ structure on $H$ defined as follows. Consider the map $c: M=\Hom_{\Gamma_0(N)}(\Delta, V_k) \to H^1(\Gamma_0(N), V_k)$ given by $\phi \mapsto \var{class}(\gamma \to \phi(\{0, \gamma^{-1} 0\}))$. Let $L_k=\Z[x,y]_{k-2}$ be the natural $\Z$-structure of $V_k$. The result of \kbd{mslattice} is a $\Z$-basis of the inverse image by $c$ of $H^1(\Gamma_0(N), L_k)$ in the space of modular symbols generated by $H$. For user convenience, $H$ can be defined by a matrix representing the $\Q$-basis of $H$ (in terms of the canonical $\Q$-basis of $M$ fixed by \kbd{msinit} and used to represent modular symbols). If omitted, $H$ is the cuspidal part of $M$ as given by \kbd{mscuspidal}. The Eisenstein part $\Hom_{\Gamma_0(N)}(\text{Div}(\P^1(\Q)), V_k)$ is in the kernel of $c$, so the result has no meaning for the Eisenstein part \kbd{H}. \bprog ? M=msinit(11,2); ? [S,E] = mscuspidal(M,1); S[1] \\ a primitive Q-basis of S %2 = [ 1 1] [-5 0] [ 0 -5] ? mslattice(M,S) %3 = [-1/5 -1/5] [ 1 0] [ 0 1] ? mslattice(M,E) %4 = [1] [0] [0] ? M=msinit(5,4); ? S=mscuspidal(M); S[1] %6 = [ 7 20] [ 3 3] [-10 -23] [-30 -30] ? mslattice(M,S) %7 = [-1/10 -11/130] [ 0 -1/130] [ 1/10 6/65] [ 0 1/13] @eprog The library syntax is \fun{GEN}{mslattice}{GEN M, GEN H = NULL}. \subsec{msnew$(M)$}\kbdsidx{msnew}\label{se:msnew} $M$ being a full modular symbol space, as given by \kbd{msinit}, return the \emph{new} part of its cuspidal subspace. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. \bprog ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ ? N = msnew(M); ? #N[1] \\ 6-dimensional %3 = 6 @eprog The library syntax is \fun{GEN}{msnew}{GEN M}. \subsec{msomseval$(\var{Mp}, \var{PHI}, \var{path})$}\kbdsidx{msomseval}\label{se:msomseval} Return the vectors of moments of the $p$-adic distribution attached to the path \kbd{path} by the overconvergent modular symbol \kbd{PHI}. \bprog ? M = msinit(3,6,1); ? Mp= mspadicinit(M,5,10); ? phi = [5,-3,-1]~; ? msissymbol(M,phi) %4 = 1 ? PHI = mstooms(Mp,phi); ? ME = msomseval(Mp,PHI,[oo, 0]); @eprog The library syntax is \fun{GEN}{msomseval}{GEN Mp, GEN PHI, GEN path}. \subsec{mspadicL$(\var{mu}, \{s = 0\}, \{r = 0\})$}\kbdsidx{mspadicL}\label{se:mspadicL} Returns the value (or $r$-th derivative) on a character $\chi^s$ of $\Z_p^*$ of the $p$-adic $L$-function attached to \kbd{mu}. Let $\Phi$ be the $p$-adic distribution-valued overconvergent symbol attached to a modular symbol $\phi$ for $\Gamma_0(N)$ (eigenvector for $T_N(p)$ for the eigenvalue $a_p$). Then $L_p(\Phi,\chi^s)=L_p(\mu,s)$ is the $p$-adic $L$ function defined by $$L_p(\Phi,\chi^s)= \int_{\Z_p^*} \chi^s(z) d\mu(z)$$ where $\mu$ is the distribution on $\Z_p^*$ defined by the restriction of $\Phi([\infty]-[0])$ to $\Z_p^*$. The $r$-th derivative is taken in direction $\langle \chi\rangle$: $$L_p^{(r)}(\Phi,\chi^s)= \int_{\Z_p^*} \chi^s(z) (\log z)^r d\mu(z).$$ In the argument list, \item \kbd{mu} is as returned by \tet{mspadicmoments} (distributions attached to $\Phi$ by restriction to discs $a + p^\nu\Z_p$, $(a,p)=1$). \item $s=[s_1,s_2]$ with $s_1 \in \Z \subset \Z_p$ and $s_2 \bmod p-1$ or $s_2 \bmod 2$ for $p=2$, encoding the $p$-adic character $\chi^s := \langle \chi \rangle^{s_1} \tau^{s_2}$; here $\chi$ is the cyclotomic character from $\text{Gal}(\Q_p(\mu_{p^\infty})/\Q_p)$ to $\Z_p^*$, and $\tau$ is the Teichm\"uller character (for $p>2$ and the character of order 2 on $(\Z/4\Z)^*$ if $p=2$); for convenience, the character $[s,s]$ can also be represented by the integer $s$. When $a_p$ is a $p$-adic unit, $L_p$ takes its values in $\Q_p$. When $a_p$ is not a unit, it takes its values in the two-dimensional $\Q_p$-vector space $D_{cris}(M(\phi))$ where $M(\phi)$ is the ``motive'' attached to $\phi$, and we return the two $p$-adic components with respect to some fixed $\Q_p$-basis. \bprog ? M = msinit(3,6,1); phi=[5, -3, -1]~; ? msissymbol(M,phi) %2 = 1 ? Mp = mspadicinit(M, 5, 4); ? mu = mspadicmoments(Mp, phi); \\ no twist \\ End of initializations ? mspadicL(mu,0) \\ L_p(chi^0) %5 = 5 + 2*5^2 + 2*5^3 + 2*5^4 + ... ? mspadicL(mu,1) \\ L_p(chi), zero for parity reasons %6 = [O(5^13)]~ ? mspadicL(mu,2) \\ L_p(chi^2) %7 = 3 + 4*5 + 4*5^2 + 3*5^5 + ... ? mspadicL(mu,[0,2]) \\ L_p(tau^2) %8 = 3 + 5 + 2*5^2 + 2*5^3 + ... ? mspadicL(mu, [1,0]) \\ L_p() %9 = 3*5 + 2*5^2 + 5^3 + 2*5^7 + 5^8 + 5^10 + 2*5^11 + O(5^13) ? mspadicL(mu,0,1) \\ L_p'(chi^0) %10 = 2*5 + 4*5^2 + 3*5^3 + ... ? mspadicL(mu, 2, 1) \\ L_p'(chi^2) %11 = 4*5 + 3*5^2 + 5^3 + 5^4 + ... @eprog Now several quadratic twists: \tet{mstooms} is indicated. \bprog ? PHI = mstooms(Mp,phi); ? mu = mspadicmoments(Mp, PHI, 12); \\ twist by 12 ? mspadicL(mu) %14 = 5 + 5^2 + 5^3 + 2*5^4 + ... ? mu = mspadicmoments(Mp, PHI, 8); \\ twist by 8 ? mspadicL(mu) %16 = 2 + 3*5 + 3*5^2 + 2*5^4 + ... ? mu = mspadicmoments(Mp, PHI, -3); \\ twist by -3 < 0 ? mspadicL(mu) %18 = O(5^13) \\ always 0, phi is in the + part and D < 0 @eprog One can locate interesting symbols of level $N$ and weight $k$ with \kbd{msnew} and \kbd{mssplit}. Note that instead of a symbol, one can input a 1-dimensional Hecke-subspace from \kbd{mssplit}: the function will automatically use the underlying basis vector. \bprog ? M=msinit(5,4,1); \\ M_4(Gamma_0(5))^+ ? L = mssplit(M, msnew(M)); \\ list of irreducible Hecke-subspaces ? phi = L[1]; \\ one Galois orbit of newforms ? #phi[1] \\... this one is rational %4 = 1 ? Mp = mspadicinit(M, 3, 4); ? mu = mspadicmoments(Mp, phi); ? mspadicL(mu) %7 = 1 + 3 + 3^3 + 3^4 + 2*3^5 + 3^6 + O(3^9) ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ ? Mp = mspadicinit(M, 3, 4); ? L = mssplit(M, msnew(M)); ? phi = L[1]; #phi[1] \\ ... this one is two-dimensional %11 = 2 ? mu = mspadicmoments(Mp, phi); *** at top-level: mu=mspadicmoments(Mp,ph *** ^-------------------- *** mspadicmoments: incorrect type in mstooms [dim_Q (eigenspace) > 1] @eprog The library syntax is \fun{GEN}{mspadicL}{GEN mu, GEN s = NULL, long r}. \subsec{mspadicinit$(M, p, n, \{\fl\})$}\kbdsidx{mspadicinit}\label{se:mspadicinit} $M$ being a full modular symbol space, as given by \kbd{msinit}, and $p$ a prime, initialize technical data needed to compute with overconvergent modular symbols, modulo $p^n$. If $\fl$ is unset, allow all symbols; else initialize only for a restricted range of symbols depending on $\fl$: if $\fl = 0$ restrict to ordinary symbols, else restrict to symbols $\phi$ such that $T_p(\phi) = a_p \phi$, with $v_p(a_p) \geq \fl$, which is faster as $\fl$ increases. (The fastest initialization is obtained for $\fl = 0$ where we only allow ordinary symbols.) For supersingular eigensymbols, such that $p\mid a_p$, we must further assume that $p$ does not divide the level. \bprog ? E = ellinit("11a1"); ? [M,phi] = msfromell(E,1); ? ellap(E,3) %3 = -1 ? Mp = mspadicinit(M, 3, 10, 0); \\ commit to ordinary symbols ? PHI = mstooms(Mp,phi); @eprog If we restrict the range of allowed symbols with \fl (for faster initialization), exceptions will occur if $v_p(a_p)$ violates this bound: \bprog ? E = ellinit("15a1"); ? [M,phi] = msfromell(E,1); ? ellap(E,7) %3 = 0 ? Mp = mspadicinit(M,7,5,0); \\ restrict to ordinary symbols ? PHI = mstooms(Mp,phi) *** at top-level: PHI=mstooms(Mp,phi) *** ^--------------- *** mstooms: incorrect type in mstooms [v_p(ap) > mspadicinit flag] (t_VEC). ? Mp = mspadicinit(M,7,5); \\ no restriction ? PHI = mstooms(Mp,phi); @eprog\noindent This function uses $O(N^2(n+k)^2p)$ memory, where $N$ is the level of $M$. The library syntax is \fun{GEN}{mspadicinit}{GEN M, long p, long n, long flag}. \subsec{mspadicmoments$(\var{Mp}, \var{PHI}, \{D = 1\})$}\kbdsidx{mspadicmoments}\label{se:mspadicmoments} Given \kbd{Mp} from \kbd{mspadicinit}, an overconvergent eigensymbol \kbd{PHI} from \kbd{mstooms} and a fundamental discriminant $D$ coprime to $p$, let $\kbd{PHI}^D$ denote the twisted symbol. This function computes the distribution $\mu = \kbd{PHI}^D([0] - \infty]) \mid \Z_p^*$ restricted to $\Z_p^*$. More precisely, it returns the moments of the $p-1$ distributions $\kbd{PHI}^D([0]-[\infty]) \mid (a + p\Z_p)$, $0 < a < p$. We also allow \kbd{PHI} to be given as a classical symbol, which is then lifted to an overconvergent symbol by \kbd{mstooms}; but this is wasteful if more than one twist is later needed. The returned data $\mu$ ($p$-adic distributions attached to \kbd{PHI}) can then be used in \tet{mspadicL} or \tet{mspadicseries}. This precomputation allows to quickly compute derivatives of different orders or values at different characters. \bprog ? M = msinit(3,6, 1); ? phi = [5,-3,-1]~; ? msissymbol(M, phi) %3 = 1 ? p = 5; mshecke(M,p) * phi \\ eigenvector of T_5, a_5 = 6 %4 = [30, -18, -6]~ ? Mp = mspadicinit(M, p, 10, 0); \\ restrict to ordinary symbols, mod p^10 ? PHI = mstooms(Mp, phi); ? mu = mspadicmoments(Mp, PHI); ? mspadicL(mu) %8 = 5 + 2*5^2 + 2*5^3 + ... ? mu = mspadicmoments(Mp, PHI, 12); \\ twist by 12 ? mspadicL(mu) %10 = 5 + 5^2 + 5^3 + 2*5^4 + ... @eprog The library syntax is \fun{GEN}{mspadicmoments}{GEN Mp, GEN PHI, long D}. \subsec{mspadicseries$(\var{mu}, \{i=0\})$}\kbdsidx{mspadicseries}\label{se:mspadicseries} Let $\Phi$ be the $p$-adic distribution-valued overconvergent symbol attached to a modular symbol $\phi$ for $\Gamma_0(N)$ (eigenvector for $T_N(p)$ for the eigenvalue $a_p$). If $\mu$ is the distribution on $\Z_p^*$ defined by the restriction of $\Phi([\infty]-[0])$ to $\Z_p^*$, let $$\hat{L}_p(\mu,\tau^{i})(x) = \int_{\Z_p^*} \tau^i(t) (1+x)^{\log_p(t)/\log_p(u)}d\mu(t)$$ Here, $\tau$ is the Teichm\"uller character and $u$ is a specific multiplicative generator of $1+2p\Z_p$. (Namely $1+p$ if $p>2$ or $5$ if $p=2$.) To explain the formula, let $G_\infty := \text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$, let $\chi:G_\infty\to \Z_p^*$ be the cyclotomic character (isomorphism) and $\gamma$ the element of $G_\infty$ such that $\chi(\gamma)=u$; then $\chi(\gamma)^{\log_p(t)/\log_p(u)}= \langle t \rangle$. The $p$-padic precision of individual terms is maximal given the precision of the overconvergent symbol $\mu$. \bprog ? [M,phi] = msfromell(ellinit("17a1"),1); ? Mp = mspadicinit(M, 5,7); ? mu = mspadicmoments(Mp, phi,1); \\ overconvergent symbol ? mspadicseries(mu) %4 = (4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + 4*5^6 + 3*5^7 + O(5^9)) \ + (3 + 3*5 + 5^2 + 5^3 + 2*5^4 + 5^6 + O(5^7))*x \ + (2 + 3*5 + 5^2 + 4*5^3 + 2*5^4 + O(5^5))*x^2 \ + (3 + 4*5 + 4*5^2 + O(5^3))*x^3 \ + (3 + O(5))*x^4 + O(x^5) @eprog\noindent An example with non-zero Teichm\"uller: \bprog ? [M,phi] = msfromell(ellinit("11a1"),1); ? Mp = mspadicinit(M, 3,10); ? mu = mspadicmoments(Mp, phi,1); ? mspadicseries(mu, 2) %4 = (2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 3^6 + 3^7 + 3^10 + 3^11 + O(3^12)) \ + (1 + 3 + 2*3^2 + 3^3 + 3^5 + 2*3^6 + 2*3^8 + O(3^9))*x \ + (1 + 2*3 + 3^4 + 2*3^5 + O(3^6))*x^2 \ + (3 + O(3^2))*x^3 + O(x^4) @eprog\noindent Supersingular example (not checked) \bprog ? E = ellinit("17a1"); ellap(E,3) %1 = 0 ? [M,phi] = msfromell(E,1); ? Mp = mspadicinit(M, 3,7); ? mu = mspadicmoments(Mp, phi,1); ? mspadicseries(mu) %5 = [(2*3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + 3^5 + 3^6 + O(3^7)) \ + (2 + 3^3 + O(3^5))*x \ + (1 + 2*3 + O(3^2))*x^2 + O(x^3),\ (3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + 3^5 + 3^6 + O(3^7)) \ + (1 + 2*3 + 2*3^2 + 3^3 + 2*3^4 + O(3^5))*x \ + (3^-2 + 3^-1 + O(3^2))*x^2 + O(3^-2)*x^3 + O(x^4)] @eprog\noindent Example with a twist: \bprog ? E = ellinit("11a1"); ? [M,phi] = msfromell(E,1); ? Mp = mspadicinit(M, 3,10); ? mu = mspadicmoments(Mp, phi,5); \\ twist by 5 ? L = mspadicseries(mu) %5 = (2*3^2 + 2*3^4 + 3^5 + 3^6 + 2*3^7 + 2*3^10 + O(3^12)) \ + (2*3^2 + 2*3^6 + 3^7 + 3^8 + O(3^9))*x \ + (3^3 + O(3^6))*x^2 + O(3^2)*x^3 + O(x^4) ? mspadicL(mu) %6 = [2*3^2 + 2*3^4 + 3^5 + 3^6 + 2*3^7 + 2*3^10 + O(3^12)]~ ? ellpadicL(E,3,10,,5) %7 = 2 + 2*3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + 2*3^7 + O(3^10) ? mspadicseries(mu,1) \\ must be 0 %8 = O(3^12) + O(3^9)*x + O(3^6)*x^2 + O(3^2)*x^3 + O(x^4) @eprog The library syntax is \fun{GEN}{mspadicseries}{GEN mu, long i}. \subsec{mspathgens$(M)$}\kbdsidx{mspathgens}\label{se:mspathgens} Let $\Delta:=\text{Div}^0(\P^1(\Q))$. Let $M$ being a full modular symbol space, as given by \kbd{msinit}, return a set of $\Z[G]$-generators for $\Delta$. The output is $[g,R]$, where $g$ is a minimal system of generators and $R$ the vector of $\Z[G]$-relations between the given generators. A relation is coded by a vector of pairs $[a_i,i]$ with $a_i\in \Z[G]$ and $i$ the index of a generator, so that $\sum_i a_i g[i] = 0$. An element $[v]-[u]$ in $\Delta$ is coded by the ``path'' $[u,v]$, where \kbd{oo} denotes the point at infinity $(1:0)$ on the projective line. An element of $\Z[G]$ is either an integer $n$ ($= n [\text{id}_2]$) or a ``factorization matrix'': the first column contains distinct elements $g_i$ of $G$ and the second integers $n_i$ and the matrix codes $\sum n_i [g_i]$: \bprog ? M = msinit(11,8); \\ M_8(Gamma_0(11)) ? [g,R] = mspathgens(M); ? g %3 = [[+oo, 0], [0, 1/3], [1/3, 1/2]] \\ 3 paths ? #R \\ a single relation %4 = 1 ? r = R[1]; #r \\ ...involving all 3 generators %5 = 3 ? r[1] %6 = [[1, 1; [1, 1; 0, 1], -1], 1] ? r[2] %7 = [[1, 1; [7, -2; 11, -3], -1], 2] ? r[3] %8 = [[1, 1; [8, -3; 11, -4], -1], 3] @eprog\noindent The given relation is of the form $\sum_i (1-\gamma_i) g_i = 0$, with $\gamma_i\in \Gamma_0(11)$. There will always be a single relation involving all generators (corresponding to a round trip along all cusps), then relations involving a single generator (corresponding to $2$ and $3$-torsion elements in the group: \bprog ? M = msinit(2,8); \\ M_8(Gamma_0(2)) ? [g,R] = mspathgens(M); ? g %3 = [[+oo, 0], [0, 1]] @eprog\noindent Note that the output depends only on the group $G$, not on the representation $V$. The library syntax is \fun{GEN}{mspathgens}{GEN M}. \subsec{mspathlog$(M,p)$}\kbdsidx{mspathlog}\label{se:mspathlog} Let $\Delta:=\text{Div}^0(\P^1(\Q))$. Let $M$ being a full modular symbol space, as given by \kbd{msinit}, encoding fixed $\Z[G]$-generators $(g_i)$ of $\Delta$ (see \tet{mspathgens}). A path $p=[a,b]$ between two elements in $\P^1(\Q)$ corresponds to $[b]-[a]\in \Delta$. The path extremities $a$ and $b$ may be given as \typ{INT}, \typ{FRAC} or $\kbd{oo} = (1:0)$. Finally, we also allow to input a path as a $2\times 2$ integer matrix, whose first and second column give $a$ and $b$ respectively, with the convention $[x,y]\til = (x:y)$ in $\P^1(\Q)$. Returns $(p_i)$ in $\Z[G]$ such that $p = \sum_i p_i g_i$. \bprog ? M = msinit(2,8); \\ M_8(Gamma_0(2)) ? [g,R] = mspathgens(M); ? g %3 = [[+oo, 0], [0, 1]] ? p = mspathlog(M, [1/2,2/3]); ? p[1] %5 = [[1, 0; 2, 1] 1] ? p[2] %6 = [[1, 0; 0, 1] 1] [[3, -1; 4, -1] 1] ? mspathlog(M, [1,2;2,3]) == p \\ give path via a 2x2 matrix %7 = 1 @eprog\noindent Note that the output depends only on the group $G$, not on the representation $V$. The library syntax is \fun{GEN}{mspathlog}{GEN M, GEN p}. \subsec{mspetersson$(M, \{F\}, \{G=F\})$}\kbdsidx{mspetersson}\label{se:mspetersson} $M$ being a full modular symbol space for $\Gamma = \Gamma_0(N)$, as given by \kbd{msinit}, calculate the intersection product $\{F, G\}$ of modular symbols $F$ and $G$ on $M=\Hom_{\Gamma}(\Delta, V_k)$ extended to an hermitian bilinear form on $M \otimes \C$ whose radical is the Eisenstein subspace of $M$. Suppose that $f_1$ and $f_2$ are two parabolic forms. Let $F_1$ and $F_2$ be the attached modular symbols $$ F_i(\delta)= \int_{\delta} f_i(z) \cdot (z X + Y)^{k-2} \,dz$$ and let $F^{\R}_1$, $F^{\R}_2$ be the attached real modular symbols $$ F^{\R}_i(\delta)= \int_{\delta} \Re\big(f_i(z) \cdot (z X + Y)^{k-2} \,dz\big) $$ Then we have $$ \{ F^{\R}_1, F^{\R}_2 \} = -2 (2i)^{k-2} \cdot \Im(_{\var{Petersson}}) $$ and $$\{ F_1, \bar{F_2} \} = (2i)^{k-2} _{\var{Petersson}}$$ In weight 2, the intersection product $\{F, G\}$ has integer values on the $\Z$-structure on $M$ given by \kbd{mslattice} and defines a Riemann form on $H^1_{par}(\Gamma,\R)$. For user convenience, we allow $F$ and $G$ to be matrices and return the attached Gram matrix. If $F$ is omitted: treat it as the full modular space attached to $M$; if $G$ is omitted, take it equal to $F$. \bprog ? M = msinit(37,2); ? C = mscuspidal(M)[1]; ? mspetersson(M, C) %3 = [ 0 -17 -8 -17] [17 0 -8 -25] [ 8 8 0 -17] [17 25 17 0] ? mspetersson(M, mslattice(M,C)) %4 = [0 -1 0 -1] [1 0 0 -1] [0 0 0 -1] [1 1 1 0] ? E = ellinit("33a1"); ? [M,xpm] = msfromell(E); [xp,xm,L] = xpm; ? mspetersson(M, mslattice(M,L)) %7 = [0 -3] [3 0] ? ellmoddegree(E) %8 = [3, -126] @eprog \noindent The coefficient $3$ in the matrix is the degree of the modular parametrization. The library syntax is \fun{GEN}{mspetersson}{GEN M, GEN F = NULL, GEN G = NULL}. \subsec{mspolygon$(M, \{\fl = 0\})$}\kbdsidx{mspolygon}\label{se:mspolygon} Given an integer $N > 1$, return an hyperbolic polygon (Farey symbol) attached to the group $\Gamma_0(N)$. More precisely, \item its vertices are an ordered list in $\P^{1}(\Q)$, forming a system of representatives of cusps, \item its edges are hyperbolic arcs joining two consecutive vertices, \item given a path $(a,b)$ between two elements of $\P^{1}(\Q)$, let $\overline{(a,b)} = (b,a)$ be the opposite path. There is an involution $e \to e^*$ on the edges, where $e^*$ is $\Gamma_0(N)$ equivalent to $\overline{e}$, i.e. there exist $\gamma_e \in \Gamma_0(N)$ such that $e = \gamma_e \overline{e^*}$. The polygon is given by \item the list $E$ of its consecutive edges as matrices in $M_2(\Z)$; \item the permutation $A$ attached to the involution, such that \kbd{A[i]} is the index of $e^*$ in $E$ if $e = E[i]$ is the $i$-th edge; \item the list $G$ of pairing matrices between $e$ and $\overline{e^*}$, i.e. the matrices $\gamma_e\in \Gamma_0(N)$ such that $e = \gamma_e \overline{e^*}$. If $e = E[i]$, then $\gamma_e = G[i]$. Remark that $\gamma_{e^*}=\gamma_e^{-1}$ if $e \neq e^*$; modulo these trivial relations, the pairing matrices form a system of independant generators of $\Gamma_0(N)/\{1,-1\}$. Note that $\gamma_e$ is elliptic if and only if $e^* = e$. The above data yields a fundamental domain for $\Gamma_0(N)$ acting on Poincar\'e's half-plane: take the convex hull of the polygon defined by \item the edges in $E$ such that $e \neq e^*$ or $e^*=e$, where the pairing matrix $\gamma_e$ has order $2$; \item the edges $(r,t)$ and $(t,s)$ where the edge $e = (r,s) \in E$ is such that $e = e^*$ and $\gamma_e$ has order $3$ and the triangle $(r,t,s)$ is the image of $(0,\exp(2i\pi/3), \infty)$ by some element of $PSL_2(\Q)$ formed around the edge. Binary digits of flag mean: 1: return a normalized hyperbolic polygon if set, else a polygon with unimodular edges (matrices of determinant $1$). A polygon is normalized in the sense of compact orientable surfaces if the distance $d(a,a^*)$ between an edge $a$ and its image by the involution $a^*$ is less than 2, with equality if and only if $a$ is \emph{linked} with another edge $b$ ($a$, $b$, $a^*$ et $b^*$ appear consecutively in $E$ up to cyclic permutation). In particular, the vertices of all edges such that that $d(a,a^*) \neq 1$ (distance is 0 or 2) are all equivalent to $0$ modulo $\Gamma_0(N)$. The external vertices of $a a^*$ such that $d(a,a^*) = 1$ are also equivalent to $0$; the internal vertices $a\cap a^*$ (a single point), together with $0$, form a system of representatives of the cusps of $\Gamma_0(N)\bs \P^{1}(\Q)$. This is useful to compute the homology group $H_1(X_0(N),\Z)$ as it gives a symplectic basis for the intersection pairing. In this case, the number of parabolic matrices (trace 2) in the system of generators $G$ is $2(t-1)$, where $t$ is the number of non equivalent cusps for $\Gamma_0(N)$. 2: add graphical representations (in LaTeX form) for the hyperbolic polygon in Poincar\'e's half-space and the involution $a\to a^*$ of the Farey symbol. The corresponding character strings can be written to file and included in a LaTeX document provided the preamble contains \kbd{\bs usepackage\obr tikz\cbr}. \bprog ? [V,A,G] = mspolygon(3); ? V %2 = [[-1, 1; -1, 0], [1, 0; 0, 1], [0, 1; -1, 1]] ? A %3 = Vecsmall([2, 1, 3]) ? G %4 = [[-1, -1; 0, -1], [1, -1; 0, 1], [1, -1; 3, -2]] ? [V,A,G, D1,D2] = mspolygon(11,2); \\ D1 and D2 contains pictures ? {write("F.tex", "\\documentclass{article}\\usepackage{tikz}\\begin{document}" D1, "\n", D2, "\\end{document}");} ? [V1,A1] = mspolygon(6,1); \\ normalized ? V1 %8 = [[-1, 1; -1, 0], [1, 0; 0, 1], [0, 1; -1, 3], [1, -2; 3, -5], [-2, 1; -5, 2], [1, -1; 2, -1]] ? A1 %9 = Vecsmall([2, 1, 4, 3, 6, 5]) ? [V0,A0] = mspolygon(6); \\ not normalized V[3]^* = V[6], d(V[3],V[6]) = 3 ? A0 %11 = Vecsmall([2, 1, 6, 5, 4, 3]) ? [V,A] = mspolygon(14, 1); ? A %13 = Vecsmall([2, 1, 4, 3, 6, 5, 9, 10, 7, 8]) @eprog One can see from this last example that the (normalized) polygon has the form $$(a_1, a_1^*, a_2, a_2^*, a_3, a_3^*, a_4, a_5, a_4^*, a_5^*),$$ that $X_0(14)$ is of genus 1 (in general the genus is the number of blocks of the form $aba^*b^*$), has no elliptic points ($A$ has no fixed point) and 4 cusps (number of blocks of the form $aa^*$ plus 1). The vertices of edges $a_4$ and $a_5$ all project to $0$ in $X_0(14)$: the paths $a_4$ and $a_5$ project as loops in $X_0(14)$ and give a symplectic basis of the homology $H_1(X_0(14),\Z)$. \bprog ? [V,A] = mspolygon(15); ? apply(matdet, V) \\ all unimodular %2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ? [V,A] = mspolygon(15,1); ? apply(matdet, V) \\ normalized polygon but no longer unimodular edges %4 = [1, 1, 1, 1, 2, 2, 47, 11, 47, 11] @eprog The library syntax is \fun{GEN}{mspolygon}{GEN M, long flag}. \subsec{msqexpansion$(M,\var{projH},\{B = \var{seriesprecision}\})$}\kbdsidx{msqexpansion}\label{se:msqexpansion} $M$ being a full modular symbol space, as given by \kbd{msinit}, and \var{projH} being a projector on a Hecke-simple subspace (as given by \tet{mssplit}), return the Fourier coefficients $a_n$, $n\leq B$ of the corresponding normalized newform. If $B$ is omitted, use \kbd{seriesprecision}. This function uses a naive $O(B^2 d^3)$ algorithm, where $d = O(kN)$ is the dimension of $M_k(\Gamma_0(N))$. \bprog ? M = msinit(11,2, 1); \\ M_2(Gamma_0(11))^+ ? L = mssplit(M, msnew(M)); ? msqexpansion(M,L[1], 20) %3 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1, -4, -2, 4, 0, 2] ? ellan(ellinit("11a1"), 20) %4 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1, -4, -2, 4, 0, 2] @eprog\noindent The shortcut \kbd{msqexpansion(M, s, B)} is available for a symbol $s$, provided it is a Hecke eigenvector: \bprog ? E = ellinit("11a1"); ? [M,S] = msfromell(E); [sp,sm] = S; ? msqexpansion(M,sp,10) \\ in the + eigenspace %3 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] ? msqexpansion(M,sm,10) \\ in the - eigenspace %4 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] ? ellan(E, 10) %5 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] @eprog The library syntax is \fun{GEN}{msqexpansion}{GEN M, GEN projH, long precdl}. \subsec{mssplit$(M,\{H\},\{\var{dimlim}\})$}\kbdsidx{mssplit}\label{se:mssplit} Let $M$ denote a full modular symbol space, as given by \kbd{msinit}$(N,k,1)$ or $\kbd{msinit}(N,k,-1)$ and let $H$ be a Hecke-stable subspace of \kbd{msnew}$(M)$ (the full new subspace if $H$ is omitted). This function splits $H$ into Hecke-simple subspaces. If \kbd{dimlim} is present and positive, restrict to subspaces of dimension $\leq \kbd{dimlim}$. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. \bprog ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ ? L = mssplit(M); \\ split msnew(M) ? #L %3 = 2 ? f = msqexpansion(M,L[1],5); f[1].mod %4 = x^2 + 8*x - 44 ? lift(f) %5 = [1, x, -6*x - 27, -8*x - 84, 20*x - 155] ? g = msqexpansion(M,L[2],5); g[1].mod %6 = x^4 - 558*x^2 + 140*x + 51744 @eprog\noindent To a Hecke-simple subspace corresponds an orbit of (normalized) newforms, defined over a number field. In the above example, we printed the polynomials defining the said fields, as well as the first 5 Fourier coefficients (at the infinite cusp) of one such form. The library syntax is \fun{GEN}{mssplit}{GEN M, GEN H = NULL, long dimlim}. \subsec{msstar$(M,\{H\})$}\kbdsidx{msstar}\label{se:msstar} $M$ being a full modular symbol space, as given by \kbd{msinit}, return the matrix of the \kbd{*} involution, induced by complex conjugation, acting on the (stable) subspace $H$ ($M$ if omitted). \bprog ? M = msinit(11,2); \\ M_2(Gamma_0(11)) ? w = msstar(M); ? w^2 == 1 %3 = 1 @eprog The library syntax is \fun{GEN}{msstar}{GEN M, GEN H = NULL}. \subsec{mstooms$(\var{Mp}, \var{phi})$}\kbdsidx{mstooms}\label{se:mstooms} Given \kbd{Mp} from \kbd{mspadicinit}, lift the (classical) eigen symbol \kbd{phi} to a $p$-adic distribution-valued overconvergent symbol in the sense of Pollack and Stevens. More precisely, let $\phi$ belong to the space $W$ of modular symbols of level $N$, $v_p(N) \leq 1$, and weight $k$ which is an eigenvector for the Hecke operator $T_N(p)$ for a non-zero eigenvalue $a_p$ and let $N_0 = \text{lcm}(N,p)$. Under the action of $T_{N_0}(p)$, $\phi$ generates a subspace $W_\phi$ of dimension $1$ (if $p\mid N$) or $2$ (if $p$ does not divide $N$) in the space of modular symbols of level $N_0$. Let $V_p=[p,0;0,1]$ and $C_p=[a_p,p^{k-1};-1,0]$. When $p$ does not divide $N$ and $a_p$ is divisible by $p$, \kbd{mstooms} returns the lift $\Phi$ of $(\phi,\phi|_k V_p)$ such that $$T_{N_0}(p) \Phi = C_p \Phi$$ When $p$ does not divide $N$ and $a_p$ is not divisible by $p$, \kbd{mstooms} returns the lift $\Phi$ of $\phi - \alpha^{-1} \phi|_k V_p$ which is an eigenvector of $T_{N_0}(p)$ for the unit eigenvalue where $\alpha^2 - a_p \alpha + p^{k-1}=0$. The resulting overconvergent eigensymbol can then be used in \tet{mspadicmoments}, then \tet{mspadicL} or \tet{mspadicseries}. \bprog ? M = msinit(3,6, 1); p = 5; ? Tp = mshecke(M, p); factor(charpoly(Tp)) %2 = [x - 3126 2] [ x - 6 1] ? phi = matker(Tp - 6)[,1] \\ generator of p-Eigenspace, a_p = 6 %3 = [5, -3, -1]~ ? Mp = mspadicinit(M, p, 10, 0); \\ restrict to ordinary symbols, mod p^10 ? PHI = mstooms(Mp, phi); ? mu = mspadicmoments(Mp, PHI); ? mspadicL(mu) %7 = 5 + 2*5^2 + 2*5^3 + ... @eprog A non ordinary symbol. \bprog ? M = msinit(4,6,1); p = 3; ? Tp = mshecke(M, p); factor(charpoly(Tp)) %2 = [x - 244 3] [ x + 12 1] ? phi = matker(Tp + 12)[,1] \\ a_p = -12 is divisible by p = 3 %3 = [-1/32, -1/4, -1/32, 1]~ ? msissymbol(M,phi) %4 = 1 ? Mp = mspadicinit(M,3,5,0); ? PHI = mstooms(Mp,phi); *** at top-level: PHI=mstooms(Mp,phi) *** ^--------------- *** mstooms: incorrect type in mstooms [v_p(ap) > mspadicinit flag] (t_VEC). ? Mp = mspadicinit(M,3,5,1); ? PHI = mstooms(Mp,phi); @eprog The library syntax is \fun{GEN}{mstooms}{GEN Mp, GEN phi}. \section{Plotting functions} Although plotting is not even a side purpose of PARI, a number of plotting functions are provided. There are three types of graphic functions. \subsec{High-level plotting functions} (all the functions starting with \kbd{ploth}) in which the user has little to do but explain what type of plot he wants, and whose syntax is similar to the one used in the preceding section. \subsec{Low-level plotting functions} (called \var{rectplot} functions, sharing the prefix \kbd{plot}), where every drawing primitive (point, line, box, etc.) is specified by the user. These low-level functions work as follows. You have at your disposal 16 virtual windows which are filled independently, and can then be physically ORed on a single window at user-defined positions. These windows are numbered from 0 to 15, and must be initialized before being used by the function \kbd{plotinit}, which specifies the height and width of the virtual window (called a \var{rectwindow} in the sequel). At all times, a virtual cursor (initialized at $[0,0]$) is attached to the window, and its current value can be obtained using the function \kbd{plotcursor}. A number of primitive graphic objects (called \var{rect} objects) can then be drawn in these windows, using a default color attached to that window (which can be changed using the \kbd{plotcolor} function) and only the part of the object which is inside the window will be drawn, with the exception of polygons and strings which are drawn entirely. The ones sharing the prefix \kbd{plotr} draw relatively to the current position of the virtual cursor, the others use absolute coordinates. Those having the prefix \kbd{plotrecth} put in the rectwindow a large batch of rect objects corresponding to the output of the related \kbd{ploth} function. Finally, the actual physical drawing is done using \kbd{plotdraw}. The rectwindows are preserved so that further drawings using the same windows at different positions or different windows can be done without extra work. To erase a window, use \kbd{plotkill}. It is not possible to partially erase a window: erase it completely, initialize it again, then fill it with the graphic objects that you want to keep. In addition to initializing the window, you may use a scaled window to avoid unnecessary conversions. For this, use \kbd{plotscale}. As long as this function is not called, the scaling is simply the number of pixels, the origin being at the upper left and the $y$-coordinates going downwards. Plotting functions are platform independent, but a number of graphical drivers are available for screen output: X11-windows (including Openwindows and Motif), Windows's Graphical Device Interface, the Qt and FLTK graphical libraries and one may even write the graphical objects to a PostScript or SVG file and use an external viewer to open it. The physical window opened by \kbd{plotdraw} or any of the \kbd{ploth*} functions is completely separated from \kbd{gp} (technically, a \kbd{fork} is done, and the non-graphical memory is immediately freed in the child process), which means you can go on working in the current \kbd{gp} session, without having to kill the window first. This window can be closed, enlarged or reduced using the standard window manager functions. No zooming procedure is implemented though. \subsec{Functions for PostScript or SVG output} in the same way that \kbd{printtex} allows you to have a \TeX\ output corresponding to printed results, the functions \kbd{plotexport}, \kbd{plothexport} and \kbd{plothrawexport} convert a plot to a character string in either \tet{PostScript} or \tet{Scalable Vector Graphics} format. This string can then be written to a file in the customary way, using \kbd{write}. These export routines are available even if no Graphic Library is. \smallskip \subsec{parploth$(X=a,b,\var{expr},\{\var{flags}=0\},\{n=0\})$}\kbdsidx{parploth}\label{se:parploth} High precision plot of the function $y=f(x)$ represented by the expression \var{expr}, $x$ going from $a$ to $b$. This opens a specific window (which is killed whenever you click on it), and returns a four-component vector giving the coordinates of the bounding box in the form $[\var{xmin},\var{xmax},\var{ymin},\var{ymax}]$. \misctitle{Important note} \kbd{parploth} may evaluate \kbd{expr} thousands of times; given the relatively low resolution of plotting devices, few significant digits of the result will be meaningful. Hence you should keep the current precision to a minimum (e.g.~9) before calling this function. $n$ specifies the number of reference point on the graph, where a value of 0 means we use the hardwired default values (1000 for general plot, 1500 for parametric plot, and 8 for recursive plot). If no $\fl$ is given, \var{expr} is either a scalar expression $f(X)$, in which case the plane curve $y=f(X)$ will be drawn, or a vector $[f_1(X),\dots,f_k(X)]$, and then all the curves $y=f_i(X)$ will be drawn in the same window. \noindent The binary digits of $\fl$ mean: \item $1 = \kbd{Parametric}$: \tev{parametric plot}. Here \var{expr} must be a vector with an even number of components. Successive pairs are then understood as the parametric coordinates of a plane curve. Each of these are then drawn. For instance: \bprog parploth(X=0,2*Pi,[sin(X),cos(X)], "Parametric") parploth(X=0,2*Pi,[sin(X),cos(X)]) parploth(X=0,2*Pi,[X,X,sin(X),cos(X)], "Parametric") @eprog\noindent draw successively a circle, two entwined sinusoidal curves and a circle cut by the line $y=x$. \item $2 = \kbd{Recursive}$: \tev{recursive plot}. If this flag is set, only \emph{one} curve can be drawn at a time, i.e.~\var{expr} must be either a two-component vector (for a single parametric curve, and the parametric flag \emph{has} to be set), or a scalar function. The idea is to choose pairs of successive reference points, and if their middle point is not too far away from the segment joining them, draw this as a local approximation to the curve. Otherwise, add the middle point to the reference points. This is fast, and usually more precise than usual plot. Compare the results of \bprog parploth(X=-1,1, sin(1/X), "Recursive") parploth(X=-1,1, sin(1/X)) @eprog\noindent for instance. But beware that if you are extremely unlucky, or choose too few reference points, you may draw some nice polygon bearing little resemblance to the original curve. For instance you should \emph{never} plot recursively an odd function in a symmetric interval around 0. Try \bprog parploth(x = -20, 20, sin(x), "Recursive") @eprog\noindent to see why. Hence, it's usually a good idea to try and plot the same curve with slightly different parameters. The other values toggle various display options: \item $4 = \kbd{no\_Rescale}$: do not rescale plot according to the computed extrema. This is used in conjunction with \tet{plotscale} when graphing multiple functions on a rectwindow (as a \tet{plotrecth} call): \bprog s = plothsizes(); plotinit(0, s[2]-1, s[2]-1); plotscale(0, -1,1, -1,1); plotrecth(0, t=0,2*Pi, [cos(t),sin(t)], "Parametric|no_Rescale") plotdraw([0, -1,1]); @eprog\noindent This way we get a proper circle instead of the distorted ellipse produced by \bprog parploth(t=0,2*Pi, [cos(t),sin(t)], "Parametric") @eprog \item $8 = \kbd{no\_X\_axis}$: do not print the $x$-axis. \item $16 = \kbd{no\_Y\_axis}$: do not print the $y$-axis. \item $32 = \kbd{no\_Frame}$: do not print frame. \item $64 = \kbd{no\_Lines}$: only plot reference points, do not join them. \item $128 = \kbd{Points\_too}$: plot both lines and points. \item $256 = \kbd{Splines}$: use splines to interpolate the points. \item $512 = \kbd{no\_X\_ticks}$: plot no $x$-ticks. \item $1024 = \kbd{no\_Y\_ticks}$: plot no $y$-ticks. \item $2048 = \kbd{Same\_ticks}$: plot all ticks with the same length. \item $4096 = \kbd{Complex}$: is a parametric plot but where each member of \kbd{expr} is considered a complex number encoding the two coordinates of a point. For instance: \bprog parploth(X=0,2*Pi,exp(I*X), "Complex") parploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex") @eprog\noindent will draw respectively a circle and a circle cut by the line $y=x$. \synt{parploth}{GEN a,GEN b,GEN code, long flag, long n, long prec}. \subsec{plot$(X=a,b,\var{expr},\{\var{Ymin}\},\{\var{Ymax}\})$}\kbdsidx{plot}\label{se:plot} Crude ASCII plot of the function represented by expression \var{expr} from $a$ to $b$, with \var{Y} ranging from \var{Ymin} to \var{Ymax}. If \var{Ymin} (resp. \var{Ymax}) is not given, the minimum (resp. the maximum) of the computed values of the expression is used instead. %\syn{NO} \subsec{plotbox$(w,\var{x2},\var{y2},\{\var{filled}=0\})$}\kbdsidx{plotbox}\label{se:plotbox} Let $(x1,y1)$ be the current position of the virtual cursor. Draw in the rectwindow $w$ the outline of the rectangle which is such that the points $(x1,y1)$ and $(x2,y2)$ are opposite corners. Only the part of the rectangle which is in $w$ is drawn. The virtual cursor does \emph{not} move. If $\var{filled}=1$, fill the box. The library syntax is \fun{void}{plotbox}{long w, GEN x2, GEN y2, long filled}. \subsec{plotclip$(w)$}\kbdsidx{plotclip}\label{se:plotclip} `clips' the content of rectwindow $w$, i.e remove all parts of the drawing that would not be visible on the screen. Together with \tet{plotcopy} this function enables you to draw on a scratchpad before committing the part you're interested in to the final picture. The library syntax is \fun{void}{plotclip}{long w}. \subsec{plotcolor$(w,c)$}\kbdsidx{plotcolor}\label{se:plotcolor} Set default color to $c$ in rectwindow $w$. Return [R,G,B] value attached to color. Possible values for $c$ are \item a \typ{VEC} or \typ{VECSMALL} $[R,G,B]$ giving the color RGB value (all 3 values are between 0 and 255), e.g. \kbd{[250,235,215]} or equivalently \kbd{[0xfa, 0xeb, 0xd7]} for \kbd{antiquewhite}; \item a \typ{STR} giving a valid colour name (see the \kbd{rgb.txt} file in X11 distributions), e.g. \kbd{"antiquewhite"} or an RGV value given by a \kbd{\#} followed by 6 hexadecimal digits, e.g. \kbd{"\#faebd7"} for \kbd{antiquewhite}; \item a \typ{INT}, an index in the \tet{graphcolormap} default, factory setting are 1=black, 2=blue, 3=violetred, 4=red, 5=green, 6=grey, 7=gainsborough. but this can be extended if needed. \bprog ? plotinit(0,100,100); ? plotcolor(0, "turquoise") %2 = [64, 224, 208] ? plotbox(0, 50,50,1); ? plotmove(0, 50,50); ? plotcolor(0, 2) \\ blue %4 = [0, 0, 255] ? plotbox(0, 50,50,1); ? plotdraw(0); @eprog The library syntax is \fun{GEN}{plotcolor}{long w, GEN c}. \subsec{plotcopy$(\var{sourcew},\var{destw},\var{dx},\var{dy},\{\fl=0\})$}\kbdsidx{plotcopy}\label{se:plotcopy} Copy the contents of rectwindow \var{sourcew} to rectwindow \var{destw} with offset (dx,dy). If flag's bit 1 is set, dx and dy express fractions of the size of the current output device, otherwise dx and dy are in pixels. dx and dy are relative positions of northwest corners if other bits of flag vanish, otherwise of: 2: southwest, 4: southeast, 6: northeast corners The library syntax is \fun{void}{plotcopy}{long sourcew, long destw, GEN dx, GEN dy, long flag}. \subsec{plotcursor$(w)$}\kbdsidx{plotcursor}\label{se:plotcursor} Give as a 2-component vector the current (scaled) position of the virtual cursor corresponding to the rectwindow $w$. The library syntax is \fun{GEN}{plotcursor}{long w}. \subsec{plotdraw$(w, \{\fl=0\})$}\kbdsidx{plotdraw}\label{se:plotdraw} Physically draw the rectwindow $w$. More generally, $w$ can be of the form $[w_1,x_1,y_1,w_2,x_2,y_2,\dots]$ (number of components must be divisible by $3$; the windows $w_1$, $w_2$, etc.~are physically placed with their upper left corner at physical position $(x_1,y_1)$, $(x_2,y_2)$,\dots\ respectively, and are then drawn together. Overlapping regions will thus be drawn twice, and the windows are considered transparent. Then display the whole drawing in a window on your screen. If $\fl \neq 0$, $x_1$, $y_1$ etc. express fractions of the size of the current output device The library syntax is \fun{void}{plotdraw}{GEN w, long flag}. \subsec{plotexport$(\var{fmt}, \var{list}, \{\fl=0\})$}\kbdsidx{plotexport}\label{se:plotexport} Draw list of rectwindows as in \kbd{plotdraw(list,flag)}, returning the resulting picture as a character string which can then be written to a file. The format \kbd{fmt} is either \kbd{"ps"} (PostScript output) or \kbd{"svg"} (Scalable Vector Graphics). \bprog ? plotinit(0, 100, 100); ? plotbox(0, 50, 50); ? plotcolor(0, 2); ? plotbox(0, 30, 30); ? plotdraw(0); \\ watch result on screen ? s = plotexport("svg, 0); ? write("graph.svg", s); \\ dump result to file @eprog The library syntax is \fun{GEN}{plotexport}{GEN fmt, GEN list, long flag}. \subsec{ploth$(X=a,b,\var{expr},\{\var{flags}=0\},\{n=0\})$}\kbdsidx{ploth}\label{se:ploth} High precision plot of the function $y=f(x)$ represented by the expression \var{expr}, $x$ going from $a$ to $b$. This opens a specific window (which is killed whenever you click on it), and returns a four-component vector giving the coordinates of the bounding box in the form $[\var{xmin},\var{xmax},\var{ymin},\var{ymax}]$. \misctitle{Important note} \kbd{ploth} may evaluate \kbd{expr} thousands of times; given the relatively low resolution of plotting devices, few significant digits of the result will be meaningful. Hence you should keep the current precision to a minimum (e.g.~9) before calling this function. $n$ specifies the number of reference point on the graph, where a value of 0 means we use the hardwired default values (1000 for general plot, 1500 for parametric plot, and 8 for recursive plot). If no $\fl$ is given, \var{expr} is either a scalar expression $f(X)$, in which case the plane curve $y=f(X)$ will be drawn, or a vector $[f_1(X),\dots,f_k(X)]$, and then all the curves $y=f_i(X)$ will be drawn in the same window. \noindent The binary digits of $\fl$ mean: \item $1 = \kbd{Parametric}$: \tev{parametric plot}. Here \var{expr} must be a vector with an even number of components. Successive pairs are then understood as the parametric coordinates of a plane curve. Each of these are then drawn. For instance: \bprog ploth(X=0,2*Pi,[sin(X),cos(X)], "Parametric") ploth(X=0,2*Pi,[sin(X),cos(X)]) ploth(X=0,2*Pi,[X,X,sin(X),cos(X)], "Parametric") @eprog\noindent draw successively a circle, two entwined sinusoidal curves and a circle cut by the line $y=x$. \item $2 = \kbd{Recursive}$: \tev{recursive plot}. If this flag is set, only \emph{one} curve can be drawn at a time, i.e.~\var{expr} must be either a two-component vector (for a single parametric curve, and the parametric flag \emph{has} to be set), or a scalar function. The idea is to choose pairs of successive reference points, and if their middle point is not too far away from the segment joining them, draw this as a local approximation to the curve. Otherwise, add the middle point to the reference points. This is fast, and usually more precise than usual plot. Compare the results of \bprog ploth(X=-1,1, sin(1/X), "Recursive") ploth(X=-1,1, sin(1/X)) @eprog\noindent for instance. But beware that if you are extremely unlucky, or choose too few reference points, you may draw some nice polygon bearing little resemblance to the original curve. For instance you should \emph{never} plot recursively an odd function in a symmetric interval around 0. Try \bprog ploth(x = -20, 20, sin(x), "Recursive") @eprog\noindent to see why. Hence, it's usually a good idea to try and plot the same curve with slightly different parameters. The other values toggle various display options: \item $4 = \kbd{no\_Rescale}$: do not rescale plot according to the computed extrema. This is used in conjunction with \tet{plotscale} when graphing multiple functions on a rectwindow (as a \tet{plotrecth} call): \bprog s = plothsizes(); plotinit(0, s[2]-1, s[2]-1); plotscale(0, -1,1, -1,1); plotrecth(0, t=0,2*Pi, [cos(t),sin(t)], "Parametric|no_Rescale") plotdraw([0, -1,1]); @eprog\noindent This way we get a proper circle instead of the distorted ellipse produced by \bprog ploth(t=0,2*Pi, [cos(t),sin(t)], "Parametric") @eprog \item $8 = \kbd{no\_X\_axis}$: do not print the $x$-axis. \item $16 = \kbd{no\_Y\_axis}$: do not print the $y$-axis. \item $32 = \kbd{no\_Frame}$: do not print frame. \item $64 = \kbd{no\_Lines}$: only plot reference points, do not join them. \item $128 = \kbd{Points\_too}$: plot both lines and points. \item $256 = \kbd{Splines}$: use splines to interpolate the points. \item $512 = \kbd{no\_X\_ticks}$: plot no $x$-ticks. \item $1024 = \kbd{no\_Y\_ticks}$: plot no $y$-ticks. \item $2048 = \kbd{Same\_ticks}$: plot all ticks with the same length. \item $4096 = \kbd{Complex}$: is a parametric plot but where each member of \kbd{expr} is considered a complex number encoding the two coordinates of a point. For instance: \bprog ploth(X=0,2*Pi,exp(I*X), "Complex") ploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex") @eprog\noindent will draw respectively a circle and a circle cut by the line $y=x$. \synt{ploth}{void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long flags, long n, long prec}, \subsec{plothexport$(\var{fmt}, X=a,b,\var{expr},\{\var{flags}=0\},\{n=0\})$}\kbdsidx{plothexport}\label{se:plothexport} Plot of expression \var{expr}, $X$ goes from $a$ to $b$ in high resolution, returning the resulting picture as a character string which can then be written to a file. The format \kbd{fmt} is either \kbd{"ps"} (PostScript output) or \kbd{"svg"} (Scalable Vector Graphics). All other parameters and flags are as in \kbd{ploth}. \bprog ? s = plothexport("svg", x=1,10, x^2+3); ? write("graph.svg", s); @eprog \synt{plothexport}{GEN fmt, void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long flags, long n, long prec}, \subsec{plothraw$(X,Y,\{\fl=0\})$}\kbdsidx{plothraw}\label{se:plothraw} Given $X$ and $Y$ two vectors of equal length, plots (in high precision) the points whose $(x,y)$-coordinates are given in $X$ and $Y$. Automatic positioning and scaling is done, but with the same scaling factor on $x$ and $y$. If $\fl$ is 1, join points, other non-0 flags toggle display options and should be combinations of bits $2^k$, $k \geq 3$ as in \kbd{ploth}. The library syntax is \fun{GEN}{plothraw}{GEN X, GEN Y, long flag}. \subsec{plothrawexport$(\var{fmt}, X,Y,\{\fl=0\})$}\kbdsidx{plothrawexport}\label{se:plothrawexport} Given $X$ and $Y$ two vectors of equal length, plots (in high precision) the points whose $(x,y)$-coordinates are given in $X$ and $Y$, returning the resulting picture as a character string which can then be written to a file. The format \kbd{fmt} is either \kbd{"ps"} (PostScript output) or \kbd{"svg"} (Scalable Vector Graphics). Automatic positioning and scaling is done, but with the same scaling factor on $x$ and $y$. If $\fl$ is 1, join points, other non-0 flags toggle display options and should be combinations of bits $2^k$, $k \geq 3$ as in \kbd{ploth}. The library syntax is \fun{GEN}{plothrawexport}{GEN fmt, GEN X, GEN Y, long flag}. \subsec{plothsizes$(\{\fl=0\})$}\kbdsidx{plothsizes}\label{se:plothsizes} Return data corresponding to the output window in the form of a 8-component vector: window width and height, sizes for ticks in horizontal and vertical directions (this is intended for the \kbd{gnuplot} interface and is currently not significant), width and height of characters, width and height of display, if applicable. If display has no sense, e.g. for svg plots or postscript plots, then width and height of display are set to 0. If $\fl = 0$, sizes of ticks and characters are in pixels, otherwise are fractions of the screen size The library syntax is \fun{GEN}{plothsizes}{long flag}. \subsec{plotinit$(w,\{x\},\{y\},\{\fl=0\})$}\kbdsidx{plotinit}\label{se:plotinit} Initialize the rectwindow $w$, destroying any rect objects you may have already drawn in $w$. The virtual cursor is set to $(0,0)$. The rectwindow size is set to width $x$ and height $y$; omitting either $x$ or $y$ means we use the full size of the device in that direction. If $\fl=0$, $x$ and $y$ represent pixel units. Otherwise, $x$ and $y$ are understood as fractions of the size of the current output device (hence must be between $0$ and $1$) and internally converted to pixels. The plotting device imposes an upper bound for $x$ and $y$, for instance the number of pixels for screen output. These bounds are available through the \tet{plothsizes} function. The following sequence initializes in a portable way (i.e independent of the output device) a window of maximal size, accessed through coordinates in the $[0,1000] \times [0,1000]$ range: \bprog s = plothsizes(); plotinit(0, s[1]-1, s[2]-1); plotscale(0, 0,1000, 0,1000); @eprog The library syntax is \fun{void}{plotinit}{long w, GEN x = NULL, GEN y = NULL, long flag}. \subsec{plotkill$(w)$}\kbdsidx{plotkill}\label{se:plotkill} Erase rectwindow $w$ and free the corresponding memory. Note that if you want to use the rectwindow $w$ again, you have to use \kbd{plotinit} first to specify the new size. So it's better in this case to use \kbd{plotinit} directly as this throws away any previous work in the given rectwindow. The library syntax is \fun{void}{plotkill}{long w}. \subsec{plotlines$(w,X,Y,\{\fl=0\})$}\kbdsidx{plotlines}\label{se:plotlines} Draw on the rectwindow $w$ the polygon such that the (x,y)-coordinates of the vertices are in the vectors of equal length $X$ and $Y$. For simplicity, the whole polygon is drawn, not only the part of the polygon which is inside the rectwindow. If $\fl$ is non-zero, close the polygon. In any case, the virtual cursor does not move. $X$ and $Y$ are allowed to be scalars (in this case, both have to). There, a single segment will be drawn, between the virtual cursor current position and the point $(X,Y)$. And only the part thereof which actually lies within the boundary of $w$. Then \emph{move} the virtual cursor to $(X,Y)$, even if it is outside the window. If you want to draw a line from $(x1,y1)$ to $(x2,y2)$ where $(x1,y1)$ is not necessarily the position of the virtual cursor, use \kbd{plotmove(w,x1,y1)} before using this function. The library syntax is \fun{void}{plotlines}{long w, GEN X, GEN Y, long flag}. \subsec{plotlinetype$(w,\var{type})$}\kbdsidx{plotlinetype}\label{se:plotlinetype} This function is obsolete and currently a no-op. Change the type of lines subsequently plotted in rectwindow $w$. \var{type} $-2$ corresponds to frames, $-1$ to axes, larger values may correspond to something else. $w = -1$ changes highlevel plotting. The library syntax is \fun{void}{plotlinetype}{long w, long type}. \subsec{plotmove$(w,x,y)$}\kbdsidx{plotmove}\label{se:plotmove} Move the virtual cursor of the rectwindow $w$ to position $(x,y)$. The library syntax is \fun{void}{plotmove}{long w, GEN x, GEN y}. \subsec{plotpoints$(w,X,Y)$}\kbdsidx{plotpoints}\label{se:plotpoints} Draw on the rectwindow $w$ the points whose $(x,y)$-coordinates are in the vectors of equal length $X$ and $Y$ and which are inside $w$. The virtual cursor does \emph{not} move. This is basically the same function as \kbd{plothraw}, but either with no scaling factor or with a scale chosen using the function \kbd{plotscale}. As was the case with the \kbd{plotlines} function, $X$ and $Y$ are allowed to be (simultaneously) scalar. In this case, draw the single point $(X,Y)$ on the rectwindow $w$ (if it is actually inside $w$), and in any case \emph{move} the virtual cursor to position $(x,y)$. If you draw few points in the rectwindow, they will be hard to see; in this case, you can use filled boxes instead. Compare: \bprog ? plotinit(0, 100,100); plotpoints(0, 50,50); ? plotdraw(0) ? plotinit(1, 100,100); plotmove(1,48,48); plotrbox(1, 4,4, 1); ? plotdraw(1) @eprog The library syntax is \fun{void}{plotpoints}{long w, GEN X, GEN Y}. \subsec{plotpointsize$(w,\var{size})$}\kbdsidx{plotpointsize}\label{se:plotpointsize} This function is obsolete. It is currently a no-op. Changes the ``size'' of following points in rectwindow $w$. If $w = -1$, change it in all rectwindows. The library syntax is \fun{void}{plotpointsize}{long w, GEN size}. \subsec{plotpointtype$(w,\var{type})$}\kbdsidx{plotpointtype}\label{se:plotpointtype} This function is obsolete and currently a no-op. change the type of points subsequently plotted in rectwindow $w$. $\var{type} = -1$ corresponds to a dot, larger values may correspond to something else. $w = -1$ changes highlevel plotting. The library syntax is \fun{void}{plotpointtype}{long w, long type}. \subsec{plotrbox$(w,\var{dx},\var{dy},\{\var{filled}\})$}\kbdsidx{plotrbox}\label{se:plotrbox} Draw in the rectwindow $w$ the outline of the rectangle which is such that the points $(x1,y1)$ and $(x1+dx,y1+dy)$ are opposite corners, where $(x1,y1)$ is the current position of the cursor. Only the part of the rectangle which is in $w$ is drawn. The virtual cursor does \emph{not} move. If $\var{filled}=1$, fill the box. The library syntax is \fun{void}{plotrbox}{long w, GEN dx, GEN dy, long filled}. \subsec{plotrecth$(w,X=a,b,\var{expr},\{\fl=0\},\{n=0\})$}\kbdsidx{plotrecth}\label{se:plotrecth} Writes to rectwindow $w$ the curve output of \kbd{ploth}$(w,X=a,b,\var{expr},\fl,n)$. Returns a vector for the bounding box. %\syn{NO} \subsec{plotrecthraw$(w,\var{data},\{\var{flags}=0\})$}\kbdsidx{plotrecthraw}\label{se:plotrecthraw} Plot graph(s) for \var{data} in rectwindow $w$. $\fl$ has the same significance here as in \kbd{ploth}, though recursive plot is no more significant. \var{data} is a vector of vectors, each corresponding to a list a coordinates. If parametric plot is set, there must be an even number of vectors, each successive pair corresponding to a curve. Otherwise, the first one contains the $x$ coordinates, and the other ones contain the $y$-coordinates of curves to plot. The library syntax is \fun{GEN}{plotrecthraw}{long w, GEN data, long flags}. \subsec{plotrline$(w,\var{dx},\var{dy})$}\kbdsidx{plotrline}\label{se:plotrline} Draw in the rectwindow $w$ the part of the segment $(x1,y1)-(x1+dx,y1+dy)$ which is inside $w$, where $(x1,y1)$ is the current position of the virtual cursor, and move the virtual cursor to $(x1+dx,y1+dy)$ (even if it is outside the window). The library syntax is \fun{void}{plotrline}{long w, GEN dx, GEN dy}. \subsec{plotrmove$(w,\var{dx},\var{dy})$}\kbdsidx{plotrmove}\label{se:plotrmove} Move the virtual cursor of the rectwindow $w$ to position $(x1+dx,y1+dy)$, where $(x1,y1)$ is the initial position of the cursor (i.e.~to position $(dx,dy)$ relative to the initial cursor). The library syntax is \fun{void}{plotrmove}{long w, GEN dx, GEN dy}. \subsec{plotrpoint$(w,\var{dx},\var{dy})$}\kbdsidx{plotrpoint}\label{se:plotrpoint} Draw the point $(x1+dx,y1+dy)$ on the rectwindow $w$ (if it is inside $w$), where $(x1,y1)$ is the current position of the cursor, and in any case move the virtual cursor to position $(x1+dx,y1+dy)$. If you draw few points in the rectwindow, they will be hard to see; in this case, you can use filled boxes instead. Compare: \bprog ? plotinit(0, 100,100); plotrpoint(0, 50,50); plotrpoint(0, 10,10); ? plotdraw(0) ? thickpoint(w,x,y)= plotmove(w,x-2,y-2); plotrbox(w,4,4,1); ? plotinit(1, 100,100); thickpoint(1, 50,50); thickpoint(1, 60,60); ? plotdraw(1) @eprog The library syntax is \fun{void}{plotrpoint}{long w, GEN dx, GEN dy}. \subsec{plotscale$(w,\var{x1},\var{x2},\var{y1},\var{y2})$}\kbdsidx{plotscale}\label{se:plotscale} Scale the local coordinates of the rectwindow $w$ so that $x$ goes from $x1$ to $x2$ and $y$ goes from $y1$ to $y2$ ($x2mfcoefs(f,3),[E4,E6]) % = [[1, 240, 2160, 6720], [1, -504, -16632, -122976]] ? E43 = mfpow(E4, 3); E62 = mfpow(E6, 2); ? DP = mflinear([E43, E62], [1, -1]/1728); ? mfcoefs(DP, 6) % = [0, 1, -24, 252, -1472, 4830, -6048] ? mfisequal(D, DP) % = 1 \end{verbatim} Self-explanatory. Note that there is a command \kbd{mfcoef(F, n)} (without the final ``s'') which simply outputs the coefficient $a(n)$. A final example of the same type: \begin{verbatim} ? F = mffrometaquo([1,2; 11,2]); mfcoefs(F,10) % = [0, 1, -2, -1, 2, 1, 2, -2, 0, -2, -2] ? G = mffromell(ellinit("11a1"))[2]; ? mfisequal(F, G) % = 1 \end{verbatim} Here, \kbd{mffrometaquo} takes as argument a matrix representing an \emph{eta quotient}, here $\eta(1\times\tau)^2\eta(11\times\tau)^2$. The second component of the \kbd{mffromell} output is the modular form associated to the elliptic curve by modularity. \section{A Second Session: Modular Form Spaces} In the first session, we have seen a few preinstalled modular forms (that we can call \emph{leaves}), and a number of operations on them. All reasonable operations have been implemented (if some are missing, please tell us). We are now going to work with \emph{spaces} of modular forms. \begin{verbatim} ? mf = mfinit([1,12]); L = mfbasis(mf); #L % = 2 ? mfdim(mf) % = 2 \end{verbatim} This creates the full space of modular forms of level $1$ and weight $12$. This space is created thanks to an almost random basis that one can obtain using \kbd{mfbasis}, and we see either by asking for the number of elements of \kbd{L} or by using the command \kbd{mfdim}, that it has dimension $2$, not surprising. We can see it better by writing: \begin{verbatim} ? mfcoefs(L[1],6) % = [691/65520, 1, 2049, 177148, 4196353, 48828126, 362976252] ? mfcoefs(L[2],6) % = [0, 1, -24, 252, -1472, 4830, -6048] \end{verbatim} or simply \begin{verbatim} ? mfcoefs(mf,6) \\ apply mfcoefs to mfbasis elements % = [691/65520 0] [ 1 1] [ 2049 -24] [ 177148 252] [ 4196353 -1472] [ 48828126 4830] [362976252 -6048] \end{verbatim} Note two things: first, the Eisenstein series are given before the cusp forms (this may change, but for now this is the case), and second, the Eisenstein series is normalized so that it is the coefficient $a(1)$ which is equal to $1$, and not $a(0)$. In particular, here at least, it is a normalized Hecke eigenform. If we want to work only in the cuspidal space $S_{12}(\G)$, we simply use the flag $1$, such as: \begin{verbatim} ? mf = mfinit([1,12], 1); L = mfbasis(mf); #L % = 1 ? mfcoefs(L[1],6) % = [0, 1, -24, 252, -1472, 4830, -6048] \end{verbatim} Let us now look at higher dimensional cases. In the following example, we consider the \emph{new space} (flag = $0$), although in the present case this is the same as the cuspidal space: \begin{verbatim} ? mf = mfinit([35,2], 0); L = mfbasis(mf); #L % = 3 ? for (i = 1, 3, print(mfcoefs(L[i], 10))) [0, 3, -1, 0, 3, 1, -8, -1, -9, 1, -1] [0, -1, 9, -8, -11, -1, 4, 1, 13, 7, 9] [0, 0, -8, 10, 4, -2, 4, 2, -4, -12, -8] \end{verbatim} These are essentially random cusp forms. Usually, you want the eigenforms: this is obtained by the function \kbd{mfeigenbasis} (note in passing that \kbd{B=mfeigenbasis(mf)} adds components to \kbd{mf}, so that the next call is instantaneous). You can ask for the defining number fields with the command \kbd{mffields}. Note that these commands act only on the new space, but the package also accepts the spaces that contain it (such as the cuspidal space or the full space, but not the old space), although the result is only about the new space. \begin{verbatim} ? mffields(mf) % = [y, y^2 - y - 4] ? L = mfeigenbasis(mf); #L % = 2 ? mfcoefs(L[1],10) % = [0, 1, 0, 1, -2, -1, 0, 1, 0, -2, 0] ? mfcoefs(L[2],4) % = [Mod(0, y^2 - y - 4), Mod(1, y^2 - y - 4),\ Mod(-y, y^2 - y - 4),Mod(y - 1, y^2 - y - 4),\ Mod(y + 2, y^2 - y - 4)] ? lift(mfcoefs(L[2],10)) % = [0, 1, -y, y - 1, y + 2, 1, -4, -1, -y - 4, -y + 2, -y] \end{verbatim} The command \kbd{mffields} gives the polynomials in the variable $y$ defining the number field extensions on which the eigenforms are defined. Here, one of the fields is $\Q$, the other is $\Q(\sqrt{17})$. To obtain the eigenforms, we use \kbd{mfeigenbasis}, and there are only two and not three, since the one defined on $\Q(\sqrt{17})$ goes together with its conjugate. Asking directly \kbd{mfcoefs(L[2],4)} gives the coefficients as \kbd{polmods}, not easy to read, so it is usually preferable to \emph{lift} them, giving the last command, where in the output we must of course remember that $y$ stands for \emph{one} of the two roots of $y^2-y-4=0$, i.e., $(1\pm\sqrt{17})/2$. In fact, for some numerical computations, we really need the coefficients of the eigenform embedded in $\C$, and not just as abstract algebraic numbers (in our case of trivial character, they will be in $\R$). This is why a few functions (most notably \kbd{mfeval} and \kbd{lfunmf}) will return a \emph{vector} of results and not a scalar when called on such a form. For instance, here is a little GP script which computes the numerical expansion of a modular form instead of the expansion in \kbd{polmods}: \begin{verbatim} mfcoefsembed(F,n) = mfembed(F, mfcoefs(F,n)); \end{verbatim} Note that this produces a vector of expansions when the eigenforms are defined over an extension, i.e. $[\Q(F):\Q(\chi)] > 1$, one per conjugate form. \begin{verbatim} ? mfcoefsembed(L[2],5) \\ two conjugate forms %4 = [[0, 1, 1.5615..., -2.5615..., 0.43844..., 1], [0, 1, -2.561...,, 1.5615...,, 4.5615..., 1]] \end{verbatim} The first eigenform found above is \emph{rational}, hence by the modularity theorem there exists up to isogeny a unique elliptic curve to which it corresponds. We check this by writing \begin{verbatim} ? [mf,F] = mffromell(ellinit("35a1")); mfcoefs(F, 10) % = [0, 1, 0, 1, -2, -1, 0, 1, 0, -2, 0] ? mfisequal(F, L[1]) % = 1 \end{verbatim} For a more typical example (still with no character): \begin{verbatim} ? [ mfdim([96,2], flag) | flag <- [0..4] ] % = [2, 9, 7, 15, 24] \end{verbatim} This gives us the dimensions of the new space, the cuspidal space, the old space, the space of Eisenstein series, and the whole space of modular forms. Just for fun, we write (recall that the default is the full space): \begin{verbatim} ? mf = mfinit([96,2]); L = mfbasis(mf); ? for (i = 12, 15, print(mfcoefs(L[i], 15))) [23/24, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 12, 28, 14, 24, 24] [31/24, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 12, 28, 14, 24, 24] [47/24, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 12, 28, 14, 24, 24] [95/24, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 12, 28, 14, 24, 24] \end{verbatim} Apparently, these four Eisenstein series differ only by their constant term, which is of course not possible. Indeed: \begin{verbatim} ? F = mflinear([L[14],L[12]],[1,-1]); mfcoefs(F, 50) % = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\ 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0] ? G = mfhecke(mf, F, 24); mfcoefs(G, 12) % = [1, 24, 24, 96, 24, 144, 96, 192, 24, 312, 144, 288, 96] ? mftobasis(mf, G) % = [0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\ 0, 0, 0, 0, 0, 0]~ ? 24*mfcoefs(L[5], 12) % = [1, 24, 24, 96, 24, 144, 96, 192, 24, 312, 144, 288, 96] \end{verbatim} The first command shows that the Eisenstein series differ on their $n$-th Fourier coefficient for $n=0$, $24$, and $48$, and the second command applies the Hecke operator $T_{24}$ (sometimes denoted $U_{24}$) to the difference, whose effect is to replace $a(n)$ by $a(24n)$, giving the much more compact output of $G$. The last commands show that $G$ is equal to $24$ times the fifth Eisenstein series \kbd{L[5]}. \begin{verbatim} ? mf=mfinit([96,2],0); mffields(mf) % = [y, y] ? L = mfeigenbasis(mf); for(i=1, 2, print(mfcoefs(L[i], 16))) [0, 1, 0, 1, 0, 2, 0, -4, 0, 1, 0, 4, 0, -2, 0, 2, 0] [0, 1, 0, -1, 0, 2, 0, 4, 0, 1, 0, -4, 0, -2, 0, -2, 0] ? Fa = mffromell(ellinit("96a1"))[2]; mfcoefs(Fa, 16) % = [0, 1, 0, 1, 0, 2, 0, -4, 0, 1, 0, 4, 0, -2, 0, 2, 0] ? Fb = mffromell(ellinit("96b1"))[2]; mfcoefs(Fb, 16) % = [0, 1, 0, -1, 0, 2, 0, 4, 0, 1, 0, -4, 0, -2, 0, -2, 0] \end{verbatim} The \kbd{mffromell} function returns a triple \kbd{[mf,F,C]}, where \kbd{mf} is the modular form cuspidal space to which \kbd{F} belongs, \kbd{F} is the rational eigenform corresponding to the elliptic curve by modularity, and \kbd{C} is the vector of coefficients of \kbd{F} on the basis in \kbd{mf}, which we recall is usually not a basis of eigenforms (otherwise \kbd{F} would belong to this basis). Note also that \kbd{Fa} and \kbd{Fb} are twists of one another: \begin{verbatim} ? mfisequal(mftwist(Fa, -4), Fb) % = 1 \end{verbatim} \section{Interlude: Dirichlet characters} There are many ways to represent multiplicative characters on $(\Z/N\Z)^*$ in \kbd{Pari/Gp}, we will list them by increasing order of sophistication, restricting to characters with complex values: \begin{itemize} \item A quadratic character $(D/.)$ (Kronecker symbol) is described by the integer $D$. For instance $1$ is the trivial character. \item There is a (non-canonical but fixed) bijection between $(\Z/N\Z)^\times$ and its character group, via \emph{Conrey labels}. So \kbd{Mod}$(a,N)$ represents a character whenever $a$ is coprime to $N$. This makes it easy to loop on all characters without worrying too much about which is which. In this labeling, \kbd{Mod(1,N)} is the trivial character, and characters are multiplied/divided by performing the corresponding operation on their Conrey labels. \item The finite abelian group $G = (\Z/N\Z)^*$ is written $$G = \bigoplus_{i\leq n}\; (\Z/d_i\Z) \cdot g_i,$$ with $d_n \mid \dots \mid d_2 \mid d_1$ (SNF condition), all $d_i > 0$, and $\prod_i d_i = \phi(N)$. The SNF condition makes the $d_i$ unique, but the generators $g_i$, of respective order $d_i$, are definitely not unique. The $\oplus$ notation means that all elements of $G$ can be written uniquely as $\prod_i g_i^{n_i}$ where $n_i \in \Z/d_i\Z$. The $g_i$ are the so-called \emph{SNF generators} of $G$. The command \kbd{znstar}$(N)$ outputs the SNF structure (group order, $d_i$ and $g_i$), but $G = \kbd{znstar}(N, 1)$ is needed to initialize a group we can work with: most importantly we can now solve discrete logarithm problems and decompose elements on the $g_i$. A character on the abelian group $\oplus (\Z/d_j\Z) g_j$ is given by a row vector $\chi = [a_1,\ldots,a_n]$ of integers $0\leq a_i < d_i$ such that $\chi(g_j) = e(a_j / d_j)$ for all $j$, with the standard notation $e(x) := \exp(2i\pi x)$. In other words, $\chi(\prod g_j^{n_j}) = e(\sum a_j n_j / d_j)$. In this encoding $[0,\dots,0]$ is the trivial character. Of course a character $\chi$ must always be given as a \emph{pair} $[G,\chi]$, since $\chi$ is meaningless without knowledge of the $(g_i)$ or the $(d_i)$. \end{itemize} The command \kbd{znchar}$(S)$ converts a datum describing a character to the third form $[G,\chi]$. The command \kbd{znchartokronecker} converts a character of order $\leq 2$ to the first form $(D/.)$, and functions such as \kbd{zncharconductor}, \kbd{znchartoprimitive}, and \kbd{zncharinduce} allow to restrict or extend characters between different $(\Z/M\Z)^*$. Note the important fact that it is necessary to give the two arguments $G$ and $\chi$ separately to these functions, for instance \kbd{zncharconductor(G,chi)} (and not \kbd{zncharconductor([G,chi])}). Functions such as \kbd{charmul}, \kbd{chardiv}, \kbd{charpow}, \kbd{charorder} or \kbd{chareval} apply to more general abelian characters than characters on $(\Z/N\Z)^\times$, whence the prefix \kbd{char} instead of \kbd{znchar}. \section{A Third Session: Nontrivial Characters} Recall that a nontrivial character can be represented either by a discriminant $D$ (not necessarily fundamental), the character being the Legendre--Kronecker symbol $(D/n)$, or by its \emph{Conrey label} in $(\Z/N\Z)^\times$, for instance \kbd{Mod(161,633)} (which has order 42, as \kbd{znorder} tells us). Defining modular form spaces with character is as simple as without: we replace the parameters $[N,k]$ by $[N,k,\chi]$. Instead of \kbd{mf=mfinit([35,2])}, one can write \kbd{mf=mfinit([35,2,5], 0)}, where 5 is the quadratic character $(5/.)$. Thus: \begin{verbatim} ? mf = mfinit([35,2,5],0); mffields(mf) % = [y^2 + 1] ? F = mfeigenbasis(mf)[1]; lift(mfcoefs(F, 10)) % = [0, 1, 2*y, -y, -2, -y - 2, 2, -y, 0, 2, -4*y + 2] \end{verbatim} where in the last output $y$ is equal to one of the two roots of $y^2+1=0$, i.e., $\pm i$. Working with nontrivial characters allows us in particular to work with odd weights, and in particular in weight $1$: \begin{verbatim} ? mf = mfinit([23,1,-23], 0); mfdim(mf) % = 1 ? F = mfbasis(mf)[1]; mfcoefs(F, 16) % = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0, -1] ? mfgaloistype(mf,F) % = 6 \end{verbatim} The last output means that the image in $\PSL_2(\C)$ of the projective representation associated to $F$ is of type $D_3$. Note that an ''exotic'' representation is given by a negative number, opposite of the cardinality of the projective image. Since this form is of dihedral type, it can be obtained via theta functions. Indeed: \begin{verbatim} ? F1 = mffromqf([2,1; 1,12])[2]; V1 = mfcoefs(F1, 16) % = [1, 2, 0, 0, 2, 0, 4, 0, 4, 2, 0, 0, 4, 0, 0, 0, 2] ? F2 = mffromqf([4,1; 1,6])[2]; V2 = mfcoefs(F2, 16) % = [1, 0, 2, 2, 2, 0, 2, 0, 2, 2, 0, 0, 4, 2, 0, 0, 4] ? (V1 - V2)/2 % = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0, -1] ? mfisequal(F, mflinear([F1, F2], [1, -1]/2)) % = 1 \end{verbatim} Here we were lucky in that we ``knew'' that the correct character was $(-23/n)$. But what if we did not know this ? The first observation is that modular form spaces corresponding to Galois conjugate characters are isomorphic ($\chi$ is Galois conjugate to $\chi'$ if $\chi'=\chi^m$ for some $m$ coprime to the order of $\chi$). Thus, it is sufficient to find a representative of each equivalence class, and this is given by the \kbd{GP} commands \kbd{G=znstar(N,1); chargalois(G)}, where $N$ is the level of the desired character (note that $N$ will not necessarily be the conductor of the characters). This exactly outputs a list of representative of each equivalence class (do not for now try to understand the details of this command, nor the fact that \kbd{chargalois} and \kbd{znstar} have optional parameters). However, this is not quite yet what we want. Although only for efficiency, we want characters with the same parity as the weight, otherwise the corresponding modular form spaces will be $0$. This is achieved by the \kbd{GP} command \kbd{zncharisodd(G,chi)} which does what you think it does. Let us first do this for $N=23$: we write \begin{verbatim} ? G = znstar(23, 1); ? L = [chi | chi<-chargalois(G), zncharisodd(G,chi)]; #L % = 2 ? [mfdim([23,1,[G,chi]], 0) | chi <- L ] % = [0, 1] ? [charorder(G,chi) | chi <- L] % = [22, 2] \end{verbatim} This tells us that (up to Galois conjugation) there are two possible odd characters, one, of order $22$, giving a $0$-dimensional space, the other being the quadratic character given above. Note that \kbd{chargalois} returns (orbits of) characters attached to an arbitrary abelian finite group $G$ while \kbd{mfinit} expects a \emph{pair} \kbd{[G,chi]} for some \kbd{znstar} $G$, as written above. When doing long explorations with all characters of a certain level, it is preferable to use \emph{wildcards}. For instance, instead of the above one can write: \begin{verbatim} ? mfall = mfinit([23,1,0], 0); #mfall % = 1 ? mf = mfall[1]; mfdim(mf) % = 1 ? mfparams(mf) % = [23, 1, -23, 0] \end{verbatim} This does not exactly give us the same information: the third parameter $0$ in the first command asks for \emph{all} nonempty spaces of level $23$ and weight $1$, and the program tells us that there is only one, of dimension $1$. The last command \kbd{mfparams} outputs \kbd{[N,k,CHI,space]}, so here tells us that the corresponding character is the Kronecker--Legendre symbol $(-23/n)$. Using wildcards, let us explore levels in certain ranges: we write \begin{verbatim} wt1exp(lim1,lim2)= { my(mfall,mf,chi,v); for (N = lim1, lim2, mfall = mfinit([N,1,0], 0); /* use wildcard */ for (i=1, #mfall, mf = mfall[i]; chi = mfparams(mf)[3]; /* nice format: D or Mod(a,N) */ [ print([N,chi,-t]) | t<-mfgaloistype(mf), t < 0 ] ) ); } \end{verbatim} For instance, \kbd{wt1exp(1,230)} outputs in 4 seconds \begin{verbatim} [124, Mod(87, 124), 12] [133, Mod(83, 133), 12] [148, Mod(105, 148), 24] [171, Mod(94, 171), 12] [201, Mod(104, 201), 12] [209, Mod(197, 209), 12] [219, Mod(8, 219), 12] [224, Mod(95, 224), 12] [229, Mod(122, 229), 24] [229, Mod(122, 229), 24] \end{verbatim} Thus, the smallest exotic $A_4$ form is in level $124$ and the smallest $S_4$ form is in level $148$. Note that in level $229$, we have two (non Galois conjugate) eigenforms of type $S_4$. If we type \kbd{wt1exp(633,633)}, in 6 seconds we obtain \kbd{[633, Mod(107, 633), 60]}, and this level is indeed the lowest level for which there exists a type $A_5$ form. The character orders are obtained either as \kbd{znorder(chi)} (since all the \kbd{chi} are \kbd{intmods}), or using the general construction \begin{verbatim} [G,v] = znstar(chi); ord = charorder(G,v) \end{verbatim} where we first convert \kbd{chi} to a general abelian character in $[G,\chi]$ format. \section{Leaf Functions} Although we have already seen most of these functions in the first session, we repeat some of examples here. \subsection{Functions Created from Scratch} We now start a slightly more systematic exploration of the available functions. We begin by \emph{leaf functions}, i.e., functions created from scratch or from a given mathematical object. \begin{verbatim} ? D = mfDelta(); mfcoefs(D, 5) % = [0, 1, -24, 252, -1472, 4830] ? E4 = mfEk(4); mfcoefs(E4, 5) % = [1, 240, 2160, 6720, 17520, 30240] ? E6 = mfEk(6); ? D2 = mflinear([mfpow(E4, 3), mfpow(E6, 2)], [1, -1]/1728); ? mfisequal(D, D2) % = 1 \end{verbatim} Self-explanatory. More complicated Eisenstein series: \begin{verbatim} ? E3 = mfeisenstein(1, 1, -3); mfcoefs(E3, 10) % = [1/6, 1, 0, 1, 1, 0, 0, 2, 0, 1, 0] ? E4 = mfeisenstein(5, -4, 1); mfcoefs(E4, 10) % = [5/4, 1, 1, -80, 1, 626, -80, -2400, 1, 6481, 626] ? H2 = mfEH(5/2); mfcoefs(H2,10) % = [1/120, -1/12, 0, 0, -7/12, -2/5, 0, 0, -1, -25/12, 0] \end{verbatim} The \kbd{mfeisenstein(k,c1,c2)} command generates the Eisenstein series of weight $k$ and characters \kbd{c1} and \kbd{c2}. The \kbd{mfEH(k)} command is specific to half-integral weight $k$ and generates the Cohen--Eisenstein series of weight $k$. \begin{verbatim} ? T = mfTheta(); mfcoefs(T,16) % = [1, 2, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2] ? mf = mfinit([4, 5, -4]); mftobasis(mf, mfpow(T, 10)) % = [64/5, 4/5, 32/5] ? B = mfbasis(mf); apply(mfdescribe, B) % = ["F_5(1, -4)", "F_5(-4, 1)", "TR^new([4, 5, -4, y])"] ? mfisCM(B[3]) % = -4 \end{verbatim} Here, we compute the coefficients of $\th^{10}$ on the basis of \kbd{mf} (we know of course the level, weight, and character). We then apply the \kbd{mfdescribe} function, which tells us that the first two forms in the basis are Eisenstein series, and the third one is some trace form on the cuspidal new space. However, the last command says that this third basis element is a \emph{CM form}, so that its coefficients can be computed just as fast as those of Eisenstein series, so that there does exist an explicit formula for the number of representations as a sum of ten squares. Keeping the above sessions, we can also write: \begin{verbatim} ? mftobasis(mf, mfpow(H2, 2)) % = [1/18000, 1/18000, -3/2000]~ \end{verbatim} \subsection{Functions Created from Mathematical Objects} \begin{verbatim} ? [mf,F,co] = mffromell(ellinit("26b1")); co % = [1/2, 1/2]~ ? mfcoefs(F,10) % = [0, 1, 1, -3, 1, -1, -3, 1, 1, 6, -1] \end{verbatim} This creates the modular form attached by modularity to the second isogeny class of elliptic curves over $\Q$ for conductor $26$. The result is a 3-component vector: \kbd{mf} is the modular form space, $F$ the modular form, and \kbd{co} are the coefficients of $F$ on the basis of \kbd{mf}. Similarly, there are functions \kbd{mffromlfun} (from $L$-functions attached to eigenforms), \kbd{mffromqf} (from quadratic forms) and \kbd{mffrometaquo}: \begin{verbatim} ? F = mffrometaquo([1, 2; 11, 2]); mfcoefs(F, 10) % = [0, 1, -2, -1, 2, 1, 2, -2, 0, -2, -2] ? F = mffrometaquo([1, 2; 2, -1]); mfparams(F) % = [16, 1/2, 1, y] ? mfcoefs(F, 10) % = [1, -2, 0, 0, 2, 0, 0, 0, 0, -2, 0] \end{verbatim} The \kbd{mfparams} command tells us that $F\in M_{1/2}(\G_0(16))$. \section{Atkin, Hecke and Expanding Operators} \begin{verbatim} ? mf = mfinit([96,4], 0); mfdim(mf) % = 6 ? M = mfheckemat(mf, 7) % = [0 0 0 372 696 0] [0 0 36 0 0 -96] [0 27/5 0 -276/5 -276/5 0] [1 0 -12 0 0 62] [0 0 1 0 0 -16] [0 -3/5 0 14/5 -16/5 0] ? P = charpoly(M) % = x^6 - 1456*x^4 + 209664*x^2 - 2985984 ? factor(P) % = [x - 36 1] [x - 12 1] [ x - 4 1] [ x + 4 1] [x + 12 1] [x + 36 1] \end{verbatim} Note a few things: first, the matrix of the Hecke operator $T(7)$ does not have integral coefficients. Indeed, recall that the basis of modular forms in \kbd{mf} is mostly random, so there is no reason for the matrix to be integral. On the other hand, since the eigenvalues of Hecke operators are algebraic integers, the characteristic polynomial of $T(7)$ must be monic with integer coefficients. As it happens, it factors completely into linear factors to the power $1$, so all the eigenvalues of $T(7)$ are in fact in $\Z$: this immediately shows that the splitting will be entirely rational and the eigenforms with integer coefficients. Let's check: \begin{verbatim} ? mffields(mf) % = [y, y, y, y, y, y] ? L = mfeigenbasis(mf); for(i=1,6,print(mfcoefs(L[i],16))) [0, 1, 0, 3, 0, 10, 0, 4, 0, 9, 0, -20, 0, 70, 0, 30, 0] [0, 1, 0, 3, 0, 2, 0, 12, 0, 9, 0, 60, 0, -42, 0, 6, 0] [0, 1, 0, 3, 0, -14, 0, -36, 0, 9, 0, -36, 0, 54, 0, -42, 0] [0, 1, 0, -3, 0, 10, 0, -4, 0, 9, 0, 20, 0, 70, 0, -30, 0] [0, 1, 0, -3, 0, 2, 0, -12, 0, 9, 0, -60, 0, -42, 0, -6, 0] [0, 1, 0, -3, 0, -14, 0, 36, 0, 9, 0, 36, 0, 54, 0, 42, 0] \end{verbatim} We see that of the six eigenforms, the last three are twists of the first three. There also exists the command \kbd{G=mfhecke(mf,F,n)}, which given a modular form $F$ in \kbd{mf}, outputs the modular form $T(n)F$. \begin{verbatim} ? mf=mfinit([96,6],0); mffields(mf) % = [y, y, y, y, y, y, y^2 - 31, y^2 - 31] ? mfatk = mfatkininit(mf,3); % factor(charpoly(mfatk[2]/mfatk[3])) % = [x - 1 5] [x + 1 5] \end{verbatim} This requires a little explanation: the command \kbd{mfatkininit(mf,3)} computes a number of quantities necessary to work with the Atkin--Lehner operator $W_3$ in the space \kbd{mf}. The main part of the result is the second component, which is essentially the matrix of $W_3$ on the basis of \kbd{mf}, and which is guaranteed to have exact coefficients (here rational). However in the general case, the matrix of $W_3$ is equal to \kbd{mfatk[2]/mfatk[3]}, where \kbd{mfatk[3]} may be an inexact complex number. For now you need not worry about the first component. Thus, the eigenvalues (or possibly the pseudo-eigenvalues) must be of modulus $1$, and in the case of a quadratic character defined modulo $N/Q$, they are equal to $\pm1$ in even weight, to $\pm i$ in odd weight. Here, $1$ and $-1$ both occur $5$ times. However, this does not tell us which eigenvalues correspond to each eigenspace. For this, we do the following: \begin{verbatim} ? mfatkineigenvalues(mf,3) % = [[-1], [-1], [-1], [1], [1], [1], [-1, -1], [1, 1]] ? mf=minit([96,3,-3],0); mffields(mf) % = [y^4 + 8*y^2 + 9, y^4 + 4*y^2 + 1] ? mfatkineigenvalues(mf,32) % = [[I, -I, -I, I], [-I, I, I, -I]] ? mfatkineigenvalues(mf,3) % = [[a, -conj(a), -a, conj(a)], [b, -conj(b), conj(b), -b]] \end{verbatim} The first command tells us that in the six rational eigenspaces, the first three have eigenvalue $-1$, the other three $+1$, and in the eigenspaces of dimension $2$, the first eigenspace has both eigenvalues $-1$, the second both $+1$. As is seen from the next lines, it is of course not necessary for the eigenvalues of $W_Q$ in the same eigenspace to be equal. In the next two commands, we are now in a case where the character is non trivial and the weight odd. The eigenvalues are now $\pm i$, and not equal in the same eigenspace. Finally, the last command is a case where the character is not defined modulo $N/Q=96/3=32$, so we only have pseudoeigenvalues, which are simply of absolute value $1$ by Atkin--Lehner theory. Here, $a$ and $b$ are complicated complex numbers and \kbd{conj} denotes the complex conjugate (using the \kbd{algdep} command, one can check that $a$ is a root of $9x^4+10x^2+9=0$ and $b$ is a root of $3x^4-2x^2+3=0$. Note that when the character is (trivial or) quadratic and defined modulo $N/Q$ the output is always rounded, but otherwise, the eigenvalues are given as approximate complex numbers. As for the Hecke operators, there exists an \kbd{mfatkin} command, whose syntax is \kbd{mfatkin(mfatk, F)}, where \kbd{mfatk} is the output of an \kbd{mfatkininit} command and $F$ is in the space \kbd{mfatk}, and which outputs the modular form $F|_kW_Q$, where $Q$ is implicit in \kbd{mfatk}. Finally note the \kbd{mfbd} expanding command which computes $B(d)F$: \begin{verbatim} ? E4 = mfEk(4); mfcoefs(E4,6) % = [1, 240, 2160, 6720, 17520, 30240, 60480] ? F = mfbd(E4,2); mfcoefs(F,6) % = [1, 0, 240, 0, 2160, 0, 6720] \end{verbatim} \section{Algebraic Functions on Modular Forms} Here we give examples of functions on modular forms which do not involve any approximate numerical computation. We have already mentioned the most important ones: \kbd{mfhecke}, \kbd{mfatkin}, and \kbd{mfbd}. \begin{verbatim} ? E4 = mfEk(4); F = mfderivE2(E4); mfcoefs(F,5) % = [-1/3, 168, 5544, 40992, 177576, 525168] ? E6 = mfEk(6); mfisequal(F, mflinear([E6], [-1/3])) % = 1 ? G = mfbracket(E4, E6, 1); mfcoefs(G,5) % = [0, -3456, 82944, -870912, 5087232, -16692480] ? mfisequal(G, mflinear([mfDelta()], [-3456])) % = 1 \end{verbatim} \medskip In the first commands, we compute the Serre derivative of $E_4$, and check that it is equal to $-E_6/3$. The name \kbd{mfderivE2} of course comes from the fact that the Serre derivative involves the quasi-modular Eisenstein series $E_2$. Note that there exists the function \kbd{mfderiv} (including to negative order, corresponding to integration), which is provided for the user's convenience for certain computations, but whose output is outside the range of modular forms. The second computation checks that the first Rankin--Cohen bracket of $E_4$ and $E_6$ is a multiple of $\Delta$. You may complain that it is heavy to write an \kbd{mflinear} command as above simply to compute a scalar multiple of a form. But nothing prevents you from defining in a script that you read at the beginning of your session: \begin{verbatim} mfscalmul(F,s)=mflinear([F],[s]); mfadd(F,G)=mflinear([F,G],[1,1]); mfsub(F,G)=mflinear([F,G],[1,-1]); \end{verbatim} There also exist the natural operations on modular forms \kbd{mfmul}, \kbd{mfdiv} (which may result in modular functions, i.e., with poles), and \kbd{mfpow}. There is also a function \kbd{mfshift} (multiply or divide by a power of $q$), but which again takes us outside the range of modular forms. \begin{verbatim} ? E4 = mfEk(4); F = mftwist(E4, -3); mfcoefs(F, 7) % = [0, 240, -2160, 0, 17520, -30240, 0, 82560] ? mfparams(F) % = [9, 4, 1, y] ? mf = mfinit([4,5,-4], 1); F = mfbasis(mf)[1]; mfcoefs(F, 10) % = [0, 1, -4, 0, 16, -14, 0, 0, -64, 81, 56] ? mfisCM(F) % = -4 ? G = mftwist(F, -4); mfcoefs(G, 10) % = [0, 1, 0, 0, 0, -14, 0, 0, 0, 81, 0] ? mfparams(G) % = [16, 5, -4, y] ? mfconductor(mfinit(G, 1), G) % = 8 \end{verbatim} This session illustrates a number of important issues concerning \emph{twisting}. In the first commands, we twist $E_4$ by the quadratic character $-3$ (in the present implementation, only twisting by quadratic characters is allowed), and we see that the resulting form has level $9=(-3)^2$. Fine. In the next command, we compute the unique form in $S_4(\G_0(5),\chi_{-4})$, and see that it has CM by $\Q(\sqrt{-4})$. However, note that the form is not equal to the form twisted by the character $\chi_{-4}$ (only the coefficients of $q^n$ with $n$ prime to $4$ are equal, the others vanish). The \kbd{mfparams} command tells us that the twisted form has level $16=(-4)^2$. However, the final command tells us that in fact it has level $8$: \kbd{mfconductor} gives the smallest level on which the form is defined. \begin{verbatim} ? mf = mfinit([96,2], 1); L = mfbasis(mf); ? apply(x->mfconductor(mf,x), L) % = [24, 48, 96, 32, 96, 48, 96, 96, 96] ? apply(x->mftonew(mf,x)[1][1..2], L) % = [[24, 1], [24, 2], [24, 4], [32, 1], [32, 3],\ [48, 1], [48, 2], [96, 1], [96, 1]] \end{verbatim} Here we compute the full cuspidal space $S_2(\G_0(96))$, of dimension $9$, and we ask which is the lowest level on which each form in the basis is defined. This list shows that there is one form $F_1$ in level $24$ which, by applying $B(d)$ with $d=2$ and $d=4$ gives a form of level $48$ and one of level $96$. Then a form $F_2$ in level $32$, by applying $B(3)$ gives a form of level $96$, a form $F_3$ in level $48$, by applying $B(2)$ gives a form of level $96$, and finally two genuine forms of level $96$ (so that the dimension of the newspace is equal to $2$, which we can check by typing \kbd{mfdim([96,2],0)}). The last command \kbd{mftonew} checks all this; look at the precise description of the command. \section{Cusps and Cosets} Recall that in the present version of the package, the only congruence subgroup that is considered is $\G_0(N)$, so when we consider cusps in the geometrical sense, they are cusps of $\G_0(N)$, and cosets are right cosets of $\G_0(N)$ in $\G$, so that $\G=\bigsqcup_j\G_0(N)\ga_j$. The function \kbd{mfcusps(N)} gives the list of all (equivalence classes of) cusps of $\G_0(N)$, \kbd{mfcuspwidth(N,cusp)} gives the width of the cusp; these are linked to the \emph{geometry}. On the other hand, the notion of \emph{regularity} of a cusp is linked to the specific modular form space, and the function \kbd{mfcuspisregular([N,k,CHI],cusp)} determines if the cusp is regular or not: \begin{verbatim} ? C = mfcusps(108) % = [0, 1/2, 1/3, 2/3, 1/4, 1/6, 5/6, 1/9, 2/9, 1/12,\ 5/12, 1/18, 5/18, 1/27, 1/36, 5/36, 1/54, 1/108] ? [mfcuspwidth(108,c) | c<-C] % = [108, 27, 12, 12, 27, 3, 3, 4, 4, 3, 3, 1, 1, 4,\ 1, 1, 1, 1] ? NK = [108,3,-4]; ? [mfcuspisregular(NK,c) | c<-C] % = [1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1] ? [c | c<-C, !mfcuspisregular(NK,c)] % = [1/2, 1/6, 5/6, 1/18, 5/18, 1/54] \end{verbatim} The first command list the $18$ cusps of $\G_0(108)$ (\kbd{mfnumcusps(108)} gives this directly, useful if there are thousands of cusps and you do not want them explicitly), the second command prints their widths, and the last commands show that the cusps $1/2$, $1/6$, $5/6$, $1/18$, $5/18$, and $1/54$ are irregular in the space $M_3(\G_0(108),\chi_{-4})$, and the others are regular. There is another command \kbd{mfcuspval} having to do with cusps, but this will be mentioned later. \medskip \begin{verbatim} ? C = mfcosets(4) % = [[0, -1; 1, 0], [1, 0; 1, 1], [0, -1; 1, 2],\ [0, -1; 1, 3], [1, 0; 2, 1], [1, 0; 4, 1]] ? mftocoset(4, [1, 1; 2, 3], C) % = [[-1, 1; -4, 3], 5] \end{verbatim} The \kbd{mfcosets(N)} command lists all right cosets of $\G_0(N)$ in $\G$. Note that in the present implementation the trivial coset is always the last one, and is represented by the matrix $[1,0;N,1]$, but since this may change one must be careful. The \kbd{mftocoset(N,M,C)} command gives a two-component vector $[\ga,i]$, where $\ga\in\G_0(N)$ is such that $M=\ga\cdot C[i]$. \section{The mfslashexpansion command} We now give examples of the use of advanced features of the package, which use inexact complex arithmetic. However in many cases the results are known algebraic numbers and, if asked to do so, the function gives them exactly. This command returns the Fourier expansion at infinity of $f |_k \gamma$, for $\gamma\in \GL_2(\Q)^+$. It returns a vector $v$ of coefficients, which can only be interpreted together with three extra parameters $\al\in \Q_{\geq 0}$, $w \in \Z_{\geq 1}$ and a $2\times 2$ upper triangular matrix $A=[a,b;0,d]$ (equal to the identity if $\gamma\in\PSL_2(\Z)$). We have $f |_k \gamma = F |_k A $, with $$F(\tau) = q^\al \sum_{n\geq 0} v[n] q^{n/w}$$ and $q = e(\tau)$. Of course, $F |_k A = (a/d)^{k/2} F(\tau + b/d)$ so the exact expansion is easily inferred from the returned one, whereas the chosen encoding allows to compute the coefficients $v[n]$ in a smaller number field than if we had included all the constants into $v$. It is important to note that the three parameters $\al, w, A$ only depend on the modular form space and $\gamma$, but not on the form $f$. \begin{verbatim} ? mf = mfinit([4,6]); B = mfbasis(mf); ? for (i=1, #B, \ print( mfslashexpansion(mf,B[i],[1,0;2,1],5,1,&P) )) \\ we don't print P which is [0, 1, [1,0;0,1]] in all cases [-1/504, 1, 33, 244, 1057, 3126] [-1/504, 0, 1, 0, 33, 0] [-1/32256, -1/64, 33/64, -61/16, 1057/64, -1563/32] [0, -1, 0, 12, 0, -54] ? R = mfslashexpansion(mf,B[1],[0,-1;4,0],5,1,&P); [P,R] % = [[0, 1, [1,0;0,1]], [-8/63, 0, 0, 0, 64, 0]] ? R = mfslashexpansion(mf,B[1],[0,-1;1,0],5,1,&P); [P,R] % = [[0, 4, [1,0;0,1]], [-1/504, 0, 0, 0, 1, 0]] ? mf=mfinit([4,7,-4]); B=mfbasis(mf); ? for (i=1, #B, \ print( mfslashexpansion(mf,B[i],[1,0;2,1],5,1,&P) )) \\ we don't print P which is [1/2, 1, [1,0;0,1]] in all cases [1/64, 91/8, 7813/32, 7353/4, 530713/64, 221445/8] [1, -728, 15626, -117648, 530713, -1771560] [1/16, -15/2, 5/8, 75, -231/16, -465/2] [2, 0, 20, 0, -462, 0] ? mfslashexpansion(mf,B[1],[0,-1;4,0],5,1,&P) % = [Mod(61/256*t, t^2 + 1), Mod(-1/64*t, t^2 + 1), Mod(-1/64*t, t^2 + 1), Mod(91/8*t, t^2 + 1), Mod(-1/64*t, t^2 + 1), Mod(-7813/32*t, t^2 + 1)] ? P % = [0, 1, [1, 0; 0, 1]] ? R=mfslashexpansion(mf,B[1],[0,-1;4,0],5,0) % = [0.23828125000000000000000000000000000000*I,\ -0.015625000000000000000000000000000000000*I,\ -0.015625000000000000000000000000000000000*I,\ 11.375000000000000000000000000000000000*I,\ -0.015625000000000000000000000000000000000*I,\ -244.15625000000000000000000000000000000*I] ? bestappr(R) % = [61/256*I, -1/64*I, -1/64*I, 91/8*I, -1/64*I, -7813/32*I] \end{verbatim} Here are some detailed explanations. The first space is $M_6(\G_0(4))$, of dimension $4$. We ask for $1+5$ terms of the Fourier expansion of $F|_6\ga$ for all $F$ in the given basis, and $\ga=[1,0;2,1]$, which is one of the possible Fourier expansions at the cusp $1/2$. The last parameter $P$ contains $[\al,w,A]$ after the call and the $1$ means we want an exact algebraic expression (a $0$ as used in the last example means we expect floating point complex numbers). We obtain the $4$ desired expansions. In the next commands, we do the same for the first basis element and $\ga=[0,-1;4,0]$, which is the \emph{Fricke involution}, and corresponds to the cusp $0$. The next command, which does essentially the same computation, uses $\ga=[0,-1;1,0]$, and now $P=[0,4, [1,0;0,1]]$ which tells us that the expansion is in powers of $q^{1/4}$. The next example is the space $M_7(\G_0(4),\chi_{-4})$, also of dimension $4$, and we ask the same thing. Now $P$ tells us that $\al = 1/2$ and $w = 1$ so we now have for instance $$B[1]|_7\ga = (1/64)q^{1/2} + (91/8)q^{3/2}+\cdots$$ In the next command, we expand $B[1]|_7\ga$ with $\ga$ equal to the Fricke involution; and finally we check numerically by setting the one-to-last parameter to $0$ and obtain the expansion as raw complex numbers. We recognize them immediately using the \kbd{bestappr} command. Note that in the special case (like here) where $\ga$ is a Fricke (or more generally an Atkin--Lehner) involution, we can proceed otherwise to obtain the expansion: \begin{verbatim} ? mfatk = mfatkininit(mf,4); C = mfatk[3] % = -1.000000000000000000000000000*I ? F = mfatkin(mfatk, B[1]); mfcoefs(F, 6) % = [61/256, -1/64, -1/64, 91/8, -1/64, -7813/32, 91/8] \end{verbatim} This tells us that the true expansion of $F|_7W_4$ is the expansion that is output divided by the constant $C$, so we recover the previous expansion. \smallskip It is important to see what affects the timing and correctness of the \kbd{mfslashexpansion} command. The following session gives typical examples: \begin{verbatim} ? mf = mfinit([496,4],0); F = mfbasis(mf)[1]; mfdim(mf) time = 329 ms. % = 45 ? mfslashexpansion(mf,F,[1,0;3,1],5,0,&P); time = 1,316 ms. ? mfslashexpansion(mf,F,[1,0;3,1],5,1,&P); time = 51,136 ms. ? mf = mfinit([503,4],0); F = mfbasis(mf)[1]; mfdim(mf) time = 1,505 ms. % = 125 ? sizebyte(mf) % = 5123352 ? mfslashexpansion(mf,F,[1,0;3,1],5,0,&P); time = 32,640 ms. ? sizebyte(mf) % = 18216400 ? mfslashexpansion(mf,F,[1,0;3,1],5,0,&P); time = 6,504 ms. \end{verbatim} We omit the numerical outputs since they have no significance for the present discussion. We notice several things: \begin{itemize} \item First, the time for rationalization (flag $1$) in the first example is extremely large: $51$ seconds instead of $1.3$. The reason for this is that the width of the corresponding cusp (here $1/3$) is equal to $P[2]=496$, and the program must recognize algebraic numbers in the large cyclotomic field $\Q(\zeta_{496})$ which takes a huge amount of time. In fact, at the default accuracy of $38D$, the result is certainly wrong. \item Second, the time depends enormously on the dimension: the expansion for dimension $125$ is $25$ times slower than for dimension $45$, of course not surprising, but it must be taken into account. \item Third, and most importantly, the last command shows the cache effect: exactly the same instruction now requires only $6.5$ seconds instead of $32.6$. This is because, behind the scenes, the first \kbd{mfslashexpansion} precomputed a number of quantities which it stored in your variable \kbd{mf}: in fact, the \kbd{sizebyte} commands show that, after the first expansion, the size of \kbd{mf} has more than tripled. \end{itemize} \section{Analytic Commands} The existence of the \kbd{mfslashexpansion} command allows us to do many useful things. In fact, already the \kbd{mfatkininit} and \kbd{mfatkin} commands would not be possible without it. Immediate applications are the \kbd{mfcuspval} command which computes the valuation at cusps, and the \kbd{mfeval} command, which in addition to computing values in the upper-half plane (see below), also computes values at the cusps: \begin{verbatim} ? T = mfTheta(); mf=mfinit(T);C=mfcusps(mf) % = [0, 1/2, 1/4] ? [ mfcuspval(mf,T,c) | c<-C ] % = [0, 1/4, 0] ? mfeval(mf, T, C) \\ or [mfeval(mf,T,c) | c<-C] % = [1/2 - 1/2*I, 0, 1] \end{verbatim} More sophisticated is the computation of numerical periods, and more generally of \emph{symbols} $$\int_{s_1}^{s_2}(X-\tau)^{k-2}F|_k\ga(\tau)\,d\tau\;,$$ where $s_1$ and $s_2$ are two cusps (e.g., $s_1=0$, $s_2=\infty$): \begin{verbatim} ? mf = mfinit([96,4],0); [F1] = mfbasis(mf); ? FS1 = mfsymbol(mf,F1); time = 2,272 ms ? mfsymboleval(FS1,[0,oo]) % = 2.0968669678226579060336519703627002478*I*x^2\ + 0.36368580656317635568444277442842940073*x\ - 0.049315736834713109138297211986510643780*I ? mfsymboleval(FS1,[1,5/2]) % = 4.1937339356453158120673039407254004956*I*x^2\ + (0.72737161312635271136888554885685880147\ - 14.678068774758605342235563792538901735*I)*x\ + (-1.2729003229711172448955497104995029026\ + 15.103654043044843600467382361156555509*I) ? mfsymboleval(FS1,[1,2],[0,-1;1,0]) % = (0.54552870984476453352666416164264410111\ + 2.5224522361088961642654705389803540222*I)*x^2\ + (-0.72737161312635271136888554885685880148\ - 6.2906009034679737181009559110881007434*I)*x\ + 4.1937339356453158120673039407254004956*I \end{verbatim} The general strategy for computing these quantities is first to do a precomputation which only involves \kbd{mf} and the form $F$ using \kbd{mfsymbol}, which can take a few seconds, but afterwards all the computations are instantaneous. Note that if you only want the period polynomial from $0$ to $\infty$ use \kbd{mfperiodpol(mf,F1)} which gives the same answer as before but in only $20$ ms. You may also use \kbd{mfsymboleval} in two other ways, but note that in this case the precomputation is not used so the computation may be slow: \begin{verbatim} ? mf=mfinit([96,6],0);F=mfbasis(mf)[1]; ? FS=mfsymbol(mf,F); time = 9,761 ms. ? mfsymboleval(FS,[I,oo]) % = 0.0029721...*I*x^4 + 0.0137806...*x^3 + ... + 0.0061009... ? mfsymboleval(FS,[I,2*I]) % = 0.0029665...*I*x^4 + 0.0137326...*x^3 + ... + 0.0059760... ? mfsymboleval(FS,[I/10000,I]) % = 46.363730...*I*x^4 + 3.8815894...*x^3 + ... + 0.0183869... ? -x^4*subst(mfsymboleval(FS,[I,10000*I],[0,-1;1,0]),x,-1/x) % = 46.363730...*I*x^4 + 3.8815894...*x^3 + ... + 0.0183869... ? mfsymboleval([mf,F],[I,oo]) % = 0.0029721...*I*x^4 + 0.0137806...*x^3 + ... + 0.0061009... ? mfsymboleval([mf,F],[I,2*I]) % = 0.0029665...*I*x^4 + 0.0137326...*x^3 + ... + 0.0059760... \end{verbatim} These examples illustrate four points: \begin{enumerate}\item Computing an \kbd{mfsymbol} may be rather long ($9.8$ seconds in this example), although as already mentioned, subsequent computations of symbols \emph{between cusps} will then be instantaneous. \item As the next three commands show, \kbd{mfsymboleval} also accepts paths with endpoints in the upper half-plane. Although we have tried to optimize the computation, in certain cases (but not in the above example) when one of the endpoints is close to the real line the computation may be slow. \item The next command shows the use of the extra parameter $\ga$ which asks to integrate $F|_k\ga$ instead of $F$, here with \kbd{ga=[0,-1;1,0]}. This allows to perform the same computation with endpoints which are away from the real line. This is essentially what is done \emph{automatically} by \kbd{mfsymboleval}. \item The last two commands show a special format which avoids doing the longish \kbd{mfsymbol} computation: the results are obtained almost instantaneously \emph{without} using symbols. The price to pay in using this ``cheaper'' format is that the endpoints of the path cannot be cusps other than \kbd{oo}. \end{enumerate} \begin{verbatim} ? mf = mfinit([96,4],0); [F1,F2] = mfbasis(mf); ? FS1 = mfsymbol(mf,F1); FS2 = mfsymbol(mf,F2); ? mfpetersson(FS1) % = 0.00061471684149817788924091516302517391826 ? mfpetersson(FS2) % = 0.0055324515734836010031682364672265652647 ? mfpetersson(FS1, FS2) % = 1.5879887877319313665 E-40 + 7.652958013165934297 E-42*I \end{verbatim} Same remark: once the \kbd{mfsymbols} \kbd{FS1} and \kbd{FS2} initialized, all the Petersson product computations (as well as others) are essentially immediate. Note that since neither \kbd{F1} nor \kbd{F2} are eigenforms, there is no reason for their Petersson product to vanish. To prove it does we do as follows: \begin{verbatim} ? BE = mfeigenbasis(mf); ? M = Mat([mftobasis(mf,f) | f<-BE]); M^(-1) % = [1 3 10 4 -20 70] [1 3 2 12 60 -42] [1 3 -14 -36 -36 54] [1 -3 10 -4 20 70] [1 -3 2 -12 -60 -42] [1 -3 -14 36 36 54] \end{verbatim} On the other hand, it is immediate to see that \kbd{BE[i+3]} is a twist of \kbd{BE[i]} and that as a consequence their Petersson square are equal. It follows from the shape of the above matrix that the Petersson scalar product of $B[i]$ with $B[j]$ will vanish when the corresponding scalar product of the corresponding columns vanish, hence for $(i,j)=(1,2)$, $(1,4)$, $(1,5)$, $(2,3)$, $(2,6)$, $(3,4)$, $(3,5)$, $(4,6)$, and $(5,6)$. \smallskip Note that \kbd{mfpetersson} can also be used for two noncuspidal forms, as long as the Petersson product converges. Consider the following example: \begin{verbatim} ? mf = mfinit([12,5,-3]); cusps = mfcusps(mf); ? E1 = mfeisenstein(5,1,-3); [mfcuspval(mf,E1,c) | c<-cusps] % = [0, 0, 1, 0, 1, 1] ? E2 = mfeisenstein(5,-3,1); [mfcuspval(mf,E2,c) | c<-cusps] % = [1/3, 1/3, 0, 1/3, 0, 0] ? P(mf) = { my(E1S = mfsymbol(mf,E1)); my(E2S = mfsymbol(mf,E2)); mfpetersson(E1S,E2S); } ? P(mf) % = -1.8848216716468969562647734582232071466 E-5\ - 1.9057659114817512165 E-43*I ? mf3 = mfinit([3,5,-3]); P(mf3) time = 16 ms. ? mf96 = mfinit([96,5,-3]); P(mf96) time = 3,521 ms. \end{verbatim} The first commands create two Eisenstein series of weight $5$, $E_5(1,\chi_{-3})$ and $E_5(\chi_{-3},1)$, which belong to $M_5(\G_0(3),\chi_{-3})$. In the next commands, we look at the larger space of level $12$ and compute the valuations of $E_1$ and $E_2$ at the six cusps of $\G_0(12)$. We see that at these six cusps one of the two Eisenstein series vanishes, so the Petersson product will converge, and is computed in the next command. In the last commands we compute the same product but in level $3$ and level $96$; because of the normalization, we obtain essentially the same result (not given), but of course the times are very different: $0.016$ seconds in level $3$ and $3.5$ seconds in level $96$. \medskip There are two more important numerical functions: evaluating a modular form at a point in the upper half plane, and evaluating the corresponding $L$-function. We begin by a trivial example: \begin{verbatim} ? E4 = mfEk(4); mf = mfinit(E4); mfeval(mf,E4,I) % = 1.4557628922687093224624220035988692874 ? 3*gamma(1/4)^8/(2*Pi)^6 % = 1.4557628922687093224624220035988692874 \end{verbatim} This is of course a trivial computation, simply sum the $q$-expansion. The fact that the value of a modular form with rational coefficients such as $E_4$ at a \emph{CM point} such as $i$ has an explicit expression is a consequence of complex multiplication. \begin{verbatim} ? mf = mfinit([12,4],1); F = mfbasis(mf)[1]; ? mfeval(mf, F, 1/Pi + 10^(-6)*I) % = -89811.049350396250531782882568405506024\ - 58409.940965200894541585402642924371696*I ? mfeval(mf, F, 1/Pi + 10^(-7)*I) % = 4.8212468504661113183253396691813292261 E-52\ + 6.7885262281520647908871247541561415340 E-52*I \end{verbatim} Several remarks are in order. \begin{enumerate} \item We are evaluating a modular form very near the real axis. If the form was in level $1$ such as $E_4$ above, we could use a modular transformation to reduce to the evaluation in the fundamental domain of $\G$, which would be very fast. Here we do something similar but more sophisticated. \item Contrary to most examples, the result at height $10^{-7}$ is not a numerical approximation of $0$, the exact value is indeed as printed to the given accuracy. \item It is amusing to see the large oscillations of the value: at height $10^{-6}$ the value is still in the $10^5$ range, and at $10^{-7}$ it is in the $10^{-52}$ range. Of course it must eventually tend to $0$ since $F$ is a cusp form (for $E_4$ it would tend to infinity). \item When applying \kbd{mfeval} at a \emph{cusp} (as above for \kbd{mfTheta()}), the result is the value at the cusp, but is in general \emph{not} equal to the limit of the value of the modular form when the argument tends to the cusp, since this limit is often infinite for a non-cusp form. \end{enumerate} Note that when dealing with \emph{eigenforms}, which may have several embeddings into $\C$, the result will have several components, one for each embedding: \begin{verbatim} ? mf = mfinit([23,2],0); F=mfeigenbasis(mf)[1]; ? mfeval(mf,F,I) % = [0.0018695834459685012330841605500720163964,\ 0.0018618146628840767703527958851699552194] \end{verbatim} More generally, this embedding problem affects all numerical functions. Continuing the above example: \begin{verbatim} ? mfparams(F) % = [23, 2, 1, y^2 - y - 1] ? mfslashexpansion(mf,F,[0,-1;1,0],5,1) % = [0, -1/23, 1/23*y, -2/23*y + 1/23, -1/23*y + 1/23, 2/23*y] ? FS = mfsymbol(mf,F); mfpetersson(FS,FS) % = [0.00394889657400250316885... -1.0827196147167250830 E-40] [-1.2120247024777595243 E-40 0.00564425429876478351015...] \end{verbatim} The $y$ in the second result is thus understood to be \emph{one} of the roots of the polynomial $y^2-y-1$, and the result of \kbd{mfpetersson} is a $2\times 2$ \emph{diagonal} matrix because of the two embeddings of $F$. \smallskip The other important evaluation function is that of the $L$-function attached to a modular form. In fact, the modular form package only creates (in a clever way) the $L$-function, all the rest of the work is done by the $L$-function package. Note the important fact that the modular form need not be an eigenform or even stable under the Fricke involution. \begin{verbatim} ? E4 = mfEk(4); mf=mfinit(E4); LE = lfunmf(mf,E4); ? lfun(LE, 2) / Pi^2 % = -3.3333333333333333333333333333333333333 ? lfun(LE, 0) % -1 ? D = mfDelta(); mf=mfinit(D); LD = lfunmf(mf,D); ? lfunlambda(LD, 3)/lfunlambda(LD, 5) % = 1.5555555555555555555555555555555555556 ? lfunlambda(LD, 1)/lfunlambda(LD, 3) % = 2.3444283646888567293777134587554269175 ? bestappr(%) % = 1620/691 ? mf = mfinit([23,2],0); F = mfbasis(mf)[1]; L = lfunmf(mf,F); ? lfun(L, 2) % = 1.5959983753450272580976413437480171832 ? G = mfeigenbasis(mf)[1]; M = lfunmf(mf,G); ? apply(x->lfun(x,I),M) % = [-0.15856033373254740657327844579672155664\ + 0.79671369922504818377602680344686311969*I,\ -0.10230278816509023908993775663030712037\ + 0.65954223983092583287784522268295299513*I] \end{verbatim} Note that the constant term $a(0)$ is ignored by the $L$-function, but can be recovered thanks to the formula $a(0)=-L(F,0)$. The last commands illustrate first the fact that the $L$-functions can be computed for non-eigenforms ($F$ is not an eigenform), and second that if there are several embeddings, the \kbd{lfunmf} function returns a vector of \kbd{lfunmf}, one for each embedding. Another illustration of the $L$-function package: \begin{verbatim} ? LIN = lfuninit(LD, [6, 6, 50]); ? ploth(t = 0, 50, lfunhardy(LIN, t)) \end{verbatim} %\includegraphics[width=\textwidth]{pari3.pdf} \medskip \section{The mfeigensearch and mfsearch commands} The last commands that we want to illustrate are \emph{searching} commands, The idea is simple: you believe that you have a modular form, but you do not know its level, weight, character, or field of definition of its coefficients, but only a number of its Fourier coefficients, perhaps only modulo $p$, and you would like to find forms which ``match'' your given form. In this degree of generality, the search space is too wide. We have therefore decided to reduce the generality, so as to make the search more reasonable. Note that this will probably vary with the different versions of the program, so what is described here may be more restrictive than future versions. In the present implementation, we assume that the form we are looking for has rational coefficients, so that its character is (trivial or) quadratic. The \kbd{mfsearch} command does this naively but is likely to be more efficient than taylor-made scripts: \begin{verbatim} ? V = mfsearch([60,2],[0,1,2,3,4,5,6], 1); #V time = 5 ms. % = 3 ? V = mfsearch([[1..60],2],[0,1,2,3,4,5,6], 1); #V time = 40 ms. % = 5 ? [ mfparams(f) | f<-V ] % = [[56, 2, 8, y], [58, 2, 1, y], [60, 2, 1, y], [60, 2, 12, y], [60, 2, 60, y]] ? [ print(mfcoefs(f,10)) | f<-V ] [0, 1, 2, 3, 4, 5, 6, -6, -4, -7, -20] [0, 1, 2, 3, 4, 5, 6, -34, 37, 22, 7] [0, 1, 2, 3, 4, 5, 6, 20, 0, -27, -6] [0, 1, 2, 3, 4, 5, 6, -170/9, -272/9, -11/3, -134/9] [0, 1, 2, 3, 4, 5, 6, 200/13, -304/13, -435/13, -278/13] \end{verbatim} This command looks for all forms, first in level $60$ then in level $1$ to $60$ and weight $2$ whose first coefficients are $[0,1,2,3,4,5,6]$, the final $1$ is optional and specifies the \emph{space} (in \kbd{mfinit} sense) where the search is performed, here the cuspidal space (by default the full space). It returns a list of $3$ forms in level $60$ and $5$ in total. The \kbd{mfeigensearch} command is more interesting. We look for is a cuspidal \emph{eigenform} whose field of definition is $\Q$, so that its Fourier coefficients are integers, and its character is (trivial or) quadratic. An example is as follows: \begin{verbatim} ? AP = [[2,2], [3,-1]] \\ a(2) = 2 and a(3) = -1 ? L = mfeigensearch([[1..120],4], AP); #L % = 2 ? [f,g] = L; [mfparams(f), mfparams(g)] % = [[26, 4, 1, y], [118, 4, 1, y]] ? mfcoefs(f, 10) % = [0, 1, 2, -1, 4, 17, -2, -35, 8, -26, 34] ? mfcoefs(g, 10) % = [0, 1, 2, -1, 4, -13, -2, -27, 8, -26, -26] \end{verbatim} The first command asks for all forms as above in weight $4$ and level from $1$ up to $120$, such that $a(2)=2$ and $a(3)=-1$. The answer is that there are two forms, which we call $f$ and $g$. We compute their levels ($26$ and $118$ respectively), notice they have trivial character, and list their Fourier coefficients up to $10$ and we see that indeed $a(2)=2$ and $a(3)=-1$ in both cases. To specify the coefficients that we want there are a number of ways. The simplest, as above, is to give the list of pairs of integers $[p,a(p)]$. For instance: \begin{verbatim} ? L = mfeigensearch([[1..80],2], [[2,2], [7,-3]]); #L % = 1 ? F = L[1]; mfparams(F) % = [75, 2, 1, y] ? mfcoefs(F, 12) % = [0, 1, 2, -1, 2, 0, -2, -3, 0, 1, 0, 2, -2] \end{verbatim} The coefficient $a(p)$ may also be given as an \kbd{intmod} \kbd{Mod}$(a,m)$ then one looks for a match for $a(p)$ modulo $m$. For instance, we come back to our first example: \begin{verbatim} ? AP5 = [[2,Mod(2,5)], [3,Mod(-1,5)]]; \\ now modulo 5 ? L=mfeigensearch([[1..120], 4], AP); #L % = 3 ? [ mfparams(f)[1] | f <- L ] % = [26, 26, 118] ? [F1,F2] = L; \\ let's consider the first two ? mfcoefs(F1, 10) % = [0, 1, 2, -1, 4, 17, -2, -35, 8, -26, 34] ? mfcoefs(F2, 10) % = [0, 1, 2, 4, 4, -18, 8, 20, 8, -11, -36] ? F = mflinear([F1, F2], [-1, 1]); ? content(mfcoefs(F, mfsturm([26,4])+1)) % = 5 \end{verbatim} Working modulo $5$, we now find that there is an extra eigenform satisfying our criteria, and perhaps surprisingly, again in level $26$. The first, \kbd{F1}, is the one found above, with $a(2)=2$ and $a(3)=-1$. The second, \kbd{F2}, has $a(2)=2$ but $a(3)=4\equiv-1\pmod5$. But we can go further and see that this is not a simple coincidence: the next command shows that both eigenforms seem to be congruent modulo $5$, at least up to $a(10)$. In fact they are indeed congruent modulo $5$: to prove this, we use the fact that the basic Sturm bound (the one obtained using \kbd{mfsturm([N,k])}, not \kbd{mfsturm(mf)}) is also valid modulo $p$. Since all coefficients are congruent up to the Sturm bound, they are congruent for all $n$. \section{Half-Integral Weight Functions} \subsection{General Functions} Many of the commands that we have seen, and most importantly the \kbd{mfinit} and \kbd{mfdim} command, can be used verbatim in the case of modular forms of half-integral weight, sometimes with small differences. \begin{itemize} \item Two functions created from mathematical objects can give forms of half-integral weight, \kbd{mfetaquo} and \kbd{mffromqf}. \item Leaf functions created from scratch are \kbd{mfTheta}, which gives the standard Jacobi theta function of weight $1/2$, and \kbd{mfEH}, which gives the Cohen--Hurwitz Eisenstein series of half-integral weight. \end{itemize} \begin{verbatim} ? F = mffrometaquo([2,5;1,-2;4,-2]); Ser(mfcoefs(F,10),q) % = 1 + 2*q + 2*q^4 + 2*q^9 + O(q^11) ? T = mfTheta(); mfisequal(F,T) % = 1 ? F = mffromqf(2*matid(3))[2]; Ser(mfcoefs(F,5),q) % = 1 + 6*q + 12*q^2 + 8*q^3 + 6*q^4 + 24*q^5 + O(q^6) ? mfisequal(F, mfpow(T,3)) % = 1 \end{verbatim} \begin{itemize}\item The only spaces which are \emph{directly} available by \kbd{mfinit} and \kbd{mfdim} are the full cuspidal space and the full modular form space. The new space can be defined in some cases but indirectly, using Kohnen's theory, see below. \item The only Hecke operators $T(n)$ which are nonzero are those where $n$ is a square (we have not programmed the $T(p)$ with $p$ dividing the level). \end{itemize} \subsection{Specific Functions} The most important specific function in half-integral weight is \kbd{mfshimura}, which computes the Shimura lift corresponding to a discriminant $D$ (1 by default) and also returns an \kbd{mf} space containing the lift: \begin{verbatim} ? mf=mfinit([60,5/2],1); F=mfbasis(mf)[1]; ? D = [1,5,8,12,13,17,21]; ? for (i=1, #D, \ [mf2,G] = mfshimura(mf,F,D[i]); print(mfcoefs(G,10))) [0, 1, 2, 0, 2, -1, -2, 6, 6, -3, -10] [0, 0, 0, -1, 0, 0, 20, 0, 0, -2, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 24, 0, 0, 0, 0, -48] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 1, 0, 3, 52, -5, -120, 14, -156, 3, 0] ? mfdescribe(mf) % = "S_5/2(G_0(60, 1))" ? mfdescribe(mf2) % = "S_4(G_0(30, 1))" \end{verbatim} Two things to notice: first the image can be identically $0$. Second, the program takes some time (20 seconds for the above), because computing a Shimura image takes time proportional to $D^4$. \smallskip The other specific functions are related to the Kohnen $+$-space. Continuing the above example: \begin{verbatim} ? K=mfkohnenbasis(mf); matsize(K) % = [14, 4] ? K[,1] % = [-1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]~ ? F=mflinear(mf,K[,1]); ? Ser(mfcoefs(F,35),q) % = -q + 2*q^4 - 4*q^16 + 3*q^21 - 6*q^24 + 5*q^25 + O(q^36) \end{verbatim} The first command shows that although the dimension of the cuspidal space is $14$, that of the Kohnen $+$-space is $4$; if desired, the corresponding modular forms can be obtained by \kbd{mflinear(mf,K[,j])} for each $j$ as done in the next command. The Fourier expansion of $F$ given on the last line shows that the only nonzero coefficients of $q^n$ occur when $n\equiv0,1\pmod4$. Continuing: \begin{verbatim} ? [mf2,FS]=mfshimura(mf,F); mfparams(FS) % = [15, 4, 1, y] ? [mf2,FS]=mfshimura(mf,mfbasis(mf)[1]); mfparams(FS) % = [30, 4, 1, y] \end{verbatim} These commmands show that the image of an element of the Kohnen $+$-space has level $15=60/4$, while the second shows that the image of a random form has level $30=60/2$. \smallskip A final command related to the Kohnen $+$-space is \kbd{mfkohnenbijection}. This allows, in half-integral weight, to compute the new space, its splitting, and the eigenforms: \begin{verbatim} ? [mf3,M,K,shi] = mfkohnenbijection(mf); ? M * mfheckemat(mf3,11) * M^(-1) % = [ 48 24 24 24] [ 0 32 0 -20] [-48 -72 -40 -72] [ 0 0 0 52] ? mf30 = mfinit(mf3,0); B0 = mfbasis(mf30); #B0 % = 2 ? BNEW = [mflinear(mf, K * M * mftobasis(mf3,f)) | f<-B0]; ? BE = mfeigenbasis(mf30); ? BEIGEN = [mflinear(mf, K * M * mftobasis(mf3,f)) | f<-BE ]; ? Ser(mfcoefs(BEIGEN[1],24),q) % = q + q^4 - 3*q^9 - 5*q^16 + 6*q^21 + 3*q^24 + O(q^25) ? Ser(mfcoefs(BEIGEN[2],24),q) % = q^5 + q^8 - 3*q^12 - 4*q^17 + 3*q^20 + O(q^25) ? mfcoefs(BEIGEN[1],10^4); time = 7,532 ms. \end{verbatim} The \kbd{mfkohnenbijection} command computes a square matrix $M$ giving a Hecke-module isomorphism from the space $S_{2k-1}(\G_0(N),\chi^2)$ to the Kohnen $+$-space $S_k^+(\G_0(4N,\chi))$. Note that this makes sense only when $N$ is squarefree. Thus, $M$ allows to transport all problems from the ``difficult'' space $S=S_k^+(\G_0(4N),\chi)$ to the ``easy'' space $S_{2k-1}(\G_0(N),\chi^2)$. For instance, the next command (essentially instantaneous) gives the matrix of the Hecke operator $T(121)$ on $S$; a direct implementation using the action of $T(121)$ would take $10.6$ seconds. The vector \kbd{BNEW} computed afterwards gives a basis of the Kohnen new space $S_k^{+,\text{new}}(\G_0(4N),\chi)$, here of dimension $2$. The vector \kbd{BEIGEN} computed in a similar way contains the eigenfunctions of this new space. The example of \kbd{BEIGEN[2]} shows that, contrary to the integral weight case, these eigenfunctions can have vanishing coefficient of $q^1$. Note that we \emph{know} by construction that the image of \kbd{BEIGEN[j]} by any Shimura lift is a multiple of \kbd{BE[j]} (with the same index $j$). \smallskip The above construction of the new space and the eigenforms being so useful, a specific function exists for this purpose: instead of all the above, simply write \kbd{[mf30,BNEW,BEIGEN]=mfkohneneigenbasis(mf,bij)}. Here \kbd{BNEW} and \kbd{BEIGEN} will be matrices whose columns are the coefficients of a basis of the Kohnen new space and of the eigenforms respectively, and \kbd{mf30} the corresponding new space of integral weight. \section{Reference Manual for the Package} We give a brief description in alphabetical order of all the functions specific to the package. To use the package, it is sometimes necessary to use functions on characters or functions of the \kbd{lfun} package, but those will not be described here. Note that when a modular form $F$ can be embedded in $\C$ in several ways (typically for eigenforms), some functions give a vector (or even a matrix for bilinear operations) of results, one for each embedding: this occurs specifically for \kbd{lfunmf}, \kbd{mfeval}, \kbd{mfmanin}, \kbd{mfpetersson}, \kbd{mfsymboleval}. This will not always be specified. \def\f{\medskip\noindent} \noindent\kbd{getcache()}: returns technical information about auto-growing caches. \f\kbd{lfunmf(mf,$\{F\}$)}: creates the $L$-function associated to $F$, for use in the \kbd{lfun} package, where $F$ need not be an eigenform. If $F$ is omitted, output all $L$-functions associated to the eigenforms. If $F$ (or the eigenforms) have several embeddings in $\C$, output the vector of the corresponding \kbd{lfunmf}. \f\kbd{mfatkin(mfatk, F)}: computes $F|_k W_Q$, where $Q\Vert N$, where \kbd{mfatk} must have been initialized by \kbd{mfatk=mfatkininit(mf,Q)}. \f\kbd{mfatkineigenvalues(mf, Q)}: \kbd{mf} being a cuspidal or new space and $Q$ a primitive divisor of $N$, output the vector of Atkin--Lehner eigenvalues or pseudo-eigenvalues for each Galois eigenspace. \f\kbd{mfatkininit(mf,Q)}: initialization function for the \kbd{mfatkin} function. The output is \kbd{[mfb,M,C,mf]}, where $C$ is a complex constant, $M/C$ is the matrix of the Atkin--Lehner operator $W_Q$ from the space \kbd{mf} to the space \kbd{mfb} (set equal to $0$ if equal to \kbd{mf}). The matrix $M$ is guaranteed to be with exact coefficients (rational or \kbd{polmods}). \f\kbd{mfbasis(mf,$\{\text{space}=4\}$)}: gives a basis of the space of modular forms \kbd{mf}, either output by an \kbd{mfinit} command, in which case \kbd{space} is ignored, or \kbd{mf=[N,k,CHI]} (use \kbd{mfeigenbasis} for the eigenforms). \f\kbd{mfbd(F,d)}: gives $B(d)(F)$, $B(d)$ expanding operator. \f\kbd{mfbracket(F,G,$\{m=0\}$)}: $m$th Rankin--Cohen bracket of $F$ and $G$. \f\kbd{mfcoef(F,n)}: $n$th Fourier coefficient $a(n)$ of $F$. \f\kbd{mfcoefs(F,n)}: vector $[a(0),a(1),...,a(n)]$ of the Fourier coefficients of $F$ up to $n$. If $F$ is a modular form \emph{space}, give the matrix whose columns are the vectors of the Fourier coefficients of the basis. \f\kbd{mfconductor(mf,F)}: smallest $M$ such that $F$ belongs to $M_k(\G_0(M),\chi)$. \f\kbd{mfcosets(N)}: list of right cosets of $\G$ modulo $\G_0(N)$. In the present implementation, the trivial coset is the last and represented by the matrix $[1,0;N,1]$. $N$ can also be an \kbd{mf}. \f\kbd{mfcuspisregular(NK,cusp)}: \kbd{NK} being $[N,k,\chi]$ or an \kbd{mf}, determine if the cusp is regular or not. \f\kbd{mfcusps(N)}: list of cusps of $\G_0(N)$. $N$ can also be an \kbd{mf}. \f\kbd{mfcuspval(mf,F,cusp)}: valuation of modular form $F$ at \kbd{cusp}, which can be a rational number or \kbd{oo}. \f\kbd{mfcuspwidth(N,cusp)}: width of \kbd{cusp} in $\G_0(N)$. $N$ can also be an \kbd{mf}. \f\kbd{mfDelta()}: Ramanujan's Delta function of weight $12$. \f\kbd{mfderiv(F,$\{m=1\}$)}: $m$th derivative $q.d/dq$ of $F$, where $m$ can be negative, corresponding to integration (the constant term is then set to $0$ by convention). The result is only quasi-modular. \f\kbd{mfderivE2(F,$\{m=1\}$)}: $m$th Serre derivative $q.d/dq F-kE_2F/12$. \f\kbd{mfdescribe(F,$\{\&G\}$)}: $F$ being a modular form or a modular form space, gives a human-readable description of $F$. If the address of $G$ is given, put in it the vector of parameters of the outmost operator defining $F$ (empty vector if $F$ is a leaf or a modular form space). \f\kbd{mfdim(mf,$\{\text{space}=4\}$)}: dimension of the space \kbd{mf}, where \kbd{mf} can also be of the form $[N,k,\chi]$ in which case \kbd{space} is taken into account. \kbd{mf} can also be of the form $[N,k,0]$, where $0$ is a wildcard, in which case it gives detailed information for each character $\chi$ for which the corresponding space of level $N$, weight $k$ and given character is nonzero: each result is of the form \kbd{[order,Conrey,dim,dimdih]}, where \kbd{Conrey} is the Conrey label for the character, \kbd{order} is its order, \kbd{dim} is the dimension of the corresponding space, and \kbd{dimdih}, which is computed only in weight $1$, is the dimension of the subspace of dihedral forms. \f\kbd{mfdiv(F,G)}: division of \kbd{F} by \kbd{G}. \f\kbd{mfEH(k)}: $k$ being half-integral, gives the Cohen--Eisenstein series of weight $k$ on $\G_0(4)$. \f\kbd{mfeigenbasis(mf)}: \kbd{mf} containing the new space, gives (in some order) the basis of normalized eigenforms. \f\kbd{mfeigensearch(NK,AP)}: search for normalized eigenforms with integer coefficients in spaces specified by \kbd{NK}, satisfying conditions satisfied by \kbd{AP}. \kbd{NK} is a pair $[N,k]$, the search being in level $N$ and weight $k$ with trivial or quadratic character; the parameter $N$ may be replaced by a vector of allowed levels. \kbd{AP} is a list of pairs $[[p_1,a(p_1)],...,[p_n,a(p_n)]]$, where $a(p)$ is either an integer or an \kbd{intmod} (match modulo $a(p)\kbd{.mod}$). \f\kbd{mfeisenstein(k,$\{\chi_1\}$,$\{\chi_2\}$)}: Eisenstein series $E_k(\chi_1)$ or $E_k(\chi_1,\chi_2)$, normalized so that $a(1)=1$ (so \kbd{mfeisenstein(k)} without any character argument is equal to \kbd{mfEk(k)} multiplied by $-B_k/(2k)$). \f\kbd{mfEk(k)}: Eisenstein series $E_k$ for the full modular group normalized so that $a(0)=1$, including for $k=2$. \f\kbd{mfeval(mf,F,vtau)}: evaluation of $F$ at the point \kbd{vtau} (or a vector of points) in the completed upper half-plane. If $F$ is an eigenform with several embeddings in $\C$, evaluate at each embedding. \f\kbd{mffields(mf)}: \kbd{mf} containing the new space, gives the list of relative polynomials defining the number field extensions for all the Galois orbits of the eigenforms. \kbd{mf} can also be a modular form, in which case the result is the number field extension of $\Q(\chi)$ in which the Fourier coefficients of \kbd{mf} lie. \f\kbd{mffromell(e)}: \kbd{e} being an elliptic curve defined over $\Q$ in \kbd{ellinit} format, gives \kbd{[mf,F,coe]}, where \kbd{F} is the eigenform corresponding to \kbd{e} by modularity, \kbd{mf} the corresponding new space, and \kbd{coe} the coefficients of \kbd{F} on the basis of \kbd{mf}. \f\kbd{mffrometaquo(eta,$\{\text{flag}=0\}$)}: \kbd{eta} being a matrix representing an eta quotient, gives the corresponding modular form or function. If the result is not a modular form or function, return an error if \kbd{flag=0}, or $0$ otherwise. If the result has negative valuation, normalize to valuation $0$. \f\kbd{mffromlfun(L)}: \kbd{L} being the $L$-function of a self-dual modular form with rational coefficients, for instance a rational eigenform, retun \kbd{[NK,space,v]}, where \kbd{mf = mfinit(NK,space)} is a modular form space containing the form and \kbd{mftobasis(mf,v)} yields the coefficients of \kbd{F} on the basis of \kbd{mf}. \f\kbd{mffromqf(Q,$\{P\}$)}: \kbd{Q} being an even integral quadratic form of even dimension and \kbd{P} an optional homogeneous spherical polynomial with respect to \kbd{Q}, gives \kbd{[mf,F,coe]}, where \kbd{F} is the theta function associated to \kbd{Q} and \kbd{P}, \kbd{mf} the corresponding space, and \kbd{coe} the coefficients of \kbd{F} on the basis of \kbd{mf}. \f\kbd{mfgaloistype(mf,$\{F\}$)}: \kbd{mf} being either $[N,1,\chi]$ or a new or cuspidal space of weight $1$ forms, outputs the type of the projective representations attached to all the eigenforms in \kbd{mf}, or only that of \kbd{F} if it is given. The output is $2n$ for $D_n$, or $-12$, $-24$, $-60$ for $A_4$, $S_4$, $A_5$. \f\kbd{mfhecke(mf,F,n)}: Computes $T(n)(f)$, where $T(n)$ is the $n$th Hecke operator. Note that the level which is used is that of the modular form space \kbd{mf}, not that of $F$ if it is different. \f\kbd{mfheckemat(mf,n)}: matrix of $T(n)$ on the space \kbd{mf}. \f\kbd{mfinit(NK,$\{\text{space}=4\}$)}: create the space of modular forms associated to $NK=[N,k,\chi]$ or $NK=[N,k]$. Codes for \kbd{space} is $0$, new space, $1$ cuspidal space, $2$ old space, $3$ space of Eisenstein series, $4$ full space $M_k$ (default). $NK$ can also be of the form $NK=[N,k,0]$, where $0$ is a wildcard, in which case it gives the vector of all nonzero \kbd{mfinit} for each Galois orbit of characters $\chi$. \f\kbd{mfisCM(F)}: returns $0$ if $F$ does not have complex multiplication, and the CM discriminant(s) if it does. Note that in weight $1$ $F$ may have two CM discriminants, which occurs iff its galoistype is $D_2$. \f\kbd{mfisequal(F,G,$\{\text{lim}=0\}$)}: Are $F$ and $G$ equal, or at least are their first \kbd{lim+1} Fourier coefficients equal ? \f\kbd{mfkohnenbasis}(mf): \kbd{mf} being a cuspidal space of half-integral weight and level $4N$ with $N$ squarefree, computes a basis $B$ of the Kohnen $+$-space as a matrix whose columns are the coefficients of $B$ on the basis of \kbd{mf}. \f\kbd{mfkohnenbijection}(mf): \kbd{mf} being a cuspidal space of half-integral weight, computes \kbd{[mf2,M,K,shi]}, where \kbd{M} is a matrix giving a Hecke-module isomorphism from the cuspidal space \kbd{mf2} of weight $2k-1$ and level $N$ to the Kohnen $+$-space of weight $k$ and level $4N$, the columns of the matrix \kbd{K} are the coefficients of the Kohnen $+$-space on the basis of \kbd{mf}, and \kbd{shi} gives technical information about which linear combination of Shimura lifts has been chosen. \f\kbd{mfkohneneigenbasis}(mf,bij): \kbd{mf} being a cuspidal space of half-integral weight and \kbd{bij} the output of \kbd{mfkohnenbijection(mf)}, computes a triple \kbd{[mf0,Bnew,Beigen]}, where \kbd{Bnew} and \kbd{Beigen} are matrices whose columns are the coefficients of a basis of the Kohnen new space and of the eigenforms on the basis of \kbd{mf} respectively, and \kbd{mf0} is the corresponding new space of integral weight $2k-1$. \f\kbd{mflinear(vecF,vecL)}: linear combination of the forms in \kbd{vecF} with coefficients in \kbd{vecL}. Forms must have the same weight and character, but not necessarily the same level. This function is used for simpler operations such as \begin{verbatim} mflinear([F],[s]) \\ scalar multiplication mflinear([F,G],[1,1]) \\ addition mflinear([F,G],[1,-1]) \\ subtraction \end{verbatim} If \kbd{vecF=mfbasis(mf)}, it is better to write \kbd{mflinear(mf,vecL)} instead, since coefficient computations will be faster. \f\kbd{mfmanin(FS)}: $FS$ being a modular symbol associated to an eigenform, returns $[[P^+,P^-],[\omega^+,\omega^-,r]]$ where the $P^{\pm}$ are the even/odd polynomials of special values, the $\omega^{\pm}$ the corresponding periods, and $r=\Im(\omega^+\overline{\omega^-})/$. \f\kbd{mfmul(F,G)}: product of the modular forms $F$ and $G$. \f\kbd{mfnumcusps(N)}: number of cusps of $\G_0(N)$. \f\kbd{mfparams(F)}: returns parameters $[N,k,\chi,P]$ of the modular form $F$, where $K$ is the polynomial defining the number field containing the coefficients of $F$ (e.g., $y$ if $F$ is rational), or $[-1,-1,-1,0]$ if it is not defined. If $F$ is a modular form space, returns $[N,k,\chi,space]$. \f\kbd{mfperiodpol(mf,F,$\{\text{parity}=0\}$)}: period polynomial of the form $F$; if the \kbd{parity} argument is $1$ or $-1$, return the even/odd period polynomial. \f\kbd{mfperiodpolbasis(k,$\{\text{parity}=0\}$)}: basis of period polynomials of weight $k$ for the full modular group, even/odd ones if \kbd{parity} is $1$ or $-1$. \f\kbd{mfpetersson(FS,$\{\text{GS}=\text{FS}\}$)}: $FS$ and $GS$ being the modular symbols associated to $F$ and $G$ with \kbd{mfsymbol}, computes the Petersson product of $F$ and $G$ with the usual normalization $1/[\G:\G_0(N)]$. (Petersson square if $GS$ is omitted.) \f\kbd{mfpow(F, n)}: Modular form $F$ to the power $n$. \f\kbd{mfsearch([N,k], V, $\{\text{space}=4\}$)}: search for \emph{rational} modular forms of weight~$k$ and level $N$ in the specified modular form spaces whose Fourier expansion up to the length of $V$ exactly matches $V$. The output is a list of forms. The parameter $N$ may be replaced by a list of allowed levels, e.g. \kbd{[$N_1$..$N_2$]} for all levels between $N_1$ and $N_2$. \f\kbd{mfshift(F,m)}: \kbd{F} divided by $q^m$, omitting the remainder if there is one, where $m$ can be positive or negative. The result is usually not a modular form. \f\kbd{mfshimura(mf,F,$\{D = 1\}$)}: $F$ being a modular form of half-integral weight $k\ge3/2$ and $D$ a discriminant, return \kbd{[mf2,FS,v]}, where \kbd{FS} is the corresponding Shimura lift of integral weight $2k-1$, \kbd{mf2} the corresponding modular form space and \kbd{v} the coefficients of \kbd{FS} on the basis of \kbd{mf2}. By extension, $D$ can also be a positive squarefree integer. \f\kbd{mfslashexpansion(mf,f,g,n,flrat,$\{\&P\}$)}: compute the Fourier expansion of $f|_k g$ to order $n$, where $f$ is a form in \kbd{mf} and $g\in M_2^+(\Q)$. If \kbd{flrat} is set, try to ``rationalize'' (error if unsuccessful). If the output is $[a(0),...,a(n)]$ and the optional $P$ contains parameters $[\al,w,A]$, then $f|_k g = F|_k A$ where $F(\tau) = q^{\al}\sum_{0\le j\le n}a(j)q^{j/w}$, with $q=\exp(2\pi i\tau)$. $A$ is always upper triangular and usually the identity, so that $F|_k A$ is immediate to compute. \f\kbd{mfspace(mf,$\{F\}$)}: type of modular space \kbd{mf} if $F$ is omitted, or of a modular form $F$ in \kbd{mf}: result is $0$ for new, $1$ for cuspidal, $2$ for old, $3$ for full, $4$ for Eisenstein, and $-1$ if form is not in the space. \f\kbd{mfsplit(mf,$\{\text{dimlim}=0\}$,$\{\text{flag}=0\}$)}: compute the eigenforms in \kbd{mf}, and limit the dimension of each Galois orbit to \kbd{dimlim} if set. \kbd{flag} is used to avoid some long computations (see doc). The space \kbd{mf} \emph{must} contain the new space. Note that the result is only a two-component vector \kbd{vF,vK}, where \kbd{vF} is a vector of eigenforms and \kbd{vK} the corresponding number fields, but is \emph{not} similar to the output of an \kbd{mfinit} command. \f\kbd{mfsturm(mf)}: If \kbd{mf} is a space, true Sturm bound of \kbd{mf}, i.e., largest valuation at infinity of a nonzero form. If \kbd{mf} is $[N,k,\chi]$, only an upper bound. \f\kbd{mfsymbol(mf,F)}: initialize data for working with integrals related to $F$ such as \kbd{mfsymboleval}, \kbd{mfpetersson}, and \kbd{mfmanin}. \f\kbd{mfsymboleval(FS,path,$\{\ga\}$)}: $FS$ being the modular symbol assocated to some form $F$ and \kbd{path} being $[s_1,s_2]$ where $s_1$ and $s_2$ are cusps or points in the upper half-plane, evaluate the symbol on the path, i.e., compute the polynomial $\int_{s_1}^{s_2}(X-\tau)^{k-2}F(\tau)\,d\tau$. If $\ga\in GL_2^+(\Q)$ is given, replace $F$ by $F|_k\ga$. If the integral diverges, the result will be either a rational function or a polynomial of degree $d>k-2$. \f\kbd{mftaylor(F,n,$\{\text{fl}=0\}$)}: for now, only for $F\in M_k(\G)$ and at the point $i$. Compute the first $n$ Taylor coefficients of $F$ around $i$; if \kbd{fl} is set compute in fact $p_n$ such that $$f(\tau)=(2i/(\tau+i))^k\sum_{n\ge0}p_n((\tau-i)/(\tau+i))^n\;.$$ \f\kbd{mfTheta($\{\chi\}$)}: unary theta series corresponding to the primitive Dirichlet character $\chi$, thus in weight $1/2$ (resp., $3/2$) if $\chi$ is even (resp., odd). \f\kbd{mftobasis(mf,F,$\{\text{flag}=0\}$)}: coefficients of form $F$ on the basis in \kbd{mf}. If \kbd{flag} is set, do not return an error if $F$ does not belong to \kbd{mf} or not enough coefficients. \f\kbd{mftocoset(N,M,L)}: $L$ being the list of cosets output by \kbd{L=mfcosets(N)} and $M$ being in $\SL_2(\Z)$, output a pair $[\ga,i]$ such that $M=\ga L[i]$, where $\ga\in \G_0(N)$. \f\kbd{mftonew(mf,F)}: Decompose $F$ is the cuspidal space \kbd{mf} as a sum of $B(d)G_M$ where $G_M\in S_k^{\new}(\G_0(M),\chi)$ and $dM\mid N$, return the vector of $[M,d,G]$. \f\kbd{mftraceform(NK,$\{\text{space}=0\}$)}: gives the trace form corresponding to $NK=[N,k,\chi]$ and \kbd{space} (only the new space and the cuspidal space). \f\kbd{mftwist(F,D)}: twist of the form $F$ by the quadratic character $(D/n)$. \end{document} pari-2.11.2/doc/usersch4.tex0000644000175000017500000030776213326135265014232 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \chapter{Programming PARI in Library Mode} \noindent The \emph{User's Guide to Pari/GP} gives in three chapters a general presentation of the system, of the \kbd{gp} calculator, and detailed explanation of high level PARI routines available through the calculator. The present manual assumes general familiarity with the contents of these chapters and the basics of ANSI C programming, and focuses on the usage of the PARI library. In this chapter, we introduce the general concepts of PARI programming and describe useful general purpose functions; the following chapters describes all public low or high-level functions, underlying or extending the GP functions seen in Chapter 3 of the User's guide. \section{Introduction: initializations, universal objects} \label{se:intro4} \noindent To use PARI in \idx{library mode}, you must write a C program and link it to the PARI library. See the installation guide or the Appendix to the \emph{User's Guide to Pari/GP} on how to create and install the library and include files. A sample Makefile is presented in Appendix~A, and a more elaborate one in \kbd{examples/Makefile}. The best way to understand how programming is done is to work through a complete example. We will write such a program in~\secref{se:prog}. Before doing this, a few explanations are in order. First, one must explain to the outside world what kind of objects and routines we are going to use. This is done\footnote{*}{This assumes that PARI headers are installed in a directory which belongs to your compiler's search path for header files. You might need to add flags like \kbd{-I/usr/local/include} or modify \tet{C_INCLUDE_PATH}.} with the directive \bprog #include @eprog \noindent In particular, this defines the fundamental type for all PARI objects: the type \teb{GEN}, which is simply a pointer to \kbd{long}. Before any PARI routine is called, one must initialize the system, and in particular the PARI stack which is both a scratchboard and a repository for computed objects. This is done with a call to the function \fun{void}{pari_init}{size_t size, ulong maxprime} \noindent The first argument is the number of bytes given to PARI to work with, and the second is the upper limit on a precomputed prime number table; \kbd{size} should not reasonably be taken below $500000$ but you may set $\tet{maxprime} = 0$, although the system still needs to precompute all primes up to about $2^{16}$. For lower-level variants allowing finer control, e.g.~preventing PARI from installing its own error or signal handlers, see~\secref{se:pari_init_tech}. \noindent We have now at our disposal: \item a PARI \tev{stack} containing nothing. This is a big connected chunk of \kbd{size} bytes of memory, where all computations take place. In large computations, intermediate results quickly clutter up memory so some kind of garbage collecting is needed. Most systems do garbage collecting when the memory is getting scarce, and this slows down the performance. PARI takes a different approach, admittedly more demanding on the programmer: you must do your own cleaning up when the intermediate results are not needed anymore. We will see later how (and when) this is done. \item the following \emph{universal objects} (by definition, objects which do not belong to the stack): the integers $0$, $1$, $-1$, $2$ and $-2$ (respectively called \tet{gen_0}, \tet{gen_1}, \tet{gen_m1}, \tet{gen_2} and \tet{gen_m2}), the fraction $\dfrac{1}{2}$ (\tet{ghalf}). All of these are of type \kbd{GEN}. \item a \tev{heap} which is just a linked list of permanent universal objects. For now, it contains exactly the ones listed above. You will probably very rarely use the heap yourself; and if so, only as a collection of copies of objects taken from the stack (called \idx{clone}s in the sequel). Thus you need not bother with its internal structure, which may change as PARI evolves. Some complex PARI functions create clones for special garbage collecting purposes, usually destroying them when returning. \item a table of primes (in fact of \emph{differences} between consecutive primes), called \teb{diffptr}, of type \kbd{byteptr} (pointer to \kbd{unsigned char}). Its use is described in \secref{se:primetable} later. Using it directly is deprecated, high-level iterators provide a cleaner and more flexible interface, see \secref{se:primeiter} (such iterators use the private prime table, but extend it dynamically). \item access to all the built-in functions of the PARI library. These are declared to the outside world when you include \kbd{pari.h}, but need the above things to function properly. So if you forget the call to \tet{pari_init}, you will get a fatal error when running your program. \section{Important technical notes} \subsec{Backward compatibility} The PARI function names evolved over time, and deprecated functions are eventually deleted. The file \kbd{pariold.h} contains macros implementing a weak form of backward compatibility. In particular, whenever the name of a documented function changes, a \kbd{\#define} is added to this file so that the old name expands to the new one (provided the prototype didn't change also). This file is included by \kbd{pari.h}, but a large section is commented out by default. Define \tet{PARI_OLD_NAMES} before including \kbd{pari.h} to pollute your namespace with lots of obsolete names like \kbd{un}\footnote{*}{For \kbd{(long)gen\_1}. Since 2004 and version 2.2.9, typecasts are completely unnecessary in PARI programs.}: that might enable you to compile old programs without having to modify them. The preferred way to do that is to add \kbd{-DPARI\_OLD\_NAMES} to your compiler \kbd{CFLAGS}, so that you don't need to modify the program files themselves. Of course, it's better to fix the program if you can! \subsec{Types} \noindent Although PARI objects all have the C type \kbd{GEN}, we will freely use the word \teb{type} to refer to PARI dynamic subtypes: \typ{INT}, \typ{REAL}, etc. The declaration \bprog GEN x; @eprog\noindent declares a C variable of type \kbd{GEN}, but its ``value'' will be said to have type \typ{INT}, \typ{REAL}, etc. The meaning should always be clear from the context. \subsec{Type recursivity} \noindent Conceptually, most PARI types are recursive. But the \kbd{GEN} type is a pointer to \kbd{long}, not to \kbd{GEN}. So special macros must be used to access \kbd{GEN}'s components. The simplest one is \tet{gel}$(V, i)$, where \key{el} stands for \key{el}ement, to access component number $i$ of the \kbd{GEN} $V$. This is a valid \kbd{lvalue} (may be put on the left side of an assignment), and the following two constructions are exceedingly frequent % \bprog gel(V, i) = x; x = gel(V, i); @eprog\noindent where \kbd{x} and \kbd{V} are \kbd{GEN}s. This macro accesses and modifies directly the components of $V$ and do not create a copy of the coefficient, contrary to all the library \emph{functions}. More generally, to retrieve the values of elements of lists of \dots\ of lists of vectors we have the \tet{gmael} macros (for {\bf m}ultidimensional {\bf a}rray {\bf el}ement). The syntax is $\key{gmael}n(V,a_1,\dots,a_n)$, where $V$ is a \kbd{GEN}, the $a_i$ are indexes, and $n$ is an integer between $1$ and $5$. This stands for $x[a_1][a_2]\dots[a_n]$, and returns a \kbd{GEN}. The macros \tet{gel} (resp.~\tet{gmael}) are synonyms for \tet{gmael1} (resp.~\kbd{gmael2}). Finally, the macro $\tet{gcoeff}(M, i, j)$ has exactly the meaning of \kbd{M[i,j]} in GP when \kbd{M} is a matrix. Note that due to the implementation of \typ{MAT}s as horizontal lists of vertical vectors, \kbd{gcoeff(x,y)} is actually equivalent to \kbd{gmael(y,x)}. One should use \kbd{gcoeff} in matrix context, and \kbd{gmael} otherwise. \subsec{Variations on basic functions}\label{se:low_level} In the library syntax descriptions in Chapter~3, we have only given the basic names of the functions. For example \kbd{gadd}$(x,y)$ assumes that $x$ and $y$ are \kbd{GEN}s, and \emph{creates} the result $x+y$ on the PARI stack. For most of the basic operators and functions, many other variants are available. We give some examples for \kbd{gadd}, but the same is true for all the basic operators, as well as for some simple common functions (a complete list is given in Chapter~6): \fun{GEN}{gaddgs}{GEN x, long y} \fun{GEN}{gaddsg}{long x, GEN y} \noindent In the following one, \kbd{z} is a preexisting \kbd{GEN} and the result of the corresponding operation is put into~\kbd{z}. The size of the PARI stack does not change: \fun{void}{gaddz}{GEN x, GEN y, GEN z} \noindent (This last form is inefficient in general and deprecated outside of PARI kernel programming.) Low level kernel functions implement these operators for specialized arguments and are also available: Level 0 deals with operations at the word level (\kbd{long}s and \kbd{ulong}s), Level 1 with \typ{INT} and \typ{REAL} and Level 2 with the rest (modular arithmetic, polynomial arithmetic and linear algebra). Here are some examples of Level $1$ functions: \fun{GEN}{addii}{GEN x, GEN y}: here $x$ and $y$ are \kbd{GEN}s of type \typ{INT} (this is not checked). \fun{GEN}{addrr}{GEN x, GEN y}: here $x$ and $y$ are \kbd{GEN}s of type \typ{REAL} (this is not checked). \noindent There also exist functions \teb{addir}, \teb{addri}, \teb{mpadd} (whose two arguments can be of type \typ{INT} or \typ{REAL}), \teb{addis} (to add a \typ{INT} and a \kbd{long}) and so on. The Level $1$ names are self-explanatory once you know that {\bf i} stands for a \typ{INT}, {\bf r} for a \typ{REAL}, {\bf mp} for i or r, {\bf s} for a signed C long integer, {\bf u} for an unsigned C long integer; finally the suffix {\bf z} means that the result is not created on the PARI stack but assigned to a preexisting GEN object passed as an extra argument. Chapter 6 gives a description of these low-level functions. Level $2$ names are more complicated, see \secref{se:level2names} for all the gory details, and we content ourselves with a simple example used to implement \typ{INTMOD} arithmetic: \fun{GEN}{Fp_add}{GEN x, GEN y, GEN m}: returns the sum of $x$ and $y$ modulo $m$. Here $x, y, m$ are \typ{INT}s (this is not checked). The operation is more efficient if the inputs $x$, $y$ are reduced modulo $m$, but this is not a necessary condition. \misctitle{Important Note} These specialized functions are of course more efficient than the generic ones, but note the hidden danger here: the types of the objects involved (which is not checked) must be severely controlled, e.g.~using \kbd{addii} on a \typ{FRAC} argument will cause disasters. Type mismatches may corrupt the PARI stack, though in most cases they will just immediately overflow the stack. Because of this, the PARI philosophy of giving a result which is as exact as possible, enforced for generic functions like \kbd{gadd} or \kbd{gmul}, is dropped in kernel routines of Level $1$, where it is replaced by the much simpler rule: the result is a \typ{INT} if and only if all arguments are integer types (\typ{INT} but also C \kbd{long} and \kbd{ulong}) and a \typ{REAL} otherwise. For instance, multiplying a \typ{REAL} by a \typ{INT} always yields a \typ{REAL} if you use \kbd{mulir}, where \kbd{gmul} returns the \typ{INT} \kbd{gen\_0} if the integer is $0$. \subsec{Portability: 32-bit / 64-bit architectures} \noindent PARI supports both 32-bit and 64-bit based machines, but not simultaneously! The library is compiled assuming a given architecture, and some of the header files you include (through \kbd{pari.h}) will have been modified to match the library. Portable macros are defined to bypass most machine dependencies. If you want your programs to run identically on 32-bit and 64-bit machines, you have to use these, and not the corresponding numeric values, whenever the precise size of your \kbd{long} integers might matter. Here are the most important ones: \settabs\+ -----------------------------&---------------&------------&\cr \+ & 64-bit & 32-bit \cr\+ \tet{BITS_IN_LONG} & 64 & 32 \cr\+ \tet{LONG_IS_64BIT} & defined & undefined \cr\+ \tet{DEFAULTPREC} & 3 & 4 & ($\approx$ 19 decimal digits, % see formula below) \cr\+ \tet{MEDDEFAULTPREC}& 4 & 6 & ($\approx$ 38 decimal digits) \cr\+ \tet{BIGDEFAULTPREC}& 5 & 8 & ($\approx$ 57 decimal digits) \cr \noindent For instance, suppose you call a transcendental function, such as \kbd{GEN \key{gexp}(GEN x, long prec)}. \noindent The last argument \kbd{prec} is an integer $\geq 3$, corresponding to the default floating point precision required. It is \emph{only} used if \kbd{x} is an exact object, otherwise the relative precision is determined by the precision of~\kbd{x}. Since the parameter \kbd{prec} sets the size of the inexact result counted in (\kbd{long}) \emph{words} (including codewords), the same value of \kbd{prec} will yield different results on 32-bit and 64-bit machines. Real numbers have two codewords (see~\secref{se:impl}), so the formula for computing the bit accuracy is $$ \tet{bit_accuracy}(\kbd{prec}) = (\kbd{prec} - 2) * \tet{BITS_IN_LONG}$$ (this is actually the definition of an inline function). The corresponding accuracy expressed in decimal digits would be % $$ \kbd{bit\_accuracy(prec)} * \log(2) / \log(10).$$ % For example if the value of \kbd{prec} is 5, the corresponding accuracy for 32-bit machines is $(5-2)*\log(2^{32})/\log(10)\approx 28$ decimal digits, while for 64-bit machines it is $(5-2)*\log(2^{64})/\log(10)\approx 57$ decimal digits. Thus, you must take care to change the \kbd{prec} parameter you are supplying according to the bit size, either using the default precisions given by the various \kbd{DEFAULTPREC}s, or by using conditional constructs of the form: % \bprog #ifndef LONG_IS_64BIT prec = 4; #else prec = 6; #endif @eprog \noindent which is in this case equivalent to the statement \kbd{prec = MEDDEFAULTPREC;}. Note that for parity reasons, half the accuracies available on 32-bit architectures (the odd ones) have no precise equivalents on 64-bit machines. \subsec{Using \kbd{malloc} / \kbd{free}} You should make use of the PARI stack as much as possible, and avoid allocating objects using the customary functions. If you do, you should use, or at least have a very close look at, the following wrappers: \fun{void*}{pari_malloc}{size_t size} calls \kbd{malloc} to allocate \kbd{size} bytes and returns a pointer to the allocated memory. If the request fails, an error is raised. The \kbd{SIGINT} signal is blocked until \kbd{malloc} returns, to avoid leaving the system stack in an inconsistent state. \fun{void*}{pari_realloc}{void* ptr, size_t size} as \tet{pari_malloc} but calls \kbd{realloc} instead of \kbd{malloc}. \fun{void*}{pari_calloc}{size_t size} as \tet{pari_malloc}, setting the memory to zero. \fun{void}{pari_free}{void* ptr} calls \kbd{free} to liberate the memory space pointed to by \kbd{ptr}, which must have been allocated by \kbd{malloc} (\tet{pari_malloc}) or \kbd{realloc} (\tet{pari_realloc}). The \kbd{SIGINT} signal is blocked until \kbd{free} returns. If you use the standard \kbd{libc} functions instead of our wrappers, then your functions will be subtly incompatible with the \kbd{gp} calculator: when the user tries to interrupt a computation, the calculator may crash (if a system call is interrupted at the wrong time). \section{Garbage collection}\label{se:garbage}\sidx{garbage collecting} \subsec{Why and how} \noindent As we have seen, \kbd{pari\_init} allocates a big range of addresses, the \tev{stack}, that are going to be used throughout. Recall that all PARI objects are pointers. Except for a few universal objects, they all point at some part of the stack. The stack starts at the address \kbd{bot} and ends just before \kbd{top}. This means that the quantity % $$ (\kbd{top} - \kbd{bot})\,/\,\kbd{sizeof(long)} $$ % is (roughly) equal to the \kbd{size} argument of \kbd{pari\_init}. The PARI stack also has a ``current stack pointer'' called \teb{avma}, which stands for {\bf av}ailable {\bf m}emory {\bf a}ddress. These three variables are global (declared by \kbd{pari.h}). They are of type \tet{pari_sp}, which means \emph{pari stack pointer}. The stack is oriented upside-down: the more recent an object, the closer to \kbd{bot}. Accordingly, initially \kbd{avma} = \kbd{top}, and \kbd{avma} gets \emph{decremented} as new objects are created. As its name indicates, \kbd{avma} always points just \emph{after} the first free address on the stack, and \kbd{(GEN)avma} is always (a pointer to) the latest created object. When \kbd{avma} reaches \kbd{bot}, the stack overflows, aborting all computations, and an error message is issued. To avoid this \emph{you} need to clean up the stack from time to time, when intermediate objects are not needed anymore. This is called ``\emph{garbage collecting}.'' We are now going to describe briefly how this is done. We will see many concrete examples in the next subsection. \noindent\item First, PARI routines do their own garbage collecting, which means that whenever a documented function from the library returns, only its result(s) have been added to the stack, possibly up to a very small overhead (non-documented ones may not do this). In particular, a PARI function that does not return a \kbd{GEN} does not clutter the stack. Thus, if your computation is small enough (e.g.~you call few PARI routines, or most of them return \kbd{long} integers), then you do not need to do any garbage collecting. This is probably the case in many of your subroutines. Of course the objects that were on the stack \emph{before} the function call are left alone. Except for the ones listed below, PARI functions only collect their own garbage. \noindent\item It may happen that all objects that were created after a certain point can be deleted~--- for instance, if the final result you need is not a \kbd{GEN}, or if some search proved futile. Then, it is enough to record the value of \kbd{avma} just \emph{before} the first garbage is created, and restore it upon exit: \bprog pari_sp av = avma; /*@Ccom record initial avma */ garbage ... avma = av; /*@Ccom restore it */ @eprog \noindent All objects created in the \kbd{garbage} zone will eventually be overwritten: they should no longer be accessed after \kbd{avma} has been restored. \noindent\item If you want to destroy (i.e.~give back the memory occupied by) the \emph{latest} PARI object on the stack (e.g.~the latest one obtained from a function call), you can use the function\sidx{destruction}% \vadjust{\penalty500}%discourage page break \fun{void}{cgiv}{GEN z} \noindent where \kbd{z} is the object you want to give back. This is equivalent to the above where the initial \kbd{av} is computed from \kbd{z}. \noindent\item Unfortunately life is not so simple, and sometimes you will want to give back accumulated garbage \emph{during} a computation without losing recent data. We shall start with the lowest level function to get a feel for the underlying mechanisms, we shall describe simpler variants later: \fun{GEN}{gerepile}{pari_sp ltop, pari_sp lbot, GEN q}. This function cleans up the stack between \kbd{ltop} and \kbd{lbot}, where $\kbd{lbot} < \kbd{ltop}$, and returns the updated object \kbd{q}. This means: 1) we translate (copy) all the objects in the interval $[\kbd{avma}, \kbd{lbot}[$, so that its right extremity abuts the address \kbd{ltop}. Graphically \vbox{\bprog bot avma lbot ltop top End of stack |-------------[++++++[-/-/-/-/-/-/-|++++++++| Start free memory garbage @eprog \noindent becomes: \bprog bot avma ltop top End of stack |---------------------------[++++++[++++++++| Start free memory @eprog } \noindent where \kbd{++} denote significant objects, \kbd{--} the unused part of the stack, and \kbd{-/-} the garbage we remove. 2) The function then inspects all the PARI objects between \kbd{avma} and \kbd{lbot} (i.e.~the ones that we want to keep and that have been translated) and looks at every component of such an object which is not a codeword. Each such component is a pointer to an object whose address is either --- between \kbd{avma} and \kbd{lbot}, in which case it is suitably updated, --- larger than or equal to \kbd{ltop}, in which case it does not change, or --- between \kbd{lbot} and \kbd{ltop} in which case \kbd{gerepile} raises an error (``significant pointers lost in gerepile''). 3) \key{avma} is updated (we add $\kbd{ltop} - \kbd{lbot}$ to the old value). 4) We return the (possibly updated) object \kbd{q}: if \kbd{q} initially pointed between \kbd{avma} and \kbd{lbot}, we return the updated address, as in~2). If not, the original address is still valid, and is returned! As stated above, no component of the remaining objects (in particular \kbd{q}) should belong to the erased segment [\kbd{lbot}, \kbd{ltop}[, and this is checked within \kbd{gerepile}. But beware as well that the addresses of the objects in the translated zone change after a call to \kbd{gerepile}, so you must not access any pointer which previously pointed into the zone below \kbd{ltop}. If you need to recover more than one object, use the \kbd{gerepileall} function below. \misctitle{Remark} As a consequence of the preceding explanation, if a PARI object is to be relocated by \hbox{gerepile} then, apart from universal objects, the chunks of memory used by its components should be in consecutive memory locations. All \kbd{GEN}s created by documented PARI functions are guaranteed to satisfy this. This is because the \kbd{gerepile} function knows only about \emph{two connected zones}: the garbage that is erased (between \kbd{lbot} and \kbd{ltop}) and the significant pointers that are copied and updated. If there is garbage interspersed with your objects, disaster occurs when we try to update them and consider the corresponding ``pointers''. In most cases of course the said garbage is in fact a bunch of other \kbd{GEN}s, in which case we simply waste time copying and updating them for nothing. But be wary when you allow objects to become disconnected. \noindent In practice this is achieved by the following programming idiom: \bprog ltop = avma; garbage(); lbot = avma; q = anything(); return gerepile(ltop, lbot, q); /*@Ccom returns the updated q */ @eprog\noindent or directly \bprog ltop = avma; garbage(); lbot = avma; return gerepile(ltop, lbot, anything()); @eprog\noindent Beware that \bprog ltop = avma; garbage(); return gerepile(ltop, avma, anything()) @eprog \noindent might work, but should be frowned upon. We cannot predict whether \kbd{avma} is evaluated after or before the call to \kbd{anything()}: it depends on the compiler. If we are out of luck, it is \emph{after} the call, so the result belongs to the garbage zone and the \kbd{gerepile} statement becomes equivalent to \kbd{avma = ltop}. Thus we return a pointer to random garbage. \subsec{Variants} \fun{GEN}{gerepileupto}{pari_sp ltop, GEN q}. Cleans the stack between \kbd{ltop} and the \emph{connected} object \kbd{q} and returns \kbd{q} updated. For this to work, \kbd{q} must have been created \emph{before} all its components, otherwise they would belong to the garbage zone! Unless mentioned otherwise, documented PARI functions guarantee this. \fun{GEN}{gerepilecopy}{pari_sp ltop, GEN x}. Functionally equivalent to, but more efficient than \bprog gerepileupto(ltop, gcopy(x)) @eprog\noindent In this case, the \kbd{GEN} parameter \kbd{x} need not satisfy any property before the garbage collection: it may be disconnected, components created before the root, and so on. Of course, this is about twice slower than either \tet{gerepileupto} or \tet{gerepile}, because \kbd{x} has to be copied to a clean stack zone first. This function is a special case of \tet{gerepileall} below, where $n=1$. \fun{void}{gerepileall}{pari_sp ltop, int n, ...}. To cope with complicated cases where many objects have to be preserved. The routine expects $n$ further arguments, which are the \emph{addresses} of the \kbd{GEN}s you want to preserve: \bprog pari_sp ltop = avma; ...; y = ...; ... x = ...; ...; gerepileall(ltop, 2, &x, &y); @eprog\noindent It cleans up the most recent part of the stack (between \kbd{ltop} and \kbd{avma}), updating all the \kbd{GEN}s added to the argument list. A copy is done just before the cleaning to preserve them, so they do not need to be connected before the call. With \kbd{gerepilecopy}, this is the most robust of the \kbd{gerepile} functions (the less prone to user error), hence the slowest. \fun{void}{gerepileallsp}{pari_sp ltop, pari_sp lbot, int n, ...}. More efficient, but trickier than \kbd{gerepileall}. Cleans the stack between \kbd{lbot} and \kbd{ltop} and updates the \kbd{GEN}s pointed at by the elements of \kbd{gptr} without any further copying. This is subject to the same restrictions as \kbd{gerepile}, the only difference being that more than one address gets updated. \subsec{Examples} \subsubsec{gerepile} Let \kbd{x} and \kbd{y} be two preexisting PARI objects and suppose that we want to compute $\kbd{x}^2 + \kbd{y}^2$. This is done using the following program: \bprog GEN x2 = gsqr(x); GEN y2 = gsqr(y), z = gadd(x2,y2); @eprog\noindent The \kbd{GEN} \kbd{z} indeed points at the desired quantity. However, consider the stack: it contains as unnecessary garbage \kbd{x2} and \kbd{y2}. More precisely it contains (in this order) \kbd{z}, \kbd{y2}, \kbd{x2}. (Recall that, since the stack grows downward from the top, the most recent object comes first.) It is not possible to get rid of \kbd{x2}, \kbd{y2} before \kbd{z} is computed, since they are used in the final operation. We cannot record \kbd{avma} before \kbd{x2} is computed and restore it later, since this would destroy \kbd{z} as well. It is not possible either to use the function \kbd{cgiv} since \kbd{x2} and \kbd{y2} are not at the bottom of the stack and we do not want to give back~\kbd{z}. But using \kbd{gerepile}, we can give back the memory locations corresponding to \kbd{x2}, \kbd{y2}, and move the object \kbd{z} upwards so that no space is lost. Specifically: \bprog pari_sp ltop = avma; /*@Ccom remember the current top of the stack */ GEN x2 = gsqr(x); GEN y2 = gsqr(y); pari_sp lbot = avma; /*@Ccom the bottom of the garbage pile */ GEN z = gadd(x2, y2); /*@Ccom z is now the last object on the stack */ z = gerepile(ltop, lbot, z); @eprog \noindent Of course, the last two instructions could also have been written more simply: \bprog z = gerepile(ltop, lbot, gadd(x2,y2)); @eprog\noindent In fact \kbd{gerepileupto} is even simpler to use, because the result of \kbd{gadd} is the last object on the stack and \kbd{gadd} is guaranteed to return an object suitable for \kbd{gerepileupto}: \bprog ltop = avma; z = gerepileupto(ltop, gadd(gsqr(x), gsqr(y))); @eprog\noindent Make sure you understand exactly what has happened before you go on! \misctitle{Remark on assignments and gerepile} When the tree structure and the size of the PARI objects which will appear in a computation are under control, one may allocate sufficiently large objects at the beginning, use assignment statements, then simply restore \kbd{avma}. Coming back to the above example, note that \emph{if} we know that x and y are of type real fitting into \kbd{DEFAULTPREC} words, we can program without using \kbd{gerepile} at all: \bprog z = cgetr(DEFAULTPREC); ltop = avma; gaffect(gadd(gsqr(x), gsqr(y)), z); avma = ltop; @eprog\noindent This is often \emph{slower} than a craftily used \kbd{gerepile} though, and certainly more cumbersome to use. As a rule, assignment statements should generally be avoided. \misctitle{Variations on a theme} it is often necessary to do several \kbd{gerepile}s during a computation. However, the fewer the better. The only condition for \kbd{gerepile} to work is that the garbage be connected. If the computation can be arranged so that there is a minimal number of connected pieces of garbage, then it should be done that way. For example suppose we want to write a function of two \kbd{GEN} variables \kbd{x} and \kbd{y} which creates the vector $\kbd{[x}^2+\kbd{y}, \kbd{y}^2+\kbd{x]}$. Without garbage collecting, one would write: % \bprog p1 = gsqr(x); p2 = gadd(p1, y); p3 = gsqr(y); p4 = gadd(p3, x); z = mkvec2(p2, p4); /* not suitable for gerepileupto! */ @eprog\noindent This leaves a dirty stack containing (in this order) \kbd{z}, \kbd{p4}, \kbd{p3}, \kbd{p2}, \kbd{p1}. The garbage here consists of \kbd{p1} and \kbd{p3}, which are separated by \kbd{p2}. But if we compute \kbd{p3} \emph{before} \kbd{p2} then the garbage becomes connected, and we get the following program with garbage collecting: % \bprog ltop = avma; p1 = gsqr(x); p3 = gsqr(y); lbot = avma; z = cgetg(3, t_VEC); gel(z, 1) = gadd(p1,y); gel(z, 2) = gadd(p3,x); z = gerepile(ltop,lbot,z); @eprog\noindent Finishing by \kbd{z = gerepileupto(ltop, z)} would be ok as well. Beware that \bprog ltop = avma; p1 = gadd(gsqr(x), y); p3 = gadd(gsqr(y), x); z = cgetg(3, t_VEC); gel(z, 1) = p1; gel(z, 2) = p3; z = gerepileupto(ltop,z); /*@Ccom WRONG */ @eprog\noindent is a disaster since \kbd{p1} and \kbd{p3} are created before \kbd{z}, so the call to \kbd{gerepileupto} overwrites them, leaving \kbd{gel(z, 1)} and \kbd{gel(z, 2)} pointing at random data! The following does work: \bprog ltop = avma; p1 = gsqr(x); p3 = gsqr(y); lbot = avma; z = mkvec2(gadd(p1,y), gadd(p3,x)); z = gerepile(ltop,lbot,z); @eprog\noindent but is very subtly wrong in the sense that \kbd{z = gerepileupto(ltop, z)} would \emph{not} work. The reason being that \kbd{mkvec2} creates the root \kbd{z} of the vector \emph{after} its arguments have been evaluated, creating the components of \kbd{z} too early; \kbd{gerepile} does not care, but the created \kbd{z} is a time bomb which will explode on any later \kbd{gerepileupto}. On the other hand \bprog ltop = avma; z = cgetg(3, t_VEC); gel(z, 1) = gadd(gsqr(x), y); gel(z, 2) = gadd(gsqr(y), x); z = gerepileupto(ltop,z); /*@Ccom INEFFICIENT */ @eprog\noindent leaves the results of \kbd{gsqr(x)} and \kbd{gsqr(y)} on the stack (and lets \kbd{gerepileupto} update them for naught). Finally, the most elegant and efficient version (with respect to time and memory use) is as follows \bprog z = cgetg(3, t_VEC); ltop = avma; gel(z, 1) = gerepileupto(ltop, gadd(gsqr(x), y)); ltop = avma; gel(z, 2) = gerepileupto(ltop, gadd(gsqr(y), x)); @eprog\noindent which avoids updating the container \kbd{z} and cleans up its components individually, as soon as they are computed. \misctitle{One last example} Let us compute the product of two complex numbers $x$ and $y$, using the $3M$ method which requires 3 multiplications instead of the obvious 4. Let $z = x*y$, and set $x = x_r + i*x_i$ and similarly for $y$ and $z$. We compute $p_1 = x_r*y_r$, $p_2=x_i*y_i$, $p_3=(x_r+x_i)*(y_r+y_i)$, and then we have $z_r=p_1-p_2$, $z_i=p_3-(p_1+p_2)$. The program is as follows: % \bprog ltop = avma; p1 = gmul(gel(x,1), gel(y,1)); p2 = gmul(gel(x,2), gel(y,2)); p3 = gmul(gadd(gel(x,1), gel(x,2)), gadd(gel(y,1), gel(y,2))); p4 = gadd(p1,p2); lbot = avma; z = cgetg(3, t_COMPLEX); gel(z, 1) = gsub(p1,p2); gel(z, 2) = gsub(p3,p4); z = gerepile(ltop,lbot,z); @eprog \misctitle{Exercise} Write a function which multiplies a matrix by a column vector. Hint: start with a \kbd{cgetg} of the result, and use \kbd{gerepile} whenever a coefficient of the result vector is computed. You can look at the answer in \kbd{src/basemath/RgV.c:RgM\_RgC\_mul()}. \subsubsec{gerepileall} Let us now see why we may need the \kbd{gerepileall} variants. Although it is not an infrequent occurrence, we do not give a specific example but a general one: suppose that we want to do a computation (usually inside a larger function) producing more than one PARI object as a result, say two for instance. Then even if we set up the work properly, before cleaning up we have a stack which has the desired results \kbd{z1}, \kbd{z2} (say), and then connected garbage from lbot to ltop. If we write \bprog z1 = gerepile(ltop, lbot, z1); @eprog\noindent then the stack is cleaned, the pointers fixed up, but we have lost the address of \kbd{z2}. This is where we need the \idx{gerepileall} function: \bprog gerepileall(ltop, 2, &z1, &z2) @eprog \noindent copies \kbd{z1} and \kbd{z2} to new locations, cleans the stack from \kbd{ltop} to the old \kbd{avma}, and updates the pointers \kbd{z1} and \kbd{z2}. Here we do not assume anything about the stack: the garbage can be disconnected and \kbd{z1}, \kbd{z2} need not be at the bottom of the stack. If all of these assumptions are in fact satisfied, then we can call \kbd{gerepilemanysp} instead, which is usually faster since we do not need the initial copy (on the other hand, it is less cache friendly). A most important usage is ``random'' garbage collection during loops whose size requirements we cannot (or do not bother to) control in advance: \bprog pari_sp av = avma; GEN x, y; while (...) { garbage(); x = anything(); garbage(); y = anything(); garbage(); if (gc_needed(av,1)) /*@Ccom memory is running low (half spent since entry) */ gerepileall(av, 2, &x, &y); } @eprog \noindent Here we assume that only \kbd{x} and \kbd{y} are needed from one iteration to the next. As it would be costly to call gerepile once for each iteration, we only do it when it seems to have become necessary. More precisely, the macro \tet{stack_lim}\kbd{(av,$n$)} denotes an address where $2^{n-1} / (2^{n-1}+1)$ of the remaining stack space since reference point \kbd{av} is exhausted ($1/2$ for $n=1$, $2/3$ for $n=2$). The test \tet{gc_needed}\kbd{(av,$n$)} becomes true whenever \kbd{avma} drops below that address. \subsec{Comments} First, \kbd{gerepile} has turned out to be a flexible and fast garbage collector for number-theoretic computations, which compares favorably with more sophisticated methods used in other systems. Our benchmarks indicate that the price paid for using \kbd{gerepile} and \kbd{gerepile}-related copies, when properly used, is usually less than 1\% of the total running time, which is quite acceptable! Second, it is of course harder on the programmer, and quite error-prone if you do not stick to a consistent PARI programming style. If all seems lost, just use \tet{gerepilecopy} (or \tet{gerepileall}) to fix up the stack for you. You can always optimize later when you have sorted out exactly which routines are crucial and what objects need to be preserved and their usual sizes. \smallskip If you followed us this far, congratulations, and rejoice: the rest is much easier. \section{Creation of PARI objects, assignments, conversions} \subsec{Creation of PARI objects}\sidx{creation} The basic function which creates a PARI object is \fun{GEN}{cgetg}{long l, long t} $l$ specifies the number of longwords to be allocated to the object, and $t$ is the type of the object, in symbolic form (see \secref{se:impl} for the list of these). The precise effect of this function is as follows: it first creates on the PARI \emph{stack} a chunk of memory of size \kbd{length} longwords, and saves the address of the chunk which it will in the end return. If the stack has been used up, a message to the effect that ``the PARI stack overflows'' is printed, and an error raised. Otherwise, it sets the type and length of the PARI object. In effect, it fills its first codeword (\kbd{z[0]}). Many PARI objects also have a second codeword (types \typ{INT}, \typ{REAL}, \typ{PADIC}, \typ{POL}, and \typ{SER}). In case you want to produce one of those from scratch, which should be exceedingly rare, \emph{it is your responsibility to fill this second codeword}, either explicitly (using the macros described in \secref{se:impl}), or implicitly using an assignment statement (using \kbd{gaffect}). Note that the length argument $l$ is predetermined for a number of types: 3 for types \typ{INTMOD}, \typ{FRAC}, \typ{COMPLEX}, \typ{POLMOD}, \typ{RFRAC}, 4 for type \typ{QUAD} and \typ{QFI}, and 5 for type \typ{PADIC} and \typ{QFR}. However for the sake of efficiency, \kbd{cgetg} does not check this: disasters will occur if you give an incorrect length for those types. \misctitle{Notes} 1) The main use of this function is create efficiently a constant object, or to prepare for later assignments (see \secref{se:assign}). Most of the time you will use \kbd{GEN} objects as they are created and returned by PARI functions. In this case you do not need to use \kbd{cgetg} to create space to hold them. \noindent 2) For the creation of leaves, i.e.~\typ{INT} or \typ{REAL}, \fun{GEN}{cgeti}{long length} \fun{GEN}{cgetr}{long length} \noindent should be used instead of \kbd{cgetg(length, t\_INT)} and \kbd{cgetg(length, t\_REAL)} respectively. Finally \fun{GEN}{cgetc}{long prec} \noindent creates a \typ{COMPLEX} whose real and imaginary part are \typ{REAL}s allocated by \kbd{cgetr(prec)}. \misctitle{Examples} 1) Both \kbd{z = cgeti(DEFAULTPREC)} and \kbd{cgetg(DEFAULTPREC, t\_INT)} create a \typ{INT} whose ``precision'' is \kbd{bit\_accuracy(DEFAULTPREC)} = 64. This means \kbd{z} can hold rational integers of absolute value less than $2^{64}$. Note that in both cases, the second codeword is \emph{not} filled. Of course we could use numerical values, e.g.~\kbd{cgeti(4)}, but this would have different meanings on different machines as \kbd{bit\_accuracy(4)} equals 64 on 32-bit machines, but 128 on 64-bit machines. \noindent 2) The following creates a \emph{complex number} whose real and imaginary parts can hold real numbers of precision $\kbd{bit\_accuracy(MEDDEFAULTPREC)} = 96\hbox{ bits:}$ % \bprog z = cgetg(3, t_COMPLEX); gel(z, 1) = cgetr(MEDDEFAULTPREC); gel(z, 2) = cgetr(MEDDEFAULTPREC); @eprog\noindent or simply \kbd{z = cgetc(MEDDEFAULTPREC)}. \noindent 3) To create a matrix object for $4\times 3$ matrices: % \bprog z = cgetg(4, t_MAT); for(i=1; i<4; i++) gel(z, i) = cgetg(5, t_COL); @eprog\noindent or simply \kbd{z = zeromatcopy(4, 3)}, which further initializes all entries to \kbd{gen\_0}. These last two examples illustrate the fact that since PARI types are recursive, all the branches of the tree must be created. The function \teb{cgetg} creates only the ``root'', and other calls to \kbd{cgetg} must be made to produce the whole tree. For matrices, a common mistake is to think that \kbd{z = cgetg(4, t\_MAT)} (for example) creates the root of the matrix: one needs also to create the column vectors of the matrix (obviously, since we specified only one dimension in the first \kbd{cgetg}!). This is because a matrix is really just a row vector of column vectors (hence a priori not a basic type), but it has been given a special type number so that operations with matrices become possible. Finally, to facilitate input of constant objects when speed is not paramount, there are four \tet{varargs} functions: \fun{GEN}{mkintn}{long n, ...} returns the non-negative \typ{INT} whose development in base $2^{32}$ is given by the following $n$ 32bit-words (\kbd{unsigned int}). \bprog mkintn(3, a2, a1, a0); @eprog \noindent returns $a_2 2^{64} + a_1 2^{32} + a_0$. \fun{GEN}{mkpoln}{long n, ...} Returns the \typ{POL} whose $n$ coefficients (\kbd{GEN}) follow, in order of decreasing degree. \bprog mkpoln(3, gen_1, gen_2, gen_0); @eprog \noindent returns the polynomial $X^2 + 2X$ (in variable $0$, use \tet{setvarn} if you want other variable numbers). Beware that $n$ is the number of coefficients, hence \emph{one more} than the degree. \fun{GEN}{mkvecn}{long n, ...} returns the \typ{VEC} whose $n$ coefficients (\kbd{GEN}) follow. \fun{GEN}{mkcoln}{long n, ...} returns the \typ{COL} whose $n$ coefficients (\kbd{GEN}) follow. \misctitle{Warning} Contrary to the policy of general PARI functions, the latter three functions do \emph{not} copy their arguments, nor do they produce an object a priori suitable for \tet{gerepileupto}. For instance \bprog /*@Ccom gerepile-safe: components are universal objects */ z = mkvecn(3, gen_1, gen_0, gen_2); /*@Ccom not OK for gerepileupto: stoi(3) creates component before root */ z = mkvecn(3, stoi(3), gen_0, gen_2); /*@Ccom NO! First vector component \kbd{x} is destroyed */ x = gclone(gen_1); z = mkvecn(3, x, gen_0, gen_2); gunclone(x); @eprog \noindent The following function is also available as a special case of \tet{mkintn}: \fun{GEN}{uu32toi}{ulong a, ulong b} Returns the \kbd{GEN} equal to $2^{32} a + b$, \emph{assuming} that $a,b < 2^{32}$. This does not depend on \kbd{sizeof(long)}: the behavior is as above on both $32$ and $64$-bit machines. \subsec{Sizes} \fun{long}{gsizeword}{GEN x} returns the total number of \B-bit words occupied by the tree representing~\kbd{x}. \fun{long}{gsizebyte}{GEN x} returns the total number of bytes occupied by the tree representing~\kbd{x}, i.e.~\kbd{gsizeword(x)} multiplied by \kbd{sizeof(long)}. This is normally useless since PARI functions use a number of \emph{words} as input for lengths and precisions. \subsec{Assignments} Firstly, if \kbd{x} and \kbd{y} are both declared as \kbd{GEN} (i.e.~pointers to something), the ordinary C assignment \kbd{y = x} makes perfect sense: we are just moving a pointer around. However, physically modifying either \kbd{x} or \kbd{y} (for instance, \kbd{x[1] = 0}) also changes the other one, which is usually not desirable. \label{se:assign} \misctitle{Very important note} Using the functions described in this paragraph is inefficient and often awkward: one of the \tet{gerepile} functions (see~\secref{se:garbage}) should be preferred. See the paragraph end for one exception to this rule. \noindent The general PARI \idx{assignment} function is the function \teb{gaffect} with the following syntax: \fun{void}{gaffect}{GEN x, GEN y} \noindent Its effect is to assign the PARI object \kbd{x} into the \emph{preexisting} object \kbd{y}. Both \kbd{x} and \kbd{y} must be \emph{scalar} types. For convenience, vector or matrices of scalar types are also allowed. This copies the whole structure of \kbd{x} into \kbd{y} so many conditions must be met for the assignment to be possible. For instance it is allowed to assign a \typ{INT} into a \typ{REAL}, but the converse is forbidden. For that, you must use the truncation or rounding function of your choice, e.g.\kbd{mpfloor}. It can also happen that \kbd{y} is not large enough or does not have the proper tree structure to receive the object \kbd{x}. For instance, let \kbd{y} the zero integer with length equal to 2; then \kbd{y} is too small to accommodate any non-zero \typ{INT}. In general common sense tells you what is possible, keeping in mind the PARI philosophy which says that if it makes sense it is valid. For instance, the assignment of an imprecise object into a precise one does \emph{not} make sense. However, a change in precision of imprecise objects is allowed, even if it \emph{increases} its accuracy: we complement the ``mantissa'' with infinitely many $0$ digits in this case. (Mantissa between quotes, because this is not restricted to \typ{REAL}s, it also applies for $p$-adics for instance.) All functions ending in ``\kbd{z}'' such as \teb{gaddz} (see~\secref{se:low_level}) implicitly use this function. In fact what they exactly do is record {\teb{avma}} (see~\secref{se:garbage}), perform the required operation, \teb{gaffect} the result to the last operand, then restore the initial \kbd{avma}. You can assign ordinary C long integers into a PARI object (not necessarily of type \typ{INT}) using \fun{void}{gaffsg}{long s, GEN y} \misctitle{Note} Due to the requirements mentioned above, it is usually a bad idea to use \tet{gaffect} statements. There is one exception: for simple objects (e.g.~leaves) whose size is controlled, they can be easier to use than \kbd{gerepile}, and about as efficient. \misctitle{Coercion} It is often useful to coerce an inexact object to a given precision. For instance at the beginning of a routine where precision can be kept to a minimum; otherwise the precision of the input is used in all subsequent computations, which is inefficient if the latter is known to thousands of digits. One may use the \kbd{gaffect} function for this, but it is easier and more efficient to call \fun{GEN}{gtofp}{GEN x, long prec} converts the complex number~\kbd{x} (\typ{INT}, \typ{REAL}, \typ{FRAC}, \typ{QUAD} or \typ{COMPLEX}) to either a \typ{REAL} or \typ{COMPLEX} whose components are \typ{REAL} of length \kbd{prec}. \subsec{Copy} It is also very useful to \idx{copy} a PARI object, not just by moving around a pointer as in the \kbd{y = x} example, but by creating a copy of the whole tree structure, without pre-allocating a possibly complicated \kbd{y} to use with \kbd{gaffect}. The function which does this is called \teb{gcopy}. Its syntax is: \fun{GEN}{gcopy}{GEN x} \noindent and the effect is to create a new copy of x on the PARI stack. Sometimes, on the contrary, a quick copy of the skeleton of \kbd{x} is enough, leaving pointers to the original data in \kbd{x} for the sake of speed instead of making a full recursive copy. Use \fun{GEN}{shallowcopy}{GEN x} for this. Note that the result is not suitable for \tet{gerepileupto} ! Make sure at this point that you understand the difference between \kbd{y = x}, \kbd{y = gcopy(x)}, \kbd{y = shallowcopy(x)} and \kbd{gaffect(x,y)}. \subsec{Clones}\sidx{clone}\label{se:clone} Sometimes, it is more efficient to create a \emph{persistent} copy of a PARI object. This is not created on the stack but on the heap, hence unaffected by \tet{gerepile} and friends. The function which does this is called \teb{gclone}. Its syntax is: \fun{GEN}{gclone}{GEN x} A clone can be removed from the heap (thus destroyed) using \fun{void}{gunclone}{GEN x} \noindent No PARI object should keep references to a clone which has been destroyed! \subsec{Conversions}\sidx{conversions} The following functions convert C objects to PARI objects (creating them on the stack as usual): \fun{GEN}{stoi}{long s}: C \kbd{long} integer (``small'') to \typ{INT}. \fun{GEN}{dbltor}{double s}: C \kbd{double} to \typ{REAL}. The accuracy of the result is 19 decimal digits, i.e.~a type \typ{REAL} of length \kbd{DEFAULTPREC}, although on 32-bit machines only 16 of them are significant. \noindent We also have the converse functions: \fun{long}{itos}{GEN x}: \kbd{x} must be of type \typ{INT}, \fun{double}{rtodbl}{GEN x}: \kbd{x} must be of type \typ{REAL}, \noindent as well as the more general ones: \fun{long}{gtolong}{GEN x}, \fun{double}{gtodouble}{GEN x}. \section{Implementation of the PARI types} \label{se:impl} \noindent We now go through each type and explain its implementation. Let \kbd{z} be a \kbd{GEN}, pointing at a PARI object. In the following paragraphs, we will constantly mix two points of view: on the one hand, \kbd{z} is treated as the C pointer it is, on the other, as PARI's handle on some mathematical entity, so we will shamelessly write $\kbd{z} \ne 0$ to indicate that the \emph{value} thus represented is nonzero (in which case the \emph{pointer}~\kbd{z} is certainly non-\kbd{NULL}). We offer no apologies for this style. In fact, you had better feel comfortable juggling both views simultaneously in your mind if you want to write correct PARI programs. Common to all the types is the first codeword \kbd{z[0]}, which we do not have to worry about since this is taken care of by \kbd{cgetg}. Its precise structure depends on the machine you are using, but it always contains the following data: the \emph{internal type number}\sidx{type number} attached to the symbolic type name, the \emph{length} of the root in longwords, and a technical bit which indicates whether the object is a clone or not (see \secref{se:clone}). This last one is used by \kbd{gp} for internal garbage collecting, you will not have to worry about it. Some types have a second codeword, different for each type, which we will soon describe as we will shortly consider each of them in turn. \noindent The first codeword is handled through the following \emph{macros}: \fun{long}{typ}{GEN z} returns the type number of \kbd{z}. \fun{void}{settyp}{GEN z, long n} sets the type number of \kbd{z} to \kbd{n} (you should not have to use this function if you use \kbd{cgetg}). \fun{long}{lg}{GEN z} returns the length (in longwords) of the root of \kbd{z}. \fun{long}{setlg}{GEN z, long l} sets the length of \kbd{z} to \kbd{l}; you should not have to use this function if you use \kbd{cgetg}. \fun{void}{lg_increase}{GEN z} increase the length of \kbd{z} by 1; you should not have to use this function if you use \kbd{cgetg}. \fun{long}{isclone}{GEN z} is \kbd{z} a clone? \fun{void}{setisclone}{GEN z} sets the \emph{clone} bit. \fun{void}{unsetisclone}{GEN z} clears the \emph{clone} bit. \misctitle{Important remark} For the sake of efficiency, none of the codeword-handling macros check the types of their arguments even when there are stringent restrictions on their use. It is trivial to create invalid objects, or corrupt one of the ``universal constants'' (e.g. setting the sign of \kbd{gen\_0} to $1$), and they usually provide negligible savings. Use higher level functions whenever possible. \misctitle{Remark} The clone bit is there so that \kbd{gunclone} can check it is deleting an object which was allocated by \kbd{gclone}. Miscellaneous vector entries are often cloned by \kbd{gp} so that a GP statement like \kbd{v[1] = x} does not involve copying the whole of \kbd{v}: the component \kbd{v[1]} is deleted if its clone bit is set, and is replaced by a clone of \kbd{x}. Don't set/unset yourself the clone bit unless you know what you are doing: in particular \emph{never} set the clone bit of a vector component when the said vector is scheduled to be uncloned. Hackish code may abuse the clone bit to tag objects for reasons unrelated to the above instead of using proper data structures. Don't do that. \subsec{Type \typ{INT} (integer)} \sidx{integer}\kbdsidx{t_INT}this type has a second codeword \kbd{z[1]} which contains the following information: the sign of \kbd{z}: coded as $1$, $0$ or $-1$ if $\kbd{z} > 0$, $\kbd{z} = 0$, $\kbd{z} < 0$ respectively. the \emph{effective length} of \kbd{z}, i.e.~the total number of significant longwords. This means the following: apart from the integer 0, every integer is ``normalized'', meaning that the most significant mantissa longword is non-zero. However, the integer may have been created with a longer length. Hence the ``length'' which is in \kbd{z[0]} can be larger than the ``effective length'' which is in \kbd{z[1]}. \noindent This information is handled using the following macros: \fun{long}{signe}{GEN z} returns the sign of \kbd{z}. \fun{void}{setsigne}{GEN z, long s} sets the sign of \kbd{z} to \kbd{s}. \fun{long}{lgefint}{GEN z} returns the \idx{effective length} of \kbd{z}. \fun{void}{setlgefint}{GEN z, long l} sets the effective length of \kbd{z} to \kbd{l}. The integer 0 can be recognized either by its sign being~0, or by its effective length being equal to~2. Now assume that $\kbd{z} \ne 0$, and let $$ |z| = \sum_{i = 0}^n z_i B^i, \quad\text{where}~z_n\ne 0~\text{and}~B = 2^{\kbd{BITS\_IN\_LONG}}. $$ With these notations, $n$ is \kbd{lgefint(z) - 3}, and the mantissa of $\kbd{z}$ may be manipulated via the following interface: \fun{GEN}{int_MSW}{GEN z} returns a pointer to the most significant word of \kbd{z}, $z_n$. \fun{GEN}{int_LSW}{GEN z} returns a pointer to the least significant word of \kbd{z}, $z_0$. \fun{GEN}{int_W}{GEN z, long i} returns the $i$-th significant word of \kbd{z}, $z_i$. Accessing the $i$-th significant word for $i > n$ yields unpredictable results. \fun{GEN}{int_W_lg}{GEN z, long i, long lz} returns the $i$-th significant word of \kbd{z}, $z_i$, assuming \kbd{lgefint(z)} is \kbd{lz} ($= n + 3$). Accessing the $i$-th significant word for $i > n$ yields unpredictable results. \fun{GEN}{int_precW}{GEN z} returns the previous (less significant) word of \kbd{z}, $z_{i-1}$ assuming \kbd{z} points to $z_i$. \fun{GEN}{int_nextW}{GEN z} returns the next (more significant) word of \kbd{z}, $z_{i+1}$ assuming \kbd{z} points to $z_i$. Unnormalized integers, such that $z_n$ is possibly $0$, are explicitly forbidden. To enforce this, one may write an arbitrary mantissa then call \fun{void}{int_normalize}{GEN z, long known0} \noindent normalizes in place a non-negative integer (such that $z_n$ is possibly $0$), assuming at least the first \kbd{known0} words are zero. \noindent For instance a binary \kbd{and} could be implemented in the following way: \bprog GEN AND(GEN x, GEN y) { long i, lx, ly, lout; long *xp, *yp, *outp; /* mantissa pointers */ GEN out; if (!signe(x) || !signe(y)) return gen_0; lx = lgefint(x); xp = int_LSW(x); ly = lgefint(y); yp = int_LSW(y); lout = min(lx,ly); /* > 2 */ out = cgeti(lout); out[1] = evalsigne(1) | evallgefint(lout); outp = int_LSW(out); for (i=2; i < lout; i++) { *outp = (*xp) & (*yp); outp = int_nextW(outp); xp = int_nextW(xp); yp = int_nextW(yp); } if ( !*int_MSW(out) ) out = int_normalize(out, 1); return out; } @eprog \noindent This low-level interface is mandatory in order to write portable code since PARI can be compiled using various multiprecision kernels, for instance the native one or GNU MP, with incompatible internal structures (for one thing, the mantissa is oriented in different directions). \subsec{Type \typ{REAL} (real number)} \kbdsidx{t_REAL}\sidx{real number}this type has a second codeword z[1] which also encodes its sign, obtained or set using the same functions as for a \typ{INT}, and a binary exponent. This exponent is handled using the following macros: \fun{long}{expo}{GEN z} returns the exponent of \kbd{z}. This is defined even when \kbd{z} is equal to zero. \fun{void}{setexpo}{GEN z, long e} sets the exponent of \kbd{z} to \kbd{e}. \noindent Note the functions: \fun{long}{gexpo}{GEN z} which tries to return an exponent for \kbd{z}, even if \kbd{z} is not a real number. \fun{long}{gsigne}{GEN z} which returns a sign for \kbd{z}, even when \kbd{z} is neither real nor integer (a rational number for instance). The real zero is characterized by having its sign equal to 0. If \kbd{z} is not equal to~0, then it is represented as $2^e M$, where $e$ is the exponent, and $M\in [1, 2[$ is the mantissa of $z$, whose digits are stored in $\kbd{z[2]},\dots, \kbd{z[lg(z)-1]}$. More precisely, let $m$ be the integer (\kbd{z[2]},\dots, \kbd{z[lg(z)-1]}) in base \kbd{2\pow BITS\_IN\_LONG}; here, \kbd{z[2]} is the most significant longword and is normalized, i.e.~its most significant bit is~1. Then we have $M := m / 2^{\kbd{bit\_accuracy(lg(z))} - 1 - \kbd{expo}(z)}$. \fun{GEN}{mantissa_real}{GEN z, long *e} returns the mantissa $m$ of $z$, and sets \kbd{*e} to the exponent $\kbd{bit\_accuracy(lg(z))}-1-\kbd{expo}(z)$, so that $z = m / 2^e$. Thus, the real number $3.5$ to accuracy \kbd{bit\_accuracy(lg(z))} is represented as \kbd{z[0]} (encoding $\kbd{type} = \typ{REAL}$, \kbd{lg(z)}), \kbd{z[1]} (encoding $\kbd{sign} = 1$, $\kbd{expo} = 1$), $\kbd{z[2]} = \kbd{0xe0000000}$, $\kbd{z[3]} =\dots = \kbd{z[lg(z)-1]} = \kbd{0x0}$. \subsec{Type \typ{INTMOD}}\kbdsidx{t_INTMOD} \kbd{z[1]} points to the modulus, and \kbd{z[2]} at the number representing the class \kbd{z}. Both are separate \kbd{GEN} objects, and both must be \typ{INT}s, satisfying the inequality $0 \le \kbd{z[2]} < \kbd{z[1]}$. \subsec{Type \typ{FRAC} (rational number)}% \kbdsidx{t_FRAC}\sidx{rational number} \kbd{z[1]} points to the numerator $n$, and \kbd{z[2]} to the denominator $d$. Both must be of type \typ{INT} such that $n\neq 0$, $d > 0$ and $(n,d) = 1$. \subsec{Type \typ{FFELT} (finite field element)}% \kbdsidx{t_FFELT}\sidx{finite field element} (Experimental) Components of this type should normally not be accessed directly. Instead, finite field elements should be created using \kbd{ffgen}. \noindent The second codeword \kbd{z[1]} determines the storage format of the element, among \item \tet{t_FF_FpXQ}: \kbd{A=z[2]} and \kbd{T=z[3]} are \kbd{FpX}, \kbd{p=z[4]} is a \typ{INT}, where $p$ is a prime number, $T$ is irreducible modulo $p$, and $\deg A < \deg T$. This represents the element $A\pmod{T}$ in $\F_p[X]/T$. \item \tet{t_FF_Flxq}: \kbd{A=z[2]} and \kbd{T=z[3]} are \kbd{Flx}, \kbd{l=z[4]} is a \typ{INT}, where $l$ is a prime number, $T$ is irreducible modulo $l$, and $\deg A < \deg T$ This represents the element $A\pmod{T}$ in $\F_l[X]/T$. \item \tet{t_FF_F2xq}: \kbd{A=z[2]} and \kbd{T=z[3]} are \kbd{F2x}, \kbd{l=z[4]} is the \typ{INT} $2$, $T$ is irreducible modulo $2$, and $\deg A < \deg T$. This represents the element $A\pmod{T}$ in $\F_2[X]/T$. \subsec{Type \typ{COMPLEX} (complex number)}% \kbdsidx{t_COMPLEX}\sidx{complex number} \kbd{z[1]} points to the real part, and \kbd{z[2]} to the imaginary part. The components \kbd{z[1]} and \kbd{z[2]} must be of type \typ{INT}, \typ{REAL} or \typ{FRAC}. For historical reasons \typ{INTMOD} and \typ{PADIC} are also allowed (the latter for $p = 2$ or congruent to 3 mod 4 only), but one should rather use the more general \typ{POLMOD} construction. \subsec{Type \typ{PADIC} ($p$-adic numbers)}% \sidx{p-adic number}\kbdsidx{t_PADIC} this type has a second codeword \kbd{z[1]} which contains the following information: the $p$-adic precision (the exponent of $p$ modulo which the $p$-adic unit corresponding to \kbd{z} is defined if \kbd{z} is not~0), i.e.~one less than the number of significant $p$-adic digits, and the exponent of \kbd{z}. This information can be handled using the following functions: \fun{long}{precp}{GEN z} returns the $p$-adic precision of \kbd{z}. This is $0$ if $\kbd{z} = 0$. \fun{void}{setprecp}{GEN z, long l} sets the $p$-adic precision of \kbd{z} to \kbd{l}. \fun{long}{valp}{GEN z} returns the $p$-adic valuation of \kbd{z} (i.e. the exponent). This is defined even if \kbd{z} is equal to~0. \fun{void}{setvalp}{GEN z, long e} sets the $p$-adic valuation of \kbd{z} to \kbd{e}. In addition to this codeword, \kbd{z[2]} points to the prime $p$, \kbd{z[3]} points to $p^{\text{precp(z)}}$, and \kbd{z[4]} points to a\typ{INT} representing the $p$-adic unit attached to \kbd{z} modulo \kbd{z[3]} (and to zero if \kbd{z} is zero). To summarize, if $z\neq 0$, we have the equality: $$ \kbd{z} = p^{\text{valp(z)}} * (\kbd{z[4]} + O(\kbd{z[3]})),\quad \text{where}\quad \kbd{z[3]} = O(p^{\text{precp(z)}}). $$ \subsec{Type \typ{QUAD} (quadratic number)} \sidx{quadratic number}\kbdsidx{t_QUAD}\kbd{z[1]} points to the canonical polynomial $P$ defining the quadratic field (as output by \tet{quadpoly}), \kbd{z[2]} to the ``real part'' and \kbd{z[3]} to the ``imaginary part''. The latter are of type \typ{INT}, \typ{FRAC}, \typ{INTMOD}, or \typ{PADIC} and are to be taken as the coefficients of \kbd{z} with respect to the canonical basis $(1,X)$ of $\Q[X]/(P(X))$. Exact complex numbers may be implemented as quadratics, but \typ{COMPLEX} is in general more versatile (\typ{REAL} components are allowed) and more efficient. Operations involving a \typ{QUAD} and \typ{COMPLEX} are implemented by converting the \typ{QUAD} to a \typ{REAL} (or \typ{COMPLEX} with \typ{REAL} components) to the accuracy of the \typ{COMPLEX}. As a consequence, operations between \typ{QUAD} and \emph{exact} \typ{COMPLEX}s are not allowed. \subsec{Type \typ{POLMOD} (polmod)}\kbdsidx{t_POLMOD}\sidx{polmod} as for \typ{INTMOD}s, \kbd{z[1]} points to the modulus, and \kbd{z[2]} to a polynomial representing the class of~\kbd{z}. Both must be of type \typ{POL} in the same variable, satisfying the inequality $\deg \kbd{z[2]} < \deg \kbd{z[1]}$. However, \kbd{z[2]} is allowed to be a simplification of such a polynomial, e.g.~a scalar. This is tricky considering the hierarchical structure of the variables; in particular, a polynomial in variable of \emph{lesser} priority (see \secref{se:vars}) than the modulus variable is valid, since it is considered as the constant term of a polynomial of degree 0 in the correct variable. On the other hand a variable of \emph{greater} priority is not acceptable. \subsec{Type \typ{POL} (polynomial)}\kbdsidx{t_POL}\sidx{polynomial} this type has a second codeword. It contains a ``\emph{sign}'': 0 if the polynomial is equal to~0, and 1 if not (see however the important remark below) and a \emph{variable number} (e.g.~0 for $x$, 1 for $y$, etc\dots). \noindent These data can be handled with the following macros: \teb{signe} and \teb{setsigne} as for \typ{INT} and \typ{REAL}, \fun{long}{varn}{GEN z} returns the variable number of the object \kbd{z}, \fun{void}{setvarn}{GEN z, long v} sets the variable number of \kbd{z} to \kbd{v}. The variable numbers encode the relative priorities of variables, we will give more details in \secref{se:vars}. Note also the function \fun{long}{gvar}{GEN z} which tries to return a \idx{variable number} for \kbd{z}, even if \kbd{z} is not a polynomial or power series. The variable number of a scalar type is set by definition equal to \tet{NO_VARIABLE}, which has lower priority than any other variable number. The components \kbd{z[2]}, \kbd{z[3]},\dots \kbd{z[lg(z)-1]} point to the coefficients of the polynomial \emph{in ascending order}, with \kbd{z[2]} being the constant term and so on. For a \typ{POL} of non-zero sign, \tet{degpol}, \tet{leading_coeff}, \tet{constant_coeff}, return its degree, and a pointer to the leading, resp. constant, coefficient with respect to the main variable. Note that no copy is made on the PARI stack so the returned value is not safe for a basic \kbd{gerepile} call. Applied to any other type than \typ{POL}, the result is unspecified. Those three functions are still defined when the sign is $0$, see \secref{se:accessors} and \secref{se:polynomials}. \fun{long}{degree}{GEN x} returns the degree of \kbd{x} with respect to its main variable even when \kbd{x} is not a polynomial (a rational function for instance). By convention, the degree of a zero polynomial is~$-1$. \misctitle{Important remark} The leading coefficient of a \typ{POL} may be equal to zero: \item it is not allowed to be an exact rational $0$, such as \tet{gen_0}; \item an exact non-rational $0$, like \kbd{Mod(0,2)}, is possible for constant polynomials, i.e. of length $3$ and no other coefficient: this carries information about the base ring for the polynomial; \item an inexact $0$, like \kbd{0.E-38} or \kbd{O(3\pow 5)}, is always possible. Inexact zeroes do not correspond to an actual $0$, but to a very small coefficient according to some metric; we keep them to give information on how much cancellation occurred in previous computations. A polynomial disobeying any of these rules is an invalid \emph{unnormalized} object. We advise \emph{not} to use low-level constructions to build a \typ{POL} coefficient by coefficient, such as \bprog GEN T = cgetg(4, t_POL); T[1] = evalvarn(0); gel(T, 2) = x; gel(T, 3) = y; @eprog\noindent But if you do and it is not clear whether the result will be normalized, call \fun{GEN}{normalizepol}{GEN x} applied to an unnormalized \typ{POL}~\kbd{x} (with all coefficients correctly set except that \kbd{leading\_term(x)} might be zero), normalizes \kbd{x} correctly in place and returns~\kbd{x}. This functions sets \kbd{signe} (to $0$ or $1$) properly. \misctitle{Caveat} A consequence of the remark above is that zero polynomials are characterized by the fact that their sign is~0. It is in general incorrect to check whether \kbd{lg(x)} is $2$ or \kbd{degpol(x)} $< 0$, although both tests are valid when the coefficient types are under control: for instance, when they are guaranteed to be \typ{INT}s or \typ{FRAC}s. The same remark applies to \typ{SER}s. \subsec{Type \typ{SER} (power series)} \kbdsidx{t_SER}\sidx{power series}This type also has a second codeword, which encodes a ``\emph{sign}'', i.e.~0 if the power series is 0, and 1 if not, a \emph{variable number} as for polynomials, and an \emph{exponent}. This information can be handled with the following functions: \teb{signe}, \teb{setsigne}, \teb{varn}, \teb{setvarn} as for polynomials, and \teb{valp}, \teb{setvalp} for the exponent as for $p$-adic numbers. Beware: do \emph{not} use \teb{expo} and \teb{setexpo} on power series. The coefficients \kbd{z[2]}, \kbd{z[3]},\dots \kbd{z[lg(z)-1]} point to the coefficients of \kbd{z} in ascending order. As for polynomials (see remark there), the sign of a \typ{SER} is $0$ if and only all its coefficients are equal to $0$. (The leading coefficient cannot be an integer $0$.) A series whose coefficients are integers equal to zero is represented as $O(x^n)$ (\kbd{zeroser}$(\var{vx},n)$). A series whose coefficients are exact zeroes, but not all of them integers (e.g. an \typ{INTMOD} such as \kbd{Mod(0,2)}) is represented as $z*x^{n-1} +O(x^n)$, where $z$ is the $0$ of the base ring, as per \tet{Rg_get_0}. Note that the exponent of a power series can be negative, i.e.~we are then dealing with a Laurent series (with a finite number of negative terms). \subsec{Type \typ{RFRAC} (rational function)}% \kbdsidx{t_RFRAC}\sidx{rational function} \kbd{z[1]} points to the numerator $n$, and \kbd{z[2]} on the denominator $d$. The denominator must be of type \typ{POL}, with variable of higher priority than the numerator. The numerator $n$ is not an exact $0$ and $(n,d) = 1$ (see \tet{gred_rfac2}). \subsec{Type \typ{QFR} (indefinite binary quadratic form)}% \kbdsidx{t_QFR}\sidx{indefinite binary quadratic form} \kbd{z[1]}, \kbd{z[2]}, \kbd{z[3]} point to the three coefficients of the form and are of type \typ{INT}. \kbd{z[4]} is Shanks's distance function, and must be of type \typ{REAL}. \subsec{Type \typ{QFI} (definite binary quadratic form)}% \kbdsidx{t_QFI}\sidx{definite binary quadratic form} \kbd{z[1]}, \kbd{z[2]}, \kbd{z[3]} point to the three coefficients of the form. All three are of type \typ{INT}. \subsec{Type \typ{VEC} and \typ{COL} (vector)}% \kbdsidx{t_VEC}\kbdsidx{t_COL}\sidx{row vector}\sidx{column vector} \kbd{z[1]}, \kbd{z[2]},\dots \kbd{z[lg(z)-1]} point to the components of the vector. \subsec{Type \typ{MAT} (matrix)}\kbdsidx{t_MAT}\sidx{matrix} \kbd{z[1]}, \kbd{z[2]},\dots \kbd{z[lg(z)-1]} point to the column vectors of \kbd{z}, i.e.~they must be of type \typ{COL} and of the same length. \subsec{Type \typ{VECSMALL} (vector of small integers)}\kbdsidx{t_VECSMALL} \kbd{z[1]}, \kbd{z[2]},\dots \kbd{z[lg(z)-1]} are ordinary signed long integers. This type is used instead of a \typ{VEC} of \typ{INT}s for efficiency reasons, for instance to implement efficiently permutations, polynomial arithmetic and linear algebra over small finite fields, etc. \subsec{Type \typ{STR} (character string)}% \kbdsidx{t_STR}\sidx{character string} \fun{char *}{GSTR}{z} (= \kbd{(z+1)}) points to the first character of the (\kbd{NULL}-terminated) string. \subsec{Type \typ{ERROR} (error context)}\kbdsidx{t_ERROR}\sidx{error context} This type holds error messages, as well as details about the error, as returned by the exception handling system. The second codeword \kbd{z[1]} contains the error type (an \kbd{int}, as passed to \tet{pari_err}). The subsequent words \kbd{z[2]},\dots \kbd{z[lg(z)-1]} are \kbd{GEN}s containing additional data, depending on the error type. \subsec{Type \typ{CLOSURE} (closure)}\kbdsidx{t_CLOSURE}\sidx{closure} This type holds GP functions and closures, in compiled form. The internal detail of this type is subject to change each time the GP language evolves. Hence we do not describe it here and refer to the Developer's Guide. However functions to create or to evaluate \typ{CLOSURE}s are documented in \secref{se:closure}. \fun{long}{closure_arity}{GEN C} returns the arity of the \typ{CLOSURE}. \fun{long}{closure_is_variadic}{GEN C} returns $1$ if the closure \kbd{C} is variadic, $0$ else. \subsec{Type \typ{INFINITY} (infinity)}\kbdsidx{t_INFINITY}\sidx{infinity} This type has a single \typ{INT} component, which is either $1$ or $-1$, corresponding to $+\infty$ and $-\infty$ respectively. \fun{GEN}{mkmoo}{} returns $-\infty$ \fun{GEN}{mkoo}{} returns $\infty$ \fun{long}{inf_get_sign}{GEN x} returns $1$ if $x$ is $+\infty$, and $-1$ if $x$ is $-\infty$. \subsec{Type \typ{LIST} (list)}\kbdsidx{t_LIST}\sidx{list} this type was introduced for specific \kbd{gp} use and is rather inefficient compared to a straightforward linked list implementation (it requires more memory, as well as many unnecessary copies). Hence we do not describe it here and refer to the Developer's Guide. \misctitle{Implementation note} For the types including an exponent (or a valuation), we actually store a biased non-negative exponent (bit-ORing the biased exponent to the codeword), obtained by adding a constant to the true exponent: either \kbd{HIGHEXPOBIT} (for \typ{REAL}) or \kbd{HIGHVALPBIT} (for \typ{PADIC} and \typ{SER}). Of course, this is encapsulated by the exponent/valuation-handling macros and needs not concern the library user. \section{PARI variables}\label{se:vars} \subsec{Multivariate objects} \sidx{variable (priority)} \noindent We now consider variables and formal computations. As we have seen in \secref{se:impl}, the codewords for types \typ{POL} and \typ{SER} encode a ``variable number''. This is an integer, ranging from $0$ to \kbd{MAXVARN}. Relative priorities may be ascertained using \fun{int}{varncmp}{long v, long w} \noindent which is $>0$, $=0$, $<0$ whenever $v$ has lower, resp.~same, resp.~higher priority than $w$. The way an object is considered in formal computations depends entirely on its ``principal variable number'' which is given by the function \fun{long}{gvar}{GEN z} \noindent which returns a \idx{variable number} for \kbd{z}, even if \kbd{z} is not a polynomial or power series. The variable number of a scalar type is set by definition equal to \tet{NO_VARIABLE} which has lower priority than any valid variable number. The variable number of a recursive type which is not a polynomial or power series is the variable number with highest priority among its components. But for polynomials and power series only the ``outermost'' number counts (we directly access $\tet{varn}(x)$ in the codewords): the representation is not symmetrical at all. Under \kbd{gp}, one needs not worry too much since the interpreter defines the variables as it sees them\footnote{*}{The first time a given identifier is read by the GP parser a new variable is created, and it is assigned a strictly lower priority than any variable in use at this point. On startup, before any user input has taken place, 'x' is defined in this way and has initially maximal priority (and variable number $0$).} % and do the right thing with the polynomials produced. But in library mode, they are tricky objects if you intend to build polynomials yourself (and not just let PARI functions produce them, which is less efficient). For instance, it does not make sense to have a variable number occur in the components of a polynomial whose main variable has a lower priority, even though PARI cannot prevent you from doing it. \subsec{Creating variables} A basic difficulty is to ``create'' a variable. Some initializations are needed before you can use a given integer $v$ as a variable number. Initially, this is done for $0$ and $1$ (the variables \kbd{x} and \kbd{y} under \kbd{gp}), and $2,\dots,9$ (printed as \kbd{t2}, \dots \kbd{t9}), with decreasing priority. \subsubsec{User variables}\sidx{variable (user)} When the program starts, \kbd{x} (number~$0$) and \kbd{y} (number~$1$) are the only available variables, numbers $2$ to $9$ (decreasing priority) are reserved for building polynomials with predictable priorities. To define further ones, you may use \fun{GEN}{varhigher}{const char *s} \fun{GEN}{varlower}{const char *s} to recover a monomial of degree $1$ in a new variable, which is guaranteed to have higer (resp.~lower) priority than all existing ones at the time of the function call. The variable is printed as $s$, but is not part of GP's interpreter: it is not a symbol bound to a value. On the other hand \fun{long}{fetch_user_var}{char *s}: inspects the user variable whose name is the string pointed to by \kbd{s}, creating it if needed, and returns its variable number. \bprog long v = fetch_user_var("y"); GEN gy = pol_x(v); @eprog\noindent The function raises an exception if the name is already in use for an \tet{install}ed or built-in function, or an alias. This function is mostly useless since it returns a variable with unpredictable priority. Don't use it to create new variables. \misctitle{Caveat} You can use \tet{gp_read_str} (see~\secref{se:gp_read_str}) to execute a GP command and create GP variables on the fly as needed: \bprog GEN gy = gp_read_str("'y"); /*@Ccom returns \kbd{pol\_x}($v$), for some $v$ */ long v = varn(gy); @eprog\noindent But please note the quote \kbd{'y} in the above. Using \kbd{gp\_read\_str("y")} might work, but is dangerous, especially when programming functions to be used under \kbd{gp}. The latter reads the value of \kbd{y}, as \emph{currently} known by the \kbd{gp} interpreter, possibly creating it in the process. But if \kbd{y} has been modified by previous \kbd{gp} commands (e.g.~\kbd {y = 1}), then the value of \kbd{gy} is not what you expected it to be and corresponds instead to the current value of the \kbd{gp} variable (e.g.~\kbd{gen\_1}). \fun{GEN}{fetch_var_value}{long v} returns a shallow copy of the current value of the variable numbered $v$. Returns \kbd{NULL} if that variable number is unknown to the interpreter, e.g. it is a user variable. Note that this may not be the same as \kbd{pol\_x(v)} if assignments have been performed in the interpreter. \subsubsec{Temporary variables}\sidx{variable (temporary)} You can create temporary variables using \fun{long}{fetch_var}{} returns a new variable with \emph{lower} priority than any variable currently in use. \fun{long}{fetch_var_higher}{} returns a new variable with \emph{higher} priority than any variable currently in use. \noindent After the statement \kbd{v = fetch\_var()}, you can use \kbd{pol\_1(v)} and \kbd{pol\_x(v)}. The variables created in this way have no identifier assigned to them though, and are printed as \kbd{t\text{number}}. You can assign a name to a temporary variable, after creating it, by calling the function \fun{void}{name_var}{long n, char *s} \noindent after which the output machinery will use the name \kbd{s} to represent the variable number~\kbd{n}. The GP parser will \emph{not} recognize it by that name, however, and calling this on a variable known to~\kbd{gp} raises an error. Temporary variables are meant to be used as free variables to build polynomials and power series, and you should never assign values or functions to them as you would do with variables under~\kbd{gp}. For that, you need a user variable. All objects created by \kbd{fetch\_var} are on the heap and not on the stack, thus they are not subject to standard garbage collecting (they are not destroyed by a \kbd{gerepile} or \kbd{avma = ltop} statement). When you do not need a variable number anymore, you can delete it using \fun{long}{delete_var}{} \noindent which deletes the \emph{latest} temporary variable created and returns the variable number of the previous one (or simply returns 0 if none remain). Of course you should make sure that the deleted variable does not appear anywhere in the objects you use later on. Here is an example: \bprog long first = fetch_var(); long n1 = fetch_var(); long n2 = fetch_var(); /*@Ccom prepare three variables for internal use */ ... /*@Ccom delete all variables before leaving */ do { num = delete_var(); } while (num && num <= first); @eprog\noindent The (dangerous) statement \bprog while (delete_var()) /*@Ccom empty */; @eprog\noindent removes all temporary variables in use. \subsec{Comparing variables} Let us go back to \kbd{varncmp}. There is an interesting corner case, when one of the compared variables (from \kbd{gvar}, say) is \kbd{NO\_VARIABLE}. In this case, \kbd{varncmp} declares it has lower priority than any other variable; of course, comparing \kbd{NO\_VARIABLE} with itself yields $0$ (same priority); In addition to \kbd{varncmp} we have \fun{long}{varnmax}{long v, long w} given two variable numbers (possibly \kbd{NO\_VARIABLE}), returns the variable with the highest priority. This function always returns a valid variable number unless it is comparing \kbd{NO\_VARIABLE} to itself. \fun{long}{varnmin}{long x, long y} given two variable numbers (possibly \kbd{NO\_VARIABLE}), returns the variable with the lowest priority. Note that when comparing a true variable with \kbd{NO\_VARIABLE}, this function returns \kbd{NO\_VARIABLE}, which is not a valid variable number. \section{Input and output} \noindent Two important aspects have not yet been explained which are specific to library mode: input and output of PARI objects. \subsec{Input} \noindent For \idx{input}, PARI provides several powerful high level functions which enable you to input your objects as if you were under \kbd{gp}. In fact, it \emph{is} essentially the GP syntactical parser. There are two similar functions available to parse a string: \fun{GEN}{gp_read_str}{const char *s}\label{se:gp_read_str} \fun{GEN}{gp_read_str_multiline}{const char *s, char *last} \noindent Both functions read the whole string \kbd{s}. The function \kbd{gp\_read\_str} ignores newlines: it assumes that the input is one expression and returns the result of this expression. The function \kbd{gp\_read\_str\_multiline} processes the text in the same way as the GP command \tet{read}: newlines are significant and can be used to separate expressions. The return value is that of the last non-empty expression evaluated. In \kbd{gp\_read\_str\_multiline}, if \kbd{last} is non-\kbd{NULL}, then \kbd{*last} receives the last character from the \emph{filtered} input: this can be used to check if the last character was a semi-colon (to hide the output in interactive usage). If (and only if) the input contains no statements, then \kbd{*last} is set to \kbd{0}. For both functions, \kbd{gp}'s metacommands \emph{are} recognized. \misctitle{Note} The obsolete form \fun{GEN}{readseq}{char *t} still exists for backward compatibility (assumes filtered input, without spaces or comments). Don't use it. To read a \kbd{GEN} from a file, you can use the simpler interface \fun{GEN}{gp_read_stream}{FILE *file} \noindent which reads a character string of arbitrary length from the stream \kbd{file} (up to the first complete expression sequence), applies \kbd{gp\_read\_str} to it, and returns the resulting \kbd{GEN}. This way, you do not have to worry about allocating buffers to hold the string. To interactively input an expression, use \kbd{gp\_read\_stream(stdin)}. Finally, you can read in a whole file, as in GP's \tet{read} statement \fun{GEN}{gp_read_file}{char *name} \noindent As usual, the return value is that of the last non-empty expression evaluated. There is one technical exception: if \kbd{name} is a \emph{binary} file (from \tet{writebin}) containing more than one object, a \typ{VEC} containing them all is returned. This is because binary objects bypass the parser, hence reading them has no useful side effect. \subsec{Output to screen or file, output to string}\sidx{output} General output functions return nothing but print a character string as a side effect. Low level routines are available to write on PARI output stream \tet{pari_outfile} (\tet{stdout} by default): \fun{void}{pari_putc}{char c}: write character \kbd{c} to the output stream. \fun{void}{pari_puts}{char *s}: write \kbd{s} to the output stream. \fun{void}{pari_flush}{}: flush output stream; most streams are buffered by default, this command makes sure that all characters output so are actually written. \fun{void}{pari_printf}{const char *fmt, ...}: the most versatile such function. \kbd{fmt} is a character string similar to the one \tet{printf} uses. In there, \kbd{\%} characters have a special meaning, and describe how to print the remaining operands. In addition to the standard format types (see the GP function \tet{printf}), you can use the \emph{length modifier}~\kbd{P} (for PARI of course!) to specify that an argument is a \kbd{GEN}. For instance, the following are valid conversions for a \kbd{GEN} argument \bprog %Ps @com convert to \kbd{char*} (will print an arbitrary \kbd{GEN}) %P.10s @com convert to \kbd{char*}, truncated to 10 chars %P.2f @com convert to floating point format with 2 decimals %P4d @com convert to integer, field width at least 4 pari_printf("x[%d] = %Ps is not invertible!\n", i, gel(x,i)); @eprog\noindent Here \kbd{i} is an \kbd{int}, \kbd{x} a \kbd{GEN} which is not a leaf (presumably a vector, or a polynomial) and this would insert the value of its $i$-th \kbd{GEN} component: \kbd{gel(x,i)}. \noindent Simple but useful variants to \kbd{pari\_printf} are \fun{void}{output}{GEN x} prints \kbd{x} in raw format, followed by a newline and a buffer flush. This is more or less equivalent to \bprog pari_printf("%Ps\n", x); pari_flush(); @eprog \fun{void}{outmat}{GEN x} as above except if $x$ is a \typ{MAT}, in which case a multi-line display is used to display the matrix. This is prettier for small dimensions, but quickly becomes unreadable and cannot be pasted and reused for input. If all entries of $x$ are small integers, you may use the recursive features of \kbd{\%Pd} and obtain the same (or better) effect with \bprog pari_printf("%Pd\n", x); pari_flush(); @eprog\noindent A variant like \kbd{"\%5Pd"} would improve alignment by imposing 5 chars for each coefficient. Similarly if all entries are to be converted to floats, a format like \kbd{"\%5.1Pf"} could be useful. These functions write on (PARI's idea of) standard output, and must be used if you want your functions to interact nicely with \kbd{gp}. In most programs, this is not a concern and it is more flexible to write to an explicit \kbd{FILE*}, or to recover a character string: \fun{void}{pari_fprintf}{FILE *file, const char *fmt, ...} writes the remaining arguments to stream \kbd{file} according to the format specification \kbd{fmt}. \fun{char*}{pari_sprintf}{const char *fmt, ...} produces a string from the remaining arguments, according to the PARI format \kbd{fmt} (see \tet{printf}). This is the \kbd{libpari} equivalent of \tet{Strprintf}, and returns a \kbd{malloc}'ed string, which must be freed by the caller. Note that contrary to the analogous \tet{sprintf} in the \kbd{libc} you do not provide a buffer (leading to all kinds of buffer overflow concerns); the function provided is actually closer to the GNU extension \kbd{asprintf}, although the latter has a different interface. Simple variants of \tet{pari_sprintf} convert a \kbd{GEN} to a \kbd{malloc}'ed ASCII string, which you must still \kbd{free} after use: \fun{char*}{GENtostr}{GEN x}, using the current default output format (\kbd{prettymat} by default). \fun{char*}{GENtoTeXstr}{GEN x}, suitable for inclusion in a \TeX\ file. Note that we have \tet{va_list} analogs of the functions of \kbd{printf} type seen so far: \fun{void}{pari_vprintf}{const char *fmt, va_list ap} \fun{void}{pari_vfprintf}{FILE *file, const char *fmt, va_list ap} \fun{char*}{pari_vsprintf}{const char *fmt, va_list ap} \subsec{Errors}\sidx{error}\kbdsidx{e_MISC} \noindent If you want your functions to issue error messages, you can use the general error handling routine \tet{pari_err}. The basic syntax is % \bprog pari_err(e_MISC, "error message"); @eprog\noindent This prints the corresponding error message and exit the program (in library mode; go back to the \kbd{gp} prompt otherwise).\label{se:err} You can also use it in the more versatile guise \bprog pari_err(e_MISC, format, ...); @eprog\noindent where \kbd{format} describes the format to use to write the remaining operands, as in the \tet{pari_printf} function. For instance: \bprog pari_err(e_MISC, "x[%d] = %Ps is not invertible!", i, gel(x,i)); @eprog\noindent The simple syntax seen above is just a special case with a constant format and no remaining arguments. The general syntax is \fun{void}{pari_err}{numerr,...} \noindent where \kbd{numerr} is a codeword which specifies the error class and what to do with the remaining arguments and what message to print. For instance, if $x$ is a \kbd{GEN} with internal type \typ{STR}, say, \kbd{pari\_err(e\_TYPE,"extgcd", $x$)} prints the message: \bprog *** incorrect type in extgcd (t_STR), @eprog\noindent See \secref{se:errors} for details. In the libpari code itself, the general-purpose \kbd{e\_MISC} is used sparingly: it is so flexible that the corresponding error contexts (\typ{ERROR}) become hard to use reliably. Other more rigid error types are generally more useful: for instance the error context attached to the \kbd{e\_TYPE} exception above is precisely documented and contains \kbd{"extgcd"} and $x$ (not only its type) as readily available components. \subsec{Warnings} \noindent To issue a warning, use \fun{void}{pari_warn}{warnerr,...} In that case, of course, we do \emph{not} abort the computation, just print the requested message and go on. The basic example is % \bprog pari_warn(warner, "Strategy 1 failed. Trying strategy 2") @eprog\noindent which is the exact equivalent of \kbd{pari\_err(e\_MISC,...)} except that you certainly do not want to stop the program at this point, just inform the user that something important has occurred; in particular, this output would be suitably highlighted under \kbd{gp}, whereas a simple \kbd{printf} would not. The valid \emph{warning} keywords are \tet{warner} (general), \tet{warnprec} (increasing precision), \tet{warnmem} (garbage collecting) and \tet{warnfile} (error in file operation), used as follows: \bprog pari_warn(warnprec, "bnfinit", newprec); pari_warn(warnmem, "bnfinit"); pari_warn(warnfile, "close", "afile"); /* error when closing "afile" */ @eprog \subsec{Debugging output}\sidx{debugging}\sidx{format}\label{se:dbg_output} For debugging output, you can use the standard output functions, \tet{output} and \tet{pari_printf} mainly. Corresponding to the \kbd{gp} metacommand \kbd{\b x}, you can also output the \idx{hexadecimal tree} attached to an object: \fun{void}{dbgGEN}{GEN x, long nb = -1}, displays the recursive structure of \kbd{x}. If $\kbd{nb} = -1$, the full structure is printed, otherwise the leaves (non-recursive components) are truncated to \kbd{nb} words. \noindent The function \tet{output} is vital under debuggers, since none of them knows how to print PARI objects by default. Seasoned PARI developers add the following \kbd{gdb} macro to their \kbd{.gdbinit}: \bprog define i call output((GEN)$arg0) end @eprog\noindent Typing \kbd{i x} at a breakpoint in \kbd{gdb} then prints the value of the \kbd{GEN} \kbd{x} (provided the optimizer has not put it into a register, but it is rarely a good idea to debug optimized code). \noindent The global variables \teb{DEBUGLEVEL} and \teb{DEBUGMEM} (corresponding to the default \teb{debug} and \teb{debugmem}) are used throughout the PARI code to govern the amount of diagnostic and debugging output, depending on their values. You can use them to debug your own functions, especially if you \tet{install} the latter under \kbd{gp}. \fun{void}{dbg_pari_heap}{void} print debugging statements about the PARI stack, heap, and number of variables used. Corresponds to \kbd{\bs s} under gp. \subsec{Timers and timing output} \noindent To handle timings in a reentrant way, PARI defines a dedicated data type, \tet{pari_timer}, together with the following methods: \fun{void}{timer_start}{pari_timer *T} start (or reset) a timer. \fun{long}{timer_delay}{pari_timer *T} returns the number of milliseconds elapsed since the timer was last reset. Resets the timer as a side effect. \fun{long}{timer_get}{pari_timer *T} returns the number of milliseconds elapsed since the timer was last reset. Does \emph{not} reset the timer. \fun{long}{timer_printf}{pari_timer *T, char *format,...} This diagnostics function is equivalent to the following code \bprog err_printf("Time ") ... prints remaining arguments according to format ... err_printf(": %ld", timer_delay(T)); @eprog\noindent Resets the timer as a side effect. \noindent They are used as follows: \bprog pari_timer T; timer_start(&T); /* initialize timer */ ... printf("Total time: %ldms\n", timer_delay(&T)); @eprog\noindent or \bprog pari_timer T; timer_start(&T); for (i = 1; i < 10; i++) { ... timer_printf(&T, "for i = %ld (L[i] = %Ps)", i, gel(L,i)); } @eprog The following functions provided the same functionality, in a non-reentrant way, and are now deprecated. \fun{long}{timer}{void} \fun{long}{timer2}{void} \fun{void}{msgtimer}{const char *format, ...} The following function implements \kbd{gp}'s timer and should not be used in libpari programs: \fun{long}{gettime}{void} equivalent to \tet{timer_delay}$(T)$ attached to a private timer $T$. \section{Iterators, Numerical integration, Sums, Products} \subsec{Iterators} Since it is easier to program directly simple loops in library mode, some GP iterators are mainly useful for GP programming. Here are the others: \item \tet{fordiv} is a trivial iteration over a list produced by \tet{divisors}. \item \tet{forell} and \tet{forsubgroup} are currently not implemented as an iterator but as a procedure with callbacks. \fun{void}{forell}{void *E, long fun(void*, GEN), GEN a, GEN b} goes through the same curves as \tet{forell(ell,a,b,)}, calling \tet{fun(E, ell)} for each curve \kbd{ell}, stopping if \kbd{fun} returns a non-zero value. \fun{void}{forsubgroup}{void *E, long fun(void*, GEN), GEN G, GEN B} goes through the same subgroups as \tet{forsubgroup(H = G, B,)}, calling \tet{fun(E, H)} for each subgroup $H$, stopping if \kbd{fun} returns a non-zero value. \item \tet{forprime}, for which we refer you to the next subsection. \item \tet{forcomposite}, we provide an iterator over composite integers: \fun{int}{forcomposite}{forcomposite_t *T, GEN a, GEN b} initialize an iterator $T$ over composite integers in $[a,b]$; over composites $\geq a$ if $b = \kbd{NULL}$. Return $0$ if the range is known to be empty from the start (as if $b < a$ or $b < 0$), and return $1$ otherwise. \fun{GEN}{forcomposite_next}{forcomposite_t *T} returns the next composite in the range, assuming that $T$ was initialized by \tet{forcomposite_init}. \item \tet{forvec}, for which we provide a convenient iterator. To initialize the analog of \kbd{forvec(X = v, ..., flag)}, call \fun{int}{forvec_init}{forvec_t *T, GEN v, long flag} initialize an iterator $T$ over the vectors generated by \kbd{forvec(X = $v$,..., flag)}. This returns $0$ if this vector list is empty, and $1$ otherwise. \fun{GEN}{forvec_next}{forvec_t *T} returns the next element in the \kbd{forvec} sequence, or \kbd{NULL} if we are done. The return value must be used immediately or copied since the next call to the iterator destroys it: the relevant vector is updated in place. The iterator works hard to not use up PARI stack, and is more efficient when all lower bounds in the initialization vector $v$ are integers. In that case, the cost is linear in the number of tuples enumerated, and you can expect to run over more than $10^9$ tuples per minute. If speed is critical and all integers involved would fit in $C$ \kbd{long}s, write a simple direct backtracking algorithm yourself. \item \tet{forpart} is a variant of \kbd{forvec} which iterates over partitions. See the documentation of the \kbd{forpart} GP function for details. This function is available as a loop with callbacks: \fun{void}{forpart}{void *data, long (*call)(void*,GEN), long k, GEN a, GEN n} \noindent It is also available as an iterator: \fun{void}{forpart_init}{forpart_t *T, long k, GEN a, GEN n} initializes an iterator over the partitions of $k$, with length restricted by $n$, and components restricted by $a$, either of which can be set to \kbd{NULL} to run without restriction. \fun{GEN}{forpart_next}{forpart_t *T} returns the next partition, or \kbd{NULL} when all partitions have been exhausted. \fun{GEN}{forpart_prev}{forpart_t *T} returns the previous partition, or \kbd{NULL} when all partitions have been exhausted. In both cases, the partition must be used or copied before the next call since it is returned from a state array which will be modified in place. You may \emph{not} mix calls to \tet{forpart_next} and \tet{forpart_prev}: the first one called determines the ordering used to iterate over the partitions; you can not go back since the \tet{forpart_t} structure is used in incompatible ways. \item \tet{forperm} to loop over permutations of $k$. See the documentation of the \kbd{forperm} GP function for details. This function is available as an iterator: \fun{void}{forperm_init}{forperm_t *T, GEN k} initializes an iterator over the permutations of $k$ (\typ{INT}, \typ{VEC} or \typ{VECSMALL}). \fun{GEN}{forperm_next}{forperm_t *T} returns the next permutation as a \typ{VECSMALL} or \kbd{NULL} whell all permutations have been exhausted. The permutation must be used or copied before the next call since it is returned from a state array which will be modified in place. \item \tet{forsubset} to loop over subsets. See the documentation of the \kbd{forsubset} GP function for details. This function is available as two iterators: \fun{void}{forallsubset_init}{forsubset_t *T, long n} \fun{void}{forksubset_init}{forsubset_t *T, long n, long k} \noindent It is also available in generic form: \fun{void}{forsubset_init}{forsubset_t *T, GEN nk} where \kbd{nk} is either a \typ{INT} $n$ or a \typ{VEC} with two integral components $[n,k]$. In all three cases, \fun{GEN}{forsubset_next}{forsubset_t *T} returns the next subset as a \typ{VECSMALL} or \kbd{NULL} when all subsets have been exhausted. \subsec{Iterating over primes}\label{se:primeiter} The library provides a high-level iterator, which stores its (private) data in a \kbd{struct} \tet{forprime_t} and runs over arbitrary ranges of primes, without ever overflowing. The iterator has two flavors, one providing the successive primes as \kbd{ulong}s, the other as \kbd{GEN}. They are initialized as follows, where we expect to run over primes $\geq a$ and $\leq b$: \fun{int}{forprime_init}{forprime_t *T, GEN a, GEN b} for the \kbd{GEN} variant, where $b = \kbd{NULL}$ means $+\infty$. \fun{int}{u_forprime_init}{forprime_t *T, ulong a, ulong b} for the \kbd{ulong} variant, where $b = \kbd{ULONG\_MAX}$ means we will run through all primes representable in a \kbd{ulong} type. Both variant return $1$ on success, and $0$ if the iterator would run over an empty interval (if $a > b$, for instance). They allocate the \tet{forprime_t} data structure on the PARI stack. \noindent The successive primes are then obtained using \fun{GEN}{forprime_next}{forprime_t *T}, returns \kbd{NULL} if no more primes are available in the interval. \fun{ulong}{u_forprime_next}{forprime_t *T}, returns $0$ if no more primes are available in the interval. These two functions leave alone the PARI stack, and write their state information in the preallocated \tet{forprime_t} struct. The typical usage is thus: \bprog forprime_t T; GEN p; pari_sp av = avma, av2; forprime_init(&T, gen_2, stoi(1000)); av2 = avma; while ( (p = forprime_next(&T)) ) { ... if ( prime_is_OK(p) ) break; avma = av2; /* delete garbage accumulated in this iteration */ } avma = av; /* delete all */ @eprog\noindent Of course, the final \kbd{avma = av} could be replaced by a \kbd{gerepile} call. Beware that swapping the \kbd{av2 = avma} and \tet{forprime_init} call would be incorrect: the first \kbd{avma = av2} would delete the \tet{forprime_t} structure! \subsec{Numerical analysis} Numerical routines code a function (to be integrated, summed, zeroed, etc.) with two parameters named \bprog void *E; GEN (*eval)(void*, GEN) @eprog\noindent The second is meant to contain all auxiliary data needed by your function. The first is such that \kbd{eval(x, E)} returns your function evaluated at \kbd{x}. For instance, one may code the family of functions $f_t: x \to (x+t)^2$ via \bprog GEN fun(void *t, GEN x) { return gsqr(gadd(x, (GEN)t)); } @eprog\noindent One can then integrate $f_1$ between $a$ and $b$ with the call \bprog intnum((void*)stoi(1), &fun, a, b, NULL, prec); @eprog\noindent Since you can set \kbd{E} to a pointer to any \kbd{struct} (typecast to \kbd{void*}) the above mechanism handles arbitrary functions. For simple functions without extra parameters, you may set \kbd{E = NULL} and ignore that argument in your function definition. \section{Catching exceptions} \subsec{Basic use} PARI provides a mechanism to trap exceptions generated via \kbd{pari\_err} using the \tet{pari_CATCH} construction. The basic usage is as follows \bprog pari_CATCH(err_code) { @com recovery branch } pari_TRY { @com main branch } pari_ENDCATCH @eprog\noindent This fragment executes the main branch, then the recovery branch \emph{if} exception \kbd{err\_code} is thrown, e.g. \kbd{e\_TYPE}. See \secref{se:errors} for the description of all error classes. The special error code \tet{CATCH_ALL} is available to catch all errors. One can replace the \tet{pari_TRY} keyword by \tet{pari_RETRY}, in which case once the recovery branch is run, we run the main branch again, still catching the same exceptions. \misctitle{Restrictions} \item Such constructs can be nested without adverse effect, the innermost handler catching the exception. \item It is \emph{valid} to leave either branch using \tet{pari_err}. \item It is \emph{invalid} to use C flow control instructions (\kbd{break}, \kbd{continue}, \kbd{return}) to directly leave either branch without seeing the \tet{pari_ENDCATCH} keyword. This would leave an invalid structure in the exception handler stack, and the next exception would crash. \item In order to leave using \kbd{break}, \kbd{continue} or \kbd{return}, one must precede the keyword by a call to \fun{void}{pari_CATCH_reset}{} disable the current handler, allowing to leave without adverse effect. \subsec{Advanced use} In the recovery branch, the exception context can be examined via the following helper routines: \fun{GEN}{pari_err_last}{} returns the exception context, as a \typ{ERROR}. The exception $E$ returned by \tet{pari_err_last} can be rethrown, using \bprog pari_err(0, E); @eprog \fun{long}{err_get_num}{GEN E} returns the error symbolic name. E.g \kbd{e\_TYPE}. \fun{GEN}{err_get_compo}{GEN E, long i} error $i$-th component, as documented in \secref{se:errors}. \noindent For instance \bprog pari_CATCH(CATCH_ALL) { /* catch everything */ GEN x, E = pari_err_last(); long code = err_get_num(E); if (code != e_INV) pari_err(0, E); /* unexpected error, rethrow */ x = err_get_compo(E, 2); /* e_INV has two components, 1: function name 2: non-invertible x */ if (typ(x) != t_INTMOD) pari_err(0, E); /* unexpected type, rethrow */ pari_CATCH_reset(); return x; /* leave ! */ @com @dots } pari_TRY { @com main branch } pari_ENDCATCH @eprog \section{A complete program} \label{se:prog} \noindent Now that the preliminaries are out of the way, the best way to learn how to use the library mode is to study a detailed example. We want to write a program which computes the gcd of two integers, together with the Bezout coefficients. We shall use the standard quadratic algorithm which is not optimal but is not too far from the one used in the PARI function \teb{bezout}. Let $x,y$ two integers and initially $ \pmatrix{s_x & s_y \cr t_x & t_y } = \pmatrix{1 & 0 \cr 0 & 1}$, so that $$ \pmatrix{s_x & s_y \cr t_x & t_y } \pmatrix{x \cr y } = \pmatrix{x \cr y }. $$ To apply the ordinary Euclidean algorithm to the right hand side, multiply the system from the left by $ \pmatrix{0 & 1 \cr 1 & -q }$, with $q = \kbd{floor}(x / y)$. Iterate until $y = 0$ in the right hand side, then the first line of the system reads $$ s_x x + s_y y = \gcd(x,y).$$ In practice, there is no need to update $s_y$ and $t_y$ since $\gcd(x,y)$ and $s_x$ are enough to recover $s_y$. The following program is now straightforward. A couple of new functions appear in there, whose description can be found in the technical reference manual in Chapter 5, but whose meaning should be clear from their name and the context. This program can be found in \kbd{examples/extgcd.c} together with a proper \kbd{Makefile}. You may ignore the first comment \bprog /* GP;install("extgcd", "GG&&", "gcdex", "./libextgcd.so"); */ @eprog\noindent which instruments the program so that \kbd{gp2c-run extgcd.c} can import the \kbd{extgcd()} routine into an instance of the \kbd{gp} interpreter (under the name \kbd{gcdex}). See the \kbd{gp2c} manual for details. \newpage \bprogfile{../examples/extgcd.c} \noindent For simplicity, the inner loop does not include any garbage collection, hence memory use is quadratic in the size of the inputs instead of linear. Here is a better version of that loop: \bprog pari_sp av = avma; ... while (!gequal0(b)) { GEN r, q = dvmdii(a, b, &r), v = vx; vx = subii(ux, mulii(q, vx)); ux = v; a = b; b = r; if (gc_needed(av,1)) gerepileall(av, 4, &a, &b, &ux, &vx); } @eprog \newpage pari-2.11.2/doc/gp.10000644000175000017500000002252013326135265012422 0ustar billbill.TH GP 1 "11 September 2017" .SH NAME gp \- The PARI calculator .SH SYNOPSIS .B gp .RB [ -s .IR stacksize ] .RB [ -p .IR primelimit ] .RB [ --emacs ] .RB [ -f | --fast ] .RB [ -q | --quiet ] .RB [ -D | --default .IR key=val ] .RB [ --help ] .RB [ --test ] .RB [ --texmacs ] .RB [ --version ] .RB [ --version-short ] [ file1 file2 ...] .SH DESCRIPTION Invokes the PARI-GP calculator \&\fBgp\fR; gp is an advanced programmable calculator, specializing in number theory, which computes symbolically as long as possible, numerically where needed, and contains a wealth of arithmetic functions: factorizations, elliptic curves, Galois theory, class field theory, modular forms, etc. Commands, written in the GP scripting language, are input interactively or loaded from files. If present at the end of the command line, files 'file1', 'file2', ... are loaded on startup; they must be written in the GP language. .SH OPTIONS Command line options are available in both short form (-f) and POSIX-like (--fast). Numeric arguments can be followed by a modifier .B k , .B M or .B G at the user's convenience; in that case the argument is multiplied by 10^3, 10^6, or 10^9 respectively. .TP .B \-f, \--fast Fast start (or factory settings). Do not read .B .gprc (see below) upon startup. .TP .B \-p limit [DEPRECATED] Upon startup, gp computes a table of small primes used in number-theoretic applications. If .I primelimit is set, the table include primes up to that bound instead of the default (= 500000). It is now mostly useless to change this value. .TP .B \-q, \--quiet Quiet mode. Do not print headers or history numbers and do not say goodbye. .TP .B \-D, \--default key=val performs .BR default(key, .BR val) ";" on startup, overriding values from the .B gprc preferences file. 'val' must be a constant value and is not allowed to involve any computation (e.g. 1+1 is forbidden). Any number of such default-setting statements may appear on the command line. A key may be set multiple times, the last setting taking precedence .TP .B \-s limit Size of gp internal stack allocated on startup. When gp runs out of space, it interrupts the current computation and raises a .BI "stack overflow" exception. If this occurs frequently, start with a bigger stack. The stack size can also be increased from within gp, using .BR default(parisize, limit) ";" it may be convenient to set .B stacksize from your .B .gprc. Note that computations with a .B smaller stack may be more efficient due to better data locality. Most computations should need less than 20MB. .TP .B \--emacs gp can be run in an .I Emacs shell (see GP User's manual for details). This flag is then required for smooth interaction with the .I PariEmacs package (pari.el). It is set automatically by the pari.el package, and will produce display oddities if you set it outside of an .I Emacs session. .TP .B \--help print a summary of available command-line options. .TP .B \--test run gp in test mode: suppress printing of history numbers and wrap long output lines (to get readable diff output). For benches only. .TP .B \--texmacs gp can be run from a .I TeXmacs frontend. This flag is set by TeXmacs, to enable special purpose communication channels. Do not set it yourself. .TP .B \--version output version info (banner) then exit. .TP .B \--version-short output version number then exit. .SH USE .TP .B ? to get online help. .TP .B ?? to get extended online help (more precisely, to call the external help program, .B gphelp by default) .TP .B quit (or \\q), or .B EOF (Ctrl-D) to quit .BR gp . .PP The following works only when gp was linked with GNU .IR readline library: .TP arrow keys for editing and viewing the input history. .TP .B TAB for automatic completion .SH MANUALS The following material is included in the standard distribution (originally in TeX format) and can also be downloaded at .RS .I http://pari.math.u-bordeaux.fr/doc.html .RE .TP .I The User's Guide to PARI/GP (users.dvi) .TP .I The User's Guide to the PARI library (library.dvi) .TP .I The Developer's Guide to the PARI library (develop.dvi) .TP .I PARI/GP, a tutorial (tutorial.dvi) .TP .I PARI/GP reference cards (refcard*.dvi) .SH FILES .TP .I gp main executable .TP .I $HOME/.gprc (or $GPRC if set) user preference file, read at beginning of execution by each .B gp shell. A default gprc .I gprc.dft is provided with the distribution. If this file cannot be found, .I /etc/gprc is checked instead. .TP .I a file used to log in all commands and results; default: .B pari.log (you need to set the .B log default in your gprc or interactively) .TP .I a file used to dump PostScript drawings; default: .B pari.ps .TP .I a file where gp will keep a history of all input commands (you need to set the .B histfile default in the gprc file) .TP .I gphelp default external help program (as above) .TP .I *.gp GP programs .SH ENVIRONMENT .TP .I $GPRC place to look for the user's preference file (gprc); if the file does not exist, we then check in $HOME/.gprc, /etc/gprc, and finally for a file named 'gprc' in PARI's .B datadir. .TP .I $GP_DATA_DIR directory containing data installed by optional PARI packages. For example, the Galois resolvents files in directory .I galdata/ needed by the .B polgalois function, in degrees 8 to 11; or the modular polynomials in .I seadata/ used by the .B ellap function for large base fields. This environment variable overrides PARI's 'datadir', defined at Configure time. .TP .I $GP_POSTSCRIPT_VIEWER an application able to display PostScript files, used by the .I plotps graphic engine. This engine is a fallback used to output hi-res plots even when no compatible graphical library was available on your platform at Configure time. (Dumps the graph to a temporary file, then open the file.) .TP .I $GP_SVG_VIEWER an application able to display SGV images files, used by the .I plotsvg graphic engine. This engine is a fallback used to output hi-res plots even when no compatible graphical library was available on your platform at Configure time. (Dumps the graph to a temporary file, then open the file.) .TP .I $GPHELP name of the external help program invoked by ?? and ??? shortcuts. .TP .I $GPTMPDIR name of the directory where temporary files will be generated. .SH HOME PAGE PARI's home page resides at .RS .I http://pari.math.u-bordeaux.fr/ .RE .SH MAILING LISTS There are a number of mailing lists devoted to the PARI/GP package, and most feedback should be directed to those. See .RS .I http://pari.math.u-bordeaux.fr/lists-index.html .RE for details. The most important ones are: .PP - .B pari-announce (moderated): for us to announce major version changes. .PP - .B pari-dev: for everything related to the development of PARI, including suggestions, technical questions, bug reports or patch submissions. .PP - .B pari-users: for discuss about everything else, in particular ask for help. To subscribe, send empty messages with a Subject: containing the word "subscribe" respectively to .PP pari-announce-request@pari.math.u-bordeaux.fr .PP pari-users-request@pari.math.u-bordeaux.fr .PP pari-dev-request@pari.math.u-bordeaux.fr .SH BUG REPORTS Bugs should be submitted online to our Bug Tracking System, available from PARI's home page, or directly from the URL .RS .I http://pari.math.u-bordeaux.fr/Bugs/ .RE Further instructions can be found on that page. .SH TRIVIA Despite the leading G, GP has nothing to do with GNU. The first version was originally called GPC, for Great Programmable Calculator. For some reason, the trailing C was eventually dropped. PARI has nothing to do with the French capital. The name is a pun about the project's early stages when the authors started to implement a library for "Pascal ARIthmetic" in the PASCAL programming language. They quickly switched to C. For the benefit of non-native French speakers, here's a slightly expanded explanation: .B Blaise Pascal (1623-1662) was a famous French mathematician and philosopher who was one of the founders of probability and devised one of the first "arithmetic machines". He once proposed the following "proof" of the existence of God for the unbelievers: whether He exists or not I lose nothing by believing in Him, whereas if He does and I misbehave... This is the so-called "pari de Pascal" (Pascal's Wager). Note that PARI also means "fairy" in Persian. .SH AUTHORS PARI was originally written by Christian Batut, Dominique Bernardi, Henri Cohen, and Michel Olivier in Laboratoire A2X (Universite Bordeaux I, France), and was maintained by Henri Cohen up to version 1.39.15 (1995), and by Karim Belabas since then. A great number of people have contributed to the successive improvements which eventually resulted in the present version. See the AUTHORS file in the distribution. .SH SEE ALSO .IR gap (1), .IR gphelp (1), .IR perl (1), .IR readline (3), .IR sage (1), .IR tex (1), .IR texmacs (1), .SH COPYING This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. pari-2.11.2/doc/usersFUNCS.tex0000644000175000017500000001540313326135265014416 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \chapter{Functions and Operations Available in PARI and GP} \label{se:functions} The functions and operators available in PARI and in the GP/PARI calculator are numerous and ever-expanding. Here is a description of the ones available in version \vers. It should be noted that many of these functions accept quite different types as arguments, but others are more restricted. The list of acceptable types will be given for each function or class of functions. Except when stated otherwise, it is understood that a function or operation which should make natural sense is legal. On the other hand, many routines list explicit preconditions for some of their argument, e.g. $p$ is a prime number, or $q$ is a positive definite quadratic form. For reasons of efficiency, all trust the user input and only perform minimal sanity checks. When a precondition is not satisfied, any of the following may occur: a regular exception is raised, the PARI stack overflows, a \kbd{SIGSEGV} or \kbd{SIGBUS} signal is generated, or we enter an infinite loop. The function can also quietly return a mathematically meaningless result: junk in, junk out. In this chapter, we will describe the functions according to a rough classification. The general entry looks something like: \key{foo}$(x,\{\fl=0\})$: short description. The library syntax is \kbd{GEN foo(GEN x, long fl = 0)}. \noindent This means that the GP function \kbd{foo} has one mandatory argument $x$, and an optional one, $\fl$, whose default value is 0. (The $\{\}$ should not be typed, it is just a convenient notation we will use throughout to denote optional arguments.) That is, you can type \kbd{foo(x,2)}, or \kbd{foo(x)}, which is then understood to mean \kbd{foo(x,0)}. As well, a comma or closing parenthesis, where an optional argument should have been, signals to GP it should use the default. Thus, the syntax \kbd{foo(x,)} is also accepted as a synonym for our last expression. When a function has more than one optional argument, the argument list is filled with user supplied values, in order. When none are left, the defaults are used instead. Thus, assuming that \kbd{foo}'s prototype had been $$\hbox{% \key{foo}$(\{x=1\},\{y=2\},\{z=3\})$,% }$$ typing in \kbd{foo(6,4)} would give you \kbd{foo(6,4,3)}. In the rare case when you want to set some far away argument, and leave the defaults in between as they stand, you can use the ``empty arg'' trick alluded to above: \kbd{foo(6,,1)} would yield \kbd{foo(6,2,1)}. By the way, \kbd{foo()} by itself yields \kbd{foo(1,2,3)} as was to be expected. In this rather special case of a function having no mandatory argument, you can even omit the $()$: a standalone \kbd{foo} would be enough (though we do not recommend it for your scripts, for the sake of clarity). In defining GP syntax, we strove to put optional arguments at the end of the argument list (of course, since they would not make sense otherwise), and in order of decreasing usefulness so that, most of the time, you will be able to ignore them. Finally, an optional argument (between braces) followed by a star, like $\{\var{x}\}*$, means that any number of such arguments (possibly none) can be given. This is in particular used by the various \kbd{print} routines. \misctitle{Flags} A \tev{flag} is an argument which, rather than conveying actual information to the routine, instructs it to change its default behavior, e.g.~return more or less information. All such flags are optional, and will be called \fl\ in the function descriptions to follow. There are two different kind of flags \item generic: all valid values for the flag are individually described (``If \fl\ is equal to $1$, then\dots''). \item binary:\sidx{binary flag} use customary binary notation as a compact way to represent many toggles with just one integer. Let $(p_0,\dots,p_n)$ be a list of switches (i.e.~of properties which take either the value $0$ or~$1$), the number $2^3 + 2^5 = 40$ means that $p_3$ and $p_5$ are set (that is, set to $1$), and none of the others are (that is, they are set to $0$). This is announced as ``The binary digits of $\fl$ mean 1: $p_0$, 2: $p_1$, 4: $p_2$'', and so on, using the available consecutive powers of~$2$. \misctitle{Mnemonics for binary flags} Numeric flags as mentioned above are obscure, error-prone, and quite rigid: should the authors want to adopt a new flag numbering scheme, it would break backward compatibility. The only advantage of explicit numeric values is that they are fast to type, so their use is only advised when using the calculator \kbd{gp}. As an alternative, one can replace a binary flag by a character string containing symbolic identifiers (mnemonics). In the function description, mnemonics corresponding to the various toggles are given after each of them. They can be negated by prepending \kbd{no\_} to the mnemonic, or by removing such a prefix. These toggles are grouped together using any punctuation character (such as ',' or ';'). For instance (taken from description of $\tet{ploth}(X=a,b,\var{expr},\{\fl=0\},\{n=0\})$) \centerline{Binary digits of flags mean: $1=\kbd{Parametric}$, $2=\kbd{Recursive}$, \dots} \noindent so that, instead of $1$, one could use the mnemonic \kbd{"Parametric; no\_Recursive"}, or simply \kbd{"Parametric"} since \kbd{Recursive} is unset by default (default value of $\fl$ is $0$, i.e.~everything unset). People used to the bit-or notation in languages like C may also use the form \kbd{"Parametric | no\_Recursive"}. \misctitle{Pointers} \varsidx{pointer} If a parameter in the function prototype is prefixed with a \& sign, as in \key{foo}$(x,\&e)$ \noindent it means that, besides the normal return value, the function may assign a value to $e$ as a side effect. When passing the argument, the \& sign has to be typed in explicitly. As of version \vers, this \tev{pointer} argument is optional for all documented functions, hence the \& will always appear between brackets as in \kbd{Z\_issquare}$(x,\{\&e\})$. \misctitle{About library programming} The \var{library} function \kbd{foo}, as defined at the beginning of this section, is seen to have two mandatory arguments, $x$ and \fl: no function seen in the present chapter has been implemented so as to accept a variable number of arguments, so all arguments are mandatory when programming with the library (usually, variants are provided corresponding to the various flag values). We include an \kbd{= default value} token in the prototype to signal how a missing argument should be encoded. Most of the time, it will be a \kbd{NULL} pointer, or -1 for a variable number. Refer to the \emph{User's Guide to the PARI library} for general background and details. pari-2.11.2/doc/appd.tex0000644000175000017500000000714313201017466013376 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \appendix{PARI and threads} To use PARI in multi-threaded programs, you must configure it using \kbd{Configure --enable-tls}. Your system must implement the \kbd{\_\_thread} storage class. As a major side effect, this breaks the \kbd{libpari} ABI: the resulting library is not compatible with the old one, and \kbd{-tls} is appended to the PARI library \kbd{soname}. On the other hand, this library is now thread-safe. PARI provides some functions to set up PARI subthreads\sidx{threads}. In our model, each concurrent thread needs its own PARI stack. The following scheme is used: \noindent Child thread: \bprog void *child_thread(void *arg) { GEN data = pari_thread_start((struct pari_thread*)arg); GEN result = ...; /* Compute result from data */ pari_thread_close(); return (void*)result; } @eprog \noindent Parent thread: \bprog pthread_t th; struct pari_thread pth; GEN data, result; pari_thread_alloc(&pth, s, data); pari_thread_sync(); pthread_create(&th, NULL, &child_thread, (void*)&pth); /* start child */ ... /* do stuff in parent */ pthread_join(th, (void*)&result); /* wait until child terminates */ result = gcopy(result); /* copy result from thread stack to main stack */ pari_thread_free(&pth); /* ... and clean up */ @eprog \fun{void}{pari_thread_valloc}{struct pari_thread *pth, size_t s, size_t v, GEN arg} Allocate a PARI stack of size \kbd{s} which can grow to at most \kbd{v} (as with \kbd{parisize} and \kbd{parisizemax}) and associate it, together with the argument \kbd{arg}, with the PARI thread data \kbd{pth}. \fun{void}{pari_thread_alloc}{struct pari_thread *pth, size_t s, GEN arg} As above but the stack cannot grow beyond \kbd{s}. \fun{void}{pari_thread_free}{struct pari_thread *pth} Free the PARI stack attached to the PARI thread data \kbd{pth}. This is called after the child thread terminates, i.e.~after \tet{pthread_join} in the parent. Any \kbd{GEN} objects returned by the child in the thread stack need to be saved before running this command. \fun{void}{pari_thread_sync}{void} Record states from the main thread so that they are available to \kbd{pari\_thread\_start()}. Must be called in the main thread before the subthreads starts. \fun{void}{pari_thread_init}{void} Initialize the thread-local PARI data structures. This function is called by \kbd{pari\_thread\_start}. \fun{GEN}{pari_thread_start}{struct pari_thread *t} Initialize the thread-local PARI data structures and set up the thread stack using the PARI thread data \kbd{pth}. This function returns the thread argument \kbd{arg} that was given to \kbd{pari\_thread\_alloc}. \fun{void}{pari_thread_close}{void} Free the thread-local PARI data structures, but keeping the thread stack, so that a \kbd{GEN} returned by the thread remains valid. \noindent Under this model, some PARI states are reset in new threads. In particular \item the random number generator is reset to the starting seed; \item the system stack exhaustion checking code, meant to catch infinite recursions, is disabled (use \kbd{pari\_stackcheck\_init()} to reenable it); \item cached real constants (returned by \kbd{mppi}, \kbd{mpeuler} and \kbd{mplog2}) are not shared between threads and will be recomputed as needed; \noindent The following sample program can be compiled using \bprog cc thread.c -o thread.o -lpari -lpthread @eprog\noindent (Add \kbd{-I/-L} paths as necessary.) \noindent\bprogfile{../examples/thread.c} \vfill\eject pari-2.11.2/doc/usersch5.tex0000644000175000017500000221114413457700327014223 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \chapter{Technical Reference Guide: the basics} In the following chapters, we describe all public low-level functions of the PARI library. These include specialized functions for handling all the PARI types. Simple higher level functions, such as arithmetic or transcendental functions, are described in Chapter~3 of the GP user's manual; we will eventually see more general or flexible versions in the chapters to come. A general introduction to the major concepts of PARI programming can be found in Chapter~4, which you should really read first. We shall now study specialized functions, more efficient than the library wrappers, but sloppier on argument checking and damage control; besides speed, their main advantage is to give finer control about the inner workings of generic routines, offering more options to the programmer. \misctitle{Important advice} Generic routines eventually call lower level functions. Optimize your algorithms first, not overhead and conversion costs between PARI routines. For generic operations, use generic routines first; do not waste time looking for the most specialized one available unless you identify a genuine bottleneck, or you need some special behavior the generic routine does not offer. The PARI source code is part of the documentation; look for inspiration there.\smallskip The type \kbd{long} denotes a \tet{BITS_IN_LONG}-bit signed long integer (32 or 64 bits). The type \tet{ulong} is defined as \kbd{unsigned long}. The word \emph{stack} always refer to the PARI stack, allocated through an initial \kbd{pari\_init} call. Refer to Chapters 1--2 and~4 for general background. \kbdsidx{BIL} We shall often refer to the notion of \tev{shallow} function, which means that some components of the result may point to components of the input, which is more efficient than a \emph{deep} copy (full recursive copy of the object tree). Such outputs are not suitable for \kbd{gerepileupto} and particular care must be taken when garbage collecting objects which have been input to shallow functions: corresponding outputs also become invalid and should no longer be accessed. A function is \emph{not stack clean} if it leaves intermediate data on the stack besides its output, for efficiency reasons. \section{Initializing the library} The following functions enable you to start using the PARI functions in a program, and cleanup without exiting the whole program. \subsec{General purpose} \fun{void}{pari_init}{size_t size, ulong maxprime} initialize the library, with a stack of \kbd{size} bytes and a prime table up to the maximum of \kbd{maxprime} and $2^{16}$. Unless otherwise mentioned, no PARI function will function properly before such an initialization. \fun{void}{pari_close}{void} stop using the library (assuming it was initialized with \kbd{pari\_init}) and frees all allocated objects. \subsec{Technical functions}\label{se:pari_init_tech} \fun{void}{pari_init_opts}{size_t size, ulong maxprime, ulong opts} as \kbd{pari\_init}, more flexible. \kbd{opts} is a mask of flags among the following: \kbd{INIT\_JMPm}: install PARI error handler. When an exception is raised, the program is terminated with \kbd{exit(1)}. \kbd{INIT\_SIGm}: install PARI signal handler. \kbd{INIT\_DFTm}: initialize the \kbd{GP\_DATA} environment structure. This one \emph{must} be enabled once. If you close pari, then restart it, you need not reinitialize \kbd{GP\_DATA}; if you do not, then old values are restored. \kbd{INIT\_noPRIMEm}: do not compute the prime table (ignore the \kbd{maxprime} argument). The user \emph{must} call \tet{pari_init_primes} later. \kbd{INIT\_noIMTm}: (technical, see \kbd{pari\_mt\_init} in the Developer's Guide for detail). Do not call \tet{pari_mt_init} to initialize the multi-thread engine. If this flag is set, \kbd{pari\_mt\_init()} will need to be called manually. See \kbd{examples/pari-mt.c} for an example. \kbd{INIT\_noINTGMPm}: do not install PARI-specific GMP memory functions. This option is ignored when the GMP library is not in use. You may install PARI-specific GMP memory functions later by calling \fun{void}{pari_kernel_init}{void} \noindent and restore the previous values using \fun{void}{pari_kernel_close}{void} This option should not be used without a thorough understanding of the problem you are trying to solve. The GMP memory functions are global variables used by the GMP library. If your program is linked with two libraries that require these variables to be set to different values, conflict ensues. To avoid a conflict, the proper solution is to record their values with \kbd{mp\_get\_memory\_functions} and to call \kbd{mp\_set\_memory\_functions} to restore the expected values each time the code switches from using one library to the other. Here is an example: \bprog void *(*pari_alloc_ptr) (size_t); void *(*pari_realloc_ptr) (void *, size_t, size_t); void (*pari_free_ptr) (void *, size_t); void *(*otherlib_alloc_ptr) (size_t); void *(*otherlib_realloc_ptr) (void *, size_t, size_t); void (*otherlib_free_ptr) (void *, size_t); void init(void) { pari_init(8000000, 500000); mp_get_memory_functions(&pari_alloc_ptr,&pari_realloc_ptr, &pari_free_ptr); otherlib_init(); mp_get_memory_functions(&otherlib_alloc_ptr,&otherlib_realloc_ptr, &otherlib_free_ptr); } void function_that_use_pari(void) { mp_set_memory_functions(pari_alloc_ptr,pari_realloc_ptr, pari_free_ptr); /*use PARI functions*/ } void function_that_use_otherlib(void) { mp_set_memory_functions(otherlib_alloc_ptr,otherlib_realloc_ptr, otherlib_free_ptr); /*use OTHERLIB functions*/ } @eprog \fun{void}{pari_close_opts}{ulong init_opts} as \kbd{pari\_close}, for a library initialized with a mask of options using \kbd{pari\_init\_opts}. \kbd{opts} is a mask of flags among \kbd{INIT\_SIGm}: restore \kbd{SIG\_DFL} default action for signals tampered with by PARI signal handler. \kbd{INIT\_DFTm}: frees the \kbd{GP\_DATA} environment structure. \kbd{INIT\_noIMTm}: (technical, see \kbd{pari\_mt\_init} in the Developer's Guide for detail). Do not call \tet{pari_mt_close} to close the multi-thread engine. \kbd{INIT\_noINTGMPm}: do not restore GMP memory functions. \fun{void}{pari_sig_init}{void (*f)(int)} install the signal handler \kbd{f} (see \kbd{signal(2)}): the signals \kbd{SIGBUS}, \kbd{SIGFPE}, \kbd{SIGINT}, \kbd{SIGBREAK}, \kbd{SIGPIPE} and \kbd{SIGSEGV} are concerned. \fun{void}{pari_init_primes}{ulong maxprime} Initialize the PARI primes. This function is called by \kbd{pari\_init(\dots,maxprime)}. It is provided for users calling \kbd{pari\_init\_opts} with the flag \kbd{INIT\_noPRIMEm}. \fun{void}{pari_sighandler}{int signum} the actual signal handler that PARI uses. This can be used as argument to \kbd{pari\_sig\_init} or \kbd{signal(2)}. \fun{void}{pari_stackcheck_init}{void *stackbase} controls the system stack exhaustion checking code in the GP interpreter. This should be used when the system stack base address change or when the address seen by \kbd{pari\_init} is too far from the base address. If \kbd{stackbase} is \kbd{NULL}, disable the check, else set the base address to \kbd{stackbase}. It is normally used this way \bprog int thread_start (...) { long first_item_on_the_stack; ... pari_stackcheck_init(&first_item_on_the_stack); } @eprog \fun{int}{pari_daemon}{void} forks a PARI daemon, detaching from the main process group. The function returns 1 in the parent, and 0 in the forked son. \fun{void}{paristack_setsize}{size_t rsize, size_t vsize} sets the default \kbd{parisize} to \kbd{rsize} and the default \kbd{parisizemax} to \kbd{vsize}, and reallocate the stack to match these value, destroying its content. Generally used just after \kbd{pari\_init}. \fun{void}{paristack_resize}{ulong newsize} changes the current stack size to \kbd{newsize} (double it if \kbd{newsize} is 0). The new size is clipped to be at least the current stack size and at most \kbd{parisizemax}. The stack content is not affected by this operation. \fun{void}{parivstack_reset}{void} resets the current stack to its default size \kbd{parisize}. This is used to recover memory after a computation that enlarged the stack. This function destroys the content of the enlarged stack (between the old and the new bottom of the stack). Before calling this function, you must ensure that \kbd{avma} lies within the new smaller stack. \fun{void}{paristack_newrsize}{ulong newsize} \emph{(does not return)}. Library version of \bprog default(parisize, "newsize") @eprog\noindent Set the default \kbd{parisize} to \kbd{newsize}, or double \kbd{parisize} if \kbd{newsize} is equal to 0, then call \kbd{cb\_pari\_err\_recover(-1)}. \fun{void}{parivstack_resize}{ulong newsize} \emph{(does not return)}. Library version of \bprog default(parisizemax, "newsize") @eprog\noindent Set the default \kbd{parisizemax} to \kbd{newsize} and call \kbd{cb\_pari\_err\_recover(-1)}. \subsec{Notions specific to the GP interpreter} An \kbd{entree} is the generic object attached to an identifier (a name) in GP's interpreter, be it a built-in or user function, or a variable. For a function, it has at least the following fields: \kbd{char *name}: the name under which the interpreter knows us. \kbd{void *value}: a pointer to the C function to call. \kbd{long menu}: a small integer $\geq 1$ (to which group of function help do we belong, for the \kbd{?$n$} help menu). \kbd{char *code}: the prototype code. \kbd{char *help}: the help text for the function. A routine in GP is described to the analyzer by an \kbd{entree} structure. Built-in PARI routines are grouped in \emph{modules}, which are arrays of \kbd{entree} structs, the last of which satisfy \kbd{name = NULL} (sentinel). There are currently four modules in PARI/GP: \item general functions (\tet{functions_basic}, known to \kbd{libpari}), \item gp-specific functions (\tet{functions_gp}), \noindent and two modules of obsolete functions. The function \kbd{pari\_init} initializes the interpreter and declares all symbols in \kbd{functions\_basic}. You may declare further functions on a case by case basis or as a whole module using \fun{void}{pari_add_function}{entree *ep} adds a single routine to the table of symbols in the interpreter. It assumes \kbd{pari\_init} has been called. \fun{void}{pari_add_module}{entree *mod} adds all the routines in module \kbd{mod} to the table of symbols in the interpreter. It assumes \kbd{pari\_init} has been called. \noindent For instance, gp implements a number of private routines, which it adds to the default set via the calls \bprog pari_add_module(functions_gp); @eprog A GP \kbd{default} is likewise attached to a helper routine, that is run when the value is consulted, or changed by \tet{default0} or \tet{setdefault}. Such routines are grouped in the module \tet{functions_default}. \fun{void}{pari_add_defaults_module}{entree *mod} adds all the defaults in module \kbd{mod} to the interpreter. It assumes that \kbd{pari\_init} has been called. From this point on, all defaults in module \kbd{mod} are known to \tet{setdefault} and friends. \subsec{Public callbacks} The \kbd{gp} calculator associates elaborate functions (for instance the break loop handler) to the following callbacks, and so can you: \doc{cb_pari_ask_confirm}{void (*cb_pari_ask_confirm)(const char *s)} initialized to \kbd{NULL}. Called with argument $s$ whenever PARI wants confirmation for action $s$, for instance in \tet{secure} mode. \doc{cb_pari_init_histfile}{void (*cb_pari_init_histfile)(void)} initialized to \kbd{NULL}. Called when the \kbd{histfile} default is changed. The intent is for that callback to read the file content, append it to history in memory, then dump the expanded history to the new \kbd{histfile}. \doc{cb_pari_is_interactive}{int (*cb_pari_is_interactive)(void)}; initialized to \kbd{NULL}. \doc{cb_pari_quit}{void (*cb_pari_quit)(long)} initialized to a no-op. Called when \kbd{gp} must evaluate the \kbd{quit} command. \doc{cb_pari_start_output}{void (*cb_pari_start_output)(void)} initialized to \kbd{NULL}. \doc{cb_pari_handle_exception}{int (*cb_pari_handle_exception)(long)} initialized to \kbd{NULL}. If not \kbd{NULL}, this routine is called with argument $-1$ on \kbd{SIGINT}, and argument \kbd{err} on error \kbd{err}. If it returns a non-zero value, the error or signal handler returns, in effect further ignoring the error or signal, otherwise it raises a fatal error. A possible simple-minded handler, used by the \kbd{gp} interpreter, is \fun{int}{gp_handle_exception}{long err} if the \kbd{breakloop} default is enabled (set to $1$) and \tet{cb_pari_break_loop} is not \kbd{NULL}, we call this routine with \kbd{err} argument and return the result. \doc{cb_pari_err_handle}{int (*cb_pari_err_handle)(GEN)} If not \kbd{NULL}, this routine is called with a \typ{ERROR} argument from \kbd{pari\_err}. If it returns a non-zero value, the error returns, in effect further ignoring the error, otherwise it raises a fatal error. The default behavior is to print a descriptive error message (display the error), then return 0, thereby raising a fatal error. This differs from \tet{cb_pari_handle_exception} in that the function is not called on \kbd{SIGINT} (which do not generate a \typ{ERROR}), only from \kbd{pari\_err}. Use \tet{cb_pari_sigint} if you need to handle \kbd{SIGINT} as well. The following function can be used by \kbd{cb\_pari\_err\_handle} to display the error message. \fun{const char*}{closure_func_err}{} return a statically allocated string holding the name of the function that triggered the error. Return NULL if the error was not caused by a function. \doc{cb_pari_break_loop}{int (*cb_pari_break_loop)(int)} initialized to \kbd{NULL}. \doc{cb_pari_sigint}{void (*cb_pari_sigint)(void)}. Function called when we receive \kbd{SIGINT}. By default, raises \bprog pari_err(e_MISC, "user interrupt"); @eprog\noindent A possible simple-minded variant, used by the \kbd{gp} interpreter, is \fun{void}{gp_sigint_fun}{void} \doc{cb_pari_pre_recover}{void (*cb_pari_pre_recover)(long)} initialized to \kbd{NULL}. If not \kbd{NULL}, this routine is called just before PARI cleans up from an error. It is not required to return. The error number is passed as argument, unless the PARI stack has been destroyed (\kbd{allocatemem}), in which case $-1$ is passed. \doc{cb_pari_err_recover}{void (*cb_pari_err_recover)(long)} initialized to \kbd{pari\_exit()}. This callback must not return. It is called after PARI has cleaned-up from an error. The error number is passed as argument, unless the PARI stack has been destroyed, in which case it is called with argument $-1$. \doc{cb_pari_whatnow}{int (*cb_pari_whatnow)(PariOUT *out, const char *s, int flag)} initialized to \kbd{NULL}. If not \kbd{NULL}, must check whether $s$ existed in older versions of \kbd{pari} (the \kbd{gp} callback checks against \kbd{pari-1.39.15}). All output must be done via \kbd{out} methods. \item $\fl = 0$: should print verbosely the answer, including help text if available. \item $\fl = 1$: must return $0$ if the function did not change, and a non-$0$ result otherwise. May print a help message. \subsec{Configuration variables} \tet{pari_library_path}: If set, It should be a path to the libpari library. It is used by the function \tet{gpinstall} to locate the PARI library when searching for symbols. This should only be useful on Windows. \subsec{Utility functions} \fun{void}{pari_ask_confirm}{const char *s} raise an error if the callback \tet{cb_pari_ask_confirm} is \kbd{NULL}. Otherwise calls \bprog cb_pari_ask_confirm(s); @eprog \fun{char*}{gp_filter}{const char *s} pre-processor for the GP parser: filter out whitespace and GP comments from $s$. \fun{GEN}{pari_compile_str}{const char *s} low-level form of \tet{compile_str}: assumes that $s$ does not contain spaces or GP comments and returns the closure attached to the GP expression $s$. Note that GP metacommands are not recognized. \fun{int}{gp_meta}{const char *s, int ismain} low-level component of \tet{gp_read_str}: assumes that $s$ does not contain spaces or GP comments and try to interpret $s$ as a GP metacommand (e.g. starting by \kbd{\bs} or \kbd{?}). If successful, execute the metacommand and return $1$; otherwise return $0$. The \kbd{ismain} parameter modifies the way \kbd{\bs r} commands are handled: if non-zero, act as if the file contents were entered via standard input (i.e. call \tet{switchin} and divert \tet{pari_infile}); otherwise, simply call \tet{gp_read_file}. \fun{void}{pari_hit_return}{void} wait for the use to enter \kbd{\bs n} via standard input. \fun{void}{gp_load_gprc}{void} read and execute the user's \kbd{GPRC} file. \fun{void}{pari_center}{const char *s} print $s$, centered. \fun{void}{pari_print_version}{void} print verbose version information. \fun{long}{pari_community}{void} return the index of the support section n the help. \fun{const char*}{gp_format_time}{long t} format a delay of $t$ ms suitable for \kbd{gp} output, with \kbd{timer} set. \fun{const char*}{gp_format_prompt}{const char *p} format a prompt $p$ suitable for \kbd{gp} prompting (includes colors and protecting ANSI escape sequences for readline). \fun{void}{pari_alarm}{long s} set an alarm after $s$ seconds (raise an \tet{e_ALARM} exception). \fun{void}{gp_help}{const char *s, long flag} print help for $s$, depending on the value of \fl: \item \tet{h_REGULAR}, basic help (\kbd{?}); \item \tet{h_LONG}, extended help (\kbd{??}); \item \tet{h_APROPOS}, a propos help (\kbd{??}). \fun{const char **}{gphelp_keyword_list}{void} return a \kbd{NULL}-terminated array a strings, containing keywords known to \kbd{gphelp} besides GP functions (e.g. \kbd{modulus} or \kbd{operator}). Used by the online help system and the contextual completion engine. \fun{void}{gp_echo_and_log}{const char *p, const char *s} given a prompt $p$ and attached input command $s$, update logfile and possibly print on standard output if \tet{echo} is set and we are not in interactive mode. The callback \tet{cb_pari_is_interactive} must be set to a sensible value. \fun{void}{gp_alarm_handler}{int sig} the \kbd{SIGALRM} handler set by the \kbd{gp} interpreter. \fun{void}{print_fun_list}{char **list, long n} print all elements of \kbd{list} in columns, pausing (hit return) every $n$ lines. \kbd{list} is \kbd{NULL} terminated. \subsec{Saving and restoring the GP context} \fun{void}{gp_context_save}{struct gp_context* rec} save the current GP context. \fun{void}{gp_context_restore}{struct gp_context* rec} restore a GP context. The new context must be an ancestor of the current context. \subsec{GP history} These functions allow to control the GP history (the \kbd{\%} operator). \fun{void}{pari_add_hist}{GEN x, long t} adds \kbd{x} as the last history entry; $t$ is the time we used to compute it. \fun{GEN}{pari_get_hist}{long p}, if $p>0$ returns entry of index $p$ (i.e. \kbd{\%p}), else returns entry of index $n+p$ where $n$ is the index of the last entry (used for \kbd{\%}, \kbd{\%`}, \kbd{\%``}, etc.). \fun{long}{pari_get_histtime}{long p} as \tet{pari_get_hist}, returning the time used to compute the history entry, instead of the entry itself. \fun{ulong}{pari_nb_hist}{void} return the index of the last entry. \section{Handling \kbd{GEN}s} \noindent Almost all these functions are either macros or inlined. Unless mentioned otherwise, they do not evaluate their arguments twice. Most of them are specific to a set of types, although no consistency checks are made: e.g.~one may access the \kbd{sign} of a \typ{PADIC}, but the result is meaningless. \subsec{Allocation} \fun{GEN}{cgetg}{long l, long t} allocates (the root of) a \kbd{GEN} of type $t$ and length $l$. Sets $z[0]$. \fun{GEN}{cgeti}{long l} allocates a \typ{INT} of length $l$ (including the 2 codewords). Sets $z[0]$ only. \fun{GEN}{cgetr}{long l} allocates a \typ{REAL} of length $l$ (including the 2 codewords). Sets $z[0]$ only. \fun{GEN}{cgetc}{long prec} allocates a \typ{COMPLEX} whose real and imaginary parts are \typ{REAL}s of length \kbd{prec}. \fun{GEN}{cgetg_copy}{GEN x, long *lx} fast version of \kbd{cgetg}: allocate a \kbd{GEN} with the same type and length as $x$, setting \kbd{*lx} to \kbd{lg(x)} as a side-effect. (Only sets the first codeword.) This is a little faster than \kbd{cgetg} since we may reuse the bitmask in $x[0]$ instead of recomputing it, and we do not need to check that the length does not overflow the possibilities of the implementation (since an object with that length already exists). Note that \kbd{cgetg} with arguments known at compile time, as in \bprog cgetg(3, t_INTMOD) @eprog\noindent will be even faster since the compiler will directly perform all computations and checks. \fun{GEN}{vectrunc_init}{long l} perform \kbd{cgetg(l,t\_VEC)}, then set the length to $1$ and return the result. This is used to implement vectors whose final length is easily bounded at creation time, that we intend to fill gradually using: \fun{void}{vectrunc_append}{GEN x, GEN y} assuming $x$ was allocated using \tet{vectrunc_init}, appends $y$ as the last element of $x$, which grows in the process. The function is shallow: we append $y$, not a copy; it is equivalent to \bprog long lx = lg(x); gel(x,lx) = y; setlg(x, lx+1); @eprog\noindent Beware that the maximal size of $x$ (the $l$ argument to \tet{vectrunc_init}) is unknown, hence unchecked, and stack corruption will occur if we append more than $l-1$ elements to $x$. Use the safer (but slower) \kbd{shallowconcat} when $l$ is not easy to bound in advance. An other possibility is simply to allocate using \kbd{cgetg(l, t)} then fill the components as they become available: this time the downside is that we do not obtain a correct \kbd{GEN} until the vector is complete. Almost no PARI function will be able to operate on it. \fun{void}{vectrunc_append_batch}{GEN x, GEN y} successively apply \bprog vectrunc_append(x, gel(y, i)) @eprog for all elements of the vector $y$. \fun{GEN}{coltrunc_init}{long l} as \kbd{vectrunc\_init} but perform \kbd{cgetg(l,t\_COL)}. \fun{GEN}{vecsmalltrunc_init}{long l} \fun{void}{vecsmalltrunc_append}{GEN x, long t} analog to the above for a \typ{VECSMALL} container. \subsec{Length conversions} These routines convert a non-negative length to different units. Their behavior is undefined at negative integers. \fun{long}{ndec2nlong}{long x} converts a number of decimal digits to a number of words. Returns $ 1 + \kbd{floor}(x \times \B \log_2 10)$. \fun{long}{ndec2prec}{long x} converts a number of decimal digits to a number of codewords. This is equal to 2 + \kbd{ndec2nlong(x)}. \fun{long}{ndec2nbits}{long x} convers a number of decimal digits to a number of bits. \fun{long}{prec2ndec}{long x} converts a number of codewords to a number of decimal digits. \fun{long}{nbits2nlong}{long x} converts a number of bits to a number of words. Returns the smallest word count containing $x$ bits, i.e $ \kbd{ceil}(x / \B)$. \fun{long}{nbits2ndec}{long x} converts a number of bits to a number of decimal digits. \fun{long}{nbits2lg}{long x} converts a number of bits to a length in code words. Currently an alias for \kbd{nbits2nlong}. \fun{long}{nbits2prec}{long x} converts a number of bits to a number of codewords. This is equal to 2 + \kbd{nbits2nlong(x)}. \fun{long}{nbits2extraprec}{long x} converts a number of bits to the mantissa length of a \typ{REAL} in codewords. This is currently an alias to \kbd{nbits2nlong(x)}. \fun{long}{nchar2nlong}{long x} converts a number of bytes to number of words. Returns the smallest word count containing $x$ bytes, i.e $\kbd{ceil}(x / \kbd{sizeof(long)})$. \fun{long}{prec2nbits}{long x} converts a \typ{REAL} length into a number of significant bits; returns $(x - 2)\B$. \fun{double}{prec2nbits_mul}{long x, double y} returns \kbd{prec2nbits}$(x)\times y$. \fun{long}{bit_accuracy}{long x} converts a length into a number of significant bits; currently an alias for \kbd{prec2nbits}. \fun{double}{bit_accuracy_mul}{long x, double y} returns \kbd{bit\_accuracy}$(x)\times y$. \fun{long}{realprec}{GEN x} length of a \typ{REAL} in words; currently an alias for \kbd{lg}. \fun{long}{bit_prec}{GEN x} length of a \typ{REAL} in bits. \fun{long}{precdbl}{long prec} given a length in words corresponding to a \typ{REAL} precision, return the length corresponding to doubling the precision. Due to the presence of 2 code words, this is $2(\kbd{prec} - 2) + 2$. \subsec{Read type-dependent information} \fun{long}{typ}{GEN x} returns the type number of~\kbd{x}. The header files included through \kbd{pari.h} define symbolic constants for the \kbd{GEN} types: \typ{INT} etc. Never use their actual numerical values. E.g to determine whether \kbd{x} is a \typ{INT}, simply check \bprog if (typ(x) == t_INT) { } @eprog\noindent The types are internally ordered and this simplifies the implementation of commutative binary operations (e.g addition, gcd). Avoid using the ordering directly, as it may change in the future; use type grouping functions instead (\secref{se:typegroup}). \fun{const char*}{type_name}{long t} given a type number \kbd{t} this routine returns a string containing its symbolic name. E.g \kbd{type\_name(\typ{INT})} returns \kbd{"\typ{INT}"}. The return value is read-only. \fun{long}{lg}{GEN x} returns the length of~\kbd{x} in \B-bit words. \fun{long}{lgefint}{GEN x} returns the effective length of the \typ{INT} \kbd{x} in \B-bit words. \fun{long}{signe}{GEN x} returns the sign ($-1$, 0 or 1) of~\kbd{x}. Can be used for \typ{INT}, \typ{REAL}, \typ{POL} and \typ{SER} (for the last two types, only 0 or 1 are possible). \fun{long}{gsigne}{GEN x} returns the sign of a real number $x$, valid for \typ{INT}, \typ{REAL} as \kbd{signe}, but also for \typ{FRAC} and \typ{QUAD} of positive discriminants. Raise a type error if \kbd{typ(x)} is not among those. \fun{long}{expi}{GEN x} returns the binary exponent of the real number equal to the \typ{INT}~\kbd{x}. This is a special case of \kbd{gexpo}. \fun{long}{expo}{GEN x} returns the binary exponent of the \typ{REAL}~\kbd{x}. \fun{long}{mpexpo}{GEN x} returns the binary exponent of the \typ{INT} or \typ{REAL}~\kbd{x}. \fun{long}{gexpo}{GEN x} same as \kbd{expo}, but also valid when \kbd{x} is not a \typ{REAL} (returns the largest exponent found among the components of \kbd{x}). When \kbd{x} is an exact~0, this returns \hbox{\kbd{-HIGHEXPOBIT}}, which is lower than any valid exponent. \fun{long}{gexpo_safe}{GEN x} same as \kbd{gexpo}, but returns a value strictly less than \hbox{\kbd{-HIGHEXPOBIT}} when the exponent is not defined (e.g. for a \typ{PADIC} or \typ{INTMOD} component). \fun{long}{valp}{GEN x} returns the $p$-adic valuation (for a \typ{PADIC}) or $X$-adic valuation (for a \typ{SER}, taken with respect to the main variable) of~\kbd{x}. \fun{long}{precp}{GEN x} returns the precision of the \typ{PADIC}~\kbd{x}. \fun{long}{varn}{GEN x} returns the variable number of the \typ{POL} or \typ{SER}~\kbd{x} (between 0 and \kbd{MAXVARN}). \fun{long}{gvar}{GEN x} returns the main variable number when any variable at all occurs in the composite object~\kbd{x} (the smallest variable number which occurs), and \tet{NO_VARIABLE} otherwise. \fun{long}{gvar2}{GEN x} returns the variable number for the ring over which $x$ is defined, e.g. if $x\in \Z[a][b]$ return (the variable number for) $a$. Return \tet{NO_VARIABLE} if $x$ has no variable or is not defined over a polynomial ring. \fun{long}{degpol}{GEN x} is a simple macro returning \kbd{lg(x) - 3}. This is the degree of the \typ{POL}~\kbd{x} with respect to its main variable, \emph{if} its leading coefficient is non-zero (a rational $0$ is impossible, but an inexact $0$ is allowed, as well as an exact modular $0$, e.g. \kbd{Mod(0,2)}). If $x$ has no coefficients (rational $0$ polynomial), its length is $2$ and we return the expected $-1$. \fun{long}{lgpol}{GEN x} is equal to \kbd{degpol(x) + 1}. Used to loop over the coefficients of a \typ{POL} in the following situation: \bprog GEN xd = x + 2; long i, l = lgpol(x); for (i = 0; i < l; i++) foo( xd[i] ). @eprog \fun{long}{precision}{GEN x} If \kbd{x} is of type \typ{REAL}, returns the precision of~\kbd{x}, namely the length of \kbd{x} in \B-bit words if \kbd{x} is not zero, and a reasonable quantity obtained from the exponent of \kbd{x} if \kbd{x} is numerically equal to zero. If \kbd{x} is of type \typ{COMPLEX}, returns the minimum of the precisions of the real and imaginary part. Otherwise, returns~0 (which stands for infinite precision). \fun{long}{lgcols}{GEN x} is equal to \kbd{lg(gel(x,1))}. This is the length of the columns of a \typ{MAT} with at least one column. \fun{long}{nbrows}{GEN x} is equal to \kbd{lg(gel(x,1))-1}. This is the number of rows of a \typ{MAT} with at least one column. \fun{long}{gprecision}{GEN x} as \kbd{precision} for scalars. Returns the lowest precision encountered among the components otherwise. \fun{long}{sizedigit}{GEN x} returns 0 if \kbd{x} is exactly~0. Otherwise, returns \kbd{\key{gexpo}(x)} multiplied by $\log_{10}(2)$. This gives a crude estimate for the maximal number of decimal digits of the components of~\kbd{x}. \subsec{Eval type-dependent information} These routines convert type-dependent information to bitmask to fill the codewords of \kbd{GEN} objects (see \secref{se:impl}). E.g for a \typ{REAL}~\kbd{z}: \bprog z[1] = evalsigne(-1) | evalexpo(2) @eprog Compatible components of a codeword for a given type can be OR-ed as above. \fun{ulong}{evaltyp}{long x} convert type~\kbd{x} to bitmask (first codeword of all \kbd{GEN}s) \fun{long}{evallg}{long x} convert length~\kbd{x} to bitmask (first codeword of all \kbd{GEN}s). Raise overflow error if \kbd{x} is so large that the corresponding length cannot be represented \fun{long}{_evallg}{long x} as \kbd{evallg} \emph{without} the overflow check. \fun{ulong}{evalvarn}{long x} convert variable number~\kbd{x} to bitmask (second codeword of \typ{POL} and \typ{SER}) \fun{long}{evalsigne}{long x} convert sign~\kbd{x} (in $-1,0,1$) to bitmask (second codeword of \typ{INT}, \typ{REAL}, \typ{POL}, \typ{SER}) \fun{long}{evalprecp}{long x} convert $p$-adic ($X$-adic) precision~\kbd{x} to bitmask (second codeword of \typ{PADIC}, \typ{SER}). Raise overflow error if \kbd{x} is so large that the corresponding precision cannot be represented. \fun{long}{_evalprecp}{long x} same as \kbd{evalprecp} \emph{without} the overflow check. \fun{long}{evalvalp}{long x} convert $p$-adic ($X$-adic) valuation~\kbd{x} to bitmask (second codeword of \typ{PADIC}, \typ{SER}). Raise overflow error if \kbd{x} is so large that the corresponding valuation cannot be represented. \fun{long}{_evalvalp}{long x} same as \kbd{evalvalp} \emph{without} the overflow check. \fun{long}{evalexpo}{long x} convert exponent~\kbd{x} to bitmask (second codeword of \typ{REAL}). Raise overflow error if \kbd{x} is so large that the corresponding exponent cannot be represented \fun{long}{_evalexpo}{long x} same as \kbd{evalexpo} \emph{without} the overflow check. \fun{long}{evallgefint}{long x} convert effective length~\kbd{x} to bitmask (second codeword \typ{INT}). This should be less or equal than the length of the \typ{INT}, hence there is no overflow check for the effective length. \subsec{Set type-dependent information} Use these functions and macros with extreme care since usually the corresponding information is set otherwise, and the components and further codeword fields (which are left unchanged) may not be compatible with the new information. \fun{void}{settyp}{GEN x, long s} sets the type number of~\kbd{x} to~\kbd{s}. \fun{void}{setlg}{GEN x, long s} sets the length of~\kbd{x} to~\kbd{s}. This is an efficient way of truncating vectors, matrices or polynomials. \fun{void}{setlgefint}{GEN x, long s} sets the effective length of the \typ{INT} \kbd{x} to~\kbd{s}. The number \kbd{s} must be less than or equal to the length of~\kbd{x}. \fun{void}{setsigne}{GEN x, long s} sets the sign of~\kbd{x} to~\kbd{s}. If \kbd{x} is a \typ{INT} or \typ{REAL}, \kbd{s} must be equal to $-1$, 0 or~1, and if \kbd{x} is a \typ{POL} or \typ{SER}, \kbd{s} must be equal to 0 or~1. No sanity check is made; in particular, setting the sign of a $0$ \typ{INT} to $\pm1$ creates an invalid object. \fun{void}{togglesign}{GEN x} sets the sign $s$ of~\kbd{x} to $-s$, in place. \fun{void}{togglesign_safe}{GEN *x} sets the $s$ sign of~\kbd{*x} to $-s$, in place, unless \kbd{*x} is one of the integer universal constants in which case replace \kbd{*x} by its negation (e.g.~replace \kbd{gen\_1} by \kbd{gen\_m1}). \fun{void}{setabssign}{GEN x} sets the sign $s$ of~\kbd{x} to $|s|$, in place. \fun{void}{affectsign}{GEN x, GEN y} shortcut for \kbd{setsigne(y, signe(x))}. No sanity check is made; in particular, setting the sign of a $0$ \typ{INT} to $\pm1$ creates an invalid object. \fun{void}{affectsign_safe}{GEN x, GEN *y} sets the sign of~\kbd{*y} to that of~\kbd{x}, in place, unless \kbd{*y} is one of the integer universal constants in which case replace \kbd{*y} by its negation if needed (e.g.~replace \kbd{gen\_1} by \kbd{gen\_m1} if \kbd{x} is negative). No other sanity check is made; in particular, setting the sign of a $0$ \typ{INT} to $\pm1$ creates an invalid object. \fun{void}{normalize_frac}{GEN z} assuming $z$ is of the form \kbd{mkfrac(a,b)} with $b\neq 0$, make sure that $b > 0$ by changing the sign of $a$ in place if needed (use \kbd{togglesign}). \fun{void}{setexpo}{GEN x, long s} sets the binary exponent of the \typ{REAL}~\kbd{x} to \kbd{s}. The value \kbd{s} must be a 24-bit signed number. \fun{void}{setvalp}{GEN x, long s} sets the $p$-adic or $X$-adic valuation of~\kbd{x} to~\kbd{s}, if \kbd{x} is a \typ{PADIC} or a \typ{SER}, respectively. \fun{void}{setprecp}{GEN x, long s} sets the $p$-adic precision of the \typ{PADIC}~\kbd{x} to~\kbd{s}. \fun{void}{setvarn}{GEN x, long s} sets the variable number of the \typ{POL} or \typ{SER}~\kbd{x} to~\kbd{s} (where $0\le \kbd{s}\le\kbd{MAXVARN}$). \subsec{Type groups}\label{se:typegroup} In the following functions, \kbd{t} denotes the type of a \kbd{GEN}. They used to be implemented as macros, which could evaluate their argument twice; \emph{no longer}: it is not inefficient to write \bprog is_intreal_t(typ(x)) @eprog \fun{int}{is_recursive_t}{long t} \kbd{true} iff \kbd{t} is a recursive type (the non-recursive types are \typ{INT}, \typ{REAL}, \typ{STR}, \typ{VECSMALL}). Somewhat contrary to intuition, \typ{LIST} is also non-recursive, ; see the Developer's guide for details. \fun{int}{is_intreal_t}{long t} \kbd{true} iff \kbd{t} is \typ{INT} or \typ{REAL}. \fun{int}{is_rational_t}{long t} \kbd{true} iff \kbd{t} is \typ{INT} or \typ{FRAC}. \fun{int}{is_real_t}{long t} \kbd{true} iff \kbd{t} is \typ{INT} or \typ{REAL} or \typ{FRAC}. \fun{int}{is_vec_t}{long t} \kbd{true} iff \kbd{t} is \typ{VEC} or \typ{COL}. \fun{int}{is_matvec_t}{long t} \kbd{true} iff \kbd{t} is \typ{MAT}, \typ{VEC} or \typ{COL}. \fun{int}{is_scalar_t}{long t} \kbd{true} iff \kbd{t} is a scalar, i.e a \typ{INT}, a \typ{REAL}, a \typ{INTMOD}, a \typ{FRAC}, a \typ{COMPLEX}, a \typ{PADIC}, a \typ{QUAD}, or a \typ{POLMOD}. \fun{int}{is_extscalar_t}{long t} \kbd{true} iff \kbd{t} is a scalar (see \kbd{is\_scalar\_t}) or \kbd{t} is \typ{POL}. \fun{int}{is_const_t}{long t} \kbd{true} iff \kbd{t} is a scalar which is not \typ{POLMOD}. \fun{int}{is_noncalc_t}{long t} true if generic operations (\kbd{gadd}, \kbd{gmul}) do not make sense for $t$: corresponds to types \typ{LIST}, \typ{STR}, \typ{VECSMALL}, \typ{CLOSURE} \subsec{Accessors and components}\label{se:accessors} The first two functions return \kbd{GEN} components as copies on the stack: \fun{GEN}{compo}{GEN x, long n} creates a copy of the \kbd{n}-th true component (i.e.\ not counting the codewords) of the object~\kbd{x}. \fun{GEN}{truecoeff}{GEN x, long n} creates a copy of the coefficient of degree~\kbd{n} of~\kbd{x} if \kbd{x} is a scalar, \typ{POL} or \typ{SER}, and otherwise of the \kbd{n}-th component of~\kbd{x}. \smallskip \noindent On the contrary, the following routines return the address of a \kbd{GEN} component. No copy is made on the stack: \fun{GEN}{constant_coeff}{GEN x} returns the address of the constant coefficient of \typ{POL}~\kbd{x}. By convention, a $0$ polynomial (whose \kbd{sign} is $0$) has \kbd{gen\_0} constant term. \fun{GEN}{leading_coeff}{GEN x} returns the address of the leading coefficient of \typ{POL}~\kbd{x}, i.e. the coefficient of largest index stored in the array representing $x$. This may be an inexact $0$. By convention, return \kbd{gen\_0} if the coefficient array is empty. \fun{GEN}{gel}{GEN x, long i} returns the address of the \kbd{x[i]} entry of~\kbd{x}. (\kbd{el} stands for element.) \fun{GEN}{gcoeff}{GEN x, long i, long j} returns the address of the \kbd{x[i,j]} entry of \typ{MAT}~\kbd{x}, i.e.~the coefficient at row~\kbd{i} and column~\kbd{j}. \fun{GEN}{gmael}{GEN x, long i, long j} returns the address of the \kbd{x[i][j]} entry of~\kbd{x}. (\kbd{mael} stands for multidimensional array element.) \fun{GEN}{gmael2}{GEN A, long x1, long x2} is an alias for \kbd{gmael}. Similar macros \tet{gmael3}, \tet{gmael4}, \tet{gmael5} are available. \section{Global numerical constants} These are defined in the various public PARI headers. \subsec{Constants related to word size} \noindent \kbd{long} $\tet{BITS_IN_LONG} = 2^{\tet{TWOPOTBITS_IN_LONG}}$: number of bits in a \kbd{long} (32 or 64). \noindent \kbd{long} \tet{BITS_IN_HALFULONG}: \kbd{BITS\_IN\_LONG} divided by $2$. \noindent \kbd{long} \tet{LONG_MAX}: the largest positive \kbd{long}. \noindent \kbd{ulong} \tet{ULONG_MAX}: the largest \kbd{ulong}. \noindent \kbd{long} \tet{DEFAULTPREC}: the length (\kbd{lg}) of a \typ{REAL} with 64 bits of accuracy \noindent \kbd{long} \tet{MEDDEFAULTPREC}: the length (\kbd{lg}) of a \typ{REAL} with 128 bits of accuracy \noindent \kbd{long} \tet{BIGDEFAULTPREC}: the length (\kbd{lg}) of a \typ{REAL} with 192 bits of accuracy \noindent \kbd{ulong} \tet{HIGHBIT}: the largest power of $2$ fitting in an \kbd{ulong}. \noindent \kbd{ulong} \tet{LOWMASK}: bitmask yielding the least significant bits. \noindent \kbd{ulong} \tet{HIGHMASK}: bitmask yielding the most significant bits. \noindent The last two are used to implement the following convenience macros, returning half the bits of their operand: \fun{ulong}{LOWWORD}{ulong a} returns least significant bits. \fun{ulong}{HIGHWORD}{ulong a} returns most significant bits. \noindent Finally \fun{long}{divsBIL}{long n} returns the Euclidean quotient of $n$ by \kbd{BITS\_IN\_LONG} (with non-negative remainder). \fun{long}{remsBIL}{n} returns the (non-negative) Euclidean remainder of $n$ by \kbd{BITS\_IN\_LONG} \fun{long}{dvmdsBIL}{long n, long *r} \fun{ulong}{dvmduBIL}{ulong n, ulong *r} sets $r$ to \kbd{remsBIL(n)} and returns \kbd{divsBIL(n)}. \subsec{Masks used to implement the \kbd{GEN} type} These constants are used by higher level macros, like \kbd{typ} or \kbd{lg}: \noindent \tet{EXPOnumBITS}, \tet{LGnumBITS}, \tet{SIGNnumBITS}, \tet{TYPnumBITS}, \tet{VALPnumBITS}, \tet{VARNnumBITS}: number of bits used to encode \kbd{expo}, \kbd{lg}, \kbd{signe}, \kbd{typ}, \kbd{valp}, \kbd{varn}. \noindent \tet{PRECPSHIFT}, \tet{SIGNSHIFT}, \tet{TYPSHIFT}, \tet{VARNSHIFT}: shifts used to recover or encode \kbd{precp}, \kbd{varn}, \kbd{typ}, \kbd{signe} \noindent \tet{CLONEBIT}, \tet{EXPOBITS}, \tet{LGBITS}, \tet{PRECPBITS}, \tet{SIGNBITS}, \tet{TYPBITS}, \tet{VALPBITS}, \tet{VARNBITS}: bitmasks used to extract \kbd{isclone}, \kbd{expo}, \kbd{lg}, \kbd{precp}, \kbd{signe}, \kbd{typ}, \kbd{valp}, \kbd{varn} from \kbd{GEN} codewords. \noindent \tet{MAXVARN}: the largest possible variable number. \noindent \tet{NO_VARIABLE}: sentinel returned by \kbd{gvar(x)} when \kbd{x} does not contain any polynomial; has a lower priority than any valid variable number. \noindent \tet{HIGHEXPOBIT}: a power of $2$, one more that the largest possible exponent for a \typ{REAL}. \noindent \tet{HIGHVALPBIT}: a power of $2$, one more that the largest possible valuation for a \typ{PADIC} or a \typ{SER}. \subsec{$\log 2$, $\pi$} These are \kbd{double} approximations to useful constants: \noindent \tet{M_PI}: $\pi$. \noindent \tet{M_LN2}: $\log 2$. \noindent \tet{LOG10_2}: $\log 2 / \log 10$. \noindent \tet{LOG2_10}: $\log 10 / \log 2$. \section{Iterating over small primes, low-level interface} \label{se:primetable} One of the methods used by the high-level prime iterator (see \secref{se:primeiter}), is a precomputed table. Its direct use is deprecated, but documented here. After \kbd{pari\_init(size, maxprime)}, a ``prime table'' is initialized with the successive \emph{differences} of primes up to (possibly just a little beyond) \kbd{maxprime}. The prime table occupies roughly $\kbd{maxprime}/\log(\kbd{maxprime})$ bytes in memory, so be sensible when choosing \kbd{maxprime}; it is $500000$ by default under \kbd{gp} and there is no real benefit in choosing a much larger value: the high-level iterator provide \emph{fast} access to primes up to the \emph{square} of \kbd{maxprime}. In any case, the implementation requires that $\tet{maxprime} < 2^{\B} - 2048$, whatever memory is available. PARI currently guarantees that the first 6547 primes, up to and including 65557, are present in the table, even if you set \kbd{maxprime} to zero. in the \kbd{pari\_init} call. \noindent Some convenience functions: \fun{ulong}{maxprime}{} the largest prime computable using our prime table. \fun{void}{maxprime_check}{ulong B} raise an error if \kbd{maxprime()} is $< B$. After the following initializations (the names $p$ and \var{ptr} are arbitrary of course) \bprog byteptr ptr = diffptr; ulong p = 0; @eprog \noindent calling the macro \tet{NEXT_PRIME_VIADIFF_CHECK}$(p, \var{ptr})$ repeatedly will assign the successive prime numbers to $p$. Overrunning the prime table boundary will raise the error \tet{e_MAXPRIME}, which just prints the error message: \kbd{*** not enough precomputed primes, need primelimit \til $c$} \noindent (for some numerical value $c$), then the macro aborts the computation. The alternative macro \tet{NEXT_PRIME_VIADIFF} operates in the same way, but will omit that check, and is slightly faster. It should be used in the following way: % \bprog byteptr ptr = diffptr; ulong p = 0; if (maxprime() < goal) pari_err_MAXPRIME(goal); /*@Ccom not enough primes */ while (p <= goal) /*@Ccom run through all primes up to \kbd{goal} */ { NEXT_PRIME_VIADIFF(p, ptr); ... } @eprog\noindent Here, we use the general error handling function \kbd{pari\_err} (see \secref{se:err}), with the codeword \kbd{e\_MAXPRIME}, raising the ``not enough primes'' error. This could be rewritten as \bprog maxprime_check(goal); while (p <= goal) /*@Ccom run through all primes up to \kbd{goal} */ { NEXT_PRIME_VIADIFF(p, ptr); ... } @eprog \fun{bytepr}{initprimes}{ulong maxprime, long *L, ulong *lastp} computes a (malloc'ed) ``prime table'', in fact a table of all prime differences for $p < \kbd{maxprime}$ (and possibly a little beyond). Set $L$ to the table length (argument to \kbd{malloc}), and \var{lastp} to the last prime in the table. \fun{void}{initprimetable}{ulong maxprime} computes a prime table (of all prime differences for $p < \kbd{maxprime}$) and assign it to the global variable \kbd{diffptr}. Don't change \kbd{diffptr} directly, call this function instead. This calls \kbd{initprimes} and updates internal data recording the table size. \fun{ulong}{init_primepointer_geq}{ulong a, byteptr *pd} returns the smallest prime $p \geq a$, and sets \kbd{*pd} to the proper offset of \kbd{diffptr} so that \kbd{NEXT\_PRIME\_VIADIFF(p, *pd)} correctly returns \kbd{unextprime(p + 1)}. \fun{ulong}{init_primepointer_gt}{ulong a, byteptr *pd} returns the smallest prime $p > a$. \fun{ulong}{init_primepointer_leq}{ulong a, byteptr *pd} returns the largest prime $p \leq a$. \fun{ulong}{init_primepointer_lt}{ulong a, byteptr *pd} returns the largest prime $p < a$. \section{Handling the PARI stack} \subsec{Allocating memory on the stack} \fun{GEN}{cgetg}{long n, long t} allocates memory on the stack for an object of length \kbd{n} and type~\kbd{t}, and initializes its first codeword. \fun{GEN}{cgeti}{long n} allocates memory on the stack for a \typ{INT} of length~\kbd{n}, and initializes its first codeword. Identical to \kbd{cgetg(n,\typ{INT})}. \fun{GEN}{cgetr}{long n} allocates memory on the stack for a \typ{REAL} of length~\kbd{n}, and initializes its first codeword. Identical to \kbd{cgetg(n,\typ{REAL})}. \fun{GEN}{cgetc}{long n} allocates memory on the stack for a \typ{COMPLEX}, whose real and imaginary parts are \typ{REAL}s of length~\kbd{n}. \fun{GEN}{cgetp}{GEN x} creates space sufficient to hold the \typ{PADIC}~\kbd{x}, and sets the prime $p$ and the $p$-adic precision to those of~\kbd{x}, but does not copy (the $p$-adic unit or zero representative and the modulus of)~\kbd{x}. \fun{GEN}{new_chunk}{size_t n} allocates a \kbd{GEN} with $n$ components, \emph{without} filling the required code words. This is the low-level constructor underlying \kbd{cgetg}, which calls \kbd{new\_chunk} then sets the first code word. It works by simply returning the address \kbd{((GEN)avma) - n}, after checking that it is larger than \kbd{(GEN)bot}. \fun{void}{new_chunk_resize}{size_t x} this function is called by \kbd{new\_chunk} when the PARI stack overflows. There is no need to call it manually. It will either extend the stack or report an \kbd{e\_STACK} error. \fun{char*}{stack_malloc}{size_t n} allocates memory on the stack for $n$ chars (\emph{not} $n$ \kbd{GEN}s). This is faster than using \kbd{malloc}, and easier to use in most situations when temporary storage is needed. In particular there is no need to \kbd{free} individually all variables thus allocated: a simple \kbd{avma = oldavma} might be enough. On the other hand, beware that this is not permanent independent storage, but part of the stack. The memory is aligned on \kbd{sizeof(long)} bytes boundaries. \fun{char*}{stack_malloc_align}{size_t n, long k} as \kbd{stack\_malloc}, but the memory is aligned on \kbd{k} bytes boundaries. The number\kbd{k} must be a multiple of the \kbd{sizeof(long)}. \fun{char*}{stack_calloc}{size_t n} as \kbd{stack\_malloc}, setting the memory to zero. \noindent Objects allocated through these last three functions cannot be \kbd{gerepile}'d, since they are not yet valid \kbd{GEN}s: their codewords must be filled first. \fun{GEN}{cgetalloc}{long t, size_t l}, same as \kbd{cgetg(t, l)}, except that the result is allocated using \tet{pari_malloc} instead of the PARI stack. The resulting \kbd{GEN} is now impervious to garbage collecting routines, but should be freed using \tet{pari_free}. \subsec{Stack-independent binary objects} \fun{GENbin*}{copy_bin}{GEN x} copies $x$ into a malloc'ed structure suitable for stack-independent binary transmission or storage. The object obtained is architecture independent provided, \kbd{sizeof(long)} remains the same on all PARI instances involved, as well as the multiprecision kernel (either native or GMP). \fun{GENbin*}{copy_bin_canon}{GEN x} as \kbd{copy\_bin}, ensuring furthermore that the binary object is independent of the multiprecision kernel. Slower than \kbd{copy\_bin}. \fun{GEN}{bin_copy}{GENbin *p} assuming $p$ was created by \kbd{copy\_bin(x)} (not necessarily by the same PARI instance: transmission or external storage may be involved), restores $x$ on the PARI stack. \noindent The routine \kbd{bin\_copy} transparently encapsulate the following functions: \fun{GEN}{GENbinbase}{GENbin *p} the \kbd{GEN} data actually stored in $p$. All addresses are stored as offsets with respect to a common reference point, so the resulting \kbd{GEN} is unusable unless it is a non-recursive type; private low-level routines must be called first to restore absolute addresses. \fun{void}{shiftaddress}{GEN x, long dec} converts relative addresses to absolute ones. \fun{void}{shiftaddress_canon}{GEN x, long dec} converts relative addresses to absolute ones, and converts leaves from a canonical form to the one specific to the multiprecision kernel in use. The \kbd{GENbin} type stores whether leaves are stored in canonical form, so \kbd{bin\_copy} can call the right variant. \noindent Objects containing closures are harder to e.g. copy and save to disk, since closures contain pointers to libpari functions that will not be valid in another gp instance: there is little chance for them to be loaded at the exact same address in memory. Such objects must be saved along with a linking table. \fun{GEN}{copybin_unlink}{GEN C} returns a linking table allowing to safely store and transmit \typ{CLOSURE} objects in $C$. If $C = \kbd{NULL}$ return a linking table corresponding to the content of all gp variables. $C$ may then be dumped to disk in binary form, for instance. \fun{void}{bincopy_relink}{GEN C, GEN V} given a binary object $C$, as dumped by writebin and read back into a session, and a linking table $V$, restore all closures contained in $C$ (function pointers are translated to their current value). \subsec{Garbage collection} See \secref{se:garbage} for a detailed explanation and many examples. \fun{void}{cgiv}{GEN x} frees object \kbd{x}, assuming it is the last created on the stack. \fun{GEN}{gerepile}{pari_sp p, pari_sp q, GEN x} general garbage collector for the stack. \fun{void}{gerepileall}{pari_sp av, int n, ...} cleans up the stack from \kbd{av} on (i.e from \kbd{avma} to \kbd{av}), preserving the \kbd{n} objects which follow in the argument list (of type \kbd{GEN*}). For instance, \kbd{gerepileall(av, 2, \&x, \&y)} preserves \kbd{x} and \kbd{y}. \fun{void}{gerepileallsp}{pari_sp av, pari_sp ltop, int n, ...} cleans up the stack between \kbd{av} and \kbd{ltop}, updating the \kbd{n} elements which follow \kbd{n} in the argument list (of type \kbd{GEN*}). Check that the elements of \kbd{g} have no component between \kbd{av} and \kbd{ltop}, and assumes that no garbage is present between \kbd{avma} and \kbd{ltop}. Analogous to (but faster than) \kbd{gerepileall} otherwise. \fun{GEN}{gerepilecopy}{pari_sp av, GEN x} cleans up the stack from \kbd{av} on, preserving the object \kbd{x}. Special case of \kbd{gerepileall} (case $\kbd{n} = 1$), except that the routine returns the preserved \kbd{GEN} instead of updating its address through a pointer. \fun{void}{gerepilemany}{pari_sp av, GEN* g[], int n} alternative interface to \kbd{gerepileall}. The preserved \kbd{GEN}s are the elements of the array \kbd{g} of length $n$: \kbd{g[0]}, \kbd{g[1]}, \dots, \kbd{g[$n$-1]}. Obsolete: no more efficient than \kbd{gerepileall}, error-prone, and clumsy (need to declare an extra \kbd{GEN *g}). \fun{void}{gerepilemanysp}{pari_sp av, pari_sp ltop, GEN* g[], int n} alternative interface to \kbd{gerepileallsp}. Obsolete. \fun{void}{gerepilecoeffs}{pari_sp av, GEN x, int n} cleans up the stack from \kbd{av} on, preserving \kbd{x[0]}, \dots, \kbd{x[n-1]} (which are \kbd{GEN}s). \fun{void}{gerepilecoeffssp}{pari_sp av, pari_sp ltop, GEN x, int n} cleans up the stack from \kbd{av} to \kbd{ltop}, preserving \kbd{x[0]}, \dots, \kbd{x[n-1]} (which are \kbd{GEN}s). Same assumptions as in \kbd{gerepilemanysp}, of which this is a variant. For instance \bprog z = cgetg(3, t_COMPLEX); av = avma; garbage(); ltop = avma; z[1] = fun1(); z[2] = fun2(); gerepilecoeffssp(av, ltop, z + 1, 2); return z; @eprog\noindent cleans up the garbage between \kbd{av} and \kbd{ltop}, and connects \kbd{z} and its two components. This is marginally more efficient than the standard \bprog av = avma; garbage(); ltop = avma; z = cgetg(3, t_COMPLEX); z[1] = fun1(); z[2] = fun2(); return gerepile(av, ltop, z); @eprog\noindent \fun{GEN}{gerepileupto}{pari_sp av, GEN q} analogous to (but faster than) \kbd{gerepilecopy}. Assumes that \kbd{q} is connected and that its root was created before any component. If \kbd{q} is not on the stack, this is equivalent to \kbd{avma = av}; in particular, sentinels which are not even proper \kbd{GEN}s such as \kbd{q = NULL} are allowed. \fun{GEN}{gerepileuptoint}{pari_sp av, GEN q} analogous to (but faster than) \kbd{gerepileupto}. Assumes further that \kbd{q} is a \typ{INT}. The length and effective length of the resulting \typ{INT} are equal. \fun{GEN}{gerepileuptoleaf}{pari_sp av, GEN q} analogous to (but faster than) \kbd{gerepileupto}. Assumes further that \kbd{q} is a leaf, i.e a non-recursive type (\kbd{is\_recursive\_t(typ(q))} is non-zero). Contrary to \kbd{gerepileuptoint} and \kbd{gerepileupto}, \kbd{gerepileuptoleaf} leaves length and effective length of a \typ{INT} unchanged. \subsec{Garbage collection: advanced use} \fun{void}{stackdummy}{pari_sp av, pari_sp ltop} inhibits the memory area between \kbd{av} \emph{included} and \kbd{ltop} \emph{excluded} with respect to \kbd{gerepile}, in order to avoid a call to \kbd{gerepile(av, ltop,...)}. The stack space is not reclaimed though. More precisely, this routine assumes that \kbd{av} is recorded earlier than \kbd{ltop}, then marks the specified stack segment as a non-recursive type of the correct length. Thus gerepile will not inspect the zone, at most copy it. To be used in the following situation: \bprog av0 = avma; z = cgetg(t_VEC, 3); gel(z,1) = HUGE(); av = avma; garbage(); ltop = avma; gel(z,2) = HUGE(); stackdummy(av, ltop); @eprog\noindent Compared to the orthodox \bprog gel(z,2) = gerepile(av, ltop, gel(z,2)); @eprog\noindent or even more wasteful \bprog z = gerepilecopy(av0, z); @eprog\noindent we temporarily lose $(\kbd{av} - \kbd{ltop})$ words but save a costly \kbd{gerepile}. In principle, a garbage collection higher up the call chain should reclaim this later anyway. Without the \kbd{stackdummy}, if the $[\kbd{av}, \kbd{ltop}]$ zone is arbitrary (not even valid \kbd{GEN}s as could happen after direct truncation via \kbd{setlg}), we would leave dangerous data in the middle of~\kbd{z}, which would be a problem for a later \bprog gerepile(..., ... , z); @eprog\noindent And even if it were made of valid \kbd{GEN}s, inhibiting the area makes sure \kbd{gerepile} will not inspect their components, saving time. Another natural use in low-level routines is to ``shorten'' an existing \kbd{GEN} \kbd{z} to its first $\kbd{n}-1$ components: \bprog setlg(z, n); stackdummy((pari_sp)(z + lg(z)), (pari_sp)(z + n)); @eprog\noindent or to its last \kbd{n} components: \bprog long L = lg(z) - n, tz = typ(z); stackdummy((pari_sp)(z + L), (pari_sp)z); z += L; z[0] = evaltyp(tz) | evallg(L); @eprog The first scenario (safe shortening an existing \kbd{GEN}) is in fact so common, that we provide a function for this: \fun{void}{fixlg}{GEN z, long ly} a safe variant of \kbd{setlg(z, ly)}. If \kbd{ly} is larger than \kbd{lg(z)} do nothing. Otherwise, shorten $z$ in place, using \kbd{stackdummy} to avoid later \kbd{gerepile} problems. \fun{GEN}{gcopy_avma}{GEN x, pari_sp *AVMA} return a copy of $x$ as from \kbd{gcopy}, except that we pretend that initially \kbd{avma} is \kbd{*AVMA}, and that \kbd{*AVMA} is updated accordingly (so that the total size of $x$ is the difference between the two successive values of \kbd{*AVMA}). It is not necessary for \kbd{*AVMA} to initially point on the stack: \tet{gclone} is implemented using this mechanism. \fun{GEN}{icopy_avma}{GEN x, pari_sp av} analogous to \kbd{gcopy\_avma} but simpler: assume $x$ is a \typ{INT} and return a copy allocated as if initially we had \kbd{avma} equal to \kbd{av}. There is no need to pass a pointer and update the value of the second argument: the new (fictitious) \kbd{avma} is just the return value (typecast to \kbd{pari\_sp}). \subsec{Debugging the PARI stack} \fun{int}{chk_gerepileupto}{GEN x} returns 1 if \kbd{x} is suitable for \kbd{gerepileupto}, and 0 otherwise. In the latter case, print a warning explaining the problem. \fun{void}{dbg_gerepile}{pari_sp ltop} outputs the list of all objects on the stack between \kbd{avma} and \kbd{ltop}, i.e. the ones that would be inspected in a call to \kbd{gerepile(...,ltop,...)}. \fun{void}{dbg_gerepileupto}{GEN q} outputs the list of all objects on the stack that would be inspected in a call to \kbd{gerepileupto(...,q)}. \subsec{Copies} \fun{GEN}{gcopy}{GEN x} creates a new copy of $x$ on the stack. \fun{GEN}{gcopy_lg}{GEN x, long l} creates a new copy of $x$ on the stack, pretending that \kbd{lg(x)} is $l$, which must be less than or equal to \kbd{lg(x)}. If equal, the function is equivalent to \kbd{gcopy(x)}. \fun{int}{isonstack}{GEN x} \kbd{true} iff $x$ belongs to the stack. \fun{void}{copyifstack}{GEN x, GEN y} sets \kbd{y = gcopy(x)} if $x$ belongs to the stack, and \kbd{y = x} otherwise. This macro evaluates its arguments once, contrary to \bprog y = isonstack(x)? gcopy(x): x; @eprog \fun{void}{icopyifstack}{GEN x, GEN y} as \kbd{copyifstack} assuming \kbd{x} is a \typ{INT}. \subsec{Simplify} \fun{GEN}{simplify}{GEN x} you should not need that function in library mode. One rather uses: \fun{GEN}{simplify_shallow}{GEN x} shallow, faster, version of \tet{simplify}. \section{The PARI heap} \subsec{Introduction} It is implemented as a doubly-linked list of \kbd{malloc}'ed blocks of memory, equipped with reference counts. Each block has type \kbd{GEN} but need not be a valid \kbd{GEN}: it is a chunk of data preceded by a hidden header (meaning that we allocate $x$ and return $x + \kbd{header size}$). A \tev{clone}, created by \tet{gclone}, is a block which is a valid \kbd{GEN} and whose \emph{clone bit} is set. \subsec{Public interface} \fun{GEN}{newblock}{size_t n} allocates a block of $n$ \emph{words} (not bytes). \fun{void}{killblock}{GEN x} deletes the block~$x$ created by \kbd{newblock}. Fatal error if $x$ not a block. \fun{GEN}{gclone}{GEN x} creates a new permanent copy of $x$ on the heap (allocated using \kbd{newblock}). The \emph{clone bit} of the result is set. \fun{GEN}{gcloneref}{GEN x} if $x$ is not a clone, clone it and return the result; otherwise, increase the clone reference count and return $x$. \fun{void}{gunclone}{GEN x} deletes a clone. Deletion at first only decreases the reference count by $1$. If the count remains positive, no further action is taken; if the count becomes zero, then the clone is actually deleted. In the current implementation, this is an alias for \kbd{killblock}, but it is cleaner to kill clones (valid \kbd{GEN}s) using this function, and other blocks using \kbd{killblock}. \fun{void}{gunclone_deep}{GEN x} is only useful in the context of the GP interpreter which may replace arbitrary components of container types (\typ{VEC}, \typ{COL}, \typ{MAT}, \typ{LIST}) by clones. If $x$ is such a container, the function recursively deletes all clones among the components of $x$, then unclones $x$. Useless in library mode: simply use \kbd{gunclone}. \fun{void}{traverseheap}{void(*f)(GEN, void *), void *data} this applies \kbd{f($x$, data)} to each object $x$ on the PARI heap, most recent first. Mostly for debugging purposes. \fun{GEN}{getheap}{} a simple wrapper around \kbd{traverseheap}. Returns a two-component row vector giving the number of objects on the heap and the amount of memory they occupy in long words. \fun{GEN}{cgetg_block}{long x, long y} as \kbd{cgetg(x,y)}, creating the return value as a \kbd{block}, not on the PARI stack. \fun{GEN}{cgetr_block}{long prec} as \kbd{cgetr(prec)}, creating the return value as a \kbd{block}, not on the PARI stack. \subsec{Implementation note} The hidden block header is manipulated using the following private functions: \fun{void*}{bl_base}{GEN x} returns the pointer that was actually allocated by \kbd{malloc} (can be freed). \fun{long}{bl_refc}{GEN x} the reference count of $x$: the number of pointers to this block. Decremented in \kbd{killblock}, incremented by the private function \fun{void}{gclone_refc}{GEN x}; block is freed when the reference count reaches $0$. \fun{long}{bl_num}{GEN x} the index of this block in the list of all blocks allocated so far (including freed blocks). Uniquely identifies a block until $2^\B$ blocks have been allocated and this wraps around. \fun{GEN}{bl_next}{GEN x} the block \emph{after} $x$ in the linked list of blocks (\kbd{NULL} if $x$ is the last block allocated not yet killed). \fun{GEN}{bl_prev}{GEN x} the block allocated \emph{before} $x$ (never \kbd{NULL}). We documented the last four routines as functions for clarity (and type checking) but they are actually macros yielding valid lvalues. It is allowed to write \kbd{bl\_refc(x)++} for instance. \section{Handling user and temp variables} Low-level implementation of user / temporary variables is liable to change. We describe it nevertheless for completeness. Currently variables are implemented by a single array of values divided in 3 zones: 0--\kbd{nvar} (user variables), \kbd{max\_avail}--\kbd{MAXVARN} (temporary variables), and \kbd{nvar+1}--\kbd{max\_avail-1} (pool of free variable numbers). \subsec{Low-level} \fun{void}{pari_var_init}{}: a small part of \kbd{pari\_init}. Resets variable counters \kbd{nvar} and \kbd{max\_avail}, notwithstanding existing variables! In effect, this even deletes \kbd{x}. Don't use it. \fun{void}{pari_var_close}{void} attached destructor, called by \kbd{pari\_close}. \fun{long}{pari_var_next}{}: returns \kbd{nvar}, the number of the next user variable we can create. \fun{long}{pari_var_next_temp}{} returns \kbd{max\_avail}, the number of the next temp variable we can create. \fun{long}{pari_var_create}{entree *ep} low-level initialization of an \kbd{EpVAR}. Return the attached (new) variable number. \fun{GEN}{vars_sort_inplace}{GEN z} given a \typ{VECSMALL} $z$ of variable numbers, sort $z$ in place according to variable priorities (highest priority comes first). \fun{GEN}{vars_to_RgXV}{GEN h} given a \typ{VECSMALL} $z$ of variable numbers, return the \typ{VEC} of \kbd{pol\_x}$(z[i])$. \subsec{User variables} \fun{long}{fetch_user_var}{char *s} returns a user variable whose name is \kbd{s}, creating it is needed (and using an existing variable otherwise). Returns its variable number. \fun{GEN}{fetch_var_value}{long v} returns a shallow copy of the current value of the variable numbered $v$. Return \kbd{NULL} for a temporary variable. \fun{entree*}{is_entry}{const char *s} returns the \kbd{entree*} attached to an identifier \kbd{s} (variable or function), from the interpreter hashtables. Return \kbd{NULL} is the identifier is unknown. \subsec{Temporary variables} \fun{long}{fetch_var}{void} returns the number of a new temporary variable (decreasing \kbd{max\_avail}). \fun{long}{delete_var}{void} delete latest temp variable created and return the number of previous one. \fun{void}{name_var}{long n, char *s} rename temporary variable number \kbd{n} to \kbd{s}; mostly useful for nicer printout. Error when trying to rename a user variable. \section{Adding functions to PARI} \subsec{Nota Bene} % As mentioned in the \kbd{COPYING} file, modified versions of the PARI package can be distributed under the conditions of the GNU General Public License. If you do modify PARI, however, it is certainly for a good reason, and we would like to know about it, so that everyone can benefit from your changes. There is then a good chance that your improvements are incorporated into the next release. We classify changes to PARI into four rough classes, where changes of the first three types are almost certain to be accepted. The first type includes all improvements to the documentation, in a broad sense. This includes correcting typos or inaccuracies of course, but also items which are not really covered in this document, e.g.~if you happen to write a tutorial, or pieces of code exemplifying fine points unduly omitted in the present manual. The second type is to expand or modify the configuration routines and skeleton files (the \kbd{Configure} script and anything in the \kbd{config/} subdirectory) so that compilation is possible (or easier, or more efficient) on an operating system previously not catered for. This includes discovering and removing idiosyncrasies in the code that would hinder its portability. The third type is to modify existing (mathematical) code, either to correct bugs, to add new functionality to existing functions, or to improve their efficiency. Finally the last type is to add new functions to PARI. We explain here how to do this, so that in particular the new function can be called from \kbd{gp}. \subsec{Coding guidelines}\label{se:coding_guidelines} \noindent Code your function in a file of its own, using as a guide other functions in the PARI sources. One important thing to remember is to clean the stack before exiting your main function, since otherwise successive calls to the function clutters the stack with unnecessary garbage, and stack overflow occurs sooner. Also, if it returns a \kbd{GEN} and you want it to be accessible to \kbd{gp}, you have to make sure this \kbd{GEN} is suitable for \kbd{gerepileupto} (see \secref{se:garbage}). If error messages or warnings are to be generated in your function, use \kbd{pari\_err} and \kbd{pari\_warn} respectively. Recall that \kbd{pari\_err} does not return but ends with a \kbd{longjmp} statement. As well, instead of explicit \kbd{printf}~/ \kbd{fprintf} statements, use the following encapsulated variants: \fun{void}{pari_putc}{char c}: write character \kbd{c} to the output stream. \fun{void}{pari_puts}{char *s}: write \kbd{s} to the output stream. \fun{void}{pari_printf}{const char *fmt, ...}: write following arguments to the output stream, according to the conversion specifications in format \kbd{fmt} (see \tet{printf}). \fun{void}{err_printf}{const char *fmt, ...}: as \tet{pari_printf}, writing to PARI's current error stream. \fun{void}{err_flush}{void} flush error stream. Declare all public functions in an appropriate header file, if you want to access them from C. The other functions should be declared \kbd{static} in your file. Your function is now ready to be used in library mode after compilation and creation of the library. If possible, compile it as a shared library (see the \kbd{Makefile} coming with the \kbd{extgcd} example in the distribution). It is however still inaccessible from \kbd{gp}.\smallskip \subsec{GP prototypes, parser codes} \label{se:gp.interface} A \tev{GP prototype} is a character string describing all the GP parser needs to know about the function prototype. It contains a sequence of the following atoms: \settabs\+\indent&\kbd{Dxxx}\quad&\cr \noindent\item Return type: \kbd{GEN} by default (must be valid for \kbd{gerepileupto}), otherwise the following can appear as the \emph{first} char of the code string: % \+& \kbd{i} & return \kbd{int}\cr \+& \kbd{l} & return \kbd{long}\cr \+& \kbd{u} & return \kbd{ulong}\cr \+& \kbd{v} & return \kbd{void}\cr \+& \kbd{m} & return a \kbd{GEN} which is not \kbd{gerepile}-safe.\cr The \kbd{m} code is used for member functions, to avoid unnecessary copies. A copy opcode is generated by the compiler if the result needs to be kept safe for later use. \noindent\item Mandatory arguments, appearing in the same order as the input arguments they describe: % \+& \kbd{G} & \kbd{GEN}\cr \+& \kbd{\&}& \kbd{*GEN}\cr \+& \kbd{L} & \kbd{long} (we implicitly typecast \kbd{int} to \kbd{long})\cr \+& \kbd{U} & \kbd{ulong} \cr \+& \kbd{V} & loop variable\cr \+& \kbd{n} & variable, expects a \idx{variable number} (a \kbd{long}, not an \kbd{*entree})\cr \+& \kbd{W} & a \kbd{GEN} which is a lvalue to be modified in place (for \typ{LIST})\cr \+& \kbd{r} & raw input (treated as a string without quotes). Quoted args are copied as strings\cr \+&&\quad Stops at first unquoted \kbd{')'} or \kbd{','}. Special chars can be quoted using \kbd{'\bs'}\cr \+&&\quad Example: \kbd{aa"b\bs n)"c} yields the string \kbd{"aab\bs{n})c"}\cr \+& \kbd{s} & expanded string. Example: \kbd{Pi"x"2} yields \kbd{"3.142x2"}\cr \+&&\quad Unquoted components can be of any PARI type, converted to string following\cr \+&&\quad current output format\cr \+& \kbd{I} & closure whose value is ignored, as in \kbd{for} loops,\cr \+&&\quad to be processed by \fun{void}{closure_evalvoid}{GEN C}\cr \+& \kbd{E} & closure whose value is used, as in \kbd{sum} loops,\cr \+&&\quad to be processed by \fun{void}{closure_evalgen}{GEN C}\cr \+& \kbd{J} & implicit function of arity $1$, as in \kbd{parsum} loops,\cr \+&&\quad to be processed by \fun{void}{closure_callgen1}{GEN C}\cr \noindent A \tev{closure} is a GP function in compiled (bytecode) form. It can be efficiently evaluated using the \kbd{closure\_eval}$xxx$ functions. \noindent\item Automatic arguments: % \+& \kbd{f} & Fake \kbd{*long}. C function requires a pointer but we do not use the resulting \kbd{long}\cr \+& \kbd{b} & current real precision in bits \cr \+& \kbd{p} & current real precision in words \cr \+& \kbd{P} & series precision (default \kbd{seriesprecision}, global variable \kbd{precdl} for the library)\cr \+& \kbd{C} & lexical context (internal, for \kbd{eval}, see \kbd{localvars\_read\_str})\cr \noindent\item Syntax requirements, used by functions like \kbd{for}, \kbd{sum}, etc.: % \+& \kbd{=} & separator \kbd{=} required at this point (between two arguments)\cr \noindent\item Optional arguments and default values: % \+& \kbd{E*} & any number of expressions, possibly 0 (see \kbd{E})\cr \+& \kbd{s*} & any number of strings, possibly 0 (see \kbd{s})\cr \+& \kbd{D\var{xxx}} & argument can be omitted and has a default value\cr The \kbd{E*} code reads all remaining arguments in closure context and passes them as a single \typ{VEC}. The \kbd{s*} code reads all remaining arguments in \tev{string context} and passes the list of strings as a single \typ{VEC}. The automatic concatenation rules in string context are implemented so that adjacent strings are read as different arguments, as if they had been comma-separated. For instance, if the remaining argument sequence is: \kbd{"xx" 1, "yy"}, the \kbd{s*} atom sends \kbd{[a, b, c]}, where $a$, $b$, $c$ are \kbd{GEN}s of type \typ{STR} (content \kbd{"xx"}), \typ{INT} (equal to $1$) and \typ{STR} (content \kbd{"yy"}). The format to indicate a default value (atom starts with a \kbd{D}) is ``\kbd{D\var{value},\var{type},}'', where \var{type} is the code for any mandatory atom (previous group), \var{value} is any valid GP expression which is converted according to \var{type}, and the ending comma is mandatory. For instance \kbd{D0,L,} stands for ``this optional argument is converted to a \kbd{long}, and is \kbd{0} by default''. So if the user-given argument reads \kbd{1 + 3} at this point, \kbd{4L} is sent to the function; and \kbd{0L} if the argument is omitted. The following special notations are available: \settabs\+\indent\indent&\kbd{Dxxx}\quad& optional \kbd{*GEN},&\cr \+&\kbd{DG}& optional \kbd{GEN}, & send \kbd{NULL} if argument omitted.\cr \+&\kbd{D\&}& optional \kbd{*GEN}, send \kbd{NULL} if argument omitted.\cr \+&&\quad The argument must be prefixed by \kbd{\&}.\cr \+&\kbd{DI}, \kbd{DE}& optional closure, send \kbd{NULL} if argument omitted.\cr \+&\kbd{DP}& optional \kbd{long}, send \kbd{precdl} if argument omitted.\cr \+&\kbd{DV}& optional \kbd{*entree}, send \kbd{NULL} if argument omitted.\cr \+&\kbd{Dn}& optional variable number, $-1$ if omitted.\cr \+&\kbd{Dr}& optional raw string, send \kbd{NULL} if argument omitted.\cr \+&\kbd{Ds}& optional \kbd{char *}, send \kbd{NULL} if argument omitted.\cr \misctitle{Hardcoded limit} C functions using more than 20 arguments are not supported. Use vectors if you really need that many parameters. When the function is called under \kbd{gp}, the prototype is scanned and each time an atom corresponding to a mandatory argument is met, a user-given argument is read (\kbd{gp} outputs an error message it the argument was missing). Each time an optional atom is met, a default value is inserted if the user omits the argument. The ``automatic'' atoms fill in the argument list transparently, supplying the current value of the corresponding variable (or a dummy pointer). For instance, here is how you would code the following prototypes, which do not involve default values: \bprog GEN f(GEN x, GEN y, long prec) ----> "GGp" void f(GEN x, GEN y, long prec) ----> "vGGp" void f(GEN x, long y, long prec) ----> "vGLp" long f(GEN x) ----> "lG" int f(long x) ----> "iL" @eprog\noindent If you want more examples, \kbd{gp} gives you easy access to the parser codes attached to all GP functions: just type \kbd{\b{h} \var{function}}. You can then compare with the C prototypes as they stand in \kbd{paridecl.h}. \misctitle{Remark} If you need to implement complicated control statements (probably for some improved summation functions), you need to know how the parser implements closures and lexicals and how the evaluator lets you deal with them, in particular the \tet{push_lex} and \tet{pop_lex} functions. Check their descriptions and adapt the source code in \kbd{language/sumiter.c} and \kbd{language/intnum.c}. \subsec{Integration with \kbd{gp} as a shared module} In this section we assume that your Operating System is supported by \tet{install}. You have written a function in C following the guidelines is \secref{se:coding_guidelines}; in case the function returns a \kbd{GEN}, it must satisfy \kbd{gerepileupto} assumptions (see \secref{se:garbage}). You then succeeded in building it as part of a shared library and want to finally tell \kbd{gp} about your function. First, find a name for it. It does not have to match the one used in library mode, but consistency is nice. It has to be a valid GP identifier, i.e.~use only alphabetic characters, digits and the underscore character (\kbd{\_}), the first character being alphabetic. Then figure out the correct \idx{parser code} corresponding to the function prototype (as explained in~\secref{se:gp.interface}) and write a GP script like the following: \bprog install(libname, code, gpname, library) addhelp(gpname, "some help text") @eprog \noindent The \idx{addhelp} part is not mandatory, but very useful if you want others to use your module. \kbd{libname} is how the function is named in the library, usually the same name as one visible from C. Read that file from your \kbd{gp} session, for instance from your \idx{preferences file} (or \kbd{gprc}), and that's it. You can now use the new function \var{gpname} under \kbd{gp}, and we would very much like to hear about it! \smallskip \misctitle{Example} A complete description could look like this: \bprog { install(bnfinit0, "GD0,L,DGp", ClassGroupInit, "libpari.so"); addhelp(ClassGroupInit, "ClassGroupInit(P,{flag=0},{data=[]}): compute the necessary data for ..."); } @eprog\noindent which means we have a function \kbd{ClassGroupInit} under \kbd{gp}, which calls the library function \kbd{bnfinit0} . The function has one mandatory argument, and possibly two more (two \kbd{'D'} in the code), plus the current real precision. More precisely, the first argument is a \kbd{GEN}, the second one is converted to a \kbd{long} using \kbd{itos} (\kbd{0} is passed if it is omitted), and the third one is also a \kbd{GEN}, but we pass \kbd{NULL} if no argument was supplied by the user. This matches the C prototype (from \kbd{paridecl.h}): % \bprog GEN bnfinit0(GEN P, long flag, GEN data, long prec) @eprog\noindent This function is in fact coded in \kbd{basemath/buch2.c}, and is in this case completely identical to the GP function \kbd{bnfinit} but \kbd{gp} does not need to know about this, only that it can be found somewhere in the shared library \kbd{libpari.so}. \misctitle{Important note} You see in this example that it is the function's responsibility to correctly interpret its operands: \kbd{data = NULL} is interpreted \emph{by the function} as an empty vector. Note that since \kbd{NULL} is never a valid \kbd{GEN} pointer, this trick always enables you to distinguish between a default value and actual input: the user could explicitly supply an empty vector! \subsec{Library interface for \kbd{install}} There is a corresponding library interface for this \kbd{install} functionality, letting you expand the GP parser/evaluator available in the library with new functions from your C source code. Functions such as \tet{gp_read_str} may then evaluate a GP expression sequence involving calls to these new function! \fun{entree *}{install}{void *f, const char *gpname, const char *code} \noindent where \kbd{f} is the (address of the) function (cast to \kbd{void*}), \kbd{gpname} is the name by which you want to access your function from within your GP expressions, and \kbd{code} is as above. \subsec{Integration by patching \kbd{gp}} If \tet{install} is not available, and installing Linux or a BSD operating system is not an option (why?), you have to hardcode your function in the \kbd{gp} binary. Here is what needs to be done: \item Fetch the complete sources of the PARI distribution. \item Drop the function source code module in an appropriate directory (a priori \kbd{src/modules}), and declare all public functions in \kbd{src/headers/paridecl.h}. \item Choose a help section and add a file \kbd{src/functions/\var{section}/\var{gpname}} containing the following, keeping the notation above: \bprog Function: @com\var{gpname} Section: @com\var{section} C-Name: @com\var{libname} Prototype: @com\var{code} Help: @com\var{some help text} @eprog\noindent (If the help text does not fit on a single line, continuation lines must start by a whitespace character.) Two GP2C-related fields (\kbd{Description} and \kbd{Wrapper}) are also available to improve the code GP2C generates when compiling scripts involving your function. See the GP2C documentation for details. \item Launch \kbd{Configure}, which should pick up your C files and build an appropriate \kbd{Makefile}. At this point you can recompile \kbd{gp}, which will first rebuild the functions database. \misctitle{Example} We reuse the \kbd{ClassGroupInit} / \kbd{bnfinit0} from the preceding section. Since the C source code is already part of PARI, we only need to add a file \kbd{functions/number\_fields/ClassGroupInit} \noindent containing the following: \bprog Function: ClassGroupInit Section: number_fields C-Name: bnfinit0 Prototype: GD0,L,DGp Help: ClassGroupInit(P,{flag=0},{tech=[]}): this routine does @com\dots @eprog\noindent and recompile \kbd{gp}. \section{Globals related to PARI configuration} \subsec{PARI version numbers} \noindent \tet{paricfg_version_code} encodes in a single \kbd{long}, the Major and minor version numbers as well as the patchlevel. \fun{long}{PARI_VERSION}{long M, long m, long p} produces the version code attached to release $M.m.p$. Each code identifies a unique PARI release, and corresponds to the natural total order on the set of releases (bigger code number means more recent release). \noindent \tet{PARI_VERSION_SHIFT} is the number of bits used to store each of the integers $M$, $m$, $p$ in the version code. \noindent \tet{paricfg_vcsversion} is a version string related to the revision control system used to handle your sources, if any. For instance \kbd{git-}\emph{commit hash} if compiled from a git repository. The two character strings \tet{paricfg_version} and \tet{paricfg_buildinfo}, correspond to the first two lines printed by \kbd{gp} just before the Copyright message. The character string \tet{paricfg_compiledate} is the date of compilation which appears on the next line. The character string \tet{paricfg_mt_engine} is the name of the threading engine on the next line. \fun{GEN}{pari_version}{} returns the version number as a PARI object, a \typ{VEC} with three \typ{INT} and one \typ{STR} components. \subsec{Miscellaneous} \tet{paricfg_datadir}: character string. The location of PARI's \tet{datadir}. \tet{paricfg_gphelp}: character string. The name of an external help command for \kbd{??} (such as the \kbd{gphelp} script) \newpage \chapter{Arithmetic kernel: Level 0 and 1} \section{Level 0 kernel (operations on ulongs)} \subsec{Micro-kernel} The Level 0 kernel simulates basic operations of the 68020 processor on which PARI was originally implemented. They need ``global'' \kbd{ulong} variables \kbd{overflow} (which will contain only 0 or 1) and \kbd{hiremainder} to function properly. A routine using one of these lowest-level functions where the description mentions either \kbd{hiremainder} or \kbd{overflow} must declare the corresponding \bprog LOCAL_HIREMAINDER; /* provides 'hiremainder' */ LOCAL_OVERFLOW; /* provides 'overflow' */ @eprog\noindent in a declaration block. Variables \kbd{hiremainder} and \kbd{overflow} then become available in the enclosing block. For instance a loop over the powers of an \kbd{ulong}~\kbd{p} protected from overflows could read \bprog while (pk < lim) { LOCAL_HIREMAINDER; ... pk = mulll(pk, p); if (hiremainder) break; } @eprog\noindent For most architectures, the functions mentioned below are really chunks of inlined assembler code, and the above `global' variables are actually local register values. \fun{ulong}{addll}{ulong x, ulong y} adds \kbd{x} and \kbd{y}, returns the lower \B\ bits and puts the carry bit into \kbd{overflow}. \fun{ulong}{addllx}{ulong x, ulong y} adds \kbd{overflow} to the sum of the \kbd{x} and \kbd{y}, returns the lower \B\ bits and puts the carry bit into \kbd{overflow}. \fun{ulong}{subll}{ulong x, ulong y} subtracts \kbd{x} and \kbd{y}, returns the lower \B\ bits and put the carry (borrow) bit into \kbd{overflow}. \fun{ulong}{subllx}{ulong x, ulong y} subtracts \kbd{overflow} from the difference of \kbd{x} and \kbd{y}, returns the lower \B\ bits and puts the carry (borrow) bit into \kbd{overflow}. \fun{int}{bfffo}{ulong x} returns the number of leading zero bits in \kbd{x}. That is, the number of bit positions by which it would have to be shifted left until its leftmost bit first becomes equal to~1, which can be between 0 and $\B-1$ for nonzero \kbd{x}. When \kbd{x} is~0, the result is undefined. \fun{ulong}{mulll}{ulong x, ulong y} multiplies \kbd{x} by \kbd{y}, returns the lower \B\ bits and stores the high-order \B\ bits into \kbd{hiremainder}. \fun{ulong}{addmul}{ulong x, ulong y} adds \kbd{hiremainder} to the product of \kbd{x} and \kbd{y}, returns the lower \B\ bits and stores the high-order \B\ bits into \kbd{hiremainder}. \fun{ulong}{divll}{ulong x, ulong y} returns the quotient of $ \left(\kbd{hiremainder} * 2^{\B}\right) + \kbd{x} $ by \kbd{y} and stores the remainder into \kbd{hiremainder}. An error occurs if the quotient cannot be represented by an \kbd{ulong}, i.e.~if initially $\kbd{hiremainder}\ge\kbd{y}$. \fun{long}{hammingl}{ulong x)} returns the Hamming weight of $x$, i.e.~the number of non-zero bits in its binary expansion. \misctitle{Obsolete routines} Those functions are awkward and no longer used; they are only provided for backward compatibility: \fun{ulong}{shiftl}{ulong x, ulong y} returns $x$ shifted left by $y$ bits, i.e.~\kbd{$x$ << $y$}, where we assume that $0\leq y\leq\B$. The global variable \kbd{hiremainder} receives the bits that were shifted out, i.e.~\kbd{$x$ >> $(\B - y)$}. \fun{ulong}{shiftlr}{ulong x, ulong y} returns $x$ shifted right by $y$ bits, i.e.~\kbd{$x$ >> $y$}, where we assume that $0\leq y\leq\B$. The global variable \kbd{hiremainder} receives the bits that were shifted out, i.e.~\kbd{$x$ << $(\B - y)$}. \subsec{Modular kernel} The following routines are not part of the level 0 kernel per se, but implement modular operations on words in terms of the above. They are written so that no overflow may occur. Let $m \geq 1$ be the modulus; all operands representing classes modulo $m$ are assumed to belong to $[0,m-1]$. The result may be wrong for a number of reasons otherwise: it may not be reduced, overflow can occur, etc. \fun{int}{odd}{ulong x} returns 1 if $x$ is odd, and 0 otherwise. \fun{int}{both_odd}{ulong x, ulong y} returns 1 if $x$ and $y$ are both odd, and 0 otherwise. \fun{ulong}{invmod2BIL}{ulong x} returns the smallest positive representative of $x^{-1}$ mod $2^\B$, assuming $x$ is odd. \fun{ulong}{Fl_add}{ulong x, ulong y, ulong m} returns the smallest non-negative representative of $x + y$ modulo $m$. \fun{ulong}{Fl_neg}{ulong x, ulong m} returns the smallest non-negative representative of $-x$ modulo $m$. \fun{ulong}{Fl_sub}{ulong x, ulong y, ulong m} returns the smallest non-negative representative of $x - y$ modulo $m$. \fun{long}{Fl_center}{ulong x, ulong m, ulong mo2} returns the representative in $]-m/2,m/2]$ of $x$ modulo $m$. Assume $0 \leq x < m$ and $\kbd{mo2} = m >> 1$. \fun{ulong}{Fl_mul}{ulong x, ulong y, ulong m} returns the smallest non-negative representative of $x y$ modulo $m$. \fun{ulong}{Fl_double}{ulong x, ulong m} returns $2x$ modulo $m$. \fun{ulong}{Fl_triple}{ulong x, ulong m} returns $3x$ modulo $m$. \fun{ulong}{Fl_halve}{ulong x, ulong m} returns $z$ such that $2\*z = x$ modulo $m$ assuming such $z$ exists. \fun{ulong}{Fl_sqr}{ulong x, ulong m} returns the smallest non-negative representative of $x^2$ modulo $m$. \fun{ulong}{Fl_inv}{ulong x, ulong m} returns the smallest positive representative of $x^{-1}$ modulo $m$. If $x$ is not invertible mod~$m$, raise an exception. \fun{ulong}{Fl_invsafe}{ulong x, ulong m} returns the smallest positive representative of $x^{-1}$ modulo $m$. If $x$ is not invertible mod~$m$, return $0$ (which is ambiguous if $m=1$). \fun{ulong}{Fl_invgen}{ulong x, ulong m, ulong *pg} set \kbd{*pg} to $g = \gcd(x,m)$ and return $u$ in $(\Z/m\Z)^*$ such that $x u = g$ modulo $m$. We have $g = 1$ if and only if $x$ is invertible, and in this case $u$ is its inverse. \fun{ulong}{Fl_div}{ulong x, ulong y, ulong m} returns the smallest non-negative representative of $x y^{-1}$ modulo $m$. If $y$ is not invertible mod $m$, raise an exception. \fun{ulong}{Fl_powu}{ulong x, ulong n, ulong m} returns the smallest non-negative representative of $x^n$ modulo $m$. \fun{GEN}{Fl_powers}{ulong x, long n, ulong p} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ modulo $m$, as a \typ{VECSMALL}. \fun{ulong}{Fl_sqrt}{ulong x, ulong p} returns the square root of \kbd{x} modulo \kbd{p} (smallest non-negative representative). Assumes \kbd{p} to be prime, and \kbd{x} to be a square modulo \kbd{p}. \fun{ulong}{Fl_sqrtl}{ulong x, ulong l, ulong p} returns a $l$-the root of \kbd{x} modulo \kbd{p}. Assumes \kbd{p} to be prime and $p \equiv 1 \pmod{l}$, and \kbd{x} to be a $l$-th power modulo \kbd{p}. \fun{ulong}{Fl_sqrtn}{ulong a, ulong n, ulong p, ulong *zn} returns \kbd{ULONG\_MAX} if $a$ is not an $n$-th power residue mod $p$. Otherwise, returns an $n$-th root of $a$; if \kbd{zn} is non-\kbd{NULL} set it to a primitive $m$-th root of 1, $m = \gcd(p-1,n)$ allowing to compute all $m$ solutions in $\F_p$ of the equation $x^n = a$. \fun{ulong}{Fl_log}{ulong a, ulong g, ulong ord, ulong p} Let $g$ such that $g^{ord} \equiv 1 \pmod{p}$. Return an integer $e$ such that $a^e \equiv g \pmod{p}$. If $e$ does not exist, the result is undefined. \fun{ulong}{Fl_order}{ulong a, ulong o, ulong p} returns the order of the \kbd{Fp} \kbd{a}. It is assumed that \kbd{o} is a multiple of the order of \kbd{a}, $0$ being allowed (no non-trivial information). \fun{ulong}{random_Fl}{ulong p} returns a pseudo-random integer uniformly distributed in $0, 1, \dots p-1$. \fun{ulong}{pgener_Fl}{ulong p} returns the smallest \idx{primitive root} modulo \kbd{p}, assuming \kbd{p} is prime. \fun{ulong}{pgener_Zl}{ulong p} returns the smallest primitive root modulo $p^k$, $k > 1$, assuming $p$ is an odd prime. \fun{ulong}{pgener_Fl_local}{ulong p, GEN L}, see \kbd{gener\_Fp\_local}, \kbd{L} is an \kbd{Flv}. \subsec{Modular kernel with ``precomputed inverse''} This is based on an algorithm by T. Grandlund and N. M\"{o}ller in ``Improved division by invariant integers'' \url{http://gmplib.org/~tege/division-paper.pdf}. In the following, we set $B=\B$. \fun{ulong}{get_Fl_red}{ulong p} returns a pseudo inverse \var{pi} for $p$ \fun{ulong}{divll_pre}{ulong x, ulong p, ulong yi} as divll, where $yi$ is the pseudo inverse of $y$. \fun{ulong}{remll_pre}{ulong u1, ulong u0, ulong p, ulong pi} returns the Euclidean remainder of $u_1\*2^B+u_0$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. This function is faster if $u_1 < p$. \fun{ulong}{remlll_pre}{ulong u2, ulong u1, ulong u0, ulong p, ulong pi} returns the Euclidean remainder of $u_2\*2^{2\*B}+u_1\*2^{B}+u_0$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_sqr_pre}{ulong x, ulong p, ulong pi} returns $x^2$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_mul_pre}{ulong x, ulong y, ulong p, ulong pi} returns $x\*y$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_addmul_pre}{ulong a, ulong b, ulong c, ulong p, ulong pi} returns $a+b\*c$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_addmulmul_pre}{ulong a,ulong b, ulong c,ulong d, ulong p, ulong pi} returns $a\*b+c\*d$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_powu_pre}{ulong x, ulong n, ulong p, ulong pi} returns $x^n$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. \fun{GEN}{Fl_powers_pre}{ulong x, long n, ulong p, ulong pi} returns the vector (\typ{VECSMALL}) $(x^0, \dots, x^n)$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_log_pre}{ulong a, ulong g, ulong ord, ulong p, ulong pi} as \kbd{Fl\_log}, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_sqrt_pre}{ulong x, ulong p, ulong pi} returns a square root of $x$ modulo $p$, assuming $pi$ is the pseudo inverse of $p$. See \kbd{Fl\_sqrt}. \fun{ulong}{Fl_sqrtl_pre}{ulong x, ulong l, ulong p, ulong pi} returns a $l$-the root of \kbd{x} modulo \kbd{p}, assuming $pi$ is the pseudo inverse of $p$, $p$ prime and $p \equiv 1 \pmod{l}$, and \kbd{x} to be a $l$-th power modulo \kbd{p}. \fun{ulong}{Fl_sqrtn_pre}{ulong x, ulong n, ulong p, ulong *zn} See \kbd{Fl\_sqrtn}, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_2gener_pre}{ulong p, ulong pi} return a generator of the $2$-Sylow subgroup of $\F_p^*$. To use with \kbd{Fl\_sqrt\_pre\_i}. \fun{ulong}{Fl_sqrt_pre_i}{ulong x, ulong s2, ulong p, ulong pi} as \kbd{Fl\_sqrt\_pre} where \kbd{s2} is the element returned by \kbd{Fl\_2gener\_pre}. \subsec{Switching between Fl\_xxx and standard operators} Even though the \kbd{Fl\_xxx} routines are efficient, they are slower than ordinary \kbd{long} operations, using the standard \kbd{+}, \kbd{\%}, etc. operators. The following macro is used to choose in a portable way the most efficient functions for given operands: \fun{int}{SMALL_ULONG}{ulong p} true if $2p^2 <2^\B$. In that case, it is possible to use ordinary operators efficiently. If $p < 2^\B$, one may still use the \kbd{Fl\_xxx} routines. Otherwise, one must use generic routines. For instance, the scalar product of the \kbd{GEN}s $x$ and $y$ mod $p$ could be computed as follows. \bprog long i, l = lg(x); if (lgefint(p) > 3) { /* arbitrary */ GEN s = gen_0; for (i = 1; i < l; i++) s = addii(s, mulii(gel(x,i), gel(y,i))); return modii(s, p). } else { ulong s = 0, pp = itou(p); x = ZV_to_Flv(x, pp); y = ZV_to_Flv(y, pp); if (SMALL_ULONG(pp)) { /* very small */ for (i = 1; i < l; i++) { s += x[i] * y[i]; if (s & HIGHBIT) s %= pp; } s %= pp; } else { /* small */ for (i = 1; i < l; i++) s = Fl_add(s, Fl_mul(x[i], y[i], pp), pp); } return utoi(s); } @eprog\noindent In effect, we have three versions of the same code: very small, small, and arbitrary inputs. The very small and arbitrary variants use lazy reduction and reduce only when it becomes necessary: when overflow might occur (very small), and at the very end (very small, arbitrary). \section{Level 1 kernel (operations on longs, integers and reals)} \misctitle{Note} Some functions consist of an elementary operation, immediately followed by an assignment statement. They will be introduced as in the following example: \fun{GEN}{gadd[z]}{GEN x, GEN y[, GEN z]} followed by the explicit description of the function \fun{GEN}{gadd}{GEN x, GEN y} \noindent which creates its result on the stack, returning a \kbd{GEN} pointer to it, and the parts in brackets indicate that there exists also a function \fun{void}{gaddz}{GEN x, GEN y, GEN z} \noindent which assigns its result to the pre-existing object \kbd{z}, leaving the stack unchanged. These assignment variants are kept for backward compatibility but are inefficient: don't use them. \subsec{Creation} \fun{GEN}{cgeti}{long n} allocates memory on the PARI stack for a \typ{INT} of length~\kbd{n}, and initializes its first codeword. Identical to \kbd{cgetg(n,\typ{INT})}. \fun{GEN}{cgetipos}{long n} allocates memory on the PARI stack for a \typ{INT} of length~\kbd{n}, and initializes its two codewords. The sign of \kbd{n} is set to $1$. \fun{GEN}{cgetineg}{long n} allocates memory on the PARI stack for a negative \typ{INT} of length~\kbd{n}, and initializes its two codewords. The sign of \kbd{n} is set to $-1$. \fun{GEN}{cgetr}{long n} allocates memory on the PARI stack for a \typ{REAL} of length~\kbd{n}, and initializes its first codeword. Identical to \kbd{cgetg(n,\typ{REAL})}. \fun{GEN}{cgetc}{long n} allocates memory on the PARI stack for a \typ{COMPLEX}, whose real and imaginary parts are \typ{REAL}s of length~\kbd{n}. \fun{GEN}{real_1}{long prec} create a \typ{REAL} equal to $1$ to \kbd{prec} words of accuracy. \fun{GEN}{real_1_bit}{long bitprec} create a \typ{REAL} equal to $1$ to \kbd{bitprec} bits of accuracy. \fun{GEN}{real_m1}{long prec} create a \typ{REAL} equal to $-1$ to \kbd{prec} words of accuracy. \fun{GEN}{real_0_bit}{long bit} create a \typ{REAL} equal to $0$ with exponent $-\kbd{bit}$. \fun{GEN}{real_0}{long prec} is a shorthand for \bprog real_0_bit( -prec2nbits(prec) ) @eprog \fun{GEN}{int2n}{long n} creates a \typ{INT} equal to \kbd{1< 2$. \fun{void}{affii}{GEN x, GEN z} assigns the \typ{INT} \kbd{x} into the \typ{INT}~\kbd{z}. \fun{void}{affir}{GEN x, GEN z} assigns the \typ{INT} \kbd{x} into the \typ{REAL}~\kbd{z}. Assumes that $\kbd{lg(z)} > 2$. \fun{void}{affiz}{GEN x, GEN z} assigns \typ{INT}~\kbd{x} into \typ{INT} or \typ{REAL}~\kbd{z}. Assumes that $\kbd{lg(z)} > 2$. \fun{void}{affsi}{long s, GEN z} assigns the \kbd{long}~\kbd{s} into the \typ{INT}~\kbd{z}. Assumes that $\kbd{lg(z)} > 2$. \fun{void}{affsr}{long s, GEN z} assigns the \kbd{long}~\kbd{s} into the \typ{REAL}~\kbd{z}. Assumes that $\kbd{lg(z)} > 2$. \fun{void}{affsz}{long s, GEN z} assigns the \kbd{long}~\kbd{s} into the \typ{INT} or \typ{REAL}~\kbd{z}. Assumes that $\kbd{lg(z)} > 2$. \fun{void}{affui}{ulong u, GEN z} assigns the \kbd{ulong}~\kbd{u} into the \typ{INT}~\kbd{z}. Assumes that $\kbd{lg(z)} > 2$. \fun{void}{affur}{ulong u, GEN z} assigns the \kbd{ulong}~\kbd{u} into the \typ{REAL}~\kbd{z}. Assumes that $\kbd{lg(z)} > 2$. \fun{void}{affrr}{GEN x, GEN z} assigns the \typ{REAL}~\kbd{x} into the \typ{REAL}~\kbd{z}. \fun{void}{affgr}{GEN x, GEN z} assigns the scalar \kbd{x} into the \typ{REAL}~\kbd{z}, if possible. \noindent The function \kbd{affrs} and \kbd{affri} do not exist. So don't use them. \fun{void}{affrr_fixlg}{GEN y, GEN z} a variant of \kbd{affrr}. First shorten $z$ so that it is no longer than $y$, then assigns $y$ to $z$. This is used in the following scenario: room is reserved for the result but, due to cancellation, fewer words of accuracy are available than had been anticipated; instead of appending meaningless $0$s to the mantissa, we store what was actually computed. Note that shortening $z$ is not quite straightforward, since \kbd{setlg(z, ly)} would leave garbage on the stack, which \kbd{gerepile} might later inspect. It is done using \fun{void}{fixlg}{GEN z, long ly} see \tet{stackdummy} and the examples that follow. \subsec{Copy} \fun{GEN}{icopy}{GEN x} copy relevant words of the \typ{INT}~\kbd{x} on the stack: the length and effective length of the copy are equal. \fun{GEN}{rcopy}{GEN x} copy the \typ{REAL}~\kbd{x} on the stack. \fun{GEN}{leafcopy}{GEN x} copy the leaf~\kbd{x} on the stack (works in particular for \typ{INT}s and \typ{REAL}s). Contrary to \kbd{icopy}, \kbd{leafcopy} preserves the original length of a \typ{INT}. The obsolete form \fun{GEN}{mpcopy}{GEN x} is still provided for backward compatibility. This function also works on recursive types, copying them as if they were leaves, i.e.~making a shallow copy in that case: the components of the copy point to the same data as the component of the source; see also \kbd{shallowcopy}. \fun{GEN}{leafcopy_avma}{GEN x, pari_sp av} analogous to \kbd{gcopy\_avma} but simpler: assume $x$ is a leaf and return a copy allocated as if initially we had \kbd{avma} equal to \kbd{av}. There is no need to pass a pointer and update the value of the second argument: the new (fictitious) \kbd{avma} is just the return value (typecast to \kbd{pari\_sp}). \fun{GEN}{icopyspec}{GEN x, long nx} copy the \kbd{nx} words \kbd{x[2]}, \dots, \kbd{x[nx+1]} to make up a new \typ{INT}. Set the sign to $1$. \subsec{Conversions} \fun{GEN}{itor}{GEN x, long prec} converts the \typ{INT}~\kbd{x} to a \typ{REAL} of length \kbd{prec} and return the latter. Assumes that $\kbd{prec} > 2$. \fun{long}{itos}{GEN x} converts the \typ{INT}~\kbd{x} to a \kbd{long} if possible, otherwise raise an exception. We consider the conversion to be possible if and only if $|x| \leq \kbd{LONG\_MAX}$, i.e. $|x| < 2^{63}$ on a 64-bit architecture. Since the range is symetric, the output of \kbd{itos} can safely be negated. \fun{long}{itos_or_0}{GEN x} converts the \typ{INT}~\kbd{x} to a \kbd{long} if possible, otherwise return $0$. \fun{int}{is_bigint}{GEN n} true if \kbd{itos(n)} would give an error. \fun{ulong}{itou}{GEN x} converts the \typ{INT}~\kbd{|x|} to an \kbd{ulong} if possible, otherwise raise an exception. The conversion is possible if and only if $\kbd{lgefint}(x) \leq 3$. \fun{long}{itou_or_0}{GEN x} converts the \typ{INT}~\kbd{|x|} to an \kbd{ulong} if possible, otherwise return $0$. \fun{GEN}{stoi}{long s} creates the \typ{INT} corresponding to the \kbd{long}~\kbd{s}. \fun{GEN}{stor}{long s, long prec} converts the \kbd{long}~\kbd{s} into a \typ{REAL} of length \kbd{prec} and return the latter. Assumes that $\kbd{prec} > 2$. \fun{GEN}{utoi}{ulong s} converts the \kbd{ulong}~\kbd{s} into a \typ{INT} and return the latter. \fun{GEN}{utoipos}{ulong s} converts the \emph{non-zero} \kbd{ulong}~\kbd{s} into a \typ{INT} and return the latter. \fun{GEN}{utoineg}{ulong s} converts the \emph{non-zero} \kbd{ulong}~\kbd{s} into the \typ{INT} $-s$ and return the latter. \fun{GEN}{utor}{ulong s, long prec} converts the \kbd{ulong}~\kbd{s} into a \typ{REAL} of length \kbd{prec} and return the latter. Assumes that $\kbd{prec} > 2$. \fun{GEN}{rtor}{GEN x, long prec} converts the \typ{REAL}~\kbd{x} to a \typ{REAL} of length \kbd{prec} and return the latter. If $\kbd{prec} < \kbd{lg(x)}$, round properly. If $\kbd{prec} > \kbd{lg(x)}$, pad with zeroes. Assumes that $\kbd{prec} > 2$. \noindent The following function is also available as a special case of \tet{mkintn}: \fun{GEN}{uu32toi}{ulong a, ulong b} returns the \kbd{GEN} equal to $2^{32} a + b$, \emph{assuming} that $a,b < 2^{32}$. This does not depend on \kbd{sizeof(long)}: the behavior is as above on both $32$ and $64$-bit machines. \fun{GEN}{uu32toineg}{ulong a, ulong b} returns the \kbd{GEN} equal to $- (2^{32} a + b)$, \emph{assuming} that $a,b < 2^{32}$ and that one of $a$ or $b$ is positive. This does not depend on \kbd{sizeof(long)}: the behavior is as above on both $32$ and $64$-bit machines. \fun{GEN}{uutoi}{ulong a, ulong b} returns the \kbd{GEN} equal to $2^{\B} a + b$. \fun{GEN}{uutoineg}{ulong a, ulong b} returns the \kbd{GEN} equal to $-(2^{\B} a + b)$. \subsec{Integer parts} The following four functions implement the conversion from \typ{REAL} to \typ{INT} using standard rounding modes. Contrary to usual semantics (complement the mantissa with an infinite number of 0), they will raise an error \emph{precision loss in truncation} if the \typ{REAL} represents a range containing more than one integer. \fun{GEN}{ceilr}{GEN x} smallest integer larger or equal to the \typ{REAL}~\kbd{x} (i.e.~the \kbd{ceil} function). \fun{GEN}{floorr}{GEN x} largest integer smaller or equal to the \typ{REAL}~\kbd{x} (i.e.~the \kbd{floor} function). \fun{GEN}{roundr}{GEN x} rounds the \typ{REAL} \kbd{x} to the nearest integer (towards~$+\infty$ in case of tie). \fun{GEN}{truncr}{GEN x} truncates the \typ{REAL}~\kbd{x} (not the same as \kbd{floorr} if \kbd{x} is negative). The following four function are analogous, but can also treat the trivial case when the argument is a \typ{INT}: \fun{GEN}{mpceil}{GEN x} as \kbd{ceilr} except that \kbd{x} may be a \typ{INT}. \fun{GEN}{mpfloor}{GEN x} as \kbd{floorr} except that \kbd{x} may be a \typ{INT}. \fun{GEN}{mpround}{GEN x} as \kbd{roundr} except that \kbd{x} may be a \typ{INT}. \fun{GEN}{mptrunc}{GEN x} as \kbd{truncr} except that \kbd{x} may be a \typ{INT}. \fun{GEN}{diviiround}{GEN x, GEN y} if \kbd{x} and \kbd{y} are \typ{INT}s, returns the quotient $\kbd{x}/\kbd{y}$ of \kbd{x} and~\kbd{y}, rounded to the nearest integer. If $\kbd{x}/\kbd{y}$ falls exactly halfway between two consecutive integers, then it is rounded towards~$+\infty$ (as for \tet{roundr}). \fun{GEN}{ceil_safe}{GEN x}, \kbd{x} being a real number (not necessarily a \typ{REAL}) returns the smallest integer which is larger than any possible incarnation of \kbd{x}. (Recall that a \typ{REAL} represents an interval of possible values.) Note that \kbd{gceil} raises an exception if the input accuracy is too low compared to its magnitude. \fun{GEN}{floor_safe}{GEN x}, \kbd{x} being a real number (not necessarily a \typ{REAL}) returns the largest integer which is smaller than any possible incarnation of \kbd{x}. (Recall that a \typ{REAL} represents an interval of possible values.) Note that \kbd{gfloor} raises an exception if the input accuracy is too low compared to its magnitude. \fun{GEN}{trunc_safe}{GEN x}, \kbd{x} being a real number (not necessarily a \typ{REAL}) returns the integer with the largest absolute value, which is closer to $0$ than any possible incarnation of \kbd{x}. (Recall that a \typ{REAL} represents an interval of possible values.) \fun{GEN}{roundr_safe}{GEN x} rounds the \typ{REAL} \kbd{x} to the nearest integer (towards~$+\infty$). Complement the mantissa with an infinite number of $0$ before rounding, hence never raise an exception. \subsec{$2$-adic valuations and shifts} \fun{long}{vals}{long s} 2-adic valuation of the \kbd{long}~\kbd{s}. Returns $-1$ if \kbd{s} is equal to 0. \fun{long}{vali}{GEN x} 2-adic valuation of the \typ{INT}~\kbd{x}. Returns $-1$ if \kbd{x} is equal to 0. \fun{GEN}{mpshift}{GEN x, long n} shifts the~\typ{INT} or \typ{REAL} \kbd{x} by~\kbd{n}. If \kbd{n} is positive, this is a left shift, i.e.~multiplication by $2^{\kbd{n}}$. If \kbd{n} is negative, it is a right shift by~$-\kbd{n}$, which amounts to the truncation of the quotient of \kbd{x} by~$2^{-\kbd{n}}$. \fun{GEN}{shifti}{GEN x, long n} shifts the \typ{INT}~$x$ by~$n$. \fun{GEN}{shiftr}{GEN x, long n} shifts the \typ{REAL}~$x$ by~$n$. \fun{void}{shiftr_inplace}{GEN x, long n} shifts the \typ{REAL}~$x$ by~$n$, in place. \fun{GEN}{trunc2nr}{GEN x, long n} given a \typ{REAL} $x$, returns \kbd{truncr(shiftr(x,n))}, but faster, without leaving garbage on the stack and never raising a \emph{precision loss in truncation} error. Called by \tet{gtrunc2n}. \fun{GEN}{trunc2nr_lg}{GEN x, long lx, long n} given a \typ{REAL} $x$, returns \kbd{trunc2nr(x,n)}, pretending that the length of $x$ is \kbd{lx}, which must be $\leq \kbd{lg}(x)$. \fun{GEN}{mantissa2nr}{GEN x, long n} given a \typ{REAL} $x$, returns the mantissa of $x 2^n$ (disregards the exponent of $x$). Equivalent to \bprog trunc2nr(x, n-expo(x)+bit_prec(x)-1) @eprog \fun{GEN}{mantissa_real}{GEN z, long *e} returns the mantissa $m$ of $z$, and sets \kbd{*e} to the exponent $\kbd{bit\_accuracy(lg(z))}-1-\kbd{expo}(z)$, so that $z = m / 2^e$. \misctitle{Low-level} In the following two functions, $s$(ource) and $t$(arget) need not be valid \kbd{GEN}s (in practice, they usually point to some part of a \typ{REAL} mantissa): they are considered as arrays of words representing some mantissa, and we shift globally $s$ by $n > 0$ bits, storing the result in $t$. We assume that $m\leq M$ and only access $s[m], s[m+1],\ldots s[M]$ (read) and likewise for $t$ (write); we may have $s = t$ but more general overlaps are not allowed. The word $f$ is concatenated to $s$ to supply extra bits. \fun{void}{shift_left}{GEN t, GEN s, long m, long M, ulong f, ulong n} shifts the mantissa $$s[m], s[m+1],\ldots s[M], f$$ left by $n$ bits. \fun{void}{shift_right}{GEN t, GEN s, long m, long M, ulong f, ulong n} shifts the mantissa $$f, s[m], s[m+1],\ldots s[M]$$ right by $n$ bits. \subsec{From \typ{INT} to bits or digits in base $2^k$ and back} \fun{GEN}{binary_zv}{GEN x} given a \typ{INT} $x$, return a \typ{VECSMALL} of bits, from most significant to least significant. \fun{GEN}{binary_2k}{GEN x, long k} given a \typ{INT} $x$, and $k > 0$, return a \typ{VEC} of digits of $x$ in base $2^k$, as \typ{INT}s, from most significant to least significant. \fun{GEN}{binary_2k_nv}{GEN x, long k} given a \typ{INT} $x$, and $0 < k < \tet{BITS_IN_LONG}$, return a \typ{VECSMALL} of digits of $x$ in base $2^k$, as \kbd{ulong}s, from most significant to least significant. \fun{GEN}{bits_to_int}{GEN x, long l} given a vector $x$ of $l$ bits (as a \typ{VECSMALL} or even a pointer to a part of a larger vector, so not a proper \kbd{GEN}), return the integer $\sum_{i = 1}^l x[i] 2^{l-i}$, as a \typ{INT}. \fun{ulong}{bits_to_u}{GEN v, long l} same as \tet{bits_to_int}, where $l < \tet{BITS_IN_LONG}$, so we can return an \kbd{ulong}. \fun{GEN}{fromdigitsu}{GEN x, GEN B} given a \typ{VECSMALL} $x$ of length $l$ and a \typ{INT} $B$, return the integer $\sum_{i = 1}^l x[i] B^{i-1}$, as a \typ{INT}, where the \kbd{x[i]} are seen as unsigned integers. \fun{GEN}{fromdigits_2k}{GEN x, long k} converse of \tet{binary_2k}; given a \typ{VEC} $x$ of length $l$ and a positive \kbd{long} $k$, where each $x[i]$ is a \typ{INT} with $0\leq x[i] < 2^k$, return the integer $\sum_{i = 1}^l x[i] 2^{k(l-i)}$, as a \typ{INT}. \fun{GEN}{nv_fromdigits_2k}{GEN x, long k} as \tet{fromdigits_2k}, but with $x$ being a \typ{VECSMALL} and each $x[i]$ being a \kbd{ulong} with $0\leq x[i] < 2^{\min\{k,\tet{BITS_IN_LONG}\}}$. Here $k$ may be any positive \kbd{long}, and the $x[i]$ are regarded as $k$-bit integers by truncating or extending with zeroes. \subsec{Integer valuation} For integers $x$ and $p$, such that $x\neq 0$ and $|p| > 1$, we define $v_p(x)$ to be the largest integer exponent $e$ such that $p^e$ divides $x$. If $p$ is prime, this is the ordinary valuation of $x$ at $p$. \fun{long}{Z_pvalrem}{GEN x, GEN p, GEN *r} applied to \typ{INT}s $\kbd{x}\neq 0$ and~\kbd{p}, $|\kbd{p}| > 1$, returns $e := v_p(x)$ The quotient $\kbd{x}/\kbd{p}^e$ is returned in~\kbd{*r}. If $|\kbd{p}|$ is a prime, \kbd{*r} is the prime-to-\kbd{p} part of~\kbd{x}. \fun{long}{Z_pval}{GEN x, GEN p} as \kbd{Z\_pvalrem} but only returns $v_p(x)$. \fun{long}{Z_lvalrem}{GEN x, ulong p, GEN *r} as \kbd{Z\_pvalrem}, except that \kbd{p} is an \kbd{ulong} ($\kbd{p} > 1$). \fun{long}{Z_lvalrem_stop}{GEN *x, ulong p, int *stop} assume $x > 0$; returns $e := v_p(x)$ and replaces $x$ by $x / p^e$. Set \kbd{stop} to $1$ if the new value of $x$ is $ < p^2$ (and $0$ otherwise). To be used when trial dividing $x$ by successive primes: the \kbd{stop} condition is cheaply tested while testing whether $p$ divides $x$ (is the quotient less than $p$?), and allows to decide that $n$ is prime if no prime $< p$ divides $n$. Not memory-clean. \fun{long}{Z_lval}{GEN x, ulong p} as \kbd{Z\_pval}, except that \kbd{p} is an \kbd{ulong} ($\kbd{p} > 1$). \fun{long}{u_lvalrem}{ulong x, ulong p, ulong *r} as \kbd{Z\_pvalrem}, except the inputs/outputs are now \kbd{ulong}s. \fun{long}{u_lvalrem_stop}{ulong *n, ulong p, int *stop} as \kbd{Z\_pvalrem\_stop}. \fun{long}{u_pvalrem}{ulong x, GEN p, ulong *r} as \kbd{Z\_pvalrem}, except \kbd{x} and \kbd{r} are now \kbd{ulong}s. \fun{long}{u_lval}{ulong x, ulong p} as \kbd{Z\_pval}, except the inputs are now \kbd{ulong}s. \fun{long}{u_pval}{ulong x, GEN p} as \kbd{Z\_pval}, except \kbd{x} is now an \kbd{ulong}. \fun{long}{z_lval}{long x, ulong p} as \kbd{u\_lval}, for signed \kbd{x}. \fun{long}{z_lvalrem}{long x, ulong p} as \kbd{u\_lvalrem}, for signed \kbd{x}. \fun{long}{z_pval}{long x, GEN p} as \kbd{Z\_pval}, except \kbd{x} is now a \kbd{long}. \fun{long}{z_pvalrem}{long x, GEN p} as \kbd{Z\_pvalrem}, except \kbd{x} is now a \kbd{long}. \fun{long}{Q_pval}{GEN x, GEN p} valuation at the \typ{INT} \kbd{p} of the \typ{INT} or \typ{FRAC}~\kbd{x}. \fun{long}{factorial_lval}{ulong n, ulong p} returns $v_p(n!)$, assuming $p$ is prime. The following convenience functions generalize \kbd{Z\_pval} and its variants to ``containers'' (\kbd{ZV} and \kbd{ZX}): \fun{long}{ZV_pvalrem}{GEN x, GEN p, GEN *r} $x$ being a \kbd{ZV} (a vector of \typ{INT}s), return the min $v$ of the valuations of its components and set \kbd{*r} to $x/p^v$. Infinite loop if $x$ is the zero vector. This function is not stack clean. \fun{long}{ZV_pval}{GEN x, GEN p} as \kbd{ZV\_pvalrem} but only returns the ``valuation''. \fun{int}{ZV_Z_dvd}{GEN x, GEN p} returns $1$ if $p$ divides all components of $x$ and $0$ otherwise. Faster than testing \kbd{ZV\_pval(x,p) >= 1}. \fun{long}{ZV_lvalrem}{GEN x, ulong p, GEN *px} as \kbd{ZV\_pvalrem}, except that \kbd{p} is an \kbd{ulong} ($\kbd{p} > 1$). This function is not stack-clean. \fun{long}{ZV_lval}{GEN x, ulong p} as \kbd{ZV\_pval}, except that \kbd{p} is an \kbd{ulong} ($\kbd{p} > 1$). \fun{long}{ZX_pvalrem}{GEN x, GEN p, GEN *r} as \kbd{ZV\_pvalrem}, for a \kbd{ZX} $x$ (a \typ{POL} with \typ{INT} coefficients). This function is not stack-clean. \fun{long}{ZX_pval}{GEN x, GEN p} as \kbd{ZV\_pval} for a \kbd{ZX} $x$. \fun{long}{ZX_lvalrem}{GEN x, ulong p, GEN *px} as \kbd{ZV\_lvalrem}, a \kbd{ZX} $x$. This function is not stack-clean. \fun{long}{ZX_lval}{GEN x, ulong p} as \kbd{ZX\_pval}, except that \kbd{p} is an \kbd{ulong} ($\kbd{p} > 1$). \subsec{Generic unary operators} Let ``\op'' be a unary operation among \item \key{neg}: negation ($-x$). \item \key{abs}: absolute value ($|x|$). \item \key{sqr}: square ($x^2$). \noindent The names and prototypes of the low-level functions corresponding to \op\ are as follows. The result is of the same type as~\kbd{x}. \funno{GEN}{\op i}{GEN x} creates the result of \op\ applied to the \typ{INT}~\kbd{x}. \funno{GEN}{\op r}{GEN x} creates the result of \op\ applied to the \typ{REAL}~\kbd{x}. \funno{GEN}{mp\op}{GEN x} creates the result of \op\ applied to the \typ{INT} or \typ{REAL}~\kbd{x}. \noindent Complete list of available functions: \fun{GEN}{absi}{GEN x}, \fun{GEN}{absr}{GEN x}, \fun{GEN}{mpabs}{GEN x} \fun{GEN}{negi}{GEN x}, \fun{GEN}{negr}{GEN x}, \fun{GEN}{mpneg}{GEN x} \fun{GEN}{sqri}{GEN x}, \fun{GEN}{sqrr}{GEN x}, \fun{GEN}{mpsqr}{GEN x} \fun{GEN}{absi_shallow}{GEN x} $x$ being a \typ{INT}, returns a shallow copy of $|x|$, in particular returns $x$ itself when $x \geq 0$, and \kbd{negi($x$)} otherwise. \fun{GEN}{mpabs_shallow}{GEN x} $x$ being a \typ{INT} or a \typ{REAL}, returns a shallow copy of $|x|$, in particular returns $x$ itself when $x \geq 0$, and \kbd{mpneg($x$)} otherwise. \noindent Some miscellaneous routines: \fun{GEN}{sqrs}{long x} returns $x^2$. \fun{GEN}{sqru}{ulong x} returns $x^2$. \subsec{Comparison operators} \fun{long}{minss}{long x, long y} \fun{ulong}{minuu}{ulong x, ulong y} \fun{double}{mindd}{double x, double y} returns the \kbd{min} of $x$ and $y$. \fun{long}{maxss}{long x, long y} \fun{ulong}{maxuu}{ulong x, ulong y} \fun{double}{maxdd}{double x, double y} returns the \kbd{max} of $x$ and $y$. \smallskip \fun{int}{mpcmp}{GEN x, GEN y} compares the \typ{INT} or \typ{REAL}~\kbd{x} to the \typ{INT} or \typ{REAL}~\kbd{y}. The result is the sign of $\kbd{x}-\kbd{y}$. \fun{int}{cmpii}{GEN x, GEN y} compares the \typ{INT} \kbd{x} to the \typ{INT}~\kbd{y}. \fun{int}{cmpir}{GEN x, GEN y} compares the \typ{INT} \kbd{x} to the \typ{REAL}~\kbd{y}. \fun{int}{cmpis}{GEN x, long s} compares the \typ{INT}~\kbd{x} to the \kbd{long}~\kbd{s}. \fun{int}{cmpiu}{GEN x, ulong s} compares the \typ{INT}~\kbd{x} to the \kbd{ulong}~\kbd{s}. \fun{int}{cmpsi}{long s, GEN x} compares the \kbd{long}~\kbd{s} to the \typ{INT}~\kbd{x}. \fun{int}{cmpui}{ulong s, GEN x} compares the \kbd{ulong}~\kbd{s} to the \typ{INT}~\kbd{x}. \fun{int}{cmpsr}{long s, GEN x} compares the \kbd{long}~\kbd{s} to the \typ{REAL}~\kbd{x}. \fun{int}{cmpri}{GEN x, GEN y} compares the \typ{REAL}~\kbd{x} to the \typ{INT}~\kbd{y}. \fun{int}{cmprr}{GEN x, GEN y} compares the \typ{REAL}~\kbd{x} to the \typ{REAL}~\kbd{y}. \fun{int}{cmprs}{GEN x, long s} compares the \typ{REAL}~\kbd{x} to the \kbd{long}~\kbd{s}. \fun{int}{equalii}{GEN x, GEN y} compares the \typ{INT}s \kbd{x} and~\kbd{y}. The result is $1$ if $\kbd{x} = \kbd{y}$, $0$ otherwise. \fun{int}{equalrr}{GEN x, GEN y} compares the \typ{REAL}s \kbd{x} and~\kbd{y}. The result is $1$ if $\kbd{x} = \kbd{y}$, $0$ otherwise. Equality is decided according to the following rules: all real zeroes are equal, and different from a non-zero real; two non-zero reals are equal if all their digits coincide up to the length of the shortest of the two, and the remaining words in the mantissa of the longest are all $0$. \fun{int}{equalis}{GEN x, long s} compare the \typ{INT} \kbd{x} and the \kbd{long}~\kbd{s}. The result is $1$ if $\kbd{x} = \kbd{y}$, $0$ otherwise. \fun{int}{equalsi}{long s, GEN x} \fun{int}{equaliu}{GEN x, ulong s} compare the \typ{INT} \kbd{x} and the \kbd{ulong}~\kbd{s}. The result is $1$ if $\kbd{x} = \kbd{y}$, $0$ otherwise. \fun{int}{equalui}{ulong s, GEN x} The remaining comparison operators disregard the sign of their operands \fun{int}{absequaliu}{GEN x, ulong u} compare the absolute value of the \typ{INT} \kbd{x} and the \kbd{ulong}~\kbd{s}. The result is $1$ if $|\kbd{x}| = \kbd{y}$, $0$ otherwise. This is marginally more efficient than \kbd{equalis} even when \kbd{x} is known to be non-negative. \fun{int}{absequalui}{ulong u, GEN x} \fun{int}{abscmpiu}{GEN x, ulong u} compare the absolute value of the \typ{INT} \kbd{x} and the \kbd{ulong}~\kbd{u}. \fun{int}{abscmpui}{ulong u, GEN x} \fun{int}{abscmpii}{GEN x, GEN y} compares the \typ{INT}s \kbd{x} and~\kbd{y}. The result is the sign of $|\kbd{x}| - |\kbd{y}|$. \fun{int}{absequalii}{GEN x, GEN y} compares the \typ{INT}s \kbd{x} and~\kbd{y}. The result is $1$ if $|\kbd{x}| = |\kbd{y}|$, $0$ otherwise. \fun{int}{abscmprr}{GEN x, GEN y} compares the \typ{REAL}s \kbd{x} and~\kbd{y}. The result is the sign of $|\kbd{x}| - |\kbd{y}|$. \fun{int}{absrnz_equal2n}{GEN x} tests whether a non-zero \typ{REAL} \kbd{x} is equal to $\pm 2^e$ for some integer $e$. \fun{int}{absrnz_equal1}{GEN x} tests whether a non-zero \typ{REAL} \kbd{x} is equal to $\pm 1$. \subsec{Generic binary operators}\label{se:genbinop} The operators in this section have arguments of C-type \kbd{GEN}, \kbd{long}, and \kbd{ulong}, and only \typ{INT} and \typ{REAL} \kbd{GEN}s are allowed. We say an argument is a real type if it is a \typ{REAL} \kbd{GEN}, and an integer type otherwise. The result is always a \typ{REAL} unless both \kbd{x} and \kbd{y} are integer types. Let ``\op'' be a binary operation among \item \key{add}: addition (\kbd{x + y}). \item \key{sub}: subtraction (\kbd{x - y}). \item \key{mul}: multiplication (\kbd{x * y}). \item \key{div}: division (\kbd{x / y}). In the case where \kbd{x} and \kbd{y} are both integer types, the result is the Euclidean quotient, where the remainder has the same sign as the dividend~\kbd{x}. It is the ordinary division otherwise. A division-by-$0$ error occurs if \kbd{y} is equal to $0$. The last two generic operations are defined only when arguments have integer types; and the result is a \typ{INT}: \item \key{rem}: remainder (``\kbd{x \% y}''). The result is the Euclidean remainder corresponding to \kbd{div},~i.e. its sign is that of the dividend~\kbd{x}. \item \key{mod}: true remainder (\kbd{x \% y}). The result is the true Euclidean remainder, i.e.~non-negative and less than the absolute value of~\kbd{y}. \misctitle{Important technical note} The rules given above fixing the output type (to \typ{REAL} unless both inputs are integer types) are subtly incompatible with the general rules obeyed by PARI's generic functions, such as \kbd{gmul} or \kbd{gdiv} for instance: the latter return a result containing as much information as could be deduced from the inputs, so it is not true that if $x$ is a \typ{INT} and $y$ a \typ{REAL}, then \kbd{gmul(x,y)} is always the same as \kbd{mulir(x,y)}. The exception is $x = 0$, in that case we can deduce that the result is an exact $0$, so \kbd{gmul} returns \kbd{gen\_0}, while \kbd{mulir} returns a \typ{REAL} $0$. Specifically, the one resulting from the conversion of \kbd{gen\_0} to a \typ{REAL} of precision \kbd{precision(y)}, multiplied by $y$; this determines the exponent of the real $0$ we obtain. The reason for the discrepancy between the two rules is that we use the two sets of functions in different contexts: generic functions allow to write high-level code forgetting about types, letting PARI return results which are sensible and as simple as possible; type specific functions are used in kernel programming, where we do care about types and need to maintain strict consistency: it is much easier to compute the types of results when they are determined from the types of the inputs only (without taking into account further arithmetic properties, like being non-0). \smallskip The names and prototypes of the low-level functions corresponding to \op\ are as follows. In this section, the \kbd{z} argument in the \kbd{z}-functions must be of type \typ{INT} when no \kbd{r} or \kbd{mp} appears in the argument code (no \typ{REAL} operand is involved, only integer types), and of type \typ{REAL} otherwise. \funno{GEN}{mp\op[z]}{GEN x, GEN y[, GEN z]} applies \op\ to the \typ{INT} or \typ{REAL} \kbd{x} and~\kbd{y}. The function \kbd{mpdivz} does not exist (its semantic would change drastically depending on the type of the \kbd{z} argument), and neither do \kbd{mprem[z]} nor \kbd{mpmod[z]} (specific to integers). \funno{GEN}{\op si[z]}{long s, GEN x[, GEN z]} applies \op\ to the \kbd{long}~\kbd{s} and the \typ{INT}~\kbd{x}. These functions always return the global constant \kbd{gen\_0} (not a copy) when the sign of the result is $0$. \funno{GEN}{\op sr[z]}{long s, GEN x[, GEN z]} applies \op\ to the \kbd{long}~\kbd{s} and the \typ{REAL}~\kbd{x}. \funno{GEN}{\op ss[z]}{long s, long t[, GEN z]} applies \op\ to the longs \kbd{s} and~\kbd{t}. These functions always return the global constant \kbd{gen\_0} (not a copy) when the sign of the result is $0$. \funno{GEN}{\op ii[z]}{GEN x, GEN y[, GEN z]} applies \op\ to the \typ{INT}s \kbd{x} and~\kbd{y}. These functions always return the global constant \kbd{gen\_0} (not a copy) when the sign of the result is $0$. \funno{GEN}{\op ir[z]}{GEN x, GEN y[, GEN z]} applies \op\ to the \typ{INT} \kbd{x} and the \typ{REAL}~\kbd{y}. \funno{GEN}{\op is[z]}{GEN x, long s[, GEN z]} applies \op\ to the \typ{INT}~\kbd{x} and the \kbd{long}~\kbd{s}. These functions always return the global constant \kbd{gen\_0} (not a copy) when the sign of the result is $0$. \funno{GEN}{\op ri[z]}{GEN x, GEN y[, GEN z]} applies \op\ to the \typ{REAL}~\kbd{x} and the \typ{INT}~\kbd{y}. \funno{GEN}{\op rr[z]}{GEN x, GEN y[, GEN z]} applies \op\ to the \typ{REAL}s~\kbd{x} and~\kbd{y}. \funno{GEN}{\op rs[z]}{GEN x, long s[, GEN z]} applies \op\ to the \typ{REAL}~\kbd{x} and the \kbd{long}~\kbd{s}. \noindent Some miscellaneous routines: \fun{long}{expu}{ulong x} assuming $x > 0$, returns the binary exponent of the real number equal to $x$. This is a special case of \kbd{gexpo}. \fun{GEN}{adduu}{ulong x, ulong y} \fun{GEN}{addiu}{GEN x, ulong y} \fun{GEN}{addui}{ulong x, GEN y} adds \kbd{x} and \kbd{y}. \fun{GEN}{subuu}{ulong x, ulong y} \fun{GEN}{subiu}{GEN x, ulong y} \fun{GEN}{subui}{ulong x, GEN y} subtracts \kbd{x} by \kbd{y}. \fun{GEN}{muluu}{ulong x, ulong y} multiplies \kbd{x} by \kbd{y}. \fun{ulong}{umuluu_le}{ulong x, ulong y, ulong n} multiplies \kbd{x} by \kbd{y}. Return $xy$ if $xy \leq n$ and $0$ otherwise (in particular if $xy$ does not fit in an \kbd{ulong}). \fun{ulong}{umuluu_or_0}{ulong x, ulong y} multiplies \kbd{x} by \kbd{y}. Return $0$ if $xy$ does not fit in an \kbd{ulong}. \fun{GEN}{mului}{ulong x, GEN y} multiplies \kbd{x} by \kbd{y}. \fun{GEN}{muluui}{ulong x, ulong y, GEN z} return $xyz$. \fun{GEN}{muliu}{GEN x, ulong y} multiplies \kbd{x} by \kbd{y}. \fun{void}{addumului}{ulong a, ulong b, GEN x} return $a + b|X|$. \fun{GEN}{addmuliu}{GEN x, GEN y, ulong u} returns $x +yu$. \fun{GEN}{addmulii}{GEN x, GEN y, GEN z} returns $x + yz$. \fun{GEN}{addmulii_inplace}{GEN x, GEN y, GEN z} returns $x + yz$, but returns $x$ itself and not a copy if $yz = 0$. Not suitable for \tet{gerepile} or \tet{gerepileupto}. \fun{GEN}{addmuliu_inplace}{GEN x, GEN y, ulong u} returns $x +yu$, but returns $x$ itself and not a copy if $yu = 0$. Not suitable for \tet{gerepile} or \tet{gerepileupto}. \fun{GEN}{submuliu_inplace}{GEN x, GEN y, ulong u} returns $x- yu$, but returns $x$ itself and not a copy if $yu = 0$. Not suitable for \tet{gerepile} or \tet{gerepileupto}. \fun{GEN}{lincombii}{GEN u, GEN v, GEN x, GEN y} returns $ux + vy$. \fun{GEN}{mulsubii}{GEN y, GEN z, GEN x} returns $yz - x$. \fun{GEN}{submulii}{GEN x, GEN y, GEN z} returns $x - yz$. \fun{GEN}{submuliu}{GEN x, GEN y, ulong u} returns $x -yu$. \fun{GEN}{mulu_interval}{ulong a, ulong b} returns $a(a+1)\cdots b$, assuming that $a \leq b$. \fun{GEN}{muls_interval}{long a, long b} returns $a(a+1)\cdots b$, assuming that $a \leq b$. \fun{GEN}{invr}{GEN x} returns the inverse of the non-zero \typ{REAL}~$x$. \fun{GEN}{truedivii}{GEN x, GEN y} returns the true Euclidean quotient (with non-negative remainder less than $|y|$). \fun{GEN}{truedivis}{GEN x, long y} returns the true Euclidean quotient (with non-negative remainder less than $|y|$). \fun{GEN}{truedivsi}{long x, GEN y} returns the true Euclidean quotient (with non-negative remainder less than $|y|$). \fun{GEN}{centermodii}{GEN x, GEN y, GEN y2}, given \typ{INT}s \kbd{x}, \kbd{y}, returns $z$ congruent to \kbd{x} modulo \kbd{y}, such that $-\kbd{y}/2 \leq z < \kbd{y}/2$. The function requires an extra argument \kbd{y2}, such that \kbd{y2 = shifti(y, -1)}. (In most cases, \kbd{y} is constant for many reductions and \kbd{y2} need only be computed once.) \fun{GEN}{remi2n}{GEN x, long n} returns \kbd{x} mod $2^n$. \fun{GEN}{addii_sign}{GEN x, long sx, GEN y, long sy} add the \typ{INT}s $x$ and $y$ as if their signs were \kbd{sx} and \kbd{sy}. \fun{GEN}{addir_sign}{GEN x, long sx, GEN y, long sy} add the \typ{INT} $x$ and the \typ{REAL} $y$ as if their signs were \kbd{sx} and \kbd{sy}. \fun{GEN}{addrr_sign}{GEN x, long sx, GEN y, long sy} add the \typ{REAL}s $x$ and $y$ as if their signs were \kbd{sx} and \kbd{sy}. \fun{GEN}{addsi_sign}{long x, GEN y, long sy} add $x$ and the \typ{INT} $y$ as if its sign was \kbd{sy}. \fun{GEN}{addui_sign}{ulong x, GEN y, long sy} add $x$ and the \typ{INT} $y$ as if its sign was \kbd{sy}. \subsec{Exact division and divisibility} \fun{GEN}{diviiexact}{GEN x, GEN y} returns the Euclidean quotient $\kbd{x} / \kbd{y}$, assuming $\kbd{y}$ divides $\kbd{x}$. Uses Jebelean algorithm (Jebelean-Krandick bidirectional exact division is not implemented). \fun{GEN}{diviuexact}{GEN x, ulong y} returns the Euclidean quotient $\kbd{x} / \kbd{y}$, assuming $\kbd{y}$ divides $\kbd{x}$ and $\kbd{y}$ is non-zero. \fun{GEN}{diviuuexact}{GEN x, ulong y, ulong z} returns the Euclidean quotient $x/(yz)$, assuming $yz$ divides $x$ and $yz \neq 0$. The following routines return 1 (true) if \kbd{y} divides \kbd{x}, and 0 otherwise. (Error if $y$ is $0$, even if $x$ is $0$.) All \kbd{GEN} are assumed to be \typ{INT}s: \fun{int}{dvdii}{GEN x, GEN y}, \fun{int}{dvdis}{GEN x, long y}, \fun{int}{dvdiu}{GEN x, ulong y}, \fun{int}{dvdsi}{long x, GEN y}, \fun{int}{dvdui}{ulong x, GEN y}. The following routines return 1 (true) if \kbd{y} divides \kbd{x}, and in that case assign the quotient to \kbd{z}; otherwise they return 0. All \kbd{GEN} are assumed to be \typ{INT}s: \fun{int}{dvdiiz}{GEN x, GEN y, GEN z}, \fun{int}{dvdisz}{GEN x, long y, GEN z}. \fun{int}{dvdiuz}{GEN x, ulong y, GEN z} if \kbd{y} divides \kbd{x}, assigns the quotient $|\kbd{x}|/\kbd{y}$ to \kbd{z} and returns 1 (true), otherwise returns 0 (false). \subsec{Division with integral operands and \typ{REAL} result} \fun{GEN}{rdivii}{GEN x, GEN y, long prec}, assuming $x$ and $y$ are both of type \typ{INT}, return the quotient $x/y$ as a \typ{REAL} of precision \kbd{prec}. \fun{GEN}{rdiviiz}{GEN x, GEN y, GEN z}, assuming $x$ and $y$ are both of type \typ{INT}, and $z$ is a \typ{REAL}, assign the quotient $x/y$ to $z$. \fun{GEN}{rdivis}{GEN x, long y, long prec}, assuming \kbd{x} is of type \typ{INT}, return the quotient x/y as a \typ{REAL} of precision \kbd{prec}. \fun{GEN}{rdivsi}{long x, GEN y, long prec}, assuming \kbd{y} is of type \typ{INT}, return the quotient x/y as a \typ{REAL} of precision \kbd{prec}. \fun{GEN}{rdivss}{long x, long y, long prec}, return the quotient x/y as a \typ{REAL} of precision \kbd{prec}. \subsec{Division with remainder} The following functions return two objects, unless specifically asked for only one of them~--- a quotient and a remainder. The quotient is returned and the remainder is returned through the variable whose address is passed as the \kbd{r} argument. The term \emph{true Euclidean remainder} refers to the non-negative one (\kbd{mod}), and \emph{Euclidean remainder} by itself to the one with the same sign as the dividend (\kbd{rem}). All \kbd{GEN}s, whether returned directly or through a pointer, are created on the stack. \fun{GEN}{dvmdii}{GEN x, GEN y, GEN *r} returns the Euclidean quotient of the \typ{INT}~\kbd{x} by a \typ{INT}~\kbd{y} and puts the remainder into~\kbd{*r}. If \kbd{r} is equal to \kbd{NULL}, the remainder is not created, and if \kbd{r} is equal to \kbd{ONLY\_REM}, only the remainder is created and returned. In the generic case, the remainder is created after the quotient and can be disposed of individually with a \kbd{cgiv(r)}. The remainder is always of the sign of the dividend~\kbd{x}. If the remainder is $0$ set \kbd{r = gen\_0}. \fun{void}{dvmdiiz}{GEN x, GEN y, GEN z, GEN t} assigns the Euclidean quotient of the \typ{INT}s \kbd{x} and \kbd{y} into the \typ{INT}~\kbd{z}, and the Euclidean remainder into the \typ{INT}~\kbd{t}. \noindent Analogous routines \tet{dvmdis}\kbd{[z]}, \tet{dvmdsi}\kbd{[z]}, \tet{dvmdss}\kbd{[z]} are available, where \kbd{s} denotes a \kbd{long} argument. But the following routines are in general more flexible: \fun{long}{sdivss_rem}{long s, long t, long *r} computes the Euclidean quotient and remainder of the longs \kbd{s} and~\kbd{t}. Puts the remainder into \kbd{*r}, and returns the quotient. The remainder is of the sign of the dividend~\kbd{s}, and has strictly smaller absolute value than~\kbd{t}. \fun{long}{sdivsi_rem}{long s, GEN x, long *r} computes the Euclidean quotient and remainder of the \kbd{long}~\kbd{s} by the \typ{INT}~\kbd{x}. As \kbd{sdivss\_rem} otherwise. \fun{long}{sdivsi}{long s, GEN x} as \kbd{sdivsi\_rem}, without remainder. \fun{GEN}{divis_rem}{GEN x, long s, long *r} computes the Euclidean quotient and remainder of the \typ{INT}~\kbd{x} by the \kbd{long}~\kbd{s}. As \kbd{sdivss\_rem} otherwise. \fun{GEN}{absdiviu_rem}{GEN x, ulong s, ulong *r} computes the Euclidean quotient and remainder of \emph{absolute value} of the \typ{INT}~\kbd{x} by the \kbd{ulong}~\kbd{s}. As \kbd{sdivss\_rem} otherwise. \fun{ulong}{uabsdiviu_rem}{GEN n, ulong d, ulong *r} as \tet{absdiviu_rem}, assuming that $|n|/d$ fits into an \kbd{ulong}. \fun{ulong}{uabsdivui_rem}{ulong x, GEN y, ulong *rem} computes the Euclidean quotient and remainder of $x$ by $|y|$. As \kbd{sdivss\_rem} otherwise. \fun{ulong}{udivuu_rem}{ulong x, ulong y, ulong *rem} computes the Euclidean quotient and remainder of $x$ by $y$. As \kbd{sdivss\_rem} otherwise. \fun{ulong}{ceildivuu}{ulong x, ulong y} return the ceiling of $x / y$. \fun{GEN}{divsi_rem}{long s, GEN y, long *r} computes the Euclidean quotient and remainder of the \kbd{long}~\kbd{s} by the \kbd{GEN}~\kbd{y}. As \kbd{sdivss\_rem} otherwise. \fun{GEN}{divss_rem}{long x, long y, long *r} computes the Euclidean quotient and remainder of the \kbd{long}~\kbd{x} by the \kbd{long}~\kbd{y}. As \kbd{sdivss\_rem} otherwise. \smallskip \fun{GEN}{truedvmdii}{GEN x, GEN y, GEN *r}, as \kbd{dvmdii} but with a non-negative remainder. \fun{GEN}{truedvmdis}{GEN x, long y, GEN *z}, as \kbd{dvmdis} but with a non-negative remainder. \fun{GEN}{truedvmdsi}{long x, GEN y, GEN *z}, as \kbd{dvmdsi} but with a non-negative remainder. \subsec{Modulo to longs} The following variants of \kbd{modii} do not clutter the stack: \fun{long}{smodis}{GEN x, long y} computes the true Euclidean remainder of the \typ{INT}~\kbd{x} by the \kbd{long}~\kbd{y}. This is the non-negative remainder, not the one whose sign is the sign of \kbd{x} as in the \kbd{div} functions. \fun{long}{smodss}{long x, long y} computes the true Euclidean remainder of the \kbd{long}~\kbd{x} by a \kbd{long}~\kbd{y}. \fun{ulong}{umodsu}{long x, ulong y} computes the true Euclidean remainder of the \kbd{long}~\kbd{x} by a \kbd{ulong}~\kbd{y}. \fun{ulong}{umodiu}{GEN x, ulong y} computes the true Euclidean remainder of the \typ{INT}~\kbd{x} by the \kbd{ulong}~\kbd{y}. \fun{ulong}{umodui}{ulong x, GEN y} computes the true Euclidean remainder of the \kbd{ulong}~\kbd{x} by the \typ{INT}~\kbd{|y|}. The routine \tet{smodsi} does not exist, since it would not always be defined: for a \emph{negative} \kbd{x}, if the quotient is $\pm1$, the result \kbd{x + |y|} would in general not fit into a \kbd{long}. Use either \kbd{umodui} or \kbd{modsi}. These functions directly access the binary data and are thus much faster than the generic modulo functions: \fun{int}{mpodd}{GEN x} which is 1 if \kbd{x} is odd, and 0 otherwise. \fun{ulong}{Mod2}{GEN x} \fun{ulong}{Mod4}{GEN x} \fun{ulong}{Mod8}{GEN x} \fun{ulong}{Mod16}{GEN x} \fun{ulong}{Mod32}{GEN x} \fun{ulong}{Mod64}{GEN x} give the residue class of $x$ modulo the corresponding power of $2$. \fun{ulong}{umodi2n}{GEN x, long n} give the residue class of $x$ modulo $2^n$, $0 \leq n < BITS\_IN\_LONG$. The following functions assume that $x\neq 0$ and in fact disregard the sign of $x$. There are about $10\%$ faster than the safer variants above: \fun{long}{mod2}{GEN x} \fun{long}{mod4}{GEN x} \fun{long}{mod8}{GEN x} \fun{long}{mod16}{GEN x} \fun{long}{mod32}{GEN x} \fun{long}{mod64}{GEN x} give the residue class of $|x|$ modulo the corresponding power of 2, for \emph{non-zero}~\kbd{x}. As well, \fun{ulong}{mod2BIL}{GEN x} returns the least significant word of $|x|$, still assuming that $x\neq 0$. \subsec{Powering, Square root} \fun{GEN}{powii}{GEN x, GEN n}, assumes $x$ and $n$ are \typ{INT}s and returns $x^n$. \fun{GEN}{powuu}{ulong x, ulong n}, returns $x^n$. \fun{GEN}{powiu}{GEN x, ulong n}, assumes $x$ is a \typ{INT} and returns $x^n$. \fun{GEN}{powis}{GEN x, long n}, assumes $x$ is a \typ{INT} and returns $x^n$ (possibly a \typ{FRAC} if $n < 0$). \fun{GEN}{powrs}{GEN x, long n}, assumes $x$ is a \typ{REAL} and returns $x^n$. This is considered as a sequence of \kbd{mulrr}, possibly empty: as such the result has type \typ{REAL}, even if $n = 0$. Note that the generic function \kbd{gpowgs(x,0)} would return \kbd{gen\_1}, see the technical note in \secref{se:genbinop}. \fun{GEN}{powru}{GEN x, ulong n}, assumes $x$ is a \typ{REAL} and returns $x^n$ (always a \typ{REAL}, even if $n = 0$). \fun{GEN}{powersr}{GEN e, long n}. Given a \typ{REAL} $e$, return the vector $v$ of all $e^i$, $0 \leq i \leq n$, where $v[i] = e^{i-1}$. \fun{GEN}{powrshalf}{GEN x, long n}, assumes $x$ is a \typ{REAL} and returns $x^{n/2}$ (always a \typ{REAL}, even if $n = 0$). \fun{GEN}{powruhalf}{GEN x, ulong n}, assumes $x$ is a \typ{REAL} and returns $x^{n/2}$ (always a \typ{REAL}, even if $n = 0$). \fun{GEN}{powrfrac}{GEN x, long n, long d}, assumes $x$ is a \typ{REAL} and returns $x^{n/d}$ (always a \typ{REAL}, even if $n = 0$). \fun{GEN}{powIs}{long n} returns $I^n\in\{1,I,-1,-I\}$ (\typ{INT} for even $n$, \typ{COMPLEX} otherwise). \fun{ulong}{upowuu}{ulong x, ulong n}, returns $x^n$ when $< 2^\B$, and $0$ otherwise (overflow). \fun{GEN}{sqrtremi}{GEN N, GEN *r}, returns the integer square root $S$ of the non-negative \typ{INT}~\kbd{N} (rounded towards 0) and puts the remainder $R$ into~\kbd{*r}. Precisely, $N = S^2 + R$ with $0\leq R \leq 2S$. If \kbd{r} is equal to \kbd{NULL}, the remainder is not created. In the generic case, the remainder is created after the quotient and can be disposed of individually with \kbd{cgiv(R)}. If the remainder is $0$ set \kbd{R = gen\_0}. Uses a divide and conquer algorithm (discrete variant of Newton iteration) due to Paul Zimmermann (``Karatsuba Square Root'', INRIA Research Report 3805 (1999)). \fun{GEN}{sqrti}{GEN N}, returns the integer square root $S$ of the non-negative \typ{INT}~\kbd{N} (rounded towards 0). This is identical to \kbd{sqrtremi(N, NULL)}. \fun{long}{logintall}{GEN B, GEN y, GEN *ptq} returns the floor $e$ of $\log_y B$, where $B > 0$ and $y > 1$ are integers. If \kbd{ptq} is not \kbd{NULL}, set it to $y^e$. (Analogous to \kbd{logint0}, whithout sanity checks.) \fun{ulong}{ulogintall}{ulong B, ulong y, ulong *ptq} as \kbd{logintall} for \kbd{ulong} arguments. \fun{long}{logint}{GEN B, GEN y} returns the floor $e$ of $\log_y B$, where $B > 0$ and $y > 1$ are integers. \fun{ulong}{ulogint}{ulong B, ulong y} as \kbd{logint} for \kbd{ulong} arguments. \fun{GEN}{vecpowuu}{long N, ulong a} return the vector of $n^a$, $n = 1, \dots, N$. Not memory clean. \fun{GEN}{vecpowug}{long N, GEN a, long prec} return the vector of $n^a$, $n = 1, \dots, N$, where the powers are computed at precision \kbd{prec}. Not memory clean. \subsec{GCD, extended GCD and LCM} \fun{long}{cgcd}{long x, long y} returns the GCD of \kbd{x} and \kbd{y}. \fun{ulong}{ugcd}{ulong x, ulong y} returns the GCD of \kbd{x} and \kbd{y}. \fun{ulong}{ugcdiu}{GEN x, ulong y} returns the GCD of \kbd{x} and \kbd{y}. \fun{ulong}{ugcdui}{ulong x, GEN y} returns the GCD of \kbd{x} and \kbd{y}. \fun{GEN}{coprimes_zv}{ulong N} return a \typ{VECSMALL} $T$ with $N$ entries such that $T[i] = 1$ iff $(i,N) = 1$ and $0$ otherwise. \fun{long}{clcm}{long x, long y} returns the LCM of \kbd{x} and \kbd{y}, provided it fits into a \kbd{long}. Silently overflows otherwise. \fun{ulong}{ulcm}{ulong x, ulong y} returns the LCM of \kbd{x} and \kbd{y}, provided it fits into an \kbd{ulong}. Silently overflows otherwise. \fun{GEN}{gcdii}{GEN x, GEN y}, returns the GCD of the \typ{INT}s \kbd{x} and \kbd{y}. \fun{GEN}{lcmii}{GEN x, GEN y}, returns the LCM of the \typ{INT}s \kbd{x} and \kbd{y}. \fun{GEN}{bezout}{GEN a,GEN b, GEN *u,GEN *v}, returns the GCD $d$ of \typ{INT}s \kbd{a} and \kbd{b} and sets \kbd{u}, \kbd{v} to the Bezout coefficients such that $\kbd{au} + \kbd{bv} = d$. \fun{long}{cbezout}{long a,long b, long *u,long *v}, returns the GCD $d$ of \kbd{a} and \kbd{b} and sets \kbd{u}, \kbd{v} to the Bezout coefficients such that $\kbd{au} + \kbd{bv} = d$. \fun{GEN}{ZV_extgcd}{GEN A} given a vector of $n$ integers $A$, returns $[d, U]$, where $d$ is the GCD of the $A[i]$ and $U$ is a matrix in $\text{GL}_n(\Z)$ such that $AU = [0,\dots,0,D]$. \subsec{Continued fractions and convergents} \fun{GEN}{ZV_allpnqn}{GEN x} given $x = [a_0, ..., a_n]$ a continued fraction from \tet{gboundcf}, $n\geq0$, return all convergents as $[P,Q]$, where $P = [p_0,\dots,p_n]$ and $Q = [q_0,\dots,q_n]$. \subsec{Pseudo-random integers} These routine return pseudo-random integers uniformly distributed in some interval. The all use the same underlying generator which can be seeded and restarted using \tet{getrand} and \tet{setrand}. \fun{void}{setrand}{GEN seed} reseeds the random number generator using the seed $n$. The seed is either a technical array output by \kbd{getrand} or a small positive integer, used to generate deterministically a suitable state array. For instance, running a randomized computation starting by \kbd{setrand(1)} twice will generate the exact same output. \fun{GEN}{getrand}{void} returns the current value of the seed used by the pseudo-random number generator \tet{random}. Useful mainly for debugging purposes, to reproduce a specific chain of computations. The returned value is technical (reproduces an internal state array of type \typ{VECSMALL}), and can only be used as an argument to \tet{setrand}. \fun{ulong}{pari_rand}{void} returns a random $0 \leq x < 2^\B$. \fun{long}{random_bits}{long k} returns a random $0 \leq x < 2^k$. Assumes that $0 \leq k \leq \B$. \fun{ulong}{random_Fl}{ulong p} returns a pseudo-random integer in $0, 1, \dots p-1$. \fun{GEN}{randomi}{GEN n} returns a random \typ{INT} between $0$ and $\kbd{n} - 1$. \fun{GEN}{randomr}{long prec} returns a random \typ{REAL} in $[0,1[$, with precision \kbd{prec}. \subsec{Modular operations} In this subsection, all \kbd{GEN}s are \typ{INT}. \fun{GEN}{Fp_red}{GEN a, GEN m} returns \kbd{a} modulo \kbd{m} (smallest non-negative residue). (This is identical to modii). \fun{GEN}{Fp_neg}{GEN a, GEN m} returns $-$\kbd{a} modulo \kbd{m} (smallest non-negative residue). \fun{GEN}{Fp_add}{GEN a, GEN b, GEN m} returns the sum of \kbd{a} and \kbd{b} modulo \kbd{m} (smallest non-negative residue). \fun{GEN}{Fp_sub}{GEN a, GEN b, GEN m} returns the difference of \kbd{a} and \kbd{b} modulo \kbd{m} (smallest non-negative residue). \fun{GEN}{Fp_center}{GEN a, GEN p, GEN pov2} assuming that \kbd{pov2} is \kbd{shifti(p,-1)} and that $-p/2 < a < p$, returns the representative of \kbd{a} in the symmetric residue system $]-p/2,p/2]$. \fun{GEN}{Fp_center_i}{GEN a, GEN p, GEN pov2} internal variant of \tet{Fp_center}, not \kbd{gerepile}-safe: when $a$ is already in the proper interval, it is returned as is, without a copy. \fun{GEN}{Fp_mul}{GEN a, GEN b, GEN m} returns the product of \kbd{a} by \kbd{b} modulo \kbd{m} (smallest non-negative residue). \fun{GEN}{Fp_addmul}{GEN x, GEN y, GEN z, GEN p} returns $x + y\*z$. \fun{GEN}{Fp_mulu}{GEN a, ulong b, GEN m} returns the product of \kbd{a} by \kbd{b} modulo \kbd{m} (smallest non-negative residue). \fun{GEN}{Fp_muls}{GEN a, long b, GEN m} returns the product of \kbd{a} by \kbd{b} modulo \kbd{m} (smallest non-negative residue). \fun{GEN}{Fp_halve}{GEN x, GEN m} returns $z$ such that $2\*z = x$ modulo $m$ assuming such $z$ exists. \fun{GEN}{Fp_sqr}{GEN a, GEN m} returns $\kbd{a}^2$ modulo \kbd{m} (smallest non-negative residue). \fun{ulong}{Fp_powu}{GEN x, ulong n, GEN m} raises \kbd{x} to the \kbd{n}-th power modulo \kbd{m} (smallest non-negative residue). Not memory-clean, but suitable for \kbd{gerepileupto}. \fun{ulong}{Fp_pows}{GEN x, long n, GEN m} raises \kbd{x} to the \kbd{n}-th power modulo \kbd{m} (smallest non-negative residue). A negative \kbd{n} is allowed Not memory-clean, but suitable for \kbd{gerepileupto}. \fun{GEN}{Fp_pow}{GEN x, GEN n, GEN m} returns $\kbd{x}^\kbd{n}$ modulo \kbd{m} (smallest non-negative residue). \fun{GEN}{Fp_pow_init}{GEN x, GEN n, long k, GEN p} Return a table \kbd{R} that can be used with \kbd{Fp\_pow\_table} to compute the powers of $x$ up to $n$. The table is of size $2^k\*\log_2(n)$. \fun{GEN}{Fp_pow_table}{GEN R, GEN n, GEN p} return $x^n$, where $R$ is given by \kbd{Fp\_pow\_init(x,m,k,p)} for some integer $m\geq n$. \fun{GEN}{Fp_powers}{GEN x, long n, GEN m} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ modulo \kbd{m} as a \typ{VEC} (smallest non-negative residue). \fun{GEN}{Fp_inv}{GEN a, GEN m} returns an inverse of \kbd{a} modulo \kbd{m} (smallest non-negative residue). Raise an error if \kbd{a} is not invertible. \fun{GEN}{Fp_invsafe}{GEN a, GEN m} as \kbd{Fp\_inv}, but return \kbd{NULL} if \kbd{a} is not invertible. \fun{GEN}{Fp_invgen}{GEN x, GEN m, GEN *pg} set \kbd{*pg} to $g = \gcd(x,m)$ and return $u$ in $(\Z/m\Z)^*$ such that $x u = g$ modulo $m$. We have $g = 1$ if and only if $x$ is invertible, and in this case $u$ is its inverse. \fun{GEN}{FpV_inv}{GEN x, GEN m} $x$ being a vector of \typ{INT}s, return the vector of inverses of the $x[i]$ mod $m$. The routine uses Montgomery's trick, and involves a single inversion mod $m$, plus $3(N-1)$ multiplications for $N$ entries. The routine is not stack-clean: $2N$ integers mod $m$ are left on stack, besides the $N$ in the result. \fun{GEN}{Fp_div}{GEN a, GEN b, GEN m} returns the quotient of \kbd{a} by \kbd{b} modulo \kbd{m} (smallest non-negative residue). Raise an error if \kbd{b} is not invertible. \fun{int}{invmod}{GEN a, GEN m, GEN *g}, return $1$ if \kbd{a} modulo \kbd{m} is invertible, else return $0$ and set $\kbd{g} = \gcd(\kbd{a},\kbd{m})$. In the following three functions the integer parameter \kbd{ord} can be given either as a positive \typ{INT} $N$, or as its factorization matrix $\var{faN}$, or as a pair $[N,\var{faN}]$. The parameter may be omitted by setting it to \kbd{NULL} (the value is then $p-1$). \fun{GEN}{Fp_log}{GEN a, GEN g, GEN ord, GEN p} Let $g$ such that $g^{ord} \equiv 1 \pmod{p}$. Return an integer $e$ such that $a^e \equiv g \pmod{p}$. If $e$ does not exist, the result is undefined. \fun{GEN}{Fp_order}{GEN a, GEN ord, GEN p} returns the order of the \kbd{Fp} \kbd{a}. Assume that \kbd{ord} is a multiple of the order of \kbd{a}. \fun{GEN}{Fp_factored_order}{GEN a, GEN ord, GEN p} returns $[o,F]$, where $o$ is the multiplicative order of the \kbd{Fp} $a$ in $\F_p^*$, and $F$ is the factorization of $o$. Assume that \kbd{ord} is a multiple of the order of \kbd{a}. \fun{int}{Fp_issquare}{GEN x, GEN p} returns $1$ if \kbd{x} is a square modulo \kbd{p}, and $0$ otherwise. \fun{int}{Fp_ispower}{GEN x, GEN n, GEN p} returns $1$ if \kbd{x} is an $n$-th power modulo \kbd{p}, and $0$ otherwise. \fun{GEN}{Fp_sqrt}{GEN x, GEN p} returns a square root of \kbd{x} modulo \kbd{p} (the smallest non-negative residue), where \kbd{x}, \kbd{p} are \typ{INT}s, and \kbd{p} is assumed to be prime. Return \kbd{NULL} if \kbd{x} is not a quadratic residue modulo \kbd{p}. \fun{GEN}{Fp_2gener}{GEN p} return a generator of the $2$-Sylow subgroup of $\F_p^*$. To use with \kbd{Fp\_sqrt\_i}. \fun{GEN}{Fp_sqrt_i}{GEN x, GEN s2, GEN p} as \kbd{Fp\_sqrt} where \kbd{s2} is the element returned by \kbd{Fp\_2gener}. \fun{GEN}{Fp_sqrtn}{GEN a, GEN n, GEN p, GEN *zn} returns \kbd{NULL} if $a$ is not an $n$-th power residue mod $p$. Otherwise, returns an $n$-th root of $a$; if \kbd{zn} is non-\kbd{NULL} set it to a primitive $m$-th root of 1, $m = \gcd(p-1,n)$ allowing to compute all $m$ solutions in $\F_p$ of the equation $x^n = a$. \fun{GEN}{Zn_sqrt}{GEN x, GEN n} returns one of the square roots of \kbd{x} modulo \kbd{n} (possibly not prime), where \kbd{x} is a \typ{INT} and \kbd{n} is either a \typ{INT} or is given by its factorization matrix. Return \kbd{NULL} if no such square root exist. \fun{long}{kross}{long x, long y} returns the \idx{Kronecker symbol} $(x|y)$, i.e.$-1$, $0$ or $1$. If \kbd{y} is an odd prime, this is the \idx{Legendre symbol}. (Contrary to \kbd{krouu}, \kbd{kross} also supports $\kbd{y} = 0$) \fun{long}{krouu}{ulong x, ulong y} returns the \idx{Kronecker symbol} $(x|y)$, i.e.~$-1$, $0$ or $1$. Assumes \kbd{y} is non-zero. If \kbd{y} is an odd prime, this is the \idx{Legendre symbol}. \fun{long}{krois}{GEN x, long y} returns the \idx{Kronecker symbol} $(x|y)$ of \typ{INT}~x and \kbd{long}~\kbd{y}. As \kbd{kross} otherwise. \fun{long}{kroiu}{GEN x, ulong y} returns the \idx{Kronecker symbol} $(x|y)$ of \typ{INT}~x and non-zero \kbd{ulong}~\kbd{y}. As \kbd{krouu} otherwise. \fun{long}{krosi}{long x, GEN y} returns the \idx{Kronecker symbol} $(x|y)$ of \kbd{long}~x and \typ{INT}~\kbd{y}. As \kbd{kross} otherwise. \fun{long}{kroui}{ulong x, GEN y} returns the \idx{Kronecker symbol} $(x|y)$ of \kbd{long}~x and \typ{INT}~\kbd{y}. As \kbd{kross} otherwise. \fun{long}{kronecker}{GEN x, GEN y} returns the \idx{Kronecker symbol} $(x|y)$ of \typ{INT}s~x and~\kbd{y}. As \kbd{kross} otherwise. \fun{GEN}{pgener_Fp}{GEN p} returns the smallest primitive root modulo \kbd{p}, assuming \kbd{p} is prime. \fun{GEN}{pgener_Zp}{GEN p} returns the smallest primitive root modulo $p^k$, $k > 1$, assuming \kbd{p} is an odd prime. \fun{long}{Zp_issquare}{GEN x, GEN p} returns 1 if the \typ{INT} $x$ is a $p$-adic square, $0$ otherwise. \fun{long}{Zn_issquare}{GEN x, GEN n} returns 1 if \typ{INT} $x$ is a square modulo \kbd{n} (possibly not prime), where $n$ is either a \typ{INT} or is given by its factorization matrix. Return $0$ otherwise. \fun{long}{Zn_ispower}{GEN x, GEN n, GEN K, GEN *py} returns 1 if \typ{INT} $x$ is a $K$-th power modulo \kbd{n} (possibly not prime), where $n$ is either a \typ{INT} or is given by its factorization matrix. Return $0$ otherwise. If \kbd{py} is not \kbd{NULL}, set it to $y$ such that $y^K = x$ modulo $n$. \fun{GEN}{pgener_Fp_local}{GEN p, GEN L}, \kbd{L} being a vector of primes dividing $p - 1$, returns the smallest integer $x > 1$ which is a generator of the $\ell$-Sylow of $\F_p^*$ for every $\ell$ in \kbd{L}. In other words, $x^{(p-1)/\ell} \neq 1$ for all such $\ell$. In particular, returns \kbd{pgener\_Fp(p)} if \kbd{L} contains all primes dividing $p - 1$. It is not necessary, and in fact slightly inefficient, to include $\ell=2$, since 2 is treated separately in any case, i.e. the generator obtained is never a square. \fun{GEN}{rootsof1_Fp}{GEN n, GEN p} returns a primitive $n$-th root modulo the prime $p$. \fun{GEN}{rootsof1u_Fp}{ulong n, GEN p} returns a primitive $n$-th root modulo the prime $p$. \fun{ulong}{rootsof1_Fl}{ulong n, ulong p} returns a primitive $n$-th root modulo the prime $p$. \subsec{Extending functions to vector inputs} The following functions apply $f$ to the given arguments, recursively if they are of vector / matrix type: \fun{GEN}{map_proto_G}{GEN (*f)(GEN), GEN x} For instance, if $x$ is a \typ{VEC}, return a \typ{VEC} whose components are the $f(x[i])$. \fun{GEN}{map_proto_lG}{long (*f)(GEN), GEN x} As above, applying the function \kbd{stoi( f() )}. \fun{GEN}{map_proto_GL}{GEN (*f)(GEN,long), GEN x, long y} \fun{GEN}{map_proto_lGL}{long (*f)(GEN,long), GEN x, long y} In the last function, $f$ implements an associative binary operator, which we extend naturally to an $n$-ary operator $f_n$ for any $n$: by convention, $f_0() = 1$, $f_1(x) = x$, and $$ f_n(x_1,\dots,x_n) = f( f_{n-1}(x_1,\dots,x_{n-1}), x_n)),$$ for $n \geq 2$. \fun{GEN}{gassoc_proto}{GEN (*f)(GEN,GEN),GEN x, GEN y} If $y$ is not \kbd{NULL}, return $f(x,y)$. Otherwise, $x$ must be of vector type, and we return the result of $f$ applied to its components, computed using a divide-and-conquer algorithm. More precisely, return $$f( f(x_1,\kbd{NULL}), f(x_2,\kbd{NULL}) ),$$ where $x_1$, $x_2$ are the two halves of $x$. \subsec{Miscellaneous arithmetic functions} \fun{long}{bigomegau}{ulong n} returns the number of prime divisors of $n > 0$, counted with multiplicity. \fun{ulong}{coreu}{ulong n}, unique squarefree integer $d$ dividing $n$ such that $n/d$ is a square. \fun{ulong}{coreu_fact}{GEN fa} same, where \kbd{fa} is \kbd{factoru(n)}. \fun{ulong}{corediscs}{long d, ulong *pt_f}, $d$ (possibly negative) being congruent to $0$ or $1$ modulo $4$, return the fundamental discriminant $D$ such that $d=D*f^2$ and set \kbd{*pt\_f} to $f$ (if \kbd{*pt\_f} not \kbd{NULL}). \fun{ulong}{eulerphiu}{ulong n}, Euler's totient function of $n$. \fun{ulong}{eulerphiu_fact}{GEN fa} same, where \kbd{fa} is \kbd{factoru(n)}. \fun{long}{moebiusu}{ulong n}, Moebius $\mu$-function of $n$. \fun{long}{moebiusu_fact}{GEN fa} same, where \kbd{fa} is \kbd{factoru(n)}. \fun{GEN}{divisorsu}{ulong n}, returns the divisors of $n$ in a \typ{VECSMALL}, sorted by increasing order. \fun{GEN}{divisorsu_fact}{GEN fa} same, where \kbd{fa} is \kbd{factoru(n)}. \fun{long}{numdivu}{ulong n}, returns the number of positive divisors of $n>0$. \fun{long}{numdivu_fact}{GEN fa} same, where \kbd{fa} is \kbd{factoru(n)}. \fun{long}{omegau}{ulong n} returns the number of prime divisors of $n > 0$. \fun{long}{uissquarefree}{ulong n} returns $1$ if \kbd{n} is square-free, and $0$ otherwise. \fun{long}{uissquarefree_fact}{GEN fa} same, where \kbd{fa} is \kbd{factoru(n)}. \fun{long}{uposisfundamental}{ulong x} return $1$ if $x$ is a fundamental discriminant, and $0$ otherwise. \fun{long}{unegisfundamental}{ulong x} return $1$ if $-x$ is a fundamental discriminant, and $0$ otherwise. \fun{long}{sisfundamental}{long x} return $1$ if $x$ is a fundamental discriminant, and $0$ otherwise. \fun{int}{uis_357_power}{ulong x, ulong *pt, ulong *mask} as \tet{is_357_power} for \kbd{ulong} $x$. \fun{int}{uis_357_powermod}{ulong x, ulong *mask} as \tet{uis_357_power}, but only check for 3rd, 5th or 7th powers modulo $211\times209\times61\times203\times117\times31\times43\times71$. \fun{long}{uisprimepower}{ulong n, ulong *p} as \tet{isprimepower}, for \kbd{ulong} $n$. \fun{int}{uislucaspsp}{ulong n} returns $1$ if the \kbd{ulong} $n$ fails Lucas compositeness test (it thus may be prime or composite), and $0$ otherwise (proving that $n$ is composite). \fun{ulong}{sumdigitsu}{ulong n} returns the sum of decimal digits of $u$. \fun{GEN}{usumdiv_fact}{GEN fa}, sum of divisors of \kbd{ulong} $n$, where \kbd{fa} is \kbd{factoru(n)}. \fun{GEN}{usumdivk_fact}{GEN fa, ulong k}, sum of $k$-th powers of divisors of \kbd{ulong} $n$, where \kbd{fa} is \kbd{factoru(n)}. \fun{GEN}{hilbertii}{GEN x, GEN y, GEN p}, returns the Hilbert symbol $(x,y)$ at the prime $p$ (\kbd{NULL} for the place at infinity); $x$ and $y$ are \typ{INT}s. \fun{GEN}{sumdedekind}{GEN h, GEN k} returns the Dedekind sum attached to the \typ{INT} $h$ and $k$, $k > 0$. \fun{GEN}{sumdedekind_coprime}{GEN h, GEN k} as \kbd{sumdedekind}, except that $h$ and $k$ are assumed to be coprime \typ{INT}s. \fun{GEN}{u_sumdedekind_coprime}{long h, long k} Let $k > 0$, $0 \leq h < k$, $(h,k) = 1$. Returns $[s_1,s_2]$ in a \typ{VECSMALL}, such that $s(h,k) = (s_2 + k s_1) / (12k)$. Requires $\max(h + k/2, k) < \kbd{LONG\_MAX}$ to avoid overflow, in particular $k \leq (2/3)\kbd{LONG\_MAX}$ is fine. \newpage \chapter{Level 2 kernel} These functions deal with modular arithmetic, linear algebra and polynomials where assumptions can be made about the types of the coefficients. \section{Naming scheme}\label{se:level2names} A function name is built in the following way: $A_1\kbd{\_}\dots\kbd{\_}A_n\var{fun}$ for an operation \var{fun} with $n$ arguments of class $A_1$,\dots, $A_n$. A class name is given by a base ring followed by a number of code letters. Base rings are among \kbd{Fl}: $\Z/l\Z$ where $l < 2^{\B}$ is not necessarily prime. Implemented using \kbd{ulong}s \kbd{Fp}: $\Z/p\Z$ where $p$ is a \typ{INT}, not necessarily prime. Implemented as \typ{INT}s $z$, preferably satisfying $0 \leq z < p$. More precisely, any \typ{INT} can be used as an \kbd{Fp}, but reduced inputs are treated more efficiently. Outputs from \kbd{Fp}xxx routines are reduced. \kbd{Fq}: $\Z[X]/(p,T(X))$, $p$ a \typ{INT}, $T$ a \typ{POL} with \kbd{Fp} coefficients or \kbd{NULL} (in which case no reduction modulo \kbd{T} is performed). Implemented as \typ{POL}s $z$ with \kbd{Fp} coefficients, $\deg(z) < \deg \kbd{T}$, although $z$ a \typ{INT} is allowed for elements in the prime field. \kbd{Z}: the integers $\Z$, implemented as \typ{INT}s. \kbd{Zp}: the $p$-adic integers $\Z_p$, implemented as \typ{INT}s, for arbitrary $p$ \kbd{Zl}: the $p$-adic integers $\Z_p$, implemented as \typ{INT}s, for $p< 2^{\B}$ \kbd{z}: the integers $\Z$, implemented using (signed) \kbd{long}s. \kbd{Q}: the rational numbers $\Q$, implemented as \typ{INT}s and \typ{FRAC}s. \kbd{Rg}: a commutative ring, whose elements can be \kbd{gadd}-ed, \kbd{gmul}-ed, etc. \noindent Possible letters are: \kbd{X}: polynomial in $X$ (\typ{POL} in a fixed variable), e.g. \kbd{FpX} means $\Z/p\Z[X]$ \kbd{Y}: polynomial in $Y\neq X$. This is used to resolve ambiguities. E.g. \kbd{FpXY} means $((\Z/p\Z)[X])[Y]$. \kbd{V}: vector (\typ{VEC} or \typ{COL}), treated as a line vector (independently of the actual type). E.g. \kbd{ZV} means $\Z^k$ for some $k$. \kbd{C}: vector (\typ{VEC} or \typ{COL}), treated as a column vector (independently of the actual type). The difference with \kbd{V} is purely semantic: if the result is a vector, it will be of type \typ{COL} unless mentioned otherwise. For instance the function \kbd{ZC\_add} receives two integral vectors (\typ{COL} or \typ{VEC}, possibly different types) of the same length and returns a \typ{COL} whose entries are the sums of the input coefficients. \kbd{M}: matrix (\typ{MAT}). E.g. \kbd{QM} means a matrix with rational entries \kbd{T}: Trees. Either a leaf or a \typ{VEC} of trees. \kbd{E}: point over an elliptic curve, represented as two-component vectors \kbd{[x,y]}, except for the represented by the one-component vector \kbd{[0]}. Not all curve models are supported. \kbd{Q}: representative (\typ{POL}) of a class in a polynomial quotient ring. E.g.~an \kbd{FpXQ} belongs to $(\Z/p\Z)[X]/(T(X))$, \kbd{FpXQV} means a vector of such elements, etc. \kbd{n}: a polynomial representative (\typ{POL}) for a truncated power series modulo $X^n$. E.g.~an \kbd{FpXn} belongs to $(\Z/p\Z)[X]/(X^n)$, \kbd{FpXnV} means a vector of such elements, etc. \kbd{x}, \kbd{y}, \kbd{m}, \kbd{v}, \kbd{c}, \kbd{q}: as their uppercase counterpart, but coefficient arrays are implemented using \typ{VECSMALL}s, which coefficient understood as \kbd{ulong}s. \kbd{x} and \kbd{y} (and \kbd{q}) are implemented by a \typ{VECSMALL} whose first coefficient is used as a code-word and the following are the coefficients , similarly to a \typ{POL}. This is known as a 'POLSMALL'. \kbd{m} are implemented by a \typ{MAT} whose components (columns) are \typ{VECSMALL}s. This is known as a 'MATSMALL'. \kbd{v} and \kbd{c} are regular \typ{VECSMALL}s. Difference between the two is purely semantic. \noindent Omitting the letter means the argument is a scalar in the base ring. Standard functions \var{fun} are \kbd{add}: add \kbd{sub}: subtract \kbd{mul}: multiply \kbd{sqr}: square \kbd{div}: divide (Euclidean quotient) \kbd{rem}: Euclidean remainder \kbd{divrem}: return Euclidean quotient, store remainder in a pointer argument. Three special values of that pointer argument modify the default behavior: \kbd{NULL} (do not store the remainder, used to implement \kbd{div}), \tet{ONLY_REM} (return the remainder, used to implement \kbd{rem}), \tet{ONLY_DIVIDES} (return the quotient if the division is exact, and \kbd{NULL} otherwise). \kbd{gcd}: GCD \kbd{extgcd}: return GCD, store Bezout coefficients in pointer arguments \kbd{pow}: exponentiate \kbd{eval}: evaluation / composition \section{Coefficient ring} \fun{long}{Rg_type}{GEN x, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the object $x$ is defined. Raise an error if it detects consistency problems in modular objects: incompatible rings (e.g. $\F_p$ and $\F_q$ for primes $p\neq q$, $\F_p[X]/(T)$ and $\F_p[X]/(U)$ for $T\neq U$). Minor discrepancies are supported if they make general sense (e.g. $\F_p$ and $\F_{p^k}$, but not $\F_p$ and $\Q_p$); \typ{FFELT} and \typ{POLMOD} of \typ{INTMOD}s are considered inconsistent, even if they define the same field: if you need to use simultaneously these different finite field implementations, multiply the polynomial by a \typ{FFELT} equal to $1$ first. \item 0: none of the others (presumably multivariate, possibly inconsistent). \item \typ{INT}: defined over $\Z$. \item \typ{FRAC}: defined over $\Q$. \item \typ{INTMOD}: defined over $\Z/p\Z$, where \kbd{*ptp} is set to $p$. It is not checked whether $p$ is prime. \item \typ{COMPLEX}: defined over $\C$ (at least one \typ{COMPLEX} with at least one inexact floating point \typ{REAL} component). Set \kbd{*ptprec} to the minimal accuracy (as per \kbd{precision}) of inexact components. \item \typ{REAL}: defined over $\R$ (at least one inexact floating point \typ{REAL} component). Set \kbd{*ptprec} to the minimal accuracy (as per \kbd{precision}) of inexact components. \item \typ{PADIC}: defined over $\Q_p$, where \kbd{*ptp} is set to $p$ and \kbd{*ptprec} to the $p$-adic accuracy. \item \typ{FFELT}: defined over a finite field $\F_{p^k}$, where \kbd{*ptp} is set to the field characteristic $p$ and \kbd{*ptpol} is set to a \typ{FFELT} belonging to the field. \item \typ{POL}: defined over a polynomial ring. \item other values are composite corresponding to quotients $R[X]/(T)$, with one primary type \kbd{t1}, describing the form of the quotient, and a secondary type \kbd{t2}, describing $R$. If \kbd{t} is the \kbd{RgX\_type}, \kbd{t1} and \kbd{t2} are recovered using \fun{void}{RgX_type_decode}{long t, long *t1, long *t2} \kbd{t1} is one of \typ{POLMOD}: at least one \typ{POLMOD} component, set \kbd{*ppol} to the modulus, \typ{QUAD}: no \typ{POLMOD}, at least one \typ{QUAD} component, set \kbd{*ppol} to the modulus (\kbd{$-$.pol}) of the \typ{QUAD}, \typ{COMPLEX}: no \typ{POLMOD} or \typ{QUAD}, at least one \typ{COMPLEX} component, set \kbd{*ppol} to $y^2 + 1$. and the underlying base ring $R$ is given by \kbd{t2}, which is one of \typ{INT}, \typ{INTMOD} (set \kbd{*ptp}) or \typ{PADIC} (set \kbd{*ptp} and \kbd{*ptprec}), with the same meaning as above. \fun{int}{RgX_type_is_composite}{long t} $t$ as returned by \kbd{RgX\_type}, return 1 if $t$ is a composite type, and 0 otherwise. \fun{GEN}{Rg_get_0}{GEN x} returns $0$ in the base ring over which $x$ is defined, to the proper accuracy (e.g. \kbd{0}, \kbd{Mod(0,3)}, \kbd{O(5\pow 10)}). \fun{GEN}{Rg_get_1}{GEN x} returns $1$ in the base ring over which $x$ is defined, to the proper accuracy (e.g. \kbd{0}, \kbd{Mod(0,3)}, \fun{long}{RgX_type}{GEN x, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the polynomial $x$ is defined, otherwise as \kbd{Rg\_type}. \fun{long}{RgX_Rg_type}{GEN x, GEN y, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the polynomial $x$ and the element $y$ are defined, otherwise as \kbd{Rg\_type}. \fun{long}{RgX_type2}{GEN x, GEN y, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the polynomials $x$ and $y$ are defined, otherwise as \kbd{Rg\_type}. \fun{long}{RgX_type3}{GEN x, GEN y, GNE z, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the polynomials $x$, $y$ and $z$ are defined, otherwise as \kbd{Rg\_type}. \fun{long}{RgM_type}{GEN x, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the matrix $x$ is defined, otherwise as \kbd{Rg\_type}. \fun{long}{RgM_type2}{GEN x, GEN y, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the matrices $x$ and $y$ are defined, otherwise as \kbd{Rg\_type}. \fun{long}{RgM_RgC_type}{GEN x, GEN y, GEN *ptp, GEN *ptpol, long *ptprec} returns the ``natural'' base ring over which the matrix $x$ and the vector $y$ are defined, otherwise as \kbd{Rg\_type}. \section{Modular arithmetic} \noindent These routines implement univariate polynomial arithmetic and linear algebra over finite fields, in fact over finite rings of the form $(\Z/p\Z)[X]/(T)$, where $p$ is not necessarily prime and $T\in(\Z/p\Z)[X]$ is possibly reducible; and finite extensions thereof. All this can be emulated with \typ{INTMOD} and \typ{POLMOD} coefficients and using generic routines, at a considerable loss of efficiency. Also, specialized routines are available that have no obvious generic equivalent. \subsec{\kbd{FpC} / \kbd{FpV}, \kbd{FpM}} A \kbd{ZV} (resp.~a~\kbd{ZM}) is a \typ{VEC} or \typ{COL} (resp.~\typ{MAT}) with \typ{INT} coefficients. An \kbd{FpV} or \kbd{FpM}, with respect to a given \typ{INT}~\kbd{p}, is the same with \kbd{Fp} coordinates; operations are understood over $\Z/p\Z$. \subsubsec{Conversions} \fun{int}{Rg_is_Fp}{GEN z, GEN *p}, checks if \kbd{z} can be mapped to $\Z/p\Z$: a \typ{INT} or a \typ{INTMOD} whose modulus is equal to \kbd{*p}, (if \kbd{*p} not \kbd{NULL}), in that case return $1$, else $0$. If a modulus is found it is put in \kbd{*p}, else \kbd{*p} is left unchanged. \fun{int}{RgV_is_FpV}{GEN z, GEN *p}, \kbd{z} a \typ{VEC} (resp. \typ{COL}), checks if it can be mapped to a \kbd{FpV} (resp. \kbd{FpC}), by checking \kbd{Rg\_is\_Fp} coefficientwise. \fun{int}{RgM_is_FpM}{GEN z, GEN *p}, \kbd{z} a \typ{MAT}, checks if it can be mapped to a \kbd{FpM}, by checking \kbd{RgV\_is\_FpV} columnwise. \fun{GEN}{Rg_to_Fp}{GEN z, GEN p}, \kbd{z} a scalar which can be mapped to $\Z/p\Z$: a \typ{INT}, a \typ{INTMOD} whose modulus is divisible by $p$, a \typ{FRAC} whose denominator is coprime to $p$, or a \typ{PADIC} with underlying prime $\ell$ satisfying $p = \ell^n$ for some $n$ (less than the accuracy of the input). Returns \kbd{lift(z * Mod(1,p))}, normalized. \fun{GEN}{padic_to_Fp}{GEN x, GEN p} special case of \tet{Rg_to_Fp}, for a $x$ a \typ{PADIC}. \fun{GEN}{RgV_to_FpV}{GEN z, GEN p}, \kbd{z} a \typ{VEC} or \typ{COL}, returns the \kbd{FpV} (as a \typ{VEC}) obtained by applying \kbd{Rg\_to\_Fp} coefficientwise. \fun{GEN}{RgC_to_FpC}{GEN z, GEN p}, \kbd{z} a \typ{VEC} or \typ{COL}, returns the \kbd{FpC} (as a \typ{COL}) obtained by applying \kbd{Rg\_to\_Fp} coefficientwise. \fun{GEN}{RgM_to_FpM}{GEN z, GEN p}, \kbd{z} a \typ{MAT}, returns the \kbd{FpM} obtained by applying \kbd{RgC\_to\_FpC} columnwise. \fun{GEN}{RgM_Fp_init}{GEN z, GEN p, ulong *pp}, given an \kbd{RgM} $z$, whose entries can be mapped to $\F_p$ (as per \tet{Rg_to_Fp}), and a prime number $p$. This routine returns a normal form of $z$: either an \kbd{F2m} ($p = 2$), an \kbd{Flm} ($p$ fits into an \kbd{ulong}) or an \kbd{FpM}. In the first two cases, \kbd{pp} is set to \kbd{itou}$(p)$, and to $0$ in the last. The functions above are generally used as follow: \bprog GEN add(GEN x, GEN y) { GEN p = NULL; if (Rg_is_Fp(x, &p) && Rg_is_Fp(y, &p) && p) { x = Rg_to_Fp(x, p); y = Rg_to_Fp(y, p); z = Fp_add(x, y, p); return Fp_to_mod(z); } else return gadd(x, y); } @eprog \fun{GEN}{FpC_red}{GEN z, GEN p}, \kbd{z} a \kbd{ZC}. Returns \kbd{lift(Col(z) * Mod(1,p))}, hence a \typ{COL}. \fun{GEN}{FpV_red}{GEN z, GEN p}, \kbd{z} a \kbd{ZV}. Returns \kbd{lift(Vec(z) * Mod(1,p))}, hence a \typ{VEC} \fun{GEN}{FpM_red}{GEN z, GEN p}, \kbd{z} a \kbd{ZM}. Returns \kbd{lift(z * Mod(1,p))}, which is an \kbd{FpM}. \subsubsec{Basic operations} \fun{GEN}{random_FpC}{long n, GEN p} returns a random \kbd{FpC} with $n$ components. \fun{GEN}{random_FpV}{long n, GEN p} returns a random \kbd{FpV} with $n$ components. \fun{GEN}{FpC_center}{GEN z, GEN p, GEN pov2} returns a \typ{COL} whose entries are the \kbd{Fp\_center} of the \kbd{gel(z,i)}. \fun{GEN}{FpM_center}{GEN z, GEN p, GEN pov2} returns a matrix whose entries are the \kbd{Fp\_center} of the \kbd{gcoeff(z,i,j)}. \fun{void}{FpC_center_inplace}{GEN z, GEN p, GEN pov2} in-place version of \kbd{FpC\_center}, using \kbd{affii}. \fun{void}{FpM_center_inplace}{GEN z, GEN p, GEN pov2} in-place version of \kbd{FpM\_center}, using \kbd{affii}. \fun{GEN}{FpC_add}{GEN x, GEN y, GEN p} adds the \kbd{ZC} $x$ and $y$ and reduce modulo $p$ to obtain an \kbd{FpC}. \fun{GEN}{FpV_add}{GEN x, GEN y, GEN p} same as \kbd{FpC\_add}, returning and \kbd{FpV}. \fun{GEN}{FpM_add}{GEN x, GEN y, GEN p} adds the two \kbd{ZM}s~\kbd{x} and \kbd{y} (assumed to have compatible dimensions), and reduce modulo \kbd{p} to obtain an \kbd{FpM}. \fun{GEN}{FpC_sub}{GEN x, GEN y, GEN p} subtracts the \kbd{ZC} $y$ to the \kbd{ZC} $x$ and reduce modulo $p$ to obtain an \kbd{FpC}. \fun{GEN}{FpV_sub}{GEN x, GEN y, GEN p} same as \kbd{FpC\_sub}, returning and \kbd{FpV}. \fun{GEN}{FpM_sub}{GEN x, GEN y, GEN p} subtracts the two \kbd{ZM}s~\kbd{x} and \kbd{y} (assumed to have compatible dimensions), and reduce modulo \kbd{p} to obtain an \kbd{FpM}. \fun{GEN}{FpC_Fp_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{ZC}~\kbd{x} (seen as a column vector) by the \typ{INT}~\kbd{y} and reduce modulo \kbd{p} to obtain an \kbd{FpC}. \fun{GEN}{FpM_Fp_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{ZM}~\kbd{x} (seen as a column vector) by the \typ{INT}~\kbd{y} and reduce modulo \kbd{p} to obtain an \kbd{FpM}. \fun{GEN}{FpC_FpV_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{ZC}~\kbd{x} (seen as a column vector) by the \kbd{ZV}~\kbd{y} (seen as a row vector, assumed to have compatible dimensions), and reduce modulo \kbd{p} to obtain an \kbd{FpM}. \fun{GEN}{FpM_mul}{GEN x, GEN y, GEN p} multiplies the two \kbd{ZM}s~\kbd{x} and \kbd{y} (assumed to have compatible dimensions), and reduce modulo \kbd{p} to obtain an \kbd{FpM}. \fun{GEN}{FpM_powu}{GEN x, ulong n, GEN p} computes $x^n$ where $x$ is a square \kbd{FpM}. \fun{GEN}{FpM_FpC_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{ZM}~\kbd{x} by the \kbd{ZC}~\kbd{y} (seen as a column vector, assumed to have compatible dimensions), and reduce modulo \kbd{p} to obtain an \kbd{FpC}. \fun{GEN}{FpM_FpC_mul_FpX}{GEN x, GEN y, GEN p, long v} is a memory-clean version of \bprog GEN tmp = FpM_FpC_mul(x,y,p); return RgV_to_RgX(tmp, v); @eprog \fun{GEN}{FpV_FpC_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{ZV}~\kbd{x} (seen as a row vector) by the \kbd{ZC}~\kbd{y} (seen as a column vector, assumed to have compatible dimensions), and reduce modulo \kbd{p} to obtain an \kbd{Fp}. \fun{GEN}{FpV_dotproduct}{GEN x,GEN y,GEN p} scalar product of $x$ and $y$ (assumed to have the same length). \fun{GEN}{FpV_dotsquare}{GEN x, GEN p} scalar product of $x$ with itself. has \typ{INT} entries. \fun{GEN}{FpV_factorback}{GEN L, GEN e, GEN p} given an \kbd{FpV} $L$ and a \kbd{ZV} $e$ of the same length, return $\prod_i L_i^{e_i}$ modulo $p$. \subsubsec{\kbd{Fp}-linear algebra} The implementations are not asymptotically efficient ($O(n^3)$ standard algorithms). \fun{GEN}{FpM_deplin}{GEN x, GEN p} returns a non-trivial kernel vector, or \kbd{NULL} if none exist. \fun{GEN}{FpM_det}{GEN x, GEN p} as \kbd{det} \fun{GEN}{FpM_gauss}{GEN a, GEN b, GEN p} as \kbd{gauss}, where $a$ and $b$ are \kbd{FpM}. \fun{GEN}{FpM_FpC_gauss}{GEN a, GEN b, GEN p} as \kbd{gauss}, where $a$ is a \kbd{FpM} and $b$ a \kbd{FpC}. \fun{GEN}{FpM_image}{GEN x, GEN p} as \kbd{image} \fun{GEN}{FpM_intersect}{GEN x, GEN y, GEN p} as \kbd{intersect} \fun{GEN}{FpM_inv}{GEN x, GEN p} returns a left inverse of \kbd{x} (the inverse if $x$ is square), or \kbd{NULL} if \kbd{x} is not invertible. \fun{GEN}{FpM_FpC_invimage}{GEN A, GEN y, GEN p} given an \kbd{FpM} $A$ and an \kbd{FpC} $y$, returns an $x$ such that $Ax = y$, or \kbd{NULL} if no such vector exist. \fun{GEN}{FpM_invimage}{GEN A, GEN y, GEN p} given two \kbd{FpM} $A$ and $y$, returns $x$ such that $Ax = y$, or \kbd{NULL} if no such matrix exist. \fun{GEN}{FpM_ker}{GEN x, GEN p} as \kbd{ker} \fun{long}{FpM_rank}{GEN x, GEN p} as \kbd{rank} \fun{GEN}{FpM_indexrank}{GEN x, GEN p} as \kbd{indexrank} \fun{GEN}{FpM_suppl}{GEN x, GEN p} as \kbd{suppl} \fun{GEN}{FpM_hess}{GEN x, GEN p} upper Hessenberg form of $x$ over $\F_p$. \fun{GEN}{FpM_charpoly}{GEN x, GEN p} characteristic polynomial of $x$. \subsubsec{\kbd{FqC}, \kbd{FqM} and \kbd{Fq}-linear algebra} An \kbd{FqM} (resp. \kbd{FqC}) is a matrix (resp a \typ{COL}) with \kbd{Fq} coefficients (with respect to given \kbd{T}, \kbd{p}), not necessarily reduced (i.e arbitrary \typ{INT}s and \kbd{ZX}s in the same variable as \kbd{T}). \fun{GEN}{RgC_to_FqC}{GEN z, GEN T, GEN p} \fun{GEN}{RgM_to_FqM}{GEN z, GEN T, GEN p} \fun{GEN}{FqC_add}{GEN a, GEN b, GEN T, GEN p} \fun{GEN}{FqC_sub}{GEN a, GEN b, GEN T, GEN p} \fun{GEN}{FqC_Fq_mul}{GEN a, GEN b, GEN T, GEN p} \fun{GEN}{FqM_FqC_gauss}{GEN a, GEN b, GEN T, GEN p} as \kbd{gauss}, where $b$ is a \kbd{FqC}. \fun{GEN}{FqM_FqC_invimage}{GEN a, GEN b, GEN T, GEN p} \fun{GEN}{FqM_FqC_mul}{GEN a, GEN b, GEN T, GEN p} \fun{GEN}{FqM_deplin}{GEN x, GEN T, GEN p} returns a non-trivial kernel vector, or \kbd{NULL} if none exist. \fun{GEN}{FqM_det}{GEN x, GEN T, GEN p} as \kbd{det} \fun{GEN}{FqM_gauss}{GEN a, GEN b, GEN T, GEN p} as \kbd{gauss}, where $b$ is a \kbd{FqM}. \fun{GEN}{FqM_image}{GEN x, GEN T, GEN p} as \kbd{image} \fun{GEN}{FqM_indexrank}{GEN x, GEN T, GEN p} as \kbd{indexrank} \fun{GEN}{FqM_inv}{GEN x, GEN T, GEN p} returns the inverse of \kbd{x}, or \kbd{NULL} if \kbd{x} is not invertible. \fun{GEN}{FqM_invimage}{GEN a, GEN b, GEN T, GEN p} as \kbd{invimage} \fun{GEN}{FqM_ker}{GEN x, GEN T, GEN p} as \kbd{ker} \fun{GEN}{FqM_mul}{GEN a, GEN b, GEN T, GEN p} \fun{long}{FqM_rank}{GEN x, GEN T, GEN p} as \kbd{rank} \fun{GEN}{FqM_suppl}{GEN x, GEN T, GEN p} as \kbd{suppl} \subsec{\kbd{Flc} / \kbd{Flv}, \kbd{Flm}} See \kbd{FpV}, \kbd{FpM} operations. \fun{GEN}{Flv_copy}{GEN x} returns a copy of \kbd{x}. \fun{GEN}{Flv_center}{GEN z, ulong p, ulong ps2} \fun{GEN}{random_Flv}{long n, ulong p} returns a random \kbd{Flv} with $n$ components. \fun{GEN}{Flm_copy}{GEN x} returns a copy of \kbd{x}. \fun{GEN}{matid_Flm}{long n} returns an \kbd{Flm} which is an $n \times n$ identity matrix. \fun{GEN}{scalar_Flm}{long s, long n} returns an \kbd{Flm} which is $s$ times the $n \times n$ identity matrix. \fun{GEN}{Flm_center}{GEN z, ulong p, ulong ps2} \fun{GEN}{Flm_Fl_add}{GEN x, ulong y, ulong p} returns $x + y*\text{Id}$ ($x$ must be square). \fun{GEN}{Flm_Flc_mul}{GEN x, GEN y, ulong p} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{Flm_Flc_mul_pre}{GEN x, GEN y, ulong p, ulong pi} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions), assuming $pi$ is the pseudo inverse of $p$. \fun{GEN}{Flc_Flv_mul}{GEN x, GEN y, ulong p} multiplies the column vector $x$ by the row vector $y$. The result is a matrix. \fun{GEN}{Flm_Flc_mul_pre_Flx}{GEN x, GEN y, ulong p, ulong pi, long sv} return \kbd{Flv\_to\_Flx(Flm\_Flc\_mul\_pre(x, y, p, pi), sv)}. \fun{GEN}{Flm_Fl_mul}{GEN x, ulong y, ulong p} multiplies the \kbd{Flm} \kbd{x} by \kbd{y}. \fun{GEN}{Flm_neg}{GEN x, ulong p} negates the \kbd{Flm} \kbd{x}. \fun{void}{Flm_Fl_mul_inplace}{GEN x, ulong y, ulong p} replaces the \kbd{Flm} \kbd{x} by $\kbd{x}*\kbd{y}$. \fun{GEN}{Flv_Fl_mul}{GEN x, ulong y, ulong p} multiplies the \kbd{Flv} \kbd{x} by \kbd{y}. \fun{void}{Flv_Fl_mul_inplace}{GEN x, ulong y, ulong p} replaces the \kbd{Flc} \kbd{x} by $\kbd{x}*\kbd{y}$. \fun{void}{Flv_Fl_mul_part_inplace}{GEN x, ulong y, ulong p, long l} multiplies $x[1..l]$ by $y$ modulo $p$. In place. \fun{GEN}{Flv_Fl_div}{GEN x, ulong y, ulong p} divides the \kbd{Flv} \kbd{x} by \kbd{y}. \fun{void}{Flv_Fl_div_inplace}{GEN x, ulong y, ulong p} replaces the \kbd{Flv} \kbd{x} by $\kbd{x}/\kbd{y}$. \fun{void}{Flc_lincomb1_inplace}{GEN X, GEN Y, ulong v, ulong q} sets $X\leftarrow X + vY$, where $X,Y$ are \kbd{Flc}. Memory efficient (e.g. no-op if $v = 0$), and gerepile-safe. \fun{GEN}{Flv_add}{GEN x, GEN y, ulong p} adds two \kbd{Flv}. \fun{void}{Flv_add_inplace}{GEN x, GEN y, ulong p} replaces $x$ by $x+y$. \fun{GEN}{Flv_neg}{GEN x, ulong p} returns $-x$. \fun{void}{Flv_neg_inplace}{GEN x, ulong p} replaces $x$ by $-x$. \fun{GEN}{Flv_sub}{GEN x, GEN y, ulong p} subtracts \kbd{y} to \kbd{x}. \fun{void}{Flv_sub_inplace}{GEN x, GEN y, ulong p} replaces $x$ by $x-y$. \fun{ulong}{Flv_dotproduct}{GEN x, GEN y, ulong p} returns the scalar product of \kbd{x} and \kbd{y} \fun{ulong}{Flv_dotproduct_pre}{GEN x, GEN y, ulong p, ulong pi} returns the scalar product of \kbd{x} and \kbd{y} assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Flv_sum}{GEN x, ulong p} returns the sum of the components of $x$. \fun{ulong}{Flv_prod}{GEN x, ulong p} returns the product of the components of $x$. \fun{ulong}{Flv_prod_pre}{GEN x, ulong p, ulong pi} as \kbd{Flv\_prod} assuming $pi$ is the pseudo inverse of $p$. \fun{GEN}{Flv_inv}{GEN x, ulong p} returns the vector of inverses of the elements of $x$ (as a \kbd{Flv}). Use Montgomery trick. \fun{void}{Flv_inv_inplace}{GEN x, ulong p} in place variant of \kbd{Flv\_inv}. \fun{GEN}{Flv_inv_pre}{GEN x, ulong p, ulong pi} as \kbd{Flv\_inv} assuming $pi$ is the pseudo inverse of $p$. \fun{void}{Flv_inv_pre_inplace}{GEN x, ulong p, ulong pi} in place variant of \kbd{Flv\_inv}. \fun{GEN}{Flc_FpV_mul}{GEN x, GEN y, GEN p} multiplies $x$ (seen as a column vector) by $y$ (seen as a row vector, assumed to have compatible dimensions) to obtain an \kbd{Flm}. \fun{GEN}{zero_Flm}{long m, long n} creates a \kbd{Flm} with \kbd{m} x \kbd{n} components set to $0$. Note that the result allocates a \emph{single} column, so modifying an entry in one column modifies it in all columns. \fun{GEN}{zero_Flm_copy}{long m, long n} creates a \kbd{Flm} with \kbd{m} x \kbd{n} components set to $0$. \fun{GEN}{zero_Flv}{long n} creates a \kbd{Flv} with \kbd{n} components set to $0$. \fun{GEN}{Flm_row}{GEN A, long x0} return $A[i,]$, the $i$-th row of the \kbd{Flm} $A$. \fun{GEN}{Flm_add}{GEN x, GEN y, ulong p} adds \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{Flm_sub}{GEN x, GEN y, ulong p} subtracts \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{Flm_mul}{GEN x, GEN y, ulong p} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{Flm_powers}{GEN x, ulong n, ulong p} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as a \typ{VEC} of \kbd{Flm}s. \fun{GEN}{Flm_powu}{GEN x, ulong n, ulong p} computes $x^n$ where $x$ is a square \kbd{Flm}. \fun{GEN}{Flm_charpoly}{GEN x, ulong p} return the characteristic polynomial of the square \kbd{Flm} $x$, as a \kbd{Flx}. \fun{GEN}{Flm_deplin}{GEN x, ulong p} \fun{ulong}{Flm_det}{GEN x, ulong p} \fun{ulong}{Flm_det_sp}{GEN x, ulong p}, as \kbd{Flm\_det}, in place (destroys~\kbd{x}). \fun{GEN}{Flm_gauss}{GEN a, GEN b, ulong p} as \kbd{gauss}, where $b$ is a \kbd{Flm}. \fun{GEN}{Flm_Flc_gauss}{GEN a, GEN b, ulong p} as \kbd{gauss}, where $b$ is a \kbd{Flc}. \fun{GEN}{Flm_indexrank}{GEN x, ulong p} \fun{GEN}{Flm_inv}{GEN x, ulong p} \fun{GEN}{Flm_adjoint}{GEN x, ulong p} as \kbd{matadjoint}. \fun{GEN}{Flm_Flc_invimage}{GEN A, GEN y, ulong p} given an \kbd{Flm} $A$ and an \kbd{Flc} $y$, returns an $x$ such that $Ax = y$, or \kbd{NULL} if no such vector exist. \fun{GEN}{Flm_invimage}{GEN A, GEN y, ulong p} given two \kbd{Flm} $A$ and $y$, returns $x$ such that $Ax = y$, or \kbd{NULL} if no such matrix exist. \fun{GEN}{Flm_ker}{GEN x, ulong p} \fun{GEN}{Flm_ker_sp}{GEN x, ulong p, long deplin}, as \kbd{Flm\_ker} (if \kbd{deplin=0}) or \kbd{Flm\_deplin} (if \kbd{deplin=1}) , in place (destroys~\kbd{x}). \fun{long}{Flm_rank}{GEN x, ulong p} \fun{long}{Flm_suppl}{GEN x, ulong p} \fun{GEN}{Flm_image}{GEN x, ulong p} \fun{GEN}{Flm_intersect}{GEN x, GEN y, ulong p} \fun{GEN}{Flm_transpose}{GEN x} \fun{GEN}{Flm_hess}{GEN x, ulong p} upper Hessenberg form of $x$ over $\F_p$. \subsec{\kbd{F2c} / \kbd{F2v}, \kbd{F2m}} An \kbd{F2v}~\kbd{v} is a \typ{VECSMALL} representing a vector over $\F_2$. Specifically \kbd{z[0]} is the usual codeword, \kbd{z[1]} is the number of components of $v$ and the coefficients are given by the bits of remaining words by increasing indices. \fun{ulong}{F2v_coeff}{GEN x, long i} returns the coefficient $i\ge 1$ of $x$. \fun{void}{F2v_clear}{GEN x, long i} sets the coefficient $i\ge 1$ of $x$ to $0$. \fun{void}{F2v_flip}{GEN x, long i} adds $1$ to the coefficient $i\ge 1$ of $x$. \fun{void}{F2v_set}{GEN x, long i} sets the coefficient $i\ge 1$ of $x$ to $1$. \fun{void}{F2v_copy}{GEN x} returns a copy of $x$. \fun{GEN}{F2v_slice}{GEN x, long a, long b} returns the \kbd{F2v} with entries $x[a]$, \dots, $x[b]$. Assumes $a \leq b$. \fun{ulong}{F2m_coeff}{GEN x, long i, long j} returns the coefficient $(i,j)$ of $x$. \fun{void}{F2m_clear}{GEN x, long i, long j} sets the coefficient $(i,j)$ of $x$ to $0$. \fun{void}{F2m_flip}{GEN x, long i, long j} adds $1$ to the coefficient $(i,j)$ of $x$. \fun{void}{F2m_set}{GEN x, long i, long j} sets the coefficient $(i,j)$ of $x$ to $1$. \fun{void}{F2m_copy}{GEN x} returns a copy of $x$. \fun{GEN}{F2m_rowslice}{GEN x, long a, long b} returns the \kbd{F2m} built from the $a$-th to $b$-th rows of the \kbd{F2m} $x$. Assumes $a \leq b$. \fun{GEN}{F2m_F2c_mul}{GEN x, GEN y} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{F2m_image}{GEN x} gives a subset of the columns of $x$ that generate the image of $x$. \fun{GEN}{F2m_invimage}{GEN A, GEN B} \fun{GEN}{F2m_F2c_invimage}{GEN A, GEN y} \fun{GEN}{F2m_gauss}{GEN a, GEN b} as \kbd{gauss}, where $b$ is a \kbd{F2m}. \fun{GEN}{F2m_F2c_gauss}{GEN a, GEN b} as \kbd{gauss}, where $b$ is a \kbd{F2c}. \fun{GEN}{F2m_indexrank}{GEN x} $x$ being a matrix of rank $r$, returns a vector with two \typ{VECSMALL} components $y$ and $z$ of length $r$ giving a list of rows and columns respectively (starting from 1) such that the extracted matrix obtained from these two vectors using \kbd{vecextract}$(x,y,z)$ is invertible. \fun{GEN}{F2m_mul}{GEN x, GEN y} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{F2m_powu}{GEN x, ulong n} computes $x^n$ where $x$ is a square \kbd{F2m}. \fun{long}{F2m_rank}{GEN x} as \kbd{rank}. \fun{long}{F2m_suppl}{GEN x} as \kbd{suppl}. \fun{GEN}{matid_F2m}{long n} returns an \kbd{F2m} which is an $n \times n$ identity matrix. \fun{GEN}{zero_F2v}{long n} creates a \kbd{F2v} with \kbd{n} components set to $0$. \fun{GEN}{const_F2v}{long n} creates a \kbd{F2v} with \kbd{n} components set to $1$. \fun{GEN}{F2v_ei}{long n, long i} creates a \kbd{F2v} with \kbd{n} components set to $0$, but for the $i$-th one, which is set to $1$ ($i$-th vector in the canonical basis). \fun{GEN}{zero_F2m}{long m, long n} creates a \kbd{Flm} with \kbd{m} x \kbd{n} components set to $0$. Note that the result allocates a \emph{single} column, so modifying an entry in one column modifies it in all columns. \fun{GEN}{zero_F2m_copy}{long m, long n} creates a \kbd{F2m} with \kbd{m} x \kbd{n} components set to $0$. \fun{GEN}{F2v_to_Flv}{GEN x} \fun{GEN}{F2c_to_ZC}{GEN x} \fun{GEN}{ZV_to_F2v}{GEN x} \fun{GEN}{RgV_to_F2v}{GEN x} \fun{GEN}{F2m_to_Flm}{GEN x} \fun{GEN}{F2m_to_ZM}{GEN x} \fun{GEN}{Flv_to_F2v}{GEN x} \fun{GEN}{Flm_to_F2m}{GEN x} \fun{GEN}{ZM_to_F2m}{GEN x} \fun{GEN}{RgM_to_F2m}{GEN x} \fun{void}{F2v_add_inplace}{GEN x, GEN y} replaces $x$ by $x+y$. It is allowed for $y$ to be shorter than $x$. \fun{ulong}{F2m_det}{GEN x} \fun{ulong}{F2m_det_sp}{GEN x}, as \kbd{F2m\_det}, in place (destroys~\kbd{x}). \fun{GEN}{F2m_deplin}{GEN x} \fun{ulong}{F2v_dotproduct}{GEN x, GEN y} returns the scalar product of \kbd{x} and \kbd{y} \fun{GEN}{F2m_inv}{GEN x} \fun{GEN}{F2m_ker}{GEN x} \fun{GEN}{F2m_ker_sp}{GEN x, long deplin}, as \kbd{F2m\_ker} (if \kbd{deplin=0}) or \kbd{F2m\_deplin} (if \kbd{deplin=1}), in place (destroys~\kbd{x}). \subsec{\kbd{FlxqV}, \kbd{FlxqC}, \kbd{FlxqM}} See \kbd{FqV}, \kbd{FqC}, \kbd{FqM} operations. \fun{GEN}{FlxqV_dotproduct}{GEN x, GEN y, GEN T, ulong p} as \kbd{FpV\_dotproduct}. \fun{GEN}{FlxM_Flx_add_shallow}{GEN x, GEN y, ulong p} as \kbd{RgM\_Rg\_add\_shallow}. \fun{GEN}{FlxqC_Flxq_mul}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{FlxqM_Flxq_mul}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{FlxqM_FlxqC_gauss}{GEN a, GEN b, GEN T, ulong p} \fun{GEN}{FlxqM_FlxqC_invimage}{GEN a, GEN b, GEN T, ulong p} \fun{GEN}{FlxqM_FlxqC_mul}{GEN a, GEN b, GEN T, ulong p} \fun{GEN}{FlxqM_deplin}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqM_det}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqM_gauss}{GEN a, GEN b, GEN T, ulong p} \fun{GEN}{FlxqM_image}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqM_indexrank}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqM_inv}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqM_invimage}{GEN a, GEN b, GEN T, ulong p} \fun{GEN}{FlxqM_ker}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqM_mul}{GEN a, GEN b, GEN T, ulong p} \fun{long}{FlxqM_rank}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqM_suppl}{GEN x, GEN T, ulong p} \fun{GEN}{matid_FlxqM}{long n, GEN T, ulong p} \subsec{\kbd{FpX}} Let \kbd{p} an understood \typ{INT}, to be given in the function arguments; in practice \kbd{p} is not assumed to be prime, but be wary. Recall than an \kbd{Fp} object is a \typ{INT}, preferably belonging to $[0, \kbd{p}-1]$; an \kbd{FpX} is a \typ{POL} in a fixed variable whose coefficients are \kbd{Fp} objects. Unless mentioned otherwise, all outputs in this section are \kbd{FpX}s. All operations are understood to take place in $(\Z/\kbd{p}\Z)[X]$. \subsubsec{Conversions} In what follows \kbd{p} is always a \typ{INT}, not necessarily prime. \fun{int}{RgX_is_FpX}{GEN z, GEN *p}, \kbd{z} a \typ{POL}, checks if it can be mapped to a \kbd{FpX}, by checking \kbd{Rg\_is\_Fp} coefficientwise. \fun{GEN}{RgX_to_FpX}{GEN z, GEN p}, \kbd{z} a \typ{POL}, returns the \kbd{FpX} obtained by applying \kbd{Rg\_to\_Fp} coefficientwise. \fun{GEN}{FpX_red}{GEN z, GEN p}, \kbd{z} a \kbd{ZX}, returns \kbd{lift(z * Mod(1,p))}, normalized. \fun{GEN}{FpXV_red}{GEN z, GEN p}, \kbd{z} a \typ{VEC} of \kbd{ZX}. Applies \kbd{FpX\_red} componentwise and returns the result (and we obtain a vector of \kbd{FpX}s). \fun{GEN}{FpXT_red}{GEN z, GEN p}, \kbd{z} a tree of \kbd{ZX}. Applies \kbd{FpX\_red} to each leaf and returns the result (and we obtain a tree of \kbd{FpX}s). \subsubsec{Basic operations} In what follows \kbd{p} is always a \typ{INT}, not necessarily prime. \noindent Now, except for \kbd{p}, the operands and outputs are all \kbd{FpX} objects. Results are undefined on other inputs. \fun{GEN}{FpX_add}{GEN x,GEN y, GEN p} adds \kbd{x} and \kbd{y}. \fun{GEN}{FpX_neg}{GEN x,GEN p} returns $-\kbd{x}$, the components are between $0$ and $p$ if this is the case for the components of $x$. \fun{GEN}{FpX_renormalize}{GEN x, long l}, as \kbd{normalizepol}, where $\kbd{l} = \kbd{lg(x)}$, in place. \fun{GEN}{FpX_sub}{GEN x,GEN y,GEN p} returns $x-y$. \fun{GEN}{FpX_halve}{GEN x, GEN p} returns $z$ such that $2\*z = x$ modulo $p$ assuming such $z$ exists. \fun{GEN}{FpX_mul}{GEN x,GEN y,GEN p} returns $x\*y$. \fun{GEN}{FpX_mulspec}{GEN a, GEN b, GEN p, long na, long nb} see \kbd{ZX\_mulspec} \fun{GEN}{FpX_sqr}{GEN x,GEN p} returns $\kbd{x}^2$. \fun{GEN}{FpX_powu}{GEN x, ulong n, GEN p} returns $x^n$. \fun{GEN}{FpX_convol}{GEN x, GEN y, GEN p} return the-term by-term product of $x$ and $y$. \fun{GEN}{FpX_divrem}{GEN x, GEN y, GEN p, GEN *pr} returns the quotient of \kbd{x} by \kbd{y}, and sets \kbd{pr} to the remainder. \fun{GEN}{FpX_div}{GEN x, GEN y, GEN p} returns the quotient of \kbd{x} by \kbd{y}. \fun{GEN}{FpX_div_by_X_x}{GEN A, GEN a, GEN p, GEN *r} returns the quotient of the \kbd{FpX}~\kbd{A} by $(X - \kbd{a})$, and sets \kbd{r} to the remainder $\kbd{A}(\kbd{a})$. \fun{GEN}{FpX_rem}{GEN x, GEN y, GEN p} returns the remainder \kbd{x} mod \kbd{y}. \fun{long}{FpX_valrem}{GEN x, GEN t, GEN p, GEN *r} The arguments \kbd{x} and \kbd{e} being non-zero \kbd{FpX} returns the highest exponent $e$ such that $\kbd{t}^{e}$ divides~\kbd{x}. The quotient $\kbd{x}/\kbd{t}^{e}$ is returned in~\kbd{*r}. In particular, if \kbd{t} is irreducible, this returns the valuation at \kbd{t} of~\kbd{x}, and \kbd{*r} is the prime-to-\kbd{t} part of~\kbd{x}. \fun{GEN}{FpX_deriv}{GEN x, GEN p} returns the derivative of \kbd{x}. This function is not memory-clean, but nevertheless suitable for \kbd{gerepileupto}. \fun{GEN}{FpX_integ}{GEN x, GEN p} returns the primitive of \kbd{x} whose constant term is $0$. \fun{GEN}{FpX_digits}{GEN x, GEN B, GEN p} returns a vector of \kbd{FpX} $[c_0,\ldots,c_n]$ of degree less than the degree of $B$ and such that $x=\sum_{i=0}^{n}{c_i\*B^i}$. \fun{GEN}{FpXV_FpX_fromdigits}{GEN v, GEN B, GEN p} where $v=[c_0,\ldots,c_n]$ is a vector of \kbd{FpX}, returns $\sum_{i=0}^{n}{c_i\*B^i}$. \fun{GEN}{FpX_translate}{GEN P, GEN c, GEN p} let $c$ be an \kbd{Fp} and let $P$ be an \kbd{FpX}; returns the translated \kbd{FpX} of $P(X+c)$. \fun{GEN}{FpX_gcd}{GEN x, GEN y, GEN p} returns a (not necessarily monic) greatest common divisor of $x$ and $y$. \fun{GEN}{FpX_halfgcd}{GEN x, GEN y, GEN p} returns a two-by-two \kbd{FpXM} $M$ with determinant $\pm 1$ such that the image $(a,b)$ of $(x,y)$ by $M$ has the property that $\deg a \geq {\deg x \over 2} > \deg b$. \fun{GEN}{FpX_extgcd}{GEN x, GEN y, GEN p, GEN *u, GEN *v} returns $d = \text{GCD}(\kbd{x},\kbd{y})$ (not necessarily monic), and sets \kbd{*u}, \kbd{*v} to the Bezout coefficients such that $\kbd{*ux} + \kbd{*vy} = d$. If \kbd{*u} is set to \kbd{NULL}, it is not computed which is a bit faster. This is useful when computing the inverse of $y$ modulo $x$. \fun{GEN}{FpX_center}{GEN z, GEN p, GEN pov2} returns the polynomial whose coefficient belong to the symmetric residue system. Assumes the coefficients already belong to $]-p/2, p[$ and that \kbd{pov2} is \kbd{shifti(p,-1)}. \fun{GEN}{FpX_center_i}{GEN z, GEN p, GEN pov2} internal variant of \tet{FpX_center}, not \kbd{gerepile}-safe. \fun{GEN}{FpX_Frobenius}{GEN T, GEN p} returns $X^{p}\pmod{T(X)}$. \fun{GEN}{FpX_matFrobenius}{GEN T, GEN p} returns the matrix of the Frobenius automorphism $x\mapsto x^p$ over the power basis of $\F_p[X]/(T)$. \subsubsec{Mixed operations} The following functions implement arithmetic operations between \kbd{FpX} and \kbd{Fp} operands, the result being of type \kbd{FpX}. The integer \kbd{p} need not be prime. \fun{GEN}{Z_to_FpX}{GEN x, GEN p, long v} converts a \typ{INT} to a scalar polynomial in variable $v$, reduced modulo $p$. \fun{GEN}{FpX_Fp_add}{GEN y, GEN x, GEN p} add the \kbd{Fp}~\kbd{x} to the \kbd{FpX}~\kbd{y}. \fun{GEN}{FpX_Fp_add_shallow}{GEN y, GEN x, GEN p} add the \kbd{Fp}~\kbd{x} to the \kbd{FpX}~\kbd{y}, using a shallow copy (result not suitable for \kbd{gerepileupto}) \fun{GEN}{FpX_Fp_sub}{GEN y, GEN x, GEN p} subtract the \kbd{Fp}~\kbd{x} from the \kbd{FpX}~\kbd{y}. \fun{GEN}{FpX_Fp_sub_shallow}{GEN y, GEN x, GEN p} subtract the \kbd{Fp}~\kbd{x} from the \kbd{FpX}~\kbd{y}, using a shallow copy (result not suitable for \kbd{gerepileupto}) \fun{GEN}{Fp_FpX_sub}{GEN x,GEN y,GEN p} returns $x - y$, where $x$ is a \typ{INT} and $y$ an \kbd{FpX}. \fun{GEN}{FpX_Fp_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{FpX}~\kbd{x} by the \kbd{Fp}~\kbd{y}. \fun{GEN}{FpX_Fp_mulspec}{GEN x, GEN y, GEN p, long lx} see \kbd{ZX\_mulspec} \fun{GEN}{FpX_mulu}{GEN x, ulong y, GEN p} multiplies the \kbd{FpX}~\kbd{x} by \kbd{y}. \fun{GEN}{FpX_Fp_mul_to_monic}{GEN y,GEN x,GEN p} returns $y\*x$ assuming the result is monic of the same degree as $y$ (in particular $x\neq 0$). \subsubsec{Miscellaneous operations} \fun{GEN}{FpX_normalize}{GEN z, GEN p} divides the \kbd{FpX}~\kbd{z} by its leading coefficient. If the latter is~$1$, \kbd{z} itself is returned, not a copy. If not, the inverse remains uncollected on the stack. \fun{GEN}{FpX_invBarrett}{GEN T, GEN p}, returns the Barrett inverse $M$ of $T$ defined by $M(x)\*x^n\*T(1/x)\equiv 1\pmod{x^{n-1}}$ where $n$ is the degree of $T$. \fun{GEN}{FpX_rescale}{GEN P, GEN h, GEN p} returns $h^{\deg(P)} P(x/h)$. \kbd{P} is an \kbd{FpX} and \kbd{h} is a non-zero \kbd{Fp} (the routine would work with any non-zero \typ{INT} but is not efficient in this case). \fun{GEN}{FpX_eval}{GEN x, GEN y, GEN p} evaluates the \kbd{FpX}~\kbd{x} at the \kbd{Fp}~\kbd{y}. The result is an~\kbd{Fp}. \fun{GEN}{FpX_FpV_multieval}{GEN P, GEN v, GEN p} returns the vector $[P(v[1]),\ldots,P(v[n])]$ as a \kbd{FpV}. \fun{GEN}{FpX_dotproduct}{GEN x, GEN y, GEN p} return the scalar product $\sum_{i\geq 0} x_i\*y_i$ of the coefficients of $x$ and $y$. \fun{GEN}{FpXV_FpC_mul}{GEN V, GEN W, GEN p} multiplies a non-empty line vector of\kbd{FpX} by a column vector of \kbd{Fp} of compatible dimensions. The result is an~\kbd{FpX}. \fun{GEN}{FpXV_prod}{GEN V, GEN p}, \kbd{V} being a vector of \kbd{FpX}, returns their product. \fun{GEN}{FpV_roots_to_pol}{GEN V, GEN p, long v}, \kbd{V} being a vector of \kbd{INT}s, returns the monic \kbd{FpX} $\prod_i (\kbd{pol\_x[v]} - \kbd{V[i]})$. \fun{GEN}{FpX_chinese_coprime}{GEN x,GEN y, GEN Tx,GEN Ty, GEN Tz, GEN p}: returns an \kbd{FpX}, congruent to \kbd{x} mod \kbd{Tx} and to \kbd{y} mod \kbd{Ty}. Assumes \kbd{Tx} and \kbd{Ty} are coprime, and \kbd{Tz = Tx * Ty} or \kbd{NULL} (in which case it is computed within). \fun{GEN}{FpV_polint}{GEN x, GEN y, GEN p, long v} returns the \kbd{FpX} interpolation polynomial with value \kbd{y[i]} at \kbd{x[i]}. Assumes lengths are the same, components are \typ{INT}s, and the \kbd{x[i]} are distinct modulo \kbd{p}. \fun{GEN}{FpV_FpM_polint}{GEN x, GEN V, GEN p, long v} equivalent (but faster) to applying \kbd{FpV\_polint(x,$\ldots$)} to all the elements of the vector $V$ (thus, returns a \kbd{FpXV}). \fun{GEN}{FpV_invVandermonde}{GEN L, GEN d, GEN p} $L$ being a \kbd{FpV} of length $n$, return the inverse $M$ of the Vandermonde matrix attached to the elements of $L$, eventually multiplied by \kbd{d} if it is not \kbd{NULL}. If $A$ is a \kbd{FpV} and $B=M\*A$, then the polynomial $P=\sum_{i=1}^n B[i]\*X^{i-1}$ verifies $P(L[i])=d\*A[i]$ for $1 \leq i \leq n$. \fun{int}{FpX_is_squarefree}{GEN f, GEN p} returns $1$ if the \kbd{FpX}~\kbd{f} is squarefree, $0$ otherwise. \fun{int}{FpX_is_irred}{GEN f, GEN p} returns $1$ if the \kbd{FpX}~\kbd{f} is irreducible, $0$ otherwise. Assumes that \kbd{p} is prime. If~\kbd{f} has few factors, \kbd{FpX\_nbfact(f,p) == 1} is much faster. \fun{int}{FpX_is_totally_split}{GEN f, GEN p} returns $1$ if the \kbd{FpX}~\kbd{f} splits into a product of distinct linear factors, $0$ otherwise. Assumes that \kbd{p} is prime. \fun{long}{FpX_ispower}{GEN f, ulong k, GEN p, GEN *pt} return $1$ if the \kbd{FpX} $f$ is a $k$-th power, $0$ otherwise. If \kbd{pt} is not \kbd{NULL}, set it to $g$ such that $g^k = f$. \fun{GEN}{FpX_factor}{GEN f, GEN p}, factors the \kbd{FpX}~\kbd{f}. Assumes that \kbd{p} is prime. The returned value \kbd{v} is a \typ{VEC} with two components: \kbd{v[1]} is a vector of distinct irreducible (\kbd{FpX}) factors, and \kbd{v[2]} is a \typ{VECSMALL} of corresponding exponents. The order of the factors is deterministic (the computation is not). \fun{GEN}{FpX_factor_squarefree}{GEN f, GEN p} returns the squarefree factorization of $f$ modulo $p$. This is a vector $[u_1,\dots,u_k]$ of pairwise coprime \kbd{FpX} such that $u_k \neq 1$ and $f = \prod u_i^i$. Shallow function. \fun{GEN}{FpX_ddf}{GEN f, GEN p} assuming that $f$ is squarefree, returns the distinct degree factorization of $f$ modulo $p$. The returned value \kbd{v} is a \typ{VEC} with two components: \kbd{F=v[1]} is a vector of (\kbd{FpX}) factors, and \kbd{E=v[2]} is a \typ{VECSMALL}, such that $f$ is equal to the product of the \kbd{F[i]} and each \kbd{F[i]} is a product of irreducible factors of degree \kbd{E[i]}. \fun{long}{FpX_ddf_degree}{GEN f, GEN XP, GEN p} assuming that $f$ is squarefree and that all its factors have the same degree, return the common degree, where \kbd{XP} is \kbd{FpX\_Frobenius(f, p)}. \fun{long}{FpX_nbfact}{GEN f, GEN p}, assuming the \kbd{FpX}~f is squarefree, returns the number of its irreducible factors. Assumes that \kbd{p} is prime. \fun{long}{FpX_nbfact_Frobenius}{GEN f, GEN XP, GEN p}, as \kbd{FpX\_nbfact(f, p)} but faster, where \kbd{XP} is \kbd{FpX\_Frobenius(f, p)}. \fun{GEN}{FpX_degfact}{GEN f, GEN p}, as \kbd{FpX\_factor}, but the degrees of the irreducible factors are returned instead of the factors themselves (as a \typ{VECSMALL}). Assumes that \kbd{p} is prime. \fun{long}{FpX_nbroots}{GEN f, GEN p} returns the number of distinct roots in \kbd{\Z/p\Z} of the \kbd{FpX}~\kbd{f}. Assumes that \kbd{p} is prime. \fun{GEN}{FpX_oneroot}{GEN f, GEN p} returns one root in \kbd{\Z/p\Z} of the \kbd{FpX}~\kbd{f}. Return \kbd{NULL} if no root exists. Assumes that \kbd{p} is prime. \fun{GEN}{FpX_oneroot_split}{GEN f, GEN p} as \kbd{FpX\_oneroot}. Faster when $f$ is close to be totally split. \fun{GEN}{FpX_roots}{GEN f, GEN p} returns the roots in \kbd{\Z/p\Z} of the \kbd{FpX}~\kbd{f} (without multiplicity, as a vector of \kbd{Fp}s). Assumes that \kbd{p} is prime. \fun{GEN}{FpX_split_part}{GEN f, GEN p} returns the largest totally split squarefree factor of $f$. \fun{GEN}{random_FpX}{long d, long v, GEN p} returns a random \kbd{FpX} in variable \kbd{v}, of degree less than~\kbd{d}. \fun{GEN}{FpX_resultant}{GEN x, GEN y, GEN p} returns the resultant of \kbd{x} and \kbd{y}, both \kbd{FpX}. The result is a \typ{INT} belonging to $[0,p-1]$. \fun{GEN}{FpX_disc}{GEN x, GEN p} returns the discriminant of the \kbd{FpX} \kbd{x}. The result is a \typ{INT} belonging to $[0,p-1]$. \fun{GEN}{FpX_FpXY_resultant}{GEN a, GEN b, GEN p}, \kbd{a} a \typ{POL} of \typ{INT}s (say in variable $X$), \kbd{b} a \typ{POL} (say in variable $X$) whose coefficients are either \typ{POL}s in $\Z[Y]$ or \typ{INT}s. Returns $\text{Res}_X(a, b)$ in $\F_p[Y]$ as an \kbd{FpY}. The function assumes that $X$ has lower priority than $Y$. \fun{GEN}{FpX_Newton}{GEN x, long n, GEN p} return $\sum{i=0}^{n-1} \pi_i\*X^i$ where $\pi_i$ is the sum of the $i$th-power of the roots of $x$ in an algebraic closure. \fun{GEN}{FpX_fromNewton}{GEN x, GEN p} recover a polynomial from it s Newton sums given by the coefficients of $x$. This function assumes that $p$ and the accuracy of $x$ as a \kbd{FpXn} is larger than the degree of the solution. \fun{GEN}{FpX_Laplace}{GEN x, GEN p} return $\sum{i=0}^{n-1} x_i\*i!\*X^i$. \fun{GEN}{FpX_invLaplace}{GEN x, GEN p} return $\sum{i=0}^{n-1} x_i/{i!}\*X^i$. \subsec{\kbd{FpXQ}, \kbd{Fq}} Let \kbd{p} a \typ{INT} and \kbd{T} an \kbd{FpX} for \kbd{p}, both to be given in the function arguments; an \kbd{FpXQ} object is an \kbd{FpX} whose degree is strictly less than the degree of \kbd{T}. An \kbd{Fq} is either an \kbd{FpXQ} or an \kbd{Fp}. Both represent a class in $(\Z/\kbd{p}\Z)[X] / (T)$, in which all operations below take place. In addition, \kbd{Fq} routines also allow $\kbd{T} = \kbd{NULL}$, in which case no reduction mod \kbd{T} is performed on the result. For efficiency, the routines in this section may leave small unused objects behind on the stack (their output is still suitable for \kbd{gerepileupto}). Besides \kbd{T} and \kbd{p}, arguments are either \kbd{FpXQ} or \kbd{Fq} depending on the function name. (All \kbd{Fq} routines accept \kbd{FpXQ}s by definition, not the other way round.) \subsubsec{Preconditioned reduction} For faster reduction, the modulus $T$ can be replaced by an extended modulus in all \kbd{FpXQ}- and \kbd{Fq}-classes functions, and in \kbd{FpX\_rem} and \kbd{FpX\_divrem}. An extended modulus(\kbd{FpXT}, which is a tree whose leaves are \kbd{FpX})In current implementation, an extended modulus is either a plain modulus (an \kbd{FpX}) or a pair of polynomials, one being the plain modulus $T$ and the other being \tet{FpX_invBarret}$(T,p)$. \fun{GEN}{FpX_get_red}{GEN T, GEN p} returns the extended modulus \kbd{eT}. To write code that works both with plain and extended moduli, the following accessors are defined: \fun{GEN}{get_FpX_mod}{GEN eT} returns the underlying modulus $T$. \fun{GEN}{get_FpX_var}{GEN eT} returns the variable number \kbd{varn}$(T)$. \fun{GEN}{get_FpX_degree}{GEN eT} returns the degree \kbd{degpol}$(T)$. \subsubsec{Conversions} \fun{GEN}{Rg_is_FpXQ}{GEN z, GEN *T, GEN *p}, checks if \kbd{z} is a \kbd{GEN} which can be mapped to $\F_p[X]/(T)$: anything for which \kbd{Rg\_is\_Fp} return $1$, a \typ{POL} for which \kbd{RgX\_to\_FpX} return $1$, a \typ{POLMOD} whose modulus is equal to \kbd{*T} if \kbd{*T} is not \kbd{NULL} (once mapped to a \kbd{FpX}), or a \typ{FFELT} $z$ with the same definition field as \kbd{*T} if \kbd{*T} is not \kbd{NULL} and is a \typ{FFELT}. If an integer modulus is found it is put in \kbd{*p}, else \kbd{*p} is left unchanged. If a polynomial modulus is found it is put in \kbd{*T}, if a \typ{FFELT} $z$ is found, $z$ is put in \kbd{*T}, else \kbd{*T} is left unchanged. \fun{int}{RgX_is_FpXQX}{GEN z, GEN *T, GEN *p}, \kbd{z} a \typ{POL}, checks if it can be mapped to a \kbd{FpXQX}, by checking \kbd{Rg\_is\_FpXQ} coefficientwise. \fun{GEN}{Rg_to_FpXQ}{GEN z, GEN T, GEN p}, \kbd{z} a \kbd{GEN} which can be mapped to $\F_p[X]/(T)$: anything \kbd{Rg\_to\_Fp} can be applied to, a \typ{POL} to which \kbd{RgX\_to\_FpX} can be applied to, a \typ{POLMOD} whose modulus is divisible by $T$ (once mapped to a \kbd{FpX}), a suitable \typ{RFRAC}. Returns \kbd{z} as an \kbd{FpXQ}, normalized. \fun{GEN}{Rg_to_Fq}{GEN z, GEN T, GEN p}, applies \kbd{Rg\_to\_Fp} if $T$ is \kbd{NULL} and \kbd{Rg\_to\_FpXQ} otherwise. \fun{GEN}{RgX_to_FpXQX}{GEN z, GEN T, GEN p}, \kbd{z} a \typ{POL}, returns the \kbd{FpXQ} obtained by applying \kbd{Rg\_to\_FpXQ} coefficientwise. \fun{GEN}{RgX_to_FqX}{GEN z, GEN T, GEN p}: let \kbd{z} be a \typ{POL}; returns the \kbd{FqX} obtained by applying \kbd{Rg\_to\_Fq} coefficientwise. \fun{GEN}{Fq_to_FpXQ}{GEN z, GEN T, GEN p /*unused*/} if $z$ is a \typ{INT}, convert it to a constant polynomial in the variable of $T$, otherwise return $z$ (shallow function). \fun{GEN}{Fq_red}{GEN x, GEN T, GEN p}, \kbd{x} a \kbd{ZX} or \typ{INT}, reduce it to an \kbd{Fq} ($\kbd{T} = \kbd{NULL}$ is allowed iff \kbd{x} is a \typ{INT}). \fun{GEN}{FqX_red}{GEN x, GEN T, GEN p}, \kbd{x} a \typ{POL} whose coefficients are \kbd{ZX}s or \typ{INT}s, reduce them to \kbd{Fq}s. (If $\kbd{T} = \kbd{NULL}$, as \kbd{FpXX\_red(x, p)}.) \fun{GEN}{FqV_red}{GEN x, GEN T, GEN p}, \kbd{x} a vector of \kbd{ZX}s or \typ{INT}s, reduce them to \kbd{Fq}s. (If $\kbd{T} = \kbd{NULL}$, only reduce components mod \kbd{p} to \kbd{FpX}s or \kbd{Fp}s.) \fun{GEN}{FpXQ_red}{GEN x, GEN T,GEN p} \kbd{x} a \typ{POL} whose coefficients are \typ{INT}s, reduce them to \kbd{FpXQ}s. \subsec{\kbd{FpXQ}} \fun{GEN}{FpXQ_add}{GEN x, GEN y, GEN T,GEN p} \fun{GEN}{FpXQ_sub}{GEN x, GEN y, GEN T,GEN p} \fun{GEN}{FpXQ_mul}{GEN x, GEN y, GEN T,GEN p} \fun{GEN}{FpXQ_sqr}{GEN x, GEN T, GEN p} \fun{GEN}{FpXQ_div}{GEN x, GEN y, GEN T,GEN p} \fun{GEN}{FpXQ_inv}{GEN x, GEN T, GEN p} computes the inverse of \kbd{x} \fun{GEN}{FpXQ_invsafe}{GEN x,GEN T,GEN p}, as \kbd{FpXQ\_inv}, returning \kbd{NULL} if \kbd{x} is not invertible. \fun{GEN}{FpXQ_pow}{GEN x, GEN n, GEN T, GEN p} computes $\kbd{x}^\kbd{n}$. \fun{GEN}{FpXQ_powu}{GEN x, ulong n, GEN T, GEN p} computes $\kbd{x}^\kbd{n}$ for small $n$. In the following three functions the integer parameter \kbd{ord} can be given either as a positive \typ{INT} $N$, or as its factorization matrix $\var{faN}$, or as a pair $[N,\var{faN}]$. The parameter may be omitted by setting it to \kbd{NULL} (the value is then $p^d-1$, $d = \deg T$). \fun{GEN}{FpXQ_log}{GEN a, GEN g, GEN ord, GEN T, GEN p} Let \kbd{g} be of order \kbd{ord} in the finite field $\F_p[X]/(T)$, return $e$ such that $a^e=g$. If $e$ does not exists, the result is undefined. Assumes that \kbd{T} is irreducible mod \kbd{p}. \fun{GEN}{Fp_FpXQ_log}{GEN a, GEN g, GEN ord, GEN T, GEN p} As \kbd{FpXQ\_log}, \kbd{a} being a \kbd{Fp}. \fun{GEN}{FpXQ_order}{GEN a, GEN ord, GEN T, GEN p} returns the order of the \kbd{FpXQ} \kbd{a}. Assume that \kbd{ord} is a multiple of the order of \kbd{a}. Assume that \kbd{T} is irreducible mod \kbd{p}. \fun{int}{FpXQ_issquare}{GEN x, GEN T, GEN p} returns $1$ if $x$ is a square and $0$ otherwise. Assumes that \kbd{T} is irreducible mod \kbd{p}. \fun{GEN}{FpXQ_sqrt}{GEN x, GEN T, GEN p} returns a square root of \kbd{x}. Return \kbd{NULL} if \kbd{x} is not a square. \fun{GEN}{FpXQ_sqrtn}{GEN x, GEN n, GEN T, GEN p, GEN *zn} Let $T$be irreducible mod $p$ and $q = p^{\deg T}$; returns \kbd{NULL} if $a$ is not an $n$-th power residue mod $p$. Otherwise, returns an $n$-th root of $a$; if \kbd{zn} is non-\kbd{NULL} set it to a primitive $m$-th root of $1$ in $\F_q$, $m = \gcd(q-1,n)$ allowing to compute all $m$ solutions in $\F_q$ of the equation $x^n = a$. \subsec{\kbd{Fq}} \fun{GEN}{Fq_add}{GEN x, GEN y, GEN T/*unused*/, GEN p} \fun{GEN}{Fq_sub}{GEN x, GEN y, GEN T/*unused*/, GEN p} \fun{GEN}{Fq_mul}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{Fq_Fp_mul}{GEN x, GEN y, GEN T, GEN p} multiplies the \kbd{Fq} $x$ by the \typ{INT} $y$. \fun{GEN}{Fq_mulu}{GEN x, ulong y, GEN T, GEN p} multiplies the \kbd{Fq} $x$ by the scalar $y$. \fun{GEN}{Fq_halve}{GEN x, GEN T, GEN p} returns $z$ such that $2\*z = x$ assuming such $z$ exists. \fun{GEN}{Fq_sqr}{GEN x, GEN T, GEN p} \fun{GEN}{Fq_neg}{GEN x, GEN T, GEN p} \fun{GEN}{Fq_neg_inv}{GEN x, GEN T, GEN p} computes $-\kbd{x}^{-1}$ \fun{GEN}{Fq_inv}{GEN x, GEN pol, GEN p} computes $\kbd{x}^{-1}$, raising an error if \kbd{x} is not invertible. \fun{GEN}{Fq_invsafe}{GEN x, GEN pol, GEN p} as \kbd{Fq\_inv}, but returns \kbd{NULL} if \kbd{x} is not invertible. \fun{GEN}{Fq_div}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FqV_inv}{GEN x, GEN T, GEN p} $x$ being a vector of \kbd{Fq}s, return the vector of inverses of the $x[i]$. The routine uses Montgomery's trick, and involves a single inversion, plus $3(N-1)$ multiplications for $N$ entries. The routine is not stack-clean: $2N$ \kbd{FpXQ} are left on stack, besides the $N$ in the result. \fun{GEN}{Fq_pow}{GEN x, GEN n, GEN pol, GEN p} returns $\kbd{x}^\kbd{n}$. \fun{GEN}{Fq_powu}{GEN x, ulong n, GEN pol, GEN p} returns $\kbd{x}^\kbd{n}$ for small $n$. \fun{GEN}{Fq_log}{GEN a, GEN g, GEN ord, GEN T, GEN p} as \tet{Fp_log} or \tet{FpXQ_log}. \fun{int}{Fq_issquare}{GEN x, GEN T, GEN p} returns $1$ if $x$ is a square and $0$ otherwise. Assumes that \kbd{T} is irreducible mod \kbd{p} and that $p$ is prime; $T = \kbd{NULL}$ is forbidden unless $x$ is an \kbd{Fp}. \fun{long}{Fq_ispower}{GEN x, GEN n, GEN T, GEN p} returns $1$ if $x$ is a $n$-th power and $0$ otherwise. Assumes that \kbd{T} is irreducible mod \kbd{p} and that $p$ is prime; $T = \kbd{NULL}$ is forbidden unless $x$ is an \kbd{Fp}. \fun{GEN}{Fq_sqrt}{GEN x, GEN T, GEN p} returns a square root of \kbd{x}. Return \kbd{NULL} if \kbd{x} is not a square. \fun{GEN}{Fq_sqrtn}{GEN a, GEN n, GEN T, GEN p, GEN *zn} as \tet{FpXQ_sqrtn}. \fun{GEN}{FpXQ_charpoly}{GEN x, GEN T, GEN p} returns the characteristic polynomial of \kbd{x} \fun{GEN}{FpXQ_minpoly}{GEN x, GEN T, GEN p} returns the minimal polynomial of \kbd{x} \fun{GEN}{FpXQ_norm}{GEN x, GEN T, GEN p} returns the norm of \kbd{x} \fun{GEN}{FpXQ_trace}{GEN x, GEN T, GEN p} returns the trace of \kbd{x} \fun{GEN}{FpXQ_conjvec}{GEN x, GEN T, GEN p} returns the vector of conjugates $[x,x^p,x^{p^2},\ldots,x^{p^{n-1}}]$ where $n$ is the degree of $T$. \fun{GEN}{gener_FpXQ}{GEN T, GEN p, GEN *po} returns a primitive root modulo $(T,p)$. $T$ is an \kbd{FpX} assumed to be irreducible modulo the prime $p$. If \kbd{po} is not \kbd{NULL} it is set to $[o,\var{fa}]$, where $o$ is the order of the multiplicative group of the finite field, and \var{fa} is its factorization. \fun{GEN}{gener_FpXQ_local}{GEN T, GEN p, GEN L}, \kbd{L} being a vector of primes dividing $p^{\deg T} - 1$, returns an element of $G:=\F_p[x]/(T)$ which is a generator of the $\ell$-Sylow of $G$ for every $\ell$ in \kbd{L}. It is not necessary, and in fact slightly inefficient, to include $\ell=2$, since 2 is treated separately in any case, i.e. the generator obtained is never a square if $p$ is odd. \fun{GEN}{gener_Fq_local}{GEN T, GEN p, GEN L} as \kbd{pgener\_Fp\_local(p, L)} if $T$ is \kbd{NULL}, or \kbd{gener\_FpXQ\_local} (otherwise). \fun{GEN}{FpXQ_powers}{GEN x, long n, GEN T, GEN p} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as a \typ{VEC} of \kbd{FpXQ}s. \fun{GEN}{FpXQ_matrix_pow}{GEN x, long m, long n, GEN T, GEN p}, as \kbd{FpXQ\_powers}$(x, n-1, T, p)$, but returns the powers as a an $m\times n$ matrix. Usually, we have $m = n = \deg T$. \fun{GEN}{FpXQ_autpow}{GEN a, ulong n, GEN T, GEN p} computes $\sigma^n(X)$ assuming $a=\sigma(X)$ where $\sigma$ is an automorphism of the algebra $\F_p[X]/T(X)$. \fun{GEN}{FpXQ_autsum}{GEN a, ulong n, GEN T, GEN p} $a$ being a two-component vector, $\sigma$ being the automorphism defined by $\sigma(X)=a[1]\pmod{T(X)}$, returns the vector $[\sigma^n(X),b\sigma(b)\ldots\sigma^{n-1}(b)]$ where $b=a[2]$. \fun{GEN}{FpXQ_auttrace}{GEN a, ulong n, GEN T, GEN p} $a$ being a two-component vector, $\sigma$ being the automorphism defined by $\sigma(X)=a[1]\pmod{T(X)}$, returns the vector $[\sigma^n(X),b+\sigma(b)+\ldots+\sigma^{n-1}(b)]$ where $b=a[2]$. \fun{GEN}{FpXQ_autpowers}{GEN S, long n, GEN T, GEN p} returns $[x,S(x),S(S(x)),\dots,S^{(n)}(x)]$ as a \typ{VEC} of \kbd{FpXQ}s. \fun{GEN}{FpXQM_autsum}{GEN a, long n, GEN T, GEN p} $\sigma$ being the automorphism defined by $\sigma(X)=a[1]\pmod{T(X)}$, returns the vector $[\sigma^n(X),b\sigma(b)\ldots\sigma^{n-1}(b)]$ where $b=a[2]$ is a square matrix. \fun{GEN}{FpX_FpXQ_eval}{GEN f, GEN x, GEN T, GEN p} returns $\kbd{f}(\kbd{x})$. \fun{GEN}{FpX_FpXQV_eval}{GEN f, GEN V, GEN T, GEN p} returns $\kbd{f}(\kbd{x})$, assuming that \kbd{V} was computed by $\kbd{FpXQ\_powers}(\kbd{x}, n, \kbd{T}, \kbd{p})$. \fun{GEN}{FpXC_FpXQV_eval}{GEN C, GEN V,GEN T,GEN p} applies \kbd{FpX\_FpXQV\_eval} to all elements of the vector $C$ and returns a \typ{COL}. \fun{GEN}{FpXM_FpXQV_eval}{GEN M, GEN V,GEN T,GEN p} applies \kbd{FpX\_FpXQV\_eval} to all elements of the matrix $M$. \subsec{\kbd{FpXn}} Let \kbd{p} a \typ{INT} and \kbd{T} an \kbd{FpX} for \kbd{p}, both to be given in the function arguments; an \kbd{FpXn} object is an \kbd{FpX} whose degree is strictly less than \kbd{n}. They represent a class in $(\Z/\kbd{p}\Z)[X] / (X^n)$, in which all operations below take place. They can be seen as truncated power series. \fun{GEN}{FpXn_mul}{GEN x, GEN y, long n, GEN p} return $x\*y\pmod{X^n}$. \fun{GEN}{FpXn_sqr}{GEN x, long n, GEN p} return $x^2\pmod{X^n}$. \fun{GEN}{FpXn_inv}{GEN x, long n, GEN p} return $1/x\pmod{X^n}$. \fun{GEN}{FpXn_exp}{GEN x, long n, GEN p} return $\exp(x)$ as a composition of formal power series. It is required that the valuation of $x$ is positive and that $p>n$. \subsec{\kbd{FpXC}, \kbd{FpXM}} \fun{GEN}{FpXC_center}{GEN C, GEN p, GEN pov2} \fun{GEN}{FpXM_center}{GEN M, GEN p, GEN pov2} \subsec{\kbd{FpXX}, \kbd{FpXY}} Contrary to what the name implies, an \kbd{FpXX} is a \typ{POL} whose coefficients are either \typ{INT}s or \kbd{FpX}s. This reduces memory overhead at the expense of consistency. The prefix \kbd{FpXY} is an alias for \kbd{FpXX} when variables matters. \fun{GEN}{FpXX_red}{GEN z, GEN p}, \kbd{z} a \typ{POL} whose coefficients are either \kbd{ZX}s or \typ{INT}s. Returns the \typ{POL} equal to \kbd{z} with all components reduced modulo \kbd{p}. \fun{GEN}{FpXX_renormalize}{GEN x, long l}, as \kbd{normalizepol}, where $\kbd{l} = \kbd{lg(x)}$, in place. \fun{GEN}{FpXX_add}{GEN x, GEN y, GEN p} adds \kbd{x} and \kbd{y}. \fun{GEN}{FpXX_sub}{GEN x, GEN y, GEN p} returns $\kbd{x}-\kbd{y}$. \fun{GEN}{FpXX_neg}{GEN x, GEN p} returns $-\kbd{x}$. \fun{GEN}{FpXX_Fp_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{FpXX}~\kbd{x} by the \kbd{Fp}~\kbd{y}. \fun{GEN}{FpXX_FpX_mul}{GEN x, GEN y, GEN p} multiplies the coefficients of the \kbd{FpXX}~\kbd{x} by the \kbd{FpX}~\kbd{y}. \fun{GEN}{FpXX_mulu}{GEN x, GEN y, GEN p} multiplies the \kbd{FpXX}~\kbd{x} by the scalar \kbd{y}. \fun{GEN}{FpXX_halve}{GEN x, GEN p} returns $z$ such that $2\*z = x$ assuming such $z$ exists. \fun{GEN}{FpXX_deriv}{GEN P, GEN p} differentiates \kbd{P} with respect to the main variable. \fun{GEN}{FpXX_integ}{GEN P, GEN p} returns the primitive of \kbd{P} with respect to the main variable whose constant term is $0$. \fun{GEN}{FpXY_eval}{GEN Q, GEN y, GEN x, GEN p} $Q$ being an \kbd{FpXY}, i.e.~a \typ{POL} with \kbd{Fp} or \kbd{FpX} coefficients representing an element of $\F_p[X][Y]$. Returns the \kbd{Fp} $Q(x,y)$. \fun{GEN}{FpXY_evalx}{GEN Q, GEN x, GEN p} $Q$ being an \kbd{FpXY}, returns the \kbd{FpX} $Q(x,Y)$, where $Y$ is the main variable of $Q$. \fun{GEN}{FpXY_evaly}{GEN Q, GEN y, GEN p, long vx} $Q$ an \kbd{FpXY}, returns the \kbd{FpX} $Q(X,y)$, where $X$ is the second variable of $Q$, and \kbd{vx} is the variable number of $X$. \fun{GEN}{FpXY_Fq_evaly}{GEN Q, GEN y, GEN T, GEN p, long vx} $Q$ an \kbd{FpXY} and $y$ being an \kbd{Fq}, returns the \kbd{FqX} $Q(X,y)$, where $X$ is the second variable of $Q$, and \kbd{vx} is the variable number of $X$. \fun{GEN}{FpXY_FpXQ_evalx}{GEN Q, GEN x, ulong p} $Q$ an \kbd{FpXY} and $x$ being an \kbd{FpXQ}, returns the \kbd{FpXQX} $Q(x,Y)$, where $Y$ is the first variable of $Q$. \fun{GEN}{FpXY_FpXQV_evalx}{GEN Q, GEN V, ulong p} $Q$ an \kbd{FpXY} and $x$ being an \kbd{FpXQ}, returns the \kbd{FpXQX} $Q(x,Y)$, where $Y$ is the first variable of $Q$, assuming that \kbd{V} was computed by $\kbd{FpXQ\_powers}(\kbd{x}, n, \kbd{T}, \kbd{p})$. \fun{GEN}{FpXYQQ_pow}{GEN x, GEN n, GEN S, GEN T, GEN p}, \kbd{x} being a \kbd{FpXY}, \kbd{T} being a \kbd{FpX} and \kbd{S} being a \kbd{FpY}, return $x^n \pmod{S,T,p}$. \subsec{\kbd{FpXQX}, \kbd{FqX}} Contrary to what the name implies, an \kbd{FpXQX} is a \typ{POL} whose coefficients are \kbd{Fq}s. So the only difference between \kbd{FqX} and \kbd{FpXQX} routines is that $\kbd{T} = \kbd{NULL}$ is not allowed in the latter. (It was thought more useful to allow \typ{INT} components than to enforce strict consistency, which would not imply any efficiency gain.) \subsubsec{Basic operations} \fun{GEN}{FqX_add}{GEN x,GEN y,GEN T,GEN p} \fun{GEN}{FqX_Fq_add}{GEN x, GEN y, GEN T, GEN p} adds the \kbd{Fq}~\kbd{y} to the \kbd{FqX}~\kbd{x}. \fun{GEN}{FqX_Fq_sub}{GEN x, GEN y, GEN T, GEN p} substracts the \kbd{Fq}~\kbd{y} to the \kbd{FqX}~\kbd{x}. \fun{GEN}{FqX_neg}{GEN x,GEN T,GEN p} \fun{GEN}{FqX_sub}{GEN x,GEN y,GEN T,GEN p} \fun{GEN}{FqX_mul}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FqX_Fq_mul}{GEN x, GEN y, GEN T, GEN p} multiplies the \kbd{FqX}~\kbd{x} by the \kbd{Fq}~\kbd{y}. \fun{GEN}{FqX_mulu}{GEN x, ulong y, GEN T, GEN p} multiplies the \kbd{FqX}~\kbd{x} by the scalar~\kbd{y}. \fun{GEN}{FqX_halve}{GEN x, GEN T, GEN p} returns $z$ such that $2\*z = x$ assuming such $z$ exists. \fun{GEN}{FqX_Fp_mul}{GEN x, GEN y, GEN T, GEN p} multiplies the \kbd{FqX}~\kbd{x} by the \typ{INT}~\kbd{y}. \fun{GEN}{FqX_Fq_mul_to_monic}{GEN x, GEN y, GEN T, GEN p} returns $x\*y$ assuming the result is monic of the same degree as $x$ (in particular $y\neq 0$). \fun{GEN}{FpXQX_normalize}{GEN z, GEN T, GEN p} \fun{GEN}{FqX_normalize}{GEN z, GEN T, GEN p} divides the \kbd{FqX}~\kbd{z} by its leading term. The leading coefficient becomes $1$ as a \typ{INT}. \fun{GEN}{FqX_sqr}{GEN x, GEN T, GEN p} \fun{GEN}{FqX_powu}{GEN x, ulong n, GEN T, GEN p} \fun{GEN}{FqX_divrem}{GEN x, GEN y, GEN T, GEN p, GEN *z} \fun{GEN}{FqX_div}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FqX_div_by_X_x}{GEN a, GEN x, GEN T, GEN p, GEN *r} \fun{GEN}{FqX_rem}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FqX_deriv}{GEN x, GEN T, GEN p} returns the derivative of \kbd{x}. (This function is suitable for \kbd{gerepilupto} but not memory-clean.) \fun{GEN}{FqX_integ}{GEN x, GEN T, GEN p} returns the primitive of \kbd{x}. whose constant term is $0$. \fun{GEN}{FqX_translate}{GEN P, GEN c, GEN T, GEN p} let $c$ be an \kbd{Fq} defined modulo $(p, T)$, and let $P$ be an \kbd{FqX}; returns the translated \kbd{FqX} of $P(X+c)$. \fun{GEN}{FqX_gcd}{GEN P, GEN Q, GEN T, GEN p} returns a (not necessarily monic) greatest common divisor of $x$ and $y$. \fun{GEN}{FqX_extgcd}{GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv} returns $d = \text{GCD}(\kbd{x},\kbd{y})$ (not necessarily monic), and sets \kbd{*u}, \kbd{*v} to the Bezout coefficients such that $\kbd{*ux} + \kbd{*vy} = d$. \fun{GEN}{FqX_halfgcd}{GEN x, GEN y, GEN T, GEN p} returns a two-by-two \kbd{FqXM} $M$ with determinant $\pm 1$ such that the image $(a,b)$ of $(x,y)$ by $M$ has the property that $\deg a \geq {\deg x \over 2} > \deg b$. \fun{GEN}{FqX_eval}{GEN x, GEN y, GEN T, GEN p} evaluates the \kbd{FqX}~\kbd{x} at the \kbd{Fq}~\kbd{y}. The result is an~\kbd{Fq}. \fun{GEN}{FqXY_eval}{GEN Q, GEN y, GEN x, GEN T, GEN p} $Q$ an \kbd{FqXY}, i.e.~a \typ{POL} with \kbd{Fq} or \kbd{FqX} coefficients representing an element of $\F_q[X][Y]$. Returns the \kbd{Fq} $Q(x,y)$. \fun{GEN}{FqXY_evalx}{GEN Q, GEN x, GEN T, GEN p} $Q$ being an \kbd{FqXY}, returns the \kbd{FqX} $Q(x,Y)$, where $Y$ is the main variable of $Q$. \fun{GEN}{random_FpXQX}{long d, long v, GEN T, GEN p} returns a random \kbd{FpXQX} in variable \kbd{v}, of degree less than~\kbd{d}. \fun{GEN}{FpXQX_renormalize}{GEN x, long lx} \fun{GEN}{FpXQX_red}{GEN z, GEN T, GEN p} \kbd{z} a \typ{POL} whose coefficients are \kbd{ZX}s or \typ{INT}s, reduce them to \kbd{FpXQ}s. \fun{GEN}{FpXQX_to_mod}{GEN P, GEN T, GEN p} $P$ being a \kbd{FpXQX}, converts each coefficient to a \typ{POLMOD} with \typ{INTMOD} coefficients. \fun{GEN}{FqX_to_mod}{GEN P, GEN T, GEN p} same but allow $\kbd{T} = \kbd{NULL}$. \fun{GEN}{FpXQX_mul}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{Kronecker_to_FpXQX}{GEN z, GEN T, GEN p}. Let $n = \deg T$ and let $P(X,Y)\in \Z[X,Y]$ lift a polynomial in $K[Y]$, where $K := \F_p[X]/(T)$ and $\deg_X P < 2n-1$ --- such as would result from multiplying minimal degree lifts of two polynomials in $K[Y]$. Let $z = P(t,t^{2*n-1})$ be a Kronecker form of $P$, this function returns $Q\in \Z[X,t]$ such that $Q$ is congruent to $P(X,t)$ mod $(p, T(X))$, $\deg_X Q < n$, and all coefficients are in $[0,p[$. Not stack-clean. Note that $t$ need not be the same variable as $Y$! \fun{GEN}{FpXQX_FpXQ_mul}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FpXQX_sqr}{GEN x, GEN T, GEN p} \fun{GEN}{FpXQX_divrem}{GEN x, GEN y, GEN T, GEN p, GEN *pr} \fun{GEN}{FpXQX_div}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FpXQX_div_by_X_x}{GEN a, GEN x, GEN T, GEN p, GEN *r} \fun{GEN}{FpXQX_rem}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FpXQX_powu}{GEN x, ulong n, GEN T, GEN p} returns $x^n$. \fun{GEN}{FpXQX_digits}{GEN x, GEN B, GEN T, GEN p} \fun{GEN}{FpXQX_dotproduct}{GEN x, GEN y, GEN T, GEN p} returns the scalar product of the coefficients of $x$ and $y$. \fun{GEN}{FpXQXV_FpXQX_fromdigits}{GEN v, GEN B, GEN T, GEN p} \fun{GEN}{FpXQX_invBarrett}{GEN y, GEN T, GEN p} returns the Barrett inverse of the \kbd{FpXQX} $y$, namely a lift of $1/\kbd{polrecip}(y)+O(x^{\deg(y)-1})$. \fun{GEN}{FpXQXV_prod}{GEN V, GEN T, GEN p}, \kbd{V} being a vector of \kbd{FpXQX}, returns their product. \fun{GEN}{FpXQX_gcd}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FpXQX_extgcd}{GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv} \fun{GEN}{FpXQX_halfgcd}{GEN x, GEN y, GEN T, GEN p} \fun{GEN}{FpXQX_FpXQXQ_eval}{GEN f,GEN x,GEN S, GEN T,GEN p} returns $\kbd{f}(\kbd{x})$. \subsec{\kbd{FpXQXn}, \kbd{FqXn}} A \kbd{FpXQXn} is a \typ{FpXQX} which represents an element of the ring $(Fp[X]/T(X))[Y]/(Y^n)$, where $T$ is a \kbd{FpX}. \fun{GEN}{FpXQXn_sqr}{GEN x, long n, GEN T, GEN p} \fun{GEN}{FqXn_sqr}{GEN x, long n, GEN T, GEN p} \fun{GEN}{FpXQXn_mul}{GEN x, GEN y, long n, GEN T, GEN p} \fun{GEN}{FqXn_mul}{GEN x, GEN y, long n, GEN T, GEN p} \fun{GEN}{FpXQXn_inv}{GEN x, long n, GEN T, GEN p} \fun{GEN}{FqXn_inv}{GEN x, long n, GEN T, GEN p} \fun{GEN}{FpXQXn_exp}{GEN x, long n, GEN T, GEN p} return $\exp(x)$ as a composition of formal power series. It is required that the valuation of $x$ is positive and that $p>n$. \fun{GEN}{FqXn_exp}{GEN x, long n, GEN T, GEN p} \subsec{\kbd{FpXQXQ}, \kbd{FqXQ}} A \kbd{FpXQXQ} is a \typ{FpXQX} which represents an element of the ring $(Fp[X]/T(X))[Y]/S(X,Y)$, where $T$ is a \kbd{FpX} and $S$ a \kbd{FpXQX} modulo $T$. A \kbd{FqXQ} is identical except that $T$ is allowed to be \kbd{NULL} in which case $S$ must be a \kbd{FpX}. \subsubsec{Preconditioned reduction} For faster reduction, the modulus \kbd{S} can be replaced by an extended modulus, which is an \kbd{FpXQXT}, in all \kbd{FpXQXQ}- and \kbd{FqXQ}-classes functions, and in \kbd{FpXQX\_rem} and \kbd{FpXQX\_divrem}. \fun{GEN}{FpXQX_get_red}{GEN S, GEN T, GEN p} returns the extended modulus \kbd{eS}. \fun{GEN}{FqX_get_red}{GEN S, GEN T, GEN p} identical, but allow $T$ to be \kbd{NULL}, in which case it returns \kbd{FpX\_get\_red(S,p)}. To write code that works both with plain and extended moduli, the following accessors are defined: \fun{GEN}{get_FpXQX_mod}{GEN eS} returns the underlying modulus \kbd{S}. \fun{GEN}{get_FpXQX_var}{GEN eS} returns the variable number of the modulus. \fun{GEN}{get_FpXQX_degree}{GEN eS} returns the degree of the modulus. Furthermore, \kbd{ZXXT\_to\_FlxXT} allows to convert an extended modulus for a \kbd{FpXQX} to an extended modulus for the corresponding \kbd{FlxqX}. \subsubsec{basic operations} \fun{GEN}{FpXQX_FpXQXQV_eval}{GEN f,GEN V,GEN S,GEN T,GEN p} returns $\kbd{f}(\kbd{x})$, assuming that \kbd{V} was computed by $\kbd{FpXQXQ\_powers}(\kbd{x}, n, \kbd{S}, \kbd{T}, \kbd{p})$. \fun{GEN}{FpXQXQ_div}{GEN x, GEN y, GEN S, GEN T, GEN p}, \kbd{x}, \kbd{y} and \kbd{S} being \kbd{FpXQX}s, returns $\kbd{x}*\kbd{y}^{-1}$ modulo \kbd{S}. \fun{GEN}{FpXQXQ_inv}{GEN x, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FpXQX}s, returns $\kbd{x}^{-1}$ modulo \kbd{S}. \fun{GEN}{FpXQXQ_invsafe}{GEN x, GEN S, GEN T,GEN p}, as \kbd{FpXQXQ\_inv}, returning \kbd{NULL} if \kbd{x} is not invertible. \fun{GEN}{FpXQXQ_mul}{GEN x, GEN y, GEN S, GEN T, GEN p}, \kbd{x}, \kbd{y} and \kbd{S} being \kbd{FpXQX}s, returns $\kbd{x}\*\kbd{y}$ modulo \kbd{S}. \fun{GEN}{FpXQXQ_sqr}{GEN x, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FpXQX}s, returns $\kbd{x}^2$ modulo \kbd{S}. \fun{GEN}{FpXQXQ_pow}{GEN x, GEN n, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FpXQX}s, returns $\kbd{x}^\kbd{n}$ modulo \kbd{S}. \fun{GEN}{FpXQXQ_powers}{GEN x, long n, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FpXQX}s, returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as a \typ{VEC} of \kbd{FpXQXQ}s. \fun{GEN}{FpXQXQ_halfFrobenius}{GEN A, GEN S, GEN T, GEN p} returns $A(X)^{(q-1)/2}\pmod{S(X)}$ over the finite field $\F_q$ defined by $T$ and $p$, thus $q=p^n$ where $n$ is the degree of $T$. \fun{GEN}{FpXQXQ_minpoly}{GEN x, GEN S, GEN T, GEN p}, as \kbd{FpXQ\_minpoly} \fun{GEN}{FpXQXQ_matrix_pow}{GEN x, long m, long n, GEN S, GEN T, GEN p} returns the same powers of \kbd{x} as \kbd{FpXQXQ\_powers}$(x, n-1,S, T, p)$, but as an $m\times n$ matrix. \fun{GEN}{FpXQXQ_autpow}{GEN a, long n, GEN S, GEN T, GEN p} $\sigma$ being the automorphism defined by $\sigma(X)=a[1]\pmod{T(X)}$, $\sigma(Y)=a[2]\pmod{S(X,Y),T(X)}$, returns $[\sigma^n(X),\sigma^n(Y)]$. \fun{GEN}{FpXQXQ_autsum}{GEN a, long n, GEN S, GEN T, GEN p} $\sigma$ being the automorphism defined by $\sigma(X)=a[1]\pmod{T(X)}$, $\sigma(Y)=a[2]\pmod{S(X,Y),T(X)}$, returns the vector $[\sigma^n(X),\sigma^n(Y),b\sigma(b)\ldots\sigma^{n-1}(b)]$ where $b=a[3]$. \fun{GEN}{FpXQXQ_auttrace}{GEN a, long n, GEN S, GEN T, GEN p} $\sigma$ being the automorphism defined by $\sigma(X)=X\pmod{T(X)}$, $\sigma(Y)=a[1]\pmod{S(X,Y),T(X)}$, returns the vector $[\sigma^n(X),\sigma^n(Y),b+\sigma(b)+\ldots+\sigma^{n-1}(b)]$ where $b=a[2]$. % FqXQ \fun{GEN}{FqXQ_add}{GEN x, GEN y, GEN S, GEN T, GEN p}, \kbd{x}, \kbd{y} and \kbd{S} being \kbd{FqX}s, returns $\kbd{x} + \kbd{y}$ modulo \kbd{S}. \fun{GEN}{FqXQ_sub}{GEN x, GEN y, GEN S, GEN T, GEN p}, \kbd{x}, \kbd{y} and \kbd{S} being \kbd{FqX}s, returns $\kbd{x} - \kbd{y}$ modulo \kbd{S}. \fun{GEN}{FqXQ_mul}{GEN x, GEN y, GEN S, GEN T, GEN p}, \kbd{x}, \kbd{y} and \kbd{S} being \kbd{FqX}s, returns $\kbd{x}\*\kbd{y}$ modulo \kbd{S}. \fun{GEN}{FqXQ_div}{GEN x, GEN y, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FqX}s, returns $\kbd{x}/\kbd{y}$ modulo \kbd{S}. \fun{GEN}{FqXQ_inv}{GEN x, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FqX}s, returns $\kbd{x}^{-1}$ modulo \kbd{S}. \fun{GEN}{FqXQ_invsafe}{GEN x, GEN S, GEN T, GEN p} , as \kbd{FqXQ\_inv}, returning \kbd{NULL} if \kbd{x} is not invertible. \fun{GEN}{FqXQ_sqr}{GEN x, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FqX}s, returns $\kbd{x}^2$ modulo \kbd{S}. \fun{GEN}{FqXQ_pow}{GEN x, GEN n, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FqX}s, returns $\kbd{x}^\kbd{n}$ modulo \kbd{S}. \fun{GEN}{FqXQ_powers}{GEN x, long n, GEN S, GEN T, GEN p}, \kbd{x} and \kbd{S} being \kbd{FqX}s, returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as a \typ{VEC} of \kbd{FqXQ}s. \fun{GEN}{FqXQ_matrix_pow}{GEN x, long m, long n, GEN S, GEN T, GEN p} returns the same powers of \kbd{x} as \kbd{FqXQ\_powers}$(x, n-1,S, T, p)$, but as an $m\times n$ matrix. \fun{GEN}{FqV_roots_to_pol}{GEN V, GEN T, GEN p, long v}, \kbd{V} being a vector of \kbd{Fq}s, returns the monic \kbd{FqX} $\prod_i (\kbd{pol\_x[v]} - \kbd{V[i]})$. \subsubsec{Miscellaneous operations} \fun{GEN}{init_Fq}{GEN p, long n, long v} returns an irreducible polynomial of degree $\kbd{n} > 0$ over $\F_p$, in variable \kbd{v}. \fun{int}{FqX_is_squarefree}{GEN P, GEN T, GEN p} \fun{GEN}{FpXQX_roots}{GEN f, GEN T, GEN p} return the roots of $f$ in $\F_p[X]/(T)$. Assumes \kbd{p} is prime and \kbd{T} irreducible in $\F_p[X]$. \fun{GEN}{FqX_roots}{GEN f, GEN T, GEN p} same but allow $\kbd{T} = \kbd{NULL}$. \fun{GEN}{FpXQX_factor}{GEN f, GEN T, GEN p} same output convention as \kbd{FpX\_factor}. Assumes \kbd{p} is prime and \kbd{T} irreducible in $\F_p[X]$. \fun{GEN}{FqX_factor}{GEN f, GEN T, GEN p} same but allow $\kbd{T} = \kbd{NULL}$. \fun{GEN}{FpXQX_factor_squarefree}{GEN f, GEN T, GEN p} squarefree factorization of $f$ modulo $(T,p)$; same output convention as \kbd{FpX\_factor\_squarefree}. Assumes \kbd{p} is prime and \kbd{T} irreducible in $\F_p[X]$. \fun{GEN}{FqX_factor_squarefree}{GEN f, GEN T, GEN p} same but allow $\kbd{T} = \kbd{NULL}$. \fun{GEN}{FpXQX_ddf}{GEN f, GEN T, GEN p} as \kbd{FpX\_ddf}. \fun{GEN}{FqX_ddf}{GEN f, GEN T, GEN p} same but allow $\kbd{T} = \kbd{NULL}$. \fun{long}{FpXQX_ddf_degree}{GEN f, GEN XP, GEN T, GEN p}, as \kbd{FpX\_ddf\_degree}. \fun{GEN}{FpXQX_degfact}{GEN f, GEN T, GEN p}, as \kbd{FpX\_degfact}. \fun{GEN}{FqX_degfact}{GEN f, GEN T, GEN p} same but allow $\kbd{T} = \kbd{NULL}$. \fun{GEN}{FpXQX_split_part}{GEN f, GEN T, GEN p} returns the largest totally split squarefree factor of $f$. \fun{long}{FpXQX_ispower}{GEN f, ulong k, GEN T, GEN p, GEN *pt} return $1$ if the \kbd{FpXQX} $f$ is a $k$-th power, $0$ otherwise. If \kbd{pt} is not \kbd{NULL}, set it to $g$ such that $g^k = f$. \fun{long}{FqX_ispower}{GEN f, ulong k, GEN T, GEN p, GEN *pt} same but allow $\kbd{T} = \kbd{NULL}$. \fun{GEN}{FpX_factorff}{GEN P, GEN T, GEN p}. Assumes \kbd{p} prime and \kbd{T} irreducible in $\F_p[X]$. Factor the \kbd{FpX} \kbd{P} over the finite field $\F_p[Y]/(T(Y))$. See \kbd{FpX\_factorff\_irred} if \kbd{P} is known to be irreducible of $\F_p$. \fun{GEN}{FpX_rootsff}{GEN P, GEN T, GEN p}. Assumes \kbd{p} prime and \kbd{T} irreducible in $\F_p[X]$. Returns the roots of the \kbd{FpX} \kbd{P} belonging to the finite field $\F_p[Y]/(T(Y))$. \fun{GEN}{FpX_factorff_irred}{GEN P, GEN T, GEN p}. Assumes \kbd{p} prime and \kbd{T} irreducible in $\F_p[X]$. Factors the \emph{irreducible} \kbd{FpX} \kbd{P} over the finite field $\F_p[Y]/(T(Y))$ and returns the vector of irreducible \kbd{FqX}s factors (the exponents, being all equal to $1$, are not included). \fun{GEN}{FpX_ffisom}{GEN P, GEN Q, GEN p}. Assumes \kbd{p} prime, \kbd{P}, \kbd{Q} are \kbd{ZX}s, both irreducible mod \kbd{p}, and $\deg(P) \mid \deg Q$. Outputs a monomorphism between $\F_p[X]/(P)$ and $\F_p[X]/(Q)$, as a polynomial $R$ such that $\kbd{Q} \mid \kbd{P}(R)$ in $\F_p[X]$. If \kbd{P} and \kbd{Q} have the same degree, it is of course an isomorphism. \fun{void}{FpX_ffintersect}{GEN P, GEN Q, long n, GEN p, GEN *SP,GEN *SQ, GEN MA,GEN MB}\hfil\break Assumes \kbd{p} is prime, \kbd{P}, \kbd{Q} are \kbd{ZX}s, both irreducible mod \kbd{p}, and \kbd{n} divides both the degree of \kbd{P} and \kbd{Q}. Compute \kbd{SP} and \kbd{SQ} such that the subfield of $\F_p[X]/(P)$ generated by \kbd{SP} and the subfield of $\F_p[X]/(Q)$ generated by \kbd{SQ} are isomorphic of degree \kbd{n}. The polynomials \kbd{P} and \kbd{Q} do not need to be of the same variable. If \kbd{MA} (resp. \kbd{MB}) is not \kbd{NULL}, it must be the matrix of the Frobenius map in $\F_p[X]/(P)$ (resp.~$\F_p[X]/(Q)$). \fun{GEN}{FpXQ_ffisom_inv}{GEN S, GEN T, GEN p}. Assumes \kbd{p} is prime, \kbd{T} a \kbd{ZX}, which is irreducible modulo \kbd{p}, \kbd{S} a \kbd{ZX} representing an automorphism of $\F_q := \F_p[X]/(\kbd{T})$. ($\kbd{S}(X)$ is the image of $X$ by the automorphism.) Returns the inverse automorphism of \kbd{S}, in the same format, i.e.~an \kbd{FpX}~$H$ such that $H(\kbd{S}) \equiv X$ modulo $(\kbd{T}, \kbd{p})$. \fun{long}{FpXQX_nbfact}{GEN S, GEN T, GEN p} returns the number of irreducible factors of the polynomial $S$ over the finite field $\F_q$ defined by $T$ and $p$. \fun{long}{FpXQX_nbfact_Frobenius}{GEN S, GEN Xq, GEN T, GEN p} as \kbd{FpXQX\_nbfact} where \kbd{Xq} is \kbd{FpXQX\_Frobenius(S, T, p)}. \fun{long}{FqX_nbfact}{GEN S, GEN T, GEN p} as above but accept \kbd{T=NULL}. \fun{long}{FpXQX_nbroots}{GEN S, GEN T, GEN p} returns the number of roots of the polynomial $S$ over the finite field $\F_q$ defined by $T$ and $p$. \fun{long}{FqX_nbroots}{GEN S, GEN T, GEN p} as above but accept \kbd{T=NULL}. \fun{GEN}{FpXQX_Frobenius}{GEN S, GEN T, GEN p} returns $X^{q}\pmod{S(X)}$ over the finite field $\F_q$ defined by $T$ and $p$, thus $q=p^n$ where $n$ is the degree of $T$. \subsec{\kbd{Flx}} Let \kbd{p} an understood \kbd{ulong}, assumed to be prime, to be given the function arguments; an \kbd{Fl} is an \kbd{ulong} belonging to $[0,\kbd{p}-1]$, an \kbd{Flx}~\kbd{z} is a \typ{VECSMALL} representing a polynomial with small integer coefficients. Specifically \kbd{z[0]} is the usual codeword, \kbd{z[1] = evalvarn($v$)} for some variable $v$, then the coefficients by increasing degree. An \kbd{FlxX} is a \typ{POL} whose coefficients are \kbd{Flx}s. \noindent In the following, an argument called \kbd{sv} is of the form \kbd{evalvarn}$(v)$ for some variable number~$v$. \subsubsec{Preconditioned reduction} For faster reduction, the modulus \kbd{T} can be replaced by an extended modulus (\kbd{FlxT}) in all \kbd{Flxq}-classes functions, and in \kbd{Flx\_divrem}. \fun{GEN}{Flx_get_red}{GEN T, ulong p} returns the extended modulus \kbd{eT}. To write code that works both with plain and extended moduli, the following accessors are defined: \fun{GEN}{get_Flx_mod}{GEN eT} returns the underlying modulus \kbd{T}. \fun{GEN}{get_Flx_var}{GEN eT} returns the variable number of the modulus. \fun{GEN}{get_Flx_degree}{GEN eT} returns the degree of the modulus. Furthermore, \kbd{ZXT\_to\_FlxT} allows to convert an extended modulus for a \kbd{FpX} to an extended modulus for the corresponding \kbd{Flx}. \subsubsec{Basic operations} \fun{ulong}{Flx_lead}{GEN x} returns the leading coefficient of $x$ as a \kbd{ulong} (return $0$ for the zero polynomial). \fun{ulong}{Flx_constant}{GEN x} returns the constant coefficient of $x$ as a \kbd{ulong} (return $0$ for the zero polynomial). \fun{GEN}{Flx_red}{GEN z, ulong p} converts from \kbd{zx} with non-negative coefficients to \kbd{Flx} (by reducing them mod \kbd{p}). \fun{int}{Flx_equal1}{GEN x} returns 1 (true) if the \kbd{Flx} $x$ is equal to~1, 0~(false) otherwise. \fun{int}{Flx_equal}{GEN x, GEN y} returns 1 (true) if the \kbd{Flx} $x$ and $y$ are equal, and 0~(false) otherwise. \fun{GEN}{Flx_copy}{GEN x} returns a copy of \kbd{x}. \fun{GEN}{Flx_add}{GEN x, GEN y, ulong p} \fun{GEN}{Flx_Fl_add}{GEN y, ulong x, ulong p} \fun{GEN}{Flx_neg}{GEN x, ulong p} \fun{GEN}{Flx_neg_inplace}{GEN x, ulong p}, same as \kbd{Flx\_neg}, in place (\kbd{x} is destroyed). \fun{GEN}{Flx_sub}{GEN x, GEN y, ulong p} \fun{GEN}{Flx_halve}{GEN x, ulong p} returns $z$ such that $2\*z = x$ modulo $p$ assuming such $z$ exists. \fun{GEN}{Flx_mul}{GEN x, GEN y, ulong p} \fun{GEN}{Flxn_mul}{GEN a, GEN b, long n, ulong p} returns $a b$ modulo $X^n$. \fun{GEN}{Flxn_inv}{GEN a, long n, ulong p} returns $1/a$ modulo $X^n$. \fun{GEN}{Flx_Fl_mul}{GEN y, ulong x, ulong p} \fun{GEN}{Flx_double}{GEN y, ulong p} returns $2\*y$. \fun{GEN}{Flx_triple}{GEN y, ulong p} returns $3\*y$. \fun{GEN}{Flx_mulu}{GEN y, ulong x, ulong p} as \kbd{Flx\_Fl\_mul} but do not assume that $x \deg b$. \fun{GEN}{Flx_extgcd}{GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv} \fun{GEN}{Flx_roots}{GEN f, ulong p} returns the vector of roots of $f$ (without multiplicity, as a \typ{VECSMALL}). Assumes that $p$ is prime. \fun{ulong}{Flx_oneroot}{GEN f, ulong p} returns one root $0 \leq r < p$ of the \kbd{Flx}~\kbd{f} in \kbd{\Z/p\Z}. Return $p$ if no root exists. Assumes that \kbd{p} is prime. \fun{ulong}{Flx_oneroot_split}{GEN f, ulong p} as \kbd{Flx\_oneroot} but assume $f$ is totally split. \fun{long}{Flx_ispower}{GEN f, ulong k, ulong p, GEN *pt} return $1$ if the \kbd{Flx} $f$ is a $k$-th power, $0$ otherwise. If \kbd{pt} is not \kbd{NULL}, set it to $g$ such that $g^k = f$. \fun{GEN}{Flx_factor}{GEN f, ulong p} \fun{GEN}{Flx_ddf}{GEN f, ulong p} \fun{GEN}{Flx_factor_squarefree}{GEN f, ulong p} returns the squarefree factorization of $f$ modulo $p$. This is a vector $[u_1,\dots,u_k]$ of pairwise coprime \kbd{Flx} such that $u_k \neq 1$ and $f = \prod u_i^i$. Shallow function. \fun{GEN}{Flx_mod_Xn1}{GEN T, ulong n, ulong p} return $T$ modulo $(X^n + 1, p)$. Shallow function. \fun{GEN}{Flx_mod_Xnm1}{GEN T, ulong n, ulong p} return $T$ modulo $(X^n - 1, p)$. Shallow function. \fun{GEN}{Flx_degfact}{GEN f, ulong p} as \tet{FpX_degfact}. \fun{GEN}{Flx_factorff_irred}{GEN P, GEN Q, ulong p} as \tet{FpX_factorff_irred}. \fun{GEN}{Flx_rootsff}{GEN P, GEN T, ulong p} as \tet{FpX_rootsff}. \fun{GEN}{Flx_ffisom}{GEN P,GEN Q,ulong l} as \tet{FpX_ffisom}. \subsubsec{Miscellaneous operations} \fun{GEN}{pol0_Flx}{long sv} returns a zero \kbd{Flx} in variable $v$. \fun{GEN}{zero_Flx}{long sv} alias for \kbd{pol0\_Flx} \fun{GEN}{pol1_Flx}{long sv} returns the unit \kbd{Flx} in variable $v$. \fun{GEN}{polx_Flx}{long sv} returns the variable $v$ as degree~1~\kbd{Flx}. \fun{GEN}{monomial_Flx}{ulong a, long d, long sv} returns the \kbd{Flx} $a\*X^d$ in variable $v$. \fun{GEN}{Flx_normalize}{GEN z, ulong p}, as \kbd{FpX\_normalize}. \fun{GEN}{Flx_rescale}{GEN P, ulong h, ulong p} returns $h^{\deg(P)} P(x/h)$, \kbd{P} is a \kbd{Flx} and \kbd{h} is a non-zero integer. \fun{GEN}{random_Flx}{long d, long sv, ulong p} returns a random \kbd{Flx} in variable \kbd{v}, of degree less than~\kbd{d}. \fun{GEN}{Flx_recip}{GEN x}, returns the reciprocal polynomial \fun{ulong}{Flx_resultant}{GEN a, GEN b, ulong p}, returns the resultant of \kbd{a} and \kbd{b} \fun{ulong}{Flx_extresultant}{GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV} given two \kbd{Flx} \kbd{a} and \kbd{b}, returns their resultant and sets Bezout coefficients (if the resultant is 0, the latter are not set). \fun{GEN}{Flx_invBarrett}{GEN T, ulong p}, returns the Barrett inverse $M$ of $T$ defined by $M(x)\*x^n\*T(1/x)\equiv 1\pmod{x^{n-1}}$ where $n$ is the degree of $T$. \fun{GEN}{Flx_renormalize}{GEN x, long l}, as \kbd{FpX\_renormalize}, where $\kbd{l} = \kbd{lg(x)}$, in place. \fun{GEN}{Flx_shift}{GEN T, long n} returns $\kbd{T} * x^n$ if $n\geq 0$, and $\kbd{T} \bs x^{-n}$ otherwise. \fun{long}{Flx_val}{GEN x} returns the valuation of \kbd{x}, i.e. the multiplicity of the $0$ root. \fun{long}{Flx_valrem}{GEN x, GEN *Z} as \kbd{RgX\_valrem}, returns the valuation of \kbd{x}. In particular, if the valuation is $0$, set \kbd{*Z} to $x$, not a copy. \fun{GEN}{Flx_div_by_X_x}{GEN A, ulong a, ulong p, ulong *rem}, returns the Euclidean quotient of the \kbd{Flx}~\kbd{A} by $X - \kbd{a}$, and sets \kbd{rem} to the remainder $ \kbd{A}(\kbd{a})$. \fun{ulong}{Flx_eval}{GEN x, ulong y, ulong p}, as \kbd{FpX\_eval}. \fun{ulong}{Flx_eval_pre}{GEN x, ulong y, ulong p, ulong pi}, as \kbd{Flx\_eval}, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Flx_eval_powers_pre}{GEN P, GEN y, ulong p, ulong pi}. Let $y$ be the \typ{VECSMALL} $(1,a,\dots,a^n)$, where $n$ is the degree of the \kbd{Flx} $P$, return $P(a)$, assuming $pi$ is the pseudo inverse of $p$. \fun{GEN}{Flx_Flv_multieval}{GEN P, GEN v, ulong p} returns the vector $[P(v[1]),\ldots,P(v[n])]$ as a \kbd{Flv}. \fun{ulong}{Flx_dotproduct}{GEN x, GEN y, ulong p} returns the scalar product of the coefficients of $x$ and $y$. \fun{GEN}{Flx_deflate}{GEN P, long d} assuming $P$ is a polynomial of the form $Q(X^d)$, return $Q$. \fun{GEN}{Flx_splitting}{GEN P, long k}, as \tet{RgX_splitting}. \fun{GEN}{Flx_inflate}{GEN P, long d} returns $P(X^d)$. \fun{int}{Flx_is_squarefree}{GEN z, ulong p} \fun{int}{Flx_is_irred}{GEN f, ulong p}, as \kbd{FpX\_is\_irred}. \fun{int}{Flx_is_smooth}{GEN f, long r, ulong p} return $1$ if all irreducible factors of $f$ are of degree at most $r$, $0$ otherwise. \fun{long}{Flx_nbroots}{GEN f, ulong p}, as \kbd{FpX\_nbroots}. \fun{long}{Flx_nbfact}{GEN z, ulong p}, as \kbd{FpX\_nbfact}. \fun{long}{Flx_nbfact_Frobenius}{GEN f, GEN XP, ulong p}, as \kbd{FpX\_nbfact\_Frobenius}. \fun{GEN}{Flx_degfact}{GEN f, ulong p}, as \kbd{FpX\_degfact}. \fun{GEN}{Flx_nbfact_by_degree}{GEN z, long *nb, ulong p} Assume that the \kbd{Flx} $z$ is squarefree mod the prime $p$. Returns a \typ{VECSMALL} $D$ with $\deg z$ entries, such that $D[i]$ is the number of irreducible factors of degree $i$. Set \kbd{nb} to the total number of irreducible factors (the sum of the $D[i]$). \fun{void}{Flx_ffintersect}{GEN P,GEN Q, long n, ulong p, GEN*SP, GEN*SQ, GEN MA,GEN MB},\hfil\break as \kbd{FpX\_ffintersect} \fun{GEN}{Flv_polint}{GEN x, GEN y, ulong p, long sv} as \kbd{FpV\_polint}, returning an \kbd{Flx} in variable $v$. \fun{GEN}{Flv_Flm_polint}{GEN x, GEN V, ulong p, long sv} equivalent (but faster) to applying \kbd{Flv\_polint(x,$\ldots$)} to all the elements of the vector $V$ (thus, returns a \kbd{FlxV}). \fun{GEN}{Flv_invVandermonde}{GEN L, ulong d, ulong p} $L$ being a \kbd{Flv} of length $n$, return the inverse $M$ of the Vandermonde matrix attached to the elements of $L$, multiplied by \kbd{d}. If $A$ is a \kbd{Flv} and $B=M\*A$, then the polynomial $P=\sum_{i=1}^n B[i]\*X^{i-1}$ verifies $P(L[i])=d\*A[i]$ for $1 \leq i \leq n$. \fun{GEN}{Flv_roots_to_pol}{GEN a, ulong p, long sv} as \kbd{FpV\_roots\_to\_pol} returning an \kbd{Flx} in variable $v$. \subsec{\kbd{FlxV}} See \kbd{FpXV} operations. \fun{GEN}{FlxV_Flc_mul}{GEN V, GEN W, ulong p}, as \kbd{FpXV\_FpC\_mul}. \fun{GEN}{FlxV_red}{GEN V, ulong p} reduces each components with \kbd{Flx\_red}. \fun{GEN}{FlxV_prod}{GEN V, ulong p}, \kbd{V} being a vector of \kbd{Flx}, returns their product. \fun{ulong}{FlxC_eval_powers_pre}{GEN x, GEN y, ulong p, ulong pi} apply \kbd{Flx\_eval\_powers\_pre} to all elements of \kbd{x}. \fun{GEN}{FlxC_neg}{GEN x, ulong p} \fun{GEN}{FlxC_sub}{GEN x, GEN y, ulong p} \fun{GEN}{zero_FlxC}{long n, long sv} \subsec{\kbd{FlxM}} See \kbd{FpXM} operations. \fun{ulong}{FlxM_eval_powers_pre}{GEN M, GEN y, ulong p, ulong pi} this function applies \kbd{FlxC\_eval\_powers\_pre} to all entries of \kbd{M}. \fun{GEN}{FlxM_neg}{GEN x, ulong p} \fun{GEN}{FlxM_sub}{GEN x, GEN y, ulong p} \fun{GEN}{zero_FlxM}{long r, long c, long sv} \subsec{\kbd{FlxT}} See \kbd{FpXT} operations. \fun{GEN}{FlxT_red}{GEN V, ulong p} reduces each leaf with \kbd{Flx\_red}. \subsec{\kbd{Flxq}} See \kbd{FpXQ} operations. \fun{GEN}{Flxq_add}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{Flxq_sub}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{Flxq_mul}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{Flxq_sqr}{GEN y, GEN T, ulong p} \fun{GEN}{Flxq_inv}{GEN x, GEN T, ulong p} \fun{GEN}{Flxq_invsafe}{GEN x, GEN T, ulong p} \fun{GEN}{Flxq_div}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{Flxq_pow}{GEN x, GEN n, GEN T, ulong p} \fun{GEN}{Flxq_powu}{GEN x, ulong n, GEN T, ulong p} \fun{GEN}{Flxq_pow_init}{GEN x, GEN n, long k, GEN T, ulong p} \fun{GEN}{Flxq_pow_table}{GEN R, GEN n, GEN T, ulong p} \fun{GEN}{Flxq_powers}{GEN x, long n, GEN T, ulong p} \fun{GEN}{Flxq_matrix_pow}{GEN x, long m, long n, GEN T, ulong p}, see \kbd{FpXQ\_matrix\_pow}. \fun{GEN}{Flxq_autpow}{GEN a, long n, GEN T, ulong p} see \kbd{FpXQ\_autpow}. \fun{GEN}{Flxq_autsum}{GEN a, long n, GEN T, ulong p} see \kbd{FpXQ\_autsum}. \fun{GEN}{Flxq_auttrace}{GEN a, ulong n, GEN T, ulong p} see \kbd{FpXQ\_auttrace}. \fun{GEN}{Flxq_ffisom_inv}{GEN S, GEN T, ulong p}, as \kbd{FpXQ\_ffisom\_inv}. \fun{GEN}{Flx_Flxq_eval}{GEN f, GEN x, GEN T, ulong p} returns $\kbd{f}(\kbd{x})$. \fun{GEN}{Flx_FlxqV_eval}{GEN f, GEN x, GEN T, ulong p}, see \kbd{FpX\_FpXQV\_eval}. \fun{GEN}{FlxqV_roots_to_pol}{GEN V, GEN T, ulong p, long v} as \kbd{FqV\_roots\_to\_pol} returning an \kbd{FlxqX} in variable $v$. \fun{int}{Flxq_issquare}{GEN x, GEN T, ulong p} returns $1$ if $x$ is a square and $0$ otherwise. Assume that \kbd{T} is irreducible mod \kbd{p}. \fun{int}{Flxq_is2npower}{GEN x, long n, GEN T, ulong p} returns $1$ if $x$ is a $2^n$-th power and $0$ otherwise. Assume that \kbd{T} is irreducible mod \kbd{p}. \fun{GEN}{Flxq_order}{GEN a, GEN ord, GEN T, ulong p} as \tet{FpXQ_order}. \fun{GEN}{Flxq_log}{GEN a, GEN g, GEN ord, GEN T, ulong p} as \tet{FpXQ_log} \fun{GEN}{Flxq_sqrtn}{GEN x, GEN n, GEN T, ulong p, GEN *zn} as \tet{FpXQ_sqrtn}. \fun{GEN}{Flxq_sqrt}{GEN x, GEN T, ulong p} returns a square root of \kbd{x}. Return \kbd{NULL} if \kbd{x} is not a square. \fun{GEN}{Flxq_lroot}{GEN a, GEN T, ulong p} returns $x$ such that $x^p = a$. \fun{GEN}{Flxq_lroot_fast}{GEN a, GEN V, GEN T, ulong p} assuming that \kbd{V=Flxq\_powers(s,p-1,T,p)} where $s(x)^p \equiv x\pmod{T(x),p}$, returns $b$ such that $b^p=a$. Only useful if $p$ is less than the degree of $T$. \fun{GEN}{Flxq_charpoly}{GEN x, GEN T, ulong p} returns the characteristic polynomial of \kbd{x} \fun{GEN}{Flxq_minpoly}{GEN x, GEN T, ulong p} returns the minimal polynomial of \kbd{x} \fun{ulong}{Flxq_norm}{GEN x, GEN T, ulong p} returns the norm of \kbd{x} \fun{ulong}{Flxq_trace}{GEN x, GEN T, ulong p} returns the trace of \kbd{x} \fun{GEN}{Flxq_conjvec}{GEN x, GEN T, ulong p} returns the conjugates $[x,x^p,x^{p^2},\ldots,x^{p^{n-1}}]$ where $n$ is the degree of $T$. \fun{GEN}{gener_Flxq}{GEN T, ulong p, GEN *po} returns a primitive root modulo $(T,p)$. $T$ is an \kbd{Flx} assumed to be irreducible modulo the prime $p$. If \kbd{po} is not \kbd{NULL} it is set to $[o,\var{fa}]$, where $o$ is the order of the multiplicative group of the finite field, and \var{fa} is its factorization. \subsec{\kbd{FlxX}} See \kbd{FpXX} operations. \fun{GEN}{pol1_FlxX}{long vX, long sx} returns the unit \kbd{FlxX} as a \typ{POL} in variable \kbd{vX} which only coefficient is \kbd{pol1\_Flx(sx)}. \fun{GEN}{polx_FlxX}{long vX, long sx} returns the variable $X$ as a degree~1~\typ{POL} with \kbd{Flx} coefficients in the variable $x$. \fun{long}{FlxY_degreex}{GEN P} return the degree of $P$ with respect to the secondary variable. \fun{GEN}{FlxX_add}{GEN P, GEN Q, ulong p} \fun{GEN}{FlxX_sub}{GEN P, GEN Q, ulong p} \fun{GEN}{FlxX_Fl_mul}{GEN x, ulong y, ulong p} \fun{GEN}{FlxX_double}{GEN x, ulong p} \fun{GEN}{FlxX_triple}{GEN x, ulong p} \fun{GEN}{FlxX_neg}{GEN x, ulong p} \fun{GEN}{FlxX_Flx_add}{GEN x, GEN y, ulong p} \fun{GEN}{FlxX_Flx_sub}{GEN x, GEN y, ulong p} \fun{GEN}{FlxX_Flx_mul}{GEN x, GEN y, ulong p} \fun{GEN}{FlxY_Flx_div}{GEN x, GEN y, ulong p} divides the coefficients of $x$ by $y$ using \kbd{Flx\_div}. \fun{GEN}{FlxX_deriv}{GEN P, ulong p} returns the derivative of \kbd{P} with respect to the main variable. \fun{GEN}{FlxY_evalx}{GEN P, ulong z, ulong p} $P$ being an \kbd{FlxY}, returns the \kbd{Flx} $P(z,Y)$, where $Y$ is the main variable of $P$. \fun{GEN}{FlxY_Flx_translate}{GEN P, GEN f, ulong p} $P$ being an \kbd{FlxY} and $f$ being an \kbd{Flx}, return $(P(x,Y+f(x))$, where $Y$ is the main variable of $P$. \fun{ulong}{FlxY_evalx_powers_pre}{GEN P, GEN xp, ulong p, ulong pi}, \kbd{xp} being the vector $[1,x,\dots,x^n]$, where $n$ is larger or equal to the degree of $P$ in $X$, return $P(x,Y)$, where $Y$ is the main variable of $Q$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{FlxY_eval_powers_pre}{GEN P, GEN xp, GEN yp, ulong p, ulong pi}, \kbd{xp} being the vector $[1,x,\dots,x^n]$, where $n$ is larger or equal to the degree of $P$ in $X$ and \kbd{yp} being the vector $[1,y,\dots,y^m]$, where $m$ is larger or equal to the degree of $P$ in $Y$ return $P(x,y)$, assuming $pi$ is the pseudo inverse of $p$. \fun{GEN}{FlxY_Flxq_evalx}{GEN x, GEN y, GEN T, ulong p} as \kbd{FpXY\_FpXQ\_evalx}. \fun{GEN}{FlxY_FlxqV_evalx}{GEN x, GEN V, GEN T, ulong p} as \kbd{FpXY\_FpXQV\_evalx}. \fun{GEN}{FlxX_renormalize}{GEN x, long l}, as \kbd{normalizepol}, where $\kbd{l} = \kbd{lg(x)}$, in place. \fun{GEN}{FlxX_resultant}{GEN u, GEN v, ulong p, long sv} Returns $\text{Res}_X(u, v)$, which is an \kbd{Flx}. The coefficients of \kbd{u} and \kbd{v} are assumed to be in the variable $v$. \fun{GEN}{Flx_FlxY_resultant}{GEN a, GEN b, ulong p} Returns $\text{Res}_x(a, b)$, which is an \kbd{Flx} in the main variable of \kbd{b}. \fun{GEN}{FlxX_shift}{GEN a, long n, long sv}, as \kbd{RgX\_shift\_shallow}, where $v$ is the secondary variable. \fun{GEN}{FlxX_swap}{GEN x, long n, long ws}, as \kbd{RgXY\_swap}. \fun{GEN}{FlxYqq_pow}{GEN x, GEN n, GEN S, GEN T, ulong p}, as \kbd{FpXYQQ\_pow}. \subsec{\kbd{FlxqX}} See \kbd{FpXQX} operations. \subsubsec{Preconditioned reduction} For faster reduction, the modulus \kbd{S} can be replaced by an extended modulus, which is an \kbd{FlxqXT}, in all \kbd{FlxqXQ}-classes functions, and in \kbd{FlxqX\_rem} and \kbd{FlxqX\_divrem}. \fun{GEN}{FlxqX_get_red}{GEN S, GEN T, ulong p} returns the extended modulus \kbd{eS}. To write code that works both with plain and extended moduli, the following accessors are defined: \fun{GEN}{get_FlxqX_mod}{GEN eS} returns the underlying modulus \kbd{S}. \fun{GEN}{get_FlxqX_var}{GEN eS} returns the variable number of the modulus. \fun{GEN}{get_FlxqX_degree}{GEN eS} returns the degree of the modulus. \subsubsec{basic functions} \fun{GEN}{random_FlxqX}{long d, long v, GEN T, ulong p} returns a random \kbd{FlxqX} in variable \kbd{v}, of degree less than~\kbd{d}. \fun{GEN}{zxX_to_Kronecker}{GEN P, GEN Q} assuming $P(X,Y)$ is a polynomial of degree in $X$ strictly less than $n$, returns $P(X,X^{2*n-1})$, the Kronecker form of $P$. \fun{GEN}{Kronecker_to_FlxqX}{GEN z, GEN T, ulong p}. Let $n = \deg T$ and let $P(X,Y)\in \Z[X,Y]$ lift a polynomial in $K[Y]$, where $K := \F_p[X]/(T)$ and $\deg_X P < 2n-1$ --- such as would result from multiplying minimal degree lifts of two polynomials in $K[Y]$. Let $z = P(t,t^{2*n-1})$ be a Kronecker form of $P$, this function returns $Q\in \Z[X,t]$ such that $Q$ is congruent to $P(X,t)$ mod $(p, T(X))$, $\deg_X Q < n$, and all coefficients are in $[0,p[$. Not stack-clean. Note that $t$ need not be the same variable as $Y$! \fun{GEN}{FlxqX_red}{GEN z, GEN T, ulong p} \fun{GEN}{FlxqX_normalize}{GEN z, GEN T, ulong p} \fun{GEN}{FlxqX_mul}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{FlxqX_Flxq_mul}{GEN P, GEN U, GEN T, ulong p} \fun{GEN}{FlxqX_Flxq_mul_to_monic}{GEN P, GEN U, GEN T, ulong p} returns $P*U$ assuming the result is monic of the same degree as $P$ (in particular $U\neq 0$). \fun{GEN}{FlxqX_sqr}{GEN x, GEN T, ulong p} \fun{GEN}{FlxqX_powu}{GEN x, ulong n, GEN T, ulong p} \fun{GEN}{FlxqX_divrem}{GEN x, GEN y, GEN T, ulong p, GEN *pr} \fun{GEN}{FlxqX_div}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{FlxqX_rem}{GEN x, GEN y, GEN T, ulong p} \fun{GEN}{FlxqX_invBarrett}{GEN T, GEN Q, ulong p} \fun{GEN}{FlxqX_gcd}{GEN x, GEN y, ulong p} returns a (not necessarily monic) greatest common divisor of $x$ and $y$. \fun{GEN}{FlxqX_extgcd}{GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv} \fun{GEN}{FlxqX_halfgcd}{GEN x, GEN y, GEN T, ulong p}, see \kbd{FpX\_halfgcd}. \fun{GEN}{FlxqXV_prod}{GEN V, GEN T, ulong p} \fun{GEN}{FlxqX_safegcd}{GEN P, GEN Q, GEN T, ulong p} Returns the \emph{monic} GCD of $P$ and $Q$ if Euclid's algorithm succeeds and \kbd{NULL} otherwise. In particular, if $p$ is not prime or $T$ is not irreducible over $\F_p[X]$, the routine may still be used (but will fail if non-invertible leading terms occur). \fun{GEN}{FlxqX_dotproduct}{GEN x, GEN y, GEN T, ulong p} returns the scalar product of the coefficients of $x$ and $y$. \fun{long}{FlxqX_is_squarefree}{GEN S, GEN T, ulong p}, as \kbd{FpX\_is\_squarefree}. \fun{long}{FlxqX_ispower}{GEN f, ulong k, GEN T, ulong p, GEN *pt} return $1$ if the \kbd{FlxqX} $f$ is a $k$-th power, $0$ otherwise. If \kbd{pt} is not \kbd{NULL}, set it to $g$ such that $g^k = f$. \fun{GEN}{FlxqX_Frobenius}{GEN S, GEN T, ulong p}, as \kbd{FpXQX\_Frobenius} \fun{GEN}{FlxqX_roots}{GEN f, GEN T, ulong p} return the roots of \kbd{f} in $\F_p[X]/(T)$. Assumes \kbd{p} is prime and \kbd{T} irreducible in $\F_p[X]$. \fun{GEN}{FlxqX_factor}{GEN f, GEN T, ulong p} return the factorization of \kbd{f} over $\F_p[X]/(T)$. Assumes \kbd{p} is prime and \kbd{T} irreducible in $\F_p[X]$. \fun{GEN}{FlxqX_factor_squarefree}{GEN f, GEN T, ulong p} returns the squarefree factorization of $f$, see \kbd{FpX\_factor\_squarefree}. \fun{GEN}{FlxqX_ddf}{GEN f, GEN T, ulong p} as \kbd{FpX\_ddf}. \fun{long}{FlxqX_ddf_degree}{GEN f, GEN XP, GEN T, GEN p}, as \kbd{FpX\_ddf\_degree}. \fun{GEN}{FlxqX_degfact}{GEN f, GEN T, ulong p}, as \kbd{FpX\_degfact}. \fun{long}{FlxqX_nbroots}{GEN S, GEN T, ulong p}, as \kbd{FpX\_nbroots}. \fun{long}{FlxqX_nbfact}{GEN S, GEN T, ulong p}, as \kbd{FpX\_nbfact}. \fun{long}{FlxqX_nbfact_Frobenius}{GEN S, GEN Xq, GEN T, ulong p}, as \kbd{FpX\_nbfact\_Frobenius}. \fun{GEN}{FlxqX_FlxqXQ_eval}{GEN Q, GEN x, GEN S, GEN T, ulong p} as \kbd{FpX\_FpXQ\_eval}. \fun{GEN}{FlxqX_FlxqXQV_eval}{GEN P, GEN V, GEN S, GEN T, ulong p} as \kbd{FpX\_FpXQV\_eval}. \subsec{\kbd{FlxqXQ}} See \kbd{FpXQXQ} operations. \fun{GEN}{FlxqXQ_mul}{GEN x, GEN y, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_sqr}{GEN x, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_inv}{GEN x, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_invsafe}{GEN x, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_div}{GEN x, GEN y, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_pow}{GEN x, GEN n, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_powu}{GEN x, ulong n, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_powers}{GEN x, long n, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_matrix_pow}{GEN x, long n, long m, GEN S, GEN T, ulong p} \fun{GEN}{FlxqXQ_autpow}{GEN a, long n, GEN S, GEN T, ulong p} as \kbd{FpXQXQ\_autpow} \fun{GEN}{FlxqXQ_autsum}{GEN a, long n, GEN S, GEN T, ulong p} as \kbd{FpXQXQ\_autsum} \fun{GEN}{FlxqXQ_auttrace}{GEN a, long n, GEN S, GEN T, ulong p} as \kbd{FpXQXQ\_auttrace} \fun{GEN}{FlxqXQ_halfFrobenius}{GEN A, GEN S, GEN T, ulong p}, as \kbd{FpXQXQ\_halfFrobenius} \fun{GEN}{FlxqXQ_minpoly}{GEN x, GEN S, GEN T, ulong p}, as \kbd{FpXQ\_minpoly} \subsec{\kbd{F2x}} An \kbd{F2x}~\kbd{z} is a \typ{VECSMALL} representing a polynomial over $\F_2[X]$. Specifically \kbd{z[0]} is the usual codeword, \kbd{z[1] = evalvarn($v$)} for some variable $v$ and the coefficients are given by the bits of remaining words by increasing degree. \subsubsec{Preconditioned reduction} For faster reduction, the modulus \kbd{T} can be replaced by an extended modulus (\kbd{FlxT}) in all \kbd{Flxq}-classes functions, and in \kbd{Flx\_divrem}. \fun{GEN}{F2x_get_red}{GEN T} returns the extended modulus \kbd{eT}. To write code that works both with plain and extended moduli, the following accessors are defined: \fun{GEN}{get_F2x_mod}{GEN eT} returns the underlying modulus \kbd{T}. \fun{GEN}{get_F2x_var}{GEN eT} returns the variable number of the modulus. \fun{GEN}{get_F2x_degree}{GEN eT} returns the degree of the modulus. \subsubsec{Basic operations} \fun{ulong}{F2x_coeff}{GEN x, long i} returns the coefficient $i\ge 0$ of $x$. \fun{void}{F2x_clear}{GEN x, long i} sets the coefficient $i\ge 0$ of $x$ to $0$. \fun{void}{F2x_flip}{GEN x, long i} adds $1$ to the coefficient $i\ge 0$ of $x$. \fun{void}{F2x_set}{GEN x, long i} sets the coefficient $i\ge 0$ of $x$ to $1$. \fun{GEN}{F2x_copy}{GEN x} \fun{GEN}{Flx_to_F2x}{GEN x} \fun{GEN}{Z_to_F2x}{GEN x, long v} \fun{GEN}{ZX_to_F2x}{GEN x} \fun{GEN}{F2v_to_F2x}{GEN x, long sv} \fun{GEN}{F2x_to_Flx}{GEN x} \fun{GEN}{F2x_to_F2xX}{GEN x, long sv} \fun{GEN}{F2x_to_ZX}{GEN x} \fun{GEN}{pol0_F2x}{long sv} returns a zero \kbd{F2x} in variable $v$. \fun{GEN}{zero_F2x}{long sv} alias for \kbd{pol0\_F2x}. \fun{GEN}{pol1_F2x}{long sv} returns the \kbd{F2x} in variable $v$ constant to $1$. \fun{GEN}{polx_F2x}{long sv} returns the variable $v$ as degree~1~\kbd{F2x}. \fun{GEN}{monomial_F2x}{long d, long sv} returns the \kbd{F2x} $X^d$ in variable $v$. \fun{GEN}{random_F2x}{long d, long sv} returns a random \kbd{F2x} in variable \kbd{v}, of degree less than~\kbd{d}. \fun{long}{F2x_degree}{GEN x} returns the degree of the \kbd{F2x x}. The degree of $0$ is defined as $-1$. \fun{int}{F2x_equal1}{GEN x} \fun{int}{F2x_equal}{GEN x, GEN y} \fun{GEN}{F2x_1_add}{GEN y} returns \kbd{y+1} where \kbd{y} is a \kbd{Flx}. \fun{GEN}{F2x_add}{GEN x, GEN y} \fun{GEN}{F2x_mul}{GEN x, GEN y} \fun{GEN}{F2x_sqr}{GEN x} \fun{GEN}{F2x_divrem}{GEN x, GEN y, GEN *pr} \fun{GEN}{F2x_rem}{GEN x, GEN y} \fun{GEN}{F2x_div}{GEN x, GEN y} \fun{GEN}{F2x_renormalize}{GEN x, long lx} \fun{GEN}{F2x_deriv}{GEN x} \fun{GEN}{F2x_deflate}{GEN x, long d} \fun{ulong}{F2x_eval}{GEN P, ulong u} returns $P(u)$. \fun{void}{F2x_shift}{GEN x, long d} as \tet{RgX_shift} \fun{void}{F2x_even_odd}{GEN P, GEN *pe, GEN *po} as \tet{RgX_even_odd} \fun{long}{F2x_valrem}{GEN x, GEN *Z} \fun{GEN}{F2x_extgcd}{GEN a, GEN b, GEN *ptu, GEN *ptv} \fun{GEN}{F2x_gcd}{GEN a, GEN b} \fun{GEN}{F2x_halfgcd}{GEN a, GEN b} \fun{int}{F2x_issquare}{GEN x} returns $1$ if $x$ is a square of a \kbd{F2x} and $0$ otherwise. \fun{int}{F2x_is_irred}{GEN f}, as \tet{FpX_is_irred}. \fun{GEN}{F2x_degfact}{GEN f} as \tet{FpX_degfact}. \fun{GEN}{F2x_sqrt}{GEN x} returns the squareroot of $x$, assuming $x$ is a square of a \kbd{F2x}. \fun{GEN}{F2x_Frobenius}{GEN T} \fun{GEN}{F2x_matFrobenius}{GEN T} \fun{GEN}{F2x_factor}{GEN f} \fun{GEN}{F2x_factor_squarefree}{GEN f} \fun{GEN}{F2x_ddf}{GEN f} \subsec{\kbd{F2xq}} See \kbd{FpXQ} operations. \fun{GEN}{F2xq_mul}{GEN x, GEN y, GEN T} \fun{GEN}{F2xq_sqr}{GEN x, GEN T} \fun{GEN}{F2xq_div}{GEN x,GEN y,GEN T} \fun{GEN}{F2xq_inv}{GEN x, GEN T} \fun{GEN}{F2xq_invsafe}{GEN x, GEN T} \fun{GEN}{F2xq_pow}{GEN x, GEN n, GEN T} \fun{GEN}{F2xq_powu}{GEN x, ulong n, GEN T} \fun{GEN}{F2xq_pow_init}{GEN x, GEN n, long k, GEN T} \fun{GEN}{F2xq_pow_table}{GEN R, GEN n, GEN T} \fun{ulong}{F2xq_trace}{GEN x, GEN T} \fun{GEN}{F2xq_conjvec}{GEN x, GEN T} returns the vector of conjugates $[x,x^2,x^{2^2},\ldots,x^{2^{n-1}}]$ where $n$ is the degree of $T$. \fun{GEN}{F2xq_log}{GEN a, GEN g, GEN ord, GEN T} \fun{GEN}{F2xq_order}{GEN a, GEN ord, GEN T} \fun{GEN}{F2xq_Artin_Schreier}{GEN a, GEN T} returns a solution of $x^2+x=a$, assuming it exists. \fun{GEN}{F2xq_sqrt}{GEN a, GEN T} \fun{GEN}{F2xq_sqrt_fast}{GEN a, GEN s, GEN T} assuming that $s^2 \equiv x\pmod{T(x)}$, computes $b \equiv a(s)\pmod{T}$ so that $b^2=a$. \fun{GEN}{F2xq_sqrtn}{GEN a, GEN n, GEN T, GEN *zeta} \fun{GEN}{gener_F2xq}{GEN T, GEN *po} \fun{GEN}{F2xq_powers}{GEN x, long n, GEN T} \fun{GEN}{F2xq_matrix_pow}{GEN x, long m, long n, GEN T} \fun{GEN}{F2x_F2xq_eval}{GEN f, GEN x, GEN T} \fun{GEN}{F2x_F2xqV_eval}{GEN f, GEN x, GEN T}, see \kbd{FpX\_FpXQV\_eval}. \fun{GEN}{F2xq_autpow}{GEN a, long n, GEN T} computes $\sigma^n(X)$ assuming $a=\sigma(X)$ where $\sigma$ is an automorphism of the algebra $\F_2[X]/T(X)$. \subsec{\kbd{F2xqV}, \kbd{F2xqM}}. See \kbd{FqV}, \kbd{FqM} operations. \fun{GEN}{F2xqM_F2xqC_gauss}{GEN a, GEN b, GEN T} \fun{GEN}{F2xqM_F2xqC_invimage}{GEN a, GEN b, GEN T} \fun{GEN}{F2xqM_F2xqC_mul}{GEN a, GEN b, GEN T} \fun{GEN}{F2xqM_deplin}{GEN x, GEN T} \fun{GEN}{F2xqM_det}{GEN a, GEN T} \fun{GEN}{F2xqM_gauss}{GEN a, GEN b, GEN T} \fun{GEN}{F2xqM_image}{GEN x, GEN T} \fun{GEN}{F2xqM_indexrank}{GEN x, GEN T} \fun{GEN}{F2xqM_inv}{GEN a, GEN T} \fun{GEN}{F2xqM_invimage}{GEN a, GEN b, GEN T} \fun{GEN}{F2xqM_ker}{GEN x, GEN T} \fun{GEN}{F2xqM_mul}{GEN a, GEN b, GEN T} \fun{long}{F2xqM_rank}{GEN x, GEN T} \fun{GEN}{F2xqM_suppl}{GEN x, GEN T} \fun{GEN}{matid_F2xqM}{long n, GEN T} \subsec{\kbd{F2xX}}. See \kbd{FpXX} operations. \fun{GEN}{ZXX_to_F2xX}{GEN x, long v} \fun{GEN}{FlxX_to_F2xX}{GEN x} \fun{GEN}{F2xX_to_ZXX}{GEN B} \fun{GEN}{F2xX_renormalize}{GEN x, long lx} \fun{long}{F2xY_degreex}{GEN P} return the degree of $P$ with respect to the secondary variable. \fun{GEN}{pol1_F2xX}{long v, long sv} \fun{GEN}{polx_F2xX}{long v, long sv} \fun{GEN}{F2xX_add}{GEN x, GEN y} \fun{GEN}{F2xX_F2x_add}{GEN x, GEN y} \fun{GEN}{F2xX_F2x_mul}{GEN x, GEN y} \fun{GEN}{F2xX_deriv}{GEN P} returns the derivative of \kbd{P} with respect to the main variable. \fun{GEN}{Kronecker_to_F2xqX}{GEN z, GEN T} \fun{GEN}{F2xX_to_Kronecker}{GEN z, GEN T} \fun{GEN}{F2xY_F2xq_evalx}{GEN x, GEN y, GEN T} as \kbd{FpXY\_FpXQ\_evalx}. \fun{GEN}{F2xY_F2xqV_evalx}{GEN x, GEN V, GEN T} as \kbd{FpXY\_FpXQV\_evalx}. \subsec{\kbd{F2xXV/F2xXC}}. See \kbd{FpXXV} operations. \fun{GEN}{FlxXC_to_F2xXC}{GEN B} \fun{GEN}{F2xXC_to_ZXXC}{GEN B} \subsec{\kbd{F2xqX}}. See \kbd{FlxqX} operations. \subsubsec{Preconditioned reduction} For faster reduction, the modulus \kbd{S} can be replaced by an extended modulus, which is an \kbd{F2xqXT}, in all \kbd{F2xqXQ}-classes functions, and in \kbd{F2xqX\_rem} and \kbd{F2xqX\_divrem}. \fun{GEN}{F2xqX_get_red}{GEN S, GEN T} returns the extended modulus \kbd{eS}. To write code that works both with plain and extended moduli, the following accessors are defined: \fun{GEN}{get_F2xqX_mod}{GEN eS} returns the underlying modulus \kbd{S}. \fun{GEN}{get_F2xqX_var}{GEN eS} returns the variable number of the modulus. \fun{GEN}{get_F2xqX_degree}{GEN eS} returns the degree of the modulus. \subsubsec{basic functions} \fun{GEN}{random_F2xqX}{long d, long v, GEN T, ulong p} returns a random \kbd{F2xqX} in variable \kbd{v}, of degree less than~\kbd{d}. \fun{GEN}{F2xqX_red}{GEN z, GEN T} \fun{GEN}{F2xqX_normalize}{GEN z, GEN T} \fun{GEN}{F2xqX_F2xq_mul}{GEN P, GEN U, GEN T} \fun{GEN}{F2xqX_F2xq_mul_to_monic}{GEN P, GEN U, GEN T} \fun{GEN}{F2xqX_mul}{GEN x, GEN y, GEN T} \fun{GEN}{F2xqX_sqr}{GEN x, GEN T} \fun{GEN}{F2xqX_powu}{GEN x, ulong n, GEN T} \fun{GEN}{F2xqX_rem}{GEN x, GEN y, GEN T} \fun{GEN}{F2xqX_div}{GEN x, GEN y, GEN T} \fun{GEN}{F2xqX_divrem}{GEN x, GEN y, GEN T, GEN *pr} \fun{GEN}{F2xqXQ_inv}{GEN x, GEN S, GEN T} \fun{GEN}{F2xqXQ_invsafe}{GEN x, GEN S, GEN T} \fun{GEN}{F2xqX_invBarrett}{GEN T, GEN Q} \fun{GEN}{F2xqX_extgcd}{GEN x, GEN y, GEN T, GEN *ptu, GEN *ptv} \fun{GEN}{F2xqX_gcd}{GEN x, GEN y, GEN T} \fun{long}{F2xqX_ispower}{GEN f, ulong k, GEN T, GEN *pt} \fun{GEN}{F2xqX_F2xqXQ_eval}{GEN Q, GEN x, GEN S, GEN T} as \kbd{FpX\_FpXQ\_eval}. \fun{GEN}{F2xqX_F2xqXQV_eval}{GEN P, GEN V, GEN S, GEN T} as \kbd{FpX\_FpXQV\_eval}. \fun{GEN}{F2xqX_roots}{GEN f, GEN T} return the roots of \kbd{f} in $\F_2[X]/(T)$. Assumes \kbd{T} irreducible in $\F_2[X]$. \fun{GEN}{F2xqX_factor}{GEN f, GEN T} return the factorization of \kbd{f} over $\F_2[X]/(T)$. Assumes \kbd{T} irreducible in $\F_2[X]$. \fun{GEN}{F2xqX_factor_squarefree}{GEN f, GEN T} as \kbd{FlxqX\_factor\_squarefree}. \fun{GEN}{F2xqX_ddf}{GEN f, GEN T} as \kbd{FpX\_ddf}. \fun{GEN}{F2xqX_degfact}{GEN f, GEN T} as \kbd{FpX\_degfact}. \subsec{\kbd{F2xqXQ}}. See \kbd{FlxqXQ} operations. \fun{GEN}{FlxqXQ_inv}{GEN x, GEN S, GEN T} \fun{GEN}{FlxqXQ_invsafe}{GEN x, GEN S, GEN T} \fun{GEN}{F2xqXQ_mul}{GEN x, GEN y, GEN S, GEN T} \fun{GEN}{F2xqXQ_sqr}{GEN x, GEN S, GEN T} \fun{GEN}{F2xqXQ_pow}{GEN x, GEN n, GEN S, GEN T} \fun{GEN}{F2xqXQ_powers}{GEN x, long n, GEN S, GEN T} \fun{GEN}{F2xqXQ_autpow}{GEN a, long n, GEN S, GEN T} as \kbd{FpXQXQ\_autpow} \fun{GEN}{F2xqXQ_auttrace}{GEN a, long n, GEN S, GEN T}. Let $\sigma$ be the automorphism defined by $\sigma(X)=a[1]\pmod{T(X)}$ and $\sigma(Y)=a[2]\pmod{S(X,Y),T(X)}$; returns the vector $[\sigma^n(X),\sigma^n(Y),b+\sigma(b)+\ldots+\sigma^{n-1}(b)]$ where $b=a[3]$. \fun{GEN}{F2xqXQV_red}{GEN x, GEN S, GEN T} \subsec{Functions returning objects with \typ{INTMOD} coefficients} Those functions are mostly needed for interface reasons: \typ{INTMOD}s should not be used in library mode since the modular kernel is more flexible and more efficient, but GP users do not have access to the modular kernel. We document them for completeness: \fun{GEN}{Fp_to_mod}{GEN z, GEN p}, \kbd{z} a \typ{INT}. Returns \kbd{z * Mod(1,p)}, normalized. Hence the returned value is a \typ{INTMOD}. \fun{GEN}{FpX_to_mod}{GEN z, GEN p}, \kbd{z} a \kbd{ZX}. Returns \kbd{z * Mod(1,p)}, normalized. Hence the returned value has \typ{INTMOD} coefficients. \fun{GEN}{FpC_to_mod}{GEN z, GEN p}, \kbd{z} a \kbd{ZC}. Returns \kbd{Col(z) * Mod(1,p)}, a \typ{COL} with \typ{INTMOD} coefficients. \fun{GEN}{FpV_to_mod}{GEN z, GEN p}, \kbd{z} a \kbd{ZV}. Returns \kbd{Vec(z) * Mod(1,p)}, a \typ{VEC} with \typ{INTMOD} coefficients. \fun{GEN}{FpVV_to_mod}{GEN z, GEN p}, \kbd{z} a \kbd{ZVV}. Returns \kbd{Vec(z) * Mod(1,p)}, a \typ{VEC} of \typ{VEC} with \typ{INTMOD} coefficients. \fun{GEN}{FpM_to_mod}{GEN z, GEN p}, \kbd{z} a \kbd{ZM}. Returns \kbd{z * Mod(1,p)}, with \typ{INTMOD} coefficients. \fun{GEN}{F2c_to_mod}{GEN x} \fun{GEN}{F2m_to_mod}{GEN x} \fun{GEN}{Flc_to_mod}{GEN z} \fun{GEN}{Flm_to_mod}{GEN z} \fun{GEN}{FqM_to_mod}{GEN z, GEN T, GEN p} \fun{GEN}{FpXQC_to_mod}{GEN V, GEN T, GEN p} $V$ being a vector of \kbd{FpXQ}, converts each entry to a \typ{POLMOD} with \typ{INTMOD} coefficients, and return a \typ{COL}. \fun{GEN}{QXQV_to_mod}{GEN V, GEN T} $V$ a vector of \kbd{QXQ}, which are lifted representatives of elements of $\Q[X]/(T)$ (number field elements in most applications) and $T$ is in $\Z[X]$. Return a vector where all non-rational entries are converted to \typ{POLMOD} modulo $T$; no reduction mod $T$ is attempted: the representatives should be already reduced. Used to normalize the output of \kbd{nfroots}. \fun{GEN}{QXQX_to_mod_shallow}{GEN P, GEN T} $P$ a polynomial with \kbd{QXQ} coefficients; replace them by \kbd{mkpolmod(.,T)}. Shallow function. \fun{GEN}{QXQC_to_mod_shallow}{GEN V, GEN T} $V$ a vector with \kbd{QXQ} coefficients; replace them by \kbd{mkpolmod(.,T)}. Shallow function. \fun{GEN}{QXQM_to_mod_shallow}{GEN M, GEN T} $M$ a matrix with \kbd{QXQ} coefficients; replace them by \kbd{mkpolmod(.,T)}. Shallow function. \fun{GEN}{QXQXV_to_mod}{GEN V, GEN T} $V$ a vector of polynomials whose coefficients are \kbd{QXQ}. Analogous to \kbd{QXQV\_to\_mod}. Used to normalize the output of \kbd{nffactor}. The following functions are obsolete and should not be used: they receive a polynomial with arbitrary coefficients, apply a conversion function to map them to a finite field, a function from the modular kernel, then \kbd{*\_to\_mod}: \fun{GEN}{rootmod}{GEN f, GEN p}, applies \kbd{FpX\_roots}. \fun{GEN}{rootmod2}{GEN f, GEN p}, (now) identical to \kbd{rootmod}. \fun{GEN}{rootmod0}{GEN f, GEN p, long flag}, calls either \kbd{rootmod} or \kbd{rootmod2} depending on \kbd{flag}. \fun{GEN}{factmod}{GEN f, GEN p} applies \kbd{*\_factor}. \fun{GEN}{simplefactmod}{GEN f, GEN p} applies \kbd{*\_degfact}. \subsec{Slow Chinese remainder theorem over $\Z$} The routines in this section have quadratic time complexity with respect to the input size; see the routines in the next two sections for quasi-linear time variants. \fun{GEN}{Z_chinese}{GEN a, GEN b, GEN A, GEN B} returns the integer in $[0, \lcm(A,B)[$ congruent to $a$ mod $A$ and $b$ mod $B$, assuming it exists; in other words, that $a$ and $b$ are congruent mod $\gcd(A,B)$. \fun{GEN}{Z_chinese_all}{GEN a, GEN b, GEN A, GEN B, GEN *pC} as \kbd{Z\_chinese}, setting \kbd{*pC} to the lcm of $A$ and $B$. \fun{GEN}{Z_chinese_coprime}{GEN a, GEN b, GEN A, GEN B, GEN C}, as \kbd{Z\_chinese}, assuming that $\gcd(A,B) = 1$ and that $C = \lcm(A,B) = AB$. \fun{ulong}{u_chinese_coprime}{ulong a, ulong b, ulong A, ulong B, ulong C}, as \kbd{Z\_chinese\_coprime} for \kbd{ulong} inputs and output. \fun{void}{Z_chinese_pre}{GEN A, GEN B, GEN *pC, GEN *pU, GEN *pd} initializes chinese remainder computations modulo $A$ and $B$. Sets \kbd{*pC} to $\lcm(A,B)$, \kbd{*pd} to $\gcd(A,B)$, \kbd{*pU} to an integer congruent to $0$ mod $(A/d)$ and $1$ mod $(B/d)$. It is allowed to set \kbd{pd = NULL}, in which case, $d$ is still computed, but not saved. \fun{GEN}{Z_chinese_post}{GEN a, GEN b, GEN C, GEN U, GEN d} returns the solution to the chinese remainder problem $x$ congruent to $a$ mod $A$ and $b$ mod $B$, where $C, U, d$ were set in \kbd{Z\_chinese\_pre}. If $d$ is \kbd{NULL}, assume the problem has a solution. Otherwise, return \kbd{NULL} if it has no solution. \medskip The following pair of functions is used in homomorphic imaging schemes, when reconstructing an integer from its images modulo pairwise coprime integers. The idea is as follows: we want to discover an integer $H$ which satisfies $|H| < B$ for some known bound $B$; we are given pairs $(H_p, p)$ with $H$ congruent to $H_p$ mod $p$ and all $p$ pairwise coprime. Given \kbd{H} congruent to $H_p$ modulo a number of $p$, whose product is $q$, and a new pair $(\kbd{Hp}, \kbd{p})$, \kbd{p} coprime to $q$, the following incremental functions use the chinese remainder theorem (CRT) to find a new \kbd{H}, congruent to the preceding one modulo $q$, but also to \kbd{Hp} modulo \kbd{p}. It is defined uniquely modulo $qp$, and we choose the centered representative. When $P$ is larger than $2B$, we have $\kbd{H} = H$, but of course, the value of \kbd{H} may stabilize sooner. In many applications it is possible to directly check that such a partial result is correct. \fun{GEN}{Z_init_CRT}{ulong Hp, ulong p} given a \kbd{Fl} \kbd{Hp} in $[0, p-1]$, returns the centered representative \kbd{H} congruent to \kbd{Hp} modulo \kbd{p}. \fun{int}{Z_incremental_CRT}{GEN *H, ulong Hp, GEN *q, ulong p} given a \typ{INT} \kbd{*H}, centered modulo \kbd{*q}, a new pair $(\kbd{Hp}, \kbd{p})$ with \kbd{p} coprime to \kbd{q}, this function updates \kbd{*H} so that it also becomes congruent to $(\kbd{Hp}, \kbd{p})$, and \kbd{*q} to the product$\kbd{qp} = \kbd{p} \cdot \kbd{*q}$. It returns $1$ if the new value is equal to the old one, and $0$ otherwise. \fun{GEN}{chinese1_coprime_Z}{GEN v} an alternative divide-and-conquer implementation: $v$ is a vector of \typ{INTMOD} with pairwise coprime moduli. Return the \typ{INTMOD} solving the corresponding chinese remainder problem. This is a streamlined version of \fun{GEN}{chinese1}{GEN v}, which solves a general chinese remainder problem (not necessarily over $\Z$, moduli not assumed coprime). As above, for $H$ a \kbd{ZM}: we assume that $H$ and all \kbd{Hp} have dimension $> 0$. The original \kbd{*H} is destroyed. \fun{GEN}{ZM_init_CRT}{GEN Hp, ulong p} \fun{int}{ZM_incremental_CRT}{GEN *H, GEN Hp, GEN *q, ulong p} As above for $H$ a \kbd{ZX}: note that the degree may increase or decrease. The original \kbd{*H} is destroyed. \fun{GEN}{ZX_init_CRT}{GEN Hp, ulong p, long v} \fun{int}{ZX_incremental_CRT}{GEN *H, GEN Hp, GEN *q, ulong p} As above, for $H$ a matrix whose coefficient are \kbd{ZX}. The original \kbd{*H} is destroyed. The entries of $H$ are not normalized, use \kbd{ZX\_renormalize} for this. \fun{GEN}{ZXM_init_CRT}{GEN Hp, long deg, ulong p} where \kbd{deg} is the maximal degree of all the \kbd{Hp} \fun{int}{ZXM_incremental_CRT}{GEN *H, GEN Hp, GEN *q, ulong p} \subsec{Fast remainders} The routines in these section are asymptotically fast (quasi-linear time in the input size). \fun{GEN}{Z_ZV_mod}{GEN A, GEN P} given a \typ{INT} $A$ and a vector $P$ of positive pairwise coprime integers of length $n\ge 1$, return a vector $B$ of the same length such that $B[i] = A\pmod{P[i]}$ and $0\leq B[i] < P[i]$ for all $1\leq i\leq n$. The vector $P$ may be a \typ{VEC} or a \typ{VECSMALL} (treated as \kbd{ulong}s) and $B$ has the same type as $P$. \fun{GEN}{Z_nv_mod}{GEN A, GEN P} given a \typ{INT} $A$ and a \typ{VECSMALL} $P$ of positive pairwise coprime integers of length $n\ge 1$, return a \typ{VECSMALL} $B$ of the same length such that $B[i]=A\pmod{P[i]}$ and $0\leq B[i] < P[i]$ for all $1\leq i\leq n$. The entries of $P$ and $B$ are treated as \kbd{ulong}s. The following low level functions allow precomputations: \fun{GEN}{ZV_producttree}{GEN P} where $P$ is a vector of integers (or \typ{VECSMALL}) of length $n\ge 1$, return the vector of \typ{VEC}s $[f(P),f^2(P),\ldots,f^k(P)]$ where $f$ is the transformation $[p_1,p_2,\ldots,p_m] \mapsto [p_1\*p_2,p_3\*p_4,\ldots,p_{m-1}\*p_m]$ if $m$ is even and $[p_1\*p_2,p_3\*p_4,\ldots,p_{m-2}\*p_{m-1},p_m]$ if $m$ is odd, and $k = O(\log m)$ is minimal so that $f^k(P)$ has length $1$; in other words, $f^k(P) = [p_1\*p_2\*\ldots\*p_m]$. \fun{GEN}{Z_ZV_mod_tree}{GEN A, GEN P, GEN T} as \kbd{Z\_ZV\_mod} where $T$ is the tree \kbd{ZV\_producttree(P)}. \fun{GEN}{ZV_nv_mod_tree}{GEN A, GEN P, GEN T} $A$ being a \kbd{ZV} and $P$ a \typ{VECSMALL} of length $n\ge 1$, the elements of $P$ being pairwise coprime, return the vector of \kbd{Flv} $[A \pmod{P[1]},\ldots,A \pmod{P[n]}]$, where $T$ is the tree \kbd{ZV\_producttree(P)}. \fun{GEN}{ZM_nv_mod_tree}{GEN A, GEN P, GEN T} $A$ being a \kbd{ZM} and $P$ a \typ{VECSMALL} of length $n\ge 1$, the elements of $P$ being pairwise coprime, return the vector of \kbd{Flm} $[A \pmod{P[1]},\ldots,A \pmod{P[n]}]$, where $T$ is the tree \kbd{ZV\_producttree(P)}. \fun{GEN}{ZX_nv_mod_tree}{GEN A, GEN P, GEN T} $A$ being a \kbd{ZX} and $P$ a \typ{VECSMALL} of length $n\ge 1$, the elements of $P$ being pairwise coprime, return the vector of \kbd{Flx} polynomials $[A \pmod{P[1]},\ldots,A \pmod{P[n]}]$, where $T$ is the tree \kbd{ZV\_producttree(P)}. \fun{GEN}{ZXC_nv_mod_tree}{GEN A, GEN P, GEN T} $A$ being a \kbd{ZXC} and $P$ a \typ{VECSMALL} of length $n\ge 1$, the elements of $P$ being pairwise coprime, return the vector of \kbd{FlxC} $[A \pmod{P[1]},\ldots,A \pmod{P[n]}]$, where $T$ is the tree \kbd{ZV\_producttree(P)}. \fun{GEN}{ZXM_nv_mod_tree}{GEN A, GEN P, GEN T} $A$ being a \kbd{ZXM} and $P$ a \typ{VECSMALL} of length $n\ge 1$, the elements of $P$ being pairwise coprime, return the vector of \kbd{FlxM} $[A \pmod{P[1]},\ldots,A \pmod{P[n]}]$, where $T$ is the tree \kbd{ZV\_producttree(P)}. \fun{GEN}{ZXX_nv_mod_tree}{GEN A, GEN P, GEN T, long v} $A$ being a \kbd{ZXX}, and $P$ a \typ{VECSMALL} of length $n\ge 1$, the elements of $P$ being pairwise coprime, return the vector of \kbd{FlxX} $[A \pmod{P[1]},\ldots,A \pmod{P[n]}]$, where $T$ is assumed to be the tree created by \kbd{ZV\_producttree(P)}. \medskip \subsec{Fast Chinese remainder theorem over $\Z$} The routines in these section are asymptotically fast (quasi-linear time in the input size) and should be used whenever the moduli are known from the start. The simplest function is \fun{GEN}{ZV_chinese}{GEN A, GEN P, GEN *pM} let $P$ be a vector of positive pairwise coprime integers, let $A$ be a vector of integers of the same length $n\ge 1$ such that $0 \leq A[i] < P[i]$ for all $i$, and let $M$ be the product of the elements of $P$. Returns the integer in $[0, M[$ congruent to $A[i]$ mod $P[i]$ for all $1\leq i\leq n$. If \kbd{pM} is not \kbd{NULL}, set \kbd{*pM} to $M$. We also allow \typ{VECSMALL}s for $A$ and $P$ (seen as vectors of unsigned integers). \fun{GEN}{ZV_chinese_center}{GEN A, GEN P, GEN *pM} As \kbd{ZV\_chinese} but return integers in $[-M/2, M/2[$ instead. The following functions allow to solve many Chinese remainder problems simultaneously, for a given set of moduli: \fun{GEN}{nxV_chinese_center}{GEN A, GEN P, GEN *pt_mod} where $A$ is a vector of \kbd{nx} and $P$ a \typ{VECSMALL} of the same length $n\ge 1$, the elements of $P$ being pairwise coprime, and $M$ being the product of the elements of $P$, returns the \typ{POL} whose entries are integers in $[-M/2, M/2[$ congruent to $A[i]$ mod $P[i]$ for all $1\leq i\leq n$. If \kbd{pt\_mod} is not \kbd{NULL}, set \kbd{*pt\_mod} to $M$. \fun{GEN}{ncV_chinese_center}{GEN A, GEN P, GEN *pM} where $A$ is a vector of \kbd{VECSMALL}s (seen as vectors of unsigned integers) and $P$ a \typ{VECSMALL} of the same length $n\ge 1$, the elements of $P$ being pairwise coprime, and $M$ being the product of the elements of $P$, returns the \typ{COL} whose entries are integers in $[-M/2, M/2[$ congruent to $A[i]$ mod $P[i]$ for all $1\leq i\leq n$. If \kbd{pM} is not \kbd{NULL}, set \kbd{*pt\_mod} to $M$. \fun{GEN}{nmV_chinese_center}{GEN A, GEN P, GEN *pM} where $A$ is a vector of \kbd{MATSMALL}s (seen as matrices of unsigned integers) and $P$ a \typ{VECSMALL} of the same length $n\ge 1$, the elements of $P$ being pairwise coprime, and $M$ being the product of the elements of $P$, returns the matrix whose entries are integers in $[-M/2, M/2[$ congruent to $A[i]$ mod $P[i]$ for all $1\leq i\leq n$. If \kbd{pM} is not \kbd{NULL}, set \kbd{*pM} to $M$. N.B.: this function uses the parallel GP interface. \fun{GEN}{nxCV_chinese_center}{GEN A, GEN P, GEN *pM} where $A$ is a vector of \kbd{nxC}s and $P$ a \typ{VECSMALL} of the same length $n\ge 1$, the elements of $P$ being pairwise coprime, and $M$ being the product of the elements of $P$, returns the \typ{COL} whose entries are integers in $[-M/2, M/2[$ congruent to $A[i]$ mod $P[i]$ for all $1\leq i\leq n$. If \kbd{pM} is not \kbd{NULL}, set \kbd{*pt\_mod} to $M$. \fun{GEN}{nxMV_chinese_center}{GEN A, GEN P, GEN *pM} where $A$ is a vector of \kbd{nxM}s and $P$ a \typ{VECSMALL} of the same length $n\ge 1$, the elements of $P$ being pairwise coprime, and $M$ being the product of the elements of $P$, returns the matrix whose entries are integers in $[-M/2, M/2[$ congruent to $A[i]$ mod $P[i]$ for all $1\leq i\leq n$. If \kbd{pM} is not \kbd{NULL}, set \kbd{*pM} to $M$. N.B.: this function uses the parallel GP interface. The other routines allow for various precomputations : \fun{GEN}{ZV_chinesetree}{GEN P, GEN T} given $P$ a vector of integers (or \typ{VECSMALL}) and a product tree $T$ from \tet{ZV_producttree}$(P)$ for the same $P$, return a ``chinese remainder tree'' $R$, preconditionning the solution of Chinese remainder problems modulo the $P[i]$. \fun{GEN}{ZV_chinese_tree}{GEN A, GEN P, GEN T, GEN R} return \kbd{ZV\_chinese}$(A,P,\kbd{NULL})$, where $T$ is created by \kbd{ZV\_producttree}$(P)$ and $R$ by \kbd{ZV\_chinesetree}$(P,T)$. \fun{GEN}{nmV_chinese_center_tree}{GEN A, GEN P, GEN T, GEN R} as \kbd{nmV\_chinese\_center} where $T$ is assumed to be the tree created by \kbd{ZV\_producttree(P)} and $R$ by \kbd{ZV\_chinesetree}$(P,T)$. \fun{GEN}{nxV_chinese_center_tree}{GEN A, GEN P, GEN T, GEN R} as \kbd{nxV\_chinese\_center} where $T$ is assumed to be the tree created by \kbd{ZV\_producttree(P)} and $R$ by \kbd{ZV\_chinesetree}$(P,T)$. \subsec{Rational reconstruction} \fun{int}{Fp_ratlift}{GEN x, GEN m, GEN amax, GEN bmax, GEN *a, GEN *b}. Assuming that $0 \leq x < m$, $\kbd{amax} \geq 0$, and $\kbd{bmax} > 0$ are \typ{INT}s, and that $2 \kbd{amax} \kbd{bmax} < m$, attempts to recognize $x$ as a rational $a/b$, i.e. to find \typ{INT}s $a$ and $b$ such that \item $a \equiv b x$ modulo $m$, \item $|a| \leq \kbd{amax}$, $0 < b \leq \kbd{bmax}$, \item $\gcd(m,b) = \gcd(a,b)$. \noindent If unsuccessful, the routine returns $0$ and leaves $a$, $b$ unchanged; otherwise it returns $1$ and sets $a$ and $b$. In almost all applications, we actually know that a solution exists, as well as a non-zero multiple $B$ of $b$, and $m = p^\ell$ is a prime power, for a prime $p$ chosen coprime to $B$ hence to $b$. Under the single assumption $\gcd(m,b) = 1$, if a solution $a,b$ exists satisfying the three conditions above, then it is unique. \fun{GEN}{FpM_ratlift}{GEN M, GEN m, GEN amax, GEN bmax, GEN denom} given an \kbd{FpM} modulo $m$ with reduced or \kbd{Fp\_center}-ed entries, reconstructs a matrix with rational coefficients by applying \kbd{Fp\_ratlift} to all entries. Assume that all preconditions for \kbd{Fp\_ratlift} are satisfied, as well $\gcd(m,b) = 1$ (so that the solution is unique if it exists). Return \kbd{NULL} if the reconstruction fails, and the rational matrix otherwise. If \kbd{denom} is not \kbd{NULL} check further that all denominators divide \kbd{denom}. The functions is not stack clean if one coefficients of $M$ is negative (centered residues), but still suitable for \kbd{gerepileupto}. \fun{GEN}{FpX_ratlift}{GEN P, GEN m, GEN amax, GEN bmax, GEN denom} as \kbd{FpM\_ratlift}, where $P$ is an \kbd{FpX}. \fun{GEN}{FpC_ratlift}{GEN P, GEN m, GEN amax, GEN bmax, GEN denom} as \kbd{FpM\_ratlift}, where $P$ is an \kbd{FpC}. \subsec{Zp} \fun{GEN}{Zp_sqrt}{GEN b, GEN p, long e} $b$ and $p$ being \typ{INT}s, with $p$ a prime (possibly $2$), returns a \typ{INT} $a$ such that $a^2 \equiv b \mod p^e$. \fun{GEN}{Z2_sqrt}{GEN b, long e} $b$ being a \typ{INT}s returns a \typ{INT} $a$ such that $a^2 \equiv b \mod 2^e$. \fun{GEN}{Zp_sqrtlift}{GEN b, GEN a, GEN p, long e} let $a,b,p$ be \typ{INT}s, with $p > 1$ odd, such that $a^2\equiv b\mod p$. Returns a \typ{INT} $A$ such that $A^2 \equiv b \mod p^e$. Special case of \tet{Zp_sqrtnlift}. \fun{GEN}{Zp_sqrtnlift}{GEN b, GEN n, GEN a, GEN p, long e} let $a,b,n,p$ be \typ{INT}s, with $n,p > 1$, and $p$ coprime to $n$, such that $a^n \equiv b \mod p$. Returns a \typ{INT} $A$ such that $A^n \equiv b \mod p^e$. Special case of \tet{ZpX_liftroot}. \fun{GEN}{Zp_teichmuller}{GEN x, GEN p, long e, GEN pe} for $p$ an odd prime, $x$ a \typ{INT} coprime to $p$, and $pe = p^e$, returns the $(p-1)$-th root of $1$ congruent to $x$ modulo $p$, modulo $p^e$. For convenience, $p = 2$ is also allowed and we return $1$ ($x$ is $1$ mod $4$) or $2^e - 1$ ($x$ is $3$ mod $4$). \fun{GEN}{teichmullerinit}{long p, long n} returns the values of \tet{Zp_teichmuller} at all $x = 1, \dots, p-1$. \subsec{ZpX} \fun{GEN}{ZpX_roots}{GEN f, GEN p, long e} $f$ a \kbd{ZX} with leading term prime to $p$, and without multiple roots mod $p$. Return a vector of \typ{INT}s which are the roots of $f$ mod $p^e$. \fun{GEN}{ZpX_liftroot}{GEN f, GEN a, GEN p, long e} $f$ a \kbd{ZX} with leading term prime to $p$, and $a$ a root mod $p$ such that $v_p(f'(a))=0$. Return a \typ{INT} which is the root of $f$ mod $p^e$ congruent to $a$ mod $p$. \fun{GEN}{ZX_Zp_root}{GEN f, GEN a, GEN p, long e} same as \tet{ZpX_liftroot} without the assumption $v_p(f'(a)) = 0$. Return a \typ{VEC} of \typ{INT}s, which are the $p$-adic roots of $f$ congruent to $a$ mod $p$ (given modulo $p^e$). \fun{GEN}{ZpX_liftroots}{GEN f, GEN S, GEN p, long e} $f$ a \kbd{ZX} with leading term prime to $p$, and $S$ a vector of simple roots mod $p$. Return a vector of \typ{INT}s which are the root of $f$ mod $p^e$ congruent to the $S[i]$ mod $p$. \fun{GEN}{ZpX_liftfact}{GEN A, GEN B, GEN pe, GEN p, long e} is the routine underlying \tet{polhensellift}. Here, $p$ is prime defines a finite field $\F_p$. $A$ is a polynomial in $\Z[X]$, whose leading coefficient is non-zero in $\F_q$. $B$ is a vector of monic \kbd{FpX}, pairwise coprime in $\F_p[X]$, whose product is congruent to $A/\text{lc}(A)$ in $\F_p[X]$. Lifts the elements of $B$ mod $\kbd{pe} = p^e$. \fun{GEN}{ZpX_Frobenius}{GEN T, GEN p, ulong e} returns the $p$-adic lift of the Frobenius automorphism of $\F_p[X]/(T)$ to precision $e$. \fun{long}{ZpX_disc_val}{GEN f, GEN p} returns the valuation at $p$ of the discriminant of $f$. Assume that $f$ is a monic \emph{separable} \kbd{ZX} and that $p$ is a prime number. Proceeds by dynamically increasing the $p$-adic accuracy; infinite loop if the discriminant of $f$ is $0$. \fun{long}{ZpX_resultant_val}{GEN f, GEN g, GEN p, long M} returns the valuation at $p$ of $\text{Res}(f,g)$. Assume $f,g$ are both \kbd{ZX}, and that $p$ is a prime number coprime to the leading coefficient of $f$. Proceeds by dynamically increasing the $p$-adic accuracy. To avoid an infinite loop when the resultant is $0$, we return $M$ if the Sylvester matrix mod $p^M$ still does not have maximal rank. \fun{GEN}{ZpX_gcd}{GEN f,GEN g, GEN p, GEN pm} $f$ a monic \kbd{ZX}, $g$ a \kbd{ZX}, $\kbd{pm} = p^m$ a prime power. There is a unique integer $r\geq 0$ and a monic $h\in \Q_p[X]$ such that $$p^rh\Z_p[X] + p^m\Z_p[X] = f\Z_p[X] + g\Z_p[X] + p^m\Z_p[X].$$ Return the $0$ polynomial if $r\geq m$ and a monic $h\in\Z[1/p][X]$ otherwise (whose valuation at $p$ is $> -m$). \fun{GEN}{ZpX_reduced_resultant}{GEN f, GEN g, GEN p, GEN pm} $f$ a monic \kbd{ZX}, $g$ a \kbd{ZX}, $\kbd{pm} = p^m$ a prime power. The $p$-adic \emph{reduced resultant}\varsidx{resultant (reduced)} of $f$ and $g$ is $0$ if $f$, $g$ not coprime in $\Z_p[X]$, and otherwise the generator of the form $p^d$ of $$ (f\Z_p[X] + g\Z_p[X])\cap \Z_p. $$ Return the reduced resultant modulo $p^m$. \fun{GEN}{ZpX_reduced_resultant_fast}{GEN f, GEN g, GEN p, long M} $f$ a monic \kbd{ZX}, $g$ a \kbd{ZX}, $p$ a prime. Returns the $p$-adic reduced resultant of $f$ and $g$ modulo $p^M$. This function computes resultants for a sequence of increasing $p$-adic accuracies (up to $M$ $p$-adic digits), returning as soon as it obtains a non-zero result. It is very inefficient when the resultant is $0$, but otherwise usually more efficient than computations using a priori bounds. \fun{GEN}{ZpX_monic_factor}{GEN f, GEN p, long M} $f$ a monic \kbd{ZX}, $p$ a primer, return the $p$-adic factorization of $f$, modulo $p^M$. This is the underlying low-level recursive function behind \kbd{factorpadic} (using a combination of Round 4 factorization and Hensel lifting); the factors are not sorted and the function is not \kbd{gerepile}-clean. \subsec{ZpXQ} \fun{GEN}{ZpXQ_invlift}{GEN b, GEN a, GEN T, GEN p, long e} let $p$ be a prime \typ{INT} and $a,b$ be \kbd{FpXQ}s (modulo $T$) such that $a\*b \equiv 1 \mod (p,T)$. Returns an \kbd{FpXQ} $A$ such that $A\*b \equiv 1 \mod (p^e, T)$. Special case of \tet{ZpXQ_liftroot}. \fun{GEN}{ZpXQ_inv}{GEN b, GEN T, GEN p, long e} let $p$ be a prime \typ{INT} and $b$ be a \kbd{FpXQ} (modulo $T, p^e$). Returns an \kbd{FpXQ} $A$ such that $A\*b \equiv 1 \mod (p^e, T)$. \fun{GEN}{ZpXQ_div}{GEN a, GEN b, GEN T, GEN q, GEN p, long e} let $p$ be a prime \typ{INT} and $a$ and $b$ be a \kbd{FpXQ} (modulo $T, p^e$). Returns an \kbd{FpXQ} $c$ such that $c\*b \equiv a \mod (p^e, T)$. The parameter $q$ must be equal to $p^e$. \fun{GEN}{ZpXQ_sqrtnlift}{GEN b, GEN n, GEN a, GEN T, GEN p, long e} let $n,p$ be \typ{INT}s, with $n,p > 1$ and $p$ coprime to $n$, and $a,b$ be \kbd{FpXQ}s (modulo $T$) such that $a^n \equiv b \mod (p,T)$. Returns an \kbd{Fq} $A$ such that $A^n \equiv b \mod (p^e, T)$. Special case of \tet{ZpXQ_liftroot}. \fun{GEN}{ZpXQ_sqrt}{GEN b, GEN T, GEN p, long e} let $p$ being a odd prime and $b$ be a \kbd{FpXQ} (modulo $T, p^e$), returns $a$ such that $a^2 \equiv b \mod (p^e, T)$. \fun{GEN}{ZpX_ZpXQ_liftroot}{GEN f, GEN a, GEN T, GEN p, long e} as \tet{ZpXQX_liftroot}, but $f$ is a polynomial in $\Z[X]$. \fun{GEN}{ZpX_ZpXQ_liftroot_ea}{GEN f, GEN a, GEN T, GEN p, long e, void *E, int early(void *E, GEN x, GEN q)} as \tet{ZpX_ZpXQ_liftroot} with early abort: the function \kbd{early(E,x,q)} will be called with $x$ is a root of $f$ modulo $q=p^n$ for some $n$. If \kbd{early} returns a non-zero value, the function returns $x$ immediately. \fun{GEN}{ZpXQ_log}{GEN a, GEN T, GEN p, long e} $T$ being a \kbd{ZpX} irreducible modulo $p$, return the logarithm of $a$ in $\Z_p[X]/(T)$ to precision $e$, assuming that $a\equiv 1 \pmod{p\Z_p[X]}$ if $p$ odd or $a\equiv 1 \pmod{4\Z_2[X]}$ if $p=2$. \subsec{Zq} \fun{GEN}{Zq_sqrtnlift}{GEN b, GEN n, GEN a, GEN T, GEN p, long e} \subsec{ZpXQM} \fun{GEN}{ZpXQM_prodFrobenius}{GEN M, GEN T, GEN p, long e} returns the product of matrices $M\*\sigma(M)\*\sigma^2(M)\ldots\sigma^{n-1}(M)$ to precision $e$ where $\sigma$ is the lift of the Frobenius automorphism over $\Z_p[X]/(T)$ and $n$ is the degree of $T$. \subsec{ZpXQX} \fun{GEN}{ZpXQX_liftfact}{GEN A, GEN B, GEN T, GEN pe, GEN p, long e} is the routine underlying \tet{polhensellift}. Here, $p$ is prime, $T(Y)$ defines a finite field $\F_q$. $A$ is a polynomial in $\Z[X,Y]$, whose leading coefficient is non-zero in $\F_q$. $B$ is a vector of monic or \kbd{FqX}, pairwise coprime in $\F_q[X]$, whose product is congruent to $A/\text{lc}(A)$ in $\F_q[X]$. Lifts the elements of $B$ mod $\kbd{pe} = p^e$, such that the congruence now holds mod $(T,p^e)$. \fun{GEN}{ZpXQX_liftroot}{GEN f, GEN a, GEN T, GEN p, long e} as \tet{ZpX_liftroot}, but $f$ is now a polynomial in $\Z[X,Y]$ and lift the root $a$ in the unramified extension of $\Q_p$ with residue field $\F_p[Y]/(T)$, assuming $v_p(f(a))>0$ and $v_p(f'(a))=0$. \fun{GEN}{ZpXQX_liftroot_vald}{GEN f, GEN a, long v, GEN T, GEN p, long e} returns the foots of $f$ as \tet{ZpXQX_liftroot}, where $v$ is the valuation of the content of $f'$ and it is required that $v_p(f(a))>v$ and $v_p(f'(a))=v$. \fun{GEN}{ZpXQX_roots}{GEN F, GEN T, GEN p, long e} \fun{GEN}{ZpXQX_divrem}{GEN x, GEN Sp, GEN T,GEN q,GEN p,long e, GEN *pr} as \kbd{FpXQX\_divrem}. The parameter $q$ must be equal to $p^e$. \fun{GEN}{ZpXQX_digits}{GEN x, GEN B, GEN T, GEN q, GEN p, long e} As \kbd{FpXQX\_digits}. The parameter $q$ must be equal to $p^e$. \subsec{ZqX} \fun{GEN}{ZqX_roots}{GEN F, GEN T, GEN p, long e} \fun{GEN}{ZqX_liftfact}{GEN A, GEN B, GEN T, GEN pe, GEN p, long e} \fun{GEN}{ZqX_liftroot}{GEN f, GEN a, GEN T, GEN p, long e} \subsec{Other $p$-adic functions} \fun{GEN}{ZpM_echelon}{GEN M, long early_abort, GEN p, GEN pm} given a \kbd{ZM} $M$, a prime $p$ and $\kbd{pm} = p^m$, returns an echelon form $E$ for $M$ mod $p^m$. I.e. there exist a square integral matrix $U$ with $\det U$ coprime to $p$ such that $E = MU$ modulo $p^m$. I \kbd{early\_abort} is non-zero, return NULL as soon as one pivot in the echelon form is divisible by $p^m$. The echelon form is an upper triangular HNF, we do not waste time to reduce it to Gauss-Jordan form. \fun{GEN}{zlm_echelon}{GEN M, long early_abort, ulong p, ulong pm} variant of \kbd{ZpM\_echelon}, for a \kbd{Zlm} $M$. \fun{GEN}{ZlM_gauss}{GEN a, GEN b, ulong p, long e, GEN C} as \kbd{gauss} with the following peculiarities: $a$ and $b$ are \kbd{ZM}, such that $a$ is invertible modulo $p$. Optional $C$ is an \kbd{Flm} that is an inverse of $a\mod p$ or \kbd{NULL}. Return the matrix $x$ such that $ax=b\mod p^e$ and all elements of $x$ are in $[0,p^e-1]$. For efficiency, it is better to reduce $a$ and $b$ mod $p^e$ first. \fun{GEN}{padic_to_Q}{GEN x} truncate the \typ{PADIC} to a \typ{INT} or \typ{FRAC}. \fun{GEN}{padic_to_Q_shallow}{GEN x} shallow version of \tet{padic_to_Q} \fun{GEN}{QpV_to_QV}{GEN v} apply \tet{padic_to_Q_shallow} \fun{long}{padicprec}{GEN x, GEN p} returns the absolute $p$-adic precision of the object $x$, by definition the minimum precision of the components of $x$. For a non-zero \typ{PADIC}, this returns \kbd{valp(x) + precp(x)}. \fun{long}{padicprec_relative}{GEN x} returns the relative $p$-adic precision of the \typ{INT}, \typ{FRAC}, or \typ{PADIC} $x$ (minimum precision of the components of $x$ for \typ{POL} or vector/matrices). For a \typ{PADIC}, this returns \kbd{precp(x)} if $x\neq0$, and $0$ for $x=0$. \subsubsec{low-level} The following technical function returns an optimal sequence of $p$-adic accuracies, for a given target accuracy: \fun{ulong}{quadratic_prec_mask}{long n} we want to reach accuracy $n\geq 1$, starting from accuracy 1, using a quadratically convergent, self-correcting, algorithm; in other words, from inputs correct to accuracy $l$ one iteration outputs a result correct to accuracy $2l$. For instance, to reach $n = 9$, we want to use accuracies $[1,2,3,5,9]$ instead of $[1,2,4,8,9]$. The idea is to essentially double the accuracy at each step, and not overshoot in the end. Let $a_0$ = 1, $a_1 = 2, \ldots, a_k = n$, be the desired sequence of accuracies. To obtain it, we work backwards and set $$ a_k = n,\quad a_{i-1} = (a_i + 1)\,\bs\, 2.$$ This is in essence what the function returns. But we do not want to store the $a_i$ explicitly, even as a \typ{VECSMALL}, since this would leave an object on the stack. Instead, we store $a_i$ implicitly in a bitmask \kbd{MASK}: let $a_0 = 1$, if the $i$-th bit of the mask is set, set $a_{i+1} = 2a_i - 1$, and $2a_i$ otherwise; in short the bits indicate the places where we do something special and do not quite double the accuracy (which would be the straightforward thing to do). In fact, to avoid returning separately the mask and the sequence length $k+1$, the function returns $\kbd{MASK} + 2^{k+1}$, so the highest bit of the mask indicates the length of the sequence, and the following ones give an algorithm to obtain the accuracies. This is much simpler than it sounds, here is what it looks like in practice: \bprog ulong mask = quadratic_prec_mask(n); long l = 1; while (mask > 1) { /* here, the result is known to accuracy l */ l = 2*l; if (mask & 1) l--; /* new accuracy l for the iteration */ mask >>= 1; /* pop low order bit */ /* ... lift to the new accuracy ... */ } /* we are done. At this point l = n */ @eprog\noindent We just pop the bits in \kbd{mask} starting from the low order bits, stop when \kbd{mask} is $1$ (that last bit corresponds to the $2^{k+1}$ that we added to the mask proper). Note that there is nothing specific to Hensel lifts in that function: it would work equally well for an Archimedean Newton iteration. Note that in practice, we rather use an infinite loop, and insert an \bprog if (mask == 1) break; @eprog\noindent in the middle of the loop: the loop body usually includes preparations for the next iterations (e.g. lifting Bezout coefficients in a quadratic Hensel lift), which are costly and useless in the \emph{last} iteration. \subsec{Conversions involving single precision objects} \subsubsec{To single precision} \fun{ulong}{Rg_to_Fl}{GEN z, ulong p}, \kbd{z} which can be mapped to $\Z/p\Z$: a \typ{INT}, a \typ{INTMOD} whose modulus is divisible by $p$, a \typ{FRAC} whose denominator is coprime to $p$, or a \typ{PADIC} with underlying prime $\ell$ satisfying $p = \ell^n$ for some $n$ (less than the accuracy of the input). Returns \kbd{lift(z * Mod(1,p))}, normalized, as an \kbd{Fl}. \fun{ulong}{Rg_to_F2}{GEN z}, as \tet{Rg_to_Fl} for $p = 2$. \fun{ulong}{padic_to_Fl}{GEN x, ulong p} special case of \tet{Rg_to_Fl}, for a $x$ a \typ{PADIC}. \fun{GEN}{RgX_to_F2x}{GEN x}, \kbd{x} a \typ{POL}, returns the \kbd{F2x} obtained by applying \kbd{Rg\_to\_Fl} coefficientwise. \fun{GEN}{RgX_to_Flx}{GEN x, ulong p}, \kbd{x} a \typ{POL}, returns the \kbd{Flx} obtained by applying \kbd{Rg\_to\_Fl} coefficientwise. \fun{GEN}{Rg_to_F2xq}{GEN z, GEN T}, \kbd{z} a \kbd{GEN} which can be mapped to $\F_2[X]/(T)$: anything \kbd{Rg\_to\_Fl} can be applied to, a \typ{POL} to which \kbd{RgX\_to\_F2x} can be applied to, a \typ{POLMOD} whose modulus is divisible by $T$ (once mapped to a \kbd{F2x}), a suitable \typ{RFRAC}. Returns \kbd{z} as an \kbd{F2xq}, normalized. \fun{GEN}{Rg_to_Flxq}{GEN z, GEN T, ulong p}, \kbd{z} a \kbd{GEN} which can be mapped to $\F_p[X]/(T)$: anything \kbd{Rg\_to\_Fl} can be applied to, a \typ{POL} to which \kbd{RgX\_to\_Flx} can be applied to, a \typ{POLMOD} whose modulus is divisible by $T$ (once mapped to a \kbd{Flx}), a suitable \typ{RFRAC}. Returns \kbd{z} as an \kbd{Flxq}, normalized. \fun{GEN}{RgX_to_FlxqX}{GEN z, GEN T, ulong p}, \kbd{z} a \kbd{GEN} which can be mapped to $\F_p[x]/(T)[X]$: anything \kbd{Rg\_to\_Flxq} can be applied to, a \typ{POL} to which \kbd{RgX\_to\_Flx} can be applied to, a \typ{POLMOD} whose modulus is divisible by $T$ (once mapped to a \kbd{Flx}), a suitable \typ{RFRAC}. Returns \kbd{z} as an \kbd{FlxqX}, normalized. \fun{GEN}{ZX_to_Flx}{GEN x, ulong p} reduce \kbd{ZX}~\kbd{x} modulo \kbd{p} (yielding an \kbd{Flx}). Faster than \kbd{RgX\_to\_Flx}. \fun{GEN}{ZV_to_Flv}{GEN x, ulong p} reduce \kbd{ZV}~\kbd{x} modulo \kbd{p} (yielding an \kbd{Flv}). \fun{GEN}{ZXV_to_FlxV}{GEN v, ulong p}, as \kbd{ZX\_to\_Flx}, repeatedly called on the vector's coefficients. \fun{GEN}{ZXT_to_FlxT}{GEN v, ulong p}, as \kbd{ZX\_to\_Flx}, repeatedly called on the tree leaves. \fun{GEN}{ZXX_to_FlxX}{GEN B, ulong p, long v}, as \kbd{ZX\_to\_Flx}, repeatedly called on the polynomial's coefficients. \fun{GEN}{zxX_to_FlxX}{GEN z, ulong p} as \kbd{zx\_to\_Flx}, repeatedly called on the polynomial's coefficients. \fun{GEN}{ZXXV_to_FlxXV}{GEN V, ulong p, long v}, as \kbd{ZXX\_to\_FlxX}, repeatedly called on the vector's coefficients. \fun{GEN}{ZXXT_to_FlxXT}{GEN V, ulong p, long v}, as \kbd{ZXX\_to\_FlxX}, repeatedly called on the tree leaves. \fun{GEN}{RgV_to_Flv}{GEN x, ulong p} reduce the \typ{VEC}/\typ{COL} $x$ modulo $p$, yielding a \typ{VECSMALL}. \fun{GEN}{RgM_to_Flm}{GEN x, ulong p} reduce the \typ{MAT} $x$ modulo $p$. \fun{GEN}{ZM_to_Flm}{GEN x, ulong p} reduce \kbd{ZM}~$x$ modulo $p$ (yielding an \kbd{Flm}). \fun{GEN}{ZV_to_zv}{GEN z}, converts coefficients using \kbd{itos} \fun{GEN}{ZV_to_nv}{GEN z}, converts coefficients using \kbd{itou} \fun{GEN}{ZM_to_zm}{GEN z}, converts coefficients using \kbd{itos} \fun{GEN}{FqC_to_FlxC}{GEN x, GEN T, GEN p}, converts coefficients in \kbd{Fq} to coefficient in Flx, result being a column vector. \fun{GEN}{FqV_to_FlxV}{GEN x, GEN T, GEN p}, converts coefficients in \kbd{Fq} to coefficient in Flx, result being a line vector. \fun{GEN}{FqM_to_FlxM}{GEN x, GEN T, GEN p}, converts coefficients in \kbd{Fq} to coefficient in Flx. \subsubsec{From single precision} \fun{GEN}{Flx_to_ZX}{GEN z}, converts to \kbd{ZX} (\typ{POL} of non-negative \typ{INT}s in this case) \fun{GEN}{Flx_to_FlxX}{GEN z}, converts to \kbd{FlxX} (\typ{POL} of constant \kbd{Flx} in this case). \fun{GEN}{Flx_to_ZX_inplace}{GEN z}, same as \kbd{Flx\_to\_ZX}, in place (\kbd{z} is destroyed). \fun{GEN}{FlxX_to_ZXX}{GEN B}, converts an \kbd{FlxX} to a polynomial with \kbd{ZX} or \typ{INT} coefficients (repeated calls to \kbd{Flx\_to\_ZX}). \fun{GEN}{FlxXC_to_ZXXC}{GEN B}, converts an \kbd{FlxXC} to a \typ{COL} with \kbd{ZXX} coefficients (repeated calls to \kbd{FlxX\_to\_ZXX}). \fun{GEN}{FlxXM_to_ZXXM}{GEN B}, converts an \kbd{FlxXM} to a \typ{MAT} with \kbd{ZXX} coefficients (repeated calls to \kbd{FlxX\_to\_ZXX}). \fun{GEN}{FlxC_to_ZXC}{GEN x}, converts a vector of \kbd{Flx} to a column vector of polynomials with \typ{INT} coefficients (repeated calls to \kbd{Flx\_to\_ZX}). \fun{GEN}{FlxV_to_ZXV}{GEN x}, as above but return a \typ{VEC}. \fun{void}{F2xV_to_FlxV_inplace}{GEN v} v is destroyed. \fun{void}{F2xV_to_ZXV_inplace}{GEN v} v is destroyed. \fun{void}{FlxV_to_ZXV_inplace}{GEN v} v is destroyed. \fun{GEN}{FlxM_to_ZXM}{GEN z}, converts a matrix of \kbd{Flx} to a matrix of polynomials with \typ{INT} coefficients (repeated calls to \kbd{Flx\_to\_ZX}). \fun{GEN}{zx_to_ZX}{GEN z}, as \kbd{Flx\_to\_ZX}, without assuming the coefficients to be non-negative. \fun{GEN}{zx_to_Flx}{GEN z, ulong p} as \kbd{Flx\_red} without assuming the coefficients to be non-negative. \fun{GEN}{Flc_to_ZC}{GEN z}, converts to \kbd{ZC} (\typ{COL} of non-negative \typ{INT}s in this case) \fun{GEN}{Flc_to_ZC_inplace}{GEN z}, same as \kbd{Flc\_to\_ZC}, in place (\kbd{z} is destroyed). \fun{GEN}{Flv_to_ZV}{GEN z}, converts to \kbd{ZV} (\typ{VEC} of non-negative \typ{INT}s in this case) \fun{GEN}{Flm_to_ZM}{GEN z}, converts to \kbd{ZM} (\typ{MAT} with non-negative \typ{INT}s coefficients in this case) \fun{GEN}{Flm_to_ZM_inplace}{GEN z}, same as \kbd{Flm\_to\_ZM}, in place (\kbd{z} is destroyed). \fun{GEN}{zc_to_ZC}{GEN z} as \kbd{Flc\_to\_ZC}, without assuming coefficients are non-negative. \fun{GEN}{zv_to_ZV}{GEN z} as \kbd{Flv\_to\_ZV}, without assuming coefficients are non-negative. \fun{GEN}{zm_to_ZM}{GEN z} as \kbd{Flm\_to\_ZM}, without assuming coefficients are non-negative. \fun{GEN}{zv_to_Flv}{GEN z, ulong p} \fun{GEN}{zm_to_Flm}{GEN z, ulong p} \subsubsec{Mixed precision linear algebra} Assumes dimensions are compatible. Multiply a multiprecision object by a single-precision one. \fun{GEN}{RgM_zc_mul}{GEN x, GEN y} \fun{GEN}{RgMrow_zc_mul}{GEN x, GEN y, long i} \fun{GEN}{RgM_zm_mul}{GEN x, GEN y} \fun{GEN}{RgV_zc_mul}{GEN x, GEN y} \fun{GEN}{RgV_zm_mul}{GEN x, GEN y} \fun{GEN}{ZM_zc_mul}{GEN x, GEN y} \fun{GEN}{zv_ZM_mul}{GEN x, GEN y} \fun{GEN}{ZV_zc_mul}{GEN x, GEN y} \fun{GEN}{ZM_zm_mul}{GEN x, GEN y} \fun{GEN}{ZC_z_mul}{GEN x, long y} \fun{GEN}{ZM_nm_mul}{GEN x, GEN y} the entries of $y$ are \kbd{ulong}s. \fun{GEN}{nm_Z_mul}{GEN y, GEN c} the entries of $y$ are \kbd{ulong}s. \subsubsec{Miscellaneous involving Fl} \fun{GEN}{Fl_to_Flx}{ulong x, long evx} converts a \kbd{unsigned long} to a scalar \kbd{Flx}. Assume that \kbd{evx = evalvarn(vx)} for some variable number \kbd{vx}. \fun{GEN}{Z_to_Flx}{GEN x, ulong p, long sv} converts a \typ{INT} to a scalar \kbd{Flx} polynomial. Assume that \kbd{sv = evalvarn(v)} for some variable number \kbd{v}. \fun{GEN}{Flx_to_Flv}{GEN x, long n} converts from \kbd{Flx} to \kbd{Flv} with \kbd{n} components (assumed larger than the number of coefficients of \kbd{x}). \fun{GEN}{zx_to_zv}{GEN x, long n} as \kbd{Flx\_to\_Flv}. \fun{GEN}{Flv_to_Flx}{GEN x, long sv} converts from vector (coefficient array) to (normalized) polynomial in variable $v$. \fun{GEN}{zv_to_zx}{GEN x, long n} as \kbd{Flv\_to\_Flx}. \fun{GEN}{Flm_to_FlxV}{GEN x, long sv} converts the columns of \kbd{Flm}~\kbd{x} to an array of \kbd{Flx} in the variable $v$ (repeated calls to \kbd{Flv\_to\_Flx}). \fun{GEN}{zm_to_zxV}{GEN x, long n} as \kbd{Flm\_to\_FlxV}. \fun{GEN}{Flm_to_FlxX}{GEN x, long sw, long sv} same as \kbd{Flm\_to\_FlxV(x,sv)} but returns the result as a (normalized) polynomial in variable $w$. \fun{GEN}{FlxV_to_Flm}{GEN v, long n} reverse \kbd{Flm\_to\_FlxV}, to obtain an \kbd{Flm} with \kbd{n} rows (repeated calls to \kbd{Flx\_to\_Flv}). \fun{GEN}{FlxX_to_Flx}{GEN P} Let $P(x,X)$ be a \kbd{FlxX}, return $P(0,X)$ as a \kbd{Flx}. \fun{GEN}{FlxX_to_Flm}{GEN v, long n} reverse \kbd{Flm\_to\_FlxX}, to obtain an \kbd{Flm} with \kbd{n} rows (repeated calls to \kbd{Flx\_to\_Flv}). \fun{GEN}{FlxX_to_FlxC}{GEN B, long n, long sv} see \kbd{RgX\_to\_RgV}. The coefficients of \kbd{B} are assumed to be in the variable $v$. \fun{GEN}{FlxXV_to_FlxM}{GEN V, long n, long sv} see \kbd{RgXV\_to\_RgM}. The coefficients of \kbd{V[i]} are assumed to be in the variable $v$. \fun{GEN}{Fly_to_FlxY}{GEN a, long sv} convert coefficients of \kbd{a} to constant \kbd{Flx} in variable $v$. \subsubsec{Miscellaneous involving \kbd{F2x}} \fun{GEN}{F2x_to_F2v}{GEN x, long n} converts from \kbd{F2x} to \kbd{F2v} with \kbd{n} components (assumed larger than the number of coefficients of \kbd{x}). \fun{GEN}{F2xC_to_ZXC}{GEN x}, converts a vector of \kbd{F2x} to a column vector of polynomials with \typ{INT} coefficients (repeated calls to \kbd{F2x\_to\_ZX}). \fun{GEN}{F2xC_to_FlxC}{GEN x} \fun{GEN}{FlxC_to_F2xC}{GEN x} \fun{GEN}{F2xV_to_F2m}{GEN v, long n} \kbd{F2x\_to\_F2v} to each polynomial to get an \kbd{F2m} with \kbd{n} rows. \section{Higher arithmetic over $\Z$: primes, factorization} \subsec{Pure powers} \fun{long}{Z_issquare}{GEN n} returns $1$ if the \typ{INT} $n$ is a square, and $0$ otherwise. This is tested first modulo small prime powers, then \kbd{sqrtremi} is called. \fun{long}{Z_issquareall}{GEN n, GEN *sqrtn} as \kbd{Z\_issquare}. If $n$ is indeed a square, set \kbd{sqrtn} to its integer square root. Uses a fast congruence test mod $64\times 63\times 65\times 11$ before computing an integer square root. \fun{long}{Z_ispow2}{GEN x} returns $1$ if the \typ{INT} $x$ is a power of $2$, and $0$ otherwise. \fun{long}{uissquare}{ulong n} as \kbd{Z\_issquare}, for an \kbd{ulong} operand \kbd{n}. \fun{long}{uissquareall}{ulong n, ulong *sqrtn} as \kbd{Z\_issquareall}, for an \kbd{ulong} operand \kbd{n}. \fun{ulong}{usqrt}{ulong a} returns the floor of the square root of $a$. \fun{ulong}{usqrtn}{ulong a, ulong n} returns the floor of the $n$-th root of $a$. \fun{long}{Z_ispower}{GEN x, ulong k} returns $1$ if the \typ{INT} $n$ is a $k$-th power, and $0$ otherwise; assume that $k > 1$. \fun{long}{Z_ispowerall}{GEN x, ulong k, GEN *pt} as \kbd{Z\_ispower}. If $n$ is indeed a $k$-th power, set \kbd{*pt} to its integer $k$-th root. \fun{long}{Z_isanypower}{GEN x, GEN *ptn} returns the maximal $k\geq 2$ such that the \typ{INT} $x = n^k$ is a perfect power, or $0$ if no such $k$ exist; in particular \kbd{ispower(1)}, \kbd{ispower(0)}, \kbd{ispower(-1)} all return 0. If the return value $k$ is not $0$ (so that $x = n^k$) and \kbd{ptn} is not \kbd{NULL}, set \kbd{*ptn} to $n$. The following low-level functions are called by \tet{Z_isanypower} but can be directly useful: \fun{int}{is_357_power}{GEN x, GEN *ptn, ulong *pmask} tests whether the integer $x > 0$ is a $3$-rd, $5$-th or $7$-th power. The bits of \kbd{*mask} initially indicate which test is to be performed; bit $0$: $3$-rd, bit $1$: $5$-th, bit $2$: $7$-th (e.g.~$\kbd{*pmask} = 7$ performs all tests). They are updated during the call: if the ``$i$-th power'' bit is set to $0$ then $x$ is not a $k$-th power. The function returns $0$ (not a $3$-rd, $5$-th or $7$-th power), $3$ ($3$-rd power, not a $5$-th or $7$-th power), $5$ ($5$-th power, not a $7$-th power), or $7$ ($7$-th power); if an $i$-th power bit is initially set to $0$, we take it at face value and assume $x$ is not an $i$-th power without performing any test. If the return value $k$ is non-zero, set \kbd{*ptn} to $n$ such that $x = n^k$. \fun{int}{is_pth_power}{GEN x, GEN *ptn, forprime_t *T, ulong cutoff} let $x > 0$ be an integer, $\kbd{cutoff} > 0$ and $T$ be an iterator over primes $\geq 11$, we look for the smallest prime $p$ such that $x = n^p$ (advancing $T$ as we go along). The $11$ is due to the fact that \tet{is_357_power} and \kbd{issquare} are faster than the generic version for $p < 11$. Fail and return $0$ when the existence of $p$ would imply $2^{\kbd{cutoff}} > x^{1/p}$, meaning that a possible $n$ is so small that it should have been found by trial division; for maximal speed, you should start by a round of trial division, but the cut-off may also be set to $1$ for a rigorous result without any trial division. Otherwise returns the smallest suitable prime power $p^i$ and set \kbd{*ptn} to the $p^i$-th root of $x$ (which is now not a $p$-th power). We may immediately recall the function with the same parameters after setting $x = \kbd{*ptn}$: it will start at the next prime. \subsec{Factorization} \fun{GEN}{Z_factor}{GEN n} factors the \typ{INT} \kbd{n}. The ``primes'' in the factorization are actually strong pseudoprimes. \fun{GEN}{absZ_factor}{GEN n} returns \kbd{Z\_factor(absi(n))}. \fun{long}{Z_issmooth}{GEN n, ulong lim} returns $1$ if all the prime factors of the \typ{INT} $n$ are less or equal to $lim$. \fun{GEN}{Z_issmooth_fact}{GEN n, ulong lim} returns \kbd{NULL} if a prime factor of the \typ{INT} $n$ is $> lim$, and returns the factorization of $n$ otherwise, as a \typ{MAT} with \typ{VECSMALL} columns (word-size primes and exponents). Neither memory-clean nor suitable for \kbd{gerepileupto}. \fun{GEN}{Z_factor_until}{GEN n, GEN lim} as \kbd{Z\_factor}, but stop the factorization process as soon as the unfactored part is smaller than \kbd{lim}. The resulting factorization matrix only contains the factors found. No other assumptions can be made on the remaining factors. \fun{GEN}{Z_factor_limit}{GEN n, ulong lim} trial divide $n$ by all primes $p < \kbd{lim}$ in the precomputed list of prime numbers and return the corresponding factorization matrix. In this case, the last ``prime'' divisor in the first column of the factorization matrix may well be a proven composite. If $\kbd{lim} = 0$, the effect is the same as setting $\kbd{lim} = \kbd{maxprime()} + 1$: use all precomputed primes. \fun{GEN}{absZ_factor_limit}{GEN n, ulong all}returns \kbd{Z\_factor\_limit(absi(n))}. \fun{GEN}{boundfact}{GEN x, ulong lim} as \tet{Z_factor_limit}, applying to \typ{INT} or \typ{FRAC} inputs. \fun{GEN}{Z_smoothen}{GEN n, GEN L, GEN *pP, GEN *pE} given a \typ{VECSMALL} $L$ containing a list of small primes and a \typ{INT} $n$, trial divide $n$ by the elements of $L$ and return the cofactor. Return \kbd{NULL} if the cofactor is $\pm 1$. \kbd{*P} and \kbd{*E} contain the list of prime divisors found and their exponents, as \typ{VECSMALL}s. Neither memory-clean, nor suitable for \tet{gerepileupto}. \fun{GEN}{Z_factor_listP}{GEN N, GEN L} given a \typ{INT} $N$, a vector or primes $L$ containing all prime divisors of $N$ (and possibly others). Return \kbd{factor(N)}. Neither memory-clean, nor suitable for \tet{gerepileupto}. \fun{GEN}{factor_pn_1}{GEN p, ulong n} returns the factorization of $p^n-1$, where $p$ is prime and $n$ is a positive integer. \fun{GEN}{factor_pn_1_limit}{GEN p, ulong n, ulong B} returns a partial factorization of $p^n-1$, where $p$ is prime and $n$ is a positive integer. Don't actively search for prime divisors $p > B$, but we may find still find some due to Aurifeuillian factorizations. Any entry $> B^2$ in the output factorization matrix is \emph{a priori} not a prime (but may well be). \fun{GEN}{factor_Aurifeuille_prime}{GEN p, long n} an Aurifeuillian factor of $\phi_n(p)$, assuming $p$ prime and an Aurifeuillian factor exists ($p \zeta_n$ is a square in $\Q(\zeta_n)$). \fun{GEN}{factor_Aurifeuille}{GEN a, long d} an Aurifeuillian factor of $\phi_n(a)$, assuming $a$ is a non-zero integer and $n > 2$. Returns $1$ if no Aurifeuillian factor exists. \fun{GEN}{odd_prime_divisors}{GEN a} \typ{VEC} of all prime divisors of the \typ{INT} $a$. \fun{GEN}{factoru}{ulong n}, returns the factorization of $n$. The result is a $2$-component vector $[P,E]$, where $P$ and $E$ are \typ{VECSMALL} containing the prime divisors of $n$, and the $v_p(n)$. \fun{GEN}{factoru_pow}{ulong n}, returns the factorization of $n$. The result is a $3$-component vector $[P,E,C]$, where $P$, $E$ and $C$ are \typ{VECSMALL} containing the prime divisors of $n$, the $v_p(n)$ and the $p^{v_p(n)}$. \fun{GEN}{vecfactoru}{ulong a, ulong b}, returns a \typ{VEC} $v$ containing the factorizations (\tet{factoru} format) of $a,\dots, b$; assume that $b \geq a > 0$. Uses a sieve with primes up to $\sqrt{b}$. For all $c$, $a \leq c \leq b$, the factorization of $c$ is given in $v[c-a+1]$. \fun{GEN}{vecfactoroddu}{ulong a, ulong b}, returns a \typ{VEC} $v$ containing the factorizations (\tet{factoru} format) of odd integers in $a,\dots, b$; assume that $b \geq a > 0$ are odd. Uses a sieve with primes up to $\sqrt{b}$. For all odd $c$, $a \leq c \leq b$, the factorization of $c$ is given in in $v[(c-a)/2 + 1]$. \fun{GEN}{vecfactoru_i}{ulong a, ulong b}, private version of \kbd{vecfactoru}, not memory clean. \fun{GEN}{vecfactoroddu_i}{ulong a, ulong b}, private version of \kbd{vecfactoroddu}, not memory clean. \fun{GEN}{vecfactorsquarefreeu}{ulong a, ulong b} return a \typ{VEC} $v$ containing the prime divisors of squarefree integers in $a,\dots,b$; assume that $a \leq b$. Uses a sieve with primes up to $\sqrt{b}$. For all squarefree $c$, $a\leq c\leq b$, the prime divisors of $c$ (as a \typ{VECSMALL}) are given in $v[c-a+1]$, and the other entries are \kbd{NULL}. Note that because of these \kbd{NULL} markers, $v$ is not a valid \kbd{GEN}, it is not memory clean and cannot be used in garbage collection routines. \fun{GEN}{vecsquarefreeu}{ulong a, ulong b} return a \typ{VECSMALL} $v$ containing the squarefree integers in $a,\dots,b$. Assume that $a\leq b$. Uses a sieve with primes up to $\sqrt{b}$. \fun{ulong}{tridiv_bound}{GEN n} returns the trial division bound used by \tet{Z_factor}$(n)$. \fun{GEN}{Z_pollardbrent}{GEN N, long n, long seed} try to factor \typ{INT} $N$ using $n\geq 1$ rounds of Pollard iterations; \var{seed} is an integer whose value (mod $8$) selects the quadratic polynomial use to generate Pollard's (pseudo)random walk. Returns \kbd{NULL} on failure, else a vector of 2 (possibly 3) integers whose product is $N$. \fun{GEN}{Z_ECM}{GEN N, long n, long seed, ulong B1} try to factor \typ{INT} $N$ using $n\geq 1$ rounds of ECM iterations (on $8$ to $64$ curves simultaneously, depending on the size of $N$); \var{seed} is an integer whose value selects the curves to be used: increase it by $64n$ to make sure that a subsequent call with a factor of $N$ uses a disjoint set of curves. Finally $B_1 > 7$ determines the computations performed on the curves: we compute $[k]P$ for some point in $E(\Z/N\Z)$ and $k = q \prod p^{e_p}$ where $p^{e_p} \leq B_1$ and $q \leq B_2 := 110 B_1$; a higher value of $B_1$ means higher chances of hitting a factor and more time spent. The computation is deterministic for a given set of parameters. Returns \kbd{NULL} on failure, else a non trivial factor or \kbd{N}. \fun{GEN}{Q_factor}{GEN x} as \tet{Z_factor}, where $x$ is a \typ{INT} or a \typ{FRAC}. \fun{GEN}{Q_factor_limit}{GEN x, ulong lim} as \tet{Z_factor_limit}, where $x$ is a \typ{INT} or a \typ{FRAC}. \subsec{Coprime factorization} Given $a$ and $b$ two non-zero integers, let \teb{ppi}$(a,b)$, \teb{ppo}$(a,b)$, \teb{ppg}$(a,b)$, \teb{pple}$(a,b)$ (powers in $a$ of primes inside $b$, outside $b$, greater than those in $b$, less than or equal to those in $b$) be the integers defined by \item $v_p(\text{ppi}) = v_p(a) [v_p(b) > 0]$, \item $v_p(\text{ppo}) = v_p(a) [v_p(b) = 0]$, \item $v_p(\text{ppg}) = v_p(a) [v_p(a) > v_p(b)]$, \item $v_p(\text{pple}) = v_p(a) [v_p(a) \leq v_p(b)]$. \fun{GEN}{Z_ppo}{GEN a, GEN b} returns $\text{ppo}(a,b)$; shallow function. \fun{ulong}{u_ppo}{ulong a, ulong b} returns $\text{ppo}(a,b)$. \fun{GEN}{Z_ppgle}{GEN a, GEN b} returns $[\text{ppg}(a,b), \text{pple}(a,b)]$; shallow function. \fun{GEN}{Z_ppio}{GEN a, GEN b} returns $[\gcd(a,b), \text{ppi}(a,b), \text{ppo}(a,b)]$; shallow function. \fun{GEN}{Z_cba}{GEN a, GEN b} fast natural coprime base algorithm. Returns a vector of coprime divisors of $a$ and $b$ such that both $a$ and $b$ can be multiplicatively generated from this set. Perfect powers are not removed, is \tet{Z_isanypower} if needed; shallow function. \fun{GEN}{ZV_cba_extend}{GEN P, GEN b} extend a coprime basis $P$ by the integer $b$, the result being a coprime basis for $P\cup \{b\}$. Perfect powers are not removed; shallow function. \fun{GEN}{ZV_cba}{GEN v} given a vector of non-zero integers $v$, return a coprime basis for $v$. Perfect powers are not removed; shallow function. \subsec{Checks attached to arithmetic functions} Arithmetic functions accept arguments of the following kind: a plain positive integer $N$ (\typ{INT}), the factorization \var{fa} of a positive integer (a \typ{MAT} with two columns containing respectively primes and exponents), or a vector $[N,\var{fa}]$. A few functions accept non-zero integers (e.g.~\tet{omega}), and some others arbitrary integers (e.g.~\tet{factorint}, \dots). \fun{int}{is_Z_factorpos}{GEN f} returns $1$ if $f$ looks like the factorization of a positive integer, and $0$ otherwise. Useful for sanity checks but not 100\% foolproof. Specifically, this routine checks that $f$ is a two-column matrix all of whose entries are positive integers. It does \emph{not} check that entries in the first column (``primes'') are prime, or even pairwise coprime, nor that they are stricly increasing. \fun{int}{is_Z_factornon0}{GEN f} returns $1$ if $f$ looks like the factorization of a non-zero integer, and $0$ otherwise. Useful for sanity checks but not 100\% foolproof, analogous to \tet{is_Z_factorpos}. (Entries in the first column need only be non-zero integers.) \fun{int}{is_Z_factor}{GEN f} returns $1$ if $f$ looks like the factorization of an integer, and $0$ otherwise. Useful for sanity checks but not 100\% foolproof. Specifically, this routine checks that $f$ is a two-column matrix all of whose entries are integers. Entries in the second column (``exponents'') are all positive. Either it encodes the ``factorization'' $0^e$, $e > 0$, or entries in the first column (``primes'') are all non-zero. \fun{GEN}{clean_Z_factor}{GEN f} assuming $f$ is the factorization of an integer $n$, return the factorization of $|n|$, i.e.~remove $-1$ from the factorization. Shallow function. \fun{GEN}{fuse_Z_factor}{GEN f, GEN B} assuming $f$ is the factorization of an integer $n$, return \kbd{boundfact(n, B)}, i.e. return a factorization where all primary factors for $|p| \leq B$ are preserved, and all others are ``fused'' into a single composite integer; if that remainder is trivial, i.e.~equal to 1, it is of course not included. Shallow function. In the following three routines, $f$ is the name of an arithmetic function, and $n$ a supplied argument. They all raise exceptions if $n$ does not correspond to an integer or an integer factorization of the expected shape. \fun{GEN}{check_arith_pos}{GEN n, const char *f} check whether $n$ is attached to the factorization of a positive integer, and return \kbd{NULL} (plain \typ{INT}) or a factorization extracted from $n$ otherwise. May raise an \tet{e_DOMAIN} ($n \leq 0$) or an \tet{e_TYPE} exception (other failures). \fun{GEN}{check_arith_non0}{GEN n, const char *f} check whether $n$ is attached to the factorization of a non-$0$ integer, and return \kbd{NULL} (plain \typ{INT}) or a factorization extracted from $n$ otherwise. May raise an \tet{e_TYPE} exception. \fun{GEN}{check_arith_all}{GEN n, const char *f} is attached to the factorization of an integer, and return \kbd{NULL} (plain \typ{INT}) or a factorization extracted from $n$ otherwise. \subsec{Incremental integer factorization} Routines attached to the dynamic factorization of an integer $n$, iterating over successive prime divisors. This is useful to implement high-level routines allowed to take shortcuts given enough partial information: e.g. \kbd{moebius}$(n)$ can be trivially computed if we hit $p$ such that $p^2 \mid n$. For efficiency, trial division by small primes should have already taken place. In any case, the functions below assume that no prime $< 2^{14}$ divides $n$. \fun{GEN}{ifac_start}{GEN n, int moebius} schedules a new factorization attempt for the integer $n$. If \kbd{moebius} is non-zero, the factorization will be aborted as soon as a repeated factor is detected (Moebius mode). The function assumes that $n > 1$ is a \emph{composite} \typ{INT} whose prime divisors satisfy $p > 2^{14}$ \emph{and} that one can write to $n$ in place. This function stores data on the stack, no \kbd{gerepile} call should delete this data until the factorization is complete. Returns \kbd{partial}, a data structure recording the partial factorization state. \fun{int}{ifac_next}{GEN *partial, GEN *p, long *e} deletes a primary factor $p^e$ from \kbd{partial} and sets \kbd{p} (prime) and \kbd{e} (exponent), and normally returns $1$. Whatever remains in the \kbd{partial} structure is now coprime to $p$. Returns $0$ if all primary factors have been used already, so we are done with the factorization. In this case $p$ is set to \kbd{NULL}. If we ran in Moebius mode and the factorization was in fact aborted, we have $e = 1$, otherwise $e = 0$. \fun{int}{ifac_read}{GEN part, GEN *k, long *e} peeks at the next integer to be factored in the list $k^e$, where $k$ is not necessarily prime and can be a perfect power as well, but will be factored by the next call to \tet{ifac_next}. You can remove this factorization from the schedule by calling: \fun{void}{ifac_skip}{GEN part} removes the next scheduled factorization. \fun{int}{ifac_isprime}{GEN n} given $n$ whose prime divisors are $> 2^{14}$, returns the decision the factoring engine would take about the compositeness of $n$: $0$ if $n$ is a proven composite, and $1$ if we believe it to be prime; more precisely, $n$ is a proven prime if \tet{factor_proven} is set, and only a BPSW-pseudoprime otherwise. \subsec{Integer core, squarefree factorization} \fun{long}{Z_issquarefree}{GEN n} returns $1$ if the \typ{INT} \kbd{n} is square-free, and $0$ otherwise. \fun{long}{Z_isfundamental}{GEN x} returns $1$ if the \typ{INT} \kbd{x} is a fundamental discriminant, and $0$ otherwise. \fun{GEN}{core}{GEN n} unique squarefree integer $d$ dividing $n$ such that $n/d$ is a square. The core of $0$ is defined to be $0$. \fun{GEN}{core2}{GEN n} return $[d,f]$ with $d$ squarefree and $n = df^2$. \fun{GEN}{corepartial}{GEN n, long lim} as \kbd{core}, using \kbd{boundfact(n,lim)} to partially factor \kbd{n}. The result is not necessarily squarefree, but $p^2 \mid n$ implies $p > \kbd{lim}$. \fun{GEN}{core2partial}{GEN n, long lim} as \kbd{core2}, using \kbd{boundfact(n,lim)} to partially factor \kbd{n}. The resulting $d$ is not necessarily squarefree, but $p^2 \mid n$ implies $p > \kbd{lim}$. \subsec{Primes, primality and compositeness tests} \subsubsec{Chebyshev's $\pi$ function, bounds} \fun{ulong}{uprimepi}{ulong n}, returns the number of primes $p\leq n$ (Chebyshev's $\pi$ function). \fun{double}{primepi_upper_bound}{double x} return a quick upper bound for $\pi(x)$, using Dusart bounds. \fun{GEN}{gprimepi_upper_bound}{GEN x} as \tet{primepi_upper_bound}, returns a \typ{REAL}. \fun{double}{primepi_lower_bound}{double x} return a quick lower bound for $\pi(x)$, using Dusart bounds. \fun{GEN}{gprimepi_lower_bound}{GEN x} as \tet{primepi_lower_bound}, returns a \typ{REAL} or \kbd{gen\_0}. \subsubsec{Primes, primes in intervals} \fun{ulong}{unextprime}{ulong n}, returns the smallest prime $\geq n$. Return $0$ if it cannot be represented as an \kbd{ulong} ($n$ bigger than $2^{64} - 59$ or $2^{32} - 5$ depending on the word size). \fun{ulong}{uprecprime}{ulong n}, returns the largest prime $\leq n$. Return $0$ if $n\leq 1$. \fun{ulong}{uprime}{long n} returns the $n$-th prime, assuming it fits in an \kbd{ulong} (overflow error otherwise). \fun{GEN}{prime}{long n} same as \kbd{utoi(uprime(n))}. \fun{GEN}{primes_zv}{long m} returns the first $m$ primes, in a \typ{VECSMALL}. \fun{GEN}{primes}{long m} return the first $m$ primes, as a \typ{VEC} of \typ{INT}s. \fun{GEN}{primes_interval}{GEN a, GEN b} return the primes in the interval $[a,b]$, as a \typ{VEC} of \typ{INT}s. \fun{GEN}{primes_interval_zv}{ulong a, ulong b} return the primes in the interval $[a,b]$, as a \typ{VECSMALL} of \kbd{ulongs}s. \fun{GEN}{primes_upto_zv}{ulong b} return the primes in the interval $[2,b]$, as a \typ{VECSMALL} of \kbd{ulongs}s. \subsubsec{Tests} \fun{int}{uisprime}{ulong p}, returns $1$ if \kbd{p} is a prime number and $0$ otherwise. \fun{int}{uisprime_101}{ulong p}, assuming that $p$ has no divisor $\leq 101$, returns $1$ if \kbd{p} is a prime number and $0$ otherwise. \fun{int}{uisprime_661}{ulong p}, assuming that $p$ has no divisor $\leq 661$, returns $1$ if \kbd{p} is a prime number and $0$ otherwise. \fun{int}{isprime}{GEN n}, returns $1$ if the \typ{INT} \kbd{n} is a (fully proven) prime number and $0$ otherwise. \fun{long}{isprimeAPRCL}{GEN n}, returns $1$ if the \typ{INT} \kbd{n} is a prime number and $0$ otherwise, using only the APRCL test --- not even trial division or compositeness tests. The workhorse \kbd{isprime} should be faster on average, especially if non-primes are included! \fun{long}{isprimeECPP}{GEN n}, returns $1$ if the \typ{INT} \kbd{n} is a prime number and $0$ otherwise, using only the ECPP test. The workhorse \kbd{isprime} should be faster on average. \fun{long}{BPSW_psp}{GEN n}, returns $1$ if the \typ{INT} \kbd{n} is a Baillie-Pomerance-Selfridge-Wagstaff pseudoprime, and $0$ otherwise (proven composite). \fun{int}{BPSW_isprime}{GEN x} assuming $x$ is a BPSW-pseudoprime, rigorously prove its primality. The function \tet{isprime} is currently implemented as \bprog BPSW_psp(x) && BPSW_isprime(x) @eprog \fun{long}{millerrabin}{GEN n, long k} performs $k$ strong Rabin-Miller compositeness tests on the \typ{INT} $n$, using $k$ random bases. This function also caches square roots of $-1$ that are encountered during the successive tests and stops as soon as three distinct square roots have been produced; we have in principle factored $n$ at this point, but unfortunately, there is currently no way for the factoring machinery to become aware of it. (It is highly implausible that hard to find factors would be exhibited in this way, though.) This should be slower than \tet{BPSW_psp} for $k\geq 4$ and we would expect it to be less reliable. \fun{GEN}{ecpp}{GEN N} returns an ECPP certificate for \typ{INT} $N$; underlies \kbd{primecert}. \fun{GEN}{ecppexport}{GEN cert, long flag} export a PARI ECPP certificate to MAGMA or Primo format; underlies \kbd{primecertexport}. \fun{long}{ecppisvalid}{GEN cert} checks whether a PARI ECPP certificate is valid; underlies \kbd{primecertisvalid}. \subsec{Iterators over primes} \fun{int}{forprime_init}{forprime_t *T, GEN a, GEN b} initialize an iterator $T$ over primes in $[a,b]$; over primes $\geq a$ if $b = \kbd{NULL}$. Return $0$ if the range is known to be empty from the start (as if $b < a$ or $b < 0$), and return $1$ otherwise. Use \tet{forprime_next} to iterate over the prime collection. \fun{int}{forprimestep_init}{forprime_t *T, GEN a, GEN b, GEN q} initialize an iterator $T$ over primes in an arithmetic progression in $[a,b]$; over primes $\geq a$ if $b = \kbd{NULL}$. The argument $q$ is either a \typ{INT} ($p \equiv a \pmod{q}$) or a \typ{INTMOD} \kbd{Mod(c,N)} and we restrict to that congruence class. Return $0$ if the range is known to be empty from the start (as if $b < a$ or $b < 0$), and return $1$ otherwise. Use \tet{forprime_next} to iterate over the prime collection. \fun{GEN}{forprime_next}{forprime_t *T} returns the next prime in the range, assuming that $T$ was initialized by \tet{forprime_init}. \fun{int}{u_forprime_init}{forprime_t *T, ulong a, ulong b} \fun{ulong}{u_forprime_next}{forprime_t *T} \fun{void}{u_forprime_restrict}{forprime_t *T, ulong c} let $T$ an iterator over primes initialized via \kbd{u\_forprime\_init(\&T, a, b)}, possibly followed by a number of calls to \tet{u_forprime_next}, and $a \leq c \leq b$. Restrict the range of primes considered to $[a,c]$. \fun{int}{u_forprime_arith_init}{forprime_t *T, ulong a,ulong b, ulong c,ulong q} initialize an iterator over primes in $[a,b]$, congruent to $c$ modulo $q$. Subsequent calls to \tet{u_forprime_next} will only return primes congruent to $c$ modulo $q$. Note that unless $(c,q) = 1$ there will be at most one such prime. \section{Integral, rational and generic linear algebra} \subsec{\kbd{ZC} / \kbd{ZV}, \kbd{ZM}} A \kbd{ZV} (resp.~a~\kbd{ZM}, resp.~a~\kbd{ZX}) is a \typ{VEC} or \typ{COL} (resp.~\typ{MAT}, resp.~\typ{POL}) with \typ{INT} coefficients. \subsubsec{\kbd{ZC} / \kbd{ZV}} \fun{void}{RgV_check_ZV}{GEN x, const char *s} Assuming \kbd{x} is a \typ{VEC} or \typ{COL} raise an error if it is not a \kbd{ZV} ($s$ should point to the name of the caller). \fun{int}{RgV_is_ZV}{GEN x} Assuming \kbd{x} is a \typ{VEC} or \typ{COL} return $1$ if it is a \kbd{ZV}, and $0$ otherwise. \fun{int}{RgV_is_ZVpos}{GEN x} Assuming \kbd{x} is a \typ{VEC} or \typ{COL} return $1$ if it is a \kbd{ZV} with positive entries, and $0$ otherwise. \fun{int}{RgV_is_ZVnon0}{GEN x} Assuming \kbd{x} is a \typ{VEC} or \typ{COL} return $1$ if it is a \kbd{ZV} with non-zero entries, and $0$ otherwise. \fun{int}{RgV_is_QV}{GEN P} return 1 if the \kbd{RgV}~$P$ has only \typ{INT} and \typ{FRAC} coefficients, and 0 otherwise. \fun{int}{ZV_equal0}{GEN x} returns 1 if all entries of the \kbd{ZV} $x$ are zero, and $0$ otherwise. \fun{int}{ZV_cmp}{GEN x, GEN y} compare two \kbd{ZV}, which we assume have the same length (lexicographic order, comparing absolute values). \fun{int}{ZV_abscmp}{GEN x, GEN y} compare two \kbd{ZV}, which we assume have the same length (lexicographic order). \fun{int}{ZV_equal}{GEN x, GEN y} returns $1$ if the two \kbd{ZV} are equal and $0$ otherwise. A \typ{COL} and a \typ{VEC} with the same entries are declared equal. \fun{GEN}{ZC_add}{GEN x, GEN y} adds \kbd{x} and \kbd{y}. \fun{GEN}{ZC_sub}{GEN x, GEN y} subtracts \kbd{x} and \kbd{y}. \fun{GEN}{ZC_Z_add}{GEN x, GEN y} adds \kbd{y} to \kbd{x[1]}. \fun{GEN}{ZC_Z_sub}{GEN x, GEN y} subtracts \kbd{y} to \kbd{x[1]}. \fun{GEN}{Z_ZC_sub}{GEN a, GEN x} returns the vector $[a - x_1, -x_2,\dots,-x_n]$. \fun{GEN}{ZC_copy}{GEN x} returns a (\typ{COL}) copy of \kbd{x}. \fun{GEN}{ZC_neg}{GEN x} returns $-\kbd{x}$ as a \typ{COL}. \fun{void}{ZV_neg_inplace}{GEN x} negates the \kbd{ZV} \kbd{x} in place, by replacing each component by its opposite (the type of \kbd{x} remains the same, \typ{COL} or \typ{COL}). If you want to save even more memory by avoiding the implicit component copies, use \kbd{ZV\_togglesign}. \fun{void}{ZV_togglesign}{GEN x} negates \kbd{x} in place, by toggling the sign of its integer components. Universal constants \kbd{gen\_1}, \kbd{gen\_m1}, \kbd{gen\_2} and \kbd{gen\_m2} are handled specially and will not be corrupted. (We use \tet{togglesign_safe}.) \fun{GEN}{ZC_Z_mul}{GEN x, GEN y} multiplies the \kbd{ZC} or \kbd{ZV}~\kbd{x} (which can be a column or row vector) by the \typ{INT}~\kbd{y}, returning a \kbd{ZC}. \fun{GEN}{ZC_Z_divexact}{GEN x, GEN y} returns $x/y$ assuming all divisions are exact. \fun{GEN}{ZC_Z_div}{GEN x, GEN y} returns $x/y$, where the resulting vector has rational entries. \fun{GEN}{ZV_dotproduct}{GEN x,GEN y} as \kbd{RgV\_dotproduct} assuming $x$ and $y$ have \typ{INT} entries. \fun{GEN}{ZV_dotsquare}{GEN x} as \kbd{RgV\_dotsquare} assuming $x$ has \typ{INT} entries. \fun{GEN}{ZC_lincomb}{GEN u, GEN v, GEN x, GEN y} returns $ux + vy$, where $u$, $v$ are \typ{INT} and $x,y$ are \kbd{ZC} or \kbd{ZV}. Return a \kbd{ZC} \fun{void}{ZC_lincomb1_inplace}{GEN X, GEN Y, GEN v} sets $X\leftarrow X + vY$, where $v$ is a \typ{INT} and $X,Y$ are \kbd{ZC} or \kbd{ZV}. (The result has the type of $X$.) Memory efficient (e.g. no-op if $v = 0$), but not gerepile-safe. \fun{void}{ZC_lincomb1_inplace_i}{GEN X, GEN Y, GEN v, long n} variant of \tet{ZC_lincomb1_inplace}: only update $X[1], \dots, X[n]$, assuming that $n < \kbd{lg}(X)$. \fun{GEN}{ZC_ZV_mul}{GEN x, GEN y, GEN p} multiplies the \kbd{ZC}~\kbd{x} (seen as a column vector) by the \kbd{ZV}~\kbd{y} (seen as a row vector, assumed to have compatible dimensions). \fun{GEN}{ZV_content}{GEN x} returns the GCD of all the components of~\kbd{x}. \fun{GEN}{ZV_extgcd}{GEN A} given a vector of $n$ integers $A$, returns $[d, U]$, where $d$ is the content of $A$ and $U$ is a matrix in $\text{GL}_n(\Z)$ such that $AU = [D,0, \dots,0]$. \fun{GEN}{ZV_prod}{GEN x} returns the product of all the components of~\kbd{x} ($1$ for the empty vector). \fun{GEN}{ZV_sum}{GEN x} returns the sum of all the components of~\kbd{x} ($0$ for the empty vector). \fun{long}{ZV_max_lg}{GEN x} returns the effective length of the longest entry in $x$. \fun{int}{ZV_dvd}{GEN x, GEN y} assuming $x$, $y$ are two \kbd{ZV}s of the same length, return $1$ if $y[i]$ divides $x[i]$ for all $i$ and $0$ otherwise. Error if one of the $y[i]$ is $0$. \fun{GEN}{ZV_sort}{GEN L} sort the \kbd{ZV} $L$. Returns a vector with the same type as $L$. \fun{void}{ZV_sort_inplace}{GEN L} sort the \kbd{ZV} $L$, in place. \fun{GEN}{ZV_sort_uniq}{GEN L} sort the \kbd{ZV} $L$, removing duplicate entries. Returns a vector with the same type as $L$. \fun{long}{ZV_search}{GEN L, GEN y} look for the \typ{INT} $y$ in the sorted \kbd{ZV} $L$. Return an index $i$ such that $L[i] = y$, and $0$ otherwise. \fun{GEN}{ZV_indexsort}{GEN L} returns the permutation which, applied to the \kbd{ZV} $L$, would sort the vector. The result is a \typ{VECSMALL}. \fun{GEN}{ZV_union_shallow}{GEN x, GEN y} given two \emph{sorted} ZV (as per \tet{ZV_sort}, returns the union of $x$ and $y$. Shallow function. In case two entries are equal in $x$ and $y$, include the one from $x$. \fun{GEN}{ZC_union_shallow}{GEN x, GEN y} as \kbd{ZV\_union\_shallow} but return a \typ{COL}. \subsubsec{\kbd{ZM}} \fun{void}{RgM_check_ZM}{GEN A, const char *s} Assuming \kbd{x} is a \typ{MAT} raise an error if it is not a \kbd{ZM} ($s$ should point to the name of the caller). \fun{GEN}{RgM_rescale_to_int}{GEN x} given a matrix $x$ with real entries (\typ{INT}, \typ{FRAC} or \typ{REAL}), return a \kbd{ZM} wich is very close to $D x$ for some well-chosen integer $D$. More precisely, if the input is exact, $D$ is the denominator of $x$; else it is a power of $2$ chosen so that all inexact entries are correctly rounded to 1 ulp. \fun{GEN}{ZM_copy}{GEN x} returns a copy of \kbd{x}. \fun{int}{ZM_equal}{GEN A, GEN B} returns $1$ if the two \kbd{ZM} are equal and $0$ otherwise. \fun{int}{ZM_equal0}{GEN A} returns $1$ if the \kbd{ZM} $A$ is identically equal to $0$. \fun{GEN}{ZM_add}{GEN x, GEN y} returns $\kbd{x} + \kbd{y}$ (assumed to have compatible dimensions). \fun{GEN}{ZM_sub}{GEN x, GEN y} returns $\kbd{x} - \kbd{y}$ (assumed to have compatible dimensions). \fun{GEN}{ZM_neg}{GEN x} returns $-\kbd{x}$. \fun{void}{ZM_togglesign}{GEN x} negates \kbd{x} in place, by toggling the sign of its integer components. Universal constants \kbd{gen\_1}, \kbd{gen\_m1}, \kbd{gen\_2} and \kbd{gen\_m2} are handled specially and will not be corrupted. (We use \tet{togglesign_safe}.) \fun{GEN}{ZM_mul}{GEN x, GEN y} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{ZM_sqr}{GEN x} returns $x^2$, where $x$ is a square \kbd{ZM}. \fun{GEN}{ZM_Z_mul}{GEN x, GEN y} multiplies the \kbd{ZM}~\kbd{x} by the \typ{INT}~\kbd{y}. \fun{GEN}{ZM_ZC_mul}{GEN x, GEN y} multiplies the \kbd{ZM}~\kbd{x} by the \kbd{ZC}~\kbd{y} (seen as a column vector, assumed to have compatible dimensions). \fun{GEN}{ZM_ZX_mul}{GEN x, GEN T} returns $x \times y$, where $y$ is \kbd{RgX\_to\_RgC}$(T, \kbd{lg}(x)-1)$. \fun{GEN}{ZM_diag_mul}{GEN d, GEN m} given a vector $d$ with integer entries and a \kbd{ZM} $m$ of compatible dimensions, return \kbd{diagonal(d) * m}. \fun{GEN}{ZM_mul_diag}{GEN m, GEN d} given a vector $d$ with integer entries and a \kbd{ZM} $m$ of compatible dimensions, return \kbd{m * diagonal(d)}. \fun{GEN}{ZM_multosym}{GEN x, GEN y} \fun{GEN}{ZM_transmultosym}{GEN x, GEN y} \fun{GEN}{ZM_transmul}{GEN x, GEN y} \fun{GEN}{ZMrow_ZC_mul}{GEN x, GEN y, long i} multiplies the $i$-th row of \kbd{ZM}~\kbd{x} by the \kbd{ZC}~\kbd{y} (seen as a column vector, assumed to have compatible dimensions). Assumes that $x$ is non-empty and $0 < i < \kbd{lg(x[1])}$. \fun{GEN}{ZV_ZM_mul}{GEN x, GEN y} multiplies the \kbd{ZV}~\kbd{x} by the \kbd{ZM}~\kbd{y}. Returns a \typ{VEC}. \fun{GEN}{ZM_Z_divexact}{GEN x, GEN y} returns $x/y$ assuming all divisions are exact. \fun{GEN}{ZM_Z_div}{GEN x, GEN y} returns $x/y$, where the resulting matrix has rational entries. \fun{GEN}{ZC_Q_mul}{GEN x, GEN y} returns $x*y$, where $y$ is a rational number and the resulting \typ{COL} has rational entries. \fun{GEN}{ZM_Q_mul}{GEN x, GEN y} returns $x*y$, where $y$ is a rational number and the resulting matrix has rational entries. \fun{GEN}{ZM_pow}{GEN x, GEN n} returns $\kbd{x}^\kbd{n}$, assuming \kbd{x} is a square \kbd{ZM} and $\kbd{n}\geq 0$. \fun{GEN}{ZM_powu}{GEN x, ulong n} returns $\kbd{x}^\kbd{n}$, assuming \kbd{x} is a square \kbd{ZM} and $\kbd{n}\geq 0$. \fun{GEN}{ZM_det}{GEN M} if \kbd{M} is a \kbd{ZM}, returns the determinant of $M$. This is the function underlying \tet{matdet} whenever $M$ is a \kbd{ZM}. \fun{GEN}{ZM_permanent}{GEN M} if \kbd{M} is a \kbd{ZM}, returns its permanent. This is the function underlying \tet{matpermanent} whenever $M$ is a \kbd{ZM}. It assumes that the matrix is square of dimension $< \kbd{BITS\_IN\_LONG}$. \fun{GEN}{ZM_detmult}{GEN M} if \kbd{M} is a \kbd{ZM}, returns a multiple of the determinant of the lattice generated by its columns. This is the function underlying \tet{detint}. \fun{GEN}{ZM_supnorm}{GEN x} return the sup norm of the \kbd{ZM} $x$. \fun{GEN}{ZM_charpoly}{GEN M} returns the characteristic polynomial (in variable $0$) of the \kbd{ZM} $M$. \fun{GEN}{ZM_imagecompl}{GEN x} returns \kbd{matimagecompl(x)}. \fun{long}{ZM_rank}{GEN x} returns \kbd{matrank(x)}. \fun{GEN}{ZM_ker}{GEN x} returns \kbd{matker(x)} \fun{GEN}{ZM_indexrank}{GEN x} returns \kbd{matindexrank(x)}. \fun{GEN}{ZM_indeximage}{GEN x} returns \kbd{gel(ZM\_indexrank(x), 2)}. \fun{long}{ZM_max_lg}{GEN x} returns the effective length of the longest entry in $x$. \fun{GEN}{ZM_inv}{GEN M, GEN *pd} if \kbd{M} is a \kbd{ZM}, return a primitive matrix $H$ such that $M H$ is $d$ times the identity and set \kbd{*pd} to $d$. Uses a multimodular algorithm up to Hadamard's bound. If you suspect that the denominator is much smaller than $\det M$, you may use \tet{ZM_inv_ratlift}. \fun{GEN}{ZM_inv_ratlift}{GEN M, GEN *pd} if \kbd{M} is a \kbd{ZM}, return a primitive matrix $H$ such that $M H$ is $d$ times the identity and set \kbd{*pd} to $d$. Uses a multimodular algorithm, attempting rational reconstruction along the way. To be used when you expect that the denominator of $M^{-1}$ is much smaller than $\det M$ else use \kbd{ZM\_inv}. \fun{GEN}{ZM_pseudoinv}{GEN M, GEN *pv, GEN *pd} if \kbd{M} is a non-empty \kbd{ZM}, let $v = [y,z]$ returned by \kbd{indexrank} and let $M_1$ be the corresponding square invertible matrix. Return a primitive left-inverse $H$ such that $H M_1$ is $d$ times the identity and set \kbd{*pd} to $d$. If \kbd{pv} is not \kbd{NULL}, set \kbd{*pv} to $v$. Not gerepile-safe. \fun{GEN}{ZM_gauss}{GEN a, GEN b} as \kbd{gauss}, where $a$ and $b$ coefficients are \typ{INT}s. \fun{GEN}{ZM_det_triangular}{GEN x} returns the product of the diagonal entries of $x$ (its determinant if it is indeed triangular). \fun{int}{ZM_isidentity}{GEN x} return 1 if the \kbd{ZM} $x$ is the identity matrix, and 0 otherwise. \fun{int}{ZM_isdiagonal}{GEN x} return 1 if the \kbd{ZM} $x$ is diagonal, and 0 otherwise. \fun{int}{ZM_isscalar}{GEN x, GEN s} given a \kbd{ZM} $x$ and a \typ{INT} $s$, return 1 if $x$ is equal to $s$ times the identity, and 0 otherwise. If $s$ is \kbd{NULL}, test whether $x$ is an arbitrary scalar matrix. \fun{long}{ZC_is_ei}{GEN x} return $i$ if the \kbd{ZC} $x$ has $0$ entries, but for a $1$ at position $i$. \fun{int}{ZM_ishnf}{GEN x} return $1$ if $x$ is in HNF form, i.e. is upper triangular with positive diagonal coefficients, and for $j>i$, $x_{i,i}>x_{i,j} \ge 0$. \subsec{\kbd{QM}} \fun{GEN}{QM_charpoly_ZX}{GEN M} returns the characteristic polynomial (in variable $0$) of the \kbd{QM} $M$, assuming that the result has integer coefficients. \fun{GEN}{QM_charpoly_ZX_bound}{GEN M, long b} as \tet{QM_charpoly_ZX} assuming that the sup norm of the (integral) result is $\leq 2^b$. \fun{GEN}{QM_gauss}{GEN a, GEN b} as \kbd{gauss}, where $a$ and $b$ coefficients are \typ{FRAC}s. \fun{GEN}{QM_indexrank}{GEN x} returns \kbd{matindexrank(x)}. \fun{GEN}{QM_inv}{GEN M} return the inverse of the \kbd{QM} $M$. \fun{long}{QM_rank}{GEN x} returns \kbd{matrank(x)}. \subsec{\kbd{Qevproj}} \fun{GEN}{Qevproj_init}{GEN M} let $M$ be a $n\times d$ \kbd{ZM} of maximal rank $d \leq n$, representing the basis of a $\Q$-subspace $V$ of $\Q^n$. Return a projector on $V$, to be used by \tet{Qevproj_apply}. The interface details may change in the future, but this function currently returns $[M, B,D,p]$, where $p$ is a \typ{VECSMALL} with $d$ entries such that the submatrix $A = \kbd{rowpermute}(M,p)$ is invertible, $B$ is a \kbd{ZM} and $d$ a \typ{INT} such that $A B = D \Id_d$. \fun{GEN}{Qevproj_apply}{GEN T, GEN pro} let $T$ be an $n\times n$ \kbd{QM}, stabilizing a $\Q$-subspace $V\subset \Q^n$ of dimension $d$, and let \kbd{pro} be a projector on that subspace initialized by \tet{Qevproj_init}$(M)$. Return the $d\times d$ matrix representing $T_{|V}$ on the basis given by the columns of $M$. \fun{GEN}{Qevproj_apply_vecei}{GEN T, GEN pro, long k} as \tet{Qevproj_apply}, return only the image of the $k$-th basis vector $M[k]$ (still on the basis given by the columns of $M$). \fun{GEN}{Qevproj_down}{GEN T, GEN pro} given a \kbd{ZC} (resp.~a \kbd{ZM}) $T$ representing an element (resp.~a vector of elements) in the subspace $V$ return a \kbd{QC} (resp.~a \kbd{QM}) $U$ such that $T = MU$. \subsec{\kbd{zv}, \kbd{zm}} \fun{GEN}{zv_neg}{GEN x} return $-x$. No check for overflow is done, which occurs in the fringe case where an entry is equal to $2^{\B-1}$. \fun{GEN}{zv_neg_inplace}{GEN x} negates $x$ in place and return it. No check for overflow is done, which occurs in the fringe case where an entry is equal to $2^{\B-1}$. \fun{GEN}{zm_zc_mul}{GEN x, GEN y} \fun{GEN}{zm_mul}{GEN x, GEN y} \fun{GEN}{zv_z_mul}{GEN x, long n} return $n\*x$. No check for overflow is done. \fun{long}{zv_content}{GEN x} returns the gcd of the entries of $x$. \fun{long}{zv_dotproduct}{GEN x, GEN y} \fun{long}{zv_prod}{GEN x} returns the product of all the components of~\kbd{x} (assumes no overflow occurs). \fun{GEN}{zv_prod_Z}{GEN x} returns the product of all the components of~\kbd{x}; consider all $x[i]$ as \kbd{ulong}s. \fun{long}{zv_sum}{GEN x} returns the sum of all the components of~\kbd{x} (assumes no overflow occurs). \fun{int}{zv_cmp0}{GEN x} returns 1 if all entries of the \kbd{zv} $x$ are $0$, and $0$ otherwise. \fun{int}{zv_equal}{GEN x, GEN y} returns $1$ if the two \kbd{zv} are equal and $0$ otherwise. \fun{int}{zv_equal0}{GEN x} returns $1$ if all entries are $0$, and return $0$ otherwise. \fun{long}{zv_search}{GEN L, long y} look for $y$ in the sorted \kbd{zv} $L$. Return an index $i$ such that $L[i] = y$, and $0$ otherwise. \fun{GEN}{zv_copy}{GEN x} as \kbd{Flv\_copy}. \fun{GEN}{zm_transpose}{GEN x} as \kbd{Flm\_transpose}. \fun{GEN}{zm_copy}{GEN x} as \kbd{Flm\_copy}. \fun{GEN}{zero_zm}{long m, long n} as \kbd{zero\_Flm}. \fun{GEN}{zero_zv}{long n} as \kbd{zero\_Flv}. \fun{GEN}{zm_row}{GEN A, long x0} as \kbd{Flm\_row}. \fun{GEN}{zm_permanent}{GEN M} return the permanent of $M$. The function assumes that the matrix is square of dimension $< \kbd{BITS\_IN\_LONG}$. \fun{int}{zvV_equal}{GEN x, GEN y} returns $1$ if the two \kbd{zvV} (vectors of \kbd{zv}) are equal and $0$ otherwise. \subsec{\kbd{ZMV} / \kbd{zmV} (vectors of \kbd{ZM}/\kbd{zm})} \fun{int}{RgV_is_ZMV}{GEN x} Assuming \kbd{x} is a \typ{VEC} or \typ{COL} return $1$ if its components are \kbd{ZM}, and $0$ otherwise. \fun{GEN}{ZMV_to_zmV}{GEN z} \fun{GEN}{zmV_to_ZMV}{GEN z} \fun{GEN}{ZMV_to_FlmV}{GEN z, ulong m} \subsec{\kbd{QC} / \kbd{QV}, \kbd{QM}} \fun{GEN}{QM_mul}{GEN x, GEN y} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{QM_QC_mul}{GEN x, GEN y} multiplies \kbd{x} and \kbd{y} (assumed to have compatible dimensions). \fun{GEN}{QM_det}{GEN M} returns the determinant of $M$. \fun{GEN}{QM_ker}{GEN x} returns \kbd{matker(x)}. \subsec{\kbd{RgC} / \kbd{RgV}, \kbd{RgM}} \kbd{RgC} and \kbd{RgV} routines assume the inputs are \kbd{VEC} or \kbd{COL} of the same dimension. \kbd{RgM} assume the inputs are \kbd{MAT} of compatible dimensions. \subsubsec{Matrix arithmetic} \fun{void}{RgM_dimensions}{GEN x, long *m, long *n} sets $m$, resp.~$n$, to the number of rows, resp.~columns of the \typ{MAT} $x$. \fun{GEN}{RgC_add}{GEN x, GEN y} returns $x + y$ as a \typ{COL}. \fun{GEN}{RgC_neg}{GEN x} returns $-x$ as a \typ{COL}. \fun{GEN}{RgC_sub}{GEN x, GEN y} returns $x - y$ as a \typ{COL}. \fun{GEN}{RgV_add}{GEN x, GEN y} returns $x + y$ as a \typ{VEC}. \fun{GEN}{RgV_neg}{GEN x} returns $-x$ as a \typ{VEC}. \fun{GEN}{RgV_sub}{GEN x, GEN y} returns $x - y$ as a \typ{VEC}. \fun{GEN}{RgM_add}{GEN x, GEN y} return $x+y$. \fun{GEN}{RgM_neg}{GEN x} returns $-x$. \fun{GEN}{RgM_sub}{GEN x, GEN y} returns $x-y$. \fun{GEN}{RgM_Rg_add}{GEN x, GEN y} assuming $x$ is a square matrix and $y$ a scalar, returns the square matrix $x + y*\text{Id}$. \fun{GEN}{RgM_Rg_add_shallow}{GEN x, GEN y} as \kbd{RgM\_Rg\_add} with much fewer copies. Not suitable for \kbd{gerepileupto}. \fun{GEN}{RgM_Rg_sub}{GEN x, GEN y} assuming $x$ is a square matrix and $y$ a scalar, returns the square matrix $x - y*\text{Id}$. \fun{GEN}{RgM_Rg_sub_shallow}{GEN x, GEN y} as \kbd{RgM\_Rg\_sub} with much fewer copies. Not suitable for \kbd{gerepileupto}. \fun{GEN}{RgC_Rg_add}{GEN x, GEN y} assuming $x$ is a non-empty column vector and $y$ a scalar, returns the vector $[x_1 + y, x_2,\dots,x_n]$. \fun{GEN}{RgC_Rg_sub}{GEN x, GEN y} assuming $x$ is a non-empty column vector and $y$ a scalar, returns the vector $[x_1 - y, x_2,\dots,x_n]$. \fun{GEN}{Rg_RgC_sub}{GEN a, GEN x} assuming $x$ is a non-empty column vector and $a$ a scalar, returns the vector $[a - x_1, -x_2,\dots,-x_n]$. \fun{GEN}{RgC_Rg_div}{GEN x, GEN y} \fun{GEN}{RgM_Rg_div}{GEN x, GEN y} returns $x/y$ ($y$ treated as a scalar). \fun{GEN}{RgC_Rg_mul}{GEN x, GEN y} \fun{GEN}{RgV_Rg_mul}{GEN x, GEN y} \fun{GEN}{RgM_Rg_mul}{GEN x, GEN y} returns $x\times y$ ($y$ treated as a scalar). \fun{GEN}{RgV_RgC_mul}{GEN x, GEN y} returns $x\times y$. \fun{GEN}{RgV_RgM_mul}{GEN x, GEN y} returns $x\times y$. \fun{GEN}{RgM_RgC_mul}{GEN x, GEN y} returns $x\times y$. \fun{GEN}{RgM_RgX_mul}{GEN x, GEN T} returns $x \times y$, where $y$ is \kbd{RgX\_to\_RgC}$(T, \kbd{lg}(x)-1)$. \fun{GEN}{RgM_mul}{GEN x, GEN y} returns $x\times y$. \fun{GEN}{RgM_transmul}{GEN x, GEN y} returns $x\til \times y$. \fun{GEN}{RgM_multosym}{GEN x, GEN y} returns $x\times y$, assuming the result is a symmetric matrix (about twice faster than a generic matrix multiplication). \fun{GEN}{RgM_transmultosym}{GEN x, GEN y} returns $x\til \times y$, assuming the result is a symmetric matrix (about twice faster than a generic matrix multiplication). \fun{GEN}{RgMrow_RgC_mul}{GEN x, GEN y, long i} multiplies the $i$-th row of \kbd{RgM}~\kbd{x} by the \kbd{RgC}~\kbd{y} (seen as a column vector, assumed to have compatible dimensions). Assumes that $x$ is non-empty and $0 < i < \kbd{lg(x[1])}$. \fun{GEN}{RgM_mulreal}{GEN x, GEN y} returns the real part of $x\times y$ (whose entries are \typ{INT}, \typ{FRAC}, \typ{REAL} or \typ{COMPLEX}). \fun{GEN}{RgM_sqr}{GEN x} returns $x^2$. \fun{GEN}{RgC_RgV_mul}{GEN x, GEN y} returns $x\times y$ (the matrix $(x_iy_j)$). The following two functions are not well defined in general and only provided for convenience in specific cases: \fun{GEN}{RgC_RgM_mul}{GEN x, GEN y} returns $x\times y[1,]$ if $y$ is a row matrix $1\times n$, error otherwise. \fun{GEN}{RgM_RgV_mul}{GEN x, GEN y} returns $x\times y[,1]$ if $y$ is a column matrix $n\times 1$, error otherwise. \fun{GEN}{RgM_powers}{GEN x, long n} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as a \typ{VEC} of \kbd{RgM}s. \smallskip \fun{GEN}{RgV_sum}{GEN v} sum of the entries of $v$ \fun{GEN}{RgV_prod}{GEN v} product of the entries of $v$, using a divide and conquer strategy \fun{GEN}{RgV_sumpart}{GEN v, long n} returns the sum $v[1] + \dots + v[n]$ (assumes that \kbd{lg}$(v) > n$). \fun{GEN}{RgV_sumpart2}{GEN v, long m, long n} returns the sum $v[m] + \dots + v[n]$ (assumes that \kbd{lg}$(v) > n$ and $m > 0$). Returns \kbd{gen\_0} when $m > n$. \fun{GEN}{RgM_sumcol}{GEN v} returns a \typ{COL}, sum of the columns of the \typ{MAT} $v$. \fun{GEN}{RgV_dotproduct}{GEN x,GEN y} returns the scalar product of $x$ and $y$ \fun{GEN}{RgV_dotsquare}{GEN x} returns the scalar product of $x$ with itself. \fun{GEN}{RgV_kill0}{GEN v} returns a shallow copy of $v$ where entries matched by \kbd{gequal0} are replaced by \kbd{NULL}. The return value is not a valid \kbd{GEN} and must be handled specially. The idea is to pre-treat a vector of coefficients to speed up later linear combinations or scalar products. \fun{GEN}{gram_matrix}{GEN v} returns the \idx{Gram matrix} $(v_i\cdot v_j)$ attached to the entries of $v$ (matrix, or vector of vectors). \fun{GEN}{RgV_polint}{GEN X, GEN Y, long v} $X$ and $Y$ being two vectors of the same length, returns the polynomial $T$ in variable $v$ such that $T(X[i]) = Y[i]$ for all $i$. The special case $X = \kbd{NULL}$ corresponds to $X = [1,2,\dots,n]$, where $n$ is the length of $Y$. \subsubsec{Special shapes} The following routines check whether matrices or vectors have a special shape, using \kbd{gequal1} and \kbd{gequal0} to test components. (This makes a difference when components are inexact.) \fun{int}{RgV_isscalar}{GEN x} return 1 if all the entries of $x$ are $0$ (as per \kbd{gequal0}), except possibly the first one. The name comes from vectors expressing polynomials on the standard basis $1,T,\dots, T^{n-1}$, or on \kbd{nf.zk} (whose first element is $1$). \fun{int}{QV_isscalar}{GEN x} as \kbd{RgV\_isscalar}, assuming $x$ is a \kbd{QV} (\typ{INT} and \typ{FRAC} entries only). \fun{int}{ZV_isscalar}{GEN x} as \kbd{RgV\_isscalar}, assuming $x$ is a \kbd{ZV} (\typ{INT} entries only). \fun{int}{RgM_isscalar}{GEN x, GEN s} return 1 if $x$ is the scalar matrix equal to $s$ times the identity, and 0 otherwise. If $s$ is \kbd{NULL}, test whether $x$ is an arbitrary scalar matrix. \fun{int}{RgM_isidentity}{GEN x} return 1 if the \typ{MAT} $x$ is the identity matrix, and 0 otherwise. \fun{int}{RgM_isdiagonal}{GEN x} return 1 if the \typ{MAT} $x$ is a diagonal matrix, and 0 otherwise. \fun{long}{RgC_is_ei}{GEN x} return $i$ if the \typ{COL} $x$ has $0$ entries, but for a $1$ at position $i$. \fun{int}{RgM_is_ZM}{GEN x} return 1 if the \typ{MAT}~$x$ has only \typ{INT} coefficients, and 0 otherwise. \fun{int}{RgM_is_QM}{GEN x} return 1 if the \typ{MAT}~$x$ has only \typ{INT} or \typ{FRAC} coefficients, and 0 otherwise. \fun{long}{RgV_isin}{GEN v, GEN x} return the first index $i$ such that $v[i] = x$ if it exists, and $0$ otherwise. Naive search in linear time, does not assume that \kbd{v} is sorted. \fun{GEN}{RgM_diagonal}{GEN m} returns the diagonal of $m$ as a \typ{VEC}. \fun{GEN}{RgM_diagonal_shallow}{GEN m} shallow version of \kbd{RgM\_diagonal} \subsubsec{Conversion to floating point entries} \fun{GEN}{RgC_gtofp}{GEN x, GEN prec} returns the \typ{COL} obtained by applying \kbd{gtofp(gel(x,i), prec)} to all coefficients of $x$. \fun{GEN}{RgV_gtofp}{GEN x, GEN prec} returns the \typ{VEC} obtained by applying \kbd{gtofp(gel(x,i), prec)} to all coefficients of $x$. \fun{GEN}{RgC_gtomp}{GEN x, long prec} returns the \typ{COL} obtained by applying \kbd{gtomp(gel(x,i), prec)} to all coefficients of $x$. \fun{GEN}{RgC_fpnorml2}{GEN x, long prec} returns (a stack-clean variant of) \bprog gnorml2( RgC_gtofp(x, prec) ) @eprog \fun{GEN}{RgM_gtofp}{GEN x, GEN prec} returns the \typ{MAT} obtained by applying \kbd{gtofp(gel(x,i), prec)} to all coefficients of $x$. \fun{GEN}{RgM_gtomp}{GEN x, long prec} returns the \typ{MAT} obtained by applying \kbd{gtomp(gel(x,i), prec)} to all coefficients of $x$. \fun{GEN}{RgM_fpnorml2}{GEN x, long prec} returns (a stack-clean variant of) \bprog gnorml2( RgM_gtofp(x, prec) ) @eprog \subsubsec{Linear algebra, linear systems} \fun{GEN}{RgM_inv}{GEN a} returns a left inverse of $a$ (which needs not be square), or \kbd{NULL} if this turns out to be impossible. The latter happens when the matrix does not have maximal rank (or when rounding errors make it appear so). \fun{GEN}{RgM_inv_upper}{GEN a} as \kbd{RgM\_inv}, assuming that $a$ is a non-empty invertible upper triangular matrix, hence a little faster. \fun{GEN}{RgM_RgC_invimage}{GEN A, GEN B} returns a \typ{COL} $X$ such that $A X = B$ if one such exists, and \kbd{NULL} otherwise. \fun{GEN}{RgM_invimage}{GEN A, GEN B} returns a \typ{MAT} $X$ such that $A X = B$ if one such exists, and \kbd{NULL} otherwise. \fun{GEN}{RgM_Hadamard}{GEN a} returns a upper bound for the absolute value of $\text{det}(a)$. The bound is a \typ{INT}. \fun{GEN}{RgM_solve}{GEN a, GEN b} returns $a^{-1}b$ where $a$ is a square \typ{MAT} and $b$ is a \typ{COL} or \typ{MAT}. Returns \kbd{NULL} if $a^{-1}$ cannot be computed, see \tet{RgM_inv}. If $b = \kbd{NULL}$, the matrix $a$ need no longer be square, and we strive to return a left inverse for $a$ (\kbd{NULL} if it does not exist). \fun{GEN}{RgM_solve_realimag}{GEN M, GEN b} $M$ being a \typ{MAT} with $r_1+r_2$ rows and $r_1+2r_2$ columns, $y$ a \typ{COL} or \typ{MAT} such that the equation $Mx = y$ makes sense, returns $x$ under the following simplifying assumptions: the first $r_1$ rows of $M$ and $y$ are real (the $r_2$ others are complex), and $x$ is real. This is stabler and faster than calling $\kbd{RgM\_solve}(M, b)$ over $\C$. In most applications, $M$ approximates the complex embeddings of an integer basis in a number field, and $x$ is actually rational. \fun{GEN}{split_realimag}{GEN x, long r1, long r2} $x$ is a \typ{COL} or \typ{MAT} with $r_1 + r_2$ rows, whose first $r_1$ rows have real entries (the $r_2$ others are complex). Return an object of the same type as $x$ and $r_1 + 2r_2$ rows, such that the first $r_1 + r_2$ rows contain the real part of $x$, and the $r_2$ following ones contain the imaginary part of the last $r_2$ rows of $x$. Called by \tet{RgM_solve_realimag}. \fun{GEN}{RgM_det_triangular}{GEN x} returns the product of the diagonal entries of $x$ (its determinant if it is indeed triangular). \fun{GEN}{Frobeniusform}{GEN V, long n} given the vector $V$ of elementary divisors for $M - x\text{Id}$, where $M$ is an $n\times n$ square matrix. Returns the Frobenius form of $M$. \fun{int}{RgM_QR_init}{GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec} QR-decomposition of a square invertible \typ{MAT} $x$ with real coefficients. Sets \kbd{*pB} to the vector of squared lengths of the $x[i]$, \kbd{*pL} to the Gram-Schmidt coefficients and \kbd{*pQ} to a vector of successive Householder transforms. If $R$ denotes the transpose of $L$ and $Q$ is the result of applying \kbd{*pQ} to the identity matrix, then $x = QR$ is the QR decomposition of $x$. Returns $0$ is $x$ is not invertible or we hit a precision problem, and $1$ otherwise. \fun{int}{QR_init}{GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec} as \kbd{RgM\_QR\_init}, assuming further that $x$ has \typ{INT} or \typ{REAL} coefficients. \fun{GEN}{R_from_QR}{GEN x, long prec} assuming that $x$ is a square invertible \typ{MAT} with \typ{INT} or \typ{REAL} coefficients, return the upper triangular $R$ from the $QR$ docomposition of $x$. Not memory clean. If the matrix is not known to have \typ{INT} or \typ{REAL} coefficients, apply \tet{RgM_gtomp} first. \fun{GEN}{gaussred_from_QR}{GEN x, long prec} assuming that $x$ is a square invertible \typ{MAT} with \typ{INT} or \typ{REAL} coefficients, returns \kbd{qfgaussred(x\til * x)}; this is essentially the upper triangular $R$ matrix from the $QR$ decomposition of $x$, renormalized to accomodate \kbd{qfgaussred} conventions. Not memory clean. \fun{GEN}{RgM_gram_schmidt}{GEN e, GEN *ptB} naive (unstable) Gram-Schmidt orthogonalization of the basis $(e_i)$ given by the columns of \typ{MAT} $e$. Return the $e_i^*$ (as columns of a \typ{MAT}) and set \kbd{*ptB} to the vector of squared lengths $|e_i^*|^2$. \fun{GEN}{RgM_Babai}{GEN M, GEN y} given an LLL-reduced \typ{MAT} $M$ and a \typ{COL} $y$ of the same dimension, apply Babai's nearest plane algorithm to return an \emph{integral} $x$ such that $y - Mx$ has small $L_2$ norm. This yields an approximate solution to the closest vector problem. \subsec{\kbd{ZG}} Let $G$ be a multiplicative group with neutral element $1_G$ whose multiplication is supported by \kbd{gmul} and where equality test is performed using \tet{gidentical}, e.g. a matrix group. The following routines implement basic computations in the group algebra $\Z[G]$. All of them are shallow for efficiency reasons. A \kbd{ZG} is either \item a \typ{INT} $n$, representing $n[1_G]$ \item or a ``factorization matrix'' with two columns $[g,e]$: the first one contains group elements, sorted according to \tet{cmp_universal}, and the second one contains integer ``exponents'', representing $\sum e_i [g_i]$. Note that \tet{to_famat} and \tet{to_famat_shallow}$(g,e)$ allow to build the \kbd{ZG} $e[g]$ from $e\in \Z$ and $g\in G$. \fun{GEN}{ZG_normalize}{GEN x} given a \typ{INT} $x$ or a factorization matrix \emph{without} assuming that the first column is properly sorted. Return a valid (sorted) \kbd{ZG}. Shallow function. \fun{GEN}{ZG_add}{GEN x, GEN y} return $x+y$; shallow function. \fun{GEN}{ZG_neg}{GEN x} return $-x$; shallow function. \fun{GEN}{ZG_sub}{GEN x, GEN y} return $x-y$; shallow function. \fun{GEN}{ZG_mul}{GEN x, GEN y} return $xy$; shallow function. \fun{GEN}{ZG_G_mul}{GEN x, GEN y} given a \kbd{ZG} $x$ and $y\in G$, return $xy$; shallow function. \fun{GEN}{G_ZG_mul}{GEN x, GEN y} given a \kbd{ZG} $y$ and $x\in G$, return $xy$; shallow function. \fun{GEN}{ZG_Z_mul}{GEN x, GEN n} given a \kbd{ZG} $x$ and $y\in \Z$, return $xy$; shallow function. \fun{GEN}{ZGC_G_mul}{GEN v, GEN x} given $v$ a vector of \kbd{ZG} and $x\in G$ return the vector (with the same type as $v$ with entries $v[i]\cdot x$. Shallow function. \fun{void}{ZGC_G_mul_inplace}{GEN v, GEN x} as \tet{ZGC_G_mul}, modifying $v$ in place. \fun{GEN}{ZGC_Z_mul}{GEN v, GEN n} given $v$ a vector of \kbd{ZG} and $n\in Z$ return the vector (with the same type as $v$ with entries $n \cdot v[i]$. Shallow function. \fun{GEN}{G_ZGC_mul}{GEN x, GEN v} given $v$ a vector of \kbd{ZG} and $x\in G$ return the vector of $x \cdot v[i]$. Shallow function. \fun{GEN}{ZGCs_add}{GEN x, GEN y} add two sparse vectors of \kbd{ZG} elements (see Blackbox linear algebra below). \subsec{Blackbox linear algebra} A sparse column \kbd{zCs} $v$ is a \typ{COL} with two components $C$ and $E$ which are \typ{VECSMALL} of the same length, representing $\sum_i E[i]*e_{C[i]}$, where $(e_j)$ is the canonical basis. A sparse matrix (\kbd{zMs}) is a \typ{VEC} of \kbd{zCs}. \kbd{FpCs} and \kbd{FpMs} are identical to the above, but $E[i]$ is now interpreted as a \emph{signed} C long integer representing an element of $\F_p$. This is important since $p$ can be so large that $p+E[i]$ would not fit in a C long. \kbd{RgCs} and \kbd{RgMs} are similar, except that the type of the components of $E$ is now unspecified. Functions handling those later objects must not depend on the type of those components. It is not possible to derive the space dimension (number of rows) from the above data. Thus most functions take an argument \kbd{nbrow} which is the number of rows of the corresponding column/matrix in dense representation. \fun{GEN}{zCs_to_ZC}{GEN C, long nbrow} convert the sparse vector $C$ to a dense \kbd{ZC} of dimension \kbd{nbrow}. \fun{GEN}{zMs_to_ZM}{GEN M, long nbrow} convert the sparse matrix $M$ to a dense \kbd{ZM} whose columns have dimension \kbd{nbrow}. \fun{GEN}{FpMs_FpC_mul}{GEN M, GEN B, GEN p} multiply the sparse matrix $M$ (over $\F_p$) by the sparse vector $B$. The result is an \kbd{FpC}, i.e.~a dense vector. \fun{GEN}{zMs_ZC_mul}{GEN M, GEN B, GEN p} multiply the sparse matrix $M$ by the sparse vector $B$ (over $\Z$). The result is an \kbd{ZC}, i.e.~a dense vector. \fun{GEN}{FpV_FpMs_mul}{GEN B, GEN M, GEN p} multiply the sparse vector $B$ by the sparse matrix $M$ (over $\F_p$). The result is an \kbd{FpV}, i.e.~a dense vector. \fun{GEN}{ZV_zMs_mul}{GEN B, GEN M, GEN p} multiply the sparse vector $B$ (over $\Z$) by the sparse matrix $M$. The result is an \kbd{ZV}, i.e.~a dense vector. \fun{void}{RgMs_structelim}{GEN M, long nbrow, GEN A, GEN *p_col, GEN *p_row} $M$ being a RgMs with \kbd{nbrow} rows, $A$ being a list of row indices, Perform structured elimination on $M$ by removing some rows and columns until the number of effectively present rows is equal to the number of columns. the result is stored in two \typ{VECSMALL}s, \kbd{*p\_col} and \kbd{*p\_row}: \kbd{*p\_col} is a map from the new columns indices to the old one. \kbd{*p\_row} is a map from the old rows indices to the new one ($0$ if removed). \fun{GEN}{FpMs_leftkernel_elt}{GEN M, long nbrow, GEN p} $M$ being a sparse matrix over $\F_p$, return a non-zero kbd{FpV} $X$ such that $X\*M$ components are almost all $0$. \fun{GEN}{FpMs_FpCs_solve}{GEN M, GEN B, long nbrow, GEN p} solve the equation $M\*X = B$, where $M$ is a sparse matrix and $B$ is a sparse vector, both over $\F_p$. Return either a solution as a \typ{COL} (dense vector), the index of a column which is linearly dependent from the others as a \typ{VECSMALL} with a single component, or \kbd{NULL} (can happen if $B$ is not in the image of $M$). \fun{GEN}{FpMs_FpCs_solve_safe}{GEN M, GEN B, long nbrow, GEN p} as above, but in the event that $p$ is not a prime and an impossible division occurs, return \kbd{NULL}. \fun{GEN}{ZpMs_ZpCs_solve}{GEN M, GEN B, long nbrow, GEN p, long e} solve the equation $MX = B$, where $M$ is a sparse matrix and $B$ is a sparse vector, both over $\Z/p^e\Z$. Return either a solution as a \typ{COL} (dense vector), or the index of a column which is linearly dependent from the others as a \typ{VECSMALL} with a single component. \fun{GEN}{gen_FpM_Wiedemann}{void *E, GEN (*f)(void*, GEN), GEN B, GEN p} solve the equation $f(X) = B$ over $\F_p$, where $B$ is a \kbd{FpV}, and $f$ is a blackbox endomorphism, where $f(E, X)$ computes the value of $f$ at the (dense) column vector $X$. Returns either a solution \typ{COL}, or a kernel vector as a \typ{VEC}. \fun{GEN}{gen_ZpM_Dixon}{void *E, GEN (*f)(void*, GEN), GEN B, GEN p, long e} solve equation $f(X) = B$ over $\Z/p^e\Z$, where $B$ is a \kbd{ZV}, and $f$ is a blackbox endomorphism, where $f(E, X)$ computes the value of $f$ at the (dense) column vector $X$. Returns either a solution \typ{COL}, or a kernel vector as a \typ{VEC}. \subsec{Obsolete functions} The functions in this section are kept for backward compatibility only and will eventually disappear. \fun{GEN}{image2}{GEN x} compute the image of $x$ using a very slow algorithm. Use \tet{image} instead. \section{Integral, rational and generic polynomial arithmetic} \subsec{\kbd{ZX}} \fun{void}{RgX_check_ZX}{GEN x, const char *s} Assuming \kbd{x} is a \typ{POL} raise an error if it is not a \kbd{ZX} ($s$ should point to the name of the caller). \fun{GEN}{ZX_copy}{GEN x,GEN p} returns a copy of \kbd{x}. \fun{long}{ZX_max_lg}{GEN x} returns the effective length of the longest component in $x$. \fun{GEN}{scalar_ZX}{GEN x, long v} returns the constant \kbd{ZX} in variable $v$ equal to the \typ{INT} $x$. \fun{GEN}{scalar_ZX_shallow}{GEN x, long v} returns the constant \kbd{ZX} in variable $v$ equal to the \typ{INT} $x$. Shallow function not suitable for \kbd{gerepile} and friends. \fun{GEN}{ZX_renormalize}{GEN x, long l}, as \kbd{normalizepol}, where $\kbd{l} = \kbd{lg(x)}$, in place. \fun{int}{ZX_equal}{GEN x, GEN y} returns $1$ if the two \kbd{ZX} have the same \kbd{degpol} and their coefficients are equal. Variable numbers are not checked. \fun{int}{ZX_equal1}{GEN x} returns $1$ if the \kbd{ZX} $x$ is equal to $1$ and $0$ otherwise. \fun{int}{ZX_is_monic}{GEN x} returns $1$ if the \kbd{ZX} $x$ is monic and $0$ otherwise. The zero polynomial considered not monic. \fun{GEN}{ZX_add}{GEN x,GEN y} adds \kbd{x} and \kbd{y}. \fun{GEN}{ZX_sub}{GEN x,GEN y} subtracts \kbd{x} and \kbd{y}. \fun{GEN}{ZX_neg}{GEN x} returns $-\kbd{x}$. \fun{GEN}{ZX_Z_add}{GEN x,GEN y} adds the integer \kbd{y} to the \kbd{ZX}~\kbd{x}. \fun{GEN}{ZX_Z_add_shallow}{GEN x,GEN y} shallow version of \tet{ZX_Z_add}. \fun{GEN}{ZX_Z_sub}{GEN x,GEN y} subtracts the integer \kbd{y} to the \kbd{ZX}~\kbd{x}. \fun{GEN}{Z_ZX_sub}{GEN x,GEN y} subtracts the \kbd{ZX} \kbd{y} to the integer \kbd{x}. \fun{GEN}{ZX_Z_mul}{GEN x,GEN y} multiplies the \kbd{ZX} \kbd{x} by the integer \kbd{y}. \fun{GEN}{ZX_mulu}{GEN x, ulong y} multiplies \kbd{x} by the integer \kbd{y}. \fun{GEN}{ZX_shifti}{GEN x, long n} shifts all coefficients of \kbd{x} by $n$ bits, which can be negative. \fun{GEN}{ZX_Z_divexact}{GEN x, GEN y} returns $x/y$ assuming all divisions are exact. \fun{GEN}{ZX_remi2n}{GEN x, long n} reduces all coefficients of \kbd{x} to $n$ bits, using \tet{remi2n}. \fun{GEN}{ZX_mul}{GEN x,GEN y} multiplies \kbd{x} and \kbd{y}. \fun{GEN}{ZX_sqr}{GEN x,GEN p} returns $\kbd{x}^2$. \fun{GEN}{ZX_mulspec}{GEN a, GEN b, long na, long nb}. Internal routine: \kbd{a} and \kbd{b} are arrays of coefficients representing polynomials $\sum_{i = 0}^{\kbd{na-1}} \kbd{a}[i] X^i$ and $\sum_{i = 0}^{\kbd{nb-1}} \kbd{b}[i] X^i$. Returns their product (as a true \kbd{GEN}) in variable $0$. \fun{GEN}{ZX_sqrspec}{GEN a, long na}. Internal routine: \kbd{a} is an array of coefficients representing polynomial $\sum_{i = 0}^{\kbd{na-1}} \kbd{a}[i] X^i$. Return its square (as a true \kbd{GEN}) in variable $0$. \fun{GEN}{ZX_rem}{GEN x, GEN y} returns the remainder of the Euclidean division of $x$ mod $y$. Assume that $x$, $y$ are two \kbd{ZX} and that $y$ is monic. \fun{GEN}{ZX_mod_Xnm1}{GEN T, ulong n} return $T$ modulo $X^n - 1)$. Shallow function. \fun{GEN}{ZX_div_by_X_1}{GEN T, GEN *r} return the quotient of $T$ by $X-1$. If $r$ is not \kbd{NULL} set it to $T(1)$. \fun{GEN}{ZX_gcd}{GEN x,GEN y} returns a gcd of the \kbd{ZX} $x$ and $y$. Not memory-clean, but suitable for \kbd{gerepileupto}. \fun{GEN}{ZX_gcd_all}{GEN x, GEN y, GEN *pX} returns a gcd $d$ of $x$ and $y$. If \kbd{pX} is not \kbd{NULL}, set $\kbd{*pX}$ to a (non-zero) integer multiple of $x/d$. If $x$ and $y$ are both monic, then $d$ is monic and \kbd{*pX} is exactly $x/d$. Not memory clean if the gcd is $1$ (in that case \kbd{*pX} is set to $x$). \fun{GEN}{ZX_radical}{GEN x} returns the largest squarefree divisor of the \kbd{ZX} $x$. Not memory clean. \fun{GEN}{ZX_content}{GEN x} returns the content of the \kbd{ZX} $x$. \fun{long}{ZX_val}{GEN P} as \kbd{RgX\_val}, but assumes \kbd{P} has \typ{INT} coefficients. \fun{long}{ZX_valrem}{GEN P, GEN *z} as \kbd{RgX\_valrem}, but assumes \kbd{P} has \typ{INT} coefficients. \fun{GEN}{ZX_to_monic}{GEN q GEN *L} given $q$ a non-zero \kbd{ZX}, returns a monic integral polynomial $Q$ such that $Q(x) = C q(x/L)$, for some rational $C$ and positive integer $L > 0$. If $\kbd{L}$ is not \kbd{NULL}, set \kbd{*L} to $L$; if $L = 1$, \kbd{*L} is set to \kbd{gen\_1}. Not suitable for gerepileupto. \fun{GEN}{ZX_primitive_to_monic}{GEN q, GEN *L} as \tet{ZX_to_monic} except $q$ is assumed to have trivial content, which avoids recomputing it. The result is suboptimal if $q$ is not primitive ($L$ larger than necessary), but remains correct. \fun{GEN}{ZX_Z_normalize}{GEN q, GEN *L} a restricted version of \kbd{ZX\_primitive\_to\_monic}, where $q$ is a \emph{monic} \kbd{ZX} of degree $> 0$. Finds the largest integer $L > 0$ such that $Q(X) := L^{-\deg q} q(Lx)$ is integral and return $Q$; this is not well-defined if $q$ is a monomial, in that case, set $L=1$ and $Q = q$. If \kbd{L} is not \kbd{NULL}, set \kbd{*L} to $L$. \fun{GEN}{ZX_Q_normalize}{GEN q, GEN *L} a variant of \tet{ZX_Z_normalize} where $L > 0$ is allowed to be rational, the monic $Q\in \Z[X]$ has possibly smaller coefficients. \fun{GEN}{ZX_Q_mul}{GEN x, GEN y} returns $x*y$, where $y$ is a rational number and the resulting \typ{POL} has rational entries. \fun{long}{ZX_deflate_order}{GEN P} given a non-constant \kbd{ZX} $P$, returns the largest exponent $d$ such that $P$ is of the form $P(x^d)$. \fun{long}{ZX_deflate_max}{GEN P, long *d}. Given a non-constant polynomial with integer coefficients $P$, sets \kbd{d} to \kbd{ZX\_deflate\_order(P)} and returns \kbd{RgX\_deflate(P,d)}. Shallow function. \fun{GEN}{ZX_rescale}{GEN P, GEN h} returns $h^{\deg(P)} P(x/h)$. \kbd{P} is a \kbd{ZX} and \kbd{h} is a non-zero integer. Neither memory-clean nor suitable for \kbd{gerepileupto}. \fun{GEN}{ZX_rescale2n}{GEN P, long n} returns $2^{n\deg(P)} P(x>>n)$ where \kbd{P} is a \kbd{ZX}. Neither memory-clean nor suitable for \kbd{gerepileupto}. \fun{GEN}{ZX_rescale_lt}{GEN P} returns the monic integral polynomial $h^{\deg(P)-1} P(x/h)$, where \kbd{P} is a non-zero \kbd{ZX} and \kbd{h} is its leading coefficient. Neither memory-clean nor suitable for \kbd{gerepileupto}. \fun{GEN}{ZX_translate}{GEN P, GEN c} assume $P$ is a \kbd{ZX} and $c$ an integer. Returns $P(X + c)$ (optimized for $c = \pm 1$). \fun{GEN}{ZX_unscale}{GEN P, GEN h} given a \kbd{ZX} $P$ and a \typ{INT} $h$, returns $P(hx)$. Not memory clean. \fun{GEN}{ZX_z_unscale}{GEN P, long h} given a \kbd{ZX} $P$, returns $P(hx)$. Not memory clean. \fun{GEN}{ZX_unscale2n}{GEN P, long n} given a \kbd{ZX} $P$, returns $P(x<0} (1-X^{ri}) \pmod{X^n}$, $r > 0$. \fun{GEN}{eta_product_ZXn}{GEN DR, long n}: $\kbd{DR}= [D,R]$ being a vector with two \typ{VECSMALL} components, return $\prod_i \eta(X^{d_i})^{r_i}$. Shallow function. \subsec{\kbd{ZXQM}} \kbd{ZXQM} are matrices of \kbd{ZXQ}. All entries must be integers or polynomials of degree strictly less than the degree of $T$. \fun{GEN}{ZXQM_mul}{GEN x,GEN y,GEN T} returns $x*y$ mod $T$, assuming that all inputs are \kbd{ZX}s and that $T$ is monic. \fun{GEN}{ZXQM_sqr}{GEN x,GEN T} returns $x^2$ mod $T$, assuming that all inputs are \kbd{ZX}s and that $T$ is monic. \subsec{\kbd{ZXQX}} \fun{GEN}{ZXQX_mul}{GEN x,GEN y,GEN T} returns $x*y$, assuming that all inputs are \kbd{ZXQX}s and that $T$ is monic. \fun{GEN}{ZXQX_sqr}{GEN x,GEN T} returns $x^2$, assuming that all inputs are \kbd{ZXQX}s and that $T$ is monic. \subsec{\kbd{ZXX}} \fun{void}{RgX_check_ZXX}{GEN x, const char *s} Assuming \kbd{x} is a \typ{POL} raise an error if it one of its coefficients is not an integer or a \kbd{ZX} ($s$ should point to the name of the caller). \fun{GEN}{ZXX_renormalize}{GEN x, long l}, as \kbd{normalizepol}, where $\kbd{l} = \kbd{lg(x)}$, in place. \fun{long}{ZXX_max_lg}{GEN x} returns the effective length of the longest component in $x$; assume all coefficients are \typ{INT} or \kbd{ZX}s. \fun{GEN}{ZXX_Z_mul}{GEN x, GEN y} returns $x\*y$. \fun{GEN}{ZXX_Z_add_shallow}{GEN x, GEN y} returns $x+y$. Shallow function. \fun{GEN}{ZXX_Z_divexact}{GEN x, GEN y} returns $x/y$ assuming all integer divisions are exact. \fun{GEN}{ZXX_to_Kronecker}{GEN P, long n} Assuming $P(X,Y)$ is a polynomial of degree in $X$ strictly less than $n$, returns $P(X,X^{2*n-1})$, the Kronecker form of $P$. Shallow function. \fun{GEN}{ZXX_to_Kronecker_spec}{GEN Q, long lQ, long n} return \tet{ZXX_to_Kronecker}$(P, n)$, where $P$ is the polynomial $\sum_{i = 0}^{\kbd{lQ} - 1} Q[i] x^i$. To be used when splitting the coefficients of genuine polynomials into blocks. Shallow function. \fun{GEN}{Kronecker_to_ZXX}{GEN z, long n, long v} recover $P(X,Y)$ from its Kronecker form $P(X,X^{2\*n-1})$, $v$ is the variable number corresponding to $Y$. Shallow function. \fun{GEN}{ZXX_mul_Kronecker}{GEN P, GEN Q, long n} return \tet{ZX_mul} applied to the Kronecker forms $P(X,X^{2\*n-1})$ and $Q(X,X^{2\*n-1})$ of $P$ and $Q$. Not memory clean. \fun{GEN}{ZXX_sqr_Kronecker}{GEN P, long n} return \tet{ZX_sqr} applied to the Kronecker forms $P(X,X^{2\*n-1})$ of $P$. Not memory clean. \subsec{\kbd{QX}} \fun{void}{RgX_check_QX}{GEN x, const char *s} Assuming \kbd{x} is a \typ{POL} raise an error if it is not a \kbd{QX} ($s$ should point to the name of the caller). \fun{GEN}{QX_mul}{GEN x,GEN y} \fun{GEN}{QX_sqr}{GEN x} \fun{GEN}{QX_ZX_rem}{GEN x, GEN y} $y$ is assumed to be monic. \fun{GEN}{QX_gcd}{GEN x,GEN y} returns a gcd of the \kbd{QX} $x$ and $y$. \fun{GEN}{QX_disc}{GEN T} returns the discriminant of the \kbd{QX} \kbd{T}. \fun{GEN}{QX_factor}{GEN T} as \kbd{ZX\_factor}. \fun{GEN}{QX_resultant}{GEN A, GEN B} returns the resultant of the \kbd{QX}~\kbd{A} and \kbd{B}. \fun{GEN}{QX_complex_roots}{GEN p, long l} returns the complex roots of the \kbd{QX} $p$ at accuracy $l$, where real roots are returned as \typ{REAL}s. More efficient when $p$ is irreducible and primitive. Special case of \tet{cleanroots}. \subsec{\kbd{QXQ}} \fun{GEN}{QXQ_norm}{GEN A, GEN B} $A$ being a \kbd{QX} and $B$ being a \kbd{ZX}, returns the norm of the algebraic number $A \mod B$, using a modular algorithm. To ensure that $B$ is a \kbd{ZX}, one may replace it by \kbd{Q\_primpart(B)}, which of course does not change the norm. If $A$ is not a \kbd{ZX} --- it has a denominator ---, but the result is nevertheless known to be an integer, it is much more efficient to call \tet{QXQ_intnorm} instead. \fun{GEN}{QXQ_intnorm}{GEN A, GEN B} $A$ being a \kbd{QX} and $B$ being a \kbd{ZX}, returns the norm of the algebraic number $A \mod B$, \emph{assuming} that the result is an integer, which is for instance the case is $A\mod B$ is an algebraic integer, in particular if $A$ is a \kbd{ZX}. To ensure that $B$ is a \kbd{ZX}, one may replace it by \kbd{Q\_primpart(B)} (which of course does not change the norm). If the result is not known to be an integer, you must use \tet{QXQ_norm} instead, which is slower. \fun{GEN}{QXQ_mul}{GEN A, GEN B, GEN T} returns the product of $A$ and $B$ modulo $T$ where both $A$ and $B$ are a \kbd{QX} and $T$ is a monic \kbd{ZX}. \fun{GEN}{QXQ_sqr}{GEN A, GEN T} returns the square of $A$ modulo $T$ where $A$ is a \kbd{QX} and $T$ is a monic \kbd{ZX}. \fun{GEN}{QXQ_inv}{GEN A, GEN B} returns the inverse of $A$ modulo $B$ where $A$ is a \kbd{QX} and $B$ is a \kbd{ZX}. Should you need this for a \kbd{QX} $B$, just use \bprog QXQ_inv(A, Q_primpart(B)); @eprog\noindent But in all cases where modular arithmetic modulo $B$ is desired, it is much more efficient to replace $B$ by \kbd{Q\_primpart$(B)$} once and for all. \fun{GEN}{QXQ_div_ratlift}{GEN C, GEN A, GEN B} returns $C/A$ modulo $B$ where $A$ and $C$ are \kbd{QX} and $B$ is a \kbd{ZX}. Use this function when the result is known to be ``small'' compared to $A^{-1}$ mod $B$, it will be faster than \tet{QXQ_inv} in this case. \fun{GEN}{QXQ_charpoly}{GEN A, GEN T, long v} where \kbd{A} is a \kbd{QX} and \kbd{T} is a \kbd{ZX}, returns the characteristic polynomial of \kbd{Mod(A, T)}. If the result is known to be a \kbd{ZX}, then calling \kbd{ZXQ\_charpoly} will be faster. \fun{GEN}{QXQ_powers}{GEN x, long n, GEN T} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as \kbd{RgXQ\_powers} would, but in a more efficient way when $x$ has a huge integer denominator (we start by removing that denominator). Meant to be used to precompute powers of algebraic integers in $\Q[t]/(T)$. The current implementation does not require $x$ to be a \kbd{QX}: any polynomial to which \kbd{Q\_remove\_denom} can be applied is fine. \fun{GEN}{QXQ_reverse}{GEN f, GEN T} as \kbd{RgXQ\_reverse}, assuming $f$ is a \kbd{QX}. \fun{GEN}{QX_ZXQV_eval}{GEN f, GEN nV, GEN dV} as \kbd{RgX\_RgXQV\_eval}, except that $f$ is assumed to be a \kbd{QX}, $V$ is given implicitly by a numerator \kbd{nV} (\kbd{ZV}) and denominator \kbd{dV} (a positive \typ{INT} or \kbd{NULL} for trivial denominator). Not memory clean, but suitable for \kbd{gerepileupto}. \fun{GEN}{QXV_QXQ_eval}{GEN v, GEN a, GEN T} $v$ is a vector of \kbd{QX}s (possibly scalars, i.e.~rational numbers, for convenience), $a$ and $T$ both \kbd{QX}. Return the vector of evaluations at $a$ modulo $T$. Not memory clean, nor suitable for \kbd{gerepileupto}. \fun{GEN}{QXX_QXQ_eval}{GEN P, GEN a, GEN T} $P(X,Y)$ is a \typ{POL} with \kbd{QX} coefficients (possibly scalars, i.e.~rational numbers, for convenience) , $a$ and $T$ both \kbd{QX}. Return the \kbd{QX} $P(X, a \mod T)$. Not memory clean, nor suitable for \kbd{gerepileupto}. \fun{GEN}{nfgcd}{GEN P, GEN Q, GEN T, GEN den} given $P$ and $Q$ in $\Z[X,Y]$, $T$ monic irreducible in $\Z[Y]$, returns the primitive $d$ in $\Z[X,Y]$ which is a gcd of $P$, $Q$ in $K[X]$, where $K$ is the number field $\Q[Y]/(T)$. If not \kbd{NULL}, \kbd{den} is a multiple of the integral denominator of the (monic) gcd of $P,Q$ in $K[X]$. \fun{GEN}{nfgcd_all}{GEN P, GEN Q, GEN T, GEN den, GEN *Pnew} as \kbd{nfgcd}. If \kbd{Pnew} is not \kbd{NULL}, set \kbd{*Pnew} to a non-zero integer multiple of $P/d$. If $P$ and $Q$ are both monic, then $d$ is monic and \kbd{*Pnew} is exactly $P/d$. Not memory clean if the gcd is $1$ (in that case \kbd{*Pnew} is set to $P$). \subsec{\kbd{QXQM}} \kbd{QXQM} are matrices of \kbd{QXQ}. All entries must be \typ{INT}, \typ{FRAC} or polynomials of degree strictly less than the degree of $T$, which must be a monic \kbd{ZX}. \fun{GEN}{QXQM_mul}{GEN x,GEN y,GEN T} returns $x*y$ mod $T$. \fun{GEN}{QXQM_sqr}{GEN x,GEN T} returns $x^2$ mod $T$. \subsec{\kbd{zx}} \fun{GEN}{zero_zx}{long sv} returns a zero \kbd{zx} in variable $v$. \fun{GEN}{polx_zx}{long sv} returns the variable $v$ as degree~1~\kbd{Flx}. \fun{GEN}{zx_renormalize}{GEN x, long l}, as \kbd{Flx\_renormalize}, where $\kbd{l} = \kbd{lg(x)}$, in place. \fun{GEN}{zx_shift}{GEN T, long n} returns \kbd{T} multiplied by $\kbd{x}^n$, assuming $n\geq 0$. \subsec{\kbd{RgX}} \subsubsec{Tests} \fun{long}{RgX_degree}{GEN x, long v} $x$ being a \typ{POL} and $v \geq 0$, returns the degree in $v$ of $x$. Error if $x$ is not a polynomial in $v$. \fun{int}{RgX_isscalar}{GEN x} return 1 if $x$ all the coefficients of $x$ of degree $> 0$ are $0$ (as per \kbd{gequal0}). \fun{int}{RgX_is_rational}{GEN P} return 1 if the \kbd{RgX}~$P$ has only rational coefficients (\typ{INT} and \typ{FRAC}), and 0 otherwise. \fun{int}{RgX_is_QX}{GEN P} return 1 if the \kbd{RgX}~$P$ has only \typ{INT} and \typ{FRAC} coefficients, and 0 otherwise. \fun{int}{RgX_is_ZX}{GEN P} return 1 if the \kbd{RgX}~$P$ has only \typ{INT} coefficients, and 0 otherwise. \fun{int}{RgX_is_monomial}{GEN x} returns 1 (true) if \kbd{x} is a non-zero monomial in its main variable, 0~otherwise. \fun{long}{RgX_equal}{GEN x, GEN y} returns $1$ if the \typ{POL}s $x$ and $y$ have the same \kbd{degpol} and their coefficients are equal (as per \tet{gequal}). Variable numbers are not checked. Note that this is more stringent than \kbd{gequal(x,y)}, which only checks whether $x - y$ satisfies \kbd{gequal0}; in particular, they may have different apparent degrees provided the extra leading terms are $0$. \fun{long}{RgX_equal_var}{GEN x, GEN y} returns $1$ if $x$ and $y$ have the same variable number and \kbd{RgX\_equal(x,y)} is $1$. \subsubsec{Coefficients, blocks} \fun{GEN}{RgX_coeff}{GEN P, long n} return the coefficient of $x^n$ in $P$, defined as \kbd{gen\_0} if $n < 0$ or $n > \kbd{degpol}(P)$. Shallow function. \fun{int}{RgX_blocks}{GEN P, long n, long m} writes $P(X)=a_0(X)+X^n*a_1(X)*X^n+\ldots+X^{n*(m-1)}\*a_{m-1}(X)$, where the $a_i$ are polynomial of degree at most $n-1$ (except possibly for the last one) and returns $[a_0(X),a_1(X),\ldots,a_{m-1}(X)]$. Shallow function. \fun{void}{RgX_even_odd}{GEN p, GEN *pe, GEN *po} write $p(X) = E(X^2) + X O(X^2)$ and set \kbd{*pe = E}, \kbd{*po = O}. Shallow function. \fun{GEN}{RgX_splitting}{GEN P, long k} write $P(X)=a_0(X^k)+X\*a_1(X^k)+\ldots+X^{k-1}\*a_{k-1}(X^k)$ and return $[a_0(X),a_1(X),\ldots,a_{k-1}(X)]$. Shallow function. \fun{GEN}{RgX_copy}{GEN x} returns (a deep copy of) $\kbd{x}$. \fun{GEN}{RgX_renormalize}{GEN x} remove leading terms in \kbd{x} which are equal to (necessarily inexact) zeros. \fun{GEN}{RgX_renormalize_lg}{GEN x, long lx} as \kbd{setlg(x, lx)} followed by \kbd{RgX\_renormalize(x)}. Assumes that $\kbd{lx} \leq \kbd{lg(x)}$. \fun{GEN}{RgX_recip}{GEN P} returns the reverse of the polynomial $P$, i.e. $X^{\deg P} P(1/X)$. \fun{GEN}{RgX_recip_shallow}{GEN P} shallow function of \tet{RgX_recip}, where we further assume that $P(0)\neq 0$, so that the degree of the output is the degree of $P$. \fun{GEN}{RgX_deflate}{GEN P, long d} assuming $P$ is a polynomial of the form $Q(X^d)$, return $Q$. Shallow function, not suitable for \kbd{gerepileupto}. \fun{long}{RgX_deflate_order}{GEN P} given a non-constant polynomial $P$, returns the largest exponent $d$ such that $P$ is of the form $P(x^d)$ (use \kbd{gequal0} to check whether coefficients are 0). \fun{long}{RgX_deflate_max}{GEN P, long *d} given a non-constant polynomial $P$, sets \kbd{d} to \kbd{RgX\_deflate\_order(P)} and returns \kbd{RgX\_deflate(P,d)}. Shallow function. \fun{GEN}{RgX_inflate}{GEN P, long d} return $P(X^d)$. Shallow function, not suitable for \kbd{gerepileupto}. \fun{GEN}{RgX_rescale_to_int}{GEN x} given a polynomial $x$ with real entries (\typ{INT}, \typ{FRAC} or \typ{REAL}), return a \kbd{ZX} wich is very close to $D x$ for some well-chosen integer $D$. More precisely, if the input is exact, $D$ is the denominator of $x$; else it is a power of $2$ chosen so that all inexact entries are correctly rounded to 1 ulp. \subsubsec{Shifts, valuations} \fun{GEN}{RgX_shift}{GEN x, long n} returns $\kbd{x} * t^n$ if $n\geq 0$, and $\kbd{x} \bs t^{-n}$ otherwise. \fun{GEN}{RgX_shift_shallow}{GEN x, long n} as \kbd{RgX\_shift}, but shallow (coefficients are not copied). \fun{GEN}{RgX_rotate_shallow}{GEN P, long k, long p} returns $\kbd{P} * X^k \pmod {X^p-1}$, assuming the degree of $P$ is strictly less than $p$, and $k\geq 0$. \fun{void}{RgX_shift_inplace_init}{long v} $v \geq 0$, prepare for a later call to \tet{RgX_shift_inplace}. Reserves $v$ words on the stack. \fun{GEN}{RgX_shift_inplace}{GEN x, long v} $v \geq 0$, assume that \tet{RgX_shift_inplace_init}$(v)$ has been called (reserving $v$ words on the stack), immediately followed by a \typ{POL} $x$. Return \kbd{RgX\_shift}$(x,v)$ by shifting $x$ in place. To be used as follows \bprog RgX_shift_inplace_init(v); av = avma; ... x = gerepileupto(av, ...); /* a t_POL */ return RgX_shift_inplace(x, v); @eprog \fun{long}{RgX_valrem}{GEN P, GEN *pz} returns the valuation $v$ of the \typ{POL}~\kbd{P} with respect to its main variable $X$. Check whether coefficients are $0$ using \kbd{isexactzero}. Set \kbd{*pz} to $\kbd{RgX\_shift\_shallow}(P,-v)$. \fun{long}{RgX_val}{GEN P} returns the valuation $v$ of the \typ{POL}~\kbd{P} with respect to its main variable $X$. Check whether coefficients are $0$ using \kbd{isexactzero}. \fun{long}{RgX_valrem_inexact}{GEN P, GEN *z} as \kbd{RgX\_valrem}, using \kbd{gequal0} instead of \kbd{isexactzero}. \subsubsec{Basic arithmetic} \fun{GEN}{RgX_add}{GEN x,GEN y} adds \kbd{x} and \kbd{y}. \fun{GEN}{RgX_sub}{GEN x,GEN y} subtracts \kbd{x} and \kbd{y}. \fun{GEN}{RgX_neg}{GEN x} returns $-\kbd{x}$. \fun{GEN}{RgX_Rg_add}{GEN y, GEN x} returns $x+y$. \fun{GEN}{RgX_Rg_add_shallow}{GEN y, GEN x} returns $x+y$; shallow function. \fun{GEN}{Rg_RgX_sub}{GEN x, GEN y} \fun{GEN}{RgX_Rg_sub}{GEN y, GEN x} returns $x-y$ \fun{GEN}{RgX_Rg_mul}{GEN y, GEN x} multiplies the \kbd{RgX} \kbd{y} by the scalar \kbd{x}. \fun{GEN}{RgX_muls}{GEN y, long s} multiplies the \kbd{RgX} \kbd{y} by the \kbd{long}~\kbd{s}. \fun{GEN}{RgX_Rg_div}{GEN y, GEN x} divides the \kbd{RgX} \kbd{y} by the scalar \kbd{x}. \fun{GEN}{RgX_divs}{GEN y, long s} divides the \kbd{RgX} \kbd{y} by the \kbd{long}~\kbd{s}. \fun{GEN}{RgX_Rg_divexact}{GEN x, GEN y} exact division of the \kbd{RgX} \kbd{y} by the scalar \kbd{x}. \fun{GEN}{RgX_Rg_eval_bk}{GEN f, GEN x} returns $\kbd{f}(\kbd{x})$ using Brent and Kung algorithm. (Use \tet{poleval} for Horner algorithm.) \fun{GEN}{RgX_RgV_eval}{GEN f, GEN V} as \kbd{RgX\_Rg\_eval\_bk(f, x)}, assuming $V$ was output by \kbd{gpowers(x, n)} for some $n\geq 1$. \fun{GEN}{RgXV_RgV_eval}{GEN f, GEN V} apply \kbd{RgX\_RgV\_eval\_bk(, V)} to all the components of the vector $f$. \fun{GEN}{RgX_normalize}{GEN x} divides $x$ by its leading coefficient. If the latter is~$1$, $x$ itself is returned, not a copy. Leading coefficients equal to $0$ are stripped, e.g. \bprog 0.*t^3 + Mod(0,3)*t^2 + 2*t @eprog\noindent is normalized to $t$. \fun{GEN}{RgX_mul}{GEN x, GEN y} multiplies the two \typ{POL} (in the same variable) \kbd{x} and \kbd{y}. Detect the coefficient ring and use an appropriate algorithm. \fun{GEN}{RgX_mul_i}{GEN x, GEN y} multiplies the two \typ{POL} (in the same variable) \kbd{x} and \kbd{y}. Do not detect the coefficient ring. Use a generic Karatsuba algorithm. \fun{GEN}{RgX_mul_normalized}{GEN A, long a, GEN B, long b} returns $(X^a + A)(X^b + B) - X^(a+b)$, where we assume that $\deg A < a$ and $\deg B < b$ are polynomials in the same variable $X$. \fun{GEN}{RgX_sqr}{GEN x} squares the \typ{POL} \kbd{x}. Detect the coefficient ring and use an appropriate algorithm. \fun{GEN}{RgX_sqr_i}{GEN x} squares the \typ{POL} \kbd{x}. Do not detect the coefficient ring. Use a generic Karatsuba algorithm. \fun{GEN}{RgX_divrem}{GEN x, GEN y, GEN *r} by default, returns the Euclidean quotient and store the remainder in $r$. Three special values of $r$ change that behavior \item \kbd{NULL}: do not store the remainder, used to implement \kbd{RgX\_div}, \item \tet{ONLY_REM}: return the remainder, used to implement \kbd{RgX\_rem}, \item \tet{ONLY_DIVIDES}: return the quotient if the division is exact, and \kbd{NULL} otherwise. \fun{GEN}{RgX_div}{GEN x, GEN y} \fun{GEN}{RgX_div_by_X_x}{GEN A, GEN a, GEN *r} returns the quotient of the \kbd{RgX}~\kbd{A} by $(X - \kbd{a})$, and sets \kbd{r} to the remainder $\kbd{A}(\kbd{a})$. \fun{GEN}{RgX_rem}{GEN x, GEN y} \fun{GEN}{RgX_pseudodivrem}{GEN x, GEN y, GEN *ptr} compute a pseudo-quotient $q$ and pseudo-remainder $r$ such that $\kbd{lc}(y)^{\deg(x) - \deg(y) + 1}x = qy + r$. Return $q$ and set \kbd{*ptr} to $r$. \fun{GEN}{RgX_pseudorem}{GEN x, GEN y} return the remainder in the pseudo-division of $x$ by $y$. \fun{GEN}{RgXQX_pseudorem}{GEN x, GEN y, GEN T} return the remainder in the pseudo-division of $x$ by $y$ over $R[X]/(T)$. \fun{int}{ZXQX_dvd}{GEN x, GEN y, GEN T} let $T$ be a monic irreducible \kbd{ZX}, let $x, y$ be \typ{POL} whose coefficients are either \typ{INT}s or \kbd{ZX} in the same variable as $T$. Assume further that the leading coefficient of $y$ is an integer. Return $1$ if $y | x$ in $(\Z[Y]/(T))[X]$, and $0$ otherwise. \fun{GEN}{RgXQX_pseudodivrem}{GEN x, GEN y, GEN T, GEN *ptr} compute a pseudo-quotient $q$ and pseudo-remainder $r$ such that $\kbd{lc}(y)^{\deg(x) - \deg(y) + 1}x = qy + r$ in $R[X]/(T)$. Return $q$ and set \kbd{*ptr} to $r$. \fun{GEN}{RgX_mulXn}{GEN a, long n} returns $a * X^n$. This may be a \typ{FRAC} if $n < 0$ and the valuation of $a$ is not large enough. \fun{GEN}{RgX_addmulXn}{GEN a, GEN b, long n} returns $a + b * X^n$, assuming that $n > 0$. \fun{GEN}{RgX_addmulXn_shallow}{GEN a, GEN b, long n} shallow variant of \tet{RgX_addmulXn}. \fun{GEN}{RgX_digits}{GEN x, GEN B} returns a vector of \kbd{RgX} $[c_0,\ldots,c_n]$ of degree less than the degree of $B$ and such that $x=\sum_{i=0}^{n}{c_i\*B^i}$. \subsubsec{Internal routines working on coefficient arrays} These routines operate on coefficient blocks which are invalid \kbd{GEN}s A \kbd{GEN} argument $a$ or $b$ in routines below is actually a coefficient arrays representing the polynomials $\sum_{i = 0}^{\kbd{na-1}} a[i] X^i$ and $\sum_{i = 0}^{\kbd{nb-1}} b[i] X^i$. Note that $a[0]$ and $b[0]$ contain coefficients and not the mandatory \kbd{GEN} codeword. This allows to implement divide-and-conquer methods directly, without needing to allocate wrappers around coefficient blocks. \fun{GEN}{RgX_mulspec}{GEN a, GEN b, long na, long nb}. Internal routine: given two coefficient arrays representing polynomials, return their product (as a true \kbd{GEN}) in variable $0$. \fun{GEN}{RgX_sqrspec}{GEN a, long na}. Internal routine: given a coefficient array representing a polynomial r eturn its square (as a true \kbd{GEN}) in variable $0$. \fun{GEN}{RgX_addspec}{GEN x, GEN y, long nx, long ny} given two coefficient arrays representing polynomials, return their sum (as a true \kbd{GEN}) in variable $0$. \fun{GEN}{RgX_addspec_shallow}{GEN x, GEN y, long nx, long ny} shallow variant of \tet{RgX_addspec}. \subsubsec{GCD, Resultant} \fun{GEN}{RgX_gcd}{GEN x, GEN y} returns the GCD of \kbd{x} and \kbd{y}, assumed to be \typ{POL}s in the same variable. \fun{GEN}{RgX_gcd_simple}{GEN x, GEN y} as \tet{RgX_gcd} using a standard extended Euclidean algorithm. Usually slower than \tet{RgX_gcd}. \fun{GEN}{RgX_extgcd}{GEN x, GEN y, GEN *u, GEN *v} returns $d = \text{GCD}(\kbd{x},\kbd{y})$, and sets \kbd{*u}, \kbd{*v} to the Bezout coefficients such that $\kbd{*ux} + \kbd{*vy} = d$. Uses a generic subresultant algorithm. \fun{GEN}{RgX_extgcd_simple}{GEN x, GEN y, GEN *u, GEN *v} as \tet{RgX_extgcd} using a standard extended Euclidean algorithm. Usually slower than \tet{RgX_extgcd}. \fun{GEN}{RgX_disc}{GEN x} returns the discriminant of the \typ{POL} \kbd{x} with respect to its main variable. \fun{GEN}{RgX_resultant_all}{GEN x, GEN y, GEN *sol} returns \kbd{resultant(x,y)}. If \kbd{sol} is not \kbd{NULL}, sets it to the last non-constant remainder in the polynomial remainder sequence if it exists and to \kbd{gen\_0} otherwise (e.g. one polynomial has degree 0). \subsubsec{Other operations} \fun{GEN}{RgX_gtofp}{GEN x, GEN prec} returns the polynomial obtained by applying \bprog gtofp(gel(x,i), prec) @eprog\noindent to all coefficients of $x$. \fun{GEN}{RgX_fpnorml2}{GEN x, long prec} returns (a stack-clean variant of) \bprog gnorml2( RgX_gtofp(x, prec) ) @eprog \fun{GEN}{RgX_deriv}{GEN x} returns the derivative of \kbd{x} with respect to its main variable. \fun{GEN}{RgX_integ}{GEN x} returns the primitive of \kbd{x} vanishing at $0$, with respect to its main variable. \fun{GEN}{RgX_rescale}{GEN P, GEN h} returns $h^{\deg(P)} P(x/h)$. \kbd{P} is an \kbd{RgX} and \kbd{h} is non-zero. (Leaves small objects on the stack. Suitable but inefficient for \kbd{gerepileupto}.) \fun{GEN}{RgX_unscale}{GEN P, GEN h} returns $P(h x)$. (Leaves small objects on the stack. Suitable but inefficient for \kbd{gerepileupto}.) \fun{GEN}{RgXV_unscale}{GEN v, GEN h} apply \kbd{RgX\_unscale} to a vector of \kbd{RgX}. \fun{GEN}{RgX_translate}{GEN P, GEN c} assume $c$ is a scalar or a polynomials whose main variable has lower priority than the main variable $X$ of $P$. Returns $P(X + c)$ (optimized for $c = \pm 1$). \subsubsec{Function related to modular forms} \fun{GEN}{RgX_act_Gl2Q}{GEN g, long k} let $R$ be a commutative ring and $g = [a,b;c,d]$ be in $\text{GL}_2(\Q)$, $g$ acts (on the left) on homogeneous polynomials of degree $k-2$ in $V := R[X,Y]_{k-2}$ via $$ g\cdot P := P(dX-cY, -bX+aY) = (\det g)^{k-2} P((X,Y)\cdot g^{-1}).$$ This function returns the matrix in $M_{k-1}(R)$ of $P\mapsto g\cdot P$ in the basis $(X^{k-2},\dots,Y^{k-2})$ of $V$. \fun{GEN}{RgX_act_ZGl2Q}{GEN z, long k} let $G:=\text{GL}_2(\Q)$, acting on $R[X,Y]_{k-2}$ and $z\in \Z[G]$. Return the matrix giving $P\mapsto z\cdot P$ in the basis $(X^{k-2},\dots,Y^{k-2})$. \subsec{\kbd{RgXn}} \fun{GEN}{RgXn_red_shallow}{GEN x, long n} return $\kbd{x \% } t^n$, where $n\geq 0$. Shallow function. \fun{GEN}{RgXn_recip_shallow}{GEN P} returns $X^n\*P(1/X)$. Shallow function. \fun{GEN}{RgXn_mul}{GEN a, GEN b, long n} returns $a b$ modulo $X^n$, where $a,b$ are two \typ{POL} in the same variable $X$ and $n \geq 0$. Uses Karatsuba algorithm (Mulders, Hanrot-Zimmermann variant). \fun{GEN}{RgXn_sqr}{GEN a, long n} returns $a^2$ modulo $X^n$, where $a$ is a \typ{POL} in the variable $X$ and $n \geq 0$. Uses Karatsuba algorithm (Mulders, Hanrot-Zimmermann variant). \fun{GEN}{RgX_mulhigh_i}{GEN f, GEN g, long n} return the Euclidean quotient of $f(x)*g(x)$ by $x^n$ (high product). Uses \tet{RgXn_mul} applied to the reciprocal polynomials of $f$ and $g$. Not suitable for \kbd{gerepile}. \fun{GEN}{RgX_sqrhigh_i}{GEN f, long n} return the Euclidean quotient of $f(x)^2$ by $x^n$ (high product). Uses \tet{RgXn_sqr} applied to the reciprocal polynomial of $f$. Not suitable for \kbd{gerepile}. \fun{GEN}{RgXn_inv}{GEN a, long n} returns $a^{-1}$ modulo $X^n$, where $a$ is a \typ{POL} in the variable $X$ and $n \geq 0$. Uses Newton-Raphson algorithm. \fun{GEN}{RgXn_inv_i}{GEN a, long n} as \tet{RgXn_inv} without final garbage collection (suitable for \kbd{gerepileupto}). \fun{GEN}{RgXn_powers}{GEN x, long m, long n} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{m}]$ modulo $X^n$ as a \typ{VEC} of \kbd{RgXn}s. \fun{GEN}{RgXn_powu}{GEN x, ulong m, long n} returns $x^m$ modulo $X^n$. \fun{GEN}{RgXn_powu_i}{GEN x, ulong m, long n} as \tet{RgXn_powu}, not memory clean. \fun{GEN}{RgXn_sqrt}{GEN a, long n} returns $a^{1/2}$ modulo $X^n$, where $a$ is a \typ{POL} in the variable $X$ and $n \geq 0$. Assume that $a = 1 \mod{X}$. Uses Newton algorithm. \fun{GEN}{RgXn_exp}{GEN a, long n} returns $exp(a)$ modulo $X^n$, assuming $a = 0 \mod{X}$. Uses Hanrot-Zimmermann algorithm. \fun{GEN}{RgXn_eval}{GEN Q, GEN x, long n} special case of \tet{RgX_RgXQ_eval}, when the modulus is a monomial: returns $\kbd{Q}(\kbd{x})$ modulo $t^n$, where $x \in R[t]$. \fun{GEN}{RgX_RgXn_eval}{GEN f, GEN x, long n} returns $\kbd{f}(\kbd{x})$ modulo $X^n$. \fun{GEN}{RgX_RgXnV_eval}{GEN f, GEN V, long n} as \kbd{RgX\_RgXn\_eval(f, x, n)}, assuming $V$ was output by \kbd{RgXn\_powers(x, m, n)} for some $m\geq 1$. \fun{GEN}{RgXn_reverse}{GEN f, long n} assuming that $f = a\*x \mod{x^2}$ with $a$ invertible, returns a \typ{POL} $g$ of degree $< n$ such that $(g \circ f)(x) = x$ modulo $x^n$. \subsec{\kbd{RgXnV}} \fun{GEN}{RgXnV_red_shallow}{GEN x, long n} apply \kbd{RgXn\_red\_shallow} to all the components of the vector $x$. \subsec{\kbd{RgXQ}} \fun{GEN}{RgXQ_mul}{GEN y, GEN x, GEN T} computes $xy$ mod $T$ \fun{GEN}{RgXQ_sqr}{GEN x, GEN T} computes $x^2$ mod $T$ \fun{GEN}{RgXQ_inv}{GEN x, GEN T} return the inverse of $x$ mod $T$. \fun{GEN}{RgXQ_pow}{GEN x, GEN n, GEN T} computes $x^n$ mod $T$ \fun{GEN}{RgXQ_powu}{GEN x, ulong n, GEN T} computes $x^n$ mod $T$, $n$ being an \kbd{ulong}. \fun{GEN}{RgXQ_powers}{GEN x, long n, GEN T} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as a \typ{VEC} of \kbd{RgXQ}s. \fun{GEN}{RgXQ_matrix_pow}{GEN y, long n, long m, GEN P} returns \kbd{RgXQ\_powers(y,m-1,P)}, as a matrix of dimension $n \geq \deg P$. \fun{GEN}{RgXQ_norm}{GEN x, GEN T} returns the norm of \kbd{Mod(x, T)}. \fun{GEN}{RgXQ_charpoly}{GEN x, GEN T, long v} returns the characteristic polynomial of \kbd{Mod(x, T)}, in variable $v$. \fun{GEN}{RgX_RgXQ_eval}{GEN f, GEN x, GEN T} returns $\kbd{f}(\kbd{x})$ modulo $T$. \fun{GEN}{RgX_RgXQV_eval}{GEN f, GEN V, GEN T} as \kbd{RgX\_RgXQ\_eval(f, x, T)}, assuming $V$ was output by \kbd{RgXQ\_powers(x, n, T)} for some $n\geq 1$. \fun{int}{RgXQ_ratlift}{GEN x, GEN T, long amax, long bmax, GEN *P, GEN *Q} Assuming that $\kbd{amax}+\kbd{bmax}<\deg T$, attempts to recognize $x$ as a rational function $a/b$, i.e. to find \typ{POL}s $P$ and $Q$ such that \item $P \equiv Q x$ modulo $T$, \item $\deg P \leq \kbd{amax}$, $\deg Q \leq \kbd{bmax}$, \item $\gcd(T,P) = \gcd(P,Q)$. \noindent If unsuccessful, the routine returns $0$ and leaves $P$, $Q$ unchanged; otherwise it returns $1$ and sets $P$ and $Q$. \fun{GEN}{RgXQ_reverse}{GEN f, GEN T} returns a \typ{POL} $g$ of degree $< n = \text{deg}~T$ such that $T(x)$ divides $(g \circ f)(x) - x$, by solving a linear system. Low-level function underlying \tet{modreverse}: it returns a lift of \kbd[modreverse(f,T)]; faster than the high-level function since it needs not compute the characteristic polynomial of $f$ mod $T$ (often already known in applications). In the trivial case where $n \leq 1$, returns a scalar, not a constant \typ{POL}. \subsec{\kbd{RgXQV, RgXQC}} \fun{GEN}{RgXQC_red}{GEN z, GEN T} \kbd{z} a vector whose coefficients are \kbd{RgX}s (arbitrary \kbd{GEN}s in fact), reduce them to \kbd{RgXQ}s (applying \kbd{grem} coefficientwise) in a \typ{COL}. \fun{GEN}{RgXQV_red}{GEN z, GEN T} \kbd{z} a vector whose coefficients are \kbd{RgX}s (arbitrary \kbd{GEN}s in fact), reduce them to \kbd{RgXQ}s (applying \kbd{grem} coefficientwise) in a \typ{VEC}. \fun{GEN}{RgXQV_RgXQ_mul}{GEN z, GEN x, GEN T} \kbd{z} multiplies the \kbd{RgXQV} \kbd{z} by the scalar (\kbd{RgXQ}) \kbd{x}. \subsec{\kbd{RgXQM}} \fun{GEN}{RgXQM_red}{GEN z, GEN T} \kbd{z} a matrix whose coefficients are \kbd{RgX}s (arbitrary \kbd{GEN}s in fact), reduce them to \kbd{RgXQ}s (applying \kbd{grem} coefficientwise). \fun{GEN}{RgXQM_mul}{GEN x, GEN y, GEN T} \subsec{\kbd{RgXQX}} \fun{GEN}{RgXQX_red}{GEN z, GEN T} \kbd{z} a \typ{POL} whose coefficients are \kbd{RgX}s (arbitrary \kbd{GEN}s in fact), reduce them to \kbd{RgXQ}s (applying \kbd{grem} coefficientwise). \fun{GEN}{RgXQX_mul}{GEN x, GEN y, GEN T} \fun{GEN}{RgXQX_RgXQ_mul}{GEN x, GEN y, GEN T} multiplies the \kbd{RgXQX} \kbd{y} by the scalar (\kbd{RgXQ}) \kbd{x}. \fun{GEN}{RgXQX_sqr}{GEN x, GEN T} \fun{GEN}{RgXQX_powers}{GEN x, long n, GEN T} \fun{GEN}{RgXQX_divrem}{GEN x, GEN y, GEN T, GEN *pr} \fun{GEN}{RgXQX_div}{GEN x, GEN y, GEN T, GEN *r} \fun{GEN}{RgXQX_rem}{GEN x, GEN y, GEN T, GEN *r} \fun{GEN}{RgXQX_translate}{GEN P, GEN c, GEN T} assume the main variable $X$ of $P$ has higher priority than the main variable $Y$ of $T$ and $c$. Return a lift of $P(X+\text{Mod}(c(Y), T(Y)))$. \fun{GEN}{Kronecker_to_mod}{GEN z, GEN T} $z\in R[X]$ represents an element $P(X,Y)$ in $R[X,Y]$ mod $T(Y)$ in Kronecker form, i.e. $z = P(X,X^{2*n-1})$ Let $R$ be some commutative ring, $n = \deg T$ and let $P(X,Y)\in R[X,Y]$ lift a polynomial in $K[Y]$, where $K := R[X]/(T)$ and $\deg_X P < 2n-1$ --- such as would result from multiplying minimal degree lifts of two polynomials in $K[Y]$. Let $z = P(t,t^{2*n-1})$ be a Kronecker form of $P$, this function returns the image of $P(X,t)$ in $K[t]$, with \typ{POLMOD} coefficients. Not stack-clean. Note that $t$ need not be the same variable as $Y$! \chapter{Black box algebraic structures} The generic routines like \kbd{gmul} or \kbd{gadd} allow handling objects belonging to a fixed list of basic types, with some natural polymorphism (you can mix rational numbers and polynomials, etc.), at the expense of efficiency and sometimes of clarity when the recursive structure becomes complicated, e.g. a few levels of \typ{POLMOD}s attached to different polynomials and variable numbers for quotient structures. This is the only possibility in GP. On the other hand, the Level 2 Kernel allows dedicated routines to handle efficiently objects of a very specific type, e.g. polynomials with coefficients in the same finite field. This is more efficient, but imvolves a lot of code duplication since polymorphism is no longer possible. A third and final option, still restricted to library programming, is to define an arbitrary algebraic structure (currently groups, fields, rings, algebras and $\Z_p$-modules) by providing suitable methods, then using generic algorithms. For instance naive Gaussian pivoting applies over all base fields and need only be implemented once. The difference with the first solution is that we no longer depend on the way functions like \kbd{gmul} or \kbd{gadd} will guess what the user is trying to do. We can then implement independently various groups / fields / algebras in a clean way. \section{Black box groups} A black box group is defined by a \tet{bb_group} struct, describing methods available to handle group elements: \bprog struct bb_group { GEN (*mul)(void*, GEN, GEN); GEN (*pow)(void*, GEN, GEN); GEN (*rand)(void*); ulong (*hash)(GEN); int (*equal)(GEN, GEN); int (*equal1)(GEN); GEN (*easylog)(void *E, GEN, GEN, GEN); }; @eprog \kbd{mul(E,x,y)} returns the product $x\*y$. \kbd{pow(E,x,n)} returns $x^n$ ($n$ integer, possibly negative or zero). \kbd{rand(E)} returns a random element in the group. \kbd{hash(x)} returns a hash value for $x$ (\kbd{hash\_GEN} is suitable for this field). \kbd{equal(x,y)} returns one if $x=y$ and zero otherwise. \kbd{equal1(x)} returns one if $x$ is the neutral element in the group, and zero otherwise. \kbd{easylog(E,a,g,o)} (optional) returns either NULL or the discrete logarithm $n$ such that $g^n=a$, the element $g$ being of order $o$. This provides a short-cut in situation where a better algorithm than the generic one is known. A group is thus described by a \kbd{struct bb\_group} as above and auxiliary data typecast to \kbd{void*}. The following functions operate on black box groups: \fun{GEN}{gen_Shanks_log}{GEN x, GEN g, GEN N, void *E, const struct bb_group *grp} \hbadness 10000\break Generic baby-step/giant-step algorithm (Shanks's method). Assuming that $g$ has order $N$, compute an integer $k$ such that $g^k = x$. Return \kbd{cgetg(1, t\_VEC)} if there are no solutions. This requires $O(\sqrt{N})$ group operations and uses an auxiliary table containing $O(\sqrt{N})$ group elements. The above is useful for a one-shot computation. If many discrete logs are desired: \fun{GEN}{gen_Shanks_init}{GEN g, long n, void *E, const struct bb_group *grp} return an auxiliary data structure $T$ required to compute a discrete log in base $g$. Compute and store all powers $g^i$, $i < n$. \fun{GEN}{gen_Shanks}{GEN T, GEN x, ulong N, void *E, const struct bb_group *grp} Let $T$ be computed by \tet{gen_Shanks_init}$(g,n,\dots)$. Return $k < n N$ such that $g^k = x$ or \kbd{NULL} if no such index exist. It uses $O(N)$ operation in the group and fast table lookups (in time $O(\log n)$). The interface is such that the function may be used when the order of the base $g$ is unknown, and hence compute it given only an upper bound $B$ for it: e.g. choose $n,N$ such that $nN \geq B$ and compute the discrete log $l$ of $g^{-1}$ in base $g$, then use \tet{gen_order} with multiple $N = l+1$. \fun{GEN}{gen_Pollard_log}{GEN x, GEN g, GEN N, void *E, const struct bb_group *grp} \hbadness 10000\break Generic Pollard rho algorithm. Assuming that $g$ has order $N$, compute an integer $k$ such that $g^k = x$. This requires $O(\sqrt{N})$ group operations in average and $O(1)$ storage. Will enter an infinite loop if there are no solutions. \fun{GEN}{gen_plog}{GEN x, GEN g, GEN N, void *E, const struct bb_group} Assuming that $g$ has prime order $N$, compute an integer $k$ such that $g^k = x$, using either \kbd{gen\_Shanks\_log} or \kbd{gen\_Pollard\_log}. Return \kbd{cgetg(1, t\_VEC)} if there are no solutions. \fun{GEN}{gen_Shanks_sqrtn}{GEN a, GEN n, GEN N, GEN *zetan, void *E, const struct bb_group *grp} \hbadness 10000 returns one solution of $x^n = a$ in a black box cyclic group of order $N$. Return \kbd{NULL} if no solution exists. If \kbd{zetan} is not \kbd{NULL} it is set to an element of exact order $n$. This function uses \kbd{gen\_plog} for all prime divisors of $\gcd(n,N)$. \fun{GEN}{gen_PH_log}{GEN a, GEN g, GEN N, void *E, const struct bb_group *grp} returns an integer $k$ such that $g^k = x$, assuming that $g$ has order $N$, by Pohlig-Hellman algorithm. Return \kbd{cgetg(1, t\_VEC)} if there are no solutions. This calls \tet{gen_plog} repeatedly for all prime divisors $p$ of $N$. In the following functions the integer parameter \kbd{ord} can be given in all the formats recognized for the argument of arithmetic functions, i.e.~either as a positive \typ{INT} $N$, or as its factorization matrix $\var{faN}$, or (preferred) as a pair $[N,\var{faN}]$. \fun{GEN}{gen_order}{GEN x, GEN ord, void *E, const struct bb_group *grp} computes the order of $x$; \kbd{ord} is a multiple of the order, for instance the group order. \fun{GEN}{gen_factored_order}{GEN x, GEN ord, void *E, const struct bb_group *grp} returns a pair $[o,F]$, where $o$ is the order of $x$ and $F$ is the factorization of $o$; \kbd{ord} is as in \tet{gen_order}. \fun{GEN}{gen_gener}{GEN ord, void *E, const struct bb_group *grp} returns a random generator of the group, assuming it is of order exactly \kbd{ord}. \fun{GEN}{get_arith_Z}{GEN ord} given \kbd{ord} as above in one of the formats recognized for arithmetic functions, i.e. a positive \typ{INT} $N$, its factorization \var{faN}, or the pair $[N, \var{faN}]$, return $N$. \fun{GEN}{get_arith_ZZM}{GEN ord} given \kbd{ord} as above, return the pair $[N, \var{faN}]$. This may require factoring $N$. \fun{GEN}{gen_select_order}{GEN v, void *E, const struct bb_group *grp} Let $v$ be a vector of possible orders for the group; try to find the true order by checking orders of random points. This will not terminate if there is an ambiguity. \subsec{Black box groups with pairing} These functions handle groups of rank at most $2$ equipped with a family of bilinear pairings which behave like the Weil pairing on elliptic curves over finite field. In the descriptions below, the function \kbd{pairorder(E, P, Q, m, F)} must return the order of the $m$-pairing of $P$ and $Q$, both of order dividing $m$, where $F$ is the factorization matrix of a multiple of $m$. \fun{GEN}{gen_ellgroup}{GEN o, GEN d, GEN *pt_m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)} returns the elementary divisors $[d_1, d_2]$ of the group, assuming it is of order exactly $o>1$, and that $d_2$ divides $d$. If $d_2=1$ then $[o]$ is returned, otherwise \kbd{m=*pt\_m} is set to the order of the pairing required to verify a generating set which is to be used with \kbd{gen\_ellgens}. For the parameter $o$, all formats recognized by arithmetic functions are allowed, preferably a factorization matrix or a pair $[n,\kbd{factor}(n)]$. \fun{GEN}{gen_ellgens}{GEN d1, GEN d2, GEN m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)} the parameters $d_1$, $d_2$, $m$ being as returned by \kbd{gen\_ellgroup}, returns a pair of generators $[P,Q]$ such that $P$ is of order $d_1$ and the $m$-pairing of $P$ and $Q$ is of order $m$. (Note: $Q$ needs not be of order $d_2$). For the parameter $d_1$, all formats recognized by arithmetic functions are allowed, preferably a factorization matrix or a pair $[n,\kbd{factor}(n)]$. \subsec{Functions returning black box groups} \fun{const struct bb_group *}{get_Flxq_star}{void **E, GEN T, ulong p} \fun{const struct bb_group *}{get_FpXQ_star}{void **E, GEN T, GEN p} returns a pointer to the black box group $(\F_p[x]/(T))^*$. \fun{const struct bb_group *}{get_FpE_group}{void **pE, GEN a4, GEN a6, GEN p} returns a pointer to a black box group and set \kbd{*pE} to the necessary data for computing in the group $E(\F_p)$ where $E$ is the elliptic curve $E:y^2=x^3+a_4\*x+a_6$, with $a_4$ and $a_6$ in $\F_p$. \fun{const struct bb_group *}{get_FpXQE_group}{void **pE, GEN a4, GEN a6, GEN T, GEN p} returns a pointer to a black box group and set \kbd{*pE} to the necessary data for computing in the group $E(\F_p[X]/(T))$ where $E$ is the elliptic curve $E:y^2=x^3+a_4\*x+a_6$, with $a_4$ and $a_6$ in $\F_p[X]/(T)$. \fun{const struct bb_group *}{get_FlxqE_group}{void **pE, GEN a4, GEN a6, GEN T, ulong p} idem for small $p$. \fun{const struct bb_group *}{get_F2xqE_group}{void **pE, GEN a2, GEN a6, GEN T} idem for $p=2$. \section{Black box fields} A black box field is defined by a \tet{bb_field} struct, describing methods available to handle field elements: \bprog struct bb_field { GEN (*red)(void *E ,GEN); GEN (*add)(void *E ,GEN, GEN); GEN (*mul)(void *E ,GEN, GEN); GEN (*neg)(void *E ,GEN); GEN (*inv)(void *E ,GEN); int (*equal0)(GEN); GEN (*s)(void *E, long); }; @eprog\noindent In contrast of black box group, elements can have non canonical forms, and only \kbd{red} is required to return a canonical form. For instance a black box implementation of finite fields, all methods except \kbd{red} may return arbitrary representatives in $\Z[X]$ of the correct congruence class modulo $(p,T(X))$. \kbd{red(E,x)} returns the canonical form of $x$. \kbd{add(E,x,y)} returns the sum $x+y$. \kbd{mul(E,x,y)} returns the product $x\*y$. \kbd{neg(E,x)} returns $-x$. \kbd{inv(E,x)} returns the inverse of $x$. \kbd{equal0(x)} $x$ being in canonical form, returns one if $x=0$ and zero otherwise. \kbd{s(n)} $n$ being a small signed integer, returns $n$ times the unit element. \noindent A field is thus described by a \kbd{struct bb\_field} as above and auxiliary data typecast to \kbd{void*}. The following functions operate on black box fields: \fun{GEN}{gen_Gauss}{GEN a, GEN b, void *E, const struct bb_field *ff} \fun{GEN}{gen_Gauss_pivot}{GEN x, long *rr, void *E, const struct bb_field *ff} \fun{GEN}{gen_det}{GEN a, void *E, const struct bb_field *ff} \fun{GEN}{gen_ker}{GEN x, long deplin, void *E, const struct bb_field *ff} \fun{GEN}{gen_matcolinvimage}{GEN a, GEN b, void *E, const struct bb_field *ff} \fun{GEN}{gen_matcolmul}{GEN a, GEN b, void *E, const struct bb_field *ff} \fun{GEN}{gen_matid}{long n, void *E, const struct bb_field *ff} \fun{GEN}{gen_matinvimage}{GEN a, GEN b, void *E, const struct bb_field *ff} \fun{GEN}{gen_matmul}{GEN a, GEN b, void *E, const struct bb_field *ff} \subsec{Functions returning black box fields} \fun{const struct bb_field *}{get_Fp_field}{void **pE, GEN p} \fun{const struct bb_field *}{get_Fq_field}{void **pE, GEN T, GEN p} \fun{const struct bb_field *}{get_Flxq_field}{void **pE, GEN T, ulong p} \fun{const struct bb_field *}{get_F2xq_field}{void **pE, GEN T} \fun{const struct bb_field *}{get_nf_field}{void **pE, GEN nf} \section{Black box algebra} A black box algebra is defined by a \tet{bb_algebra} struct, describing methods available to handle algebra elements: \bprog struct bb_algebra { GEN (*red)(void *E, GEN x); GEN (*add)(void *E, GEN x, GEN y); GEN (*sub)(void *E, GEN x, GEN y); GEN (*mul)(void *E, GEN x, GEN y); GEN (*sqr)(void *E, GEN x); GEN (*one)(void *E); GEN (*zero)(void *E); }; @eprog\noindent In contrast with black box groups, elements can have non canonical forms, but only \kbd{add} is allowed to return a non canonical form. \kbd{red(E,x)} returns the canonical form of $x$. \kbd{add(E,x,y)} returns the sum $x+y$. \kbd{sub(E,x,y)} returns the difference $x-y$. \kbd{mul(E,x,y)} returns the product $x\*y$. \kbd{sqr(E,x)} returns the square $x^2$. \kbd{one(E)} returns the unit element. \kbd{zero(E)} returns the zero element. \noindent An algebra is thus described by a \kbd{struct bb\_algebra} as above and auxiliary data typecast to \kbd{void*}. The following functions operate on black box algebra: \fun{GEN}{gen_bkeval}{GEN P, long d, GEN x, int use_sqr, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)} $x$ being an element of the black box algebra, and $P$ some black box polynomial of degree $d$ over the base field, returns $P(x)$. The function \kbd{cmul(E,P,a,y)} must return the coefficient of degree $a$ of $P$ multiplied by $y$. \kbd{cmul} is allowed to return a non canonical form; it is also allowed to return \kbd{NULL} instead of an exact $0$. The flag \kbd{use\_sqr} has the same meaning as for \kbd{gen\_powers}. This implements an algorithm of Brent and Kung (1978). \fun{GEN}{gen_bkeval_powers}{GEN P, long d, GEN V, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)} as \tet{gen_RgX_bkeval} assuming $V$ was output by \tet{gen_powers}$(x, l, E, \var{ff})$ for some $l\geq 1$. For optimal performance, $l$ should be computed by \tet{brent_kung_optpow}. \fun{long}{brent_kung_optpow}{long d, long n, long m} returns the optimal parameter $l$ for the evaluation of $n/m$ polynomials of degree $d$. Fractional values can be used if the evaluations are done with different accuracies, and thus have different weights. \subsec{Functions returning black box algebras} \fun{const struct bb_algebra *}{get_FpX_algebra}{void **E, GEN p, long v} return the algebra of polynomials over $\F_p$ in variable $v$. \fun{const struct bb_algebra *}{get_FpXQ_algebra}{void **E, GEN T, GEN p} return the algebra $\F_p[X]/(T(X))$. \fun{const struct bb_algebra *}{get_FpXQX_algebra}{void **E, GEN T, GEN p, long v} return the algebra of polynomials over $\F_p[X]/(T(X))$ in variable $v$. \fun{const struct bb_algebra *}{get_FlxqXQ_algebra}{void **E, GEN S, GEN T, ulong p} return the algebra $\F_p[X,Y]/(S(X,Y),T(X))$ (for \kbd{ulong} $p$). \fun{const struct bb_algebra *}{get_FpXQXQ_algebra}{void **E, GEN S, GEN T, GEN p} return the algebra $\F_p[X,Y]/(S(X,Y),T(X))$. \fun{const struct bb_algebra *}{get_Rg_algebra}{void} return the generic algebra. \section{Black box ring} A black box ring is defined by a \tet{bb_ring} struct, describing methods available to handle ring elements: \bprog struct bb_ring { GEN (*add)(void *E, GEN x, GEN y); GEN (*mul)(void *E, GEN x, GEN y); GEN (*sqr)(void *E, GEN x); }; @eprog \kbd{add(E,x,y)} returns the sum $x+y$. \kbd{mul(E,x,y)} returns the product $x\*y$. \kbd{sqr(E,x)} returns the square $x^2$. \fun{GEN}{gen_fromdigits}{GEN v, GEN B, void *E, struct bb_ring *r} where $B$ is a ring element and $v=[c_0,\ldots,c_{n-1}]$ a vector of ring elements, return $\sum_{i=0}^n c_i\*B^i$ using binary splitting. \fun{GEN}{gen_digits}{GEN x, GEN B, long n, void *E, struct bb_ring *r, GEN (*div)(void *E, GEN x, GEN y, GEN *r)} (Require the ring to be Euclidean) \kbd{div(E,x,y,\&r)} performs the Euclidean division of $x$ by $y$ in the ring $R$, returning the quotient $q$ and setting $r$ to the residue so that $x=q\*y+r$ holds. The residue must belong to a fixed set of representatives of $R/(y)$. The argument $x$ being a ring element, \kbd{gen\_digits} returns a vector of ring elements $[c_0,\ldots,c_{n-1}]$ such that $x = \sum_{i=0}^n c_i\*B^i$. Furthermore for all $i\ne n-1$, the elements $c_i$ belonging to the fixed set of representatives of $R/(B)$. \section{Black box free $\Z_p$-modules} (Very experimental) \fun{GEN}{gen_ZpX_Dixon}{GEN F, GEN V, GEN q, GEN p, long N, void *E, GEN lin(void *E, GEN F, GEN z, GEN q), GEN invl(void *E, GEN z)} Let $F$ be a \kbd{ZpXT} representing the coefficients of some abstract linear mapping $f$ over $\Z_p[X]$ seen as a free $\Z_p$-module, let $V$ be an element of $\Z_p[X]$ and let $q = p^N$. Return $y\in\Z_p[X]$ such that $f(y)=V\pmod{p^N}$ assuming the following holds for $n\leq N$: \item $\kbd{lin}(E, \kbd{FpX\_red}(F, p^n), z, p^n) \equiv f(z) \pmod{p^n}$ \item $f(\kbd{invl}(E, z)) \equiv z \pmod{p}$ The rationale for the argument $F$ being that it allows \kbd{gen\_ZpX\_Dixon} to reduce it to the required $p$-adic precision. \fun{GEN}{gen_ZpX_Newton}{GEN x, GEN p, long n, void *E, GEN eval(void *E, GEN a, GEN q), GEN invd(void *E, GEN b, GEN v, GEN q, long N)} Let $x$ be an element of $\Z_p[X]$ seen as a free $\Z_p$-module, and $f$ some differentiable function over $\Z_p[X]$ such that $f(x) \equiv 0 \pmod{p}$. Return $y$ such that $f(y) \equiv 0\pmod{p^n}$, assuming the following holds for all $a, b\in \Z_p[X]$ and $M\leq N$: \item $v = \kbd{eval}(E,a,p^N)$ is a vector of elements of $\Z_p[X]$, \item $w = \kbd{invd}(E,b,v,p^M,M)$ is an element in $\Z_p[X]$, \item $v[1] \equiv f(a) \pmod{p^N\Z_p[X]}$, \item $df_a(w) \equiv b \pmod{p^M\Z_p[X]}$ \noindent and $df_a$ denotes the differential of $f$ at $a$. Motivation: \kbd{eval} allows to evaluate $f$ and \kbd{invd} allows to invert its differential. Frequently, data useful to compute the differential appear as a subproduct of computing the function. The vector $v$ allows \kbd{eval} to provide these to \kbd{invd}. The implementation of \kbd{invd} will generally involves the use of the function \kbd{gen\_ZpX\_Dixon}. \newpage \chapter{Operations on general PARI objects} \section{Assignment} It is in general easier to use a direct conversion, e.g.~\kbd{y = stoi(s)}, than to allocate a target of correct type and sufficient size, then assign to it: \bprog GEN y = cgeti(3); affsi(s, y); @eprog\noindent These functions can still be moderately useful in complicated garbage collecting scenarios but you will be better off not using them. \fun{void}{gaffsg}{long s, GEN x} assigns the \kbd{long}~\kbd{s} into the object~\kbd{x}. \fun{void}{gaffect}{GEN x, GEN y} assigns the object \kbd{x} into the object~\kbd{y}. Both \kbd{x} and \kbd{y} must be scalar types. Type conversions (e.g.~from \typ{INT} to \typ{REAL} or \typ{INTMOD}) occur if legitimate. \fun{int}{is_universal_constant}{GEN x} returns $1$ if $x$ is a global PARI constant you should never assign to (such as \kbd{gen\_1}), and $0$ otherwise. \section{Conversions} \subsec{Scalars} \fun{double}{rtodbl}{GEN x} applied to a \typ{REAL}~\kbd{x}, converts \kbd{x} into a \kbd{double} if possible. \fun{GEN}{dbltor}{double x} converts the \kbd{double} \kbd{x} into a \typ{REAL}. \fun{long}{dblexpo}{double x} returns \kbd{expo(dbltor(x))}, but faster and without cluttering the stack. \fun{ulong}{dblmantissa}{double x} returns the most significant word in the mantissa of \kbd{dbltor(x)}. \fun{double}{gtodouble}{GEN x} if \kbd{x} is a real number (not necessarily a~\typ{REAL}), converts \kbd{x} into a \kbd{double} if possible. \fun{long}{gtos}{GEN x} converts the \typ{INT} \kbd{x} to a small integer if possible, otherwise raise an exception. This function is similar to \tet{itos}, slightly slower since it checks the type of \kbd{x}. \fun{double}{dbllog2r}{GEN x} assuming that \kbd{x} is a non-zero \typ{REAL}, returns an approximation to \kbd{log2(|x|)}. \fun{double}{dblmodulus}{GEN x} return an approximation to \kbd{|x|}. \fun{long}{gtolong}{GEN x} if \kbd{x} is an integer (not necessarily a~\typ{INT}), converts \kbd{x} into a \kbd{long} if possible. \fun{GEN}{fractor}{GEN x, long l} applied to a \typ{FRAC}~\kbd{x}, converts \kbd{x} into a \typ{REAL} of length \kbd{prec}. \fun{GEN}{quadtofp}{GEN x, long l} applied to a \typ{QUAD}~\kbd{x}, converts \kbd{x} into a \typ{REAL} or \typ{COMPLEX} depending on the sign of the discriminant of~\kbd{x}, to precision \hbox{\kbd{l} \B-bit} words. % forbid line brk at hyphen here [GN] \fun{GEN}{upper_to_cx}{GEN x, long *prec} valid for a \typ{COMPLEX} or \typ{QUAD} belonging to the upper half-plane. If a \typ{QUAD}, convert it to \typ{COMPLEX} using accuracy \kbd{*prec}. If $x$ is inexact, sets \kbd{*prec} to the precision of $x$. \fun{GEN}{cxtofp}{GEN x, long prec} converts the \typ{COMPLEX}~\kbd{x} to a a complex whose real and imaginary parts are \typ{REAL} of length \kbd{prec} (special case of~\kbd{gtofp}. \fun{GEN}{cxcompotor}{GEN x, long prec} converts the \typ{INT}, \typ{REAL} or \typ{FRAC} $x$ to a \typ{REAL} of length \kbd{prec}. These are all the real types which may occur as components of a \typ{COMPLEX}; special case of~\kbd{gtofp} (introduced so that the latter is not recursive and can thus be inlined). \fun{GEN}{cxtoreal}{GEN x} converts the complex (\typ{INT}, \typ{REAL}, \typ{FRAC} or \typ{COMPLEX}) $x$ to a real number if its imaginary part is 0. Shallow function. converts the \typ{COMPLEX}~\kbd{x} to a a complex whose real and imaginary parts are \typ{REAL} of length \kbd{prec} (special case of~\kbd{gtofp}. \fun{GEN}{gtofp}{GEN x, long prec} converts the complex number~\kbd{x} (\typ{INT}, \typ{REAL}, \typ{FRAC}, \typ{QUAD} or \typ{COMPLEX}) to either a \typ{REAL} or \typ{COMPLEX} whose components are \typ{REAL} of precision \kbd{prec}; not necessarily of \emph{length} \kbd{prec}: a real $0$ may be given as \kbd{real\_0(...)}). If the result is a \typ{COMPLEX} extra care is taken so that its modulus really has accuracy \kbd{prec}: there is a problem if the real part of the input is an exact $0$; indeed, converting it to \kbd{real\_0(prec)} would be wrong if the imaginary part is tiny, since the modulus would then become equal to $0$, as in $1.E-100 + 0.E-28 = 0.E-28$. \fun{GEN}{gtomp}{GEN z, long prec} converts the real number~\kbd{x} (\typ{INT}, \typ{REAL}, \typ{FRAC}, real \typ{QUAD}) to either a \typ{INT} or a \typ{REAL} of precision \kbd{prec}. Not memory clean if $x$ is a \typ{INT}: we return $x$ itself and not a copy. \fun{GEN}{gcvtop}{GEN x, GEN p, long l} converts $x$ into a \typ{PADIC} of precision~$l$. Works componentwise on recursive objects, e.g.~\typ{POL} or \typ{VEC}. Converting $0$ yields $O(p^l)$; converting a non-zero number yield a result well defined modulo $p^{v_p(x) + l}$. \fun{GEN}{cvtop}{GEN x, GEN p, long l} as \kbd{gcvtop}, assuming that $x$ is a scalar. \fun{GEN}{cvtop2}{GEN x, GEN y} $y$ being a $p$-adic, converts the scalar $x$ to a $p$-adic of the same accuracy. Shallow function. \fun{GEN}{cvstop2}{long s, GEN y} $y$ being a $p$-adic, converts the scalar $s$ to a $p$-adic of the same accuracy. Shallow function. \fun{GEN}{gprec}{GEN x, long l} returns a copy of $x$ whose precision is changed to $l$ digits. The precision change is done recursively on all components of $x$. Digits means \emph{decimal}, $p$-adic and $X$-adic digits for \typ{REAL}, \typ{SER}, \typ{PADIC} components, respectively. \fun{GEN}{gprec_w}{GEN x, long l} returns a shallow copy of $x$ whose \typ{REAL} components have their precision changed to $l$ \emph{words}. This is often more useful than \kbd{gprec}. \fun{GEN}{gprec_wtrunc}{GEN x, long l} returns a shallow copy of $x$ whose \typ{REAL} components have their precision \emph{truncated} to $l$ \emph{words}. Contrary to \kbd{gprec\_w}, this function may never increase the precision of~$x$. \fun{GEN}{gprec_wensure}{GEN x, long l} returns a shallow copy of $x$ whose \typ{REAL} components have their precision \emph{increased} to at least $l$ \emph{words}. Contrary to \kbd{gprec\_w}, this function may never decrease the precision of~$x$. \subsec{Modular objects / lifts} \fun{GEN}{gmodulo}{GEN x, GEN y} creates the object \kbd{\key{Mod}(x,y)} on the PARI stack, where \kbd{x} and \kbd{y} are either both \typ{INT}s, and the result is a \typ{INTMOD}, or \kbd{x} is a scalar or a \typ{POL} and \kbd{y} a \typ{POL}, and the result is a \typ{POLMOD}. \fun{GEN}{gmodulgs}{GEN x, long y} same as \key{gmodulo} except \kbd{y} is a \kbd{long}. \fun{GEN}{gmodulsg}{long x, GEN y} same as \key{gmodulo} except \kbd{x} is a \kbd{long}. \fun{GEN}{gmodulss}{long x, long y} same as \key{gmodulo} except both \kbd{x} and \kbd{y} are \kbd{long}s. \fun{GEN}{lift_shallow}{GEN x} shallow version of \tet{lift} \fun{GEN}{liftall_shallow}{GEN x} shallow version of \tet{liftall} \fun{GEN}{liftint_shallow}{GEN x} shallow version of \tet{liftint} \fun{GEN}{liftpol_shallow}{GEN x} shallow version of \tet{liftpol} \fun{GEN}{centerlift0}{GEN x,long v} DEPRECATED, kept for backward compatibility only: use either \tet{lift0}$(x,v)$ or \tet{centerlift}$(x)$. \subsec{Between polynomials and coefficient arrays} \fun{GEN}{gtopoly}{GEN x, long v} converts or truncates the object~\kbd{x} into a \typ{POL} with main variable number~\kbd{v}. A common application would be the conversion of coefficient vectors (coefficients are given by decreasing degree). E.g.~\kbd{[2,3]} goes to \kbd{2*v + 3} \fun{GEN}{gtopolyrev}{GEN x, long v} converts or truncates the object~\kbd{x} into a \typ{POL} with main variable number~\kbd{v}, but vectors are converted in reverse order compared to \kbd{gtopoly} (coefficients are given by increasing degree). E.g.~\kbd{[2,3]} goes to \kbd{3*v + 2}. In other words the vector represents a polynomial in the basis $(1,v,v^2,v^3,\dots)$. \fun{GEN}{normalizepol}{GEN x} applied to an unnormalized \typ{POL}~\kbd{x} (with all coefficients correctly set except that \kbd{leading\_term(x)} might be zero), normalizes \kbd{x} correctly in place and returns~\kbd{x}. For internal use. Normalizing means deleting all leading \emph{exact} zeroes (as per \kbd{isexactzero}), except if the polynomial turns out to be $0$, in which case we try to find a coefficient $c$ which is a non-rational zero, and return the constant polynomial $c$. (We do this so that information about the base ring is not lost.) \fun{GEN}{normalizepol_lg}{GEN x, long l} applies \kbd{normalizepol} to \kbd{x}, pretending that \kbd{lg(x)} is $l$, which must be less than or equal to \kbd{lg(x)}. If equal, the function is equivalent to \kbd{normalizepol(x)}. \fun{GEN}{normalizepol_approx}{GEN x, long lx} as \kbd{normalizepol\_lg}, with the difference that we just delete all leading zeroes (as per \kbd{gequal0}). This rougher normalization is used when we have no other choice, for instance before attempting a Euclidean division by $x$. The following routines do \emph{not} copy coefficients on the stack (they only move pointers around), hence are very fast but not suitable for \kbd{gerepile} calls. Recall that an \kbd{RgV} (resp.~an \kbd{RgX}, resp.~an \kbd{RgM}) is a \typ{VEC} or \typ{COL} (resp.~a \typ{POL}, resp.~a \typ{MAT}) with arbitrary components. Similarly, an \kbd{RgXV} is a \typ{VEC} or \typ{COL} with \kbd{RgX} components, etc. \fun{GEN}{RgV_to_RgX}{GEN x, long v} converts the \kbd{RgV}~\kbd{x} to a (normalized) polynomial in variable~\kbd{v} (as \kbd{gtopolyrev}, without copy). \fun{GEN}{RgV_to_RgX_reverse}{GEN x, long v} converts the \kbd{RgV}~\kbd{x} to a (normalized) polynomial in variable~\kbd{v} (as \kbd{gtopoly}, without copy). \fun{GEN}{RgX_to_RgC}{GEN x, long N} converts the \typ{POL}~\kbd{x} to a \typ{COL}~\kbd{v} with \kbd{N} components. Coefficients of \kbd{x} are listed by increasing degree, so that \kbd{y[i]} is the coefficient of the term of degree $i-1$ in \kbd{x}. \fun{GEN}{Rg_to_RgC}{GEN x, long N} as \tet{RgX_to_RgV}, except that other types than \typ{POL} are allowed for \kbd{x}, which is then considered as a constant polynomial. \fun{GEN}{RgM_to_RgXV}{GEN x, long v} converts the \kbd{RgM}~\kbd{x} to a \typ{VEC} of \kbd{RgX}, by repeated calls to \kbd{RgV\_to\_RgX}. \fun{GEN}{RgV_to_RgM}{GEN v, long N} converts the vector~\kbd{v} to a~\typ{MAT} with \kbd{N}~rows, by repeated calls to \kbd{Rg\_to\_RgV}. \fun{GEN}{RgXV_to_RgM}{GEN v, long N} converts the vector of \kbd{RgX}~\kbd{v} to a~\typ{MAT} with \kbd{N}~rows, by repeated calls to \kbd{RgX\_to\_RgV}. \fun{GEN}{RgM_to_RgXX}{GEN x, long v,long w} converts the \kbd{RgM}~\kbd{x} into a \typ{POL} in variable~\kbd{v}, whose coefficients are \typ{POL}s in variable~\kbd{w}. This is a shortcut for \bprog RgV_to_RgX( RgM_to_RgXV(x, w), v ); @eprog\noindent There are no consistency checks with respect to variable priorities: the above is an invalid object if $\kbd{varncmp(v, w)} \geq 0$. \fun{GEN}{RgXX_to_RgM}{GEN x, long N} converts the \typ{POL}~\kbd{x} with \kbd{RgX} (or constant) coefficients to a matrix with \kbd{N} rows. \fun{long}{RgXY_degreex}{GEN P} return the degree of $P$ with respect to the secondary variable. \fun{GEN}{RgXY_swap}{GEN P, long n, long w} converts the bivariate polynomial $\kbd{P}(u,v)$ (a \typ{POL} with \typ{POL} or scalar coefficients) to $P(\kbd{pol\_x[w]},u)$, assuming \kbd{n} is an upper bound for $\deg_v(\kbd{P})$. \fun{GEN}{RgXY_swapspec}{GEN C, long n, long w, long lP} as \kbd{RgXY\_swap} where the coefficients of $P$ are given by \kbd{gel(C,0),\dots,gel(C,lP-1)}. \fun{GEN}{RgX_to_ser}{GEN x, long l} convert the \typ{POL}~\kbd{x} to a \emph{shallow} \typ{SER} of length~$l\geq 2$. Unless the polynomial is an exact zero, the coefficient of lowest degree $T^d$ of the result is not an exact zero (as per \kbd{isexactzero}). The remainder is $O(T^{d+l-2})$. \fun{GEN}{RgX_to_ser_inexact}{GEN x, long l} convert the \typ{POL}~\kbd{x} to a \emph{shallow} \typ{SER} of length~$l\geq 2$. Unless the polynomial is zero, the coefficient of lowest degree $T^d$ of the result is not zero (as per \kbd{gequal0}). The remainder is $O(T^{d+l-2})$. \fun{GEN}{RgV_to_ser}{GEN x, long v, long l} convert the \typ{VEC}~\kbd{x}, to a \emph{shallow} \typ{SER} of length~$l\geq 2$. \fun{GEN}{rfrac_to_ser}{GEN F, long l} applied to a \typ{RFRAC}~$F$, creates a \typ{SER} of length~$l\geq 2$ congruent to $F$. Not memory-clean but suitable for \kbd{gerepileupto}. \fun{GEN}{rfracrecip_to_ser_absolute}{GEN F, long d} applied to a \typ{RFRAC}~$F$, creates the \typ{SER} $F(1/t) + O(t^d)$. Note that we use absolute and not relative precision here. \fun{GEN}{gtoser}{GEN s, long v, long d}. This function is deprecated, kept for backward compatibility: it follows the semantic of \kbd{Ser(s,v)}, with $d = \kbd{seriesprecision}$ implied and is hard to use as a general conversion function. Use \tet{gtoser_prec} instead. It converts the object~$s$ into a \typ{SER} with main variable number~\kbd{v} and $d > 0$ significant terms, but the argument $d$ is sometimes ignored. More precisely \item if $s$ is a scalar (with respect to variable $v$), we return a constant power series with $d$ significant terms; \item if $s$ is a \typ{POL} in variable $v$, it is truncated to $d$ terms if needed; \item if $s$ is a vector, the coefficients of the vector are understood to be the coefficients of the power series starting from the constant term (as in \tet{Polrev}), and the precision $d$ is \emph{ignored}; \item if $s$ is already a power series in $v$, we return a copy, and the precision $d$ is again \emph{ignored}. \fun{GEN}{gtoser_prec}{GEN s, long v, long d} this function is a variant of \kbd{gtoser} following the semantic of \kbd{Ser(s,v,d)}: the precision $d$ is always taken into account. \fun{GEN}{gtocol}{GEN x} converts the object~\kbd{x} into a \typ{COL} \fun{GEN}{gtomat}{GEN x} converts the object~\kbd{x} into a \typ{MAT}. \fun{GEN}{gtovec}{GEN x} converts the object~\kbd{x} into a \typ{VEC}. \fun{GEN}{gtovecsmall}{GEN x} converts the object~\kbd{x} into a \typ{VECSMALL}. \fun{GEN}{normalize}{GEN x} applied to an unnormalized \typ{SER}~\kbd{x} (i.e.~type \typ{SER} with all coefficients correctly set except that \kbd{x[2]} might be zero), normalizes \kbd{x} correctly in place. Returns~\kbd{x}. For internal use. \fun{GEN}{serchop0}{GEN s} given a \typ{SER} of the form $x^v s(x)$, with $s(0)\neq 0$, return $x^v(s - s(0))$. Shallow function. \fun{GEN}{serchop_i}{GEN x, long n} returns a shallow chopy of \typ{SER} $x$ with all terms of degree strictly less than $n$ removed. Shallow version of \kbd{serchop}. \section{Constructors} \subsec{Clean constructors}\label{se:clean} \fun{GEN}{zeropadic}{GEN p, long n} creates a $0$ \typ{PADIC} equal to $O(\kbd{p}^\kbd{n})$. \fun{GEN}{zeroser}{long v, long n} creates a $0$ \typ{SER} in variable \kbd{v} equal to $O(X^\kbd{n})$. \fun{GEN}{scalarser}{GEN x, long v, long prec} creates a constant \typ{SER} in variable \kbd{v} and precision \kbd{prec}, whose constant coefficient is (a copy of) \kbd{x}, in other words $\kbd{x} + O(\kbd{v}^\kbd{prec})$. Assumes that $\kbd{prec}\geq 0$. \fun{GEN}{pol_0}{long v} Returns the constant polynomial $0$ in variable $v$. \fun{GEN}{pol_1}{long v} Returns the constant polynomial $1$ in variable $v$. \fun{GEN}{pol_x}{long v} Returns the monomial of degree $1$ in variable $v$. \fun{GEN}{pol_xn}{long n, long v} Returns the monomial of degree $n$ in variable $v$; assume that $n \geq 0$. \fun{GEN}{pol_xnall}{long n, long v} Returns the Laurent monomial of degree $n$ in variable $v$; $n < 0$ is allowed. \fun{GEN}{pol_x_powers}{long N, long v} returns the powers of \kbd{pol\_x(v)}, of degree $0$ to $N-1$, in a vector with $N$ components. \fun{GEN}{scalarpol}{GEN x, long v} creates a constant \typ{POL} in variable \kbd{v}, whose constant coefficient is (a copy of) \kbd{x}. \fun{GEN}{deg1pol}{GEN a, GEN b,long v} creates the degree 1 \typ{POL} $a \kbd{pol\_x}(v) + b$ \fun{GEN}{zeropol}{long v} is identical \kbd{pol\_0}. \fun{GEN}{zerocol}{long n} creates a \typ{COL} with \kbd{n} components set to \kbd{gen\_0}. \fun{GEN}{zerovec}{long n} creates a \typ{VEC} with \kbd{n} components set to \kbd{gen\_0}. \fun{GEN}{zerovec_block}{long n} as \kbd{zerovec} but return a clone. \fun{GEN}{col_ei}{long n, long i} creates a \typ{COL} with \kbd{n} components set to \kbd{gen\_0}, but for the \kbd{i}-th one which is set to \kbd{gen\_1} (\kbd{i}-th vector in the canonical basis). \fun{GEN}{vec_ei}{long n, long i} creates a \typ{VEC} with \kbd{n} components set to \kbd{gen\_0}, but for the \kbd{i}-th one which is set to \kbd{gen\_1} (\kbd{i}-th vector in the canonical basis). \fun{GEN}{trivial_fact}{void} returns the trivial (empty) factorization \kbd{Mat([]\til,[]\til)} \fun{GEN}{prime_fact}{GEN x} returns the factorization \kbd{Mat([x]\til, [1]\til)} \fun{GEN}{Rg_col_ei}{GEN x, long n, long i} creates a \typ{COL} with \kbd{n} components set to \kbd{gen\_0}, but for the \kbd{i}-th one which is set to \kbd{x}. \fun{GEN}{vecsmall_ei}{long n, long i} creates a \typ{VECSMALL} with \kbd{n} components set to \kbd{0}, but for the \kbd{i}-th one which is set to \kbd{1} (\kbd{i}-th vector in the canonical basis). \fun{GEN}{scalarcol}{GEN x, long n} creates a \typ{COL} with \kbd{n} components set to \kbd{gen\_0}, but the first one which is set to a copy of \kbd{x}. (The name comes from \kbd{RgV\_isscalar}.) \smallskip \fun{GEN}{mkintmodu}{ulong x, ulong y} creates the \typ{INTMOD} \kbd{Mod(x, y)}. The inputs must satisfy $x < y$. \fun{GEN}{zeromat}{long m, long n} creates a \typ{MAT} with \kbd{m} x \kbd{n} components set to \kbd{gen\_0}. Note that the result allocates a \emph{single} column, so modifying an entry in one column modifies it in all columns. To fully allocate a matrix initialized with zero entries, use \kbd{zeromatcopy}. \fun{GEN}{zeromatcopy}{long m, long n} creates a \typ{MAT} with \kbd{m} x \kbd{n} components set to \kbd{gen\_0}. \fun{GEN}{matid}{long n} identity matrix in dimension \kbd{n} (with components \kbd{gen\_1} and\kbd{gen\_0}). \fun{GEN}{scalarmat}{GEN x, long n} scalar matrix, \kbd{x} times the identity. \fun{GEN}{scalarmat_s}{long x, long n} scalar matrix, \kbd{stoi(x)} times the identity. \fun{GEN}{vecrange}{GEN a, GEN b} returns the \typ{VEC} $[a..b]$. \fun{GEN}{vecrangess}{long a, long b} returns the \typ{VEC} $[a..b]$. \smallskip See also next section for analogs of the following functions: \fun{GEN}{mkfracss}{long x, long y} creates the \typ{FRAC} $x/y$. Assumes that $y > 1$ and $(x,y) = 1$. \fun{GEN}{sstoQ}{long x, long y} returns the \typ{INT} or \typ{FRAC} $x/y$; no assumptions. \fun{void}{Qtoss}{GEN q, long *n, long *d} given a \typ{INT} or \typ{FRAC} $q$, set $n$ and $d$ such that $q = n/d$ with $d \geq 1$ and $(n,d)$ = 1. Overflow error if numerator or denominator do not fit into a long integer. \fun{GEN}{mkfraccopy}{GEN x, GEN y} creates the \typ{FRAC} $x/y$. Assumes that $y > 1$ and $(x,y) = 1$. \fun{GEN}{mkrfraccopy}{GEN x, GEN y} creates the \typ{RFRAC} $x/y$. Assumes that $y$ is a \typ{POL}, $x$ a compatible type whose variable has lower or same priority, with $(x,y) = 1$. \fun{GEN}{mkcolcopy}{GEN x} creates a 1-dimensional \typ{COL} containing \kbd{x}. \fun{GEN}{mkmatcopy}{GEN x} creates a 1-by-1 \typ{MAT} wrapping the \typ{COL} \kbd{x}. \fun{GEN}{mkveccopy}{GEN x} creates a 1-dimensional \typ{VEC} containing \kbd{x}. \fun{GEN}{mkvec2copy}{GEN x, GEN y} creates a 2-dimensional \typ{VEC} equal to \kbd{[x,y]}. \fun{GEN}{mkcols}{long x} creates a 1-dimensional \typ{COL} containing \kbd{stoi(x)}. \fun{GEN}{mkcol2s}{long x, long y} creates a 2-dimensional \typ{COL} containing \kbd{[stoi(x), stoi(y)]~}. \fun{GEN}{mkcol3s}{long x, long y, long z} creates a 3-dimensional \typ{COL} containing \kbd{[stoi(x), stoi(y), stoi(z)]~}. \fun{GEN}{mkcol4s}{long x, long y, long z, long t} creates a 4-dimensional \typ{COL} containing \kbd{[stoi(x), stoi(y), stoi(z), stoi(t)]~}. \fun{GEN}{mkvecs}{long x} creates a 1-dimensional \typ{VEC} containing \kbd{stoi(x)}. \fun{GEN}{mkvec2s}{long x, long y} creates a 2-dimensional \typ{VEC} containing \kbd{[stoi(x), stoi(y)]}. \fun{GEN}{mkmat22s}{long a, long b, long c, long d} creates the $2$ by $2$ \typ{MAT} with successive rows \kbd{[stoi(a), stoi(b)]} and \kbd{[stoi(c), stoi(d)]}. \fun{GEN}{mkvec3s}{long x, long y, long z} creates a 3-dimensional \typ{VEC} containing \kbd{[stoi(x), stoi(y), stoi(z)]}. \fun{GEN}{mkvec4s}{long x, long y, long z, long t} creates a 4-dimensional \typ{VEC} containing \kbd{[stoi(x), stoi(y), stoi(z), stoi(t)]}. \fun{GEN}{mkvecsmall}{long x} creates a 1-dimensional \typ{VECSMALL} containing \kbd{x}. \fun{GEN}{mkvecsmall2}{long x, long y} creates a 2-dimensional \typ{VECSMALL} containing \kbd{[x, y]}. \fun{GEN}{mkvecsmall3}{long x, long y, long z} creates a 3-dimensional \typ{VECSMALL} containing \kbd{[x, y, z]}. \fun{GEN}{mkvecsmall4}{long x, long y, long z, long t} creates a 4-dimensional \typ{VECSMALL} containing \kbd{[x, y, z, t]}. \fun{GEN}{mkvecsmalln}{long n, ...} returns the \typ{VECSMALL} whose $n$ coefficients (\kbd{long}) follow. \emph{Warning:} since this is a variadic function, C type promotion is not performed on the arguments by the compiler, thus you have to make sure that all the arguments are of type \kbd{long}, in particular integer constants need to be written with the \kbd{L} suffix: \kbd{mkvecsmalln(2, 1L, 2L)} is correct, but \kbd{mkvecsmalln(2, 1, 2)} is not. \subsec{Unclean constructors}\label{se:unclean} Contrary to the policy of general PARI functions, the functions in this subsection do \emph{not} copy their arguments, nor do they produce an object a priori suitable for \tet{gerepileupto}. In particular, they are faster than their clean equivalent (which may not exist). \emph{If} you restrict their arguments to universal objects (e.g \kbd{gen\_0}), then the above warning does not apply. \fun{GEN}{mkcomplex}{GEN x, GEN y} creates the \typ{COMPLEX} $x + iy$. \fun{GEN}{mulcxI}{GEN x} creates the \typ{COMPLEX} $ix$. The result in general contains data pointing back to the original $x$. Use \kbd{gcopy} if this is a problem. But in most cases, the result is to be used immediately, before $x$ is subject to garbage collection. \fun{GEN}{mulcxmI}{GEN x}, as \tet{mulcxI}, but returns $-ix$. \fun{GEN}{mulcxpowIs}{GEN x, long k}, as \tet{mulcxI}, but returns $x \cdot i^k$. \fun{GEN}{mkquad}{GEN n, GEN x, GEN y} creates the \typ{QUAD} $x + yw$, where $w$ is a root of $n$, which is of the form \kbd{quadpoly(D)}. \fun{GEN}{mkfrac}{GEN x, GEN y} creates the \typ{FRAC} $x/y$. Assumes that $y > 1$ and $(x,y) = 1$. \fun{GEN}{mkrfrac}{GEN x, GEN y} creates the \typ{RFRAC} $x/y$. Assumes that $y$ is a \typ{POL}, $x$ a compatible type whose variable has lower or same priority, with $(x,y) = 1$. \fun{GEN}{mkcol}{GEN x} creates a 1-dimensional \typ{COL} containing \kbd{x}. \fun{GEN}{mkcol2}{GEN x, GEN y} creates a 2-dimensional \typ{COL} equal to \kbd{[x,y]}. \fun{GEN}{mkcol3}{GEN x, GEN y, GEN z} creates a 3-dimensional \typ{COL} equal to \kbd{[x,y,z]}. \fun{GEN}{mkcol4}{GEN x, GEN y, GEN z, GEN t} creates a 4-dimensional \typ{COL} equal to \kbd{[x,y,z,t]}. \fun{GEN}{mkcol5}{GEN a1, GEN a2, GEN a3, GEN a4, GEN a5} creates the 5-dimensional \typ{COL} equal to $[a_1,a_2,a_3,a_4,a_5]$. \fun{GEN}{mkcol6}{GEN x, GEN y, GEN z, GEN t, GEN u, GEN v} creates the $6$-dimensional column vector \kbd{[x,y,z,t,u,v]~}. \fun{GEN}{mkintmod}{GEN x, GEN y} creates the \typ{INTMOD} \kbd{Mod(x, y)}. The inputs must be \typ{INT}s satisfying $0 \leq x < y$. \fun{GEN}{mkpolmod}{GEN x, GEN y} creates the \typ{POLMOD} \kbd{Mod(x, y)}. The input must satisfy $\deg x < \deg y$ with respect to the main variable of the \typ{POL} $y$. $x$ may be a scalar. \fun{GEN}{mkmat}{GEN x} creates a 1-column \typ{MAT} with column $x$ (a \typ{COL}). \fun{GEN}{mkmat2}{GEN x, GEN y} creates a 2-column \typ{MAT} with columns $x$, $y$ (\typ{COL}s of the same length). \fun{GEN}{mkmat22}{GEN a, GEN b, GEN c, GEN d} creates the $2$ by $2$ \typ{MAT} with successive rows $[a,b]$ and $[c,d]$. \fun{GEN}{mkmat3}{GEN x, GEN y, GEN z} creates a 3-column \typ{MAT} with columns $x$, $y$, $z$ (\typ{COL}s of the same length). \fun{GEN}{mkmat4}{GEN x, GEN y, GEN z, GEN t} creates a 4-column \typ{MAT} with columns $x$, $y$, $z$, $t$ (\typ{COL}s of the same length). \fun{GEN}{mkmat5}{GEN x, GEN y, GEN z, GEN t, GEN u} creates a 5-column \typ{MAT} with columns $x$, $y$, $z$, $t$, $u$ (\typ{COL}s of the same length). \fun{GEN}{mkvec}{GEN x} creates a 1-dimensional \typ{VEC} containing \kbd{x}. \fun{GEN}{mkvec2}{GEN x, GEN y} creates a 2-dimensional \typ{VEC} equal to \kbd{[x,y]}. \fun{GEN}{mkvec3}{GEN x, GEN y, GEN z} creates a 3-dimensional \typ{VEC} equal to \kbd{[x,y,z]}. \fun{GEN}{mkvec4}{GEN x, GEN y, GEN z, GEN t} creates a 4-dimensional \typ{VEC} equal to \kbd{[x,y,z,t]}. \fun{GEN}{mkvec5}{GEN a1, GEN a2, GEN a3, GEN a4, GEN a5} creates the 5-dimensional \typ{VEC} equal to $[a_1,a_2,a_3,a_4,a_5]$. \fun{GEN}{mkqfi}{GEN x, GEN y, GEN z} creates \typ{QFI} equal to \kbd{Qfb(x,y,z)}, assuming that $y^2 - 4xz < 0$. \fun{GEN}{mkerr}{long n} returns a \typ{ERROR} with error code $n$ (\kbd{enum err\_list}). \smallskip It is sometimes useful to return such a container whose entries are not universal objects, but nonetheless suitable for \tet{gerepileupto}. If the entries can be computed at the time the result is returned, the following macros achieve this effect: \fun{GEN}{retmkvec}{GEN x} returns a vector containing the single entry $x$, where the vector root is created just before the function argument $x$ is evaluated. Expands to \bprog { GEN res = cgetg(2, t_VEC); gel(res, 1) = x; /* @Ccom or rather, the \emph{expansion} of $x$ */ return res; } @eprog\noindent For instance, the \kbd{retmkvec(gcopy(x))} returns a clean object, just like \kbd{return mkveccopy(x)} would. \fun{GEN}{retmkvec2}{GEN x, GEN y} returns the $2$-dimensional \typ{VEC} \kbd{[x,y]}. \fun{GEN}{retmkvec3}{GEN x, GEN y, GEN z} returns the $3$-dimensional \typ{VEC} \kbd{[x,y,z]}. \fun{GEN}{retmkvec4}{GEN x, GEN y, GEN z, GEN t} returns the $4$-dimensional \typ{VEC} \kbd{[x,y,z,t]}. \fun{GEN}{retmkvec5}{GEN x, GEN y, GEN z, GEN t, GEN u} returns the $5$-dimensional row vector \kbd{[x,y,z,t,u]}. \fun{GEN}{retconst_vec}{long n, GEN x} returns the $n$-dimensional \typ{VEC} whose entries are constant and all equal to $x$. \fun{GEN}{retmkcol}{GEN x} returns the $1$-dimensional \typ{COL} \kbd{[x]~}. \fun{GEN}{retmkcol2}{GEN x, GEN y} returns the $2$-dimensional \typ{COL} \kbd{[x,y]~}. \fun{GEN}{retmkcol3}{GEN x, GEN y, GEN z} returns the $3$-dimensional \typ{COL} \kbd{[x,y,z]~}. \fun{GEN}{retmkcol4}{GEN x, GEN y, GEN z, GEN t} returns the $4$-dimensional \typ{COL} \kbd{[x,y,z,t]~}. \fun{GEN}{retmkcol5}{GEN x, GEN y, GEN z, GEN t, GEN u} returns the $5$-dimensional column vector \kbd{[x,y,z,t,u]~}. \fun{GEN}{retmkcol6}{GEN x, GEN y, GEN z, GEN t, GEN u, GEN v} returns the $6$-dimensional column vector \kbd{[x,y,z,t,u,v]~}. \fun{GEN}{retconst_col}{long n, GEN x} returns the $n$-dimensional \typ{COL} whose entries are constant and all equal to $x$. \fun{GEN}{retmkmat}{GEN x} returns the $1$-column \typ{MAT} with colum \kbd{x}. \fun{GEN}{retmkmat2}{GEN x, GEN y} returns the $2$-column \typ{MAT} with columns \kbd{x}, \kbd{y}. \fun{GEN}{retmkmat3}{GEN x, GEN y, GEN z} returns the $3$-dimensional \typ{MAT} with columns \kbd{x}, \kbd{y}, \kbd{z}. \fun{GEN}{retmkmat4}{GEN x, GEN y, GEN z, GEN t} returns the $4$-dimensional \typ{MAT} with columns \kbd{x}, \kbd{y}, \kbd{z}, \kbd{t}. \fun{GEN}{retmkmat5}{GEN x, GEN y, GEN z, GEN t, GEN u} returns the $5$-dimensional \typ{MAT} with columns \kbd{x}, \kbd{y}, \kbd{z}, \kbd{t}, \kbd{u}. \fun{GEN}{retmkcomplex}{GEN x, GEN y} returns the \typ{COMPLEX} \kbd{x + I*y}. \fun{GEN}{retmkfrac}{GEN x, GEN y} returns the \typ{FRAC} \kbd{x / y}. Assume $x$ and $y$ are coprime and $y > 1$. \fun{GEN}{retmkrfrac}{GEN x, GEN y} returns the \typ{RFRAC} \kbd{x / y}. Assume $x$ and $y$ are coprime and more generally that the rational function cannot be simplified. \fun{GEN}{retmkintmod}{GEN x, GEN y} returns the \typ{INTMOD} \kbd{Mod(x, y)}. \fun{GEN}{retmkqfi}{GEN a, GEN b, GEN c}. \fun{GEN}{retmkqfr}{GEN a, GEN b, GEN c, GEN d}. \fun{GEN}{retmkquad}{GEN n, GEN a, GEN b}. \fun{GEN}{retmkpolmod}{GEN x, GEN y} returns the \typ{POLMOD} \kbd{Mod(x, y)}. \smallskip \fun{GEN}{mkintn}{long n, ...} returns the non-negative \typ{INT} whose development in base $2^{32}$ is given by the following $n$ 32bit-words (\kbd{unsigned int}). \bprog mkintn(3, a2, a1, a0); @eprog \noindent returns $a_2 2^{64} + a_1 2^{32} + a_0$. \fun{GEN}{mkpoln}{long n, ...} Returns the \typ{POL} whose $n$ coefficients (\kbd{GEN}) follow, in order of decreasing degree. \bprog mkpoln(3, gen_1, gen_2, gen_0); @eprog \noindent returns the polynomial $X^2 + 2X$ (in variable $0$, use \tet{setvarn} if you want other variable numbers). Beware that $n$ is the number of coefficients, hence \emph{one more} than the degree. \fun{GEN}{mkvecn}{long n, ...} returns the \typ{VEC} whose $n$ coefficients (\kbd{GEN}) follow. \fun{GEN}{mkcoln}{long n, ...} returns the \typ{COL} whose $n$ coefficients (\kbd{GEN}) follow. \fun{GEN}{scalarcol_shallow}{GEN x, long n} creates a \typ{COL} with \kbd{n} components set to \kbd{gen\_0}, but the first one which is set to a shallow copy of \kbd{x}. (The name comes from \kbd{RgV\_isscalar}.) \fun{GEN}{scalarmat_shallow}{GEN x, long n} creates an $n\times n$ scalar matrix whose diagonal is set to shallow copies of the scalar \kbd{x}. \fun{GEN}{RgX_sylvestermatrix}{GEN f, GEN g} return the Sylvester matrix attached to the two \typ{POL} in the same variable $f$ and $g$. \fun{GEN}{diagonal_shallow}{GEN x} returns a diagonal matrix whose diagonal is given by the vector $x$. Shallow function. \fun{GEN}{scalarpol_shallow}{GEN a, long v} returns the degree $0$ \typ{POL} $a \kbd{pol\_x}(v)^0$. \fun{GEN}{deg1pol_shallow}{GEN a, GEN b,long v} returns the degree $1$ \typ{POL} $a\kbd{pol\_x}(v) + b$ \fun{GEN}{deg2pol_shallow}{GEN a, GEN b, GEN c, long v} returns the degree $2$ \typ{POL} $a\*x^2+b\*x+c$ where $x=\kbd{pol\_x}(v)$. \fun{GEN}{zeropadic_shallow}{GEN p, long n} returns a (shallow) $0$ \typ{PADIC} equal to $O(\kbd{p}^\kbd{n})$. \subsec{From roots to polynomials} \fun{GEN}{deg1_from_roots}{GEN L, long v} given a vector $L$ of scalars, returns the vector of monic linear polynomials in variable $v$ whose roots are the $L[i]$, i.e. the $x - L[i]$. \fun{GEN}{roots_from_deg1}{GEN L} given a vector $L$ of monic linear polynomials, return their roots, i.e. the $- L[i](0)$. \fun{GEN}{roots_to_pol}{GEN L, long v} given a vector of scalars $L$, returns the monic polynomial in variable $v$ whose roots are the $L[i]$. Leaves some garbage on stack, but suitable for \kbd{gerepileupto}. \fun{GEN}{roots_to_pol_r1}{GEN L, long v, long r1} as \kbd{roots\_to\_pol} assuming the first $r_1$ roots are ``real'', and the following ones are representatives of conjugate pairs of ``complex'' roots. So if $L$ has $r_1 + r_2$ elements, we obtain a polynomial of degree $r_1 + 2r_2$. In most applications, the roots are indeed real and complex, but the implementation assumes only that each ``complex'' root $z$ introduces a quadratic factor $X^2 - \kbd{trace}(z) X + \kbd{norm}(z)$. Leaves some garbage on stack, but suitable for \kbd{gerepileupto}. \section{Integer parts} \fun{GEN}{gfloor}{GEN x} creates the floor of~\kbd{x}, i.e.\ the (true) integral part. \fun{GEN}{gfrac}{GEN x} creates the fractional part of~\kbd{x}, i.e.\ \kbd{x} minus the floor of~\kbd{x}. \fun{GEN}{gceil}{GEN x} creates the ceiling of~\kbd{x}. \fun{GEN}{ground}{GEN x} rounds towards~$+\infty$ the components of \kbd{x} to the nearest integers. \fun{GEN}{grndtoi}{GEN x, long *e} same as \kbd{ground}, but in addition sets \kbd{*e} to the binary exponent of $x - \kbd{ground}(x)$. If this is positive, all significant bits are lost. This kind of situation raises an error message in \key{ground} but not in \key{grndtoi}. \fun{GEN}{gtrunc}{GEN x} truncates~\kbd{x}. This is the false integer part if \kbd{x} is a real number (i.e.~the unique integer closest to \kbd{x} among those between 0 and~\kbd{x}). If \kbd{x} is a \typ{SER}, it is truncated to a \typ{POL}; if \kbd{x} is a \typ{RFRAC}, this takes the polynomial part. \fun{GEN}{gtrunc2n}{GEN x, long n} creates the floor of~$2^n$\kbd{x}, this is only implemented for \typ{INT}, \typ{REAL}, \typ{FRAC} and \typ{COMPLEX} of those. \fun{GEN}{gcvtoi}{GEN x, long *e} analogous to \key{grndtoi} for \typ{REAL} inputs except that rounding is replaced by truncation. Also applies componentwise for vector or matrix inputs; otherwise, sets \kbd{*e} to \kbd{-HIGHEXPOBIT} (infinite real accuracy) and return \kbd{gtrunc(x)}. \section{Valuation and shift} \fun{GEN}{gshift[z]}{GEN x, long n[, GEN z]} yields the result of shifting (the components of) \kbd{x} left by \kbd{n} (if \kbd{n} is non-negative) or right by $-\kbd{n}$ (if \kbd{n} is negative). Applies only to \typ{INT} and vectors/matrices of such. For other types, it is simply multiplication by~$2^{\kbd{n}}$. \fun{GEN}{gmul2n[z]}{GEN x, long n[, GEN z]} yields the product of \kbd{x} and~$2^{\kbd{n}}$. This is different from \kbd{gshift} when \kbd{n} is negative and \kbd{x} is a \typ{INT}: \key{gshift} truncates, while \key{gmul2n} creates a fraction if necessary. \fun{long}{gvaluation}{GEN x, GEN p} returns the greatest exponent~$e$ such that $\kbd{p}^e$ divides~\kbd{x}, when this makes sense. \fun{long}{gval}{GEN x, long v} returns the highest power of the variable number \kbd{v} dividing the \typ{POL}~\kbd{x}. \section{Comparison operators} \subsec{Generic} \fun{long}{gcmp}{GEN x, GEN y} comparison of \kbd{x} with \kbd{y}: returns $1$ ($x > y$), $0$ ($x = y$) or $-1$ ($x < y$). Two \typ{STR} are compared using the standard lexicographic ordering; a \typ{STR} cannot be compared to any non-string type. If neither $x$ nor $y$ is a \typ{STR}, their allowed types are \typ{INT}, \typ{REAL}, \typ{FRAC}, \typ{QUAD} with positive discriminant (use the canonical embedding $w \to \sqrt{D}/2$ or $w \to (1 + \sqrt{D})/2$) or \typ{INFINITY}. Use \tet{cmp_universal} to compare arbitrary \kbd{GEN}s. \fun{long}{lexcmp}{GEN x, GEN y} comparison of \kbd{x} with \kbd{y} for the lexicographic ordering; when comparing objects of different lengths whose components are all equal up to the smallest of their length, consider that the longest is largest. Consider scalars as $1$-component vectors. Return \kbd{gcmp}$(x,y)$ if both arguments are scalars. \fun{int}{gequalX}{GEN x} return 1 (true) if \kbd{x} is a variable (monomial of degree $1$ with \typ{INT} coefficients equal to $1$ and $0$), and $0$ otherwise \fun{long}{gequal}{GEN x, GEN y} returns 1 (true) if \kbd{x} is equal to~\kbd{y}, 0~otherwise. A priori, this makes sense only if \kbd{x} and \kbd{y} have the same type, in which case they are recursively compared componentwise. When the types are different, a \kbd{true} result means that \kbd{x - y} was successfully computed and that \kbd{gequal0} found it equal to $0$. In particular \bprog gequal(cgetg(1, t_VEC), gen_0) @eprog\noindent is true, and the relation is not transitive. E.g.~an empty \typ{COL} and an empty \typ{VEC} are not equal but are both equal to \kbd{gen\_0}. \fun{long}{gidentical}{GEN x, GEN y} returns 1 (true) if \kbd{x} is identical to~\kbd{y}, 0~otherwise. In particular, the types and length of \kbd{x} and \kbd{y} must be equal. This test is much stricter than \tet{gequal}, in particular, \typ{REAL} with different accuracies are tested different. This relation is transitive. \fun{GEN}{gmax}{GEN x, GEN y} returns a copy of the maximum of $x$ and $y$, compared using \kbd{gcmp}. \fun{GEN}{gmin}{GEN x, GEN y} returns a copy of the minimum of $x$ and $y$, compared using \kbd{gcmp}. \fun{GEN}{gmax_shallow}{GEN x, GEN y} shallow version of \kbd{gmax}. \fun{GEN}{gmin_shallow}{GEN x, GEN y} shallow version of \kbd{gmin}. \subsec{Comparison with a small integer} \fun{int}{isexactzero}{GEN x} returns 1 (true) if \kbd{x} is exactly equal to~0 (including \typ{INTMOD}s like \kbd{Mod(0,2)}), and 0~(false) otherwise. This includes recursive objects, for instance vectors, whose components are $0$. \fun{GEN}{gisexactzero}{GEN x} returns \kbd{NULL} unless \kbd{x} is exactly equal to~0 (as per \kbd{isexactzero}). When \kbd{x} is an exact zero return the attached scalar zero as a \typ{INT} (\kbd{gen\_0}), a \typ{INTMOD} (\kbd{Mod(0,$N$)} for the largest possible $N$) or a \typ{FFELT}. \fun{int}{isrationalzero}{GEN x} returns 1 (true) if \kbd{x} is equal to an integer~0 (excluding \typ{INTMOD}s like \kbd{Mod(0,2)}), and 0~(false) otherwise. Contrary to \kbd{isintzero}, this includes recursive objects, for instance vectors, whose components are $0$. \fun{int}{ismpzero}{GEN x} returns 1 (true) if \kbd{x} is a \typ{INT} or a \typ{REAL} equal to~0. \fun{int}{isintzero}{GEN x} returns 1 (true) if \kbd{x} is a \typ{INT} equal to~0. \fun{int}{isint1}{GEN x} returns 1 (true) if \kbd{x} is a \typ{INT} equal to~1. \fun{int}{isintm1}{GEN x} returns 1 (true) if \kbd{x} is a \typ{INT} equal to~$-1$. \fun{int}{equali1}{GEN n} Assuming that \kbd{x} is a \typ{INT}, return 1 (true) if \kbd{x} is equal to $1$, and return 0~(false) otherwise. \fun{int}{equalim1}{GEN n} Assuming that \kbd{x} is a \typ{INT}, return 1 (true) if \kbd{x} is equal to $-1$, and return 0~(false) otherwise. \fun{int}{is_pm1}{GEN x}. Assuming that \kbd{x} is a \emph{non-zero} \typ{INT}, return 1 (true) if \kbd{x} is equal to $-1$ or $1$, and return 0~(false) otherwise. \fun{int}{gequal0}{GEN x} returns 1 (true) if \kbd{x} is equal to~0, 0~(false) otherwise. \fun{int}{gequal1}{GEN x} returns 1 (true) if \kbd{x} is equal to~1, 0~(false) otherwise. \fun{int}{gequalm1}{GEN x} returns 1 (true) if \kbd{x} is equal to~$-1$, 0~(false) otherwise. \fun{long}{gcmpsg}{long s, GEN x} \fun{long}{gcmpgs}{GEN x, long s} comparison of \kbd{x} with the \kbd{long}~\kbd{s}. \fun{GEN}{gmaxsg}{long s, GEN x} \fun{GEN}{gmaxgs}{GEN x, long s} returns the largest of \kbd{x} and the \kbd{long}~\kbd{s} (converted to \kbd{GEN}) \fun{GEN}{gminsg}{long s, GEN x} \fun{GEN}{gmings}{GEN x, long s} returns the smallest of \kbd{x} and the \kbd{long}~\kbd{s} (converted to \kbd{GEN}) \fun{long}{gequalsg}{long s, GEN x} \fun{long}{gequalgs}{GEN x, long s} returns 1 (true) if \kbd{x} is equal to the \kbd{long}~\kbd{s}, 0~otherwise. \section{Miscellaneous Boolean functions} \fun{int}{isrationalzeroscalar}{GEN x} equivalent to, but faster than, \bprog is_scalar_t(typ(x)) && isrationalzero(x) @eprog \fun{int}{isinexact}{GEN x} returns 1 (true) if $x$ has an inexact component, and 0 (false) otherwise. \fun{int}{isinexactreal}{GEN x} return 1 if $x$ has an inexact \typ{REAL} component, and 0 otherwise. \fun{int}{isrealappr}{GEN x, long e} applies (recursively) to complex inputs; returns $1$ if $x$ is approximately real to the bit accuracy $e$, and 0 otherwise. This means that any \typ{COMPLEX} component must have imaginary part $t$ satisfying $\kbd{gexpo}(t) < e$. \fun{int}{isint}{GEN x, GEN *n} returns 0 (false) if \kbd{x} does not round to an integer. Otherwise, returns 1 (true) and set \kbd{n} to the rounded value. \fun{int}{issmall}{GEN x, long *n} returns 0 (false) if \kbd{x} does not round to a small integer (suitable for \kbd{itos}). Otherwise, returns 1 (true) and set \kbd{n} to the rounded value. \fun{long}{iscomplex}{GEN x} returns 1 (true) if \kbd{x} is a complex number (of component types embeddable into the reals) but is not itself real, 0~if \kbd{x} is a real (not necessarily of type \typ{REAL}), or raises an error if \kbd{x} is not embeddable into the complex numbers. \subsec{Obsolete} The following less convenient comparison functions and Boolean operators were used by the historical GP interpreter. They are provided for backward compatibility only and should not be used: \fun{GEN}{gle}{GEN x, GEN y} \fun{GEN}{glt}{GEN x, GEN y} \fun{GEN}{gge}{GEN x, GEN y} \fun{GEN}{ggt}{GEN x, GEN y} \fun{GEN}{geq}{GEN x, GEN y} \fun{GEN}{gne}{GEN x, GEN y} \fun{GEN}{gor}{GEN x, GEN y} \fun{GEN}{gand}{GEN x, GEN y} \fun{GEN}{gnot}{GEN x, GEN y} \section{Sorting} \subsec{Basic sort} \fun{GEN}{sort}{GEN x} sorts the vector \kbd{x} in ascending order using a mergesort algorithm, and \kbd{gcmp} as the underlying comparison routine (returns the sorted vector). This routine copies all components of $x$, use \kbd{gen\_sort\_inplace} for a more memory-efficient function. \fun{GEN}{lexsort}{GEN x}, as \kbd{sort}, using \kbd{lexcmp} instead of \kbd{gcmp} as the underlying comparison routine. \fun{GEN}{vecsort}{GEN x, GEN k}, as \kbd{sort}, but sorts the vector \kbd{x} in ascending \emph{lexicographic} order, according to the entries of the \typ{VECSMALL} \kbd{k}. For example, if $\kbd{k} = [2,1,3]$, sorting will be done with respect to the second component, and when these are equal, with respect to the first, and when these are equal, with respect to the third. \subsec{Indirect sorting} \fun{GEN}{indexsort}{GEN x} as \kbd{sort}, but only returns the permutation which, applied to \kbd{x}, would sort the vector. The result is a \typ{VECSMALL}. \fun{GEN}{indexlexsort}{GEN x}, as \kbd{indexsort}, using \kbd{lexcmp} instead of \kbd{gcmp} as the underlying comparison routine. \fun{GEN}{indexvecsort}{GEN x, GEN k}, as \kbd{vecsort}, but only returns the permutation that would sort the vector \kbd{x}. \fun{long}{vecindexmin}{GEN x} returns the index for a maximal element of $x$ (\typ{VEC}, \typ{COL} or \typ{VECSMALL}). \fun{long}{vecindexmax}{GEN x} returns the index for a maximal element of $x$ (\typ{VEC}, \typ{COL} or \typ{VECSMALL}). \fun{long}{vecindexmax}{GEN x} \subsec{Generic sort and search} The following routines allow to use an arbitrary comparison function \kbd{int (*cmp)(void* data, GEN x, GEN y)}, such that \kbd{cmp(data,x,y)} returns a negative result if $x < y$, a positive one if $x > y$ and 0 if $x = y$. The \kbd{data} argument is there in case your \kbd{cmp} requires additional context. \fun{GEN}{gen_sort}{GEN x, void *data, int (*cmp)(void *,GEN,GEN)}, as \kbd{sort}, with an explicit comparison routine. \fun{GEN}{gen_sort_uniq}{GEN x, void *data, int (*cmp)(void *,GEN,GEN)}, as \kbd{gen\_sort}, removing duplicate entries. \fun{GEN}{gen_indexsort}{GEN x, void *data, int (*cmp)(void*,GEN,GEN)}, as \kbd{indexsort}. \fun{GEN}{gen_indexsort_uniq}{GEN x, void *data, int (*cmp)(void*,GEN,GEN)}, as \kbd{indexsort}, removing duplicate entries. \fun{void}{gen_sort_inplace}{GEN x, void *data, int (*cmp)(void*,GEN,GEN), GEN *perm} sort \kbd{x} in place, without copying its components. If \kbd{perm} is non-\kbd{NULL}, it is set to the permutation that would sort the original \kbd{x}. \fun{GEN}{gen_setminus}{GEN A, GEN B, int (*cmp)(GEN,GEN)} given two sorted vectors $A$ and $B$, returns the vector of elements of $A$ not belonging to $B$. \fun{GEN}{sort_factor}{GEN y, void *data, int (*cmp)(void *,GEN,GEN)}: assuming \kbd{y} is a factorization matrix, sorts its rows in place (no copy is made) according to the comparison function \kbd{cmp} applied to its first column. \fun{GEN}{merge_sort_uniq}{GEN x,GEN y, void *data, int (*cmp)(void *,GEN,GEN)} assuming \kbd{x} and \kbd{y} are sorted vectors, with respect to the \kbd{cmp} comparison function, return a sorted concatenation, with duplicates removed. \fun{GEN}{merge_factor}{GEN fx, GEN fy, void *data, int (*cmp)(void *,GEN,GEN)} let \kbd{fx} and \kbd{fy} be factorization matrices for $X$ and $Y$ sorted with respect to the comparison function \kbd{cmp} (see \tet{sort_factor}), returns the factorization of $X * Y$. \fun{long}{gen_search}{GEN v, GEN y, long flag, void *data, int (*cmp)(void*,GEN,GEN)}.\hfil\break Let \kbd{v} be a vector sorted according to \kbd{cmp(data,a,b)}; look for an index $i$ such that \kbd{v[$i$]} is equal to \kbd{y}. \kbd{flag} has the same meaning as in \kbd{setsearch}: if \kbd{flag} is 0, return $i$ if it exists and 0 otherwise; if \kbd{flag} is non-zero, return $0$ if $i$ exists and the index where \kbd{y} should be inserted otherwise. \fun{long}{tablesearch}{GEN T, GEN x, int (*cmp)(GEN,GEN)} is a faster implementation for the common case \kbd{gen\_search(T,x,0,cmp,cmp\_nodata)}. \subsec{Further useful comparison functions} \fun{int}{cmp_universal}{GEN x, GEN y} a somewhat arbitrary universal comparison function, devoid of sensible mathematical meaning. It is transitive, and returns 0 if and only if \kbd{gidentical(x,y)} is true. Useful to sort and search vectors of arbitrary data. \fun{int}{cmp_nodata}{void *data, GEN x, GEN y}. This function is a hack used to pass an existing basic comparison function lacking the \kbd{data} argument, i.e. with prototype \kbd{int (*cmp)(GEN x, GEN y)}. Instead of \kbd{gen\_sort(x, NULL, cmp)} which may or may not work depending on how your compiler handles typecasts between incompatible function pointers, one should use \kbd{gen\_sort(x, (void*)cmp, cmp\_nodata)}. Here are a few basic comparison functions, to be used with \kbd{cmp\_nodata}: \fun{int}{ZV_cmp}{GEN x, GEN y} compare two \kbd{ZV}, which we assume have the same length (lexicographic order). \fun{int}{cmp_Flx}{GEN x, GEN y} compare two \kbd{Flx}, which we assume have the same main variable (lexicographic order). \fun{int}{cmp_RgX}{GEN x, GEN y} compare two polynomials, which we assume have the same main variable (lexicographic order). The coefficients are compared using \kbd{gcmp}. \fun{int}{cmp_prime_over_p}{GEN x, GEN y} compare two prime ideals, which we assume divide the same prime number. The comparison is ad hoc but orders according to increasing residue degrees. \fun{int}{cmp_prime_ideal}{GEN x, GEN y} compare two prime ideals in the same \var{nf}. Orders by increasing primes, breaking ties using \kbd{cmp\_prime\_over\_p}. \fun{int}{cmp_padic}{GEN x, GEN y} compare two \typ{PADIC} (for the same prime $p$). Finally a more elaborate comparison function: \fun{int}{gen_cmp_RgX}{void *data, GEN x, GEN y} compare two polynomials, ordering first by increasing degree, then according to the coefficient comparison function: \bprog int (*cmp_coeff)(GEN,GEN) = (int(*)(GEN,GEN)) data; @eprog \section{Divisibility, Euclidean division} \fun{GEN}{gdivexact}{GEN x, GEN y} returns the quotient $\kbd{x} / \kbd{y}$, assuming $\kbd{y}$ divides $\kbd{x}$. Not stack clean if $y = 1$ (we return $x$, not a copy). \fun{int}{gdvd}{GEN x, GEN y} returns 1 (true) if \kbd{y} divides~\kbd{x}, 0~otherwise. \fun{GEN}{gdiventres}{GEN x, GEN y} creates a 2-component vertical vector whose components are the true Euclidean quotient and remainder of \kbd{x} and~\kbd{y}. \fun{GEN}{gdivent[z]}{GEN x, GEN y[, GEN z]} yields the true Euclidean quotient of \kbd{x} and the \typ{INT} or \typ{POL}~\kbd{y}, as per the \kbd{\bs} GP operator. \fun{GEN}{gdiventsg}{long s, GEN y[, GEN z]}, as \kbd{gdivent} except that \kbd{x} is a \kbd{long}. \fun{GEN}{gdiventgs[z]}{GEN x, long s[, GEN z]}, as \kbd{gdivent} except that \kbd{y} is a \kbd{long}. \fun{GEN}{gmod[z]}{GEN x, GEN y[, GEN z]} yields the remainder of \kbd{x} modulo the \typ{INT} or \typ{POL}~\kbd{y}, as per the \kbd{\%} GP operator. A \typ{REAL} or \typ{FRAC} \kbd{y} is also allowed, in which case the remainder is the unique real $r$ such that $0 \leq r < |\kbd{y}|$ and $\kbd{y} = q\kbd{x} + r$ for some (in fact unique) integer $q$. \fun{GEN}{gmodsg}{long s, GEN y[, GEN z]} as \kbd{gmod}, except \kbd{x} is a \kbd{long}. \fun{GEN}{gmodgs}{GEN x, long s[, GEN z]} as \kbd{gmod}, except \kbd{y} is a \kbd{long}. \fun{GEN}{gdivmod}{GEN x, GEN y, GEN *r} If \kbd{r} is not equal to \kbd{NULL} or \kbd{ONLY\_REM}, creates the (false) Euclidean quotient of \kbd{x} and~\kbd{y}, and puts (the address of) the remainder into~\kbd{*r}. If \kbd{r} is equal to \kbd{NULL}, do not create the remainder, and if \kbd{r} is equal to \kbd{ONLY\_REM}, create and output only the remainder. The remainder is created after the quotient and can be disposed of individually with a \kbd{cgiv(r)}. \fun{GEN}{poldivrem}{GEN x, GEN y, GEN *r} same as \key{gdivmod} but specifically for \typ{POL}s~\kbd{x} and~\kbd{y}, not necessarily in the same variable. Either of \kbd{x} and \kbd{y} may also be scalars, treated as polynomials of degree $0$. \fun{GEN}{gdeuc}{GEN x, GEN y} creates the Euclidean quotient of the \typ{POL}s~\kbd{x} and~\kbd{y}. Either of \kbd{x} and \kbd{y} may also be scalars, treated as polynomials of degree $0$. \fun{GEN}{grem}{GEN x, GEN y} creates the Euclidean remainder of the \typ{POL}~\kbd{x} divided by the \typ{POL}~\kbd{y}. Either of \kbd{x} and \kbd{y} may also be scalars, treated as polynomials of degree $0$. \fun{GEN}{gdivround}{GEN x, GEN y} if \kbd{x} and \kbd{y} are real (\typ{INT}, \typ{REAL}, \typ{FRAC}), return the rounded Euclidean quotient of $x$ and $y$ as per the \kbd{\bs/} GP operator. Operate componentwise if \kbd{x} is a \typ{COL}, \typ{VEC} or \typ{MAT}. Otherwise as \key{gdivent}. \fun{GEN}{centermod_i}{GEN x, GEN y, GEN y2}, as \kbd{centermodii}, componentwise. \fun{GEN}{centermod}{GEN x, GEN y}, as \kbd{centermod\_i}, except that \kbd{y2} is computed (and left on the stack for efficiency). \fun{GEN}{ginvmod}{GEN x, GEN y} creates the inverse of \kbd{x} modulo \kbd{y} when it exists. \kbd{y} must be of type \typ{INT} (in which case \kbd{x} is of type \typ{INT}) or \typ{POL} (in which case \kbd{x} is either a scalar type or a \typ{POL}). \section{GCD, content and primitive part} \subsec{Generic} \fun{GEN}{resultant}{GEN x, GEN y} creates the resultant of the \typ{POL}s \kbd{x} and~\kbd{y} computed using Sylvester's matrix (inexact inputs), a modular algorithm (inputs in $\Q[X]$) or the subresultant algorithm, as optimized by Lazard and Ducos. Either of \kbd{x} and \kbd{y} may also be scalars (treated as polynomials of degree $0$) \fun{GEN}{ggcd}{GEN x, GEN y} creates the GCD of \kbd{x} and~\kbd{y}. \fun{GEN}{glcm}{GEN x, GEN y} creates the LCM of \kbd{x} and~\kbd{y}. \fun{GEN}{gbezout}{GEN x,GEN y, GEN *u,GEN *v} returns the GCD of \kbd{x} and~\kbd{y}, and puts (the addresses of) objects $u$ and~$v$ such that $u\kbd{x}+v\kbd{y}=\gcd(\kbd{x},\kbd{y})$ into \kbd{*u} and~\kbd{*v}. \fun{GEN}{subresext}{GEN x, GEN y, GEN *U, GEN *V} returns the resultant of \kbd{x} and~\kbd{y}, and puts (the addresses of) polynomials $u$ and~$v$ such that $u\kbd{x}+v\kbd{y}=\text{Res}(\kbd{x},\kbd{y})$ into \kbd{*U} and~\kbd{*V}. \fun{GEN}{content}{GEN x} returns the GCD of all the components of~\kbd{x}. \fun{GEN}{primitive_part}{GEN x, GEN *c} sets \kbd{c} to \kbd{content(x)} and returns the primitive part \kbd{x} / \kbd{c}. A trivial content is set to \kbd{NULL}. \fun{GEN}{primpart}{GEN x} as above but the content is lost. (For efficiency, the content remains on the stack.) \fun{GEN}{denom_i}{GEN x} shallow version of \kbd{denom}. \fun{GEN}{numer_i}{GEN x} shallow version of \kbd{numer}. \subsec{Over the rationals} \fun{long}{Q_pval}{GEN x, GEN p} valuation at the \typ{INT} \kbd{p} of the \typ{INT} or \typ{FRAC}~\kbd{x}. \fun{long}{Q_pvalrem}{GEN x, GEN p, GEN *r} returns the valuation $e$ at the \typ{INT} \kbd{p} of the \typ{INT} or \typ{FRAC}~\kbd{x}. The quotient $\kbd{x}/\kbd{p}^{e}$ is returned in~\kbd{*r}. \fun{GEN}{Q_abs}{GEN x} absolute value of the \typ{INT} or \typ{FRAC}~\kbd{x}. \fun{GEN}{Qdivii}{GEN x, GEN y}, assuming $x$ and $y$ are both of type \typ{INT}, return the quotient $x/y$ as a \typ{INT} or \typ{FRAC}; marginally faster than \kbd{gdiv}. \fun{GEN}{Q_abs_shallow}{GEN x} $x$ being a \typ{INT} or a \typ{FRAC}, returns a shallow copy of $|x|$, in particular returns $x$ itself when $x \geq 0$, and \kbd{gneg($x$)} otherwise. \fun{GEN}{Q_gcd}{GEN x, GEN y} gcd of the \typ{INT} or \typ{FRAC}~\kbd{x} and~\kbd{y}. \smallskip In the following functions, arguments belong to a $M\otimes_\Z\Q$ for some natural $\Z$-module $M$, e.g. multivariate polynomials with integer coefficients (or vectors/matrices recursively built from such objects), and an element of $M$ is said to be \emph{integral}. We are interested in contents, denominators, etc. with respect to this canonical integral structure; in particular, contents belong to $\Q$, denominators to $\Z$. For instance the $\Q$-content of $(1/2)xy$ is $(1/2)$, and its $\Q$-denominator is $2$, whereas \kbd{content} would return $y/2$ and \kbd{denom}~1. \fun{GEN}{Q_content}{GEN x} the $\Q$-content of $x$. \fun{GEN}{Z_content}{GEN x} as \kbd{Q\_content} but assume that all rationals are in fact \typ{INT}s and return \kbd{NULL} when the content is $1$. This function returns as soon as the content is found to equal $1$. \fun{GEN}{Q_content_safe}{GEN x} as \kbd{Q\_content}, returning \kbd{NULL} when the $\Q$-content is not defined (e.g. for a \typ{REAL} or \typ{INTMOD} component). \fun{GEN}{Q_denom}{GEN x} the $\Q$-denominator of $x$. Shallow function. Raises en \kbd{e\_TYPE} error out when the notion is meaningless, e.g. for a \typ{REAL} or \typ{INTMOD} component. \fun{GEN}{Q_denom_safe}{GEN x} the $\Q$-denominator of $x$. Shallow function. Return \kbd{NULL} when the notion is meaningless. \fun{GEN}{Q_primitive_part}{GEN x, GEN *c} sets \kbd{c} to the $\Q$-content of \kbd{x} and returns \kbd{x / c}, which is integral. \fun{GEN}{Q_primpart}{GEN x} as above but the content is lost. (For efficiency, the content remains on the stack.) \fun{GEN}{vec_Q_primpart}{GEN x} as above component-wise. \fun{GEN}{Q_remove_denom}{GEN x, GEN *ptd} sets \kbd{d} to the $\Q$-denominator of \kbd{x} and returns \kbd{x * d}, which is integral. Shallow function. \fun{GEN}{Q_div_to_int}{GEN x, GEN c} returns \kbd{x / c}, assuming $c$ is a rational number (\typ{INT} or \typ{FRAC}) and the result is integral. \fun{GEN}{Q_mul_to_int}{GEN x, GEN c} returns \kbd{x * c}, assuming $c$ is a rational number (\typ{INT} or \typ{FRAC}) and the result is integral. \fun{GEN}{Q_muli_to_int}{GEN x, GEN d} returns \kbd{x * c}, assuming $c$ is a \typ{INT} and the result is integral. \fun{GEN}{mul_content}{GEN cx, GEN cy} \kbd{cx} and \kbd{cy} are as set by \kbd{primitive\_part}: either a \kbd{GEN} or \kbd{NULL} representing the trivial content $1$. Returns their product (either a \kbd{GEN} or \kbd{NULL}). \fun{GEN}{inv_content}{GEN c} $c$ is as set by \kbd{primitive\_part}: either a \kbd{GEN} or \kbd{NULL} representing the trivial content $1$. Returns its inverse (either a \kbd{GEN} or \kbd{NULL}). \fun{GEN}{mul_denom}{GEN dx, GEN dy} \kbd{dx} and \kbd{dy} are as set by \kbd{Q\_remove\_denom}: either a \typ{INT} or \kbd{NULL} representing the trivial denominator $1$. Returns their product (either a \typ{INT} or \kbd{NULL}). \section{Generic arithmetic operators} \subsec{Unary operators} \fun{GEN}{gneg[z]}{GEN x[, GEN z]} yields $-\kbd{x}$. \fun{GEN}{gneg_i}{GEN x} shallow function yielding $-\kbd{x}$. \fun{GEN}{gabs[z]}{GEN x[, GEN z]} yields $|\kbd{x}|$. \fun{GEN}{gsqr}{GEN x} creates the square of~\kbd{x}. \fun{GEN}{ginv}{GEN x} creates the inverse of~\kbd{x}. \subsec{Binary operators} Let ``\op'' be a binary operation among \op=\key{add}: addition (\kbd{x + y}). \op=\key{sub}: subtraction (\kbd{x - y}). \op=\key{mul}: multiplication (\kbd{x * y}). \op=\key{div}: division (\kbd{x / y}). \noindent The names and prototypes of the functions corresponding to \op\ are as follows: \funno{GEN}{g\op}{GEN x, GEN y} \funno{GEN}{g\op gs}{GEN x, long s} \funno{GEN}{g\op sg}{long s, GEN y} \noindent Explicitly \fun{GEN}{gadd}{GEN x, GEN y}, \fun{GEN}{gaddgs}{GEN x, long s}, \fun{GEN}{gaddsg}{long s, GEN x} \fun{GEN}{gmul}{GEN x, GEN y}, \fun{GEN}{gmulgs}{GEN x, long s}, \fun{GEN}{gmulsg}{long s, GEN x} \fun{GEN}{gsub}{GEN x, GEN y}, \fun{GEN}{gsubgs}{GEN x, long s}, \fun{GEN}{gsubsg}{long s, GEN x} \fun{GEN}{gdiv}{GEN x, GEN y}, \fun{GEN}{gdivgs}{GEN x, long s}, \fun{GEN}{gdivsg}{long s, GEN x} \fun{GEN}{gpow}{GEN x, GEN y, long l} creates $\kbd{x}^{\kbd{y}}$. If \kbd{y} is a \typ{INT}, return \kbd{powgi(x,y)} (the precision \kbd{l} is not taken into account). Otherwise, the result is $\exp(\kbd{y}*\log(\kbd{x}))$ where exact arguments are converted to floats of precision~\kbd{l} in case of need; if there is no need, for instance if $x$ is a \typ{REAL}, $l$ is ignored. Indeed, if $x$ is a \typ{REAL}, the accuracy of $\log x$ is determined from the accuracy of $x$, it is no problem to multiply by $y$, even if it is an exact type, and the accuracy of the exponential is determined, exactly as in the case of the initial $\log x$. \fun{GEN}{gpowgs}{GEN x, long n} creates $\kbd{x}^{\kbd{n}}$ using binary powering. To treat the special case $n = 0$, we consider \kbd{gpowgs} as a series of \kbd{gmul}, so we follow the rule of returning result which is as exact as possible given the input. More precisely, we return \item \kbd{gen\_1} if $x$ has type \typ{INT}, \typ{REAL}, \typ{FRAC}, or \typ{PADIC} \item \kbd{Mod(1,N)} if $x$ is a \typ{INTMOD} modulo $N$. \item \kbd{gen\_1} for \typ{COMPLEX}, \typ{QUAD} unless one component is a \typ{INTMOD}, in which case we return \kbd{Mod(1, N)} for a suitable $N$ (the gcd of the moduli that appear). \item \kbd{FF\_1}$(x)$ for a \typ{FFELT}. \item \kbd{qfi\_1}$(x)$ and \kbd{qfr\_1}$(x)$ for \typ{QFI} and \typ{QFR}. \item the identity permutation for \typ{VECSMALL}. \item \kbd{Rg\_get\_1}$(x)$ otherwise Of course, the only practical use of this routine for $n = 0$ is to obtain the multiplicative neutral element in the base ring (or to treat marginal cases that should be special cased anyway if there is the slightest doubt about what the result should be). \fun{GEN}{powgi}{GEN x, GEN y} creates $\kbd{x}^{\kbd{y}}$, where \kbd{y} is a \typ{INT}, using left-shift binary powering. The case where $y = 0$ (as all cases where $y$ is small) is handled by \kbd{gpowgs(x, 0)}. \fun{GEN}{gpowers}{GEN x, long n} returns the vector $[1,x,\dots,x^n]$. \fun{GEN}{grootsof1}{long n, long prec} returns the vector $[1,x,\dots,x^{n-1}]$, where $x$ is the $n$-th root of unity $\exp(2i\pi/n)$. \fun{GEN}{gsqrpowers}{GEN x, long n} returns the vector $[x,x^4,\dots,x^{n^2}]$. In addition we also have the obsolete forms: \fun{void}{gaddz}{GEN x, GEN y, GEN z} \fun{void}{gsubz}{GEN x, GEN y, GEN z} \fun{void}{gmulz}{GEN x, GEN y, GEN z} \fun{void}{gdivz}{GEN x, GEN y, GEN z} \section{Generic operators: product, powering, factorback} To describe the following functions, we use the following private typedefs to simplify the description: \bprog typedef (*F0)(void *); typedef (*F1)(void *, GEN); typedef (*F2)(void *, GEN, GEN); @eprog \noindent They correspond to generic functions with one and two arguments respectively (the \kbd{void*} argument provides some arbitrary evaluation context). \fun{GEN}{gen_product}{GEN v, void *D, F2 op} Given two objects $x,y$, assume that \kbd{op(D, $x$, $y$)} implements an associative binary operator. If $v$ has $k$ entries, return $$v[1]~\var{op}~v[2]~\var{op}~\ldots ~\var{op}~v[k];$$ returns \kbd{gen\_1} if $k = 0$ and a copy of $v[1]$ if $k = 1$. Use divide and conquer strategy. Leave some garbage on stack, but suitable for \kbd{gerepileupto} if \kbd{mul} is. \fun{GEN}{gen_pow}{GEN x, GEN n, void *D, F1 sqr, F2 mul} $n > 0$ a \typ{INT}, returns $x^n$; \kbd{mul(D, $x$, $y$)} implements the multiplication in the underlying monoid; \kbd{sqr} is a (presumably optimized) shortcut for \kbd{mul(D, $x$, $x$)}. \fun{GEN}{gen_powu}{GEN x, ulong n, void *D, F1 sqr, F2 mul} $n > 0$, returns $x^n$. See \tet{gen_pow}. \fun{GEN}{gen_pow_i}{GEN x, GEN n, void *E, F1 sqr, F2 mul} internal variant of \tet{gen_pow}, not memory-clean. \fun{GEN}{gen_powu_i}{GEN x, ulong n, void *E, F1 sqr, F2 mul} internal variant of \tet{gen_powu}, not memory-clean. \fun{GEN}{gen_pow_fold}{GEN x, GEN n, void *D, F1 sqr, F1 msqr} variant of \tet{gen_pow}, where \kbd{mul} is replaced by \kbd{msqr}, with \kbd{msqr(D, $y$)} returning $xy^2$. In particular \kbd{D} must implicitly contain $x$. \fun{GEN}{gen_pow_fold_i}{GEN x, GEN n, void *E, F1 sqr, F1 msqr} internal variant of the function \tet{gen_pow_fold}, not memory-clean. \fun{GEN}{gen_powu_fold}{GEN x, ulong n, void *D, F1 sqr, F1 msqr}, see \tet{gen_pow_fold}. \fun{GEN}{gen_powu_fold_i}{GEN x, ulong n, void *E, F1 sqr, F1 msqr} see \tet{gen_pow_fold_i}. \fun{GEN}{gen_pow_init}{GEN x, GEN n, long k, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)} Return a table \kbd{R} that can be used with \kbd{gen\_pow\_table} to compute the powers of $x$ up to $n$. The table is of size $2^k\*\log_2(n)$. \fun{GEN}{gen_pow_table}{GEN R, GEN n, void *E, GEN (*one)(void*), GEN (*mul)(void*,GEN,GEN)} Return $x^n$, where $R$ is as given by \kbd{gen\_pow\_init(x,m,k,E,sqr,mul)} for some integer $m\geq n$. \fun{GEN}{gen_powers}{GEN x, long n, long usesqr, void *D, F1 sqr, F2 mul, F0 one} returns $[\kbd{x}^0, \dots, \kbd{x}^\kbd{n}]$ as a \typ{VEC}; \kbd{mul(D, $x$, $y$)} implements the multiplication in the underlying monoid; \kbd{sqr} is a (presumably optimized) shortcut for \kbd{mul(D, $x$, $x$)}; \kbd{one} returns the monoid unit. The flag \kbd{usesqr} should be set to $1$ if squaring are faster than multiplication by $x$. \fun{GEN}{gen_factorback}{GEN L, GEN e, F2 mul, F2 pow, void *D} generic form of \tet{factorback}. The pair $[L,e]$ is of the form \item \kbd{[fa, NULL]}, \kbd{fa} a two-column factorization matrix: expand it. \item \kbd{[v, NULL]}, $v$ a vector of objects: return their product. \item or \kbd{[v, e]}, $v$ a vector of objects, $e$ a vector of integral exponents: return the product of the $v[i]^{e[i]}$. \noindent \kbd{mul(D, $x$, $y$)} and \kbd{pow(D, $x$, $n$)} return $xy$ and $x^n$ respectively. \section{Matrix and polynomial norms} This section concerns only standard norms of $\R$ and $\C$ vector spaces, not algebraic norms given by the determinant of some multiplication operator. We have already seen type-specific functions like \tet{ZM_supnorm} or \tet{RgM_fpnorml2} and limit ourselves to generic functions assuming nothing about their \kbd{GEN} argument; these functions allow the following scalar types: \typ{INT}, \typ{FRAC}, \typ{REAL}, \typ{COMPLEX}, \typ{QUAD} and are defined recursively (in terms of norms of their components) for the following ``container'' types: \typ{POL}, \typ{VEC}, \typ{COL} and \typ{MAT}. They raise an error if some other type appears in the argument. \fun{GEN}{gnorml2}{GEN x} The norm of a scalar is the square of its complex modulus, the norm of a recursive type is the sum of the norms of its components. For polynomials, vectors or matrices of complex numbers one recovers the \emph{square} of the usual $L^2$ norm. In most applications, the missing square root computation can be skipped. \fun{GEN}{gnorml1}{GEN x, long prec} The norm of a scalar is its complex modulus, the norm of a recursive type is the sum of the norms of its components. For polynomials, vectors or matrices of complex numbers one recovers the usual $L^1$ norm. One must include a real precision \kbd{prec} in case the inputs include \typ{COMPLEX} or \typ{QUAD} with exact rational components: a square root must be computed and we must choose an accuracy. \fun{GEN}{gnorml1_fake}{GEN x} as \tet{gnorml1}, except that the norm of a \typ{QUAD} $x + wy$ or \typ{COMPLEX} $x + Iy$ is defined as $|x| + |y|$, where we use the ordinary real absolute value. This is still a norm of $\R$ vector spaces, which is easier to compute than \kbd{gnorml1} and can often be used in its place. \fun{GEN}{gsupnorm}{GEN x, long prec} The norm of a scalar is its complex modulus, the norm of a recursive type is the max of the norms of its components. A precision \kbd{prec} must be included for the same reason as in \kbd{gnorml1}. \fun{void}{gsupnorm_aux}{GEN x, GEN *m, GEN *m2, long prec} is the low-level function underlying \kbd{gsupnorm}, used as follows: \bprog GEN m = NULL, m2 = NULL; gsupnorm_aux(x, &m, &m2); @eprog After the call, the sup norm of $x$ is the min of \kbd{m} and the square root of \kbd{m2}; one or both of \kbd{m}, \kbd{m2} may be \kbd{NULL}, in which case it must be omitted. You may initially set \kbd{m} and \kbd{m2} to non-\kbd{NULL} values, in which case, the above procedure yields the max of (the initial) \kbd{m}, the square root of (the initial) \kbd{m2}, and the sup norm of $x$. The strange interface is due to the fact that $|z|^2$ is easier to compute than $|z|$ for a \typ{QUAD} or \typ{COMPLEX} $z$: \kbd{m2} is the max of those $|z|^2$, and \kbd{m} is the max of the other $|z|$. \section{Substitution and evaluation} \fun{GEN}{gsubst}{GEN x, long v, GEN y} substitutes the object \kbd{y} into~\kbd{x} for the variable number~\kbd{v}. \fun{GEN}{poleval}{GEN q, GEN x} evaluates the \typ{POL} or \typ{RFRAC} $q$ at $x$. For convenience, a \typ{VEC} or \typ{COL} is also recognized as the \typ{POL} \kbd{gtovecrev(q)}. \fun{GEN}{RgX_cxeval}{GEN T, GEN x, GEN xi} evaluate the \typ{POL} $T$ at $x$ via Horner's scheme. If \var{xi} is not \kbd{NULL} it must be equal to $1/x$ and we evaluate $x^{\deg T}T(1/x)$ instead. This is useful when $|x| > 1$ is a \typ{REAL} or an inexact \typ{COMPLEX} and $T$ has ``balanced'' coefficients, since the evaluation becomes numerically stable. \fun{GEN}{RgX_RgM_eval}{GEN q, GEN x} evaluates the \typ{POL} $q$ at the square matrix $x$. \fun{GEN}{RgX_RgMV_eval}{GEN f, GEN V} returns the evaluation $\kbd{f}(\kbd{x})$, assuming that \kbd{V} was computed by $\kbd{FpXQ\_powers}(\kbd{x}, n)$ for some $n>1$. \fun{GEN}{qfeval}{GEN q, GEN x} evaluates the quadratic form $q$ (symmetric matrix) at $x$ (column vector of compatible dimensions). \fun{GEN}{qfevalb}{GEN q, GEN x, GEN y} evaluates the polar bilinear form attached to the quadratic form $q$ (symmetric matrix) at $x$, $y$ (column vectors of compatible dimensions). \fun{GEN}{hqfeval}{GEN q, GEN x} evaluates the Hermitian form $q$ (a Hermitian complex matrix) at $x$. \fun{GEN}{qf_apply_RgM}{GEN q, GEN M} $q$ is a symmetric $n\times n$ matrix, $M$ an $n\times k$ matrix, return $M' q M$. \fun{GEN}{qf_apply_ZM}{GEN q, GEN M} as above assuming that both $q$ and $M$ have integer entries. \newpage \chapter{Miscellaneous mathematical functions} \section{Fractions} \fun{GEN}{absfrac}{GEN x} returns the absolute value of the \typ{FRAC} $x$. \fun{GEN}{absfrac_shallow}{GEN x} $x$ being a \typ{FRAC}, returns a shallow copy of $|x|$, in particular returns $x$ itself when $x \geq 0$, and \kbd{gneg($x$)} otherwise. \fun{GEN}{sqrfrac}{GEN x} returns the square of the \typ{FRAC} $x$. \section{Binomials} \fun{GEN}{binomial}{GEN x, long k} \fun{GEN}{binomialuu}{ulong n, ulong k} \fun{GEN}{vecbinomial}{long n}, which returns a vector $v$ with $n+1$ \typ{INT} components such that $v[k+1] = \kbd{binomial}(n,k)$ for $k$ from $0$ up to $n$. \section{Real numbers} \fun{GEN}{R_abs}{GEN x} $x$ being a \typ{INT}, a \typ{REAL} or a \typ{FRAC}, returns $|x|$. \fun{GEN}{R_abs_shallow}{GEN x} $x$ being a \typ{INT}, a \typ{REAL} or a \typ{FRAC}, returns a shallow copy of $|x|$, in particular returns $x$ itself when $x \geq 0$, and \kbd{gneg($x$)} otherwise. \fun{GEN}{modRr_safe}{GEN x, GEN y} let $x$ be a \typ{INT}, a \typ{REAL} or \typ{FRAC} and let $y$ be a \typ{REAL}. Return $x\% y$ unless the input accuracy is unsufficient to compute the floor or $x/y$ in which case we return \kbd{NULL}. \section{Complex numbers} \fun{GEN}{gimag}{GEN x} returns a copy of the imaginary part of \kbd{x}. \fun{GEN}{greal}{GEN x} returns a copy of the real part of \kbd{x}. If \kbd{x} is a \typ{QUAD}, returns the coefficient of $1$ in the ``canonical'' integral basis $(1,\omega)$. \fun{GEN}{gconj}{GEN x} returns $\kbd{greal}(x) - 2\kbd{gimag}(x)$, which is the ordinary complex conjugate except for a real \typ{QUAD}. \fun{GEN}{imag_i}{GEN x}, shallow variant of \kbd{gimag}. \fun{GEN}{real_i}{GEN x}, shallow variant of \kbd{greal}. \fun{GEN}{conj_i}{GEN x}, shallow variant of \kbd{gconj}. \fun{GEN}{mulreal}{GEN x, GEN} returns the real part of $xy$; $x,y$ have type \typ{INT}, \typ{FRAC}, \typ{REAL} or \typ{COMPLEX}. See also \kbd{RgM\_mulreal}. \fun{GEN}{cxnorm}{GEN x} norm of the \typ{COMPLEX} $x$ (modulus squared). \fun{GEN}{cxexpm1}{GEN x} returns $\exp(x)-1$, for a \typ{COMPLEX} $x$. \fun{int}{cx_approx_equal}{GEN a, GEN b} test whether (\typ{INT}, \typ{FRAC}, \typ{REAL}, or \typ{COMPLEX} of those) $a$ and $b$ are approximately equal. This returns $1$ if and only if the division by $a-b$ would produce a division by $0$ (which is a less stringent test than testing whether $a-b$ evaluates to $0$). \section{Quadratic numbers and binary quadratic forms} \fun{GEN}{quad_disc}{GEN x} returns the discriminant of the \typ{QUAD} $x$. Not stack-clean but suitable for \kbd{gerepileupto}. \fun{GEN}{quadnorm}{GEN x} norm of the \typ{QUAD} $x$. \fun{GEN}{qfb_disc}{GEN x} returns the discriminant of the \typ{QFI} or \typ{QFR} \kbd{x}. \fun{GEN}{qfb_disc3}{GEN x, GEN y, GEN z} returns $y^2 - 4xz$ assuming all inputs are \typ{INT}s. Not stack-clean. \fun{GEN}{qfb_apply_ZM}{GEN q, GEN g} returns $q \circ g$. \fun{GEN}{qfbforms}{GEN D} given a discriminant $D < 0$, return the list of reduced forms of discriminant $D$ as \typ{VECSMALL} with 3 components. The primitive forms in the list enumerate the class group of the quadratic order of discriminant $D$; if $D$ is fundamental, all returned forms are automatically primitive. \section{Polynomials}\label{se:polynomials} \fun{GEN}{truecoef}{GEN x, long n} returns \kbd{polcoef(x,n, -1)}, i.e. the coefficient of the term of degree \kbd{n} in the main variable. This is a safe but expensive function that must \emph{copy} its return value so that it be \kbd{gerepile}-safe. Use \kbd{polcoef\_i} for a fast internal variant. \fun{GEN}{polcoef_i}{GEN x, long n, long v} internal shallow function. Rewrite $x$ as a Laurent polynomial in the variable $v$ and returns its coefficient of degree $n$ (\kbd{gen\_0} if this falls outside the coefficient array). Allow \typ{POL}, \typ{SER}, \typ{RFRAC} and scalars. \fun{long}{degree}{GEN x} returns \kbd{poldegree(x, -1)}, the degree of \kbd{x} with respect to its main variable, with the usual meaning if the leading coefficient of $x$ is non-zero. If the sign of $x$ is $0$, this function always returns $-1$. Otherwise, we return the index of the leading coefficient of $x$, i.e. the coefficient of largest index stored in $x$. For instance the ``degrees'' of \bprog 0. E-38 * x^4 + 0.E-19 * x + 1 Mod(0,2) * x^0 \\ sign is 0 ! @eprog\noindent are $4$ and $-1$ respectively. \fun{long}{degpol}{GEN x} is a simple macro returning \kbd{lg(x) - 3}. This is the degree of the \typ{POL}~\kbd{x} with respect to its main variable, \emph{if} its leading coefficient is non-zero (a rational $0$ is impossible, but an inexact $0$ is allowed, as well as an exact modular $0$, e.g. \kbd{Mod(0,2)}). If $x$ has no coefficients (rational $0$ polynomial), its length is $2$ and we return the expected $-1$. \fun{GEN}{characteristic}{GEN x} returns the characteristic of the base ring over which the polynomial is defined (as defined by \typ{INTMOD} and \typ{FFELT} components). The function raises an exception if incompatible primes arise from \typ{FFELT} and \typ{PADIC} components. Shallow function. \fun{GEN}{residual_characteristic}{GEN x} returns a kind of ``residual characteristic'' of the base ring over which the polynomial is defined. This is defined as the gcd of all moduli \typ{INTMOD}s occurring in the structure, as well as primes $p$ arising from \typ{PADIC}s or \typ{FFELT}s. The function raises an exception if incompatible primes arise from \typ{FFELT} and \typ{PADIC} components. Shallow function. \fun{GEN}{resultant}{GEN x,GEN y} resultant of \kbd{x} and \kbd{y}, with respect to the main variable of highest priority. Uses either the subresultant algorithm (generic case), a modular algorithm (inputs in $\Q[X]$) or Sylvester's matrix (inexact inputs). \fun{GEN}{resultant2}{GEN x, GEN y} resultant of \kbd{x} and \kbd{y}, with respect to the main variable of highest priority. Computes the determinant of Sylvester's matrix. \fun{GEN}{cleanroots}{GEN x, long prec} returns the complex roots of the complex polynomial $x$ (with coefficients \typ{INT}, \typ{FRAC}, \typ{REAL} or \typ{COMPLEX} of the above). The roots are returned as \typ{REAL} or \typ{COMPLEX} of \typ{REAL}s of precision \kbd{prec} (guaranteeing a non-$0$ imaginary part). See \tet{QX_complex_roots}. \fun{double}{fujiwara_bound}{GEN x} return a quick upper bound for the logarithm in base $2$ of the modulus of the largest complex roots of the polynomial $x$ (complex coefficients). \fun{double}{fujiwara_bound_real}{GEN x, long sign} return a quick upper bound for the logarithm in base $2$ of the absolute value of the largest real root of sign \var{sign} ($1$ or $-1$), for the polynomial $x$ (real coefficients). \fun{GEN}{polmod_to_embed}{GEN x, long prec} return the vector of complex embeddings of the \typ{POLMOD} $x$ (with complex coefficients). Shallow function, simple complex variant of \tet{conjvec}. \section{Power series} \fun{GEN}{sertoser}{GEN x, long prec} return the \typ{SER} $x$ truncated or extended (with zeros) to \kbd{prec} terms. Shallow function, assume that $\kbd{prec} \geq 0$. \fun{GEN}{derivser}{GEN x} returns the derivative of the \typ{SER} \kbd{x} with respect to its main variable. \fun{GEN}{integser}{GEN x} returns the primitive of the \typ{SER} \kbd{x} with respect to its main variable. \fun{GEN}{truecoef}{GEN x, long n} returns \kbd{polcoef(x,n, -1)}, i.e. the coefficient of the term of degree \kbd{n} in the main variable. This is a safe but expensive function that must \emph{copy} its return value so that it be \kbd{gerepile}-safe. Use \kbd{polcoef\_i} for a fast internal variant. \fun{GEN}{ser_unscale}{GEN P, GEN h} return $P(h x)$, not memory clean. \fun{GEN}{ser_normalize}{GEN x} divide $x$ by its ``leading term'' so that the series is either $0$ or equal to $t^v(1+O(t))$. Shallow function if the ``leading term'' is $1$. \fun{int}{ser_isexactzero}{GEN x} return $1$ if $x$ is a zero series, all of whose known coefficients are exact zeroes; this implies that $\kbd{sign}(x) = 0$ and $\kbd{lg}(x) \leq 3$. \fun{GEN}{ser_inv}{GEN x} return the inverse of the \typ{SER} $x$ using Newton iteration. This is in general slower than \kbd{ginv} unless the precision is huge (hundreds of terms, where the threshold depends strongly on the base field). \section{Functions to handle \typ{FFELT}} These functions define the public interface of the \typ{FFELT} type to use in generic functions. However, in specific functions, it is better to use the functions class \kbd{FpXQ} and/or \kbd{Flxq} as appropriate. \fun{GEN}{FF_p}{GEN a} returns the characteristic of the definition field of the \typ{FFELT} element \kbd{a}. \fun{long}{FF_f}{GEN a} returns the dimension of the definition field over its prime field; the cardinality of the dimension field is thus $p^f$. \fun{GEN}{FF_p_i}{GEN a} shallow version of \kbd{FF\_p}. \fun{GEN}{FF_q}{GEN a} returns the cardinality of the definition field of the \typ{FFELT} element \kbd{a}. \fun{GEN}{FF_mod}{GEN a} returns the polynomial (with reduced \typ{INT} coefficients) defining the finite field, in the variable used to display $a$. \fun{GEN}{FF_gen}{GEN a} returns the standard generator of the definition field of the \typ{FFELT} element \kbd{a}, see \kbd{ffgen}, that is $x\pmod{T}$ where $T$ is the polynomial over the prime field that define the finite field. \fun{GEN}{FF_to_FpXQ}{GEN a} converts the \typ{FFELT} \kbd{a} to a polynomial $P$ with reduced \typ{INT} coefficients such that $a=P(g)$ where $g$ is the generator of the finite field returned by \kbd{ffgen}, in the variable used to display $g$. \fun{GEN}{FF_to_FpXQ_i}{GEN a} shallow version of \kbd{FF\_to\_FpXQ}. \fun{GEN}{FF_to_F2xq}{GEN a} converts the \typ{FFELT} \kbd{a} to a \kbd{F2x} $P$ such that $a=P(g)$ where $g$ is the generator of the finite field returned by \kbd{ffgen}, in the variable used to display $g$. This only work if the characteristic is $2$. \fun{GEN}{FF_to_F2xq_i}{GEN a} shallow version of \kbd{FF\_to\_F2xq}. \fun{GEN}{FF_to_Flxq}{GEN a} converts the \typ{FFELT} \kbd{a} to a \kbd{Flx} $P$ such that $a=P(g)$ where $g$ is the generator of the finite field returned by \kbd{ffgen}, in the variable used to display $g$. This only work if the characteristic is small enough. \fun{GEN}{FF_to_Flxq_i}{GEN a} shallow version of \kbd{FF\_to\_Flxq}. \fun{GEN}{p_to_FF}{GEN p, long v} returns a \typ{FFELT} equal to $1$ in the finite field $\Z/p\Z$. Useful for generic code that wants to handle (inefficiently) $\Z/p\Z$ as if it were not a prime field. \fun{GEN}{Tp_to_FF}{GEN T, GEN p} returns a \typ{FFELT} equal to $1$ in the finite field $\F_p/(T)$, where $T$ is a \kbd{ZX}, assumed to be irreducible modulo $p$, or \kbd{NULL} in which case the routine acts as \tet{p_to_FF(p,0)}. No checks. \fun{GEN}{Fq_to_FF}{GEN x, GEN ff} returns a \typ{FFELT} equal to $x$ in the finite field defined by the \typ{FFELT} \kbd{ff}, where $x$ is an \kbd{Fq} (either a \typ{INT} or a \kbd{ZX}: a \typ{POL} with \typ{INT} coefficients). No checks. \fun{GEN}{FqX_to_FFX}{GEN x, GEN ff} given an \kbd{FqX} $x$, return the polynomial with \typ{FFELT} coefficients obtained by applying \tet{Fq_to_FF} coefficientwise. No checks, and no normalization if the leading coefficient maps to $0$. \fun{GEN}{FF_1}{GEN a} returns the unity in the definition field of the \typ{FFELT} element \kbd{a}. \fun{GEN}{FF_zero}{GEN a} returns the zero element of the definition field of the \typ{FFELT} element \kbd{a}. \fun{int}{FF_equal0}{GEN a} returns $1$ if the \typ{FFELT} \kbd{a} is equal to $0$ else returns $0$. \fun{int}{FF_equal1}{GEN a} returns $1$ if the \typ{FFELT} \kbd{a} is equal to $1$ else returns $0$. \fun{int}{FF_equalm1}{GEN a} returns $-1$ if the \typ{FFELT} \kbd{a} is equal to $1$ else returns $0$. \fun{int}{FF_equal}{GEN a, GEN b} return $1$ if the \typ{FFELT} \kbd{a} and \kbd{b} have the same definition field and are equal, else $0$. \fun{int}{FF_samefield}{GEN a, GEN b} return $1$ if the \typ{FFELT} \kbd{a} and \kbd{b} have the same definition field, else $0$. \fun{int}{Rg_is_FF}{GEN c, GEN *ff} to be called successively on many objects, setting \kbd{*ff = NULL} (unset) initially. Returns $1$ as long as $c$ is a \typ{FFELT} defined over the same field as \kbd{*ff} (setting \kbd{*ff = c} if unset), and $0$ otherwise. \fun{int}{RgC_is_FFC}{GEN x, GEN *ff} apply \tet{Rg_is_FF} successively to all components of the \typ{VEC} or \typ{COL} $x$. Return $0$ if one call fails, and $1$ otherwise. \fun{int}{RgM_is_FFM}{GEN x, GEN *ff} apply \tet{Rg_is_FF} to all components of the \typ{MAT}. Return $0$ if one call fails, and $1$ otherwise. \fun{GEN}{FF_add}{GEN a, GEN b} returns $a+b$ where \kbd{a} and \kbd{b} are \typ{FFELT} having the same definition field. \fun{GEN}{FF_Z_add}{GEN a, GEN x} returns $a+x$, where \kbd{a} is a \typ{FFELT}, and \kbd{x} is a \typ{INT}, the computation being performed in the definition field of \kbd{a}. \fun{GEN}{FF_Q_add}{GEN a, GEN x} returns $a+x$, where \kbd{a} is a \typ{FFELT}, and \kbd{x} is a \typ{RFRAC}, the computation being performed in the definition field of \kbd{a}. \fun{GEN}{FF_sub}{GEN a, GEN b} returns $a-b$ where \kbd{a} and \kbd{b} are \typ{FFELT} having the same definition field. \fun{GEN}{FF_mul}{GEN a, GEN b} returns $a\*b$ where \kbd{a} and \kbd{b} are \typ{FFELT} having the same definition field. \fun{GEN}{FF_Z_mul}{GEN a, GEN b} returns $a\*b$, where \kbd{a} is a \typ{FFELT}, and \kbd{b} is a \typ{INT}, the computation being performed in the definition field of \kbd{a}. \fun{GEN}{FF_div}{GEN a, GEN b} returns $a/b$ where \kbd{a} and \kbd{b} are \typ{FFELT} having the same definition field. \fun{GEN}{FF_neg}{GEN a} returns $-a$ where \kbd{a} is a \typ{FFELT}. \fun{GEN}{FF_neg_i}{GEN a} shallow function returning $-a$ where \kbd{a} is a \typ{FFELT}. \fun{GEN}{FF_inv}{GEN a} returns $a^{-1}$ where \kbd{a} is a \typ{FFELT}. \fun{GEN}{FF_sqr}{GEN a} returns $a^2$ where \kbd{a} is a \typ{FFELT}. \fun{GEN}{FF_mul2n}{GEN a, long n} returns $a\*2^n$ where \kbd{a} is a \typ{FFELT}. \fun{GEN}{FF_pow}{GEN a, GEN n} returns $a^n$ where \kbd{a} is a \typ{FFELT} and \kbd{n} is a \typ{INT}. \fun{GEN}{FF_Frobenius}{GEN a, GEN n} returns $a^{p^n}$ where \kbd{a} is a \typ{FFELT} \kbd{n} is a \typ{INT}, and $p$ is the characteristic of the definition field of $a$. \fun{GEN}{FF_Z_Z_muldiv}{GEN a, GEN x, GEN y} returns $a\*y/z$, where \kbd{a} is a \typ{FFELT}, and \kbd{x} and \kbd{y} are \typ{INT}, the computation being performed in the definition field of \kbd{a}. \fun{GEN}{Z_FF_div}{GEN x, GEN a} return $x/a$ where \kbd{a} is a \typ{FFELT}, and \kbd{x} is a \typ{INT}, the computation being performed in the definition field of \kbd{a}. \fun{GEN}{FF_norm}{GEN a} returns the norm of the \typ{FFELT} \kbd{a} with respect to its definition field. \fun{GEN}{FF_trace}{GEN a} returns the trace of the \typ{FFELT} \kbd{a} with respect to its definition field. \fun{GEN}{FF_conjvec}{GEN a} returns the vector of conjugates $[a,a^p,a^{p^2},\ldots,a^{p^{n-1}}]$ where the \typ{FFELT} \kbd{a} belong to a field with $p^n$ elements. \fun{GEN}{FF_charpoly}{GEN a} returns the characteristic polynomial) of the \typ{FFELT} \kbd{a} with respect to its definition field. \fun{GEN}{FF_minpoly}{GEN a} returns the minimal polynomial of the \typ{FFELT} \kbd{a}. \fun{GEN}{FF_sqrt}{GEN a} returns an \typ{FFELT} $b$ such that $a=b^2$ if it exist, where \kbd{a} is a \typ{FFELT}. \fun{long}{FF_issquareall}{GEN x, GEN *pt} returns $1$ if \kbd{x} is a square, and $0$ otherwise. If \kbd{x} is indeed a square, set \kbd{pt} to its square root. \fun{long}{FF_issquare}{GEN x} returns $1$ if \kbd{x} is a square and $0$ otherwise. \fun{long}{FF_ispower}{GEN x, GEN K, GEN *pt} Given $K$ a positive integer, returns $1$ if \kbd{x} is a $K$-th power, and $0$ otherwise. If \kbd{x} is indeed a $K$-th power, set \kbd{pt} to its $K$-th root. \fun{GEN}{FF_sqrtn}{GEN a, GEN n, GEN *zn} returns an \kbd{n}-th root of $\kbd{a}$ if it exist. If \kbd{zn} is non-\kbd{NULL} set it to a primitive \kbd{n}-th root of the unity. \fun{GEN}{FF_log}{GEN a, GEN g, GEN o} the \typ{FFELT} \kbd{g} being a generator for the definition field of the \typ{FFELT} \kbd{a}, returns a \typ{INT} $e$ such that $a^e=g$. If $e$ does not exists, the result is currently undefined. If \kbd{o} is not \kbd{NULL} it is assumed to be a factorization of the multiplicative order of \kbd{g} (as set by \tet{FF_primroot}) \fun{GEN}{FF_order}{GEN a, GEN o} returns the order of the \typ{FFELT} \kbd{a}. If \kbd{o} is non-\kbd{NULL}, it is assumed that \kbd{o} is a multiple of the order of \kbd{a}. \fun{GEN}{FF_primroot}{GEN a, GEN *o} returns a generator of the multiplicative group of the definition field of the \typ{FFELT} \kbd{a}. If \kbd{o} is not \kbd{NULL}, set it to the factorization of the order of the primitive root (to speed up \tet{FF_log}). \fun{GEN}{FF_map}{GEN m, GEN a} returns $A(m)$ where \kbd{A=a.pol} assuming $a$ and $m$ belongs to fields having the same characteristic. \subsec{FFX} The functions in this sections take polynomial arguments and a \typ{FFELT} $a$. The coefficients of the polynomials must be of type \typ{INT}, \typ{INTMOD} or \typ{FFELT} and compatible with \kbd{a}. \fun{GEN}{FFX_mul}{GEN P, GEN Q, GEN a} returns the product of the polynomials \kbd{P} and \kbd{Q} defined over the definition field of the \typ{FFELT} \kbd{a}. \fun{GEN}{FFX_sqr}{GEN P, GEN a} returns the square of the polynomial \kbd{P} defined over the definition field of the \typ{FFELT} \kbd{a}. \fun{GEN}{FFX_rem}{GEN P, GEN Q, GEN a} returns the remainder of the polynomial \kbd{P} modulo the polynomial \kbd{Q}, where \kbd{P} and \kbd{Q} are defined over the definition field of the \typ{FFELT} \kbd{a}. \fun{GEN}{FFX_ispower}{GEN P, ulong k, GEN a, GEN *py} return $1$ if the \kbd{FFX} $P$ is a $k$-th power, $0$ otherwise, where \kbd{P} is defined over the definition field of the \typ{FFELT} \kbd{a}. If \kbd{py} is not \kbd{NULL}, set it to $g$ such that $g^k = f$. \fun{GEN}{FFX_factor}{GEN f, GEN a} returns the factorization of the univariate polynomial \kbd{f} over the definition field of the \typ{FFELT} \kbd{a}. The coefficients of \kbd{f} must be of type \typ{INT}, \typ{INTMOD} or \typ{FFELT} and compatible with \kbd{a}. \fun{GEN}{FFX_factor_squarefree}{GEN f, GEN a} returns the squarefree factorization of the univariate polynomial \kbd{f} over the definition field of the \typ{FFELT} \kbd{a}. This is a vector $[u_1,\dots,u_k]$ of pairwise coprime \kbd{FFX} such that $u_k \neq 1$ and $f = \prod u_i^i$. \fun{GEN}{FFX_ddf}{GEN f, GEN a} assuming that $f$ is squarefree, returns the distinct degree factorization of $f$ modulo $p$. The returned value \kbd{v} is a \typ{VEC} with two components: \kbd{F=v[1]} is a vector of (\kbd{FFX}) factors, and \kbd{E=v[2]} is a \typ{VECSMALL}, such that $f$ is equal to the product of the \kbd{F[i]} and each \kbd{F[i]} is a product of irreducible factors of degree \kbd{E[i]}. \fun{GEN}{FFX_degfact}{GEN f, GEN a}, as \kbd{FFX\_factor}, but the degrees of the irreducible factors are returned instead of the factors themselves (as a \typ{VECSMALL}). \fun{GEN}{FFX_roots}{GEN f, GEN a} returns the roots (\typ{FFELT}) of the univariate polynomial \kbd{f} over the definition field of the \typ{FFELT} \kbd{a}. The coefficients of \kbd{f} must be of type \typ{INT}, \typ{INTMOD} or \typ{FFELT} and compatible with \kbd{a}. \fun{GEN}{FFX_preimage}{GEN F, GEN x, GEN a} returns $P\%F$ where \kbd{P=x.pol} assuming $a$ and $x$ belongs to fields having the same characteristic, and that the coefficients of $F$ belong to the definition field of $a$. \subsec{FFM} \fun{GEN}{FFM_FFC_gauss}{GEN M, GEN C, GEN ff} given a matrix \kbd{M} (\typ{MAT}) and a column vector \kbd{C} (\typ{COL}) over the finite field given by \kbd{ff} (\typ{FFELT}) such that $M$ is invertible, return the unique column vector $X$ such that $MX=C$. \fun{GEN}{FFM_FFC_invimage}{GEN M, GEN C, GEN ff} given a matrix \kbd{M} (\typ{MAT}) and a column vector \kbd{C} (\typ{COL}) over the finite field given by \kbd{ff} (\typ{FFELT}), return a column vector \kbd{X} such that $MX=C$, or \kbd{NULL} if no such vector exists. \fun{GEN}{FFM_FFC_mul}{GEN M, GEN C, GEN ff} returns the product of the matrix~\kbd{M} (\typ{MAT}) and the column vector~\kbd{C} (\typ{COL}) over the finite field given by \kbd{ff} (\typ{FFELT}). \fun{GEN}{FFM_deplin}{GEN M, GEN ff} returns a non-zero vector (\typ{COL}) in the kernel of the matrix~\kbd{M} over the finite field given by \kbd{ff}, or \kbd{NULL} if no such vector exists. \fun{GEN}{FFM_det}{GEN M, GEN ff} returns the determinant of the matrix~\kbd{M} over the finite field given by \kbd{ff}. \fun{GEN}{FFM_gauss}{GEN M, GEN N, GEN ff} given two matrices \kbd{M} and~\kbd{N} (\typ{MAT}) over the finite field given by \kbd{ff} (\typ{FFELT}) such that $M$ is invertible, return the unique matrix $X$ such that $MX=N$. \fun{GEN}{FFM_image}{GEN M, GEN ff} returns a matrix whose columns span the image of the matrix~\kbd{M} over the finite field given by \kbd{ff}. \fun{GEN}{FFM_indexrank}{GEN M, GEN ff} given a matrix \kbd{M} of rank~$r$ over the finite field given by \kbd{ff}, returns a vector with two \typ{VECSMALL} components $y$ and $z$ containing $r$ row and column indices, respectively, such that the $r\times r$-matrix formed by the \kbd{M[i,j]} for $i$ in $y$ and $j$ in $z$ is invertible. \fun{GEN}{FFM_inv}{GEN M, GEN ff} returns the inverse of the square matrix~\kbd{M} over the finite field given by \kbd{ff}, or \kbd{NULL} if \kbd{M} is not invertible. \fun{GEN}{FFM_invimage}{GEN M, GEN N, GEN ff} given two matrices \kbd{M} and~\kbd{N} (\typ{MAT}) over the finite field given by \kbd{ff} (\typ{FFELT}), return a matrix \kbd{X} such that $MX=N$, or \kbd{NULL} if no such matrix exists. \fun{GEN}{FFM_ker}{GEN M, GEN ff} returns the kernel of the \typ{MAT} \kbd{M} over the finite field given by the \typ{FFELT} \kbd{ff}. \fun{GEN}{FFM_mul}{GEN M, GEN N, GEN ff} returns the product of the matrices \kbd{M} and~\kbd{N} (\typ{MAT}) over the finite field given by \kbd{ff} (\typ{FFELT}). \fun{long}{FFM_rank}{GEN M, GEN ff} returns the rank of the matrix~\kbd{M} over the finite field given by \kbd{ff}. \fun{GEN}{FFM_suppl}{GEN M, GEN ff} given a matrix \kbd{M} over the finite field given by \kbd{ff} whose columns are linearly independent, returns a square invertible matrix whose first columns are those of~\kbd{M}. \subsec{FFXQ} \fun{GEN}{FFXQ_mul}{GEN P, GEN Q, GEN T, GEN a} returns the product of the polynomials \kbd{P} and \kbd{Q} modulo the polynomial \kbd{T}, where \kbd{P}, \kbd{Q} and \kbd{T} are defined over the definition field of the \typ{FFELT} \kbd{a}. \fun{GEN}{FFXQ_sqr}{GEN P, GEN T, GEN a} returns the square of the polynomial \kbd{P} modulo the polynomial \kbd{T}, where \kbd{P} and \kbd{T} are defined over the definition field of the \typ{FFELT} \kbd{a}. \fun{GEN}{FFXQ_inv}{GEN P, GEN Q, GEN a} returns the inverse of the polynomial \kbd{P} modulo the polynomial \kbd{Q}, where \kbd{P} and \kbd{Q} are defined over the definition field of the \typ{FFELT} \kbd{a}. \section{Transcendental functions} The following two functions are only useful when interacting with \kbd{gp}, to manipulate its internal default precision (expressed as a number of decimal digits, not in words as used everywhere else): \fun{long}{getrealprecision}{void} returns \kbd{realprecision}. \fun{long}{setrealprecision}{long n, long *prec} sets the new \kbd{realprecision} to $n$, which is returned. As a side effect, set \kbd{prec} to the corresponding number of words \kbd{ndec2prec(n)}. \subsec{Transcendental functions with \typ{REAL} arguments} In the following routines, $x$ is assumed to be a \typ{REAL} and the result is a \typ{REAL} (sometimes a \typ{COMPLEX} with \typ{REAL} components), with the largest accuracy which can be deduced from the input. The naming scheme is inconsistent here, since we sometimes use the prefix \kbd{mp} even though \typ{INT} inputs are forbidden: \fun{GEN}{sqrtr}{GEN x} returns the square root of $x$. \fun{GEN}{cbrtr}{GEN x} returns the real cube root of $x$. \fun{GEN}{sqrtnr}{GEN x, long n} returns the $n$-th root of $x$, assuming $n\geq 1$ and $x \geq 0$. \fun{GEN}{sqrtnr_abs}{GEN x, long n} returns the $n$-th root of $|x|$, assuming $n\geq 1$ and $x \neq 0$. \fun{GEN}{mpcos[z]}{GEN x[, GEN z]} returns $\cos(x)$. \fun{GEN}{mpsin[z]}{GEN x[, GEN z]} returns $\sin(x)$. \fun{GEN}{mplog[z]}{GEN x[, GEN z]} returns $\log(x)$. We must have $x > 0$ since the result must be a \typ{REAL}. Use \kbd{glog} for the general case, where you want such computations as $\log(-1) = I$. \fun{GEN}{mpexp[z]}{GEN x[, GEN z]} returns $\exp(x)$. \fun{GEN}{mpexpm1}{GEN x} returns $\exp(x)-1$, but is more accurate than \kbd{subrs(mpexp(x), 1)}, which suffers from catastrophic cancellation if $|x|$ is very small. \fun{void}{mpsincosm1}{GEN x, GEN *s, GEN *c} sets $s$ and $c$ to $\sin(x)$ and $\cos(x)-1$ respectively, where $x$ is a \typ{REAL}; the latter is more accurate than \kbd{subrs(mpcos(y), 1)}, which suffers from catastrophic cancellation if $|x|$ is very small. \fun{GEN}{mpveceint1}{GEN C, GEN eC, long n} as \kbd{veceint1}; assumes that $C > 0$ is a \typ{REAL} and that \kbd{eC} is \kbd{NULL} or \kbd{mpexp(C)}. \fun{GEN}{mpeint1}{GEN x, GEN expx} returns \kbd{eint1}$(x)$, for a \typ{REAL} $x\geq 0$, assuming that \kbd{expx} is \kbd{mpexp}$(x)$. \fun{GEN}{mplambertW}{GEN y} solution $x$ of the implicit equation $x \exp(x) = y$, for $y > 0$ a \typ{REAL}. \noindent Useful low-level functions which \emph{disregard} the sign of $x$: \fun{GEN}{sqrtr_abs}{GEN x} returns $\sqrt{|x|}$ assuming $x\neq 0$. \fun{GEN}{cbrtr_abs}{GEN x} returns $|x|^{1/3}$ assuming $x\neq 0$. \fun{GEN}{exp1r_abs}{GEN x} returns $\exp(|x|) - 1$, assuming $x \neq 0$. \fun{GEN}{logr_abs}{GEN x} returns $\log(|x|)$, assuming $x \neq 0$. \subsec{Other complex transcendental functions} \fun{GEN}{szeta}{long s, long prec} returns the value of Riemann's zeta function at the (possibly negative) integer $s\neq 1$, in relative accuracy \kbd{prec}. \fun{GEN}{veczeta}{GEN a, GEN b, long N, long prec} returns in a vector all the $\zeta(aj + b)$, where $j = 0, 1, \dots, N-1$, where $a$ and $b$ are real numbers (of arbitrary type, although \typ{INT} is treated more efficiently) and $b > 1$. Assumes that $N \geq 1$. \fun{GEN}{ggamma1m1}{GEN x, long prec} return $\Gamma(1+x) - 1$ assuming $|x| < 1$. Guard against cancellation when $x$ is small. \noindent A few variants on sin and cos: \fun{void}{mpsincos}{GEN x, GEN *s, GEN *c} sets $s$ and $c$ to $\sin(x)$ and $\cos(x)$ respectively, where $x$ is a \typ{REAL} \fun{GEN}{expIr}{GEN x} returns $\exp(ix)$, where $x$ is a \typ{REAL}. The return type is \typ{COMPLEX} unless the imaginary part is equal to $0$ to the current accuracy (its sign is $0$). \fun{GEN}{expIxy}{GEN x, GEN y, long prec} returns $\exp(ixy)$. Efficient when $x$ is real and $y$ pure imaginary. \fun{void}{gsincos}{GEN x, GEN *s, GEN *c, long prec} general case. \fun{GEN}{rootsof1_cx}{GEN d, long prec} return $e(1/d)$ at precision \kbd{prec}, $e(x) = \exp(2i\pi x)$. \fun{GEN}{rootsof1u_cx}{ulong d, long prec} return $e(1/d)$ at precision \kbd{prec}. \fun{GEN}{rootsof1q_cx}{long a, long b, long prec} return $e(a/b)$ at precision \kbd{prec}. \fun{GEN}{rootsof1powinit}{long a, long b, long prec} precompute $b$-th roots of $1$ for \kbd{rootsof1pow}, i.e. to later compute $e(ac/b)$ for varying $c$. \fun{GEN}{rootsof1pow}{GEN T, long c} given $T = \kbd{rootsof1powinit}(a,b,\kbd{prec})$, return $e(ac/b)$. \noindent A generalization of \tet{affrr_fixlg} \fun{GEN}{affc_fixlg}{GEN x, GEN res} assume \kbd{res} was allocated using \tet{cgetc}, and that $x$ is either a \typ{REAL} or a \typ{COMPLEX} with \typ{REAL} components. Assign $x$ to \kbd{res}, first shortening the components of \kbd{res} if needed (in a \kbd{gerepile}-safe way). Further convert \kbd{res} to a \typ{REAL} if $x$ is a \typ{REAL}. \fun{GEN}{trans_eval}{const char *fun, GEN (*f) (GEN, long), GEN x, long prec} evaluate the transcendental function $f$ (named \kbd{"fun"} at the argument $x$ and precision \kbd{prec}. This is a quick way to implement a transcendental function to be made available under GP, starting from a $C$ function handling only \typ{REAL} and \typ{COMPLEX} arguments. This routine first converts $x$ to a suitable type: \item \typ{INT}/\typ{FRAC} to \typ{REAL} of precision \kbd{prec}, \typ{QUAD} to \typ{REAL} or \typ{COMPLEX} of precision \kbd{prec}. \item \typ{POLMOD} to a \typ{COL} of complex embeddings (as in \tet{conjvec}) Then evaluates the function at \typ{VEC}, \typ{COL}, \typ{MAT} arguments coefficientwise. \subsec{Modular functions} \fun{GEN}{cxredsl2}{GEN z, GEN *g} given $t$ a \typ{COMPLEX} belonging to the upper half-plane, find $\gamma \in \text{SL}_2(\Z)$ such that $\gamma \cdot z$ belongs to the standard fundamental domain and set \kbd{*g} to $\gamma$. \fun{GEN}{cxredsl2_i}{GEN z, GEN *g, GEN *czd} as \kbd{cxredsl2}; also sets \kbd{*czd} to $cz + d$, if $\gamma = [a,b;c,d]$. \fun{GEN}{cxEk}{GEN tau, long k, long prec} returns $E_k(\tau)$ by direct evaluation of $1 + 2/\zeta(1-k) \sum_n n^{k-1} q^n/(1-q^n)$, $q = e(\tau)$. Assume that $\Im \tau > 0$ and $k$ even. Very slow unless $\tau$ is already reduced modulo $\text{SL}_2(\Z)$. Not \kbd{gerepile}-clean but suitable for \kbd{gerepileupto}. \subsec{Transcendental functions with \typ{PADIC} arguments} \fun{GEN}{Qp_exp}{GEN x} shortcut for \kbd{gexp(x, /*ignored*/prec)} \fun{GEN}{Qp_gamma}{GEN x} shortcut for \kbd{ggamma(x, /*ignored*/prec)} \fun{GEN}{Qp_log}{GEN x} shortcut for \kbd{glog(x, /*ignored*/prec)} \fun{GEN}{Qp_sqrt}{GEN x} shortcut for \kbd{gsqrt(x, /*ignored*/prec)} Return \kbd{NULL} if $x$ is not a square. \fun{GEN}{Qp_sqrtn}{GEN x, GEN n, GEN *z} shortcut for \kbd{gsqrtn(x, n, z, /*ignored*/prec)}. Return \kbd{NULL} if $x$ is not an $n$-th power. \fun{GEN}{Qp_agm2_sequence}{GEN a1, GEN b1} assume $a_1/b_1 = 1$ mod $p$ if $p$ odd and mod $2^4$ if $p = 2$. Let $A_1 = a_1/p^v$ and $B_1 = b_1/p^v$ with $v = v_p(a_1) = v_p(b_1)$; let further $A_{n+1} = (A_n + B_n + 2 B_{n+1}) / 4$, $B_{n+1} = B_n \sqrt{A_n / B_n}$ (the square root of $A_n B_n$ congruent to $B_n$ mod $p$) and $R_n = p^v(A_n - B_n)$. We stop when $R_n$ is $0$ at the given $p$-adic accuracy. This function returns in a triplet \typ{VEC} the three sequences $(A_n)$, $(B_n)$ and $(R_n)$, corresponding to a sequence of $2$-isogenies on the Tate curve $y^2 = x(x-a_1)(x+a_1-b_1)$. The common limit of $A_n$ and $B_n$ is the $M_2(a_1,b_1)$, the square of the $p$-adic AGM of $\sqrt(a_1)$ and $\sqrt(b_1)$. This is given by \tet{ellQp_Ei} and is used by corresponding ascending and descending $p$-adic Landen transforms: \fun{void}{Qp_ascending_Landen}{GEN ABR, GEN *ptx, GEN *pty} \fun{void}{Qp_descending_Landen}{GEN ABR, GEN *ptx, GEN *pty} \subsec{Cached constants} The cached constant is returned at its current precision, which may be larger than \kbd{prec}. One should always use the \kbd{mp\var{xxx}} variant: \kbd{mppi}, \kbd{mpeuler}, or \kbd{mplog2}. \fun{GEN}{consteuler}{long prec} precomputes Euler-Mascheroni's constant at precision \kbd{prec}. \fun{GEN}{constcatalan}{long prec} precomputes Catalan's constant at precision \kbd{prec}. \fun{GEN}{constpi}{long prec} precomputes $\pi$ at precision \kbd{prec}. \fun{GEN}{constlog2}{long prec} precomputes $\log(2)$ at precision \kbd{prec}. \fun{void}{mpbern}{long n, long prec} precomputes the $n$ even \idx{Bernoulli} numbers $B_2,\dots,B_{2n}$ as \typ{FRAC} or \typ{REAL}s of precision \kbd{prec}. For any $2 \leq k \leq 2n$, if a floating point approximation of $B_k$ to accuracy \kbd{prec} is enough to reconstruct it exactly, a \typ{FRAC} is stored; otherwise a \typ{REAL} at the requested accuracy. No more than $n$ Bernoulli numbers will ever be stored (by \tet{bernfrac} or \tet{bernreal}), unless a subsequent call to \kbd{mpbern} increases the cache. If \kbd{prec} is $0$, the $B_k$ are computed exactly. The following functions use cached data if \kbd{prec} is smaller than the precision of the cached value; otherwise the newly computed data replaces the old cache. \fun{GEN}{mppi}{long prec} returns $\pi$ at precision \kbd{prec}. \fun{GEN}{Pi2n}{long n, long prec} returns $2^n\pi$ at precision \kbd{prec}. \fun{GEN}{PiI2}{long n, long prec} returns the complex number $2\pi i$ at precision \kbd{prec}. \fun{GEN}{PiI2n}{long n, long prec} returns the complex number $2^n\pi i$ at precision \kbd{prec}. \fun{GEN}{mpeuler}{long prec} returns Euler-Mascheroni's constant at precision \kbd{prec}. \fun{GEN}{mpeuler}{long prec} returns Catalan's number at precision \kbd{prec}. \fun{GEN}{mplog2}{long prec} returns $\log 2$ at precision \kbd{prec}. \fun{GEN}{bernreal}{long i, long prec} returns the \idx{Bernoulli} number $B_i$ as a \typ{REAL} at precision \kbd{prec}. If \kbd{mpbern(n, p)} was called previously with $n \geq i$ and $p \geq \kbd{prec}$, then the cached value is (converted to a \typ{REAL} of accuracy \kbd{prec} then) returned. Otherwise, the missing value is computed. In the latter case, if $n \geq i$, the cached table is updated. \fun{GEN}{bernfrac}{long i} returns the \idx{Bernoulli} number $B_i$ as a rational number (\typ{FRAC} or \typ{INT}). If a cached table includes $B_i$ as a rational number, the latter is returned. Otherwise, the missing value is computed. In the latter case, the cached Bernoulli table may be updated. \section{Permutations } \noindent Permutations are represented in two different ways \item (\kbd{perm}) a \typ{VECSMALL} $p$ representing the bijection $i\mapsto p[i]$; unless mentioned otherwise, this is the form used in the functions below for both input and output, \item (\kbd{cyc}) a \typ{VEC} of \typ{VECSMALL}s representing a product of disjoint cycles. \fun{GEN}{identity_perm}{long n} return the identity permutation on $n$ symbols. \fun{GEN}{cyclic_perm}{long n, long d} return the cyclic permutation mapping $i$ to $i+d$ (mod $n$) in $S_n$. Assume that $d \leq n$. \fun{GEN}{perm_mul}{GEN s, GEN t} multiply $s$ and $t$ (composition $s\circ t$) \fun{GEN}{perm_conj}{GEN s, GEN t} return $sts^{-1}$. \fun{int}{perm_commute}{GEN p, GEN q} return $1$ if $p$ and $q$ commute, 0 otherwise. \fun{GEN}{perm_inv}{GEN p} returns the inverse of $p$. \fun{GEN}{perm_pow}{GEN p, long n} returns $p^n$ \fun{GEN}{cyc_pow_perm}{GEN p, long n} the permutation $p$ is given as a product of disjoint cycles (\kbd{cyc}); return $p^n$ (as a \kbd{perm}). \fun{GEN}{cyc_pow}{GEN p, long n} the permutation $p$ is given as a product of disjoint cycles (\kbd{cyc}); return $p^n$ (as a \kbd{cyc}). \fun{GEN}{perm_cycles}{GEN p} return the cyclic decomposition of $p$. \fun{long}{perm_order}{GEN p} returns the order of the permutation $p$ (as the lcm of its cycle lengths). \fun{long}{perm_sign}{GEN p} returns the sign of the permutation $p$. \fun{GEN}{vecperm_orbits}{GEN p, long n} the permutation $p\in S_n$ being given as a product of disjoint cycles, return the orbits of the subgroup generated by $p$ on $\{1,2,\ldots,n\}$. \fun{GEN}{Z_to_perm}{long n, GEN x} as \kbd{numtoperm}, returning a \typ{VECSMALL}. \fun{GEN}{perm_to_Z}{GEN v} as \kbd{permtonum} for a \typ{VECSMALL} input. \section{Small groups} The small (finite) groups facility is meant to deal with subgroups of Galois groups obtained by \tet{galoisinit} and thus is currently limited to weakly super-solvable groups. A group \var{grp} of order $n$ is represented by its regular representation (for an arbitrary ordering of its element) in $S_n$. A subgroup of such group is represented by the restriction of the representation to the subgroup. A \emph{small group} can be either a group or a subgroup. Thus it is embedded in some $S_n$, where $n$ is the multiple of the order. Such an $n$ is called the \emph{domain} of the small group. The domain of a trivial subgroup cannot be derived from the subgroup data, so some functions require the subgroup domain as argument. The small group \var{grp} is represented by a \typ{VEC} with two components: $\var{grp}[1]$ is a generating subset $[s_1,\ldots,s_g]$ of \var{grp} expressed as a vector of permutations of length~$n$. $\var{grp}[2]$ contains the relative orders $[o_1,\ldots,o_g]$ of the generators $\var{grp}[1]$. See \tet{galoisinit} for the technical details. \fun{GEN}{checkgroup}{GEN gal, GEN *elts} check whether \var{gal} is a small group or a Galois group. Returns the underlying small group and set \var{elts} to the list of elements or to \kbd{NULL} if it is not known. \fun{GEN}{checkgroupelts}{GEN gal} check whether \var{gal} is a small group or a Galois group, or a vector of permutations listing the group elements. Returns the list of group elements as permutations. \fun{GEN}{galois_group}{GEN gal} return the underlying small group of the Galois group \var{gal}. \fun{GEN}{cyclicgroup}{GEN g, long s} return the cyclic group with generator $g$ of order $s$. \fun{GEN}{trivialgroup}{void} return the trivial group. \fun{GEN}{dicyclicgroup}{GEN g1, GEN g2, long s1, long s2} returns the group with generators \var{g1}, \var{g2} with respecting relative orders \var{s1}, \var{s2}. \fun{GEN}{abelian_group}{GEN v} let v be a \typ{VECSMALL} seen as the SNF of a small abelian group, return its regular representation. \fun{long}{group_domain}{GEN grp} returns the \kbd{domain} of the \emph{non-trivial} small group \var{grp}. Return an error if \var{grp} is trivial. \fun{GEN}{group_elts}{GEN grp, long n} returns the list of elements of the small group \var{grp} of domain \var{n} as permutations. \fun{GEN}{group_set}{GEN grp, long n} returns a \var{F2v} $b$ such that $b[i]$ is set if and only if the small group \var{grp} of domain \var{n} contains a permutation sending $1$ to $i$. \fun{GEN}{groupelts_set}{GEN elts, long n}, where \var{elts} is the list of elements of a small group of domain \var{n}, returns a \var{F2v} $b$ such that $b[i]$ is set if and only if the small group contains a permutation sending $1$ to $i$. \fun{GEN}{groupelts_conjclasses}{GEN elts, long *pn}, where \var{elts} is the list of elements of a small group (sorted with respect to \kbd{vecsmall\_lexcmp}), return a \typ{VECSMALL} \kbd{conj} of the same length such that \kbd{conj[i]} is the index in $\{1,\cdots,n\}$ of the conjugacy class of \kbd{elts[i]} for some unspecified but deterministic ordering of the classes, where $n$ is the number of conjugacy classes. If \kbd{pn} is non \kbd{NULL}, \kbd{*pn} is set to $n$. \fun{GEN}{conjclasses_repr}{GEN conj, long nb}, where \kbd{conj} and \kbd{nb} are as returned by the call \kbd{groupelts\_conjclasses(elts)}, return \typ{VECSMALL} of length \kbd{nb} which gives the indices in \kbd{elts} of a representative of each conjugacy class. \fun{GEN}{group_to_cc}{GEN G}, where $G$ is a small group or a Galois group, returns a \kbd{cc} (conjclasses) structure \kbd{[elts,conj,rep,flag]}, as obtained by \kbd{alggroupcenter}, where \kbd{conj} is \kbd{groupelts\_conjclasses}$(\kbd{elts})$ and \kbd{rep} is the attached \kbd{conjclasses\_repr}. \kbd{flag} is 1 if the permutation representation is transitive (in which case an element $g$ of $G$ is characterized by $g[1]$), and 0 otherwise. Shallow function. \fun{long}{group_order}{GEN grp} returns the order of the small group \var{grp} (which is the product of the relative orders). \fun{long}{group_isabelian}{GEN grp} returns $1$ if the small group \var{grp} is Abelian, else $0$. \fun{GEN}{group_abelianHNF}{GEN grp, GEN elts} if \var{grp} is not Abelian, returns \kbd{NULL}, else returns the HNF matrix of \var{grp} with respect to the generating family $\var{grp}[1]$. If \var{elts} is no \kbd{NULL}, it must be the list of elements of \var{grp}. \fun{GEN}{group_abelianSNF}{GEN grp, GEN elts} if \var{grp} is not Abelian, returns \kbd{NULL}, else returns its cyclic decomposition. If \var{elts} is no \kbd{NULL}, it must be the list of elements of \var{grp}. \fun{long}{group_subgroup_isnormal}{GEN G, GEN H}, $H$ being a subgroup of the small group $G$, returns $1$ if $H$ is normal in $G$, else $0$. \fun{long}{group_isA4S4}{GEN grp} returns $1$ if the small group \var{grp} is isomorphic to $A_4$, $2$ if it is isomorphic to $S_4$ and $0$ else. This is mainly to deal with the idiosyncrasy of the format. \fun{GEN}{group_leftcoset}{GEN G, GEN g} where $G$ is a small group and $g$ a permutation of the same domain, the left coset $gG$ as a vector of permutations. \fun{GEN}{group_rightcoset}{GEN G, GEN g} where $G$ is a small group and $g$ a permutation of the same domain, the right coset $Gg$ as a vector of permutations. \fun{long}{group_perm_normalize}{GEN G, GEN g} where $G$ is a small group and $g$ a permutation of the same domain, return $1$ if $gGg^{-1}=G$, else $0$. \fun{GEN}{group_quotient}{GEN G, GEN H}, where $G$ is a small group and $H$ is a subgroup of $G$, returns the quotient map $G\rightarrow G/H$ as an abstract data structure. \fun{GEN}{quotient_perm}{GEN C, GEN g} where $C$ is the quotient map $G\rightarrow G/H$ for some subgroup $H$ of $G$ and $g$ an element of $G$, return the image of $g$ by $C$ (i.e. the coset $gH$). \fun{GEN}{quotient_group}{GEN C, GEN G} where $C$ is the quotient map $G\rightarrow G/H$ for some \emph{normal} subgroup $H$ of $G$, return the quotient group $G/H$ as a small group. \fun{GEN}{quotient_subgroup_lift}{GEN C, GEN H, GEN S} where $C$ is the quotient map $G\rightarrow G/H$ for some group $G$ normalizing $H$ and $S$ is a subgroup of $G/H$, return the inverse image of $S$ by $C$. \fun{GEN}{group_subgroups}{GEN grp} returns the list of subgroups of the small group \var{grp} as a \typ{VEC}. \fun{GEN}{subgroups_tableset}{GEN S, long n} where $S$ is a vector of subgroups of domain $n$, returns a table which matchs the set of elements of the subgroups against the index of the subgroups. \fun{long}{tableset_find_index}{GEN tbl, GEN set} searchs the set \kbd{set} in the table \kbd{tbl} and returns its attached index, or $0$ if not found. \fun{GEN}{groupelts_abelian_group}{GEN elts} where \var{elts} is the list of elements of an \emph{Abelian} small group, returns the corresponding small group. \fun{long}{groupelts_exponent}{GEN elts} where \var{elts} is the list of elements of a small group, returns the exponent the group (the LCM of the order of the elements of the group). \fun{GEN}{groupelts_center}{GEN elts} where \var{elts} is the list of elements of a small group, returns the list of elements of the center of the group. \fun{GEN}{group_export}{GEN grp, long format} convert a small group to another format, as a \typ{STR} describing the group for the given syntax, see \tet{galoisexport}. \fun{GEN}{group_export_GAP}{GEN G} export a small group to GAP format. \fun{GEN}{group_export_MAGMA}{GEN G} export a small group to MAGMA format. \fun{long}{group_ident}{GEN grp, GEN elts} returns the index of the small group \var{grp} in the GAP4 Small Group library, see \tet{galoisidentify}. If \var{elts} is not \kbd{NULL}, it must be the list of elements of \var{grp}. \fun{long}{group_ident_trans}{GEN grp, GEN elts} returns the index of the regular representation of the small group \var{grp} in the GAP4 Transitive Group library, see \tet{polgalois}. If \var{elts} is no \kbd{NULL}, it must be the list of elements of \var{grp}. \newpage \chapter{Standard data structures} \section{Character strings} \subsec{Functions returning a \kbd{char *}} \fun{char*}{pari_strdup}{const char *s} returns a malloc'ed copy of $s$ (uses \kbd{pari\_malloc}). \fun{char*}{pari_strndup}{const char *s, long n} returns a malloc'ed copy of at most $n$ chars from $s$ (uses \kbd{pari\_malloc}). If $s$ is longer than $n$, only $n$ characters are copied and a terminal null byte is added. \fun{char*}{stack_strdup}{const char *s} returns a copy of $s$, allocated on the PARI stack (uses \kbd{stack\_malloc}). \fun{char*}{stack_strcat}{const char *s, const char *t} returns the concatenation of $s$ and $t$, allocated on the PARI stack (uses \kbd{stack\_malloc}). \fun{char*}{stack_sprintf}{const char *fmt, ...} runs \kbd{pari\_sprintf} on the given arguments, returning a string allocated on the PARI stack. \fun{char*}{uordinal}{ulong x} return the ordinal number attached to $x$ (i.e. $1$st, $2$nd, etc.) as a \tet{stack_malloc}'ed string. \fun{char*}{itostr}{GEN x} writes the \typ{INT} $x$ to a \tet{stack_malloc}'ed string. \fun{char*}{GENtostr}{GEN x}, using the current default output format (\kbd{GP\_DATA->fmt}, which contains the output style and the number of significant digits to print), converts $x$ to a malloc'ed string. Simple variant of \tet{pari_sprintf}. \fun{char*}{GENtostr_raw}{GEN x} as \tet{GENtostr} with the following differences: 1) the output format is \tet{f_RAW}; 2) the result is allocated on the stack and \emph{must not} be freed. \fun{char*}{GENtostr_unquoted}{GEN x} as \tet{GENtostr_raw} with the following additional difference: a \typ{STR} $x$ is printed without enclosing quotes (to be used by \kbd{print}. \fun{char*}{GENtoTeXstr}{GEN x}, as \kbd{GENtostr}, except that \tet{f_TEX} overrides the output format from \kbd{GP\_DATA->fmt}. \fun{char*}{RgV_to_str}{GEN g, long flag} $g$ being a vector of \kbd{GEN}s, returns a malloc'ed string, the concatenation of the \kbd{GENtostr} applied to its elements, except that \typ{STR} are printed without enclosing quotes. \kbd{flag} determines the output format: \tet{f_RAW}, \tet{f_PRETTYMAT} or \tet{f_TEX}. \subsec{Functions returning a \typ{STR}} \fun{GEN}{strtoGENstr}{const char *s} returns a \typ{STR} with content $s$. \fun{GEN}{strntoGENstr}{const char *s, long n} returns a \typ{STR} containing the first $n$ characters of $s$. \fun{GEN}{chartoGENstr}{char c} returns a \typ{STR} containing the character $c$. \fun{GEN}{GENtoGENstr}{GEN x} returns a \typ{STR} containing the printed form of $x$ (in \tet{raw} format). This is often easier to use that \tet{GENtostr} (which returns a malloc-ed \kbd{char*}) since there is no need to free the string after use. \fun{GEN}{GENtoGENstr_nospace}{GEN x} as \kbd{GENtoGENstr}, removing all spaces from the output. \fun{GEN}{Str}{GEN g} as \tet{RgV_to_str} with output format \tet{f_RAW}, but returns a \typ{STR}, not a malloc'ed string. \fun{GEN}{Strtex}{GEN g} as \tet{RgV_to_str} with output format \tet{f_TEX}, but returns a \typ{STR}, not a malloc'ed string. \fun{GEN}{Strexpand}{GEN g} as \tet{RgV_to_str} with output format \tet{f_RAW}, performing tilde and environment expansion on the result. Returns a \typ{STR}, not a malloc'ed string. \fun{GEN}{gsprintf}{const char *fmt, ...} equivalent to \kbd{pari\_sprintf(fmt,...}, followed by \tet{strtoGENstr}. Returns a \typ{STR}, not a malloc'ed string. \fun{GEN}{gvsprintf}{const char *fmt, va_list ap} variadic version of \tet{gsprintf} \subsec{Dynamic strings} A \tet{pari_str} is a dynamic string which grows dynamically as needed. This structure contains private data and two public members \kbd{char *string}, which is the string itself and \kbd{use\_stack} which tells whether the string lives \item on the PARI stack (value $1$), meaning that it will be destroyed by any manipulation of the stack, e.g. a \kbd{gerepile} call or resetting \kbd{avma}; \item in malloc'ed memory (value $0$), in which case it is impervious to stack manipulation but will need to be explicitly freed by the user after use, via \kbd{pari\_free(s.string)}. \fun{void}{str_init}{pari_str *S, int use_stack} initializes a dynamic string; if \kbd{use\_stack} is 0, then the string is malloc'ed, else it lives on the PARI stack. \fun{void}{str_printf}{pari_str *S, const char *fmt, ...} write to the end of $S$ the remaining arguments according to PARI format \kbd{fmt}. \fun{void}{str_putc}{pari_str *S, char c} write the character $c$ to the end of $S$. \fun{void}{str_puts}{pari_str *S, const char *s} write the string $s$ to the end of $S$. \section{Output} \subsec{Output contexts} An output coutext, of type \tet{PariOUT}, is a \kbd{struct} that models a stream and contains the following function pointers: \bprog void (*putch)(char); /* fputc()-alike */ void (*puts)(const char*); /* fputs()-alike */ void (*flush)(void); /* fflush()-alike */ @eprog\noindent The methods \tet{putch} and \tet{puts} are used to print a character or a string respectively. The method \tet{flush} is called to finalize a messages. The generic functions \tet{pari_putc}, \tet{pari_puts}, \tet{pari_flush} and \tet{pari_printf} print according to a \emph{default output context}, which should be sufficient for most purposes. Lower level functions are available, which take an explicit output context as first argument: \fun{void}{out_putc}{PariOUT *out, char c} essentially equivalent to \kbd{out->putc(c)}. In addition, registers whether the last character printed was a \kbd{\bs n}. \fun{void}{out_puts}{PariOUT *out, const char *s} essentially equivalent to \kbd{out->puts(s)}. In addition, registers whether the last character printed was a \kbd{\bs n}. \fun{void}{out_printf}{PariOUT *out, const char *fmt, ...} \fun{void}{out_vprintf}{PariOUT *out, const char *fmt, va_list ap} \noindent N.B. The function \kbd{out\_flush} does not exist since it would be identical to \kbd{out->flush()} \fun{int}{pari_last_was_newline}{void} returns a non-zero value if the last character printed via \tet{out_putc} or \tet{out_puts} was \kbd{\bs n}, and $0$ otherwise. \fun{void}{pari_set_last_newline}{int last} sets the boolean value to be returned by the function \tet{pari_last_was_newline} to \var{last}. \subsec{Default output context} They are defined by the global variables \tet{pariOut} and \tet{pariErr} for normal outputs and warnings/errors, and you probably do not want to change them. If you \emph{do} change them, diverting output in non-trivial ways, this probably means that you are rewriting \kbd{gp}. For completeness, we document in this section what the default output contexts do. \misctitle{pariOut} writes output to the \kbd{FILE*} \tet{pari_outfile}, initialized to \tet{stdout}. The low-level methods are actually the standard \kbd{putc} / \kbd{fputs}, plus some magic to handle a log file if one is open. \misctitle{pariErr} prints to the \kbd{FILE*} \tet{pari_errfile}, initialized to \tet{stderr}. The low-level methods are as above. You can stick with the default \kbd{pariOut} output context and change PARI's standard output, redirecting \tet{pari_outfile} to another file, using \fun{void}{switchout}{const char *name} where \kbd{name} is a character string giving the name of the file you want to write to; the output is \emph{appended} at the end of the file. To close the file and revert to outputting to \kbd{stdout}, call \kbd{switchout(NULL)}. \subsec{PARI colors} In this section we describe the low-level functions used to implement GP's color scheme, attached to the \tet{colors} default. The following symbolic names are attached to gp's output strings: \item \tet{c_ERR} an error message \item \tet{c_HIST} a history number (as in \kbd{\%1 = ...}) \item \tet{c_PROMPT} a prompt \item \tet{c_INPUT} an input line (minus the prompt part) \item \tet{c_OUTPUT} an output \item \tet{c_HELP} a help message \item \tet{c_TIME} a timer \item \tet{c_NONE} everything else \emph{If} the \tet{colors} default is set to a non-empty value, before gp outputs a string, it first outputs an ANSI colors escape sequence --- understood by most terminals ---, according to the \kbd{colors} specifications. As long as this is in effect, the following strings are rendered in color, possibly in bold or underlined. \fun{void}{term_color}{long c} prints (as if using \tet{pari_puts}) the ANSI color escape sequence attached to output object \kbd{c}. If \kbd{c} is \tet{c_NONE}, revert to default printing style. \fun{void}{out_term_color}{PariOUT *out, long c} as \tet{term_color}, using output context \kbd{out}. \fun{char*}{term_get_color}{char *s, long c} returns as a character string the ANSI color escape sequence attached to output object \kbd{c}. If \kbd{c} is \tet{c_NONE}, the value used to revert to default printing style is returned. The argument \kbd{s} is either \kbd{NULL} (string allocated on the PARI stack), or preallocated storage (in which case, it must be able to hold at least 16 chars, including the final \kbd{\bs 0}). \subsec{Obsolete output functions} These variants of \fun{void}{output}{GEN x}, which prints \kbd{x}, followed by a newline and a buffer flush are complicated to use and less flexible than what we saw above, or than the \tet{pari_printf} variants. They are provided for backward compatibility and are scheduled to disappear. \fun{void}{brute}{GEN x, char format, long dec} \fun{void}{matbrute}{GEN x, char format, long dec} \fun{void}{texe}{GEN x, char format, long dec} \section{Files} The following routines are trivial wrappers around system functions (possibly around one of several functions depending on availability). They are usually integrated within PARI's diagnostics system, printing messages if \kbd{DEBUGFILES} is high enough. \fun{int}{pari_is_dir}{const char *name} returns $1$ if \kbd{name} points to a directory, $0$ otherwise. \fun{int}{pari_is_file}{const char *name} returns $1$ if \kbd{name} points to a directory, $0$ otherwise. \fun{int}{file_is_binary}{FILE *f} returns $1$ if the file $f$ is a binary file (in the \tet{writebin} sense), $0$ otherwise. \fun{void}{pari_unlink}{const char *s} deletes the file named $s$. Warn if the operation fails. \fun{void}{pari_fread_chars}{void *b, size_t n, FILE *f} read $n$ chars from stream $f$, storing the result in pre-allocated buffer $b$ (assumed to be large enough). \fun{char*}{path_expand}{const char *s} perform tilde and environment expansion on $s$. Returns a \kbd{malloc}'ed buffer. \fun{void}{strftime_expand}{const char *s, char *buf, long max} perform time expansion on $s$, storing the result (at most \kbd{max} chars) in buffer \kbd{buf}. Trivial wrapper around \bprog time_t t = time(NULL); strftime(but, max, s, localtime(&t); @eprog \fun{char*}{pari_get_homedir}{const char *user} expands \kbd{\til user} constructs, returning the home directory of user \kbd{user}, or \kbd{NULL} if it could not be determined (in particular if the operating system has no such concept). The return value may point to static area and may be overwritten by subsequent system calls: use immediately or \kbd{strdup} it. \fun{int}{pari_stdin_isatty}{void} returns $1$ if our standard input \kbd{stdin} is attached to a terminal. Trivial wrapper around \kbd{isatty}. \subsec{pariFILE} PARI maintains a linked list of open files, to reclaim resources (file descriptors) on error or interrupts. The corresponding data structure is a \kbd{pariFILE}, which is a wrapper around a standard \kbd{FILE*}, containing further the file name, its type (regular file, pipe, input or output file, etc.). The following functions create and manipulate this structure; they are integrated within PARI's diagnostics system, printing messages if \kbd{DEBUGFILES} is high enough. \fun{pariFILE*}{pari_fopen}{const char *s, const char *mode} wrapper around \kbd{fopen(s, mode)}, return \kbd{NULL} on failure. \fun{pariFILE*}{pari_fopen_or_fail}{const char *s, const char *mode} simple wrapper around \kbd{fopen(s, mode)}; error on failure. \fun{pariFILE*}{pari_fopengz}{const char *s} opens the file whose name is $s$, and associates a (read-only) \kbd{pariFILE} with it. If $s$ is a compressed file (\kbd{.gz} suffix), it is uncompressed on the fly. If $s$ cannot be opened, also try to open \kbd{$s$.gz}. Returns \kbd{NULL} on failure. \fun{void}{pari_fclose}{pariFILE *f} closes the underlying file descriptor and deletes the \kbd{pariFILE} struct. \fun{pariFILE*}{pari_safefopen}{const char *s, const char *mode} creates a \emph{new} file $s$ (a priori for writing) with \kbd{600} permissions. Error if the file already exists. To avoid symlink attacks, a symbolic link exists, regardless of where it points to. \subsec{Temporary files} PARI has its own idea of the system temp directory derived from an environment variable (\kbd{\$GPTMPDIR}, else \kbd{\$TMPDIR}), or the first writable directory among \kbd{/tmp}, \kbd{/var/tmp} and \kbd{.}. \fun{char*}{pari_unique_dir}{const char *s} creates a ``unique directory'' and return its name built from the string $s$, the user id and process pid (on Unix systems). This directory is itself located in the temp directory mentioned above. The name returned is \tet{malloc}'ed. \fun{char*}{pari_unique_filename}{const char *s} creates a \emph{new} empty file in the temp directory, whose name contains the id-string $s$ (truncated to its first $8$ chars), followed by a system-dependent suffix (incorporating the ids of both the user and the running process, for instance). The function returns the tempfile name and creates an empty file with that name. The name returned is \tet{malloc}'ed. \fun{char*}{pari_unique_filename_suffix}{const char *s, const char *suf} analogous to above \tet{pari_unique_filename}, creating a (previously non-existent) tempfile whose name ends with suffix \kbd{suf}. \section{Errors}\label{se:errors} This section documents the various error classes, and the corresponding arguments to \tet{pari_err}. The general syntax is \fun{void}{pari_err}{numerr,...} \noindent In the sequel, we mostly use sequences of arguments of the form \bprog const char *s const char *fmt, ... @eprog\noindent where \kbd{fmt} is a PARI format, producing a string $s$ from the remaining arguments. Since providing the correct arguments to \tet{pari_err} is quite error-prone, we also provide specialized routines \kbd{pari\_err\_\var{ERRORCLASS}(\dots)} instead of \kbd{pari\_err(e\_\var{ERRORCLASS}, \dots)} so that the C compiler can check their arguments. \noindent We now inspect the list of valid keywords (error classes) for \kbd{numerr}, and the corresponding required arguments. \subsec{Internal errors, ``system'' errors} \subsubsec{e\_ARCH} A requested feature $s$ is not available on this architecture or operating system. \bprog pari_err(e_ARCH) @eprog\noindent prints the error message: \kbd{sorry, '$s$' not available on this system}. \subsubsec{e\_BUG} A bug in the PARI library, in function $s$. \bprog pari_err(e_BUG, const char *s) pari_err_BUG(const char *s) @eprog\noindent prints the error message: \kbd{Bug in $s$, please report}. \subsubsec{e\_FILE} Error while trying to open a file. \bprog pari_err(e_FILE, const char *what, const char *name) pari_err_FILE(const char *what, const char *name) @eprog\noindent prints the error message: \kbd{error opening \emph{what}: `\emph{name}'}. \subsubsec{e\_FILEDESC} Error while handling a file descriptor. \bprog pari_err(e_FILEDESC, const char *where, long n) pari_err_FILEDESC(const char *where, long n) @eprog\noindent prints the error message: \kbd{invalid file descriptor in \emph{where}: `\emph{name}'}. \subsubsec{e\_IMPL} A requested feature $s$ is not implemented. \bprog pari_err(e_IMPL, const char *s) pari_err_IMPL(const char *s) @eprog\noindent prints the error message: \kbd{sorry, $s$ is not yet implemented}. \subsubsec{e\_PACKAGE} Missing optional package $s$. \bprog pari_err(e_PACKAGE, const char *s) pari_err_PACKAGE(const char *s) @eprog\noindent prints the error message: \kbd{package $s$ is required, please install it} \subsec{Syntax errors, type errors} \subsubsec{e\_DIM} arguments submitted to function $s$ have inconsistent dimensions. E.g., when solving a linear system, or trying to compute the determinant of a non-square matrix. \bprog pari_err(e_DIM, const char *s) pari_err_DIM(const char *s) @eprog\noindent prints the error message: \kbd{inconsistent dimensions in $s$}. \subsubsec{e\_FLAG} A flag argument is out of bounds in function $s$. \bprog pari_err(e_FLAG, const char *s) pari_err_FLAG(const char *s) @eprog\noindent prints the error message: \kbd{invalid flag in $s$}. \subsubsec{e\_NOTFUNC} Generated by the PARI evaluator; tried to use a \kbd{GEN} which is not a \typ{CLOSURE} in a function call syntax (as in \kbd{f = 1; f(2);}). \bprog pari_err(e_NOTFUNC, GEN fun) @eprog\noindent prints the error message: \kbd{not a function in a function call}. \subsubsec{e\_OP} Impossible operation between two objects than cannot be typecast to a sensible common domain for deeper reasons than a type mismatch, usually for arithmetic reasons. As in \kbd{O(2) + O(3)}: it is valid to add two \typ{PADIC}s, provided the underlying prime is the same; so the addition is not forbidden a priori for type reasons, it only becomes so when inspecting the objects and trying to perform the operation. \bprog pari_err(e_OP, const char *op, GEN x, GEN y) pari_err_OP(const char *op, GEN x, GEN y) @eprog\noindent As \kbd{e\_TYPE2}, replacing \kbd{forbidden} by \kbd{inconsistent}. \subsubsec{e\_PRIORITY} object $o$ in function $s$ contains variables whose priority is incompatible with the expected operation. E.g.~\kbd{Pol([x,1], 'y)}: this raises an error because it's not possible to create a polynomial whose coefficients involve variables with higher priority than the main variable. \bprog pari_err(e_PRIORITY, const char *s, GEN o, const char *op, long v) pari_err_PRIORITY(const char *s, GEN o, const char *op, long v) @eprog\noindent prints the error message: \kbd{incorrect priority in $s$, variable $v_o$ \var{op} $v$}, were $v_o$ is \kbd{gvar(o)}. \subsubsec{e\_SYNTAX} Syntax error, generated by the PARI parser. \bprog pari_err(e_SYNTAX, const char *msg, const char *e, const char *entry) @eprog\noindent where \kbd{msg} is a complete error message, and \kbd{e} and \kbd{entry} point into the \emph{same} character string, which is the input that was incorrectly parsed: \kbd{e} points to the character where the parser failed, and $\kbd{entry}\leq \kbd{e}$ points somewhat before. \noindent Prints the error message: \kbd{msg}, followed by a colon, then a part of the input character string (in general \kbd{entry} itself, but an initial segment may be truncated if $\kbd{e}-\kbd{entry}$ is large); a caret points at \kbd{e}, indicating where the error took place. \subsubsec{e\_TYPE} An argument $x$ of function $s$ had an unexpected type. (As in \kbd{factor("blah")}.) \bprog pari_err(e_TYPE, const char *s, GEN x) pari_err_TYPE(const char *s, GEN x) @eprog\noindent prints the error message: \kbd{incorrect type in $s$ (\typ{$x$})}, where \typ{$x$} is the type of $x$. \subsubsec{e\_TYPE2} Forbidden operation between two objects than cannot be typecast to a sensible common domain, because their types do not match up. (As in \kbd{Mod(1,2) + Pi}.) \bprog pari_err(e_TYPE2, const char *op, GEN x, GEN y) pari_err_TYPE2(const char *op, GEN x, GEN y) @eprog\noindent prints the error message: \kbd{forbidden} $s$ \typ{$x$} \var{op} \typ{$y$}, where \typ{$z$} denotes the type of $z$. Here, $s$ denotes the spelled out name of the operator $\var{op}\in\{\kbd{+}, \kbd{*}, \kbd{/}, \kbd{\%}, \kbd{=}\}$, e.g. \emph{addition} for \kbd{"+"} or \emph{assignment} for \kbd{"="}. If \var{op} is not in the above operator, list, it is taken to be the already spelled out name of a function, e.g. \kbd{"gcd"}, and the error message becomes \kbd{forbidden} \var{op} \typ{$x$}, \typ{$y$}. \subsubsec{e\_VAR} polynomials $x$ and $y$ submitted to function $s$ have inconsistent variables. E.g., considering the algebraic number \kbd{Mod(t,t\pow2+1)} in \kbd{nfinit(x\pow2+1)}. \bprog pari_err(e_VAR, const char *s, GEN x, GEN y) pari_err_VAR(const char *s, GEN x, GEN y) @eprog\noindent prints the error message: \kbd{inconsistent variables in $s$ $X$ != $Y$}, where $X$ and $Y$ are the names of the variables of $x$ and $y$, respectively. \subsec{Overflows} \subsubsec{e\_COMPONENT} Trying to access an inexistent component of a vector/matrix/list: the index is less than $1$ or greater than the allowed length. \bprog pari_err(e_COMPONENT, const char *f, const char *op, GEN lim, GEN x) pari_err_COMPONENT(const char *f, const char *op, GEN lim, GEN x) @eprog\noindent prints the error message: \kbd{non-existent component in $f$: index \var{op} \var{lim}}. Special case: if $f$ is the empty string (no meaningful public function name can be used), we ignore it and print the message: \kbd{non-existent component: index \var{op} \var{lim}}. \subsubsec{e\_DOMAIN} An argument $x$ is not in the function's domain (as in \kbd{moebius(0)} or \kbd{zeta(1)}). \bprog pari_err(e_DOMAIN, char *f, char *v, char *op, GEN lim, GEN x) pari_err_DOMAIN(char *f, char *v, char *op, GEN lim, GEN x) @eprog\noindent prints the error message: \kbd{domain error in $f$: $v$ \var{op} \var{lim}}. Special case: if \var{op} is the empty string, we ignore \var{lim} and print the error message: \kbd{domain error in $f$: $v$ out of range}. \subsubsec{e\_MAXPRIME} A function using the precomputed list of prime numbers ran out of primes. \bprog pari_err(e_MAXPRIME, ulong c) pari_err_MAXPRIME(ulong c) @eprog\noindent prints the error message: \kbd{not enough precomputed primes, need primelimit \til $c$} if $c$ is non-zero. And simply \kbd{not enough precomputed primes} otherwise. \subsubsec{e\_MEM} A call to \tet{pari_malloc} or \tet{pari_realloc} failed. \bprog pari_err(e_MEM) @eprog\noindent prints the error message: \kbd{not enough memory}. \subsubsec{e\_OVERFLOW} An object in function $s$ becomes too large to be represented within PARI's hardcoded limits. (As in \kbd{2\pow2\pow2\pow10} or \kbd{exp(1e100)}, which overflow in \kbd{lg} and \kbd{expo}.) \bprog pari_err(e_OVERFLOW, const char *s) pari_err_OVERFLOW(const char *s) @eprog\noindent prints the error message: \kbd{overflow in $s$}. \subsubsec{e\_PREC} Function $s$ fails because input accuracy is too low. (As in \kbd{floor(1e100)} at default accuracy.) \bprog pari_err(e_PREC, const char *s) pari_err_PREC(const char *s) @eprog\noindent prints the error message: \kbd{precision too low in $s$}. \subsubsec{e\_STACK} The PARI stack overflows. \bprog pari_err(e_STACK) @eprog\noindent prints the error message: \kbd{the PARI stack overflows !} as well as some statistics concerning stack usage. \subsec{Errors triggered intentionally} \subsubsec{e\_ALARM} A timeout, generated by the \tet{alarm} function. \bprog pari_err(e_ALARM, const char *fmt, ...) @eprog\noindent prints the error message: $s$. \subsubsec{e\_USER} A user error, as triggered by \tet{error}($g_1,\dots,g_n)$ in GP. \bprog pari_err(e_USER, GEN g) @eprog\noindent prints the error message: \kbd{user error:}, then the entries of the vector $g$. \subsec{Mathematical errors} \subsubsec{e\_CONSTPOL} An argument of function $s$ is a constant polynomial, which does not make sense. (As in \kbd{galoisinit(Pol(1))}.) \bprog pari_err(e_CONSTPOL, const char *s) pari_err_CONSTPOL(const char *s) @eprog\noindent prints the error message: \kbd{constant polynomial in $s$}. \subsubsec{e\_COPRIME} Function $s$ expected two coprime arguments, and did receive $x$, $y$ which were not. \bprog pari_err(e_COPRIME, const char *s, GEN x, GEN y) pari_err_COPRIME(const char *s, GEN x, GEN y) @eprog\noindent prints the error message: \kbd{elements not coprime in $s$: $x, y$}. \subsubsec{e\_INV} Tried to invert a non-invertible object $x$. \bprog pari_err(e_INV, const char *s, GEN x) pari_err_INV(const char *s, GEN x) @eprog\noindent prints the error message: \kbd{impossible inverse in $s$: $x$}. If $x = \kbd{Mod}(a,b)$ is a \typ{INTMOD} and $a$ is not $0$ mod $b$, this allows to factor the modulus, as \kbd{gcd}$(a,b)$ is a non-trivial divisor of $b$. \subsubsec{e\_IRREDPOL} Function $s$ expected an irreducible polynomial, and did not receive one. (As in \kbd{nfinit(x\pow2-1)}.) \bprog pari_err(e_IRREDPOL, const char *s, GEN x) pari_err_IRREDPOL(const char *s, GEN x) @eprog\noindent prints the error message: \kbd{not an irreducible polynomial in $s$: $x$}. \subsubsec{e\_MISC} Generic uncategorized error. \bprog pari_err(e_MISC, const char *fmt, ...) @eprog\noindent prints the error message: $s$. \subsubsec{e\_MODULUS} moduli $x$ and $y$ submitted to function $s$ are inconsistent. E.g., considering the algebraic number \kbd{Mod(t,t\pow2+1)} in \kbd{nfinit(t\pow3-2)}. \bprog pari_err(e_MODULUS, const char *s, GEN x, GEN y) pari_err_MODULUS(const char *s, GEN x, GEN y) @eprog\noindent prints the error message: \kbd{inconsistent moduli in $s$}, then the moduli. \subsubsec{e\_PRIME} Function $s$ expected a prime number, and did receive $p$, which was not. (As in \kbd{idealprimedec(nf, 4)}.) \bprog pari_err(e_PRIME, const char *s, GEN x) pari_err_PRIME(const char *s, GEN x) @eprog\noindent prints the error message: \kbd{not a prime in $s$: $x$}. \subsubsec{e\_ROOTS0} An argument of function $s$ is a zero polynomial, and we need to consider its roots. (As in \kbd{polroots(0)}.) \bprog pari_err(e_ROOTS0, const char *s) pari_err_ROOTS0(const char *s) @eprog\noindent prints the error message: \kbd{zero polynomial in $s$}. \subsubsec{e\_SQRTN} Tried to compute an $n$-th root of $x$, which does not exist, in function $s$. (As in \kbd{sqrt(Mod(-1,3))}.) \bprog pari_err(e_SQRTN, GEN x) pari_err_SQRTN(GEN x) @eprog\noindent prints the error message: \kbd{not an n-th power residue in $s$: $x$}. \subsec{Miscellaneous functions} \fun{long}{name_numerr}{const char *s} return the error number corresponding to an error name. E.g. \kbd{name\_numerr("e\_DIM")} returns \kbd{e\_DIM}. \fun{const char*}{numerr_name}{long errnum} returns the error name corresponding to an error number. E.g. \kbd{name\_numerr(e\_DIM)} returns \kbd{"e\_DIM"}. \fun{char*}{pari_err2str}{GEN err} returns the error message that would be printed on \typ{ERROR} \kbd{err}. The name is allocated on the PARI stack and must not be freed. \section{Hashtables} A \tet{hashtable}, or associative array, is a set of pairs $(k,v)$ of keys and values. PARI implements general extensible hashtables for fast data retrieval: when creating a table, we may either choose to use the PARI stack, or \kbd{malloc} so as to be stack-independent. A hashtable is implemented as a table of linked lists, each list containing all entries sharing the same hash value. The table length is a prime number, which roughly doubles as the table overflows by gaining new entries; both the current number of entries and the threshold before the table grows are stored in the table. Finally the table remembers the functions used to hash the entries's keys and to test for equality two entries hashed to the same value. An entry, or \tet{hashentry}, contains \item a key/value pair $(k,v)$, both of type \kbd{void*} for maximal flexibility, \item the hash value of the key, for the table hash function. This hash is mapped to a table index (by reduction modulo the table length), but it contains more information, and is used to bypass costly general equality tests if possible, \item a link pointer to the next entry sharing the same table cell. \bprog typedef struct { void *key, *val; ulong hash; /* hash(key) */ struct hashentry *next; } hashentry; typedef struct { ulong len; /* table length */ hashentry **table; /* the table */ ulong nb, maxnb; /* number of entries stored and max nb before enlarging */ ulong pindex; /* prime index */ ulong (*hash) (void *k); /* hash function */ int (*eq) (void *k1, void *k2); /* equality test */ int use_stack; /* use the PARI stack, resp. malloc */ } hashtable; @eprog\noindent \fun{hashtable*}{hash_create}{size, hash, eq, use_stack} \vskip -0.5em % switch to K&R style to avoid atrocious line break \bprog ulong size; ulong (*hash)(void*); int (*eq)(void*,void*); int use_stack; @eprog\noindent creates a hashtable with enough room to contain \kbd{size} entries. The functions \kbd{hash} and \kbd{eq} compute the hash value of keys and test keys for equality, respectively. If \kbd{use\_stack} is non zero, the resulting table will use the PARI stack; otherwise, we use \kbd{malloc}. \fun{hashtable*}{hash_create_ulong}{ulong size, long stack} special case when the keys are \kbd{ulongs} with ordinary equality test. \fun{hashtable*}{hash_create_str}{ulong size, long stack} special case when the keys are character strings with string equality test (and \tet{hash_str} hash function). \fun{void}{hash_init_GEN}{hashtable *h, ulong size, int (*eq)(GEN,GEN), use_stack} Initialize \kbd{h } for an hashtable with enough room to contain \kbd{size} entries of type \kbd{GEN}. The functions \kbd{eq} test keys for equality. If \kbd{use\_stack} is non zero, the resulting table will use the PARI stack; otherwise, we use \kbd{malloc}. The hash used is \kbd{hash\_GEN}. \fun{void}{hash_insert}{hashtable *h, void *k, void *v} inserts $(k,v)$ in hashtable $h$. No copy is made: $k$ and $v$ themselves are stored. The implementation does not prevent one to insert two entries with equal keys $k$, but which of the two is affected by later commands is undefined. \fun{void}{hash_insert2}{hashtable *h, void *k, void *v, ulong hash} as \kbd{hash\_insert}, assuming \kbd{h->hash(k)} is \kbd{hash}. \fun{void}{hash_insert_long}{hashtable *h, void *k, long v} as \kbd{hash\_insert} but \kbd{v} is a \kbd{long}. \fun{hashentry*}{hash_search}{hashtable *h, void *k} look for an entry with key $k$ in $h$. Return it if it one exists, and \kbd{NULL} if not. \fun{hashentry*}{hash_search2}{hashtable *h, void *k, ulong hash} as \kbd{hash\_search} assuming \kbd{h->hash(k)} is \kbd{hash}. \fun{int}{hash_haskey_long}{hashtable *h, void *k, long *v} returns $1$ if the key $k$ belongs to the hash and set $v$ to its value, otherwise returns 0. \fun{hashentry *}{hash_select}{hashtable *h, void *k, void *E, int (*select)(void *, hashentry *)} variant of \tet{hash_search}, useful when entries with identical keys are inserted: among the entries attached to key $k$, return one satisfying the selection criterion (such that \kbd{select(E,e)} is non-zero), or \kbd{NULL} if none exist. \fun{hashentry*}{hash_remove}{hashtable *h, void *k} deletes an entry $(k,v)$ with key $k$ from $h$ and return it. (Return \kbd{NULL} if none was found.) Only the linking structures are freed, memory attached to $k$ and $v$ is not reclaimed. \fun{hashentry*}{hash_remove_select}{hashtable *h, void *k, void *E, int(*select)(void*, hashentry *)} a variant of \tet{hash_remove}, useful when entries with identical keys are inserted: among the entries attached to key $k$, return one satisfying the selection criterion (such that \kbd{select(E,e)} is non-zero) and delete it, or \kbd{NULL} if none exist. Only the linking structures are freed, memory attached to $k$ and $v$ is not reclaimed. \fun{GEN}{hash_keys}{hashtable *h} return in a \typ{VECSMALL} the keys stored in hashtable $h$. \fun{GEN}{hash_values}{hashtable *h} return in a \typ{VECSMALL} the values stored in hashtable $h$. \fun{void}{hash_destroy}{hashtable *h} deletes the hashtable, by removing all entries. \fun{void}{hash_dbg}{hashtable *h} print statistics for hashtable $h$, allows to evaluate the attached hash function performance on actual data. Some interesting hash functions are available: \fun{ulong}{hash_str}{const char *s} \fun{ulong}{hash_str2}{const char *s} is the historical PARI string hashing function and seems to be generally inferior to \kbd{hash\_str}. \fun{ulong}{hash_GEN}{GEN x} \section{Dynamic arrays} A \teb{dynamic array} is a generic way to manage stacks of data that need to grow dynamically. It allocates memory using \kbd{pari\_malloc}, and is independent of the PARI stack; it even works before the \kbd{pari\_init} call. \subsec{Initialization} To create a stack of objects of type \kbd{foo}, we proceed as follows: \bprog foo *t_foo; pari_stack s_foo; pari_stack_init(&s_foo, sizeof(*t_foo), (void**)&t_foo); @eprog\noindent Think of \kbd{s\_foo} as the controlling interface, and \kbd{t\_foo} as the (dynamic) array tied to it. The value of \kbd{t\_foo} may be changed as you add more elements. \subsec{Adding elements} The following function pushes an element on the stack. \bprog /* access globals t_foo and s_foo */ void push_foo(foo x) { long n = pari_stack_new(&s_foo); t_foo[n] = x; } @eprog \subsec{Accessing elements} Elements are accessed naturally through the \kbd{t\_foo} pointer. For example this function swaps two elements: \bprog void swapfoo(long a, long b) { foo x; if (a > s_foo.n || b > s_foo.n) pari_err_BUG("swapfoo"); x = t_foo[a]; t_foo[a] = t_foo[b]; t_foo[b] = x; } @eprog \subsec{Stack of stacks} Changing the address of \kbd{t\_foo} is not supported in general. In particular \kbd{realloc()}'ed array of stacks and stack of stacks are not supported. \subsec{Public interface} Let \kbd{s} be a \kbd{pari\_stack} and \kbd{data} the data linked to it. The following public fields are defined: \item \kbd{s.alloc} is the number of elements allocated for \kbd{data}. \item \kbd{s.n} is the number of elements in the stack and \kbd{data[s.n-1]} is the topmost element of the stack. \kbd{s.n} can be changed as long as $0\leq\kbd{s.n}\leq\kbd{s.alloc}$ holds. \fun{void}{pari_stack_init}{pari_stack *s, size_t size, void **data} links \kbd{*s} to the data pointer \kbd{*data}, where \kbd{size} is the size of data element. The pointer \kbd{*data} is set to \kbd{NULL}, \kbd{s->n} and \kbd{s->alloc} are set to $0$: the array is empty. \fun{void}{pari_stack_alloc}{pari_stack *s, long nb} makes room for \kbd{nb} more elements, i.e.~makes sure that $\kbd{s.alloc}\geq\kbd{s.n} + \kbd{nb}$, possibly reallocating \kbd{data}. \fun{long}{pari_stack_new}{pari_stack *s} increases \kbd{s.n} by one unit, possibly reallocating \kbd{data}, and returns $\kbd{s.n}-1$. \misctitle{Caveat} The following construction is incorrect because \kbd{stack\_new} can change the value of \kbd{t\_foo}: \bprog t_foo[ pari_stack_new(&s_foo) ] = x; @eprog \fun{void}{pari_stack_delete}{pari_stack *s} frees \kbd{data} and resets the stack to the state immediately following \kbd{stack\_init} (\kbd{s->n} and \kbd{s->alloc} are set to $0$). \fun{void *}{pari_stack_pushp}{pari_stack *s, void *u} This function assumes that \kbd{*data} is of pointer type. Pushes the element \kbd{u} on the stack \kbd{s}. \fun{void **}{pari_stack_base}{pari_stack *s} returns the address of \kbd{data}, typecast to a \kbd{void **}. \section{Vectors and Matrices} \subsec{Access and extract} See~\secref{se:clean} and~\secref{se:unclean} for various useful constructors. Coefficients are accessed and set using \tet{gel}, \tet{gcoeff}, see~\secref{se:accessors}. There are many internal functions to extract or manipulate subvectors or submatrices but, like the accessors above, none of them are suitable for \tet{gerepileupto}. Worse, there are no type verification, nor bound checking, so use at your own risk. \fun{GEN}{shallowcopy}{GEN x} returns a \kbd{GEN} whose components are the components of $x$ (no copy is made). The result may now be used to compute in place without destroying $x$. This is essentially equivalent to \bprog GEN y = cgetg(lg(x), typ(x)); for (i = 1; i < lg(x); i++) y[i] = x[i]; return y; @eprog\noindent except that \typ{MAT} is treated specially since shallow copies of all columns are made. The function also works for non-recursive types, but is useless in that case since it makes a deep copy. If $x$ is known to be a \typ{MAT}, you may call \tet{RgM_shallowcopy} directly; if $x$ is known not to be a \typ{MAT}, you may call \tet{leafcopy} directly. \fun{GEN}{RgM_shallowcopy}{GEN x} returns \kbd{shallowcopy(x)}, where $x$ is a \typ{MAT}. \fun{GEN}{shallowtrans}{GEN x} returns the transpose of $x$, \emph{without} copying its components, i.~e.,~it returns a \kbd{GEN} whose components are (physically) the components of $x$. This is the internal function underlying \tet{gtrans}. \fun{GEN}{shallowconcat}{GEN x, GEN y} concatenate $x$ and $y$, \emph{without} copying components, i.~e.,~it returns a \kbd{GEN} whose components are (physically) the components of $x$ and $y$. \fun{GEN}{shallowconcat1}{GEN x} $x$ must be \typ{VEC} or \typ{LIST}, concatenate its elements from left to right. Shallow version of \kbd{gconcat1}. \fun{GEN}{shallowmatconcat}{GEN v} shallow version of \kbd{matconcat}. \fun{GEN}{shallowextract}{GEN x, GEN y} extract components of the vector or matrix $x$ according to the selection parameter $y$. This is the shallow analog of \kbd{extract0(x, y, NULL)}, see \tet{vecextract}. \kbdsidx{extract0} \fun{GEN}{shallowmatextract}{GEN M, GEN l1, GEN l2} extract components of the matrix $M$ according to the \typ{VECSMALL} $l1$ (list of lines indices) and $l2$ (list of columns indices). This is the shallow analog of \kbd{extract0(x, l1, l2)}, see \tet{vecextract}. \kbdsidx{extract0} \fun{GEN}{RgM_minor}{GEN A, long i, long j} given a square \typ{MAT} A, return the matrix with $i$-th row and $j$-th column removed. \fun{GEN}{vconcat}{GEN A, GEN B} concatenate vertically the two \typ{MAT} $A$ and $B$ of compatible dimensions. A \kbd{NULL} pointer is accepted for an empty matrix. See \tet{shallowconcat}. \fun{GEN}{matslice}{GEN A, long a, long b, long c, long d} returns the submatrix $A[a..b,c..d]$. Assume $a \leq b$ and $c \leq d$. \fun{GEN}{row}{GEN A, long i} return $A[i,]$, the $i$-th row of the \typ{MAT} $A$. \fun{GEN}{row_i}{GEN A, long i, long j1, long j2} return part of the $i$-th row of \typ{MAT}~$A$: $A[i,j_1]$, $A[i,j_1+1]\dots,A[i,j_2]$. Assume $j_1 \leq j_2$. \fun{GEN}{rowcopy}{GEN A, long i} return the row $A[i,]$ of the~\typ{MAT}~$A$. This function is memory clean and suitable for \kbd{gerepileupto}. See \kbd{row} for the shallow equivalent. \fun{GEN}{rowslice}{GEN A, long i1, long i2} return the \typ{MAT} formed by the $i_1$-th through $i_2$-th rows of \typ{MAT} $A$. Assume $i_1 \leq i_2$. \fun{GEN}{rowsplice}{GEN A, long i} return the \typ{MAT} formed from the coefficients of \typ{MAT} $A$ with $j$-th row removed. \fun{GEN}{rowpermute}{GEN A, GEN p}, $p$ being a \typ{VECSMALL} representing a list $[p_1,\dots,p_n]$ of rows of \typ{MAT} $A$, returns the matrix whose rows are $A[p_1,],\dots, A[p_n,]$. \fun{GEN}{rowslicepermute}{GEN A, GEN p, long x1, long x2}, short for \bprog rowslice(rowpermute(A,p), x1, x2) @eprog\noindent (more efficient). \fun{GEN}{vecslice}{GEN A, long j1, long j2}, return $A[j_1], \dots, A[j_2]$. If $A$ is a \typ{MAT}, these correspond to \emph{columns} of $A$. The object returned has the same type as $A$ (\typ{VEC}, \typ{COL} or \typ{MAT}). Assume $j_1 \leq j_2$. \fun{GEN}{vecsplice}{GEN A, long j} return $A$ with $j$-th entry removed (\typ{VEC}, \typ{COL}) or $j$-th column removed (\typ{MAT}). \fun{GEN}{vecreverse}{GEN A}. Returns a \kbd{GEN} which has the same type as $A$ (\typ{VEC}, \typ{COL} or \typ{MAT}), and whose components are the $A[n],\dots,A[1]$. If $A$ is a \typ{MAT}, these are the \emph{columns} of $A$. \fun{void}{vecreverse_inplace}{GEN A} as \kbd{vecreverse}, but reverse $A$ in place. \fun{GEN}{vecpermute}{GEN A, GEN p} $p$ is a \typ{VECSMALL} representing a list $[p_1,\dots,p_n]$ of indices. Returns a \kbd{GEN} which has the same type as $A$ (\typ{VEC}, \typ{COL} or \typ{MAT}), and whose components are $A[p_1],\dots,A[p_n]$. If $A$ is a \typ{MAT}, these are the \emph{columns} of $A$. \fun{GEN}{vecsmallpermute}{GEN A, GEN p} as \kbd{vecpermute} when \kbd{A} is a \typ{VECSMALL}. \fun{GEN}{vecslicepermute}{GEN A, GEN p, long y1, long y2} short for \bprog vecslice(vecpermute(A,p), y1, y2) @eprog\noindent (more efficient). \subsec{Componentwise operations} The following convenience routines automate trivial loops of the form \bprog for (i = 1; i < lg(a); i++) gel(v,i) = f(gel(a,i), gel(b,i)) @eprog\noindent for suitable $f$: \fun{GEN}{vecinv}{GEN a}. Given a vector $a$, returns the vector whose $i$-th component is \kbd{ginv}$(a[i])$. \fun{GEN}{vecmul}{GEN a, GEN b}. Given $a$ and $b$ two vectors of the same length, returns the vector whose $i$-th component is \kbd{gmul}$(a[i], b[i])$. \fun{GEN}{vecdiv}{GEN a, GEN b}. Given $a$ and $b$ two vectors of the same length, returns the vector whose $i$-th component is \kbd{gdiv}$(a[i], b[i])$. \fun{GEN}{vecpow}{GEN a, GEN n}. Given $n$ a \typ{INT}, returns the vector whose $i$-th component is $a[i]^n$. \fun{GEN}{vecmodii}{GEN a, GEN b}. Assuming $a$ and $b$ are two \kbd{ZV} of the same length, returns the vector whose $i$-th component is \kbd{modii}$(a[i], b[i])$. \fun{GEN}{vecmoduu}{GEN a, GEN b}. Assuming $a$ and $b$ are two \typ{VECSMALL} of the same length, returns the vector whose $i$-th component is $a[i]~\kbd{\%}~b[i]$. Note that \kbd{vecadd} or \kbd{vecsub} do not exist since \kbd{gadd} and \kbd{gsub} have the expected behavior. On the other hand, \kbd{ginv} does not accept vector types, hence \kbd{vecinv}. \subsec{Low-level vectors and columns functions} These functions handle \typ{VEC} as an abstract container type of \kbd{GEN}s. No specific meaning is attached to the content. They accept both \typ{VEC} and \typ{COL} as input, but \kbd{col} functions always return \typ{COL} and \kbd{vec} functions always return \typ{VEC}. \misctitle{Note} All the functions below are shallow. \fun{GEN}{const_col}{long n, GEN x} returns a \typ{COL} of \kbd{n} components equal to \kbd{x}. \fun{GEN}{const_vec}{long n, GEN x} returns a \typ{VEC} of \kbd{n} components equal to \kbd{x}. \fun{int}{vec_isconst}{GEN v} Returns 1 if all the components of \kbd{v} are equal, else returns 0. \fun{void}{vec_setconst}{GEN v, GEN x} $v$ a pre-existing vector. Set all its components to $x$. \fun{int}{vec_is1to1}{GEN v} Returns 1 if the components of \kbd{v} are pair-wise distinct, i.e. if $i\mapsto v[i]$ is a 1-to-1 mapping, else returns 0. \fun{GEN}{vec_append}{GEN V, GEN s} append \kbd{s} to the vector \kbd{V}. \fun{GEN}{vec_prepend}{GEN V, GEN s} prepend \kbd{s} to the vector \kbd{V}. \fun{GEN}{vec_shorten}{GEN v, long n} shortens the vector \kbd{v} to \kbd{n} components. \fun{GEN}{vec_lengthen}{GEN v, long n} lengthens the vector \kbd{v} to \kbd{n} components. The extra components are not initialized. \fun{GEN}{vec_insert}{GEN v, long n, GEN x} inserts $x$ at position $n$ in the vector $v$. \section{Vectors of small integers} \subsec{\typ{VECSMALL}} These functions handle \typ{VECSMALL} as an abstract container type of small signed integers. No specific meaning is attached to the content. \fun{GEN}{const_vecsmall}{long n, long c} returns a \typ{VECSMALL} of \kbd{n} components equal to \kbd{c}. \fun{GEN}{vec_to_vecsmall}{GEN z} identical to \kbd{ZV\_to\_zv(z)}. \fun{GEN}{vecsmall_to_vec}{GEN z} identical to \kbd{zv\_to\_ZV(z)}. \fun{GEN}{vecsmall_to_col}{GEN z} identical to \kbd{zv\_to\_ZC(z)}. \fun{GEN}{vecsmall_to_vec_inplace}{GEN z} apply \kbd{stoi} to all entries of $z$ and set its type to \typ{VEC}. \fun{GEN}{vecsmall_copy}{GEN x} makes a copy of \kbd{x} on the stack. \fun{GEN}{vecsmall_shorten}{GEN v, long n} shortens the \typ{VECSMALL} \kbd{v} to \kbd{n} components. \fun{GEN}{vecsmall_lengthen}{GEN v, long n} lengthens the \typ{VECSMALL} \kbd{v} to \kbd{n} components. The extra components are not initialized. \fun{GEN}{vecsmall_indexsort}{GEN x} performs an indirect sort of the components of the \typ{VECSMALL} \kbd{x} and return a permutation stored in a \typ{VECSMALL}. \fun{void}{vecsmall_sort}{GEN v} sorts the \typ{VECSMALL} \kbd{v} in place. \fun{void}{vecsmall_reverse}{GEN v} as \kbd{vecreverse} for a \typ{VECSMALL} \kbd{v}. \fun{long}{vecsmall_max}{GEN v} returns the maximum of the elements of \typ{VECSMALL} \kbd{v}, assumed non-empty. \fun{long}{vecsmall_indexmax}{GEN v} returns the index of the largest element of \typ{VECSMALL} \kbd{v}, assumed non-empty. \fun{long}{vecsmall_min}{GEN v} returns the minimum of the elements of \typ{VECSMALL} \kbd{v}, assumed non-empty. \fun{long}{vecsmall_indexmin}{GEN v} returns the index of the smallest element of \typ{VECSMALL} \kbd{v}, assumed non-empty. \fun{long}{vecsmall_isin}{GEN v, long x} returns the first index $i$ such that \kbd{v[$i$]} is equal to \kbd{x}. Naive search in linear time, does not assume that \kbd{v} is sorted. \fun{GEN}{vecsmall_uniq}{GEN v} given a \typ{VECSMALL} \kbd{v}, return the vector of unique occurrences. \fun{GEN}{vecsmall_uniq_sorted}{GEN v} same as \kbd{vecsmall\_uniq}, but assumes \kbd{v} sorted. \fun{long}{vecsmall_duplicate}{GEN v} given a \typ{VECSMALL} \kbd{v}, return $0$ if there is no duplicates, or the index of the first duplicate (\kbd{vecsmall\_duplicate([1,1])} returns $2$). \fun{long}{vecsmall_duplicate_sorted}{GEN v} same as \kbd{vecsmall\_duplicate}, but assume \kbd{v} sorted. \fun{int}{vecsmall_lexcmp}{GEN x, GEN y} compares two \typ{VECSMALL} lexically. \fun{int}{vecsmall_prefixcmp}{GEN x, GEN y} truncate the longest \typ{VECSMALL} to the length of the shortest and compares them lexicographically. \fun{GEN}{vecsmall_prepend}{GEN V, long s} prepend \kbd{s} to the \typ{VECSMALL} \kbd{V}. \fun{GEN}{vecsmall_append}{GEN V, long s} append \kbd{s} to the \typ{VECSMALL} \kbd{V}. \fun{GEN}{vecsmall_concat}{GEN u, GEN v} concat the \typ{VECSMALL} \kbd{u} and \kbd{v}. \fun{long}{vecsmall_coincidence}{GEN u, GEN v} returns the numbers of indices where \kbd{u} and \kbd{v} agree. \fun{long}{vecsmall_pack}{GEN v, long base, long mod} handles the \typ{VECSMALL} \kbd{v} as the digit of a number in base \kbd{base} and return this number modulo \kbd{mod}. This can be used as an hash function. \fun{GEN}{vecsmall_prod}{GEN v} given a \typ{VECSMALL} \kbd{v}, return the product of its entries. \subsec{Vectors of \typ{VECSMALL}} These functions manipulate vectors of \typ{VECSMALL} (vecvecsmall). \fun{GEN}{vecvecsmall_sort}{GEN x} sorts lexicographically the components of the vector \kbd{x}. \fun{GEN}{vecvecsmall_sort_uniq}{GEN x} sorts lexicographically the components of the vector \kbd{x}, removing duplicates entries. \fun{GEN}{vecvecsmall_indexsort}{GEN x} performs an indirect lexicographic sorting of the components of the vector \kbd{x} and return a permutation stored in a \typ{VECSMALL}. \fun{long}{vecvecsmall_search}{GEN x, GEN y, long flag} \kbd{x} being a sorted vecvecsmall and \kbd{y} a \typ{VECSMALL}, search \kbd{y} inside \kbd{x}. \kbd{flag} has the same meaning as for \kbd{setsearch}. \fun{GEN}{vecvecsmall_max}{GEN x} returns the largest entry in all $x[i]$, assumed non-empty. \newpage \chapter{Functions related to the GP interpreter} \section{Handling closures}\label{se:closure} \subsec{Functions to evaluate \typ{CLOSURE}} \fun{void}{closure_disassemble}{GEN C} print the \typ{CLOSURE} \kbd{C} in GP assembly format. \fun{GEN}{closure_callgenall}{GEN C, long n, ...} evaluate the \typ{CLOSURE} \kbd{C} with the \kbd{n} arguments (of type \kbd{GEN}) following \kbd{n} in the function call. Assumes \kbd{C} has arity $\geq \kbd{n}$. \fun{GEN}{closure_callgenvec}{GEN C, GEN args} evaluate the \typ{CLOSURE} \kbd{C} with the arguments supplied in the vector \kbd{args}. Assumes \kbd{C} has arity $\geq \kbd{lg(args)-1}$. \fun{GEN}{closure_callgenvecprec}{GEN C, GEN args, long prec} as \kbd{closure\_callgenvec} but set the precision locally to \kbd{prec}. \fun{GEN}{closure_callgen1}{GEN C, GEN x} evaluate the \typ{CLOSURE} \kbd{C} with argument \kbd{x}. Assumes \kbd{C} has arity $\geq 1$. \fun{GEN}{closure_callgen1prec}{GEN C, GEN x, long prec} as \kbd{closure\_callgen1}, but set the precision locally to \kbd{prec}. \fun{GEN}{closure_callgen2}{GEN C, GEN x, GEN y} evaluate the \typ{CLOSURE} \kbd{C} with argument \kbd{x}, \kbd{y}. Assumes \kbd{C} has arity $\geq 2$. \fun{void}{closure_callvoid1}{GEN C, GEN x} evaluate the \typ{CLOSURE} \kbd{C} with argument \kbd{x} and discard the result. Assumes \kbd{C} has arity $\geq 1$. The following technical functions are used to evaluate \emph{inline} closures and closures of arity 0. The control flow statements (break, next and return) will cause the evaluation of the closure to be interrupted; this is called below a \emph{flow change}. When that occurs, the functions below generally return \kbd{NULL}. The caller can then adopt three positions: \item raises an exception (\kbd{closure\_evalnobrk}). \item passes through (by returning NULL itself). \item handles the flow change. \fun{GEN}{closure_evalgen}{GEN code} evaluates a closure and returns the result, or \kbd{NULL} if a flow change occurred. \fun{GEN}{closure_evalnobrk}{GEN code} as \kbd{closure\_evalgen} but raise an exception if a flow change occurs. Meant for iterators where interrupting the closure is meaningless, e.g.~\kbd{intnum} or \kbd{sumnum}. \fun{void}{closure_evalvoid}{GEN code} evaluates a closure whose return value is ignored. The caller has to deal with eventual flow changes by calling \kbd{loop\_break}. The remaining functions below are for exceptional situations: \fun{GEN}{closure_evalres}{GEN code} evaluates a closure and returns the result. The difference with \kbd{closure\_evalgen} being that, if the flow end by a \kbd{return} statement, the result will be the returned value instead of \kbd{NULL}. Used by the main GP loop. \fun{GEN}{closure_evalbrk}{GEN code, long *status} as \kbd{closure\_evalres} but set \kbd{status} to a non-zero value if a flow change occurred. This variant is not stack clean. Used by the break loop. \fun{GEN}{closure_trapgen}{long numerr, GEN code} evaluates closure, while trapping error \kbd{numerr}. Return \kbd{(GEN)1L} if error trapped, and the result otherwise, or \kbd{NULL} if a flow change occurred. Used by trap. \subsec{Functions to handle control flow changes} \fun{long}{loop_break}{void} processes an eventual flow changes inside an iterator. If this function return $1$, the iterator should stop. \subsec{Functions to deal with lexical local variables}\label{se:pushlex} Function using the prototype code \kbd{`V'} need to manually create and delete a lexical variable for each code \kbd{`V'}, which will be given a number $-1, -2, \ldots$. \fun{void}{push_lex}{GEN a, GEN code} creates a new lexical variable whose initial value is $a$ on the top of the stack. This variable get the number $-1$, and the number of the other variables is decreased by one unit. When the first variable of a closure is created, the argument \kbd{code} must be the closure that references this lexical variable. The argument \kbd{code} must be \kbd{NULL} for all subsequent variables (if any). (The closure contains the debugging data for the variable). \fun{void}{pop_lex}{long n} deletes the $n$ topmost lexical variables, increasing the number of other variables by $n$. The argument $n$ must match the number of variables allocated through \kbd{push\_lex}. \fun{GEN}{get_lex}{long vn} get the value of the variable with number \kbd{vn}. \fun{void}{set_lex}{long vn, GEN x} set the value of the variable with number \kbd{vn}. \subsec{Functions returning new closures} \fun{GEN}{compile_str}{const char *s} returns the closure corresponding to the GP expression $s$. \fun{GEN}{closure_deriv}{GEN code} returns a closure corresponding to the numerical derivative of the closure \kbd{code}. \fun{GEN}{snm_closure}{entree *ep, GEN data} Let \kbd{data} be a vector of length $m$, \kbd{ep} be an \kbd{entree} pointing to a C function $f$ of arity $n+m$, returns a \typ{CLOSURE} object $g$ of arity $n$ such that $g(x_1,\ldots,x_n)=f(x_1,\ldots,x_n,gel(data,1),...,gel(data,m))$. If \kbd{data} is \kbd{NULL}, then $m=0$ is assumed. This function has a low overhead since it does not copy \kbd{data}. \fun{GEN}{strtofunction}{char *str} returns a closure corresponding to the built-in or install'ed function named \kbd{str}. \fun{GEN}{strtoclosure}{char *str, long n, ...} returns a closure corresponding to the built-in or install'ed function named \kbd{str} with the $n$ last parameters set to the $n$ \kbd{GEN}s following $n$, see \tet{snm_closure}. This function has an higher overhead since it copies the parameters and does more input validation. In the example code below, \kbd{agm1} is set to the function \kbd{x->agm(x,1)} and \kbd{res} is set to \kbd{agm(2,1)}. \bprog GEN agm1 = strtoclosure("agm",1, gen_1); GEN res = closure_callgen1(agm1, gen_2); @eprog \subsec{Functions used by the gp debugger (break loop)} \fun{long}{closure_context}{long s} restores the compilation context starting at frame \kbd{s+1}, and returns the index of the topmost frame. This allow to compile expressions in the topmost lexical scope. \fun{void}{closure_err}{long level} prints a backtrace of the last $20$ stack frames, starting at frame \kbd{level}, the numbering starting at $0$. \subsec{Standard wrappers for iterators} Two families of standard wrappers are provided to interface iterators like \kbd{intnum} or \kbd{sumnum} with GP. \subsubsec{Standard wrappers for inline closures} These wrappers are used to implement GP functions taking inline closures as input. The object \kbd{(GEN)E} must be an inline closure which is evaluated with the lexical variable number $-1$ set to $x$. \fun{GEN}{gp_eval}{void *E, GEN x} is used for the prototype code \kbd{`E'}. \fun{GEN}{gp_evalprec}{void *E, GEN x, long prec} as \kbd{gp\_eval}, but set the precision locally to \kbd{prec}. \fun{long}{gp_evalvoid}{void *E, GEN x} is used for the prototype code \kbd{`I'}. The resulting value is discarded. Return a non-zero value if a control-flow instruction request the iterator to terminate immediately. \fun{long}{gp_evalbool}{void *E, GEN x} returns the boolean \kbd{gp\_eval(E, x)} evaluates to (i.e. true iff the value is non-zero). \fun{GEN}{gp_evalupto}{void *E, GEN x} memory-safe version of \kbd{gp\_eval}, \kbd{gcopy}-ing the result, when the evaluator returns components of previously allocated objects (e.g. member functions). \subsubsec{Standard wrappers for true closures} These wrappers are used to implement GP functions taking true closures as input. \fun{GEN}{gp_call}{void *E, GEN x} evaluates the closure \kbd{(GEN)E} on $x$. \fun{GEN}{gp_callprec}{void *E, GEN x, long prec} as \kbd{gp\_call}, but set the precision locally to \kbd{prec}. \fun{GEN}{gp_call2}{void *E, GEN x, GEN y} evaluates the closure \kbd{(GEN)E} on $(x,y)$. \fun{long}{gp_callbool}{void *E, GEN x} evaluates the closure \kbd{(GEN)E} on $x$, returns \kbd{1} if its result is non-zero, and \kbd{0} otherwise. \fun{long}{gp_callvoid}{void *E, GEN x} evaluates the closure \kbd{(GEN)E} on $x$, discarding the result. Return a non-zero value if a control-flow instruction request the iterator to terminate immediately. \section{Defaults} \fun{entree*}{pari_is_default}{const char *s} return the \kbd{entree} structure attached to $s$ if it is the name of a default, \kbd{NULL} otherwise. \fun{GEN}{setdefault}{const char *s, const char *v, long flag} is the low-level function underlying \kbd{default0}. If $s$ is \kbd{NULL}, call all default setting functions with string argument \kbd{NULL} and flag \tet{d_ACKNOWLEDGE}. Otherwise, check whether $s$ corresponds to a default and call the corresponding default setting function with arguments $v$ and \fl. We shall describe these functions below: if $v$ is \kbd{NULL}, we only look at the default value (and possibly print or return it, depending on \kbd{flag}); otherwise the value of the default to $v$, possibly after some translation work. The flag is one of \item \tet{d_INITRC} called while reading the \kbd{gprc}: print and return \kbd{gnil}, possibly defer until \kbd{gp} actually starts. \item \tet{d_RETURN} return the current value, as a \typ{INT} if possible, as a \typ{STR} otherwise. \item \tet{d_ACKNOWLEDGE} print the current value, return \kbd{gnil}. \item \tet{d_SILENT} print nothing, return \kbd{gnil}. \noindent Low-level functions called by \kbd{setdefault}: \fun{GEN}{sd_TeXstyle}{const char *v, long flag} \fun{GEN}{sd_breakloop}{const char *v, long flag} \fun{GEN}{sd_colors}{const char *v, long flag} \fun{GEN}{sd_compatible}{const char *v, long flag} \fun{GEN}{sd_datadir}{const char *v, long flag} \fun{GEN}{sd_debug}{const char *v, long flag} \fun{GEN}{sd_debugfiles}{const char *v, long flag} \fun{GEN}{sd_debugmem}{const char *v, long flag} \fun{GEN}{sd_echo}{const char *v, long flag} \fun{GEN}{sd_factor_add_primes}{const char *v, long flag} \fun{GEN}{sd_factor_proven}{const char *v, long flag} \fun{GEN}{sd_format}{const char *v, long flag} \fun{GEN}{sd_graphcolormap}{const char *v, long flag} \fun{GEN}{sd_graphcolors}{const char *v, long flag} \fun{GEN}{sd_help}{const char *v, long flag} \fun{GEN}{sd_histfile}{const char *v, long flag} \fun{GEN}{sd_histsize}{const char *v, long flag} \fun{GEN}{sd_lines}{const char *v, long flag} \fun{GEN}{sd_linewrap}{const char *v, long flag} \fun{GEN}{sd_log}{const char *v, long flag} \fun{GEN}{sd_logfile}{const char *v, long flag} \fun{GEN}{sd_nbthreads}{const char *v, long flag} \fun{GEN}{sd_new_galois_format}{const char *v, long flag} \fun{GEN}{sd_output}{const char *v, long flag} \fun{GEN}{sd_parisize}{const char *v, long flag} \fun{GEN}{sd_parisizemax}{const char *v, long flag} \fun{GEN}{sd_path}{const char *v, long flag} \fun{GEN}{sd_plothsizes}{const char *v, long flag} \fun{GEN}{sd_prettyprinter}{const char *v, long flag} \fun{GEN}{sd_primelimit}{const char *v, long flag} \fun{GEN}{sd_prompt}{const char *v, long flag} \fun{GEN}{sd_prompt_cont}{const char *v, long flag} \fun{GEN}{sd_psfile}{const char *v, long flag} The \kbd{psfile} default is obsolete, don't use this function. \fun{GEN}{sd_readline}{const char *v, long flag} \fun{GEN}{sd_realbitprecision}{const char *v, long flag} \fun{GEN}{sd_realprecision}{const char *v, long flag} \fun{GEN}{sd_recover}{const char *v, long flag} \fun{GEN}{sd_secure}{const char *v, long flag} \fun{GEN}{sd_seriesprecision}{const char *v, long flag} \fun{GEN}{sd_simplify}{const char *v, long flag} \fun{GEN}{sd_sopath}{const char *v, int flag} \fun{GEN}{sd_strictargs}{const char *v, long flag} \fun{GEN}{sd_strictmatch}{const char *v, long flag} \fun{GEN}{sd_timer}{const char *v, long flag} \fun{GEN}{sd_threadsize}{const char *v, long flag} \fun{GEN}{sd_threadsizemax}{const char *v, long flag} \noindent Generic functions used to implement defaults: most of the above routines are implemented in terms of the following generic ones. In all routines below \item \kbd{v} and \kbd{flag} are the arguments passed to \kbd{default}: \kbd{v} is a new value (or the empty string: no change), and \kbd{flag} is one of \tet{d_INITRC}, \tet{d_RETURN}, etc. \item \kbd{s} is the name of the default being changed, used to display error messages or acknowledgements. \fun{GEN}{sd_toggle}{const char *v, long flag, const char *s, int *ptn} \item if \kbd{v} is neither \kbd{"0"} nor \kbd{"1"}, an error is raised using \tet{pari_err}. \item \kbd{ptn} points to the current numerical value of the toggle (1 or 0), and is set to the new value (when \kbd{v} is non-empty). For instance, here is how the timer default is implemented internally: \bprog GEN sd_timer(const char *v, long flag) { return sd_toggle(v,flag,"timer", &(GP_DATA->chrono)); } @eprog The exact behavior and return value depends on \kbd{flag}: \item \tet{d_RETURN}: returns the new toggle value, as a \kbd{GEN}. \item \tet{d_ACKNOWLEDGE}: prints a message indicating the new toggle value and return \kbd{gnil}. \item other cases: print nothing and return \kbd{gnil}. \fun{GEN}{sd_ulong}{const char *v, long flag, const char *s, ulong *ptn, ulong Min, ulong Max, const char **msg}\hbadness 10000 \item \kbd{ptn} points to the current numerical value of the toggle, and is set to the new value (when \kbd{v} is non-empty). \item \kbd{Min} and \kbd{Max} point to the minimum and maximum values allowed for the default. \item \kbd{v} must translate to an integer in the allowed ranger, a suffix among \kbd{k}/\kbd{K} ($\times 10^3$), \kbd{m}/\kbd{M} ($\times 10^6$), or \kbd{g}/\kbd{G} ($\times 10^9$) is allowed, but no arithmetic expression. \item \kbd{msg} is a \kbd[NULL]-terminated array of messages or \kbd{NULL} (ignored). If \kbd{msg} is not \kbd{NULL}, \kbd{msg}$[i]$ contains a message attached to the value $i$ of the default. The last entry in the \kbd{msg} array is used as a message attached to all subsequent ones. The exact behavior and return value depends on \kbd{flag}: \item \tet{d_RETURN}: returns the new value, as a \kbd{GEN}. \item \tet{d_ACKNOWLEDGE}: prints a message indicating the new value, possibly a message attached to it via the \kbd{msg} argument, and return \kbd{gnil}. \item other cases: print nothing and return \kbd{gnil}. \fun{GEN}{sd_intarray}{const char *v, long flag, const char *s, GEN *pz} \item records a \typ{VECSMALL} array of non-negative integers. \item \kbd{pz} points to the current \typ{VECSMALL} value, and is set to the new value (when \kbd{v} is non-empty). The exact return value depends on \kbd{flag}: \item \tet{d_RETURN}: returns the new value, as a \typ{VEC} (converted via \kbd{zv\_to\_ZV}) \item \tet{d_ACKNOWLEDGE}: prints a message indicating the new value, (as a \typ{VEC}) and return \kbd{gnil}. \item other cases: print nothing and return \kbd{gnil}. \fun{GEN}{sd_string}{const char *v, long flag, const char *s, char **pstr} \item \kbd{v} is subjet to environment expansion, then time expansion. \item \kbd{pstr} points to the current string value, and is set to the new value (when \kbd{v} is non-empty). \section{Records and Lazy vectors} The functions in this section are used to implement \kbd{ell} structures and analogous objects, which are vectors some of whose components are initialized to dummy values, later computed on demand. We start by initializing the structure: \fun{GEN}{obj_init}{long d, long n} returns an \tev{obj} $S$, a \typ{VEC} with $d$ regular components, accessed as \kbd{gel(S,1)}, \dots, \kbd{gel(S,d)}; together with a record of $n$ members, all initialized to $0$. The arguments $d$ and $n$ must be non-negative. After \kbd{S = obj\_init(d, n)}, the prototype of our other functions are of the form \bprog GEN obj_do(GEN S, long tag, ...) @eprog\noindent The first argument $S$ holds the structure to be managed. The second argument \var{tag} is the index of the struct member (from $1$ to $n$) we operate on. We recommend to define an \kbd{enum} and use descriptive names instead of hardcoded numbers. For instance, if $n = 3$, after defining \bprog enum { TAG_p = 1, TAG_list, TAG_data }; @eprog\noindent one may use \kbd{TAG\_list} or $2$ indifferently as a tag. The former being preferred, of course. \misctitle{Technical note} In the current implementation, $S$ is a \typ{VEC} with $d+1$ entries. The first $d$ components are ordinary \typ{GEN} entries, which you can read or assign to in the customary way. But the last component $\kbd{gel(S, d+1)}$, a \typ{VEC} of length $n$ initialized to \kbd{zerovec}$(n)$, must be handled in a special way: you should never access or modify its components directly, only through the API we are about to describe. Indeed, its entries are meant to contain dynamic data, which will be stored, retrieved and replaced (for instance by a value computed to a higher accuracy), while interacting safely with intermediate \kbd{gerepile} calls. This mechanism allows to simulate C \kbd{struct}s, in a simpler way than with general hashtables, while remaining compatible with the GP language, which knows neither structs nor hashtables. It also serialize the structure in an ordinary \kbd{GEN}, which facilitates copies and garbage collection (use \kbd{gcopy} or \kbd{gerepile}), rather than having to deal with individual components of actual C \kbd{struct}s. \fun{GEN}{obj_reinit}{GEN S} make a shallow copy of $S$, re-initializing all dynamic components. This allows ``forking'' a lazy vector while avoiding both a memory leak, and storing pointers to the same data in different objects (with risks of a double free later). \fun{GEN}{obj_check}{GEN S, long tag} if the \emph{tag}-component in $S$ is non empty, return it. Otherwise return \kbd{NULL}. The \typ{INT} $0$ (initial value) is used as a sentinel to indicated an empty component. \fun{GEN}{obj_insert}{GEN S, long tag, GEN O} insert (a clone of) $O$ as \emph{tag}-component of $S$. Any previous value is deleted, and data pointing to it become invalid. \fun{GEN}{obj_insert_shallow}{GEN S, long K, GEN O} as \tet{obj_insert}, inserting $O$ as-is, not via a clone. \fun{GEN}{obj_checkbuild}{GEN S, long tag, GEN (*build)(GEN)} if the \emph{tag}-component of $S$ is non empty, return it. Otherwise insert (a clone of) \kbd{build(S)} as \emph{tag}-component in $S$, and return it. \fun{GEN}{obj_checkbuild_padicprec}{GEN S, long tag, GEN (*build)(GEN,long), long prec} if the \emph{tag}-component of $S$ is non empty \emph{and} has relative $p$-adic precision $\geq \kbd{prec}$, return it. Otherwise insert (a clone of) \kbd{build(S, prec)} as \emph{tag}-component in $S$, and return it. \fun{GEN}{obj_checkbuild_realprec}{GEN S, long tag, GEN (*build)(GEN, long), long prec} if the \emph{tag}-component of $S$ is non empty \emph{and} satisfies \kbd{gprecision} $\geq \kbd{prec}$, return it. Otherwise insert (a clone of) \kbd{build(S, prec)} as \emph{tag}-component in $S$, and return it. \fun{GEN}{obj_checkbuild_prec}{GEN S, long tag, GEN (*build)(GEN,long), GEN (*gpr)(GEN), long prec} if the \emph{tag}-component of $S$ is non empty \emph{and} has precision $\kbd{gpr}(x)\geq \kbd{prec}$, return it. Otherwise insert (a clone of) \kbd{build(S, prec)} as \emph{tag}-component in $S$, and return it. \fun{void}{obj_free}{GEN S} destroys all clones stored in the $n$ tagged components, and replace them by the initial value $0$. The regular entries of $S$ are unaffected, and $S$ remains a valid object. This is used to avoid memory leaks. pari-2.11.2/doc/tutorial.tex0000644000175000017500000053314713457566441014344 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/\kbd{gp} documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License % This should be compiled with plain TeX \def\TITLE{A Tutorial for Pari/GP} \input parimacro.tex \chapno=0 \begintitle \vskip2.5truecm \centerline{\mine A Tutorial} \vskip1.truecm \centerline{\mine for} \vskip1.truecm \centerline{\mine PARI / GP} \vskip1.truecm \centerline{\sectiontitlebf (version \vers)} \vskip1.truecm \authors \endtitle \copyrightpage \tableofcontents \noindent This booklet is a guided tour and a tutorial to the \kbd{gp} calculator. Many examples will be given, but each time a new function is used, the reader should look at the appropriate section in the \emph{User's Manual to PARI/GP} for detailed explanations. This chapter can be read independently, for example to get acquainted with the possibilities of \kbd{gp} without having to read the whole manual. At this point. \section{Greetings!} So you are sitting in front of your workstation (or terminal, or PC\dots), and you type \kbd{gp} to get the program started (or click on the relevant icon, or select some menu item). It says hello in its particular manner, and then waits for you after its \kbd{prompt}, initially \kbd{?} (or something like {\bf gp}~\kbd{>}). Type \bprog 2 + 2 @eprog\noindent What happens? Maybe not what you expect. First of all, of course, you should tell \kbd{gp} that your input is finished, and this is done by hitting the \kbd{Return} (or \kbd{Newline}, or \kbd{Enter}) key. If you do exactly this, you will get the expected answer. However some of you may be used to other systems like Gap, Macsyma, Magma or Maple. In this case, you will have subconsciously ended the line with a semicolon ``\kbd{;}'' before hitting \kbd{Return}, since this is how it is done on those systems. In that case, you will simply see \kbd{gp} answering you with a smug expression, i.e.~a new prompt and no answer! This is because a semicolon at the end of a line tells \kbd{gp} not to print the result (it is still stored in the result history). You will certainly want to use this feature if the output is several pages long. Try \bprog 27 * 37 @eprog\noindent Wow! even multiplication works. Actually, maybe those spaces are not necessary after all. Let's try \kbd{27*37}. Seems to be ok. We will still insert them in this document since it makes things easier to read, but as \kbd{gp} does not care about them, you don't have to type them all. Now this session is getting lengthy, so the second thing one needs to learn is to quit. Each system has its quit signal. In \kbd{gp}, you can use \kbd{quit} or \b{q} (backslash q), the \kbd{q} being of course for quit. Try it. Now you've done it! You're out of \kbd{gp}, so how do you want to continue studying this tutorial? Get back in please. Let's get to more serious stuff. I seem to remember that the decimal expansion of $1/7$ has some interesting properties. Let's see what \kbd{gp} has to say about this. Type \bprog 1 / 7 @eprog\noindent What? This computer is making fun of me, it just spits back to me my own input, that's not what I want! Now stop complaining, and think a little. Mathematically, $1/7$ is an element of the field $\Q$ of rational numbers, so how else but $1/7$ can the computer give the answer to you? Well maybe $2/14$ or $7^{-1}$, but why complicate matters? Seriously, the basic point here is that PARI, hence \kbd{gp}, will almost always try to give you a result which is as precise as possible (we will see why ``almost'' later). Hence since here the result can be represented exactly, that's what it gives you. But I still want the decimal expansion of $1/7$. No problem. Type one of the following: \bprog 1./ 7 1 / 7. 1./ 7. 1 / 7 + 0. @eprog\noindent Immediately a number of decimals of this fraction appear, 38 on most systems, 28 on the others, and the repeating pattern is $142857$. The reason is that you have included in the operations numbers like \kbd{0.}, \kbd{1.} or \kbd{7.} which are \emph{imprecise} real numbers, hence \kbd{gp} cannot give you an exact result. Why 28 / 38 decimals by the way? Well, it is the default initial precision. This has been chosen so that the computations are very fast, and gives already 12 decimals more accuracy than conventional double precision floating point operations. The precise value depends on a technical reason: if your machine supports 64-bit integers (the standard C library can handle integers up to $2^{64}$), the default precision is 38 decimals, and 28 otherwise. For definiteness, we will assume the former henceforth. Of course, you can extend the precision (almost) as much as you like as we will see in a moment. I'm getting bored, why don't we get on with some more exciting stuff? Well, try \kbd{exp(1)}. Presto, comes out the value of $e$ to 38 digits. Try \kbd{log(exp(1))}. Well, we get a floating point number and not an exact $1$, but pretty close! That's what you lose by working numerically. What could we try now? Hum, \kbd{pi}? The answer is not that enlightening. \kbd{Pi}? Ah. This works better. But let's remember that \kbd{gp} distinguishes between uppercase and lowercase letters. \kbd{pi} was as meaningless to it as \kbd{stupid garbage} would have been: in both cases \kbd{gp} will just create a variable with that funny unknown name you just used. Try it! Note that it is actually equivalent to type \kbd{stupidgarbage}: all spaces are suppressed from the input. In the \kbd{27~*~37} example it was not so conspicuous as we had an operator to separate the two operands. This has important consequences for the writing of \kbd{gp} scripts. More about this later. By the way, you can ask \kbd{gp} about any identifier you think it might know about: just type it, prepending a question mark ``\kbd{?}''. Try \kbd{?Pi} and \kbd{?pi} for instance. On most systems, an extended online help should be available: try doubling the question mark to check whether it's the case on yours: \kbd{??Pi}. In fact the \kbd{gp} header already gave you that information if it was the case, just before the copyright message. As well, if it says something like ``\kbd{readline enabled}'' then you should have a look at the \kbd{readline} introduction in the User's Manual before you go on: it will be much easier to type in examples and correct typos after you've done that. Now try \kbd{exp(Pi * sqrt(163))}. Hmmm, we suspect that the last digit may be wrong, can this really be an integer? This is the time to change precision. Type \kbd{\b{p} 50}, then try \kbd{exp(Pi * sqrt(163))} again. We were right to suspect that the last decimal was incorrect, since we get quite a few nines in its place, but it is now convincingly clear that this is not an integer. Maybe it's a bug in PARI, and the result is really an integer? Type \bprog (log(%) / Pi)^2 @eprog\noindent immediately after the preceding computation; \kbd{\%} means the result of the last computed expression. More generally, the results are numbered \kbd{\%1, \%2, \dots} \emph{including} the results that you do not want to see printed by putting a semicolon at the end of the line, and you can evidently use all these quantities in any further computations. The result seems to be indistinguishable from $163$, hence it does not seem to be a bug. In fact, it is known that $\exp(\pi*\sqrt{n})$ not only is not an integer or a rational number, but is even a transcendental number when $n$ is a non-zero rational number. So \kbd{gp} is just a fancy calculator, able to give me more decimals than I will ever need? Not so, \kbd{gp} is incredibly more powerful than an ordinary calculator, independently of its arbitrary precision possibilities. \misctitle{Additional comments} (you are supposed to skip this at first, and come back later) 1) If you are a PARI old timer, say the last version of PARI you used was released around 1996, you have certainly noticed already that many many things changed between the older 1.39.xx versions and this one. Conspicuously, most function names have been changed. To know how a specific function was changed, type \kbd{whatnow({\rm function})}. 2) It seems that the text implicitly says that as soon as an imprecise number is entered, the result will be imprecise. Is this always true? There is a unique exception: when you multiply an imprecise number by the exact number 0, you will get the exact 0. Compare \kbd{0 * 1.4} and \kbd{0.~*~1.4}. \smallskip % 3) Not only can the number of decimal places of real numbers be large, but the number of digits of integers also. Try \kbd{1000!}. It is never necessary to tell \kbd{gp} in advance the size of the integers that it will encounter. The same is true for real numbers, although most computations with floating point assume a default precision and truncate their results to this accuracy; initially 38 decimal digits, but we may change that with \b{p} of course. \smallskip % 4) Come back to 38 digits of precision (\kbd{\b{p} 38}), and type \kbd{exp(100)}. As you can see the result is printed in exponential format. This is because \kbd{gp} never wants you to believe that a result is correct when it is not. We are working with 38 digits of precision, but the integer part of $\exp(100)$ has 44 decimal digits. Hence if \kbd{gp} had dutifully printed out 44 digits, the last few digits would have been wrong. Hence \kbd{gp} wants to print only 38 significant digits, but to do so it has to print in exponential format. \smallskip % 5) There are two ways to avoid this. One is of course to increase the precision. Let's try it. To give it a wide margin, we set the precision to 50 decimals. Then we recall our last result (\kbd{\%} or \kbd{\%n} where \kbd{n} is the number of the result). What? We still have an exponential format! Do you understand why? Again let's try to see what's happening. The number you recalled had been computed only to 38 decimals, and even if you set the precision to 1000 decimals, \kbd{gp} knows that your number has only 38 digits of accuracy but an integral part with 44 digits. So you haven't improved things by increasing the precision. Or have you? What if we retype \kbd{exp(100)} now that we have 50 digits? Try it. Now we no longer have an exponential format. \medskip % 6) What if I forget what the current precision is and I don't feel like counting all the decimals? Well, you can type \b{p} by itself. You may also learn about \kbd{gp} internal variables (and change them!) using \kbd{default}. Type \kbd{default(realprecision)}, then \kbd{default(realprecision, 38)}. Huh? In fact this last command is strictly equivalent to \kbd{\b{p} 38}! (Admittedly more cumbersome to type.) There are more ``defaults'' than just \kbd{format} and \kbd{realprecision}: type \kbd{default} by itself now, they are all there. \smallskip % 7) Note that the \kbd{default} command reacts differently according to the number of input arguments. This is not an uncommon behavior for \kbd{gp} functions. You can see this from the online help, or the complete description in Chapter~3: any argument surrounded by braces \kbd{\obr\cbr} in the function prototype is optional, which really means that a \emph{default} argument will be supplied by \kbd{gp}. You can then check out from the text what effect a given value will have, and in particular the default one. \smallskip % 8) Try the following: starting in precision 38, type first \kbd{default(format, "e0.100")}, then \kbd{exp(1)}. Where are my 100 significant digits? Well, \kbd{default(format,)} only changes the output format, but \emph{not} the default precision. On the other hand, the \b{p} command changes both the precision and the output format. \section{Warming up} Another thing you better get used to pretty fast is error messages. Try typing \kbd{1/0}. Could not be clearer. But why has the prompt become funny, turning from \kbd{?} to \kbd{break>} ? When an error occurs, we enter a so-called \emph{break loop}, where you get a chance, e.g to inspect (and save!) values of variables before the prompt returns and all computations so far are lost. In fact you can run an arbitrary command at this point, and this mechanism is a tremendous help in debugging. To get out of the break loop, type \kbd{break}, as instructed in the error message last line. \misctitle{Comment} You can enter the break loop at any time using \kbd{Control-C}: this freezes the current computation and gets you a new prompt so that you may e.g., increase debugging level, inspect or modify variables (again, run arbitrary commands), before letting the program go on. \medskip Now, back to our favorite example, in precision 38, type \bprog floor(exp(100)) @eprog\noindent \kbd{floor} is the mathematician's integer part, not to be confused with \kbd{truncate}, which is the computer scientist's: \kbd{floor(-3.4)} is equal to $-4$ whereas \kbd{truncate(-3.4)} is equal to $-3$. You get a more cryptic error message, which you would immediately understand if you had read the additional comments of the preceding section. Since you were told not to read them, here's the explanation: \kbd{gp} is unable to compute the integer part of \kbd{exp(100)} given only 38 decimals of accuracy, since it has 44 digits. Some error messages are more cryptic and sometimes not so easy to understand. For instance, try \kbd{log(x)}. It simply tells you that \kbd{gp} does not understand what \kbd{log(x)} is, although it does know the \kbd{log} function, as \kbd{?log} will readily tell us. Now let's try \kbd{sqrt(-1)} to see what error message we get now. Haha! \kbd{gp} even knows about complex numbers, so impossible to trick it that way. Similarly, try typing \kbd{log(-2)}, \kbd{exp(I*Pi)}, \kbd{I\pow I}\dots\ So we have a lot of real and complex analysis at our disposal. There always is a specific branch of multivalued complex transcendental functions which is taken, specified in the manual. Again, beware that \kbd{I} and \kbd{i} are not the same thing. Compare \kbd{I\pow2} with \kbd{i\pow2} for instance. Just for fun, let's try \kbd{6*zeta(2) / Pi\pow2}. Pretty close, no? \medskip Now \kbd{gp} didn't seem to know what \kbd{log(x)} was, although it did know how to compute numerical values of \kbd{log}. This is annoying. Maybe it knows the exponential function? Let's give it a try. Type \kbd{exp(x)}. What's this? If you had any experience with other computer algebra systems, the answer should have simply been \kbd{exp(x)} again. But here the answer is the Taylor expansion of the function around $\kbd{x}=0$, to 16 terms. 16 is the default \kbd{seriesprecision}, which can be changed by typing \kbd{\b{ps} $n$} or \kbd{default(seriesprecision, $n$)} where $n$ is the number of terms that you want in your power series. Note the \kbd{O(x\pow16)} which ends the series, and which is trademark of this type of object in \kbd{gp}. It is the familiar ``big--oh'' notation of analysis. You thus automatically get the Taylor expansion of any function that can be expanded around $0$, and incidentally this explains why we weren't able to do anything with \kbd{log(x)} which is not defined at $0$. (In fact \kbd{gp} knows about Laurent series, but \kbd{log(x)} is not meromorphic either at $0$.) If we try \kbd{log(1+x)}, then it works. But what if we wanted the expansion around a point different from 0? Well, you're able to change $x$ into $x-a$, aren't you? So for instance you can type \kbd{log(x+2)} to have the expansion of \kbd{log} around $\kbd{x}=2$. As exercises you can try \bprog cos(x) cos(x)^2 + sin(x)^2 exp(cos(x)) gamma(1 + x) exp(exp(x) - 1) 1 / tan(x) @eprog\noindent for different values of \kbd{serieslength} (change it using \b{ps} \var{newvalue}). Let's try something else: type \kbd{(1 + x)\pow 3}. No \kbd{O(x)} here, since the result is a polynomial. Haha, but I have learnt that if you do not take exponents which are integers greater or equal to 0, you obtain a power series with an infinite number of non-zero terms. Let's try. Type \kbd{(1 + x)\pow (-3)} (the parentheses around \kbd{-3} are not necessary but make things easier to read). Surprise! Contrary to what we expected, we don't get a power series but a rational function. Again this is for the same reason that \kbd{1 / 7} just gave you $1/7$: the result being exact, PARI doesn't see any reason to make it non-exact. But I still want that power series. To obtain it, you can do as in the $1/7$ example and type \bprog (1 + x)^(-3) + O(x^16) (1 + x)^(-3) * (1 + O(x^16)) (1 + x + O(x^16))^(-3) @eprog\noindent (Not on this example, but there is a difference between the first $2$ methods. Do you spot it?) Better yet, use the series constructor which transforms any object into a power series, using the current \kbd{seriesprecision}, and simply type \bprog Ser( (1 + x)^(-3) ) @eprog Now try \kbd{(1 + x)\pow (1/2)}: we obtain a power series, since the result is an object which PARI does not know how to represent exactly. (We could teach PARI about algebraic functions, but then take \kbd{(1 + x)\pow Pi} as another example.) This gives us still another solution to our preceding exercise: we can type \kbd{(1 + x)\pow (-3.)}. Since \kbd{-3.} is not an exact quantity, PARI has no means to know that we are dealing with a rational function, and will instead give you the power series, this time with real instead of integer coefficients. \smallskip To summarize, in this section we have seen that in addition to integers, real numbers and rational numbers, PARI can handle complex numbers, polynomials, rational functions and power series. A large number of functions exist which handle these types, but in this tutorial we will only look at a few. \misctitle{Additional comments} (as before, you are supposed to skip this at first reading) 1) In almost all cases, there is no loss of information in PARI output: what you see is all that PARI knows about the object, and you can happily copy-paste it into another session. There are exceptions, though. Type \kbd{n = 3 + 0*x}, then \kbd{n} is not the integer 3 but a constant polynomial equal to $3 x^0$. Check it with \kbd{type(n)}. However, it \emph{looks} like an integer without being one, and this may cause some confusion in programs which actually expect integers. Hence if you try to \kbd{factor(n)}, you obtain an empty factorization ! (Because, once considered as a polynomial, \kbd{n} is a unit in $\Q[x]$.) If you try to apply more general arithmetic functions, say the Euler totient function (known as \kbd{eulerphi} to \kbd{gp}), you get an error message worrying about integer arguments. You would have guessed yourself, but the message is difficult to understand since 3 looks like a genuine integer! Please make sure you understand the above, it is a common source of incomprehension. 2) If you want the final expression to be in the simplest form possible (for example before applying an arithmetic function, or simply because things will go faster afterwards), apply the function \kbd{simplify} to the result. This is done automatically at the end of a \kbd{gp} command, but \emph{not} in intermediate expressions. Hence \kbd{n} above is not an integer, but the final result stored in the output history is! So if you type \kbd{type(\%)} instead of \kbd{type(n)} the answer is \typ{INT}, adding to the confusion. 3) As already stated, power series expansions are always implicitly around $\kbd{x} = 0$. When we wanted them around $\kbd{x} = \kbd{a}$, we replaced \kbd{x} by \kbd{z + a} in the function we wanted to expand. For complicated functions, it may be simpler to use the substitution function \kbd{subst}. For example, if \kbd{p~= 1 / (x\pow 4 + 3*x\pow 3 + 5*x\pow 2 - 6*x + 7)}, you may not want to retype this, replacing \kbd{x} by \kbd{z~+ a}, so you can write \kbd{subst(p, x, z+a)} (look up the exact description of the \kbd{subst} function). Now type \kbd{subst(1 + O(x), x, z+1)}. Do you understand the error message? 4) The valuation at $\kbd{x} = 0$ for a power series \kbd{p} is obtained as \kbd{valuation(p, x)}. \section{The Remaining PARI Types} Let's talk some more about the basic PARI types. Type \kbd{p = x * exp(-x)}. As expected, you get the power series expansion to 16 terms (if you have not changed the default). Now type \kbd{pr = serreverse(p)}. You are asking here for the \emph{reversion} of the power series \kbd{p}, in other words the inverse function. This is possible only for power series whose first non-zero coefficient is that of $x^1$. To check the correctness of the result, you can type \kbd{subst(p, x, pr)} or \kbd{ subst(pr, x, p)} and you should get back \kbd{x + O(x\pow 17)}. Now the coefficients of \kbd{pr} obey a very simple formula. First, we would like to multiply the coefficient of \kbd{x\pow n} by \kbd{n!} (in the case of the exponential function, this would simplify things considerably!). The PARI function \kbd{serlaplace} does just that. So type \kbd{ps = serlaplace(pr)}. The coefficients now become integers, which can be immediately recognized by inspection. The coefficient of $x^n$ is now equal to $n^{n-1}$. In other words, we have % $$\kbd{pr} = \sum_{n\ge1}\dfrac{n^{n-1}}{n!} X^{n}.$$ % Do you know how to prove this? (The proof is difficult.) \smallskip % Of course PARI knows about vectors (rows and columns are distinguished, even though mathematically there is no difference) and matrices. Type for example \kbd{[1,2,3,4]}. This gives the row vector whose coordinates are 1, 2, 3 and 4. If you want a column vector, type \kbd{[1,2,3,4]\til}, the tilde meaning of course transpose. You don't see much difference in the output, except for the tilde at the end. However, now type \b{b}: lo and behold, the column vector appears as a proper vertical thingy now. The \b{b} command is used mainly for this purpose. The length of a vector is given by, well \kbd{length} of course. The shorthand ``cardinality'' notation \kbd{\#v} for \kbd{length(v)} is also available, for instance \kbd{v[\#v]} is the last element of \kbd{v}. Type \kbd{m = [a,b,c; d,e,f]}. You have just entered a matrix with 2 rows and 3 columns. Note that the matrix is entered by \emph{rows} and the rows are separated by semicolons ``\kbd{;}''. The matrix is printed naturally in a rectangle shape. If you want it printed horizontally just as you typed it, type \b{a}, or if you want this type of printing to be the permanent default type \kbd{default(output, 0)}. Type \kbd{default(output, 1)} if you want to come back to the original output mode. Now type \kbd{m[1,2]}, \kbd{m[1,]}, \kbd{m[,2]}. Are explanations necessary? (In an expression such as \kbd{m[j,k]}, the \kbd{j} always refers to the row number, and the \kbd{k} to the column number, and the first index is always 1, never 0. This default cannot be changed.) Even better, type \kbd{m[1,2] = 5; m}. The semicolon also allows us to put several instructions on the same line; the final result is the output of the last statement on the line. Now type \kbd{m[1,] = [15,-17,8]}. No problem. Finally type \kbd{m[,2] = [j,k]}. You have an error message since you have typed a row vector, while \kbd{m[,2]} is a column vector. If you type instead \kbd{m[,2] = [j,k]\til} it works. \smallskip % \label{se:types} Type now \kbd{h = mathilbert(20)}. You get the so-called ``Hilbert matrix'' whose coefficient of row $i$ and column $j$ is equal to $(i+j-1)^{-1}$. Incidentally, the matrix \kbd{h} takes too much room. If you don't want to see it, simply type a semi-colon ``\kbd{;}'' at the end of the line (\kbd{h = mathilbert(20);}). This is an example of a ``precomputed'' matrix, built into PARI. We will see a more general construction later. What is interesting about Hilbert matrices is that first their inverses and determinants can be computed explicitly (and the inverse has integer coefficients), and second they are numerically very unstable, which make them a severe test for linear algebra packages in numerical analysis. Of course with PARI, no such problem can occur: since the coefficients are given as rational numbers, the computation will be done exactly, so there cannot be any numerical error. Try it. Type \kbd{d~=~matdet(h)}. The result is a rational number (of course) of numerator equal to 1 and denominator having 226 digits. How do I know, by the way? Well, type \kbd{sizedigit(1/d)}. Or \kbd{\#Str(1/d)}. (The length of the character string representing the result.) Now type \kbd{hr = 1.* h;} (do not forget the semicolon, we don't want to see the result!), then \kbd{dr = matdet(hr)}. You notice two things. First the computation, is much faster than in the rational case. (If your computer is too fast for you to notice, try again with \kbd{h = mathilbert(40)}, or even some larger value.) The reason for this is that PARI is handling real numbers with 38 digits of accuracy, while in the rational case it is handling integers having up to 226 decimal digits. The second, more important, fact is that the result is terribly wrong. If you compare with \kbd{1.$*$d} computed earlier, which is the correct answer, you will see that few decimals agree! (None agree if you replaced 20 by 40 as suggested above.) This catastrophic instability is as already mentioned one of the characteristics of Hilbert matrices. In fact, the situation is worse than that. Type \kbd{norml2(1/h - 1/hr)} (the function \kbd{norml2} gives the square of the $L^2$ norm, i.e.~the sum of the squares of the coefficients). The result is larger than $10^{32}$, showing that some coefficients of \kbd{1/hr} are wrong by as much as $10^{16}$. To obtain the correct result after rounding for the inverse, we have to use a default precision of 57 digits (try it). Although vectors and matrices can be entered manually, by typing explicitly their elements, very often the elements satisfy a simple law and one uses a different syntax. For example, assume that you want a vector whose $i$-th coordinate is equal to $i^2$. No problem, type for example \kbd{vector(10,i, i\pow 2)} if you want a vector of length 10. Similarly, if you type \bprog matrix(5,5, i,j, 1 / (i+j-1)) @eprog\noindent you will get the Hilbert matrix of order 5, hence the \kbd{mathilbert} function is in fact redundant. The \kbd{i} and \kbd{j} represent dummy variables which are used to number the rows and columns respectively (in the case of a vector only one is present of course). You must not forget, in addition to the dimensions of the vector or matrix, to indicate explicitly the names of these variables. You may omit the variables and the final expression to get zero entries, as in \kbd{matrix(10,20)}. \misctitle{Warning} The letter \kbd{I} is reserved for the complex number equal to the square root of $-1$. Hence it is forbidden to use it as a variable. Try typing \kbd{vector(10,I, I\pow 2)}, the error message that you get clearly indicates that \kbd{gp} does not consider \kbd{I} as a variable. There are other reserved variable names: \kbd{Pi}, \kbd{Euler}, \kbd{Catalan} and \kbd{oo}. All function names are forbidden as well. On the other hand there is nothing special about \kbd{i}, \kbd{pi}, \kbd{euler} or \kbd{catalan}. When creating vectors or matrices, it is often useful to use Boolean operators and the \kbd{if()} statement. Indeed, an \kbd{if} expression has a value, which is of course equal to the evaluated part of the \kbd{if}. So for example you can type \bprog matrix(8,8, i,j, if ((i-j)%2, 1, 0)) @eprog\noindent to get a checkerboard matrix of \kbd{1} and \kbd{0}. Note however that a vector or matrix must be \emph{created} first before being used. For example, it is possible to write \bprog v = vector(5); for (i = 1, 5, v[i] = 1/i) @eprog\noindent but this would fail if the vector \kbd{v} had not been created beforehand. Of course, the above example is better written as \bprog v = vector(5, i, 1/i); @eprog Another useful way to create vectors and matrices is to extract them from larger ones. For instance, if \kbd{h} is the $20\times 20$ Hilbert matrix as above, \bprog h = mathilbert(20); h[11..20, 11..20] @eprog\noindent is its lower right quadrant. \medskip The last PARI types which we have not yet played with are closely linked to number theory. People not interested in number theory can skip ahead. The first is the type ``integer--modulo''. Let us see an example. Type \bprog n = 10^15 + 3 @eprog We want to know whether this number is prime or not. Of course we could make use of the built-in facilities of PARI, but let us do otherwise. We first trial divide by the built-in table of primes. We slightly cheat here and use a variant of the function \kbd{factor} which does exactly this. So type \kbd{factor(n, 200000)}. The last argument tells \kbd{factor} to trial divide up to the given bound and stop at this point. Set it to 0 to trial divide by the full set of built-in primes, which goes up to $500000$ by default. As for all factoring functions, the result is a 2 column matrix: the first column gives the primes and the second their exponents. Here we get a single row, telling us that if primes stopped at $200000$ as we made \kbd{factor} believe, \kbd{n} would be prime. (Or is that a contradiction?) More seriously, \kbd{n} is not divisible by any prime up to $200000$. We could now trial divide further, or cheat and call the PARI function \kbd{factor} without the optional second argument, but before we do this let us see how to get an answer ourselves. By Fermat's little theorem, if $n$ is prime we must have $a^{n-1}\equiv 1 \pmod{n}$ for all $a$ not divisible by $n$. Hence we could try this with $a=2$ for example. But $2^{n-1}$ is a number with approximately $3\cdot10^{14}$ digits, hence impossible to write down, let alone to compute. But instead type \kbd{a = Mod(2,n)}. This creates the number $2$ considered now as an element of the ring $R = \Z/\kbd{n}\Z$. The elements of $R$, called intmods, can always be represented by numbers smaller than \kbd{n}, hence small. Fermat's theorem can be rewritten % $\kbd{a}^{n-1} = \kbd{Mod(1,n)}$ % in the ring $R$, and this can be computed very efficiently. Elements of $R$ may be lifted back to $\Z$ with either \kbd{lift} or \kbd{centerlift}. Type \kbd{a\pow (n-1)}. The result is definitely \emph{not} equal to \kbd{Mod(1,n)}, thus \emph{proving} that \kbd{n} is not a prime. If we had obtained \kbd{Mod(1,n)} on the other hand, it would have given us a hint that \kbd{n} is maybe prime, but not a proof. To find the factors is another story. In this case, the integer $n$ is small enough to let trial division run to completion. Type \kbd{\#} to turn on the \kbd{gp} timer, then \bprog for (i = 2, ceil(sqrt(n)), if (n%i==0, print(i); break)) @eprog\noindent This should take less than 5 seconds. In general, one must use less naive techniques than trial division, or be very patient. Type \kbd{fa = factor(n)} to let the factoring engine find all prime factors. You may stop the timer by typing \kbd{\#} again. Note that, as is the case with most ``prime''-producing functions, the ``prime'' factors given by \kbd{factor} are only strong pseudoprimes, and not \emph{proven} primes. Use \kbd{isprime( fa[,1] )} to rigorously prove primality of the factors. The latter command applies \kbd{isprime} to all entries in the first column of \kbd{fa}, i.e to all pseudoprimes, and returns the column vector of results: all equal to 1, so our pseudoprimes were true primes. All arithmetic functions can be applied in this way to the entries of a vector or matrix. In fact, it has been checked that the strong pseudoprimes output by \kbd{factor} (Baillie-Pomerance-Selfridge-Wagstaff pseudoprimes, without small divisors) are true primes at least up to $2^{64}$, and no explicit counter-example is known.\smallskip The second specifically number-theoretic type is the $p$-adic numbers. I have no room for definitions, so please skip ahead if you have no use for such beasts. A $p$-adic number is entered as a rational or integer valued expression to which is added \kbd{O(p\pow n)}, or simply \kbd{O(p)} if $\kbd{n}=1$, where \kbd{p} is the prime and \kbd{n} the $p$-adic precision. Note that you have to explicitly type in \kbd{3\pow 2} for instance, \kbd{9} will not do. Unless you want to cheat \kbd{gp} into believing that \kbd{9} is prime, but you had better know what you are doing in this case: most computations will yield a wrong result. Apart from the usual arithmetic operations, you can apply a number of transcendental functions. For example, type \kbd{n = 569 + O(7\pow 8)}, then \kbd{s~=~sqrt(n)}, you obtain one of the square roots of \kbd{n}; to check this, type \kbd{s\pow 2 - n}). Type now \kbd{s = log(n)}, then \kbd{e = exp(s)}. If you know about $p$-adic logarithms, you will not be surprised that \kbd{e} is not equal to \kbd{n}. Type \kbd{(n/e)\pow 6}: \kbd{e} is in fact equal to \kbd{n} times the $(p-1)$-st root of unity \kbd{teichmuller(n)}. Incidentally, if you want to get back the integer 569 from the $p$-adic number \kbd{n}, type \kbd{lift(n)} or \kbd{truncate(n)}. \smallskip The third number-theoretic type is the type ``quadratic number''. This type is specially tailored so that we can easily work in a quadratic extension of a base field, usually $\Q$. It is a generalization of the type ``complex''. To start, we must specify which quadratic field we want to work in. For this, we use the function \kbd{quadgen} applied to the \emph{discriminant} \kbd{d} (as opposed to the radicand) of the quadratic field. This returns a number equal to $(\kbd{d}+a) / 2$ where $a$ is equal to 0 or 1 according to whether \kbd{d} is even or odd. The function \kbd{quadgen} takes an extra parameter which is how the number will be printed. To avoid confusion, this number should be set to a variable of the same name, i.e. do \kbd{w = quadgen(d, 'w)}. So type \kbd{w = quadgen(-163,'w)}, then \kbd{charpoly(w)} which asks for the characteristic polynomial of \kbd{w}. The result shows what \kbd{w} will represent. You may ask for \kbd{1.*w} to see which root of the quadratic has been taken, but this is rarely necessary. We can now play in the field $\Q(\sqrt{-163})$. Type for example \kbd{w\pow 10}, \kbd{norm(3 + 4*w)}, \kbd{1 / (4+w)}. More interesting, type \kbd{a = Mod(1,23) * w} then \kbd{b = a\pow 264}. This is a generalization of Fermat's theorem to quadratic fields. If you do not want to see the modulus 23 all the time, type \kbd{lift(b)}. Another example: type \kbd{p = x\pow 2 + w*x + 5*w + 7}, then \kbd{norm(p)}. We thus obtain the quartic equation over $\Q$ corresponding to the relative quadratic extension over $\Q(\kbd{w})$ defined by \kbd{p}. On the other hand, if you type \kbd{wr = sqrt(w\pow 2)}, do not expect to get back \kbd{w}. Instead, you get the numerical value, the function \kbd{sqrt} being considered as a ``transcendental'' function, even though it is algebraic. Type \kbd{algdep(wr,2)}: this looks for algebraic relations involving the powers of \kbd{w} up to degree 2. This is one way to get \kbd{w} back. Similarly, type \kbd{algdep(sqrt(3*w + 5), 4)}. See the user's manual for the function \kbd{algdep}.\smallskip The fourth number-theoretic type is the type ``polynomial--modulo'', i.e. polynomial modulo another polynomial. This type is used to work in general algebraic extensions, for example elements of number fields (if the base field is $\Q$), or elements of finite fields (if the base field is $\Z/p\Z$ for a prime $p$). In a sense it is a generalization of the type quadratic number. The syntax used is the same as for intmods. For example, instead of typing \kbd{w = quadgen(-163,'w)}, you can type \bprog w = Mod(x, quadpoly(-163)) @eprog\noindent Then, exactly as in the quadratic case, you can type \kbd{w\pow 10}, \kbd{norm(3 + 4*w)}, \kbd{1 / (4+w)}, \kbd{a = Mod(1,23)*w}, \kbd{b = a\pow 264}, obtaining of course the same results. (Type \kbd{lift(\dots)} if you don't want to see the polynomial \kbd{x\pow 2 - x + 41} repeated all the time.) Of course, you can work in any degree, not only quadratic. For the latter, the corresponding elementary operations will be slower than with quadratic numbers. Start the timer, then compare \bprog w = quadgen(-163,'w); W = Mod(x, quadpoly(-163)); a = 2 + w; A = 2 + W; b = 3 + w; B = 3 + W; for (i=1,10^5, a+b) for (i=1,10^5, A+B) for (i=1,10^5, a*b) for (i=1,10^5, A*B) for (i=1,10^5, a/b) for (i=1,10^5, A/B) @eprog\noindent Don't retype everything, use the arrow keys! There is however a slight difference in behavior. Keeping our polmod \kbd{w}, type \kbd{1.*w}. As you can see, the result is not the same. Type \kbd{sqrt(w)}. Here, we obtain a vector with 2 components, the two components being the principal branch of the square root of all the possible embeddings of \kbd{w} in $\C$. More generally, if \kbd{w} was of degree $n$, we would get an $n$-component vector, and similarly for all transcendental functions. We have at our disposal the usual arithmetic functions, plus a few others. Type \kbd{a = Mod(x, x\pow 3 - x - 1)} defining a cubic extension. We can for example ask for \kbd{b = a\pow 5}. Now assume we want to express \kbd{a} as a polynomial in \kbd{b}. This is possible since \kbd{b} is also a generator of the same field. No problem, type \kbd{modreverse(b)}. This gives a new defining polynomial for the same field, i.e.~the characteristic polynomial of \kbd{b}, and expresses \kbd{a} in terms of this new polmod, i.e.~in terms of \kbd{a}. We will see this in more detail in the number field section. An important special case of the above construction allows to work in finite fields, by choosing an irreducible polynomial $T$ of degree $f$ over $\F_p$ and considering $\F_p[t]/(T)$. As in \bprog T = ffinit(5, 6, 't); \\ @com degree 6, irreducible over $\F_5$ g = Mod(t, T) @eprog\noindent Try a few elementary operations involving $g$, such as $g^{100}$. This special case of \typ{POLMOD}s is in fact so important that we now introduce a final dedicated number theoretical type \typ{FFELT}, for ``finite field element'', to simplify work with finite fields: \kbd{g = ffgen(5\pow6, 't)} computes a suitable polynomial $T$ as above and returns the generator $t \mod T(t)$. This has major advantages over the generic \typ{POLMOD} solution: elements are printed in a simplified way (in lifted form), and functions can assume that $T$ is indeed irreducible. A few dedicated functions \kbd{ffprimroot} (analog of \kbd{znprimroot}), \kbd{fforder} (analog of \kbd{znorder}), \kbd{fflog} (analog of \kbd{znlog}) are available. Rational expressions in the variable $t$ can be mapped to such a finite field by substituting $t$ by $g$, for instance \bprog ? g = ffgen(5^6, 't); ? g.mod \\ @com irreducible over $\F_5$, defines $\F_{5^6}$ %2 = t^6 + t^5 + t^4 + t^3 + t^2 + t + 1 ? Q = x^2 + t*x + 1 ? factor(subst(Q,t,g)) %3 = [ x + (t^5 + 3*t^4 + t^3 + 4*t + 1) 1] [x + (4*t^5 + 2*t^4 + 4*t^3 + 2*t + 4) 1] @eprog\noindent factors the polynomial $Q \in \F_{5^6}[x]$, where $\F_{5^6} = \F_5[t]/(\kbd{g.mod})$. \section{Elementary Arithmetic Functions} Since PARI is aimed at number theorists, it is not surprising that there exists a large number of arithmetic functions; see the list by typing \kbd{?4}. We have already seen several, such as \kbd{factor}. Note that \kbd{factor} handles not only integers, but also univariate polynomials. Type for example \kbd{factor(x\pow 200 - 1)}. You can also ask to factor a polynomial modulo a finite field or a number field ! Evidently, you have functions for computing GCD's (\kbd{gcd}), extended GCD's (\kbd{bezout}), solving the Chinese remainder theorem (\kbd{chinese}) and so on. In addition to the factoring facilities, you have a few functions related to primality testing such as \kbd{isprime}, \kbd{ispseudoprime}, \kbd{precprime}, and \kbd{nextprime}. As previously mentioned, only strong pseudoprimes are produced by the latter two (they pass the \kbd{ispseudoprime} test); the more sophisticated primality tests in \kbd{isprime}, being so much slower, are not applied by default. We also have the usual multiplicative arithmetic functions: the M\"obius $\mu$ function (\kbd{moebius}), the Euler $\phi$ function (\kbd{eulerphi}), the $\omega$ and $\Omega$ functions (\kbd{omega} and \kbd{bigomega}), the $\sigma_k$ functions (\kbd{sigma}), which compute sums of $k$-th powers of the positive divisors of a given integer, etc\dots You can compute continued fractions. For example, type \kbd{\b{p} 1000}, then \kbd{contfrac(exp(1))}: you obtain the continued fraction of the base of natural logarithms, which as you can see obeys a very simple pattern. Can you prove it? In many cases, one wants to perform some task only when an arithmetic condition is satisfied. \kbd{gp} gives you the following functions: \kbd{isprime} as mentioned above, \kbd{issquare}, \kbd{isfundamental} to test whether an integer is a fundamental discriminant (i.e.~$1$ or the discriminant of a quadratic field), and the \kbd{forprime}, \kbd{fordiv} and \kbd{sumdiv} loops. Assume for example that we want to compute the product of all the divisors of a positive integer \kbd{n}. The easiest way is to write \bprog p = 1; fordiv(n,d, p *= d); p @eprog\noindent (There is a simple formula for this product in terms of $n$ and the number of its divisors: find and prove it!) The notation \kbd{p *= d} is just a shorthand for \kbd{p = p * d}. If we want to know the list of primes $p$ less than 1000 such that 2 is a primitive root modulo $p$, one way would be to write: \bprog forprime(p=3,1000, if (znprimroot(p) == 2, print(p))) @eprog\noindent % Note that this assumes that \kbd{znprimroot} returns the smallest primitive root, and this is indeed the case. Had we not known about this, we could have written \bprog forprime(p=3,1000, if (znorder(Mod(2,p)) == p-1, print(p))) @eprog\noindent % (which is actually faster since we only compute the order of $2$ in $\Z/p\Z$, instead of looking for a generator by trying successive elements whose orders have to be computed as well.) Once we know a primitive root $g$, we can write any non-zero element of $\Z/p\Z$ as $g^x$ for some unique $x$ in $\Z/(p-1)\Z$. Computing such a discrete logarithm is a hard problem in general, performed by the function \kbd{znlog}. Arithmetic functions related to quadratic fields, binary quadratic forms and general number fields will be seen in the next sections. \section{Performing Linear Algebra} The standard linear algebra routines are available: \kbd{matdet}, \kbd{mateigen} (eigenvectors), \kbd{matker}, \kbd{matimage}, \kbd{matrank}, \kbd{matsolve} (to solve a linear system), \kbd{charpoly} (characteristic polynomial), to name a few. Bilinear algebra over $\R$ is also there: \kbd{qfgaussred} (Gauss reduction), \kbd{qfsign} (signature). You may also type \kbd{?8}. Can you guess what each of these do? Let us see how this works. First, a vector space (or module) is given by a generating set of vectors (often a basis) which are represented as \emph{column} vectors. This set of vectors is in turn represented by the columns of a matrix. Quadratic forms are represented by their Gram matrix. The base field (or ring) can be any ring type PARI supports. However, certain operations are specifically written for a real or complex base field, while others are written for $\Z$ as the base ring. We had some fun with Hilbert matrices and numerical instability a while back, but most of the linear algebra routines are generic. If as before \kbd{h = mathilbert(20)}, we may compute \bprog matdet(h * Mod(1,101)) matdet(h * (1 + O(101^100))) @eprog\noindent in $\Z/101\Z$ and the $p$-adic ring $\Z_{101}$ (to $100$ words of accuracy) respectively. Let \kbd{H = 1/h} the inverse of \kbd{h}: \bprog H = 1/h; \\ @com integral L = primes([10^5, 10^5 + 1000]); \\ @com pick a few primes v = vector(#L, i, matdet(H * Mod(1,L[i]))); centerlift( chinese(v) ) @eprog\noindent returns the determinant of \kbd{H}. (Assuming it is an integer less than half the product of elements of \kbd{L} in absolute value, which it is.) In fact, we computed an homomorphic image of the determinant in a few small finite fields, which admits a single integer representative given the size constraints. We could also have made a single determinant computation modulo a big prime (or pseudoprime) number, e.g \kbd{nextprime(2 * B)} if we know that the determinant is less than \kbd{B} in absolute value. (Why is that $2$ necessary?) By the way, this is how you insert comments in a script: everything following a double backslash, up to the first newline character, is ignored. If you want comments which span many lines, you can brace them between \kbd{/* ... */} pairs. Everything in between will be ignored as well. For instance as a header for the script above you could insert the following: \bprog /* Homomorphic imaging scheme to compute the determinant of a classical * integral matrix. * TODO: Look up the explicit formula */ @eprog\noindent (I hope you did not waste your time copying this nonsense, did you?) \medskip In addition, linear algebra over $\Z$, i.e.~work on lattices, can also be performed. Let us now consider the lattice $\Lambda$ generated by the columns of \kbd{H} in $\Z^{20}\subset\R^{20}$. Since the determinant is non-zero, we have in fact a basis. What is the structure of the finite abelian group $\Z^{20}/\Lambda$? Type \kbd{matsnf(H)}. Wow, 20 cyclic factors. There is a triangular basis for $\Lambda$ (triangular when expressed in the canonical basis), perhaps it looks better than our initial one? Type \kbd{mathnf(H)}. Hum, what if I also want the unimodular transformation matrix? Simple : \kbd{z = mathnf(H, 1);} \kbd{z[1]} is the triangular HNF basis, and \kbd{z[2]} is the base change matrix from the canonical basis to the new one, with determinant $\pm 1$. Try \kbd{matdet(z[2])}, then \kbd{H * z[2] == z[1]}. Fine, it works. And \kbd{z[1]} indeed looks better than \kbd{H}. Can we do better? Perhaps, but then we'd better drop the requirement that the basis be triangular, since the latter is essentially canonical. Type \bprog M = H * qflll(H) @eprog Its columns give an LLL-reduced basis for $\Lambda$ (\kbd{qflll(H)} itself gives the base change matrix). The LLL algorithm outputs a nice basis for a lattice given by an arbitrary basis, where nice means the basis vectors are almost orthogonal and short, with precise guarantees on their relations to the shortest vectors. Not really spectacular on this example, though. Let us try something else, there should be an integer relation between $\log 3$, $\log 5$ and $\log 15$. How to detect it? \bprog u = [log(15), log(5), log(3)]; m = matid(3); m[3,] = round(u * 10^25); v = qflll(m)[,1] \\@com first vector of the LLL-reduced basis u * v @eprog\noindent Pretty close. In fact, \kbd{lindep} automates this kind of search for integer relations; try \kbd{lindep(u)}. Let us come back to $\Lambda$ above, and our LLL basis in \kbd{M}. Type \bprog G = M~*M \\@com Gram matrix m = qfminim(G, norml2(M[,1]), 100, 2); @eprog\noindent This enumerates the vectors in $\Lambda$ which are shorter than the first LLL basis vector, at most 100 of them. The final argument $2$ instructs the function to use a safe (slower) algorithm, since the matrix entries are rather large; trying to remove it should produce an error, in this case. There are $\kbd{m[1]} = 6$ such vectors, and \kbd{m[3]} gives half of them (\kbd{-m[3]} would complete the lot): they are the first 3 basis vectors! So these are optimally short, at least with respect to the Euclidean length. Let us try \bprog m = qfminim(G, norml2(M[,4]), 100, 2); @eprog\noindent (The flag $2$ instructs \kbd{qfminim} to use a different enumeration strategy, which is much faster when we expect more short vectors than we want to store. Without the flag, this example requires several hours. This is an exponential time algorithm, after all!) This time, we find a slew of short vectors; \kbd{matrank(m[3])} says the 100 we have are all included in a 2-dimensional space. Let us try \bprog m = qfminim(G, norml2(M[,4]) - 1, 100000, 2); @eprog\noindent This time we find 50886 vectors of the requested length, spanning a $4$-dimensional space, which is actually generated by \kbd{M[,1]}, \kbd{M[,2]} \kbd{M[,3]} and \kbd{M[,5]}. \section{Using Transcendental Functions} All the elementary transcendental functions and several higher transcendental functions are provided: $\Gamma$ function, incomplete $\Gamma$ function, error function, exponential integral, Bessel functions ($H^1$, $H^2$, $I$, $J$, $K$, $N$), confluent hypergeometric functions, Riemann $\zeta$ function, polylogarithms, Weber functions, theta functions. More will be written if the need arises. In this type of functions, the default precision plays an essential role. In almost all cases transcendental functions work in the following way. If the argument is exact, the result is computed using the current default precision. If the argument is not exact, the precision of the argument is used for the computation. A note of warning however: even in this case the \emph{printed} value is the current real format, usually the same as the default precision. In the present chapter we assume that your machine works with 64-bit long integers. If it is not the case, we leave it to you as a good exercise to make the necessary modifications. Let's assume that we have 38 decimals of default precision (this is what we get automatically at the start of a \kbd{gp} session on 64-bit machines). Type \kbd{e = exp(1)}. We get the number $e=2.718\dots$ to 38 decimals. Let us check how many correct decimals we really have. Change the precision to a substantially higher value, for example by typing \kbd{\b{p} 100}. Then type \kbd{e}, then \kbd{exp(1)} once again. This last value is the correct value of the mathematical constant $e$ to 100 decimals, while the variable \kbd{e} shows the value that was computed to 38 decimals. Clearly they coincide to exactly 29 significant digits. So 38 digits are printed, but how many significant digits are actually contained in the variable \kbd{e}? Type \kbd{\#e} which indicates we have exactly $2$ mantissa words. Since $2\ln(2^{64}) / \ln(10)\approx38.5$ we see that we have 38 or 39 significant digits (on 64-bit machines). \smallskip Come back to 38 decimals (\kbd{\b{p} 38}). If we type \kbd{exp(1.)} you can check that we also obtain 38 decimals. However, type \kbd{f = exp(1 + 1E-40)}. Although the default precision is still 38, you can check using the method above that we have in fact 96 significant digits! The reason is that \kbd{1 + 1E-40} is computed according to the PARI philosophy, i.e.~to the best possible precision. Since \kbd{1E-40} has 39 significant digits and 1 has ``infinite'' precision, the number \kbd{1 + 1E-30} will have $79=39+40$ significant digits, hence \kbd{f} also. Now type \kbd{cos(1E-19)}. The result is printed as $1.0000\dots$, but is of course not exactly equal to 1. Using \kbd{\#\%}, we see that the result has 4 mantissa words, giving us the possibility of having 77 correct significant digits. PARI gives you as much as it can, and since 3 mantissa words would have given you only 57 digits, it uses 4. But why does it give so precise a result? Well, it is the same reason as before. When $x$ is close to 1, $\cos(x)$ is close to $1-x^2/2$, hence the precision is going to be approximately the same as when computing this quantity, here $1-0.5*10^{-38}$ where $0.5*10^{-38}$ is considered with 38 significant digit accuracy. Hence the result will have approximately $38+38=76$ significant digits. This philosophy cannot go too far. For example, when you type \kbd{cos(0)}, \kbd{gp} should give you exactly 1. Since it is reasonable for a program to assume that a transcendental function never gives you an exact result, \kbd{gp} gives you $1.000\dots$ with as many mantissa word as the current precision. \medskip Let's see some more transcendental functions at work. Type \kbd{gamma(10)}. No problem (type \kbd{9!} to check). Type \kbd{gamma(100)}. The number is now written in exponential format because the default accuracy is too small to give the correct result. To get all digits, the most natural solution is to increase the precision; since \kbd{gamma(100)} has 156 decimal digits, type \kbd{\b{p} 170} to be on the safe side, then \kbd{gamma(100)} once again. Another one is to compute \kbd{99!} directly. Try \kbd{gamma(1/2 + 10*I)}. No problem, we have the complex $\Gamma$ function. Now type \bprog t = 1000; z = gamma(1 + I*t) * t^(-1/2) * exp(Pi/2*t) / sqrt(2*Pi) norm(z) @eprog\noindent The latter is very close to 1, in accordance with the complex Stirling formula. \smallskip Let's play now with the Riemann zeta function. First turn on the timer (type \kbd{\#}). Type \kbd{zeta(2)}, then \kbd{Pi\pow 2/6}. This seems correct. Type \kbd{zeta(3)}. All this takes essentially no time at all. However, type \kbd{zeta(3.1)}. You will notice that the time is substantially larger; if your machine is too fast to see the difference, increase the precision to \kbd{\b{p}1000}. This is because PARI uses special formulas to compute \kbd{zeta(n)} when \kbd{n} is an integer. Type \kbd{zeta(1 + I)}. This also works. Now for fun, let us compute in a naive way the first complex zero of \kbd{zeta}. We know that it is of the form $1/2 + i*t$ with $t$ between 14 and 15. Thus, we can use the following series of instructions. But instead of typing them directly, write them into a file, say \kbd{zeta.gp}, then type \kbd{\b{r} zeta.gp} under \kbd{gp} to read it in: \bprog { t1 = 1/2 + 14*I; t2 = 1/2 + 15*I; eps = 1E-50; z1 = zeta(t1); until (norm(z2) < eps, z2 = zeta(t2); if (norm(z2) < norm(z1), t3 = t1; t1 = t2; t2 = t3; z1 = z2 ); t2 = (t1+t2) / 2.; print(t1 ": " z1) ) } @eprog\noindent Don't forget the braces: they tell \kbd{gp} that a sequence of instructions is going to span many lines. We thus obtain the first zero to 25 significant digits. By the way, you don't need to type in the suffix~\kbd{.gp} in the \b{r} command: it is supplied by \kbd{gp} if you forget it. The suffix is not mandatory either, but it is convenient to have all GP scripts labeled in the same distinctive way. Also, some text editors, e.g. Emacs or Vim, will recognize GP scripts as such by their suffix and load special colourful modes. \medskip % As mentioned at the beginning of this tutorial, some transcendental functions can also be applied to $p$-adic numbers. This is as good a time as any to familiarize yourself with them. Type \bprog a = exp(7 + O(7^10)) log(a) @eprog\noindent All seems in order. \bprog b = log(5 + O(7^10)) exp(b) @eprog\noindent Is something wrong? We don't recover the number we started with? This is normal: type \bprog exp(b) * teichmuller(5 + O(7^10)) @eprog\noindent and we indeed recover our initial number. The Teichm\"uller character \kbd{teichmuller(x)} on $\Z_p^*$ is the unique \hbox{$(p-1)$-st} root of unity which is congruent to \kbd{x} modulo $p$, assuming that \kbd{x} is a $p$-adic unit.\smallskip % Let us come back to real numbers for the moment. Type \kbd{agm(1,sqrt(2))}. This gives the arithmetic-geometric mean of 1 and $\sqrt2$, and is the basic method for computing complete elliptic integrals. In fact, type \kbd{Pi/2 / intnum(t=0,Pi/2, 1 / sqrt(1 + sin(t)\pow 2))}, \noindent and the result is the same. The elementary transformation \kbd{x = sin(t)} gives the mathematical equality $$\int_0^1 \dfrac{dx}{\sqrt{1-x^4}} = \dfrac{\pi}{2\text{AGM}(1,\sqrt2)} \enspace,$$ which was one of Gauss's remarkable discoveries in his youth. Now type \kbd{2 * agm(1,I) / (1+I)}. As you see, the complex AGM also works, although one must be careful with its definition. The result found is almost identical to the previous one. Do you see why? Finally, type \kbd{agm(1, 1 + 7 + O(7\pow 10))}. So we also have $p$-adic AGM. Note however that since the square root of a $p$-adic number is not in general an element of the same $p$-adic field, only certain $p$-adic AGMs can be computed. In addition, when $p=2$, the congruence restriction is that \kbd{agm(a,b)} can be computed only when \kbd{a/b} is congruent to 1 modulo $16$, and not 8 as could be expected.\smallskip % Now type \kbd{?3}. This gives you the list of all transcendental functions. Instead of continuing with more examples, we suggest that you experiment yourself with this list. Try integer, real, complex and $p$-adic arguments. You will notice that some have not been implemented (or do not have a reasonable definition). \section{Using Numerical Tools} Although not written to be a numerical analysis package, PARI can nonetheless perform some numerical computations. Since linear algebra and polynomial computations are treated somewhere else, this section focuses on solving equations and various methods of summation. You of course know the formula $\pi = 4(1-\dfrac13+\dfrac15-\dfrac17+\cdots)$ which is deduced from the power series expansion of \kbd{atan(x)}. You also know that $\pi$ cannot be computed from this formula, since the convergence is so slow. Right? Wrong! Type \bprog \p 100 4 * sumalt(k=0, (-1)^k/(2*k + 1)) @eprog\noindent In a split second, we get $\pi$ to 100 significant digits (type \kbd{Pi} to check). Similarly, try \bprog sumpos(k=1, k^-2) @eprog\noindent Although once again the convergence is slow, the summation is rather fast; compare with the exact result \kbd{Pi\pow 2/6}. This is less impressive because a bit slower than for alternating sums, but still useful. Even better, \kbd{sumalt} can be used to sum divergent series! Type \bprog zet(s) = sumalt(k=1, (-1)^(k-1) / k^s) / (1 - 2^(1-s)) @eprog\noindent Then for positive values of \kbd{s} different from 1, \kbd{zet(s)} is equal to \kbd{zeta(s)} and the series converges, albeit slowly; \kbd{sumalt} doesn't care however. For negative \kbd{s}, the series diverges, but \kbd{zet(s)} still gives the correct result! (Namely, the value of a suitable analytic continuation.) Try \kbd{zet(-1)}, \kbd{zet(-2)}, \kbd{zet(-1.5)}, and compare with the corresponding values of \kbd{zeta}. You should not push the game too far: \kbd{zet(-100)}, for example, gives a completely wrong answer. Try \kbd{zet(I)}, and compare with \kbd{zeta(I)}. Even (some) complex values work, although the sum is not alternating any more! Similarly, try \bprog sumalt(n=1, (-1)^n / (n+I)) @eprog \medskip More traditional functions are the numerical integration functions. Try \kbd{intnum(t=1,2, 1/t)} and presto! you get 100 decimals of $\log(2)$. Look at Chapter 3 to see the available integration functions. With PARI, however, you can go further since complex types are allowed. For example, assume that we want to know the location of the zeros of the function $h(z)=e^z-z$. We use Cauchy's theorem, which tells us that the number of zeros in a disk of radius $r$ centered around the origin is equal to $$\dfrac{1}{2i\pi}\int_{C_r}\dfrac{h'(z)}{h(z)}\,dz\enspace,$$ where $C_r$ is the circle of radius $r$ centered at the origin. The function we want to integrate is \bprog fun(z) = my(u = exp(z)); (u-1) / (u-z) @eprog\noindent (Here \kbd{u} is a local variable to the function \kbd{f}: whenever a function is called, \kbd{gp} fills its argument list with the actual arguments given, and initializes the other declared parameters and local variables to 0. It will then restore their former values upon exit. If we had not declared \kbd{u} in the function prototype, it would be considered as a global variable, whose value would be permanently changed. It is not mandatory to declare in this way all parameters, but beware of side effects!) Type now: \bprog zero(r) = r/(2*Pi) * intnum(t=0, 2*Pi, real( fun(r*exp(I*t)) * exp(I*t) )) @eprog The function \kbd{zero(r)} will count the number of zeros of \kbd{fun} whose modulus is less than \kbd{r}: we simply made the change of variable $z = r*\exp(i*t)$, and took the real part to avoid integrating the imaginary part. Actually, there is a built-in function \kbd{intcirc} to integrate over a circle, yielding the much simpler: \bprog zero2(r) = intcirc(z=0, r, fun(z)) @eprog (This is a little faster than the previous implementation, and no less accurate.) We may type \kbd{\b{p} 9} since we know that the result is a small integer (but the computations should be instantaneous even at \b{p} 100 or so), then \kbd{zero(1)}, \kbd{zero(1.5)}. The result tells us that there are no zeros inside the unit disk, but that there are two (necessarily complex conjugate) in the annulus $1<|z|<1.5$. For the sake of completeness, let us compute them. Let $z = x+iy$ be such a zero, with $x$ and $y$ real. Then the equation $e^z-z=0$ implies, after elementary transformations, that $e^{2x}=x^2+y^2$ and that $e^x\cos(y)=x$. Hence $y=\pm\sqrt{e^{2x}-x^2}$ and hence $e^x\cos(\sqrt{e^{2x}-x^2})=x$. Therefore, type \bprog fun(x) = my(u = exp(x)); u * cos(sqrt(u^2 - x^2)) - x @eprog\noindent Then \kbd{fun(0)} is positive while \kbd{fun(1)} is negative. Come back to precision 38 and type \bprog x0 = solve(x=0,1, fun(x)) z = x0 + I*sqrt(exp(2*x0) - x0^2) @eprog\noindent which is the required zero. As a check, type \kbd{exp(z) - z}. Of course you can integrate over contours which are more complicated than circles, but you must perform yourself the variable changes, as we have done above to reduce the integral to a number of integrals on line segments. \smallskip % The example above also shows the use of the \kbd{solve} function. To use \kbd{solve} on functions of a complex variable, it is necessary to reduce the problem to a real one. For example, to find the first complex zero of the Riemann zeta function as above, we could try typing \kbd{solve(t=14,15, real( zeta(1/2 + I*t) ))}, \noindent but this does not work because the real part is positive for $\kbd{t}=14$ and $15$. As it happens, the imaginary part works. Type \kbd{solve(t=14,15, imag( zeta(1/2 + I*t) ))}, \noindent and this now works. We could also narrow the search interval and type for instance \kbd{solve(t=14,14.2, real( zeta(1/2 + I*t) ))} \noindent which would also work. \section{Polynomials} First a word of warning: it is essential to understand the difference between exact and inexact objects. Try \bprog gcd(x - Pi, x^2 - 6*zeta(2)) @eprog\noindent We return a trivial GCD because the notion of GCD for non-exact polynomials doesn't make much sense. A better quantitative approach is to use \bprog polresultant(x - Pi, x^2 - 6*zeta(2)) @eprog\noindent A result close to zero shows that the GCD is non-trivial for small deformations of the inputs. Without telling us what it is, of course. This being said, we will mostly use polynomials (and power series) with exact coefficients in our examples.\smallskip The simplest way to input a polynomial, is to simply write it down, or use an explicit formula for the coefficients and the function \kbd{sum}: \bprog T = 1 + x^2 + 27*x^10; T = sum(i = 1, 100, (i+1) * x^i); @eprog\noindent but it is in much more efficient to create a vector of coefficients then convert it to a polynomial using \kbd{Pol} or \kbd{Polrev} (\kbd{Pol([1,2])} is $x+2$, \kbd{Polrev([1,2]) is $2x + 1$}) : \bprog T = Polrev( vector(100, i, i) ); for (i=1, 10^4, Polrev( vector(100, i, i) ) ) \\@com time: 60ms for (i=1, 10^4, sum(i = 1, 100, (i+1) * x^i) ) \\@com time: 1,74ms @eprog\noindent The reason for the discrepancy is that the explicit summation (of densely encoded polynomials) is quadratic in the degree, whereas creating a vector of coefficients then converting it to a polynomial type is linear. We also have a few built-in classical polynomial families. Consider the $15$-th cyclotomic polynomial, \bprog pol = polcyclo(15) @eprog\noindent which is of degree $\varphi(15)=8$. Now, type \bprog r = polroots(pol) @eprog\noindent We obtain the 8 complex roots of \kbd{pol}, given to 38 significant digits. To see them better, type \b{b}: they are given as pairs of complex conjugate roots, in a random order. The only ordering done by the function \kbd{polroots} concerns the real roots, which are given first, and in increasing order. The roots of \kbd{pol} are by definition the primitive $15$-th roots of unity. To check this, simply type \kbd{rc = r\pow 15}. Why, we get an error message! Fair enough, vectors cannot be multiplied, even less raised to a power. However, type \bprog rc = r^15. @eprog\noindent without forgetting the `\kbd{.}' at the end. Now it works, because powering to a non-integer exponent is a transcendental function and hence is applied termwise. Note that the fact that $15.$ is a real number which is representable exactly as an integer has nothing to do with the problem. We see that the components of the result are very close to 1. It is however tedious to look at all these real and imaginary parts. It would be impossible if we had many more. Let's do it automatically. Type \bprog rr = round(rc) sqrt( norml2(rc - rr) ) @eprog\noindent We see that \kbd{rr} is indeed all 1's, and that the $L^2$-norm of \kbd{rc - rr} is around $2.10^{-37}$, reasonable enough when we work with 38 significant digits! Note that the function \kbd{norml2}, contrary to what its name implies, does not give the $L^2$ norm but its square, hence we must take the square root. Well, this is not absolutely necessary in the present case! In fact, \kbd{round} itself already provides a built-in rough approximation of the error: \bprog rr = round(rc, &e) @eprog\noindent Now \kbd{e} contains the number of error bits when rounding \kbd{rc} to \kbd{rr}; in other words the sup norm of $\kbd{rc} - \kbd{rr}$ is bounded by $2^{-\kbd{e}}$. % \smallskip Now type \bprog pol = x^5 + x^4 + 2*x^3 - 2*x^2 - 4*x - 3 factor(pol) factor( poldisc(pol) ) fun(p) = factorpadic(pol,p,10); @eprog\noindent The polynomial \kbd{pol} factors over $\Q$ (or $\Z$) as a product of two factors, and the primes dividing its discriminant are $11$, $23$ and $37$. We also created a function \kbd{fun(p)} which factors \kbd{pol} over $\Q_p$ to $p$-adic precision 10. Type \bprog fun(5) fun(11) fun(23) fun(37) @eprog\noindent to see different splittings. Similarly, type \bprog lf(p) = lift( factormod(pol,p) ); lf(2) lf(11) lf(23) lf(37) @eprog\noindent which show the different factorizations, this time over $\F_p$. In fact, even better: type successively \bprog T = ffinit(3,3, 't) \\@com we want \kbd{t} to be a free variable fq = factormod(pol, [T,3]) liftall(fq) @eprog\noindent \kbd{T}, which is actually \kbd{t\pow 3 + t\pow 2 + t + 2} (with intmod coefficients), is defined above to be an irreducible polynomial of degree $3$ over $\F_3$. This code snippet factors the polynomial \kbd{pol} over the finite field $\F_3[t]/(T)$. This is of course a form of the field $\F_{27}$. Note that we introduced a new variable $t$ to express elements in this non-prime field. There is a crucial rule in all routines involving relative extensions: the variable attached to the base field is required to have lower priority than the variables of polynomials whose coefficients are taken in that base field. Have a look at the section on \emph{Variable priorities} in the user's manual (see ``The GP programming language''). A simpler way to accomplish the above, using \typ{FFELT}s is \bprog g = ffgen(3^3, 't); factormod(pol, g) @eprog\noindent It is also possible to use \kbd{factor}: \bprog factormod(pol * g^0) @eprog\noindent Multiplying by $g^0 = 1$ seems to do ``nothing'', but it has the interesting effect of mapping all coefficients to $\F_{27}$. The generic function \kbd{factor} then does the right thing. (Typing \kbd{factor(pol)} directly would factor it over $\Q$, not what we wanted.) Similarly, type \bprog pol2 = x^4 - 4*x^2 + 16 fn = lift( factornf(pol2, t^2 + 1) ) @eprog\noindent and we get the factorization of the polynomial \kbd{pol2} over the number field defined by $t^2+1$, i.e.~over $\Q(i)$. Without the \kbd{lift}, the result would involve number field elements as \typ{POLMOD}s of the form \kbd{Mod(1+t, t\pow2+1)}, which are more explicit but much less readable. \smallskip To summarize, in addition to being able to factor integers, you can factor polynomials over $\C$ and $\R$ using \kbd{polroots}, over finite fields using \kbd{factormod}, over $\Q_p$ using \kbd{factorpadic}, over $\Q$ using \kbd{factor}, and over number fields using \kbd{factornf} or \kbd{nffactor}. Note however that \kbd{factor} itself will guess intelligently over which ring you want to factor: try \bprog pol = x^2 + 1; factor(pol) factor(pol *1.) factor(pol * (1 + 0*I)) factor(pol * (1 + 0.*I)) factor(pol * Mod(1,2)) factor(pol * Mod(1, Mod(1,3)*(t^2+1))) pol2 = x^2 + y^2; factor(pol2) factor(pol2 * Mod(1,5)) @eprog\noindent In the present version \vers{}, it is not possible to factor over other base rings than the ones mentioned above, but multivariate polynomials over those rings are allowed as shown in the last examples. Other functions related to factoring are \kbd{padicappr}, \kbd{polrootsmod}, \kbd{polrootspadic}, \kbd{polsturm}. Play with them a little. Finally, type \bprog polsym(pol2, 20) @eprog\noindent where \kbd{pol2} was defined above. This gives the sum of the $k$-th powers of the roots of \kbd{pol2} up to $k=20$, of course computed using Newton's formula and not using \kbd{polroots}. You notice that every odd sum is zero (expected, since the polynomial is even), but also that the signs follow a regular pattern and that the (non-zero) absolute values are powers of 2. This is true: prove it, and more precisely find an explicit formula for the $k$-th symmetric power not involving (non-rational) algebraic numbers. \section{Power series} Now let's play with power series as we have done at the beginning. Type \bprog N = 39; 8*x + prod(n=1,N, if(n%4, 1 - x^n, 1), 1 + O(x^(N+1)))^8 @eprog\noindent Apparently, only even powers of \kbd{x} appear. This is surprising, but can be proved using the theory of modular forms. Note that we initialize the product to \kbd{1 + O(x\pow (N+1))}, otherwise the whole computation would be done with polynomials; this would first have been slightly slower and also totally useless since the coefficients of \kbd{x\pow (N+1)} and above are irrelevant anyhow if we stop the product at $\kbd{n} = \kbd{N}$. While we are on the subject of modular forms (which, together with Taylor series expansions are another great source of power series), type \bprog \ps 122 \\@com shortcut for \kbd{default(seriesprecision, 122)} d = x * eta(x)^24 @eprog\noindent This gives the first 122 terms of the Fourier series expansion of the modular discriminant function $\Delta$ of Ramanujan. Its coefficients give by definition the Ramanujan $\tau$ function, which has a number of marvelous properties (look at any book on modular forms for explanations). We would like to see its properties modulo 2. Type \kbd{d\%2}. Hmm, apparently PARI doesn't like to reduce coefficients of power series, or polynomials for that matter, directly. Can we do it without writing a little program? No problem. Type instead \bprog lift(Mod(1,2) * d) centerlift(Mod(1,3) * d) @eprog\noindent and now this works like a charm. The pattern in the first result is clear; the pattern is less clear in the second result, but nonetheless there is one. Of course, it now remains to prove it (see Antwerp III or your resident modular forms guru). \section{Working with Elliptic Curves} Now we are getting to more complicated objects. Just as with number fields which we will meet later on, the first thing to do is to initialize them. That's because a lot of data will be needed repeatedly, and it's much more convenient to have it ready once and for all. Here, this is done with the function \kbd{ellinit}. So type \bprog e0 = ellinit([6,-3,9,-16,-14]) @eprog This computes a number of things about the elliptic curve defined by the affine equation % $$ y^2+6xy+9y = x^3-3x^2-16x-14\enspace. $$ % It is not that clear what all these funny numbers mean, except that we recognize the first few of them as the coefficients we just input. To retrieve meaningful information from such complicated objects (and number fields will be much worse), one uses so-called \emph{member functions}. Type \kbd{?.} to get a complete list. Whenever \kbd{ell} appears in the right hand side, we can apply the corresponding function to an object output by \kbd{ellinit}. (I'm sure you know how the other \kbd{init} functions will be called now, don't you? Oh, by the way, neither \kbd{clgpinit} nor \kbd{pridinit} exist.) Let's try it. The discriminant \kbd{e0.disc} is equal to 37, hence the conductor of the curve is 37. Of course in general it is not so trivial. In fact, although the equation of the curve is clearly minimal (since the discriminant is $12$th-power-free), it is not in standard reduced form, so type \bprog e = ellminimalmodel(e0) @eprog\noindent which gives the \kbd{ell} structure attached to the standard model, exactly as if we had used \kbd{ellinit} on a reduced equation. For some related data, type \bprog gr = ellglobalred(e0) @eprog\noindent The first component \kbd{gr[1]} tells us that the conductor is 37 as we already knew. The second component is a 4-component vector which allows us to get the minimal equation: in fact \kbd{e} is \kbd{ellchangecurve(e0, gr[2])}. Type \bprog q0 = [-2,2] ellisoncurve(e0, q0) q = ellchangepoint(q0,gr[2]) ellisoncurve(e, q) @eprog\noindent The point \kbd{q0} is on the curve, as checked by \kbd{ellisoncurve}, and we transferred it onto the minimal model \kbd{e}, using \kbd{ellchangepoint} and the change of variable computed above. Note that \kbd{ellchangepoint()} is unusual among the elliptic curve functions in that it does not take an \kbd{ell} structure as its first argument: in \kbd{gp}, points do not ``know'' which curve they are on, but to move a point from one model to another we only need to know the coordinates of the point and the transformation data here stored in \kbd{gr[2]}. Also, the point at infinity is represented as \kbd{[0]} on all elliptic curves; this is the identity for the group law. Here, \kbd{q=[0,0]} obviously lies on \kbd{e}, which has equation $y^2+y = x^3-x$. Let us now play a little with points on \kbd{e}. The group law on an elliptic curve is implemented with the functions \kbd{elladd} for addition, \kbd{ellsub} for subtraction and \kbd{ellmul} for multiplication by an integer. For example, the negative of \kbd{q} is \kbd{ellsub(e,[0],q)}, and the double is obtained either as \kbd{ellmul(e,q,2)} or as \kbd{elladd(e,q,q)}. Now \kbd{q} may be a torsion point. Type \kbd{ellheight(e, q)}, which computes the canonical Neron-Tate height of \kbd{q}. Note that \kbd{ellheight} does not assume that \kbd{e} is \emph{minimal}! (Although it is, making things a little faster.) This is non-zero, hence \kbd{q} is not torsion. To see this even better, type \bprog for(k = 1, 20, print(ellmul(e, q, k))) @eprog\noindent and we see the characteristic parabolic explosion of the size of the points. (And another proof that \kbd{q} is not torsion, assuming Mazur's bound on the size of the rational torsion.) We could can also type \kbd{ellorder(e, q)} which returns 0, telling us yet again that \kbd{q} is non-torsion. As a consistency check, type \bprog ellheight(e, ellmul(e, q,20)) / ellheight(e, q) @eprog\noindent We indeed find $400=20^2$ as it should be. Notice how (almost) all those \kbd{ell}--prefixed functions take our elliptic curve as a first argument? This will be true with number fields as well: whatever object was initialized by an $ob$--\kbd{init} function will have to be used as a first argument of all the $ob$--prefixed functions. Conversely, you won't be able to use any such high-level function before you correctly initialize the relevant object. \smallskip Ok, let's try another curve. Type \bprog E = ellinit([0,-1,1,0,0]) q = [0,0]; ellheight(E, q) @eprog\noindent This corresponds to the equation $y^2+y = x^3-x^2$ and an obvious rational point on it. Again from the discriminant we see that the conductor is equal to 11, and if you type \kbd{ellminimalmodel(E)} you will see that the equation for \kbd{E} is minimal. This time the height is exactly zero, hence \kbd{q} must be a torsion point. Indeed, typing \bprog for(k=1, 5, print(ellmul(E, q,k))) ellorder(E, q) \\@com simpler @eprog\noindent we see in two different ways that \kbd{q} is a point of order 5. Moreover, typing \bprog elltors(E) @eprog\noindent shows that \kbd{q} generates all the torsion of \kbd{E}, which is cyclic of order~$5$. \smallskip Let's try still another curve, $y^2+y = x^3-7x+6$: \bprog e = ellinit([0,0,1,-7,6]) ellglobalred(e) @eprog\noindent As before, this is a minimal equation; now the conductor is 5077. There are some trivial integral points on this curve, but let's try to be more systematic. Typing \bprog elltors(e) @eprog\noindent shows that the torsion subgroup is trivial, so we don't have to worry about torsion points. Next, the function \kbd{ellratpoints} allows us to find rational points of small height \bprog v = ellratpoints(e,1000) @eprog\noindent The vector $v$ contains all 130 rational points $(x,y)$ on the curve whose $x$-coordinate is $n/d$ with $|n|$ and $|d|$ both less than $1000$. Note that \kbd{ellratpoints(e,10\pow6)} takes less than 1 second, and produces 344 points. Of course, these are grouped by pairs: if $(x,y)$ is on the curve, its opposite is $(x,-y-1)$ as \bprog ellneg(e, ['x,'y]) @eprog\noindent shows. Note that there is no problem with manipulating points with formal coordinates. This is large for a curve having such a small conductor. So we suspect (if we do not know already, since this curve is quite famous!) that the rank of this curve must be large. Let's try and put some order into this. First, we eliminate one element in each pair of opposite points: \bprog v = vecsort(v, 1, 8) @eprog\noindent The argument $1$ specifies a comparison function: we sort the points by first coordinate only, in particular two points with the same $x$-coordinate compare as equal; the $8$ flag eliminates ``duplicates''. The same effect could be obtained in a more verbose way using an inline anonymous function \bprog v = vecsort(v, (P,Q) -> sign(P[1]-Q[1]), 8) @eprog\noindent We now order the points according to their canonical height: \bprog hv = [ ellheight(e,P) | P <- v ]; v = vecextract(v, vecsort(hv,,1)) \\ indirect sort wrt h, then permute @eprog\noindent It seems reasonable to take the numbers with smallest height as possible generators of the Mordell-Weil group. Let's try the first four: type \bprog m = ellheightmatrix(e, v[1..4]); matdet(m) @eprog\noindent Since the curve has no torsion, the determinant being close to zero implies that the first four points are dependent. To find the dependency, it is enough to find the kernel of the matrix \kbd{m}. So type \kbd{matker(m)}: we indeed get a non-trivial kernel, and the coefficients are close to integers. Typing \kbd{elladd(e, v[1],v[3])} does indeed show that it is equal to \kbd{v[4]}. Taking any other four points, we seem to always find a dependency. Let's find all dependencies. Type \bprog vp = v[1..3]; m = ellheightmatrix(e,vp); matdet(m) @eprog\noindent This is now clearly non-zero so the first 3 points are linearly independent, showing that the rank of the curve is at least equal to 3. (In fact, \kbd{e} is the curve of smallest conductor having rank 3.) We would like to see whether the other points are dependent: if \kbd{Q} is some point which is dependent on \kbd{v[1],v[2]} and \kbd{v[3]} and \bprog c = [ellheight(e, P, Q) | P <- vp]~ @eprog\noindent then \kbd{m\pow(-1) * c} will give the coefficients of the dependence relation. If these coefficients are not close to integers, then there is no dependency, otherwise we can round and check rigourously using a function such as the following: \bprog ellcomb(e, P, L) = { my (Q = [0]); for (i = 1, #P, Q = elladd(e, Q, ellmul(e, P[i], L[i]))); return (Q); } @eprog\noindent This is safer than using the \kbd{matker} function. Thus, type \bprog mi = m^(-1); w = vector(#v, k, mi * [ellheight(e, P, v[k]) | P <- vp]~) wr = round(w, &e) @eprog\noindent We ``see'' that the coefficients are all very close to integers, and we quantified it with the last instruction: \kbd{wr} is the vector expressing all the components of \kbd{v} on its first 3, and $2^{-e}$ gives an upper bound on the maximum distance to an integer. The rigorous check is positive: \bprog for (i=1, #w, if (v[i] != ellcomb(e,vp,wr[i]), error(i))); @eprog No error! We are thus led to strongly believe that the curve has rank exactly 3, with generators \kbd{v[1]}, \kbd{v[2]} and \kbd{v[3]}, and this can be proved to be the case. Two remarks: (1) Using the height pairing to find dependence relations as we have done only finds relations modulo torsion; but in this example, the curve has trivial torsion, as we checked earlier. (2) In the above calculation we were lucky that all the \kbd{v[j]} were $\Z$-linear combinations of \kbd{v[1]}, \kbd{v[2]} and \kbd{v[3]} and not just $\Q$-linear combinations; in general the results in $w$ might have given a vector of rationals: if $k\ge2$ is minimal such that $kQ$ is in the subgroup generated by \kbd{v[1]}, \kbd{v[2]} and \kbd{v[3]}, then the entries of \kbd{matsolve(m, ellbil(e, vp,Q))} will be rationals with common denominator~$k$. This can be detected by using \kbd{bestappr} instead of \kbd{round} in the above. \smallskip Let us explore a few more elliptic curve related functions. Keep our curve \kbd{e} of rank 3, and type \bprog v1 = [1,0]; z1 = ellpointtoz(e, v1) v2 = [2,0]; z2 = ellpointtoz(e, v2) @eprog\noindent We thus get the complex parametrization of the curve. To add the points \kbd{v1} and \kbd{v2}, we should of course type \kbd{elladd(e, v1,v2)}, but we can also type \kbd{ellztopoint(e, z1 + z2)} which has the disadvantage of giving complex numbers, but illustrates how the group law on \kbd{e} is obtained from the addition law on $\C$. Type \bprog f = x * Ser(ellan(e, 30)) @eprog\noindent This gives a power series which is the Fourier expansion of a modular form of weight 2 for $\Gamma_0(5077)$. (This has been proved directly, before Wiles's general result.) In fact, to find the modular parametrization of the curve, type \bprog modul = elltaniyama(e) u = modul[1]; v = modul[2]; @eprog\noindent We can check in various ways that this indeed parametrizes the curve: \bprog (v^2 + v) - (u^3 - 7*u + 6) @eprog\noindent is close to $0$ for instance, or simply that \kbd{ellisoncurve(e,modul)} returns~$1$. Now type \bprog x * u' / (2*v + 1) @eprog\noindent and we see that this is equal to the modular form \kbd{f} found above; the quote \kbd{'} tells \kbd{gp} to take the derivative of the expression with respect to its main variable. The functions \kbd{u} and \kbd{v}, considered on the upper half plane with $x=e^{2i\pi\tau}$, are in fact modular \emph{functions} for $\Gamma_0(5077)$. \smallskip The function \kbd{ellan(e, 30)} gives the first~$30$ coefficients $a_n$ of the $L$-series of \kbd{e}. One can also ask for a single coefficient: the millionth is \kbd{ellak(e, 10\pow 6)}. Note however that calling \kbd{ellan(e,100000)} is much faster than the equivalent \kbd{vector(100000,k,ellak(e,k))}. For a prime~\kbd{p}, \kbd{ellap(e,p)} is equivalent to \kbd{ellak(e,p)}; this is the integer $a_p$ such that the number of points on \kbd{e} over $\F_p$ is $1+p-a_p$. (With the standard PARI distribution, \kbd{ellap} is the only way to obtain the order of an elliptic curve over $\F_p$ in \kbd{gp}. The external package \kbd{ellsea} provides much more efficient routines.) Finally, let us come back to the curve \kbd{E} defined above by \kbd{E = ellinit([0,-1,1,0,0])}, which had an obvious rational $5$-torsion point. The sign of the functional equation, given by \kbd{ellrootno(E)}, is $+1$. Assuming the rank parity conjecture, it follows that the Mordell-Weil group of $E$ has even rank. The value of the L-function of \kbd{E} at 1 \bprog ls = lfun(E, 1) @eprog\noindent is definitely non-zero, so \kbd{E} has rank $0$. According to the Birch and Swinnerton-Dyer conjecture, which is proved for this curve, \kbd{ls} is given by the following formula (in this case): % \def\sha{\hbox{III}} $$L(E,1)=\dfrac{\Omega\cdot c\cdot|\sha|}{|E_{\text{tors}}|^2}\enspace,$$ % where $\Omega$ is the real period of $E$, $c$ is the global Tamagawa number, $|\sha|$ is the order of the Tate-Shafarevich group, and $E_{\text{tors}}$ is the torsion group of $E$. Now we know many of these quantities: $\Omega$ is equal to \kbd{E.omega[1]} The global Tamagawa number $c$ is given by \kbd{elltamagawa(E)} and is $1$ We already know that the torsion subgroup of $E$ contains a point of order 5, and typing \kbd{elltors(E)} shows that it is of order exactly 5. So type \bprog ls * 25/E.omega[1] @eprog\noindent This shows that $\sha$ must be the trivial group. A short hand for $\dfrac{\Omega\cdot c}{|E_{\text{tors}}|^2}$ is \kbd{ellbsd(E)}, so the previous line can be written as \bprog ls / ellbsd(E) @eprog For more detailed information on the local reduction of an elliptic curve at a specific prime~\kbd{p}, use the function \kbd{elllocalred(E,p)}; the second component gives the Kodaira symbol in an encoded form. See the manual or online help for details. \section{Working in Quadratic Number Fields} The simplest of all number fields outside $\Q$ are quadratic fields and are the subject of the present section. We shall deal in the next one with general number fields (including $\Q$ and quadratic fields!), and one should be aware that all we will see now has a more powerful, in general easier to use, equivalent in the general context. But possibly much slower. Such fields are characterized by their discriminant. Even better, any non-square integer $D$ congruent to 0 or 1 modulo 4 is the discriminant of a specific order in a quadratic field. We can check whether this order is maximal with \kbd{isfundamental(D)}. Elements of a quadratic field are of the form $a+b\omega$, where $\omega$ is chosen as $\sqrt{D}/2$ if $D$ is even and $(1+\sqrt{D})/2$ if $D$ is odd, and are represented in PARI by quadratic numbers. To initialize working in a quadratic order, one starts by the command \kbd{w = quadgen($D$,'w)}. This sets \kbd{w} equal to $\omega$ as above, and is printed \kbd{w}. If you need several quadratic orders at the same time, you can use different variable names: \bprog w1 = quadgen(-23,'w1) w2 = quadgen(-15,'w1) @eprog\noindent \smallskip % In addition to elements of a quadratic order, we also want to be able to handle ideals of such orders. In the quadratic case, it is equivalent to handling binary quadratic forms. For negative discriminants, quadratic forms are triples $(a,b,c)$ representing the form $ax^2+bxy+cy^2$. Such a form will be printed as, and can be created by, \kbd{Qfb($a$,$b$,$c$)}. Such forms can be multiplied, divided, powered as many PARI objects using the usual operations, and they can also be reduced using the function \kbd{qfbred} (it is not the purpose of this tutorial to explain what all these things mean). In addition, Shanks's NUCOMP algorithm has been implemented (functions \kbd{qfbnucomp} and \kbd{qfbnupow}), and this is usually a little faster. Finally, you have at your disposal the functions \kbd{qfbclassno} which (\emph{usually}) gives the class number, the function \kbd{qfbhclassno} which gives the Hurwitz class number, and the much more sophisticated \kbd{quadclassunit} function which gives the class number and class group structure. Let us see examples of all this at work. Type \kbd{qfbclassno(-10007)}. \kbd{gp} tells us that the result is 77. However, you may have noticed in the explanation above that the result is only \emph{usually} correct. This is because the implementers of the algorithm have been lazy and have not put the complete Shanks algorithm into PARI, causing it to fail in certain very rare cases. In practice, it is almost always correct, and the much more powerful \kbd{quadclassunit} program, which \emph{is} complete (at least for fundamental discriminants) can give confirmation; but now, under the Generalized Riemann Hypothesis! So we may be a little suspicious of this class number. Let us check it. First, we need to find a quadratic form of discriminant $-10007$. Since this discriminant is congruent to 1 modulo 8, we know that there is an ideal of norm equal to 2, i.e.~a binary quadratic form $(a,b,c)$ with $a=2$. To compute it we type \kbd{f = qfbprimeform(-10007, 2)}. OK, now we have a form. If the class number is correct, the very least is that this form raised to the power 77 should equal the identity. Type \kbd{f\pow 77}. We get a form starting with 1, i.e.~the identity. Raising \kbd{f} to the powers 11 and 7 does not give the identity, thus we now know that the order of \kbd{f} is exactly 77, hence the class number is a multiple of 77. But how can we be sure that it is exactly 77 and not a proper multiple? Well, type \bprog sqrt(10007)/Pi * prodeuler(p=2,500, 1./(1 - kronecker(-10007,p)/p)) @eprog\noindent This is nothing else than an approximation to the Dirichlet class number formula. The function \kbd{kronecker} is the Kronecker symbol, in this case simply the Legendre symbol. Note also that we have written \kbd{1./(1 - \dots)} with a dot after the first 1. Otherwise, PARI may want to compute the whole thing as a rational number, which would be terribly long and useless. In fact PARI does no such thing in this particular case (\kbd{prodeuler} is always computed as a real number), but you never know. Better safe than sorry! We find 77.77, pretty close to 77, so things seem in order. Explicit bounds on the prime limit to be used in the Euler product can be given which make the above reasoning rigorous. Let us try the same thing with $D=-3299$. \kbd{qfbclassno} and the Euler product convince us that the class number must be 27. However, we get stuck when we try to prove this in the simple-minded way above. Indeed, we type \kbd{f = qfbprimeform(-3299, 3)} (2 is not the norm of a prime ideal but 3 is), and we see that \kbd{f} raised to the power 9 is equal to the identity. This is the case for any other quadratic form we choose. So we suspect that the class group is not cyclic. Indeed, if we list all 9 distinct powers of \kbd{f}, we see that \kbd{qfbprimeform(-3299, 5)} is not on the list, although its cube is as it must. This implies that the class group is probably equal to a product of a cyclic group of order 9 by a cyclic group of order 3. The Euler product plus explicit bounds prove this. Another way to check it is to use the \kbd{quadclassunit} function by typing for example \bprog quadclassunit(-3299) @eprog\noindent Note that this function cheats a little and could still give a wrong answer, even assuming GRH: the forms given could generate a strict subgroup of the class group. If we want to use proven bounds under GRH, we have to type \bprog quadclassunit(-3299,,[1,6]) @eprog\noindent The double comma \kbd{,,} is not a typo, it means we omit an optional second argument. As we want to use the optional \emph{third} argument, we have to indicate to \kbd{gp} we skipped this one. Now, if we believe in GRH, the class group is as we thought (see Chapter 3 for a complete description of this function). Note that using the even more general function \kbd{bnfinit} (which handles general number fields and gives more complicated results), we could \emph{certify} this result, i.e~remove the GRH assumption. Let's do it, type \bprog bnf = bnfinit(x^2 + 3299); bnfcertify(bnf) @eprog A non-zero result (here 1) means that everything is ok. Good, but what did we certify after all? Let's have a look at this \kbd{bnf} (just type it!). Enlightening, isn't it? Recall that the \kbd{init} functions (we've already seen \kbd{ellinit}) store all kind of technical information which you certainly don't care about, but which will be put to good use by higher level functions. That's why \kbd{bnfcertify} could not be used on the output of \kbd{quadclassunit}: it needs much more data. To extract sensible information from such complicated objects, you must use one of the many \emph{member functions} (remember: \kbd{?.} to get a complete list). In this case \kbd{bnf.clgp} which extracts the class group structure. This is much better. Type \kbd{\%.no} to check that this leading 27 is indeed what we think it is and not some stupid technical parameter. Note that \kbd{bnf.clgp.no} would work just as well, or even \kbd{bnf.no}! As a last check, we can request a relative equation for the Hilbert class field of $\Q(\sqrt{-3299})$: type \kbd{quadhilbert(-3299)}. It is indeed of degree 27 so everything fits together. \medskip % Working in real quadratic fields instead of complex ones, i.e.~with $D>0$, is not very different. The same \kbd{quadgen} function is used to create elements. Ideals are again represented by binary quadratic forms $(a,b,c)$, this time indefinite. However, the Archimedean valuations of the number field start to come into play, hence in fact quadratic forms with positive discriminant will be represented as a quadruplet $(a,b,c,d)$ where the quadratic form itself is $ax^2+bxy+cy^2$ with $a$, $b$ and $c$ integral, and $d\in \R$ is a ``distance'' component, as defined by Shanks and Lenstra. To create such forms, one uses the same function as for definite ones, but you can add a fourth (optional) argument to initialize the distance: \kbd{q = Qfb($a$, $b$, $c$, $d$)}. If the discriminant of \kbd{poldisc(q)} is negative, $d$ is silently discarded. If you omit it, this component is set to \kbd{0.} (i.e.~a real zero to the current precision). Again these forms can be multiplied, divided, powered, and they can be reduced using \kbd{qfbred}. This function is in fact a succession of elementary reduction steps corresponding essentially to a continued fraction expansion, and a single one of these steps can be achieved by adding an (optional) flag to the arguments of \kbd{qfbred}. Since handling the fourth component $d$ usually involves computing expensive logarithms, the same flag may be used to ignore the fourth component. Finally, it is sometimes useful to operate on forms of positive discriminant without performing any reduction (this is useless in the negative case), the functions \kbd{qfbcompraw} and \kbd{qfbpowraw} do exactly that. Again, the function \kbd{qfbprimeform} gives a prime form, but the form which is given corresponds to an ideal of prime norm which is usually not reduced. If desired, it can be reduced using \kbd{qfbred}. Finally, you still have at your disposal the function \kbd{qfbclassno} which gives the class number (this time \emph{guaranteed} correct), \kbd{quadregulator} which gives the regulator, and the much more sophisticated \kbd{quadclassunit} giving the class group's structure and its generators, as well as the regulator. The \kbd{qfbclassno} and \kbd{quadregulator} functions use an algorithm which is $O(\sqrt D)$, hence become very slow for discriminants of more than 10 digits. \kbd{quadclassunit} can be used on a much larger range. Let us see examples of all this at work and learn some little known number theory at the same time. First of all, type \bprog d = 3 * 3299; qfbclassno(d) @eprog\noindent We see that the class number is 3. (We know in advance that it must be divisible by 3 from the \kbd{d = -3299} case above and Scholz's mirror theorem.) Let us create a form by typing \bprog f = qfbred(qfbprimeform(d,2), 2) @eprog\noindent (the last 2 tells \kbd{qfbred} to ignore the Archimedean component). This gives us a prime ideal of norm equal to 2. Is this ideal principal? Well, one way to check this, which is not the most efficient but will suffice for now, is to look at the complete cycle of reduced forms equivalent to \kbd{f}. Type \bprog g = f; for(i=1,20, g = qfbred(g, 3); print(g)) @eprog\noindent (this time the 3 means to do a single reduction step, still not using Shanks's distance). We see that we come back to the form \kbd{f} without having the principal form (starting with $\pm1$) in the cycle, so the ideal corresponding to \kbd{f} is not principal. Since the class number is equal to 3, we know however that \kbd{f\pow 3} will be a principal ideal $\alpha\Z_K$. How do we find $\alpha$? For this, type \bprog f3 = qfbpowraw(f, 3) @eprog This computes the cube of \kbd{f}, without reducing it. Hence it corresponds to an ideal of norm equal to $8=2^3$, so we already know that the norm of $\alpha$ is equal to $\pm8$. We need more information, and this will be given by the fourth component of the form. Reduce your form until you reach the unit form (you will have to type \kbd{qfbred(\%,~1)} exactly 6 times), then extract the Archimedean component, say $c$. By definition of this distance, we know that $${\alpha\over{\sigma(\alpha)}}=\pm e^{2c},$$ where $\sigma$ denotes real conjugation in our quadratic field. This can be automated: \bprog q = f3; while(abs(component(q,1)) != 1, print(q); q = qfbred(q, 1)) c = component(q,4); @eprog\noindent Thus, if we type \bprog a = sqrt(8 * exp(2*c)) sa = 8 / a @eprog\noindent we know that up to sign, \kbd{a} and \kbd{sa} are numerical approximations of $\alpha$ and $\sigma(\alpha)$. Of course, $\alpha$ can always be chosen to be positive, and a quick numerical check shows that the difference of \kbd{a} and \kbd{sa} is close to an integer, and not the sum, so that in fact the norm of $\alpha$ is equal to $-8$ and the numerical approximation to $\sigma(\alpha)$ is \kbd{$-$sa}. Thus we type \bprog p = x^2 - round(a-sa)*x - 8 @eprog\noindent and this is the characteristic polynomial of $\alpha$. We can check that the discriminant of this polynomial is a square multiple of \kbd{d}, so $\alpha$ is indeed in our field. More precisely, solving for $\alpha$ and using the numerical approximation that we have to resolve the sign ambiguity in the square root, we get explicitly $\alpha=(15221+153\sqrt d)/2$. Note that this can also be done automatically using the functions \kbd{polred} and \kbd{modreverse}, as we will see later in the general number field case, or by solving a system of 2 linear equations in 2 variables. (Exercise: now that we have $\alpha$, check that it is indeed a generator of the ideal corresponding to the form \kbd{f3}.) \medskip Let us now play a little with cycles. Type \bprog D = 10^7 + 1 quadclassunit(D) @eprog\noindent We get as a result a 5-component vector, which tells us that (under GRH) the class number is equal to 1, and the regulator is approximately equal to $2641.5$. You may certify this with \bprog bnf = bnfinit(x^2 - D, 1); \\ @com insist on finding fundamental unit bnfcertify(bnf); @eprog\noindent although it's a little inefficient. Indeed \kbd{bnfcertify} needs the fundamental unit which is so large that \kbd{bnfinit} will have a hard time computing it: it needs about $R/\log(10)\approx 1147$ digits of precision! (So that it would have given up had we not inserted the flag $1$.) See \kbd{bnf.fu}. On the other hand, you can try \kbd{quadunit(D,'w)}. Impressive, isn't it? (You can check that its logarithm is indeed equal to the regulator.) Now just as an example, let's assume that we want the regulator to 500 decimals, say. (Without cheating and computing the fundamental unit exactly first!) I claim that simply from the crude approximation above, this can be computed with no effort. This time, we want to start with the unit form. Type: \bprog u = qfbred(qfbprimeform(D, 1), 2) @eprog\noindent We use the function \kbd{qfbred} with no distance since we want the initial distance to be equal to~0. Now type \kbd{f = qfbred(u, 1)}. This is the first form encountered along the principal cycle. For the moment, keep the precision low, for example the initial default precision. The distance from the identity of \kbd{f} is around 4.253. Very crudely, since we want a distance of $2641.5$, this should be encountered approximately at $2641.5/4.253=621$ times the distance of \kbd{f}. Hence, as a first try, we type \kbd{f\pow 621}. Oops, we overshot, since the distance is now $3173.02$. Now we can refine our initial estimate and believe that we should be close to the correct distance if we raise \kbd{f} to the power $621*2641.5/3173$ which is close to $517$. Now if we compute \kbd{f\pow 517} we hit the principal form right on the dot. Note that this is not a lucky accident: we will always land extremely close to the correct target using this method, and usually at most one reduction correction step is necessary. Of course, only the distance component can tell us where we are along the cycle. Up to now, we have only worked to low precision. The goal was to obtain this unknown integer $517$. Note that this number has absolutely no mathematical significance: indeed the notion of reduction of a form with positive discriminant is not well defined since there are usually many reduced forms equivalent to a given form. However, when PARI makes its computations, the specific order and reductions that it performs are dictated entirely by the coefficients of the quadratic form itself, and not by the distance component, hence the precision used has no effect. Hence we now start again by setting the precision to (for example) 500, we retype the definition of \kbd{u} (why is this necessary?), and then \kbd{qfbred(u, 1)\pow 517}. Of course we know in advance that we land on the unit form, and the fourth component gives us the regulator to 500 decimal places with no effort at all. In a similar way, we could obtain the so-called \emph{compact representation} of the fundamental unit itself, or $p$-adic regulators. I leave this as exercises for the interested reader. You can try the \kbd{quadhilbert} function on that field but, since the class number is $1$, the result won't be that exciting. If you try it on our preceding example ($3*3299$) it should take about 2 seconds. \medskip Time for a coffee break? \section{Working in General Number Fields} \subsec{Elements} The situation here is of course more difficult. First of all, remembering what we did with elliptic curves, we need to initialize data linked to our base number field, with something more serious than \kbd{quadgen}. For example assume that we want to work in the number field $K$ defined by one of the roots of the equation $x^4+24x^2+585x+1791=0$. This is done by typing \bprog T = x^4 + 24*x^2 + 585*x + 1791 nf = nfinit(T) @eprog\noindent We get an \kbd{nf} structure but, thanks to member functions, we do not need to know anything about it. If you type \kbd{nf.pol}, you will get the polynomial \kbd{T} which you just input. \kbd{nf.sign} yields the signature $(r_1,r_2)$ of the field, \kbd{nf.disc} the field discriminant, \kbd{nf.zk} an integral basis, etc\dots. The integral basis is expressed in terms of a generic root \kbd{x} of \kbd{T} and we notice it's very far from being a power integral basis, which is a little strange for such a small field. Hum, let's check that: \kbd{poldisc(T)}? Ooops, small wonder we had such denominators, the index of the power order $\Z[x]/(T)$ in the maximal order $\Z_K$ is, well, \kbd{nf.index}. Note that this is also given by \bprog sqrtint(poldisc(nf.pol) / nf.disc) @eprog\noindent Anyway, that's $3087$, we don't want to work with such a badly skewed polynomial! So, we type \bprog P = polred(T) @eprog\noindent We see from the third component that the polynomial $x^4-x^3-21x^2+17x+133$ defines the same field with much smaller coefficients, so type \bprog A = P[3] @eprog\noindent The \kbd{polred} function usually gives a simpler polynomial, and also sometimes some information on the existence of subfields. For example in this case, the second component of \kbd{polred} tells us that the field defined by $x^2-x+1=0$, i.e.~the field generated by the cube roots of unity, is a subfield of~$K$. Note this is incidental information and that the list of subfields found in this way is usually far from complete. To get the complete list, one uses \kbd{nfsubfields} (we shall do that later on). Type \kbd{poldisc(A)}, this is much better, but maybe not optimal yet (the index is still $7$). Type \kbd{polredabs(A)} (the \kbd{abs} stands for absolute). Since it seems that we won't get anything better, we'll stick with \kbd{A} (note however that \kbd{polredabs} finds a smallest generating polynomial with respect to a bizarre norm which ensures that the index will be small, but not necessarily minimal). In fact, had you typed \kbd{nfinit(T, 3)}, \kbd{nfinit} would first have tried to find a good polynomial defining the same field (i.e.~one with small index) before proceeding. It's not too late, let's redefine our number field: \bprog NF = nfinit(nf, 3) @eprog\noindent The output is a two-component vector. The first component is the new \kbd{nf}: type \bprog nf = NF[1]; @eprog\noindent If you type \kbd{nf.pol}, you notice that \kbd{gp} indeed replaced your bad polynomial \kbd{T} by a much better one, which happens to be \kbd{A}. (Small wonder, \kbd{nfinit} internally called \kbd{polredabs}.) The second component enables you to switch conveniently to our new polynomial. Namely, call $\theta$ a root of our initial polynomial \kbd{T}, and $\alpha$ a root of the one that \kbd{polred} has found, namely \kbd{A}. These are algebraic numbers, and as already mentioned are represented as polmods. For example, in our special case $\theta$ and $\alpha$ are equal to the polmods \bprog THETA = Mod(x, x^4 + 24*x^2 + 585*x + 1791) ALPHA = Mod(x, x^4 - x^3 - 21*x^2 + 17*x + 133) @eprog\noindent respectively. Here we are considering only the algebraic aspect, and hence ignore completely \emph{which} root $\theta$ or $\alpha$ is chosen. Now you may have a number of elements of your number field which are expressed as polmods with respect to your old polynomial, i.e.~as polynomials in $\theta$. Since we are now going to work with $\alpha$ instead, it is necessary to convert these numbers to a representation using $\alpha$. This is what the second component of \kbd{NF} is for: type \kbd{C = NF[2]}, you get \bprog Mod(-10/7*x^3 + 43/7*x^2 + 73/7*x - 64, x^4 - x^3 - 21*x^2 + 17*x + 133) @eprog\noindent meaning that $\theta = -\dfrac{10}{7}\alpha^3+\dfrac{43}{7}\alpha^2+\dfrac{73}{7}\alpha-64$, and hence the conversion from a polynomial in $\theta$ to one in $\alpha$ is easy, using \kbd{subst}. (We could get this polynomial from \kbd{polred} as well, try \kbd{polred(T, 2)}.) If we want the reverse, i.e.~to go back from a representation in $\alpha$ to a representation in $\theta$, we use the function \kbd{modreverse} on this polmod \kbd{C}. Try it. The result has a big denominator (1029) essentially because our initial polynomial \kbd{T} was so bad. By the way, to get that 1029, you should type \kbd{denominator(content(C))}. Trying \kbd{denominator} by itself would not work since the denominator of a polynomial is defined to be 1 (and its numerator is itself). The reason for this is that we think of a polynomial as a special case of a rational function.\smallskip From now on, we forget about \kbd{T}, and use only the polynomial \kbd{A} defining $\alpha$, and the components of the vector \kbd{nf} which gives information on our number field $K$. Type \bprog u = Mod(x^3 - 5*x^2 - 8*x + 56, A) / 7 @eprog\noindent This is an element in $K$. There are three equivalent representations for number field elements: polmod, polynomial, and column vector giving a decomposition in the integral basis \kbd{nf.zk} (\emph{not} on the power basis $(1,x,x^2,\dots)$). All three are equally valid when the number field is understood (is given as first argument to the function). You will be able to use any one of them as long as the function you call requires an \kbd{nf} argument as well. However, most PARI functions will return elements as column vectors. It's an important feature of number theoretic functions that, although they may have a preferred format for input, they will accept a wealth of other different formats. We already saw this for \kbd{nfinit} which accepts either a polynomial or an \kbd{nf}. It will be true for ideals, congruence subgroups, etc. Let's stick with elements for the time being. How does one go from one representation to the other? Between polynomials and polmods, it's easy: \kbd{lift} and \kbd{Mod} will do the job. Next, from polmods/polynomials to column vectors: type \kbd{v = nfalgtobasis(nf, u)}. So $\kbd{u} = \alpha^3- \alpha^2 - \alpha + 8$, right? Wrong! The coordinates of \kbd{u} are given with respect to the \emph{integral basis}, not the power basis $(1,\alpha,\alpha^2,\alpha^3)$ (and they don't coincide, type \kbd{nf.zk} if you forgot what the integral basis looked like). As a polynomial in $\alpha$, we simply have $\kbd{u} = {1\over7}(\alpha^3 - 5\alpha^2-8\alpha+56)$, which is trivially deduced from the original polmod representation! Of course \kbd{v = nfalgtobasis(nf, lift(u))} would work equally well. Indeed we don't need the polmod information since \kbd{nf} already provides the defining polynomial. To go back to polmod representation, use \kbd{nfbasistoalg(nf, v)}. Notice that \kbd{u} is an algebraic integer since \kbd{v} has integer coordinates (try \kbd{denominator(v) == 1}, which is of course overkill here, but not so in a program). Let's try this out. We may for instance compute \kbd{u\pow 3}. Try it. Or, we can type \kbd{1/u}. Better yet, if we want to know the norm from $K$ to $\Q$ of \kbd{u}, we type \kbd{norm(u)} (what else?); \kbd{trace(u)} works as well. Notice that none of this would work on polynomials or column vectors since you don't have the opportunity to supply \kbd{nf}! But we could use \kbd{nfeltpow(nf,u,3)}, \kbd{nfeltdiv(nf,1,u)} (or \kbd{nfeltpow(nf,u,-1)}) which would work whatever representation was chosen. Of course, there is also an \kbd{nfeltnorm} function (and \kbd{nfelttrace} as well). You can also consider $(u)$ as a principal ideal, and just type \bprog idealnorm(nf,u) @eprog\noindent Of course, in this way, we lose the \emph{sign} information. We will talk about ideals later on. If we want all the symmetric functions of \kbd{u} and not only the norm, we type \kbd{charpoly(u)}. Note that this gives the characteristic polynomial of \kbd{u}, and not in general the minimal polynomial. We have \kbd{minpoly(u)} for this. \misctitle{Exercise} Find a simpler expression for \kbd{u}. \smallskip Now let's work on the field itself. The \kbd{nfinit} command already gave us some information. The field is totally complex (its signature \kbd{nf.sign} is $[0,2]$), its discriminant \kbd{nf.disc} is $18981$ and \kbd{nf.zk} is an integral basis. The Galois group of its Galois closure can be obtained by typing \kbd{polgalois(A)}. The answer (\kbd{[8,-1,1]}, or \kbd{[8,-1,1,"D(4)"]} if the \kbd{galdata} package is installed) shows that it is equal to $D_4$, the dihedral group with 8 elements, i.e.~the group of symmetries of a square. This implies that the field is ``partially Galois'', i.e.~that there exists at least one non-trivial field isomorphism which fixes $K$, exactly one in this case. Type \kbd{nfgaloisconj(nf)}. The result tells us that, apart from the trivial automorphism, the map $$\alpha \mapsto {1\over7}(-\alpha^3+5\alpha^2+\alpha-49)$$ is the only field automorphism. \bprog nfgaloisconj(nf); s = Mod(%[2], A) charpoly(s) @eprog\noindent and we obtain \kbd{A} once again. Let us check that \kbd{s} is of order 2: \kbd{subst(lift(s), x, s)}. It is. We may express it as a matrix: \bprog w = Vec( matid(4) ) \\@com canonical basis v = vector(#w, i, nfgaloisapply(nf, s, w[i])) M = Mat(v) @eprog\noindent The vector \kbd{v} contains the images of the integral basis elements (as column vectors). The last statement concatenates them into a square matrix. So, \kbd{M} gives the action of \kbd{s} on the integral basis. Let's check \kbd{M\pow2}. That's the identity all right. The fixed field of this automorphism is going to be the only non-trivial subfield of $K$. I seem to recall that \kbd{polred} told us this was the third cyclotomic field. Let's check this: type \kbd{nfsubfields(nf)}. Indeed, there's a quadratic subfield, but it's given by \kbd{T = x\pow 2 + 22*x + 133 } and I don't recognize it. But \kbd{nfisisom(T, polcyclo(3))} indeed tells us that the fields $\Q[x]/(T)$ and $\Q[x]/(x^2+x+1)$ are isomorphic. (In fact, \kbd{polred(T)} would tell us the same, but does not correspond to a foolproof test: \kbd{polred} could have returned some other polynomials.) We may also check that \kbd{k = matker(M-1)} is two-dimensional, then \kbd{z = nfbasistoalg(nf, k[,2])} generates the quadratic subfield. Notice that 1, \kbd{z} and \kbd{u} are $\Q$-linearly dependent, and in fact $\Z$-linearly as well. Exercise: how would you check these two assertions in general? (Answer: \kbd{concat}, then respectively \kbd{matrank} or \kbd{matkerint} (or \kbd{qflll})). \kbd{z = charpoly(z)}, \kbd{z = gcd(z,z')} and \kbd{polred(z)} tell us that we found back the same subfield again (as we ought to!). Final check: type \kbd{nfrootsof1(nf)}. Again we find that $K$ contains a cube root of unity, since the torsion subgroup of its unit group has order 6. The given generator happens to be equal to \kbd{u}. \misctitle{Additional comment} (you are no longer supposed to skip this, but do as you wish): Before working with ideals, let us note one more thing. The main part of the work of \kbd{polred} or \kbd{nfinit}$(T)$ is to compute an integral basis, i.e.~a $\Z$-basis of the maximal order $\Z_K$ of $K$. This implies factoring the discriminant of the polynomial $T$, which is often not feasible. The situation may be improved in many ways: 1) First, it is often the case that our number field is of quite a special type. For example, one may know in advance some prime divisors of the discriminant. Hence we can ``help'' PARI by giving it that information. More precisely, we can use the function \kbd{addprimes} to inform PARI to keep on eye for these prime numbers. Do it only for big primes ! (Say, larger than \kbd{primelimit}.) 2) The second way in which the situation may be improved is that often we do not need the complete information on the maximal order, but only require that the order be $p$-maximal for a certain number of primes $p$ --- but then, we may not be able to use functions which require a genuine \kbd{nf}. The function \kbd{nfbasis} specifically computes the integral basis and is not much quicker than \kbd{nfinit} so is not very useful in its standard use. But we can optionally provide a list of primes: this returns a basis of an order which is $p$-maximal at the given primes. For example coming back to our initial polynomial $T$, the discriminant of the polynomial is $3^7\cdot7^6\cdot19\cdot37$. If we only want a $7$-maximal order, we simply type \bprog nfbasis([T, [7]]) @eprog\noindent Of course, \kbd{nfbasis([T, [2,3,5,7]])} would return an order which is maximal at $2,3,5,7$. A variant offers a nice generalization: \bprog nfbasis([T, 10^5]) @eprog\noindent will return an order which is maximal at all primes less than $10^5$. 3) Building on the previous points, \emph{if} the field discriminant is $y$-smooth (never mind the polynomial discriminant), up to a few big primes known to \kbd{addprimes}, then \kbd{bas = nfbasis(T, y)} returns a basis for the maximal order! We can then input the resulting basis to \kbd{nfinit}, as \kbd{nfinit([T, bas])}. Better: the $[T, \var{listP}]$ format can be directly used with nfinit, where \var{listP} specifies a finite list of primes in one of the above ways (explicit list or primes up to some bound), and the result can be unconditionally certified, independently of the \var{listP} parameter: \bprog T = polcompositum(x^7-2, polcyclo(5))[1]; K = nfinit( [T, [2,5,7]] ); nfcertify(K) @eprog\noindent The output is a list of composite integers whose complete factorization must be computed in order to certify the result (which may be very hard, hence is not done on the spot). When the list is empty, as here, the result is unconditional \kbd{nfcertify(nf)} \subsec{Ideals} We now want to work with ideals and not only with elements. An ideal can be represented in many different ways. First, an element of the field (in any of the various guises seen above) will be considered as a principal ideal. Then the standard representation is a square matrix giving the Hermite Normal Form (HNF) of a $\Z$-basis of the ideal expressed on the integral basis \kbd{nf.zk}. Standard means that most ideal related functions will use this representation for their output. Prime ideals can be represented in a special form as well (see \kbd{idealprimedec}) and all ideal-related functions will accept them. On the other hand, the function \kbd{idealtwoelt} can be used to find a two-element $\Z_K$-basis of a given ideal (as $a\Z_K + b\Z_K$, where $a$ and $b$ belong to $K$), but this is \emph{not} a valid representation for an ideal under \kbd{gp}, and most functions will choke on it (or worse, take it for something else and output a meaningless result). To be able to use such an ideal, you will first have to convert it to HNF form. Whereas it's very easy to go to HNF form (use \kbd{idealhnf(nf,id)} for valid ideals, or \kbd{idealhnf(nf,a,b)} for a two-element representation as above), it's a much more complicated problem to check whether an ideal is principal and find a generator. In fact an \kbd{nf} does not contain enough data for this particular task. We'll need a Buchmann Number Field, or \kbd{bnf}, for that. In particular, we need the class group and fundamental units, at least in some approximate form. More on this later (which will trivialize the end of the present section).\smallskip Let us keep our number field $K$ as above and its \kbd{nf} structure. Type \bprog P = idealprimedec(nf,7) @eprog\noindent This gives the decomposition of the prime number 7 into prime ideals. We have chosen 7 because it divides \kbd{nf.index} (in fact, is equal to it), hence is the most difficult case to treat. The result is a vector with 4 components, showing that 7 is totally split in the field $K$ into prime ideals of norm 7 (you can check: \kbd{idealnorm(nf,P[1])}). Let us take one of these ideals, say the first, so type \bprog pr = P[1] @eprog We obtain its inertia and residue degree as \kbd{pr.e} and \kbd{pr.f}, and its two generators as \kbd{pr.gen}. One of them is $\kbd{pr.p} = 7$, and the other is guaranteed to have valuation $1$ at \kbd{pr}. What is the Hermite Normal Form of this ideal? No problem: \bprog idealhnf(nf,pr) @eprog\noindent and we have the desired HNF. Let's now perform ideal operations. For example type \bprog idealmul(nf, pr, idealmul(nf, pr,pr)) @eprog\noindent or more simply \bprog pr3 = idealpow(nf, pr,3) @eprog\noindent to get the cube of the ideal \kbd{pr}. Since the norm of this ideal is equal to $343=7^3$, to check that it is really the cube of \kbd{pr} and not of other ideals above 7, we can type \bprog for(i=1, #P, print( idealval(nf, pr3, P[i]) )) @eprog\noindent and we see that the valuation at \kbd{pr} is equal to 3, while the others are equal to zero. We could see this as well from \kbd{idealfactor(nf, pr3)}. Let us now work in the class group ``by hand'' (we shall see simpler ways later). We shall work with \emph{extended ideals}: an extended ideal is a pair \kbd{[A, t]}, where $A$ is an ordinary ideal as above, and $t$ a number field element; this pair represents the ideal $(t) A$. \bprog id3 = [pr3, 1] r0 = idealred(nf, id3) @eprog\noindent The input \kbd{id3} is an extended ideal: pr3 together with 1 (trivial factorization). The new extended ideal \kbd{r0} is equal to the old one, in the sense that the products $(t)A$ are the same. It contains a ``reduced'' ideal equivalent to \kbd{pr3} (modulo the principal ideals), and a generator of the principal ideal that was factored out. Now, just for fun type \bprog r = r0; for(i=1,3, r = idealred(nf,r, [1,5]); print(r)) @eprog\noindent The ideals in the third \kbd{r} and initial \kbd{r0} are equal, say $(t) A = (t_0) A$: this means we have found a unit $(t_0/t)$ in our field, and it is easy to extract this unit given the extended component: \bprog t0 = r0[2]; t = r[2]; u = nfeltdiv(nf, t0, t) u = nfbasistoalg(nf, u) @eprog\noindent The last line recovers the unit as an algebraic number. Type \bprog ch = charpoly(u) @eprog\noindent and we obtain the characteristic polynomial \kbd{ch} of $u$ again. (Whose constant coefficient is $1$, hence $u$ is indeed a unit.) There is of course no reason for $u$ to be a fundamental unit. Let us see if it is a square. Type \bprog F = factor(subst(ch, x, x^2)) @eprog\noindent We see that \kbd{ch(x\pow2)} is a product of 2 polynomials of degree 4, hence $u$ is a square. (Why?) We now want to find its square root. A simple method is as follows: \bprog NF = subst(nf,x,y); r = F[1,1] % (x^2 - nfbasistoalg(NF, u)) @eprog\noindent to find the remainder of the characteristic polynomial of \kbd{u2} divided by \kbd{x\pow 2 - $u$}. This is a polynomial of degree 1 in \kbd{x}, with polmod coefficients, and we know that \kbd{u2}, being a root of both polynomials, is the root of \kbd{r}, hence can be obtained by typing \bprog u2 = -polcoef(r,0) / polcoef(r,1) @eprog\noindent There is an important technicality in the above: why did we need to substitute \kbd{NF} to \kbd{nf}? The reason is that data related to \kbd{nf} is given in terms of the variable \kbd{x}, seen modulo \kbd{nf.pol}; but we need \kbd{x} as a free variable for our polynomial divisions. Hence the substitution of \kbd{x} by \kbd{y} in our \kbd{nf} data. The most natural method is to try directly \bprog nffactor(nf, y^2 - u) @eprog\noindent Except that this won't work for the same technical reason as above: the main variable of the polynomial to be factored must have \emph{higher} priority than the number field variable. This won't be possible here since \kbd{nf} was defined using the variable \kbd{x} which has the highest possible priority. So we need to substitute variables around: \bprog nffactor(NF, x^2 - nfbasistoalg(NF, subst(lift(u),x,y))) @eprog\noindent (Of course, with better planning, we would just have defined \kbd{nf} in terms of the \kbd{'y} variable, to avoid all these substitutions.) \smallskip A much simpler approach is to consider the above as instances of a \emph{discrete logarithm} problem, where we want to express some elements an abelian group (of finite type) in terms of explicitly given generators, and transfer all computations from abstract groups like $\text{Cl}(K)$ and $\Z_K^*$ to products of simpler groups like $\Z^n$ or $\Z/d\Z$. We shall do exactly that in the next section. Before that, let us mention another famous (but in fact, simpler) \emph{discrete logarithm} problem, namely the one attached to the invertible elements modulo an ideal: $(\Z_K / I)^*$. Just use \kbd{idealstar} (this is an \kbd{init} function) and \kbd{ideallog}. Many more functions on ideals are available. We mention here the complete list, referring to Chapter 3 for detailed explanations: \kbd{idealadd}, \kbd{idealaddtoone}, \kbd{idealappr}, \kbd{idealchinese}, \kbd{idealcoprime}, \kbd{idealdiv}, \kbd{idealfactor}, \kbd{idealhnf}, \kbd{idealintersect}, \kbd{idealinv}, \kbd{ideallist}, \kbd{ideallog}, \kbd{idealmin}, \kbd{idealmul}, \kbd{idealnorm}, \kbd{idealpow}, \kbd{idealprimedec}, \kbd{idealred}, \kbd{idealstar}, \kbd{idealtwoelt}, \kbd{idealval}, \kbd{nfisideal}. We suggest you play with these to get a feel for the algebraic number theory package. Remember that when a matrix (usually in HNF) is output, it is always a $\Z$-basis of the result expressed on the \emph{integral basis} \kbd{nf.zk} of the number field, which is usually \emph{not} a power basis. \subsec{Class groups and units, \kbd{bnf}} Apart from the above functions you have at your disposal the powerful function \kbd{bnfinit}, which initializes a \kbd{bnf} structure, i.e.~a number field with all its invariants (including class group and units), and enough technical data to solve discrete logarithm problems in the class and unit groups. First type \kbd{setrand(1)}: this resets the random seed (to make sure we and you get the exact same results). Now type \bprog bnf = bnfinit(NF); @eprog\noindent where \kbd{NF} is the same number field as before. You do not want to see the output clutter a number of screens so don't forget the semi-colon. (Well if you insist, it is about three screenful in this case, but may require several Megabytes for larger degrees.) Note that \kbd{NF} is now expressed in terms of the variable \kbd{y}, to avoid later problems with variable priorities. A word of warning: both the \kbd{bnf} and all results obtained from it are \emph{conditional} on a Riemann Hypothesis at this point; the \kbd{bnf} must be certified before the following statements become actual theorems. \smallskip Member functions are still available for \kbd{bnf} structures. So, let's try them: \kbd{bnf.pol} gives \kbd{A}, \kbd{bnf.sign}, \kbd{bnf.disc}, \kbd{bnf.zk}, ok nothing really exciting. In fact, an \kbd{nf} is included in the \kbd{bnf} structure: \kbd{bnf.nf} should be identical to \kbd{NF}. Thus, all functions which took an \kbd{nf} as first argument, will equally accept a \kbd{bnf} (and a \kbd{bnr} as well which contains even more data). Anyway, new members are available now: \kbd{bnf.no} tells us the class number is 4, \kbd{bnf.cyc} that it is cyclic (of order 4 but that we already knew), \kbd{bnf.gen} that it is generated by the ideal \kbd{g = bnf.gen[1]}. If you \kbd{idealfactor(bnf, g)}, you recognize \kbd{P[2]}. (You may also play in the other direction with \kbd{idealhnf}.) The regulator \kbd{bnf.reg} is equal to $3.794\dots$. \kbd{bnf.tu} tells us that the roots of unity in $K$ are exactly the sixth roots of 1 and gives a primitive root $\zeta = {1\over7}(\alpha^3 - 5\alpha^2 - 8\alpha + 56)$, which we have seen already. Finally \kbd{bnf.fu} gives us a fundamental unit $\epsilon = {1\over7}(\alpha^3 - 5\alpha^2 - \alpha + 28)$, which must be linked to the units \kbd{u} and \kbd{u2} found above since the unit rank is~1. To find these relations, type \bprog bnfisunit(bnf, u) bnfisunit(bnf, u2) @eprog\noindent Lo and behold, \kbd{u = $\zeta^2\epsilon^2$} and \kbd{u2 = $\zeta^{4}\epsilon^1$}. \misctitle{Note} Since the fundamental unit obtained depends on the random seed, you could have obtained another unit than $\epsilon$, had you not reset the random seed before the computation. This was the purpose of the initial \kbd{setrand} instruction, which was otherwise unnecessary.\medskip We are now ready to perform operations in the class group. First and foremost, let us certify the result: type \kbd{bnfcertify(bnf)}. The output is \kbd{1} if all went well; in fact no other output is possible, whether the input is correct or not, but you can get an error message (or in exceedingly rare cases an infinite loop) if it is incorrect. It means that we now know the class group and fundamental units unconditionally (no more GRH then!). In this case, the certification process takes a very short time, and you might wonder why it is not built in as a final check in the \kbd{bnfinit} function. The answer is that as the regulator gets bigger this process gets increasingly difficult, and becomes soon impractical, while \kbd{bnfinit} still happily spits out results. So it makes sense to dissociate the two: you can always check afterwards, if the result is interesting enough. Looking at the tentative regulator, you know in advance whether the certification can possibly succeed: if \kbd{bnf.reg} is large, don't waste your time. Now that we feel safe about the \kbd{bnf} output, let's do some real work. For example, let us take again our prime ideal \kbd{pr} above 7. Since we know that the class group is of order 4, we deduce that \kbd{pr} raised to the fourth power must be principal. Type \bprog pr4 = idealpow(nf, pr, 4) v = bnfisprincipal(bnf, pr4) @eprog\noindent The first component gives the factorization of the ideal in the class group. Here, \kbd{[0]} means that it is up to equivalence equal to the 0-th power of the generator \kbd{g} given in \kbd{bnf.gen}, in other words that it is a principal ideal. The second component gives us the algebraic number $\alpha$ such that $\kbd{pr4}=\alpha\Z_K$, $\alpha$ being as usual expressed on the integral basis. Type \kbd{alpha = v[2]}. Let us check that the result is correct: first, type \kbd{idealnorm(bnf, alpha)}. (Note that we can use a \kbd{bnf} with all the \kbd{nf} functions; but not the other way round, of course.) It is indeed equal to $7^4 = 2401$, which is the norm of \kbd{pr4}. This is only a first check. The complete check is obtained by computing the HNF of the principal ideal generated by \kbd{alpha}. To do this, type \kbd{idealhnf(bnf, alpha) == pr4}. Since the equality is true, \kbd{alpha} is correct (not that there was any doubt!). But \kbd{bnfisprincipal} also gives us information for non-principal ideals. For example, type \bprog v = bnfisprincipal(bnf, pr) @eprog\noindent The component \kbd{v[1]} is now equal to \kbd{[3]}, and tells us that \kbd{pr} is ideal-equivalent to the cube of the generator \kbd{g}. Of course we already knew this since the product of \kbd{P[3]} and \kbd{P[4]} was principal (generated by \kbd{al}), as well as the product of all the \kbd{P[$i$]} (generated by 7), and we noticed that \kbd{P[2]} was equal to \kbd{g}, which has order 4. The second component \kbd{v[2]} gives us $\alpha$ on the integral basis such that $\kbd{pr}=\alpha \kbd{g}^3$. Note that if you \emph{don't} want this $\alpha$, which may be large and whose computation may take some time, you can just add the flag $1$ (see the online help) to the arguments of \kbd{bnfisprincipal}, so that it only returns the position of \kbd{pr} in the class group. \smallskip \subsec{Class field theory, \kbd{bnr}} We now survey quickly some class field theoretic routines. We must first initialize a Buchmann Number Ray, or \kbd{bnr}, structure, attached to a \kbd{bnf} base field and a modulus. Let's keep $K$, and try a finite modulus ${\goth f} = 7\Z_K$. (See the manual for how to include infinite places in the modulus.) Since $K$ will now become a base field over which we want to build relative extensions, the attached \kbd{bnf} needs to have variables of lower priority than the polynomials defining the extensions. Fortunately, we already took care that, but it would have been easy to deal with the problem now (as easy as \kbd{bnf = subst(bnf, x, y)}). Then type \bprog bnr = bnrinit(bnf, 7, 1); bnr.cyc @eprog\noindent tells us the ray class group modulo ${\goth f}$ is isomorphic to $\Z/24\Z \times \Z/6\Z \times \Z/2\Z $. The attached generators are \kbd{bnr.gen}. Just as a \kbd{bnf} contained an \kbd{nf}, a \kbd{bnr} contains a \kbd{bnf} (hence an \kbd{nf}), namely \kbd{bnr.bnf}. Here \kbd{bnr.clgp} refers to the ray class group, while \kbd{bnr.bnf.clgp} refers to the class group. \bprog rnfkummer(bnr,, 2) rnfkummer(bnr,, 3) @eprog\noindent outputs defining polynomials for the $2$ abelian extensions of $K$ of degree $2$ (resp.~$3$), whose conductor is exactly equal to ${\goth f}$ (the modulus used to define \kbd{bnr}). (In the current implementation of \kbd{rnfkummer}, these degrees must be \emph{prime}.) What about other extensions of degree $2$ for instance? \bprog L0= subgrouplist(bnr, [2]) L = subgrouplist(bnr, [2], 1) @eprog\noindent \kbd{L0}, resp.~\kbd{L} is the list of those subgroups of the full ray class group mod $7$, whose index is $2$, and whose conductor is $7$, resp.~arbitrary. (Subgroups are given by a matrix of generators, in terms of \kbd{bnr.gen}.) \kbd{L0} has $2$ elements, attached to the $2$ extensions we already know. \kbd{L} has $7$ elements, the $2$ from \kbd{L0}, and $5$ new ones: \bprog L1 = setminus(Set(L), Set(L0)) @eprog\noindent The conductors are \bprog vector(#L1, i, bnrconductor(bnr, L1[i])) @eprog\noindent among which one sees the identity matrix, i.e. the trivial ideal. (It is \kbd{L1[3]} in my session, maybe not in yours. Take the right one!) Indeed, the class group was cyclic of order $4$ and there exists a unique unramified quadratic extension. We could find it directly by recomputing a \kbd{bnr} with trivial conductor, but we can also use \bprog rnfkummer(bnr, L1[3]) \\ @com pick the subgroup with trivial conductor! @eprog\noindent directly which outputs the (unique by Takagi's theorem) class field attached to the subgroup \kbd{L1[3]}. In fact, it is of the form $K(\sqrt{-\epsilon})$. We can check this directly: \bprog rnfconductor(bnf, x^2 + bnf.fu[1]) @eprog\noindent \subsec{Galois theory over $\Q$} PARI includes a nearly complete set of routines to compute with Galois extensions of $\Q$. We start with a very simple example. Let $\zeta$ a $8$th-root of unity and $K=\Q(\zeta)$. The minimal polynomial of $\zeta$ is the 8$th$ cyclotomic polynomial, namely \kbd{polcyclo(8)} (=$x^4+1$). We issue the command \bprog G = galoisinit(x^4 + 1); @eprog\noindent to compute $G=\text{Gal}(K/\Q)$. The command \kbd{galoisisabelian(G)} returns \kbd{[2,0;0,2]} so $G$ is an abelian group, isomorphic to $(\Z/2\Z)^2$, generated by $\sigma$=\kbd{G.gen[1]} and $\tau$=\kbd{G.gen[2]}. These automorphisms are given by their actions on the roots of $x^4+1$ in a suitable $p$-adic extension. To get the explicit action on $\zeta$, we use \kbd{galoispermtopol(G,G.gen[i])} for $i=1,2$ and get $\sigma(\zeta)=-\zeta$ and $\tau(\zeta)=\zeta^3$. The last non-trivial automorphism is $\sigma\tau$=\kbd{G.gen[1]*G.gen[2]} and we have $\sigma\tau(\zeta)=-\zeta^3$. (At least in my version, yours may return a different set of generators, rename accordingly.) We compute the fixed field of $K$ by the subgroup generated by $\tau$ with \bprog galoisfixedfield(G, G.gen[2], 1) @eprog\noindent and get $x^2 + 2$. Now we want the factorization of $x^4+1$ over that subfield. Of course, we could use \kbd{nffactor}, but here we have a much simpler option: \kbd{galoisfixedfield(G, G.gen[1], 2)} outputs \bprog [x^2 + 2, Mod(x^3 + x, x^4 + 1), [x^2 - y*x - 1, x^2 + y*x - 1]] @eprog\noindent which means that $x^4+1=(x^2-\alpha\*x-1)(x^2+\alpha\*x-1)$ where $\alpha$ is a root of $x^2+2$, and more precisely, $\alpha=\zeta^3+\zeta$. So we recover the well-known factorization: $$x^4+1=(x^2-\sqrt{-2}\*x-1)(x^2+\sqrt{-2}\*x-1)$$ For our second example, let us take the field $K$ defined by the polynomial \bprog P = x^18 - 3*x^15 + 115*x^12 + 104*x^9 + 511*x^6 + 196*x^3 + 343; G = galoisinit(P); @eprog\noindent Since \kbd{galoisinit} succeeds, the extension $K/\Q$ is Galois. This time \kbd{galoisisabelian(G)} return $0$, so the extension is not abelian, however we can still put a name on the underlying abstract group. Use \kbd{galoisidentify(G)}, which return $[18, 3]$. By looking at the GAP4 classification we find that $[18, 3]$ is $S_3\times\Z/3\Z$. This time, the subgroups of $G$ are not obvious, fortunately we can ask PARI : \kbd{galoissubgroups(G)}. Let us look for a polynomial $Q$ with the property that $K$ is the splitting field of $Q(x^2)$. For that purpose, let us take $\sigma$=\kbd{G.gen[3]}. We check that \kbd{G.gen[3]\^{}2} is the identity, so $\sigma$ is of order $2$. We now compute the fixed field $K^\sigma$ and the relative factorization of $P$ over $K^\sigma$: \bprog F = galoisfixedfield(G, G.gen[3], 2); @eprog\noindent So $K$ is a quadratic extension of $K^\sigma$ defined by the polynomial \kbd{R=F[3][1]}. It is well-known that $K$ is also defined by $x^2-D$ where $D$ is the discriminant of $R$ (over $K^\sigma$). To compute $D$ we issue: \bprog D = poldisc(F[3][1]) * Mod(1,subst(F[1],x,y)); @eprog\noindent Note that since \kbd{y} in \kbd{F[3][1]} denotes a root of \kbd{F[1]}, we have to use \kbd{subst(,x,y)}. Now we hope that $D$ generate $K^\sigma$ and compute \kbd{Q=charpoly(D)}. We check that $Q=x^9+270\*x^6+12393\*x^3+19683$ is irreducible with \kbd{polisirreducible(Q)}. (Were it not the case, we would multiply $D$ by a random square.) So $D$ is a generator of $K^\sigma$ and $\sqrt{D}$ is a generator of $K$. The result is that $K$ is the splitting field of $Q(x^2)$. We can check that with \kbd{nfisisom(P,subst(Q,x,x\^{}2))}. \section{Working with associative algebras} Beyond the realm of number fields, we can perform operations with more general associative algebras, that need not even be commutative! Of course things become more complicated. We have two different structures: the first one allows us to manipulate any associative algebra that is finite-dimensional over a prime field ($\Q$ or $\F_p$ for some prime~$p$), and the second one is dedicated to central simple algebras over number fields, which are some nice algebras that behave a lot like number fields. Like in other parts of~\kbd{gp}, every function that has to do with associative algebras begins with the same prefix:~\kbd{alg}. \subsec{Arbitrary associative algebras} In order to create an associative algebra, you need to tell~\kbd{gp} how to multiply elements. We do this by providing a \emph{multiplication table} for the algebra, in the form of the matrix of left multiplication by each basis element, and use the function~\kbd{algtableinit}. For instance, let us work in~$\F_3[x]/(x^2)$. Of course, we could use polmods of intmods to represent elements in this algebra, but let's introduce the general mechanism with this simple example! This algebra has a basis with two elements:~$1$ and~$\epsilon$, the image of~$x$ in the quotient. By the way,~\kbd{gp} will only accept your multiplication table if the first basis vector is~$1$. The multiplication matrix of~$1$ is the~$2\times 2$ identity matrix, and since~$\epsilon\cdot 1 = \epsilon$ and~$\epsilon\cdot\epsilon = 0$, the left multiplication table of~$\epsilon$ is~$\pmatrix{0 & 0 \cr 1 & 0}$. So we use the following multiplication table: \bprog mt1 = [matid(2), [0,0;1,0]] @eprog\noindent Since we want our algebra to be over~$\F_3$, we have to specify the characteristic and create the algebra with \bprog al1 = algtableinit(mt1, 3); @eprog\noindent Let's create another one: the algebra of upper-triangular~$2\times 2$ matrices over~$\Q$. This algebra has dimension~$3$, with basis~$1$, $a = \pmatrix{0 & 1 \cr 0 & 0}$ and~$b = \pmatrix{0 & 0 \cr 0 & 1}$, and these elements satisfy~$a^2=0$, $ab = a$, $ba=0$ and~$b^2=b$. Watch out, even though~$a$ and~$b$ are~$2\times 2$ matrices, their left multiplication tables are~$3\times 3$ matrices! The left multiplication tables of~$a$ and~$b$ are respectively \bprog ma = [0,0,0; 1,0,1; 0,0,0]; mb = [0,0,0; 0,0,0; 1,0,1]; @eprog\noindent The multiplication table of our second algebra is therefore \bprog mt2 = [matid(3), ma, mb]; @eprog\noindent and we can create the algebra with \bprog al2 = algtableinit(mt2,0); @eprog\noindent In fact, we can omit the second argument and type \bprog al2 = algtableinit(mt2); @eprog\noindent and the characteristic of the algebra will implicitly be~$0$. Warning: in characteristic~$0$, \kbd{algtableinit} expects an integral multiplication table. In fact, \kbd{gp} does not check that the multiplication table you provided really defines an associative algebra. You can check it a posteriori with \bprog algisassociative(al2) @eprog\noindent or before creating the algebra with \bprog algisassociative(mt1,3) @eprog\noindent After creating the algebra, you can get back the multiplication table that you provided with~\kbd{algmultable(al2)}, the characteristic with~\kbd{algchar(al1)} and the dimension with~\kbd{algdim(al2)}. \subsubsec{Elements} In an associative algebra, we represent elements as column vectors expressing them on the basis of the algebra. For instance, in~\kbd{al1} $=\F_3[\epsilon]$, the element~$1-\epsilon$ is represented as~\kbd{[1,-1]\til}. Similarly, in~\kbd{al2} we can define~$a$, $b$ and~$c = \pmatrix{2 & 1\cr 0 & 1}$ by \bprog a = [0,1,0]~ b = [0,0,1]~ c = [2,1,-1]~ @eprog\noindent We can also draw random elements in a box using \bprog algrandom(al2, 10) @eprog\noindent You can compute any elementary operation: try various combinations of~\kbd{algadd}, \kbd{algsub}, \kbd{algneg}, \kbd{algmul}, \kbd{alginv}, \kbd{algsqr}, \kbd{algpow}, using the syntax \bprog algmul(al2, b, a) algpow(al2, c, 10) @eprog\noindent and the natural variants. In every algebra we have the left regular representation, which sends every element~$x$ to the matrix of left multiplication by~$x$. In~\kbd{gp} we access it by calling \bprog algtomatrix(al2, c) @eprog\noindent For every element~$x$ in an associative algebra, the trace of that matrix is called the \emph{trace} of~$x$, the determinant is called the \emph{norm} of~$x$, and the characteristic polynomial is called the \emph{characteristic polynomial} of~$x$. We can compute them: \bprog algtrace(al2, a) algnorm(al2, c) algcharpoly(al2, b) @eprog \subsubsec{Properties} Now let's try to compute some interesting properties of our algebras. Maybe the simplest one we want to test is whether an algebra is commutative; \kbd{algiscommutative} does that for us: you can use it to check that~\kbd{al1} is of course commutative, but~\kbd{al2} is not since for instance~$ab=a\neq 0 = ba$. More precisely, we can compute a basis of the center of an algebra with~\kbd{algcenter}. Since~\kbd{al1} is commutative, we obtain the identity matrix, and \bprog algcenter(al2) @eprog\noindent tells us that the center of~\kbd{al2} is one-dimensional and generated by the identity. An important object in the structure of associative algebras is the \emph{Jacobson radical}: the set of elements that annihilate every simple left module. It is a nilpotent two-sided ideal. An algebra is \emph{semisimple} if its Jacobson radical is zero, and for every algebra~$A$ with radical~$J$, the quotient~$A/J$ is semisimple. You can compute a basis for the Jacobson radical using~\kbd{algradical}. For instance, the radical of~\kbd{al1} is generated by the element~$\epsilon$. Indeed, in a commutative algebra the Jacobson radical is equal to the set of nilpotent elements. The radical of~\kbd{al2} has basis~$a$: it is the subspace of strictly upper-triangular~$2\times 2$ matrices. You can also directly test whether an algebra is semisimple using~\kbd{algissemisimple}. Let's compute the semisimplification of our second algebra by quotienting out its radical: \bprog al3 = algquotient(al2, algradical(al2)); @eprog\noindent Check that~\kbd{al3} is indeed semisimple now that you know how to do it! Group algebras provide interesting examples: when~$G$ is a finite group and~$F$ is a field, the group algebra~$F[G]$ is semisimple if and only if the characteristic of~$F$ does not divide the order of~$G$. Let's try it! \bprog K = nfsplitting(x^3-x+1); \\ Galois closure -> S_3 G = galoisinit(K) al4 = alggroup(G, 5) \\ F_5[S_3] algissemisimple(al4) @eprog\noindent Check what happens when you change the characteristic of the algebra. The building blocks of semisimple algebras are \emph{simple} algebras: algebras with no nontrivial two-sided ideals. Since the Jacobson radical is a two-sided ideal, every simple algebra is semisimple. You can check whether an algebra is simple using~\kbd{algissimple}. For instance, you can check that \bprog algissimple(al1) @eprog\noindent returns~\kbd{0}, but this is not very interesting since~\kbd{al1} is not even semisimple. Instead we can test whether~\kbd{al3} is simple, and since we already know that it is semisimple we can prevent~\kbd{gp} from checking it again by using the optional second argument: \bprog algissimple(al3, 1) @eprog\noindent We see that~\kbd{al3} is not simple, and this implies that we can decompose it further. Indeed, every semisimple algebra is isomorphic to a product of simple algebras. We can obtain this decomposition with \bprog dec3 = algsimpledec(al3)[2]; apply(algdim, dec3) @eprog\noindent We see that~\kbd{al3} is isomorphic to~$\Q\times\Q$. Similarly, we can decompose~\kbd{al4}. \bprog dec4 = algsimpledec(al4)[2]; apply(algdim, dec4) @eprog\noindent We see that~\kbd{al4} is isomorphic to~$\F_5\times\F_5\times A$ where~$A$ is a mysterious 4-dimensional simple algebra. However every simple algebra over a finite field is isomorphic to a matrix algebra over a possibly larger finite field. By computing the center \bprog algcenter(dec4[3]) @eprog\noindent we see that this algebra has center~$\F_5$, so that~\kbd{al4} is isomorphic to~$\F_5\times\F_5\times M_2(\F_5)$. \subsec{Central simple algebras over number fields} As we saw, simple algebras are building blocks for more complicated algebras. The center of a simple algebra is always a field, and we say that an algebra over a field~$F$ is \emph{central} if its center is~$F$. The most natural noncommutative generalization of a number field is a \emph{division algebra} over~$\Q$: an algebra in which every nonzero element is invertible. Since the center of a division algebra over~$\Q$ is a number field, we do not lose any generality by considering central division algebras over number fields. However, the tensor product of two central division algebras is not always a division algebra, but division algebras are always simple and central simple algebras are closed under tensor products, giving a much nicer global picture. This is why we choose central simple algebras over number fields as our noncommutative generalization of number fields. \subsubsec{Creation} Let's create our first central simple algebras! A well-known construction is that of \emph{quaternion algebras}, which proceeds as follows. Let~$F$ be a number field, and let~$a,b\in F^\times$; the quaternion algebra~$(a,b)_F$ is the $F$-algebra generated by two elements~$i$ and~$j$ satisfying~$i^2=a$, $j^2=b$ and~$ij=-ji$. Hamilton's quaternions correspond to the choice~$a=b=-1$, but it is not the only possible one! Here is our first quaternion algebra: \bprog Q = nfinit(y); al1 = alginit(Q,[-2,-1]); \\ (-2,-1)_Q @eprog\noindent Note that we represented the rationals~$\Q$ with an~\kbd{nf} structure and used the variable~$y$ in that structure. The reason for this variable choice will be clearer after looking at the next construction. You can see from the definition of a quaternion algebra that it has dimension~$4$ over its center, a fact that you can check in our example: \bprog algdim(al1) @eprog\noindent Cyclic algebras generalize the quaternion algebra construction. Let~$F$ be a number field and~$K/F$ a cyclic extension of degree~$d$ with~$\sigma\in\text{Gal}(K/F)$ an automorphism of order~$d$, and let~$b\in F^\times$; the \emph{cyclic algebra}~$(K/F,\sigma,b)$ is the algebra~$\bigoplus_{i=0}^{d-1}u^iK$ with~$u^d=b$ and~$k u = u \sigma(k)$ for all~$k\in K$. It is a central simple algebra of dimension~$d^2$ over~$F$. Let's construct one. First, start with a cyclic extension of number fields. A simple way of obtaining such an extension is to take a cyclotomic field over~$\Q$. \bprog T = polcyclo(5) K = rnfinit(Q,T); aut = Mod(x^2,T) @eprog\noindent Here the variable of~\kbd{T} must have higher priority than that of~\kbd{Q} to build the~\kbd{rnf} structure. Now choose an element~$b\in\Q^\times$, say~$3$. \bprog b = 3 @eprog\noindent Now we can create the algebra and check that it has the right dimension:~$16$. \bprog al2 = alginit(K, [aut,b]); algdim(al2) @eprog\noindent We can recover the field~\kbd{K}, the automorphism~\kbd{aut} and the element~\kbd{b} respectively as follows. \bprog algsplittingfield(al2) algaut(al2) algb(al2) @eprog\noindent In order to see how we recover quaternion algebras with this construction, let's look at \bprog algsplittingfield(al1).pol algaut(al1) algb(al1) @eprog\noindent We see that the quaternion algebra~$(-2,-1)_{\Q}$ constructed by~\kbd{gp} is represented as a cyclic algebra~$(\Q(\sqrt{-2})/\Q, \sigma, -1)$ by writing~$\Q+\Q i+\Q j+\Q ij = \Q(i) + j\Q(i)$. A nice feature of central simple algebras over a given number field is that they are completely classified up to isomorphism, in terms of certain invariants. We therefore provide functions to create an algebra directly from its invariants. The first basic invariant is the dimension of the algebra over its center. In fact, the dimension of a central simple algebra is always a square, and we call the square root of the dimension the \emph{degree} of the algebra. For instance, a quaternion algebra has degree~$2$. We can access the degree with \bprog algdegree(al1) algdegree(al2) @eprog\noindent Let~$F$ be a number field and~$A$ a central simple algebra of degree~$d$ over~$F$. To every place~$v$ of~$F$ we can attach a \emph{Hasse invariant} $h_v(A)\in(\dfrac{1}{d}\Z)/\Z\subset\Q/\Z$, with the additional restrictions that the invariant is~$0$ at every complex place and in~$(\dfrac{1}{2}\Z)/\Z$ at every real place. These invariants are~$0$ at all but finitely many places. For instance we can compute the invariants for our algebras: \bprog alghassei(al1) alghassef(al1) alghassei(al2) alghassef(al2) @eprog\noindent The output of~\kbd{alghassei} (infinite places) is a vector of integers of length the number of real places of~$F$, and the corresponding Hasse invariants are these integers divided by~$d$. Here we learn that the invariant of~\kbd{al1} at~$\infty$ is~$1/2$ and that of~\kbd{al2} is~$0$. Similarly, the output of~\kbd{alghassef} (finite places) is a pair of vectors, one containing primes of the base field, and a vector of integers of the same length representing the Hasse invariants at finite places. We learn that~\kbd{al1} has invariant~$1/2$ at~$2$ and~$0$ at every other finite place, and that~\kbd{al2} has invariant~$-1/3$ at~$3$, invariant~$1/3$ at~$5$, and~$0$ at every other finite place. These invariants give a complete classification of central simple algebras over~$F$: \item two central simple algebras over~$F$ of the same degree are isomorphic if and only if they have the same invariants; \item the sum of the Hasse invariants is~$0$ in $\Q/\Z$; \item for every degree~$d$ and finite collection of Hasse invariants satisfying the conditions above, there exists a central simple algebra over~$F$ having those invariants. Let's use~\kbd{gp} to construct an algebra from its invariants. First let's construct a number field and a few places. \bprog nf = nfinit(y^2-2); p3 = idealprimedec(nf,3)[1] p17 = idealprimedec(nf,17)[1] @eprog\noindent Now let's construct an algebra of degree~$6$. The following Hasse invariants satisfy the correct conditions since~$1/3+1/6+1/2=0$ in~$\Q/\Z$: \bprog hf = [[p3,p17],[1/3,1/6]]; hi = [1/2,0]; \\ nf has 2 real places @eprog\noindent Finally we can create the algebra: \bprog al3 = alginit(nf,[6,hf,hi]); @eprog\noindent This will require less than half a minute but a lot of memory: this is an algebra of dimension~$2\times 6^2 = 72$ over~$\Q$ and we are doing a nontrivial computation in the initialization! You can check that the dimension over~$\Q$ is what we expect: \bprog algdim(al3,1) @eprog\noindent During the initialization, \kbd{gp} computes an integral multiplication table for the algebra. This allows us to recreate a table version of the algebra: \bprog mt3 = algmultable(al3); al4 = algtableinit(mt3); @eprog\noindent We can then check that the algebra is simple as expected: \bprog algissimple(al4) @eprog\noindent Finally, an important test for a central simple algebra is whether it is a division algebra. \bprog algisdivision(al3) @eprog \subsubsec{Elements} In a cyclic algebra~$(K/F,\sigma,b)$ of degree~$d$, we represent elements as column vectors of length~$d$, expressed on the basis of the~$K$-vector space~$\bigoplus_{i=0}^{d-1}u^iK$: \bprog a = [x^3-1, -x^2, 3, -1]~*Mod(1,T) \\represents an element in al2 @eprog\noindent To represent elements in the quaternion algebra~\kbd{al1}, we must view it as a cyclic algebra, and therefore use the representation~\kbd{al1} $ = \Q(i)+j\Q(i)$. The standard basis elements~$1,i,j,k=ij=-ji$ become \bprog one = [1,0]~ i = [x,0]~ j = [0,1]~ k = [0,-x]~ @eprog\noindent The expected equalities hold: \bprog algsqr(al1,i) == -2*one algsqr(al1,j) == -1*one algsqr(al1,k) == -2*one algmul(al1,i,j) == k algmul(al1,j,i) == -k @eprog\noindent Like~\kbd{nfinit} for number fields, the~\kbd{alginit} function computes an integral basis of the algebra being initialized. More precisely, an \emph{order} in a~$\Q$-algebra~$A$ is a subring~${\cal O}\subset A$ that is finitely generated as a~$\Z$-module and such that~$\Q{\cal O} = A$. In an algebra structure computed with~\kbd{alginit}, we store a basis of an order~${\cal O}_0$, which we will call the integral basis of the algebra. There is no canonical choice for such a basis, and not every integral element has integral coordinates with respect to that basis (the set of integral elements in~$A$ does not form a ring in general). By default, ${\cal O}_0$ is a maximal order and hence behaves in a way similar to the ring of integers in a number field. You can disable the (costly) computation of a maximal order with an optional argument: \bprog al5 = alginit(nf,[6,hf,hi],,0); @eprog\noindent This command should be faster than the initialization of~\kbd{al3}. As in number fields, you can represent elements of central simple algebras in \emph{algebraic form}, which means the cyclic algebra representation we described above, or in \emph{basis form}, which means as a~$\Q$-linear combination of the integral basis. You can switch between the two representations: \bprog algalgtobasis(al2, a) algalgtobasis(al1, j) algbasistoalg(al3, algrandom(al3,1)) @eprog\noindent As usual you can compute any elementary operation: try various combinations of~\kbd{algadd}, \kbd{algsub}, \kbd{algneg}, \kbd{algmul}, \kbd{alginv}, \kbd{algsqr}, \kbd{algpow}. Every central simple algebra~$A$ over a number field~$F$ admits a \emph{splitting field}, i.e. an extension~$K/F$ such that~$A\otimes_F K\cong M_d(K)$. We always store such a splitting in an~\kbd{alginit} structure, and you can access it using \bprog algsplittingfield(al1) \\ K as an rnf structure algtomatrix(al1, k) \\ image of k by the splitting isomorphism @eprog\noindent For every~$x\in A$, the trace (resp. determinant, characteristic polynomial) of that matrix is in~$K$ (resp.~$K$,~$K[X]$) and is called the \emph{reduced trace} (resp. \emph{reduced norm}, \emph{reduced characteristic polynomial}) of~$x$. You can compute them using \bprog algtrace(al3, vector(72,i,i==3)~) algnorm(al2, a) algcharpoly(al1, -1+i+j+2*k) @eprog \section{Plotting} PARI supports high and low-level graphing functions, on a variety of output devices: a special purpose window under standard graphical environments (the \kbd{X Windows} system, Mac OS X, Microsoft Windows), or a \kbd{PostScript} file ready for the printer. These functions use a multitude of flags, which are mostly power-of-2. To simplify understanding we first give these flags symbolic names. \bprog /* Relative positioning of graphic objects: */ nw = 0; se = 4; relative = 1; sw = 2; ne = 6; /* String positioning: */ /* V */ bottom = 0; /* H */ left = 0; /* Fine tuning */ hgap = 16; vcenter = 4; center = 1; vgap = 32; top = 8; right = 2; @eprog\noindent We also decrease drastically the default precision. \bprog \p 9 @eprog\noindent This is very important, since plotting involves calculation of functions at a huge number of points, and a relative precision of 38 significant digits is an obvious overkill: the output device resolution certainly won't reach $10^{38} \times 10^{38}$ pixels! Start with a simple plot: \bprog ploth(X = -2, 2, sin(X^7)) @eprog\noindent You can see the limitations of the ``straightforward'' mode of plotting: while the first several cycles of \kbd{sin} reach $-1$ and $1$, the cycles which are closer to the left and right border do not. This is understandable, since PARI is calculating $\sin(X^7)$ at many (evenly spaced) points, but these points have no direct relationship to the ``interesting'' points on the graph of this function. No value close enough to the maxima and minima are calculated, which leads to wrong turning points in the graph. To fix this, one may use variable steps which are smaller where the function varies rapidly: \bprog ploth(X = -2, 2, sin(X^7), "Recursive") @eprog\noindent The precision near the edges of the graph is much better now. However, the recursive plotting (named so since PARI subdivides intervals until the graph becomes almost straight) has its own pitfalls. Try \bprog ploth(X = -2, 2, sin(X*7), "Recursive") @eprog\noindent The graph looks correct far away, but it has a straight interval near the origin, and some sharp corners as well. This happens because the graph is symmetric with respect to the origin, thus the middle 3 points calculated during the initial subdivision of $[-2,2]$ are exactly on the same line. To PARI this indicates that no further subdivision is needed, and it plots the graph on this subinterval as a straight line. There are many ways to circumvent this. Say, one can make the right limit 2.1. Or one can ask PARI for an initial subdivision into 16 points instead of default 15: \bprog ploth(X = -2, 2, sin(X*7), "Recursive", 16) @eprog\noindent All these arrangements break the symmetry of the initial subdivision, thus make the problem go away. Eventually PARI will be able to better detect such pathological cases, but currently some manual intervention may be required. The function \kbd{ploth} has some additional enhancements which allow graphing in situations when the calculation of the function takes a lot of time. Let us plot $\zeta({1\over 2} + it)$: \bprog ploth(t = 100, 110, real(zeta(0.5+I*t)), /*empty*/, 1000) @eprog\noindent This can take quite some time. (1000 is close to the default for many plotting devices, we want to specify it explicitly so that the result does not depend on the output device.) Try the recursive plot: \bprog ploth(t = 100, 110, real(zeta(0.5+I*t)), "Recursive") @eprog\noindent It takes approximately the same time. Now try specifying fewer points, but make PARI approximate the data by a smooth curve: \bprog ploth(t = 100, 110, real(zeta(0.5+I*t)), "Splines", 100) @eprog\noindent This takes much less time, and the output is practically the same. How to compare these two outputs? We will see it shortly. Right now let us plot both real and complex parts of $\zeta$ on the same graph: \bprog f(t) = my(z = zeta(0.5+I*t)); [real(z),imag(z)]; ploth(t = 100, 110, f(t), , 1000) @eprog\noindent (Note the use of the temporary variable \kbd{z}; \kbd{my} declares it local to the function's body.) Note how one half of the roots of the real and imaginary parts coincide. Why did we define a function \kbd{f(t)}? To avoid calculation of $\zeta({1\over2} + it)$ twice for the same value of t. Similarly, we can plot parametric graphs: \bprog ploth(t = 100, 110, f(t), "Parametric", 1000) @eprog\noindent In that case (parametric plot of the real and imaginary parts of a complex function), we can also use directly \bprog ploth(t = 100, 110, zeta(0.5+I*t), "Complex", 1000) ploth(t = 100, 110, zeta(0.5+I*t), "Complex|Splines", 100) @eprog If your plotting device supports it, you may ask PARI to show the points in which it calculated your function: \bprog ploth(t = 100, 110, f(t), "Parametric|Splines|Points_too", 100) @eprog As you can see, the points are very dense on the graph. To see some crude graph, one can even decrease the number of points to 30. However, if you decrease the number of points to 20, you can see that the approximation to the graph now misses zero. Using splines, one can create reasonable graphs for larger values of t, say with \bprog ploth(t = 10000, 10004, f(t), "Parametric|Splines|Points_too", 50) @eprog How can we compare two graphs of the same function plotted by different methods? Documentation shows that \kbd{ploth} does not provide any direct method to do so. However, it is possible, and even not very complicated. The solution comes from the other direction. PARI has a power mix of high level plotting function with low level plotting functions, and these functions can be combined together to obtain many different effects. Return back to the graph of $\sin(X^7)$. Suppose we want to create an additional rectangular frame around our graph. No problem! First, all low-level graphing work takes place in some virtual drawing boards (numbered from 0 to 15), called ``rectangles'' (or ``rectwindows''). So we create an empty ``rectangle'' and name it rectangle 2 (any number between 0 and 15 would do): \bprog plotinit(2) plotscale(2, 0,1, 0,1) @eprog This creates a rectwindow whose size exactly fits the size of the output device, and makes the coordinate system inside it go from 0 to 1 (for both $x$ and $y$). Create a rectangular frame along the boundary of this rectangle: \bprog plotmove(2, 0,0) plotbox(2, 1,1) @eprog Suppose we want to draw the graph inside a subrectangle of this with upper and left margins of $0.10$ (so 10\% of the full rectwindow width), and lower and top margins of $0.02$, just to make it more interesting. That makes it an $0.88 \times 0.88$ subrectangle; so we create another rectangle (call it 3) of linear size 0.88 of the size of the initial rectangle and graph the function in there: \bprog plotinit(3, 0.88, 0.88, relative) plotrecth(3, X = -2, 2, sin(X^7), "Recursive") @eprog (nothing is output yet, these commands only fills the virtual drawing boards with PARI graphic objects). Finally, output rectangles 2 and 3 on the same plot, with the required offsets (counted from upper-left corner): \bprog plotdraw([2, 0,0, 3, 0.1,0.02], relative) @eprog \noindent The output misses something comparing to the output of \kbd{ploth}: there are no coordinates of the corners of the internal rectangle. If your output device supports mouse operations (only \kbd{gnuplot} does), you can find coordinates of particular points of the graph, but it is nice to have something printed on a hard copy too. However, it is easy to put $x$- and $y$-limits on the graph. In the coordinate system of the rectangle 2 the corners are $(0.1,0.1)$, $(0.1,0.98)$, $(0.98,0.1)$, $(0.98,0.98)$. We can mark lower $x$-limit by doing \bprog plotmove(2, 0.1,0.1) plotstring(2, "-2.000", left+top+vgap) @eprog\noindent Computing the minimal and maximal $y$-coordinates might be trickier, since in principle we do not know the range in advance (though for $\sin(X^7)$ it is easy to guess!). Fortunately, \kbd{plotrecth} returns the $x$- and $y$-limits. Here is the complete program: \bprog plotinit(3, 0.88, 0.88, relative) lims = plotrecth(3, X = -2, 2, sin(X^7), "Recursive") \p 3 \\ @com $3$ significant digits for the bounding box are enough plotinit(2); plotscale(2, 0,1, 0,1) plotmove(2, 0,0); plotbox(2, 1,1) plotmove(2, 0.1,0.1); plotstring(2, lims[1], left+top+vgap) plotstring(2, lims[3], bottom+vgap+right+hgap) plotmove(2, 0.98,0.1); plotstring(2, lims[2], right+top+vgap) plotmove(2, 0.1,0.98); plotstring(2, lims[4], right+hgap+top) plotdraw([2, 0,0, 3, 0.1,0.02], relative) @eprog We started with a trivial requirement: have an additional frame around the graph, and it took some effort to do so. But at least it was possible, and PARI did the hardest part: creating the actual graph. Now do a different thing: plot together the ``exact'' graph of $\zeta({1/2}+it)$ together with one obtained from splines approximation. We can emit these graphs into two rectangles, say 0 and 1, then put these two rectangles together on one plot. Or we can emit these graphs into one rectangle 0. However, a problem arises: note how we introduced a coordinate system in rectangle 2 of the above example, but we did not introduce a coordinate system in rectangle 3. Plotting a graph into rectangle 3 automatically created a coordinate system inside this rectangle (you could see this coordinate system in action if your output device supports mouse operations). If we use two different methods of graphing, the bounding boxes of the graphs will not be exactly the same, thus outputting the rectangles may be tricky. Thus during the second plotting we ask \kbd{plotrecth} to use the coordinate system of the first plotting. Let us add another plotting with fewer points too: \bprog plotinit(0, 0.9,0.9, relative) plotrecth(0, t=100,110, f(t), "Parametric",300) plotrecth(0, t=100,110, f(t), "Parametric|Splines|Points_too|no_Rescale",30); plotrecth(0, t=100,110, f(t), "Parametric|Splines|Points_too|no_Rescale",20); plotdraw([0, 0.05,0.05], relative) @eprog This achieves what we wanted: we may compare different ways to plot a graph, but the picture is confusing: which graph is what, and why there are multiple boxes around the graph? At least with some output devices one can control how the output curves look like, so we can use this to distinguish different graphs. And the mystery of multiple boxes is also not that hard to solve: they are bounding boxes for calculated points on each graph. We can disable output of bounding boxes with appropriate options for \kbd{plotrect}. With these frills the script becomes: \bprog plotinit(0, 0.9,0.9, relative) plotrecth(0, t=100,110, f(t), "Parametric|no_Lines", 300) opts="Parametric|Splines|Points_too|no_Rescale|no_Frame|no_X_axis|no_Y_axis"; plotrecth(0, t=100,110,f(t), opts, 30); plotdraw([0, 0.05,0.05], relative) @eprog \noindent Plotting axes on the second graph would not hurt, but is not needed either, so we omit them. One can see that the discrepancies between the exact graph and one based on 30 points exist, but are pretty small. On the other hand, decreasing the number of points to 20 would make quite a noticeable difference. Additionally, one can ask PARI to convert a plot to PS (PostScript) or SVG (Scalable Vector Graphics) format: just use the command \kbd{plotexport} instead of \kbd{plotdraw} in the above examples (or \kbd{plothexport} instead of \kbd{ploth}). This returns a character string which you can then write to a file using \kbd{write}. Now suppose we want to join many different small graphs into one picture. We cannot use one rectangle for all the output as we did in the example with $\zeta({1/2}+it)$, since the graphs should go into different places. Rectangles are a scarce commodity in PARI, since only 16 of them are user-accessible. Does it mean that we cannot have more than 16 graphs on one picture? Thanks to an additional operation of PARI plotting engine, there is no such restrictions. This operation is \kbd{plotcopy}. The following script puts 4 different graphs on one plot using 2 rectangles only, \kbd{A} and \kbd{T}: \bprog A = 2; \\@com accumulator T = 3; \\@com temporary target plotinit(A); plotscale(A, 0, 1, 0, 1) plotinit(T, 0.42, 0.42, relative); plotrecth(T, x= -5, 5, sin(x), "Recursive") plotcopy(T, 2, 0.05, 0.05, relative + nw) plotmove(A, 0.05 + 0.42/2, 1 - 0.05/2) plotstring(A,"Graph", center + vcenter) plotinit(T, 0.42, 0.42, relative); plotrecth(T, x= -5, 5, [sin(x),cos(2*x)], 0) plotcopy(T, 2, 0.05, 0.05, relative + ne) plotmove(A, 1 - 0.05 - 0.42/2, 1 - 0.05/2) plotstring(A,"Multigraph", center + vcenter) plotinit(T, 0.42, 0.42, relative); plotrecth(T, x= -5, 5, [sin(3*x), cos(2*x)], "Parametric") plotcopy(T, 2, 0.05, 0.05, relative + sw) plotmove(A, 0.05 + 0.42/2, 0.5) plotstring(A,"Parametric", center + vcenter) plotinit(T, 0.42, 0.42, relative); plotrecth(T, x= -5, 5, [sin(x), cos(x), sin(3*x),cos(2*x)], "Parametric") plotcopy(T, 2, 0.05, 0.05, relative + se) plotmove(A, 1 - 0.05 - 0.42/2, 0.5) plotstring(A,"Multiparametric", center + vcenter) plotmove(A, 0, 0) plotbox(A, 1, 1) plotdraw(A) \\ s = plotexport(A, relative); write("foo.ps", s) \\ @com if hard copy needed @eprog The rectangle \kbd{A} plays the role of accumulator, rectangle \kbd{T} is used as a target to \kbd{plotrecth} only. Immediately after plotting into rectangle \kbd{T} the contents is copied to accumulator. Let us explain numbers which appear in this example: we want to create 4 internal rectangles with a gap 0.06 between them, and the outside gap 0.05 (of the size of the plot). This leads to the size 0.42 for each rectangle. We also put captions above each graph, centered in the middle of each gap. There is no need to have a special rectangle for captions: they go into the accumulator too. To simplify positioning of the rectangles, the above example uses relative ``geographic'' notation: the last argument of \kbd{plotcopy} specifies the corner of the graph (say, northwest) one counts offset from. (Positive offsets go into the rectangle.) To demonstrate yet another useful plotting function, design a program to plot Taylor polynomials for a $\sin x$ about 0. For simplicity, make the program good for any function, but assume that a function is odd, so only odd-numbered Taylor series about 0 should be plotted. Start with defining some useful shortcuts \bprog xlim = 13; ordlim = 25; f(x) = sin(x); default(seriesprecision,ordlim) farray(t) = vector((ordlim+1)/2, k, truncate( f(1.*t + O(t^(2*k+1)) ))); FARRAY = farray('t); \\@com\kbd{'t} to make sure \kbd{t} is a free variable @eprog\noindent \kbd{farray(x)} returns a vector of Taylor polynomials for $f(x)$, which we store in \kbd{FARRAY}. We want to plot $f(x)$ into a rectangle, then make the rectangle which is 1.2 times higher, and plot Taylor polynomials into the larger rectangle. Assume that the larger rectangle takes 0.9 of the final plot. First of all, we need to measure the height of the smaller rectangle: \bprog plotinit(3, 0.9, 0.9/1.2, 1); opts = "Recursive | no_X_axis|no_Y_axis|no_Frame"; lims = plotrecth(3, x= -xlim, xlim, f(x), opts,16); h = lims[4] - lims[3]; @eprog\noindent Next step is to create a larger rectangle, and plot the Taylor polynomials into the larger rectangle: \bprog plotinit(4, 0.9,0.9, relative); plotscale(4, lims[1], lims[2], lims[3] - h/10, lims[4] + h/10) plotrecth(4, x = -xlim, xlim, subst(FARRAY,t,x), "no_Rescale"); @eprog Here comes the central command of this example: \bprog plotclip(4) @eprog\noindent What does it do? The command \kbd{plotrecth(\dots, "no\_Rescale")} scales the graphs according to coordinate system in the rectangle, but it does not pay any other attention to the size of the rectangle. Since \kbd{xlim} is 13, the Taylor polynomials take very large values in the interval \kbd{-xlim...xlim}. In particular, significant part of the graphs is going to be \emph{outside} of the rectangle. \kbd{plotclip} removes the parts of the plottings which fall off the rectangle boundary \bprog plotinit(2) plotscale(2, 0.0, 1.0, 0.0, 1.0) plotmove(2,0.5,0.975) plotstring(2,"Multiple Taylor Approximations",center+vcenter) plotdraw([2, 0, 0, 3, 0.05, 0.05 + 0.9/12, 4, 0.05, 0.05], relative) @eprog\noindent These commands draw a caption, and combine 3 rectangles (one with the caption, one with the graph of the function, and one with graph of Taylor polynomials) together. The plots are not very beautiful with the default colors. See \kbd{examples/taylor.gp} for a user function encapsulating the above example, and a colormap generator. This finishes our survey of PARI plotting functions, but let us add some remarks. First of all, for a typical output device the picture is composed of small colored squares (pixels), as a very large checkerboard. Each output rectangle is a disjoint union of such squares. Each drop of paint in the rectangle will color a whole square in it. Since the rectangle has a coordinate system, it is important to know how this coordinate system is positioned with respect to the boundaries of these squares. The command \kbd{plotscale} describes a range of $x$ and $y$ in the rectangle. The limit values of $x$ and $y$ in the coordinate system are coordinates \emph{of the centers} of corner squares. In particular, if ranges of $x$ and $y$ are $[0,1]$, then the segment which connects (0,0) with (0,1) goes along the \emph{middle} of the left column of the rectangle. In particular, if we made tiny errors in calculation of endpoints of this segment, this will not change which squares the segment intersects, thus the resulting picture will be the same. (It is important to know such details since many calculations are approximate.) Another consideration is that all examples we did in this section were using relative sizes and positions for the rectangles. This is nice, since different output devices will have very similar pictures, while we did not need to care about particular resolution of the output device. On the other hand, using relative positions does not guarantee that the pictures will be similar. Why? Even if two output devices have the same resolution, the picture may be different. The devices may use fonts of different size, or may have a different ``unit of length''. The information about the device in PARI is encoded in 6 numbers: resolution, size of a character cell of the font, and unit of length, all separately for horizontal and vertical direction. These sizes are expressed as numbers of pixels. To inspect these numbers one may use the function \kbd{plothsizes}. The ``units of length'' are currently used to calculate right and top gaps near graph rectangle of \kbd{ploth}, and gaps for \kbd{plotstring}. Left and bottom gaps near graph rectangle are calculate using both units of length, and sizes of character boxes (so that there is enough place to print limits of the graphs). What does it show? Using relative sizes during plotting produces \var{approximately} the same plotting on different devices, but does not ensure that the plottings ``look the same''. Moreover, ``looking the same'' is not a desirable target, ``looking tuned for the environment'' will be much better. If you want to produce such fine-tuned plottings, you need to abandon a relative-size model, and do your plottings in pixel units. To do this one removes flag \kbd{relative} from the above examples, which will make size and offset arguments interpreted this way. After querying sizes with \kbd{plothsizes} one can fine-tune sizes and locations of subrectangles to the details of an arbitrary plotting device. The last two elements of the array returned by \kbd{plothsizes} are the dimensions of the display, if applicable. If there is no real display, like in svg or postscript plots, the width and height of display are set to $0$. To check how good your fine-tuning is, you may test your graphs with a medium-resolution plotting (as many display output devices are), and with a low-resolution plotting (say, with \kbd{plotterm("dumb")} of gnuplot). \section{GP Programming} Do we really need such a section after all we have learnt so far? We now know how to write scripts and feed them to \kbd{gp}, in particular how to define functions. It's possible to define \emph{member} function as well, but we trust you to find them in the manual. We have seen most control statements: the missing ones (\kbd{while}, \kbd{break}, \kbd{next}, \kbd{return} and various \kbd{for} loops) should be straightforward. (You won't forget to look them up in the manual, will you?) Output is done via variants of the familiar \kbd{print} (to screen), \kbd{write} (to a file). Input via \kbd{read} (from file), \kbd{input} (querying user), or \kbd{extern} (from an external auxiliary program). To customize \kbd{gp}, e.g.~increase the default stack space or load your private script libraries on startup, look up \kbd{The preferences file} section in the User's manual. We strongly advise to set \kbd{parisizemax} to a large non-zero value, about what you believe your machine can stand: this both limits the amount of memory PARI will use for its computation (thereby keeping your machine usable), and let PARI increases its stack size (up to this limit) to accommodate large computations. If you regularly see \kbd{PARI stack overflows} messages, think about this one! For clarity, it is advisable to declare local variables in user functions (and in fact, with the smallest possible scope), as we have done so far with the keyword \kbd{my}. As usual, one is usually better off avoiding global variables altogether. \emph{Break loops} are more powerful than we saw: look up \kbd{dbg\_down} / \kbd{dbg\_up} (to get a chance to inspect local variables in various scopes) and \kbd{dbg\_err} (to access all components of an error context). To reach grandwizard status, you may need to understand the all powerful \kbd{install} function, which imports into \kbd{gp} an (almost) arbitrary function from the PARI library (and elsewhere too!), or how to use the \kbd{gp2c} compiler and its extended types. But both are beyond the scope of the present document. Have fun! \bye pari-2.11.2/doc/develop.tex0000644000175000017500000007405513457566441014135 0ustar billbill\def\TITLE{Developer's Guide to the PARI library} \input parimacro.tex % START TYPESET \begintitle \vskip 2.5truecm \centerline{\mine Developer's Guide} \vskip 1.truecm \centerline{\mine to} \vskip 1.truecm \centerline{\mine the PARI library} \vskip 1.truecm \centerline{\sectiontitlebf (version \vers)} \vskip 1.truecm \authors \endtitle \copyrightpage \tableofcontents \openin\std=develop.aux \ifeof\std \else \input develop.aux \fi \chapno=0 \chapter{Work in progress} This draft documents private internal functions and structures for hard-core PARI developers. Anything in here is liable to change on short notice. Don't use anything in the present document, unless you are implementing new features for the PARI library. Try to fix the interfaces before using them, or document them in a better way. If you find an undocumented hack somewhere, add it here. Hopefully, this will eventually document everything that we buried in \kbd{paripriv.h} or even more private header files like \kbd{anal.h}. Possibly, even implementation choices! Way to go. \section{The type \typ{CLOSURE}}\kbdsidx{t_CLOSURE}\sidx{closure} This type holds closures and functions in compiled form, so is deeply linked to the internals of the GP compiler and evaluator. The length of this type can be $6$, $7$ or $8$ depending whether the object is an ``inline closure'', a ``function'' or a ``true closure''. A function is a regular GP function. The GP input line is treated as a function of arity $0$. A true closure is a GP function defined in a non-empty lexical context. An inline closure is a closure that appears in the code without the preceding \kbd{->} token. They are generally attached to the prototype code 'E' and 'I'. Inline closures can only exist as data of other closures, see below. In the following example, \bprog f(a=Euler)=x->sin(x+a); g=f(Pi/2); plot(x=0,2*Pi,g(x)) @eprog\noindent \kbd{f} is a function, \kbd{g} is a true closure and both \kbd{Euler} and \kbd{g(x)} are inline closures. This type has a second codeword \kbd{z[1]}, which is the arity of the function or closure. This is zero for inline closures. To access it, use \fun{long}{closure_arity}{GEN C} \item \kbd{z[2]} points to a \typ{STR} which holds the opcodes. To access it, use \fun{GEN}{closure_get_code}{GEN C}. \fun{const char *}{closure_codestr}{GEN C} returns as an array of \kbd{char} starting at $1$. \item \kbd{z[3]} points to a \typ{VECSMALL} which holds the operands of the opcodes. To access it, use \fun{GEN}{closure_get_oper}{GEN C} \item \kbd{z[4]} points to a \typ{VEC} which hold the data referenced by the \kbd{pushgen} opcodes, which can be \typ{CLOSURE}, and in particular inline closures. To access it, use \fun{GEN}{closure_get_data}{GEN C} \item \kbd{z[5]} points to a \typ{VEC} which hold extra data needed for error-reporting and debugging. See \secref{se:dbgclosure} for details. To access it, use \fun{GEN}{closure_get_dbg}{GEN C} Additionally, for functions and true closures, \item \kbd{z[6]} usually points to a \typ{VEC} with two components which are \typ{STR}. The first one displays the list of arguments of the closure without the enclosing parentheses, the second one the GP code of the function at the right of the \kbd{->} token. They are used to display the closure, either in implicit or explicit form. However for closures that were not generated from GP code, \kbd{z[6]} can point to a \typ{STR} instead. To access it, use \fun{GEN}{closure_get_text}{GEN C} Additionally, for true closure, \item \kbd{z[7]} points to a \typ{VEC} which holds the values of all lexical variables defined in the scope the closure was defined. To access it, use \fun{GEN}{closure_get_frame}{GEN C} \subsec{Debugging information in closure}\label{se:dbgclosure} Every \typ{CLOSURE} object \kbd{z} has a component \kbd{dbg=z[5]} which hold extra data needed for error-reporting and debugging. The object \kbd{dbg} is a \typ{VEC} with $3$ components: \kbd{dbg[1]} is a \typ{VECSMALL} of the same length than \kbd{z[3]}. For each opcode, it holds the position of the corresponding GP source code in the strings stored in \kbd{z[6]} for function or true closures, positive indices referring to the second strings, and negative indices referring to the first strings, the last element being indexed as $-1$. For inline closures, the string of the parent function or true closure is used instead. \kbd{dbg[2]} is a \typ{VECSMALL} that lists opcodes index where new lexical local variables are created. The value $0$ denotes the position before the first offset and variables created by the prototype code 'V'. \kbd{dbg[3]} is a \typ{VEC} of \typ{VECSMALL}s that give the list of \kbd{entree*} of the lexical local variables created at a given index in \kbd{dbg[2]}. \section{The type \typ{LIST}}\kbdsidx{t_LIST}\sidx{list} This type needs to go through various hoops to support GP's inconvenient memory model. Don't use \typ{LIST}s in pure library mode, reimplement ordinary lists! This dynamic type is implemented by a \kbd{GEN} of length 3: two codewords and a vector containing the actual entries. In a normal setup (a finished list, ready to be used), \item the vector is malloc'ed, so that it can be realloc'ated without moving the parent \kbd{GEN}. \item all the entries are clones, possibly with cloned subcomponents; they must be deleted with \tet{gunclone_deep}, not \tet{gunclone}. The following macros are proper lvalues and access the components \fun{long}{list_nmax}{GEN L}: current maximal number of elements. This grows as needed. \fun{GEN}{list_data}{GEN L}: the elements. If \kbd{v = list\_data(L)}, then either \kbd{v} is \kbd{NULL} (empty list) or \kbd{l = lg(v)} is defined, and the elements are \kbd{v[1]}, \dots, \kbd{v[l-1]}. In most \kbd{gerepile} scenarios, the list components are not inspected and a shallow copy of the malloc'ed vector is made. The functions \kbd{gclone}, \kbd{copy\_bin\_canon} are exceptions, and make a full copy of the list. The main problem with lists is to avoid memory leaks; in the above setup, a statement like \kbd{a = List(1)} would already leak memory, since \kbd{List(1)} allocates memory, which is cloned (second allocation) when assigned to \kbd{a}; and the original list is lost. The solution we implemented is \item to create anonymous lists (from \kbd{List}, \kbd{gtolist}, \kbd{concat} or \kbd{vecsort}) entirely on the stack, \emph{not} as described above, and to set \kbd{list\_nmax} to $0$. Such a list is not yet proper and trying to append elements to it fails: \bprog ? listput(List(),1) *** variable name expected: listput(List(),1) *** ^---------------- @eprog\noindent If we had been malloc'ing memory for the \kbd{List([1,2,3])}, it would have leaked already. \item as soon as a list is assigned to a variable (or a component thereof) by the GP evaluator, the assigned list is converted to the proper format (with \kbd{list\_nmax} set) previously described. \fun{GEN}{listcopy}{GEN L} return a full copy of the \typ{LIST}~\kbd{L}, allocated on the \emph{stack} (hence \kbd{list\_nmax} is $0$). Shortcut for \kbd{gcopy}. \fun{GEN}{mklistcopy}{GEN x} returns a list with a single element $x$, allocated on the stack. Used to implement most cases of \kbd{gtolist} (except vectors and lists). A typical low-level construct: \bprog long l; /* assume L is a t_LIST */ L = list_data(L); /* discard t_LIST wrapper */ l = L? lg(L): 1; for (i = 1; i < l; i++) output( gel(L, i) ); for (i = 1; i < l; i++) gel(L, i) = gclone( ... ); @eprog \subsec{Maps as Lists} GP's maps are implemented on top of \typ{LIST}s so as to benefit from their peculiar memory models. Lists thus come in two subtypes: \typ{LIST\_RAW} (actual lists) and \typ{LIST\_MAP} (a map). \fun{GEN}{mklist_typ}{long t} create a list of subtype $t$. \fun{GEN}{mklist}{void} is an alias for \bprog mklist_typ(t_LIST_RAW); @eprog and \fun{GEN}{mkmap}{void} is an alias for \bprog mklist_typ(t_LIST_MAP); @eprog \fun{long}{list_typ}{GEN L} return the list subtype, either \typ{LIST\_RAW} or \typ{LIST\_MAP}. \fun{void}{listpop}{GEN L, long index} as \kbd{listpop0}, assuming that $L$ is a \typ{LIST\_RAW}. \fun{GEN}{listput}{GEN list, GEN object, long index} as \kbd{listput0}, assuming that $L$ is a \typ{LIST\_RAW}. \fun{GEN}{mapdomain}{GEN T} vector of keys of the map $T$. \fun{GEN}{mapdomain_shallow}{GEN T} shallow version of \kbd{mapdomain}. \fun{GEN}{maptomat}{GEN T} convert a map to a factorization matrix. \fun{GEN}{maptomat_shallow}{GEN T} shallow version of \kbd{maptomat}. \section{Protection of non-interruptible code} GP allows the user to interrupt a computation by issuing SIGINT (usually by entering control-C) or SIGALRM (usually using alarm()). To avoid such interruption to occurs in section of code which are not reentrant (in particular \kbd{malloc} and \kbd{free}) the following mechanism is provided: \fun{}{BLOCK_SIGINT_START}{} Start a non-interruptible block code. Block both \kbd{SIGINT} and \kbd{SIGARLM}. \fun{}{BLOCK_SIGALRM_START}{} Start a non-interruptible block code. Block only \kbd{SIGARLM}. This is used in the \kbd{SIGINT} handler itself to delay an eventual pending alarm. \fun{}{BLOCK_SIGINT_END}{} End a non-interruptible block code The above macros make use of the following global variables: \tet{PARI_SIGINT_block}: set to $1$ (resp. $2$) by \kbd{BLOCK\_SIGINT\_START} (resp. \kbd{BLOCK\_SIGALRM\_START}). \tet{PARI_SIGINT_pending}: Either $0$ (no signal was blocked), \kbd{SIGINT} (\kbd{SIGINT} was blocked) or \kbd{SIGALRM} (\kbd{SIGALRM} was blocked). This need to be set by the signal handler. Within a block, an automatic variable \kbd{int block} is defined which records the value of \kbd{PARI\_SIGINT\_block} when entering the block. \subsec{Multithread interruptions} To support multithreaded programs, \kbd{BLOCK\_SIGINT\_START} and \kbd{BLOCK\_SIGALRM\_START} call \kbd{MT\_SIGINT\_BLOCK(block)}, and \kbd{BLOCK\_SIGINT\_END} calls \kbd{MT\_SIGINT\_UNBLOCK(block)}. \tet{MT_SIGINT_BLOCK} and \tet{MT_SIGINT_UNBLOCK} are defined by the multithread engine. They can calls the following public functions defined by the multithread engine. \fun{void}{mt_sigint_block}{void} \fun{void}{mt_sigint_unblock}{void} In practice this mechanism is used by the POSIX thread engine to protect against asychronous cancellation. \section{$\F_{l^2}$ field for small primes $l$} Let $l>2$ be a prime \kbd{ulong}. A \kbd{Fl2} is an element of the finite field $\F_{l^2}$ represented (currently) by a \kbd{Flx} of degree at most $1$ modulo a polynomial of the form $x^2-D$ for some non square $0\leq D #include pari_rl_interface S; ... pari_use_readline(S); @eprog\noindent The variable $S$, as initialized above, encapsulates the libpari readline interface. (And allow us to move gp's readline code to libpari without introducing a mandatory dependency on readline in libpari.) The following functions then become available: \fun{char**}{pari_completion_matches}{pari_rl_interface *pS, const char *s, long pos, long *wordpos} given a command string $s$, where the cursor is at index \kbd{pos}, return an array of completion matches. If \kbd{wordpos} is not \kbd{NULL}, set \kbd{*wordpos} to the index for the start of the expression we complete. \fun{char**}{pari_completion}{pari_rl_interface *pS, char *text, int start, int end} the low-level completer called by \tet{pari_completion_matches}. The following wrapper \bprog char** gp_completion(char *text, int START, int END) { return pari_completion(&S, text, START, END);) @eprog\noindent is a valid value for \tet{rl_attempted_completion_function}. \section{Constructors called by \kbd{pari\_init} functions} \fun{void}{pari_init_buffers}{} \fun{void}{pari_init_compiler}{} \fun{void}{pari_init_defaults}{} \fun{void}{pari_init_evaluator}{} \fun{void}{pari_init_files}{} \fun{void}{pari_init_floats}{} \fun{void}{pari_init_graphics}{} \fun{void}{pari_init_homedir}{} \fun{void}{pari_init_parser}{} \fun{void}{pari_init_paths}{} \fun{void}{pari_init_primetab}{} \fun{void}{pari_init_rand}{} \fun{void}{pari_init_seadata}{} \section{Destructors called by \kbd{pari\_close}} \fun{void}{pari_close_compiler}{} \fun{void}{pari_close_evaluator}{} \fun{void}{pari_close_files}{} \fun{void}{pari_close_floats}{} \fun{void}{pari_close_homedir}{} \fun{void}{pari_close_mf}{} \fun{void}{pari_close_parser}{} \fun{void}{pari_close_paths}{} \fun{void}{pari_close_primes}{} \section{Constructors and destructors used by the \kbd{pthreads} interface} \item Called by \tet{pari_thread_sync} \fun{void}{pari_pthread_init_primetab}{} \fun{void}{pari_pthread_init_seadata}{} \fun{void}{pari_pthread_init_varstate}{} \item Called by \tet{pari_thread_start} \fun{void}{pari_thread_init_primetab}{} \fun{void}{pari_thread_init_seadata}{} \fun{void}{pari_thread_init_varstate}{} \item Called by \tet{pari_thread_close} \fun{void}{pari_thread_close_files}{} \newpage \chapter{Regression tests, benches} This chapter documents how to write an automated test module, say \kbd{fun}, so that \kbd{make test-fun} executes the statements in the \kbd{fun} module and times them, compares the output to a template, and prints an error message if they do not match. \item Pick a \emph{new} name for your test, say \kbd{fun}, and write down a GP script named \kbd{fun}. Make sure it produces some useful output and tests adequately a set of routines. \item The script should not be too long: one minute runs should be enough. Try to break your script into independent easily reproducible tests, this way regressions are easier to debug; e.g. include \kbd{setrand(1)} statement before a randomized computation. The expected output may be different on 32-bit and 64-bit machines but should otherwise be platform-independent. If possible, the output shouldn't even depend on \kbd{sizeof(long)}; using a \kbd{realprecision} that exists on both 32-bit and 64-bit architectures, e.g. \kbd{\bs p 38} is a good first step. You can use \kbd{sizebyte(0)==16} to detect a 64-bit architecture and \kbd{sizebyte(0)==8} for 32-bit. \item Dump your script into \kbd{src/test/in/} and run \kbd{Configure}. \item \kbd{make test-fun} now runs the new test, producing a \kbd{[BUG]} error message and a \kbd{.dif} file in the relevant object directory \kbd{Oxxx}. In fact, we compared the output to a non-existing template, so this must fail. \item Now \bprog patch -p1 < Oxxx/fun.dif @eprog\noindent generates a template output in the right place \kbd{src/test/32/fun}, for instance on a 32-bit machine. \item If different output is expected on 32-bit and 64-bit machines, run the test on a 64-bit machine and patch again, thereby producing \kbd{src/test/64/fun}. If, on the contrary, the output must be the same (preferred behavior!), make sure the output template land in the \kbd{src/test/32/} directory which provides a default template when the 64-bit output file is missing; in particular move the file from \kbd{src/test/64/} to \kbd{src/test/32/} if the test was run on a 64-bit machine. \item You can now re-run the test to check for regressions: no \kbd{[BUG]} is expected this time! Of course you can at any time add some checks, and iterate the test / patch phases. In particular, each time a bug in the \kbd{fun} module is fixed, it is a good idea to add a minimal test case to the test suite. \item By default, your new test is now included in \kbd{make test-all}. If it is particularly annoying, e.g. opens tons of graphical windows as \kbd{make test-ploth} or just much longer than the recommended minute, you may edit \kbd{config/get\_tests} and add the \kbd{fun} test to the list of excluded tests, in the \kbd{test\_extra\_out} variable. \item You can run a subset of existing tests by using the following idiom: \bprog cd Oxxx # call from relevant build directory make TESTS="lfuntype lfun gamma" test-all @eprog\noindent will run the \kbd{lfuntype}, \kbd{lfun} and \kbd{gamma} tests. This produces a combined output whereas the alternative \bprog make test-lfuntype test-lfun test-gamma @eprog\noindent would not. \item By default, the test is run on both the \kbd{gp-sta} and \kbd{gp-dyn} binaries, making it twice as slow. If the test is somewhat long, it can be annoying; you can restrict to one binary only using the \kbd{statest-all} or \kbd{dyntest-all} targets. Both accept the \kbd{TESTS} argument seen above. \bprog make test-lfuntype test-lfun gamma @eprog\noindent would not. \item Finally, the \kbd{get\_tests} script also defines the recipe for \kbd{make bench} timings, via the variable \kbd{test\_basic}. A test is included as \kbd{fun} or \kbd{fun\_$n$}, where $n$ is an integer $\leq 1000$; the latter means that the timing is weighted by a factor $n/1000$. (This was introduced a long time ago, when the \kbd{nfields} bench was so much slower than the others that it hid slowdowns elsewhere.) \section{Functions for GP2C} \subsec{Functions for safe access to components} These functions return the address of the requested component after checking it is actually valid. This is used by GP2C -C. \fun{GEN*}{safegel}{GEN x, long l}, safe version of \kbd{gel(x,l)} for \typ{VEC}, \typ{COL} and \typ{MAT}. \fun{long*}{safeel}{GEN x, long l}, safe version of \kbd{x[l]} for \typ{VECSMALL}. \fun{GEN*}{safelistel}{GEN x, long l} safe access to \typ{LIST} component. \fun{GEN*}{safegcoeff}{GEN x, long a, long b} safe version of \kbd{gcoeff(x,a, b)} for \typ{MAT}. \newpage \chapter{Parallelism} \section{The PARI MT interface} PARI provides an abstraction for doing parallel computations. \fun{void}{mt_queue_start}{struct pari_mt *pt, GEN worker} Let \kbd{worker} be a \typ{CLOSURE} object of arity $1$. Initialize the structure \kbd{pt} to evaluate \kbd{worker} in parallel. \fun{void}{mt_queue_start_lim}{struct pari_mt *pt, GEN worker, long lim} as \kbd{mt\_queue\_start}, where \kbd{lim} is an upper bound on the number of \kbd{tasks} to perform. Concretly the number of threads will be \kbd{min(lim,nbthreads}. The values $0$ and $1$ of \kbd{lim} are special: \item $0$: no limit, equivalent to \kbd{mt\_queue\_start}. \item $1$: no parallelism. Evaluate the tasks sequentially. \fun{void}{mt_queue_submit}{struct pari_mt *pt, long taskid, GEN task} Submit \kbd{task} to be evaluated by \kbd{worker}, or \kbd{NULL} if no further task is left to be submitted. The value \kbd{taskid} is user-specified and allows to later match up results and submitted tasks. \fun{GEN}{mt_queue_get}{struct pari_mt *pt, long *taskid, long *pending} Return the result of the evaluation by \kbd{worker} of one of the previously submitted tasks. Set \kbd{pending} to the number of remaining pending tasks. Set \kbd{taskid} to the value associate to this task by \kbd{mt\_queue\_submit}. Returns \kbd{NULL} if more tasks need to be submitted. \fun{void}{mt_queue_end}{struct pari_mt *pt} End the parallel execution. Calls to \tet{mt_queue_submit} and \tet{mt_queue_get} must alternate: each call to \tet{mt_queue_submit} must be followed by a call to \tet{mt_queue_get} before any other call to \tet{mt_queue_submit}, and conversely. The first call to \tet{mt_queue_get} will return \kbd{NULL} until a sufficient number of tasks have been submitted. If no more tasks are left to be submitted, use \bprog mt_queue_submit(handle, id, NULL) @eprog\noindent to allow further calls to \tet{mt_queue_get}. If \tet{mt_queue_get} sets \kbd{pending} to $0$, then no more tasks are pending and it is safe to call \tet{mt_queue_end}. The parameter \kbd{taskid} can be chosen arbitrarily. It is attached to a task but is not available to \kbd{worker}. It provides an efficient way to match a tasks and results. It is ignored when the parameter \kbd{task} is \kbd{NULL}. \subsec{Miscellaneous} \fun{void}{mt_broadcast}{GEN code}: do nothing unless the MPI threading engine is in use. In that case, it evaluates the closure \kbd{code} on all secondary nodes. This can be sued to change the states of the MPI child nodes. This is used by \tet{install}. \section{Initialization} This section is technical. \fun{void}{pari_mt_init}{void} \label{pari_mt_init} When using MPI, it is sometimes necessary to run initialization code on the child nodes after PARI is initialized. This can be done as follow: \item call \tet{pari_init_opts} with the flag \tet{INIT_noIMTm}. This initializes PARI, but not the MT engine. \item call the required initialization code. \item call \tet{pari_mt_init} to initialize the MT engine. Note that under MPI, this function only returns on the master node. On the child nodes, it enters slave mode. Thus it is no longer possible to run initialization code on the child nodes. See the file \kbd{examples/pari-mt.c} for an example. \fun{void}{pari_mt_close}{void} \label{pari_mt_close} When using MPI, calling \tet{pari_close} will terminate the MPI execution environment. If this is undesirable, you should call \tet{pari_close_opts} with the flag \tet{INIT_noIMTm}. This closes PARI without terminating the MPI execution environment It is allowed to call \kbd{pari\_mt\_close} later to terminate it. Note that the once MPI is terminated it cannot be restarted, and that it is considered an error for a program to end without having terminated the MPI execution environment. \vfill\eject \input index\end pari-2.11.2/doc/appb.tex0000644000175000017500000000211513326135265013374 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \appendix{A Sample program and Makefile} We assume that you have installed the PARI library and include files as explained in Appendix A or in the installation guide. If you chose differently any of the directory names, change them accordingly in the Makefiles. If the program example that we have given is in the file \kbd{extgcd.c}, then a sample Makefile might look as follows. Note that the actual file \kbd{examples/Makefile} is more elaborate and you should have a look at it if you intend to use \kbd{install()} on custom made functions. \bprog CC = cc INCDIR = @includedir LIBDIR = @libdir CFLAGS = -O -I$(INCDIR) -L$(LIBDIR) all: extgcd extgcd: extgcd.c $(CC) $(CFLAGS) -o extgcd extgcd.c -lpari -lm @eprog \noindent We then give the listing of the program \kbd{examples/extgcd.c} seen in detail in \secref{se:prog}. \bprogfile{../examples/extgcd.c} \vfill\eject pari-2.11.2/doc/refcard-mf.tex0000644000175000017500000003010613447371554014470 0ustar billbill% Copyright (c) 2007-2016 Karim Belabas. % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License % Reference Card for PARI-GP, Algebraic Number Theory. % Author: % Karim Belabas % Universite de Bordeaux, 351 avenue de la Liberation, F-33405 Talence % email: Karim.Belabas@math.u-bordeaux.fr % % See refcard.tex for acknowledgements and thanks. \def\TITLE{Modular forms, modular symbols} \input refmacro.tex \section{Modular Forms} \subsec{Dirichlet characters} Characters are encoded in three different ways: \item a \typ{INT} $D\equiv 0,1\mod 4$: the quadratic character $(D/\cdot)$; \item a \typ{INTMOD} \kbd{Mod}$(m,q)$, $m\in(\ZZ/q)^*$ using a canonical bijection with the dual group (the Conrey character $\chi_q(m,\cdot)$); \item a pair $[G,\kbd{chi}]$, where $G = \kbd{znstar}(q,1)$ encodes $(\ZZ/q\ZZ)^* = \sum_{j \leq k} (\ZZ/d_j\ZZ) \cdot g_j$ and the vector $\kbd{chi} = [c_1,\dots,c_k]$ encodes the character such that $\chi(g_j) = e(c_j/d_j)$. \medskip \li{initialize $G = (\ZZ/q\ZZ)^*$}{G = znstar$(q,1)$} \li{convert datum $D$ to $[G,\chi]$}{znchar$(D)$} \li{Galois orbits of Dirichlet characters}{chargalois$(G)$} \subsec{Spaces of modular forms} Arguments of the form $[N,k,\chi]$ give the level weight and nebentypus $\chi$; $\chi$ can be omitted: $[N,k]$ means trivial $\chi$.\hfil\break \li{initialize $S_k^{\text{new}}(\Gamma_0(N),\chi)$}{mfinit$([N,k,\chi])$} \li{initialize $S_k(\Gamma_0(N),\chi)$}{mfinit$([N,k,\chi],1)$} \li{initialize $S_k^{\text{old}}(\Gamma_0(N),\chi)$}{mfinit$([N,k,\chi],2)$} \li{initialize $E_k(\Gamma_0(N),\chi)$}{mfinit$([N,k,\chi],3)$} \li{initialize $M_k(\Gamma_0(N),\chi)$}{mfinit$([N,k,\chi],4)$} \li{find eigenforms}{mfsplit$(M)$} \li{statistics on self-growing caches}{getcache$()$} \smallskip We let $M$ = \kbd{mfinit}$(\dots)$ denote a modular space. \hfil\break \li{describe the space $M$}{mfdescribe$(M)$} \li{recover $(N,k,\chi)$}{mfparams$(M)$} \li{\dots the space identifier (0 to 4)}{mfspace$(M)$} \li{\dots the dimension of $M$ over $\CC$}{mfdim$(M)$} \li{\dots a $\CC$-basis $(f_i)$ of $M$}{mfbasis$(M)$} \li{\dots a basis $(F_j)$ of eigenforms}{mfeigenbasis$(M)$} \li{\dots polynomials defining $\QQ(\chi)(F_j)/\QQ(\chi)$}{mffields$(M)$} \smallskip \li{matrix of Hecke operator $T_n$ on $(f_i)$}{mfheckemat$(M,n)$} \li{eigenvalues of $w_Q$}{mfatkineigenvalues$(M,Q)$} \li{basis of period poynomials for weight $k$}{mfperiodpolbasis$(k)$} \li{basis of the Kohnen $+$-space}{mfkohnenbasis$(M)$} \li{\dots new space and eigenforms}{mfkohneneigenbasis$(M, b)$} \li{isomorphism $S_k^+(4N,\chi) \to S_{2k-1}(N,\chi^2)$} {mfkohnenbijection$(M)$} \smallskip Useful data can also be obtained a priori, without computing a complete modular space: \hfil\break \li{dimension of $S_k^{\text{new}}(\Gamma_0(N),\chi)$}{mfdim$([N,k,\chi])$} \li{dimension of $S_k(\Gamma_0(N),\chi)$}{mfdim$([N,k,\chi],1)$} \li{dimension of $S_k^{\text{old}}(\Gamma_0(N),\chi)$}{mfdim$([N,k,\chi],2)$} \li{dimension of $M_k(\Gamma_0(N),\chi)$}{mfdim$([N,k,\chi],3)$} \li{dimension of $E_k(\Gamma_0(N),\chi)$}{mfdim$([N,k,\chi],4)$} \li{Sturm's bound for $M_k(\Gamma_0(N),\chi)$}{mfsturm$(N,k)$} \subsec{$\Gamma_0(N)$ cosets} \li{list of right $\Gamma_0(N)$ cosets}{mfcosets$(N)$} \li{identify coset a matrix belongs to}{mftocoset} \subsec{Cusps} a cusp is given by a rational number or \kbd{oo}.\hfil\break \li{lists of cusps of $\Gamma_0(N)$}{mfcusps$(N)$} \li{number of cusps of $\Gamma_0(N)$}{mfnumcusps$(N)$} \li{width of cusp $c$ of $\Gamma_0(N)$}{mfcuspwidth$(N,c)$} \li{is cusp $c$ regular for $M_k(\Gamma_0(N),\chi)$?} {mfcuspisregular$([N,k,\chi], c)$} \subsec{Create an individual modular form} Besides \kbd{mfbasis} and \kbd{mfeigenbasis}, an individual modular form can be identified by a few coefficients.\hfil\break \li{modular form from coefficients}{mftobasis(mf,\var{vec})} \smallskip There are also many predefined ones:\hfil\break \li{Eisenstein series $E_k$ on $Sl_2(\ZZ)$}{mfEk$(k)$} \li{Eisenstein-Hurwitz series on $\Gamma_0(4)$}{mfEH$(k)$} \li{unary $\theta$ function (for character $\psi$)}{mfTheta$(\{\psi\})$} \li{Ramanujan's $\Delta$}{mfDelta$()$} \li{$E_k(\chi)$}{mfeisenstein$(k,\chi)$} \li{$E_k(\chi_1,\chi_2)$}{mfeisenstein$(k,\chi_1,\chi_2)$} \li{eta quotient $\prod_i \eta(a_{i,1} \cdot z)^{a_{i,2}}$}{mffrometaquo$(a)$} \li{newform attached to ell. curve $E/\QQ$}{mffromell$(E)$} \li{identify an $L$-function as a eigenform}{mffromlfun$(L)$} \li{$\theta$ function attached to $Q > 0$}{mffromqf$(Q)$} \li{trace form in $S_k^{\text{new}}(\Gamma_0(N),\chi)$} {mftraceform$([N,k,\chi])$} \li{trace form in $S_k(\Gamma_0(N),\chi)$} {mftraceform$([N,k,\chi], 1)$} \subsec{Operations on modular forms} In this section, $f$, $g$ and the $F[i]$ are modular forms\hfil\break \li{$f\times g$}{mfmul$(f,g)$} \li{$f / g$}{mfdiv$(f,g)$} \li{$f^n$}{mfpow$(f,n)$} \li{$f(q)/q^v$}{mfshift$(f,v)$} \li{$\sum_{i\leq k} \lambda_i F[i]$, $L = [\lambda_1,\dots,\lambda_k]$} {mflinear$(F,L)$} \li{$f = g$?}{mfisequal(f,g)} \li{expanding operator $B_d(f)$}{mfbd$(f,d)$} \li{Hecke operator $T_n f$}{mfhecke$(mf,f,n)$} \li{initialize Atkin--Lehner operator $w_Q$}{mfatkininit$(mf,Q)$} \li{\dots apply $w_Q$ to $f$}{mfatkin$(w_Q,f)$} \li{twist by the quadratic char $(D/\cdot)$}{mftwist$(f,D)$} \li{derivative wrt. $q \cdot d/dq$}{mfderiv$(f)$} \li{see $f$ over an absolute field}{mfreltoabs$(f)$} \li{Serre derivative $\big(q \cdot {d\over dq} - {k\over 12} E_2\big) f$} {mfderivE2$(f)$} \li{Rankin-Cohen bracket $[f,g]_n$}{mfbracket$(f,g,n)$} \li{Shimura lift of $f$ for discriminant $D$}{mfshimura$(mf,f,D)$} \subsec{Properties of modular forms} In this section, $f = \sum_n f_n q^n$ is a modular form in some space $M$ with parameters $N,k,\chi$.\hfil\break \li{describe the form $f$}{mfdescribe$(f)$} \li{$(N,k,\chi)$ for form $f$}{mfparams$(f)$} \li{the space identifier (0 to 4) for $f$}{mfspace$(mf,f)$} \li{$[f_0,\dots,f_n]$}{mfcoefs$(f, n)$} \li{$f_n$}{mfcoef$(f,n)$} \li{is $f$ a CM form?}{mfisCM$(f)$} \li{Galois rep. attached to $(1,\chi)$-eigenform} {mfgaloistype$(M,F)$} \li{Galois rep. attached to all $(1,\chi)$ eigenforms} {mfgaloistype$(M)$} \li{decompose $f$ on \kbd{mfbasis}$(M)$}{mftobasis$(M,f)$} \li{smallest level on which $f$ is defined}{mfconductor$(M,f)$} \li{decompose $f$ on $\oplus S_k^{\text{new}}(\Gamma_0(d))$, $d\mid N$} {mftonew$(M,f)$} \li{valuation of $f$ at cusp $c$}{mfcuspval$(M,f,c)$} \li{expansion at $\infty$ of $f \mid_k \gamma$}{mfslashexpansion$(M,f,\gamma,n)$} \li{$n$-Taylor expansion of $f$ at $i$}{mftaylor$(f,n)$} \li{all rational eigenforms matching criteria}{mfeigensearch} \li{\dots forms matching criteria}{mfsearch} \subsec{Forms embedded into $\CC$} Given a modular form $f$ in $M_k(\Gamma_0(N),\chi)$ its field of definition $\Q(f)$ has $n = [\Q(f):\Q(\chi)]$ embeddings into the complex numbers. If $n = 1$, the following functions return a single answer, attached to the canonical embedding of $f$ in $\CC[[q]]$; else a vector of $n$ results, corresponding to the $n$ conjugates of $f$.\hfill\break \li{complex embeddings of $\Q(f)$}{mfembed$(f)$} \li{... embed coefs of $f$}{mfembed$(f, v)$} \li{evaluate $f$ at $\tau\in{\cal H}$}{mfeval$(f,\tau)$} \li{$L$-function attached to $f$}{lfunmf$(mf,f)$} \li{\dots eigenforms of new space $M$}{lfunmf$(M)$} \subsec{Periods and symbols} The functions in this section depend on $[\Q(f):\Q(\chi)]$ as above. \li{initialize symbol $fs$ attached to $f$}{mfsymbol$(M,f)$} \li{evaluate symbol $fs$ on path $p$}{mfsymboleval$(fs,p)$} \li{Petersson product of $f$ and $g$}{mfpetersson$(fs,gs)$} \li{period polynomial of form $f$}{mfperiodpol$(M,fs)$} \li{period polynomials for eigensymbol $FS$}{mfmanin$(FS)$} \newcolumn \section{Modular Symbols} Let $G = \Gamma_0(N)$, $V_k = \QQ[X,Y]_{k-2}$, $L_k = \ZZ[X,Y]_{k-2}$. We let $\Delta = \text{Div}^0(\PP^1(\QQ))$; an element of $\Delta$ is a \emph{path} between cusps of $X_0(N)$ via the identification $[b]-[a] \to $ the path from $a$ to $b$. A path is coded by the pair $[a,b]$, where $a,b$ are rationals or \kbd{oo}, denoting the point at infinity $(1:0)$.\hfil\break Let $\MM_k(G) = \Hom_G(\Delta, V_k) \simeq H^1_c(X_0(N),V_k)$; an element of $\MM_k(G)$ is a $V_k$-valued \emph{modular symbol}. There is a natural decomposition $\MM_k(G) = \MM_k(G)^+ \oplus \MM_k(G)^-$ under the action of the $*$ involution, induced by complex conjugation. The \kbd{msinit} function computes either $\MM_k$ ($\varepsilon = 0$) or its $\pm$-parts ($\varepsilon = \pm1$) and fixes a minimal set of $\ZZ[G]$-generators $(g_i)$ of $\Delta$.\hfil\break \li{initialize $M = \MM_k(\Gamma_0(N))^\varepsilon$} {msinit$(N,k,\{\varepsilon=0\})$} \li{the level $M$}{msgetlevel$(M)$} \li{the weight $k$}{msgetweight$(M)$} \li{the sign $\varepsilon$}{msgetsign$(M)$} \li{Farey symbol attached to $G$}{mspolygon$(M)$} \smallskip \li{$\ZZ[G]$-generators $(g_i)$ and relations for $\Delta$}{mspathgens$(M)$} \li{decompose $p = [a,b]$ on the $(g_i)$}{mspathlog$(M,p)$} \smallskip \subsec{Create a symbol} \li{Eisenstein symbol attached to cusp $c$}{msfromcusp$(M,c)$} \li{cuspidal symbol attached to $E/\QQ$}{msfromell$(E)$} \li{symbol having given Hecke eigenvalues}{msfromhecke$(M,v,\{H\})$} \li{is $s$ a symbol ?}{msissymbol$(M,s)$} \subsec{Operations on symbols} \li{the list of all $s(g_i)$}{mseval$(M,s)$} \li{evaluate symbol $s$ on path $p=[a,b]$}{mseval$(M,s,p)$} \li{Petersson product of $s$ and $t$}{mspetersson$(M,s,t)$} \subsec{Operators on subspaces} An operator is given by a matrix of a fixed $\QQ$-basis. $H$, if given, is a stable $\QQ$-subspace of $\MM_k(G)$: operator is restricted to $H$.\hfil\break \li{matrix of Hecke operator $T_p$ or $U_p$}{mshecke$(M,p,\{H\})$} \li{matrix of Atkin-Lehner $w_Q$}{msatkinlehner$(M,Q\{H\})$} \li{matrix of the $*$ involution}{msstar$(M,\{H\})$} \subsec{Subspaces} A subspace is given by a structure allowing quick projection and restriction of linear operators. Its fist component is a matrix with integer coefficients whose columns for a $\QQ$-basis. If $H$ is a Hecke-stable subspace of $M_k(G)^+$ or $M_k(G)^-$, it can be split into a direct sum of Hecke-simple subspaces. To a simple subspace corresponds a single normalized newform $\sum_n a_n q^n$. \hfil\break \li{cuspidal subspace $S_k(G)^\varepsilon$}{mscuspidal$(M)$} \li{Eisenstein subspace $E_k(G)^\varepsilon$}{mseisenstein$(M)$} \li{new part of $S_k(G)^\varepsilon$}{msnew$(M)$} \li{split $H$ into simple subspaces (of dim $\leq d$)}{mssplit$(M,H,\{d\})$} \li{dimension of a subspace}{msdim$(M)$} \li{$(a_1,\dots, a_B)$ for attached newform} {msqexpansion$(M, H, \{B\})$} \li{$\ZZ$-structure from $H^1(G,L_k)$ on subspace $A$ }{mslattice$(M,A)$} \medskip \subsec{Overconvergent symbols and $p$-adic $L$ functions} Let $M$ be a full modular symbol space given by \kbd{msinit} and $p$ be a prime. To a classical modular symbol $\phi$ of level $N$ ($v_p(N)\leq 1$), which is an eigenvector for $T_p$ with non-zero eigenvalue $a_p$, we can attach a $p$-adic $L$-function $L_p$. The function $L_p$ is defined on continuous characters of $\text{Gal}(\QQ(\mu_{p^\infty})/\QQ)$; in GP we allow characters $\langle \chi \rangle^{s_1} \tau^{s_2}$, where $(s_1,s_2)$ are integers, $\tau$ is the Teichm\"uller character and $\chi$ is the cyclotomic character. The symbol $\phi$ can be lifted to an \emph{overconvergent} symbol $\Phi$, taking values in spaces of $p$-adic distributions (represented in GP by a list of moments modulo $p^n$). \kbd{mspadicinit} precomputes data used to lift symbols. If $\fl$ is given, it speeds up the computation by assuming that $v_p(a_p) = 0$ if $\fl = 0$ (fastest), and that $v_p(a_p) \geq \fl$ otherwise (faster as $\fl$ increases). \kbd{mspadicmoments} computes distributions \var{mu} attached to $\Phi$ allowing to compute $L_p$ to high accuracy. \li{initialize $\var{Mp}$ to lift symbols}{mspadicinit$(M,p,n,\{\fl\})$} \li{lift symbol $\phi$}{mstooms$(\var{Mp}, \phi)$} \li{eval overconvergent symbol $\Phi$ on path $p$}{msomseval$(\var{Mp},\Phi,p)$} \li{\var{mu} for $p$-adic $L$-functions} {mspadicmoments$(\var{Mp}, S, \{D=1\})$} \li{$L_p^{(r)}(\chi^s)$, $s = [s_1,s_2]$} {mspadicL$(\var{mu}, \{s = 0\}, \{r = 0\})$} \li{$\hat{L}_p(\tau^i)(x)$}{mspadicseries$(\var{mu}, \{i = 0\})$} \copyrightnotice \bye pari-2.11.2/doc/refcard-ell.tex0000644000175000017500000002253513326135265014642 0ustar billbill% Copyright (c) 2007-2016 Karim Belabas. % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License % Reference Card for PARI-GP, Algebraic Number Theory. % Author: % Karim Belabas % Universite de Bordeaux, 351 avenue de la Liberation, F-33405 Talence % email: Karim.Belabas@math.u-bordeaux.fr % % See refcard.tex for acknowledgements and thanks. \def\TITLE{Elliptic Curves} \input refmacro.tex An elliptic curve is initially given by 5-tuple $v=\kbd{[}a_1,a_2,a_3,a_4,a_6\kbd{]}$ attached to Weierstrass model or simply $\kbd{[}a_4,a_6\kbd{]}$. It must be converted to an \var{ell} struct. \hfil\break \li{Initialize \var{ell} struct over domain $D$}{E = ellinit$(v,\{D=1\})$} \beginindentedkeys \li{over $\QQ$}{$D = 1$} \li{over $\FF_p$}{$D = p$} \li{over $\FF_q$, $q = p^f$}{$D =\, $\kbd{ffgen([}$p,f$\kbd{])}} \li{over $\QQ_p$, precision $n$}{$D = O(p^n)$} \li{over $\CC$, current bitprecision}{$D = \kbd{1.0}$} \li{over number field $K$}{$D = \var{nf}$} \endindentedkeys \leavevmode Points are \kbd{[x,y]}, the origin is \kbd{[0]}. Struct members accessed as \kbd{E.}\var{member}:\hfill\break $\bullet$ All domains: \kbd{E.a1},\kbd{a2},\kbd{a3},\kbd{a4},\kbd{a6}, \kbd{b2},\kbd{b4},\kbd{b6},\kbd{b8}, \kbd{c4},\kbd{c6}, \kbd{disc}, \kbd{j}\hfill\break \li{$\bullet$ $E$ defined over $\RR$ or $\CC$}{} \beginindentedkeys \li{$x$-coords. of points of order $2$}{E.roots} \li{periods / quasi-periods}{E.omega{,\rm }E.eta} \li{volume of complex lattice}{E.area} \endindentedkeys \li{$\bullet$ $E$ defined over $\QQ_p$}{} \beginindentedkeys \li{residual characteristic}{E.p} \li{If $|j|_p>1$: Tate's $[u^2, u, q, [a,b], {\cal L}]$}{E.tate} \endindentedkeys \li{$\bullet$ $E$ defined over $\FF_q$}{} \beginindentedkeys \li{characteristic}{E.p} \li{$\#E(\FF_q)$/cyclic structure/generators}{E.no{\rm, }E.cyc{\rm, }E.gen} \endindentedkeys \li{$\bullet$ $E$ defined over $\QQ$}{} \beginindentedkeys \li{generators of $E(\QQ)$ (require \kbd{elldata})}{E.gen} \endindentedkeys \li{$[a_1,a_2,a_3,a_4,a_6]$ from $j$-invariant}{ellfromj$(j)$} \li{cubic/quartic/biquadratic to Weierstrass} {ellfromeqn$(\var{eq})$} \li{add points $P+Q$ / $P-Q$}{elladd$(E,P,Q)${\rm, }ellsub} \li{negate point}{ellneg$(E,P)$} \li{compute $n\cdot P$}{ellmul$(E,P,n)$} \li{check if $P$ is on $E$}{ellisoncurve$(E,P)$} \li{order of torsion point $P$}{ellorder$(E,P)$} \li{$y$-coordinates of point(s) for $x$}{ellordinate$(E,x)$} \li{$[\wp(z),\wp'(z)]\in E(\CC)$ attached to $z\in\CC$}{ellztopoint$(E,z)$} \li{$z\in\CC$ such that $P=[\wp(z),\wp'(z)]$}{ellpointtoz$(E,P)$} \li{$z\in \bar{\QQ}^*/q^{\ZZ}$ to $P\in E(\bar{\QQ_p})$}{ellztopoint$(E,z)$} \li{$P\in E(\bar{\QQ_p})$ to $z\in \bar{\QQ}^*/q^{\ZZ}$}{ellpointtoz$(E,P)$} \subsec{Change of Weierstrass models, using $v = [u,r,s,t]$} \li{change curve $E$ using $v$}{ellchangecurve$(E,v)$} \li{change point $P$ using $v$}{ellchangepoint$(P,v)$} \li{change point $P$ using inverse of $v$}{ellchangepointinv$(P,v)$} \subsec{Twists and isogenies} \li{quadratic twist}{elltwist$(E,d)$} \li{$n$-division polynomial $f_n(x)$}{elldivpol$(E,n,\{x\})$} \li{$[n]P =(\phi_n\psi_n\colon \omega_n\colon \psi_n^3)$; return $(\phi_n, \psi_n^2)$}{ellxn$(E,n,\{x\})$} \li{isogeny from $E$ to $E/G$}{ellisogeny$(E,G)$} \li{apply isogeny to $g$ (point or isogeny)}{ellisogenyapply$(f,g)$} \li{torsion subgroup with generators}{elltors$(E)$} \subsec{Formal group} \li{formal exponential, $n$ terms}{ellformalexp$(E,\{n\},\{x\})$} \li{formal logarithm, $n$ terms}{ellformallog$(E,\{n\},\{x\})$} \li{$log_E(-x(P)/y(P))\in\QQ_p$; $P\in E(\QQ_p)$}{ellpadiclog$(E,p,n,P)$} \li{$P$ in the formal group}{ellformalpoint$(E,\{n\},\{x\})$} \li{$[\omega/dt,x\omega/dt]$}{ellformaldifferential$(E,\{n\},\{x\})$} \li{$w = -1/y$ in parameter $-x/y$}{ellformalw$(E,\{n\},\{x\})$} \section{Curves over finite fields, Pairings} \li{random point on $E$}{random$(E)$} \li{$\#E(\FF_q)$}{ellcard$(E)$} \li{$\#E(\FF_q)$ with almost prime order}{ellsea$(E, \{\var{tors}\})$} \li{structure $\ZZ/d_1\ZZ\times \ZZ/d_2\ZZ$ of $E(\FF_q)$}{ellgroup$(E)$} \li{is $E$ supersingular?}{ellissupersingular$(E)$} \li{Weil pairing of $m$-torsion pts $P,Q$}{ellweilpairing$(E,P,Q, m)$} \li{Tate pairing of $P,Q$; $P$ $m$-torsion}{elltatepairing$(E,P,Q, m)$} \li{Discrete log, find $n$ s.t. $P=[n]Q$}{elllog$(E,P,Q,\{ord\})$} \section{Curves over $\QQ$} \subsec{Reduction, minimal model} \li{minimal model of $E/\QQ$} {ellminimalmodel$(E,\{$\&$v\})$} \li{quadratic twist of minimal conductor}{ellminimaltwist$(E)$} \li{$[k]P$ with good reduction}{ellnonsingularmultiple$(E,P)$} \li{$E$ supersingular at $p$?}{ellissupersingular$(E, p)$} \li{affine points of na\"\i ve height $\leq h$}{ellratpoints$(E, h)$} \subsec{Complex heights} \li{canonical height of $P$}{ellheight$(E,P)$} \li{canonical bilinear form taken at $P$, $Q$}{ellheight$(E,P,Q)$} \li{height regulator matrix for pts in $L$}{ellheightmatrix$(E,L)$} \subsec{$p$-adic heights} \li{cyclotomic $p$-adic height of $P\in E(\QQ)$}{ellpadicheight$(E,p,n,P)$} \li{\dots bilinear form at $P,Q\in E(\QQ)$}{ellpadicheight$(E,p,n,P,Q)$} \li{\dots matrix at vector for pts in $L$}{ellpadicheightmatrix$(E,p,n,L)$} \li{\dots regulator for canonical height}{ellpadicregulator$(E,p,n, Q)$} \li{Frobenius on $\QQ_p \otimes H^1_{dR}(E/\QQ)$}{ellpadicfrobenius$(E,p,n)$} \li{slope of unit eigenvector of Frobenius}{ellpadics2$(E,p,n)$} \subsec{Isogenous curves} \li{matrix of isogeny degrees for $\QQ$-isog. curves}{ellisomat$(E)$} \li{tree of prime degree isogenies}{ellisotree$(E)$} \li{a modular equation of prime degree $N$}{ellmodulareqn$(N)$} \subsec{$L$-function} \li{$p$-th coeff $a_p$ of $L$-function, $p$ prime}{ellap$(E,p)$} \li{$k$-th coeff $a_k$ of $L$-function}{ellak$(E,k)$} \li{$L(E,s)$ (using less memory than \kbd{lfun})}{elllseries$(E,s)$} \li{$L^{(r)}(E,1)$ (using less memory than \kbd{lfun})}{ellL1$(E,r)$} % \li{a Heegner point on $E$ of rank $1$}{ellheegner$(E)$} \li{order of vanishing at $1$}{ellanalyticrank$(E,\{\var{eps}\})$} \li{root number for $L(E,.)$ at $p$}{ellrootno$(E,\{p\})$} \li{modular parametrization of $E$}{elltaniyama$(E)$} \li{degree of modular parametrization}{ellmoddegree$(E)$} \li{compare with $H^1(X_0(N),\ZZ)$ (for $E'\to E$)} {ellweilcurve$(E)$} \li{$p$-adic $L$ function $L_p^{(r)}(E,d,\chi^s)$} {ellpadicL$(E,p,n,\{s\},\{r\},\{d\})$} \li{BSD conjecture for $L_p^{(r)}(E_D,\chi^0)$} {ellpadicbsd$(E,p,n,\{D=1\})$} \subsec{Elldata package, Cremona's database:} \li{db code \kbd{"11a1"} $\leftrightarrow$ $[\var{conductor}, \var{class}, \var{index}]$}{ellconvertname$(s)$} \li{generators of Mordell-Weil group}{ellgenerators$(E)$} \li{look up $E$ in database}{ellidentify$(E)$} \li{all curves matching criterion}{ellsearch$(N)$} \li{loop over curves with cond.~from $a$ to $b$}{forell$(E, a,b,\seq)$} \section{Curves over number field $K$} \li{coeff $a_{\goth{p}}$ of $L$-function}{ellap$(E,\goth{p})$} \li{Kodaira type of $\goth{p}$-fiber of $E$}{elllocalred$(E,\goth{p})$} \li{integral model of $E/K$} {ellintegralmodel$(E,\{$\&$v\})$} \li{minimal model of $E/K$} {ellminimalmodel$(E,\{$\&$v\})$} \li{minimal discriminant of $E/K$}{ellminimaldisc$(E)$} \li{cond, min mod, Tamagawa num \kbd{[}$N,v,c$\kbd{]}}{ellglobalred$(E)$} \li{global Tamagawa number}{elltamagawa$(E)$} \li{$P\in E(K)$ $n$-divisible? $[n]Q=P$}{ellisdivisible$(E,P,n,\{\&Q\})$} \subsec{$L$-function} A domain $D = [c,w,h]$ in initialization mean we restrict $s\in \CC$ to domain $|\Re(s)-c| < w$, $|\Im(s)| < h$; $D = [w,h]$ encodes $[1/2,w,h]$ and $[h]$ encodes $D = [1/2,0,h]$ (critical line up to height $h$).\hfil\break \li{vector of first $n$ $a_k$'s in $L$-function}{ellan$(E,n)$} \li{init $L^{(k)}(E,s)$ for $k \leq n$}{L = lfuninit$(E, D, \{n = 0\})$} \li{compute $L(E,s)$ ($n$-th derivative)}{lfun$(L, s, \{n=0\})$} \li{$L(E,1,r)/(r! \cdot R\cdot \#Sha)$ assuming BSD}{ellbsd$(E)$} \section{Other curves of small genus} A hyperelliptic curve is given by a pair $[P,Q]$ ($y^2+Qy = P$ with $Q^2+4P$ squarefree) or a single squarefree polynomial $P$ ($y^2 = P$).\hfil\break \li{reduction of $y^2+Qy = P$ (genus $2$)}{genus2red$([P,Q],\{p\})$} \li{affine rational points of height $\leq h$}{hyperellratpoints$([P,Q], h)$} \li{find a rational point on a conic, $^t x G x = 0$}{qfsolve$(G)$} \li{quadratic Hilbert symbol (at $p$)}{hilbert$(x,y,\{p\})$} \li{all solutions in $\QQ^3$ of ternary form}{qfparam$(G,x)$} \li{$P,Q\in\FF_q[X]$; char. poly. of Frobenius}{hyperellcharpoly$([P,Q])$} \li{matrix of Frobenius on $\QQ_p\otimes H^1_{dR}$}{hyperellpadicfrobenius} \medskip \section{Elliptic \& Modular Functions} $w = [\omega_1,\omega_2]$ or \var{ell} struct (\kbd{E.omega}), $\tau=\omega_1/\omega_2$.\hfill\break % \li{arithmetic-geometric mean}{agm$(x,y)$} \li{elliptic $j$-function $1/q+744+\cdots$}{ellj$(x)$} \li{Weierstrass $\sigma$/$\wp$/$\zeta$ function} {ellsigma$(w,z)${\rm, }ellwp{\rm, }ellzeta} \li{periods/quasi-periods}{ellperiods$(E,\{\fl\})${\rm, }elleta$(w)$} \li{$(2i\pi/\omega_2)^k E_k(\tau)$}{elleisnum$(w,k,\{\fl\})$} \li{modified Dedekind $\eta$ func. $\prod(1-q^n)$}{eta$(x,\{\fl\})$} \li{Dedekind sum $s(h,k)$}{sumdedekind$(h,k)$} \li{Jacobi sine theta function}{theta$(q,z)$} \li{k-th derivative at z=0 of \kbd{theta}$(q,z)$}{thetanullk$(q,k)$} \li{Weber's $f$ functions}{weber$(x,\{\fl\})$} \li{modular pol.~of level $N$}{polmodular$(N,\{\var{inv = j}\})$} \li{Hilbert class polynomial for $\QQ(\sqrt{D})$} {polclass$(D,\{\var{inv = j}\})$} % \vfill \copyrightnotice \bye pari-2.11.2/doc/usersch8.tex0000644000175000017500000003565013326135265014230 0ustar billbill% Copyright (c) 2015 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \chapter{$L$-functions} \section{Accessors} \fun{long}{is_linit}{GEN data} \fun{GEN}{ldata_get_an}{GEN ldata} \fun{GEN}{ldata_get_dual}{GEN ldata} \fun{long}{ldata_isreal}{GEN ldata} \fun{GEN}{ldata_get_gammavec}{GEN ldata} \fun{long}{ldata_get_degree}{GEN ldata} \fun{long}{ldata_get_k}{GEN ldata} \fun{GEN}{ldata_get_conductor}{GEN ldata} \fun{GEN}{ldata_get_rootno}{GEN ldata} \fun{GEN}{ldata_get_residue}{GEN ldata} \fun{GEN}{ldata_vecan}{GEN ldata, long L, long prec} \fun{long}{ldata_get_type}{GEN ldata} \fun{long}{linit_get_type}{GEN linit} \fun{GEN}{linit_get_ldata}{GEN linit} \fun{GEN}{linit_get_tech}{GEN linit} \fun{GEN}{lfun_get_domain}{GEN tech} \fun{GEN}{lfun_get_dom}{GEN tech} \fun{long}{lfun_get_bitprec}{GEN tech} \fun{GEN}{lfun_get_factgammavec}{GEN tech} \fun{GEN}{lfun_get_step}{GEN tech} \fun{GEN}{lfun_get_pol}{GEN tech} \fun{GEN}{lfun_get_Residue}{GEN tech} \fun{GEN}{lfun_get_k2}{GEN tech} \fun{GEN}{lfun_get_w2}{GEN tech} \fun{GEN}{lfun_get_expot}{GEN tech} \fun{long}{lfun_get_bitprec}{GEN tech} \fun{GEN}{lfunprod_get_fact}{GEN tech} \fun{GEN}{theta_get_an}{GEN tdata} \fun{GEN}{theta_get_K}{GEN tdata} \fun{GEN}{theta_get_R}{GEN tdata} \fun{long}{theta_get_bitprec}{GEN tdata} \fun{long}{theta_get_m}{GEN tdata} \fun{GEN}{theta_get_tdom}{GEN tdata} \fun{GEN}{theta_get_sqrtN}{GEN tdata} \section{Conversions and constructors} \fun{GEN}{lfunmisc_to_ldata}{GEN ldata} \fun{GEN}{lfunmisc_to_ldata_shallow}{GEN ldata} \fun{GEN}{lfunrtopoles}{GEN r} \fun{int}{sdomain_isincl}{GEN dom, GEN dom0} \section{Variants of GP functions} \fun{GEN}{lfun}{GEN ldata, GEN s, long bitprec} \fun{GEN}{lfuninit}{GEN ldata, GEN dom, long der, long bitprec} \fun{GEN}{lfuninit_make}{long t, GEN ldata, GEN molin, GEN domain} \fun{GEN}{lfunlambda}{GEN ldata, GEN s, long bitprec} \fun{long}{lfunthetacost}{GEN ldata, GEN tdom, long m, long bitprec}: \kbd{lfunthetacost0} when the first argument is known to be an \kbd{Ldata}. \fun{GEN}{lfunthetacheckinit}{GEN data, GEN tinf, long m, long bitprec} \fun{GEN}{lfunrootno}{GEN data, long bitprec} \fun{GEN}{lfunzetakinit}{GEN pol, GEN dom, long der, long flag, long bitprec} \fun{GEN}{lfunellmfpeters}{GEN E, long bitprec} \fun{GEN}{ellanalyticrank}{GEN E, long prec} DEPRECATED. \fun{GEN}{ellL1}{GEN E, long prec} DEPRECATED. \section{Inverse Mellin transforms of Gamma products} \fun{GEN}{gammamellininv}{GEN Vga, GEN s, long m, long bitprec} \fun{GEN}{gammamellininvinit}{GEN Vga, long m, long bitprec} \fun{GEN}{gammamellininvrt}{GEN K, GEN s, long bitprec} \fun{double}{dbllambertW0}{double a} \fun{double}{dbllambertW_1}{double a} \fun{double}{dbllemma526}{double a, double b, double c, long B} \fun{double}{dblcoro526}{double a, double c, long B} \newpage \chapter{Modular symbols} \fun{void}{checkms}{GEN W} raise an exception if $W$ is not an \var{ms} structure from \kbd{msinit}. \fun{void}{checkmspadic}{GEN W} raise an exception if $W$ is not an \var{mspadic} structure from \kbd{mspadicinit}. Variants of \kbd{mfnumcusps} : \fun{ulong}{mfnumcuspsu}{ulong n} \fun{GEN}{mfnumcusps_fact}{GEN fa} where \kbd{fa} is \kbd{factor}$(n)$. \fun{ulong}{mfnumcuspsu_fact}{GEN fa} where \kbd{fa} is \kbd{factoru}$(n)$. \chapter{Modular forms} \section{Implementation of public data structures} \fun{void}{checkMF}{GEN mf} raise an exception if the argument is not a modular form space. \fun{GEN}{checkMF_i}{GEN mf} return the underlying modular form space if \kbd{mf} is either directly a modular form space from \kbd{mfinit} or a symbol from \kbd{mfsymbol}. Return \kbd{NULL} otherwise. \fun{int}{checkmf_i}{GEN mf} return $1$ if the argument is a modular form and $0$ otherwise. \subsec{Accessors for modular form spaces} Shallow functions; assume that their argument is a modular form space is created by \kbd{mfinit} and checked using \kbd{checkMF}. \fun{GEN}{MF_get_gN}{GEN mf} return the level $N$ as a \typ{INT}. \fun{long}{MF_get_N}{GEN mf} return the level $N$ as a \kbd{long}. \fun{GEN}{MF_get_gk}{GEN mf} return the level $k$ as a \typ{INT}. \fun{long}{MF_get_k}{GEN mf} return the level $k$ as a \kbd{long}. \fun{long}{MF_get_r}{GEN mf} assuming the level is a half-integer, return the integer $r = k - (1/2)$. \fun{GEN}{MF_get_CHI}{GEN mf} return the nebentypus $\chi$, which is a special form of character structure attached to Dirichlet characters (see next section). Its values are given as algebraic numbers: either $\pm1$ or \typ{POLMOD} in $t$. \fun{long}{MF_get_space}{GEN mf} returns the space type, corresponding to \kbd{mfinit}'s \kbd{space} flag. The current list is \bprog mf_NEW, mf_CUSP, mf_OLD, mf_EISEN, mf_FULL @eprog \fun{GEN}{MF_get_basis}{GEN mf} return the $\Q$-basis of the space, concatenation of \tet{MF_get_E} and \tet{MF_get_S}, in this order; the forms have coefficients in $\Q(\chi)$. Low-level version of \kbd{mfbasis}. \fun{long}{MF_get_dim}{GEN mf} returns the dimension $d$ of the space. It is the cardinality of \tet{MF_get_basis}. \fun{GEN}{MF_get_E}{GEN mf} returns a $\Q$-basis for the subspace spanned by Eisenstein series in the space; the forms have coefficients in $\Q(\chi)$. \fun{GEN}{MF_get_S}{GEN mf} returns a $\Q$-basis for the cuspidal subspace in the space; the forms have coefficients in $\Q(\chi)$. \fun{GEN}{MF_get_fields}{GEN mf} returns the vector of polynomials defining each Galois orbit of newforms over $\Q(\chi)$. Uses memoization: a first call splits the space and may be costly; subsequent calls return the cached result. \fun{GEN}{MF_get_newforms}{GEN mf} returns a vector \kbd{vF} containing the coordinates of the eigenforms on \tet{MF_get_basis} (\kbd{mftobasis} form). Low-level version of \kbd{mfeigenbasis}, whose elements are recovered as \kbd{mflinear(mf, gel(vF,i))}. Uses memoization, sharing the same data as \kbd{MF\_get\_fields}. Note that it is much more efficient to use \kbd{mfcoefs(mf,)} then multiply by this vector than to compute the coefficients of eigenforms from \kbd{mfeigenbasis} individually. The following accessors are technical, \fun{GEN}{MF_get_M}{GEN mf} the $(1+m) \times d$ matrix whose $j$-th column contain the coefficients of the $j$-th entry in \tet{MF_get_basis}, $m$ is the optimal ``Sturm bound'' for the space: the maximum of the $v_\infty(f)$ over non-zero forms. It has entries in $\Q(\chi)$. \fun{GEN}{MF_get_Mindex}{GEN mf} is a \typ{VECSMALL} containing $d$ row indices, the corresponding rows of $M$ form an invertible matrix $M_0$. \fun{GEN}{MF_get_Minv}{GEN mf} the inverse of $M_0$ in a form suitable for fast multiplication. \fun{GEN}{MFcusp_get_vMjd}{GEN mf} valid only for a full \emph{cuspidal} space. Then the functions in \tet{MF_get_S} are of the form $B_d T_j Tr^{new}_M$. This returns the vector of triples (\typ{VECSMALL}) $[M,j,d]$, in the same order. \fun{GEN}{MFnew_get_vj}{GEN mf} valid only for a \emph{new} space. Then the functions in \tet{MF_get_S} are of the form $T_j Tr^{new}_N$. This returns a \typ{VECSMALL} of the Hecke indices $j$, in the same order. \subsec{Accessors for individual modular forms} \fun{GEN}{mf_get_gN}{GEN F} return the level of $F$, which may be a multiple of the conductor, as a \typ{INT} \fun{long}{mf_get_N}{GEN F} return the level as a \kbd{long}. \fun{GEN}{mf_get_gk}{GEN F} return the weight of $F$ as a \typ{INT} or a \typ{FRAC} with denominator $2$ (half-integral weight). \fun{long}{mf_get_k}{GEN F} return the weight as a \kbd{long}; if the weight is not integral, this raises an exception. \fun{long}{mf_get_r}{GEN F} assuming $F$ is a modular form of half-integral weight $k = (2r+1)/2$, return $r = k - (1/2)$. \fun{GEN}{mf_get_CHI}{GEN F} return the nebentypus, which is a special form of character structure attached to Dirichlet characters (see next section). Its values are given as algebraic numbers: either $\pm1$ or \typ{POLMOD} in $t$. \fun{GEN}{mf_get_field}{GEN F} return the polynomial (in variable $y$) defining $\Q(f)$ over $\Q(\chi)$. \fun{GEN}{mf_get_NK}{GEN F} return the tag attached to $F$: a vector containing \kbd{gN}, \kbd{gk}, \kbd{CHI}, \kbd{field}. Never use its component directly, use individual accessors as above. \fun{long}{mf_get_type}{GEN F} returns a symbolic name for the constructur used to create the form, e.g. \kbd{t\_MF\_EISEN} for a general Eisenstein series. A form has a recursive structure represented by a tree: its definition may involve other forms, e.g. the tree attached to $T_n f$ contains $f$ as a subtree. Such trees have \emph{leaves}, forms which do not contain a strict subtree, e.g. \kbd{t\_MF\_DELTA} is a leaf, attached to Ramanujan's $\Delta$. Here is the current list of types; since the names are liable to change, they are not documented at this point. Use \kbd{mfdescribe} to visualize their mathematical structure. \bprog /*leaves*/ t_MF_CONST, t_MF_EISEN, t_MF_Ek, t_MF_DELTA, t_MF_ETAQUO, t_MF_ELL, t_MF_DIHEDRAL, t_MF_THETA, t_MF_TRACE, t_MF_NEWTRACE, /*recursive*/ t_MF_MUL, t_MF_POW, t_MF_DIV, t_MF_BRACKET, t_MF_LINEAR, t_MF_LINEAR_BHN, t_MF_SHIFT, t_MF_DERIV, t_MF_DERIVE2, t_MF_TWIST, t_MF_HECKE, t_MF_BD, @eprog \subsec{Nebentypus} The characters stored in modular forms and modular form spaces have a special structure. One can recover the parameters of an ordinary Dirichlet character by \kbd{G = gel(CHI,1)} (the underlying \kbd{znstar}) and \kbd{chi = gel(CHI,2)} (the underlying character in \kbd{znconreylog} form). \fun{long}{mfcharmodulus}{GEN CHI} the modulus of $\chi$. \fun{long}{mfcharorder}{GEN CHI} the order of $\chi$. \fun{GEN}{mfcharpol}{GEN CHI} the cyclotomic polynomial $\Phi_n$ defining $\Q(\chi)$, always normalized so that $n$ is not $2$ mod $4$. \subsec{Miscellaneous functions} \fun{long}{mfnewdim}{long N, long k, GEN CHI} dimension of the new part of the cuspidal space. \fun{long}{mfcuspdim}{long N, long k, GEN CHI} dimension of the cuspidal space. \fun{long}{mfolddim}{long N, long k, GEN CHI} dimension of the old part of the cuspidal space. \fun{long}{mfeisensteindim}{long N, long k, GEN CHI} dimension of the Eisenstein subspace. \fun{long}{mffulldim}{long N, long k, GEN CHI} dimension of the full space. \fun{GEN}{mfeisensteinspaceinit}{GEN NK} \fun{GEN}{mfdiv_val}{GEN F, GEN G, long vG} \fun{GEN}{mfembed}{GEN E, GEN v} \fun{GEN}{mfmatembed}{GEN E, GEN v} \fun{GEN}{mfvecembed}{GEN E, GEN v} \fun{long}{mfsturmNgk}{long N, GEN k} \fun{long}{mfsturmNk}{long N, long k} \fun{long}{mfsturm_mf}{GEN mf} \fun{long}{mfiscuspidal}{GEN mf, GEN F} \fun{GEN}{mftobasisES}{GEN mf, GEN F} \fun{GEN}{mftocol}{GEN F, long lim, long d} \fun{GEN}{mfvectomat}{GEN vF, long lim, long d} \newpage \chapter{Plots} A \tet{PARI_plot} canvas is a record of dimensions, with the following fields: \bprog long width; /* window width */ long height; /* window height */ long hunit; /* length of horizontal 'ticks' */ long vunit; /* length of vertical 'ticks' */ long fwidth; /* font width */ long fheight;/* font height */ void (*draw)(PARI_plot *T, GEN w, GEN x, GEN y); @eprog\noindent The \kbd{draw} method performs the actual drawing of a \typ{VECSMALL} w (rectwindow indices); $x$ and $y$ are \typ{VECSMALL}s of the same length and rectwindow $w[i]$ is drawn with its upper left corner at offset $(x[i],y[i])$. No plot engine is available in \kbd{libpari} by default, since thie would introduce a dependency on extra graphical libraries. See the files \kbd{src/graph/plot*} for basic implementations of various plot engines: \kbd{plotsvg} is particularly simple (\kbd{draw} is a 1-liner). \fun{void}{pari_set_plot_engine}{void (*T)(PARI_plot *)} installs the graphical engine $T$ and initializes the graphical subsystem. No routine in this chapter will work without this initialization. \fun{void}{pari_kill_plot_engine}{void} closes the graphical subsystem and frees the ressources it occupies. \subsec{Highlevel function} Those functions plot $f(E,x)$ for $x\in [a,b]$, using $n$ regularly spaced points (by default). \fun{GEN}{ploth}{void *E, GEN(*f)(void*,GEN), GEN a, GEN b, long flags,long n, long prec} draw physically. \fun{GEN}{plotrecth}{void *E, GEN(*f)(void*,GEN), long w, GEN a,GEN b, ulong flags,long n, long prec} draw in rectwindow $w$. \subsec{Function } \fun{void}{plotbox}{long ne, GEN gx2, GEN gy2} \fun{void}{plotclip}{long rect} \fun{void}{plotcolor}{long ne, long color} \fun{void}{plotcopy}{long source, long dest, GEN xoff, GEN yoff, long flag} \fun{GEN}{plotcursor}{long ne} \fun{void}{plotdraw}{GEN list, long flag} \fun{GEN}{plothraw}{GEN listx, GEN listy, long flag} \fun{GEN}{plothsizes}{long flag} \fun{void}{plotinit}{long ne, GEN x, GEN y, long flag} \fun{void}{plotkill}{long ne} \fun{void}{plotline}{long ne, GEN x2, GEN y2} \fun{void}{plotlines}{long ne, GEN listx, GEN listy, long flag} \fun{void}{plotlinetype}{long ne, long t} \fun{void}{plotmove}{long ne, GEN x, GEN y} \fun{void}{plotpoints}{long ne, GEN listx, GEN listy} \fun{void}{plotpointsize}{long ne, GEN size} \fun{void}{plotpointtype}{long ne, long t} \fun{void}{plotrbox}{long ne, GEN x2, GEN y2} \fun{GEN}{plotrecthraw}{long ne, GEN data, long flags} \fun{void}{plotrline}{long ne, GEN x2, GEN y2} \fun{void}{plotrmove}{long ne, GEN x, GEN y} \fun{void}{plotrpoint}{long ne, GEN x, GEN y} \fun{void}{plotscale}{long ne, GEN x1, GEN x2, GEN y1, GEN y2} \fun{void}{plotstring}{long ne, char *x, long dir} \subsec{Obsolete functions} These draw directly to a PostScript file specified by a global variable and should no longer be used. Use \kbd{plotexport} and friends instead. \fun{void}{psdraw}{GEN list, long flag} \fun{GEN}{psplothraw}{GEN listx, GEN listy, long flag} \fun{GEN}{psploth}{void *E, GEN(*f)(void*,GEN), GEN a, GEN b, long flags, long n, long prec} draw to a PostScript file. \subsec{Dump rectwindows to a PostScript or SVG file} $w,x,y$ are three \typ{VECSMALL}s indicating the rectwindows to dump, at which offsets. If $T$ is \kbd{NULL}, rescale with respect to the installed graphic engine dimensions; else with respect to $T$. \fun{char*}{rect2ps}{GEN w, GEN x, GEN y, PARI_plot *T} \fun{char*}{rect2ps_i}{GEN w, GEN x, GEN y, PARI_plot *T, int plotps} if \kbd{plotps} is $0$, as above; else private version used to implement the \kbd{plotps} graphic engine (do not rescale, rotate to portrait orientation). \fun{char*}{rect2svg}{GEN w, GEN x, GEN y, PARI_plot *T} \subsec{Technical functions exported for convenience} \fun{void}{pari_plot_by_file}{const char *env, const char *suf, const char *img} backend used by the \kbd{plotps} and \kbd{plotsvg} graphic engines. \fun{void}{colorname_to_rgb}{const char *s, int *r, int *g, int *b} convert an \kbd{X11} colorname to RGB values. \fun{void}{color_to_rgb}{GEN c, int *r, int *g, int *b} convert a pari color (\typ{VECSMALL} RGB triple or \typ{STR} name) to RGB values. \fun{void}{long_to_rgb}{long c, int *r, int *g, int *b} split a standard hexadecimal color value \kbd{0xfdf5e6} to its rgb components (\kbd{0xfd}, \kbd{0xf5}, \kbd{0xe6}). \newpage pari-2.11.2/doc/usersch6.tex0000644000175000017500000040360713447371554014236 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \newpage \chapter{Algebraic Number Theory} \section{General Number Fields} \subsec{Number field types} None of the following routines thoroughly check their input: they distinguish between \emph{bona fide} structures as output by PARI routines, but designing perverse data will easily fool them. To give an example, a square matrix will be interpreted as an ideal even though the $\Z$-module generated by its columns may not be an $\Z_K$-module (i.e. the expensive \kbd{nfisideal} routine will \emph{not} be called). \fun{long}{nftyp}{GEN x}. Returns the type of number field structure stored in \kbd{x}, \tet{typ_NF}, \tet{typ_BNF}, or \tet{typ_BNR}. Other answers are possible, meaning \kbd{x} is not a number field structure. \fun{GEN}{get_nf}{GEN x, long *t}. Extract an \var{nf} structure from \kbd{x} if possible and return it, otherwise return \kbd{NULL}. Sets \kbd{t} to the \kbd{nftyp} of \kbd{x} in any case. \fun{GEN}{get_bnf}{GEN x, long *t}. Extract a \kbd{bnf} structure from \kbd{x} if possible and return it, otherwise return \kbd{NULL}. Sets \kbd{t} to the \kbd{nftyp} of \kbd{x} in any case. \fun{GEN}{get_nfpol}{GEN x, GEN *nf} try to extract an \var{nf} structure from \kbd{x}, and sets \kbd{*nf} to \kbd{NULL} (failure) or to the \var{nf}. Returns the (monic, integral) polynomial defining the field. \fun{GEN}{get_bnfpol}{GEN x, GEN *bnf, GEN *nf} try to extract a \var{bnf} and an \var{nf} structure from \kbd{x}, and sets \kbd{*bnf} and \kbd{*nf} to \kbd{NULL} (failure) or to the corresponding structure. Returns the (monic, integral) polynomial defining the field. \fun{GEN}{checknf}{GEN x} if an \var{nf} structure can be extracted from \kbd{x}, return it; otherwise raise an exception. The more general \kbd{get\_nf} is often more flexible. \fun{GEN}{checkbnf}{GEN x} if an \var{bnf} structure can be extracted from \kbd{x}, return it; otherwise raise an exception. The more general \kbd{get\_bnf} is often more flexible. \fun{GEN}{checkbnf_i}{GEN bnf} same as \kbd{checkbnf} but return \kbd{NULL} instead of raising an exception. \fun{void}{checkbnr}{GEN bnr} Raise an exception if the argument is not a \var{bnr} structure. \fun{GEN}{checknf_i}{GEN nf} same as \kbd{checknf} but return \kbd{NULL} instead of raising an exception. \fun{void}{checkbnrgen}{GEN bnr} Raise an exception if the argument is not a \var{bnr} structure, complete with explicit generators for the ray class group. This is normally useless and \tet{checkbnr} should be instead, unless you are absolutely certain that the generators will be needed at a later point, and you are about to embark in a costly intermediate computation. PARI functions do check that generators are present in \var{bnr} before accessing them: they will raise an error themselves; many functions that may require them, e.g. \kbd{bnrconductor}, often do not actually need them. \fun{void}{checkrnf}{GEN rnf} Raise an exception if the argument is not an \var{rnf} structure. \fun{int}{checkrnf_i}{GEN rnf} same as \kbd{checkrnf} but return $0$ on failure and $1$ on success. \fun{void}{checkbid}{GEN bid} Raise an exception if the argument is not a \var{bid} structure. \fun{GEN}{checkbid_i}{GEN bid} same as \kbd{checkbid} but return \kbd{NULL} instead of raising an exception and return \kbd{bid} on success. \fun{GEN}{checkznstar_i}{GEN G} return $G$ if it is a \var{znstar}; else return \kbd{NULL} on failure. \fun{GEN}{checkgal}{GEN x} if a \var{galoisinit} structure can be extracted from \kbd{x}, return it; otherwise raise an exception. \fun{void}{checksqmat}{GEN x, long N} check whether \kbd{x} is a square matrix of dimension \kbd{N}. May be used to check for ideals if \kbd{N} is the field degree. \fun{void}{checkprid}{GEN pr} Raise an exception if the argument is not a prime ideal structure. \fun{int}{checkprid_i}{GEN pr} same as \kbd{checkprid} but return $0$ instead of raising an exception and return $1$ on success. \fun{int}{is_nf_factor}{GEN F} return $1$ if $F$ is an ideal factorization and $0$ otherwise. \fun{int}{is_nf_extfactor}{GEN F} return $1$ if $F$ is an extended ideal factorization (allowing $0$ or negative exponents) and $0$ otherwise. \fun{GEN}{get_prid}{GEN ideal} return the underlying prime ideal structure if one can be extracted from \kbd{ideal} (ideal or extended ideal), and return \kbd{NULL} otherwise. \fun{void}{checkabgrp}{GEN v} Raise an exception if the argument is not an abelian group structure, i.e. a \typ{VEC} with either $2$ or $3$ entries: $[N,\var{cyc}]$ or $[N,\var{cyc}, \var{gen}]$. \fun{GEN}{abgrp_get_no}{GEN x} extract the cardinality $N$ from an abelian group structure. \fun{GEN}{abgrp_get_cyc}{GEN x} extract the elementary divisors \var{cyc} from an abelian group structure. \fun{GEN}{abgrp_get_gen}{GEN x} extract the generators \var{gen} from an abelian group structure. \fun{void}{checkmodpr}{GEN modpr} Raise an exception if the argument is not a \kbd{modpr} structure (from \kbd{nfmodprinit}). \fun{GEN}{get_modpr}{GEN x} return $x$ if it is a \kbd{modpr} structure and \kbd{NULL} otherwise. \fun{GEN}{checknfelt_mod}{GEN nf, GEN x, const char *s} given an \var{nf} structure \kbd{nf} and a \typ{POLMOD} \kbd{x}, return the attached polynomial representative (shallow) if \kbd{x} and \kbd{nf} are compatible. Raise an exception otherwise. Set $s$ to the name of the caller for a meaningful error message. \fun{void}{check_ZKmodule}{GEN x, const char *s} check whether $x$ looks like $\Z_K$-module (a pair $[A,I]$, where $A$ is a matrix and $I$ is a list of ideals; $A$ has as many columns as $I$ has elements. Otherwise raises an exception. Set $s$ to the name of the caller for a meaningful error message. \fun{long}{idealtyp}{GEN *ideal, GEN *fa} The input is \kbd{ideal}, a pointer to an ideal (or extended ideal), which is usually modified, \kbd{fa} being set as a side-effect. Returns the type of the underlying ideal among \tet{id_PRINCIPAL} (a number field element), \tet{id_PRIME} (a prime ideal) \tet{id_MAT} (an ideal in matrix form). If \kbd{ideal} pointed to an ideal, set \kbd{fa} to \kbd{NULL}, and possibly simplify \kbd{ideal} (for instance the zero ideal is replaced by \kbd{gen\_0}). If it pointed to an extended ideal, replace \kbd{ideal} by the underlying ideal and set \kbd{fa} to the factorization matrix component. \subsec{Extracting info from a \kbd{nf} structure} These functions expect a true \var{nf} argument attached to a number field $K = \Q[x]/(T)$, e.g.~a \var{bnf} will not work. Let $n = [K:\Q]$ be the field degree. \fun{GEN}{nf_get_pol}{GEN nf} returns the polynomial $T$ (monic, in $\Z[x]$). \fun{long}{nf_get_varn}{GEN nf} returns the variable number of the number field defining polynomial. \fun{long}{nf_get_r1}{GEN nf} returns the number of real places $r_1$. \fun{long}{nf_get_r2}{GEN nf} returns the number of complex places $r_2$. \fun{void}{nf_get_sign}{GEN nf, long *r1, long *r2} sets $r_1$ and $r_2$ to the number of real and complex places respectively. Note that $r_1+2r_2$ is the field degree. \fun{long}{nf_get_degree}{GEN nf} returns the number field degree, $n = r_1 + 2r_2$. \fun{GEN}{nf_get_disc}{GEN nf} returns the field discriminant. \fun{GEN}{nf_get_index}{GEN nf} returns the index of $T$, i.e. the index of the order generated by the power basis $(1,x,\ldots,x^{n-1})$ in the maximal order of $K$. \fun{GEN}{nf_get_zk}{GEN nf} returns a basis $(w_1,w_2,\ldots,w_n)$ for the maximal order of $K$. Those are polynomials in $\Q[x]$ of degree $ 0$, return $a$ in the image of $A$ such that $1-a$ is in the image of $B$. (By abuse of notation we denote $1$ the column vector $[1,0,\dots,0]$.) If such an $a$ does not exist, return \kbd{NULL}. This is the function underlying \tet{idealaddtoone}. \fun{GEN}{idealaddmultoone}{GEN nf, GEN v} given a list of $n$ (globally) coprime integer ideals $(v[i])$ returns an $n$-dimensional vector $a$ such that $a[i]\in v[i]$ and $\sum a[i] = 1$. If $[K:\Q] = N$, this routine computes the HNF reduction (with $Gl_{nN}(\Z)$ base change) of an $N\times nN$ matrix; so it is well worth pruning "useless" ideals from the list (as long as the ideals remain globally coprime). \fun{GEN}{idealapprfact}{GEN nf, GEN fx} as \tet{idealappr}, except that $x$ \emph{must} be given in factored form. (This is unchecked.) \fun{GEN}{idealcoprime}{GEN nf, GEN x, GEN y}. Given 2 integral ideals $x$ and $y$, returns an algebraic number $\alpha$ such that $\alpha x$ is an integral ideal coprime to $y$. \fun{GEN}{idealcoprimefact}{GEN nf, GEN x, GEN fy} same as \tet{idealcoprime}, except that $y$ is given in factored form, as from \tet{idealfactor}. \fun{GEN}{idealchinese}{GEN nf, GEN x, GEN y} \fun{GEN}{idealchineseinit}{GEN nf, GEN x} \subsec{Maximal ideals} The PARI structure attached to maximal ideals is a \tev{prid} (for \emph{pr}ime \emph{id}eal), usually produced by \tet{idealprimedec} and \tet{idealfactor}. In this section, we describe the format; other sections will deal with their daily use. A \var{prid} attached to a maximal ideal $\goth{p}$ stores the following data: the underlying rational prime $p$, the ramification degree $e\geq 1$, the residue field degree $f\geq 1$, a $p$-uniformizer $\pi$ with valuation $1$ at $\goth{p}$ and valuation $0$ at all other primes dividing $p$ and a rescaled ``anti-uniformizer'' $\tau$ used to compute valuations. This $\tau$ is an algebraic integer such that $\tau/p$ has valuation $-1$ at $\goth{p}$ and is integral at all other primes; in particular, the valuation of $x\in\Z_K$ is positive if and only if the algebraic integer $x\tau$ is divisible by $p$ (easy to check for elements in \typ{COL} form). \fun{GEN}{pr_get_p}{GEN pr} returns $p$. Shallow function. \fun{GEN}{pr_get_gen}{GEN pr} returns $\pi$. Shallow function. \fun{long}{pr_get_e}{GEN pr} returns $e$. \fun{long}{pr_get_f}{GEN pr} returns $f$. \fun{GEN}{pr_get_tau}{GEN pr} returns $\tet{zk_scalar_or_multable}(\var{nf}, \tau)$, which is the \typ{INT}~$1$ iff $p$ is inert, and a \kbd{ZM} otherwise. Shallow function. \fun{int}{pr_is_inert}{GEN pr} returns $1$ if $p$ is inert, $0$ otherwise. \fun{GEN}{pr_norm}{GEN pr} returns the norm $p^f$ of the maximal ideal. \fun{ulong}{upr_norm}{GEN pr} returns the norm $p^f$ of the maximal ideal, as an \kbd{ulong}. Assume that the result does not overflow. \fun{GEN}{pr_hnf}{GEN pr} return the HNF of $\goth{p}$. \fun{GEN}{pr_inv}{GEN pr} return the fractional ideal $\goth{p}^{-1}$, in HNF. \fun{GEN}{pr_inv_p}{GEN pr} return the integral ideal $p \goth{p}^{-1}$, in HNF. \fun{GEN}{idealprimedec}{GEN nf, GEN p} list of maximal ideals dividing the prime $p$. \fun{GEN}{idealprimedec_limit_f}{GEN nf, GEN p, long f} as \tet{idealprimedec}, limiting the list to primes of residual degree $\leq f$ if $f$ is non-zero. \fun{GEN}{idealprimedec_limit_norm}{GEN nf, GEN p, GEN B} as \tet{idealprimedec}, limiting the list to primes of norm $\leq B$, which must be a positive \typ{INT}. \fun{GEN}{idealprimedec_galois}{GEN nf, GEN p} return a single prime ideal above $p$. \fun{GEN}{idealprimedec_degrees}{GEN nf, GEN p} return a (sorted) \typ{VECSMALL} containing the residue degrees $f(\goth{p} / p)$. \fun{GEN}{idealprimedec_kummer}{GEN nf, GEN Ti, long ei, GEN p} let \var{nf} (true \var{nf}) correspond to $K = \Q[X]/(T)$ ($T$ monic \kbd{ZX}). Let $T \equiv \prod_i T_i^{e_i} \pmod{p}$ be the factorization of $T$ and let $(f,g,h)$ be as in Dedekind criterion for prime $p$: $f \equiv \prod T_i$, $g \equiv \prod T_i^{e_i-1}$, $h = (T - fg) / p$, and let $D$ be the gcd of $(f,g,h)$ in $\F_p[X]$. Let \kbd{Ti} (\kbd{FpX}) be one irreducible factor $T_i$ not dividing $D$, with \kbd{ei} $= e_i$. This function returns the prime ideal attached to $T_i$ by Kummer / Dedekind criterion, namely $p \Z_K + T_i(\bar{X}) \Z_K$, which has ramification index $e_i$ over $p$. Shallow function. \fun{GEN}{idealHNF_Z_factor}{GEN x, GEN *pvN, GEN *pvZ} given an integral (non-$0$) ideal $x$ in HNF, compute both the factorization of $Nx$ and of $x\cap\Z$. This returns the vector of prime divisors of both and sets \kbd{*pvN} and \kbd{*pvZ} to the corresponding \typ{VECSMALL} vector of exponents for the factorization for the Norm and intersection with $\Z$ respetively. \fun{GEN}{idealHNF_Z_factor_i}{GEN x, GEN fa, GEN *pvN, GEN *pvZ} internal variant of \tet{idealHNF_Z_factor} where \kbd{fa} is either a partial factorization of $x\cap \Z$ ($= x[1,1]$) or \kbd{NULL}. Returns the prime divisors of $x$ above the rational primes in \kbd{fa} and attached \kbd{vN} and \kbd{vZ}. If \kbd{fa} is \kbd{NULL}, use the full factorization, i.e. identical to \tet{idealHNF_Z_factor}. \fun{GEN}{nf_pV_to_prV}{GEN}{nf, GEN P} given a vector of rational primes $P$, return the vector of all prime ideals above the $P[i]$. \fun{GEN}{nf_deg1_prime}{GEN nf} let \kbd{nf} be a true \var{nf}. This function returns a degree $1$ (unramified) prime ideal not dividing \kbd{nf.index}. In fact it returns an ideal above the smallest prime $p \geq [K:\Q]$ satisfying those conditions. \fun{GEN}{prV_lcm_capZ}{GEN L} given a vector $L$ of \var{prid} (maximal ideals) return the squarefree positive integer generating their lcm intersected with $\Z$. Not \kbd{gerepile}-safe. \fun{GEN}{pr_uniformizer}{GEN pr, GEN F} given a \var{prid} attached to $\goth{p} / p$ and $F$ in $\Z$ divisible exactly by $p$, return an $F$-uniformizer for \kbd{pr}, i.e. a $t$ in $\Z_K$ such that $v_{\goth{p}}(t) = 1$ and $(t, F/\goth{p}) = 1$. Not \kbd{gerepile}-safe. \subsec{Decomposition group} \fun{GEN}{idealramfrobenius}{GEN nf, GEN gal, GEN pr, GEN ram} Let $K$ be the number field defined by $nf$ and assume $K/\Q$ be a Galois extension with Galois group given \kbd{gal=galoisinit(nf)}, and that $pr$ is the prime ideal $\goth{P}$ in prid format, and that $\goth{P}$ is ramified, and \kbd{ram} is its list of ramification groups as output by \kbd{idealramgroups}. This function returns a permutation of \kbd{gal.group} which defines an automorphism $\sigma$ in the decomposition group of $\goth{P}$ such that if $p$ is the unique prime number in $\goth{P}$, then $\sigma(x)\equiv x^p\mod\P$ for all $x\in\Z_K$. \fun{GEN}{idealramfrobenius_aut}{GEN nf, GEN gal, GEN pr, GEN ram, GEN aut} as \kbd{idealramfrobenius(nf, gal, pr, ram}. \fun{GEN}{idealramgroups_aut}{GEN nf, GEN gal, GEN pr, GEN aut} as \kbd{idealramgroups(nf, gal, pr}. \fun{GEN}{idealfrobenius_aut}{GEN nf, GEN gal, GEN pr, GEN aut} faster version of \kbd{idealfrobenius(nf, gal, pr} where \kbd{aut} must be equal to \kbd{nfgaloispermtobasis(nf, gal)}. \subsec{Reducing modulo maximal ideals} \fun{GEN}{nfmodprinit}{GEN nf, GEN pr} returns an abstract \kbd{modpr} structure, attached to reduction modulo the maximal ideal \kbd{pr}, in \kbd{idealprimedec} format. From this data we can quickly project any \kbd{pr}-integral number field element to the residue field. \fun{GEN}{modpr_get_pr}{GEN x} return the \kbd{pr} component from a \kbd{modpr} structure. \fun{GEN}{modpr_get_p}{GEN x} return the $p$ component from a \kbd{modpr} structure (underlying rational prime). \fun{GEN}{modpr_get_T}{GEN x} return the \kbd{T} component from a \kbd{modpr} structure: either \kbd{NULL} (prime of degree $1$) or an irreducible \kbd{FpX} defining the residue field over $\F_p$. In library mode, it is often easier to use directly \fun{GEN}{nf_to_Fq_init}{GEN nf, GEN *ppr, GEN *pT, GEN *pp} concrete version of \kbd{nfmodprinit}: \kbd{nf} and \kbd{*ppr} are the inputs, the return value is a \kbd{modpr} and \kbd{*ppr}, \kbd{*pT} and \kbd{*pp} are set as side effects. The input \kbd{*ppr} is either a maximal ideal or already a \kbd{modpr} (in which case it is replaced by the underlying maximal ideal). The residue field is realized as $\F_p[X]/(T)$ for some monic $T\in\F_p[X]$, and we set \kbd{*pT} to $T$ and \kbd{*pp} to $p$. Set $T = \kbd{NULL}$ if the prime has degree $1$ and the residue field is $\F_p$. In short, this receives (or initializes) a \kbd{modpr} structure, and extracts from it $T$, $p$ and $\goth{p}$. \fun{GEN}{nf_to_Fq}{GEN nf, GEN x, GEN modpr} returns an \kbd{Fq} congruent to $x$ modulo the maximal ideal attached to \kbd{modpr}. The output is canonical: all elements in a given residue class are represented by the same \kbd{Fq}. \fun{GEN}{Fq_to_nf}{GEN x, GEN modpr} returns an \kbd{nf} element lifting the residue field element $x$, either a \typ{INT} or an algebraic integer in \kbd{algtobasis} format. \fun{GEN}{modpr_genFq}{GEN modpr} Returns an \kbd{nf} element whose image by \tet{nf_to_Fq} is $X \pmod T$, if $\deg T>1$, else $1$. \fun{GEN}{zkmodprinit}{GEN nf, GEN pr} as \tet{nfmodprinit}, but we assume we will only reduce algebraic integers, hence do not initialize data allowing to remove denominators. More precisely, we can in fact still handle an $x$ whose rational denominator is not $0$ in the residue field (i.e. if the valuation of $x$ is non-negative at all primes dividing $p$). \fun{GEN}{zk_to_Fq_init}{GEN nf, GEN *pr, GEN *T, GEN *p} as \kbd{nf\_to\_Fq\_init}, able to reduce only $p$-integral elements. \fun{GEN}{zk_to_Fq}{GEN x, GEN modpr} as \kbd{nf\_to\_Fq}, for a $p$-integral $x$. \fun{GEN}{nfM_to_FqM}{GEN M, GEN nf,GEN modpr} reduces a matrix of \kbd{nf} elements to the residue field; returns an \kbd{FqM}. \fun{GEN}{FqM_to_nfM}{GEN M, GEN modpr} lifts an \kbd{FqM} to a matrix of \kbd{nf} elements. \fun{GEN}{nfV_to_FqV}{GEN A, GEN nf,GEN modpr} reduces a vector of \kbd{nf} elements to the residue field; returns an \kbd{FqV} with the same type as \kbd{A} (\typ{VEC} or \typ{COL}). \fun{GEN}{FqV_to_nfV}{GEN A, GEN modpr} lifts an \kbd{FqV} to a vector of \kbd{nf} elements (same type as \kbd{A}). \fun{GEN}{nfX_to_FqX}{GEN Q, GEN nf,GEN modpr} reduces a polynomial with \kbd{nf} coefficients to the residue field; returns an \kbd{FqX}. \fun{GEN}{FqX_to_nfX}{GEN Q, GEN modpr} lifts an \kbd{FqX} to a polynomial with coefficients in \kbd{nf}. The following functions are technical and avoid computing a true \kbd{nfmodpr}: \fun{GEN}{pr_basis_perm}{GEN nf, GEN pr} given a true \var{nf} structure and a prime ideal \kbd{pr} above $p$, return as a \typ{VECSMALL} the $f(\goth{p}/p)$ indices $i$ such that the \kbd{nf.zk}$[i]$ mod \goth{p} form an $\F_p$-basis of the residue field. \fun{GEN}{QXQV_to_FpM}{GEN v, GEN T, GEN p} let $p$ be a positive integer, $v$ be a vector of $n$ polynomials with rational coefficients whose denominators are coprime to $p$, and $T$ be a \kbd{ZX} (preferably monic) of degree $d$ whose leading coefficient is coprime to $p$. Return the $d \times n$ \kbd{FpM} whose columns are the $v[i]$ mod $T,p$ in the canonical basis $1, X, \dots, X^{d-1}$, see \kbd{RgX\_to\_RgC}. This is for instance useful when $v$ contains a $\Z$-basis of the maximal order of a number field $\Q[X]/(P)$, $p$ is a prime not dividing the index of $P$ and $T$ is an irreducible factor of $P$ mod $p$, attached to a maximal ideal $\goth{p}$: left-multiplication by the matrix maps number field elements (in basis form) to the residue field of $\goth{p}$. \subsec{Valuations} \fun{long}{nfval}{GEN nf, GEN x, GEN P} return $v_P(x)$ \misctitle{Unsafe functions} assume that $P$, $Q$ are \kbd{prid}. \fun{long}{ZC_nfval}{GEN x, GEN P} returns $v_P(x)$, assuming $x$ is a \kbd{ZC}, representing a non-zero algebraic integer. \fun{long}{ZC_nfvalrem}{GEN x, GEN P, GEN *newx} returns $v = v_P(x)$, assuming $x$ is a \kbd{ZC}, representing a non-zero algebraic integer, and sets \kbd{*newx} to $x\tau^v$ which is an algebraic integer coprime to $p$. \fun{int}{ZC_prdvd}{GEN x, GEN P} returns $1$ is $P$ divides $x$ and $0$ otherwise. Assumes that $x$ is a \kbd{ZC}, representing an algebraic integer. Faster than computing $v_P(x)$. \fun{int}{pr_equal}{GEN P, GEN Q} returns 1 is $P$ and $Q$ represent the same maximal ideal: they must lie above the same $p$ and share the same $e,f$ invariants, but the $p$-uniformizer and $\tau$ element may differ. Returns $0$ otherwise. \subsec{Signatures}\label{se:signatures} ``Signs'' of the real embeddings of number field element are represented in additive notation, using the standard identification $(\Z/2\Z, +) \to (\{-1,1\},\times)$, $s\mapsto (-1)^s$. With respect to a fixed \kbd{nf} structure, a selection of real places (a divisor at infinity) is normally given as a \typ{VECSMALL} of indices of the roots \kbd{nf.roots} of the defining polynomial for the number field. For compatibility reasons, in particular under GP, the (obsolete) \kbd{vec01} form is also accepted: a \typ{VEC} with \kbd{gen\_0} or \kbd{gen\_1} entries. The following internal functions go back and forth between the two representations for the Archimedean part of divisors (GP: $0/1$ vectors, library: list of indices): \fun{GEN}{vec01_to_indices}{GEN v} given a \typ{VEC} $v$ with \typ{INT} entries return as a \typ{VECSMALL} the list of indices $i$ such that $v[i] \neq 0$. (Typically used with $0,1$-vectors but not necessarily so.) If $v$ is already a \typ{VECSMALL}, return it: not suitable for \kbd{gerepile} in this case. \fun{GEN}{vecsmall01_to_indices}{GEN v} as \bprog vec01_to_indices(zv_to_ZV(v)); @eprog \fun{GEN}{indices_to_vec01}{GEN p, long n} return the $0/1$ vector of length $n$ with ones exactly at the positions $p[1], p[2], \ldots$ \fun{GEN}{nfembed}{GEN nf, GEN x, long k} returns a floating point approximation of the $k$-th embedding of $x$ (attached to the $k$-th complex root in \kbd{nf.roots}). \fun{GEN}{nfsign}{GEN nf,GEN x} $x$ being a number field element and \kbd{nf} any form of number field, return the $0-1$-vector giving the signs of the $r_1$ real embeddings of $x$, as a \typ{VECSMALL}. Linear algebra functions like \tet{Flv_add_inplace} then allow keeping track of signs in series of multiplications. If $x$ is a \typ{VEC} of number field elements, return the matrix whose columns are the signs of the $x[i]$. \fun{GEN}{nfsign_arch}{GEN nf,GEN x,GEN arch} \kbd{arch} being a list of distinct real places, either in \kbd{vec01} (\typ{VEC} with \kbd{gen\_0} or \kbd{gen\_1} entries) or \kbd{indices} (\typ{VECSMALL}) form (see \tet{vec01_to_indices}), returns the signs of $x$ at the corresponding places. This is the low-level function underlying \kbd{nfsign}. \fun{int}{nfchecksigns}{GEN nf, GEN x, GEN pl} \var{pl} is a \typ{VECSMALL} with $r_1$ components, all of which are in $\{-1,0,1\}$. Return $1$ if $\sigma_i(x) \var{pl}[i] \geq 0$ for all $i$, and $0$ otherwise. \fun{GEN}{nfsign_units}{GEN bnf, GEN archp, int add_tu} \kbd{archp} being a divisor at infinity in \kbd{indices} form (or \kbd{NULL} for the divisor including all real places), return the signs at \kbd{archp} of a system of fundamental units for the field, in the same order as \kbd{bnf.tufu} if \kbd{add\_tu} is set; and in the same order as \kbd{bnf.fu} otherwise. \fun{GEN}{nfsign_from_logarch}{GEN L, GEN invpi, GEN archp} given $L$ the vector of the $\log \sigma(x)$, where $\sigma$ runs through the (real or complex) embeddings of some number field, \kbd{invpi} being a floating point approximation to $1/\pi$, and \kbd{archp} being a divisor at infinity in \kbd{indices} form, return the signs of $x$ at the corresponding places. This is the low-level function underlying \kbd{nfsign\_units}; the latter is actually a trivial wrapper \kbd{bnf} structures include the $\log \sigma(x)$ for a system of fundamental units of the field. \fun{GEN}{set_sign_mod_divisor}{GEN nf, GEN x, GEN y, GEN sarch} let $f = f_0f_\infty$ be a divisor, let \kbd{sarch} be the output of \kbd{nfarchstar(nf, f0, finf)}, let $x$ encode a vector of signs at the places of $f_\infty$ (see below), and let $y$ be a non-zero number field element. Returns $z$ congruent to $y$ mod $f_0$ (integral if $y$ is) such that $z$ and $x$ have the same signs at $f_\infty$. The following formats are supported for $x$: a $\{0,1\}$-vector of signs as a \typ{VECSMALL} (0 for positive, 1 for negative); \kbd{NULL} for a totally positive element (only $0$s); a number field element which is replaced by its signature at $f_\infty$. \fun{GEN}{nfarchstar}{GEN nf, GEN f0, GEN finf} for a divisor $f = f_0f_\infty$ represented by the integral ideal \kbd{f0} in HNF and the \kbd{finf} in \kbd{indices} form, returns $(\Z_K/f_\infty)^*$ in a form suitable for computations mod $f$. See \tet{set_sign_mod_divisor}. \fun{GEN}{idealprincipalunits}{GEN nf, GEN pr, long e} returns the multiplicative group $(1 + \var{pr}) / (1 + \var{pr}^e)$ as an abelian group. Faster than \tet{idealstar} when the norm of \var{pr} is large, since it avoids (useless) work in the multiplicative group of the residue field. \subsec{Maximal order and discriminant, conversion to \kbd{nf} structure} A number field $K = \Q[X]/(T)$ is defined by a monic $T\in\Z[X]$. The low-level function computing a maximal order is \fun{void}{nfmaxord}{nfmaxord_t *S, GEN T0, long flag}, where the polynomial $T_0$ is squarefree with integer coefficients. Let $K$ be the \'etale algebra $\Q[X]/(T_0)$ and let $T = \kbd{ZX\_Q\_normalize}(T_0)$, i.e. $T = C T_0(X/L)$ is monic and integral for some $C,Q\in \Q$. The structure \tet{nfmaxord_t} is initialized by the call; it has the following fields: \bprog GEN T0, T, dT, dK; /* T0, T, discriminants of T and K */ GEN unscale; /* the integer L */ GEN index; /* index of power basis in maximal order */ GEN dTP, dTE; /* factorization of |dT|, primes / exponents */ GEN dKP, dKE; /* factorization of |dK|, primes / exponents */ GEN basis; /* Z-basis for maximal order of Q[X]/(T) */ @eprog\noindent The exponent vectors are \typ{VECSMALL}. The primes in \kbd{dTP} and \kbd{dKP} are pseudoprimes, not proven primes. We recommend restricting to $T = T_0$, i.e. either to pass the input polynomial through \tet{ZX_Q_normalize} \emph{before} the call, or to forget about $T_0$ and go on with the polynomial $T$; otherwise $\kbd{unscale}\neq 1$, all data is expressed in terms of $T\neq T_0$, and needs to be converted to $T_0$. For instance to convert the basis to $\Q[X]/(T_0)$: \bprog RgXV_unscale(S.basis, S.unscale) @eprog Instead of passing $T$ (monic \kbd{ZX}), one can use the format $[T,\var{listP}]$ as in \kbd{nfbasis} or \kbd{nfinit}, which computes an order which is maximal at a set of primes, but need not be the maximal order. The \kbd{flag} is an or-ed combination of the binary flags, both of them deprecated: \tet{nf_PARTIALFACT}: do not try to fully factor \kbd{dT} and only look for primes less than \kbd{primelimit}. In that case, the elements in \kbd{dTP} and \kbd{dKP} need not all be primes. But the resulting \kbd{dK}, \kbd{index} and \kbd{basis} are correct provided there exists no prime $p > \kbd{primelimit}$ such that $p^2$ divides the field discriminant \kbd{dK}. This flag is \emph{deprecated}: the $[T,\var{listP}]$ format is safer and more flexible. \tet{nf_ROUND2}: this flag is \emph{deprecated} and now ignored. \fun{void}{nfinit_basic}{nfmaxord_t *S, GEN T0} a wrapper around \kbd{nfmaxord} (without the deprecated \kbd{flag}) that also accepts number field structures (\var{nf}, \var{bnf}, \dots) for \kbd{T0}. \fun{GEN}{nfmaxord_to_nf}{nfmaxord_t *S, GEN ro, long prec} convert an \tet{nfmaxord_t} to an \var{nf} structure at precision \kbd{prec}, where \kbd{ro} is \kbd{NULL}. The argument \kbd{ro} may also be set to a vector with $r_1 + r_2$ components containing the roots of \kbd{S->T} suitably ordered, i.e. first $r_1$ \typ{REAL} roots, then $r_2$ \typ{COMPLEX} representing the conguate pairs, but this is \emph{strongly discouraged}: the format is error-prone, and it is hard to compute the roots to the right accuracy in order to achieve \kbd{prec} accuracy for the \kbd{nf}. This function uses the integer basis \kbd{S->basis} as is, \emph{without} performing LLL-reduction. Unless the basis is already known to be reduced, use rather the following higher-level function: \fun{GEN}{nfinit_complete}{nfmaxord_t *S, long flag, long prec} convert an \tet{nfmaxord_t} to an \var{nf} structure at precision \kbd{prec}. The \kbd{flag} has the same meaning as in \kbd{nfinitall}. If \kbd{S->basis} is known to be reduced, it will be faster to use \tet{nfmaxord_to_nf}. \fun{GEN}{indexpartial}{GEN T, GEN dT} $T$ a monic separable \kbd{ZX}, \kbd{dT} is either \kbd{NULL} (no information) or a multiple of the discriminant of $T$. Let $K = \Q[X]/(T)$ and $\Z_K$ its maximal order. Returns a multiple of the exponent of the quotient group $\Z_K/(\Z[X]/(T))$. In other word, a \emph{denominator} $d$ such that $d x\in\Z[X]/(T)$ for all $x\in\Z_K$. \fun{GEN}{FpX_gcd_check}{GEN x, GEN y, GEN D} let $x$ and $y$ be two coprime polynomials with integer coefficients and let $D$ be a factor of the resultant of $x$ and $y$; try to factor $D$ by running the Euclidean algorithm on $x$ and $y$ modulo $D$. This returns \kbd{NULL} or a non trivial factor of $D$. This is the low-level function underlying \kbd{poldiscfactors} (applied to $x$, \kbd{ZX\_deriv}$(x)$ and the discriminant of $x$). It succeeds when $D$ has at least two prime divisors $p$ and $q$ such that one sub-resultant of $x$ and $y$ is divisible by $p$ but not by $q$. \subsec{Computing in the class group} We compute with arbitrary ideal representatives (in any of the various formats seen above), and call \fun{GEN}{bnfisprincipal0}{GEN bnf, GEN x, long flag}. The \kbd{bnf} structure already contains information about the class group in the form $\oplus_{i=1}^n (\Z/d_i\Z) g_i$ for canonical integers $d_i$ (with $d_n\mid\dots\mid d_1$ all $> 1$) and essentially random generators $g_i$, which are ideals in HNF. We normally do not need the value of the $g_i$, only that they are fixed once and for all and that any (non-zero) fractional ideal $x$ can be expressed uniquely as $x = (t)\prod_{i=1}^n g_i^{e_i}$, where $0 \leq e_i < d_i$, and $(t)$ is some principal ideal. Computing $e$ is straightforward, but $t$ may be very expensive to obtain explicitly. The routine returns (possibly partial) information about the pair $[e,t]$, depending on \kbd{flag}, which is an or-ed combination of the following symbolic flags: \item \tet{nf_GEN} tries to compute $t$. Returns $[e,t]$, with $t$ an empty vector if the computation failed. This flag is normally useless in non-trivial situations since the next two serve analogous purposes in more efficient ways. \item \tet{nf_GENMAT} tries to compute $t$ in factored form, which is much more efficient than \kbd{nf\_GEN} if the class group is moderately large; imagine a small ideal $x = (t)g^{10000}$: the norm of $t$ has $10000$ as many digits as the norm of $g$; do we want to see it as a vector of huge meaningless integers? The idea is to compute $e$ first, which is easy, then compute $(t)$ as $x \prod g_i^{-e_i}$ using successive \tet{idealmulred}, where the ideal reduction extracts small principal ideals along the way, eventually raised to large powers because of the binary exponentiation technique; the point is to keep this principal part in factored \emph{unexpanded} form. Returns $[e,t]$, with $t$ an empty vector if the computation failed; this should be exceedingly rare, unless the initial accuracy to which \kbd{bnf} was computed was ridiculously low (and then \kbd{bnfinit} should not have succeeded either). Setting/unsetting \kbd{nf\_GEN} has no effect when this flag is set. \item \tet{nf_GEN_IF_PRINCIPAL} tries to compute $t$ \emph{only} if the ideal is principal ($e = 0$). Returns \kbd{gen\_0} if the ideal is not principal. Setting/unsetting \kbd{nf\_GEN} has no effect when this flag is set, but setting/unsetting \kbd{nf\_GENMAT} is possible. \item \tet{nf_FORCE} in the above, insist on computing $t$, even if it requires recomputing a \kbd{bnf} from scratch. This is a last resort, and normally the accuracy of a \kbd{bnf} can be increased without trouble, but it may be that some algebraic information simply cannot be recovered from what we have: see \tet{bnfnewprec}. It should be very rare, though. In simple cases where you do not care about $t$, you may use \fun{GEN}{isprincipal}{GEN bnf, GEN x}, which is a shortcut for \kbd{bnfisprincipal0(bnf, x, 0)}. The following low-level functions are often more useful: \fun{GEN}{isprincipalfact}{GEN bnf, GEN C, GEN L, GEN f, long flag} is about the same as \kbd{bnfisprincipal0} applied to $C \prod L[i]^{f[i]}$, where the $L[i]$ are ideals, the $f[i]$ integers and $C$ is either an ideal or \kbd{NULL} (omitted). Make sure to include \tet{nf_GENMAT} in \kbd{flag}! \fun{GEN}{isprincipalfact_or_fail}{GEN bnf, GEN C, GEN L, GEN f} is for delicate cases, where we must be more clever than \kbd{nf\_FORCE} (it is used when trying to increase the accuracy of a \var{bnf}, for instance). If performs \bprog isprincipalfact(bnf,C, L, f, nf_GENMAT); @eprog\noindent but if it fails to compute $t$, it just returns a \typ{INT}, which is the estimated precision (in words, as usual) that would have been sufficient to complete the computation. The point is that \kbd{nf\_FORCE} does exactly this internally, but goes on increasing the accuracy of the \kbd{bnf}, then discarding it, which is a major inefficiency if you intend to compute lots of discrete logs and have selected a precision which is just too low. (It is sometimes not so bad since most of the really expensive data is cached in \kbd{bnf} anyway, if all goes well.) With this function, the \emph{caller} may decide to increase the accuracy using \tet{bnfnewprec} (and keep the resulting \kbd{bnf}!), or avoid the computation altogether. In any case the decision can be taken at the place where it is most likely to be correct. \fun{void}{bnftestprimes}{GEN bnf, GEN B} is an ingredient to certify unconditionnally a \kbd{bnf} computed assuming GRH, cf. \kbd{bnfcertify}. Running this function successfully proves that the classes of all prime ideals of norm $\leq B$ belong to the subgroup of the class group generated by the factorbase used to compute the \kbd{bnf} (equal to the class group under GRH). If the condition is not true, then (GRH is false and) the function will run forever. If it is known that primes of norm less than $B$ generate the class group (through variants of Minkowski's convex body or Zimmert's twin classes theorems), then the true class group is proven to be a quotient of \kbd{bnf.clgp}. \subsec{Floating point embeddings, the $T_2$ quadratic form} We assume the \var{nf} is a true \kbd{nf} structure, attached to a number field $K$ of degree $n$ and signature $(r_1,r_2)$. We saw that \fun{GEN}{nf_get_M}{GEN nf} returns the $(r_1+r_2)\times n$ matrix $M$ giving the embeddings of $K$, so that if $v$ is an $n$-th dimensional \typ{COL} representing the element $\sum_{i=1}^n v[i] w_i$ of $K$, then \kbd{RgM\_RgC\_mul(M,v)} represents the embeddings of $v$. Its first $r_1$ components are real numbers (\typ{INT}, \typ{FRAC} or \typ{REAL}, usually the latter), and the last $r_2$ are complex numbers (usually of \typ{COMPLEX}, but not necessarily for embeddings of rational numbers). \fun{GEN}{embed_T2}{GEN x, long r1} assuming $x$ is the vector of floating point embeddings of some algebraic number $v$, i.e. \bprog x = RgM_RgC_mul(nf_get_M(nf), algtobasis(nf,v)); @eprog\noindent returns $T_2(v)$. If the floating point embeddings themselves are not needed, but only the values of $T_2$, it is more efficient to restrict to real arithmetic and use \bprog gnorml2( RgM_RgC_mul(nf_get_G(nf), algtobasis(nf,v))); @eprog \fun{GEN}{embednorm_T2}{GEN x, long r1} analogous to \tet{embed_T2}, applied to the \kbd{gnorm} of the floating point embeddings. Assuming that \bprog x = gnorm( RgM_RgC_mul(nf_get_M(nf), algtobasis(nf,v)) ); @eprog\noindent returns $T_2(v)$. \fun{GEN}{embed_roots}{GEN z, long r1} given a vector $z$ of $r_1+r_2$ complex embeddings of the algebraic number $v$, return the $r_1+2r_2$ roots of its characteristic polynomial. Shallow function. \fun{GEN}{embed_disc}{GEN z, long r1, long prec} given a vector $z$ of $r_1+r_2$ complex embeddings of the algebraic number $v$, return a floating point approximation of the discriminant of its characteristic polynomial as a \typ{REAL} of precision \kbd{prec}. \fun{GEN}{embed_norm}{GEN x, long r1} given a vector $z$ of $r_1+r_2$ complex embeddings of the algebraic number $v$, return (a floating point approximation of) the norm of $v$. \subsec{Ideal reduction, low level} In the following routines \var{nf} is a true \kbd{nf}, attached to a number field $K$ of degree $n$: \fun{GEN}{nf_get_Gtwist}{GEN nf, GEN v} assuming $v$ is a \typ{VECSMALL} with $r_1+r_2$ entries, let $$|| x ||_v^2 = \sum_{i=1}^{r_1+r_2} 2^{v_i}\varepsilon_i|\sigma_i(x)|^2,$$ where as usual the $\sigma_i$ are the (real and) complex embeddings and $\varepsilon_i = 1$, resp.~$2$, for a real, resp.~complex place. This is a twisted variant of the $T_2$ quadratic form, the standard Euclidean form on $K\otimes \R$. In applications, only the relative size of the $v_i$ will matter. Let $G_v\in M_n(\R)$ be a square matrix such that if $x\in K$ is represented by the column vector $X$ in terms of the fixed $\Z$-basis of $\Z_K$ in \var{nf}, then $$||x||_v^2 = {}^t (G_v X) \cdot G_v X.$$ (This is a kind of Cholesky decomposition.) This function returns a rescaled copy of $G_v$, rounded to nearest integers, specifically \tet{RM_round_maxrank}$(G_v)$. Suitable for \kbd{gerepileupto}, but does not collect garbage. For convenience, also allow $v = $\kbd{NULL} (\tet{nf_get_roundG}) and $v$ a \typ{MAT} as output from the function itself: in both these cases, shallow function. \fun{GEN}{nf_get_Gtwist1}{GEN nf, long i}. Simple special case. Returns the twisted $G$ matrix attached to the vector $v$ whose entries are all $0$ except the $i$-th one, which is equal to $10$. \fun{GEN}{idealpseudomin}{GEN x, GEN G}. Let $x$, $G$ be two \kbd{ZM}s, such that the product $Gx$ is well-defined. This returns a ``small'' integral linear combinations of the columns of $x$, given by the LLL-algorithm applied to the lattice $G x$. Suitable for \kbd{gerepileupto}, but does not collect garbage. In applications, $x$ is an integral ideal, $G$ approximates a Cholesky form for the $T_2$ quadratic form as returned by \tet{nf_get_Gtwist}, and we return a small element $a$ in the lattice $(x,T_2)$. This is used to implement \tet{idealred}. \fun{GEN}{idealpseudomin_nonscalar}{GEN x, GEN G}. As \tet{idealpseudomin}, but we insist of returning a non-scalar $a$ (\kbd{ZV\_isscalar} is false), if the dimension of $x$ is $> 1$. In the interpretation where $x$ defines an integral ideal on a fixed $\Z_K$ basis whose first element is $1$, this means that $a$ is not rational. \fun{GEN}{idealpseudored}{GEN x, GEN G}. As \tet{idealpseudomin} but we return the full reduced $\Z$-basis of $x$ as a \typ{MAT} instead of a single vector. \fun{GEN}{idealred_elt}{GEN nf, GEN x} shortcut for \bprog idealpseudomin(x, nf_get_roundG(nf)) @eprog \subsec{Ideal reduction, high level} \label{se:Ideal_reduction} Given an ideal $x$ this means finding a ``simpler'' ideal in the same ideal class. The public GP function is of course available \fun{GEN}{idealred0}{GEN nf, GEN x, GEN v} finds an $a\in K^*$ such that $(a) x$ is integral of small norm and returns it, as an ideal in HNF. What ``small'' means depends on the parameter $v$, see the GP description. More precisely, $a$ is returned by \kbd{idealpseudomin}$((x_\Z) x^(-1),G)$ divided by $x_\Z$, where $x_\Z = (x\cap \Z)$ and where $G$ is \tet{nf_get_Gtwist}$(\var{nf}, v)$ for $v\neq \kbd{NULL}$ and \tet{nf_get_roundG}$(\var{nf})$ otherwise. \noindent Usually one sets $v = \kbd{NULL}$ to obtain an element of small $T_2$ norm in $x$: \fun{GEN}{idealred}{GEN nf, GEN x} is a shortcut for \kbd{idealred0(nf,x,NULL)}. The function \kbd{idealred} remains complicated to use: in order not to lose information $x$ must be an extended ideal, otherwise the value of $a$ is lost. There is a subtlety here: the principal ideal $(a)$ is easy to recover, but $a$ itself is an instance of the principal ideal problem which is very difficult given only an \var{nf} (once a \var{bnf} structure is available, \tet{bnfisprincipal0} will recover it). \fun{GEN}{idealmoddivisor}{GEN bnr, GEN x} A proof-of-concept implementation, useless in practice. If \kbd{bnr} is attached to some modulus $f$, returns a ``small'' ideal in the same class as $x$ in the ray class group modulo $f$. The reason why this is useless is that using extended ideals with principal part in a computation, there is a simple way to reduce them: simply reduce the generator of the principal part in $(\Z_K/f)^*$. \fun{GEN}{famat_to_nf_moddivisor}{GEN nf, GEN g, GEN e, GEN bid} given a true \var{nf} attached to a number field $K$, a \var{bid} structure attached to a modulus $f$, and an algebraic number in factored form $\prod g[i]^{e[i]}$, such that $(g[i],f) = 1$ for all $i$, returns a small element in $\Z_K$ congruent to it mod $f$. Note that if $f$ contains places at infinity, this includes sign conditions at the specified places. A simpler case when the conductor has no place at infinity: \fun{GEN}{famat_to_nf_modideal_coprime}{GEN nf, GEN g, GEN e, GEN f, GEN expo} as above except that the ideal $f$ is now integral in HNF (no need for a full \var{bid}), and we pass the exponent of the group $(\Z_K/f)^*$ as \kbd{expo}; any multiple will also do, at the expense of efficiency. Of course if a \var{bid} for $f$ is available, if is easy to extract $f$ and the exact value of \kbd{expo} from it (the latter is the first elementary divisor in the group structure). A useful trick: if you set \kbd{expo} to \emph{any} positive integer, the result is correct up to \kbd{expo}-th powers, hence exact if \kbd{expo} is a multiple of the exponent; this is useful when trying to decide whether an element is a square in a residue field for instance! (take \kbd{expo}$ = 2$). \fun{GEN}{nf_to_Fp_coprime}{GEN nf, GEN x, GEN modpr} this low-level function is variant of \tet{famat_to_nf_modideal_coprime}: \var{nf} is a true \var{nf} structure, \kbd{modpr} is from \kbd{zkmodprinit} attached to a prime of degree $1$ above the prime number $p$, and $x$ is either a number field element or a \kbd{famat} factorization matrix. We finally assume that no component of $x$ has a denominator $p$. What to do when the $g[i]$ are not coprime to $f$, but only $\prod g[i]^{e[i]}$ is? Then the situation is more complicated, and we advise to solve it one prime divisor of $f$ at a time. Let $v$ the valuation attached to a maximal ideal \kbd{pr} and assume $v(f) = k > 0$: \fun{GEN}{famat_makecoprime}{GEN nf, GEN g, GEN e, GEN pr, GEN prk, GEN expo} returns an element in $(\Z_K/\kbd{pr}^k)^*$ congruent to the product $\prod g[i]^{e[i]}$, assumed to be globally coprime to $f$. As above, \kbd{expo} is any positive multiple of the exponent of $(\Z_K/\kbd{pr}^k)^*$, for instance $(Nv-1)p^{k-1}$, if $p$ is the underlying rational prime. You may use other values of \kbd{expo} (see the useful trick in \tet{famat_to_nf_modideal_coprime}). \fun{GEN}{Idealstarprk}{GEN nf, GEN pr, long k, long flag} same as \kbd{Idealstar} for $I = \kbd{pr}^k$ \subsec{Class field theory} Under GP, a class-field theoretic description of a number field is given by a triple $A$, $B$, $C$, where the defining set $[A,B,C]$ can have any of the following forms: $[\var{bnr}]$, $[\var{bnr},\var{subgroup}]$, $[\var{bnf},\var{modulus}]$, $[\var{bnf},\var{modulus},\var{subgroup}]$. You can still use directly all of (\kbd{libpari}'s routines implementing) GP's functions as described in Chapter~3, but they are often awkward in the context of \kbd{libpari} programming. In particular, it does not make much sense to always input a triple $A,B,C$ because of the fringe $[\var{bnf},\var{modulus},\var{subgroup}]$. The first routine to call, is thus \fun{GEN}{Buchray}{GEN bnf, GEN mod, long flag} initializes a \var{bnr} structure from \kbd{bnf} and modulus \kbd{mod}. \kbd{flag} is an or-ed combination of \kbd{nf\_GEN} (include generators) and \kbd{nf\_INIT} (if omitted, do not return a \var{bnr}, only the ray class group as an abelian group). In fact, a single value of \kbd{flag} actually makes sense: \kbd{nf\_GEN | nf\_INIT} to initialize a proper \var{bnr}: removing \kbd{nf\_GEN} saves very little time, but the corresponding crippled \var{bnr} structure will raise errors in most class field theoretic functions. Possibly also 0 to quickly compute the ray class group structure; \tet{bnrclassno} is faster if we only need the \emph{order} of the ray class group. Now we have a proper \var{bnr} encoding a \kbd{bnf} and a modulus, we no longer need the $[\var{bnf},\var{modulus}]$ and $[\var{bnf},\var{modulus},\var{subgroup}]$ forms, which would internally call \tet{Buchray} anyway. Recall that a subgroup $H$ is given by a matrix in HNF, whose column express generators of $H$ on the fixed generators of the ray class group that stored in our \var{bnr}. You may also code the trivial subgroup by \kbd{NULL}. \fun{GEN}{bnrconductor}{GEN bnr, GEN H, long flag} see the documentation of the GP function. \fun{GEN}{bnrconductor_i}{GEN bnr, GEN H, long flag} shallow variant of \kbd{bnrconductor}. Useful when $\fl=2$ and the conductor is the \kbd{bnr} modulus: avoids copying the \kbd{bnr} (wasteful). \fun{long}{bnrisconductor}{GEN bnr, GEN H} returns 1 is the class field defined by the subgroup $H$ (of the ray class group mod $f$ coded in \kbd{bnr}) has conductor $f$. Returns 0 otherwise. \fun{GEN}{bnrchar_primitive}{GEN bnr, GEN chi, GEN bnrc} Given a normalized character $\kbd{chi} = [d,c]$ on \kbd{bnr.clgp} (see \tet{char_normalize}) of conductor \kbd{bnrc.mod}, compute the primitive character \kbd{chic} on \kbd{bnrc.clgp} equivalent to \kbd{chi}, given as a normalized character $[D,C]$ : \kbd{chic(bnrc.gen[i])} is $\zeta_D^{C[i]}$, where $D$ is minimal. It is easier to use \kbd{bnrconductor\_i(bnr,chi,2)}, but the latter recomputes \kbd{bnrc} for each new character. \fun{GEN}{bnrdisc}{GEN bnr, GEN H, long flag} returns the discriminant and signature of the class field defined by \kbd{bnr} and $H$. See the description of the GP function for details. \fl\ is an or-ed combination of the flags \tet{rnf_REL} (output relative data) and \tet{rnf_COND} (return 0 unless the modulus is the conductor). \fun{GEN}{bnrsurjection}{GEN BNR, GEN bnr} \kbd{BNR} and \kbd{bnr} defined over the same field $K$, for moduli $F$ and $f$ with $F\mid f$, returns the matrix of the canonical surjection $\text{Cl}_K(F)\to \text{Cl}_K(f)$ (giving the image of the fixed ray class group generators of \kbd{BNR} in terms of the ones in \kbd{bnr}). \fun{GEN}{ABC_to_bnr}{GEN A, GEN B, GEN C, GEN *H, int addgen} This is a quick conversion function designed to go from the too general (inefficient) $A$, $B$, $C$ form to the preferred \var{bnr}, $H$ form for class fields. Given $A$, $B$, $C$ as explained above (omitted entries coded by \kbd{NULL}), return the attached \var{bnr}, and set $H$ to the attached subgroup. If \kbd{addgen} is $1$, make sure that if the \var{bnr} needed to be computed, then it contains generators. \subsec{Grunwald--Wang theorem} \fun{GEN}{nfgwkummer}{GEN nf, GEN Lpr, GEN Ld, GEN pl, long var} low-level version of \kbd{nfgrunwaldwang}, assuming that \kbd{nf} contains suitable roots of unity, and directly using Kummer theory to construct the extension. \fun{GEN}{bnfgwgeneric}{GEN bnf, GEN Lpr, GEN Ld, GEN pl, long var} low-level version of \kbd{nfgrunwaldwang}, assuming that \kbd{bnf} is a \kbd{bnfinit} structure, and calling \kbd{rnfkummer} to construct the extension. \subsec{Relative equations, Galois conjugates} \fun{GEN}{nfissquarefree}{GEN nf, GEN P} given $P$ a polynomial with coefficients in \var{nf}, return $1$ is $P$ is squarefree, and $0$ otherwise. If is allowed (though less efficient) to replace \var{nf} by a monic \kbd{ZX} defining the field. \fun{GEN}{rnfequationall}{GEN A, GEN B, long *pk, GEN *pLPRS} $A$ is either an \var{nf} type (corresponding to a number field $K$) or an irreducible \kbd{ZX} defining a number field $K$. $B$ is an irreducible polynomial in $K[X]$. Returns an absolute equation $C$ (over $\Q$) for the number field $K[X]/(B)$. $C$ is the characteristic polynomial of $b + k a$ for some roots $a$ of $A$ and $b$ of $B$, and $k$ is a small rational integer. Set \kbd{*pk} to $k$. If \kbd{pLPRS} is not \kbd{NULL} set it to $[h_0, h_1]$, $h_i\in \Q[X]$, where $h_0+h_1 Y$ is the last non-constant polynomial in the pseudo-Euclidean remainder sequence attached to $A(Y)$ and $B(X-kY)$, leading to $C = \text{Res}_Y(A(Y), B(X-kY))$. In particular $a := -h_0/h_1$ is a root of $A$ in $\Q[X]/(C)$, and $X - ka$ is a root of $B$. \fun{GEN}{nf_rnfeq}{GEN A, GEN B} wrapper around \tet{rnfequationall} to allow mapping $K\to L$ (\kbd{eltup}) and converting elements of $L$ between absolute and relative form (\kbd{reltoabs}, \kbd{abstorel}), \emph{without} computing a full \var{rnf} structure, which is useful if the relative integral basis is not required. In fact, since $A$ may be a \typ{POL} or an \var{nf}, the integral basis of the base field is not needed either. The return value is the same as \tet{rnf_get_map}. Shallow function. \fun{GEN}{nf_rnfeqsimple}{GEN nf, GEN relpol} as \tet{nf_rnfeq} except some fields are omitted, so that only the \tet{abstorel} operation is supported. Shallow function. \fun{GEN}{eltabstorel}{GEN rnfeq, GEN x} \kbd{rnfeq} is as given by \tet{rnf_get_map} (but in this case \tet{rnfeltabstorel} is more robust), \tet{nf_rnfeq} or \tet{nf_rnfeqsimple}, return $x$ as an element of $L/K$, i.e. as a \typ{POLMOD} with \typ{POLMOD} coefficients. Shallow function. \fun{GEN}{eltabstorel_lift}{GEN rnfeq, GEN x} same as \tet{eltabstorel}, except that $x$ is returned in partially lifted form, i.e.~ as a \typ{POL} with \typ{POLMOD} coefficients. \fun{GEN}{eltreltoabs}{GEN rnfeq, GEN x} \kbd{rnfeq} is as given by \tet{rnf_get_map} (but in this case \tet{rnfeltreltoabs} is more robust) or \tet{nf_rnfeq}, return $x$ in absolute form. \fun{GEN}{nf_nfzk}{GEN nf, GEN rnfeq} \kbd{rnfeq} as given by \tet{nf_rnfeq}, \kbd{nf} a true \var{nf} structure, return a a suitable representation of \kbd{nf.zk} allowing quick computation of the map $K\to L$ by the function \tet{nfeltup}, \emph{without} computing a full \var{rnf} structure, which is useful if the relative integral basis is not required. The computed value is the same as in \tet{rnf_get_nfzk}. Shallow function. \fun{GEN}{nfeltup}{GEN nf, GEN x, GEN zknf} \kbd{zknf} and is initialized by \tet{nf_nfzk} or \tet{rnf_get_nfzk} (but in this case \tet{rnfeltup} is more robust); \kbd{nf} is a true \var{nf} structure for $K$, returns $x \in K$ as a (lifted) element of $L$, in absolute form. \fun{GEN}{rnfdisc_factored}{GEN nf, GEN pol, GEN *pd} variant of \kbd{rnfdisc} returning the relative discriminant ideal \emph{factorization}, and setting \kbd{*pd} to the discriminant as an element in $K^*/(K^*)^2$. Shallow function. \fun{GEN}{Rg_nffix}{const char *f, GEN T, GEN c, int lift} given a \kbd{ZX} $T$ and a ``coefficient'' $c$ supposedly belonging to $\Q[y]/(T)$, check whether this is a the case and return a cleaned up version of $c$. The string $f$ is the calling function name, used to report errors. This means that $c$ must be one of \typ{INT}, \typ{FRAC}, \typ{POL} in the variable $y$ with rational coefficients, or \typ{POLMOD} modulo $T$ which lift to a rational \typ{POL} as above. The cleanup consists in the following improvements: \item \typ{POL} coefficients are reduced modulo $T$. \item \typ{POL} and \typ{POLMOD} belonging to $\Q$ are converted to rationals, \typ{INT} or \typ{FRAC}. \item if \kbd{lift} is non-zero, convert \typ{POLMOD} to \typ{POL}, and otherwise convert \typ{POL} to \typ{POLMOD}s modulo $T$. \fun{GEN}{RgX_nffix}{const char *f, GEN T, GEN P, int lift} check whether $P$ is a polynomials with coefficients in the number field defined by the absolute equation $T(y) = 0$, where $T$ is a \kbd{ZX} and returns a cleaned up version of $P$. This checks whether $P$ is indeed a \typ{POL} with variable compatible with coefficients in $\Q[y]/(T)$, i.e. \bprog varncmp(varn(P), varn(T)) < 0 @eprog\noindent and applies \tet{Rg_nffix} to each coefficient. \fun{GEN}{RgV_nffix}{const char *f, GEN T, GEN P, int lift} as \tet{RgX_nffix} for a vector of coefficients. \fun{GEN}{polmod_nffix}{const char *f, GEN rnf, GEN x, int lift} given a \typ{POLMOD} $x$ supposedly defining an element of \var{rnf}, check this and perform \tet{Rg_nffix} cleanups. \fun{GEN}{polmod_nffix2}{const char *f, GEN T, GEN P, GEN x, int lift} as in \tet{polmod_nffix}, where the relative extension is explicitly defined as $L = (\Q[y]/(T))[x]/(P)$, instead of by an \kbd{rnf} structure. \fun{long}{numberofconjugates}{GEN T, long pinit} returns a quick multiple for the number of $\Q$-automorphism of the (integral, monic) \typ{POL} $T$, from modular factorizations, starting from prime \kbd{pinit} (you can set it to $2$). This upper bounds often coincides with the actual number of conjugates. Of course, you should use \tet{nfgaloisconj} to be sure. \fun{GEN}{nfroots_if_split}{GEN *pt, GEN T} let \kbd{*pt} point either to a number field structure or an irreducible \kbd{ZX}, defining a number field $K$. Given $T$ a monic squarefree polynomial with coefficients in $\Z_K$, return the list of roots of \kbd{pol} in $K$ if the polynomial splits completely, and \kbd{NULL} otherwise. In other words, this checks whether $K[X]/(T)$ is normal over $K$ (hence Galois since $T$ is separable by assumption). In the case where \kbd{*pT} is a \kbd{ZX}, the function has to compute internally a conditional \kbd{nf} attached to $K$ , whose \kbd{nf.zk} may not define the maximal order $\Z_K$ (see \kbd{nfroots}); \kbd{*pT} is then replaced by the conditional \kbd{nf} to avoid losing that information. \subsec{Cyclotomics units} \fun{GEN}{nfrootsof1}{GEN nf} returns a two-component vector $[w,z]$ where $w$ is the number of roots of unity in the number field \var{nf}, and $z$ is a primitive $w$-th root of unity. \fun{GEN}{nfcyclotomicunits}{GEN nf, GEN zu} where \kbd{zu} is as output by \kbd{nfrootsof1(nf)}, return the vector of the cyclotomic units in \kbd{nf} expressed over the integral basis. \subsec{Obsolete routines} Still provided for backward compatibility, but should not be used in new programs. They will eventually disappear. \fun{GEN}{zidealstar}{GEN nf, GEN x} short for \kbd{Idealstar(nf,x,nf\_GEN)} \fun{GEN}{zidealstarinit}{GEN nf, GEN x} short for \kbd{Idealstar(nf,x,nf\_INIT)} \fun{GEN}{zidealstarinitgen}{GEN nf, GEN x} short for \kbd{Idealstar(nf,x,nf\_GEN|nf\_INIT)} \fun{GEN}{buchimag}{GEN D, GEN c1, GEN c2, GEN gCO} short for \bprog Buchquad(D,gtodouble(c1),gtodouble(c2), /*ignored*/0) @eprog \fun{GEN}{buchreal}{GEN D, GEN gsens, GEN c1, GEN c2, GEN RELSUP, long prec} short for \bprog Buchquad(D,gtodouble(c1),gtodouble(c2), prec) @eprog The following use a naming scheme which is error-prone and not easily extensible; besides, they compute generators as per \kbd{nf\_GEN} and not \kbd{nf\_GENMAT}. Don't use them: \fun{GEN}{isprincipalforce}{GEN bnf,GEN x} \fun{GEN}{isprincipalgen}{GEN bnf, GEN x} \fun{GEN}{isprincipalgenforce}{GEN bnf, GEN x} \fun{GEN}{isprincipalraygen}{GEN bnr, GEN x}, use \tet{bnrisprincipal}. \noindent Variants on \kbd{polred}: use \kbd{polredbest}. \fun{GEN}{factoredpolred}{GEN x, GEN fa} \fun{GEN}{factoredpolred2}{GEN x, GEN fa} \fun{GEN}{smallpolred}{GEN x} \fun{GEN}{smallpolred2}{GEN x}, use \tet{Polred}. \fun{GEN}{polred0}{GEN x, long flag, GEN p} \fun{GEN}{polredabs}{GEN x} \fun{GEN}{polredabs2}{GEN x} \fun{GEN}{polredabsall}{GEN x, long flun} \noindent Superseded by \tet{bnrdisclist0}: \fun{GEN}{discrayabslist}{GEN bnf,GEN listes} \fun{GEN}{discrayabslistarch}{GEN bnf, GEN arch, long bound} \noindent Superseded by \tet{idealappr} (\fl is ignored) \fun{GEN}{idealappr0}{GEN nf, GEN x, long flag} \section{Galois extensions of $\Q$} This section describes the data structure output by the function \tet{galoisinit}. This will be called a \kbd{gal} structure in the following. \subsec{Extracting info from a \kbd{gal} structure} The functions below expect a \kbd{gal} structure and are shallow. See the documentation of \tet{galoisinit} for the meaning of the member functions. \fun{GEN}{gal_get_pol}{GEN gal} returns \kbd{gal.pol} \fun{GEN}{gal_get_p}{GEN gal} returns \kbd{gal.p} \fun{GEN}{gal_get_e}{GEN gal} returns the integer $e$ such that \kbd{gal.mod==gal.p\pow e}. \fun{GEN}{gal_get_mod}{GEN gal} returns \kbd{gal.mod}. \fun{GEN}{gal_get_roots}{GEN gal} returns \kbd{gal.roots}. \fun{GEN}{gal_get_invvdm}{GEN gal} \kbd{gal[4]}. \fun{GEN}{gal_get_den}{GEN gal} return \kbd{gal[5]}. \fun{GEN}{gal_get_group}{GEN gal} returns \kbd{gal.group}. \fun{GEN}{gal_get_gen}{GEN gal} returns \kbd{gal.gen}. \fun{GEN}{gal_get_orders}{GEN gal} returns \kbd{gal.orders}. \subsec{Miscellaneous functions} \fun{GEN}{nfgaloispermtobasis}{GEN nf, GEN gal} return the images of the field generator by the automorphisms \kbd{gal.orders} expressed on the integral basis \kbd{nf.zk}. \fun{GEN}{nfgaloismatrix}{GEN nf, GEN s} returns the \kbd{ZM} attached to the automorphism $s$, seen as a linear operator expressend on the number field integer basis. This allows to use \bprog M = nfgaloismatrix(nf, s); sx = ZM_ZC_mul(M, x); /* or RgM_RgC_mul(M, x) if x is not integral */ @eprog\noindent instead of \bprog sx = nfgaloisapply(nf, s, x); @eprog\noindent for an algebraic integer $x$. \section{Quadratic number fields and quadratic forms} \subsec{Checks} \fun{void}{check_quaddisc}{GEN x, long *s, long *mod4, const char *f} checks whether the \kbd{GEN} $x$ is a quadratic discriminant (\typ{INT}, not a square, congruent to $0,1$ modulo $4$), and raise an exception otherwise. Set \kbd{*s} to the sign of $x$ and \kbd{*mod4} to $x$ modulo $4$ (0 or 1). \fun{void}{check_quaddisc_real}{GEN x, long *mod4, const char *f} as \tet{check_quaddisc}; check that \kbd{signe(x)} is positive. \fun{void}{check_quaddisc_imag}{GEN x, long *mod4, const char *f} as \tet{check_quaddisc}; check that \kbd{signe(x)} is negative. \subsec{Class number} The function \kbd{quadclassunit} uses index calculus and runs in subexponential time but it assumes the truth of the GRH. For imaginary quadratic orders, it is comparatively slow for \emph{small} values, say $|D|\leq 10^{18}$. Here are some alternatives: \fun{GEN}{classno}{GEN D} corresponds to \kbd{qfbclassno(D,0)} and is only useful for $D < 0$, uses a baby-step giant-step technique and runs in time $O(D{1/4})$. The result is guaranteed correct for $|D| < 2\cdot 10^{10}$ and fastest in that range. For larger values of $|D|$, the algorithm is no longer rigorous and may give incorrect results (we know no concrete example); it also becomes relatively less interesting compared to \kbd{quadclassunit}. \fun{GEN}{classno2}{GEN D} corresponds to \kbd{qfbclassno(D,1)} and runs in time $O(D^{1/2})$; it is provided for testing purposes only: it is never competitive. \fun{GEN}{hclassno}{GEN d} returns the Hurwitz-Kronecker class number $H(d)$. These play a central role in trace fomulas and are usually needed for many consecutive values of $d$. Thus, the function uses a cache so that later calls for \emph{small} consecutive values of $d$ are instantaneous, see \kbd{getcache}. Large values of $d$ ($d > 500000$) call \kbd{quadclassunit} individually and are not memoized. \fun{GEN}{hclassno6}{GEN d} assuming $d > 0$, returns the integer $6 H(d)$. This is a low-level function behind \kbd{hclassno}. \fun{ulong}{hclassno6u}{ulong d} assuming $d > 0$, returns the integer $6 H(d)$. \subsec{\typ{QFI}, \typ{QFR}} \fun{GEN}{qfi}{GEN x, GEN y, GEN z} creates the \typ{QFI} $(x,y,z)$. \fun{GEN}{qfr}{GEN x, GEN y, GEN z, GEN d} creates the \typ{QFR} $(x,y,z)$ with distance component $d$. \fun{GEN}{qfr_1}{GEN q} given a \typ{QFR} $q$, return the unit form $q^0$. \fun{GEN}{qfi_1}{GEN q} given a \typ{QFI} $q$, return the unit form $q^0$. \fun{int}{qfb_equal1}{GEN q} returns 1 if the \typ{QFI} or \typ{QFR} $q$ is the unit form. \subsubsec{Composition} \fun{GEN}{qficomp}{GEN x, GEN y} compose the two \typ{QFI} $x$ and $y$, then reduce the result. This is the same as \kbd{gmul(x,y)}. \fun{GEN}{qfrcomp}{GEN x, GEN y} compose the two \typ{QFR} $x$ and $y$, then reduce the result. This is the same as \kbd{gmul(x,y)}. \fun{GEN}{qfisqr}{GEN x} as \kbd{qficomp(x,y)}. \fun{GEN}{qfrsqr}{GEN x} as \kbd{qfrcomp(x,y)}. \noindent Same as above, \emph{without} reducing the result: \fun{GEN}{qficompraw}{GEN x, GEN y} \fun{GEN}{qfrcompraw}{GEN x, GEN y} \fun{GEN}{qfisqrraw}{GEN x} \fun{GEN}{qfrsqrraw}{GEN x} \fun{GEN}{qfbcompraw}{GEN x, GEN y} compose two \typ{QFI}s or two \typ{QFR}s, without reduce the result. \subsubsec{Powering} \fun{GEN}{powgi}{GEN x, GEN n} computes $x^n$ (will work for many more types than \typ{QFI} and \typ{QFR}, of course). Reduce the result. \fun{GEN}{qfrpow}{GEN x, GEN n} computes $x^n$ for a \typ{QFR} $x$, reducing along the way. If the distance component is initially $0$, leave it alone; otherwise update it. \fun{GEN}{qfbpowraw}{GEN x, long n} compute $x^n$ (pure composition, no reduction), for a \typ{QFI} or \typ{QFR} $x$. \fun{GEN}{qfipowraw}{GEN x, long n} as \tet{qfbpowraw}, for a \typ{QFI} $x$. \fun{GEN}{qfrpowraw}{GEN x, long n} as \tet{qfbpowraw}, for a \typ{QFR} $x$. \subsubsec{Order, discrete log} \fun{GEN}{qfi_order}{GEN q, GEN o} assuming that the \typ{QFI} $q$ has order dividing $o$, compute its order in the class group. The order can be given in all formats allowed by generic discrete log functions, the preferred format being \kbd{[ord, fa]} (\typ{INT} and its factorization). \fun{GEN}{qfi_log}{GEN a, GEN g, GEN o} given a \typ{QFI} $a$ and assuming that the \typ{QFI} $g$ has order $o$, compute an integer $k$ such that $a^k = g$. Return \kbd{cgetg(1, t\_VEC)} if there are no solutions. Uses a generic Pollig-Hellman algorithm, then either Shanks (small $o$) or Pollard rho (large $o$) method. The order can be given in all formats allowed by generic discrete log functions, the preferred format being \kbd{[ord, fa]} (\typ{INT} and its factorization). \fun{GEN}{qfi_Shanks}{GEN a, GEN g, long n} given a \typ{QFI} $a$ and assuming that the \typ{QFI} $g$ has (small) order $n$, compute an integer $k$ such that $a^k = g$. Return \kbd{cgetg(1, t\_VEC)} if there are no solutions. Directly uses Shanks algorithm, which is inefficient when $n$ is composite. \subsubsec{Solve, Cornacchia} The following functions underly \tet{qfbsolve}; $p$ denotes a prime number. \fun{GEN}{qfisolvep}{GEN Q, GEN p} solves $Q(x,y) = p$ over the integers, for a \typ{QFI} $Q$. Return \kbd{gen\_0} if there are no solutions. \fun{GEN}{qfrsolvep}{GEN Q, GEN p} solves $Q(x,y) = p$ over the integers, for a \typ{QFR} $Q$. Return \kbd{gen\_0} if there are no solutions. \fun{long}{cornacchia}{GEN d, GEN p, GEN *px, GEN *py} solves $x^2+ dy^2 = p$ over the integers, where $d > 0$. Return $1$ if there is a solution (and store it in \kbd{*x} and \kbd{*y}), $0$ otherwise. \fun{long}{cornacchia2}{GEN d, GEN p, GEN *px, GEN *py} as \kbd{cornacchia}, for the equation $x^2 + dy^2 = 4p$. \fun{long}{cornacchia2_sqrt}{GEN d, GEN p, GEN b, GEN *px, GEN *py} as \kbd{cornacchia2}, where $p > 2$ and $b$ is the smallest squareroot of $d$ modulo $p$. \subsubsec{Prime forms} \fun{GEN}{primeform_u}{GEN x, ulong p} \typ{QFI} whose first coefficient is the prime $p$. \fun{GEN}{primeform}{GEN x, GEN p, long prec} \subsec{Efficient real quadratic forms} Unfortunately, \typ{QFR}s are very inefficient, and are only provided for backward compatibility. \item they do not contain needed quantities, which are thus constantly recomputed (the discriminant $D$, $\sqrt{D}$ and its integer part), \item the distance component is stored in logarithmic form, which involves computing one extra logarithm per operation. It is much more efficient to store its exponential, computed from ordinary multiplications and divisions (taking exponent overflow into account), and compute its logarithm at the very end. Internally, we have two representations for real quadratic forms: \item \tet{qfr3}, a container $[a,b,c]$ with at least 3 entries: the three coefficients; the idea is to ignore the distance component. \item \tet{qfr5}, a container with at least 5 entries $[a,b,c,e,d]$: the three coefficients a \typ{REAL} $d$ and a \typ{INT} $e$ coding the distance component $2^{Ne} d$, in exponential form, for some large fixed $N$. It is a feature that \kbd{qfr3} and \kbd{qfr5} have no specified length or type. It implies that a \kbd{qfr5} or \typ{QFR} will do whenever a \kbd{qfr3} is expected. Routines using these objects all require a global context, provided by a \kbd{struct qfr\_data *}: \bprog struct qfr_data { GEN D; /* discriminant, t_INT */ GEN sqrtD; /* sqrt(D), t_REAL */ GEN isqrtD; /* floor(sqrt(D)), t_INT */ }; @eprog \fun{void}{qfr_data_init}{GEN D, long prec, struct qfr_data *S} given a discriminant $D > 0$, initialize $S$ for computations at precision \kbd{prec} ($\sqrt{D}$ is computed to that initial accuracy). \noindent All functions below are shallow, and not stack clean. \fun{GEN}{qfr3_comp}{GEN x, GEN y, struct qfr_data *S} compose two \kbd{qfr3}, reducing the result. \fun{GEN}{qfr3_pow}{GEN x, GEN n, struct qfr_data *S} compute $x^n$, reducing along the way. \fun{GEN}{qfr3_red}{GEN x, struct qfr_data *S} reduce $x$. \fun{GEN}{qfr3_rho}{GEN x, struct qfr_data *S} perform one reduction step; \kbd{qfr3\_red} just performs reduction steps until we hit a reduced form. \fun{GEN}{qfr3_to_qfr}{GEN x, GEN d} recover an ordinary \typ{QFR} from the \kbd{qfr3} $x$, adding distance component $d$. Before we explain \kbd{qfr5}, recall that it corresponds to an ideal, that reduction corresponds to multiplying by a principal ideal, and that the distance component is a clever way to keep track of these principal ideals. More precisely, reduction consists in a number of reduction steps, going from the form $(a,b,c)$ to $\rho(a,b,c) = (c, -b \mod 2c, *)$; the distance component is multiplied by (a floating point approximation to) $(b + \sqrt{D}) / (b - \sqrt{D})$. \fun{GEN}{qfr5_comp}{GEN x, GEN y, struct qfr_data *S} compose two \kbd{qfr5}, reducing the result, and updating the distance component. \fun{GEN}{qfr5_pow}{GEN x, GEN n, struct qfr_data *S} compute $x^n$, reducing along the way. \fun{GEN}{qfr5_red}{GEN x, struct qfr_data *S} reduce $x$. \fun{GEN}{qfr5_rho}{GEN x, struct qfr_data *S} perform one reduction step. \fun{GEN}{qfr5_dist}{GEN e, GEN d, long prec} decode the distance component from exponential (\kbd{qfr5}-specific) to logarithmic form (as in a \typ{QFR}). \fun{GEN}{qfr_to_qfr5}{GEN x, long prec} convert a \typ{QFR} to a \kbd{qfr5} with initial trivial distance component ($= 1$). \fun{GEN}{qfr5_to_qfr}{GEN x, GEN d}, assume $x$ is a \kbd{qfr5} and $d$ was the original distance component of some \typ{QFR} that we converted using \tet{qfr_to_qfr5} to perform efficiently a number of operations. Convert $x$ to a \typ{QFR} with the correct (logarithmic) distance component. \section{Linear algebra over $\Z$} \subsec{Hermite and Smith Normal Forms} \fun{GEN}{ZM_hnf}{GEN x} returns the upper triangular Hermite Normal Form of the \kbd{ZM} $x$ (removing $0$ columns), using the \tet{ZM_hnfall} algorithm. If you want the true HNF, use \kbd{ZM\_hnfall(x, NULL, 0)}. \fun{GEN}{ZM_hnfmod}{GEN x, GEN d} returns the HNF of the \kbd{ZM} $x$ (removing $0$ columns), assuming the \typ{INT} $d$ is a multiple of the determinant of $x$. This is usually faster than \tet{ZM_hnf} (and uses less memory) if the dimension is large, $> 50$ say. \fun{GEN}{ZM_hnfmodid}{GEN x, GEN d} returns the HNF of the matrix $(x \mid d \text{Id})$ (removing $0$ columns), for a \kbd{ZM} $x$ and a \typ{INT} $d$. \fun{GEN}{ZM_hnfmodprime}{GEN x, GEN p} returns the HNF of the matrix $(x \mid p \text{Id})$ (removing $0$ columns), for a \kbd{ZM} $x$ and a prime number $p$. The algorithm involves only $\F_p$-linear algebra and is is faster than \tet{ZM_hnfmodid} (which will call it when $d$ is prime). \fun{GEN}{ZM_hnfmodall}{GEN x, GEN d, long flag} low-level function underlying the \kbd{ZM\_hnfmod} variants. If \kbd{flag} is $0$, calls \kbd{ZM\_hnfmod(x,d)}; \kbd{flag} is an or-ed combination of: \item \tet{hnf_MODID} call \kbd{ZM\_hnfmodid} instead of \kbd{ZM\_hnfmod}, \item \tet{hnf_PART} return as soon as we obtain an upper triangular matrix, saving time. The pivots are non-negative and give the diagonal of the true HNF, but the entries to the right of the pivots need not be reduced, i.e.~they may be large or negative. \item \tet{hnf_CENTER} returns the centered HNF, where the entries to the right of a pivot $p$ are centered residues in $[-p/2, p/2[$, hence smallest possible in absolute value, but possibly negative. \fun{GEN}{ZM_hnfmodall_i}{GEN x, GEN d, long flag} as \tet{ZM_hnfmodall} without final garbage collection. Not \kbd{gerepile}-safe. \fun{GEN}{ZM_hnfall}{GEN x, GEN *U, long remove} returns the upper triangular HNF $H$ of the \kbd{ZM} $x$; if $U$ is not \kbd{NULL}, set if to the matrix $U$ such that $x U = H$. If $\kbd{remove} = 0$, $H$ is the true HNF, including $0$ columns; if $\kbd{remove} = 1$, delete the $0$ columns from $H$ but do not update $U$ accordingly (so that the integer kernel may still be recovered): we no longer have $x U = H$; if $\kbd{remove} = 2$, remove $0$ columns from $H$ and update $U$ so that $x U = H$. The matrix $U$ is square and invertible unless $\kbd{remove} = 2$. This routine uses a naive algorithm which is potentially exponential in the dimension (due to coefficient explosion) but is fast in practice, although it may require lots of memory. The base change matrix $U$ may be very large, when the kernel is large. \fun{GEN}{ZM_hnfall_i}{GEN x, GEN *U, long remove} as \tet{ZM_hnfall} without final garbage collection. Not \kbd{gerepile}-safe. \fun{GEN}{ZM_hnfperm}{GEN A, GEN *ptU, GEN *ptperm} returns the hnf $H = P A U$ of the matrix $P A$, where $P$ is a suitable permutation matrix, and $U\in \text{Gl}_n(\Z)$. $P$ is chosen so as to (heuristically) minimize the size of $U$; in this respect it is less efficient than \kbd{ZM\_hnflll} but usually faster. Set \kbd{*ptU} to $U$ and \kbd{*pterm} to a \typ{VECSMALL} representing the row permutation attached to $P = (\delta_{i,\kbd{perm}[i]}$. If \kbd{ptU} is set to \kbd{NULL}, $U$ is not computed, saving some time; although useless, setting \kbd{ptperm} to \kbd{NULL} is also allowed. \fun{GEN}{ZM_hnf_knapsack}{GEN x} given a \kbd{ZM} $x$, compute its HNF $h$. Return $h$ if it has the knapsack property: every column contains only zeroes and ones and each row contains a single $1$; return \kbd{NULL} otherwise. Not suitable for gerepile. \fun{GEN}{ZM_hnflll}{GEN x, GEN *U, int remove} returns the HNF $H$ of the \kbd{ZM} $x$; if $U$ is not \kbd{NULL}, set if to the matrix $U$ such that $x U = H$. The meaning of \kbd{remove} is the same as in \tet{ZM_hnfall}. This routine uses the \idx{LLL} variant of Havas, Majewski and Mathews, which is polynomial time, but rather slow in practice because it uses an exact LLL over the integers instead of a floating point variant; it uses polynomial space but lots of memory is needed for large dimensions, say larger than 300. On the other hand, the base change matrix $U$ is essentially optimally small with respect to the $L_2$ norm. \fun{GEN}{ZM_hnfcenter}{GEN M}. Given a \kbd{ZM} in HNF $M$, update it in place so that non-diagonal entries belong to a system of \emph{centered} residues. Not suitable for gerepile. Some direct applications: the following routines apply to upper triangular integral matrices; in practice, these come from HNF algorithms. \fun{GEN}{hnf_divscale}{GEN A, GEN B,GEN t} $A$ an upper triangular \kbd{ZM}, $B$ a \kbd{ZM}, $t$ an integer, such that $C := tA^{-1}B$ is integral. Return $C$. \fun{GEN}{hnf_invscale}{GEN A, GEN t} $A$ an upper triangular \kbd{ZM}, $t$ an integer such that $C := tA^{-1}$ is integral. Return $C$. Special case of \tet{hnf_divscale} when $B$ is the identity matrix. \fun{GEN}{hnf_solve}{GEN A, GEN B} $A$ a \kbd{ZM} in upper HNF (not necessarily square), $B$ a \kbd{ZM} or \kbd{ZC}. Return $A^{-1}B$ if it is integral, and \kbd{NULL} if it is not. \fun{GEN}{hnf_invimage}{GEN A, GEN b} $A$ a \kbd{ZM} in upper HNF (not necessarily square), $b$ a \kbd{ZC}. Return $A^{-1}B$ if it is integral, and \kbd{NULL} if it is not. \fun{int}{hnfdivide}{GEN A, GEN B} $A$ and $B$ are two upper triangular \kbd{ZM}. Return $1$ if $A^{-1} B$ is integral, and $0$ otherwise. \misctitle{Smith Normal Form} \fun{GEN}{ZM_snf}{GEN x} returns the Smith Normal Form (vector of elementary divisors) of the \kbd{ZM} $x$. \fun{GEN}{ZM_snfall}{GEN x, GEN *U, GEN *V} returns \kbd{ZM\_snf(x)} and sets $U$ and $V$ to unimodular matrices such that $U\, x\, V = D$ (diagonal matrix of elementary divisors). Either (or both) $U$ or $V$ may be \kbd{NULL} in which case the corresponding matrix is not computed. \fun{GEN}{ZV_snfall}{GEN d, GEN *U, GEN *V} here $d$ is a \kbd{ZV}; same as \tet{ZM_snfall} applied to \kbd{diagonal(d)}, but faster. \fun{GEN}{ZM_snfall_i}{GEN x, GEN *U, GEN *V, int returnvec} same as \kbd{ZM\_snfall}, except that, depending on the value of \kbd{returnvec}, we either return a diagonal matrix (as in \kbd{ZM\_snfall}, \kbd{returnvec} is 0) or a vector of elementary divisors (as in \kbd{ZM\_snf}, \kbd{returnvec} is 1) . \fun{void}{ZM_snfclean}{GEN d, GEN U, GEN V} assuming $d$, $U$, $V$ come from \kbd{d = ZM\_snfall(x, \&U, \&V)}, where $U$ or $V$ may be \kbd{NULL}, cleans up the output in place. This means that elementary divisors equal to 1 are deleted and $U$, $V$ are updated. The output is not suitable for \kbd{gerepileupto}. \fun{void}{ZV_snf_trunc}{GEN D} given a vector $D$ of elementary divisors (i.e. a \kbd{ZV} such that $d_i \mid d_{i+1}$), truncate it \emph{in place} to leave out the trivial divisors (equal to $1$). \fun{GEN}{ZM_snf_group}{GEN H, GEN *U, GEN *Uinv} this function computes data to go back and forth between an abelian group (of finite type) given by generators and relations, and its canonical SNF form. Given an abstract abelian group with generators $g = (g_1,\dots,g_n)$ and a vector $X=(x_i)\in\Z^n$, we write $g X$ for the group element $\sum_i x_i g_i$; analogously if $M$ is an $n\times r$ integer matrix $g M$ is a vector containing $r$ group elements. The group neutral element is $0$; by abuse of notation, we still write $0$ for a vector of group elements all equal to the neutral element. The input is a full relation matrix $H$ among the generators, i.e. a \kbd{ZM} (not necessarily square) such that $gX = 0$ for some $X\in\Z^n$ if and only if $X$ is in the integer image of $H$, so that the abelian group is isomorphic to $\Z^n/\text{Im} H$. \emph{The routine assumes that $H$ is in HNF;} replace it by its HNF if it is not the case. (Of course this defines the same group.) Let $G$ a minimal system of generators in SNF for our abstract group: if the $d_i$ are the elementary divisors ($\dots \mid d_2\mid d_1$), each $G_i$ has either infinite order ($d_i = 0$) or order $d_i > 1$. Let $D$ the matrix with diagonal $(d_i)$, then $$G D = 0,\quad G = g U_{\text{inv}},\quad g = G U,$$ for some integer matrices $U$ and $U_{\text{inv}}$. Note that these are not even square in general; even if square, there is no guarantee that these are unimodular: they are chosen to have minimal entries given the known relations in the group and only satisfy $D \mid (U U_{\text{inv}} - \text{Id})$ and $H \mid (U_{\text{inv}}U - \text{Id})$. The function returns the vector of elementary divisors $(d_i)$; if \kbd{U} is not \kbd{NULL}, it is set to $U$; if \kbd{Uinv} is not \kbd{NULL} it is set to $U_{\text{inv}}$. The function is not memory clean. \fun{GEN}{ZV_snf_group}{GEN d, GEN *newU, GEN *newUi}, here $d$ is a \kbd{ZV}; same as \tet{ZM_snf_group} applied to \kbd{diagonal(d)}, but faster. The following routines underly the various \tet{matrixqz} variants. In all case the $m\times n$ \typ{MAT} $x$ is assumed to have rational (\typ{INT} and \typ{FRAC}) coefficients \fun{GEN}{QM_ImQ_hnf}{GEN x} returns an HNF basis for $\text{Im}_\Q x \cap \Z^n$. \fun{GEN}{QM_ImZ_hnf}{GEN x} returns an HNF basis for $\text{Im}_\Z x \cap \Z^n$. \fun{GEN}{QM_ImQ_hnfall}{GEN A, GEN *pB, long remove} as \tet{QM_ImQ_hnf}, further returning the transformation matrix as in \tet{ZM_hnfall}. \fun{GEN}{QM_ImZ_hnfall}{GEN A, GEN *pB, long remove} as \tet{QM_ImZ_hnf}, further returning the transformation matrix as in \tet{ZM_hnfall}. \fun{GEN}{QM_minors_coprime}{GEN x, GEN D}, assumes $m\geq n$, and returns a matrix in $M_{m,n}(\Z)$ with the same $\Q$-image as $x$, such that the GCD of all $n\times n$ minors is coprime to $D$; if $D$ is \kbd{NULL}, we want the GCD to be $1$. \smallskip The following routines are simple wrappers around the above ones and are normally useless in library mode: \fun{GEN}{hnf}{GEN x} checks whether $x$ is a \kbd{ZM}, then calls \tet{ZM_hnf}. Normally useless in library mode. \fun{GEN}{hnfmod}{GEN x, GEN d} checks whether $x$ is a \kbd{ZM}, then calls \tet{ZM_hnfmod}. Normally useless in library mode. \fun{GEN}{hnfmodid}{GEN x,GEN d} checks whether $x$ is a \kbd{ZM}, then calls \tet{ZM_hnfmodid}. Normally useless in library mode. \fun{GEN}{hnfall}{GEN x} calls \kbd{ZM\_hnfall(x, \&U, 1)} and returns $[H, U]$. Normally useless in library mode. \fun{GEN}{hnflll}{GEN x} calls \kbd{ZM\_hnflll(x, \&U, 1)} and returns $[H, U]$. Normally useless in library mode. \fun{GEN}{hnfperm}{GEN x} calls \kbd{ZM\_hnfperm(x, \&U, \&P)} and returns $[H, U, P]$. Normally useless in library mode. \fun{GEN}{smith}{GEN x} checks whether $x$ is a \kbd{ZM}, then calls \kbd{ZM\_snf}. Normally useless in library mode. \fun{GEN}{smithall}{GEN x} checks whether $x$ is a \kbd{ZM}, then calls \kbd{ZM\_snfall(x, \&U, \&V)} and returns $[U,V,D]$. Normally useless in library mode. \noindent Some related functions over $K[X]$, $K$ a field: \fun{GEN}{gsmith}{GEN A} the input matrix must be square, returns the elementary divisors. \fun{GEN}{gsmithall}{GEN A} the input matrix must be square, returns the $[U,V,D]$, $D$ diagonal, such that $UAV = D$. \fun{GEN}{RgM_hnfall}{GEN A, GEN *pB, long remove} analogous to \tet{ZM_hnfall}. \fun{GEN}{smithclean}{GEN z} cleanup the output of \kbd{smithall} or \kbd{gsmithall} (delete elementary divisors equal to $1$, updating base change matrices). \subsec{The LLL algorithm}\sidx{LLL} The basic GP functions and their immediate variants are normally not very useful in library mode. We briefly list them here for completeness, see the documentation of \kbd{qflll} and \kbd{qflllgram} for details: \item \fun{GEN}{qflll0}{GEN x, long flag} \fun{GEN}{lll}{GEN x} \fl = 0 \fun{GEN}{lllint}{GEN x} \fl = 1 \fun{GEN}{lllkerim}{GEN x} \fl = 4 \fun{GEN}{lllkerimgen}{GEN x} \fl = 5 \fun{GEN}{lllgen}{GEN x} \fl = 8 \item \fun{GEN}{qflllgram0}{GEN x, long flag} \fun{GEN}{lllgram}{GEN x} \fl = 0 \fun{GEN}{lllgramint}{GEN x} \fl = 1 \fun{GEN}{lllgramkerim}{GEN x} \fl = 4 \fun{GEN}{lllgramkerimgen}{GEN x} \fl = 5 \fun{GEN}{lllgramgen}{GEN x} \fl = 8 \smallskip The basic workhorse underlying all integral and floating point LLLs is \fun{GEN}{ZM_lll}{GEN x, double D, long flag}, where $x$ is a \kbd{ZM}; $D \in ]1/4,1[$ is the Lov\'{a}sz constant determining the frequency of swaps during the algorithm: a larger values means better guarantees for the basis (in principle smaller basis vectors) but longer running times (suggested value: $D = 0.99$). \misctitle{Important} This function does not collect garbage and its output is not suitable for either \kbd{gerepile} or \kbd{gerepileupto}. We expect the caller to do something simple with the output (e.g. matrix multiplication), then collect garbage immediately. \noindent\kbd{flag} is an or-ed combination of the following flags: \item \tet{LLL_GRAM}. If set, the input matrix $x$ is the Gram matrix ${}^t v v$ of some lattice vectors $v$. \item \tet{LLL_INPLACE}. If unset, we return the base change matrix $U$, otherwise the transformed matrix $x U$ or ${}^t U x U$ (\kbd{LLL\_GRAM}). Implies \tet{LLL_IM} (see below). \item \tet{LLL_KEEP_FIRST}. The first vector in the output basis is the same one as was originally input. Provided this is a shortest non-zero vector of the lattice, the output basis is still LLL-reduced. This is used to reduce maximal orders of number fields with respect to the $T_2$ quadratic form, to ensure that the first vector in the output basis corresponds to $1$ (which is a shortest vector). \item \tet{LLL_COMPATIBLE}. This is a no-op on 64-bit kernels; on 32-bit kernels, restrict to 64-bit-compatible accuracies in the course of LLL algorithms. This is very likely to produce identical results on all kernels, but this is not guaranteed. The last three flags are mutually exclusive, either 0 or a single one must be set: \item \tet{LLL_KER} If set, only return a kernel basis $K$ (not LLL-reduced). \item \tet{LLL_IM} If set, only return an LLL-reduced lattice basis $T$. (This is implied by \tet{LLL_INPLACE}). \item \tet{LLL_ALL} If set, returns a 2-component vector $[K, T]$ corresponding to both kernel and image. \fun{GEN}{lllfp}{GEN x, double D, long flag} is a variant for matrices with inexact entries: $x$ is a matrix with real coefficients (types \typ{INT}, \typ{FRAC} and \typ{REAL}), $D$ and $\fl$ are as in \tet{ZM_lll}. The matrix is rescaled, rounded to nearest integers, then fed to \kbd{ZM\_lll}. The flag \kbd{LLL\_INPLACE} is still accepted but less useful (it returns an LLL-reduced basis attached to rounded input, instead of an exact base change matrix). \fun{GEN}{ZM_lll_norms}{GEN x, double D, long flag, GEN *ptB} slightly more general version of \kbd{ZM\_lll}, setting \kbd{*ptB} to a vector containing the squared norms of the Gram-Schmidt vectors $(b_i^*)$ attached to the output basis $(b_i)$, $b_i^* = b_i + \sum_{j < i} \mu_{i,j} b_j^*$. \fun{GEN}{lllintpartial_inplace}{GEN x} given a \kbd{ZM} $x$ of maximal rank, returns a partially reduced basis $(b_i)$ for the space spanned by the columns of $x$: $|b_i \pm b_j| \geq |b_i|$ for any two distinct basis vectors $b_i$, $b_j$. This is faster than the LLL algorithm, but produces much larger bases. \fun{GEN}{lllintpartial}{GEN x} as \kbd{lllintpartial\_inplace}, but returns the base change matrix $U$ from the canonical basis to the $b_i$, i.e. $x U$ is the output of \kbd{lllintpartial\_inplace}. \fun{GEN}{RM_round_maxrank}{GEN G} given a matrix $G$ with real floating point entries and independent columns, let $G_e$ be the rescaled matrix $2^e G$ rounded to nearest integers, for $e \geq 0$. Finds a small $e$ such that the rank of $G_e$ is equal to the rank of $G$ (its number of columns) and return $G_e$. This is useful as a preconditioning step to speed up LLL reductions, see \tet{nf_get_Gtwist}. Suitable for \kbd{gerepileupto}, but does not collect garbage. \subsec{Linear dependencies} The following functions underly the \kbd{lindep} GP function: \fun{GEN}{lindep}{GEN v} real/complex entries, guess that about only the 80\% leading bits of the input are correct. \fun{GEN}{lindep_bit}{GEN v, long b} real/complex entries, explicit form of the above: multiply the input by $2^b$ and round to nearest integer before looking for a linear dependency. Truncating dubious bits allows to find better relations. \fun{GEN}{lindepfull_bit}{GEN v, long b} as \kbd{lindep\_bit} but return a matrix $M$ with $n = \#v$ columns and $r$ rows, with $r = n+1$ (if $v$ is real) or $n+2$ (general case) which is an LLL-reduced basis of the lattice formed by concatenating vertically an identity matrix and the floor of $2^b \kbd{real}(v)$ and $2^b \kbd{imag}(v)$ if $r = n+2$. The first $n$ rows of $M$ potentially correspond to relations: whenever the last $r-n$ entries of a column are small. The function \kbd{lindep\_bit} essentially returns the first column of $M$ truncated to $n$ components. \fun{GEN}{lindep_padic}{GEN v} $p$-adic entries. \fun{GEN}{lindep_Xadic}{GEN v} polynomial entries. \fun{GEN}{deplin}{GEN v} returns a non-zero kernel vector for a \typ{MAT} input. Deprecated routine: \fun{GEN}{lindep2}{GEN x, long dig} analogous to \kbd{lindep\_bit}, with \kbd{dig} counting decimal digits. \subsec{Reduction modulo matrices} \fun{GEN}{ZC_hnfremdiv}{GEN x, GEN y, GEN *Q} assuming $y$ is an invertible \kbd{ZM} in HNF and $x$ is a \kbd{ZC}, returns the \kbd{ZC} $R$ equal to $x$ mod $y$ (whose $i$-th entry belongs to $[-y_{i,i}/2, y_{i,i}/2[$). Stack clean \emph{unless} $x$ is already reduced (in which case, returns $x$ itself, not a copy). If $Q$ is not \kbd{NULL}, set it to the \kbd{ZC} such that $x = yQ + R$. \fun{GEN}{ZM_hnfdivrem}{GEN x, GEN y, GEN *Q} reduce each column of the \kbd{ZM} $x$ using \kbd{ZC\_hnfremdiv}. If $Q$ is not \kbd{NULL}, set it to the \kbd{ZM} such that $x = yQ + R$. \fun{GEN}{ZC_hnfrem}{GEN x, GEN y} alias for \kbd{ZC\_hnfremdiv(x,y,NULL)}. \fun{GEN}{ZM_hnfrem}{GEN x, GEN y} alias for \kbd{ZM\_hnfremdiv(x,y,NULL)}. \fun{GEN}{ZC_reducemodmatrix}{GEN v, GEN y} Let $y$ be a ZM, not necessarily square, which is assumed to be LLL-reduced (otherwise, very poor reduction is expected). Size-reduces the ZC $v$ modulo the $\Z$-module $Y$ spanned by $y$ : if the columns of $y$ are denoted by $(y_1,\dots, y_{n-1})$, we return $y_n \equiv v$ modulo $Y$, such that the Gram-Schmidt coefficients $\mu_{n,j}$ are less than $1/2$ in absolute value for all $j < n$. In short, $y_n$ is almost orthogonal to $Y$. \fun{GEN}{ZM_reducemodmatrix}{GEN v, GEN y} Let $y$ be as in \tet{ZC_reducemodmatrix}, and $v$ be a ZM. This returns a matrix $v$ which is congruent to $v$ modulo the $\Z$-module spanned by $y$, whose columns are size-reduced. This is faster than repeatedly calling \tet{ZC_reducemodmatrix} on the columns since most of the Gram-Schmidt coefficients can be reused. \fun{GEN}{ZC_reducemodlll}{GEN v, GEN y} Let $y$ be an arbitrary ZM, LLL-reduce it then call \tet{ZC_reducemodmatrix}. \fun{GEN}{ZM_reducemodlll}{GEN v, GEN y} Let $y$ be an arbitrary ZM, LLL-reduce it then call \tet{ZM_reducemodmatrix}. Besides the above functions, which were specific to integral input, we also have: \fun{GEN}{reducemodinvertible}{GEN x, GEN y} $y$ is an invertible matrix and $x$ a \typ{COL} or \typ{MAT} of compatible dimension. Returns $x - y\lfloor y^{-1}x \rceil$, which has small entries and differs from $x$ by an integral linear combination of the columns of $y$. Suitable for \kbd{gerepileupto}, but does not collect garbage. \fun{GEN}{closemodinvertible}{GEN x, GEN y} returns $x - \kbd{reducemodinvertible}(x,y)$, i.e. an integral linear combination of the columns of $y$, which is close to $x$. \fun{GEN}{reducemodlll}{GEN x,GEN y} LLL-reduce the non-singular \kbd{ZM} $y$ and call \kbd{reducemodinvertible} to find a small representative of $x$ mod $y \Z^n$. Suitable for \kbd{gerepileupto}, but does not collect garbage. \section{Finite abelian groups and characters} \subsec{Abstract groups} A finite abelian group $G$ in GP format is given by its Smith Normal Form as a pair $[h,d]$ or triple $[h,d,g]$. Here $h$ is the cardinality of $G$, $(d_i)$ is the vector of elementary divisors, and $(g_i)$ is a vector of generators. In short, $G = \oplus_{i\leq n} (\Z/d_i\Z) g_i$, with $d_n \mid \dots \mid d_2 \mid d_1$ and $\prod d_i = h$. Let $e(x) := \exp(2i\pi x)$. For ease of exposition, we restrict to complex-valued characters, but everything applies to more general fields $K$ where $e$ denotes a morphism $(\Q,+) \to (K^*,\times)$ such that $e(a/b)$ denotes a $b$-th root of unity. A \tev{character} on the abelian group $\oplus (\Z/d_j\Z) g_j$ is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = e(\sum a_j n_j / d_j)$. \fun{GEN}{cyc_normalize}{GEN d} shallow function. Given a vector $(d_i)_{i \leq n}$ of elementary divisors for a finite group (no $d_i$ vanish), returns the vector $D = [1]$ if $n = 0$ (trivial group) and $[d_1, d_1/d_2, \dots, d_1/d_n]$ otherwise. This will allow to define characters as $\chi(\prod g_j^{x_j}) = e(\sum_j x_j a_j D_j / D_1)$, see \tet{char_normalize}. \fun{GEN}{char_normalize}{GEN chi, GEN ncyc} shallow function. Given a character \kbd{chi} $ = (a_j)$ and \var{ncyc} from \kbd{cyc\_normalize} above, returns the normalized representation $[d, (n_j)]$, such that $\chi(\prod g_j^{x_j}) = \zeta_d^{\sum_j n_j x_j}$, where $\zeta_d = e(1/d)$ and $d$ is \emph{minimal}. In particular, $d$ is the order of \kbd{chi}. Shallow function. \fun{GEN}{char_simplify}{GEN D, GEN N} given a quasi-normalized character $[D, (N_j)]$ such that $\chi(\prod g_j^{x_j}) = \zeta_D^{\sum_j N_j x_j}$, but where we only assume that $D$ is a multiple of the character order, return a normalized character $[d, (n_j)]$ with $d$ \emph{minimal}. Shallow function. \fun{GEN}{char_denormalize}{GEN cyc, GEN d, GEN n} given a normalized representation $[d, n]$ (where $d$ need not be minimal) of a character on the abelian group with abelian divisors \kbd{cyc}, return the attached character (where the image of each generator $g_i$ is given in terms of roots of unity of different orders $\kbd{cyc}[i]$). \fun{GEN}{charconj}{GEN cyc, GEN chi} return the complex conjugate of \kbd{chi}. \fun{GEN}{charmul}{GEN cyc, GEN a, GEN b} return the product character $a\times b$. \fun{GEN}{chardiv}{GEN cyc, GEN a, GEN b} returns the character $a / b = a \times \overline{b}$. \fun{int}{char_check}{GEN cyc, GEN chi} return $1$ if \kbd{chi} is a character compatible with cyclic factors \kbd{cyc}, and $0$ otherwise. \fun{GEN}{cyc2elts}{GEN d} given a \typ{VEC} $d = (d_1,\dots,d_n)$ of non-negative integers, return the vector of all \typ{VECSMALL}s of length $n$ whose $i$-th entry lies in $[0,d_i]$. Assumes that the product of the $d_i$ fits in a \kbd{long}. \subsec{Dirichlet characters} The functions in this section are specific to characters on $(\Z/N\Z)^*$. The argument $G$ is a special \kbd{bid} structure as returned by \kbd{znstar0(N, nf\_INIT)}. In this case, there are additional ways to input character via Conrey's representation. The character \kbd{chi} is either a \typ{INT} (Conrey label), a \typ{COL} (a Conrey logarithm) or a \typ{VEC} (generic character on \kbd{bid.gen} as explained in the previous subsection). The following low-level functions are called by GP's generic character functions. \fun{int}{zncharcheck}{GEN G, GEN chi} return $1$ if \kbd{chi} is a valid character and $0$ otherwise. \fun{GEN}{zncharconj}{GEN G, GEN chi} as \kbd{charconj}. \fun{GEN}{znchardiv}{GEN G, GEN a, GEN b} as \kbd{chardiv}. \fun{GEN}{zncharker}{GEN G, GEN chi} as \kbd{charker}. \fun{GEN}{znchareval}{GEN G, GEN chi, GEN n, GEN z} as \kbd{chareval}. \fun{GEN}{zncharmul}{GEN G, GEN a, GEN b} as \kbd{charmul}. \fun{GEN}{zncharpow}{GEN G, GEN a, GEN n} as \kbd{charpow}. \fun{GEN}{zncharorder}{GEN G, GEN chi} as \kbd{charorder}. The following functions handle characters in Conrey notation (attached to Conrey generators, not \kbd{G.gen}): \fun{int}{znconrey_check}{GEN cyc, GEN chi} return $1$ if \kbd{chi} is a valid Conrey logarithm and $0$ otherwise. \fun{GEN}{znconrey_normalized}{GEN G, GEN chi} return normalized character attached to \kbd{chi}, as in \kbd{char\_normalize} but on Conrey generators. \fun{GEN}{znconreyfromchar}{GEN G, GEN chi} return Conrey logarithm attached to the generic (\typ{VEC}, on \kbd{G.gen}) \fun{GEN}{znconreyfromchar_normalized}{GEN G, GEN chi} return normalized Conrey character attached to the generic (\typ{VEC}, on \kbd{G.gen}) character \kbd{chi}. \fun{GEN}{znconreylog_normalize}{GEN G, GEN m} given a Conrey logarithm $m$ (\typ{COL}), return the attached normalized Conrey character, as in \kbd{char\_normalize} but on Conrey generators. \fun{GEN}{znchar_quad}{GEN G, GEN D} given a non-zero \typ{INT} $D$ congruent to $0,1$ mod $4$, return $(D/.)$ as a character modulo $N$, given by a Conrey logarithm (\typ{COL}). Assume that $|D|$ divides $N$. \fun{GEN}{Zideallog}{GEN G, GEN x} return the \kbd{znconreylog} of $x$ expressed on \kbd{G.gen}, i.e. the ordinary discrete logarithm from \kbd{ideallog}. \fun{GEN}{ncharvecexpo}{GEN G, GEN nchi} given \kbd{nchi} $= [d,n]$ a quasi-normalized character ($d$ may be a multiple of the character order), i.e. $\chi(g_i) = e(n[i]/d)$ for all Conrey or SNF generators $g_i$ (as usual, we use SNF generators if $n$ is a \typ{VEC} and the Conrey generators otherwise). Return a \typ{VECSMALL} $v$ such that $v[i] = -1$ if $(i,N) > 1$ else $\chi(i) = e(v[i]/d)$, $1 \leq i \leq N$. \section{Central simple algebras} \subsec{Initialization} Low-level routines underlying \kbd{alginit}. \fun{GEN}{alg_csa_table}{GEN nf, GEN mt, long v, long maxord} algebra defined by a multiplication table. \fun{GEN}{alg_cyclic}{GEN rnf, GEN aut, GEN b, long maxord} cyclic algebra~$(L/K,\sigma,b)$. \fun{GEN}{alg_hasse}{GEN nf, long d, GEN hi, GEN hf, long v, long maxord} algebra defined by local Hasse invariants. \fun{GEN}{alg_hilbert}{GEN nf, GEN a, GEN b, long v, long maxord} quaternion algebra. \fun{GEN}{alg_matrix}{GEN nf, long n, long v, GEN L, long maxord} matrix algebra. \fun{GEN}{alg_complete}{GEN rnf, GEN aut, GEN hi, GEN hf, long maxord} cyclic algebra~$(L/K,\sigma,b)$ with~$b$ computed from the Hasse invariants. \subsec{Type checks} \fun{void}{checkalg}{GEN a} raise an exception if $a$ was not initialized by \tet{alginit}. \fun{void}{checklat}{GEN al, GEN lat} raise an exception if \kbd{lat} is not a valid full lattice in the algebra~\kbd{al}. \fun{void}{checkhasse}{GEN nf, GEN hi, GEN hf, long n} raise an exception if~$(\kbd{hi},\kbd{hf})$ do not describe valid Hasse invariants of a central simple algebra of degree~\kbd{n} over~\kbd{nf}. \fun{long}{alg_type}{GEN al} internal function called by \tet{algtype}: assume \kbd{al} was created by \tet{alginit} (thereby saving a call to \kbd{checkalg}). Return values are symbolic rather than numeric: \item \kbd{al\_NULL}: not a valid algebra. \item \kbd{al\_TABLE}: table algebra output by \kbd{algtableinit}. \item \kbd{al\_CSA}: central simple algebra output by \kbd{alginit} and represented by a multiplication table over its center. \item \kbd{al\_CYCLIC}: central simple algebra output by \kbd{alginit} and represented by a cyclic algebra. \fun{long}{alg_model}{GEN al, GEN x} given an element $x$ in algebra \var{al}, check for inconsistencies (raise a type error) and return the representation model used for $x$: \item \kbd{al\_ALGEBRAIC}: \kbd{basistoalg} form, algebraic representation. \item \kbd{al\_BASIS}: \kbd{algtobasis} form, column vector on the integral basis. \item \kbd{al\_MATRIX}: matrix with coefficients in an algebra. \item \kbd{al\_TRIVIAL}: trivial algebra of degree $1$; can be understood as both basis or algebraic form (since $e_1 = 1$). \subsec{Shallow accessors} All these routines assume their argument was initialized by \tet{alginit} and provide minor speedups compared to the GP equivalent. The routines returning a \kbd{GEN} are shallow. \fun{long}{alg_get_absdim}{GEN al} low-level version of \kbd{algabsdim}. \fun{long}{alg_get_dim}{GEN al} low-level version of \kbd{algdim}. \fun{long}{alg_get_degree}{GEN al} low-level version of \kbd{algdegree}. \fun{GEN}{alg_get_aut}{GEN al} low-level version of \kbd{algaut}. \fun{GEN}{alg_get_auts}{GEN al}, given a cyclic algebra $\var{al} = (L/K,\sigma,b)$ of degree $n$, returns the vector of $\sigma^i$, $1 \leq i < n$. \fun{GEN}{alg_get_b}{GEN al} low-level version of \kbd{algb}. \fun{GEN}{alg_get_basis}{GEN al} low-level version of \kbd{albasis}. \fun{GEN}{alg_get_center}{GEN al} low-level version of \kbd{algcenter}. \fun{GEN}{alg_get_char}{GEN al} low-level version of \kbd{algchar}. \fun{GEN}{alg_get_hasse_f}{GEN al} low-level version of \kbd{alghassef}. \fun{GEN}{alg_get_hasse_i}{GEN al} low-level version of \kbd{alghassei}. \fun{GEN}{alg_get_invbasis}{GEN al} low-level version of \kbd{alginvbasis}. \fun{GEN}{alg_get_multable}{GEN al} low-level version of \kbd{algmultable}. \fun{GEN}{alg_get_relmultable}{GEN al} low-level version of \kbd{algrelmultable}. \fun{GEN}{alg_get_splittingfield}{GEN al} low-level version of \kbd{algsplittingfield}. \fun{GEN}{alg_get_abssplitting}{GEN al} returns the absolute \var{nf} structure attached to the \var{rnf} returned by \kbd{algsplittingfield}. \fun{GEN}{alg_get_splitpol}{GEN al} returns the relative polynomial defining the \var{rnf} returned by \kbd{algsplittingfield}. \fun{GEN}{alg_get_splittingdata}{GEN al} low-level version of \kbd{algsplittingdata}. \fun{GEN}{alg_get_splittingbasis}{GEN al} the matrix \var{Lbas} from \kbd{algsplittingdata} \fun{GEN}{alg_get_splittingbasisinv}{GEN al} the matrix \var{Lbasinv} from \kbd{algsplittingdata}. \fun{GEN}{alg_get_tracebasis}{GEN al} returns the traces of the basis elements; used by \kbd{algtrace}. \fun{GEN}{alglat_get_primbasis}{GEN lat} from the description of \kbd{lat} as~$\lambda L$ with~$L\subset{\cal O}_0$ and~$\lambda\in\Q$, returns a basis of~$L$. \fun{GEN}{alglat_get_scalar}{GEN lat} from the description of \kbd{lat} as~$\lambda L$ with~$L\subset{\cal O}_0$ and~$\lambda\in\Q$, returns~$\lambda$. \subsec{Other low-level functions} \fun{GEN}{conjclasses_algcenter}{GEN cc, GEN p} low-level function underlying \kbd{alggroupcenter}, where \kbd{cc} is the output of \kbd{groupelts\_to\_conjclasses}, and $p$ is either \kbd{NULL} or a prime number. Not stack clean. \fun{GEN}{algsimpledec_ss}{GEN al, long maps} assuming that~\kbd{al} is semisimple, returns the second component of~\kbd{algsimpledec(al,maps)}. \newpage pari-2.11.2/doc/usersch7.tex0000644000175000017500000011213513326135265014221 0ustar billbill% Copyright (c) 2000 The PARI Group % % This file is part of the PARI/GP documentation % % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License \chapter{Elliptic curves and arithmetic geometry} This chapter is quite short, but is added as a placeholder, since we expect the library to expand in that direction. \section{Elliptic curves} Elliptic curves are represented in the Weierstrass model $$ (E): y^2z + a_1xyz + a_3 yz = x^3 + a_2 x^2z + a_4 xz^2 + a_6z^3, $$ by the $5$-tuple $[a_1,a_2,a_3,a_4,a_6]$. Points in the projective plane are represented as follows: the point at infinity $(0:1:0)$ is coded as \kbd{[0]}, a finite point $(x:y:1)$ outside the projective line at infinity $z = 0$ is coded as $[x,y]$. Note that other points at infinity than $(0:1:0)$ cannot be represented; this is harmless, since they do not belong to any of the elliptic curves $E$ above. \emph{Points on the curve} are just projective points as described above, they are not tied to a curve in any way: the same point may be used in conjunction with different curves, provided it satisfies their equations (if it does not, the result is usually undefined). In particular, the point at infinity belongs to all elliptic curves. As with \tet{factor} for polynomial factorization, the $5$-tuple $[a_1,a_2,a_3,a_4,a_6]$ implicitly defines a base ring over which the curve is defined. Point coordinates must be operation-compatible with this base ring (\kbd{gadd}, \kbd{gmul}, \kbd{gdiv} involving them should not give errors). \subsec{Types of elliptic curves} We call a $5$-tuble as above an \kbd{ell5}; most functions require an \kbd{ell} structure, as returned by \tet{ellinit}, which contains additional data (usually dynamically computed as needed), depending on the base field. \fun{GEN}{ellinit}{GEN E, GEN D, long prec}, returns an \tet{ell} structure, attached to the elliptic curve $E$ : either an \kbd{ell5}, a pair $[a_4,a_6]$ or a \typ{STR} in Cremona's notation, e.g. \kbd{"11a1"}. The optional $D$ (\kbd{NULL} to omit) describes the domain over which the curve is defined. \subsec{Type checking} \fun{void}{checkell}{GEN e} raise an error unless $e$ is an \var{ell}. \fun{int}{checkell_i}{GEN e} return $1$ if $e$ is an \var{ell} and $0$ otherwise. \fun{void}{checkell5}{GEN e} raise an error unless $e$ is an \var{ell} or an \var{ell5}. \fun{void}{checkellpt}{GEN z} raise an error unless $z$ is a point (either finite or at infinity). \fun{long}{ell_get_type}{GEN e} returns the domain type over which the curve is defined, one of \tet{t_ELL_Q} the field of rational numbers; \tet{t_ELL_NF} a number field; \tet{t_ELL_Qp} the field of $p$-adic numbers, for some prime $p$; \tet{t_ELL_Fp} a prime finite field, base field elements are represented as \kbd{Fp}, i.e.~a \typ{INT} reduced modulo~$p$; \tet{t_ELL_Fq} a non-prime finite field (a prime finite field can also be represented by this subtype, but this is inefficient), base field elements are represented as \typ{FFELT}; \tet{t_ELL_Rg} none of the above. \fun{void}{checkell_Fq}{GEN e} checks whether $e$ is an \kbd{ell}, defined over a finite field (either prime or non-prime). Otherwise the function raises a \tet{pari_err_TYPE} exception. \fun{void}{checkell_Q}{GEN e} checks whether $e$ is an \kbd{ell}, defined over $\Q$. Otherwise the function raises a \tet{pari_err_TYPE} exception. \fun{void}{checkell_Qp}{GEN e} checks whether $e$ is an \kbd{ell}, defined over some $\Q_p$. Otherwise the function raises a \tet{pari_err_TYPE} exception. \fun{void}{checkellisog}{GEN v} raise an error unless $v$ is an isogeny, from \tet{ellisogeny}. \subsec{Extracting info from an \kbd{ell} structure} These functions expect an \kbd{ell} argument. If the required data is not part of the structure, it is computed then inserted, and the new value is returned. \subsubsec{All domains} \fun{GEN}{ell_get_a1}{GEN e} \fun{GEN}{ell_get_a2}{GEN e} \fun{GEN}{ell_get_a3}{GEN e} \fun{GEN}{ell_get_a4}{GEN e} \fun{GEN}{ell_get_a6}{GEN e} \fun{GEN}{ell_get_b2}{GEN e} \fun{GEN}{ell_get_b4}{GEN e} \fun{GEN}{ell_get_b6}{GEN e} \fun{GEN}{ell_get_b8}{GEN e} \fun{GEN}{ell_get_c4}{GEN e} \fun{GEN}{ell_get_c6}{GEN e} \fun{GEN}{ell_get_disc}{GEN e} \fun{GEN}{ell_get_j}{GEN e} \subsubsec{Curves over $\Q$} \fun{GEN}{ellQ_get_N}{GEN e} returns the curve conductor \fun{void}{ellQ_get_Nfa}{GEN e, GEN *N, GEN *faN} sets $N$ to the conductor and \kbd{faN} to its factorization \fun{int}{ell_is_integral}{GEN e} return $1$ if $e$ is given by an integral model, and $0$ otherwise. \fun{long}{ellQ_get_CM}{GEN e} if $e$ has CM by a principal imaginary quadratic order, return its discriminant. Else return $0$. \fun{long}{ellap_CM_fast}{GEN e, ulong p, long CM} assuming that $p$ does not divide the discriminant of $E$ (in particular, $E$ has good reduction at $p$), and that \kbd{CM} is as given by \tet{ellQ_get_CM}, return the trace of Frobenius for $E/\F_p$. This is meant to quickly compute lots of $a_p$, esp.~when $e$ has CM by a principal quadratic order. \fun{long}{ellrootno_global}{GEN e} returns the global root number $c\in \{-1,1\}$. \fun{GEN}{ellheightoo}{GEN E, GEN P, long prec} given $P = [x,y]$ an affine point on $E$, return $$ \lambda_\infty(P) + \dfrac{1}{12}\log|\disc E| = \dfrac{1}{2} \text{real}(z\eta(z)) - \log |\sigma(E,z)| \in \R, $$ where $\lambda_\infty(P)$ is the canonical local height at infinity and $z$ is \kbd{ellpointtoz}$(E,P)$. This is computed using Mestre's (quadratically convergent) AGM algorithm. \fun{long}{ellorder_Q}{GEN E, GEN P} return the order of $P\in E(\Q)$, using the impossible value $0$ for a point of infinite order. Ultimately called by the generic \tet{ellorder} function. \fun{GEN}{point_to_a4a6}{GEN E, GEN P, GEN p, GEN *a4} given $E/\Q$, $p\neq 2,3$ not dividing the discriminant of $E$ and $P\in E(\Q)$ outside the kernel of reduction, return the image of $P$ on the short Weierstrass model $y^2 = x^3 + a_4x + a_6$ isomorphic to the reduction $E_p$ of $E$ at $p$. Also set \kbd{a4} to the $a_4$ coefficient in the above model. This function allows quick computations modulo varying primes $p$, avoiding the overhead of \kbd{ellinit}$(E,p)$, followed by a change of coordinates. It produces data suitable for \kbd{FpE} routines. \fun{GEN}{point_to_a4a6_Fl}{GEN E, GEN P, ulong p, ulong *pa4} as \tet{point_to_a4a6}, returning a \kbd{Fle}. \fun{GEN}{elldatagenerators}{GEN E} returns generators for $E(\Q)$ extracted from Cremona's table. \fun{GEN}{ellanal_globalred}{GEN e, GEN *v} takes an \var{ell} over $\Q$ and returns a global minimal model $E$ (in \kbd{ellinit} form, over $\Q$) for $e$ suitable for analytic computations related to the curve $L$ series: it contains \kbd{ellglobalred} data, as well as global and local root numbers. If \kbd{v} is not \kbd{NULL}, set \kbd{*v} to the needed change of variable: \kbd{NULL} if $e$ was already the standard minimal model, such that $E = \kbd{ellchangecurve(e,v)}$ otherwise. Compared to the direct use of \kbd{ellchangecurve} followed by \kbd{ellrootno}, this function avoids converting unneeded dynamic data and avoids potential memory leaks (the changed curve would have had to be deleted using \tet{obj_free}). The original curve $e$ is updated as well with the same information. \fun{GEN}{ellanal_globalred_all}{GEN e, GEN *v, GEN *N, GEN *tam} as \tet{ellanal_globalred}; further set \kbd{*N} to the curve conductor and \kbd{*tam} to the product of the local Tamagawa numbers, including the factor at infinity (multiply by the number of connected components of $e(\R)$). \fun{GEN}{ellintegralmodel}{GEN e, GEN *pv} return an integral model for $e$ (in \kbd{ellinit} form, over $\Q$). Set $v = \kbd{NULL}$ (already integral, we returned $e$ itself), else to the variable change $[u,0,0,0]$ making $e$ integral. We have $u = 1/t$, $t > 1$. \fun{GEN}{ellintegralmodel_i}{GEN e, GEN *pv} shallow version of \kbd{ellintegralmodel}. \misctitle{Deprecated routines} \fun{GEN}{elltors0}{GEN e, long flag} this function is deprecated; use \tet{elltors} \subsubsec{Curves over a number field \var{nf}} Let $K$ be the number field over which $E$ is defined, given by a \var{nf} or \var{bnf} structure. \fun{GEN}{ellnf_get_nf}{GEN E} returns the underlying \kbd{nf}. \fun{GEN}{ellnf_get_bnf}{GEN x} returns \kbd{NULL} if $K$ does not contain a \var{bnf} structure, else return the \var{bnf}. \fun{GEN}{ellnf_vecarea}{GEN E} returns the vector of the period lattices areas of all the complex embeddings of \kbd{E} in the same order as \kbd{E.nf.roots}. \fun{GEN}{ellnf_veceta}{GEN E} returns the vector of the quasi-periods of all the complex embeddings of \kbd{E} in the same order as \kbd{E.nf.roots}. \fun{GEN}{ellnf_vecomega}{GEN E} returns the vector of the periods of all the complex embeddings of \kbd{E} in the same order as \kbd{E.nf.roots}. \subsubsec{Curves over $\Q_p$} \fun{GEN}{ellQp_get_p}{GEN E} returns $p$ \fun{long}{ellQp_get_prec}{GEN E} returns the default $p$-adic accuracy to which we must compute approximate results attached to $E$. \fun{GEN}{ellQp_get_zero}{GEN x} returns $O(p^n)$, where $n$ is the default $p$-adic accuracy as above. The following functions are only defined when $E$ has multiplicative reduction (Tate curves): \fun{GEN}{ellQp_Tate_uniformization}{GEN E, long prec} returns a \typ{VEC} containing $u^2, u, q, [a,b]$, at $p$-adic precision \kbd{prec}. \fun{GEN}{ellQp_u}{GEN E, long prec} returns $u$. \fun{GEN}{ellQp_u2}{GEN E, long prec} returns $u^2$. \fun{GEN}{ellQp_q}{GEN E, long prec} returns the Tate period $q$. \fun{GEN}{ellQp_ab}{GEN E, long prec} returns $[a,b]$. \fun{GEN}{ellQp_AGM}{GEN E, long prec} returns $[a,b,R,v]$, where $v$ is an integer, $a, b, R$ are vectors describing the sequence of $2$-isogenous curves $E_i: y^2 = x(x+A_i)(x+A_i-B_i)$, $i \geq 1$ converging to the singular curve $E_\infty: y^2 = x^2(x+M)$. We have $a[i] = A[i] p^v$, $b[i] = B[i] p^v$, $R[i] = A_i - B_i$. These are used in \kbd{ellpointtoz} and \kbd{ellztopoint}. \fun{GEN}{ellQp_L}{GEN E, long prec} returns the ${\cal L}$-invariant $L$. \fun{GEN}{ellQp_root}{GEN E, long prec} returns $e_1$. \subsubsec{Curves over a finite field $\F_q$} \fun{GEN}{ellff_get_p}{GEN E} returns the characteristic \fun{GEN}{ellff_get_field}{GEN E} returns $p$ if $\F_q$ is a prime field, and a \typ{FFELT} belonging to $\F_q$ otherwise. \fun{GEN}{ellff_get_card}{GEN E} returns $\#E(\F_q)$ \fun{GEN}{ellff_get_gens}{GEN E} returns a minimal set of generators for $E(\F_q)$. \fun{GEN}{ellff_get_group}{GEN E} returns \kbd{ellgroup}$(E)$. \fun{GEN}{ellff_get_m}{GEN E} returns the \typ{INT} $m$ as needed by the \kbd{gen\_ellgroup} function (the order of the pairing required to verify a generating set). \fun{GEN}{ellff_get_o}{GEN E} returns $[d, \kbd{factor{d}}]$, where $d$ is the exponent of $E(\F_q)$. \fun{GEN}{ellff_get_D}{GEN E} returns the elementary divisors for $E(\F_q)$ in a form suitable for \tet{gen_ellgens}: either $[d_1]$ or $[d_1,d_2]$, where $d_1$ is in \tet{elff_get_o} format. $[d, \kbd{factor{d}}]$, where $d$ is the exponent of $E(\F_q)$. \fun{GEN}{ellff_get_a4a6}{GEN E} returns a canonical ``short model'' for $E$, and the corresponding change of variable $[u,r,s,t]$. For $p\neq 2,3$, this is $[A_4,A_6,[u,r,s,t]]$, corresponding to $y^2 = x^3 + A_4x + A_6$, where $A_4 = -27c_4$, $A_6 = -54c_6$, $[u,r,s,t] = [6, 3b_2,3a_1,108a_3]$. \item If $p = 3$ and the curve is ordinary ($b_2\neq 0$), this is $[[b_2], A_6, [1,v,-a_1,-a_3]]$, corresponding to $$y^2 = x^3 + b_2 x^2 + A_6,$$ where $v = b_4/b_2$, $A_6 = b_6 - v(b_4+v^2)$. \item If $p = 3$ and the curve is supersingular ($b_2 = 0$), this is $[-b_4, b_6, [1,0,-a_1,-a_3]]$, corresponding to $$y^2 = x^3 + 2b_4 x + b_6.$$ \item If $p = 2$ and the curve is ordinary ($a_1 \neq 0$), return $[A_2,A_6,[a_1^{-1}, da_1^{-2}, 0, (a_4+d^2)a_1^{-1}]]$, corresponding to $$ y^2 + xy = x^3 + A_2 x^2 + A_6,$$ where $d = a_3/a_1$, $a_1^2 A_2 = (a_2 + d)$ and $$ a_1^6 A_6 = d^3 + a_2 d^2 + a_4 d + a_6 + (a_4^2 + d^4)a_1^{-2}.$$ \item If $p = 2$ and the curve is supersingular ($a_1 = 0$, $a_3\neq 0$), return $[[a_3, A_4, 1/a_3], A_6, [1,a_2,0,0]]$, corresponding to $$ y^2 + a_3 y = x^3 + A_4 x + A_6,$$ where $A_4 = a_2^2 + a_4$, $ A_6 = a_2a_4 + a_6$. The value $1/a_3$ is included in the vector since it is frequently needed in computations. \subsubsec{Curves over $\C$} (This includes curves over $\Q$!) \fun{long}{ellR_get_prec}{GEN E} return the default accuracy to which we must compute approximate results attached to $E$. \fun{GEN}{ellR_ab}{GEN E, long prec} return $[a,b]$ \fun{GEN}{ellR_omega}{GEN x, long prec} return periods $[\omega_1,\omega_2]$. \fun{GEN}{ellR_eta}{GEN E, long prec} return quasi-periods $[\eta_1,\eta_2]$. \fun{GEN}{ellR_area}{GEN x, long prec} return the area $(\Im(\omega_1\*\overline{\omega_2}))$. \fun{GEN}{ellR_roots}{GEN E, long prec} return $[e_1,e_2,e_3]$. If $E$ is defined over $\R$, then $e_1$ is real. If furthermore $\disc E > 0$, then $e_1 > e_2 > e_3$. \fun{long}{ellR_get_sign}{GEN E} if $E$ is defined over $\R$ returns the signe of its discriminant, otherwise return $0$. \subsec{Points} \fun{int}{ell_is_inf}{GEN z} tests whether the point $z$ is the point at infinity. \fun{GEN}{ellinf}{} returns the point at infinity \kbd{[0]}. \subsec{Change of variables} \fun{GEN}{ellchangeinvert}{GEN w} given a change of variables $w = [u,r,s,t]$, returns the inverse change of variables $w'$, such that if $E' = \kbd{ellchangecurve(E, w)}$, then $E = \kbd{ellchangecurve}(E, w')$. \subsec{Generic helper functions} The naming scheme assumes an affine equation $F(x,y) = f(x) - (y^2 + h(x)y) = 0$ in standard Weierstrass form: $f = x^3+a_2x^2+a_4x+a_6$, $h = a_1x + a_3$. Unless mentionned otherwise, these routine assume that all arguments are compatible with generic functions of \kbd{gadd} or \kbd{gmul} type. In particular they do not handle elements in number field in \kbd{nfalgtobasis} format. \fun{GEN}{ellbasechar}{GEN E} returns the characteristic of the base ring over which $E$ is defined. \fun{GEN}{ec_bmodel}{GEN E} returns the polynomial $4x^3 + b_2x^2 + 2b_4x + b_6$. \fun{GEN}{ec_f_evalx}{GEN E, GEN x} returns $f(x)$. \fun{GEN}{ec_h_evalx}{GEN E, GEN x} returns $h(x)$. \fun{GEN}{ec_dFdx_evalQ}{GEN E, GEN Q} returns $3x^2 + 2a_2x + a_4 -a_1y$, where $Q = [x,y]$. \fun{GEN}{ec_dFdy_evalQ}{GEN E, GEN Q} returns $-(2y + a_1 x + a_3)$, where $Q = [x,y]$. \fun{GEN}{ec_dmFdy_evalQ}{GEN e, GEN Q} returns $2y + a_1 x + a_3$, where $Q = [x,y]$. \fun{GEN}{ec_2divpol_evalx}{GEN E, GEN x} returns $4x^3 + b_2\*x^2 + 2\*b_4x + b_6$. This function supports inputs in \kbd{nfalgtobasis} format. \fun{GEN}{ec_half_deriv_2divpol_evalx}{GEN E, GEN x} returns $6\*x^2 + b_2\*x + b_4$. \fun{GEN}{ec_3divpol_evalx}{GEN E, GEN x} returns $3\*x^4 + b_2\*x^2 + 3\*b_4\*x^2 + 3\*b_6\*x + b_8$. \subsec{Functions to handle elliptic curves over finite fields} \subsubsec{Tolerant routines} \fun{GEN}{ellap}{GEN E, GEN p} given a prime number $p$ and an elliptic curve defined over $\Q$ or $\Q_p$ (assumed integral and minimal at $p$), computes the trace of Frobenius $a_p = p+1 - \#E(\F_p)$. If $E$ is defined over a non-prime finite field $\F_q$, ignore $p$ and return $q+1 - \#E(\F_q)$. When $p$ is implied ($E$ defined over $\Q_p$ or a finite field), $p$ can be omitted (set to \kbd{NULL}). \subsubsec{Curves defined a non-prime finite field} In this subsection, we assume that \tet{ell_get_type}$(E)$ is \tet{t_ELL_Fq}. (As noted above, a curve defined over $\Z/p\Z$ can be represented as a \tet{t_ELL_Fq}.) \fun{GEN}{FF_elltwist}{GEN E} returns the coefficients $[a_1,a_2,a_3,a_4,a_6]$ of the quadratic twist of $E$. \fun{GEN}{FF_ellmul}{GEN E, GEN P, GEN n} returns $[n]P$ where $n$ is an integer and $P$ is a point on the curve $E$. \fun{GEN}{FF_ellrandom}{GEN E} returns a random point in $E(\F_q)$. This function never returns the point at infinity, unless this is the only point on the curve. \fun{GEN}{FF_ellorder}{GEN E, GEN P, GEN o} returns the order of the point $P$, where $o$ is a multiple of the order of $P$, or its factorization. \fun{GEN}{FF_ellcard}{GEN E} returns $\#E(\F_q)$. \fun{GEN}{FF_ellcard_SEA}{GEN E, long s} This function returns $\#E(\F_q)$, using the Schoof-Elkies-Atkin algorithm. Assume $p\neq 2,3$. The parameter $s$ has the same meaning as in \kbd{Fp\_ellcard\_SEA}. \fun{GEN}{FF_ellgens}{GEN E} returns the generators of the group $E(\F_q)$. \fun{GEN}{FF_elllog}{GEN E, GEN P, GEN G, GEN o} Let \kbd{G} be a point of order \kbd{o}, return $e$ such that $[e]P=G$. If $e$ does not exists, the result is undefined. \fun{GEN}{FF_ellgroup}{GEN E, GEN *pm} returns the structure of the Abelian group $E(\F_q)$ and set \kbd{*pm} to $m$ (see \kbd{gen\_ellgens}). \fun{GEN}{FF_ellweilpairing}{GEN E, GEN P, GEN Q, GEN m} returns the Weil pairing of the points of $m$-torsion $P$ and $Q$. \fun{GEN}{FF_elltatepairing}{GEN E, GEN P, GEN Q, GEN m} returns the Tate pairing of $P$ and $Q$, where $[m]P = 0$. \section{Arithmetic on elliptic curve over a finite field in simple form} The functions in this section no longer operate on elliptic curve structures, as seen up to now. They are used to implement those higher-level functions without using cached information and thus require suitable explicitly enumerated data. \subsec{Helper functions} \fun{GEN}{elltrace_extension}{GEN t, long n, GEN q} Let $E$ some elliptic curve over $\F_q$ such that the trace of the Frobenius is $t$, returns the trace of the Frobenius over $\F_q^n$. \subsec{Elliptic curves over $\F_p$, $p>3$} Let $p$ a prime number and $E$ the elliptic curve given by the equation $E:y^2=x^3+a_4\*x+a_6$, with $a_4$ and $a_6$ in $\F_p$. A \kbd{FpE} is a point of $E(\F_p)$. Since an affine point and $a_4$ determine an unique $a6$, most functions do not take $a_6$ as an argument. A \kbd{FpE} is either the point at infinity (\kbd{ellinf()}) or a $FpV$ whith two components. The parameters $a_4$ and $a_6$ are given as \typ{INT}s when required. \fun{GEN}{Fp_ellj}{GEN a4, GEN a6, GEN p} returns the $j$-invariant of the curve $E$. \fun{int}{Fp_elljissupersingular}{GEN j, GEN p} returns $1$ if $j$ is the $j$-invariant of a supersingular curve over $\F_p$, $0$ otherwise. \fun{GEN}{Fp_ellcard}{GEN a4, GEN a6, GEN p} returns the cardinality of the group $E(\F_p)$. \fun{GEN}{Fp_ellcard_SEA}{GEN a4, GEN a6, GEN p, long s} This function returns $\#E(\F_p)$, using the Schoof-Elkies-Atkin algorithm. If the \kbd{seadata} package is installed, the function will be faster. The extra flag \kbd{s}, if set to a non-zero value, causes the computation to return \kbd{gen\_0} (an impossible cardinality) if one of the small primes $\ell$ divides the curve order but does not divide $s$. For cryptographic applications, where one is usually interested in curves of prime order, setting $s=1$ efficiently weeds out most uninteresting curves; if curves of order a power of $2$ times a prime are acceptable, set $s=2$. If moreover \kbd{s} is negative, similar checks are performed for the twist of the curve. \fun{GEN}{Fp_ffellcard}{GEN a4, GEN a6, GEN q, long n, GEN p} returns the cardinality of the group $E(\F_q)$ where $q=p^n$. \fun{GEN}{Fp_ellgroup}{GEN a4, GEN a6, GEN N, GEN p, GEN *pm} returns the group structure $D$ of the group $E(\F_p)$, which is assumed to be of order $N$ and set \kbd{*pm} to $m$. \fun{GEN}{Fp_ellgens}{GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN p} returns generators of the group $E(\F_p)$ with the base change \kbd{ch} (see \kbd{FpE\_changepoint}), where $D$ and $m$ are as returned by \kbd{Fp\_ellgroup}. \fun{GEN}{Fp_elldivpol}{GEN a4, GEN a6, long n, GEN p} returns the $n$-division polynomial of the elliptic curve $E$. \fun{void}{Fp_elltwist}{GEN a4, GEN a6, GEN p, GEN *pA4, GEN *pA6} sets \kbd{*pA4} and \kbd{*pA6} to the corresponding parameters for the quadratic twist of $E$. \subsec{\kbd{FpE}} \fun{GEN}{FpE_add}{GEN P, GEN Q, GEN a4, GEN p} returns the sum $P+Q$ in the group $E(\F_p)$, where $E$ is defined by $E:y^2=x^3+a_4\*x+a_6$, for any value of $a_6$ compatible with the points given. \fun{GEN}{FpE_sub}{GEN P, GEN Q, GEN a4, GEN p} returns $P-Q$. \fun{GEN}{FpE_dbl}{GEN P, GEN a4, GEN p} returns $2.P$. \fun{GEN}{FpE_neg}{GEN P, GEN p} returns $-P$. \fun{GEN}{FpE_mul}{GEN P, GEN n, GEN a4, GEN p} return $n.P$. \fun{GEN}{FpE_changepoint}{GEN P, GEN m, GEN a4, GEN p} returns the image $Q$ of the point $P$ on the curve $E:y^2=x^3+a_4\*x+a_6$ by the coordinate change $m$ (which is a \kbd{FpV}). \fun{GEN}{FpE_changepointinv}{GEN P, GEN m, GEN a4, GEN p} returns the image $Q$ on the curve $E:y^2=x^3+a_4\*x+a_6$ of the point $P$ by the inverse of the coordinate change $m$ (which is a \kbd{FpV}). \fun{GEN}{random_FpE}{GEN a4, GEN a6, GEN p} returns a random point on $E(\F_p)$, where $E$ is defined by $E:y^2=x^3+a_4\*x+a_6$. \fun{GEN}{FpE_order}{GEN P, GEN o, GEN a4, GEN p} returns the order of $P$ in the group $E(\F_p)$, where $o$ is a multiple of the order of $P$, or its factorization. \fun{GEN}{FpE_log}{GEN P, GEN G, GEN o, GEN a4, GEN p} Let \kbd{G} be a point of order \kbd{o}, return $e$ such that $e.P=G$. If $e$ does not exists, the result is currently undefined. \fun{GEN}{FpE_tatepairing}{GEN P, GEN Q, GEN m, GEN a4, GEN p} returns the Tate pairing of the point of $m$-torsion $P$ and the point $Q$. \fun{GEN}{FpE_weilpairing}{GEN P, GEN Q, GEN m, GEN a4, GEN p} returns the Weil pairing of the points of $m$-torsion $P$ and $Q$. \fun{GEN}{FpE_to_mod}{GEN P, GEN p} returns $P$ as a vector of \typ{INTMOD}s. \fun{GEN}{RgE_to_FpE}{GEN P, GEN p} returns the \kbd{FpE} obtained by applying \kbd{Rg\_to\_Fp} coefficientwise. \subsec{\kbd{Fle}} Let $p$ be a prime \kbd{ulong}, and $E$ the elliptic curve given by the equation $E:y^2=x^3+a_4\*x+a_6$, where $a_4$ and $a_6$ are \kbd{ulong}. A \kbd{Fle} is either the point at infinity (\kbd{ellinf()}), or a \kbd{Flv} with two components $[x,y]$. \fun{long}{Fl_elltrace}{ulong a4, ulong a6, ulong p} returns the trace $t$ of the Frobenius of $E(\F_p)$. The cardinality of $E(\F_p)$ is thus $p+1-t$, which might not fit in an \kbd{ulong}. \fun{long}{Fl_elltrace_CM}{long CM, ulong a4, ulong a6, ulong p} as \tet{Fl_elltrace}. If \kbd{CM} is $0$, use the standard algorithm; otherwise assume the curve has CM by a principal imaginary quadratic order of discriminant \kbd{CM} and use a faster algorithm. Useful when the curve is the reduction of $E/\Q$, which has CM by a principal order, and we need the trace of Frobenius for many distinct $p$, see \tet{ellQ_get_CM}. \fun{ulong}{Fl_elldisc}{ulong a4, ulong a6, ulong p} returns the discriminant of the curve $E$. \fun{ulong}{Fl_elldisc_pre}{ulong a4, ulong a6, ulong p, ulong pi} returns the discriminant of the curve $E$, assuming $pi$ is the pseudo inverse of $p$. \fun{ulong}{Fl_ellj}{ulong a4, ulong a6, ulong p} returns the $j$-invariant of the curve $E$. \fun{ulong}{Fl_ellj_pre}{ulong a4, ulong a6, ulong p, ulong pi} returns the $j$-invariant of the curve $E$, assuming $pi$ is the pseudo inverse of $p$. \fun{void}{Fl_ellj_to_a4a6}{ulong j, ulong p, ulong *pa4, ulong *pa6} sets \kbd{*pa4} to $a_4$ and \kbd{*pa6} to $a_6$ where $a_4$ and $a_6$ define a fixed elliptic curve with $j$-invariant $j$. \fun{void}{Fl_elltwist}{ulong a4, ulong a6, ulong p, ulong *pA4, ulong *pA6} set \kbd{*pA4} to $A_4$ and \kbd{*pA6} to $A_6$ where $A_4$ and $A_6$ define the twist of $E$. \fun{void}{Fl_elltwist_disc}{ulong a4, ulong a6, ulong D, ulong p, ulong *pA4, ulong *pA6} sets \kbd{*pA4} to $A_4$ and \kbd{*pA6} to $A_6$ where $A_4$ and $A_6$ define the twist of $E$ by the discriminant $D$. \fun{GEN}{Fle_add}{GEN P, GEN Q, ulong a4, ulong p} \fun{GEN}{Fle_dbl}{GEN P, ulong a4, ulong p} \fun{GEN}{Fle_sub}{GEN P, GEN Q, ulong a4, ulong p} \fun{GEN}{Fle_mul}{GEN P, GEN n, ulong a4, ulong p} \fun{GEN}{Fle_mulu}{GEN P, ulong n, ulong a4, ulong p} \fun{GEN}{Fle_order}{GEN P, GEN o, ulong a4, ulong p} \fun{GEN}{Fle_log}{GEN P, GEN G, GEN o, ulong a4, ulong p} \fun{GEN}{random_Fle}{ulong a4, ulong a6, ulong p} \fun{GEN}{random_Fle_pre}{ulong a4, ulong a6, ulong p, ulong pi} \fun{GEN}{Fle_changepoint}{GEN x, GEN ch, ulong p}, \kbd{ch} is assumed to give the change of coordinates $[u,r,s,t]$ as a \typ{VECSMALL}. \fun{GEN}{Fle_changepointinv}{GEN x, GEN ch, ulong p}, as \tet{Fle_changepoint} \subsec{\kbd{FpJ}} Let $p$ be a prime \typ{INT}, and $E$ the elliptic curve given by the equation $E:y^2=x^3+a_4\*x+a_6$, where $a_4$ and $a_6$ are \typ{INT}. A \kbd{FpJ} is a \kbd{FpV} with three components $[x,y,z]$, representing the affine point $[x/z^2,y/z^3]$ in Jacobian coordinates, the point at infinity being represented by $[1, 1, 0]$. The following must holds: $y^2=x^3+a_4\*x\*z^4+a_6\*z^6$. For all non-zero $u$, the points $[u^2\*x,u^3\*y,u\*z]$ and $[x,y,z]$ are representing the same affine point. \fun{GEN}{FpJ_add}{GEN P, GEN Q, GEN a4, GEN p} \fun{GEN}{FpJ_dbl}{GEN P, GEN a4, GEN p} \fun{GEN}{FpJ_mul}{GEN P, GEN n, GEN a4, GEN p}; \fun{GEN}{FpJ_neg}{GEN P, GEN p} return $-P$. \fun{GEN}{FpJ_to_FpE}{GEN P, GEN p} return the corresponding \kbd{FpE}. \fun{GEN}{FpE_to_FpJ}{GEN P} return the corresponding \kbd{FpJ}. \subsec{\kbd{Flj}} Below, \kbd{pi} is assumed to be the precomputed inverse of $p$. \fun{GEN}{Fle_to_Flj}{GEN P} convert a \kbd{Fle} to an equivalent \kbd{Flj}. \fun{GEN}{Flj_to_Fle_pre}{GEN P} convert a \kbd{Flj} to the equivalent \kbd{Fle}. \fun{GEN}{Flj_add_pre}{GEN P, GEN Q, ulong a4, ulong p, ulong pi} \fun{GEN}{Flj_dbl_pre}{GEN P, ulong a4, ulong p, ulong pi} \fun{GEN}{Flj_neg}{GEN P, ulong p} return $-P$. \fun{GEN}{Flj_mulu_pre}{GEN P, ulong n, ulong a4, ulong p, ulong pi} \fun{GEN}{random_Flj_pre}{ulong a4, ulong a6, ulong p, ulong pi} \subsec{Elliptic curves over $\F_{2^n}$} Let $T$ be an irreducible \kbd{F2x} and $E$ the elliptic curve given by either the equation $E:y^2+x*y=x^3+a_2\*x^2+a_6$, where $a_2, a_6$ are \kbd{F2x} in $\F_2[X]/(T)$ (ordinary case) or $E:y^2+a_3*y=x^3+a_4\*x+a_6$, where $a_3, a_4, a_6$ are \kbd{F2x} in $\F_2[X]/(T)$ (supersingular case). A \kbd{F2xqE} is a point of $E(\F_2[X]/(T))$. In the supersingular case, the parameter \kbd{a2} is actually the \typ{VEC} $[a_3,a_4,a_3^{-1}]$. \fun{GEN}{F2xq_ellcard}{GEN a2, GEN a6, GEN T} Return the order of the group $E(\F_2[X]/(T))$. \fun{GEN}{F2xq_ellgroup}{GEN a2, GEN a6, GEN N, GEN T, GEN *pm} Return the group structure $D$ of the group $E(\F_2[X]/(T))$, which is assumed to be of order $N$ and set \kbd{*pm} to $m$. \fun{GEN}{F2xq_ellgens}{GEN a2, GEN a6, GEN ch, GEN D, GEN m, GEN T} Returns generators of the group $E(\F_2[X]/(T))$ with the base change \kbd{ch} (see \kbd{F2xqE\_changepoint}), where $D$ and $m$ are as returned by \kbd{F2xq\_ellgroup}. \fun{void}{F2xq_elltwist}{GEN a4, GEN a6, GEN T, GEN *a4t, GEN *a6t} sets \kbd{*a4t} and \kbd{*a6t} to the parameters of the quadratic twist of $E$. \subsec{\kbd{F2xqE}} \fun{GEN}{F2xqE_changepoint}{GEN P, GEN m, GEN a2, GEN T} returns the image $Q$ of the point $P$ on the curve $E:y^2+x*y=x^3+a_2\*x^2+a_6$ by the coordinate change $m$ (which is a \kbd{F2xqV}). \fun{GEN}{F2xqE_changepointinv}{GEN P, GEN m, GEN a2, GEN T} returns the image $Q$ on the curve $E:y^2=x^3+a_4\*x+a_6$ of the point $P$ by the inverse of the coordinate change $m$ (which is a \kbd{F2xqV}). \fun{GEN}{F2xqE_add}{GEN P, GEN Q, GEN a2, GEN T} \fun{GEN}{F2xqE_sub}{GEN P, GEN Q, GEN a2, GEN T} \fun{GEN}{F2xqE_dbl}{GEN P, GEN a2, GEN T} \fun{GEN}{F2xqE_neg}{GEN P, GEN a2, GEN T} \fun{GEN}{F2xqE_mul}{GEN P, GEN n, GEN a2, GEN T} \fun{GEN}{random_F2xqE}{GEN a2, GEN a6, GEN T} \fun{GEN}{F2xqE_order}{GEN P, GEN o, GEN a2, GEN T} returns the order of $P$ in the group $E(\F_2[X]/(T))$, where $o$ is a multiple of the order of $P$, or its factorization. \fun{GEN}{F2xqE_log}{GEN P, GEN G, GEN o, GEN a2, GEN T} Let \kbd{G} be a point of order \kbd{o}, return $e$ such that $e.P=G$. If $e$ does not exists, the result is currently undefined. \fun{GEN}{F2xqE_tatepairing}{GEN P, GEN Q, GEN m, GEN a2, GEN T} returns the Tate pairing of the point of $m$-torsion $P$ and the point $Q$. \fun{GEN}{F2xqE_weilpairing}{GEN Q, GEN Q, GEN m, GEN a2, GEN T} returns the Weil pairing of the points of $m$-torsion $P$ and $Q$. \fun{GEN}{RgE_to_F2xqE}{GEN P, GEN T} returns the \kbd{F2xqE} obtained by applying \kbd{Rg\_to\_F2xq} coefficientwise. \subsec{Elliptic curves over $\F_q$, small characteristic $p>2$ } Let $p > 2$ be a prime \kbd{ulong}, $T$ an irreducible \kbd{Flx} mod $p$, and $E$ the elliptic curve given by the equation $E:y^2=x^3+a_4\*x+a_6$, where $a_4$ and $a_6$ are \kbd{Flx} in $\F_p[X]/(T)$. A \kbd{FlxqE} is a point of $E(\F_p[X]/(T))$. In the special case $p = 3$, ordinary elliptic curves ($j(E)\neq 0$) cannot be represented as above, but admit a model $E:y^2 = x^3+a_2\*x^2+a_6$ with $a_2$ and $a_6$ being \kbd{Flx} in $\F_3[X]/(T)$. In that case, the parameter \kbd{a2} is actually stored as a \typ{VEC}, $[a_2]$, to avoid ambiguities. \fun{GEN}{Flxq_ellj}{GEN a4, GEN a6, GEN T, ulong p} returns the $j$-invariant of the curve $E$. \fun{void}{Flxq_ellj_to_a4a6}{GEN j, GEN T, ulong p, GEN *pa4, GEN *pa6} sets \kbd{*pa4} to $a_4$ and \kbd{*pa6} to $a_6$ where $a_4$ and $a_6$ define a fixed elliptic curve with $j$-invariant $j$. \fun{GEN}{Flxq_ellcard}{GEN a4, GEN a6, GEN T, ulong p} returns the order of $E(\F_p[X]/(T))$. \fun{GEN}{Flxq_ellgroup}{GEN a4, GEN a6, GEN N, GEN T, ulong p, GEN *pm} returns the group structure $D$ of the group $E(\F_p[X]/(T))$, which is assumed to be of order $N$ and sets \kbd{*pm} to $m$. \fun{GEN}{Flxq_ellgens}{GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, ulong p} returns generators of the group $E(\F_p[X]/(T))$ with the base change \kbd{ch} (see \kbd{FlxqE\_changepoint}), where $D$ and $m$ are as returned by \kbd{Flxq\_ellgroup}. \fun{void}{Flxq_elltwist}{GEN a4, GEN a6, GEN T, ulong p, GEN *pA4, GEN *pA6} sets \kbd{*pA4} and \kbd{*pA6} to the corresponding parameters for the quadratic twist of $E$. \subsec{\kbd{FlxqE}} Let $p > 2$ be a prime number. \fun{GEN}{FlxqE_changepoint}{GEN P, GEN m, GEN a4, GEN T, ulong p} returns the image $Q$ of the point $P$ on the curve $E:y^2=x^3+a_4\*x+a_6$ by the coordinate change $m$ (which is a \kbd{FlxqV}). \fun{GEN}{FlxqE_changepointinv}{GEN P, GEN m, GEN a4, GEN T, ulong p} returns the image $Q$ on the curve $E:y^2=x^3+a_4\*x+a_6$ of the point $P$ by the inverse of the coordinate change $m$ (which is a \kbd{FlxqV}). \fun{GEN}{FlxqE_add}{GEN P, GEN Q, GEN a4, GEN T, ulong p} \fun{GEN}{FlxqE_sub}{GEN P, GEN Q, GEN a4, GEN T, ulong p} \fun{GEN}{FlxqE_dbl}{GEN P, GEN a4, GEN T, ulong p} \fun{GEN}{FlxqE_neg}{GEN P, GEN T, ulong p} \fun{GEN}{FlxqE_mul}{GEN P, GEN n, GEN a4, GEN T, ulong p} \fun{GEN}{random_FlxqE}{GEN a4, GEN a6, GEN T, ulong p} \fun{GEN}{FlxqE_order}{GEN P, GEN o, GEN a4, GEN T, ulong p} returns the order of $P$ in the group $E(\F_p[X]/(T))$, where $o$ is a multiple of the order of $P$, or its factorization. \fun{GEN}{FlxqE_log}{GEN P, GEN G, GEN o, GEN a4, GEN T, ulong p} Let \kbd{G} be a point of order \kbd{o}, return $e$ such that $e.P=G$. If $e$ does not exists, the result is currently undefined. \fun{GEN}{FlxqE_tatepairing}{GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p} returns the Tate pairing of the point of $m$-torsion $P$ and the point $Q$. \fun{GEN}{FlxqE_weilpairing}{GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p} returns the Weil pairing of the points of $m$-torsion $P$ and $Q$. \fun{GEN}{RgE_to_FlxqE}{GEN P, GEN T, ulong p} returns the \kbd{FlxqE} obtained by applying \kbd{Rg\_to\_Flxq} coefficientwise. \subsec{Elliptic curves over $\F_q$, large characteristic } Let $p > 3$ be a prime number, $T$ an irreducible polynomial mod $p$, and $E$ the elliptic curve given by the equation $E:y^2=x^3+a_4\*x+a_6$ with $a_4$ and $a_6$ in $\F_p[X]/(T)$. A \kbd{FpXQE} is a point of $E(\F_p[X]/(T))$. \fun{GEN}{FpXQ_ellj}{GEN a4, GEN a6, GEN T, GEN p} returns the $j$-invariant of the curve $E$. \fun{int}{FpXQ_elljissupersingular}{GEN j, GEN T, GEN p} returns $1$ if $j$ is the $j$-invariant of a supersingular curve over $\F_p[X]/(T)$, $0$ otherwise. \fun{GEN}{FpXQ_ellcard}{GEN a4, GEN a6, GEN T, GEN p} returns the order of $E(\F_p[X]/(T))$. \fun{GEN}{Fq_ellcard_SEA}{GEN a4, GEN a6, GEN q, GEN T, GEN p, long s} This function returns $\#E(\F_p[X]/(T))$, using the Schoof-Elkies-Atkin algorithm. Assume $p\neq 2,3$, and $q$ is the cardinality of $\F_p[X]/(T)$. The parameter $s$ has the same meaning as in \kbd{Fp\_ellcard\_SEA}. If the \kbd{seadata} package is installed, the function will be faster. \fun{GEN}{FpXQ_ellgroup}{GEN a4, GEN a6, GEN N, GEN T, GEN p, GEN *pm} Return the group structure $D$ of the group $E(\F_p[X]/(T))$, which is assumed to be of order $N$ and set \kbd{*pm} to $m$. \fun{GEN}{FpXQ_ellgens}{GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, GEN p} Returns generators of the group $E(\F_p[X]/(T))$ with the base change \kbd{ch} (see \kbd{FpXQE\_changepoint}), where $D$ and $m$ are as returned by \kbd{FpXQ\_ellgroup}. \fun{GEN}{FpXQ_elldivpol}{GEN a4, GEN a6, long n, GEN T, GEN p} returns the $n$-division polynomial of the elliptic curve $E$. \fun{GEN}{Fq_elldivpolmod}{GEN a4,GEN a6, long n, GEN h, GEN T, GEN p} returns the $n$-division polynomial of the elliptic curve $E$ modulo the polynomial $h$. \fun{void}{FpXQ_elltwist}{GEN a4, GEN a6, GEN T, GEN p, GEN *pA4, GEN *pA6} sets \kbd{*pA4} and \kbd{*pA6} to the corresponding parameters for the quadratic twist of $E$. \subsec{\kbd{FpXQE}} \fun{GEN}{FpXQE_changepoint}{GEN P, GEN m, GEN a4, GEN T, GEN p} returns the image $Q$ of the point $P$ on the curve $E:y^2=x^3+a_4\*x+a_6$ by the coordinate change $m$ (which is a \kbd{FpXQV}). \fun{GEN}{FpXQE_changepointinv}{GEN P, GEN m, GEN a4, GEN T, GEN p} returns the image $Q$ on the curve $E:y^2=x^3+a_4\*x+a_6$ of the point $P$ by the inverse of the coordinate change $m$ (which is a \kbd{FpXQV}). \fun{GEN}{FpXQE_add}{GEN P, GEN Q, GEN a4, GEN T, GEN p} \fun{GEN}{FpXQE_sub}{GEN P, GEN Q, GEN a4, GEN T, GEN p} \fun{GEN}{FpXQE_dbl}{GEN P, GEN a4, GEN T, GEN p} \fun{GEN}{FpXQE_neg}{GEN P, GEN T, GEN p} \fun{GEN}{FpXQE_mul}{GEN P, GEN n, GEN a4, GEN T, GEN p} \fun{GEN}{random_FpXQE}{GEN a4, GEN a6, GEN T, GEN p} \fun{GEN}{FpXQE_log}{GEN P, GEN G, GEN o, GEN a4, GEN T, GEN p} Let \kbd{G} be a point of order \kbd{o}, return $e$ such that $e.P=G$. If $e$ does not exists, the result is currently undefined. \fun{GEN}{FpXQE_order}{GEN P, GEN o, GEN a4, GEN T, GEN p} returns the order of $P$ in the group $E(\F_p[X]/(T))$, where $o$ is a multiple of the order of $P$, or its factorization. \fun{GEN}{FpXQE_tatepairing}{GEN P,GEN Q, GEN m, GEN a4, GEN T, GEN p} returns the Tate pairing of the point of $m$-torsion $P$ and the point $Q$. \fun{GEN}{FpXQE_weilpairing}{GEN P,GEN Q, GEN m, GEN a4, GEN T, GEN p} returns the Weil pairing of the points of $m$-torsion $P$ and $Q$. \fun{GEN}{RgE_to_FpXQE}{GEN P, GEN T, GEN p} returns the \kbd{FpXQE} obtained by applying \kbd{Rg\_to\_FpXQ} coefficientwise. \section{Functions related to modular polynomials} Variants of \tet{polmodular}, returning the modular polynomial of prime level $L$ for the invariant coded by \kbd{inv} (0: $j$, 1: Weber-$f$, see \tet{polclass} for the full list). \fun{GEN}{polmodular_ZXX}{long L, long inv, long xvar, long yvar} returns a bivariate polynomial in variables \kbd{xvar} and \kbd{yvar}. \fun{GEN}{polmodular_ZM}{long L, long inv} returns a matrix of (integral) coefficients. \fun{GEN}{Fp_polmodular_evalx}{long L, long inv, GEN J, GEN p, long v, int derivs} returns the modular polynomial evaluated at $J$ modulo the prime $p$ in the variable $v$ (if \kbd{derivs} is non-zero, returns a vector containing the modular polynomial and its first and second derivatives, all evaluated at $J$ modulo~$p$). \subsec{Functions related to modular invariants} \fun{void}{check_modinv}{long inv} report an error if \kbd{inv} is not a valid code for a mdular invariant. \fun{int}{modinv_good_disc}{long inv, long D} test whether the invariant \kbd{inv} is defined for the discriminant \kbd{D}. \fun{int}{modinv_good_prime}{long inv, long D} test whether the invariant \kbd{inv} is defined for the prime \kbd{p}. \fun{long}{modinv_height_factor}{long inv} return the height factor of the modular invariant \kbd{inv} with respect to the $j$-invariant. This is an integer $n$ such that the $j$-invariant is asymptotically of the order of the $n$-th power of the invariant \kbd{inv}. \fun{long}{modinv_is_Weber}{long inv} test whether the invariant \kbd{inv} is a power of Weber $f$. \fun{long}{modinv_is_double_eta}{long inv} test whether the invariant \kbd{inv} is a double $\eta$ quotient. \fun{long}{disc_best_modinv}{long D} the integer $D$ being a negative discriminant, return the modular invariant compatible with $D$ with the highest height factor. \fun{GEN}{Fp_modinv_to_j}{GEN x, long inv, GEN p} Let $\Phi$ the modular equation between $j$ and the modular invariant \kbd{inv}, return $y$ such that $\Phi(y,x)=0\pmod{p}$. \section{Other curves} The following functions deal with hyperelliptic curves in weighted projective space $\P_{(1,d,1)}$, with coordinates $(x,y,z)$ and a model of the form $ y^2 = T(x,z)$, where $T$ is homogeneous of degree $2d$, and squarefree. Thus the curve is nonsingular of genus $d-1$. \fun{long}{hyperell_locally_soluble}{GEN T, GEN p} assumes that $T\in\Z[X]$ is integral. Returns $1$ if the curve is locally soluble over $\Q_p$, $0$ otherwise. \fun{long}{nf_hyperell_locally_soluble}{GEN nf, GEN T, GEN pr} let $K$ be a number field, attached to \kbd{nf}, \kbd{pr} a \var{prid} attached to some maximal ideal $\goth{p}$; assumes that $T\in\Z_K[X]$ is integral. Returns $1$ if the curve is locally soluble over $K_{\goth{p}}$. \newpage pari-2.11.2/doc/refcard-nf.tex0000644000175000017500000005603013326135265014466 0ustar billbill% Copyright (c) 2007-2016 Karim Belabas. % Permission is granted to copy, distribute and/or modify this document % under the terms of the GNU General Public License % Reference Card for PARI-GP, Algebraic Number Theory. % Author: % Karim Belabas % Universite de Bordeaux, 351 avenue de la Liberation, F-33405 Talence % email: Karim.Belabas@math.u-bordeaux.fr % % See refcard.tex for acknowledgements and thanks. \def\TITLE{Algebraic Number Theory} \input refmacro.tex \def\p{\goth{p}} \section{Binary Quadratic Forms} % \li{create $ax^2+bxy+cy^2$ (distance $d$) }{Qfb$(a,b,c,\{d\})$} \li{reduce $x$ ($s =\sqrt{D}$, $l=\floor{s}$)} {qfbred$(x,\{\fl\},\{D\},\{l\},\{s\})$} \li{return $[y,g]$, $g\in \text{SL}_2(\ZZ)$, $y = g\cdot x$ reduced} {qfbredsl2$(x)$} \li{composition of forms}{$x$*$y$ {\rm or }qfbnucomp$(x,y,l)$} \li{$n$-th power of form}{$x$\pow$n$ {\rm or }qfbnupow$(x,n)$} \li{composition without reduction}{qfbcompraw$(x,y)$} \li{$n$-th power without reduction}{qfbpowraw$(x,n)$} \li{prime form of disc. $x$ above prime $p$}{qfbprimeform$(x,p)$} \li{class number of disc. $x$}{qfbclassno$(x)$} \li{Hurwitz class number of disc. $x$}{qfbhclassno$(x)$} \li{solve $Q(x,y) = p$ in integers, $p$ prime}{qfbsolve$(Q,p)$} \section{Quadratic Fields} % \li{quadratic number $\omega=\sqrt x$ or $(1+\sqrt x)/2$}{quadgen$(x)$} \li{minimal polynomial of $\omega$}{quadpoly$(x)$} \li{discriminant of $\QQ(\sqrt{x})$}{quaddisc$(x)$} \li{regulator of real quadratic field}{quadregulator$(x)$} \li{fundamental unit in real $\QQ(\sqrt{D})$}{quadunit($D$,\{'w\})} \li{class group of $\QQ(\sqrt{D})$}{quadclassunit$(D,\{\fl\},\{t\})$} \li{Hilbert class field of $\QQ(\sqrt{D})$}{quadhilbert$(D,\{\fl\})$} \li{\dots using specific class invariant ($D<0$)}{polclass$(D,\{\var{inv}\})$} \li{ray class field modulo $f$ of $\QQ(\sqrt{D})$}{quadray$(D,f,\{\fl\})$} \bigskip \section{General Number Fields: Initializations} The number field $K = \QQ[X]/(f)$ is given by irreducible $f\in\QQ[X]$. We denote $\theta = \bar{X}$ the canonical root of $f$ in $K$. A \var{nf} structure contains a maximal order and allows operations on elements and ideals. A \var{bnf} adds class group and units. A \var{bnr} is attached to ray class groups and class field theory. A \var{rnf} is attached to relative extensions $L/K$.\hfill\break % \li{init number field structure \var{nf}}{nfinit$(f,\{\fl\})$} \beginindentedkeys \li{known integer basis $B$}{nfinit$([f,B])$} \li{order maximal at $\var{vp}=[p_1,\dots,p_k]$}{nfinit$([f,\var{vp}])$} \li{order maximal at all $p \leq P$}{nfinit$([f,P])$} \li{certify maximal order}{nfcertify$(\var{nf})$} \endindentedkeys \subsec{nf members:} \beginindentedkeys \li{a monic $F\in \ZZ[X]$ defining $K$}{\var{nf}.pol} \li{number of real/complex places}{\var{nf}.r1/r2/sign} \li{discriminant of \var{nf}}{\var{nf}.disc} \li{$T_2$ matrix}{\var{nf}.t2} \li{complex roots of $F$}{\var{nf}.roots} \li{integral basis of $\ZZ_K$ as powers of $\theta$}{\var{nf}.zk} \li{different/codifferent}{\var{nf}.diff{\rm, }\var{nf}.codiff} \li{index $[\ZZ_K:\ZZ[X]/(F)]$}{\var{nf}.index} \endindentedkeys \li{recompute \var{nf}\ using current precision}{nfnewprec$(nf)$} \li{init relative \var{rnf} $L = K[Y]/(g)$}{rnfinit$(\var{nf},g)$} % \li{init \var{bnf} structure}{bnfinit$(f,\{\fl\})$} \subsec{bnf members: {\rm same as \var{nf}, plus}} \beginindentedkeys \li{underlying \var{nf}}{\var{bnf}.nf} \li{classgroup}{\var{bnf}.clgp} \li{regulator}{\var{bnf}.reg} \li{fundamental/torsion units}{\var{bnf}.fu{\rm, }\var{bnf}.tu} \endindentedkeys \newcolumn \li{compress a \var{bnf}\ for storage}{bnfcompress$(\var{bnf})$} \li{recover a \var{bnf}\ from compressed \var{bnfz}}{bnfinit$(\var{bnfz})$} % \li{add $S$-class group and units, yield \var{bnf}S}{bnfsunit$(\var{bnf},S)$} \li{init class field structure \var{bnr}}{bnrinit$(\var{bnf},m,\{\fl\})$} % \subsec{bnr members: {\rm same as \var{bnf}, plus}} \beginindentedkeys \li{underlying \var{bnf}}{\var{bnr}.bnf} \li{big ideal structure}{\var{bnr}.bid} \li{modulus}{\var{bnr}.mod} \li{structure of $(\ZZ_K/m)^*$}{\var{bnr}.zkst} \endindentedkeys \smallskip \section{Fields, subfields, embeddings} \subsec{Defining polynomials, embeddings} \li{smallest poly defining $f=0$ (slow)}{polredabs$(f,\{\fl\})$} \li{small poly defining $f=0$ (fast)}{polredbest$(f,\{\fl\})$} \li{random Tschirnhausen transform of $f$}{poltschirnhaus$(f)$} \li{$\QQ[t]/(f) \subset \QQ[t]/(g)$ ? Isomorphic?} {nfisincl$(f,g)$, \kbd{nfisisom}} \li{reverse polmod $a=A(t)\mod T(t)$}{modreverse$(a)$} \li{compositum of $\QQ[t]/(f)$, $\QQ[t]/(g)$}{polcompositum$(f,g,\{\fl\})$} \li{compositum of $K[t]/(f)$, $K[t]/(g)$}{nfcompositum$(\var{nf}, f,g,\{\fl\})$} \li{splitting field of $K$ (degree divides $d$)} {nfsplitting$(\var{nf},\{d\})$} \li{signs of real embeddings of $x$}{nfeltsign$(\var{nf},x,\{pl\})$} \li{complex embeddings of $x$}{nfeltembed$(\var{nf},x,\{pl\})$} \li{$T\in K[t]$, \# of real roots of $\sigma(T)\in\R[t]$}{nfpolsturm$(\var{nf},T,\{pl\})$} \smallskip \subsec{Subfields, polynomial factorization} \li{subfields (of degree $d$) of \var{nf}}{nfsubfields$(\var{nf},\{d\})$} \li{$d$-th degree subfield of $\QQ(\zeta_n)$} {polsubcyclo$(n,d,\{v\})$} \li{roots of unity in \var{nf}}{nfrootsof1$(\var{nf}\,)$} \li{roots of $g$ belonging to \var{nf}}{nfroots$(\var{nf},g)$} \li{factor $g$ in \var{nf}}{nffactor$(\var{nf},g)$} \li{factor $g$ mod prime \var{pr} in \var{nf}}{nffactormod$(\var{nf},g,pr)$} \smallskip \subsec{Linear and algebraic relations} \li{poly of degree $\le k$ with root $x\in\CC$}{algdep$(x,k)$} \li{alg. dep. with pol.~coeffs for series $s$}{seralgdep$(s,x,y)$} \li{small linear rel.\ on coords of vector $x$}{lindep$(x)$} \section{Basic Number Field Arithmetic (nf)} Number field elements are \typ{INT}, \typ{FRAC}, \typ{POL}, \typ{POLMOD}, or \typ{COL} (on integral basis \kbd{\var{nf}.zk}). \smallskip \subsec{Basic operations} \li{$x+y$}{nfeltadd$(\var{nf},x,y)$} \li{$x\times y$}{nfeltmul$(\var{nf},x,y)$} \li{$x^n$, $n\in \ZZ$}{nfeltpow$(\var{nf},x,n)$} \li{$x / y$}{nfeltdiv$(\var{nf},x,y)$} \li{$q = x$\kbd{\bs/}$y := $\kbd{round}$(x/y)$}{nfeltdiveuc$(\var{nf},x,y)$} \li{$r = x$\kbd{\%}$y := x - (x$\kbd{\bs/}$y)y$}{nfeltmod$(\var{nf},x,y)$} \li{\dots $[q,r]$ as above}{nfeltdivrem$(\var{nf},x,y)$} \li{reduce $x$ modulo ideal $A$}{nfeltreduce$(\var{nf},x,A)$} \li{absolute trace $\text{Tr}_{K/\QQ} (x)$}{nfelttrace$(\var{nf},x)$} \li{absolute norm $\text{N}_{K/\QQ} (x)$}{nfeltnorm$(\var{nf},x)$} \smallskip \subsec{Multiplicative structure of $K^*$; $K^*/(K^*)^n$} \li{valuation $v_\p(x)$}{nfeltval$(\var{nf},x,\p)$} \li{\dots write $x = \pi^{v_\p(x)} y$}{nfeltval$(\var{nf},x,\p,\&y)$} \li{quadratic Hilbert symbol (at $\p$)} {nfhilbert$(\var{nf},a,b,\{\p\})$} \li{$b$ such that $x b^n = v$ is small}{idealredmodpower$(\var{nf},x,n)$} \smallskip \subsec{Maximal order and discriminant} \li{integral basis of field $\QQ[x]/(f)$}{nfbasis$(f)$} \li{field discriminant of field $f=0$}{nfdisc$(f)$} \li{express $x$ on integer basis}{nfalgtobasis$(\var{nf},x)$} \li{express element\ $x$ as a polmod}{nfbasistoalg$(\var{nf},x)$} \smallskip \subsec{Dedekind Zeta Function $\zeta_K$, Hecke $L$ series} $R = [c,w,h]$ in initialization means we restrict $s\in \CC$ to domain $|\Re(s)-c| < w$, $|\Im(s)| < h$; $R = [w,h]$ encodes $[1/2,w,h]$ and $[h]$ encodes $R = [1/2,0,h]$ (critical line up to height $h$).\hfil\break \li{$\zeta_K$ as Dirichlet series, $N(I): use color "number" (same scheme as in GP) # -color_bold (-cb) : display bold in color "number" # -color_underline (-cu) : display underlined text in color "number" # # -raw use internal format for output with @x markers, -detex is implicit # (for the TeX-to-pod converter) # # -to_pod file convert file to POD (should be the only args) # # -to_dumbpod file same, but without nested formating # -utf8 in detex mode, use UFT-8 encoding for output # # Granted environment variables (override): # GPTMPDIR: where temporary files will go (/tmp by default). # GPDOCDIR: where is manual (by default, where make install will put it). # GPXDVI: which 'xdvi' program to call (xdvi by default) # $version= "@version@"; $datadir= "@datadir@"; # no expanded material (@key@) below $wwwsite= "http://pari.math.u-bordeaux.fr/"; $xdvi = $ENV{GPXDVI} || "xdvi"; $xdviref = $ENV{GPXDVIREF} || "$xdvi -paper 29.7x21cm"; $gzip = "gzip"; $zcat = "$gzip -dc"; $bzip = "bzip2"; $bzcat = "$bzip -dc"; $docdir = &get_docdir(); $tex = $ENV{GPTEX} || "tex"; $refcard = (@ARGV and $ARGV[-1] =~ /refcard/i); $dumb_pod=1, $ARGV[0] = '-to_pod' if @ARGV && $ARGV[0] eq '-to_dumb_pod'; &to_pod() if @ARGV == 2 && $ARGV[0] eq '-to_pod'; &options(); &init(); if ($#ARGV < 0) { &treat(""); cleanexit(); } &pretex() if (!$detex); for (@ARGV) { &treat($_); } if ($apropos) { &apropos_final_print(); cleanexit(); } &posttex() if (!$detex); print "ugly_kludge_done\n" if (!$detex && $fromgp); cleanexit(); # # Procedures # sub cleanexit { print "\e[0m" unless $to_pod or $raw; exit 0; } sub help { print "Usage: $0 [-k] [-detex] [-ch c1] [-cb c2] [-cu c3] keyword\n"; print "where c1,c2,c3 denote background, bold and underline color\n"; exit(1); } sub options { $utf8 = $raw = $detex = $fromgp = $apropos = $noskip = 0; $ch = $cb = $cu = ''; while ($_ = $ARGV[0]) { last if (! /^-[a-z]/); shift(@ARGV); if ($_ eq "-fromgp") { $fromgp = 1; } elsif ($_ eq "-k") { $apropos = $detex = 1; } elsif ($_ eq "-balloon") { $balloon = 1; } elsif ($_ eq "-detex" || $_ eq "-d") { $detex = 1; } elsif ($_ eq "-raw") { $raw = $detex = 1; } elsif ($_ eq "-utf8") { $utf8 = 1; } elsif ($_ eq "-noskip") { $noskip = 1; } elsif ($_ eq "-color_help" || $_ eq "-ch") { $ch = &color(shift(@ARGV)); } elsif ($_ eq "-color_bold" || $_ eq "-cb") { $cb = &color(shift(@ARGV)); } elsif ($_ eq "-color_underline" || $_ eq "-cu") { $cu = &color(shift(@ARGV)); } else { &help(); } } $ch = "\e[m$ch"; $cu .= $cu ? "\e[1m": "\e[4m"; $cb .= "\e[1m"; $detex = 1 if (!$ENV{DISPLAY}); } sub get_docdir { my $d = $ENV{GPDOCDIR} || $ENV{GPHELP_DOCDIR}; if (!defined $d) { # work from TOPDIR/Oarch or TOPDIR too: may be uninstalled yet; $d = $0; $d =~ s,/gphelp,,; for ("$datadir", '.', '..', $d) { my $t = "$_/doc"; if (-f "$t/translations") { $d = $t; last; } } $d ||= "$datadir/doc"; # Last resort } if ($d =~ /^\./) { eval { require Cwd; $d = Cwd::cwd() . "/$d"; $d =~ s,doc/\.\./doc,doc,; } } return $d; } sub init { &inittr(); $indent = " "; # avoid Glob.pm! (for minimal Windows install) opendir(DIR, $docdir) || die "$docdir not found"; @file_list = grep { /^usersch.*tex/ } readdir(DIR); closedir(DIR); chdir($docdir); $docfile = "usersch3.tex"; open(IN,"translations") || die("Could not find translation file, docdir='$docdir'"); while() { chomp; @_ = split(/ *\@ */); $key = shift(@_); $transl{$key} = join('@',@_); } close(IN); } sub not_found { my($help) = shift; $help =~ s/\\\\/_B#K#S_/g; $help =~ s/\\(.)/$1/g; $help =~ s/_B#K#S_/\\/g; print "'$help' not found !\n"; } sub choose_chap { while (s/\@([0-9])$//) { $docfile = "usersch$1.tex"; } if (-f $docfile) { $pipe = ""; } else { die "Cannot find $docfile" if (! -f "$docfile.z" && ! -f "$docfile.gz" && ! -f "$docfile.Z" && ! -f "$docfile.bz2"); if (-f "$docfile.bz2") { $pipe = $bzcat; $docfile = "$docfile.bz2"; } else { $pipe = $zcat; } } } sub safe_setsid { eval { require POSIX; POSIX::setsid(); # detach from terminal (^C will not kill xdvi) }; } # assume we're in $docdir sub open_viewer_then_quit { my $F = shift; my ($f, $viewer, $redirect); my $cygwin = ($^O =~ /cygwin/); my $win32 = ($^O =~ /ms(win|ys)/); my $osx = ($^O =~ /darwin/); $f = "$F.dvi"; $f = "$F.dvi.gz" if (! -f "$f"); $f = "$F.pdf" if (! -f "$f"); die "could not find \'$F\'" if (! -f "$f"); $F = $f; $redirect = ' 2>/dev/null >/dev/null &'; if ($f =~ /\.dvi/) { # DVI $viewer = ($f =~ /refcard/)? $xdviref: $xdvi; } elsif ($cygwin) { # PDF Win32 @_ = split(/"/, `acro.exe`); ($viewer = $_[1]) =~ s,\\,/,g; $redirect = ""; $F =~ s,/cygdrive/(.),$1:, ; # Reader can't cope with Cygwin paths $F = "\"$F\""; $viewer = "\"$viewer\""; } elsif ($win32) { # PDF Win32 @_ = split(/"/, "$ENV{GP_PDF_VIEWER}"); $viewer = $_[1]; print "using \'$viewer\', "; } elsif ($osx) { $viewer = "open"; } else { # PDF generic $viewer = "acroread"; } print "displaying \'$F\'."; print "\n" if (!$fromgp); safe_setsid(); if ($win32) { system($viewer,$F); } else { system("$viewer $F$redirect"); } cleanexit(); } sub treat { my($help); $_ = $_[0]; s/_QUOTE/'/g; s/_BACKQUOTE/`/g; s/_DOUBQUOTE/"/g; s/^ *"(.*)"([^"]*) *$/$1$2/; if (s/\@$//) { $found = 0; $searchall = 1; $help = $_; for (@file_list) { next if (!/^usersch(.*)\.tex/); &treat("$help\@$1"); if ($apropos && $#list > 0 || $#sentence_list > 0) { print "\nChapter $1:\n"; print "==========\n"; &apropos_final_print(); } } return not_found($help) if (!$found && !$apropos); $searchall = 0; $apropos = 0; return; } &choose_chap; if (!$apropos) { $_ = "users" if (/^$/); open_viewer_then_quit($_) if (/^(users|tutorial|refcard|libpari)$/ || /^refcard-/ || /^tutorial-mf$/); if ($transl{$_}) { $_ = $transl{$_}; &choose_chap; } } if (/^[^a-zA-Z0-9]*$/) { $_ = 'GP operators@2'; &choose_chap; } s/(\W)/\\$1/g; s/_/\\\\_/g if (!/^se\\:/); ($pipe && open(DOC,"$pipe $docfile |")) || (!$pipe && open(DOC,"$docfile")) || die "Cannot open $docfile: $!"; return &apropos($_) if ($apropos); $help = $_; my ($first); my ($pat) = $help; if ($pat =~ /[a-zA-Z0-9]$/) { $pat .= '\b'; } else { $pat .= '}'; } while () { if (/\\(subsubsec[a-z]*|subsec[a-z]*|section|chapter|label)\{$pat/ && (!/\\label\{se:def,/ || $pat =~ /se\\:def/)) { $first = $_; last; } } if (eof(DOC)) { ¬_found($help) if (!$searchall); return; } $found = 1; if (!$detex) { tex($first); } else { &detex(); print "\n" if (!$fromgp); # Avoid broken pipe from zcat do {local $/; } if $^O eq 'os2' and $pipe; } close(DOC); } # # A propos # sub apropos_print_list { $current = ""; @_ = sort(@_); for (@_) { next if ($_ eq $current); $current = $_; print "$indent$_\n"; } } sub apropos_raw_print { $indent = ""; &apropos_print_list(@sentence_list); &apropos_print_list(@list); } sub apropos_final_print { my($maxlen) = 0; my($i,$nbcol,$current); my($cols) = ($ENV{'COLUMNS'} || 80) - 1; if ($raw) { &apropos_raw_print(); return; } @list = sort(@list); for (@list) { $i= length($_); $maxlen = $i if ($i > $maxlen); } $maxlen++; $nbcol = $cols / $maxlen; $nbcol =~ s/\..*//; $nbcol-- if ($nbcol * $maxlen == $cols); $nbcol = 1 if (!$nbcol); $current = ""; $i = 0; for (@list) { next if ($_ eq $current); $current = $_; print($_); $i++; if ($i >= $nbcol) { $i=0; print "\n"; next; } print " " x ($maxlen - length($_)); } print "\n" if ($i); if ($#sentence_list > 0) { print "\nSee also:\n" if ($#list > 0); $indent = " "; apropos_print_list(@sentence_list); } } sub apropos_check { my($line, $current) = @_; $line =~ s/\n/ /g; return if ($line !~ /$help/i); local($_) = $current; s/\\b\{(.)\}/\\$1/; s/\{\}//g; s/\\pow/^/; s/\\%/%/; s/\\bs/\\/; s/\\_/_/g; s/\\\#/\#/g; s,\+\$/\$-,+/-,; s/\$\(.*//; # remove argument lists if (/ /) { push(@sentence_list,$_); } else { push(@list,$_); } } sub apropos { my($line,$current,$new); $help = $_[0]; $help='\\\\pow' if ($help eq '\^'); $help='\\\\til' if ($help eq '\~'); @sentence_list = @list = ""; while () { if (/^\\(subsubsec[a-z]*|subsec[a-z]*|section|chapter)\{/) { $new = &get_match($_,'\\{','\\}'); &apropos_check($line, $current); $current = $new; $line = ""; } $line .= $_; } &apropos_check($line, $current); } ## ## Tex Part ## # Actual text is in file TEX. Parimacro + Geometry info goes to WRAP sub pretex { my ($basedir) = $ENV{GPHELP_TMPDIR} || $ENV{GPTMPDIR} || $ENV{TMPDIR} || "/tmp"; $tmpdir = "$basedir/gp.help$$"; mkdir $tmpdir, 0755 || die "Cannot create temporary directory"; $texfile = "$tmpdir/gp.help"; open(TEX,">$texfile.tex") || die "Couldn't open $texfile.tex"; } sub endsection { /^\\(section|sub[sub]*sec)/i && ($noskip || !/\%GPHELPskip/); } sub tex { my ($first) = @_; print TEX $first; while () { last if endsection(); print TEX; } } sub posttex { my ($wrap) = "$tmpdir/gpwrapper.help"; my (@goners) = ("$texfile.tex", "$wrap.tex", "$wrap.dvi", "$wrap.log", "$wrap.aux"); if (!$found) { unlink @goners; rmdir("$tmpdir"); cleanexit(); } open(WRAP, ">$wrap.tex") || die "Couldn't open $wrap.tex"; if ($balloon) { print WRAP '\nopagenumbers\def\fromgphelp{}' . "\\input $docdir/parimacro.tex" . '\setbox0\vbox{' . "\\input $texfile.tex" . ' } \dimen0=\the\ht0 \advance\dimen0 by \dp0 \advance\dimen0 by 60pt \dimen1=\the\wd0 \advance\dimen1 by 60pt \vsize \dimen0 \hsize \dimen1 \advance\voffset 30pt\advance\hoffset 30pt \advance\hoffset-1in \advance\voffset-1in \special{papersize=\the\dimen1,\the\dimen0} \noindent\box0 \end'; } else { print WRAP '\nopagenumbers\def\fromgphelp{}' . "\\input $docdir/parimacro.tex" . "\\input $texfile.tex" . '\end'; } close(WRAP) || die "Error closing '$wrap.tex': $!"; close(TEX) || die "Error closing '$texfile.tex': $!"; chdir($tmpdir); $out = `$tex $wrap.tex 2>&1 < /dev/null`; -f "$wrap.dvi" || die "could not create '$wrap.dvi': status=$?, $out"; safe_setsid(); my ($goners) = join(" ", @goners); system("($xdvi $wrap.dvi 2>/dev/null >/dev/null; rm -f $goners; rmdir $tmpdir)&"); } # # Detex Part # sub fit_loop { my($i); return if ($miss > 9 || $#_ <= 0); while ($miss > 0) { # print "1:$miss ";print @_;print "\n"; for (@_) { $miss-- if (s/([?!\.;])$/$1 /); return if ($miss == 0); } # print "2:$miss ";print @_;print "\n"; for (@_) { $miss-- if (s/([?!\.;]) $/$1 /); return if ($miss == 0); } # print "3:$miss ";print @_;print "\n"; for (@_) { $miss-- if (s/([\),])$/$1 /); return if ($miss == 0); } # print "4:$miss ";print @_;print "\n"; $i = 0; for (@_) { if (!$i) { $i = 1; next; } $miss-- if (s/^\(/ (/); return if ($miss == 0); } # print "5:$miss "; print @_;print "\n"; for (@_) { next if (/^ *$/); $miss--; s/$/ /; return if ($miss == 0); } } } sub fit_line { my($wi, @a); my($l) = -1; my($rem) = $_[0]; for (@l) { my ($l2) = $l; $l += ($_ + 1); if ($l > $rem) { $l = $l2; last; } $wi++; } $miss = $rem - $l; splice(@l, 0, $wi); @a = splice(@w, 0, $wi-1); &fit_loop(@a); push(@a, shift(@w)); return join(' ', @a); } # empty output line sub is_void { my($in) = shift; $in =~ s/\@\[\w+\]//g; $in =~ s/\@[012]//g; ($in =~ /^\s*$/)? 1: 0; } sub nl { push(@f_text, shift); } sub split_words { my ($txt) = @_; $txt =~ s/^ +//; for ( split(/\s+/, $txt) ) { s/\Q$tr{nbrk}/ /g; my ($w) = $_; # these codes will be replaced by 1 character s/\@\[(obr|cbr|ldollar|lt|gt|\{|\})]/\@/g; if ($utf8) { s/\@\[(ouml|uuml|agrav|aacute|eacute|pm)]/\@/g; } # one char else { s/\@\[(ouml|uuml|agrav|aacute|eacute)]/\@\@/g; # two chars s/\@\[pm]/+\/-/g; # three chars } # the rest will be replaced by zero-width characters s/\@\[\w+\]//g; my ($l) = length($_); # zero-width word if (!$l && $#w >= 0) { $w[$#w] .= $w; next; } push(@l, $l); push(@w, $w); } # first word might still be zero-width if ($#w >= 1 && !$l[0]) { splice(@w, 0,2, "$w[0]$w[1]"); splice(@l, 0,1); } } sub format_text { my($last_void) = 0; my($noindent) = 0; my($init) = 1; my($cols) = ($ENV{'COLUMNS'} || 80) - 1; my($first) = $cols - length($indent); for (@text) { if (s/^\@1//) # start verbatim { nl(&fit_line($first)) if (@w); nl("") if (!$last_void && !is_void($_)); # add empty line nl("$indent$_"); next; } if (s/^\@0//) # verbatim lines { nl("$indent$_"); next; } if (s/^\@2//) # end verbatim, add indent { nl("") if (!$last_void); $last_void = 1; split_words($_); next; } if (s/^\@3//) # end verbatim + no indent { nl("") if (!$last_void); $noindent = 1; $last_void = 1; split_words($_); next; } if (!is_void($_)) { split_words($_); next; } # line is empty, split out previous paragraph next if (!@l || !$l[0]); # nothing if ($init) { nl(&fit_line($first)); } else { nl("") if (!$last_void); nl("\@[endbold]" . ($noindent? "": $indent) . &fit_line($noindent? $cols: $first)); } while (@w) { nl(&fit_line($cols)); } $noindent = $init = $last_void = 0; } } # argument has the form s1${open}s2${close}s3 # Return 's2'. Set $remainder to 's3'. sub get_match { local ($_, $open, $close) = @_; my (@tmp, $arg,$parity,$ok); my ($obr) = 1; $parity = ($open eq $close); /$open/; $_ = $'; # remove everything before (and including) first $open while ($_) { @tmp = split(/($open|$close)/); while ($#tmp >= 0) { $_ = shift(@tmp); $obr++ if (/^$open$/); if ($parity && $obr == 2) { $ok = 1; last } $obr-- if (/^$close$/); if (!$obr) { $ok = 1; last } $arg .= $_; } last if ($ok); $_ = ; } $remainder = join('',@tmp); return $arg; } sub detex { my($fun); # 1: get the function "prototype" $fun = &get_match($_,'\\{','\\}'); $fun = &basic_subst($fun); $_ = $remainder; $_ = if (!&basic_subst($_)); push(@text, "\@[startbold]$fun:\@[endbold]"); push(@text, ""); # 2: parse the function description if ($_) { s/^ *://; &presubst(); } while () { last if endsection(); &presubst(); } if ($raw) { print join("\n", @text); return; } # for (@text) { print("AA{$_}BB\n"); } # DEBUG &format_text(); for (@f_text) { &TeXprint($_); } } # We use the special char @ to transmit special sequences sub inittr { @ou = qw( dollar nbrk startref endref startbold endbold startcode endcode obr cbr uuml ouml agrave aacute eacute startpodcode endpodcode startlink endlink startbc endbc startbg endbg startbcode endbcode startbi endbi startit endit startword endword startlword endlword pm empty gt lt podleader ); @tr{@ou} = map "\@[$_]", @ou; $tr{dollar} = '$' if $to_pod; %pr = ( dollar => '', ldollar => '$', # literal dollar nbrk => 'S< >', startbold => 'B<', endbold => '>', startcode => 'C<', startlink => 'L<', endlink => '>', endcode => '>', obr => '{', cbr => '}', startpodcode => 'C<', endpodcode => '>', ( $dumb_pod ? (startbcode => 'B<', endbcode => '>', startbi => 'B<', endbi => '>',) : (startbcode => 'B '>>', startbi => 'B '>>')), startbc => 'I<', endbc => '>', startbg => 'B<', endbg => '>', startit => 'I<', endit => '>', startword => 'F<', endword => '>', startlword => ' F<', endlword => '> ', pm => 'F<+->', "gt" => 'E', "lt" => 'E', ouml => 'E', uuml => 'E', eacute => 'E', agrave => 'E', aacute => 'E', empty => 'Z<>', podleader => '=', ); } sub indent_equally { my $in = shift; $in =~ s/^[ \t]*/ /mg; $in } sub quote { my $in = shift; $in =~ s/~/\\~/g; $in } sub basic_subst { local($_) = shift; s/\\teb\{([^\}]*)\}/"\\sidx{$1}$tr{startbold}" . quote($1) . "$tr{endbold}"/eg; s/\\tet\{([^\}]*)\}/"\\sidx{$1}$tr{startcode}" . quote($1) . "$tr{endcode}"/eg; s/\\url\{([^\}]*)\}/"\\sidx{$1}$tr{startcode}" . quote($1) . "$tr{endcode}"/eg; s/\\tev\{([^\}]*)\}/"\\sidx{$1}$tr{startit}" . quote($1) . "$tr{endit}"/eg; s/(\S)[ \t]*\n[ \t]+/$1\n/gm; s/([^\\])\\\{/$1$tr{obr}/g; s/([^\\])\\\}/$1$tr{cbr}/g; s/([^\\])\\-/$1/g; s/\A\\q?quad(?![a-zA-Z])\s*/$tr{nbrk}$tr{nbrk}/; s|\\wwwsite|$wwwsite|g; s/^\\def\\.*\{\n.*\n\}//gm; s/\\def\\.*//g; s(\\footnote\s*\{?\*+\}?\s*\{\s*((?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*)\}) {$tr{startbold}FOOTNOTE$tr{endbold}$tr{lt}$tr{lt}$tr{lt} $1 $tr{gt}$tr{gt}$tr{gt}}g; s/(\{[\w\s]+)\{\}([\s\w]+\})/$1$2/g; # {nf{}init} s(\\op(?![a-zA-Z])\s*)({\\it op\\/})g; # {nf{}init} s/\\emacs\b//; s/\\unix\b//; s/\\(leavevmode|strut)(?![a-zA-Z])\s*//g; s/ \\funno \s* { \s* ((?:[^{}]|\{[^{}]*\})*) } \s* { \s* ((?:[^{}]|\{[^{}]*\})*) } \s* { \s* ((?:[^{}]|\{[^{}]*\})*) } /\\noindent{\\tt $1 \$\\key{$2}\$($3)}/gx; s/\\fun\s*\{([^{}]*)\}\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*\{((?:[^{}]|\{[^{}]*\})*)\}/\\kbd{$1 \\key{$2}($3)}\\sidx{$2}/g; s/\\\\(?=[a-zA-Z])/\\bs /g; s/\\b\{\}\\b\{\}/\\bs\\bs /g; s/\\\\/\\bs/g; s/(\'\'|\`\`)/"/g unless $to_pod; # (english) double quotes # asymptotic or isomorphic (~) [beware of ties] s/(^|[^\\]) +~/$1~/; s/~ */~/; s/(^|[^\\])~/$1$tr{nbrk}/g; # ties s/\\(simeq|sim|approx)(?![a-zA-Z])/ ~ /g; s/\\til(?![a-zA-Z])/~/g; # ~ (transpose) s/\\(~|tilde|widetilde)/~/g; s/\\colon\b/:/g; s/\\(equiv)(?![a-zA-Z])/ = /g; s/\\'a/$tr{aacute}/g; s/\\'\{a\}/$tr{aacute}/g; s/\\`a/$tr{agrave}/g; s/\\`\{a\}/$tr{agrave}/g; s/\\"o/$tr{ouml}/g; s/\\"\{o\}/$tr{ouml}/g; s/\\"u/$tr{uuml}/g; s/\\"\{u\}/$tr{uuml}/g; s/\\'e/$tr{eacute}/g; s/\\'\{e\}/$tr{eacute}/g; s/{\\cal (.)}/$tr{startbc}$1$tr{endbc}/g; s/(^|[^\\])%.*/$1/g; # comments s/\\vadjust\s*\{\s*\\penalty\s*\d+\s*\}//g; # We do not strip %\n, thus: s/\\kbd\{\n\s*/\\kbd{/g; s/\$\\bf(\b|(?=[\d_]))\s*([^\$]+)\$/\$$tr{startbcode}$1$tr{endbcode}\$/g; s/\$/$tr{dollar}/g; # math mode s/\t/ /g; s/\\,//g; s/\\[ ;]/ /g; # various spaces s/\\\///g; # italic correction s/^&+//g; # tab marks s/([^\\])&+/$1 /g; # tab marks s/\\TeX\{\}/TeX/g; s/\\TeX(\W)/TeX$1/g; s/ *\\circ\b */ o /g; s/\\d?frac\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}/($1)\/($2)/g; s(\\d?frac\s*(\d)\s*(\d))(($1/$2))g; s[{\s*(\w)\s*\\over(?![a-zA-Z])\s*(\w)\s*}]{($1/$2)}g; s[{\s*((?:[^{}]|\{[^{}]*\})*)\\over(?![a-zA-Z])\s*((?:[^{}]|\{[^{}]*\})*)}][($1)/($2)]g; # \def\synt#1#2{\syn{#1}{\tt #2}} # \def\syn#1#2{\synx{#1}{#2}{#1}} s/\\synt?\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}/\\synx{$1}{$2}{$1}/g; # \def\synx#1#2#3{\sidx{#3}The library syntax is $\key{#1}({#2})$} # Often used with embedded {}. s/\\synx\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{((?:[^{}]|\{[^{}]*\})*)\}/\\sidx{$3}The library syntax is $tr{startcode}$tr{startbold}$1$tr{endbold}($2)$tr{endcode}/; # May be used with an empty arg s/\\typ\{([^\}]*)\}/$tr{startcode}t_$1$tr{endcode}/g; s/(\\string)?\\_/_/g; s/\\([#\$&%|])/$1/g; s/\\(hat(?![a-zA-Z])|\^)(\{\\?\s*\})?/^/g; s/\\hbox\{\\kbd\{\\pow}}/^/g; # from doc_make s/^(\@\[podleader\]head\d *)\\pow(?![a-zA-z])( *)/$1^$2/gm; s/ *\\pow(?![a-zA-z]) */^/g; s/\\neq?(?![a-zA-Z])/ != /g; s/\\enspace(?![a-zA-Z])/ /g; s/\\\*/ /g; s/\\times(?![a-zA-Z]) */ x /g; s/\\infty(?![a-zA-Z]) */ oo /g; s/ *\\(bmod|mod) */ mod /g; s/ *\\pmod(?![a-zA-Z]) *\{\s*((?:[^{}]|\{[^{}]*\})*)\}/ (mod $1)/g; s/ *\\cdot(?![a-zA-Z]) */./g; # Maybe " . "? s/ *(\\|\@)[lc]?dots(?![a-zA-Z]) */.../g; # math operators s/\\(Norm | Frob | disc | Cl | Re | Im | exp | log | ln | arg | sin(h)? | cos(h)? | tan(h)? | sqrt | lim(proj)? | mod | gcd | lcm | Id | det | Hom | deg | expr | seq | args | min | max ) (?![a-zA-Z])/$tr{startlword}$1$tr{endlword}/xg; # s/\\pi(?![a-zA-Z])/$tr{startword}Pi$tr{endword}/g; # math symbols with HTML entities equivalents s/\\(Alpha | Beta | Chi | Delta | Epsilon | Phi | Gamma | Eta | Iota | vartheta | Kappa | Lambda | Mu | Nu | Omicron | Pi | Theta | Rho | Sigma | Tau | Ypsilon | varsigma | Omega | Xi | Psi | Zeta | alpha | beta | chi | delta | epsilon | varepsilon | phi | gamma | eta | iota | varphi | kappa | lambda | mu | nu | omicron | pi | theta | rho | sigma | tau | ypsilon | varpi | omega | xi | psi | zeta | ell | wp | cap | cup | sup | prod | sum | int | nmid) (?![a-zA-Z])/$tr{startword}$1$tr{endword}/xg; # s/ *\\in(?![a-zA-Z]) */ belongs to /g; s/\\pm(?![a-zA-Z])/$tr{pm}/g; s/ *\\mid(?![a-zA-Z]) */ | /g; s/\\idxtyp\{([^{}]*)\}/\\sidx{t_$1}/g; if (!$to_pod) { s/\\secref\{/Section \\ref{/g; s/\\ref\{([^\}]*)\}/$tr{startref}$1$tr{endref}/g; if ($raw) { s/\\label\{([^\}]*)\}/\@[label $1]/g; } else { s/\\label\{[^\}]*\}//g; } } s/ *\\noindent\b */\@3/; s/\\(medskip|bigskip|smallskip|left|right)(?![a-zA-Z])[ \t]*//g; s/\\vfill *(\\eject)?//g; s/\\(q|quad)(?![a-zA-Z])\s*/ /g; s/\\qquad(?![a-zA-Z])\s*/ /g; s/\\centerline\s*\{\s*(?:\\tt\b\s*)?(.*(\n[ \t].*)*)\}(?=\s*$)/indent_equally($1)/ge; s/\\centerline\s*\{\s*(?:\\tt\b\s*)?((?:[^{}]|\{[^{}]*\})*)\}/ indent_equally($1)/ge; s/\\big\b//g; s/\\settabs.*//; s/^\\\+/\n$tr{nbrk}/gm; s/\\\+//g; s/\\cr(?![a-zA-Z])//g; s/\\B(?![a-zA-Z])/\\kbd{BIL}/g; s/ *([=><]) */ $1 /g; s/ *< *([=<]) */ <$1 /g; s/ *> *([=>]) */ >$1 /g; s/ *([*+-\/^&=|:]) += */ $1= /g; s/ *! *= */ != /g; # now fix spacing s/ == = / === /g; s/< *([-a-zA-Z]*) *>/<$1>/g; s/ *\\Rightarrow */ ==$tr{gt} /g; s/\\rangle(?![a-zA-Z])\s*/$tr{startcode}$tr{gt}$tr{endcode}/g; s/\\langle(?![a-zA-Z])\s*/$tr{startcode}$tr{lt}$tr{endcode}/g; s/\\rightarrow(?![a-zA-Z])\s*/$tr{startcode}--$tr{gt}$tr{endcode}/g; s/\\longleftrightarrow(?![a-zA-Z])\s*/$tr{startcode}$tr{lt}-----$tr{gt}$tr{endcode}/g; s/\\mapsto(?![a-zA-Z])\s*/$tr{startcode}:---$tr{gt}$tr{endcode}/g; s/ *\\geq?(?![a-zA-Z]) *([^ ])/ $tr{startcode}$tr{gt}=$tr{endcode} $1/g; s/ *\\leq?(?![a-zA-Z]) *([^ ])/ $tr{startcode}$tr{lt}=$tr{endcode} $1/g; s/ *\\gg?(?![a-zA-Z]) *([^ ])/ $tr{startcode}$tr{gt}$tr{gt}$tr{endcode} $1/g; s/ *\\ll?(?![a-zA-Z]) *([^ ])/ $tr{startcode}$tr{lt}$tr{ll}$tr{endcode} $1/g; s/\\(vers|PARIversion)(?![a-zA-Z])/$tr{startbold}$version$tr{endbold}/g; s/\\([QRCPFZN])(?![a-zA-Z])/$tr{startbi}$1$tr{endbi}$2/g; s/\\Bbb\b\s*(\w)/$tr{startbi}$1$tr{endbi}/g; s/\\([oc]br)/$tr{$1}/g; s/\\quo(?![a-zA-Z])/\"/g; s/(^|\s)\{(\w+)\}/$1$2/g; s/\\p(?![a-zA-Z])/$tr{startbold}p$tr{endbold}$1/g; s/^ *\\point\{([^\}]*)\}/\\item $1/g; s/\@\[dollar]\\bullet\@\[dollar]/\\item /g; s/\\bullet/\\item/g; s/^ *\\item/\@3$tr{startbold}*$tr{endbold}/g; s/\\item/$tr{startbold}*$tr{endbold}/g; s/^ *\\misctitle\{([^\}]*)\}/\@3$tr{startbold}$1.$tr{endbold}/g; s/\\subsubsec\{([^\}]*)\}/\@3$tr{startbold}$1.$tr{endbold}/g unless $to_pod; s/\\subsec\{([^\}]*)\}/\@3$tr{startbold}$1.$tr{endbold}/g unless $to_pod; s/\\\$/$tr{ldollar}/g; s/\\kbd\s*\{\s*/\\kbd{$tr{gt}/g if $to_pod; s/\\kbd\s*\{((?:[^{}]|\{[^{}]*\})*)\}/$tr{startcode}$1$tr{endcode}/g; s/\\key\{((?:[^{}]|\{[^{}]*\})*)\}/$tr{startbold}$1$tr{endbold}/g unless $refcard; s/\\goth\{((?:[^{}]|\{[^{}]*\})*)\}/$tr{startbg}$1$tr{endbg}/g; if ($refcard) { s/\\(?:key|li)\{((?:[^{}]+(?=[{}])|\{[^{}]*\})*)\}\s*\{\}[ \t]*\n/\n\n=back\n\n$1\n\n=over\n\n/g; s/\\(?:key|li)\{((?:[^{}]+(?=[{}])|\{[^{}]*\})*)\}\s*\{(([^{}]+(?=[{}])|\{[^{}]*\})*)\}/\n=item $tr{startcode}$2$tr{endcode}\n\n$1\n/g; } s/\\(floor|ceil|round|binom)\{/$1\{/g; s/\\(var|emph)\{([^\}]*)\}/$tr{startit}$2$tr{endit}/g; s/\\fl(?![a-zA-Z])/$tr{startit}flag$tr{endit}/g; s/\\b\{([^}]*)\}/$tr{startcode}\\$1$tr{endcode}/g; s/\\kbdsidx/\\sidx/g; s/\\sidx\{[^\}]*\}//g unless $to_pod; s/\\[a-zA-Z]*idx\{([^\}]*)\}/$1/g unless $to_pod; s/\{\\text\{(st|nd|th)\}\}/\\text{$1}/g; s/\^\\text\{th\}/-th/g; s/1\^\\text\{st\}/1st/g; s/2\^\\text\{nd\}/2nd/g; s/\\text\{([a-zA-z0-9]*)\}/$1/g; s/\\(text|hbox|Big)//g; s/([A-Za-z])--([A-Za-z])/$1-$2/g; # Rankin--Cohen s/^([ \t]+)\{ *\\(it|sl|bf|tt)\b/S<$1>{\\$2/gm; s/\{ *\\(it|sl) *(([^{}]+(?=[{}])|\{[^{}]*\})*)\}/$tr{startit}$2$tr{endit}/g; s/\{ *\\bf *(([^{}]+(?=[{}])|\{[^{}]*\})*)\}/$tr{startbold}$1$tr{endbold}/g; s/\{ *\\tt *(([^{}]+(?=[{}])|\{[^{}]*\})*)\}/$tr{startpodcode}$1$tr{endpodcode}/g; $seek=1 if (s/\\emph\{ */$tr{startit}/g); if ($seek) { $seek=0 if (s/\}/$tr{endit}/) } s/\\(backslash|bs)\{(\w)\}/\\$2/g; s/\\(backslash|bs)(?![a-zA-Z]) */\\/g; s/ *\\setminus */ \\ /g; s/\@com(.*)$/$tr{startcode}$1$tr{endcode}/g; # Last resort: s/\\kbd\s*\{(.*?)\}/$tr{startcode}$1$tr{endcode}/g; s/^([ \t]{3,})\Q$tr{startcode}\E(.*)\Q$tr{endcode}\E/$1$2/gmo if $to_pod; # Last resort: s/^([ \t]{3,})\Q$tr{startcode}\E(.*?)\Q$tr{endcode}\E/$1$2/gmso if $to_pod; # Remove leading spaces unless have embedded wrapped code: s/^[ \t]+//gm if $to_pod and /^\S/ and not /^[ \t]*\n[ \t]/m; s/\{ *\}//g; # empty args s{\Q$tr{startcode}\E((ftp|http)://.*?)\Q$tr{endcode}\E}{$tr{startlink}$1$tr{endlink}}go if $to_pod; $_; } sub presubst { chomp; if ($in_prog && /\@eprog *(\\noindent)? */) { my ($eprog) = $1? '@3': '@2'; $in_prog = 0; $_ = $eprog . &code_subst($`) . $tr{endcode}; push(@text, $_); $_ = &basic_subst($'); } elsif ($in_prog || s/\\bprog(tabs.*)?//g) { $in_prog++; # = 1 on the \bprog line # code should start on the next line $_ = &code_subst($_); s/^/\@1$tr{startcode}/ if ($in_prog == 2); s/^/\@0/ if ($in_prog > 2); } else { $_ = &basic_subst($_); } if (/^ *$/) { push(@text,"\n"); } else { for (split(/\n/, $_)) { push(@text, $_); } } } sub code_subst { my $in = shift; $in =~ s/\@dots\b/.../g; if ($in =~ /\@com(.*)/) { my ($c) = &basic_subst($1); if (!$to_pod) { $c = $tr{endcode} . $c . $tr{startcode}; } $in = $` . $c . &code_subst($'); } if ($in =~ /\@Ccom(.*)\*\//) { my ($c) = &basic_subst($1); if (!$to_pod) { $c = $tr{endcode} . $c . $tr{startcode}; } $in = $` .$c . "*/" . &code_subst($'); } $in; } sub wrap_code { my $in = shift; $in =~ s/^[ \t]+$//mg; $in = &code_subst($in); $in =~ s/^(.)/ $1/mg; $in =~ s/\s*\Z//; # $in =~ s/\\kbd\{((?:[^{}]|\{[^{}]*\})*)\}/$1/g if $to_pod; $in =~ s/\$([^\$\n]*)\$/$1/g if $to_pod; "\n\n$in\n\n"; } sub indexify { my $in = shift; $in =~ s/(^|and\s+)(\w+)(\$?\()/$1\\idx{$2}$3/g; $in =~ s/^(\\b\{\w+\})(?!\S)/\\idx{$1}/g; $in; } sub for_index { my $in = shift; 1 while $in =~ s/\Q$tr{startcode}\E(.*?)\Q$tr{endcode}\E/$1/go; $in; } sub strip_trail { my $in = shift; $in =~ s/\s+\Z//; $in } # This subroutine works in paragraph mode sub TeXprint_topod { s/\A\s+//; s/^\\def\\.*\{\n.*\n\}//gm; s/\\def\\.*//g; # Repeated in basic_subst, as the next one s/(\{[\w\s]+)\{\}([\s\w]+\})/$1$2/g; # {rnf{}llgram} s/\\vbox\s*\{\s*\\bprog/\\bprog/g; s/([\\\@])eprog\s*\}/$1eprog/g; # \n is below to prevent splitting on ' ' # We also remove ':' s/\\sectype\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}/\\subsec{Type \\typ{$1} (${2}s)}\n\\sidx{$2}/g; s/\\sectypeindex\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}/\\subsec{Type \\typ{$1} (${2}s)}\n\\sidx{$3}/g; s/\\sectypes\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}/\\subsec{Type \\typ{$1} and \\typ{$1} (${3}s)}\n\\sidx{$3}/g; # Try to guard \label/\sidx (removing possible '.') # This somehow breaks index... # s/(\\(?:section|subsec(?:ref|idx|op)?(unix)?)\s*{(?:(?:[^{}]+(?=[{}])|{[^{}]+})+)})\.?\s*\\(label|sidx)/$1\n\\$2/; s/(\\(?:section|subsec(?:ref|idx|op)?)\s*\{(?:(?:[^{}]+(?=[{}])|{[^{}]+})+)\})\.?\s*\\(label|sidx)/$1\n\\$2/; # last if /\\subsec[\\{}ref]*[\\\${]$help[}\\\$]/o; s/\\chapter\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*/\n\n$tr{podleader}head1 NAME\n\nlibPARI - $1\n\n/; s/\\appendix\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*/\n\n$tr{podleader}head1 NAME\n\nAppendix - $1\n\n/; s/\\section\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*/"\n\n$tr{podleader}head1 " . indexify($1) . "\n\n"/e; # Try to delimit by : s/\\subsec(?:ref)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]+})+)\}([^\n]*):[\n ]/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; s/\\subsubsec(?:ref)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]+})+)\}([^:]*):\s*/"\n\n$tr{podleader}head3 " . indexify("$1$3") . "\n\n"/e; s/\\subsubsec\s*{(([^{}]+(?=[{}])|{[^{}]+})+)}(.*)$/"\n\n$tr{podleader}head3 " . indexify("$1") . "$3\n\n"/me; s/\\subseckbd\s*{(([^{}]+(?=[{}])|{[^{}]+})+)}([^:]*):\s*/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; # Try to delimit by ' ' s/\\subsec(?:ref)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]+})+)\}(\S*)\s+/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; s/\\subsec(?:title)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]*})+)\}:?\s*/"\n\n$tr{podleader}head2 " . indexify("$1") . "\n\n"/e; # This is to skip preface in refcard: /\Q$tr{podleader}\Ehead1|\\title(?![a-zA-Z])\s*\{/o and $seen_start = 1 or $seen_start or return; # Skip now! s/\\title\s*\{([^{}\s]*)(\s+([^{}]*))?\}(\s*\\centerline\s*\{([^{}]*)\})?\s*/$tr{podleader}head1 NAME\n\n$1 - $3. $5\n\n/ and $seen_title++ unless $seen_title; s/\\title\s*\{([^{}\s]*)(\s+([^{}]*))?\}(\s*\\centerline\s*\{([^{}]*)\})?\s*/\n\n/; s/\\parskip.*/\n/g; # Up to end of the line #s/([A-Z])\ until /(\\|@)eprog\b/ or eof(DOC); $acc .= wrap_code($1) if s/\A(?:tabs[^\n]*)?(?![a-zA-Z])[ \t]*\n?(.*?)(\\|@)eprog\s*//s; } $_ = $acc . basic_subst($_); # s/\\kbd\{/\{\\tt /g; # startcode # s/\\typ\{/\{\\tt t_/g; # startcode s/\$\s*(\@\[startbi\][A-Z]\@\[endbi\])\s*\$/$1/g; # s/\\p(\b|(?=[\d_]))/B

/g; #s/\$\\bf\b\s*([^\$]+)\$/C>/g; @lines = split /^$/m, $_; for (@lines) { s/>/\@[gt]/g unless /^\n*[ \t]/; s/$tr{startcode}$1$tr{endcode}\n\n/gs; s/\$([^\$]+)\$/$tr{startcode}$1$tr{endcode}/g; s/\\s(?:ref|idx)\{\s*([^{}]*)\}/"X<" . for_index($1) . ">"/ge; # s/\\(?:ref|idx)\{\s*([^{}]*)\}/"X<" . for_index($1) . ">$1"/ge; # Conflict between different versions of PARI and refcard: # s/\\(?:key|li)\s*\{(.*)\}\s*\{(.+)\}[ \t]*\n/\n\n=item C<$2>\n\n$1\n\n/msg; # s/\\(?:key|li)\s*\{(.*)\}\s*\{\}[ \t]*\n/\n\n=back\n\n$1\n\n=over\n\n/mgs; # s/\\(key|var)(?![a-zA-Z])\s*\{(\w+)\}/C<$2>/mg; s/\\var\s*\{X<(\w+)>(\w+)\}/X<$1>$tr{startcode}$2$tr{endcode}/mg; s/\\var\s*\{f\{\}lag\}/$tr{startcode}flag$tr{endcode}/mg; s/\\metax(?![a-zA-Z])\s*\{(.*)\}\s*\{\s*(\w+)(?=C\<)(.*)\}[ \t]*\n/\n\n=item C$3>\n\n$1\n\n/mg; s/\\metax(?![a-zA-Z])\s*\{(.*)\}\s*\{(.*)\}[ \t]*\n/\n\n=item C<$2>\n\n$1\n\n/mg; s/C\<\{\}=/C\<=/g; s/\\fl(?![a-zA-Z])/I/g; s/\\file(?![a-zA-Z])/F/g; s/\\(unix|emacs)\b\s*(\{?)(\s*\\(no)?indent)?\s*/X<\U$1>$2/g; s/\A\\label\s*\{([\w:.-]*)\}([ \t]*\n\s*(?=[^\s=]))?/X

] Options: some names can be abbreviated to one character (e.g -h = -help) -a, --ask interactive configuration -h, --help this message -l, --load skip Configure and specify a default config file -s, --static build static GP binary only -v, --verbhelp a longer help message Build Options: --host= target achitecture --kernel= kernel used --graphic= graphic library used (none, X11, Qt, fltk, ps, svg, win32) --time= timing function to use (getrusage, clock_gettime, times, ftime) --builddir= directory where the object files will be created --tune tune the binary for compiling host (slow) Additional developer options: -g creates debugging version (in Oxxx.dbg) -pg creates profiling version (in Oxxx.prf) -gcov creates gcov version (in Oxxx.gcov) --enable-tls (*experimental*) enable thread-local stack --mt=pthread (*experimental*) enable pthread thread engine --mt=mpi (*experimental*) enable MPI thread engine --disable-mmap (*troubleshooting*) disable mmap usage Installation directories: --prefix= install files in (default $prefix) --share-prefix= as 'prefix', for architecture independent files --bindir= for binaries --includedir= for C header files --libdir= for libraries --mandir= for manual pages --sysdatadir= for architecture-dependent data --datadir= for architecture-independent data Optional libraries: --without-readline do not link with GNU readline --with-readline[=DIR] use GNU readline [prefix for readline files] --with-readline-include=DIR specify location of readline headers --with-readline-lib=DIR specify location of readline libs --with-ncurses-lib=DIR specify location of ncurses lib (for readline) --without-gmp use the native kernel instead of GNU MP --with-gmp[=DIR] use the GMP kernel [prefix for gmp files] --with-gmp-include=DIR specify location of gmp headers --with-gmp-lib=DIR specify location of gmp libs --with-qt[=DIR] use the Qt graphical library [prefix for Qt dir.] --with-qt-include=DIR specify location of Qt headers --with-qt-lib=DIR specify location of Qt libs --with-fltk use the FLTK graphical library [need fltk-config] Miscellaneous --with-runtime-perl[=path-to-perl-binary] for gphelp / tex2mail Environment variables affecting the build: CC C compiler CFLAGS additional flags to the C compiler LD linker LDFLAGS additional linker flags DLLDFLAGS additional linker flags for linking the shared lib C_INCLUDE_PATH directories to search for include files (separate by :) LIBRARY_PATH directories to search for libraries (separate by :) EOT exit 1 ;; verb) cat >&2 < #include #include main(){ struct tms t; printf("%d%d", times(&t), #ifdef _SC_CLK_TCK sysconf(_SC_CLK_TCK) #else CLK_TCK #endif ); } pari-2.11.2/config/settar0000755000175000017500000000146013201017466013654 0ustar billbill#!/bin/sh dir=$1; status=$2; # true status (probably 'snapshot') STATUS=$3; # status we're being coerced into case "$STATUS" in alpha|beta) dir="$dir.$STATUS";; snapshot) STATUS="development git-"`git log -1 --pretty=format:%h`; dir=`git describe` case $dir in pari-*);; *) dir=pari-$dir;; esac ;; esac if test -d $dir; then echo "Remove $dir before building a new release"; exit 1 fi tarfile=$dir.tar tar cf $tarfile `config/get_MANIFEST` mkdir $dir && mv $tarfile $dir cd $dir && tar xf $tarfile && rm -f $tarfile && cd .. if test "$status" != "$STATUS"; then v=$dir/config/version mv $v $v.old sed -e "s/^stat=.*/stat=\'$STATUS\'/" $v.old > $v rm -f $v.old fi tar cf $tarfile $dir rm -rf $dir rm -f $tarfile.gz gzip $tarfile pari-2.11.2/config/pari.nsi.SH0000644000175000017500000000034513201017466014404 0ustar billbillcfg=$config_dir obj=$objdir file="$obj/pari.nsi" case "$sizeof_long" in 4) bitsize=32;; 8) bitsize=64;; esac; if [ -f "$cfg/$osname-pari.nsi" ]; then echo "Extracting $file" "$cfg/$osname-pari.nsi" $bitsize > "$file" fi pari-2.11.2/config/get_PATH0000644000175000017500000000135711636712103013747 0ustar billbillif test -z "$OS2_SHELL"; then dir_sep=':' ; else dir_sep=';' ; fi # Proper PATH setting pth="\ /bin\ /usr/bin\ /usr/locateal/bin\ /usr/ucb\ /usr/locateal\ /usr/lbin\ /usr/5bin\ /etc\ /usr/etc\ /usr/gnu/bin\ /usr/new\ /usr/new/bin\ /usr/nbin\ /sys5.3/bin\ /sys5.3/usr/bin\ /bsd4.3/bin\ /bsd4.3/usr/ucb\ /bsd4.3/usr/bin\ /usr/bsd\ /bsd43/bin\ /opt/ansic/bin\ /usr/ccs/bin\ /usr/lib\ /usr/ucblib\ /lib\ /usr/ccs/lib\ /sbin\ /usr/sbin\ /usr/libexec\ /usr/openwin/bin\ /usr/local/bin\ " # /usr/openwin/bin added for xmkmf for p in $pth do case "$dir_sep$PATH$dir_sep" in *$dir_sep$p$dir_sep*) ;; *) test -d $p && PATH=$PATH$dir_sep$p ;; esac done PATH=.$dir_sep$PATH; export PATH pari-2.11.2/config/make_tags0000755000175000017500000000407512314242551014311 0ustar billbilleval 'exec perl "$0" "$1" "$2"' if $running_under_some_shell; use File::Find 'find'; # Build a (sorted) EMACS / VI(M) tags file including GP functions # $emacs_mode = ($ARGV[0] eq "--emacs"); $src = $ARGV[1]; if ($emacs_mode) { $tags = "$src/TAGS"; } else # Case sensitive? { $tags = $^O eq 'os2' ? "$src/ctags" : "$src/tags"; } $tmptags = "$tags.tmp"; my (%gp); getnames("$src/gp/gp_init.h"); getnames("$src/language/init.h"); my (@files) = (); find \&filter_c, $src; @tags = ""; if ($emacs_mode) { system('exuberant-ctags', '-e', '-f', $tmptags, @files) && system('ctags-exuberant', '-e', '-f', $tmptags, @files) && system('etags', '-f', $tmptags, @files) && die("etags failed"); open(T,"$tmptags"); while() { my ($a,$b); $a = $_; if (/^(\w+)\(/ && ($b = $gp{$1}) && $b ne $1) { $a =~ s/\x7F.*\x01/\x7F$b\x01/; push(@tags,$a); } push(@tags,$_); } } else { system('exuberant-ctags', '-f', $tmptags, @files) && system('ctags-exuberant', '-f', $tmptags, @files) && system('ctags', '-dT', '-o', $tmptags, @files) # gctags && system('ctags', '-f', $tmptags, @files) && die("ctags failed"); open(T,"$tmptags"); # Assume ctags outputs sorted tags (e.g Exuberant Ctags) my ($old) = ""; for (sort(keys %gp)) { my ($a) = $_; my ($b) = $gp{$a}; if ($a eq $old) { push(@tags,"$b$rest\n"); next; } $old = $a; while() { push(@tags,$_); if (/^$a(.*)/) { $rest="$1"; push(@tags,"$b$rest\n"); last; } } } while() { push(@tags,$_); } @tags = sort(@tags); } close(T); open(OUT,">$tags"); print OUT @tags; unlink $tmptags; # $gp{GP_function} = C_function sub getnames { open(A,$_[0]); while () { if (/^entree functions_/../^$/) { if (/[^"]*"([^"]*)".*\(void\*\) *([^,]*)/) { my ($gpfun, $cfun) = ($1,$2); $gpfun =~ s/_\.//g; # member functions $gp{$cfun} = $gpfun; } } } close(A); } sub filter_c { return unless /\.[chy]\Z/ && -f; return if (/(dummy|tune|kerntest|parse)\.c/); push @files, "$File::Find::name"; } pari-2.11.2/config/get_graphic_lib0000644000175000017500000000427713326135265015470 0ustar billbillif test "$optimization" = profiling; then which_graphic_lib=none fi _graphic_list="which_graphic_lib X11 X11_INC X11_LIBS \ FLTK_LIBS QTDIR QTLIB" if test -n "$with_fltk"; then which_graphic_lib=fltk; fi if test -n "$with_qt"; then which_graphic_lib=Qt; fi if test "$fastread" != yes; then cat << EOT ========================================================================== GP contains high resolution plotting functions. Choose among none X11 fltk Qt win32 ps svg EOT echo $n ..."Use which graphic library (\"none\" means no hi-res plot) ? $c" rep="none X11 fltk Qt win32 ps"; dflt=$which_graphic_lib; . ./myread which_graphic_lib=$ans fi case $osname in mingw|cygwin) case $which_graphic_lib in auto) which_graphic_lib=win32;; esac;; esac case $which_graphic_lib in auto|X11|x11) . ./get_X11 # X11,X11_INC,X11_LIBS. if test -z "$X11_LIBS"; then case $which_graphic_lib in X11|x11) which_graphic_lib=none;; esac else which_graphic_lib=X11 fi;; esac case $which_graphic_lib in auto|fltk) case $osname in darwin) ;; # fltk brings in CoreFoundation, incompatible with pari_daemon *). ./get_fltk # FLTK_LIBS ;; if test -z "$FLTK_LIBS"; then case $which_graphic_lib in fltk) which_graphic_lib=none;; esac else which_graphic_lib=fltk fi;; esac;; esac # TODO: Check whether Qt + pari_daemon() work on darwin [ probably not ] case $which_graphic_lib in Qt|qt) . ./get_Qt # QTDIR, QTLIB if test -z "$QTDIR"; then case $which_graphic_lib in qt|Qt) which_graphic_lib=none;; esac # Never automatically pick Qt fi;; esac case $which_graphic_lib in auto|svg) which_graphic_lib=svg;; esac case $which_graphic_lib in auto|PS|ps) which_graphic_lib=ps;; esac case $which_graphic_lib in X11|fltk|Qt4|ps|svg) if test "$has_waitpid" = no -o "$has_setsid" = no; then echo "### Missing waitpid() or setsid(), no Hi-Res graphing window" which_graphic_lib=none fi;; esac case $osname in linux|gnu*|*bsd) gp_mime_open="xdg-open";; darwin) gp_mime_open="open -W";; esac echo "Hi-Res Graphics: $which_graphic_lib" pari-2.11.2/config/has_getrusage.c0000644000175000017500000000033512314242551015410 0ustar billbill#define _INCLUDE_POSIX_SOURCE #include #include #include #include #include int main(){ struct rusage a; printf("%d",getrusage(RUSAGE_SELF,&a)); return 0; } pari-2.11.2/config/Makefile.SH0000644000175000017500000005205313326135265014407 0ustar billbillfile=$objdir/Makefile echo Extracting $file rm -f $file # Path to directories cfg=../$config_dir data=../$data_dir doc=../$doc_dir desc=../$desc_dir ex=../$examples_dir misc=../$misc_dir src=../$src_dir knone=$src/kernel/none kern0=$src/kernel/$kernlvl0 kern1=$src/kernel/$kernlvl1 if test -n "$add_funclist"; then add_funclist=$src/funclist fi # # File lists # kernel="mpker mpinl" gp=`ls $src_dir/gp/*.c | sed 's,.*/\(.*\)\.c,\1,'` language=`ls $src_dir/language/*.c | sed 's,.*/\(.*\)\.c,\1,'` basemath=`ls $src_dir/basemath/*.c | sed 's,.*/\(.*\)\.c,\1,'` modules=`ls $src_dir/modules/*.c | sed 's,.*/\(.*\)\.c,\1,'` mt="mt $thread_engine" systems= if test -d "$src_dir/systems/$osname"; then systems=`ls $src_dir/systems/$osname/*.c | sed 's,.*/\(.*\)\.c,\1,'` fi # remove paridecl: no general recompilation when only changing a prototype hlist=`ls $src_dir/headers/*.h | grep -v paridecl | grep -v paripriv |\ sed 's,.*/\(.*\)\.h,\1,'` # for installation put paridecl back. Remove \n otherwise make will choke. headerlist="paridecl paripriv `echo $hlist| tr '\n' ' '`" #Add src/language/parse.c if it is not yet generated case $language in *parse*);; *) language="$language parse";; esac # special systems (OS/2 for now) shortlib_prefix=lib lib_prefix=lib dllib_prefix=lib case "$osname" in os2) shortlib_prefix= # 8.3 filenames dllib_prefix= # != lib_prefix to allow gp-dyn link with DLL export_lib_create=emximp; export_lib='$(DLLIBPARI)$(_A)' export_file=pari.def; export_create="emxexp -u" # Actually, the build will fail until the switch to -Zomf dlld_ignore=- ;; mingw) export_file='$(LIBPARI).def';; darwin) ld_install_name="-Wl,-install_name -Wl,\"$libdir\"/\$(LIBPARI_DYN)";; esac case "$osname" in mingw|cygwin) install_implib="\$(INSTALL_DATA) \$(LIBPARI_SO)\$(_A) \$(LIBDIR)/\$(LIBPARI_SO)\$(_A)";; *) install_implib="";; esac PLOTCFLAGS= PLOTLIBS= postconfig=: plotrunpath= case "$which_graphic_lib" in ps|svg|none) graph=plot$which_graphic_lib;; Qt4) PLOTCFLAGS="\$(QTINC)" PLOTLIBS="\$(QTLIB) $QTLIBS" graph=plotQt4;; fltk) PLOTCFLAGS= PLOTLIBS="$FLTK_LIBS" postconfig='fltk-config --post ' graph=plotfltk;; win32) PLOTLIBS="-lgdi32" graph=plotWin32;; X11) PLOTCFLAGS="$PLOTCFLAGS $X11_INC" PLOTLIBS="$PLOTLIBS $X11_LIBS" plotrunpath=$X11 graph=plotX;; *) echo >&2 "### Unrecognized graphic library '$which_graphic_lib'." exit 1;; esac libgraph="plotport plottty" KERNOBJS= for f in $kernel; do KERNOBJS="$KERNOBJS $f\$(_O)" done OBJS=$KERNOBJS for f in $basemath $language $modules $systems $mt $libgraph; do OBJS="$OBJS $f\$(_O)" done OBJSGP= for f in $gp $graph; do OBJSGP="$OBJSGP $f\$(_O)" done HEADERS="mpinl.h parimt.h" for f in $hlist; do HEADERS="$HEADERS $src/headers/$f.h"; done graph="$graph $libgraph" # runpath tmp=$runpath for d in "$plotrunpath" "$gmp" "$readline"; do case "$d" in ""|yes) ;; *) case "$tmp" in $d|*$dir_sep$d|*$dir_sep$d$dir_sep*);; *) tmp="$tmp$dir_sep$d";; esac ;; esac done RUNPTH_FINAL= RUNPTH= if test -n "$runpathprefix"; then RUNPTH_FINAL=`$config_dir/ldflags "$LDneedsWl" $runpathprefix"$tmp"` RUNPTH=`$config_dir/ldflags "$LDneedsWl" $runpathprefix\\\$\(TOPDIR\)/$objdir$dir_sep"$tmp"` fi if test -z "$DLLD"; then exec="gp-sta$exe_suff"; static=y else exec="gp-sta$exe_suff gp-dyn$exe_suff" fi case "$sizeof_long" in 4) numbits=32;; 8) numbits=64;; esac dotest="env \"RUNTEST=\$(RUNTEST)\" \"LD_LIBRARY_PATH=.$dir_sep\$\$LD_LIBRARY_PATH\" \$(SHELL) ../src/test/dotest $numbits \"$exe_suff\"" case "$static" in n) dft=dyn; libdft=lib-dyn;; y) dft=sta; libdft= ;; esac CPPFLAGS="-I. -I$src/headers" if test "$has_dlopen" = builtin; then CPPFLAGS="$CPPFLAGS -I$src/systems/$osname" fi case "$ln_s" in *cp*) ln_objdir=".";; *) ln_objdir="$objdir" esac cat > $file << EOT # Makefile for Pari/GP -- $pretty # # This file was created by Configure. Any change made to it will be # lost when Configure is run. # TOPDIR="$TOP" SHELL = $make_sh PERL = $perl BISON = bison AR = ar RANLIB = ranlib SIZEOF_LONG= $sizeof_long CC_FLAVOR = CC = $CC \$(CC_FLAVOR) CPPFLAGS = $CPPFLAGS CFLAGS = $CFLAGS DLCFLAGS = $DLCFLAGS KERNELCFLAGS = $KERNELCFLAGS LD_FLAVOR = \$(CC_FLAVOR) LD = $LD \$(LD_FLAVOR) LDFLAGS = $LDFLAGS DLLD_FLAVOR = \$(LD_FLAVOR) DLLD = $DLLD \$(DLLD_FLAVOR) DLLDFLAGS = $DLLDFLAGS EXTRADLLDFLAGS = $EXTRADLLDFLAGS RUNTEST = $RUNTEST # HIGHLY EXPERIMENTAL (only tested with gmp-4.0 on ix86 and Ultra). # If you've configured and compiled GMP and would like to tune PARI using # the nice cycle counting functions in GMP, uncomment the 4 lines below # (correct the first one to the path to your gmp source tree). # #GMP = /some/directory/gmp-4.0/tune #GMPFLAGS= -DGMP_TIMER #GMPO1 = \$(GMP)/time.o \$(GMP)/freq.o #GMPOBJS=\$(GMPO1) \$(GMPO2) # #You may need to add a few object files to GMPOBJS. On UltraSparc, uncomment #the following line #GMPO2 = \$(GMP)/sparcv9.o _O = .o _A = .a LIB_PREFIX = $lib_prefix DLLIB_PREFIX = $dllib_prefix LIBPARI_BASE = $libpari_base LIBPARI = \$(LIB_PREFIX)pari DLLIBPARI = \$(DLLIB_PREFIX)pari LIBPARI_STA = \$(LIBPARI)\$(_A) LIBPARI_SO = \$(DLLIBPARI).$DLSUFFIX SOLIBPARI = \$(DLLIB_PREFIX)\$(LIBPARI_BASE).$DLSUFFIX LIBPARI_DYN = \$(SOLIBPARI)$sodest LIBPARI_SONAME= \$(SOLIBPARI)$soname DL_DFLT_NAME = $DL_DFLT_NAME LD_INSTALL_NAME = $ld_install_name EXPORT_FILE = $export_file EXPORT_CREATE = $export_create EXPORT_LIB = $export_lib EXPORT_LIB_CREATE = $export_lib_create DLLD_IGNORE = $dlld_ignore DLLTOOL = $DLLTOOL RUNPTH = $RUNPTH RUNPTH_FINAL = $RUNPTH_FINAL LDDYN = $LDDYN LIBS = $LIBS GMPLIBS = $GMPLIBS MT_LIBS = $MT_LIBS RT_LIBS = $RT_LIBS DL_LIBS = $DL_LIBS DYN_LIBS = \$(GMPLIBS) \$(DL_LIBS) \$(RT_LIBS) \$(MT_LIBS) \$(LIBS) STA_LIBS = \$(GMPLIBS) \$(DL_LIBS) \$(RT_LIBS) \$(MT_LIBS) \$(LIBS) RM = rm -f MV = mv -f LN = $ln_s CP_F = cp -f STRIP = strip STRIPFLAGS = # Change these installation directories to suit your needs. # DESTDIR is used to install to a false hierachy (to build a Debian package) INCLUDEDIR= "\$(DESTDIR)$includedir" LIBDIR = "\$(DESTDIR)$libdir" BINDIR = "\$(DESTDIR)$bindir" MANDIR = "\$(DESTDIR)$mandir" DATADIR = "\$(DESTDIR)$datadir" SYSDATADIR= "\$(DESTDIR)$sysdatadir" EXDIR = \$(DATADIR)/examples MISCDIR = \$(DATADIR)/misc DOCDIR = \$(DATADIR)/doc INSTALL = $cfg/install INSTALL_PROGRAM = \$(INSTALL) INSTALL_DATA = \$(INSTALL) -m 644 # Readline RLINCLUDE = $RLINCLUDE RLLIBS = $RLLIBS # GMP GMPINCLUDE = $GMPINCLUDE # Graphic library. QTMOC = $QTMOC QTINC = $QTINC QTLIB = $QTLIB PLOTCFLAGS = $PLOTCFLAGS PLOTLIBS = $PLOTLIBS CXX = g++ TOPLDDYN = "$TOP/$objdir" # Description system DESC = pari.desc DESC_HELP_GEN = $desc/gen_proto $desc/PARI/822.pm TMPSUF = $osname-$arch.tmp DOTEST=$dotest OBJS = $OBJS OBJSGP = $OBJSGP TESTS = $test_extra .PHONY: gp dft clean gp: gp-$dft ../gp$suffix$exe_suff $libdft ../gp$suffix$exe_suff: gp-$dft$exe_suff -\$(RM) \$@ -\$(LN) $ln_objdir/gp-$dft$exe_suff \$@ all: $exec lib-sta lib-sta: \$(LIBPARI_STA) lib-dyn: \$(LIBPARI_DYN) \$(LIBPARI_STA): $add_funclist \$(OBJS) -\$(RM) \$@ \$(AR) r \$@ \$(OBJS) -\$(RANLIB) \$@ kerntest\$(_O): $src/test/kerntest.c \$(CC) -c -I$src/language \$(CPPFLAGS) \$(CFLAGS) -o \$@ $src/test/kerntest.c dummy\$(_O): $src/test/dummy.c \$(CC) -c \$(CPPFLAGS) \$(CFLAGS) -o \$@ $src/test/dummy.c kerntest: $KERNOBJS dummy\$(_O) kerntest\$(_O) \$(CC) \$(CPPFLAGS) \$(CFLAGS) -o \$@ $KERNOBJS dummy\$(_O) kerntest\$(_O) \$(STA_LIBS) mpinl\$(_O): .headers parilvl0.h parilvl1.h $knone/mpinl.c \$(CC) -c \$(CPPFLAGS) \$(CFLAGS) \$(DLCFLAGS) -o mpinl\$(_O) $knone/mpinl.c test-kernel:: kerntest @./kerntest > gp.out;\ diff -c gp.out $src/test/32/kernel > kern.dif;\ if test -s kern.dif; then echo "KERNEL BUG"; else echo OK; fi tune\$(_O): .headers $src/test/tune.c \$(CC) \$(GMPFLAGS) \$(CPPFLAGS) \$(CFLAGS) -o \$@ $src/test/tune.c -c tune: mpinl.h tune-sta -\$(RM) tune ../tune -\$(LN) tune-sta tune -\$(LN) $ln_objdir/tune ../tune tune-dyn: tune\$(_O) \$(LIBPARI_DYN) \$(LD) -L. \$(LDFLAGS) \$(RUNPTH) -o \$@ \$< \$(GMPOBJS) \$(LDDYN) \$(STA_LIBS) tune-sta: tune\$(_O) \$(LIBPARI_STA) \$(LD) \$(LDFLAGS) \$(RUNPTH) -o \$@ \$< \$(GMPOBJS) ./\$(LIBPARI_STA) \$(STA_LIBS) gp-sta$exe_suff: $add_funclist \$(OBJS) \$(OBJSGP) \$(RM) \$@ \$(LD) -o \$@ \$(LDFLAGS) \$(OBJS) \$(OBJSGP) \$(RUNPTH) \$(RLLIBS) \$(PLOTLIBS) \$(STA_LIBS) $postconfig gp-sta$exe_suff clean_pari_ps:: @-\$(RM) pari.ps cleantest: \$(RM) *.dif gp.out io-testfile pari.ps cleanobj: -\$(RM) *\$(_O) mpker.c *.s parimt.h mpinl.h parilvl0.h parilvl1.h libpari* $exec kerntest -\$(RM) gmon.out -\$(RM) *.gcno *.gcda cleandesc: -\$(RM) $desc/\$(DESC) *\$(TMPSUF) cleantune: -\$(RM) tune tune-sta tune\$(_O) cleanall: cleanobj cleantune cleantest cleandesc clean: cleanall # Use this version to avoid problems with NFS and slightly out of synch # fileserver/host. We are recompiling everything anyway. Not on by default: # 3s is slower than the whole compilation on our development server :-) # .headers: $HEADERS # @sleep 3; touch \$@ .headers: $HEADERS @touch \$@ install-nodata: install-lib-$dft install-include install-bin install-man install-misc install-examples install-cfg install: install-doc install-nodata install-data install-include: -mkdir -p \$(INCLUDEDIR)/pari -for i in paricfg.h mpinl.h parimt.h; do \\ \$(INSTALL_DATA) \$\$i \$(INCLUDEDIR)/pari; done -for i in $headerlist; do \\ \$(INSTALL_DATA) $src/headers/\$\$i.h \$(INCLUDEDIR)/pari; done -\$(RM) \$(INCLUDEDIR)/pari/genpari.h -\$(LN) pari.h \$(INCLUDEDIR)/pari/genpari.h install-bin: install-bin-$dft install-bin-dyn: gp-dyn$exe_suff install-lib-dyn -mkdir -p \$(BINDIR) -\$(RM) \$(BINDIR)/gp-$version$exe_suff \$(BINDIR)/gp$exe_suff \$(LD) -o \$(BINDIR)/gp-$version$exe_suff -L\$(LIBDIR) \$(LDFLAGS) \$(OBJSGP) \$(RUNPTH_FINAL) \$(LDDYN) \$(RLLIBS) \$(PLOTLIBS) \$(LIBS) -\$(STRIP) \$(STRIPFLAGS) \$(BINDIR)/gp-$version$exe_suff -cd \$(BINDIR); $postconfig gp-$version$exe_suff -\$(LN) gp-$version$exe_suff \$(BINDIR)/gp$exe_suff install-bin-sta: gp-sta$exe_suff -mkdir -p \$(BINDIR) -\$(RM) \$(BINDIR)/gp-$version$exe_suff \$(BINDIR)/gp$exe_suff \$(INSTALL_PROGRAM) gp-sta$exe_suff \$(BINDIR)/gp-$version$exe_suff -\$(LN) gp-$version$exe_suff \$(BINDIR)/gp$exe_suff # Can't strip it if we want install() to work on OSF. # -\$(STRIP) \$(STRIPFLAGS) \$(BINDIR)/gp-$version -cd \$(BINDIR); $postconfig gp-$version$exe_suff install-man:: -mkdir -p \$(MANDIR) -\$(RM) \$(MANDIR)/pari.1 \$(MANDIR)/gp.1 \$(MANDIR)/gp-$version.1 \$(INSTALL_DATA) $doc/gphelp.1 \$(MANDIR) \$(INSTALL_DATA) $doc/gp.1 \$(MANDIR)/gp-$version.1 -\$(LN) gp.1 \$(MANDIR)/pari.1 -\$(LN) gp-$version.1 \$(MANDIR)/gp.1 install-misc: -mkdir -p \$(MISCDIR) \$(BINDIR) \$(INSTALL_PROGRAM) $misc/tex2mail \$(BINDIR) \$(INSTALL_DATA) $doc/tex2mail.1 \$(MANDIR) \$(INSTALL_DATA) $misc/README \$(MISCDIR) \$(INSTALL_DATA) $misc/color.dft \$(MISCDIR) \$(INSTALL_DATA) $misc/gpalias \$(MISCDIR) \$(INSTALL_PROGRAM) $misc/gpflog \$(MISCDIR) \$(INSTALL_DATA) $misc/gprc.dft \$(MISCDIR) \$(INSTALL_PROGRAM) $misc/xgp \$(MISCDIR) install-cfg:: -mkdir -p \$(SYSDATADIR) -\$(INSTALL_DATA) pari.cfg \$(SYSDATADIR) -if test -n "$add_funclist"; then\ mkdir -p \$(DATADIR)/PARI;\ \$(INSTALL_DATA) $desc/PARI/822.pm \$(DATADIR)/PARI;\ \$(INSTALL_DATA) $desc/\$(DESC) \$(DATADIR); fi install-doc: install-docdvi install-doctex install-doctex: -mkdir -p \$(BINDIR) \$(DOCDIR) -\$(INSTALL_DATA) $doc/translations \$(DOCDIR) -\$(INSTALL_PROGRAM) $doc/gphelp \$(BINDIR) -cd $doc; \$(MAKE) usersch3.tex -\$(INSTALL_DATA) $doc/appa.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/appb.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/appd.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/parimacro.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/pdfmacs.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/develop.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/refcard.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/tutorial.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/tutorial-mf.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/users.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch1.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch2.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch3.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch4.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch5.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch6.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch7.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/usersch8.tex \$(DOCDIR) -\$(INSTALL_DATA) $doc/paricfg.tex \$(DOCDIR) install-docdvi:: -mkdir -p \$(DOCDIR) -cd $doc; \$(MAKE) doc; for f in *.dvi; do \ \$(INSTALL_DATA) \$\$f \$(DOCDIR); \ done install-docpdf:: -mkdir -p \$(DOCDIR) -cd $doc; \$(MAKE) docpdf; for f in *.pdf; do \ \$(INSTALL_DATA) \$\$f \$(DOCDIR); \ done install-examples: -mkdir -p \$(EXDIR) -\$(INSTALL_DATA) $ex/EXPLAIN \$(EXDIR) -\$(INSTALL_DATA) $ex/Inputrc \$(EXDIR) -\$(INSTALL_DATA) $ex/Makefile \$(EXDIR) -\$(INSTALL_DATA) $ex/bench.gp \$(EXDIR) -\$(INSTALL_DATA) $ex/cl.gp \$(EXDIR) -\$(INSTALL_DATA) $ex/classno.gp \$(EXDIR) -\$(INSTALL_DATA) $ex/contfrac.gp \$(EXDIR) -\$(INSTALL_DATA) $ex/lucas.gp \$(EXDIR) -\$(INSTALL_DATA) $ex/extgcd.c \$(EXDIR) -\$(INSTALL_DATA) $ex/rho.gp \$(EXDIR) -\$(INSTALL_DATA) $ex/squfof.gp \$(EXDIR) -\$(INSTALL_DATA) $ex/taylor.gp \$(EXDIR) install-data: -if test -d $data; then cd $data; \ for d in \`ls\`; do \ mkdir -p \$(DATADIR)/\$\$d && \ for f in \`ls \$\$d\`; do \ \$(INSTALL_DATA) \$\$d/\$\$f \$(DATADIR)/\$\$d; \ done >/dev/null;\ done; \ fi install-lib-sta: \$(LIBPARI_STA) -mkdir -p \$(LIBDIR) -\$(RM) \$(LIBDIR)/\$(LIBPARI_STA) \$(INSTALL_DATA) \$(LIBPARI_STA) \$(LIBDIR)/\$(LIBPARI_STA) install-lib-dyn-base: -mkdir -p \$(LIBDIR) -\$(RM) \$(LIBDIR)/\$(LIBPARI_DYN) \$(LIBDIR)/\$(LIBPARI_SONAME) \$(LIBDIR)/\$(LIBPARI_SO) \$(DLLD_IGNORE)\$(DLLD) -o \$(LIBDIR)/\$(LIBPARI_DYN) \$(DLLDFLAGS) \$(OBJS) \$(EXTRADLLDFLAGS) \$(DYN_LIBS) \$(EXPORT_FILE) \$(LD_INSTALL_NAME) $install_implib install-lib-dyn-link: install-lib-dyn-base -if test "\$(LIBPARI_DYN)" != "\$(LIBDIR)/\$(LIBPARI_SO)"; then \ \$(LN) \$(LIBPARI_DYN) \$(LIBDIR)/\$(LIBPARI_SO); fi -if test "\$(LIBPARI_SONAME)" != "\$(LIBPARI_SO)"; then \ \$(LN) \$(LIBPARI_DYN) \$(LIBDIR)/\$(LIBPARI_SONAME); fi install-lib-dyn: \$(LIBPARI_DYN) install-lib-dyn-link nsis: gp -cd $doc; \$(MAKE) docpdf makensis pari.nsi parimt.h: $src/mt/$thread_engine.h cat $src/mt/$thread_engine.h > parimt.h mpinl.h: parilvl0.h parilvl1.h cat parilvl0.h parilvl1.h > mpinl.h bench: $exec clean_pari_ps @\$(DOTEST) $test_basic dobench:: clean_pari_ps @\$(DOTEST) $test_basic test-all: $exec clean_pari_ps @\$(DOTEST) \$(TESTS) dotest-all:: clean_pari_ps @\$(DOTEST) \$(TESTS) dyntest-all: gp-dyn$exe_suff clean_pari_ps @env dotestSUF=dyn \$(DOTEST) \$(TESTS) statest-all: gp-sta$exe_suff clean_pari_ps @env dotestSUF=sta \$(DOTEST) \$(TESTS) dotest-env:: @export AAA=XXX BBB=YYY; \$(DOTEST) env EOT for i in $test_extra $test_extra_out $test_extra_OUT; do echo "test-$i: $exec dotest-$i" >>$file done for i in $test_extra $test_extra_out; do cat >> $file << EOT dotest-$i:: @\$(DOTEST) $i EOT done if test "$optimization" = gcov; then cat >> $file << EOT .PHONY: lcov-report lcov-reset LCOV_TRACE = lcov.info LCOV_REPORT= lcov-report LCOV_FLAGS= GENHTML_FLAGS= LCOV_TITLE="PARI/GP v$version.$patch lcov report ($status)" lcov-report: \$(RM) \$(LCOV_TRACE) rm -rf \$(LCOV_REPORT) lcov -c \$(LCOV_FLAGS) -d . -b . -o \$(LCOV_TRACE) genhtml \$(GENHTML_FLAGS) --legend -t \$(LCOV_TITLE) -o \$(LCOV_REPORT) \$(LCOV_TRACE) lcov-reset: \$(RM) *.gcda EOT fi if test -n "$exe_suff"; then cat >> $file << EOT gp-sta: gp-sta$exe_suff gp-dyn: gp-dyn$exe_suff EOT fi if test -z "$DLLD"; then cat >> $file << EOT \$(LIBPARI_DYN):: @echo "Configure could not find a way to build a shared library on this machine" EOT else if test -n "$export_file"; then case "$osname" in os2) cat >> $file << EOT EXPORT_FILE_BASE = $src/systems/os2/pari.def.base VERSION_VERBOSE = $pari_release_verbose \$(EXPORT_FILE): \$(OBJS) \$(EXPORT_FILE_BASE) cat \$(EXPORT_FILE_BASE) | sed 's//\$(DLLIBPARI)/' | sed 's//pari.math.u-bordeaux.fr\//' | sed 's//\$(VERSION_VERBOSE)/' | sed 's//GP\/PARI compiled with \$(CFLAGS)/' > \$@ \$(EXPORT_CREATE) \$(OBJS) >> \$@ \$(DLLIBPARI)\$(_A): \$(EXPORT_FILE) \$(EXPORT_LIB_CREATE) -o \$@ \$(EXPORT_FILE) EOT ;; mingw) cat >> $file << EOT \$(EXPORT_FILE): \$(OBJS) \$(DLLTOOL) --export-all-symbols -k -z \$@.tmp \$(OBJS) echo "LIBRARY \$(LIBPARI)" > \$@ && cat \$@.tmp >> \$@ && rm \$@.tmp EOT ;; esac fi cat >> $file << EOT gp-dyn$exe_suff: $add_funclist \$(OBJSGP) \$(LIBPARI_DYN) \$(EXPORT_LIB) \$(RM) \$@ \$(LD) -o \$@ -L\$(TOPLDDYN) \$(LDFLAGS) \$(OBJSGP) \$(RUNPTH) \$(RLLIBS) \$(LDDYN) \$(PLOTLIBS) \$(LIBS) $postconfig gp-dyn$exe_suff \$(LIBPARI_DYN): $add_funclist \$(OBJS) \$(EXPORT_FILE) -\$(RM) \$(LIBPARI_DYN) \$(DLLD_IGNORE)\$(DLLD) -o \$(TOPLDDYN)/\$(LIBPARI_DYN) \$(DLLDFLAGS) \$(OBJS) \$(EXTRADLLDFLAGS) \$(DYN_LIBS) \$(EXPORT_FILE) -if test "\$(LIBPARI_DYN)" != "\$(LIBPARI_SO)"; then \ \$(RM) \$(LIBPARI_SO);\ \$(LN) \$(LIBPARI_DYN) \$(LIBPARI_SO); fi -if test "\$(LIBPARI_DYN)" != "\$(LIBPARI_SONAME)"; then \ \$(RM) \$(LIBPARI_SONAME);\ \$(LN) \$(LIBPARI_DYN) \$(LIBPARI_SONAME); fi EOT fi cat >> $file << EOT $src/language/parse.h: $src/language/parse.y \$(BISON) -d $src/language/parse.y -o $src/language/parse.c $src/language/parse.c: $src/language/parse.h @: EOT if test -n "$add_funclist"; then # files generated using external scripts HUGELINE=" $src/funclist:: @-$cfg/genfunclist $src/funclist $desc" suffix='$$$$-$(TMPSUF)' list="funclist init default gp_init" for name in $list; do case $name in funclist) target="$desc/\$(DESC)" depend="$src/funclist $desc/merge_822 $desc/PARI/822.pm" script="merge_822 ../$src/funclist" ;; init) target=$src/language/init.h depend="$desc/\$(DESC) \$(DESC_HELP_GEN)" script="gen_proto basic \$(DESC)" ;; default) target=$src/language/default.h depend="$desc/\$(DESC) \$(DESC_HELP_GEN)" script="gen_proto default \$(DESC)" ;; gp_init) target=$src/gp/gp_init.h depend="$desc/\$(DESC) \$(DESC_HELP_GEN)" script="gen_proto gp \$(DESC)" ;; esac HUGELINE="$HUGELINE $target: $depend f=$name-$suffix; (cd $desc && \$(PERL) $script > \$\$f) && mv $desc/\$\$f \$@" done echo "$HUGELINE" >> $file fi # Level 0 f=src/kernel/$kernlvl0/MakeLVL0.SH if test -s $f; then . $f else cat >> $file < parilvl0.h EOT fi if test -f "$TOP/.git/index"; then vcfile="../.git/index" cat >> $file <> $file pari-2.11.2/config/ldflags0000755000175000017500000000017511636712103013770 0ustar billbill#! /bin/sh t=$1; shift if test -n "$t"; then L=-Wl for c in "$@"; do L=$L,"$c" done; echo $L else echo "$@" fi pari-2.11.2/config/has_dlopen.c0000644000175000017500000000012412314242551014677 0ustar billbill#include #include int main() {dlopen("a",RTLD_LAZY); return 0;} pari-2.11.2/config/look0000755000175000017500000000066613201017466013325 0ustar billbill# Look for functions in $list. Return as soon as the first function is found, # defining has_$fun for fun in $list; do cmd="$CC $CFLAGS has_$fun.c -o $exe $extra_flags"; . log_cmd if test -s $exe ; then eval "has_$fun=yes"; echo ..."Found $fun." case "$_has_list" in *has_$fun*);; *) _has_list="$_has_list has_$fun";; esac break fi eval "has_$fun=no"; echo ..."I did not find $fun." done . cleanup_exe pari-2.11.2/config/has_stat.c0000644000175000017500000000034411636712103014376 0ustar billbill#include #if (!defined(_MSC_VER) && !defined(_WIN32)) # include # include #endif int main(void) { struct stat buf; if (stat (".", &buf) || !S_ISDIR(buf.st_mode)) return 1; return 0; } pari-2.11.2/config/display0000755000175000017500000000046511636712103014023 0ustar billbillif test -n "$perl"; then echo $rep | $perl -e " @input=split(/\s/,<>); \$len = \$#input + 3; \$len = ( \$len - \$len % 3) / 3; for(\$i=0;\$i<\$len;\$i++) { printf qq( %-18s%-18s%-18s\n), \$input[\$i], \$input[\$i+\$len], \$input[\$i+2*\$len]; }" else echo $rep fi pari-2.11.2/config/get_MANIFEST0000755000175000017500000000042213326135265014422 0ustar billbillgit ls-files | grep -v '/$' | grep -v '\.gitignore' | grep -v TODO # generated files echo doc/usersch3.tex echo src/language/default.h echo src/language/init.h echo src/language/parse.c echo src/language/parse.h echo src/gp/gp_init.h echo src/gp/whatnow.h echo src/funclist pari-2.11.2/config/get_cc0000644000175000017500000001122613201017466013574 0ustar billbill# Exported variables _cc_list="__gnuc__ CC CFLAGS optimization DBGFLAGS OPTFLAGS exe_suff suffix ASMINLINE KERNELCFLAGS" # Which optimization ? if test "$fastread" != yes; then cat << EOT ========================================================================== The default is to fully optimize the compilation. You may choose to build an executable for debugging or profiling instead. Choose among : full debugging profiling gcov EOT echo $n ..."Which optimization do you prefer ? $c" dflt=$optimization; rep='full debugging profiling gcov'; . ./myread optimization=$ans fi case "$osname" in os2) exe_suff=.exe; extraflag="-Zexe";; emscripten) exe_suff=.js;; cygwin|mingw) exe_suff=.exe; extraflag="";; # On Darwin, by default, the full library search path is searched for a .dylib # before a .a can be considered, preventing users to install their libraries # in a simple way (e.g. the readline / Editline conflict). Override this. darwin) exe_suff=; extraflag=-Wl,-search_paths_first;; *) exe_suff=; extraflag="";; esac if test -z "$CC"; then echo Choosing C compiler ... if test -n "$gcc"; then CC=$gcc; else CC=$cc; fi fi if test "$fastread" != yes; then cat << EOT ========================================================================== Only ANSI C and C++ compilers are supported. Choosing the GNU compiler gcc/g++ enables the inlining of kernel routines (about 20% speedup; if you use g++, include the -fpermissive flag). We strongly recommand using gcc all the way through. EOT echo $n ..."Which C compiler shall I use ? $c" dflt=$CC; rep=; . ./myread CC=$ans fi if test -z "$CC"; then cat <&1 |\ grep ' version ' | tr '\n' ,` __gnuc__=`echo $__gnuc__ | sed -e 's/ *,$//'` echo GNU compatible compiler: $__gnuc__ fi . cleanup_exe fi # Which Flags for Compiler ? cflags= ASMINLINE= if test -n "$__gnuc__"; then __GNUC__="-D__GNUC__" warn="-Wall" OPTFLAGS=-O3 ASMINLINE=yes OPTFLAGS="$OPTFLAGS $warn" cmd="$CC $CFLAGS $extraflag -fno-strict-aliasing -o $exe gnu.c" . log_cmd if test -s $exe; then OPTFLAGS="$OPTFLAGS -fno-strict-aliasing" fi . cleanup_exe KERNELCFLAGS=-funroll-loops DBGFLAGS=${DBGFLAGS:-"-g $warn"} # Specific optimisations for some architectures case "$arch" in sparcv8*) cflags=-mv8;; i?86|x86_64) case "$__gnuc__" in gcc*4.0.*) cflags=-fno-gcse-after-reload esac esac # problems on some architectures case "$osname" in os2) cflags="$cflags -Zmt -Zsysv-signals";; nextstep) cflags="$cflags -traditional-cpp";; esac # omit-frame-pointer incompatible with -pg PRFFLAGS="-pg $OPTFLAGS" GCOVFLAGS="-fprofile-arcs -ftest-coverage" case "$optimization" in full) case "$osname" in mingw) ;; *) OPTFLAGS="$OPTFLAGS -fomit-frame-pointer";; esac;; esac else DBGFLAGS=${DBGFLAGS:-'-g'} PRFFLAGS='-pg' case "$osname-$arch" in hpux-*) # -Ae is for ANSI C + defines HPUX_SOURCE OPTFLAGS=-O; cflags=-Ae;; aix-*) OPTFLAGS='-O2 -qtune=auto -qmaxmem=8192' cflags='-qlanglvl=ansi';; osf1-*) OPTFLAGS='-O4 -migrate -ifo -Olimit 9999';; sunos-*) OPTFLAGS=-fast; PRFFLAGS='-pg -Bstatic';; solaris-*) OPTFLAGS='-fast -fsimple=1'; PRFFLAGS=-xpg; case "$arch" in sparc*) OPTFLAGS="$OPTFLAGS -xalias_level=any";; esac;; concentrix-*) OPTFLAGS=-Ogi;; *) OPTFLAGS=-O;; esac PRFFLAGS="$PRFFLAGS $OPTFLAGS" fi case "$optimization" in full) suffix=; cflags="$OPTFLAGS $cflags";; profiling) suffix=.prf; cflags="$PRFFLAGS $cflags";; debugging) suffix=.dbg; cflags="-DMEMSTEP=1048576 $DBGFLAGS $cflags";; gcov) suffix=.gcov; cflags="$GCOVFLAGS $cflags";; esac CFLAGS="$cflags $CFLAGS $CPPFLAGS" if test "$fastread" != yes; then echo $n ..."With which flags ? $c" dflt=$CFLAGS; rep=; . ./myread CFLAGS=$ans fi pari-2.11.2/config/gprc.mingw0000644000175000017500000000023712314242551014422 0ustar billbilllines = 25 colors = "brightfg" prompt = "(%H:%M) gp > " histfile = "gp_history.txt" breakloop = 0 help = "@ perl\\perl gphelp.pl -detex -ch 10 -cb 11 -cu 12" pari-2.11.2/config/get_gmp0000644000175000017500000000503513201017466013773 0ustar billbill_gmp_list="gmp GMPLIBS GMPINCLUDE" gmp= case "$with_gmp" in yes|"");; *) if test -z "$with_gmp_lib"; then with_gmp_lib="$with_gmp/lib" fi if test -z "$with_gmp_include"; then with_gmp_include="$with_gmp/include" fi;; esac pth="$with_gmp_include" x=`./locate 'gmp.h' '' $pth` case $x in ?:/*|/*) gmp_include=`dirname $x` echo ..."Found gmp header in $gmp_include" GMPINCLUDE="-I$gmp_include" ;; esac try() { GMPLIBS=$1; cmd="$cmd0 $1"; . log_cmd; } exe=$osname-$arch-gmp$$$exe_suff cmd0="$CC $CFLAGS $extraflag $GMPINCLUDE -o $exe gmp_version.c" if test -n "$with_gmp_lib"; then gmp=$with_gmp_lib try "-L$gmp -lgmp" fi if test ! -r $exe; then try "-lgmp" fi if test ! -r $exe; then lib=gmp; . ./locatelib if test -n "$gmp"; then try "-L$gmp -lgmp" fi fi if test -r $exe; then gmp_version=`env LD_LIBRARY_PATH="$LD_LIBRARY_PATH$dir_sep$gmp" $RUNTEST $exe`; fi case "$gmp_version" in unsupported) gmp= echo "### Your GMP library ABI is unsupported.";; "") gmp= cmd="$CC $CFLAGS $extraflag $GMPINCLUDE -o $exe ansi.c $GMPLIBS" . log_cmd if test -r $exe; then echo "### Your version of GMP is too old for PARI. Please upgrade" else echo "### Your GMP library is incompatible with the compiler settings." fi;; *) if test -z "$gmp"; then gmp=yes; fi;; esac if test -n "$gmp"; then cmd="$CC $CFLAGS $extraflag $GMPINCLUDE -o $exe gmp_mismatch.c $GMPLIBS" . log_cmd if test ! -r $exe; then gmp= echo "### GMP headers mismatch: try both --with-gmp-lib and --with-gmp-include" fi fi . cleanup_exe if test -z "$gmp"; then echo "### Building without GNU MP support" else if test "$fastread" = yes; then echo "Using GNU MP, version $gmp_version" else cat << EOM ========================================================================== GNU MP library can be used as an alternate multiprecision kernel, which is faster than PARI's native one as soon as integers larger than 10^100 are considered. Unfortunately, with GNU MP, libpari is binary incompatible with the native one. Despite this, you should only answer 'no' to the following question if you plan to use libpari (not only the gp shell) and have stringent backward compatibility requirements. EOM echo $n "Do you want to use GNU MP library instead of the native kernel? $c" if test "$with_gmp" = yes; then dflt=y; else dflt=n; fi rep='y n'; . ./myread case $ans in n) gmp=;; esac fi fi if test -n "$gmp"; then kernlvl1=gmp else kernlvl1=none GMPINCLUDE= GMPLIBS= fi . get_pretty pari-2.11.2/config/arch-osname0000755000175000017500000000554511636712103014557 0ustar billbill#! /bin/sh arch=none; osname=unknown myuname=`(uname -a) 2>/dev/null || arch 2>&1` if test -d /NextApps; then myuname=nextstep; fi if test -n "$myuname"; then myuname=`echo $myuname | sed -e 's/^[^=]*=//' -e 's,/,,g' | \ tr '[A-Z]' '[a-z]' | tr '\012' ' '` set X $myuname; shift; osname=$1 case "$osname" in irix*) osname=irix;; fx2800) arch=fx2800; osname=concentrix;; hp*) osname=hpux; arch=`uname -m` case $arch in ia64) arch=ia64;; 9000/[34]*) arch=m68k;; 9000/[678]*) arch=hppa;; *) arch=hppa;; esac;; os2) arch=`uname -m` if test -z "$arch"; then arch=ix86; fi ;; freebsd|netbsd|openbsd) arch=`uname -m` if test -z "$arch"; then arch=ix86; fi case $arch in amd64) arch=x86_64;; esac;; cygwin*) arch=`uname -m` if test -z "$arch"; then arch=ix86; fi osname=cygwin;; mingw*) arch=`uname -m` if test -z "$arch"; then arch=ix86; fi osname=mingw;; ultrix) arch=mips;; nextstep) arch=`file /bin/sh | sed 's/.*(for architecture \(.*\))/\1/'`;; darwin*) arch=`uname -p` if test "$arch" = powerpc; then arch=ppc; fi ;; osf1) case "$5" in alpha) arch=alpha;; esac;; linux) arch=`uname -m` case $arch in sparc64) arch=sparcv9;; parisc*) arch=hppa;; sparc) case "`cat /proc/cpuinfo`" in *SuperSparc*) arch=sparcv8_super;; *TMS390Z5[05]*) arch=sparcv8_super;; # SuperSparc I or II *TMS390S1[05]*) arch=sparcv8_micro;; # MicroSparc I *MB86904*) arch=sparcv8_micro;; # MicroSparc II *MB86907*) arch=sparcv8_micro;; # TurboSparc *MB86934*) arch=sparcv8_super;; # SparcLite *RT625*) arch=sparcv8_super;; # HyperSparc *CY605*) arch=sparcv8_super;; esac;; esac;; sunos) case "$3" in 5*) osname=solaris;; esac case "$5" in sun4|sun4[ce]) ;; #arch=sparcv7;; sun4[dm]) cpu="TI,|FMI,|Cypress,|Ross," case "`(prtconf||devinfo)2>&- |egrep $cpu`" in *TI,TMS390Z5[05]*) arch=sparcv8_super;; # SuperSparc I or II *TI,TMS390S1[05]*) arch=sparcv8_micro;; # MicroSparc I *FMI,MB86904*) arch=sparcv8_micro;; # MicroSparc II *FMI,MB86907*) arch=sparcv8_micro;; # TurboSparc *FMI,MB86934*) arch=sparcv8_super;; # SparcLite *Ross,RT625*) arch=sparcv8_super;; # HyperSparc *Cypress,CY605*) arch=sparcv8_super;; *) arch=sparcv8_super;; # ??? esac;; sun4[uv]) arch=sparcv9;; i*pc) arch=ix86;; esac;; gnu*) # Cover GNU/Hurd, GNU/kFreeBSD and other GNU userland arch=`uname -m`; case $arch in i386-*) arch=i386;;esac;; aix) arch=`uname -p`; case $arch in powerpc) arch=ppc;;esac;; esac fi echo $arch-$osname pari-2.11.2/config/has_clock_gettime.c0000644000175000017500000000022012314242551016224 0ustar billbill#include #include int main() { struct timespec t; printf("%d",clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t)); return 0; } pari-2.11.2/config/get_nl0000644000175000017500000000043711636712103013622 0ustar billbillecho "Checking echo to see how to suppress newlines..." if (echo "hi\c"; echo " ") | grep c >/dev/null 2>&1 ; then echo "...using -n."; n=-n; c= else cat <$c"; echo '*' fi pari-2.11.2/config/locatelib0000755000175000017500000000167412314242551014316 0ustar billbill_pb= # to detect missing .so when .so.x is found for dir in $pth; do base=$dir/lib$lib case "$osname" in os2) try=`ls $base.a 2> /dev/null`;; *) ok=`(ls $base.* | ${head}1) 2> /dev/null` if test -n "$ok"; then _pb="$ok" # so, sl, dylib, dll.a try=`ls $base.s? $base.a $base.dylib $base.dll.a 2> /dev/null` else try= fi;; esac if test -n "$try"; then echo ..."Found lib$lib in $dir"; eval $lib=$dir; break fi done # not found? detect missing lib*.so (missing *-devel package) if test -z "$try"; then if test "$osname" = linux -a -n "$_pb"; then case "$lib" in X11) rpmlib="[XFree86|xorg-x11|libx11]"; devlib=libx11 ;; *) rpmlib=$lib; devlib=lib$lib ;; esac echo "###" echo "### lib$lib.so not found. Maybe install $lib development files?" echo "### E.g.$rpmlib-devel (RPM) or $devlib-dev (Debian) packages" echo "###" fi fi pari-2.11.2/config/has_alarm.c0000644000175000017500000000013611636712103014516 0ustar billbill#include unsigned int (*f)(unsigned int) = alarm; int main(){ return f != alarm; } pari-2.11.2/config/version0000644000175000017500000000220713461316051014034 0ustar billbill# Major version number VersionMajor='2' # minor version number VersionMinor='11' # Patch level patch='2' # Version code version_code=`expr $VersionMajor \\* 65536 + $VersionMinor \\* 256 + $patch` # Status: alpha, beta, released, development. Rewritten by config/settar ! stat='released' # soname of stable libpari.so is libpari.so.$soname_num status="$stat" patchlevel_verbose= case "$stat" in # $stat rewritten by config/settar ? *git-*) patchlevel_verbose="[ $stat ]";; *) if test -d "$TOP/.git"; then t=`git rev-list HEAD 2>/dev/null | wc -l` # ~ svn revision number t=`echo $t | sed -e 's/ //g'` # some broken wc prepend spaces T=`git log -1 --pretty=format:%h` # commit hash if test -z "$t"; then t=0; fi vcsversion=$t-$T status="$stat $vcsversion" patchlevel_verbose="[ $status ]" fi esac version=$VersionMajor.$VersionMinor pari_release="$version.$patch" if test `expr $VersionMinor % 2` = 1; then pari_release_verbose="$pari_release (STABLE)" soname_num=`expr '(' $VersionMinor '+' 1 ')' / 2` else pari_release_verbose="$pari_release (DEVELOPMENT VERSION)" soname_num=$patch fi pari-2.11.2/config/kernel-name0000755000175000017500000000113111636712103014543 0ustar billbill#! /bin/sh name=$1 arch=$2 lvl1=$3 case "$name" in *-*) kernlvl0=`echo "$name" | sed -e 's/\(.*\)-.*/\1/'` kernlvl1=`echo "$name" | sed -e 's/.*-\(.*\)/\1/'` ;; gmp) #Alias for auto-gmp kernlvl0="$arch"; kernlvl1=gmp ;; none) #Alias for none-none kernlvl0=none; kernlvl1=none;; *) kernlvl0="$name"; kernlvl1=auto ;; esac if [ "$kernlvl0" = "auto" ]; then kernlvl0="$arch"; fi case "$kernlvl1" in gmp|none) ;; auto) kernlvl1=$lvl1;; *) cat << EOM >& 2 ### ### Level1 kernel = '$kernlvl1' unknown, using 'none' ### EOM kernlvl1=none ;; esac echo "$kernlvl0-$kernlvl1" pari-2.11.2/config/get_pretty0000644000175000017500000000064011636712103014534 0ustar billbillpretty="$prettya running $osname" case "$kernlvl1" in gmp) if test -n "$gmp_version"; then prettyk="$prettyk0/GMP-${gmp_version}" else prettyk="$prettyk0/GMP" fi;; none) prettyk="$prettyk0";; *) prettyk="$prettyk0/$kernlvl1";; esac case "$sizeof_long" in 4) pretty="$pretty ($prettyk kernel) 32-bit version";; 8) pretty="$pretty ($prettyk kernel) 64-bit version";; esac; pari-2.11.2/config/kernel.c0000644000175000017500000000047412314242551014053 0ustar billbill#define ulong unsigned long #define ASMINLINE #include "asm0.h" #define __asm__ __asm__ volatile void fun(ulong a, ulong b) { LOCAL_HIREMAINDER; LOCAL_OVERFLOW; addll(a,b); addllx(a,b); mulll(a,b); addmul(a,b); #if 0 bfffo(a); #endif } int main(void) { fun(0xb9f3dcdcUL,0xfbdc740b); return 0; } pari-2.11.2/config/objdir0000755000175000017500000000026611636712103013626 0ustar billbill#! /bin/sh tmp_host=`config/arch-osname` arch=`echo "$tmp_host" | sed -e 's/\(.*\)-.*/\1/'` osname=`echo "$tmp_host" | sed -e 's/.*-\(.*\)/\1/'` objdir=O$osname-$arch; echo $objdir pari-2.11.2/config/has_getenv.c0000644000175000017500000000007612314242551014714 0ustar billbill#include int main(){ (void)getenv(""); return 0; } pari-2.11.2/config/paricfg.h.SH0000644000175000017500000000763013326135265014534 0ustar billbillfile="$objdir/paricfg.h" echo Extracting $file rm -f $file case "$optimization" in full) ;; *) debuginfo=" -- $optimization";; esac if test -n "$perl"; then case "$osname" in os2|mingw) gphelp="perl -S gphelp -detex" ;; *) gphelp="\\\"$bindir/gphelp\\\"" ;; esac fi has_stack_check= if test "$osname" = "os2" -o "$has_getrlimit" = "yes"; then has_stack_check=yes; fi cat > $file << EOT /* This file was created by Configure. Any change made to it will be lost * next time Configure is run. */ #ifndef __PARICFG_H__ #define __PARICFG_H__ EOT cat >> $file << EOT #define UNIX #define GPHELP "$gphelp" #define GPDATADIR "$datadir" #define SHELL_Q '\\$shell_q' #define PARIVERSION "GP/PARI CALCULATOR Version ${version}.${patch} (${status})" #define PARIINFO "${pretty}${debuginfo}" #define PARI_VERSION_CODE ${version_code} #define PARI_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #define PARI_VERSION_SHIFT 8 #define PARI_VCSVERSION "${vcsversion}" #define PARI_MT_ENGINE "${thread_engine}" #define PARI_DOUBLE_FORMAT ${doubleformat} EOT if test -n "$__gnuc__"; then echo "#define GCC_VERSION \"$__gnuc__\"" >> $file fi case $asmarch in none) echo '#define __HAS_NO_ASM__' >> $file;; hppa) echo '#define __HPPA__' >> $file;; esac if test -n "$ASMINLINE"; then echo '#define ASMINLINE' >> $file fi if test -n "$gzip"; then cat >> $file << EOT /* Location of GNU gzip program (enables reading of .Z and .gz files). */ #define GNUZCAT #define ZCAT "$gzip -dc" EOT else if test -n "$zcat"; then cat >> $file << EOT /* Location of zcat program (enables reading of .Z files). */ #define ZCAT "$zcat" EOT fi fi if test -n "$gp_mime_open"; then cat >> $file << EOT #define GP_MIME_OPEN "$gp_mime_open" EOT fi if test "$osname" = "mingw"; then cat >> $file << EOT #undef UNIX #define GNUZCAT #undef ZCAT #define ZCAT "gzip.exe -dc" EOT fi if test -n "$readline"; then cat >> $file <> $file;; esac case $has_sse2 in yes) echo '#define HAS_SSE2' >> $file;; esac case "$has_exp2" in yes) echo '#define HAS_EXP2' >> $file;; esac case "$has_log2" in yes) echo '#define HAS_LOG2' >> $file;; esac case "$has_isatty" in yes) echo '#define HAS_ISATTY' >> $file;; esac case "$has_alarm" in yes) echo '#define HAS_ALARM' >> $file;; esac case "$has_system" in yes) echo '#define HAS_SYSTEM' >> $file;; esac case "$has_clock_gettime" in yes) echo '#define USE_CLOCK_GETTIME 1' >> $file;; *) case "$has_getrusage" in yes) echo '#define USE_GETRUSAGE 1' >> $file;; *) case "$has_times" in yes) echo '#define USE_TIMES 1' >> $file;; *) case "$has_ftime" in yes) echo '#define USE_FTIME 1' >> $file;; esac;; esac;; esac;; esac case "$has_gettimeofday" in yes) echo '#define USE_GETTIMEOFDAY 1' >> $file;; *) case "$has_ftimeforwalltime" in yes) echo '#define USE_FTIMEFORWALLTIME 1' >> $file;; esac;; esac case $has_sigaction in yes) echo '#define HAS_SIGACTION' >> $file;; esac case $has_waitpid in yes) echo '#define HAS_WAITPID' >> $file;; esac case $has_getenv in yes) echo '#define HAS_GETENV' >> $file;; esac case $has_setsid in yes) echo '#define HAS_SETSID' >> $file;; esac case $has_dlopen in yes|builtin) echo '#define HAS_DLOPEN' >> $file;; esac case $has_stack_check in yes) echo '#define STACK_CHECK' >> $file;; esac case $has_vsnprintf in yes) echo '#define HAS_VSNPRINTF' >> $file;; esac case $has_TIOCGWINSZ in yes) echo '#define HAS_TIOCGWINSZ' >> $file;; esac case $has_strftime in yes) echo '#define HAS_STRFTIME' >> $file;; esac case $has_opendir in yes) echo '#define HAS_OPENDIR' >> $file;; esac case $has_stat in yes) echo '#define HAS_STAT' >> $file;; esac case $has_mmap in yes) echo '#define HAS_MMAP' >> $file;; esac case $enable_tls in yes) echo '#define ENABLE_TLS' >> $file;; esac echo '#endif' >> $file pari-2.11.2/config/mpi.c0000644000175000017500000000040013036414401013342 0ustar billbill#include #include int main() { int pari_MPI_size, pari_MPI_rank; int res = MPI_Init(0, NULL); if (res == MPI_SUCCESS) { MPI_Comm_size(MPI_COMM_WORLD, &pari_MPI_size); MPI_Comm_rank(MPI_COMM_WORLD, &pari_MPI_rank); } } pari-2.11.2/config/get_ld0000644000175000017500000000341013201017466013602 0ustar billbill# Which Executable Linker ? # _ld_list='LD LDFLAGS LIBS runpathprexix LDneedsWl LDused GNULDused' case "$osname" in darwin) LIBS= ;; osf1) LIBS='-lm -lots';; *) LIBS=-lm;; esac if test -z "$LD"; then LD=$CC; fi if test "$fastread" != yes; then echo $n ..."Which linker for building executables ? $c" dflt=$LD; rep=; . ./myread LD=$ans fi LDused=$LD # Which Flags for Executable Linker? ldflags= GNULDused= if test "$LD" = "$CC"; then ldflags=$CFLAGS if test -n "$__gnuc__"; then LDused=`$CC -print-prog-name=ld 2>/dev/null` LDneedsWl=yes else if test "$osname" = hpux; then LDneedsWl=yes; fi fi fi if ($LDused -v 2>&1 | grep GNU > /dev/null); then GNULDused=yes; fi tmp= if test "$GNULDused" = "yes"; then case "$osname" in cygwin|mingw) tmp=--enable-auto-import ;; # PE does not support --export-dynamic *) tmp=--export-dynamic ;; esac else case "$osname-$arch" in aix-*) tmp=-brtl ;; # in case we link against a shared library hpux-*) tmp=-E ;; esac fi case "$osname" in darwin) tmp="$tmp -search_paths_first";; esac if test -n "$tmp"; then tmp=`./ldflags "$LDneedsWl" $tmp` ldflags="$ldflags $tmp" fi case "$osname-$arch" in os2-*) ldflags="$ldflags -Zexe" if test "$optimization" = "full"; then ldflags="$ldflags -s"; fi esac LDFLAGS="$ldflags $LDFLAGS" if test "$fastread" != yes; then echo $n ..."With which flags ? $c" dflt=$LDFLAGS; rep=; . ./myread LDFLAGS=$ans fi echo "Executable linker is $LD $LDFLAGS" if test "$GNULDused" = yes; then runpathprefix='-rpath ' else # guess... case "$osname" in gnu|osf1|linux|cygwin*|freebsd|netbsd) runpathprefix='-rpath ' ;; solaris) runpathprefix='-R ' ;; hpux) runpathprefix='+b ' ;; aix) runpathprefix='-blibpath:' ;; esac fi pari-2.11.2/config/TOP_Make.SH0000644000175000017500000001056713201017466014267 0ustar billbillfile=Makefile echo "Extracting $file" rm -f $file dosversion=`echo $version|sed -e 's/\.//g'` dosversion="_$dosversion$patch" __status__=$status case "$status" in development*) __status__='snapshot';; esac cat > $file << EOT # This file was created by Configure. All changes made will be lost # next time Configure is run. # SHELL = $make_sh VERS = pari-$version.$patch $__status__ TAG=release-$VersionMajor-$VersionMinor-$patch dft target:: @echo "Main targets: we suggest 'make all', then 'make install' as root" @echo " all Compilation + Documentation" @echo " gp Compilation" @echo " bench Compilation + Quick test" @echo " dobench Quick test only" @echo " doc Documentation only" @echo " install Installation" @echo " clean, cleantest Clean up" @echo "For pari maintainers:" @echo " dbg Compile gp binary suitable for debugging" @echo " prf Compile gp binary suitable for profiling" @echo " gcov Compile gp binary for test coverage reporting" @echo " alpha, beta, release Tarfile for official source distribution" @echo " snapshot, distrib Tarfile for source snapshot" @echo " nsis Create a NSIS installer for win32" @echo " ctags Generate VI/VIM tags file in ./src" @echo " etags Generate Emacs tags file in ./src" @echo " tune Generate tuning utility" @echo " test-all Thorough regression tests (slow)" all:: @\$(MAKE) gp @-cd doc && \$(MAKE) doc gp bench test-kernel test-all install cleanall cleanobj cleantest nsis install-bin install-doc install-docpdf install-nodata install-data install-lib-sta install-bin-sta dobench dyntest-all statest-all tune $top_test_extra $top_dotest_extra:: @dir=\`config/objdir\`; echo "Making \$@ in \$\$dir";\\ if test ! -d \$\$dir; then echo "Please run Configure first!"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) \$@ dbg gp.dbg:: @dir=\`config/objdir\`.dbg; echo "Making gp in \$\$dir";\\ if test ! -d \$\$dir; then echo "Please run Configure -g first!"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) gp prf gp.prf:: @dir=\`config/objdir\`.prf; echo "Making gp in \$\$dir";\\ if test ! -d \$\$dir; then echo "Please run Configure -pg first!"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) gp gcov gp.gcov:: @dir=\`config/objdir\`.gcov; echo "Making gp in \$\$dir";\\ if test ! -d \$\$dir; then echo "Please run Configure -gcov first!"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) gp doc docps docpdf gpman cleandoc:: cd doc && \$(MAKE) \$@ clean:: cleandoc cleanall clean.dbg:: @dir=\`config/objdir\`.dbg; echo "Making clean in \$\$dir";\\ if test ! -d \$\$dir; then echo "Nothing to be done"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) clean clean.prf:: @dir=\`config/objdir\`.prf; echo "Making clean in \$\$dir";\\ if test ! -d \$\$dir; then echo "Nothing to be done"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) clean clean.gcov:: @dir=\`config/objdir\`.gcov; echo "Making clean in \$\$dir";\\ if test ! -d \$\$dir; then echo "Nothing to be done"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) clean bench.dbg:: @dir=\`config/objdir\`.dbg; echo "Making bench in \$\$dir";\\ if test ! -d \$\$dir; then echo "Please run Configure -g first!"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) bench bench.prf:: @dir=\`config/objdir\`.prf; echo "Making bench in \$\$dir";\\ if test ! -d \$\$dir; then echo "Please run Configure -pg first!"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) bench bench.gcov:: @dir=\`config/objdir\`.gcov; echo "Making bench in \$\$dir";\\ if test ! -d \$\$dir; then echo "Please run Configure -gcov first!"; exit 1; fi;\\ cd \$\$dir && \$(MAKE) bench distrib: $config_dir/settar \$(VERS) $__status__ setdoc: cd doc && \$(MAKE) usersch3.tex alpha: setdoc $config_dir/settar \$(VERS) alpha beta: setdoc $config_dir/settar \$(VERS) beta release: setdoc $config_dir/settar \$(VERS) released snapshot: setdoc $config_dir/settar \$(VERS) snapshot dosdistrib: gpman -zip -kr GPB${dosversion}.ZIP GP.EXE README README.DOS ../EMX/README.DOC ../RSX/README.TXT -zip -k GPD${dosversion}.ZIP doc/*.tex doc/gphelp doc/gp.man examples misc/gprc* misc/gpalias etags: config/make_tags --emacs "$TOP/src" ctags: config/make_tags --vi "$TOP/src" checkspaces: config/checkspaces EOT pari-2.11.2/config/get_Qt0000644000175000017500000000310413326135265013575 0ustar billbillif test -z "$with_qt"; then with_qt=yes fi QTLIBS="-lQtCore -lQtGui -lstdc++" QTMOC= QTLIB= QTINC= if test -n "$with_qt_lib"; then QTLIB="-L$with_qt_lib" fi if test -n "$with_qt_include"; then QTINC="-I$with_qt_include" fi case "$with_qt" in yes) pth=`echo $PATH | tr ':' ' '`; QTMOC=`./locate moc '' $pth` if ! test -n "$QTMOC"; then case "$sizeof_long" in 4) addlib="/usr/local/lib32 /lib32 /usr/lib32";; 8) addlib="/usr/local/lib64 /lib64 /usr/lib64";; esac pth="$addlib /usr/local/lib /usr/local/share /usr/lib /lib /usr/share" QTMOC=`./locate qt4/bin/moc '' $pth` if ! test -n "$QTMOC"; then QTMOC=`./locate qt/bin/moc '' $pth` fi fi;; *) if test ! -d "$with_qt"; then echo "### Qt binary '$with_qt/moc' not found" else QTMOC=$with_qt/moc which_graphic_lib=Qt4 fi;; esac if test -n "$QTMOC"; then if test -z "$QTINC"; then QTDIR=`dirname $QTMOC` if test -d "$QTDIR/include"; then QTINC="-I$QTDIR/include" else QTINC="-I/usr/include/qt4" fi fi if test -z "$QTLIB"; then lib=QtCore; . ./locatelib if test -n "$QtCore"; then QTLIB="-L$QtCore" fi fi fi if test -n "$QTMOC"; then exe=$osname-$arch-Qt4$$$exe_suff cmd="g++ $CFLAGS $extraflag $QTLIB $QTLIBS $QTINC -o $exe has_Qt4.c" . log_cmd; if test ! -r $exe; then QTMOC= fi fi if test -n "$QTMOC"; then echo "Using Qt library, QTMOC = $QTMOC, QTLIB = $QTLIB, QTINC = $QTINC" which_graphic_lib=Qt4 else which_graphic_lib=none echo "### Qt not found. Building without Qt support" fi pari-2.11.2/config/get_fltk0000644000175000017500000000064613201017466014153 0ustar billbillif test -z "$with_fltk"; then with_fltk=yes fi cmd="FLTK_LIBS=\`fltk-config --ldflags\`" . log_cmd exe=$osname-$arch-fltk$$$exe_suff cxx=$CXX if test -z "$cxx"; then cxx=g++; fi; cmd="$cxx $CFLAGS $FLTK_LIBS -o $exe has_fltk.c" . log_cmd if test -r "$exe"; then echo "Using FLTK library" FLTK_LIBS="$FLTK_LIBS -lstdc++" else echo "### FLTK not found. Building without FLTK support" FLTK_LIBS= fi . cleanup_exe pari-2.11.2/config/has_gettimeofday.c0000644000175000017500000000022013201017466016075 0ustar billbill#include #include int main(void) { static struct timeval tv0; if(!gettimeofday(&tv0, NULL)) return 1; return 0; } pari-2.11.2/config/has_setsid.c0000644000175000017500000000014411636712103014714 0ustar billbill#include #include pid_t (*f)() = setsid; int main(){ return f != setsid; } pari-2.11.2/config/get_tests0000644000175000017500000000214213201017466014346 0ustar billbill# Format: filename_weight (weight = 1000 if omitted) # individual times are printed as is, but accumulated time is weighed # by (weight / 1000) _test_list='test_extra_OUT test_extra_out test_extra test_basic top_test_extra top_dotest_extra' # _not_ included in 'make test-all' (annoying) test_extra_out="ploth io parallel install time" # _not_ included automatically in Oxxx/Makefile (special cased there) test_extra_OUT="env" test_extra_all_out="$test_extra_out $test_extra_OUT" pattern_out=`echo $test_extra_all_out | sed -e 's/ /|/g'` # included in 'make bench' test_basic="\ objets\ analyz\ number\ polyser\ linear\ elliptic\ sumiter\ graph\ program\ trans\ nfields_200\ " # included in 'make test-all' in addition to regular components of 'make bench' test_extra=`ls "$TOP"/src/test/in | egrep -v "\b($pattern_out)\b"` test_extra=`echo $test_extra | sed -e 's/\n/ /g'` all_tests="$test_extra $test_extra_out $test_extra_OUT" top_test_extra="test-`echo $all_tests | sed -e 's/ \\([^ ]\\)/ test-\\1/g'`" top_dotest_extra="dotest-`echo $all_tests | sed -e 's/ \\([^ ]\\)/ dotest-\\1/g'`" pari-2.11.2/config/cygwin-pari.nsi0000755000175000017500000001514612314242551015400 0ustar billbill#! /bin/sh . config/version release=`echo "$pari_release"|sed 's/\./-/g'` cat << EOT ;--- PARI/GP: NullSoft Installer configuration file !include "MUI.nsh" Name "PARI $pari_release_verbose" !define dll "libpari.dll" !define PARIver "Pari-$release" EOT cat << 'EOT' ;--No need to modify things below -- !define top ".." !define cfgdir "${top}\config" AutoCloseWindow false OutFile "Pari.exe" InstallDir "$PROGRAMFILES\${PARIver}" InstallDirRegKey HKLM "Software\${PARIver}" "" !define MUI_ABORTWARNING !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "${top}\COPYING" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ;Installer Sections !define uninst "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PARIver}" Section "pari (required)" SecCopy SetOutPath "$INSTDIR" File /oname=gp.exe "gp-dyn.exe" File /oname=.gprc "${cfgdir}\cygwin-gprc" File /oname=postinst "${cfgdir}\cygwin-postinst" File "${top}\misc\tex2mail" File "${dll}" FILE "\cygwin\bin\cygcrypt-0.dll" FILE "\cygwin\bin\cygiconv-2.dll" FILE "\cygwin\bin\cygintl-8.dll" File "\cygwin\bin\cyggmp-3.dll" File "\cygwin\bin\cygncursesw-10.dll" File "\cygwin\bin\cygreadline7.dll" File "\cygwin\bin\cygperl5_10.dll" File "\cygwin\bin\cyggcc_s-1.dll" File "\cygwin\bin\cygssp-0.dll" File "\cygwin\bin\cygwin1.dll" File "\cygwin\bin\perl.exe" File "\cygwin\bin\sh.exe" File "\cygwin\bin\ln.exe" SetOutPath "$INSTDIR\terminfo\c" File /nonfatal "\cygwin\usr\share\terminfo\c\cygwin" SetOutPath "$INSTDIR\terminfo\63" File /nonfatal "\cygwin\usr\share\terminfo\63\cygwin" SetOutPath "$INSTDIR" CreateDirectory "$INSTDIR\..\bin" ExecWait 'sh ./postinst' Delete "ln.exe" Delete "postinst" WriteRegStr HKCU "Software\${PARIver}" "" $INSTDIR WriteRegStr HKLM ${uninst} "DisplayName" "${PARIver} (remove only)" WriteRegStr HKLM ${uninst} "UninstallString" '"$INSTDIR\uninstall.exe"' WriteUninstaller "$INSTDIR\Uninstall.exe" SectionEnd SectionGroup /e "Data files" SecDATA Section "Elliptic curves files" SecELL SetOutPath "$INSTDIR\data\elldata" File "${top}\data\elldata\*" SectionEnd Section "Galois files" SecGAL SetOutPath "$INSTDIR\data\galdata" File "${top}\data\galdata\*" SectionEnd Section "Frobenius of elliptic curves files" SecSEA SetOutPath "$INSTDIR\data\seadata" File "${top}\data\seadata\*" SectionEnd Section "Galois polynomial files" SecGPL SetOutPath "$INSTDIR\data\galpol" File "${top}\data\galpol\*" SectionEnd SectionGroupEnd Section "documentation" SecDOC SetOutPath "$INSTDIR" File "${top}\doc\gphelp" SetOutPath $INSTDIR\doc File "${top}\doc\translations" File "${top}\doc\*.tex" File "${top}\doc\*.pdf" SectionEnd Section "examples" SecEX SetOutPath "$INSTDIR" File "${top}\doc\gphelp" SetOutPath $INSTDIR\examples File "${top}\examples\EXPLAIN" File "${top}\examples\Inputrc" File "${top}\examples\*.gp" File "${top}\examples\*.c" File "${top}\examples\Makefile.cygwin-i686" SectionEnd Function .onInstSuccess MessageBox MB_OK "Thank you for using PARI/GP! Double-click on 'gp' to start the calculator.$\r$\nTweak $INSTDIR\.gprc to customize GP: colors, script search path, etc." ExecShell "open" "$INSTDIR" FunctionEnd !define short "$SMPROGRAMS\${PARIver}" Section "shortcuts" SecSM CreateDirectory "${short}" CreateShortCut "${short}\gp.lnk" "$INSTDIR\gp.exe" "" "$INSTDIR\gp.exe" 0 CreateShortCut "${short}\users.lnk" "$INSTDIR\doc\users.pdf" "" "$INSTDIR\doc\users.pdf" 0 CreateShortCut "${short}\libpari.lnk" "$INSTDIR\doc\libpari.pdf" "" "$INSTDIR\doc\libpari.pdf" 0 CreateShortCut "${short}\tutorial.lnk" "$INSTDIR\doc\tutorial.pdf" "" "$INSTDIR\doc\tutorial.pdf" 0 CreateShortCut "${short}\refcard.lnk" "$INSTDIR\doc\refcard.pdf" "" "$INSTDIR\doc\refcard.pdf" 0 WriteINIStr "${short}\PARI pages.url" "InternetShortcut" "URL" "http://pari.math.u-bordeaux.fr" CreateShortCut "${short}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 CreateShortCut "$DESKTOP\PARI.lnk" "$INSTDIR\gp.exe" SectionEnd ;-------------------------------- ;Descriptions LangString DESC_SecCopy ${LANG_ENGLISH} "Copy pari files to application folder." LangString DESC_DOC ${LANG_ENGLISH} "Install documentation and online help." LangString DESC_EX ${LANG_ENGLISH} "Install sample GP scripts." LangString DESC_DATA ${LANG_ENGLISH} "Data files pertaining to pari" LangString DESC_ELL ${LANG_ENGLISH} "Install elliptic curves data files (for ellsearch and ellidentify)." LangString DESC_GAL ${LANG_ENGLISH} "Install Galois data files (for polgalois in degree > 7)." LangString DESC_SEA ${LANG_ENGLISH} "Install Modular polynomials (for ellap'SEA implementation)." LangString DESC_GPL ${LANG_ENGLISH} "Install Galois polynomials data files (for galoisgetpol)." LangString DESC_SM ${LANG_ENGLISH} "Add PARI shortcuts to Start Menu and desktop." !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecCopy} $(DESC_SecCopy) !insertmacro MUI_DESCRIPTION_TEXT ${SecDATA} $(DESC_DATA) !insertmacro MUI_DESCRIPTION_TEXT ${SecELL} $(DESC_ELL) !insertmacro MUI_DESCRIPTION_TEXT ${SecGAL} $(DESC_GAL) !insertmacro MUI_DESCRIPTION_TEXT ${SecSEA} $(DESC_SEA) !insertmacro MUI_DESCRIPTION_TEXT ${SecGPL} $(DESC_GPL) !insertmacro MUI_DESCRIPTION_TEXT ${SecSM} $(DESC_SM) !insertmacro MUI_DESCRIPTION_TEXT ${SecDOC} $(DESC_DOC) !insertmacro MUI_DESCRIPTION_TEXT ${SecEX} $(DESC_EX) !insertmacro MUI_FUNCTION_DESCRIPTION_END ;-------------------------------- Section "Uninstall" Delete "$INSTDIR\gp.exe" Delete "$INSTDIR\.gprc" Delete "$INSTDIR\gphelp" Delete "$INSTDIR\tex2mail" Delete "$INSTDIR\${dll}" Delete "$INSTDIR\cygcrypt-0.dll" Delete "$INSTDIR\cygiconv-2.dll" Delete "$INSTDIR\cygintl-8.dll" Delete "$INSTDIR\cyggmp-3.dll" Delete "$INSTDIR\cygncursesw-10.dll" Delete "$INSTDIR\cygreadline7.dll" Delete "$INSTDIR\cygperl5_10.dll" Delete "$INSTDIR\cyggcc_s-1.dll" Delete "$INSTDIR\cygssp-0.dll" Delete "$INSTDIR\cygwin1.dll" Delete "$INSTDIR\perl.exe" Delete "$INSTDIR\sh.exe" Delete "$INSTDIR\Uninstall.exe" RMDir /r "$INSTDIR\doc" RMDir /r "$INSTDIR\examples" RMDir /r "$INSTDIR\data" RMDir /r "$INSTDIR\terminfo" DeleteRegKey HKLM ${uninst} DeleteRegKey /ifempty HKLM "Software\${PARIver}" RMDir /r "$SMPROGRAMS\${PARIver}" Delete "$DESKTOP\PARI.lnk" Delete "$INSTDIR\..\bin\sh" RMDir "$INSTDIR\..\bin" RMDir "$INSTDIR" SectionEnd EOT pari-2.11.2/config/get_libc0000644000175000017500000000345113326135265014127 0ustar billbill# Looking in libc for some functions. exe=$osname-$arch-tmp$$$exe_suff _has_list= echo Looking in C lib for some symbols... extra_flags=-lm if test "$arch" = "x86_64" && test "$sizeof_long" = "8"; then list=sse2; . ./look fi list=exp2; . ./look list=log2; . ./look extra_flags= list=strftime; . ./look if test "$timing_fun" = "clock_gettime"; then list=clock_gettime; . ./look if test "$has_clock_gettime" = no; then echo "Try again, with -lrt this time..." extra_flags=-lrt list=clock_gettime; . ./look extra_flags= if test "$has_clock_gettime" = yes; then RT_LIBS=-lrt fi fi else if test -n "$timing_fun"; then list=$timing_fun else case "$osname" in *cygwin*) list='times';; # getrusage based timer always returns 0 *) list='getrusage times';; esac; fi; . ./look fi if test "$has_clock_gettime" = yes -o "$has_ftime" = yes; then : else list='gettimeofday ftime'; . ./look if test "$has_ftime" = yes; then has_ftimeforwalltime=yes unset has_ftime fi fi list=sigaction; . ./look list=TIOCGWINSZ; . ./look list=getrlimit; . ./look list='stat opendir'; . ./look list=vsnprintf; . ./look if test "$enable_mmap" = "no"; then has_mmap=no else list=mmap; . ./look fi list=waitpid; . ./look list=setsid; . ./look list=getenv; . ./look list=isatty; . ./look list=alarm; . ./look list=system; . ./look # For install(). Do we need libdl.so? # on irix and osf1 -ldl not needed extra_flags= DL_LIBS= list=dlopen; . ./look if test "$has_dlopen" = no; then echo "Try again, with -ldl this time..." extra_flags=-ldl; . ./look if test "$has_dlopen" = yes; then DL_LIBS=-ldl fi fi if test "$has_dlopen" = no; then case "$osname" in os2|darwin) echo "Will use builtin dlopen() support for $osname..." has_dlopen=builtin esac fi pari-2.11.2/config/convertllp640000755000175000017500000000333113201017466014713 0ustar billbill#!/bin/sh # This script is intended to be run from the pari directory. It will make the following # changes to all source code in preparation for making on mingw64: # 1.) Convert 32 bit constants to 64 bit constants (i.e. L->LL and UL->ULL), # 2.) Convert formatting in printf/sprintf/fprintf (i.e. %ld->%lld, %lu->%llu, etc). test -d config || cd .. test -d config || exit 1 test -d src64 && rm -rf src64 cd src for file in `find . -type f -name "*.[chy]"` ; do outfile="../src64/$file" mkdir -p `dirname $outfile` echo "converting file: $file -> $outfile" # Add LL to the end of any constant with 10 or more numbers sed 's/\([-+({ ][0-9]\{10,\}\)\([,;:)} ]\)/\1LL\2/g' < $file > TMP # Convert all decimal constants ending in L or UL. # Note: replacing strings with lower case l breaks a couple things, namely strings like "%+1ld" sed -e 's/\([-+* ,()=~&|%][0-9][0-9]*\)[L]\{1,2\}/\1LL/g' -e 's/\([-+* ,()=~&|%][0-9][0-9]*\)[uU][lL]\{1,2\}/\1ULL/g' < TMP > TMP2 # Convert all hexadecimal constants ending in L or UL. sed -e 's/\(0x[0-9a-fA-F][0-9a-fA-F]*\)[lL]\{1,2\}/\1LL/g' -e 's/\(0x[0-9a-fA-F][0-9a-fA-F]*\)[uU][lL]\{1,2\}/\1ULL/g' < TMP2 > TMP # String formatting conversions: %ld -> %lld, %lu -> %llu, %lx -> %llx. # This will also handle cases like %+2ld and %0*lx # Replace formatting with microsoft ll convention, but only inside regular printfs # (and its variants) # Do nothing inside of pari_printf() or pari_sprintf(). sed -e '/\"/ s/\(%[-+]\{0,1\}[0-9]*\)ld/\1lld/g' -e '/\"/ s/\(%[-+]\{0,1\}[0-9]*\)lu/\1llu/g' -e '/\"/ s/\(%[-+]\{0,1\}[0-9]*\)lx/\1llx/g' -e '/\"/ s/\(%[0-9]\*\)lx/\1llx/g' < TMP > $outfile # clean up rm TMP TMP2; done echo "Done." pari-2.11.2/config/has_isatty.c0000644000175000017500000000006712314242551014741 0ustar billbill#include int main(){ isatty(0); return 0; } pari-2.11.2/config/cygwin-postinst0000644000175000017500000000037612314242551015534 0ustar billbillpwd="$(pwd)" echo 'colors = "boldfg"' >> .gprc echo 'help = "'"$pwd"'/perl.exe '"$pwd"'/gphelp -cu 6"' >> .gprc echo 'prettyprinter = "'"$pwd"'/perl.exe tex2mail -TeX -noindent -ragged -by_par"' >> .gprc pwd=${pwd##*/} ./ln -s ../${pwd}/sh.exe ../bin/sh pari-2.11.2/config/pthread.c0000644000175000017500000000055413036414401014216 0ustar billbill#include #include static __thread long counter; void *start_routine(void *pt_val) { long val = *(long *)pt_val; counter = val+1; return NULL; } int main(void) { pthread_t thread; counter = 0; if (pthread_create(&thread, NULL, start_routine, &counter)) exit(1); if (pthread_join(thread, NULL)) exit(1); return 0; } pari-2.11.2/config/get_X110000644000175000017500000000276013201017466013563 0ustar billbilltdir=$osname-$arch-X11$$ mkdir $tdir; cp Imakefile $tdir; cd $tdir cmd="xmkmf"; . ../log_cmd if test -f Makefile; then eval `make gp-X11 >&5 2>&1 | grep -v make` x11pth="$usrlibdir $libdir"; fi cd ..; rm -rf $tdir # Check xmkmf answer # X11 -- Headers if test ! -f $Xincroot/X11/Xos.h; then x11pth="$addlib64\ /usr/openwin/share/lib\ /usr/openwin/lib\ /usr/X11R6/lib /usr/X11R5/lib /usr/X11R4/lib\ /usr/lib/X11R6 /usr/lib/X11R5 /usr/lib/X11R4\ /usr/local/X11R6/lib /usr/local/X11R5/lib /usr/local/X11R4/lib\ /usr/local/lib/X11R6 /usr/local/lib/X11R5 /usr/local/lib/X11R4\ /usr/X11/lib\ /usr/lib/X11\ /usr/local/X11/lib\ /usr/local/lib/X11\ /usr/XFree86/lib/X11\ /usr/lib\ /usr/local/lib\ /usr/athena/lib\ "; pth=`echo $x11pth | sed 's,/lib,/include,g'` x=`./locate X11/Xos.h '' $pth` case $x in /*) Xincroot=`echo $x | sed 's,/X11/Xos.h,,'`;; *) Xincroot=;; esac fi if test -f $Xincroot/X11/Xos.h; then echo ..."Found X11 header files in $Xincroot/X11" X11_INC="-I$Xincroot" fi # X11 -- Lib exe=$osname-$arch-X11$$$exe_suff cmd0="$CC $CFLAGS $extraflag $X11_INC -o $exe has_X11.c" try() { X11_LIBS=$1; cmd="$cmd0 $1"; . log_cmd; } try "-lX11 $extralib" if test ! -r $exe; then pth=$x11pth lib=X11; . ./locatelib if test -n "$X11"; then try "-L$X11 -lX11 $extralib" fi fi if test ! -r $exe; then echo "### X11 not found" X11_LIBS= X11_INC= fi . cleanup_exe echo ..."X11 libraries: $X11_LIBS" pari-2.11.2/config/get_head0000644000175000017500000000013211636712103014102 0ustar billbillif (head -n 1 < /dev/null >/dev/null 2>&1); then head='head -n' else head='head -' fi pari-2.11.2/config/has_log2.c0000644000175000017500000000011611636712103014263 0ustar billbill#include double (*f)(double) = log2; int main(){ return f != log2; } pari-2.11.2/config/gmp_mismatch.c0000644000175000017500000000027313201017466015241 0ustar billbill#include #include int main() { mp_limb_t *x = NULL, *y = NULL; long nx = 0; #ifdef mpn_sqr mpn_sqr(y, x, nx); #else mpn_mul_n(y, x, x, nx); #endif return 0; } pari-2.11.2/config/has_getrlimit.c0000644000175000017500000000027212314242551015422 0ustar billbill#include #include #include int main() { struct rlimit rip; getrlimit(RLIMIT_STACK, &rip); setrlimit(RLIMIT_STACK, &rip); return 0; } pari-2.11.2/config/has_TIOCGWINSZ.c0000644000175000017500000000044413201017466015124 0ustar billbill#include #include #ifdef __sun # include #endif #include #ifdef __EMSCRIPTEN__ #error TIOCGWINSZ broken with emscripten #endif int main() { struct winsize s; int status = ioctl(0, TIOCGWINSZ, &s); (void)status; return s.ws_col; } pari-2.11.2/config/get_install0000644000175000017500000000400113036414401014642 0ustar billbill# Exported variables _install_list="prefix share_prefix bindir datadir includedir libdir mandir sysdatadir " dflt=$prefix; rep= test "$fastread" = yes || cat < #include #include int main(){ (void)XOpenDisplay(NULL); return 0; } pari-2.11.2/config/has_fltk.c0000644000175000017500000000016213201017466014361 0ustar billbill#include #include #include int main() { &fl_color_cube; return 0; } pari-2.11.2/config/get_dlcflags0000644000175000017500000000062611636712103014770 0ustar billbill_dl_list="DLCFLAGS" if test -n "$__gnuc__"; then case $osname in cygwin|mingw) DLCFLAGS=;; darwin) DLCFLAGS=-fPIC case $arch in ppc|ppc64) DLCFLAGS="$DLCFLAGS -fno-common" esac;; *) DLCFLAGS=-fPIC;; esac else #assume native compiler case "$osname" in hpux) DLCFLAGS=+z;; solaris) DLCFLAGS=-KPIC;; esac fi echo "C compiler is $CC $CFLAGS $DLCFLAGS" pari-2.11.2/config/get_archos0000644000175000017500000000207313201017466014466 0ustar billbill# Testing Architectures. Try uname to provide a default, then ask user. # if test -z "$target_host"; then target_host=`./arch-osname` fi arch=`echo "$target_host" | sed -e 's/\(.*\)-.*/\1/'` osname=`echo "$target_host" | sed -e 's/.*-\(.*\)/\1/'` if test "$fastread" != yes; then cat << EOM ========================================================================== Currently supported architectures: EOM rep='none sparcv8_super sparcv8_micro sparcv9 ix86 i386 i486 i586 i686 alpha x86_64 arm aarch64 fx2800 hppa ia64 mips m68k ppc s390' . ./display echo $n ..."Which of these apply, if any ? $c" dflt=$arch; . ./myread; arch=$ans fi # # Test OS, using the info uname provided. # if test "$fastread" != yes; then cat << EOM ========================================================================== I know of the following Operating Systems EOM rep='os2 freebsd netbsd cygwin linux mingw gnu gnukfreebsd hpux aix osf1 solaris sunos nextstep concentrix irix'; . ./display echo $n ..."Any of these apply ? $c" dflt=$osname; . ./myread osname=$ans fi pari-2.11.2/config/gnu.c0000644000175000017500000000011111636712103013351 0ustar billbill#ifdef __GNUC__ int main(){return 0;} #else int main(){return 1;} #endif pari-2.11.2/config/has_waitpid.c0000644000175000017500000000015412314242551015062 0ustar billbill#include #include #include int main(){ waitpid(-1,NULL,0); return 0; } pari-2.11.2/config/get_double_format0000644000175000017500000000310513201017466016026 0ustar billbillexe=$osname-$arch-endian$$$exe_suff cmd="$CC $CFLAGS $extraflag endian.c -o $exe"; . log_cmd if test -r $exe; then doubleformat=`$RUNTEST $exe`; else echo "***************************************************************" echo "Cannot compile endian.c. Aborting. PLEASE REPORT!" exit 1 fi . cleanup_exe case "$doubleformat" in *IEEE*) echo "***************************************************************" echo "Your 'double' type does not follow the IEEE754 format. Aborting" echo "PLEASE REPORT! (dbltor/rtodbl need to be fixed)"; exit 1;; -) sizeof_long=8;; *) sizeof_long=4;; esac echo "Given the previous choices, sizeof(long) is $sizeof_long chars." if test "$fastread" != yes; then cat << EOT If your hardware supports different size of longs (e.g SGI/MIPS), and you want to use a different word size than the above. You should probably have specified some exotic compilation flag CFLAG (e.g -o32,-n32). EOT if test $doubleformat != "-"; then cat << EOT For 32-bit architecture, PARI needs to know the format of your 'double' type. PARI assumes doubles are stored in IEEE754 format [ (sign, exponent, mantissa high) on one word, (mantissa low) on another ]; assuming a union { double d; ulong l[2]; } x; are the double exponent and sign stored on x.i[0] (0) or on x.i[1] (1) ? Using \$CC \$CFLAGS with CC =$CC CFLAGS=$CFLAGS the answer is: $doubleformat. EOT fi fi case $doubleformat in 0) _format='l[0], l[1]';; 1) _format='l[1], l[0]';; -) _format='not needed (64bit)';; esac cat < #include int main(){ printf("%s\n", rl_library_version); return 0; } pari-2.11.2/config/ansi.c0000644000175000017500000000005511636712103013521 0ustar billbillint main(int argc, char **argv){ return 0; } pari-2.11.2/config/has_vsnprintf.c0000644000175000017500000000024212314242551015450 0ustar billbill#include #include int main() { return 0; } int f(int i,...) { char s[1]; va_list ap; va_start(ap,i); vsnprintf(s,1," ",ap); return 0; } pari-2.11.2/config/endian.c0000644000175000017500000000100713201017466014023 0ustar billbill#include #ifdef _WIN64 #define long long long #endif int main() { if (sizeof(long) == 4) { union {double d; unsigned long l[2];} x; x.d = 2.; if (x.l[0]==0 && x.l[1]==(1UL<<30)) printf("1\n"); else if (x.l[1]==0 && x.l[0]==(1UL<<30)) printf("0\n"); else printf("NOT IEEE (32 bit)\n"); } else { union {double d; unsigned long l;} x; x.d = 2.; if (x.l==((unsigned long)1)<<62) printf("-\n"); else printf("NOT IEEE (64 bit)\n"); } return 0; } pari-2.11.2/config/has_wait.c0000644000175000017500000000012611636712103014365 0ustar billbill#include #include #include main(){ wait(NULL); } pari-2.11.2/config/locatedir0000755000175000017500000000017211636712103014317 0ustar billbill#!/bin/sh t=$1; shift; for dir in $*; do file=$dir/$t if test -d $file; then echo $file; exit 0 fi done exit 1 pari-2.11.2/config/get_kernel0000644000175000017500000001036213201017466014467 0ustar billbill# Testing Architectures. Try uname to provide a default, then ask user. # case "$arch" in sparc) asmarch=sparcv8_micro; prettya=Sparc ;; sparcv8_micro) asmarch=$arch; prettya=MicroSparc ;; sparcv8_super) asmarch=$arch; prettya=SuperSparc ;; sparcv9) case "$sizeof_long" in 4) asmarch=sparcv8_micro;; 8) asmarch=none;; esac; prettya=UltraSparc ;; i?86) case "$sizeof_long" in 4) asmarch=ix86;; 8) asmarch=x86_64;; esac; prettya=$arch ;; x86_64) case "$sizeof_long" in 4) asmarch=ix86;; 8) asmarch=x86_64;; esac; prettya='amd64';; ia64) case "$sizeof_long" in 4) asmarch=none;; 8) asmarch=ia64;; esac; prettya=Itanium;; hppa) case "$sizeof_long" in 4) asmarch=hppa; prettya='PA-RISC1.1';; 8) asmarch=hppa64; prettya='PA-RISC2.0';; esac;; mips|mips64) case "$sizeof_long" in 4) asmarch=mips; prettya='MIPS';; 8) asmarch=mips64; prettya='MIPS64';; esac;; alpha) asmarch=$arch; prettya=Alpha ;; ppc|ppc64|ppc64le) case "$sizeof_long" in 4) asmarch=ppc;; 8) asmarch=ppc64;; esac; prettya='PowerPC' ;; arm*|aarch64) case "$sizeof_long" in 4) exe=$osname-$arch-endian$$$exe_suff echo $n "Checking supported ARM kernel: $c" cmd="$CC $CFLAGS -I../src/kernel/arm kernel.c -o $exe"; . log_cmd if test -r $exe; then asmarch=arm; else asmarch=none; fi; echo "$asmarch" . cleanup_exe prettya=$arch;; 8) asmarch=aarch64; prettya=arm64;; esac;; m68k) asmarch=m68k; prettya='Motorola 68k';; sh3) asmarch=none; prettya=SH-3 ;; sh4) asmarch=none; prettya=SH-4 ;; sh5) asmarch=none; prettya=SH-5 ;; vax) asmarch=none; prettya=VAX ;; fx2800) asmarch=none; prettya='Alliant FX/2800' ;; s390) asmarch=none; prettya='S/390' ;; none) asmarch=none; prettya=unknown ;; *) asmarch=none; prettya=$arch echo " Warning ! architecture $arch not tested";; esac # # Modifications for pretty name and asm file # cat << EOM ========================================================================== EOM tmp_kern=auto-auto if test -n "$kernel"; then tmp_kern=$kernel else if test "$fastread" != yes; then cat << EOM An optimized Pari kernel is available for these architectures ("none" means that we will use the portable C version of GP/PARI) ("-gmp" means we will use the GMP library (that needs to be installed)) EOM rep='none sparcv8_super sparcv8_micro ix86 alpha hppa m68k ppc ppc64 x86_64 none-gmp sparcv8_super-gmp sparcv8_micro-gmp ix86-gmp alpha-gmp hppa-gmp m68k-gmp ppc-gmp ppc64-gmp x86_64-gmp' . ./display echo $n ..."Which of these apply, if any ? $c" dflt=$asmarch; . ./myread; kernel=$ans # explicit kernel, needed when checking for gmp in Configure tmp_kern=$ans cat << EOM ========================================================================== EOM fi fi if test -z "$without_gmp" ; then lvl1=gmp else lvl1=none fi tmp_kern=`./kernel-name $tmp_kern $asmarch $lvl1` kernlvl0=`echo "$tmp_kern" | sed -e 's/\(.*\)-.*/\1/'` kernlvl1=`echo "$tmp_kern" | sed -e 's/.*-\(.*\)/\1/'` case "$kernlvl0" in none) prettyk0="portable C";; m68k) prettyk0="m68k";; sparcv8_super) prettyk0=SuperSparc;; sparcv8_micro) prettyk0=MicroSparc;; ix86) prettyk0=ix86;; ia64) prettyk0=ia64;; hppa) prettyk0=HPPA;; hppa64) prettyk0=HPPA64;; alpha) prettyk0=Alpha;; ppc) prettyk0=PPC;; ppc64) prettyk0=PPC64;; x86_64) prettyk0="x86-64";; arm) prettyk0="arm";; aarch64) prettyk0="aarch64";; *) prettyk0="$kernlvl0";; esac . get_pretty echo "Building for: $pretty" cat << EOM ========================================================================== EOM pari-2.11.2/config/extract_files0000755000175000017500000000141413201017466015205 0ustar billbillif test "$osname" = mingw && test "$sizeof_long" = 8; then src_dir="src64" echo $n "Patching PARI source for LLP64 mode... $c" ./config/convertllp64 > /dev/null echo done fi flist=`ls $config_dir/*.SH` for file in $flist; do . ./$file done echo "Extracting scripts and macros" for dir in "$doc_dir" "$misc_dir"; do if test -d $dir; then echo "...in $dir" flist=`ls $dir/*.in` for file in $flist; do sed -e "s%@runtime_perl@%$runtime_perl%g"\ -e "s%@datadir@%$datadir%g"\ -e "s%@bindir@%$bindir%g"\ -e "s%@includedir@%$includedir%g"\ -e "s%@libdir@%$libdir%g"\ -e "s%@version@%$pari_release%g"\ $file > $dir/`basename $file .in` done fi done chmod +x $doc_dir/gphelp $misc_dir/tex2mail pari-2.11.2/config/checkspaces0000755000175000017500000000132613447371554014644 0ustar billbill#! /bin/sh unset LANG LC_ALL LC_COLLATE LC_CTYPE srcbase="`echo src/*/*.[chy] | sed -e 's,src/language/parse\.[ch],,g'`" CFILES="$srcbase src/*/*/*.[ch] examples/*.c examples/*.gp" docbase="`echo doc/*.tex doc/*.1 | sed -e 's,doc/usersch3.tex,,'`" OFILES="$docbase AUTHORS COMPAT NEW TODO CHANGES src/test/in/* src/functions/*/*" SCRIPTS="config/* src/test/dotest" ALLFILES="$CFILES $OFILES $SCRIPTS" err=0; if grep -P '[\x80-\xff]' $ALLFILES; then echo "BUG: high bit found." err=1; fi if grep ' $' $ALLFILES; then echo "BUG: trailing spaces found." err=1; fi if grep ' ' $CFILES $OFILES; then echo "BUG: TAB found." err=1; fi if grep ' $' $SCRIPTS; then echo "BUG: TAB found in scripts." err=1; fi exit $err pari-2.11.2/config/GEN_Make.SH0000644000175000017500000000421611636712103014230 0ustar billbilldir=examples name=Makefile.$osname-$arch file=$dir/$name lnfile=Makefile echo Extracting $file rm -f $file $dir/$lnfile if test -z "$DLLD"; then static=y; fi case "$static" in n) dft=dyn ;; y) dft=sta ;; esac RUNPTH= if test -n "$runpathprefix"; then RUNPTH=`config/ldflags "$LDneedsWl" "$runpathprefix $runpath"` fi cat > $file << EOT # Generic Makefile for PARI programs -- $pretty # # This file was created by Configure. Any change made to it will be # lost when Configure is run. # # make all will create # extgcd-dyn (linked dynamically with libpari) # extgcd-sta (linked statically) # libextgcd.so (to be used by "install" under GP) # # Under GP: install("extgcd", "GG&&", "gcdex", "./libextgcd.so") enables # you to subsequently use gcdex to call extgcd (see the reference manual). # # change this TARGET to compile your own programs TARGET = extgcd SHELL = $make_sh DBGFLAGS = $DBGFLAGS CFLAGS = $OPTFLAGS EXTRACFLAGS= #CFLAGS = \$(DBGFLAGS) # Various linkers use different flags to force static compilation. Choose # the one which is relevant for your installation. # # Solaris ld (global) #STATIC = -dn # Solaris ld (toggle: no shared object accepted until -B dynamic is seen #STATIC = -B static # gcc #STATIC = -static CC = $CC CPPFLAGS = -I. -I$includedir LD = $LD LDFLAGS = $LDFLAGS MODLD = $MODLD MODLDFLAGS = $MODLDFLAGS EXTRAMODLDFLAGS = $EXTRAMODLDFLAGS EXTRALIBS = RUNPTH = $RUNPTH DLCFLAGS = $DLCFLAGS LIBS = $LIBS -L$libdir -lpari RM = rm -f OBJS = \$(TARGET).o DYN = lib\$(TARGET).$DLSUFFIX ALL = \$(TARGET)-sta \$(TARGET)-dyn \$(DYN) dft: \$(TARGET)-$dft all: \$(ALL) sta: \$(TARGET)-sta dyn: \$(TARGET)-dyn dynlib: \$(DYN) \$(DYN): \$(OBJS) \$(MODLD) -o \$@ \$(MODLDFLAGS) \$(EXTRACFLAGS) \$(OBJS) \$(EXTRAMODLDFLAGS) \$(TARGET)-sta: \$(OBJS) \$(LD) -o \$@ \$(LDFLAGS) \$(EXTRACFLAGS) \$< \$(EXTRALIBS) \$(STATIC) \$(LIBS) \$(TARGET)-dyn: \$(OBJS) \$(LD) -o \$@ \$(LDFLAGS) \$(EXTRACFLAGS) \$< \$(EXTRALIBS) \$(RUNPTH) \$(LIBS) %.o: %.c \$(CC) -c \$(CFLAGS) \$(EXTRACFLAGS) \$(CPPFLAGS) \$(DLCFLAGS) \$< clean: -\$(RM) *.o \$(ALL) EOT ( cd $dir ; $ln_s $name $lnfile ) pari-2.11.2/config/genkernel0000755000175000017500000000060113201017466014320 0ustar billbill#! /bin/sh src=$1; shift; K=$src/kernel knone=$K/none EXTRA="divll_pre" for file in "$@"; do echo "#ifndef ASMINLINE" for i in `grep '^ASM' $file`; do case $i in ASM);; *) cat $knone/$i.h;; esac; done echo "#endif" cat $file for i in `grep '^NOASM' $file` $EXTRA; do case $i in NOASM);; *) cat $knone/$i.h;; esac; done done exit 0 pari-2.11.2/config/has_sse2.c0000644000175000017500000000071513326135265014307 0ustar billbill#include typedef __v2di bit_array; #define AND(a,b) ((bit_array)__builtin_ia32_andps((__v4sf)(a), (__v4sf)(b))) #define EXT0(a) ((ulong)__builtin_ia32_vec_ext_v2di((__v2di)(a), 0)) #define EXT1(a) ((ulong)__builtin_ia32_vec_ext_v2di((__v2di)(a), 1)) #define TEST(a) (EXT0(a) || EXT1(a)) #define RBA(a) ((__v2di){((long) a), ((long) a)}) int main(void) { bit_array x = RBA(1L), y = RBA(3L); ulong t = TEST(AND(x,y)); (void) t; return 0; } pari-2.11.2/config/has_sigaction.c0000644000175000017500000000031412314242551015377 0ustar billbill#include int main() { struct sigaction sa, oldsa; sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NODEFER; (void)(sigaction(SIGINT, &sa, &oldsa)); return 0; } pari-2.11.2/config/log_cmd0000644000175000017500000000004112314242551013744 0ustar billbillecho $cmd >&5 eval $cmd >&5 2>&1 pari-2.11.2/config/has_system.c0000644000175000017500000000012613201017466014745 0ustar billbill#include int (*f)(const char*) = system; int main(){ return f != system; } pari-2.11.2/config/cygwin-gprc0000644000175000017500000000017312314242551014577 0ustar billbillhelp = "perl.exe gphelp -cu 6" prettyprinter = "perl.exe tex2mail -TeX -noindent -ragged -by_par" prompt = "(%H:%M) gp > " pari-2.11.2/config/has_ftime.c0000644000175000017500000000014413036414401014521 0ustar billbill# include int main() { struct timeb t; ftime(&t); return t.time*1000+t.millitm; } pari-2.11.2/config/get_static0000644000175000017500000000173411636712103014501 0ustar billbillif test -z "$DLLD" -o "$optimization" != full; then static=y else static=${static-n} fi if test "$fastread" != yes; then if test -z "$DLLD"; then cat < $TMPFL if cmp $FL $TMPFL >/dev/null 2>&1; then rm -f $TMPFL else echo "File $FL updated." mv $TMPFL $FL fi pari-2.11.2/config/get_dlld0000644000175000017500000000750413201017466014132 0ustar billbill# Exported variables _dlld_list='DL_DFLT_NAME DLLD DLLDFLAGS EXTRADLLDFLAGS DLSUFFIX soname sodest DLLTOOL' # Which suffix for Dynamic Lib? # Some linkers (SunOS 4) need minor and major lib version numbers. # Some others (SunOS 5) need a link from a .so # Some others (HPUX 09) do not want version numbers. DLSUFFIX=so soname=.$soname_num do_dll=yes case "$osname" in gnu*|aix|osf1|solaris|linux|freebsd|netbsd) case $pari_release_verbose in *STABLE*) sodest=.$version.$patch;; # released version *DEVELOPMENT*) sodest=.$patch.0.0;; # unstable version esac ;; sunos) sodest=.$VersionMajor$VersionMinor.$patch soname=$sodest;; hpux) soname= ; sodest= ; DLSUFFIX=sl;; irix) soname= ; sodest= ;; os2|cygwin|mingw)soname= ; sodest= ; DLSUFFIX=dll if test "x$DLLTOOL" = x; then if dlltool --version >/dev/null 2>&1; then DLLTOOL=dlltool else DLLTOOL=`$CC -dumpmachine`-dlltool fi fi;; darwin)soname= ; sodest= ; DLSUFFIX=dylib; compat_ver=$VersionMajor.$VersionMinor.0; num_ver=$VersionMajor.$VersionMinor.$patch;; *) do_dll=no ;; esac # dlopen(NULL) should return a handle to the running process. # On FreeBSD 2.2.5 (Y. Uchikawa) and Cygwin, this does not work. case "$osname" in freebsd|cygwin) DL_DFLT_NAME="\\\"\$(LIBPARI_DYN)\\\"" ;; mingw) DL_DFLT_NAME="\\\"\$(LIBPARI_SO)\\\"" ;; *) DL_DFLT_NAME=NULL ;; esac # if DLLD is defined at this point, respect it, even if do_dll=no if test $do_dll = yes -a -z "$DLLD"; then if test -n "$__gnuc__" -o "$osname" = "solaris"; then DLLD="$CC" else DLLD=$ld # don't take risks fi fi GNUdlld= DLLDisGCC= if test -n "$DLLD"; then # Which Dynamic Lib Linker? if test "$fastread" != yes; then echo $n ..."Which linker for building dynamic libs? $c" dflt="$DLLD"; rep=; . ./myread DLLD=$ans fi if test "$DLLD" = "$CC" -a -n "$__gnuc__"; then DLLDisGCC=yes; GNUdlld=$GNULDused else case "$DLLD" in *ld) if ($DLLD -v 2>&1 | grep GNU > /dev/null); then GNUdlld=yes; fi;; esac fi # Which Flags for Dynamic Lib Linker ? dlldflags="$DLLDFLAGS" DLLDFLAGS= if test -n "$GNUdlld"; then DLLDFLAGS="-shared -soname=\$(LIBPARI_SONAME)" else # DLLD != GNU ld case "$osname" in aix) DLLDFLAGS='-r' ;; darwin) DLLDFLAGS="-compatibility_version $compat_ver -current_version $num_ver" ;; freebsd) DLLDFLAGS='-Bshareable -x' ;; hpux) DLLDFLAGS='-b' ;; irix) DLLDFLAGS='-shared -elf -no_unresolved -all' ;; osf1) DLLDFLAGS='-shared' ;; solaris) DLLDFLAGS="-G -h \$(LIBPARI_SONAME)" ;; sunos) DLLDFLAGS='-assert nodefinitions' ;; os2) ;; # see below linux) ;; # for e.g. the Portland Group cc (pgcc) *) DLLD=;; esac fi if test -n "$DLLDFLAGS"; then DLLDFLAGS=`./ldflags "$DLLDisGCC" $DLLDFLAGS` fi case "$osname" in os2) DLLDFLAGS="$CFLAGS -Zdll" ;; # assume DLLD = gcc cygwin) DLLDFLAGS="-Wl,--out-implib=\$(LIBPARI_SO)\$(_A),--export-all-symbols";; mingw) DLLDFLAGS="-Wl,--out-implib=\$(LIBPARI_SO)\$(_A)";; esac if test -n "$DLLDisGCC"; then case "$arch-$osname" in sparc-solaris) extra='-mimpure-text';; *) extra=;; esac case "$osname" in darwin) shared=-dynamiclib;; *) shared=-shared;; esac DLLDFLAGS="$shared $extra \$(CFLAGS) \$(DLCFLAGS) $DLLDFLAGS" fi case "$osname" in # Beware: will run through 'eval' [ hence ${...} instead of \$(...) ] gnu*|cygwin|osf1|freebsd|linux|sunos|solaris) EXTRADLLDFLAGS='-lc ${LIBS}';; esac if test "$fastread" != yes; then echo $n ..."Which flags for linker? $c" dflt=$DLLDFLAGS; rep=; . ./myread DLLDFLAGS=$ans fi DLLDFLAGS="$DLLDFLAGS $dlldflags" fi if test -z "$DLLD"; then echo "No Dynamic Lib" else echo "Dynamic Lib linker is $DLLD $DLLDFLAGS" fi pari-2.11.2/config/get_perl0000644000175000017500000000057113201017466014152 0ustar billbill# set variables depending on perl's version _perl_list="add_funclist" add_funclist= if test -n "$perl"; then res=`$perl -e 'print "OK" if ($] >= 5.005);'`; if test $? != 0; then echo "###" echo "### $perl seems to be broken" echo "###" perl= fi if test "$res" = OK; then add_funclist=yes; fi fi if test -z "$runtime_perl"; then runtime_perl=$perl fi pari-2.11.2/config/get_readline0000644000175000017500000000471413447371554015013 0ustar billbill#exported variables _readline_list="readline readline_version RLINCLUDE RLLIBS" readline= case "$with_readline" in yes|"");; *) if test -z "$with_readline_lib"; then with_readline_lib="$with_readline/lib" fi if test -z "$with_readline_include"; then with_readline_include="$with_readline/include" fi;; esac # Readline -- Headers pth="$with_readline_include" x=`./locate 'readline/readline.h' '' $pth` case $x in ?:/*|/*) rl_include=`dirname $x` echo ..."Found readline header in $rl_include" if (echo $rl_include | grep "readline$" > /dev/null); then rl_include=`dirname $rl_include` RLINCLUDE="-I$rl_include" fi ;; esac exe=$osname-$arch-rlv$$$exe_suff cmd0="$CC $CFLAGS $extraflag $RLINCLUDE -o $exe rl_version.c" try() { RLLIBS=$1; cmd="$cmd0 $1"; . log_cmd; } if test -n "$with_readline_lib"; then readline=$with_readline_lib rl="-L$readline -lreadline" else rl="-lreadline" fi # try linking without locatelib (without -L except --with-xxx-lib) for tlib in "" tinfo ncurses termcap; do t=$rl if test -n "$tlib"; then # need a termcap compatible library? eval with="\$with_${tlib}_lib" if test -n "$with"; then t="$t -L$with -l$tlib" else t="$t -l$tlib" fi fi try "$t" if test -r $exe; then break; fi done readline_version= if test -r $exe; then readline_version=`env LD_LIBRARY_PATH="$LD_LIBRARY_PATH$dir_sep$readline" $RUNTEST $exe`; fi . cleanup_exe case "$readline_version" in *Editline*|*EditLine*) readline= echo "###" echo "### Editline wrapper detected, building without readline support" echo "###";; "") readline= echo "###" echo "### Readline library does not seem to work. Maybe install libncurses?" echo "###";; *) if test -z "$readline"; then readline=yes; fi;; esac if test -n "$readline"; then if test "$fastread" != yes; then cat << EOM ========================================================================== GNU readline provides line editing in the gp shell, with history and context-dependent completions. You should really answer 'yes' to the following question, unless you are trying to overcome a problem in the default build. EOM echo $n "Do you want to use GNU readline library within GP ? $c" rep='y n'; dflt=y; . ./myread case $ans in n) readline=;; esac fi fi if test -z "$readline"; then echo "### Building without GNU readline support" RLLIBS= RLINCLUDE= else echo "Using GNU readline, version $readline_version" fi pari-2.11.2/config/cleanup_exe0000644000175000017500000000005313201017466014634 0ustar billbillrm -f $exe rm -rf $exe.dSYM rm -f $exe.mem pari-2.11.2/config/myread0000755000175000017500000000075211636712103013636 0ustar billbillif test "$fastread" = yes; then echo "[$dflt]" ans=$dflt else if test -n "$dflt"; then echo $n "[$dflt] $c"; fi while :; do read ans case "$ans" in '') ans="$dflt" break ;; !*) ans=`echo "$ans"|cut -c2-` break ;; *) if test -z "$rep"; then break; fi for i in $rep; do if test "$i" = "$ans"; then break 2; fi done echo $n "*** Please try something else : [$rep] $c" ;; esac done fi pari-2.11.2/config/get_objdir0000644000175000017500000000163313036414401014455 0ustar billbill# Target directory for object files pre=O objdir=$pre$osname-$arch; if test -n "$dfltobjdir"; then if test "$dfltobjdir" = auto; then case "$kernlvl0" in $asmarch);; sparcv8_micro) if test "$arch" != sparcv9; then objdir=$objdir-$kernlvl0; fi ;; *) objdir=$objdir-$kernlvl0 ;; esac if test -n "$with_gmp"; then objdir=$objdir-gmp; fi dfltobjdir= else objdir="$dfltobjdir" fi fi if test -z "$dfltobjdir"; then case "$optimization" in full) objdir=$objdir;; debugging) objdir=$objdir.dbg ;; profiling) objdir=$objdir.prf ;; gcov) objdir=$objdir.gcov ;; esac fi if test "$fastread" != yes; then cat << EOT ========================================================================== This is the name of the directory where all the object files will be: EOT echo $n ..."Enter dir name : $c" dflt=$objdir; rep=; . ./myread objdir=$ans fi pari-2.11.2/config/has_exp2.c0000644000175000017500000000011611636712103014276 0ustar billbill#include double (*f)(double) = exp2; int main(){ return f != exp2; } pari-2.11.2/config/gmp_version.c0000644000175000017500000000035713201017466015124 0ustar billbill#include #include void f(void) { mpn_gcdext(NULL,NULL, NULL, NULL, 0, NULL, 0); } int main() { if (sizeof(mp_limb_t) == sizeof(long *)) printf("%s\n", gmp_version); else printf("unsupported\n"); return 0; } pari-2.11.2/config/install0000755000175000017500000000060011636712103014013 0ustar billbill#! /bin/sh mode=755 while test $# -gt 0; do case "$1" in -c);; -m) shift; mode="$1";; *) break;; esac shift done if test -d "$2"; then file="$2/`basename "$1"`" else file="$2" fi if test -d "$1"; then mkdir -p "$file" for f in `ls "$1"`; do "$0" -m "$mode" "$1/$f" "$file" done else cp "$1" "$2"; if test -f "$file"; then chmod "$mode" "$file"; fi fi pari-2.11.2/README-git0000644000175000017500000001032012314242551012612 0ustar billbillWe use the GIT open-source revision control system. For us developers, it provides network-transparent source control. For ordinary users it provides a convenient way to obtain patched versions in between releases, or follow development branches. GIT clients are available for all major platforms: Unix, MacOS, Windows, see http://git-scm.com/download In particular, the git command-line client is readily available in all Linux distributions. Note: We worked happily for many years with CVS, then Subversion, and provided anonymous read-only CVS / Subversion servers. The transition period is over: fetching PARI using this method is no longer possible; please upgrade to GIT. This file documents access to the PARI GIT server, which is intended for PARI lovers who want the very latest bleeding edge release and development branches. These sources may contain severe bugs, they may not even compile, benches may fail and so on. Stable releases are made available on a regular basis using the customary method: a message to pari-announce. Note that in order to use the sources fetched via GIT, you will need a working bison and perl installation, as well as the regular build toolchain. 1) First connection to the GIT repository: ========================================== To get a working copy, type the following command from the shell git clone http://pari.math.u-bordeaux.fr/git/pari.git This creates a local copy of the distribution from the distant repository in local directory pari, which you may move or rename as you wish. From now on, you can cd to this pari directory and use any git command directly, as long as you remain there, or in a subdirectory. 2) What can I do now ? ====================== * You can build pari in the usual way (see INSTALL) as if this 'pari' directory had been created by fetching, then extracting, an archive on an FTP server. * You can update your local copy at any time using git pull, which puts you in synch with the repository. * You can list all available development branches using git branch -a. To checkout a specific branch, type git checkout branchname. The two main branches are master (testing branch) and pari-2-5 (updates to old stable branch). Other branches are customarily named after the developer who sent the initial patch and the proposed feature, and eventually merged into master. * You can create your own private branches: for instance, the following creates a local branch my-branch, starting from a copy of some-branch you found on our server. git checkout origin/some-branch -b my-branch Of course, you can modify files in your copy and commit changes to your local branches. You can send the output of the relevant git diff command, to the pari-dev mailing list with a short description of what you have done. (No need to subscribe to the mailing list to post, but it will allow you to follow the discussion!) * On the other hand, you will not be able to commit your changes to our GIT repository using anonymous access. For this, you will need read-write access, which requires an account on our development machine. 3) Version tags and branches: ============================= Official releases (starting from version 2.0.17) are 'tagged' so that all files pertaining to a given release can be simultaneously accessed without tracking version numbers. Tag names are pari-version with dots replaced by dashes, e.g. pari-2-0-20 for 2.0.20. To fetch a specific version of pari (2.0.17 or more recent), type for instance git checkout pari-2-0-20 The branch pari-2-5 denotes the stable branch 2.5.* as a whole, and can be used to checkout up to date sources from that branch in between releases. For instance: git checkout pari-2-5 produces the latest stable distribution with all relevant patches (the ones not affecting stability) backported. Tips and Caveats: * git diff gives you the difference between your local copy and the sources they were based on, not with the current state of the testing branch on the PARI repository. Use 'git diff master' for that. * To see the log message associated to the last commit leading to the current state of your local repository, type 'git show'. You may add a file or directory name to get the log message for the last commit which modified it. pari-2.11.2/CHANGES-2.20000644000175000017500000064100111636712103012452 0ustar billbill# $Id$ Bug numbers refer to the BTS at http://pari.math.u-bordeaux.fr/Bugs/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.3.0 (released 19/05/2006): Fixed 1- ispower(HUGE t_INT, n) could give wrong results (rounding errors) 2- ellheightoo (internal) and RgXQ_norm (public) not declared BA 3- [m68k kernel] didn't compile + need -fPIC 4- libpari.so: soname was incorrect %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.13 (released 26/04/2006): Fixed BA 1-[HPUX] 'program' bench failed for gp-sta [install did not work] 2- made BITS_IN_LONG and related constants 'signed long' [ avoid problems like : exp(10^10) --> 10^10 + 1 (silent overflow) ] 3- --kernel=none : libpari ended up not containing the 'divll' symbol 4- polgalois(x^3-2) --> [,,,"A3"] when new_galois_format was unset. 5- problem with negative valuations in ggcd(t_PADIC) [#411] 6- Fp_pow for huge moduli could return a negative number [#417] 7- y;x/y/z/x --> error [#410] 8- polredabs(x^4-35048*x^2+1016392*x-7368842) --> same, instead of x^4 - 17524*x^2 + 69403802. Rounding error, due to setting the relative precision wrt the wrong reference object. 9- nfisideal() could raise an error instead of returning 0 10- nfreducemodpr only accepted nf's (not bnf's or richer) 11- 1/a/x --> 1/a/x; 1/(a*x) --> 1/(a*x). Now 1/(a*x) in both cases (unify t_RFRAC normalization routines) 12- content(1.*a*x) --> 1 [ now returns a ] 13- content(1./a*x) --> 1.00000/a, but content(1./a*x + 1./a) --> 1/a [ now returns 1/a ] 14- t_SER ^ t_FRAC introduced floating point numbers even when rational expression available, e.g (8 + x)^(1/3) 15- round(t_POL/t_SER, &e) with leading coeff rounded to zero 16- trace(Mod(y,x)) --> SEGV 17- gcd(1, 1/x) --> 1 [ gcd(Pol(1),1/x) correctly returns 1/x ] content(x/y + 1) --> 1 [ content(x/y) correctly returns 1/y ] content(x + 1/y) --> 1 [ also wrong in pari-2.1.7 ] content(1/x/y) --> 1 [ should be 1/y ] 18- missing vectors in qfminim(x,b,,2) [ m omitted ] 19- 'make test-kernel' [ wouldn't compile ] 20- matsnf(matrix with t_POL entries, 1) ---> incorrect matrix V 21- O((-2)^3) --> invalid object 22- (0.*x)*(0.*x) --> 0.E-57 [ instead of 0.E-57*x^2 ] 23- qfminim(x,,m,2) [b omitted] -> [n,B,v]: output correct vectors (v), but reported too many (n too large). 24- qfminim(x,,,2) wrong when x has huge entries. Work out a sensible default precision if x has exact entries. BA 25- HPPA 32bit level0 inline assembly addmul constraint was too weak. 26- factorback(x,y) --> error if x,y were valid t_VEC with exactly 6 components [ typo in checknf_i ] 27- [configure] shared libraries on 64bit sparc require -fPIC / -KPIC 28- (x^3/y^3)^(1/3) -> x + O(x^17) [ leading coeff sometimes lost #433 ] 29- ??INT worked, but not ??t_INT 30- inconsistencies wrt variables in t_POLMOD, e.g Mod(x*a,x^2)' ---> Mod(x, x^2) deriv(Mod(x*a,x^2)) ---> 0 31- contfrac(sqrt(19),2^31-1) --> overflow [ signed overflow can't be reliably tested, use unsigned computations ] BA 32- on x86_64 + gcc-4.0, CFLAGS was missing a -fno-gcse-after-reload 33- [output=3] give more time to external prettyprinter [#209] 34- rare SEGV in factor(t_INT) with low stack space [ #345 ] 35- ispower(1) --> error, ispower(-8) --> error [ allow negative numbers ] 36- Configure -a + kernel = $arch-gmp didn't work [missing -lgmp #438] 37- divisors([]) --> SEGV [#441] 38- missing GC in bernfrac 39- bnrrootnumber(bnrinit(bnfinit(x),1),[]) --> SEGV [#443] 40- f()= local(m = matrix(2,2)); m[1,1] = 1 f() --> m[1,2] also set to 1 41- make test-kernel would always fail with gmp kernel. 42- elllseries(e, 0.) --> error [ only elllseries(e,0) worked ] [#445] 43- 'ftime' was never detected by Configure 44- setrand(74);quadclassunit(-83138791008,,[0.2,6]) --> oo loop [ large prime relation hashtable corrupted when changing subfactorbase ] 45- a(k)=if(k==0,0,a(k)=a(k-1)) a(1) --> SEGV [#447] (add refcounts to 'user function' structs) 46- getheap() did not report properly the "size" of user functions (value too small) 47- add compatibility macro decomp -> Z_factor [ used by mwrank ] BA 48- minpoly(,,v) might return polynomials in x instead of v. 49- make test-kernel required inlining compiler 50- make test-kernel didn't work with C++ compilers 51- ia64 kernel assumed 64bit longs, whereas compilers can be configured for 32bit Changed 1- RgX_simple_gcd: make sure result has non-zero leading term [#412] 2- simplify(t_RFRAC): remove assumption that deg(denom) > 0 [#413] 3- split bfffo.h from level0.h 4- semantic of t_SER with inexact coefficients is now the same as for t_POL: the sign is 0 iff all coefficients are zero. Either there are no coefficients, or the leading coefficient is an inexact zero. 5- removed all non-inline assembler kernels : they were complicated to Configure, mostly untested, and inefficient ( function call overhead + must use global variable hiremainder/overlow when operating on limbs instead of LOCAL_HIREMAINDER trick ). If this slows down your application (it should not), install gcc or use the gmp kernel. 6- allow arbitrary n in divisors(n) and fordiv(n,), provided factor(n) succeeds [ was restricted to t_INT or their factorization matrix ] 7- made LLL the default algorithm in algdep / lindep again [ replaces PSLQ ] Our PSLQ implementation is slow and unstable, and LLL performs much better, see the example in ??algdep. 8- addrr: extend accuracy much less frequently 9- make sure all kernel symbols are present in all versions of libpari (addll & friends could be inline) 10- change the meaning of gcd(x) and lcm(x) when x has vector/matrix components (a global recursive gcd/lcm is taken, instead of a cartesian product of individual gcd/lcm) 11- disallow vecmin([]), vecmax([]) [ returning stoi(+/- BIGINT) is not helpful ] 12- [libpari] renamed lellseries -> elllseries [ as in GP ] 13- semantics of stackdummy() [ make it consistent with gerepile ] 14- never assume that part of an object is "permanent" when it is out of the stack (was used by INTMOD/POLMOD/PADIC). Always copy it. As a result, 'gmodulo' and 'forcecopy' become obsolete. 15- use quadclassunit in qfbhclassno for large D, thereby ASSUMING GRH. 16- ellan was bypassing the check for CM 17- uniformize the generation of parilvl0.h [ genkernel ] Added 1- [library] new function isinexact. BA 2- [elldata] function forell() to loop over elliptic curves. BA 3- [elldata] function ellconvertname() to parse curve name. 4- [library] new function RgX_shift, RgX_mulXn, RgX_shift_shallow, RgX_Rg_div BA 5- m68k level0 inline assembly kernel 6- [library] new function isint, issmall, mkrfrac 7- Configure --time=timing_fun 8- [Configure] genkernel script Removed 1- kernel functions shiftl / shiftlr (inefficient, unused, untested) [ backward compatibility version in src/kernel/level1.h ] 2- obsolete functions forcecopy (use gcopy) and gmodulcp (use gmodulo). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.12 (released 24/01/2006): Fixed 1- incorrect detection of EditLine library 2- issquare(Mod(2,9)) --> 1 [ should be 0 ]. Implicitly assumed v_p(N) odd for all primes divising the modulus N. BA 3- poltschirnhaus(ffinit(2,4)) could return 0. BA 4- Configure -a did not propose fltk and Qt as graphic engine. 5- g()=local(x;f) -- oo-loop [#352] 6- charpoly( Mod(a, b) ) --> wrong result when 'a' is not a t_POL or t_INT. 7- \p2051 log(exp(-1)) --> printing bug [#357] 8- bad argument checks in qfrep() / qfminim() [#359] 9- fix mkintn to work as documented (even when leading word is 0) BA 10- [Linux] gp only accepts one SIGINT in batch mode [#251, #370] (initial patch JD). 11- contfrac(5/3.) was wrong: [1,2] instead of [1,1,2]. For a t_REAL x, when the last partial quotients of a lower and upper bound differ by 1, choose the one associated to the digits of x (followed by infinitely many 0s) unless it was too small and the next partial quotient was 1. [#371] 12- bnfisintnorm: results could have a wrong sign [#372] 13- isprime(N,2): oo loop if N is a perfect square 14- \p n was limited to a value ~ 10 times smaller than the actual limit BA 15- qfbsolve fix 2.2.11-F86 was not sufficient. 16- (1 + O(2))^2 was less precise than sqr(1+O(2)) 17- in the extended help pager, typing ' ' then \n would skip one page [#375] BA 18- config/has_stat.c didn't work with g++ 19- charpoly/minpol(Mod(a,T)) was only monic if T was. BA 20- 'make install' did not work if 'prefix' contained spaces 21- has_dlopen always compiled in on Mac OS X, even if present in libc 22- unsafe handling of t_QFI/t_QFR (setsigne) [#384] 23- idealaddtoone didn't handle zero ideals [#386] 24- workaround a bug in g++ version 3.4.1 (Mandrakelinux 10.1 3.4.1-4mdk) infinite loop on factor(41093858855767145965571) 25- constlog2() was not restartable [ no way to set glog2 = NULL ] 26- sloppy arg check in ellchangecurve [#388] 27- [internal] gprec_w reduced the accuracy of real 0s [#396] 28- wrong arg check in matsolve [#400] 29- minpoly([;]) --> SEGV 30- y*x^3/( 1+x+x^2 +O(y)) -> gerepile error [#403] 31- poldivrem didn't handle properly multivariate polynomials [#402] 32- insufficient accuracy in ellheight --> singular curve, SEGV [#404] 33- [MacOS X + fltk] installed gp binary couldn't use hi-res graphics (resource fork not copied) IZ 34- [2.2.9-A20] -fno-strict-aliasing not supported in older gcc 35- heapsize reported by getheap() were wrong (overestimate). 36- gerepile error in nfgaloisapply [#408] 37- wrong results in bessel functions at non-integer indices (typo in isint(t_REAL) ) [#409] 38- vector(3,n,n*=10) -> [10, 100, 1000] ( now [10, 20, 30] ) 39- bnf.codiff didn't work 40- content([[2]]) --> error Changed 1- speed up prime() by using checkpoints. 2- allow lists with vector entries in listsort (use lexsort) 3- allow vector of points in ellisoncurve() 4- tunings in quadclassunit (#298 / #355) 5- [Configure:] take CPPFLAGS into account 6- 'int' C type is now reserved for -1/0/1 values. Use 'long' otherwise. 7- Fl_inv and Fl_div now raise an error when divisor not invertible [ used to return 0 ] 8- removed the threshold that prevented exponent overflow in exp(-10^10) and returnd 0. instead [ either return correct digits or raise an exception ]. VL 9- honor C_INCLUDE_PATH in Configure (for get_readline) 10- [readline] remove old hack bypassing a bug in readline-2.0 [ did not release SIGINT ]: useless nowadays, and used deprecated functions. 11- export combine_factors [ needed by giac ] 12- do not alias labs to abs in paricom.h 13- randomize polredabs() to improve bound on difficult fields, e.g. f(k) = { p = polcompositum(x^6-3*k^3,x^6-3*k^3)[4]; polredabs(poltschirnhaus(poltschirnhaus(p)),16) } for k = 2, 5, 6, 8, ... 14- try more names in 'pari_unique_filename' (26^2 instead of 26)) 15- remove GCC_INLINE from CFLAGS. Define DISABLE_INLINE or DISABLE_VOLATILE to prevent the compiler from inlining or using the 'volatile' keyword 16- let paripriv.h include parinf.h 17- rename 'prec' -> 'precreal' [ from paripriv.h ] BA 18- define INLINE to 'inline static' for C++ compilers also 19- rename polx -> pol_x, polun -> pol_1 20- make hell, hell2 static to elliptic.c 21- rename decomp -> Z_factor, decomp_limit -> Z_factor_limit 22- rename wf -> weberf, wf1 -> weberf1, wf2 -> weberf2 23- make incpos / incneg static 24- export setseriesprecision, setrealprecision BA 25- make pari restartable 26- [initialization of GP hashtables] remove the 'module' structure, simplify pari_addfunctions, plug helpmessages in initializing entree arrays. 27- rename err -> pari_err, pariputsf -> pariprintf 28- rename rnfhermitebasis -> rnfhnfbasis 29- forbid t_STR, t_VECSMALL and t_LIST in gvar. 30- cleanup mpqs use of temporary files 31- pari_unique_filename now MT-safe, returns a malloc'ed buffer. 32- default() now always returns the value of the (possibly changed) default. No need for a flag anymore. The construction default(def,,1) is still valid but deprecated (the flag is ignored). 33- increase default accuracy in ellinit() when curve has large coefficients [ avoid large relative error on periods, #404 ] 34- qfminim(,,,0) often gives wrong results for matrices with large entries. Test whether rounding errors occur and abort if so [#407] 35- qfminim(x,b,m,flag): b and m are now optional. Allow omitting b (formerly b=0) if flag = 2 also. 36- eval("1a") is now '1' again (was "a" since 2.2.10) Removed BA 1- gnuplot graphic engine (complicated, did not work from gnuplot-4 on) 2- has_sigrelse.c & has_sigsetmask.c [ deprecated, unused after C-10 ] 3- src/desc/Makefile 4- log2old ( = 2atanh(1/3) ) 5- src/desc/gen_help BA 6- obsolete macros INIT_JMP/INIT_SIG Added 1- library function ellisoncurve() BA 2- library functions related to sorting: gen_sort_aux, gen_search_aux, vecsmall_indexsort 3- functions strtoi, strtor BA 4- function minpoly() 5- function zeromatcopy() BA 6- support for GNU/kFreeBSD and other GNU userlands. 7- document ZY_ZXY_rnfequation and ZY_ZXY_resultant 8- function pari_warn() use instead of pari_err() for warnings 9- function pari_add_function, pari_add_module 10- doc/develop.tex 11- library function uisprime, uissquarerem, Z_issquare, Z_issquarerem 12- library function pari_unique_dir 13- library function gp_default 14- library function rowcopy (GP2C) 15- library function traverseheap %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.11 (released 19/10/2005): Fixed 1- a()=b(1,) --> error message 2- agm(-1.0000000004656,1) --> oo loop [Bug #214] 3- sdivss_rem(x,y,&rem) did not set rem, contrary to the documentation BA 4- ellzeta(ellinit([0,0,0,0,1]),1) --> gerepile error 5- random() was less random on 64 bit machines 6- typing 0.e-28 returned 0.E-38 (!) 7- ellminimalmodel(e).a2 was not always in {-1,0,1} 8- check arguments in elllocalred BA 9- [GP2C] type-checking codes generated for some types was wrong. 10- stray output: (a()= for(i=1,1, return);) a() --> 0 11- qfminim & qfrep didn't check their arguments 12- [library:] pariputsf() and GP print() used different output formats 13- nfdisc(x^4 - 2947*x^2 + 1553545) --> SEGV [ incorrect test for gcd in Round 4: gcmp1(d) --> degpol(d) == 0 ] 14- forvec(v=vector(4,k,[1,4]),,2) -> oo loop [bad initialization] 15- eta(x << 1) used far too much accuracy in intermediate computations GN 16- MPQS warning "factoring this number will take several/many hours" now assume more current hardware. 17- off-by-1 error in initprimes0 allocation [Bug #237] -> SEGV in default(primelimit,155100 + 41*7) 18-[Cygwin] incorrect links created by 'make install' 19- a( --> oo loop in parser [Bug #240] 20- at \p366, the last digits of Pi were wrong [ not enough iterations, from 2.2.9, A-2]. [Bug #238] GTo21- wrong prototype for qfrep 22- factornf(P, T) did not accept non-monic T [Bug #241] 23- lngamma(1E+10) --> "Impossible assignment I --> S" 24- "couldn't deal with this field" errors in bnfinit/quadclassunit for tiny discriminants, huge Bach constants (e.g. 12), and unlucky random seeds. Remove arbitrary limits and let the loop run to completion. 25- neither freadseq() nor readGEN() were able to parse '{' / '}' [Bug #216] 26- accuracy problem in polroots (--> division by zero) [Bug #252] 27- acos(x < 0) --> result off by Pi [ introduced in 2.2.9-A3 ] 28- ellrootno(e,p) incorrect in the case of good reduction [#262] 29- (rare) "impossible assignment I-->I" in contfrac 30- typo in qfbclassno's hash function (when D < 0, function can't handle 0). qfbclassno(-948) --> division by 0 [GMP kernel] 31- [Makefiles:] the behaviour of '//' as path leader is undefined. Make sure path prefixes are not '/' [ e.g $prefix/lib --> //lib ] 32- pollead(u*v + (v+1)/v, v) --> 'x' [ should raise an error ] GN 33- problems in MPQS : some factors missed e.g factor(2^263-9) --> expensive extra runs ( + possible stack corruptions when many factors found simultaneously ). 34- tanh(x) was actually computing tanh(|x|) for real x ([#269] from 2.2.8) 35- [MacOS X] dlopen is now part of the system library. Don't redefine dlopen in darwin.c if HAS_DLOPEN is defined. 36- fix Trager's trick in factorff (from 2.2.10) 37- rnfisnorminit(quadpoly(145,y),quadray(145,1)) --> stack overflow [#273] 38- matker([1,2,3;4,5,6]*1.) --> [;] (missing 1 vector) 39- rnfconductor(bnfinit(y),x,1) --> error [#277] 40- gcc-4.0 miscompiles PARI on ix86 [#274] ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23453 ) 41- truncate(1/4/x+1+O(x)) -> (x + 1/4)/x instead of (4*x + 1)/(4*x) [#276] 42- bitneg(2^32-1,32) -> corrupt integer [#279] 43- typo in rnf_is_abelian [#277] GN 44- several minor fixes in mpqs.c BA 45- ellrootno(e,2) was wrong for curves of Kodaira type 3 and -7. ([#212] from 2.2.9) BA 46- galoisfixedfield() was not robust enough ([#256, #228 from 2.2.9) 47- tanh(-10^20) --> error instead of -1 [tanh(10^20) was treated properly] BA 48- wrong rounding in wr_float: with default(format,"f0.10") 1.23456789049999999997 -> 1.234567891 GH 49- typo in thue.c:MiddleSols() --> missing solutions [#264] 50- default(prettyprinter,,1) --> t_POL instead of t_STR [#296] BA 51- truncate(1/x+O(x)) --> SEGV 52- overflow in Flm_gauss (when solving triangular system) --> wrong result [#284] 53- isprime(25, 2) *** impossible inverse modulo: Mod(5, 25). although it's useful to get a factor, it's not nice to raise an error, since 'trap' then becomes mandatory. Removed this feature: the factor is silently discarded (exceedingly rare anyway). 54- (-1)^(any integer >= 2^31) --> -1 [ from 2.2.9 ] GH 55- zncoppersmith(x,1002,1001) --> SEGV [#221] 56- subst(1+O(x),x,x^2+O(x^3)) --> SEGV [#287] (patch by MSo) subst(1+O(x^2),x, x^2+O(x^3)) --> 1 + O(x^3) [ should be O(x^4) ] 57- component() didn't work on lists [ SEGV ] 58- quadclassunit(D,, [c0 > 6]) --> weird error message 59- weird errors in bnrstark [#285] 60- (x^0)^2^31 --> length overflow 61- polroots(pollegendre(51),1) --> SEGV [#293] 62- print({}) --> oo loop BA 63- when choosing between (p-1) and APRCL, isprime() required a complete factorization of p-1, whereas accumuluting factors up to sqrt(p-1) was enough. (e.g 2^127 - 1) BA 64- function name not always properly reported on interrupt (e.g if, while) 65- content([-1]) --> -1 66- memory leaks in quadclassunit (#318) BA 67- [Configure] check that 'readline' is not an EditLine wrapper [ ==> compilation failure otherwise ] 68- Str() --> junk string (uninitialized data) (#326) 69- arg(I*O(7^5)+1) --> junk, exp(3*I + O(3^5)) --> junk. (#328) 70- powiu(2, ulong n) called int2n(long n), incorrect for huge n (#331) 71- Qfb(8,-4,1)*Qfb(5,-4,1) --> Floating Point Exception (BIB, #332) 72- t_QRF distance component was evaluated using an unstable algorithm, possibly leading to catastrophic cancellation (#333) 73- dbltor did not recognize Infinity, NaN, or unnormalized numbers. 74- makerfrac(1,quadgen(24)*x^0)%b --> SEGV, where GEN makerfrac(GEN p,GEN q) { GEN z=cgetg(3,t_RFRAC); z[1]=lcopy(p); z[2]=lcopy(q); return z; } BA 75- exp(x) gave imprecise results at huge accuracies for expo(x) >> 1. 76- valuation(x,p) using a divide & conquer algorithm would kill the session if p = 1 77- (2 + O(2^8))^(-1/3) --> SEGV [#341] 78- exp(0.E100) --> invalid GEN 79- stack corruption in gsubst [#343] 80- Pol([Mat(0.1)],x)^3. --> crash [#346] 81- besseljh(0,2^65) --> crash [#340] BA 82- [plotQt:] ^C while hi-res window is present would crash the session 83- Strtex(Vecsmall) --> SEGV [#348] 84- oo loop in zeta() [catastrophic cancellation in get_xinf() ] 85- oo loop in nfdisc() [#350] 86- Mod(1,2)*x / (1/2) --> incorrect t_POL 87- qfbsolve forgot some solutions: qfbsolve(Qfb(2,1,3),3) --> 0 88- multiplying ideals could lead to factoring big integers (failsafe algorithm in idealtwoelt, when random trials don't work): fix idealtwoelt. Changed BA 1- FpM_FpV_mul is renamed to FpM_FpC_mul, Flm_Flv_mul to Flm_Flc_mul and FlxV_to_ZXC to FlxC_to_ZXC, Flv_to_ZC to Flc_to_ZC, FqV_to_FlxC to FqC_to_FlxC, zv_to_ZC to zc_to_ZC BA 2- FpXV_FpV_innerprod renamed to FpXV_FpC_mul and FlxV_Flv_innerprod to FlxV_Flc_mul 3- retain 'CHANGES' revision after 'make distrib' GN 4- extensive re-tuning in MPQS (all sizes) and avoid "sizing marginal, index1 too large" warning 5- rename globalreduction -> ellglobalred, localreduction -> elllocalred 6- taniyama(e) is deprecated. Use elltaniyama(e, prec) instead of old = precdl; precdl = prec; x = taniyama(e); precdl = old; 7- [bnfinit] retune compute_R to try and detect cheating with Bach's constant. 8- rename lisexpr -> readexp, lisseq -> readseq, flisexpr -> freadexpr, flisseq -> freadseq 9- rename Fp_gener -> gener_Fp, Fl_gener -> gener_Fl 10- change TeX output so that it's easier to handle: - replace \over by \frac [ most people use AMS styles which forbids \over, not plain TeX, which doesn't have \frac ] - remove many extra braces { } [ would prevent line breaks ] - insert carriage returns 11- [GP handling of print1()] get rid of 'added_newline' hack, replace by monitoring in pariputc/pariputs.[#243] 12- do not install libpari.a.xxx [ include files are not versionned either and libpari.a is useless without the correct ones, contrary to .so ] 13- rename gtrans_i -> shallowtrans, concatsp -> shallowconcat. 14- add GC in parsing loop for huge input vectors [ needs roughly 2 or 3 times less memory ] 15- implement pari_is_dir() using stat() instead of opendir() 16- moved defaults from gp/gp.c to language/default.c [ -> into libpari ] 17- moved input_loop to language/es.c [-> into libpari ] 18- when called as 'gp --test', disregard actual terminal dimensions 19- allow ellinit over any ring (support only basic operations) 20- allow ellchangecurve on e = [a1,a2,a3,a4,a6]. 21- typecast cleanup: move most of paricast.h to pariold.h 22- rename readGEN -> gp_read_stream, freadseq -> gp_read_str. freadexpr/readexpr are deprecated, use gp_read_str/readseq 23- make sure GP_DATA is always defined --> default() becomes available in libpari 24- make gnil public 25- change content() so that it always returns the gcd of all entries (as documented). Used to return the gcd of all _contents_ of the entries of a t_VEC/t_COL/t_MAT. 26- backport into quadclassunit some of the bnfinit improvements [specifically, change subfactorbase, #298] BA 27- rewrite rectdraw in an object-oriented way [ reduce code duplication in hi-res plot routines ] BA 28- change the semantic of includedir to not include the pari suffix. Instead /pari is automatically added by make install. 29- improve plindep (use lllintpartial and floating point LLL) + allow lindep with p-adic entries BA 30- allow relative paths in Configure --with-xxx directives BA 31- allow sinh, cosh, tanh with t_PADIC arguments XR 32- bnrstark(): try harder to find solutions [increase precision faster #255] BA 33- rename coefs_to_xxx() to mkxxxn() for xxx in {vec,col,pol,int}. 34- semantics of gcd with inexact zeros: now gcd(0., a) is 1 [used to be a and led to problems: e.g 0./(1.*a)/(1.*a) not simplified ] 35- warn if 'perl' is found but doesn't seem to work 36- forbid the f'(x) construction when x is not a constant type [#327] Added BA 1- polgalois(): 4th component: transitive group name following GAP4 BA 2- new functions ZX_add, ZX_sub, ZX_neg, ZX_Z_add, ZX_Z_mul BA 3- new functions FpC_to_mod, FqV_to_FlxV, FpC_red 4- member functions r1, r2 5- functions factoru(), factoru_pow(), powiu(), powuu(). 6- symbolic link $MANDIR/gp-$version.1 -> $MANDIR/gp.1 7- new functions shallowcopy, shallowconcat, shallowtrans, vecslice, vecpermute, vecslicepermute, rowslice, rowpermute, rowslicepermute BA 8- support for gp2c-run on cygwin BA 9- new optional package 'elldata' and new GP functions ellsearch and ellidentify to access it. BA 10- support for ellinit("") through elldata. 11- new functions vec_ei / col_ei BA 12- new function FpC_Fp_mul, FpV_FpC_mul BA 13- new functions const_col, const_vec, vec_is1to1, vec_isconst 14- new function gp_read_file BA 15- new function substvec BA 16- new divide_conquer_assoc (make divide_conquer_prod thread-safe) 17- p-adic zeta, cos, sin, tan, cotan BA 18- p-adic gamma BA 19- new routine readvec() %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.10 (released 17/04/2005): Fixed BA 1- gp2c description of == operator was broken. 2- asin(I) --> SEGV, acos(1 + 0. * I) --> SEGV, atan(I/2) --> SEGV sqrt(0*I),acosh(1+0*I) --> oo loop 3- make test-kernel didn't work [missing gen_m1 & int2n] 4- thetanullk(1/2,1) --> SEGV [from 2.2.9] 5- unit component in factor(t_INT + 0*I) was wrong 6- no typecheck for qfbhclassno input 7- diviuexact destroyed input and made further assumptions [=> wrong results in ellglobalred]. Replaced it by a clean wrapper. GH 8- thue(thueinit(x^3 - 2), 2) --> SEGV 9- reorder([1]) --> SEGV (bad input, but sanity check was wrong) 10- rnfconductor(,1) [ = rnf_is_abelian() ] didn't accept polynomials with POLMOD coeffs + used a wrong algorithm [ not modular + wrong result ] 11- broken code in hnfmodid() wrt GC (would add one 0 column, Bug #129) 12- sqrti(gen_0) --> SEGV [native kernel] BA 13- polrootsmod(,,1) could return a line vector instead of a column. 14- issquare(Pol(1)) --> SEGV BA 15- polsubcyclo() used too much memory for large conductors. 16- typo in quadtoc() --> quadgen(odd t_INT)*1. was wrong 17- subgrouplist([], [2]) --> [[;]] (instead of []) 18- typo in FqX_split [ (!degpol(x)) --> degpol(x) <= 0 ] -> very rare SEGV 19- after alias(a, b); kill(b), invoking 'a' would access corrupted data 20- round(-0.5) --> -1 [ should be 0, as was output by round(-0.5, &e) ] RS 21- gcc-3.4 breaks on compatibility code to support old readline versions [ pre-4.2 ]. Typecast parameters, not functions and dump (approximate) support for g++ + old readlines in gp_rl.c 22- \p 8000 E=ellinit([0,0,0,0,1296]); P=[-8,28]; ellpointtoz(E,P) --> oo loop 23- idealaddtoone(nfinit(y),[0]) --> SEGV [ BIB ] 24- aprcl would wrongly report composites [ introduced aprcl.c:1.48, before release-2-2-8 ] 25- ellchangecurve(e over Qp) --> e.w not updated 26- ellheight(e over Fp, pt) --> SEGV 27- issquare(Mat(2), &z); z --> SEGV [ don't allow matrices as input ] issquare(1/x^2) --> SEGV [ typo in polcarrecomplet ] 28- rnfkummer(over Q) --> type error. 29- allow qfbprimeform(d > 0, p < 0) 30- Since exp(-1e100) --> 0. [ tolerable: alternative being underflow error ], we shouldn't have exp(-1e100) --> truncation error. Fixed. 31- rnfkummer(bnrinit(bnfinit(y),nextprime(10^20),1),Mat(3)) --> module too large in Fp_shanks [ conductor() was computing unnecessarily tough discrete logs ] 32- [Configure:] add /lib64 and /usr/lib64 to library search path 33- SEGV in nfeltpowmodpr() for primes of degree 1 [see 2.2.7-F21] + inputs containing t_INTMODs yield unpredictable [wrong] results 34- znlog(x,g): first check whether x == g [ quite frequent ] 35- rnfisnorminit(nfinit(y^2+y+1), x^3-y,2) --> "incompatible variables" 36- nffactormod() returned a factorization which was not a proper t_MAT 37- rnfequation(y^2+1, x + Mod(z*y - 1, y^2+1)) --> SEGV [ BIB ] 38- many problems in matfrobenius for _inexact_ matrices LGr39- very rare SEGV in idealprimedec() [ typo in init_norm(), using FpX_red on a t_INT, which is no longer valid ] 40- [library:] precision() output "wrong" value for small non-zero t_REAL (depended on exponent, not the bit accuracy of the input). Change so that true bit accuracy is used unless input is 0 (then use exponent). 41- rare memory corruption in thue() [ SmallSols ] 42- gamma(z) for tiny z suffered from catastrophic cancellation 43- ??? sometimes output extra entries [ e.g. ???eigen output matfrobenius ] 44- bezout(0., 0.) --> division by 0 45- issquare(5, &n) --> SEGV 46- factor(x in Q[i] \ Z[i]) --> rubbish [ typo in factor_gauss() ] 47- ellrootno & elllseries didn't check their arguments 48- rnfisnorminit(non-monic polynomial) --> SEGV 49- prevent Ser & Pol from creating invalid objects (e.g Pol(x+y, y) -> y+y) 50- TODO item: polrootspadic(x^2+8*x+4, 2, 2) --> 2 + O(2^2), whereas there's no padic root. The documentation is not clear enough: should polrootspadic(x,p,r) find roots in Z/p^r [current behaviour], or use the precision of the supplied polynomial to compute roots in Qp, then return them at precision p^r [ better, polroots() and factorpadic() behave this way ] ? 51- padicappr(f, t_POLMOD) didn't work 52- rnfidealnormabs(rnfinit(nfinit(y),x^2+1),1) --> SEGV 53- no argument check in primepi() 54- ellminimalmodel(ellinit([1,2,3,4,5])) --> gerepile error 55- gcd([]) was 1 [ should be 0 ] + gcd([...]) used an inefficient algorithm 56- [readline] completion in extended help context ?? didn't include GP defaults 57- [from 2.2.9] nfsubfields(x) had become unable to exploit the trivial case when x is irreducible modulo some prime 58- [from 2.2.9] typo in krosi -> wrong result [ affected aprcl only ] 59- dirdiv([],[]) -> SEGV 60- using allocatemem() in files input with read() could corrupt stack allocatemem() does not end by a longjmp anymore; it is still impossible to use it in loops 61- typo in matrixqz: matrixqz(Mat([1,1]~)/2,0) --> "not a rational matrix" 62- [cf 2.2.7-F23-] use safer parameters in bernfrac(): bernfrac(166) was wrong. 63- [Bug #201] gp --test: line split mode initialized too late print(vector(1000)) would bypass it. 64- [Bug #200] gmul2n(t_POL, n) would not normalize the resulting polynomial [ needed in characteristic 2 for instance ]. 65- FpX_center and centermod didn't use the same normalizations. Fix FpX_center 66- factormod(T,p,1): output was not sorted BA 67- [from 2.2.9] -fPIC missing for gp2c-run on platforms that require it. 68- if(1,print,print(no)) --> no was printed [a function expecting any number of string objects, called without parentheses (no args), would read the following arguments as its own ] 69- more stringent tests in ideal* functions: don't accept t_COL with incorrect length as ideals ([]~ produced SEGV in many cases) 70- factorback([1,1; 0,1],nfinit(x^3+2)) --> SEGV 71- [Bug #156] kbessel was unstably evaluated ? besselk(1,120) %1 = 448600744132608.0000000000000 72- hyperu and kbessel(,1) inaccurate. E.g: hyperu(1,1,1) at \p28 -> last 3 digits wrong Added 1- routines equalsi/equalis, equaliu/equalui, cmpui/cmpiu 2- exported FFTinit() / FFT() wrappers to rootpol.c:fft() [not under GP yet] 3- routines Rg_to_Fl, Rg_to_Fp, RgX_to_FpX, RgX_to_FpXQX, RgX_to_FqX, RgV_to_FpV, RgXQ_mul, RgXQ_sqr, RgX_div_by_X_x, FpX_div_by_X_x, RgXV_unscale 4- file Qfb.c [ stuff related to binary quad. forms moved out of arith1.c ] 5- routines truedivii, truedvmdis, truedivis BA 6- [GMP] faster divri routine. BA 7- support for real forms for qfbsolve. 8- routines RgX_gcd_simple, RgX_extgcd_simple [ when no coeff explosion in base field ] BA 9- new algorithm for exp(t_REAL) [ Newton ] 10- new macro ndec2prec() 11- use Trager's trick in factorff() 12- member function .bid (from a bnr). Extend mod, clgp, no, cyc, gen to bid and bnr structure. 13- new keywords for ?? : bid, CFT, ideal, idele, modulus, rnf. 14- new construction %#: number of history entries so far PC 15- an optional 2nd argument to znorder() to limit the search space Changed 1- renamed gegal --> gequal, gegalgs --> gequalgs, gegalsg --> gequalsg, egalii --> equalii 2- improve trial division in all basic arithmetic functions [ e.g try for(i=1,10^5, factor(1009)), or moebius, or ... ]. Old logic was broken for small inputs (tried far too many primes) 3- improve quadclassunit(D >> 1), about 10 times faster in the 40 digits range [forbid long reduction cycles (too costly to update arch. info when a relation is found + streamline factorquad() ]. See Z_lvalrem_stop() + remove extra_relations() and use large prime variation all the way [almost all relations are found this way] 4- streamline/clean-up polroots [ complete rewrite, much faster for small degrees ]. 5- improved zetakinit() [save some multiplications, about half of them for quadratic fields. Less so as the degree increases. ] 6- renamed RgX_RgX_compo -> RgX_RgXQ_compo 7- renamed binome -> binomial, chinois -> chinese [ added chinese1(x) for chinese(x, NULL) ] 8- add GC in integer valuation functions + use recursive algorithm when valuation looks large 9- no longer raise an exception when online help used on unknown id or obsolete function [report 'unknown identifier' or 'obsolete function'] 10- removed buggy support for narrow class group in quadclassunit + rewrite binary quadratic forms [ qfr3 / qfr5 ]. TODO: move from arith1.c to qfb.c 11- reinstate cornacchia + cornacchia2 with a different interface [ use cornacchia in qfbsolve ] 12- allow non-real arguments in incgamc, incgam MW 13- ellap: if E has CM by a principal order, use Cornacchia instead of Shanks/Mestre 14- more efficient algorithm for issquare(t_FRAC | t_RFRAC) 15- don't return t_INTMODs component in *modpr routines, but lifted representatives. 16- FpX_roots, FpX_factor: normalize input first + direct support for quadratic and linear polynomials [ no need to compute X^p !] 17- FpXQ_powers and similar routines: use multiplications when input has small degree, squarings otherwise. 18- matsnf over polynomial rings: make sure elementary divisors are monic 19- ellpointtoz() now returns z such that 0 <= Im(z) < Im(w2), 0 <= Re(z) < Re(w1). 20- bnfinit(non-monic t_POL) --> now discard variable change 21- rename apprgen9 -> padicappr, factmod9 -> factorff 22- rewrite padicappr() 23- [COMPAT] bnrdisclist has lost its 4th argument 'flag', and omitting the archimedean component now means that all 2^r1 possible values are substituted (formerly: indicate no ramification at infinity). The prototype of bnrdisclist0 has likewise changed. 24- renamed isprincipalrayall -> bnrisprincipal, rayclassno -> bnrclassno rayclassnolist -> bnrclassnolist 25- Change the output of ideallist with technical (flag 2,3) [ with units ]: instead of two vectors, output a vector of 2-component vectors. Change the input of all list routines (bnrclassnolist, bnrdisclist) accordingly. 26- %0 (undocumented) is no longer accepted as an alias for % 27- renamed realzero -> real_0, realun -> real_1, realmun -> real_m1. GN 28- MPQS rewrite [cleaner, faster] Removed 1- obsolete implementation incgam1 [ use incgam. As far as private functions go, incgam2 is better ] 2- removed ideallistarch0, ideallistarchgen, ideallistunitarch, ideallistunitarchgen. Just use ideallistarch. 3- obsolete default 'buffersize'. Flag -b is a no-op. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.9 (released 23/12/2004): Fixed 1- ploth(,256). splines had stopped working 2- gamma(-1.), psi(-1.) [ non-positive integers masquerading as t_REALs ]: wrong results (oo) or 'division by 0' error messages 3- log(1. + 1e-20) --> print more decimals than are significant 4- [Mac OS X + Fltk]: remove the BROKEN_FORK assertion --> graphic window becomes independant of gp as under other OSes. 5- elllseries did not accept complex arguments GN 6- [ix86 + Sun cc] build fails [ unsatisfied symbol reference to 'mulll' ] 7- [libpari] gprec_w didn't behave well for real zero 8- gp -p 51234567890 --> internal overflow and primelimit set to smaller integer 9- [ GMP kernel ] incorrect resmod2n --> wrong 2-adic sqrt 10- [hi-res plot: fltk] fix compilation with g++-3.4 BA 11- [hi-res plot: fltk] line plotting was broken 12- oo loops in prodinf [ e.g prodinf(x=2, zeta(x)) ] 13- [compatible=3] wrong prototype for isoncurve, lex, sign, thetanullk 14- quadhilbert(D > 0) spent an unreasonable time to find a relative equation defined over Q [ use Galois theory instead of naive search ] 15- typo in resmod2n [ missing (ulong) typecast ] -> issquare((2^64+1)^2)=0 BA 16- galoisinit() could fail to find a polynomial defining the fixed field. 17- elllseries had an apparent singularity at s = 2 [ loss of accuracy ] 18- gcoeff, gmael & their variants were not lvalues. 19- typo in element_val(t_FRAC) [ "non invertible" errors in rnfpseudobasis ] 20- added -fno-strict-aliasing to gcc flags [ PARI code doesn't follow strict aliasing rules. In any case, gcc 3.3 can't handle new mael ] 21- 1.a --> 1.0000 [ should be error ]. (x.a = x+1); 1.a --> 1.0000 [ should be 2 ] 22- bnrdisclist(bnfinit(x,2),1) --> SEGV GN 23- [Solaris cc] use safer optimization flag [ -xalias_level=any, fix a pb with 18 above ] Changed 1- increased maximum binary exponent for t_REAL, and maximum GEN length on 64 bit machines. Bumped BINARY_VERSION for writebin --> objects saved in writebin format between 2.2.1 and 2.2.8 are incompatible. 2- use easier to differentiate colors for hi-res plots [ replace "sienna" by "violetred" and "cornsilk" by "green" ] 3- GP interface of function intnum [ old flags not recognized, much more elaborate interface ] 4- library interface of functions intnum, prodeuler, suminf, sumalt, sumalt2, sumpos, sumpos2, prodinf, prodinf1 [ GEN (*eval)(GEN,void*) everywhere instead of entree * ] BA 5- allow Configure -l [ in addition to /pari.cfg ] 6- renamed gzero --> gen_0, gun --> gen_1, gdeux --> gen_2. 7- replaced kludgy matexp.c example by straightforward extgcd Added 1- new algorithm for log( t_COMPLEX ), log(2) [ AGM ] 2- new algorithm for Pi [ AGM ] 3- new algorithm for atan, acos, asin [ AGM ] HC 4- "double exponential method" for numerical integration and sumation. See ??intnum. New functions intcirc, intfouriercos, intfourierexp, intfouriersin, intfuncinit, intlaplaceinv, intmellininv, intmellininvshort, intnuminit, intnuminitgen, intnumromb, intnumstep, sumnum, sumnumalt, sumnuminit 5- new universal constant gen_m1 6- [bench suite] test-intnum and test-stark toplevel targets %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.8 (released 25/11/2004): Fixed 1- gp --version: stack overflow 2- overflow (in C long multiplication) in zeta(4.45+292532.0*I) 3- setrand(1); bnr = bnrinit(bnfinit(quadpoly(1020,y)), 31,1); rnfkummer(bnr, matdiagonal([5,1,1])); --> SEGV ( typo in FpXQX_from_Kronecker ) 4- make -j4 bench could start the bench before the binary was built 5- matkerint had stopped working [from 2.2.7] GN 6- [Solaris + cc:] fix linker warnings (missing object types in src/kernel/*.S) 7- listsort(List([]), 1) --> SEGV 8- setrand(1582268146); bnr=bnrinit(bnfinit(y^12+6*y^10+31*y^8+84*y^6+159*y^4+166*y^2+1),4,1); rnfkummer(bnr,[1,0,0,0,0,0;0,1,0,0,0,0;0,0,1,0,0,0;0,0,0,1,0,0;0,0,0,0,2,1;0,0,0,0,0,1]); --> bug in gadd [ typo in FqX_split ] Smaller test-case: setrand(1701015992) factorff(x^2+y+2, 3, y^3+y^2+2) MSo 9- bug in print_version() --> SEGV on startup if cc version number too long 10- subst(O(x),x,x+O(x^2)) --> SEGV [ substituting in 0 t_SER ] MSo11- various bugs in anal.c: uninitialized reads in get_op_fun(), double_op() memory possibly freed twice because ep->args was not reset to NULL after being freed 12- (10^100 + 0.) / (10^100 + 1.) --> 0. [ display bug from 2.2.6 ] 13- rnfnormgroup(): restrict to primes of degree 1 [ much faster ] 14- gamma(351/2) --> 1.235874058265488750143951998 E740 [ = gamma(351) ] 15- gammah was much slower than gamma [ contrary to docs ] 16- problems with 0 t_SERs: O(y^5)/(1+x) + O(x^3) --> O(x^3) O(y^5)/(1+x+O(x^3)) --> O(y^5) + O(y^5)*x + O(y^5)*x^2 + O(x^3) O(y) / (1+x) --> O(y) O(y) * 1/(1+x) --> O(y) subst(x+O(b),x,a) --> a 17- (0. * x) / x --> 0.E-28 * x 18- content(0.*x) --> 0 19- nfinit([x^2+1, y]) --> SEGV (bad input) 20- lngamma(10^50*I) returned many more digits than were significant 21- bnfinit(x^4-768*x^3+220032*x^2-27869184*x+1316749312) --> recent oo loop 22- elllseries(large t_REAL) --> 0 [ instead of ~ 1 ] 23- erfc(0) --> error [ instead of 1 ] 24- bnfinit(,1) could return without giving fundamental units (if the computation is unfeasible). Raise an error instead. IS 25- config/get_head would not work only if one invoked $PWD/Configure 26- obscure simplification bug: x;s;t;u; a = -9*u*x^3+3*u*s*x^2-3*u*s^2*x+u*s^3+u^4 b = 9*u*x^3+3*u*s*x^2+3*u*s^2*x+u*s^3+u^4 bezout(a,b) * (2*u^4*s^3+2*u^7) --> involves terms like u^5/u^2 27- matrixqz(matrix(2,1,i,j,i-1),-2) --> [;] instead of [0;1] 28- possible SEGV in bnrinit [ when ray class group is trivial ] 29- negative definite forms allowed by Qfb() while most qfb* routines can only cope with positive definite forms. Explicitly disallow negative definite forms. 30- \p 38 ellinit([1,0,0,-19959260,-34323045317]) -> precision too low in initell 31- {p = x^36 - 252*x^34 + 27504*x^32 - 1723392*x^30 + 69300198*x^28 - 1894026456*x^2 6 + 36355251492*x^24 - 499350803616*x^22 + 4953373719489*x^20 - 355510821425 40*x^18 + 183790369965636*x^16 - 677399199594048*x^14 + 1751507793357696*x^1 2 - 3105079104411648*x^10 + 3651333353058816*x^8 - 2698458969378816*x^6 + 11 30370773667840*x^4 - 207898980728832*x^2 + 2879456034816; nfroots(nfinit(subst(p,x,y)), p); } --> loop forever in lllintpartial() Fix: abort lllintpartial if progress negligible (was: if _no_ progress) 32- some permanent structs not freed in freeall() 33- [--with-gmp] round(-4294967296.1) --> '-0' [ typo in mpent ] 34- polredabs(x^4-x^3-31*x^2-12*x+144) was not reduced [ typo in subfield detection algorithm ] 35- nffactor(nfinit(a^2+1),x^2+[]) --> SEGV GH 36- lngamma was not even continuous : its argument was reduced mod 2Pi 37- contfrac(sqrt(2)/2,,2) --> trying to overwrite a universal object 38- nfroots(nfinit(a^2+a+1),x^2-a/4) --> [] (leading coeff not properly taken into account in nf_DDF_roots) 39- Y=Mod(y,y+1);Mod(Y*x,x-1)^2 --> bug in FpX_divrem, p == NULL 40- return type for nffactormod was not a factorization (had become t_VEC) 41- Pol(Ser(1+x)) != 1+x [ bitmask not cleared properly in gconvsp() ] 42- default(datadir,"...") --> SEGV [ attempt to free a static string ] 43- Configure was missing log2/exp2 on systems that had it 44- typo in base2.c:init_norm() [ wrong result in idealprimedec for huge fields ] 45- matsnf([x,1; 0,x],6) --> incorrect type 46- qfgaussred(a) did not work if coefficients of a did not support the "sign" operation [ signature was computed internally ] BA 47- bitneg(1,0) --> SEGV (caused by 2.2.5 A10). 48- factorback([;]) didn't work [ should be 1 ] 49- f = factor(n); divisors(f) destroyed the factorization stored in f 50- add missing GC in hess() 51- [Configure:] runpathprefix was computed only in terms of $osname (assuming standard vendor supplied linker). At least check whether it's GNU ld first. 52- misleading error message rtodber "overflow or underflow in R->dbl" (in fact, only overflow) 53- quadgen(-8) * 0. --> SEGV 54- I + O(2^10) --> error 55- ((x + quadgen(-8))*Mod(1, i))/(x^2+1) --> SEGV [ from randomgen ] 56- Mod(a^0,i^0) --> Mod(1,1) [ should be Mod(0,1) ] 57- factor(HUGE, 100000) --> "pointers lost in gerepile" in random GC in ifac_realloc() [ missing copy() for (*partial)[2] ] 58- incorrect gerepile() behaviour on t_LIST [ would try to update non-existing components if list not full ] BA 59- quoted strings were not displayed properly quoted. 60- bestappr(0.1, 8) --> 0 [ should be 1/8 ] 61- rare bugs in copying routines [ clone bit sometimes not unset ] 62- SEGV in qfminim when integer entries and precision error occured BA 63- galoisidentify() could fail on WSS group with S4 residue. 64- t_POLMOD + t_MAT was incorrect. E.g Mat(1) + Mod(1,x) --> Mod(Mat(1),x) instead of Mat(Mod(1,x)) as for other scalars. 65- Mod(1,8) + O(2^2) --> Mod(1,8) [ should be error ] 66- lngamma(1.) returned a t_REAL of length 'realprecision' (instead of 3) BA 67- matsnf(Mat([])) was returning a matrix instead of a vector. 68- ellap(ellinit([0,1,0,1,0]), 100) --> FPE [ BIB: 100 is not prime, but make the routine more robust ] 69- give meaningful error messages (with context) for 1<<(1<<32), 1<S" ] 70- memory possibly freed twice in pop_val_if_newer() [ race condition on interrupt () during new_val_cell() ] 71- ellap(ellinit([0,1,0,1,0]),100) --> SEGV [ 100 is not prime ! ] MS 72- recover from readline history corruption [ don't trust history_length in history_is_new() ] 73- obscure bug in thue() [ unit of norm -1 not found due to interface inconsistencies ] t = thueinit(x^6 - 2); thue(t, 2638) --> [] JD 74- [Configure:] detection of times() 75- Forbid t_POL + t_VEC: useless and inconsistent [ we had: 1 + [] --> error, x + [] --> OK but x * [] --> [] instead of '[]*x' , etc. ] 76- obscure bugs wrt polynomials with t_MAT coefficients created via Pol() [ e.g content(x*[;]) --> [;], primitive_part(x*[;]) --> [;] ] 77- incorrect behaviour in scalarpol()/scalarser() for exact 0 argument 78- typo in ellap: e defined over Fp didn't work any more 79- t_SER ^ t_QUAD --> SEGV 80- nffactor(non-monic t_POL) --> SEGV due to FpX_red interface change [ don't allow t_INT argument, t_POL is mandatory ] 81- ZX_incremental_CRT: wrong handling of degree increase (--> oo loop) 82- SEGV in Karatsuba multiplication for polynomials, when high product was 0 (over a ring which is not an integral domain!) 83- 1 / Mod((a^2-a)*x^2-1,Mod(2,6)*x^3+Mod(1,2)*x^2+1) --> SEGV 84- ellap(e defined over F2, 2) gave wrong results [ assumed e defined over Q and reduced relevant data modulo 8 ] 85- matcompanion(degree 0 polynomial) --> stack corruption 86- incorrect handling of inexact polynomials in matsnf(,2) [ inexact leading 0 coefficients ] 87- writebin(file, 0) saved a "corrupted" object (0 couldn't be read back) 88- wrong prototype used in rnfdet() [ accepted 3 arguments instead of 2 ] 89- typo in to_Kronecker [ when at least 3 variables involved ] 90- typo in x = sqrt(t_PADIC) [ returned either x or -x ] 91- rare stack corruption in RgX_mul(t_POL, t_POL) [ when product of leading coefficient cancel, valuation is non-zero _and_ we use an "unsafe" gerepile right afterwards ] 92- component(Ser(x),2^31-1) --> SEGV 93- typos in krosi(), kronecker() [ e.g krosi(-4,1), kronecker(0,2^32+1) ] 94- agm(-1,2) --> oo loop 95- tanh(10^10) --> exponent overflow [ should be 1 ! ] 96- gamma(exp(-373)) --> exponent overflow 97- readline: assume a file 'foo' exists, \rf --> \foo [ r deleted! ] [\r f was OK]. Solution: just expand to '\r f'; hitting again completes properly --> \r foo. BA 98- Reduce stack consumption in ffinit and polsubcyclo. 99- (p/q)' wasn't simplified if q wasn't squarefree 100- polylog(n, x < 0) had a (small) non-zero imaginary part 101- 3 + O((-1)) --> oo loop 102- creating t_PADIC/t_SERs via x + O(...) eventually blew up the heap 103- fix memory leaks related to GP pointers and clones Changed 1- lgef / setlgef / evallgef removed. One may safely use lg for t_POLs. As a result maximal degree jumps to ~ 2^24 on 32bit machines 2- renamed *res(te) routines to *rem(ainder). Eg poldivres --> poldivrem, nfdivres --> nfdivrem BA 3- Internal u_Fp* routines now are renamed Fl* and made public. BA 4- [GMP kernel] Library soname changed to libpari-gmp[-2.2].so.N. BA 5- Library .so link changed to libpari.so for all versions. Static library changed to libpari.a for all versions. 6- COMPAT: ellheight now uses the standard normalization: twice the value it used to return. The values returned by ellbil() and ellheightmatrix are unaffected. In particular, ellheightmatrix() is the polar form of elleight(), and ellbil now satisfies the proper identity for B(P, Q) = (h(P+Q)-h(P)-h(Q)) / 2 7- renamed and declared gmul_mat_smallvec --> RM_zc_mul gmul_mati_smallvec--> ZM_zc_mul 8- move functions in highlvl.c to libpari, excluding install(). 9- bnfinit: use approximate integral LLL reduction (much faster than fp) 10- bnfinit: cache multiplication table by prime ideal anti-uniformizers (faster valuations) BA 11- improve binomial (use divide_conquer_prod) 12- improve bnrinit & idealstart when finite part of conductor is 1 (+ improve stability) 13- subgrouplist(bnr,...) does not require bnr to contain generators anymore ( bnrinit(,,1) ). Also much faster. 14- allow zetakinit() to use a bnf argument [ would be recomputed before, making it impossible to certify the result since bnfcertify could not be applied ] BA 15- error messages now mention the GP function when the error occured. 16- intro message [ no point in displaying "realprecision", "seriesprecision" and "format" on startup. One can query them individually, or ask for all defaults ] BA 17- macro varncmp(vx,vy) should now be used to compare variable numbers. BA 18- split substpol from subst ( reverse [ 2.2.1 C24 ] ). Use substpol for non-trivial algebraic substitution. 19- remove t_FRACN / t_RFRACN from \t output, add t_VECSMALL BA 20- bittest() now handle negative operand as 2-adic. BA 21- type() does not allow to change object types anymore. 22- internal routines setloop()/incloop() allocated 2 chunks of memory, then assumed they were connected [ true for the current allocation model ]. Remove that unecessary assumption. 23- more informative error messages in concat() 24- in affsi / affui (s, z) : do not check that lg(z) >= 3 25- replace gexpo(t_QUAD) by a rough aproximation (as t_COMPLEX): faster 26- made Mat(t_VEC of w t_COLs of the same length h) return a h x w matrix Used to be a 1 x w matrix whose elements were t_COLs. Obsoletes such hacks as: v = vector(...); v[1] = Mat(v[1]); concat(v). Now Mat(v) is enough. 27- move BEGINEXTERN / ENDEXTERN pairs out of kernel headers into pari.h 28- split the User's manual in two: PARI/GP and libpari. 29- updated and completed the tutorial 30- faster basic transcendental functions on small inputs (sqrt, log, exp) 31- rewrote basic generic kernel (add,mul,div) [ faster, less obfuscated ] 32- macroified gop1z, gop2z, gops2gsz, gops2sgz, gops2ssz 33- diviiz(x,y,z), divisz, divsiz and divssz always assign the euclidean quotient [ used to depend on the type of z: if t_REAL computed exact quotient ]. Use rdivii, rdivis, rdivsi, rdivss for analogous functionality (no "z" variant); 34- ensure proper rounding in divrs 35- renamed padiczero --> zeropadic [ as in zero[pol|ser|vec|col|mat] ] 36- macroified gcosz, gsinz, gexpz, etc + cleanup transcendental functions 37- macroified mulssz, addssz 38- rename mpent --> mpfloor 39- rename divise --> dvdii, gdivise --> gdvd, mpdivis --> dvdiiz, mpdivisis --> dvdisz 40- rename mpppcm --> lcmii, remove mppgcd [ use gcdii ] 41- rename resss --> remss, ressi --> remsi, resis --> remis, resii --> remii, gres --> grem 42- rename krogs --> krois, krosg --> krosi 43- rename FpXQX_FpXQ_mul -> FqX_Fq_mul, FpXQX_normalize -> FqX_normalize 44- rename adduumod, subuumod, muluumod, divuumod --> Fl_[add,sub,mul,div] invumod --> Fl_inv, invsmod --> Fl_inv_signed, powuumod --> Fl_pow powiumod --> Fp_powu, mpsqrtmod --> Fp_sqrt, mpsqrtnmod --> Fp_sqrtn 45- rename mpsqrt --> sqrtr, mpsqrtn --> sqrtnr 46- don't copy arguments of user functions for types which have no modifiable components (anything but VEC, COL, MAT, LIST, VECSMALL): much faster. 47- ':' no longer allowed as a substitute for ';' if compatible = 0. Use GP2C semantics [ x:int, v:vec ]. For the time being the type information is discarded. 48- modulargcd() was very inefficient for non-monic t_POLs [ e.g (poltchebi(x) - 1) / (x-1) ] JD 49- [timer: ] use sysconf(_SC_CLK_TCK) instead of CLK_TCK if available, and make sure one of these is available before choosing times() in Configure JD 50- check for 'exuberant-ctags' before 'ctags' in make_vi_tags [ and fail gracefully if neither is found ] BA 51- support for gp2c-run on Darwin 52- remove blanks in "raw" outputs ( default(output,0) ) 53- made .fu and .tu return t_POLMOD, not t_POL BA 54- [GMP kernel] use mpn_sqrtrem for sqrtr_abs 55- nfsubfields (use much less memory) GH 56- more robust thue(): faster enumeration of small solution, don't assume that the full unit group is known, warn when conditional result is obtained. 57- remove log() flag: decide alone whether to use AGM or not. Rewrote logagm and mpexp1 58- make ??? index search ignore case [ ???bernoulli will find Bernoulli ] 59- renamed svaluation --> u_lvalrem, pvaluation --> Z_pvalrem 60- change semantics of sqrtn to catch easily non-residues from the user's side 61- rewrote the 'tune' utility, add one tune.h file for each kernel, support for user override still needs to be rethought (or documented). Added 1- make test-all [ all available test suites (SLOW !)] BA 2- add support for GNU/Hurd. 3- conversion routines zv_to_ZC, zv_to_ZV, zm_to_ZM, and matrix multiplication: RgM_zm_mul, ZM_zm_mul. 4- output support for zm / Flm matrices (t_MAT with t_VECSMALLs instead of t_COLs) 5- FpM_rank 6- allow factor( an elt in Z[i] ) 7- put back bruteall [ used by Math::Pari ] BA 8- Configure support for sparc64, x86_64 and ppc64 BA 9- x86_64 level0 inline assembly kernel BA 10- add POSIX-style long options --fast, --quiet, --primelimit and --stacksize. 11- new internal library routine itos_or_0 12- new member function .index 13- rdivii, rdivis, rdivsi, rdivss to replace diviiz & co. 14- new routine mpround, mpfloor, mpceil, mptrunc, roundr, floorr, ceilr, truncr BA 15- galoisisabelian, galoisexport, galoisidentify and galoissubgroups now also accept subgroups returned by galoissubgroups. 16- new routine Fl_sqrt 17- new routines FpX_factor, FqX_factor, FpX_degfact, FqX_red 18- private header file pari-priv.h 19- new function ispower 20- forvec iterator GH 21- new function zncoppersmith 22- public interface to forvec() [ forvec_start + forvec_data, for GP2C ] 23- routine sqrtremi() [ Karatsuba square root ] 24- internal routine int2n() [ = 2^n ] 25- new functions Z_pval, Z_lval, u_lval 26- new function primepi BA 27- new default factor_add_primes BA 28- HPPA 32bit and 64bit level0 inline assembly kernel Removed 1- obsolete macro leadingcoeff [kept for backward compatibility but removed from the documentation]. Use leading_term. 2- obsolete undocumented type t_SMALL BA 3- revert 2.2.1 A14 and A17 (broken with GMP kernel, unmaintainable). BA 4- cornacchia, in favour of qfbsolve. 5- useless inefficient types FRACN / RFRACN 6- routines gred [useless] / gredz [ useless did not work ]. Define gred --> gcopy for backward compatibility 7- many obsolete error codes [ for err(...) ] 8- smodsi() [ useless, not well defined ] 9- buggy macros mppiz, mpeulerz [ undocumented, useless, broke compilation to use them ] 10- inconsistently named macros mpinv[sir]r [ were "z" functions ]. 11- public macros refering to static transcendental routines (e.g mpatanz) 12- undocumented, inconsistently named, useless, mulsii, addsii, divisii 13- useless routine umuluu [ use mulll ] 14- undocumented [macro] constants pariC1, pariC2, pariC3, pariK, pariK2, pariK4 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.7 (released 18/12/2003): Fixed 1- bench input files: should all start by a 'gettime()' instruction 2- bnfisnorm(bnfinit(x^2-11),1) --> [Mod(1, #), 1] [ return a result involving MAXVARN on trivial input ] 3- [Mat(5)] * [[0]~]~ --> 0. Should be [0]~ [introduced in 2.2.6-C.25] 4- \p 1000 E=ellinit([1,0,1,-120039822036992245303534619191166796374,5042249924849106700108 01799168082726759443756222911415116]); x1=1e100; y1=ellordinate(E,x1)[1]; ellpointtoz(E,[x1,y1]); --> impossible addition t_VEC + t_VEC. [ precision error ] 5- erfc(non scalar) --> type error 6- raising to t_FRAC power didn't work with p-adics: (-1+O(5))^(1/2) --> 1 7- [ isprime / APRCL: ] integer overflow, e.g isprime(2^32 + 1, 2) 8- sum(i=2^32-10,2^32+10,1) --> 11 [ kind of overflow ] + didn't use the t_INT interface ==> broken with GMP kernel 9- polgalois(x^6-3*x^4+3) --> [24, -1, 1], should be [24, -1, 2]. From 2.2.4 10- nfisincl(x, x^2+1/2) --> SEGV [ assumed integral inputs ] 11- numbpart(10^15+2) --> SEGV [ check for x < 10^15 incorrect ] 12- polcompositum(x,x) --> SEGV [ problem with poldeflate(deg 0 pol) ] 13- zeta((1+I)/2^225) --> 7e28 [ precision error when using func. eq. ] 14- typos in qfsign/qfgaussred() [ aka sqred2 ]: wrong results: e.g qfsign([0, -1, 1, 1; -1, 0, 0, 1; 1, 0, 0, -1; 1, 1, -1, 0]) --> [2,2] ( should be [2,1] ) 15- numbpart(0) --> 0 [ should be 1 ] GN 16- assembler section of Sparc Makefiles relied on GNU make specific $< MSo17- off-by-1 error in Vec( t_STR ) [ memory corruption ] 18- off-by-1 error in itostr(), e.g 10^11 [ memory corruption ] BA 19- [hi-res plot: X-Windows] rescaling bug MSo20- bittest(1,32) --> 1 [ off-by-1 error ] 21- nfeltpowmodpr(nf,x, prime of degree 1) --> SEGV [ FpXQ_pow couldn't handle computation in prime fields ] 22- charpoly( Mod(mat, poly) ) --> SEGV [ out of stack components not treated properly ] 23- memory corruption when parsing floating point constants [ constante() ] 24- too little GC in serreverse() 25- bnfinit(huge field) --> "precision loss in truncation" [ missing term sqrt(disc(K)) in norm bound ] 26- allow conj(t_POLMOD) provided the modulus degree is <= 2. MSo27- ?0 with _many_ user functions defined --> SEGV [ typo in commands() ] 28- quadclassunit(5) --> PLEASE REPORT [ can't build subfactorbase, introduced in 2.2.6 ] 29- valuation(x^3, x^2) --> 3 [ valuation at a monomial assumed it had degree 1, introduced in 2.2.2 ] 30- Set(matid(2)) --> [ "[1, 0;\n0, 1]" ]. Ensure "raw" format is used, not "prettymat". 31- typo in rnfpolred(bnf, *). E.g rnfpolred(nfinit(polcyclo(3,a)),x^3-19) --> oo loop [ non-positive T_2 form ] 32- typo in ellap: rare wrong result. E.g E=ellinit([0,0,1,-5115523309,-140826120488927]); ellap(E, 1315717181) BA 33- qfbprimeform(-3, 1) --> data corruption [ gzero's signe set to 1 ] 34- qfbpowraw(x, n < 0) reduced its output 35- stack corruption when adding huge p-adics 36- idealintersect did not allow fractional ideals 37- Ser([1,2]) --> 1 + 2*x + O(x^2) [ OK ], but Ser([0,0]) --> O(x^16) 38- writebin() still produced incompatible output depending on the multiprecision kernel. 39- [alg | lin]dep( t_PADIC ) had stopped working in 2.2.6 40- some precision problems in polgalois(deg(p) > 7) [ changed slightly some heuristic settings: the algorithm is simply not rigorous... ] 41- typo in polredabs: polynomial of minimal T_2 norm might be missed [ actually found, then deleted due to a typo when "Sorting" small vectors, which would assess them the norm of a larger element ] 42- polredabs(,4): some polynomials of minimal norm could be eliminated due to fixed buffer size for the small vectors. Made that dynamic. 43- in certain situations (when using Allombert's algo.), subfields did not output subfields sorted by degree 44- [Windows installer:] online help did not work on most installations 45- lines continuation with \ did not work with DOS fileformat BG 46- random(2^31) returned integers in [0, 2^32-1] [ long/ulong problem ] 47- isprime(156499227435744375600531968861048687296374896432841731) --> SEGV [ missing case in aprcl:sqrmod5() ] BA 48- Configure: using gcc-3.3 + LANG=french, Configure failed to detect gcc [ messages translated ] 49- alpha kernel would not compile with a C++ compiler (missing extern "C") 50- rare stack corruption in gmul(t_COMPLEX, t_COMPLEX) [ when result is real ] 51- valuation(Mod(x,x^2), y) --> oo loop [ now 0 ] 52- optimization problems in new zeta() and gamma() [2.2.0 C13] ( e.g zeta(0.5 + 10000*I) was _much_ slower than before ) 53- precision problem in nffactor [ in get_R() ], could yield to a SEGV, e.g nffactor(nfinit(y^4+7^2),x^28-14*x^24+20321*x^20+166992*x^16+1171296*x^12+1342208*x^8-5005056*x^4+3211264); 54- contfrac(Pi/2,2) --> [1, 1] (doc says a_n != 1, so should be [2]) 55- factorint( 3280696195200006885547973357173182411881462602934802054749349683516314460050 2548596646024265171468102088952756084355402608216473040677346490348936595334 0299389230010814564530645152250241760175805765084544728012391149823776145022 4913178048870032606672750626773595019035786804361581343222144074318522768947 2061349830773562073895748494534362180537529975336881525935996152181576667869 0625865166662910961888106910345518707973056625912728422391238723575276042635 9727112469435556047168454738353621102783718736137552743946577993495054202848 9372915917197045423574773583244796785665263319216397122018435444897 ,11) --> impossible assignment I-->S [ stack corruption ]. 56- typo in kummer.c:invimsubgroup [ hnfmod --> hnfmodid ]. Very rare weird error message in rnfkummer(): "wrong subgroup in conductor". 57- typo in alglin2.c:hnfspec() [ same loop index used twice ] 58- zeta(x) very slow for large integer |x| (use new bernfrac() code) 59- removed -mimpure-text from DLLDFLAGS on non-sparc architecture XR 60- Configure/bench: use head -n # instead of head -# (deprecated and unsupported by GNU coreutils) 61- not enough GC in mpbern() [ Bernoulli numbers ] and psi() 62- \p50000, then polroots(x) --> exponent overflow 63- ellj( t_QUAD ) / eta( t_QUAD ) was forbidden. 64- polredabs(x,1) did not work when x was already reduced 65- polroots(x^3 + 0e-20) --> oo loop [ didn't handle nicely non-exact 0 as a constant coeff ] 66- 'make doc' always rebuilt the documentation, even if it was up to date Changed 1- bnfinit: [small_norm phase] speed up norm computations. 2- [make etags:] use $ETAGS instead of 'etags' if defined 3- [libpari:] renamed incgam4 --> incgam0, incgam3 --> incgamc BA 4- [Description system] Store GP functions in a database in src/functions/ instead of hard-coding them in C files. 5- [libpari:] modified zbrent interface to allow library programming 6- ellpointtoz(E, P): remove the test that P be on E [ useless and often wrong when P has inexact entries] 7- allow serconvol() with 0 series. MSo 8- allow numtoperm(0,k) [ --> [] ] 9- simplify result of basic op. involving complex numbers, e.g. I*I --> -1 as t_INT (was t_COMPLEX) 10- embedings of number fields: use x + iy --> (x + y, x - y) instead of (sqrt(2)x, sqrt(2)y) to map complex embeddings to R^2. 11- disallow Ser( t_MAT ) [ resulted in a series with t_COL coefficients ] 12- nf format to improve idealinv() [ nf[5][6] and nf[5][7] ] 13- disallow sqrtint( x < 0 ) 14- meaning of the GP_DATA_DIR global variable: now points to the directory _containing_ galdata, not to the galdata files 15- qfminim(,,2) + polredabs: look for points by (roughly) increasing norms (was: full enumeration and roughly decreasing norms) 16- exp(-10^10) --> 0.E2525223 [ was 'underflow' ] 17- polredabs: improve the search for subfields (no polynomial factorization required now, only linear algebra) 18- ellglobalred(): use gcd(e.c4, e.c6) to help factor e.disc 19- removed obsolete components ("checks", "bits of accuracy left in computation") from quadclassunit / bnfinit / bnfisprincipal / bnrisprincipal / bnfunit outputs. 20- 'make test-graphic' is gone. Use 'make test-ploth' HC 21- new implementation of gamma() 22- renamed Oxxx/dft.Config.in --> pari.cfg 23- new implementation of bernfrac() [ use zeta(2k), initial GP code by HC] 24- bernvec always calls bernfrac() [ hence has become useless ] 25- [sparcv8_super kernel:] replace asm divll with portable one (slightly slower but fixes many compilation problems, and easier to maintain on an architecture which has become hard to test) 26- buchall() [ bnfinit, etc ]: complete rewrite to avoid restarting from scratch after a precision increase. All relations stored in algebraic form, so that data is easily recomputed to higher accuracy if necessary. Use lower default precision. 27- remove special handling of t_STR by printtex / writetex [ 2-2-6-C19: a \ would be inserted in front of $, %, etc. ]. This broke things like printtex("$", x, "$"), and is better done by the user herself. 28- bnfinit(): remove useless components from the "technical parameter". Added 1- [Configure:] flag --with-ncurses-lib=* BA 2- support for FLTK graphical library [ hi-res plot ] BA 3- galoisidentify for order 96 to 127. 4- default 'datadir' [ to allow relocating 'galdata' for polgalois ] 5- hi-res plotting under Windows GTo 6- routine qfrep() BA 7- routine qfbsolve(Q,p) for Q imaginary and p prime 8- new testsuite: make test-galois (~ 1 minute) 9- new options to Configure: --with-fltk, --emacsdir, --datadir, --sysdatadir SG 10- updated micro-kernel for HPPA BA 11- Add code 'i' for functions returning C int (not long) Removed 1- bruteall [ useless, undocumented variant of 'brute' ] 2- option to Configure: --miscdir %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.6 (released 19/06/2003): Fixed 1- rnfidealtwoelt, rnfidealmult --> SEGV 2- agm(x+1, x+2) --> oo loop [2.2.5 F-61 was undone...] 3- setrand(1); elltors(ellinit(vector(5,k,random/random))) --> SEGV [ incorrect use of partial factorization in ellintegralmodel --> surviving denominator ] 4- old typo in cauchy_bound --> factor((x - 155)*(x^2 + 160*x + 12864)) returned a single irreducible factor [ missing factor 2: initial upper bound for roots was 125 instead of 250 ] 5- zeta(x) very slow near large negative integers 6- algdep(2^46,1) ---> 1 [from 2.2.5] 7- bnrclassnolist(bnfinit(y),[2,2]) --> SEGV IS 8- typo in paricom.h [extra , in enum] --> compilation failure IS 9- typo in part.c [ // comments ] --> compilation failure 10- y/(x/y) --> error [ wrong assumption that y is a genuine GEN in mulscalrfrac ] 11- example/Makefile wasn't up to date [ link with -lpari ] 12- zetak(zetakinit(y), 3-1e-28) --> -7.2e28 [ catastrophic precision loss triggered by anything non-integral but very close to an integer ] IS 13- gp-dyn build on AIX 14- subst(y*x,y^2,x) --> 0 15- rnfisnorminit(x,x^3-2) --> SEGV [ bad input. Missing argument checks ] 16- Compiling with g++ + gmp, missing gmp version number [missing stdio.h] IS 17- [AIX:] various compilation problems + select better CFLAGS (-qtune=auto -qmaxmem=8192) IS 18- [HPUX:] remove -E from DLCFLAGS 19- bnrconductor(bnfinit(x)) --> SEGV [ missing check ] 20- ellpow(E,...,-1) --> stack error [ from 2.2.5 ] 21- a:b:c; c/a/b == c/b/a --> 0 22- sparcv8 inline assembler kernel used global registers for hiremainder / overflow, which was dangerous, inefficient, and complicated. Now none of the inline kernels use any global variable. The non-inline assembler kernels do define and access globals hiremainder and overflow. BA 23- cos(2^2^22) --> precision too low [ idem sin, tan ] 24- setrand(1504969109; quadclassunit(-403195) --> incorrect. Check against L-value too liberal; now allow quotient in [ 0.8, 1.3 ], not [0.75,1.5] 25- TODO item: quadclassunit not reliable when fed non fundamental discriminant (oo loop [e.g quadclassunit(-352)], wrong result). [ fix: increase factor base ] 26- sign of elleisnum(E, 6, 1) was wrong BA 27- [GMP kernel] factor(18295370635792208009) --> error 28- idealprimedec(nfinit(x^16+16),256) --> SEGV [ bad input ] 29- setrand(1642014180);quadclassunit(1642014180) --> PLEASE REPORT [ bug in large prime relation code ] 30- TODO item: rnfpolred(nfinit(quadpoly(904,y)),quadray(904,1)) *** division by zero in gdiv, gdivgs or ginv BA 31- uninitialized memory read in divrr(x,y), when lg(y) < lg(x), leading to random rounding of result. 32- [Cygwin + bash >= 2.05a]: HOSTTYPE no longer auto-exported by bash --> Cygwin compilation broken. Define it to i386 by default. 33- TODO items related to polgalois + polgalois(x^8-1864259299553450972214799899167226732549697977945716*x^6+331143259018657601105207922631212331088735421305543663274125986698777318014979969*x^4-2225286541902342283500014249183311190477390*x^2+5); --> degree too large + setrand(7); polgalois(x^8+162644002617632464507038884216211529274267271168000002) --> wrong result + polgalois(x^11 - 2) took a looong time. 34- systematic warning in bnfisnorm() [ "useless flag" ] 35- charpoly could not handle t_POL in variable MAXVARN 36- \p400 + sin(2*Pi) boasted far too many significant digits 37- [Configure:] --with-readline=path did not work 38- [Configure:] $TOP/readline was added to search path for ncurses, termcap, etc 39- memory leak: x = vector(2); y = vectorv(2); while(1, m = matrix(2,2); m[2, ] = x; m[, 2] = y) --> out of memory 40- factor(12345)[,1][3] --> error 41- overflow in some GP interface routines: e.g default(realprecision,10^125) 42- polhensellift((x^2+1)*Mod(1,5),...) --> SEGV [ bad input ] 43- lindep([x,y]) --> SEGV [ bad input ] 44- polredabs(x^4+9670527181567158504671*x^2+4840282594390812607599424249,16); --> impossible concatenation in concat [ from 2.2.5 ] 45- [Cygwin compilation:] incorrect cygtop [ --> readline not found ] 46- [Cygwin:] DLL build. libpari.dll and gp-dyn build OK. Install does not work in gp-sta (SEGV) 47- rare SEGV in Round 4 when using non-primes in addprimes() 48- overflow when computing Euler's constant to 20000+ decimal digits MSo49- error message for unrecognized GP metacommand: off-by-1 error GN 50- Configure breaks if CFLAGS contains '/' (invoke sed with '!' separator) IZ 51- [tex2mail:] line couldn't start with {...\over...} (required indent) IZ 52- [tex2mail:] \over wasn't allowed within \left( \right) 53- ZX_QX_resultant (modular resultant with integer result): possible oo loop when the result is 0, and non trivial denominator. 54- elleta(E.omega) gave incorrect results [ conflicting normalizations ] 55- typo in charpoly(t_MAT) [ stack overflow after garbage collection ] 56- subst(y,x+y-x,y) --> 0 [ missing simplification ] 57- typo in nfroots [ returned inverse of roots when polynomial had small degree (using Trager's method) ] 58- 'path' default incorrectly set on Cygwin 59- [internal:] isprincipalfact() incorrect if flag contained nf_GEN_IF_PRINCIPAL (was unused). 60- bnfisintnorm(bnfinit(y^4+y+1), -1) --> SEGV [ could occur for any unit ] 61- stack corruption in matsnf() [ when GC occurs ] 62- vecsort(t_VECSMALL) --> SEGV 63- v = vector(2); j = 0; v[j++] = 1 --> j = 2 [ side effect of 2.2.4-F21: LHS for matrix assignment was evaluated twice ] Rem: v = vector(2); v[j++] = v = 0 --> SEGV. Don't cry. BA 64- [ix86 + gcc compilation]: fix "invalid preprocessing token" Warning BA 65- galoisinit could very rarely trigger a 'impossible inverse modulo' error. Changed 1- rnf structure (removed useless components) 2- rnfidealreltoabs, rnfidealup: now return a Z-basis as a vector of elements in the relative extension, instead of a meaningless HNF matrix wrt an unknown basis. Was especially dangerous if the extension also existed in nfinit form, since the HNF matrices were _not_ ideals wrt this nf structure. [ also consistent with rnfeltreltoabs ] 3- rnfidealabstorel now requires input in the above form, so use rnfidealabstorel(rnf, nf.zk * A), if A is a standard ideal in HNF form. Used to require matrices in HNF form, which was confusing since ideals such as A gave wrong results [ HNF wrt different implicit bases ]. 4- idealadd(x,y): multiply by lcm(denom(x), denom(y)), not their product 5- rewrote nfhnf/nfhnfmod/nfbezout [ many small improvements ] 6- rnf structure now filled incrementally [ absolute nf, data for norm computations ]. Use build_and_check_obj() mechanism already used for bnf: cycgen ( bnf.gen[i]^bnf.cyc[i] ) + matal (relations in algebraic form) 7- rewrote rnfpseudobasis, rnfordmax [+ new routine rnfallbase ] 8- always define checkmemory() in libpari [ was included only if MEMSTEP was defined ]. Could cause compilation failure when compiling with different flags. 9- upgrade pariemacs, see pariemacs.txt 10- faster divll for portable kernel [ inspired by GMP ] 11- allow system() under Windows (95 and higher) 12- use cmprr() in gegal(t_REAL, t_REAL) 13- have Configure check explicitly that the C compiler is ANSI 14- faster modular algorithm for characteristic polynomial of algebraic integers Mod(x, y) [ ZX_caract(): old would replace x by its integral part and correct at the end; new is fully modular ] 15- separated mpadd functions from [none|gmp]/mp.c --> kernel/add.c 16- use 'lgeflist' for t_LIST: remove the 65536 limit on list size 17- subst(1 + x^2 + O(x^5), x^2, y) --> 1 + y + O(y^2) 18- nffactor: allow modular factorization over primes of degree > 1 IZ 19- try to output usable TeX (avoid braces, let TeX split lines) 20- [libpari internals:] jmp_buf 'environnement' no longer global MSo21- allow poltchebi(n < 0) [ := poltchebi(-n), still satisfies the 3-term recursion ] IZ 22- prime sieve optimization [ primelimit ] 23- try to reduce the likelihood of an artefact relation in PSLQ [ use "confidence level" 2^(-20) ] IZ 24- [tex2mail:] add a "cut here" sign when expression does not fit in the linelength: \o3 \p240 [Pi, Pi]~ 25- faster multiplication [t_VEC | t_MAT] * t_COL for sparse t_COL [ induces faster charpoly for sparse t_MAT ] 26- matsnf: allow rectangular matrices + improvements for singular matrices 27- made startup errors ( GPRC ) non fatal. 28- allow vecsort(t_VECSMALL) 29- renamed mulssmod/divssmod --> muluumod/divuumod and changed their prototype (use ulong arguments, return ulong) [ was already the case, with various casts ] 30- renamed u_invmod --> invumod. Documented all level0 modular routines. [ also added invsmod ] 31- separated "negative or zero argument" (arither2) and "zero argument" (arither3) errors. Added 1- member function rnf.pol (polynomial generating absolute extension) 2- src/kernel/sparcv8_[micro|super] 3- in emacs/ : pari-completion.el pari-conf.el.in pari-fontification.el pari-help.el pari-messages.el sli-tools.el 4- Configure --builddir : find a decent name for build directory depending on kernel options (with/without gmp, exotic assembler kernel) GH 5- PowerPC level0 inline assembly kernel 6- support for install() on Mac OS X BA 7- GP function galoisexport IZ 8- logstyle and TeXstyle defaults 9- [GP defaults:] support 'G' suffix (for Giga) (already supported k and M) 10- extend GP command line: once flags (-xxx) are processed, remaining args are taken to be filenames, read upon startup [ _after_ the gprc read statements have been processed ] GH 11- IA64 level0 inline assembly kernel BA 12- GP function galoisidentify and groups identification facility 13- public function GENtoGENstr [ for GP2C ]. (was private: gtostr()) 14- function coefs_to_vec() NS 15- support for Qt graphical library [ hi-res plot ] Remove 1- remove emacs/compile [ integrated in Makefile ] 2- src/kernel/sparcv[89] 3- config/MANIFEST [ now built dynamically ] 4- config/Makefile.DLLs [ use recent libtool instead of dirty hacks ] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.5 (released 11/02/2003): Fixed 1- [bnfinit:] typo in be_honest() --> SEGV when cbach2 > cbach [from 2.2.4] 2- apprpadic() when p = 2 (could not work) + typos 3- typo in gphelp [detex mode]: ubiquitous "var" in translation [from 2.2.4] 4- typo in var_make_safe() [ protecting user variables after trapped "stack overflow" ] --> possible SEGV [from 2.2.4] BA 5- [Configure:] add -lm -lc to EXTRADLLDFLAGS, not DLLDFLAGS 6- typo in gp_main_loop: avma not restored properly after allocatemem. [from 2.2.4] 7- typo in [imag|real]_be_honest: SEGV in quadclassunit(D,,[c,c2]), c2 > c [from 2.2.4] 8- typo in rnfisnorminit (pol_up) 9- at \p28: x = (1. + 10^-28) - 1; for (j=1, 100, x = (x-10^-28) + 10^-28) now x has 200 words of precision 10- stack corruption in addition (t_INT + t_PADIC) 11- factorpadic(z+y,2,4) --> SEGV 12- wrong result in idealchinese when the y_i had denominator BA 13- sigma(n,-1) output a wrong result. BA 14- inline alpha assembler broken (registers clobbered) GH 15- polsturm(1, 0, 1) ---> error [ return 0! ] 16- "break loop" did not react correctly to allocatemem() read from a file with \r (stopped reading file right away) 17- matker(x, 1): internal loop forgot a pointer when garbage collecting --> SEGV (or weird error, e.g division by 0) 18- ideallog(nfinit(y),2,idealstar(nfinit(y),4,1)) --> SEGV [bad input] 19- ellrootno(ellinit([0,-25,0,-1250,0])) --> SEGV [from 2.2.3] 20- typo in elllocalred (wrong Tamagawa number, case I0). [from 2.2.4] 21- idealtwoelt(nfinit(y),2/3,1) --> SEGV [bad input] 22- for transcendental function f and polynomial p, f(p) only gave seriesprecision significant terms when val(p) = 0 23- Ser(a/b) --> 1 + O(x^16) (!!) 24- (x^2)^(1/2) --> error 25- idealnorm(nfinit(y),matdiagonal([1+I])) --> SEGV [bad input] 26- polylog(10,x^10) --> O(x^6) at \ps16 [ 16 significant terms ?] --> x^10 + O(x^21) at \ps 21 [missing x^20 term] 27- nffactor/nfroots: SEGV over Q 28- missing sanity checks in install() [ did not check the parser code ] 29- typo in nilord() [lg-->lgefint]: nfdisc() didn't work on 64bit HP 30- ellisoncurve(ellinit([0,0,0,0,1]),[1/2-sqrt(3)/2*I,0]) --> 0 31- type 'gphelp' from command line: carriage return is missing 32- typo in LLL_cmbf() [ rare oo loop in factor() over Z[X] ] IS 33- [HPUX:] should compile with cc -Ae, not -Aa 34- excessive memory usage in bnrstark() [ InitPrimes ] 35- bessel[jk](t_SER) not implemented around a!=0, but gave (bogus) results [output error message for now] IZ 36- [OS/2:] rename static functions _core[2] (conflict with stdlib.h) IZ 37- [OS/2:] ^C would only work once 38- algdep(.1^5,1,10) --> 1 39- { "a b" } \\ with an explicit \n produced "ab", whereas whitespace in strings is to be retained. 40- inconsistencies in return type from lindep [t_VEC/t_COL]. 41- possible oo loop in ellap [ typo in appell1 ] 42- made PSLQ (algdep/lindep) insensitive to 'realprecision' [use precision of the input] 43- nfinit(x^2-4*3,4) --> SEGV 44- Compilation failure on ORIGIN + Irix: rename 'sgi' --> 'SG' in basemath/galconj.c 45- '\r a' where file 'a' is empty --> "a is not a GP binary file". 46- make sure qflll[gram](x) never fails when x has exact entries [ much faster than qflll(x,1) when the entries are large ] 47- increase subFB sooner in buchall() + add GC in Q_denom { bnfinit(x^8 - 4*x^7 + 462*x^6 - 1372*x^5 + 85789*x^4 - 169296*x^3 + 7540560*x^2 - 7456140*x + 263038707) } took a long time, then overflowed the stack 48- make test-kernel did not work anymore (prototype error in kerntest.c) 49- overflow in u_FpM_gauss (oo loop in ZM_inv for huge matrices) 50- polcoeff(1+O(x^2),1,y) --> SEGV 51- content(y/x) --> 1 [ should be y ] 52- divrem(x,2) --> x/2 instead of [x/2, 0]~ 53- divrem([1.,2],x) --> stack corruption 54- ff(n)=local(v=[],w=[]);n f(n)=n ff(f(n))=n --> error (OK) + SEGV on Linux (same data freed twice) 55- qflll(matrix(2,3,x,y,x+y)) --> SEGV IZ 56- default(primelimit, 2156858852) --> SEGV and other signed/unsigned conversion problems. IZ 57- printtex("x1") and printtex("x_1") gave same output IZ 58- printtex(t_STR) [ protect special characters, eg ~ or \ ] IZ 59- [readline:] support old versions (1.0), try to recover from mismatched headers wrt. library, report version of loaded library in gp header [as opposed to library version at Configure time] BA 60- add "const" keyword to allow building with g++ 61- agm(1+x,2+x) --> oo loop 62- lindep([1,0]) --> error [ problem with trivial cases in PSLQ ] 63- wrong reconstruction bounds in nffactor 64- short help message for isprime/ispseudoprime 65- issquare(t_FRAC or t_RFRAC, &x) did not work [ worked without &x ] 66- nfgaloisconj(x^2+1,4, 0) --> SEGV [ bad input ] 67- typo in quadhilbert(-D): required O(D) memory instead of O(sqrt(D)) 68- all signed/unsigned compiler warnings 69- \p29, tan(Pi/2) --> "division by zero". Made error more explicit 70- nfnewprec(nfinit(x,3)) --> SEGV 71- bnrconductorofchar(0,0)--> SEGV [bad input] 72- qfjacobi( non-square matrix ) --> SEGV [bad input] 73- matmultodiagonal([;],matrix(0,1)); --> SEGV [bad input] 74- [GP, trap:] prevent oo recursion if default exception handler itself raises an exception 75- allow qfbred(,2) [don't update Shanks's distance] also for definite forms [ignore flag]. 76- lex(x,"y") --> error [ should be -1 ] 77- algdep(0,1) --> 0 [ should be x ] 78- log(1, AGM) --> oo loop 79- [Configure+gcc] remove useless -m* arguments from CFLAGS [ obsolete ] 80- improper rounding when printing floats: 1.2 --> 1.199999999 81- [default:] realprecision was allowed to be 0, and then treated as 9. 82- Precision loss in inputs of large exponent: 1e100000 -->9.99999824 E99999 83- quadgen / quadpoly accepted square inputs --> weird bugs later. 84- poldegree(x^2 / y^4, y) --> -1 85- setrand(178);quadclassunit(82421) --> 2 instead of 1 [from 2.2.4:] 86- polroots( Pol(subst([1,0,4*x,0,2*x^2+24,0,16*x,0,16],x,10^2589) ) --> division by zero [ double overflow ] 87- LLL-reduction over polynomial rings (almost always failed) 88- (x/y)*(y/x) --> y/y 89- fix pari_init_stackcheck to avoid bogus "deep recursion" messages on broken machines. 90- reused invalid (gerepile'd) pointer in mat_ideal_two_elt. Changed: 1- "not enough precomputed primes": output largest needed p if available XR 2- factorpadic so that factorback gives back the original polynomial, up to a power of p 3- type of avma, bot, top to 'pari_sp' (pari stack pointer) [does not break existing code] 4- [library:] make floating point assignments round the inputs (used to truncate) 5- ensure proper rounding in divrr/mulrr() [ important for numbers input in scientific format, e.g. 1e20 ] BA 6- moved internals of mppgcd to mp.c/gcdii BA 7- moved internals of genrand to mp.c/randomi BA 8- renamed mymyrand --> pari_rand31 9- bnrstark: use partial factorization of discriminant when (pol)reducing the polynomial [could embark into hopeless factorizations] 10- primedec: improved search for uniformizers when p | index IZ 11- [OS/2:] improve dlopen(NULL,...) IZ 12- [OS/2:] enable dynamic-linking build IZ 13- [OS/2:] use same CFLAGS as under Linux IZ 14- when using external prettyprinter, write in raw format to logfile [not in TeX format sent to prettyprinter] IZ 15- don't output pseudo-TeX sequences to logfile when using external prettyprinter (raw format) IZ 16- make X11.builtin-gnuplot-dynamic the default graphic library. IZ 17- allow changing the gnuplot DLL name for gnuplot-dynamic at Configure-time e.g. Configure --graphic=gnuplot-dynamic,gnpltdrw 18- allow Vecsmall(t_STR) 19- polredabs heuristic (try harder to detect subfields). Ex: try it on polcompositum(x^2 - d, polcyclo(11)); MSo20- simplified polzagier() DS 21- improvements in elltors() [ faster torsion bound, check bound > 1 before checking precision ] 22- minor improvements in plindep() [p-adic lindep/algdep] 23- 'make all' now builds the documentation [ that way, 'make install' need not run a bunch of TeX commands as root ] 24- improved idealaddtoone/idealchinese/idealapprfact [use dedicated HNF variant + simpler uniformizers in idealapprfact] 25- rnfkummer: do not return rational coeffs as POLMODs: -1, not Mod(-1,pol) 26- improved idealval() 27- simplified element_reduce, idealmodidele (redideal), compute_raygen (create bnr.gen): faster, smaller elements 28- new algorithm for conductor() and bnrdisc() [much faster, does not need bnr.gen]: find minimal f such that P_{1,f}(K) \subset H, computations are done for a fixed modulus F instead of computing the image of H in Cl_f(K) for many f | F. IZ 29- improve portability of make_vi_tags (cf 'make ctags') 30- using install() twice on the same symbol now updates the prototype code 31- re-enable ranlib support (disabled in 2.0.13) 32- declare first argument in pariputs[f] as 'const char*' 33- enabled Karatsuba multiplication for t_REAL 34- broken Configure into many smaller files (config/get_*) 35- let gphelp write all cross-references as [label:LABELNAME] (was [??]) IZ 36- cache optimization in initprimes() [ default(primelimit,.) ] 37- Str() now takes multiple arguments as print(). Str(,1) replaced by Strexpand() 38- prototype of strtoGENstr() [remove flag] 39- remove -Wno-implicit from CFLAGS 40- prototype code 's*' now produces a t_VEC of GENs [callee's business to call GENtostr] (used to be a NULL-terminated list) 41- [gphelp:] if perl not available, don't pretend extended help is. 42- try harder to detect precision problems in floating point lllgram 43- [ix86 kernel:] macroified bfffo() 44- made all GEN macros return signed types [ had inadvertently switched to ulong as a side effect of some other change, long ago ] BA 45- split kernel Makefiles in MakeLVL0 and MakeLVL1. BA 46- --disable-kernel Configure option replaced by --kernel=none 47- compute_polrel() [rnfkummer] was very slow for [L:K] > 5 (compute Newton sums directly) 48- simplified fincke_pohst() [don't recompute gram_matrix] 49- faster trueeta(), faster quadhilbert(D < 0) 50- faster isprime (trial divide by small primes, recognize 1-word moduli) 51- ellheight: use Mestre's AGM to compute Archimedean height 52- poldegree(0) is now VERYBIGINT 53- alpha + gcc: compile with -O3 [ since F14 fixed the optimizer "bugs" ] Added: 1- [TeXmacs:] contextual completion () BA 2- routines ishiftr, gfloor2n, isqrti, randomi 3- routine random_bits BA 4- [Configure:] --builddir flag IZ 5- File README.os2 6- Allow nfroots(, P) [ roots in Q ] 7- routines Strexpand(), Strtex() IZ 8- detect oo recursion on OS/2 [as on Unix systems] (cf STACK_CHECK) RS 9- routine numbpart() BA 10- GMP kernel BA 11- --kernel Configure option IZ 12- allow an arbitrary polynomial as a 2nd argument to subst() 13- many files in config/ [ from Configure ] Removed 1- macro definition BITS_IN_RANDOM (useless) 2- appr_reduce() [static base4.c]: lllreducemodmatrix does the same. Faster. 3- [useless,undocumented]: idealoplll, idealmullll, idealdivlll 4- 68k assembler kernel [ unmaintained, obsoleted by the GMP kernel ] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.4 (released 12/09/2002): Fixed 1- add default 'new_galois_format' to make 2.2.3 C-22 optional (by default, old format will be used, preserving compatibility) BA 2- FreeBSD: DL_DFLT_NAME value was incorrect 3- Configure: TIOCGWINSZ not detected on Linux BA 4- FpV_roots_to_pol not reduced when applied to a singleton 5- (a.x = [a]); "a".x ---> [a] \\ should be ["a"] 6- (a.x = [a]); print("a".x) ---> a0.E-28x \\ should be ["a"] 7- (a.x = [a]); 1.x ---> error \\ should be [1] 8- wrong rnfidealnorm[rel | abs] (wrong result if O_L not free O_K-module) 9- gcd(x + 1, x + 1/2) --> 1 \\ should be 1/2 [introduced in 2.2.1] 10- gcd for multivariate polynomials over finite fields slower than in characteristic 0 11- [library:] typo in vpariputs: pariputsf("%Z%Z",x,y) did not work (prints x and address of y) IZ 12- [gnuplot + dynamic link:] allow building even when dlopen() not available 13- [CVS:] warnings about unknown files (added .cvsignore files) 14- f()=return \\ return "void" g()=return(f()) \\ return eval("void") = 0 now g() returns "void" also 15- f(x=11,y=x)=local(t=ff(),u=t);1 --> parse error 16- conjvec([[],[],[]]) --> SEGV 17- galoisisabelian(x) --> SEGV 18- nfeltreducemodpr(nfinit(x),1,1) --> SEGV 19- idealmul(nf, principal ideal, prime ideal) returned wrong result [introduced sometime in 2.2] 20- elltors(ellinit([...], 1)) --> SEGV 21- try to make sure life of GP variables is not too short. Was: v = [0,0]; v + [v=0,v=0] --> SEGV u = Mod(x*Mod(1,2),polcyclo(25)*Mod(1,2)); sum(i=1,4,u=u^32) --> SEGV 22- typo in to_Fp_simple [ bnfcertify(bnfinit(x^2-40!)) --> type error ] 23- memory leak in gp when handling '&' arguments 24- removed hack in gcopy [ did not reset the isclone() flag because gunclone checks isonstack(). But other routines may want to use it ]. 25- apparent oo loop in bnfcertify [when computing lower bound for regulator] 26- ideallistarch(nfinit(x),[1,1],0); --> SEGV [bad input] 27- factor(x-I) --> x - #<16382> 28- ellsigma(...,matid(1)) --> SEGV [bad input] 29- ideleprincipal([],1) --> SEGV [bad input] 30- factorback(matid(1),nfinit(x)) --> SEGV [bad input] 31- incomplete help message for vecsort 32- polredabs fails to reduce x^8-2*x^7-34*x^6+78*x^5+265*x^4-628*x^3-389*x^2+1237*x-449 [typo in chk_gen_init: skipfirst not initialized properly] MW 33- (recent) typo in localred (char 2) 34- 2.2.3-C20 had broken backward compatibility: restore [inefficient, useless] previous output of nfelt*modpr routines 35- idealappr(nfinit(y),matid(2),1) --> SEGV [bad input] 36- sqrtn(0,...) ---> error 37- galoisinit(x^4 + 5264*x^3 + 8034856*x^2 + 4205424384*x + 504485485632) --> weird error 38- qfsign([;]) --> SEGV MW 39- torsion group of [0,0,0,-6648,208633] reported as C2 instead of C6 40- bnfinit: very rare stack corruption 41- bnfinit: used too much memory when needing huge number of relations [when computing fundamental units] 42- bnrL1(bnr with conductor 1) --> SEGV 43- "impossible inverse modulo ..." when using addprimes() + ROUND 2 MSo44- [gp: \x] missing 'break' statement in escape() 45- wrong bound in nf_LLL_cmbf (nffactor) [no counter example to the old bound, but proof was wrong anyway...] 46- [gp:] memory leak when assigning to multidimensional arrays (x[i][j]=1) 47- added user-friendly error message if Configure not run properly + fix INSTALL.tex about make gp.dbg / gp.prf 48- matcompanion(x*y) --> weird error 49- typos in hilbert(), e.g hilbert(Mod(1,2), y) --> SEGV, hilbert(-1+O(2^3), 12 + O(2^3)) accepted wheras 2-adic precision too low to decide BA 50- [FreeBSD:] PORTOBJFORMAT undefined by the system --> Configure fails 51- rnfisnorm() [errors, SEGV]. Had to change the prototype. BA 52- Oxxx/Makefile was not compatible with BSD make. 53- errors in files read from .gprc, containing trap() --> SEGV 54- bezoutres(Pol(sin(x)+Pi),Pol(cos(x))) --> "bug in subresext" 55- nfsubfields had a different output format when using galoissubfieds 56- polcoeff(1/x, -3) --> SEGV 57- (-2/x)/(-1/x) --> -2/-1 BA 58- [GP internals:] trap() had an invalid prototype [DI,DI] 59- M[,2][1]=1 --> error; M[1,][2]=1 --> no effect [ now <==> M[1,2]=1 ] 60- [GP:] newline in multiline comments /* */ was not ignored 61- [GP:] when using default 'colors' for input at \gn>1, first debugging msg could be colored 62- [GP:] in break loop, trailing ; was ignored (all results were printed) XR 63- smarter precision increase in update_alpha() (ROUND 4) [stick to padics don't go over Z] Ex: factorpadic(polzagier(18,3), 2, 30) much faster than before. 64- E=ellinit([0,0,0,-10301051460877581926458079712219,-12725370882271967125361344545020920373899020890]); ellap(E,1167254453) --> wrong result 65- factor(x^2 + I*1.) --> SEGV 66- when printing x < 0 t_REAL, was rounded in the wrong direction 67- [WINCE port:] small and SID are already defined in windows.h Changed 1- remove most global variables from gp.c (put them in struct gp_data). 2- use better bounds for size of factors in nffactor() 3- tuning for van Hoeij's factorizer (factor + nffactor) nffactor: call factornf when deg(pol) << deg(nf) + remove a priori overlift for d-1/d-2 test [major overkill] 4- automatic concatenation for strings: use longest match for expression. print("a"[1]) is not valid since "a" is not a vector print("a", [1]) prints 'a[1]' IZ 5- [gphelp:] allow uninstalled operation from $TOPDIR or $TOPDIR/Oarch IZ 6- [gphelp:] better error messages in case TeX compilation fails 7- [development version:] add version number for this file to the gp header when using CVS IZ 8- [library:] unified access to diffptr (NEXT_PRIME_VIADIFF macro) 9- buchall: re-use the same random seed when doubling prec (for units) 10- major cleanup in thue / thueinit 11- major improvements in rnfkummer (use elements in factored form): much faster, give smaller elements, allow arbitrary prime degree 12- improved quadray(D < 0) when relative degree is huge 13- improved bnfisprincipal when class group large: use factorisation (+idealred) instead of arch. components (require much less precision) 14- [library:] allow trapping invmoder and recovering the offending INTMOD 15- improved factor over Z[X] for _huge_ degrees (factorizations mod p) 16- change in ordering for primedec output [use cmp_prime_over_p] 17- [library:] moved (formerly) gp-specific write* and print* to libpari 18- input format to rnfisnorm() [use rnfisnorminit] 19- [GP:] break loop prompt from '>' to 'break>' 20- [GP:] don't get out of break loop after \r 21- type f(x=1)=; twice ---> x = 1 22- [trap:] the way default error handlers operate, how to get out of break loops (see section 2.7 of manual) Added BA 1- Add PARI_VERSION and PARI_VERSION_CODE to paricfg.h BA 2- Add pari_release at top of dft.Config.in 3- rnfpolredabs: flag to use partial factorization 4- [gprc:] test against VERSION number in .gprc 5- [gprc:] multiline constructs IZ 6- mnemonics for flags 7- internal flag nf_GEN_IF_PRINCIPAL to bnfisprincipal [isprincipalall] 8- routine rnfisnorminit() BA 9- [Makefile:] bzdist target 10- [library:] CATCH / TRY mechanism [ encapsulate err_catch ] Removed 1- (useless, undocumented) macros buchgen*, buchinit* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.3 (released 10/06/2002): Fixed 1- bnrinit(bnfinit(subst(polsubcyclo(89,8),x,-x)),4) --> SEGV [make sure isprincipalfact is used in makecygen, even in case of precision problems] 2- bnrisprincipal --> warning + "not an element in ..." [missing nf_FORCE] 3- oo loop in isprincipalfact when increasing bnf precision 4- stack corruption in ellap (LARGE p) 5- zeta(s) destroyed the Bernoulli cache when using the functional equation 6- oo loop in random_relation (called from bnfinit) 7- fixed lower bound for p in nfsubfields (could get oo loop: pol never squarefree mod p) 8- [Vecsmall([1, 2])][1][2][1] --> SEGV 9- typo in t_FRAC + t_PADIC [only numerator of t_FRAC used] 10- factorback(t,nfinit(x)) --> SEGV IZ 11- shift(x > 0,, flag!=0) didn't act as the docs said [flag now ignored] 12- lindep(Vec(x^48)) --> oo loop 13- could get NaN in max_modulus (polroots) --> havoc later 14- missing normalizepol() in centermod(t_POL,) 15- [Follow-up to 2.2.2-F10] even more recent pdftex failed again 16- not enough GC when printing a huge t_PADIC 17- factorpadic(x*(x+1),3,10) would corrupt polx --> SEGV later 18- delayed carry treated improperly in red_montgomery 19- F() = 0; local(x) ==> confusing error message IZ 20- OS/2: make bench didn't work [env wouldn't start shell scripts] BA 21- sqrtn(Mod(1,7),2,&z)-->z=1 should be -1 HC 22- Standard transcental functions exp, sin, cos, ^, *, are now orders of magnitude faster for t_POL arguments of small degree. HC 23- fixed a severe bug in p-adic/integer addition (1+3^4+O(3^10))+3 didn't work. HC 24- Corrected p-adic initell. 25- ellj / eta (t_SER) truncated result to seriesprecision 26- possible overflow in u_FpM_gauss (from ZM_inv) 27- various problems with C++ compilers 28- polredabs could fail to reduce "obvious" input, e.g x^2 + n*x + n^2 29- gcd(x,y,1) didn't check its arguments 30- typo in elltors: could forget a point of order 2 31- gdivgs(t_RFRAC,x) incorrect (if numerator had denominator) 32- serreverse(O(x) or x + O(x^2)) --> SEGV 33- dbltor(0) returned 2^-308, instead of 10^-308 34- precision problems in thue/thueinit setrand(5);tnf=thueinit(x^3 + x^2 - 43690*x - 3529208) --> error in mplog 35- typo in bnfnarrow ("impossible inverse") 36- subst(x,x^0,x) --> floating point exception ISo37- many typos in the documentation 38- [DOS/Windows]: incorrect conversion between 'double' and t_REAL 39- polrootspadic(4*x^2-1,2,2) --> impossible inverse: Mod(2, 16). [specific to 2, and non-monic equations] 40- discrepancy between bnfsunit output and docs [ bnfS[5][2] was t_MAT ] 41- matdet: pivoting strategy incorrectly chosen ("incorrect type in gexpo") 42- polcompositum output ordering depended on random seed 43- plotrecthraw(0,[0]) --> SEGV 44- plothraw([],[]) --> SEGV IZ 45- ix86 inline assembler compilation problem [divll] XR 46- forgotten case in Round4 [ nfdisc(x^12-10*x^11-57*x^10+740*x^9+353*x^8-16130*x^7+17749*x^6+100120*x^5-108466*x^4-292200*x^3+128380*x^2+380800*x+133112) --> impossible inverse: Mod(2, ...) ] 47- sin(1e-100) ---> 9.999999999999999999735998397 E-101 [ precision loss ] 48- idealpow(nf,x, n < 0, 1) did not reduce the result 49- gcd(0, -1) --> -1, content([0, Pi]) --> 3.14, content([0,Pi,Pi]) --> 1 BA 50- compilation problem on OSF (RTLD_GLOBAL undefined) BA 51- [X-Windows] hi-res plot: window not redrawn properly (BackingStore pb) 52- problems with tex2mail output (wrong alignment, wrong colors) 53- contfrac(sin(Pi/4),,2) --> impossible assignment 54- oo recursion in gaffect(t_POL, scalar) 55- content([-1]) was -1 [ should be 1 ] 56- stack corruption in u_FpV_polint (used by modular bivariate resultant) 57- polroots() used too high a precision when checking errors a posteriori (--> slow) 58- contfrac(1/x) --> SEGV 59- typo in sinh(0) --> wrong zero exponent 60- exp(O(x^-1)) = O(x^(-1)) [ouch...] 61- dilog(O(x^10)) = O(1) 62- cosh(O(1)) --> division by 0 63- sqrt(4*x^2) --> not an integer exponent for non invertible series in gpow 64- besselj(0,O(1)) [or besseli] --> precision<=0 in gprec. 65- O(1)' --> O(x^-1) 66- gcd(O(2^1), O(2^10)) --> O(2^10) 67- polrootspadic(x^2+8*x+4,2,2) --> "impossible assignment" 68- one could write() an object to a binary file, corrupting it MW 69- ellap(ellinit([0,0,1,-7077,235516]), 1075060289) --> "zero argument in an arithmetic function" MW 70- ellap(ellinit([0,0,1,-7077,235516]),1135392007) --> SEGV BA 71- user's manual index truncated if LANG=fr_FR 72- lex(string1, string2) could return something not in {-1,0,1} 73- bnfisprincipal(bnf,x, 0) was not instantaneous when bnf.no = 1 74- no GC in poleval 75- make clean did not remove libpari-2.2.* 76- incorrect result in gaffsg(s < 0, t_PADIC) [ wrong valuation ] Changed BA 1- improved Fp_isom IZ 2- remove all dependance on __OPTIMIZE__ for inlining [cf 2.0.14 F-24] 3- implementation of psi() [very slow + wrong results at low accuracy] 4- cleaned up forvec() [no more global variables] 5- improvements in bnrstark (precompute common data) BA 6- improved ffinit() 7- rewrote time-critical parts of bnrstark 8- all 'input filter' code removed from GP. es.c:filtre() now handles the full filtering [and has become reentrant] 9- isprime() now guarantees primality BA 10- improved polsubcyclo() BA 11- new interface for galoissubcyclo HC 12- gamma function for integral/rational arguments 13- faster factornf / nfgcd 14- removed readline-specific code from gp.c 15- allow bnrstark over Q 16- 'subgroup' argument made optional in bnrL1, bnrstark, rnfkummer 17- use relative van Hoeij algorithm in nffactor [can handle huge number of modular factors] 18- rewrote factorff() to use new modular functions 19- rewrote primedec() to use new modular functions 20- rewrote most *modpr functions 21- modified diagnostics for integral LLL to match floating point version 22- INCOMPATIBILITY: polgalois(); changed 3rd component of result so that it gives the numbering among all transitive subgroups of S_n [ was ad hoc up to 7, then as described above for n >= 8 ] 23- INCOMPATIBILITY: nf.zk is now T2-LLL-reduced 24- idealtwoelt was very slow when a small prime with many divisors divided the index (use approximation theorem) 25- content(scalar) = abs(scalar) [when it makes sense] 26- changed the interface to ispseudoprime and isprime 27- [internal] element_muli: check input is consistent 28- rewrote all LLL algorithms (use Householder, not Gram-Schmidt; do not use Gram matrix; unified code). 29- INCOMPATIBILITY: the internal components of nf[5] have changed (MC and T2 not needed anymore) 30- INCOMPATIBILITY: [library] polred & polredabs do not take a 'prec' argument anymore 31- unified nfinit, polred* [use dedicated structs internally] 32- rnfconductor(..., 1) doesn't need GRH anymore 33- extracted FpXQ_gener from idealstar 34- allow more types in gdivround 35- improved root_bound (first step in factor() over Z[X]) for huge pols. 36- faster bernfrac / bernvec 37- INCOMPATIBILITY: removed gentimer() / genmsgtimer(). Use TIMER/msgTIMER 38- let nfsubfields call galoissubfields (much faster when field is Galois) 39- Configure (locatelib): don't look for lib*.so.x [ pb on Linux with [readline | ncurses]-devel.rpm. Added 1- mplog2() function --> faster mplog() 2- gcd for Gaussian integers HC 3- APRCL primality test 4- (strong) Lucas primality test + Baillie-Pomerance-Selfridge-Wagstaff test BA 5- Facilities for permutation groups (perm.c). BA 6- New functions galoissubgroups, galoisubfields. HC 7- Implemented all Bessel functions J, I, N, K, H1, H2, and Bessel functions for power series and polynomials. HC 8- Implemented PSLQ [preliminary] GTo 9- Implemented Cipolla's algorithm for sqrt(Mod(x, p)) 10- library functions FpM_ker, FpM_deplin, diviiround, centermodii 11- library function gerepileall 12- library functions corepartial, core2partial 13- library functions affui, itou, stor, itor 14- library function lllint_ip (in place) 15- library functions Q_primitive_part, Q_primpart, Q_remove_denom, Q_denom 16- allow polredabs to use a partial factorisation of disc(nf) [as polred, but inconsistent values for flag. Backward compatibility problem here...] 17- routine ellminimalmodel() IZ 18- systems/ directory (currently for OS/2 only) IZ 19- [OS/2:] install() for OS/2 system (using builtin dlopen) IZ 20- gnuplot and X11 are now simultaneously supported %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.2 (released 10/01/2002): Fixed 1- qfbred(Qfb(4, 17, 18)) --> SIGFPE 2- broken compilation in arith.c when CC != gcc 3- nfhilbert (local case pr | 2) expected POLMOD argument without check 4- poldegree(P, t) slow when t != varn(P), and may not work in library mode 5- polrootspadic only worked when leading coeff was a unit 6- paddicappr was very slow (esp. when p was large) 7- Configure: check for 'double endianness' [used for double --> t_REAL conversion]. Previous check was failing on ARM architecture. 8- forsubgroup state not properly restored after ^C 9- libpari.so included symbols from libc without linking it explicitly (Debian requirement, and cleaner anyway) 10- recent pdftex failed to compile users.tex (\pdfannotlink undefined) 11- !nf.sign[1] was parsed as (!nf.sign)[1] 12- matrix(0,1) --> "identical index variables in matrix" [from 2.2.1 F48] 13- bnfinit could miss some relations in the "small norm" phase 14- x % y incorrect when y < 0 inexact (2 % -3. --> -1.) 15- typo in gcdreal (result < 0) [introduced in 2.2.1] 16- some obscure problems in rnfkummer 17- not enough GC in hnflll 18- sqrt(25 + O(2^5))^2 - 25 = O(2^4) 19- not enough GC when writing a t_PADIC 20- user member functions were very slow (unnecessary copy) 21- cd Oxxx; make -j4 bench ran things in the wrong order 22- poltchebi, pollegendre gave bogus output for negative degrees 23- possible SEGV or oo loop in polrootsmod when p not a prime 24- nfnewprec(bnf) could change bnf.gen (due to round-off errors) 25- SEGV in gcd(x,y) when operands have coeffs of the form Mod(t_INT,t_POL) 26- not enough GC in poldivres (= t_POL % t_POL) 27- issquare(Mod(3,27)) = 1 [from 2.2.1 C 10] 28- [BUG] message in 'elliptic' bench [made polroots more canonical] Changed 1- allow compressing *.dvi files for the online help system 2- index bound was restricted to MAXLONG in subgrouplist. Made it a GEN 3- try to guess correct precision earlier in polgalois/polroots 4- allow GP pointers to 'matrix components', e.g issquare(25,&x[i][j]) 5- changed assignment semantics to make it closer to C: x = y understood as (evaluate Y:=y, then set x:=Y), e.g i=0; i += (i=2) sets i to 4 (was 2) 6- output VECSMALLs as 'Vecsmall([...])' 7- more efficient polcoeff [also: made it independent of MAXVARN] 8- retuned bnfinit (let subfactorbase increase further): setrand(1);bnfinit(x^4 + 1159*x^2 + 335241) would never finish. 9- specified precisely lex() [see manual]. Now: lex([0,0],[0]) = 1 (was -1), lex(0,[0]) = -1 (was 0) 10- allow factorback(x, e) for prod x[i]^e[i] 11- don't store empty lines in history [cf 2.2.1 F57] 12- extend x \ y, x \/ y and divrem(x,y) XR 13- improvements in bnrstark (try harder to find modulus, need less memory) 14- global(x): ignore if x already global (used to raise a warning) BA 15- install: add RTLD_GLOBAL to dlopen flags [so that symbols can be used in other .so] 16- removed hack in gp_init.c [used "constant default args" to call print0] Added BA 1- New function 'vectorsmall'. 2- allow setting variable in divrem 3- GP operator #l for length(l) 4- a warning in zsign ("increase precision?") when dubious result 5- Montgomery reduction (only used in powmodulo() for now) 6- [experimental] basic tuning utilities (src/test/tune.c) [make tune] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.1 (released 18/10/2001): Fixed 1- typo in factornf (factor of degree 3 --> error message) 2- rnflllgram(), idealinv() didn't check their arguments 3- [readline] \r would complete using files matching r* 4- wrong result in ZY_ZXY_resultant when degree dropped in ERS 5- factor(x^2 + I*1.) --> stack corruption 6- \r directory was silently accepted 7- check arguments in polcompositum() TH 8- [Cygwin:] fixed paths for readline on cygwin 1.* XR 9- possible overflow in ComputeCoeff [ bnrstark() ] 10- numtoperm(2,x) --> SEGV [check arguments now] 11- rnfkummer could fail with "missing units" 12- factornf(P, non-monic t) --> error 13- forsubgroup/subgrouplist didn't check their arguments nor accepted SNF matrices XR 14- typo in nilord4 --> SEGV, e.g. nfdisc(x^16-363*x^14+53550*x^12-4091823*x^10+170172414*x^8 \ -3663509067*x^6+33703350345*x^4-63300912912*x^2+32451860736) 15- some messages didn't distinguish between MBytes and millions of Bytes 16- typo in BuildTree [hensel lift]: SEGV 17- (rare) oo loop in polroots, e.g. x^5-2*x^4-32*x^3+72*x^2+218*x-491 18- oo loop in ellpointtoz on certain rare inputs 19- stack corruption in factorff BA 20- better interface for galoissubcyclo BA 21- galoisfixedfield(,,2) now works with non Galois subfields BA 22- nfgaloisconj now use `d-1'-test + better strategy BA 23- fix accuracy problems in vandermondeinverse 24- missed some simplifications when handling multivariate t_RFRAC 25- [Cygwin:] incorrect default 'path' (used : instead of ;) 26- element_sqr didn't check its arguments (SEGV if bad input) 27- possible stack corruption in polroots (+ improved GC there) 28- typo in nfsubfields (incorrect bound: could miss a subfield) 29- typo in zsimpjoin (concat error in bnrdisclist, intr. in 2.2.0) IZ 30- typo in Configure [rl_save_prompt and _eprintf not found in target libs] MD 31- oo loop in ellap [uninitialized array length in apell1] 32- stack corruption in addfrac [wrong result for large denominators] MD 33- resmod2n [called from powmodulo] could return unnormalized integers 34- not enough GC in nfinit for huge degrees [get_mul_table] 35- intformal(1/2/t^2) --> apparent oo loop 36- polredabs(degree 1 polynomial) --> x [could be very slow] 37- polredabs() could use a basis which was not LLL reduced BA 38- pariformats (e.g %Z) incorrect on 64bit machines 39- polhensellift(x,[x,1],2,2) --> "bug in multiplication" 40- glitches in readline completion (random() * ne inserted args) IZ 41- CLK_TCK may reside in time.h 42- misleading definition for ?omega / ?bigomega 43- on \q, "Good bye" --> Goodbye 44- install() accepted gpnames which were not valid identifiers 45- bnfinit(x^4+65,,[.1]) --> SEGV (whenever c < c2) 46- when host badily configured (~ not expanded), gp would die on startup XR 47- factorpadic(, not a prime, ) --> SEGV 48- matrix(2,2,i,i, ...) allowed, with weird result BA 49- better arguments checking for galoisfixedfield 50- psi(I) --> incorrect type in rtodbl XR 51- increase precision automatically when needed in quadhilbertreal 52- idealstar(bnfinit(polcyclo(5)),11).clgp --> stack error 53- default(format,"g0.4"); 3./10 --> 0.300004577 [now: 0.3000] 54- subst() didn't check its arguments (e.g SEGV on t_STR) 55- qfbclassno(x < 0): wrong algo when x non fundamental 56- obscure bugs with types FRACN/RFRACN [when simplifies to INT/POL] IZ 57- readline history: while inputing continuation lines, the partial command was not put into history until full command was run 58- not enough GC in polroots (dft) for huge degrees 59- Cygwin: don't try to build gp-dyn.exe [crashes] 60- use vsnprintf to fix a long-standing bug in PARI output (using formats) used a fixed-length buffer that could overflow. If vsnprintf is not found by Configure, the bug remains. Changed 1- removed useless parameter prec in many bnr* and rnf* functions 2- major update of bnr* functions [use elements in factored form] 3- use /tmp instead of /var/tmp as default tmp directory [faster on Solaris] BA 4- Fp_PHlog (Pohlig-Hellman) can use a factorization of the subgroup order 5- major update of buchall() [bnfinit]: accurate precision increase, use multiplicative archimedean components (fewer logs), cleanup 6- [libpari:] rename permute/permuteInv to GP names numtoperm/permtonum 7- scalar + [;] --> error [made it [;]] BA 8- factorback, chinese, lcm and gcd now accept a single vector 9- Use I \cap Z instead of NI in hnfideal_inv 10- improved issquare(t_INTMOD) 11- improved subresultant routines (new function pseudodiv) 12- command-line options to Configure (installation directories) 13- rnfequation: use modular (bivariate) resultant 14- polynomial gcd (srgcd): uses modular algo (modulargcd,nfgcd) if possible 15- unified internal hnf* functions 16- improved nfsubfields [Hensel lift, allow nfsubfields(pol) instead of nf] 17- merged all "integer logarithms" + "safe ceil" functions (mylogint, get_e, floor_bound, myceil) 18- readline: TAB on empty parentheses following a function name has the same effect as M-h (used to insert args). IZ 19- faster computation of prime number table [better cache use] IS 20- obscure compiler bug in rootpol.c:max_modulus() [don't modify tau] 21- make bench ('elliptic'): explained [BUG] message 22- allow lift(t_PADIC) 23- faster polroots for Q of the form P(x^k) 24- allow subst(t, x^n, x) 25- ?user_fun: do not include function text if help available from addhelp [always include it for ??user_fun] 26- default values for used defined function arguments are evaluated when the function is called [used to be "when it's defined"] 27- allow subgrouplist(znstar(5)) [didn't accept groups in general form] 28- taught GP about GP2C-style type declaration [ignored] 29- 0. [realzero()] is now coded on 2 words (was 3, with third one ignored) IZ 30- readline history: lines are remembered as they were input (whitespace was deleted) Added BA 1- function pith() [= pi(x), naive implementation] 2- new target for Makefile: gp.dbg BA 3- library functions FpX_roots_to_pol, FqX_roots_to_pol BA 4- library function FpX_FpXQ_compo (Brent & Kung) 5- library function FpM_inv, FpM_gauss, ZM_inv, QM_inv 6- library function primitive_part IZ 7- readline: allow switching readline editing on/off [for commandtools] IZ 8- readline: F1 has same effect as M-h, and F1F1 as M-H (short/long help) 9- function writebin XR 10- new error message "precer" (precision too low in...) 11- allow minimal handling of t_VECSMALL under GP IZ 12- add error messages (as in err(shier2)) to emacs tag file 13- add error messages (as in err(shier2)) to vi tag file IZ 14- add flag to shift() to enable consistency with 2-complement semantic IZ 15- default 'prompt_cont' for continuation lines IZ 16- default 'readline' to switch readline on/off in readline-able binaries IZ 17- capabilities to 'bittest' (return bitmap, 2-complement arithmetic) GH 18- inline assembler micro-kernel for alpha + recent gcc (at least 2.95.3) Removed 1- obsolete functions twototwo, threetotwo, threetotwo2 XR 2- error message truer2 (superseded by precer) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.2.0 (released 30/04/2001): Fixed BA 1- gpflog could print some lines twice 2- return() could forget objects on heap 3- polhensellift didn't accept factors which were not squarefree 4- Configure missed some shared libraries (when only .so.version was there) 5- possible symlink attacks against mpqs() 6- internal requests for precision of bnfinit(x) [ = Q ] could yield SEGV 7- compatible = 3 not taken into account when reading a file 8- cbezout(0,0) = 1 (should be 0) 9- when lines > 0, output driver didn't reset properly after user output 10- nfdisc(x^5+2*x^4+3*x^3-3*x^2+122*x-1) --> impossible inverse 11- bug in gcc-2.95 -O3 -fomit-frame-pointer [Linux]: SEGV in quicksqri 12- addrfrac: could return a t_RFRAC whose denominator wasn't a t_POL 13- bnfcertify (zimmertbound): off by two error when reading bound 14- very inefficient Hensel lift (used ideas from Shoup's NTL) 15- incorrect assumption on factor degrees in polcompositum (SEGV in rare cases) 16- Vec(VECSMALL) --> incorrect object 17- galoispermtopol didn't check permutation length (--> SEGV on bad input) XR 18- rnfinit(nf, T) -> bug in multiplication if nf = Q 19- Pol(cotan(x)) -> SEGV 20- factor(tough polynomial over Z[X]) --> possible SEGV when padic precision is increased [e.g factor(polzagier(60,0))] XR 21- bug in ideal bound computation in rnfnormgroup 22- bnrisprincipal(...,y+z) --> SEGV 23- GP could forget about a function whose redefinition was stopped by a syntax error (sometimes with a delay!) 24- bnfisnorm result would include pols in MAXVARN: e.g. Mod(1, #) BA 25- pbs in Fp_factor_irred (factoring over Fq a pol. defined over Fp) 26- missing macros for gphelp (tex-mode) in chapter 5 27- nfsubfields(nfinit(polcyclo(13))) --> impossible inverse Mod(0, 29) 28- argument checks for element_mulid, nf_get_r1 (access to nf.sign) 29- typo in quadhilbertimag (SEGV for very large discriminants) 30- wrong precision used in numerical derivation BA 31- isprime(n < 2, 1 or 2) gave wrong result IZ 32- \r C:\a.gp wouldn't work [ : and \ forbidden... ] BA 33- bad PARI prototypes in init.c [were confusing GP2C] XR 34- nfdisc: fixed cache system in nilord (esp. precision handling) BA 35- nfgaloisconj(polcyclo(40)): accuracy lost nfgaloisconj(polcyclo(11)+1): oo loop IS 36- typo in squfof tuning on 64bit machines 37- -lm doesn't exist on MacOS X BD 38- typo in src/kernel/l0asm.c: ulong not recognized by MSVC IZ 39- TeX quasi-parsing in gphelp 40- ^C in gp would kill an xdvi launched by gphelp via ?? [detach from tty] 41- factor(P in Z[X]): wrong bound used in LLL_cmbf --> "no factor" 42- one extra blank line printed with some error messages [errcontext] 43- no typechecks in subgrouplist and forsubgroup 44- round4 [dbasis]: make sure polmodi gets a polynomial, not an int (SEGV) 45- various typos in rnfkummer (SEGV or 'non-maximal rank in nfhermite') 46- Configure -l (no argument) didn't work anymore BA 47- incorrect quoting in src/make_vi_tags (make ctags) 48- 1/[;] --> error, whereas [;]^-1 --> [;] [ now, allow 1/[;] ] 49- ??real only gave the help on t_REALs, not on real() 50- eigen: "missing eigenspace" [roundoff pb in ker() compared to exact 0] 51- error messages on GP metacommands (\...) indicated wrong context 52- bnr functions might fail with "indefinite matrix in lllgram" [prec pb] 53- nfhilbert(nf,a,b, pr | 2) would give bogus result if nf in variable 0 (x) MD 54- real(1 / (a+quadgen(...)*b)) was a / (a^2 + b^2) [assumed quadgen(-4) !] 55- wrong HNF (reduction not finished) when nblines >> nbcol [hnf(,0) only] 56- rare problem in isprincipal (large non Galois base field)--> wrong result (generators not required) or oo loop. 57- compatibility problems with readline-4.2 (build would fail) BA 58- pari format %Z (pariputsf) treated incorrectly on 64bit machines XR 59- typo in smallvectors (polredabs): possible oo loop Changed 1- DOS distribution archives (GPM removed) XR 2- round 4 algorithm: compute characteristic polynomials via Newton sums XR 3- nffactormod now calls factmod / factmod9 when possible XR 4- don't compute discriminant in nffactor/nfroots + better bounds in nfsqff 5- input loops rewritten (filtre more flexible + unified common code) 6- better modular arithmetic for polynomials (+ uniformized names) 7- bnfinit: "looking hard" part overdone in random relations. Tuned down. XR 8- added flag in rnfconductor to check extension is abelian (under GRH) 9- made Vec("pari") return ["p","a","r","i"] instead of ["pari"] 10- renamed library function gsize() to sizedigit() [conflict with gtk] XR 11- bnrstark: check if N0 is too large (=> computation impossible) IK 12- let readGEN() return NULL when EOF is met (was oo loop) 13- algorithm for zeta(), gamma() [initial GP code by HC] 14- improved rnfnormgroup() [reduce number of calls to isprincipal] IZ 15- flags for OS/2 build + use generic [pre|suf]fix for object files IZ 16- readline: hit_return() would not work after Esc-H extend online help recognition capabilities (Esc h/H, F1) 17- install the whole distribution (see ?12) 18- clean up in the bnrdisclist ray class group internal functions 19- naming scheme for development versions library: libpari-2.2.so.0.0.0 20- new Configure flags --share-prefix, --host 21- allow library functions to return NULL to the GP interpreter 22- let A^-1 and 1/A return a left inverse of A if it exists [A had to be square] 23- retuned factorization over Z[X] (+ "d-1 test" in naive recombination) 24- sort factorpadic() output Added 1- files README.WIN, config/[arch-osname|locatesymbol], doc/tex2mail.1 GN 2- Jebelean extended gcd + rational number reconstruction XR 3- new flag to rnfconductor (check extension is abelian) IZ 4- set of default colors (boldfg) 5- modular polynomial arithmetic ([uni|bi]variate resultant over Z, characteristic polynomial of algebraic numbers, nfgcd). [undocumented, experimental] 6- Pohlig-Hellman discrete log over Fp and nf.zk / pr BA 7- flag to galoissubcyclo (also output conductor) Changed 1- start using the new modular functions [polcompositum] BA 2- sqrtn, aka mpsqrtnmod (modular n-th root) uses Fp_shanks now Removed 1- obsolete undocumented functions oldidealinv, idealinv0 2- buggy function hnfhavas (hnflll is a better alternative) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.1.0 (released 17/11/2000): Fixed 1- non portable \e in es.c (pb with Sun cc) 2- ^C while prettyprinter in action --> gp crash 3- polresultant(a,b,x,2) --> b 4- exp(log(1.+x+y)) --> division by 0 TH 5- support cygwin version 1 6- TeXmacs interface 7- GP parser codes (sqrtint, idealprimedec) 8- trap (break loop) + NO readline + ^C at input time --> exit. 9- qfminim(,,,1) --> nonsensical result (typo) 10- SPARC + gcc-2.97 --> bug in addsmulsi (register reset too soon) 11- trapping allocatemem() could crash GP Changed 1- release PARI under the GNU GPL. Remove COPYRIGHT file, add COPYING =========================================================================== Done for version 2.0.21 (released 27/10/2000): Fixed 1- trap(gdiver2,a,1/0) trap(,a,1/0); trap(gdiver2,a,1/0) --> crash 2- lllgramintern could reduce a wrong lattice (after precision problems) XR 3- not enough GC in bezout() 4- use hnfmodid in ideallllred (work mod I \cap Z, not mod N(I)) IS 5- C++ compilation problem (compl is a C++ operator + casts) 6- factor(x^2 - 16810110*x + 62994937599000) --> division by 0 BA 7- Pocklington-Lehmer didn't stop factorisation after sqrt(N) 8- exp(log(Pi+x+y)*1.) --> SEGV (still gives an error, but a decent one) 9- factorff needed a prime field F_p where p was single precision 10- more digits than were significant could be printed (ex: precision(Pi,1)) 11- rnfisnorm didn't accept vectors on Zk basis as argument 12- [cygwin] fixed timer (always returned 0) IS 13- function prototypes (missing 'extern') 14- quadray(bnf, ...) didn't work when bnf.disc < 0. Could also return a relative equation over an intermediate field 15- deficient argument checks: asinh(2*x-1), agm(1,1-x), zetakinit(2*x-1), idealinv( , wrongtype), nfnewprec([2*x-1]), thueinit(non-monic or degree 1), lcm(x, 0) rnfidealmul(2*x-1,0), galoisfixedfield(2*x-1), qfbnupow(2*x-1, 0), polred([x,x]), bezout(Mod(x,x^2+1),0), numtoperm(-1,0), polred(nf), idealhnf(nf,y+z), factorpadic(,y,), nfelftreduce, rnfsteinitz, idealappr(not an nf, ...): SEGV 16- check variable numbers in algtobasis: nfalgtobasis(nfinit(P(y), x)) 17- factorcantor(x^4 - x^3 - 2*x - 1, 3) --> SEGV [typo!] 18- matsupplement(non-exact entries): fixed zero test (--> |x| < eps) 19- precision(I*1.) --> +oo (should be realprecision) 20- global() could check uninitialized memory 21- default(prettyprinter,"non-existent-file") ---> SIGPIPE and GP crash 22- gamma(1+O(3^2)+x) --> SIGFPE 23- typo in cxgamma (gamma(-4.1+Pi*I/2) --> exponent overflow) 24- Odos/paricfg.h defined PARIINFO incorrectly 25- inconsistenty t_POLMOD specification: Mod(x,y)+16 --> invalid object 26- bnfsunit error (impossible I-->S) when large class group 27- qfminim([;],...) / qfperfection([;]) --> SEGV 28- idealpow(,,,1) only reduced at the end, not after each multiplication 29- typo in zbrent (always used bisection) BA 30- cotan(x) wasn't accepted 31- wrong internal prototype for thetanullk (prec not taken into account) 32- various bugs in gphelp -detex (??\a) 33- trap + ^C + next would interrupt \r or read() IZ 34- external prettyprinter incompatible with colors 35- idealval used much larger numbers than necessary 36- sqrtint very inefficient (computed with full precision all along) 37- bnfisprincipal couldn't deal with some non-Galois fields 38- listcreate allowed creating longer lists than GP could later handle 39- INPUT colors was "leaking out" (affected status messages) 40- idealpowred(, power > 2^32) --> wrong result 41- when lines > 0, output driver didn't reset properly after overflow 42- huge precision losses in bnfinit computations (--> truncation error) 43- mateigen([1,2;3,4]) wouldn't work at default precision 44- leftover debugging statements in gphelp -to_pod 45- zeta(x) didn't always use the precision of x (contrary to the other trans. functions) 46- some Warnings from MIPSPro 7.2.1 compiler (contributed by PM) BA 47- gdiv(SER,POL) --> SEGV when POL has lgef < lg 48- check relative pol is monic before calling a rnf* function XR 49- cleaned up bnrL1 character computations XR 50- round 4: possible problems when increasing p-adic precision 51- stack corruption in mppgcd(huge t_FRAC, huge t_FRAC) BA 52- abs(t_SER) not allowed 53- nfdisc(non monic polynomial,, disc factorization) returned wrong answer 54- rnfidealnormrel(rnfinit(nfinit(y^2-2),x),2) --> SIGBUS 55- hardcoded paths in a few scripts (tex2mail, gpflog, make_vi_tags) Changed BA 1- more efficient quadratic Hensel lift 2- made ya optional in polinterpolate BA 3- more efficient factorff when pol belongs to Fp[X] (based on Fp_isom) 4- catch SIGFPE 5- made poltchebi efficient 6- write all real zeroes in exponential format (0e28) in format 'g' 7- bnfsunit: try to compute S-units even when the class group is large reduce class group generators 8- 0.e N now inputs a real 0 of decimal exponent N (was N-defaultprecision) 9- try to avoid errors due to precision loss (while computing archimedian components) in bnfnewprec/bnfmake 10- restore \o2 to previous meaning, use \o3 for alternate prettyprinter 11- normalized output of idealfactor (sort factors) 12- better TeXization (\left / \right) 13- allow color changes in error messages (when sample input is given) 14- format for bnf[9] (new isprincipal) 15- cleaned up isprincipal + bnfinit (small_norm, getfu, class_group_gen) XR 16- added flag for D>0 in quadhilbert: if non-zero, try more modulii 17- idealred: reduce huge ideals as Z-module first (using lllintpartial) 18- TeXmacs interface Added 1- library function zerovec 2- van Hoeij's algo. for modular factors recombination (factor over Z[X]) 3- algdep for p-adic numbers IZ 4- default values for 'colors' (light/dark) and 'prettyprinter' (tex2mail) 5- hnflll implementation (old one was preliminary and didn't work at all) GN 6- squfof implementation 7- numerical derivation XR 8- GP interface to hensel_lift functions (polhensellift) Removed 1- quadrayimagwei, preliminary implementation to quadray(D < 0) =========================================================================== Done for version 2.0.20.beta (released 07/06/2000): Fixed 1- gp -p1e -->SEGV 2- nfinit([x,1]) --> SEGV 3- ensure stack large enough [allocatemem(1) painted user in a corner] 4- make sure mpinl.o is linked (binaries may fail to build otherwise) 5- make sure sqrt(Mod(a,b)) terminates 6- memory leak with PARI pointers (issquare(4,&x)) 7- 'make clean' didn't affect doc 8- Configure didn't detect some SuperSparc + Linux combination 9- forprime (and friends) could crash when loop index was tampered with 10- trap(, -1, (1/0)) == -1 ---> -1 (analyseur not reset) XR 11- bnrstark initializations (incorrect when field not totally real) 12- member functions not very robust [e.g. ellinit(e,1).roots --> SEGV] 13- compiler warnings (gcc -O -Wall) 14- trap() not robust enough in library mode (nested handlers) 15- (x^2+3)/(2*x)*x --> invalid RFRAC 16- factorpadic result used too high a precision (+improved handling of nonmonic polynomials) 17- sqrt(Mod(0,1)) --> oo loop (+ improved a bit mpsqrtmod) 18- no GC in norml2 IZ 19- tex2mail had difficulties with rational functions 20- (rare) SIGBUS in quadclassunit(non-fundamental discriminant) 21- g()=f()==0 --> syntax error 22- } as last char of an input file (missing a final \n) caused problems 23- ??keyword@ didn't work properly (pattern modified between chapters) BA 24- bug in galconj.c:corediscpartial (could return half integer) 25- factorff and ffinit "not random enough" TH 26- Configure doesn't handle cygwin new directory structure CW 27- polsturm(x,0,1) = 1 (should be 0) 28- [library:] gentimer(3) didn't work PW 29- various bugs in qfminim(,,2) [bound was rounded up + stack corruption] 30- ellap(e,2) gave wrong result when 2 | e.disc 31- factorint: isprime() used on factors even within smallfact() GN 32- SEGV in mpqs main sieving routine (unsigned comparison) 33- prevent polredabs from keeping small vectors accumulating in a subfield Changed 1- renamed .DOC files to .txt (Explorer was getting confused...) 2- moved MANIFEST to config/MANIFEST IZ 3- meaning of flags > 1 in plothraw IZ 4- output of \x (a bit more verbose) 5- unified basic t_QFR routines (use exponential distance internally) Added BA 1- Pocklington-Lehmer primality prover BA 2- Fp_isom (library) BA 3- Mod(a,b)^(c/d) for a,b,c,d integers 4- flag to vecsort (decreasing order) BA 5- function sqrtn =========================================================================== Done for version 2.0.19.beta (released 17/03/2000): Fixed 1- buffer overflow in ploth (when extrema too large) 2- trap(,"") didn't work IS+BA 3- various fixes necessary for g++ 3- prototype inconsistency in level1.h (evalexpo/evalvalp) 4- trouble with pgcc -mk6 + variable k6 in elliptic.c HC 5- nfnewprec(bnf) could contain objects of low accuracy XR 6- check subgroup argument in bnrL1 7- typo in ideal_two_elt (oo loop) 8- pb with GNU as + preprocessor on Sparc 9- incorrect result in matdet over Z[1/n] (Gauss-Bareiss) [gdivexact] 10- solve(x=0,1,deriv(x)) --> SEGV 11- ??' --> weird error 12- generic SNF (polynomial entries) couldn't handle 0s on diagonal 13- incorrect handling of 0 ideals in some functions XR 14- typos in bnrL1 15- bad input not handled in rnfcharpoly() IZ 16- delay rounding in rectplot structures until plotting device 17- Mod(1,x) / matid(2) --> incorrect object 18- avoid getrusage on alpha (pb with gp-dyn) 19- incorrect file inclusions when using gas on Sparc (-->undefined symbols) 20- massive cancellations in zetak(nfz,) when current prec lower than nfz's XR 21- bnrstark(): fixed inconsistency between 32bit & 64bit versions + check maxprime() before starting the computation PW 22- hyperu bad input bug PW 23- intnum(x=1,2,0) --> oo loop 24- sin(x + y) --> error 25- next(i > 1) didn't work (part of the last loop could be executed) 26- typo in polrootspadic(p, 2, *) [singular case] Changed XR 1- bnrL1 now takes a congruence subgroup as second argument 2- allow some functions to modify bnf/bnr structures (matal + cycgen) CB 3- modified TeX macros for pdftex 4- have abs(t_COMPLEX) give an exact result if possible [abs(0*I) was 0.0] IS 5- improved generic gcc compilation flags 6- in qfbclassno(), compute in G^2 to get rid of cycli factors 7- improved bnrdisc/bnrconductor Added BA 1- function galoissubcyclo() BA 2- (for now internal) function inverseimage_mod_p() BA 3- optional arguments (vertical range) to plot() IZ 4- `ticks' on hi-res plots IZ 5- prettyprinter default and tex2mail file BA 6- new function Fq_ker =========================================================================== Done for version 2.0.18.beta (released 20/12/1999): Fixed 1- wrong method chosen in isinexactfield for 0 polynomials 2- stack corruption in sylvestermatrix(0,...): Mod(x,x)^-1 --> SEGV 3- garbage left on stack in ginv(1 / n) 4- typo: carreparfait --> gcarreparfait in nfiso0() 5- for (A=1, 2, A = -A) --> SEGV IZ 6- [gnuplot] couldn't set terminal as the first graphing operation DE 7- typo in kernel/sparcv7/level0.S: err --> pari_err 8- TeXmacs interface (use new protocol) 9- call simplify() before applying GP '==' and '!=' operators Ex: x;n;k;m; (n+m)==(k+1-k)*(n+m) was false. 10- sumdiv(N,...) required single precision N BA 11- bound problems in nfgaloisconj() 12- oo loop in do_agm() 13- "Warning: in Gauss lg(a)=1..." from isprincipalall0 14- specific error for precision problems with p-adic ell. curves IZ 15- ploth() plots are 1/2-pixel off BA 16- result was not always complete in nfgaloisconj() 17- type(1/y, RFRACN) --> SEGV + check compatibility before applying type() 18- made 'secure' safer. Confirm before write, prevent from changing 'help' 19- gettime() called the wrong timer(): was reset in debug mode 20- missing case (doubling) in apell1 21- gmod(x, mod) replaced by gmul(x, gmodulcp(gun,mod)) in poldivres [obscure bugs when dividing complicated polynomials with mixed polmods/intmods]. 22- Make sure result is a t_POL before doing a setvarn in caract2_i() 23- precision problems in ClxModulus (bnrstark()) [check leading term!=0] 24- elltors() could miss some points: determine needed precision first 25- clean up files after an error (not only under GP) 26- divisors(highly composite integer) --> "cryptic" error message 27- 'make clean' wasn't thorough 28- ellpointtoz(e, [0,0]) could correspond to the inverse point 29- "ideals not coprime" in rnfsteinitz BA 30- typo in Configure [CPP] (cc --> CC) BA 31- member functions for galoisinit 32- allowed power series in Mod(). Fixed cryptic error messages. 33- precision problems in zsigne 34- value of 'gzip' found by Configure overwritten in TOP_Make.SH XR 35- precision loss in Round 4 XR 36- ensure that fundamental unit is computed in quadray (if D > 0) XR 37- precision fixes in stark.c (inconsistencies 32/64 bit + early abort) 38- bug in P*Q for polynomials over (non prime) finite fields if Q is defined over the prime field XR 39- [stark.c]: bugs in RecCoeff3, reduced memory use in ComputeArtinNumber 40- core dump on oo recursion under GP 41- use appropriate precision in torselldoud (could be much too large) 42- removeprimes(addprimes) didn't work 43- (at least part of) numerical instability of LLL over R 44- f() = bug(x, &y) ---> syntax error XR 45- inefficiencies in ComputeArtinNumber for large modulus HC 46- no GC in dirmul 47- meaningless heap count for user functions 48- setrand(16);quadclassunit(48893) --> oo loop 49- rnfpolred(bnfinit(y^2+1),x) --> SEGV 50- float overflow in polroots (e.g polroots(x^3 + 2^1024*x + 1)) 51- charpoly(Mod(1,x^2+1)) --> SEGV 52- added GC in polsturm BA 53- bugs involving rarely used type combinations in generic operations 54- check x >= 0 in lllgramint(x) 55- in rnfdedekind: use rnfhermitemod, not rnfhermite (slooow) XR 56- updated factorpadic to use new Round 4 BA 57- nfgaloisconj: discrepancies between 32/64 bits architectures 58- random(1 << 32) could have 32 bits 59- missing newline in error messages on startup (reading .gprc) 60- silent codeword overflows (e.g. O(x^100000)) IZ 61- updated gnuplot support 62- x="a"; eval(x) --> error 63- general flakiness with buffer handling under GP (Ex: input() + allocatemem --> SEGV) 64- [1] == 2 --> error (instead of 0) 65- lngamma(-0.106) --> SEGV 66- quadray(-11,3) --> x^2 XR 67- typo in nilord2 (wrong value for modular reduction) 68- unsafe division t_SER / t_SER with clonable components 69- polroots(1E-28*I*x^2+1) --> bug in roots (conjugates) 70- typo in cxlngamma [ lngamma(-7.4927-0.418564*I) --> SEGV ] 71- polroots(polynomial of very small Norm wrt prec) behaved badly (SEGV) 72- polylog(1, Mod(1,2)) --> SEGV 73- zeta(22!/23) --> SEGV 74- not enough GC in rnformax 75- over-reactive 'secure' default (+ moved it later in default .gprc) 76- sqrt(Mod(15,y^2+1) + O(x^5)) --> SEGV BA 77- typo in isinexactfield 78- sum(x=1,10, expr1; seq) : seq silently ignored 79- ellan and elltaniyama didn't check their arguments 80- simplify(t_POLMOD) could create invalid objects (mod not a t_POL) 81- primes(-1) --> SEGV 82- addprimes(0) wasn't rejected 83- various inconsistant error bessages (e.g. factor("a")) 84- estimate for the precision of unit embeddings in isprincipalall 85- global("b") --> polvar corrupt 86- hnfmod --> hnfmodid whenever possible 87- check arguments in incgamc 88- non-rectangular matrices could trigger a SEGV (in error msg!) 89- qfminim(,,2) didn't like mixed t_REAL/ t_FRAC entries (typo) 90- inconsistant spacing after GP error messages 91- regrouped code between idealred and idealmin 92- prevent 'install' in secure mode DS 93- typo in bnfisnorm(,,flag > 1) [extraneous gtrans] 94- don't reset pariErr in err_recover() 95- highlevel.c had become dependent from gp.c XR 96- incorrect output of quadray(D,,1) when D>0 and rayclass is trivial 97- typo in lllall_trivial --> matkerint([0;0]) didn't work BA 98- incorrect object for gerepileupto in gscalcol 99- try to detect bad input (e.g quad. form not > 0) in (integral) LLL XR100- typo in nffactor ("keep the value of i") IS101- work around an obscure gcc bug (gcc-2.96, alpha-linux) in stark.c 102- rnfcharpoly(nfinit(y^2+1),1,1) --> SEGV BA103- tan(t_COMPLEX) gave bogus result BA104- trace([;]) --> SEGV Added IZ 1- [gnuplot] look up directory tree for gnuplot related files 2- improved on-line help wrt to defaults and ambiguities (? default/some_default, ? some_default) 3- library functions gentimer, genmsgtimer, get_timer HC 4- optional argument to direuler (length of result) 5- low-level kernel function for integer squarings (twice faster) 6- error trapping in library mode and under GP 7- break loop to investigate errors under GP 8- "sprintf-rounding" under GP IZ 9- string justification in high-res plot IZ 10- bit operations ( bit[ and | or | neg | negimply | xor ] ) XR 11- add new flag value in bnrstark/quadray: try to find a better modulus 12- Configure flags to indicate where gmp/readline library/headers are to be found Changed 1- default binary produced by Configure -g is now static 2- improved the heuristics in ellisoncurve HC 3- extend the range of direuler (maxp was 2^16) 4- trial divide by the "private primes" before the primality tests 5- don't double stack automatically 6- disable ff_poltype correction (for lack of decent finite fields) in gmul 7- slight optimization to hnf / hnfmod (skip zeroes) XR 8- nfsqff: choose a prime ideal with few factors + better heuristic bound IS 9- default CFLAGS on linux-alpha 10- improved factorcantor / factorff 11- default multiprecision kernel is GMP if the library is installed Removed 1- sunview "support" (didn't work, hard to test, X11 is a better standard) =========================================================================== Done for version 2.0.17.beta (released 24/09/1999): Fixed XR 1- typo in zarchstar (result possibly incorrect when more than two places) 2- check_unit not severe enough ([;] --> session could die !) 3- wrong error message when using global var as argument to user function 4- typo in boundfact(t_FRAC) --> SEGV 5- buchall: don't compute xarch if not needed 6- remove limit on string size + silent overflow, e.g Str(10^5000) 7- "break status" not checked often enough: [break, 1] --> SEGV 8- rewrote errcontext (use print_text to fit messages on terminal) BD 9- added workarounds against some MSVC annoyances (Windows version) IZ 10- typo in Gnuplot.h 11- typo in Configure ("2>&1 >/dev/null" replaced by ">/dev/null 2>&1") 12- simplified incgam[23] + typo (mulrr --> gmul) IZ 13- typo in LD_LIBRARY_PATH setting (benches) 14- inconsistency in gadd(0., FRAC) (should give 0. if FRAC small enough) 15- libraries/headers ordering inconsistent in Configure (report: IZ and KO) 16- typo in ff_poltype [symptom: (Mod(1, y^2 + 1)*x + 1)*x --> garbage] 17- qfbprimeform(4, [2]) --> SEGV 18- overflow in factorcantor(2*x^3+3*x^2+x, 2^31-1) 19- memory corruption in apell1 + no garbage collection, rewrote the function to parallel apell0, replaced hashing by sorting, use Montgomery's trick, removed the p < 10^25 limit IS 20- cc -64 warning in mp.c:vals() 21- bad free in gp_expand_path 22- extract([;], "..") --> SEGV 23- not enough GC in hnfall 24- recover gracefully when precision too low in lindep/algdep IS 25- cleaned up unused variables, fixed some missing casts 26- algdep(x) --> undefined behavior when x exact. Replace by decimal approximation IS 27- C++ keywords (new, class) occurred as variable names 28- arguments of ideallistarch not checked 29- Mod(t_FRAC or t_PADIC, t_INT) --> garbage 30- gcmp1(t_REAL) always false: polylog(2, 1) --> error 31- (spurious) compiler warnings about variables used before initialization 32- memory (possibly) freed twice in buchall + unsafe allocation of matcopy 33- online help for matsnf not updated 34- rnfequation() didn't check its arguments correctly 35- removed spurious special case in compute_class_number() 36- typo in the compatibility macros mpabsz / mpnegz (missing ;) 37- "lost pointers in gerepile" in bnfisprincipal(Q, ...) 38- bnfisprincipal(..., Pol(0)) accepted 39- [Configure] Makefile name didn't necessarily match object directory 40- zetak(nfz, integer + 0.) --> stack corruption 41- for(i=1, ..., zetak(nfz, any complex number)) went slower and slower 42- poltchebi(.,y), pollegendre(.,y) didn't work 43- confusing "array index out of allowed range" message (e.g [1-0]) IS 44- fixed obscure compiler optimization bugs in smithall() and eint1() GN 45- weird results in ellisoncurve() due to misguided precision heuristics 46- typo in forvec([],...): readexpr() --> readseq() 47- check arguments in ploth() XR 48- rare bug in bnrL1 (wrong value!) 49- precision problems in polredabs 50- division by 0 in rnfordmax [typo in mymod()] 51- removed all dangerous occurences of constpi/consteuler (cf 41-) 52- typo in det() [forgot to divide by a pivot] 53- divide by 0 error in lllgramintern (precision problem) 54- suminf(k=1,suminf(j=1,.067^(k+j)/k^4/(k+j))) ran forever 55- factor(2*x + 2) --> [2*x + 2, 1] (instead of stripping the content) 56- (ultra-rare) stack corruption in mpqs_solve_linear_system() 57- rl_refresh_line() prototype changed across readline's versions 58- incorrect handling of INTMODs modulo integers of different magnitude XR 59- matsnf(3 x 3 matrix, 4) --> SEGV 60- some pathological bnfinit() computations (strive to get maximal rank) XR 61- precision problems in nfsqff() [increase precision for T2-norm bound] 62- time wasted checking generators of the form [x,0,...,0] in polredabs 63- variables deleted too late in freeall() Changed XR 1- modulus choice in bnrstark 2- make sure that addii(x,y) returns gzero, not icopy(gzero) 3- cutoff in ellap to use Jacobi sums (457 --> 100) 4- pariputsf("%Z",(long)g): removed the casts (not needed) 5- cleaned up hnfspec 6- look for at least MIN_EXTRA extra relations in buchall 7- simplified calling interface to hnfspec/add 8 Used hnfspec in bnfsunit, changed the way S-units are found 8- output of bnfsunit modified (removed res[3], made res[2] suitable for hnfadd) 9- listput and listinsert now return the inserted element, not the list 10- check_break_status rewritten: was very inefficient 11- Used parser code DG whenever it was possible (moved reorder to init.c) 12- faster isunit() 13- added GC in expr() 14- buchall(): increase subfactorbase without starting over GN 15- minor tuning in pollardbrent() for huge integers (call ECM sooner) 16- renamed directories dos -> Odos, o.xxx.xxx --> Oxxx. Moved win32/* --> Odos OR 17- new version of pari.el XR 18- new modular round 4 implementation (nilord2) BA 19- improved algorithms in galconj.c Added 1- an optional argument to next() 2- MANIFEST YU 3- support for FreeBSD ELF binary format 4- file CVS.DOC 5- support for Windows CE (Nigel Smart + coworkers) BA 6- functions related to Galois theory: galoisinit, galoisfixedfield, etc 7- [library] trivial function realun() Removed 1- #define HIGHBITM1 (useless) 2- files config/tar_[include | exclude] (obsoleted by MANIFEST) =========================================================================== Done for version 2.0.16.beta (released 29/06/1999): Fixed 1- paricfg.tex (needed to compile INSTALL.tex) missing if Configure is not run. Added a test in parimacro.tex 2- non-portable casts in galconj.c 3- 64-bit graph benches (extra spaces) IZ 4- typos in plotgnuplot.c 5- unnecessary plothsizes in "graph" bench (fails if no X server) 6- typo in ff_poltype IZ 7- check rectwindow in rectcopy and rectclip IZ 8- /opt/local/lib missing in Configure's library path IZ 9- [Math::Pari] needs pariErr->die _before_ pariErr->flush IZ 10- wrong valence code for plotcolor, plotclip IS 11- obscure inlining bug (pgcc 1.1.3 -O3) in stark.c:ComputeKernel0() 12- gcc -E doesn't define __GNUC__. Add it explicitly to KERNELCPPFLAGS 13- whatnow(sigmak) didn't tell the arguments have been swapped 14- [1]~ * [[1]] --> SEGV 15- lim=(av+ x * bot) >> y can overflow if large addresses are available (e.g Linux...). Use lim_stack() instead 16- algdep(I,1), lindep([I,1]) entered an oo loop 17- removed the maxHastad (= 50) limit in algdep/lindep 18- typo in polrootspadic(,,1) --> SEGV 19- GC not frequent enough in idealval 20- in split_ideal (isprincipal), LLL-reduce first if ideal is big 21- factorpadic(,,,1) didn't work anymore 22- round 2 (= nfbasis(,2)) used too much memory 23- idealval did not accept all types of ideals GN 24- unsafe stack handling in auxdecomp 25- polroots[mod|padic] returned a t_VEC, not a t_COL (as polroots) 26- check coeffs of polynomials with coeffs in nf (rnf* functions) 27- typos in polredabs0 (get_Bnf + nf_RAW in storeallpols) BA 28- nfgaloisapply could forget to clean up the stack 29- typo in gp_rl.c (rl_save_prompt <--> rl_restore_prompt) DE 30- arch="sun4" non reconnu par Configure 31- uninitialized variable (prec) in quadhilbertimag IS 32- pari.el.in was not updated when gphelp was moved from miscdir to bindir 33- rnfkummer(bnrinit(bnfinit(y^2-y-1),101,1),[1,0;0,2]) --> gerepile error IZ 34- update gnuplot interface a) Strings were put too low in gnuplot terminal; b) Allow setting of output file sizes, as in plotterm("gif=300,200"); c) Allow querying of possible output terminals, via plotterm("?") d) Update to newer Gnuplot-interface-layer (Gnuplot.h) allows compilation on Linux (stdout was bad as an initializer), corrects bugs in processing of terminal options 35- in buchall, allow minfsb to increase before doubling cbach (bnfinit(x^4+5*239*x^2+5*239^2) couldn't be computed) 36- bnfnewprec can't handle bnf = bnfinit(,2) --> SEGV (now, error) 37- typo in pseudorem (didn't recognize 0 properly) GH 38- weird bugs in thue() on alpha: typo int <--> long in thue.c 39- bnrisconductor assumed moduli had small norm (< VERYBIGINT) 40- bnfnewprec didn't accept imaginary quadratic fields ("missing units") 41- inefficiency in zarchstar (VERYBIGINT --> BIGINT) (rnfconductor(bnfinit(y^3+972*y-12),x^2+x+1) ran forever) 42- too much memory used in rnfordmax (+ removed some inefficiencies) 43- try to recover in nffactormod if input not prime (SEGV) 44- SEGV in nffactormod if degree(pol) > 100 45- factornf(p(x), q(x)) was accepted (and produced incorrect objects) 46- nfisincl / nfisiso made use of the bug above 47- subgrouplist(bnr) with trivial ray class group --> SEGV 48- background color was assumed to be "white" (by gphelp and gp) Made it "transparent" by default 49- pages shifted by 1 in User's Manual's table of contents 50- Mod(x, x^2+1) + x return Mod(2*x, x^2+1), not x + Mod(x,x^2+1) (fixed gadd, gmul, gdiv) 51- for certain flag combinations buchrayall unsuitable for gerepileupto (+ cleaned up the code) 52- ^C in smithclean corrupt existing objects 53- silent overflow in qfbhclasso 54- nfreducemodpr didn't check its arguments 55- confusing error messages when precision too low in initell 56- polx[0] modified in nfsubfields(P(y)) 57- various memory optimizations in bnrstark 58- incorrect debugging output in calc_bloc (at \g6) 59- rare memory corruption when garbage collecting in mppgcd 60- type t_STR not treated correctly in changevar 61- C-long overflow in ellan 62- memory use in the incgam* functions 63- bad input bug: qfperfection(indefinite matrix) --> SEGV 64- mateigen dropped some eigenvectors when precision was too low Changed 1- err() --> parierr() [conflict with system library in Redhat 6.0] 2- use Doud's algorithm in elltors [initial patch: HC] 3- new (internal) function get_mul_table (for nfinit, padicff) 4- disable LD_LIBRARY_PATH before running benches 5- strtoGEN() --> strtoGENstr() + added flag 6- optimized stack usage in pollardbrent (in place) 7- don't try to compute units in buchrayall if bnf doesn't contain them 8- simplified misc/gprc.* (esp. colors) 9- use C long to keep track of exponent in regula 10- src/kernel/sparcv7/level0.s --> level0.S + include preprocessing stuff 11- extended matsnf flags: immediate cleanup (backward compatible) 12- arguments swapped in veceint1 13- allow @ markers (??keyword@) in extended help (was apropos only) 14- do all computations in mppgcd in place (as in Changed-6) OR 15- new pari.el (cf emacs/pariemacs.txt) 16- search multiple lines in apropos extended help (???key) Removed 1- make test duplicated the "make bench" computations. Removed the test and dotest targets 2 -veceint1() function. Can be reached in library mode or using a flag to eint1 Added 1- default 'secure' 2- optional flag to Str() 3- expand environment variables in filenames 4- TODO file 5- man page for gphelp 6- Trivia section in the pari/gp man page =========================================================================== Done for version 2.0.15.beta (released 21/05/1999): Fixed 1- ?? (TeX mode) didn't work anymore 2- rl_save_prompt incorrectly detected on a.out systems 3- allow extra_relation() (bnfclassunit) to abort 4- allow cbach to double once more before triggering PLEASE REPORT (introduced in 2.0.14) 5- check for non-monic pol in smallbuchinit 6- vecex --> SEGV on some Linux systems (typo in match_concat) 7- exceedingly rare but possible overflow in forvec(, flag == 1) 8- factorff(x^7-3,3,y^3+2) --> SEGV DC 9- ghpelp doesn't exit when problems arise in TeX processing 10- made idealprimedec random again (also use det_mod_P_n to compute norm) 11- inefficiencies in nfeltval (computing norm is a waste of time) 12- did same prime twice when collecting garbage in modulargcd (=> error) 13- ffinit(huge prime,) output a weird error message 14- highly inefficient memory use in nfsubfields IS 15- [cygwin] typo in Makefile generation 16- file leak in mpqs (COMB) 17- allow prime_to_ideal to be called with a t_INT argument (for quadray) 18- typo in nf_shanks (calling Fp_shanks with wrong parameters) 19- polun (possibly) destroyed in bnrstark IS 20- keep logfile in synch with screen output 21- reset DEBUGLEVEL correctly on ^C (was sometimes set to 0) 22- bnrstark does not require anymore the modulus to be the conductor 23- check bnrstark's arguments in the right order (bnrstark(1,0) --> SEGV) 24- inefficiencies in idealval (removed element_mulh) 25- idealadd unsuitable for gerepileupto HC 26- quadray should work in all cases now and give better polynomials XR 27- bnrstark should return smaller polynomials 28- very inefficient pseudo-remainder routine (psres) 29- forstep(x=a,b, 1/2, ...) --> SEGV (signe -> gsigne) IS 30- [Cygwin] Configure fix (use $HOSTTYPE instead of uname -m) 31- polcoeff(a*x^-1*y^-1+O(x^2)+O(y^2),-1,y) --> 0 HC 32- (false) accuracy problem in mpsc1 ("truncation error") 33- don't use mpqs_diffptr in mpqs_find_k, set it in mpqs_create_FB 34- (very rare) "precision loss in truncation" in buchall 35- C-long overflow in zarchstar 36- C-long overflow in zprimestar 37- (old versions of) GNU as not recognized correctly BA 38- ?? in TeX mode could not process some sections (missing macros) 39- factor(polynomial with t_PADIC coeffs) didn't work (factorpadic assumed coeffs were integers) 40- T=[1,x; x,1]; charpoly(T,Z) produced object with wrong variable ordering 41- polrootsmod(x^n,p) could corrupt the stack 42- Warnings/errors from HPUX and AIX native compilers OR 43- many problems in the emacs interface pari.el (introduced in 2.0.14) 44- factorpadic treated only monic polynomials 45- gphelp TeX mode (use general macros instead of a specific file) 46- under readline, input lines of length > 2048 could trigger SEGV 47- more thorough check in checkbid (accepted prime ideals->SEGV) GH 48- possible stack corruption in thueinit(totally real field) XR 49- various problems in bnrstark (oo loop in fincke_pohst) 50- in doc/Makefile: removed GNU-style make macros + put a missing TAB 51- sloppy garbage collecting in hnfperm 52- HPUX+cc: work around a compiler bug (wr_float) 53- warnings in make_emacs_tags (perl5.005) 54- Configure --static should not disable install() 55- in rare cases reduction not complete in lllgramall (off-by-1 error) 56- addshiftw (polynomial case) could produce non-normalized polynomials 57- take content into account in modulargcd as in srgcd (not normalized) GH 58- uninitialized variable in poldisc0 (purify warning) 59- inefficiencies in round 4: modular computations [more needed!] (starting from a patch by DF+XR) GN 60- lllintpartial did not output the right matrix 61- huge memory leaks in bnrstark 62- signed int overflow in allocatemem 63- parisize (local to gp/gp.c) not updated properly 64- *sol not properly initialized in subresall 65- in idealpowred, check whether |n| < 16, not n < 16 (would slow down bnfinit a lot when class number is large) 66- polrootsmod(x^6-10,25) --> SEGV (now error message) 67- SEGV when renormalizing zero series in gdiv XR 68- unify precision choice in bnrstark (4 different formulae used...) GN 69- oo loop in mpqs (64bits machines + harsh compiler) when more factors were found than were hoped for (1 <--> 1L) GN 70- SIGFPE in buchall (double didn't fit in 32-bit integer) 71- also check sign in real0 (internal: called by gauss_pivot) 72- use current realprecision in plot() (was fixed: 28 digits) 73- memory use in subgrouplist(bnr) 74- in bnfcertify: "Too many iterations in isprincipal" 75- auto detect precision in quadhilbertimag ("overflow in I+R") 76- error message numbers in src/kernel/m68k/mp.s 77- polroots(x^3-x-422!) --> "impossible R-> dbl conversion" 78- not enough modular reductions in buchrayall (bnrinit) 79- technical argument in quadclassunit not read correctly 80- factor(x^3-1 + 0.*I) --> gerepile error GN 81- gp -p (close to a p^2) --> p possibly missing in the prime table 82- until narrow class group in quadclassunit is implemented, non-zero flag raises an error IZ 83- some code numbers in functions_basic (for Math::Pari) 84- precision problem in initell (AGM) 85- "impossible assignment I-->S" in ellrootno 86- missing break in poltype (factor) Changed 1- ?? (no arguments) opens the users'manual in xdvi 2- print readline version in header on startup 3- compute multiplication table first in element_mulvec[row] 4- nf[5][7] is now stored in two-element form (faster ideal inversion) 5- install gphelp in BINDIR, not MISCDIR 6- simplified output of trivial matrices 7- replaced square_free_factorization by mysquare_free_factorization 8- call LLL before using idealtwoelt GH 9- choose random elements in idealtwoelt, and allow bigger ones in two_elt 10- cleaned up lllgramall/lllgramintern + give quality ratio as argument 11- in rnflllgram, try to survive lllgram errors (findmin) 12- simplified rnfpolredabs (simple interface to polredabs). Should be much more efficient 13- replace many gdiv by 1 ginv + many gmul in sqred1intern 14- optimized polredabs (always do the initial polred now: it is for free) 15- more efficient ideal multiplication in random_relation (bnfinit) 16- library names nfhermite[mod|basis] <--> nfhnf[mod|basis] 17- subgrouplist function (use Birkhoff algorithm) 18- improve recovery in lllgramintern 19- improved checkgenerator in polredabs (look directly for double roots) 20- for consistency, return S-units in t_POL format (as fundamental units) IZ 21- revamp gnuplot autodetection by Configure BA 22- nfgaloisconj(nf, 4) uses Allombert's algorithm instead of Kluners's Added 1- install-doc target 2- make install makes a symlink pari.1 --> gp.1 3- ??tutorial/refcard opens tutorial/refcard.dvi in xdvi 4- posibility to extract the complement in vecextract HC 5- Ducos's subresultant algorithm (polresultant(,,2)) HC 6- accept a "vector of steps" in forstep 7- examples/classno.gp XR 8- new function bnrL1 9- new function gdivexact (used in subresultant, Gauss-Bareiss...) 10- new function bnfnewprec 11- optional argument to \l and \e shortcut 12- nfinit,polred[abs] accept input of the form [pol, HNF basis for Z_K] 13- q-Pascal triangle (matpascal(n,q)) 14- file src/basemath/subgroup.c, new function forsubgroup() IZ 15- function plotclip IZ 16- new file examples/taylor.gp (nice example for plotclip) BA 17- new file galconj.c =========================================================================== Done for version 2.0.14.alpha (released 05/03/1999): Fixed 1- factormod(2*x+1, 2) --> "factor for general pol. not implemented" IK 2- gphelp could leak temporary files BD 3- for native Win32 build: buffer overflow in get_home, incomplete paricfg.h, typo in try_pipe (#endif misplaced) 4- nfsubfields: could miss subfields if index > 1 5- removed 3 useless setrand(1) in subfields.c 6- rare and obscure memory bug in inverseimage (lost pointers in gerepile) 7- memory bug in factorpadic4 (prime not copied before result) 8- memory consumption in round2 (allbase) GT 9- m68k version: duplicate symbols from mp.c IS 10- Cygwin: in mpqs.c, open files in binary mode (otherwise fseek goes crazy) 11- bnfisprincipal().gen gives the expected answer IZ 12- signatures for Math::Pari in highlvl.c / init.c + GNUPLOT set-output-file problem 13- if we think readline needs libiberty, check whether it's installed first DB 14- PowerMac: header inclusion in highlvl.c, lround def'd in system headers XR 15- rnfkummer makes sure to return an integer XR 16- rnfconductor accepts polynomials with rational coeffs 17- polredabs + internal precision change --> nfnewprec forgets nf[5][1] 18- don't log lines twice when pariecho is set 19- glitches in content() (e.g content("a") --> SEGV) 20- get_sep(2) reacted incorrectly to empty strings 21- rootmod could destroy its argument 22- Fp_pow_mod_pol(x, 1,...) should return gcopy(x), not x 23- galoisconj1 computed wrongly the precision needed (+ prototype change) IZ 24- remove __OPTIMIZE__ dependence (define GCC_INLINE instead) 25- off-by-1 error in apell1 26- misleading error message in minimalexponent() XR 27- in nffactor, forgot to update precision when increasing exponent (+ various typos) 28- sparc + non-gcc --> kernel2 possibly not included: compilation failure 29- when echo is set don't print prompt if line is empty 30- ellpointtoz sometimes return -x instead of x 31- gp -b 1 --> hangs gp DE 32- many glitches in manual 33- mathnf(x, 3) when x hasn't maximal rank (SEGV) 34- differences in buchall 32bit/64bit (PRECREG too high. bnfinit(x^13-6)) 35- various inefficiencies in nfshanks ("module too large in nfshanks") 36- memory leak in buchall (= bnf*) 37- "not a definite matrix in lllgram" after a call to bnf* 38- typo in factorff(x^3+2,3,y^2+1) --> SEGV 39- [internal] missing tags (e.g zprimestar) after make ctags 40- idealstar(*, big prime) --> cryptic error msg (more tolerant now) 41- have Mod(0,1)^-1 return Mod(0,1) (fixes znstar(prime)) 42- ginv(-1/2) --> 2 43- heap leak when using local() 44- overflow in addssmod 45- changed the syntax of round() 46- sqrt(1. + O(x)) --> oo recursion IZ 47- don't create GP variables when expanding strings 48- internal variable 'parisize' not properly updated after allocatemem() IS 49- config/display didn't work properly with ActivePerl IS 50- Configure didn't handle most recent Cygwin 51- polinterpolate([],[]) --> SEGV 52- adapted gp_rl.c to readline 4.0 53- glitches in whatnow database (new file src/gp/whatnow.c) 54- all warnings from gcc 2.8.1 55- uninitialized tetpil in gscal() (bnfreg(x^2+1)) 56- precision problems in polgalois (degree > 7) 57- config/locatelib prompted a lot of useless work (returning too many libraries) and could pick up the wrong library 58- very rare bug in nfbasis (discriminant ok, but wrong basis) 59- quadclassunit: make sure sub factor base is big enough (oo loop) 60- more flexible "colors" default (initial work IZ) Changed 1- x.fu outputs polynomials (as all bnf* functions), not polmods 2- improved mppgcd (including vali) 3- improved division vector/scalar 4- \x to print a * in front of out-of-stack moduli (t_[INT|POL]MOD) IZ 5- better commandline usage message 6- don't buffer log messages going to pari.log 7- accept [nf, t_POLMOD] where nf is expected 8- poldisc() and quadgen() accept an optional variable name 9- when defining user function check for duplicate variable names 10- [internal] is_entry always uses function_hash (use is_entry_intern) OR 11- pari.el updated (see emacs/pariemacs.txt) 12- removed shiftl from lgcdii 13- use roots_to_pol in polgalois 14- precision heuristic in gauss_get_prec 15- cleaned up lllall and lllgramall 16- sort the output of nffactor, nfroots, factorff and factornf 17- nfgaloisconj now guaranteed to find all conjugates (use nffactor) 18- Removed flag 1 in nfisisom/nfisincl: function checks its arguments, and uses the best algorithm (both guaranteed complete). Changed the names (nfiso/nfincl) in library mode to match GP usage 19- gerepile(ltop,lbot,0) no longer returns ltop - lbot 20- improved floor and round(t_FRAC) 21- removed some duplicate code from nffactor 22- passing a pointer to GEN in a GP funciton now explicitly requires an & IZ 23- more verbose error messages for online help 24- increased a bit poltschirnaus's period 25- DOS version: don't use more for external help 26- cleaned up buchall code 27- removed unnecessary gres from polarit1.c:to_fq() Added 1- apropos command in gphelp (-k switch), ??? under GP 2- function global() 3- function gp_variable to use sums, etc in library mode 4- [internal] new functions mulmat_real 5- new functions gerepileupto[leaf|int] 6- function znlog() IZ 7- added default(color, "yes" / "no") 8- --static flag to Configure GH 9- inline alpha assembler (gcc specific) Removed 1- isinclfast/isisomfast 2- rounderror =========================================================================== Done for version 2.0.13 alpha (released 14/12/98): Fixed IK 1- Configure hangs on FreeBSD systems RD 2- Roland's patch (2.0.11: Fixed- 42) had been incorrectly applied 3- stack corruption in glcm (if operands > 10^155) 4- index wrap-around in polsubcyclo (n > sqrt(2^31)) 5- incorrect placement of strings in psdraw 6- memory corruption in rhoimag0 7- fix up memory debug mode (\gm) when switching to alternate stack 8- memory corruption (new_chunk + mulii) in gmul/gdiv (t_FRAC) 9- escape chars in GP strings sometimes parsed twice (e.g Str("\\") --> "") 10- nfinit(x^18+16) --> impossible inverse mod(0,2) (bug in eltppm() introduced in 2.0.12) 11- weird SEGVs due to variable handling (changed the 'bloc' structure) 12- moved highlvl.c to src/gp (libpari was missing symbols from plotport) 13- polcyclo ignored its second argument (introduced in 2.0.12) TP 14- minor fixes in paridecl.h (poldivres, gredsp: C++ compiler exits) HC 15- still sign problems in resultant (see 2.0.12: Fixed-58) 16- (Solaris):GNU ld doesn't like empty object files: remove kernel2.o IZ 17- make bench forgot to treat the install() BUG in a special way 18- factor(x^2 + I) --> SEGV (also with t_QUADs) 19- factornf(x^3+1,y^2-1) --> stack doubling (now output error msg) IZ 20- for Math::Pari fix valence of factormod() IZ 21- outfile rename pari_outfile (conflict with gnuplot headers) 22- DEBUGLEVEL could be modified and not reset upon interrupt IK 23- make perl -wc gphelp happy 24- incorrect use of gettime() in the library (nffactor) --> wrong timings (in particular for the 'nfield' bench) 25- polred/polredabs used different types for output. Made both t_VEC 26- remove duplicate polynomials in polredabs(x,4) and polred XR 27- precision fixes in modules/[nffactor|stark].c 28- in compatible mode, \precision didn't work anymore 29- typo in Round4 (case "p small" and "p huge" were swapped) 30- incorrect prototype for conductor in compatible mode 31- factor((x^2-1)/2) --> SEGV (factpol assumed integer entries) 32- memory usage in Round2: nfbasis(*, 2) (also cleared some inefficiencies) IK 33- typo in primitive_pol_to_monic 34- deplin did not check its arguments 35- quadray() assumed variable "y" was not in use Changed 1- glength() returns a C-long integer 2- in hnfmodid(x,d) reduce mod d immediately 3- allow vector(n), and matrix(n,m) (filled with 0s) 4- under GP, wait for input if line ends with '=' (cf \) 5- wait for input when a line ends with an '=' sign 6- modified extended help to (potentially) search the whole manual 7- in nfdisc, specific error message if discriminant is 0 8- use divide_conquer_prod() in factorback() IZ 9- in test suite, add setrand(1) in front of poltschirnaus IZ 10- M-( bound by default IZ 11- improved gnuplot support 12- improved gcmp[1|_1](t_REAL) OR 13- new pari.el (see emacs/pariemacs.txt) Added 1- members e, f, p, gen for prime ideals 2- mathnf([M, M2]) computes mathnf(M), updating M2 (equivalent to v=mathnf(M,1) then M2*v[2], but much faster if M2 is small or over a finite field) 3- local() keyword for user function definitions in GP IZ 4- new functions plotfile(), plotpointsize() IZ 5- splines for ploth (flag 256) Removed 1- \k metacommand =========================================================================== Done for version 2.0.12 alpha (released 06/11/98): Fixed 1- GNU as incorrectly treated by Configure GN 2- various fixes in mpqs.c (incl. file descriptor leak) GN 3- [From 2.0.11- Fixed 14] floating point exponents: 1E1 --> possibly 0.1 4- 1 % Pol(2) still wasn't right [cf 2.0.11- Fixed 31] 5- src/test/dotest for DOS boxes (running sh) 6- removed unreachable err() in factor() 7- system() is defined under EMX, so make it available for DOS 8- possibly use / as path separator under EMX, check COMSPEC and EMXSHELL 9- compatible = 3 downcased all the following lines in gprc and caused incorrect behaviour of preprocessing statements 10- unified default commands + better checks (e.g: default(log,0)->SEGV) 11- memory leak in gp_main_loop: bufferlisit wasn't reset on error 12- gptimer() not initialized properly if ^C was first command 13- extra space (sometimes) output by command line completion in DOS version 14- modifying histsize could corrupt the history stack 15- incorrect error messages in gsqr 16- not enough garbage collection in rootmod (polgcdnun) TP 17- compilation using cc -64 on 64-bit SGI IS+GN 18- "(hit return to continue)" message did not flush stdin GN 18- ECM rewrite 19- incorect absi_cmp in buch3.c 20- useless garbage collecting in sqred2 21- O(1)^(1/2) --> SEGV 22- forvec(i=[],...) --> SEGV GN 23- deriv(x*y, y) --> 0 GN 24- inefficient GC in ispseudoprime() 25- fixed some (not all) compiler warnings (char * --> unsigned char *) 26- exp(too large number) now gives a meaningful error message AW 27- getrusage still not detected on FreeBSD 2.2.5 GN 28- off by 1 error in initprimes() (--> not enough calculated primes) 29- inefficiencies in factor(t_POL) HC 30- bug in rnfelementabstorel for Mod(scalar, t_POL) HC 31- typo in gaussmoduloall 32- idealred(principal ideal) always returned an archimedean part HC 33- idealpowprime wrong for negative powers 34- typo in binomial(n,k) (wrong answer if n<=k) 35- online help for polinterpolate 36- incorrect garbage collecting in quickmulii/quicksqri 37- reformatted the output in test mode (gp -test) 38- polroots((x-7)*(x-8)*(x+16)) took far too much time 39- ellap assumed ell was given in characteristic 0 IZ 40- outlook of plot function (better labels, better choice of chars) RD 41- when factoring over a non prime finite field and found a p-th power, forgot about Frobenius GN 42- rare memory bug in ellfacteur 43- gscalmat was not suitable for gerepileupto 44- polredabs(,2) didn't handle non-monic polynomials 45- check for various overflows (x ^ 1000000, etc.) 46- printtex(I) --> missing closing brace 47- setisset() did not check that elements were strings 48- typo in gdiv(t_POLMOD, t_POLMOD) with different variables KO 49- missing ; in level1.h (Windows specific code) 50- forprime(p=0,10,) indeed started at p=0 51- (cf 2.0.11 Fixed-1) put back 3 cgeti in galois.c (were necessary) 52- factorpadic could overstate the precision of the result 53- (very) rare memory corruption in allhnfmod (when cleaning up) PM 54- prototypes in paridecl.h (fussy IRIX compiler), cc -64 in MACHINES 55- factormod implemented for all primes (p = 2 and p > 2^31 called factorcantor which was much slower) 56- check for unsuitable input in [factor|roots] (SEGV for multivar. pol) 57- polresultant sometimes gave the wrong sign 58- extraneous space in err(impl,"") (= "sorry,... not implemented") 59- aliases treated incorrectly during error recovery (--> obscure bugs) 60- obscure bug when normalizing rational functions with real coeffs (corrected content()) Changed 1- paricfg.h in dos and win32 extracted by Configure before the release (to get version number right) 2- GPRC logic: try $GPRC, then look in $HOME, /etc (/ and C:/ under EMX) 3- make sure the output of pari_unique_filename() doesn't exist already 4- use a stack of files to gracefully handle errors/interrupts without leaking file descriptors 5- replaced fixed-size buffers by dynamically allocated ones (es.c/gp.c) 6- rename INSTALL.QUICK --> INSTALL.DOC (updated) Changelog --> CHANGES (looks better under DOS) 7- mention ?12 in the header 8- use ; (instead of :) as PATH separator under DOS, OS/2 or Windows (for drive letter) GN 9- ECM tunings 10- check for overflow in cget* (instead of silent wraparound) 11- gp_main_loop cut into (improved) pieces 12- simplified normalizepol 13- Warn when trying to replace an existing function with install (previously error) 14- new function mpcopy. replaced some inlined function (rcopy, absi, absr, negi, negr) by compatibility macros 15- gphelp now uses GPDOCDIR and GPTMPDIR 16- improved rational arithmetic by computing smaller gcds (gredsp removed) GN 17- improvements in MPQS (use less memory, count relations precisely) 18- text-mode (non-TeX) extended help printed screen by screen 19- retuned integer multiplication, and made polkaramul the default polynomial multiplication XR 20- stark.c rewritten IZ 21- updated the pariperl interface 22- improved handling of t_INTMODs (less GC) 23- improved (a lot) factoring/root finding for intmod polynomials 24- modified poldivres to avoid computing remainder when useless 25- removed inefficient shiftl/shiftlr from the kernel 26- from the same sources, Configure can now simultaneously run on different architectures 27- polynomial factorizer now sorts the factors (increasing degree) 28- ?an_obsolete_function now calls whatnow 29- .pol operates also on t_POLMOD 30- random() argument can have arbitrary length IZ 31- with gnuplot, pick a sensible terminal when X11 is not around IZ 32- change valences for use with Math::PARI IZ 33- various interface patches (new file highlvl.c, different prototype for foreignAutoload...) 34- optimized permute() 35- setrand, getrand, getstack, gettime return a C long, and not a GEN 36- pari_randseed no longer global. Don't reset random number generator when entering certain functions 37- improved smallvectors() (correcting the "not enough storage" bug) 38- improved computation of special polynomials ([sub]cyclo,tchebi,legendre) 39- read() and extern() are timed as a whole now 40- check if LONG_IS_64BIT is correctly defined in pari_init (in case we include the wrong pari.h) GN 41- use Lehmer-Jebelean to compute inverse mod p (TODO: extended gcd) 42- moved subcyclo() to bibli2.c 43- improved polredabs, suppressed flag 8 44- improved ground(), case t_REAL 45- modified the internal SMALL nf structure (add matrix M, for polredabs) Removed 1- doc/Makefile.SOS, since make should succeed even if Configure failed 2- many error messages from the analyzer (referer*, trucer1, matvecter...), better handled by talker2 3- obsolete test %_ in bench 4- polkaramul(), which is now the default multiplication 5- factmoder error message 6- obsolete function polredabsfast Added 1- `pipes' for DOS running EMX, i.e extern() and extended help are available (perl needed for the latter) 2- file handling functions pari_fopen, pari_fclose, pari_unlink 3- new default `debugfiles' 4- file README.DOS IZ 5- target etags in top Makefile 6- target ctags IZ 7- gnuplot support HC 8- elliptic functions package (ellzeta, ellwp, ellsigma) HC 9- quadray function, extending quadhilbert 10- files src/basemath/polarit3.c and src/gp/highlvl.c 11- user-defined member functions 12- possibility to choose sizeof(long) at Configure time when the hardware suports it (eg. MIPS) =========================================================================== Done for version 2.0.11 beta (released 30/07/98): Fixed 1- removed all dummy cgeti (--> new_chunk) 2- stack corruption in gcarreparfait (t_INTMOD) 3- incorrect Fq-loop in apprgen9 4- removed useless normalize in gdivgs, gdiv 5- some {} Warnings from gcc -Wall (unjustified, but doesn't hurt) 6- incorrect zero series return by deriv 7- gaffsg(, t_PADIC) misused the valuation (symptom: deriv((1+O(2^2))*x^2) 8- online help for ellinit GN 9- default gp built without X11 in presence of some versions of xmkmf 10- ggval: zero series + simplified the code in there 11- subst(O(q),q,x) --> O(q) 12- newtonpoly did not treat correctly zero coefficients IK 13- getrusage incorrectly detected (at least on Linux/FreeBSD machines) 14- constante() used far too much memory (+ an int should have been a long + an lg should have been an lgefint). Reading in a huge bnf needs much less memory now 15- y[2] checked in divri instead of is_bigint (see 2.0.10, Changed 2) 16- powgi, default case: missing gcopy + incorrect gerepilemany if y==NULL Also, uniformized random GC with gpowgs 17- stack corruption in hil(x,y,p) when typ(x) > typ(y) 18- SEGV if DISPLAY was unset and hi-res routine under X11 is called GN 19- ispseudoprime(negative integer) 20- removed -static from the CFLAGS of profiling version (didn't build) 21- linear algebra routines involving polynomials with real coeffs 22- compiles properly under DOS + EMX GN 23- Warnings from C++ compiler (include unistd.h and sys/ioctl.h where needed) 24- znprimroot(0) --> oo loop GN 25- various fixes in mpqs GN 26- add safety parentheses to macros in paricom.h 27- polroots needed too much precision (two extra words) 28- factor(1. * x + I) ---> rubbish or SEGV (bug in polynomialtype automat) 29- possible address wrapparound in gerepile* (cast to ulong) 30- in gerepile: useless special case for t_SER 31- Pol(1) % 1 returned 1, not 0 32- matdet([x1,1,1/x1; x2,1,1/x2 ; x3,1,1/x3]) returned wrong result (call to gdeuc should have been gdiv in all cases in det()) 33- SEGV in powmodulo (access garbage pointer just before exiting) GN 34- various problems in rho and mpqs Changed 1- simplified detint, fibo 2- simplified GC and optimized gmul: t_SERxt_SER, t_POLxt_POL, and gsqr (same types) 3- streamlined binomial 4- replaced all abusive cmpsi by the relevant egalii 5- prototype for error types [gmuler|gadder|gdiver][fi], assign[ri] using new function type_name 6- uniformized the test suites (make test*,bench,...) GN 7- add random GC in mppgcd. Use modified plus-minus algorithm (new cgcd) 8- format of bench files (to reduce size) 9- cleaned up factor and polynomialtype 10- matdet tries to return a significant 0 when called with a non-invertible argument, e.g matdet([1+O(3),1+O(3);O(3),O(3)]) --> O(3), not 0 11- made the output of make bench/test slightly more informative Removed 1- mpkaramul 2- error messages expter1 and gaffer13 Added 1- misc/gprc.dos a sample gprc for DOS boxes 2- Configure --prefix=dir is now recognized (in addition to -p) =========================================================================== Done for version 2.0.10 beta (released 09/07/98): Fixed 1- integer factoring engine (ECM): sisprime killed N XR 2- file closed twice in MPQS GN 3- bad argument checking in [next|prec]prime BD 4- warnings from MSVC compiler 5- warnings from purify (vpariputs + puissii) 6- sample program and Makefile in examples/ 7- v=...; forvec(a=v, v=...) ==> SEGV LG 8- support for HP running NextStep GN 9- have checkmemory (in cget*) check for overflows LG 10- avoid a bug in cc compiler (version 4.2) under Solaris (in factmod()) LG 11- some missing prototypes and typecasts (for C++) GN 12- add LOCAL_HIREMAINDER in mulssmod (factor(17!+1) => SEGV on some PCs) 13- non portable pari_is_rwxdir GN 14- lots of typos in the documentation Changed GN 1- add debugging output to ECM 2- forvec implementation (+ new flags) GN 3- rewrote the integer factorizer (use Pollard-Brent + improved ECM + new MPQS code from 2.0.9) 4- disabled pari-matched-insert under Emacs 5- reorganized vecsort & co 6- in library mode, classno3 --> hclassno XR 7- improved the nffactor module HC 8- elllseries (use ellglobalred + ellrootno) Added 1- new function in library mode readGEN() HC 2- new GP function ellrootno Removed 1- error message vecsorter2 2- functions vecindexsort, veclexsort (use vecsort with flag) =========================================================================== Done for version 2.0.9 alpha (released 16/06/98): Fixed 1- typo in qfbhclassno (SEGV when result in (1/3)Z) 2- too much memory allocated in factmod /factcantor (use clones) 3- removed the -DREADLINE_LIBRARY hack, use and not 4- version 2.0.8 did not compile with readline 1.* 5- after gaffect(0, padic), padic was unsuitable for further gaffect 6- length(a string) gave number of non code words, not string length 7- factorpadic(polynomial of degree one) did not convert coeffs to padics 8- reduction mod p^r forgotten in gaffsg(s,t_PADIC) 9- default(realprecision,,1) did not return # significant digits 10- typo in nfmodprinit (return x instead of 1-x) 11- matinverseimage did not check its arguments 12- mathess([;]) --> SEGV 13- matid(-100) --> SEGV 14- mateigen([;]) --> SEGV 15- matmultodiagonal([;],Mat(1)) --> SEGV 16- vecextract([;],"..") --> SEGV 17- introduced in 2.0.8 (Added 3-): aliases/user function + ==> SEGV GN 18- (t_RFRAC) ^ t_INT took an unreasonable amount of time 19- prevent quick succession of ^C from corrupting memory in recover() 20- hyperu could enter an oo loop due to round-off errors XR 21- matadjoint(Mat(n)) returned Mat(n), not Mat(1) 22- matadjoint([;]) returned [[;]] (???) 23- wrap some long error messages XR 24- inefficiencies in rnfpolredabs XR 25- nffactor (wrong format for discriminant computation + problems with unseparable polynomials + compute disc only once) HC 26- typos in kummer.c GN 27- check environment variable LINES, not ROWS 28- introduced in 2.0.7 (Fixed 7-): lift(Mod(O(2^0)*x, x^3 - 2)^4) was a zero polynomial with non-zero sign (=> pb when normalizing in poldivres) 29- timer always returned 0 if times() was used (e.g linux-alpha) 30- kill'ing the argument of a user function corrupted the function 31- make clean did not remove pariinline.h 32- incorrect memcopy in identifier, case 's' (removed * sizeof(long)) 33- online help for ?. (nf.nf does not exist) 34- lisseq0: gnil not respected after break/next. avma=av too brutal after return 35- ellwp assumed precdl > 3 36- under emacs, \c + hit return froze emacs (Emmanuel Kowalski) 37- (f()= f()=x); f; didn't set f properly GN 38- comments in anal.c 39- qflllgram([;]) --> SEGV 40- no online help for bernfrac 41- from 2.0.6 (Fixed-8): in padicff2, forgot to raise ideal to power e Changed 1- improved (trivially) gneg (case t_INTMOD), gtopoly 2- use macro is_bigint() instead of tests (ulong)x[2] < VERYBIGINT (led to typos as in Fixed-4 in 2.0.8) 3- improved poldivres by replacing many gsub by 1 gneg + many gadd 4- in pvaluation check for small integer 5- internal function rnfelement_*mod (prhall=NULL instead of gzero) 6- improved mathess 7- added error message "inconsistent data in" in parierr.h 8- gpui[gs] renamed to gpow[gs] GN 9- improved probable-primality tests ('end matching') 10- moved pseudo primality and ECM stuff into ifactor1.c GN 11- raise to an integer power using left-shift binary (new functions powi and powgi) 12- add some details in the online help headers GN 13- nextprime, precprime now accept real arguments TP 14- improved the alpha micro kernel (addllx and subllx) 15- simplified poltschirnaus 16- cleaned up identifier(): #ifdef __hpux__ + call_fun() modified 17- taylor() improved (one gerepile removed) 18- unified the treatment of zero series 19- gerepilemany faster and more efficient memory-wise (copy to heap first) GN 20- improved stack checking in lllgramall Removed 1- global variable defaultpadicprecision 2- function compute_prhall (nfmodprinit is better) 3- function [g]pseudopremier (miller[rabin] better) Added 1- function egalii 2- support for cygwin32 in Configure (Andy Stubbs) 3- new function gunclone to delete a clone (killbloc should be used by the analyser only) 4- comments in anal.c TP/XR 5- new function factorint(), using MPQS (_experimental_) =========================================================================== Done for version 2.0.8.alpha (released 07/05/98): Fixed 1- improved garbage collecting in polroots 2- zetak did not check its nfz argument properly 3- warnings from MSVC GN 4- isprime() did not work for numbers in [2^(BIL-1), 2^BIL-1] GN 5- precprime sometimes missed a prime 6- quaddisc(x in Q\Z) did not always work 7- powering of zero series 8- factorization of null matrices (SEGV) 9- mateigen for non-diagonalizable matrices (SEGV) GN 10- oo loops in some arithmetical functions when arg = big prime GN 11- cleaned up paridecl.h 12- gimag/greal for type t_RFRAC/t_RFRACN (fix: Terje Sparre Olsen) GN 13- ordinal numbers to number components seen through \x HC 14- lllgram: incorrect gabage collecting in first "warnmem" 15- theta(q exact, z) entered oo loop 16- typo in gdiventres (x<-->y in last line) MS 17- gtrunc for p-adics when valp(x) < 0 MS 18- polresultant(u+v,u-v,v) => x + u; polresultant(u+v,u-v) => 2*u MS 19- issquare(Pol), where Pol(0) = 0 IZ 20- use 15 points (by default) for recursive plotting as documented 21- matsnf for singular matrices (supersedes a patch by GN) LG 22- micro kernel support for HPUX LG 23- compilation with Sun's C++ compiler (version 4.2) 24- SEGV when factoring polynomials of huge degree (removed expos[100],etc) 25- garbage collection in gpuigs GN/BH 26- micro kernel support for ix86 running SunOS HC 27- handling of 0x0 matrix in some hnf* functions HC 28- bug in discrayabslist* (try bnrdisclist(bnfinit(y^2-2),200,,1) in 2.0.7) Changed: 1- moved hnf and snf from base1.c to alglin2.c (base1.c too big) 2- use gexpo in linear algebra functions when entries contain real numbers (work for inexact polynomial entries now). Still does not work properly for p-adics GN 3- in sigma() fall back to numbdiv() or sumdiv() when k < 2 4- made comments started in file through read("file") local to file (not so \r file) 5- valuation(0) now returns VERYBIGINT instead of raising an error MS 6- simplified gegal in case t_FRAC IZ/GN 7- faster initprimes, using less memory LG 8- improved Configure Added: 1- new function write1 MS 2- new Lisp-like quote operator 'a IZ 3- readline: electric parentheses, move across balanced expressions, add formal arguments to completion of GP command (when unique) 4- micro-kernel for hppa 5- quiet mode (gp -q) to suppress headers =========================================================================== Done for version 2.0.7.alpha (released 21/03/98): Fixed XR 1- SEGV in get_regulator for imag. quad. fields 2- "beautified" output (still ugly, less buggy, ok for simple objects) 3- error during "print()" could change output default 4- SEGV when syntax errors in gprc 5- make install failed when libpari.$sodest had been removed 6- moved term_width and term_heigth to es.c HC 7- inefficiency in mulii (Karatsuba used too easily) XR 8- many problems in stark.c XR 9- bugs in rnfpolredabs (+ new flag) GN 10- _many_ typos in tutorial and user's manual. New, much nicer, layout 11- whatnow not robust enough + faulty call by err_new_fun ==> SEGV 12- idealadd treated incorrectly the 0 ideal 13- default(realprecision) gave wrong value when format had been changed 14- bnfs structure was inefficient for applications (inverted 2nd comp.) 15- buffersize was incorrectly updated during complicated read() 16- one-line comments "ignored" if buffersize too small 17- using eval on object containing killed variables caused a SEGV 18- contfrac lost last term when first parameter was rational and numerators were supplied 19- problems when dividing with polynomials/series whose leading coeff is non-exact 0 BD 20- missing #ifdef ZCAT in es.c BD 21- check in paricom.h whether min / max are already defined BD 22- universal_constants freed early in freeall() (problems on Windows NT) BH 23- update Makefile.dos (nf.h --> parinf.h) BH 24- changed kernel/ix86/level0asm.c (FUNBEGIN/FUNEND + ALIGN) 25- cleaned the gauss_pivot functions + garbage collecting in gauss() 26- mathnfmod did not check its second argument 27- since 2.0.4 (item 24) install did not work anymore on FreeBSD + gp-dyn 28- cleaner malloc in plotX.c (to remove Warnings when debugmem > 0) 29- slightly optimized matdet (gsub --> gadd(,gneg)) 30- ? x=1; Pol(1) *** variable name expected: x,n, ^--- is fixed everwhere (wherever an optional variable name is expected) setting "x" to some value is now safe IZ 31- nicer looking plot() function 32- warnings while building for m68k arch 33- sqrt(Mod(1,2)) went into an oo loop 34- ?? did not resolve aliases 35- besselk near integers entered an oo loop 36- p-adic sqrt (bad valp) 37- hnfmodid could output wrong results (wrong diagonal) and wreck the powering of prime ideals 38- added garbage collecting in izeta 39- ??a_number now works as gphelp 40- in prettymatrix format, matrices 0xn and nx0 are always printed as [;] 41- 1 - "a" ==> SEGV Changed 1- reorganized output functions (es.c) 2- have mulir check if integer is small 3- part of GENtostr inlined (check_output_length()) HC 4- functions where it makes sense now admit an optional argument for "variable number" (intformal, deriv, things having to do with polynomials, etc) 5- lines of any length can be input interactively (previously 1k at most) 6- remove {} and \ from readline history 7- improve treatment of sample programs in gphelp -d 8- uniformized debugmem messages MSo 9- simplify the coinit function 10- changing the function set through default(compatible,) no longer resets installed functions 11- renamed nfker-->nfkermodpr, nfgauss-->nfsolvemodpr 12- simplified/extended dummycopy 13- listput gives more informative error messages Added 1- default: lines HC 2- (made known to GP) functions nfmodprinit, nfkermodpr & nfsolvemodpr XR 3- function bnrstark 4- install code D& (optional pointer) 5- function name_var (to use after fetch_var) 6- concatenation of lists (or row vectors) of objects (overloaded concat) 7- ranges for vecextract (eg. vecextract(x, "1..3")) Removed 1- useless code 'F' in analyzer 2- perl directory (moved the files in ./perl to ./doc) =========================================================================== Done for version 2.0.6.alpha (released 22/02/98): Fixed 1- \x (voir2) did not always print the correct number of words 2- in changevar, type POLMOD, modulus and polynomial were interchanged 3- all occurences of former header file names in the documentation 4- (from 2.0.5. item C5) using allocatemem in a script aborted file reading 5- expanded the documentation for bnrrootnumber 6- factor(pol. with rational non integer coeff) could corrupt the stack 7- Euler gave wrong results when prec > 80502 digits (also cleaned up Pi) 8- cleaned up ggcd, grando0, tayl and factorpadic2 9- is_scalar_t --> is_const_t in gvar/gvar2 IZ 10- Configure and example Makefile for OS/2 11- idealprincipal did not accept n x 1 matrices 12- idealhnf(nf,a,b) did not work for quadratic fields 13- matsolve[mod]([;],.) could corrupt the stack or accept incorrect input 14- modules/galois.c unnecessarily included BH 15- symbol name problem in level0asm.c (cancels patch by IZ) XR 16- fixes in stark.c 17- cleaned all occurences of HIGHVALPBIT and HIGHEXPOBIT 18- serconvol assumed main variable was "x" 19- (x + O(x^2))^(3/2) gave a stupid error message 20- types not checked correctly in gtoser 21- check more seriously arguments to default() 22- in Makefile: added some missing $(RM), changed an "ln -s" in $(LN) 23- extra '\n' after print1 + sequence of warnings 24- simplified a statement in addii() 25- typo in classno() (classno(-200183): "division by 0") + cleaned classno 26- all compiler warnings + most of lint's 27- make install would not work anymore if emacs was not found 28- HNF reduction not always complete when rank is small compared to dim 29- gphelp -d did not handle ~ properly (+ cosmetic changes) Removed 1- unused files src/kernel/ix86/{asmi386.h,asmi386inline.h} 2- useless macro gcopyifstack and global variable RAVYZARC 3- useless error message gcder1 4- useless (undocumented) function fasthnf Changed 1- simplified isonstack 2- extended valid inputs for matsolvemod 3- don't output a '\n' before an empty matrix 4- mpsincos no longer static (so that it can be installed) 5- reorganized gp_initrc() to cater for for non-UNIX arch 6- the "obsolete function" message now launches whatnow() directly (and caters for the special cases "i" and "o" now) 7- improved stack management in hnf/allhnfmod/fasthnf 8- moved powering functions to trans1.c 9- disable logfile while reading .gprc 10- (slightly) the output of whatnow() Added BH 1- support for DOS build using EMX (dos directory + fixes) 2- function cotan() and bernfrac() 3- a code for pointers (&) for analyzer and install() 4- ??readline now includes info about completion and online help =========================================================================== Done for version 2.0.5.alpha (released 07/02/98): Fixed BH 1- LOCAL_HIREMAINDER added twice more in mp.c LG 2- some symbols declared extern in gp_rl.c to avoid compiler warnings LG 3- isprime could corrupt the stack (isprime_proto removed) LG 4- possible redeclaration of macro from system header (MAX in bibli1.c) 5- typos in the user's manual 6- removed unused error numbers and fixed their ordering in mp.s 7- a ; or : after read/extern was not always correctly taken into account 8- a bug in polroots (possible SEGV in very rare cases) (Paul Zimmermann) Changed LG 1- (huge) reorganization of PARI kernel and headers 2- logfile example in gprc.dft to take advantage of "time expansion" XR 3- stark units module rewritten HC 4- rnfpolredabs improved 5- errors now cause GP to close any file it was reading instead of going on 6- increased the static limit for the number of files opened simultaneously Added XR 1- function bnrrootnumber =========================================================================== Done for version 2.0.4.alpha (released 26/01/98): Fixed 1- recovery on startup was not correctly disabled GN 2- pari.el (see emacs/pari.el-changes) 3- "" missing around a DLLD caused Configure to fail if shared library not available 4- component of GEN could be created before its root in gadd(t_SER, t_SER) 5- nffactormod did not like big primes 6- removed the `.' binary concat operator introduced in last update (broke semantics). Instead Str() argument evaluated in string context 7- solve did not find some obvious zeroes (solve(x=-2,1,x) for instance) 8- Configure -pg did not work 9- 68k version didn't work: corrected mp.s, moved some code & defines 10- subst(x,variable(x),1) did not work 11- flag acted contrary to doc in matsolvemod 12- in rare cases the prompt could still start at column > 1 13- bnfissunit much faster now 14- idealval could make mistakes with non-integers 15- Mat([1])[1,] gave a stack error 16- zetakinit(x-1) as well 17- zetakinit(K, even integer) gave a wrong result whenever r1(K)>0 18- typo in whatnow(hermite) and ?bnfsunit 19- missing newline in user error after print1 20- various typos and omissions in chapters 1, 2 and 5 of manual 21- (x-x)==(y-y) returned FALSE 22- polfactormod(f,0) gave a SIGFPE 23- some missing #ifdef UNIX BH 24- install() now works for gp-sta under Linux and OSF BH 25- gcc Warnings in gp.c + es.c BH 26- problems when installing from a different non-priviledged account BH 27- inefficiencies in mpinline.h (replace memory access by a constant) Changed 1- when logging mode is on, record command line as well as result, and flush buffer often 2- subdirectory lib now called misc. Changed some filenames in it 3- defaults psfile and logfile are now run through strftime 4- for benches total time now taken into account ([BUG] was excluded) 5- noerr is now the LAST error message (for CLISP interface) 6- cleaned path expansion (default(path,...)) 7- renamed types.h and cast.h (prefixed by "pari") 8- renamed type Rect to PariRect DB 9- kernel/kerPPC.s replaced by kernel/kerPPC.c 10- made static the arrays in check_isin() (for the Mac port) BH 11- overflow/hiremainder use local variables as much as possible 12- prompt not printed during a batch job, unless echo is set commands not echoed twice in interactive mode Added 1- gplogfilter script in misc 2- check for strftime in Configure 3- support for alpha running linux (include portability fix on keralpha.s) 4- file MACHINES 5- made message for "array index out of range" error more precise 6- more frequent garbage collecting in mathnf BH 7- inline asm for i386 GN 8- support for native compiler on AIX Removed 1- support for dynamic linking on AIX (did not work) =========================================================================== Done for version 2.0.3.alpha (released 13/01/98): Fixed: 1- rare bug in gadd (PADIC + PADIC) which caused one of the arguments to be overwritten 2- typos in refcard 3- galois.c still couldn't compile on the HP (_INCLUDE_POSIX_SOURCE) 4- introduced in 2.0.2: item 14 used gexpo incorrectly (bnfinit sometimes did not give units it could have computed) 5- replaced INFINITY by pariINFINITY in rootpol.c (cancels Warning on OS/2) 6- on OS/2, target ../gp-$dft in o.xxx/Makefile could not be built (extraneous $exe_suff) 7- command line switches so that one can enter them with or without white space (new function read_arg in gp.c) 8- setdcolors so that it can't unset disable_colors if we are under emacs 9- random did not check its argument correctly (random(2^32) was accepted) 10- b=10; for(a=1,b, b=2) exited immediately, whereas the upper bound is supposed to be evaluated only once 11- reorganized the error recovery system (initially because errpile could cause SEGV on Linux systems) 12- typo. problems in doc and refcard (interletter spacing in $nfz$...) Changed: 1- Reorganized Makefile.SH: extraction twice as fast 2- pari.menu and pariemacs.txt rewritten, pari.el updated 3- expanded the man gp.1 to mention command line switches 4- the implied input from non-interactive input command (like extern and read) does not go into the GP history (%x) anymore (it never went into readline's). The final output (value of last expression evaluated) of course still does! 5- updated chapter 5 of the User's Manual (removed obsolete information) Added: 1- better settings for handling the Meta key under readline in examples/Inputrc YU 2- support for shared libraries under FreeBSD 3- colors under Emacs 1) emulate exactly the "colors" default after a M-x gp 2) .gp files edited get a special highlighting 4- a flag to default() to get the result under GP 5- overloaded the "." (member) operator to concatenate as strings if LHS is a string 6- .gprc accepts some limited preprocessing directive (#if READL and #if EMACS (and #ifnot as well)). Updated lib/gprc.default to reflect the changes Removed: 1- some unused, undocumented functions (allocatemem(), checksqid()) made static some other (op_ReIm) =========================================================================== Done for version 2.0.2.alpha (released 15/12/1997): Fixed: 1- typos in the documentation for the random() function 2- removed an extra -emacs flag in pari.el 3- decodefactor was incorrectly remembered by whatnow (it's factorback now) 4- test mode did not prevent all prompt expansion (==> bug in make test) 5- gphelp stopped abruptly when meeting a cross-referencing macro 6- zetainit now aborts cleanly when disc. too big (caused memory fault) 7- exceedingly rare bug in the printing of real numbers (missing decimals) 8- too early rounding in polroots which in rare cases made GP think some error had happened 9- text overflowed the manual pages (and tutorial) on non-A4 paper 10- polred incorrectly assumed that nf arguments were totally real (in a non critical part: that just led to some unnecessary computations) 11- polred(f,2) could try to overwrite universal integer gzero 12- check if we are using GNU as or GNU ld in Configure 13- empty -R argument to $CC when building GP without graphics (==> link failed) 14- bnfinit acts sensibly when fundamental units are too large (before: "overflow in R*R") 15- cleaned up buch2.c (removed ideallllredpart1, removed gerepile in class_group_generators(), not_given now called from getfu) 16- nfgaloisconj(...,2) was unusable (tried an illegal multiplication) 17- is_totally_split was very inefficient (==> nfgaloisconj was very slow) 18- some unimportant typos (gexpo) in polgalois 19- compiling without readline gave a Warning in gp.c (already_hist) 20- some make programs don't like $< (suppressed from doc/Makefile) 21- ellap sometimes assumed wrongly that coeffs of the curve were integers 22- flag 0 and 1 in ellap had been mixed up 23- print an extra \n before an error message if last output did not include it 24- component(any non recursive type) gave a SEGV 25- suminf / prodinf / prodeuler assumed they treated a real expression 26- lindep / algep had problems with numbers having a rational component 27- last significant digits of bessel* and hyperu were wrong (now only the last one is) 28- expi now returns a long as documented (expi(gzero) returned 0 on 64-bit machines!) 29- g++ could not compile libpari.a (casts missing, extraneous extern "C", faulty inline, etc.) 30- cleaned up the enums in gp.h 31- incorrect target veryclean in doc/Makefile Changed: 1- '_' is now valid in GP identifiers 2- removed subsections from table of contents. pages in the manual are now numbered consecutively 3- gexpo now accepts exact 0 arguments (return -HIGHEXPOBIT) gexpo for complex numbers now return max(gexpo(Re), gexpo(Im)) 4- parts of lib/gprc.default 5- the second argument of subgrouplist is now optional Removed: 1- buggy label/goto functions 2- (now unused) error messages: labeler, gexpoer2 3- _ as shorthand for conj() 4- (useless, undocumented) function gnormalize 5- some files in the lib directory (functions, gp) Added: 1- some files in the lib directory (README, pari.xbm, xgp) ============================================================================== Done for version 2.0.1.alpha (released 29/11/1997): Fixed: 1- multiple factors forgotten when factoring univariate pols over Z 2- extraneous modifications of the random seed (period of random generator was ridiculously small for some buchxxx functions). Change the bench results (in a non essential way) 3- bad terminal size determination 4- aliases incorrectly killed (possible SEGV) 5- incrementing/decrementing array elements with the (valid) syntax v[i]++ / v[i]-- caused a weird error message 6- subgrouplist() could end up by a SEGV on Linux systems LG 7- on HP-UX, flag -Aa not taken into account in Configure (caused it to fail on has_TIOCGWINSZ.c) LG 8- added a missing #define _INCLUDE_POSIX_SOURCE in galois.c (7 & 8 independently fixed by OV) GN 9- the script examples/cl.gp called vecconcat() instead of concat() GN 10- make install-sta rebuilt gp-sta unnecessarily GN 11- many, many typos in the tutorial 12- tu / fu applied incorrectly to a bnfclassunit 13- bnfclassunit did not output a valid object (matrix whose elements were rows instead of columns) 14- conversion bug from t_QUAD to t_REAL/t_COMPLEX 15- off-by-1 error in the history recovery after an error 16- in fprintferr() (debug messages), embedded %Z did not work correctly 17- rnfequation over Q yielded a SEGV 18- string() in compatibility mode corrupted the stack 19- it is now safe to have colours in prompt and input line under readline 20- default colours restored upon exiting 21- default colors in lib/gprc.default used 0 instead of -1 for "no color" 22- psi and lngamma could give wrong results when the argument was not real 23- the make test-graphic bench was missing a newline 24- Pol(break) gave a SEGV 25- x=1; Pol(1) gave a stupid error message IZ 26- tutorial.tex was unnecessarily rebuilt 27- typos in ggcd (cases nobody will ever access: gcd of a non-reduced LG fraction with an intmod, etc.) LG 28- incorrect handling of integrals of vectors 29- gcd of polynomials with non-exact coeffs gave stupid results (they are still often wrong, since the mathematical notion is rather imprecise) 30- typos in rnfkummer (incorrect flag handling) 31- typo in idealpowprime (negative exponent gave wrong denominator) 32- multiplication t_COMPLEX x t_COMPLEX used 4 mult. instead of 3 33- some modular functions (j, f, f2) rewritten to take advantage of new eta function (trueta) Changed: 1- ?? (gphelp) starts in detex mode (-d) from a console window. tmp files now placed according to the $TMPDIR environment variable (in /tmp by default) 2- /usr/local/lib/pari/data is a better place for the Galois resolvents (which are not included yet in the standard distribution) 3- The example for prompt in gprc.default to discuss escape sequences under readline 4- Configure now starts by searching the toplevel directory for a temporary readline installation 5- The output of default(colors) was confusing. It is a string now 6- third argument of polinterpolate can be arbitrary and is now optional ("x" by default) (it had to be numeric) 7- directory configure renamed config, some of the Makefiles in there as well (to avoid confusion) 8- the low_stack macro to facilitate dynamic stack expansion 9- if, back to GP main loop, the last command was a print1(), output an extra newline. This way the prompt is guaranteed to be anchored on column 1 (suppresses a readline display bug as well) 10- Due to 9, pari.el now supposes the prompt starts in col. 1 11- Better handling of version numbers (LG) 12- decodefactor() renamed to factorback() Removed: 1- The (unused, undocumented) Malloc_Procs functions and macros 2- The (now unused) error message numvarer 3- some (useless, undocumented) targets in the top Makefile 4- (useless, undocumented) function polgcd() Added: 1- This file ! 2- new flags -ch, -cb, -cu (colour support) to gphelp (see its header) IZ 3- OS/2 (+ enough tools...) supported by Configure 4- file examples/Inputrc (example of .inputrc for readline) 5- Weber f1 function implemented 6- Karatsuba multiplication t_REAL x t_REAL (development code, not used by PARI yet). Test it with install if you wish pari-2.11.2/CHANGES-2.80000644000175000017500000013006313326135265012467 0ustar billbillBug numbers refer to the BTS at http://pari.math.u-bordeaux.fr/Bugs/ Done for version 2.9.0 (released 1/11/2016): Fixed 1- idealappr: allow flag for backward compatibility 2- nfisisom(x,x^0) -> SEGV BA 3- galoisgetpol: fix crash if some files are missing BA 4- [libpari] fix support for PARI_OLD_NAMES Done for version 2.8.1 (released 23/10/2016): Fixed 1- nfroots(non-monic t_POL) => wrong result [#1841] [from 2.8.0] 2- crash on BIB in ellpointtoz(t_PADIC) [#1840] 3- nfisideal(nfinit(x^2+1),[1,0;0,2]) -> 1 instead of 0 4- intnuminit(-oo,oo,1) -> error [#1847] 5- idealstar([f_0,f_oo]) for f_oo t_VECSMALL (place selection) didn't work 6- msinit objects could not be saved to file then read back in [from 2.8.0] 7- wrong value for bnrrootnumber for non-primitive characters [#1848] 8- allow znstar(N,flag) for idealstar(,N,flag) 9- allow znlog(x,G) for G = znstar(N), instead of ideallog(,x,G), for DL wrt. G.gen; in addition to traditional znlog(x,g), where an arbitrary generator g is specified 10- e=ellinit([1,-1,1,98,126],O(5^10)); ellpointtoz(e,[1,14]) -> div. by 0 11- ellpointtoz(E / Qp, P) was not reduced mod q^Z BA 12- [breakloop] changes done in the first-level breakloop were lost when leaving the second-level breakloop. 13- polinterpolate could create illegal objects [#1837] (test-case by PB) BA 14- [libpari] FqX_nbfact did not work 15- incorrect change of variable in elllocalred over a number field for places dividing 6 [from 2.8.0] 16- contfraceval([[],[]],1) -> SEGV [from 2.8.0] 17- agm(1.0, 1.0*I + x + O(x^200)) -> oo loop [#1654] 18- primepi(2750160) -> crash [#1855] 19- polinterpolate([],[],Mod(1,3)) => 0 instead of Mod(0,3) 20- subst(Pol(0),x,Mod(1,3)) => 0 instead of Mod(0,3) 21- subst(Pol(1),x,Mod(1,3)) => 1 instead of Mod(1,3) 22- e=znconreyexp(idealstar(,N),) could give a result with (e,N) = 2 when N = 2 (mod 4) [from 2.8.0] 23- idealprincipalunits(,,1) not supported [ concat error ] [from 2.8.0] 24- stack corruption in pollardbrent() at \g4 [#1858] BA 25- fflog could crash in char 2. [from 2.8.0] JD 26- is_universal_constant() made (possibly wrong) assumptions about memory layout (gen_0 < ghalf) BA 27- lfundiv(L1,L2): division by 0 if L2[6] (rootno) is 0. 28- inconsistent thresholds for zeta(2*n); e.g. at \p100000, zeta(22934) was much faster than zeta(22936) BA 29- [pthread] fix race conditions that caused memory corruption 30- rare SEGV in bnfisprincipal Added 1- permtonum: allow t_VECSMALL input 2- [libpari] Z_to_perm, perm_to_Z 3- [libpari] checkprid_i, is_nf_factor, is_nf_extfactor 4- extend ellissupersingular for E/nf 5- added a tag Obsolete: to the RFC822 description system (pari.desc) 6- new GP functions nfmodpr, nfmodprlift 7- [libpari] get_arith_Z, get_arith_ZZM 8- [libpari] Mod2, Mod4, Mod8, Mod16, Mod32, Mod64, umodi2n 9- [libpari] logint, logintall 10- [libpari] zk_inv, zkmultable_capZ, zkmultable_inv, nfC_multable_mul, zkC_multable_mul 11- [libpari] Idealstarprk 12- [libpari] ZpX_monic_factor 13- [libpari] nf_to_Fp_coprime 14- [libpari] idealprod, idealHNF_Z_factor 15- [libpari] rnfcomplete, rnf_build_nfabs, bnf_build_cycgen, bnf_build_units, bnf_build_matalpha 16- [libpari] rnf_zkabs 17- [libpari] get_nf_field (black box field arithmetic over a number field nf), nfM_det, nfM_inv, nfM_mul, nfM_nfC_mul 18- [libpari] bnftestprimes 19- [libpari] upr_norm 20- [libpari] bid_get_fact, bid_get_ind, bid_get_sarch, bid_get_sprk 21- [libpari] qfbforms 22- [libpari] nfroots_if_split 23- [libpari] nfmaxord_to_nf, nfinit_basic, nfinit_complete, idealprimedec_kummer, nf_deg1_prime 24- [libpari] ZNstar, znstar0, znlog0 25- GP function znchartokronecker 26- [libpari] ser_inv 27- allow ellztopoint for E/Qp BA 28- [libpari] F2x_factor_squarefree, F2xqX_factor, FlxqX_factor BA 29- [libpari] FlxXC_to_F2xXC, F2xXC_to_ZXXC 30- [libpari] pr_uniformizer, prV_lcm_capZ, pr_inv, pr_inv_p, pr_basis_perm 31- [libpari] cmp_padic 32- [libpari] ZV_snf_trunc, ZM_hnfmodall_i, ZM_hnfall_i, ZC_Z_div 33- [libpari] uisprime_101, uisprime_661 34- [libpari] lift_shallow 35- [libpari] rowsplice 36- GP functions bnflogef, bnflog, bnflogdegree, nfislocalpower, rnfislocalcyclo 37- [libpari] varnmin, varnmax 38- allow ellglobalred for E over a number field BA 39- [libpari] FpXQX_split_part BA 40- [libpari] ZpXQX_roots, ZqX_roots, ZqX_liftfact, ZqX_liftroot, Zq_sqrtnlift 41- [libpari] hash_dbg 42- [libpari] Qdivii, ceildivuu 43- GP function ellintegralmodel 44- [libpari] ZM_hnf_knapsack, hnf_invscale 45- [libpari] pol_xn, pol_xnall, retmkrfrac 46- allow lindep(vector of t_VEC), lindep(vector of t_COL) [#1857] 47- [libpari] famat_pow_shallow, famat_mulpow_shallow 48- [libpari] modRr_safe 49- [libpari] Z_ppo, u_ppo Changed 1- remove useless flag in idealappr: directly allow factorization 2- [libpari] idealappr0 is now obsolete: use idealappr 3- replace qfbil(x,y,{q}) by qfeval({q},x,y) and qfnorm(x,{q}) by qfeval({q},x): it makes more sense to have q first, and a single function for qf+polar form (as in all other qf-like routines: ellheight, etc.) 4- functions nfeltdivmodpr, nfeltmulmodpr, nfeltpowmodpr, nfeltreducemodpr, nfkermodpr, nfsolvemodpr are obsolete. Use nfmodpr, work in the finite field, then lift back using nfmodprlift. 5- split off historical refcard in submodules basic, ell, lfun, mf, nf 6- rewrite nfeltinv / nfeltdiv (use mult. table rather than polmod representation) 7- idealred algorithm (find small y in I^(-1), not in I) 8- bnf format (allow dynamically adding units): old bnfs will be detected as invalid. Dirty trick to force conversion: bnf[10]=vector(3); 9- nfelt* functions may now return scalars (t_INT/t_FRAC) in addition to t_COL on nf.zk basis. 10- remove flag = 2 in nfgaloisconj (slow, unreliable, obsolete for 15 years) 11- bnfcertify(K): use automorphisms (speedup roughly #Aut_Q(K)) 12- idealstar format, to access data more conveniently (and avoid recomputations): old bid and bnr structures from versions up to 2.8.0 are now invalid 13- narchstar output: include finf in output 14- set_sign_mod_divisor prototype: module is now useless (implicitly contained in sarch argument) 15- [libpari] removed discrayabs, discrayabscond, discrayrel, discrayrelcond, discrayabslistlong: obsoleted since 2.0 16- gcd(t_VEC/t_COL/t_MAT, ...) is now forbidden, same for lcm 17- E/Qp: add sequence of isogenous curves to structure (converges to the singular E_oo) => much faster ellpointtoz BA 18- ZpX_liftfact no longer handles extensions of Qp, use ZqX_liftfact 19- char_rootof1 renamed to rootsof1_cx, char_rootof1_u -> rootsof1u_cx 20- gp --test: consider that the session is not interactive BA 21- [libpari] rename listcreate to mklist 22- [libpari] rename idealinv_HNF -> idealHNF_inv, idealinv_HNF_Z -> idealHNF_inv, idealmul_HNF -> idealHNF_mul 23- [libpari] made famat_mul_shallow a true equivalent of famat_mul 24- move 'install' tests from test-program to test-install target 25- allow normlp(v, +oo) 26- [documentation] removed .ps files (use dvips -o if you need them); install dvis Done for version 2.8.0 (released 12/08/2016): Fixed 1- make install fails on OS/X: ln -s libpari.dylib libpari.dylib fails 2- Q_pvalrem(t_FRAC) => wrong result 3- [] == 0 but []~ != 0 (now []~ == 0 as well) [#1560] BA 4- test-kernel did not work when using --mt=pthread BA 5- ellheegner was using too much memory in some case 6- ellap can overflow on 32-bit machine [#1558] ellap(ellinit([582304190,64196421]),2147438927) -> overflow ellap(ellinit([-1137195,489565862]),2038074751) -> wrong result 7- nfhilbert(K,x,y, P above 2) could give wrong results [#1561] 8- rnfkummer sometimes failed to return an answer: error or oo loop. Relied on exhaustive enumeration of an Fp-vector space, some of whose elements would trigger an error. Replace by Fp-linear algebra that directly picks the correct line (O(d^3) algo instead of O(p^d), and no failures). Only compute the defining poly for the right element. XR 9- padicfields(huge p, d) was very slow [even though ramification is tame] 10- gcd(1/2, 1+I*1.) -> SEGV [#1563], 2.5.5 returned the wrong answer 1/2 11- mathnf(t_VEC) could corrupt input (change sign) 12- [libpari] RgM_transmul did not work 13- [libpari] Fq_issquare didn't support T=NULL 14- [libpari] nfpow_u didn't handle non-integral rational numbers 15- eint1(0) -> stack overflow [#1568] 16- liftint(List([0])) -> gerepile bug 17- factorint(n,flag): flag was ignored when n fit into a long 18- factor(n,lim): lim was ignored when n fit into a long 19- nfrootsQ(t_POL with leading coeff -1) could miss some solutions, e.g. nfroots(,-y^2-24476*y+119814917) -> [] instead of [-28657,4181] 20- precprime(1) -> invalid t_INT [#1576] 21- gaffsg(0, t_PADIC): wrong valuation 22- thue(f^e*g, ...), e even, (f,g)=1 missed solutions such that f<0 23- faster znlog when p-1 has only smallish prime factors. 24- (t_INTMOD with word-sized modulus)^(huge negative power) wrong [#1584] 25- (gp -p N) or (primelimit=N in gprc_ for N >= 436273290 resulted in an incorrect primetable. N.B. Such commands are now useless: needed primes are produced dynamically anyway. 26- monomial(exact zero, d, v) returned an invalid t_POL / t_RFRAC 27- contfracpnqn(v, n) returned partial quotients p[-1]/q[-1] ... p[n-1]/q[n-1], instead of the documented p[0]/q[0] ... p[n]/q[n] [#1580] 28- isprime(N, 0) was often slower than either of isprime(N, 1 or 2) 29- factor((3+4*I)/25) -> factor 2+I had 0 exponent [#1586] 30- made qfbclassno more reliable (fixes all counter examples in [#1411]) BA 31- iferr() could crash if some component of the t_ERROR were clones. 32- nffactor() could overflow the stack when default accuracy too low: e.g. nffactor(y^2-22, x^2+926246528884912528275985458927067632*y-4344481316563541186659879867597013188) 33- some elliptic curve functions accepted (elladd, ellmul) a Weierstrass 5-uple [a1,a2,a3,a4,a6] instead of an ell structure. No longer. Now only ellinit and ellchangecurve allow this syntax. 34- incorrect rounding in mulrr/divrr for one-word precision reals. BA 35- multiif did not handle correctly return() in conditions [#1590] 36- [0..5] -> [0,0,0,0,0] on some architectures 37- is_gener_Fp could return wrong results 38- Fq_sqrtn(t_INT,..,&zeta) could return a wrong root of 1 39- bnfinit: SEGV due to precision issues [#1592] 40- zm_zc_mul only worked for square zm matrices 41- genus2red(0,27*x^5+97*x^4+118*x^3+60*x^2+13*x+1,3) -> bug msg [#1596] 42- [gphelp] oo loop when $COLUMNS too small [#1594] 43- genus2red(x,-x^6-3*x^4-10*x^2-1,3) -> impossible inverse [#1597] 44- factoru(1) returned a t_MAT instead of the expected "matsmall" [#1598] 45- FpM_charpoly wrong in small characteristic [#1602] 46- Ser(Mod(0,2)) => incorrect object [#1587] 47- Ser(Mod(1,2)*x^2,,4) => incorrect precision [#1587] 48- Ser(x,v,prec < 0) => crash [#1587] 49- The t_SER Mod(0,2) + O(x^n) was not handled properly [precision and valuation would change unexpectedly] [#1587] 50- when compatible = 3; series() used a random precision 51- genus2red(0,6*x^6+5*x^4+x^2+1,7) -> impossible inverse [#1597] 52- isprime(2030967737887612953751815611955778057721609672149695775998900201419048774375002716065557720510887824952942799737911826638068045234238082640629966597954851668852106621828704531597859470496362810381251800973022824003330423370127762722630493369197869948901862977534730314352222720177713223750671181797) -> SEGV [#1604] 53- genus2red(x^3+1,1) -> type error [#1597] 54- gphelp did not handle === correctly [#1603] XR 55- bnrL1(bnrinit(bnfinit(x^2-168),[6,[1,1]],1)) -> bug in ArtinNumber[#1601] 56- FpXY_evaly() wrong when evaluating at 0 BA 57- [win32] gp could crash at start up [#1607] 58- nfisincl(t_POL, t_POL) could lead to wrong negative results 59- polresultant(1+x*z^2,1+y*z^4,z) -> GC error [#1614] BA 60- ellcard over non-prime fields of large char could return wrong results 61- [libpari] FpX_roots could produce GC errors [#1618] 62- weber(1+I) was missing its imaginary part 63- (1+I)*(1+1/2*I) => wrong result (type errors) [#1619] 64- contfracpnqn([a]) => [1,a;0,1] instead of [a,1;1,0] 65- primes([2^50, 2^50+200000]) => stack overflow 66- issquare((x+1/2)^2,&z); z => 1.0*x+0.5 instead of x+1/2 67- possibly wrong result in nfsnf 68- possibly missing roots in nfroots (when using Trager) 69- quadray(bnf, ideal) did not work 70- thue(-14*x^3 + 10*x^2 + 63*x - 5,1) -> "short continued fraction" [#1629] 71- thue(29*x^3+130*x^2-35*x-48,1) -> "round error" bug 72- T=thueinit(10*x^3+6*x^2-41*x+8,1); thue(T,8) => SEGV [#1630] 73- ellrootno(e,p = 2 or 3) when e not minimal at p => random result 74- catastrophic cancellation in ellheight (at oo) [#1637] 75- bnfnewprec could return a corrupt bnf structure: K=bnfinit(x^3-15667*x^2-88630960*x-1836105977032,1); bnfisprincipal(K,[29,14,15;0,1,0;0,0,1],3) -> oo loop 76- agm(1,2+O(5)) -> SEGV [#1645] BA 77- [cygwin64] ellap(ellinit([0,0,1,-1,0]),10007) broken 78- primes([-5,5]) -> [5] (spurious absolute values) 79- matqr([;]) -> crash 80- Fp_rem_mBarrett could return a non-normalized result p=436^56-35;Mod(271,p)^((p-1)/2) -> p+1 81- plotcopy would corrupt "string" objects (ROt_ST) BA 82- [GP] default arguments to GP functions could cause corruption [#1658] VBr83- [darwin] remove obsolete linker options that cause crashes [#1623] 84- divisors([2,1]) -> SEGV [#1664] 85- acos([Pol(1)]) -> GC bug [#1663] 86- matsolve(a,b) and a^(-1) gave wrong results [or SEGV] when t_MAT a was not square and a,b "modular" (F2m,Flm,FpM,FqM,F2xqM,FlxqM) same for x^(-1) [#1666] 87- primes([1,Pol(2)]) -> SEGV [#1668] 88- znlog(0,Mod(1,4),1) -> 0 (instead of []) 89- polzagier / sumalt(,1) / sumpos(,1) were slow and used too much memory 90- sumpos was wasting time when pre-computing \sum 2^e a(k*2^e) [ only needed for k odd, but was also done for k = 0 mod 4 ] + improve accuracy 91- intnum(x=[0,-1/2],[oo,-3/2],1/(sqrt(x)+x^(3/2))) -> junk t_COMPLEX (more generally: one endpoint has an algebraic singularity and the other is +-oo, non-oscillatory 92- intnum(x = [-oo,-3/2], [oo,-5/2], f(x)) --> loss of accuracy due to confusion between endpoint behaviours a/b in intnuminit data E.g. f(x)=(x<0,1/(1+(-x)^(3/2)), 1/(1+x^(5/2))); 93- intnum(x = [-oo,-3/2], [oo,-5/2], f(x)) --> loss of accuracy due to confusion between endpoint behaviours a/b in intnuminit data E.g. f(x)=(x<0,1/(1+(-x)^(3/2)), 1/(1+x^(5/2))); 94- intnum(x=[0,-1/2],[1,-1/3], x^(-1/2) + (1-x)^(-1/3)) -> error [didn't suport singularities at both endpoints] 95- buffer overflow after default(format,"f.precision") (whenever many initial zeroes) 96- qfminim(A, 0, ...) -> stack overflow [#1682] 97- e=ellinit("11a1"); ellztopoint(e,3*e.omega[1]/5) -> [5, junk] (instead of expected [5,5]) [#1683] 98- bnfinit(quadhilbert(-2180)) -> precision error [#1688] 99- div_scal_rfrac could create an invalid t_POL [#1651] 100- polroots(t_POL with leading coeff = 0) -> fp exception or error [#1690] 101- \r cannot deal with very long filenames [#1616] 102- rnfisabelian(nf, non monic t_POL) -> SEGV [#1693] 103- Vecrev(x,n) / Colrev(x,n) when 'n' is not omitted: it wasn't true that Colrev/Polrev were inverse functions [#1698] 104- possibly incorrect result in nfdisc(T,listP) even though listP included all prime divisors of the field discriminant. Example: p=10^100+267; q=10^120+79; T=polcompositum(x^2-p,x^2-q,2); nfdisc([T,[2,p,q]]) 105- wrong dim(Ker) returned by ZM_pivot => SEGV in Z-linear algebra routines. E.g. setrand(1);quadclassunit(-612556842419) [#1700] 106- moebius(factor(18)) -> 1 instead of 0 [#1702] 107- ispower(-167^10) => domain error [#1703] 108- ispowerful(factor(0)) != ispowerful(0) 109- expm1(2*I) => wrong result 110- gamma(1+a*x+O(x^2)) => error [#1707] 111- printsep() printed its argument in random format, instead of f_RAW as print() [#1708] 112- nfdisc(x^10 - 29080*x^5 - 25772600) -> oo loop [#1710] 113- forprime engine could skip (fast) sieve in favour of (slow) nextprime [#1711] 114- 0^[1] -> domain error [#1713] 115- memory leaks (clones) in ellchangecurve [#1716] 116- zeta inaccurate around 0 [ from 2.7 ], [#1714] 117- ellj(simple t_SER in 'x) much slower than in other variable [#1720] 118- bnrrootnumber did not support the trivial character in the form [0,..,0] 119- default(log,1) when logfile is write-protected later lead to SEGV [#1730] BA120- 2-adic gamma function: fix accuracy loss 121- A==A -> 0 for A a t_SER of huge accuracy (so that A-A overflows valuation) [#1734] XR122- P=[1,-2,12,-12,-181,-4,-6899,9780,6360,702,-45]; setrand(3); nfdisc(P) -> wrong answer [ crash if setrand(138) ] [#1735] 123- select(x->x,Vecsmall([1,2,3]),1) -> crash [#1737] 124- (1./x+O(1))-(1./x+O(1)) -> 0.E-38*x^-2+O(x^-1) [#1741] BA125- [libpari] RgV_to_RgX_reverse did not work if v[1] or v[2] was 0 126- bnfinit(x^3-87156*x^2-6728799*x-456533) [#1736] 127- Rg_to_ff: incorrect type in zk_to_ff [#1755] BA128- nfsubfields could fail [#1758] 129- rare SEGV in ArtinNumber [#1759] 130- K.codiff incorrect if [K:Q] > 2 131- chinese([]) -> '1' instead of Mod(0,1) 132- m1=Mod(0,1);m2=Mod(1,x^2+1); chinese(m1,m2) -> m1; chinese(m2,m1) -> m2 [instead of error] 133- nfrootsof1(polcyclo(85)) -> 85 instead of 170 [#1766] 134- at \p19, polroots((x+1)^2 * (x-1)^7 * (x^2-x+1)^5 * 1.0) -> SEGV [#1767] BA135- ellsea returned the trace instead of the cardinal as documented. BA136- ellsea(,,1) could return a wrong result [#1768] 137- rnfconductor: sanity checks were not taken into account MC138- memory leak in pari_close: sopath not freed HC139- incgam(30,60) < 0. More generally, wrong results for s >> 1 [#1689] HC140- excessive loss of accuracy in incgam, incgamc, eint1 141- isprimepower(30011^(3*17)) returned 0 142- a = Mod(1,x); z = Mod(0,Pol(1)); chinese(a, z) works but chinese(a, simplify(z)) failed BA143- [mpi] interrupt/alarm could caused a crash BA144- [mpi] relinking empty t_LIST caused a crash 145- ispower(t_POL) didn't work in small characteristic [#1779]; make it work over finite fields BA146- my(s=1,a=0);forstep(i=1,20,s,s++;a+=i);a -> wrong result KR147- gphelp -detex: accented letters counted as 1 char for line splitting but rendered as 2 148- sqrt(0) -> loss of accuracy (sqrtn was correct) 149- nfgaloisconj(t_POL T) was unnecessary slow when large divisors of disc(T) were internally detected (and subsequently ignored) BA150- elltatepairing could return wrong results [#1784] 151- padicappr(x^3+1,-2+O(2^5)) -> SEGV [mod a root mod p] [#1793] 152- K = bnrinit(bnfinit(y^2-5),[1,[1,1]]); bnrdisc(K) -> wrong [#1804] 153- ellztopoint(ellinit([-1,0]), I) -> wrong result [#1800] Potentially affected all elliptic functions (ellwp,ellzeta,ellsigma) at real or pure imaginary arguments. 154- gamma(2+x) did not start with an exact 1, unlike gamma(1+x). lngamma(2+x) didn't have valuation 1 155- gamma(t_INT+x) at large accuracy and seriesprecision was very slow, even for small t_INTs (same for lngamma and psi). E.g. at \p1000 gamma(1000+x+O(x^100)) 156- a=Mod(y,y^2+1); Mod(a, x^2-2) == a returned 0 [#1806] 157- x \/ y did not conform to documentation when either x or y was a t_REAL. E.g. 28/10 \/ 1 == 3 but 2.8 \/ 1 == 2. Now both return 3 [#1811] BA158- digits(N,B) with 31/63 bit B could return wrong result BA159- [pthread] parallel GP could leak memory 160- ellinit(E, O(p^n)) was slightly incorrect for E / Q [ started by approximating exact equation mod p^something instead of keeping everything exact ] 161- ellinit(E, O(2^n)) was hardly supported, e.g. ellinit("14a1",O(2^5)).tate => precision too low in p-adic AGM. BA162- polrootsmod(x^3-1, not a prime) -> SEGV (BIB) BA163- [windows] MPQS could fail due to temporary files 164- matsnf([27, 0; 0, 3; 1, 1; 0, 0],1+4) -> SEGV 165- gcd(Mod(1,2)*x+Mod(1,2), Mod(0,2)) -> Mod(1,2) 166- qfperfection() only allowed matrices of small norm [#1719] 167- wrong formula for poldisc when characteristic divides degree [#1831] 168- wrong result for poldisc(ZX) in huge degree [#1830] 169- missing typechecks in ellheight() [SEGV on BIB] 170- ellminimalmodel() didn't use a coprime bases so that it was very slow for [c4,c6] = [p^5*q, p^6*q] for huge p and q BP171- ellpointtoz(E / Qp) was totally wrong [#1833] 172- genus2red(177*x^6+126*x^5-63*x^4+72*x+84) -> bug in labelm3 [#1826] 173- normalize genus2red stable reduction output: a type K1-K2-r now guarantees K1 <= K2 (before both K1-K2-r and K2-K1-r could occur) 174- gmulsg(0, 1+O(x)) -> O(x^0) instead of t_INT 0 as in gmul(gen_0, ...) Added 1- add optional argument to sumdigits to specify the base 2- [libpari] bits_to_int,bits_to_u,binary_zv,binary_2k,binary_2k_nv BA 3- [GP] support for variadic GP functions (f(v[..])=expr) 4- nfeltval(K, x, pr, &y) now takes an optional 4th argument, containing the part of x coprime to pr. BA 5- [libpari] New functions family RgXn: new functions RgXnV_red_shallow, RgXn_powers, RgX_RgXnV_eval, RgX_RgXn_eval, RgXn_reverse, RgXn_inv, RgXn_exp BA 6- [libpari] New functions Flv_inv BA 7- [libpari] New functions Flx_Flv_eval, Flv_Flm_polint, FpX_FpV_eval, FpV_FpM_polint WH 8- [libpari] New low-level functions get_Fl_inv, remll_pre BA 9- [libpari] New low-level functions Fl_sqr_pre, Fl_mul_pre, remlll_pre, Fl_powu_pre, Fl_sqrt_pre, divll_pre, random_Fle_pre 10- [TeX documentation] new primitive \url (verbatim arg) 11- [libpari] New functions Fq_log, gener_Fq_local BA 12- GP functions bnrisgalois, bnrgaloismatrix, bnrgaloisapply LGr13- GP function polrootsreal 14- GP constant "oo" (for +/- infinity) 15- [libpari] New functions mkoo, mkmoo, inf_get_sign 16- [libpari] New functions ellbasechar, ec_f_evalx, ec_dfdx_evalQ, ec_dfdy_evalQ, ec_2divpol_evalx, ec_half_deriv_2divpol_evalx, ec_h_evalx, ec_dmFdy_evalQ, ec_bmodel HIL17- GP functions ellisogeny, ellisogenyapply 18- [libpari] New function RgX_coeff BA 19- [libpari] New functions Fl_halve, Fp_halve, Flx_halve, Fq_halve BA 20- [libpari] New functions vecsmallpermute, vec_append 21- GP functions qfsolve, qfparam [ adapted from Denis Simon's qfsolve.gp ] 22- [libpari] New function ZM_transmul 23- allow elliptic curves over number fields: ellinit([a1,...,a5], nf) 24- [libpari] ZX_sturm, ZX_sturmpart, RgX_sturmpart 25- [libpari] RgXQV_RgXQ_mul 26- thue / thueinit now also support (powers of) imaginary quadratic equations BA 27- [libpari] ZpX_ZpXQ_liftroot, ZpX_ZpXQ_liftroot_ea 28- [libpari] fuse_Z_factor 29- ellformalw, ellformalpoint, ellformaldifferential, ellformallog, ellformalexp, ellnonsingularmultiple, ellpadicheight, ellpadicheightmatrix, ellpadics2, ellpadiclog BA 30- [libpari] functions FpX_powu, FpX_digits, FpX_fromdigits, FpXQX_powu, FpXQX_digits, FpXQX_fromdigits, FqX_powu BA 31- GP functions ellpadicfrobenius, hyperellpadicfrobenius, hyperellcharpoly 32- [libpari] function RgX_normalize BA 33- much faster matfrobenius/minpoly(t_MAT) BA 34- prototype codes U and u for ulong 35- allow testing for BITS_IN_LONG in gprc 36- GP functions msinit, ellpadicL BA 37- [mingw] support for the alarm GP function BA 38- [libpari] functions Fl_sqrtl, Fl_sqrtl_pre 39- [libpari] function ZV_allpnqn 40- [libpari] function Qevproj_init, Qevproj_apply, Qevproj_apply_vecei 41- [libpari] functions G_ZGC_mul, G_ZG_mul, ZGC_G_mul, ZGC_Z_mul, ZG_G_mul, ZG_Z_mul, ZG_add, ZG_mul, ZG_neg, ZG_normalize, ZG_sub, ZGC_G_mul_inplace, ZGCs_add 42- [libpari] function kroui BA 43- GP function powers and libpari function gpowers 44- flag LLL_COMPATIBLE for LLL routines [ use 64-bit compatible accuracies only ] BA 45- [libpari] functions FpX_Frobenius, FpX_matFrobenius, Flx_Frobenius, Flx_matFrobenius, ZpX_Frobenius, F2x_Frobenius, F2x_matFrobenius 46- [libpari] function ser_isexactzero BA 47- [libpari] functions ZV_chinese, Z_ZV_mod, Z_nv_mod, nmV_chinese_center BA 48- GP function fromdigits BA 49- [libpari] functions Zp_sqrt, ZpXQ_sqrt 50- GP functions mscuspidal, mseisenstein, msnew, mssplit, msqexpansion, mshecke, ellmsinit, msatkinlehner, msstar, mseval, mspathgens, mspathlog, msissymbol, msfromcusp, msfromell BA 51- GP declaration localprec(), localbitprec() HIL52- [libpari] functions Fl_powers_pre, Fl_ellj_pre, Fl_elldisc_pre, Fl_elltwist_disc BA 53- [libpari] functions Fl_powers, Fp_powers, Fl_ellj, Fl_elldisc, Fl_ellj_to_a4a6, Flxq_ellj_to_a4a6 BA 54- [libpari] functions FpXQX_div_by_X_x, FqX_div_by_X_x HIL55- [libpari] function Flx_oneroot_split, zxX_to_FlxX, RgXY_degreex BA 56- [libpari] functions Flv_inv_pre, Flv_inv_inplace, Flv_inv_pre_inplace HIL57- GP function ellissupersingular HIL58- [libpari] functions Fp_elljissupersingular, FpXQ_elljissupersingular BA 59- [libpari] functions umodsu, zx_to_Flx, corediscs 60- GP function qfbredsl2 61- [libpari] functions ell_is_integral, ellintegralmodel, ellQ_get_CM, ellorder_Q, ellap_CM_fast, point_to_a4a6, point_to_a4a6, Fl_elltrace_CM, Fle_changepoint, Fle_changepointinv, Fle_log 62- allow elltors and ellorder for E/K number field 63- GP function ellxn, ellisdivisible HIL64- [libpari] function family Flj_* 65- [libpari] idealprimedec_limit_f, idealprimedec_limit_norm 66- [libpari] modpr_get_p, modpr_get_T, modpr_get_pr 67- GP function nfsplitting HIL68- [libpari] functions Flv_dotproduct_pre, Flx_eval_pre, Flx_eval_powers_pre, FlxY_eval_powers_pre, FlxY_evalx_powers_pre HIL69- GP functions polclass, polmodular BA 70- ellcard over fields of medium characteristic (SEA, Kedlaya, Satoh) 71- GP functions varhigher() / varlower() / variables() BA 72- GP function self() (for defining recursive anonymous functions) BA 73- GP function fold() 74- [libpari] hash_create_ulong, hash_create_str, hash_select, hash_remove_select, hash_keys, hash_values 75- allow serlaplace(t_POL) 76- GP function ispseudoprimepower 77- [libpari] functions FpM_add, Flm_add, FpM_Fp_mul, RgMrow_zc_mul 78- [libpari] function nfembed, nfissquarefree 79- new binary flag to polcompositum: assume fields are linearly disjoint 80- GP function nfcompositum AP 81- [GP] associative and central simple algebra package, functions algabsdim algdisc algisramified algrandom algadd algdivl algissemisimple algrelmultable algalgtobasis algdivr algissimple algsimpledec algaut alghasse algissplit algsplittingdata algb alghassef algleftmultable algsplittingfield algbasis alghassei algmul algsplittingmatrix algbasistoalg algindex algmultable algsqr algcenter alginit algneg algsub algcentralproj alginv algnorm algsubalg algchar alginvbasis algpoleval algtableinit algcharpoly algisassociative algpow algtensor algdecomposition algiscommutative algprimesubalg algtrace algdegree algisdivision algquotient algtype algdim algisdivl algradical algisinv algramifiedplaces 82- [libpari] functions rnf_get_alpha, rnf_get_idealdisc, rnf_get_k 83- [libpari] functions ZC_is_ei, RgC_is_ei, ZM_Z_div, ZMV_to_FlmV, checkal 84- [libpari] functions cbrtr, cbrtr_abs 85- nfinit(rnf) now returns an nf structure associated to rnf.polabs 86- idealprimedec now allows an optional 3rd argument, to limit f(P/p) 87- [libpari] cb_pari_err_handle callback 88- [libpari] function nf_get_ramified_primes 89- Configure --with-runtime-perl option PB 90- Faster matrix multiplication over finite fields 91- allow content(t_VECSMALL) 92- [libpari] ZX_div_by_X_1 HC 93- intnumgauss / intnumgaussinit: Gauss-Legendre quadrature LGr94- GP function sinc HC 95- contfracinit / contfraceval functions HC 96- limitnum / asympnum BA 97- [libpari] functions FlxV_prod, RgV_prod BA 98- GP function ellfromeqn HC 99- gammamellininv, gammamellininvasymp, gammamellininvinit BA 100- [libpari] RgX_Rg_eval_bk, RgX_RgV_eval, RgXV_RgV_eval 101- [libpari] RgX_cxeval HC 102- GP function zetamult PB 103- ZM_mul: Add Strassen-Winograd algorithm 104- GP functions sumnummonien/sumnummonieninit 105- [libpari] RgM_gram_schmidt, RgM_Babai BA 106- GP function cotanh 107- support sign(t_QUAD with positive discriminant) 108- comparison operators (<,>,<=,>=): support t_QUAD with *same* positive discriminant BA 109- [libpari] Flv_prod, Flv_prod_pre BA 110- [libpari] Flv_neg, Flv_neg_inplace ED 111- mingw64 support BA 112- [parallel] new GP function parforvec BA 113- [libpari] Fl_addmul_pre, Fl_addmulmul_pre BA 114- [libpari] Fl_eltwist, Fp_elltwist, FpXQ_elltwist, Flxq_elltwist, F2xq_elltwist BA 115- GP functions elltwist, ellminimaltwist 116- [libpari] omegau, bigomegau VB 117- GP support for 0xffff and 0b1111 (input t_INT in binary or hex notation) BA 118- GP functions ellisomat HC 119- GP function ramanujantau PB 120- Speed up {Flx,FpX,FpXQX}_divrem_basecase for modulus of the form x^n+O(x^m) with m small HC 121- GP function solvestep 122- [GP] New lfun family of functions lfun lfundiv lfunmfspec lfunabelianrelinit lfunetaquo lfunmul lfuntheta lfunan lfunhardy lfunorderzero lfunthetainit lfuncheckfeq lfuninit lfunqf lfunzeros lfunconductor lfunlambda lfunrootres lfunartin lfuncreate 123- [libpari] nfchecksigns, idealchineseinit JD 124- [libpari] gp_read_str_multiline BA 125- [libpari] Flx_nbfact_Frobenius, FpX_nbfact_Frobenius 126- extend idealchinese() to impose sign conditions at specified real places [#1501] 127- [libpari] qfb_equal1, qfi_order, qfi_log, qfi_Shanks 128- [libpari] RgV_kill0 BA 129- factorcantor: use Shoup-Kaltofen algorithm (much faster) BA 130- [libpari] FpX_dotproduct, Flx_dotproduct JK 131- FpXQ_minpoly/Flxq_minpoly: use Shoup algorithm (much faster), and do not assume modulus is irreducible BA 132- [libpari] idealramfrobenius, idealfrobenius_aut, nfgaloispermtobasis 133- Allow ??lfun, ??Lmath, etc. [#1753] 134- [libpari] cyc_normalize, char_normalize, char_check, char_rootof1, char_rootof1_u, bnrchar_primitive, bnrconductor_i 135- GP functions charker, bnrchar 136- bnrconductor(bnr, chi) as a shortcut for bnrconductor(bnr, Ker chi); same for bnrisconductor, bnrdisc and bnrclassno 137- [libpari] real_1_bit(), grootsof1() PB 138- [libpari] Flm_sub, FpM_sub BA 138- [libpari] get_FpXQX_mod, get_FpXQX_degree, get_FpXQX_var, FpXQX_get_red, FqX_get_red, random_FpXQX BA 139- [libpari] get_FlxqX_mod, get_FlxqX_degree, get_FlxqX_var, FlxqX_get_red, random_FlxqX BA 140- Prototype code 'b' and default 'realbitprecision' 141- \pb shortcut [ manipulate realbitprecision ] BA 142- [GP] Map, mapget, mapput, mapisdefined, mapdelete BA 143- [GP] bitprecision BA 143- [arm64] add aarch64 assembly kernel 144- [libpari] ZV_snf_group, ZV_snfall 145- [libpari] znstar0 with Idealstar semantic; could be made available under GP as default znstar, but current znstar/idealstar have incompatible defaults. Called by idealstar(,N). 146- [GP] znconreychar, znconreyexp, znconreylog, znconreyconductor, charorder, charconj BA 147- [GP] call (for calling closures). 148- [GP] optional flag to forell [ loop over isogeny classes ] 149- lfunthetacost, lfuncost SCh150- [mingw] timer: support for user time JD 151- [libpari] pari_completion interface for readline SCh152- [mingw+pthread]: default nbthreads support 153- teichmuller([p,n]) to cache all value at i + O(p^n), 1 <= i < p 154- optional argument 'tab' to teichmuller(x) 155- [GP] function chareval, charmul, chardiv, zncharinduce, zncharisodd 156- [libpari] Flm_intersect 157- [libpari] ggamma1m1 158- allow ispower(t_POLMOD representing a finite field element) 159- [libpari] Fq_ispower, FqX_ispower, RgX_deflate_order, Fq_to_FF, FqX_to_FFX 160- [libpari] Z2_sqrt, divisorsu_fact, usumdiv_fact, usumdivk_fact 161- gphelp -detex: new flag -utf8 to allow utf-8 encoding in output, e.g. render \'{e} as é (the actual eight-bit char) instead of 'e 162- GP function msfromhecke, msgetlevel, msgetweight, msgetsign BA 163- qfisominit: allow to pass the matrix of minimal vectors [#1656] 164- [libpari] GENtostr_raw BA 165- [libpari] FlxqX_halfgcd, FpXQX_halfgcd 166- issquare(t_POLMOD of t_INTMOD) assuming a finite field 167- RgXn_powu, RgXn_powu_i 168- [libpari] is_real_t, R_abs, R_abs_shallow BA 169- [libpari] F2xX, F2xqX, F2xqXQ family functions 170- GP functions rnfidealprimedec, rnfidealfactor BA 171- [libpari] get_FpX_algebra, get_FpXQ_algebra, get_FpXQX_algebra, get_FlxqXQ_algebra, get_FpXQXQ_algebra, get_Rg_algebra 172- E/Qp: Added Mazur-Tate-Teitelbaum's L invariant to E.tate BA 173- [libpari] ZpXQ_div, ZpXQX_divrem, ZpXQX_digits 174- [libpari] ZX_deflate_max, ZX_deflate_order 175- [libpari] idealinv_HNF, idealinv_HNF_Z 176- [libpari] QM_charpoly_ZX_bound BA 177- libpari support for low-res plot() 178- GP function serprec 179- ellap(E, p), ellcard(E,p) for E/K number field, and p maximal ideal 180- [libpari] function sertoser 181- ellan(E, n) for E/K number field 182- [libpari] function gisexactzero BA 183- GP function ellsea 183- [libpari] nfsub, Rg_RgC_sub, Rg_RgC_sub, Z_ZC_sub 184- [libpari] zkchinese, zkchinese1, zkchineseinit 185- [libpari] vecsmall_reverse 186- [libpari] Z_ppio, Z_ppgle, Z_cba 187- ellminimalmodel over number fields 188- [libpari] FpX_factor_squarefree, Flx_factor_squarefree 189- [libpari] checknf_i, checkbnf_i, checkbid_i, checkrnf_i Changed 1- make log(+/-I) return (+/-)Pi/2*I with gen_0 real part [#1556] BA 2- [libpari] rename RgX_mullow -> RgXn_mul, RgX_sqrlow -> RgXn_sqr, RgX_modXn_eval -> RgXn_eval, RgX_modXn_shallow-> RgXn_red_shallow 3- change rnfnormgroup to return [;] instead of raising an error whenever it detects a problem (modulus not a multiple of the conductor, non-abelian extension...): this is a BIB with undefined result, but returning a sentinel is more useful *if* we notice it. 4- [gp] uniformize errors from the % history operator (SYNTAX->MISC) [#1553] 5- t_STR used to compare as larger than any real number via < or > operators. Such a comparison now raises an exception. 6- valuation(0,p), nfeltval(nf,0,pr), idealval(nf,0) now all return +oo poldegree(0) now returns -oo BA 7- rootpadicfast renamed ZpX_roots 8- nfinit: switch from sturm() to ZX_sturm() [Uspensky], and from polroots to polrootsreal (totally real fields). polsturm() now uses Uspensky in most cases. 9- polsturm interface change - polsturm(T, a, b) is still supported but deprecated, use polsturm(T, [a,b]) - polsturm(T, a, b) used to return the number of roots in ]a,b], we now use the closed interval [a,b]: more intuitive given the new syntax, and compatible with polrootsreal() BA 10- [libpari] mkintn: handles arguments as 32bit unsigned int 11- nfdisc, nfbasis: no longer support the old (T,flag,fa) arguments. Use the generic [T,listP] syntax (see 2.6.0-C105) 12- factorpadic: no longer support the deprecated (no-op) 'flag' argument 13- thue() sort solutions lexicographically 14- thueinit tnf format: always include a bnf (also when r1=0), to allow checking for norm equation solutions first: e.g. thue(x^4+1,7*10^80) becomes instantaneous instead of overflowing BA 15- Flx_pow renamed to Flx_powu 16- optional flag to ellheight is gone (useless) 17- ellbil(E,P,Q) is now deprecated, use ellheight(E,P,Q) 18- [libpari] rename ghell->ellheight, mathell->ellheightmatrix BA 19- Rg_to_RgV renamed to Rg_to_RgC, RgX_to_RgV renamed to RgX_to_RgC 20- ellL1(e, r): make r optional (default value = 0) BA 21- powruvec is replaced by powersr 22- [libpari] merge_factor no longer keeps entries with exponent 0 Pmo23- More robust and much faster ellL1 and ellanalyticrank. The condition ord(L_E,s=1) <= r in ellL1(E,r) is no longer necessary. 24- renamed ZV_gcdext -> ZV_extgcd for consistency with other gcdext methods BA 25- setrand now return a (huge) integer instead of a vecsmall 26- unify 32/64 bit random generators. Probabilistic algorithm should now behave identically on all architecture, provided they do not involve the floating point kernel 28- unify 32/64 bit tests 29- move extern(), externstr(), readstr() and system() to the generic part of GP language (was gp-specific). This allows to use them in parallel mode and under gp2c [#1593] 30- made cmprr, cmpri, equalrr consistent with == semantic. We now have, e.g., 0e1==1.0 and (0e1 < 1) = 0 (since 1-0e1 evaluates to 0e1) 31- [libpari] comment out function names obsoleted during the 2.3.* cycle (2007). See PARI_OLD_NAMES. 32- default 'strictmatch' has been obsoleted. It is now a no-op. 33- default 'compatible' has been obsoleted. It is now a no-op. 34- zeta(odd integer): use Borwein's "sumalt" algorithm (10 times faster than previous at \p1000) 35- elltors flags are now deprecated (and ignored, removed corresponding code) 36- add optional flag to nfhnf / nfsnf: return transformation matrices 37- nfroots/nffactor: factor polynomials in Q[X] over Q first BA 38- much faster polresultant over Z 39- GP and libpari polynomial variables of arbitrary priority can now be created: 'x' is no longer guaranteed to have maximal priority, nor MAXVARN to have minimal priority. 40- GP: polynomial variable 'y' is now always defined on startup, with priority lower than 'x' 41- Allow ffgen([p,f]) in addition to ffgen(p^f) and ffgen(T*Mod(1,p)) 42- thue() needed to compute to huge accuracies when regulator was large E.g. t=thueinit(15*x^3+8*x^2-95*x+24,1); thue(t,8) 43- rnf structures may now contain a full absolute nf struct ('nfabs') 44- matkerint: replace underlying LLL algorithm by mathnf Simple bench: M=matrix(50,55,i,j,random(10^5)); \\ 200 times faster 45- allow t_VECSMALL vector exponents in gen_factorback 47- [libpari] rename 'define' PI -> M_PI and use proper constant 48- no longer print 0 t_POLMOD as "0", bug e.g. Mod(0,x). Uniformize code and behaviour with t_INTMOD. 49- warn when coercing quotient rings when 'debug' non-zero ? \g1 ? Mod(1,2)+Mod(1,3) *** _+_: Warning: coercing quotient rings; moduli 2 and 3 -> 1. 50- content([]) -> 0 [ was 1 ] 51- [] / 0 => div. by 0. Now returns [] (as [] \ 0 already did) LGr52- use GRH-guaranteed bounds in bnfinit for residue estimate 53- Configure: avoid inserting unnecessary -L arguments in link line 54- genus2red: change syntax. Allow either genus2red(P) or genus2red([P,Q]) instead of mandatory Q (was: genus2red(Q,P) with Q almost always 0). Allow uniformization with hyperellcharpoly 55- old functions from gp-1.39.15 no longer loaded into an "entree" table, no longer complete specially "whatnow" arguments; remove compat.c and most of gp_init.c BA 56- Rename row_Flm -> Flm_row, row_zm -> zm_row 57- rewrote intnum / intnuminit routines 58- nucomp now takes L = floor(|D|^(1/4)) as a 3rd argument. Former nucomp(x,n) is nucomp(x,n,NULL). BA 59- divide_conquer_assoc renamed to gen_product 60- sumnum algorithm (replace Abel-Plana by Euler-Mac Laurin). Changed the interface ! BA 61- [libpari] concat, concat1 renamed to gconcat, gconcat1 62- rnfconductor now returns [cond, bnr, H] instead of [cond, bnr.clgp, H] 63- nfrootsof1(), more stringent ramification tests: looking for a subfield Q(zeta_p^k) is now faster. 64- intnumromb to use realbitprecision 65- idealstar / ideallog: allow omitting 'nf' argument (for nf = Q; use znstar and znlog internally) 66- improved p-adic log at high accuracy (O(sqrt(padicprec)) algorithm instead of O(padicprec)) 67- allow genus2red to handle (rational) non integral models KR 68- new version of misc/xgp BA 69- rename Flc_Fl_mul -> Flv_Fl_mul, Flc_Fl_div -> Flv_Fl_div, RgC_to_Flc to RgV_to_Flv, F2c_to_Flc to F2v_to_Flv 70- rename leading_term -> leading_coeff, constant_term -> constant_coeff 71- improve gamma(a+O(x)) BA 72- Z_to_Flx now takes a shifted variable number, as Fl_to_Flx. BA 73- improve hash_GEN to reduce # of collisions (change glue) 74- added explicit ways to attach an absolute nf to a rnf structure, allowing rnf functions to return objects in standard notation (e.g. ideals in HNF instead of as a vector of t_POLMOD generators). Add optional flag to rnfeltabstorel, rnfeltdown, rnfeltup, rnfidealreltoabs, rnfinit BA 75- rename FlxqX_pow to FlxqX_powu 76- polredabs([T,listP]) no longer returns 0 if the attached order cannot be proven to be maximal: it computes the expected canonical polynomial in all cases, which can be very slow. Always use polredbest() if you don't require a canonical output. 77- polredabs(T) now internally uses the polredabs([T,listP]) strategy, making it much faster in favourable cases, while still always returning a canonical defining polynomial. 78- precision(0), bitprecision(0), padicprec(0,p) now all return +oo under GP [ used to return LONG_MAX ] 79- meaning of precision(x, n) no longer depends on the type of x: it now always refers to floating point precision. Before the change: precision([O(2),O(3),O(x)], 10) -> [O(2^10),O(3^10),O(x^10)] 80- infinite slopes of newtonpoly replaced by "+oo" (instead of 2^63-1) 81- rename anell -> ellan, anellsmall -> ellanQ_zv BA 82- Fp_ellcard_SEA/Fq_ellcard_SEA meaning of flag has changed. 83- renamed absi_cmp -> abscmpii, absr_cmp -> abscmprr, absi_equal -> absequalii, absi_factor -> absZ_factor, absi_factor_limit -> absZ_factor_limit, equaliu -> absequaliu, equalui -> absequalui, cmpiu -> abscmpiu, cmpui -> abscmpui Removed 1- deprecated functions nfbasis0, nfdisc0, factorpadic0 2- deprecated function manage_var 3- useless function intnuminitgen (not very useful and impossible to use reliably together with intnum with boundary conditions) 4- useless function intnumstep: instead of intnum(a,b, intnumstep()+m), use intnum(a,b,m). 5- partially implemented functions intfouriercos / intfouriersin / intfourierexp / intlaplaceinv / intmellininv / intmellinvshort: use intnum (possibly intfuncinit). Make sure to indicate oscillating behaviour when function decrease slowly at oo 6- optional flag to intfuncinit BA 7- divide_conquer_prod: use gen_product instead 8- useless function sumnumalt 9- badly implemented functions zetakinit / zetak: the interface did not make sense (it is impossible to initialize for Dedekind zeta without specifying a domain where the function is to be evaluated). Closest equivalent to zetakinit: L = lfuninit(x^2+1, [c, w, h]); to compute zeta_Q(i)(s) for |Re(s - c)| < w, |Im(s)| < h. Then lfun(L, s) as an analog to zetak(). Or directly lfun(x^2+1, s) if a single value is needed. [#368, #1647] BA10- [libpari] FpXQX_rem_Barrett, FpXQX_divrem_Barrett: use FpXQX_get_red BA11- [libpari] FlxqX_rem_Barrett: use FlxqX_get_red BA12- [libpari] RgX_RgM_eval_col pari-2.11.2/CHANGES-2.40000644000175000017500000025507212314242551012464 0ustar billbill# $Id$ Bug numbers refer to the BTS at http://pari.math.u-bordeaux.fr/Bugs/ Done for version 2.5.0 (released 31/05/2011): Fixed BA 1- DESTDIR did not work. [#1194] BA 2- Improve Darwin shared library support. LGr 3- bnfinit -> oo-loop if class number is divisible by 27449 [#1197] BA 4- [gp2c] error("foo") did not work. 5- wrong generators in quadclassunit(D > 0) [ fix qfr3_pow / qfr5_pow ] [#1195] 6- setrand(45);quadclassunit(185477) -> SEGV [#1200] 7- fix derivnum for large arguments [#1201] 8- "#if READL" always evaluated to "FALSE" in gprc [#1202] 9- matsnf(non-square matrix, 4) --> SEGV [#1208] HC 10- fix p-adic Gamma inefficiency for small p: gamma(O(2^20))->no answer %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.4.4 (released 29/04/2011): Fixed BA 1- FpX_gcd did not garbage-collect for large input. BA 2- 'make all' failed to build the documentation. 3- typo in polgalois() when new_galois_format is 0 : returned [3,1,2] instead of [3,1,1] for C_3 4- rnfkummer was using too much stack. 5- nfgaloisapply did not work on extended ideals. 6- Strprintf and printf0 prototypes were wrong. 7- Mod(4*x+1,Mod(1,2)*x) -> SEGV [#1116] 8- gcd(t_INTMOD, t_FRAC) -> SEGV 9- qfjacobi failed on a matrix of zeros (or in presence of 0s of large exponent) [#990] 10- t_SER / t_SER where denominator has 0 leading term -> SEGV [#1120] 11- (t_COMPLEX of t_INTMOD) + t_PADIC -> SEGV [#1121] 12- (t_QUAD of t_INTMOD) + t_PADIC -> SEGV [#1122] LGr13- bnfinit: various performance improvement. BA 14- several instance of random garbage collection were broken. BA 15- [install]: support for D0,G, and D"str",s, in prototype code. BA 16- [gp2c]: foo(x:mp)=... did not work. 17- when the divisor's leading term was 0, RgX_divrem(,,&rem) created rem before the quotient (invalidating the use of cgiv() suggested in the documentation) [#1129] 18- gadd(t_COMPLEX of t_REAL, t_QUAD = 0) -> SEGV [#1131] 19- log(11+11^2+O(11^3)) -> bug in log_p [#1136] BA 20- (ffgen(ffinit(2,10))*0)^-1 -> oo-loop BA 21- ispseudoprime(-3,0) != ispseudoprime(-3,1) BA 22- text form of a closure now include the closure context. BA 23- reading compressed files could corrupt the stack. BA 24- t_CLOSURE==t_CLOSURE and t_CLOSURE===t_CLOSURE did not work. 25- gequal1(0.*x + 1) returned 0 26- ispower((100!)^2) -> 0 [#1155] Affected pure powers divisible by more than 22 of the 26 primes <= 101. (introduced in 2.4.3) BA 27- LLL could fail (rarely) due to insufficient precision [#1154] 28- rnfisnorminit(y,x^2-Mod(2+y,y)): polynomial not in Z[X] in nfinit [#1157] 29- factorff failed to merge identical irreducible factors [#1159] BA 30- ploth(x=0,1,0,"Complex|Recursive") -> SEGV [#1163] 31- mathnf(dim > 8) could return a non-HNF upper triangular matrix [#1153] BA 32- forsubgroup() did not handle break/next/return. 33- modular resultant, e.g. rnfequation(polcyclo(17,y), x+y^6,1) [#1151] 34- gequal1(x) / gequalm1(x) did not implement gequal(x, 1) for t_COL/t_MAT 35- matsize(vecextract(M,0,y)) -> [;] instead of matrix with 0 and the requested number of columns [#1170] 36- readline completion : allow commas ',' in directory names [#105] 37- List() == List() returned 0. 38- [Configure] C_INCLUDE_PATH was not used when looking for libgmp BA 39- polroots(1) returned [] instead of []~. 40- a succession of in breakloop context would reinitialize timer 41- matsnf(matdiagonal([x,0])) --> [x,0] instead of [0,x] BA 42- qfbred(large discriminant, small prec): precision too low in truncr [#1173] PMo43- erfc(large x) was slow and inaccurate [#364] 44- erfc() : allow t_COMPLEX inputs 45- stack corruption in ifac_decomp_break() [#1115] 46- factor(0) returned 0^1, but factorint(0) raised an error. Allow factorint(0), core(0), coredisc(0), etc. 47- ellwp, ellzeta, ellsigma only used realprecision, instead of the input precision [#1184] BA 48- tuning for 32bit and 64bit, with or without GMP5. 49- idealintersect(K, 1/2,1/2) -> 1/4 instead of 1/2 [#1192] Changed LGr1- universal constants (gen_0,gen_1, etc.) are now read-only 2- qfjacobi : sort eigenvalues by increasing order 3- [libpari] gtoser : add a third precdl argument. 4- [libpari] swap the last 2 arguments of ellwp0 (prec and precdl) 5- ellwp now outputs a number of terms equal to the default seriesprecision, instead of *twice* that number. 6- Ser, ellwp, taylor, elltaniyama: add an optional 'precdl' argument (by default equal to 'seriesprecision'). One no longer has to rely on (and change locally) a global variable to handle conversion to power series. LGr7- add information to the version() output [backward compatible if version() used as recommended in the documentation] [#1130] 8- O(x^0) is now printed as is, not as O(1). t_SER and t_PADIC are now treated in the same way. 9- inverse trigonometric functions (acos,asin,atan,acosh,asinh,atanh): values on the branch cuts changed to conform to standards, e.g. "implementations shall map a cut so the function is continuous as the cut is approached coming around the finite endpoint of the cut in a counter clockwise direction." (ISO C99) [initial patch Richard Kreckel, #1084] BA 10-[libpari] nf_get_TrInv renamed to nf_get_diff 11- Qfb() : forbid square discriminants (-> corrupted objects [#1145]) 12- allow gequal1 / gequalm1 to return 'true' for t_SER 13- follow-up to (2.4.3, C104) [#1156]: - stop using the undocumented feature Z_factor_limit(x,1) = Z_factor(x). - abide by the "lim" parameter in all cases : factor(100,1 or 2) -> [10; 2] (was [2,2; 5,2]) 14- include GP defaults in the function description system + use standard hashtables instead of ad hoc types 15- cleanup and document term_color() and term_get_color() BA 16- prototype of summations functions now is fun(void *E, GEN call(void*, GEN),...) BA 17- traversesubgroups renamed to forsubgroup. 18- t_QFR with the same coefficients but different distance component are now tested equal by == (they are still different according to ===). 19- bnfinit no longer outputs a warning when fundamental units couldn't be computed (annoying and rather useless) [#1166] 20-[Configure] no longer support a link to an uninstalled readline library in PARI toplevel 21- thue() no longer outputs a Warning when the result is conditional on the GRH. 22- [libpari] rename TIMER -> timer_delay, TIMERread -> timer_get, TIMERstart -> timer_start, msgTIMER -> timer_printf BA 23- polrootsff now returns a t_COL 24- default(a, b) used to return "b". Now returns gnil 25- [libpari] remove allocatemem0 [make it private to GP], write allocatemem 26- matdet() : allow Guass-Bareiss to develop somewhat wrt. rows/columns [ cf test O1 in Lewis-Wester's bench ] 27- addprimes() now includes its argument as-is (used to take gcds, making an insertion linear in the table size instead of O(1); filling an inially empty table was quadratic in the final table size). They must be true primes, otherwise number theoretic routines may return wrong values. [#322] 28- rename fprintferr -> err_printf, flusherr -> err_flush 29- ellpow (CM case). Try to determine the discriminant of the endomorphism ring first [#1186] Added BA 1- trap keyword "syntaxer" to trap syntax error from eval. BA 2- Flx_shift now support negative shift BA 3- [gp2c] add description _(_) for closure evaluation BA 4- PARI function FpX_halfgcd() and subquadratic FpX_gcd(), FpX_extgcd() BA 5- PARI function Flx_halfgcd() and subquadratic Flx_gcd(), Flx_extgcd() BA 6- random() now allow to draw random polynomials BA 7- PARI functions pol_0, pol0_Flx, pol0_F2x VB 8- [mingw] --datadir=@ option to Configure BA 9- PARI functions FlxqX_div 10- PARI function ismpzero BA 11- PARI function bnr_get_clgp 12- new default 'histfile' (to save readline history in between sessions) 13- PARI function cmp_universal BA 14- [gp2c] add descriptions to support intnum/suminf type functions. BA 15- function diffop 16- PARI function zero_Flm_copy 17- PARI function mantissa_real BA 18- PARI functions F2v_clear, F2m_clear, Z_to_F2x, F2x_set, F2x_clear, F2x_flip, F2x_coeff BA 19- PARI functions F2xq_sqrt, F2x_deriv BA 20- PARI functions FpXQ_trace, Flxq_trace, F2xq_trace BA 21- PARI functions FpM_det, Flm_det, F2m_det Removed BA 1- PARI function CM_CardEFp (ellsea script deprecated). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.4.3 (released 08/10/2010): Fixed 1- \h m-n no longer worked BA 2- some error messages displayed internal token names (e.g for '1) 3- named colors in 'graphcolormap' were not portable across graphic drivers 4- setunion(Set(),Set()) -> SEGV [#714] DE 5- [Solaris] pari.desc won't compile [#715] 6- 822.pm broke the formatting of inline program examples 7- memory leaks in pari_close_opts [ freeep(), parser stacks, some defaults... ]. FIXME: calls to getpwuid introduce (small) leaks 8- ZV_Z_mul might not reset clonebit. 9- nfeltreducemodpr --> gerepile errors [#716]. Also SEGV for residue degre > 1 (when p does not divide the index) JD 10- write1("/dev/null", foo);1 --> extra newline JD 11- is_dir_stat() gave incorrect results on special files (pipes,...) JD 12- read() would block on pipes 13- nfeltreducemodpr used different canonical representatives than all other modpr routines [#719] 14- rnfconductor(,,1) did not recognize some abelian extensions [#718] (when the discriminant of a defining polynomial for the absolute number field could not be factored). Related to Changed-4. 15- polgalois could confuse S_11 and F_110(11) if a certain polynomial discriminant could not be fully factored. Related to Changed-4. 16- a = 0./x; a+a --> 0. BA 17- [from 2.4.2] use of pointers in recursive expressions [#717] BA 18- [from 2.4.2] trap() did not restore evaluator states [#722] 19- simplifications missed when adding t_RFRAC [#721] 20- gtofp(1 + 0*I, prec) should not return 1. + 0.*I but 1. gtofp(0 + (tiny real) * I, prec) should make sure the real part is converted to a zero of sufficiently small exponent (otherwise the modulus of the result is zero, because 1E-100 + 0E-28 = 0E-28) 21- factor(500501^36): impossible assignment I-->S 22- quadray(-7,6) [or other "impossible conductors"] --> oo loop [#725] 23- acosh([Pol(1)]) -> gerepile error [#728] (same asin, asinh) 24- rnf functions sometimes do not reduce their output when relative extension has degree 1 [#727] 25- zetakinit(bnfinit(...)) -> gerepile error 26- zeta(1-2^31 or 1-2^63) -> SEGV [#730] BA 27- priority of << had become lower than priority of * (should be =) 28- last digit of polylogs was wrong BA 29- missing GC in the leftrightpow functions 30- bnr=bnrinit(bnfinit(y^2-229,1),5,1); rnfkummer(bnr,,3) --> oo loop 31- mathnf(a,1) could have negative entries if non-trivial kernel [#741] 32- [Configure -pg] some variables not written to pari.cfg 33- missing subfields in nfsubfields [#744] 34- [readline] or would fail on 'fun()'. Delete trailing garbage in help routine. 35- modular matrix inversion routines used O(n^2) inversions instead of O(n) 36- print1() + read() or extern() + error/warning ==> missing \n 37- infinite loop in nffactor [#751] 38- ellordinate couldn't handle t_FFELTs 39- eint1(10,10) completely wrong 40- ispower broken due to 1) uninitialized variable, 2) insufficient precision [#916] 41- compilation fails with yacc unable to handle parse.y [ add explicit rule in Makefile to prevent from generating a wrong one ] 42- duplicate factors in nffactor (easy cases) [#761] 43- ellisoncurve(e, P) didn't check that "point" P had the correct format 44- znlog(...,znprimroot(p)) --> SEGV [#765] 45- wrong signs in bnfisintnorm e.g. [bnfinit(x^3+5), 5] -> x [#767] 46- x/(x+2) * Mod(1,2) -> Mod(1, 2)*x/(x + 2) [ should be Mod(1,2) ] 47- substpol(x/(y^3*x+1),y^2,1) -> x/(y^3*x + 1) [ should be x/(y*x+1) ] 48- missing sanity checks in rnfbasistoalg() 49- setrand(1); E=ellinit([0,0,0,1,T^4]*Mod(1,ffinit(2,7,T))) --> "weird base ring; can't divide" 50- nffactor(nfinit(y),x*y) nffactor(nfinit(y),x^2*y+1) nffactor(nfinit(y),x^2*y) --> errors or SEGV. [#769] 51- hilbert(1,1,1) --> oo loop [#770] 52- nffactor(y^2+1, x+1/2) --> x+1/2 [ not integral ] 53- nffactor(y^2+1,x*y+1) --> x*y + 1 [ not normalized, missing POLMOD ] 54- nffactor(y^2+1,x^2+2*y+1) --> x^2+2*y+1 [ missing POLMOD ] 55- ellpow() with CM raised a "division by 0" instead of returning [0] [#777] 56- ellpow(e,z,2^20*I) --> norm too large in CM. 57- p=x^4-x^3+x^2-x+1; tnf = thueinit(p); thue(tnf,1) -> missing solutions (could occur whenever p has no real root) [#764] 58- missing GC in numtoperm() 59- harmless uninitialized memory read in mulrrz_i() 60- sigma(..., 2) --> SEGV [ introduced in 2.4.1 ] [#783] 61- tuning problems in bnfinit bnfinit(polredabs(quadhilbert(-2939))) --> oo loop 62- minor inaccuracy in GMP kernel (affir) 63- missing GC in gamma / lngamma 64- obscure SEGV when setting 'log' in a file read from command-line as gp foo.gp [#789] 65- check that moduli are compatible in Rg_to_Fp(t_INTMOD, t_INT) 66- matsolve([1;2;3],[1,2,4]~) --> [1]~ (should raise an error) 67- allow polredabs(x in Q[X]) BA 68- [galoisinit] Documentation of "weakly" supersolvable was incorrect. 69- binomial(t_REAL or t_COMPLEX, k) was very slow for large k 70- quadclassunit(-3 or -4) --> one extra (obsolete) component. BA 71- the evaluator did not garbage collect huge expressions [#713] BA 72- changing a function in use caused a crash [#784] 73- vecsort() would not check the type of element in 1-dimensional vector [ e.g. vecsort([I] now raises an error ] 74- RgX_val would raise a SEGV on t_POLs with exact *non-rational* 0 leading coeff, e.g. Mod(0,2)*x 75- SEGV (stack corruption) in idealval(K, rational number, pr) [#808] 76- All the charpoly(x,v) variants failed when v > variable(x) BA 77- conjvec did not support FFELTs. 78- memory leak in t_LIST handling 79- polrootsmod(,1) could return an incomplete result [when 0 was a root or there was a double root], e.g. polrootsmod(x^3 + x^2 + 21*x,23,1) IM 80- lngamma(x) gave incorrect results (off by 2*Pi*I) when real(x) was a negative half-integer. 81- trying to write to a binary file and failing leaked a file descriptor 82- long-standing stack corruption when pressed during gclone [#458] 83- idealaddtoone had problems with 0 ideals [#829] 84- wrong results in qfgaussred() [only totally real case was correct] 85- uninitialized memory read in divrr (both kernels), would only affect the last bit of the result, but could cause SEGV on empty stack. 86- After A=1/(y + 0.); B=1. + O(y); all of A*B, A/B, B/A caused an error 87- wrong result in ellap(E, 2) if bad reduction 88- 0.*x+1 == 1 --> 1 but 0.*x^2+x == x --> 0 [ latter is now 1 ] 89- ffinit(2,30) --> division by 0 [typo in FlxY_Flx_div], [#859] 90- when unexpected exception/signal raised (^C, stack overflow, out of memory), == would cancel it and silently return wrong value [#329] 91- reading recently freed memory in popinfile() 92- contfrac(1,[],-1) ==> SEGV [#865] 93- missing type checks in bnrconductorofchar [#867], nfhilbert [#868] 94- unstable evaluation of tan(t_COMPLEX); at \p9, try ploth(t=-0.1,0.1,abs(tan(10*I+t))) BA 95- Vecsmall([1,1])^-1 returned garbage 96- was not handling nffactor(*huge degree* nf, *non-monic* t_POL) properly --> wrong result and possible memory corruption [#870] 97- polredabs: excessive stack usage [#872] 98- besselj(0., 0) --> error [#880] 99- polred didn't accept non-monic inputs 100- factor(..., 10^100) ==> "overflow in t_INT-->long conversion" [#855] IZ101- missing `const's in groupid.c cause massive copying to stack. 102- [native kernel only] int_normalize() didn't treat properly inputs of lgefint 2 103- gerepile errors in quadclassunit(13).gen or .cyc 104- from_Kronecker & FpXQX_from_Kronecker returned polynomials with invalid first codeword [ unused bits not reset to 0 ] 105- gred_rfrac_simple(n,d) [ basic constructor for t_RFRAC n/d ] did not cater for d = constant polynomial 106- RgX_extgcd created invalid objects in trivial cases [ gen_0 used by RgX-only routines ] BA107- Fix detection for ppc64 running in 32bit mode. 108- Fp_div used remii instead of modii: Mod(3,5)-1/3 -> Mod(0, 5) [#893] 109- trying to prevent accuracy problems in thue() caused oo loop 110- wrong results in matsnf with t_POL entries [#901] minpoly(matrix(4,4,i,j,i/j)) -> x^3 - 4*x^2 + x 111- thue(thueinit(x^3-100,1), 25) -> "Short continued fraction" 112- thue(thueinit(x^3-48, 320) -> missing solutions (similar problem when LHS is a polynomial of degree d and RHS includes a d-th power). 113- completely wrong results in nfsnf 114- intformal(A,Y) -> 1/2*A^2 115- uninitialized memory read in sin / cos / exp (possibly fed random final digits to the algorithm, normally truncated away before returning) 116- nffactor(): SEGV if "relifting" was necessary (very rare) 117- nffactor(): obscure "no factor" bug [when trial division found and extracted *non monic* factors], #930 118- incorrect output type in FpX_factor [#933] 119- possible stack corruption in polylog() + missing imaginary part. 120- incorrect final simplification in idealtwoelt(nf, x, y). Eg: idealtwoelt(nfinit(x^2+23), 3, 6) -> [0, 0]~ BA121- listsort() could return a pointer referencing freed memory: make it return void BA122- src/kernel/ix86/asm0.h had an incorrect #line entry. 123- rnfkummer could miss some fields ( bug in rnfnormgroup() ), e.g. bnrM = bnrinit(bnfinit(X^4 - 34*X^2 + 1189,1), 5, 1); rnfkummer(bnrM, matdiagonal([3,1,1])) 124- nfgaloisconj(y,1) -> invalid object 125- weird error message in ellpointtoz on loss of accuracy [#962] 126- ^C before inital prompt appears ==> SEGV [#965] BA127- ellsea(,,1) did not work BA128- COMPAT file was missing some functions renamed in 2.3: flisexpr, flisseq -> gp_read_str; lisGEN -> gp_read_stream AF129- fix for documentation of polcoeff, extern and readvec BA130- 1/matrix(2,2,i,j,Mod(0, 2)) -> SEGV 131- wrong results for qfminim(A,,,2) if minimal norm < 1. E.g. A = matid(2)/2 BA132- besselk(0.001,1) -> SEGV BA133- galoisinit(x).gen was not a t_VEC 134- lngamma(10^1000) -> precision too low in truncr. Same for psi() 135- nffactor could segfault. [#979] 136- Mod(10,37)^10000000000 -> SEGV 137- missing Flx_renormalize at the end of Flx_mulspec_basecase() & Flx_sqrspec_basecase() [#984] 138- after \y0, [1,x]*[0,0]~ returned 0 t_INT, which should be a t_POL [#983] 139- isprime(x) possibly incorrect on 64 bit machines when 10^15 < x < 2^64 LM140- fix for the documentation of deriv, intformal, poldisc and taylor. JD141- fix for the documentation of install, matsnf and polsturm. LM142- general documentation spelling fixes. BA143- detection of exp2 and log2 was broken with C++ BA144- support for shared library on netbsd. IZ145- [readline] 'foo)' + M-C-b -> infinite loop 146- factorff / polrootsff : wrong result if t_FFELT coefficients in variable 'x BA147- nfisideal did not reject invalid hnf ideal matrices [#999] 148- v=vectorv(1);concat([matrix(0,0),v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v]) -> SEGV [#1002] BA149- minpoly([-5,0,-1,1;0,-5,-1,-1;1,1,-5,0;-1,1,0,-5]/3) -> wrong result[#994] BA150- 2/O(5) -> O(5^-1) (should raise an error) [#1009] 151- factor(13533236897) -> I/O Warning [#1012] BA152- usqrtsafe result could be off by one. BA153- faster algorithm for nfgaloisapply. 154- bnfisnorm: output could have constant t_POL(MAXVARN) components instead of t_INT. E.g. bnfisnorm( bnfinit(x^2+10), 1690 ) [#1026] IZ155- [OS/2] Fix warning about string signedness. IZ156- [OS/2] Fix symbol checking in Configure. BA157- upowuu(2,31) returned a wrong result [#1031] BA158- [from 2.4.2] issquare(x^2+y^2) -> SEGV [#1027] BA159- [from 2.4.2] pointers to Vecsmall components were broken. BA160- [from 2.4.2] ellap could return a wrong result. [#1030] 161- thue() could return wrong results (ZX_Z_normalize() didn't follow its documentation) [#1032] 162- qfminim([1,2;2,1]*1.,,,2) -> SEGV [#1033] 163- [doc] const_col, const_vec: typo in prototype [#1040] BA164- precision(0.E100) returned an invalid object. 165- nbits2nlong, nbits2prec, nbits2nchar : avoid overflow [#1037] 166- normalization problems in RgX_Rg_add & friends, leading to t_POL with sign incorrectly set to 0, e.g. O(2)*x + 1 [#1042] 167- t_FFELT + t_FRAC -> SEGV (missing case in gadd) 168- polred(x) -> stack overflow [#1044] 169- sign of t_POL whose coefficients were all equal to 0 was not always set to 0 (RgX_add / RgX_sub) [#1053] 170- problems with p-adic gamma function : - remove extra digit in Morita's algorithm [ e.g. gamma(1/2+O(3^10)) ] - better threshold between Morita and Dwork's algorithm BA171- qfbhclassno(x) was wrong for x<0 172- subst(t_LIST,x,y) returned a copy without substituting [#969] substvec & substpol didn't work on t_LISTs BA173- RETRY macro was incorrect and could cause crash [#1064] BA174- factorpadic(,,,1) was actually using ROUND4 [#1064 again] 175- nfbasis(x^2+1,,factor(-4)) --> oo loop [#1072] 176- factorpadic: incorrect conversion from ZX to ZpX [#1073] 177- bnfinit() : possible overflow in double -> long conversion [#1099] 178- various inconsistencies in polinterpolate() [#1096] 179- rnfequation() broken when called over the prime field Q [#1079] BA180- F2x_divrem could call bfffo(0) which is not defined. 181- remove restriction on forsubgroup / subgrouplist that cyclic factors of all p-Sylows should have less than 2^32 / 2^64 elements Changed 1- [libpari] prototype of gpmalloc, gprealloc [ return void * ] 2- contfrac(x, b): no longer allow (undocumented) type t_MAT for b BA 3- builtin-in GP functions can now be used as closures. 4- allow nffactor(t_POL, t_POL), nfroots(t_POL, t_POL) [ necessary when nf.disc could not be factored and addprimes() would have to be used ] 5- removed undocumented interface FpM_mul(x,y,NULL), and analogously for FpV_dotproduct, FpV_dotsquare, FpM_FpC_mul 6- [library] major names cleanup; rename *lots* of functions: BSW_* -> BPSW_* Z_factor_limit -> Z_factor_until, auxdecomp -> Z_factor_limit assmat -> matcompanion certifybuchall -> bnfcertify derivpol -> RgX_deriv discf -> nfdisc, nfdiscf0 -> nfdisc0 element_div -> nfdiv, element_divmodpr -> nfdivmodpr, element_mul -> nfmul, element_mulmodpr -> nfmulmodpr, element_pow -> nfpow, element_powmodpr -> nfpowmodpr, element_reduce -> nfreduce, element_val -> nfval factorback0 -> factorback2 factorpadic4 -> factorpadic, factorpadic2 now static fundunit -> quadunit gcmp0 -> gequal0, gcmp1 -> gequal1, gcmp_1 -> gequalm1 Flx_cmp1->Flx_equal1, F2x_cmp1->F2x_equal1, FF_cmp1->FF_equal1 FF_cmp0->FF_equal0, FF_cmp_1->FF_equalm1 ZV_cmp0 -> ZV_equal0 gener -> znprimroot, ggener -> znprimroot0 greffe -> RgX_to_ser (+ change prototype) hil0 -> hilbert, hilii -> hilbertii [ delete useless hil() ] ideal_two_elt* -> idealtwoelt*, idealhermite -> idealhnf initalg -> nfinit, initalgred -> nfinitred, initalgred2 -> nfinitred2 initell -> ellinit, smallinitell -> smallellinit isfundamental -> Z_isfundamental ismonome -> RgX_is_monomial isunit -> bnfisunit matrixqz -> QM_minors_coprime matrixqz2 -> QM_ImZ_hnf matrixqz3 -> QM_ImQ_hnf minideal -> idealmin and change prototype mu -> moebius, gmu -> gmoebius, nfhermite -> nfhnf, nfhermitemod -> nfhnfmod, nfsmith -> nfsnf phi -> eulerphi, gphi -> geulerphi, phiu -> eulerphiu, poldeflate -> RgX_deflate_max polymodrecip -> modreverse powraw -> qfbpowraw, compraw -> qfbcompraw primedec -> idealprimedec racine -> sqrtint, regula -> quadregulator rename cmp_ZV -> ZV_cmp smith2 -> smithall, gsmith2 -> gsmithall srgcd -> RgX_gcd subfields0 -> nfsubfields, subres -> resultant, subresall -> resultant_all. torsell -> elltors and document it zideallog -> ideallog RgXQ_caract -> RgXQ_charpoly ZX_caract -> ZXQ_charpoly ZX_isirreducible -> ZX_is_irred pariputc -> pari_putc, pariputs -> pari_puts, pariflush -> pari_flush, gpmalloc -> pari_malloc, gprealloc -> pari_realloc, gpfree -> pari_free ordell -> ellordinate 7- polvaluation -> RgX_valrem(x, pz) and no longer accept pz = NULL (use RgX_val). Same for ZX_valuation -> ZX_valrem [ & ZX_val ] 8- rename u2toi -> uu32toi [ paste two 32-bit unsigned into a t_INT ] Write uutoi for the more natural operation of pasting two ulongs into a t_INT. 9- prototype of FpX_center [ add one argument ] BA 10- [svn/CVS] number development snapshots according to repository version 11- delete CVS.txt and replace it with README-subversion 12- syntax errors, SIGINT and "PARI bugs" are no longer trapped 13- quadray no longer allows an (optional) 3rd argument 14- 'format' was updated after each 'realprecision' change. Don't update if 'format' is Xm.-1 (show all significant digits). 15- the algorithm used to round t_REAL for output 16- the "minimum field width" component of the 'format' default is now ignored (was used only for integers in 'prettyprint' output mode and defaulted to 0 [no effect]). Use printf ! 17- %Z is no longer a valid conversion specification for PARI formats, since this is now handled as a length modifier. Use %Ps instead (P stands for PARI). 18- remove the (ugly) prettyprint engine ('output' = 2), render as matbrute. printp / printp1 now act as print/print1 19- pariprintf renamed to pari_printf, %Z conversion disappeared (use %Ps) 20- check for small prime divisors in ispower [ large speedup ] 21- the conversion style 'g' of the 'format' default now printfs in style 'f' if the decimal exponent is < -4 ( was: if the binary exponent is < -32 ), in order to conform to standard printf specifications. 22- [GMP kernel] enable GMP exact division 23- matdetint: use less memory + faster finish 24- change the default algorithm for mathnf(a) [ much faster ], flag 0 is no longer deprecated 25- library/GP function galoisinit() now returns NULL/0 on failure (used to raise an exception) 26- allow nfgaloisconj(t_POL, 1) [ cf C-4 ], never resort to nfgaloisconj(,2) [ slow, unreliable ] with default flag = 0 27- [library]: gsub now implemented directly when typ(x) = typ(y) BA 28- all LLL variants now use an implementation of NGuyen & Stehle's algorithm 29- [library]: the "prec" parameter of floating point LLLs has disappeared 30- Vecrev(x) now equivalent to extract(Vec(x), "-1..1") [was only for t_POL] 31- allow t_COMPLEX as well as t_QUAD in ellpow 32- we used to have Set(1) == Set("1") ( = ["1"] ). Now the latter returns ["\"1\""] (the Set whose element evaluate to the character string "1") 33- plotinit: change the way default arguments are evaluated (omit, instead of interpreting 0 in a special way) 34- nfbasistoalg / nfalgtobasis no longer accept t_VEC/t_COL/t_MAT, use matbasistoalg / matalgtobasis, which now also accept t_VEC/t_COL 35- uniformize factornf and nffactor outputs (+ speed them up for non-squarefree inputs: compute valuations mod a suitable prime) 36- treat Mat(t_LIST) as Mat(t_VEC) 37- t_POL^0 always returned t_INT 1 [ try to return 1 in coefficient ring ] 38- polresultant(x,y,,0) now chooses the best algorithm by itself [Ducos, modular, Sylvester], polresultant(x,y,,2) is now a synonym for the default. The change also improves poldisc(). 39- regression tests in src/test/in/ no longer need to end with 'print("Total time spent: ",gettime)' 40- arguments of stirling1 / stirling2 are now ulongs [ were longs ] BA 41- user variables can now be aliased [#790] 42- conjvec(POLMOD of INTMODs) was slow 43- bnfcertify can now handle Zimmert/Minkowski bounds > 2^31 44- moved misc/dico.new to src/whatnow + integrate it in the description system [ new script desc/whatnow ] 45- bittest(x, n) no longer accepts t_VEC arguments n 46- split library function disable_dbg() -> dbg_block() / dbg_release() 47- make the semantics of substpol more precise and less surprising: substpol((x^2+x+1)/(x^2+x-1),x^2,x^3) -> (x^3 + x + 1)/(x^3 + x - 1) [ was: (x^6 - x^3 - 2*x - 1)/(x^6 - 3*x^3 + 1) ] 48- deprecated flag '2' for bnfinit [ don't compute units ] is now ignored ==> bnfunit becomes totally useless. 49- the last component in prime ideals "primedec" format is a number field element, but no longer necessarily in t_COL form 50- no longer allow ideals in *non-square* t_MAT form 51- idealmin now returns a number field element, instead of the associated "principal idele" 52- cleared up the confusion caused by PARI "ideles", which were remotely related to the mathematical notion, and covered two distinct uses. The first one (ideal + list of real places) is now called "divisor"; the second one (ideal + factorization matrix, which used to be a vector of logarithms of complex embeddings) is now called "extended ideal". 53- Allow Scalar + t_COL: x + y returns [ y[1]+x, y[2],... ]. Consistent with RgC_Rg_add and RgV_isscalar, and allows linear algebra over number fields with less rigid data types (can mix freely t_COL, t_INT and t_FRAC, instead of converting everything to t_COL). 54- Functions quadunit(), quadregulator(), and factor() no longer apply componentwise to vector / matrix arguments. Use apply() 55- [libpari] removed obsolete 'prec' argument from prototypes of idealmul0, idealmulred, idealpow0, idealpowred, ideallllred, algdep, algdep0, lindep, lindep0 56- factorback() no longer accepts an optional 3rd argument (nf). Use idealfactorback(). See also nffactorback(). 57- Extend polhensellift to work over unramified extensions of Q_p [ was Q_p only ] 58- [libpari] changed prototypes of bnrdisc, bnrconductor, bnrisconductor 59- slightly change the matrices used in idealmin (round them): the elements returned are a little different. 60- no longer export private library function incgam2. Remove it also under GP when compatible = 3. Like incgam1 (suppressed), 1.39.15 doc stated it was provided "for debugging only". 61- addhelp: TABs are now treated properly (would overflow line without wrapping) and \n are no longer ignored. No longer add a trailing '.' when missing. 62- Useless nfinit flags 4, 5 (partial polred) removed. 63- Split off inline functions unrelated to the kernel from src/kernel/level1.h 64- Swap the order of the 2 arguments to select(): selection function now comes first [ as in apply() ] 65- error() messages now prefixed with the customary *** [ used to be ### ] 66- dvmdiiz(x, y, z) now expects z to be a t_INT [ to be consistent with all other xxxz functions where xxx includes only i,s,u arguments ] 67- improved charpoly(,,2) [ Hessenberg form ] 68- allow Flxq_mul and Flxq_sqr to call Flx_rem_montgomery 69- t_POLMOD * t_POLMOD with same modulus: if all coefficients are in Z/NZ, call specialized functions FpXQ_mul / Flxq_mul [ analog with gsqr, gdiv, ginv, powgi ] 70- bezout(): make sure the leading term of the gcd of 2 polynomials is positive (when it makes sense), as was already the case for gcd() 71- mpcopy, Flv_copy, Flx_copy, vecsmall_copy have all become aliases for leafcopy. 72- trap(,,foo) was actually equivalent to trap(,foo) changing the global exception handler, which was awkward an unintended 73- norml2(t_POL) now returns the expected (square of) the standard L^2 norm. Use x * conj(x) to get back the old behaviour. norml2 now raises an error on t_POLMOD and t_FFELT components; used to add relative norms as in ? norml2([Mod(Mod(1,3)*x,x^2-2), 2]) %1 = Mod(2, 3) 74- [library] kernel functions involving a t_INT and a t_REAL now return a t_REAL, e.g. divsr(0, x) or mulir(gen_0,x) return real_0(...) [ used to return gen_0 ] ==> much better control of object types when writing kernel code. Generic functions (gmul, gdiv), as called from gp still return a result as precise as possible given the input: 0 * 1. --> gen_0 75- [library] cleanup t_COMPLEX arithmetic to take advantage of real parts equal to a t_INT 0. Imaginary parts equal to 0 should never be created by our generic functions (so no need to cater for them specially: they will be very rare, produced by ad hoc routines). Special case trigonometric functions on pure imaginary arguments. 76- kill(z) no longer destroys user variable, only resets them to their "undefined" value (as z = 'z would). 77- [library] prototype of galoisconj [ add one argument ], and made it correspond to the default nfgaloisconj flag 78- allow ordinary sorted vectors in set* functions [ sets are still t_VECs of t_STR, but if components can be directly compared, ordinary vectors are simpler and faster ] 79- allow arbitrary nf entries in relative matrices; nfhnf and nfhnfmod return matrices whose entries may be t_INT or t_FRAC besides the traditionnal nfalgtobasis form. Allow ideals in arbitrary form [was: necessarily HNF] 80- linear algebra routines: determines first whether we are over Z/NZ then call specialized FpM_* routines if possible [fixes #376] 81- [library] commented out a large section of pariold.h. Define PARI_OLD_NAMES to recover compatibility macros for old friends like 'un' and 'lstoi' 82- Mat(t_QFI or t_QFR) now returns the associated 2x2 symmetric matrix 83- [library] rename Buchall -> Buchall_param and export a new Buchall with a simplified interface. 84- trap() no longer allows installing default error handlers. 85- GP's break loop is now *enabled* by default [ set breakloop = 0 in your gprc to disable it ], and no longer controlled by trap(). To get out of a break loop, hit Return three times (next, return, break are no longer accepted) BA 86- factormod and matker: faster linear algebra over F2. 87- remove duplicate polynomials in polred output [#874] 88- let forvec(X = v,...) respect the type of v (t_VEC or t_COL) 89- polred: compute characteristic polynomials as in polredabs [ using complex embeddings, not ZX_charpoly ] PMo90- algorithm for nfrootsof1 now defaults to nffactor: generically a little slower than qfminim, but safer and sometimes much faster (e.g. 1mn against a few hours) 91- added a new component nf_get_roundG to the nf structure [ to speed up ideal reductions ] BA 92- make test-xxx: trap SIGINT in benching script to exit on 93- removed optional flag to rnfconductor, use rnfisabelian. 94- improved dirzetak() by an order of magnitude: e.g. K=nfinit(x^3-10*x+8), dirzetak(K, 10^6) from 4min (2.4.2) to 2.5s 95- renormalize rnfkummer output so that it cannot be written as P(C * x)*C^(-deg P) for any integer C > 1 [ saves large powers of C in disc P ] 96- added a flag to the (mostly useless) function rnfdedekind(), the version with the flag set is a little more useful. Allow list of prime ideals instead of single prime ideal, and make this list optional (omitted = test for maximality at ALL primes) 97- the "zetakinit" format: bnf no longer included 98- thueinit / thue: allow reducible and non-monic polynomials 99- rnfdedekind: allow non-monic polynomials 100- bnrclassno(bnr,id) : allow bid as well as modules for the 'id' argument. 101- GP 'path' now also applies for file paths containing a '/' provided they do not *start* with a '/' (i.e. not an absolute path) 102- [library mode] the function znlog now takes an extra "order" argument 103- added an optional "order" argument to znlog, fflog, elllog, znorder, fforder, ellorder, whose preferred format is [ord, factor(ord)] and ord is the order of the group 104- factor(t_INT/t_FRAC, lim) used to trial divide by primes up to min(lim, primelimit). Now we trial divide up to lim and raise an error if lim > primelimit. [ Having the routine return an obviously "wrong" result depending on an invisible parameter was not a good idea. ] 105- factor(t_INT/t_FRAC, 1) was the same as factor(t_INT/t_FRAC, 0). Now abide by the input value and leave (..., 0) as the single special case (shortcut for "the largest precomputed prime") BA106- [native kernel] Schoenhage-Strassen multiplication/squaring 107- factorff(A, p, T): make p & T optional if A has t_FFELT coefficients BA108- [TLS] Change pari_thread calling convention 109- allow x.a1, ..., x.a6 for an "ell5" x (5-component vector) 110- removed 'primelimit' grom gp_data struct: we now print the actual limit of the primetable, not the value input by the user (which may be a little less) BA111- listsort(L) no longer returns the list L: it now returns nothing. (No point in sorting in place if we must immediately copy the result.) 112- allow component(t_VECSMALL,...) [#957] 113- allow bestappr(x) [2nd argument made optional] BA114- GMP kernel chosen by default when GMP is available BA115- Rename RgXQ_u_pow to RgXQ_powu 116- Darwin: add -search_paths_first to LDFLAGS (try to solve the Editline / Readline conflict in a user-friendly way) BA117- [enable-tls] Library soname changed to libpari[-gmp]-tls[-2.4].so.N. 118- integrate a final polredabs in quadhilbertreal() BA119- Rename leftright_pow to gen_pow, leftright_pow_u to gen_pow_u and implement sliding window powering. BA120- galoisapply now accept automorphisms in t_COL format. 121- allow moduli equal to 0 in matsolvemod (was SEGV) [#947] + rigorously size-reduce the output in all cases. 122- the bnr structure in a minor way (bnr[6] has 3 components now) 123- cleaned up the code used by the GP evaluator to call PARI (and installed) functions. Functions can now have 20 arguments [#795] BA124- galoisfixedfield now accept subgroups. 125- ellap(E, p) second argument now optional if E has t_INTMOD or t_PADIC coefficients. 126- generalize the "generic pivot" strategy to all linear algebra (support RgM_solve and det() in addition to existing functions); implement maximal pivot strategy for p-adics [#1054] BA127- padic_sqrt -> Qp_sqrt, padic_sqrtn -> Qp_sqrtn, gammap -> Qp_gamma 128- rename rnfinitalg -> rnfinit 129- [readline + vi-mode] h/H no longer clobbered by online help. 'h' will now act as expected (= 'move left one character') 130- any of break / next / return now get out of the break loop debugger (as they used to in 2.3) 131- typing thrice no longer gets out of the break loop : use break 132- faster eta(,1), weber() and quadhilbert() [ rewrite using eta's functional equation explicitely ] 133- checked that no 2-strong pseudoprime passes BSPW primality test up to 2^64 (use Feitsma's list, extending Galway's) Added 1- many new benches (make test-all) 2- split up some large monolithic files: new files src/basemath/ RgV.c, FpV.c, ZX.c, ZV.c, concat.c, lll.c, hnf_snf.c prime.c, bit.c src/modules/ QX_factor.c, Hensel.c, DedekZeta.c 3- split off module of general inline functions: src/headers/pariinl.h. 4- Write or rename / document many convenience library functions: pari_calloc, cgetalloc mkfraccopy, mkquad, mkvecsmall4, absfrac, sqrfrac, mul_content, mul_denom roundr_safe, trunc_safe shallowextract, shallowconcat1, concat1, BPSW_psp & BPSW_isprime Z_smoothen, Z_ispower, Z_ispowerall Z_isanypower, chinese_coprime_Z, Z_chinese, Z_chinese_all, Z_chinese_coprime, Z_chinese_post, Z_chinese_pre, Z_incremental_CRT, Z_init_CRT, ZM_incremental_CRT, ZM_init_CRT, ZX_incremental_CRT, ZX_init_CRT, ZX_to_monic, ZX_primitive_to_monic, ZX_squff, ZX_gcd_all, nfgcd, nfgcd_all, RgX_disc, quad_disc, qfb_disc, ZpX_liftfact, ZpX_gcd, ZpX_reduced_resultant, ZpX_reduced_resultant_fast Fp_center, FpM_center, FpV_center Fp_ratlift, FpM_ratlift, FpX_ratlift FpM_FpC_mul_FpX Fp_red, FpXQ_red Flxq_add, Flxq_sub, FpXQ_add, FpXQ_sub, FqXQ_add, FqXQ_sub FqX_add, FqX_sub FqX_roots, FpX_factorff, FpX_rootsff FpXQX_div, FpXQX_rem, FpXQXQ_mul, FpXQXQ_sqr, FpXQXQ_pow FpXQXQ_inv, FpXQXQ_invsafe, FpXQXQ_div FqXQ_mul, FqXQ_sqr, FqXQ_pow, FqXQ_inv, FqXQ_invsafe, FqXQ_div FqX_extgcd ZC_ZV_mul, ZM_is_identity, ZM_copy, ZM_neg, ZM_add, ZM_mul, ZM_pow ZM_max_lg, ZM_sub, ZM_ZC_mul, ZXV_Z_mul, ZM_Z_mul, ZV_Z_mul, ZV_isscalar, ZV_copy, ZV_neg, ZV_neg_inplace ZV_togglesign, ZV_indexsort ZMrow_ZC_mul, ZV_ZM_mul, ZV_cmp0, ZV_content, ZV_equal, ZC_lincomb, ZC_lincomb1_inplace, ZC_z_mul, ZV_prod, ZV_pval, ZV_pvalrem zv_prod ZM_Z_divexact, ZC_Z_divexact, ZX_Z_divexact, ZM_charpoly, Flm_charpoly, Flm_hess Z_ZX_sub, ZX_Z_sub, Fp_FpX_sub, Flc_Fl_div, Flc_Fl_div_inplace, Flc_Fl_mul, Flc_Fl_mul_inplace, Flm_Fl_mul, Flm_Fl_mul_inplace, Flm_copy, Flm_mul, Flm_inage, Flv_Fl_mul_inplace, Flv_add, Flv_add_inplace, Flv_copy, Flv_dotproduct, Flv_sub, Flv_sub_inplace, Fl_order, Flx_nbfact_by_degree, Flx_roots_naive, FF_sub, Fp_mulu, FpV_inv, FpXQ_inv, FqV_inv, FpXY_eval, FpXY_evalx, FpXY_evaly, Flx_Fl_mul_to_monic, FlxqX_Flxq_mul_to_monic, FlxqX_rem, FlxqX_gcd, FlxqX_extgcd, FlxqXQ_mul, FlxqXQ_sqr, FlxqXQ_inv, FlxqXQ_invsafe, pol1_FlxX, FpX_Fp_sub, FpX_Fp_sub_shallow, FpX_Fp_mul_to_monic, FqX_Fq_mul_to_monic, FpXX_Fp_mul, RgM_check_ZM, RgM_det_trianguar, RgM_isdiagonal, RgV_check_ZV, RgV_neg, RgV_add, RgV_sub, RgV_Rg_mul, RgC_neg, RgC_add, RgC_sub, RgC_Rg_div, RgC_Rg_mul, RgM_neg, RgM_add, RgM_sub, RgM_Rg_div, RgM_Rg_mul, RgC_RgM_mul, RgC_RgV_mul, RgM_RgC_mul, RgM_RgV_mul, RgM_mul, RgM_sqr, RgV_RgM_mul, RgV_RgC_mul, RgV_add, RgV_neg, RgV_sub, RgC_Rg_add RgM_diagonal, RgM_diagonal_shallow, RgM_inv, RgM_solve, RgM_mulreal, mulreal, RgX_RgM_eval RgV_sum, RgV_sumpart, RgV_sumpart2 RgX_neg, RgX_add, RgX_add_shallow, RgX_sub, RgX_Rg_add, RgX_Rg_sub, Rg_RgX_sub, RgX_equal, RgX_equal_var, RgX_translate, RgX_to_nfX, RgM_to_nfM, RgC_to_nfC, RgX_type, RgX_type_decode, RgX_type_is_composite, RgX_Rg_divexact, RgXQ_norm, RgXQ_pow, RgXQ_caract, RgXQ_reverse RgXQX_translate, RgXQV_to_mod, RgXQXV_to_mod RgXQX_pseudorem, RgXQX_pseudodivrem, RgX_check_ZX, RgX_check_ZXY, RgX_pseudodivrem, RgX_pseudorem, RgX_recip, RgX_recip_shallow, ZC_hnfrem, ZC_hnfremdiv, ZM_det_triangular, ZM_detmult, ZM_equal, ZM_hnf, ZM_hnfall, ZM_hnfcenter, ZM_hnflll, ZM_hnfmod, ZM_hnfmodid, ZM_hnfmodall, ZM_hnfrem, ZM_hnfremdiv, ZM_hnfperm, ZM_snf, ZM_snfall, ZM_snfall_i, ZM_snf_group, ZM_snfclean ZM_lll, ZM_lll_norms, hnfmerge_get_1, ZXY_max_lg, ZX_copy, ZX_equal, ZX_max_lg, row_Flm, row_zm, scalar_ZX, scalar_ZX_shallow, deg1pol, deg1pol_shallow togglesign_safe, setabssign, zero_Flm, zero_Flv, zero_zm, zero_zv, zm_copy, zv_cmp0, zv_copy, zv_equal, zv_content, zx_renormalize, identity_perm, cyclic_perm, perm_mul, perm_commute, perm_inv, perm_pow, cyc_pow_perm, cyc_pow, perm_cycles, perm_order, vecperm_orbits bitvec_test_set, RgX_get_0, RgX_get_1, resultant, resultant_all, QX_disc, QX_resultant, lllfp, lllintpartial, lllintpartial_inplace, reducemodlll, reducemodinvertible, closemodinvertible, init_primepointer, galoisinit0, get_nfpol, get_bnfpol, get_prid, bnf_get_nf, bnr_get_bnf, bnr_get_bid, bnr_get_mod, bnr_get_nf nf_get_r1, nf_get_r2, nf_get_roots, nf_get_sign, nf_get_roots, nf_get_M, nf_get_G, nf_get_roundG, nf_get_Tr, nf_get_TrInv, nf_get_disc, nf_get_index, nf_get_pol, nf_get_zk nf_get_prec (was nfgetprec), nf_to_scalar_or_basis, nf_to_scalar_or_alg nf_to_Fq_init, nf_to_Fq, Fq_to_nf, zkmodprinit, zk_to_Fq_init, zk_to_Fq, nfM_to_FqM, FqM_to_nfM, nfX_to_FqX, FqX_to_nfX zk_multable, zk_scalar_or_multable, multable, tablemul, tablemul_ei, tablemul_ei_ej, tablemulvec, tablesqr, ei_multable. nfordmax, nfarchstar (was zarchstar), nfadd, nfsign, nfnorm, nftrace nfsign_arch, nfsign_units, nfsign_from_logarch, Buchquad, Buchall, Idealstar, idealaddtoone_i, idealcoprimefact, nfinvmodideal, nfpowmodideal, idealsqr, nfpow_u numberofconjugates, bnrisconductor0, bnrdisc0, bnrconductor0, bnrsurjection, ABC_to_bnr, idealred, idealred0 (was ideallllred), idealred_elt, idealred_elt0 ellinit_padic, ellinit_real, ellinf, ell_is_inf, ell_is_padic, ell_is_real, checkerr_real, checkell_padic, checksmallell, checkell5, checkellpt trueeta, exp_Ir, roots_from_deg1, deg1_from_roots 5- [libpari] public generic hashtables 6- library functions sqrr and invr [ Newton inversion, called by ginv() ] BA 7- library functions checkgroup, galois_group, cyclicgroup, dicyclicgroup, abelian_group, group_domain, group_elts, group_order, group_isabelian, group_abelianHNF, group_abelianSNF, group_isA4S4, group_leftcoset, group_rightcoset, group_perm_normalize, group_quotient, quotient_perm, quotient_group, quotient_subgroup_lift, group_subgroups, groupelts_abelian_group, groupelts_center, group_export, group_ident 8- library functions pr_get_p, pr_get_gen, pr_get_e, pr_get_f, pr_get_tau to access components of prime ideals BA 9- handle numerical derivation as an operation on closure. RB 10- GP functions printf, Strprintf 11- pari_printf, pari_fprintf, pari_sprintf, pari_vfprintf, pari_vprintf, pari_vsprintf BA 12- docpdf and install-docpdf targets (toplevel Makefile) JD 13- add an optional argument to quit() 14- universal constant gen_m2, for symmetry 15- GP function version() [ current version number ] BA 16- [ellap] Port of SEA algorithm from the ellsea GP package BA 17- new alarm GP function and alarmer error code RM 18- partitions() 19- New chapters in Libpari Guide: usersch6.tex, usersch7.tex 20- library function dbg_pari_heap 21- function bnfcompress() [ to create a "small bnf" from a true bnf, to be recoved using bnfinit ]. More consistent than old bnfnit(,3) / bnfmake. 22- a concept of "extended ideal" [I, t], where t is an algebraic number (possibly in factored form). The pair represents the ideal I x (t) In applications the norm of I stays bounded for a given base field, and t keeps track of the "principal part" of the ideal (usually in factored form to avoid coefficient explosion). 23- public interface to forsubgroup: traversesubgroups() 24- library function bnfisprincipal0 (with new public flags, see nf_GENMAT) 25- GP functions nffactorback / idealfactorback JD 26- GP function warning() 27- new flag to charpoly [ integral matrix, modular algorithm ] BA 28- GP function galoisisnormal() BA 29- F2x functions family for polynomials over GF(2) and BA 30- t_FFELT subtype_FF_F2xq for GF(2^n) BA 31- F2v/F2m functions family and F2m_ker for linear algebra over GF(2) BA 32- extra debugging data in t_CLOSURE and debugging facility. BA 33- compile-time copy optimizer BA 34- elliptic discrete logarithm function elllog() BA 35- direct implementation of ZX_mul, ZX_sqr using Kronecker's trick + mulii 36- rnfisabelian GP function 37- default 'recover' 38- more possibilities to draw "random" elements in natural sets using random(), e.g. finite fields, elliptic curve over finite field. 39- GP routines nfeltadd, nfelttrace, nfeltnorm BA 40- Pollard rho discrete logarithm algorithm (function gen_Pollard_log) 41- GP routine polrootsff 42- matadjoint: implement division-free algorithm (flag = 1) [#937] BA 43- GP routines and PARI functions ellweilpairing, elltatepairing and ellgroup BA 44- FpE functions family for points on E(F_p) BA 45- GP routine galoisgetpol and PARI function galoisgetpol, galoisnbpol BA 46- GP routine and PARI function elldivpol BA 47- GP routine and PARI function ellmodulareqn BA 48- function RgXQ_ratlift for reconstruction of rational functions. 49- optional flag to bnfcertify : only check that the correct class group is a quotient of the computed one. VB 50- mingw support VB 51- plotwin32 graphic engine 52- plotQt4 graphic engine BA 53- low-level accessors functions gal_get_* for galoisinit objects 54- libpari functions cvstop2, z_lval, z_lvalrem, z_pvalrem 55- GP function externstr() 56- library function ZC_reducemodmatrix, ZM_reducemodmatrix, ZC_reducemodlll, ZM_reducemodlll BA 57- libpari functions vecsmall_max and vecsmall_min BA 58- GP functions idealfrobenius and idealramgroups BA 59- library functions Zn_sqrt, Zn_issquare 60- library function gidentical BA 61- GP operator === that use gidentical 62- GP function sumdedekind() JD 63- [gphelp] support for bzip2 compressed documentation. Removed 1- obsolete GP functions printp, printp1. Either replace them by print / print1 [ or the new printf ], or define aliases alias(printp, print); alias(printp1, print1) 2- obsolete GP functions bnfclassunit, bnfreg, bnfclgp, bnfunit. Use bnfinit. 3- obsolete GP functions bnrclass. Use bnrinit or bnrclassno. 4- obsolete GP function idealprincipal. Use number field elements "as is" 5- obsolete GP function ideleprincipal. No routine remains that would use the auxiliary "archimedean information" 6- obsolete library functions extract and matextract 7- obsolete optional argument to quadhilbert(D < 0) 8- unused undocumented library functions os_open/os_read/os_close 9- obsolete README.DOS and README.WIN 10- cant_deflate, elliper1, lllger3, varer1, obsoler, infprecer, errlg, errexpo, errvalp, rtodber, affer2, primer2, siginter error codes 11- obsolete library function bruteall 12- useless undocumented library function gkrogs (use krois) 13- obsolete library functions roots2 and rootsold are no longer public 14- useless library function isnfscalar 15- obsolete undocumented library function factpol(), lift_to_pol() 16- library function combine_factors() is no longer public 17- obsolete undocumented library function rnfdet0, rnfdet2 18- obsolete library function discsr(). Use RgX_disc (or quad_disc, qfb_disc) 19- obsolete library function element_powmodidele() [use element_powmodideal + set_sign_mod_idele], ideleaddone, reducemodmatrix, nfreducemodidele, nfreducemodideal, nfreducemodideal_i, elementinv_modpr 20- useless macros gaddgsz, gaddsgz, gdiventgsz, gdiventsgz, gdivgsz, gdivsgz, gmaxgsz, gmaxsgz, gmingsz, gminsgz, gmodgsz, gmodsgz, gmulgsz, gmulsgz, gsubgsz, gsubsgz, gachz, gacosz, gashz, gasinz, gatanz, gathz, gchz, gcosz, gcotanz, gexpz, ggamdz, ggammaz, glngammaz, glogz, gpsiz, gshz, gsinz, gsqrtz, gtanz, gthz, gzetaz, gmaxz, gminz, TRgopgz, mpfloorz, mptruncz, mpdvmdz 21- obsolete library function gmillerrabin, gpolcomp, caradj0 22- obsolete library functions allbase, base, base2, factoredbase, smallbase, discf2, factoreddiscf, smalldiscf. Use nfbasis0 / nfdisc0 / nfmaxord 23- obsolete library function pari_rand31 [ use pari_rand ] 24- obsolete undocumented library function bruterr 25- obsolete library function smallbuchinit 26- awkward flag '3' for bnfinit. Use bnfcompress(). 27- badly named bnfmake. Use bnfinit(sbnf). 28- useless component v[6] in "small bnfs" (was 'different', is 0) 29- obsolete library functions buchray, buchrayinit, buchrayinitgen: use Buchray. 30- obsolete library function smallfact [ use boundfact or Z_factor_limit ] 31- obsolete library function gracine [ use sqrtint ] 32- obsolete library function ispsp, gispsp. Use ispseudoprime or BPSW_psp. 33- obsolete library function gregula, gfundunit, gboundfact. Use quadregulator, quadunit, boundfact 34- obsolete library functions ideallistunit, ideallistunitgen, ideallistzstar, ideallistzstargen. Use ideallist0. 35- obsolete library function algdep2. Use algdep0 (same arguments). 36- obsolete library function Mod0. Use gmodulo. 37- obsolete undocumented library function poldvd. Use RgX_divrem(x,y, ONLY_DIVIDES) 38- obsolete library function kerint1. Use kerint or ZM_lll(,0.99,LLL_KER) 39- header file paritype.h [ split between parigen.h and pariinl.h ] 40- obsolete library functions sor, outbrute, outbeaut 41- dangerous macros max & min [ use maxss/minss, maxuu/minuu, maxdd/mindd ] 42- deprecated global constants gi, geuler, gpi. Use mulcxI/mkcomplex/gen_I(), mpeuler() and mppi(). BA 43- bitvec family function. Use F2v instead. BA 44- useless prototype code 'S'. Use 'r' instead. BA 45- useless function delete_named_var. 46- obsolete and dangerous switch_stack() [#1013] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.4.2 (released 22/12/2007): Fixed 1- divrs(0., negative integer) had the wrong exponent 2- vecsort(,,4) was broken in 2.4.1 3- allocatemem(z) didn't check that z >= 0 [#556] 4- remove hack in internal function 'readbin' that used the clone bit as a special marker hence returned an invalid object, which could be propagated to higher level public functions. BA 5- sqrtn(Mod(a,p),..) and factorff() were broken in 2.4.1 BA 6- bitnegimply(1,2^65) returned a wrong result [#560] 7- nfeltreduce(nf,t_POLMOD,id) didn't work [#558] 8- [library] missing function intfourierexp() 9- segv in polrootspadic / repeated roots in FpX_root (only in deg 2) [#562] 10- log(2+O(4^4)) --> oo loop 11- log(exp(1e-100)) -> 1.000000000149525401279188592 E-100 [ for some accuracies, log & exp inacurate near 1 and 0 resp. ] 12- numbpart inaccurate (and slow). E.g numbpart(52602) off by 1 [#557]. BA 13- &, |, && and || were right-associative instead of left-associative 14- remove type assumptions in mulcxI, mulcxmI: unsafe [#516]] 15- too much memory allocated to print real numbers 16- (y/x)/(x^0/y) not correctly simplified 17- \s reported a misleading number of available user variables 18- 1/(quadgen(-4)*x)+0. -> exponent overflow [#591] 19- sumpos(x=1,1/x^2,1) had the wrong sign [#587] 20- matrixqz(x,0) would not work if first two determinants were 0 + might lose pointers in gerepile 21- sumpos(x=1,0) -> oo loop [#585] 22- qfminim([[;]],,,2) --> SEGV [#598] 23- intformal(1) --> incorrect object 24- intformal(y,x) --> y*y 25- matadjoint(0) --> gerepile error 26- prodinf(x=0,0), prodinf(x=0,-1,1) --> oo loop 27- agm(-1, 1+1e-55) --> oo loop, agm(-1,1) --> wrong result LGr28- killing hi-res graphic window created zombie process (missing wait()) 29- missing type check in eint1(x,n) 30- ploth(...) + Ctrl-C --> hi-res graphic window killed [use pari_daemon()] 31- quadgen([]) --> incorrect object [#606] 32- hyperu(0,1,1) --> oo loop [#608] 33- fix headers so that ulong is always defined 34- read("a b.gz") \\ filename contains a space gzip: ./a.gz: No such file or directory 35- logagmcx inaccurate [ used for log(t_COMPLEX), large precision ] 36- RgX_divrem: prevent "impossible" situations for weird base rings 1/ Mod((y-1)*x-1, Mod(2,6)*x^3-Mod(1,2)*x^2-1) --> SEGV 37- gclone didn't work on t_INTs with lg > lgefint 38- GC error in add_rfrac() [#612] 39- missing type check in subgrouplist [#616] 40- inconsistent type checking in nfeltdivmodpr [#617] 41- nfdisc(x^32+24888960*x^30+227077545803904*x^28+887225199431341086720*x^26+1145458263702669503266741248*x^24-459489127319699704284694158213120*x^22+73430099675988831740428200872826863616*x^20-6599321778961370851005469933592282336329728*x^18+369563540304176984501448638025309170375722401792*x^16-13214618078037183940422584396181416089308059714715648*x^14+291247424536170563676138246427605494527806096141868597248*x^12-3407227562250271661213064368167141844394234574629997803208704*x^10+8699659624155196549893192408316795253695601521375537680749690880*x^8+153390110447793800411208197070089975539253907830958400507847198638080*x^6-34704742472413552993642506624568826441560550586777137133227202205188096*x^4+43389826962123095743039577910848855441856968086933919852164410699581227008*x^2+336462877895453750216450425189196151877685043455706101021513167474262016, 1) --> "not a prime" error (help Round4 to recover when using non-primes, instead of raising immediate errors) [#624] 42- vecextract: C14 in 2.4.0 didn't work for large masks [#623] 43- clean up version handling: move version setting code to config/version and always set PARIVERSION from CHANGES if 'CVS' [ used to require a 'Configure' ] 44- zeta(0e1) --> SEGV [#627], exp(0e1*I) --> SEGV [#630] 45- exp(2^200*I) --> catastrophic cancellation [cos/sin were OK] [#631] DE 46- on NFS filesystems, make install would rebuild all [#503] 47- default(compatible,3); default(compatible,1) --> case no longer taken into account [#629] 48- missing GC in 'sigma' 49- eta(x): valuation would overflow if seriesprecision is large 50- typo in src/kernel/none/mp.c:convi --> inefficiency 51- concat(v) used too much memory (quadratic in #v, make it linear) [#634] BA 52- gp -q -f < eval('y) --> SEGV 53- "significant pointers lost" for objects involving 0 t_SERs [#635] 54- for trivial x, isanypower(x,&p) would not set p MSo55- [Configure] don't rely on $CC exit status, check whether a non-0 size executable is produced [ problems with tcc ] BA 56- wrong Prototype for subgrouplist [ extra 'p' ] 57- hole in 'secure' mode: don't allow changing psfile / logfile [#645] 58- nf.codiff was only correct up to multiplication by some rational number [cf #510 & 2.4.1-F7] 59- cgiv failed to delete the last object on stack [ if recursive ] LGr60- first default(parisize,*) would segfault [due to C-1, #569] 61- pariputs("") --> invalid read of size 1 [ valgrind ] 62- ell.omega, ell.eta, pr.gen could lead to gerepile error [#641] 63- y=[x];eval('y) --> error [#652] 64- incorrect use of gerepileupto in inittestlift [ galoisconj ] 65- extra multiplication in the innermost loop of Cholesky decomposition (qfgaussred, etc). 66- made FpX_add, FpX_sub, Fq_add, Fq_sub stack-clean. FpX_neg, Fq_neg returned an incorrect result if input was not reduced mod p 67- setrand(4);polgalois(x^8-264*x^6+25410*x^4-1054152*x^2+15856203) --> wrong result [#660] 68- build fails with "env: parameter list too long" [#661] 69- factorff did not accept inputs with t_FFELT coeffs 70- could use PARI stack while reading gprc [ before pari_init ] 71- Mod(Mod(1,v),v) --> invalid object. 72- a = Mod(y, v); y = Mod(1,v); eval(a) --> invalid object 73- for some complicated t_RFRAC z: z' --> impossible assignment I-->S 74- typo in bnfisintnorm(): missed some solutions [ couldn't find a unit of norm -1 even though one exists ] 75- ffprimroot(ffgen( t_POL of degree 1)) --> oo loop 76- wrong result in theta(q, z) if sin(nz) was small for some small n [#667] 77- 1/Mod(0,2) --> impossible inverse modulo: Mod(2, 2) 78- alias(a,b), then ?a --> 'a is aliased to a' 79- -Mod(0,2) --> Mod(2,2) MA 80- [Linux-PPC] missing -fPIC in DLCFLAGS 81- possible oo loop in _isprincipal [ precision was supposed to increase, but could in fact remain the same ] 82- quadregulator(y) -> SEGV [#674] 83- acos(x^0) -> division by 0 [ instead of O(x^8), at \ps 16 ] Analogously, acosh(x^0), asin(x^0), asinh(I+O(x)) --> division by 0 84- dilog(-1) [ more generally polylog of < 0 t_REALs ] should have 0 imaginary part 85- problems with [ build/install ] directory names containing spaces 86- avoid catastrophic cancellation in 3M [ Karatsuba ] formula for t_COMPLEX * t_COMPLEX 87- ix86, x86_64: missing earlyclobber constraint for addllx, subllx, divll 88- ploth(,4) --> huge memory use for large plots 89- stirling(0,0,2) --> 0 [ should be 1, #690 ] 90- deriv(x/(x+1),y) --> invalid t_RFRAC with exact 0 numerator [#687] 91- issquare(t_POL) assumed characteristic 0 [#549] 92- sqrt(Mod(4,5) + x) --> error [ e.g. stack overflow ] 93- hyperu(0*I,1,1) --> forbidden assignment t_COMPLEX --> t_REAL. BA 94- fix compilation problem with g++-4.2 and GMP. 95- ??factor_proven, ??factor_add_primes did not work 96- typo in znprimroot: wrong result for large moduli znprimroot(5*2^127+1) --> 2 [#696] 97- ffgen(x*Mod(1,2)) --> x [ should be 0 ] 98- ffprimroot(ffgen((x+1)*Mod(1,2))) --> oo loop 99- nffactor(nfinit(y),x^2+Mod(1,y)) --> SEGV [#699] 100- "precision error in minim0" on qfminim(G, norml2(M[,1]), 100) from tutorial 101- nffactor(nfinit(y^2+1),(2*x+1)*x*(x+1)) --> SEGV [#702] 102- isprime((6^2176+1)/(6^128+1)) --> length (lg) overflow [#697] [ analogous problems for any large integer ] 103- various problems related to allocatemem() [ + document quirks ] Remove the br_ALOCATEMEM construct and end allocatemem0() by a longjmp 104- missing GC in det_simple_gauss() [ matdet for inexact inputs ] 105- rare stack corruption in add_rfrac [#700] 106- add missing GC in gsubst 107- polred([pol, b]) computed unnecessary but possibly expensive invariants of pol [ e.g. disc, index ] 108- compilation failed on AIX [ YYSIZE_T, pow ] 109- ? Mod(1,2)*x + Mod(1,2)*y %1 = Mod(1, 2)*x + (Mod(1, 2)*y) \\ extra parentheses in constant term ? % + 0*z %2 = Mod(1, 2)*x + Mod(1, 2)*y 110- factornf(x^5+(-a+2)*x^4-a*x^3+(3*a-6)*x^2+(5*a-10)*x+(2*a-5), a^2-5) --> SEGV [ not squarefree -> denominators creeping in ] [#708] 111- problems with isexactzero and t_INTMODs. Mod(0,2)*x*1. -> 0, Pol(Mod(0,2))+2 -> 2, (2+0*I)+I*Mod(0,4)->Mod(2,4), Mod(0,2)/x -> 0 Use isrationalzero instead. 112- substvec(x^2, [x^2], [y]) --> y^2 [ should be an error ] 113- typo in FpM_gauss_pivot: FpM_rank, FpM_image, FpM_suppl, FpM_indexrank much slower than they should be. Analogous problem in FqM_gauss_pivot. BA114- missing GP2C descriptions for Pol and Polrev. BA115- zero FFELTs were not considered as exact zeros [#710] 116- rare SEGV in gp when recovering from error (dereferencing global_err_data equal to BREAK_LOOP) 117- vecsort(t_LIST) returned a t_VEC 118- gp "huge file" + stack overflow --> stack overflow in next interactive command (+ minor memoryleak) [#712] Changed BA 1- The combined GP parser/evaluator has been replaced by a bytecode compiler and a bytecode evaluator BA 2- install(): parser code 'E' and 'I' now refer to closures, not strings: 'I': closure whose value is ignored, like in for() loop 'E': closure whose value is used, like in sum() loop 3- Fl_pow renamed to Fl_powu [ exponent may not be negative ] 4- split usersch3.tex moving function documentation to src/functions/* 5- simplify table of contents for users.dvi 6- rename Flx_rand -> random_Flx, FpX_rand -> random_FpX BA 7- use factor_pn_1 to compute various orders in FF.c 8- file usersch3.tex is now generated from functions/* 9- rewrote logr_abs [ inaccurate + slow for x = 2^k * (1 - epsilon) ] 10- rewrote exp1r_abs [ inaccurate + slow ] and mpexp_basecase [ reduce input mod log(2) ] 11- rewrote mpsc1 [ slow ] -> faster sin and cos 12- [library] rename pointch -> ellchangepoint, coordch -> ellchangecurve 13- prototype of constpi, consteuler. 14- use a little less memory to compute pi, euler, log(2) 15- qfminim(x,b,m,flag) made 'm' parameter optionnal also when flag=0 16- made second argument to matrixqz optional, allow non-prime values 17- matpascal(n < -1), mathilbert(n < 0) now raise an error 18- add optional extra argument to ffprimroot, fforder, fflog 19- allow znlog(x,g) where g a t_PADIC or an t_INTMOD modulo any N that znprimroot(N) would accept 20- log(x t_PADIC): check whether x = 1 (mod p) before replacing x <- x^(p-1) 21- znprimroot(p^k): use isanypower() instead of factor(). E.g. znprimroot(nextprime(10^20)^1000): 8mn --> 12ms znprimroot(N) no longer checks reliably whether (Z/N)^* is cyclic. Result undefined if it is not. 22- padic sqrt much faster [ small and large accuracies ] 23- let primes() indicate a value of primelimit if unable to answer [#625] 24- remove variable names from ?0 25- exp(0e10) returned 1.000, made it 0exxx [ no significant digit ] MSo26- define polchebyshev(n, 1 or 2), pollegendre(n) for n < 0 27- znorder faster for non-prime modulus [ try it for Mod(2,5^10*7^10) ] (compute lcm of local p-adic orders) 28- changed icopyifstack / copyifstack macros so that their arguments are GENs, not GENs typecast to long. 29- add -funroll-loops to gcc flags when compiling arithmetic kernel 30- improve ellap (Shanks) by computing #E(F_p) mod 2 [ idea stolen from Pierrick Gaudry ] 31- nfreducemodpr was exceedingly slow for large t_POL inputs, e.g. w=x^48 + 158*x^46 + 4*x^45 + 12103*x^44 + 448*x^43 + 597874*x^42 + 23928*x^41 + 21373779*x^40 + 802424*x^39 + 588314524*x^38 + 18516794*x^37 + 12951694530*x^36 + 294992428*x^35 + 233870773964*x^34 + 2752210590*x^33 + 3524535272389*x^32 - 5797649292*x^31 + 44873186922754*x^30 - 798816466566*x^29 + 486736157075707*x^28 - 18082470992066*x^27 + 4523171646555185*x^26 - 271968456240780*x^25 + 36127625049532658*x^24 - 3144283847234232*x^23 + 248308835345289047*x^22 - 29271322082172250*x^21 + 1467438460133718165*x^20 - 223406933340907742*x^19 + 7435650911902583447*x^18 - 1405525828628464338*x^17 + 32139937168429173010*x^16 - 7272631544138987758*x^15 + 117563850386577478340*x^14 - 30686320483051428956*x^13 + 359649878031434743177*x^12 - 103986861631984042496*x^11 + 904392935429691313557*x^10 - 276283466933590000414*x^9 + 1822091999374665372405*x^8 - 554259164403897051340*x^7 + 2827767569115449802250*x^6 - 788757355446858093774*x^5 + 3170224521565069297504*x^4 - 708295322502763110380*x^3 + 2280480720610858280676*x^2 - 300602103002034938488*x + 788466592242441477569; nf=nfinit([w, nfbasis(w,1)]); modpr=nfmodprinit(nf, idealprimedec(nf,5)[1]); L = nfgaloisconj(w); vector(#L,i, nfeltreducemodpr(nf,L[i],modpr)); (in this example, the last reduction is down from ~ 1minute to ~ 2s) 32- make sure nfmodprininit chooses a monic T to represent Fq ~ Fp[X]/(T) [#646] 33- remove obsolete undocumented functions outerr, outbeauterr, outsor, outtex. Rename voir -> dbgGEN. Functions brute, outbrute, matbrute, outmat, sor, outbeaut are obsoleted and no longer documented. 34- rename errfile -> pari_errfile, infile -> pari_infile, logfile -> pari_logfile 35- extra test infrastructure [ drop file in src/test/in and possibly src/test/[32|64], then run Configure, no need to edit config/get_tests ] 36- inline gerepileupto/gerepileuptoleaf + improve gerepileupto 37- [libpari] cleanup of user / temp variable handling. manage_var obsoleted (kept for backward compatibility, to be removed), see Section 5.9 for new equivalents. Fixes #633, #650 38- fix t_LIST as components: v = [List()]; listput(v[1],) didn't work [#468] 39- listcreate() and listkill() are obsolete, don't use them. L = List() should be enough in all cases. All lists now grow as needed, without requiring an awkward maximal length (from listcreate). 40- rename sqred -> qfgaussred, signat -> qfsign, sqred1 -> qfgaussred_positive 41- rename gaddmat -> RgM_Rg_add and swap arguments. Add RgM_Rg_add_shallow 42- document library functions zv_neg, zm_transpose, fix typo in documentation for RgX_neg 43- document library functions gmaxgs, gmaxsg, gmings, gminsg. 44- document library function gfloor2n 45- document library function zx_shift 46- cleaned up splines handling [ ploth(,,,256) ] : remove quark_gen & QUARK BA 47- implicitly local variables are lexically-scoped BA 48- local and my can now appear anywhere in a program. 49- [library] rename apell -> ellap 50- Removed the OK_ULONG macro and renamed u_OK_ULONG -> SMALL_ULONG 51- Rename BIGINT -> NO_VARIABLE [used by gvar()], VERYBIGINT -> LONG_MAX, MAXULONG -> LONG_UMAX. Remove BYTES_IN_LONG, TWOPOTBYTES_IN_LONG 52- implement directly gsubsg [ was a macro calling a trivial wrapper ] 53- optimize multiplication for quadratic t_POLMOD [ t_QUAD remains faster ] 54- theta(q,z) very inefficient for large accuracies 55- remove support for nf of the form [nf, change of variable] in nfnewprec() [#672] 56- global() now obsolete and scheduled for removal LGr57- 'make ctags' gctags-specific flags [ add #defines, typedefs ] 58- prototype of nfsubfields [ 2nd argument GEN -> long ] 59- allow t_FFELT in issquare / issquarerem / ispower 60- sqrt(t_SER) now uses Newton iteration 61- rename gissquarerem -> gissquareall, uissquarerem -> uissquareall, Z_issquarerem -> Z_issquareall (analogy with sqrtrem was faulty: we do not store a remainder but the square root) BA 62- User functions are now regular variables holding values of type t_CLOSURE 63- Output of \u is now sorted 64- More explicit error messages in gp_history, e.g. *** History result %10 not available [%1-%6] BA 65- vecsmall_uniq(v) no longer assumes that v is sorted 66- allow ellorder to handle curves over Fp, add an optional parameter to indicate a multiple of the order as in znorder. 67- allow polcyclo(n, a) for an arbitrary a [ had to be a variable ] + major speedups: polcyclo(10^6) 5min -> 16ms. Similarly for polchebyshev, pollegendre and polhermite 68- ?0 listed all "user-defined identifiers". Restrict to "functions" 69- use simplify in setsearch() and Set() [#707] 70- change gcd(t_POL, t_POL) so that inexact inputs have scalar gcd [ used to compute a "sensible" approximate gcd ] Added 1- library functions expu, adduu, subuu 2- library functions divisorsu, factor_pn_1 (using cyclotomic factors and Aurifeuille), merge_factor 3- library function divru, dbllog2r 4- library function ZX_gcd, ZX_isirreducible 5- library function gtos 6- library function pari_daemon 7- library function Fp_sqr, padicsqrtlift 8- library function RgXQ_inv 9- bench 'extract' 10- charpoly: Berkowitz division-free algorithm (new default) [#541] 11- library function phiu 12- library function mkvecsmalln 13- library function chk_gerepileupto, dbg_gerepile, dbg_gerepileupto 14- library function gen_sort_uniq, gen_indexsort_uniq+add flag 8 in vecsort 15- library function remi2n, cmp_RgX, gen_cmp_RgX 16- library function RgV_dotproduct, ZV_dotproduct, RgV_dotsquare, ZV_dotsquare, FpV_dotproduct, FpV_dotsquare 17- library function FpX_Fp_add_shallow 18- library function Q_pval BA 19- new keyword "my" to declare lexically-scopped local variables. 20- new GP function listpop() 21- library function RgX_inflate, RgX_deflate, Flx_inflate, Flx_deflate, poldeflate 22- library function Fp_neg, Fp_add, Fp_sub 23- library function ugcd 24- library function vecinv, vecmul, vecpow, vecdiv, vecmodii 25- library function RgM_isidentity, RgV_isin 26- library function nfnewprec_shallow, bnfnewprec_shallow, bnrnewprec_shallow 27- library function Zp_issquare 28- library function dvmdsBIL, divsBIL, remsBIL 29- library functions gassoc_proto, map_proto_G, map_proto_GG, map_proto_GL, map_proto_lG, map_proto_lGG, map_proto_lGL [ were private with other names ] 30- default factor_proven 31- experimental -balloon option to gphelp LGr32- defaults graphcolormap, graphcolors [runtime-defined colormap for plots] LGr33- bit 4096 [ complex ] to ploth 34- member function .p / .mod for t_PADIC 35- same mnemonic flags to plotrecth as in ploth BA 36- member function .pol, .mod and .p for t_FFELT BA 37- New type t_CLOSURE to store GP functions 38- Ability to use arbitrary comparison functions in vecsort() 39- library functions closure_callgen1, closure_callgen2, closure_callgen, closure_callgenvec. 40- GP function apply(), select() 41- library functions FF_issquare, FpXQ_issquare, Flxq_issquare BA 42- library function vecsmall_uniq_sorted 43- bench 'ff', 'exact0' 44- has_getenv.c 45- library function FpX_oneroot 46- library function gcmpX 47- library functions ZV_sort, ZV_sort_uniq, ZV_search Removed 1- obsolete function kbessel2 (now static). Removed optional flag in besselk 2- Removed obsolete optional flag in ellap(), Mod() and gcd() 3- Rename gen_search_aux -> gen_search and document it [ old gen_search disappears: use tablesearch() ] 4- undocumented library functions gpolylogz, polylog, polylogd, polylogp, polylogdold. Use polylog0 with appropriate flags. 5- undocumented library function ghell2. Use ellheight0 with appropriate flag. 6- obsolete function log0; use glog 7- obsolete undocumented library function mpdivz, polzagreel, RgX_powers (use RgXQ_powers) 8- obsolete undocumented library function sqred3 9- the emacs/ directory: PariEmacs is now distributed separately. 10- obsolete functions ellap0, apell2 11- obsolete header file pariport.h 12- obsolete error codes paramer1, valencer1, accurer, caracer1 13- removed obsolete system-specific #ifdefs (macintosh, alliant) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.4.1 (released 28/03/2007): Fixed 1- qflll / qflllgram (t_MAT with t_FRAC entries) would not reduce to the integer case (--> insufficient precision, SEGV) [#505] 2- [Cygwin] missing -L... -lgmp when compiling with gmp. 3- ispower(522^3) -> 0 [ looked like a 7th power to is_357_power(), which then forgot to test for cubes ] [#506] LGr 4- [gphelp] race condition --> incomplete cleanup (improved patch BA) 5- Cleanup library linking: do not link libpari with -ld [only gp], do not link gp with -lgmp [only libpari]. Side effect: libgmp.so no longer needed for modules compiled by gp2c-run 6- when nf.disc < 0, nf.diff was an incorrect PARI ideal [#510] 7- nf.codiff was only correct up to multiplication by some rational number (a divisor of nf.disc) [#510] 8- inaccuracy (>= 2ulp) in [cached] log(2) [#498] 9- exp, sinh, asinh, tanh, atanh were inaccurate near 0 10- [GMP kernel] forvec(x=[[-1,0]],print(x)) --> error [#509] [ 'resetloop' failed when passing through '0' ] 11- nfbasistoalg(nfinit(y),x) created an invalid t_POLMOD 12- incorrect result in ZX_resultant (accuracy loss in bound computation) 13- bnfinit(): avoid further precision problems for large degree fields 14- [Configure] gcc-specific flags were used on linux/freebsd/cygwin, even when __gnuc__ was unset 15- factor( pure power FqX ) --> SEGV 16- [GMP kernel] polrootsmod(f, 4) --> wrong result [ low level t_INT manipulation not using the int_* macros ] 17- polrootspadic(f, 2, r) --> some roots would be found twice [ due to FpX_roots(f, 4) called ] [#521] 18- ??sumalt doesn't compile: in GPHELP, treat \ref in verbatim mode [#518] 19- matinverseimage returned [;] when no pre-image exists. Conform to the docs: "an empty vector or matrix", depending on the input types. 20- [Configure] abort when $CFLAGS is not supported by $CC 21- 3.5 % 2 --> error [ should be 0.5 ] 22- sin(1/10^100) --> 0e-28 [ also affected cos,tan,cotan ] 23- fix e.eta and elleta such that e.eta = 2 ellzeta(e,e.omega/2) [ was ellzeta(e,e.omega/2) ]. COMPAT. 24- elleta(e) was different from elleta(e.omega). Analogous problems in all quasi-elliptic functions. COMPAT: change e.omega so that e.omega[1] / e.omega[2] belongs to the Poincare half plane [ used to be the inverse ]. Together with 24: the Legendre relation now reads w1 e2 - w2 e1 = 2 I Pi Rationale: 1) the action of Sl_2(R) becomes the standard one, not a twisted one 2) fixes quite a few normalization problems in our code. 25- check that k >= 0 in thetanullk [#531] 26- isprime(-2,1) returned 1 27- Fix 'Not enough precision in thue' error BA 28- [OS X] Fix kernel detection on x86_64-darwin 29- Remove "VERY long time" Warning in bnfcertify (few minutes nowadays) BA 30- missing prototype for documented function ZY_ZXY_rnfequation 31- sqrt(x^2/y^2) --> SEGV [#536] 32- \r foo no longer worked if foo was a directory and foo.gp a valid input file [#540] BA 33- [Configure] spectacular failure to recognize gcc under some locales. 34- polredabs(x^8+2*x^6-5*x^4+78*x^2+9) was incorrect [ missed x^8+6*x^6-x^4+54*x^2+25 due to incorrect "skipfirst" ] [#542] 35- typo in resmod2n (both kernels) [#546] 36- At \p28, 0.1 - 0.1 would return 0.E-30 instead of 0.E-29 BA 37- missing prototype for documented function FpX_div_by_X_x 38- isprime(,0) very slow when primelimit is large [#546] 39- nfmodprinit could create FpX's which were not reduced mod p 40- O(x^3)^(1/2) was O(x^2) instead of O(x) RB 41- the following TODO item: v = vector(2); v[1] = v = 0 --> SEGV. Occurs with high probability if any variable is "deleted", while it (or part of it) is still in use Reference count could be helpful here. 42- substpol(x^-2+O(x^-1),x^2,x) --> error [#555] BA 43- [TLS] addss, addsr and subsr were not reentrant. Changed 1- concat(t_VECSMALL, t_VECSMALL) to return the concatenated vector [was: a vector with two t_VECSMALL entries] 2- pariprintf() so that it handles t_STR as print() [ don't include quotes ] LGr 3- [Makefile] make generated src/funclist independent of locale 4- Extend Pocklington-Lehmer to the case N-1 = FU, F > N^(1/3) BA 5- Much faster base-2 to base-10 conversion. BA 6- FpX_Fp_add() is now clean. BA 7- rename ZY_ZXY_resultant -> ZX_ZXY_resultant, ZY_ZXY_rnfequation -> ZX_ZXY_rnfequation and FpY_FpXY_resultant -> FpX_FpXY_resultant. BA 8- FpV_polint() now take a variable number as last parameter. 9- use Miller-Rabin-like improvement in znprimroot and FpXQ_gener 10- indexrank, indexsort and indexlexsort now return t_VECSMALLs 11- API for gen_sort, vecsort Added BA 1- derivnum(x=a,expr) for numerical derivations BA 2- library function strntoGENstr 3- function Vecrev BA 4- ppc64 level0 inline assembly kernel 5- library function floor_safe() 6- library function itostr() BA 7- library function Fp_div(), Fp_mul() BA 8- library function FpXQ_norm() BA 9- library functions FlxX_resultant() and Flx_FlxY_resultant() BA 10- library function FlxY_Flx_div() BA 11- library function Flm_transpose() BA 12- library function Flx_Fl_add() BA 13- library function Flxq_div() BA 14- function stirling (Stirling numbers of 1st and 2nd kind) BA 15- library function FpX_valrem() 16- library function Flxq_gener BA 17- library function Flxq_norm, Flxq_minpoly, Flxq_charpoly BA 18- [toplevel benchmark] ffisom BA 19- library functions Fp_order, FpXQ_order, FpXQ_log, FpXQ_sqrtn, Flxq_order, Flxq_log, Flxq_sqrtn 20- library functions gen_sort_inplace, gen_indexsort, sort_factor, indexvecsort BA 21- New PARI type t_FFELT and support functions (FF_*) for finite field elements. BA 22- functions ffgen, fforder, fflog, ffprimroot for finite field elements. Removed 1- obsolete functions readexpr(), readexpr_nobreak() 2- pariemacs support from Configure 3- obsolete functions sindexsort, sindexlexsort, sindexrank %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Done for version 2.4.0 (released 06/10/2006): Fixed 1- typo in remiimul: wrong result in a "failsafe" branch (hardly ever taken). May affect modular powering /Fp if p >> 10^1300 [#457] Also affects the gmp kernel, for p >> 10^5800. 2- rare accuracy problem in bnfinit P=x^8-787856*x^6+232721637848*x^4-30546112988506688*x^2+1503204734505922286224; setrand(1974190693); bnfinit(P) --> non invertible matrix in gauss 3- inconsistent return type in nffactormod [#460] 4- the following TODO item bnfinit may give wrong answers because we cheat on the value of Bach's bound, using B := 0.3 log^2 D by default, where 0.3 should really be 12 (under GRH). If the prime ideals of norm <= B do not generate the classgroup, we may not detect it, and compute junk. Ex: * setrand(3); bnfinit(y^4 + 1190*y^2 + 1416100).cyc --> [8,2,2,2]. The correct structure is [8,4,2]. * setrand(1414185642); bnfinit(y^4 + 635*y^2 + 403225).reg [twice the correct value] * setrand(867341586); bnfinit(y^4-y^3+6122*y^2+6121*y+37466641).gen[2] [is principal]. Group structure and regulator are correct! Retune check_bach() IZ 5- remove bogus test for "external help" (= ??) IZ 6- [OS/2]: stack check [prevent oo recursion] present but not enabled IZ 7- [OS/2]: bogus [BUG] in 'program' bench (install pb not detected) 8- gammah(1+O(3^5)) --> incorrect type in ggamd. 9- invalid read in copy_leaf [ SEGV in some libc ] BA 10- ellheight short help was accidentally truncated. 11- substpol(1+O(x^(2*n)),x^2,x) --> 1+O(x) instead of 1+O(x^n) [#470] 12- [OS X] only use -no-cpp-precomp with Apple cc 13- divrem(x,x,y) --> [1/y*x, 0] 14- (1+x)/(1-x)/(1+x)^2 not simplified [#472] 15- typo in qflll: in rare cases (exact input+floating point computation+ precision increase in last-but-1 step), the returned base change is not properly updated in last iteration --> basis not LLL-reduced 16- simplification missed in div_scal_rfrac() [ #473 ] 17- ispower(x^k, k) would answer 0 for some x and k in {3,5,7} [#476] 18- content(t_MAT with exactly 1 col) gave a wrong result 19- random(N) was not uniformly distributed in [0,N-1] (use a reject strategy instead of moding out) [#210] 20- rare bug in red_montgomery (returning 0 with + sign, an incorrect object) [ polrootspadic(x^11+x,11,10) --> corrupts gen_0 ] 21- qfbsolve(Qfb(1,2,10),5) --> [0,0; 0,0] instead of 0 [#479] 22- ispower(0, n, &z) would not set z 23- wrong result in conversion t_QUAD -> t_PADIC whenever disc = 1 (4) JJ 24- gaddgsz macro was wrong [#481] 25- gener_Fl(p^k) can't handle k > 1, use gener_Zl instead [#480] SC 26- [GMP] mp_set_memory_functions was called with an incompatible realloc function. [#484] 27- raising a t_QFI or t_QFR to the power n would return a reduced form (OK) except when n = 1. Make it systematic. 28- in rare cases (return 0, native kernel) int_normalize was not suitable for gerepileupto 29- idealnorm(nf, t_POL) didn't work AM 30- [TeXmacs] typo in texmacs_output: x --> [#491] 31- accuracy errors in bnfinit: setrand(3); bnfinit(x^2+999999999999971) [ use a failsafe version of gmod (modr_safe), and increase accuracy if necessary ] 32- possible corruption of gen_2 in mynegi() [ hnflll ] 33- factor(4/x) --> [2, 2; x -1] (content not removed) BA 34- bnrstark prototype code was non-standard. 35- rnfkummer(,,degree) often found too many fields [#482] 36- loss of accuracy in p-adic ellinit: wrong digits and spurious errors: E.g i = 5; ellinit([1, -1, 1, -1, -14]*(1+O(17^i))) 37- missing GC in forvec(,,2) BA 38- Interrupting GP could lead to a freeze. [#488] 39- possible stack corruption in charpoly(,1) 40- Ser(x) raised an error [#499] Changed 1- moved cgiv, gtofp to inline kernel 2- reduce amount of memory needed by APRCL 3- remove CPP from Configure tests (not needed) 4- allow arbitrary sequences (not only expressions) in sum, prod, etc. sum(i = 1, 2, 1;2) --> 4 [ was: error ] 5- checked that no 2-strong pseudoprime passes BSPW primality test up to 10^15 (use Galway's list, extending Pinch's 10^13) 6- random() now uses Brent's XORGEN (replaces congruential linear generator) getrand() returns the FSR internal state array, used by setrand(). The latter no longer returns the input seed. (Initial patch by RR) 7- for install(): parser code 'E' is now obsolete, use 'I' 8- if issquare(x, &n) == 1, always set n to a square root of x 9- if ispower(x, k, &n) == 1, always set n to a k-root of x 10- issquare(t_QFI or t_QFR) now is an error. Use explicitly issquare(component(x,1)) if you relied(?) on the old behaviour 11- [library] rename gener_Fp -> pgener_Fp, gener_Fl -> pgener_Fp [ contrary to 'gener', these assume that their argument is prime ] 12- [library] rename cyclo -> polcyclo, subcyclo -> polsubcyclo, tchebi -> polchebyshev1, legendre -> pollegendre 13- restrict the types allowed in gaffect and gaffsg to scalar types and vectors of such. 14- vecextract(x, bitmask) much faster [ read bits, don't use shifts ] 15- improve hyperu 16- remove gp-specific signal handler. Use the one in libpari 17- [library] pol_1 and pol_x are no longer global arrays but functions 18- [GMP] was inefficient for small sizes (e.g. 1-word operands) 19- optimized rectplothrawin & plot (remove gaffect, use gtodouble whenever possible). Coordinate computations should be faster and more accurate. Added BA 1- function Flm_rank BA 2- Add experimental --enable-tls Configure option and thread-local stack support. Warning: using this option break the ABI. 3- centerlift(t_PADIC) 4- pgener_Zp, pgener_Zl 5- dvdiu, dvdis, dvdiu, dvdsi, affgr 6- cgetipos, cgetineg, togglesign RM 7- polhermite, polchebyshev2 8- allow rnf.zk and rnf.nf 9- [toplevel benchmarks] bnfisintnorm, quadclassunit, rnfkummer 10- ZX_factor, QX_factor 11- allow gzip'ped elldata & galdata files 12- allow t_VECSMALL in vecmin / vecmax BA 13- add pari_stackcheck_init() function to control deep recursion detection 14- Configure --tune flag Removed 1- Odos/Makefile (no longer functional, obsolete) 2- old CodeWarrior-specific hack (malloc) 3- error code: intger2, affer3, overwriter 4- useless static function gp_handle_SIGINT 5- functions changevar() [ use substvec ] and reorder() [ use variable() to get the list of user variables ], global arrays pol_1[], pol_x[] ordvar[] and polvar[] pari-2.11.2/AUTHORS0000644000175000017500000001366313447371554012254 0ustar billbillThe PARI/GP project started around 1985 in the Laboratoire A2X (Universite Bordeaux 1, France) and a first version was written by Christian Batut, Dominique Bernardi, Henri Cohen and Michel Olivier and maintained by Henri Cohen till 1995. Karim Belabas took over the maintainance between 1995 and 2001, the project has been jointly maintained by Bill Allombert and Karim Belabas since 2002. A great number of people have contributed code through the successive stages which eventually resulted in the present version of PARI/GP. Even more people, too numerous to list, contributed by testing, reporting bugs or suggesting improvements, Igor Schein foremost among them. We would like to thank them all here. Current lead developers: Bill ALLOMBERT (Bordeaux) Karim BELABAS (Bordeaux) Major contributors (large modules written or rewritten from scratch): Bill ALLOMBERT: GP2C, the GP parser, extension of the GP language (my, closures), GMP kernel, modular kernel, ffinit, galois* routines, subcyclo, black-box groups, elliptic curves, the elldata and galdata package, multithread model, PARI description system, FLTK support, Bug tracking system, administration of pari.math.u-bordeaux.fr, the http://pari.math.u-bordeaux.fr website, Lfun package Jared ASUNCION: ECPP Christian BATUT: 68k multiprecision kernel, Linear algebra, lattices Karim BELABAS: current project leader, native multiprecision kernel, modular kernel, polynomial arithmetic, polynomial factorization (finite fields, number fields), LLL, primality and compositeness tests, number fields, polgalois and the galdata package, elliptic curves, qfsolve, transcendental functions, install(), extension of the GP language (next/break/return, local, op=, default()), gphelp, gphtml fork, Configure, readline, man pages, documentation layout, reference card and user's manuals, the FAQ, the http://pari.math.u-bordeaux.fr website, Lfun package, ModularForms package Dominique BERNARDI: the original gp interpreter, ECM, original elliptic curves implementation Peter BRUIN: asymptotically fast linear algebra over finite fields Henri COHEN: original designer and project leader, native multiprecision kernel, arithmetic functions, LLL, transcendental functions, number fields, original elliptic curves implementation, numerical integration and summation, Lfun package, ModularForms package Jeroen DEMEYER: SVG support Francisco DIAZ Y DIAZ: number fields (class groups, units) Yves EICHENLAUB: original polgalois implementation Xavier GOURDON: polroots, initial Karatsuba/Toom Cook/fft implementations Louis GRANBOULAN: breakup of monolithic PARI into modules, first GMP kernel, first Configure Loic GRENIE: bnfinit() rewrite, openMP / MPI implementations, polrootsreal/polsturm Bruno HAIBLE: micro assembly implementations, DOS/Windows support Guillaume HANROT: thue, zncoppersmith, initial polrootsreal implementation Hamish IVEY-LAW: ellisogeny, ellisogenyapply, ellissupersingular, Sutherland algorithms for class and modular polynomials (polclass, polmodular), Flj_ functions family. Pascal LETARD: basic number fields (round2, initial round4) Jean-Francois MESTRE: original elliptic curves implementation Pascal MOLIN: Lfun package, numerical integration Gerhard NIKLASCH: binary powering, integer extended gcd and rational reconstruction, primality and compositeness test, integer factorization, documentation layout, AIX and Solaris support, first PARI web site. Michel OLIVIER: 68k multiprecision kernel, number fields, original polgalois and nfsubfields implementation Aurel PAGE: Associative and central simple algebras package, linear algebra over Z/NZ Thomas PAPANIKOlAOU: MPQS integration, Pari-Lidia project Xavier ROBLOT: MPQS integration, Stark, original nffactor, padicfields Denis SIMON: Norm equations, S-units, Hilbert symbols, original qfsolve implementation Nils SKORUPPA: gphtml script, Qt graphics driver Michael STOLL: original 'ratpoints' code Emmanuel TOLLIS: primedec, zetak Ilya ZAKHAREVITCH: prime sieves, gphelp, tex2mail, rewrite of the graphic engine (incl. splines and clipping), GP parser codes, gnuplot support, readline support, OS/2 support, DOS/EMX support Other contributors: the 2 or 3 letter code refer to the CHANGES file. Please, kindly remind us if you have been forgotten! = Karim Belabas (maintainer) AF = Aurimas Fiseras AM = Alex V. Myltsev AMe= Anton Mellit AP = Aurel Page AS = Andy Stubbs AW = Aleksander Wittlin BA = Bill Allombert BD = Bill Daly BG = Brian Gladman BH = Bruno Haible BK = Bruce Kaskel BP = Bernadette Perrin-Riou CB = Cliff Bergman CG = Charles Greathouse CW = Carl Witty DB = Dominique Bernardi DCa= David Carlisle DC = Dan Christensen DE = Denis Excoffier DF = David Ford DS = Denis Simon EB = Erik Bray ED = Eric Driver EP = Esa Peuha FB = Francois Bissey GH = Guillaume Hanrot GN = Gerhard Niklasch GT = Glenn Thobe GTo= Gonzalo Tornaria HC = Henri Cohen HIL= Hamish Ivey-Law HR = Harvey Rose IK = Iwao Kimura IM = Ivan Middleton IS = Igor Schein ISo= Ignat Soroko IZ = Ilya Zakharevich JA = Jared Asuncion JD = Jeroen Demeyer JJ = John Jones JK = Julien Keuffer JM = Jerome Milan JS = Juhana Sadeharju KO = Kiyoshi Ohgishi KPN= Klaus-Peter Nischke KR = Kevin Ryde LG = Louis Granboulan LGr= Loic Grenie LM = Lorenz Minder MA = Michael Abshoff MC = Marie-Angela Cornelie MD = Mark Dickinson MH = Marije Huizing MS = Michael Stoll MSo= Michael Somos MW = Mark Watkins NS = Nils Skoruppa OR = Olivier Ramare OV = Oliver Voigt PB = Peter Bruin PC = Phil Carmody PM = Peter Montgomery PMo= Pascal Molin PW = Paul van Wamelen RB = Remi Butel RM = Richard J. Mathar RS = Ralf Stephan RR = Randall Rathbun SC = Sylvain Chevillard SCh= Steven Charlton SG = Scott Garee TH = Teluhiko Hilano TP = Thomas Papanikolaou VB = Vasili Burdo VBr= Volker Braun VD = Vincent Delecroix VL = Vincent Lefevre XR = Xavier Roblot YU = Yoshiaki Uchikawa WH = William Hart pari-2.11.2/COMPAT0000644000175000017500000014206013326135265012075 0ustar billbillThis file lists the incompatible changes between Version 2.x and older versions %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.10 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - the bid struct from idealstar has changed, the new format is not compatible with pari-2.9 - the rnf struct from rnfinit has changed, the new format is not compatible with pari-2.9 - the bnrdisclist output is now and ordinary vector (not a vector of vectors) - sumnummonieninit(a) for [a,a] did not conform to documentation. Change to sumnummonieninit(b) for [1,b] - lfuncreate() change of format for (p,d)->Lp closure: - Lp here and in bad primes [p,Lp] must now use the actual local factor and not its inverse - d is now the exact number of terms needed (was 1 less), i.e. one need only return Lp + O(x^d) - bad primes are given as a separate 2nd component: [Lp, [[p1,L1],...[pk,Lk]]], not as [Lp, [p1,L1],...[pk,Lk]] - nf struct: nf[7] now stores nf.zk / content(nf.zk). Old format is still supported (to read in data involving old-style nf generated by gp version < 2.10) but incurs a speed penalty. - component(t_POL T, n) used to return polcoeff(T, n-1) for all n >= 1 [ undocumented compatibility behaviour, deprecated since the introduction of polcoeff ], and raised an exception for n <= 0. Now returns a true GEN component whenever it exists and raises an exception when it does not [ n <= 0 or n > polcoeff(T)+1 ]. - For T in Q_p[X], factor (round then compute multiplicity) and issquarefree (assume input is separable) did not agree. Now, factor() repeats irreducible factors according to apparent multiplicity (note that the multiplicity is not well defined for inexact inputs, which are close to being inseparable, i.e. v_p( disc(T) ) is large compared to the input accuracy). OTOH, factorpadic with exact input is able to compute multiplicities reliably. - change polred-type algorithm to return 'x' (no longer 'x-1') for the field of rational numbers (make it consistent with polredabs). The documentation now only guarantees a 'polynomial of degree 1' - ellisomat: ellisomat(E,flag) is now ellisomat(E,,flag) - changed the definition used in polred / polredbest / polredabs to decide what is the "best" polynomial to return. This had never been specified in the documentation; while making explicit the de facto choices made in the code, it was decided to make it mathematically more appealing. There is no efficiency tradeoff involved: we are just replacing an arbitrary definition by another less arbitrary one, with the same implied costs. - ellpadicmatrix now returns a pair of matrices (instead of a matrix whose entries are pairs of values) - ellpadicheight and ellpadicmatrix no longer accept [p,[a,b]] arguments; use * [a,b]~ - msissymbol now returns a GEN (gen_0/gen_1) instead of a long - V=galoisfixedfield(P,,2): return V[1] in the same variable as the coeffs of V[3] instead of P. - numtoperm now returns a t_VECSMALL (so that results can be multiplied as permutations, etc.), no longer a ZV - The functions psdraw, psploth and psplothraw and the default psfile are obsolete. Use one of plotexport, plothexport or plothrawexport with format "ps" and write the result to file. - isprime(n,1) no longer outputs a certificate, use primecert(n) - isprime(n,1) no longer uses APRCL for large prime divisors of n-1 (pure Pocklington-Lehmer-Selfridge); use primecert(n). - removed useless (optional) flag argument in polrootsmod - factorff and polrootsff are now obsolete. Use factormod/polrootsmod - Ser(s, 'x, d) now always return a series with d significant terms. It used to return a t_SER s in 'x verbatim and to use all given coefficients for a t_VEC/t_COL. Only if d is explicitly given, no change for Ser(s,'x) - renamed algsplittingmatrix -> algtomatrix - algleftmultable now always returns the multiplication table on the integral basis - merged algdecomposition + algsimpledec -> algsimpledec - merged algabsdim + algdim -> algdim - merged algleftmultable + algtomatrix -> algtomatrix - ellmoddegree now only returns the modular degree D (divided by c^2), not [D, err] - polcoeff is deprecated and renamed polcoef: it now only applies to scalars, polynomials, series and rational functions; no longer to vector/matrices or quadratic forms (use [] or "component"). - in prettymatrix format, no longer print all 0 x n matrices as [;]: use [;] iff n = 0 and matrix(0,n) otherwise * Specific to the PARI library: =============================== - renamed buchnarrow -> bnfnarrow - removed useless argument nf in ZC_nfval, ZC_nfvalrem, pr_equal, ZC_prdvd - prototype of FlxX_shift has changed - renamed FpX_fromdigits -> FpXV_FpX_fromdigits - renamed FpXQX_fromdigits -> FpXQXV_FpXQX_fromdigits - rename vecbinome -> vecbinomial - rename padic_lindep -> lindep_padic, Xadic_lindep -> lindep_Xadic - keri and ZM_ker_ratlift replaced by ZM_ker - Fl_addmul_pre: change arguments order to follow Fp_addmul convention - removed resultant_all, use RgX_resultant_all - rename {FpXQXQ,FlxqXQ,F2xqXQ}V_aut{sum,trace,pow} -> {FpXQXQ,FlxqXQ,F2xqXQ}_aut{sum,trace,pow} - RgX_type now only handles t_POL. Use RgX_type for other objects. - changed ZM_inv: remove denominator bound and replace by pointer to denominator - changed QM_inv interface: removed second argument (useless) - useless function Flx_roots_naive; rootmod and rootmod2 are now an alias for polrootsmod (both have been deprecated for years). rootmod0 is just as obsolete. - matsolvemod0 is deprecated, use matsolvemod - cmpiu / cmpiu, equaliu / equalui : no longer assume that t_INT argument is non-negative - rename diviu_rem -> absdiviu_rem, udiviu_rem -> uabsdiviu_rem, udivui_rem -> uabsdivui_rem - rename polcoeff0 -> polcoef, truecoeff -> truecoef, polcoeff_i -> polcoef_i - rename constant LOG2 -> M_LN2 (from math.h if available) - rnf_get_nfzk / nf_nfzk / nfeltup interface (czknf was useless, return and use nfzk) %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.8 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - removed useless function sumnumalt: use sumalt - replace algorithm behind sumnum / sumnuminit : replace Abel-Plana (slow, imprecise, forced to assume holomorphy and evaluate at complex values, yielding determination problems) by Euler MacLaurin (none of these disadvantages). The interface had to change : the (mandatory) abscissa of integration becomes meaningless, and the initialization possibilities are different. Please read the documentation ??sumnum and ??sumnuminit - t_STR used to compare as larger than any real number via < or > operators. Such a comparison now raises an exception. - valuation(0,p), nfeltval(nf,0,pr), idealval(nf,0) now all return +oo under GP [ used to return LONG_MAX ] - precision(0), bitprecision(0), padicprec(0,p) now all return +oo under GP [ used to return LONG_MAX ] - infinite slopes of newtonpoly replaced by +oo (instead of LONG_MAX) - poldegree(0) now returns -oo [ used to return -LONG_MAX ] - polsturm interface change * polsturm(T, a, b) is still supported but deprecated, use polsturm(T, [a,b]) * polsturm(T, a, b) used to return the number of roots in ]a,b], we now use the closed interval [a,b]: more intuitive given the new syntax, and compatible with polrootsreal() - nfdisc, nfbasis: no longer support the old (T,flag,fa) arguments. Use the generic [T,listP] syntax (see 2.6.0-C105) - factorpadic: no longer support the deprecated (no-op) 'flag' argument - optional flag to ellheight is gone (useless) - ellbil(E,P,Q) is now deprecated, use ellheight(E,P,Q) - default 'strictmatch' has been obsoleted. It is now a no-op. - default 'compatible' has been obsoleted. It is now a no-op. - GP and libpari polynomial variables of arbitrary priority can now be created: 'x' is no longer guaranteed to have maximal priority, nor MAXVARN to have minimal priority. - GP: polynomial variables no longer spring into existence unless a true t_POL/t_SER in the variable is needed. E.g. y = 0 does not create the "variable" y, thereby messing up variable ordering. - genus2red: change syntax. Allow either genus2red(P) or genus2red([P,Q]) instead of mandatory Q (was: genus2red(Q,P) with Q almost always 0). Allow uniformization with hyperellcharpoly - remove useless function intnuminitgen (not very useful and impossible to use reliably together with intnum with boundary conditions) - remove useless function intnumstep: instead of intnum(a,b, intnumstep()+m), use intnum(a,b,m) - remove partially implemented functions intfouriercos / intfouriersin / intfourierexp / intlaplaceinv / intmellininv / intmellinvshort: use intnum (possibly intfuncinit). Make sure to indicate oscillating behaviour when function decrease slowly at oo - remove optional flag to intfuncinit: misleading and only affords a 2 x speedup in an 'init' function (maybe reimplement later in a more general form...) - remove badly implemented functions zetakinit / zetak: the interface did not make sense (it is impossible to initialize for Dedekind zeta without specifying a domain where the function is to be evaluated). Closest equivalent to zetakinit: L = lfuninit(x^2+1, [c, w, h]); to compute zeta_Q(i)(s) for |Re(s - c)| < w, |Im(s)| < h. Then lfun(L, s) as an analog to zetak(). Or directly lfun(x^2+1, s) if a single value is needed. [closes #368, #1647] - rnfconductor now returns [cond, bnr, H] instead of [cond, bnr.clgp, H] - polredabs([T,listP]) no longer returns 0 if the attached order cannot be proven to be maximal: it computes the expected canonical polynomial in all cases, which can be very slow. Always use polredbest() if you don't require a canonical output. - meaning of precision(x, n) no longer depends on the type of x: it now always refers to floating point precision. Before the change: precision([O(2),O(3),O(x)], 10) -> [O(2^10),O(3^10),O(x^10)]. Now in order to truncate a p-adic or series, you have to multiply by 1 + O(t^n); in order to extend it, use truncate. - remove useless flag in idealappr: directly allow factorization - replace qfbil(x,y,{q}) by qfeval({q},x,y) and qfnorm(x,{q}) by qfeval({q},x): it makes more sense to have q first, and a single function for qf+polar form (as in all other qf-like routines: ellheight, etc.) - functions nfeltdivmodpr, nfeltmulmodpr, nfeltpowmodpr, nfeltreducemodpr, nfkermodpr, nfsolvemodpr are obsolete. Use nfmodpr, work in the finite field, then lift back using nfmodprlift. - changed bnf format (allow dynamically adding units): old bnfs will be detected as invalid. Dirty trick to force conversion: bnf[10]=vector(3); - changed idealstar format, to access data more conveniently (and avoid recomputations): old bid and bnr structures from versions up to 2.8.0 are now invalid - gcd(t_VEC/t_COL/t_MAT, ...) is now forbidden, same for lcm * Specific to the PARI library: =============================== - renamed RgX_mullow -> RgXn_mul, RgX_sqrlow -> RgXn_sqr, RgX_modXn_eval -> RgXn_eval, RgX_modXn_shallow -> RgXn_shallow - top and bot are replaced by pari_mainstack->top and pari_mainstack->bot. - allocatemem() is replaced by paristack_resize. - rootpadicfast was renamed to ZpX_roots - mkintn() now handles arguments as 32bit unsigned int on both 64/32 bits. - sturmpart(x, a, b) is deprecated, use RgX_sturmpart(x, ab) or (better) ZX_sturmpart(x, ab) - removed deprecated functions nfbasis0, nfdisc0, factorpadic0 - Flx_pow renamed to Flx_powu - [libpari] rename ghell->ellheight, mathell->ellheightmatrix - Rg_to_RgV renamed to Rg_to_RgC, RgX_to_RgV renamed to RgX_to_RgC - powruvec was replaced by powersr - renamed ZV_gcdext -> ZV_extgcd for consistency with other 'gcdext' methods - comment out libpari function names obsoleted during the 2.3.* cycle See PARI_OLD_NAMES. - ellsea is replaced by Fp_ellcard_SEA - rename PI -> M_PI - renamed row_zm -> zm_row, row_Flm -> Flm_row - nucomp now takes L = floor(|D|^(1/4)) as a 3rd argument. Former nucomp(x,n) is nucomp(x,n,NULL). - divide_conquer_assoc renamed to gen_product, divide_conquer_prod removed - rename concat to gconcat, concat1 to gconcat1 - rename Flc_Fl_mul -> Flv_Fl_mul, Flc_Fl_div -> Flv_Fl_div, RgC_to_Flc to RgV_to_Flv, F2c_to_Flc to F2v_to_Flv - rename leading_term -> leading_coeff, constant_term -> constant_coeff - Z_to_Flx now takes a shifted variable number, as Fl_to_Flx. - rename FlxqX_pow to FlxqX_powu - rename anell -> ellan, anellsmall -> ellanQ_zv - ellsea: the argument p was removed and the interface modified - renamed absi_cmp -> abscmpii, absr_cmp -> abscmprr, absi_equal -> absequalii, absi_factor -> absZ_factor, absi_factor_limit -> absZ_factor_limit, equaliu -> absequaliu, equalui -> absequalui, cmpiu -> abscmpiu, cmpui -> abscmpui - idealappr0 is obsolete: use idealappr - qfbil, qfnorm are obsolete: use qfeval0, qfeval or qfevalb - changed set_sign_mod_divisor prototype: module is now useless (implicitly contained in sarch argument), hence removed. - removed discrayabs, discrayabscond, discrayrel, discrayrelcond, discrayabslistlong: obsoleted since 2.0 - ZpX_liftfact no more handles extensions of Qp, use ZqX_liftfact for that - rename listcreate to mklist %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.6 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - eval() no longer evaluates its arguments in "permissive" mode: eval("1a") now produces a syntax error. - '|' is no longer a synonym for '||' (boolean 'or'); '&' for '&&' is still supported but deprecated. - GP set elements are no longer converted to t_STR (requiring "eval" to recover the underlying object). Arbitrary GENs can be stored in a set. - no longer allow 3 arguments in bestappr() [useless], no longer mix Pade approximants and continued fractions [too confusing: must a t_SER be converted to a t_RFRAC or be treated coefficientwise?]. Use bestapprPade() to obtain rational functions, and bestappr() to obtain rational numbers. - [non-Unix systems] the name of the preferences file is now "gprc.txt" (it remains ".gprc" on Unix systems) - removed rootsold() code : polroots(x, 1) is no longer accepted. - format of cached Bernoulli table: now a t_VEC of t_FRAC / t_REALs. Removed bern() macro. The new data must be accessed using bernfrac / bernreal. - forprime loop: no longer allow to modify the loop index ? forprime(p = 2, 10, p = []) *** at top-level: forprime(p=2,10,p=[]) *** ^--- *** prime index read-only: was changed to []. - rename ellpow -> ellmul - polrootsmod(, 4) is no longer accepted. The second argument must be prime. - binary(0) now return [] - arithmetic functions no longer accept vector / matrix arguments [ to later allow passing factorization matrices ]: use apply() - permtonum/numtoperm now use the standadr lexicographic numbering. - ellsigma: removed flags 3 and 4 [ inefficient algorithm using the product formula ] - removed member function 'w' (this is technical, and no longer needed:-) - ellpointtoz(E / Qp, ...), now return phi(P) [ used to return the same result for phi(P) and phi(-P) [ split multiplicative reduction ], resp. phi(P) + 1/phi(P) [ non-split reduction ] - ellinit(E / Qp).tate : the u component is now always a square root of u2, also in the non-split case (in which case it lives in a quadratic extension of Qp) - when timer = 1, no longer print timing if the time is negligible; in particular, no timing should be printed when defining a user function or and alias. - change nfbasis(T, flag, fa) to nfbasis(T, listP). flag was used to invoke round2 instead of round4 (inefficient=> useless) OR to only partially factor poldisc(T), up to primelimit (very dangerous since primelimit is a global variable). Now listP describes a list of primes, and we return a basis of an order which is p-maximal at all those primes: either a vector of primes, a factorisation (as fa before) or an integer B to indicated {p <= B} (a safe and flexible version of nfbasis(T, 1)). nfdisc() was changed similarly. - The proper way to initialize an nf structure when the polynomial discriminant is hard to factor is nfinit([T, listP]), where listP specifies a list of primes (see ??nfinit). nfdisc, nfbasis, all the polred functions allow analogous arguments. This is cleaner and more flexible than optionnal flags relying on the value primelimit (e.g. nfinit([T, nfbasis(T, 1)]), now deprecated). Also, the nfinit function now sees the local specifications directly and can take steps to fix problems. The result can also be certified (nfcertify) - renamed bezout() -> gcdext(), polresultant() -> polresultantext() - the prime table is now computed once and for all on startup and can no longer be increased by modifying primelimit: the dynamic forprime machinery allows fast primes up to primelimit^2 which is more than enough even with a small table. The default value of 500.000 is already larger than necessary - removed optional flag to factorpadic() / factorpadic0() [ enabling Buchman-Lenstra + round2 ] Use the default factorpadic(T, p, r), both under GP and in library mode. - default help text for a user function is now as in \u: ?fun produces fun = (args)->body - after addhelp(f,...), ?f no longer include default help text for a user function (function code). Type 'f' to see the function code. - rnf structure: added new components - lift(x,'v) / centerlift(x,'v) now only lift t_POLMODs in variable v, no longer (most) t_INTMOD / t_PADICs met along the way - rnf.pol (absolute defining polynomial / Q) is now called rnf.polabs, rnf.pol is now the relative polynomial, defining the relative extension over the base. - the prid structure returned by idealprimedec: the anti-uniformizer tau (pr_get_tau / pr[5]) is now stored via its multiplication table * Specific to the PARI library: =============================== - renamed all libpari error codes [ pari_err() arguments ] - ellwp0(): remove precdl argument - rename stackmalloc -> stack_malloc - rename ggval -> gvaluation - simplify init_primepointer(n, p, &pd) interface => init_primepointer(n, &pd). Remove argument 'p', ignore the previous value of pd [ remove assumption that it pointed into a prime table ] and always set pd to a pointer into the private prime table. - powell, addell, subell renamed to ellpow, elladd, ellsub. - last tow arguments of FpX_factorff and FpX_rootsff have been swapped. - rnf_fix_pol() takes an extra argument, the calling function's name - rename leftright_pow_fold -> gen_pow_fold, leftright_pow_fold_i -> gen_pow_fold_i - upowuu(x,n) now returns 0 on overflow. Used to return x^n mod 2^BITS_IN_LONG - rename RgX_check_ZXY -> RgX_check_ZXX, ZXY_max_lg -> to ZXX_max_lg - removed gisfundamental, gkronecker, gbigomega, geulerphi, gissquarefree, gmoebius, gnextprime, gnumbdiv, gomega, gprecprime, gsumdiv, gdumdivk, znprimroot0 - rename zv_cmp0 -> to zv_equal0 - removed obsolete function weipell(). Use ellwpseries() - the prototype of nfbasis() changed [ remove 'flag'; if you needed it, use nfmaxord() ]. The old nfbasis0 / nfdisc0 are deprecated: don't use them. - removed obsolete Polred(): use polred() or polredbest() - rename exp_Ir -> expIr - the *_invimage function no longer accept a t_COL second argument. Use the RgM_RgC_invimage variant. They now return NULL when no solution exist (used to return a t_COL / t_MAT of length 1) - the forvec_start() function has been replaced by a standard iterator: forvec_init() / forvec_next() - renamed rnfelementxxx -> rnfeltxxx, rnfidealhermite -> rnfidealhnf - removed useless wrappers map_proto_GG, map_proto_GL, map_proto_lGG - renamed ZM_hnfremdiv -> ZM_hnfdivrem - removed useless functions gand, gor - removed useless function ratlift [ use Fp_ratlift ] - renamed gcmpX -> gequalX - renamed ordred -> polredord: useless function, use polredbest! - renamed recip -> serreverse - renamed FlxYqQ_pow -> FlxYqq_pow - FpXYQQ_pow/FlxYqq_pow: the order of the moduli S,T have been swapped to match FpXQXQ_pow - renamed gsh -> gsinh, gch -> gcosh, gth -> gtanh, gash -> gasinh, gach -> gacosh, gath -> gatanh, ggamd -> ggammah (follow GP names) %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.4 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - The "break loop" is now *on* by default, and no longer controlled by trap(), but by the default 'breakloop'. To get out of a break loop, hit or type 'next', 'return', or 'break' - trap() no longer allows installing default error handlers. - GP's break loop is now *enabled* by default [ set breakloop = 0 in your gprc to disable it ] - random() now uses Brent's XORGEN (replaces congruential linear generator) As a consequence, getrand() returns the FSR internal state array, used by setrand() and the prototypes of both functions changed. To adapt simple library code, replace long seed = getrand(); ...; (void)setrand(seed); by GEN seed = getrand(); ...; setrand(seed); The sequence of generated pseudo-random numbers are completely different. - install(): parser code 'E' and 'I' now refer to closure, not strings: 'I': closure whose value is ignored, like in for() loop 'E': closure whose value is used, like in sum() loop - changevar() [ use substvec ] and reorder() [ use variable() for the list of user variables ] have been removed - The quasi-periods e.eta (and elleta(e)) are now twice the old value, so that e.eta = 2 ellzeta(e,e.omega/2) - Change e.omega so that e.omega[1] / e.omega[2] belongs to the Poincare half plane [ used to be the inverse ]. - indexrank, indexsort and indexlexsort now return t_VECSMALLs - besselk no longer admits a flag, the default implementation caters for all cases - removed (obsolete) optional flag in ellap(), Mod() and gcd() - the weird extra argument to listcreate() [ maximal length ] has disappeared. In fact, listcreate() is now obsolete: juste use List() to create an empty list. It will grow as needed. - listkill() is also obsolete: no need for a specific function to kill old lists floating around. L = List() reclaims memory just as efficiently as listkill(L) would. In most cases, you won't even need that, e.g. local variables are automatically cleared when a user function returns; no need to kill the ones which are lists specifically. - local variables declared implicitly (user function parameters, loop indices) are now lexically-scoped. The keyword 'my' allows to declare lexically-scoped variables explicitly. - global(), being awkward to implement in the new parser model and essentially useless is now a no-op, scheduled for removal. - PariEmacs is now distributed as a separate package, and is no longer included in the PARI distribution - distinction between user functions and user variables has been removed. As a consequence, calling a user function without parentheses no more evaluate it. - syntax errors are no longer trap-ped, only runtime errors are. First, error trapping and compile-time errors are best left unrelated. Second, since the code is first byte-compiled, then evaluated, it made no sense trapping a syntax error that would necessarily occur in the first milliseconds after inputing the command to the interpreter. (Not so in the old evaluator which could notice syntax errors very late, and one was happy to be able to still salvage something when it bombed.) - quadray no longer allows an (optional) 3rd argument: was not properly documented, broke the symmetry between real / imaginary case (was ignored if D > 0), complicated the code, and was rather useless in any case. - the "minimum field width" component of the 'format' default is now ignored (was used only for integers in 'prettyprint' output mode and defaulted to 0 [no effect]). Use printf ! - removed the fieldw "minimum field width" field from the undocumented pariout_t struct - remove obsolete "prettyprint" support: printp / printp1 now act as print/print1 - the conversion style 'g' of the 'format' default now printfs in style 'f' if the decimal exponent is < -4 ( was: if the binary exponent is < -32 ), in order to conform to standard printf specifications. - all LLL variants now use an implementation of NGuyen & Stehle's algorithm The LLL-reduced bases will be different from previous versions. - plotinit: change the way default arguments are evaluated (omit dimension, instead of interpreting 0 in a special way) - nfbasistoalg / nfalgtobasis no longer accept t_VEC/t_COL/t_MAT (not being able to apply nfbasistoalg to nfalgtobasis(nf,x) was awkward and inconsistent; the doc stated that those were inverse functions, but they were not). Use matbasistoalg / matalgtobasis, which now also accept t_VEC/t_COL. - removed obsolete optional argument to quadhilbert(D < 0) - removed obsolete GP functions printp, printp1. Use print. - bittest(x, n) no longer accepts t_VEC arguments n - remove obsolete GP functions bnfclassunit, bnfreg, bnfclgp, bnfunit. Use bnfinit. - remove obsolete GP functions bnrclass. Use bnrinit or bnrclassno. - remove awkward flag '3' for bnfinit. Use bnfcompress(). - remove badly named bnfmake. Use bnfinit(sbnf). - idealmin now returns a number field element, instead of the associated "principal idele" - removed obsolete GP functions idealprincipal. Use number field elements "as is". - Functions quadunit(), quadregulator(), and factor() no longer apply componentwise to vector / matrix arguments. Use apply() - factorback() no longer accepts an optional 3rd argument (nf). Use idealfactorback(). See also nffactorback(). - no longer export private library function incgam2. Remove it also under GP when compatible = 3. Situation is the same as incgam1 (removed long ago), 1.39.15 doc stated both were provided "for debugging only". - Change of behaviour for Set(t_STR): Set("1") used to return ["1"], now it returns ["\"1\""], i.e returns the set whose element evaluates to the character string "1". - Flags 4, 5, 6 (useless) have disappeared in nfinit() - norml2(t_POL) now returns the expected (square of) the polynomial L^2 norm. Use x * conj(x) to get back the old behaviour. norml2 now raises an error on t_POLMOD and t_FFELT components; used to add relative norms as in ? norml2([Mod(Mod(1,3)*x,x^2-2), 2]) %1 = Mod(2, 3) - kill(z) has essentially the same effect as z = 'z [ it also kills addhelp messages attached to z, and works for aliases and installed functions too ] - removed optional flag to rnfconductor, use rnfisabelian. - changed the "zetakinit" format: bnf no longer included - factor(t_INT/t_FRAC, lim) used to trial divide by primes up to min(lim, primelimit). Now we trial divide up to lim and raise an error if lim > primelimit. [ Having the routine return an obviously "wrong" result depending on an invisible parameter was not a good idea. ] - factor(t_INT/t_FRAC, 1) was the same as factor(t_INT/t_FRAC, 0). Now abide by the input value and leave (..., 0) as the single special case (shortcut for "the largest precomputed prime") - listsort(L) no longer returns the list L: it now returns nothing. (No point in sorting in place if we must immediately copy the result.) - ellwp now outputs a number of terms equal to the default seriesprecision, instead of *twice* that number. - inverse trigonometric functions (acos,asin,atan,acosh,asinh,atanh): values on the branch cuts changed to conform to standards, e.g. "implementations shall map a cut so the function is continuous as the cut is approached coming around the finite endpoint of the cut in a counter clockwise direction." (ISO C99) - bnfinit no longer outputs a warning when fundamental units couldn't be computed (annoying and rather useless) [#1166] -[Configure] no longer support a link to an uninstalled readline library in PARI toplevel - thue() no longer outputs a Warning when the result is conditional on the GRH. - addprimes() now includes its argument as-is (used to take gcds, making an insertion linear in the table size instead of O(1); filling an inially empty table was quadratic in the final table size). They must be true primes, otherwise number theoretic routines may return wrong values. [#322] * Specific to the PARI library: =============================== - allocatemoremem() is gone. Use allocatemem(). - rename fprintferr() -> err_printf(). - rename TIMER -> timer_delay, TIMERread -> timer_get, TIMERstart -> timer_start, msgTIMER -> timer_printf - rename gener_Fp -> pgener_Fp, gener_Fl -> pgener_Fp [ contrary to 'gener', these assume that their argument is prime ] - rename Flx_rand -> random_Flx, FpX_rand -> random_FpX - rename cyclo -> polcyclo (GP name), subcyclo -> polsubcyclo (GP name), tchebi -> polchebyshev (GP name), legendre -> pollegendre (GP name) - only scalar types (and vectors/matrices of such) are allowed in gaffect and gaffsg. - pol_x and pol_1 are now functions, not global arrays. Use pol_x(v) instead of pol_x[v]. polvar[] and ordvar[] have disappeared - rename ZY_ZXY_resultant -> ZX_ZXY_resultant, ZY_ZXY_rnfequation -> ZX_ZXY_rnfequation and FpY_FpXY_resultant -> FpX_FpXY_resultant - FpX_ functions no longer accept p==NULL. - Fl_pow renamed to Fl_powu [ exponent may not be negative ] - rename pointch -> ellchangepoint, coordch -> ellchangecurve, ordell -> ellordinate - remove obsolete undocumented functions outerr, outbeauterr, outsor, outtex. Rename voir -> dbgGEN. Functions brute, outbrute, matbrute, outmat, sor, outbeaut are obsoleted and no longer documented. - rename errfile -> pari_errfile, infile -> pari_infile, logfile -> pari_logfile - manage_var obsoleted (kept for backward compatibility, to be removed), use pari_var_init, pari_var_next, pari_var_max_avil, pari_var_create instead. - rename sqred -> qfgaussred, signat -> qfsign - rename gscalmat -> scalarmat, gscalsmat -> scalarmat_s, gscalcol -> scalarcol, gscalcol_i -> scalarcol_shallow - removed obsolete apell2, ellap0. Rename apell -> ellap. - typedef for type col_counter [last argument of unused, undocumented plot_count()] changed (must be malloced since MAX_COLORS is no longer a constant) - rename gissquarerem -> gissquareall, uissquarerem -> uissquareall, Z_issquarerem -> Z_issquareall (analogy with sqrtrem was faulty: we do not store a remainder but the square root) - rename assmat -> matcompanion, polymodrecip -> modreverse - removed obsolete undocumented bruteall() - %Z is no longer a valid conversion specification for PARI formats, since this is now handled as a length modifier. Use %Ps instead. - rename pariprintf -> pari_printf (%Z conversion disappeared, use %Ps) - rename pariputc -> pari_putc, pariputs -> pari_puts, pariflush -> pari_flush - rename gpmalloc -> pari_malloc, gprealloc -> pari_realloc, gpfree -> pari_free - rename derivpol -> RgX_deriv - obsolete library functions roots2 and rootsold are no longer public - rename factorpadic4 -> factorpadic, factorpadic2 now static - the "prec" parameter has disappeared in all floating point LLL various - remove obsolete function factpol() - rename library functions nfhermite -> nfhnf, nfhermitemod -> nfhnfmod, nfsmith -> nfsnf - rename subres -> resultant, subresall -> resultant_all. - remove obsolete discsr. Use RgX_disc (or quad_disc, qfb_disc...) - remove obsolete allbase, base, base2, factoredbase, smallbase, discf2, factoreddiscf, smalldiscf. Use nfbasis0 / nfdisc0 / nfmaxord - rename library functions matrixqz2 -> QM_ImZ_hnf, matrixqz3 -> QM_ImQ_hnf, matrixqz -> QM_minors_coprime - rename library functions hil0->hilbert, hilii->hilbertii - rename library functions srgcd -> RgX_gcd - rename library functions ismonome -> RgX_is_monomial - remove obsolete buchray, buchrayinit, buchrayinitgen: use Buchray. - rename library functions minideal -> idealmin and change prototype - rename library functions element_mulmodpr -> nfmulmodpr, element_powmodpr -> nfpowmodpr, element_val -> nfval, element_add -> nfadd, element_divmodpr -> nfdivmodpr, element_mul -> nfmul, element_pow -> nfpow, element_div -> nfdiv. - remove obsolete library function smallfact; use boundfact or Z_factor_limit - rename mu -> moebius, gmu -> gmoebius, phi -> eulerphi, gphi -> geulerphi, phiu -> eulerphiu, gener -> znprimroot, ggener -> znprimroot0, racine -> sqrtint [ NO COMPATIBILITY #define PROVIDED: too dangerous ] - rename regula -> quadregulator, fundunit -> quadunit - remove obsolete library function gracine - remove obsolete library function ispsp, gispsp. Use ispseudoprime or BPSW_psp. - remove obsolete library function gregula, gfundunit. Use quadregulator and quadunit - removed obsolete 'prec' argument from prototypes of idealmul0, idealmulred, idealpow0, idealpowred, ideallllred, algdep, algdep0, lindep, lindep0 - removed obsolete library functions ideallistunit, ideallistunitgen, ideallistzstar, ideallistzstargen. Use ideallist0. - removed obsolete library function algdep2. Use algdep0 (same arguments). - removed obsolete library function Mod0. Use gmodulo. - factorback() now accepts a single argument. - rename library functions factorback0 -> factorback2, subfields0 -> nfsubfields, ideallllred -> idealred0, zideallog -> ideallog, isunit -> bnfisunit, ideal_two_elt* -> idealtwoelt* - changed prototypes of bnrdisc, bnrconductor, bnrisconductor [ actually renamed bnrdisc0, bnrconductor0, bnrisconductor0 ]. Just use the new prototype, it's more convenient. - removed obsolete library function kerin1. Use kerint or [simpler if LLL reduction of the returned basis is not deisred] ZM_lll(,0.99,LLL_KER) - rename library functions initell -> ellinit, smallinitell -> smallellinit initalg -> nfinit, initalgred -> nfinitred -> initalgred2 -> nfinitred2 primedec -> idealprimedec, powraw -> qfbpowraw, compraw -> qfbcompraw - rename library function u2toi -> uu32toi. - remove obsolete library functions sor, outbrute, outbeaut - basic kernel functions involving a t_INT and a t_REAL now return a t_REAL, e.g. divsr(0, x) or mulir(gen_0,x) return real_0(...) [ used to return gen_0 ] ==> much better control of object types when writing kernel code. Generic functions (gmul, gdiv), as called from gp still return a result as precise as possible given the input: 0 * 1. --> gen_0 - deprecated global constants gi; use mulcxI, gen_I() or mkcomplex(). - deprecated global constants geuler & gpi; use mpeuler() & mppi(). - changed prototype of galoisconj: galoisconj(x) -> galoisconj(x,NULL) - commented out a large section of pariold.h. Define PARI_OLD_NAMES to recover compatibility macros for old friends like 'un' and 'lstoi' - rename greffe -> RgX_to_ser and remove the "use_pari_stack" flag - rename Buchall -> Buchall_param and export a new Buchall with a simplified interface. - rename certifybuchall -> bnfcertify - the bitvec family function was replaced by the new F2v family functions. - prototype change: added a flag to the (mostly useless) function rnfdedekind(), the version with the flag set is more useful. - rename gcmp0 -> gequal0, gcmp1 -> gequal1, gcmp_1 -> gequalm1 - rename ZX_caract -> ZXQ_charpoly and swap arguments. - rename RgXQ_u_pow -> RgXQ_powu - remove function delete_named_var (using kill0 instead). - remove RgM_ishnf (use ZM_ishnf instead). - rename leftright_pow to gen_pow, leftright_pow_u to gen_powu. - remove unused 'prec' argument in rnfinitalg(). Rename rnfinitalg -> rnfinit - remove unused 'prec' argument in bnfisnorm() - add a third precdl argument to gtoser() - the last 2 arguments of ellwp0 (prec and precdl) have been swapped - prototype of "summation" functions (suminf,intnum,prodinf,etc.) now is fun(void *E, GEN call(void*, GEN),...) %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * General: [ use GP function names in description ] ========== - Default args for user defined functions now evaluated when function is called (used to be: at definition time) E.g f(x) = local(z = x); z. Before: f(2) -> x Now: f(2) -> 2 - rnfisnorm() input format has changed. Older version was complicated and only worked if rnfequation(bnf, p, 1)[3] == 0 [otherwise, crash]. Use rnfisnorminit() now. - rnfidealreltoabs, rnfidealup: now return a Z-basis as a vector of elements in the relative extension, instead of a meaningless HNF matrix wrt an unknown basis. Was especially dangerous if the extension also existed in nfinit form, since the HNF matrices were _not_ ideals wrt this nf structure. [ also consistent with rnfeltreltoabs ]. Use the following construction instead, referring to an explicit NF structure: \\ return y = rnfidealup(rnf,...) as an ideal in HNF form associated to \\ nf = nfinit(rnf.pol); idealgentoHNF(nf, y) = mathnf( Mat( nfalgtobasis(nf, y) ) ); - the "bit accuracy component" for computations of principal ideal generators (bnfisprincipal), units (bnfunit), and some of the bnf structures has been removed. - the "technical parameter" to bnfinit() has been shortened to 3 components (the others were deprecated / useless): [c, c2, nrpid]. The output format has changed (technical components). - poldegree(0) now returns -VERYBIGINT, not -1. Before using d = poldegree(x), always check for 0 first: either (x == 0) or (d >= 0) as you prefer. Never check for d == -1 or -2^31-1 which is not portable. - ellheight now uses the standard normalization: twice the value it used to return. The values returned by ellbil() and ellheightmatrix are unaffected. In particular, ellheightmatrix() is the polar form of elleight(), and ellbil now satisfies the proper identity B(P, Q) = (h(P+Q)-h(P)-h(Q)) / 2 - ':' no longer allowed as a substitute for ';' if compatible = 0. Use GP2C semantics [ x:int, v:vec ]. For the time being the type information is discarded. - log(x, {flag}): optional flag removed. Decide alone whether to use AGM. - valuation(x, 1) used to return 1, valuation(x, -1) returned 0 if (x >= 0) and 1 otherwise. Not anymore: error message. - bnrdisclist has lost its 4th argument 'flag', and omitting the archimedean component now means that all 2^r1 possible values are substituted (formerly: indicate no ramification at infinity). - 'buffersize' default has disappeared: it is adjusted internally whenever needed. The -b xxx flag to gp is a no-op. - the member function bnr.zkst is deprecated, use bnr.bid.clgp - the member function bnr.futu is deprecated. Please don't use bnr.tufu either. - use \frac instead of \over in TeX output. Define \def\frac#1#2{{#1\over#2}} if you insist on using plain TeX and run into problems. - automatic concatenation for strings: use longest match for expression. print("a"[1]) is not valid since "a" is not a vector print("a", [1]) prints 'a[1]'. - isprime() now guarantees primality, use ispseudoprime() for fast pseudo-primality tests. - default() now always returns the value of the (possibly changed) default. No need for a flag anymore. - semantic of t_SER with inexact coefficients is now the same as for t_POL: the sign is 0 iff all coefficients are zero. Either there are no coefficients, or the leading coefficient is an inexact zero. - No longer assume that part of an object is "permanent" when it is out of the stack (was used by INTMOD/POLMOD/PADIC). Always copy it. As a result, 'gmodulo' and 'forcecopy' become obsolete. Rename gmodulcp -> gmodulo. * Specific to the PARI library: =============================== Incompatible changes: --------------------- - gsize() -> gsizeword() [conflict with gtk] taille2 -> gsizebyte() - hnfhavas removed (didn't work properly, hnflll provides an alternative) - real zeroes are now coded on 2 words. Beware of constructs like t = cgetg(lg(x), t_REAL); gaffect(y, t). If x = 0, so will be t. - polgalois(): old format deprecated. New preferred format for result has 3rd component giving numbering among all transitive subgroups of S_n [ was ad hoc up to 7, as described above for n >= 8 ]. Old format is still the default, but will eventually change. Use default(new_galois_format, 1) or, in library mode, set global variable new_galois_format to 1 to enable the new format. - The nf structure output by nfinit has changed: *) nf.zk is now T2-LLL-reduced, not in HNF wrt the power basis *) the internal components of nf[5] have changed (MC and T2 not needed anymore) - polred & polredabs do not take a 'prec' argument anymore [was unused] - gentimer / genmsgtimer / get_timer have been removed. They are superseded by TIMER and msgTIMER which are fully reentrant and easier to use. - (undocumented) macros buch[gen | genfu | init | iniftu] - rnfisnorm() prototype has changed [ + need to call rnfisnorminit first ] - incgam4 renamed to incgam0, incgam3 renamed to incgamc - prototypes of buchall and smallbuchinit have changed (much simpler) - co8() renamed to quadtoc() - ker_mod_p() renamed to FpM_ker [ and supplemented with many analogous modular routines ] - nfreducemodpr2() removed, use an nfmodpr structure from nfmodprinit() or zkmodprinit() instead - smodsi() removed [ not well defined ]. Use either modsi() or umodui() - Many error codes were removed. It is usually better to use only talker outside libpari. - Macro BITS_IN_RANDOM has been removed. Used to be 32. - mymyrand() has been removed, use pari_rand31() or pari_rand() instead - diviiz(x,y,z), divisz, divsiz and divssz always assign the euclidean quotient [ used to depend on the type of z: if t_REAL computed exact quotient ]. Use rdivii, rdivis, rdivsi, rdivss for analogous functionality (no "z" variant); - mpdivz(x,y,z) assigns the euclidean quotient when x,y are t_INT (used to depend on the type of z) - removed inconsistently named macros mpinv[sir]r [ were "z" functions ] - removed useless routine shifts [ use shifti( stoi() ) ] - library interface of functions intnum, prodeuler, suminf, sumalt, sumalt2, sumpos, sumpos2, prodinf, prodinf1 [ use GEN (*eval)(GEN,void*) everywhere instead of entree * ] - changed the prototype of bnrdisclist0 - removed ideallistarch0, ideallistarchgen, ideallistunitarch, ideallistunitarchgen. Just use ideallistarch. - change the output of ideallist with technical (flag 2,3) [ with units ]: instead of two vectors, output a vector of 2-component vectors. change the input of all list routines (bnrclassnolist, bnrdisclist) accordingly. - rename gtrans_i -> shallowtrans, concatsp -> shallowconcat. - pari_err(warner | warnmem | warnfile | warnprec,) no longer accepted. Use pari_warn. Partially compatible changes: ----------------------------- [ not mandatory for your program to work with 2.3, since compatibility macros support the old names but are likely to become mandatory in 2.4, so we advise you to update soon ] - typecasting macros (e.g. ladd(), lmul() ...) are obsolete and shouldn't be used in new programs. Use accessors gel() and friends. - stack locations used to be of type long or ulong, now they have a dedicated type pari_sp [ pari stack pointer ] - in order to compare variable numbers, use the macro varncmp() instead of < or > operators. - access to the prime numbers table is done via the macros NEXT_PRIME_VIADIFF or NEXT_PRIME_VIADIFF_CHECK. - direct access to the mantissa of t_INT is deprecated. Instead you should use the t_INT API (macros int_MSW, int_LSW, int_precW, int_nextW, int_W). This will ensure your code is compatible with both native and GMP kernels. - the macros lgef / setlgef / evallgef have been removed. t_POLs no longer include an "effective length". One should use lg() for t_POLs as for most other types. Don't use lgef() in new code. lgef() and setlgef() are aliased to lg() and setlg(). They will break on hackish code accessing directly the first component of t_POL objets, e.g x = cgetg(20, t_POL); x[1] = evalsigne(1) | evalvarn(0) | evallgef( 10 ) /* 10, not 20 */ ... setlgef(x, 20); /* now create/use further coefficients */ - types t_FRACN, t_RFRACN and gred() have been removed (complicated, unused, and very inefficient). There are now aliases to t_FRAC, t_RFRAC and gcopy respectively for backward compatibility. - renamed nfdivres -> nfdivrem, poldivres -> poldivrem - renamed permute -> numtoperm, permuteInv -> permtonum - renamed gzero -> gen_0, gun -> gen_1, gdeux -> gen_2, polx -> pol_x, polun -> pol_1 - renamed gegal -> gequal, gegalgs -> gequalgs, gegalsg -> gequalsg, egalii -> equalii - renamed binome -> binomial, chinois -> chinese - renamed apprgen9, apprgen -> padicappr, factmod9 -> factorff - rename resss -> remss, ressi -> remsi, resis -> remis, resii -> remii, gres -> grem - rename divise -> dvdii, gdivise -> gdvd, mpdivis -> dvdiiz, mpdivisis -> dvdisz - rename mpent -> mpfloor - rename isprincipalrayall -> bnrisprincipal, rayclassno -> bnrclassno rayclassnolist -> bnrclassnolist - rename globalreduction -> ellglobalred, localreduction -> elllocalred - taniyama(e) is deprecated. Use elltaniyama(e, prec) instead of old = precdl; precdl = prec; x = taniyama(e); precdl = old; - rename lisexpr -> readexp, lisseq -> readseq - rename flisexpr, flisseq -> gp_read_str - rename lisGEN -> gp_read_stream - rename idmat -> matid - rename coefs_to_col -> mkcoln, coefs_to_int -> mkintn coefs_to_pol -> mkpoln, coefs_to_vec -> mkvecn - rename wf -> weberf, wf1 -> weberf1, wf2 -> weberf2 - rename err -> pari_err, pariputsf -> pariprintf - rename rnfhermitebasis -> rnfhnfbasis - rename gcarreparfait -> gissquare, gcarrecomplet -> gissquarerem - rename lseriesell -> elllseries - gmodulo and forcecopy are obsolete. Use gmodulcp and gcopy. %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * The calculator GP: ==================== - most function names have changed (see misc/new.dic or use whatnow under GP) - lowercase / uppercase letters distinguished. - the syntax \var = value is not recognized anymore. Use standard metacommands instead. (setting the compatibility level "compatible" to 3, with "default" will give you those three back). - strict parenthesis matching before executing the command (set strictmatch to 0 to get old behaviour) - functions label / goto have been removed (use break/next/return instead). - conjugation x_ has been removed. '_' can be freely used in identifiers. - \k metacommand removed - result history is now cyclic (older results are erased when the maximal size "histsize" is reached). - the Set() function turns objects into strings (so that set functions are able to treat arbitrary objects). Use eval to turn them back to GENs. - the type() function returns a string and not a number. - sum(X=a,b,...,x) yields x if b empty [#2096] [F49] FB 6- [Configure] library not found despite --with-readline-lib [#2097][F53] 7- minpoly(Mod(1,t^2)) -> SEGV [#2102] [F55] 8- a=ffgen(3^2,'a);poldisc(x^6+a*x+y) -> division by 0 [ positive [F56] characteristic with a few t_INT coefficients ] BA 9- [pthread] parapply could crash [F58] BA 10- ffinvmap(m) could SEGV on bad input [F59] 11- ellisdivisible(E/K number field in 'x) -> incorrect priority [F60] 12- idealispower(nf, t_INT n) possibly wrong if (n, nf.disc) > 1 [F61] 13- zeta''(0): all precision lost [more generally f'...'(n quotes) imprecise in the neighbourhood of 0, while derivnum(,n) was OK] [F62] 14- sumdigits(negative number, B) sometimes negative [F63] 15- poldiscfactors(x^0) -> division by 0 [F64] 16- factormod(x^3+1,[y^2+1,2]) -> SEGV [F65] 17- factormod(x^3+1,[y^2+1,5]) -> weird error message [F66] BA 18- fix inefficiency in fplll not present in original code [F69] 19- polrootsreal(x^4+2*x^3+x^2/3+x/100-1/2000,[1/100,oo]): no root [F70] 20- polrootsreal(x^4+2*x^3+x^2/3+x/100-1/1000,[1/10,oo]): extra root [F71] 21- lfun may crash on lfuncreate input with too short an vector [F72] BA 22- incorrect use of graphcolors -> SEGV [F73] 23- forcomposite(..., oo, ) was not supported [F74] BA 24- lfunartin with poles: incorrect result [F75] JD 25- factor: significant pointers lost [#2125] [F76] BA 26- matdet/matrank over large fields was inefficient [F77] 27- poldisc(y^2/x + 1, y) -> error [also affects polresultant] [F78] 28- poldisc(x^2/y + 1, y) -> 0 [also affects polresultant] [F79] 29- ispower(2, 2^64) -> error [F80] 30- (f(x) = x*'y); f'(1) -> error [F81] BA 31- sqrtn(Mod(3,19),4) -> no error [#2127] [F82] 32- nfhnfmod: wrong result [F83] 33- matdet(mat with t_RFRAC entries): wrong result [#2128] [F84] 34- n-th derivative of zetahurwitz used 'seriesprecision' instead of n + imprecise value when n large [#2130] [F85] 35- lfunzeros(f, [0, b]) wasn't allowed [F86] 36- mateigen(): typo causing wrong results when correct results were achievable [#2131] [F87] 37- intnum(x=-oo,[0,-1/2],1/sqrt(-x*(x^4+1))) -> division by 0 [F88] 38- printtex(quadgen(-3,'z)) ==> w [F90] BA 39- [a,b]=a could lead to memory corruption [F91] 40- memory leak in cgetalloc when lg overflows [F92] 41- possible SEGV in padicappr [#2133] [F93] 42- core() could destroy its input, if stored in a GP variable [F96] 43- quadgen(2^64+1) * 1. => junk (stack corruption in quad_disc). [F97] 44- ellmoddegree: infinite loop and stack corruption (e.g on 52a2) [F98] 45- ellmoddegree(ellinit("10890ba6")) -> wrong result [F99] 46- nfgcd called ZX_resultant(a,T) with typ(a) == t_INT [F100] Done for version 2.11.1 (released 1/12/2018): Fixed 1- heap-buffer-overflow in init_prefix [readline] [F4] 2- mfsplit(mf,,flag) could return uninitialized objects => SEGV [F5] 3- mfeisenstein(k,,chi) was treated as E(k,chi) instead of E(k,1,chi)[F6] 4- poldegree(y/x) -> 0 [ instead of -1 ] [F7] 5- sumeulerrat(y/x^2,1) -> junk [F8] HC 6- incgam(-1000.4,2) -> SEGV [F9] 7- mfatkininit(mfinit([366,2]),2) -> precision error [F10] 8- forprimestep: wrong when wrapping over word boundary [#2071] [F11] 9- mfbracket: [f,g]_m was multiplied by (-1)^m [F12] 10- wrong results in mfatkininit / mfatkineigenvalues [#2073/#2074] [F13] 11- issquare(Mod(x,ffinit(3,2))) -> wrong result [broken Fq_ispower] [F14] 12- possible SEGV in rnfpseudobasis(, [pol,lim]) [F15] 13- wrong result in elllog over F_p, p in [2^63,2^64[ [F16] 14- wrong result in mfsymboleval when path extremities are close to [F17] real axis (cusps were OK) [#2075] 15- mfcoefs(mfDelta(),0) -> SEGV [#2078] [F18] 16- GC error in lfuncreate(elliptic curve over number field) [#2080] [F19] 17- X11 and Qt graphic engine: pari_close called too soon => crash [F20] 18- pariold.h: mix up with obsoleted taille / taille2 [F21] 19- foo(n)=vector(n)[1..n];123; would corrupt the GP interpreter [F22] 20- Pol(0)/'x -> t_INT 0 (instead of 0*x^0) [F23] Pol(0)/(Mod(1,2)*'x) -> t_INT 0 (instead of Mod(0,2)*x^0) 21- missing typecheck in nfalgtobasis [#2084] [F24] 22- dbllog2(t_COMPLEX of t_FRAC) => junk [F25] 23- nffactor(t_POL, t_POL) => bug in LLL_cmbf [#2083] [F26] 24- ideallog(pure archimedean conductor, t_FRAC) -> log(0) error [F27] 25- lfunrootres: avoid oo-loop [F28] 26- mfgaloistype: dihedral forms possibly incorrect for N > 3000 [F29] 27- mfgaloistype: error on mf=mfinit([1159,1,Mod(930,1159)],0); [F30] 28- hash_GEN(x) differed depending on whether x was a clone [F33] BA 29- [mpi] setting nbthreads in .gprc could lead to crashes. [F34] 30- accuracy too large in derivnum => slowdown [F35] 31- nfisincl(x^5-x^4+x^3-2*x^2+3*x-1,x^20+x^15+x^10+x^5+1) -> SEGV [F36] 32- stack corruption in addsub_frac [F37] AP 33- segfault in rnfidealup [#2093] [F38] 34- Ser(x,x,0) -> error instead of O(x) [#2092] [F39] 35- fix mspolygon(,2) [add 1/3rd hyperbolic triangles + fix labels] [F40] 36- factor(3/(x^5+3*y*x^4+3*y^2*x^3+y^3*x^2)) -> SEGV [F41] 37- catastrophic cancellation in acosh / asinh for large t_COMPLEX [F43] 38- zeta(1/2 + I*t) => internal error [F44] pari-2.11.2/src/0000755000175000017500000000000013461316051011745 5ustar billbillpari-2.11.2/src/headers/0000755000175000017500000000000013461316051013360 5ustar billbillpari-2.11.2/src/headers/pariinl.h0000644000175000017500000023316113457700535015206 0ustar billbill/* Copyright (C) 2000-2010 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* CONSTRUCTORS */ /* */ /*******************************************************************/ #define retmkfrac(x,y)\ do { GEN _v = cgetg(3, t_FRAC);\ gel(_v,1) = (x);\ gel(_v,2) = (y); return _v; } while(0) #define retmkrfrac(x,y)\ do { GEN _v = cgetg(3, t_RFRAC);\ gel(_v,1) = (x);\ gel(_v,2) = (y); return _v; } while(0) #define retmkintmod(x,y)\ do { GEN _v = cgetg(3, t_INTMOD);\ gel(_v,1) = (y);\ gel(_v,2) = (x); return _v; } while(0) #define retmkcomplex(x,y)\ do { GEN _v = cgetg(3, t_COMPLEX);\ gel(_v,1) = (x);\ gel(_v,2) = (y); return _v; } while(0) #define retmkpolmod(x,y)\ do { GEN _v = cgetg(3, t_POLMOD);\ gel(_v,1) = (y);\ gel(_v,2) = (x); return _v; } while(0) #define retmkvec(x)\ do { GEN _v = cgetg(2, t_VEC);\ gel(_v,1) = (x); return _v; } while(0) #define retmkvec2(x,y)\ do { GEN _v = cgetg(3, t_VEC);\ gel(_v,1) = (x);\ gel(_v,2) = (y); return _v; } while(0) #define retmkvec3(x,y,z)\ do { GEN _v = cgetg(4, t_VEC);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z); return _v; } while(0) #define retmkqfi(x,y,z)\ do { GEN _v = cgetg(4, t_QFI);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z); return _v; } while(0) #define retmkqfr(x,y,z,d)\ do { GEN _v = cgetg(5, t_QFR);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (d); return _v; } while(0) #define retmkquad(x,y,z)\ do { GEN _v = cgetg(4, t_QUAD);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z); return _v; } while(0) #define retmkvec4(x,y,z,t)\ do { GEN _v = cgetg(5, t_VEC);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t); return _v; } while(0) #define retmkvec5(x,y,z,t,u)\ do { GEN _v = cgetg(6, t_VEC);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t);\ gel(_v,5) = (u); return _v; } while(0) #define retmkcol(x)\ do { GEN _v = cgetg(2, t_COL);\ gel(_v,1) = (x); return _v; } while(0) #define retmkcol2(x,y)\ do { GEN _v = cgetg(3, t_COL);\ gel(_v,1) = (x);\ gel(_v,2) = (y); return _v; } while(0) #define retmkcol3(x,y,z)\ do { GEN _v = cgetg(4, t_COL);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z); return _v; } while(0) #define retmkcol4(x,y,z,t)\ do { GEN _v = cgetg(5, t_COL);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t); return _v; } while(0) #define retmkcol5(x,y,z,t,u)\ do { GEN _v = cgetg(6, t_COL);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t);\ gel(_v,5) = (u); return _v; } while(0) #define retmkcol6(x,y,z,t,u,v)\ do { GEN _v = cgetg(7, t_COL);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t);\ gel(_v,5) = (u);\ gel(_v,6) = (v); return _v; } while(0) #define retmkmat(x)\ do { GEN _v = cgetg(2, t_MAT);\ gel(_v,1) = (x); return _v; } while(0) #define retmkmat2(x,y)\ do { GEN _v = cgetg(3, t_MAT);\ gel(_v,1) = (x);\ gel(_v,2) = (y); return _v; } while(0) #define retmkmat3(x,y,z)\ do { GEN _v = cgetg(4, t_MAT);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z); return _v; } while(0) #define retmkmat4(x,y,z,t)\ do { GEN _v = cgetg(5, t_MAT);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t); return _v; } while(0) #define retmkmat5(x,y,z,t,u)\ do { GEN _v = cgetg(6, t_MAT);\ gel(_v,1) = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t);\ gel(_v,5) = (u); return _v; } while(0) INLINE GEN mkintmod(GEN x, GEN y) { retmkintmod(x,y); } INLINE GEN mkintmodu(ulong x, ulong y) { GEN v = cgetg(3,t_INTMOD); gel(v,1) = utoipos(y); gel(v,2) = utoi(x); return v; } INLINE GEN mkpolmod(GEN x, GEN y) { retmkpolmod(x,y); } INLINE GEN mkfrac(GEN x, GEN y) { retmkfrac(x,y); } INLINE GEN mkfracss(long x, long y) { retmkfrac(stoi(x),stoi(y)); } /* q = n/d a t_FRAC or t_INT; recover (n,d) */ INLINE void Qtoss(GEN q, long *n, long *d) { if (typ(q) == t_INT) { *n = itos(q); *d = 1; } else { *n = itos(gel(q,1)); *d = itou(gel(q,2)); } } INLINE GEN sstoQ(long n, long d) { ulong r; long g, q; if (!n) { if (!d) pari_err_INV("sstoQ",gen_0); return gen_0; } if (d < 0) { d = -d; n = -n; } if (d == 1) return stoi(n); q = udivuu_rem(labs(n),d,&r); if (!r) return n > 0? utoipos(q): utoineg(q); g = ugcd(d,r); /* gcd(n,d) */ if (g != 1) { n /= g; d /= g; } retmkfrac(stoi(n), utoi(d)); } INLINE GEN mkfraccopy(GEN x, GEN y) { retmkfrac(icopy(x), icopy(y)); } INLINE GEN mkrfrac(GEN x, GEN y) { GEN v = cgetg(3, t_RFRAC); gel(v,1) = x; gel(v,2) = y; return v; } INLINE GEN mkrfraccopy(GEN x, GEN y) { GEN v = cgetg(3, t_RFRAC); gel(v,1) = gcopy(x); gel(v,2) = gcopy(y); return v; } INLINE GEN mkcomplex(GEN x, GEN y) { retmkcomplex(x,y); } INLINE GEN gen_I(void) { return mkcomplex(gen_0, gen_1); } INLINE GEN cgetc(long l) { retmkcomplex(cgetr(l), cgetr(l)); } INLINE GEN mkquad(GEN n, GEN x, GEN y) { GEN v = cgetg(4, t_QUAD); gel(v,1) = n; gel(v,2) = x; gel(v,3) = y; return v; } /* vecsmall */ INLINE GEN mkvecsmall(long x) { GEN v = cgetg(2, t_VECSMALL); v[1] = x; return v; } INLINE GEN mkvecsmall2(long x,long y) { GEN v = cgetg(3, t_VECSMALL); v[1]=x; v[2]=y; return v; } INLINE GEN mkvecsmall3(long x,long y,long z) { GEN v = cgetg(4, t_VECSMALL); v[1]=x; v[2]=y; v[3]=z; return v; } INLINE GEN mkvecsmall4(long x,long y,long z,long t) { GEN v = cgetg(5, t_VECSMALL); v[1]=x; v[2]=y; v[3]=z; v[4]=t; return v; } INLINE GEN mkvecsmall5(long x,long y,long z,long t,long u) { GEN v = cgetg(6, t_VECSMALL); v[1]=x; v[2]=y; v[3]=z; v[4]=t; v[5]=u; return v; } INLINE GEN mkqfi(GEN x, GEN y, GEN z) { retmkqfi(x,y,z); } /* vec */ INLINE GEN mkvec(GEN x) { retmkvec(x); } INLINE GEN mkvec2(GEN x, GEN y) { retmkvec2(x,y); } INLINE GEN mkvec3(GEN x, GEN y, GEN z) { retmkvec3(x,y,z); } INLINE GEN mkvec4(GEN x, GEN y, GEN z, GEN t) { retmkvec4(x,y,z,t); } INLINE GEN mkvec5(GEN x, GEN y, GEN z, GEN t, GEN u) { retmkvec5(x,y,z,t,u); } INLINE GEN mkvecs(long x) { retmkvec(stoi(x)); } INLINE GEN mkvec2s(long x, long y) { retmkvec2(stoi(x),stoi(y)); } INLINE GEN mkvec3s(long x, long y, long z) { retmkvec3(stoi(x),stoi(y),stoi(z)); } INLINE GEN mkvec4s(long x, long y, long z, long t) { retmkvec4(stoi(x),stoi(y),stoi(z),stoi(t)); } INLINE GEN mkveccopy(GEN x) { GEN v = cgetg(2, t_VEC); gel(v,1) = gcopy(x); return v; } INLINE GEN mkvec2copy(GEN x, GEN y) { GEN v = cgetg(3,t_VEC); gel(v,1) = gcopy(x); gel(v,2) = gcopy(y); return v; } /* col */ INLINE GEN mkcol(GEN x) { retmkcol(x); } INLINE GEN mkcol2(GEN x, GEN y) { retmkcol2(x,y); } INLINE GEN mkcol3(GEN x, GEN y, GEN z) { retmkcol3(x,y,z); } INLINE GEN mkcol4(GEN x, GEN y, GEN z, GEN t) { retmkcol4(x,y,z,t); } INLINE GEN mkcol5(GEN x, GEN y, GEN z, GEN t, GEN u) { retmkcol5(x,y,z,t,u); } INLINE GEN mkcol6(GEN x, GEN y, GEN z, GEN t, GEN u, GEN v) { retmkcol6(x,y,z,t,u,v); } INLINE GEN mkcols(long x) { retmkcol(stoi(x)); } INLINE GEN mkcol2s(long x, long y) { retmkcol2(stoi(x),stoi(y)); } INLINE GEN mkcol3s(long x, long y, long z) { retmkcol3(stoi(x),stoi(y),stoi(z)); } INLINE GEN mkcol4s(long x, long y, long z, long t) { retmkcol4(stoi(x),stoi(y),stoi(z),stoi(t)); } INLINE GEN mkcolcopy(GEN x) { GEN v = cgetg(2, t_COL); gel(v,1) = gcopy(x); return v; } /* mat */ INLINE GEN mkmat(GEN x) { retmkmat(x); } INLINE GEN mkmat2(GEN x, GEN y) { retmkmat2(x,y); } INLINE GEN mkmat3(GEN x, GEN y, GEN z) { retmkmat3(x,y,z); } INLINE GEN mkmat4(GEN x, GEN y, GEN z, GEN t) { retmkmat4(x,y,z,t); } INLINE GEN mkmat5(GEN x, GEN y, GEN z, GEN t, GEN u) { retmkmat5(x,y,z,t,u); } INLINE GEN mkmatcopy(GEN x) { GEN v = cgetg(2, t_MAT); gel(v,1) = gcopy(x); return v; } INLINE GEN mkerr(long x) { GEN v = cgetg(2, t_ERROR); v[1] = x; return v; } INLINE GEN mkoo(void) { GEN v = cgetg(2, t_INFINITY); gel(v,1) = gen_1; return v; } INLINE GEN mkmoo(void) { GEN v = cgetg(2, t_INFINITY); gel(v,1) = gen_m1; return v; } INLINE long inf_get_sign(GEN x) { return signe(gel(x,1)); } INLINE GEN mkmat22s(long a, long b, long c, long d) {retmkmat2(mkcol2s(a,c),mkcol2s(b,d));} INLINE GEN mkmat22(GEN a, GEN b, GEN c, GEN d) { retmkmat2(mkcol2(a,c),mkcol2(b,d)); } /* pol */ INLINE GEN pol_x(long v) { GEN p = cgetg(4, t_POL); p[1] = evalsigne(1)|evalvarn(v); gel(p,2) = gen_0; gel(p,3) = gen_1; return p; } /* x^n, assume n >= 0 */ INLINE GEN pol_xn(long n, long v) { long i, a = n+2; GEN p = cgetg(a+1, t_POL); p[1] = evalsigne(1)|evalvarn(v); for (i = 2; i < a; i++) gel(p,i) = gen_0; gel(p,a) = gen_1; return p; } /* x^n, no assumption on n */ INLINE GEN pol_xnall(long n, long v) { if (n < 0) retmkrfrac(gen_1, pol_xn(-n,v)); return pol_xn(n, v); } INLINE GEN pol_1(long v) { GEN p = cgetg(3, t_POL); p[1] = evalsigne(1)|evalvarn(v); gel(p,2) = gen_1; return p; } INLINE GEN pol_0(long v) { GEN x = cgetg(2,t_POL); x[1] = evalvarn(v); return x; } #define retconst_vec(n,x)\ do { long _i, _n = (n);\ GEN _v = cgetg(_n+1, t_VEC), _x = (x);\ for (_i = 1; _i <= _n; _i++) gel(_v,_i) = _x;\ return _v; } while(0) INLINE GEN const_vec(long n, GEN x) { retconst_vec(n, x); } #define retconst_col(n,x)\ do { long _i, _n = (n);\ GEN _v = cgetg(_n+1, t_COL), _x = (x);\ for (_i = 1; _i <= _n; _i++) gel(_v,_i) = _x;\ return _v; } while(0) INLINE GEN const_col(long n, GEN x) { retconst_col(n, x); } INLINE GEN const_vecsmall(long n, long c) { long i; GEN V = cgetg(n+1,t_VECSMALL); for(i=1;i<=n;i++) V[i] = c; return V; } /*** ZERO ***/ /* O(p^e) */ INLINE GEN zeropadic(GEN p, long e) { GEN y = cgetg(5,t_PADIC); gel(y,4) = gen_0; gel(y,3) = gen_1; gel(y,2) = icopy(p); y[1] = evalvalp(e) | _evalprecp(0); return y; } INLINE GEN zeropadic_shallow(GEN p, long e) { GEN y = cgetg(5,t_PADIC); gel(y,4) = gen_0; gel(y,3) = gen_1; gel(y,2) = p; y[1] = evalvalp(e) | _evalprecp(0); return y; } /* O(pol_x(v)^e) */ INLINE GEN zeroser(long v, long e) { GEN x = cgetg(2, t_SER); x[1] = evalvalp(e) | evalvarn(v); return x; } INLINE int ser_isexactzero(GEN x) { if (!signe(x)) switch(lg(x)) { case 2: return 1; case 3: return isexactzero(gel(x,2)); } return 0; } /* 0 * pol_x(v) */ INLINE GEN zeropol(long v) { return pol_0(v); } /* vector(n) */ INLINE GEN zerocol(long n) { GEN y = cgetg(n+1,t_COL); long i; for (i=1; i<=n; i++) gel(y,i) = gen_0; return y; } /* vectorv(n) */ INLINE GEN zerovec(long n) { GEN y = cgetg(n+1,t_VEC); long i; for (i=1; i<=n; i++) gel(y,i) = gen_0; return y; } /* matrix(m, n) */ INLINE GEN zeromat(long m, long n) { GEN y = cgetg(n+1,t_MAT); GEN v = zerocol(m); long i; for (i=1; i<=n; i++) gel(y,i) = v; return y; } /* = zero_zx, sv is a evalvarn()*/ INLINE GEN zero_Flx(long sv) { return pol0_Flx(sv); } INLINE GEN zero_Flv(long n) { GEN y = cgetg(n+1,t_VECSMALL); long i; for (i=1; i<=n; i++) y[i] = 0; return y; } /* matrix(m, n) */ INLINE GEN zero_Flm(long m, long n) { GEN y = cgetg(n+1,t_MAT); GEN v = zero_Flv(m); long i; for (i=1; i<=n; i++) gel(y,i) = v; return y; } /* matrix(m, n) */ INLINE GEN zero_Flm_copy(long m, long n) { GEN y = cgetg(n+1,t_MAT); long i; for (i=1; i<=n; i++) gel(y,i) = zero_Flv(m); return y; } INLINE GEN zero_F2v(long m) { long l = nbits2nlong(m); GEN v = zero_Flv(l+1); v[1] = m; return v; } INLINE GEN zero_F2m(long m, long n) { long i; GEN M = cgetg(n+1, t_MAT); GEN v = zero_F2v(m); for (i = 1; i <= n; i++) gel(M,i) = v; return M; } INLINE GEN zero_F2m_copy(long m, long n) { long i; GEN M = cgetg(n+1, t_MAT); for (i = 1; i <= n; i++) gel(M,i)= zero_F2v(m); return M; } /* matrix(m, n) */ INLINE GEN zeromatcopy(long m, long n) { GEN y = cgetg(n+1,t_MAT); long i; for (i=1; i<=n; i++) gel(y,i) = zerocol(m); return y; } INLINE GEN zerovec_block(long len) { long i; GEN blk = cgetg_block(len + 1, t_VEC); for (i = 1; i <= len; ++i) gel(blk, i) = gen_0; return blk; } /* i-th vector in the standard basis */ INLINE GEN col_ei(long n, long i) { GEN e = zerocol(n); gel(e,i) = gen_1; return e; } INLINE GEN vec_ei(long n, long i) { GEN e = zerovec(n); gel(e,i) = gen_1; return e; } INLINE GEN F2v_ei(long n, long i) { GEN e = zero_F2v(n); F2v_set(e,i); return e; } INLINE GEN vecsmall_ei(long n, long i) { GEN e = zero_zv(n); e[i] = 1; return e; } INLINE GEN Rg_col_ei(GEN x, long n, long i) { GEN e = zerocol(n); gel(e,i) = x; return e; } INLINE GEN shallowcopy(GEN x) { return typ(x) == t_MAT ? RgM_shallowcopy(x): leafcopy(x); } /* routines for naive growarrays */ INLINE GEN vectrunc_init(long l) { GEN z = new_chunk(l); z[0] = evaltyp(t_VEC) | _evallg(1); return z; } INLINE GEN coltrunc_init(long l) { GEN z = new_chunk(l); z[0] = evaltyp(t_COL) | _evallg(1); return z; } INLINE void lg_increase(GEN x) { x[0]++; } INLINE void vectrunc_append(GEN x, GEN t) { gel(x, lg(x)) = t; lg_increase(x); } INLINE void vectrunc_append_batch(GEN x, GEN y) { long i, l = lg(x), ly = lg(y); GEN z = x + l-1; for (i = 1; i < ly; i++) gel(z,i) = gel(y,i); setlg(x, l+ly-1); } INLINE GEN vecsmalltrunc_init(long l) { GEN z = new_chunk(l); z[0] = evaltyp(t_VECSMALL) | _evallg(1); return z; } INLINE void vecsmalltrunc_append(GEN x, long t) { x[ lg(x) ] = t; lg_increase(x); } /*******************************************************************/ /* */ /* VEC / COL / VECSMALL */ /* */ /*******************************************************************/ /* shallow*/ INLINE GEN vec_shorten(GEN v, long n) { long i; GEN V = cgetg(n+1,t_VEC); for(i=1;i<=n;i++) gel(V,i) = gel(v,i); return V; } /* shallow*/ INLINE GEN vec_lengthen(GEN v, long n) { long i; long l=lg(v); GEN V = cgetg(n+1,t_VEC); for(i=1;i t) t = x[i0=i]; return i0; } INLINE long vecsmall_max(GEN x) { long i, t = x[1], lx = lg(x); for (i=2; i t) t = x[i]; return t; } INLINE long vecsmall_indexmin(GEN x) { long i, i0 = 1, t = x[1], lx =lg(x); for (i=2; i 1) if (signe(gel(x, l))) return 0; return 1; } INLINE int QV_isscalar(GEN x) { long lx = lg(x),i; for (i=2; i2; i--) if (!gequal0(gel(x, i))) return 0; return 1; } INLINE long RgX_equal_var(GEN x, GEN y) { return varn(x) == varn(y) && RgX_equal(x,y); } INLINE int RgX_is_rational(GEN x) { long i; for (i = lg(x)-1; i > 1; i--) if (!is_rational_t(typ(gel(x,i)))) return 0; return 1; } INLINE int RgX_is_ZX(GEN x) { long i; for (i = lg(x)-1; i > 1; i--) if (typ(gel(x,i)) != t_INT) return 0; return 1; } INLINE int RgX_is_QX(GEN x) { long k = lg(x)-1; for ( ; k>1; k--) if (!is_rational_t(typ(gel(x,k)))) return 0; return 1; } INLINE int RgX_is_monomial(GEN x) { long i; if (!signe(x)) return 0; for (i=lg(x)-2; i>1; i--) if (!isexactzero(gel(x,i))) return 0; return 1; } INLINE int RgV_is_ZV(GEN x) { long i; for (i = lg(x)-1; i > 0; i--) if (typ(gel(x,i)) != t_INT) return 0; return 1; } INLINE int RgV_is_QV(GEN x) { long i; for (i = lg(x)-1; i > 0; i--) if (!is_rational_t(typ(gel(x,i)))) return 0; return 1; } /********************************************************************/ /** **/ /** Dynamic arrays implementation **/ /** **/ /********************************************************************/ INLINE void ** pari_stack_base(pari_stack *s) { return s->data; } INLINE void pari_stack_init(pari_stack *s, size_t size, void **data) { s->data = data; *data = NULL; s->n = 0; s->alloc = 0; s->size = size; } INLINE void pari_stack_alloc(pari_stack *s, long nb) { void **sdat = pari_stack_base(s); long alloc = s->alloc; if (s->n+nb <= alloc) return; if (!alloc) alloc = nb; else { while (s->n+nb > alloc) alloc <<= 1; } *sdat = pari_realloc(*sdat,alloc*s->size); s->alloc = alloc; } INLINE long pari_stack_new(pari_stack *s) { pari_stack_alloc(s, 1); return s->n++; } INLINE void pari_stack_delete(pari_stack *s) { void **sdat = pari_stack_base(s); if (*sdat) pari_free(*sdat); } INLINE void pari_stack_pushp(pari_stack *s, void *u) { long n = pari_stack_new(s); void **sdat =(void**) *pari_stack_base(s); sdat[n] = u; } /*******************************************************************/ /* */ /* EXTRACT */ /* */ /*******************************************************************/ INLINE GEN vecslice(GEN A, long y1, long y2) { long i,lB = y2 - y1 + 2; GEN B = cgetg(lB, typ(A)); for (i=1; i>1, i; for (i = 1; i <= lim; i++) { GEN z = gel(y,i); gel(y,i) = gel(y,l-i); gel(y,l-i) = z; } } INLINE GEN vecsmallpermute(GEN A, GEN p) { return perm_mul(A, p); } INLINE GEN vecpermute(GEN A, GEN x) { pari_APPLY_type(typ(A), gel(A, x[i])) } INLINE GEN rowpermute(GEN x, GEN p) { pari_APPLY_same(typ(gel(x,i)) == t_VECSMALL ? vecsmallpermute(gel(x, i), p) : vecpermute(gel(x, i), p)) } /*******************************************************************/ /* */ /* PERMUTATIONS */ /* */ /*******************************************************************/ /* identity permutation */ INLINE GEN identity_perm(long n) { GEN perm = cgetg(n+1, t_VECSMALL); long i; for (i = 1; i <= n; i++) perm[i] = i; return perm; } /* assume d <= n */ INLINE GEN cyclic_perm(long n, long d) { GEN perm = cgetg(n+1, t_VECSMALL); long i; for (i = 1; i <= n-d; i++) perm[i] = i+d; for ( ; i <= n; i++) perm[i] = i-n+d; return perm; } /* Multiply (compose) two permutations */ INLINE GEN perm_mul(GEN s, GEN x) { pari_APPLY_long(s[x[i]]) } /* Compute the inverse (reciprocal) of a permutation. */ INLINE GEN perm_inv(GEN x) { long i, lx; GEN y = cgetg_copy(x, &lx); for (i=1; i 0) y[i] = x[i]; y[0] = evaltyp(t_INT)|evallg(lx); return y; } /* copy leaf x as if we had avma = av */ INLINE GEN leafcopy_avma(GEN x, pari_sp av) { long i = lg(x); GEN y = ((GEN)av) - i; while (--i > 0) y[i] = x[i]; y[0] = x[0] & (~CLONEBIT); return y; } INLINE GEN gerepileuptoleaf(pari_sp av, GEN x) { long lx; GEN q; if (!isonstack(x) || (GEN)av<=x) { avma = av; return x; } lx = lg(x); q = ((GEN)av) - lx; avma = (pari_sp)q; while (--lx >= 0) q[lx] = x[lx]; return q; } INLINE GEN gerepileuptoint(pari_sp av, GEN x) { if (!isonstack(x) || (GEN)av<=x) { avma = av; return x; } avma = (pari_sp)icopy_avma(x, av); return (GEN)avma; } INLINE GEN gerepileupto(pari_sp av, GEN x) { if (!isonstack(x) || (GEN)av<=x) { avma = av; return x; } switch(typ(x)) { /* non-default = !is_recursive_t(tq) */ case t_INT: return gerepileuptoint(av, x); case t_REAL: case t_STR: case t_VECSMALL: return gerepileuptoleaf(av,x); default: /* NB: x+i --> ((long)x) + i*sizeof(long) */ return gerepile(av, (pari_sp) (x+lg(x)), x); } } /* gerepileupto(av, gcopy(x)) */ INLINE GEN gerepilecopy(pari_sp av, GEN x) { if (is_recursive_t(typ(x))) { GENbin *p = copy_bin(x); avma = av; return bin_copy(p); } else { avma = av; if (x < (GEN)av) { if (x < (GEN)pari_mainstack->bot) new_chunk(lg(x)); x = leafcopy_avma(x, av); avma = (pari_sp)x; } else x = leafcopy(x); return x; } } /* Takes an array of pointers to GENs, of length n. Copies all * objects to contiguous locations and cleans up the stack between * av and avma. */ INLINE void gerepilemany(pari_sp av, GEN* gptr[], int n) { int i; for (i=0; i=0; i--) *gptr[i] = bin_copy((GENbin*)*gptr[i]); } else { GEN **gptr = (GEN**) pari_malloc(n*sizeof(GEN*)); for (i=0; i=0; i--) *gptr[i] = bin_copy((GENbin*)*gptr[i]); pari_free(gptr); } va_end(a); } INLINE void gerepilecoeffs(pari_sp av, GEN x, int n) { int i; for (i=0; ix back to stack, then destroy p */ INLINE GEN bin_copy(GENbin *p) { GEN x, y, base; long dx, len; x = p->x; if (!x) { pari_free(p); return gen_0; } len = p->len; base= p->base; dx = x - base; y = (GEN)memcpy((void*)new_chunk(len), (void*)GENbinbase(p), len*sizeof(long)); y += dx; p->rebase(y, ((ulong)y-(ulong)x)); pari_free(p); return y; } INLINE GEN GENbinbase(GENbin *p) { return (GEN)(p + 1); } INLINE void cgiv(GEN x) { pari_sp av = (pari_sp)(x+lg(x)); if (isonstack((GEN)av)) avma = av; } INLINE void killblock(GEN x) { gunclone(x); } INLINE int is_universal_constant(GEN x) { return (x >= gen_0 && x <= ghalf); } /*******************************************************************/ /* */ /* CONVERSION / ASSIGNMENT */ /* */ /*******************************************************************/ /* z is a type which may be a t_COMPLEX component (not a t_QUAD) */ INLINE GEN cxcompotor(GEN z, long prec) { switch(typ(z)) { case t_INT: return itor(z, prec); case t_FRAC: return fractor(z, prec); case t_REAL: return rtor(z, prec); default: pari_err_TYPE("cxcompotor",z); return NULL; /* LCOV_EXCL_LINE */ } } INLINE GEN cxtofp(GEN x, long prec) { retmkcomplex(cxcompotor(gel(x,1),prec), cxcompotor(gel(x,2),prec)); } INLINE GEN cxtoreal(GEN q) { return (typ(q) == t_COMPLEX && gequal0(gel(q,2)))? gel(q,1): q; } INLINE double gtodouble(GEN x) { if (typ(x)!=t_REAL) { pari_sp av = avma; x = gtofp(x, DEFAULTPREC); if (typ(x)!=t_REAL) pari_err_TYPE("gtodouble [t_REAL expected]", x); avma = av; } return rtodbl(x); } INLINE long gtos(GEN x) { if (typ(x) != t_INT) pari_err_TYPE("gtos [integer expected]",x); return itos(x); } INLINE ulong gtou(GEN x) { if (typ(x) != t_INT || signe(x)<0) pari_err_TYPE("gtou [integer >=0 expected]",x); return itou(x); } INLINE GEN absfrac(GEN x) { GEN y = cgetg(3, t_FRAC); gel(y,1) = absi(gel(x,1)); gel(y,2) = icopy(gel(x,2)); return y; } INLINE GEN absfrac_shallow(GEN x) { return signe(gel(x,1))>0? x: mkfrac(negi(gel(x,1)), gel(x,2)); } INLINE GEN Q_abs(GEN x) { return (typ(x) == t_INT)? absi(x): absfrac(x); } INLINE GEN Q_abs_shallow(GEN x) { return (typ(x) == t_INT)? absi_shallow(x): absfrac_shallow(x); } INLINE GEN R_abs_shallow(GEN x) { return (typ(x) == t_FRAC)? absfrac_shallow(x): mpabs_shallow(x); } INLINE GEN R_abs(GEN x) { return (typ(x) == t_FRAC)? absfrac(x): mpabs(x); } /* Force z to be of type real/complex with floating point components */ INLINE GEN gtofp(GEN z, long prec) { switch(typ(z)) { case t_INT: return itor(z, prec); case t_FRAC: return fractor(z, prec); case t_REAL: return rtor(z, prec); case t_COMPLEX: { GEN a = gel(z,1), b = gel(z,2); if (isintzero(b)) return cxcompotor(a, prec); if (isintzero(a)) { GEN y = cgetg(3, t_COMPLEX); b = cxcompotor(b, prec); gel(y,1) = real_0_bit(expo(b) - prec2nbits(prec)); gel(y,2) = b; return y; } return cxtofp(z, prec); } case t_QUAD: return quadtofp(z, prec); default: pari_err_TYPE("gtofp",z); return NULL; /* LCOV_EXCL_LINE */ } } /* Force z to be of type real / int */ INLINE GEN gtomp(GEN z, long prec) { switch(typ(z)) { case t_INT: return z; case t_FRAC: return fractor(z, prec); case t_REAL: return rtor(z, prec); case t_QUAD: z = quadtofp(z, prec); if (typ(z) == t_REAL) return z; default: pari_err_TYPE("gtomp",z); return NULL; /* LCOV_EXCL_LINE */ } } INLINE GEN RgX_gtofp(GEN x, long prec) { long l; GEN y = cgetg_copy(x, &l); while (--l > 1) gel(y,l) = gtofp(gel(x,l), prec); y[1] = x[1]; return y; } INLINE GEN RgC_gtofp(GEN x, long prec) { pari_APPLY_type(t_COL, gtofp(gel(x,i), prec)) } INLINE GEN RgV_gtofp(GEN x, long prec) { pari_APPLY_type(t_VEC, gtofp(gel(x,i), prec)) } INLINE GEN RgM_gtofp(GEN x, long prec) { pari_APPLY_same(RgC_gtofp(gel(x,i), prec)) } INLINE GEN RgC_gtomp(GEN x, long prec) { pari_APPLY_type(t_COL, gtomp(gel(x,i), prec)) } INLINE GEN RgM_gtomp(GEN x, long prec) { pari_APPLY_same(RgC_gtomp(gel(x,i), prec)) } INLINE GEN RgX_fpnorml2(GEN x, long prec) { pari_sp av = avma; return gerepileupto(av, gnorml2(RgX_gtofp(x, prec))); } INLINE GEN RgC_fpnorml2(GEN x, long prec) { pari_sp av = avma; return gerepileupto(av, gnorml2(RgC_gtofp(x, prec))); } INLINE GEN RgM_fpnorml2(GEN x, long prec) { pari_sp av = avma; return gerepileupto(av, gnorml2(RgM_gtofp(x, prec))); } /* y a t_REAL */ INLINE void affgr(GEN x, GEN y) { pari_sp av; switch(typ(x)) { case t_INT: affir(x,y); break; case t_REAL: affrr(x,y); break; case t_FRAC: rdiviiz(gel(x,1),gel(x,2), y); break; case t_QUAD: av = avma; affgr(quadtofp(x,realprec(y)), y); avma = av; break; default: pari_err_TYPE2("=",x,y); } } INLINE GEN affc_fixlg(GEN x, GEN res) { if (typ(x) == t_COMPLEX) { affrr_fixlg(gel(x,1), gel(res,1)); affrr_fixlg(gel(x,2), gel(res,2)); } else { avma = (pari_sp)(res+3); res = cgetr(realprec(gel(res,1))); affrr_fixlg(x, res); } return res; } INLINE GEN trunc_safe(GEN x) { long e; return gcvtoi(x,&e); } /*******************************************************************/ /* */ /* LENGTH CONVERSIONS */ /* */ /*******************************************************************/ INLINE long ndec2nlong(long x) { return 1 + (long)((x)*(LOG2_10/BITS_IN_LONG)); } INLINE long ndec2prec(long x) { return 2 + ndec2nlong(x); } INLINE long ndec2nbits(long x) { return ndec2nlong(x) << TWOPOTBITS_IN_LONG; } /* Fast implementation of ceil(x / (8*sizeof(long))); typecast to (ulong) * to avoid overflow. Faster than 1 + ((x-1)>>TWOPOTBITS_IN_LONG)) : * addl, shrl instead of subl, sarl, addl */ INLINE long nbits2nlong(long x) { return (long)(((ulong)x+BITS_IN_LONG-1) >> TWOPOTBITS_IN_LONG); } INLINE long nbits2extraprec(long x) { return (long)(((ulong)x+BITS_IN_LONG-1) >> TWOPOTBITS_IN_LONG); } /* Fast implementation of 2 + nbits2nlong(x) */ INLINE long nbits2prec(long x) { return (long)(((ulong)x+3*BITS_IN_LONG-1) >> TWOPOTBITS_IN_LONG); } INLINE long nbits2lg(long x) { return (long)(((ulong)x+3*BITS_IN_LONG-1) >> TWOPOTBITS_IN_LONG); } /* ceil(x / sizeof(long)) */ INLINE long nchar2nlong(long x) { return (long)(((ulong)x+sizeof(long)-1) >> (TWOPOTBITS_IN_LONG-3L)); } INLINE long prec2nbits(long x) { return (x-2) * BITS_IN_LONG; } INLINE double bit_accuracy_mul(long x, double y) { return (x-2) * (BITS_IN_LONG*y); } INLINE double prec2nbits_mul(long x, double y) { return (x-2) * (BITS_IN_LONG*y); } INLINE long bit_prec(GEN x) { return prec2nbits(realprec(x)); } INLINE long bit_accuracy(long x) { return prec2nbits(x); } INLINE long prec2ndec(long x) { return (long)prec2nbits_mul(x, LOG10_2); } INLINE long nbits2ndec(long x) { return (long)(x * LOG10_2); } INLINE long precdbl(long x) {return (x - 1) << 1;} INLINE long divsBIL(long n) { return n >> TWOPOTBITS_IN_LONG; } INLINE long remsBIL(long n) { return n & (BITS_IN_LONG-1); } /*********************************************************************/ /** **/ /** OPERATIONS MODULO m **/ /** **/ /*********************************************************************/ /* Assume m > 0, more efficient if 0 <= a, b < m */ INLINE GEN Fp_red(GEN a, GEN m) { return modii(a, m); } INLINE GEN Fp_add(GEN a, GEN b, GEN m) { pari_sp av=avma; GEN p = addii(a,b); long s = signe(p); if (!s) return p; /* = gen_0 */ if (s > 0) /* general case */ { GEN t = subii(p, m); s = signe(t); if (!s) { avma = av; return gen_0; } if (s < 0) { avma = (pari_sp)p; return p; } if (cmpii(t, m) < 0) return gerepileuptoint(av, t); /* general case ! */ p = remii(t, m); } else p = modii(p, m); return gerepileuptoint(av, p); } INLINE GEN Fp_sub(GEN a, GEN b, GEN m) { pari_sp av=avma; GEN p = subii(a,b); long s = signe(p); if (!s) return p; /* = gen_0 */ if (s > 0) { if (cmpii(p, m) < 0) return p; /* general case ! */ p = remii(p, m); } else { GEN t = addii(p, m); if (!s) { avma = av; return gen_0; } if (s > 0) return gerepileuptoint(av, t); /* general case ! */ p = modii(t, m); } return gerepileuptoint(av, p); } INLINE GEN Fp_neg(GEN b, GEN m) { pari_sp av = avma; long s = signe(b); GEN p; if (!s) return gen_0; if (s > 0) { p = subii(m, b); if (signe(p) >= 0) return p; /* general case ! */ p = modii(p, m); } else p = remii(negi(b), m); return gerepileuptoint(av, p); } INLINE GEN Fp_halve(GEN a, GEN p) { if (mpodd(a)) a = addii(a,p); return shifti(a,-1); } /* assume 0 <= u < p and ps2 = p>>1 */ INLINE GEN Fp_center(GEN u, GEN p, GEN ps2) { return abscmpii(u,ps2)<=0? icopy(u): subii(u,p); } /* same without copy */ INLINE GEN Fp_center_i(GEN u, GEN p, GEN ps2) { return abscmpii(u,ps2)<=0? u: subii(u,p); } /* x + y*z mod p */ INLINE GEN Fp_addmul(GEN x, GEN y, GEN z, GEN p) { pari_sp av; if (!signe(y) || !signe(z)) return Fp_red(x, p); if (!signe(x)) return Fp_mul(z,y, p); av = avma; return gerepileuptoint(av, modii(addii(x, mulii(y,z)), p)); } INLINE GEN Fp_mul(GEN a, GEN b, GEN m) { pari_sp av=avma; GEN p; /*HACK: assume modii use <=lg(p)+(lg(m)<<1) space*/ (void)new_chunk(lg(a)+lg(b)+(lg(m)<<1)); p = mulii(a,b); avma = av; return modii(p,m); } INLINE GEN Fp_sqr(GEN a, GEN m) { pari_sp av=avma; GEN p; /*HACK: assume modii use <=lg(p)+(lg(m)<<1) space*/ (void)new_chunk((lg(a)+lg(m))<<1); p = sqri(a); avma = av; return remii(p,m); /*Use remii: p >= 0 */ } INLINE GEN Fp_mulu(GEN a, ulong b, GEN m) { long l = lgefint(m); if (l == 3) { ulong mm = m[2]; return utoi( Fl_mul(umodiu(a, mm), b, mm) ); } else { pari_sp av = avma; GEN p; /*HACK: assume modii use <=lg(p)+(lg(m)<<1) space*/ (void)new_chunk(lg(a)+1+(l<<1)); p = muliu(a,b); avma = av; return modii(p,m); } } INLINE GEN Fp_muls(GEN a, long b, GEN m) { long l = lgefint(m); if (l == 3) { ulong mm = m[2]; if (b < 0) { ulong t = Fl_mul(umodiu(a, mm), -b, mm); return t? utoipos(mm - t): gen_0; } else return utoi( Fl_mul(umodiu(a, mm), b, mm) ); } else { pari_sp av = avma; GEN p; /*HACK: assume modii use <=lg(p)+(lg(m)<<1) space*/ (void)new_chunk(lg(a)+1+(l<<1)); p = mulis(a,b); avma = av; return modii(p,m); } } INLINE GEN Fp_inv(GEN a, GEN m) { GEN res; if (! invmod(a,m,&res)) pari_err_INV("Fp_inv", mkintmod(res,m)); return res; } INLINE GEN Fp_invsafe(GEN a, GEN m) { GEN res; if (! invmod(a,m,&res)) return NULL; return res; } INLINE GEN Fp_div(GEN a, GEN b, GEN m) { pari_sp av=avma; GEN p; /*HACK: assume modii use <=lg(p)+(lg(m)<<1) space*/ (void)new_chunk(lg(a)+(lg(m)<<1)); p = mulii(a, Fp_inv(b,m)); avma = av; return modii(p,m); } INLINE GEN Flx_mulu(GEN x, ulong a, ulong p) { return Flx_Fl_mul(x,a%p,p); } INLINE GEN get_F2x_mod(GEN T) { return typ(T)==t_VEC? gel(T,2): T; } INLINE long get_F2x_var(GEN T) { return typ(T)==t_VEC? mael(T,2,1): T[1]; } INLINE long get_F2x_degree(GEN T) { return typ(T)==t_VEC? F2x_degree(gel(T,2)): F2x_degree(T); } INLINE GEN get_F2xqX_mod(GEN T) { return typ(T)==t_VEC? gel(T,2): T; } INLINE long get_F2xqX_var(GEN T) { return typ(T)==t_VEC? varn(gel(T,2)): varn(T); } INLINE long get_F2xqX_degree(GEN T) { return typ(T)==t_VEC? degpol(gel(T,2)): degpol(T); } INLINE GEN get_Flx_mod(GEN T) { return typ(T)==t_VEC? gel(T,2): T; } INLINE long get_Flx_var(GEN T) { return typ(T)==t_VEC? mael(T,2,1): T[1]; } INLINE long get_Flx_degree(GEN T) { return typ(T)==t_VEC? degpol(gel(T,2)): degpol(T); } INLINE GEN get_FlxqX_mod(GEN T) { return typ(T)==t_VEC? gel(T,2): T; } INLINE long get_FlxqX_var(GEN T) { return typ(T)==t_VEC? varn(gel(T,2)): varn(T); } INLINE long get_FlxqX_degree(GEN T) { return typ(T)==t_VEC? degpol(gel(T,2)): degpol(T); } INLINE GEN get_FpX_mod(GEN T) { return typ(T)==t_VEC? gel(T,2): T; } INLINE long get_FpX_var(GEN T) { return typ(T)==t_VEC? varn(gel(T,2)): varn(T); } INLINE long get_FpX_degree(GEN T) { return typ(T)==t_VEC? degpol(gel(T,2)): degpol(T); } INLINE GEN get_FpXQX_mod(GEN T) { return typ(T)==t_VEC? gel(T,2): T; } INLINE long get_FpXQX_var(GEN T) { return typ(T)==t_VEC? varn(gel(T,2)): varn(T); } INLINE long get_FpXQX_degree(GEN T) { return typ(T)==t_VEC? degpol(gel(T,2)): degpol(T); } /*******************************************************************/ /* */ /* ADDMULII / SUBMULII */ /* */ /*******************************************************************/ /* x - y*z */ INLINE GEN submulii(GEN x, GEN y, GEN z) { long lx = lgefint(x), ly, lz; pari_sp av; GEN t; if (lx == 2) { t = mulii(z,y); togglesign(t); return t; } ly = lgefint(y); if (ly == 2) return icopy(x); lz = lgefint(z); av = avma; (void)new_chunk(lx+ly+lz); /* HACK */ t = mulii(z, y); avma = av; return subii(x,t); } /* y*z - x */ INLINE GEN mulsubii(GEN y, GEN z, GEN x) { long lx = lgefint(x), ly, lz; pari_sp av; GEN t; if (lx == 2) return mulii(z,y); ly = lgefint(y); if (ly == 2) return negi(x); lz = lgefint(z); av = avma; (void)new_chunk(lx+ly+lz); /* HACK */ t = mulii(z, y); avma = av; return subii(t,x); } /* x - u*y */ INLINE GEN submuliu(GEN x, GEN y, ulong u) { pari_sp av; long ly = lgefint(y); if (ly == 2) return icopy(x); av = avma; (void)new_chunk(3+ly+lgefint(x)); /* HACK */ y = mului(u,y); avma = av; return subii(x, y); } /* x + u*y */ INLINE GEN addmuliu(GEN x, GEN y, ulong u) { pari_sp av; long ly = lgefint(y); if (ly == 2) return icopy(x); av = avma; (void)new_chunk(3+ly+lgefint(x)); /* HACK */ y = mului(u,y); avma = av; return addii(x, y); } /* x - u*y */ INLINE GEN submuliu_inplace(GEN x, GEN y, ulong u) { pari_sp av; long ly = lgefint(y); if (ly == 2) return x; av = avma; (void)new_chunk(3+ly+lgefint(x)); /* HACK */ y = mului(u,y); avma = av; return subii(x, y); } /* x + u*y */ INLINE GEN addmuliu_inplace(GEN x, GEN y, ulong u) { pari_sp av; long ly = lgefint(y); if (ly == 2) return x; av = avma; (void)new_chunk(3+ly+lgefint(x)); /* HACK */ y = mului(u,y); avma = av; return addii(x, y); } /* ux + vy */ INLINE GEN lincombii(GEN u, GEN v, GEN x, GEN y) { long lx = lgefint(x), ly; GEN p1, p2; pari_sp av; if (lx == 2) return mulii(v,y); ly = lgefint(y); if (ly == 2) return mulii(u,x); av = avma; (void)new_chunk(lx+ly+lgefint(u)+lgefint(v)); /* HACK */ p1 = mulii(u,x); p2 = mulii(v,y); avma = av; return addii(p1,p2); } /*******************************************************************/ /* */ /* GEN SUBTYPES */ /* */ /*******************************************************************/ INLINE int is_const_t(long t) { return (t < t_POLMOD); } INLINE int is_extscalar_t(long t) { return (t <= t_POL); } INLINE int is_intreal_t(long t) { return (t <= t_REAL); } INLINE int is_matvec_t(long t) { return (t >= t_VEC && t <= t_MAT); } INLINE int is_noncalc_t(long tx) { return (tx) >= t_LIST; } INLINE int is_rational_t(long t) { return (t == t_INT || t == t_FRAC); } INLINE int is_real_t(long t) { return (t == t_INT || t == t_REAL || t == t_FRAC); } INLINE int is_recursive_t(long t) { return lontyp[t]; } INLINE int is_scalar_t(long t) { return (t < t_POL); } INLINE int is_vec_t(long t) { return (t == t_VEC || t == t_COL); } /*******************************************************************/ /* */ /* TRANSCENDENTAL */ /* */ /*******************************************************************/ INLINE GEN sqrtr(GEN x) { long s = signe(x); if (s == 0) return real_0_bit(expo(x) >> 1); if (s >= 0) return sqrtr_abs(x); retmkcomplex(gen_0, sqrtr_abs(x)); } INLINE GEN cbrtr_abs(GEN x) { return sqrtnr_abs(x, 3); } INLINE GEN cbrtr(GEN x) { long s = signe(x); GEN r; if (s == 0) return real_0_bit(expo(x) / 3); r = cbrtr_abs(x); if (s < 0) togglesign(r); return r; } INLINE GEN sqrtnr(GEN x, long n) { long s = signe(x); GEN r; if (s == 0) return real_0_bit(expo(x) / n); r = sqrtnr_abs(x, n); if (s < 0) pari_err_IMPL("sqrtnr for x < 0"); return r; } INLINE long logint(GEN B, GEN y) { return logintall(B,y,NULL); } INLINE ulong ulogint(ulong B, ulong y) { ulong r; long e; if (y == 2) return expu(B); r = y; for (e=1;; e++) { /* here, r = y^e, r2 = y^(e-1) */ if (r >= B) return r == B? e: e-1; r = umuluu_or_0(y, r); if (!r) return e; } } /*******************************************************************/ /* */ /* MISCELLANEOUS */ /* */ /*******************************************************************/ INLINE int ismpzero(GEN x) { return is_intreal_t(typ(x)) && !signe(x); } INLINE int isintzero(GEN x) { return typ(x) == t_INT && !signe(x); } INLINE int isint1(GEN x) { return typ(x)==t_INT && equali1(x); } INLINE int isintm1(GEN x){ return typ(x)==t_INT && equalim1(x);} INLINE int equali1(GEN n) { return (ulong) n[1] == (evallgefint(3UL) | evalsigne(1)) && n[2] == 1; } INLINE int equalim1(GEN n) { return (ulong) n[1] == (evallgefint(3UL) | evalsigne(-1)) && n[2] == 1; } /* works only for POSITIVE integers */ INLINE int is_pm1(GEN n) { return lgefint(n) == 3 && n[2] == 1; } INLINE int is_bigint(GEN n) { long l = lgefint(n); return l > 3 || (l == 3 && (n[2] & HIGHBIT)); } INLINE int odd(long x) { return x & 1; } INLINE int both_odd(long x, long y) { return x & y & 1; } INLINE int isonstack(GEN x) { return ((pari_sp)x >= pari_mainstack->bot && (pari_sp)x < pari_mainstack->top); } /* assume x != 0 and x t_REAL, return an approximation to log2(|x|) */ INLINE double dbllog2r(GEN x) { return log2((double)(ulong)x[2]) + (double)(expo(x) - (BITS_IN_LONG-1)); } INLINE GEN mul_content(GEN cx, GEN cy) { if (!cx) return cy; if (!cy) return cx; return gmul(cx,cy); } INLINE GEN inv_content(GEN c) { return c? ginv(c): NULL; } INLINE GEN mul_denom(GEN dx, GEN dy) { if (!dx) return dy; if (!dy) return dx; return mulii(dx,dy); } /* POLYNOMIALS */ INLINE GEN constant_coeff(GEN x) { return signe(x)? gel(x,2): gen_0; } INLINE GEN leading_coeff(GEN x) { return lg(x) == 2? gen_0: gel(x,lg(x)-1); } INLINE ulong Flx_lead(GEN x) { return lg(x) == 2? 0: x[lg(x)-1]; } INLINE ulong Flx_constant(GEN x) { return lg(x) == 2? 0: x[2]; } INLINE long degpol(GEN x) { return lg(x)-3; } INLINE long lgpol(GEN x) { return lg(x)-2; } INLINE long lgcols(GEN x) { return lg(gel(x,1)); } INLINE long nbrows(GEN x) { return lg(gel(x,1))-1; } INLINE GEN truecoef(GEN x, long n) { return polcoef(x,n,-1); } INLINE GEN ZXQ_mul(GEN y, GEN x, GEN T) { return ZX_rem(ZX_mul(y, x), T); } INLINE GEN ZXQ_sqr(GEN x, GEN T) { return ZX_rem(ZX_sqr(x), T); } INLINE GEN RgX_copy(GEN x) { long lx, i; GEN y = cgetg_copy(x, &lx); y[1] = x[1]; for (i = 2; i l)? gen_0: gel(x,n+2); } INLINE GEN RgX_renormalize(GEN x) { return RgX_renormalize_lg(x, lg(x)); } INLINE GEN RgX_div(GEN x, GEN y) { return RgX_divrem(x,y,NULL); } INLINE GEN RgXQX_div(GEN x, GEN y, GEN T) { return RgXQX_divrem(x,y,T,NULL); } INLINE GEN RgXQX_rem(GEN x, GEN y, GEN T) { return RgXQX_divrem(x,y,T,ONLY_REM); } INLINE GEN FpX_div(GEN x, GEN y, GEN p) { return FpX_divrem(x,y,p, NULL); } INLINE GEN Flx_div(GEN x, GEN y, ulong p) { return Flx_divrem(x,y,p, NULL); } INLINE GEN F2x_div(GEN x, GEN y) { return F2x_divrem(x,y, NULL); } INLINE GEN FpV_FpC_mul(GEN x, GEN y, GEN p) { return FpV_dotproduct(x,y,p); } INLINE GEN pol0_Flx(long sv) { return mkvecsmall(sv); } INLINE GEN pol1_Flx(long sv) { return mkvecsmall2(sv, 1); } INLINE GEN polx_Flx(long sv) { return mkvecsmall3(sv, 0, 1); } INLINE GEN zero_zx(long sv) { return zero_Flx(sv); } INLINE GEN polx_zx(long sv) { return polx_Flx(sv); } INLINE GEN zx_shift(GEN x, long n) { return Flx_shift(x,n); } INLINE GEN zx_renormalize(GEN x, long l) { return Flx_renormalize(x,l); } INLINE GEN zero_F2x(long sv) { return zero_Flx(sv); } INLINE GEN pol0_F2x(long sv) { return pol0_Flx(sv); } INLINE GEN pol1_F2x(long sv) { return pol1_Flx(sv); } INLINE GEN polx_F2x(long sv) { return mkvecsmall2(sv, 2); } INLINE int F2x_equal1(GEN x) { return Flx_equal1(x); } INLINE int F2x_equal(GEN V, GEN W) { return Flx_equal(V,W); } INLINE GEN F2x_copy(GEN x) { return leafcopy(x); } INLINE GEN F2v_copy(GEN x) { return leafcopy(x); } INLINE GEN Flv_copy(GEN x) { return leafcopy(x); } INLINE GEN Flx_copy(GEN x) { return leafcopy(x); } INLINE GEN vecsmall_copy(GEN x) { return leafcopy(x); } INLINE int Flx_equal1(GEN x) { return degpol(x)==0 && x[2] == 1; } INLINE int ZX_equal1(GEN x) { return degpol(x)==0 && equali1(gel(x,2)); } INLINE int ZX_is_monic(GEN x) { return equali1(leading_coeff(x)); } INLINE GEN ZX_renormalize(GEN x, long lx) { return ZXX_renormalize(x,lx); } INLINE GEN FpX_renormalize(GEN x, long lx) { return ZXX_renormalize(x,lx); } INLINE GEN FpXX_renormalize(GEN x, long lx) { return ZXX_renormalize(x,lx); } INLINE GEN FpXQX_renormalize(GEN x, long lx) { return ZXX_renormalize(x,lx); } INLINE GEN F2x_renormalize(GEN x, long lx) { return Flx_renormalize(x,lx); } INLINE GEN F2v_to_F2x(GEN x, long sv) { GEN y = leafcopy(x); y[1] = sv; F2x_renormalize(y, lg(y)); return y; } INLINE long sturm(GEN x) { return sturmpart(x, NULL, NULL); } INLINE long gval(GEN x, long v) { pari_sp av = avma; long n = gvaluation(x, pol_x(v)); avma = av; return n; } INLINE void RgX_shift_inplace_init(long v) { if (v) (void)cgetg(v, t_VECSMALL); } /* shift polynomial in place. assume v free cells have been left before x */ INLINE GEN RgX_shift_inplace(GEN x, long v) { long i, lx; GEN y, z; if (!v) return x; lx = lg(x); if (lx == 2) return x; y = x + v; z = x + lx; /* stackdummy from normalizepol: move it up */ if (lg(z) != v) x[lx + v] = z[0]; for (i = lx-1; i >= 2; i--) gel(y,i) = gel(x,i); for (i = v+1; i >= 2; i--) gel(x,i) = gen_0; /* leave x[1] alone: it is correct */ x[0] = evaltyp(t_POL) | evallg(lx+v); return x; } /* LINEAR ALGEBRA */ INLINE GEN zv_to_ZV(GEN x) { return vecsmall_to_vec(x); } INLINE GEN zc_to_ZC(GEN x) { return vecsmall_to_col(x); } INLINE GEN ZV_to_zv(GEN x) { return vec_to_vecsmall(x); } INLINE GEN zx_to_zv(GEN x, long N) { return Flx_to_Flv(x,N); } INLINE GEN zv_to_zx(GEN x, long sv) { return Flv_to_Flx(x,sv); } INLINE GEN zm_to_zxV(GEN x, long sv) { return Flm_to_FlxV(x,sv); } INLINE GEN zero_zm(long x, long y) { return zero_Flm(x,y); } INLINE GEN zero_zv(long x) { return zero_Flv(x); } INLINE GEN zm_transpose(GEN x) { return Flm_transpose(x); } INLINE GEN zm_copy(GEN x) { return Flm_copy(x); } INLINE GEN zv_copy(GEN x) { return Flv_copy(x); } INLINE GEN zm_row(GEN x, long i) { return Flm_row(x,i); } INLINE GEN ZC_hnfrem(GEN x, GEN y) { return ZC_hnfremdiv(x,y,NULL); } INLINE GEN ZM_hnfrem(GEN x, GEN y) { return ZM_hnfdivrem(x,y,NULL); } INLINE GEN ZM_lll(GEN x, double D, long f) { return ZM_lll_norms(x,D,f,NULL); } INLINE void RgM_dimensions(GEN x, long *m, long *n) { *n = lg(x)-1; *m = *n? nbrows(x): 0; } INLINE GEN RgM_shallowcopy(GEN x) { long l; GEN y = cgetg_copy(x, &l); while (--l > 0) gel(y,l) = leafcopy(gel(x,l)); return y; } INLINE GEN F2m_copy(GEN x) { return RgM_shallowcopy(x); } INLINE GEN Flm_copy(GEN x) { return RgM_shallowcopy(x); } /* divisibility: return 1 if y[i] | x[i] for all i, 0 otherwise. Assume * x,y are ZV of the same length */ INLINE int ZV_dvd(GEN x, GEN y) { long i, l = lg(x); for (i=1; i < l; i++) if ( ! dvdii( gel(x,i), gel(y,i) ) ) return 0; return 1; } /* Fq */ INLINE GEN Fq_red(GEN x, GEN T, GEN p) { return typ(x)==t_INT? Fp_red(x,p): FpXQ_red(x,T,p); } INLINE GEN Fq_to_FpXQ(GEN x, GEN T, GEN p /*unused*/) { (void) p; return typ(x)==t_INT ? scalarpol(x, get_FpX_var(T)): x; } INLINE GEN Rg_to_Fq(GEN x, GEN T, GEN p) { return T? Rg_to_FpXQ(x,T,p): Rg_to_Fp(x,p); } INLINE GEN gener_Fq_local(GEN T, GEN p, GEN L) { return T? gener_FpXQ_local(T,p, L) : pgener_Fp_local(p, L); } /* FpXQX */ INLINE GEN FpXQX_div(GEN x, GEN y, GEN T, GEN p) { return FpXQX_divrem(x, y, T, p, NULL); } INLINE GEN FlxqX_div(GEN x, GEN y, GEN T, ulong p) { return FlxqX_divrem(x, y, T, p, NULL); } INLINE GEN F2xqX_div(GEN x, GEN y, GEN T) { return F2xqX_divrem(x, y, T, NULL); } /* FqX */ INLINE GEN FqX_red(GEN z, GEN T, GEN p) { return T? FpXQX_red(z, T, p): FpX_red(z, p); } INLINE GEN FqX_add(GEN x,GEN y,GEN T,GEN p) { return T? FpXX_add(x,y,p): FpX_add(x,y,p); } INLINE GEN FqX_neg(GEN x,GEN T,GEN p) { return T? FpXX_neg(x,p): FpX_neg(x,p); } INLINE GEN FqX_sub(GEN x,GEN y,GEN T,GEN p) { return T? FpXX_sub(x,y,p): FpX_sub(x,y,p); } INLINE GEN FqX_Fp_mul(GEN P, GEN u, GEN T, GEN p) { return T? FpXX_Fp_mul(P, u, p): FpX_Fp_mul(P, u, p); } INLINE GEN FqX_Fq_mul(GEN P, GEN U, GEN T, GEN p) { return typ(U)==t_INT ? FqX_Fp_mul(P, U, T, p): FpXQX_FpXQ_mul(P, U, T, p); } INLINE GEN FqX_mul(GEN x, GEN y, GEN T, GEN p) { return T? FpXQX_mul(x, y, T, p): FpX_mul(x, y, p); } INLINE GEN FqX_mulu(GEN x, ulong y, GEN T, GEN p) { return T? FpXX_mulu(x, y, p): FpX_mulu(x, y, p); } INLINE GEN FqX_sqr(GEN x, GEN T, GEN p) { return T? FpXQX_sqr(x, T, p): FpX_sqr(x, p); } INLINE GEN FqX_powu(GEN x, ulong n, GEN T, GEN p) { return T? FpXQX_powu(x, n, T, p): FpX_powu(x, n, p); } INLINE GEN FqX_halve(GEN x, GEN T, GEN p) { return T? FpXX_halve(x, p): FpX_halve(x, p); } INLINE GEN FqX_div(GEN x, GEN y, GEN T, GEN p) { return T? FpXQX_divrem(x,y,T,p,NULL): FpX_divrem(x,y,p,NULL); } INLINE GEN FqX_get_red(GEN S, GEN T, GEN p) { return T? FpXQX_get_red(S,T,p): FpX_get_red(S,p); } INLINE GEN FqX_rem(GEN x, GEN y, GEN T, GEN p) { return T? FpXQX_rem(x,y,T,p): FpX_rem(x,y,p); } INLINE GEN FqX_divrem(GEN x, GEN y, GEN T, GEN p, GEN *z) { return T? FpXQX_divrem(x,y,T,p,z): FpX_divrem(x,y,p,z); } INLINE GEN FqX_div_by_X_x(GEN x, GEN y, GEN T, GEN p, GEN *z) { return T? FpXQX_div_by_X_x(x,y,T,p,z): FpX_div_by_X_x(x,y,p,z); } INLINE GEN FqX_halfgcd(GEN P,GEN Q,GEN T,GEN p) {return T? FpXQX_halfgcd(P,Q,T,p): FpX_halfgcd(P,Q,p);} INLINE GEN FqX_gcd(GEN P,GEN Q,GEN T,GEN p) {return T? FpXQX_gcd(P,Q,T,p): FpX_gcd(P,Q,p);} INLINE GEN FqX_extgcd(GEN P,GEN Q,GEN T,GEN p, GEN *U, GEN *V) { return T? FpXQX_extgcd(P,Q,T,p,U,V): FpX_extgcd(P,Q,p,U,V); } INLINE GEN FqX_normalize(GEN z, GEN T, GEN p) { return T? FpXQX_normalize(z, T, p): FpX_normalize(z, p); } INLINE GEN FqX_deriv(GEN f, GEN T, GEN p) { return T? FpXX_deriv(f, p): FpX_deriv(f, p); } INLINE GEN FqX_integ(GEN f, GEN T, GEN p) { return T? FpXX_integ(f, p): FpX_integ(f, p); } INLINE GEN FqX_factor(GEN f, GEN T, GEN p) { return T?FpXQX_factor(f, T, p): FpX_factor(f, p); } INLINE GEN FqX_factor_squarefree(GEN f, GEN T, GEN p) { return T ? FpXQX_factor_squarefree(f, T, p): FpX_factor_squarefree(f, p); } INLINE GEN FqX_ddf(GEN f, GEN T, GEN p) { return T ? FpXQX_ddf(f, T, p): FpX_ddf(f, p); } INLINE GEN FqX_degfact(GEN f, GEN T, GEN p) { return T?FpXQX_degfact(f, T, p): FpX_degfact(f, p); } INLINE GEN FqX_roots(GEN f, GEN T, GEN p) { return T?FpXQX_roots(f, T, p): FpX_roots(f, p); } INLINE GEN FqX_to_mod(GEN f, GEN T, GEN p) { return T?FpXQX_to_mod(f, T, p): FpX_to_mod(f, p); } /*FqXQ*/ INLINE GEN FqXQ_add(GEN x, GEN y, GEN S/*unused*/, GEN T, GEN p) { (void)S; return T? FpXX_add(x,y,p): FpX_add(x,y,p); } INLINE GEN FqXQ_sub(GEN x, GEN y, GEN S/*unused*/, GEN T, GEN p) { (void)S; return T? FpXX_sub(x,y,p): FpX_sub(x,y,p); } INLINE GEN FqXQ_div(GEN x, GEN y, GEN S, GEN T, GEN p) { return T? FpXQXQ_div(x,y,S,T,p): FpXQ_div(x,y,S,p); } INLINE GEN FqXQ_inv(GEN x, GEN S, GEN T, GEN p) { return T? FpXQXQ_inv(x,S,T,p): FpXQ_inv(x,S,p); } INLINE GEN FqXQ_invsafe(GEN x, GEN S, GEN T, GEN p) { return T? FpXQXQ_invsafe(x,S,T,p): FpXQ_inv(x,S,p); } INLINE GEN FqXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p) { return T? FpXQXQ_mul(x,y,S,T,p): FpXQ_mul(x,y,S,p); } INLINE GEN FqXQ_sqr(GEN x, GEN S, GEN T, GEN p) { return T? FpXQXQ_sqr(x,S,T,p): FpXQ_sqr(x,S,p); } INLINE GEN FqXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p) { return T? FpXQXQ_pow(x,n,S,T,p): FpXQ_pow(x,n,S,p); } /*FqXn*/ INLINE GEN FqXn_exp(GEN x, long n, GEN T, GEN p) { return T? FpXQXn_exp(x,n,T,p): FpXn_exp(x,n,p); } INLINE GEN FqXn_inv(GEN x, long n, GEN T, GEN p) { return T? FpXQXn_inv(x,n,T,p): FpXn_inv(x,n,p); } INLINE GEN FqXn_mul(GEN x, GEN y, long n, GEN T, GEN p) { return T? FpXQXn_mul(x, y, n, T, p): FpXn_mul(x, y, n, p); } INLINE GEN FqXn_sqr(GEN x, long n, GEN T, GEN p) { return T? FpXQXn_sqr(x,n,T,p): FpXn_sqr(x,n,p); } /*FpXQ*/ INLINE GEN FpXQ_add(GEN x,GEN y,GEN T/*unused*/,GEN p) { (void)T; return FpX_add(x,y,p); } INLINE GEN FpXQ_sub(GEN x,GEN y,GEN T/*unused*/,GEN p) { (void)T; return FpX_sub(x,y,p); } /*Flxq*/ INLINE GEN Flxq_add(GEN x,GEN y,GEN T/*unused*/,ulong p) { (void)T; return Flx_add(x,y,p); } INLINE GEN Flxq_sub(GEN x,GEN y,GEN T/*unused*/,ulong p) { (void)T; return Flx_sub(x,y,p); } /* F2x */ INLINE ulong F2x_coeff(GEN x,long v) { ulong u=(ulong)x[2+divsBIL(v)]; return (u>>remsBIL(v))&1UL; } INLINE void F2x_clear(GEN x,long v) { ulong* u=(ulong*)&x[2+divsBIL(v)]; *u&=~(1UL< 0) return powiu(x, n[2]); z = cgetg(3, t_FRAC); gel(z,1) = gen_1; gel(z,2) = powiu(x, n[2]); return z; } if (ln == 2) return gen_1; /* rare */ /* should never happen */ return powgi(x, n); /* overflow unless x = 0, 1, -1 */ } INLINE GEN powIs(long n) { switch(n & 3) { case 1: return mkcomplex(gen_0,gen_1); case 2: return gen_m1; case 3: return mkcomplex(gen_0,gen_m1); } return gen_1; } /*******************************************************************/ /* */ /* ASSIGNMENTS */ /* */ /*******************************************************************/ INLINE void mpexpz(GEN x, GEN z) { pari_sp av = avma; gaffect(mpexp(x), z); avma = av; } INLINE void mplogz(GEN x, GEN z) { pari_sp av = avma; gaffect(mplog(x), z); avma = av; } INLINE void mpcosz(GEN x, GEN z) { pari_sp av = avma; gaffect(mpcos(x), z); avma = av; } INLINE void mpsinz(GEN x, GEN z) { pari_sp av = avma; gaffect(mpsin(x), z); avma = av; } INLINE void gnegz(GEN x, GEN z) { pari_sp av = avma; gaffect(gneg(x), z); avma = av; } INLINE void gabsz(GEN x, long prec, GEN z) { pari_sp av = avma; gaffect(gabs(x,prec), z); avma = av; } INLINE void gaddz(GEN x, GEN y, GEN z) { pari_sp av = avma; gaffect(gadd(x,y), z); avma = av; } INLINE void gsubz(GEN x, GEN y, GEN z) { pari_sp av = avma; gaffect(gsub(x,y), z); avma = av; } INLINE void gmulz(GEN x, GEN y, GEN z) { pari_sp av = avma; gaffect(gmul(x,y), z); avma = av; } INLINE void gdivz(GEN x, GEN y, GEN z) { pari_sp av = avma; gaffect(gdiv(x,y), z); avma = av; } INLINE void gdiventz(GEN x, GEN y, GEN z) { pari_sp av = avma; gaffect(gdivent(x,y), z); avma = av; } INLINE void gmodz(GEN x, GEN y, GEN z) { pari_sp av = avma; gaffect(gmod(x,y), z); avma = av; } INLINE void gmul2nz(GEN x, long s, GEN z) { pari_sp av = avma; gaffect(gmul2n(x,s), z); avma = av; } INLINE void gshiftz(GEN x, long s, GEN z) { pari_sp av = avma; gaffect(gshift(x,s), z); avma = av; } /*******************************************************************/ /* */ /* ELLIPTIC CURVES */ /* */ /*******************************************************************/ INLINE GEN ell_get_a1(GEN e) { return gel(e,1); } INLINE GEN ell_get_a2(GEN e) { return gel(e,2); } INLINE GEN ell_get_a3(GEN e) { return gel(e,3); } INLINE GEN ell_get_a4(GEN e) { return gel(e,4); } INLINE GEN ell_get_a6(GEN e) { return gel(e,5); } INLINE GEN ell_get_b2(GEN e) { return gel(e,6); } INLINE GEN ell_get_b4(GEN e) { return gel(e,7); } INLINE GEN ell_get_b6(GEN e) { return gel(e,8); } INLINE GEN ell_get_b8(GEN e) { return gel(e,9); } INLINE GEN ell_get_c4(GEN e) { return gel(e,10); } INLINE GEN ell_get_c6(GEN e) { return gel(e,11); } INLINE GEN ell_get_disc(GEN e) { return gel(e,12); } INLINE GEN ell_get_j(GEN e) { return gel(e,13); } INLINE long ell_get_type(GEN e) { return mael(e,14,1); } INLINE GEN ellff_get_field(GEN x) { return gmael(x, 15, 1); } INLINE GEN ellff_get_a4a6(GEN x) { return gmael(x, 15, 2); } INLINE GEN ellQp_get_zero(GEN x) { return gmael(x, 15, 1); } INLINE long ellQp_get_prec(GEN E) { GEN z = ellQp_get_zero(E); return valp(z); } INLINE GEN ellQp_get_p(GEN E) { GEN z = ellQp_get_zero(E); return gel(z,2); } INLINE long ellR_get_prec(GEN x) { return nbits2prec(mael3(x, 15, 1, 1)); } INLINE long ellR_get_sign(GEN x) { return mael3(x, 15, 1, 2); } INLINE GEN ellnf_get_nf(GEN x) { return checknf_i(gmael(x,15,1)); } INLINE GEN ellnf_get_bnf(GEN x) { return checkbnf_i(gmael(x,15,1)); } INLINE int checkell_i(GEN e) { return typ(e) == t_VEC && lg(e) == 17; } INLINE int ell_is_inf(GEN z) { return lg(z) == 2; } INLINE GEN ellinf(void) { return mkvec(gen_0); } /*******************************************************************/ /* */ /* ALGEBRAIC NUMBER THEORY */ /* */ /*******************************************************************/ INLINE GEN modpr_get_pr(GEN x) { return gel(x,3); } INLINE GEN modpr_get_p(GEN x) { return pr_get_p(modpr_get_pr(x)); } INLINE GEN modpr_get_T(GEN x) { return lg(x) == 4? NULL: gel(x,4); } INLINE GEN pr_get_p(GEN pr) { return gel(pr,1); } INLINE GEN pr_get_gen(GEN pr){ return gel(pr,2); } /* .[2] instead of itos works: e and f are small positive integers */ INLINE long pr_get_e(GEN pr) { return gel(pr,3)[2]; } INLINE long pr_get_f(GEN pr) { return gel(pr,4)[2]; } INLINE GEN pr_get_tau(GEN pr){ return gel(pr,5); } INLINE int pr_is_inert(GEN P) { return pr_get_f(P) == lg(pr_get_gen(P))-1; } INLINE GEN pr_norm(GEN pr) { return powiu(pr_get_p(pr), pr_get_f(pr)); } INLINE ulong upr_norm(GEN pr) { return upowuu(pr_get_p(pr)[2], pr_get_f(pr)); } /* assume nf a genuine nf */ INLINE long nf_get_varn(GEN nf) { return varn(gel(nf,1)); } INLINE GEN nf_get_pol(GEN nf) { return gel(nf,1); } INLINE long nf_get_degree(GEN nf) { return degpol( nf_get_pol(nf) ); } INLINE long nf_get_r1(GEN nf) { GEN x = gel(nf,2); return itou(gel(x,1)); } INLINE long nf_get_r2(GEN nf) { GEN x = gel(nf,2); return itou(gel(x,2)); } INLINE GEN nf_get_disc(GEN nf) { return gel(nf,3); } INLINE GEN nf_get_index(GEN nf) { return gel(nf,4); } INLINE GEN nf_get_M(GEN nf) { return gmael(nf,5,1); } INLINE GEN nf_get_G(GEN nf) { return gmael(nf,5,2); } INLINE GEN nf_get_roundG(GEN nf) { return gmael(nf,5,3); } INLINE GEN nf_get_Tr(GEN nf) { return gmael(nf,5,4); } INLINE GEN nf_get_diff(GEN nf) { return gmael(nf,5,5); } INLINE GEN nf_get_ramified_primes(GEN nf) { return gmael(nf,5,8); } INLINE GEN nf_get_roots(GEN nf) { return gel(nf,6); } INLINE GEN nf_get_zk(GEN nf) { GEN y = gel(nf,7), D = gel(y, 1); if (typ(D) == t_POL) D = gel(D, 2); if (!equali1(D)) y = gdiv(y, D); return y; } INLINE GEN nf_get_zkprimpart(GEN nf) { GEN y = gel(nf,7); /* test for old format of nf.zk: non normalized */ if (!equali1(gel(nf,4)) && gequal1(gel(y,1))) y = Q_remove_denom(y,NULL); return y; } INLINE GEN nf_get_zkden(GEN nf) { GEN y = gel(nf,7), D = gel(y,1); if (typ(D) == t_POL) D = gel(D,2); /* test for old format of nf.zk: non normalized */ if (!equali1(gel(nf,4)) && equali1(D)) D = Q_denom(y); return D; } INLINE GEN nf_get_invzk(GEN nf) { return gel(nf,8); } INLINE void nf_get_sign(GEN nf, long *r1, long *r2) { GEN x = gel(nf,2); *r1 = itou(gel(x,1)); *r2 = itou(gel(x,2)); } INLINE GEN abgrp_get_no(GEN x) { return gel(x,1); } INLINE GEN abgrp_get_cyc(GEN x) { return gel(x,2); } INLINE GEN abgrp_get_gen(GEN x) { return gel(x,3); } INLINE GEN bnf_get_nf(GEN bnf) { return gel(bnf,7); } INLINE GEN bnf_get_clgp(GEN bnf) { return gmael(bnf,8,1); } INLINE GEN bnf_get_no(GEN bnf) { return abgrp_get_no(bnf_get_clgp(bnf)); } INLINE GEN bnf_get_cyc(GEN bnf) { return abgrp_get_cyc(bnf_get_clgp(bnf)); } INLINE GEN bnf_get_gen(GEN bnf) { return abgrp_get_gen(bnf_get_clgp(bnf)); } INLINE GEN bnf_get_reg(GEN bnf) { return gmael(bnf,8,2); } INLINE GEN bnf_get_logfu(GEN bnf) { return gel(bnf,3); } INLINE GEN bnf_get_tuU(GEN bnf) { return gmael3(bnf,8,4,2); } INLINE long bnf_get_tuN(GEN bnf) { return gmael3(bnf,8,4,1)[2]; } INLINE GEN bnf_get_fu(GEN bnf) { GEN fu = bnf_get_fu_nocheck(bnf); if (typ(fu) == t_MAT) pari_err(e_MISC,"missing units in bnf"); return fu; } INLINE GEN bnf_get_fu_nocheck(GEN bnf) { return gmael(bnf,8,5); } INLINE GEN bnr_get_bnf(GEN bnr) { return gel(bnr,1); } INLINE GEN bnr_get_bid(GEN bnr) { return gel(bnr,2); } INLINE GEN bnr_get_mod(GEN bnr) { return gmael(bnr,2,1); } INLINE GEN bnr_get_nf(GEN bnr) { return gmael(bnr,1,7); } INLINE GEN bnr_get_clgp(GEN bnr) { return gel(bnr,5); } INLINE GEN bnr_get_no(GEN bnr) { return abgrp_get_no(bnr_get_clgp(bnr)); } INLINE GEN bnr_get_cyc(GEN bnr) { return abgrp_get_cyc(bnr_get_clgp(bnr)); } INLINE GEN bnr_get_gen_nocheck(GEN bnr) { return abgrp_get_gen(bnr_get_clgp(bnr)); } INLINE GEN bnr_get_gen(GEN bnr) { GEN G = bnr_get_clgp(bnr); if (lg(G) != 4) pari_err(e_MISC,"missing bnr generators: please use bnrinit(,,1)"); return gel(G,3); } INLINE GEN bid_get_mod(GEN bid) { return gel(bid,1); } INLINE GEN bid_get_ideal(GEN bid) { return gmael(bid,1,1); } INLINE GEN bid_get_arch(GEN bid) { return gmael(bid,1,2); } INLINE GEN bid_get_grp(GEN bid) { return gel(bid,2); } INLINE GEN bid_get_fact(GEN bid) { return gmael(bid,3,1); } INLINE GEN bid_get_fact2(GEN bid) { return gmael(bid,3,2); } INLINE GEN bid_get_sprk(GEN bid) { return gmael(bid,4,1); } INLINE GEN bid_get_sarch(GEN bid) { return gmael(bid,4,2); } INLINE GEN bid_get_archp(GEN bid) { return gmael3(bid,4,2,2); } INLINE GEN bid_get_U(GEN bid) { return gel(bid,5); } INLINE GEN bid_get_no(GEN bid) { return abgrp_get_no(bid_get_grp(bid)); } INLINE GEN bid_get_cyc(GEN bid) { return abgrp_get_cyc(bid_get_grp(bid)); } INLINE GEN bid_get_gen_nocheck(GEN bid) { return abgrp_get_gen(bid_get_grp(bid)); } INLINE GEN bid_get_gen(GEN bid) { GEN G = bid_get_grp(bid); if (lg(G) != 4) pari_err(e_MISC,"missing bid generators. Use idealstar(,,2)"); return abgrp_get_gen(G); } INLINE GEN znstar_get_N(GEN G) { return gmael(G,1,1); } INLINE GEN znstar_get_faN(GEN G) { return gel(G,3); } INLINE GEN znstar_get_no(GEN G) { return abgrp_get_no(gel(G,2)); } INLINE GEN znstar_get_cyc(GEN G) { return abgrp_get_cyc(gel(G,2)); } INLINE GEN znstar_get_gen(GEN G) { return abgrp_get_gen(gel(G,2)); } INLINE GEN znstar_get_conreycyc(GEN G) { return gmael(G,4,5); } INLINE GEN znstar_get_conreygen(GEN G) { return gmael(G,4,4); } INLINE GEN znstar_get_Ui(GEN G) { return gmael(G,4,3); } INLINE GEN znstar_get_U(GEN G) { return gel(G,5); } INLINE GEN znstar_get_pe(GEN G) { return gmael(G,4,1); } INLINE GEN gal_get_pol(GEN gal) { return gel(gal,1); } INLINE GEN gal_get_p(GEN gal) { return gmael(gal,2,1); } INLINE GEN gal_get_e(GEN gal) { return gmael(gal,2,2); } INLINE GEN gal_get_mod(GEN gal) { return gmael(gal,2,3); } INLINE GEN gal_get_roots(GEN gal) { return gel(gal,3); } INLINE GEN gal_get_invvdm(GEN gal) { return gel(gal,4); } INLINE GEN gal_get_den(GEN gal) { return gel(gal,5); } INLINE GEN gal_get_group(GEN gal) { return gel(gal,6); } INLINE GEN gal_get_gen(GEN gal) { return gel(gal,7); } INLINE GEN gal_get_orders(GEN gal) { return gel(gal,8); } /* assume rnf a genuine rnf */ INLINE long rnf_get_degree(GEN rnf) { return degpol(rnf_get_pol(rnf)); } INLINE long rnf_get_nfdegree(GEN rnf) { return degpol(nf_get_pol(rnf_get_nf(rnf))); } INLINE long rnf_get_absdegree(GEN rnf) { return degpol(gmael(rnf,11,1)); } INLINE GEN rnf_get_idealdisc(GEN rnf) { return gmael(rnf,3,1); } INLINE GEN rnf_get_k(GEN rnf) { return gmael(rnf,11,3); } INLINE GEN rnf_get_alpha(GEN rnf) { return gmael(rnf, 11, 2); } INLINE GEN rnf_get_nf(GEN rnf) { return gel(rnf,10); } INLINE GEN rnf_get_nfzk(GEN rnf) { return gel(rnf,2); } INLINE GEN rnf_get_polabs(GEN rnf) { return gmael(rnf,11,1); } INLINE GEN rnf_get_pol(GEN rnf) { return gel(rnf,1); } INLINE GEN rnf_get_disc(GEN rnf) { return gel(rnf,3); } INLINE GEN rnf_get_index(GEN rnf) { return gel(rnf,4); } INLINE long rnf_get_varn(GEN rnf) { return varn(gel(rnf,1)); } INLINE GEN rnf_get_nfpol(GEN rnf) { return gmael(rnf,10,1); } INLINE long rnf_get_nfvarn(GEN rnf) { return varn(gmael(rnf,10,1)); } INLINE GEN rnf_get_zk(GEN rnf) { return gel(rnf,7); } INLINE GEN rnf_get_map(GEN rnf) { return gel(rnf,11); } INLINE GEN rnf_get_invzk(GEN rnf) { return gel(rnf,8); } /* I integral ZM (not HNF), G ZM, rounded Cholesky form of a weighted * T2 matrix. Reduce I wrt G */ INLINE GEN idealpseudored(GEN I, GEN G) { return ZM_mul(I, ZM_lll(ZM_mul(G, I), 0.99, LLL_IM)); } /* I integral (not necessarily HNF), G ZM, rounded Cholesky form of a weighted * T2 matrix. Return m in I with T2(m) small */ INLINE GEN idealpseudomin(GEN I, GEN G) { GEN u = ZM_lll(ZM_mul(G, I), 0.99, LLL_IM); return ZM_ZC_mul(I, gel(u,1)); } /* I, G as in idealpseudomin. Return an irrational m in I with T2(m) small */ INLINE GEN idealpseudomin_nonscalar(GEN I, GEN G) { GEN u = ZM_lll(ZM_mul(G, I), 0.99, LLL_IM); GEN m = ZM_ZC_mul(I, gel(u,1)); if (ZV_isscalar(m) && lg(u) > 2) m = ZM_ZC_mul(I, gel(u,2)); return m; } INLINE GEN idealred_elt(GEN nf, GEN I) { pari_sp av = avma; GEN u = idealpseudomin(I, nf_get_roundG(nf)); return gerepileupto(av, u); } INLINE GEN idealred(GEN nf, GEN I) { return idealred0(nf, I, NULL); } INLINE GEN idealchineseinit(GEN nf, GEN x) { return idealchinese(nf,x,NULL); } /*******************************************************************/ /* */ /* CLOSURES */ /* */ /*******************************************************************/ INLINE long closure_arity(GEN C) { return ((ulong)C[1])&ARITYBITS; } INLINE long closure_is_variadic(GEN C) { return !!(((ulong)C[1])&VARARGBITS); } INLINE const char *closure_codestr(GEN C) { return GSTR(gel(C,2))-1; } INLINE GEN closure_get_code(GEN C) { return gel(C,2); } INLINE GEN closure_get_oper(GEN C) { return gel(C,3); } INLINE GEN closure_get_data(GEN C) { return gel(C,4); } INLINE GEN closure_get_dbg(GEN C) { return gel(C,5); } INLINE GEN closure_get_text(GEN C) { return gel(C,6); } INLINE GEN closure_get_frame(GEN C) { return gel(C,7); } /*******************************************************************/ /* */ /* ERRORS */ /* */ /*******************************************************************/ INLINE long err_get_num(GEN e) { return e[1]; } INLINE GEN err_get_compo(GEN e, long i) { return gel(e, i+1); } INLINE void pari_err_BUG(const char *f) { pari_err(e_BUG,f); } INLINE void pari_err_CONSTPOL(const char *f) { pari_err(e_CONSTPOL, f); } INLINE void pari_err_COPRIME(const char *f, GEN x, GEN y) { pari_err(e_COPRIME, f,x,y); } INLINE void pari_err_DIM(const char *f) { pari_err(e_DIM, f); } INLINE void pari_err_FILE(const char *f, const char *g) { pari_err(e_FILE, f,g); } INLINE void pari_err_FILEDESC(const char *f, long n) { pari_err(e_FILEDESC, f,n); } INLINE void pari_err_FLAG(const char *f) { pari_err(e_FLAG,f); } INLINE void pari_err_IMPL(const char *f) { pari_err(e_IMPL,f); } INLINE void pari_err_INV(const char *f, GEN x) { pari_err(e_INV,f,x); } INLINE void pari_err_IRREDPOL(const char *f, GEN x) { pari_err(e_IRREDPOL, f,x); } INLINE void pari_err_DOMAIN(const char *f, const char *v, const char *op, GEN l, GEN x) { pari_err(e_DOMAIN, f,v,op,l,x); } INLINE void pari_err_COMPONENT(const char *f, const char *op, GEN l, GEN x) { pari_err(e_COMPONENT, f,op,l,x); } INLINE void pari_err_MAXPRIME(ulong c) { pari_err(e_MAXPRIME, c); } INLINE void pari_err_OP(const char *f, GEN x, GEN y) { pari_err(e_OP, f,x,y); } INLINE void pari_err_OVERFLOW(const char *f) { pari_err(e_OVERFLOW, f); } INLINE void pari_err_PREC(const char *f) { pari_err(e_PREC,f); } INLINE void pari_err_PACKAGE(const char *f) { pari_err(e_PACKAGE,f); } INLINE void pari_err_PRIME(const char *f, GEN x) { pari_err(e_PRIME, f,x); } INLINE void pari_err_MODULUS(const char *f, GEN x, GEN y) { pari_err(e_MODULUS, f,x,y); } INLINE void pari_err_ROOTS0(const char *f) { pari_err(e_ROOTS0, f); } INLINE void pari_err_SQRTN(const char *f, GEN x) { pari_err(e_SQRTN, f,x); } INLINE void pari_err_TYPE(const char *f, GEN x) { pari_err(e_TYPE, f,x); } INLINE void pari_err_TYPE2(const char *f, GEN x, GEN y) { pari_err(e_TYPE2, f,x,y); } INLINE void pari_err_VAR(const char *f, GEN x, GEN y) { pari_err(e_VAR, f,x,y); } INLINE void pari_err_PRIORITY(const char *f, GEN x, const char *op, long v) { pari_err(e_PRIORITY, f,x,op,v); } pari-2.11.2/src/headers/parigen.h0000644000175000017500000001351713201017466015165 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file defines the parameters of the GEN type */ #ifdef _WIN64 typedef unsigned long long pari_ulong; #define long long long #define labs llabs #else typedef unsigned long pari_ulong; #endif #define ulong pari_ulong typedef long *GEN; #undef ULONG_MAX #undef LONG_MAX #ifdef LONG_IS_64BIT # define BITS_IN_LONG 64 # define TWOPOTBITS_IN_LONG 6 # define LONG_MAX (9223372036854775807L) /* 2^63-1 */ # define SMALL_ULONG(p) ((ulong)p <= 3037000493UL) #else # define BITS_IN_LONG 32 # define TWOPOTBITS_IN_LONG 5 # define LONG_MAX (2147483647L) /* 2^31-1 */ # define SMALL_ULONG(p) ((ulong)p <= 46337UL) /* 2p^2 < 2^BITS_IN_LONG */ #endif #define ULONG_MAX (~0x0UL) #define DEFAULTPREC (2 + (long)(8/sizeof(long))) #define MEDDEFAULTPREC (2 + (long)(16/sizeof(long))) #define BIGDEFAULTPREC (2 + (long)(24/sizeof(long))) #define LOWDEFAULTPREC 3 #define EXTRAPRECWORD 1 #define HIGHBIT (1UL << (BITS_IN_LONG-1)) #define BITS_IN_HALFULONG (BITS_IN_LONG>>1) #define LOWMASK ((1UL<> BITS_IN_HALFULONG) #define LOWWORD(a) ((a) & LOWMASK) /* Order of bits in codewords: * x[0] TYPBITS, CLONEBIT, LGBITS * x[1].real SIGNBITS, EXPOBITS * int SIGNBITS, LGBITS * pol SIGNBITS, VARNBITS * ser SIGNBITS, VARNBITS, VALPBITS * padic VALPBITS, PRECPBITS */ #define TYPnumBITS 7 #define SIGNnumBITS 2 #ifdef LONG_IS_64BIT # define VARNnumBITS 16 /* otherwise MAXVARN too large */ #else # define VARNnumBITS 14 #endif /* no user serviceable parts below :-) */ #define LGnumBITS (BITS_IN_LONG - 1 - TYPnumBITS) #define VALPnumBITS (BITS_IN_LONG - SIGNnumBITS - VARNnumBITS) #define EXPOnumBITS (BITS_IN_LONG - SIGNnumBITS) #define PRECPSHIFT VALPnumBITS #define VARNSHIFT VALPnumBITS #define TYPSHIFT (BITS_IN_LONG - TYPnumBITS) #define SIGNSHIFT (BITS_IN_LONG - SIGNnumBITS) #define EXPOBITS ((1UL<> TYPSHIFT)) #define settyp(x,s) (((ulong*)(x))[0]=\ (((ulong*)(x))[0]&(~TYPBITS)) | evaltyp(s)) #define isclone(x) (((ulong*) (x))[0] & CLONEBIT) #define setisclone(x) (((ulong*) (x))[0] |= CLONEBIT) #define unsetisclone(x) (((ulong*) (x))[0] &= (~CLONEBIT)) #define lg(x) ((long)(((ulong)((x)[0])) & LGBITS)) #define setlg(x,s) (((ulong*)(x))[0]=\ (((ulong*)(x))[0]&(~LGBITS)) | evallg(s)) #define signe(x) (((long)((x)[1])) >> SIGNSHIFT) #define setsigne(x,s) (((ulong*)(x))[1]=\ (((ulong*)(x))[1]&(~SIGNBITS)) | (ulong)evalsigne(s)) #define lgefint(x) ((long)(((ulong)((x)[1])) & LGBITS)) #define setlgefint(x,s) (((ulong*)(x))[1]=\ (((ulong*)(x))[1]&(~LGBITS)) | (ulong)evallgefint(s)) #define realprec(x) ((long)(((ulong)((x)[0])) & LGBITS)) #define setprec(x,s) (((ulong*)(x))[0]=\ (((ulong*)(x))[0]&(~LGBITS)) | evallg(s)) #define incrprec(x) ((x)++) #define expo(x) ((long) ((((ulong)((x)[1])) & EXPOBITS) - HIGHEXPOBIT)) #define setexpo(x,s) (((ulong*)(x))[1]=\ (((ulong*)(x))[1]&(~EXPOBITS)) | (ulong)evalexpo(s)) #define valp(x) ((long) ((((ulong)((x)[1])) & VALPBITS) - HIGHVALPBIT)) #define setvalp(x,s) (((ulong*)(x))[1]=\ (((ulong*)(x))[1]&(~VALPBITS)) | (ulong)evalvalp(s)) #define precp(x) ((long) (((ulong)((x)[1])) >> PRECPSHIFT)) #define setprecp(x,s) (((ulong*)(x))[1]=\ (((ulong*)(x))[1]&(~PRECPBITS)) | (ulong)evalprecp(s)) #define varn(x) ((long)((((ulong)((x)[1]))&VARNBITS) >> VARNSHIFT)) #define setvarn(x,s) (((ulong*)(x))[1]=\ (((ulong*)(x))[1]&(~VARNBITS)) | (ulong)evalvarn(s)) /* t_LIST */ #define list_typ(x) ((long)(((ulong)((x)[1])) >> TYPSHIFT)) #define list_nmax(x) ((long)(((ulong)((x)[1])) & LGBITS)) #define list_data(x) ((GEN*)x)[2] enum { t_LIST_RAW = 0, t_LIST_MAP = 1 }; /* DO NOT REORDER THESE * actual values can be changed. Adapt lontyp in gen2.c */ enum { t_INT = 1, t_REAL = 2, t_INTMOD = 3, t_FRAC = 4, t_FFELT = 5, t_COMPLEX= 6, t_PADIC = 7, t_QUAD = 8, t_POLMOD = 9, t_POL = 10, t_SER = 11, t_RFRAC = 13, t_QFR = 15, t_QFI = 16, t_VEC = 17, t_COL = 18, t_MAT = 19, t_LIST = 20, t_STR = 21, t_VECSMALL= 22, t_CLOSURE = 23, t_ERROR = 24, t_INFINITY= 25 }; pari-2.11.2/src/headers/parierr.h0000644000175000017500000000210313326135265015177 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ enum err_list { /* Force errors into non-0 */ e_SYNTAX = 1, e_BUG, e_ALARM, e_FILE, e_MISC, e_FLAG, e_IMPL, e_ARCH, e_PACKAGE, e_NOTFUNC, e_PREC, e_TYPE, e_DIM, e_VAR, e_PRIORITY, e_USER, e_STACK, e_STACKTHREAD, e_OVERFLOW, e_DOMAIN, e_COMPONENT, e_MAXPRIME, e_CONSTPOL, e_IRREDPOL, e_COPRIME, e_PRIME, e_MODULUS, e_ROOTS0, e_OP, e_TYPE2, e_INV, e_MEM, e_SQRTN, e_FILEDESC, /* NO ERROR */ e_NONE }; enum { warner, warnprec, warnfile, warnmem, warnuser, warnstack, warnstackthread }; pari-2.11.2/src/headers/paricom.h0000644000175000017500000001140513326135265015172 0ustar billbill/* Copyright (C) 2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /******************************************************************/ /* */ /* PARI header file (common to all versions) */ /* */ /******************************************************************/ #ifdef STMT_START /* perl headers */ # undef STMT_START #endif #ifdef STMT_END # undef STMT_END #endif /* STMT_START { statements; } STMT_END; * can be used as a single statement, as in * if (x) STMT_START { ... } STMT_END; else ... * [ avoid "dangling else" problem in macros ] */ #define STMT_START do #define STMT_END while (0) /*=====================================================================*/ /* pari_CATCH(numer) { * recovery * } pari_TRY { * code * } pari_ENDCATCH * will execute 'code', then 'recovery' if exception 'numer' is thrown * [ any exception if numer == CATCH_ALL ]. * pari_RETRY = as pari_TRY, but execute 'recovery', then 'code' again [still catching] */ extern THREAD jmp_buf *iferr_env; extern const long CATCH_ALL; #define pari_CATCH2(var,err) { \ jmp_buf *var=iferr_env; \ jmp_buf __env; \ iferr_env = &__env; \ if (setjmp(*iferr_env)) \ { \ GEN __iferr_data = pari_err_last(); \ iferr_env = var; \ if (err!=CATCH_ALL && err_get_num(__iferr_data) != err) \ pari_err(0, __iferr_data); #define pari_CATCH2_reset(var) (iferr_env = var) #define pari_ENDCATCH2(var) iferr_env = var; } } #define pari_CATCH(err) pari_CATCH2(__iferr_old,err) #define pari_RETRY } iferr_env = &__env; { #define pari_TRY } else { #define pari_CATCH_reset() pari_CATCH2_reset(__iferr_old) #define pari_ENDCATCH pari_ENDCATCH2(__iferr_old) #define pari_APPLY_same(EXPR)\ { \ long i, _l; \ GEN _y = cgetg_copy(x, &_l);\ for (i=1; i<_l; i++) gel(_y,i) = EXPR;\ return _y;\ } #define pari_APPLY_type(TYPE, EXPR)\ { \ long i, _l = lg(x); \ GEN _y = cgetg(_l, TYPE);\ for (i=1; i<_l; i++) gel(_y,i) = EXPR;\ return _y;\ } #define pari_APPLY_long(EXPR)\ { \ long i, _l = lg(x); \ GEN _y = cgetg(_l, t_VECSMALL);\ for (i=1; i<_l; i++) _y[i] = EXPR;\ return _y;\ } #define pari_APPLY_ulong(EXPR)\ { \ long i, _l = lg(x); \ GEN _y = cgetg(_l, t_VECSMALL);\ for (i=1; i<_l; i++) ((ulong*)_y)[i] = EXPR;\ return _y;\ } extern const double LOG10_2, LOG2_10; #ifndef M_PI # define M_PI 3.14159265358979323846264338327950288 #endif #ifndef M_LN2 # define M_LN2 0.693147180559945309417232121458176568 #endif /* Common global variables: */ extern int new_galois_format, factor_add_primes, factor_proven; extern ulong DEBUGFILES, DEBUGLEVEL, DEBUGMEM, precdl; extern long DEBUGVAR; extern ulong pari_mt_nbthreads; extern THREAD GEN bernzone, primetab; extern GEN gen_m1,gen_1,gen_2,gen_m2,ghalf,gen_0,gnil,err_e_STACK; extern THREAD VOLATILE int PARI_SIGINT_block, PARI_SIGINT_pending; extern const long lontyp[]; extern void (*cb_pari_ask_confirm)(const char *); extern void (*cb_pari_init_histfile)(void); extern int (*cb_pari_whatnow)(PariOUT *out, const char *, int); extern void (*cb_pari_quit)(long); extern void (*cb_pari_sigint)(void); extern int (*cb_pari_handle_exception)(long); extern int (*cb_pari_err_handle)(GEN); extern void (*cb_pari_pre_recover)(long); extern void (*cb_pari_err_recover)(long); extern int (*cb_pari_break_loop)(int); extern int (*cb_pari_is_interactive)(void); extern void (*cb_pari_start_output)(void); extern const char *pari_library_path; extern THREAD long *varpriority; /* pari_init_opts */ enum { INIT_JMPm = 1, INIT_SIGm = 2, INIT_DFTm = 4, INIT_noPRIMEm = 8, INIT_noIMTm = 16, INIT_noINTGMPm = 32 }; #ifndef HAS_EXP2 # undef exp2 # define exp2(x) (exp((double)(x)*M_LN2)) #endif #ifndef HAS_LOG2 # undef log2 # define log2(x) (log((double)(x))/M_LN2) #endif #define ONLY_REM ((GEN*)0x1L) #define ONLY_DIVIDES ((GEN*)0x2L) #define NEXT_PRIME_VIADIFF(p,d) STMT_START { (p) += *(d)++; } STMT_END #define PREC_PRIME_VIADIFF(p,d) STMT_START { (p) -= *--(d); } STMT_END #define NEXT_PRIME_VIADIFF_CHECK(p,d) STMT_START \ { if (!*(d)) pari_err_MAXPRIME(0); NEXT_PRIME_VIADIFF(p,d); } STMT_END pari-2.11.2/src/headers/parisys.h0000644000175000017500000000334313201017466015226 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This files contains macros depending on system and compiler */ #ifdef __cplusplus # define ANYARG ... # define BEGINEXTERN extern "C" { # define ENDEXTERN } #else # define ANYARG # define BEGINEXTERN # define ENDEXTERN #endif #ifdef DISABLE_INLINE # undef ASMINLINE #else # ifdef __cplusplus # define INLINE inline static # elif defined(__GNUC__) # define INLINE __inline__ static # endif #endif #ifndef DISABLE_VOLATILE # ifdef __GNUC__ # define VOLATILE volatile # endif #endif #ifndef VOLATILE # define VOLATILE #endif #ifndef INLINE # define INLINE static #endif #ifdef ENABLE_TLS # define THREAD __thread #else # define THREAD #endif #if defined(_WIN32) || defined(__CYGWIN32__) /* ANSI C does not allow to longjmp() out of a signal handler, in particular, * the SIGINT handler. On Win32, the handler is executed in another thread, and * longjmp'ing into another thread's stack will utterly confuse the system. * Instead, we check whether win32ctrlc is set in new_chunk(). */ BEGINEXTERN extern int win32ctrlc, win32alrm; void dowin32ctrlc(void); ENDEXTERN #define CHECK_CTRLC if (win32ctrlc) dowin32ctrlc(); #else #define CHECK_CTRLC #endif pari-2.11.2/src/headers/pari.h0000644000175000017500000000253013201017466014464 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GENPARI__ #define __GENPARI__ #include "paricfg.h" #include /* malloc, free, atoi */ #ifdef UNIX # define _INCLUDE_POSIX_SOURCE /* for HPUX */ # include /* size_t */ #endif #include #include #include #include #include #if !defined(_WIN32) # include #else # include #endif #include #include #include #include "parisys.h" #include "parigen.h" #include "paricast.h" #include "paristio.h" #include "paricom.h" #include "parierr.h" BEGINEXTERN #include "paridecl.h" #include "paritune.h" #include "parimt.h" #ifndef PARI_NO_MPINL_H # include "mpinl.h" #endif #ifndef PARI_NO_PARIINL_H # include "pariinl.h" #endif ENDEXTERN #include "pariold.h" #endif pari-2.11.2/src/headers/paridecl.h0000644000175000017500000066526013457423612015342 0ustar billbill/* Copyright (C) 1999-2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* DECLARATIONS of PUBLIC FUNCTIONS */ /* */ /*******************************************************************/ #include "parinf.h" /* black box groups */ struct bb_group { GEN (*mul)(void *E, GEN, GEN); GEN (*pow)(void *E, GEN, GEN); GEN (*rand)(void *E); ulong (*hash)(GEN); int (*equal)(GEN,GEN); int (*equal1)(GEN); GEN (*easylog)(void *E, GEN, GEN, GEN); }; /* black box fields */ struct bb_field { GEN (*red)(void *E ,GEN); GEN (*add)(void *E ,GEN, GEN); GEN (*mul)(void *E ,GEN, GEN); GEN (*neg)(void *E ,GEN); GEN (*inv)(void *E ,GEN); int (*equal0)(GEN); GEN (*s)(void *E, long); }; /* black box algebra */ struct bb_algebra { GEN (*red)(void *E, GEN x); GEN (*add)(void *E, GEN x, GEN y); GEN (*sub)(void *E, GEN x, GEN y); GEN (*mul)(void *E, GEN x, GEN y); GEN (*sqr)(void *E, GEN x); GEN (*one)(void *E); GEN (*zero)(void *E); }; /* black box ring */ struct bb_ring { GEN (*add)(void *E, GEN x, GEN y); GEN (*mul)(void *E, GEN x, GEN y); GEN (*sqr)(void *E, GEN x); }; /* OBSOLETE */ GEN bernvec(long nomb); GEN buchimag(GEN D, GEN c1, GEN c2, GEN gCO); GEN buchreal(GEN D, GEN gsens, GEN c1, GEN c2, GEN gRELSUP, long prec); GEN zidealstar(GEN nf, GEN x); GEN zidealstarinit(GEN nf, GEN x); GEN zidealstarinitgen(GEN nf, GEN x); GEN factmod(GEN f, GEN p); GEN simplefactmod(GEN f, GEN p); void listkill(GEN list); GEN isprincipalforce(GEN bnf,GEN x); GEN isprincipalgen(GEN bnf, GEN x); GEN isprincipalgenforce(GEN bnf,GEN x); /* F2x.c */ GEN F2c_to_ZC(GEN x); GEN F2c_to_mod(GEN x); GEN F2m_rowslice(GEN x, long a, long b); GEN F2m_to_Flm(GEN z); GEN F2m_to_ZM(GEN z); GEN F2m_to_mod(GEN z); void F2v_add_inplace(GEN x, GEN y); ulong F2v_dotproduct(GEN x, GEN y); GEN F2v_slice(GEN x, long a, long b); GEN F2v_to_Flv(GEN x); GEN F2x_F2xq_eval(GEN Q, GEN x, GEN T); GEN F2x_F2xqV_eval(GEN P, GEN V, GEN T); GEN F2x_Frobenius(GEN T); GEN F2x_1_add(GEN y); GEN F2x_add(GEN x, GEN y); GEN F2x_deflate(GEN x0, long d); GEN F2x_degfact(GEN f); long F2x_degree(GEN x); GEN F2x_deriv(GEN x); GEN F2x_divrem(GEN x, GEN y, GEN *pr); ulong F2x_eval(GEN P, ulong x); void F2x_even_odd(GEN p, GEN *pe, GEN *po); GEN F2x_extgcd(GEN a, GEN b, GEN *ptu, GEN *ptv); GEN F2x_gcd(GEN a, GEN b); GEN F2x_get_red(GEN T); GEN F2x_halfgcd(GEN a, GEN b); int F2x_issquare(GEN a); GEN F2x_matFrobenius(GEN T); GEN F2x_mul(GEN x, GEN y); GEN F2x_rem(GEN x, GEN y); GEN F2x_shift(GEN y, long d); GEN F2x_sqr(GEN x); GEN F2x_sqrt(GEN x); GEN F2x_to_F2v(GEN x, long n); GEN F2x_to_F2xX(GEN z, long sv); GEN F2x_to_Flx(GEN x); GEN F2x_to_ZX(GEN x); long F2x_valrem(GEN x, GEN *Z); GEN F2xC_to_FlxC(GEN v); GEN F2xC_to_ZXC(GEN x); GEN F2xV_to_F2m(GEN v, long n); GEN F2xX_F2x_add(GEN x, GEN y); GEN F2xX_F2x_mul(GEN P, GEN U); GEN F2xX_add(GEN x, GEN y); GEN F2xX_deriv(GEN z); GEN F2xX_renormalize(GEN /*in place*/ x, long lx); GEN F2xX_to_Kronecker(GEN P, long d); GEN F2xX_to_ZXX(GEN B); GEN F2xXC_to_ZXXC(GEN B); GEN F2xY_F2xq_evalx(GEN P, GEN x, GEN T); GEN F2xY_F2xqV_evalx(GEN P, GEN x, GEN T); long F2xY_degreex(GEN b); GEN F2xq_Artin_Schreier(GEN a, GEN T); GEN F2xq_autpow(GEN x, long n, GEN T); GEN F2xq_conjvec(GEN x, GEN T); GEN F2xq_div(GEN x,GEN y,GEN T); GEN F2xq_inv(GEN x, GEN T); GEN F2xq_invsafe(GEN x, GEN T); GEN F2xq_log(GEN a, GEN g, GEN ord, GEN T); GEN F2xq_matrix_pow(GEN y, long n, long m, GEN P); GEN F2xq_mul(GEN x, GEN y, GEN pol); GEN F2xq_order(GEN a, GEN ord, GEN T); GEN F2xq_pow(GEN x, GEN n, GEN pol); GEN F2xq_pow_init(GEN x, GEN n, long k, GEN T); GEN F2xq_pow_table(GEN R, GEN n, GEN T); GEN F2xq_powu(GEN x, ulong n, GEN pol); GEN F2xq_powers(GEN x, long l, GEN T); GEN F2xq_sqr(GEN x,GEN pol); GEN F2xq_sqrt(GEN a, GEN T); GEN F2xq_sqrt_fast(GEN c, GEN sqx, GEN T); GEN F2xq_sqrtn(GEN a, GEN n, GEN T, GEN *zeta); ulong F2xq_trace(GEN x, GEN T); GEN F2xqX_F2xq_mul(GEN P, GEN U, GEN T); GEN F2xqX_F2xq_mul_to_monic(GEN P, GEN U, GEN T); GEN F2xqX_F2xqXQ_eval(GEN Q, GEN x, GEN S, GEN T); GEN F2xqX_F2xqXQV_eval(GEN P, GEN V, GEN S, GEN T); GEN F2xqX_divrem(GEN x, GEN y, GEN T, GEN *pr); GEN F2xqX_gcd(GEN a, GEN b, GEN T); GEN F2xqX_extgcd(GEN a, GEN b, GEN T, GEN *ptu, GEN *ptv); GEN F2xqX_get_red(GEN S, GEN T); GEN F2xqX_invBarrett(GEN T, GEN Q); long F2xqX_ispower(GEN f, long k, GEN T, GEN *pt_r); GEN F2xqX_mul(GEN x, GEN y, GEN T); GEN F2xqX_normalize(GEN z, GEN T); GEN F2xqX_powu(GEN x, ulong n, GEN T); GEN F2xqX_red(GEN z, GEN T); GEN F2xqX_rem(GEN x, GEN S, GEN T); GEN F2xqX_sqr(GEN x, GEN T); GEN F2xqXQ_inv(GEN x, GEN S, GEN T); GEN F2xqXQ_invsafe(GEN x, GEN S, GEN T); GEN F2xqXQ_mul(GEN x, GEN y, GEN S, GEN T); GEN F2xqXQ_sqr(GEN x, GEN S, GEN T); GEN F2xqXQ_pow(GEN x, GEN n, GEN S, GEN T); GEN F2xqXQ_powers(GEN x, long l, GEN S, GEN T); GEN F2xqXQ_autpow(GEN aut, long n, GEN S, GEN T); GEN F2xqXQ_auttrace(GEN aut, long n, GEN S, GEN T); GEN F2xqXQV_red(GEN z, GEN S, GEN T); GEN Flm_to_F2m(GEN x); GEN Flv_to_F2v(GEN x); GEN Flx_to_F2x(GEN x); GEN FlxC_to_F2xC(GEN x); GEN FlxX_to_F2xX(GEN B); GEN FlxXC_to_F2xXC(GEN B); GEN Kronecker_to_F2xqX(GEN z, GEN T); GEN Rg_to_F2xq(GEN x, GEN T); GEN RgM_to_F2m(GEN x); GEN RgV_to_F2v(GEN x); GEN RgX_to_F2x(GEN x); GEN Z_to_F2x(GEN x, long v); GEN ZM_to_F2m(GEN x); GEN ZV_to_F2v(GEN x); GEN ZX_to_F2x(GEN x); GEN ZXX_to_F2xX(GEN B, long v); GEN const_F2v(long m); GEN gener_F2xq(GEN T, GEN *po); const struct bb_field *get_F2xq_field(void **E, GEN T); GEN monomial_F2x(long d, long vs); GEN pol1_F2xX(long v, long sv); GEN polx_F2xX(long v, long sv); GEN random_F2x(long d, long vs); GEN random_F2xqX(long d1, long v, GEN T); /* F2xqE.c */ GEN F2xq_ellcard(GEN a2, GEN a6, GEN T); GEN F2xq_ellgens(GEN a2, GEN a6, GEN ch, GEN D, GEN m, GEN T); GEN F2xq_ellgroup(GEN a2, GEN a6, GEN N, GEN T, GEN *pt_m); void F2xq_elltwist(GEN a, GEN a6, GEN T, GEN *pt_a, GEN *pt_a6); GEN F2xqE_add(GEN P, GEN Q, GEN a2, GEN T); GEN F2xqE_changepoint(GEN x, GEN ch, GEN T); GEN F2xqE_changepointinv(GEN x, GEN ch, GEN T); GEN F2xqE_dbl(GEN P, GEN a2, GEN T); GEN F2xqE_log(GEN a, GEN b, GEN o, GEN a2, GEN T); GEN F2xqE_mul(GEN P, GEN n, GEN a2, GEN T); GEN F2xqE_neg(GEN P, GEN a2, GEN T); GEN F2xqE_order(GEN z, GEN o, GEN a2, GEN T); GEN F2xqE_sub(GEN P, GEN Q, GEN a2, GEN T); GEN F2xqE_tatepairing(GEN t, GEN s, GEN m, GEN a2, GEN T); GEN F2xqE_weilpairing(GEN t, GEN s, GEN m, GEN a2, GEN T); const struct bb_group * get_F2xqE_group(void **E, GEN a2, GEN a6, GEN T); GEN RgE_to_F2xqE(GEN x, GEN T); GEN random_F2xqE(GEN a2, GEN a6, GEN T); /* Fle.c */ ulong Fl_elldisc(ulong a4, ulong a6, ulong p); ulong Fl_elldisc_pre(ulong a4, ulong a6, ulong p, ulong pi); ulong Fl_ellj(ulong a4, ulong a6, ulong p); void Fl_ellj_to_a4a6(ulong j, ulong p, ulong *pt_a4, ulong *pt_a6); void Fl_elltwist(ulong a4, ulong a6, ulong p, ulong *pt_a4, ulong *pt_a6); void Fl_elltwist_disc(ulong a4, ulong a6, ulong D, ulong p, ulong *pt_a4, ulong *pt_a6); GEN Fle_add(GEN P, GEN Q, ulong a4, ulong p); GEN Fle_dbl(GEN P, ulong a4, ulong p); GEN Fle_changepoint(GEN x, GEN ch, ulong p); GEN Fle_changepointinv(GEN x, GEN ch, ulong p); GEN Fle_log(GEN a, GEN b, GEN o, ulong a4, ulong p); GEN Fle_mul(GEN P, GEN n, ulong a4, ulong p); GEN Fle_mulu(GEN P, ulong n, ulong a4, ulong p); GEN Fle_order(GEN z, GEN o, ulong a4, ulong p); GEN Fle_sub(GEN P, GEN Q, ulong a4, ulong p); GEN Fle_to_Flj(GEN P); GEN Flj_add_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi); GEN Flj_dbl_pre(GEN P, ulong a4, ulong p, ulong pi); GEN Flj_mulu_pre(GEN P, ulong n, ulong a4, ulong p, ulong pi); GEN Flj_neg(GEN Q, ulong p); GEN Flj_to_Fle_pre(GEN P, ulong p, ulong pi); GEN random_Fle(ulong a4, ulong a6, ulong p); GEN random_Fle_pre(ulong a4, ulong a6, ulong p, ulong pi); GEN random_Flj_pre(ulong a4, ulong a6, ulong p, ulong pi); /* Flx.c */ GEN Fl_to_Flx(ulong x, long sv); int Fl2_equal1(GEN x); GEN Fl2_inv_pre(GEN x, ulong D, ulong p, ulong pi); GEN Fl2_mul_pre(GEN x, GEN y, ulong D, ulong p, ulong pi); ulong Fl2_norm_pre(GEN x, ulong D, ulong p, ulong pi); GEN Fl2_pow_pre(GEN x, GEN n, ulong D, ulong p, ulong pi); GEN Fl2_sqr_pre(GEN x, ulong D, ulong p, ulong pi); GEN Fl2_sqrtn_pre(GEN a, GEN n, ulong D, ulong p, ulong pi, GEN *zeta); GEN Flc_to_ZC(GEN z); GEN Flc_to_ZC_inplace(GEN z); GEN Flm_to_FlxV(GEN x, long sv); GEN Flm_to_FlxX(GEN x, long v,long w); GEN Flm_to_ZM(GEN z); GEN Flm_to_ZM_inplace(GEN z); GEN Flv_Flm_polint(GEN xa, GEN ya, ulong p, long vs); GEN Flv_inv(GEN x, ulong p); void Flv_inv_inplace(GEN x, ulong p); void Flv_inv_pre_inplace(GEN x, ulong p, ulong pi); GEN Flv_inv_pre(GEN x, ulong p, ulong pi); GEN Flv_invVandermonde(GEN L, ulong den, ulong p); GEN Flv_polint(GEN xa, GEN ya, ulong p, long vs); ulong Flv_prod(GEN v, ulong p); ulong Flv_prod_pre(GEN x, ulong p, ulong pi); GEN Flv_roots_to_pol(GEN a, ulong p, long vs); GEN Flv_to_Flx(GEN x, long vs); GEN Fly_to_FlxY(GEN B, long v); GEN Flv_to_ZV(GEN z); GEN Flx_Fl_add(GEN y, ulong x, ulong p); GEN Flx_Fl_mul(GEN y, ulong x, ulong p); GEN Flx_Fl_mul_to_monic(GEN y, ulong x, ulong p); GEN Flx_Fl2_eval_pre(GEN x, GEN y, ulong D, ulong p, ulong pi); GEN Flx_Flv_multieval(GEN P, GEN v, ulong p); GEN Flx_Flxq_eval(GEN f,GEN x,GEN T,ulong p); GEN Flx_FlxqV_eval(GEN f,GEN x,GEN T,ulong p); GEN Flx_Frobenius(GEN T, ulong p); GEN Flx_add(GEN x, GEN y, ulong p); GEN Flx_deflate(GEN x0, long d); GEN Flx_deriv(GEN z, ulong p); GEN Flx_diff1(GEN P, ulong p); GEN Flx_digits(GEN x, GEN T, ulong p); GEN Flx_div_by_X_x(GEN a, ulong x, ulong p, ulong *rem); GEN Flx_divrem(GEN x, GEN y, ulong p, GEN *pr); GEN Flx_double(GEN y, ulong p); int Flx_equal(GEN V, GEN W); ulong Flx_eval(GEN x, ulong y, ulong p); ulong Flx_eval_powers_pre(GEN x, GEN y, ulong p, ulong pi); ulong Flx_eval_pre(GEN x, ulong y, ulong p, ulong pi); GEN Flx_extgcd(GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv); ulong Flx_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV); GEN Flx_gcd(GEN a, GEN b, ulong p); GEN Flx_get_red(GEN T, ulong p); GEN Flx_halfgcd(GEN a, GEN b, ulong p); GEN Flx_halve(GEN y, ulong p); GEN Flx_inflate(GEN x0, long d); GEN Flx_invBarrett(GEN T, ulong p); int Flx_is_squarefree(GEN z, ulong p); int Flx_is_smooth(GEN g, long r, ulong p); GEN Flx_matFrobenius(GEN T, ulong p); GEN Flx_mod_Xn1(GEN T, ulong n, ulong p); GEN Flx_mod_Xnm1(GEN T, ulong n, ulong p); GEN Flx_mul(GEN x, GEN y, ulong p); GEN Flx_neg(GEN x, ulong p); GEN Flx_neg_inplace(GEN x, ulong p); GEN Flx_normalize(GEN z, ulong p); GEN Flx_powu(GEN x, ulong n, ulong p); GEN Flx_recip(GEN x); GEN Flx_red(GEN z, ulong p); GEN Flx_rem(GEN x, GEN y, ulong p); GEN Flx_renormalize(GEN x, long l); GEN Flx_rescale(GEN P, ulong h, ulong p); ulong Flx_resultant(GEN a, GEN b, ulong p); GEN Flx_shift(GEN a, long n); GEN Flx_splitting(GEN p, long k); GEN Flx_sqr(GEN x, ulong p); GEN Flx_sub(GEN x, GEN y, ulong p); GEN Flx_translate1(GEN P, ulong p); GEN Flx_to_Flv(GEN x, long N); GEN Flx_to_FlxX(GEN z, long v); GEN Flx_to_ZX(GEN z); GEN Flx_to_ZX_inplace(GEN z); GEN Flx_triple(GEN y, ulong p); long Flx_val(GEN x); long Flx_valrem(GEN x, GEN *Z); GEN FlxC_eval_powers_pre(GEN z, GEN x, ulong p, ulong pi); GEN FlxC_neg(GEN x, ulong p); GEN FlxC_sub(GEN x, GEN y, ulong p); GEN FlxC_to_ZXC(GEN x); GEN FlxM_Flx_add_shallow(GEN x, GEN y, ulong p); GEN FlxM_eval_powers_pre(GEN z, GEN x, ulong p, ulong pi); GEN FlxM_neg(GEN x, ulong p); GEN FlxM_sub(GEN x, GEN y, ulong p); GEN FlxM_to_ZXM(GEN z); GEN FlxT_red(GEN z, ulong p); GEN FlxV_Flc_mul(GEN V, GEN W, ulong p); GEN FlxV_Flx_fromdigits(GEN x, GEN T, ulong p); GEN FlxV_prod(GEN V, ulong p); GEN FlxV_red(GEN z, ulong p); GEN FlxV_to_Flm(GEN v, long n); GEN FlxV_to_ZXV(GEN x); GEN FlxX_Fl_mul(GEN x, ulong y, ulong p); GEN FlxX_Flx_add(GEN y, GEN x, ulong p); GEN FlxX_Flx_mul(GEN x, GEN y, ulong p); GEN FlxX_Flx_sub(GEN y, GEN x, ulong p); GEN FlxX_add(GEN P, GEN Q, ulong p); GEN FlxX_deriv(GEN z, ulong p); GEN FlxX_double(GEN x, ulong p); GEN FlxX_neg(GEN x, ulong p); GEN FlxX_sub(GEN P, GEN Q, ulong p); GEN FlxX_swap(GEN x, long n, long ws); GEN FlxX_renormalize(GEN x, long lx); GEN FlxX_shift(GEN a, long n, long vs); GEN FlxX_to_Flm(GEN v, long n); GEN FlxX_to_Flx(GEN f); GEN FlxX_to_FlxC(GEN x, long N, long sv); GEN FlxX_to_ZXX(GEN B); GEN FlxX_triple(GEN x, ulong p); GEN FlxXC_to_ZXXC(GEN B); GEN FlxXM_to_ZXXM(GEN B); GEN FlxXV_to_FlxM(GEN v, long n, long sv); GEN FlxY_Flx_div(GEN x, GEN y, ulong p); GEN FlxY_Flx_translate(GEN P, GEN c, ulong p); GEN FlxY_Flxq_evalx(GEN P, GEN x, GEN T, ulong p); GEN FlxY_FlxqV_evalx(GEN P, GEN x, GEN T, ulong p); long FlxY_degreex(GEN b); ulong FlxY_eval_powers_pre(GEN pol, GEN ypowers, GEN xpowers, ulong p, ulong pi); GEN FlxY_evalx(GEN Q, ulong x, ulong p); GEN FlxY_evalx_powers_pre(GEN pol, GEN ypowers, ulong p, ulong pi); GEN FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p); GEN Flxn_inv(GEN f, long e, ulong p); GEN Flxn_mul(GEN a, GEN b, long n, ulong p); GEN Flxq_autpow(GEN x, ulong n, GEN T, ulong p); GEN Flxq_autsum(GEN x, ulong n, GEN T, ulong p); GEN Flxq_auttrace(GEN x, ulong n, GEN T, ulong p); GEN Flxq_charpoly(GEN x, GEN T, ulong p); GEN Flxq_conjvec(GEN x, GEN T, ulong p); GEN Flxq_div(GEN x, GEN y, GEN T, ulong p); GEN Flxq_inv(GEN x,GEN T,ulong p); GEN Flxq_invsafe(GEN x, GEN T, ulong p); int Flxq_issquare(GEN x, GEN T, ulong p); int Flxq_is2npower(GEN x, long n, GEN T, ulong p); GEN Flxq_log(GEN a, GEN g, GEN ord, GEN T, ulong p); GEN Flxq_lroot(GEN a, GEN T, long p); GEN Flxq_lroot_fast(GEN a, GEN sqx, GEN T, long p); GEN Flxq_matrix_pow(GEN y, long n, long m, GEN P, ulong l); GEN Flxq_minpoly(GEN x, GEN T, ulong p); GEN Flxq_mul(GEN x, GEN y, GEN T, ulong p); ulong Flxq_norm(GEN x, GEN T, ulong p); GEN Flxq_order(GEN a, GEN ord, GEN T, ulong p); GEN Flxq_pow(GEN x, GEN n, GEN T, ulong p); GEN Flxq_pow_init(GEN x, GEN n, long k, GEN T, ulong p); GEN Flxq_pow_table(GEN R, GEN n, GEN T, ulong p); GEN Flxq_powu(GEN x, ulong n, GEN T, ulong p); GEN Flxq_powers(GEN x, long l, GEN T, ulong p); GEN Flxq_sqr(GEN y,GEN T,ulong p); GEN Flxq_sqrt(GEN a, GEN T, ulong p); GEN Flxq_sqrtn(GEN a, GEN n, GEN T, ulong p, GEN *zetan); ulong Flxq_trace(GEN x, GEN T, ulong p); GEN FlxqC_Flxq_mul(GEN x, GEN y, GEN T, ulong p); GEN FlxqM_Flxq_mul(GEN x, GEN y, GEN T, ulong p); GEN FlxqV_dotproduct(GEN x, GEN y, GEN T, ulong p); GEN FlxqV_roots_to_pol(GEN V, GEN T, ulong p, long v); GEN FlxqX_FlxqXQ_eval(GEN Q, GEN x, GEN S, GEN T, ulong p); GEN FlxqX_FlxqXQV_eval(GEN P, GEN V, GEN S, GEN T, ulong p); GEN FlxqX_Flxq_mul(GEN P, GEN U, GEN T, ulong p); GEN FlxqX_Flxq_mul_to_monic(GEN P, GEN U, GEN T, ulong p); GEN FlxqX_divrem(GEN x, GEN y, GEN T, ulong p, GEN *pr); GEN FlxqX_dotproduct(GEN x, GEN y, GEN T, ulong p); GEN FlxqX_extgcd(GEN a, GEN b, GEN T, ulong p, GEN *ptu, GEN *ptv); GEN FlxqX_gcd(GEN P, GEN Q, GEN T, ulong p); GEN FlxqX_get_red(GEN S, GEN T, ulong p); GEN FlxqX_halfgcd(GEN x, GEN y, GEN T, ulong p); GEN FlxqX_invBarrett(GEN T, GEN Q, ulong p); GEN FlxqX_mul(GEN x, GEN y, GEN T, ulong p); GEN FlxqX_normalize(GEN z, GEN T, ulong p); GEN FlxqX_powu(GEN V, ulong n, GEN T, ulong p); GEN FlxqX_red(GEN z, GEN T, ulong p); GEN FlxqX_rem(GEN x, GEN y, GEN T, ulong p); GEN FlxqX_safegcd(GEN P, GEN Q, GEN T, ulong p); GEN FlxqX_sqr(GEN x, GEN T, ulong p); GEN FlxqXQ_div(GEN x, GEN y, GEN S, GEN T, ulong p); GEN FlxqXQ_inv(GEN x, GEN S, GEN T, ulong p); GEN FlxqXQ_invsafe(GEN x, GEN S, GEN T, ulong p); GEN FlxqXQ_matrix_pow(GEN x, long n, long m, GEN S, GEN T, ulong p); GEN FlxqXQ_minpoly(GEN x, GEN S, GEN T, ulong p); GEN FlxqXQ_mul(GEN x, GEN y, GEN S, GEN T, ulong p); GEN FlxqXQ_pow(GEN x, GEN n, GEN S, GEN T, ulong p); GEN FlxqXQ_powu(GEN x, ulong n, GEN S, GEN T, ulong p); GEN FlxqXQ_powers(GEN x, long n, GEN S, GEN T, ulong p); GEN FlxqXQ_sqr(GEN x, GEN S, GEN T, ulong p); GEN FlxqXQ_autpow(GEN x, long n, GEN S, GEN T, ulong p); GEN FlxqXQ_autsum(GEN aut, long n, GEN S, GEN T, ulong p); GEN FlxqXQ_auttrace(GEN x, ulong n, GEN S, GEN T, ulong p); GEN FlxqXV_prod(GEN V, GEN T, ulong p); GEN Kronecker_to_FlxqX(GEN z, GEN T, ulong p); ulong Rg_to_F2(GEN x); ulong Rg_to_Fl(GEN x, ulong p); GEN Rg_to_Flxq(GEN x, GEN T, ulong p); GEN RgX_to_Flx(GEN x, ulong p); GEN RgX_to_FlxqX(GEN x, GEN T, ulong p); GEN Z_to_Flx(GEN x, ulong p, long sv); GEN ZX_to_Flx(GEN x, ulong p); GEN ZXV_to_FlxV(GEN v, ulong p); GEN ZXT_to_FlxT(GEN z, ulong p); GEN ZXX_to_FlxX(GEN B, ulong p, long v); GEN ZXXT_to_FlxXT(GEN z, ulong p, long v); GEN ZXXV_to_FlxXV(GEN V, ulong p, long v); GEN gener_Flxq(GEN T, ulong p, GEN *o); const struct bb_field *get_Flxq_field(void **E, GEN T, ulong p); const struct bb_group *get_Flxq_star(void **E, GEN T, ulong p); const struct bb_algebra *get_FlxqXQ_algebra(void **E, GEN S, GEN T, ulong p); GEN monomial_Flx(ulong a, long d, long vs); GEN pol1_FlxX(long v, long sv); GEN polx_FlxX(long v, long sv); GEN random_Flx(long d1, long v, ulong p); GEN random_FlxqX(long d1, long v, GEN T, ulong p); GEN zero_FlxC(long n, long sv); GEN zero_FlxM(long r, long c, long sv); GEN zx_to_Flx(GEN x, ulong p); GEN zxX_to_FlxX(GEN B, ulong p); GEN zxX_to_Kronecker(GEN P, GEN Q); /* FlxqE.c */ GEN Flxq_ellcard(GEN a4, GEN a6, GEN T, ulong p); GEN Flxq_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, ulong p); GEN Flxq_ellgroup(GEN a4, GEN a6, GEN N, GEN T, ulong p, GEN *pt_m); void Flxq_elltwist(GEN a, GEN a6, GEN T, ulong p, GEN *pt_a, GEN *pt_a6); GEN Flxq_ellj(GEN a4, GEN a6, GEN T, ulong p); void Flxq_ellj_to_a4a6(GEN j, GEN T, ulong p, GEN *pt_a4, GEN *pt_a6); GEN FlxqE_add(GEN P, GEN Q, GEN a4, GEN T, ulong p); GEN FlxqE_changepoint(GEN x, GEN ch, GEN T, ulong p); GEN FlxqE_changepointinv(GEN x, GEN ch, GEN T, ulong p); GEN FlxqE_dbl(GEN P, GEN a4, GEN T, ulong p); GEN FlxqE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, ulong p); GEN FlxqE_mul(GEN P, GEN n, GEN a4, GEN T, ulong p); GEN FlxqE_neg(GEN P, GEN T, ulong p); GEN FlxqE_order(GEN z, GEN o, GEN a4, GEN T, ulong p); GEN FlxqE_sub(GEN P, GEN Q, GEN a4, GEN T, ulong p); GEN FlxqE_tatepairing(GEN t, GEN s, GEN m, GEN a4, GEN T, ulong p); GEN FlxqE_weilpairing(GEN t, GEN s, GEN m, GEN a4, GEN T, ulong p); const struct bb_group * get_FlxqE_group(void **E, GEN a4, GEN a6, GEN T, ulong p); GEN RgE_to_FlxqE(GEN x, GEN T, ulong p); GEN random_FlxqE(GEN a4, GEN a6, GEN T, ulong p); /* FpE.c */ long Fl_elltrace(ulong a4, ulong a6, ulong p); long Fl_elltrace_CM(long CM, ulong a4, ulong a6, ulong p); GEN Fp_ellcard(GEN a4, GEN a6, GEN p); GEN Fp_elldivpol(GEN a4, GEN a6, long n, GEN p); GEN Fp_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN p); GEN Fp_ellgroup(GEN a4, GEN a6, GEN N, GEN p, GEN *pt_m); GEN Fp_ellj(GEN a4, GEN a6, GEN p); int Fp_elljissupersingular(GEN j, GEN p); void Fp_elltwist(GEN a4, GEN a6, GEN p, GEN *pt_a4, GEN *pt_a6); GEN Fp_ffellcard(GEN a4, GEN a6, GEN q, long n, GEN p); GEN FpE_add(GEN P, GEN Q, GEN a4, GEN p); GEN FpE_changepoint(GEN x, GEN ch, GEN p); GEN FpE_changepointinv(GEN x, GEN ch, GEN p); GEN FpE_dbl(GEN P, GEN a4, GEN p); GEN FpE_log(GEN a, GEN b, GEN o, GEN a4, GEN p); GEN FpE_mul(GEN P, GEN n, GEN a4, GEN p); GEN FpE_neg(GEN P, GEN p); GEN FpE_order(GEN z, GEN o, GEN a4, GEN p); GEN FpE_sub(GEN P, GEN Q, GEN a4, GEN p); GEN FpE_to_FpJ(GEN P); GEN FpE_to_mod(GEN P, GEN p); GEN FpE_tatepairing(GEN t, GEN s, GEN m, GEN a4, GEN p); GEN FpE_weilpairing(GEN t, GEN s, GEN m, GEN a4, GEN p); GEN FpJ_add(GEN P, GEN Q, GEN a4, GEN p); GEN FpJ_dbl(GEN P, GEN a4, GEN p); GEN FpJ_mul(GEN P, GEN n, GEN a4, GEN p); GEN FpJ_neg(GEN Q, GEN p); GEN FpJ_to_FpE(GEN P, GEN p); GEN FpXQ_ellcard(GEN a4, GEN a6, GEN T, GEN p); GEN FpXQ_elldivpol(GEN a4, GEN a6, long n, GEN T, GEN p); GEN FpXQ_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, GEN p); GEN FpXQ_ellgroup(GEN a4, GEN a6, GEN N, GEN T, GEN p, GEN *pt_m); GEN FpXQ_ellj(GEN a4, GEN a6, GEN T, GEN p); int FpXQ_elljissupersingular(GEN j, GEN T, GEN p); void FpXQ_elltwist(GEN a4, GEN a6, GEN T, GEN p, GEN *pt_a4, GEN *pt_a6); GEN FpXQE_add(GEN P, GEN Q, GEN a4, GEN T, GEN p); GEN FpXQE_changepoint(GEN x, GEN ch, GEN T, GEN p); GEN FpXQE_changepointinv(GEN x, GEN ch, GEN T, GEN p); GEN FpXQE_dbl(GEN P, GEN a4, GEN T, GEN p); GEN FpXQE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, GEN p); GEN FpXQE_mul(GEN P, GEN n, GEN a4, GEN T, GEN p); GEN FpXQE_neg(GEN P, GEN T, GEN p); GEN FpXQE_order(GEN z, GEN o, GEN a4, GEN T, GEN p); GEN FpXQE_sub(GEN P, GEN Q, GEN a4, GEN T, GEN p); GEN FpXQE_tatepairing(GEN t, GEN s, GEN m, GEN a4, GEN T, GEN p); GEN FpXQE_weilpairing(GEN t, GEN s, GEN m, GEN a4, GEN T, GEN p); GEN Fq_elldivpolmod(GEN a4, GEN a6, long n, GEN h, GEN T, GEN p); GEN RgE_to_FpE(GEN x, GEN p); GEN RgE_to_FpXQE(GEN x, GEN T, GEN p); const struct bb_group * get_FpE_group(void **E, GEN a4, GEN a6, GEN p); const struct bb_group * get_FpXQE_group(void **E, GEN a4, GEN a6, GEN T, GEN p); GEN elltrace_extension(GEN t, long n, GEN p); GEN random_FpE(GEN a4, GEN a6, GEN p); GEN random_FpXQE(GEN a4, GEN a6, GEN T, GEN p); /* FpX.c */ int Fp_issquare(GEN x, GEN p); GEN Fp_FpX_sub(GEN x, GEN y, GEN p); GEN Fp_FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p); GEN FpV_FpM_polint(GEN xa, GEN ya, GEN p, long vs); GEN FpV_inv(GEN x, GEN p); GEN FpV_invVandermonde(GEN L, GEN den, GEN p); GEN FpV_polint(GEN xa, GEN ya, GEN p, long v); GEN FpV_roots_to_pol(GEN V, GEN p, long v); GEN FpX_Fp_add(GEN x, GEN y, GEN p); GEN FpX_Fp_add_shallow(GEN y,GEN x,GEN p); GEN FpX_Fp_mul(GEN x, GEN y, GEN p); GEN FpX_Fp_mul_to_monic(GEN y,GEN x,GEN p); GEN FpX_Fp_mulspec(GEN y,GEN x,GEN p,long ly); GEN FpX_Fp_sub(GEN x, GEN y, GEN p); GEN FpX_Fp_sub_shallow(GEN y,GEN x,GEN p); GEN FpX_FpV_multieval(GEN P, GEN xa, GEN p); GEN FpX_FpXQ_eval(GEN f,GEN x,GEN T,GEN p); GEN FpX_FpXQV_eval(GEN f,GEN x,GEN T,GEN p); GEN FpX_Frobenius(GEN T, GEN p); GEN FpX_Laplace(GEN x, GEN p); GEN FpX_Newton(GEN P, long n, GEN p); GEN FpX_add(GEN x, GEN y, GEN p); GEN FpX_center(GEN x, GEN p, GEN pov2); GEN FpX_center_i(GEN T, GEN p, GEN pov2); GEN FpX_chinese_coprime(GEN x,GEN y,GEN Tx,GEN Ty,GEN Tz,GEN p); GEN FpX_convol(GEN x, GEN y, GEN p); GEN FpX_deriv(GEN x, GEN p); GEN FpX_digits(GEN x, GEN y, GEN p); GEN FpX_disc(GEN x, GEN p); GEN FpX_div_by_X_x(GEN a, GEN x, GEN p, GEN *r); GEN FpX_divrem(GEN x, GEN y, GEN p, GEN *pr); GEN FpX_dotproduct(GEN x, GEN y, GEN p); GEN FpX_eval(GEN x,GEN y,GEN p); GEN FpX_extgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv); GEN FpX_fromNewton(GEN P, GEN p); GEN FpX_gcd(GEN x, GEN y, GEN p); GEN FpX_gcd_check(GEN x, GEN y, GEN p); GEN FpX_get_red(GEN T, GEN p); GEN FpX_halve(GEN y, GEN p); GEN FpX_halfgcd(GEN x, GEN y, GEN p); GEN FpX_integ(GEN x, GEN p); GEN FpX_invBarrett(GEN T, GEN p); GEN FpX_invLaplace(GEN x, GEN p); int FpX_is_squarefree(GEN f, GEN p); long FpX_ispower(GEN f, ulong k, GEN p, GEN *pt_r); GEN FpX_matFrobenius(GEN T, GEN p); GEN FpX_mul(GEN x, GEN y, GEN p); GEN FpX_mulspec(GEN a, GEN b, GEN p, long na, long nb); GEN FpX_mulu(GEN x, ulong y, GEN p); GEN FpX_neg(GEN x, GEN p); GEN FpX_normalize(GEN z, GEN p); GEN FpX_powu(GEN x, ulong n, GEN p); GEN FpX_red(GEN z, GEN p); GEN FpX_rem(GEN x, GEN y, GEN p); GEN FpX_rescale(GEN P, GEN h, GEN p); GEN FpX_resultant(GEN a, GEN b, GEN p); GEN FpX_sqr(GEN x, GEN p); GEN FpX_sub(GEN x, GEN y, GEN p); long FpX_valrem(GEN x0, GEN t, GEN p, GEN *py); GEN FpXC_FpXQV_eval(GEN Q, GEN x, GEN T, GEN p); GEN FpXM_FpXQV_eval(GEN Q, GEN x, GEN T, GEN p); GEN FpXQ_autpow(GEN x, ulong n, GEN T, GEN p); GEN FpXQ_autpowers(GEN aut, long f, GEN T, GEN p); GEN FpXQ_autsum(GEN x, ulong n, GEN T, GEN p); GEN FpXQ_auttrace(GEN x, ulong n, GEN T, GEN p); GEN FpXQ_charpoly(GEN x, GEN T, GEN p); GEN FpXQ_conjvec(GEN x, GEN T, GEN p); GEN FpXQ_div(GEN x,GEN y,GEN T,GEN p); GEN FpXQ_inv(GEN x,GEN T,GEN p); GEN FpXQ_invsafe(GEN x, GEN T, GEN p); int FpXQ_issquare(GEN x, GEN T, GEN p); GEN FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p); GEN FpXQ_matrix_pow(GEN y, long n, long m, GEN P, GEN l); GEN FpXQ_minpoly(GEN x, GEN T, GEN p); GEN FpXQ_mul(GEN y,GEN x,GEN T,GEN p); GEN FpXQ_norm(GEN x, GEN T, GEN p); GEN FpXQ_order(GEN a, GEN ord, GEN T, GEN p); GEN FpXQ_pow(GEN x, GEN n, GEN T, GEN p); GEN FpXQ_powu(GEN x, ulong n, GEN T, GEN p); GEN FpXQ_powers(GEN x, long l, GEN T, GEN p); GEN FpXQ_red(GEN x, GEN T, GEN p); GEN FpXQ_sqr(GEN y, GEN T, GEN p); GEN FpXQ_sqrt(GEN a, GEN T, GEN p); GEN FpXQ_sqrtn(GEN a, GEN n, GEN T, GEN p, GEN *zetan); GEN FpXQ_trace(GEN x, GEN T, GEN p); GEN FpXQC_to_mod(GEN z, GEN T, GEN p); GEN FpXQM_autsum(GEN x, ulong n, GEN T, GEN p); GEN FpXT_red(GEN z, GEN p); GEN FpXV_FpX_fromdigits(GEN x, GEN T, GEN p); GEN FpXV_prod(GEN V, GEN p); GEN FpXV_red(GEN z, GEN p); GEN FpXn_exp(GEN x, long n, GEN p); GEN FpXn_inv(GEN x, long n, GEN p); GEN FpXn_mul(GEN a, GEN b, long n, GEN p); GEN FpXn_sqr(GEN a, long n, GEN p); int Fq_issquare(GEN x, GEN T, GEN p); long Fq_ispower(GEN x, GEN K, GEN T, GEN p); GEN Fq_log(GEN a, GEN g, GEN ord, GEN T, GEN p); GEN FqM_to_mod(GEN z, GEN T, GEN p); GEN FqV_inv(GEN x, GEN T, GEN p); GEN Z_to_FpX(GEN a, GEN p, long v); GEN gener_FpXQ(GEN T, GEN p, GEN *o); GEN gener_FpXQ_local(GEN T, GEN p, GEN L); const struct bb_group * get_FpXQ_star(void **E, GEN T, GEN p); const struct bb_algebra * get_FpX_algebra(void **E, GEN p, long v); const struct bb_algebra * get_FpXQ_algebra(void **E, GEN T, GEN p); GEN random_FpX(long d, long v, GEN p); /* FpX_factor.c */ GEN F2x_ddf(GEN f); GEN F2x_factor(GEN f); GEN F2x_factor_squarefree(GEN f); int F2x_is_irred(GEN f); void F2xV_to_FlxV_inplace(GEN v); void F2xV_to_ZXV_inplace(GEN v); GEN Flx_ddf(GEN T, ulong p); int Flx_is_irred(GEN f, ulong p); long Flx_ispower(GEN f, ulong k, ulong p, GEN *pt_r); GEN Flx_degfact(GEN f, ulong p); GEN Flx_factor(GEN f, ulong p); GEN Flx_factor_squarefree(GEN f, ulong p); long Flx_nbfact(GEN z, ulong p); long Flx_nbfact_Frobenius(GEN T, GEN XP, ulong p); GEN Flx_nbfact_by_degree(GEN z, long *nb, ulong p); long Flx_nbroots(GEN f, ulong p); ulong Flx_oneroot(GEN f, ulong p); ulong Flx_oneroot_split(GEN f, ulong p); GEN Flx_roots(GEN f, ulong p); GEN Flx_rootsff(GEN P, GEN T, ulong p); void FlxV_to_ZXV_inplace(GEN v); GEN FpX_ddf(GEN f, GEN p); long FpX_ddf_degree(GEN T, GEN XP, GEN p); GEN FpX_degfact(GEN f, GEN p); GEN FpX_factor(GEN f, GEN p); GEN FpX_factor_squarefree(GEN T, GEN p); int FpX_is_irred(GEN f, GEN p); int FpX_is_totally_split(GEN f, GEN p); long FpX_nbfact(GEN f, GEN p); long FpX_nbfact_Frobenius(GEN T, GEN XP, GEN p); long FpX_nbroots(GEN f, GEN p); GEN FpX_oneroot(GEN f, GEN p); GEN FpX_oneroot_split(GEN fact, GEN p); GEN FpX_roots(GEN f, GEN p); GEN FpX_rootsff(GEN P, GEN T, GEN p); GEN FpX_split_part(GEN f, GEN p); /* FpXQX_factor.c */ GEN F2xqX_ddf(GEN S, GEN T); GEN F2xqX_degfact(GEN S, GEN T); GEN F2xqX_factor(GEN x, GEN T); GEN F2xqX_factor_squarefree(GEN x, GEN T); GEN F2xqX_roots(GEN x, GEN T); GEN Flx_factorff_irred(GEN P, GEN Q, ulong p); void Flx_ffintersect(GEN P,GEN Q,long n,ulong l,GEN *SP,GEN *SQ,GEN MA,GEN MB); GEN Flx_ffisom(GEN P,GEN Q,ulong l); GEN Flxq_ffisom_inv(GEN S,GEN Tp, ulong p); GEN FlxqX_Frobenius(GEN S, GEN T, ulong p); GEN FlxqX_ddf(GEN S, GEN T, ulong p); long FlxqX_ddf_degree(GEN S, GEN XP, GEN T, ulong p); GEN FlxqX_degfact(GEN S, GEN T, ulong p); GEN FlxqX_factor(GEN x, GEN T, ulong p); GEN FlxqX_factor_squarefree(GEN x, GEN T, ulong p); long FlxqX_ispower(GEN f, ulong k, GEN T, ulong p, GEN *pt_r); long FlxqX_is_squarefree(GEN P, GEN T, ulong p); long FlxqX_nbfact(GEN S, GEN T, ulong p); long FlxqX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, ulong p); long FlxqX_nbroots(GEN f, GEN T, ulong p); GEN FlxqX_roots(GEN S, GEN T, ulong p); GEN FlxqXQ_halfFrobenius(GEN a, GEN S, GEN T, ulong p); GEN FpX_factorff(GEN P, GEN T, GEN p); GEN FpX_factorff_irred(GEN P, GEN Q, GEN p); void FpX_ffintersect(GEN P,GEN Q,long n,GEN l,GEN *SP,GEN *SQ,GEN MA,GEN MB); GEN FpX_ffisom(GEN P,GEN Q,GEN l); GEN FpXQ_ffisom_inv(GEN S,GEN Tp, GEN p); GEN FpXQX_Frobenius(GEN S, GEN T, GEN p); GEN FpXQX_ddf(GEN S, GEN T, GEN p); long FpXQX_ddf_degree(GEN S, GEN XP, GEN T, GEN p); GEN FpXQX_degfact(GEN S, GEN T, GEN p); GEN FpXQX_factor(GEN x, GEN T, GEN p); GEN FpXQX_factor_squarefree(GEN x, GEN T, GEN p); long FpXQX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt); long FpXQX_nbfact(GEN u, GEN T, GEN p); long FpXQX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, GEN p); long FpXQX_nbroots(GEN f, GEN T, GEN p); GEN FpXQX_roots(GEN f, GEN T, GEN p); GEN FpXQX_split_part(GEN f, GEN T, GEN p); GEN FpXQXQ_halfFrobenius(GEN a, GEN S, GEN T, GEN p); long FqX_is_squarefree(GEN P, GEN T, GEN p); long FqX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt); long FqX_nbfact(GEN u, GEN T, GEN p); long FqX_nbroots(GEN f, GEN T, GEN p); GEN factorff(GEN f, GEN p, GEN a); GEN factormod0(GEN f, GEN p,long flag); GEN factormodDDF(GEN f, GEN D); GEN factormodSQF(GEN f, GEN D); GEN polrootsff(GEN f, GEN p, GEN T); GEN polrootsmod(GEN f, GEN p); GEN rootmod0(GEN f, GEN p,long flag); /* FpXX.c */ GEN FpXQX_FpXQ_mul(GEN P, GEN U, GEN T, GEN p); GEN FpXQX_FpXQXQV_eval(GEN P, GEN V, GEN S, GEN T, GEN p); GEN FpXQX_FpXQXQ_eval(GEN P, GEN x, GEN S, GEN T, GEN p); GEN FpXQX_div_by_X_x(GEN a, GEN x, GEN T, GEN p, GEN *pr); GEN FpXQX_divrem(GEN x, GEN y, GEN T, GEN p, GEN *pr); GEN FpXQX_digits(GEN x, GEN B, GEN T, GEN p); GEN FpXQX_dotproduct(GEN x, GEN y, GEN T, GEN p); GEN FpXQX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv); GEN FpXQX_gcd(GEN P, GEN Q, GEN T, GEN p); GEN FpXQX_get_red(GEN S, GEN T, GEN p); GEN FpXQX_halfgcd(GEN x, GEN y, GEN T, GEN p); GEN FpXQX_invBarrett(GEN S, GEN T, GEN p); GEN FpXQX_mul(GEN x, GEN y, GEN T, GEN p); GEN FpXQX_powu(GEN x, ulong n, GEN T, GEN p); GEN FpXQX_red(GEN z, GEN T, GEN p); GEN FpXQX_rem(GEN x, GEN S, GEN T, GEN p); GEN FpXQX_sqr(GEN x, GEN T, GEN p); GEN FpXQX_to_mod(GEN z, GEN T, GEN p); GEN FpXQXQ_div(GEN x,GEN y,GEN S, GEN T,GEN p); GEN FpXQXQ_inv(GEN x, GEN S, GEN T,GEN p); GEN FpXQXQ_invsafe(GEN x, GEN S, GEN T, GEN p); GEN FpXQXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, GEN p); GEN FpXQXQ_minpoly(GEN x, GEN S, GEN T, GEN p); GEN FpXQXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p); GEN FpXQXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p); GEN FpXQXQ_powers(GEN x, long n, GEN S, GEN T, GEN p); GEN FpXQXQ_sqr(GEN x, GEN S, GEN T, GEN p); GEN FpXQXQ_autpow(GEN aut, long n, GEN S, GEN T, GEN p); GEN FpXQXQ_autsum(GEN aut, long n, GEN S, GEN T, GEN p); GEN FpXQXQ_auttrace(GEN aut, long n, GEN S, GEN T, GEN p); GEN FpXQXV_FpXQX_fromdigits(GEN x, GEN B, GEN T, GEN p); GEN FpXQXV_prod(GEN V, GEN Tp, GEN p); GEN FpXQXn_exp(GEN x, long n, GEN T, GEN p); GEN FpXQXn_inv(GEN x, long n, GEN T, GEN p); GEN FpXQXn_mul(GEN x, GEN y, long n, GEN T, GEN p); GEN FpXQXn_sqr(GEN x, long n, GEN T, GEN p); GEN FpXX_Fp_mul(GEN x, GEN y, GEN p); GEN FpXX_FpX_mul(GEN x, GEN y, GEN p); GEN FpXX_add(GEN x, GEN y, GEN p); GEN FpXX_deriv(GEN P, GEN p); GEN FpXX_halve(GEN P, GEN p); GEN FpXX_integ(GEN P, GEN p); GEN FpXX_mulu(GEN P, ulong u, GEN p); GEN FpXX_neg(GEN x, GEN p); GEN FpXX_red(GEN z, GEN p); GEN FpXX_sub(GEN x, GEN y, GEN p); GEN FpXY_FpXQ_evalx(GEN P, GEN x, GEN T, GEN p); GEN FpXY_FpXQV_evalx(GEN P, GEN x, GEN T, GEN p); GEN FpXY_eval(GEN Q, GEN y, GEN x, GEN p); GEN FpXY_evalx(GEN Q, GEN x, GEN p); GEN FpXY_evaly(GEN Q, GEN y, GEN p, long vy); GEN FpXYQQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p); GEN Kronecker_to_FpXQX(GEN z, GEN pol, GEN p); GEN Kronecker_to_ZXX(GEN z, long N, long v); GEN ZXX_mul_Kronecker(GEN x, GEN y, long n); GEN ZXX_sqr_Kronecker(GEN x, long n); const struct bb_algebra * get_FpXQX_algebra(void **E, GEN T, GEN p, long v); const struct bb_algebra * get_FpXQXQ_algebra(void **E, GEN S, GEN T, GEN p); GEN random_FpXQX(long d1, long v, GEN T, GEN p); /* FpV.c */ GEN F2m_F2c_mul(GEN x, GEN y); GEN F2m_mul(GEN x, GEN y); GEN F2m_powu(GEN x, ulong n); GEN Flc_Flv_mul(GEN x, GEN y, ulong p); GEN Flc_to_mod(GEN z, ulong pp); GEN Flm_Fl_add(GEN x, ulong y, ulong p); GEN Flm_Fl_mul(GEN y, ulong x, ulong p); void Flm_Fl_mul_inplace(GEN y, ulong x, ulong p); GEN Flm_Flc_mul(GEN x, GEN y, ulong p); GEN Flm_Flc_mul_pre(GEN x, GEN y, ulong p, ulong pi); GEN Flm_Flc_mul_pre_Flx(GEN x, GEN y, ulong p, ulong pi, long sv); GEN Flm_add(GEN x, GEN y, ulong p); GEN Flm_center(GEN z, ulong p, ulong ps2); GEN Flm_mul(GEN x, GEN y, ulong p); GEN Flm_neg(GEN y, ulong p); GEN Flm_powers(GEN x, ulong n, ulong p); GEN Flm_powu(GEN x, ulong n, ulong p); GEN Flm_sub(GEN x, GEN y, ulong p); GEN Flm_to_mod(GEN z, ulong pp); GEN Flm_transpose(GEN x); GEN Flv_Fl_div(GEN x, ulong y, ulong p); void Flv_Fl_div_inplace(GEN x, ulong y, ulong p); GEN Flv_Fl_mul(GEN x, ulong y, ulong p); void Flv_Fl_mul_inplace(GEN x, ulong y, ulong p); void Flv_Fl_mul_part_inplace(GEN x, ulong y, ulong p, long l); GEN Flv_add(GEN x, GEN y, ulong p); void Flv_add_inplace(GEN x, GEN y, ulong p); GEN Flv_center(GEN z, ulong p, ulong ps2); ulong Flv_dotproduct(GEN x, GEN y, ulong p); ulong Flv_dotproduct_pre(GEN x, GEN y, ulong p, ulong pi); GEN Flv_neg(GEN v, ulong p); void Flv_neg_inplace(GEN v, ulong p); GEN Flv_sub(GEN x, GEN y, ulong p); void Flv_sub_inplace(GEN x, GEN y, ulong p); ulong Flv_sum(GEN x, ulong p); ulong Flx_dotproduct(GEN x, GEN y, ulong p); GEN Fp_to_mod(GEN z, GEN p); GEN FpC_FpV_mul(GEN x, GEN y, GEN p); GEN FpC_Fp_mul(GEN x, GEN y, GEN p); GEN FpC_center(GEN z, GEN p, GEN pov2); void FpC_center_inplace(GEN z, GEN p, GEN pov2); GEN FpC_red(GEN z, GEN p); GEN FpC_to_mod(GEN z, GEN p); GEN FpM_add(GEN x, GEN y, GEN p); GEN FpM_Fp_mul(GEN X, GEN c, GEN p); GEN FpM_FpC_mul(GEN x, GEN y, GEN p); GEN FpM_FpC_mul_FpX(GEN x, GEN y, GEN p, long v); GEN FpM_center(GEN z, GEN p, GEN pov2); void FpM_center_inplace(GEN z, GEN p, GEN pov2); GEN FpM_mul(GEN x, GEN y, GEN p); GEN FpM_powu(GEN x, ulong n, GEN p); GEN FpM_red(GEN z, GEN p); GEN FpM_sub(GEN x, GEN y, GEN p); GEN FpM_to_mod(GEN z, GEN p); GEN FpMs_FpC_mul(GEN M, GEN B, GEN p); GEN FpMs_FpCs_solve(GEN M, GEN B, long nbrow, GEN p); GEN FpMs_FpCs_solve_safe(GEN M, GEN A, long nbrow, GEN p); GEN FpMs_leftkernel_elt(GEN M, long nbrow, GEN p); GEN FpC_add(GEN x, GEN y, GEN p); GEN FpC_sub(GEN x, GEN y, GEN p); GEN FpV_FpMs_mul(GEN B, GEN M, GEN p); GEN FpV_add(GEN x, GEN y, GEN p); GEN FpV_sub(GEN x, GEN y, GEN p); GEN FpV_dotproduct(GEN x, GEN y, GEN p); GEN FpV_dotsquare(GEN x, GEN p); GEN FpV_red(GEN z, GEN p); GEN FpV_to_mod(GEN z, GEN p); GEN FpVV_to_mod(GEN z, GEN p); GEN FpX_to_mod(GEN z, GEN p); GEN ZabM_ker(GEN M, GEN P, long n); GEN ZabM_indexrank(GEN M, GEN P, long n); GEN ZabM_inv(GEN M, GEN P, long n, GEN *pden); GEN ZabM_inv_ratlift(GEN M, GEN P, long n, GEN *pden); GEN ZabM_pseudoinv(GEN M, GEN P, long n, GEN *pv, GEN *den); GEN ZV_zMs_mul(GEN B, GEN M); GEN ZpMs_ZpCs_solve(GEN M, GEN B, long nbrow, GEN p, long e); GEN gen_FpM_Wiedemann(void *E, GEN (*f)(void*, GEN), GEN B, GEN p); GEN gen_ZpM_Dixon(void *E, GEN (*f)(void*, GEN), GEN B, GEN p, long e); GEN gen_matid(long n, void *E, const struct bb_field *S); GEN matid_F2m(long n); GEN matid_Flm(long n); GEN matid_F2xqM(long n, GEN T); GEN matid_FlxqM(long n, GEN T, ulong p); GEN random_Flv(long n, ulong p); GEN random_FpC(long d, GEN p); GEN random_FpV(long d, GEN p); GEN scalar_Flm(long s, long n); GEN zCs_to_ZC(GEN C, long nbrow); GEN zMs_to_ZM(GEN M, long nbrow); GEN zMs_ZC_mul(GEN M, GEN B); GEN ZMV_to_FlmV(GEN z, ulong m); /* Hensel.c */ GEN Z2_sqrt(GEN x, long e); GEN Zp_sqrt(GEN x, GEN p, long e); GEN Zp_sqrtlift(GEN b, GEN a, GEN p, long e); GEN Zp_sqrtnlift(GEN b, GEN n, GEN a, GEN p, long e); GEN ZpX_Frobenius(GEN T, GEN p, long e); GEN ZpX_ZpXQ_liftroot(GEN P, GEN S, GEN T, GEN p, long e); GEN ZpX_ZpXQ_liftroot_ea(GEN P, GEN S, GEN T, GEN p, long n, void *E, int early(void *E, GEN x, GEN q)); GEN ZpX_liftfact(GEN pol, GEN Q, GEN pe, GEN p, long e); GEN ZpX_liftroot(GEN f, GEN a, GEN p, long e); GEN ZpX_liftroots(GEN f, GEN S, GEN p, long e); GEN ZpX_roots(GEN f, GEN p, long e); GEN ZpXQ_div(GEN a, GEN b, GEN T, GEN q, GEN p, long e); GEN ZpXQ_inv(GEN a, GEN T, GEN p, long e); GEN ZpXQ_invlift(GEN b, GEN a, GEN T, GEN p, long e); GEN ZpXQ_log(GEN a, GEN T, GEN p, long N); GEN ZpXQ_sqrt(GEN a, GEN T, GEN p, long e); GEN ZpXQ_sqrtnlift(GEN b, GEN n, GEN a, GEN T, GEN p, long e); GEN ZpXQM_prodFrobenius(GEN M, GEN T, GEN p, long e); GEN ZpXQX_digits(GEN x, GEN B, GEN T, GEN q, GEN p, long e); GEN ZpXQX_divrem(GEN x, GEN S, GEN T, GEN q, GEN p, long e, GEN *pr); GEN ZpXQX_liftfact(GEN pol, GEN Q, GEN T, GEN pe, GEN p, long e); GEN ZpXQX_liftroot(GEN f, GEN a, GEN T, GEN p, long e); GEN ZpXQX_liftroot_vald(GEN f, GEN a, long v, GEN T, GEN p, long e); GEN ZpXQX_roots(GEN F, GEN T, GEN p, long e); GEN Zq_sqrtnlift(GEN a, GEN n, GEN x, GEN T, GEN p, long e); GEN ZqX_liftfact(GEN pol, GEN Q, GEN T, GEN pe, GEN p, long e); GEN ZqX_liftroot(GEN f, GEN a, GEN T, GEN p, long e); GEN ZqX_roots(GEN F, GEN T, GEN p, long e); GEN gen_ZpX_Dixon(GEN F, GEN V, GEN q, GEN p, long N, void *E, GEN lin(void *E, GEN F, GEN d, GEN q), GEN invl(void *E, GEN d)); GEN gen_ZpX_Newton(GEN x, GEN p, long n, void *E, GEN eval(void *E, GEN f, GEN q), GEN invd(void *E, GEN V, GEN v, GEN q, long M)); GEN polhensellift(GEN pol, GEN fct, GEN p, long exp); ulong quadratic_prec_mask(long n); /* QX_factor.c */ GEN QX_factor(GEN x); GEN ZX_factor(GEN x); long ZX_is_irred(GEN x); GEN ZX_squff(GEN f, GEN *ex); GEN polcyclofactors(GEN f); long poliscyclo(GEN f); long poliscycloprod(GEN f); /* RgV.c */ GEN Rg_RgC_sub(GEN a, GEN x); GEN RgC_Rg_add(GEN x, GEN y); GEN RgC_Rg_div(GEN x, GEN y); GEN RgC_Rg_mul(GEN x, GEN y); GEN RgC_Rg_sub(GEN x, GEN y); GEN RgC_RgM_mul(GEN x, GEN y); GEN RgC_RgV_mul(GEN x, GEN y); GEN RgC_add(GEN x, GEN y); long RgC_is_ei(GEN x); GEN RgC_neg(GEN x); GEN RgC_sub(GEN x, GEN y); GEN RgM_Rg_add(GEN x, GEN y); GEN RgM_Rg_add_shallow(GEN x, GEN y); GEN RgM_Rg_div(GEN x, GEN y); GEN RgM_Rg_mul(GEN x, GEN y); GEN RgM_Rg_sub(GEN x, GEN y); GEN RgM_Rg_sub_shallow(GEN x, GEN y); GEN RgM_RgC_mul(GEN x, GEN y); GEN RgM_RgV_mul(GEN x, GEN y); GEN RgM_add(GEN x, GEN y); GEN RgM_det_triangular(GEN x); int RgM_is_QM(GEN x); int RgM_is_ZM(GEN x); int RgM_isdiagonal(GEN x); int RgM_isidentity(GEN x); int RgM_isscalar(GEN x, GEN s); GEN RgM_mul(GEN x, GEN y); GEN RgM_multosym(GEN x, GEN y); GEN RgM_neg(GEN x); GEN RgM_powers(GEN x, long l); GEN RgM_sqr(GEN x); GEN RgM_sub(GEN x, GEN y); GEN RgM_sumcol(GEN A); GEN RgM_transmul(GEN x, GEN y); GEN RgM_transmultosym(GEN x, GEN y); GEN RgMrow_zc_mul(GEN x, GEN y, long i); GEN RgM_zc_mul(GEN x, GEN y); GEN RgM_zm_mul(GEN x, GEN y); GEN RgMrow_RgC_mul(GEN x, GEN y, long i); GEN RgV_RgM_mul(GEN x, GEN y); GEN RgV_RgC_mul(GEN x, GEN y); GEN RgV_Rg_mul(GEN x, GEN y); GEN RgV_add(GEN x, GEN y); GEN RgV_dotproduct(GEN x, GEN y); GEN RgV_dotsquare(GEN x); int RgV_is_ZMV(GEN V); long RgV_isin(GEN v, GEN x); GEN RgV_kill0(GEN v); GEN RgV_neg(GEN x); GEN RgV_prod(GEN v); GEN RgV_sub(GEN x, GEN y); GEN RgV_sum(GEN v); GEN RgV_sumpart(GEN v, long n); GEN RgV_sumpart2(GEN v, long m, long n); GEN RgV_zc_mul(GEN x, GEN y); GEN RgV_zm_mul(GEN x, GEN y); GEN RgX_RgM_eval(GEN x, GEN y); GEN RgX_RgMV_eval(GEN x, GEN y); int isdiagonal(GEN x); GEN matid(long n); GEN scalarcol(GEN x, long n); GEN scalarcol_shallow(GEN x, long n); GEN scalarmat(GEN x, long n); GEN scalarmat_shallow(GEN x, long n); GEN scalarmat_s(long x, long n); /* RgX.c */ GEN Kronecker_to_mod(GEN z, GEN pol); GEN QX_ZXQV_eval(GEN P, GEN V, GEN dV); GEN QXQ_charpoly(GEN A, GEN T, long v); GEN QXQ_powers(GEN a, long n, GEN T); GEN QXQC_to_mod_shallow(GEN V, GEN T); GEN QXQM_to_mod_shallow(GEN V, GEN T); GEN QXQV_to_mod(GEN V, GEN T); GEN QXQX_to_mod_shallow(GEN z, GEN T); GEN QXQXV_to_mod(GEN V, GEN T); GEN QXV_QXQ_eval(GEN v, GEN a, GEN T); GEN QXX_QXQ_eval(GEN v, GEN a, GEN T); GEN Rg_RgX_sub(GEN x, GEN y); GEN Rg_get_0(GEN x); GEN Rg_get_1(GEN x); GEN Rg_to_RgC(GEN x, long N); GEN RgM_to_RgXV(GEN x, long v); GEN RgM_to_RgXX(GEN x, long v,long w); GEN RgV_to_RgX(GEN x, long v); GEN RgV_to_RgM(GEN v, long n); GEN RgV_to_RgX_reverse(GEN x, long v); GEN RgX_RgXQ_eval(GEN f, GEN x, GEN T); GEN RgX_RgXQV_eval(GEN P, GEN V, GEN T); GEN RgX_RgXn_eval(GEN Q, GEN x, long n); GEN RgX_RgXnV_eval(GEN Q, GEN x, long n); GEN RgX_Rg_add(GEN y, GEN x); GEN RgX_Rg_add_shallow(GEN y, GEN x); GEN RgX_Rg_div(GEN y, GEN x); GEN RgX_Rg_divexact(GEN x, GEN y); GEN RgX_Rg_eval_bk(GEN Q, GEN x); GEN RgX_Rg_mul(GEN y, GEN x); GEN RgX_Rg_sub(GEN y, GEN x); GEN RgX_RgV_eval(GEN Q, GEN x); GEN RgX_add(GEN x, GEN y); GEN RgX_addmulXn_shallow(GEN x, GEN y, long d); GEN RgX_addmulXn(GEN x, GEN y, long d); GEN RgX_addspec(GEN x, GEN y, long nx, long ny); GEN RgX_addspec_shallow(GEN x, GEN y, long nx, long ny); GEN RgX_blocks(GEN P, long n, long m); GEN RgX_deflate(GEN x0, long d); GEN RgX_deriv(GEN x); GEN RgX_digits(GEN A, GEN B); GEN RgX_div_by_X_x(GEN a, GEN x, GEN *r); GEN RgX_divrem(GEN x,GEN y,GEN *r); GEN RgX_divs(GEN y, long x); long RgX_equal(GEN x, GEN y); void RgX_even_odd(GEN p, GEN *pe, GEN *po); GEN RgX_inflate(GEN x0, long d); GEN RgX_mul(GEN x,GEN y); GEN RgX_mul_i(GEN x,GEN y); GEN RgX_mul_normalized(GEN A, long a, GEN B, long b); GEN RgX_mulXn(GEN x, long d); GEN RgX_mulhigh_i(GEN f, GEN g, long n); GEN RgX_muls(GEN y, long x); GEN RgX_mulspec(GEN a, GEN b, long na, long nb); GEN RgX_neg(GEN x); GEN RgX_normalize(GEN x); GEN RgX_pseudodivrem(GEN x, GEN y, GEN *ptr); GEN RgX_pseudorem(GEN x, GEN y); GEN RgX_recip(GEN x); GEN RgX_recip_shallow(GEN x); GEN RgX_rem(GEN x, GEN y); GEN RgX_renormalize_lg(GEN x, long lx); GEN RgX_rescale(GEN P, GEN h); GEN RgX_rotate_shallow(GEN P, long k, long p); GEN RgX_shift(GEN a, long n); GEN RgX_shift_shallow(GEN x, long n); GEN RgX_splitting(GEN p, long k); GEN RgX_sqr(GEN x); GEN RgX_sqr_i(GEN x); GEN RgX_sqrhigh_i(GEN f, long n); GEN RgX_sqrspec(GEN a, long na); GEN RgX_sub(GEN x, GEN y); GEN RgX_to_RgC(GEN x, long N); GEN RgX_translate(GEN P, GEN c); GEN RgX_unscale(GEN P, GEN h); GEN RgXQ_matrix_pow(GEN y, long n, long m, GEN P); GEN RgXQ_norm(GEN x, GEN T); GEN RgXQ_pow(GEN x, GEN n, GEN T); GEN RgXQ_powers(GEN x, long l, GEN T); GEN RgXQ_powu(GEN x, ulong n, GEN T); GEN RgXQC_red(GEN P, GEN T); GEN RgXQM_mul(GEN P, GEN Q, GEN T); GEN RgXQM_red(GEN P, GEN T); GEN RgXQV_RgXQ_mul(GEN v, GEN x, GEN T); GEN RgXQV_red(GEN P, GEN T); GEN RgXQX_RgXQ_mul(GEN x, GEN y, GEN T); GEN RgXQX_divrem(GEN x,GEN y,GEN T,GEN *r); GEN RgXQX_mul(GEN x,GEN y,GEN T); GEN RgXQX_powers(GEN P, long n, GEN T); GEN RgXQX_pseudodivrem(GEN x, GEN y, GEN T, GEN *ptr); GEN RgXQX_pseudorem(GEN x, GEN y, GEN T); GEN RgXQX_red(GEN P, GEN T); GEN RgXQX_sqr(GEN x, GEN T); GEN RgXQX_translate(GEN P, GEN c, GEN T); GEN RgXV_RgV_eval(GEN Q, GEN x); GEN RgXV_to_RgM(GEN v, long n); GEN RgXV_unscale(GEN v, GEN h); GEN RgXX_to_RgM(GEN v, long n); long RgXY_degreex(GEN bpol); GEN RgXY_swap(GEN x, long n, long w); GEN RgXY_swapspec(GEN x, long n, long w, long nx); GEN RgXn_eval(GEN Q, GEN x, long n); GEN RgXn_exp(GEN f, long e); GEN RgXn_inv(GEN f, long e); GEN RgXn_inv_i(GEN f, long e); GEN RgXn_mul(GEN f, GEN g, long n); GEN RgXn_powers(GEN f, long m, long n); GEN RgXn_recip_shallow(GEN P, long n); GEN RgXn_red_shallow(GEN a, long n); GEN RgXn_reverse(GEN f, long e); GEN RgXn_sqr(GEN f, long n); GEN RgXn_sqrt(GEN f, long n); GEN RgXnV_red_shallow(GEN P, long n); GEN RgXn_powu(GEN x, ulong m, long n); GEN RgXn_powu_i(GEN x, ulong m, long n); GEN ZX_translate(GEN P, GEN c); GEN ZX_unscale2n(GEN P, long n); GEN ZX_unscale(GEN P, GEN h); GEN ZX_unscale_div(GEN P, GEN h); GEN ZX_z_unscale(GEN P, long h); int ZXQX_dvd(GEN x, GEN y, GEN T); long brent_kung_optpow(long d, long n, long m); GEN gen_bkeval(GEN Q, long d, GEN x, int use_sqr, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)); GEN gen_bkeval_powers(GEN P, long d, GEN V, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)); const struct bb_algebra * get_Rg_algebra(void); /* ZG.c */ void ZGC_G_mul_inplace(GEN v, GEN x); GEN ZGCs_add(GEN x, GEN y); GEN G_ZGC_mul(GEN x, GEN v); GEN G_ZG_mul(GEN x, GEN y); GEN ZGC_G_mul(GEN v, GEN x); GEN ZGC_Z_mul(GEN v, GEN x); GEN ZG_G_mul(GEN x, GEN y); GEN ZG_Z_mul(GEN x, GEN c); GEN ZG_add(GEN x, GEN y); GEN ZG_mul(GEN x, GEN y); GEN ZG_neg(GEN x); GEN ZG_normalize(GEN x); GEN ZG_sub(GEN x, GEN y); /* ZV.c */ void Flc_lincomb1_inplace(GEN X, GEN Y, ulong v, ulong q); GEN vecsmall_prod(GEN v); GEN QM_QC_mul(GEN x, GEN y); GEN QM_det(GEN x); GEN QM_ker(GEN M); GEN QM_mul(GEN x, GEN y); void RgM_check_ZM(GEN A, const char *s); void RgV_check_ZV(GEN A, const char *s); GEN Z_ZC_sub(GEN a, GEN x); GEN ZV_zc_mul(GEN x, GEN y); GEN ZC_Q_mul(GEN A, GEN z); GEN ZC_Z_add(GEN x, GEN y); GEN ZC_Z_div(GEN x, GEN c); GEN ZC_Z_divexact(GEN X, GEN c); GEN ZC_Z_mul(GEN X, GEN c); GEN ZC_Z_sub(GEN x, GEN y); GEN ZC_ZV_mul(GEN x, GEN y); GEN ZC_add(GEN x, GEN y); GEN ZC_copy(GEN x); GEN ZC_hnfremdiv(GEN x, GEN y, GEN *Q); long ZC_is_ei(GEN x); GEN ZC_lincomb(GEN u, GEN v, GEN X, GEN Y); void ZC_lincomb1_inplace(GEN X, GEN Y, GEN v); void ZC_lincomb1_inplace_i(GEN X, GEN Y, GEN v, long n); GEN ZC_neg(GEN M); GEN ZC_reducemodlll(GEN x,GEN y); GEN ZC_reducemodmatrix(GEN v, GEN y); GEN ZC_sub(GEN x, GEN y); GEN ZC_z_mul(GEN X, long c); GEN ZM_Q_mul(GEN A, GEN z); GEN ZM_ZC_mul(GEN x, GEN y); GEN ZM_Z_div(GEN X, GEN c); GEN ZM_Z_divexact(GEN X, GEN c); GEN ZM_Z_mul(GEN X, GEN c); GEN ZM_add(GEN x, GEN y); GEN ZM_copy(GEN x); GEN ZM_det_triangular(GEN mat); GEN ZM_diag_mul(GEN m, GEN d); int ZM_equal(GEN A, GEN B); int ZM_equal0(GEN A); GEN ZM_hnfdivrem(GEN x, GEN y, GEN *Q); int ZM_ishnf(GEN x); int ZM_isdiagonal(GEN x); int ZM_isidentity(GEN x); int ZM_isscalar(GEN x, GEN s); long ZM_max_lg(GEN x); GEN ZM_mul(GEN x, GEN y); GEN ZM_mul_diag(GEN m, GEN d); GEN ZM_multosym(GEN x, GEN y); GEN ZM_neg(GEN x); GEN ZM_nm_mul(GEN x, GEN y); GEN ZM_pow(GEN x, GEN n); GEN ZM_powu(GEN x, ulong n); GEN ZM_reducemodlll(GEN x,GEN y); GEN ZM_reducemodmatrix(GEN v, GEN y); GEN ZM_sqr(GEN x); GEN ZM_sub(GEN x, GEN y); GEN ZM_supnorm(GEN x); GEN ZM_to_Flm(GEN x, ulong p); GEN ZM_to_zm(GEN z); GEN ZM_transmul(GEN x, GEN y); GEN ZM_transmultosym(GEN x, GEN y); GEN ZMV_to_zmV(GEN z); void ZM_togglesign(GEN M); GEN ZM_zc_mul(GEN x, GEN y); GEN ZM_zm_mul(GEN x, GEN y); GEN ZMrow_ZC_mul(GEN x, GEN y, long i); GEN ZV_ZM_mul(GEN x, GEN y); int ZV_abscmp(GEN x, GEN y); int ZV_cmp(GEN x, GEN y); GEN ZV_content(GEN x); GEN ZV_dotproduct(GEN x,GEN y); GEN ZV_dotsquare(GEN x); int ZV_equal(GEN V, GEN W); int ZV_equal0(GEN V); long ZV_max_lg(GEN x); void ZV_neg_inplace(GEN M); GEN ZV_prod(GEN v); GEN ZV_sum(GEN v); GEN ZV_to_Flv(GEN x, ulong p); GEN ZV_to_nv(GEN z); void ZV_togglesign(GEN M); GEN gram_matrix(GEN M); GEN nm_Z_mul(GEN X, GEN c); GEN zm_mul(GEN x, GEN y); GEN zm_to_Flm(GEN z, ulong p); GEN zm_to_ZM(GEN z); GEN zm_zc_mul(GEN x, GEN y); GEN zmV_to_ZMV(GEN z); long zv_content(GEN x); long zv_dotproduct(GEN x, GEN y); int zv_equal(GEN V, GEN W); int zv_equal0(GEN V); GEN zv_neg(GEN x); GEN zv_neg_inplace(GEN M); long zv_prod(GEN v); GEN zv_prod_Z(GEN v); long zv_sum(GEN v); GEN zv_to_Flv(GEN z, ulong p); GEN zv_z_mul(GEN v, long n); GEN zv_ZM_mul(GEN x, GEN y); int zvV_equal(GEN V, GEN W); /* ZX.c */ GEN QX_ZX_rem(GEN x, GEN y); GEN QX_mul(GEN x, GEN y); GEN QX_sqr(GEN x); GEN QXQM_mul(GEN x, GEN y, GEN T); GEN QXQM_sqr(GEN x, GEN T); void RgX_check_QX(GEN x, const char *s); void RgX_check_ZX(GEN x, const char *s); void RgX_check_ZXX(GEN x, const char *s); GEN Z_ZX_sub(GEN x, GEN y); GEN ZX_Z_add(GEN y,GEN x); GEN ZX_Z_add_shallow(GEN y, GEN x); GEN ZX_Z_divexact(GEN y,GEN x); GEN ZX_Z_mul(GEN y,GEN x); GEN ZX_Z_sub(GEN y, GEN x); GEN ZX_add(GEN x, GEN y); GEN ZX_copy(GEN x); GEN ZX_deriv(GEN x); GEN ZX_div_by_X_1(GEN a, GEN *r); int ZX_equal(GEN V, GEN W); GEN ZX_eval1(GEN x); long ZX_max_lg(GEN x); GEN ZX_mod_Xnm1(GEN T, ulong n); GEN ZX_mul(GEN x, GEN y); GEN ZX_mulspec(GEN a, GEN b, long na, long nb); GEN ZX_mulu(GEN y, ulong x); GEN ZX_neg(GEN x); GEN ZX_rem(GEN x, GEN y); GEN ZX_remi2n(GEN y, long n); GEN ZX_rescale2n(GEN P, long n); GEN ZX_rescale(GEN P, GEN h); GEN ZX_rescale_lt(GEN P); GEN ZX_shifti(GEN x, long n); GEN ZX_sqr(GEN x); GEN ZX_sqrspec(GEN a, long na); GEN ZX_sub(GEN x, GEN y); long ZX_val(GEN x); long ZX_valrem(GEN x, GEN *Z); GEN ZXQM_mul(GEN x, GEN y, GEN T); GEN ZXQM_sqr(GEN x, GEN T); GEN ZXQX_sqr(GEN x, GEN T); GEN ZXQX_mul(GEN x, GEN y, GEN T); GEN ZXT_remi2n(GEN z, long n); GEN ZXV_Z_mul(GEN y, GEN x); GEN ZXV_dotproduct(GEN V, GEN W); int ZXV_equal(GEN V, GEN W); GEN ZXV_remi2n(GEN x, long n); GEN ZXX_Z_divexact(GEN y, GEN x); GEN ZXX_Z_mul(GEN y, GEN x); GEN ZXX_Z_add_shallow(GEN x, GEN y); long ZXX_max_lg(GEN x); GEN ZXX_renormalize(GEN x, long lx); GEN ZXX_to_Kronecker(GEN P, long n); GEN ZXX_to_Kronecker_spec(GEN P, long lP, long n); GEN ZXn_mul(GEN x, GEN y, long n); GEN ZXn_sqr(GEN x, long n); GEN scalar_ZX(GEN x, long v); GEN scalar_ZX_shallow(GEN x, long v); GEN zx_to_ZX(GEN z); /* algebras.c */ GEN alg_centralproj(GEN al, GEN z, long maps); GEN alg_complete(GEN rnf, GEN aut, GEN hi, GEN hf, long maxord); GEN alg_csa_table(GEN nf, GEN mt, long v, long maxord); GEN alg_cyclic(GEN rnf, GEN aut, GEN b, long maxord); long alg_get_absdim(GEN al); GEN alg_get_abssplitting(GEN al); GEN alg_get_aut(GEN al); GEN algaut(GEN al); GEN alg_get_auts(GEN al); GEN alg_get_b(GEN al); GEN algb(GEN al); GEN algcenter(GEN al); GEN alg_get_center(GEN al); GEN alg_get_char(GEN al); GEN algchar(GEN al); long alg_get_degree(GEN al); long algdegree(GEN al); long alg_get_dim(GEN al); long algdim(GEN al, long abs); GEN alg_get_hasse_f(GEN al); GEN alghassef(GEN al); GEN alg_get_hasse_i(GEN al); GEN alghassei(GEN al); GEN alg_get_invbasis(GEN al); GEN alginvbasis(GEN al); GEN alg_get_multable(GEN al); GEN alg_get_basis(GEN al); GEN algbasis(GEN al); GEN alg_get_relmultable(GEN al); GEN algrelmultable(GEN al); GEN alg_get_splitpol(GEN al); GEN alg_get_splittingfield(GEN al); GEN algsplittingfield(GEN al); GEN alg_get_splittingbasis(GEN al); GEN alg_get_splittingbasisinv(GEN al); GEN alg_get_splittingdata(GEN al); GEN algsplittingdata(GEN al); GEN alg_get_tracebasis(GEN al); GEN alg_hasse(GEN nf, long n, GEN hi, GEN hf, long var, long maxord); GEN alg_hilbert(GEN nf, GEN a, GEN b, long v, long maxord); GEN alg_matrix(GEN nf, long n, long v, GEN L, long maxord); long alg_model(GEN al, GEN x); GEN alg_quotient(GEN al, GEN I, long maps); GEN algradical(GEN al); GEN algsimpledec(GEN al, long maps); GEN algsimpledec_ss(GEN al, long maps); GEN algsubalg(GEN al, GEN basis); long alg_type(GEN al); GEN algadd(GEN al, GEN x, GEN y); GEN algalgtobasis(GEN al, GEN x); GEN algbasistoalg(GEN al, GEN x); GEN algcharpoly(GEN al, GEN x, long v, long abs); GEN algdisc(GEN al); GEN algdivl(GEN al, GEN x, GEN y); GEN algdivr(GEN al, GEN x, GEN y); GEN alggroup(GEN gal, GEN p); GEN alggroupcenter(GEN gal, GEN p, GEN* ptr_conjclasses); GEN alghasse(GEN al, GEN pl); GEN alginit(GEN A, GEN B, long v, long maxord); long algindex(GEN al, GEN pl); GEN alginv(GEN al, GEN x); int algisassociative(GEN mt0, GEN p); int algiscommutative(GEN al); int algisdivision(GEN al, GEN pl); int algisramified(GEN al, GEN pl); int algissemisimple(GEN al); int algissimple(GEN al, long ss); int algissplit(GEN al, GEN pl); int algisdivl(GEN al, GEN x, GEN y, GEN* ptz); int algisinv(GEN al, GEN x, GEN* ptix); GEN algmakeintegral(GEN mt0, long maps); GEN algmul(GEN al, GEN x, GEN y); GEN algmultable(GEN al); GEN alglat_get_primbasis(GEN lat); GEN alglat_get_scalar(GEN lat); GEN alglatadd(GEN al, GEN lat1, GEN lat2, GEN* ptinter); int alglatcontains(GEN al, GEN lat, GEN x, GEN* ptc); GEN alglatelement(GEN al, GEN lat, GEN c); GEN alglathnf(GEN al, GEN m, GEN d); GEN alglatindex(GEN al, GEN lat1, GEN lat2); GEN alglatinter(GEN al, GEN lat1, GEN lat2, GEN* ptsum); GEN alglatmul(GEN al, GEN lat1, GEN lat2); GEN alglatlefttransporter(GEN al, GEN lat1, GEN lat2); GEN alglatrighttransporter(GEN al, GEN lat1, GEN lat2); int alglatsubset(GEN al, GEN lat1, GEN lat2, GEN* ptindex); GEN algneg(GEN al, GEN x); GEN algnorm(GEN al, GEN x, long abs); GEN algpoleval(GEN al, GEN pol, GEN x); GEN algpow(GEN al, GEN x, GEN n); GEN algprimesubalg(GEN al); GEN algramifiedplaces(GEN al); GEN algrandom(GEN al, GEN b); GEN algsplit(GEN al, long v); GEN algtomatrix(GEN al, GEN x, long abs); GEN algsqr(GEN al, GEN x); GEN algsub(GEN al, GEN x, GEN y); GEN algtableinit(GEN mt, GEN p); GEN algtensor(GEN al1, GEN al2, long maxord); GEN algtrace(GEN al, GEN x, long abs); long algtype(GEN al); GEN bnfgwgeneric(GEN bnf, GEN Lpr, GEN Ld, GEN pl, long var); void checkalg(GEN x); void checkhasse(GEN nf, GEN hi, GEN hf, long n); void checklat(GEN al, GEN lat); GEN conjclasses_algcenter(GEN cc, GEN p); GEN galoischardet(GEN gal, GEN ch, long o); GEN galoischarpoly(GEN gal, GEN ch, long o); GEN galoischartable(GEN gal); GEN nfgrunwaldwang(GEN nf0, GEN Lpr, GEN Ld, GEN pl, long var); GEN nfgwkummer(GEN nf, GEN Lpr, GEN Ld, GEN pl, long var); /* alglin1.c */ GEN F2m_F2c_gauss(GEN a, GEN b); GEN F2m_F2c_invimage(GEN A, GEN y); GEN F2m_deplin(GEN x); ulong F2m_det(GEN x); ulong F2m_det_sp(GEN x); GEN F2m_gauss(GEN a, GEN b); GEN F2m_image(GEN x); GEN F2m_indexrank(GEN x); GEN F2m_inv(GEN x); GEN F2m_invimage(GEN A, GEN B); GEN F2m_ker(GEN x); GEN F2m_ker_sp(GEN x, long deplin); long F2m_rank(GEN x); GEN F2m_suppl(GEN x); GEN F2xqM_F2xqC_gauss(GEN a, GEN b, GEN T); GEN F2xqM_F2xqC_invimage(GEN a, GEN b, GEN T); GEN F2xqM_F2xqC_mul(GEN a, GEN b, GEN T); GEN F2xqM_deplin(GEN x, GEN T); GEN F2xqM_det(GEN a, GEN T); GEN F2xqM_gauss(GEN a, GEN b, GEN T); GEN F2xqM_ker(GEN x, GEN T); GEN F2xqM_image(GEN x, GEN T); GEN F2xqM_indexrank(GEN x, GEN T); GEN F2xqM_inv(GEN a, GEN T); GEN F2xqM_invimage(GEN a, GEN b, GEN T); GEN F2xqM_mul(GEN a, GEN b, GEN T); long F2xqM_rank(GEN x, GEN T); GEN F2xqM_suppl(GEN x, GEN T); GEN Flm_Flc_gauss(GEN a, GEN b, ulong p); GEN Flm_Flc_invimage(GEN mat, GEN y, ulong p); GEN Flm_adjoint(GEN A, ulong p); GEN Flm_deplin(GEN x, ulong p); ulong Flm_det(GEN x, ulong p); ulong Flm_det_sp(GEN x, ulong p); GEN Flm_gauss(GEN a, GEN b, ulong p); GEN Flm_image(GEN x, ulong p); GEN Flm_invimage(GEN m, GEN v, ulong p); GEN Flm_indexrank(GEN x, ulong p); GEN Flm_intersect(GEN x, GEN y, ulong p); GEN Flm_inv(GEN x, ulong p); GEN Flm_ker(GEN x, ulong p); GEN Flm_ker_sp(GEN x, ulong p, long deplin); long Flm_rank(GEN x, ulong p); GEN Flm_suppl(GEN x, ulong p); GEN FlxqM_FlxqC_gauss(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_FlxqC_invimage(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_FlxqC_mul(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_deplin(GEN x, GEN T, ulong p); GEN FlxqM_det(GEN a, GEN T, ulong p); GEN FlxqM_gauss(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_ker(GEN x, GEN T, ulong p); GEN FlxqM_image(GEN x, GEN T, ulong p); GEN FlxqM_indexrank(GEN x, GEN T, ulong p); GEN FlxqM_inv(GEN x, GEN T, ulong p); GEN FlxqM_invimage(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_mul(GEN a, GEN b, GEN T, ulong p); long FlxqM_rank(GEN x, GEN T, ulong p); GEN FlxqM_suppl(GEN x, GEN T, ulong p); GEN FpM_FpC_gauss(GEN a, GEN b, GEN p); GEN FpM_FpC_invimage(GEN m, GEN v, GEN p); GEN FpM_deplin(GEN x, GEN p); GEN FpM_det(GEN x, GEN p); GEN FpM_gauss(GEN a, GEN b, GEN p); GEN FpM_image(GEN x, GEN p); GEN FpM_indexrank(GEN x, GEN p); GEN FpM_intersect(GEN x, GEN y, GEN p); GEN FpM_inv(GEN x, GEN p); GEN FpM_invimage(GEN m, GEN v, GEN p); GEN FpM_ker(GEN x, GEN p); long FpM_rank(GEN x, GEN p); GEN FpM_suppl(GEN x, GEN p); GEN FqM_FqC_gauss(GEN a, GEN b, GEN T, GEN p); GEN FqM_FqC_invimage(GEN a, GEN b, GEN T, GEN p); GEN FqM_FqC_mul(GEN a, GEN b, GEN T, GEN p); GEN FqM_deplin(GEN x, GEN T, GEN p); GEN FqM_det(GEN x, GEN T, GEN p); GEN FqM_gauss(GEN a, GEN b, GEN T, GEN p); GEN FqM_ker(GEN x, GEN T, GEN p); GEN FqM_image(GEN x, GEN T, GEN p); GEN FqM_indexrank(GEN x, GEN T, GEN p); GEN FqM_inv(GEN x, GEN T, GEN p); GEN FqM_invimage(GEN a, GEN b, GEN T, GEN p); GEN FqM_mul(GEN a, GEN b, GEN T, GEN p); long FqM_rank(GEN a, GEN T, GEN p); GEN FqM_suppl(GEN x, GEN T, GEN p); GEN QM_gauss(GEN a, GEN b); GEN QM_indexrank(GEN x); GEN QM_inv(GEN M); long QM_rank(GEN x); GEN RgM_Fp_init(GEN a, GEN p, ulong *pp); GEN RgM_Hadamard(GEN a); GEN RgM_RgC_invimage(GEN A, GEN B); GEN RgM_diagonal(GEN m); GEN RgM_diagonal_shallow(GEN m); GEN RgM_inv(GEN a); GEN RgM_inv_upper(GEN a); GEN RgM_invimage(GEN A, GEN B); GEN RgM_solve(GEN a, GEN b); GEN RgM_solve_realimag(GEN x, GEN y); void RgMs_structelim(GEN M, long nbrow, GEN A, GEN *p_col, GEN *p_lin); GEN ZM_det(GEN a); GEN ZM_detmult(GEN A); GEN ZM_gauss(GEN a, GEN b); GEN ZM_ker(GEN M); GEN ZM_imagecompl(GEN x); GEN ZM_indeximage(GEN x); GEN ZM_indexrank(GEN x); GEN ZM_inv(GEN M, GEN *den); GEN ZM_inv_ratlift(GEN M, GEN *pden); GEN ZM_pseudoinv(GEN M, GEN *pv, GEN *den); long ZM_rank(GEN x); GEN ZlM_gauss(GEN a, GEN b, ulong p, long e, GEN C); GEN closemodinvertible(GEN x, GEN y); GEN deplin(GEN x); GEN det(GEN a); GEN det0(GEN a,long flag); GEN det2(GEN a); GEN detint(GEN x); GEN eigen(GEN x, long prec); GEN gauss(GEN a, GEN b); GEN gaussmodulo(GEN M, GEN D, GEN Y); GEN gaussmodulo2(GEN M, GEN D, GEN Y); GEN gen_Gauss(GEN a, GEN b, void *E, const struct bb_field *ff); GEN gen_Gauss_pivot(GEN x, long *rr, void *E, const struct bb_field *ff); GEN gen_det(GEN a, void *E, const struct bb_field *ff); GEN gen_ker(GEN x, long deplin, void *E, const struct bb_field *ff); GEN gen_matcolinvimage(GEN a, GEN b, void *E, const struct bb_field *ff); GEN gen_matcolmul(GEN a, GEN b, void *E, const struct bb_field *ff); GEN gen_matinvimage(GEN a, GEN b, void *E, const struct bb_field *ff); GEN gen_matmul(GEN a, GEN b, void *E, const struct bb_field *ff); GEN image(GEN x); GEN image2(GEN x); GEN imagecompl(GEN x); GEN indexrank(GEN x); GEN inverseimage(GEN mat, GEN y); GEN ker(GEN x); GEN mateigen(GEN x, long flag, long prec); GEN matimage0(GEN x,long flag); GEN matker0(GEN x, long flag); long rank(GEN x); GEN reducemodinvertible(GEN x, GEN y); GEN reducemodlll(GEN x,GEN y); GEN split_realimag(GEN x, long r1, long r2); GEN suppl(GEN x); /* alglin2.c */ GEN Flm_charpoly(GEN x, ulong p); GEN Flm_hess(GEN x, ulong p); GEN FpM_charpoly(GEN x, GEN p); GEN FpM_hess(GEN x, GEN p); GEN Frobeniusform(GEN V, long n); GEN QM_minors_coprime(GEN x, GEN pp); GEN QM_ImZ_hnf(GEN x); GEN QM_ImZ_hnfall(GEN x, GEN *U, long remove); GEN QM_ImQ_hnf(GEN x); GEN QM_ImQ_hnfall(GEN x, GEN *U, long remove); GEN QM_charpoly_ZX(GEN M); GEN QM_charpoly_ZX_bound(GEN M, long bit); GEN ZM_charpoly(GEN x); GEN adj(GEN x); GEN adjsafe(GEN x); GEN caract(GEN x, long v); GEN caradj(GEN x, long v, GEN *py); GEN carberkowitz(GEN x, long v); GEN carhess(GEN x, long v); GEN charpoly(GEN x, long v); GEN charpoly0(GEN x, long v,long flag); GEN gnorm(GEN x); GEN gnorml1(GEN x,long prec); GEN gnorml1_fake(GEN x); GEN gnormlp(GEN x, GEN p, long prec); GEN gnorml2(GEN x); GEN gsupnorm(GEN x, long prec); void gsupnorm_aux(GEN x, GEN *m, GEN *msq, long prec); GEN gtrace(GEN x); GEN hess(GEN x); GEN intersect(GEN x, GEN y); GEN jacobi(GEN a, long prec); GEN matadjoint0(GEN x, long flag); GEN matcompanion(GEN x); GEN matrixqz0(GEN x, GEN pp); GEN minpoly(GEN x, long v); GEN qfgaussred(GEN a); GEN qfgaussred_positive(GEN a); GEN qfsign(GEN a); /* alglin3.c */ GEN apply0(GEN f, GEN A); GEN diagonal(GEN x); GEN diagonal_shallow(GEN x); GEN extract0(GEN x, GEN l1, GEN l2); GEN fold0(GEN f, GEN A); GEN genapply(void *E, GEN (*f)(void *E, GEN x), GEN A); GEN genfold(void *E, GEN (*f)(void *E, GEN x, GEN y), GEN A); GEN genindexselect(void *E, long (*f)(void *E, GEN x), GEN A); GEN genselect(void *E, long (*f)(void *E, GEN x), GEN A); GEN gtomat(GEN x); GEN gtrans(GEN x); GEN matmuldiagonal(GEN x, GEN d); GEN matmultodiagonal(GEN x, GEN y); GEN matslice0(GEN A, long x1, long x2, long y1, long y2); GEN parapply(GEN V, GEN C); void parfor(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN)); void parforprime(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN)); void parforvec(GEN x, GEN code, long flag, void *E, long call(void*, GEN, GEN)); GEN parselect(GEN C, GEN D, long flag); GEN select0(GEN A, GEN f, long flag); GEN shallowextract(GEN x, GEN L); GEN shallowmatextract(GEN x, GEN l1, GEN l2); GEN shallowtrans(GEN x); GEN vecapply(void *E, GEN (*f)(void* E, GEN x), GEN x); GEN veccatapply(void *E, GEN (*f)(void* E, GEN x), GEN x); GEN veccatselapply(void *Epred, long (*pred)(void* E, GEN x), void *Efun, GEN (*fun)(void* E, GEN x), GEN A); GEN vecrange(GEN a, GEN b); GEN vecrangess(long a, long b); GEN vecselapply(void *Epred, long (*pred)(void* E, GEN x), void *Efun, GEN (*fun)(void* E, GEN x), GEN A); GEN vecselect(void *E, long (*f)(void* E, GEN x), GEN A); GEN vecslice0(GEN A, long y1, long y2); GEN vecsum(GEN v); /* anal.c */ void addhelp(const char *e, char *s); void alias0(const char *s, const char *old); GEN compile_str(const char *s); GEN chartoGENstr(char c); long delete_var(void); long fetch_user_var(const char *s); long fetch_var(void); long fetch_var_higher(void); GEN fetch_var_value(long vx, GEN t); char * gp_embedded(const char *s); void gp_embedded_init(long rsize, long vsize); GEN gp_read_str(const char *t); entree* install(void *f, const char *name, const char *code); entree* is_entry(const char *s); void kill0(const char *e); void pari_var_close(void); void pari_var_init(void); long pari_var_next(void); long pari_var_next_temp(void); long pari_var_create(entree *ep); void name_var(long n, const char *s); GEN readseq(char *t); GEN* safegel(GEN x, long l); long* safeel(GEN x, long l); GEN* safelistel(GEN x, long l); GEN* safegcoeff(GEN x, long a, long b); GEN strntoGENstr(const char *s, long n0); GEN strtoGENstr(const char *s); GEN strtoi(const char *s); GEN strtor(const char *s, long prec); GEN type0(GEN x); GEN varhigher(const char *s, long v); GEN varlower(const char *s, long v); /* aprcl.c */ GEN divisorslenstra(GEN N, GEN r, GEN s); long isprimeAPRCL(GEN N); /* Qfb.c */ GEN Qfb0(GEN x, GEN y, GEN z, GEN d, long prec); void check_quaddisc(GEN x, long *s, long *r, const char *f); void check_quaddisc_imag(GEN x, long *r, const char *f); void check_quaddisc_real(GEN x, long *r, const char *f); long cornacchia(GEN d, GEN p, GEN *px, GEN *py); long cornacchia2(GEN d, GEN p, GEN *px, GEN *py); long cornacchia2_sqrt(GEN d, GEN p, GEN b, GEN *px, GEN *py); GEN nucomp(GEN x, GEN y, GEN L); GEN nudupl(GEN x, GEN L); GEN nupow(GEN x, GEN n, GEN L); GEN primeform(GEN x, GEN p, long prec); GEN primeform_u(GEN x, ulong p); int qfb_equal1(GEN f); GEN qfbcompraw(GEN x, GEN y); GEN qfbpowraw(GEN x, long n); GEN qfbred0(GEN x, long flag, GEN D, GEN isqrtD, GEN sqrtD); GEN qfbredsl2(GEN q, GEN S); GEN qfbsolve(GEN Q, GEN n); GEN qfi(GEN x, GEN y, GEN z); GEN qfi_1(GEN x); GEN qfi_Shanks(GEN a, GEN g, long n); GEN qfi_log(GEN a, GEN g, GEN o); GEN qfi_order(GEN q, GEN o); GEN qficomp(GEN x, GEN y); GEN qficompraw(GEN x, GEN y); GEN qfipowraw(GEN x, long n); GEN qfisolvep(GEN Q, GEN p); GEN qfisqr(GEN x); GEN qfisqrraw(GEN x); GEN qfr(GEN x, GEN y, GEN z, GEN d); GEN qfr3_comp(GEN x, GEN y, struct qfr_data *S); GEN qfr3_pow(GEN x, GEN n, struct qfr_data *S); GEN qfr3_red(GEN x, struct qfr_data *S); GEN qfr3_rho(GEN x, struct qfr_data *S); GEN qfr3_to_qfr(GEN x, GEN z); GEN qfr5_comp(GEN x, GEN y, struct qfr_data *S); GEN qfr5_dist(GEN e, GEN d, long prec); GEN qfr5_pow(GEN x, GEN n, struct qfr_data *S); GEN qfr5_red(GEN x, struct qfr_data *S); GEN qfr5_rho(GEN x, struct qfr_data *S); GEN qfr5_to_qfr(GEN x, GEN d0); GEN qfr_1(GEN x); void qfr_data_init(GEN D, long prec, struct qfr_data *S); GEN qfr_to_qfr5(GEN x, long prec); GEN qfrcomp(GEN x, GEN y); GEN qfrcompraw(GEN x, GEN y); GEN qfrpow(GEN x, GEN n); GEN qfrpowraw(GEN x, long n); GEN qfrsolvep(GEN Q, GEN p); GEN qfrsqr(GEN x); GEN qfrsqrraw(GEN x); GEN quadgen(GEN x); GEN quadgen0(GEN x, long v); GEN quadpoly(GEN x); GEN quadpoly0(GEN x, long v); GEN redimag(GEN x); GEN redreal(GEN x); GEN redrealnod(GEN x, GEN isqrtD); GEN rhoreal(GEN x); GEN rhorealnod(GEN x, GEN isqrtD); /* arith1.c */ ulong Fl_2gener_pre(ulong p, ulong pi); ulong Fl_log(ulong a, ulong g, ulong ord, ulong p); ulong Fl_log_pre(ulong a, ulong g, ulong ord, ulong p, ulong pi); ulong Fl_order(ulong a, ulong o, ulong p); GEN Fl_powers(ulong x, long n, ulong p); GEN Fl_powers_pre(ulong x, long n, ulong p, ulong pi); ulong Fl_powu(ulong x, ulong n, ulong p); ulong Fl_powu_pre(ulong x, ulong n, ulong p, ulong pi); ulong Fl_sqrt(ulong a, ulong p); ulong Fl_sqrt_pre(ulong a, ulong p, ulong pi); ulong Fl_sqrt_pre_i(ulong a, ulong s2, ulong p, ulong pi); ulong Fl_sqrtl(ulong a, ulong l, ulong p); ulong Fl_sqrtl_pre(ulong a, ulong l, ulong p, ulong pi); ulong Fl_sqrtn(ulong a, long n, ulong p, ulong *zetan); ulong Fl_sqrtn_pre(ulong a, long n, ulong p, ulong pi, ulong *zetan); GEN Fp_2gener(GEN p); GEN Fp_factored_order(GEN a, GEN o, GEN p); int Fp_ispower(GEN x, GEN K, GEN p); GEN Fp_log(GEN a, GEN g, GEN ord, GEN p); GEN Fp_order(GEN a, GEN o, GEN p); GEN Fp_pow(GEN a, GEN n, GEN m); GEN Fp_pow_init(GEN x, GEN n, long k, GEN p); GEN Fp_pow_table(GEN R, GEN n, GEN p); GEN Fp_powers(GEN x, long n, GEN p); GEN Fp_pows(GEN A, long k, GEN N); GEN Fp_powu(GEN x, ulong k, GEN p); GEN Fp_sqrt(GEN a, GEN p); GEN Fp_sqrt_i(GEN a, GEN y, GEN p); GEN Fp_sqrtn(GEN a, GEN n, GEN p, GEN *zetan); GEN Z_ZV_mod(GEN P, GEN xa); GEN Z_ZV_mod_tree(GEN P, GEN xa, GEN T); GEN Z_chinese(GEN a, GEN b, GEN A, GEN B); GEN Z_chinese_all(GEN a, GEN b, GEN A, GEN B, GEN *pC); GEN Z_chinese_coprime(GEN a, GEN b, GEN A, GEN B, GEN C); GEN Z_chinese_post(GEN a, GEN b, GEN C, GEN U, GEN d); void Z_chinese_pre(GEN A, GEN B, GEN *pC, GEN *pU, GEN *pd); GEN Z_factor_listP(GEN N, GEN L); long Z_isanypower(GEN x, GEN *y); long Z_isfundamental(GEN x); long Z_ispow2(GEN x); long Z_ispowerall(GEN x, ulong k, GEN *pt); long Z_issquareall(GEN x, GEN *pt); GEN Z_nv_mod(GEN P, GEN xa); GEN ZM_nv_mod_tree(GEN M, GEN xa, GEN T); GEN ZV_allpnqn(GEN x); GEN ZV_chinese(GEN A, GEN P, GEN *pt_mod); GEN ZV_chinese_tree(GEN A, GEN P, GEN T, GEN R); GEN ZV_chinesetree(GEN P, GEN T); GEN ZV_nv_mod_tree(GEN V, GEN xa, GEN T); GEN ZV_producttree(GEN xa); GEN ZX_nv_mod_tree(GEN P, GEN xa, GEN T); GEN ZXC_nv_mod_tree(GEN P, GEN xa, GEN T, long w); GEN ZXM_nv_mod_tree(GEN M, GEN xa, GEN T, long w); GEN ZXX_nv_mod_tree(GEN P, GEN xa, GEN T, long w); GEN Zideallog(GEN bid, GEN x); long Zp_issquare(GEN a, GEN p); GEN bestappr(GEN x, GEN k); GEN bestapprPade(GEN x, long B); long cgcd(long a,long b); GEN chinese(GEN x, GEN y); GEN chinese1(GEN x); GEN chinese1_coprime_Z(GEN x); GEN classno(GEN x); GEN classno2(GEN x); long clcm(long a,long b); GEN contfrac0(GEN x, GEN b, long flag); GEN contfracpnqn(GEN x, long n); GEN fibo(long n); GEN gboundcf(GEN x, long k); GEN gcf(GEN x); GEN gcf2(GEN b, GEN x); const struct bb_field *get_Fp_field(void **E, GEN p); long gisanypower(GEN x, GEN *pty); GEN gissquare(GEN x); GEN gissquareall(GEN x, GEN *pt); GEN hclassno(GEN x); GEN hclassno6(GEN x); long hilbert(GEN x, GEN y, GEN p); long hilbertii(GEN x, GEN y, GEN p); long isfundamental(GEN x); long ispolygonal(GEN x, GEN S, GEN *N); long ispower(GEN x, GEN k, GEN *pty); long isprimepower(GEN x, GEN *pty); long ispseudoprimepower(GEN n, GEN *pt); long issquare(GEN x); long issquareall(GEN x, GEN *pt); long krois(GEN x, long y); long kroiu(GEN x, ulong y); long kronecker(GEN x, GEN y); long krosi(long s, GEN x); long kross(long x, long y); long kroui(ulong x, GEN y); long krouu(ulong x, ulong y); GEN lcmii(GEN a, GEN b); GEN Fp_invgen(GEN x, GEN N, GEN *pd); long logint0(GEN B, GEN y, GEN *ptq); long logintall(GEN B, GEN y, GEN *ptq); GEN mpfact(long n); GEN muls_interval(long a, long b); GEN mulu_interval(ulong a, ulong b); GEN ncV_chinese_center(GEN A, GEN P, GEN *pt_mod); GEN nmV_chinese_center(GEN A, GEN P, GEN *pt_mod); GEN nmV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R); GEN nxCV_chinese_center(GEN A, GEN P, GEN *pt_mod); GEN nxMV_chinese_center(GEN A, GEN P, GEN *pt_mod); GEN nxV_chinese_center(GEN A, GEN P, GEN *pt_mod); GEN nxV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R); GEN ZV_chinese_center(GEN A, GEN P, GEN *pt_mod); GEN odd_prime_divisors(GEN q); GEN order(GEN x); ulong pgener_Fl(ulong p); ulong pgener_Fl_local(ulong p, GEN L); GEN pgener_Fp(GEN p); GEN pgener_Fp_local(GEN p, GEN L); ulong pgener_Zl(ulong p); GEN pgener_Zp(GEN p); GEN pnqn(GEN x); GEN qfbclassno0(GEN x,long flag); GEN quadclassno(GEN x); GEN quaddisc(GEN x); GEN quadregulator(GEN x, long prec); GEN quadunit(GEN x); GEN quadunit0(GEN x, long v); GEN ramanujantau(GEN n); ulong rootsof1_Fl(ulong n, ulong p); GEN rootsof1_Fp(GEN n, GEN p); GEN rootsof1u_Fp(ulong n, GEN p); long sisfundamental(long x); GEN sqrtint(GEN a); ulong u_chinese_coprime(ulong a, ulong b, ulong A, ulong B, ulong C); ulong ugcd(ulong a,ulong b); ulong ulcm(ulong a, ulong b); long uisprimepower(ulong n, ulong *p); long uissquare(ulong A); long uissquareall(ulong A, ulong *sqrtA); long ulogintall(ulong B, ulong y, ulong *ptq); long unegisfundamental(ulong x); long uposisfundamental(ulong x); GEN znlog(GEN x, GEN g, GEN o); GEN znorder(GEN x, GEN o); GEN znprimroot(GEN m); GEN znstar(GEN x); GEN znstar0(GEN N, long flag); /* arith2.c */ int RgV_is_ZVpos(GEN v); int RgV_is_ZVnon0(GEN v); GEN Z_smoothen(GEN N, GEN L, GEN *pP, GEN *pe); GEN boundfact(GEN n, ulong lim); GEN check_arith_pos(GEN n, const char *f); GEN check_arith_non0(GEN n, const char *f); GEN check_arith_all(GEN n, const char *f); GEN clean_Z_factor(GEN f); GEN corepartial(GEN n, long l); GEN core0(GEN n,long flag); GEN core2(GEN n); GEN core2partial(GEN n, long l); GEN coredisc(GEN n); GEN coredisc0(GEN n,long flag); GEN coredisc2(GEN n); long corediscs(long D, ulong *f); GEN digits(GEN N, GEN B); GEN divisors(GEN n); GEN divisors_factored(GEN N); GEN divisors0(GEN N, long flag); GEN divisorsu(ulong n); GEN divisorsu_fact(GEN fa); GEN factor_pn_1(GEN p, ulong n); GEN factor_pn_1_limit(GEN p, long n, ulong lim); GEN factoru_pow(ulong n); GEN fromdigits(GEN x, GEN B); GEN fromdigitsu(GEN x, GEN B); GEN fuse_Z_factor(GEN f, GEN B); GEN gen_digits(GEN x, GEN B, long n, void *E, struct bb_ring *r, GEN (*div)(void *E, GEN x, GEN y, GEN *r)); GEN gen_fromdigits(GEN x, GEN B, void *E, struct bb_ring *r); int is_Z_factor(GEN f); int is_Z_factornon0(GEN f); int is_Z_factorpos(GEN f); int is_nf_factor(GEN F); int is_nf_extfactor(GEN F); GEN sumdigits(GEN n); GEN sumdigits0(GEN n, GEN B); ulong sumdigitsu(ulong n); GEN usumdiv_fact(GEN f); GEN usumdivk_fact(GEN f, ulong k); /* base1.c */ GEN FpX_FpC_nfpoleval(GEN nf, GEN pol, GEN a, GEN p); GEN embed_T2(GEN x, long r1); GEN embednorm_T2(GEN x, long r1); GEN embed_norm(GEN x, long r1); void check_ZKmodule(GEN x, const char *s); void checkbid(GEN bid); GEN checkbid_i(GEN bid); GEN checkbnf(GEN bnf); GEN checkbnf_i(GEN bnf); void checkbnr(GEN bnr); void checkbnrgen(GEN bnr); void checkabgrp(GEN v); void checksqmat(GEN x, long N); GEN checknf(GEN nf); GEN checknf_i(GEN nf); GEN checknfelt_mod(GEN nf, GEN x, const char *s); void checkprid(GEN bid); int checkprid_i(GEN x); void checkrnf(GEN rnf); int checkrnf_i(GEN rnf); GEN factoredpolred(GEN x, GEN fa); GEN factoredpolred2(GEN x, GEN fa); GEN galoisapply(GEN nf, GEN aut, GEN x); GEN get_bnf(GEN x, long *t); GEN get_bnfpol(GEN x, GEN *bnf, GEN *nf); GEN get_nf(GEN x, long *t); GEN get_nfpol(GEN x, GEN *nf); GEN get_prid(GEN x); GEN idealfrobenius(GEN nf, GEN gal, GEN pr); GEN idealfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN aut); GEN idealramfrobenius(GEN nf, GEN gal, GEN pr, GEN ram); GEN idealramfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN ram, GEN aut); GEN idealramgroups(GEN nf, GEN gal, GEN pr); GEN idealramgroups_aut(GEN nf, GEN gal, GEN pr, GEN aut); GEN nf_get_allroots(GEN nf); long nf_get_prec(GEN x); GEN nfmaxord_to_nf(nfmaxord_t *T, GEN ro, long prec); GEN nfcertify(GEN x); GEN nfgaloismatrix(GEN nf, GEN s); GEN nfgaloispermtobasis(GEN nf, GEN gal); void nfinit_basic(nfmaxord_t *T, GEN x); GEN nfinit_complete(nfmaxord_t *T, long flag, long prec); GEN nfinit(GEN x, long prec); GEN nfinit0(GEN x, long flag, long prec); GEN nfinitall(GEN x, long flag, long prec); GEN nfinitred(GEN x, long prec); GEN nfinitred2(GEN x, long prec); GEN nfisincl(GEN a, GEN b); GEN nfisisom(GEN a, GEN b); GEN nfnewprec(GEN nf, long prec); GEN nfnewprec_shallow(GEN nf, long prec); GEN nfpoleval(GEN nf, GEN pol, GEN a); long nftyp(GEN x); GEN polredord(GEN x); GEN polred(GEN x); GEN polred0(GEN x, long flag, GEN fa); GEN polred2(GEN x); GEN polredabs(GEN x); GEN polredabs0(GEN x, long flag); GEN polredabs2(GEN x); GEN polredabsall(GEN x, long flun); GEN polredbest(GEN x, long flag); GEN rnfpolredabs(GEN nf, GEN pol, long flag); GEN rnfpolredbest(GEN nf, GEN relpol, long flag); GEN smallpolred(GEN x); GEN smallpolred2(GEN x); GEN tschirnhaus(GEN x); GEN ZX_Q_mul(GEN A, GEN z); GEN ZX_Q_normalize(GEN pol, GEN *ptlc); GEN ZX_Z_normalize(GEN pol, GEN *ptk); GEN ZX_to_monic(GEN pol, GEN *lead); GEN ZX_primitive_to_monic(GEN pol, GEN *lead); /* base2.c */ GEN Fq_to_nf(GEN x, GEN modpr); GEN FqM_to_nfM(GEN z, GEN modpr); GEN FqV_to_nfV(GEN z, GEN modpr); GEN FqX_to_nfX(GEN x, GEN modpr); GEN Rg_nffix(const char *f, GEN T, GEN c, int lift); GEN RgV_nffix(const char *f, GEN T, GEN P, int lift); GEN RgX_nffix(const char *s, GEN nf, GEN x, int lift); long ZpX_disc_val(GEN f, GEN p); GEN ZpX_gcd(GEN f1,GEN f2,GEN p, GEN pm); GEN ZpX_monic_factor(GEN f, GEN p, long prec); GEN ZpX_primedec(GEN T, GEN p); GEN ZpX_reduced_resultant(GEN x, GEN y, GEN p, GEN pm); GEN ZpX_reduced_resultant_fast(GEN f, GEN g, GEN p, long M); long ZpX_resultant_val(GEN f, GEN g, GEN p, long M); void checkmodpr(GEN modpr); GEN ZX_compositum_disjoint(GEN A, GEN B); GEN compositum(GEN P, GEN Q); GEN compositum2(GEN P, GEN Q); GEN nfdisc(GEN x); GEN get_modpr(GEN x); GEN indexpartial(GEN P, GEN DP); GEN modpr_genFq(GEN modpr); GEN nf_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p); GEN nf_to_Fq(GEN nf, GEN x, GEN modpr); GEN nfM_to_FqM(GEN z, GEN nf,GEN modpr); GEN nfV_to_FqV(GEN z, GEN nf,GEN modpr); GEN nfX_to_FqX(GEN x, GEN nf,GEN modpr); GEN nfbasis(GEN x, GEN *y,GEN p); GEN nfcompositum(GEN nf, GEN A, GEN B, long flag); void nfmaxord(nfmaxord_t *S, GEN T, long flag); GEN nfmodpr(GEN nf, GEN x, GEN pr); GEN nfmodprinit(GEN nf, GEN pr); GEN nfmodprlift(GEN nf, GEN x, GEN pr); GEN nfreducemodpr(GEN nf, GEN x, GEN modpr); GEN nfsplitting(GEN T, GEN D); GEN polcompositum0(GEN P, GEN Q,long flag); GEN idealprimedec(GEN nf,GEN p); GEN idealprimedec_galois(GEN nf, GEN p); GEN idealprimedec_degrees(GEN nf, GEN p); GEN idealprimedec_kummer(GEN nf,GEN pol,long e,GEN p); GEN idealprimedec_limit_f(GEN nf, GEN p, long f); GEN idealprimedec_limit_norm(GEN nf, GEN p, GEN B); GEN poldiscfactors(GEN T, long flag); GEN rnfbasis(GEN bnf, GEN order); GEN rnfdedekind(GEN nf, GEN T, GEN pr, long flag); GEN rnfdet(GEN nf, GEN order); GEN rnfdisc_factored(GEN nf, GEN pol, GEN *pd); GEN rnfdiscf(GEN nf, GEN pol); GEN rnfequation(GEN nf, GEN pol); GEN rnfequation0(GEN nf, GEN pol, long flall); GEN rnfequation2(GEN nf, GEN pol); GEN nf_pV_to_prV(GEN nf, GEN P); GEN nf_rnfeq(GEN nf, GEN relpol); GEN nf_rnfeq_partial(GEN nf, GEN R); GEN nf_rnfeqsimple(GEN nf, GEN relpol); GEN rnfequationall(GEN A, GEN B, long *pk, GEN *pLPRS); GEN rnfhnfbasis(GEN bnf, GEN order); long rnfisfree(GEN bnf, GEN order); GEN rnflllgram(GEN nf, GEN pol, GEN order,long prec); GEN rnfpolred(GEN nf, GEN pol, long prec); GEN rnfpseudobasis(GEN nf, GEN pol); GEN rnfsimplifybasis(GEN bnf, GEN order); GEN rnfsteinitz(GEN nf, GEN order); long factorial_lval(ulong n, ulong p); GEN zk_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p); GEN zk_to_Fq(GEN x, GEN modpr); GEN QXQV_to_FpM(GEN basis, GEN T, GEN p); GEN zkmodprinit(GEN nf, GEN pr); /* base3.c */ GEN Idealstar(GEN nf, GEN x,long flun); GEN Idealstarprk(GEN nf, GEN pr, long k, long flag); GEN RgC_to_nfC(GEN nf,GEN x); GEN RgM_RgX_mul(GEN A, GEN x); GEN RgM_to_nfM(GEN nf,GEN x); GEN RgX_to_nfX(GEN nf,GEN pol); long ZC_nfval(GEN x, GEN P); long ZC_nfvalrem(GEN x, GEN P, GEN *t); int ZC_prdvd(GEN x, GEN P); GEN ZM_ZX_mul(GEN A, GEN x); GEN algtobasis(GEN nf, GEN x); GEN basistoalg(GEN nf, GEN x); GEN ei_multable(GEN nf, long i); const struct bb_field *get_nf_field(void **E, GEN nf); GEN gpnfvalrem(GEN nf, GEN x, GEN pr, GEN *py); GEN ideallist(GEN nf,long bound); GEN ideallist0(GEN nf,long bound, long flag); GEN ideallistarch(GEN nf, GEN list, GEN arch); GEN ideallog(GEN nf,GEN x,GEN bigideal); GEN idealprincipalunits(GEN nf, GEN pr, long e); GEN idealstar0(GEN nf, GEN x,long flag); GEN indices_to_vec01(GEN archp, long r); GEN matalgtobasis(GEN nf, GEN x); GEN matbasistoalg(GEN nf, GEN x); GEN multable(GEN nf, GEN x); GEN nf_to_scalar_or_alg(GEN nf, GEN x); GEN nf_to_scalar_or_basis(GEN nf, GEN x); GEN nfadd(GEN nf, GEN x, GEN y); int nfchecksigns(GEN nf, GEN x, GEN pl); GEN nfdiv(GEN nf, GEN x, GEN y); GEN nfdiveuc(GEN nf, GEN a, GEN b); GEN nfdivrem(GEN nf, GEN a, GEN b); GEN nfembed(GEN nf, GEN x, long k); GEN nfeltembed(GEN nf, GEN x, GEN ind0, long prec); GEN nfeltsign(GEN nf, GEN x, GEN ind0); GEN nfinv(GEN nf, GEN x); GEN nfinvmodideal(GEN nf, GEN x, GEN ideal); GEN nfM_det(GEN nf, GEN M); GEN nfM_inv(GEN nf, GEN M); GEN nfM_mul(GEN nf, GEN A, GEN B); GEN nfM_nfC_mul(GEN nf, GEN A, GEN B); GEN nfmod(GEN nf, GEN a, GEN b); GEN nfmul(GEN nf,GEN x,GEN y); GEN nfmuli(GEN nf,GEN x,GEN y); GEN nfnorm(GEN nf, GEN x); GEN nfpolsturm(GEN nf, GEN f, GEN ind0); GEN nfpow(GEN nf,GEN x,GEN k); GEN nfpow_u(GEN nf, GEN z, ulong n); GEN nfpowmodideal(GEN nf,GEN x,GEN k,GEN ideal); GEN nfsign(GEN nf,GEN alpha); GEN nfsign_arch(GEN nf,GEN alpha,GEN arch); GEN nfsign_from_logarch(GEN Larch, GEN invpi, GEN archp); GEN nfsqr(GEN nf,GEN x); GEN nfsqri(GEN nf, GEN x); GEN nfsub(GEN nf, GEN x, GEN y); GEN nftrace(GEN nf, GEN x); long nfval(GEN nf, GEN x, GEN vp); long nfvalrem(GEN nf, GEN x, GEN pr, GEN *py); GEN polmod_nffix(const char *f, GEN rnf, GEN x,int lift); GEN polmod_nffix2(const char *f, GEN T, GEN relpol, GEN x, int lift); GEN pr_basis_perm(GEN nf, GEN pr); int pr_equal(GEN P, GEN Q); GEN rnfalgtobasis(GEN rnf, GEN x); GEN rnfbasistoalg(GEN rnf, GEN x); GEN rnfeltnorm(GEN rnf, GEN x); GEN rnfelttrace(GEN rnf, GEN x); GEN set_sign_mod_divisor(GEN nf, GEN x, GEN y, GEN sarch); GEN tablemul(GEN TAB, GEN x, GEN y); GEN tablemul_ei(GEN M, GEN x, long i); GEN tablemul_ei_ej(GEN M, long i, long j); GEN tablemulvec(GEN M, GEN x, GEN v); GEN tablesqr(GEN tab, GEN x); GEN vec01_to_indices(GEN arch); GEN vecmodii(GEN a, GEN b); GEN vecmoduu(GEN a, GEN b); GEN vecsmall01_to_indices(GEN v); GEN zk_inv(GEN nf, GEN x); GEN zk_multable(GEN nf, GEN x); GEN zk_scalar_or_multable(GEN, GEN x); GEN zkchinese(GEN zkc, GEN x, GEN y); GEN zkchinese1(GEN zkc, GEN x); GEN zkchineseinit(GEN nf, GEN A, GEN B, GEN AB); GEN zkmultable_capZ(GEN mx); GEN zkmultable_inv(GEN mx); /* base4.c */ GEN Z_cba(GEN a, GEN b); GEN Z_ppgle(GEN a, GEN b); GEN Z_ppio(GEN a, GEN b); GEN Z_ppo(GEN x, GEN f); GEN ZV_cba_extend(GEN P, GEN b); GEN ZV_cba(GEN v); GEN RM_round_maxrank(GEN G); GEN ZM_famat_limit(GEN fa, GEN limit); GEN famat_Z_gcd(GEN M, GEN n); GEN famat_div_shallow(GEN f, GEN g); GEN famat_inv(GEN f); GEN famat_inv_shallow(GEN f); GEN famat_makecoprime(GEN nf, GEN g, GEN e, GEN pr, GEN prk, GEN EX); GEN famat_mul(GEN f, GEN g); GEN famat_mul_shallow(GEN f, GEN g); GEN famat_mulpow_shallow(GEN f, GEN g, GEN e); GEN famat_mulpows_shallow(GEN f, GEN g, long e); GEN famat_pow(GEN f, GEN n); GEN famat_pow_shallow(GEN f, GEN n); GEN famat_pows_shallow(GEN f, long n); GEN famat_sqr(GEN f); GEN famat_reduce(GEN fa); GEN famat_to_nf(GEN nf, GEN f); GEN famat_to_nf_modideal_coprime(GEN nf, GEN g, GEN e, GEN id, GEN EX); GEN famat_to_nf_moddivisor(GEN nf, GEN g, GEN e, GEN bid); GEN famatsmall_reduce(GEN fa); GEN gpidealval(GEN nf, GEN ix, GEN P); GEN gpidealfactor(GEN nf, GEN x, GEN lim); GEN idealHNF_Z_factor(GEN x, GEN *pvN, GEN *pvZ); GEN idealHNF_Z_factor_i(GEN x, GEN f, GEN *pvN, GEN *pvZ); GEN idealtwoelt(GEN nf, GEN ix); GEN idealtwoelt0(GEN nf, GEN ix, GEN a); GEN idealtwoelt2(GEN nf, GEN x, GEN a); GEN idealadd(GEN nf, GEN x, GEN y); GEN idealaddmultoone(GEN nf, GEN list); GEN idealaddtoone(GEN nf, GEN x, GEN y); GEN idealaddtoone_i(GEN nf, GEN x, GEN y); GEN idealaddtoone_raw(GEN nf, GEN x, GEN y); GEN idealaddtoone0(GEN nf, GEN x, GEN y); GEN idealappr(GEN nf, GEN x); GEN idealappr0(GEN nf, GEN x, long fl); GEN idealapprfact(GEN nf, GEN x); GEN idealchinese(GEN nf, GEN x, GEN y); GEN idealcoprime(GEN nf, GEN x, GEN y); GEN idealcoprimefact(GEN nf, GEN x, GEN fy); GEN idealdiv(GEN nf, GEN x, GEN y); GEN idealdiv0(GEN nf, GEN x, GEN y,long flag); GEN idealdivexact(GEN nf, GEN x, GEN y); GEN idealdivpowprime(GEN nf, GEN x, GEN vp, GEN n); GEN idealmulpowprime(GEN nf, GEN x, GEN vp, GEN n); GEN idealfactor(GEN nf, GEN x); GEN idealfactor_limit(GEN nf, GEN x, ulong lim); GEN idealhnf(GEN nf, GEN x); GEN idealhnf_principal(GEN nf, GEN x); GEN idealhnf_shallow(GEN nf, GEN x); GEN idealhnf_two(GEN nf, GEN vp); GEN idealhnf0(GEN nf, GEN a, GEN b); GEN idealintersect(GEN nf, GEN x, GEN y); GEN idealinv(GEN nf, GEN ix); GEN idealHNF_inv(GEN nf, GEN I); GEN idealHNF_inv_Z(GEN nf, GEN I); long idealispower(GEN nf, GEN A, long n, GEN *pB); GEN idealred0(GEN nf, GEN I,GEN vdir); GEN idealmul(GEN nf, GEN ix, GEN iy); GEN idealmul0(GEN nf, GEN ix, GEN iy, long flag); GEN idealHNF_mul(GEN nf, GEN ix, GEN iy); GEN idealmulred(GEN nf, GEN ix, GEN iy); GEN idealnorm(GEN nf, GEN x); GEN idealnumden(GEN nf, GEN x); GEN idealpow(GEN nf, GEN ix, GEN n); GEN idealpow0(GEN nf, GEN ix, GEN n, long flag); GEN idealpowred(GEN nf, GEN ix, GEN n); GEN idealpows(GEN nf, GEN ideal, long iexp); long idealprodval(GEN nf, GEN I, GEN pr); GEN idealprodprime(GEN nf, GEN L); GEN idealsqr(GEN nf, GEN x); long idealtyp(GEN *ideal, GEN *arch); long idealval(GEN nf,GEN ix,GEN vp); GEN idealprod(GEN nf, GEN I); long isideal(GEN nf,GEN x); GEN idealmin(GEN nf,GEN ix,GEN vdir); GEN nf_get_Gtwist(GEN nf, GEN vdir); GEN nf_get_Gtwist1(GEN nf, long i); GEN nf_to_Fp_coprime(GEN nf, GEN x, GEN modpr); GEN nfC_multable_mul(GEN v, GEN x); GEN nfC_nf_mul(GEN nf, GEN v, GEN x); GEN nfdetint(GEN nf,GEN pseudo); GEN nfdivmodpr(GEN nf, GEN x, GEN y, GEN modpr); GEN idealredmodpower(GEN nf, GEN x, ulong k, ulong B); GEN nfhnf(GEN nf, GEN x); GEN nfhnf0(GEN nf, GEN x, long flag); GEN nfhnfmod(GEN nf, GEN x, GEN d); GEN nfkermodpr(GEN nf, GEN x, GEN modpr); GEN nfmulmodpr(GEN nf, GEN x, GEN y, GEN modpr); GEN nfpowmodpr(GEN nf, GEN x, GEN k, GEN modpr); GEN nfreduce(GEN nf, GEN x, GEN ideal); GEN nfsnf(GEN nf, GEN x); GEN nfsnf0(GEN nf, GEN x, long flag); GEN nfsolvemodpr(GEN nf, GEN a, GEN b, GEN modpr); GEN pr_hnf(GEN nf, GEN pr); GEN pr_inv(GEN pr); GEN pr_inv_p(GEN pr); GEN pr_uniformizer(GEN pr, GEN F); GEN prV_lcm_capZ(GEN L); GEN to_famat(GEN x, GEN y); GEN to_famat_shallow(GEN x, GEN y); ulong u_ppo(ulong x, ulong f); GEN vecdiv(GEN x, GEN y); GEN vecinv(GEN x); GEN vecmul(GEN x, GEN y); GEN vecpow(GEN x, GEN n); GEN zkC_multable_mul(GEN v, GEN x); /* base5.c */ GEN eltreltoabs(GEN rnfeq, GEN x); GEN eltabstorel(GEN eq, GEN P); GEN eltabstorel_lift(GEN rnfeq, GEN P); GEN nf_nfzk(GEN nf, GEN rnfeq); GEN rnf_build_nfabs(GEN rnf, long prec); GEN rnf_zkabs(GEN rnf); GEN nfeltup(GEN nf, GEN x, GEN zknf); void rnfcomplete(GEN rnf); GEN rnfeltabstorel(GEN rnf, GEN x); GEN rnfeltdown(GEN rnf, GEN x); GEN rnfeltdown0(GEN rnf, GEN x, long flag); GEN rnfeltreltoabs(GEN rnf, GEN x); GEN rnfeltup(GEN rnf, GEN x); GEN rnfeltup0(GEN rnf, GEN x, long flag); GEN rnfidealabstorel(GEN rnf, GEN x); GEN rnfidealdown(GEN rnf, GEN x); GEN rnfidealfactor(GEN rnf, GEN x); GEN rnfidealhnf(GEN rnf, GEN x); GEN rnfidealmul(GEN rnf,GEN x,GEN y); GEN rnfidealnormabs(GEN rnf, GEN x); GEN rnfidealnormrel(GEN rnf, GEN x); GEN rnfidealprimedec(GEN rnf, GEN pr); GEN rnfidealreltoabs(GEN rnf, GEN x); GEN rnfidealreltoabs0(GEN rnf, GEN x, long flag); GEN rnfidealtwoelement(GEN rnf,GEN x); GEN rnfidealup(GEN rnf, GEN x); GEN rnfidealup0(GEN rnf,GEN x, long flag); GEN rnfinit(GEN nf,GEN pol); GEN rnfinit0(GEN nf,GEN pol,long flag); /* bb_group.c */ GEN get_arith_ZZM(GEN o); GEN get_arith_Z(GEN o); GEN gen_PH_log(GEN a, GEN g, GEN ord, void *E, const struct bb_group *grp); GEN gen_Shanks_init(GEN g, long n, void *E, const struct bb_group *grp); GEN gen_Shanks(GEN T, GEN x, ulong N, void *E, const struct bb_group *grp); GEN gen_Shanks_sqrtn(GEN a, GEN n, GEN q, GEN *zetan, void *E, const struct bb_group *grp); GEN gen_gener(GEN o, void *E, const struct bb_group *grp); GEN gen_ellgens(GEN d1, GEN d2, GEN m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)); GEN gen_ellgroup(GEN N, GEN F, GEN *pt_m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)); GEN gen_factored_order(GEN a, GEN o, void *E, const struct bb_group *grp); GEN gen_order(GEN x, GEN o, void *E, const struct bb_group *grp); GEN gen_select_order(GEN o, void *E, const struct bb_group *grp); GEN gen_plog(GEN x,GEN g0,GEN q, void *E, const struct bb_group *grp); GEN gen_pow(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)); GEN gen_pow_fold(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)); GEN gen_pow_fold_i(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)); GEN gen_pow_i(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)); GEN gen_pow_init(GEN x, GEN n, long k, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)); GEN gen_pow_table(GEN R, GEN n, void *E, GEN (*one)(void*), GEN (*mul)(void*,GEN,GEN)); GEN gen_powers(GEN x, long l, int use_sqr, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN), GEN (*one)(void*)); GEN gen_powu(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)); GEN gen_powu_fold(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)); GEN gen_powu_fold_i(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)); GEN gen_powu_i(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)); GEN gen_product(GEN x, void *data, GEN (*mul)(void*,GEN,GEN)); /* bb_hnf.c */ GEN matdetmod(GEN A, GEN d); GEN matimagemod(GEN A, GEN d, GEN* U); GEN matinvmod(GEN A, GEN d); GEN matkermod(GEN A, GEN d, GEN* im); GEN matsolvemod(GEN M, GEN D, GEN Y, long flag); /* bibli1.c */ int QR_init(GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec); GEN R_from_QR(GEN x, long prec); GEN RgM_Babai(GEN B, GEN t); int RgM_QR_init(GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec); GEN RgM_gram_schmidt(GEN e, GEN *ptB); GEN lindep_Xadic(GEN x); GEN algdep(GEN x, long n); GEN algdep0(GEN x, long n, long bit); void forqfvec(void *E, long (*fun)(void *, GEN, GEN, double), GEN a, GEN BORNE); void forqfvec0(GEN a, GEN BORNE, GEN code); GEN bestapprnf(GEN x, GEN T, GEN rootsT, long prec); GEN gaussred_from_QR(GEN x, long prec); GEN lindep0(GEN x, long flag); GEN lindep(GEN x); GEN lindep_bit(GEN x, long bit); GEN lindepfull_bit(GEN x, long bit); GEN lindep2(GEN x, long bit); GEN mathouseholder(GEN Q, GEN v); GEN matqr(GEN x, long flag, long prec); GEN minim(GEN a, GEN borne, GEN stockmax); GEN minim_raw(GEN a, GEN borne, GEN stockmax); GEN minim2(GEN a, GEN borne, GEN stockmax); GEN lindep_padic(GEN x); GEN perf(GEN a); GEN qfrep0(GEN a, GEN borne, long flag); GEN qfminim0(GEN a, GEN borne, GEN stockmax,long flag, long prec); GEN seralgdep(GEN s, long p, long r); GEN zncoppersmith(GEN P0, GEN N, GEN X, GEN B) ; /* bibli2.c */ GEN QXQ_reverse(GEN a, GEN T); GEN RgV_polint(GEN X, GEN Y, long v); GEN RgXQ_reverse(GEN a, GEN T); GEN ZC_union_shallow(GEN x, GEN y); GEN ZV_indexsort(GEN L); long ZV_search(GEN x, GEN y); GEN ZV_sort(GEN L); void ZV_sort_inplace(GEN L); GEN ZV_sort_uniq(GEN L); GEN ZV_union_shallow(GEN x, GEN y); GEN binomial(GEN x, long k); GEN binomial0(GEN x, GEN k); GEN binomialuu(ulong n, ulong k); int cmp_Flx(GEN x, GEN y); int cmp_RgX(GEN x, GEN y); int cmp_nodata(void *data, GEN x, GEN y); int cmp_prime_ideal(GEN x, GEN y); int cmp_prime_over_p(GEN x, GEN y); int cmp_universal(GEN x, GEN y); GEN convol(GEN x, GEN y); int gen_cmp_RgX(void *data, GEN x, GEN y); GEN polcyclo(long n, long v); GEN polcyclo_eval(long n, GEN x); GEN dirdiv(GEN x, GEN y); GEN dirmul(GEN x, GEN y); GEN gprec_wensure(GEN x, long pr); GEN gen_indexsort(GEN x, void *E, int (*cmp)(void*,GEN,GEN)); GEN gen_indexsort_uniq(GEN x, void *E, int (*cmp)(void*,GEN,GEN)); long gen_search(GEN x, GEN y, long flag, void *data, int (*cmp)(void*,GEN,GEN)); GEN gen_setminus(GEN set1, GEN set2, int (*cmp)(GEN,GEN)); GEN gen_sort(GEN x, void *E, int (*cmp)(void*,GEN,GEN)); void gen_sort_inplace(GEN x, void *E, int (*cmp)(void*,GEN,GEN), GEN *perm); GEN gen_sort_uniq(GEN x, void *E, int (*cmp)(void*,GEN,GEN)); long getstack(void); long gettime(void); long getabstime(void); GEN getwalltime(void); GEN gprec(GEN x, long l); GEN gprec_wtrunc(GEN x, long pr); GEN gprec_w(GEN x, long pr); GEN gtoset(GEN x); GEN indexlexsort(GEN x); GEN indexsort(GEN x); GEN indexvecsort(GEN x, GEN k); GEN laplace(GEN x); GEN lexsort(GEN x); GEN mathilbert(long n); GEN matqpascal(long n, GEN q); GEN merge_factor(GEN fx, GEN fy, void *data, int (*cmp)(void *,GEN,GEN)); GEN merge_sort_uniq(GEN x, GEN y, void *data, int (*cmp)(void *,GEN,GEN)); GEN modreverse(GEN x); GEN polhermite(long n, long v); GEN polhermite_eval(long n, GEN x); GEN pollegendre(long n, long v); GEN pollegendre_eval(long n, GEN x); GEN polint(GEN xa, GEN ya, GEN x, GEN *dy); GEN polchebyshev(long n, long kind, long v); GEN polchebyshev_eval(long n, long kind, GEN x); GEN polchebyshev1(long n, long v); GEN polchebyshev2(long n, long v); GEN polrecip(GEN x); GEN setbinop(GEN f, GEN x, GEN y); GEN setintersect(GEN x, GEN y); long setisset(GEN x); GEN setminus(GEN x, GEN y); long setsearch(GEN x, GEN y, long flag); GEN setunion(GEN x, GEN y); GEN sort(GEN x); GEN sort_factor(GEN y, void *data, int (*cmp)(void*,GEN,GEN)); GEN stirling(long n, long m, long flag); GEN stirling1(ulong n, ulong m); GEN stirling2(ulong n, ulong m); long tablesearch(GEN T, GEN x, int (*cmp)(GEN,GEN)); GEN vecbinomial(long n); long vecsearch(GEN v, GEN x, GEN k); GEN vecsort(GEN x, GEN k); GEN vecsort0(GEN x, GEN k, long flag); long zv_search(GEN x, long y); /* bit.c */ GEN bits_to_int(GEN x, long l); ulong bits_to_u(GEN v, long l); GEN binaire(GEN x); GEN binary_2k(GEN x, long k); GEN binary_2k_nv(GEN x, long k); GEN binary_zv(GEN x); long bittest(GEN x, long n); GEN fromdigits_2k(GEN x, long k); GEN gbitand(GEN x, GEN y); GEN gbitneg(GEN x, long n); GEN gbitnegimply(GEN x, GEN y); GEN gbitor(GEN x, GEN y); GEN gbittest(GEN x, long n); GEN gbitxor(GEN x, GEN y); long hammingl(ulong w); long hammingweight(GEN n); GEN ibitand(GEN x, GEN y); GEN ibitnegimply(GEN x, GEN y); GEN ibitor(GEN x, GEN y); GEN ibitxor(GEN x, GEN y); GEN nv_fromdigits_2k(GEN x, long k); /* bnflog.c */ GEN bnflogef(GEN bnf, GEN pr); GEN bnflog(GEN bnf, GEN l); GEN bnflogdegree(GEN bnf, GEN A, GEN ell); long nfislocalpower(GEN nf, GEN pr, GEN a, GEN n); long rnfislocalcyclo(GEN rnf); /* buch1.c */ GEN Buchquad(GEN D, double c1, double c2, long prec); GEN quadclassunit0(GEN x, long flag,GEN data, long prec); GEN quadhilbert(GEN D, long prec); GEN quadray(GEN bnf, GEN f, long prec); /* buch2.c */ GEN Buchall(GEN P, long flag, long prec); GEN Buchall_param(GEN P, double bach, double bach2, long nbrelpid, long flun, long prec); GEN bnf_build_cycgen(GEN bnf); GEN bnf_build_matalpha(GEN bnf); GEN bnf_build_units(GEN bnf); GEN bnfcompress(GEN bnf); GEN bnfinit0(GEN P,long flag,GEN data,long prec); GEN bnfisprincipal0(GEN bnf, GEN x,long flall); GEN bnfisunit(GEN bignf, GEN x); GEN bnfnewprec(GEN nf, long prec); GEN bnfnewprec_shallow(GEN nf, long prec); void bnftestprimes(GEN bnf, GEN bound); GEN bnrnewprec(GEN bnr, long prec); GEN bnrnewprec_shallow(GEN bnr, long prec); GEN isprincipalfact(GEN bnf, GEN C, GEN L, GEN f, long flag); GEN isprincipalfact_or_fail(GEN bnf, GEN C, GEN P, GEN e); GEN isprincipal(GEN bnf, GEN x); GEN nfcyclotomicunits(GEN nf, GEN zu); GEN nfsign_units(GEN bnf, GEN archp, int add_zu); GEN signunits(GEN bignf); /* buch3.c */ GEN ABC_to_bnr(GEN A, GEN B, GEN C, GEN *H, int gen); GEN Buchray(GEN bnf, GEN module, long flag); GEN bnrautmatrix(GEN bnr, GEN aut); GEN bnrchar(GEN bnr, GEN g, GEN v); GEN bnrchar_primitive(GEN bnr, GEN chi, GEN bnrc); GEN bnrclassno(GEN bignf,GEN ideal); GEN bnrclassno0(GEN A,GEN B,GEN C); GEN bnrclassnolist(GEN bnf,GEN listes); GEN bnrconductor0(GEN A, GEN B, GEN C, long flag); GEN bnrconductor(GEN bnr, GEN H0, long flag); GEN bnrconductor_i(GEN bnr, GEN H0, long flag); GEN bnrconductorofchar(GEN bnr,GEN chi); GEN bnrdisc0(GEN A, GEN B, GEN C, long flag); GEN bnrdisc(GEN bnr, GEN H, long flag); GEN bnrdisclist0(GEN bnf,GEN borne, GEN arch); GEN bnrgaloismatrix(GEN bnr, GEN aut); GEN bnrgaloisapply(GEN bnr, GEN mat, GEN x); GEN bnrinit0(GEN bignf,GEN ideal,long flag); long bnrisconductor0(GEN A, GEN B, GEN C); long bnrisconductor(GEN bnr, GEN H); long bnrisgalois(GEN bnr, GEN M, GEN H); GEN bnrisprincipal(GEN bnf, GEN x,long flag); GEN bnrsurjection(GEN bnr1, GEN bnr2); GEN bnfnarrow(GEN bignf); long bnfcertify(GEN bnf); long bnfcertify0(GEN bnf, long flag); GEN decodemodule(GEN nf, GEN fa); GEN discrayabslist(GEN bnf,GEN listes); GEN discrayabslistarch(GEN bnf, GEN arch, ulong bound); GEN idealmoddivisor(GEN bnr, GEN x); GEN isprincipalray(GEN bnf, GEN x); GEN isprincipalraygen(GEN bnf, GEN x); GEN nf_deg1_prime(GEN nf); GEN nfarchstar(GEN nf,GEN x,GEN arch); GEN rnfconductor(GEN bnf, GEN polrel); long rnfisabelian(GEN nf, GEN pol); GEN rnfnormgroup(GEN bnr, GEN polrel); GEN subgrouplist0(GEN bnr, GEN indexbound, long all); /* buch4.c */ GEN bnfisnorm(GEN bnf,GEN x,long flag); GEN rnfisnorm(GEN S, GEN x, long flag); GEN rnfisnorminit(GEN bnf, GEN relpol, int galois); GEN bnfissunit(GEN bnf,GEN suni,GEN x); GEN bnfsunit(GEN bnf,GEN s,long PREC); long nfhilbert(GEN bnf,GEN a,GEN b); long nfhilbert0(GEN bnf,GEN a,GEN b,GEN p); long hyperell_locally_soluble(GEN pol,GEN p); long nf_hyperell_locally_soluble(GEN nf,GEN pol,GEN p); /* char.c */ GEN coprimes_zv(ulong N); int char_check(GEN cyc, GEN chi); GEN charconj(GEN cyc, GEN chi); GEN charconj0(GEN cyc, GEN chi); GEN chardiv(GEN x, GEN a, GEN b); GEN chardiv0(GEN x, GEN a, GEN b); GEN chareval(GEN G, GEN chi, GEN n, GEN z); GEN chargalois(GEN G, GEN ORD); GEN charker(GEN cyc, GEN chi); GEN charker0(GEN cyc, GEN chi); GEN charmul(GEN x, GEN a, GEN b); GEN charmul0(GEN x, GEN a, GEN b); GEN charorder(GEN cyc, GEN x); GEN charorder0(GEN x, GEN chi); GEN charpow(GEN cyc, GEN a, GEN N); GEN charpow0(GEN x, GEN a, GEN N); GEN char_denormalize(GEN cyc, GEN D, GEN chic); GEN char_normalize(GEN chi, GEN ncyc); GEN char_simplify(GEN D, GEN C); int checkznstar_i(GEN G); GEN cyc_normalize(GEN c); GEN ncharvecexpo(GEN G, GEN nchi); GEN znchar(GEN D); GEN znchar_quad(GEN G, GEN D); int zncharcheck(GEN G, GEN chi); GEN zncharconductor(GEN G, GEN chi); GEN zncharconj(GEN G, GEN chi); GEN znchardecompose(GEN G, GEN chi, GEN Q); GEN znchardiv(GEN G, GEN a, GEN b); GEN znchareval(GEN G, GEN chi, GEN n, GEN z); GEN zncharinduce(GEN G, GEN chi, GEN N); long zncharisodd(GEN G, GEN chi); GEN zncharker(GEN G, GEN chi); GEN zncharmul(GEN G, GEN a, GEN b); GEN zncharorder(GEN G, GEN chi); GEN zncharpow(GEN G, GEN a, GEN n); GEN znchartokronecker(GEN G, GEN chi, long flag); GEN znchartoprimitive(GEN G, GEN chi); int znconrey_check(GEN cyc, GEN chi); GEN znconrey_normalized(GEN G, GEN chi); GEN znconreychar(GEN bid, GEN m); GEN znconreyfromchar_normalized(GEN bid, GEN chi); GEN znconreyconductor(GEN bid, GEN co, GEN *pm); GEN znconreyexp(GEN bid, GEN x); GEN znconreyfromchar(GEN bid, GEN chi); GEN znconreylog(GEN bid, GEN x); GEN znconreylog_normalize(GEN G, GEN m); GEN znlog0(GEN h, GEN g, GEN o); long zv_cyc_minimal(GEN cyc, GEN g, GEN coprime); long zv_cyc_minimize(GEN cyc, GEN g, GEN coprime); /* compile.c */ GEN closure_deriv(GEN G); long localvars_find(GEN pack, entree *ep); GEN localvars_read_str(const char *str, GEN pack); GEN snm_closure(entree *ep, GEN data); GEN strtoclosure(const char *s, long n, ...); GEN strtofunction(const char *s); /* concat.c */ GEN gconcat(GEN x, GEN y); GEN gconcat1(GEN x); GEN matconcat(GEN v); GEN shallowconcat(GEN x, GEN y); GEN shallowconcat1(GEN x); GEN shallowmatconcat(GEN v); GEN vconcat(GEN A, GEN B); /* default.c */ enum { d_SILENT = 0, d_ACKNOWLEDGE, d_INITRC, d_RETURN }; GEN default0(const char *a, const char *b); long getrealprecision(void); entree *pari_is_default(const char *s); GEN sd_TeXstyle(const char *v, long flag); GEN sd_colors(const char *v, long flag); GEN sd_compatible(const char *v, long flag); GEN sd_datadir(const char *v, long flag); GEN sd_debug(const char *v, long flag); GEN sd_debugfiles(const char *v, long flag); GEN sd_debugmem(const char *v, long flag); GEN sd_factor_add_primes(const char *v, long flag); GEN sd_factor_proven(const char *v, long flag); GEN sd_format(const char *v, long flag); GEN sd_histsize(const char *v, long flag); GEN sd_log(const char *v, long flag); GEN sd_logfile(const char *v, long flag); GEN sd_nbthreads(const char *v, long flag); GEN sd_new_galois_format(const char *v, long flag); GEN sd_output(const char *v, long flag); GEN sd_parisize(const char *v, long flag); GEN sd_parisizemax(const char *v, long flag); GEN sd_path(const char *v, long flag); GEN sd_plothsizes(const char *v, long flag); GEN sd_prettyprinter(const char *v, long flag); GEN sd_primelimit(const char *v, long flag); GEN sd_realbitprecision(const char *v, long flag); GEN sd_realprecision(const char *v, long flag); GEN sd_secure(const char *v, long flag); GEN sd_seriesprecision(const char *v, long flag); GEN sd_simplify(const char *v, long flag); GEN sd_sopath(char *v, int flag); GEN sd_strictargs(const char *v, long flag); GEN sd_strictmatch(const char *v, long flag); GEN sd_string(const char *v, long flag, const char *s, char **f); GEN sd_threadsize(const char *v, long flag); GEN sd_threadsizemax(const char *v, long flag); GEN sd_intarray(const char *v, long flag, GEN *pz, const char *s); GEN sd_toggle(const char *v, long flag, const char *s, int *ptn); GEN sd_ulong(const char *v, long flag, const char *s, ulong *ptn, ulong Min, ulong Max, const char **msg); GEN setdefault(const char *s, const char *v, long flag); long setrealprecision(long n, long *prec); /* ecpp.c */ GEN ecpp(GEN N); GEN ecppexport(GEN cert, long flag); long ecppisvalid(GEN cert); long isprimeECPP(GEN N); /* gplib.c */ GEN sd_breakloop(const char *v, long flag); GEN sd_echo(const char *v, long flag); GEN sd_graphcolormap(const char *v, long flag); GEN sd_graphcolors(const char *v, long flag); GEN sd_help(const char *v, long flag); GEN sd_histfile(const char *v, long flag); GEN sd_lines(const char *v, long flag); GEN sd_linewrap(const char *v, long flag); GEN sd_prompt(const char *v, long flag); GEN sd_prompt_cont(const char *v, long flag); GEN sd_psfile(const char *v, long flag); GEN sd_readline(const char *v, long flag); GEN sd_recover(const char *v, long flag); GEN sd_timer(const char *v, long flag); void pari_hit_return(void); void gp_load_gprc(void); int gp_meta(const char *buf, int ismain); const char **gphelp_keyword_list(void); void pari_center(const char *s); long pari_community(void); void pari_print_version(void); const char *gp_format_time(long delay); const char *gp_format_prompt(const char *p); void pari_alarm(long s); GEN gp_alarm(long s, GEN code); GEN gp_input(void); void gp_allocatemem(GEN z); int gp_handle_exception(long numerr); void gp_alarm_handler(int sig); void gp_sigint_fun(void); enum { h_REGULAR=0, h_LONG=1, h_APROPOS=2, h_RL=4 }; void gp_help(const char *s, long flag); void gp_echo_and_log(const char *prompt, const char *s); void print_fun_list(char **list, long nbli); /* dirichlet.c */ GEN direuler(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, GEN c); /* ellanal.c */ GEN ellanalyticrank(GEN e, GEN eps, long prec); GEN ellanalyticrank_bitprec(GEN e, GEN eps, long bitprec); GEN ellanal_globalred_all(GEN e, GEN *N, GEN *cb, GEN *tam); GEN ellheegner(GEN e); GEN ellL1(GEN E, long r, long prec); GEN ellL1_bitprec(GEN E, long r, long bitprec); /* elldata.c */ GEN ellconvertname(GEN s); GEN elldatagenerators(GEN E); GEN ellidentify(GEN E); GEN ellsearch(GEN A); GEN ellsearchcurve(GEN name); void forell(void *E, long call(void*, GEN), long a, long b, long flag); /* ellfromeqn.c */ GEN ellfromeqn(GEN s); /* elliptic.c */ enum { t_ELL_Rg = 0, t_ELL_Q, t_ELL_Qp, t_ELL_Fp, t_ELL_Fq, t_ELL_NF }; long ellQ_get_CM(GEN e); int ell_is_integral(GEN E); GEN ellbasechar(GEN E); GEN akell(GEN e, GEN n); GEN ellan(GEN e, long n); GEN ellanQ_zv(GEN e, long n); GEN bilhell(GEN e, GEN z1, GEN z2, long prec); void checkell(GEN e); void checkell_Fq(GEN e); void checkell_Q(GEN e); void checkell_Qp(GEN e); void checkellisog(GEN v); void checkellpt(GEN z); void checkell5(GEN e); GEN cxredsl2(GEN t, GEN *U); GEN cxredsl2_i(GEN z, GEN *pU, GEN *czd); GEN ec_bmodel(GEN e); GEN ec_f_evalx(GEN E, GEN x); GEN ec_h_evalx(GEN e, GEN x); GEN ec_dFdx_evalQ(GEN E, GEN Q); GEN ec_dFdy_evalQ(GEN E, GEN Q); GEN ec_dmFdy_evalQ(GEN e, GEN Q); GEN ec_2divpol_evalx(GEN E, GEN x); GEN ec_3divpol_evalx(GEN E, GEN x); GEN ec_half_deriv_2divpol_evalx(GEN E, GEN x); GEN ellanal_globalred(GEN e, GEN *gr); GEN ellQ_get_N(GEN e); void ellQ_get_Nfa(GEN e, GEN *N, GEN *faN); GEN ellQp_Tate_uniformization(GEN E, long prec); GEN ellQp_AGM(GEN E, long prec); GEN ellQp_u(GEN E, long prec); GEN ellQp_u2(GEN E, long prec); GEN ellQp_q(GEN E, long prec); GEN ellQp_ab(GEN E, long prec); GEN ellQp_L(GEN E, long prec); GEN ellQp_root(GEN E, long prec); GEN ellR_area(GEN E, long prec); GEN ellR_ab(GEN E, long prec); GEN ellR_eta(GEN E, long prec); GEN ellR_omega(GEN x, long prec); GEN ellR_roots(GEN E, long prec); GEN elladd(GEN e, GEN z1, GEN z2); GEN ellap(GEN e, GEN p); long ellap_CM_fast(GEN E, ulong p, long CM); GEN ellbsd(GEN e, long prec); GEN ellcard(GEN E, GEN p); GEN ellchangecurve(GEN e, GEN ch); GEN ellchangeinvert(GEN w); GEN ellchangepoint(GEN x, GEN ch); GEN ellchangepointinv(GEN x, GEN ch); GEN elldivpol(GEN e, long n, long v); GEN elleisnum(GEN om, long k, long flag, long prec); GEN elleta(GEN om, long prec); GEN ellff_get_card(GEN E); GEN ellff_get_gens(GEN E); GEN ellff_get_group(GEN E); GEN ellff_get_o(GEN x); GEN ellff_get_p(GEN E); GEN ellff_get_m(GEN E); GEN ellff_get_D(GEN E); GEN ellfromj(GEN j); GEN ellgenerators(GEN E); GEN ellglobalred(GEN e1); GEN ellgroup(GEN E, GEN p); GEN ellgroup0(GEN E, GEN p, long flag); GEN ellheight0(GEN e, GEN a, GEN b, long prec); GEN ellheight(GEN e, GEN a, long prec); GEN ellheightmatrix(GEN E, GEN x, long n); GEN ellheightoo(GEN e, GEN z, long prec); GEN ellinit(GEN x, GEN p, long prec); GEN ellintegralmodel(GEN e, GEN *pv); GEN ellintegralmodel_i(GEN e, GEN *pv); GEN ellisoncurve(GEN e, GEN z); GEN ellisotree(GEN e); int ellissupersingular(GEN x, GEN p); int elljissupersingular(GEN x); GEN elllseries(GEN e, GEN s, GEN A, long prec); GEN elllocalred(GEN e, GEN p1); GEN elllog(GEN e, GEN a, GEN g, GEN o); GEN ellminimaldisc(GEN E); GEN ellminimalmodel(GEN E, GEN *ptv); GEN ellminimaltwist(GEN e); GEN ellminimaltwist0(GEN e, long fl); GEN ellminimaltwistcond(GEN e); GEN ellmul(GEN e, GEN z, GEN n); GEN ellnf_vecarea(GEN E, long prec); GEN ellnf_veceta(GEN E, long prec); GEN ellnf_vecomega(GEN E, long prec); GEN ellneg(GEN e, GEN z); GEN ellorder(GEN e, GEN p, GEN o); long ellorder_Q(GEN E, GEN P); GEN ellordinate(GEN e, GEN x, long prec); GEN ellpadicheight0(GEN e, GEN p, long n, GEN P, GEN Q); GEN ellpadicheightmatrix(GEN e, GEN p, long n, GEN P); GEN ellperiods(GEN w, long flag, long prec); GEN elltwist(GEN E, GEN D); GEN ellrandom(GEN e); long ellrootno(GEN e, GEN p); long ellrootno_global(GEN e); GEN ellsea(GEN E, long smallfact); GEN ellsigma(GEN om, GEN z, long flag, long prec); GEN ellsub(GEN e, GEN z1, GEN z2); GEN elltamagawa(GEN e); GEN elltaniyama(GEN e, long prec); GEN elltatepairing(GEN E, GEN t, GEN s, GEN m); GEN elltors(GEN e); GEN elltors0(GEN e, long flag); GEN ellweilpairing(GEN E, GEN t, GEN s, GEN m); GEN ellwp(GEN w, GEN z, long prec); GEN ellwp0(GEN w, GEN z, long flag, long prec); GEN ellwpseries(GEN e, long v, long PRECDL); GEN ellxn(GEN e, long n, long v); GEN ellzeta(GEN om, GEN z, long prec); GEN expIxy(GEN x, GEN y, long prec); int oncurve(GEN e, GEN z); GEN orderell(GEN e, GEN p); GEN pointell(GEN e, GEN z, long prec); GEN point_to_a4a6(GEN E, GEN P, GEN p, GEN *pa4); GEN point_to_a4a6_Fl(GEN E, GEN P, ulong p, ulong *pa4); GEN zell(GEN e, GEN z, long prec); /* ellpadic.c */ GEN Qp_agm2_sequence(GEN a1, GEN b1); void Qp_ascending_Landen(GEN AB, GEN *ptx, GEN *pty); void Qp_descending_Landen(GEN AB, GEN *ptx, GEN *pty); GEN ellformaldifferential(GEN e, long n, long v); GEN ellformalexp(GEN e, long n, long v); GEN ellformallog(GEN e, long n, long v); GEN ellformalpoint(GEN e, long n, long v); GEN ellformalw(GEN e, long n, long v); GEN ellnonsingularmultiple(GEN e, GEN P); GEN ellpadicL(GEN E, GEN p, long n, GEN s, long r, GEN D); GEN ellpadicbsd(GEN E, GEN p, long n, GEN D); GEN ellpadicfrobenius(GEN E, ulong p, long n); GEN ellpadicheight(GEN e, GEN p, long n, GEN P); GEN ellpadiclog(GEN E, GEN p, long n, GEN P); GEN ellpadicregulator(GEN E, GEN p, long n, GEN S); GEN ellpadics2(GEN E, GEN p, long n); /* elltors.c */ long ellisdivisible(GEN E, GEN P, GEN n, GEN *Q); /* ellisog.c */ GEN ellisogenyapply(GEN f, GEN P); GEN ellisogeny(GEN e, GEN G, long only_image, long vx, long vy); GEN ellisomat(GEN E, long p, long flag); GEN ellweilcurve(GEN E, GEN *pm); /* ellsea.c */ GEN Fp_ellcard_SEA(GEN a4, GEN a6, GEN p, long smallfact); GEN Fq_ellcard_SEA(GEN a4, GEN a6, GEN q, GEN T, GEN p, long smallfact); GEN ellmodulareqn(long l, long vx, long vy); /* es.c */ GEN externstr(const char *cmd); char *gp_filter(const char *s); GEN gpextern(const char *cmd); void gpsystem(const char *s); GEN readstr(const char *s); GEN GENtoGENstr_nospace(GEN x); GEN GENtoGENstr(GEN x); char* GENtoTeXstr(GEN x); char* GENtostr(GEN x); char* GENtostr_raw(GEN x); char* GENtostr_unquoted(GEN x); GEN Str(GEN g); GEN Strchr(GEN g); GEN Strexpand(GEN g); GEN Strtex(GEN g); void brute(GEN g, char format, long dec); void dbgGEN(GEN x, long nb); void error0(GEN g); void dbg_pari_heap(void); int file_is_binary(FILE *f); void err_flush(void); void err_printf(const char* pat, ...); GEN gp_getenv(const char *s); void gp_fileclose(long n); long gp_fileextern(char *s); void gp_fileflush(long n); void gp_fileflush0(GEN n); long gp_fileopen(char *s, char *mode); GEN gp_fileread(long n); GEN gp_filereadstr(long n); void gp_filewrite(long n, const char *s); void gp_filewrite1(long n, const char *s); GEN gp_read_file(const char *s); GEN gp_read_str_multiline(const char *s, char *last); GEN gp_read_stream(FILE *f); GEN gp_readvec_file(char *s); GEN gp_readvec_stream(FILE *f); void gpinstall(const char *s, const char *code, const char *gpname, const char *lib); GEN gsprintf(const char *fmt, ...); GEN gvsprintf(const char *fmt, va_list ap); char* itostr(GEN x); void matbrute(GEN g, char format, long dec); char* os_getenv(const char *s); char* uordinal(ulong i); void outmat(GEN x); void output(GEN x); char* RgV_to_str(GEN g, long flag); void pari_add_hist(GEN z, long t); void pari_ask_confirm(const char *s); void pari_fclose(pariFILE *f); void pari_flush(void); pariFILE* pari_fopen(const char *s, const char *mode); pariFILE* pari_fopen_or_fail(const char *s, const char *mode); pariFILE* pari_fopengz(const char *s); void pari_fprintf(FILE *file, const char *fmt, ...); void pari_fread_chars(void *b, size_t n, FILE *f); GEN pari_get_hist(long p); long pari_get_histtime(long p); char* pari_get_homedir(const char *user); int pari_is_dir(const char *name); int pari_is_file(const char *name); int pari_last_was_newline(void); void pari_set_last_newline(int last); ulong pari_nb_hist(void); void pari_printf(const char *fmt, ...); void pari_putc(char c); void pari_puts(const char *s); pariFILE* pari_safefopen(const char *s, const char *mode); char* pari_sprintf(const char *fmt, ...); int pari_stdin_isatty(void); char* pari_strdup(const char *s); char* pari_strndup(const char *s, long n); char* pari_unique_dir(const char *s); char* pari_unique_filename(const char *s); char* pari_unique_filename_suffix(const char *s, const char *suf); void pari_unlink(const char *s); void pari_vfprintf(FILE *file, const char *fmt, va_list ap); void pari_vprintf(const char *fmt, va_list ap); char* pari_vsprintf(const char *fmt, va_list ap); char* path_expand(const char *s); void out_print0(PariOUT *out, const char *sep, GEN g, long flag); void out_printf(PariOUT *out, const char *fmt, ...); void out_putc(PariOUT *out, char c); void out_puts(PariOUT *out, const char *s); void out_term_color(PariOUT *out, long c); void out_vprintf(PariOUT *out, const char *fmt, va_list ap); char* pari_sprint0(const char *msg, GEN g, long flag); void print(GEN g); void printp(GEN g); enum { f_RAW = 0, f_PRETTYMAT = 1, f_PRETTY = 3, f_TEX = 4 }; void print0(GEN g, long flag); void print1(GEN g); void printf0(const char *fmt, GEN args); void printsep(const char *s, GEN g); void printsep1(const char *s, GEN g); void printtex(GEN g); char* stack_sprintf(const char *fmt, ...); char* stack_strcat(const char *s, const char *t); char* stack_strdup(const char *s); void str_init(pari_str *S, int use_stack); void str_printf(pari_str *S, const char *fmt, ...); void str_putc(pari_str *S, char c); void str_puts(pari_str *S, const char *s); void strftime_expand(const char *s, char *buf, long max); GEN Strprintf(const char *fmt, GEN args); FILE* switchin(const char *name); void switchout(const char *name); void term_color(long c); char* term_get_color(char *s, long c); void texe(GEN g, char format, long dec); const char* type_name(long t); void warning0(GEN g); void write0(const char *s, GEN g); void write1(const char *s, GEN g); void writebin(const char *name, GEN x); void writetex(const char *s, GEN g); /* eval.c */ enum { br_NONE = 0, br_BREAK, br_NEXT, br_MULTINEXT, br_RETURN }; void bincopy_relink(GEN C, GEN vi); GEN break0(long n); GEN call0(GEN fun, GEN args); GEN closure_callgen1(GEN C, GEN x); GEN closure_callgen1prec(GEN C, GEN x, long prec); GEN closure_callgen2(GEN C, GEN x, GEN y); GEN closure_callgenall(GEN C, long n, ...); GEN closure_callgenvec(GEN C, GEN args); GEN closure_callgenvecprec(GEN C, GEN args, long prec); void closure_callvoid1(GEN C, GEN x); long closure_context(long start, long level); void closure_disassemble(GEN n); void closure_err(long level); GEN closure_evalbrk(GEN C, long *status); GEN closure_evalgen(GEN C); GEN closure_evalnobrk(GEN C); GEN closure_evalres(GEN C); void closure_evalvoid(GEN C); const char * closure_func_err(void); GEN closure_trapgen(GEN C, long numerr); GEN copybin_unlink(GEN C); GEN get_lex(long vn); long get_localprec(void); long get_localbitprec(void); GEN gp_call(void *E, GEN x); GEN gp_callprec(void *E, GEN x, long prec); GEN gp_call2(void *E, GEN x, GEN y); long gp_callbool(void *E, GEN x); long gp_callvoid(void *E, GEN x); GEN gp_eval(void *E, GEN x); long gp_evalbool(void *E, GEN x); GEN gp_evalprec(void *E, GEN x, long prec); GEN gp_evalupto(void *E, GEN x); long gp_evalvoid(void *E, GEN x); void localprec(long p); void localbitprec(long p); long loop_break(void); GEN next0(long n); GEN pareval(GEN C); GEN pari_self(void); GEN parsum(GEN a, GEN b, GEN code, GEN x); GEN parvector(long n, GEN code); void pop_lex(long n); void pop_localprec(void); void push_lex(GEN a, GEN C); void push_localbitprec(long p); void push_localprec(long p); GEN return0(GEN x); void set_lex(long vn, GEN x); /* forprime.c */ int forcomposite_init(forcomposite_t *C, GEN a, GEN b); GEN forcomposite_next(forcomposite_t *C); GEN forprime_next(forprime_t *T); int forprime_init(forprime_t *T, GEN a, GEN b); int forprimestep_init(forprime_t *T, GEN a, GEN b, GEN q); byteptr initprimes(ulong maxnum, long *lenp, ulong *lastp); void initprimetable(ulong maxnum); ulong init_primepointer_geq(ulong a, byteptr *pd); ulong init_primepointer_gt(ulong a, byteptr *pd); ulong init_primepointer_leq(ulong a, byteptr *pd); ulong init_primepointer_lt(ulong a, byteptr *pd); ulong maxprime(void); void maxprime_check(ulong c); void pari_init_primes(ulong maxprime); ulong u_forprime_next(forprime_t *T); int u_forprime_init(forprime_t *T, ulong a, ulong b); void u_forprime_restrict(forprime_t *T, ulong c); int u_forprime_arith_init(forprime_t *T, ulong a, ulong b, ulong c, ulong q); /* FF.c */ GEN FF_1(GEN a); GEN FF_Frobenius(GEN x, long e); GEN FF_Z_Z_muldiv(GEN x, GEN y, GEN z); GEN FF_Q_add(GEN x, GEN y); GEN FF_Z_add(GEN a, GEN b); GEN FF_Z_mul(GEN a, GEN b); GEN FF_add(GEN a, GEN b); GEN FF_charpoly(GEN x); GEN FF_conjvec(GEN x); GEN FF_div(GEN a, GEN b); GEN FF_ellcard(GEN E); GEN FF_ellcard_SEA(GEN E, long smallfact); GEN FF_ellgens(GEN E); GEN FF_ellgroup(GEN E, GEN *m); GEN FF_elllog(GEN E, GEN P, GEN Q, GEN o); GEN FF_ellmul(GEN E, GEN P, GEN n); GEN FF_ellorder(GEN E, GEN P, GEN o); GEN FF_elltwist(GEN E); GEN FF_ellrandom(GEN E); GEN FF_elltatepairing(GEN E, GEN P, GEN Q, GEN m); GEN FF_ellweilpairing(GEN E, GEN P, GEN Q, GEN m); int FF_equal(GEN a, GEN b); int FF_equal0(GEN x); int FF_equal1(GEN x); int FF_equalm1(GEN x); long FF_f(GEN x); GEN FF_gen(GEN x); GEN FF_inv(GEN a); long FF_issquare(GEN x); long FF_issquareall(GEN x, GEN *pt); long FF_ispower(GEN x, GEN K, GEN *pt); GEN FF_log(GEN a, GEN b, GEN o); GEN FF_map(GEN m, GEN x); GEN FF_minpoly(GEN x); GEN FF_mod(GEN x); GEN FF_mul(GEN a, GEN b); GEN FF_mul2n(GEN a, long n); GEN FF_neg(GEN a); GEN FF_neg_i(GEN a); GEN FF_norm(GEN x); GEN FF_order(GEN x, GEN o); GEN FF_p(GEN x); GEN FF_p_i(GEN x); GEN FF_pow(GEN x, GEN n); GEN FF_primroot(GEN x, GEN *o); GEN FF_q(GEN x); int FF_samefield(GEN x, GEN y); GEN FF_sqr(GEN a); GEN FF_sqrt(GEN a); GEN FF_sqrtn(GEN x, GEN n, GEN *zetan); GEN FF_sub(GEN x, GEN y); GEN FF_to_F2xq(GEN x); GEN FF_to_F2xq_i(GEN x); GEN FF_to_Flxq(GEN x); GEN FF_to_Flxq_i(GEN x); GEN FF_to_FpXQ(GEN x); GEN FF_to_FpXQ_i(GEN x); GEN FF_trace(GEN x); GEN FF_zero(GEN a); GEN FFM_FFC_invimage(GEN M, GEN C, GEN ff); GEN FFM_FFC_gauss(GEN M, GEN C, GEN ff); GEN FFM_FFC_mul(GEN M, GEN C, GEN ff); GEN FFM_deplin(GEN M, GEN ff); GEN FFM_det(GEN M, GEN ff); GEN FFM_gauss(GEN M, GEN N, GEN ff); GEN FFM_image(GEN M, GEN ff); GEN FFM_indexrank(GEN M, GEN ff); GEN FFM_inv(GEN M, GEN ff); GEN FFM_invimage(GEN M, GEN N, GEN ff); GEN FFM_ker(GEN M, GEN ff); GEN FFM_mul(GEN M, GEN N, GEN ff); long FFM_rank(GEN M, GEN ff); GEN FFM_suppl(GEN M, GEN ff); GEN FFX_ddf(GEN f, GEN x); GEN FFX_degfact(GEN Pf, GEN ff); GEN FFX_factor(GEN f, GEN x); GEN FFX_factor_squarefree(GEN f, GEN x); long FFX_ispower(GEN Pf, long k, GEN ff, GEN *pt_r); GEN FFX_mul(GEN Pf, GEN Qf, GEN ff); GEN FFX_preimage(GEN x, GEN F, GEN y); GEN FFX_rem(GEN Pf, GEN Qf, GEN ff); GEN FFX_roots(GEN f, GEN x); GEN FFX_sqr(GEN Pf, GEN ff); GEN FFXQ_inv(GEN Pf, GEN Qf, GEN ff); GEN FFXQ_mul(GEN Pf, GEN Qf, GEN Sf, GEN ff); GEN FFXQ_sqr(GEN Pf, GEN Qf, GEN ff); GEN FqX_to_FFX(GEN x, GEN ff); GEN Fq_to_FF(GEN x, GEN ff); GEN Z_FF_div(GEN a, GEN b); GEN ffembed(GEN a, GEN b); GEN ffextend(GEN a, GEN P, long v); GEN fffrobenius(GEN m, long n); GEN ffgen(GEN T, long v); GEN ffinvmap(GEN m); GEN fflog(GEN x, GEN g, GEN o); GEN ffmap(GEN m, GEN x); GEN ffcompomap(GEN m, GEN n); GEN fforder(GEN x, GEN o); GEN ffprimroot(GEN x, GEN *o); GEN ffrandom(GEN ff); int Rg_is_FF(GEN c, GEN *ff); int RgC_is_FFC(GEN x, GEN *ff); int RgM_is_FFM(GEN x, GEN *ff); GEN p_to_FF(GEN p, long v); GEN Tp_to_FF(GEN T, GEN p); /* galconj.c */ GEN checkgal(GEN gal); GEN checkgroup(GEN g, GEN *S); GEN checkgroupelts(GEN gal); GEN embed_disc(GEN r, long r1, long prec); GEN embed_roots(GEN r, long r1); GEN galois_group(GEN gal); GEN galoisconj(GEN nf, GEN d); GEN galoisconj0(GEN nf, long flag, GEN d, long prec); GEN galoisconjclasses(GEN gal); GEN galoisexport(GEN gal, long format); GEN galoisfixedfield(GEN gal, GEN v, long flag, long y); GEN galoisidentify(GEN gal); GEN galoisinit(GEN nf, GEN den); GEN galoisisabelian(GEN gal, long flag); long galoisisnormal(GEN gal, GEN sub); GEN galoispermtopol(GEN gal, GEN perm); GEN galoissubgroups(GEN G); GEN galoissubfields(GEN G, long flag, long v); long numberofconjugates(GEN T, long pdepart); GEN vandermondeinverse(GEN L, GEN T, GEN den, GEN prep); /* galois.c */ GEN polgalois(GEN x, long prec); /* galpol.c */ GEN galoisnbpol(long a); GEN galoisgetgroup(long a, long b); GEN galoisgetname(long a, long b); GEN galoisgetpol(long a, long b, long s); /* gen1.c */ GEN conj_i(GEN x); GEN conjvec(GEN x,long prec); GEN gadd(GEN x, GEN y); GEN gaddsg(long x, GEN y); GEN gconj(GEN x); GEN gdiv(GEN x, GEN y); GEN gdivgs(GEN x, long s); GEN ginv(GEN x); GEN gmul(GEN x, GEN y); GEN gmul2n(GEN x, long n); GEN gmulsg(long s, GEN y); GEN gsqr(GEN x); GEN gsub(GEN x, GEN y); GEN gsubsg(long x, GEN y); GEN mulcxI(GEN x); GEN mulcxmI(GEN x); GEN mulcxpowIs(GEN x, long k); GEN Qdivii(GEN x1, GEN x2); GEN ser_normalize(GEN x); /* gen2.c */ GEN gassoc_proto(GEN f(GEN,GEN),GEN,GEN); GEN map_proto_G(GEN f(GEN), GEN x); GEN map_proto_lG(long f(GEN), GEN x); GEN map_proto_lGL(long f(GEN,long), GEN x, long y); long Q_pval(GEN x, GEN p); long Q_pvalrem(GEN x, GEN p, GEN *y); long RgX_val(GEN x); long RgX_valrem(GEN x, GEN *z); long RgX_valrem_inexact(GEN x, GEN *Z); int ZV_Z_dvd(GEN v, GEN p); long ZV_pval(GEN x, GEN p); long ZV_pvalrem(GEN x, GEN p, GEN *px); long ZV_lval(GEN x, ulong p); long ZV_lvalrem(GEN x, ulong p, GEN *px); long ZX_lvalrem(GEN x, ulong p, GEN *px); long ZX_lval(GEN x, ulong p); long ZX_pval(GEN x, GEN p); long ZX_pvalrem(GEN x, GEN p, GEN *px); long Z_lval(GEN n, ulong p); long Z_lvalrem(GEN n, ulong p, GEN *py); long Z_lvalrem_stop(GEN *n, ulong p, int *stop); long Z_pval(GEN n, GEN p); long Z_pvalrem(GEN x, GEN p, GEN *py); GEN cgetp(GEN x); GEN cvstop2(long s, GEN y); GEN cvtop(GEN x, GEN p, long l); GEN cvtop2(GEN x, GEN y); int cx_approx_equal(GEN a, GEN b); GEN gabs(GEN x, long prec); void gaffect(GEN x, GEN y); void gaffsg(long s, GEN x); int gcmp(GEN x, GEN y); int gequal0(GEN x); int gequal1(GEN x); int gequalX(GEN x); int gequalm1(GEN x); int gcmpsg(long x, GEN y); GEN gcvtop(GEN x, GEN p, long r); int gequal(GEN x, GEN y); int gequalsg(long s, GEN x); long gexpo(GEN x); long gexpo_safe(GEN x); GEN gpexponent(GEN x); GEN gpvaluation(GEN x, GEN p); long gvaluation(GEN x, GEN p); int gidentical(GEN x, GEN y); long glength(GEN x); GEN gmax(GEN x, GEN y); GEN gmaxgs(GEN x, long y); GEN gmin(GEN x, GEN y); GEN gmings(GEN x, long y); GEN gneg(GEN x); GEN gneg_i(GEN x); int gsigne(GEN x); GEN gtolist(GEN x); long gtolong(GEN x); int lexcmp(GEN x, GEN y); GEN listinsert(GEN list, GEN object, long index); void listpop(GEN L, long index); void listpop0(GEN L, long index); GEN listput(GEN list, GEN object, long index); GEN listput0(GEN list, GEN object, long index); void listsort(GEN list, long flag); GEN matsize(GEN x); GEN mklist(void); GEN mklist_typ(long t); GEN mklistcopy(GEN x); GEN mkmap(void); GEN normalize(GEN x); GEN normalizepol(GEN x); GEN normalizepol_approx(GEN x, long lx); GEN normalizepol_lg(GEN x, long lx); ulong padic_to_Fl(GEN x, ulong p); GEN padic_to_Fp(GEN x, GEN Y); GEN quadtofp(GEN x, long l); long sizedigit(GEN x); long u_lval(ulong x, ulong p); long u_lvalrem(ulong x, ulong p, ulong *py); long u_lvalrem_stop(ulong *n, ulong p, int *stop); long u_pval(ulong x, GEN p); long u_pvalrem(ulong x, GEN p, ulong *py); long vecindexmax(GEN x); long vecindexmin(GEN x); GEN vecmax0(GEN x, GEN *pv); GEN vecmax(GEN x); GEN vecmin0(GEN x, GEN *pv); GEN vecmin(GEN x); long z_lval(long s, ulong p); long z_lvalrem(long s, ulong p, long *py); long z_pval(long n, GEN p); long z_pvalrem(long n, GEN p, long *py); /* Ser.c */ GEN RgX_to_ser(GEN x, long l); GEN RgX_to_ser_inexact(GEN x, long l); GEN gtoser(GEN x, long v, long d); GEN gtoser_prec(GEN x, long v, long d); GEN rfrac_to_ser(GEN x, long l); GEN rfracrecip_to_ser_absolute(GEN R, long l); GEN scalarser(GEN x, long v, long prec); GEN sertoser(GEN x, long prec); GEN toser_i(GEN x); GEN RgV_to_ser(GEN x, long v, long l); GEN Ser0(GEN x, long v, GEN d, long prec); /* gen3.c */ GEN padic_to_Q(GEN x); GEN padic_to_Q_shallow(GEN x); GEN QpV_to_QV(GEN v); GEN RgM_mulreal(GEN x, GEN y); GEN RgX_cxeval(GEN T, GEN u, GEN ui); GEN RgX_deflate_max(GEN x0, long *m); long RgX_deflate_order(GEN x); long ZX_deflate_order(GEN x); GEN ZX_deflate_max(GEN x, long *m); long RgX_degree(GEN x,long v); GEN RgX_integ(GEN x); GEN bitprecision0(GEN x,long n); GEN ceil_safe(GEN x); GEN ceilr(GEN x); GEN centerlift(GEN x); GEN centerlift0(GEN x,long v); GEN compo(GEN x, long n); GEN deg1pol(GEN x1, GEN x0,long v); GEN deg1pol_shallow(GEN x1, GEN x0,long v); GEN deg2pol_shallow(GEN x2, GEN x1, GEN x0,long v); long degree(GEN x); GEN denom(GEN x); GEN denom_i(GEN x); GEN denominator(GEN x, GEN D); GEN deriv(GEN x, long v); GEN derivser(GEN x); GEN diffop(GEN x, GEN v, GEN dv); GEN diffop0(GEN x, GEN v, GEN dv, long n); GEN diviiround(GEN x, GEN y); GEN divrem(GEN x, GEN y, long v); GEN floor_safe(GEN x); GEN gceil(GEN x); GEN gcvtoi(GEN x, long *e); GEN gdeflate(GEN x, long v, long d); GEN gdivent(GEN x, GEN y); GEN gdiventgs(GEN x, long y); GEN gdiventsg(long x, GEN y); GEN gdiventres(GEN x, GEN y); GEN gdivmod(GEN x, GEN y, GEN *pr); GEN gdivround(GEN x, GEN y); int gdvd(GEN x, GEN y); GEN geq(GEN x, GEN y); GEN geval(GEN x); GEN gfloor(GEN x); GEN gtrunc2n(GEN x, long s); GEN gfrac(GEN x); GEN gge(GEN x, GEN y); GEN ggrando(GEN x, long n); GEN ggt(GEN x, GEN y); GEN gimag(GEN x); GEN gisexactzero(GEN g); GEN gle(GEN x, GEN y); GEN glt(GEN x, GEN y); GEN gmod(GEN x, GEN y); GEN gmodgs(GEN x, long y); GEN gmodsg(long x, GEN y); GEN gmodulo(GEN x,GEN y); GEN gmodulsg(long x, GEN y); GEN gmodulss(long x, long y); GEN gne(GEN x, GEN y); GEN gnot(GEN x); GEN gpolvar(GEN y); GEN gppadicprec(GEN x, GEN p); GEN gppoldegree(GEN x, long v); long gprecision(GEN x); GEN gpserprec(GEN x, long v); GEN greal(GEN x); GEN grndtoi(GEN x, long *e); GEN ground(GEN x); GEN gshift(GEN x, long n); GEN gsubst(GEN x, long v, GEN y); GEN gsubstpol(GEN x, GEN v, GEN y); GEN gsubstvec(GEN x, GEN v, GEN y); GEN gtocol(GEN x); GEN gtocol0(GEN x, long n); GEN gtocolrev(GEN x); GEN gtocolrev0(GEN x, long n); GEN gtopoly(GEN x, long v); GEN gtopolyrev(GEN x, long v); GEN gtovec(GEN x); GEN gtovec0(GEN x, long n); GEN gtovecrev(GEN x); GEN gtovecrev0(GEN x, long n); GEN gtovecsmall(GEN x); GEN gtovecsmall0(GEN x, long n); GEN gtrunc(GEN x); long gvar(GEN x); long gvar2(GEN x); GEN hqfeval(GEN q, GEN x); GEN imag_i(GEN x); GEN integ(GEN x, long v); GEN integser(GEN x); GEN ser_inv(GEN b); int iscomplex(GEN x); int isexactzero(GEN g); int isrationalzeroscalar(GEN g); int isinexact(GEN x); int isinexactreal(GEN x); int isint(GEN n, GEN *ptk); int isrationalzero(GEN g); int issmall(GEN n, long *ptk); GEN lift(GEN x); GEN lift_shallow(GEN x); GEN lift0(GEN x,long v); GEN liftall(GEN x); GEN liftall_shallow(GEN x); GEN liftint(GEN x); GEN liftint_shallow(GEN x); GEN liftpol(GEN x); GEN liftpol_shallow(GEN x); GEN mkcoln(long n, ...); GEN mkintn(long n, ...); GEN mkpoln(long n, ...); GEN mkvecn(long n, ...); GEN mkvecsmalln(long n, ...); GEN modRr_safe(GEN x, GEN y); GEN mulreal(GEN x, GEN y); GEN numer(GEN x); GEN numer_i(GEN x); GEN numerator(GEN x, GEN D); long padicprec(GEN x, GEN p); long padicprec_relative(GEN x); GEN polcoef(GEN x, long n, long v); GEN polcoef_i(GEN x, long n, long v); long poldegree(GEN x,long v); GEN poleval(GEN x, GEN y); GEN pollead(GEN x,long v); long precision(GEN x); GEN precision0(GEN x,long n); GEN qf_apply_RgM(GEN q, GEN M); GEN qf_apply_ZM(GEN q, GEN M); GEN qfb_apply_ZM(GEN q, GEN M); GEN qfbil(GEN x, GEN y, GEN q); GEN qfeval(GEN q, GEN x); GEN qfeval0(GEN q, GEN x, GEN y); GEN qfevalb(GEN q, GEN x, GEN y); GEN qfnorm(GEN x, GEN q); GEN real_i(GEN x); GEN round0(GEN x, GEN *pte); GEN roundr(GEN x); GEN roundr_safe(GEN x); GEN scalarpol(GEN x, long v); GEN scalarpol_shallow(GEN x, long v); GEN ser_unscale(GEN P, GEN h); long serprec(GEN x, long v); GEN serreverse(GEN x); GEN simplify(GEN x); GEN simplify_shallow(GEN x); GEN tayl(GEN x, long v, long precdl); GEN trunc0(GEN x, GEN *pte); GEN uu32toi(ulong a, ulong b); GEN uu32toineg(ulong a, ulong b); GEN vars_sort_inplace(GEN z); GEN vars_to_RgXV(GEN h); GEN variables_vecsmall(GEN x); GEN variables_vec(GEN x); /* genus2red.c */ GEN genus2red(GEN PQ, GEN p); /* groupid.c */ long group_ident(GEN G, GEN S); long group_ident_trans(GEN G, GEN S); /* hash.c */ hashtable *hash_create_ulong(ulong s, long stack); hashtable *hash_create_str(ulong s, long stack); hashtable *hash_create(ulong minsize, ulong (*hash)(void*), int (*eq)(void*,void*), int use_stack); void hash_dbg(hashtable *h); int hash_haskey_long(hashtable *h, void *k, long *v); void hash_init_GEN(hashtable *h, ulong minsize, int (*eq)(GEN,GEN), int use_stack); void hash_insert(hashtable *h, void *k, void *v); void hash_insert_long(hashtable *h, void *k, long v); void hash_insert2(hashtable *h, void *k, void *v, ulong hash); GEN hash_keys(hashtable *h); GEN hash_values(hashtable *h); hashentry *hash_search(hashtable *h, void *k); hashentry *hash_search2(hashtable *h, void *k, ulong hash); hashentry *hash_select(hashtable *h, void *k, void *E,int(*select)(void *,hashentry *)); hashentry *hash_remove(hashtable *h, void *k); hashentry *hash_remove_select(hashtable *h, void *k, void *E, int (*select)(void*,hashentry*)); void hash_destroy(hashtable *h); ulong hash_str(const char *str); ulong hash_str2(const char *s); ulong hash_GEN(GEN x); /* hyperell.c */ GEN hyperellpadicfrobenius(GEN x, ulong p, long e); GEN hyperellcharpoly(GEN x); GEN nfhyperellpadicfrobenius(GEN H, GEN T, ulong p, long n); /* hnf_snf.c */ GEN RgM_hnfall(GEN A, GEN *pB, long remove); GEN ZM_hnf(GEN x); GEN ZM_hnf_knapsack(GEN x); GEN ZM_hnfall(GEN A, GEN *ptB, long remove); GEN ZM_hnfall_i(GEN A, GEN *ptB, long remove); GEN ZM_hnfcenter(GEN M); GEN ZM_hnflll(GEN A, GEN *ptB, int remove); GEN ZV_extgcd(GEN A); GEN ZV_snfall(GEN D, GEN *pU, GEN *pV); GEN ZV_snf_group(GEN d, GEN *newU, GEN *newUi); void ZV_snf_trunc(GEN D); GEN ZM_hnfmod(GEN x, GEN d); GEN ZM_hnfmodall(GEN x, GEN dm, long flag); GEN ZM_hnfmodall_i(GEN x, GEN dm, long flag); GEN ZM_hnfmodid(GEN x, GEN d); GEN ZM_hnfmodprime(GEN x, GEN p); GEN ZM_hnfperm(GEN A, GEN *ptU, GEN *ptperm); void ZM_snfclean(GEN d, GEN u, GEN v); GEN ZM_snf(GEN x); GEN ZM_snf_group(GEN H, GEN *newU, GEN *newUi); GEN ZM_snfall(GEN x, GEN *ptU, GEN *ptV); GEN ZM_snfall_i(GEN x, GEN *ptU, GEN *ptV, int return_vec); GEN zlm_echelon(GEN x, long early_abort, ulong p, ulong pm); GEN ZpM_echelon(GEN x, long early_abort, GEN p, GEN pm); GEN gsmith(GEN x); GEN gsmithall(GEN x); GEN hnf(GEN x); GEN hnf_divscale(GEN A, GEN B,GEN t); GEN hnf_invscale(GEN A, GEN t); GEN hnf_solve(GEN A, GEN B); GEN hnf_invimage(GEN A, GEN b); GEN hnfall(GEN x); int hnfdivide(GEN A, GEN B); GEN hnflll(GEN x); GEN hnfmerge_get_1(GEN A, GEN B); GEN hnfmod(GEN x, GEN d); GEN hnfmodid(GEN x,GEN p); GEN hnfperm(GEN x); GEN matfrobenius(GEN M, long flag, long v); GEN mathnf0(GEN x, long flag); GEN matsnf0(GEN x, long flag); GEN smith(GEN x); GEN smithall(GEN x); GEN smithclean(GEN z); /* ifactor1.c */ GEN Z_ECM(GEN N, long rounds, long seed, ulong B1); GEN Z_factor(GEN n); GEN Z_factor_limit(GEN n, ulong all); GEN Z_factor_until(GEN n, GEN limit); long Z_issmooth(GEN m, ulong lim); GEN Z_issmooth_fact(GEN m, ulong lim); long Z_issquarefree(GEN x); GEN Z_pollardbrent(GEN n, long rounds, long seed); GEN absZ_factor(GEN n); GEN absZ_factor_limit(GEN n, ulong all); long bigomega(GEN n); long bigomegau(ulong n); GEN core(GEN n); ulong coreu(ulong n); ulong coreu_fact(GEN f); GEN eulerphi(GEN n); ulong eulerphiu(ulong n); ulong eulerphiu_fact(GEN f); GEN factorint(GEN n, long flag); GEN factoru(ulong n); int ifac_isprime(GEN x); int ifac_next(GEN *part, GEN *p, long *e); int ifac_read(GEN part, GEN *p, long *e); void ifac_skip(GEN part); GEN ifac_start(GEN n, int moebius); int is_357_power(GEN x, GEN *pt, ulong *mask); int is_pth_power(GEN x, GEN *pt, forprime_t *T, ulong cutoffbits); long ispowerful(GEN n); long issquarefree(GEN x); long istotient(GEN n, GEN *px); long moebius(GEN n); long moebiusu(ulong n); long moebiusu_fact(GEN f); GEN nextprime(GEN n); GEN numdiv(GEN n); long numdivu(long N); long numdivu_fact(GEN fa); long omega(GEN n); long omegau(ulong n); GEN precprime(GEN n); GEN sumdiv(GEN n); GEN sumdivk(GEN n,long k); ulong tridiv_bound(GEN n); int uis_357_power(ulong x, ulong *pt, ulong *mask); int uis_357_powermod(ulong x, ulong *mask); long uissquarefree(ulong n); long uissquarefree_fact(GEN f); ulong unextprime(ulong n); ulong uprecprime(ulong n); GEN vecfactorsquarefreeu(ulong a, ulong b); GEN vecfactoru_i(ulong a, ulong b); GEN vecfactoru(ulong a, ulong b); GEN vecfactoroddu_i(ulong a, ulong b); GEN vecfactoroddu(ulong a, ulong b); GEN vecsquarefreeu(ulong a, ulong b); /* init.c */ long timer_delay(pari_timer *T); long timer_get(pari_timer *T); void timer_start(pari_timer *T); int chk_gerepileupto(GEN x); GENbin* copy_bin(GEN x); GENbin* copy_bin_canon(GEN x); void dbg_gerepile(pari_sp av); void dbg_gerepileupto(GEN q); GEN errname(GEN err); GEN gclone(GEN x); GEN gcloneref(GEN x); void gclone_refc(GEN x); GEN gcopy(GEN x); GEN gcopy_avma(GEN x, pari_sp *AVMA); GEN gcopy_lg(GEN x, long lx); GEN gerepile(pari_sp ltop, pari_sp lbot, GEN q); void gerepileallsp(pari_sp av, pari_sp tetpil, int n, ...); void gerepilecoeffssp(pari_sp av, pari_sp tetpil, long *g, int n); void gerepilemanysp(pari_sp av, pari_sp tetpil, GEN* g[], int n); GEN getheap(void); void gp_context_save(struct gp_context* rec); void gp_context_restore(struct gp_context* rec); long gsizeword(GEN x); long gsizebyte(GEN x); void gunclone(GEN x); void gunclone_deep(GEN x); GEN listcopy(GEN x); GEN listinit(GEN x); void timer_printf(pari_timer *T, const char *format, ...); void msgtimer(const char *format, ...); long name_numerr(const char *s); void new_chunk_resize(size_t x); GEN newblock(size_t n); const char * numerr_name(long errnum); GEN obj_check(GEN S, long K); GEN obj_checkbuild(GEN S, long tag, GEN (*build)(GEN)); GEN obj_checkbuild_padicprec(GEN S, long tag, GEN (*build)(GEN,long), long prec); GEN obj_checkbuild_realprec(GEN S, long tag, GEN (*build)(GEN,long), long prec); GEN obj_checkbuild_prec(GEN S, long tag, GEN (*build)(GEN,long), long (*pr)(GEN), long prec); void obj_free(GEN S); GEN obj_init(long d, long n); GEN obj_insert(GEN S, long K, GEN O); GEN obj_insert_shallow(GEN S, long K, GEN O); GEN obj_reinit(GEN S); void (*os_signal(int sig, void (*f)(int)))(int); void pari_add_function(entree *ep); void pari_add_module(entree *ep); void pari_add_defaults_module(entree *ep); void pari_close(void); void pari_close_opts(ulong init_opts); GEN pari_compile_str(const char *lex); int pari_daemon(void); void pari_err(int numerr, ...); GEN pari_err_last(void); char * pari_err2str(GEN err); void pari_init_opts(size_t parisize, ulong maxprime, ulong init_opts); void pari_init(size_t parisize, ulong maxprime); void pari_stackcheck_init(void *pari_stack_base); void pari_sighandler(int sig); void pari_sig_init(void (*f)(int)); void pari_thread_alloc(struct pari_thread *t, size_t s, GEN arg); void pari_thread_close(void); void pari_thread_free(struct pari_thread *t); void pari_thread_init(void); GEN pari_thread_start(struct pari_thread *t); void pari_thread_sync(void); void pari_thread_valloc(struct pari_thread *t, size_t s, size_t v, GEN arg); GEN pari_version(void); void pari_warn(int numerr, ...); void paristack_newrsize(ulong newsize); void paristack_resize(ulong newsize); void paristack_setsize(size_t rsize, size_t vsize); void parivstack_resize(ulong newsize); void parivstack_reset(void); GEN trap0(const char *e, GEN f, GEN r); void shiftaddress(GEN x, long dec); void shiftaddress_canon(GEN x, long dec); long timer(void); long timer2(void); void traverseheap( void(*f)(GEN, void *), void *data ); /* intnum.c */ GEN contfraceval(GEN CF, GEN t, long nlim); GEN contfracinit(GEN M, long lim); GEN intcirc(void *E, GEN (*eval) (void *, GEN), GEN a, GEN R, GEN tab, long prec); GEN intfuncinit(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, long m, long prec); GEN intnum(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, GEN tab, long prec); GEN intnumgauss(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab, long prec); GEN intnumgaussinit(long n, long prec); GEN intnuminit(GEN a, GEN b, long m, long prec); GEN intnumromb(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, long flag, long prec); GEN intnumromb_bitprec(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, long flag, long bit); GEN prodeulerrat(GEN F, GEN s, long a, long prec); GEN prodnumrat(GEN F, long a, long prec); GEN sumeulerrat(GEN F, GEN s, long a, long prec); GEN sumnum(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec); GEN sumnumap(void *E, GEN (*eval)(void*,GEN), GEN a, GEN tab, long prec); GEN sumnumapinit(GEN fast, long prec); GEN sumnuminit(GEN fast, long prec); GEN sumnumlagrangeinit(GEN al, GEN c1, long prec); GEN sumnumlagrange(void *E, GEN (*eval)(void*,GEN,long), GEN a, GEN tab, long prec); GEN sumnummonien(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec); GEN sumnummonieninit(GEN asymp, GEN w, GEN n0, long prec); GEN sumnumrat(GEN F, GEN a, long prec); GEN vecpowuu(long N, ulong B); GEN vecpowug(long N, GEN B, long prec); /* krasner.c */ GEN padicfields0(GEN p, GEN n, long flag); GEN padicfields(GEN p, long m, long d, long flag); /* kummer.c */ GEN rnfkummer(GEN bnr, GEN subgroup, long all, long prec); /* lfun.c */ long is_linit(GEN data); GEN ldata_get_an(GEN ldata); GEN ldata_get_dual(GEN ldata); GEN ldata_get_gammavec(GEN ldata); long ldata_get_degree(GEN ldata); long ldata_get_k(GEN ldata); GEN ldata_get_conductor(GEN ldata); GEN ldata_get_rootno(GEN ldata); GEN ldata_get_residue(GEN ldata); long ldata_get_type(GEN ldata); long ldata_isreal(GEN ldata); GEN ldata_vecan(GEN ldata, long L, long prec); long linit_get_type(GEN linit); GEN linit_get_ldata(GEN linit); GEN linit_get_tech(GEN linit); GEN lfun_get_domain(GEN tech); GEN lfun_get_dom(GEN tech); long lfun_get_bitprec(GEN tech); GEN lfun_get_factgammavec(GEN tech); GEN lfun_get_step(GEN tech); GEN lfun_get_pol(GEN tech); GEN lfun_get_Residue(GEN tech); GEN lfun_get_k2(GEN tech); GEN lfun_get_w2(GEN tech); GEN lfun_get_expot(GEN tech); long lfun_get_bitprec(GEN tech); GEN lfun(GEN ldata, GEN s, long bitprec); GEN lfun0(GEN ldata, GEN s, long der, long bitprec); long lfuncheckfeq(GEN data, GEN t0, long bitprec); GEN lfunconductor(GEN data, GEN maxcond, long flag, long bitprec); GEN lfuncost(GEN lmisc, GEN dom, long der, long bitprec); GEN lfuncost0(GEN L, GEN dom, long der, long bitprec); GEN lfuncreate(GEN obj); GEN lfunan(GEN ldata, long L, long prec); GEN lfunhardy(GEN ldata, GEN t, long bitprec); GEN lfuninit(GEN ldata, GEN dom, long der, long bitprec); GEN lfuninit0(GEN ldata, GEN dom, long der, long bitprec); GEN lfuninit_make(long t, GEN ldata, GEN molin, GEN domain); GEN lfunlambda(GEN ldata, GEN s, long bitprec); GEN lfunlambda0(GEN ldata, GEN s, long der, long bitprec); GEN lfunmisc_to_ldata(GEN ldata); GEN lfunmisc_to_ldata_shallow(GEN ldata); long lfunorderzero(GEN ldata, long m, long bitprec); GEN lfunprod_get_fact(GEN tech); GEN lfunrootno(GEN data, long bitprec); GEN lfunrootres(GEN data, long bitprec); GEN lfunrtopoles(GEN r); GEN lfuntwist(GEN ldata1, GEN ldata2); GEN lfuntheta(GEN data, GEN t, long m, long bitprec); long lfunthetacost0(GEN L, GEN tdom, long m, long bitprec); long lfunthetacost(GEN ldata, GEN tdom, long m, long bitprec); GEN lfunthetainit(GEN ldata, GEN tdom, long m, long bitprec); GEN lfunthetacheckinit(GEN data, GEN tinf, long m, long bitprec); GEN lfunzeros(GEN ldata, GEN lim, long divz, long bitprec); int sdomain_isincl(long k, GEN dom, GEN dom0); GEN theta_get_an(GEN tdata); GEN theta_get_K(GEN tdata); GEN theta_get_R(GEN tdata); long theta_get_bitprec(GEN tdata); long theta_get_m(GEN tdata); GEN theta_get_tdom(GEN tdata); GEN theta_get_sqrtN(GEN tdata); GEN znchargauss(GEN G, GEN chi, GEN a, long bitprec); /* lfunutils.c */ GEN dirzetak(GEN nf, GEN b); GEN ellmoddegree(GEN e); GEN eta_ZXn(long v, long L); GEN eta_product_ZXn(GEN eta, long L); long etaquotype(GEN *eta, GEN *pN, GEN *pk, GEN *CHI, long *pv, long *sd, long *cusp); GEN lfunabelianrelinit(GEN bnfabs, GEN bnf, GEN polrel, GEN dom, long der, long bitprec); GEN lfunartin(GEN N, GEN G, GEN M, long o, long bitprec); GEN lfundiv(GEN ldata1, GEN ldata2, long bitprec); GEN lfunellmfpeters(GEN E, long bitprec); GEN lfunetaquo(GEN eta); GEN lfungenus2(GEN PS); GEN lfunmfspec(GEN lmisc, long bitprec); GEN lfunmul(GEN ldata1, GEN ldata2, long bitprec); GEN lfunqf(GEN ldata, long prec); GEN lfunsympow(GEN E, ulong m); GEN lfunzetakinit(GEN pol, GEN dom, long der, long flag, long bitprec); long qf_iseven(GEN M); /* lll.c */ GEN ZM_lll_norms(GEN x, double D, long flag, GEN *B); GEN kerint(GEN x); GEN lll(GEN x); GEN lllfp(GEN x, double D, long flag); GEN lllgen(GEN x); GEN lllgram(GEN x); GEN lllgramgen(GEN x); GEN lllgramint(GEN x); GEN lllgramkerim(GEN x); GEN lllgramkerimgen(GEN x); GEN lllint(GEN x); GEN lllintpartial(GEN mat); GEN lllintpartial_inplace(GEN mat); GEN lllkerim(GEN x); GEN lllkerimgen(GEN x); GEN matkerint0(GEN x,long flag); GEN qflll0(GEN x, long flag); GEN qflllgram0(GEN x, long flag); /* map.c */ GEN gtomap(GEN M); void mapdelete(GEN T, GEN a); GEN mapdomain(GEN T); GEN mapdomain_shallow(GEN T); GEN mapget(GEN T, GEN a); int mapisdefined(GEN T, GEN a, GEN *pt_z); void mapput(GEN T, GEN a, GEN b); GEN maptomat(GEN T); GEN maptomat_shallow(GEN T); /* matperm.c */ GEN matpermanent(GEN M); GEN zm_permanent(GEN M); GEN ZM_permanent(GEN M); /* mellininv.c */ double dbllambertW0(double a); double dbllambertW_1(double a); double dbllemma526(double a, double b, double c, double B); double dblcoro526(double a, double c, double B); GEN gammamellininv(GEN Vga, GEN s, long m, long bitprec); GEN gammamellininvasymp(GEN Vga, long nlimmax, long m); GEN gammamellininvinit(GEN Vga, long m, long bitprec); GEN gammamellininvrt(GEN K, GEN s, long bitprec); /* members.c */ GEN member_a1(GEN x); GEN member_a2(GEN x); GEN member_a3(GEN x); GEN member_a4(GEN x); GEN member_a6(GEN x); GEN member_area(GEN x); GEN member_b2(GEN x); GEN member_b4(GEN x); GEN member_b6(GEN x); GEN member_b8(GEN x); GEN member_bid(GEN x); GEN member_bnf(GEN x); GEN member_c4(GEN x); GEN member_c6(GEN x); GEN member_clgp(GEN x); GEN member_codiff(GEN x); GEN member_cyc(GEN clg); GEN member_diff(GEN x); GEN member_disc(GEN x); GEN member_e(GEN x); GEN member_eta(GEN x); GEN member_f(GEN x); GEN member_fu(GEN x); GEN member_futu(GEN x); GEN member_gen(GEN x); GEN member_group(GEN x); GEN member_index(GEN x); GEN member_j(GEN x); GEN member_mod(GEN x); GEN member_nf(GEN x); GEN member_no(GEN clg); GEN member_omega(GEN x); GEN member_orders(GEN x); GEN member_p(GEN x); GEN member_pol(GEN x); GEN member_polabs(GEN x); GEN member_reg(GEN x); GEN member_r1(GEN x); GEN member_r2(GEN x); GEN member_roots(GEN x); GEN member_sign(GEN x); GEN member_t2(GEN x); GEN member_tate(GEN x); GEN member_tufu(GEN x); GEN member_tu(GEN x); GEN member_zk(GEN x); GEN member_zkst(GEN bid); /* mftrace.c */ enum { mf_NEW = 0, mf_CUSP, mf_OLD, mf_EISEN, mf_FULL }; enum { /*leaves*/ t_MF_CONST, t_MF_EISEN, t_MF_Ek, t_MF_DELTA, t_MF_ETAQUO, t_MF_ELL, t_MF_DIHEDRAL, t_MF_THETA, t_MF_TRACE, t_MF_NEWTRACE, /**/ t_MF_MUL, t_MF_POW, t_MF_DIV, t_MF_BRACKET, t_MF_LINEAR, t_MF_LINEAR_BHN, t_MF_SHIFT, t_MF_DERIV, t_MF_DERIVE2, t_MF_TWIST, t_MF_HECKE, t_MF_BD, }; GEN MF_get_CHI(GEN mf); GEN MF_get_M(GEN mf); GEN MF_get_Mindex(GEN mf); GEN MF_get_Minv(GEN mf); long MF_get_N(GEN mf); GEN MF_get_basis(GEN mf); long MF_get_dim(GEN mf); GEN MF_get_E(GEN mf); GEN MF_get_fields(GEN mf); GEN MF_get_gN(GEN mf); GEN MF_get_gk(GEN mf); long MF_get_k(GEN mf); GEN MF_get_newforms(GEN mf); long MF_get_r(GEN mf); long MF_get_space(GEN mf); GEN MF_get_S(GEN mf); GEN MFcusp_get_vMjd(GEN mf); GEN MFnew_get_vj(GEN mf); GEN QabV_tracerel(GEN v, long t, GEN x); GEN Qab_trace_init(GEN Pn, long n, long m); GEN checkMF(GEN mf); GEN checkMF_i(GEN mf); int checkmf_i(GEN mf); GEN getcache(void); ulong hclassno6u(ulong d); GEN lfunmf(GEN mf, GEN F, long bitprec); GEN mfDelta(void); GEN mfEH(GEN gk); GEN mfEk(long k); GEN mfTheta(GEN psi); GEN mf_get_CHI(GEN F); long mf_get_N(GEN F); GEN mf_get_NK(GEN F); GEN mf_get_field(GEN F); GEN mf_get_gN(GEN F); GEN mf_get_gk(GEN F); long mf_get_k(GEN F); long mf_get_r(GEN F); long mf_get_type(GEN F); GEN mfatkin(GEN mfa, GEN F); GEN mfatkineigenvalues(GEN mf, long Q, long prec); GEN mfatkininit(GEN mf, long Q, long prec); GEN mfbasis(GEN mf, long space); GEN mfbd(GEN F, long d); GEN mfbracket(GEN F, GEN G, long m); long mfcharorder(GEN CHI); long mfcharmodulus(GEN CHI); GEN mfcharpol(GEN CHI); GEN mfcoef(GEN F, long n); GEN mfcoefs(GEN F, long n, long d); long mfconductor(GEN mf, GEN F); GEN mfcosets(GEN N); long mfcuspdim(long N, long k, GEN CHI); long mfcuspisregular(GEN NK, GEN cusp); GEN mfcusps(GEN gN); GEN mfcuspval(GEN mf, GEN F, GEN cusp, long bitprec); long mfcuspwidth(GEN gN, GEN cusp); GEN mfderiv(GEN F, long m); GEN mfderivE2(GEN F, long k); GEN mfdescribe(GEN F, GEN *PTU); GEN mfdim(GEN NK, long codespace); GEN mfdiv(GEN F, GEN G); GEN mfdiv_val(GEN F, GEN G, long vG); GEN mfeigenbasis(GEN mf); GEN mfeigensearch(GEN nklim, GEN vmod); GEN mfeisenstein(long k, GEN CHI1, GEN CHI2); long mfeisensteindim(long N, long k, GEN CHI); GEN mfembed(GEN E, GEN f); GEN mfembed0(GEN E, GEN v, long prec); GEN mfeval(GEN mf, GEN F, GEN vtau, long bitprec); GEN mffields(GEN mf); GEN mffromell(GEN E); GEN mffrometaquo(GEN eta, long flag); GEN mffromlfun(GEN L, long prec); GEN mffromqf(GEN Q, GEN P); long mffulldim(long N, long k, GEN CHI); GEN mfgaloistype(GEN NK, GEN F); GEN mfhecke(GEN mf, GEN F, long n); GEN mfheckemat(GEN mf, GEN vecn); GEN mfinit(GEN NK, long space); GEN mfisCM(GEN F); long mfiscuspidal(GEN mf, GEN F); long mfisequal(GEN F, GEN G, long lim); GEN mfkohnenbasis(GEN mf); GEN mfkohnenbijection(GEN mf); GEN mfkohneneigenbasis(GEN mf, GEN bij); GEN mflinear(GEN vF, GEN vla); GEN mfmanin(GEN F, long bitprec); GEN mfmatembed(GEN E, GEN f); GEN mfmul(GEN F, GEN G); long mfnewdim(long N, long k, GEN CHI); long mfolddim(long N, long k, GEN CHI); GEN mfparams(GEN F); GEN mfperiodpol(GEN mf, GEN F, long flag, long prec); GEN mfperiodpolbasis(long k, long flag); GEN mfpetersson(GEN FS, GEN GS); GEN mfpow(GEN F, long n); GEN mfsearch(GEN nklim, GEN V, long space); GEN mfshift(GEN F, long sh); GEN mfshimura(GEN mf, GEN F, long t); GEN mfslashexpansion(GEN mf, GEN F, GEN gamma, long n, long flrat, GEN *param, long prec); long mfspace(GEN mf, GEN f); GEN mfsplit(GEN mf, long dimlim, long flag); long mfsturm(GEN A); long mfsturmNgk(long N, GEN k); long mfsturmNk(long N, long k); long mfsturm_mf(GEN mf); GEN mfsymboleval(GEN F, GEN path, GEN ga, long bitprec); GEN mfsymbol(GEN mf, GEN F, long bitprec); GEN mftaylor(GEN F, long n, long flreal, long prec); GEN mftobasis(GEN mf, GEN F, long flag); GEN mftobasisES(GEN mf, GEN F); GEN mftocol(GEN F, long lim, long d); GEN mftocoset(ulong N, GEN M, GEN listcosets); GEN mftonew(GEN mf, GEN F); GEN mftraceform(GEN NK, long coderat); GEN mftwist(GEN F, GEN D); GEN mfvecembed(GEN E, GEN v); GEN mfvectomat(GEN vF, long lim, long d); /* mp.c */ ulong Fl_inv(ulong x, ulong p); ulong Fl_invgen(ulong x, ulong p, ulong *pg); ulong Fl_invsafe(ulong x, ulong p); int Fp_ratlift(GEN x, GEN m, GEN amax, GEN bmax, GEN *a, GEN *b); int abscmpii(GEN x, GEN y); int abscmprr(GEN x, GEN y); int absequalii(GEN x, GEN y); GEN addii_sign(GEN x, long sx, GEN y, long sy); GEN addir_sign(GEN x, long sx, GEN y, long sy); GEN addmulii(GEN x, GEN y, GEN z); GEN addmulii_inplace(GEN x, GEN y, GEN z); GEN addrr_sign(GEN x, long sx, GEN y, long sy); GEN addsi_sign(long x, GEN y, long sy); GEN addsr(long x, GEN y); GEN addui_sign(ulong x, GEN y, long sy); GEN addumului(ulong a, ulong b, GEN Y); void affir(GEN x, GEN y); void affrr(GEN x, GEN y); GEN bezout(GEN a, GEN b, GEN *u, GEN *v); long cbezout(long a,long b,long *uu,long *vv); int cmpii(GEN x, GEN y); int cmprr(GEN x, GEN y); long dblexpo(double x); ulong dblmantissa(double x); GEN dbltor(double x); GEN diviiexact(GEN x, GEN y); GEN divir(GEN x, GEN y); GEN divis(GEN y, long x); GEN divis_rem(GEN x, long y, long *rem); GEN absdiviu_rem(GEN y, ulong x, ulong *rem); GEN diviuuexact(GEN x, ulong y, ulong z); GEN diviuexact(GEN x, ulong y); GEN divri(GEN x, GEN y); GEN divrr(GEN x, GEN y); GEN divrs(GEN x, long y); GEN divru(GEN x, ulong y); GEN divsi(long x, GEN y); GEN divsr(long x, GEN y); GEN divur(ulong x, GEN y); GEN dvmdii(GEN x, GEN y, GEN *z); int equalii(GEN x, GEN y); int equalrr(GEN x, GEN y); GEN floorr(GEN x); GEN gcdii(GEN x, GEN y); GEN int2n(long n); GEN int2u(ulong n); GEN int2um1(ulong n); GEN int_normalize(GEN x, long known_zero_words); int invmod(GEN a, GEN b, GEN *res); ulong invmod2BIL(ulong b); GEN invr(GEN b); GEN mantissa_real(GEN x, long *e); GEN modii(GEN x, GEN y); void modiiz(GEN x, GEN y, GEN z); GEN mulii(GEN x, GEN y); GEN mulir(GEN x, GEN y); GEN mulrr(GEN x, GEN y); GEN mulsi(long x, GEN y); GEN mulsr(long x, GEN y); GEN mulss(long x, long y); GEN mului(ulong x, GEN y); GEN mulur(ulong x, GEN y); GEN muluu(ulong x, ulong y); GEN muluui(ulong x, ulong y, GEN z); void pari_kernel_init(void); void pari_kernel_close(void); GEN remi2n(GEN x, long n); double rtodbl(GEN x); GEN shifti(GEN x, long n); GEN sqri(GEN x); GEN sqrr(GEN x); GEN sqrs(long x); GEN sqrtr_abs(GEN x); GEN sqrtremi(GEN S, GEN *R); GEN sqru(ulong x); GEN subsr(long x, GEN y); GEN truedvmdii(GEN x, GEN y, GEN *z); GEN truedvmdis(GEN x, long y, GEN *z); GEN truedvmdsi(long x, GEN y, GEN *z); GEN trunc2nr(GEN x, long n); GEN mantissa2nr(GEN x, long n); GEN truncr(GEN x); ulong umodiu(GEN y, ulong x); long vals(ulong x); /* nffactor.c */ GEN FpC_ratlift(GEN P, GEN mod, GEN amax, GEN bmax, GEN denom); GEN FpM_ratlift(GEN M, GEN mod, GEN amax, GEN bmax, GEN denom); GEN FpX_ratlift(GEN P, GEN mod, GEN amax, GEN bmax, GEN denom); GEN nffactor(GEN nf,GEN x); GEN nffactormod(GEN nf,GEN pol,GEN pr); GEN nfgcd(GEN P, GEN Q, GEN nf, GEN den); GEN nfgcd_all(GEN P, GEN Q, GEN T, GEN den, GEN *Pnew); int nfissquarefree(GEN nf, GEN x); GEN nfroots(GEN nf,GEN pol); GEN nfroots_if_split(GEN *pnf, GEN pol); GEN polfnf(GEN a, GEN t); GEN rootsof1(GEN x); GEN rootsof1_kannan(GEN nf); /* paricfg.c */ extern const char *paricfg_datadir; extern const char *paricfg_version; extern const char *paricfg_buildinfo; extern const long paricfg_version_code; extern const char *paricfg_vcsversion; extern const char *paricfg_compiledate; extern const char *paricfg_mt_engine; extern const char *paricfg_gphelp; /* part.c */ void forpart(void *E, long call(void*,GEN), long k, GEN nbound, GEN abound); void forpart_init(forpart_t *T, long k, GEN abound, GEN nbound); GEN forpart_next(forpart_t *T); GEN forpart_prev(forpart_t *T); GEN numbpart(GEN x); GEN partitions(long k, GEN nbound, GEN abound); /* forperm.c */ void forperm(void *E, long call(void *, GEN), GEN k); void forperm_init(forperm_t *T, GEN k); GEN forperm_next(forperm_t *T); /* forsubset.c */ void forallsubset_init(forsubset_t *T, long n); void forksubset_init(forsubset_t *T, long n, long k); GEN forsubset_next(forsubset_t *T); void forsubset_init(forsubset_t *T, GEN nk); /* perm.c */ GEN Z_to_perm(long n, GEN x); GEN abelian_group(GEN G); GEN conjclasses_repr(GEN conj, long nb); GEN cyc_pow(GEN cyc, long exp); GEN cyc_pow_perm(GEN cyc, long exp); GEN cyclicgroup(GEN g, long s); GEN dicyclicgroup(GEN g1, GEN g2, long s1, long s2); GEN group_abelianHNF(GEN G, GEN L); GEN group_abelianSNF(GEN G, GEN L); GEN group_elts(GEN G, long n); GEN group_export(GEN G, long format); GEN group_export_GAP(GEN G); GEN group_export_MAGMA(GEN G); GEN group_leftcoset(GEN G, GEN g); GEN group_quotient(GEN G, GEN H); GEN group_rightcoset(GEN G, GEN g); GEN group_set(GEN G, long n); GEN group_subgroups(GEN G); GEN group_to_cc(GEN G); GEN groupelts_abelian_group(GEN S); GEN groupelts_center(GEN S); GEN groupelts_conjclasses(GEN elts, long *nbcl); GEN groupelts_set(GEN G, long n); GEN numtoperm(long n, GEN x); GEN perm_cycles(GEN v); GEN perm_pow(GEN perm, long exp); GEN perm_to_Z(GEN v); GEN permtonum(GEN x); GEN quotient_group(GEN C, GEN G); GEN quotient_perm(GEN C, GEN p); GEN quotient_subgroup_lift(GEN C, GEN H, GEN S); GEN subgroups_tableset(GEN S, long n); GEN trivialgroup(void); GEN vec_insert(GEN v, long n, GEN x); GEN vecperm_orbits(GEN v, long n); GEN vecsmall_indexsort(GEN V); GEN vecsmall_uniq(GEN V); GEN vecsmall_uniq_sorted(GEN V); GEN vecvecsmall_indexsort(GEN x); GEN vecvecsmall_sort(GEN x); GEN vecvecsmall_sort_uniq(GEN x); int perm_commute(GEN p, GEN q); int vec_is1to1(GEN v); int vec_isconst(GEN v); long group_domain(GEN G); long group_isA4S4(GEN G); long group_isabelian(GEN G); long group_order(GEN G); long group_perm_normalize(GEN N, GEN g); long group_subgroup_isnormal(GEN G, GEN H); long groupelts_exponent(GEN G); long perm_order(GEN perm); long perm_sign(GEN perm); long permorder(GEN perm); long permsign(GEN perm); long tableset_find_index(GEN tbl, GEN set); long vecsmall_duplicate(GEN x); long vecsmall_duplicate_sorted(GEN x); long vecvecsmall_max(GEN x); long vecvecsmall_search(GEN x, GEN y, long flag); void vecsmall_sort(GEN V); /* mt.c */ void mt_broadcast(GEN code); void mt_sigint_block(void); void mt_sigint_unblock(void); void mt_queue_end(struct pari_mt *pt); GEN mt_queue_get(struct pari_mt *pt, long *jobid, long *pending); void mt_queue_start(struct pari_mt *pt, GEN worker); void mt_queue_start_lim(struct pari_mt *pt, GEN worker, long lim); void mt_queue_submit(struct pari_mt *pt, long jobid, GEN work); void pari_mt_init(void); void pari_mt_close(void); /* plotport.c */ void color_to_rgb(GEN c, int *r, int *g, int *b); void colorname_to_rgb(const char *s, int *r, int *g, int *b); void long_to_rgb(long c, int *r, int *g, int *b); void pari_plot_by_file(const char *env, const char *suf, const char *img); void pari_set_plot_engine(void (*plot)(PARI_plot *)); void pari_kill_plot_engine(void); void plotbox(long ne, GEN gx2, GEN gy2, long fl); void plotclip(long rect); GEN plotcolor(long ne, GEN c); void plotcopy(long source, long dest, GEN xoff, GEN yoff, long flag); GEN plotcursor(long ne); void plotdraw(GEN list, long flag); GEN plotexport(GEN fmt, GEN wxy, long flag); GEN ploth(void *E, GEN(*f)(void*,GEN), GEN a, GEN b, long flags,long n, long prec); GEN plothexport(GEN fmt, void *E, GEN(*f)(void*,GEN), GEN a,GEN b, long flags, long n, long prec); GEN parploth(GEN a, GEN b, GEN code, long flags,long n, long prec); GEN plothraw(GEN listx, GEN listy, long flag); GEN plothrawexport(GEN fmt, GEN X, GEN Y, long flags); GEN plothsizes(long flag); void plotinit(long ne, GEN x, GEN y, long flag); void plotkill(long ne); void plotline(long ne, GEN gx2, GEN gy2); void plotlines(long ne, GEN listx, GEN listy, long flag); void plotlinetype(long ne, long t); void plotmove(long ne, GEN x, GEN y); void plotpoints(long ne, GEN listx, GEN listy); void plotpointsize(long ne, GEN size); void plotpointtype(long ne, long t); void plotrbox(long ne, GEN x2, GEN y2, long fl); GEN plotrecth(void *E, GEN(*f)(void*,GEN), long ne, GEN a,GEN b, ulong flags,long n, long prec); GEN plotrecthraw(long ne, GEN data, long flags); void plotrline(long ne, GEN x2, GEN y2); void plotrmove(long ne, GEN x, GEN y); void plotrpoint(long ne, GEN x, GEN y); void plotscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2); void plotstring(long ne, char *x, long dir); void psdraw(GEN list, long flag); GEN psploth(void *E, GEN(*f)(void*,GEN), GEN a, GEN b, long flags, long n, long prec); GEN psplothraw(GEN listx, GEN listy, long flag); char* rect2ps(GEN w, GEN x, GEN y, PARI_plot *T); char* rect2ps_i(GEN w, GEN x, GEN y, PARI_plot *T, int plotps); char* rect2svg(GEN w, GEN x, GEN y, PARI_plot *T); /* polarit1.c */ GEN ZX_Zp_root(GEN f, GEN a, GEN p, long prec); GEN Zp_appr(GEN f, GEN a); int cmp_padic(GEN x, GEN y); GEN factorpadic(GEN x, GEN p, long r); GEN gdeuc(GEN x, GEN y); GEN grem(GEN x, GEN y); GEN padicappr(GEN f, GEN a); GEN poldivrem(GEN x, GEN y, GEN *pr); GEN rootpadic(GEN f, GEN p, long r); /* polarit2.c */ GEN FpV_factorback(GEN L, GEN e, GEN p); GEN Q_content(GEN x); GEN Q_content_safe(GEN x); GEN Q_denom(GEN x); GEN Q_denom_safe(GEN x); GEN Q_div_to_int(GEN x, GEN c); GEN Q_gcd(GEN x, GEN y); GEN Q_mul_to_int(GEN x, GEN c); GEN Q_muli_to_int(GEN x, GEN d); GEN Q_primitive_part(GEN x, GEN *ptc); GEN Q_primpart(GEN x); GEN Q_remove_denom(GEN x, GEN *ptd); GEN Q_factor(GEN x); GEN Q_factor_limit(GEN x, ulong lim); long Rg_type(GEN x, GEN *ptp, GEN *ptpol, long *ptpa); long RgM_RgC_type(GEN x, GEN y, GEN *p, GEN *pol, long *pa); GEN RgM_rescale_to_int(GEN x); long RgM_type(GEN x, GEN *p, GEN *pol, long *pa); long RgM_type2(GEN x, GEN y, GEN *p, GEN *pol, long *pa); long RgX_Rg_type(GEN x, GEN y, GEN *p, GEN *pol, long *pa); GEN RgX_rescale_to_int(GEN x); GEN RgX_disc(GEN x); GEN RgX_extgcd(GEN x, GEN y, GEN *U, GEN *V); GEN RgX_extgcd_simple(GEN a, GEN b, GEN *pu, GEN *pv); GEN RgX_gcd(GEN x, GEN y); GEN RgX_gcd_simple(GEN x, GEN y); GEN RgX_resultant_all(GEN P, GEN Q, GEN *sol); long RgX_sturmpart(GEN x, GEN ab); GEN RgX_sylvestermatrix(GEN x, GEN y); long RgX_type(GEN x, GEN *ptp, GEN *ptpol, long *ptpa); long RgX_type2(GEN x, GEN y, GEN *ptp, GEN *ptpol, long *ptpa); long RgX_type3(GEN x, GEN y, GEN z, GEN *ptp, GEN *ptpol, long *ptpa); void RgX_type_decode(long x, long *t1, long *t2); int RgX_type_is_composite(long t); GEN RgXQ_charpoly(GEN x, GEN T, long v); GEN RgXQ_inv(GEN x, GEN y); GEN RgXQ_mul(GEN x, GEN y, GEN T); int RgXQ_ratlift(GEN y, GEN x, long amax, long bmax, GEN *P, GEN *Q); GEN RgXQ_sqr(GEN x, GEN y); GEN Z_content(GEN x); GEN ZX_content(GEN x); GEN centermod(GEN x, GEN p); GEN centermod_i(GEN x, GEN p, GEN ps2); GEN centermodii(GEN x, GEN p, GEN po2); GEN content(GEN x); GEN content0(GEN x, GEN D); GEN deg1_from_roots(GEN L, long v); GEN factor(GEN x); GEN factor0(GEN x, GEN flag); GEN factorback(GEN fa); GEN factorback2(GEN fa,GEN e); GEN gbezout(GEN x, GEN y, GEN *u, GEN *v); GEN gdivexact(GEN x, GEN y); GEN gen_factorback(GEN L, GEN e, GEN (*_mul)(void*,GEN,GEN), GEN (*_pow)(void*,GEN,GEN), void *data); GEN ggcd(GEN x, GEN y); GEN ggcd0(GEN x, GEN y); GEN ginvmod(GEN x, GEN y); GEN glcm(GEN x, GEN y); GEN glcm0(GEN x, GEN y); GEN idealfactorback(GEN nf, GEN L, GEN e, int red); long isirreducible(GEN x); GEN newtonpoly(GEN x, GEN p); GEN nffactorback(GEN nf, GEN L, GEN e); GEN nfrootsQ(GEN x); GEN poldisc0(GEN x, long v); GEN polresultant0(GEN x, GEN y,long v,long flag); GEN polsym(GEN x, long n); GEN primitive_part(GEN x, GEN *c); GEN primpart(GEN x); GEN reduceddiscsmith(GEN pol); GEN resultant2(GEN x, GEN y); GEN resultant(GEN u, GEN v); GEN rnfcharpoly(GEN nf, GEN T, GEN alpha, long v); GEN roots_from_deg1(GEN x); GEN roots_to_pol(GEN a, long v); GEN roots_to_pol_r1(GEN a, long v, long r1); long sturmpart(GEN x, GEN a, GEN b); GEN subresext(GEN x, GEN y, GEN *U, GEN *V); GEN sylvestermatrix(GEN x,GEN y); GEN trivial_fact(void); GEN gcdext0(GEN x, GEN y); GEN polresultantext0(GEN x, GEN y, long v); GEN polresultantext(GEN x, GEN y); GEN prime_fact(GEN x); GEN vec_Q_primpart(GEN M); GEN vecprod(GEN v); /* polarit3.c */ GEN Flx_FlxY_resultant(GEN a, GEN b, ulong pp); GEN FlxX_resultant(GEN u, GEN v, ulong p, long sx); GEN FpX_FpXY_resultant(GEN a, GEN b0, GEN p); GEN FpX_translate(GEN P, GEN c, GEN p); GEN FpXQX_normalize(GEN z, GEN T, GEN p); GEN FpXV_FpC_mul(GEN V, GEN W, GEN p); GEN FpXY_Fq_evaly(GEN Q, GEN y, GEN T, GEN p, long vx); GEN FpXC_center(GEN C, GEN p, GEN pov2); GEN FpXM_center(GEN M, GEN p, GEN pov2); GEN Fq_Fp_mul(GEN x, GEN y, GEN T, GEN p); GEN Fq_add(GEN x, GEN y, GEN T/*unused*/, GEN p); GEN Fq_div(GEN x, GEN y, GEN T, GEN p); GEN Fq_halve(GEN x, GEN T/*unused*/, GEN p); GEN Fq_inv(GEN x, GEN T, GEN p); GEN Fq_invsafe(GEN x, GEN T, GEN p); GEN Fq_mul(GEN x, GEN y, GEN T, GEN p); GEN Fq_mulu(GEN x, ulong y, /*unused*/GEN T, GEN p); GEN Fq_neg(GEN x, GEN T, GEN p); GEN Fq_neg_inv(GEN x, GEN T, GEN p); GEN Fq_pow(GEN x, GEN n, GEN T, GEN p); GEN Fq_powu(GEN x, ulong n, GEN pol, GEN p); GEN Fq_sqr(GEN x, GEN T, GEN p); GEN Fq_sqrt(GEN x, GEN T, GEN p); GEN Fq_sqrtn(GEN x, GEN n, GEN T, GEN p, GEN *zeta); GEN Fq_sub(GEN x, GEN y, GEN T/*unused*/, GEN p); GEN FqC_Fq_mul(GEN x, GEN y, GEN T, GEN p); GEN FqC_add(GEN x, GEN y, GEN T, GEN p); GEN FqC_sub(GEN x, GEN y, GEN T, GEN p); GEN FqC_to_FlxC(GEN v, GEN T, GEN pp); GEN FqM_to_FlxM(GEN x, GEN T, GEN pp); GEN FqV_red(GEN z, GEN T, GEN p); GEN FqV_roots_to_pol(GEN V, GEN T, GEN p, long v); GEN FqV_to_FlxV(GEN v, GEN T, GEN pp); GEN FqX_Fq_add(GEN y, GEN x, GEN T, GEN p); GEN FqX_Fq_mul_to_monic(GEN P, GEN U, GEN T, GEN p); GEN FqX_Fq_sub(GEN y, GEN x, GEN T, GEN p); GEN FqX_eval(GEN x, GEN y, GEN T, GEN p); GEN FqX_translate(GEN P, GEN c, GEN T, GEN p); GEN FqXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, GEN p); GEN FqXQ_powers(GEN x, long l, GEN S, GEN T, GEN p); GEN FqXY_eval(GEN Q, GEN y, GEN x, GEN T, GEN p); GEN FqXY_evalx(GEN Q, GEN x, GEN T, GEN p); GEN QX_disc(GEN x); GEN QX_gcd(GEN a,GEN b); GEN QX_resultant(GEN A, GEN B); GEN QXQ_div_ratlift(GEN C, GEN A, GEN B); GEN QXQ_intnorm(GEN A, GEN B); GEN QXQ_inv(GEN A, GEN B); GEN QXQ_mul(GEN A, GEN B, GEN T); GEN QXQ_norm(GEN A, GEN B); GEN QXQ_sqr(GEN A, GEN B); int Rg_is_Fp(GEN x, GEN *p); int Rg_is_FpXQ(GEN x, GEN *pT, GEN *pp); GEN Rg_to_Fp(GEN x, GEN p); GEN Rg_to_FpXQ(GEN x, GEN T, GEN p); GEN RgC_to_FpC(GEN x, GEN p); GEN RgC_to_FqC(GEN x, GEN T, GEN p); int RgM_is_FpM(GEN x, GEN *p); GEN RgM_to_Flm(GEN x, ulong p); GEN RgM_to_FpM(GEN x, GEN p); GEN RgM_to_FqM(GEN x, GEN T, GEN p); int RgV_is_FpV(GEN x, GEN *p); GEN RgV_to_Flv(GEN x, ulong p); GEN RgV_to_FpV(GEN x, GEN p); int RgX_is_FpX(GEN x, GEN *p); GEN RgX_to_FpX(GEN x, GEN p); int RgX_is_FpXQX(GEN x, GEN *pT, GEN *pp); GEN RgX_to_FpXQX(GEN x, GEN T, GEN p); GEN RgX_to_FqX(GEN x, GEN T, GEN p); int Z_incremental_CRT(GEN *H, ulong Hp, GEN *q, ulong p); GEN Z_init_CRT(ulong Hp, ulong p); int ZM_incremental_CRT(GEN *H, GEN Hp, GEN *q, ulong p); GEN ZM_init_CRT(GEN Hp, ulong p); GEN ZX_ZXY_resultant(GEN a, GEN b); GEN ZX_ZXY_rnfequation(GEN A, GEN B, long *lambda); GEN ZX_disc(GEN x); GEN ZX_gcd(GEN A, GEN B); GEN ZX_gcd_all(GEN A, GEN B, GEN *Anew); int ZX_incremental_CRT(GEN *ptH, GEN Hp, GEN *q, ulong p); GEN ZX_init_CRT(GEN Hp, ulong p, long v); int ZX_is_squarefree(GEN x); GEN ZX_radical(GEN A); GEN ZX_resultant(GEN A, GEN B); int ZXM_incremental_CRT(GEN *pH, GEN Hp, GEN *ptq, ulong p); GEN ZXM_init_CRT(GEN Hp, long deg, ulong p); GEN ZXQ_charpoly(GEN A, GEN T, long v); GEN characteristic(GEN x); GEN ffinit(GEN p, long n, long v); GEN ffnbirred(GEN p, long n); GEN ffnbirred0(GEN p, long n, long flag); GEN ffsumnbirred(GEN p, long n); const struct bb_field *get_Fq_field(void **E, GEN T, GEN p); GEN init_Fq(GEN p, long n, long v); GEN pol_x_powers(long N, long v); GEN residual_characteristic(GEN x); /* polclass.c */ GEN polclass(GEN D, long inv, long xvar); /* polmodular.c */ GEN Fp_modinv_to_j(GEN x, long inv, GEN p); GEN Fp_polmodular_evalx(long L, long inv, GEN J, GEN P, long v, int compute_derivs); void check_modinv(long inv); long disc_best_modinv(long D); long modinv_height_factor(long inv); int modinv_good_disc(long inv, long D); int modinv_good_prime(long inv, long p); int modinv_is_Weber(long inv); int modinv_is_double_eta(long inv); GEN polmodular(long L, long inv, GEN x, long yvar, long compute_derivs); GEN polmodular_ZM(long L, long inv); GEN polmodular_ZXX(long L, long inv, long xvar, long yvar); /* prime.c */ long BPSW_isprime(GEN x); long BPSW_psp(GEN N); GEN addprimes(GEN primes); GEN gisprime(GEN x, long flag); GEN gispseudoprime(GEN x, long flag); GEN gprimepi_upper_bound(GEN x); GEN gprimepi_lower_bound(GEN x); long isprime(GEN x); long ispseudoprime(GEN x, long flag); long millerrabin(GEN n, long k); GEN prime(long n); GEN primecert(GEN x, long flag); GEN primecertexport(GEN cert, long flag); long primecertisvalid(GEN x); GEN primepi(GEN x); double primepi_upper_bound(double x); double primepi_lower_bound(double x); GEN primes(long n); GEN primes_interval(GEN a, GEN b); GEN primes_interval_zv(ulong a, ulong b); GEN primes_upto_zv(ulong b); GEN primes0(GEN n); GEN primes_zv(long m); GEN randomprime(GEN N); GEN removeprimes(GEN primes); int uislucaspsp(ulong n); int uisprime(ulong n); int uisprime_101(ulong n); int uisprime_661(ulong n); ulong uprime(long n); ulong uprimepi(ulong n); /* qfisom.c */ GEN qfauto(GEN g, GEN flags); GEN qfauto0(GEN g, GEN flags); GEN qfautoexport(GEN g, long flag); GEN qfisom(GEN g, GEN h, GEN flags, GEN G); GEN qfisom0(GEN g, GEN h, GEN flags, GEN G); GEN qfisominit(GEN g, GEN flags, GEN minvec); GEN qfisominit0(GEN g, GEN flags, GEN minvec); GEN qforbits(GEN G, GEN V); /* qfparam.c */ GEN qfsolve(GEN G); GEN qfparam(GEN G, GEN sol, long fl); /* random.c */ GEN genrand(GEN N); GEN getrand(void); ulong pari_rand(void); GEN randomi(GEN x); GEN randomr(long prec); ulong random_Fl(ulong n); long random_bits(long k); void setrand(GEN seed); /* ratpoints.c */ GEN ellratpoints(GEN E, GEN h, long flag); GEN hyperellratpoints(GEN P, GEN h, long flag); /* rootpol.c */ GEN QX_complex_roots(GEN p, long l); GEN ZX_graeffe(GEN p); GEN cleanroots(GEN x,long l); double fujiwara_bound(GEN p); double fujiwara_bound_real(GEN p, long sign); int isrealappr(GEN x, long l); GEN polgraeffe(GEN p); GEN polmod_to_embed(GEN x, long prec); GEN polrootsbound(GEN p, GEN tau); GEN roots(GEN x,long l); GEN realroots(GEN P, GEN ab, long prec); long ZX_sturm(GEN P); long ZX_sturmpart(GEN P, GEN ab); GEN ZX_Uspensky(GEN P, GEN ab, long flag, long prec); /* subcyclo.c */ GEN factor_Aurifeuille(GEN p, long n); GEN factor_Aurifeuille_prime(GEN p, long n); GEN galoissubcyclo(GEN N, GEN sg, long flag, long v); GEN polsubcyclo(long n, long d, long v); /* subfield.c */ GEN nfsubfields(GEN nf, long d); /* subgroup.c */ GEN subgrouplist(GEN cyc, GEN bound); void forsubgroup(void *E, long fun(void*,GEN), GEN cyc, GEN B); /* stark.c */ GEN bnrL1(GEN bnr, GEN sbgrp, long flag, long prec); GEN bnrrootnumber(GEN bnr, GEN chi, long flag, long prec); GEN bnrstark(GEN bnr, GEN subgroup, long prec); GEN cyc2elts(GEN cyc); GEN qfbforms(GEN D); /* sumiter.c */ GEN asympnum(void *E, GEN (*f)(void *,GEN,long), long muli, GEN alpha, long prec); GEN derivnum(void *E, GEN (*eval)(void *, GEN, long prec), GEN x, long prec); GEN derivnumk(void *E, GEN (*eval)(void *, GEN, long), GEN x, GEN ind0, long prec); GEN derivfun(void *E, GEN (*eval)(void *, GEN, long prec), GEN x, long prec); GEN derivfunk(void *E, GEN (*eval)(void *, GEN, long), GEN x, GEN ind0, long prec); int forvec_init(forvec_t *T, GEN x, long flag); GEN forvec_next(forvec_t *T); GEN laurentseries(void *E, GEN (*f)(void*,GEN x, long), long M, long v, long prec); GEN limitnum(void *E, GEN (*f)(void *,GEN,long), long muli, GEN alpha, long prec); GEN polzag(long n, long m); GEN prodeuler(void *E, GEN (*eval)(void *, GEN), GEN ga, GEN gb, long prec); GEN prodinf(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); GEN prodinf1(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); GEN sumalt(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); GEN sumalt2(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); GEN sumpos(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); GEN sumpos2(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); GEN suminf(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); GEN zbrent(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, long prec); GEN solvestep(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, GEN step, long flag, long prec); /* thue.c */ GEN bnfisintnorm(GEN x, GEN y); GEN bnfisintnormabs(GEN bnf, GEN a); GEN thue(GEN thueres, GEN rhs, GEN ne); GEN thueinit(GEN pol, long flag, long prec); /* trans1.c */ GEN Pi2n(long n, long prec); GEN PiI2(long prec); GEN PiI2n(long n, long prec); GEN Qp_exp(GEN x); GEN Qp_log(GEN x); GEN Qp_sqrt(GEN x); GEN Qp_sqrtn(GEN x, GEN n, GEN *zetan); long Zn_ispower(GEN a, GEN q, GEN K, GEN *pt); long Zn_issquare(GEN x, GEN n); GEN Zn_sqrt(GEN x, GEN n); GEN Zp_teichmuller(GEN x, GEN p, long n, GEN q); GEN agm(GEN x, GEN y, long prec); GEN constcatalan(long prec); GEN consteuler(long prec); GEN constlog2(long prec); GEN constpi(long prec); GEN cxexpm1(GEN z, long prec); GEN expIr(GEN x); GEN exp1r_abs(GEN x); GEN gcos(GEN x, long prec); GEN gcotan(GEN x, long prec); GEN gcotanh(GEN x, long prec); GEN gexp(GEN x, long prec); GEN gexpm1(GEN x, long prec); GEN glog(GEN x, long prec); GEN glog1p(GEN x, long prec); GEN gpow(GEN x, GEN n, long prec); GEN gpowers(GEN x, long n); GEN gpowers0(GEN x, long n, GEN x0); GEN gpowgs(GEN x, long n); GEN grootsof1(long N, long prec); GEN gsin(GEN x, long prec); GEN gsinc(GEN x, long prec); void gsincos(GEN x, GEN *s, GEN *c, long prec); GEN gsqrpowers(GEN q, long n); GEN gsqrt(GEN x, long prec); GEN gsqrtn(GEN x, GEN n, GEN *zetan, long prec); GEN gtan(GEN x, long prec); GEN logr_abs(GEN x); GEN mpcos(GEN x); GEN mpeuler(long prec); GEN mpcatalan(long prec); void mpsincosm1(GEN x, GEN *s, GEN *c); GEN mpexp(GEN x); GEN mpexpm1(GEN x); GEN mplog(GEN x); GEN mplog2(long prec); GEN mppi(long prec); GEN mpsin(GEN x); void mpsincos(GEN x, GEN *s, GEN *c); GEN powersr(GEN a, long n); GEN powis(GEN x, long n); GEN powiu(GEN p, ulong k); GEN powrfrac(GEN x, long n, long d); GEN powrs(GEN x, long n); GEN powrshalf(GEN x, long s); GEN powru(GEN x, ulong n); GEN powruhalf(GEN x, ulong s); GEN powuu(ulong p, ulong k); GEN powgi(GEN x, GEN n); GEN rootsof1_cx(GEN d, long prec); GEN rootsof1u_cx(ulong d, long prec); GEN rootsof1q_cx(long a, long b, long prec); GEN rootsof1powinit(long a, long b, long prec); GEN rootsof1pow(GEN T, long c); GEN serchop(GEN s, long n); GEN serchop_i(GEN s, long n); GEN serchop0(GEN s); GEN sqrtnint(GEN a, long n); GEN sqrtnr_abs(GEN x, long n); GEN teich(GEN x); GEN teichmullerinit(long p, long n); GEN teichmuller(GEN x, GEN tab); GEN trans_eval(const char *fun, GEN (*f) (GEN, long), GEN x, long prec); ulong upowuu(ulong p, ulong k); ulong usqrtn(ulong a, ulong n); ulong usqrt(ulong a); /* trans2.c */ GEN Qp_gamma(GEN x); GEN bernfrac(long n); GEN bernpol(long k, long v); GEN bernreal(long n, long prec); GEN gacosh(GEN x, long prec); GEN gacos(GEN x, long prec); GEN garg(GEN x, long prec); GEN gasinh(GEN x, long prec); GEN gasin(GEN x, long prec); GEN gatan(GEN x, long prec); GEN gatanh(GEN x, long prec); GEN gcosh(GEN x, long prec); GEN ggammah(GEN x, long prec); GEN ggamma(GEN x, long prec); GEN ggamma1m1(GEN x, long prec); GEN glngamma(GEN x, long prec); GEN gpsi(GEN x, long prec); GEN gsinh(GEN x, long prec); GEN gtanh(GEN x, long prec); void mpbern(long nomb, long prec); GEN mpfactr(long n, long prec); GEN sumformal(GEN T, long v); /* trans3.c */ GEN cxEk(GEN tau, long k, long prec); double dblmodulus(GEN x); GEN dilog(GEN x, long prec); GEN eint1(GEN x, long prec); GEN eta(GEN x, long prec); GEN eta0(GEN x, long flag,long prec); GEN gerfc(GEN x, long prec); GEN glambertW(GEN y, long prec); GEN gpolylog(long m, GEN x, long prec); GEN gzeta(GEN x, long prec); GEN hbessel1(GEN n, GEN z, long prec); GEN hbessel2(GEN n, GEN z, long prec); GEN hyperu(GEN a, GEN b, GEN gx, long prec); GEN ibessel(GEN n, GEN z, long prec); GEN incgam(GEN a, GEN x, long prec); GEN incgam0(GEN a, GEN x, GEN z,long prec); GEN incgamc(GEN a, GEN x, long prec); GEN jbessel(GEN n, GEN z, long prec); GEN jbesselh(GEN n, GEN z, long prec); GEN jell(GEN x, long prec); GEN kbessel(GEN nu, GEN gx, long prec); GEN mpeint1(GEN x, GEN expx); GEN mplambertW(GEN y); GEN mpveceint1(GEN C, GEN eC, long n); GEN nbessel(GEN n, GEN z, long prec); GEN polylog0(long m, GEN x, long flag, long prec); GEN sumdedekind(GEN h, GEN k); GEN sumdedekind_coprime(GEN h, GEN k); GEN szeta(long x, long prec); GEN theta(GEN q, GEN z, long prec); GEN thetanullk(GEN q, long k, long prec); GEN trueeta(GEN x, long prec); GEN u_sumdedekind_coprime(long h, long k); GEN upper_to_cx(GEN x, long *prec); GEN veceint1(GEN nmax, GEN C, long prec); GEN vecthetanullk(GEN q, long k, long prec); GEN vecthetanullk_tau(GEN tau, long k, long prec); GEN veczeta(GEN a, GEN b, long N, long prec); GEN weber0(GEN x, long flag,long prec); GEN weberf(GEN x, long prec); GEN weberf1(GEN x, long prec); GEN weberf2(GEN x, long prec); GEN zetahurwitz(GEN s, GEN x, long der, long bitprec); /* modsym.c */ GEN Qevproj_apply(GEN T, GEN pro); GEN Qevproj_apply_vecei(GEN T, GEN pro, long k); GEN Qevproj_down(GEN T, GEN pro); GEN Qevproj_init(GEN M); GEN RgX_act_Gl2Q(GEN g, long k); GEN RgX_act_ZGl2Q(GEN z, long k); void checkms(GEN W); void checkmspadic(GEN W); GEN mfnumcusps(GEN n); GEN mfnumcusps_fact(GEN fa); ulong mfnumcuspsu_fact(GEN fa); ulong mfnumcuspsu(ulong n); GEN msfromcusp(GEN W, GEN c); GEN msfromell(GEN E, long signe); GEN msfromhecke(GEN W, GEN v, GEN H); long msdim(GEN W); long msgetlevel(GEN W); long msgetsign(GEN W); long msgetweight(GEN W); GEN msatkinlehner(GEN W, long Q, GEN); GEN mscuspidal(GEN W, long flag); GEN mseisenstein(GEN W); GEN mseval(GEN W, GEN s, GEN p); GEN mshecke(GEN W, long p, GEN H); GEN msinit(GEN N, GEN k, long sign); GEN msissymbol(GEN W, GEN s); GEN mslattice(GEN M, GEN F); GEN msomseval(GEN W, GEN phi, GEN path); void mspadic_parse_chi(GEN s, GEN *s1, GEN *s2); GEN mspadic_unit_eigenvalue(GEN ap, long k, GEN p, long n); GEN mspadicinit(GEN W, long p, long n, long flag); GEN mspadicL(GEN oms, GEN s, long r); GEN mspadicmoments(GEN W, GEN phi, long D); GEN mspadicseries(GEN M, long teichi); GEN mspathgens(GEN W); GEN mspathlog(GEN W, GEN path); GEN msnew(GEN W); GEN mspetersson(GEN W, GEN F1, GEN F2); GEN mspolygon(GEN M, long flag); GEN msstar(GEN W, GEN); GEN msqexpansion(GEN W, GEN proV, ulong B); GEN mssplit(GEN W, GEN H, long deglim); GEN mstooms(GEN W, GEN phi); /* zetamult.c */ GEN zetamult(GEN avec, long prec); GEN zetamult0(GEN avec, GEN T, long prec); GEN zetamultall(long k, long prec); GEN zetamultconvert(GEN a, long fl); GEN zetamultinit(long k, long prec); /* level1.h */ INLINE ulong Fl_add(ulong a, ulong b, ulong p); INLINE ulong Fl_addmul_pre(ulong x0, ulong x1, ulong y0, ulong p, ulong pi); INLINE ulong Fl_addmulmul_pre(ulong x0, ulong y0, ulong x1, ulong y1, ulong p, ulong pi); INLINE long Fl_center(ulong u, ulong p, ulong ps2); INLINE ulong Fl_div(ulong a, ulong b, ulong p); INLINE ulong Fl_double(ulong a, ulong p); INLINE ulong Fl_ellj_pre(ulong a4, ulong a6, ulong p, ulong pi); INLINE ulong Fl_halve(ulong y, ulong p); INLINE ulong Fl_mul(ulong a, ulong b, ulong p); INLINE ulong Fl_mul_pre(ulong a, ulong b, ulong p, ulong pi); INLINE ulong Fl_neg(ulong x, ulong p); INLINE ulong Fl_sqr(ulong a, ulong p); INLINE ulong Fl_sqr_pre(ulong a, ulong p, ulong pi); INLINE ulong Fl_sub(ulong a, ulong b, ulong p); INLINE ulong Fl_triple(ulong a, ulong p); INLINE ulong Mod2(GEN x); INLINE ulong Mod4(GEN x); INLINE ulong Mod8(GEN x); INLINE ulong Mod16(GEN x); INLINE ulong Mod32(GEN x); INLINE ulong Mod64(GEN x); INLINE int abscmpiu(GEN x, ulong y); INLINE int abscmpui(ulong x, GEN y); INLINE int absequaliu(GEN x, ulong y); INLINE GEN absi(GEN x); INLINE GEN absi_shallow(GEN x); INLINE GEN absr(GEN x); INLINE int absrnz_equal1(GEN x); INLINE int absrnz_equal2n(GEN x); INLINE GEN addii(GEN x, GEN y); INLINE void addiiz(GEN x, GEN y, GEN z); INLINE GEN addir(GEN x, GEN y); INLINE void addirz(GEN x, GEN y, GEN z); INLINE GEN addis(GEN x, long s); INLINE GEN addri(GEN x, GEN y); INLINE void addriz(GEN x, GEN y, GEN z); INLINE GEN addrr(GEN x, GEN y); INLINE void addrrz(GEN x, GEN y, GEN z); INLINE GEN addrs(GEN x, long s); INLINE GEN addsi(long x, GEN y); INLINE void addsiz(long s, GEN y, GEN z); INLINE void addsrz(long s, GEN y, GEN z); INLINE GEN addss(long x, long y); INLINE void addssz(long s, long y, GEN z); INLINE GEN adduu(ulong x, ulong y); INLINE void affgr(GEN x, GEN y); INLINE void affii(GEN x, GEN y); INLINE void affiz(GEN x, GEN y); INLINE void affrr_fixlg(GEN y, GEN z); INLINE void affsi(long s, GEN x); INLINE void affsr(long s, GEN x); INLINE void affsz(long x, GEN y); INLINE void affui(ulong s, GEN x); INLINE void affur(ulong s, GEN x); INLINE GEN cgetg(long x, long y); INLINE GEN cgetg_block(long x, long y); INLINE GEN cgetg_copy(GEN x, long *plx); INLINE GEN cgeti(long x); INLINE GEN cgetineg(long x); INLINE GEN cgetipos(long x); INLINE GEN cgetr(long x); INLINE GEN cgetr_block(long prec); INLINE int cmpir(GEN x, GEN y); INLINE int cmpis(GEN x, long y); INLINE int cmpiu(GEN x, ulong y); INLINE int cmpri(GEN x, GEN y); INLINE int cmprs(GEN x, long y); INLINE int cmpsi(long x, GEN y); INLINE int cmpsr(long x, GEN y); INLINE int cmpui(ulong x, GEN y); INLINE GEN cxtofp(GEN x, long prec); INLINE GEN divii(GEN a, GEN b); INLINE void diviiz(GEN x, GEN y, GEN z); INLINE void divirz(GEN x, GEN y, GEN z); INLINE void divisz(GEN x, long s, GEN z); INLINE void divriz(GEN x, GEN y, GEN z); INLINE void divrrz(GEN x, GEN y, GEN z); INLINE void divrsz(GEN y, long s, GEN z); INLINE GEN divsi_rem(long x, GEN y, long *rem); INLINE void divsiz(long x, GEN y, GEN z); INLINE void divsrz(long s, GEN y, GEN z); INLINE GEN divss(long x, long y); INLINE GEN divss_rem(long x, long y, long *rem); INLINE void divssz(long x, long y, GEN z); INLINE int dvdii(GEN x, GEN y); INLINE int dvdiiz(GEN x, GEN y, GEN z); INLINE int dvdis(GEN x, long y); INLINE int dvdisz(GEN x, long y, GEN z); INLINE int dvdiu(GEN x, ulong y); INLINE int dvdiuz(GEN x, ulong y, GEN z); INLINE int dvdsi(long x, GEN y); INLINE int dvdui(ulong x, GEN y); INLINE void dvmdiiz(GEN x, GEN y, GEN z, GEN t); INLINE GEN dvmdis(GEN x, long y, GEN *z); INLINE void dvmdisz(GEN x, long y, GEN z, GEN t); INLINE long dvmdsBIL(long n, long *r); INLINE GEN dvmdsi(long x, GEN y, GEN *z); INLINE void dvmdsiz(long x, GEN y, GEN z, GEN t); INLINE GEN dvmdss(long x, long y, GEN *z); INLINE void dvmdssz(long x, long y, GEN z, GEN t); INLINE ulong dvmduBIL(ulong n, ulong *r); INLINE int equalis(GEN x, long y); INLINE int equalsi(long x, GEN y); INLINE int equalui(ulong x, GEN y); INLINE int equaliu(GEN x, ulong y); INLINE int absequalui(ulong x, GEN y); INLINE ulong ceildivuu(ulong a, ulong b); INLINE long evalexpo(long x); INLINE long evallg(long x); INLINE long evalprecp(long x); INLINE long evalvalp(long x); INLINE long expi(GEN x); INLINE long expu(ulong x); INLINE void fixlg(GEN z, long ly); INLINE GEN fractor(GEN x, long prec); INLINE GEN gmax_shallow(GEN x, GEN y); INLINE GEN gmin_shallow(GEN x, GEN y); INLINE GEN icopy(GEN x); INLINE GEN icopyspec(GEN x, long nx); INLINE GEN icopy_avma(GEN x, pari_sp av); INLINE ulong int_bit(GEN x, long n); INLINE GEN itor(GEN x, long prec); INLINE long itos(GEN x); INLINE long itos_or_0(GEN x); INLINE ulong itou(GEN x); INLINE ulong itou_or_0(GEN x); INLINE GEN leafcopy(GEN x); INLINE GEN leafcopy_avma(GEN x, pari_sp av); INLINE double maxdd(double x, double y); INLINE long maxss(long x, long y); INLINE long maxuu(ulong x, ulong y); INLINE double mindd(double x, double y); INLINE long minss(long x, long y); INLINE long minuu(ulong x, ulong y); INLINE long mod16(GEN x); INLINE long mod2(GEN x); INLINE ulong mod2BIL(GEN x); INLINE long mod32(GEN x); INLINE long mod4(GEN x); INLINE long mod64(GEN x); INLINE long mod8(GEN x); INLINE GEN modis(GEN x, long y); INLINE void modisz(GEN y, long s, GEN z); INLINE GEN modsi(long x, GEN y); INLINE void modsiz(long s, GEN y, GEN z); INLINE GEN modss(long x, long y); INLINE void modssz(long s, long y, GEN z); INLINE GEN mpabs(GEN x); INLINE GEN mpabs_shallow(GEN x); INLINE GEN mpadd(GEN x, GEN y); INLINE void mpaddz(GEN x, GEN y, GEN z); INLINE void mpaff(GEN x, GEN y); INLINE GEN mpceil(GEN x); INLINE int mpcmp(GEN x, GEN y); INLINE GEN mpcopy(GEN x); INLINE GEN mpdiv(GEN x, GEN y); INLINE long mpexpo(GEN x); INLINE GEN mpfloor(GEN x); INLINE GEN mpmul(GEN x, GEN y); INLINE void mpmulz(GEN x, GEN y, GEN z); INLINE GEN mpneg(GEN x); INLINE int mpodd(GEN x); INLINE GEN mpround(GEN x); INLINE GEN mpshift(GEN x,long s); INLINE GEN mpsqr(GEN x); INLINE GEN mpsub(GEN x, GEN y); INLINE void mpsubz(GEN x, GEN y, GEN z); INLINE GEN mptrunc(GEN x); INLINE void muliiz(GEN x, GEN y, GEN z); INLINE void mulirz(GEN x, GEN y, GEN z); INLINE GEN mulis(GEN x, long s); INLINE GEN muliu(GEN x, ulong s); INLINE GEN mulri(GEN x, GEN s); INLINE void mulriz(GEN x, GEN y, GEN z); INLINE void mulrrz(GEN x, GEN y, GEN z); INLINE GEN mulrs(GEN x, long s); INLINE GEN mulru(GEN x, ulong s); INLINE void mulsiz(long s, GEN y, GEN z); INLINE void mulsrz(long s, GEN y, GEN z); INLINE void mulssz(long s, long y, GEN z); INLINE GEN negi(GEN x); INLINE GEN negr(GEN x); INLINE GEN new_chunk(size_t x); INLINE GEN rcopy(GEN x); INLINE GEN rdivii(GEN x, GEN y, long prec); INLINE void rdiviiz(GEN x, GEN y, GEN z); INLINE GEN rdivis(GEN x, long y, long prec); INLINE GEN rdivsi(long x, GEN y, long prec); INLINE GEN rdivss(long x, long y, long prec); INLINE GEN real2n(long n, long prec); INLINE GEN real_m2n(long n, long prec); INLINE GEN real_0(long prec); INLINE GEN real_0_bit(long bitprec); INLINE GEN real_1(long prec); INLINE GEN real_1_bit(long bit); INLINE GEN real_m1(long prec); INLINE GEN remii(GEN a, GEN b); INLINE void remiiz(GEN x, GEN y, GEN z); INLINE GEN remis(GEN x, long y); INLINE void remisz(GEN y, long s, GEN z); INLINE ulong remlll_pre(ulong u2, ulong u1, ulong u0, ulong p, ulong pi); INLINE GEN remsi(long x, GEN y); INLINE void remsiz(long s, GEN y, GEN z); INLINE GEN remss(long x, long y); INLINE void remssz(long s, long y, GEN z); INLINE GEN rtor(GEN x, long prec); INLINE long sdivsi(long x, GEN y); INLINE long sdivsi_rem(long x, GEN y, long *rem); INLINE long sdivss_rem(long x, long y, long *rem); INLINE ulong uabsdiviu_rem(GEN n, ulong d, ulong *r); INLINE ulong udivuu_rem(ulong x, ulong y, ulong *r); INLINE ulong umodi2n(GEN x, long n); INLINE void setabssign(GEN x); INLINE void shift_left(GEN z2, GEN z1, long min, long M, ulong f, ulong sh); INLINE void shift_right(GEN z2, GEN z1, long min, long M, ulong f, ulong sh); INLINE ulong shiftl(ulong x, ulong y); INLINE ulong shiftlr(ulong x, ulong y); INLINE GEN shiftr(GEN x, long n); INLINE void shiftr_inplace(GEN z, long d); INLINE long smodis(GEN x, long y); INLINE long smodss(long x, long y); INLINE void stackdummy(pari_sp av, pari_sp ltop); INLINE char *stack_malloc(size_t N); INLINE char *stack_malloc_align(size_t N, long k); INLINE char *stack_calloc(size_t N); INLINE GEN stoi(long x); INLINE GEN stor(long x, long prec); INLINE GEN subii(GEN x, GEN y); INLINE void subiiz(GEN x, GEN y, GEN z); INLINE GEN subir(GEN x, GEN y); INLINE void subirz(GEN x, GEN y, GEN z); INLINE GEN subis(GEN x, long y); INLINE void subisz(GEN y, long s, GEN z); INLINE GEN subri(GEN x, GEN y); INLINE void subriz(GEN x, GEN y, GEN z); INLINE GEN subrr(GEN x, GEN y); INLINE void subrrz(GEN x, GEN y, GEN z); INLINE GEN subrs(GEN x, long y); INLINE void subrsz(GEN y, long s, GEN z); INLINE GEN subsi(long x, GEN y); INLINE void subsiz(long s, GEN y, GEN z); INLINE void subsrz(long s, GEN y, GEN z); INLINE GEN subss(long x, long y); INLINE void subssz(long x, long y, GEN z); INLINE GEN subuu(ulong x, ulong y); INLINE void togglesign(GEN x); INLINE void togglesign_safe(GEN *px); INLINE void affectsign(GEN x, GEN y); INLINE void affectsign_safe(GEN x, GEN *py); INLINE GEN truedivii(GEN a,GEN b); INLINE GEN truedivis(GEN a, long b); INLINE GEN truedivsi(long a, GEN b); INLINE ulong uabsdivui_rem(ulong x, GEN y, ulong *rem); INLINE ulong umodsu(long x, ulong y); INLINE ulong umodui(ulong x, GEN y); INLINE ulong ugcdiu(GEN x, ulong y); INLINE ulong ugcdui(ulong y, GEN x); INLINE ulong umuluu_le(ulong x, ulong y, ulong n); INLINE ulong umuluu_or_0(ulong x, ulong y); INLINE GEN utoi(ulong x); INLINE GEN utoineg(ulong x); INLINE GEN utoipos(ulong x); INLINE GEN utor(ulong s, long prec); INLINE GEN uutoi(ulong x, ulong y); INLINE GEN uutoineg(ulong x, ulong y); INLINE long vali(GEN x); INLINE int varncmp(long x, long y); INLINE long varnmax(long x, long y); INLINE long varnmin(long x, long y); /* pariinl.h */ INLINE GEN abgrp_get_cyc(GEN x); INLINE GEN abgrp_get_gen(GEN x); INLINE GEN abgrp_get_no(GEN x); INLINE GEN bid_get_arch(GEN bid); INLINE GEN bid_get_archp(GEN bid); INLINE GEN bid_get_cyc(GEN bid); INLINE GEN bid_get_fact(GEN bid); INLINE GEN bid_get_gen(GEN bid); INLINE GEN bid_get_gen_nocheck(GEN bid); INLINE GEN bid_get_grp(GEN bid); INLINE GEN bid_get_ideal(GEN bid); INLINE GEN bid_get_mod(GEN bid); INLINE GEN bid_get_no(GEN bid); INLINE GEN bid_get_sarch(GEN bid); INLINE GEN bid_get_sprk(GEN bid); INLINE GEN bid_get_U(GEN bid); INLINE GEN bnf_get_clgp(GEN bnf); INLINE GEN bnf_get_cyc(GEN bnf); INLINE GEN bnf_get_fu(GEN bnf); INLINE GEN bnf_get_fu_nocheck(GEN bnf); INLINE GEN bnf_get_gen(GEN bnf); INLINE GEN bnf_get_logfu(GEN bnf); INLINE GEN bnf_get_nf(GEN bnf); INLINE GEN bnf_get_no(GEN bnf); INLINE GEN bnf_get_reg(GEN bnf); INLINE GEN bnf_get_tuU(GEN bnf); INLINE long bnf_get_tuN(GEN bnf); INLINE GEN bnr_get_bnf(GEN bnr); INLINE GEN bnr_get_clgp(GEN bnr); INLINE GEN bnr_get_cyc(GEN bnr); INLINE GEN bnr_get_gen(GEN bnr); INLINE GEN bnr_get_gen_nocheck(GEN bnr); INLINE GEN bnr_get_no(GEN bnr); INLINE GEN bnr_get_bid(GEN bnr); INLINE GEN bnr_get_mod(GEN bnr); INLINE GEN bnr_get_nf(GEN bnr); INLINE int checkell_i(GEN e); INLINE GEN ell_get_a1(GEN e); INLINE GEN ell_get_a2(GEN e); INLINE GEN ell_get_a3(GEN e); INLINE GEN ell_get_a4(GEN e); INLINE GEN ell_get_a6(GEN e); INLINE GEN ell_get_b2(GEN e); INLINE GEN ell_get_b4(GEN e); INLINE GEN ell_get_b6(GEN e); INLINE GEN ell_get_b8(GEN e); INLINE GEN ell_get_c4(GEN e); INLINE GEN ell_get_c6(GEN e); INLINE GEN ell_get_disc(GEN e); INLINE GEN ell_get_j(GEN e); INLINE long ell_get_type(GEN e); INLINE int ell_is_inf(GEN z); INLINE GEN ellinf(void); INLINE GEN ellff_get_field(GEN x); INLINE GEN ellff_get_a4a6(GEN x); INLINE GEN ellnf_get_nf(GEN x); INLINE GEN ellQp_get_p(GEN E); INLINE long ellQp_get_prec(GEN E); INLINE GEN ellQp_get_zero(GEN x); INLINE long ellR_get_prec(GEN x); INLINE long ellR_get_sign(GEN x); INLINE GEN gal_get_pol(GEN gal); INLINE GEN gal_get_p(GEN gal); INLINE GEN gal_get_e(GEN gal); INLINE GEN gal_get_mod(GEN gal); INLINE GEN gal_get_roots(GEN gal); INLINE GEN gal_get_invvdm(GEN gal); INLINE GEN gal_get_den(GEN gal); INLINE GEN gal_get_group(GEN gal); INLINE GEN gal_get_gen(GEN gal); INLINE GEN gal_get_orders(GEN gal); INLINE GEN idealchineseinit(GEN nf, GEN x); INLINE GEN idealpseudomin(GEN I, GEN G); INLINE GEN idealpseudomin_nonscalar(GEN I, GEN G); INLINE GEN idealpseudored(GEN I, GEN G); INLINE GEN idealred_elt(GEN nf, GEN I); INLINE GEN idealred(GEN nf, GEN I); INLINE long logint(GEN B, GEN y); INLINE ulong ulogint(ulong B, ulong y); INLINE GEN modpr_get_pr(GEN x); INLINE GEN modpr_get_p(GEN x); INLINE GEN modpr_get_T(GEN x); INLINE GEN nf_get_M(GEN nf); INLINE GEN nf_get_G(GEN nf); INLINE GEN nf_get_Tr(GEN nf); INLINE GEN nf_get_diff(GEN nf); INLINE long nf_get_degree(GEN nf); INLINE GEN nf_get_disc(GEN nf); INLINE GEN nf_get_index(GEN nf); INLINE GEN nf_get_invzk(GEN nf); INLINE GEN nf_get_pol(GEN nf); INLINE long nf_get_r1(GEN nf); INLINE long nf_get_r2(GEN nf); INLINE GEN nf_get_ramified_primes(GEN nf); INLINE GEN nf_get_roots(GEN nf); INLINE GEN nf_get_roundG(GEN nf); INLINE void nf_get_sign(GEN nf, long *r1, long *r2); INLINE long nf_get_varn(GEN nf); INLINE GEN nf_get_zk(GEN nf); INLINE GEN nf_get_zkden(GEN nf); INLINE GEN nf_get_zkprimpart(GEN nf); INLINE long pr_get_e(GEN pr); INLINE long pr_get_f(GEN pr); INLINE GEN pr_get_gen(GEN pr); INLINE GEN pr_get_p(GEN pr); INLINE GEN pr_get_tau(GEN pr); INLINE int pr_is_inert(GEN P); INLINE GEN pr_norm(GEN pr); INLINE GEN rnf_get_alpha(GEN rnf); INLINE long rnf_get_absdegree(GEN rnf); INLINE long rnf_get_degree(GEN rnf); INLINE GEN rnf_get_idealdisc(GEN rnf); INLINE GEN rnf_get_invzk(GEN rnf); INLINE GEN rnf_get_k(GEN rnf); INLINE GEN rnf_get_map(GEN rnf); INLINE GEN rnf_get_nf(GEN rnf); INLINE long rnf_get_nfdegree(GEN rnf); INLINE GEN rnf_get_nfpol(GEN rnf); INLINE long rnf_get_nfvarn(GEN rnf); INLINE GEN rnf_get_pol(GEN rnf); INLINE GEN rnf_get_polabs(GEN rnf); INLINE GEN rnf_get_zk(GEN nf); INLINE GEN rnf_get_nfzk(GEN rnf); INLINE long rnf_get_varn(GEN rnf); INLINE ulong upr_norm(GEN pr); INLINE GEN znstar_get_N(GEN G); INLINE GEN znstar_get_conreycyc(GEN G); INLINE GEN znstar_get_conreygen(GEN G); INLINE GEN znstar_get_faN(GEN G); INLINE GEN znstar_get_no(GEN G); INLINE GEN znstar_get_pe(GEN G); INLINE GEN znstar_get_Ui(GEN G); INLINE long closure_arity(GEN C); INLINE const char * closure_codestr(GEN C); INLINE GEN closure_get_code(GEN C); INLINE GEN closure_get_oper(GEN C); INLINE GEN closure_get_data(GEN C); INLINE GEN closure_get_dbg(GEN C); INLINE GEN closure_get_text(GEN C); INLINE GEN closure_get_frame(GEN C); INLINE long closure_is_variadic(GEN C); INLINE GEN addmuliu(GEN x, GEN y, ulong u); INLINE GEN addmuliu_inplace(GEN x, GEN y, ulong u); INLINE GEN lincombii(GEN u, GEN v, GEN x, GEN y); INLINE GEN mulsubii(GEN y, GEN z, GEN x); INLINE GEN submulii(GEN x, GEN y, GEN z); INLINE GEN submuliu(GEN x, GEN y, ulong u); INLINE GEN submuliu_inplace(GEN x, GEN y, ulong u); INLINE GEN FpXQ_add(GEN x,GEN y,GEN T,GEN p); INLINE GEN FpXQ_sub(GEN x,GEN y,GEN T,GEN p); INLINE GEN Flxq_add(GEN x,GEN y,GEN T,ulong p); INLINE GEN Flxq_sub(GEN x,GEN y,GEN T,ulong p); INLINE GEN FpXQX_div(GEN x, GEN y, GEN T, GEN p); INLINE GEN FlxqX_div(GEN x, GEN y, GEN T, ulong p); INLINE GEN F2xqX_div(GEN x, GEN y, GEN T); INLINE GEN Rg_to_Fq(GEN x, GEN T, GEN p); INLINE GEN Fq_red(GEN x, GEN T, GEN p); INLINE GEN Fq_to_FpXQ(GEN x, GEN T, GEN p); INLINE GEN gener_Fq_local(GEN T, GEN p, GEN L); INLINE GEN FqX_Fp_mul(GEN P, GEN U, GEN T, GEN p); INLINE GEN FqX_Fq_mul(GEN P, GEN U, GEN T, GEN p); INLINE GEN FqX_add(GEN x,GEN y,GEN T,GEN p); INLINE GEN FqX_ddf(GEN f, GEN T, GEN p); INLINE GEN FqX_degfact(GEN f, GEN T, GEN p); INLINE GEN FqX_deriv(GEN f, GEN T, GEN p); INLINE GEN FqX_div(GEN x, GEN y, GEN T, GEN p); INLINE GEN FqX_div_by_X_x(GEN x, GEN y, GEN T, GEN p, GEN *z); INLINE GEN FqX_divrem(GEN x, GEN y, GEN T, GEN p, GEN *z); INLINE GEN FqX_extgcd(GEN P,GEN Q,GEN T,GEN p, GEN *U, GEN *V); INLINE GEN FqX_factor(GEN f, GEN T, GEN p); INLINE GEN FqX_factor_squarefree(GEN f, GEN T, GEN p); INLINE GEN FqX_gcd(GEN P, GEN Q, GEN T, GEN p); INLINE GEN FqX_get_red(GEN S, GEN T, GEN p); INLINE GEN FqX_halfgcd(GEN P,GEN Q,GEN T,GEN p); INLINE GEN FqX_halve(GEN x, GEN T, GEN p); INLINE GEN FqX_integ(GEN f, GEN T, GEN p); INLINE GEN FqX_mul(GEN x, GEN y, GEN T, GEN p); INLINE GEN FqX_mulu(GEN x, ulong y, GEN T, GEN p); INLINE GEN FqX_neg(GEN x, GEN T, GEN p); INLINE GEN FqX_normalize(GEN z, GEN T, GEN p); INLINE GEN FqX_powu(GEN x, ulong n, GEN T, GEN p); INLINE GEN FqX_red(GEN z, GEN T, GEN p); INLINE GEN FqX_rem(GEN x, GEN y, GEN T, GEN p); INLINE GEN FqX_roots(GEN f, GEN T, GEN p); INLINE GEN FqX_sqr(GEN x, GEN T, GEN p); INLINE GEN FqX_sub(GEN x,GEN y,GEN T,GEN p); INLINE GEN FqX_to_mod(GEN f, GEN T, GEN p); INLINE GEN FqXQ_add(GEN x, GEN y, GEN S, GEN T, GEN p); INLINE GEN FqXQ_div(GEN x, GEN y, GEN S, GEN T, GEN p); INLINE GEN FqXQ_inv(GEN x, GEN S, GEN T, GEN p); INLINE GEN FqXQ_invsafe(GEN x, GEN S, GEN T, GEN p); INLINE GEN FqXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p); INLINE GEN FqXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p); INLINE GEN FqXQ_sqr(GEN x, GEN S, GEN T, GEN p); INLINE GEN FqXQ_sub(GEN x, GEN y, GEN S, GEN T, GEN p); INLINE GEN FqXn_exp(GEN x, long n, GEN T, GEN p); INLINE GEN FqXn_inv(GEN x, long n, GEN T, GEN p); INLINE GEN FqXn_mul(GEN x, GEN y, long n, GEN T, GEN p); INLINE GEN FqXn_sqr(GEN x, long n, GEN T, GEN p); INLINE long get_F2x_degree(GEN T); INLINE GEN get_F2x_mod(GEN T); INLINE long get_F2x_var(GEN T); INLINE long get_F2xqX_degree(GEN T); INLINE GEN get_F2xqX_mod(GEN T); INLINE long get_F2xqX_var(GEN T); INLINE long get_Flx_degree(GEN T); INLINE GEN get_Flx_mod(GEN T); INLINE long get_Flx_var(GEN T); INLINE long get_FlxqX_degree(GEN T); INLINE GEN get_FlxqX_mod(GEN T); INLINE long get_FlxqX_var(GEN T); INLINE long get_FpX_degree(GEN T); INLINE GEN get_FpX_mod(GEN T); INLINE long get_FpX_var(GEN T); INLINE long get_FpXQX_degree(GEN T); INLINE GEN get_FpXQX_mod(GEN T); INLINE long get_FpXQX_var(GEN T); INLINE ulong F2m_coeff(GEN x, long a, long b); INLINE void F2m_clear(GEN x, long a, long b); INLINE void F2m_flip(GEN x, long a, long b); INLINE void F2m_set(GEN x, long a, long b); INLINE void F2v_clear(GEN x,long v); INLINE ulong F2v_coeff(GEN x,long v); INLINE void F2v_flip(GEN x,long v); INLINE GEN F2v_to_F2x(GEN x, long sv); INLINE void F2v_set(GEN x,long v); INLINE void F2x_clear(GEN x,long v); INLINE ulong F2x_coeff(GEN x,long v); INLINE void F2x_flip(GEN x,long v); INLINE void F2x_set(GEN x,long v); INLINE int F2x_equal1(GEN x); INLINE int F2x_equal(GEN V, GEN W); INLINE GEN F2x_div(GEN x, GEN y); INLINE GEN F2x_renormalize(GEN x, long lx); INLINE GEN F2m_copy(GEN x); INLINE GEN F2v_copy(GEN x); INLINE GEN F2x_copy(GEN x); INLINE GEN F2v_ei(long n, long i); INLINE GEN Flm_copy(GEN x); INLINE GEN Flv_copy(GEN x); INLINE int Flx_equal1(GEN x); INLINE ulong Flx_constant(GEN x); INLINE GEN Flx_copy(GEN x); INLINE GEN Flx_div(GEN x, GEN y, ulong p); INLINE ulong Flx_lead(GEN x); INLINE GEN Flx_mulu(GEN x, ulong a, ulong p); INLINE GEN FpV_FpC_mul(GEN x, GEN y, GEN p); INLINE GEN FpXQX_renormalize(GEN x, long lx); INLINE GEN FpXX_renormalize(GEN x, long lx); INLINE GEN FpX_div(GEN x, GEN y, GEN p); INLINE GEN FpX_renormalize(GEN x, long lx); INLINE GEN Fp_add(GEN a, GEN b, GEN m); INLINE GEN Fp_addmul(GEN x, GEN y, GEN z, GEN p); INLINE GEN Fp_center(GEN u, GEN p, GEN ps2); INLINE GEN Fp_center_i(GEN u, GEN p, GEN ps2); INLINE GEN Fp_div(GEN a, GEN b, GEN m); INLINE GEN Fp_halve(GEN y, GEN p); INLINE GEN Fp_inv(GEN a, GEN m); INLINE GEN Fp_invsafe(GEN a, GEN m); INLINE GEN Fp_mul(GEN a, GEN b, GEN m); INLINE GEN Fp_muls(GEN a, long b, GEN m); INLINE GEN Fp_mulu(GEN a, ulong b, GEN m); INLINE GEN Fp_neg(GEN b, GEN m); INLINE GEN Fp_red(GEN x, GEN p); INLINE GEN Fp_sqr(GEN a, GEN m); INLINE GEN Fp_sub(GEN a, GEN b, GEN m); INLINE GEN GENbinbase(GENbin *p); INLINE GEN Q_abs(GEN x); INLINE GEN Q_abs_shallow(GEN x); INLINE int QV_isscalar(GEN x); INLINE void Qtoss(GEN q, long *n, long *d); INLINE GEN R_abs(GEN x); INLINE GEN R_abs_shallow(GEN x); INLINE GEN RgC_fpnorml2(GEN x, long prec); INLINE GEN RgC_gtofp(GEN x, long prec); INLINE GEN RgC_gtomp(GEN x, long prec); INLINE void RgM_dimensions(GEN x, long *m, long *n); INLINE GEN RgM_fpnorml2(GEN x, long prec); INLINE GEN RgM_gtofp(GEN x, long prec); INLINE GEN RgM_gtomp(GEN x, long prec); INLINE GEN RgM_minor(GEN a, long i, long j); INLINE GEN RgM_shallowcopy(GEN x); INLINE GEN RgV_gtofp(GEN x, long prec); INLINE int RgV_isscalar(GEN x); INLINE int RgV_is_ZV(GEN x); INLINE int RgV_is_QV(GEN x); INLINE long RgX_equal_var(GEN x, GEN y); INLINE int RgX_is_monomial(GEN x); INLINE int RgX_is_rational(GEN x); INLINE int RgX_is_QX(GEN x); INLINE int RgX_is_ZX(GEN x); INLINE int RgX_isscalar(GEN x); INLINE GEN RgX_shift_inplace(GEN x, long v); INLINE void RgX_shift_inplace_init(long v); INLINE GEN RgXQX_div(GEN x, GEN y, GEN T); INLINE GEN RgXQX_rem(GEN x, GEN y, GEN T); INLINE GEN RgX_coeff(GEN x, long n); INLINE GEN RgX_copy(GEN x); INLINE GEN RgX_div(GEN x, GEN y); INLINE GEN RgX_fpnorml2(GEN x, long prec); INLINE GEN RgX_gtofp(GEN x, long prec); INLINE GEN RgX_renormalize(GEN x); INLINE GEN Rg_col_ei(GEN x, long n, long i); INLINE GEN ZC_hnfrem(GEN x, GEN y); INLINE GEN ZM_hnfrem(GEN x, GEN y); INLINE GEN ZM_lll(GEN x, double D, long f); INLINE int ZV_dvd(GEN x, GEN y); INLINE int ZV_isscalar(GEN x); INLINE GEN ZV_to_zv(GEN x); INLINE int ZX_equal1(GEN x); INLINE int ZX_is_monic(GEN x); INLINE GEN ZX_renormalize(GEN x, long lx); INLINE GEN ZXQ_mul(GEN x,GEN y,GEN T); INLINE GEN ZXQ_sqr(GEN x,GEN T); INLINE long Z_ispower(GEN x, ulong k); INLINE long Z_issquare(GEN x); INLINE GEN absfrac(GEN x); INLINE GEN absfrac_shallow(GEN x); INLINE GEN affc_fixlg(GEN x, GEN res); INLINE GEN bin_copy(GENbin *p); INLINE long bit_accuracy(long x); INLINE double bit_accuracy_mul(long x, double y); INLINE long bit_prec(GEN x); INLINE int both_odd(long x, long y); INLINE GEN cbrtr(GEN x); INLINE GEN cbrtr_abs(GEN x); INLINE GEN cgetc(long x); INLINE GEN cgetalloc(long t, size_t l); INLINE void cgiv(GEN x); INLINE GEN col_ei(long n, long i); INLINE GEN const_col(long n, GEN x); INLINE GEN const_vec(long n, GEN x); INLINE GEN const_vecsmall(long n, long c); INLINE GEN constant_coeff(GEN x); INLINE GEN cxcompotor(GEN z, long prec); INLINE GEN cxnorm(GEN x); INLINE GEN cxtoreal(GEN q); INLINE GEN cyclic_perm(long l, long d); INLINE double dbllog2r(GEN x); INLINE long degpol(GEN x); INLINE long divsBIL(long n); INLINE void gabsz(GEN x, long prec, GEN z); INLINE GEN gaddgs(GEN y, long s); INLINE void gaddz(GEN x, GEN y, GEN z); INLINE int gcmpgs(GEN y, long s); INLINE void gdiventz(GEN x, GEN y, GEN z); INLINE GEN gdivsg(long s, GEN y); INLINE void gdivz(GEN x, GEN y, GEN z); INLINE GEN gen_I(void); INLINE void gerepileall(pari_sp av, int n, ...); INLINE void gerepilecoeffs(pari_sp av, GEN x, int n); INLINE GEN gerepilecopy(pari_sp av, GEN x); INLINE void gerepilemany(pari_sp av, GEN* g[], int n); INLINE int gequalgs(GEN y, long s); INLINE GEN gerepileupto(pari_sp av, GEN q); INLINE GEN gerepileuptoint(pari_sp av, GEN q); INLINE GEN gerepileuptoleaf(pari_sp av, GEN q); INLINE GEN gmaxsg(long s, GEN y); INLINE GEN gminsg(long s, GEN y); INLINE void gmodz(GEN x, GEN y, GEN z); INLINE void gmul2nz(GEN x, long s, GEN z); INLINE GEN gmulgs(GEN y, long s); INLINE void gmulz(GEN x, GEN y, GEN z); INLINE void gnegz(GEN x, GEN z); INLINE void gshiftz(GEN x, long s, GEN z); INLINE GEN gsubgs(GEN y, long s); INLINE void gsubz(GEN x, GEN y, GEN z); INLINE double gtodouble(GEN x); INLINE GEN gtofp(GEN z, long prec); INLINE GEN gtomp(GEN z, long prec); INLINE long gtos(GEN x); INLINE long gval(GEN x, long v); INLINE GEN identity_perm(long l); INLINE int equali1(GEN n); INLINE int equalim1(GEN n); INLINE long inf_get_sign(GEN x); INLINE GEN inv_content(GEN c); INLINE int is_bigint(GEN n); INLINE int is_const_t(long t); INLINE int is_extscalar_t(long t); INLINE int is_intreal_t(long t); INLINE int is_matvec_t(long t); INLINE int is_noncalc_t(long tx); INLINE int is_pm1(GEN n); INLINE int is_rational_t(long t); INLINE int is_real_t(long t); INLINE int is_recursive_t(long t); INLINE int is_scalar_t(long t); INLINE int is_universal_constant(GEN x); INLINE int is_vec_t(long t); INLINE int isint1(GEN x); INLINE int isintm1(GEN x); INLINE int isintzero(GEN x); INLINE int ismpzero(GEN x); INLINE int isonstack(GEN x); INLINE void killblock(GEN x); INLINE GEN leading_coeff(GEN x); INLINE void lg_increase(GEN x); INLINE long lgcols(GEN x); INLINE long lgpol(GEN x); INLINE GEN matpascal(long n); INLINE GEN matslice(GEN A, long x1, long x2, long y1, long y2); INLINE GEN mkcol(GEN x); INLINE GEN mkcol2(GEN x, GEN y); INLINE GEN mkcol2s(long x, long y); INLINE GEN mkcol3(GEN x, GEN y, GEN z); INLINE GEN mkcol3s(long x, long y, long z); INLINE GEN mkcol4(GEN x, GEN y, GEN z, GEN t); INLINE GEN mkcol4s(long x, long y, long z, long t); INLINE GEN mkcol5(GEN x, GEN y, GEN z, GEN t, GEN u); INLINE GEN mkcol6(GEN x, GEN y, GEN z, GEN t, GEN u, GEN v); INLINE GEN mkcolcopy(GEN x); INLINE GEN mkcols(long x); INLINE GEN mkcomplex(GEN x, GEN y); INLINE GEN mkerr(long n); INLINE GEN mkmoo(void); INLINE GEN mkoo(void); INLINE GEN mkfrac(GEN x, GEN y); INLINE GEN mkfracss(long x, long y); INLINE GEN mkfraccopy(GEN x, GEN y); INLINE GEN mkintmod(GEN x, GEN y); INLINE GEN mkintmodu(ulong x, ulong y); INLINE GEN mkmat(GEN x); INLINE GEN mkmat2(GEN x, GEN y); INLINE GEN mkmat22(GEN a, GEN b, GEN c, GEN d); INLINE GEN mkmat22s(long a, long b, long c, long d); INLINE GEN mkmat3(GEN x, GEN y, GEN z); INLINE GEN mkmat4(GEN x, GEN y, GEN z, GEN t); INLINE GEN mkmat5(GEN x, GEN y, GEN z, GEN t, GEN u); INLINE GEN mkmatcopy(GEN x); INLINE GEN mkpolmod(GEN x, GEN y); INLINE GEN mkqfi(GEN x, GEN y, GEN z); INLINE GEN mkquad(GEN n, GEN x, GEN y); INLINE GEN mkrfrac(GEN x, GEN y); INLINE GEN mkrfraccopy(GEN x, GEN y); INLINE GEN mkvec(GEN x); INLINE GEN mkvec2(GEN x, GEN y); INLINE GEN mkvec2copy(GEN x, GEN y); INLINE GEN mkvec2s(long x, long y); INLINE GEN mkvec3(GEN x, GEN y, GEN z); INLINE GEN mkvec3s(long x, long y, long z); INLINE GEN mkvec4(GEN x, GEN y, GEN z, GEN t); INLINE GEN mkvec4s(long x, long y, long z, long t); INLINE GEN mkvec5(GEN x, GEN y, GEN z, GEN t, GEN u); INLINE GEN mkveccopy(GEN x); INLINE GEN mkvecs(long x); INLINE GEN mkvecsmall(long x); INLINE GEN mkvecsmall2(long x,long y); INLINE GEN mkvecsmall3(long x,long y,long z); INLINE GEN mkvecsmall4(long x,long y,long z,long t); INLINE void mpcosz(GEN x, GEN z); INLINE void mpexpz(GEN x, GEN z); INLINE void mplogz(GEN x, GEN z); INLINE void mpsinz(GEN x, GEN z); INLINE GEN mul_content(GEN cx, GEN cy); INLINE GEN mul_denom(GEN cx, GEN cy); INLINE long nbits2nlong(long x); INLINE long nbits2extraprec(long x); INLINE long nbits2ndec(long x); INLINE long nbits2prec(long x); INLINE long nbits2lg(long x); INLINE long nbrows(GEN x); INLINE long nchar2nlong(long x); INLINE long ndec2nbits(long x); INLINE long ndec2nlong(long x); INLINE long ndec2prec(long x); INLINE void normalize_frac(GEN z); INLINE int odd(long x); INLINE void pari_free(void *pointer); INLINE void* pari_calloc(size_t size); INLINE void* pari_malloc(size_t bytes); INLINE void* pari_realloc(void *pointer,size_t size); INLINE GEN perm_conj(GEN s, GEN t); INLINE GEN perm_inv(GEN x); INLINE GEN perm_mul(GEN s, GEN t); INLINE GEN pol_0(long v); INLINE GEN pol_1(long v); INLINE GEN pol_x(long v); INLINE GEN pol_xn(long n, long v); INLINE GEN pol_xnall(long n, long v); INLINE GEN pol0_F2x(long sv); INLINE GEN pol1_F2x(long sv); INLINE GEN polx_F2x(long sv); INLINE GEN pol0_Flx(long sv); INLINE GEN pol1_Flx(long sv); INLINE GEN polx_Flx(long sv); INLINE GEN polx_zx(long sv); INLINE GEN powii(GEN x, GEN n); INLINE GEN powIs(long n); INLINE long prec2nbits(long x); INLINE double prec2nbits_mul(long x, double y); INLINE long prec2ndec(long x); INLINE long precdbl(long x); INLINE GEN quad_disc(GEN x); INLINE GEN qfb_disc(GEN x); INLINE GEN qfb_disc3(GEN x, GEN y, GEN z); INLINE GEN quadnorm(GEN q); INLINE long remsBIL(long n); INLINE GEN row(GEN A, long x1); INLINE GEN Flm_row(GEN A, long x0); INLINE GEN row_i(GEN A, long x0, long x1, long x2); INLINE GEN zm_row(GEN x, long i); INLINE GEN rowcopy(GEN A, long x0); INLINE GEN rowpermute(GEN A, GEN p); INLINE GEN rowslice(GEN A, long x1, long x2); INLINE GEN rowslicepermute(GEN A, GEN p, long x1, long x2); INLINE GEN rowsplice(GEN a, long j); INLINE int ser_isexactzero(GEN x); INLINE GEN shallowcopy(GEN x); INLINE GEN sqrfrac(GEN x); INLINE GEN sqrti(GEN x); INLINE GEN sqrtnr(GEN x, long n); INLINE GEN sqrtr(GEN x); INLINE GEN sstoQ(long n, long d); INLINE void pari_stack_alloc(pari_stack *s, long nb); INLINE void** pari_stack_base(pari_stack *s); INLINE void pari_stack_delete(pari_stack *s); INLINE void pari_stack_init(pari_stack *s, size_t size, void **data); INLINE long pari_stack_new(pari_stack *s); INLINE void pari_stack_pushp(pari_stack *s, void *u); INLINE long sturm(GEN x); INLINE GEN truecoef(GEN x, long n); INLINE GEN trunc_safe(GEN x); INLINE GEN vec_ei(long n, long i); INLINE GEN vec_append(GEN v, GEN s); INLINE GEN vec_lengthen(GEN v, long n); INLINE GEN vec_setconst(GEN v, GEN x); INLINE GEN vec_shorten(GEN v, long n); INLINE GEN vec_to_vecsmall(GEN z); INLINE GEN vecpermute(GEN A, GEN p); INLINE GEN vecreverse(GEN A); INLINE void vecreverse_inplace(GEN y); INLINE GEN vecsmallpermute(GEN A, GEN p); INLINE GEN vecslice(GEN A, long y1, long y2); INLINE GEN vecslicepermute(GEN A, GEN p, long y1, long y2); INLINE GEN vecsplice(GEN a, long j); INLINE GEN vecsmall_append(GEN V, long s); INLINE long vecsmall_coincidence(GEN u, GEN v); INLINE GEN vecsmall_concat(GEN u, GEN v); INLINE GEN vecsmall_copy(GEN x); INLINE GEN vecsmall_ei(long n, long i); INLINE long vecsmall_indexmax(GEN x); INLINE long vecsmall_indexmin(GEN x); INLINE long vecsmall_isin(GEN v, long x); INLINE GEN vecsmall_lengthen(GEN v, long n); INLINE int vecsmall_lexcmp(GEN x, GEN y); INLINE long vecsmall_max(GEN v); INLINE long vecsmall_min(GEN v); INLINE long vecsmall_pack(GEN V, long base, long mod); INLINE int vecsmall_prefixcmp(GEN x, GEN y); INLINE GEN vecsmall_prepend(GEN V, long s); INLINE GEN vecsmall_reverse(GEN A); INLINE GEN vecsmall_shorten(GEN v, long n); INLINE GEN vecsmall_to_col(GEN z); INLINE GEN vecsmall_to_vec(GEN z); INLINE GEN vecsmall_to_vec_inplace(GEN z); INLINE void vecsmalltrunc_append(GEN x, long t); INLINE GEN vecsmalltrunc_init(long l); INLINE void vectrunc_append(GEN x, GEN t); INLINE void vectrunc_append_batch(GEN x, GEN y); INLINE GEN vectrunc_init(long l); INLINE GEN coltrunc_init(long l); INLINE GEN zc_to_ZC(GEN x); INLINE GEN zero_F2m(long n, long m); INLINE GEN zero_F2m_copy(long n, long m); INLINE GEN zero_F2v(long m); INLINE GEN zero_F2x(long sv); INLINE GEN zero_Flm(long m, long n); INLINE GEN zero_Flm_copy(long m, long n); INLINE GEN zero_Flv(long n); INLINE GEN zero_Flx(long sv); INLINE GEN zero_zm(long x, long y); INLINE GEN zero_zv(long x); INLINE GEN zero_zx(long sv); INLINE GEN zerocol(long n); INLINE GEN zeromat(long m, long n); INLINE GEN zeromatcopy(long m, long n); INLINE GEN zeropadic(GEN p, long e); INLINE GEN zeropadic_shallow(GEN p, long e); INLINE GEN zeropol(long v); INLINE GEN zeroser(long v, long e); INLINE GEN zerovec(long n); INLINE GEN zerovec_block(long len); INLINE GEN zm_copy(GEN x); INLINE GEN zm_to_zxV(GEN x, long sv); INLINE GEN zm_transpose(GEN x); INLINE GEN zv_copy(GEN x); INLINE GEN zv_to_ZV(GEN x); INLINE GEN zv_to_zx(GEN x, long sv); INLINE GEN zx_renormalize(GEN x, long l); INLINE GEN zx_shift(GEN x, long n); INLINE GEN zx_to_zv(GEN x, long N); INLINE GEN err_get_compo(GEN e, long i); INLINE long err_get_num(GEN e); INLINE void pari_err_BUG(const char *f); INLINE void pari_err_COMPONENT(const char *f, const char *op, GEN l, GEN x); INLINE void pari_err_CONSTPOL(const char *f); INLINE void pari_err_COPRIME(const char *f, GEN x, GEN y); INLINE void pari_err_DIM(const char *f); INLINE void pari_err_DOMAIN(const char *f, const char *v, const char *op, GEN l, GEN x); INLINE void pari_err_FILE(const char *f, const char *g); INLINE void pari_err_FILEDESC(const char *f, long n); INLINE void pari_err_FLAG(const char *f); INLINE void pari_err_IMPL(const char *f); INLINE void pari_err_INV(const char *f, GEN x); INLINE void pari_err_IRREDPOL(const char *f, GEN x); INLINE void pari_err_MAXPRIME(ulong c); INLINE void pari_err_MODULUS(const char *f, GEN x, GEN y); INLINE void pari_err_OP(const char *f, GEN x, GEN y); INLINE void pari_err_OVERFLOW(const char *f); INLINE void pari_err_PACKAGE(const char *f); INLINE void pari_err_PREC(const char *f); INLINE void pari_err_PRIME(const char *f, GEN x); INLINE void pari_err_PRIORITY(const char *f, GEN x, const char *op, long v); INLINE void pari_err_SQRTN(const char *f, GEN x); INLINE void pari_err_TYPE(const char *f, GEN x); INLINE void pari_err_TYPE2(const char *f, GEN x, GEN y); INLINE void pari_err_VAR(const char *f, GEN x, GEN y); INLINE void pari_err_ROOTS0(const char *f); pari-2.11.2/src/headers/paristio.h0000644000175000017500000001774313326135265015405 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file contains memory and I/O management definitions */ typedef struct { long s, us; } pari_timer; typedef struct pari_str { char *string; /* start of the output buffer */ char *end; /* end of the output buffer */ char *cur; /* current writing place in the output buffer */ size_t size; /* buffer size */ int use_stack; /* use stack_malloc instead of malloc ? */ } pari_str; typedef unsigned char *byteptr; typedef ulong pari_sp; struct pari_sieve { ulong start, end, maxpos; ulong c, q; unsigned char* sieve; }; /* iterator over primes */ typedef struct { int strategy; /* 1 to 4 */ GEN bb; /* iterate through primes <= bb */ ulong c, q; /* congruent to c (mod q) */ /* strategy 1: private prime table */ byteptr d; /* diffptr + n */ ulong p; /* current p = n-th prime */ ulong b; /* min(bb, ULONG_MAX) */ /* strategy 2: sieve, use p */ struct pari_sieve *psieve; unsigned char *sieve, *isieve; ulong cache[9]; /* look-ahead primes already computed */ ulong chunk; /* # of odd integers in sieve */ ulong a, end, sieveb; /* [a,end] interval currently being sieved, * end <= sieveb = min(bb, maxprime^2, ULONG_MAX) */ ulong pos, maxpos; /* current cell and max cell */ /* strategy 3: unextprime, use p */ /* strategy 4: nextprime */ GEN pp; } forprime_t; typedef struct { int first; GEN b, n, p; forprime_t T; } forcomposite_t; typedef struct forvec_t { long first; GEN *a, *m, *M; /* current n-uplet, minima, Maxima */ long n; /* length */ GEN (*next)(struct forvec_t *); } forvec_t; /* Iterate over partitions */ typedef struct { long k; long amax, amin, nmin, nmax, strip; GEN v; } forpart_t; /* Iterate over permutations */ typedef struct { long k, first; GEN v; } forperm_t; /* Iterate over subsets */ typedef struct { long n, k, all, first; GEN v; } forsubset_t; /* Plot engines */ typedef struct PARI_plot { void (*draw)(struct PARI_plot *T, GEN w, GEN x, GEN y); long width; long height; long hunit; long vunit; long fwidth; long fheight; long dwidth; long dheight; } PARI_plot; /* binary I/O */ typedef struct GENbin { size_t len; /* gsizeword(x) */ GEN x; /* binary copy of x */ GEN base; /* base address of p->x */ void (*rebase)(GEN,long); } GENbin; struct pari_mainstack { pari_sp top, bot, vbot; size_t size, rsize, vsize, memused; }; extern THREAD struct pari_mainstack *pari_mainstack; struct pari_thread { struct pari_mainstack st; GEN data; }; typedef struct pariFILE { FILE *file; int type; const char *name; struct pariFILE* prev; struct pariFILE* next; } pariFILE; /* pariFILE.type */ enum { mf_IN = 1, mf_PIPE = 2, mf_FALSE = 4, mf_OUT = 8, mf_PERM = 16 }; typedef struct entree { const char *name; ulong valence; void *value; long menu; const char *code; const char *help; void *pvalue; long arity; ulong hash; struct entree *next; } entree; struct pari_parsestate { long node; int once; long discarded; const char *lex_start; GEN lasterror; }; struct pari_compilestate { long opcode, operand, data, localvars, frames, dbginfo; long offset; const char *dbgstart; }; struct pari_evalstate { pari_sp avma; long sp; long rp; long var; long lvars; long prec; long trace; long pending_threads; struct pari_compilestate comp; }; struct pari_varstate { long nvar, max_avail, min_priority, max_priority; }; struct pari_filestate { pariFILE *file; long serial; }; struct gp_context { long listloc; long prettyp; struct pari_varstate var; struct pari_evalstate eval; struct pari_parsestate parse; struct pari_filestate file; jmp_buf *iferr_env; GEN err_data; }; struct mt_state { GEN worker; GEN pending; long workid; }; struct pari_mt { struct mt_state mt; GEN (*get)(struct mt_state *mt, long *workid, long *pending); void (*submit)(struct mt_state *mt, long workid, GEN work); void (*end)(void); }; typedef struct PariOUT { void (*putch)(char); void (*puts)(const char*); void (*flush)(void); } PariOUT; /* hashtables */ typedef struct hashentry { void *key, *val; ulong hash; /* hash(key) */ struct hashentry *next; } hashentry; typedef struct hashtable { ulong len; /* table length */ hashentry **table; /* the table */ ulong nb, maxnb; /* number of entries stored and max nb before enlarging */ ulong pindex; /* prime index */ ulong (*hash) (void *k); /* hash function */ int (*eq) (void *k1, void *k2); /* equality test */ int use_stack; /* use stack_malloc instead of malloc ? */ } hashtable; typedef struct { void **data; long n; long alloc; size_t size; } pari_stack; /* GP_DATA */ typedef struct { GEN z; /* result */ time_t t; /* time to obtain result */ } gp_hist_cell; typedef struct { gp_hist_cell *v; /* array of previous results, FIFO */ size_t size; /* # res */ ulong total; /* # of results computed since big bang */ } gp_hist; /* history */ typedef struct { pariFILE *file; char *cmd; } gp_pp; /* prettyprinter */ typedef struct { char *PATH; char **dirs; } gp_path; /* path */ typedef struct { char format; /* e,f,g */ long sigd; /* -1 (all) or number of significant digits printed */ int sp; /* 0 = suppress whitespace from output */ int prettyp; /* output style: raw, prettyprint, etc */ int TeXstyle; } pariout_t; /* output format */ enum { gpd_QUIET=1, gpd_TEST=2, gpd_EMACS=256, gpd_TEXMACS=512}; enum { DO_MATCHED_INSERT = 2, DO_ARGS_COMPLETE = 4 }; typedef struct { gp_hist *hist; gp_pp *pp; gp_path *path, *sopath; pariout_t *fmt; ulong lim_lines, flags, linewrap, readline_state, echo; int breakloop, recover, use_readline; char *help, *histfile, *prompt, *prompt_cont, *prompt_comment; GEN colormap, graphcolors, plothsizes; int secure, simplify, strictmatch, strictargs, chrono; pari_timer *T; ulong primelimit; /* deprecated */ ulong threadsizemax, threadsize; } gp_data; extern gp_data *GP_DATA; /* Common global variables: */ extern PariOUT *pariOut, *pariErr; extern FILE *pari_outfile, *pari_logfile, *pari_infile, *pari_errfile; extern ulong logstyle; enum logstyles { logstyle_none, /* 0 */ logstyle_plain, /* 1 */ logstyle_color, /* 2 */ logstyle_TeX /* 3 */ }; enum { c_ERR, c_HIST, c_PROMPT, c_INPUT, c_OUTPUT, c_HELP, c_TIME, c_LAST, c_NONE = 0xffffUL }; enum { TEXSTYLE_PAREN=2, TEXSTYLE_BREAK=4 }; extern THREAD pari_sp avma; #define DISABLE_MEMUSED (size_t)-1 extern byteptr diffptr; extern char *current_psfile, *pari_datadir; #define gcopyifstack(x,y) STMT_START {pari_sp _t=(pari_sp)(x); \ (y)=(_t>=pari_mainstack->bot &&_ttop)? \ gcopy((GEN)_t): (GEN)_t;} STMT_END #define copyifstack(x,y) STMT_START {pari_sp _t=(pari_sp)(x); \ (y)=(_t>=pari_mainstack->bot &&_ttop)? \ gcopy((GEN)_t): (GEN)_t;} STMT_END #define icopyifstack(x,y) STMT_START {pari_sp _t=(pari_sp)(x); \ (y)=(_t>=pari_mainstack->bot &&_ttop)? \ icopy((GEN)_t): (GEN)_t;} STMT_END /* Define this to thoroughly check "random" garbage collecting */ #ifdef DEBUG_LOWSTACK # define low_stack(x,l) 1 # define gc_needed(av,n) 1 #else # define low_stack(x,l) ((void)(x),avma < (pari_sp)(l)) # define gc_needed(av,n) (avma < (pari_sp)stack_lim(av,n)) #endif #define stack_lim(av,n) (pari_mainstack->bot+(((av)-pari_mainstack->bot)>>(n))) #ifndef SIG_IGN # define SIG_IGN (void(*)())1 #endif #ifndef SIGINT # define SIGINT 2 #endif pari-2.11.2/src/headers/paricast.h0000644000175000017500000000251713036414402015341 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define mael2(m,x1,x2) (((GEN*) (m))[x1][x2]) #define mael3(m,x1,x2,x3) (((GEN**) (m))[x1][x2][x3]) #define mael4(m,x1,x2,x3,x4) (((GEN***) (m))[x1][x2][x3][x4]) #define mael5(m,x1,x2,x3,x4,x5) (((GEN****)(m))[x1][x2][x3][x4][x5]) #define mael mael2 #define gmael1(m,x1) (((GEN*) (m))[x1]) #define gmael2(m,x1,x2) (((GEN**) (m))[x1][x2]) #define gmael3(m,x1,x2,x3) (((GEN***) (m))[x1][x2][x3]) #define gmael4(m,x1,x2,x3,x4) (((GEN****) (m))[x1][x2][x3][x4]) #define gmael5(m,x1,x2,x3,x4,x5) (((GEN*****)(m))[x1][x2][x3][x4][x5]) #define gmael(m,x,y) gmael2(m,x,y) #define gel(m,x) gmael1(m,x) #define gcoeff(a,i,j) (((GEN**)(a))[j][i]) #define coeff(a,i,j) (((GEN*)(a))[j][i]) #define GSTR(x) ((char*) (((GEN) (x)) + 1 )) pari-2.11.2/src/headers/paripriv.h0000644000175000017500000007140513326135265015402 0ustar billbill/* Copyright (C) 2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ BEGINEXTERN /* for qsort */ typedef int (*QSCOMP)(const void *, const void *); #define uel(a,i) (((ulong*)(a))[i]) #define ucoeff(a,i,j) (((ulong**)(a))[j][i]) #define umael(a,i,j) (((ulong**)(a))[i][j]) #define umael2(a,i,j) (((ulong**)(a))[i][j]) #define umael3(a,i,j,k) (((ulong***)(a))[i][j][k]) #define umael4(a,i,j,k,l) (((ulong****)(a))[i][j][k][l]) #define umael5(a,i,j,k,l,m) (((ulong*****)(a))[i][j][k][l][m]) #define numberof(x) (sizeof(x) / sizeof((x)[0])) /* to manipulate 'blocs' */ #define BL_HEAD 5 #define bl_base(x) (void*)((x) - BL_HEAD) #define bl_size(x) (((GEN)x)[-5]) #define bl_refc(x) (((GEN)x)[-4]) #define bl_next(x) (((GEN*)x)[-3]) #define bl_prev(x) (((GEN*)x)[-2]) #define bl_num(x) (((GEN)x)[-1]) INLINE void clone_lock(GEN C) { if (isclone(C)) ++bl_refc(C); } INLINE void clone_unlock(GEN C) { if (isclone(C)) gunclone(C); } INLINE void clone_unlock_deep(GEN C) { if (isclone(C)) gunclone_deep(C); } /* swap */ #define lswap(x,y) {long _z=x; x=y; y=_z;} #define pswap(x,y) {GEN *_z=x; x=y; y=_z;} #define swap(x,y) {GEN _z=x; x=y; y=_z;} #define dswap(x,y) { double _t=x; x=y; y=_t; } #define pdswap(x,y) { double* _t=x; x=y; y=_t; } #define swapspec(x,y, nx,ny) {swap(x,y); lswap(nx,ny);} /* loops */ GEN incloop(GEN a); GEN resetloop(GEN a, GEN b); GEN setloop(GEN a); /* parser */ /* GP control structures */ #define EXPR_WRAP(code, call) \ { GEN z; GEN __E = code; \ push_lex(gen_0, __E); z = call; pop_lex(1); return z; } #define EXPR_ARG __E, &gp_eval #define EXPR_ARGPREC __E, &gp_evalprec #define EXPR_ARGUPTO __E, &gp_evalupto #define EXPR_ARGBOOL __E, &gp_evalbool GEN iferrpari(GEN a, GEN b, GEN c); void forfactored(GEN a, GEN b, GEN code); void forpari(GEN a, GEN b, GEN node); void forsquarefree(GEN a, GEN b, GEN code); void untilpari(GEN a, GEN b); void whilepari(GEN a, GEN b); GEN ifpari(GEN g, GEN a, GEN b); GEN andpari(GEN a, GEN b); GEN orpari(GEN a, GEN b); void ifpari_void(GEN g, GEN a, GEN b); GEN ifpari_multi(GEN g, GEN a); GEN geval_gp(GEN x, GEN t); GEN gadde(GEN *x, GEN y); GEN gadd1e(GEN *x); GEN gdive(GEN *x, GEN y); GEN gdivente(GEN *x, GEN y); GEN gdivrounde(GEN *x, GEN y); GEN gmode(GEN *x, GEN y); GEN gmule(GEN *x, GEN y); GEN gshiftle(GEN *x, long n); GEN gshiftre(GEN *x, long n); GEN gsube(GEN *x, GEN y); GEN gsub1e(GEN *x); GEN gshift_right(GEN x, long n); GEN asympnum0(GEN u, long muli, GEN alpha, long prec); GEN derivnum0(GEN a, GEN code, GEN ind, long prec); GEN derivfun0(GEN code, GEN args, long prec); GEN direuler0(GEN a, GEN b, GEN code, GEN c); GEN direuler_bad(void *E, GEN (*eval)(void *, GEN, long), GEN a, GEN b, GEN c, GEN Sbad); void forcomposite(GEN a, GEN b, GEN code); void fordiv(GEN a, GEN code); void fordivfactored(GEN a, GEN code); void forell0(long a, long b, GEN code, long flag); void forperm0(GEN k, GEN code); void forprime(GEN a, GEN b, GEN code); void forprimestep(GEN a, GEN b, GEN q, GEN code); void forstep(GEN a, GEN b, GEN s, GEN code); void forsubgroup0(GEN cyc, GEN bound, GEN code); void forsubset0(GEN nk, GEN code); void forvec(GEN x, GEN code, long flag); void forpart0(GEN k, GEN code , GEN nbound, GEN abound); GEN intcirc0(GEN a, GEN R, GEN code, GEN tab, long prec); GEN intfuncinit0(GEN a, GEN b, GEN code, long m, long prec); GEN intnum0(GEN a, GEN b, GEN code, GEN tab, long prec); GEN intnumgauss0(GEN a, GEN b, GEN code, GEN tab, long prec); GEN intnumromb0_bitprec(GEN a, GEN b, GEN code, long flag, long bit); GEN laurentseries0(GEN f, long M, long v, long prec); GEN limitnum0(GEN u, long muli, GEN alpha, long prec); GEN matrice(GEN nlig, GEN ncol, GEN code); void pariplot(GEN a, GEN b, GEN code, GEN ysmlu, GEN ybigu, long prec); GEN prodeuler0(GEN a, GEN b, GEN code, long prec); GEN prodinf0(GEN a, GEN code, long flag, long prec); GEN produit(GEN a, GEN b, GEN code, GEN x); GEN somme(GEN a, GEN b, GEN code, GEN x); GEN sumalt0(GEN a, GEN code,long flag, long prec); GEN sumdivexpr(GEN num, GEN code); GEN sumdivmultexpr(GEN num, GEN code); GEN suminf0(GEN a, GEN code, long prec); GEN sumnum0(GEN a, GEN code, GEN tab, long prec); GEN sumnumap0(GEN a, GEN code, GEN tab, long prec); GEN sumnumlagrange0(GEN a, GEN code, GEN tab, long prec); GEN sumnummonien0(GEN a, GEN code, GEN tab, long prec); GEN sumpos0(GEN a, GEN code, long flag,long prec); GEN vecexpr0(GEN nmax, GEN code, GEN pred); GEN vecexpr1(GEN nmax, GEN code, GEN pred); GEN vecteursmall(GEN nmax, GEN code); GEN vecteur(GEN nmax, GEN n); GEN vvecteur(GEN nmax, GEN n); GEN zbrent0(GEN a, GEN b, GEN code, long prec); GEN solvestep0(GEN a, GEN b, GEN step, GEN code, long flag, long prec); GEN ploth0(GEN a, GEN b, GEN code, long flag, long n, long prec); GEN plothexport0(GEN fmt, GEN a, GEN b, GEN code, long flags, long n, long prec); GEN psploth0(GEN a,GEN b,GEN code,long flag,long n,long prec); GEN plotrecth0(long ne,GEN a,GEN b,GEN code,ulong flags,long n,long prec); GEN listcreate_gp(long n); /* mt */ void mt_sigint(void); void mt_err_recover(long er); void mt_init_stack(size_t s); int mt_is_thread(void); GEN pareval_worker(GEN code); GEN parselect_worker(GEN d, GEN code); void parfor0(GEN a, GEN b, GEN code, GEN code2); GEN parfor_worker(GEN i, GEN C); void parforprime0(GEN a, GEN b, GEN code, GEN code2); void parforvec0(GEN a, GEN code, GEN code2, long flag); GEN parvector_worker(GEN i, GEN C); GEN polmodular_worker(ulong p, ulong t, ulong L, GEN hilb, GEN factu, GEN vne, GEN vinfo, long compute_derivs, GEN j_powers, GEN fdb); GEN nmV_polint_center_tree_worker(GEN Va, GEN T, GEN R, GEN xa, GEN m2); GEN nmV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R); GEN nxMV_polint_center_tree_worker(GEN Va, GEN T, GEN R, GEN xa, GEN m2); GEN nxMV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R); GEN F2xq_log_Coppersmith_worker(GEN u, long i, GEN V, GEN R); GEN Flxq_log_Coppersmith_worker(GEN u, long i, GEN V, GEN R); GEN Fp_log_sieve_worker(long a, long prmax, GEN C, GEN c, GEN Ci, GEN ci, GEN pr, GEN sz); GEN ZX_resultant_worker(GEN P, GEN A, GEN B, GEN dB); GEN ZX_ZXY_resultant_worker(GEN P, GEN A, GEN B, GEN dB, GEN v); GEN ZM_det_worker(GEN P, GEN A); GEN ZM_inv_worker(GEN P, GEN A); GEN ZabM_inv_worker(GEN P, GEN A, GEN Q); GEN aprcl_step4_worker(ulong q, GEN pC, GEN N, GEN v); GEN aprcl_step6_worker(GEN r, long t, GEN N, GEN N1, GEN et); GEN gen_parapply(GEN worker, GEN D); GEN gen_crt(const char *str, GEN worker, GEN dB, ulong bound, long mmin, GEN *pt_mod, GEN crt(GEN, GEN, GEN*), GEN center(GEN, GEN, GEN)); void gen_inccrt(const char *str, GEN worker, GEN dB, long n, long mmin, ulong *p, GEN *pt_H, GEN *pt_mod, GEN crt(GEN, GEN, GEN*), GEN center(GEN, GEN, GEN)); /* Relative number fields */ enum { rnf_NFABS = 1, rnf_MAPS }; /* Finite fields */ enum { t_FF_FpXQ = 0, t_FF_Flxq = 1, t_FF_F2xq = 2 }; GEN FF_ellinit(GEN E, GEN fg); GEN FF_elldata(GEN E, GEN fg); /* L functions */ enum { t_LFUN_GENERIC, t_LFUN_ZETA, t_LFUN_NF, t_LFUN_ELL, t_LFUN_KRONECKER, t_LFUN_CHIZ, t_LFUN_CHIGEN, t_LFUN_ETA, t_LFUN_DIV, t_LFUN_MUL, t_LFUN_CONJ, t_LFUN_SYMPOW_ELL, t_LFUN_QF, t_LFUN_ARTIN, t_LFUN_MFCLOS, t_LFUN_GENUS2, t_LFUN_TWIST}; enum { t_LDESC_INIT, t_LDESC_THETA, t_LDESC_PRODUCT }; /* Elliptic curves */ /* common to Q and Rg */ enum { R_PERIODS = 1, R_ETA, R_ROOTS, R_AB }; enum { Qp_ROOT = 1, Qp_TATE }; enum { Q_GROUPGEN = 5, Q_GLOBALRED, Q_ROOTNO, Q_MINIMALMODEL }; enum { NF_MINIMALMODEL = 1, NF_GLOBALRED, NF_MINIMALPRIMES, NF_ROOTNO, NF_NF }; /* common to Fp and Fq */ enum { FF_CARD = 1, FF_GROUP, FF_GROUPGEN, FF_O }; /* for Buchall_param */ enum { fupb_NONE = 0, fupb_RELAT, fupb_LARGE, fupb_PRECI }; /* Polycyclic presentation for the classgroup of discriminant D */ typedef struct { long D; /* Negative discriminant */ long h; /* Size of classgroup */ long enum_cnt; /* Either h or h/2 (if L0 is set) */ /* If nonzero, L0=L[0] and n[0]=2 and classpoly is a perfect square * (and we enumerate each double root just once), default is 0 */ long L0; /* Product of primes L that are prohibited as norms of generators or * auxilliary prime forms (by default, primes that make enumeration hard) */ long Lfilter; /* Norms of implicit generators (primeforms a=(L*x^2+b*x*y+c*y^2) * with norm L and b >=0) */ long *L; long *m; /* products of relative orders: m[i] is the order of */ long *n; /* Relative orders */ long *o; /* Absolute orders */ /* Power relations (a[i]^n[i] = a[0]^e[0]*...*a[i-1]^e[i-1], where e * is an exponent vector of length i stored at offset binom(i,2) of r) */ long *r; long *orient_p; /* Optional list of norms of orienting primes p ... */ long *orient_q; /* or product of primes p*q (q=1 when only p is needed) */ long *orient_reps; /* Representation of orienting norm p*q in terms of Ls */ long inv; /* Attached invariant */ long k; /* Number of generators */ GEN _data; /* Storage space for the above arrays */ } classgp_pcp_struct; typedef classgp_pcp_struct classgp_pcp_t[1]; /* Represents the data in the equation(s) * 4p = t^2 - v^2 D = t^2 - v^2 u^2 D_K = w^2 D_K. * t is the absolute trace, so always > 0. * T is a twisting parameter, which satisfies (T|p) == -1. */ typedef struct { long D, t, u, v; ulong p, pi, s2, T; } norm_eqn_struct; typedef norm_eqn_struct norm_eqn_t[1]; #define zv_to_longptr(v) (&((v)[1])) #define zv_to_ulongptr(v) ((ulong *)&((v)[1])) /* Modular invariants */ #define INV_J 0 #define INV_F 1 #define INV_F2 2 #define INV_F3 3 #define INV_F4 4 #define INV_G2 5 #define INV_W2W3 6 #define INV_F8 8 #define INV_W3W3 9 #define INV_W2W5 10 #define INV_W2W7 14 #define INV_W3W5 15 #define INV_W3W7 21 #define INV_W2W3E2 23 #define INV_W2W5E2 24 #define INV_W2W13 26 #define INV_W2W7E2 27 #define INV_W3W3E2 28 #define INV_W5W7 35 #define INV_W3W13 39 /* Get coefficient of x^d in f, assuming f is nonzero. */ INLINE ulong Flx_coeff(GEN f, long d) { return f[d + 2]; } /* Return the root of f, assuming deg(f) = 1. */ INLINE ulong Flx_deg1_root(GEN f, ulong p) { if (degpol(f) != 1) pari_err_BUG("Flx_deg1_root"); return Fl_div(Fl_neg(Flx_coeff(f, 0), p), Flx_coeff(f, 1), p); } /* Allocation / gerepile */ long getdebugvar(void); void setdebugvar(long n); void debug_stack(void); void fill_stack(void); void minim_alloc(long n, double ***q, GEN *x, double **y, double **z, double **v); int pop_entree_block(entree *ep, long loc); int pop_val_if_newer(entree *ep, long loc); /* general printing */ void print_errcontext(PariOUT *out, const char *msg, const char *s, const char *entry); void print_prefixed_text(PariOUT *out, const char *s, const char *prefix, const char *str); INLINE void print_text(const char *s) { print_prefixed_text(pariOut, s,NULL,NULL); } INLINE void out_print_text(PariOUT *out, const char *s) { print_prefixed_text(out, s,NULL,NULL); } INLINE long is_keyword_char(char c) { return (isalnum((int)c) || c=='_'); } /* Interfaces (GP, etc.) */ hashtable *hash_from_link(GEN e, GEN names, int use_stack); void gen_relink(GEN x, hashtable *table); entree* do_alias(entree *ep); char* get_sep(const char *t); long get_int(const char *s, long dflt); ulong get_uint(const char *s); void gp_initrc(pari_stack *p_A); void pari_sigint(const char *s); void* get_stack(double fraction, long min); void free_graph(void); void initout(int initerr); void resetout(int initerr); void init_linewrap(long w); void print_functions_hash(const char *s); GEN readbin(const char *name, FILE *f, int *vector); int term_height(void); int term_width(void); /* gp_colors */ void decode_color(long n, long *c); /* defaults */ extern long precreal; void lim_lines_output(char *s, long n, long max); int tex2mail_output(GEN z, long n); void gen_output(GEN x); void fputGEN_pariout(GEN x, pariout_t *T, FILE *out); void parsestate_reset(void); void parsestate_save(struct pari_parsestate *state); void parsestate_restore(struct pari_parsestate *state); void compilestate_reset(void); void compilestate_save(struct pari_compilestate *comp); void compilestate_restore(struct pari_compilestate *comp); void filestate_save(struct pari_filestate *file); void filestate_restore(struct pari_filestate *file); void tmp_restore(pariFILE *F); void evalstate_clone(void); void evalstate_reset(void); void evalstate_restore(struct pari_evalstate *state); GEN evalstate_restore_err(struct pari_evalstate *state); void evalstate_save(struct pari_evalstate *state); void varstate_save(struct pari_varstate *s); void varstate_restore(struct pari_varstate *s); void mtstate_save(long *pending); void mtstate_reset(void); void mtstate_restore(long *pending); void debug_context(void); typedef struct { const char *s; size_t ls; char **dir; } forpath_t; void forpath_init(forpath_t *T, gp_path *path, const char *s); char *forpath_next(forpath_t *T); /* GP output && output format */ void gpwritebin(const char *s, GEN x); extern char *current_logfile; /* colors */ extern long gp_colors[]; extern int disable_color; /* entrees */ #define EpVALENCE(ep) ((ep)->valence & 0xFF) #define EpSTATIC(ep) ((ep)->valence & 0x100) #define EpSETSTATIC(ep) ((ep)->valence |= 0x100) enum { EpNEW = 100, EpALIAS, EpVAR, EpINSTALL }; #define initial_value(ep) ((ep)+1) /* functions lists */ extern const long functions_tblsz; /* hashcodes table size */ extern entree **functions_hash; /* functions hashtable */ extern entree **defaults_hash; /* defaults hashtable */ /* buffers */ typedef struct Buffer { char *buf; ulong len; jmp_buf env; } Buffer; Buffer *new_buffer(void); void delete_buffer(Buffer *b); void fix_buffer(Buffer *b, long newlbuf); typedef struct { const char *s; /* source */ char *t, *end; /* target, last char read */ int in_string, in_comment, more_input, wait_for_brace; Buffer *buf; } filtre_t; void init_filtre(filtre_t *F, Buffer *buf); Buffer *filtered_buffer(filtre_t *F); void kill_buffers_upto_including(Buffer *B); void pop_buffer(void); void kill_buffers_upto(Buffer *B); int gp_read_line(filtre_t *F, const char *PROMPT); void parse_key_val(char *src, char **ps, char **pt); extern int (*cb_pari_get_line_interactive)(const char*, const char*, filtre_t *F); extern char *(*cb_pari_fgets_interactive)(char *s, int n, FILE *f); int get_line_from_file(const char *prompt, filtre_t *F, FILE *file); void pari_skip_space(char **s); void pari_skip_alpha(char **s); char *pari_translate_string(const char *src, char *s, char *entry); gp_data *default_gp_data(void); typedef char *(*fgets_t)(char *, int, void*); typedef struct input_method { /* optional */ fgets_t fgets; /* like libc fgets() but last argument is (void*) */ /* mandatory */ char * (*getline)(char**, int f, struct input_method*, filtre_t *F); int free; /* boolean: must we free the output of getline() ? */ /* optional */ const char *prompt, *prompt_cont; void *file; /* can be used as last argument for fgets() */ } input_method; int input_loop(filtre_t *F, input_method *IM); char *file_input(char **s0, int junk, input_method *IM, filtre_t *F); char *file_getline(Buffer *b, char **s0, input_method *IM); /* readline */ typedef struct { /* pointers to readline variables/functions */ char **line_buffer; int *point; int *end; char **(*completion_matches)(const char *, char *(*)(const char*, int)); char *(*filename_completion_function)(const char *, int); char *(*username_completion_function)(const char *, int); int (*insert)(int, int); int *completion_append_character; /* PARI-specific */ int back; /* rewind the cursor by this number of chars */ } pari_rl_interface; /* Code which wants to use readline needs to do the following: #include #include pari_rl_interface pari_rl; pari_use_readline(pari_rl); This will initialize the pari_rl structure. A pointer to this structure must be given as first argument to all PARI readline functions. */ /* IMPLEMENTATION NOTE: this really must be a macro (not a function), * since we refer to readline symbols. */ #define pari_use_readline(pari_rl) do {\ (pari_rl).line_buffer = &rl_line_buffer; \ (pari_rl).point = &rl_point; \ (pari_rl).end = &rl_end; \ (pari_rl).completion_matches = &rl_completion_matches; \ (pari_rl).filename_completion_function = &rl_filename_completion_function; \ (pari_rl).username_completion_function = &rl_username_completion_function; \ (pari_rl).insert = &rl_insert; \ (pari_rl).completion_append_character = &rl_completion_append_character; \ (pari_rl).back = 0; } while(0) /* FIXME: EXPORT AND DOCUMENT THE FOLLOWING */ /* PROBABLY NOT IN THE RIGHT FILE, SORT BY THEME */ /* multiprecision */ GEN adduispec_offset(ulong s, GEN x, long offset, long nx); int lgcdii(ulong* d, ulong* d1, ulong* u, ulong* u1, ulong* v, ulong* v1, ulong vmax); ulong rgcduu(ulong d, ulong d1, ulong vmax, ulong* u, ulong* u1, ulong* v, ulong* v1, long *s); ulong xgcduu(ulong d, ulong d1, int f, ulong* v, ulong* v1, long *s); ulong xxgcduu(ulong d, ulong d1, int f, ulong* u, ulong* u1, ulong* v, ulong* v1, long *s); GEN divgunu(GEN x, ulong i); GEN divrunu(GEN x, ulong i); GEN muliispec(GEN x, GEN y, long nx, long ny); GEN red_montgomery(GEN T, GEN N, ulong inv); GEN sqrispec(GEN x, long nx); ulong *convi(GEN x, long *l); int approx_0(GEN x, GEN y); GEN bernfrac_using_zeta(long n); /* powers */ GEN rpowuu(ulong a, ulong n, long prec); /* floats */ double dabs(double s, double t); double darg(double s, double t); void dcxlog(double s, double t, double *a, double *b); double dnorm(double s, double t); double dbllog2(GEN z); /* hnf */ GEN hnfadd(GEN m,GEN p,GEN* ptdep,GEN* ptA,GEN* ptC,GEN extramat,GEN extraC); GEN hnfadd_i(GEN m,GEN p,GEN* ptdep,GEN* ptA,GEN* ptC,GEN extramat,GEN extraC); GEN hnfspec_i(GEN m,GEN p,GEN* ptdep,GEN* ptA,GEN* ptC,long k0); GEN hnfspec(GEN m,GEN p,GEN* ptdep,GEN* ptA,GEN* ptC,long k0); GEN mathnfspec(GEN x, GEN *ptperm, GEN *ptdep, GEN *ptB, GEN *ptC); GEN ZM_hnfmodall_i(GEN x, GEN dm, long flag); GEN LLL_check_progress(GEN Bnorm, long n0, GEN m, int final, long *ti_LLL); /* integer factorization / discrete log */ ulong is_kth_power(GEN x, ulong p, GEN *pt); GEN mpqs(GEN N); /* Polynomials */ /* a) Arithmetic/conversions */ GEN lift_if_rational(GEN x); GEN monomial(GEN a, long degpol, long v); GEN monomialcopy(GEN a, long degpol, long v); GEN ser2pol_i(GEN x, long lx); GEN ser2rfrac_i(GEN x); GEN swap_vars(GEN b0, long v); GEN RgX_recipspec_shallow(GEN x, long l, long n); /* b) Modular */ GEN bezout_lift_fact(GEN T, GEN Tmod, GEN p, long e); GEN polsym_gen(GEN P, GEN y0, long n, GEN T, GEN N); GEN ZXQ_charpoly_sqf(GEN A, GEN B, long *lambda, long v); GEN ZX_disc_all(GEN,ulong); GEN ZX_resultant_all(GEN A, GEN B, GEN dB, ulong bound); GEN ZX_ZXY_resultant_all(GEN A, GEN B, long *lambda, GEN *LPRS); GEN FlxqM_mul_Kronecker(GEN A, GEN B, GEN T, ulong p); GEN FqM_mul_Kronecker(GEN x, GEN y, GEN T, GEN p); /* c) factorization */ GEN chk_factors_get(GEN lt, GEN famod, GEN c, GEN T, GEN N); long cmbf_maxK(long nb); GEN ZX_DDF(GEN x); GEN initgaloisborne(GEN T, GEN dn, long prec, GEN *pL, GEN *pprep, GEN *pdis); GEN polint_i(GEN xa, GEN ya, GEN x, long n, GEN *ptdy); GEN quicktrace(GEN x, GEN sym); /* pari_init / pari_close */ void pari_close_compiler(void); void pari_close_evaluator(void); void pari_close_files(void); void pari_close_floats(void); void pari_close_homedir(void); void pari_close_parser(void); void pari_close_paths(void); void pari_close_primes(void); void pari_init_buffers(void); void pari_init_compiler(void); void pari_init_defaults(void); void pari_init_evaluator(void); void pari_init_files(void); void pari_init_floats(void); void pari_init_homedir(void); void pari_init_graphics(void); void pari_init_parser(void); void pari_init_rand(void); void pari_init_paths(void); void pari_init_primetab(void); void pari_init_seadata(void); void pari_pthread_init_primetab(void); void pari_pthread_init_seadata(void); void pari_pthread_init_varstate(void); void pari_thread_close_files(void); void pari_thread_init_primetab(void); void pari_thread_init_seadata(void); void pari_thread_init_varstate(void); /* BY FILES */ /* parinf.h */ GEN fincke_pohst(GEN a,GEN BOUND,long stockmax,long PREC, FP_chk_fun *CHECK); void init_zlog(zlog_S *S, GEN bid); GEN log_gen_arch(zlog_S *S, long index); GEN log_gen_pr(zlog_S *S, long index, GEN nf, long e); GEN poltobasis(GEN nf,GEN x); GEN coltoalg(GEN nf,GEN x); GEN check_polrel(GEN nf, GEN P, ulong *lim); GEN get_arch_real(GEN nf,GEN x,GEN *emb,long prec); GEN make_integral(GEN nf, GEN L0, GEN f, GEN listpr); GEN rnfallbase(GEN nf, GEN pol, ulong lim, GEN rnfeq, GEN *pD, GEN *pfi); GEN subgroupcondlist(GEN cyc, GEN bound, GEN listKer); GEN ideallog_sgn(GEN nf, GEN x, GEN sgn, GEN bid); /* Qfb.c */ GEN redimagsl2(GEN q, GEN *U); GEN redrealsl2(GEN V, GEN d, GEN rd); GEN redrealsl2step(GEN A, GEN d, GEN rd); /* alglin1.c */ typedef long (*pivot_fun)(GEN,GEN,long,GEN); GEN ZM_pivots(GEN x0, long *rr); GEN RgM_pivots(GEN x0, GEN data, long *rr, pivot_fun pivot); void RgMs_structelim_col(GEN M, long nbcol, long nbrow, GEN A, GEN *p_col, GEN *p_lin); /* arith1.c */ int is_gener_Fp(GEN x, GEN p, GEN p_1, GEN L); int is_gener_Fl(ulong x, ulong p, ulong p_1, GEN L); /* arith2.c */ int divisors_init(GEN n, GEN *pP, GEN *pE); long set_optimize(long what, GEN g); /* base1.c */ GEN zk_galoisapplymod(GEN nf, GEN z, GEN S, GEN p); /* base2.c */ GEN dim1proj(GEN prh); GEN gen_if_principal(GEN bnf, GEN x); GEN nfbasis_gp(GEN T); /* base3.c */ void check_nfelt(GEN x, GEN *den); GEN zk_ei_mul(GEN nf, GEN x, long i); GEN zlog_pr(GEN nf, GEN a, GEN sprk); GEN vzlog_pr(GEN nf, GEN v, GEN sprk); GEN zlog_pr_init(GEN nf, GEN pr, long k); /* base4.c */ GEN factorbackprime(GEN nf, GEN L, GEN e); /* bb_group.c */ GEN producttree_scheme(long n); /* bibli2.c */ GEN sort_factor_pol(GEN y, int (*cmp)(GEN,GEN)); /* buch1.c */ long bnf_increase_LIMC(long LIMC, long LIMCMAX); /* buch2.c */ typedef struct GRHprime_t { ulong p; double logp; GEN dec; } GRHprime_t; typedef struct GRHcheck_t { double cD, cN; GRHprime_t *primes; long clone, nprimes, maxprimes; ulong limp; forprime_t P; } GRHcheck_t; void free_GRHcheck(GRHcheck_t *S); void init_GRHcheck(GRHcheck_t *S, long N, long R1, double LOGD); void GRH_ensure(GRHcheck_t *S, long nb); ulong GRH_last_prime(GRHcheck_t *S); int GRHok(GRHcheck_t *S, double L, double SA, double SB); GEN extract_full_lattice(GEN x); GEN init_red_mod_units(GEN bnf, long prec); GEN isprincipalarch(GEN bnf, GEN col, GEN kNx, GEN e, GEN dx, long *pe); GEN red_mod_units(GEN col, GEN z); /* buch3.c */ GEN minkowski_bound(GEN D, long N, long r2, long prec); int subgroup_conductor_ok(GEN H, GEN L); GEN subgrouplist_cond_sub(GEN bnr, GEN C, GEN bound); /* buch4.c */ GEN bnfsunit0(GEN bnf, GEN S, long flag, long prec); /* crvwtors.c */ void random_curves_with_m_torsion(ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, long m, ulong p); /* dirichlet.c */ GEN direuler_factor(GEN s, long n); /* elliptic.c */ void ellprint(GEN e); /* es.c */ void killallfiles(void); pariFILE* newfile(FILE *f, const char *name, int type); int popinfile(void); pariFILE* try_pipe(const char *cmd, int flag); /* Fle.c */ void FleV_add_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi); void FleV_dbl_pre_inplace(GEN P, GEN a4, ulong p, ulong pi); void FleV_mulu_pre_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi); void FleV_sub_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi); /* Flxq_log.c */ GEN Flxq_log_index(GEN a0, GEN b0, GEN m, GEN T0, ulong p); int Flxq_log_use_index(GEN m, GEN T0, ulong p); /* FlxqE.c */ GEN ZpXQ_norm_pcyc(GEN x, GEN T, GEN q, GEN p); long zx_is_pcyc(GEN T); /* FpV.c */ GEN FpMs_leftkernel_elt_col(GEN M, long nbcol, long nbrow, GEN p); /* FpX_factor.c */ GEN ddf_to_ddf2(GEN V); long ddf_to_nbfact(GEN D); GEN vddf_to_simplefact(GEN V, long d); /* FpXQX_factor.c */ GEN FpXQX_factor_Berlekamp(GEN x, GEN T, GEN p); /* forprime.c*/ void init_modular_big(forprime_t *S); void init_modular_small(forprime_t *S); /* galconj.c */ GEN galoiscosets(GEN O, GEN perm); GEN matrixnorm(GEN M, long prec); /* gen1.c */ GEN gred_rfrac_simple(GEN n, GEN d); GEN sqr_ser_part(GEN x, long l1, long l2); /* hash.c */ hashtable *hashstr_import_static(hashentry *e, ulong size); /* hyperell.c */ GEN ZlXQX_hyperellpadicfrobenius(GEN H, GEN T, ulong p, long n); /* ifactor1.c */ ulong snextpr(ulong p, byteptr *d, long *rcn, long *q, long k); /* intnum.c */ GEN contfraceval_inv(GEN CF, GEN tinv, long nlim); /* mftrace.c */ void pari_close_mf(void); long polishomogeneous(GEN P); GEN sertocol(GEN S); /* prime.c */ long BPSW_psp_nosmalldiv(GEN N); int Fl_MR_Jaeschke(ulong n, long k); int MR_Jaeschke(GEN n); long isanypower_nosmalldiv(GEN N, GEN *px); void prime_table_next_p(ulong a, byteptr *pd, ulong *pp, ulong *pn); /* perm.c */ long cosets_perm_search(GEN C, GEN p); GEN perm_generate(GEN S, GEN H, long o); long perm_relorder(GEN p, GEN S); /* polclass.c */ GEN polclass0(long D, long inv, long xvar, GEN *db); /* polmodular.c */ GEN polmodular0_ZM(long L, long inv, GEN J, GEN Q, int compute_derivs, GEN *db); GEN Flm_Fl_polmodular_evalx(GEN phi, long L, ulong j, ulong p, ulong pi); GEN polmodular_db_init(long inv); void polmodular_db_clear(GEN db); void polmodular_db_add_level(GEN *db, long L, long inv); void polmodular_db_add_levels(GEN *db, long *levels, long k, long inv); GEN polmodular_db_for_inv(GEN db, long inv); GEN polmodular_db_getp(GEN fdb, long L, ulong p); long modinv_level(long inv); long modinv_degree(long *p1, long *p2, long inv); long modinv_ramified(long D, long inv); long modinv_j_from_2double_eta(GEN F, long inv, ulong *j, ulong x0, ulong x1, ulong p, ulong pi); GEN double_eta_raw(long inv); ulong modfn_root(ulong j, norm_eqn_t ne, long inv); long modfn_unambiguous_root(ulong *r, long inv, ulong j0, norm_eqn_t ne, GEN jdb); GEN qfb_nform(long D, long n); /* Fle.c */ ulong Flj_order_ufact(GEN P, ulong n, GEN F, ulong a4, ulong p, ulong pi); /* polarit3.c */ GEN Flm_Frobenius_pow(GEN M, long d, GEN T, ulong p); GEN FpM_Frobenius_pow(GEN M, long d, GEN T, GEN p); GEN FpX_compositum(GEN A, GEN B, GEN p); GEN FpX_direct_compositum(GEN A, GEN B, GEN p); GEN FpXV_direct_compositum(GEN V, GEN p); ulong ZX_ZXY_ResBound(GEN A, GEN B, GEN dB); GEN ffinit_Artin_Shreier(GEN ip, long l); GEN ffinit_rand(GEN p, long n); /* readline.c */ char** pari_completion(pari_rl_interface *pari_rl, char *text, int START, int END); char** pari_completion_matches(pari_rl_interface *pari_rl, const char *s, long pos, long *wordpos); /* rootpol.c */ GEN FFT(GEN x, GEN Omega); GEN FFTinit(long k, long prec); /* subcyclo.c */ GEN bnr_to_znstar(GEN bnr, long *complex); GEN galoiscyclo(long n, long v); GEN znstar_bits(long n, GEN H); long znstar_conductor(GEN H); long znstar_conductor_bits(GEN bits); GEN znstar_cosets(long n, long phi_n, GEN H); GEN znstar_elts(long n, GEN H); GEN znstar_generate(long n, GEN V); GEN znstar_hnf(GEN Z, GEN M); GEN znstar_hnf_elts(GEN Z, GEN H); GEN znstar_hnf_generators(GEN Z, GEN M); GEN znstar_reduce_modulus(GEN H, long n); GEN znstar_small(GEN zn); /* trans1.c */ struct abpq { GEN *a, *b, *p, *q; }; struct abpq_res { GEN P, Q, B, T; }; void abpq_init(struct abpq *A, long n); void abpq_sum(struct abpq_res *r, long n1, long n2, struct abpq *A); GEN logagmcx(GEN q, long prec); GEN zellagmcx(GEN a0, GEN b0, GEN r, GEN t, long prec); /* trans2.c */ GEN trans_fix_arg(long *prec, GEN *s0, GEN *sig, GEN *tau, pari_sp *av, GEN *res); /* trans3.c */ GEN double_eta_quotient(GEN a, GEN w, GEN D, long p, long q, GEN pq, GEN sqrtD); GEN inv_szeta_euler(long n, double lba, long prec); /* volcano.c */ long j_level_in_volcano(GEN phi, ulong j, ulong p, ulong pi, long L, long depth); ulong ascend_volcano(GEN phi, ulong j, ulong p, ulong pi, long level, long L, long depth, long steps); ulong descend_volcano(GEN phi, ulong j, ulong p, ulong pi, long level, long L, long depth, long steps); long next_surface_nbr(ulong *nJ, GEN phi, long L, long h, ulong J, const ulong *pJ, ulong p, ulong pi); GEN enum_roots(ulong j, norm_eqn_t ne, GEN fdb, classgp_pcp_t G); ENDEXTERN pari-2.11.2/src/headers/pariold.h0000644000175000017500000003147613447371554015213 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* For compatibility with older PARI versions */ #define LOG2 M_LN2 #define truecoeff truecoef #define polcoeff0 polcoef #define polcoeff_i polcoef_i #define factorcantor0 factormod0 #define factcantor factmod #define matsolvemod0 matsolvemod #define rootmod2 polrootsmod #define rootmod polrootsmod #define resultant_all RgX_resultant_all #define vecbinome vecbinomial #define Xadic_lindep lindep_Xadic #define padic_lindep lindep_padic #define ZM_ker_ratlift ZM_ker #define keri ZM_ker /* Following obsoleted in 2.9.* (2016) */ #define absi_factor absZ_factor #define absi_factor_limit absZ_factor_limit #define absi_cmp abscmpii #define absr_cmp abscmprr #define absi_equal absequalii #define anell ellan #define anellsmall ellanQ_zv #define leading_term leading_coeff #define constant_term constant_coeff #define concat gconcat #define concat1 gconcat1 #define mathell ellheightmatrix #define ghell ellheight /* Following obsoleted in 2.7.* (2014) */ #define mpexp1 mpexpm1 #define ggamd ggammah #define gach gacosh #define gash gasinh #define gath gatanh #define gch gcosh #define gsh gsinh #define gth gtanh #define recip serreverse #define gcmpX gequalX #define ZM_hnfremdiv ZM_hnfdivrem #define rnfidealhermite rnfidealhnf #define rnfelementabstorel rnfeltabstorel #define rnfelementreltoabs rnfeltreltoabs #define rnfelementdown rnfeltdown #define rnfelementup rnfeltup #define exp_Ir expIr #define vecbezout gcdext0 #define vecbezoutres polresultantext #define init_primepointer init_primepointer_geq #define ellap0(e,p,flag) ellap(e,p) #define apell2(e,p) ellap(e,p) #define geulerphi eulerphi #define numbdiv numdiv #define gnumbdiv numdiv #define gsumdivk sumdivk #define gnextprime nextprime #define gprecprime precprime #define leftright_pow_fold gen_pow_fold #define leftright_pow_u_fold gen_powu_fold #define subell ellsub #define addell elladd #define powell ellmul #define ggval gvaluation #define stackmalloc stack_malloc #define listcreate mklist /* Following obsoleted in 2.5.* (2011) */ #define fprintferr err_printf #define msgTIMER timer_printf #define TIMER timer_delay #define TIMERread timer_get #define TIMERstart timer_start #define rnfinitalg rnfinit #define ordell ellordinate #define gcmp0 gequal0 #define gcmp1 gequal1 #define gcmp_1 gequalm1 #define nfsmith nfsnf #define certifybuchall bnfcertify #define greffe(x,y,z) (RgX_to_ser(x,y)) #define newbloc newblock #define killbloc killblock #define taille2 gsizebyte #define taille gsizeword #define polymodrecip modreverse #define primedec idealprimedec #define initalg nfinit #define initalgred nfinitred #define initalgred2 nfinitred2 #define initell ellinit #define smallinitell smallellinit #define isunit bnfisunit #define zideallog ideallog #define ideallllred idealred0 #define ideal_two_elt idealtwoelt #define ideal_two_elt2 idealtwoelt2 #define ideal_two_elt0 idealtwoelt0 #define gregula quadregulator #define gfundunit quadunit #define minideal(x,y,z,t) idealmin(x,y,z) #define idealhermite idealhnf #define srgcd(x) RgX_gcd(x) #define nfdiscf0(x) nfdisc0(x) #define discf(x) nfdisc(x) #define discsr(x) poldisc0((x),-1) #define factorpadic4 factorpadic #define smith2 smithall #define gsmith2 gsmithall #define derivpol RgX_deriv #define gpmalloc pari_malloc #define gprealloc pari_realloc #define gpfree pari_free #define pariprintf pari_printf #define pariputc pari_putc #define pariputs pari_puts #define pariflush pari_flush /* Following deprecated for a long time now, obsoleted in 2.3.* (2007) */ #ifdef PARI_OLD_NAMES #define apell ellap #define gscalsmat scalarmat_s #define sqred qfgaussred #define signat qfsign #define infile pari_infile #define errfile pari_errfile #define logfile pari_logfile #define voir dbgGEN #define pointch ellchangepoint #define coordch ellchangecurve #define Flx_rand random_Flx #define FpX_rand random_FpX #define galois polgalois #define sindexlexsort indexlexsort #define sindexsort indexsort #define sindexrank indexrank #define decomp Z_factor #define gmodulcp gmodulo #define forcecopy gcopy #define lseriesell elllseries #define uissquarerem uissquareall #define Z_issquarerem Z_issquareall #define gissquarerem gissquareall #define gcarrecomplet gissquareall #define gcarreparfait gissquare #define rnfhermitebasis rnfhnfbasis #define wf weberf #define wf1 weberf1 #define wf2 weberf2 #define coefs_to_col mkcoln #define coefs_to_int mkintn #define coefs_to_pol mkpoln #define coefs_to_vec mkvecn #define localreduction elllocalred #define idmat matid #define globalreduction ellglobalred #define taniyama(e) elltaniyama((e),precdl) #define chinois chinese #define binome binomial #define egalii equalii #define gegal gequal #define gegalgs gequalgs #define gegalsg gequalsg #define gzero gen_0 #define gun gen_1 #define gdeux gen_2 #define realzero real_0 #define realzero_bit real_0_bit #define realun real_1 #define realmun real_m1 #define gen2str GENtostr #define gpui gpow #define gpuigs gpowgs #define classno3 hclassno #define strtoGEN gp_read_str #define flisexpr gp_read_str #define flisseq gp_read_str #define lisseq readseq #define lisGEN gp_read_stream #define lisexpr readseq #define permute numtoperm #define permuteInv permtonum #define evallgef(x) 0 #define lgef lg #define setlgef setlg #define leadingcoeff(x) (pollead((x),-1)) #define poldivres poldivrem #define nfdivres nfdivrem #define gred gcopy #define pvaluation Z_pvalrem #define svaluation u_lvalrem #define isprincipalrayall bnrisprincipal #define rayclassno bnrclassno #define rayclassnolist bnrclassnolist #define idealhermite2 idealhnf0 #define gener_Fp pgener_Fp #define gener_Fl pgener_Fl #define cyclo polcyclo #define tchebi polchebyshev1 #define legendre pollegendre #define subcyclo polsubcyclo #define leftright_pow gen_pow #define leftright_pow_u gen_powu #define apprgen padicappr #define apprgen9 padicappr #define factmod9 factorff #define ggrandocp ggrando #define glogagm glog #define logagm mplog #define mpsqrtz gopgz(absr,(x),(y)) #define adduumod Fl_add #define subuumod Fl_sub #define muluumod Fl_mul #define divuumod Fl_div #define powuumod Fl_powu #define invumod Fl_inv #define invsmod Fl_inv_signed #define mpinvmod Fp_inv #define powmodulo Fp_pow #define mpsqrtmod Fp_sqrt #define mpsqrtnmod Fp_sqrtn #define mpsqrt sqrtr #define mpsqrtn sqrtnr #define resii remii #define resis remis #define ressi remsi #define resss remss #define resiiz remiiz #define resisz remisz #define ressiz remsiz #define resssz remssz #define gres grem #define lres lrem #define gdivise gdvd #define divise dvdii #define mpdivis dvdiiz #define mpdivisis dvdisz #define mpent mpfloor #define mpentz mpfloorz #define mpnegz(x,y) \ STMT_START {pari_sp _av=avma;mpaff(mpneg(x),y);avma=_av;} STMT_END #define mpabsz(x,y) \ STMT_START {pari_sp _av=avma;mpaff(mpabs(x),y);avma=_av;} STMT_END #define absrz(x,z) mpabsz((x),(z)) #define negrz(x,z) mpnegz((x),(z)) #define err pari_err #define init pari_init #define zero (long)gen_0 #define un (long)gen_1 #define deux (long)gen_2 #define lhalf (long)ghalf /* removed GEN subtypes */ #define t_FRACN t_FRAC #define t_RFRACN t_RFRAC #define is_frac_t(t) ( (t) == t_FRAC ) #define is_rfrac_t(t) ( (t) == t_RFRAC ) /*casts*/ #define labsi (long)absi #define labsr (long)absr #define lach (long)gacosh #define lacos (long)gacos #define ladd (long)gadd #define laddgs (long)gaddgs #define laddii (long)addii #define laddir (long)addir #define laddis (long)addis #define laddrr (long)addrr #define laddsg (long)gaddsg #define laddsi (long)addsi #define laddrs (long)addrs #define laddsr (long)addsr #define ladj (long)adj #define larg (long)garg #define lash (long)gasinh #define lasin (long)gasin #define lassmat (long)matcompanion #define latan (long)gatan #define lath (long)gatanh #define lbezout (long)bezout #define lbinome (long)binomial #define lcaract (long)caract #define lcaradj (long)caradj #define lceil (long)gceil #define lch (long)gcosh #define lchangevar (long)changevar #define lclone (long)gclone #define lconcat (long)gconcat #define lconj (long)gconj #define lcontent (long)content #define lcopy (long)gcopy #define lcos (long)gcos #define lcvtoi (long)gcvtoi #define lderiv (long)deriv #define ldet2 (long)det2 #define ldet (long)det #define ldeuc (long)gdeuc #define ldiscsr (long)discsr #define ldiventgs (long)gdiventgs #define ldiventsg (long)gdiventsg #define ldivgs (long)gdivgs #define ldivii (long)divii #define ldivir (long)divir #define ldivis (long)divis #define ldivmod (long)gdivmod #define ldivri (long)divri #define ldivrr (long)divrr #define ldivrs (long)divrs #define ldivsg (long)gdivsg #define ldivsi (long)divsi #define ldivsr (long)divsr #define ldvmdii (long)dvmdii #define ldvmdis (long)dvmdis #define ldvmdsi (long)dvmdsi #define lexp (long)gexp #define lfibo (long)fibo #define lfloor (long)gfloor #define lfrac (long)gfrac #define lgamd (long)ggammah #define lgamma (long)ggamma #define lgauss (long)gauss #define lgcd (long)ggcd #define lgetg (long)cgetg #define lgeti (long)cgeti #define lgetp (long)cgetp #define lgetr (long)cgetr #define licopy (long)icopy #define limag (long)gimag #define linteg (long)integ #define linv (long)ginv #define linvmat (long)RgM_inv #define linvmod (long)ginvmod #define llegendre (long)legendre #define llift (long)lift #define llngamma (long)glngamma #define llog (long)glog #define lmaxgs (long)gmaxgs #define lmax (long)gmax #define lmaxsg (long)gmaxsg #define lmings (long)gmings #define lmin (long)gmin #define lminsg (long)gminsg #define lmodgs (long)gmodgs #define lmodii (long)modii #define lmod (long)gmod #define lmodsg (long)gmodsg #define lmodsi (long)modsi #define lmodulcp (long)gmodulo #define lmodulo (long)gmodulo #define lmpabs (long)mpabs #define lmpadd (long)mpadd #define lmpcos (long)mpcos #define lmpdiv (long)mpdiv #define lmpent (long)mpent #define lmpeuler (long)mpeuler #define lmpexp1 (long)mpexpm1 #define lmpexp (long)mpexp #define lmpfact (long)mpfact #define lmplog (long)mplog #define lmpmul (long)mpmul #define lmpneg (long)mpneg #define lmppgcd (long)mppgcd #define lmppi (long)mppi #define lmpshift (long)mpshift #define lmpsin (long)mpsin #define lmpsqrt (long)mpsqrt #define lmpsub (long)mpsub #define lmptrunc (long)mptrunc #define lmul2n (long)gmul2n #define lmulgs (long)gmulgs #define lmulii (long)mulii #define lmulir (long)mulir #define lmulis (long)mulis #define lmul (long)gmul #define lmulri (long)mulri #define lmulrr (long)mulrr #define lmulrs (long)mulrs #define lmulsg (long)gmulsg #define lmulsi (long)mulsi #define lmulsr (long)mulsr #define lmulss (long)mulss #define lnegi (long)negi #define lneg (long)gneg #define lnegr (long)negr #define lnorml2 (long)gnorml2 #define lnorm (long)gnorm #define lpile (long)gerepile #define lpilecopy (long)gerepilecopy #define lpileupto (long)gerepileupto #define lpileuptoint (long)gerepileuptoint #define lpileuptoleaf (long)gerepileuptoleaf #define lpoleval (long)poleval #define lpowgs (long)gpowgs #define lprec (long)gprec #define lpsi (long)gpsi #define lpuigs (long)gpuigs #define lpui (long)gpui #define lquadgen (long)quadgen #define lquadpoly (long)quadpoly #define lracine (long)sqrtint #define lrcopy (long)rcopy #define lreal (long)greal #define lrecip (long)recip #define lred (long)gred #define lremii (long)remii #define lrem (long)grem #define lrndtoi (long)grndtoi #define lroots (long)roots #define lscalmat (long)scalarmat #define lscalsmat (long)scalarmat_s #define lsh (long)gsinh #define lshifti (long)shifti #define lshift (long)gshift #define lshiftr (long)shiftr #define lsin (long)gsin #define lsqri (long)sqri #define lsqr (long)gsqr #define lsqrt (long)gsqrt #define lstoi (long)stoi #define lsub (long)gsub #define lsubgs (long)gsubgs #define lsubii (long)subii #define lsubir (long)subir #define lsubis (long)subis #define lsubres (long)resultant #define lsubri (long)subri #define lsubrr (long)subrr #define lsubrs (long)subrs #define lsubst (long)gsubst #define lsubsg (long)gsubsg #define lsubsi (long)subsi #define lsubsr (long)subsr #define ltan (long)gtan #define ltchebi (long)polchebyshev #define lth (long)gtanh #define ltrace (long)gtrace #define ltrans (long)gtrans #define ltrunc (long)gtrunc #define lutoi (long)utoi #define lround (long)ground #define ldiv (long)gdiv #endif pari-2.11.2/src/headers/paritune.h0000644000175000017500000001602413326135265015371 0ustar billbill#define PARI_TUNE #ifdef PARI_TUNE extern long AGM_ATAN_LIMIT; extern long DIVRR_GMP_LIMIT; extern long EXPNEWTON_LIMIT; extern long F2x_MUL_KARATSUBA_LIMIT; extern long Flx_BARRETT_QUARTMULII_LIMIT; extern long Flx_BARRETT_HALFMULII_LIMIT; extern long Flx_BARRETT_KARATSUBA_LIMIT; extern long Flx_BARRETT_MULII2_LIMIT; extern long Flx_BARRETT_MULII_LIMIT; extern long Flx_DIVREM_BARRETT_LIMIT; extern long Flx_EXTGCD_LIMIT; extern long Flx_GCD_LIMIT; extern long Flx_HALFGCD_QUARTMULII_LIMIT; extern long Flx_HALFGCD_HALFMULII_LIMIT; extern long Flx_HALFGCD_KARATSUBA_LIMIT; extern long Flx_HALFGCD_MULII2_LIMIT; extern long Flx_HALFGCD_MULII_LIMIT; extern long Flx_INVBARRETT_QUARTMULII_LIMIT; extern long Flx_INVBARRETT_HALFMULII_LIMIT; extern long Flx_INVBARRETT_KARATSUBA_LIMIT; extern long Flx_INVBARRETT_MULII2_LIMIT; extern long Flx_INVBARRETT_MULII_LIMIT; extern long Flx_MUL_QUARTMULII_LIMIT; extern long Flx_MUL_HALFMULII_LIMIT; extern long Flx_MUL_KARATSUBA_LIMIT; extern long Flx_MUL_MULII2_LIMIT; extern long Flx_MUL_MULII_LIMIT; extern long Flx_REM_BARRETT_LIMIT; extern long Flx_SQR_QUARTSQRI_LIMIT; extern long Flx_SQR_HALFSQRI_LIMIT; extern long Flx_SQR_KARATSUBA_LIMIT; extern long Flx_SQR_SQRI2_LIMIT; extern long Flx_SQR_SQRI_LIMIT; extern long F2xqX_BARRETT_LIMIT; extern long F2xqX_DIVREM_BARRETT_LIMIT; extern long F2xqX_INVBARRETT_LIMIT; extern long F2xqX_REM_BARRETT_LIMIT; extern long FlxqX_BARRETT_LIMIT; extern long FlxqX_DIVREM_BARRETT_LIMIT; extern long FlxqX_EXTGCD_LIMIT; extern long FlxqX_GCD_LIMIT; extern long FlxqX_HALFGCD_LIMIT; extern long FlxqX_INVBARRETT_LIMIT; extern long FlxqX_REM_BARRETT_LIMIT; extern long FpX_BARRETT_LIMIT; extern long FpX_DIVREM_BARRETT_LIMIT; extern long FpX_EXTGCD_LIMIT; extern long FpX_GCD_LIMIT; extern long FpX_HALFGCD_LIMIT; extern long FpX_INVBARRETT_LIMIT; extern long FpX_REM_BARRETT_LIMIT; extern long FpXQX_BARRETT_LIMIT; extern long FpXQX_DIVREM_BARRETT_LIMIT; extern long FpXQX_EXTGCD_LIMIT; extern long FpXQX_GCD_LIMIT; extern long FpXQX_HALFGCD_LIMIT; extern long FpXQX_INVBARRETT_LIMIT; extern long FpXQX_REM_BARRETT_LIMIT; extern long Fp_POW_BARRETT_LIMIT; extern long Fp_POW_REDC_LIMIT; extern long INVMOD_GMP_LIMIT; extern long INVNEWTON_LIMIT; extern long LOGAGMCX_LIMIT; extern long LOGAGM_LIMIT; extern long MULII_FFT_LIMIT; extern long MULII_KARATSUBA_LIMIT; extern long MULRR_MULII_LIMIT; extern long RgX_MUL_LIMIT; extern long RgX_SQR_LIMIT; extern long SQRI_FFT_LIMIT; extern long SQRI_KARATSUBA_LIMIT; extern long SQRR_SQRI_LIMIT; #else # define AGM_ATAN_LIMIT __AGM_ATAN_LIMIT # define DIVRR_GMP_LIMIT __DIVRR_GMP_LIMIT # define EXPNEWTON_LIMIT __EXPNEWTON_LIMIT # define F2x_MUL_KARATSUBA_LIMIT __F2x_MUL_KARATSUBA_LIMIT # define Flx_BARRETT_QUARTMULII_LIMIT __Flx_BARRETT_QUARTMULII_LIMIT # define Flx_BARRETT_HALFMULII_LIMIT __Flx_BARRETT_HALFMULII_LIMIT # define Flx_BARRETT_KARATSUBA_LIMIT __Flx_BARRETT_KARATSUBA_LIMIT # define Flx_BARRETT_MULII2_LIMIT __Flx_BARRETT_MULII2_LIMIT # define Flx_BARRETT_MULII_LIMIT __Flx_BARRETT_MULII_LIMIT # define Flx_DIVREM_BARRETT_LIMIT __Flx_DIVREM_BARRETT_LIMIT # define Flx_EXTGCD_LIMIT __Flx_EXTGCD_LIMIT # define Flx_GCD_LIMIT __Flx_GCD_LIMIT # define Flx_HALFGCD_QUARTMULII_LIMIT __Flx_HALFGCD_QUARTMULII_LIMIT # define Flx_HALFGCD_HALFMULII_LIMIT __Flx_HALFGCD_HALFMULII_LIMIT # define Flx_HALFGCD_KARATSUBA_LIMIT __Flx_HALFGCD_KARATSUBA_LIMIT # define Flx_HALFGCD_MULII2_LIMIT __Flx_HALFGCD_MULII2_LIMIT # define Flx_HALFGCD_MULII_LIMIT __Flx_HALFGCD_MULII_LIMIT # define Flx_INVBARRETT_QUARTMULII_LIMIT __Flx_INVBARRETT_QUARTMULII_LIMIT # define Flx_INVBARRETT_HALFMULII_LIMIT __Flx_INVBARRETT_HALFMULII_LIMIT # define Flx_INVBARRETT_KARATSUBA_LIMIT __Flx_INVBARRETT_KARATSUBA_LIMIT # define Flx_INVBARRETT_MULII2_LIMIT __Flx_INVBARRETT_MULII2_LIMIT # define Flx_INVBARRETT_MULII_LIMIT __Flx_INVBARRETT_MULII_LIMIT # define Flx_MUL_QUARTMULII_LIMIT __Flx_MUL_QUARTMULII_LIMIT # define Flx_MUL_HALFMULII_LIMIT __Flx_MUL_HALFMULII_LIMIT # define Flx_MUL_KARATSUBA_LIMIT __Flx_MUL_KARATSUBA_LIMIT # define Flx_MUL_MULII2_LIMIT __Flx_MUL_MULII2_LIMIT # define Flx_MUL_MULII_LIMIT __Flx_MUL_MULII_LIMIT # define Flx_REM_BARRETT_LIMIT __Flx_REM_BARRETT_LIMIT # define Flx_SQR_QUARTSQRI_LIMIT __Flx_SQR_QUARTSQRI_LIMIT # define Flx_SQR_HALFSQRI_LIMIT __Flx_SQR_HALFSQRI_LIMIT # define Flx_SQR_KARATSUBA_LIMIT __Flx_SQR_KARATSUBA_LIMIT # define Flx_SQR_SQRI2_LIMIT __Flx_SQR_SQRI2_LIMIT # define Flx_SQR_SQRI_LIMIT __Flx_SQR_SQRI_LIMIT # define F2xqX_BARRETT_LIMIT __F2xqX_BARRETT_LIMIT # define F2xqX_DIVREM_BARRETT_LIMIT __F2xqX_DIVREM_BARRETT_LIMIT # define F2xqX_INVBARRETT_LIMIT __F2xqX_INVBARRETT_LIMIT # define F2xqX_REM_BARRETT_LIMIT __F2xqX_REM_BARRETT_LIMIT # define FlxqX_BARRETT_LIMIT __FlxqX_BARRETT_LIMIT # define FlxqX_DIVREM_BARRETT_LIMIT __FlxqX_DIVREM_BARRETT_LIMIT # define FlxqX_EXTGCD_LIMIT __FlxqX_EXTGCD_LIMIT # define FlxqX_GCD_LIMIT __FlxqX_GCD_LIMIT # define FlxqX_HALFGCD_LIMIT __FlxqX_HALFGCD_LIMIT # define FlxqX_INVBARRETT_LIMIT __FlxqX_INVBARRETT_LIMIT # define FlxqX_REM_BARRETT_LIMIT __FlxqX_REM_BARRETT_LIMIT # define FpX_BARRETT_LIMIT __FpX_BARRETT_LIMIT # define FpX_DIVREM_BARRETT_LIMIT __FpX_DIVREM_BARRETT_LIMIT # define FpX_EXTGCD_LIMIT __FpX_EXTGCD_LIMIT # define FpX_GCD_LIMIT __FpX_GCD_LIMIT # define FpX_HALFGCD_LIMIT __FpX_HALFGCD_LIMIT # define FpX_INVBARRETT_LIMIT __FpX_INVBARRETT_LIMIT # define FpX_REM_BARRETT_LIMIT __FpX_REM_BARRETT_LIMIT # define FpXQX_BARRETT_LIMIT __FpXQX_BARRETT_LIMIT # define FpXQX_DIVREM_BARRETT_LIMIT __FpXQX_DIVREM_BARRETT_LIMIT # define FpXQX_EXTGCD_LIMIT __FpXQX_EXTGCD_LIMIT # define FpXQX_GCD_LIMIT __FpXQX_GCD_LIMIT # define FpXQX_HALFGCD_LIMIT __FpXQX_HALFGCD_LIMIT # define FpXQX_INVBARRETT_LIMIT __FpXQX_INVBARRETT_LIMIT # define FpXQX_REM_BARRETT_LIMIT __FpXQX_REM_BARRETT_LIMIT # define Fp_POW_BARRETT_LIMIT __Fp_POW_BARRETT_LIMIT # define Fp_POW_REDC_LIMIT __Fp_POW_REDC_LIMIT # define INVMOD_GMP_LIMIT __INVMOD_GMP_LIMIT # define INVNEWTON_LIMIT __INVNEWTON_LIMIT # define LOGAGMCX_LIMIT __LOGAGMCX_LIMIT # define LOGAGM_LIMIT __LOGAGM_LIMIT # define MULII_FFT_LIMIT __MULII_FFT_LIMIT # define MULII_KARATSUBA_LIMIT __MULII_KARATSUBA_LIMIT # define MULRR_MULII_LIMIT __MULRR_MULII_LIMIT # define RgX_MUL_LIMIT __RgX_MUL_LIMIT # define RgX_SQR_LIMIT __RgX_SQR_LIMIT # define SQRI_FFT_LIMIT __SQRI_FFT_LIMIT # define SQRI_KARATSUBA_LIMIT __SQRI_KARATSUBA_LIMIT # define SQRR_SQRI_LIMIT __SQRR_SQRI_LIMIT #endif pari-2.11.2/src/headers/parinf.h0000644000175000017500000000575613326135265015033 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* output of get_nf and get_bnf */ enum { typ_NULL = 0, typ_POL, typ_Q, typ_NF, typ_BNF, typ_BNR, typ_ELL, /* elliptic curve */ typ_QUA, /* quadclassunit */ typ_GAL, /* galoisinit */ typ_BID, typ_BIDZ, typ_PRID, typ_MODPR, typ_RNF }; /* types of algebras */ enum { al_NULL = 0, al_TABLE, al_CSA, al_CYCLIC }; /* models for elements of algebras */ enum { al_INVALID = 0, al_TRIVIAL, al_ALGEBRAIC, al_BASIS, al_MATRIX }; /* idealtyp */ enum { id_PRINCIPAL = 0, id_PRIME, id_MAT }; typedef struct { GEN T, dT; /* defining polynomial (monic ZX), disc(T) */ GEN T0; /* original defining polynomial (ZX) */ GEN unscale; /* T = C*T0(x / unscale), rational */ GEN dK; /* disc(K) */ GEN index; /* [O_K : Z[X]/(T)] */ GEN basis; /* Z-basis of O_K (t_VEC of t_POL) */ long r1; /* number of real places of K */ GEN basden; /* [nums(bas), dens(bas)] */ GEN dTP, dTE; /* (possibly partial) factorization of dT, primes / exponents */ GEN dKP, dKE; /* (possibly partial) factorization of dK, primes / exponents */ } nfmaxord_t; /* qfr3 / qfr5 */ struct qfr_data { GEN D, sqrtD, isqrtD; }; /* various flags for nf/bnf routines */ enum { nf_ORIG = 1, nf_GEN = 1, nf_ABSOLUTE = 2, nf_FORCE = 2, nf_ALL = 4, nf_GENMAT = 4, nf_INIT = 4, nf_RAW = 8, nf_RED = 8, nf_PARTIALFACT = 16, nf_ROUND2 = 64, /* obsolete */ nf_GEN_IF_PRINCIPAL = 512 }; enum { rnf_REL = 1, rnf_COND = 2 }; /* LLL */ enum { LLL_KER = 1, /* only kernel */ LLL_IM = 2, /* only image */ LLL_ALL = 4, /* kernel & image */ LLL_GRAM = 0x100, LLL_KEEP_FIRST = 0x200, LLL_INPLACE = 0x400, LLL_COMPATIBLE = 0x800 /* attempt same behavior on 32/64bit kernels */ }; /* HNF */ enum { hnf_MODID = 1, hnf_PART = 2, hnf_CENTER = 4 }; /* for fincke_pohst() */ typedef struct FP_chk_fun { GEN (*f)(void *,GEN); /* f_init allowed to permute the columns of u and r */ GEN (*f_init)(struct FP_chk_fun*,GEN,GEN); GEN (*f_post)(struct FP_chk_fun*,GEN,GEN); void *data; long skipfirst; } FP_chk_fun; /* for ideallog / zlog */ typedef struct { GEN bid; GEN P, k; GEN sprk; /* sprk[i] = sprkinit(P[i]^k[i])*/ GEN archp; /* archimedean part of conductor, in permutation form */ GEN U; /* base change matrix blocks from (Z_K/P^k)^* and (Z/2)^#f_oo * to bid.gen */ long hU; /* #bid.gen */ int no2; /* 1 iff fa2 = fa, i.e. no prime of norm 2 divide exactly bid.mod */ } zlog_S; pari-2.11.2/src/desc/0000755000175000017500000000000013461316051012663 5ustar billbillpari-2.11.2/src/desc/gen_tune0000755000175000017500000000434413201017466014422 0ustar billbill#! /usr/bin/perl -w use strict; sub gendefine { my($hash)=@_; for (sort keys %{$hash}) { printf TUNE "#define __%-30s %s\n",$_,$hash->{$_}; } } sub gendefinefile { my($file,$hash32,$hash64)=@_; open TUNE, ">$file"; print TUNE "#ifdef LONG_IS_64BIT\n"; gendefine $hash64; print TUNE "#else\n"; gendefine $hash32; print TUNE "#endif\n"; close TUNE; } sub gentune { my (%none32, %none64, %gmp32, %gmp64, @list); while(<>) { /^#/ and next; my($tunable,$none32,$gmp32,$none64,$gmp64) = split(' '); push @list,$tunable; $none32{$tunable}=$none32; $gmp32{$tunable}=$gmp32; $none64{$tunable}=$none64; $gmp64{$tunable}=$gmp64; } open TUNE, ">src/headers/paritune.h"; print TUNE <src/kernel/none/tune-gen.h"; print TUNE "#ifdef PARI_TUNE\n"; for (@list) { printf TUNE "long %-30s = __%s;\n",$_,$_; } print TUNE "#endif\n"; close TUNE; gendefinefile "src/kernel/none/tune.h",\%none32,\%none64; gendefinefile "src/kernel/gmp/tune.h",\%gmp32,\%gmp64; } sub gendesc { my ($file,$hash32,$hash64)=@_; open DESC, "<$file"; my $hash = $hash64; while() { /^#else/ and $hash=$hash32; /#define[ \t]+__([^ ]+)[ \t]+([0-9]+)/ and $hash->{$1}=$2; } close DESC; } sub cc { my $v = $_[0]; return $v if (defined $v); return -1; } sub gendescfile { my (%none32, %none64, %gmp32, %gmp64); gendesc "src/kernel/none/tune.h",\%none32,\%none64; gendesc "src/kernel/gmp/tune.h",\%gmp32,\%gmp64; my %hlist=map {$_=>1} (keys %none32, keys %none64, keys %gmp32, keys %gmp64); my @list = sort keys %hlist; printf "%-30s %7s %7s %7s %7s\n","#LIMIT","none32","gmp32","none64","gmp64"; for $_ (@list) { printf "%-30s %7s %7s %7s %7s\n",$_,cc($none32{$_}),cc($gmp32{$_}), cc($none64{$_}),cc($gmp64{$_}); } } my $arg = shift; if ($arg eq "--gendesc") { &gendescfile; } elsif ($arg eq "--gentune") { &gentune; } else { die("Error: gentune --gendesc|--gentune\n"); } pari-2.11.2/src/desc/PARI/0000755000175000017500000000000013461316051013416 5ustar billbillpari-2.11.2/src/desc/PARI/822.pm0000755000175000017500000000721412314242551014275 0ustar billbill#!/usr/bin/perl -w #Copyright (C) 2003 The PARI group. # #This file is part of the GP2C package. # #PARI/GP is free software; you can redistribute it and/or modify it under the #terms of the GNU General Public License as published by the Free Software #Foundation. It is distributed in the hope that it will be useful, but WITHOUT #ANY WARRANTY WHATSOEVER. # #Check the License for details. You should have received a copy of it, along #with the package; see the file 'COPYING'. If not, write to the Free Software #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #Based on Debconf::Format::822 by Joey Hess . package PARI::822; use strict; sub new { bless {} } =d1 NAME PARI::822::read -- Read Description files. =head1 SYNOPSIS $database->PARI::822::new(); $database->read($filename,$mode) PARI::822::read(\%database,$filename,$mode) =head1 DESCRIPTION read the database file $filename and merge the information in the database. Mode is a bitmap flag mode&1: new values cannot overwrite old ones. mode&2: new functions are not allowed. =cut sub read { local $/="\n"; local *FILE; my ($ret,$file,$check)=@_; $check=0 if (!defined($check)); my $invars=0; my ($key, $value); my $last_was_void=0; my $entry; my ($store) = sub { $value =~ s/\s*$//; if (!defined($ret->{$entry}->{$key})) { $ret->{$entry}->{$key}=$value; } elsif (($check&1) and $ret->{$entry}->{$key} ne $value) { die "Unmatched data: $entry: $key: $ret->{$entry}->{$key} ne $value"; } }; open FILE,"<$file"; while (my $line = ) { chomp $line; if ($invars && $line =~ /^\s/) { $line =~ s/^\s//; $value.= ($last_was_void?"\n\n$line":"\n$line"); $last_was_void = 0; next; } $last_was_void = ($line =~ /^\s*$/); next if ($last_was_void); $store->() if ($invars); ($key, $value)=split(/:\s*/, $line, 2); die("Bad entry in $file: $key") if (!defined($value)); if ($key eq 'Function') { $entry=$value; die("New function $value") if (($check&2) and !defined($ret->{$entry})); } $invars=1; } $store->() if ($invars); return 0; } =d1 NAME PARI::822::write -- Write Description files. =head1 SYNOPSIS $database->PARI::822::new(); $database->write($filename) PARI::822::write(\%database,STREAM) =head1 DESCRIPTION output a database to STREAM in canonical 822 format. =cut sub write { my @order=("Function","Class","Section","C-Name","Prototype","Help", "Iterator","Wrapper","Description","Doc"); my %knowfields=map {$_ => 1} @order; my %data=%{shift()}; my $STREAM=shift; defined($STREAM) or $STREAM=*STDOUT; foreach my $func (sort keys %data) { foreach my $field (@order) { my $val=$data{$func}->{$field}; next if (!defined($val)); $val =~ s/\n/\n /g; print $STREAM $field.": $val\n"; } foreach my $field (sort keys %{$data{$func}}) { next if ($knowfields{$field}); my $val=$data{$func}->{$field}; $val =~ s/\n/\n /g; print $STREAM $field.": $val\n"; } print $STREAM "\n"; } } 1; pari-2.11.2/src/desc/doc_make0000755000175000017500000001075313326135265014367 0ustar billbill#!/usr/bin/perl BEGIN { @INC=(".",@INC); } use warnings FATAL => 'all'; use strict; use PARI::822; my (%funcs, %Fun_by_sec, %sec_header, @SECTIONS); PARI::822::read(\%funcs, "pari.desc"); @SECTIONS = qw( programming/control programming/specific programming/parallel default operators conversions combinatorics number_theoretical polynomials linear_algebra transcendental sums number_fields algebras elliptic_curves l_functions modular_forms modular_symbols graphic ); for (keys %funcs) { my ($s) = $funcs{$_}->{Section}; next if (!$s); my ($c) = $funcs{$_}->{Class}; if ($c eq 'header') { $sec_header{$s} = $funcs{$_}->{Doc} } else { push(@{$Fun_by_sec{$s}}, $_); } } for (@SECTIONS) { my ($sec) = $_; my ($head) = $sec_header{$sec}; print "$head\n" if defined($head); next if (!$Fun_by_sec{$sec}); for ( sort @{$Fun_by_sec{$sec}} ) { my ($fun) = $funcs{$_}; my ($doc) = $fun->{Doc}; next if (!defined($doc)); my ($args) = $fun->{Help}; my ($v); $doc =~ s/^[\n\t ]*(.)/uc($1)/e; $args =~ s/ *:.*//s; # sanity checks if ($args =~ /([_a-zA-Z0-9]*)\(/ && $fun->{Function} ne $1) { die "fix $fun->{Function} Help" } if ($fun->{Help} =~ /\$/) { die "\$ in $fun->{Function}"; } die "double parenthesis in $fun->{Function} proto" if ($args =~ /\)\)/); # ok if (!$args || $args =~ /^\w+=\w+\(\)/) { $args = $v = ''; } else { $args =~ s/^[^(]*\((.*)\)/$1/; # args proper $v = $args; $v =~ s/([{}&])/\\$1/g; $v =~ s/\^(\d+)/^{$1}/g; $v =~ s/\[\]/[\\,]/g; $v =~ s/([a-zA-Z]\w+)/\\var{$1}/g; $v =~ s/\^([a-z])/\\hbox{\\kbd{\\pow}}$1/g; $v =~ s/\\var\{flag\}/\\fl/g; $v =~ s/\\var\{(\d+)\}/{$1}/g; $v =~ s/_/\\_/g; # don't merge with first subst: \var{} rule kills it $v = "\$($v)\$"; } if ($doc !~ /\\syn\w*\{/ && $sec !~ /programming\/control/) { $doc .= library_syntax($fun, $args); } s/_def_//; my ($secname) = $_; my ($l) = ($fun->{Section} =~ 'default')? "def,$_": $_; my ($idx) = ($secname =~ s/_/\\_/g)? $l: $secname; print "\n\\subsec{$secname$v}\\kbdsidx{$idx}\\label{se:$l}\n$doc\n"; } } print '\vfill\eject'; sub library_syntax { my ($fun, $args) = @_; return '' if ($fun->{Class} =~ /^(gp|default|gp_default)$/); my ($Cname) = $fun->{'C-Name'}; return '' if (!$Cname); my ($Variant) = $fun->{Variant}; my ($Proto) = $fun->{Prototype}; $Proto =~ s/\\n.*//; # delete Mnemonics my (@proto) = split(//, $Proto); $args =~ s/[{}&]//g; $args =~ s/ *=[^,\)]*//g; # delete default values my (@ARGS) = split(/[,^] */, $args); # ^ for O(p^e) my ($type) = "GEN"; my (@vars)=(); $args = ''; for (my $i = 0; $i <= $#proto; ) { my ($c) = $proto[$i++]; if ($c eq 'l') { $type = "long"; next; } if ($c eq 'v') { $type = "void"; next; } if ($c =~ /^[GWIJE]$/) {$args .= ", GEN " . shift(@ARGS); next;} if ($c eq 'U') {$args .= ", ulong " . shift(@ARGS); next;} if ($c eq 'L') {$args .= ", long " . shift(@ARGS); next;} if ($c eq 'n') {my ($v) = shift(@ARGS); push @vars,"\\kbd{$v}"; $args .= ", long " . $v; next;} if ($c =~ /^[rs]$/) {$args .= ", const char *" . shift(@ARGS); next;} if ($c eq 'p') {$args .= ", long prec"; next;} if ($c eq 'b') {$args .= ", long bitprec"; next;} if ($c eq 'P') {$args .= ", long precdl"; next;} if ($c eq 'C') {$args .= ", GEN ctx"; next;} if ($c eq '') { next; } if ($c eq 'D') { $c = $proto[$i++]; if ($c eq 'G') {$args .= ", GEN " . shift(@ARGS) ." = NULL"; next;} if ($c =~ /^[rs]$/) {$args .= ", const char *" . shift(@ARGS) ." = NULL"; next;} if ($c eq '&') {$args .= ", GEN *". shift(@ARGS) ." = NULL"; next;} if ($c eq 'P') {$args .= ", long precdl"; next;} if ($c eq 'n') { my ($v) = shift(@ARGS); $args .= ", long $v = -1"; push @vars,"\\kbd{$v}"; next; } if ($c eq 'V') { next; } if ($c =~ /^[EI]$/) { $args .= ", GEN ". shift(@ARGS) ." = NULL"; next; } while (($c = $proto[$i++]) ne ',') {} } } $args =~ s/^, //; my ($post); my ($l)=scalar @vars; if ($l==0) { $post=''; } elsif ($l==1) { $post = " where $vars[0] is a variable number"; } else { my ($vl)=join(", ",@vars); $post = " where $vl are variable numbers"; } my ($txt) = "\n\nThe library syntax is \\fun{$type}{$Cname}{$args}$post."; $txt .= "\n$Variant" if ($Variant); return $txt; } pari-2.11.2/src/desc/deftune0000644000175000017500000001077113326135265014254 0ustar billbill#LIMIT none32 gmp32 none64 gmp64 AGM_ATAN_LIMIT 159 89 56 60 DIVRR_GMP_LIMIT -1 4 -1 4 EXPNEWTON_LIMIT 66 197 66 66 F2x_MUL_KARATSUBA_LIMIT 23 23 15 15 Flx_BARRETT_QUARTMULII_LIMIT 244 20 29 23 Flx_BARRETT_HALFMULII_LIMIT 244 23 29 21 Flx_BARRETT_KARATSUBA_LIMIT 905 905 2561 1172 Flx_BARRETT_MULII2_LIMIT 1004 647 30 16 Flx_BARRETT_MULII_LIMIT 2715 433 1681 448 Flx_DIVREM_BARRETT_LIMIT 3942 1289 2804 768 Flx_EXTGCD_LIMIT 850 632 284 241 Flx_GCD_LIMIT 7165 2514 1890 1017 Flx_HALFGCD_QUARTMULII_LIMIT 116 37 60 52 Flx_HALFGCD_HALFMULII_LIMIT 116 78 60 48 Flx_HALFGCD_KARATSUBA_LIMIT 230 139 58 77 Flx_HALFGCD_MULII2_LIMIT 1045 537 64 25 Flx_HALFGCD_MULII_LIMIT 168 91 90 71 Flx_INVBARRETT_QUARTMULII_LIMIT 898 73 424 139 Flx_INVBARRETT_HALFMULII_LIMIT 898 240 424 231 Flx_INVBARRETT_KARATSUBA_LIMIT 3471 3600 5120 5067 Flx_INVBARRETT_MULII2_LIMIT 3672 1815 36 26 Flx_INVBARRETT_MULII_LIMIT 4196 1293 3840 1154 Flx_MUL_QUARTMULII_LIMIT 8 7 5 5 Flx_MUL_HALFMULII_LIMIT 8 7 5 5 Flx_MUL_KARATSUBA_LIMIT 85 90 147 142 Flx_MUL_MULII2_LIMIT 3755 152 5 5 Flx_MUL_MULII_LIMIT 698 8 1639 7 Flx_REM_BARRETT_LIMIT 3942 689 3577 1266 Flx_SQR_QUARTSQRI_LIMIT 6 4 3 3 Flx_SQR_HALFSQRI_LIMIT 6 4 3 3 Flx_SQR_KARATSUBA_LIMIT 159 159 330 316 Flx_SQR_SQRI2_LIMIT 4139 470 8 7 Flx_SQR_SQRI_LIMIT 1276 5 5 5 F2xqX_BARRETT_LIMIT 17 17 17 48 F2xqX_DIVREM_BARRETT_LIMIT 46 46 46 292 F2xqX_INVBARRETT_LIMIT 22 22 22 46 F2xqX_REM_BARRETT_LIMIT 48 48 48 292 FlxqX_BARRETT_LIMIT 17 17 17 17 FlxqX_DIVREM_BARRETT_LIMIT 46 46 46 46 FlxqX_EXTGCD_LIMIT 44 44 44 44 FlxqX_GCD_LIMIT 2544 1289 796 470 FlxqX_HALFGCD_LIMIT 427 89 191 60 FlxqX_INVBARRETT_LIMIT 22 22 22 22 FlxqX_REM_BARRETT_LIMIT 48 48 48 48 FpX_BARRETT_LIMIT 144 44 85 38 FpX_DIVREM_BARRETT_LIMIT 306 116 292 113 FpX_EXTGCD_LIMIT 238 81 117 87 FpX_GCD_LIMIT 1292 414 731 406 FpX_HALFGCD_LIMIT 145 55 75 58 FpX_INVBARRETT_LIMIT 337 121 254 111 FpX_REM_BARRETT_LIMIT 306 127 306 111 FpXQX_BARRETT_LIMIT 12 12 12 12 FpXQX_DIVREM_BARRETT_LIMIT 30 30 30 30 FpXQX_EXTGCD_LIMIT 28 28 34 28 FpXQX_GCD_LIMIT 254 182 254 191 FpXQX_HALFGCD_LIMIT 48 35 56 35 FpXQX_INVBARRETT_LIMIT 40 40 40 40 FpXQX_REM_BARRETT_LIMIT 30 30 30 30 Fp_POW_BARRETT_LIMIT 97 11 101 127 Fp_POW_REDC_LIMIT 99 3 99 17 INVMOD_GMP_LIMIT -1 3 -1 3 INVNEWTON_LIMIT 66 93 550 75 LOGAGMCX_LIMIT 58 32 13 22 LOGAGM_LIMIT 55 45 16 6 MULII_FFT_LIMIT 1386 -1 1441 -1 MULII_KARATSUBA_LIMIT 18 -1 23 -1 MULRR_MULII_LIMIT 422 19 210 55 RgX_MUL_LIMIT 5 7 9 9 RgX_SQR_LIMIT 26 34 35 38 SQRI_FFT_LIMIT 1469 -1 1651 -1 SQRI_KARATSUBA_LIMIT 27 -1 36 -1 SQRR_SQRI_LIMIT 20 9 54 12 pari-2.11.2/src/desc/merge_8220000755000175000017500000000045213201017466014304 0ustar billbill#!/usr/bin/perl -w BEGIN { @INC=(".",@INC); } use PARI::822; open(IN, $ARGV[0]) || die "cannot find $ARGV[0]"; for () { s/^\d+\s+\d+\s+//; PARI::822::read(\%funcs,$_,1) } for (keys %funcs) { $funcs{$_}->{'Class'} = 'basic' if (!defined($funcs{$_}->{'Class'})); } PARI::822::write(\%funcs); pari-2.11.2/src/desc/gen_proto0000755000175000017500000000421213326135265014612 0ustar billbill#!/usr/bin/perl -w BEGIN { @INC=(".",@INC); } use PARI::822; $class=$ARGV[0]; $i = 2; # update MAX_SECTION in gplib.c when changing this %secnumber=( 'operators' => $i++, 'conversions' => $i++, 'combinatorics' => $i++, 'number_theoretical' => $i++, 'polynomials' => $i++, 'linear_algebra' => $i++, 'transcendental' => $i++, 'sums' => $i++, 'number_fields' => $i++, 'algebras' => $i++, 'elliptic_curves' => $i++, 'l_functions' => $i++, 'modular_forms' => $i++, 'modular_symbols' => $i++, 'graphic' => $i++, ); $i++;# skip next = PARI community $secnumber{'symbolic_operators'} = $i++; $secnumber{'member_functions'} = $i++; $secnumber{'programming/internals'} = $i++; $secnumber{'default'} = $i++; # join $secnumber{'programming/control'} = 1; $secnumber{'programming/specific'} = 1; $secnumber{'programming/parallel'} = 1; print <head) #define RTail(rp) ((rp)->tail) #define RXsize(rp) ((rp)->sizex) #define RYsize(rp) ((rp)->sizey) #define RXcursor(rp) ((rp)->cursorx) #define RYcursor(rp) ((rp)->cursory) #define RXshift(rp) ((rp)->xshift) #define RYshift(rp) ((rp)->yshift) #define RXscale(rp) ((rp)->xscale) #define RYscale(rp) ((rp)->yscale) #define RoNext(rop) ((rop)->next) #define RoType(rop) ((rop)->code) #define RoCol(rop) ((rop)->color) #define RoMVx(rop) (RoMV(rop)->x) #define RoMVy(rop) (RoMV(rop)->y) #define RoPTx(rop) (RoPT(rop)->x) #define RoPTy(rop) (RoPT(rop)->y) #define RoLNx1(rop) (RoLN(rop)->x1) #define RoLNy1(rop) (RoLN(rop)->y1) #define RoLNx2(rop) (RoLN(rop)->x2) #define RoLNy2(rop) (RoLN(rop)->y2) #define RoBXx1(rop) (RoBX(rop)->x1) #define RoBXy1(rop) (RoBX(rop)->y1) #define RoBXx2(rop) (RoBX(rop)->x2) #define RoBXy2(rop) (RoBX(rop)->y2) #define RoMPcnt(rop) (RoMP(rop)->count) #define RoMPxs(rop) (RoMP(rop)->xs) #define RoMPys(rop) (RoMP(rop)->ys) #define RoMLcnt(rop) (RoML(rop)->count) #define RoMLxs(rop) (RoML(rop)->xs) #define RoMLys(rop) (RoML(rop)->ys) #define RoSTs(rop) (RoST(rop)->s) #define RoSTl(rop) (RoST(rop)->length) #define RoSTx(rop) (RoST(rop)->x) #define RoSTy(rop) (RoST(rop)->y) #define RoSTdir(rop) (RoST(rop)->dir) #define RoPTTpen(rop) (RoPTT(rop)->pen) #define RoLNTpen(rop) (RoLNT(rop)->pen) #define RoPTSsize(rop) (RoPTS(rop)->size) void gen_draw(struct plot_eng *eng, GEN w, GEN x, GEN y, double xs, double ys); void gp_get_plot(PARI_plot *T); #define gp_get_ploth_default_sizes(S) \ { PARI_plot *_T = (PARI_plot *)S; \ GEN D = GP_DATA->plothsizes; \ if (D) switch(lg(D)) { \ case 5: if (D[4]) _T->vunit = D[4]; \ case 4: if (D[3]) _T->hunit = D[3]; \ case 3: if (D[2]) _T->height = D[2]; \ case 2: if (D[1]) _T->width = D[1]; \ } \ } #define gp_get_plot_generic(S,gp_get_display_sizes) \ { PARI_plot *_T = (PARI_plot *)S; \ gp_get_display_sizes(&_T->dwidth, &_T->dheight, &_T->fwidth, &_T->fheight);\ _T->width = _T->dwidth? _T->dwidth*4/5: 640; \ _T->height= _T->dheight?_T->dheight*4/5: 480; \ _T->hunit = maxss(_T->height/100,3); \ _T->vunit = maxss(_T->height/100,3); \ gp_get_ploth_default_sizes(S); \ } ENDEXTERN pari-2.11.2/src/graph/plotport.c0000644000175000017500000024731613457566440015130 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* PLOT ROUTINES */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" #include "rect.h" static void (*pari_get_plot)(PARI_plot *); /* no need for THREAD: OK to share this */ static hashtable *rgb_colors = NULL; THREAD PariRect rectgraph[18]; /*NUMRECT*/ static THREAD long current_color[18]; /*NUMRECT*/ static long plotpoint_itype = 0, rectline_itype = 0; const long NUMRECT = 18; const long RECUR_MAXDEPTH = 10; const double RECUR_PREC = 0.001; const long DEFAULT_COLOR = 1, AXIS_COLOR = 2; enum { ROt_MV = 1, /* Move */ ROt_PT, /* Point */ ROt_LN, /* Line */ ROt_BX, /* Box */ ROt_FBX, /* Filled Box */ ROt_MP, /* Multiple point */ ROt_ML, /* Multiple lines */ ROt_ST, /* String */ ROt_PTT, /* Point type change */ ROt_LNT, /* Line type change */ ROt_PTS, /* Point size change */ ROt_NULL, /* To be the start of the chain */ }; /* string justification */ #define RoSTdirLEFT 0x00 #define RoSTdirRIGHT 0x02 #define RoSTdirHPOS_mask 0x03 #define RoSTdirBOTTOM 0x00 #define RoSTdirTOP 0x08 #define RoSTdirVPOS_mask 0x0c #define RoSTdirHGAP 0x10 #define RoSTdirVGAP 0x20 /* ploth flags */ #define PLOT_PARAMETRIC 0x00001 #define PLOT_RECURSIVE 0x00002 #define PLOT_NO_RESCALE 0x00004 #define PLOT_NO_AXE_X 0x00008 #define PLOT_NO_AXE_Y 0x00010 #define PLOT_NO_FRAME 0x00020 #define PLOT_POINTS 0x00040 #define PLOT_POINTS_LINES 0x00080 #define PLOT_SPLINES 0x00100 #define PLOT_NO_TICK_X 0x00200 #define PLOT_NO_TICK_Y 0x00400 #define PLOT_NODOUBLETICK 0x00800 #define PLOT_COMPLEX 0x01000 #define PLOT_PARA 0x02000 INLINE long DTOL(double t) { return (long)(t + 0.5); } static const long PS_WIDTH = 1120 - 60; /* 1400 - 60 for hi-res */ static const long PS_HEIGH = 800 - 40; /* 1120 - 60 for hi-res */ static void _psdraw_scale(PARI_plot *T, GEN w, GEN x, GEN y) { pari_sp av = avma; FILE *F = fopen(current_psfile, "a"); if (!F) pari_err_FILE("postscript file",current_psfile); fputs(rect2ps(w,x,y,T), F); fclose(F); avma = av; } static void _psdraw(PARI_plot *T, GEN w, GEN x, GEN y) { (void)T; _psdraw_scale(NULL,w,x,y); } static void pari_get_psplot(PARI_plot *T) { T->width = PS_WIDTH; T->height = PS_HEIGH; T->fheight= 15; T->fwidth = 6; T->hunit = 5; T->vunit = 5; T->dwidth = 0; T->dheight= 0; T->draw = NULL; } static void pari_get_svgplot(PARI_plot *T) { T->width = 480; T->height = 320; T->fheight = 12; T->fwidth = 6; T->hunit = 3; T->vunit = 3; T->dwidth = 0; T->dheight = 0; T->draw = NULL; } /********************************************************************/ /** **/ /** RECTPLOT FUNCTIONS **/ /** **/ /********************************************************************/ static void get_plot_null(PARI_plot *T) { (void)T; pari_err(e_MISC,"high resolution graphics disabled"); } void pari_init_graphics(void) { pari_get_plot = &get_plot_null; } void pari_set_plot_engine(void (*plot)(PARI_plot *)) { long n; pari_get_plot = plot; for (n = 0; n < NUMRECT; n++) { PariRect *e = &rectgraph[n]; RHead(e) = RTail(e) = NULL; RXsize(e) = RYsize(e) = 0; } } void pari_kill_plot_engine(void) { int i; for (i=0; itable); pari_free((void*)rgb_colors); } } static PariRect * check_rect(long ne) { const char *f = "graphic function"; const long m = NUMRECT-1; if (ne < 0) pari_err_DOMAIN(f, "rectwindow", "<", gen_0, stoi(ne)); if (ne > m) pari_err_DOMAIN(f, "rectwindow", ">", stoi(m), stoi(ne)); return &rectgraph[ne]; } static PariRect * check_rect_init(long ne) { PariRect *e = check_rect(ne); if (!RHead(e)) pari_err_TYPE("graphic function [use plotinit()]", stoi(ne)); return e; } static void Rchain(PariRect *e, RectObj *z) { if (!RHead(e)) RHead(e) = z; else RoNext(RTail(e)) = z; RTail(e) = z; RoNext(z) = NULL; } static long rgb_to_long(long r, long g, long b) { return (r << 16) | (g << 8) | b; } /* c from graphcolormap */ static long colormap_to_color(long i) { GEN c = GP_DATA->colormap; long k = i+1, l = lg(c)-1; int r, g, b; if (k > l) pari_err_COMPONENT("graphcolormap",">", stoi(l), stoi(k)); color_to_rgb(gel(c, k), &r,&g,&b); return rgb_to_long(r, g, b); } static void initrect_i(long ne, long x, long y) { PariRect *e; RectObj *z; if (x <= 1) pari_err_DOMAIN("plotinit", "x", "<=", gen_1, stoi(x)); if (y <= 1) pari_err_DOMAIN("plotinit", "y", "<=", gen_1, stoi(y)); e = check_rect(ne); if (RHead(e)) plotkill(ne); current_color[ne] = colormap_to_color(DEFAULT_COLOR); z = (RectObj*) pari_malloc(sizeof(RectObj)); RoType(z) = ROt_NULL; Rchain(e, z); RXsize(e) = x; RXcursor(e) = 0; RXscale(e) = 1; RXshift(e) = 0; RYsize(e) = y; RYcursor(e) = 0; RYscale(e) = 1; RYshift(e) = 0; } static long initrect_get_arg(GEN x, long dft) { if (!x) return dft; if (typ(x) != t_INT) pari_err_TYPE("plotinit",x); return itos(x); } void plotinit(long ne, GEN x, GEN y, long flag) { const long m = NUMRECT-3; long xi, yi; PARI_plot T; if (flag) { pari_get_plot(&T); xi = T.width -1; if (x) xi = DTOL(xi * gtodouble(x)); yi = T.height-1; if (y) yi = DTOL(yi * gtodouble(y)); } else { if (!x || !y) pari_get_plot(&T); xi = initrect_get_arg(x, T.width -1); yi = initrect_get_arg(y, T.height-1); } if (ne > m) pari_err_DOMAIN("plotinit", "rectwindow", ">", stoi(m), stoi(ne)); initrect_i(ne, xi, yi); } GEN plotcursor(long ne) { PariRect *e = check_rect_init(ne); return mkvec2s((long)RXcursor(e), (long)RYcursor(e)); } static void plotscale0(long ne, double x1, double x2, double y1, double y2) { PariRect *e = check_rect_init(ne); double x, y; x = RXshift(e) + RXscale(e) * RXcursor(e); y = RYshift(e) + RYscale(e) * RYcursor(e); RXscale(e) = RXsize(e)/(x2-x1); RXshift(e) = -x1*RXscale(e); RYscale(e) = RYsize(e)/(y1-y2); RYshift(e) = -y2*RYscale(e); RXcursor(e) = (x - RXshift(e)) / RXscale(e); RYcursor(e) = (y - RYshift(e)) / RYscale(e); } void plotscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2) { plotscale0(ne, gtodouble(x1), gtodouble(x2), gtodouble(y1), gtodouble(y2)); } static void plotmove0(long ne, double x, double y, long relative) { PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj1P)); if (relative) { RXcursor(e) += x; RYcursor(e) += y; } else { RXcursor(e) = x; RYcursor(e) = y; } RoType(z) = ROt_MV; RoMVx(z) = RXcursor(e) * RXscale(e) + RXshift(e); RoMVy(z) = RYcursor(e) * RYscale(e) + RYshift(e); Rchain(e, z); } static void _move(long ne, double x, double y) { plotmove0(ne,x,y,0); } void plotmove(long ne, GEN x, GEN y) { plotmove0(ne,gtodouble(x),gtodouble(y),0); } void plotrmove(long ne, GEN x, GEN y) { plotmove0(ne,gtodouble(x),gtodouble(y),1); } /* ROt_MV/ROt_PT */ static void plotpoint0(long ne, double x, double y,long relative) { PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj1P)); if (relative) { RXcursor(e) += x; RYcursor(e) += y; } else { RXcursor(e) = x; RYcursor(e) = y; } RoPTx(z) = RXcursor(e)*RXscale(e) + RXshift(e); RoPTy(z) = RYcursor(e)*RYscale(e) + RYshift(e); RoType(z) = ( DTOL(RoPTx(z)) < 0 || DTOL(RoPTy(z)) < 0 || DTOL(RoPTx(z)) > RXsize(e) || DTOL(RoPTy(z)) > RYsize(e) ) ? ROt_MV : ROt_PT; Rchain(e, z); RoCol(z) = current_color[ne]; } static void plotpoint(long ne, GEN x, GEN y) { plotpoint0(ne,gtodouble(x),gtodouble(y),0); } void plotrpoint(long ne, GEN x, GEN y) { plotpoint0(ne,gtodouble(x),gtodouble(y),1); } GEN plotcolor(long ne, GEN c) { long t = typ(c), n = lg(GP_DATA->colormap)-2; int r, g, b; check_rect(ne); if (t == t_INT) { long i = itos(c); if (i < 0) pari_err_DOMAIN("plotcolor", "color", "<", gen_0, c); if (i > n) pari_err_DOMAIN("plotcolor", "color", ">", stoi(n), c); c = gel(GP_DATA->colormap,i+1); } else { if (t == t_VEC) { c = ZV_to_zv(c); t = typ(c); } if (t != t_VECSMALL && t != t_STR) pari_err_TYPE("plotcolor",c); } color_to_rgb(c, &r,&g,&b); current_color[ne] = rgb_to_long(r,g,b); return mkvec3s(r, g, b); } /* ROt_MV/ROt_LN */ static void rectline0(long ne, double gx2, double gy2, long relative) { double dx, dy, dxy, xmin, xmax, ymin, ymax, x1, y1, x2, y2; PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj2P)); const double c = 1 + 1e-10; x1 = RXcursor(e)*RXscale(e) + RXshift(e); y1 = RYcursor(e)*RYscale(e) + RYshift(e); if (relative) { RXcursor(e)+=gx2; RYcursor(e)+=gy2; } else { RXcursor(e)=gx2; RYcursor(e)=gy2; } x2 = RXcursor(e)*RXscale(e) + RXshift(e); y2 = RYcursor(e)*RYscale(e) + RYshift(e); xmin = maxdd(mindd(x1,x2),0); xmax = mindd(maxdd(x1,x2),RXsize(e)); ymin = maxdd(mindd(y1,y2),0); ymax = mindd(maxdd(y1,y2),RYsize(e)); dxy = x1*y2 - y1*x2; dx = x2-x1; dy = y2-y1; if (dy) { double a = (dxy + RYsize(e)*dx) / dy, b = dxy / dy; if (dx*dy < 0) { xmin=maxdd(xmin,a); xmax=mindd(xmax,b); } else { xmin=maxdd(xmin,b); xmax=mindd(xmax,a); } } if (dx) { double a = (RXsize(e)*dy - dxy) / dx, b = -dxy / dx; if (dx*dy < 0) { ymin=maxdd(ymin,a); ymax=mindd(ymax,b); } else { ymin=maxdd(ymin,b); ymax=mindd(ymax,a); } } RoLNx1(z) = xmin; RoLNx2(z) = xmax; if (dx*dy < 0) { RoLNy1(z) = ymax; RoLNy2(z) = ymin; } else { RoLNy1(z) = ymin; RoLNy2(z) = ymax; } RoType(z) = (xmin>xmax*c || ymin>ymax*c) ? ROt_MV : ROt_LN; Rchain(e, z); RoCol(z) = current_color[ne]; } static void _line(long ne, double x, double y) { rectline0(ne, x, y, 0); } void plotline(long ne, GEN gx2, GEN gy2) { rectline0(ne, gtodouble(gx2), gtodouble(gy2),0); } void plotrline(long ne, GEN gx2, GEN gy2) { rectline0(ne, gtodouble(gx2), gtodouble(gy2),1); } enum { TICKS_CLOCKW = 1, /* Draw in clockwise direction */ TICKS_ACLOCKW = 2, /* Draw in anticlockwise direction */ TICKS_ENDSTOO = 4, /* Draw at endspoints if needed */ TICKS_NODOUBLE = 8 /* Do not draw double-length ticks */ }; /* Given coordinates of ends of a line, and labels l1 l2 attached to the * ends, plot ticks where the label coordinate takes "round" values */ static void rectticks(PARI_plot *WW, long ne, double dx1, double dy1, double dx2, double dy2, double l1, double l2, long flags) { long dx, dy, dxy, dxy1, x1, y1, x2, y2, nticks, n, n1, dn; double minstep, maxstep, step, l_min, l_max, minl, maxl, dl, dtx, dty, x, y; double ddx, ddy; const double mult[3] = { 2./1., 5./2., 10./5. }; PariRect *e = check_rect_init(ne); int do_double = !(flags & TICKS_NODOUBLE); x1 = DTOL(dx1*RXscale(e) + RXshift(e)); y1 = DTOL(dy1*RYscale(e) + RYshift(e)); x2 = DTOL(dx2*RXscale(e) + RXshift(e)); y2 = DTOL(dy2*RYscale(e) + RYshift(e)); dx = x2 - x1; if (dx < 0) dx = -dx; dy = y2 - y1; if (dy < 0) dy = -dy; dxy1 = maxss(dx, dy); dx /= WW->hunit; dy /= WW->vunit; if (dx > 1000 || dy > 1000) dxy = 1000; /* avoid overflow */ else dxy = usqrt(dx*dx + dy*dy); nticks = (long) ((dxy + 2.5)/4); if (!nticks) return; /* Find nticks (or less) "round" numbers between l1 and l2. For our purpose * round numbers have "last significant" decimal digit either * - any; * - even; * - divisible by 5. * We need to choose which alternative is better. */ if (l1 < l2) l_min = l1, l_max = l2; else l_min = l2, l_max = l1; minstep = (l_max - l_min)/(nticks + 1); maxstep = 2.5*(l_max - l_min); step = exp(log(10.) * floor(log10(minstep))); if (!(flags & TICKS_ENDSTOO)) { double d = 2*(l_max - l_min)/dxy1; /* Two pixels off */ l_min += d; l_max -= d; } for (n = 0; ; n++) { if (step >= maxstep) return; if (step >= minstep) { minl = ceil(l_min/step); maxl = floor(l_max/step); if (minl <= maxl && maxl - minl + 1 <= nticks) { nticks = (long) (maxl - minl + 1); l_min = minl * step; l_max = maxl * step; break; } } step *= mult[ n % 3 ]; } /* Where to position doubleticks. Variants: * small: each 5, double: each 10 ; n=2 mod 3 * small: each 2, double: each 10 ; n=1 mod 3 * small: each 1, double: each 5 */ dn = (n % 3 == 2)? 2: 5; n1 = ((long)minl) % dn; /* unused if do_double = FALSE */ /* now l_min and l_max keep min/max values of l with ticks, and nticks is the number of ticks to draw. */ if (nticks == 1) ddx = ddy = 0; /* -Wall */ else { dl = (l_max - l_min)/(nticks - 1); ddx = (dx2 - dx1) * dl / (l2 - l1); ddy = (dy2 - dy1) * dl / (l2 - l1); } x = dx1 + (dx2 - dx1) * (l_min - l1) / (l2 - l1); y = dy1 + (dy2 - dy1) * (l_min - l1) / (l2 - l1); /* assume hunit and vunit form a square. For clockwise ticks: */ dtx = WW->hunit * dy/dxy * (y2 > y1 ? 1 : -1); /* y-coord runs down */ dty = WW->vunit * dx/dxy * (x2 > x1 ? 1 : -1); for (n = 0; n < nticks; n++, x += ddx, y += ddy) { RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj2P)); double lunit = WW->hunit > 1 ? 1.5 : 2; double l = (do_double && (n + n1) % dn == 0) ? lunit: 1; double x1, x2, y1, y2; x1 = x2 = x*RXscale(e) + RXshift(e); y1 = y2 = y*RYscale(e) + RYshift(e); if (flags & TICKS_CLOCKW) { x1 += dtx*l; y1 -= dty*l; } if (flags & TICKS_ACLOCKW) { x2 -= dtx*l; y2 += dty*l; } RoLNx1(z) = x1; RoLNy1(z) = y1; RoLNx2(z) = x2; RoLNy2(z) = y2; RoType(z) = ROt_LN; Rchain(e, z); RoCol(z) = current_color[ne]; } } static void rectbox0(long ne, double gx2, double gy2, long relative, long filled) { double xx, yy, x1, y1, x2, y2, xmin, ymin, xmax, ymax; PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj2P)); x1 = RXcursor(e)*RXscale(e) + RXshift(e); y1 = RYcursor(e)*RYscale(e) + RYshift(e); if (relative) { xx = RXcursor(e)+gx2; yy = RYcursor(e)+gy2; } else { xx = gx2; yy = gy2; } x2 = xx*RXscale(e) + RXshift(e); y2 = yy*RYscale(e) + RYshift(e); xmin = maxdd(mindd(x1,x2),0); xmax = mindd(maxdd(x1,x2),RXsize(e)); ymin = maxdd(mindd(y1,y2),0); ymax = mindd(maxdd(y1,y2),RYsize(e)); RoType(z) = filled ? ROt_FBX: ROt_BX; RoBXx1(z) = xmin; RoBXy1(z) = ymin; RoBXx2(z) = xmax; RoBXy2(z) = ymax; Rchain(e, z); RoCol(z) = current_color[ne]; } static void _box(long ne, double x, double y) { rectbox0(ne, x, y, 0, 0); } void plotbox(long ne, GEN gx2, GEN gy2, long f) { rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 0, f); } void plotrbox(long ne, GEN gx2, GEN gy2, long f) { rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 1, f); } static void freeobj(RectObj *z) { switch(RoType(z)) { case ROt_MP: case ROt_ML: pari_free(RoMPxs(z)); pari_free(RoMPys(z)); break; case ROt_ST: pari_free(RoSTs(z)); break; } pari_free(z); } void plotkill(long ne) { RectObj *z, *t; PariRect *e = check_rect_init(ne); z = RHead(e); RHead(e) = RTail(e) = NULL; RXsize(e) = RYsize(e) = 0; RXcursor(e) = RYcursor(e) = 0; RXscale(e) = RYscale(e) = 1; RXshift(e) = RYshift(e) = 0; while (z) { t = RoNext(z); freeobj(z); z = t; } } /* ROt_MP */ static void plotpoints0(long ne, double *X, double *Y, long lx) { double *px, *py; long i, cp=0; PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) pari_malloc(sizeof(RectObjMP)); RoMPxs(z) = px = (double*) pari_malloc(lx*sizeof(double)); RoMPys(z) = py = (double*) pari_malloc(lx*sizeof(double)); for (i=0; i= 0 && y >= 0 && x <= RXsize(e) && y <= RYsize(e)) { px[cp] = x; py[cp] = y; cp++; } } RoType(z) = ROt_MP; RoMPcnt(z) = cp; Rchain(e, z); RoCol(z) = current_color[ne]; } void plotpoints(long ne, GEN X, GEN Y) { pari_sp av = avma; double *px, *py; long i, lx; if (!is_vec_t(typ(X)) || !is_vec_t(typ(Y))) { plotpoint(ne, X, Y); return; } lx = lg(X); if (lg(Y) != lx) pari_err_DIM("plotpoints"); lx--; if (!lx) return; px = (double*)stack_malloc_align(lx*sizeof(double), sizeof(double)); X++; py = (double*)stack_malloc_align(lx*sizeof(double), sizeof(double)); Y++; for (i=0; i 1) pari_err_DOMAIN("plotcopy","dx",">",gen_1,xoff); if (xd < 0) pari_err_DOMAIN("plotcopy","dx","<",gen_0,xoff); if (yd > 1) pari_err_DOMAIN("plotcopy","dy",">",gen_1,yoff); if (yd < 0) pari_err_DOMAIN("plotcopy","dy","<",gen_0,yoff); pari_get_plot(&T); x = DTOL(xd * (T.width-1)); y = DTOL(yd * (T.height-1)); } else { if (typ(xoff) != t_INT) pari_err_TYPE("plotcopy",xoff); if (typ(yoff) != t_INT) pari_err_TYPE("plotcopy",yoff); x = itos(xoff); y = itos(yoff); } switch (flag & ~RECT_CP_RELATIVE) { case RECT_CP_NW: break; case RECT_CP_SW: y = RYsize(d) - RYsize(s) - y; break; case RECT_CP_SE: y = RYsize(d) - RYsize(s) - y; /* fall through */ case RECT_CP_NE: x = RXsize(d) - RXsize(s) - x; break; } for (R = RHead(s); R; R = RoNext(R)) { RectObj *o; switch(RoType(R)) { case ROt_PT: o = (RectObj*)cp(R, sizeof(RectObj1P)); RoPTx(o) += x; RoPTy(o) += y; break; case ROt_LN: case ROt_BX: case ROt_FBX: o = (RectObj*)cp(R, sizeof(RectObj2P)); RoLNx1(o) += x; RoLNy1(o) += y; RoLNx2(o) += x; RoLNy2(o) += y; break; case ROt_MP: case ROt_ML: o = (RectObj*)cp(R, sizeof(RectObjMP)); RoMPxs(o) = (double*)cp(RoMPxs(R), sizeof(double)*RoMPcnt(o)); RoMPys(o) = (double*)cp(RoMPys(R), sizeof(double)*RoMPcnt(o)); for (i=0; i xmax && x2 > xmax)) return 0; if (fabs(x1 - x2) < fabs(y1 - y2)) { /* Exchange x and y */ xy_exch = 1; dswap(xmin, ymin); dswap(x1, y1); dswap(xmax, ymax); dswap(x2, y2); } /* Build y as a function of x */ xi = x1; yi = y1; sl = x1==x2? 0: (y2 - yi)/(x2 - xi); if (x1 > x2) { x1_is_xmn = 0; xmn = x2; xmx = x1; } else { x1_is_xmn = 1; xmn = x1; xmx = x2; } if (xmn < xmin) { xmn = xmin; rc |= x1_is_xmn? CLIPLINE_CLIP_1: CLIPLINE_CLIP_2; } if (xmx > xmax) { xmx = xmax; rc |= x1_is_xmn? CLIPLINE_CLIP_2: CLIPLINE_CLIP_1; } if (xmn > xmx) return 0; ymn = yi + (xmn - xi)*sl; ymx = yi + (xmx - xi)*sl; if (sl < 0) t = ymn, ymn = ymx, ymx = t; if (ymn > ymax || ymx < ymin) return 0; if (rc & CLIPLINE_CLIP_1) x1 = x1_is_xmn? xmn: xmx; if (rc & CLIPLINE_CLIP_2) x2 = x1_is_xmn? xmx: xmn; /* Now we know there is an intersection, need to move x1 and x2 */ x1_is_ymn = ((sl >= 0) == (x1 < x2)); if (ymn < ymin) { double x = (ymin - yi)/sl + xi; /* slope != 0 ! */ if (x1_is_ymn) x1 = x, rc |= CLIPLINE_CLIP_1; else x2 = x, rc |= CLIPLINE_CLIP_2; } if (ymx > ymax) { double x = (ymax - yi)/sl + xi; /* slope != 0 ! */ if (x1_is_ymn) x2 = x, rc |= CLIPLINE_CLIP_2; else x1 = x, rc |= CLIPLINE_CLIP_1; } if (rc & CLIPLINE_CLIP_1) y1 = yi + (x1 - xi)*sl; if (rc & CLIPLINE_CLIP_2) y2 = yi + (x2 - xi)*sl; if (xy_exch) /* Exchange x and y */ *x1p = y1, *x2p = y2, *y1p = x1, *y2p = x2; else *x1p = x1, *x2p = x2, *y1p = y1, *y2p = y2; return rc; } void plotclip(long rect) { PariRect *s = check_rect_init(rect); RectObj *next, *R = RHead(s), **prevp = &RHead(s); double xmin = 0, xmax = RXsize(s); double ymin = 0, ymax = RYsize(s); for (; R; R = next) { int did_clip = 0; #define REMOVE() { *prevp = next; freeobj(R); break; } #define NEXT() { prevp = &RoNext(R); break; } next = RoNext(R); switch(RoType(R)) { case ROt_PT: if ( DTOL(RoPTx(R)) < xmin || DTOL(RoPTx(R)) > xmax || DTOL(RoPTy(R)) < ymin || DTOL(RoPTy(R)) > ymax) REMOVE(); NEXT(); case ROt_BX: case ROt_FBX: if (RoLNx1(R) < xmin) RoLNx1(R) = xmin, did_clip = 1; if (RoLNx2(R) < xmin) RoLNx2(R) = xmin, did_clip = 1; if (RoLNy1(R) < ymin) RoLNy1(R) = ymin, did_clip = 1; if (RoLNy2(R) < ymin) RoLNy2(R) = ymin, did_clip = 1; if (RoLNx1(R) > xmax) RoLNx1(R) = xmax, did_clip = 1; if (RoLNx2(R) > xmax) RoLNx2(R) = xmax, did_clip = 1; if (RoLNy1(R) > ymax) RoLNy1(R) = ymax, did_clip = 1; if (RoLNy2(R) > ymax) RoLNy2(R) = ymax, did_clip = 1; /* Remove zero-size clipped boxes */ if (did_clip && RoLNx1(R) == RoLNx2(R) && RoLNy1(R) == RoLNy2(R)) REMOVE(); NEXT(); case ROt_LN: if (!clipline(xmin, xmax, ymin, ymax, &RoLNx1(R), &RoLNy1(R), &RoLNx2(R), &RoLNy2(R))) REMOVE(); NEXT(); case ROt_MP: { int c = RoMPcnt(R), f = 0, t = 0; while (f < c) { if ( DTOL(RoMPxs(R)[f]) >= xmin && DTOL(RoMPxs(R)[f]) <= xmax && DTOL(RoMPys(R)[f]) >= ymin && DTOL(RoMPys(R)[f]) <= ymax) { if (t != f) { RoMPxs(R)[t] = RoMPxs(R)[f]; RoMPys(R)[t] = RoMPys(R)[f]; } t++; } f++; } if (t == 0) REMOVE(); RoMPcnt(R) = t; NEXT(); } case ROt_ML: { /* Hard case. Break a multiline into several pieces * if some part is clipped. */ int c = RoMPcnt(R) - 1; int f = 0, t = 0, had_lines = 0, had_hole = 0, rc; double ox = RoMLxs(R)[0], oy = RoMLys(R)[0], oxn, oyn; while (f < c) { /* Endpoint of this segment is startpoint of next one: need to * preserve it if it is clipped. */ oxn = RoMLxs(R)[f+1]; oyn = RoMLys(R)[f+1]; rc = clipline(xmin, xmax, ymin, ymax, &ox, &oy, /* &RoMLxs(R)[f], &RoMLys(R)[f], */ &RoMLxs(R)[f+1], &RoMLys(R)[f+1]); RoMLxs(R)[f] = ox; ox = oxn; RoMLys(R)[f] = oy; oy = oyn; if (!rc) { if (had_lines) had_hole = 1; f++; continue; } if (!had_lines || (!(rc & CLIPLINE_CLIP_1) && !had_hole) ) { /* Continuous */ had_lines = 1; if (t != f) { if (t == 0) { RoMPxs(R)[t] = RoMPxs(R)[f]; RoMPys(R)[t] = RoMPys(R)[f]; } RoMPxs(R)[t+1] = RoMPxs(R)[f+1]; RoMPys(R)[t+1] = RoMPys(R)[f+1]; } t++; f++; if (rc & CLIPLINE_CLIP_2) had_hole = 1, RoMLcnt(R) = t+1; continue; } /* Is not continuous, automatically R is not pari_free()ed. */ t++; RoMLcnt(R) = t; if (rc & CLIPLINE_CLIP_2) { /* Needs separate entry */ RectObj *n = (RectObj*) pari_malloc(sizeof(RectObj2P)); RoType(n) = ROt_LN; RoCol(n) = RoCol(R); RoLNx1(n) = RoMLxs(R)[f]; RoLNy1(n) = RoMLys(R)[f]; RoLNx2(n) = RoMLxs(R)[f+1]; RoLNy2(n) = RoMLys(R)[f+1]; RoNext(n) = next; RoNext(R) = n; /* Restore the unclipped value: */ RoMLxs(R)[f+1] = oxn; RoMLys(R)[f+1] = oyn; f++; prevp = &RoNext(n); } if (f + 1 < c) { /* Are other lines */ RectObj *n = (RectObj*) pari_malloc(sizeof(RectObjMP)); RoType(n) = ROt_ML; RoCol(n) = RoCol(R); RoMLcnt(n) = c - f; RoMLxs(n) = cpd(RoMPxs(R) + f, c-f); RoMLys(n) = cpd(RoMPys(R) + f, c-f); RoMPxs(n)[0] = oxn; RoMPys(n)[0] = oyn; RoNext(n) = next; RoNext(R) = n; next = n; } break; } if (t == 0) REMOVE(); NEXT(); } } #undef REMOVE #undef NEXT } } /********************************************************************/ /** **/ /** HI-RES PLOT **/ /** **/ /********************************************************************/ static void set_xrange(dblPointList *f, double x) { if (x < f->xsml) f->xsml = x; if (x > f->xbig) f->xbig = x; } static void Appendxat(dblPointList *f, dblPointList *l,long n,double x) { (l->d)[n] = x; l->nb = n+1; set_xrange(f,x); } static void set_yrange(dblPointList *f, double y) { if (y < f->ysml) f->ysml = y; if (y > f->ybig) f->ybig = y; } static void Appendyat(dblPointList *f, dblPointList *l,long n,double y) { (l->d)[n] = y; l->nb = n+1; set_yrange(f,y); } static void Appendx(dblPointList *f, dblPointList *l,double x) { Appendxat(f,l,l->nb,x); } static void Appendy(dblPointList *f, dblPointList *l,double y) { Appendyat(f,l,l->nb,y); } static void get_xy(long cplx, GEN t, double *x, double *y) { GEN a, b; if (cplx) { if (typ(t) == t_VEC) { if (lg(t) != 2) pari_err_DIM("get_xy"); t = gel(t,1); } a = real_i(t); b = imag_i(t); } else { if (typ(t) != t_VEC || lg(t) != 3) pari_err_DIM("get_xy"); a = gel(t,1); b = gel(t,2); } *x = gtodouble(a); *y = gtodouble(b); } /* t a t_VEC (possibly a scalar if cplx), get next (x,y) coordinate starting * at index *i [update i] */ static void get_xy_from_vec(long cplx, GEN t, long *i, double *x, double *y) { GEN a, b; if (cplx) { if (typ(t) == t_VEC) t = gel(t,*i); a = real_i(t); b = imag_i(t); (*i)++; } else { a = gel(t, (*i)++); b = gel(t, (*i)++); } *x = gtodouble(a); *y = gtodouble(b); } /* X,Y t_VEC; next (x,y) coordinate starting at index i; Y ignored if (cplx) */ static void get_xy_from_vec2(long cplx, GEN X, GEN Y, long i, double *x, double *y) { GEN a, b; if (cplx) { GEN z = gel(X,i); a = real_i(z); b = imag_i(z); } else { a = gel(X,i); b = gel(Y,i); } *x = gtodouble(a); *y = gtodouble(b); } /* Convert data from GEN to double before we call plotrecthrawin. */ static dblPointList* gtodblList(GEN data, long flags) { dblPointList *l, *L; double *X, *Y; long nl=lg(data)-1, lx1, i, j; const long param = (flags & (PLOT_PARAMETRIC|PLOT_COMPLEX)); const long cplx = (flags & PLOT_COMPLEX); if (! is_vec_t(typ(data))) pari_err_TYPE("gtodblList",data); if (!nl) return NULL; lx1 = lg(gel(data,1)); if (!param && lx1 == 1) return NULL; if (nl == 1 && !cplx) pari_err_DIM("gtodblList"); /* Allocate memory, then convert coord. to double */ l = (dblPointList*)pari_malloc((cplx? 2*nl: nl)*sizeof(dblPointList)); L = &l[0]; for (i = 0; i < nl; i += cplx? 1: 2) { GEN x = gel(data,i+1), y; long lx = lg(x); if (!is_vec_t(typ(x))) pari_err_TYPE("gtodblList",x); if (cplx) y = NULL; else { y = gel(data,i+2); if (!is_vec_t(typ(y))) pari_err_TYPE("gtodblList",y); if (lg(y) != lx || (!param && lx != lx1)) pari_err_DIM("gtodblList"); } lx--; l[i].d = X = (double*)pari_malloc(lx*sizeof(double)); l[i+1].d = Y = (double*)pari_malloc(lx*sizeof(double)); for (j=1; j<=lx; j++) get_xy_from_vec2(cplx, x, y, j, X+(j-1), Y+(j-1)); l[i].nb = l[i+1].nb = lx; } /* Compute extremas */ if (param) { L->nb = cplx? nl: nl/2; for (i=0; i < L->nb; i+=2) if (l[i+1].nb) break; if (i >= L->nb) { pari_free(l); return NULL; } L->xsml = L->xbig = l[i ].d[0]; L->ysml = L->ybig = l[i+1].d[0]; for (; i < L->nb; i+=2) { long nbi = l[i+1].nb; X = l[i].d; Y = l[i+1].d; for (j = 0; j < nbi; j++) { set_xrange(L, X[j]); set_yrange(L, Y[j]); } } } else { L->nb = nl-1; X = L->d; L->xsml = L->xbig = X[0]; Y = l[1].d; L->ysml = L->ybig = Y[0]; for (j=0; j < l[1].nb; j++) set_xrange(L, X[j]); for (i=1; i <= L->nb; i++) { long nbi = l[i].nb; Y = l[i].d; for (j = 0; j < nbi; j++) set_yrange(L, Y[j]); } } return l; } /* (x+y)/2 */ static GEN rmiddle(GEN x, GEN y) { GEN z = addrr(x,y); shiftr_inplace(z,-1); return z; } static void single_recursion(void *E, GEN(*eval)(void*,GEN), dblPointList *pl, GEN xleft,double yleft, GEN xright,double yright,long depth) { GEN xx; pari_sp av = avma; double yy, dy=pl[0].ybig - pl[0].ysml; if (depth==RECUR_MAXDEPTH) return; xx = rmiddle(xleft,xright); yy = gtodouble(eval(E,xx)); if (dy && fabs(yleft+yright-2*yy) < dy*RECUR_PREC) return; single_recursion(E,eval, pl,xleft,yleft, xx,yy, depth+1); Appendx(&pl[0],&pl[0],rtodbl(xx)); Appendy(&pl[0],&pl[1],yy); single_recursion(E,eval, pl,xx,yy, xright,yright, depth+1); avma = av; } static void param_recursion(void *E,GEN(*eval)(void*,GEN), long cplx, dblPointList *pl, GEN tleft,double xleft, double yleft, GEN tright,double xright,double yright, long depth) { GEN tt; pari_sp av = avma; double xx, dy=pl[0].ybig - pl[0].ysml; double yy, dx=pl[0].xbig - pl[0].xsml; if (depth==RECUR_MAXDEPTH) return; tt = rmiddle(tleft,tright); get_xy(cplx, eval(E,tt), &xx,&yy); if (dx && dy && fabs(xleft+xright-2*xx) < dx*RECUR_PREC && fabs(yleft+yright-2*yy) < dy*RECUR_PREC) return; param_recursion(E,eval, cplx, pl, tleft,xleft,yleft, tt,xx,yy, depth+1); Appendx(&pl[0],&pl[0],xx); Appendy(&pl[0],&pl[1],yy); param_recursion(E,eval,cplx, pl, tt,xx,yy, tright,xright,yright, depth+1); avma = av; } /* Graph 'code' for parameter values in [a,b], using 'N' sample points * (0 = use a default value); code is either a t_CLOSURE or a t_POL or a * t_VEC of two t_POLs from rectsplines. Returns a dblPointList of * (absolute) coordinates. */ static dblPointList * plotrecthin(void *E, GEN(*eval)(void*, GEN), GEN a, GEN b, ulong flags, long N, long prec) { const double INF = 1.0/0.0; const long param = flags & (PLOT_PARAMETRIC|PLOT_COMPLEX); const long recur = flags & PLOT_RECURSIVE; const long cplx = flags & PLOT_COMPLEX; GEN t,dx,x; dblPointList *pl; long tx, i, j, sig, nc, nl, ncoords, nbpoints, non_vec = 0; pari_sp av = avma; sig = gcmp(b,a); if (!sig) return NULL; if (sig < 0) swap(a, b); if (N == 1) pari_err_DOMAIN("ploth", "#points", "<", gen_2, stoi(N)); if (!N) N = recur? 8: (param? 1500: 1000); /* compute F(a) to determine nc = #curves; nl = #coord. lists */ x = gtofp(a, prec); t = eval(E, x); tx = typ(t); if (cplx) nc = nl = (tx == t_VEC)? lg(t)-1: 1; else if (param) { if (tx != t_VEC) pari_err_TYPE("ploth [not a t_VEC in parametric plot]", t); nl = lg(t)-1; nc = nl >> 1; if (odd(nl)) pari_err_TYPE("ploth [odd #components in parametric plot]",t); } else if (!is_matvec_t(tx)) { nl = 2; non_vec = 1; nc = 1; } else { if (tx != t_VEC) pari_err_TYPE("ploth [not a t_VEC]",t); nl = lg(t); nc = nl-1; } if (!nc) { avma = av; return NULL; } if (recur && nc > 1) pari_err_TYPE("ploth [multi-curves + recursive]",t); ncoords = cplx? 2*nl: nl; nbpoints = recur? N << RECUR_MAXDEPTH: N; pl=(dblPointList*) pari_malloc(ncoords*sizeof(dblPointList)); /* set [xy]sml,[xy]big to default values */ if (param) { pl[0].xsml = INF; pl[0].xbig =-INF; } else { pl[0].xsml = gtodouble(a); pl[0].xbig = gtodouble(b); } pl[0].ysml = INF; pl[0].ybig =-INF; for (i = 0; i < ncoords; i++) { pl[i].d = (double*)pari_malloc((nbpoints+1)*sizeof(double)); pl[i].nb=0; } dx = divru(gtofp(gsub(b,a),prec), N-1); if (recur) { /* recursive plot */ double yleft, yright = 0; if (param) { GEN tleft = cgetr(prec), tright = cgetr(prec); double xleft, xright = 0; pari_sp av2 = avma; affgr(a,tleft); t = eval(E, tleft); get_xy(cplx,t, &xleft,&yleft); for (i=0; idraw) T->draw(T, w,x,y); else get_plot_null(NULL); } static void set_range(double m, double M, double *sml, double *big) { if (M - m < 1.e-9) { double d = fabs(m)/10; if (!d) d = 0.1; M += d; m -= d; } *sml = m; *big = M; } /* Plot a dblPointList. Complete with axes, bounding box, etc. * * data is an array of structs. Its meaning depends on flags : * * + data[0] contains global extremas, the number of curves to plot * (data[0].nb) and a list of doubles (first set of x-coordinates). * * + data[i].nb (i>0) contains the number of points in the list * data[i].d (hopefully, data[2i].nb=data[2i+1].nb when i>0...) * * + If flags contain PLOT_PARAMETRIC, the array length should be * even, and successive pairs (data[2i].d, data[2i+1].d) represent * curves to plot. * * + If there is no such flag, the first element is an array with * x-coordinates and the following ones contain y-coordinates. * If W != NULL, output wrt this PARI_plot using two drawing rectangles: * one for labels, another for graphs. Else draw to rectwindow ne without * labels. * If fmt != NULL (requires W != NULL), output is a t_STR containing the * converted picture, else a bounding box */ static GEN plotrecthrawin(GEN fmt, PARI_plot *W, long ne, dblPointList *data, long flags) { const long param = flags & (PLOT_PARAMETRIC|PLOT_COMPLEX); const long max_graphcolors = lg(GP_DATA->graphcolors)-1; const pari_sp av = avma; dblPointList x, y; double xsml, xbig, ysml, ybig; long ltype, i, nc, w[3], wx[3], wy[3]; if (!data) return cgetg(1,t_VEC); x = data[0]; nc = x.nb; set_range(x.xsml, x.xbig, &xsml, &xbig); set_range(x.ysml, x.ybig, &ysml, &ybig); if (W) { /* actual output; else output to rectwindow: no labels */ const long se = NUMRECT-2; long lm, rm, tm, bm; char YBIG[16], YSML[16], XSML[16], XBIG[16]; /* left/right/top/bottom margin */ sprintf(YSML,"%.5g", ysml); sprintf(YBIG,"%.5g", ybig); sprintf(XSML,"%.5g", xsml); sprintf(XBIG,"%.5g", xbig); /* left margin has y labels with hgap on both sides of text */ lm = maxss(strlen(YSML),strlen(YBIG))*W->fwidth + 2*W->hunit-1; rm = W->hunit-1; tm = W->vunit-1; bm = W->vunit+W->fheight-1; w[0] = wx[0] = wy[0] = evaltyp(t_VECSMALL) | evallg(3); w[1] = se; wx[1] = 0; wy[1] = 0; w[2] = ne; wx[2] = lm; wy[2] = tm; /* Window (width x height) is given in pixels, correct pixels are 0..n-1, * whereas rect functions work with windows whose pixel range is [0,n] */ initrect_i(se, W->width - 1, W->height - 1); initrect_i(ne, W->width - (lm+rm) - 1, W->height - (tm+bm) - 1); /* draw labels on se */ _move(se,lm,0); plotstring(se, YBIG, RoSTdirRIGHT|RoSTdirHGAP|RoSTdirTOP); _move(se,lm,W->height-bm); plotstring(se,YSML, RoSTdirRIGHT|RoSTdirHGAP|RoSTdirVGAP); _move(se,lm,W->height-bm); plotstring(se, XSML, RoSTdirLEFT|RoSTdirTOP); _move(se,W->width-rm-1, W->height-bm); plotstring(se, XBIG, RoSTdirRIGHT|RoSTdirTOP); } if (!(flags & PLOT_NO_RESCALE)) plotscale0(ne, xsml, xbig, ysml, ybig); if (!(flags & PLOT_NO_FRAME)) { long fl = (flags & PLOT_NODOUBLETICK)? TICKS_CLOCKW|TICKS_NODOUBLE : TICKS_CLOCKW; PARI_plot T, *pl; if (W) pl = W; else { pl = &T; pari_get_plot(pl); } plotlinetype(ne, -2); /* frame */ current_color[ne] = colormap_to_color(DEFAULT_COLOR); _move(ne,xsml,ysml); _box(ne,xbig,ybig); if (!(flags & PLOT_NO_TICK_X)) { rectticks(pl, ne, xsml, ysml, xbig, ysml, xsml, xbig, fl); rectticks(pl, ne, xbig, ybig, xsml, ybig, xbig, xsml, fl); } if (!(flags & PLOT_NO_TICK_Y)) { rectticks(pl, ne, xbig, ysml, xbig, ybig, ysml, ybig, fl); rectticks(pl, ne, xsml, ybig, xsml, ysml, ybig, ysml, fl); } } if (!(flags & PLOT_NO_AXE_Y) && (xsml<=0 && xbig >=0)) { plotlinetype(ne, -1); /* axes */ current_color[ne] = colormap_to_color(AXIS_COLOR); _move(ne,0.0,ysml); _line(ne,0.0,ybig); } if (!(flags & PLOT_NO_AXE_X) && (ysml<=0 && ybig >=0)) { plotlinetype(ne, -1); /* axes */ current_color[ne] = colormap_to_color(AXIS_COLOR); _move(ne,xsml,0.0); _line(ne,xbig,0.0); } if (param) { i = 0; flags |= PLOT_PARAMETRIC; flags &= (~PLOT_COMPLEX); /* turn COMPLEX to PARAMETRIC*/ } else i = 1; for (ltype = 0; ltype < nc; ltype++) { long c = GP_DATA->graphcolors[1+(ltype%max_graphcolors)]; current_color[ne] = colormap_to_color(c); if (param) x = data[i++]; y = data[i++]; if (flags & (PLOT_POINTS_LINES|PLOT_POINTS)) { plotlinetype(ne, plotpoint_itype + ltype); /* Graphs */ plotpointtype(ne,plotpoint_itype + ltype); /* Graphs */ plotpoints0(ne, x.d, y.d, y.nb); if (!(flags & PLOT_POINTS_LINES)) continue; } if (flags & PLOT_SPLINES) { /* rectsplines will call us back with ltype == 0 */ int old = rectline_itype; rectline_itype = rectline_itype + ltype; rectsplines(ne, x.d, y.d, y.nb, flags); rectline_itype = old; } else { plotlinetype(ne, rectline_itype + ltype); /* Graphs */ rectlines0(ne, x.d, y.d, y.nb, 0); } } for (i--; i>=0; i--) pari_free(data[i].d); pari_free(data); if (W) { GEN s = NULL; if (fmt) s = fmt_convert(fmt, w, wx, wy, W); else Draw(W, w,wx,wy); plotkill(w[1]); plotkill(w[2]); if (fmt) return s; } avma = av; retmkvec4(dbltor(xsml), dbltor(xbig), dbltor(ysml), dbltor(ybig)); } /*************************************************************************/ /* */ /* HI-RES FUNCTIONS */ /* */ /*************************************************************************/ /* If T != NULL, draw using the attached graphic (using rectwindow ne as a temp) * Else write to rectwindow 'ne'. * Graph y=f(x), x=a..b, use n points */ static GEN plotrecth_i(GEN fmt, void *E, GEN(*f)(void*,GEN), PARI_plot *T, long ne, GEN a,GEN b, ulong flags,long n, long prec) { dblPointList *pl = plotrecthin(E,f, a,b, flags, n, prec); return plotrecthrawin(fmt, T, ne, pl, flags); } GEN plotrecth(void *E, GEN(*f)(void*,GEN), long ne, GEN a,GEN b, ulong flags, long n, long prec) { return plotrecth_i(NULL, E,f, NULL, ne, a,b, flags&~PLOT_PARA, n, prec); } GEN plotrecth0(long ne, GEN a,GEN b,GEN code,ulong flags,long n, long prec) { EXPR_WRAP(code, plotrecth(EXPR_ARG, ne, a,b, flags, n, prec)); } GEN ploth(void *E, GEN(*f)(void*,GEN), GEN a, GEN b,long flags, long n, long prec) { PARI_plot T; pari_get_plot(&T); return plotrecth_i(NULL, E,f, &T, NUMRECT-1, a,b, flags&~PLOT_PARA,n, prec); } GEN parploth(GEN a, GEN b, GEN code, long flags, long n, long prec) { PARI_plot T; pari_get_plot(&T); return plotrecth_i(NULL, code,gp_call,&T, NUMRECT-1, a,b, flags|PLOT_PARA,n, prec); } GEN ploth0(GEN a, GEN b, GEN code, long flags,long n, long prec) { EXPR_WRAP(code, ploth(EXPR_ARG, a,b,flags,n, prec)); } GEN psploth(void *E, GEN(*f)(void*,GEN), GEN a,GEN b, long flags, long n, long prec) { PARI_plot T; pari_get_psplot(&T); T.draw = &_psdraw; return plotrecth_i(NULL, E,f, &T, NUMRECT-1, a,b, flags&~PLOT_PARA,n, prec); } GEN psploth0(GEN a, GEN b, GEN code, long flags, long n, long prec) { EXPR_WRAP(code, psploth(EXPR_ARG, a, b, flags, n, prec)); } GEN plothexport(GEN fmt, void *E, GEN(*f)(void*,GEN), GEN a,GEN b, long flags, long n, long prec) { pari_sp av = avma; GEN s; PARI_plot T; pari_get_fmtplot(fmt, &T); s = plotrecth_i(fmt, E,f, &T, NUMRECT-1, a,b, flags&~PLOT_PARA,n, prec); return gerepileuptoleaf(av, s); } GEN plothexport0(GEN fmt, GEN a, GEN b, GEN code, long flags, long n, long prec) { EXPR_WRAP(code, plothexport(fmt, EXPR_ARG, a, b, flags, n, prec)); } /* Draw list of points */ static GEN plotrecthraw_i(GEN fmt, PARI_plot *T, long ne, GEN data, long flags) { dblPointList *pl = gtodblList(data,flags); return plotrecthrawin(fmt, T, ne, pl, flags); } static GEN plothraw_i(GEN fmt, PARI_plot *T, GEN X, GEN Y, long flag) { pari_sp av = avma; switch (flag) { case 0: flag = PLOT_PARAMETRIC|PLOT_POINTS; break; case 1: flag = PLOT_PARAMETRIC; break; default: flag |= PLOT_PARAMETRIC; break; } return gerepileupto(av, plotrecthraw_i(fmt, T, NUMRECT-1, mkvec2(X,Y), flag)); } GEN plothraw(GEN X, GEN Y, long flags) { PARI_plot T; pari_get_plot(&T); return plothraw_i(NULL,&T,X,Y,flags); } GEN psplothraw(GEN X, GEN Y, long flags) { PARI_plot T; pari_get_psplot(&T); T.draw = &_psdraw; return plothraw_i(NULL,&T,X,Y,flags); } GEN plotrecthraw(long ne, GEN data, long flags) { return plotrecthraw_i(NULL, NULL, ne, data, flags); } GEN plothrawexport(GEN fmt, GEN X, GEN Y, long flags) { PARI_plot T; pari_get_fmtplot(fmt,&T); return plothraw_i(fmt,&T,X,Y,flags); } GEN plothsizes(long flag) { GEN vect = cgetg(1+8,t_VEC); PARI_plot T; pari_get_plot(&T); gel(vect,1) = stoi(T.width); gel(vect,2) = stoi(T.height); if (flag) { gel(vect,3) = dbltor(T.hunit*1.0/T.width); gel(vect,4) = dbltor(T.vunit*1.0/T.height); gel(vect,5) = dbltor(T.fwidth*1.0/T.width); gel(vect,6) = dbltor(T.fheight*1.0/T.height); } else { gel(vect,3) = stoi(T.hunit); gel(vect,4) = stoi(T.vunit); gel(vect,5) = stoi(T.fwidth); gel(vect,6) = stoi(T.fheight); } gel(vect,7) = stoi(T.dwidth); gel(vect,8) = stoi(T.dheight); return vect; } /*************************************************************************/ /* */ /* POSTSCRIPT OUTPUT */ /* */ /*************************************************************************/ static long wxy_n(GEN wxy) { long n; switch(typ(wxy)) { case t_INT: return 1; case t_VEC: n = lg(wxy)-1; if (n%3) pari_err_DIM("plotdraw"); return n/3; } pari_err_TYPE("plotdraw",wxy); return 0;/*LCOV_EXCL_LINE*/ } static void wxy_init(GEN wxy, GEN W, GEN X, GEN Y, PARI_plot *T) { long i, l = lg(X); if (typ(wxy) == t_INT) { W[1] = itos(wxy); check_rect_init(W[1]); X[1] = 0; Y[1] = 0; return; } for (i = 1; i < l; i++) { GEN w = gel(wxy,3*i-2), x = gel(wxy,3*i-1), y = gel(wxy,3*i); if (typ(w) != t_INT) pari_err_TYPE("plotdraw",w); if (T) { X[i] = DTOL(gtodouble(x)*(T->width - 1)); Y[i] = DTOL(gtodouble(y)*(T->height - 1)); } else { X[i] = gtos(x); Y[i] = gtos(y); } W[i] = itos(w); check_rect_init(W[i]); } } /* if flag is set, rescale wrt T */ static void gendraw(PARI_plot *T, GEN wxy, long flag) { long n = wxy_n(wxy); /* malloc mandatory in case draw() forks then pari_close() */ GEN W = cgetalloc(t_VECSMALL, n+1); /* win number */ GEN X = cgetalloc(t_VECSMALL, n+1); GEN Y = cgetalloc(t_VECSMALL, n+1); /* (x,y)-offset */ wxy_init(wxy, W,X,Y, flag? T: NULL); Draw(T,W,X,Y); pari_free(W); pari_free(X); pari_free(Y); } void psdraw(GEN wxy, long flag) { PARI_plot T; pari_get_psplot(&T); T.draw = flag? &_psdraw: &_psdraw_scale; gendraw(&T, wxy, flag); } void plotdraw(GEN wxy, long flag) { PARI_plot T; pari_get_plot(&T); gendraw(&T, wxy, flag); } GEN plotexport(GEN fmt, GEN wxy, long flag) { pari_sp av = avma; long n = wxy_n(wxy); GEN w = cgetg(n+1, t_VECSMALL); GEN x = cgetg(n+1, t_VECSMALL); GEN y = cgetg(n+1, t_VECSMALL); PARI_plot _T, *T = flag? &_T: NULL; if (T) pari_get_plot(T); wxy_init(wxy, w, x, y, T); return gerepileuptoleaf(av, fmt_convert(fmt, w, x, y, T)); } /* may be called after pari_close(): don't use the PARI stack */ void gen_draw(struct plot_eng *eng, GEN w, GEN x, GEN y, double xs, double ys) { void *data = eng->data; long i, j, lw = lg(w); long hgapsize = eng->pl->hunit, fheight = eng->pl->fheight; long vgapsize = eng->pl->vunit, fwidth = eng->pl->fwidth; for(i = 1; i < lw; i++) { PariRect *e = &rectgraph[w[i]]; RectObj *R; long x0 = x[i], y0 = y[i]; for (R = RHead(e); R; R = RoNext(R)) { long col = RoCol(R); switch(RoType(R)) { case ROt_PT: eng->sc(data,col); eng->pt(data, DTOL((RoPTx(R)+x0)*xs), DTOL((RoPTy(R)+y0)*ys)); break; case ROt_LN: eng->sc(data,col); eng->ln(data, DTOL((RoLNx1(R)+x0)*xs), DTOL((RoLNy1(R)+y0)*ys), DTOL((RoLNx2(R)+x0)*xs), DTOL((RoLNy2(R)+y0)*ys)); break; case ROt_BX: eng->sc(data,col); eng->bx(data, DTOL((RoBXx1(R)+x0)*xs), DTOL((RoBXy1(R)+y0)*ys), DTOL((RoBXx2(R)-RoBXx1(R))*xs), DTOL((RoBXy2(R)-RoBXy1(R))*ys)); break; case ROt_FBX: eng->sc(data,col); eng->fb(data, DTOL((RoBXx1(R)+x0)*xs), DTOL((RoBXy1(R)+y0)*ys), DTOL((RoBXx2(R)-RoBXx1(R))*xs), DTOL((RoBXy2(R)-RoBXy1(R))*ys)); break; case ROt_MP: { double *ptx = RoMPxs(R); double *pty = RoMPys(R); long nb = RoMPcnt(R); struct plot_points *points = (struct plot_points *) pari_malloc(sizeof(*points)*nb); for(j=0;jsc(data,col); eng->mp(data, nb, points); pari_free(points); break; } case ROt_ML: { double *ptx = RoMLxs(R); double *pty = RoMLys(R); long nb = RoMLcnt(R); struct plot_points *points = (struct plot_points *) pari_malloc(sizeof(*points)*nb); for(j=0;jsc(data,col); eng->ml(data, nb, points); pari_free(points); break; } case ROt_ST: { long dir = RoSTdir(R); long h = dir & RoSTdirHPOS_mask, hgap = 0; long v = dir & RoSTdirVPOS_mask, vgap = 0; long x, y, l = RoSTl(R); long shift = (h == RoSTdirLEFT ? 0 : (h == RoSTdirRIGHT? 2: 1)); long vshift= (v == RoSTdirBOTTOM? 0: (v == RoSTdirTOP? 2: 1)); if (dir & RoSTdirHGAP) hgap = (h == RoSTdirLEFT) ? hgapsize : -hgapsize; if (dir & RoSTdirVGAP) vgap = (v == RoSTdirBOTTOM) ? 2*vgapsize : -2*vgapsize; x = DTOL(xs * (RoSTx(R) + x0 + hgap - (l * fwidth * shift)/2)); y = DTOL(ys * (RoSTy(R) + y0 - (vgap - vshift*(fheight-1))/2)); eng->sc(data,col); eng->st(data, x, y, RoSTs(R), l); break; } default: break; } } } } /*************************************************************************/ /* SVG */ /*************************************************************************/ struct svg_data { pari_str str; char hexcolor[8]; /* "#rrggbb\0" */ }; #define data_str(d) (&((struct svg_data*)(d))->str) #define data_hexcolor(d) (((struct svg_data*)(d))->hexcolor) /* Work with precision 1/scale */ static const float SVG_SCALE = 1024.0; static float svg_rescale(float x) { return x / SVG_SCALE; } static void svg_point(void *data, long x, long y) { pari_str *S = data_str(data); str_printf(S, "", data_hexcolor(data)); } static void svg_line(void *data, long x1, long y1, long x2, long y2) { pari_str *S = data_str(data); str_printf(S, "", data_hexcolor(data)); } static void svg_rect(void *data, long x, long y, long w, long h) { pari_str *S = data_str(data); str_printf(S, "", data_hexcolor(data)); } static void svg_fillrect(void *data, long x, long y, long w, long h) { pari_str *S = data_str(data); const char * color = data_hexcolor(data); str_printf(S, "", color, color); } static void svg_points(void *data, long nb, struct plot_points *p) { long i; for (i = 0; i < nb; i++) svg_point(data, p[i].x, p[i].y); } static void svg_color(void *data, long col) { static const char hex[] = "0123456789abcdef"; char *c = data_hexcolor(data); int r, g, b; long_to_rgb(col, &r, &g, &b); c[0] = '#'; c[1] = hex[r / 16]; c[2] = hex[r & 15]; c[3] = hex[g / 16]; c[4] = hex[g & 15]; c[5] = hex[b / 16]; c[6] = hex[b & 15]; c[7] = '\0'; } static void svg_lines(void *data, long nb, struct plot_points *p) { long i; pari_str *S = data_str(data); str_printf(S, "", data_hexcolor(data)); } static void svg_text(void *data, long x, long y, char *text, long numtext) { pari_str *S = data_str(data); (void)numtext; str_printf(S, "%s", svg_rescale(x),svg_rescale(y), 12, data_hexcolor(data), text); } static void svg_head(PARI_plot *T, pari_str *S) { str_printf(S, "", T->width, T->height); } static void svg_tail(pari_str *S) { str_printf(S, ""); } char * rect2svg(GEN w, GEN x, GEN y, PARI_plot *T) { struct plot_eng pl; struct svg_data data; PARI_plot U; str_init(&data.str, 1); svg_color(&data, 0); if (!T) { long i, l = lg(w), xmax = 0, ymax = 0; T = &U; pari_get_svgplot(T); for (i = 1; i < l; i++) { PariRect *e = check_rect_init(w[i]); xmax = maxss(xmax, RXsize(e) + x[i]); ymax = maxss(ymax, RYsize(e) + y[i]); } T->width = xmax; T->height = ymax; } pl.data = &data; pl.sc = &svg_color; pl.pt = &svg_point; pl.ln = &svg_line; pl.bx = &svg_rect; pl.fb = &svg_fillrect; pl.mp = &svg_points; pl.ml = &svg_lines; pl.st = &svg_text; pl.pl = T; svg_head(T, &data.str); gen_draw(&pl, w, x, y, SVG_SCALE, SVG_SCALE); svg_tail(&data.str); return data.str.string; } /*************************************************************************/ /* POSTSCRIPT */ /*************************************************************************/ static void ps_sc(void *data, long col) { pari_str *S = (pari_str*)data; int r, g, b; long_to_rgb(col, &r, &g, &b); if (!r && !g && !b) str_puts(S,"c0\n"); else str_printf(S,"%.6f %.6f %.6f c\n", r/255., g/255., b/255.); } static void ps_point(void *data, long x, long y) { pari_str *S = (pari_str*)data; str_printf(S,"%ld %ld p\n",y,x); } static void ps_line(void *data, long x1, long y1, long x2, long y2) { pari_str *S = (pari_str*)data; str_printf(S,"%ld %ld m %ld %ld l\n",y1,x1,y2,x2); str_printf(S,"stroke\n"); } static void ps_rect(void *data, long x, long y, long w, long h) { pari_str *S = (pari_str*)data; str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath stroke\n", y,x, y,x+w, y+h,x+w, y+h,x); } static void ps_fillrect(void *data, long x, long y, long w, long h) { pari_str *S = (pari_str*)data; str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath fill\n", y,x, y,x+w, y+h,x+w, y+h,x); } static void ps_points(void *data, long nb, struct plot_points *p) { long i; for (i=0; iwidth; ys *= ((double)PS_HEIGH) / T->height; } } else { T = &U; pari_get_psplot(T); } str_init(&S, 1); /* Definitions taken from post terminal of Gnuplot. */ str_printf(&S, "%%!\n\ 50 50 translate\n\ /p {moveto 0 2 rlineto 2 0 rlineto 0 -2 rlineto closepath fill} def\n\ /c0 {0 0 0 setrgbcolor} def\n\ /c {setrgbcolor} def\n\ /l {lineto} def\n\ /m {moveto} def\n" "/Times-Roman findfont %ld scalefont setfont\n", DTOL(T->fheight * xs)); pl.sc = &ps_sc; pl.pt = &ps_point; pl.ln = &ps_line; pl.bx = &ps_rect; pl.fb = &ps_fillrect; pl.mp = &ps_points; pl.ml = &ps_lines; pl.st = &ps_string; pl.pl = T; pl.data = (void*)&S; if (plotps) str_printf(&S,"0 %ld translate -90 rotate\n", T->height - 50); gen_draw(&pl, w, x, y, xs, ys); str_puts(&S,"stroke showpage\n"); *S.cur = 0; return S.string; } char * rect2ps(GEN w, GEN x, GEN y, PARI_plot *T) { return rect2ps_i(w,x,y,T,0); } void pari_plot_by_file(const char *env, const char *suf, const char *img) { const char *cmd, *s = pari_unique_filename_suffix("plotfile", suf); FILE *f = fopen(s, "w"); if (!f) pari_err_FILE("image file", s); fputs(img, f); (void)fclose(f); cmd = os_getenv(env); #ifdef GP_MIME_OPEN if (!cmd) cmd = GP_MIME_OPEN; #else if (!cmd) cmd = "open -W"; #endif cmd = pari_sprintf("%s \"%s\" 2>/dev/null", cmd, s); gpsystem(cmd); pari_unlink(s); pari_free((char*)s); } /*************************************************************************/ /* */ /* RGB COLORS */ /* */ /*************************************************************************/ /* generated from /etc/X11/rgb.txt by the following perl script #!/usr/bin/perl while(<>) { ($hex, $name) = split(/\t\t/, $_); $hex =~ s/^ +//; chomp($name); $name =~ s, *,,g; $hex = sprintf("0x%02x%02x%02x", split(/\s+/, $hex)); $name = lc($name); next if ($done{$name}); $done{$name} = 1; print "COL(\"$name\", $hex),\n"; } */ #define COL(x,y) {(void*)x,(void*)y,0,NULL} static hashentry col_list[] = { COL("", 0x000000), COL("snow", 0xfffafa), COL("ghostwhite", 0xf8f8ff), COL("whitesmoke", 0xf5f5f5), COL("gainsboro", 0xdcdcdc), COL("floralwhite", 0xfffaf0), COL("oldlace", 0xfdf5e6), COL("linen", 0xfaf0e6), COL("antiquewhite", 0xfaebd7), COL("papayawhip", 0xffefd5), COL("blanchedalmond", 0xffebcd), COL("bisque", 0xffe4c4), COL("peachpuff", 0xffdab9), COL("navajowhite", 0xffdead), COL("moccasin", 0xffe4b5), COL("cornsilk", 0xfff8dc), COL("ivory", 0xfffff0), COL("lemonchiffon", 0xfffacd), COL("seashell", 0xfff5ee), COL("honeydew", 0xf0fff0), COL("mintcream", 0xf5fffa), COL("azure", 0xf0ffff), COL("aliceblue", 0xf0f8ff), COL("lavender", 0xe6e6fa), COL("lavenderblush", 0xfff0f5), COL("mistyrose", 0xffe4e1), COL("white", 0xffffff), COL("black", 0x000000), COL("darkslategray", 0x2f4f4f), COL("darkslategrey", 0x2f4f4f), COL("dimgray", 0x696969), COL("dimgrey", 0x696969), COL("slategray", 0x708090), COL("slategrey", 0x708090), COL("lightslategray", 0x778899), COL("lightslategrey", 0x778899), COL("gray", 0xbebebe), COL("grey", 0xbebebe), COL("lightgrey", 0xd3d3d3), COL("lightgray", 0xd3d3d3), COL("midnightblue", 0x191970), COL("navy", 0x000080), COL("navyblue", 0x000080), COL("cornflowerblue", 0x6495ed), COL("darkslateblue", 0x483d8b), COL("slateblue", 0x6a5acd), COL("mediumslateblue", 0x7b68ee), COL("lightslateblue", 0x8470ff), COL("mediumblue", 0x0000cd), COL("royalblue", 0x4169e1), COL("blue", 0x0000ff), COL("dodgerblue", 0x1e90ff), COL("deepskyblue", 0x00bfff), COL("skyblue", 0x87ceeb), COL("lightskyblue", 0x87cefa), COL("steelblue", 0x4682b4), COL("lightsteelblue", 0xb0c4de), COL("lightblue", 0xadd8e6), COL("powderblue", 0xb0e0e6), COL("paleturquoise", 0xafeeee), COL("darkturquoise", 0x00ced1), COL("mediumturquoise", 0x48d1cc), COL("turquoise", 0x40e0d0), COL("cyan", 0x00ffff), COL("lightcyan", 0xe0ffff), COL("cadetblue", 0x5f9ea0), COL("mediumaquamarine", 0x66cdaa), COL("aquamarine", 0x7fffd4), COL("darkgreen", 0x006400), COL("darkolivegreen", 0x556b2f), COL("darkseagreen", 0x8fbc8f), COL("seagreen", 0x2e8b57), COL("mediumseagreen", 0x3cb371), COL("lightseagreen", 0x20b2aa), COL("palegreen", 0x98fb98), COL("springgreen", 0x00ff7f), COL("lawngreen", 0x7cfc00), COL("green", 0x00ff00), COL("chartreuse", 0x7fff00), COL("mediumspringgreen", 0x00fa9a), COL("greenyellow", 0xadff2f), COL("limegreen", 0x32cd32), COL("yellowgreen", 0x9acd32), COL("forestgreen", 0x228b22), COL("olivedrab", 0x6b8e23), COL("darkkhaki", 0xbdb76b), COL("khaki", 0xf0e68c), COL("palegoldenrod", 0xeee8aa), COL("lightgoldenrodyellow", 0xfafad2), COL("lightyellow", 0xffffe0), COL("yellow", 0xffff00), COL("gold", 0xffd700), COL("lightgoldenrod", 0xeedd82), COL("goldenrod", 0xdaa520), COL("darkgoldenrod", 0xb8860b), COL("rosybrown", 0xbc8f8f), COL("indianred", 0xcd5c5c), COL("saddlebrown", 0x8b4513), COL("sienna", 0xa0522d), COL("peru", 0xcd853f), COL("burlywood", 0xdeb887), COL("beige", 0xf5f5dc), COL("wheat", 0xf5deb3), COL("sandybrown", 0xf4a460), COL("tan", 0xd2b48c), COL("chocolate", 0xd2691e), COL("firebrick", 0xb22222), COL("brown", 0xa52a2a), COL("darksalmon", 0xe9967a), COL("salmon", 0xfa8072), COL("lightsalmon", 0xffa07a), COL("orange", 0xffa500), COL("darkorange", 0xff8c00), COL("coral", 0xff7f50), COL("lightcoral", 0xf08080), COL("tomato", 0xff6347), COL("orangered", 0xff4500), COL("red", 0xff0000), COL("hotpink", 0xff69b4), COL("deeppink", 0xff1493), COL("pink", 0xffc0cb), COL("lightpink", 0xffb6c1), COL("palevioletred", 0xdb7093), COL("maroon", 0xb03060), COL("mediumvioletred", 0xc71585), COL("violetred", 0xd02090), COL("magenta", 0xff00ff), COL("violet", 0xee82ee), COL("plum", 0xdda0dd), COL("orchid", 0xda70d6), COL("mediumorchid", 0xba55d3), COL("darkorchid", 0x9932cc), COL("darkviolet", 0x9400d3), COL("blueviolet", 0x8a2be2), COL("purple", 0xa020f0), COL("mediumpurple", 0x9370db), COL("thistle", 0xd8bfd8), COL("snow1", 0xfffafa), COL("snow2", 0xeee9e9), COL("snow3", 0xcdc9c9), COL("snow4", 0x8b8989), COL("seashell1", 0xfff5ee), COL("seashell2", 0xeee5de), COL("seashell3", 0xcdc5bf), COL("seashell4", 0x8b8682), COL("antiquewhite1", 0xffefdb), COL("antiquewhite2", 0xeedfcc), COL("antiquewhite3", 0xcdc0b0), COL("antiquewhite4", 0x8b8378), COL("bisque1", 0xffe4c4), COL("bisque2", 0xeed5b7), COL("bisque3", 0xcdb79e), COL("bisque4", 0x8b7d6b), COL("peachpuff1", 0xffdab9), COL("peachpuff2", 0xeecbad), COL("peachpuff3", 0xcdaf95), COL("peachpuff4", 0x8b7765), COL("navajowhite1", 0xffdead), COL("navajowhite2", 0xeecfa1), COL("navajowhite3", 0xcdb38b), COL("navajowhite4", 0x8b795e), COL("lemonchiffon1", 0xfffacd), COL("lemonchiffon2", 0xeee9bf), COL("lemonchiffon3", 0xcdc9a5), COL("lemonchiffon4", 0x8b8970), COL("cornsilk1", 0xfff8dc), COL("cornsilk2", 0xeee8cd), COL("cornsilk3", 0xcdc8b1), COL("cornsilk4", 0x8b8878), COL("ivory1", 0xfffff0), COL("ivory2", 0xeeeee0), COL("ivory3", 0xcdcdc1), COL("ivory4", 0x8b8b83), COL("honeydew1", 0xf0fff0), COL("honeydew2", 0xe0eee0), COL("honeydew3", 0xc1cdc1), COL("honeydew4", 0x838b83), COL("lavenderblush1", 0xfff0f5), COL("lavenderblush2", 0xeee0e5), COL("lavenderblush3", 0xcdc1c5), COL("lavenderblush4", 0x8b8386), COL("mistyrose1", 0xffe4e1), COL("mistyrose2", 0xeed5d2), COL("mistyrose3", 0xcdb7b5), COL("mistyrose4", 0x8b7d7b), COL("azure1", 0xf0ffff), COL("azure2", 0xe0eeee), COL("azure3", 0xc1cdcd), COL("azure4", 0x838b8b), COL("slateblue1", 0x836fff), COL("slateblue2", 0x7a67ee), COL("slateblue3", 0x6959cd), COL("slateblue4", 0x473c8b), COL("royalblue1", 0x4876ff), COL("royalblue2", 0x436eee), COL("royalblue3", 0x3a5fcd), COL("royalblue4", 0x27408b), COL("blue1", 0x0000ff), COL("blue2", 0x0000ee), COL("blue3", 0x0000cd), COL("blue4", 0x00008b), COL("dodgerblue1", 0x1e90ff), COL("dodgerblue2", 0x1c86ee), COL("dodgerblue3", 0x1874cd), COL("dodgerblue4", 0x104e8b), COL("steelblue1", 0x63b8ff), COL("steelblue2", 0x5cacee), COL("steelblue3", 0x4f94cd), COL("steelblue4", 0x36648b), COL("deepskyblue1", 0x00bfff), COL("deepskyblue2", 0x00b2ee), COL("deepskyblue3", 0x009acd), COL("deepskyblue4", 0x00688b), COL("skyblue1", 0x87ceff), COL("skyblue2", 0x7ec0ee), COL("skyblue3", 0x6ca6cd), COL("skyblue4", 0x4a708b), COL("lightskyblue1", 0xb0e2ff), COL("lightskyblue2", 0xa4d3ee), COL("lightskyblue3", 0x8db6cd), COL("lightskyblue4", 0x607b8b), COL("slategray1", 0xc6e2ff), COL("slategray2", 0xb9d3ee), COL("slategray3", 0x9fb6cd), COL("slategray4", 0x6c7b8b), COL("lightsteelblue1", 0xcae1ff), COL("lightsteelblue2", 0xbcd2ee), COL("lightsteelblue3", 0xa2b5cd), COL("lightsteelblue4", 0x6e7b8b), COL("lightblue1", 0xbfefff), COL("lightblue2", 0xb2dfee), COL("lightblue3", 0x9ac0cd), COL("lightblue4", 0x68838b), COL("lightcyan1", 0xe0ffff), COL("lightcyan2", 0xd1eeee), COL("lightcyan3", 0xb4cdcd), COL("lightcyan4", 0x7a8b8b), COL("paleturquoise1", 0xbbffff), COL("paleturquoise2", 0xaeeeee), COL("paleturquoise3", 0x96cdcd), COL("paleturquoise4", 0x668b8b), COL("cadetblue1", 0x98f5ff), COL("cadetblue2", 0x8ee5ee), COL("cadetblue3", 0x7ac5cd), COL("cadetblue4", 0x53868b), COL("turquoise1", 0x00f5ff), COL("turquoise2", 0x00e5ee), COL("turquoise3", 0x00c5cd), COL("turquoise4", 0x00868b), COL("cyan1", 0x00ffff), COL("cyan2", 0x00eeee), COL("cyan3", 0x00cdcd), COL("cyan4", 0x008b8b), COL("darkslategray1", 0x97ffff), COL("darkslategray2", 0x8deeee), COL("darkslategray3", 0x79cdcd), COL("darkslategray4", 0x528b8b), COL("aquamarine1", 0x7fffd4), COL("aquamarine2", 0x76eec6), COL("aquamarine3", 0x66cdaa), COL("aquamarine4", 0x458b74), COL("darkseagreen1", 0xc1ffc1), COL("darkseagreen2", 0xb4eeb4), COL("darkseagreen3", 0x9bcd9b), COL("darkseagreen4", 0x698b69), COL("seagreen1", 0x54ff9f), COL("seagreen2", 0x4eee94), COL("seagreen3", 0x43cd80), COL("seagreen4", 0x2e8b57), COL("palegreen1", 0x9aff9a), COL("palegreen2", 0x90ee90), COL("palegreen3", 0x7ccd7c), COL("palegreen4", 0x548b54), COL("springgreen1", 0x00ff7f), COL("springgreen2", 0x00ee76), COL("springgreen3", 0x00cd66), COL("springgreen4", 0x008b45), COL("green1", 0x00ff00), COL("green2", 0x00ee00), COL("green3", 0x00cd00), COL("green4", 0x008b00), COL("chartreuse1", 0x7fff00), COL("chartreuse2", 0x76ee00), COL("chartreuse3", 0x66cd00), COL("chartreuse4", 0x458b00), COL("olivedrab1", 0xc0ff3e), COL("olivedrab2", 0xb3ee3a), COL("olivedrab3", 0x9acd32), COL("olivedrab4", 0x698b22), COL("darkolivegreen1", 0xcaff70), COL("darkolivegreen2", 0xbcee68), COL("darkolivegreen3", 0xa2cd5a), COL("darkolivegreen4", 0x6e8b3d), COL("khaki1", 0xfff68f), COL("khaki2", 0xeee685), COL("khaki3", 0xcdc673), COL("khaki4", 0x8b864e), COL("lightgoldenrod1", 0xffec8b), COL("lightgoldenrod2", 0xeedc82), COL("lightgoldenrod3", 0xcdbe70), COL("lightgoldenrod4", 0x8b814c), COL("lightyellow1", 0xffffe0), COL("lightyellow2", 0xeeeed1), COL("lightyellow3", 0xcdcdb4), COL("lightyellow4", 0x8b8b7a), COL("yellow1", 0xffff00), COL("yellow2", 0xeeee00), COL("yellow3", 0xcdcd00), COL("yellow4", 0x8b8b00), COL("gold1", 0xffd700), COL("gold2", 0xeec900), COL("gold3", 0xcdad00), COL("gold4", 0x8b7500), COL("goldenrod1", 0xffc125), COL("goldenrod2", 0xeeb422), COL("goldenrod3", 0xcd9b1d), COL("goldenrod4", 0x8b6914), COL("darkgoldenrod1", 0xffb90f), COL("darkgoldenrod2", 0xeead0e), COL("darkgoldenrod3", 0xcd950c), COL("darkgoldenrod4", 0x8b6508), COL("rosybrown1", 0xffc1c1), COL("rosybrown2", 0xeeb4b4), COL("rosybrown3", 0xcd9b9b), COL("rosybrown4", 0x8b6969), COL("indianred1", 0xff6a6a), COL("indianred2", 0xee6363), COL("indianred3", 0xcd5555), COL("indianred4", 0x8b3a3a), COL("sienna1", 0xff8247), COL("sienna2", 0xee7942), COL("sienna3", 0xcd6839), COL("sienna4", 0x8b4726), COL("burlywood1", 0xffd39b), COL("burlywood2", 0xeec591), COL("burlywood3", 0xcdaa7d), COL("burlywood4", 0x8b7355), COL("wheat1", 0xffe7ba), COL("wheat2", 0xeed8ae), COL("wheat3", 0xcdba96), COL("wheat4", 0x8b7e66), COL("tan1", 0xffa54f), COL("tan2", 0xee9a49), COL("tan3", 0xcd853f), COL("tan4", 0x8b5a2b), COL("chocolate1", 0xff7f24), COL("chocolate2", 0xee7621), COL("chocolate3", 0xcd661d), COL("chocolate4", 0x8b4513), COL("firebrick1", 0xff3030), COL("firebrick2", 0xee2c2c), COL("firebrick3", 0xcd2626), COL("firebrick4", 0x8b1a1a), COL("brown1", 0xff4040), COL("brown2", 0xee3b3b), COL("brown3", 0xcd3333), COL("brown4", 0x8b2323), COL("salmon1", 0xff8c69), COL("salmon2", 0xee8262), COL("salmon3", 0xcd7054), COL("salmon4", 0x8b4c39), COL("lightsalmon1", 0xffa07a), COL("lightsalmon2", 0xee9572), COL("lightsalmon3", 0xcd8162), COL("lightsalmon4", 0x8b5742), COL("orange1", 0xffa500), COL("orange2", 0xee9a00), COL("orange3", 0xcd8500), COL("orange4", 0x8b5a00), COL("darkorange1", 0xff7f00), COL("darkorange2", 0xee7600), COL("darkorange3", 0xcd6600), COL("darkorange4", 0x8b4500), COL("coral1", 0xff7256), COL("coral2", 0xee6a50), COL("coral3", 0xcd5b45), COL("coral4", 0x8b3e2f), COL("tomato1", 0xff6347), COL("tomato2", 0xee5c42), COL("tomato3", 0xcd4f39), COL("tomato4", 0x8b3626), COL("orangered1", 0xff4500), COL("orangered2", 0xee4000), COL("orangered3", 0xcd3700), COL("orangered4", 0x8b2500), COL("red1", 0xff0000), COL("red2", 0xee0000), COL("red3", 0xcd0000), COL("red4", 0x8b0000), COL("debianred", 0xd70751), COL("deeppink1", 0xff1493), COL("deeppink2", 0xee1289), COL("deeppink3", 0xcd1076), COL("deeppink4", 0x8b0a50), COL("hotpink1", 0xff6eb4), COL("hotpink2", 0xee6aa7), COL("hotpink3", 0xcd6090), COL("hotpink4", 0x8b3a62), COL("pink1", 0xffb5c5), COL("pink2", 0xeea9b8), COL("pink3", 0xcd919e), COL("pink4", 0x8b636c), COL("lightpink1", 0xffaeb9), COL("lightpink2", 0xeea2ad), COL("lightpink3", 0xcd8c95), COL("lightpink4", 0x8b5f65), COL("palevioletred1", 0xff82ab), COL("palevioletred2", 0xee799f), COL("palevioletred3", 0xcd6889), COL("palevioletred4", 0x8b475d), COL("maroon1", 0xff34b3), COL("maroon2", 0xee30a7), COL("maroon3", 0xcd2990), COL("maroon4", 0x8b1c62), COL("violetred1", 0xff3e96), COL("violetred2", 0xee3a8c), COL("violetred3", 0xcd3278), COL("violetred4", 0x8b2252), COL("magenta1", 0xff00ff), COL("magenta2", 0xee00ee), COL("magenta3", 0xcd00cd), COL("magenta4", 0x8b008b), COL("orchid1", 0xff83fa), COL("orchid2", 0xee7ae9), COL("orchid3", 0xcd69c9), COL("orchid4", 0x8b4789), COL("plum1", 0xffbbff), COL("plum2", 0xeeaeee), COL("plum3", 0xcd96cd), COL("plum4", 0x8b668b), COL("mediumorchid1", 0xe066ff), COL("mediumorchid2", 0xd15fee), COL("mediumorchid3", 0xb452cd), COL("mediumorchid4", 0x7a378b), COL("darkorchid1", 0xbf3eff), COL("darkorchid2", 0xb23aee), COL("darkorchid3", 0x9a32cd), COL("darkorchid4", 0x68228b), COL("purple1", 0x9b30ff), COL("purple2", 0x912cee), COL("purple3", 0x7d26cd), COL("purple4", 0x551a8b), COL("mediumpurple1", 0xab82ff), COL("mediumpurple2", 0x9f79ee), COL("mediumpurple3", 0x8968cd), COL("mediumpurple4", 0x5d478b), COL("thistle1", 0xffe1ff), COL("thistle2", 0xeed2ee), COL("thistle3", 0xcdb5cd), COL("thistle4", 0x8b7b8b), COL("gray0", 0x000000), COL("grey0", 0x000000), COL("gray1", 0x030303), COL("grey1", 0x030303), COL("gray2", 0x050505), COL("grey2", 0x050505), COL("gray3", 0x080808), COL("grey3", 0x080808), COL("gray4", 0x0a0a0a), COL("grey4", 0x0a0a0a), COL("gray5", 0x0d0d0d), COL("grey5", 0x0d0d0d), COL("gray6", 0x0f0f0f), COL("grey6", 0x0f0f0f), COL("gray7", 0x121212), COL("grey7", 0x121212), COL("gray8", 0x141414), COL("grey8", 0x141414), COL("gray9", 0x171717), COL("grey9", 0x171717), COL("gray10", 0x1a1a1a), COL("grey10", 0x1a1a1a), COL("gray11", 0x1c1c1c), COL("grey11", 0x1c1c1c), COL("gray12", 0x1f1f1f), COL("grey12", 0x1f1f1f), COL("gray13", 0x212121), COL("grey13", 0x212121), COL("gray14", 0x242424), COL("grey14", 0x242424), COL("gray15", 0x262626), COL("grey15", 0x262626), COL("gray16", 0x292929), COL("grey16", 0x292929), COL("gray17", 0x2b2b2b), COL("grey17", 0x2b2b2b), COL("gray18", 0x2e2e2e), COL("grey18", 0x2e2e2e), COL("gray19", 0x303030), COL("grey19", 0x303030), COL("gray20", 0x333333), COL("grey20", 0x333333), COL("gray21", 0x363636), COL("grey21", 0x363636), COL("gray22", 0x383838), COL("grey22", 0x383838), COL("gray23", 0x3b3b3b), COL("grey23", 0x3b3b3b), COL("gray24", 0x3d3d3d), COL("grey24", 0x3d3d3d), COL("gray25", 0x404040), COL("grey25", 0x404040), COL("gray26", 0x424242), COL("grey26", 0x424242), COL("gray27", 0x454545), COL("grey27", 0x454545), COL("gray28", 0x474747), COL("grey28", 0x474747), COL("gray29", 0x4a4a4a), COL("grey29", 0x4a4a4a), COL("gray30", 0x4d4d4d), COL("grey30", 0x4d4d4d), COL("gray31", 0x4f4f4f), COL("grey31", 0x4f4f4f), COL("gray32", 0x525252), COL("grey32", 0x525252), COL("gray33", 0x545454), COL("grey33", 0x545454), COL("gray34", 0x575757), COL("grey34", 0x575757), COL("gray35", 0x595959), COL("grey35", 0x595959), COL("gray36", 0x5c5c5c), COL("grey36", 0x5c5c5c), COL("gray37", 0x5e5e5e), COL("grey37", 0x5e5e5e), COL("gray38", 0x616161), COL("grey38", 0x616161), COL("gray39", 0x636363), COL("grey39", 0x636363), COL("gray40", 0x666666), COL("grey40", 0x666666), COL("gray41", 0x696969), COL("grey41", 0x696969), COL("gray42", 0x6b6b6b), COL("grey42", 0x6b6b6b), COL("gray43", 0x6e6e6e), COL("grey43", 0x6e6e6e), COL("gray44", 0x707070), COL("grey44", 0x707070), COL("gray45", 0x737373), COL("grey45", 0x737373), COL("gray46", 0x757575), COL("grey46", 0x757575), COL("gray47", 0x787878), COL("grey47", 0x787878), COL("gray48", 0x7a7a7a), COL("grey48", 0x7a7a7a), COL("gray49", 0x7d7d7d), COL("grey49", 0x7d7d7d), COL("gray50", 0x7f7f7f), COL("grey50", 0x7f7f7f), COL("gray51", 0x828282), COL("grey51", 0x828282), COL("gray52", 0x858585), COL("grey52", 0x858585), COL("gray53", 0x878787), COL("grey53", 0x878787), COL("gray54", 0x8a8a8a), COL("grey54", 0x8a8a8a), COL("gray55", 0x8c8c8c), COL("grey55", 0x8c8c8c), COL("gray56", 0x8f8f8f), COL("grey56", 0x8f8f8f), COL("gray57", 0x919191), COL("grey57", 0x919191), COL("gray58", 0x949494), COL("grey58", 0x949494), COL("gray59", 0x969696), COL("grey59", 0x969696), COL("gray60", 0x999999), COL("grey60", 0x999999), COL("gray61", 0x9c9c9c), COL("grey61", 0x9c9c9c), COL("gray62", 0x9e9e9e), COL("grey62", 0x9e9e9e), COL("gray63", 0xa1a1a1), COL("grey63", 0xa1a1a1), COL("gray64", 0xa3a3a3), COL("grey64", 0xa3a3a3), COL("gray65", 0xa6a6a6), COL("grey65", 0xa6a6a6), COL("gray66", 0xa8a8a8), COL("grey66", 0xa8a8a8), COL("gray67", 0xababab), COL("grey67", 0xababab), COL("gray68", 0xadadad), COL("grey68", 0xadadad), COL("gray69", 0xb0b0b0), COL("grey69", 0xb0b0b0), COL("gray70", 0xb3b3b3), COL("grey70", 0xb3b3b3), COL("gray71", 0xb5b5b5), COL("grey71", 0xb5b5b5), COL("gray72", 0xb8b8b8), COL("grey72", 0xb8b8b8), COL("gray73", 0xbababa), COL("grey73", 0xbababa), COL("gray74", 0xbdbdbd), COL("grey74", 0xbdbdbd), COL("gray75", 0xbfbfbf), COL("grey75", 0xbfbfbf), COL("gray76", 0xc2c2c2), COL("grey76", 0xc2c2c2), COL("gray77", 0xc4c4c4), COL("grey77", 0xc4c4c4), COL("gray78", 0xc7c7c7), COL("grey78", 0xc7c7c7), COL("gray79", 0xc9c9c9), COL("grey79", 0xc9c9c9), COL("gray80", 0xcccccc), COL("grey80", 0xcccccc), COL("gray81", 0xcfcfcf), COL("grey81", 0xcfcfcf), COL("gray82", 0xd1d1d1), COL("grey82", 0xd1d1d1), COL("gray83", 0xd4d4d4), COL("grey83", 0xd4d4d4), COL("gray84", 0xd6d6d6), COL("grey84", 0xd6d6d6), COL("gray85", 0xd9d9d9), COL("grey85", 0xd9d9d9), COL("gray86", 0xdbdbdb), COL("grey86", 0xdbdbdb), COL("gray87", 0xdedede), COL("grey87", 0xdedede), COL("gray88", 0xe0e0e0), COL("grey88", 0xe0e0e0), COL("gray89", 0xe3e3e3), COL("grey89", 0xe3e3e3), COL("gray90", 0xe5e5e5), COL("grey90", 0xe5e5e5), COL("gray91", 0xe8e8e8), COL("grey91", 0xe8e8e8), COL("gray92", 0xebebeb), COL("grey92", 0xebebeb), COL("gray93", 0xededed), COL("grey93", 0xededed), COL("gray94", 0xf0f0f0), COL("grey94", 0xf0f0f0), COL("gray95", 0xf2f2f2), COL("grey95", 0xf2f2f2), COL("gray96", 0xf5f5f5), COL("grey96", 0xf5f5f5), COL("gray97", 0xf7f7f7), COL("grey97", 0xf7f7f7), COL("gray98", 0xfafafa), COL("grey98", 0xfafafa), COL("gray99", 0xfcfcfc), COL("grey99", 0xfcfcfc), COL("gray100", 0xffffff), COL("grey100", 0xffffff), COL("darkgrey", 0xa9a9a9), COL("darkgray", 0xa9a9a9), COL("darkblue", 0x00008b), COL("darkcyan", 0x008b8b), COL("darkmagenta", 0x8b008b), COL("darkred", 0x8b0000), COL("lightgreen", 0x90ee90), COL(NULL,0) /* sentinel */ }; #undef COL void long_to_rgb(long c, int *r, int *g, int *b) { *b = c & 0xff; c >>= 8; *g = c & 0xff; c >>= 8; *r = c; } static int hex2(const char *s) { int m = 0, c = 0, i; for (i = 0; i < 2; i++, s++) { if (*s >= '0' && *s <= '9') c = *s - '0'; else if (*s >= 'A' && *s <= 'F') c = *s - 'A' + 10; else if (*s >= 'a' && *s <= 'f') c = *s - 'a' + 10; else pari_err(e_MISC,"incorrect hexadecimal number: %s", s); m = 16*m + c; } return m; } void colorname_to_rgb(const char *s, int *r, int *g, int *b) { if (!rgb_colors) rgb_colors = hashstr_import_static(col_list, 1000); if (*s == '#' && strlen(s) == 7) { *r = hex2(s+1); *g = hex2(s+3); *b = hex2(s+5); } else { hashentry *ep = hash_search(rgb_colors, (void*)s); if (!ep) pari_err(e_MISC, "unknown color %s", s); long_to_rgb((long)ep->val, r,g,b); } } static void chk_8bit(int v, GEN c) { if (v & ~0xff) pari_err(e_MISC, "invalid RGB code: %Ps", c); } void color_to_rgb(GEN c, int *r, int *g, int *b) { switch(typ(c)) { case t_STR: colorname_to_rgb(GSTR(c), r,g,b); break; default: /* t_VECSMALL: */ *r = c[1]; chk_8bit(*r, c); *g = c[2]; chk_8bit(*g, c); *b = c[3]; chk_8bit(*b, c); break; } } pari-2.11.2/src/graph/plotX.c0000644000175000017500000001766313447371554014352 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* HIGH RESOLUTION PLOT */ /* */ /*******************************************************************/ #include "pari.h" #include "rect.h" #ifdef HPPA # ifndef __GNUC__ typedef char *caddr_t; # endif #endif BEGINEXTERN #include #include #include #ifndef XK_c # include #endif ENDEXTERN static Colormap PARI_Colormap; struct data_x { Display *display; Window win; int numcolors; GC gc; }; /* after fork(), we don't want the child to recover but to exit */ static void exiterr(const char *str) { term_color(c_ERR); err_printf("\n *** X fatal error: %s\n",str); term_color(c_NONE); exit(1); } static long rgb_to_pixel(Display *display, int r, int g, int b) { XColor X; X.red = r*65535/255; X.green = g*65535/255; X.blue = b*65535/255; X.flags = DoRed | DoGreen | DoBlue; if (!XAllocColor(display,PARI_Colormap,&X)) exiterr("cannot allocate color"); return X.pixel; } static long colormapindex_to_pixel(Display *display, long i) { GEN c = gel(GP_DATA->colormap, i+1); int r,g,b; color_to_rgb(c, &r,&g,&b); return rgb_to_pixel(display, r, g, b); } static long rgb_color(Display *display, long c) { int r,g,b; long_to_rgb(c, &r, &g, &b); return rgb_to_pixel(display, r, g, b); } static void SetForeground(void *data, long col) { struct data_x *dx = (struct data_x *) data; XSetForeground(dx->display,dx->gc, rgb_color(dx->display,col)); } static void DrawPoint(void *data, long x, long y) { struct data_x *dx = (struct data_x *) data; XDrawPoint(dx->display,dx->win,dx->gc, x,y); } static void DrawLine(void *data, long x1, long y1, long x2, long y2) { struct data_x *dx = (struct data_x *) data; XDrawLine(dx->display,dx->win,dx->gc, x1,y1, x2,y2); } static void DrawRectangle(void *data, long x, long y, long w, long h) { struct data_x *dx = (struct data_x *) data; XDrawRectangle(dx->display,dx->win,dx->gc, x,y, w,h); } static void FillRectangle(void *data, long x, long y, long w, long h) { struct data_x *dx = (struct data_x *) data; XFillRectangle(dx->display,dx->win,dx->gc, x,y, w,h); } static void DrawPoints(void *data, long nb, struct plot_points *p) { struct data_x *dx = (struct data_x *) data; XPoint *xp=(XPoint*)pari_malloc(sizeof(xp)*nb); long i; for (i=0;idisplay,dx->win,dx->gc, xp, nb, 0); pari_free(xp); } static void DrawLines(void *data, long nb, struct plot_points *p) { struct data_x *dx = (struct data_x *) data; XPoint *xp=(XPoint*)pari_malloc(sizeof(xp)*nb); long i; for (i=0;idisplay,dx->win,dx->gc, xp, nb, 0); pari_free(xp); } static void DrawString(void *data, long x, long y, char *text, long numtext) { struct data_x *dx = (struct data_x *) data; XDrawString(dx->display,dx->win,dx->gc, x,y, text, numtext); } #define MAX_BUF 256 static int Xerror(Display *d, XErrorEvent *pari_err) { char buf[MAX_BUF]; XGetErrorText(d,pari_err->error_code,buf,MAX_BUF); exiterr(buf); return 0; } static int IOerror(Display *d) { char buf[MAX_BUF]; sprintf(buf, "lost display on %s", DisplayString(d)); exiterr(buf); return 0; } static void draw(PARI_plot *T, GEN w, GEN x, GEN y) { long oldwidth,oldheight; struct plot_eng plotX; struct data_x dx; double xs = 1, ys = 1; int screen, keystate; Display *display; GC gc; Window win; XEvent event; XSizeHints size_hints; XFontStruct *font_info; XSetWindowAttributes attrib; Atom wm_delete_window, wm_protocols; if (pari_daemon()) return; /* parent process returns */ display = XOpenDisplay(NULL); if (!display) exiterr("cannot open Display"); font_info = XLoadQueryFont(display, "7x13"); if (!font_info) exiterr("cannot open 7x13 font"); XSetErrorHandler(Xerror); XSetIOErrorHandler(IOerror); PARI_Colormap = DefaultColormap(display, 0); screen = DefaultScreen(display); win = XCreateSimpleWindow (display, RootWindow(display, screen), 0, 0, T->width, T->height, 4, colormapindex_to_pixel(display, 1), colormapindex_to_pixel(display, 0)); size_hints.flags = PPosition | PSize; size_hints.x = 0; size_hints.y = 0; size_hints.width = T->width; size_hints.height = T->height; XSetStandardProperties (display, win, "PARI plot", NULL, None, NULL, 0, &size_hints); wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False); XSetWMProtocols(display,win,&wm_delete_window, 1); XSelectInput (display, win, ExposureMask | ButtonPressMask | KeyReleaseMask | StructureNotifyMask); /* enable backing-store */ attrib.backing_store = Always; attrib.backing_planes = AllPlanes; XChangeWindowAttributes(display,win,CWBackingStore|CWBackingPlanes,&attrib); gc = XCreateGC(display, win, 0, NULL); XSetFont(display, gc, font_info->fid); XClearWindow(display, win); XMapWindow(display, win); oldwidth = T->width; oldheight = T->height; dx.display= display; dx.win = win; dx.numcolors = lg(GP_DATA->colormap)-1; dx.gc = gc; plotX.sc = &SetForeground; plotX.pt = &DrawPoint; plotX.ln = &DrawLine; plotX.bx = &DrawRectangle; plotX.fb = &FillRectangle; plotX.mp = &DrawPoints; plotX.ml = &DrawLines; plotX.st = &DrawString; plotX.pl = T; plotX.data = (void*)&dx; pari_close(); for(;;) { XNextEvent(display, &event); switch(event.type) { case ClientMessage: if (event.xclient.message_type != wm_protocols || (Atom)event.xclient.data.l[0] != wm_delete_window) break; case ButtonPress: case DestroyNotify: EXIT: XUnloadFont(display,font_info->fid); XFreeGC(display,gc); XCloseDisplay(display); exit(0); case KeyRelease: /* Mod4 == Super on "std" Linux */ keystate = event.xkey.state & (ShiftMask|ControlMask|Mod1Mask|Mod4Mask); switch (XkbKeycodeToKeysym(display, event.xkey.keycode, 0,0)) { case XK_q: if (!keystate || keystate == ControlMask) goto EXIT; break; case XK_c: if (keystate == ControlMask) goto EXIT; break; } break; case ConfigureNotify: { int width = event.xconfigure.width; int height = event.xconfigure.height; if (width == oldwidth && height == oldheight) break; oldwidth = width; oldheight = height; /* recompute scale */ xs = ((double)width)/T->width; ys = ((double)height)/T->height; } case Expose: gen_draw(&plotX, w, x, y, xs, ys); } } } INLINE void gp_get_display_sizes(long *dwidth, long *dheight, long *fwidth, long *fheight) { Display *display; display = XOpenDisplay(NULL); if (display) { int screen = DefaultScreen(display); *dwidth = DisplayWidth(display, screen); *dheight = DisplayHeight(display, screen); XCloseDisplay(display); } else { /* Situation looks grim */ *dwidth = 0; *dheight = 0; } *fwidth = 7; *fheight = 13; } void gp_get_plot(PARI_plot *T) { gp_get_plot_generic(T,gp_get_display_sizes); T->draw = &draw; } pari-2.11.2/src/graph/plotsvg.c0000644000175000017500000000231613326135265014720 0ustar billbill/* Copyright (C) 2017 The PARI group. This file is part of the PARI/GP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "rect.h" static void draw(PARI_plot *T, GEN w, GEN x, GEN y) { if (pari_daemon()) return; /* parent process returns */ pari_plot_by_file("GP_SVG_VIEWER", ".svg", rect2svg(w,x,y,T)); exit(0); } void gp_get_plot(PARI_plot *T) { T->width = 480; T->height = 320; T->fheight = 12; T->fwidth = 6; T->hunit = 3; T->vunit = 3; gp_get_ploth_default_sizes(T); T->dwidth = 0; T->dheight = 0; T->draw = &draw; } pari-2.11.2/src/graph/plotfltk.c0000644000175000017500000001047413326135265015065 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ ///////////////////////////////////////////////////////////////////////////// // // High resolution plot using FLTK library // Bill Allombert 2003 // // Based on plotQt by Nils-Peter Skoruppa (www.countnumber.de) ///////////////////////////////////////////////////////////////////////////// extern "C" { #include "pari.h" #include "rect.h" } #include #include #include class Plotter: public Fl_Window { public: Plotter(PARI_plot *T, GEN w, GEN x, GEN y); private: void draw(); int handle(int event); private: PARI_plot *T; GEN my_w, my_x, my_y; }; static Fl_Color rgb_color(long c) { int r, g, b; long_to_rgb(c, &r, &g, &b); return fl_color_cube(r*FL_NUM_RED/256, g*FL_NUM_GREEN/256, b*FL_NUM_BLUE/256); } Plotter::Plotter(PARI_plot *T, GEN w, GEN x, GEN y) : Fl_Window(T->width, T->height, "PARI/GP") { this->T = T; this->my_w = w; this->my_x = x; this->my_y = y; } static void DrawPoint(void *data, long x, long y) { (void)data; fl_point(x,y); } static void DrawLine(void *data, long x1, long y1, long x2, long y2) { (void)data; fl_line(x1,y1, x2,y2); } static void DrawRectangle(void *data, long x, long y, long w, long h) { (void)data; fl_rect(x,y,w,h); } static void FillRectangle(void *data, long x, long y, long w, long h) { (void)data; fl_rectf(x,y,w,h); } static void DrawPoints(void *data, long nb, struct plot_points *p) { long i; (void)data; for (i=0; iw()) / T->width; double ys = double(this->h()) / T->height; fl_font(FL_COURIER, int(T->fheight * xs)); fl_color(rgb_color(0xffffff)); // transparent window on Windows otherwise fl_rectf(0, 0, this->w(), this->h()); pl.sc = &SetForeground; pl.pt = &DrawPoint; pl.ln = &DrawLine; pl.bx = &DrawRectangle; pl.fb = &FillRectangle; pl.mp = &DrawPoints; pl.ml = &DrawLines; pl.st = &DrawString; pl.pl = T; pl.data = NULL; gen_draw(&pl, my_w, my_x, my_y, xs, ys); } int Plotter::handle(int event) { switch(event) { case FL_PUSH: switch(Fl::event_button()) { case 1: exit(0); case 2: { static int flag = 0, my_x, my_y, my_w, my_h; flag = 1-flag; if (flag) { my_x = this->x(); my_y = this->y(); my_w = this->w(); my_h = this->h(); this->fullscreen(); } else { this->fullscreen_off(my_x, my_y, my_w, my_h); this->size_range(1,1); } return 1; } } case FL_KEYUP: switch(Fl::event_key()) { case 'q': switch(Fl::event_shift()) { case 0: case FL_CTRL: exit(0); } break; case 'c': if (Fl::event_state() == FL_CTRL) exit(0); break; } default: return 0; } } static void draw(PARI_plot *T, GEN w, GEN x, GEN y) { Plotter *win; if (pari_daemon()) return; // parent process returns pari_close(); Fl::visual(FL_DOUBLE|FL_INDEX); win = new Plotter(T, w, x, y); win->size_range(1,1); win->box(FL_FLAT_BOX); win->end(); win->show(); Fl::run(); exit(0); } INLINE void gp_get_display_sizes(long *dwidth, long *dheight, long *fwidth, long *fheight) { *dwidth = 800; *dheight = 600; *fwidth = 6; *fheight = 9; } void gp_get_plot(PARI_plot *T) { gp_get_plot_generic(T,gp_get_display_sizes); T->draw = &draw; } pari-2.11.2/src/graph/plotWin32.c0000644000175000017500000000707313326135265015030 0ustar billbill/* Copyright (C) 2009 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Written by Vasili Burdo */ #include "../systems/mingw/pwinver.h" #include #include #include "pari.h" #include "rect.h" static void SetForeground(void *data, long col) { HPEN hOldPen; int r, g, b; long_to_rgb(col, &r, &g, &b); SetDCPenColor((HDC)data,RGB(r,g,b)); hOldPen = SelectObject((HDC)data, CreatePen(PS_SOLID, 1, RGB(r,g,b))); if( hOldPen ) DeleteObject(hOldPen); } static void DrawPoint(void *data, long x, long y) { Ellipse((HDC)data,x-1,y-1,x+1,y+1); } static void DrawLine(void *data, long x1, long y1, long x2, long y2) { MoveToEx((HDC)data, x1, y1, NULL); LineTo((HDC)data,x2,y2); } static void DrawRectangle(void *data, long x, long y, long w, long h) { DrawLine(data, x,y,x+w,y); DrawLine(data, x,y,x,y+h); DrawLine(data, x+w,y,x+w,y+h); DrawLine(data, x,y+h,x+w,y+h); } static void FillRectangle(void *data, long x, long y, long w, long h) { RECT rc; COLORREF color; HBRUSH brush; rc.left = x; rc.right = x+w; rc.top = y; rc.bottom = y+h; color = GetDCPenColor((HDC) data); brush = CreateSolidBrush(color); FillRect((HDC)data, &rc, brush); DeleteObject(brush); } static void DrawPoints(void *data, long nb, struct plot_points *p) { long i; for (i=0; icolormap,1), &r,&g,&b); SetBkColor(hEmf, RGB(r,g,b)); SetBkMode(hEmf, OPAQUE); plotWin32.sc=&SetForeground; plotWin32.pt=&DrawPoint; plotWin32.ln=&DrawLine; plotWin32.bx=&DrawRectangle; plotWin32.fb=&FillRectangle; plotWin32.mp=&DrawPoints; plotWin32.ml=&DrawLines; plotWin32.st=&DrawString; plotWin32.pl=T; plotWin32.data=(void*)hEmf; gen_draw(&plotWin32, w, x, y, 1, 1); DeleteEnhMetaFile(CloseEnhMetaFile(hEmf)); ShellExecute(NULL,NULL,fname,NULL,NULL,SW_SHOWDEFAULT); } INLINE void gp_get_display_sizes(long *dwidth, long *dheight, long *fwidth, long *fheight) { HDC hdc; TEXTMETRIC tm; *dwidth = GetSystemMetrics(SM_CXSCREEN); *dheight = GetSystemMetrics(SM_CYSCREEN); hdc = GetDC(0); SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); GetTextMetrics(hdc, &tm); ReleaseDC(0,hdc); *fwidth = tm.tmAveCharWidth; *fheight = tm.tmHeight; } void gp_get_plot(PARI_plot *T) { gp_get_plot_generic(T,gp_get_display_sizes); T->draw = &draw; } pari-2.11.2/src/graph/plotQt4.c0000644000175000017500000002376513447371554014613 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ ///////////////////////////////////////////////////////////////////////////// // // High resolution plot using Trolltech's Qt library // // You may possibly want to use this file with a "Qt Free Edition" // which is distributed under the terms of the Q PUBLIC LICENSE (QPL), // or with a "Qt/Embedded Free Edition" which is // distributed under the terms of the GNU General Public License (GPL). // Please check http://www.trolltech.com for details. // // ---Nils-Peter Skoruppa (www.countnumber.de) ///////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include "pari.h" #include "rect.h" #undef grem } using namespace Qt; class Plotter: public QWidget { Q_OBJECT signals: void clicked(); protected: void mouseReleaseEvent(QMouseEvent*); public: Plotter(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent = 0); void save(const QString& s = *plotFile + ".xpm", const QString& f = QString("XPM")); protected: void paintEvent(QPaintEvent *); private: PARI_plot *T; GEN w, x, y; QColor color0; QFont font; static QString *plotFile; void draw(QPainter *p); }; QString *Plotter::plotFile = new QString("pariplot"); static QColor rgb_color(long c) { int r, g, b; long_to_rgb(c, &r, &g, &b); return QColor(r, g, b); } Plotter::Plotter(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent) : QWidget(parent), font("lucida", 9) { this->w = w; this->x = x; this->y = y; this->T = T; this->setFont(font); { int r, g, b; color_to_rgb(gel(GP_DATA->colormap,1), &r, &g, &b); color0 = QColor(r, g, b); } QPalette palette; palette.setColor(backgroundRole(), color0); setPalette(palette); } static void SetForeground(void *data, long col) { QPainter *p = (QPainter *)data; p->setPen(rgb_color(col)); } static void DrawPoint(void *data, long x, long y) { QPainter *p = (QPainter *)data; p->drawPoint(x, y); } static void DrawLine(void *data, long x1, long y1, long x2, long y2) { QPainter *p = (QPainter *)data; p->drawLine(x1, y1, x2, y2); } static void DrawRectangle(void *data, long x, long y, long w, long h) { QPainter *p = (QPainter *)data; p->drawRect(x, y, w, h); } static void FillRectangle(void *data, long x, long y, long w, long h) { QPainter *p = (QPainter *)data; p->fillRect(x, y, w, h, p->pen().color()); } static void DrawPoints(void *data, long nb, struct plot_points *pt) { QPainter *p = (QPainter *)data; QPolygon xp = QPolygon(nb); long i; for (i = 0;i < nb; i++) xp.setPoint(i,pt[i].x, pt[i].y); p->drawPoints(xp); } static void DrawLines(void *data, long nb, struct plot_points *pt) { QPainter *p = (QPainter *)data; QPolygon xp = QPolygon(nb); long i; for (i = 0;i < nb; i++) xp.setPoint(i, pt[i].x, pt[i].y); p->drawPolyline(xp); } static void DrawString(void *data, long x, long y, char *text, long numtext) { QPainter *p = (QPainter *)data; p->drawText(x, y, QString(text).left(numtext)); } void Plotter::draw(QPainter *p) { struct plot_eng plotQt; plotQt.sc=&SetForeground; plotQt.pt=&DrawPoint; plotQt.ln=&DrawLine; plotQt.bx=&DrawRectangle; plotQt.fb=&FillRectangle; plotQt.mp=&DrawPoints; plotQt.mp=&DrawPoints; plotQt.ml=&DrawLines; plotQt.st=&DrawString; plotQt.pl=T; plotQt.data=(void *)p; double xs = double(this->width()) / T->width; double ys = double(this->height()) / T->height; gen_draw(&plotQt, this->w, this->x, this->y, xs, ys); } void Plotter::save(const QString& s, const QString& f) { QPixmap pm(this->width(), this->height()); QPainter p; p.begin(&pm); p.initFrom(this); p.fillRect(0, 0, pm.width(), pm.height(), color0); draw(&p); p.end(); pm.save(s, f.toAscii().data()); } void Plotter::paintEvent(QPaintEvent *) { QPainter p; p.begin(this); this->draw(&p); p.end(); } void Plotter::mouseReleaseEvent(QMouseEvent*) { emit clicked(); } /* XPM */ static const char * const fullscreen_xpm[] = { "14 14 2 1", " c None", ". c #000000", "..............", ". .. .", ". .. .", ". .... .", ". .. .", ". . .. . .", "..............", "..............", ". . .. . .", ". .. .", ". .... .", ". .. .", ". .. .", ".............."}; class PlotWindow: public QMainWindow { Q_OBJECT public: PlotWindow(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent = 0); ~PlotWindow(); protected: void resizeEvent(QResizeEvent *); private slots: void fullScreen(); void normalView(); void save(); void save(int); private: static const QList file_formats; Plotter *plr; QString saveFileName; int saveFileFormat; QLabel *res; QMenu* menuFile; QMenu* menuView; QMenu* menuFormat; QAction* quitAction; QAction* saveAction; QAction* fullScreenAction; QSignalMapper* signalMapper; QIcon* icon; }; const QList PlotWindow::file_formats = QImageWriter::supportedImageFormats(); PlotWindow::PlotWindow(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent) : QMainWindow(parent), saveFileName("pariplot"), saveFileFormat(0) { setWindowTitle("Pari QtPlot"); QPalette palette; palette.setColor(this->backgroundRole(), white); this->setPalette(palette); menuFile = menuBar()->addMenu("&File"); saveAction = new QAction("&Save",this); saveAction->setShortcut(QKeySequence(CTRL+Key_S)); connect (saveAction, SIGNAL(triggered()), this, SLOT(save())); menuFile->addAction(saveAction); menuFormat = menuFile->addMenu("Save &as"); signalMapper = new QSignalMapper(this); for(int i = 0; i < file_formats.count(); i++) { QAction* tmpAction; tmpAction = new QAction(QString(file_formats.at(i)),this); connect (tmpAction, SIGNAL(triggered()), signalMapper, SLOT(map())); signalMapper->setMapping(tmpAction,i); menuFormat->addAction(tmpAction); } connect (signalMapper, SIGNAL(mapped(int)), this,SLOT(save(int))); quitAction = new QAction("&Quit",this); quitAction->setShortcut(QKeySequence(CTRL+Key_Q)); connect (quitAction, SIGNAL(triggered()), this, SLOT(close())); menuFile->addAction(quitAction); menuView = menuBar()->addMenu("&View"); fullScreenAction = new QAction("Use &full screen", this); fullScreenAction->setShortcut(QKeySequence(CTRL+Key_F)); icon = new QIcon(); icon->addPixmap(QPixmap((const char ** )fullscreen_xpm)); fullScreenAction->setIcon(*icon); connect(fullScreenAction, SIGNAL(triggered()), this, SLOT(fullScreen())); menuView->addAction(fullScreenAction); // Setting up an instance of plotter plr = new Plotter(T, w, x, y, this); connect(plr, SIGNAL(clicked()), this, SLOT(normalView())); this->setCentralWidget(plr); this->resize(T->width, T->height + 24); res = new QLabel(); statusBar()->addWidget(res); } PlotWindow::~PlotWindow() {} void PlotWindow::resizeEvent(QResizeEvent *e) { QMainWindow::resizeEvent(e); res->setText(QString("Resolution: ") + QString::number(plr->width()) + "x" + QString::number(plr->height())); res->setFixedSize(res->sizeHint()); } void PlotWindow::fullScreen() { plr->setParent(0); plr->showMaximized(); plr->show(); } void PlotWindow::normalView() { if (!plr->parentWidget()) { plr->setParent(this); this->setCentralWidget(plr); plr->show(); } } void PlotWindow::save() { QString ff = QString(file_formats.at(saveFileFormat)); QString fn = saveFileName + "." + ff.toLower(); plr->save(fn, ff); setWindowTitle(QString("Pari QtPlot:") + fn); } void PlotWindow::save(int id) { QString ff(file_formats.at(id)); QString s(ff + " (*." + ff.toLower() +");;All (*)"); QString fn = QFileDialog::getSaveFileName(this, saveFileName + "." + ff, saveFileName + "." + ff, s); if (!fn.isEmpty()) { saveFileName = fn; int p; if ((p = saveFileName.lastIndexOf("." + ff, -1)) >= 0) saveFileName.truncate(p); saveFileFormat = id; save(); } } #include "plotQt4.moc.cpp" static void draw(PARI_plot *T, GEN w, GEN x, GEN y) { if (pari_daemon()) return; // parent process returns // launch Qt window int argc = 1; // set argc = 2 for cross const char * argv[] = { "gp", "-qws"}; // development using qvfb QApplication a(argc, (char**) argv); PlotWindow *win = new PlotWindow(T, w, x, y); win->show(); a.exec(); pari_close(); exit(0); } INLINE void gp_get_display_sizes(long *dwidth, long *dheight, long *fwidth, long *fheight) { /* There must be an easier way to get desktop size... */ int argc = 1; const char * argv[] = { "gp", "-qws"}; QApplication a(argc, (char**) argv); QDesktopWidget *qw = new QDesktopWidget(); if (qw) { QRect rec = qw->screenGeometry(); *dwidth = rec.width(); // screen width *dheight = rec.height(); // and height } else { *dwidth = 0; *dheight = 0; } *fwidth = 6; // font width *fheight = 9; // and height } void gp_get_plot(PARI_plot *T) { gp_get_plot_generic(T,gp_get_display_sizes); T->draw = &draw; } pari-2.11.2/src/graph/plotps.c0000644000175000017500000000234013326135265014540 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* HIGH RESOLUTION PLOT VIA POSTSCRIPT FILE */ /*******************************************************************/ #include "pari.h" #include "rect.h" static void draw(PARI_plot *T, GEN w, GEN x, GEN y) { if (pari_daemon()) return; /* parent process returns */ pari_plot_by_file("GP_POSTSCRIPT_VIEWER", ".ps", rect2ps_i(w,x,y,T,1)); exit(0); } void gp_get_plot(PARI_plot *T) { T->width = 400; T->height = 300; T->fheight= 9; T->fwidth = 5; T->hunit = 3; T->vunit = 3; gp_get_ploth_default_sizes(T); T->dwidth = 0; T->dheight= 0; T->draw = &draw; } pari-2.11.2/src/graph/plottty.c0000644000175000017500000001060413326135265014740 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /********************************************************************/ /** **/ /** LOW-RES PLOT **/ /** **/ /********************************************************************/ #define ISCR 64 #define JSCR 22 INLINE long DTOL(double t) { return (long)(t + 0.5); } static char PICT(long j) { switch(j%3) { case 0: return '_'; case 1: return 'x'; default: return '"'; } } static char PICTZERO(long j) { switch(j%3) { case 0: return ','; case 1: return '-'; default: return '`'; } } static char * dsprintf9(double d, char *buf) { int i = 10; while (--i >= 0) { sprintf(buf, "%9.*g", i, d); if (strlen(buf) <= 9) break; } return buf; } typedef unsigned char screen[ISCR+1][JSCR+1]; static void fill_gap(screen scr, long i, int jnew, int jpre) { int mid, i_up, i_lo, up, lo; if (jpre < jnew - 2) { up = jnew - 1; i_up = i; lo = jpre + 1; i_lo = i - 1; } else if (jnew < jpre - 2) { up = jpre - 1; i_up = i - 1; lo = jnew + 1; i_lo = i; } else return; /* if gap < 2, leave it as it is. */ mid = (jpre+jnew)/2; if (mid>JSCR) mid=JSCR; else if (mid<0) mid=0; if (lo<0) lo=0; if (lo<=JSCR) while (lo <= mid) scr[i_lo][lo++] = ':'; if (up>JSCR) up=JSCR; if (up>=0) while (up > mid) scr[i_up][up--] = ':'; } static double todbl(GEN x) { return rtodbl(gtofp(x, LOWDEFAULTPREC)); } /* code is either a t_CLOSURE (from GP: ploth, etc.) or a t_POL/t_VEC of * two t_POLs from rectsplines */ static GEN READ_EXPR(GEN code, GEN x) { if (typ(code)!=t_CLOSURE) return gsubst(code,0,x); set_lex(-1, x); return closure_evalgen(code); } void pariplot(GEN a, GEN b, GEN code, GEN ysmlu,GEN ybigu, long prec) { const char BLANK = ' ', YY = '|', XX_UPPER = '\'', XX_LOWER = '.'; long jz, j, i, sig; pari_sp av = avma; int jnew, jpre = 0; /* for lint */ GEN x, dx; double diff, dyj, ysml, ybig, y[ISCR+1]; screen scr; char buf[80], z; sig=gcmp(b,a); if (!sig) return; if (sig<0) { x=a; a=b; b=x; } x = gtofp(a, prec); push_lex(x, code); dx = divru(gtofp(gsub(b,a),prec), ISCR-1); for (j=1; j<=JSCR; j++) scr[1][j]=scr[ISCR][j]=YY; for (i=2; i ybig) ybig = y[i]; } x = addrr(x,dx); } avma = av; if (ysmlu) ysml = gtodouble(ysmlu); if (ybigu) ybig = gtodouble(ybigu); diff = ybig - ysml; if (!diff) { ybig += 1; diff= 1.; } dyj = ((JSCR-1)*3+2) / diff; /* work around bug in gcc-4.8 (32bit): plot(x=-5,5,sin(x)))) */ jz = 3 - (long)(ysml*dyj + 0.5); /* 3 - DTOL(ysml*dyj) */ z = PICTZERO(jz); jz /= 3; for (i=1; i<=ISCR; i++) { if (0<=jz && jz<=JSCR) scr[i][jz]=z; j = 3 + DTOL((y[i]-ysml)*dyj); jnew = j/3; if (i > 1) fill_gap(scr, i, jnew, jpre); if (0<=jnew && jnew<=JSCR) scr[i][jnew] = PICT(j); jpre = jnew; } pari_putc('\n'); pari_printf("%s ", dsprintf9(ybig, buf)); for (i=1; i<=ISCR; i++) pari_putc(scr[i][JSCR]); pari_putc('\n'); for (j=(JSCR-1); j>=2; j--) { pari_puts(" "); for (i=1; i<=ISCR; i++) pari_putc(scr[i][j]); pari_putc('\n'); } pari_printf("%s ", dsprintf9(ysml, buf)); for (i=1; i<=ISCR; i++) pari_putc(scr[i][1]); pari_putc('\n'); { char line[10 + 32 + 32 + ISCR - 9]; sprintf(line, "%10s%-9.7g%*.7g\n"," ",todbl(a),ISCR-9,todbl(b)); pari_printf(line); } pop_lex(1); } pari-2.11.2/src/mt/0000755000175000017500000000000013461316051012365 5ustar billbillpari-2.11.2/src/mt/pthread.h0000644000175000017500000000141613036414402014164 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define MT_IS_THREAD mt_is_thread() #define MT_SIGINT_BLOCK(block) do {if (!block) mt_sigint_block();} while(0) #define MT_SIGINT_UNBLOCK(block) do {if (!block) mt_sigint_unblock();} while(0) pari-2.11.2/src/mt/mpi.h0000644000175000017500000000124313036414402013320 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define MT_IS_THREAD mt_is_thread() #define MT_SIGINT_BLOCK(block) #define MT_SIGINT_UNBLOCK(block) pari-2.11.2/src/mt/mt.h0000644000175000017500000000130613036414402013153 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ BEGINEXTERN void mtsingle_queue_start(struct pari_mt *pt, GEN worker); void mt_queue_reset(void); int mt_is_parallel(void); ENDEXTERN pari-2.11.2/src/mt/single.h0000644000175000017500000000122413036414402014013 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define MT_IS_THREAD 0 #define MT_SIGINT_BLOCK(block) #define MT_SIGINT_UNBLOCK(block) pari-2.11.2/src/mt/mpi.c0000644000175000017500000001763013447371554013342 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "pari.h" #include "paripriv.h" #include "mt.h" static THREAD int pari_MPI_size, pari_MPI_rank; static THREAD long nbreq = 0; enum PMPI_cmd { PMPI_close, PMPI_worker, PMPI_work, PMPI_parisizemax, PMPI_parisize, PMPI_precreal, PMPI_primetab, PMPI_eval }; struct mt_mstate { long n; int source; long nbint; long *workid; }; static struct mt_mstate pari_mt_data; static struct mt_mstate *pari_mt; static void send_long(long a, long dest) { BLOCK_SIGINT_START MPI_Send(&a, 1, MPI_LONG, dest, 0, MPI_COMM_WORLD); BLOCK_SIGINT_END } static void send_request(enum PMPI_cmd ecmd, long dest) { send_long((long)ecmd, dest); } static void send_GEN(GEN elt, int dest) { pari_sp av = avma; int size; GEN reloc = copybin_unlink(elt); GENbin *buf = copy_bin(mkvec2(elt,reloc)); size = sizeof(GENbin) + buf->len*sizeof(ulong); { BLOCK_SIGINT_START MPI_Send(buf, size, MPI_CHAR, dest, 0, MPI_COMM_WORLD); BLOCK_SIGINT_END } pari_free(buf); avma = av; } static void send_request_GEN(enum PMPI_cmd ecmd, GEN elt, int dest) { send_request(ecmd, dest); send_GEN(elt, dest); } static void send_request_long(enum PMPI_cmd ecmd, long elt, int dest) { send_request(ecmd, dest); send_long(elt, dest); } static long recvfrom_long(int src) { long a; BLOCK_SIGINT_START MPI_Recv(&a, 1, MPI_LONG, src, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); BLOCK_SIGINT_END return a; } static enum PMPI_cmd recvfrom_request(int src) { return (enum PMPI_cmd) recvfrom_long(src); } static GENbin * recvstatus_buf(int source, MPI_Status *status) { int size; GENbin *buf; BLOCK_SIGINT_START MPI_Get_count(status, MPI_CHAR, &size); buf = (GENbin *)pari_malloc(size); MPI_Recv(buf, size, MPI_CHAR, source, 0/* tag */, MPI_COMM_WORLD, MPI_STATUS_IGNORE); BLOCK_SIGINT_END return buf; } static GEN recvstatus_GEN(int source, MPI_Status *status) { GEN res; GENbin *buf = recvstatus_buf(source, status); buf->rebase = &shiftaddress; res = bin_copy(buf); bincopy_relink(gel(res,1),gel(res,2)); return gel(res,1); } static void recvstatus_void(int source, MPI_Status *status) { GENbin *buf = recvstatus_buf(source, status); free(buf); } static GEN recvfrom_GEN(int src) { MPI_Status status; BLOCK_SIGINT_START MPI_Probe(src, 0, MPI_COMM_WORLD, &status); BLOCK_SIGINT_END return recvstatus_GEN(src, &status); } static GEN recvany_GEN(int *source) { MPI_Status status; BLOCK_SIGINT_START MPI_Probe(MPI_ANY_SOURCE, 0 /* tag */, MPI_COMM_WORLD, &status); *source = status.MPI_SOURCE; BLOCK_SIGINT_END return recvstatus_GEN(*source, &status); } static void recvany_void(int *source) { MPI_Status status; BLOCK_SIGINT_START MPI_Probe(MPI_ANY_SOURCE, 0 /* tag */, MPI_COMM_WORLD, &status); *source = status.MPI_SOURCE; BLOCK_SIGINT_END recvstatus_void(*source, &status); } static jmp_buf child_env; static void pari_MPI_child(void) { pari_sp av = avma; ulong rsize = 0, vsize = 0; GEN worker = NULL, work, done; struct gp_context rec; pari_mt_nbthreads = 1; gp_context_save(&rec); if (setjmp(child_env)) { send_GEN(pari_err_last(), 0); gp_context_restore(&rec); } while (1) switch (recvfrom_request(0)) { case PMPI_worker: paristack_setsize(rsize, vsize); gp_context_save(&rec); worker = recvfrom_GEN(0); av = avma; break; case PMPI_work: work = recvfrom_GEN(0); done = closure_callgenvec(worker, work); send_GEN(done, 0); avma = av; break; case PMPI_parisizemax: vsize = recvfrom_long(0); break; case PMPI_parisize: rsize = recvfrom_long(0); break; case PMPI_precreal: precreal = recvfrom_long(0); break; case PMPI_primetab: { pari_sp ltop = avma; GEN tab = recvfrom_GEN(0); if (!gequal(tab, primetab)) { long i, l = lg(tab); GEN old = primetab, t = cgetg_block(l, t_VEC); for (i = 1; i < l; i++) gel(t,i) = gclone(gel(tab,i)); primetab = t; gunclone_deep(old); } avma = ltop; } break; case PMPI_eval: (void) closure_evalgen(recvfrom_GEN(0)); avma = av; break; case PMPI_close: MPI_Barrier(MPI_COMM_WORLD); MPI_Finalize(); exit(0); break; } } void mt_err_recover(long er) { if (pari_MPI_rank) longjmp(child_env,er); } void mt_sigint_block(void) { } void mt_sigint_unblock(void) { } void mt_sigint(void) {} int mt_is_parallel(void) { return !!pari_mt; } int mt_is_thread(void) { return pari_MPI_rank; } void mt_broadcast(GEN code) { long i; if (!pari_MPI_rank && !pari_mt) for (i=1;inbint<=mt->n) { mt->source=mt->nbint; *pending = nbreq; return NULL; } done = recvany_GEN(&mt->source); nbreq--; *pending = nbreq; if (workid) *workid = mt->workid[mt->source]; if (typ(done) == t_ERROR) { if (err_get_num(done)==e_STACK) pari_err(e_STACKTHREAD); else pari_err(0,done); } return done; } static void mtmpi_queue_submit(struct mt_state *junk, long workid, GEN work) { struct mt_mstate *mt = pari_mt; (void) junk; if (!work) { mt->nbint=mt->n+1; return; } if (mt->nbint<=mt->n) mt->nbint++; nbreq++; mt->workid[mt->source] = workid; send_request_GEN(PMPI_work, work, mt->source); } void mt_queue_reset(void) { struct mt_mstate *mt = pari_mt; if (DEBUGLEVEL>0 && nbreq) pari_warn(warner,"%ld discarded threads (MPI)",nbreq); for( ;nbreq>0; nbreq--) recvany_void(&mt->source); pari_free(mt->workid); pari_mt = NULL; } void mt_queue_start_lim(struct pari_mt *pt, GEN worker, long lim) { if (lim==0) lim = pari_mt_nbthreads; else lim = minss(pari_mt_nbthreads, lim); if (pari_mt || pari_MPI_rank || pari_MPI_size <= 2 || lim <= 1) mtsingle_queue_start(pt, worker); else { struct mt_mstate *mt = &pari_mt_data; long i, n = minss(lim, pari_MPI_size-1); long mtparisize = GP_DATA->threadsize? GP_DATA->threadsize: pari_mainstack->rsize; long mtparisizemax = GP_DATA->threadsizemax; pari_mt = mt; mt->workid = (long*) pari_malloc(sizeof(long)*(n+1)); for (i=1; i <= n; i++) { send_request_long(PMPI_parisize, mtparisize, i); send_request_long(PMPI_parisizemax, mtparisizemax, i); send_request_long(PMPI_precreal, get_localbitprec(), i); send_request_GEN(PMPI_primetab, primetab, i); send_request_GEN(PMPI_worker, worker, i); } mt->n = n; mt->nbint = 1; mt->source = 1; pt->get=&mtmpi_queue_get; pt->submit=&mtmpi_queue_submit; pt->end=&mt_queue_reset; } } pari-2.11.2/src/mt/single.c0000644000175000017500000000214013326135265014015 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #include "mt.h" void mt_sigint_block(void) { } void mt_sigint_unblock(void) { } void mt_err_recover(long er) { (void)er; } void pari_mt_close(void) { } void mt_queue_reset(void) { } void mt_broadcast(GEN code) {(void) code;} void mt_sigint(void) {} int mt_is_parallel(void) { return 0; } int mt_is_thread(void) { return 0; } void pari_mt_init(void) { pari_mt_nbthreads = 1; } void mt_queue_start_lim(struct pari_mt *pt, GEN worker, long lim) { (void) lim; mtsingle_queue_start(pt, worker); } pari-2.11.2/src/mt/pthread.c0000644000175000017500000002032713455326605014175 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "pari.h" #include "paripriv.h" #include "mt.h" #if defined(_WIN32) # include "../systems/mingw/mingw.h" #endif struct mt_queue { long no; pari_sp avma; struct pari_mainstack *mainstack; GEN input, output; GEN worker; long workid; pthread_cond_t cond; pthread_mutex_t mut; pthread_cond_t *pcond; pthread_mutex_t *pmut; }; struct mt_pstate { pthread_t *th; struct pari_thread *pth; struct mt_queue *mq; long n, nbint, last; long pending; pthread_cond_t pcond; pthread_mutex_t pmut; }; static THREAD long mt_thread_no = -1; static struct mt_pstate *pari_mt; #define LOCK(x) pthread_mutex_lock(x); do #define UNLOCK(x) while(0); pthread_mutex_unlock(x) void mt_sigint_block(void) { if (mt_thread_no>=0) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); } void mt_sigint_unblock(void) { if (mt_thread_no>=0) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); } void mt_err_recover(long er) { (void) er; if (mt_thread_no>=0) { struct mt_pstate *mt = pari_mt; struct mt_queue *mq = mt->mq+mt_thread_no; GEN err = pari_err_last(); err = err_get_num(err)==e_STACK ? err_e_STACK: bin_copy(copy_bin(err)); LOCK(mq->pmut) { mq->output = err; pthread_cond_signal(mq->pcond); } UNLOCK(mq->pmut); pthread_exit((void*)1); } } void mt_sigint(void) { if (pari_mt) pthread_cond_broadcast(&pari_mt->pcond); } int mt_is_parallel(void) { return !!pari_mt; } int mt_is_thread(void) { return mt_thread_no>=0; } void mt_broadcast(GEN code) {(void) code;} void pari_mt_init(void) { pari_mt = NULL; #ifdef _SC_NPROCESSORS_CONF if (!pari_mt_nbthreads) pari_mt_nbthreads = sysconf(_SC_NPROCESSORS_CONF); #elif defined(_WIN32) if (!pari_mt_nbthreads) pari_mt_nbthreads = win32_nbthreads(); #else pari_mt_nbthreads = 1; #endif } void pari_mt_close(void) { } static void mt_queue_cleanup(void *arg) { (void) arg; pari_thread_close(); } static void* mt_queue_run(void *arg) { GEN args = pari_thread_start((struct pari_thread*) arg); pari_sp av = avma; struct mt_queue *mq = (struct mt_queue *) args; mt_thread_no = mq->no; pthread_cleanup_push(mt_queue_cleanup,NULL); LOCK(mq->pmut) { mq->mainstack = pari_mainstack; mq->avma = av; pthread_cond_signal(mq->pcond); } UNLOCK(mq->pmut); for(;;) { GEN work, done; LOCK(&mq->mut) { while(!mq->input) pthread_cond_wait(&mq->cond, &mq->mut); } UNLOCK(&mq->mut); pari_mainstack = mq->mainstack; avma = mq->avma; work = mq->input; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); done = closure_callgenvec(mq->worker,work); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); LOCK(mq->pmut) { mq->mainstack = pari_mainstack; mq->avma = av; mq->input = NULL; mq->output = done; pthread_cond_signal(mq->pcond); } UNLOCK(mq->pmut); } pthread_cleanup_pop(1); #ifdef __GNUC__ return NULL; /* LCOV_EXCL_LINE */ #endif } static long mt_queue_check(struct mt_pstate *mt) { long i; for(i=0; in; i++) { struct mt_queue *mq = mt->mq+i; if (mq->output) return i; } return -1; } static GEN mtpthread_queue_get(struct mt_state *junk, long *workid, long *pending) { struct mt_pstate *mt = pari_mt; struct mt_queue *mq; GEN done = NULL; long last; (void) junk; if (mt->nbintn) { mt->last = mt->nbint; *pending = mt->pending; return NULL; } BLOCK_SIGINT_START LOCK(&mt->pmut) { while ((last = mt_queue_check(mt)) < 0) { pthread_cond_wait(&mt->pcond, &mt->pmut); if (PARI_SIGINT_pending) { int sig = PARI_SIGINT_pending; PARI_SIGINT_pending = 0; pthread_mutex_unlock(&mt->pmut); PARI_SIGINT_block = 0; raise(sig); PARI_SIGINT_block = 1; pthread_mutex_lock(&mt->pmut); } } } UNLOCK(&mt->pmut); BLOCK_SIGINT_END mq = mt->mq+last; done = gcopy(mq->output); mq->output = NULL; if (workid) *workid = mq->workid; if (typ(done) == t_ERROR) { if (err_get_num(done)==e_STACK) pari_err(e_STACKTHREAD); else pari_err(0,done); } mt->last = last; mt->pending--; *pending = mt->pending; return done; } static void mtpthread_queue_submit(struct mt_state *junk, long workid, GEN work) { struct mt_pstate *mt = pari_mt; struct mt_queue *mq = mt->mq+mt->last; (void) junk; if (!work) { mt->nbint=mt->n; return; } BLOCK_SIGINT_START if (mt->nbintn) { mt->nbint++; LOCK(mq->pmut) { while(!mq->avma) pthread_cond_wait(mq->pcond, mq->pmut); } UNLOCK(mq->pmut); } LOCK(&mq->mut) { mq->output = NULL; mq->workid = workid; BLOCK_SIGINT_START { pari_sp av = avma; struct pari_mainstack *st = pari_mainstack; pari_mainstack = mq->mainstack; avma = mq->avma; mq->input = gcopy(work); mq->avma = avma; mq->mainstack = pari_mainstack; pari_mainstack = st; avma = av; } BLOCK_SIGINT_END pthread_cond_signal(&mq->cond); } UNLOCK(&mq->mut); mt->pending++; BLOCK_SIGINT_END } void mt_queue_reset(void) { struct mt_pstate *mt = pari_mt; long i; BLOCK_SIGINT_START for (i=0; in; i++) pthread_cancel(mt->th[i]); for (i=0; in; i++) pthread_join(mt->th[i],NULL); pari_mt = NULL; BLOCK_SIGINT_END if (DEBUGLEVEL) pari_warn(warner,"stopping %ld threads", mt->n); for (i=0;in;i++) { struct mt_queue *mq = mt->mq+i; pthread_cond_destroy(&mq->cond); pthread_mutex_destroy(&mq->mut); pari_thread_free(&mt->pth[i]); } pari_free(mt->mq); pari_free(mt->pth); pari_free(mt->th); pari_free(mt); } static long closure_has_clone(GEN fun) { if (isclone(fun)) return 1; if (lg(fun) >= 8) { GEN f = closure_get_frame(fun); long i, l = lg(f); for (i = 1; i < l; i++) if (isclone(gel(f,i))) return 1; } return 0; } void mt_queue_start_lim(struct pari_mt *pt, GEN worker, long lim) { if (lim==0) lim = pari_mt_nbthreads; else lim = minss(pari_mt_nbthreads, lim); if (pari_mt || lim <= 1) mtsingle_queue_start(pt, worker); else { struct mt_pstate *mt = (struct mt_pstate*) pari_malloc(sizeof(struct mt_pstate)); long mtparisize = GP_DATA->threadsize? GP_DATA->threadsize: pari_mainstack->rsize; long mtparisizemax = GP_DATA->threadsizemax; long i; if (closure_has_clone(worker)) worker = gcopy(worker); /* to avoid clone_lock race */ mt->mq = (struct mt_queue *) pari_malloc(sizeof(*mt->mq)*lim); mt->th = (pthread_t *) pari_malloc(sizeof(*mt->th)*lim); mt->pth = (struct pari_thread *) pari_malloc(sizeof(*mt->pth)*lim); mt->pending = 0; mt->n = lim; mt->nbint = 0; mt->last = 0; pthread_cond_init(&mt->pcond,NULL); pthread_mutex_init(&mt->pmut,NULL); pari_thread_sync(); for (i=0;imq+i; mq->no = i; mq->avma = 0; mq->mainstack = NULL; mq->worker = worker; mq->input = NULL; mq->output = NULL; mq->pcond = &mt->pcond; mq->pmut = &mt->pmut; pthread_cond_init(&mq->cond,NULL); pthread_mutex_init(&mq->mut,NULL); if (mtparisizemax) pari_thread_valloc(&mt->pth[i],mtparisize,mtparisizemax,(GEN)mq); else pari_thread_alloc(&mt->pth[i],mtparisize,(GEN)mq); } if (DEBUGLEVEL) pari_warn(warner,"starting %ld threads", lim); BLOCK_SIGINT_START for (i=0;ith[i],NULL, &mt_queue_run, (void*)&mt->pth[i]); pari_mt = mt; BLOCK_SIGINT_END pt->get=&mtpthread_queue_get; pt->submit=&mtpthread_queue_submit; pt->end=&mt_queue_reset; } } pari-2.11.2/src/mt/mt.c0000644000175000017500000000352313326135265013162 0ustar billbill/* $Id$ Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "pari.h" #include "paripriv.h" #include "mt.h" static GEN mtsingle_queue_get(struct mt_state *mt, long *workid, long *pending) { GEN done = mt->pending; if (workid) *workid = mt->workid; mt->pending = NULL; *pending = 0; return done; } static void mtsingle_queue_submit(struct mt_state *mt, long workid, GEN work) { mt->pending = work? closure_callgenvec(mt->worker, work): NULL; mt->workid = workid; } static void mtsingle_queue_end(void) { } void mtsingle_queue_start(struct pari_mt *pt, GEN worker) { pt->get = mtsingle_queue_get; pt->submit = mtsingle_queue_submit; pt->end = mtsingle_queue_end; pt->mt.worker = worker; pt->mt.pending = NULL; } void mt_queue_end(struct pari_mt *pt) { pt->end(); } void mt_queue_submit(struct pari_mt *pt, long workid, GEN work) { pt->submit(&pt->mt, workid, work); } GEN mt_queue_get(struct pari_mt *pt, long *workid, long *pending) { return pt->get(&pt->mt, workid, pending); } void mt_queue_start(struct pari_mt *pt, GEN worker) { return mt_queue_start_lim(pt, worker, 0); } void mtstate_save(long *pending) { *pending = mt_is_parallel(); } void mtstate_restore(long *pending) { if (!*pending && mt_is_parallel()) mt_queue_reset(); } void mtstate_reset(void) { if (mt_is_parallel()) mt_queue_reset(); } pari-2.11.2/src/gp/0000755000175000017500000000000013461316051012353 5ustar billbillpari-2.11.2/src/gp/texmacs.c0000644000175000017500000001356313326135265014201 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* TEXMACS-SPECIFIC STUFF */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" #include "gp.h" #define DATA_BEGIN ((char) 2) #define DATA_END ((char) 5) #define DATA_ESCAPE ((char) 27) /*******************************************************************/ /* */ /* READLINE INTERFACE */ /* */ /*******************************************************************/ #ifdef READLINE static pari_rl_interface pari_rl; #endif static int did_complete = 0; #ifdef READLINE BEGINEXTERN #include ENDEXTERN static void print_escape_string(char *s) { long l = strlen(s); char *t, *t0 = (char*)pari_malloc(l * 3 + 3); t = t0; *t++ = '"'; for ( ;*s; *t++ = *s++) switch(*s) { case DATA_BEGIN: case DATA_END: case DATA_ESCAPE: *t++ = DATA_ESCAPE; continue; case '\\': case '"': *t++ = '\\'; continue; } *t++ = '"'; *t = '\0'; puts(t0); pari_free(t0); } /* completion required, cursor on s + pos. Complete wrt strict left prefix */ static void tm_completion(const char *s, long pos) { char **matches, *text; long w; matches = pari_completion_matches(&pari_rl, s, pos, &w); text = *pari_rl.line_buffer + w; printf("%cscheme:(tuple",DATA_BEGIN); if (matches) { long i, prelen = (rl_line_buffer+pos) - text; char *t = (char*)pari_malloc(prelen+1); strncpy(t, text, prelen); t[prelen] = 0; /* prefix */ printf(" "); print_escape_string(t); pari_free(t); for (i = matches[1]? 1: 0; matches[i]; i++) { printf(" "); print_escape_string(matches[i] + prelen); pari_free(matches[i]); } pari_free(matches); } printf(")%c", DATA_END); fflush(stdout); } #else /* no-op */ static void tm_completion(const char *s, long pos) { (void)s; (void)pos; } #endif typedef struct { char *cmd; long n; /* number of args */ char **v; /* args */ } tm_cmd; static void tm_parse_command(tm_cmd *c, const char *ch) { long l = strlen(ch); char *t, *s = (char*)ch, *send = s+l-1; char **A; pari_stack s_A; if (*s != DATA_BEGIN || *send-- != DATA_END) pari_err(e_MISC, "missing DATA_[BEGIN | END] in TeXmacs command"); s++; if (strncmp(s, "special:", 8)) pari_err(e_MISC, "unrecognized TeXmacs command"); s += 8; if (*s != '(' || *send-- != ')') pari_err(e_MISC, "missing enclosing parentheses for TeXmacs command"); s++; t = s; pari_skip_alpha(&s); c->cmd = pari_strndup(t, s - t); pari_stack_init(&s_A,sizeof(*A),(void**)&A); for (c->n = 0; s <= send; c->n++) { char *u = (char*)pari_malloc(strlen(s) + 1); pari_skip_space(&s); if (*s == '"') s = pari_translate_string(s, u, t); else { /* read integer */ t = s; while (isdigit((int)*s)) s++; strncpy(u, t, s - t); u[s-t] = 0; } pari_stack_pushp(&s_A, u); } c->v = A; } static void tm_free_cmd(tm_cmd *c) { while (c->n--) pari_free((void*)c->v[c->n]); pari_free((void*)c->v); } static void tm_handle_command(const char *s) { tm_cmd c; tm_parse_command(&c, s); if (strcmp(c.cmd, "complete")) pari_err(e_MISC,"Texmacs command %s not implemented", c.cmd); if (c.n != 2) pari_err(e_MISC,"was expecting 2 arguments for Texmacs command"); tm_completion(c.v[0], atol(c.v[1])); tm_free_cmd(&c); did_complete = 1; } /****/ int tm_is_interactive(void) { return 0; } static int tm_is_waiting = 0; /* tell TeXmacs GP will start outputing data */ void tm_start_output(void) { if (!tm_is_waiting) { printf("%cverbatim:",DATA_BEGIN); fflush(stdout); } tm_is_waiting = 1; } /* tell TeXmacs GP is done and is waiting for new data */ void tm_end_output(void) { if (tm_is_waiting) { printf("%c", DATA_END); fflush(stdout); } tm_is_waiting = 0; } char * tm_fgets(char *s, int n, FILE *f) { if (!did_complete) { /* we need input */ tm_start_output(); tm_end_output(); } return fgets(s,n,f); } int tm_get_line(const char *prompt, const char *prompt_cont, filtre_t *F) { int res = get_line_from_file(prompt, F, pari_infile); (void)prompt_cont; if (res) { char *s = F->buf->buf; did_complete = 0; if (pari_infile == stdin && *s == DATA_BEGIN) { tm_handle_command(s); *s = 0; } else tm_start_output(); } return res; } void tm_output(GEN z) { char *sz = GENtoTeXstr(z); printf("%clatex:", DATA_BEGIN); printf("\\magenta\\%%%lu = ", GP_DATA->hist->total); printf("$\\blue %s$%c", sz,DATA_END); pari_free(sz); fflush(stdout); pari_flush(); } void init_texmacs(void) { #ifdef READLINE printf("%ccommand:(cas-supports-completions-set! \"pari\")%c\n", DATA_BEGIN, DATA_END); pari_use_readline(pari_rl); #endif cb_pari_fgets_interactive = tm_fgets; cb_pari_get_line_interactive = tm_get_line; cb_pari_start_output = tm_start_output; cb_pari_end_output = tm_end_output; cb_pari_is_interactive = tm_is_interactive; cb_gp_output = tm_output; disable_color = 1; tm_start_output(); } pari-2.11.2/src/gp/gp_init.h0000644000175000017500000000164213457701146014170 0ustar billbill/* This file is autogenerated from the database. */ /* See src/desc/gen_proto */ /* Do not edit*/ entree functions_gp[]={ {"breakpoint",0,(void*)pari_breakpoint,1,"v","breakpoint(): interrupt the program and enter the breakloop. The program continues when the breakloop is exited."}, {"dbg_down",0,(void*)dbg_down,1,"vD1,L,","dbg_down({n=1}): (break loop) go down n frames. Cancel a previous dbg_up."}, {"dbg_err",0,(void*)dbg_err,1,"","dbg_err(): (break loop) return the error data of the current error, if any."}, {"dbg_up",0,(void*)dbg_up,1,"vD1,L,","dbg_up({n=1}): (break loop) go up n frames. Allow to inspect data of the parent function."}, {"quit",0,(void*)gp_quit,1,"vD0,L,","quit({status = 0}): quit, return to the system with exit status 'status'."}, {"whatnow",0,(void*)whatnow0,1,"vr","whatnow(key): if key was present in GP version 1.39.15, gives the new function name."}, {NULL,0,NULL,0,NULL,NULL} /* sentinel */ }; pari-2.11.2/src/gp/gp.h0000644000175000017500000000265513326135265013150 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*************************************************************************/ /* */ /* GP-SPECIFIC DECLARATIONS */ /* */ /*************************************************************************/ BEGINEXTERN void init_emacs(void); void init_readline(void); void init_texmacs(void); /* gp specific routines */ void dbg_down(long k); void dbg_up(long k); GEN dbg_err(void); void gp_quit(long exitcode); void pari_breakpoint(void); int whatnow(PariOUT *out, const char *s, int silent); extern void (*cb_gp_output)(GEN z); extern void (*cb_pari_end_output)(void); extern entree functions_gp[]; /* architecture-dependent plot files (src/graph/plot*.c) */ void gp_get_plot(PARI_plot *T); ENDEXTERN pari-2.11.2/src/gp/gp.c0000644000175000017500000004221213326135265013134 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /** **/ /** PARI CALCULATOR **/ /** **/ /*******************************************************************/ #ifdef _WIN32 # include "../systems/mingw/pwinver.h" # include # include "../systems/mingw/mingw.h" #endif #include "pari.h" #include "paripriv.h" #include "gp.h" static jmp_buf *env; static pari_stack s_env; void (*cb_gp_output)(GEN z) = NULL; void (*cb_pari_end_output)(void) = NULL; static void gp_ask_confirm(const char *s) { err_printf(s); err_printf(". OK ? (^C if not)\n"); pari_hit_return(); } /* numerr < 0: from SIGINT */ static void gp_err_recover(long numerr) { longjmp(env[s_env.n-1], numerr); } /* numerr < 0: from SIGINT */ static void gp_pre_recover(long numerr) { if (numerr>=0) { out_puts(pariErr, "\n"); pariErr->flush(); } longjmp(env[s_env.n-1], numerr); } static void reset_ctrlc(void) { #if defined(_WIN32) || defined(__CYGWIN32__) win32ctrlc = 0; #endif } static int is_silent(char *s) { return s[strlen(s) - 1] == ';'; } static int stdin_isatty = 0; static int is_interactive(void) { return pari_infile == stdin && stdin_isatty; } /*******************************************************************/ /** **/ /** INITIALIZATION **/ /** **/ /*******************************************************************/ static void print_shortversion(void) { const ulong mask = (1UL<>= PARI_VERSION_SHIFT; minor = n & mask; n >>= PARI_VERSION_SHIFT; major = n; printf("%lu.%lu.%lu\n", major,minor,patch); exit(0); } static void usage(char *s) { printf("### Usage: %s [options] [GP files]\n", s); printf("Available options:\n"); printf(" [-f,--fast]\t\tFast start: do not read .gprc\n"); printf(" [-q,--quiet]\t\tQuiet mode: do not print banner and history numbers\n"); printf(" [-s stacksize]\tStart with the PARI stack of given size (in bytes)\n"); printf(" [--default key=val]\tExecute default(key,val) on startup\n"); printf(" [--emacs]\t\tRun as if in Emacs shell\n"); printf(" [--help]\t\tPrint this message\n"); printf(" [--test]\t\tTest mode. No history, wrap long lines (bench only)\n"); printf(" [--texmacs]\t\tRun as if using TeXmacs frontend\n"); printf(" [--version]\t\tOutput version info and exit\n"); printf(" [--version-short]\tOutput version number and exit\n\n"); exit(0); } static void gp_head(void) { pari_print_version(); pari_putc('\n'); pari_center("Copyright (C) 2000-2018 The PARI Group"); pari_putc('\n'); print_text("PARI/GP is free software, covered by the GNU General Public \ License, and comes WITHOUT ANY WARRANTY WHATSOEVER."); pari_puts("\nType ? for help, \\q to quit.\n"); pari_printf("Type ?%d for how to get moral" " (and possibly technical) support.\n", pari_community()); if (pari_mainstack->vsize) pari_printf("\nparisizemax = %lu, primelimit = %lu", pari_mainstack->vsize,GP_DATA->primelimit); else pari_printf("\nparisize = %lu, primelimit = %lu", pari_mainstack->rsize,GP_DATA->primelimit); if (pari_mt_nbthreads > 1) pari_printf(", nbthreads = %lu", pari_mt_nbthreads); pari_putc('\n'); } static char * read_arg(long *nread, char *t, long argc, char **argv) { long i = *nread; if (isdigit((int)*t)) return t; if (*t || i==argc) usage(argv[0]); *nread = i+1; return argv[i]; } static char * read_arg_equal(long *nread, char *t, long argc, char **argv) { long i = *nread; if (*t=='=' && isdigit((int)t[1])) return t+1; if (*t || i==argc) usage(argv[0]); *nread = i+1; return argv[i]; } static void init_trivial_stack(void) { const size_t s = 2048; pari_mainstack->size = s; pari_mainstack->bot = (pari_sp)pari_malloc(s); avma = pari_mainstack->top = pari_mainstack->bot + s; } static void free_trivial_stack(void) { free((void*)pari_mainstack->bot); } typedef struct { char *key, *val; } pair_t; /* If ab of the form key=val, record pair in new stack entry * P[n].key must be freed by caller to avoid memory leak */ static void record_default(pari_stack *s_P, char *ab) { pair_t *P = (pair_t*)*pari_stack_base(s_P); char *k, *v; long n; ab = pari_strdup(ab); parse_key_val(ab, &k, &v); n = pari_stack_new(s_P); P[n].key = k; P[n].val = v; } static void read_opt(pari_stack *p_A, long argc, char **argv) { pair_t *P; pari_stack s_P; /* key / value to record default() settings */ char *b = NULL, *p = NULL, *s = NULL; ulong f = GP_DATA->flags; long i = 1, initrc = 1; (void)&p; (void)&b; (void)&s; /* -Wall gcc-2.95 */ pari_stack_init(&s_P,sizeof(*P),(void**)&P); pari_stack_alloc(&s_P, 64); pari_outfile = stderr; while (i < argc) { char *t = argv[i]; if (*t++ != '-') break; i++; START: switch(*t++) { case 'p': p = read_arg(&i,t,argc,argv); break; case 's': s = read_arg(&i,t,argc,argv); break; case 'e': f |= gpd_EMACS; if (*t) goto START; break; case 'q': f |= gpd_QUIET; if (*t) goto START; break; case 't': f |= gpd_TEST; if (*t) goto START; break; case 'f': initrc = 0; if (*t) goto START; break; case 'D': if (*t || i == argc) usage(argv[0]); record_default(&s_P, argv[i++]); break; case '-': if (strcmp(t, "version-short") == 0) { print_shortversion(); exit(0); } if (strcmp(t, "version") == 0) { init_trivial_stack(); pari_print_version(); free_trivial_stack(); exit(0); } if (strcmp(t, "default") == 0) { if (i == argc) usage(argv[0]); record_default(&s_P, argv[i++]); break; } if (strcmp(t, "texmacs") == 0) { f |= gpd_TEXMACS; break; } if (strcmp(t, "emacs") == 0) { f |= gpd_EMACS; break; } if (strcmp(t, "test") == 0) { f |= gpd_TEST; initrc = 0; break; } if (strcmp(t, "quiet") == 0) { f |= gpd_QUIET; break; } if (strcmp(t, "fast") == 0) { initrc = 0; break; } if (strncmp(t, "primelimit",10) == 0) {p = read_arg_equal(&i,t+10,argc,argv); break; } if (strncmp(t, "stacksize",9) == 0) {s = read_arg_equal(&i,t+9,argc,argv); break; } /* fall through */ default: usage(argv[0]); } } if (f & gpd_TEST) stdin_isatty = 0; GP_DATA->flags = f; #ifdef READLINE GP_DATA->use_readline = stdin_isatty; #endif if (!is_interactive()) GP_DATA->breakloop = 0; if (initrc) gp_initrc(p_A); for ( ; i < argc; i++) pari_stack_pushp(p_A, pari_strdup(argv[i])); /* override the values from gprc */ if (p) (void)sd_primelimit(p, d_INITRC); if (s) (void)sd_parisize(s, d_INITRC); for (i = 0; i < s_P.n; i++) { setdefault(P[i].key, P[i].val, d_INITRC); free((void*)P[i].key); } pari_stack_delete(&s_P); pari_outfile = stdout; } /*******************************************************************/ /** **/ /** TEST MODE **/ /** **/ /*******************************************************************/ static int test_is_interactive(void) { return 0; } static void test_output(GEN z) { init_linewrap(76); gen_output(z); } void init_test(void) { disable_color = 1; init_linewrap(76); pari_errfile = stdout; cb_gp_output = test_output; cb_pari_is_interactive = test_is_interactive; } /*******************************************************************/ /** **/ /** FORMAT GP OUTPUT **/ /** **/ /*******************************************************************/ /* REGULAR */ static void normal_output(GEN z, long n) { long l = 0; char *s; /* history number */ if (n) { char buf[64]; if (!(GP_DATA->flags & gpd_QUIET)) { term_color(c_HIST); sprintf(buf, "%%%ld = ", n); pari_puts(buf); l = strlen(buf); } } /* output */ term_color(c_OUTPUT); s = GENtostr(z); if (GP_DATA->lim_lines) lim_lines_output(s, l, GP_DATA->lim_lines); else pari_puts(s); pari_free(s); term_color(c_NONE); pari_putc('\n'); } static void gp_output(GEN z) { if (cb_gp_output) { cb_gp_output(z); return; } if (GP_DATA->fmt->prettyp == f_PRETTY) { if (tex2mail_output(z, GP_DATA->hist->total)) return; } normal_output(z, GP_DATA->hist->total); pari_flush(); } static GEN gp_main_loop(long ismain) { VOLATILE GEN z = gnil; VOLATILE long t = 0; VOLATILE pari_sp av = avma; filtre_t F; Buffer *b = filtered_buffer(&F); struct gp_context rec; long er; if ((er = setjmp(env[s_env.n-1]))) { /* recover: jump from error [ > 0 ] or allocatemem [ -1 ] */ if (er > 0) { /* true error */ if (!(GP_DATA->recover)) exit(1); gp_context_restore(&rec); /* true error not from main instance, let caller sort it out */ if (!ismain) { kill_buffers_upto_including(b); return NULL; } } else { /* allocatemem */ tmp_restore(rec.file.file); gp_context_save(&rec); } avma = av = pari_mainstack->top; parivstack_reset(); kill_buffers_upto(b); pari_alarm(0); } for(;;) { gp_context_save(&rec); if (! gp_read_line(&F, NULL)) { if (popinfile()) gp_quit(0); if (ismain) continue; pop_buffer(); return z; } if (ismain) { reset_ctrlc(); timer_start(GP_DATA->T); pari_set_last_newline(1); } if (gp_meta(b->buf,ismain)) continue; z = pari_compile_str(b->buf); z = closure_evalres(z); if (!ismain) continue; t = timer_delay(GP_DATA->T); if (!pari_last_was_newline()) pari_putc('\n'); pari_alarm(0); if (t && GP_DATA->chrono) { pari_puts("time = "); pari_puts(gp_format_time(t)); } if (GP_DATA->simplify) z = simplify_shallow(z); pari_add_hist(z, t); if (z != gnil && ! is_silent(b->buf) ) gp_output(z); avma = av; parivstack_reset(); } } /* as gp_read_file, before running the main gp instance */ static void read_main(const char *s) { GEN z; if (setjmp(env[s_env.n-1])) z = NULL; else { FILE *f = switchin(s); if (file_is_binary(f)) { z = readbin(s,f, NULL); popinfile(); } else z = gp_main_loop(0); } if (!z) err_printf("... skipping file '%s'\n", s); avma = pari_mainstack->top; } static const char * break_loop_prompt(long n) { const char *s = (n==1)? "break> ": stack_sprintf("break[%ld]> ", n); return gp_format_prompt(s); } static long frame_level=0, dbg_level = 0; static int break_loop(int numerr) { filtre_t F; Buffer *b; int sigint = numerr<0, go_on = sigint; struct gp_context rec1, rec2; const char *prompt, *msg; long nenv, oldframe_level = frame_level; pari_sp av; if (numerr == e_SYNTAX) return 0; if (numerr == e_STACK) { evalstate_clone(); avma = pari_mainstack->top; } gp_context_save(&rec1); b = filtered_buffer(&F); nenv=pari_stack_new(&s_env); prompt = break_loop_prompt(s_env.n-1); iferr_env = NULL; dbg_level = 0; frame_level = closure_context(oldframe_level, dbg_level); pari_infile = newfile(stdin, "stdin", mf_IN)->file; term_color(c_ERR); pari_putc('\n'); if (sigint) msg = "Break loop: to continue; 'break' to go back to GP prompt"; else msg = "Break loop: type 'break' to go back to GP prompt"; print_errcontext(pariOut, msg, NULL, NULL); term_color(c_NONE); av = avma; for(;;) { GEN x; long er, br_status; avma = av; gp_context_save(&rec2); if ((er=setjmp(env[nenv]))) { if (er < 0) { s_env.n = 1; frame_level = oldframe_level; longjmp(env[s_env.n-1], er); } gp_context_restore(&rec2); iferr_env = NULL; closure_err(dbg_level); compilestate_restore(&rec1.eval.comp); (void) closure_context(oldframe_level, dbg_level); pari_infile = newfile(stdin, "stdin", mf_IN)->file; } term_color(c_NONE); if (!gp_read_line(&F, prompt)) br_status = br_BREAK; /* EOF */ else { /* Empty input ? Continue if entry on sigint (exit debugger frame) */ if (! *(b->buf) && sigint) break; reset_ctrlc(); if (gp_meta(b->buf,0)) continue; x = pari_compile_str(b->buf); x = closure_evalbrk(x, &br_status); } switch (br_status) { case br_NEXT: case br_MULTINEXT: popinfile(); /* exit frame. Don't exit debugger if s_env.n > 2 */ go_on = 0; goto BR_EXIT; case br_BREAK: case br_RETURN: killallfiles(); /* completely exit the debugger */ go_on = 0; goto BR_EXIT; } if (x!=gnil && !is_silent(b->buf)) { term_color(c_OUTPUT); gen_output(x); } } BR_EXIT: s_env.n=nenv; frame_level = oldframe_level; gp_context_restore(&rec1); pop_buffer(); return go_on; } #ifdef __CYGWIN32__ void cyg_environment(int argc, char ** argv) { char *ti_dirs = getenv("TERMINFO_DIRS"); char *argv0, *p; char *newdir; long n; if (!argc || !argv) return; argv0 = *argv; if (!argv0 || !*argv0) return; p = strrchr(argv0, '/'); if (!p) p = argv0 = ""; else p++; n = p - argv0; if (ti_dirs) { n += 14 + strlen(ti_dirs) + 1 + 8 + 1; newdir = malloc(n); if (!newdir) return; snprintf(newdir, n-8, "TERMINFO_DIRS=%s:%s", ti_dirs, argv0); } else { n += 14 + 8 + 1; newdir = malloc(n); if (!newdir) return; snprintf(newdir, n-8, "TERMINFO_DIRS=%s", argv0); } strcpy(newdir+n-9,"terminfo"); putenv(newdir); } #endif int main(int argc, char **argv) { char **A; pari_stack s_A; GP_DATA = default_gp_data(); pari_stack_init(&s_env, sizeof(*env), (void**)&env); (void)pari_stack_new(&s_env); if (setjmp(env[s_env.n-1])) { puts("### Errors on startup, exiting...\n\n"); exit(1); } #ifdef __CYGWIN32__ cyg_environment(argc, argv); #endif stdin_isatty = pari_stdin_isatty(); pari_init_defaults(); pari_library_path = DL_DFLT_NAME; pari_stack_init(&s_A,sizeof(*A),(void**)&A); pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm); cb_pari_err_recover = gp_err_recover; cb_pari_pre_recover = gp_pre_recover; cb_pari_break_loop = break_loop; cb_pari_is_interactive = is_interactive; read_opt(&s_A, argc,argv); pari_init_primes(GP_DATA->primelimit); #ifdef SIGALRM (void)os_signal(SIGALRM,gp_alarm_handler); #endif pari_add_module(functions_gp); pari_set_plot_engine(gp_get_plot); cb_pari_quit = gp_quit; cb_pari_whatnow = whatnow; cb_pari_sigint = gp_sigint_fun; cb_pari_handle_exception = gp_handle_exception; cb_pari_ask_confirm = gp_ask_confirm; pari_init_paths(); pari_mt_init(); /* MPI: will not return on slaves (pari_MPI_rank = 0) */ #ifdef _WIN32 if (stdin_isatty) win32_set_codepage(); #endif #ifdef READLINE init_readline(); #endif if (GP_DATA->flags & gpd_EMACS) init_emacs(); if (GP_DATA->flags & gpd_TEXMACS) init_texmacs(); timer_start(GP_DATA->T); if (!(GP_DATA->flags & gpd_QUIET)) gp_head(); if (GP_DATA->flags & gpd_TEST) init_test(); if (s_A.n) { FILE *l = pari_logfile; long i; pari_logfile = NULL; for (i = 0; i < s_A.n; pari_free(A[i]),i++) read_main(A[i]); /* Reading one of the input files above can set pari_logfile. * Don't restore in that case. */ if (!pari_logfile) pari_logfile = l; } pari_stack_delete(&s_A); (void)gp_main_loop(1); gp_quit(0); return 0; /* LCOV_EXCL_LINE */ } void pari_breakpoint(void) { if (!pari_last_was_newline()) pari_putc('\n'); closure_err(0); if (cb_pari_break_loop && cb_pari_break_loop(-1)) return; cb_pari_err_recover(e_MISC); } void dbg_down(long k) { if (k<0) k=0; dbg_level -= k; if (dbg_level<0) dbg_level=0; gp_err_recover(e_NONE); } GEN dbg_err(void) { GEN E = pari_err_last(); return E? gcopy(E):gnil; } void dbg_up(long k) { if (k<0) k=0; dbg_level += k; if (dbg_level>frame_level) dbg_level=frame_level; gp_err_recover(e_NONE); } void gp_quit(long code) { pari_kill_plot_engine(); pari_close(); kill_buffers_upto(NULL); if (!(GP_DATA->flags & gpd_QUIET)) pari_puts("Goodbye!\n"); if (cb_pari_end_output) cb_pari_end_output(); exit(code); } void whatnow0(char *s) { whatnow(pariOut, s,0); } #include "gp_init.h" pari-2.11.2/src/gp/whatnow.c0000644000175000017500000000431413455107437014221 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #include "gp.h" #include "whatnow.h" static void msg(PariOUT *out, const char *s) { out_term_color(out, c_HELP); out_print_text(out, s); out_putc(out, '\n'); out_term_color(out, c_NONE); } /* If flag = 0 (default): check if s existed in 1.39.15 and print verbosely * the answer. * Else: return 1 if function changed, 0 otherwise, and print help message * plus the above. */ int whatnow(PariOUT *out, const char *s, int flag) { const char *def; const whatnow_t *wp = whatnowlist; entree *ep; while (wp->old && strcmp(wp->old,s)) wp++; /* Above linear search is slow, esp. if the symbol is not found. BUT no * point in wasting time by preallocating [ or autoloading ] a hashtable: * whatnow() is never used in a case where speed would be necessary */ if (!wp->old) { if (!flag) msg(out, "As far as I can recall, this function never existed"); return 0; } def = wp->name; if (def == SAME) { if (!flag) msg(out, "This function did not change"); return 0; } if (flag) { out_term_color(out, c_NONE); out_print_text(out, "\nA function with that name existed in GP-1.39.15. Please update your script."); out_putc(out, '\n'); } if (def == REMOV) { msg(out, "This function no longer exists"); return 0; } /* special case compimag -> x*y */ if (!strcmp(def,"x*y")) def = "_*_"; ep = is_entry(def); if (!ep) pari_err_BUG("whatnow"); out_puts(out, "New syntax: "); out_term_color(out, c_ERR); out_printf(out, "%s%s ===> %s%s\n\n", s, wp->oldarg, wp->name, wp->newarg); msg(out, ep->help); out_term_color(out, c_NONE); return 1; } pari-2.11.2/src/gp/gp_rl.c0000644000175000017500000003070213326135265013632 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* INTERFACE TO READLINE COMPLETION */ /* */ /*******************************************************************/ #include "pari.h" #ifdef READLINE #include "paripriv.h" #include "gp.h" typedef int (*RLCI)(int, int); /* rl_complete and rl_insert functions */ BEGINEXTERN /* otherwise C++ compilers will choke on rl_message() prototype */ #define USE_VARARGS #define PREFER_STDARG #include #include ENDEXTERN /**************************************************************************/ static pari_rl_interface pari_rl; static int did_init_matched = 0; static int change_state(const char *msg, ulong flag, int count) { int c = (GP_DATA->readline_state & flag) != 0; ulong state = GP_DATA->readline_state; switch(count) { default: c = 0; break; /* off */ case -1: c = 1; break; /* on */ case -2: c = 1 - c; /* toggle */ } if (c) GP_DATA->readline_state |= flag; else { GP_DATA->readline_state &= ~flag; if (!GP_DATA->readline_state && state) GP_DATA->readline_state = 1; } rl_save_prompt(); rl_message("[%s: %s] ", msg, c? "on": "off"); c = rl_read_key(); rl_restore_prompt(); rl_clear_message(); rl_stuff_char(c); return 1; } /* Wrapper around rl_complete to allow toggling insertion of arguments */ static int pari_rl_complete(int count, int key) { int ret; pari_rl.back = 0; if (count <= 0) return change_state("complete args", DO_ARGS_COMPLETE, count); rl_begin_undo_group(); if (rl_last_func == pari_rl_complete) rl_last_func = (RLCI) rl_complete; /* Make repeated TABs different */ ret = ((RLCI)rl_complete)(count,key); if (pari_rl.back && (pari_rl.back <= rl_point)) rl_point -= pari_rl.back; rl_end_undo_group(); return ret; } static int did_matched_insert; static int pari_rl_matched_insert_suspend(int count, int key) { ulong state = GP_DATA->readline_state; (void)count; (void)key; did_matched_insert = (GP_DATA->readline_state & DO_MATCHED_INSERT); GP_DATA->readline_state &= ~DO_MATCHED_INSERT; if (!GP_DATA->readline_state && state) GP_DATA->readline_state = 1; return 1; } static int pari_rl_matched_insert_restore(int count, int key) { (void)count; (void)key; if (did_matched_insert) GP_DATA->readline_state |= DO_MATCHED_INSERT; return 1; } static const char paropen[] = "([{"; static const char parclose[] = ")]}"; /* To allow insertion of () with a point in between. */ static int pari_rl_matched_insert(int count, int key) { int i = 0, ret; if (count <= 0) return change_state("electric parens", DO_MATCHED_INSERT, count); while (paropen[i] && paropen[i] != key) i++; if (!paropen[i] || !(GP_DATA->readline_state & DO_MATCHED_INSERT) || GP_DATA->flags & gpd_EMACS) return ((RLCI)rl_insert)(count,key); rl_begin_undo_group(); ((RLCI)rl_insert)(count,key); ret = ((RLCI)rl_insert)(count,parclose[i]); rl_point -= count; rl_end_undo_group(); return ret; } static int pari_rl_default_matched_insert(int count, int key) { if (!did_init_matched) { did_init_matched = 1; GP_DATA->readline_state |= DO_MATCHED_INSERT; } return pari_rl_matched_insert(count, key); } static int pari_rl_forward_sexp(int count, int key) { int deep = 0, dir = 1, move_point = 0, lfail; (void)key; if (count < 0) { count = -count; dir = -1; if (!rl_point) goto fail; rl_point--; } while (count || deep) { move_point = 1; /* Need to move point if moving left. */ lfail = 0; /* Do not need to fail left movement yet. */ while ( !is_keyword_char(rl_line_buffer[rl_point]) && !strchr("\"([{}])",rl_line_buffer[rl_point]) && !( (dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0 && (lfail = 1)))) rl_point += dir; if (lfail || !rl_line_buffer[rl_point]) goto fail; if (is_keyword_char(rl_line_buffer[rl_point])) { while ( is_keyword_char(rl_line_buffer[rl_point]) && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0 && (lfail = 1))) || (move_point = 0))) rl_point += dir; if (deep && lfail) goto fail; if (!deep) count--; } else if (strchr(paropen,rl_line_buffer[rl_point])) { if (deep == 0 && dir == -1) goto fail; /* We are already out of pars. */ rl_point += dir; deep++; if (!deep) count--; } else if (strchr(parclose,rl_line_buffer[rl_point])) { if (deep == 0 && dir == 1) { rl_point++; goto fail; /* Get out of pars. */ } rl_point += dir; deep--; if (!deep) count--; } else if (rl_line_buffer[rl_point] == '\"') { int bad = 1; rl_point += dir; while ( ((rl_line_buffer[rl_point] != '\"') || (bad = 0)) && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0)) || (move_point = 0)) ) rl_point += dir; if (bad) goto fail; rl_point += dir; /* Skip the other delimiter */ if (!deep) count--; } else { fail: rl_ding(); return 1; } } if (dir != 1 && move_point) rl_point++; return 1; } static int pari_rl_backward_sexp(int count, int key) { return pari_rl_forward_sexp(-count, key); } static void rl_print_aide(char *s, int flag) { int p = rl_point, e = rl_end; FILE *save = pari_outfile; rl_point = 0; rl_end = 0; pari_outfile = rl_outstream; rl_save_prompt(); rl_message("%s",""); /* rl_message("") ==> "zero length format" warning */ gp_help(s, flag); rl_restore_prompt(); rl_point = p; rl_end = e; pari_outfile = save; rl_clear_message(); rl_refresh_line(0,0); } /* long help if count < 0 */ static int rl_short_help(int count, int key) { int flag = h_RL; char *s = rl_line_buffer + rl_point; (void)key; /* func() with cursor on ')', e.g. following completion */ if (s > rl_line_buffer && *s == ')' && s[-1] == '(') s--; while (s > rl_line_buffer && is_keyword_char(s[-1])) s--; /* check for '\c' */ if (s > rl_line_buffer && s[-1] == '\\') s--; if (count < 0 || rl_last_func == rl_short_help) flag |= h_LONG; rl_print_aide(s, flag); return 0; } static int rl_long_help(int count, int key) { (void)count; return rl_short_help(-1,key); } static void init_histfile(void) { char *h = GP_DATA->histfile; if (h && read_history(h)) write_history(h); } /*******************************************************************/ /* */ /* GET LINE FROM READLINE */ /* */ /*******************************************************************/ static int history_is_new(char *s) { HIST_ENTRY *e; if (!*s) return 0; if (!history_length) return 1; e = history_get(history_length); /* paranoia: e != NULL, unless readline is in a weird state */ return e? strcmp(s, e->line): 0; } static void gp_add_history(char *s) { if (history_is_new(s)) { add_history(s); append_history(1,GP_DATA->histfile); } } /* Read line; returns a malloc()ed string of the user input or NULL on EOF. Increments the buffer size appropriately if needed; fix *endp if so. */ static char * gprl_input(char **endp, int first, input_method *IM, filtre_t *F) { pari_sp av = avma; Buffer *b = F->buf; ulong used = *endp - b->buf; ulong left = b->len - used, l; const char *p; char *s, *t; if (first) p = IM->prompt; else { p = F->in_comment ? GP_DATA->prompt_comment: IM->prompt_cont; p = gp_format_prompt(p); } if (! (s = readline(p)) ) { avma = av; return NULL; } /* EOF */ gp_add_history(s); /* Makes a copy */ l = strlen(s) + 1; /* put back \n that readline stripped. This is needed for * { print("a * b"); } * and conforms with the other input methods anyway. */ t = (char*)pari_malloc(l + 1); memcpy(t, s, l-1); t[l-1] = '\n'; t[l] = 0; /* equivalent to sprintf(t,"%s\n", s) */ if (left < l) { ulong incr = b->len; if (incr < l) incr = l; fix_buffer(b, b->len + incr); *endp = b->buf + used; } avma = av; return t; } /* request one line interactively. * Return 0: EOF * 1: got one line from readline or pari_infile */ int get_line_from_readline(const char *prompt, const char *prompt_cont, filtre_t *F) { const int index = history_length; char *s; input_method IM; if (!GP_DATA->use_readline) { pari_puts(prompt); pari_flush(); return get_line_from_file(prompt, F, pari_infile); } IM.prompt = prompt; IM.prompt_cont = prompt_cont; IM.getline = &gprl_input; IM.free = 1; if (! input_loop(F,&IM)) { pari_puts("\n"); return 0; } s = F->buf->buf; if (*s) { if (history_length > index+1) { /* Multi-line input. Remove incomplete lines */ int i = history_length; while (i > index) { HIST_ENTRY *e = remove_history(--i); pari_free(e->line); pari_free(e); } gp_add_history(s); } gp_echo_and_log(prompt, s); } return 1; } static char** gp_completion(char *text, int START, int END) { return pari_completion(&pari_rl, text, START, END); } void init_readline(void) { static int init_done = 0; if (init_done) return; pari_use_readline(pari_rl); if (! GP_DATA->use_readline) GP_DATA->readline_state = 0; init_done = 1; init_histfile(); cb_pari_init_histfile = init_histfile; cb_pari_get_line_interactive = get_line_from_readline; /* Allow conditional parsing of the ~/.inputrc file. */ rl_readline_name = "Pari-GP"; /* added ~, ? and , */ rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(?~"; rl_special_prefixes = "~"; /* custom completer */ rl_attempted_completion_function = (rl_completion_func_t*) gp_completion; /* we always want the whole list of completions under emacs */ if (GP_DATA->flags & gpd_EMACS) rl_completion_query_items = 0x8fff; rl_add_defun("short-help", rl_short_help, -1); rl_add_defun("long-help", rl_long_help, -1); rl_add_defun("pari-complete", pari_rl_complete, '\t'); rl_add_defun("pari-matched-insert", pari_rl_default_matched_insert, -1); rl_add_defun("pari-matched-insert-suspend", pari_rl_matched_insert_suspend, -1); rl_add_defun("pari-matched-insert-restore", pari_rl_matched_insert_restore, -1); rl_add_defun("pari-forward-sexp", pari_rl_forward_sexp, -1); rl_add_defun("pari-backward-sexp", pari_rl_backward_sexp, -1); rl_bind_key_in_map('h', rl_short_help, emacs_meta_keymap); rl_bind_key_in_map('H', rl_long_help, emacs_meta_keymap); #define KSbind(s,f,k) rl_generic_bind(ISFUNC, (s), (char*)(f), (k)) KSbind("OP", rl_short_help, emacs_meta_keymap); /* f1, vt100 */ KSbind("[11~", rl_short_help, emacs_meta_keymap); /* f1, xterm */ KSbind("OP", rl_short_help, vi_movement_keymap); /* f1, vt100 */ KSbind("[11~", rl_short_help, vi_movement_keymap); /* f1, xterm */ /* XTerm may signal start/end of paste by emitting F200/F201 * TODO: check to what extent this patch has been applied */ /* FIXME: For vi mode something more intelligent is needed - to switch to the insert mode - and back when restoring. */ KSbind("[200~", pari_rl_matched_insert_suspend, emacs_meta_keymap); /* pre-paste xterm */ KSbind("[200~", pari_rl_matched_insert_suspend, vi_movement_keymap); /* pre-paste xterm */ KSbind("[201~", pari_rl_matched_insert_restore, emacs_meta_keymap); /* post-paste xterm */ KSbind("[201~", pari_rl_matched_insert_restore, vi_movement_keymap); /* post-paste xterm */ rl_bind_key_in_map('(', pari_rl_matched_insert, emacs_standard_keymap); rl_bind_key_in_map('[', pari_rl_matched_insert, emacs_standard_keymap); rl_bind_key_in_map(6, pari_rl_forward_sexp, emacs_meta_keymap); /* M-C-f */ rl_bind_key_in_map(2, pari_rl_backward_sexp, emacs_meta_keymap); /* M-C-b */ } #endif pari-2.11.2/src/gp/whatnow.h0000644000175000017500000005151513326135265014230 0ustar billbilltypedef struct whatnow_t { const char *old, *name, *oldarg, *newarg; } whatnow_t; #define SAME NULL #define REMOV (char *)1L #define _REMOV REMOV,NULL,NULL #define _SAME SAME,NULL,NULL static const whatnow_t whatnowlist[]={ {"!_",_SAME}, {"#_",_SAME}, {"%",_SAME}, {"+_",_SAME}, {"-_",_SAME}, {"_!",_SAME}, {"_!=_",_SAME}, {"_%=_",_SAME}, {"_%_",_SAME}, {"_&&_",_SAME}, {"_'",_SAME}, {"_*=_",_SAME}, {"_*_",_SAME}, {"_++",_SAME}, {"_+=_",_SAME}, {"_+_",_SAME}, {"_--",_SAME}, {"_-=_",_SAME}, {"_-_",_SAME}, {"_.a1",_SAME}, {"_.a2",_SAME}, {"_.a3",_SAME}, {"_.a4",_SAME}, {"_.a6",_SAME}, {"_.area",_SAME}, {"_.b2",_SAME}, {"_.b4",_SAME}, {"_.b6",_SAME}, {"_.b8",_SAME}, {"_.bid",_SAME}, {"_.bnf",_SAME}, {"_.c4",_SAME}, {"_.c6",_SAME}, {"_.clgp",_SAME}, {"_.codiff",_SAME}, {"_.cyc",_SAME}, {"_.diff",_SAME}, {"_.disc",_SAME}, {"_.e",_SAME}, {"_.eta",_SAME}, {"_.f",_SAME}, {"_.fu",_SAME}, {"_.futu",_SAME}, {"_.gen",_SAME}, {"_.group",_SAME}, {"_.index",_SAME}, {"_.j",_SAME}, {"_.mod",_SAME}, {"_.nf",_SAME}, {"_.no",_SAME}, {"_.omega",_SAME}, {"_.orders",_SAME}, {"_.p",_SAME}, {"_.pol",_SAME}, {"_.r1",_SAME}, {"_.r2",_SAME}, {"_.reg",_SAME}, {"_.roots",_SAME}, {"_.sign",_SAME}, {"_.t2",_SAME}, {"_.tate",_SAME}, {"_.tu",_SAME}, {"_.tufu",_SAME}, {"_.zk",_SAME}, {"_.zkst",_SAME}, {"_/=_",_SAME}, {"_/_",_SAME}, {"_<<=_",_SAME}, {"_<<_",_SAME}, {"_<=_",_SAME}, {"_<_",_SAME}, {"_==_",_SAME}, {"_>=_",_SAME}, {"_>>=_",_SAME}, {"_>>_",_SAME}, {"_>_",_SAME}, {"_[_.._,_.._]",_SAME}, {"_[_.._]",_SAME}, {"_\\/=_",_SAME}, {"_\\/_",_SAME}, {"_\\=_",_SAME}, {"_\\_",_SAME}, {"_^_",_SAME}, {"_^s",_SAME}, {"__",_SAME}, {"_derivfun",_SAME}, {"_eval_mnemonic",_SAME}, {"_multi_if",_SAME}, {"_void_if",_SAME}, {"_||_",_SAME}, {"_~",_SAME}, {"O",_SAME}, {"O(_^_)",_SAME}, {"Str",_SAME}, {"abs",_SAME}, {"acos",_SAME}, {"acosh",_SAME}, {"addell","elladd","(e,z1,z2)","(e,z1,z2)"}, {"addprimes",_SAME}, {"adj","matadjoint","(x)","(x)"}, {"agm",_SAME}, {"akell","ellak","(e,n)","(e,n)"}, {"algdep",_SAME}, {"algdep2","algdep","(x,n,dec)","(x,n,dec)"}, {"algtobasis","nfalgtobasis","(nf,x)","(nf,x)"}, {"anell","ellan","(e,n)","(e,n)"}, {"apell","ellap","(e,n)","(e,n)"}, {"apell2","ellap","(e,n)","(e,n)"}, {"apprpadic","padicappr","(x,a)","(x,a)"}, {"arg",_SAME}, {"asin",_SAME}, {"asinh",_SAME}, {"assmat","matcompanion","(x)","(x)"}, {"atan",_SAME}, {"atanh",_SAME}, {"basis","nfbasis","(x)","(x)"}, {"basis2","nfbasis","(x)","(x,2)"}, {"basistoalg","nfbasistoalg","(nf,x)","(nf,x)"}, {"bernreal",_SAME}, {"bernvec",_SAME}, {"bestappr",_SAME}, {"bezout","gcdext","(a,b)","(a,b)"}, {"bezoutres",_SAME}, {"bigomega",_SAME}, {"bilhell","ellbil","(e,z1,z2)","(e,z1,z2)"}, {"bin","binomial","(x,y)","(x,y)"}, {"binary",_SAME}, {"bittest",_SAME}, {"boundcf","contfrac","(x,lmax)","(x,,lmax)"}, {"boundfact","factor","(x,lim)","(x,lim)"}, {"buchcertify","bnfcertify","(bnf)","(bnf)"}, {"buchfu",_REMOV}, {"buchgen",_REMOV}, {"buchgenforcefu",_REMOV}, {"buchgenfu",_REMOV}, {"buchimag","quadclassunit","(D,c1,c2,g)","(D,,[c1,c2,g])"}, {"buchinit","bnfinit","(P)","(P,2)"}, {"buchinitforcefu","bnfinit","(P)","(P,1)"}, {"buchinitfu","bnfinit","(P)","(P)"}, {"buchnarrow","bnfnarrow","(bnf)","(bnf)"}, {"buchray","bnrinit","(bnf,ideal)","(bnf,ideal)"}, {"buchrayinit","bnrinit","(bnf,ideal)","(bnf,ideal)"}, {"buchrayinitgen","bnrinit","(bnf,ideal)","(bnf,ideal,1)"}, {"buchreal","quadclassunit","(D)","(D)"}, {"bytesize","sizebyte","(x)","(x)"}, {"ceil",_SAME}, {"centerlift",_SAME}, {"cf","contfrac","(x)","(x)"}, {"cf2","contfrac","(b,x)","(x,b)"}, {"changevar",_REMOV}, {"char","charpoly","(x,y)","(x,y)"}, {"char1","charpoly","(x,y)","(x,y,1)"}, {"char2","charpoly","(x,y)","(x,y,2)"}, {"chell","ellchangecurve","(x,y)","(x,y)"}, {"chinese",_SAME}, {"chptell","ellchangepoint","(x,y)","(x,y)"}, {"classno","qfbclassno","(x)","(x)"}, {"classno2","qfbclassno","(x)","(x,1)"}, {"coeff","polcoeff","(x,s)","(x,s)"}, {"compimag","x*y","(x,y)",""}, {"compo","component","(x,s)","(x,s)"}, {"compositum","polcompositum","(pol1,pol2)","(pol1,pol2)"}, {"compositum2","polcompositum","(pol1,pol2)","(pol1,pol2,1)"}, {"comprealraw","qfbcompraw","(x,y)","(x,y)"}, {"concat",_SAME}, {"conductor","bnrconductor","(a1)","(a1)"}, {"conductorofchar","bnrconductorofchar","(bnr,chi)","(bnr,chi)"}, {"conj",_SAME}, {"conjvec",_SAME}, {"content",_SAME}, {"convol","serconvol","(x,y)","(x,y)"}, {"core",_SAME}, {"core2","core","(x)","(x,1)"}, {"coredisc",_SAME}, {"coredisc2","coredisc","(x)","(x,1)"}, {"cos",_SAME}, {"cosh",_SAME}, {"cvtoi","truncate","(x)","(x,&e)"}, {"cyclo","polcyclo","(n)","(n)"}, {"decodefactor","factorback","(fa)","(fa)"}, {"decodemodule","bnfdecodemodule","(nf,fa)","(nf,fa)"}, {"degree","poldegree","(x)","(x)"}, {"denom","denominator","(x)","(x)"}, {"deplin","lindep","(x)","(x,-1)"}, {"deriv",_SAME}, {"det","matdet","(x)","(x)"}, {"det2","matdet","(x)","(x,1)"}, {"detint","matdetint","(x)","(x)"}, {"diagonal","matdiagonal","(x)","(x)"}, {"dilog",_SAME}, {"dirdiv",_SAME}, {"direuler",_SAME}, {"dirmul",_SAME}, {"dirzetak",_SAME}, {"disc","poldisc","(x)","(x)"}, {"discf","nfdisc","(x)","(x)"}, {"discf2","nfdisc","(x)","(x,2)"}, {"discrayabs","bnrdisc","(bnr,subgroup)","(bnr,subgroup)"}, {"discrayabscond","bnrdisc","(bnr)","(bnr,,,2)"}, {"discrayabslist","bnrdisclist","(bnf,list)","(bnf,list)"}, {"discrayabslistarch","bnrdisclist","(bnf,arch,bound)","(bnf,bound,arch)"}, {"discrayabslistarchall","bnrdisclist","(bnf,bound)","(bnf,bound,,1)"}, {"discrayabslistlong","bnrdisclist","(bnf,bound)","(bnf,bound)"}, {"discrayrel","bnrdisc","(bnr,subgroup)","(bnr,subgroup,,1)"}, {"discrayrelcond","bnrdisc","(bnr,subgroup)","(bnr,subgroup,,3)"}, {"divisors",_SAME}, {"divres","divrem","(x,y)","(x,y)"}, {"divsum","sumdiv","(n,X,expr)","(n,X,expr)"}, {"eigen","mateigen","(x)","(x)"}, {"eint1",_SAME}, {"erfc",_SAME}, {"eta",_SAME}, {"euler","Euler","",""}, {"eval",_SAME}, {"exp",_SAME}, {"extract","vecextract","(x,y)","(x,y)"}, {"fact","factorial","(x)","(x)"}, {"factcantor","factorcantor","(x,p)","(x,p)"}, {"factfq","factorff","(x,p,a)","(x,p,a)"}, {"factmod","factormod","(x,p)","(x,p)"}, {"factor",_SAME}, {"factoredbasis","nfbasis","(x,p)","(x,,p)"}, {"factoreddiscf","nfdisc","(x,p)","(x,,p)"}, {"factoredpolred","polred","(x,p)","(x,,p)"}, {"factoredpolred2","polred","(x,p)","(x,2,p)"}, {"factornf",_SAME}, {"factorpadic",_SAME}, {"factorpadic2","factorpadic","(x,p,r)","(x,p,r,1)"}, {"factpol","factor","(x,l,hint)","(x)"}, {"factpol2","factor","(x,l,hint)","(x)"}, {"fibo","fibonacci","(x)","(x)"}, {"floor",_SAME}, {"for",_SAME}, {"fordiv",_SAME}, {"forprime",_SAME}, {"forstep",_SAME}, {"forvec",_SAME}, {"fpn","ffinit","(p,n)","(p,n)"}, {"frac",_SAME}, {"galois","polgalois","(x)","(x)"}, {"galoisapply","nfgaloisapply","(nf,aut,x)","(nf,aut,x)"}, {"galoisconj","nfgaloisconj","(nf)","(nf)"}, {"galoisconj1","nfgaloisconj","(nf)","(nf,2)"}, {"galoisconjforce","nfgaloisconj","","(nf,1)"}, {"gamh","gammah","(x)","(x)"}, {"gamma",_SAME}, {"gauss","matsolve","(a,b)","(a,b)"}, {"gaussmodulo","matsolvemod","(M,D,Y)","(M,D,Y)"}, {"gaussmodulo2","matsolvemod","(M,D,Y)","(M,D,Y,1)"}, {"gcd",_SAME}, {"getheap",_SAME}, {"getrand",_SAME}, {"getstack",_SAME}, {"gettime",_SAME}, {"globalred","ellglobalred","(x,y)","(x,y)"}, {"goto",_REMOV}, {"hclassno","qfbhclassno","(x)","(x)"}, {"hell","ellheight","(e,x)","(e,x)"}, {"hell2","ellheight","(e,x)","(e,x,1)"}, {"hermite","mathnf","(x)","(x)"}, {"hermite2","mathnf","(x)","(x,1)"}, {"hermitehavas",_REMOV}, {"hermitemod","mathnfmod","(x,d)","(x,d)"}, {"hermitemodid","mathnfmodid","(x,d)","(x,d)"}, {"hermiteperm","mathnf","(x)","(x,3)"}, {"hess","mathess","(x)","(x)"}, {"hilb","hilbert","(x,y)","(x,y)"}, {"hilbert","mathilbert","(n)","(n)"}, {"hilbp","hilbert","(x,y,p)","(x,y,p)"}, {"hvector","vector","(n,X,expr)","(n,X,expr)"}, {"hyperu",_SAME}, {"i","I","",""}, {"idealadd",_SAME}, {"idealaddmultone","idealaddtoone","(nf,list)","(nf,list)"}, {"idealaddone","idealaddtoone","(nf,x,y)","(nf,x,y)"}, {"idealappr",_SAME}, {"idealapprfact","idealappr","(nf,x)","(nf,x,1)"}, {"idealchinese",_SAME}, {"idealcoprime",_SAME}, {"idealdiv",_SAME}, {"idealdivexact","idealdiv","(nf,x,y)","(nf,x,y,1)"}, {"idealfactor",_SAME}, {"idealhermite","idealhnf","(nf,x)","(nf,x)"}, {"idealhermite2","idealhnf","(nf,x)","(nf,x)"}, {"idealintersect",_SAME}, {"idealinv",_SAME}, {"idealinv2","idealinv","(nf,x)","(nf,x,1)"}, {"ideallist",_SAME}, {"ideallistarch",_SAME}, {"ideallistarchgen","ideallistarch","(nf,list,arch)","(nf,list,arch)"}, {"ideallistunit","ideallist","(nf,list)","(nf,list,2)"}, {"ideallistunitarch","ideallistarch","","(nf,list,arch)"}, {"ideallistunitarchgen","ideallistarch","","(nf,list,arch)"}, {"ideallistunitgen","ideallist","","(nf,list,3)"}, {"ideallistzstar","ideallist","(nf,bound)","(nf,bound)"}, {"ideallistzstargen","ideallist","(nf,bound)","(nf,bound,1)"}, {"ideallllred","idealred","(nf,x,vdir)","(nf,x,vdir)"}, {"idealmul",_SAME}, {"idealmulred","idealmul","(nf,x,y)","(nf,x,y,1)"}, {"idealnorm",_SAME}, {"idealpow",_SAME}, {"idealpowred","idealpow","(nf,x,y)","(nf,x,y,1)"}, {"idealtwoelt",_SAME}, {"idealtwoelt2","idealtwoelt","(nf,x,a)","(nf,x,a)"}, {"idealval",_SAME}, {"idmat","matid","(n)","(n)"}, {"if",_SAME}, {"imag",_SAME}, {"image","matimage","(x)","(x)"}, {"image2","matimage","(x)","(x,1)"}, {"imagecompl","matimagecompl","(x)","(x)"}, {"incgam",_SAME}, {"incgam1",_REMOV}, {"incgam2",_REMOV}, {"incgam3",_REMOV}, {"incgam4","incgam","(s,x,y)","(s,x,y)"}, {"indexrank","matindexrank","(x)","(x)"}, {"indsort","vecsort","(x)","(x,,1)"}, {"initalg","nfinit","(pol)","(pol)"}, {"initalgred","nfinit","(x)","(x,2)"}, {"initalgred2","nfinit","(x)","(x,3)"}, {"initell","ellinit","(x)","(x)"}, {"initzeta",_REMOV}, {"integ","intformal","(x,y)","(x,y)"}, {"intersect","matintersect","(x,y)","(x,y)"}, {"intgen","intnum","(x=a,b,s)","(x=a,b,s,1)"}, {"intinf","intnum","(x=a,b,s)","(x=a,b,s,2)"}, {"intnum",_SAME}, {"intopen","intnum","(x=a,b,s)","(x=a,b,s,3)"}, {"inverseimage","matinverseimage","(x,y)","(x,y)"}, {"isdiagonal","matisdiagonal","(x)","(x)"}, {"isfund","isfundamental","(x)","(x)"}, {"isideal","nfisideal","(nf,x)","(nf,x)"}, {"isincl","nfisincl","(x,y)","(x,y)"}, {"isinclfast","nfisincl","(nf1,nf2)","(nf1,nf2,1)"}, {"isirreducible","polisirreducible","(x)","(x)"}, {"isisom","nfisisom","(x,y)","(x,y)"}, {"isisomfast","nfisisom","(x,y)","(x,y)"}, {"isoncurve","ellisoncurve","(e,x)","(e,x)"}, {"isprime",_SAME}, {"isprincipal","bnfisprincipal","(bnf,x)","(bnf,x,0)"}, {"isprincipalforce","bnfisprincipal","(bnf,x)","(bnf,x,2)"}, {"isprincipalgen","bnfisprincipal","(bnf,x)","(bnf,x)"}, {"isprincipalgenforce","bnfisprincipal","(bnf,x)","(bnf,x,3)"}, {"isprincipalray","bnrisprincipal","(bnf,x)","(bnf,x)"}, {"isprincipalraygen",_SAME}, {"ispsp","ispseudoprime","(x)","(x)"}, {"isqrt","sqrtint","(x)","(x)"}, {"isset","setisset","(x)","(x)"}, {"issqfree","issquarefree","(x)","(x)"}, {"issquare",_SAME}, {"isunit","bnfisunit","(bnf,x)","(bnf,x)"}, {"jacobi","qfjacobi","(x)","(x)"}, {"jbesselh","besseljh","(n,x)","(n,x)"}, {"jell","ellj","(x)","(x)"}, {"karamul",_REMOV}, {"kbessel","besselk","(nu,x)","(nu,x)"}, {"kbessel2","besselk","(nu,x)","(nu,x)"}, {"ker","matker","(x)","(x)"}, {"keri","matker","(x)","(x,1)"}, {"kerint","matkerint","(x)","(x)"}, {"kerint1","matkerint","(x)","(x,1)"}, {"kerint2",_REMOV}, {"kro","kronecker","(x,y)","(x,y)"}, {"label",_REMOV}, {"lambdak",_REMOV}, {"laplace","serlaplace","(x)","(x)"}, {"lcm",_SAME}, {"legendre","pollegendre","(n)","(n)"}, {"length",_SAME}, {"lex",_SAME}, {"lexsort","vecsort","(x)","(x,,2)"}, {"lift",_SAME}, {"lindep",_SAME}, {"lindep2","lindep","(x)","(x,1)"}, {"lll","qflll","(x)","(x)"}, {"lll1",_REMOV}, {"lllgen","qflll","(x)","(x,8)"}, {"lllgram","qflllgram","(x)","(x)"}, {"lllgram1",_REMOV}, {"lllgramgen","qflllgram","(x)","(x,8)"}, {"lllgramint","qflllgram","(x)","(x,1)"}, {"lllgramkerim","qflllgram","(x)","(x,4)"}, {"lllgramkerimgen","qflllgram","(x)","(x,5)"}, {"lllint","qflll","(x)","(x,1)"}, {"lllintpartial","qflll","(x)","(x,2)"}, {"lllkerim","qflll","(x)","(x,4)"}, {"lllkerimgen","qflll","(x)","(x,5)"}, {"lllrat",_REMOV}, {"ln","log","(x)","(x)"}, {"lngamma",_SAME}, {"localred","elllocalred","(e)","(e)"}, {"log",_SAME}, {"logagm","log","(x)","(x,1)"}, {"lseriesell","elllseries","(e,s,N,A)","(e,s,A)"}, {"makebigbnf","bnfinit","(sbnf)","(sbnf)"}, {"mat","Mat","(x)","(x)"}, {"matextract","vecextract","(x,y,z)","(x,y,z)"}, {"mathell","ellheightmatrix","(e,x)","(e,x)"}, {"matrix",_SAME}, {"matrixqz",_SAME}, {"matrixqz2","matrixqz","(x,p)","(x,-1)"}, {"matrixqz3","matrixqz","(x,p)","(x,-2)"}, {"matsize",_SAME}, {"max",_SAME}, {"min",_SAME}, {"minideal","idealmin","(nf,ix,vdir)","(nf,ix,vdir)"}, {"minim","qfminim","(x,bound,maxnum)","(x,bound,maxnum)"}, {"minim2","qfminim","(x,bound)","(x,bound,,1)"}, {"mod","Mod","(x,y)","(x,y)"}, {"modp","Mod","(x,y,p)","(x,y)"}, {"modreverse",_SAME}, {"modulargcd","gcd","(x,y)","(x,y,1)"}, {"mu","moebius","(n)","(n)"}, {"newtonpoly",_SAME}, {"nextprime",_SAME}, {"nfdetint",_SAME}, {"nfdiv","nfeltdiv","(nf,a,b)","(nf,a,b)"}, {"nfdiveuc","nfeltdiveuc","(nf,a,b)","(nf,a,b)"}, {"nfdivres","nfeltdivrem","(nf,a,b)","(nf,a,b)"}, {"nfhermite","nfhnf","(nf,x)","(nf,x)"}, {"nfhermitemod","nfhnfmod","(nf,x,detx)","(nf,x,detx)"}, {"nfmod","nfeltmod","(nf,a,b)","(nf,a,b)"}, {"nfmul","nfeltmul","(nf,a,b)","(nf,a,b)"}, {"nfpow","nfeltpow","(nf,a,k)","(nf,a,k)"}, {"nfreduce","nfeltreduce","(nf,a,id)","(nf,a,id)"}, {"nfsmith","nfsnf","(nf,x)","(nf,x)"}, {"nfval","nfeltval","(nf,a,pr)","(nf,a,pr)"}, {"norm",_SAME}, {"norml2",_SAME}, {"nucomp","qfbnucomp","(x,y,l)","(x,y,l)"}, {"numdiv",_SAME}, {"numer","numerator","(x)","(x)"}, {"nupow","qfbnupow","(x,n)","(x,n)"}, {"o","O","(x)","(x)"}, {"omega",_SAME}, {"ordell","ellordinate","(e,x)","(e,x)"}, {"order","znorder","(x)","(x)"}, {"orderell","ellorder","(e,x)","(e,x)"}, {"ordred","polredord","(x)","(x)"}, {"padicprec",_SAME}, {"pascal","matpascal","(n)","(n)"}, {"perf","qfperfection","(a)","(a)"}, {"permutation","numtoperm","(n,k)","(n,k)"}, {"permutation2num","permtonum","(vect)","(vect)"}, {"pf","qfbprimeform","(x,p)","(x,p)"}, {"phi","eulerphi","(x)","(x)"}, {"pi","Pi","",""}, {"pnqn","contfracpnqn","(x)","(x)"}, {"pointell","ellztopoint","(e,z)","(e,z)"}, {"polint","polinterpolate","(xa,ya,x)","(xa,ya,p)"}, {"polred",_SAME}, {"polred2","polred","(x)","(x,2)"}, {"polredabs",_SAME}, {"polredabs2","polredabs","(x)","(x,1)"}, {"polredabsall","polredabs","(x)","(x,4)"}, {"polredabsfast","polredabs","(x)","(x,8)"}, {"polredabsnored","polredabs","(x)","(x,2)"}, {"polsym",_SAME}, {"polvar","variable","(x)","(x)"}, {"poly","Pol","(x,v)","(x,v)"}, {"polylog",_SAME}, {"polylogd","polylog","(m,x)","(m,x,1)"}, {"polylogdold","polylog","(m,x)","(m,x,2)"}, {"polylogp","polylog","(m,x)","(m,x,3)"}, {"polyrev","Polrev","(x,v)","(x,v)"}, {"polzag","polzagier","(n,m)","(n,m)"}, {"powell","ellmul","(e,x,n)","(e,x,n)"}, {"powrealraw","qfbpowraw","(x,n)","(x,n)"}, {"prec","precision","(x,n)","(x,n)"}, {"precision",_SAME}, {"prime",_SAME}, {"primedec","idealprimedec","(nf,p)","(nf,p)"}, {"primes",_SAME}, {"primroot","znprimroot","(n)","(n)"}, {"principalideal",_REMOV}, {"principalidele",_REMOV}, {"prod","prod","(x,X=a,b,expr)","(X=a,b,expr,x)"}, {"prodeuler",_SAME}, {"prodinf",_SAME}, {"prodinf1","prodinf","(X=a,expr)","(X=a,expr,1)"}, {"psi",_SAME}, {"qfi","Qfb","(a,b,c)","(a,b,c)"}, {"qfr","Qfb","(a,b,c,d)","(a,b,c,d)"}, {"quaddisc",_SAME}, {"quadgen",_SAME}, {"quadpoly",_SAME}, {"random",_SAME}, {"rank","matrank","(x)","(x)"}, {"rayclassno","bnrclassno","(bnf,x)","(bnf,x)"}, {"rayclassnolist","bnrclassnolist","(bnf,liste)","(bnf,liste)"}, {"real",_SAME}, {"recip","polrecip","(x)","(x)"}, {"redimag","qfbred","(x)","(x)"}, {"redreal","qfbred","(x)","(x)"}, {"redrealnod","qfbred","(x,d)","(x,2,,d)"}, {"reduceddisc","poldiscreduced","(f)","(f)"}, {"regula","quadregulator","(x)","(x)"}, {"reorder",_REMOV}, {"resultant","polresultant","(x,y)","(x,y)"}, {"resultant2","polresultant","(x,y)","(x,y,1)"}, {"reverse","serreverse","(x)","(x)"}, {"rhoreal","qfbred","(x)","(x,1)"}, {"rhorealnod","qfbred","(x,d)","(x,3,,d)"}, {"rndtoi","round","(x)","(x,&e)"}, {"rnfbasis",_SAME}, {"rnfdiscf","rnfdisc","(nf,pol)","(nf,pol)"}, {"rnfequation",_SAME}, {"rnfequation2","rnfequation","(nf,pol)","(nf,pol,1)"}, {"rnfhermitebasis","rnfhnfbasis","(bnf,order)","(bnf,order)"}, {"rnfisfree",_SAME}, {"rnflllgram",_SAME}, {"rnfpolred",_SAME}, {"rnfpseudobasis",_SAME}, {"rnfsteinitz",_SAME}, {"rootmod","polrootsmod","(x,p)","(x,p)"}, {"rootmod2","polrootsmod","(x,p)","(x,p)"}, {"rootpadic","polrootspadic","(x,p,r)","(x,p,r)"}, {"roots","polroots","(x)","(x)"}, {"rootsof1","nfrootsof1","(nf)","(nf)"}, {"rootsold",_REMOV}, {"round",_SAME}, {"rounderror","round","(x)","(x,&e)"}, {"series","Ser","(x,v)","(x,v)"}, {"set","Set","(x)","(x)"}, {"setintersect",_SAME}, {"setminus",_SAME}, {"setrand",_SAME}, {"setsearch",_SAME}, {"setunion",_SAME}, {"shift",_SAME}, {"shiftmul",_SAME}, {"sigma",_SAME}, {"sigmak","sigma","(k,x)","(x,k)"}, {"sign",_SAME}, {"signat","qfsign","(x)","(x)"}, {"signunit","bnfsignunit","(bnf)","(bnf)"}, {"simplefactmod","factormod","(x,p)","(x,p,1)"}, {"simplify",_SAME}, {"sin",_SAME}, {"sinh",_SAME}, {"size","sizedigit","(x)","(x)"}, {"smallbasis","nfbasis","(x)","(x,1)"}, {"smallbuchinit","bnfcompress","(x)","(x)"}, {"smalldiscf","nfdisc","(x)","(x,1)"}, {"smallfact","factor","(x)","(x,0)"}, {"smallinitell","ellinit","(x)","(x,1)"}, {"smallpolred","polred","(x)","(x,1)"}, {"smallpolred2","polred","(x)","(x,3)"}, {"smith","matsnf","(x)","(x)"}, {"smith2","matsnf","(x)","(x,1)"}, {"smithclean","matsnf","(x)","(x,4)"}, {"smithpol","matsnf","(x)","(x,2)"}, {"solve",_SAME}, {"sort","vecsort","(x)","(x)"}, {"sqr",_SAME}, {"sqred","qfgaussred","(x)","(x)"}, {"sqrt",_SAME}, {"srgcd","gcd","(x,y)","(x,y,2)"}, {"sturm","polsturm","(x)","(x)"}, {"sturmpart","polsturm","(x,a,b)","(x,a,b)"}, {"subcyclo","polsubcyclo","(p,d)","(p,d)"}, {"subell","ellsub","(e,a,b)","(e,a,b)"}, {"subst",_SAME}, {"sum","sum","(x,X=a,b,expr)","(X=a,b,expr,x)"}, {"sumalt",_SAME}, {"sumalt2","sumalt","(X=a,expr)","(X=a,expr,1)"}, {"suminf",_SAME}, {"sumpos",_SAME}, {"sumpos2","sumpos","(X=a,expr)","(X=a,expr,1)"}, {"supplement","matsupplement","(x)","(x)"}, {"sylvestermatrix","polsylvestermatrix","(x,y)","(x,y)"}, {"system",_SAME}, {"tan",_SAME}, {"tanh",_SAME}, {"taniyama","elltaniyama","(e)","(e)"}, {"taylor",_SAME}, {"tchebi","polchebyshev","(n)","(n)"}, {"teich","teichmuller","(x)","(x)"}, {"theta",_SAME}, {"thetanullk",_SAME}, {"threetotwo",_REMOV}, {"threetotwo2",_REMOV}, {"torsell","elltors","(e)","(e)"}, {"trace",_SAME}, {"trans","mattranspose","(x)","(x)"}, {"trunc","truncate","(x)","(x)"}, {"tschirnhaus","poltschirnhaus","(x)","(x)"}, {"twototwo",_REMOV}, {"unit","quadunit","(x)","(x)"}, {"until",_SAME}, {"valuation",_SAME}, {"vec","Vec","(x)","(x)"}, {"vecindexsort","vecsort","(x)","(x,,1)"}, {"veclexsort","vecsort","(x)","(x,,2)"}, {"vecmax",_SAME}, {"vecmin",_SAME}, {"vecsort",_SAME}, {"vector",_SAME}, {"vvector","vectorv","(n,X,expr)","(n,X,expr)"}, {"weipell","ellwp","(e)","(e)"}, {"wf","weber","(x)","(x)"}, {"wf2","weber","(x)","(x,2)"}, {"while",_SAME}, {"zell","ellpointtoz","(e,P)","(e,P)"}, {"zeta",_SAME}, {"zetak","lfun","(nfz,s)","(L,s)"}, {"zideallog","ideallog","(nf,x,bid)","(nf,x,bid)"}, {"zidealstar","idealstar","(nf,I)","(nf,I)"}, {"zidealstarinit","idealstar","(nf,id)","(nf,id,1)"}, {"zidealstarinitgen","idealstar","(nf,id)","(nf,id,2)"}, {"znstar",_SAME}, {"allocatemem",_SAME}, {"box","plotbox","(x,a)","(x,a)"}, {"color","plotcolor","(w,c)","(w,c)"}, {"cursor","plotcursor","(w)","(w)"}, {"default",_SAME}, {"draw","plotdraw","(list)","(list)"}, {"plotinit","plotinit","(w,x,y)","(w,x,y)"}, {"kill",_SAME}, {"plotkill","plotkill","(w)","(w)"}, {"line","plotlines","(w,x2,y2)","(w,x2,y2)"}, {"lines","plotlines","(w,x2,y2)","(w,x2,y2)"}, {"move","plotmove","(w,x,y)","(w,x,y)"}, {"plot",_SAME}, {"ploth",_SAME}, {"ploth2","ploth","(X=a,b,expr)","(X=a,b,expr,1)"}, {"plothmult","ploth","(X=a,b,expr)","(X=a,b,expr)"}, {"plothraw",_SAME}, {"point","plotpoints","(w,x,y)","(w,x,y)"}, {"points","plotpoints","(w,x,y)","(w,x,y)"}, {"psdraw","psdraw","(list)","(list)"}, {"psploth","psploth","(X=a,b,expr)","(X=a,b,expr)"}, {"postploth2","psploth","(X=a,b,expr)","(X=a,b,expr,1)"}, {"psplothraw","psplothraw","(listx,listy)","(listx,listy)"}, {"pprint",_REMOV}, {"pprint1",_REMOV}, {"print",_SAME}, {"print1",_SAME}, {"rbox","plotrbox","(w,dx,dy)","(w,dx,dy)"}, {"read","input","(x)","(x)"}, {"rline","plotrline","(w,dx,dy)","(w,dx,dy)"}, {"rlines","plotrlines","(w,dx,dy)","(w,dx,dy,1)"}, {"rmove","plotrmove","(w,dx,dy)","(w,dx,dy)"}, {"rpoint","plotrpoint","(w,dx,dy)","(w,dx,dy)"}, {"rpoints","plotrpoints","(w,dx,dy)","(w,dx,dy)"}, {"scale","plotscale","(w,x1,x2,y1,y2)","(w,x1,x2,y1,y2)"}, {"setprecision","default","(n)","(realprecision,n)"}, {"setserieslength","default","(n)","(seriesprecision,n)"}, {"settype","type","(x,t)","(x,t)"}, {"string","plotstring","(w,x)","(w,x)"}, {"texprint","printtex","(x)","(x)"}, {"type",_SAME}, /* not in 1.39.15 */ {"intfouriercos",_REMOV}, {"intfouriersin",_REMOV}, {"intfourierexp",_REMOV}, {"intlaplaceinv",_REMOV}, {"intmellininv",_REMOV}, {"intmellininvshort",_REMOV}, {"zetakinit","lfuninit","(T)","(T,sdom)"}, {NULL,_SAME} }; pari-2.11.2/src/gp/emacs.c0000644000175000017500000000203413201017466013606 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* EMACS FRONTEND */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" #include "gp.h" void init_emacs(void) { GP_DATA->breakloop = 0; disable_color = 1; } pari-2.11.2/src/modules/0000755000175000017500000000000013461316051013415 5ustar billbillpari-2.11.2/src/modules/mpqs.h0000644000175000017500000005365513201017466014564 0ustar billbill/* - debug support */ #ifdef MPQS_DEBUG_VERYVERBOSE # ifndef MPQS_DEBUG_VERBOSE # define MPQS_DEBUG_VERBOSE # endif #endif #ifdef MPQS_DEBUG_VERBOSE # ifndef MPQS_DEBUG # define MPQS_DEBUG # endif # define PRINT_IF_VERBOSE(x) err_printf(x) #else # define PRINT_IF_VERBOSE(x) #endif #ifdef MPQS_DEBUG # define MPQS_DEBUGLEVEL 1000 /* infinity */ #else # define MPQS_DEBUGLEVEL DEBUGLEVEL #endif /* - string and external file stuff for the relations "database" */ #ifndef SEEK_SET # define SEEK_SET 0 #endif #ifdef __CYGWIN32__ /* otherwise fseek() goes crazy due to silent \n <--> LF translations */ # define WRITE "wb" # define READ "rb" #else # define WRITE "w" # define READ "r" #endif #define MPQS_STRING_LENGTH (4 * 1024UL) /* - non-configurable sizing parameters */ #define MPQS_POSSIBLE_MULTIPLIERS 5 /* how many values for k we'll try */ /* following must be in range of the cand_multipliers table below */ #define MPQS_MULTIPLIER_SEARCH_DEPTH 5 /* how many primes to inspect per k */ /* `large primes' must be smaller than * min(MPQS_LP_BOUND, largest_FB_p) * MPQS_LP_FACTOR * - increased this with the idea of capping it at about 2^30 */ #define MPQS_LP_BOUND 12500000 /* works for 32 and 64bit */ /* see mpqs_locate_A_range() for an explanation of the following. I had * some good results with about -log2(0.85) but in the range I was testing, * this shifts the primes for A only by one position in the FB. Don't go * over the top with this one... */ #define MPQS_A_FUDGE 0.15 /* ~ -log2(0.9) */ #define MPQS_CANDIDATE_ARRAY_SIZE 2000 /* max. this many cand's per poly */ #ifdef MPQS_USE_HISTOGRAMS /* histogram evaluation/feedback available when size_of_FB exceeds this: */ # define MPQS_MIN_SIZE_FB_FOR_HISTO 600 /* min number of candidates to look at before evaluating histograms */ # define MPQS_MIN_CANDS_FOR_HISTO 4000 /* min number of full relations to have been created before etc. */ # define MPQS_MIN_FRELS_FOR_HISTO 110 /* see mpqs_eval_histograms() for explanation of the following */ # define MPQS_HISTO_FREL_QUANTILE 2.4 # define MPQS_HISTO_DROP_LIMIT 3.6 # define MPQS_HISTO_LPREL_BASEFLOW 1.4 #endif /* give up when nothing found after ~1.5 times the required number of * relations has been computed (N might be a prime power or the * parameters might be exceptionally unfortunate for it) */ #define MPQS_ADMIT_DEFEAT 1500 /* - structures, types, and constants */ /* -- reasonably-sized integers */ #ifdef LONG_IS_64BIT typedef int mpqs_int32_t; typedef unsigned int mpqs_uint32_t; typedef ulong mpqs_uint64_t; #else typedef long mpqs_int32_t; typedef ulong mpqs_uint32_t; typedef struct { ulong _w0; ulong _w1; } mpqs_uint64_t; #endif /* -- we'll sometimes want to use the machine's native size here, and * sometimes (for future double-large-primes) force 64 bits - thus: */ typedef union mpqs_invp { ulong _ul; mpqs_uint64_t _u64; } mpqs_invp_t; /* -- factor base entries should occupy 32 bytes (and we'll keep them * aligned, for good L1 cache hit rates). Some of the entries will be * abused for e.g. -1 and (factors of) k instead for real factor base * primes, and for a sentinel at the end. This is why __p is a signed * field.-- The two start fields depend on the current polynomial and * keep changing during sieving, the flags will also change depending on * the current A. */ /* Let (z1, z2) be the roots of Q(x) = A x^2 + Bx + C mod p_i; then * Q(z1 + p_i Z) == 0 mod p_i and Q(z2 + p_i Z) == 0 mod p_i; * start_1, start_2 are the positions where p_i divides Q(x) for the * first time, already adjusted for the fact that the sieving array, * nominally [-M, M], is represented by a 0-based C array of length * 2M + 1. For the prime factors of A and those of k, the two roots * are equal mod p_i. */ #define MPQS_FB_ENTRY_PAD 32 typedef union mpqs_FB_entry { char __pad[MPQS_FB_ENTRY_PAD]; struct { mpqs_int32_t __p; /* the prime p */ /* Following two are not yet used: */ float __flogp; /* its logarithm as a 4-byte float */ mpqs_invp_t __invp; /* 1/p mod 2^64 or 2^BITS_IN_LONG */ mpqs_int32_t __start1; /* representatives of the two APs mod p */ mpqs_int32_t __start2; mpqs_uint32_t __sqrt_kN; /* sqrt(kN) mod p */ unsigned char __val; /* 8-bit approx. scaled log for sieving */ unsigned char __flags; } __entry; } mpqs_FB_entry_t; /* --- convenience accessor macros for the preceding: */ #define fbe_p __entry.__p #define fbe_flogp __entry.__flogp #define fbe_invp __entry.__invp #define fbe_start1 __entry.__start1 #define fbe_start2 __entry.__start2 #define fbe_sqrt_kN __entry.__sqrt_kN #define fbe_logval __entry.__val #define fbe_flags __entry.__flags /* --- flag bits for fbe_flags: */ /* TODO */ #define MPQS_FBE_CLEAR 0x0 /* no flags */ /* following used for odd FB primes, and applies to the divisors of A but not * those of k. Must occupy the rightmost bit because we also use it as a * shift count after extracting it from the byte. */ #define MPQS_FBE_DIVIDES_A 0x1ul /* and Q(x) mod p only has degree 1 */ /* XX tentative: one bit to mark normal FB primes, * XX one to mark the factors of k, * XX one to mark primes used in sieving, * XX later maybe one to mark primes of which we'll be tracking the square, * XX one to mark primes currently in use for A; * XX once we segment the FB, one bit marking the members of the first segment */ /* -- multiplier k and attached quantities: More than two prime factors * for k will be pointless in practice, thus capping them at two. */ #define MPQS_MAX_OMEGA_K 2 typedef struct mpqs_multiplier { mpqs_uint32_t k; /* the multiplier (odd, squarefree) */ mpqs_uint32_t omega_k; /* number (>=0) of primes dividing k */ mpqs_uint32_t kp[MPQS_MAX_OMEGA_K]; /* prime factors of k, if any */ } mpqs_multiplier_t; static const mpqs_multiplier_t cand_multipliers[] = { { 1, 0, { 0, 0} }, { 3, 1, { 3, 0} }, { 5, 1, { 5, 0} }, { 7, 1, { 7, 0} }, { 11, 1, { 11, 0} }, { 13, 1, { 13, 0} }, { 15, 2, { 3, 5} }, { 17, 1, { 17, 0} }, { 19, 1, { 19, 0} }, { 21, 2, { 3, 7} }, { 23, 1, { 23, 0} }, { 29, 1, { 29, 0} }, { 31, 1, { 31, 0} }, { 33, 2, { 3, 11} }, { 35, 2, { 5, 7} }, { 37, 1, { 37, 0} }, { 39, 2, { 3, 13} }, { 41, 1, { 41, 0} }, { 43, 1, { 43, 0} }, { 47, 1, { 47, 0} }, { 51, 2, { 3, 17} }, { 53, 1, { 53, 0} }, { 55, 2, { 5, 11} }, { 57, 2, { 3, 19} }, { 59, 1, { 59, 0} }, { 61, 1, { 61, 0} }, { 65, 2, { 5, 13} }, { 67, 1, { 67, 0} }, { 69, 2, { 3, 23} }, { 71, 1, { 71, 0} }, { 73, 1, { 73, 0} }, { 77, 2, { 7, 11} }, { 79, 1, { 79, 0} }, { 83, 1, { 83, 0} }, { 85, 2, { 5, 17} }, { 87, 2, { 3, 29} }, { 89, 1, { 89, 0} }, { 91, 2, { 7, 13} }, { 93, 2, { 3, 31} }, { 95, 2, { 5, 19} }, { 97, 1, { 97, 0} } }; /* -- the array of (Chinese remainder) idempotents which add/subtract up to * the middle coefficient B, and for convenience, the FB subscripts of the * primes in current use for A. We keep these together since both arrays * are of the same size and are used at the same times. */ typedef struct mqps_per_A_prime { GEN _H; /* summand for B */ mpqs_int32_t _i; /* subscript into FB */ } mpqs_per_A_prime_t; /* following cooperate with names of local variables in the self_init fcns. * per_A_pr must exist and be an alias for the eponymous handle pointer for * all of these, and FB must exist and correspond to the handle FB pointer * for all but the first two of them. */ #define MPQS_H(i) (per_A_pr[i]._H) #define MPQS_I(i) (per_A_pr[i]._i) #define MPQS_AP(i) (FB[per_A_pr[i]._i].fbe_p) #define MPQS_LP(i) (FB[per_A_pr[i]._i].fbe_flogp) #define MPQS_SQRT(i) (FB[per_A_pr[i]._i].fbe_sqrt_kN) #define MPQS_FLG(i) (FB[per_A_pr[i]._i].fbe_flags) /* -- the array of addends / subtrahends for changing polynomials during * self-initialization: (1/A) H[i] mod p_j, with i subscripting the inner * array in each entry, and j choosing the entry in an outer array. * Entries will occupy 64 bytes each no matter what (which imposes one * sizing restriction: at most 17 prime factors for A; thus i will range * from 0 to at most 15.) This wastes a little memory for smaller N but * makes it easier for compilers to generate efficient code. */ /* NOTE: At present, memory locality vis-a-vis accesses to this array is good * in the slow (new A) branch of mpqs_self_init(), but poor in the fast * (same A, new B) branch, which now loops over the outer array index, * reading just one field of each inner array each time through the FB * loop. This doesn't really harm, but will improve one day when we do * segmented sieve arrays with the attached segmented FB-range accesses. */ #define MPQS_MAX_OMEGA_A 17 typedef struct mpqs_inv_A_H { mpqs_uint32_t _i[MPQS_MAX_OMEGA_A - 1]; } mpqs_inv_A_H_t; #define MPQS_INV_A_H(i,j) (inv_A_H[j]._i[i]) /* -- global handle for keeping track of everything used throughout any one * factorization attempt. The order of the fields is roughly determined by * wanting to keep the most frequently used stuff near the beginning. */ typedef struct mpqs_handle { /* pointers into pari_malloc()d memory which must be freed at the end: */ unsigned char *sieve_array; /* 0-based, representing [-M,M-1] */ unsigned char *sieve_array_end; /* points at sieve_array[M-1] */ mpqs_FB_entry_t *FB; /* (aligned) FB array itself */ long *candidates; /* collects promising sieve subscripts */ char *relations; /* freshly found relations (strings) */ long *relaprimes; /* prime/exponent pairs in a relation */ mpqs_inv_A_H_t *inv_A_H; /* self-init: (aligned) stepping array, and */ mpqs_per_A_prime_t *per_A_pr; /* FB subscripts of primes in A etc. */ /* other stuff that's being used all the time */ mpqs_int32_t M; /* sieving over |x| <= M */ mpqs_int32_t size_of_FB; /* # primes in FB (or dividing k) */ /* the following three are in non-descending order, and the first two must * be adjusted for omega_k at the beginning */ mpqs_int32_t index0_FB; /* lowest subscript into FB of a "real" prime * (i.e. other than -1, 2, factors of k) */ mpqs_int32_t index1_FB; /* lowest subscript into FB for sieving */ mpqs_int32_t index2_FB; /* primes for A are chosen relative to this */ unsigned char index2_moved; /* true when we're starved for small A's */ unsigned char sieve_threshold; /* distinguishes candidates in sieve */ #ifdef MPQS_USE_HISTOGRAMS /* histogram feedback */ unsigned char do_histograms; /* (boolean) enable histogram updating */ unsigned char done_histograms; /* histos have been eval'd for feedback */ /* more pari_malloc()d memory here: */ long *histo_full; /* distribution of full rels from sieve */ long *histo_lprl; /* - of LP rels from sieve */ long *histo_drop; /* - of useless candidates */ #endif GEN N; /* given number to be factored */ GEN kN; /* N with multiplier (on PARI stack) */ /* quantities attached to the current polynomial; all these also * live in preallocated slots on the PARI stack: */ GEN A; /* leading coefficient */ GEN B; /* middle coefficient */ #ifdef MPQS_DEBUG GEN C; /* and constant coefficient */ #endif mpqs_int32_t omega_A; /* number of primes going into each A */ mpqs_int32_t no_B; /* number of B's for each A: 2^(omega_A-1) */ double l2_target_A; /* ~log2 of desired typical A */ /* counters and bit pattern determining and numbering the current * polynomial: */ mpqs_uint32_t bin_index; /* bit pattern for selecting primes for A */ mpqs_uint32_t index_i; /* running count of A's */ mpqs_uint32_t index_j; /* B's ordinal number in A's cohort */ /* TODO: one more to follow here... */ /* further sizing parameters: */ mpqs_int32_t target_no_rels; /* target number of full relations */ mpqs_int32_t largest_FB_p; /* largest prime in the FB */ mpqs_int32_t pmin_index1; /* lower bound for primes used for sieving */ mpqs_int32_t lp_scale; /* factor by which LPs may exceed FB primes */ mpqs_int32_t first_sort_point; /* when to sort and combine */ mpqs_int32_t sort_pt_interval; /* (in units of 1/1000) */ /* subscripts determining where to pick primes for A... */ /* FIXME: lp_bound might have to be mpqs_int64_t ? or mpqs_invp_t ? */ long lp_bound; /* cutoff for Large Primes */ long digit_size_N; long digit_size_kN; const mpqs_multiplier_t *_k; /* multiplier k and attached quantities */ double tolerance; /* controls the tightness of the sieve */ double dkN; /* - double prec. approximation of kN */ double l2sqrtkN; /* ~log2(sqrt(kN)) */ double l2M; /* ~log2(M) (cf. below) */ /* TODO: need an index2_FB here to remember where to start picking primes */ /* Put statistics here ? Currently keep them as local variables in mpqs() */ /* bookkeeping pointers to containers of aligned memory chunks: */ void *FB_chunk; /* (unaligned) chunk containing the FB */ void *invAH_chunk; /* (unaligned) chunk for self-init array */ } mpqs_handle_t; /* -- sizing table entries */ /* The "tolerance" is explained below apropos of mpqs_set_sieve_threshold(). * The LP scale, for very large kN, prevents us from accumulating vast amounts * of LP relations with little chance of hitting any particular large prime * a second time and being able to combine a full relation from two LP ones; * however, the sieve threshold (determined by the tolerance) already works * against very large LPs being produced.-- The present relations "database" * can detect duplicate full relations only during the sort/combine phases, * so we must do some sort points even for tiny kN where we do not admit * large primes at all. * Some constraints imposed by the present implementation: * + omega_A should be at least 3, and no more than MPQS_MAX_OMEGA_A * + The size of the FB must be large enough compared to omega_A * (about 2*omega_A + 3, but this is always true below) */ /* XXX Changes needed for segmented mode: * XXX When using it (kN large enough), * XXX - M must become a multiple of the (cache block) segment size * XXX (or to keep things simple: a multiple of 32K) * XXX - we need index3_FB to seperate (smaller) primes used for normal * XXX sieving from larger ones used with transaction buffers * XXX (and the locate_A_range and attached logic must be changed to * XXX cap index2_FB below index3_FB instead of below size_of_FB) */ typedef struct mpqs_parameterset { float tolerance; /* "mesh width" of the sieve */ /* XX following subject to further change */ mpqs_int32_t lp_scale; /* factor by which LPs may exceed FB primes */ mpqs_int32_t M; /* size of half the sieving interval */ mpqs_int32_t size_of_FB; /* #primes to use for FB (including 2) */ mpqs_int32_t omega_A; /* #primes to go into each A */ /* following is auto-adjusted to account for prime factors of k inserted * near the start of the FB. NB never ever sieve on the prime 2 (which * would just contribute a constant at each sieve point). */ mpqs_int32_t pmin_index1; /* lower bound for primes used for sieving */ /* the remaining two are expressed in percent (of the target number of full * relations), and determine when we stop sieving to review the contents * of the relations DB and sort them and combine full relations from LP * ones. Note that the handle has these in parts per thousand instead. */ mpqs_int32_t first_sort_point; mpqs_int32_t sort_pt_interval; } mpqs_parameterset_t; /* - the table of sizing parameters itself */ /* indexed by size of kN in decimal digits, subscript 0 corresponding to * 9 (or fewer) digits */ static const mpqs_parameterset_t mpqs_parameters[] = { /* tol lp_scl M szFB oA pmx1 1st sti */ { /*9*/ 0.8, 1, 900, 20, 3, 5, 70, 8}, { /*10*/ 0.8, 1, 900, 21, 3, 5, 70, 8}, { /*11*/ 0.8, 1, 920, 22, 3, 5, 70, 6}, { /*12*/ 0.8, 1, 960, 24, 3, 5, 70, 6}, { /*13*/ 0.8, 1, 1020, 26, 3, 5, 70, 6}, { /*14*/ 0.8, 1, 1100, 29, 3, 5, 70, 6}, { /*15*/ 0.8, 1, 1200, 32, 3, 5, 60, 8}, { /*16*/ 0.8, 1, 1500, 35, 3, 5, 60, 8}, { /*17*/ 0.8, 1, 1900, 40, 3, 5, 60, 8}, { /*18*/ 0.8, 1, 2500, 60, 3, 5, 50, 10}, { /*19*/ 0.8, 1, 3200, 80, 3, 5, 50, 10}, { /*20*/ 0.8, 1, 4000, 100, 3, 5, 40, 10}, { /*21*/ 0.8, 1, 4300, 100, 3, 5, 40, 10}, { /*22*/ 0.8, 1, 4500, 120, 3, 5, 40, 10}, { /*23*/ 0.8, 1, 4800, 140, 3, 5, 30, 10}, { /*24*/ 0.8, 1, 5100, 160, 4, 7, 30, 10}, { /*25*/ 0.8, 1, 5400, 180, 4, 7, 30, 10}, { /*26*/ 0.9, 1, 5700, 200, 4, 7, 30, 10}, { /*27*/ 1.12, 1, 6000, 220, 4, 7, 30, 10}, { /*28*/ 1.17, 1, 6300, 240, 4, 11, 30, 10}, { /*29*/ 1.22, 1, 6500, 260, 4, 11, 30, 10}, { /*30*/ 1.30, 1, 6800, 325, 4, 11, 20, 10}, { /*31*/ 1.33, 1, 7000, 355, 4, 13, 20, 10}, { /*32*/ 1.36, 1, 7200, 375, 5, 13, 20, 10}, { /*33*/ 1.40, 1, 7400, 400, 5, 13, 20, 10}, { /*34*/ 1.43, 1, 7600, 425, 5, 17, 20, 10}, /* around here, sieving takes long enough to make it worthwhile recording * LP relations into their separate output files, although they tend not * yet to contribute a lot to the full relations until we get up to around * 47 digits or so. */ { /*35*/ 1.48, 30, 7800, 550, 5, 17, 20, 10}, { /*36*/ 1.53, 45, 8100, 650, 5, 17, 20, 10}, { /*37*/ 1.60, 60, 9000, 750, 6, 19, 20, 10}, { /*38*/ 1.66, 70, 10000, 850, 6, 19, 20, 10}, { /*39*/ 1.69, 80, 11000, 950, 6, 23, 20, 10}, /* around here, the largest prime in FB becomes comparable to M in size */ { /*40*/ 1.69, 80, 12500, 1000, 6, 23, 20, 10}, { /*41*/ 1.69, 80, 14000, 1150, 6, 23, 10, 10}, { /*42*/ 1.69, 80, 15000, 1300, 6, 29, 10, 10}, { /*43*/ 1.69, 80, 16000, 1500, 6, 29, 10, 10}, { /*44*/ 1.69, 80, 17000, 1700, 7, 31, 10, 10}, { /*45*/ 1.69, 80, 18000, 1900, 7, 31, 10, 10}, { /*46*/ 1.69, 80, 20000, 2100, 7, 37, 10, 10}, { /*47*/ 1.69, 80, 25000, 2300, 7, 37, 10, 10}, { /*48*/ 1.69, 80, 27500, 2500, 7, 37, 10, 10}, { /*49*/ 1.72, 80, 30000, 2700, 7, 41, 10, 10}, { /*50*/ 1.75, 80, 35000, 2900, 7, 41, 10, 10}, { /*51*/ 1.80, 80, 40000, 3000, 7, 43, 10, 10}, { /*52*/ 1.85, 80, 50000, 3200, 7, 43, 10, 10}, { /*53*/ 1.90, 80, 60000, 3500, 7, 47, 10, 10}, { /*54*/ 1.95, 80, 70000, 3800, 7, 47, 10, 10}, { /*55*/ 1.95, 80, 80000, 4100, 7, 53, 10, 10}, { /*56*/ 1.95, 80, 90000, 4400, 7, 53, 10, 8}, { /*57*/ 2.00, 80, 100000, 4700, 8, 53, 10, 8}, { /*58*/ 2.05, 80, 110000, 5000, 8, 59, 10, 8}, { /*59*/ 2.10, 80, 120000, 5400, 8, 59, 10, 8}, { /*60*/ 2.15, 80, 130000, 5800, 8, 61, 10, 8}, { /*61*/ 2.20, 80, 140000, 6100, 8, 61, 10, 8}, { /*62*/ 2.25, 80, 150000, 6400, 8, 67, 10, 6}, { /*63*/ 2.39, 80, 160000, 6700, 8, 67, 10, 6}, { /*64*/ 2.30, 80, 165000, 7000, 8, 67, 10, 6}, { /*65*/ 2.31, 80, 170000, 7300, 8, 71, 10, 6}, { /*66*/ 2.32, 80, 175000, 7600, 8, 71, 10, 6}, { /*67*/ 2.33, 80, 180000, 7900, 8, 73, 10, 6}, { /*68*/ 2.34, 80, 185000, 8200, 8, 73, 10, 6}, { /*69*/ 2.35, 80, 190000, 8600, 8, 79, 8, 6}, { /*70*/ 2.36, 80, 195000, 8800, 8, 79, 8, 6}, { /*71*/ 2.37, 80, 200000, 9000, 9, 79, 8, 6}, { /*72*/ 2.38, 80, 205000, 9250, 9, 83, 5, 5}, { /*73*/ 2.41, 80, 210000, 9500, 9, 83, 5, 5}, { /*74*/ 2.46, 80, 220000, 9750, 9, 83, 5, 5}, { /*75*/ 2.51, 80, 230000, 10000, 9, 89, 5, 5}, { /*76*/ 2.56, 80, 240000, 10500, 9, 89, 5, 5}, { /*77*/ 2.58, 80, 250000, 11200, 9, 89, 5, 5}, { /*78*/ 2.60, 80, 260000, 12500, 9, 89, 5, 5}, { /*79*/ 2.63, 80, 270000, 14000, 9, 97, 5, 4}, { /*80*/ 2.65, 80, 280000, 15500, 9, 97, 5, 4}, { /*81*/ 2.72, 80, 300000, 17000, 9, 97, 4, 4}, { /*82*/ 2.77, 80, 320000, 18500, 9, 101, 4, 4}, { /*83*/ 2.82, 80, 340000, 20000, 10, 101, 4, 4}, { /*84*/ 2.84, 80, 360000, 21500, 10, 103, 4, 4}, { /*85*/ 2.86, 80, 400000, 23000, 10, 103, 4, 3}, { /*86*/ 2.88, 80, 460000, 24500, 10, 107, 4, 3}, /* architectures with 1MBy L2 cache will become noticeably slower here * as 2*M exceeds that mark - to be addressed in a future version by * segmenting the sieve interval */ { /*87*/ 2.90, 80, 520000, 26000, 10, 107, 4, 3}, { /*88*/ 2.91, 80, 580000, 27500, 10, 109, 4, 3}, { /*89*/ 2.92, 80, 640000, 29000, 10, 109, 4, 3}, { /*90*/ 2.93, 80, 700000, 30500, 10, 113, 2, 2}, { /*91*/ 2.94, 80, 770000, 32200, 10, 113, 2, 2}, /* entries below due to Thomas Denny, never tested */ { /*92*/ 3.6, 90, 2000000, 35000, 9, 113, 2, 2}, { /*93*/ 3.7, 90, 2000000, 37000, 9, 113, 2, 2}, { /*94*/ 3.7, 90, 2000000, 39500, 9, 127, 2, 2}, { /*95*/ 3.7, 90, 2500000, 41500, 9, 127, 2, 2}, { /*96*/ 3.8, 90, 2500000, 45000, 10, 127, 2, 2}, { /*97*/ 3.8, 90, 2500000, 47500, 10, 131, 2, 2}, { /*98*/ 3.7, 90, 3000000, 51000, 10, 131, 2, 2}, { /*99*/ 3.8, 90, 3000000, 53000, 10, 133, 2, 2}, {/*100*/ 3.8, 90, 3500000, 51000, 10, 133, 2, 2}, {/*101*/ 3.8, 90, 3500000, 54000, 10, 139, 2, 2}, {/*102*/ 3.8, 90, 3500000, 57000, 10, 139, 2, 2}, {/*103*/ 3.9, 90, 4000000, 61000, 10, 139, 2, 2}, {/*104*/ 3.9, 90, 4000000, 66000, 10, 149, 2, 2}, {/*105*/ 3.9, 90, 4000000, 70000, 10, 149, 2, 2}, {/*106*/ 3.9, 90, 4000000, 75000, 10, 151, 2, 2}, {/*107*/ 3.9, 90, 4000000, 80000, 10, 151, 2, 2}, }; #define MPQS_MAX_DIGIT_SIZE_KN 107 pari-2.11.2/src/modules/forsubset.c0000644000175000017500000000432413326135265015606 0ustar billbill/* Copyright (C) 2017 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" void forksubset_init(forsubset_t *T, long n, long k) { T->all = 0; T->first = 1; T->n = n; T->k = k; T->v = identity_perm(k); } void forallsubset_init(forsubset_t *T, long n) { T->all = 1; T->first = 1; T->n = n; T->k = 0; T->v = vecsmalltrunc_init(n + 1); } static GEN forksubset_next(forsubset_t *T) { GEN v = T->v; long i, n = T->n, k = T->k; if (T->first) { T->first = 0; return (k >= 0 && k <= n) ? v: NULL; } if (k <= 0 || k >= n) return NULL; if (v[k] < n) { v[k]++; return v; } for (i = k - 1; i >= 1 && v[i+1] == v[i] + 1; i--); if (i == 0) return NULL; v[i]++; for (; i < k; i++) v[i+1] = v[i] + 1; return v; } static GEN forallsubset_next(forsubset_t *T) { long i; if (forksubset_next(T)) return T->v; else if (T->k < T->n) { (T->k)++; setlg(T->v, T->k+1); for (i = 1; i <= T->k; i++) (T->v)[i] = i; return T->v; } return NULL; } GEN forsubset_next(forsubset_t *T) { return T->all? forallsubset_next(T): forksubset_next(T); } void forsubset_init(forsubset_t *T, GEN nk) { switch(typ(nk)) { case t_INT: forallsubset_init(T, itos(nk)); return; case t_VEC: if (lg(nk) == 3) { GEN n = gel(nk,1), k = gel(nk,2); if (typ(n) == t_INT && typ(k) == t_INT) return forksubset_init(T, itos(n),itos(k)); } default: pari_err_TYPE("forsubset", nk); } } void forsubset0(GEN nk, GEN code) { pari_sp av = avma; forsubset_t T; void *E = (void*)code; GEN v; push_lex(gen_0, code); forsubset_init(&T, nk); while ((v = forsubset_next(&T))) if (gp_evalvoid(E, v)) break; pop_lex(1); avma = av; } pari-2.11.2/src/modules/genus2red.c0000644000175000017500000020550313326135265015472 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "pari.h" #include "paripriv.h" /********************************************************************/ /** **/ /** IGUSA INVARIANTS **/ /** (GP2C-generated) **/ /** **/ /********************************************************************/ /* j2(a0,a1,a2,a3,a4,a5,a6) = (-120*a0*a6+20*a1*a5-8*a2*a4+3*a3^2) / 4; */ static GEN igusaj2(GEN a0, GEN a1, GEN a2, GEN a3, GEN a4, GEN a5, GEN a6) { pari_sp av = avma; return gerepileupto(av, gmul2n(gadd(gsub(gadd(gmul(gmulsg(-120, a0), a6), gmul(gmulsg(20, a1), a5)), gmul(gmulsg(8, a2), a4)), gmulsg(3, gsqr(a3))), -2)); } /* j4(a0,a1,a2,a3,a4,a5,a6) = (240*(a0*a3*a4*a5+a1*a2*a3*a6)-400*(a0*a2*a5^2+a1^2*a4*a6)-64*(a0*a4^3+a2^3*a6)+16*(a1*a3*a4^2+a2^2*a3*a5)-672*a0*a3^2*a6+240*a1^2*a5^2-112*a1*a2*a4*a5-8*a1*a3^2*a5+16*a2^2*a4^2-16*a2*a3^2*a4+3*a3^4+2640*a0^2*a6^2-880*a0*a1*a5*a6+1312*a0*a2*a4*a6) / 2^7 */ static GEN igusaj4(GEN a0, GEN a1, GEN a2, GEN a3, GEN a4, GEN a5, GEN a6) { pari_sp av = avma; return gerepileupto(av, gmul2n(gadd(gsub(gadd(gadd(gsub(gadd(gsub(gsub(gadd(gsub(gadd(gsub(gsub(gmulsg(240, gadd(gmul(gmul(gmul(a0, a3), a4), a5), gmul(gmul(gmul(a1, a2), a3), a6))), gmulsg(400, gadd(gmul(gmul(a0, a2), gsqr(a5)), gmul(gmul(gsqr(a1), a4), a6)))), gmulsg(64, gadd(gmul(a0, gpowgs(a4, 3)), gmul(gpowgs(a2, 3), a6)))), gmulsg(16, gadd(gmul(gmul(a1, a3), gsqr(a4)), gmul(gmul(gsqr(a2), a3), a5)))), gmul(gmul(gmulsg(672, a0), gsqr(a3)), a6)), gmul(gmulsg(240, gsqr(a1)), gsqr(a5))), gmul(gmul(gmul(gmulsg(112, a1), a2), a4), a5)), gmul(gmul(gmulsg(8, a1), gsqr(a3)), a5)), gmul(gmulsg(16, gsqr(a2)), gsqr(a4))), gmul(gmul(gmulsg(16, a2), gsqr(a3)), a4)), gmulsg(3, gpowgs(a3, 4))), gmul(gmulsg(2640, gsqr(a0)), gsqr(a6))), gmul(gmul(gmul(gmulsg(880, a0), a1), a5), a6)), gmul(gmul(gmul(gmulsg(1312, a0), a2), a4), a6)), -7)); } /* j6(a0,a1,a2,a3,a4,a5,a6) = (1600*(a0^2*a4^2*a5^2+a1^2*a2^2*a6^2)+1600*(a0*a1*a2*a5^3+a1^3*a4*a5*a6)+640*(a0*a1*a3*a4*a5^2+a1^2*a2*a3*a5*a6)-4000*(a0^2*a3*a5^3+a1^3*a3*a6^2)-384*(a0*a1*a4^3*a5+a1*a2^3*a5*a6)-640*(a0*a2^2*a4*a5^2+a1^2*a2*a4^2*a6)+80*(a0*a2*a3^2*a5^2+a1^2*a3^2*a4*a6)+192*(a0*a2*a3*a4^2*a5+a1*a2^2*a3*a4*a6)-48*(a0*a3^3*a4*a5+a1*a2*a3^3*a6)-224*(a1^2*a3*a4^2*a5+a1*a2^2*a3*a5^2)+64*(a1^2*a4^4+a2^4*a5^2)-64*(a1*a2*a3*a4^3+a2^3*a3*a4*a5)+16*(a1*a3^3*a4^2+a2^2*a3^3*a5)-4096*(a0^2*a4^3*a6+a0*a2^3*a6^2)+6400*(a0^2*a2*a5^2*a6+a0*a1^2*a4*a6^2)+10560*(a0^2*a3*a4*a5*a6+a0*a1*a2*a3*a6^2)+2624*(a0*a1*a3*a4^2*a6+a0*a2^2*a3*a5*a6)-4432*a0*a1*a3^2*a5*a6-8*a2*a3^4*a4+a3^6-320*a1^3*a5^3+64*a1^2*a2*a4*a5^2+176*a1^2*a3^2*a5^2+128*a1*a2^2*a4^2*a5+112*a1*a2*a3^2*a4*a5-28*a1*a3^4*a5+16*a2^2*a3^2*a4^2+5120*a0^3*a6^3-2544*a0^2*a3^2*a6^2+312*a0*a3^4*a6-14336*a0^2*a2*a4*a6^2+1024*a0*a2^2*a4^2*a6-2560*a0^2*a1*a5*a6^2-2240*a0*a1^2*a5^2*a6-6528*a0*a1*a2*a4*a5*a6-1568*a0*a2*a3^2*a4*a6) / 2^10 */ static GEN igusaj6(GEN a0, GEN a1, GEN a2, GEN a3, GEN a4, GEN a5, GEN a6) { pari_sp av = avma; return gerepileupto(av, gmul2n(gsub(gsub(gsub(gsub(gadd(gsub(gadd(gsub(gadd(gadd(gsub(gadd(gadd(gadd(gadd(gsub(gadd(gsub(gsub(gadd(gadd(gadd(gsub(gadd(gsub(gadd(gsub(gsub(gadd(gadd(gsub(gsub(gsub(gadd(gadd(gmulsg(1600, gadd(gmul(gmul(gsqr(a0), gsqr(a4)), gsqr(a5)), gmul(gmul(gsqr(a1), gsqr(a2)), gsqr(a6)))), gmulsg(1600, gadd(gmul(gmul(gmul(a0, a1), a2), gpowgs(a5, 3)), gmul(gmul(gmul(gpowgs(a1, 3), a4), a5), a6)))), gmulsg(640, gadd(gmul(gmul(gmul(gmul(a0, a1), a3), a4), gsqr(a5)), gmul(gmul(gmul(gmul(gsqr(a1), a2), a3), a5), a6)))), gmulsg(4000, gadd(gmul(gmul(gsqr(a0), a3), gpowgs(a5, 3)), gmul(gmul(gpowgs(a1, 3), a3), gsqr(a6))))), gmulsg(384, gadd(gmul(gmul(gmul(a0, a1), gpowgs(a4, 3)), a5), gmul(gmul(gmul(a1, gpowgs(a2, 3)), a5), a6)))), gmulsg(640, gadd(gmul(gmul(gmul(a0, gsqr(a2)), a4), gsqr(a5)), gmul(gmul(gmul(gsqr(a1), a2), gsqr(a4)), a6)))), gmulsg(80, gadd(gmul(gmul(gmul(a0, a2), gsqr(a3)), gsqr(a5)), gmul(gmul(gmul(gsqr(a1), gsqr(a3)), a4), a6)))), gmulsg(192, gadd(gmul(gmul(gmul(gmul(a0, a2), a3), gsqr(a4)), a5), gmul(gmul(gmul(gmul(a1, gsqr(a2)), a3), a4), a6)))), gmulsg(48, gadd(gmul(gmul(gmul(a0, gpowgs(a3, 3)), a4), a5), gmul(gmul(gmul(a1, a2), gpowgs(a3, 3)), a6)))), gmulsg(224, gadd(gmul(gmul(gmul(gsqr(a1), a3), gsqr(a4)), a5), gmul(gmul(gmul(a1, gsqr(a2)), a3), gsqr(a5))))), gmulsg(64, gadd(gmul(gsqr(a1), gpowgs(a4, 4)), gmul(gpowgs(a2, 4), gsqr(a5))))), gmulsg(64, gadd(gmul(gmul(gmul(a1, a2), a3), gpowgs(a4, 3)), gmul(gmul(gmul(gpowgs(a2, 3), a3), a4), a5)))), gmulsg(16, gadd(gmul(gmul(a1, gpowgs(a3, 3)), gsqr(a4)), gmul(gmul(gsqr(a2), gpowgs(a3, 3)), a5)))), gmulsg(4096, gadd(gmul(gmul(gsqr(a0), gpowgs(a4, 3)), a6), gmul(gmul(a0, gpowgs(a2, 3)), gsqr(a6))))), gmulsg(6400, gadd(gmul(gmul(gmul(gsqr(a0), a2), gsqr(a5)), a6), gmul(gmul(gmul(a0, gsqr(a1)), a4), gsqr(a6))))), gmulsg(10560, gadd(gmul(gmul(gmul(gmul(gsqr(a0), a3), a4), a5), a6), gmul(gmul(gmul(gmul(a0, a1), a2), a3), gsqr(a6))))), gmulsg(2624, gadd(gmul(gmul(gmul(gmul(a0, a1), a3), gsqr(a4)), a6), gmul(gmul(gmul(gmul(a0, gsqr(a2)), a3), a5), a6)))), gmul(gmul(gmul(gmul(gmulsg(4432, a0), a1), gsqr(a3)), a5), a6)), gmul(gmul(gmulsg(8, a2), gpowgs(a3, 4)), a4)), gpowgs(a3, 6)), gmul(gmulsg(320, gpowgs(a1, 3)), gpowgs(a5, 3))), gmul(gmul(gmul(gmulsg(64, gsqr(a1)), a2), a4), gsqr(a5))), gmul(gmul(gmulsg(176, gsqr(a1)), gsqr(a3)), gsqr(a5))), gmul(gmul(gmul(gmulsg(128, a1), gsqr(a2)), gsqr(a4)), a5)), gmul(gmul(gmul(gmul(gmulsg(112, a1), a2), gsqr(a3)), a4), a5)), gmul(gmul(gmulsg(28, a1), gpowgs(a3, 4)), a5)), gmul(gmul(gmulsg(16, gsqr(a2)), gsqr(a3)), gsqr(a4))), gmul(gmulsg(5120, gpowgs(a0, 3)), gpowgs(a6, 3))), gmul(gmul(gmulsg(2544, gsqr(a0)), gsqr(a3)), gsqr(a6))), gmul(gmul(gmulsg(312, a0), gpowgs(a3, 4)), a6)), gmul(gmul(gmul(gmulsg(14336, gsqr(a0)), a2), a4), gsqr(a6))), gmul(gmul(gmul(gmulsg(1024, a0), gsqr(a2)), gsqr(a4)), a6)), gmul(gmul(gmul(gmulsg(2560, gsqr(a0)), a1), a5), gsqr(a6))), gmul(gmul(gmul(gmulsg(2240, a0), gsqr(a1)), gsqr(a5)), a6)), gmul(gmul(gmul(gmul(gmul(gmulsg(6528, a0), a1), a2), a4), a5), a6)), gmul(gmul(gmul(gmul(gmulsg(1568, a0), a2), gsqr(a3)), a4), a6)), -10)); } /********************************************************************/ /** **/ /** A REDUCTION ALGORITHM "A LA TATE" FOR CURVES OF GENUS 2 **/ /** **/ /********************************************************************/ /* Based on genus2reduction-0.3, http://www.math.u-bordeaux.fr/~liu/G2R/ * by Qing Liu * and Henri Cohen * Qing Liu: Modeles minimaux des courbes de genre deux * J. fuer die Reine und Angew. Math., 453 (1994), 137-164. * http://www.math.u-bordeaux.fr/~liu/articles/modregE.ps */ /* some auxiliary polynomials, gp2c-generated */ /* apol2(a0,a1,a2) = -5*a1^2+12*a0*a2; */ static GEN apol2(GEN a0, GEN a1, GEN a2) { return gadd(gmulsg(-5, gsqr(a1)), gmul(gmulsg(12, a0), a2)); } /* apol3(a0,a1,a2,a3) = 5*a1^3+9*a0*(-2*a1*a2+3*a0*a3); */ static GEN apol3(GEN a0, GEN a1, GEN a2, GEN a3) { return gadd(gmulsg(5, gpowgs(a1, 3)), gmul(gmulsg(9, a0), gadd(gmul(gmulsg(-2, a1), a2), gmul(gmulsg(3, a0), a3)))); } /* apol5(a0,a1,a2,a3,a4,a5) = a1^5+3*a0*(-2*a1^3*a2+9*a0*a1^2*a3-36*a0^2*a1*a4+108*a0^3*a5); */ static GEN apol5(GEN a0, GEN a1, GEN a2, GEN a3, GEN a4, GEN a5) { return gadd(gpowgs(a1, 5), gmul(gmulsg(3, a0), gadd(gsub(gadd(gmul(gmulsg(-2, gpowgs(a1, 3)), a2), gmul(gmul(gmulsg(9, a0), gsqr(a1)), a3)), gmul(gmul(gmulsg(36, gsqr(a0)), a1), a4)), gmul(gmulsg(108, gpowgs(a0, 3)), a5)))); } /* bpol2(a0,a1,a2,a3,a4) = 2*a2^2-5*a1*a3+10*a0*a4; */ static GEN bpol2(GEN a0, GEN a1, GEN a2, GEN a3, GEN a4) { return gadd(gsub(gmulsg(2, gsqr(a2)), gmul(gmulsg(5, a1), a3)), gmul(gmulsg(10, a0), a4)); } static const long VERYBIG = (1L<<20); static long myval(GEN x, GEN p) { return signe(x)? Z_pval(x,p): VERYBIG; } static long my3val(GEN x) { return signe(x)? Z_lval(x,3): VERYBIG; } /* b in Z[i], return v_3(b) */ static long myval_zi(GEN b) { return minss(my3val(real_i(b)), my3val(imag_i(b))); } /* b in Z[i, Y]/(Y^2-3), return v_Y(b) */ static long myval_zi2(GEN b) { long v0, v1; b = lift_shallow(b); v0 = myval_zi(RgX_coeff(b,0)); v1 = myval_zi(RgX_coeff(b,1)); return minss(2*v0, 2*v1+1); } /* min(a,b,c) */ static long min3(long a, long b, long c) { long m = a; if (b < m) m = b; if (c < m) m = c; return m; } /* Vector of p-adic factors (over Q_p) to accuracy r of pol. */ static GEN padicfactors(GEN pol, GEN p, long r) { return gel(factorpadic(pol,p,r),1); } /* x(1/t)*t^6, deg x <= 6 */ static GEN RgX_recip6(GEN x) { long lx = lg(x), i, j; GEN y = cgetg(9, t_POL); y[1] = x[1]; for (i=8,j=2; j < lx; i--,j++) gel(y,i) = gel(x,j); for ( ; j < 9; i--,j++) gel(y,i) = gen_0; return normalizepol_lg(y, 9); } /* extract coefficients of a polynomial a0 X^6 + ... + a6, of degree <= 6 */ static void RgX_to_06(GEN q, GEN *a0, GEN *a1, GEN *a2, GEN *a3, GEN *a4, GEN *a5, GEN *a6) { *a0 = gen_0; *a1 = gen_0; *a2 = gen_0; *a3 = gen_0; *a4 = gen_0; *a5 = gen_0; *a6 = gen_0; switch(degpol(q)) { case 6: *a0 = gel(q,8); /*fall through*/ case 5: *a1 = gel(q,7); /*fall through*/ case 4: *a2 = gel(q,6); /*fall through*/ case 3: *a3 = gel(q,5); /*fall through*/ case 2: *a4 = gel(q,4); /*fall through*/ case 1: *a5 = gel(q,3); /*fall through*/ case 0: *a6 = gel(q,2); /*fall through*/ } } /* extract coefficients a0,...a3 of a polynomial a0 X^6 + ... + a6 */ static void RgX_to_03(GEN q, GEN *a0, GEN *a1, GEN *a2, GEN *a3) { *a0 = gen_0; *a1 = gen_0; *a2 = gen_0; *a3 = gen_0; switch(degpol(q)) { case 6: *a0 = gel(q,8); /*fall through*/ case 5: *a1 = gel(q,7); /*fall through*/ case 4: *a2 = gel(q,6); /*fall through*/ case 3: *a3 = gel(q,5); /*fall through*/ } } /* deg(H mod p) = 3, return v_p( disc(correspondig p-adic factor) ) */ static long discpart(GEN H, GEN p, long prec) { GEN list, prod, dis; long i, j; if (degpol(FpX_red(H,p)) != 3) pari_err_BUG("discpart [must not reach]"); /* LCOV_EXCL_LINE */ list = padicfactors(H,p,prec); prod = pol_1(varn(H)); for(i = 1; i < lg(list); i++) { GEN t = gel(list,i); for(j = 3; j < lg(t); j++) /* include if non-constant mod p */ if (!valp(gel(t,j))) { prod = RgX_mul(prod,t); break; } } if (degpol(prod) != 3) pari_err_BUG("discpart [prod degree]"); dis = RgX_disc(prod); return gequal0(dis)? prec+1: valp(dis); } /* B = b0 X^6 + ... + b6 a ZX, 0 <= j <= 3. * Let theta_j(H) := min { v_p(b_i) / (i - j), j < i <= 6 } >= 0. * Return 60 theta \in Z */ static long theta_j(GEN B, GEN p, long j) { long i, t = 60*myval(RgX_coeff(B,5-j), p); for(i = 2+j; i <= 6; i++) t = minss(t, myval(RgX_coeff(B,6-i), p) * (60 / (i-j))); return t; } /* compute 6 * theta_3 for B in Z[i][X], p = 3 */ static long theta_3_zi(GEN B) { long v2 = myval_zi(RgX_coeff(B,2)); long v1 = myval_zi(RgX_coeff(B,1)); long v0 = myval_zi(RgX_coeff(B,0)); return min3(6*v2, 3*v1, 2*v0); } /* compute 6 * theta_3 for B in (Z[i,Y]/(Y^2-3))[X], p = 3 */ static long theta_3_zi2(GEN B) { long v2 = myval_zi2(RgX_coeff(B,2)); long v1 = myval_zi2(RgX_coeff(B,1)); long v0 = myval_zi2(RgX_coeff(B,0)); return min3(6*v2, 3*v1, 2*v0); } /* Set maxord to the maximal multiplicity of a factor. If there is at least * a triple root (=> maxord >= 3) return it, else return NULL */ static GEN factmz(GEN Q, GEN p, long *maxord) { GEN z = FpX_factor_squarefree(Q, p); long m = lg(z)-1; /* maximal multiplicity */ *maxord = m; return (m >= 3)? FpX_oneroot(gel(z,m), p): NULL; } /* H integral ZX of degree 5 or 6, p > 2. Modify until * y^2 = p^alpha H is minimal over Z_p, alpha = 0,1 * Return [H,lambda,60*theta,alpha,quad,beta], where * - quad = 1 if H has a root of order 3 in F_p^2 \ F_p, 0 otherwise * - 0 <= lambda <= 3, index of a coefficient with valuation 0 * - theta = theta_j(H(x + r), p, lambda), 60*theta in Z, where r is a root * of H mod p * - beta >= -1 s.t. H = p^n H0(r + p^beta * X) for some n, r in Z, where * H0 is the initial H or polrecip(H) */ static GEN polymini(GEN H, GEN p) { GEN a0, a1, a2, a3, Hp, rac; long t60, alpha, lambda, maxord, quad = 0, beta = 0; alpha = ZX_pvalrem(H, p, &H) & 1; RgX_to_03(H, &a0,&a1,&a2,&a3); if (dvdii(a0,p) && dvdii(a1,p) && dvdii(a2,p) && dvdii(a3,p)) { H = RgX_recip6(H); RgX_to_03(H, &a0,&a1,&a2,&a3); } if (!dvdii(a3,p)) lambda = 3; else if (!dvdii(a2,p)) lambda = 2; else if (!dvdii(a1,p)) lambda = 1; else lambda = 0; for(;;) { /* lambda <= 3, t60 = 60*theta */ long e; t60 = theta_j(H,p,lambda); e = t60 / 60; if (e) { GEN pe = powiu(p,e); /* H <- H(p^e X) / p^(e(6-lambda)) */ H = ZX_Z_divexact(ZX_unscale_div(H,pe), powiu(pe,5-lambda)); alpha = (alpha + lambda*e)&1; beta += e; t60 -= 60*e; } /* 0 <= t < 60 */ Hp = FpX_red(H, p); if (t60) break; rac = factmz(Hp,p, &maxord); if (maxord <= 2) { if (degpol(Hp) <= 3) break; goto end; } else { /* maxord >= 3 */ if (!rac) { quad = 1; goto end; } if (signe(rac)) H = ZX_translate(H, rac); lambda = 6-maxord; } } if (lambda <= 2) { if (myval(RgX_coeff(H,2),p) > 1-alpha && myval(RgX_coeff(H,1),p) > 2-alpha && myval(RgX_coeff(H,0),p) > 3-alpha) { H = ZX_unscale(H, p); if (alpha) H = ZX_Z_mul(H, p); return polymini(H, p); } } else if (lambda == 3 && alpha == 1) { if (degpol(Hp) == 3) { if (myval(RgX_coeff(H,6),p) >= 3 && myval(RgX_coeff(H,5),p) >= 2) { /* too close to root [Kodaira symbol for y^2 = p^alpha*H not implemented when alpha = 1]: go back one step */ H = ZX_rescale(H, p); /* H(x/p)p^(deg H) */ H = ZX_Z_divexact(H, powiu(p, degpol(H)-3)); /* H(x/p)p^3 */ t60 += 60; alpha = 0; beta--; } } else if (degpol(Hp) == 6 && t60) { rac = factmz(RgX_mulXn(Hp, -3), p, &maxord); if (maxord == 3) { GEN T = ZX_unscale(ZX_translate(H,rac),p); /* H(rac + px) */ if (ZX_pval(T,p)>= 3) { H = RgX_Rg_div(T, powiu(p,3)); alpha = 0; beta++; t60 = theta_j(H,p,3); if (!t60) { Hp = FpX_red(H, p); if (!signe(FpX_disc(Hp,p))) { rac = FpX_oneroot(Hp, p); t60 = theta_j(ZX_translate(H,rac),p,3); } } } } } } end: return mkvec2(H, mkvecsmall5(lambda,t60,alpha,quad,beta)); } /* a in Q[i], return a^3 mod 3 */ static GEN zi_pow3mod(GEN a) { GEN x, y; if (typ(a) != t_COMPLEX) return gmodgs(a,3); x = gmodgs(gel(a,1), 3); y = gmodgs(gel(a,2), 3); return mkcomplex(x, negi(y)); } static GEN polymini_zi(GEN pol) /* polynome minimal dans Z[i] */ { GEN polh, rac, a0, a1, a2, a3, a4, a5, a6, p = utoipos(3); long alpha, beta = 0, t6; alpha = ZX_pval(pol,p) & 1; polh = alpha? RgX_Rg_div(pol, p): pol; rac = mkcomplex(Fp_div(RgX_coeff(polh,3), RgX_coeff(polh,6), p), gen_1); for(;;) { long e; polh = RgX_translate(polh, rac); t6 = theta_3_zi(polh); e = t6 / 6; if (e) { GEN pe = powiu(p,e); polh = RgX_Rg_div(RgX_unscale(polh,pe), powiu(pe,3)); alpha = (alpha+e)&1; t6 -= e * 6; beta += e; } RgX_to_06(polh, &a0,&a1,&a2,&a3,&a4,&a5,&a6); if (t6 || !myval_zi(a4) || !myval_zi(a5)) break; rac = zi_pow3mod(gdiv(a6, gneg(a3))); } if (alpha && myval_zi(a0) >= 3 && myval_zi(a1) >= 2 && myval_zi(a2) >= 1) { t6 += 6; beta--; alpha = 0; } if (alpha && beta >= 1) pari_err_BUG("quadratic"); return mkvecsmall3(t6, alpha, beta); } /* pol is a ZX, minimal polynomial over Z_3[i,Y]/(Y^2-3) */ static GEN polymini_zi2(GEN pol) { long alpha, beta, t6; GEN a0, a1, a2, a3, a4, a5, a6; GEN polh, rac, y = pol_x(fetch_var()), p = utoipos(3); if (ZX_pval(pol,p)) pari_err_BUG("polymini_zi2 [polynomial not minimal]"); y = mkpolmod(y, gsubgs(gsqr(y), 3)); /* mod(y,y^2-3) */ polh = gdivgs(RgX_unscale(pol, y),27); /* H(y*x) / 27 */ if (myval_zi2(RgX_coeff(polh,4)) <= 0 || myval_zi2(RgX_coeff(polh,2)) <= 0) { (void)delete_var(); return mkvecsmall2(0,0); } if (myval_zi2(gsub(RgX_coeff(polh,6), RgX_coeff(polh,0))) > 0) rac = gen_I(); else rac = gen_1; alpha = 0; beta = 0; for(;;) { long e; polh = RgX_translate(polh, rac); t6 = theta_3_zi2(polh); e = t6 / 6; if (e) { GEN pent = gpowgs(y, e); polh = RgX_Rg_div(RgX_unscale(polh, pent), gpowgs(pent,3)); alpha = (alpha+e)&1; t6 -= 6*e; beta += e; } RgX_to_06(polh, &a0,&a1,&a2,&a3,&a4,&a5,&a6); if (t6 || !myval_zi2(a4) || !myval_zi2(a5)) break; a3 = liftpol_shallow(a3); if (typ(a3)==t_POL) a3 = RgX_coeff(a3,0); a6 = liftpol_shallow(a6); if (typ(a6)==t_POL) a6 = RgX_coeff(a6,0); rac = zi_pow3mod(gdiv(a6,gneg(a3))); } if (alpha) { if (myval_zi2(a0) < 3 || myval_zi2(a1) < 2 || myval_zi2(a2) < 1) pari_err_BUG("polymini_zi2 [alpha]"); t6 += 6; beta--; } (void)delete_var(); if (odd(beta)) pari_err_BUG("quartic [type over Z[i] must be [K-K-(2*m)]]"); return mkvecsmall2(t6, beta); } struct igusa { GEN j2, i4, j4, j6, j8, j10, i12; GEN a0, A2, A3, A5, B2; }; struct igusa_p { long eps, tt, r1, r2, tame; GEN p, stable, val, neron; const char *type; }; /* initialize Ip */ static void stable_reduction(struct igusa *I, struct igusa_p *Ip, GEN p) { static const long d[9] = { 0,60,30,30,20,15,12,10 }; /* 120 / deg(X) */ GEN j2 = I->j2, i4 = I->i4, j4 = I->j4, j6 = I->j6, j8 = I->j8; GEN val, J, v, Ieps, j10 = I->j10, i12 = I->i12; long s, r1, r2, r3, r4, i, eps; Ip->tame = 0; Ip->neron = NULL; Ip->type = NULL; Ip->p = p; Ip->val = val = cgetg(9, t_VECSMALL); val[1] = myval(j2,p); val[2] = myval(j4,p); val[3] = myval(i4,p); val[4] = myval(j6,p); val[5] = myval(j8,p); val[6] = myval(j10,p); val[7] = myval(i12,p); switch(itos_or_0(p)) { case 2: eps = 4; val[8] = val[5]; Ieps = j8; break; case 3: eps = 3; val[8] = val[4]; Ieps = j6; break; default: eps = 1; val[8] = val[1]; Ieps = gdivgs(j2,12); break; } v = cgetg(8,t_VECSMALL); for(i = 1; i <= 7; i++) v[i] = val[i] * d[i]; s = vecsmall_min(v); Ip->eps = eps; r1 = 3*eps*val[3]; r3 = eps*val[6] + val[8]; r2 = eps*val[7]; r4 = min3(r1, r2, r3); /* s = max(v_p(X) / deg(X)) */ J = cgetg(1, t_VEC); if (s == v[6]) Ip->tt = 1; else if (s == v[7]) { J = mkvec( Fp_to_mod(gmod(gdiv(gpowgs(i4,3),i12), p), p) ); Ip->tt = 2; } else if (s == v[3]) Ip->tt = (val[2] == val[3] || 2*val[4] == 3*val[3])? 3: 4; else if (r3 == r4) { GEN a,b, P, sj, pj, t = gmul(gpowgs(j10,eps),Ieps); sj = gaddsg(1728, gdiv(gpowgs(i12,eps), t)); pj = gdiv(gpowgs(i4,3*eps), t); a = gmod(sj, p); b = gmod(pj, p); P = mkpoln(3, gen_1, Fp_neg(a,p), b, 0); /* X^2 - SX + P: roots j1,j2 */ J = FpX_roots(P, p); switch(lg(J)-1) { case 0: P = FpX_to_mod(P, p); a = FpX_to_mod(pol_x(0), p); b = FpX_to_mod(deg1pol_shallow(b, gen_m1,0), p); J = mkvec2(mkpolmod(a,P), mkpolmod(b,P)); break; case 1: a = Fp_to_mod(gel(J,1), p); J = mkvec2(a, a); break; case 2: settyp(J, t_VEC); J = FpV_to_mod(J, p); break; } Ip->tt = 5; } else if (r2 == r4) { J = mkvec( Fp_to_mod(gmod(gdiv(gpowgs(i4,3),i12), p), p) ); Ip->tt = 6; } else Ip->tt = 7; /* r1 == r4 */ Ip->stable = mkvec2(stoi(Ip->tt), J); } struct red { const char *t, *pages; double tnum; GEN g; }; /* destroy v */ static GEN zv_snf(GEN v) { long i, l = lg(v); for (i = 1; i < l; i++) { long j, a = v[i]; for (j = i+1; j < l; j++) { long b = v[j], d = ugcd(a,b); v[i] = a = a*(b/d); v[j] = d; } } for (i = l-1; i > 0; i--) if (v[i] != 1) { setlg(v, i+1); break; } return zv_to_ZV(v); } static GEN cyclic(long n) { return (n <= 1)? cgetg(1, t_VECSMALL): mkvecsmall(n); } static GEN dicyclic(long a, long b) { long d; if (!a) a = 1; if (!b) b = 1; if (a < b) lswap(a,b); d = ugcd(a,b); if (d == 1) return cyclic(a*b); return mkvecsmall2(a*b/d, d); } /* Z/2xZ/2, resp Z/4 for n even, resp. odd */ static GEN groupH(long n) { return odd(n)? cyclic(4): dicyclic(2,2); } static long get_red(struct red *S, struct igusa_p *Ip, GEN polh, GEN p, long alpha, long r) { GEN val = Ip->val; long indice; switch(r) { case 0: indice = FpX_is_squarefree(FpX_red(polh,p), p) ? 0 : val[6] - val[7] + val[8]/Ip->eps; S->t = stack_sprintf("I{%ld}", indice); S->tnum = 1; S->pages = "159-177"; S->g = cyclic(indice); return indice ? indice: 1; case 6: if (alpha == 0) /* H(px) /p^3 */ polh = ZX_Z_divexact(ZX_unscale_div(polh,p), sqri(p)); indice = FpX_is_squarefree(FpX_red(polh,p), p) ? 0 : val[6] - val[7] + val[8]/Ip->eps; S->t = stack_sprintf("I*{%ld}", indice); S->tnum = 1.5; S->pages = "159-177"; S->g = groupH(indice); return indice + 5; case 3: S->t = "III"; S->tnum = 3; S->pages = "161-177"; S->g = cyclic(2); return 2; case 9: S->t = "III*"; S->tnum = 3.5; S->pages = "162-177"; S->g = cyclic(2); return 8; case 2: S->t = "II"; S->tnum = 2; S->pages = "159-174"; S->g = cyclic(1); return 1; case 8: S->t = "IV*"; S->tnum = 4.5; S->pages = "160-175"; S->g = cyclic(3); return 7; case 4: S->t = "IV"; S->tnum = 4; S->pages = "160-174"; S->g = cyclic(3); return 3; case 10: S->t = "II*"; S->tnum = 2.5; S->pages = "160-174"; S->g = cyclic(1); return 9; default: pari_err_BUG("get_red [type]"); S->t = ""; S->tnum = 0; S->pages = ""; /* gcc -Wall */ S->g = NULL; return -1; /*LCOV_EXCL_LINE*/ } } /* reduce a/b; assume b > 0 */ static void ssQ_red(long a, long b, long *n, long *d) { long g = ugcd(labs(a), b); if (g > 1) { a /= g; b /= g; } *n = a; *d = b; } /* denom(a/b); assume b > 0 */ static long ssQ_denom(long a, long b) { long g = ugcd(labs(a), b); return g == 1? b: b / g; } /* n = lcm(d, denom(a/b)); r = (a/b * n mod n); assume b > 0 and d > 0 */ static void get_nr(long d, long a, long b, long *n, long *r) { long c, A, B; ssQ_red(a, b, &A,&B); c = d / ugcd(d, B); *n = B * c; *r = smodss(A * c, *n); } /* n = lcm(denom(a/b), denom(c/d)); r = (a/b * n mod n); q = (c/d * n mod n); * assume b > 0 and d > 0 */ static void get_nrq(long a, long b, long c, long d, long *n, long *r, long *q) { long g, A, B, C, D; ssQ_red(a, b, &A,&B); ssQ_red(c, d, &C,&D); g = ugcd(B,D); *n = B * (D/g); *r = smodss(A * (D/g), *n); *q = smodss(C * (B/g), *n); } /* Ip->tt = 1 */ static long tame_1(struct igusa *I, struct igusa_p *Ip) { GEN p = Ip->p, val = Ip->val; long condp = -1, va0, va5, r, n; va0 = myval(I->a0,p); va5 = myval(I->A5,p); if (!gequal0(I->A5) && 20*va0+val[6] > 6*va5) get_nr(ssQ_denom(5*val[6]-6*va5, 40), val[6]-2*va5, 20, &n,&r); else get_nr(ssQ_denom(5*va0-val[6], 10), 10*va0-val[6], 30, &n,&r); switch(n) { case 1: condp = 0; Ip->type = "[I{0-0-0}] page 155"; Ip->neron = cyclic(1); break; case 2: switch(r) { case 0: condp = 4; Ip->type = "[I*{0-0-0}] page 155"; Ip->neron = mkvecsmall4(2,2,2,2); break; case 1: condp = 2; Ip->type = "[II] page 155"; Ip->neron = cyclic(1); break; default: pari_err_BUG("tame_1 [bug1]"); } break; case 4: condp = 4; Ip->type = "[VI] page 156"; Ip->neron = dicyclic(2,2); break; default: pari_err_BUG("tame_1 [bug8]"); } return condp; } /* (4.2) */ static long tame_234_init(struct igusa *I, struct igusa_p *Ip, long *n, long *q, long *r) { long va0, va5, vb2, v12 = -1, flc = 1; GEN p = Ip->p; switch(Ip->tt) { case 2: v12 = myval(I->i12, Ip->p); break; case 3: v12 = 3*myval(I->i4, Ip->p); break; case 4: v12 = 6*myval(I->j2, Ip->p); break; } va0 = myval(I->a0,p); va5 = myval(I->A5,p); vb2 = myval(I->B2,p); if (9*vb2 >= 6*va0+v12 && 36*va5 >= 120*va0+5*v12) { get_nrq(12*va0-v12,36, 6*va0-v12,12, n, r, q); } else if (120*va0+5*v12 > 36*va5 && 60*vb2 >= 12*va5+5*v12) { ssQ_red(36*va5-25*v12,240, q,n); *r = smodss(-2* *q, *n); } else /* 6*va0+v12 > 9*vb2 && 12*va5+5*v12 > 60*vb2 */ { get_nrq(v12-6*vb2,12, v12-9*vb2,12, n,r,q); flc = 0; } return flc; } /* Ip->tt = 2 */ static long tame_2(struct igusa *I, struct igusa_p *Ip) { long condp = -1, d, n, q, r; GEN val = Ip->val; (void)tame_234_init(I, Ip, &n, &q, &r); d = n * (6*val[6]-5*val[7]) / 6; switch(n) { case 1: condp = 1; Ip->type = stack_sprintf("[I{%ld-0-0}] page 170", d); Ip->neron = cyclic(d); break; case 2: switch(r) { case 0: condp = 4; Ip->type = stack_sprintf("[I*{%ld-0-0}] page 171",d/2); Ip->neron = shallowconcat(dicyclic(2,2),groupH(d/2)); break; case 1: switch(q) { case 0: condp = 2; Ip->type = stack_sprintf("[II*{%ld-0}] page 172",d/2); Ip->neron = cyclic(1); break; case 1: condp = 3; Ip->type = stack_sprintf("[II{%ld-0}] page 171",d/2); Ip->neron = cyclic(2*d); break; default: pari_err_BUG("tame2 [bug10]"); } break; default: pari_err_BUG("tame2 [bug11]"); } break; case 3: condp = 3; Ip->neron = cyclic(d); switch(r) { case 1: Ip->type = stack_sprintf("[II{%ld}-IV] page 175", (d-2)/3); break; case 2: Ip->type = stack_sprintf("[II{%ld}-IV*] page 175", (d-1)/3); break; default: pari_err_BUG("tame2 [bug12]"); } break; case 4: switch(r) { case 1: switch(q) { case 1: condp = 3; Ip->type = stack_sprintf("[II{%ld}-III] page 177",(d-2)/4); Ip->neron = cyclic(d/2); break; case 3: condp = 4; Ip->type = stack_sprintf("[II*{%ld}-III*] page 178",(d-2)/4); Ip->neron = cyclic(8); break; default: pari_err_BUG("tame2 [bug13]"); } break; case 3: switch(q) { case 1: condp = 4; Ip->type = stack_sprintf("[II*{%ld}-III] page 178",(d-2)/4); Ip->neron = cyclic(8); break; case 3: condp = 3; Ip->type = stack_sprintf("[II{%ld}-III*] page 178",(d-2)/4); Ip->neron = cyclic(d/2); break; default: pari_err_BUG("tame2 [bug14]"); } break; default: pari_err_BUG("tame2 [bug15]"); } break; case 6: switch(r) { case 2: condp = 4; Ip->type = stack_sprintf("[II*-II*{%ld}] page 176", (d-4)/6); Ip->neron = groupH((d+2)/6); break; case 4: condp = 4; Ip->type = stack_sprintf("[II-II*{%ld}] page 176", (d-2)/6); Ip->neron = groupH((d+4)/6); break; default: pari_err_BUG("tame2 [bug16]"); } break; default: pari_err_BUG("tame2 [bug17]"); } return condp; } /* Ip->tt = 3 */ static long tame_3(struct igusa *I, struct igusa_p *Ip) { long condp = -1, n, q, r, va5, d1, d2; long flc = tame_234_init(I, Ip, &n, &q, &r); GEN val = Ip->val; va5 = 2*val[6]-5*val[3]; d1 = minss(n * (val[7]-3*val[3]), n * va5 / 4); d2 = n * va5 / 2 - d1; switch(n) { case 1: condp = 2; Ip->type = stack_sprintf("[I{%ld-%ld-0}] page 179", d1,d2); Ip->neron = dicyclic(d1,d2); break; case 2: switch(r) { case 0: condp = 4; Ip->type = stack_sprintf("[I*{%ld-%ld-0}] page 180", d1/2,d2/2); Ip->neron = shallowconcat(groupH(d1/2),groupH(d2/2)); break; case 1: condp = 3; if (flc) { Ip->type = stack_sprintf("[2I{%ld}-0] page 181", d1); Ip->neron = cyclic(d1); } else { /* FIXME: "or" same with d1<->d2 */ Ip->type = stack_sprintf("[II{%ld-%ld}] page 182",d1/2,d2/2); Ip->neron = ((d1*d2-4)&7)? cyclic(2*d1): dicyclic(d1,2); } break; default: pari_err_BUG("tame3 [bug20]"); } break; case 4: condp = 4; Ip->type = stack_sprintf("[III{%ld}] page 182", d1/2); Ip->neron = groupH(d1/2); break; default: pari_err_BUG("tame3 [bug21]"); } return condp; } /* Ip->tt = 4 */ static long tame_4(struct igusa *I, struct igusa_p *Ip) { long condp = -1, d1,d2,d3, f1,f2, g, h, n, q, r, vl,vn,vm, e1,e2,e3; GEN val = Ip->val; (void)tame_234_init(I, Ip, &n, &q, &r); vl = val[6]-5*val[1]; vn = val[7]-6*val[1]; vm = val[2]-2*val[1]; /* all >= 0 */ e1 = min3(2*vl, 3*vn, 6*vm); e2 = minss(6*vl - e1, 12*vn - 2*e1); /* >= 0 */ e3 = 12*vl - (2*e1+e2); /* >= 0 */ d1 = e1*n / 6; d2 = e2*n / 12; d3 = e3*n / 12; g = d1*d2 + d1*d3 + d2*d3; h = ugcd(ugcd(d1,d2),d3); switch(n) { case 1: condp = 2; Ip->type = stack_sprintf("[I{%ld-%ld-%ld}] page 182",d1,d2,d3); Ip->neron = dicyclic(h,g/h); break; case 2: switch(r) { case 0: condp = 4; Ip->type = stack_sprintf("[I*{%ld-%ld-%ld}] page 183",d1/2,d2/2,d3/2); Ip->neron = shallowconcat(groupH(g/4), groupH(2-((h&2)>>1))); break; case 1: if (d1 == d2 || d1 == d3) f2 = d1; else if (d2 == d3) f2 = d2; else { pari_err_BUG("tame4 [bug23]"); return -1; /*LCOV_EXCL_LINE*/ } f1 = d1+d2+d3-2*f2; switch(q) { case 0: condp = 3; Ip->type = stack_sprintf("[II*{%ld-%ld}] page 184", f1/2,f2); Ip->neron = cyclic(f2); break; case 1: condp = 3; Ip->type = stack_sprintf("[II{%ld-%ld}] page 183", f1/2,f2); Ip->neron = cyclic(2*f1+f2); break; default: pari_err_BUG("tame4 [bug24]"); } break; default: pari_err_BUG("tame4 [bug25]"); } break; case 3: condp = 4; Ip->type = stack_sprintf("[III{%ld}] page 184",d1); Ip->neron = (d1%3)? cyclic(9): dicyclic(3,3); break; case 6: condp = 4; Ip->type = stack_sprintf("[III*{%ld}] page 184",d1/2); Ip->neron = cyclic(1); break; default: pari_err_BUG("tame4 [bug26]"); } return condp; } /* p = 3 */ static void tame_567_init_3(struct igusa_p *Ip, long dk, long *pd, long *pn, long *pdm, long *pr) { long n = 1 + Ip->r1/6; *pd = n * dk / 36; /* / (12*Ip->eps) */ *pn = n; *pr = -1; /* unused */ *pdm = 0; } /* (4.3) */ static void tame_567_init(struct igusa *I, struct igusa_p *Ip, long dk, long *pd, long *pn, long *pdm, long *pr) { long ndk, ddk; GEN p = Ip->p, val = Ip->val; if (equaliu(p,3)) { tame_567_init_3(Ip, dk, pd, pn, pdm, pr); return; } /* assume p > 3, Ip->eps = 1 */ ssQ_red(dk, 12, &ndk, &ddk); if (! odd(val[8])) { long va0 = myval(I->a0,p), va2 = myval(I->A2,p), va3 = myval(I->A3,p); long va5 = myval(I->A5,p), vb2 = myval(I->B2,p); long v1 = 2*va3-4*va0-val[1], v2 = 6*va5-20*va0-5*val[1]; long v3 = 3*vb2-2*va0-2*val[1], v4 = 10*vb2-2*va5-5*val[1]; if (v3 >= 0 && v2 >= 0 && v1 >= 0) { if (v1==0 || v2==0) get_nr(ddk, va0+val[1], 6,pn,pr); /* Prop 4.3.1 (a) */ else { /* Prop 4.3.1 (d) */ long v5 = myval(subii(mulii(I->A2,I->A3),mului(3,I->A5)),p); if (gequal0(I->A2)) pari_err_BUG("tame567 [bug27]"); get_nr(ddk, 12*va0 + min3(dk, 6*va3-9*va2, 4*v5 - 10*va2), 24, pn,pr); } } else if (v2 < 0 && v4 >= 0) get_nr(ddk, 2*va5+val[1], 8, pn,pr); /* Prop 4.3.1 (b) */ else /* (v3 < 0 && v4 < 0) */ get_nr(ddk, vb2, 4, pn,pr); /* Prop 4.3.1 (c) */ *pd = (*pn/ddk) * ndk; } else { *pr = ndk; *pn = 2*ddk; *pd = 2*ndk; } *pdm = smodss(*pd, *pn); } static long tame_5(struct igusa *I, struct igusa_p *Ip) { long condp = -1, d, n, dm, r, dk; GEN val = Ip->val; dk = Ip->eps*val[6]-5*val[8]; tame_567_init(I, Ip, dk, &d, &n, &dm, &r); if (! odd(val[8])) { switch(n) { case 1: condp = 0; Ip->type = stack_sprintf("[I{0}-I{0}-%ld] page 158", d); Ip->neron = cyclic(1); break; case 2: switch(dm) { case 0: condp = 4; Ip->type = stack_sprintf("[I*{0}-I*{0}-%ld] page 158",(d-2)/2); Ip->neron = mkvecsmall4(2,2,2,2); break; case 1: condp = 2; Ip->type = stack_sprintf("[I{0}-I*{0}-%ld] page 159",(d-1)/2); Ip->neron = dicyclic(2,2); break; } break; case 3: switch(dm) { case 0: condp = 4; Ip->type = stack_sprintf("[IV-IV*-%ld] page 165",(d-3)/3); Ip->neron = dicyclic(3,3); break; case 1: switch(r) { case 0: case 1: condp = 2; Ip->type = stack_sprintf("[I{0}-IV-%ld] page 160",(d-1)/3); Ip->neron = cyclic(3); break; case 2: condp = 4; Ip->type = stack_sprintf("[IV*-IV*-%ld] page 166",(d-4)/3); Ip->neron = dicyclic(3,3); break; } break; case 2: switch(r) { case 0: case 2: condp = 2; Ip->type = stack_sprintf("[I{0}-IV*-%ld] page 160",(d-2)/3); Ip->neron = cyclic(3); break; case 1: condp = 4; Ip->type = stack_sprintf("[IV-IV-%ld] page 165",(d-2)/3); Ip->neron = dicyclic(3,3); break; } break; } break; case 4: switch(dm) { case 0: condp = 4; Ip->type = stack_sprintf("[III-III*-%ld] page 169",(d-4)/4); Ip->neron = dicyclic(2,2); break; case 1: switch(r) { case 0: case 1: condp = 2; Ip->type = stack_sprintf("[I{0}-III-%ld] page 161",(d-1)/4); Ip->neron = cyclic(2); break; case 2: case 3: condp = 4; Ip->type = stack_sprintf("[I*{0}-III*-%ld] page 162",(d-5)/4); Ip->neron = mkvecsmall3(2,2,2); break; } break; case 2: condp = 4; Ip->neron = dicyclic(2,2); switch(r) { case 1: Ip->type = stack_sprintf("[III-III-%ld] page 169",(d-2)/4); break; case 3: Ip->type = stack_sprintf("[III*-III*-%ld] page 169",(d-6)/4); break; default: pari_err_BUG("tame5 [bug29]"); } break; case 3: switch(r) { case 0: case 3: condp = 2; Ip->type = stack_sprintf("[I{0}-III*-%ld] page 162",(d-3)/4); Ip->neron = cyclic(2); break; case 1: case 2: condp = 4; Ip->type = stack_sprintf("[I*{0}-III-%ld] page 162",(d-3)/4); Ip->neron = mkvecsmall3(2,2,2); break; } break; } break; case 6: switch(dm) { case 0: condp = 4; Ip->type = stack_sprintf("[II-II*-%ld] page 163",(d-6)/6); Ip->neron = cyclic(1); break; case 1: switch(r) { case 0: case 1: condp = 2; Ip->type = stack_sprintf("[I{0}-II-%ld] page 159",(d-1)/6); Ip->neron = cyclic(1); break; case 2: case 5: condp = 4; Ip->type = stack_sprintf("[II*-IV-%ld] page 164",(d-7)/6); Ip->neron = cyclic(3); break; case 3: case 4: condp = 4; Ip->type = stack_sprintf("[I*{0}-IV*-%ld] page 161",(d-7)/6); Ip->neron = mkvecsmall2(6,2); break; } break; case 2: switch(r) { case 1: condp = 4; Ip->type = stack_sprintf("[II-II-%ld] page 163",(d-2)/6); Ip->neron = cyclic(1); break; case 3: case 5: condp = 4; Ip->type = stack_sprintf("[I*{0}-II*-%ld] page 160",(d-8)/6); Ip->neron = dicyclic(2,2); break; default: pari_err_BUG("tame5 [bug30]"); } break; case 3: Ip->neron = cyclic(3); switch(r) { case 1: case 2: condp = 4; Ip->type = stack_sprintf("[II-IV-%ld] page 164",(d-3)/6); break; case 4: case 5: condp = 4; Ip->type = stack_sprintf("[II*-IV*-%ld] page 164",(d-9)/6); break; default: pari_err_BUG("tame5 [bug31]"); } break; case 4: switch(r) { case 1: case 3: condp = 4; Ip->type = stack_sprintf("[I*{0}-II-%ld] page 160",(d-4)/6); Ip->neron = dicyclic(2,2); break; case 5: condp = 4; Ip->type = stack_sprintf("[II*-II*-%ld] page 163",(d-10)/6); Ip->neron = cyclic(1); break; default: pari_err_BUG("tame5 [bug32]"); } break; case 5: switch(r) { case 0: case 5: condp = 2; Ip->type = stack_sprintf("[I{0}-II*-%ld] page 160",(d-5)/6); Ip->neron = cyclic(1); break; case 1: case 4: condp = 4; Ip->type = stack_sprintf("[II-IV*-%ld] page 164",(d-5)/6); Ip->neron = cyclic(3); break; case 2: case 3: condp = 4; Ip->type = stack_sprintf("[I*{0}-IV-%ld] page 161",(d-5)/6); Ip->neron = mkvecsmall2(6,2); break; } break; default: pari_err_BUG("tame5 [bug33]"); } break; case 12: condp = 4; switch(dm) { case 1: switch(r) { case 3: case 10: Ip->type = stack_sprintf("[II*-III-%ld] page 166",(d-13)/12); Ip->neron = cyclic(2); break; case 4: case 9: Ip->type = stack_sprintf("[III*-IV-%ld] page 167",(d-13)/12); Ip->neron = cyclic(6); break; default: pari_err_BUG("tame5 [bug34]"); } break; case 5: switch(r) { case 2: case 3: Ip->type = stack_sprintf("[II-III-%ld] page 166",(d-5)/12); Ip->neron = cyclic(2); break; case 8: case 9: Ip->type = stack_sprintf("[III*-IV*-%ld] page 168",(d-17)/12); Ip->neron = cyclic(6); break; default: pari_err_BUG("tame5 [bug35]"); } break; case 7: switch(r) { case 3: case 4: Ip->type = stack_sprintf("[III-IV-%ld] page 167",(d-7)/12); Ip->neron = cyclic(6); break; case 9: case 10: Ip->type = stack_sprintf("[II*-III*-%ld] page 167",(d-19)/12); Ip->neron = cyclic(2); break; default: pari_err_BUG("tame5 [bug36]"); } break; case 11: switch(r) { case 3: case 8: Ip->type = stack_sprintf("[III-IV*-%ld] page 168",(d-11)/12); Ip->neron = cyclic(6); break; case 2: case 9: Ip->type = stack_sprintf("[II-III*-%ld] page 166",(d-11)/12); Ip->neron = cyclic(2); break; default: pari_err_BUG("tame5 [bug37]"); } break; default: pari_err_BUG("tame5 [bug38]"); } break; default: pari_err_BUG("tame5 [bug39]"); } } else { r %= (n >> 1); switch(n) { case 2: condp = 2; Ip->type = stack_sprintf("[2I{0}-%ld] page 159",(d/2)); Ip->neron = cyclic(1); break; case 4: condp = 4; Ip->type = stack_sprintf("[2I*{0}-%ld] page 159",(d/2-1)/2); Ip->neron = dicyclic(2,2); break; case 6: condp = 4; Ip->neron = cyclic(3); switch(r) { case 1: Ip->type = stack_sprintf("[2IV-%ld] page 165",(d/2-1)/3); break; case 2: Ip->type = stack_sprintf("[2IV*-%ld] page 165",(d/2-2)/3); break; default: pari_err_BUG("tame5 [bug40]"); } break; case 8: condp = 4; Ip->neron = cyclic(2); switch(r) { case 1: Ip->type = stack_sprintf("[2III-%ld] page 168",(d/2-1)/4); break; case 3: Ip->type = stack_sprintf("[2III*-%ld] page 168",(d/2-3)/4); break; default: pari_err_BUG("tame5 [bug41]"); } break; case 12: condp = 4; Ip->neron = cyclic(1); switch(r) { case 1: Ip->type = stack_sprintf("[2II-%ld] page 162",(d/2-1)/6); break; case 5: Ip->type = stack_sprintf("[2II*-%ld] page 163",(d/2-5)/6); break; default: pari_err_BUG("tame5 [bug42]"); } break; default: pari_err_BUG("tame5 [bug43]"); } } return condp; } static long tame_6(struct igusa *I, struct igusa_p *Ip) { long condp = -1, d, d1, n, dm, r, dk; GEN val = Ip->val; dk = Ip->eps*val[7]-6*val[8]; tame_567_init(I, Ip, dk, &d, &n, &dm, &r); d1 = n * (Ip->eps*(val[6]-val[7])+val[8]) / Ip->eps; switch(n) { case 1: condp = 1; Ip->type = stack_sprintf("[I{0}-I{%ld}-%ld] page 170",d1,d); Ip->neron = cyclic(d1); break; case 2: switch(dm) { case 0: condp = 4; Ip->type=stack_sprintf("[I*{0}-I*{%ld}-%ld] page 171", d1/2,(d-2)/2); Ip->neron = shallowconcat(groupH(d1/2), dicyclic(2,2)); break; case 1: return -1; default: pari_err_BUG("tame6 [bug44]"); } break; case 3: condp = 3; Ip->neron = dicyclic(3,d1/3); switch(dm) { case 1: Ip->type = stack_sprintf("[I{%ld}-IV-%ld] page 173",d1/3,(d-1)/3); break; case 2: Ip->type = stack_sprintf("[I{%ld}-IV*-%ld] page 173",d1/3,(d-2)/3); break; default: pari_err_BUG("tame6 [bug45]"); } break; case 4: switch(dm) { case 1: switch(r) { case 0: case 1: condp = 3; Ip->type=stack_sprintf("[I{%ld}-III-%ld] page 176",d1/4,(d-1)/4); Ip->neron = dicyclic(2,d1/4); break; case 2: case 3: condp = 4; Ip->type=stack_sprintf("[I*{%ld}-III*-%ld] page 177",d1/4,(d-5)/4); Ip->neron = shallowconcat(groupH(d1/4), cyclic(2)); break; default: pari_err_BUG("tame6 [bug46]"); } break; case 3: switch(r) { case 0: case 3: condp = 3; Ip->type=stack_sprintf("[I{%ld}-III*-%ld] page 176",d1/4,(d-3)/4); Ip->neron = dicyclic(2,d1/4); break; case 1: case 2: condp = 4; Ip->type=stack_sprintf("[I*{%ld}-III-%ld] page 177",d1/4,(d-3)/4); Ip->neron = shallowconcat(groupH(d1/4), cyclic(2)); break; default: pari_err_BUG("tame6 [bug47]"); } break; default: pari_err_BUG("tame6 [bug48]"); } break; case 6: switch(dm) { case 1: switch(r) { case 0: case 1: condp = 3; Ip->type = stack_sprintf("[I{%ld}-II-%ld] page 172",d1/6,(d-1)/6); Ip->neron = cyclic(d1/6); break; case 3: case 4: condp = 4; Ip->type=stack_sprintf("[I*{%ld}-IV*-%ld] page 174",d1/6,(d-7)/6); Ip->neron = shallowconcat(groupH(d1/6), cyclic(3)); break; default: pari_err_BUG("tame6 [bug49]"); } break; case 2: condp = 4; Ip->type = stack_sprintf("[I*{%ld}-II*-%ld] page 174",d1/6,(d-8)/6); Ip->neron = groupH(d1/6); break; case 4: condp = 4; Ip->type = stack_sprintf("[I*{%ld}-II-%ld] page 173",d1/6,(d-4)/6); Ip->neron = groupH(d1/6); break; case 5: switch(r) { case 0: case 5: condp = 3; Ip->type=stack_sprintf("[I{%ld}-II*-%ld] page 172",d1/6,(d-5)/6); Ip->neron = cyclic(d1/6); break; case 2: case 3: condp = 4; Ip->type=stack_sprintf("[I*{%ld}-IV-%ld] page 174",d1/6,(d-5)/6); Ip->neron = shallowconcat(groupH(d1/6), cyclic(3)); break; default: pari_err_BUG("tame6 [bug50]"); } break; default: pari_err_BUG("tame6 [bug51]"); } break; default: pari_err_BUG("tame6 [bug52]"); } return condp; } static long tame_7(struct igusa *I, struct igusa_p *Ip) { long condp = -1, d, D, d1, d2, n, dm, r, dk; GEN val = Ip->val; dk = 3*(Ip->eps*val[3]-2*val[8]); tame_567_init(I, Ip, dk, &d, &n, &dm, &r); D = n * (Ip->eps*(val[6]-3*val[3])+val[8]) / Ip->eps; d1 = minss(n * (val[7]-3*val[3]), D/2); d2 = D - d1; /* d1 <= d2 */ switch(n) { case 1: condp = 2; Ip->type = stack_sprintf("[I{%ld}-I{%ld}-%ld] page 179",d1,d2,d); Ip->neron = dicyclic(d1,d2); break; case 2: if (odd(val[8])) { condp = 3; Ip->type = stack_sprintf("[2I{%ld}-%ld] page 181",d1,d/2); Ip->neron = cyclic(d1); } else if (dm == 0) { condp = 4; Ip->type = stack_sprintf("[I*{%ld}-I*{%ld}-%ld] page 180", d1/2,d2/2,(d-2)/2); Ip->neron = shallowconcat(groupH(d1/2),groupH(d2/2)); } else { GEN H; if (d1 != d2) return -1; condp = 3; H = groupH(d1/2); Ip->type = stack_sprintf("[I{%ld}-I*{%ld}-%ld] page 180", d1/2,d1/2,(d-1)/2); Ip->neron = shallowconcat(H, H); } break; case 4: condp = 4; Ip->type = stack_sprintf("[2I*{%ld}-%ld] page 181",d1/2,(d-2)/4); Ip->neron = groupH(d1/2); break; default: pari_err_BUG("tame7 [bug55]"); } return condp; } static long labelm3(GEN polh, long t60, long alpha, long Dmin, struct igusa *I, struct igusa_p *Ip); static long tame(GEN polh, long t60, long alpha, long Dmin, struct igusa *I, struct igusa_p *Ip) { long d; Ip->tame = 1; switch(Ip->tt) { case 1: return tame_1(I,Ip); case 2: return tame_2(I,Ip); case 3: return tame_3(I,Ip); case 4: return tame_4(I,Ip); case 5: return tame_5(I,Ip); case 6: d = tame_6(I,Ip); break; default:d = tame_7(I,Ip); break; } if (d < 0) d = labelm3(polh,t60,alpha,Dmin,I,Ip); /* => tt=6 or 7 */ return d; } /* maxc = maximum conductor valuation at p */ static long get_maxc(GEN p) { switch (itos_or_0(p)) { case 2: return 20; break; case 3: return 10; break; case 5: return 9; break; default: return 4; break; /* p > 5 */ } } /* p = 3 */ static long quartic(GEN polh, long alpha, long Dmin, struct igusa_p *Ip) { GEN val = Ip->val, p = Ip->p; GEN polf = polymini_zi2(ZX_Z_mul(polh, powiu(p, alpha))); long condp = -1, d, R, r1, beta; r1 = polf[1]; beta = polf[2]; R = beta/2; switch(Ip->tt) { case 1: case 5: d = 0;break; case 3: d = val[6] - 5*val[3]/2;break; case 7: d = val[6] - 3*val[3] + val[8]/Ip->eps;break; default: pari_err_BUG("quartic [type choices]"); d = 0; /*LCOV_EXCL_LINE*/ } switch(r1) { case 0: if (d) { condp = 3; Ip->type = stack_sprintf("[2I{%ld}-%ld] page 181",d,R); Ip->neron = cyclic(d); } else { condp = 2; Ip->neron = cyclic(1); if (R) Ip->type = stack_sprintf("[2I{0}-%ld] page 159",R); else Ip->type = "[II] page 155"; } break; case 6: condp = 4; Ip->type = stack_sprintf("[2I*{%ld}-%ld] pages 159, 181",d,R); Ip->neron = dicyclic(2,2); break; case 3: condp = 4; Ip->type = stack_sprintf("[2III-%ld] page 168",R); Ip->neron = cyclic(2); break; case 9: condp = 4; Ip->type = stack_sprintf("[2III*-%ld] page 168",R); Ip->neron = cyclic(2); break; case 2: condp = Dmin-12*R-13; Ip->type = stack_sprintf("[2II-%ld] page 162",R); Ip->neron = cyclic(1); break; case 8: condp = Dmin-12*R-19; Ip->type = stack_sprintf("[2IV*-%ld] page 165",R); Ip->neron = cyclic(3); break; case 4: condp = Dmin-12*R-15; Ip->type = stack_sprintf("[2IV-%ld] page 165",R); Ip->neron = cyclic(3); break; case 10: condp = Dmin-12*R-21; Ip->type = stack_sprintf("[2II*-%ld] page 163",R); Ip->neron = cyclic(1); break; default: pari_err_BUG("quartic [type1]"); } if (condp > get_maxc(p) || condp < 0) pari_err_BUG("quartic [conductor]"); return condp; } static long litredtp(long alpha, long alpha1, long t60, long t60_1, GEN polh, GEN polh1, long Dmin, long R, struct igusa *I, struct igusa_p *Ip) { GEN val = Ip->val, p = Ip->p; long condp = -1, indice, d; if ((Ip->r1 == 0||Ip->r1 == 6) && (Ip->r2 == 0||Ip->r2 == 6)) { /* (r1,r2) = (0,0), (0,6), (6,0) or (6,6) */ if (Ip->tt == 5) { switch(Ip->r1 + Ip->r2) { case 0: /* (0,0) */ condp = 0; Ip->type = stack_sprintf("[I{0}-I{0}-%ld] page 158",R); Ip->neron = cyclic(1); break; case 6: /* (0,6) or (6,0) */ condp = 2; Ip->type = stack_sprintf("[I{0}-I*{0}-%ld] page 159",R); Ip->neron = dicyclic(2,2); break; case 12: /* (6,6) */ condp = 4; Ip->type = stack_sprintf("[I*{0}-I*{0}-%ld] page 158",R); Ip->neron = mkvecsmall4(2,2,2,2); break; } return condp; } if (Ip->r1 == Ip->r2) return tame(polh, t60, alpha, Dmin, I, Ip); if (Ip->tt == 6) { d = val[6] - val[7] + val[8]/Ip->eps; if (Ip->r1 && alpha1 == 0) /* H(px) / p^3 */ polh1 = ZX_Z_divexact(ZX_unscale_div(polh1,p), sqri(p)); if (FpX_is_squarefree(FpX_red(polh1,p),p)) { indice = 0; condp = 3-Ip->r2/6; } else { indice = d; condp = 3-Ip->r1/6; } } else { /* Ip->tt == 7 */ long d1; d = val[6] - 3*val[3] + val[8]/Ip->eps; if (t60_1 == 60) /* H(px) / p^3 */ polh1 = ZX_Z_divexact(ZX_unscale_div(polh1,p), sqri(p)); d1 = minss(val[7]-3*val[3],d/2); if (d == 2*d1) indice = d1; else { indice = discpart(polh1,p,d1+1); if (indice>= d1+1) indice = d-d1; else indice = d1; } condp = 3; } if (Ip->r1) indice = d - indice; /* (r1,r2) = (6,0) */ Ip->neron = shallowconcat(cyclic(indice),groupH(d-indice)); Ip->type = stack_sprintf("[I{%ld}-I*{%ld}-%ld] page %ld", indice,d-indice,R, (Ip->tt==6)? 170L: 180L); return condp; } if (Ip->tt == 7) pari_err_BUG("litredtp [switch ri]"); { struct red __S1, __S2, *S1 = &__S1, *S2 = &__S2; long f1 = get_red(S1, Ip, polh1, p, alpha1, Ip->r1); long f2 = get_red(S2, Ip, polh, p, alpha, Ip->r2); /* reorder to normalize representation */ if (S1->tnum > S2->tnum || (S1->tnum == S2->tnum && f1 > f2)) { struct red *S = S1; S1 = S2; S2 = S; } Ip->type = stack_sprintf("[%s-%s-%ld] pages %s", S1->t,S2->t, R, S1->pages); Ip->neron = shallowconcat(S1->g, S2->g); condp = Dmin - (f1 + f2) + ((R >= 0)? 2-12*R: 4); } if (condp > get_maxc(p)) pari_err_BUG("litredtp [conductor]"); return condp; } static long labelm3(GEN h1, long t60_1, long alpha1, long Dmin, struct igusa *I, struct igusa_p *Ip) { GEN h, pm, vs, val = Ip->val, p = Ip->p; long alpha, t60, lambda, beta, R; pm = polymini(ZX_Z_mul(RgX_recip6(h1), powiu(p,alpha1)), p); h = gel(pm,1); vs = gel(pm,2); lambda= vs[1]; t60 = vs[2]; alpha = vs[3]; beta = vs[5]; if (lambda != 3) pari_err_BUG("labelm3 [lambda != 3]"); R = beta-(alpha1+alpha); if (odd(R)) pari_err_BUG("labelm3 [R odd]"); R /= 2; if (R <= -2) pari_err_BUG("labelm3 [R <= -2]"); if (val[8] % (2*Ip->eps)) pari_err_BUG("labelm3 [val(eps2)]"); if (R >= 0 && (alpha+alpha1) >= 1) pari_err_BUG("labelm3 [minimal equation]"); Ip->r1 = t60_1 / 10 + 6*alpha1; Ip->r2 = t60 / 10 + 6*alpha; return litredtp(alpha, alpha1, t60, t60_1, h, h1, Dmin, R, I, Ip); } /* p = 3 */ static long quadratic(GEN polh, long alpha, long Dmin, struct igusa *I, struct igusa_p *Ip) { long alpha1 = alpha, beta, t6, R; GEN vs = polymini_zi(ZX_Z_mul(polh, powiu(Ip->p,alpha))); t6 = vs[1]; alpha = vs[2]; beta = vs[3]; R = beta-alpha; if (R >= 0 && alpha1) { Dmin -= 10; if (DEBUGLEVEL) err_printf("(Care: minimal discriminant over Z[i] smaller than over Z)\n"); } Ip->r2 = Ip->r1 = t6 + 6*alpha; return litredtp(alpha, alpha, t6*10, t6*10, polh, polh, Dmin, R, I, Ip); } static long genus2localred(struct igusa *I, struct igusa_p *Ip, GEN p, GEN polmini) { GEN val, vs, polh, list, c1, c2, c3, c4, c5, c6, prod; long i, vb5, vb6, d, Dmin, alpha, lambda, t60; long condp = -1, indice, vc6, mm, nb, dism; stable_reduction(I, Ip, p); val = Ip->val; Dmin = val[6]; if (Dmin == 0) { Ip->tame = 1; Ip->type = "[I{0-0-0}] page 155"; Ip->neron = cyclic(1); return 0; } if (Dmin == 1) { Ip->type = "[I{1-0-0}] page 170"; Ip->neron = cyclic(1); return 1; } if (Dmin == 2) switch(Ip->tt) { case 2: Ip->type = "[I{2-0-0}] page 170"; Ip->neron = cyclic(2); return 1; case 3: Ip->type = "[I{1-1-0}] page 179"; Ip->neron = cyclic(1); return 2; case 5: if (cmpis(p,3) <= 0) pari_err_BUG("genus2localred [tt 1]"); Ip->type = "[I{0}-II-0] page 159"; Ip->neron = cyclic(1); return 2; default: pari_err_BUG("genus2localred [tt 2]"); } if (absequaliu(p,2)) return -1; polh = gel(polmini,1); vs = gel(polmini,2); lambda = vs[1]; t60 = vs[2]; alpha = vs[3]; if (vs[4]) return equaliu(p,3)? quadratic(polh, alpha, Dmin, I, Ip): tame(polh, t60, alpha, Dmin, I, Ip); if (!t60 && lambda<= 2) { if (Ip->tt >= 5) pari_err_BUG("genus2localred [tt 3]"); return tame(polh, t60, alpha, Dmin, I, Ip); } if (Dmin == 3) { switch(Ip->tt) { case 2: return tame(polh, t60, alpha, Dmin, I, Ip); case 3: Ip->type = "[I{2-1-0}] page 179"; Ip->neron = cyclic(2); return 2; case 4: Ip->type = "[I{1-1-1}] page 182"; Ip->neron = cyclic(3); return 2; case 5: if (equaliu(p,3) && t60 != 30) return labelm3(polh,t60,alpha,Dmin,I,Ip); Ip->type = "[I{0}-III-0] page 161"; Ip->neron = cyclic(2); return 2; case 6: if (equaliu(p,3)) pari_err_BUG("genus2localred [conductor]"); Ip->type = "[I{1}-II-0] page 172"; Ip->neron = cyclic(1); return 3; } pari_err_BUG("genus2localred [switch tt 4]"); return -1; /* LCOV_EXCL_LINE */ } switch(lambda) { case 0: switch(t60+alpha) { case 10: condp = Dmin-1; Ip->type = "[V] page 156"; Ip->neron = cyclic(3); break; case 11: condp = Dmin-11; Ip->type = "[V*] page 156"; Ip->neron = cyclic(3); break; case 12: condp = Dmin-2; Ip->type = "[IX-2] page 157"; Ip->neron = cyclic(5); break; case 13: condp = Dmin-12; Ip->type = "[VIII-4] page 157"; Ip->neron = cyclic(1); break; case 24: condp = Dmin-8; Ip->type = "[IX-4] page 158"; Ip->neron = cyclic(5); break; case 15: case 16: if (Ip->tt>= 5) pari_err_BUG("genus2localred [tt 6]"); return tame(polh, t60, alpha, Dmin, I, Ip); case 20: case 21: { GEN b0, b1, b2, b3, b4, b5, b6, b02, b03, b04, b05; RgX_to_06(polh, &b0,&b1,&b2,&b3,&b4,&b5,&b6); vb5 = myval(b5,p); vb6 = myval(b6,p); if (vb6 >= 3) { if (vb5 < 2) pari_err_BUG("genus2localred [red1]"); if (vb5 >= 3) { condp = Dmin-8; Ip->type = "[II*-IV-(-1)] page 164"; Ip->neron = cyclic(3); } else { condp = Dmin-7; Ip->type = "[IV-III*-(-1)] page 167"; Ip->neron = cyclic(6); } break; } if (dvdii(b0,p)) pari_err_BUG("genus2localred [b0]"); b02 = gsqr(b0); b03 = gmul(b02, b0); b04 = gmul(b03, b0); b05 = gmul(b04, b0); c1 = gmul2n(b1,-1); c2 = gmul2n(gsub(gmul(b0,b2), gsqr(c1)),-1); c3 = gmul2n(gsub(gmul(b02,b3), gmul2n(gmul(c1,c2),1)),-1); c4 = gsub(gmul(b03,b4), gadd(gmul2n(gmul(c1,c3),1),gsqr(c2))); c5 = gsub(gmul(b04,b5), gmul2n(gmul(c2,c3),1)); c6 = gsub(gmul(b05,b6), gsqr(c3)); /* b0^5*H(x/b0) = (x^3+c1*x^2+c2*x+c3)^2+c4*x^2+c5*x+c6 */ vc6 = myval(c6,p); if (vc6 == 2) { if (alpha) { condp = Dmin-16; Ip->type = "[IV] page 155"; Ip->neron = cyclic(1); } else { condp = Dmin-6; Ip->type = "[III] page 155"; Ip->neron = dicyclic(3,3); } } else { if (myval(c3,p) > 1) pari_err_BUG("genus2localred [c3]"); mm = min3(3*myval(c4,p)-4, 3*myval(c5,p)-5, 3*vc6-6); if (alpha) { condp = Dmin-mm-16; Ip->type = stack_sprintf("[III*{%ld}] page 184", mm); Ip->neron = cyclic(1); } else { condp = Dmin-mm-6; Ip->type = stack_sprintf("[III{%ld}] page 184", mm); Ip->neron = (mm%3)? cyclic(9): dicyclic(3,3); } } } break; case 30: return equaliu(p,3)? quartic(polh, alpha, Dmin, Ip) : tame(polh, t60, alpha, Dmin, I, Ip); default: pari_err_BUG("genus2localred [red2]"); } break; case 1: switch(t60+alpha) { case 12: condp = Dmin; Ip->type = "[VIII-1] page 156"; Ip->neron = cyclic(1); break; case 13: condp = Dmin-10; Ip->type = "[IX-3] page 157"; Ip->neron = cyclic(5); break; case 24: condp = Dmin-4; Ip->type = "[IX-1] page 157"; Ip->neron = cyclic(5); break; case 25: condp = Dmin-14; Ip->type = "[VIII-3] page 157"; Ip->neron = cyclic(1); break; case 36: condp = Dmin-8; Ip->type = "[VIII-2] page 157"; Ip->neron = cyclic(1); break; case 15: condp = Dmin-1; Ip->type = "[VII] page 156"; Ip->neron = cyclic(2); break; case 16: condp = Dmin-11; Ip->type = "[VII*] page 156"; Ip->neron = cyclic(2); break; case 20: if (cmpis(p,3)) { d = 6*val[6]-5*val[7]-2; if (d%6) pari_err_BUG("genus2localred [index]"); dism = (d/6); } else { list = padicfactors(polh,p,Dmin-5); nb = lg(list); prod = pol_1(varn(polh)); for(i = 1;i 2) pari_err_BUG("genus2localred [padicfactors]"); dism = valp(RgX_disc(prod)) - 1; } condp = Dmin-dism-3; Ip->type = stack_sprintf("[II-II*{%ld}] page 176", dism); Ip->neron = groupH(dism+1); break; case 21: vb6 = myval(RgX_coeff(polh,0),p); if (vb6<2) pari_err_BUG("genus2localred [red3]"); condp = Dmin-14; Ip->type = "[IV*-II{0}] page 175"; Ip->neron = cyclic(1); break; case 30: vb5 = myval(RgX_coeff(polh,1),p); if (vb5 == 2) { if (Ip->tt >= 5) pari_err_BUG("genus2localred [tt 6]"); return tame(polh, t60, alpha, Dmin, I, Ip); } condp = Dmin-7; Ip->type = "[II*-III-(-1)] page 167"; Ip->neron = cyclic(2); break; } break; case 2: if (ugcd(t60, 60) == 15) /* denom(theta) = 4 */ { if (Ip->tt>4) pari_err_BUG("genus2localred [tt 5]"); return tame(polh, t60, alpha, Dmin, I, Ip); } if (!equaliu(p,3) && ugcd(t60, 60) == 20) /* denom(theta) = 3 */ return tame(polh, t60, alpha, Dmin, I, Ip); list = padicfactors(polh,p,Dmin-10*alpha); nb = lg(list); prod = pol_1(varn(polh)); for(i = 1;itype = stack_sprintf("[IV-II{%ld}] page 175", dism); Ip->neron = cyclic(3*dism+2); break; case 1: condp = Dmin-dism-10; Ip->type = stack_sprintf("[II*-II*{%ld}] page 176",dism); Ip->neron = groupH(dism+1); break; case 2: case 3: if (myval(RgX_coeff(polh,0),p) == 2) { if (Ip->tt>4) pari_err_BUG("genus2localred [tt 5]"); return tame(polh, t60, alpha, Dmin, I, Ip); } dism++; indice = val[6]-(5*val[3]/2)-dism; condp = Dmin-dism-indice-2; Ip->type = stack_sprintf("[II{%ld-%ld}] page 182", dism,indice); Ip->neron = both_odd(dism,indice)? dicyclic(2,2*dism): cyclic(4*dism); break; case 4: condp = Dmin-dism-5; Ip->type = stack_sprintf("[IV*-II{%ld}] page 175",dism+1); Ip->neron = cyclic(3*dism+4); break; } break; case 3: if (!equaliu(p,3) || Ip->tt <= 4) return tame(polh, t60, alpha, Dmin, I, Ip); return labelm3(polh,t60,alpha,Dmin,I,Ip); /* p = 3 */ default: pari_err_BUG("genus2localred [switch lambda]"); } if (condp < 2 || condp > get_maxc(p)) pari_err_BUG("genus2localred [conductor]"); return condp; } static long chk_pol(GEN P) { switch(typ(P)) { case t_INT: break; case t_POL: RgX_check_ZX(P,"genus2red"); return varn(P); break; default: pari_err_TYPE("genus2red", P); } return -1; } /* P,Q are ZX, study Y^2 + Q(X) Y = P(X) */ GEN genus2red(GEN PQ, GEN p) { pari_sp av = avma; struct igusa I; GEN P, Q, D; GEN j22, j42, j2j6, a0,a1,a2,a3,a4,a5,a6, V,polr,facto,factp, vecmini, cond; long i, l, dd, vP,vQ; PQ = Q_remove_denom(PQ, &D); if (typ(PQ) == t_VEC && lg(PQ) == 3) { P = gel(PQ,1); Q = gel(PQ,2); } else { P = PQ; Q = gen_0; } vP = chk_pol(P); vQ = chk_pol(Q); if (vP < 0) { if (vQ < 0) pari_err_TYPE("genus2red",mkvec2(P,Q)); P = scalarpol(P,vQ); } else if (vQ < 0) Q = scalarpol(Q,vP); if (p && typ(p) != t_INT) pari_err_TYPE("genus2red", p); if (D) P = ZX_Z_mul(P,D); polr = ZX_add(ZX_sqr(Q), gmul2n(P,2)); /* ZX */ switch(degpol(polr)) { case 5: case 6: break; default: pari_err_DOMAIN("genus2red","genus","!=", gen_2,mkvec2(P,Q)); } RgX_to_03(polr, &a0,&a1,&a2,&a3); I.j10 = !signe(a0)? mulii(sqri(a1), ZX_disc(polr)): ZX_disc(polr); if (!signe(I.j10)) pari_err_DOMAIN("genus2red","genus","<",gen_2,mkvec2(P,Q)); I.j10 = gmul2n(I.j10, -12); /* t_INT */ if (p == NULL) { facto = absZ_factor(I.j10); factp = gel(facto,1); } else { factp = mkcol(p); facto = mkmat2(factp, mkcol(gen_1)); } l = lg(factp); vecmini = cgetg(l, t_COL); for(i = 1; i= 0) N = zv_snf(Ip.neron); if (DEBUGLEVEL) { if (!p) err_printf("p = %Ps\n", q); err_printf("(potential) stable reduction: %Ps\n", Ip.stable); if (f >= 0) { err_printf("reduction at p: %s, %Ps", Ip.type, N); err_printf(", f = %ld\n", f); } } red = f >= 0? mkvec2(strtoGENstr(Ip.type), N): cgetg(1, t_VEC); gel(V, i) = mkvec3(q, Ip.stable, red); } if (p) V = gel(V,1); cond = factorback(facto); /* remove denominator 2 coming from f = -1 in genuslocalred(, p = 2) */ if (typ(cond) != t_INT) cond = gel(cond,1); return gerepilecopy(av, mkvec4(cond, facto, polr, V)); } pari-2.11.2/src/modules/ratpoints.c0000644000175000017500000014454713366427320015631 0ustar billbill/* Copyright (C) 2017 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file is based on ratpoints-2.1.3 by Michael Stoll, see * http://www.mathe2.uni-bayreuth.de/stoll/programs/ * Original copyright / license: */ /*********************************************************************** * ratpoints-2.1.3 * * Copyright (C) 2008, 2009 Michael Stoll * * - A program to find rational points on hyperelliptic curves * * * * This program is free software: you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation, either version 2 of * * the License, or (at your option) any later version. * ***********************************************************************/ #include "pari.h" #include "paripriv.h" #define pel(a,b) gel((a),(b)+2) #define RATPOINTS_ARRAY_SIZE 256 /* Array size in longs */ #define RATPOINTS_DEFAULT_SP1 9 /* Default value for sp1 */ #define RATPOINTS_DEFAULT_SP2 16 /* Default value for sp2 */ #define RATPOINTS_DEFAULT_NUM_PRIMES 28 /* Default value for num_primes */ #define RATPOINTS_DEFAULT_BIT_PRIMES 7 /* Default value for bit_primes */ #define RATPOINTS_DEFAULT_MAX_FORBIDDEN 30 /* Default value for max_forbidden */ typedef struct {double low; double up;} ratpoints_interval; /* Define the flag bits for the flags component: */ #define RATPOINTS_NO_REVERSE 0x0004UL #define RATPOINTS_FLAGS_INPUT_MASK (RATPOINTS_NO_REVERSE) /* Flags bits for internal purposes */ #define RATPOINTS_REVERSED 0x0100UL #define RATPOINTS_CHECK_DENOM 0x0200UL #define RATPOINTS_USE_SQUARES 0x0400UL #define RATPOINTS_USE_SQUARES1 0x0800UL #define LONG_MASK (~(-(1UL< #define AND(a,b) ((ratpoints_bit_array)__builtin_ia32_andps((__v4sf)(a), (__v4sf)(b))) #define EXT0(a) ((ulong)__builtin_ia32_vec_ext_v2di((__v2di)(a), 0)) #define EXT1(a) ((ulong)__builtin_ia32_vec_ext_v2di((__v2di)(a), 1)) #define TEST(a) (EXT0(a) || EXT1(a)) #define RBA(a) ((__v2di){((long) a), ((long) a)}) /* Use SSE 128 bit registers for the bit arrays */ typedef __v2di ratpoints_bit_array; #define RBA_LENGTH (128) #define RBA_SHIFT (7) #define RBA_ALIGN (sizeof(ratpoints_bit_array)) #define RBA_MASK (~(-(1UL<is_f_square; register long b = b1; long lmp = BITS_IN_LONG % p; long ldp = BITS_IN_LONG / p; long p1 = (ldp + 1) * p; long diff_shift = p1 & LONG_MASK; long diff = BITS_IN_LONG - diff_shift; register ulong help0; register long a; register long d = se->inverses[b]; register long ab = 0; /* a/b mod p */ register ulong test = 1UL; register ulong he0 = 0UL; for (a = 0; a < p; a++) { if (isfs[ab]) he0 |= test; ab += d; if (ab >= p) ab -= p; test <<= 1; } help0 = he0; { register ulong help1; /* repeat bit pattern floor(BITS_IN_LONG/p) times */ register ulong pattern = help0; register long i; /* the p * (floor(BITS_IN_LONG/p) + 1) - BITS_IN_LONG = p - (BITS_IN_LONG mod p) upper bits into help[b][1] : shift away the BITS_IN_LONG mod p lower bits */ help1 = pattern >> lmp; for (i = p; i < BITS_IN_LONG; i <<= 1) help0 |= help0 << i; { /* fill the bit pattern from help0/help1 into sieve[b][]. sieve[b][a0] has the same semantics as help0/help1, but here, a0 runs from 0 to p-1 and all bits are filled. */ register long a; ulong *si = (ulong *)args->ba_next; args->ba_next += p; /* copy the first chunk into sieve[b][] */ si[0] = help0; /* now keep repeating the bit pattern, rotating it in help0/help1 */ for (a = 1 ; a < p; a++) { register ulong temp = help0 >> diff; help0 = help1 | (help0 << diff_shift); si[a] = help0; help1 = temp; } CODE_INIT_SIEVE_COPY /* set sieve array */ se->sieve[b] = (ratpoints_bit_array *)si; return (ratpoints_bit_array *)si; } } } /* This is for p > BITS_IN_LONG */ static ratpoints_bit_array * #if defined(__GNUC__) __attribute__((noinline)) #endif sieve_init2(long p, ratpoints_sieve_entry *se1, long b1, ratpoints_args *args1) { ratpoints_sieve_entry *se = se1; ratpoints_args *args = args1; register int *isfs = se->is_f_square; register long b = b1; /* long ldp = 0; = BITS_IN_LONG / p */ /* long p1 = p; = (ldp + 1) * p; */ long wp = p >> TWOPOTBITS_IN_LONG; long diff_shift = p & LONG_MASK; long diff = BITS_IN_LONG - diff_shift; ulong help[(p>>TWOPOTBITS_IN_LONG) + 2]; /* initialize help */ { register ulong *he = &help[0]; register ulong *he1 = &he[(p>>TWOPOTBITS_IN_LONG) + 2]; while (he1 != he) { he1--; *he1 = 0UL; } } { register ulong work = 0UL; register long a; register long ab = 0; /* a/b mod p */ register long d = se->inverses[b]; register long n = 0; register ulong test = 1UL; for (a = 0; a < p; ) { if (isfs[ab]) work |= test; ab += d; if (ab >= p) ab -= p; test <<= 1; a++; if ((a & LONG_MASK) == 0) { help[n] = work; n++; work = 0UL; test = 1UL; } } help[n] = work; } { /* fill the bit pattern from help[] into sieve[b][]. sieve[b][a0] has the same semantics as help[b][a0], but here, a0 runs from 0 to p-1 and all bits are filled. */ register ulong *si = (ulong *)args->ba_next; register long a1; register long a; args->ba_next += p; /* copy the first chunk from help[] into sieve[num][b][] */ for (a = 0; a < wp; a++) si[a] = help[a]; /* now keep repeating the bit pattern, rotating it in help */ for (a1 = a ; a < p; a++) { register long t = (a1 == wp) ? 0 : a1+1; help[a1] |= help[t]<>= diff; } CODE_INIT_SIEVE_COPY /* set sieve array */ se->sieve[b] = (ratpoints_bit_array *)si; return (ratpoints_bit_array *)si; } } static GEN gen_squares(GEN listprime) { long nbprime = lg(listprime)-1; GEN sq = cgetg(nbprime+1, t_VEC); long n; for (n = 1; n <= nbprime; n++) { ulong i, p = uel(listprime,n); GEN w = zero_zv(p), work = w+1; work[0] = 1; /* record non-zero squares mod p, p odd */ for (i = 1; i < p; i += 2) work[(i*i) % p] = 1; gel(sq, n) = w; } return sq; } static GEN gen_offsets(GEN P) { long n, l = lg(P); GEN of = cgetg(l, t_VEC); for (n = 1; n < l; n++) { ulong p = uel(P,n); uel(of, n) = Fl_inv((2*RBA_LENGTH)%p, p); } return of; } static GEN gen_inverses(GEN P) { long n, l = lg(P); GEN iv = cgetg(l, t_VEC); for (n = 1; n < l; n++) { ulong i, p = uel(P,n); GEN w = cgetg(p, t_VECSMALL); for (i = 1; i < p; i++) uel(w, i) = Fl_inv(i, p); gel(iv, n) = w; } return iv; } static ulong ** gen_sieves0(GEN listprime) { long n; long nbprime = lg(listprime)-1; ulong ** si = (ulong**) new_chunk(nbprime+1); for (n = 1; n <= nbprime; n++) { ulong i, p = uel(listprime,n); ulong *w = (ulong *) stack_malloc_align(2*p*sizeof(ulong), RBA_ALIGN); for (i = 0; i < p; i++) uel(w,i) = ~0UL; for (i = 0; i < BITS_IN_LONG; i++) uel(w,(p*i)>>TWOPOTBITS_IN_LONG) &= ~(1UL<<((p*i) & LONG_MASK)); for (i = 0; i < p; i++) uel(w,i+p) = uel(w,i); si[n] = w; } return si; } static void gen_sieve(ratpoints_args *args) { GEN listprimes = args->listprime; args->offsets = gen_offsets(listprimes); args->inverses = gen_inverses(listprimes); args->sieves0 = gen_sieves0(listprimes); } static GEN ZX_positive_region(GEN P, long h, long bitprec) { long prec = nbits2prec(bitprec); GEN it = mkvec2(stoi(-h),stoi(h)); GEN R = ZX_Uspensky(P, it, 1, bitprec); long nR = lg(R)-1; long s = signe(poleval(P,gel(it,1))); long i=1, j; GEN iv, st, en; if (s<0 && nR==0) return NULL; iv = cgetg(((nR+1+(s>=0))>>1)+1, t_VEC); if (s>=0) st = itor(gel(it,1),prec); else { st = gel(R,i); i++; } for (j=1; idomain; args->num_inter = posint(ivlist, args->cof, (long) ivlist[0].up); return args->num_inter; } /************************************************************************** * Try to avoid divisions * **************************************************************************/ INLINE long mod(long a, long b) { long b1 = b << 4; /* b1 = 16*b */ if (a < -b1) { a %= b; if (a < 0) { a += b; } return a ; } if (a < 0) { a += b1; } else { if (a >= b1) { return a % b; } } b1 >>= 1; /* b1 = 8*b */ if (a >= b1) { a -= b1; } b1 >>= 1; /* b1 = 4*b */ if (a >= b1) { a -= b1; } b1 >>= 1; /* b1 = 2*b */ if (a >= b1) { a -= b1; } if (a >= b) { a -= b; } return a; } static void set_bc(long b, ratpoints_args *args) { GEN w0 = gen_1; GEN c = args->cof, bc; long k, degree = degpol(c); bc = cgetg(degree+2, t_POL); for (k = degree-1; k >= 0; k--) { w0 = muliu(w0, b); gel(bc,k+2) = mulii(gel(c,k+2), w0); } args->bc = bc; } /************************************************************************** * Check a `survivor' of the sieve if it really gives a point. * **************************************************************************/ static long _ratpoints_check_point(long a, long b, ratpoints_args *args, int *quit, int process(long, long, GEN, void*, int*), void *info) { pari_sp av = avma; GEN w0, w2, c = args->cof, bc = args->bc; long k, degree = degpol(c); int reverse = args->flags & RATPOINTS_REVERSED; /* Compute F(a, b), where F is the homogenized version of f of smallest possible even degree */ w2 = gel(c, degree+2); for (k = degree-1; k >= 0; k--) { w2 = mulis(w2, a); w2 = addii(w2, gel(bc,k+2)); } if (odd(degree)) w2 = muliu(w2, b); /* check if f(x,z) is a square; if so, process the point(s) */ if (signe(w2) >= 0 && Z_issquareall(w2, &w0)) { if (reverse) { if (a >= 0) (void)process(b, a, w0, info, quit); else (void)process(-b, -a, w0, info, quit); } else (void)process(a, b, w0, info, quit); if (!*quit && signe(w0) != 0) { GEN nw0 = negi(w0); if (reverse) { if (a >= 0) (void)process(b, a, nw0, info, quit); else (void)process(-b, -a, nw0, info, quit); } else (void)process(a, b, nw0, info, quit); } return 1; } avma = av; return 0; } /************************************************************************** * The inner loop of the sieving procedure * **************************************************************************/ static long _ratpoints_sift0(long b, long w_low, long w_high, ratpoints_args *args, bit_selection which_bits, ratpoints_bit_array *survivors, sieve_spec *sieves, int *quit, int process(long, long, GEN, void*, int*), void *info) { long range = w_high - w_low; long sp1 = args->sp1; long sp2 = args->sp2; long i, n, nb = 0, absb = labs(b); ratpoints_bit_array *surv0; /* now do the sieving (fast!) */ for (n = 0; n < sp1; n++) { ratpoints_bit_array *sieve_n = sieves[n].ptr; register long p = sieves[n].p; long r = mod(-w_low-sieves[n].offset, p); register ratpoints_bit_array *surv = survivors; if (w_high < w_low + r) { /* if we get here, r > 0, since w_high >= w_low always */ register ratpoints_bit_array *siv1 = &sieve_n[p-r]; register ratpoints_bit_array *siv0 = siv1 + range; while (siv1 != siv0) { *surv = AND(*surv, *siv1++); surv++; } } else { register ratpoints_bit_array *siv1 = &sieve_n[p-r]; register ratpoints_bit_array *surv_end = &survivors[range - p]; register long i; for (i = r; i; i--) { *surv = AND(*surv, *siv1++); surv++; } siv1 -= p; while (surv <= surv_end) { for (i = p; i; i--) { *surv = AND(*surv, *siv1++); surv++; } siv1 -= p; } surv_end += p; while (surv < surv_end) { *surv = AND(*surv, *siv1++); surv++; } } } /* for n */ /* 2nd phase of the sieve: test each surviving bit array with more primes */ surv0 = &survivors[0]; for (i = w_low; i < w_high; i++) { register ratpoints_bit_array nums = *surv0++; sieve_spec *ssp = &sieves[sp1]; register long n; for (n = sp2-sp1; n && TEST(nums); n--) { register long p = ssp->p; nums = AND(nums, ssp->ptr[mod(i + ssp->offset, p)]); ssp++; } /* Check the survivors of the sieve if they really give points */ if (TEST(nums)) { long a0, a, d; #ifdef HAS_SSE2 long da = (which_bits == num_all) ? RBA_LENGTH/2 : RBA_LENGTH; #endif /* a will be the numerator corresponding to the selected bit */ if (which_bits == num_all) { d = 1; a0 = i * RBA_LENGTH; } else { d = 2; a0 = i * 2 * RBA_LENGTH; if (which_bits == num_odd) a0++; } { #ifdef HAS_SSE2 ulong nums0 = EXT0(nums); ulong nums1 = EXT1(nums); #else ulong nums0 = nums; #endif for (a = a0; nums0; a += d, nums0 >>= 1) { /* test one bit */ if (odd(nums0) && ugcd(labs(a), absb)==1) { if (!args->bc) set_bc(b, args); nb += _ratpoints_check_point(a, b, args, quit, process, info); if (*quit) return nb; } } #ifdef HAS_SSE2 for (a = a0 + da; nums1; a += d, nums1 >>= 1) { /* test one bit */ if (odd(nums1) && ugcd(labs(a), absb)==1) { if (!args->bc) set_bc(b, args); nb += _ratpoints_check_point(a, b, args, quit, process, info); if (*quit) return nb; } } #endif } } } return nb; } #define MAX_DIVISORS 512 /* Maximal length of array for squarefree divisors of leading coefficient */ typedef struct { double r; ratpoints_sieve_entry *ssp; } entry; static const int squares16[16] = {1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0}; /* Says if a is a square mod 16, for a = 0..15 */ /************************************************************************** * Initialization and cleanup of ratpoints_args structure * **************************************************************************/ static ratpoints_sieve_entry* alloc_sieve(long nbprime, long maxprime) { long i; ratpoints_sieve_entry * s = (ratpoints_sieve_entry*) stack_malloc(nbprime*sizeof(ratpoints_sieve_entry)); for (i=0; idegree must be set */ static void find_points_init(ratpoints_args *args, long bit_primes) { long need = 0; long n, nbprime,maxprime; args->listprime = primes_interval_zv(3, 1<listprime)-1; maxprime = args->listprime[nbprime]; /* allocate space for se_buffer */ args->se_buffer = alloc_sieve(nbprime, maxprime); args->se_next = args->se_buffer; for (n = 1; n <= nbprime; n++) { ulong p = args->listprime[n]; need += p*p; } args->ba_buffer = (ratpoints_bit_array*) stack_malloc_align(need*sizeof(ratpoints_bit_array),RBA_ALIGN); args->ba_next = args->ba_buffer; /* allocate space for int_buffer */ args->int_buffer = (int *) stack_malloc(nbprime*(maxprime+1)*sizeof(int)); args->int_next = args->int_buffer; args->forb_ba = (forbidden_entry*) stack_malloc((nbprime + 1)*sizeof(forbidden_entry)); args->forbidden = new_chunk(nbprime + 1); gen_sieve(args); return; } /* f = leading coeff; b = b1*b2, b1 maximal with (b1, 2*f) = 1; * return Jacobi symbol (f, b1) */ INLINE int rpjacobi(long b, GEN lcf) { ulong f; b >>= vals(b); f = umodiu(lcf, b); return krouu(f, u_ppo(b,f)); } /************************************************************************ * Set up information on possible denominators * * when polynomial is of odd degree with leading coefficient != +-1 * ************************************************************************/ static void setup_us1(ratpoints_args *args, GEN w0) { GEN divisors; GEN F = Z_factor_limit(w0, 1000), P = gel(F,1), E = gel(F,2), S; long i, l = lg(P); if (cmpiu(gel(P,l-1), 1000) > 0) return; P = ZV_to_zv(P); E = ZV_to_zv(E); divisors = cgetg(1+(1<<(l-1)), t_VECSMALL); /* factorization is complete, set up array of squarefree divisors */ divisors[1] = 1; for (i = 1; i < l; i++) { /* multiply all divisors known so far by next prime */ long k, n = 1<<(i-1); for (k=0; k v_p(f_d) - v_p(f_k), k = 0,...,d-1} */ GEN c = args->cof; long p = P[i], v = E[i]; long k, n = 1, d = degpol(c); for (k = d - 1; k >= 0; k--) { long t = 1 + v - Z_lval(gel(c,k+2), p); long m = CEIL(t, (d - k)); if (m > n) n = m; } S[i] = n; } args->divisors = divisors; args->flags |= RATPOINTS_USE_SQUARES1; args->den_info = mkvec3(P, E, S); } /************************************************************************ * Consider 2-adic information * ************************************************************************/ static bit_selection get_2adic_info(ratpoints_args *args, ulong *den_bits, ratpoints_bit_array *num_bits) { GEN c = args->cof; long degree = degpol(c); int is_f_square16[24]; long *cmp = new_chunk(degree+1); long npe = 0, npo = 0; bit_selection result; long n, a, b; /* compute coefficients mod 16 */ for (n = 0; n <= degree; n++) cmp[n] = Mod16(gel(c,n+2)); for (a = 0 ; a < 16; a++) { ulong s = cmp[degree]; long n; for (n = degree - 1 ; n >= 0 ; n--) s = s*a + cmp[n]; s &= 0xf; if ((is_f_square16[a] = squares16[s])) { if (odd(a)) npo++; else npe++; } } /* even denominators: is_f_square16[16+k] says if f((2k+1)/2) is a square, k = 0..3 is_f_square16[20+k] says if f((2k+1)/4) is a square, k = 0,1 is_f_square16[22] says if f(odd/8) is a square is_f_square16[23] says if f(odd/2^n), n >= 4, can be a square */ { long np1 = 0, np2 = 0, np3 = 0, np4 = 0; if (odd(degree)) { long a, cf = 4*cmp[degree-1]; if (degree >= 2) cf += 8*cmp[degree-2]; for (a = 0; a < 4; a++) { /* Compute 2 c[d] k^d + 4 c[d-1] k^(d-1) + 8 c[d-2] k^(d-2), k = 2a+1. Note that k^d = k mod 8, k^(d-1) = 1 mod 8. */ long k = 2*a+1; long s = (2*k*cmp[degree] + cf) & 0xf; if ((is_f_square16[16+a] = squares16[s])) np1++; } if ((is_f_square16[20] = squares16[(4*cmp[degree]) & 0xf])) np2++; if ((is_f_square16[21] = squares16[(12*cmp[degree]) & 0xf])) np2++; if ((is_f_square16[22] = squares16[(8*cmp[degree]) & 0xf])) np3++; is_f_square16[23] = 1; np4++; } else { long a, cf = (degree >= 2) ? 4*cmp[degree-2] : 0; if (degree >= 3) cf += 8*cmp[degree-3]; for (a = 0; a < 4; a++) { /* compute c[d] k^d + 2 c[d-1] k^(d-1) + ... + 8 c[d-3] k^(d-3), k = 2a+1. Note that k^d = k^2 mod 16, k^(d-1) = k mod 8. */ long k = 2*a+1; long s = ((cmp[degree]*k + 2*cmp[degree-1])*k + cf) & 0xf; if ((is_f_square16[16+a] = squares16[s])) np1++; } if ((is_f_square16[20] = squares16[(cmp[degree]+4*cmp[degree-1]) & 0xf])) np2++; if ((is_f_square16[21] = squares16[(cmp[degree]+12*cmp[degree-1]) & 0xf])) np2++; if ((is_f_square16[22] = squares16[(cmp[degree]+8*cmp[degree-1]) & 0xf])) np3++; if ((is_f_square16[23] = squares16[cmp[degree]])) np4++; } /* set den_bits */ { ulong db = 0; long i; if (npe + npo > 0) db |= 0xaaaaUL; /* odd denominators */ if (np1 > 0) db |= 0x4444UL; /* v_2(den) = 1 */ if (np2 > 0) db |= 0x1010UL; /* v_2(den) = 2 */ if (np3 > 0) db |= 0x0100UL; /* v_2(den) = 3 */ if (np4 > 0) db |= 0x0001UL; /* v_2(den) >= 4 */ if (db == 0) { *den_bits = 0UL; return num_none; } for (i = 16; i < BITS_IN_LONG; i <<= 1) db |= db << i; *den_bits = db; } result = (npe == 0) ? (npo == 0) ? num_none : num_odd : (npo == 0) ? num_even : num_all; } /* set up num_bits[16] */ /* odd denominators */ switch(result) { case num_all: for (b = 1; b < 16; b += 2) { ulong work = 0, bit = 1; long i, invb = b; /* inverse of b mod 16 */ if (b & 2) invb ^= 8; if (b & 4) invb ^= 8; for (i = 0; i < 16; i++) { if (is_f_square16[(invb*i) & 0xf]) work |= bit; bit <<= 1; } /* now repeat the 16 bits */ for (i = 16; i < BITS_IN_LONG; i <<= 1) work |= work << i; num_bits[b] = RBA(work); } break; case num_odd: for (b = 1; b < 16; b += 2) { ulong work = 0, bit = 1; long i, invb = b; /* inverse of b mod 16 */ if (b & 2) invb ^= 8; if (b & 4) invb ^= 8; for (i = 1; i < 16; i += 2) { if (is_f_square16[(invb*i) & 0xf]) work |= bit; bit <<= 1; } /* now repeat the 8 bits */ for (i = 8; i < BITS_IN_LONG; i <<= 1) { work |= work << i; } num_bits[b] = RBA(work); } break; case num_even: for (b = 1; b < 16; b += 2) { ulong work = 0, bit = 1; long i, invb = b; /* inverse of b mod 16 */ if (b & 2) invb ^= 8; if (b & 4) invb ^= 8; for (i = 0; i < 16; i += 2) { if (is_f_square16[(invb*i) & 0xf]) work |= bit; bit <<= 1; } /* now repeat the 8 bits */ for (i = 8; i < BITS_IN_LONG; i <<= 1) work |= work << i; num_bits[b] = RBA(work); } break; case num_none: for (b = 1; b < 16; b += 2) num_bits[b] = RBA(0UL); break; } /* v_2(den) = 1 : only odd numerators */ for (b = 1; b < 8; b += 2) { ulong work = 0, bit = 1; long i; for (i = 1; i < 16; i += 2) { if (is_f_square16[16 + (((b*i)>>1) & 0x3)]) work |= bit; bit <<= 1; } /* now repeat the 8 bits */ for (i = 8; i < BITS_IN_LONG; i <<= 1) work |= work << i; num_bits[2*b] = RBA(work); } /* v_2(den) = 2 : only odd numerators */ for (b = 1; b < 4; b += 2) { ulong work = 0, bit = 1; long i; for (i = 1; i < 8; i += 2) { if (is_f_square16[20 + (((b*i)>>1) & 0x1)]) work |= bit; bit <<= 1; } /* now repeat the 4 bits */ for (i = 4; i < BITS_IN_LONG; i <<= 1) work |= work << i; num_bits[4*b] = RBA(work); } /* v_2(den) = 3, >= 4 : only odd numerators */ num_bits[8] = (is_f_square16[22]) ? RBA(~(0UL)) : RBA(0UL); num_bits[0] = (is_f_square16[23]) ? RBA(~(0UL)) : RBA(0UL); return result; } /************************************************************************** * This is a comparison function needed for sorting in order to determine * * the `best' primes for sieving. * **************************************************************************/ static int compare_entries(const void *a, const void *b) { double diff = ((entry *)a)->r - ((entry *)b)->r; return (diff > 0) ? 1 : (diff < 0) ? -1 : 0; } /************************************************************************ * Collect the sieving information * ************************************************************************/ static long sieving_info(ratpoints_args *args, ratpoints_sieve_entry **sieve_list) { GEN c = args->cof; GEN inverses = args->inverses, squares; GEN offsets = args->offsets; ulong ** sieves0 = args->sieves0; long degree = degpol(c); long fba = 0, fdc = 0; long pn, pnp = 0; long n; long nbprime = lg(args->listprime)-1; entry *prec = (entry*) stack_malloc(nbprime*sizeof(entry)); /* This array is used for sorting in order to determine the `best' sieving primes. */ forbidden_entry *forb_ba = args->forb_ba; long *forbidden = args->forbidden; ulong bound = (1UL)<<(BITS_IN_LONG - args->bit_primes); pari_sp av = avma; squares = gen_squares(args->listprime); /* initialize sieve in se_buffer */ for (pn = 1; pn <= args->num_primes; pn++) { long coeffs_mod_p[degree+1]; /* The coefficients of f reduced modulo p */ ulong a, p = args->listprime[pn], np; long n; int *is_f_square = args->int_next; args->int_next += p + 1; /* need space for (p+1) int's */ /* compute coefficients mod p */ for (n = 0; n <= degree; n++) coeffs_mod_p[n] = umodiu(pel(c,n), p); np = umael(squares,pn,coeffs_mod_p[0]+1); is_f_square[0] = np; for (a = 1 ; a < p; a++) { ulong s = coeffs_mod_p[degree]; if ((degree+1)*args->bit_primes <= BITS_IN_LONG) { for (n = degree - 1 ; n >= 0 ; n--) s = s*a + coeffs_mod_p[n]; /* here, s < p^(degree+1) <= max. long */ s %= p; } else { for (n = degree - 1 ; n >= 0 ; n--) { s = s*a + coeffs_mod_p[n]; if (s+1 >= bound) s %= p; } s %= p; } if ((is_f_square[a] = mael(squares,pn,s+1))) np++; } is_f_square[p] = odd(degree) || mael(squares,pn,coeffs_mod_p[degree]+1); /* check if there are no solutions mod p */ if (np == 0 && !is_f_square[p]) { avma = av; return p; } /* Fill arrays with info for p */ if (np < p) { /* only when there is some information */ ulong i; ratpoints_sieve_entry *se = args->se_next; double r = is_f_square[p] ? ((double)(np*(p-1) + p))/((double)(p*p)) : (double)np/(double)p; prec[pnp].r = r; args->se_next ++; se->p = p; se->is_f_square = is_f_square; se->inverses = gel(inverses,pn); se->offset = offsets[pn]; se->sieve[0] = (ratpoints_bit_array *)sieves0[pn]; for (i = 1; i < p; i++) se->sieve[i] = NULL; prec[pnp].ssp = se; pnp++; } if ((args->flags & RATPOINTS_CHECK_DENOM) && fba + fdc < args->max_forbidden && !is_f_square[p]) { /* record forbidden divisors of the denominator */ if (coeffs_mod_p[degree] == 0) { /* leading coeff. divisible by p */ GEN r; long v = Z_lvalrem(pel(c,degree), p, &r); if (odd(v) || !mael(squares,pn, umodiu(r,p)+1)) { /* Can only get something when valuation is odd or when valuation is even and lcf is not a p-adic square. Compute smallest n such that if v(den) >= n, the leading term determines the valuation. Then we must have v(den) < n. */ long k, n = 1; for (k = degree-1; k >= 0; k--) { if (coeffs_mod_p[k] == 0) { long t = 1 + v - Z_lval(pel(c,k), p); long m = CEIL(t, (degree-k)); if (m > n) n = m; } } if (n == 1) { forb_ba[fba].p = p; forb_ba[fba].start = sieves0[pn]; forb_ba[fba].end = sieves0[pn]+p; forb_ba[fba].curr = forb_ba[fba].start; fba++; } else { forbidden[fdc] = upowuu(p, n); fdc++; } } } else /* leading coefficient is a non-square mod p */ { /* denominator divisible by p is excluded */ forb_ba[fba].p = p; forb_ba[fba].start = sieves0[pn]; forb_ba[fba].end = sieves0[pn]+p; forb_ba[fba].curr = forb_ba[fba].start; fba++; } } } /* end for pn */ /* update sp2 and sp1 if necessary */ if (args->sp2 > pnp) args->sp2 = pnp; if (args->sp1 > args->sp2) args->sp1 = args->sp2; /* sort the array to get at the best primes */ qsort(prec, pnp, sizeof(entry), compare_entries); /* put the sorted entries into sieve_list */ for (n = 0; n < args->sp2; n++) sieve_list[n] = prec[n].ssp; /* terminate array of forbidden divisors */ if (args->flags & RATPOINTS_CHECK_DENOM) { long n; for (n = args->num_primes+1; fba + fdc < args->max_forbidden && n <= nbprime; n++) { ulong p = args->listprime[n]; if (p*p > (ulong) args->b_high) break; if (kroiu(pel(c,degree), p) == -1) { forb_ba[fba].p = p; forb_ba[fba].start = sieves0[n]; forb_ba[fba].end = sieves0[n]+p; forb_ba[fba].curr = forb_ba[fba].start; fba++; } } forb_ba[fba].p = 0; /* terminating zero */ forbidden[fdc] = 0; /* terminating zero */ args->max_forbidden = fba + fdc; /* note actual number */ } if (fba + fdc == 0) args->flags &= ~RATPOINTS_CHECK_DENOM; avma = av; return 0; } /************************************************************************** * The sieving procedure itself * **************************************************************************/ static void sift(long b, ratpoints_bit_array *survivors, ratpoints_args *args, bit_selection which_bits, ratpoints_bit_array bits16, ratpoints_sieve_entry **sieve_list, long *bp_list, int *quit, int process(long, long, GEN, void*, int*), void *info) { pari_sp av = avma; sieve_spec ssp[args->sp2]; int do_setup = 1; long k, height = args->height, nb; if (odd(b) == 0) which_bits = num_odd; /* even denominator */ /* Note that b is new */ args->bc = NULL; nb = 0; for (k = 0; k < args->num_inter; k++) { ratpoints_interval inter = args->domain[k]; long low, high; /* Determine relevant interval [low, high] of numerators. */ if (b*inter.low <= -height) low = -height; else { if (b*inter.low > height) break; low = ceil(b*inter.low); } if (b*inter.up >= height) high = height; else { if (b*inter.up < -height) continue; high = floor(b*inter.up); } if (do_setup) { /* set up the sieve information */ long n; do_setup = 0; /* only do it once for every b */ for (n = 0; n < args->sp2; n++) { ratpoints_sieve_entry *se = sieve_list[n]; long p = se->p; long bp = bp_list[n]; ratpoints_bit_array *sptr; if (which_bits != num_all) /* divide by 2 mod p */ bp = odd(bp) ? (bp+p) >> 1 : bp >> 1; sptr = se->sieve[bp]; ssp[n].p = p; ssp[n].offset = (which_bits == num_odd) ? se->offset : 0; /* copy if already initialized, else initialize */ ssp[n].ptr = sptr ? sptr : (p>= 1; high--; high >>= 1; break; case num_even: low++; low >>= 1; high >>= 1; break; } /* now turn the bit interval into [low, high[ */ high++; if (low < high) { long w_low, w_high, w_low0, w_high0, range = args->array_size; /* Now the range of longwords (= bit_arrays) */ w_low = low >> RBA_SHIFT; w_high = (high + (long)(RBA_LENGTH-1)) >> RBA_SHIFT; w_low0 = w_low; w_high0 = w_low0 + range; for ( ; w_low0 < w_high; w_low0 = w_high0, w_high0 += range) { long i; if (w_high0 > w_high) { w_high0 = w_high; range = w_high0 - w_low0; } /* initialise the bits */ for (i = range; i; i--) survivors[i-1] = bits16; /* boundary words */ if (w_low0 == w_low) { long sh = low - RBA_LENGTH * w_low; ulong *survl = (ulong *)survivors; #ifdef HAS_SSE2 if (sh >= BITS_IN_LONG) { survl[0] = 0UL; survl[1] &= (~0UL)<<(sh - BITS_IN_LONG); } else survl[0] &= ~(0UL)<= BITS_IN_LONG) { survl[0] &= ~(0UL)>>(sh - BITS_IN_LONG); survl[1] = 0UL; } else survl[1] &= ~(0UL)>>sh; #else survl[0] &= ~(0UL)>>sh; #endif } nb += _ratpoints_sift0(b, w_low0, w_high0, args, which_bits, survivors, &ssp[0], quit, process, info); if (*quit) return; } } } if (nb==0) avma = av; } /************************************************************************** * Find points by looping over the denominators and sieving numerators * **************************************************************************/ static void find_points_work(ratpoints_args *args, int process(long, long, GEN, void*, int*), void *info) { int quit = 0; GEN c = args->cof; long degree = degpol(c); long nbprime = lg(args->listprime)-1; long height = args->height; int point_at_infty = 0; /* indicates if there are points at infinity */ int lcfsq = Z_issquare(pel(c,degree)); forbidden_entry *forb_ba = args->forb_ba; long *forbidden = args->forbidden; /* The forbidden divisors, a zero-terminated array. Used when degree is even and leading coefficient is not a square */ /* These are used when degree is odd and leading coeff. is not +-1 */ ratpoints_sieve_entry **sieve_list = (ratpoints_sieve_entry**) stack_malloc(nbprime*sizeof(ratpoints_sieve_entry*)); bit_selection which_bits = num_all; ulong den_bits; ratpoints_bit_array num_bits[16]; args->flags &= RATPOINTS_FLAGS_INPUT_MASK; args->flags |= RATPOINTS_CHECK_DENOM; /* initialize memory management */ args->se_next = args->se_buffer; args->ba_next = args->ba_buffer; args->int_next = args->int_buffer; /* Some sanity checks */ args->num_inter = 0; if (args->num_primes > nbprime) args->num_primes = nbprime; if (args->sp2 > args->num_primes) args->sp2 = args->num_primes; if (args->sp1 > args->sp2) args->sp1 = args->sp2; if (args->b_low < 1) args->b_low = 1; if (args->b_high < 1) args->b_high = height; if (args->b_high > height) args->b_high = height; if (args->max_forbidden < 0) args->max_forbidden = RATPOINTS_DEFAULT_MAX_FORBIDDEN; if (args->max_forbidden > nbprime) args->max_forbidden = nbprime; if (args->array_size <= 0) args->array_size = RATPOINTS_ARRAY_SIZE; { long s = 2*CEIL(height, BITS_IN_LONG); if (args->array_size > s) args->array_size = s; } /* Don't reverse if intervals are specified or limits for the denominator are given */ if (args->num_inter > 0 || args->b_low > 1 || args->b_high < height) args->flags |= RATPOINTS_NO_REVERSE; /* Check if reversal of polynomial might be better: * case 1: degree is even, but trailing coefficient is zero * case 2: degree is even, leading coefficient is a square, but * trailing coefficient is not * case 3: degree is odd, |leading coefficient| > 1, * trailing coefficient is zero, |coeff. of x| = 1 */ if (!(args->flags & RATPOINTS_NO_REVERSE)) { if (!odd(degree)) { if (signe(pel(c,0)) == 0) { /* case 1 */ long n; args->flags |= RATPOINTS_REVERSED; for (n = 0; n < degree>>1; n++) swap(pel(c,n), pel(c,degree-n)); degree--; setlg(c,degree+3); } else if (lcfsq && !Z_issquare(pel(c,0))) { /* case 2 */ long n; args->flags |= RATPOINTS_REVERSED; for (n = 0; n < degree>>1; n++) swap(pel(c,n), pel(c,degree-n)); lcfsq = 0; } } else { /* odd degree, case 3*/ if (!is_pm1(pel(c,degree)) && !signe(pel(c,0)) && is_pm1(pel(c,1))) { long n; args->flags |= RATPOINTS_REVERSED; for (n = 1; n < degree>>1; n++) swap(pel(c,n),pel(c,degree+1-n)); } } } /* Deal with the intervals */ if (args->num_inter == 0) { /* default interval (effectively ]-oo,oo[) if none is given */ args->domain = (ratpoints_interval*) stack_malloc(2*degree*sizeof(ratpoints_interval)); args->domain[0].low = -height; args->domain[0].up = height; args->num_inter = 1; } ratpoints_compute_sturm(args); /* Point(s) at infinity? */ if (odd(degree) || lcfsq) { args->flags &= ~RATPOINTS_CHECK_DENOM; point_at_infty = 1; } /* Can use only squares as denoms if degree is odd and poly is +-monic */ if (odd(degree)) { GEN w1 = pel(c,degree); if (is_pm1(w1)) args->flags |= RATPOINTS_USE_SQUARES; else /* set up information on divisors of leading coefficient */ setup_us1(args, absi_shallow(w1)); } /* deal with f mod powers of 2 */ which_bits = get_2adic_info(args, &den_bits, &num_bits[0]); /* which_bits says whether to consider even and/or odd numerators * when the denominator is odd. * * Bit k in den_bits is 0 if b congruent to k mod BITS_IN_LONG need * not be considered as a denominator. * * Bit k in num_bits[b] is 0 is numerators congruent to * k (which_bits = den_all) * 2k (which_bits = den_even) * 2k+1 (which_bits = den_odd) * need not be considered for denominators congruent to b mod 16. */ /* set up the sieve data structure */ if (sieving_info(args, sieve_list)) return; /* deal with point(s) at infinity */ if (point_at_infty) { long a = 1, b = 0; if (args->flags & RATPOINTS_REVERSED) { a = 0; b = 1; } if (odd(degree)) (void)process(a, b, gen_0, info, &quit); else { GEN w0 = sqrti(pel(c,degree)); (void)process(a, b, w0, info, &quit); (void)process(a, b, negi(w0), info, &quit); } if (quit) return; } /* now do the sieving */ { ratpoints_bit_array *survivors = (ratpoints_bit_array *) stack_malloc_align((args->array_size)*sizeof(ratpoints_bit_array), RBA_ALIGN); if (args->flags & (RATPOINTS_USE_SQUARES | RATPOINTS_USE_SQUARES1)) { if (args->flags & RATPOINTS_USE_SQUARES) /* need only take squares as denoms */ { long b, bb; long bp_list[args->sp2]; long last_b = args->b_low; long n; for (n = 0; n < args->sp2; n++) bp_list[n] = mod(args->b_low, sieve_list[n]->p); for (b = 1; bb = b*b, bb <= args->b_high; b++) if (bb >= args->b_low) { ratpoints_bit_array bits = num_bits[bb & 0xf]; if (TEST(bits)) { long n; long d = bb - last_b; /* fill bp_list */ for (n = 0; n < args->sp2; n++) bp_list[n] = mod(bp_list[n] + d, sieve_list[n]->p); last_b = bb; sift(bb, survivors, args, which_bits, bits, sieve_list, &bp_list[0], &quit, process, info); if (quit) break; } } } else /* args->flags & RATPOINTS_USE_SQUARES1 */ { GEN den_info = args->den_info; GEN divisors = args->divisors; long ld = lg(divisors); long k; long b, bb; long bp_list[args->sp2]; for (k = 1; k < ld; k++) { long d = divisors[k]; long last_b = d; long n; if (d > args->b_high) continue; for (n = 0; n < args->sp2; n++) bp_list[n] = mod(d, sieve_list[n]->p); for (b = 1; bb = d*b*b, bb <= args->b_high; b++) { if (bb >= args->b_low) { int flag = 1; ratpoints_bit_array bits = num_bits[bb & 0xf]; if (EXT0(bits)) { long i, n, l = lg(gel(den_info,1)); long d = bb - last_b; /* fill bp_list */ for (n = 0; n < args->sp2; n++) bp_list[n] = mod(bp_list[n] + d, sieve_list[n]->p); last_b = bb; for(i = 1; i < l; i++) { long v = z_lval(bb, mael(den_info,1,i)); if((v >= mael(den_info,3,i)) && odd(v + (mael(den_info,2,i)))) { flag = 0; break; } } if (flag) { sift(bb, survivors, args, which_bits, bits, sieve_list, &bp_list[0], &quit, process, info); if (quit) break; } } } } if (quit) break; } } } else { if (args->flags & RATPOINTS_CHECK_DENOM) { long *forb; long b; long bp_list[args->sp2]; long last_b = args->b_low; ulong b_bits; long n; for (n = 0; n < args->sp2; n++) bp_list[n] = mod(args->b_low, sieve_list[n]->p); { forbidden_entry *fba = &forb_ba[0]; long b_low = args->b_low; long w_low = (b_low-1) >> TWOPOTBITS_IN_LONG; b_bits = den_bits; while (fba->p) { fba->curr = fba->start + mod(w_low, fba->p); b_bits &= *(fba->curr); fba++; } b_bits >>= (b_low-1) & LONG_MASK; } for (b = args->b_low; b <= args->b_high; b++) { ratpoints_bit_array bits = num_bits[b & 0xf]; if ((b & LONG_MASK) == 0) { /* next b_bits */ forbidden_entry *fba = &forb_ba[0]; b_bits = den_bits; while (fba->p) { fba->curr++; if (fba->curr == fba->end) fba->curr = fba->start; b_bits &= *(fba->curr); fba++; } } else b_bits >>= 1; if (odd(b_bits) && EXT0(bits)) { /* check if denominator is excluded */ for (forb = &forbidden[0] ; *forb && (b % (*forb)); forb++) continue; if (*forb == 0 && rpjacobi(b, pel(c,degree)) == 1) { long n, d = b - last_b; /* fill bp_list */ for (n = 0; n < args->sp2; n++) { long bp = bp_list[n] + d; long p = sieve_list[n]->p; while (bp >= p) bp -= p; bp_list[n] = bp; } last_b = b; sift(b, survivors, args, which_bits, bits, sieve_list, &bp_list[0], &quit, process, info); if (quit) break; } } } } /* if (args->flags & RATPOINTS_CHECK_DENOM) */ else { long b, n; long bp_list[args->sp2]; long last_b = args->b_low; for (n = 0; n < args->sp2; n++) bp_list[n] = mod(args->b_low, sieve_list[n]->p); for (b = args->b_low; b <= args->b_high; b++) { ratpoints_bit_array bits = num_bits[b & 0xf]; if (EXT0(bits)) { long n; long d = b - last_b; /* fill bp_list */ for (n = 0; n < args->sp2; n++) { long bp = bp_list[n] + d; long p = sieve_list[n]->p; while (bp >= p) bp -= p; bp_list[n] = bp; } last_b = b; sift(b, survivors, args, which_bits, bits, sieve_list, &bp_list[0], &quit, process, info); if (quit) break; } } } } } } static GEN vec_append_grow(GEN z, long i, GEN x) { long n = lg(z)-1; if (i > n) { n <<= 1; z = vec_lengthen(z,n); } gel(z,i) = x; return z; } struct points { GEN z; long i, f; }; static int process(long a, long b, GEN y, void *info0, int *quit) { struct points *p = (struct points *) info0; if (b==0 && (p->f&2L)) return 0; *quit = (p->f&1); p->z = vec_append_grow(p->z, ++p->i, mkvec3(stoi(a),y,stoi(b))); return 1; } static GEN ZX_hyperellratpoints(GEN P, GEN h, long flag) { pari_sp av = avma; ratpoints_args args; struct points data; ulong flags = 0; if (!ZX_is_squarefree(P)) pari_err_DOMAIN("hyperellratpoints","issquarefree(pol)","=",gen_0, P); if (typ(h)==t_INT && signe(h)>0) { long H = itos(h); args.height = H; args.b_low = 1; args.b_high = H; } else if (typ(h)==t_VEC && lg(h)==3) { args.height = gtos(gel(h,1)); if (typ(gel(h,2))==t_INT) { args.b_low = 1; args.b_high = itos(gel(h,2)); } else if (typ(gel(h,2))==t_VEC && lg(gel(h,2))==3) { args.b_low = gtos(gmael(h,2,1)); args.b_high = gtos(gmael(h,2,2)); } else pari_err_TYPE("hyperellratpoints",h); } else pari_err_TYPE("hyperellratpoints",h); find_points_init(&args, RATPOINTS_DEFAULT_BIT_PRIMES); args.cof = shallowcopy(P); args.num_inter = 0; args.sp1 = RATPOINTS_DEFAULT_SP1; args.sp2 = RATPOINTS_DEFAULT_SP2; args.array_size = RATPOINTS_ARRAY_SIZE; args.num_primes = RATPOINTS_DEFAULT_NUM_PRIMES; args.bit_primes = RATPOINTS_DEFAULT_BIT_PRIMES; args.max_forbidden = RATPOINTS_DEFAULT_MAX_FORBIDDEN; args.flags = flags; data.z = cgetg(17,t_VEC); data.i = 0; data.f = flag; find_points_work(&args, process, (void *)&data); setlg(data.z, data.i+1); return gerepilecopy(av, data.z); } static GEN ZX_homogenous_evalpow(GEN Q, GEN A, GEN B) { pari_sp av = avma; long i, d = degpol(Q); GEN s = gel(Q, d+2); for (i = d-1; i >= 0; i--) s = addii(mulii(s, A), mulii(gel(B,d+1-i), gel(Q,i+2))); return gerepileuptoint(av, s); } static GEN to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; } static int hyperell_check(GEN PQ, GEN *P, GEN *Q) { *P = *Q = NULL; if (typ(PQ) == t_POL) { if (!RgX_is_ZX(PQ)) return 0; *P = PQ; } else { long v = gvar(PQ); if (v == NO_VARIABLE || typ(PQ) != t_VEC || lg(PQ) != 3) return 0; *P = to_ZX(gel(PQ,1), v); if (!RgX_is_ZX(*P)) return 0; *Q = to_ZX(gel(PQ,2), v); if (!RgX_is_ZX(*Q)) return 0; if (!signe(*Q)) *Q = NULL; } return 1; } GEN hyperellratpoints(GEN PQ, GEN h, long flag) { pari_sp av = avma; GEN P, Q, H, L; long i, l, dy, dQ; if (flag<0 || flag>1) pari_err_FLAG("ellratpoints"); if (!hyperell_check(PQ, &P, &Q)) pari_err_TYPE("hyperellratpoints",PQ); if (!Q) { L = ZX_hyperellratpoints(P, h, flag|2L); dy = (degpol(P)+1)>>1; l = lg(L); for (i = 1; i < l; i++) { GEN Li = gel(L,i), x = gel(Li,1), y = gel(Li,2), z = gel(Li,3); gel(L,i) = mkvec2(gdiv(x,z), gdiv(y, powiu(z, dy))); } return gerepilecopy(av, L); } H = ZX_add(ZX_shifti(P,2), ZX_sqr(Q)); dy = (degpol(H)+1)>>1; dQ = degpol(Q); L = ZX_hyperellratpoints(H, h, flag|2L); l = lg(L); for (i = 1; i < l; i++) { GEN Li = gel(L,i), x = gel(Li,1), y = gel(Li,2), z = gel(Li,3); GEN B = gpowers(z, dQ); GEN Qx = gdiv(ZX_homogenous_evalpow(Q, x, B), gel(B, dQ+1)); gel(L,i) = mkvec2(gdiv(x,z), gmul2n(gsub(gdiv(y,powiu(z, dy)),Qx),-1)); } return gerepilecopy(av, L); } GEN ellratpoints(GEN E, GEN h, long flag) { pari_sp av = avma; GEN L, a1, a3; long i, l; checkell_Q(E); if (flag<0 || flag>1) pari_err_FLAG("ellratpoints"); if (!RgV_is_ZV(vecslice(E,1,5))) pari_err_TYPE("ellratpoints",E); a1 = ell_get_a1(E); a3 = ell_get_a3(E); L = ZX_hyperellratpoints(ec_bmodel(E), h, flag|2L); l = lg(L); for (i = 1; i < l; i++) { GEN P, Li = gel(L,i), x = gel(Li,1), y = gel(Li,2), z = gel(Li,3); if (!signe(z)) P = ellinf(); else { GEN z2 = sqri(z); y = subii(y, addii(mulii(a1, mulii(x,z)), mulii(a3,z2))); P = mkvec2(gdiv(x,z), gdiv(y,shifti(z2,1))); } gel(L,i) = P; } return gerepilecopy(av, L); } pari-2.11.2/src/modules/groupid.c0000644000175000017500000005067213326135265015252 0ustar billbill/* Copyright (C) 2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" static long groupelts_sumorders(GEN S) { long i, s = 0; for(i=1; i < lg(S); i++) s += perm_order(gel(S,i)); return s; } static long vecgroup_sumorders(GEN L) { long i, s = 0; for(i=1; i3*/ { long q= p[2], q2 = q*q, p3 = (q%3 == 1), p9 = (q%9 == 1); if (s==7+47*q+7*q2) return 1; /* 3p.3 */ if (s==61-61*q+61*q2) return 1+p3; /* 9p */ if (s==1+59*q+q2) return 3; /* p:9 */ if (s==7+11*q+7*q2) return 3+p9; /* p:3x3 */ return 2+2*p3+p9; /* 3^2xp */ } break; } case 3: switch(e[1]+e[2]+e[3]) { case 3: /*pqr*/ if (p[1]==2) /*2qr*/ { long q = p[2],q2 = q*q, qc = 1-q+q2, qd = 1+q+q2; long r = p[3],r2 = r*r, rc = 1-r+r2, rd = 1+r+r2; long pmq = (r%q==1)? 2: 0; if (pmq && s==3*r*(q2-q)+rd) return 1; /* r:2q */ if (pmq && s==3*(r2+(q2-q-1)*r+1)) return 2; /* r:qx2 */ if (s==qd*rc) return 1+pmq; /* D2qxr */ if (s==rd*qc) return 2+pmq; /* D2rxq */ if (s==3*qc*rc) return 4+pmq; /* 2qr */ return 3+pmq; /* q:2+r:2 */ } break; } } { const long tab[]={ 24, 173, 301, 99, 125, 113, 101, 97, 85, 161, 133, 189, 67, 87, 73, 105, -1, 36, 255, 671, 265, 219, 427, 243, 147, 275, 115, 127, 121, 159, 111, 175, -1, 40, 391, 903, 263, 311, 291, 271, 227, 207, 483, 399, 567, 163, 187, 315, -1, 56, 697, 1849, 585, 557, 529, 413, 385, 989, 817, 1161, 351, 357, 645, -1, 60, 945, 721, 561, 1617, 211, 497, 337, 373, 651, 581, 693, 501, 1029, -1, 75, 3647, 271, 847, -1, 84, 647, 935, 1935, 1295, 1071, 3311, 451, 699, 595, 1333, 469, 1099, 1419, 987, 2107, -1, 88, 1573, 4773, 1397, 1353, 1309, 953, 909, 2553, 2109, 2997, 865, 1665, -1, 90, 1659, 1891, 1371, 3843, 775, 1407, 735, 903, 615, 1575, -1, 104, 2143, 6751, 991, 1935, 1883, 1831, 1307, 1255, 3611, 2983, 4239, 731, 1203, 2355, -1, 105, 1785, 6321, -1, 126, 1533, 2037, 3397, 3477, 2749, 7869, 777, 937, 721, 1281, 1425, 2881, 1369, 1849, 1201, 3225, -1, 132, 4995, 2947, 2595, 8547, 1663, 3441, 2639, 3663, 2463, 5439, -1, 136, 3547, 11739, 1499, 3275, 3207, 3139, 2183, 2115, 6279, 5187, 7371, 987, 1159, 2047, 4095, -1, 140, 4429, 3885, 2989, 9933, 3053, 1613, 1697, 3297, 3569, 2849, 6321, -1, -1}; long i; const long *t; for(t=tab;*t!=-1;t++) { if (t[0]==n) { for(i=1; t[i] != -1; i++) if (t[i]==s) return i; return -1; } while (*t>=0) t++; } } { const long tab[]={ 16, 1710031, 550075, 70099, 70075, 870059, 110059, 30079, 30071, 30063, 470131, 70155, 70107, 110115, 310307, -1, 32, 6830063, 150323, 1830171, /*230171*/0, 230227, 30283, 30251, 30203, /*70267*/0, 70219, 110227, /*230171*/0, /*70187*/0, /*70187*/0, 110155, 3430123, 430123, 30191, 30175, 30159, 1110387, 150563, 150387, 230323, 230411, 230299, 70619, 70467, 70355, /*70379*/0, /*70379*/0, /*70267*/0, 70291, 70555, 70331, 1750291, 230291, 430275, 70411, 70363, 70315, 110331, 30371, 30323, 950819, 150995, 150643, 230691, 30747, 30635, 632451, -1, 48, 430156, 11970124, 10219, 430324, 110324, 30396, 30444, 30348, 230300, 110300, 230396, /*70396*/0, /*70396*/0, 70540, 30412, 30364, 30380, 30332, 70492, 3850300, 490396, 490300, 6090236, 770236, 210316, 210284, 210252, 30299, 30371, 30363, 110299, 70311, 110271, 70588, 230732, 70876, 110636, 30868, 30628, 30596, 30644, 150684, 70828, 3290524, 490620, 490428, 770460, 30627, 70571, 10643, 151740, 2171228, -1, 54, 10256, 16410120, 70292, 610232, 10373, 10292, 10616, 70517, 5610228, 210309, 210228, 250448, 70616, 11696, 2370552, -1, /*64*/ 72, 110307, 26230195, 210272, 30523, 110631, 30739, 70575, 30683, 14030351, 1830403, 1830299, 770346, 110586, 10750330, 10620, 210420, 71223, 9150663, 30426, 30858, 30978, 30954, 31074, 30762, 210452, 210538, 770634, 210730, 490626, 210722, 31018, 111234, 31450, 71106, 31322, 5750594, 750682, 750506, 10346, 10826, 10490, 70620, 11124, 10716, 30786, 31746, 210636, 491202, 72402, 3751122, -1, 80, 430250, 35910186, 110282, 430530, 110530, 30650, 30730, 30570, 230482, 110482, 230642, /*70642*/0, /*70642*/0, 70882, 30666, 30586, 30618, 30538, 70786, 11550450, 1470594, 1470450, 18270354, 2310354, 630474, 630426, 630378, 110562, 30562, 110722, 30722, 70546, 30546, 30946, 70962, 231202, 71442, 111042, 31426, 31026, 30978, 31058, 151106, 71346, 9870786, 1470930, 1470642, 2310690, 10467, 71266, 152866, 6511842, -1, 81,49210121, 6730319, 250427, 250319, 16450238, 610238, 70454, 70346, 70400, 70319, 5650670, 250994, 250670, 610589, 2412452, -1, /*96*/ 100, 30393, 57310217, 10481, 30693, 36470341, 630408, 30968, 13310392, 210416, 10576, 11256, 10856, 11096, 630648, 31768, 8470616, -1, 108, 30552, 60170280, 610359, 30984, 38290440, 210660, 1830540, 30849, 30660, 31308, 211137, 20570532, 770721, 770532, 70769, 11636, 11813, 610647, 70647, 250674, 70674, 70890, 211092, 1830852, 31389, 31092, 32388, 211965, 13090836, 491133, 490836, 751080, 211416, 33576, 8691288, 70904, 11048, 71720, 13688, 12344, 251538, 751608, 212280, 36600, 5532024,-1, 112, 430344, 73530248, 430736, 110736, 30904, 31016, 30792, 230664, 110664, 230888, 0/*70888*/, 0/*70888*/, 71224, 30920, 30808, 30856, 30744, 71080, 23650600, 3010792, 3010600, 37410472, 4730472, 1290632, 1290568, 1290504, 71336, 231672, 72008, 111448, 31984, 31424, 31360, 31472, 151528, 71864, 20211048, 3011240, 3010856, 4730920, 30643, 153992, 13332456,-1, 120, 2310456, 770488, 110648, 63210360, 30763, 210552, 30712, 31256, 31240, 31336, 31400, 31496, 31480, 31096, 630498, 210808, 770968, 211128, 490904, 211064, 630744, 2310888, 631032, 1470840, 630984, 31128, 111368, 31608, 71224, 31464, 33810648, 4410744, 4410552, 11211, 31263, 11416, 210858, 11290, 11090, 211032, 31352, 32600, 630738, 491864, 1471704, 72664, 22051224, -1, 135, 114870240, 39270456, 1470618, 1470456, 16591104 , -1, -1}; long i; const long *t; GEN Z = groupelts_center(S), L = group_subgroups(G); long scenter = groupelts_sumorders(Z), svecgroup = vecgroup_sumorders(L); long u = svecgroup+10000*scenter; /*This is used as a hash value*/ for(t=tab; *t!=-1; t++) { if (t[0]==n) { for(i=1; t[i] != -1; i++) if (t[i]==u) return i; switch(n) { case 32: switch(u) { case 230171: { const long good[]={2,0}, bad[]={4,5,0}; return indexgroupcentre(G,Z,good,bad)? 4: 12; } case 70267: if (s==135) return 9; return 32; case 70187: { const long good[]={8,0}, bad[]={7,9,0}; return indexgroupcentre(G,Z,good,bad)? 13: 14; } case 70379: { const long good[]={4,0},bad[]={0}; return indexgroupsubgroup(L,8,good,bad)? 31: 30; } } break; case 48: case 80: { const long good[]={5,8,0},bad[]={6,7,0}; return indexgroupcentre(G,Z,good,bad)? 12: 13; } case 112: { const long good[]={7,4,0},bad[]={5,6,0}; return indexgroupcentre(G,Z,good,bad)? 11: 12; } } return -1; } while (*t!=-1) t++; } { const long tab[]={ 64, 1270001, /*4270003*/0, /*4270003*/0, 8190072, 6430073, 6670445, 5550446, 8190278, 7070279, 6350071, 5230072, 8110154, /*5870155*/0, /*5870155*/0, /*4270042*/0, /*4270042*/0, 7710246, 7390277, 6750037, 8032377, 8670266, 6750397, 11390022, 7710267, 7070277, /*3630046*/0, /*3630046*/0, 3630057, 4830196, 4830207, 4671808, 9070697, 6670700, 8750094, 6990091, 6350111, 5870115, 6671599, 5711601, 5551702, 5871512, 6351709, 5391711, /*3630046*/0, 3630047, 4111467, /*4430156*/0, /*4430156*/0, 3790166, /*2510026*/0, /*2510026*/0, 4470028, 4150300, 3830030, 13470021, 20350065, 10910041, 16514365, /*12190433*/0, 34110271, /*16514475*/0, 15230465, /*10910433*/0, 9630041, 13470233, /*16514475*/0, 20834696, /*10910433*/0, 13954343, /*12190433*/0, 19553542, 13474377, 25790466, 15870467, 18914476, 14110477, /*14590443*/0, 13310443, 11550043, /*14590443*/0, 10270043, 8990002, 8990546, 8990646, 8993647, 8356896, 13310905, 13310915, 12039018, 16990866, 12670888, 15071116, 11551217, 12038218, 16031739, 12512740, 12353138, 12993048, 15391849, 11872850, 12993551, 12353851, 8991446, 8991447, 8354830, 9951566, 9951666, 8674709, 9317039, 8031897, 8030187, 7713641, 7714641, 7074743, 9236585, 9236415, 9236586, 10990821, 9879066, 8751833, 9873399, 8751766, 10990754, 8593054, 8593087, 6830446, 6833546, 17472434, 13953445, 14432313, 16352544, 12833555, 13313423, 15635143, 13234877, 13874853, 12755287, 17870919, 14190949, 13075209, 11955310, 10835253, 9715354, 11312124, 10193135, 11074927, 12197529, 9957664, 11074970, 12196539, 9956674, 9958907, 10439497, 9479551, 9554015, 8433958, 9553915, 8434058, 8918081, 7798421, 10110856, 10110756, 9476648, 8991757, 8991857, 8356682, 10994275, 8750435, 8590474, 9230510, 10355254, 8115355, 13556790, 15790679, 11310691, 12275539, 14035061, 11795172, 8750465, 7474472, 8750475, 8114920, 6110196, 6111806, 5951808, 10191819, 9238364, 8271841, 8590736, 9390959, 8432079, 25470255, 41792701, 25470275, 20355344, 27233751, 18593673, 19717567, 23394762, 17312707, 19717633, 46115277, 31557088, 22917189, 24677288, 24039835, 24676366, 16032362, 17793529, 17153269, 38432486, 21153763, 23393635, 16037076, 27710971, 27074338, 20995174, 23396204, 20193482, 17157790, 19550231, 14751475, 17153832, 19070249, 16038080, 33391110, 25875097, 22197835, 22195018, 21070221, 24590112, 18999456, 15952565, 18356361, 17237769, 18359003, 15951169, 14832955, 16110295, 18350268, 21392354, 22030301, 18353365, 15955257, 13550032, 18430405, 18434015, 17150260, 17154128, 27234036, 23710639, 20194057, 21157900, 24198470, 20679613, 21158141, 22435065, 21318520, 20197076, 67390501, 83715011, 51070497, 54590283, 58915129, 50275230, 52035340, 263870051, -1, -1}; long i; const long *t; GEN V=vecgroup_idxlist(L,32); long idxlist=vecsmall_pack(V,10,9967); long w=10000*svecgroup+idxlist; /*This is used as a hash value*/ for(t=tab; *t!=-1; t++) { if (t[0]==n) { for(i=1; t[i] != -1; i++) if (t[i]==w) return i; switch(n) { case 64: switch(w) { case 4270003: return (scenter==439)? 2: 3; case 5870155: { const long good[]={8,9,0},bad[]={7,0}; return indexgroupcentre(G,Z,good,bad)? 13: 14; } case 4270042: { const long good[]={13,0},bad[]={14,0}; return indexgroupcentre(G,Z,good,bad)? 15: 16; } case 4430156: { const long good[]={18,20,0},bad[]={19,0}; return indexgroupcentre(G,Z,good,bad)? 47: 48; } case 2510026: return scenter==1367? 50: 51; case 12190433: return scenter==47? 59: 70; case 16514475: { const long good[]={22,24,28,0},bad[]={23,25,27,30,0}; return indexgroupcentre(G,Z,good,bad)? 61: 66; } case 10910433: { const long good[]={23,31,0},bad[]={25,26,29,30,33,0}; return indexgroupcentre(G,Z,good,bad)? 63: 68; } case 14590443: { const long good[]={28,33,0},bad[]={30,34,0}; return indexgroupcentre(G,Z,good,bad)? 77: 80; } case 3630046: { const long good[]={3,0},bad[]={12,16,0}; if (scenter==695) return 26; return indexgroupcentre(G,Z,good,bad)? 27: 44; } } break; } return -1; } while (*t!=-1) t++; } } { const long tab[]={ 96, 316010002, 252010002, 707020000, 676160124, 676170124, 87180027, 988190278, 892200028, 876030110, 876040110, 876120110, 215111237, 503062153, 972141052, 972131052, 455091156, 167101154, 620160033, 620170033, 908031033, 908121033, 908041033, 199101564, 7130153, 7140153, 812150123, 247051165, 487091566, 812151024, 391071276, 103081274, 247111377, 988180195, 892190205, 924190197, 828200207, 103050134, 679020464, 295091075, 199070145, 391060235, 103101076, 7080146, 135111157, 295020044, 684030223, 684040223, 908050274, 135060255, 7070285, 812080286, 71092475, 876102476, 908112287, 684120223, 748130243, 748140243, 620150254, 492160043, 492170043, 764180045, 700190477, 636200047, 963110003, 779050031, 935100032, 799110033, 819210003, 791260032, 246270050, 723330003, 987340003, 651360031, 623380033, 647263930, 839351534, 455321350, 178211335, 791244031, 322256848, 189340236, 130316409, 599331360, 743244548, 935295937, 551333907, 189222029, 274255883, 525275609, 82306043, 610289391, 82315641, 82307025, 647262487, 839353950, 0/*455322385*/, 0/*455322385*/, 178233588, 791245051, 322256982, 130307015, 658286619, 983297004, 983297037, 599333858, 631365165, 631376165, 535386399, 66408676, 354390966, 871428265, 775411064, 631376407, 535386309, 114430028, 823441008, 314398920, 74437993, 831420054, 42405827, 90439425, 799440830, 847426805, 767410275, 815440314, 863429143, 487360134, 487371044, 66211564, 66231664, 871295713, 66231764, 679242567, 125228724, 210253894, 18306803, 546288536, 162390938, 919437378, 871401018, 162255761, 967304398, 967313318, 413274329, 498283470, 498288163, 29345108, 967401139, 727449579, 679411219, 775352619, 583261276, 919295225, 66312839, 423381047, 2437470, 759424560, 711448550, 770222372, 109272382, 551210244, 258222592, 551230264, 295242430, 647254411, 199262266, 482272602, 871283751, 423293752, 519303751, 519312662, 71320222, 167332232, 226340245, 327352266, 167360274, 167372584, 103382587, 647392595, 455406162, 263412616, 327428742, 487438955, 295440098, 358290331, 622253358, 886280358, 322410312, 754400322, 394443122, 282440313, 354423123, 522430323, 726220349, 990273529, 470450359, 742460359, 522470032, 198470031, 282480353, 290490033, 274500353, 414470000, 614490000, 605473864, 664459790, 723464091, 893482714, 675465704, 845486215, 184493728, 653478045, 941489155, 605501588, 925482982, 264492577, 589502601, 312450472, 371466994, 285450492, 989464902, 578470486, 770489139, 994490497, 546500507, 604460529, 65270050, 684510049, 468510050, 134510562, 831510052, -1 -1}; long i; const long *t; GEN V=vecgroup_idxlist(L,48); long idx48=vecsmall_pack(V,10,9967); long idx32=vecgroup_idxlist(L,32)[1]; long w=1000000*(svecgroup%997)+10000*idx32+idx48; /*This is used as a hash value*/ for(t=tab; *t!=-1; t++) { if (t[0]==n) { for(i=1; t[i] != -1; i++) if (t[i]==w) return i; switch(n) { case 96: switch(w) { case 455322385: { const long good[]={37,40,0},bad[]={34,41,0}; return indexgroupcentre(G,Z,good,bad)? 96: 97; } } break; } return -1; } while (*t!=-1) t++; } } } return 0; } long group_ident(GEN G, GEN S) { pari_sp av = avma; long idx = group_ident_i(G, S); if (idx < 0) pari_err_TYPE("group_ident [not a group]", G); if (!idx) pari_err_IMPL("galoisidentify for groups of order > 127"); avma = av; return idx; } long group_ident_trans(GEN G, GEN S) { const long tab[]={ 4, 1, 2, -1, 6, 2, 1, -1, 8, 1, 2, 4, 5, 3, -1, 9, 1, 2, -1, 10, 2, 1, -1, 12, 5, 1, 4, 3, 2, -1, 14, 2, 1, -1, 15, 1, -1, 16, 1, 4, 10, 8, 5, 6, 13, 12, 14, 2, 9, 7, 11, 3, -1, 18, 5, 1, 3, 4, 2, -1, 20, 2, 1, 5, 4, 3, -1, 21, 2, 1, -1, 22, 2, 1, -1, 24, 8, 1, 7, 5, 12, 13, 6, 14, 2, 15, 4, 10, 9, 11, 3, -1, 25, 1, 2, -1, 26, 2, 1, -1, 27, 1, 2, 3, 5, 4, -1, 28, 3, 1, 4, 2, -1, 30, 2, 4, 3, 1, -1, -1}; long n = group_order(G), s; const long *t; if (n == 1) return 1; /* N.B. known up to 32 (Cannon-Holt) */ if (n > 30) pari_err_IMPL("group_ident_trans [n > 30]"); if (uisprime(n)) return 1; s = group_ident(G,S); for(t=tab;*t>=0;t++) { if (t[0]==n) return t[s]; while (*t>=0) t++; } return 0; /*LCOV_EXCL_LINE*/ } pari-2.11.2/src/modules/krasner.c0000644000175000017500000006277413326135265015254 0ustar billbill/* Copyright (C) 2009 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /************************************************************/ /* Computation of all the extensions of a given */ /* degree of a p-adic field */ /* Xavier Roblot */ /************************************************************/ /* cf. Math. Comp, vol. 70, No. 236, pp. 1641-1659 for more details. Note that n is now e (since the e from the paper is always = 1) and l is now f */ /* Structure for a given type of extension */ typedef struct { GEN p; long e, f, j; long a, b, c; long v; /* auxiliary variable */ long r; /* pr = p^r */ GEN pr; /* p-adic precision for poly. reduction */ GEN q, qm1; /* p^f, q - 1 */ GEN T; /* polynomial defining K^ur */ GEN frob; /* Frobenius acting of the root of T (mod pr) */ GEN u; /* suitable root of unity (expressed in terms of the root of T) */ GEN nbext; /* number of extensions */ GEN roottable; /* table of roots of polynomials over the residue field */ GEN pk; /* powers of p: [p^1, p^2, ..., p^c] */ } KRASNER_t; /* Structure containing the field data (constructed with FieldData) */ typedef struct { GEN p; GEN top; /* absolute polynomial of a = z + pi (mod pr) */ GEN topr; /* top mod p */ GEN z; /* root of T in terms of a (mod pr) */ GEN eis; /* relative polynomial of pi in terms of z (mod pr) */ GEN pi; /* prime element in terms of a */ GEN ipi; /* p/pi in terms of a (mod pr) (used to divide by pi) */ GEN pik; /* [1, pi, ..., pi^(e-1), pi^e/p] in terms of a (mod pr). Note the last one is different! */ long cj; /* number of conjugate fields */ } FAD_t; #undef CHECK /* Eval P(x) assuming P has positive coefficients and the result is a long */ static ulong ZX_z_eval(GEN P, ulong x) { long i, l = lg(P); ulong z; if (typ(P) == t_INT) return itou(P); if (l == 2) return 0; z = itou(gel(P, l-1)); for (i = l-2; i > 1; i--) z = z*x + itou(gel(P,i)); return z; } /* Eval P(x, y) assuming P has positive coefficients and the result is a long */ static ulong ZXY_z_eval(GEN P, ulong x, ulong y) { long i, l = lg(P); ulong z; if (l == 2) return 0; z = ZX_z_eval(gel(P, l-1), y); for (i = l-2; i > 1; i--) z = z*x + ZX_z_eval(gel(P, i), y); return z; } /* P an Fq[X], where Fq = Fp[Y]/(T(Y)), a an FpX representing the automorphism * y -> a(y). Return a(P), applying a() coefficientwise. */ static GEN FqX_FpXQ_eval(GEN P, GEN a, GEN T, GEN p) { long i, l; GEN Q = cgetg_copy(P, &l); Q[1] = P[1]; for (i = 2; i < l; i++) { GEN cf = gel(P, i); if (typ(cf) == t_POL) { switch(degpol(cf)) { case -1: cf = gen_0; break; case 0: cf = gel(cf,2); break; default: cf = FpX_FpXQ_eval(cf, a, T, p); cf = simplify_shallow(cf); break; } } gel(Q, i) = cf; } return Q; } /* Sieving routines */ static GEN InitSieve(long l) { return zero_F2v(l); } static long NextZeroValue(GEN sv, long i) { for(; i <= sv[1]; i++) if (!F2v_coeff(sv, i)) return i; return 0; /* sieve is full or out of the sieve! */ } static void SetSieveValue(GEN sv, long i) { if (i >= 1 && i <= sv[1]) F2v_set(sv, i); } /* return 1 if the data verify Ore condition and 0 otherwise */ static long VerifyOre(GEN p, long e, long j) { long nv, b, vb, nb; if (j < 0) return 0; nv = e * u_pval(e, p); b = j%e; if (b == 0) return (j == nv); if (j > nv) return 0; /* j < nv */ vb = u_pval(b, p); nb = vb*e; return (nb <= j); } /* Given [K:Q_p] = m and disc(K/Q_p) = p^d, return all decompositions K/K^ur/Q_p * as [e, f, j] with * K^ur/Q_p unramified of degree f, * K/K^ur totally ramified of degree e and discriminant p^(e+j-1); * thus d = f*(e+j-1) and j > 0 iff ramification is wild */ static GEN possible_efj_by_d(GEN p, long m, long d) { GEN rep, div; long i, ctr, l; if (d == 0) return mkvec(mkvecsmall3(1, m, 0)); /* unramified */ div = divisorsu(ugcd(m, d)); l = lg(div); ctr = 1; rep = cgetg(l, t_VEC); for (i = 1; i < l; i++) { long f = div[i], e = m/f, j = d/f - e + 1; if (VerifyOre(p, e, j)) gel(rep, ctr++) = mkvecsmall3(e, f, j); } setlg(rep, ctr); return rep; } /* return the number of extensions corresponding to (e,f,j) */ static GEN NumberExtensions(KRASNER_t *data) { ulong pp, pa; long e, a, b; GEN p, q, s0, p1; e = data->e; p = data->p; q = data->q; a = data->a; /* floor(j/e) <= v_p(e), hence p^a | e */ b = data->b; /* j % e */ if (is_bigint(p)) /* implies a = 0 */ return b == 0? utoipos(e): mulsi(e, data->qm1); pp = p[2]; switch(a) { case 0: pa = 1; s0 = utoipos(e); break; case 1: pa = pp; s0 = mului(e, powiu(q, e / pa)); break; default: pa = upowuu(pp, a); /* p^a */ s0 = mulsi(e, powiu(q, (e / pa) * ((pa - 1) / (pp - 1)))); } /* s0 = e * q^(e*sum(p^-i, i=1...a)) */ if (b == 0) return s0; /* q^floor((b-1)/p^(a+1)) */ p1 = powiu(q, sdivsi(b-1, muluu(pa, pp))); return mulii(mulii(data->qm1, s0), p1); } static GEN get_topx(KRASNER_t *data, GEN eis) { GEN p1, p2, rpl, c; pari_sp av; long j; /* top poly. is the minimal polynomial of root(T) + root(eis) */ if (data->f == 1) return eis; c = FpX_neg(pol_x(data->v),data->pr); rpl = FqX_translate(eis, c, data->T, data->pr); p1 = p2 = rpl; av = avma; for (j = 1; j < data->f; j++) { /* compute conjugate polynomials using the Frobenius */ p1 = FqX_FpXQ_eval(p1, data->frob, data->T, data->pr); p2 = FqX_mul(p2, p1, data->T, data->pr); if (gc_needed(av,2)) gerepileall(av, 2, &p1,&p2); } return simplify_shallow(p2); /* ZX */ } /* eis (ZXY): Eisenstein polynomial over the field defined by T. * topx (ZX): absolute equation of root(T) + root(eis). * Return the struct FAD corresponding to the field it defines (GENs created * as clones). Assume e > 1. */ static void FieldData(KRASNER_t *data, FAD_t *fdata, GEN eis, GEN topx) { GEN p1, p2, p3, z, ipi, cipi, dipi, t, Q; fdata->p = data->p; t = leafcopy(topx); setvarn(t, data->v); fdata->top = t; fdata->topr = FpX_red(t, data->pr); if (data->f == 1) z = gen_0; else { /* Compute a root of T in K(top) using Hensel's lift */ z = pol_x(data->v); p1 = FpX_deriv(data->T, data->p); /* First lift to a root mod p */ for (;;) { p2 = FpX_FpXQ_eval(data->T, z, fdata->top, data->p); if (gcmp0(p2)) break; p3 = FpX_FpXQ_eval(p1, z, fdata->top, data->p); z = FpX_sub(z, FpXQ_div(p2, p3, fdata->top, data->p), data->p); } /* Then a root mod p^r */ z = ZpX_ZpXQ_liftroot(data->T, z, fdata->top, data->p, data->r); } fdata->z = z; fdata->eis = eis; fdata->pi = Fq_sub(pol_x(data->v), fdata->z, FpX_red(fdata->top, data->p), data->p); ipi = RgXQ_inv(fdata->pi, fdata->top); ipi = Q_remove_denom(ipi, &dipi); Q = mulii(data->pr, data->p); cipi = Fp_inv(diviiexact(dipi, data->p), Q); fdata->ipi = FpX_Fp_mul(ipi, cipi, Q); /* p/pi mod p^(pr+1) */ /* Last one is set to pi^e/p (so we compute pi^e with one extra precision) */ p2 = mulii(data->pr, data->p); p1 = FpXQ_powers(fdata->pi, data->e, fdata->topr, p2); gel(p1, data->e+1) = ZX_Z_divexact(gel(p1, data->e+1), data->p); fdata->pik = p1; } /* return pol*ipi/p (mod top, pp) if it has integral coefficient, NULL otherwise. The result is reduced mod top, pp */ static GEN DivideByPi(FAD_t *fdata, GEN pp, GEN ppp, GEN pol) { GEN P; long i, l; pari_sp av = avma; /* "pol" is a t_INT or an FpX: signe() works for both */ if (!signe(pol)) return pol; P = Fq_mul(pol, fdata->ipi, fdata->top, ppp); /* FpX */ l = lg(P); for (i = 2; i < l; i++) { GEN r; gel(P,i) = dvmdii(gel(P,i), fdata->p, &r); if (r != gen_0) { avma = av; return NULL; } } return FpX_red(P, pp); } /* return pol# = pol~/pi^vpi(pol~) mod pp where pol~(x) = pol(pi.x + beta) * has coefficients in the field defined by top and pi is a prime element */ static GEN GetSharp(FAD_t *fdata, GEN pp, GEN ppp, GEN pol, GEN beta, long *pl) { GEN p1, p2; long i, v, l, d = degpol(pol); pari_sp av = avma; if (!gequal0(beta)) p1 = FqX_translate(pol, beta, fdata->topr, pp); else p1 = shallowcopy(pol); p2 = p1; for (v = 0;; v++) { for (i = 0; i <= v; i++) { GEN c = gel(p2, i+2); c = DivideByPi(fdata, pp, ppp, c); if (!c) break; gel(p2, i+2) = c; } if (i <= v) break; p1 = shallowcopy(p2); } if (!v) pari_err_BUG("GetSharp [no division]"); for (l = v; l >= 0; l--) { GEN c = gel(p1, l+2); c = DivideByPi(fdata, pp, ppp, c); if (!c) { break; } } *pl = l; if (l < 2) return NULL; /* adjust powers */ for (i = v+1; i <= d; i++) gel(p1, i+2) = Fq_mul(gel(p1, i+2), gel(fdata->pik, i-v+1), fdata->topr, pp); return gerepilecopy(av, normalizepol(p1)); } /* Compute roots of pol in the residue field. Use table look-up if possible */ static GEN Quick_FqX_roots(KRASNER_t *data, GEN pol) { GEN rts; ulong ind = 0; if (data->f == 1) pol = FpXY_evalx(pol, gen_0, data->p); else pol = FqX_red(pol, data->T, data->p); if (data->roottable) { ind = ZXY_z_eval(pol, data->q[2], data->p[2]); if (gel(data->roottable, ind)) return gel(data->roottable, ind); } rts = FqX_roots(pol, data->T, data->p); if (ind) gel(data->roottable, ind) = gclone(rts); return rts; } static void FreeRootTable(GEN T) { if (T) { long j, l = lg(T); for (j = 1; j < l; j++) if (gel(T,j)) gunclone(gel(T,j)); } } /* Return the number of roots of pol congruent to alpha modulo pi working modulo pp (all roots if alpha is NULL); if flag is non-zero, return 1 as soon as a root is found. (Note: ppp = pp*p for DivideByPi) */ static long RootCongruents(KRASNER_t *data, FAD_t *fdata, GEN pol, GEN alpha, GEN pp, GEN ppp, long sl, long flag) { GEN R; long s, i; if (alpha) { long l; pol = GetSharp(fdata, pp, ppp, pol, alpha, &l); if (l <= 1) return l; /* decrease precision if sl gets bigger than a multiple of e */ sl += l; if (sl >= data->e) { sl -= data->e; ppp = pp; pp = diviiexact(pp, data->p); } } R = Quick_FqX_roots(data, pol); for (s = 0, i = 1; i < lg(R); i++) { s += RootCongruents(data, fdata, pol, gel(R, i), pp, ppp, sl, flag); if (flag && s) return 1; } return s; } /* pol is a ZXY defining a polynomial over the field defined by fdata If flag != 0, return 1 as soon as a root is found. Computations are done with a precision of pr. */ static long RootCountingAlgorithm(KRASNER_t *data, FAD_t *fdata, GEN pol, long flag) { long j, l, d; GEN P = cgetg_copy(pol, &l); P[1] = pol[1]; d = l-3; for (j = 0; j < d; j++) { GEN cf = gel(pol, j+2); if (typ(cf) == t_INT) cf = diviiexact(cf, data->p); else cf = ZX_Z_divexact(cf, data->p); gel(P, j+2) = Fq_mul(cf, gel(fdata->pik, j+1), fdata->topr, data->pr); } gel(P, d+2) = gel(fdata->pik, d+1); /* pik[d] = pi^d/p */ return RootCongruents(data, fdata, P, NULL, diviiexact(data->pr, data->p), data->pr, 0, flag); } /* Return non-zero if the field given by fdata defines a field isomorphic to * the one defined by pol */ static long IsIsomorphic(KRASNER_t *data, FAD_t *fdata, GEN pol) { long j, nb; pari_sp av = avma; if (RgX_is_ZX(pol)) return RootCountingAlgorithm(data, fdata, pol, 1); for (j = 1; j <= data->f; j++) { GEN p1 = FqX_FpXQ_eval(pol, fdata->z, fdata->top, data->pr); nb = RootCountingAlgorithm(data, fdata, p1, 1); if (nb) { avma = av; return nb; } if (j < data->f) pol = FqX_FpXQ_eval(pol, data->frob, data->T, data->pr); } avma = av; return 0; } /* Compute the number of conjugates fields of the field given by fdata */ static void NbConjugateFields(KRASNER_t *data, FAD_t *fdata) { GEN pol = fdata->eis; long j, nb; pari_sp av = avma; if (RgX_is_ZX(pol)) { /* split for efficiency; contains the case f = 1 */ fdata->cj = data->e / RootCountingAlgorithm(data, fdata, pol, 0); avma = av; return; } nb = 0; for (j = 1; j <= data->f; j++) { /* Transform to pol. in z to pol. in a */ GEN p1 = FqX_FpXQ_eval(pol, fdata->z, fdata->top, data->pr); nb += RootCountingAlgorithm(data, fdata, p1, 0); /* Look at the roots of conjugates polynomials */ if (j < data->f) pol = FqX_FpXQ_eval(pol, data->frob, data->T, data->pr); } avma = av; fdata->cj = data->e * data->f / nb; return; } /* return a minimal list of polynomials generating all the totally ramified extensions of K^ur of degree e and discriminant p^{e + j - 1} in the tamely ramified case */ static GEN TamelyRamifiedCase(KRASNER_t *data) { long av = avma; long g = ugcdui(data->e, data->qm1); /* (e, q-1) */ GEN rep, eis, Xe = gpowgs(pol_x(0), data->e), m = stoi(data->e / g); rep = zerovec(g); eis = gadd(Xe, data->p); gel(rep, 1) = mkvec2(get_topx(data,eis), m); if (g > 1) { ulong pmodg = umodiu(data->p, g); long r = 1, ct = 1; GEN sv = InitSieve(g-1); /* let Frobenius act to get a minimal set of polynomials over Q_p */ while (r) { long gr; GEN p1 = (typ(data->u) == t_INT)? mulii(Fp_powu(data->u, r, data->p), data->p): ZX_Z_mul(FpXQ_powu(data->u, r, data->T, data->p), data->p); eis = gadd(Xe, p1); /* add cst coef */ ct++; gel(rep, ct) = mkvec2(get_topx(data,eis), m); gr = r; do { SetSieveValue(sv, gr); gr = Fl_mul(gr, pmodg, g); } while (gr != r); r = NextZeroValue(sv, r); } setlg(rep, ct+1); } return gerepilecopy(av, rep); } static long function_l(GEN p, long a, long b, long i) { long l = 1 + a - z_pval(i, p); if (i < b) l++; return (l < 1)? 1: l; } /* Structure of the coefficients set Omega. Each coefficient is [start, zr] * meaning all the numbers of the form: * zeta_0 * p^start + ... + zeta_s * p^c (s = c - start) * with zeta_i roots of unity (powers of zq + zero), zeta_0 = 0 is * possible iff zr = 1 */ static GEN StructureOmega(KRASNER_t *data, GEN *pnbpol) { GEN nbpol, O = cgetg(data->e + 1, t_VEC); long i; /* i = 0 */ gel(O, 1) = mkvecsmall2(1, 0); nbpol = mulii(data->qm1, powiu(data->q, data->c - 1)); for (i = 1; i < data->e; i++) { long v_start, zero = 0; GEN nbcf, p1; v_start = function_l(data->p, data->a, data->b, i); p1 = powiu(data->q, data->c - v_start); if (i == data->b) nbcf = mulii(p1, data->qm1); else { nbcf = mulii(p1, data->q); zero = 1; } gel(O, i+1) = mkvecsmall2(v_start, zero); nbpol = mulii(nbpol, nbcf); } *pnbpol = nbpol; return O; } /* a random element of the finite field */ static GEN RandomFF(KRASNER_t *data) { long i, l = data->f + 2, p = itou(data->p); GEN c = cgetg(l, t_POL); c[1] = evalvarn(data->v); for (i = 2; i < l; i++) gel(c, i) = utoi(random_Fl(p)); return ZX_renormalize(c, l); } static GEN RandomPol(KRASNER_t *data, GEN Omega) { long i, j, l = data->e + 3, end = data->c; GEN pol = cgetg(l, t_POL); pol[1] = evalsigne(1) | evalvarn(0); for (i = 1; i <= data->e; i++) { GEN c, cf = gel(Omega, i); long st = cf[1], zr = cf[2]; /* c = sum_{st <= j <= end} x_j p^j, where x_j are random Fq mod (p,upl) * If (!zr), insist on x_st != 0 */ for (;;) { c = RandomFF(data); if (zr || signe(c)) break; } for (j = 1; j <= end-st; j++) c = ZX_add(c, ZX_Z_mul(RandomFF(data), gel(data->pk, j))); c = ZX_Z_mul(c, gel(data->pk, st)); c = FpX_red(c, data->pr); switch(degpol(c)) { case -1: c = gen_0; break; case 0: c = gel(c,2); break; } gel(pol, i+1) = c; } gel(pol, i+1) = gen_1; /* monic */ return pol; } static void CloneFieldData(FAD_t *fdata) { fdata->top = gclone(fdata->top); fdata->topr= gclone(fdata->topr); fdata->z = gclone(fdata->z); fdata->eis = gclone(fdata->eis); fdata->pi = gclone(fdata->pi); fdata->ipi = gclone(fdata->ipi); fdata->pik = gclone(fdata->pik); } static void FreeFieldData(FAD_t *fdata) { gunclone(fdata->top); gunclone(fdata->topr); gunclone(fdata->z); gunclone(fdata->eis); gunclone(fdata->pi); gunclone(fdata->ipi); gunclone(fdata->pik); } static GEN WildlyRamifiedCase(KRASNER_t *data) { long nbext, ct, fd, nb = 0, j; GEN nbpol, rpl, rep, Omega; FAD_t **vfd; pari_timer T; pari_sp av = avma, av2; /* Omega = vector giving the structure of the set Omega */ /* nbpol = number of polynomials to consider = |Omega| */ Omega = StructureOmega(data, &nbpol); nbext = itos_or_0(data->nbext); if (!nbext || (nbext & ~LGBITS)) pari_err_OVERFLOW("padicfields [too many extensions]"); if (DEBUGLEVEL>0) { err_printf("There are %ld extensions to find and %Ps polynomials to consider\n", nbext, nbpol); timer_start(&T); } vfd = (FAD_t**)new_chunk(nbext); for (j = 0; j < nbext; j++) vfd[j] = (FAD_t*)new_chunk(sizeof(FAD_t)); ct = 0; fd = 0; av2 = avma; while (fd < nbext) { /* Jump randomly among the polynomials : seems best... */ rpl = RandomPol(data, Omega); if (DEBUGLEVEL>3) err_printf("considering polynomial %Ps\n", rpl); for (j = 0; j < ct; j++) { nb = IsIsomorphic(data, vfd[j], rpl); if (nb) break; } if (!nb) { GEN topx = get_topx(data, rpl); FAD_t *f = (FAD_t*)vfd[ct]; FieldData(data, f, rpl, topx); CloneFieldData(f); NbConjugateFields(data, f); nb = f->cj; fd += nb; ct++; if (DEBUGLEVEL>1) err_printf("%ld more extension%s\t(%ld/%ld, %ldms)\n", nb, (nb == 1)? "": "s", fd, nbext, timer_delay(&T)); } avma = av2; } rep = cgetg(ct+1, t_VEC); for (j = 0; j < ct; j++) { FAD_t *f = (FAD_t*)vfd[j]; GEN topx = ZX_copy(f->top); setvarn(topx, 0); gel(rep, j+1) = mkvec2(topx, stoi(f->cj)); FreeFieldData(f); } FreeRootTable(data->roottable); return gerepileupto(av, rep); } /* return the minimal polynomial T of a generator of K^ur and the expression (mod pr) * in terms of T of a root of unity u such that u is l-maximal for all primes l * dividing g = (e,q-1). */ static void setUnramData(KRASNER_t *d) { if (d->f == 1) { d->T = pol_x(d->v); d->u = pgener_Fp(d->p); d->frob = pol_x(d->v); } else { GEN L, z, T, p = d->p; d->T = T = init_Fq(p, d->f, d->v); L = gel(factoru(ugcdui(d->e, d->qm1)), 1); z = gener_FpXQ_local(T, p, zv_to_ZV(L)); d->u = ZpXQ_sqrtnlift(pol_1(d->v), d->qm1, z, T, p, d->r); d->frob = ZpX_ZpXQ_liftroot(T, FpXQ_pow(pol_x(d->v), p, T, p), T, p, d->r); } } /* return [ p^1, p^2, ..., p^c ] */ static GEN get_pk(KRASNER_t *data) { long i, l = data->c + 1; GEN pk = cgetg(l, t_VEC), p = data->p; gel(pk, 1) = p; for (i = 2; i <= data->c; i++) gel(pk, i) = mulii(gel(pk, i-1), p); return pk; } /* Compute an absolute polynomial for all the totally ramified extensions of Q_p(z) of degree e and discriminant p^{e + j - 1} where z is a root of upl defining an unramified extension of Q_p */ /* See padicfields for the meaning of flag */ static GEN GetRamifiedPol(GEN p, GEN efj, long flag) { long e = efj[1], f = efj[2], j = efj[3], i, l; const long v = 1; GEN L, pols; KRASNER_t data; pari_sp av = avma; if (DEBUGLEVEL>1) err_printf(" Computing extensions with decomposition [e, f, j] = [%ld, %ld, %ld]\n", e,f,j); data.p = p; data.e = e; data.f = f; data.j = j; data.a = j/e; data.b = j%e; data.c = (e+2*j)/e+1; data.q = powiu(p, f); data.qm1 = subiu(data.q, 1); data.v = v; data.r = 1 + (long)ceildivuu(2*j + 3, e); /* enough precision */ data.pr = powiu(p, data.r); data.nbext = NumberExtensions(&data); if (flag == 2) return data.nbext; setUnramData(&data); if (DEBUGLEVEL>1) err_printf(" Unramified part %Ps\n", data.T); data.roottable = NULL; if (j) { if (lgefint(data.q) == 3) { ulong npol = upowuu(data.q[2], e+1); if (npol && npol < (1<<19)) data.roottable = const_vec(npol, NULL); } data.pk = get_pk(&data); L = WildlyRamifiedCase(&data); } else L = TamelyRamifiedCase(&data); pols = cgetg_copy(L, &l); if (flag == 1) { GEN E = utoipos(e), F = utoipos(f), D = utoi(f*(e+j-1)); for (i = 1; i < l; i++) { GEN T = gel(L,i); gel(pols, i) = mkvec5(ZX_copy(gel(T, 1)), E,F,D, icopy(gel(T, 2))); } } else { for (i = 1; i < l; i++) { GEN T = gel(L,i); gel(pols, i) = ZX_copy(gel(T,1)); } } return gerepileupto(av, pols); } static GEN possible_efj(GEN p, long m) { /* maximal possible discriminant valuation d <= m * (1+v_p(m)) - 1 */ /* 1) [j = 0, tame] d = m - f with f | m and v_p(f) = v_p(m), or * 2) [j > 0, wild] d >= m, j <= v_p(e)*e */ ulong m1, pve, pp = p[2]; /* pp used only if v > 0 */ long ve, v = u_pvalrem(m, p, &m1); GEN L, D = divisorsu(m1); long i, taum1 = lg(D)-1, nb = 0; if (v) { for (pve = 1,ve = 1; ve <= v; ve++) { pve *= pp; nb += pve * ve; } nb = itos_or_0(muluu(nb, zv_sum(D))); if (!nb || is_bigint( mului(pve, sqru(v)) ) ) pari_err_OVERFLOW("padicfields [too many ramification possibilities]"); } nb += taum1; /* upper bound for the number of possible triples [e,f,j] */ L = cgetg(nb + 1, t_VEC); /* 1) tame */ for (nb=1, i=1; i < lg(D); i++) { long e = D[i], f = m / e; gel(L, nb++) = mkvecsmall3(e, f, 0); } /* 2) wild */ /* Ore's condition: either * 1) j = v_p(e) * e, or * 2) j = a e + b, with 0 < b < e and v_p(b) <= a < v_p(e) */ for (pve = 1, ve = 1; ve <= v; ve++) { pve *= pp; /* = p^ve */ for (i = 1; i < lg(D); i++) { long a,b, e = D[i] * pve, f = m / e; for (b = 1; b < e; b++) for (a = u_lval(b, pp); a < ve; a++) gel(L, nb++) = mkvecsmall3(e, f, a*e + b); gel(L, nb++) = mkvecsmall3(e, f, ve*e); } } setlg(L, nb); return L; } #ifdef CHECK static void checkpols(GEN p, GEN EFJ, GEN pols) { GEN pol, p1, p2; long c1, c2, e, f, j, i, l = lg(pols); if (typ(pols) == t_INT) return; e = EFJ[1]; f = EFJ[2]; j = EFJ[3]; for (i = 1; i < l; i++) { pol = gel(pols, i); if (typ(pol) == t_VEC) pol = gel(pol, 1); if (!isirreducible(pol)) pari_err_BUG("Polynomial is reducible"); p1 = poldisc0(pol, -1); if (gvaluation(p1, p) != f*(e+j-1)) pari_err_BUG("Discriminant is incorrect"); /* only compute a p-maximal order */ p1 = nfinitall(mkvec2(pol, mkvec(p)), 0, DEFAULTPREC); p2 = idealprimedec(p1, p); if(lg(p2) > 2) pari_err_BUG("Prime p is split"); p2 = gel(p2, 1); if (cmpis(gel(p2, 3), e)) pari_err_BUG("Ramification index is incorrect"); if (cmpis(gel(p2, 4), f)) pari_err_BUG("inertia degree is incorrect"); } if (l == 2) return; if (e*f > 20) return; /* TODO: check that (random) distinct polynomials give non-isomorphic extensions */ for (i = 1; i < 3*l; i++) { c1 = random_Fl(l-1)+1; c2 = random_Fl(l-1)+1; if (c1 == c2) continue; p1 = gel(pols, c1); if (typ(p1) == t_VEC) p1 = gel(p1, 1); p2 = gel(pols, c2); if (typ(p2) == t_VEC) p2 = gel(p2, 1); pol = polcompositum0(p1, p2, 0); pol = gel(pol, 1); if (poldegree(pol, -1) > 100) continue; p1 = factorpadic(pol, p, 2); p1 = gmael(p1, 1, 1); if (poldegree(p1, -1) == e*f) pari_err_BUG("fields are isomorphic"); /* p1 = nfinitall(mkvec2(pol, mkvec(p)), 0, DEFAULTPREC); p2 = idealprimedec_galois(p1, p); if (!cmpis(mulii(gel(p2, 3), gel(p2, 4)), e*f)) pari_err_BUG("fields are isomorphic"); */ } } #endif static GEN pols_from_efj(pari_sp av, GEN EFJ, GEN p, long flag) { long i, l; GEN L = cgetg_copy(EFJ, &l); if (l == 1) { avma = av; return flag == 2? gen_0: cgetg(1, t_VEC); } for (i = 1; i < l; i++) { gel(L,i) = GetRamifiedPol(p, gel(EFJ,i), flag); #ifdef CHECK checkpols(p, gel(EFJ, i), gel(L, i)); #endif } if (flag == 2) return gerepileuptoint(av, ZV_sum(L)); return gerepilecopy(av, shallowconcat1(L)); } /* return a minimal list of polynomials generating all the extensions of Q_p of given degree N; if N is a t_VEC [n,d], return extensions of degree n and discriminant p^d. */ /* Return only the polynomials if flag = 0 (default), also the ramification degree, the residual degree and the discriminant if flag = 1 and only the number of extensions if flag = 2 */ GEN padicfields0(GEN p, GEN N, long flag) { pari_sp av = avma; long m = 0, d = -1; GEN L; if (typ(p) != t_INT) pari_err_TYPE("padicfields",p); /* be nice to silly users */ if (!BPSW_psp(p)) pari_err_PRIME("padicfields",p); switch(typ(N)) { case t_VEC: if (lg(N) != 3) pari_err_TYPE("padicfields",N); d = gtos(gel(N,2)); N = gel(N,1); /* fall through */ case t_INT: m = itos(N); if (m <= 0) pari_err_DOMAIN("padicfields", "degree", "<=", gen_0,N); break; default: pari_err_TYPE("padicfields",N); } if (d >= 0) return padicfields(p, m, d, flag); L = possible_efj(p, m); return pols_from_efj(av, L, p, flag); } GEN padicfields(GEN p, long m, long d, long flag) { long av = avma; GEN L = possible_efj_by_d(p, m, d); return pols_from_efj(av, L, p, flag); } pari-2.11.2/src/modules/thue.c0000644000175000017500000013711213326135265014541 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /********************************************************************/ /** **/ /** THUE EQUATION SOLVER (G. Hanrot) **/ /** **/ /********************************************************************/ /* In all the forthcoming remarks, "paper" designs the paper "Thue Equations of * High Degree", by Yu. Bilu and G. Hanrot, J. Number Theory (1996). The * numbering of the constants corresponds to Hanrot's thesis rather than to the * paper. See also * "Solving Thue equations without the full unit group", Math. Comp. (2000) */ /* Check whether tnf is a valid structure */ static int checktnf(GEN tnf) { long l = lg(tnf); GEN v; if (typ(tnf)!=t_VEC || (l!=8 && l!=4)) return 0; v = gel(tnf,1); if (typ(v) != t_VEC || lg(v) != 4) return 0; if (l == 4) return 1; /* s=0 */ (void)checkbnf(gel(tnf,2)); return (typ(gel(tnf,3)) == t_COL && typ(gel(tnf,4)) == t_COL && typ(gel(tnf,5)) == t_MAT && typ(gel(tnf,6)) == t_MAT && typ(gel(tnf,7)) == t_VEC); } /* Compensates rounding errors for computation/display of the constants. * Round up if dir > 0, down otherwise */ static GEN myround(GEN x, long dir) { GEN eps = powis(stoi(dir > 0? 10: -10), -10); return gmul(x, gadd(gen_1, eps)); } /* v a t_VEC/t_VEC */ static GEN vecmax_shallow(GEN v) { return gel(v, vecindexmax(v)); } static GEN tnf_get_roots(GEN poly, long prec, long S, long T) { GEN R0 = QX_complex_roots(poly, prec), R = cgetg(lg(R0), t_COL); long k; for (k=1; k<=S; k++) gel(R,k) = gel(R0,k); /* swap roots to get the usual order */ for (k=1; k<=T; k++) { gel(R,k+S) = gel(R0,2*k+S-1); gel(R,k+S+T)= gel(R0,2*k+S); } return R; } /* Computation of the logarithmic height of x (given by embeddings) */ static GEN LogHeight(GEN x, long prec) { pari_sp av = avma; long i, n = lg(x)-1; GEN LH = gen_1; for (i=1; i<=n; i++) { GEN t = gabs(gel(x,i), prec); if (gcmpgs(t,1) > 0) LH = gmul(LH, t); } return gerepileupto(av, gdivgs(glog(LH,prec), n)); } /* |x|^(1/n), x t_INT */ static GEN absisqrtn(GEN x, long n, long prec) { GEN r = itor(x,prec); setabssign(r); return sqrtnr(r, n); } static GEN get_emb(GEN x, GEN r) { long l = lg(r), i; GEN y; if (typ(x) == t_INT) return const_col(l-1, x); y = cgetg(l, t_COL); for (i=1; i1) err_printf("epsilon_3 -> %Ps\n",eps3); *eps5 = mulur(r, eps3); return A; } /* find a few large primes such that p Z_K = P1 P2 P3 Q, whith f(Pi/p) = 1 * From x - \alpha y = \prod u_i^b_i we will deduce 3 equations in F_p * in check_prinfo. Eliminating x,y we get a stringent condition on (b_i). */ static GEN get_prime_info(GEN bnf) { long n = 1, e = gexpo(bnf_get_reg(bnf)), nbp = e < 20? 1: 2; GEN L = cgetg(nbp+1, t_VEC), nf = checknf(bnf), fu = bnf_get_fu(bnf); GEN X = pol_x(nf_get_varn(nf)); ulong p; for(p = 2147483659UL; n <= nbp; p = unextprime(p+1)) { GEN PR, A, U, LP = idealprimedec_limit_f(bnf, utoipos(p), 1); long i; if (lg(LP) < 4) continue; A = cgetg(5, t_VECSMALL); U = cgetg(4, t_VEC); PR = cgetg(4, t_VEC); for (i = 1; i <= 3; i++) { GEN modpr = zkmodprinit(nf, gel(LP,i)); GEN a = nf_to_Fq(nf, X, modpr); GEN u = nfV_to_FqV(fu, nf, modpr); A[i] = itou(a); gel(U,i) = ZV_to_Flv(u,p); gel(PR,i) = modpr; } A[4] = p; gel(L,n++) = mkvec3(A,U,PR); } return L; } /* Performs basic computations concerning the equation. * Returns a "tnf" structure containing * 1) the polynomial * 2) the bnf (used to solve the norm equation) * 3) roots, with presumably enough precision * 4) The logarithmic heights of units * 5) The matrix of conjugates of units * 6) its inverse * 7) a few technical constants */ static GEN inithue(GEN P, GEN bnf, long flag, long prec) { GEN MatFU, x0, tnf, tmp, gpmin, dP, csts, ALH, eps5, ro, c1, c2, Ind = gen_1; long k,j, n = degpol(P); long s,t, prec_roots; if (!bnf) { bnf = Buchall(P, nf_FORCE, maxss(prec, DEFAULTPREC)); if (flag) (void)bnfcertify(bnf); else Ind = floorr(mulru(bnf_get_reg(bnf), 5)); } nf_get_sign(bnf_get_nf(bnf), &s, &t); prec_roots = prec; for(;;) { ro = tnf_get_roots(P, prec_roots, s, t); MatFU = Conj_LH(bnf_get_fu(bnf), &ALH, ro, prec); if (MatFU) break; prec_roots = precdbl(prec_roots); if (DEBUGLEVEL>1) pari_warn(warnprec, "inithue", prec_roots); } dP = ZX_deriv(P); c1 = NULL; /* min |P'(r_i)|, i <= s */ for (k=1; k<=s; k++) { tmp = gabs(poleval(dP,gel(ro,k)),prec); if (!c1 || gcmp(tmp,c1) < 0) c1 = tmp; } c1 = gdiv(int2n(n-1), c1); c1 = gprec_w(myround(c1, 1), DEFAULTPREC); c2 = NULL; /* max |r_i - r_j|, i!=j */ for (k=1; k<=n; k++) for (j=k+1; j<=n; j++) { tmp = gabs(gsub(gel(ro,j),gel(ro,k)), prec); if (!c2 || gcmp(c2,tmp) > 0) c2 = tmp; } c2 = gprec_w(myround(c2, -1), DEFAULTPREC); if (t==0) x0 = real_1(DEFAULTPREC); else { gpmin = NULL; /* min |P'(r_i)|, i > s */ for (k=1; k<=t; k++) { tmp = gabs(poleval(dP,gel(ro,s+k)), prec); if (!gpmin || gcmp(tmp,gpmin) < 0) gpmin = tmp; } gpmin = gprec_w(gpmin, DEFAULTPREC); /* Compute x0. See paper, Prop. 2.2.1 */ x0 = gmul(gpmin, vecmax_shallow(gabs(imag_i(ro), prec))); x0 = sqrtnr(gdiv(int2n(n-1), x0), n); } if (DEBUGLEVEL>1) err_printf("c1 = %Ps\nc2 = %Ps\nIndice <= %Ps\n", c1, c2, Ind); ALH = gmul2n(ALH, 1); tnf = cgetg(8,t_VEC); csts = cgetg(9,t_VEC); gel(tnf,1) = P; gel(tnf,2) = bnf; gel(tnf,3) = ro; gel(tnf,4) = ALH; gel(tnf,5) = MatFU; gel(tnf,6) = T_A_Matrices(MatFU, s+t-1, &eps5, prec); gel(tnf,7) = csts; gel(csts,1) = c1; gel(csts,2) = c2; gel(csts,3) = LogHeight(ro, prec); gel(csts,4) = x0; gel(csts,5) = eps5; gel(csts,6) = utoipos(prec); gel(csts,7) = Ind; gel(csts,8) = get_prime_info(bnf); return tnf; } typedef struct { GEN c10, c11, c13, c15, c91, bak, NE, Ind, hal, MatFU, divro, Hmu; GEN delta, lambda, inverrdelta, ro, Pi, Pi2; long r, iroot, deg; } baker_s; static void other_roots(long iroot, long *i1, long *i2) { switch (iroot) { case 1: *i1=2; *i2=3; break; case 2: *i1=1; *i2=3; break; default: *i1=1; *i2=2; break; } } /* low precision */ static GEN abslog(GEN x) { return gabs(glog(gtofp(x,DEFAULTPREC),0), 0); } /* Compute Baker's bound c9 and B_0, the bound for the b_i's. See Thm 2.3.1 */ static GEN Baker(baker_s *BS) { GEN tmp, B0, hb0, c9, Indc11; long i1, i2; other_roots(BS->iroot, &i1,&i2); /* Compute a bound for the h_0 */ hb0 = gadd(gmul2n(BS->hal,2), gmul2n(gadd(BS->Hmu,mplog2(DEFAULTPREC)), 1)); tmp = gmul(BS->divro, gdiv(gel(BS->NE,i1), gel(BS->NE,i2))); tmp = gmax_shallow(gen_1, abslog(tmp)); hb0 = gmax_shallow(hb0, gdiv(tmp, BS->bak)); c9 = gmul(BS->c91,hb0); c9 = gprec_w(myround(c9, 1), DEFAULTPREC); Indc11 = rtor(mulir(BS->Ind,BS->c11), DEFAULTPREC); /* Compute B0 according to Lemma 2.3.3 */ B0 = mulir(shifti(BS->Ind,1), divrr(addrr(mulrr(c9,mplog(divrr(mulir(BS->Ind, c9),BS->c10))), mplog(Indc11)), BS->c10)); B0 = gmax_shallow(B0, dbltor(2.71828183)); B0 = gmax_shallow(B0, mulrr(divir(BS->Ind, BS->c10), mplog(divrr(Indc11, BS->Pi2)))); if (DEBUGLEVEL>1) { err_printf(" B0 = %Ps\n",B0); err_printf(" Baker = %Ps\n",c9); } return B0; } /* || x d ||, x t_REAL, d t_INT */ static GEN errnum(GEN x, GEN d) { GEN dx = mulir(d, x), D = subri(dx, roundr(dx)); setabssign(D); return D; } /* Try to reduce the bound through continued fractions; see paper. */ static int CF_1stPass(GEN *B0, GEN kappa, baker_s *BS) { GEN a, b, q, ql, qd, l0, denbound = mulri(*B0, kappa); if (cmprr(mulrr(dbltor(0.1),sqrr(denbound)), BS->inverrdelta) > 0) return -1; q = denom_i( bestappr(BS->delta, denbound) ); qd = errnum(BS->delta, q); ql = errnum(BS->lambda,q); l0 = subrr(ql, addrr(mulrr(qd, *B0), divri(dbltor(0.1),kappa))); if (signe(l0) <= 0) return 0; if (BS->r > 1) { a = BS->c15; b = BS->c13; } else { a = BS->c11; b = BS->c10; l0 = mulrr(l0, Pi2n(1, DEFAULTPREC)); } *B0 = divrr(mplog(divrr(mulir(q,a), l0)), b); if (DEBUGLEVEL>1) err_printf(" B0 -> %Ps\n",*B0); return 1; } static void get_B0Bx(baker_s *BS, GEN l0, GEN *B0, GEN *Bx) { GEN t = divrr(mulir(BS->Ind, BS->c15), l0); *B0 = divrr(mulir(BS->Ind, mplog(t)), BS->c13); *Bx = sqrtnr(shiftr(t,1), BS->deg); } static int LLL_1stPass(GEN *pB0, GEN kappa, baker_s *BS, GEN *pBx) { GEN B0 = *pB0, Bx = *pBx, lllmat, C, l0, l1, triv; long e; C = grndtoi(mulir(mulii(BS->Ind, kappa), gpow(B0, dbltor(2.2), DEFAULTPREC)), &e); if (DEBUGLEVEL > 1) err_printf("C (bitsize) : %d\n", expi(C)); lllmat = matid(3); if (cmpri(B0, BS->Ind) > 0) { gcoeff(lllmat, 1, 1) = grndtoi(divri(B0, BS->Ind), &e); triv = shiftr(sqrr(B0), 1); } else triv = addir(sqri(BS->Ind), sqrr(B0)); gcoeff(lllmat, 3, 1) = grndtoi(negr(mulir(C, BS->lambda)), &e); if (e >= 0) return -1; gcoeff(lllmat, 3, 2) = grndtoi(negr(mulir(C, BS->delta)), &e); if (e >= 0) return -1; gcoeff(lllmat, 3, 3) = C; lllmat = ZM_lll(lllmat, 0.99, LLL_IM|LLL_INPLACE); l0 = gnorml2(gel(lllmat,1)); l0 = subrr(divir(l0, dbltor(1.8262)), triv); /* delta = 0.99 */ if (signe(l0) <= 0) return 0; l1 = shiftr(addri(shiftr(B0,1), BS->Ind), -1); l0 = divri(subrr(sqrtr(l0), l1), C); if (signe(l0) <= 0) return 0; get_B0Bx(BS, l0, &B0, &Bx); if (DEBUGLEVEL>=2) { err_printf("LLL_First_Pass successful\n"); err_printf("B0 -> %Ps\n", B0); err_printf("x <= %Ps\n", Bx); } *pB0 = B0; *pBx = Bx; return 1; } /* add solution (x,y) if not already known */ static void add_sol(GEN *pS, GEN x, GEN y) { *pS = shallowconcat(*pS, mkvec(mkvec2(x,y))); } /* z = P(p,q), d = deg P, |z| = |rhs|. Check signs and (possibly) * add solutions (p,q), (-p,-q) */ static void add_pm(GEN *pS, GEN p, GEN q, GEN z, long d, GEN rhs) { if (signe(z) == signe(rhs)) { add_sol(pS, p, q); if (!odd(d)) add_sol(pS, negi(p), negi(q)); } else if (odd(d)) add_sol(pS, negi(p), negi(q)); } /* Check whether a potential solution is a true solution. Return 0 if * truncation error (increase precision) */ static int CheckSol(GEN *pS, GEN z1, GEN z2, GEN P, GEN rhs, GEN ro) { GEN x, y, ro1 = gel(ro,1), ro2 = gel(ro,2); long e; y = grndtoi(real_i(gdiv(gsub(z2,z1), gsub(ro1,ro2))), &e); if (e > 0) return 0; if (!signe(y)) return 1; /* y = 0 taken care of in SmallSols */ x = gadd(z1, gmul(ro1, y)); x = grndtoi(real_i(x), &e); if (e > 0) return 0; if (e <= -13) { /* y != 0 and rhs != 0; check whether P(x,y) = rhs or P(-x,-y) = rhs */ GEN z = poleval(ZX_rescale(P,y),x); if (absequalii(z, rhs)) add_pm(pS, x,y, z, degpol(P), rhs); } return 1; } static const long EXPO1 = 7; static int round_to_b(GEN v, long B, long b, GEN Delta2, long i1, GEN L) { long i, l = lg(v); if (!b) { for (i = 1; i < l; i++) { long c; if (i == i1) c = 0; else { GEN d = gneg(gel(L,i)); long e; d = grndtoi(d,&e); if (e > -EXPO1 || is_bigint(d)) return 0; c = itos(d); if (labs(c) > B) return 0; } v[i] = c; } } else { for (i = 1; i < l; i++) { long c; if (i == i1) c = b; else { GEN d = gsub(gmulgs(gel(Delta2,i), b), gel(L,i)); long e; d = grndtoi(d,&e); if (e > -EXPO1 || is_bigint(d)) return 0; c = itos(d); if (labs(c) > B) return 0; } v[i] = c; } } return 1; } /* mu \prod U[i]^b[i] */ static ulong Fl_factorback(ulong mu, GEN U, GEN b, ulong p) { long i, l = lg(U); ulong r = mu; for (i = 1; i < l; i++) { long c = b[i]; ulong u = U[i]; if (!c) continue; if (c < 0) { u = Fl_inv(u,p); c = -c; } r = Fl_mul(r, Fl_powu(u,c,p), p); } return r; } /* x - alpha y = \pm mu \prod \mu_i^{b_i}. Reduce mod 3 distinct primes of * degree 1 above the same p, and eliminate x,y => drastic conditions on b_i */ static int check_pr(GEN bi, GEN Lmu, GEN L) { GEN A = gel(L,1), U = gel(L,2); ulong a = A[1], b = A[2], c = A[3], p = A[4]; ulong r = Fl_mul(Fl_sub(c,b,p), Fl_factorback(Lmu[1],gel(U,1),bi, p), p); ulong s = Fl_mul(Fl_sub(a,c,p), Fl_factorback(Lmu[2],gel(U,2),bi, p), p); ulong t = Fl_mul(Fl_sub(b,a,p), Fl_factorback(Lmu[3],gel(U,3),bi, p), p); return Fl_add(Fl_add(r,s,p),t,p) == 0; } static int check_prinfo(GEN b, GEN Lmu, GEN prinfo) { long i; for (i = 1; i < lg(prinfo); i++) if (!check_pr(b, gel(Lmu,i), gel(prinfo,i))) return 0; return 1; } /* For each possible value of b_i1, compute the b_i's * and 2 conjugates of z = x - alpha y. Then check. */ static int TrySol(GEN *pS, GEN B0, long i1, GEN Delta2, GEN Lambda, GEN ro, GEN Lmu, GEN NE, GEN MatFU, GEN prinfo, GEN P, GEN rhs) { long bi1, i, B = itos(gceil(B0)), l = lg(Delta2); GEN b = cgetg(l,t_VECSMALL), L = cgetg(l,t_VEC); for (i = 1; i < l; i++) { if (i == i1) gel(L,i) = gen_0; else { GEN delta = gel(Delta2,i); gel(L, i) = gsub(gmul(delta,gel(Lambda,i1)), gel(Lambda,i)); } } for (bi1 = -B; bi1 <= B; bi1++) { GEN z1, z2; if (!round_to_b(b, B, bi1, Delta2, i1, L)) continue; if (!check_prinfo(b, Lmu, prinfo)) continue; z1 = gel(NE,1); z2 = gel(NE,2); for (i = 1; i < l; i++) { z1 = gmul(z1, gpowgs(gcoeff(MatFU,1,i), b[i])); z2 = gmul(z2, gpowgs(gcoeff(MatFU,2,i), b[i])); } if (!CheckSol(pS, z1,z2,P,rhs,ro)) return 0; } return 1; } /* find q1,q2,q3 st q1 b + q2 c + q3 ~ 0 */ static GEN GuessQi(GEN b, GEN c, GEN *eps) { const long shift = 65; GEN Q, Lat; Lat = matid(3); gcoeff(Lat,3,1) = ground(gmul2n(b, shift)); gcoeff(Lat,3,2) = ground(gmul2n(c, shift)); gcoeff(Lat,3,3) = int2n(shift); Q = gel(lllint(Lat),1); if (gequal0(gel(Q,2))) return NULL; /* FAIL */ *eps = mpadd(mpadd(gel(Q,3), mpmul(gel(Q,1),b)), mpmul(gel(Q,2),c)); *eps = mpabs_shallow(*eps); return Q; } /* x a t_REAL */ static GEN myfloor(GEN x) { return expo(x) > 30 ? ceil_safe(x): floorr(x); } /* Check for not-so-small solutions. Return a t_REAL or NULL */ static GEN MiddleSols(GEN *pS, GEN bound, GEN roo, GEN P, GEN rhs, long s, GEN c1) { long j, k, nmax, d; GEN bndcf; if (expo(bound) < 0) return bound; d = degpol(P); bndcf = sqrtnr(shiftr(c1,1), d - 2); if (cmprr(bound, bndcf) < 0) return bound; /* divide by log2((1+sqrt(5))/2) * 1 + ==> ceil * 2 + ==> continued fraction is normalized if last entry is 1 * 3 + ==> start at a0, not a1 */ nmax = 3 + (long)(dbllog2(bound) * 1.44042009041256); bound = myfloor(bound); for (k = 1; k <= s; k++) { GEN ro = real_i(gel(roo,k)), t = gboundcf(ro, nmax); GEN pm1, qm1, p0, q0; pm1 = gen_0; p0 = gen_1; qm1 = gen_1; q0 = gen_0; for (j = 1; j < lg(t); j++) { GEN p, q, z, Q, R; pari_sp av; p = addii(mulii(p0, gel(t,j)), pm1); pm1 = p0; p0 = p; q = addii(mulii(q0, gel(t,j)), qm1); qm1 = q0; q0 = q; if (cmpii(q, bound) > 0) break; if (DEBUGLEVEL >= 2) err_printf("Checking (+/- %Ps, +/- %Ps)\n",p, q); av = avma; z = poleval(ZX_rescale(P,q), p); /* = P(p/q) q^dep(P) */ Q = dvmdii(rhs, z, &R); if (R != gen_0) { avma = av; continue; } setabssign(Q); if (Z_ispowerall(Q, d, &Q)) { if (!is_pm1(Q)) { p = mulii(p, Q); q = mulii(q, Q); } add_pm(pS, p, q, z, d, rhs); } } if (j == lg(t)) { long prec; if (j > nmax) pari_err_BUG("thue [short continued fraction]"); /* the theoretical value is bit_prec = gexpo(ro)+1+log2(bound) */ prec = precdbl(precision(ro)); if (DEBUGLEVEL>1) pari_warn(warnprec,"thue",prec); roo = realroots(P, NULL, prec); if (lg(roo)-1 != s) pari_err_BUG("thue [realroots]"); k--; } } return bndcf; } static void check_y_root(GEN *pS, GEN P, GEN Y) { GEN r = nfrootsQ(P); long j; for (j = 1; j < lg(r); j++) if (typ(gel(r,j)) == t_INT) add_sol(pS, gel(r,j), Y); } static void check_y(GEN *pS, GEN P, GEN poly, GEN Y, GEN rhs) { long j, l = lg(poly); GEN Yn = Y; gel(P, l-1) = gel(poly, l-1); for (j = l-2; j >= 2; j--) { gel(P,j) = mulii(Yn, gel(poly,j)); if (j > 2) Yn = mulii(Yn, Y); } gel(P,2) = subii(gel(P,2), rhs); /* P = poly(Y/y)*y^deg(poly) - rhs */ check_y_root(pS, P, Y); } /* Check for solutions under a small bound (see paper) */ static GEN SmallSols(GEN S, GEN x3, GEN poly, GEN rhs) { pari_sp av = avma; GEN X, P, rhs2; long j, l = lg(poly), n = degpol(poly); ulong y, By; x3 = myfloor(x3); if (DEBUGLEVEL>1) err_printf("* Checking for small solutions <= %Ps\n", x3); if (lgefint(x3) > 3) pari_err_OVERFLOW(stack_sprintf("thue (SmallSols): y <= %Ps", x3)); By = itou(x3); /* y = 0 first: solve X^n = rhs */ if (odd(n)) { if (Z_ispowerall(absi_shallow(rhs), n, &X)) add_sol(&S, signe(rhs) > 0? X: negi(X), gen_0); } else if (signe(rhs) > 0 && Z_ispowerall(rhs, n, &X)) { add_sol(&S, X, gen_0); add_sol(&S, negi(X), gen_0); } rhs2 = shifti(rhs,1); /* y != 0 */ P = cgetg(l, t_POL); P[1] = poly[1]; for (y = 1; y <= By; y++) { pari_sp av2 = avma; long lS = lg(S); GEN Y = utoipos(y); /* try y */ check_y(&S, P, poly, Y, rhs); /* try -y */ for (j = l-2; j >= 2; j -= 2) togglesign( gel(P,j) ); if (j == 0) gel(P,2) = subii(gel(P,2), rhs2); check_y_root(&S, P, utoineg(y)); if (lS == lg(S)) { avma = av2; continue; } /* no solution found */ if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"SmallSols"); gerepileall(av, 2, &S, &rhs2); P = cgetg(l, t_POL); P[1] = poly[1]; } } return S; } /* Computes [x]! */ static double fact(double x) { double ft = 1.0; x = floor(x); while (x>1) { ft *= x; x--; } return ft ; } static GEN RgX_homogenize(GEN P, long v) { GEN Q = leafcopy(P); long i, l = lg(P), d = degpol(P); for (i = 2; i < l; i++) gel(Q,i) = monomial(gel(Q,i), d--, v); return Q; } /* Compute all relevant constants needed to solve the equation P(x,y)=a given * the solutions of N_{K/Q}(x)=a (see inithue). */ GEN thueinit(GEN pol, long flag, long prec) { GEN POL, C, L, fa, tnf, bnf = NULL; pari_sp av = avma; long s, lfa, dpol; if (checktnf(pol)) { bnf = checkbnf(gel(pol,2)); pol = gel(pol,1); } if (typ(pol)!=t_POL) pari_err_TYPE("thueinit",pol); dpol = degpol(pol); if (dpol <= 0) pari_err_CONSTPOL("thueinit"); RgX_check_ZX(pol, "thueinit"); if (varn(pol)) { pol = leafcopy(pol); setvarn(pol, 0); } POL = Q_primitive_part(pol, &C); L = gen_1; fa = ZX_factor(POL); lfa = lgcols(fa); if (lfa > 2 || itos(gcoeff(fa,1,2)) > 1) { /* reducible polynomial, no need to reduce to the monic case */ GEN P, Q, R, g, f = gcoeff(fa,1,1), E = gcoeff(fa,1,2); long e = itos(E); long vy = fetch_var(); long va = fetch_var(); long vb = fetch_var(); C = C? ginv(C): gen_1; if (e != 1) { if (lfa == 2) { tnf = mkvec3(mkvec3(POL,C,L), thueinit(f, flag, prec), E); delete_var(); delete_var(); delete_var(); return gerepilecopy(av, tnf); } P = gpowgs(f,e); } else P = f; g = RgX_div(POL, P); P = RgX_Rg_sub(RgX_homogenize(f, vy), pol_x(va)); Q = RgX_Rg_sub(RgX_homogenize(g, vy), pol_x(vb)); R = polresultant0(P, Q, -1, 0); tnf = mkvec3(mkvec3(POL,C,L), mkvecsmall4(degpol(f), e, va,vb), R); delete_var(); delete_var(); delete_var(); return gerepilecopy(av, tnf); } /* POL monic: POL(x) = C pol(x/L), L integer */ POL = ZX_primitive_to_monic(POL, &L); C = gdiv(powiu(L, dpol), gel(pol, dpol+2)); pol = POL; s = ZX_sturm(pol); if (s) { long PREC, n = degpol(pol); double d, dr, dn = (double)n; if (dpol <= 2) pari_err_DOMAIN("thueinit", "P","=",pol,pol); dr = (double)((s+n-2)>>1); /* s+t-1 */ d = dn*(dn-1)*(dn-2); /* Guess precision by approximating Baker's bound. The guess is most of * the time not sharp, ie 10 to 30 decimal digits above what is _really_ * necessary. Note that the limiting step is the reduction. See paper. */ PREC = nbits2prec((long)((5.83 + (dr+4)*5 + log(fact(dr+3)) + (dr+3)*log(dr+2) + (dr+3)*log(d) + log(log(2*d*(dr+2))) + (dr+1)) /10.)*32+32); if (flag == 0) PREC = (long)(2.2 * PREC); /* Lazy, to be improved */ if (PREC < prec) PREC = prec; if (DEBUGLEVEL >=2) err_printf("prec = %d\n", PREC); for (;;) { if (( tnf = inithue(pol, bnf, flag, PREC) )) break; PREC = precdbl(PREC); if (DEBUGLEVEL>1) pari_warn(warnprec,"thueinit",PREC); bnf = NULL; avma = av; } } else { GEN ro, c0; long k,l; if (!bnf) { bnf = gen_0; if (expi(ZX_disc(pol)) <= 50) { bnf = Buchall(pol, nf_FORCE, DEFAULTPREC); if (flag) (void)bnfcertify(bnf); } } ro = typ(bnf)==t_VEC? nf_get_roots(bnf_get_nf(bnf)) : QX_complex_roots(pol, DEFAULTPREC); l = lg(ro); c0 = imag_i(gel(ro,1)); for (k = 2; k < l; k++) c0 = mulrr(c0, imag_i(gel(ro,k))); setsigne(c0,1); c0 = invr(c0); tnf = mkvec3(pol, bnf, c0); } gel(tnf,1) = mkvec3(gel(tnf,1), C, L); return gerepilecopy(av,tnf); } /* arg(t^2) / 2Pi; arg(t^2) = arg(t/conj(t)) */ static GEN argsqr(GEN t, GEN Pi) { GEN v, u = divrr(garg(t,0), Pi); /* in -1 < u <= 1 */ /* reduce mod Z to -1/2 < u <= 1/2 */ if (signe(u) > 0) { v = subrs(u,1); /* ]-1,0] */ if (abscmprr(v,u) < 0) u = v; } else { v = addrs(u,1);/* ]0,1] */ if (abscmprr(v,u) <= 0) u = v; } return u; } /* i1 != i2 */ static void init_get_B(long i1, long i2, GEN Delta2, GEN Lambda, GEN Deps5, baker_s *BS, long prec) { GEN delta, lambda; if (BS->r > 1) { delta = gel(Delta2,i2); lambda = gsub(gmul(delta,gel(Lambda,i1)), gel(Lambda,i2)); if (Deps5) BS->inverrdelta = divrr(Deps5, addsr(1,delta)); } else { /* r == 1: i1 = s = t = 1; i2 = 2 */ GEN fu = gel(BS->MatFU,1), ro = BS->ro, t; t = gel(fu,2); delta = argsqr(t, BS->Pi); if (Deps5) BS->inverrdelta = shiftr(gabs(t,prec), prec2nbits(prec)-1); t = gmul(gsub(gel(ro,1), gel(ro,2)), gel(BS->NE,3)); lambda = argsqr(t, BS->Pi); } BS->delta = delta; BS->lambda = lambda; } static GEN get_B0(long i1, GEN Delta2, GEN Lambda, GEN Deps5, long prec, baker_s *BS) { GEN B0 = Baker(BS); long step = 0, i2 = (i1 == 1)? 2: 1; for(;;) /* i2 from 1 to r unless r = 1 [then i2 = 2] */ { init_get_B(i1,i2, Delta2,Lambda,Deps5, BS, prec); /* Reduce B0 as long as we make progress: newB0 < oldB0 - 0.1 */ for (;;) { GEN oldB0 = B0, kappa = utoipos(10); long cf; for (cf = 0; cf < 10; cf++, kappa = muliu(kappa,10)) { int res = CF_1stPass(&B0, kappa, BS); if (res < 0) return NULL; /* prec problem */ if (res) break; if (DEBUGLEVEL>1) err_printf("CF failed. Increasing kappa\n"); } if (!step && cf == 10) { /* Semirational or totally rational case */ GEN Q, ep, q, l0, denbound; if (! (Q = GuessQi(BS->delta, BS->lambda, &ep)) ) break; denbound = mpadd(B0, absi_shallow(gel(Q,1))); q = denom_i( bestappr(BS->delta, denbound) ); l0 = subrr(errnum(BS->delta, q), ep); if (signe(l0) <= 0) break; B0 = divrr(mplog(divrr(mulir(gel(Q,2), BS->c15), l0)), BS->c13); if (DEBUGLEVEL>1) err_printf("Semirat. reduction: B0 -> %Ps\n",B0); } /* if no progress, stop */ if (gcmp(oldB0, gadd(B0,dbltor(0.1))) <= 0) return gmin_shallow(oldB0, B0); else step++; } i2++; if (i2 == i1) i2++; if (i2 > BS->r) break; } pari_err_BUG("thue (totally rational case)"); return NULL; /* LCOV_EXCL_LINE */ } static GEN get_Bx_LLL(long i1, GEN Delta2, GEN Lambda, long prec, baker_s *BS) { GEN B0 = Baker(BS), Bx = NULL; long step = 0, i2 = (i1 == 1)? 2: 1; for(;;) /* i2 from 1 to r unless r = 1 [then i2 = 2] */ { init_get_B(i1,i2, Delta2,Lambda,NULL, BS, prec); if (DEBUGLEVEL>1) err_printf(" Entering LLL...\n"); /* Reduce B0 as long as we make progress: newB0 < oldB0 - 0.1 */ for (;;) { GEN oldBx = Bx, kappa = utoipos(10); const long cfMAX = 10; long cf; for (cf = 0; cf < cfMAX; cf++, kappa = muliu(kappa,10)) { int res = LLL_1stPass(&B0, kappa, BS, &Bx); if (res < 0) return NULL; if (res) break; if (DEBUGLEVEL>1) err_printf("LLL failed. Increasing kappa\n"); } /* FIXME: TO BE COMPLETED */ if (!step && cf == cfMAX) { /* Semirational or totally rational case */ GEN Q, Q1, Q2, ep, q, l0, denbound; if (! (Q = GuessQi(BS->delta, BS->lambda, &ep)) ) break; /* Q[2] != 0 */ Q1 = absi_shallow(gel(Q,1)); Q2 = absi_shallow(gel(Q,2)); denbound = gadd(mulri(B0, Q1), mulii(BS->Ind, Q2)); q = denom_i( bestappr(BS->delta, denbound) ); l0 = divri(subrr(errnum(BS->delta, q), ep), Q2); if (signe(l0) <= 0) break; get_B0Bx(BS, l0, &B0, &Bx); if (DEBUGLEVEL>1) err_printf("Semirat. reduction: B0 -> %Ps x <= %Ps\n",B0, Bx); } /* if no progress, stop */ if (oldBx && gcmp(oldBx, Bx) <= 0) return oldBx; else step++; } i2++; if (i2 == i1) i2++; if (i2 > BS->r) break; } pari_err_BUG("thue (totally rational case)"); return NULL; /* LCOV_EXCL_LINE */ } static GEN LargeSols(GEN P, GEN tnf, GEN rhs, GEN ne) { GEN S = NULL, Delta0, ro, ALH, bnf, nf, MatFU, A, csts, dP, Bx; GEN c1,c2,c3,c4,c90,c91,c14, x0, x1, x2, x3, tmp, eps5, prinfo; long iroot, ine, n, r, Prec, prec, s,t; baker_s BS; pari_sp av = avma; prec = 0; /*-Wall*/ bnf = NULL; /*-Wall*/ iroot = 1; ine = 1; START: if (S) /* restart from precision problems */ { S = gerepilecopy(av, S); prec = precdbl(prec); if (DEBUGLEVEL) pari_warn(warnprec,"thue",prec); tnf = inithue(P, bnf, 0, prec); } else S = cgetg(1, t_VEC); bnf= gel(tnf,2); nf = bnf_get_nf(bnf); csts = gel(tnf,7); nf_get_sign(nf, &s, &t); BS.r = r = s+t-1; n = degpol(P); ro = gel(tnf,3); ALH = gel(tnf,4); MatFU = gel(tnf,5); A = gel(tnf,6); c1 = mpmul(absi_shallow(rhs), gel(csts,1)); c2 = gel(csts,2); BS.hal = gel(csts,3); x0 = gel(csts,4); eps5 = gel(csts,5); Prec = itos(gel(csts,6)); BS.Ind = gel(csts,7); BS.MatFU = MatFU; BS.bak = muluu(n, (n-1)*(n-2)); /* safe */ BS.deg = n; prinfo = gel(csts,8); if (t) x0 = gmul(x0, absisqrtn(rhs, n, Prec)); tmp = divrr(c1,c2); c3 = mulrr(dbltor(1.39), tmp); c4 = mulur(n-1, c3); c14 = mulrr(c4, vecmax_shallow(RgM_sumcol(gabs(A,DEFAULTPREC)))); x1 = gmax_shallow(x0, sqrtnr(shiftr(tmp,1),n)); x2 = gmax_shallow(x1, sqrtnr(mulur(10,c14), n)); x3 = gmax_shallow(x2, sqrtnr(shiftr(c14, EXPO1+1),n)); c90 = gmul(shiftr(mulur(18,mppi(DEFAULTPREC)), 5*(4+r)), gmul(gmul(mpfact(r+3), powiu(muliu(BS.bak,r+2), r+3)), glog(muliu(BS.bak,2*(r+2)),DEFAULTPREC))); dP = ZX_deriv(P); Delta0 = RgM_sumcol(A); for (; iroot<=s; iroot++) { GEN Delta = Delta0, Delta2, D, Deps5, MatNE, Hmu, diffRo, c5, c7, ro0; long i1, iroot1, iroot2, k; if (iroot <= r) Delta = RgC_add(Delta, RgC_Rg_mul(gel(A,iroot), stoi(-n))); D = gabs(Delta,Prec); i1 = vecindexmax(D); c5 = gel(D, i1); Delta2 = RgC_Rg_div(Delta, gel(Delta, i1)); c5 = myround(gprec_w(c5,DEFAULTPREC), 1); Deps5 = divrr(subrr(c5,eps5), eps5); c7 = mulur(r,c5); BS.c10 = divur(n,c7); BS.c13 = divur(n,c5); if (DEBUGLEVEL>1) { err_printf("* real root no %ld/%ld\n", iroot,s); err_printf(" c10 = %Ps\n",BS.c10); err_printf(" c13 = %Ps\n",BS.c13); } prec = Prec; for (;;) { if (( MatNE = Conj_LH(ne, &Hmu, ro, prec) )) break; prec = precdbl(prec); if (DEBUGLEVEL>1) pari_warn(warnprec,"thue",prec); ro = tnf_get_roots(P, prec, s, t); } ro0 = gel(ro,iroot); BS.ro = ro; BS.iroot = iroot; BS.Pi = mppi(prec); BS.Pi2 = Pi2n(1,prec); diffRo = cgetg(r+1, t_VEC); for (k=1; k<=r; k++) { GEN z = gel(ro,k); z = (k == iroot)? gdiv(rhs, poleval(dP, z)): gsub(ro0, z); gel(diffRo,k) = gabs(z, prec); } other_roots(iroot, &iroot1,&iroot2); BS.divro = gdiv(gsub(ro0, gel(ro,iroot2)), gsub(ro0, gel(ro,iroot1))); /* Compute h_1....h_r */ c91 = c90; for (k=1; k<=r; k++) { GEN z = gdiv(gcoeff(MatFU,iroot1,k), gcoeff(MatFU,iroot2,k)); z = gmax_shallow(gen_1, abslog(z)); c91 = gmul(c91, gmax_shallow(gel(ALH,k), gdiv(z, BS.bak))); } BS.c91 = c91; for (; ine1) err_printf(" - norm sol. no %ld/%ld\n",ine,lg(ne)-1); for (k=1; k<=r; k++) { GEN z = gdiv(gel(diffRo,k), gabs(gel(NE,k), prec)); gel(v,k) = glog(z, prec); } Lambda = RgM_RgC_mul(A,v); c6 = addrr(dbltor(0.1), vecmax_shallow(gabs(Lambda,DEFAULTPREC))); c6 = myround(c6, 1); c8 = addrr(dbltor(1.23), mulur(r,c6)); BS.c11= mulrr(shiftr(c3,1) , mpexp(divrr(mulur(n,c8),c7))); BS.c15= mulrr(shiftr(c14,1), mpexp(divrr(mulur(n,c6),c5))); BS.NE = NE; BS.Hmu = gel(Hmu,ine); if (is_pm1(BS.Ind)) { GEN mu = gel(ne,ine), Lmu = cgetg(lg(prinfo),t_VEC); long i, j; for (i = 1; i < lg(prinfo); i++) { GEN v = gel(prinfo,i), PR = gel(v,3), L = cgetg(4, t_VECSMALL); for (j = 1; j <= 3; j++) L[j] = itou(nf_to_Fq(nf, mu, gel(PR,j))); gel(Lmu, i) = L; } if (! (B0 = get_B0(i1, Delta2, Lambda, Deps5, prec, &BS)) || !TrySol(&S, B0, i1, Delta2, Lambda, ro, Lmu, NE,MatFU,prinfo, P,rhs)) goto START; if (lg(S) == lS) avma = av2; } else { if (! (Bx = get_Bx_LLL(i1, Delta2, Lambda, prec, &BS)) ) goto START; x3 = gerepileupto(av2, gmax_shallow(Bx, x3)); } } ine = 1; } x3 = gmax_shallow(x0, MiddleSols(&S, x3, ro, P, rhs, s, c1)); return SmallSols(S, x3, P, rhs); } /* restrict to solutions (x,y) with L | x, replacing each by (x/L, y) */ static GEN filter_sol_x(GEN S, GEN L) { long i, k, l; if (is_pm1(L)) return S; l = lg(S); k = 1; for (i = 1; i < l; i++) { GEN s = gel(S,i), r; gel(s,1) = dvmdii(gel(s,1), L, &r); if (r == gen_0) gel(S, k++) = s; } setlg(S, k); return S; } static GEN filter_sol_Z(GEN S) { long i, k = 1, l = lg(S); for (i = 1; i < l; i++) { GEN s = gel(S,i); if (RgV_is_ZV(s)) gel(S, k++) = s; } setlg(S, k); return S; } static GEN bnfisintnorm_i(GEN bnf, GEN a, long s, GEN z); static GEN tnf_get_Ind(GEN tnf) { return gmael(tnf,7,7); } static GEN tnf_get_bnf(GEN tnf) { return gel(tnf,2); } static void maybe_warn(GEN bnf, GEN a, GEN Ind) { if (!is_pm1(Ind) && !is_pm1(bnf_get_no(bnf)) && !is_pm1(a)) pari_warn(warner, "The result returned by 'thue' is conditional on the GRH"); } /* return solutions of Norm(x) = a mod U(K)^+ */ static GEN get_ne(GEN bnf, GEN a, GEN Ind) { if (DEBUGLEVEL) maybe_warn(bnf,a,Ind); return bnfisintnorm(bnf, a); } /* return solutions of |Norm(x)| = |a| mod U(K) */ static GEN get_neabs(GEN bnf, GEN a, GEN Ind) { if (DEBUGLEVEL) maybe_warn(bnf,a,Ind); return bnfisintnormabs(bnf, a); } /* Let P(z)=z^2+Bz+C, convert t=u+v*z (mod P) solution of norm equation N(t)=A * to [x,y] = [u,-v] form: y^2P(x/y) = A */ static GEN ne2_to_xy(GEN t) { GEN u,v; if (typ(t) != t_POL) { u = t; v = gen_0; } else switch(degpol(t)) { case -1: u = v = gen_0; break; case 0: u = gel(t,2); v = gen_0; break; default: u = gel(t,2); v = gneg(gel(t,3)); } return mkvec2(u, v); } static GEN ne2V_to_xyV(GEN v) { long i, l; GEN w = cgetg_copy(v,&l); for (i=1; i POL(L x, y) = C rhs, with POL monic in Z[X] */ POL = gel(tnf,1); C = gel(POL,2); rhs = gmul(C, rhs); if (typ(rhs) != t_INT) { avma = av; return cgetg(1, t_VEC); } if (!signe(rhs)) { GEN v = gel(tnf,2); avma = av; /* at least 2 irreducible factors, one of which has degree 1 */ if (typ(v) == t_VECSMALL && v[1] ==1) pari_err_DOMAIN("thue","#sols","=",strtoGENstr("oo"),rhs); return sol_0(); } L = gel(POL,3); POL = gel(POL,1); if (lg(tnf) == 8) { if (!ne) ne = get_ne(tnf_get_bnf(tnf), rhs, tnf_get_Ind(tnf)); if (lg(ne) == 1) { avma = av; return cgetg(1, t_VEC); } S = LargeSols(POL, tnf, rhs, ne); } else if (typ(gel(tnf,3)) == t_REAL) { /* Case s=0. All solutions are "small". */ GEN bnf = tnf_get_bnf(tnf); GEN c0 = gel(tnf,3), F; x3 = sqrtnr(mulir(absi_shallow(rhs),c0), degpol(POL)); x3 = addrr(x3, dbltor(0.1)); /* guard from round-off errors */ S = cgetg(1,t_VEC); if (!ne && typ(bnf) == t_VEC && expo(x3) > 10) { F = Z_factor_if_easy(rhs); if (F) ne = get_ne(bnf, F, gen_1); } if (ne) { if (lg(ne) == 1) { avma = av; return cgetg(1,t_VEC); } if (degpol(POL) == 2) /* quadratic imaginary */ { GEN u = NULL; long w = 2; if (typ(bnf) == t_VEC) { u = bnf_get_tuU(bnf); w = bnf_get_tuN(bnf); } else { GEN D = coredisc(ZX_disc(POL)); if (cmpis(D, -4) >= 0) { GEN F, T = quadpoly(D); w = equalis(D, -4)? 4: 6; setvarn(T, fetch_var_higher()); F = gcoeff(nffactor(POL, T), 1, 1); u = gneg(lift_shallow(gel(F,2))); delete_var(); } } if (w == 4) /* u = I */ ne = shallowconcat(ne, RgXQV_RgXQ_mul(ne,u,POL)); else if (w == 6) /* u = j */ { GEN u2 = RgXQ_sqr(u,POL); ne = shallowconcat1(mkvec3(ne, RgXQV_RgXQ_mul(ne,u,POL), RgXQV_RgXQ_mul(ne,u2,POL))); } S = ne2V_to_xyV(ne); S = filter_sol_Z(S); S = shallowconcat(S, RgV_neg(S)); } } if (lg(S) == 1) S = SmallSols(S, x3, POL, rhs); } else if (typ(gel(tnf,3)) == t_INT) /* reducible case, pure power*/ { GEN bnf, ne1 = NULL, ne2 = NULL; long e = itos( gel(tnf,3) ); if (!Z_ispowerall(rhs, e, &rhs)) { avma = av; return cgetg(1, t_VEC); } tnf = gel(tnf,2); bnf = tnf_get_bnf(tnf); ne = get_neabs(bnf, rhs, lg(tnf)==8?tnf_get_Ind(tnf): gen_1); ne1= bnfisintnorm_i(bnf,rhs,1,ne); S = thue(tnf, rhs, ne1); if (!odd(e) && lg(tnf)==8) /* if s=0, norms are positive */ { ne2 = bnfisintnorm_i(bnf,rhs,-1,ne); S = shallowconcat(S, thue(tnf, negi(rhs), ne2)); } } else /* other reducible cases */ { /* solve f^e * g = rhs, f irreducible factor of smallest degree */ GEN P, D, v = gel(tnf, 2), R = gel(tnf, 3); long i, l, e = v[2], va = v[3], vb = v[4]; P = cgetg(lg(POL), t_POL); P[1] = POL[1]; D = divisors(rhs); l = lg(D); S = cgetg(1,t_VEC); for (i = 1; i < l; i++) { GEN Rab, df = gel(D,i), dg = gel(D,l-i); /* df*dg=|rhs| */ if (e > 1 && !Z_ispowerall(df, e, &df)) continue; /* Rab: univariate polynomial in Z[Y], whose roots are the possible y. */ /* Here and below, Rab != 0 */ if (signe(rhs) < 0) dg = negi(dg); /* df*dg=rhs */ Rab = gsubst(gsubst(R, va, df), vb, dg); sols_from_R(Rab, &S,P,POL,rhs); Rab = gsubst(gsubst(R, va, negi(df)), vb, odd(e)? negi(dg): dg); sols_from_R(Rab, &S,P,POL,rhs); } } S = filter_sol_x(S, L); S = gen_sort_uniq(S, (void*)lexcmp, cmp_nodata); return gerepileupto(av, S); } /********************************************************************/ /** **/ /** BNFISINTNORM (K. Belabas) **/ /** **/ /********************************************************************/ struct sol_abs { GEN rel; /* Primes PR[i] above a, expressed on generators of Cl(K) */ GEN partrel; /* list of vectors, partrel[i] = rel[1..i] * u[1..i] */ GEN cyc; /* orders of generators of Cl(K) given in bnf */ long *f; /* f[i] = f(PR[i]/p), inertia degree */ long *n; /* a = prod p^{ n_p }. n[i]=n_p if PR[i] divides p */ long *next; /* index of first P above next p, 0 if p is last */ long *S; /* S[i] = n[i] - sum_{ 1<=k<=i } f[k]*u[k] */ long *u; /* We want principal ideals I = prod PR[i]^u[i] */ GEN normsol;/* lists of copies of the u[] which are solutions */ long nPR; /* length(T->rel) = #PR */ long sindex, smax; /* current index in T->normsol; max. index */ }; /* u[1..i] has been filled. Norm(u) is correct. * Check relations in class group then save it. */ static void test_sol(struct sol_abs *T, long i) { long k, l; GEN s; if (T->partrel && !ZV_dvd(gel(T->partrel, i), T->cyc)) return; if (T->sindex == T->smax) { /* no more room in solution list: enlarge */ long new_smax = T->smax << 1; GEN new_normsol = new_chunk(new_smax+1); for (k=1; k<=T->smax; k++) gel(new_normsol,k) = gel(T->normsol,k); T->normsol = new_normsol; T->smax = new_smax; } gel(T->normsol, ++T->sindex) = s = cgetg_copy(T->u, &l); for (k=1; k <= i; k++) s[k] = T->u[k]; for ( ; k < l; k++) s[k] = 0; if (DEBUGLEVEL>2) { err_printf("sol = %Ps\n",s); if (T->partrel) err_printf("T->partrel = %Ps\n",T->partrel); err_flush(); } } /* partrel[i] <-- partrel[i-1] + u[i] * rel[i] */ static void fix_partrel(struct sol_abs *T, long i) { pari_sp av = avma; GEN part1 = gel(T->partrel,i); GEN part0 = gel(T->partrel,i-1); GEN rel = gel(T->rel, i); ulong u = T->u[i]; long k, l = lg(part1); for (k=1; k < l; k++) affii(addii(gel(part0,k), muliu(gel(rel,k), u)), gel(part1,k)); avma = av; } /* Recursive loop. Suppose u[1..i] has been filled * Find possible solutions u such that, Norm(prod PR[i]^u[i]) = a, taking * into account: * 1) the relations in the class group if need be. * 2) the factorization of a. */ static void isintnorm_loop(struct sol_abs *T, long i) { if (T->S[i] == 0) /* sum u[i].f[i] = n[i], do another prime */ { long k, next = T->next[i]; if (next == 0) { test_sol(T, i); return; } /* no primes left */ /* some primes left */ if (T->partrel) gaffect(gel(T->partrel,i), gel(T->partrel, next-1)); for (k=i+1; k < next; k++) T->u[k] = 0; i = next-1; } else if (i == T->next[i]-2 || i == T->nPR-1) { /* only one Prime left above prime; change prime, fix u[i+1] */ long q; if (T->S[i] % T->f[i+1]) return; q = T->S[i] / T->f[i+1]; i++; T->u[i] = q; if (T->partrel) fix_partrel(T,i); if (T->next[i] == 0) { test_sol(T,i); return; } } i++; T->u[i] = 0; if (T->partrel) gaffect(gel(T->partrel,i-1), gel(T->partrel,i)); if (i == T->next[i-1]) { /* change prime */ if (T->next[i] == i+1 || i == T->nPR) /* only one Prime above p */ { T->S[i] = 0; T->u[i] = T->n[i] / T->f[i]; /* we already know this is exact */ if (T->partrel) fix_partrel(T, i); } else T->S[i] = T->n[i]; } else T->S[i] = T->S[i-1]; /* same prime, different Prime */ for(;;) { isintnorm_loop(T, i); T->S[i] -= T->f[i]; if (T->S[i] < 0) break; T->u[i]++; if (T->partrel) { pari_sp av = avma; gaffect(ZC_add(gel(T->partrel,i), gel(T->rel,i)), gel(T->partrel,i)); avma = av; } } } static int get_sol_abs(struct sol_abs *T, GEN bnf, GEN fact, GEN *ptPR) { GEN nf = bnf_get_nf(bnf); GEN P = gel(fact,1), E = gel(fact,2), PR; long N = nf_get_degree(nf), nP = lg(P)-1, Ngen, max, nPR, i, j; max = nP*N; /* upper bound for T->nPR */ T->f = new_chunk(max+1); T->n = new_chunk(max+1); T->next = new_chunk(max+1); *ptPR = PR = cgetg(max+1, t_VEC); /* length to be fixed later */ nPR = 0; for (i = 1; i <= nP; i++) { GEN L = idealprimedec(nf, gel(P,i)); long lL = lg(L), gcd, k, v; ulong vn = itou(gel(E,i)); /* check that gcd_{P | p} f_P divides n_p */ gcd = pr_get_f(gel(L,1)); for (j=2; gcd > 1 && j < lL; j++) gcd = ugcd(gcd, pr_get_f(gel(L,j))); if (gcd > 1 && vn % gcd) { if (DEBUGLEVEL>2) { err_printf("gcd f_P does not divide n_p\n"); err_flush(); } return 0; } v = (i==nP)? 0: nPR + lL; for (k = 1; k < lL; k++) { GEN pr = gel(L,k); gel(PR, ++nPR) = pr; T->f[nPR] = pr_get_f(pr) / gcd; T->n[nPR] = vn / gcd; T->next[nPR] = v; } } T->nPR = nPR; setlg(PR, nPR + 1); T->u = cgetg(nPR+1, t_VECSMALL); T->S = new_chunk(nPR+1); T->cyc = bnf_get_cyc(bnf); Ngen = lg(T->cyc)-1; if (Ngen == 0) T->rel = T->partrel = NULL; /* trivial Cl(K), no relations to check */ else { int triv = 1; T->partrel = new_chunk(nPR+1); T->rel = new_chunk(nPR+1); for (i=1; i <= nPR; i++) { GEN c = isprincipal(bnf, gel(PR,i)); gel(T->rel,i) = c; if (triv && !ZV_equal0(c)) triv = 0; /* non trivial relations in Cl(K)*/ } /* triv = 1: all ideals dividing a are principal */ if (triv) T->rel = T->partrel = NULL; } if (T->partrel) { long B = ZV_max_lg(T->cyc) + 3; for (i = 0; i <= nPR; i++) { /* T->partrel[0] also needs to be initialized */ GEN c = cgetg(Ngen+1, t_COL); gel(T->partrel,i) = c; for (j=1; j<=Ngen; j++) { GEN z = cgeti(B); gel(c,j) = z; z[1] = evalsigne(0)|evallgefint(B); } } } T->smax = 511; T->normsol = new_chunk(T->smax+1); T->S[0] = T->n[1]; T->next[0] = 1; T->sindex = 0; isintnorm_loop(T, 0); return 1; } /* Look for unit of norm -1. Return 1 if it exists and set *unit, 0 otherwise */ static long get_unit_1(GEN bnf, GEN *unit) { GEN v, nf = bnf_get_nf(bnf); long i, n = nf_get_degree(nf); if (DEBUGLEVEL > 2) err_printf("looking for a fundamental unit of norm -1\n"); if (odd(n)) { *unit = gen_m1; return 1; } v = nfsign_units(bnf, NULL, 0); for (i = 1; i < lg(v); i++) if ( Flv_sum( gel(v,i), 2) ) { *unit = gel(bnf_get_fu(bnf), i); return 1; } return 0; } GEN bnfisintnormabs(GEN bnf, GEN a) { struct sol_abs T; GEN nf, res, PR, F; long i; if ((F = check_arith_all(a,"bnfisintnormabs"))) { a = typ(a) == t_VEC? gel(a,1): factorback(F); if (signe(a) < 0) F = clean_Z_factor(F); } bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); if (!signe(a)) return mkvec(gen_0); if (is_pm1(a)) return mkvec(gen_1); if (!F) F = absZ_factor(a); if (!get_sol_abs(&T, bnf, F, &PR)) return cgetg(1, t_VEC); /* |a| > 1 => T.nPR > 0 */ res = cgetg(T.sindex+1, t_VEC); for (i=1; i<=T.sindex; i++) { GEN x = vecsmall_to_col( gel(T.normsol,i) ); x = isprincipalfact(bnf, NULL, PR, x, nf_FORCE | nf_GEN_IF_PRINCIPAL); gel(res,i) = nf_to_scalar_or_alg(nf, x); /* x solution, up to sign */ } return res; } /* z = bnfisintnormabs(bnf,a), sa = 1 or -1, return bnfisintnorm(bnf,sa*|a|) */ static GEN bnfisintnorm_i(GEN bnf, GEN a, long sa, GEN z) { GEN nf = checknf(bnf), T = nf_get_pol(nf), f = nf_get_index(nf), unit = NULL; GEN Tp, A = signe(a) == sa? a: negi(a); long sNx, i, j, N = degpol(T), l = lg(z); long norm_1 = 0; /* gcc -Wall */ ulong p, Ap = 0; /* gcc -Wall */ forprime_t S; if (!signe(a)) return z; u_forprime_init(&S,3,ULONG_MAX); while((p = u_forprime_next(&S))) if (umodiu(f,p)) { Ap = umodiu(A,p); if (Ap) break; } Tp = ZX_to_Flx(T,p); /* p > 2 doesn't divide A nor Q_denom(z in Z_K)*/ /* update z in place to get correct signs: multiply by unit of norm -1 if * it exists, otherwise delete solution with wrong sign */ for (i = j = 1; i < l; i++) { GEN x = gel(z,i); int xpol = (typ(x) == t_POL); if (xpol) { GEN dx, y = Q_remove_denom(x,&dx); ulong Np = Flx_resultant(Tp, ZX_to_Flx(y,p), p); ulong dA = dx? Fl_mul(Ap, Fl_powu(umodiu(dx,p), N, p), p): Ap; /* Nx = Res(T,y) / dx^N = A or -A. Check mod p */ sNx = dA == Np? sa: -sa; } else sNx = gsigne(x) < 0 && odd(N) ? -1 : 1; if (sNx != sa) { if (! unit) norm_1 = get_unit_1(bnf, &unit); if (!norm_1) { if (DEBUGLEVEL > 2) err_printf("%Ps eliminated because of sign\n",x); continue; } if (xpol) x = (unit == gen_m1)? RgX_neg(x): RgXQ_mul(unit,x,T); else x = (unit == gen_m1)? gneg(x): RgX_Rg_mul(unit,x); } gel(z,j++) = x; } setlg(z, j); return z; } GEN bnfisintnorm(GEN bnf, GEN a) { pari_sp av = avma; GEN ne = bnfisintnormabs(bnf,a); switch(typ(a)) { case t_VEC: a = gel(a,1); break; case t_MAT: a = factorback(a); break; } return gerepilecopy(av, bnfisintnorm_i(bnf,a,signe(a), ne)); } pari-2.11.2/src/modules/subfield.c0000644000175000017500000006440513457566437015413 0ustar billbill/* Copyright (C) 2000-2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* SUBFIELDS OF A NUMBER FIELD */ /* J. Klueners and M. Pohst, J. Symb. Comp. (1996), vol. 11 */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" typedef struct _poldata { GEN pol; GEN dis; /* |disc(pol)| */ GEN roo; /* roots(pol) */ GEN den; /* multiple of index(pol) */ } poldata; typedef struct _primedata { GEN p; /* prime */ GEN pol; /* pol mod p, squarefree */ GEN ff; /* factorization of pol mod p */ GEN Z; /* cycle structure of the above [ Frobenius orbits ] */ long lcm; /* lcm of the above */ GEN T; /* ffinit(p, lcm) */ GEN fk; /* factorization of pol over F_(p^lcm) */ GEN firstroot; /* *[i] = index of first root of fk[i] */ GEN interp; /* *[i] = interpolation polynomial for fk[i] * [= 1 on the first root firstroot[i], 0 on the others] */ GEN bezoutC; /* Bezout coefficients attached to the ff[i] */ GEN Trk; /* used to compute traces (cf poltrace) */ } primedata; typedef struct _blockdata { poldata *PD; /* data depending from pol */ primedata *S;/* data depending from pol, p */ GEN DATA; /* data depending from pol, p, degree, # translations [updated] */ long N; /* deg(PD.pol) */ long d; /* subfield degree */ long size;/* block degree = N/d */ } blockdata; static GEN print_block_system(blockdata *B, GEN Y, GEN BS); static GEN test_block(blockdata *B, GEN L, GEN D); /* COMBINATORIAL PART: generate potential block systems */ #define BIL 32 /* for 64bit machines also */ /* Computation of potential block systems of given size d attached to a * rational prime p: give a row vector of row vectors containing the * potential block systems of imprimitivity; a potential block system is a * vector of row vectors (enumeration of the roots). */ static GEN calc_block(blockdata *B, GEN Z, GEN Y, GEN SB) { long r = lg(Z), lK, i, j, t, tp, T, u, nn, lnon, lY; GEN K, n, non, pn, pnon, e, Yp, Zp, Zpp; pari_sp av0 = avma; if (DEBUGLEVEL>3) { err_printf("lg(Z) = %ld, lg(Y) = %ld\n", r,lg(Y)); if (DEBUGLEVEL > 5) { err_printf("Z = %Ps\n",Z); err_printf("Y = %Ps\n",Y); } } lnon = minss(BIL, r); e = new_chunk(BIL); n = new_chunk(r); non = new_chunk(lnon); pnon = new_chunk(lnon); pn = new_chunk(lnon); Zp = cgetg(lnon,t_VEC); Zpp = cgetg(lnon,t_VEC); nn = 0; for (i=1; isize; for (j = 1; j < r; j++) if (n[j] % k) break; if (j == r) { gel(Yp,lY) = Z; SB = print_block_system(B, Yp, SB); avma = av; } } gel(Yp,lY) = Zp; K = divisorsu(n[1]); lK = lg(K); for (i=1; isize*k, lpn = 0; for (j=2; j= BIL) pari_err_OVERFLOW("calc_block"); pn[lpn] = n[j]; pnon[lpn] = j; ngcd = ugcd(ngcd, n[j]); } if (dk % ngcd) continue; T = 1L< print_block_system */ if (!T) continue; } if (dk == n[1]) { /* empty subset, t = 0. Split out for clarity */ Zp[1] = Z[1]; setlg(Zp, 2); for (u=1,j=2; j>=1) { if (tp&1) { nn += pn[u]; e[u] = 1; } else e[u] = 0; } if (dk != nn) continue; for (j=1; jN; long *k, *n, **e, *t; GEN D, De, Z, cyperm, perm, VOID = cgetg(1, t_VECSMALL); if (DEBUGLEVEL>5) err_printf("Y = %Ps\n",Y); n = new_chunk(N+1); D = vectrunc_init(N+1); t = new_chunk(r+1); k = new_chunk(r+1); Z = cgetg(r+1, t_VEC); for (ns=0,i=1; isize; De = cgetg(ki+1,t_VEC); for (j=1; j<=ki; j++) gel(De,j) = VOID; for (j=1; j<=si; j++) { GEN cy = gel(Yi,j); for (l=1,lp=0; l<=n[j]; l++) { lp++; if (lp > ki) lp = 1; gel(De,lp) = vecsmall_append(gel(De,lp), cy[l]); } } append(D, De); if (si>1 && ki>1) { GEN p1 = cgetg(si,t_VEC); for (j=2; j<=si; j++) p1[j-1] = Yi[j]; ns++; t[ns] = si-1; k[ns] = ki-1; gel(Z,ns) = p1; } } if (DEBUGLEVEL>2) err_printf("\nns = %ld\n",ns); if (!ns) return test_block(B, SB, D); setlg(Z, ns+1); e = (long**)new_chunk(ns+1); for (i=1; i<=ns; i++) { e[i] = new_chunk(t[i]+1); for (j=1; j<=t[i]; j++) e[i][j] = 0; } cyperm= cgetg(N+1,t_VECSMALL); perm = cgetg(N+1,t_VECSMALL); i = ns; do { pari_sp av = avma; for (u=1; u<=N; u++) perm[u] = u; for (u=1; u<=ns; u++) for (v=1; v<=t[u]; v++) perm_mul_i(perm, cycle_power_to_perm(cyperm, gmael(Z,u,v), e[u][v])); SB = test_block(B, SB, im_block_by_perm(D,perm)); avma = av; /* i = 1..ns, j = 1..t[i], e[i][j] loop through 0..k[i]. * TODO: flatten to 1-dimensional loop */ if (++e[ns][t[ns]] > k[ns]) { j = t[ns]-1; while (j>=1 && e[ns][j] == k[ns]) j--; if (j >= 1) { e[ns][j]++; for (l=j+1; l<=t[ns]; l++) e[ns][l] = 0; } else { i = ns-1; while (i>=1) { j = t[i]; while (j>=1 && e[i][j] == k[i]) j--; if (j<1) i--; else { e[i][j]++; for (l=j+1; l<=t[i]; l++) e[i][l] = 0; for (ll=i+1; ll<=ns; ll++) for (l=1; l<=t[ll]; l++) e[ll][l] = 0; break; } } } } } while (i > 0); return SB; } /* ALGEBRAIC PART: test potential block systems */ static GEN polsimplify(GEN x) { long i,lx = lg(x); for (i=2; i M[i] for some i; 1 otherwise */ static long ok_coeffs(GEN g,GEN M) { long i, lg = lg(g)-1; /* g is monic, and cst term is ok */ for (i=3; i 0) return 0; return 1; } /* assume x in Fq, return Tr_{Fq/Fp}(x) as a t_INT */ static GEN trace(GEN x, GEN Trq, GEN p) { long i, l; GEN s; if (typ(x) == t_INT) return Fp_mul(x, gel(Trq,1), p); l = lg(x)-1; if (l == 1) return gen_0; x++; s = mulii(gel(x,1), gel(Trq,1)); for (i=2; ip, pol = FpX_red(gel(DATA,1), p); long i, l; interp = gel(DATA,9); bezoutC= gel(DATA,6); h = NULL; l = lg(interp); for (i=1; iT, p); t = poltrace(t, gel(S->Trk,i), p); t = FpX_mul(t, gel(bezoutC,i), p); h = h? FpX_add(h,t,p): t; } return FpX_rem(h, pol, p); } /* g in Z[X] potentially defines a subfield of Q[X]/f. It is a subfield iff A * (cf subfield) was a block system; then there * exists h in Q[X] such that f | g o h. listdelta determines h s.t f | g o h * in Fp[X] (cf chinese_retrieve_pol). Try to lift it; den is a * multiplicative bound for denominator of lift. */ static GEN embedding(GEN g, GEN DATA, primedata *S, GEN den, GEN listdelta) { GEN TR, w0_Q, w0, w1_Q, w1, wpow, h0, gp, T, q2, q, maxp, a, p = S->p; long rt; pari_sp av; T = gel(DATA,1); rt = brent_kung_optpow(degpol(T), 4, 3); maxp= gel(DATA,7); gp = RgX_deriv(g); av = avma; w0 = chinese_retrieve_pol(DATA, S, listdelta); w0_Q = centermod(gmul(w0,den), p); h0 = FpXQ_inv(FpX_FpXQ_eval(gp,w0, T,p), T,p); /* = 1/g'(w0) mod (T,p) */ wpow = NULL; q = sqri(p); for(;;) {/* Given g,w0,h0 in Z[x], s.t. h0.g'(w0) = 1 and g(w0) = 0 mod (T,p), find * [w1,h1] satisfying the same conditions mod p^2, [w1,h1] = [w0,h0] (mod p) * (cf. Dixon: J. Austral. Math. Soc., Series A, vol.49, 1990, p.445) */ if (DEBUGLEVEL>1) err_printf("lifting embedding mod p^k = %Ps^%ld\n",S->p, Z_pval(q,S->p)); /* w1 := w0 - h0 g(w0) mod (T,q) */ if (wpow) a = FpX_FpXQV_eval(g,wpow, T,q); else a = FpX_FpXQ_eval(g,w0, T,q); /* first time */ /* now, a = 0 (p) */ a = FpXQ_mul(ZX_neg(h0), ZX_Z_divexact(a, p), T,p); w1 = ZX_add(w0, ZX_Z_mul(a, p)); w1_Q = centermod(ZX_Z_mul(w1, remii(den,q)), q); if (ZX_equal(w1_Q, w0_Q)) { GEN G = is_pm1(den)? g: RgX_rescale(g,den); if (gequal0(RgX_RgXQ_eval(G, w1_Q, T))) break; } else if (cmpii(q,maxp) > 0) { GEN G = is_pm1(den)? g: RgX_rescale(g,den); if (gequal0(RgX_RgXQ_eval(G, w1_Q, T))) break; if (DEBUGLEVEL) err_printf("coeff too big for embedding\n"); return NULL; } gerepileall(av, 5, &w1,&h0,&w1_Q,&q,&p); q2 = sqri(q); wpow = FpXQ_powers(w1, rt, T, q2); /* h0 := h0 * (2 - h0 g'(w1)) mod (T,q) * = h0 + h0 * (1 - h0 g'(w1)) */ a = FpXQ_mul(ZX_neg(h0), FpX_FpXQV_eval(gp, FpXV_red(wpow,q),T,q), T,q); a = ZX_Z_add_shallow(a, gen_1); /* 1 - h0 g'(w1) = 0 (p) */ a = FpXQ_mul(h0, ZX_Z_divexact(a, p), T,p); h0 = ZX_add(h0, ZX_Z_mul(a, p)); w0 = w1; w0_Q = w1_Q; p = q; q = q2; } TR = gel(DATA,5); if (!gequal0(TR)) w1_Q = RgX_translate(w1_Q, TR); return gdiv(w1_Q,den); } /* return U list of polynomials s.t U[i] = 1 mod fk[i] and 0 mod fk[j] for all * other j */ static GEN get_bezout(GEN pol, GEN fk, GEN p) { long i, l = lg(fk); GEN A, B, d, u, v, U = cgetg(l, t_VEC); for (i=1; i 0) pari_err_COPRIME("get_bezout",A,B); d = constant_coeff(d); if (!gequal1(d)) v = FpX_Fp_mul(v, Fp_inv(d, p), p); gel(U,i) = FpX_mul(B,v, p); } return U; } static GEN init_traces(GEN ff, GEN T, GEN p) { long N = degpol(T),i,j,k, r = lg(ff); GEN Frob = FpX_matFrobenius(T,p); GEN y,p1,p2,Trk,pow,pow1; k = degpol(gel(ff,r-1)); /* largest degree in modular factorization */ pow = cgetg(k+1, t_VEC); gel(pow,1) = gen_0; /* dummy */ gel(pow,2) = Frob; pow1= cgetg(k+1, t_VEC); /* 1st line */ for (i=3; i<=k; i++) gel(pow,i) = FpM_mul(gel(pow,i-1), Frob, p); gel(pow1,1) = gen_0; /* dummy */ for (i=2; i<=k; i++) { p1 = cgetg(N+1, t_VEC); gel(pow1,i) = p1; p2 = gel(pow,i); for (j=1; j<=N; j++) gel(p1,j) = gcoeff(p2,1,j); } /* Trk[i] = line 1 of x -> x + x^p + ... + x^{p^(i-1)} */ Trk = pow; /* re-use (destroy) pow */ gel(Trk,1) = vec_ei(N,1); for (i=2; i<=k; i++) gel(Trk,i) = gadd(gel(Trk,i-1), gel(pow1,i)); y = cgetg(r, t_VEC); for (i=1; iff), v = fetch_var(), N = degpol(S->pol); GEN T, p = S->p; if (S->lcm == degpol(gel(S->ff,lff-1))) { T = leafcopy(gel(S->ff,lff-1)); setvarn(T, v); } else T = init_Fq(p, S->lcm, v); S->T = T; S->firstroot = cgetg(lff, t_VECSMALL); S->interp = cgetg(lff, t_VEC); S->fk = cgetg(N+1, t_VEC); for (l=1,j=1; jff, j), deg1 = FpX_factorff_irred(F, T,p); GEN H = gel(deg1,1), a = Fq_neg(constant_coeff(H), T,p); GEN Q = FqX_div(F, H, T,p); GEN q = Fq_inv(FqX_eval(Q, a, T,p), T,p); gel(S->interp,j) = FqX_Fq_mul(Q, q, T,p); /* = 1 at a, 0 at other roots */ S->firstroot[j] = l; for (i=1; ifk, l) = gel(deg1, i); } S->Trk = init_traces(S->ff, T,p); S->bezoutC = get_bezout(S->pol, S->ff, p); } static void choose_prime(primedata *S, GEN pol, GEN dpol) { long i, j, k, r, lcm, oldlcm, N = degpol(pol); ulong p, pp; GEN Z, ff, oldff, n, oldn; pari_sp av; forprime_t T; u_forprime_init(&T, (N*N) >> 2, ULONG_MAX); oldlcm = 0; oldff = oldn = NULL; pp = 0; /* gcc -Wall */ av = avma; for(k = 1; k < 11 || !oldlcm; k++,avma = av) { if (k > 5 * N) pari_err_OVERFLOW("choose_prime [too many block systems]"); do p = u_forprime_next(&T); while (!umodiu(dpol, p)); ff = gel(Flx_factor(ZX_to_Flx(pol,p), p), 1); r = lg(ff)-1; if (r == N || r >= BIL) continue; n = cgetg(r+1, t_VECSMALL); lcm = n[1] = degpol(gel(ff,1)); for (j=2; j<=r; j++) { n[j] = degpol(gel(ff,j)); lcm = ulcm(lcm, n[j]); } if (lcm <= oldlcm) continue; /* false when oldlcm = 0 */ if (DEBUGLEVEL) err_printf("p = %lu,\tlcm = %ld,\torbits: %Ps\n",p,lcm,n); pp = p; oldn = n; oldff = ff; oldlcm = lcm; if (r == 1) break; av = avma; } if (DEBUGLEVEL) err_printf("Chosen prime: p = %ld\n", pp); FlxV_to_ZXV_inplace(oldff); S->ff = oldff; S->lcm= oldlcm; S->p = utoipos(pp); S->pol = FpX_red(pol, S->p); init_primedata(S); n = oldn; r = lg(n); Z = cgetg(r,t_VEC); for (k=0,i=1; iZ = Z; } /* maxroot t_REAL */ static GEN bound_for_coeff(long m, GEN rr, GEN *maxroot) { long i,r1, lrr=lg(rr); GEN p1,b1,b2,B,M, C = matpascal(m-1); for (r1=1; r1 < lrr; r1++) if (typ(gel(rr,r1)) != t_REAL) break; r1--; rr = gabs(rr,0); *maxroot = vecmax(rr); for (i=1; i pol(X+1) ] and update DATA * 1: polynomial pol * 2: p^e (for Hensel lifts) such that p^e > max(M), * 3: Hensel lift to precision p^e of DATA[4] * 4: roots of pol in F_(p^S->lcm), * 5: number of polynomial changes (translations) * 6: Bezout coefficients attached to the S->ff[i] * 7: Hadamard bound for coefficients of h(x) such that g o h = 0 mod pol. * 8: bound M for polynomials defining subfields x PD->den * 9: *[i] = interpolation polynomial for S->ff[i] [= 1 on the first root S->firstroot[i], 0 on the others] */ static void compute_data(blockdata *B) { GEN ffL, roo, pe, p1, p2, fk, fhk, MM, maxroot, pol; primedata *S = B->S; GEN p = S->p, T = S->T, ff = S->ff, DATA = B->DATA; long i, j, l, e, N, lff = lg(ff); if (DEBUGLEVEL>1) err_printf("Entering compute_data()\n\n"); pol = B->PD->pol; N = degpol(pol); roo = B->PD->roo; if (DATA) { GEN Xm1 = gsub(pol_x(varn(pol)), gen_1); GEN TR = addiu(gel(DATA,5), 1); GEN mTR = negi(TR), interp, bezoutC; if (DEBUGLEVEL>1) err_printf("... update (translate) an existing DATA\n\n"); gel(DATA,5) = TR; pol = RgX_translate(gel(DATA,1), gen_m1); p1 = cgetg_copy(roo, &l); for (i=1; i 0) /* do not turn pol_1(0) into gen_1 */ { p1 = RgX_translate(gel(interp,i), gen_m1); gel(interp,i) = FpXX_red(p1, p); } if (degpol(gel(bezoutC,i)) > 0) { p1 = RgX_translate(gel(bezoutC,i), gen_m1); gel(bezoutC,i) = FpXX_red(p1, p); } } ff = cgetg(lff, t_VEC); /* copy, do not overwrite! */ for (i=1; iff,i), mTR), p); } else { DATA = cgetg(10,t_VEC); fk = S->fk; gel(DATA,5) = gen_0; gel(DATA,6) = leafcopy(S->bezoutC); gel(DATA,9) = leafcopy(S->interp); } gel(DATA,1) = pol; MM = gmul2n(bound_for_coeff(B->d, roo, &maxroot), 1); gel(DATA,8) = MM; e = logintall(shifti(vecmax(MM),20), p, &pe); /* overlift 2^20 [d-1 test] */ gel(DATA,2) = pe; gel(DATA,4) = roots_from_deg1(fk); /* compute fhk = ZpX_liftfact(pol,fk,T,p,e,pe) in 2 steps * 1) lift in Zp to precision p^e */ ffL = ZpX_liftfact(pol, ff, pe, p, e); fhk = NULL; for (l=i=1; isize + N*(N-1)/2); p1 = divrr(mulrr(p1,p2), gsqrt(B->PD->dis,DEFAULTPREC)); gel(DATA,7) = mulii(shifti(ceil_safe(p1), 1), B->PD->den); if (DEBUGLEVEL>1) { err_printf("f = %Ps\n",DATA[1]); err_printf("p = %Ps, lift to p^%ld\n", p, e); err_printf("2 * Hadamard bound * ind = %Ps\n",DATA[7]); err_printf("2 * M = %Ps\n",DATA[8]); } if (B->DATA) { DATA = gclone(DATA); if (isclone(B->DATA)) gunclone(B->DATA); } B->DATA = DATA; } /* g = polynomial, h = embedding. Return [[g,h]] */ static GEN _subfield(GEN g, GEN h) { return mkvec(mkvec2(g,h)); } /* Return a subfield, gen_0 [ change p ] or NULL [ not a subfield ] */ static GEN subfield(GEN A, blockdata *B) { long N, i, j, d, lf, m = lg(A)-1; GEN M, pe, pol, fhk, g, e, d_1_term, delta, listdelta, whichdelta; GEN T = B->S->T, p = B->S->p, firstroot = B->S->firstroot; pol= gel(B->DATA,1); N = degpol(pol); d = N/m; /* m | N */ pe = gel(B->DATA,2); fhk= gel(B->DATA,3); M = gel(B->DATA,8); delta = cgetg(m+1,t_VEC); whichdelta = cgetg(N+1, t_VECSMALL); d_1_term = gen_0; for (i=1; i<=m; i++) { GEN Ai = gel(A,i), p1 = gel(fhk,Ai[1]); for (j=2; j<=d; j++) p1 = Fq_mul(p1, gel(fhk,Ai[j]), T, pe); gel(delta,i) = p1; if (DEBUGLEVEL>5) err_printf("delta[%ld] = %Ps\n",i,p1); /* g = prod (X - delta[i]) * if g o h = 0 (pol), we'll have h(Ai[j]) = delta[i] for all j */ /* fk[k] belongs to block number whichdelta[k] */ for (j=1; j<=d; j++) whichdelta[Ai[j]] = i; if (typ(p1) == t_POL) p1 = constant_coeff(p1); d_1_term = addii(d_1_term, p1); } d_1_term = centermod(d_1_term, pe); /* Tr(g) */ if (abscmpii(d_1_term, gel(M,3)) > 0) { if (DEBUGLEVEL>1) err_printf("d-1 test failed\n"); return NULL; } g = FqV_roots_to_pol(delta, T, pe, 0); g = centermod(polsimplify(g), pe); /* assume g in Z[X] */ if (!ok_coeffs(g,M)) { if (DEBUGLEVEL>2) err_printf("pol. found = %Ps\n",g); if (DEBUGLEVEL>1) err_printf("coeff too big for pol g(x)\n"); return NULL; } if (!FpX_is_squarefree(g, p)) { if (DEBUGLEVEL>2) err_printf("pol. found = %Ps\n",g); if (DEBUGLEVEL>1) err_printf("changing f(x): p divides disc(g)\n"); compute_data(B); return subfield(A, B); } lf = lg(firstroot); listdelta = cgetg(lf, t_VEC); for (i=1; iDATA, B->S, B->PD->den, listdelta); if (!e) return NULL; if (DEBUGLEVEL) err_printf("... OK!\n"); return _subfield(g, e); } /* L list of current subfields, test whether potential block D is a block, * if so, append corresponding subfield */ static GEN test_block(blockdata *B, GEN L, GEN D) { pari_sp av = avma; GEN sub = subfield(D, B); if (sub) { GEN old = L; L = gclone( L? shallowconcat(L, sub): sub ); if (old) gunclone(old); } avma = av; return L; } /* subfields of degree d */ static GEN subfields_of_given_degree(blockdata *B) { pari_sp av = avma; GEN L; if (DEBUGLEVEL) err_printf("\n* Look for subfields of degree %ld\n\n", B->d); B->DATA = NULL; compute_data(B); L = calc_block(B, B->S->Z, cgetg(1,t_VEC), NULL); if (DEBUGLEVEL>9) err_printf("\nSubfields of degree %ld: %Ps\n", B->d, L? L: cgetg(1,t_VEC)); if (isclone(B->DATA)) gunclone(B->DATA); avma = av; return L; } static GEN fix_var(GEN x, long v) { long i, l = lg(x); if (!v) return x; for (i=1; ipol = T; setvarn(T, 0); if (nf) { PD->den = nf_get_zkden(nf); PD->roo = nf_get_roots(nf); PD->dis = mulii(absi_shallow(nf_get_disc(nf)), sqri(nf_get_index(nf))); } else { PD->den = initgaloisborne(T,NULL,nbits2prec(bit_accuracy(ZX_max_lg(T))), &L,NULL,&dis); PD->roo = L; PD->dis = absi_shallow(dis); } } static GEN subfieldsall(GEN nf) { pari_sp av = avma; long N, ld, i, v0; GEN G, pol, dg, LSB, NLSB; poldata PD; primedata S; blockdata B; /* much easier if nf is Galois (WSS) */ G = galoisinit(nf, NULL); if (G != gen_0) { GEN L, S, p; long l; pol = get_nfpol(nf, &nf); L = lift_shallow( galoissubfields(G, 0, varn(pol)) ); l = lg(L); S = cgetg(l, t_VECSMALL); for (i=1; i 2) { B.PD = &PD; B.S = &S; B.N = N; choose_prime(&S, PD.pol, PD.dis); for (i=ld-1; i>1; i--) { B.size = dg[i]; B.d = N / B.size; NLSB = subfields_of_given_degree(&B); if (NLSB) { LSB = gconcat(LSB, NLSB); gunclone(NLSB); } } (void)delete_var(); /* from choose_prime */ } LSB = shallowconcat(LSB, _subfield(pol, pol_x(0))); if (DEBUGLEVEL) err_printf("\n***** Leaving subfields\n\n"); return fix_var(gerepilecopy(av, LSB), v0); } GEN nfsubfields(GEN nf, long d) { pari_sp av = avma; long N, v0; GEN LSB, pol, G; poldata PD; primedata S; blockdata B; if (!d) return subfieldsall(nf); pol = get_nfpol(nf, &nf); /* in order to treat trivial cases */ RgX_check_ZX(pol,"nfsubfields"); v0 = varn(pol); N = degpol(pol); if (d == N) return gerepilecopy(av, _subfield(pol, pol_x(v0))); if (d == 1) return gerepilecopy(av, _subfield(pol_x(v0), pol)); if (d < 1 || d > N || N % d) return cgetg(1,t_VEC); /* much easier if nf is Galois (WSS) */ G = galoisinit(nf? nf: pol, NULL); if (G != gen_0) { /* Bingo */ GEN L = galoissubgroups(G), F; long k,i, l = lg(L), o = N/d; F = cgetg(l, t_VEC); k = 1; for (i=1; i= (lvl) + 3) err_printf /********************************************************************/ /** **/ /** ASSOCIATIVE ALGEBRAS, CENTRAL SIMPLE ALGEBRAS **/ /** contributed by Aurel Page (2014) **/ /** **/ /********************************************************************/ static GEN alg_subalg(GEN al, GEN basis); static GEN alg_maximal_primes(GEN al, GEN P); static GEN algnatmultable(GEN al, long D); static GEN _tablemul_ej(GEN mt, GEN x, long j); static GEN _tablemul_ej_Fp(GEN mt, GEN x, long j, GEN p); static GEN _tablemul_ej_Fl(GEN mt, GEN x, long j, ulong p); static ulong algtracei(GEN mt, ulong p, ulong expo, ulong modu); static GEN alg_pmaximal(GEN al, GEN p); static GEN alg_maximal(GEN al); static GEN algtracematrix(GEN al); static GEN algtableinit_i(GEN mt0, GEN p); static GEN algbasisrightmultable(GEN al, GEN x); static GEN algabstrace(GEN al, GEN x); static GEN algbasismul(GEN al, GEN x, GEN y); static GEN algbasismultable(GEN al, GEN x); static GEN algbasismultable_Flm(GEN mt, GEN x, ulong m); static int checkalg_i(GEN al) { GEN mt; if (typ(al) != t_VEC || lg(al) != 12) return 0; mt = alg_get_multable(al); if (typ(mt) != t_VEC || lg(mt) == 1 || typ(gel(mt,1)) != t_MAT) return 0; if (!isintzero(alg_get_splittingfield(al)) && gequal0(alg_get_char(al))) { if (typ(gel(al,2)) != t_VEC || lg(gel(al,2)) == 1) return 0; checkrnf(alg_get_splittingfield(al)); } return 1; } void checkalg(GEN al) { if (!checkalg_i(al)) pari_err_TYPE("checkalg [please apply alginit()]",al); } static int checklat_i(GEN al, GEN lat) { long N,i,j; GEN m,t,c; if (typ(lat)!=t_VEC || lg(lat) != 3) return 0; t = gel(lat,2); if (typ(t) != t_INT && typ(t) != t_FRAC) return 0; if (gsigne(t)<=0) return 0; m = gel(lat,1); if (typ(m) != t_MAT) return 0; N = alg_get_absdim(al); if (lg(m)-1 != N || lg(gel(m,1))-1 != N) return 0; for (i=1; i<=N; i++) for (j=1; j<=N; j++) { c = gcoeff(m,i,j); if (typ(c) != t_INT) return 0; if (j0) { if (v[i]==b) { v[i] = -b; i--; } else { v[i]++; break; } } if (i==0) break; y1 = y0; for (i=1; i<=n; i++) y1 = nfadd(nf, y1, ZC_z_mul(gel(red,i), v[i])); if (!nfchecksigns(nf, y1, pl)) continue; ny = absi_shallow(nfnorm(nf, y1)); if (!signe(ny)) continue; ny = diviiexact(ny,gcdii(ny,N)); fan = Z_factor_limit(ny,1<<17); if (lg(fan)>1 && nbrows(fan)>0 && !isprime(gcoeff(fan,nbrows(fan),1))) continue; y2 = idealdivexact(nf,y1,idealadd(nf,y1,I)); *fa = idealfactor(nf, y2); if (!data || test(data,y1,*fa)) return y1; } } } /* if data == NULL, the test is skipped */ /* in the test, the factorization does not contain the known factors */ static GEN factoredextchinesetest(GEN nf, GEN x, GEN y, GEN pl, GEN* fa, GEN data, int (*test)(GEN,GEN,GEN)) { pari_sp av = avma; long n,i; GEN x1, y0, y1, red, N, I, P = gel(x,1), E = gel(x,2); n = nf_get_degree(nf); x = idealchineseinit(nf, mkvec2(x,pl)); x1 = gel(x,1); red = lg(x1) == 1? matid(n): gel(x1,1); y0 = idealchinese(nf, x, y); E = shallowcopy(E); if (!gequal0(y0)) for (i=1; i= d. Initialize Mx = y solver */ static GEN Flm_invimage_init(GEN M, ulong p) { GEN v = Flm_indexrank(M, p), perm = gel(v,1); GEN MM = rowpermute(M, perm); /* square invertible */ return mkvec2(Flm_inv(MM,p), perm); } /* assume Mx = y has a solution, v = Flm_invimage_init(M,p); return x */ static GEN Flm_invimage_pre(GEN v, GEN y, ulong p) { GEN inv = gel(v,1), perm = gel(v,2); return Flm_Flc_mul(inv, vecsmallpermute(y, perm), p); } GEN algradical(GEN al) { pari_sp av = avma; GEN I, x, traces, K, MT, P, mt; long l,i,ni, n; ulong modu, expo, p; checkalg(al); P = alg_get_char(al); mt = alg_get_multable(al); n = alg_get_absdim(al); dbg_printf(1)("algradical: char=%Ps, dim=%d\n", P, n); traces = algtracematrix(al); if (!signe(P)) { dbg_printf(2)(" char 0, computing kernel...\n"); K = ker(traces); dbg_printf(2)(" ...done.\n"); ni = lg(K)-1; if (!ni) { avma = av; return gen_0; } return gerepileupto(av, K); } dbg_printf(2)(" char>0, computing kernel...\n"); K = FpM_ker(traces, P); dbg_printf(2)(" ...done.\n"); ni = lg(K)-1; if (!ni) { avma = av; return gen_0; } if (abscmpiu(P,n)>0) return gerepileupto(av, K); /* tough case, p <= n. Ronyai's algorithm */ p = P[2]; l = 1; expo = p; modu = p*p; dbg_printf(2)(" char>0, hard case.\n"); while (modu<=(ulong)n) { l++; modu *= p; } MT = ZMV_to_FlmV(mt, modu); I = ZM_to_Flm(K,p); /* I_0 */ for (i=1; i<=l; i++) {/*compute I_i, expo = p^i, modu = p^(l+1) > n*/ long j, lig,col; GEN v = cgetg(ni+1, t_VECSMALL); GEN invI = Flm_invimage_init(I, p); dbg_printf(2)(" computing I_%d:\n", i); traces = cgetg(ni+1,t_MAT); for (j = 1; j <= ni; j++) { GEN M = algbasismultable_Flm(MT, gel(I,j), modu); uel(v,j) = algtracei(M, p,expo,modu); } for (col=1; col<=ni; col++) { GEN t = cgetg(n+1,t_VECSMALL); gel(traces,col) = t; x = gel(I, col); /*col-th basis vector of I_{i-1}*/ for (lig=1; lig<=n; lig++) { GEN y = _tablemul_ej_Fl(MT,x,lig,p); GEN z = Flm_invimage_pre(invI, y, p); uel(t,lig) = Flv_dotproduct(v, z, p); } } dbg_printf(2)(" computing kernel...\n"); K = Flm_ker(traces, p); dbg_printf(2)(" ...done.\n"); ni = lg(K)-1; if (!ni) { avma = av; return gen_0; } I = Flm_mul(I,K,p); expo *= p; } return Flm_to_ZM(I); } /* compute the multiplication table of the element x, where mt is a * multiplication table in an arbitrary ring */ static GEN Rgmultable(GEN mt, GEN x) { long i, l = lg(x); GEN z = NULL; for (i = 1; i < l; i++) { GEN c = gel(x,i); if (!gequal0(c)) { GEN M = RgM_Rg_mul(gel(mt,i),c); z = z? RgM_add(z, M): M; } } return z; } static GEN change_Rgmultable(GEN mt, GEN P, GEN Pi) { GEN mt2; long lmt = lg(mt), i; mt2 = cgetg(lmt,t_VEC); for (i=1;i first basis element is identity */ GEN alg_centralproj(GEN al, GEN z, long maps) { pari_sp av = avma; GEN S, U, Ui, alq, p; long i, iu, lz = lg(z); checkalg(al); if (typ(z) != t_VEC) pari_err_TYPE("alcentralproj",z); p = alg_get_char(al); dbg_printf(3)(" alg_centralproj: char=%Ps, dim=%d, #z=%d\n", p, alg_get_absdim(al), lz-1); S = cgetg(lz,t_VEC); /* S[i] = Im(z_i) */ for (i=1; i1 */ { GEN C2, P; long m, d, i, j; m = lg(C)-1; d = m/n; C2 = cgetg(d+1,t_COL); for (i=1; i<=d; i++) { P = pol_xn(n-1,v); for (j=1; j<=n; j++) gel(P,j+1) = gel(C,n*(i-1)+j); P = normalizepol(P); gel(C2,i) = P; } return C2; } static GEN RgM_contract(GEN A, long n, long v) /* n>1 */ { GEN A2 = cgetg(lg(A),t_MAT); long i; for (i=1; i (F_p)^(d^2*n) */ static GEN Fq_mat2col(GEN M, long d, long n) { long N = d*d*n, i, j, k; GEN C = cgetg(N+1, t_COL); for (i=1; i<=d; i++) for (j=1; j<=d; j++) for (k=0; k1) { T2 = init_Fq(p,n,v); setvarn(T,fetch_var_higher()); ro = FpXQX_roots(T2,T,p); ro = gel(ro,1); primelt = algpoleval(al,ro,primelt); T = T2; } /* descend al*e to a vector space over the center */ /* lifte: al*e -> al ; proje: al*e -> al */ lifte = shallowextract(mte,gel(ire,2)); extre = shallowmatextract(mte,gel(ire,1),gel(ire,2)); extre = FpM_inv(extre,p); proje = rowpermute(mte,gel(ire,1)); proje = FpM_mul(extre,proje,p); if (n==1) { B = lifte; C = proje; } else { M = algbasismultable(al,primelt); M = FpM_mul(M,lifte,p); M = FpM_mul(proje,M,p); B = descend(M,n,p,v); C = gel(B,2); B = gel(B,1); B = FpM_mul(lifte,B,p); C = FqM_mul(C,proje,T,p); } /* compute the isomorphism */ mt = alg_get_multable(al); map = cgetg(N+1,t_VEC); M = cgetg(N+1,t_MAT); for (i=1; i<=N; i++) { mx = gel(mt,i); mx = FpM_mul(mx,B,p); mx = FqM_mul(C,mx,T,p); gel(map,i) = mx; gel(M,i) = Fq_mat2col(mx,d,n); } mapi = FpM_inv(M,p); if (!mapi) pari_err(e_MISC, "the algebra must be simple (alg_finite_csa_split 3)"); return mkvec3(T,map,mapi); } GEN algsplit(GEN al, long v) { pari_sp av = avma; GEN res, T, map, mapi, ff, p; long i,j,k,li,lj; checkalg(al); p = alg_get_char(al); if (gequal0(p)) pari_err_IMPL("splitting a characteristic 0 algebra over its center"); res = alg_finite_csa_split(al, v); T = gel(res,1); map = gel(res,2); mapi = gel(res,3); ff = Tp_to_FF(T,p); for (i=1; i 1 && ZC_is_ei(gel(M,1)) != i) return NULL; /* i = 1 checked at end */ gel(MT,i) = M; } if (!ZM_isidentity(gel(MT,1))) return NULL; return MT; } static GEN check_relmt(GEN nf, GEN mt) { long i, l = lg(mt), j, k; GEN MT = gcopy(mt), a, b, d; if (typ(MT) != t_VEC || l == 1) return NULL; for (i = 1; i < l; i++) { GEN M = gel(MT,i); if (typ(M) != t_MAT || lg(M) != l || lgcols(M) != l) return NULL; for (k = 1; k < l; k++) for (j = 1; j < l; j++) { a = gcoeff(M,j,k); if (typ(a)==t_INT) continue; b = algtobasis(nf,a); d = Q_denom(b); if (!isint1(d)) pari_err_DOMAIN("alg_csa_table", "denominator(mt)", "!=", gen_1, mt); gcoeff(M,j,k) = lift(basistoalg(nf,b)); } if (i > 1 && RgC_is_ei(gel(M,1)) != i) return NULL; /* i = 1 checked at end */ gel(MT,i) = M; } if (!RgM_isidentity(gel(MT,1))) return NULL; return MT; } int algisassociative(GEN mt0, GEN p) { pari_sp av = avma; long i, j, k, n; GEN M, mt; if (checkalg_i(mt0)) { p = alg_get_char(mt0); mt0 = alg_get_multable(mt0); } if (typ(p) != t_INT) pari_err_TYPE("algisassociative",p); mt = check_mt(mt0, isintzero(p)? NULL: p); if (!mt) pari_err_TYPE("algisassociative (mult. table)", mt0); n = lg(mt)-1; M = cgetg(n+1,t_MAT); for (j=1; j<=n; j++) gel(M,j) = cgetg(n+1,t_COL); for (i=1; i<=n; i++) { GEN mi = gel(mt,i); for (j=1; j<=n; j++) gcoeff(M,i,j) = gel(mi,j); /* ei.ej */ } for (i=2; i<=n; i++) { GEN mi = gel(mt,i); for (j=2; j<=n; j++) { for (k=2; k<=n; k++) { GEN x, y; if (signe(p)) { x = _tablemul_ej_Fp(mt,gcoeff(M,i,j),k,p); y = FpM_FpC_mul(mi,gcoeff(M,j,k),p); } else { x = _tablemul_ej(mt,gcoeff(M,i,j),k); y = RgM_RgC_mul(mi,gcoeff(M,j,k)); } /* not cmp_universal: must not fail on 0 == Mod(0,2) for instance */ if (!gequal(x,y)) { avma = av; return 0; } } } } avma = av; return 1; } int algiscommutative(GEN al) /* assumes e_1 = 1 */ { long i,j,k,N,sp; GEN mt,a,b,p; checkalg(al); if (alg_type(al) != al_TABLE) return alg_get_degree(al)==1; N = alg_get_absdim(al); mt = alg_get_multable(al); p = alg_get_char(al); sp = signe(p); for (i=2; i<=N; i++) for (j=2; j<=N; j++) for (k=1; k<=N; k++) { a = gcoeff(gel(mt,i),k,j); b = gcoeff(gel(mt,j),k,i); if (sp) { if (cmpii(Fp_red(a,p), Fp_red(b,p))) return 0; } else if (gcmp(a,b)) return 0; } return 1; } int algissemisimple(GEN al) { pari_sp av = avma; GEN rad; checkalg(al); if (alg_type(al) != al_TABLE) return 1; rad = algradical(al); avma = av; return gequal0(rad); } /* ss : known to be semisimple */ int algissimple(GEN al, long ss) { pari_sp av = avma; GEN Z, dec, p; checkalg(al); if (alg_type(al) != al_TABLE) return 1; if (!ss && !algissemisimple(al)) return 0; p = alg_get_char(al); if (signe(p)) Z = algprimesubalg(al); else Z = algtablecenter(al); if (lg(Z) == 2) {/* dim Z = 1 */ avma = av; return 1; } dec = alg_decompose(al, Z, 1, NULL); avma = av; return gequal0(dec); } static long is_place_emb(GEN nf, GEN pl) { long r, r1, r2; if (typ(pl) != t_INT) pari_err_TYPE("is_place_emb", pl); if (signe(pl)<=0) pari_err_DOMAIN("is_place_emb", "pl", "<=", gen_0, pl); nf_get_sign(nf,&r1,&r2); r = r1+r2; if (cmpiu(pl,r)>0) pari_err_DOMAIN("is_place_emb", "pl", ">", utoi(r), pl); return itou(pl); } static long alghasse_emb(GEN al, long emb) { GEN nf = alg_get_center(al); long r1 = nf_get_r1(nf); return (emb <= r1)? alg_get_hasse_i(al)[emb]: 0; } static long alghasse_pr(GEN al, GEN pr) { GEN hf = alg_get_hasse_f(al); long i = tablesearch(gel(hf,1), pr, &cmp_prime_ideal); return i? gel(hf,2)[i]: 0; } static long alghasse_0(GEN al, GEN pl) { GEN pr, nf; if (alg_type(al)== al_CSA) pari_err_IMPL("computation of Hasse invariants over table CSA"); if ((pr = get_prid(pl))) return alghasse_pr(al, pr); nf = alg_get_center(al); return alghasse_emb(al, is_place_emb(nf, pl)); } GEN alghasse(GEN al, GEN pl) { long h; checkalg(al); if (alg_type(al) == al_TABLE) pari_err_TYPE("alghasse [use alginit]",al); h = alghasse_0(al,pl); return sstoQ(h, alg_get_degree(al)); } /* h >= 0, d >= 0 */ static long indexfromhasse(long h, long d) { return d/ugcd(h,d); } long algindex(GEN al, GEN pl) { long d, res, i, l; GEN hi, hf; checkalg(al); if (alg_type(al) == al_TABLE) pari_err_TYPE("algindex [use alginit]",al); d = alg_get_degree(al); if (pl) return indexfromhasse(alghasse_0(al,pl), d); /* else : global index */ res = 1; hi = alg_get_hasse_i(al); l = lg(hi); for (i=1; i 1 and 0 < i < lgcols(x) */ static GEN alMrow_alC_mul_i(GEN al, GEN x, GEN y, long i, long lx) { pari_sp av = avma; GEN c = algmul(al,gcoeff(x,i,1),gel(y,1)), ZERO; long k; ZERO = zerocol(alg_get_absdim(al)); for (k = 2; k < lx; k++) { GEN t = algmul(al, gcoeff(x,i,k), gel(y,k)); if (!gequal(t,ZERO)) c = algadd(al, c, t); } return gerepilecopy(av, c); } /* return x * y, 1 < lx = lg(x), l = lgcols(x) */ static GEN alM_alC_mul_i(GEN al, GEN x, GEN y, long lx, long l) { GEN z = cgetg(l,t_COL); long i; for (i=1; i1 && i==j) gel(res, ijk) = gsub(gel(res,ijk), gel(res,k)); } } } return res; } static GEN algbasis2mat(GEN al, GEN M, long N) { long n = alg_get_absdim(al), i, j, k, ij, ijk; GEN res, x; res = zeromatcopy(N,N); for (i=1; i<=N; i++) for (j=1; j<=N; j++) gcoeff(res,i,j) = zerocol(n); for (i=1; i<=N; i++) { for (j=1, ij=(i-1)*N+1; j<=N; j++, ij++) { x = gcoeff(res,i,j); for (k=1, ijk=(ij-1)*n+1; k<=n; k++, ijk++) { gel(x,k) = gel(M,ijk); if (i>1 && i==j) gel(x,k) = gadd(gel(x,k), gel(M,k)); } } } return res; } static GEN algmatbasis_ei(GEN al, long ijk, long N) { long n = alg_get_absdim(al), i, j, k, ij; GEN res; res = zeromatcopy(N,N); for (i=1; i<=N; i++) for (j=1; j<=N; j++) gcoeff(res,i,j) = zerocol(n); k = ijk%n; if (k==0) k=n; ij = (ijk-k)/n+1; if (ij==1) { for (i=1; i<=N; i++) gcoeff(res,i,i) = col_ei(n,k); return res; } j = ij%N; if (j==0) j=N; i = (ij-j)/N+1; gcoeff(res,i,j) = col_ei(n,k); return res; } /* FIXME lazy implementation! */ static GEN algleftmultable_mat(GEN al, GEN M) { long N = lg(M)-1, n = alg_get_absdim(al), D = N*N*n, j; GEN res, x, Mx; if (N == 0) return cgetg(1, t_MAT); if (N != nbrows(M)) pari_err_DIM("algleftmultable_mat (nonsquare)"); res = cgetg(D+1, t_MAT); for (j=1; j<=D; j++) { x = algmatbasis_ei(al, j, N); Mx = algmul(al, M, x); gel(res, j) = algmat2basis(al, Mx); } return res; } /* left multiplication table on integral basis */ static GEN algleftmultable(GEN al, GEN x) { pari_sp av = avma; long tx; GEN res; checkalg(al); tx = alg_model(al,x); switch(tx) { case al_TRIVIAL : res = mkmatcopy(mkcol(gel(x,1))); break; case al_ALGEBRAIC : x = algalgtobasis(al,x); case al_BASIS : res = algbasismultable(al,x); break; case al_MATRIX : res = algleftmultable_mat(al,x); break; default : return NULL; /* LCOV_EXCL_LINE */ } return gerepileupto(av,res); } static GEN algbasissplittingmatrix_csa(GEN al, GEN x) { long d = alg_get_degree(al), i, j; GEN rnf = alg_get_splittingfield(al), splba = alg_get_splittingbasis(al), splbainv = alg_get_splittingbasisinv(al), M; M = algbasismultable(al,x); M = RgM_mul(M, splba); /* TODO best order ? big matrix /Q vs small matrix /nf */ M = RgM_mul(splbainv, M); for (i=1; i<=d; i++) for (j=1; j<=d; j++) gcoeff(M,i,j) = rnfeltabstorel(rnf, gcoeff(M,i,j)); return M; } GEN algtomatrix(GEN al, GEN x, long abs) { pari_sp av = avma; GEN res = NULL; long ta, tx, i, j; checkalg(al); ta = alg_type(al); if (abs || ta==al_TABLE) return algleftmultable(al,x); tx = alg_model(al,x); if (tx==al_MATRIX) { if (lg(x) == 1) return cgetg(1, t_MAT); res = zeromatcopy(nbrows(x),lg(x)-1); for (j=1; j=0) pari_err_PRIORITY("algredcharpoly",pol_x(v),">=",w); switch(alg_type(al)) { case al_CYCLIC: case al_CSA: return gerepileupto(av, algredcharpoly_i(al, x, v)); } return NULL; /*LCOV_EXCL_LINE*/ } static GEN algbasischarpoly(GEN al, GEN x, long v) { pari_sp av = avma; GEN p = alg_get_char(al), mx; if (alg_model(al,x) == al_MATRIX) mx = algleftmultable_mat(al,x); else mx = algbasismultable(al,x); if (signe(p)) { GEN res = FpM_charpoly(mx,p); setvarn(res,v); return gerepileupto(av, res); } return gerepileupto(av, charpoly(mx,v)); } GEN algcharpoly(GEN al, GEN x, long v, long abs) { checkalg(al); if (v<0) v=0; /* gneg(x[1]) left on stack */ if (alg_model(al,x) == al_TRIVIAL) { GEN p = alg_get_char(al); if (signe(p)) return deg1pol(gen_1,Fp_neg(gel(x,1),p),v); return deg1pol(gen_1,gneg(gel(x,1)),v); } switch(alg_type(al)) { case al_CYCLIC: case al_CSA: if (abs) { if (alg_model(al,x)==al_ALGEBRAIC) x = algalgtobasis(al,x); } else return algredcharpoly(al,x,v); case al_TABLE: return algbasischarpoly(al,x,v); default : return NULL; /* LCOV_EXCL_LINE */ } } /* assumes x in basis form */ static GEN algabstrace(GEN al, GEN x) { pari_sp av = avma; GEN res = NULL, p = alg_get_char(al); if (signe(p)) return FpV_dotproduct(x, alg_get_tracebasis(al), p); switch(alg_model(al,x)) { case al_TRIVIAL: return gcopy(gel(x,1)); break; case al_BASIS: res = RgV_dotproduct(x, alg_get_tracebasis(al)); break; } return gerepileupto(av,res); } static GEN algredtrace(GEN al, GEN x) { pari_sp av = avma; GEN res = NULL; switch(alg_model(al,x)) { case al_TRIVIAL: return gcopy(gel(x,1)); break; case al_BASIS: return algredtrace(al, algbasistoalg(al,x)); /* TODO precompute too? */ case al_ALGEBRAIC: switch(alg_type(al)) { case al_CYCLIC: res = rnfelttrace(alg_get_splittingfield(al),gel(x,1)); break; case al_CSA: res = gtrace(algalgmultable_csa(al,x)); res = gdiv(res, stoi(alg_get_degree(al))); break; default: return NULL; /* LCOV_EXCL_LINE */ } } return gerepileupto(av,res); } static GEN algtrace_mat(GEN al, GEN M, long abs) { pari_sp av = avma; long N = lg(M)-1, i; GEN res, p = alg_get_char(al); if (N == 0) return gen_0; if (N != nbrows(M)) pari_err_DIM("algtrace_mat (nonsquare)"); if (!signe(p)) p = NULL; res = algtrace(al, gcoeff(M,1,1), abs); for (i=2; i<=N; i++) { if (p) res = Fp_add(res, algtrace(al,gcoeff(M,i,i),abs), p); else res = gadd(res, algtrace(al,gcoeff(M,i,i),abs)); } if (abs || alg_type(al) == al_TABLE) res = gmulgs(res, N); /* absolute trace */ return gerepileupto(av, res); } GEN algtrace(GEN al, GEN x, long abs) { checkalg(al); if (alg_model(al,x) == al_MATRIX) return algtrace_mat(al,x,abs); switch(alg_type(al)) { case al_CYCLIC: case al_CSA: if (!abs) return algredtrace(al,x); if (alg_model(al,x)==al_ALGEBRAIC) x = algalgtobasis(al,x); case al_TABLE: return algabstrace(al,x); default : return NULL; /* LCOV_EXCL_LINE */ } } static GEN ZM_trace(GEN x) { long i, lx = lg(x); GEN t; if (lx < 3) return lx == 1? gen_0: gcopy(gcoeff(x,1,1)); t = gcoeff(x,1,1); for (i = 2; i < lx; i++) t = addii(t, gcoeff(x,i,i)); return t; } static GEN FpM_trace(GEN x, GEN p) { long i, lx = lg(x); GEN t; if (lx < 3) return lx == 1? gen_0: gcopy(gcoeff(x,1,1)); t = gcoeff(x,1,1); for (i = 2; i < lx; i++) t = Fp_add(t, gcoeff(x,i,i), p); return t; } static GEN algtracebasis(GEN al) { pari_sp av = avma; GEN mt = alg_get_multable(al), p = alg_get_char(al); long i, l = lg(mt); GEN v = cgetg(l, t_VEC); if (signe(p)) for (i=1; i < l; i++) gel(v,i) = FpM_trace(gel(mt,i), p); else for (i=1; i < l; i++) gel(v,i) = ZM_trace(gel(mt,i)); return gerepileupto(av,v); } /* Assume: i > 0, expo := p^i <= absdim, x contained in I_{i-1} given by mult * table modulo modu=p^(i+1). Return Tr(x^(p^i)) mod modu */ static ulong algtracei(GEN mt, ulong p, ulong expo, ulong modu) { pari_sp av = avma; long j, l = lg(mt); ulong tr = 0; mt = Flm_powu(mt,expo,modu); for (j=1; j1; i--) { gel(res,1) = Fp_add(gel(res,1), gel(pol,i), p); if (i>2) res = FpM_FpC_mul(mx, res, p); } } else { for (i=lg(pol)-1; i>1; i--) { gel(res,1) = gadd(gel(res,1), gel(pol,i)); if (i>2) res = RgM_RgC_mul(mx, res); } } return gerepileupto(av, res); } /** GRUNWALD-WANG **/ /* Song Wang's PhD thesis (pdf pages) p.25 definition of chi_b. K^Ker(chi_b) = K(b^(1/m)) p.26 bound on the conductor (also Cohen adv. GTM 193 p.166) p.21 & p.34 description special case, also on wikipedia: http://en.wikipedia.org/wiki/Grunwald%E2%80%93Wang_theorem#Special_fields p.77 Kummer case */ /* n > 0. Is n = 2^k ? */ static int uispow2(ulong n) { return !(n &(n-1)); } static GEN get_phi0(GEN bnr, GEN Lpr, GEN Ld, GEN pl, long *pr, long *pn) { const long NTRY = 10; /* FIXME: magic constant */ const long n = (lg(Ld)==1)? 2: vecsmall_max(Ld); GEN S = bnr_get_cyc(bnr); GEN Sst, G, globGmod, loc, X, Rglob, Rloc, H, U, Lconj; long i, j, r, nbfrob, nbloc, nz, t; *pn = n; *pr = r = lg(S)-1; if (!r) return NULL; Lconj = NULL; nbloc = nbfrob = lg(Lpr)-1; if (uispow2(n)) { long l = lg(pl), k = 1; GEN real = cgetg(l, t_VECSMALL); for (i=1; i 1) { GEN nf = bnr_get_nf(bnr), I = bid_get_fact(bnr_get_bid(bnr)); GEN v, y, C = idealchineseinit(bnr, I); long r1 = nf_get_r1(nf), n = nbrows(I); nbloc += k-1; Lconj = cgetg(k, t_VEC); v = const_vecsmall(r1,1); y = const_vec(n, gen_1); for (i = 1; i < k; i++) { v[i] = -1; gel(Lconj,i) = idealchinese(nf,mkvec2(C,v),y); v[i] = 1; } } } /* compute Z/n-dual */ Sst = cgetg(r+1, t_VECSMALL); for (i=1; i<=r; i++) Sst[i] = ugcdiu(gel(S,i), n); if (Sst[1] != n) return NULL; globGmod = cgetg(r+1,t_MAT); G = cgetg(r+1,t_VECSMALL); for (i=1; i<=r; i++) { G[i] = n / Sst[i]; /* pairing between S and Sst */ gel(globGmod,i) = cgetg(nbloc+1,t_VECSMALL); } /* compute images of Frobenius elements (and complex conjugation) */ loc = cgetg(nbloc+1,t_VECSMALL); for (i=1; i<=nbloc; i++) { long L; if (i<=nbfrob) { X = gel(Lpr,i); L = Ld[i]; } else { /* X = 1 (mod f), sigma_i(x) < 0, positive at all other real places */ X = gel(Lconj,i-nbfrob); L = 2; } X = ZV_to_Flv(isprincipalray(bnr,X), n); for (nz=0,j=1; j<=r; j++) { ulong c = (X[j] * G[j]) % L; ucoeff(globGmod,i,j) = c; if (c) nz = 1; } if (!nz) return NULL; loc[i] = L; } /* try some random elements in the dual */ Rglob = cgetg(r+1,t_VECSMALL); for (t=0; t nbloc) return zv_to_ZV(Rglob); } /* try to realize some random elements of the product of the local duals */ H = ZM_hnfall_i(shallowconcat(zm_to_ZM(globGmod), diagonal_shallow(zv_to_ZV(loc))), &U, 2); /* H,U nbloc x nbloc */ Rloc = cgetg(nbloc+1,t_COL); for (t=0; t= 0) pari_err_PRIORITY("nfgrunwaldwang", pol_x(var), ">=", vnf); if (typ(Lpr) != t_VEC) pari_err_TYPE("nfgrunwaldwang",Lpr); if (lg(Lpr) != lg(Ld)) pari_err_DIM("nfgrunwaldwang [#Lpr != #Ld]"); for (i=1; i1) return gerepileupto(av,nfgwkummer(nf,Lpr,Ld,pl,var)); if (ell==n) { if (!bnf) bnf = Buchall(nf,0,0); return gerepileupto(av,bnfgwgeneric(bnf,Lpr,Ld,pl,var)); } else { pari_err_IMPL("nfgrunwaldwang for non-prime degree"); avma = av; return gen_0; /*LCOV_EXCL_LINE*/ } } /** HASSE INVARIANTS **/ /* TODO long -> ulong + uel */ static GEN hasseconvert(GEN H, long n) { GEN h, c; long i, l; switch(typ(H)) { case t_VEC: l = lg(H); h = cgetg(l,t_VECSMALL); if (l == 1) return h; c = gel(H,1); if (typ(c) == t_VEC && l == 3) return mkvec2(gel(H,1),hasseconvert(gel(H,2),n)); for (i=1; i= 2 */ static long cyclicrelfrob0(GEN nf, GEN aut, GEN pr, GEN q, long f, long g) { pari_sp av = avma; long s; GEN T, p, modpr, a, b; modpr = nf_to_Fq_init(nf,&pr,&T,&p); a = pol_x(nf_get_varn(nf)); b = galoisapply(nf, aut, modpr_genFq(modpr)); b = nf_to_Fq(nf, b, modpr); for (s=0; !ZX_equal(a, b); s++) a = Fq_pow(a, q, T, p); avma = av; return g*Fl_inv(s, f);/* 0) pari_err_DOMAIN("cyclicrelfrob","e(PR/pr)",">",gen_1,pr); g = nbrows(fa); f = n/g; if (f <= 2) frob = g%n; else { GEN nf2, PR = gcoeff(fa,1,1); GEN autabs = rnfeltreltoabs(rnf,gel(auts,g)); nf2 = obj_check(rnf,rnf_NFABS); autabs = nfadd(nf2, autabs, gmul(rnf_get_k(rnf), rnf_get_alpha(rnf))); frob = cyclicrelfrob0(nf2, autabs, PR, pr_norm(pr), f, g); } avma = av; return frob; } static long localhasse(GEN rnf, GEN cnd, GEN pl, GEN auts, GEN b, long k) { pari_sp av = avma; long v, m, h, lfa, frob, n, i; GEN previous, y, pr, nf, q, fa; nf = rnf_get_nf(rnf); n = rnf_get_degree(rnf); pr = gcoeff(cnd,k,1); v = nfval(nf, b, pr); m = lg(cnd)>1 ? nbrows(cnd) : 0; /* add the valuation of b to the conductor... */ previous = gcoeff(cnd,k,2); gcoeff(cnd,k,2) = addis(previous, v); y = const_vec(m, gen_1); gel(y,k) = b; /* find a factored element y congruent to b mod pr^(vpr(b)+vpr(cnd)) and to 1 mod the conductor. */ y = factoredextchinese(nf, cnd, y, pl, &fa); h = 0; lfa = nbrows(fa); /* sum of all Hasse invariants of (rnf/nf,aut,y) is 0, Hasse invariants at q!=pr are easy, Hasse invariant at pr is the same as for al=(rnf/nf,aut,b). */ for (i=1; i<=lfa; i++) { q = gcoeff(fa,i,1); if (cmp_prime_ideal(pr,q)) { frob = cyclicrelfrob(rnf, auts, q); frob = Fl_mul(frob,umodiu(gcoeff(fa,i,2),n),n); h = Fl_add(h,frob,n); } } /* ...then restore it. */ gcoeff(cnd,k,2) = previous; avma = av; return Fl_neg(h,n); } static GEN allauts(GEN rnf, GEN aut) { long n = rnf_get_degree(rnf), i; GEN pol = rnf_get_pol(rnf), vaut; if (n==1) n=2; vaut = cgetg(n,t_VEC); aut = lift_shallow(rnfbasistoalg(rnf,aut)); gel(vaut,1) = aut; for (i=1; i= 0 */ static void nextgen(GEN gene, long h, GEN* gens, GEN* hgens, long* ngens, long* curgcd) { long nextgcd = ugcd(h,*curgcd); if (nextgcd == *curgcd) return; (*ngens)++; gel(*gens,*ngens) = gene; gel(*hgens,*ngens) = utoi(h); *curgcd = nextgcd; return; } static int dividesmod(long d, long h, long n) { return !(h%cgcd(d,n)); } /* ramified prime with nontrivial Hasse invariant */ static GEN localcomplete(GEN rnf, GEN pl, GEN cnd, GEN auts, long j, long n, long h, long* v) { GEN nf, gens, hgens, pr, modpr, T, p, sol, U, D, b, gene, randg, pu; long ngens, i, d, np, k, d1, d2, hg, dnf, vcnd, curgcd; nf = rnf_get_nf(rnf); pr = gcoeff(cnd,j,1); np = umodiu(pr_norm(pr), n); dnf = nf_get_degree(nf); vcnd = itos(gcoeff(cnd,j,2)); ngens = 13+dnf; gens = zerovec(ngens); hgens = zerovec(ngens); *v = 0; curgcd = 0; ngens = 0; if (!uisprime(n)) { gene = pr_get_gen(pr); hg = localhasse(rnf, cnd, pl, auts, gene, j); nextgen(gene, hg, &gens, &hgens, &ngens, &curgcd); } if (ugcd(np,n) != 1) { /* GCD(Np,n) != 1 */ pu = idealprincipalunits(nf,pr,vcnd); pu = abgrp_get_gen(pu); for (i=1; i1 || lk%2==0) { maxdeg = 1; Lpr = gel(hfl,1); Ld = gcopy(gel(hfl,2)); for (j=1; j1) pl[1] = -1; else { Lpr2 = extraprime(nf,Lpr); Ld2 = cgetg(lg(Ld)+1, t_VECSMALL); for (j=1; j2) return 0; } return 1; } /* no garbage collection */ static GEN subcycloindep(GEN nf, long n, long v, GEN L, GEN *pr) { pari_sp av; forprime_t S; ulong p; u_forprime_arith_init(&S, 1, ULONG_MAX, 1, n); av = avma; while ((p = u_forprime_next(&S))) { ulong r = pgener_Fl(p); GEN pol = galoissubcyclo(utoipos(p), utoipos(Fl_powu(r,n,p)), 0, v); GEN fa = nffactor(nf, pol); if (lgcols(fa) == 2 && linindep(pol,L)) { *pr = utoipos(r); return pol; } avma = av; } pari_err_BUG("subcycloindep (no suitable prime = 1(mod n))"); /*LCOV_EXCL_LINE*/ *pr = NULL; return NULL; /*LCOV_EXCL_LINE*/ } GEN alg_matrix(GEN nf, long n, long v, GEN L, long maxord) { pari_sp av = avma; GEN pol, gal, rnf, cyclo, g, r, aut; dbg_printf(1)("alg_matrix\n"); if (n<=0) pari_err_DOMAIN("alg_matrix", "n", "<=", gen_0, stoi(n)); pol = subcycloindep(nf, n, v, L, &r); rnf = rnfinit(nf, pol); cyclo = nfinit(pol, nf_get_prec(nf)); gal = galoisinit(cyclo, NULL); g = genefrob(cyclo,gal,r); aut = galoispermtopol(gal,g); return gerepileupto(av, alg_cyclic(rnf, aut, gen_1, maxord)); } GEN alg_hilbert(GEN nf, GEN a, GEN b, long v, long maxord) { pari_sp av = avma; GEN C, P, rnf, aut; dbg_printf(1)("alg_hilbert\n"); checknf(nf); if (!isint1(Q_denom(a))) pari_err_DOMAIN("alg_hilbert", "denominator(a)", "!=", gen_1,a); if (!isint1(Q_denom(b))) pari_err_DOMAIN("alg_hilbert", "denominator(b)", "!=", gen_1,b); if (v < 0) v = 0; C = Rg_col_ei(gneg(a), 3, 3); gel(C,1) = gen_1; P = gtopoly(C,v); rnf = rnfinit(nf, P); aut = gneg(pol_x(v)); return gerepileupto(av, alg_cyclic(rnf, aut, b, maxord)); } GEN alginit(GEN A, GEN B, long v, long maxord) { long w; switch(nftyp(A)) { case typ_NF: if (v<0) v=0; w = gvar(nf_get_pol(A)); if (varncmp(v,w)>=0) pari_err_PRIORITY("alginit", pol_x(v), ">=", w); switch(typ(B)) { long nB; case t_INT: return alg_matrix(A, itos(B), v, cgetg(1,t_VEC), maxord); case t_VEC: nB = lg(B)-1; if (nB && typ(gel(B,1)) == t_MAT) return alg_csa_table(A,B,v,maxord); switch(nB) { case 2: return alg_hilbert(A, gel(B,1), gel(B,2), v, maxord); case 3: if (typ(gel(B,1))!=t_INT) pari_err_TYPE("alginit [degree should be an integer]", gel(B,1)); return alg_hasse(A, itos(gel(B,1)), gel(B,2), gel(B,3), v, maxord); } } pari_err_TYPE("alginit", B); break; case typ_RNF: if (typ(B) != t_VEC || lg(B) != 3) pari_err_TYPE("alginit", B); return alg_cyclic(A, gel(B,1), gel(B,2), maxord); } pari_err_TYPE("alginit", A); return NULL;/*LCOV_EXCL_LINE*/ } /* assumes al CSA or CYCLIC */ static GEN algnatmultable(GEN al, long D) { GEN res, x; long i; res = cgetg(D+1,t_VEC); for (i=1; i<=D; i++) { x = algnattoalg(al,col_ei(D,i)); gel(res,i) = algZmultable(al,x); } return res; } /* no garbage collection */ static void algcomputehasse(GEN al) { long r1, k, n, m, m1, m2, m3, i, m23, m123; GEN rnf, nf, b, fab, disc2, cnd, fad, auts, pr, pl, perm; GEN hi, PH, H, L; rnf = alg_get_splittingfield(al); n = rnf_get_degree(rnf); nf = rnf_get_nf(rnf); b = alg_get_b(al); r1 = nf_get_r1(nf); auts = alg_get_auts(al); (void)alg_get_abssplitting(al); /* real places where rnf/nf ramifies */ pl = cgetg(r1+1, t_VECSMALL); for (k=1; k<=r1; k++) pl[k] = !rnfrealdec(rnf,k); /* infinite Hasse invariants */ if (odd(n)) hi = const_vecsmall(r1, 0); else { GEN s = nfsign(nf, b); hi = cgetg(r1+1, t_VECSMALL); for (k = 1; k<=r1; k++) hi[k] = (s[k] && pl[k]) ? (n/2) : 0; } fab = idealfactor(nf, b); disc2 = rnf_get_idealdisc(rnf); L = nfmakecoprime(nf, &disc2, gel(fab,1)); m = lg(L)-1; /* m1 = #{pr|b: pr \nmid disc}, m3 = #{pr|b: pr | disc} */ perm = cgetg(m+1, t_VECSMALL); for (i=1, m1=m, k=1; k<=m; k++) if (signe(gel(L,k))) perm[m1--] = k; else perm[i++] = k; m3 = m - m1; /* disc2 : factor of disc coprime to b */ fad = idealfactor(nf, disc2); /* m2 : number of prime factors of disc not dividing b */ m2 = nbrows(fad); m23 = m2+m3; m123 = m1+m2+m3; /* initialize the possibly ramified primes (hasse) and the factored conductor of rnf/nf (cnd) */ cnd = zeromatcopy(m23,2); PH = cgetg(m123+1, t_VEC); /* ramified primes */ H = cgetg(m123+1, t_VECSMALL); /* Hasse invariant */ /* compute Hasse invariant at primes that are unramified in rnf/nf */ for (k=1; k<=m1; k++) {/* pr | b, pr \nmid disc */ long frob, e, j = perm[k]; pr = gcoeff(fab,j,1); e = itos(gcoeff(fab,j,2)); frob = cyclicrelfrob(rnf, auts, pr); gel(PH,k) = pr; H[k] = Fl_mul(frob, e, n); } /* compute Hasse invariant at primes that are ramified in rnf/nf */ for (k=1; k<=m2; k++) {/* pr \nmid b, pr | disc */ pr = gcoeff(fad,k,1); gel(PH,k+m1) = pr; gcoeff(cnd,k,1) = pr; gcoeff(cnd,k,2) = gcoeff(fad,k,2); } for (k=1; k<=m3; k++) { /* pr | (b, disc) */ long j = perm[k+m1]; pr = gcoeff(fab,j,1); gel(PH,k+m1+m2) = pr; gcoeff(cnd,k+m2,1) = pr; gcoeff(cnd,k+m2,2) = gel(L,j); } gel(cnd,2) = gdiventgs(gel(cnd,2), eulerphiu(n)); for (k=1; k<=m23; k++) H[k+m1] = localhasse(rnf, cnd, pl, auts, b, k); gel(al,4) = hi; perm = gen_indexsort(PH, (void*)&cmp_prime_ideal, &cmp_nodata); gel(al,5) = mkvec2(vecpermute(PH,perm),vecsmallpermute(H,perm)); checkhasse(nf,alg_get_hasse_f(al),alg_get_hasse_i(al),n); } static GEN alg_maximal_primes(GEN al, GEN P) { pari_sp av = avma; long l = lg(P), i; for (i=1; i2) { for (i=1; i0 either an integer or a rational number. Recommended and returned by the functions below: - I HNF and primitive */ /* TODO use hnfmodid whenever possible using a*O <= I <= O * for instance a = ZM_det_triangular(I) */ static GEN primlat(GEN lat) { GEN m, t, c; m = alglat_get_primbasis(lat); t = alglat_get_scalar(lat); m = Q_primitive_part(m,&c); if (c) return mkvec2(m,gmul(t,c)); return lat; } /* assumes the lattice contains d * integral basis, d=0 allowed */ GEN alglathnf(GEN al, GEN m, GEN d) { pari_sp av = avma; long N,i,j; GEN m2, c; checkalg(al); N = alg_get_absdim(al); if (!d) d = gen_0; if (typ(m) == t_VEC) m = matconcat(m); if (typ(m) == t_COL) m = algleftmultable(al,m); if (typ(m) != t_MAT) pari_err_TYPE("alglathnf",m); if (typ(d) != t_FRAC && typ(d) != t_INT) pari_err_TYPE("alglathnf",d); if (lg(m)-1 < N || lg(gel(m,1))-1 != N) pari_err_DIM("alglathnf"); for (i=1; i<=N; i++) for (j=1; j R^{m*n} */ static GEN mat2col(GEN M, long m, long n) { long i,j,k,p; GEN C; p = m*n; C = cgetg(p+1,t_COL); for (i=1,k=1;i<=m;i++) for (j=1;j<=n;j++,k++) gel(C,k) = gcoeff(M,i,j); return C; } static GEN alglattransporter_i(GEN al, GEN lat1, GEN lat2, long right) { GEN m1, m2, m2i, M, MT, mt, t1, t2, T, c; long N, i; N = alg_get_absdim(al); m1 = alglat_get_primbasis(lat1); m2 = alglat_get_primbasis(lat2); m2i = RgM_inv_upper(m2); c = detint(m1); t1 = alglat_get_scalar(lat1); m1 = RgM_Rg_mul(m1,t1); t2 = alglat_get_scalar(lat2); m2i = RgM_Rg_div(m2i,t2); MT = right? NULL: alg_get_multable(al); M = cgetg(N+1, t_MAT); for (i=1; i<=N; i++) { if (right) mt = algbasisrightmultable(al, vec_ei(N,i)); else mt = gel(MT,i); mt = RgM_mul(m2i,mt); mt = RgM_mul(mt,m1); gel(M,i) = mat2col(mt, N, N); } c = gdiv(t2,gmul(c,t1)); c = denom_i(c); T = QM_invimZ_mod(M,c); return primlat(mkvec2(T,gen_1)); } /* { x in al | x*lat1 subset lat2} */ GEN alglatlefttransporter(GEN al, GEN lat1, GEN lat2) { pari_sp av = avma; checkalg(al); checklat(al,lat1); checklat(al,lat2); return gerepilecopy(av, alglattransporter_i(al,lat1,lat2,0)); } /* { x in al | lat1*x subset lat2} */ GEN alglatrighttransporter(GEN al, GEN lat1, GEN lat2) { pari_sp av = avma; checkalg(al); checklat(al,lat1); checklat(al,lat2); return gerepilecopy(av, alglattransporter_i(al,lat1,lat2,1)); } GEN algmakeintegral(GEN mt0, long maps) { pari_sp av = avma; long n,i; GEN m,P,Pi,mt2,mt; n = lg(mt0)-1; mt = check_mt(mt0,NULL); if (!mt) pari_err_TYPE("algmakeintegral", mt0); if (isint1(Q_denom(mt0))) { if (maps) mt = mkvec3(mt,matid(n),matid(n)); return gerepilecopy(av,mt); } dbg_printf(2)(" algmakeintegral: dim=%d, denom=%Ps\n", n, Q_denom(mt0)); m = cgetg(n+1,t_MAT); for (i=1;i<=n;i++) gel(m,i) = mat2col(gel(mt,i),n,n); dbg_printf(2)(" computing order, dims m = %d x %d...\n", nbrows(m), lg(m)-1); P = QM_invimZ(m); dbg_printf(2)(" ...done.\n"); P = shallowmatconcat(mkvec2(col_ei(n,1),P)); P = hnf(P); Pi = RgM_inv(P); mt2 = change_Rgmultable(mt,P,Pi); if (maps) mt2 = mkvec3(mt2,Pi,P); /* mt2, mt->mt2, mt2->mt */ return gerepilecopy(av,mt2); } /** ORDERS **/ /** IDEALS **/ pari-2.11.2/src/modules/galpol.c0000644000175000017500000000625613326135265015056 0ustar billbill/* Copyright (C) 2000-2018 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" GEN galoisnbpol(long a) { GEN n; pariFILE *F; char *s = stack_malloc(strlen(pari_datadir) + 11 + 20 + 1); sprintf(s,"%s/galpol/%ld/nb", pari_datadir, a); F = pari_fopengz(s); if (!F) pari_err_FILE("galpol file",s); n = gp_read_stream(F->file); if (!n || typ(n)!=t_INT) pari_err_FILE("galpol file [incompatible]",s); pari_fclose(F); return n; } GEN galoisgetpol(long a, long b, long sig) { pariFILE *F; GEN V; const char *si; char *s; if (a<=0) pari_err_DOMAIN("galoisgetpol", "degree", "<=", gen_0, stoi(a)); if (b<0) pari_err_DOMAIN("galoisgetpol", "index", "<", gen_0, stoi(b)); if (!b) return galoisnbpol(a); switch(sig) { case 1: si="real"; break; case 2: if (a%2==0) { si="complex"; break; } pari_err_DOMAIN("galoisgetpol", "s", ">", gen_1, stoi(sig)); default: pari_err_FLAG("galoisgetpol"); return NULL; } s = pari_sprintf("%s/galpol/%ld/%ld/%s", pari_datadir, a,b,si); F = pari_fopengz(s); if (!F) { long n = itos(galoisnbpol(a)); if (b > n) pari_err_DOMAIN("galoisgetpol", "group index", ">", stoi(n), stoi(b)); else pari_err_FILE("galpol file", s); } pari_free(s); V = gp_read_stream(F->file); if (!V || typ(V)!=t_VEC) pari_err_FILE("galpol file", F->name); pari_fclose(F); return V; } GEN galoisgetgroup(long a, long b) { pariFILE *F; GEN V; char *s; if (a<=0) pari_err_DOMAIN("galoisgetgroup", "degree", "<=", gen_0, stoi(a)); if (b<0) pari_err_DOMAIN("galoisgetgroup", "index", "<", gen_0, stoi(b)); if (!b) return galoisnbpol(a); s = pari_sprintf("%s/galpol/%ld/%ld/group", pari_datadir, a,b); F = pari_fopengz(s); if (!F) { long n = itos(galoisnbpol(a)); if (b > n) pari_err_DOMAIN("galoisgetgroup", "group index", ">", stoi(n), stoi(b)); else pari_err_FILE("galpol file", s); } pari_free(s); V = gp_read_stream(F->file); if (!V || typ(V)!=t_VEC) pari_err_FILE("galpol file", F->name); pari_fclose(F); return V; } GEN galoisgetname(long a, long b) { pariFILE *F; GEN V; char *s; if (a<=0) pari_err_DOMAIN("galoisgetname", "degree", "<=", gen_0, stoi(a)); if (b<0) pari_err_DOMAIN("galoisgetname", "index", "<", gen_0, stoi(b)); s = pari_sprintf("%s/galpol/%ld/%ld/name", pari_datadir, a,b); F = pari_fopengz(s); if (!F) { long n = itos(galoisnbpol(a)); if (b > n) pari_err_DOMAIN("galoisgetname", "group index", ">", stoi(n), stoi(b)); else pari_err_FILE("galpol file", s); } pari_free(s); V = gp_read_stream(F->file); if (!V || typ(V)!=t_STR) pari_err_FILE("galpol file", F->name); pari_fclose(F); return V; } pari-2.11.2/src/modules/elldata.c0000644000175000017500000001506613326135265015205 0ustar billbill/* Copyright (C) 2005 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** INTERFACE TO JOHN CREMONA ELLIPTIC CURVES DATABASE **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" static long strtoclass(const char *s) { long c=0; while (*s && *s<='9') s++; if (!*s) return -1; while ('a'<=*s && *s<='z') c = 26*c + *(s++)-'a'; return c; } /*Take a curve name like "100a2" and set * f to the conductor, (100) * c to the isogeny class (in base 26), ("a" or 0) * i to the curve index (2). * return 0 if parse error. */ static int ellparsename(const char *s, long *f, long *c, long *i) { long j; *f=-1; *c=-1; *i=-1; if (*s<'0' || *s>'9') return 0; *f=0; for (j=0;j<10 && '0'<=*s && *s<='9';j++) *f=10**f+*(s++)-'0'; if (j==10) {*f=-1; return 0;} if (*s<'a' || *s>'z') return !*s; *c=0; for (j=0; j<7 && 'a'<=*s && *s<='z';j++) *c=26**c+*(s++)-'a'; if (j==7) {*c=-1; return 0;} if (*s<'0' || *s>'9') return !*s; *i=0; for (j=0; j<10 && '0'<=*s && *s<='9';j++) *i=10**i+*(s++)-'0'; if (j==10) {*i=-1; return 0;} return !*s; } /* Take an integer and convert it to base 26 */ static GEN ellrecode(long x) { GEN str; char *s; long d = 0, n = x; do { d++; n /= 26; } while (n); str = cgetg(nchar2nlong(d+1)+1, t_STR); s = GSTR(str); s[d] = 0; n = x; do { s[--d] = n%26 + 'a'; n /= 26; } while (n); return str; } GEN ellconvertname(GEN n) { switch(typ(n)) { case t_STR: { long f,i,c; if (!ellparsename(GSTR(n),&f,&c,&i)) pari_err_TYPE("ellconvertname", n); if (f<0 || c<0 || i<0) pari_err_TYPE("ellconvertname [incomplete name]", n); return mkvec3s(f,c,i); } case t_VEC: if (lg(n)==4) { pari_sp av = avma; GEN f=gel(n,1), c=gel(n,2), s=gel(n,3); if (typ(f)!=t_INT || typ(c)!=t_INT || typ(s)!=t_INT) pari_err_TYPE("ellconvertname",n); return gerepilecopy(av, shallowconcat1(mkvec3(f, ellrecode(itos(c)), s))); } /*fall through*/ } pari_err_TYPE("ellconvertname",n); return NULL; /*LCOV_EXCL_LINE*/ } static GEN ellcondfile(long f) { pari_sp av = avma; long n = f / 1000; char *s = stack_malloc(strlen(pari_datadir) + 12 + 20 + 1); pariFILE *F; GEN V; sprintf(s, "%s/elldata/ell%ld", pari_datadir, n); F = pari_fopengz(s); if (!F) pari_err_FILE("elldata file",s); avma = av; V = gp_read_stream(F->file); if (!V || typ(V)!=t_VEC ) pari_err_FILE("elldata file [read]",s); pari_fclose(F); return V; } /* return the vector of all curves of conductor f */ static int cmpi1(GEN x, GEN v) { return cmpii(x, gel(v,1)); } static GEN ellcondlist(long f) { pari_sp av = avma; GEN V = ellcondfile(f); long i = tablesearch(V, utoipos(f), &cmpi1); if (i) { GEN v = gel(V,i); return vecslice(v,2, lg(v)-1); } avma = av; return cgetg(1,t_VEC); } static GEN ellsearchbyname(GEN V, char *name) { GEN x; long j; for (j=1; j=2 ? gtos(gel(A,2)): -1; i = l>=3 ? gtos(gel(A,3)): -1; if (l>=3) A = ellconvertname(A); } else if (typ(A)==t_STR) { if (!ellparsename(GSTR(A),&f,&c,&i)) pari_err_TYPE("ellsearch",A); } else { pari_err_TYPE("ellsearch",A); return NULL; } if (f <= 0) pari_err_DOMAIN("ellsearch", "conductor", "<=", gen_0,stoi(f)); V = ellcondlist(f); if (c >= 0) V = (i < 0)? ellsearchbyclass(V,c): ellsearchbyname(V, GSTR(A)); return gerepilecopy(av, V); } GEN ellsearchcurve(GEN name) { pari_sp ltop=avma; long f, c, i; if (!ellparsename(GSTR(name),&f,&c,&i)) pari_err_TYPE("ellsearch",name); if (f<0 || c<0 || i<0) pari_err_TYPE("ellsearch [incomplete name]", name); return gerepilecopy(ltop, ellsearchbyname(ellcondlist(f), GSTR(name))); } GEN ellidentify(GEN E) { pari_sp ltop=avma; long j; GEN V, M, G, N; checkell_Q(E); G = ellglobalred(E); N = gel(G,1); V = ellcondlist(itos(N)); M = ellchangecurve(vecslice(E,1,5),gel(G,2)); for (j=1; jb) break; for(k=2; k 1 to be factored, we throw in a small odd and * squarefree multiplier k so as to make kN congruent 1 mod 4 and to have * many small primes over which X^2 - kN splits. We compute a factor base * FB of such primes, and then essentially look for values x0 such that * Q0(x0) = x0^2 - kN can be decomposed over this factor base, up to a * possible factor dividing k and a possible "large prime". Relations * involving the latter can be combined into full relations (working mod N * now) which don't, and full relations, by Gaussian elimination over the * 2-element field for the exponent vectors, will finally lead us to an * expression X^2 - Y^2 divisible by N and hopefully to a nontrivial * splitting when we compute gcd(X +- Y, N). Note that this can never * split prime powers. (Any odd prime dividing the X - Y factor, say, will * divide it to the same power as it divides N.) * * Candidates x0 are found by sieving along arithmetic progressions modulo * the small primes in the factor base, and evaluation of candidates picks * out those x0 where many of these APs happen to coincide, resulting in a * highly divisible Q0(x0). * * The Multi-Polynomial version improves this by choosing a modest subset of * factor base primes and forcing these to divide Q0(x). Let A be the product * of the chosen primes, and write Q(x) = Q0(2Ax + B) = (2Ax + B)^2 - kN = * 4A(Ax^2 + Bx + C), where B has been suitably chosen. For each A, there * are 2^omega_A possible values for B when A is the product of omega_A * distinct primes, but we'll use only half of these, since the other half * is more easily covered by exploiting the symmetry x <-> -x of the original * quadratic. The "Self-Initializating" bit refers to the fact that switching * from one B to the next can be done very fast, whereas switching to the * next A involves some recomputation from scratch. (C is never needed * explicitly except for debug diagnostics.) Thus we can very quickly run * through an entire "cohort" of polynomials sharing the same A. * * The sieve now ranges over values x0 such that |x0| < M (we use x = x0 + M * as the non-negative array subscript). The coefficients A are chosen so * that A*M is approximately sqrt(kN). Then |B| will be bounded by about * (j+4)*A, and |C| = -C will be about (M/4)*sqrt(kN), so Q(x0)/(4A) will * take values roughly between -|C| and 3|C|. * * There are numerous refinements to this basic outline (e.g. it is more * efficient to _not_ use the very smallest primes in the FB for sieving, * incorporating them only after selecting candidates). The substition of * 2Ax+B into X^2 - kN, with odd B, forces 2 to occur; when kN is 1 mod 8, * it will always occur at least to the 3rd power; when kN = 5 mod 8, it * will always occur exactly to the 2nd power. We never sieve on 2 and we * always pull out the power of 2 directly (which is easy, of course). * The prime factor(s) of k will show up whenever 2Ax + B has a factor in * common with k; we don't sieve on these either but can easily recognize * them in a candidate. */ #include #include "pari.h" #include "paripriv.h" static char * paristrtok_r(char *str, const char *delim, char **saveptr) { char *res; if (!str) str = *saveptr; str += strspn(str, delim); if (!*str) return NULL; res = str; str += strcspn(str, delim); if (*str) *str++ = 0; *saveptr = str; return res; } /** DEBUG **/ /* #define MPQS_DEBUG_VERBOSE 1 */ /* histograms are pretty, but don't help performance after all (see below) */ /* #define MPQS_USE_HISTOGRAMS */ #include "mpqs.h" /*********************************************************************/ /** **/ /** INITIAL SIZING **/ /** **/ /*********************************************************************/ /* number of decimal digits of argument - for parameter choosing and for * diagnostics */ static long decimal_len(GEN N) { pari_sp av = avma; long d = strlen(itostr(N)); avma = av; return d; } /* To be called after choosing k and putting kN into the handle: * Pick up the requested parameter set for the given size of kN in decimal * digits and fill in various fields in the handle. Return 0 when kN is * too large, 1 when we're ok. */ static int mpqs_set_parameters(mpqs_handle_t *h) { long i; const mpqs_parameterset_t *P; h->digit_size_kN = decimal_len(h->kN); if (h->digit_size_kN <= 9) i = 0; else if (h->digit_size_kN > MPQS_MAX_DIGIT_SIZE_KN) return 0; else i = h->digit_size_kN - 9; /* (cf PARI bug#235) the following has always been, and will remain, * a moving target... increased thresholds from 64, 80 to 79, 86 * respectively --GN20050601. Note that the new values correspond to * kN having >= 86 or >= 95 decimal digits, respectively. Note also * that the current sizing parameters for 90 or more digits are based * on 100% theory and 0% practice. */ if (i >= 79) pari_warn(warner, "MPQS: factoring this number will take %s hours:\nN = %Ps", i >= 86 ? "many": "several", h->N); if (DEBUGLEVEL >= 5) { err_printf("MPQS: kN = %Ps\n", h->kN); err_printf("MPQS: kN has %ld decimal digits\n", h->digit_size_kN); } P = &(mpqs_parameters[i]); h->tolerance = P->tolerance; h->lp_scale = P->lp_scale; /* make room for prime factors of k if any: */ h->size_of_FB = P->size_of_FB + h->_k->omega_k; /* for the purpose of Gauss elimination etc., prime factors of k behave * like real FB primes, so take them into account when setting the goal: */ h->target_no_rels = (h->size_of_FB >= 200 ? h->size_of_FB + 70 : (mpqs_int32_t)(h->size_of_FB * 1.35)); h->M = P->M; h->omega_A = P->omega_A; h->no_B = 1UL << (P->omega_A - 1); h->pmin_index1 = P->pmin_index1; /* certain subscripts into h->FB should also be offset by omega_k: */ h->index0_FB = 3 + h->_k->omega_k; /* following are converted from % to parts per thousand: */ h->first_sort_point = 10 * P->first_sort_point; h->sort_pt_interval = 10 * P->sort_pt_interval; if (DEBUGLEVEL >= 5) { double mb = (h->size_of_FB + 1)/(8.*1048576.) * h->target_no_rels; err_printf("\t(estimated memory needed: %4.1fMBy)\n", mb); } return 1; } /*********************************************************************/ /** **/ /** OBJECT HOUSEKEEPING **/ /** **/ /*********************************************************************/ /* The sub-constructors for the pieces of the handle will be called in the * same order as their appearance here, and the later ones in part rely on * the earlier ones having filled in some fields. * There's a single destructor to handle all cleanup at the end (except * for mpqs() itself resetting avma). */ /* main handle constructor */ static mpqs_handle_t * mpqs_handle_ctor(GEN N) { mpqs_handle_t *h = (mpqs_handle_t *) pari_calloc(sizeof(mpqs_handle_t)); h->N = N; #ifdef MPQS_DEBUG_VERBOSE err_printf("MPQS DEBUG: created handle @0x%p\n", (void *)h); #endif return h; } /* factor base constructor. Really a home-grown memalign(3c) underneath. * We don't want FB entries to straddle L1 cache line boundaries, and * malloc(3c) only guarantees alignment adequate for all primitive data * types of the platform ABI - typically to 8 or 16 byte boundaries. * Also allocate the inv_A_H array. * The FB array pointer is returned for convenience */ static mpqs_FB_entry_t * mpqs_FB_ctor(mpqs_handle_t *h) { /* leave room for slots 0, 1, and sentinel slot at the end of the array */ long size_FB_chunk = (h->size_of_FB + 3) * sizeof(mpqs_FB_entry_t); /* like FB, except this one does not have a sentinel slot at the end */ long size_IAH_chunk = (h->size_of_FB + 2) * sizeof(mpqs_inv_A_H_t); char *fbp = (char*)pari_malloc(size_FB_chunk + 64); char *iahp = (char*)pari_malloc(size_IAH_chunk + 64); long fbl, iahl; h->FB_chunk = (void *)fbp; h->invAH_chunk = (void *)iahp; /* round up to next higher 64-bytes-aligned address */ fbl = (((long)fbp) + 64) & ~0x3FL; /* and put the actual array there */ h->FB = (mpqs_FB_entry_t *)fbl; iahl = (((long)iahp) + 64) & ~0x3FL; h->inv_A_H = (mpqs_inv_A_H_t *)iahl; return (mpqs_FB_entry_t *)fbl; } /* sieve array constructor; also allocates the candidates array, the * histograms, and temporary storage for relations under construction */ static void mpqs_sieve_array_ctor(mpqs_handle_t *h) { long size = (h->M << 1) + 1; mpqs_int32_t size_of_FB = h->size_of_FB; h->sieve_array = (unsigned char *) pari_malloc(size * sizeof(unsigned char)); h->sieve_array_end = h->sieve_array + size - 2; h->sieve_array_end[1] = 255; /* sentinel */ h->candidates = (long *)pari_malloc(MPQS_CANDIDATE_ARRAY_SIZE * sizeof(long)); /* Room needed for string representation of a relation - worst case: * + leading " 1 1" * + trailing " 0\n" with final NUL character * + in between up to size_of_FB pairs each consisting of an exponent, a * subscript into FB, and two spaces. * Subscripts into FB fit into 5 digits, and exponents fit into 3 digits * with room to spare -- anything needing 3 or more digits for the * subscript must come with an exponent of at most 2 digits. Moreover the * product of the first 58 primes is larger than 10^110 (and the righthand * sides of proto-relations are much smaller than kN: on the order of * M*sqrt(kN)), so there cannot be more than 60 pairs in all, even if * size_of_FB > 10^5. --GN */ /* whereas mpqs_self_init() uses size_of_FB+1, we just use the size as * it is, not counting FB[1], to start off the following estimate */ if (size_of_FB > 60) size_of_FB = 60; h->relations = (char *) pari_malloc((8 + size_of_FB * 9) * sizeof(char)); /* and for tracking which primes occur in the current relation: */ h->relaprimes = (long *) pari_malloc((size_of_FB << 1) * sizeof(long)); #ifdef MPQS_USE_HISTOGRAMS /* histograms to be used only when kN isn't very small */ if (h->size_of_FB > MPQS_MIN_SIZE_FB_FOR_HISTO) { h->do_histograms = 1; h->histo_full = (long *) pari_calloc(128 * sizeof(long)); h->histo_lprl = (long *) pari_calloc(128 * sizeof(long)); h->histo_drop = (long *) pari_calloc(128 * sizeof(long)); } #endif } /* mpqs() calls the following (after recording avma) to allocate GENs for * the current polynomial and self-initialization scratchpad data on the * PARI stack. This space is released by mpqs() itself at the end. */ static void mpqs_poly_ctor(mpqs_handle_t *h) { mpqs_int32_t i; long size_per = h->omega_A * sizeof(mpqs_per_A_prime_t); h->per_A_pr = (mpqs_per_A_prime_t *) pari_calloc(size_per); /* Sizing: A is the product of omega_A primes, each well below word * size. * |B| is bounded by (omega_A + 4) * A, so can have at most one word * more, and that's generous. * |C| is less than A*M^2, so can take at most two words more than A. * The array H holds residues modulo A, so the same size as used for A * is sufficient. */ h->A = cgeti(h->omega_A + 2); h->B = cgeti(h->omega_A + 3); #ifdef MPQS_DEBUG h->C = cgeti(h->omega_A + 4); #endif for (i = 0; i < h->omega_A; i++) h->per_A_pr[i]._H = cgeti(h->omega_A + 2); /* the handle starts out all zero, so in particular bin_index and index_i * are initially 0. * TODO: index_j currently initialized in mqps() but this is going to * change. */ } /* main handle destructor, also cleans up all other allocated pieces * (except for stuff created on the PARI stack which the caller should * deal with by resetting avma) */ static void mpqs_handle_dtor(mpqs_handle_t *h) { #define myfree(x) if(x) pari_free((void*)x) myfree((h->per_A_pr)); myfree((h->relaprimes)); myfree(h->relations); #ifdef MPQS_USE_HISTOGRAMS myfree((h->histo_drop)); myfree((h->histo_lprl)); myfree((h->histo_full)); #endif myfree((h->candidates)); myfree((h->sieve_array)); myfree((h->invAH_chunk)); myfree((h->FB_chunk)); myfree(h); } /* TODO: relationsdb handle */ /*********************************************************************/ /** **/ /** FACTOR BASE SETUP **/ /** **/ /*********************************************************************/ /* fill in the best-guess multiplier k for N. We force kN = 1 mod 4. * Caller should proceed to fill in kN */ static ulong mpqs_find_k(mpqs_handle_t *h) { const pari_sp av = avma; const long N_mod_8 = mod8(h->N), N_mod_4 = N_mod_8 & 3; forprime_t S; struct { const mpqs_multiplier_t *_k; long np; /* number of primes in factorbase so far for this k */ double value; /* the larger, the better */ } cache[MPQS_POSSIBLE_MULTIPLIERS]; ulong p, i, nbk; for (i = nbk = 0; i < numberof(cand_multipliers); i++) { const mpqs_multiplier_t *cand_k = &cand_multipliers[i]; long k = cand_k->k; double v; if ((k & 3) != N_mod_4) continue; /* want kN = 1 (mod 4) */ v = -0.35 * log2((double)k); if ((k & 7) == N_mod_8) v += M_LN2; /* kN = 1 (mod 8) */ cache[nbk].np = 0; cache[nbk]._k = cand_k; cache[nbk].value = v; if (++nbk == MPQS_POSSIBLE_MULTIPLIERS) break; /* enough */ } /* next test is an impossible situation: kills spurious gcc-5.1 warnings * "array subscript is above array bounds" */ if (nbk > MPQS_POSSIBLE_MULTIPLIERS) nbk = MPQS_POSSIBLE_MULTIPLIERS; u_forprime_init(&S, 2, ULONG_MAX); while ( (p = u_forprime_next(&S)) ) { ulong Np = umodiu(h->N, p); long kroNp, seen = 0; if (!Np) return p; kroNp = krouu(Np, p); for (i = 0; i < nbk; i++) { if (cache[i].np > MPQS_MULTIPLIER_SEARCH_DEPTH) continue; seen++; if (krouu(cache[i]._k->k % p, p) == kroNp) /* kronecker(k*N, p)=1 */ { cache[i].value += log2((double) p)/p; cache[i].np++; } } if (!seen) break; /* we're gone through SEARCH_DEPTH primes for all k */ } if (!p) pari_err_OVERFLOW("mpqs_find_k [ran out of primes]"); { long best_i = 0; double v = cache[0].value; for (i = 1; i < nbk; i++) if (cache[i].value > v) { best_i = i; v = cache[i].value; } h->_k = cache[best_i]._k; avma = av; return 0; } } /******************************/ /* Create a factor base of 'size' primes p_i such that legendre(k*N, p_i) != -1 * We could have shifted subscripts down from their historical arrangement, * but this seems too risky for the tiny potential gain in memory economy. * The real constraint is that the subscripts of anything which later shows * up at the Gauss stage must be nonnegative, because the exponent vectors * there use the same subscripts to refer to the same FB entries. Thus in * particular, the entry representing -1 could be put into FB[0], but could * not be moved to FB[-1] (although mpqs_FB_ctor() could be easily adapted * to support negative subscripts).-- The historically grown layout is: * FB[0] is unused. * FB[1] is not explicitly used but stands for -1. * FB[2] contains 2 (always). * Before we are called, the size_of_FB field in the handle will already have * been adjusted by _k->omega_k, so there's room for the primes dividing k, * which when present will occupy FB[3] and following. * The "real" odd FB primes begin at FB[h->index0_FB]. * FB[size_of_FB+1] is the last prime p_i. * FB[size_of_FB+2] is a sentinel to simplify some of our loops. * Thus we allocate size_of_FB+3 slots for FB. * * If a prime factor of N is found during the construction, it is returned * in f, otherwise f = 0. */ /* returns the FB array pointer for convenience */ static mpqs_FB_entry_t * mpqs_create_FB(mpqs_handle_t *h, ulong *f) { const pari_sp av = avma; mpqs_int32_t size = h->size_of_FB; long i; mpqs_uint32_t k = h->_k->k; mpqs_FB_entry_t *FB; forprime_t S; FB = mpqs_FB_ctor(h); FB[2].fbe_p = 2; /* the fbe_logval and the fbe_sqrt_kN for 2 are never used */ FB[2].fbe_flags = MPQS_FBE_CLEAR; (void)u_forprime_init(&S, 3, ULONG_MAX); /* the first loop executes h->_k->omega_k = 0, 1, or 2 times */ for (i = 3; i < h->index0_FB; i++) { mpqs_uint32_t kp = (ulong)h->_k->kp[i-3]; if (MPQS_DEBUGLEVEL >= 7) err_printf(",<%lu>", (ulong)kp); FB[i].fbe_p = kp; /* we *could* flag divisors of k here, but so far I see no need, * and no flags bit has been assigned for the purpose */ FB[i].fbe_flags = MPQS_FBE_CLEAR; FB[i].fbe_flogp = (float) log2((double) kp); FB[i].fbe_sqrt_kN = 0; } /* now i == h->index0_FB */ while (i < size + 2) { ulong p = u_forprime_next(&S); if (p > k || k % p) { ulong kN_mod_p = umodiu(h->kN, p); long kr = krouu(kN_mod_p, p); if (kr != -1) { if (kr == 0) { *f = p; return FB; } FB[i].fbe_p = (mpqs_uint32_t) p; FB[i].fbe_flags = MPQS_FBE_CLEAR; /* dyadic logarithm of p; single precision suffices */ FB[i].fbe_flogp = (float) log2((double)p); /* cannot yet fill in fbe_logval because the scaling multiplier * depends on the largest prime in FB, as yet unknown */ /* x such that x^2 = kN (mod p_i) */ FB[i++].fbe_sqrt_kN = (mpqs_uint32_t)Fl_sqrt(kN_mod_p, p); } } } avma = av; if (MPQS_DEBUGLEVEL >= 7) { err_printf("MPQS: FB [-1,2"); for (i = 3; i < h->index0_FB; i++) err_printf(",<%lu>", FB[i].fbe_p); for (; i < size + 2; i++) err_printf(",%lu", FB[i].fbe_p); err_printf("]\n"); } FB[i].fbe_p = 0; /* sentinel */ h->largest_FB_p = FB[i-1].fbe_p; /* at subscript size_of_FB + 1 */ /* locate the smallest prime that will be used for sieving */ for (i = h->index0_FB; FB[i].fbe_p != 0; i++) if (FB[i].fbe_p >= h->pmin_index1) break; h->index1_FB = i; /* with our parameters this will never fall of the end of the FB */ *f = 0; return FB; } /*********************************************************************/ /** **/ /** MISC HELPER FUNCTIONS **/ /** **/ /*********************************************************************/ /* Effect of the following: multiplying the base-2 logarithm of some * quantity by log_multiplier will rescale something of size * log2 ( sqrt(kN) * M / (largest_FB_prime)^tolerance ) * to 232. Note that sqrt(kN) * M is just A*M^2, the value our polynomials * take at the outer edges of the sieve interval. The scale here leaves * a little wiggle room for accumulated rounding errors from the approximate * byte-sized scaled logarithms for the factor base primes which we add up * in the sieving phase.-- The threshold is then chosen so that a point in * the sieve has to reach a result which, under the same scaling, represents * log2 ( sqrt(kN) * M / (largest_FB_prime)^tolerance ) * in order to be accepted as a candidate. */ /* The old formula was... * log_multiplier = * 127.0 / (0.5 * log2 (handle->dkN) * + log2((double)M) * - tolerance * log2((double)handle->largest_FB_p) * ); * and we used to use this with a constant threshold of 128. */ /* NOTE: We used to divide log_multiplier by an extra factor 2, and in * compensation we were multiplying by 2 when the fbe_logp fields were being * filled in, making all those bytes even. Tradeoff: the extra bit of * precision is helpful, but interferes with a possible sieving optimization * (artifically shift right the logp's of primes in A, and just run over both * arithmetical progressions (which coincide in this case) instead of * skipping the second one, to avoid the conditional branch in the * mpqs_sieve() loops). We could still do this, but might lose a little bit * accuracy for those primes. Probably no big deal. */ static void mpqs_set_sieve_threshold(mpqs_handle_t *h) { mpqs_FB_entry_t *FB = h->FB; long i; double log_maxval; double log_multiplier; h->l2sqrtkN = 0.5 * log2(h->dkN); h->l2M = log2((double)h->M); log_maxval = h->l2sqrtkN + h->l2M - MPQS_A_FUDGE; log_multiplier = 232.0 / log_maxval; h->sieve_threshold = (unsigned char) (log_multiplier * (log_maxval - h->tolerance * log2((double)h->largest_FB_p) ) ) + 1; /* That "+ 1" really helps - we may want to tune towards somewhat smaller * tolerances (or introduce self-tuning one day)... */ /* If this turns out to be <128, scream loudly. * That means that the FB or the tolerance or both are way too * large for the size of kN. (Normally, the threshold should end * up in the 150...170 range.) */ if (h->sieve_threshold < 128) { h->sieve_threshold = 128; pari_warn(warner, "MPQS: sizing out of tune, FB size or tolerance\n\ttoo large"); } /* Now fill in the byte-sized approximate scaled logarithms of p_i */ if (DEBUGLEVEL >= 5) { err_printf("MPQS: computing logarithm approximations for p_i in FB\n"); } for (i = h->index0_FB; i < h->size_of_FB + 2; i++) { FB[i].fbe_logval = (unsigned char) (log_multiplier * FB[i].fbe_flogp); } } /* Given the partially populated handle, find the optimum place in the FB * to pick prime factors for A from. The lowest admissible subscript is * index0_FB, but unless kN is very small, we stay away a bit from that. * The highest admissible is size_of_FB + 1, where the largest FB prime * resides. The ideal corner is about (sqrt(kN)/M) ^ (1/omega_A), * so that A will end up of size comparable to sqrt(kN)/M; experimentally * it seems desirable to stay slightly below this. Moreover, the selection * of the individual primes happens to err on the large side, for which we * compensate a bit, using the (small positive) quantity MPQS_A_FUDGE. * We rely on a few auxiliary fields in the handle to be already set by * mqps_set_sieve_threshold() before we are called. * Return 1 on success, and 0 otherwise. */ static int mpqs_locate_A_range(mpqs_handle_t *h) { /* i will be counted up to the desirable index2_FB + 1, and omega_A is never * less than 3, and we want * index2_FB - (omega_A - 1) + 1 >= index0_FB + omega_A - 3, * so: */ long i = h->index0_FB + 2*(h->omega_A) - 4; double l2_target_pA; mpqs_FB_entry_t *FB = h->FB; h->l2_target_A = (h->l2sqrtkN - h->l2M - MPQS_A_FUDGE); l2_target_pA = h->l2_target_A / h->omega_A; /* find the sweet spot, normally shouldn't take long */ while ((FB[i].fbe_p != 0) && (FB[i].fbe_flogp <= l2_target_pA)) i++; #ifdef MPQS_DEBUG_LOCATE_A_RANGE err_printf("MPQS DEBUG: omega_A=%ld, index0=%ld, i=%ld\n", (long) h->omega_A, (long) h->index0_FB, i); #endif /* check whether this hasn't walked off the top end... */ /* The following should actually NEVER happen. */ if (i > h->size_of_FB - 3) { /* this isn't going to work at all. */ pari_warn(warner, "MPQS: sizing out of tune, FB too small or\n\tway too few primes in A"); return 0; } h->index2_FB = i - 1; #ifdef MPQS_DEBUG_LOCATE_A_RANGE err_printf("MPQS DEBUG: index2_FB = %ld\n", i - 1); #endif /* GN20050723 * assert: index0_FB + (omega_A - 3) [the lowest FB subscript eligible to * be used in picking primes for A] plus (omega_A - 2) does not exceed * index2_FB [the subscript from which the choice of primes for A starts, * putting omega_A - 1 of them at or below index2_FB, and the last and * largest one above, cf. mpqs_si_choose_primes() below]. * Moreover, index2_FB indicates the last prime below the ideal size, unless * (when kN is very small) the ideal size was too small to use. */ return 1; } /*********************************************************************/ /** **/ /** HISTOGRAMS AND THRESHOLD FEEDBACK **/ /** **/ /*********************************************************************/ #ifdef MPQS_USE_HISTOGRAMS /* The histogram-related code is left in this file, but all under the * above #ifdef, and disabled by default. I'm finding that: * - merely keeping the numbers updated in mpqs_eval_cand() below (and * keeping the "negligible" 1.5 or 3KBys' worth of extra arrays in use) * causes us to run quite noticeably slower: 8-10% for a 73-digit number, * - mpqs_eval_cand() has already become so much faster than it used to be * that raising the threshold to get rid of many low-valued unpromising * candidates does not save any significant time, and even losing a pretty * small number of additional LP relations actually harms us by lowering * the efficiency of LP relation combining. * (The first point might be due merely to code bloat and less effective * compiler optimizations - I'm not sure about that.) * Just for getting a visual impression of how the sieve is performing, * however, this is nice to have available. Just turn on the #define at * the top of the file and recompile with it. --GN2005-02-03 */ /* histogram evaluation happens very infrequently if at all. So we'll do * all the adding and putting-into-relation-with here, while mpqs_eval_cand() * merely bumps one cell at a time and doesn't keep running totals. */ static void mpqs_print_histo(mpqs_handle_t *h) { long i, tot = 0; if (!h->do_histograms) return; err_printf("\nMPQS: values from sieve vs. distribution of evaluated candidates:\n"); err_printf(" val ___full __lprel ___none ___total\n"); for (i = 127; i >= 0; i--) { long rowtot = h->histo_full[i] + h->histo_lprl[i] + h->histo_drop[i]; tot += rowtot; if ((rowtot > 0) || (i == h->sieve_threshold)) err_printf("%s[%3d] %7ld %7ld %7ld %8ld\n", i + 128 == h->sieve_threshold ? "^-" : " ", i + 128, h->histo_full[i], h->histo_lprl[i], h->histo_drop[i], rowtot); } err_printf(" (total evaluated candidates: %ld)\n", tot); } /* evaluation/feedback heuristics: * First of all, refuse to draw any conclusions unless and until there's * enough material to be statistically significant. * Second, after sifting through the histo arrays, the new threshold is * set to the minimum of the following three quantities: * - the position where going down from the top value the histo_full * totals first exceed 100 - MPQS_HISTO_FREL_QUANTILE percent of all * full relations found so far by direct sieving. (I.e. if the quantile * is 4, we want to keep all rows which account for 96% of all frels * obtained from the sieve. Note that once we increase the threshold, * further counts will be biased against smaller values; but we normally * don't expect to do many adjustments.) * - the position where, going down from the top towards smaller values, * the cumulative number of useless candidates in histo_drop first exceeds * MPQS_HISTO_DROP_LIMIT times the number of useful ones. I.e. when that * limit is 2, we're aiming for at least about 1/3 of all candidates coming * from the sieve to result in usable relations. * - one less than the position where the histo_lprl count first falls below * MPQS_HISTO_LPREL_BASEFLOW times the number of useless candidates. This * one will be capable of lowering the current threshold (but never below * 128). * FIXME: For Double Large Prime mode, this will need to be seriously reworked. */ /* This function returns 1 when it actually did something and decided on a * good threshold (although possibly the same as it was before), -1 when * there was nothing to do and never will be ("don't call us again"), 0 * when the caller should retry somewhat later. Note that mpqs() already * knows the total number of candidates generated so far (from the return * values of mpqs_eval_sieve()), and won't call us too early; but we also * insist on minimal standards for the column sums. Conversely when we ever * lower the threshold, we ask for a re-evaluation later on. * NB With the present accounting, once the threshold has been raised, it * won't ever be lowered again, since the increasing counts above it will * totally swamp the few earlier measurements below which can no longer * grow. So we might chop off those accumulating loops at the current sieve * threshold. */ static int mpqs_eval_histograms(mpqs_handle_t *h) { long tot_full = 0, tot_lprl = 0, tot_drop = 0, total = 0; long target_full, i; int th_full, th_base, th_drop; int th = h->sieve_threshold - 128; if (!h->do_histograms) return -1; /* first compute column sums */ for (i = 127; i >= 0; i--) { tot_full += h->histo_full[i]; tot_lprl += h->histo_lprl[i]; tot_drop += h->histo_drop[i]; } total = tot_full + tot_lprl + tot_drop; if ((total < MPQS_MIN_CANDS_FOR_HISTO) || (tot_full < MPQS_MIN_FRELS_FOR_HISTO)) return 0; /* too early to call the race */ th_full = th_drop = th_base = -1; /* find the full relations quantile point */ target_full = tot_full - (tot_full * MPQS_HISTO_FREL_QUANTILE) / 100.; tot_full = 0; for (i = 127; i >= th; i--) { if ((tot_full += h->histo_full[i]) >= target_full) { th_full = i; break; } } /* find the "lp relations baseflow" point */ for (i = 127; i >= th; i--) { if (h->histo_lprl[i] + 1 < MPQS_HISTO_LPREL_BASEFLOW * h->histo_drop[i]) { th_base = i; break; } } /* find the wastefulness point */ tot_lprl = 0; tot_drop = 0; for (i = 127; i >= th; i--) { tot_lprl += h->histo_full[i] + h->histo_lprl[i]; tot_drop += h->histo_drop[i]; if (tot_drop > MPQS_HISTO_DROP_LIMIT * (tot_lprl + 1)) { th_drop = i; break; } } /* if these loops found nothing, then th_(full|base|drop) will still be -1. * We won't tighten the sieve, but th_base would tell us we should loosen * it (reluctantly). */ if (MPQS_DEBUGLEVEL >= 5) { mpqs_print_histo(h); if (th_full >= 0) err_printf("MPQS: threshold estimate for full rels: %d\n", th_full + 128); if (th_drop >= 0) err_printf("MPQS: threshold estimate for useful candidates: %d\n", th_drop + 128); } /* any reason to open up the sieve? wait until a minimal number of lprels * at the threshold has been seen before going down... */ if ((th > 0) && (th_base <= th) && (h->histo_lprl[th] > (MPQS_MIN_FRELS_FOR_HISTO * 3.5)) ) { h->sieve_threshold = th + 127; if (MPQS_DEBUGLEVEL >= 4) err_printf("MPQS: loosening sieve tolerance, new threshold %d\n", h->sieve_threshold); return 0; /* this should be re-examined after a bit */ } /* otherwise, any reason to tighten it? */ th = (th_full < th_drop ? th_full : th_drop) + 128; if (th > h->sieve_threshold) { h->sieve_threshold = th; if (MPQS_DEBUGLEVEL >= 4) err_printf("MPQS: tightening sieve tolerance, new threshold %d\n", h->sieve_threshold); } /* maybe also loosen it if th_drop persistently stays below th... */ return 1; /* wait a good while before rechecking */ } #endif /*********************************************************************/ /** **/ /** RELATIONS AS STRINGS AND RELATIONS DATABASE **/ /** **/ /*********************************************************************/ /* determines a unique name for a file based on a short nickname * name is allocated on the stack */ static char * mpqs_get_filename(char *dir, const char *s) { char *buf = stack_malloc(strlen(dir) + strlen(s) + 2); #if defined(__EMX__) sprintf(buf, "%s\\%s", dir,s); #else sprintf(buf, "%s/%s", dir,s); #endif return buf; } /* compares two `large prime' relations according to their first element * (the large prime itself). */ static int mpqs_relations_cmp(const void *a, const void *b) { char **sa = (char**) a; char **sb = (char**) b; long qa = strtol(*sa, NULL, 10); long qb = strtol(*sb, NULL, 10); /* atol() isn't entirely portable for the Full Relations case where the strings of digits are too long to fit into a long --GN */ if (qa < qb) return -1; else if (qa > qb) return 1; else return strcmp(*sa, *sb); } static void pari_fputs(char *s, pariFILE *f) { if (fputs(s, f->file) < 0) pari_err_FILE("output file [fputs]", f->name); } #define min_bufspace 120UL /* use new buffer when < min_bufspace left */ #define buflist_size 1024 /* size of list-of-buffers blocks */ /* Given a file "filename" containing full or `large prime' relations, * rearrange the file so that relations are sorted by their first elements. * Works also for sorting full relations. Works in memory, discards duplicate * lines, and overwrites the original file. */ static long mpqs_sort_lp_file(char *filename) { pariFILE *pTMP; FILE *TMP; char *old_s, *buf, *cur_line; char **sort_table, **buflist, **next_buflist, **buflist_head; long i, j, count; size_t length, bufspace; pari_sp av=avma; buflist_head = (char**) stack_malloc(buflist_size * sizeof(char*)); buflist = buflist_head; *buflist++ = NULL; /* flag this as last and only buflist block */ /* extra blocks may be allocated as needed and linked ahead of * buflist_head. NB: whilst extra buflist blocks might have been * needed when we were still sorting entire FREL files (more than 1023 * buffers, corresponding to about 20000 lines of ~200 characters), they * should never be touched now that we only sort LPNEW and FNEW files, which * are rather shorter. But the code might as well stay around for future * upgrades to handling even larger numbers (and factor bases and thus * relations files). It costs one comparison per buffer allocation. --GN */ pTMP = pari_fopen_or_fail(filename, READ); TMP = pTMP->file; /* get first buffer and read first line, if any, into it */ buf = (char*) pari_malloc(MPQS_STRING_LENGTH * sizeof(char)); cur_line = buf; bufspace = MPQS_STRING_LENGTH; if (fgets(cur_line, bufspace, TMP) == NULL) { /* file empty */ pari_free(buf); pari_fclose(pTMP); avma = av; return 0; } /* enter first buffer into buflist */ *buflist++ = buf; /* can't overflow the buflist block */ length = strlen(cur_line) + 1; /* count the \0 byte as well */ bufspace -= length; sort_table = (char**)avma; /* at start of loop, one line from the file is sitting in cur_line inside buf, * the next will go into cur_line + length, and there's room for bufspace * further characters in buf. The loop reads another line if one exists, and * if this overruns the current buffer, it allocates a fresh one --GN */ for (i=0, sort_table--; /* until end of file */; i++, sort_table--) { /* sort_table is allocated on the stack, 0x100 cells at a time. Hence the * stack must be left alone in the rest of the loop to keep the array * connected. In particular, buffers can't be new_chunk'ed */ if ((i & 0xff) == 0) (void)new_chunk(0x100); *sort_table = cur_line; cur_line += length; /* if little room is left, allocate a fresh buffer before attempting to * read a line, and remember to free it if no further line is forthcoming. * This avoids some copying of partial lines --GN */ if (bufspace < min_bufspace) { if (MPQS_DEBUGLEVEL >= 7) err_printf("MQPS: short of space -- another buffer for sorting\n"); buf = (char*) pari_malloc(MPQS_STRING_LENGTH * sizeof(char)); cur_line = buf; bufspace = MPQS_STRING_LENGTH; if (fgets(cur_line, bufspace, TMP) == NULL) { pari_free(buf); break; } /* remember buffer for later deallocation */ if (buflist - buflist_head >= buflist_size) { /* need another buflist block */ next_buflist = (char**) pari_malloc(buflist_size * sizeof(char*)); *next_buflist = (char*)buflist_head; /* link */ buflist_head = next_buflist; buflist = buflist_head + 1; } *buflist++ = buf; length = strlen(cur_line) + 1; bufspace -= length; continue; } /* normal case: try fitting another line into the current buffer */ if (fgets(cur_line, bufspace, TMP) == NULL) break; /* none exists */ length = strlen(cur_line) + 1; bufspace -= length; /* check whether we got the entire line or only part of it */ if (bufspace == 0 && cur_line[length-2] != '\n') { size_t lg1; if (MPQS_DEBUGLEVEL >= 7) err_printf("MQPS: line wrap -- another buffer for sorting\n"); buf = (char*) pari_malloc(MPQS_STRING_LENGTH * sizeof(char)); /* remember buffer for later deallocation */ if (buflist - buflist_head >= buflist_size) { /* need another buflist block */ next_buflist = (char**)pari_malloc(buflist_size * sizeof(char*)); *next_buflist = (char*)buflist_head; /* link */ buflist_head = next_buflist; buflist = buflist_head + 1; } *buflist++ = buf; /* copy what we've got to the new buffer */ (void)strcpy(buf, cur_line); /* cannot overflow */ cur_line = buf + length - 1; /* point at the \0 byte */ bufspace = MPQS_STRING_LENGTH - length + 1; /* read remainder of line */ if (fgets(cur_line, bufspace, TMP) == NULL) pari_err_FILE("TMP file [fgets]", pTMP->name); lg1 = strlen(cur_line); length += lg1; /* we already counted the \0 once */ bufspace -= (lg1 + 1); /* but here we must take it into account */ cur_line = buf; /* back up to the beginning of the line */ } } /* for */ pari_fclose(pTMP); /* sort the whole lot in place by swapping pointers */ qsort(sort_table, i, sizeof(char*), mpqs_relations_cmp); /* copy results back to the original file, skipping exact duplicates */ pTMP = pari_fopen_or_fail(filename, WRITE); old_s = sort_table[0]; pari_fputs(sort_table[0], pTMP); count = 1; for(j = 1; j < i; j++) { if (strcmp(old_s, sort_table[j])) { pari_fputs(sort_table[j], pTMP); count++; } old_s = sort_table[j]; } pari_fclose(pTMP); if (MPQS_DEBUGLEVEL >= 6) err_printf("MPQS: done sorting one file.\n"); /* deallocate buffers and any extraneous buflist blocks except the first */ while (*--buflist) { if (buflist != buflist_head) /* not a linkage pointer */ pari_free((void*) *buflist); /* free a buffer */ else { /* linkage pointer */ next_buflist = (char**)(*buflist); pari_free((void*)buflist_head); /* free a buflist block */ buflist_head = next_buflist; buflist = buflist_head + buflist_size; } } avma = av; return count; } /* appends contents of file fp1 to f (auxiliary routine for merge sort) and * returns number of lines copied. Close f afterwards */ static long mpqs_append_file(pariFILE *f, FILE *fp1) { FILE *fp = f->file; char line[MPQS_STRING_LENGTH]; long c = 0; while (fgets(line, MPQS_STRING_LENGTH, fp1)) { pari_fputs(line, f); c++; } if (fflush(fp)) pari_warn(warner, "error whilst flushing file %s", f->name); pari_fclose(f); return c; } /* Merge-sort on the files LPREL and LPNEW; assumes that LPREL and LPNEW are * already sorted. Creates/truncates the TMP file, writes result to it and * closes it (via mpqs_append_file()). Instead of LPREL, LPNEW we may also call * this with FREL, FNEW. In the latter case pCOMB should be NULL (and we * return the count of all full relations), in the former non-NULL (and we * return the count of frels we expect to be able to combine out of the * present lprels). If pCOMB is non-NULL, the combinable lprels are written * out to this separate file. * We keep only one occurrence of each `large prime' in TMP (i.e. in the * future LPREL file). --GN */ #define swap_lines() { char *line_tmp;\ line_tmp = line_new_old; \ line_new_old = line_new; \ line_new = line_tmp; } static long mpqs_mergesort_lp_file0(FILE *LPREL, FILE *LPNEW, pariFILE *pCOMB, pariFILE *pTMP) { char line1[MPQS_STRING_LENGTH], line2[MPQS_STRING_LENGTH]; char line[MPQS_STRING_LENGTH]; char *line_new = line1, *line_new_old = line2; long q_new, q_new_old = -1, q, i = 0, c = 0; long comb_in_progress; if ( !fgets(line_new, MPQS_STRING_LENGTH, LPNEW) ) { /* LPNEW is empty: copy LPREL to TMP. Could be done by a rename if we * didn't want to count the lines (again)... however, this case will not * normally happen */ i = mpqs_append_file(pTMP, LPREL); return pCOMB ? 0 : i; } /* we now have a line_new from LPNEW */ if (!fgets(line, MPQS_STRING_LENGTH, LPREL)) { /* LPREL is empty: copy LPNEW to TMP... almost. */ pari_fputs(line_new, pTMP); if (!pCOMB) { /* full relations mode */ i = mpqs_append_file(pTMP, LPNEW); return i + 1; } /* LP mode: check for combinable relations */ q_new_old = atol(line_new); /* we need to retain a copy of the old line just for a moment, because we * may yet have to write it to pCOMB. Do this by swapping the two buffers */ swap_lines(); comb_in_progress = 0; i = 0; while (fgets(line_new, MPQS_STRING_LENGTH, LPNEW)) { q_new = atol(line_new); if (q_new_old == q_new) { /* found combinables, check whether we're already busy on this particular `large prime' */ if (!comb_in_progress) { /* if not, write first line to pCOMB, creating and opening the * file first if it isn't open yet */ pari_fputs(line_new_old, pCOMB); comb_in_progress = 1; } /* in any case, write the current line, and count it */ pari_fputs(line_new, pCOMB); i++; } else { /* not combinable */ q_new_old = q_new; comb_in_progress = 0; /* and dump it to the TMP file */ pari_fputs(line_new, pTMP); /* and stash it away for a moment */ swap_lines(); } } /* while */ pari_fclose(pTMP); return i; } /* normal case: both LPNEW and LPREL are not empty */ q_new = atol(line_new); q = atol(line); for(;;) { /* main merging loop */ i = comb_in_progress = 0; /* first the harder case: let LPNEW catch up with LPREL, and possibly overtake it, checking for combinables coming from LPNEW alone */ while (q > q_new) { if (!pCOMB || !comb_in_progress) pari_fputs(line_new, pTMP); if (!pCOMB) c++; /* in FREL mode, count lines written */ else if (!comb_in_progress) { q_new_old = q_new; swap_lines(); } if (!fgets(line_new, MPQS_STRING_LENGTH, LPNEW)) { pari_fputs(line, pTMP); if (!pCOMB) c++; else c += i; i = mpqs_append_file(pTMP, LPREL); return pCOMB? c: c + i; } q_new = atol(line_new); if (!pCOMB) continue; /* LP mode only: */ if (q_new_old != q_new) /* not combinable */ comb_in_progress = 0; /* next loop will deal with it, or loop may end */ else { /* found combinables, check whether we're already busy on this `large prime' */ if (!comb_in_progress) { pari_fputs(line_new_old, pCOMB); comb_in_progress = 1; } /* in any case, write the current line, and count it */ pari_fputs(line_new, pCOMB); i++; } } /* while q > q_new */ /* q <= q_new */ if (pCOMB) c += i; /* accumulate count of combinables */ i = 0; /* and clear it */ comb_in_progress = 0;/* redundant */ /* now let LPREL catch up with LPNEW, and possibly overtake it */ while (q < q_new) { pari_fputs(line, pTMP); if (!pCOMB) c++; if (!fgets(line, MPQS_STRING_LENGTH, LPREL)) { pari_fputs(line_new, pTMP); i = mpqs_append_file(pTMP, LPNEW); return pCOMB? c: c + i + 1; } else q = atol(line); } /* q >= q_new */ /* Finally, it may happen that q == q_new, indicating combinables whose * `large prime' is already in LPREL, and appears now once or more often in * LPNEW. Thus in this sub-loop we advance LPNEW. The `line' from LPREL is * left alone, and will be written to TMP the next time around the main for * loop; we only write it to pCOMB here -- unless all we find is an exact * duplicate of the line we already have, that is. (There can be at most * one such, and if so it is simply discarded.) */ while (q == q_new) { if (!strcmp(line_new, line)) { /* duplicate -- move right ahead to the next LPNEW line */ ;/* do nothing here */ } else if (!pCOMB) { /* full relations mode: write line_new out first, keep line */ pari_fputs(line_new, pTMP); c++; } else { /* LP mode, and combinable relation */ if (!comb_in_progress) { pari_fputs(line, pCOMB); comb_in_progress = 1; } pari_fputs(line_new, pCOMB); i++; } /* NB comb_in_progress is cleared by q_new becoming bigger than q, thus * the current while loop terminating, the next time through the main for * loop */ /* common ending: get another line_new, if any */ if (!fgets(line_new, MPQS_STRING_LENGTH, LPNEW)) { pari_fputs(line, pTMP); if (!pCOMB) c++; else c += i; i = mpqs_append_file(pTMP, LPREL); return pCOMB? c: c + i; } else q_new = atol(line_new); } /* while */ if (pCOMB) c += i; /* accumulate count of combinables */ } } static long mpqs_mergesort_lp_file(char *REL_str, char *NEW_str, char *TMP_str, pariFILE *pCOMB) { pariFILE *pREL = pari_fopen_or_fail(REL_str, READ); pariFILE *pNEW = pari_fopen_or_fail(NEW_str, READ); pariFILE *pTMP = pari_fopen_or_fail(TMP_str, WRITE); long tp; tp = mpqs_mergesort_lp_file0(pREL->file, pNEW->file, pCOMB, pTMP); pari_fclose(pREL); pari_fclose(pNEW); pari_unlink(REL_str); while (rename(TMP_str,REL_str)) { if (errno != EEXIST) pari_err_FILE("output file [rename]", REL_str); } if (MPQS_DEBUGLEVEL >= 6) err_printf("MPQS: renamed file %s to %s\n", TMP_str, REL_str); return tp; } /*********************************************************************/ /** **/ /** SELF-INITIALIZATION **/ /** **/ /*********************************************************************/ #ifdef MPQS_DEBUG /* Debug-only helper routine: check correctness of the root z mod p_i * by evaluting A * z^2 + B * z + C mod p_i (which should be 0). * C is written as (B*B-kN)/(4*A) */ static void check_root(mpqs_handle_t *h, long p, long start) { long z = start - ((long)(h->M) % p); if (smodis(addii(h->C, mului(z, addii(h->B, mului(z, h->A)))), p)) { err_printf("MPQS: p = %ld\n", p); err_printf("MPQS: A = %Ps\n", h->A); err_printf("MPQS: B = %Ps\n", h->B); err_printf("MPQS: C = %Ps\n", h->C); err_printf("MPQS: z = %ld\n", z); pari_err_BUG("MPQS: self_init: found wrong polynomial"); } } #endif /* There are four parts to self-initialization, which are exercised at * somewhat different times: * - choosing a new coefficient A (selecting the prime factors to go into it, * and doing the required bookkeeping in the FB entries, including clearing * out the flags from the previous cohort), together with: * - doing the actual computations attached to a new A * - choosing a new B keeping the same A (very much simpler and quicker) * - and a small common bit that needs to happen in both cases. * As to the first item, the new scheme works as follows: * We pick omega_A - 1 prime factors for A below the index2_FB point which * marks their ideal size, and one prime above this point, choosing the * latter so as to get log2(A) as close as possible to l2_target_A. * The lower prime factors are chosen using bit patterns of constant weight, * gradually moving away from index2_FB towards smaller FB subscripts. * If this bumps into index0_FB (might happen for very small input), we * back up by increasing index2_FB by two, and from then on choosing only * bit patterns with either or both of their bottom bits set, so at least * one of the omega_A - 1 smaller prime factor will be beyond the original * index2_FB point. In this way we avoid re-using A's which had already * been done. * (The choice of the upper "flyer" prime is of course constrained by the * size of the FB, which normally should never be anywhere close to becoming * a problem. In unfortunate cases, e.g. for very small kN, we might have * to live with a rather non-optimal choice. * Then again, MPQS as such is surprisingly robust. One day, I had got the * order of entries in mpqs_parameterset_t mixed up, and was running on a * smallish N with a huuuuge factor base and extremely tiny sieve interval, * and it still managed to factor it fairly quickly...) * * Mathematically, there isn't much more to this than the usual formula for * solving a quadratic (over the field of p elements for each prime p in * the FB which doesn't divide A), solving a linear equation for each of * the primes which do divide A, and precomputing differences between roots * mod p so we can adjust the roots quickly when we change B. * See Thomas Sosnowski's diploma thesis. */ /* Helper function: * Increment *x (!=0) to a larger value which has the same number of 1s in its * binary representation. Wraparound can be detected by the caller as long as * we keep total_no_of_primes_for_A strictly less than BITS_IN_LONG. * * Changed switch to increment *x in all cases to the next larger number * which (a) has the same count of 1 bits and (b) does not arise from the * old value by moving a single 1 bit one position to the left (which was * undesirable for the sieve). --GN based on discussion with TP */ INLINE void mpqs_increment(mpqs_uint32_t *x) { mpqs_uint32_t r1_mask, r01_mask, slider=1UL; /* 32-way computed jump handles 22 out of 32 cases */ switch (*x & 0x1F) { case 29: (*x)++; break; /* shifts a single bit, but we postprocess this case */ case 26: (*x) += 2; break; /* again */ case 1: case 3: case 6: case 9: case 11: case 17: case 19: case 22: case 25: case 27: (*x) += 3; return; case 20: (*x) += 4; break; /* again */ case 5: case 12: case 14: case 21: (*x) += 5; return; case 2: case 7: case 13: case 18: case 23: (*x) += 6; return; case 10: (*x) += 7; return; case 8: (*x) += 8; break; /* and again */ case 4: case 15: (*x) += 12; return; default: /* 0, 16, 24, 28, 30, 31 */ /* isolate rightmost 1 */ r1_mask = ((*x ^ (*x - 1)) + 1) >> 1; /* isolate rightmost 1 which has a 0 to its left */ r01_mask = ((*x ^ (*x + r1_mask)) + r1_mask) >> 2; /* simple cases. Both of these shift a single bit one position to the left, and will need postprocessing */ if (r1_mask == r01_mask) { *x += r1_mask; break; } if (r1_mask == 1) { *x += r01_mask; break; } /* general case -- idea: add r01_mask, kill off as many 1 bits as possible * to its right while at the same time filling in 1 bits from the LSB. */ if (r1_mask == 2) { *x += (r01_mask>>1) + 1; return; } while (r01_mask > r1_mask && slider < r1_mask) { r01_mask >>= 1; slider <<= 1; } *x += r01_mask + slider - 1; return; } /* post-process all cases which couldn't be finalized above. If we get here, slider still has its original value. */ r1_mask = ((*x ^ (*x - 1)) + 1) >> 1; r01_mask = ((*x ^ (*x + r1_mask)) + r1_mask) >> 2; if (r1_mask == r01_mask) { *x += r1_mask; return; } if (r1_mask == 1) { *x += r01_mask; return; } if (r1_mask == 2) { *x += (r01_mask>>1) + 1; return; } while (r01_mask > r1_mask && slider < r1_mask) { r01_mask >>= 1; slider <<= 1; } *x += r01_mask + slider - 1; return; } /* self-init (1): advancing the bit pattern, and choice of primes for A. * The first time this is called, it finds h->bin_index == 0, which tells us * to initialize things from scratch. On later occasions, we need to begin * by clearing the MPQS_FBE_DIVIDES_A bit in the fbe_flags of the former * prime factors of A. We use, of course, the per_A_pr array for finding * them. Upon successful return, that array will have been filled in, and * the flag bits will have been turned on again in the right places. * We return 1 (true) when we could set things up successfully, and 0 when * we found we'd be using more bits to the left in bin_index than we have * matching primes for in the FB. In the latter case, bin_index will be * zeroed out, index2_FB will be incremented by 2, index2_moved will be * turned on, and the caller, after checking that index2_FB has not become * too large, should just call us again, which then is guaranteed to succeed: * we'll start again with a right-justified sequence of 1 bits in bin_index, * now interpreted as selecting primes relative to the new index2_FB. */ #ifndef MPQS_DEBUG_SI_CHOOSE_PRIMES # define MPQS_DEBUG_SI_CHOOSE_PRIMES 0 #endif INLINE int mpqs_si_choose_primes(mpqs_handle_t *h) { mpqs_FB_entry_t *FB = h->FB; mpqs_per_A_prime_t *per_A_pr = h->per_A_pr; double l2_last_p = h->l2_target_A; mpqs_int32_t omega_A = h->omega_A; int i, j, v2, prev_last_p_idx; int room = h->index2_FB - h->index0_FB - omega_A + 4; /* GN 20050723: I.e., index2_FB minus (index0_FB + omega_A - 3) plus 1 * The notion of room here (cf mpqs_locate_A_range() above) is the number * of primes at or below index2_FB which are eligible for A. * At the very least, we need omega_A - 1 of them, and it is guaranteed * by mpqs_locate_A_range() that at least this many are available when we * first get here. The logic here ensures that the lowest FB slot used * for A is never less than index0_FB + omega_A - 3. In other words, when * omega_A == 3 (very small kN), we allow ourselves to reach all the way * down to index0_FB; otherwise, we keep away from it by at least one * position. For omega_A >= 4 this avoids situations where the selection * of the smaller primes here has advanced to a lot of very small ones, and * the single last larger one has soared away to bump into the top end of * the FB. */ mpqs_uint32_t room_mask; mpqs_int32_t p; ulong bits; /* XXX also clear the index_j field here? */ if (h->bin_index == 0) { /* first time here, or after increasing index2_FB, initialize to a pattern * of omega_A - 1 consecutive right-justified 1 bits. * Caller will have ensured that there are enough primes for this in the * FB below index2_FB. */ h->bin_index = (1UL << (omega_A - 1)) - 1; prev_last_p_idx = 0; } else { /* clear out the old flags */ for (i = 0; i < omega_A; i++) MPQS_FLG(i) &= ~MPQS_FBE_DIVIDES_A; prev_last_p_idx = MPQS_I(omega_A-1); /* find out how much maneuvering room we have before we're up against * the index0_FB wall */ if (room > 30) room = 30; room_mask = ~((1UL << room) - 1); /* bump bin_index to the next acceptable value. If index2_moved is off, * call mpqs_increment() just once; otherwise, repeat until there's * something in the least significant 2 bits - this to ensure that we * never re-use an A which we'd used before increasing index2_FB - but * also stop if something shows up in the forbidden bits on the left * where we'd run out of bits or out of subscripts (i.e. walk beyond * index0_FB + omega_A - 3). */ mpqs_increment(&h->bin_index); if (h->index2_moved) { while ((h->bin_index & (room_mask | 0x3)) == 0) mpqs_increment(&h->bin_index); } /* ok so did we fall off the edge on the left? */ if ((h->bin_index & room_mask) != 0) { /* Yes. Turn on the index2_moved flag in the handle */ h->index2_FB += 2; /* caller to check this isn't too large!!! */ h->index2_moved = 1; h->bin_index = 0; if (MPQS_DEBUG_SI_CHOOSE_PRIMES || (MPQS_DEBUGLEVEL >= 5)) err_printf("MPQS: wrapping, more primes for A now chosen near FB[%ld] = %ld\n", (long)h->index2_FB, (long)FB[h->index2_FB].fbe_p); return 0; /* back off - caller should retry */ } } /* assert: we aren't occupying any of the room_mask bits now, and if * index2_moved had already been on, at least one of the two LSBs is on */ bits = h->bin_index; if (MPQS_DEBUG_SI_CHOOSE_PRIMES || (MPQS_DEBUGLEVEL >= 6)) err_printf("MPQS: new bit pattern for primes for A: 0x%lX\n", bits); /* map bits to FB subscripts, counting downward with bit 0 corresponding * to index2_FB, and accumulate logarithms against l2_last_p */ j = h->index2_FB; v2 = vals((long)bits); if (v2) { j -= v2; bits >>= v2; } for (i = omega_A - 2; i >= 0; i--) { MPQS_I(i) = j; l2_last_p -= MPQS_LP(i); MPQS_FLG(i) |= MPQS_FBE_DIVIDES_A; bits &= ~1UL; if (!bits) break; /* that was the i=0 iteration */ v2 = vals((long)bits); j -= v2; bits >>= v2; } /* Choose the larger prime. Note we keep index2_FB <= size_of_FB - 3 */ for (j = h->index2_FB + 1; (p = FB[j].fbe_p) != 0; j++) { if (FB[j].fbe_flogp > l2_last_p) break; } /* GN 20050724: The following trick avoids generating a relatively large * proportion of duplicate relations when the last prime happens to fall * into an area where there are large gaps from one FB prime to the next, * and would otherwise often be repeated (so that successive A's would * wind up too similar to each other). While this trick isn't perfect, * it seems to get rid of a major part of the potential duplication. */ if ((p != 0) && (j == prev_last_p_idx)) { j++; p = FB[j].fbe_p; } MPQS_I(omega_A - 1) = (p == 0 ? /* did we fall off the end of the FB? */ h->size_of_FB + 1 : /* then improvise */ j); MPQS_FLG(omega_A - 1) |= MPQS_FBE_DIVIDES_A; if (MPQS_DEBUG_SI_CHOOSE_PRIMES || (MPQS_DEBUGLEVEL >= 6)) { err_printf("MPQS: chose primes for A"); for (i = 0; i < omega_A; i++) { err_printf(" FB[%ld]=%ld%s", (long) MPQS_I(i), (long) MPQS_AP(i), i < omega_A - 1 ? "," : "\n"); } } return 1; } /* compute coefficients of the sieving polynomial for self initializing * variant. Coefficients A and B are returned and several tables are * updated. */ /* A and B are kept on the PARI stack in preallocated GENs. So is C when * we're compiled for debugging. */ static void mpqs_self_init(mpqs_handle_t *h) { const ulong size_of_FB = h->size_of_FB + 1; mpqs_FB_entry_t *FB = h->FB; mpqs_inv_A_H_t *inv_A_H = h->inv_A_H; const pari_sp av = avma; GEN p1, p2; GEN A = h->A; GEN B = h->B; mpqs_per_A_prime_t *per_A_pr = h->per_A_pr; long i, j; long inv_A2; ulong p; #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: enter self init, avma = 0x%lX\n", (ulong)avma); #endif /* when all of the B's have already been used, choose new A ; this is indicated by setting index_j to 0 */ if (++h->index_j == (mpqs_uint32_t)h->no_B) { h->index_j = 0; h->index_i++; /* count finished A's */ } if (h->index_j == 0) /* "mpqs_self_init_A()" */ { /* compute first polynomial with new A */ if (!mpqs_si_choose_primes(h)) { /* We ran out of room towards small primes, and index2_FB was raised. * Check that we're still ok in that direction before re-trying the * operation, which then is guaranteed to succeed. The invariant we * maintain towards the top end is that h->size_of_FB - h->index2_FB >= 3, * but note that our size_of_FB is one larger. */ /* "throw exception up to caller." ( bin_index set to impossible value * 0 by mpqs_si_choose_primes() */ if (size_of_FB - h->index2_FB < 4) return; (void) mpqs_si_choose_primes(h); } /* assert: bin_index and per_A_pr are now populated with consistent * values */ /* compute A = product of omega_A primes given by bin_index */ p1 = NULL; for (i = 0; i < h->omega_A; i++) { p = (ulong) MPQS_AP(i); p1 = p1 ? muliu(p1, p): utoipos(p); } affii(p1, A); avma = av; /* Compute H[i], 0 <= i < omega_A. Also compute the initial * B = sum(v_i*H[i]), by taking all v_i = +1 */ /* TODO: following needs to be changed later for segmented FB and sieve * interval, where we'll want to precompute several B's. */ p2 = NULL; for (i = 0; i < h->omega_A; i++) { p = (ulong) MPQS_AP(i); p1 = divis(A, (long)p); p1 = muliu(p1, Fl_inv(umodiu(p1, p), p)); p1 = muliu(p1, MPQS_SQRT(i)); affii(remii(p1, A), MPQS_H(i)); p2 = p2 ? addii(p2, MPQS_H(i)) : MPQS_H(i); } affii(p2, B); avma = av; /* must happen outside the loop */ /* ensure B = 1 mod 4 */ if (mod2(B) == 0) affii(addii(B, mului(mod4(A), A)), B); /* B += (A % 4) * A; */ p1 = shifti(A, 1); /* compute the roots z1, z2, of the polynomial Q(x) mod p_j and * initialize start1[i] with the first value p_i | Q(z1 + i p_j) * initialize start2[i] with the first value p_i | Q(z2 + i p_j) * The following loop "miraculously" does The Right Thing for the * primes dividing k (where sqrt_kN is 0 mod p). Primes dividing A * are skipped here, and are handled further down in the common part * of SI. */ for (j = 3; (ulong)j <= size_of_FB; j++) { ulong mb, tmp1, tmp2, m; if (FB[j].fbe_flags & MPQS_FBE_DIVIDES_A) continue; p = (ulong)FB[j].fbe_p; m = h->M % p; inv_A2 = Fl_inv(umodiu(p1, p), p); /* = 1/(2*A) mod p_j */ mb = umodiu(B, p); if (mb) mb = p - mb; /* mb = -B mod p */ tmp1 = Fl_sub(mb, FB[j].fbe_sqrt_kN, p); tmp1 = Fl_mul(tmp1, inv_A2, p); FB[j].fbe_start1 = (mpqs_int32_t)Fl_add(tmp1, m, p); tmp2 = Fl_add(mb, FB[j].fbe_sqrt_kN, p); tmp2 = Fl_mul(tmp2, inv_A2, p); FB[j].fbe_start2 = (mpqs_int32_t)Fl_add(tmp2, m, p); for (i = 0; i < h->omega_A - 1; i++) { ulong h = umodiu(MPQS_H(i), p) << 1; if (h > p) h -= p; MPQS_INV_A_H(i,j) = Fl_mul(h, inv_A2, p); /* 1/A * H[i] mod p_j */ } } } else /* "mpqs_self_init_B()" */ { /* no "real" computation -- use recursive formula */ /* The following exploits that B is the sum of omega_A terms +-H[i]. * Each time we switch to a new B, we choose a new pattern of signs; * the precomputation of the inv_A_H array allows us to change the * two arithmetic progressions equally fast. The choice of sign * patterns does *not* follow the bit pattern of the ordinal number * of B in the current cohort; rather, we use a Gray code, changing * only one sign each time. When the i-th rightmost bit of the new * ordinal number index_j of B is 1, the sign of H[i] is changed; * the next bit to the left tells us whether we should be adding or * subtracting the difference term. We never need to change the sign * of H[omega_A-1] (the topmost one), because that would just give us * the same sieve items Q(x) again with the opposite sign of x. This * is why we only precomputed inv_A_H up to i = omega_A - 2. */ ulong v2 = 0; /* 2-valuation of h->index_j */ j = h->index_j; /* could use vals() here, but we need to right shift the bit pattern * anyway in order to find out which inv_A_H entries must be added to or * subtracted from the modular roots */ while ((j & 1) == 0) { v2++; j >>= 1; } /* v2 = v_2(index_j), determine new starting positions for sieving */ p1 = shifti(MPQS_H(v2), 1); if (j & 2) { /* j = 3 mod 4 */ for (j = 3; (ulong)j <= size_of_FB; j++) { if (FB[j].fbe_flags & MPQS_FBE_DIVIDES_A) continue; p = (ulong)FB[j].fbe_p; FB[j].fbe_start1 = Fl_sub(FB[j].fbe_start1, MPQS_INV_A_H(v2,j), p); FB[j].fbe_start2 = Fl_sub(FB[j].fbe_start2, MPQS_INV_A_H(v2,j), p); } p1 = addii(B, p1); } else { /* j = 1 mod 4 */ for (j = 3; (ulong)j <= size_of_FB; j++) { if (FB[j].fbe_flags & MPQS_FBE_DIVIDES_A) continue; p = (ulong)FB[j].fbe_p; FB[j].fbe_start1 = Fl_add(FB[j].fbe_start1, MPQS_INV_A_H(v2,j), p); FB[j].fbe_start2 = Fl_add(FB[j].fbe_start2, MPQS_INV_A_H(v2,j), p); } p1 = subii(B, p1); } affii(p1, B); } avma = av; /* p=2 is a special case. start1[2], start2[2] are never looked at, * so don't bother setting them. */ /* "mpqs_self_init_common()" */ /* now compute zeros of polynomials that have only one zero mod p because p divides the coefficient A */ /* compute coefficient -C */ p1 = diviiexact(subii(h->kN, sqri(B)), shifti(A, 2)); for (i = 0; i < h->omega_A; i++) { ulong tmp, s; p = (ulong) MPQS_AP(i); tmp = Fl_div(umodiu(p1, p), umodiu(B, p), p); s = (tmp + h->M) % p; FB[MPQS_I(i)].fbe_start1 = (mpqs_int32_t)s; FB[MPQS_I(i)].fbe_start2 = (mpqs_int32_t)s; } if (MPQS_DEBUGLEVEL >= 6) err_printf("MPQS: chose Q_%ld(x) = %Ps x^2 %c %Ps x + C\n", (long) h->index_j, h->A, signe(h->B) < 0? '-': '+', absi_shallow(h->B)); avma = av; #ifdef MPQS_DEBUG /* stash C into the handle. Since check_root() is the only thing which * uses it, and only for debugging, C doesn't even exist as a field in * the handle unless we're built with MPQS_DEBUG. */ affii(negi(p1), h->C); for (j = 3; j <= size_of_FB; j++) { check_root(h, FB[j].fbe_p, FB[j].fbe_start1); check_root(h, FB[j].fbe_p, FB[j].fbe_start2); avma = av; } if (DEBUGLEVEL >= 6) PRINT_IF_VERBOSE("MPQS: checking of roots of Q(x) was successful\n"); #endif #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: leave self init, avma = 0x%lX\n", (ulong)avma); #endif } /*********************************************************************/ /** **/ /** THE SIEVE **/ /** **/ /*********************************************************************/ /* Main sieving routine: * p4 = 4*p (used for loop unrolling) * log_p: approximation for log(p) * begin: points to a sieve array * end: points to the end of the sieve array * starting_sieving_index: marks the first FB element used for sieving */ INLINE void mpqs_sieve_p(unsigned char *begin, unsigned char *end, long p4, long p, unsigned char log_p) { register unsigned char *e = end - p4; /* Loop unrolled some time ago. It might be better to let the compiler worry * about *this* kind of optimization, based on its knowledge of whatever * useful tricks the machine instruction set architecture is offering * ("speculative loads" being the buzzword). --GN */ while (e - begin >= 0) /* signed comparison */ { (*begin) += log_p, begin += p; (*begin) += log_p, begin += p; (*begin) += log_p, begin += p; (*begin) += log_p, begin += p; } while (end - begin >= 0) /* again */ (*begin) += log_p, begin += p; } static void mpqs_sieve(mpqs_handle_t *h) { long p, l = h->index1_FB; mpqs_FB_entry_t *ptr_FB; unsigned char *sieve_array = h->sieve_array; unsigned char *sieve_array_end = h->sieve_array_end; for (ptr_FB = &(h->FB[l]); (p = ptr_FB->fbe_p) != 0; ptr_FB++, l++) { unsigned char log_p = ptr_FB->fbe_logval; long start1 = ptr_FB->fbe_start1; long start2 = ptr_FB->fbe_start2; /* sieve with FB[l] from start_1[l] */ /* if start1 != start2 sieve with FB[l] from start_2[l] */ /* Maybe it is more efficient not to have a conditional branch in * the present loop body, and instead to right-shift log_p one bit * based on a flag bit telling us that we're on a one-root prime? * And instead roll the two invocations of mpqs_sieve_p into one. */ mpqs_sieve_p(sieve_array + start1, sieve_array_end, p << 2, p, log_p); if (start1 != start2) mpqs_sieve_p(sieve_array + start2, sieve_array_end, p << 2, p, log_p); } } /******************************/ /* Could make shameless use of the fact that M is divisible by 4, but * let the compiler worry about loop unrolling. Indeed I wonder whether * modern compilers woudln't have an easier time optimizing this if it * were written as array accesses. Doing so. */ static long mpqs_eval_sieve(mpqs_handle_t *h) { long x = 0, count = 0, M_2 = h->M << 1; /* TODO: replace the following by an auto-adjusting threshold driven * by histogram yield measurements */ unsigned char th = h->sieve_threshold; unsigned char *sieve_array = h->sieve_array; long *candidates = h->candidates; /* The following variation on the original is marginally faster with a * good optimizing compiler. Exploiting the sentinel, we don't need to * check for x < M_2 in the inner while loop - this more than makes up * for the "lack" of explicit unrolling. Optimizations like loop * unrolling are best left to the compiler anyway... */ while (count < MPQS_CANDIDATE_ARRAY_SIZE - 1) { while (sieve_array[x] < th) x++; if (x >= M_2) break; candidates[count++] = x++; } candidates[count] = 0; return count; } /*********************************************************************/ /** **/ /** CONSTRUCTING RELATIONS **/ /** **/ /*********************************************************************/ /* Main relation routine */ static void mpqs_add_factor(char **last, ulong ei, ulong pi) { sprintf(*last, " %lu %lu", ei, pi); *last += strlen(*last); } /* concatenate " 0" */ static void mpqs_add_0(char **last) { char *s = *last; *s++ = ' '; *s++ = '0'; *s++ = 0; *last = s; } #ifdef MPQS_DEBUG static GEN mpqs_factorback(mpqs_handle_t *h, char *relations) { char *s, *t = stack_strdup(relations), *tok; GEN N = h->N, prod = gen_1; long i; mpqs_FB_entry_t *FB = h->FB; s = paristrtok_r(t, " \n", &tok); while (s != NULL) { long e = atol(s); if (!e) break; s = paristrtok_r(NULL, " \n", &tok); i = atol(s); /* special case -1 */ if (i == 1) { prod = Fp_neg(prod,N); s = paristrtok_r(NULL, " \n", &tok); continue; } prod = Fp_mul(prod, Fp_powu(utoipos(FB[i].fbe_p), e, N), N); s = paristrtok_r(NULL, " \n", &tok); } return prod; } #endif /* NB FREL, LPREL are actually FNEW, LPNEW when we get called */ static long mpqs_eval_cand(mpqs_handle_t *h, long number_of_cand, FILE *FREL, FILE *LPREL) { pari_sp av; long number_of_relations = 0; char *relations = h->relations; long *relaprimes = h->relaprimes; ulong i, pi; mpqs_FB_entry_t *FB = h->FB; GEN A = h->A; GEN B = h->B; /* we don't need coefficient C here */ int pii; long *candidates = h->candidates; av = avma; #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: enter eval cand, avma = 0x%lX\n", (ulong)avma); #endif for (i = 0; i < (ulong)number_of_cand; i++, avma = av) { GEN Qx, Qx_part, A_2x_plus_B, Y; long powers_of_2, p; long x = candidates[i]; long x_minus_M = x - h->M; char *relations_end = relations; int relaprpos = 0; #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: eval loop 1, avma = 0x%lX\n", (ulong)avma); #endif *relations_end = 0; #ifdef MPQS_DEBUG_VERYVERBOSE err_printf("%c", (char)('0' + i%10)); #endif /* A_2x_plus_B = (A*(2x)+B), Qx = (A*(2x)+B)^2/(4*A) = Q(x) */ A_2x_plus_B = addii(mulis(A, 2 * x_minus_M), B); Y = absi_shallow(A_2x_plus_B); Qx = subii(sqri(A_2x_plus_B), h->kN); #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: eval loop 2, avma = 0x%lX\n", (ulong)avma); #endif /* When N is relatively small, it may happen that Qx is outright * divisible by N at this point. In any case, when no extensive prior * trial division / Rho / ECM had been attempted, gcd(Qx,N) may turn * out to be a nontrivial factor of N (larger than what the FB contains * or we'd have found it already, but possibly smaller than the large- * prime bound). This is too rare to check for here in the inner loop, * but it will be caught if such an LP relation is ever combined with * another. */ /* Qx cannot possibly vanish here */ if (!signe(Qx)) { PRINT_IF_VERBOSE("<+>"); continue; } else if (signe(Qx) < 0) { setabssign(Qx); mpqs_add_factor(&relations_end, 1, 1); /* i = 1, ei = 1, pi */ } /* divide by powers of 2; we're really dealing with 4*A*Q(x), so we * always have at least 2^2 here, and at least 2^3 when kN is 1 mod 4 */ powers_of_2 = vali(Qx); Qx = shifti(Qx, -powers_of_2); mpqs_add_factor(&relations_end, powers_of_2, 2); /* That has dealt with a possible -1 and the power of 2. First pass * over odd primes in FB: pick up all possible divisors of Qx including * those sitting in k or in A, and remember them in relaprimes. Do not * yet worry about possible repeated factors, these will be found in the * second pass. */ Qx_part = A; /* The first pass recognizes divisors of A by their corresponding flags * bit in the FB entry. (Divisors of k require no special treatment at * this stage.) We construct a preliminary table of FB subscripts and * "exponents" of the FB primes which divide Qx. (We store subscripts * rather than the primes themselves because the string representation * of a relation is in terms of the subscripts.) * We must distinguish three cases so we can do the right thing in the * 2nd pass: prime not in A which divides Qx, prime in A which does not * divide Qx/A, prime in A which does divide Qx/A. The first and third * kinds need checking for repeated factors, the second kind doesn't. The * first and second kinds contribute 1 to the exponent in the relation, * the 3rd kind contributes 2. We store 1,0,2 respectively in these three * cases. * Factors in common with k are much simpler - if they occur, they occur * exactly to the first power, and this makes no difference in the first * pass - here they behave just like every normal odd factor base prime. */ for (pi = 3; (p = FB[pi].fbe_p); pi++) { long tmp_p = x % p; ulong ei = 0; /* Here we use that MPQS_FBE_DIVIDES_A equals 1. */ ei = FB[pi].fbe_flags & MPQS_FBE_DIVIDES_A; if (tmp_p == FB[pi].fbe_start1 || tmp_p == FB[pi].fbe_start2) { /* p divides Q(x)/A (and possibly A), 1st or 3rd case */ relaprimes[relaprpos++] = pi; relaprimes[relaprpos++] = 1 + ei; Qx_part = muliu(Qx_part, p); } else if (ei) { /* p divides A but does not divide Q(x)/A, 2nd case */ relaprimes[relaprpos++] = pi; relaprimes[relaprpos++] = 0; } } /* We have now accumulated the known factors of Qx except for possible * repeated factors and for possible large primes. Divide off what we * have. (This is faster than dividing off A and each prime separately.) */ Qx = diviiexact(Qx, Qx_part); /* (ToDo: MPQS_DEBUG sanity check...) */ #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: eval loop 3, avma = 0x%lX\n", (ulong)avma); #endif /* second pass - deal with any repeated factors, and write out the string * representation of the tentative relation. At this point, the only * primes which can occur again in the adjusted Qx are those in relaprimes * which are followed by 1 or 2. We must pick up those followed by a 0, * too, though. */ PRINT_IF_VERBOSE("a"); for (pii = 0; pii < relaprpos; pii+=2) { long remd_p; ulong ei = relaprimes[pii+1]; GEN Qx_div_p; pi = relaprimes[pii]; /* Here, prime factors of k go their separate way. We could have * introduced another FB entry flag for marking them, but it is easier * to identify them just by their position before index0_FB. */ if ((mpqs_int32_t)pi < h->index0_FB) { #ifdef MPQS_DEBUG PRINT_IF_VERBOSE("\bk!"); #endif mpqs_add_factor(&relations_end, 1, pi); continue; } if (ei == 0) /* p divides A and that was it */ { mpqs_add_factor(&relations_end, 1, pi); continue; } p = FB[pi].fbe_p; #ifdef MPQS_DEBUG_CANDIDATE_EVALUATION err_printf("MPQS DEBUG: Qx=%Ps p=%ld\n", Qx, p); #endif /* otherwise p might still divide the current adjusted Qx. Try it... */ /* NOTE: break out of loop when remaining Qx is 1 ? Or rather, suppress * the trial divisions, since we still need to write our string. * Actually instead of testing for 1, test whether Qx is smaller than p; * cf Karim's mail from 20050124. If it is, without being 1, then it has * a common factor with k. But those factors are soon going to have * disappeared before we get here. However, inserting * an explicit if (!is_pm1(Qx)) here did not help any. */ Qx_div_p = divis_rem(Qx, p, &remd_p); while (remd_p == 0) { ei++; Qx = Qx_div_p; Qx_div_p = divis_rem(Qx, p, &remd_p); } mpqs_add_factor(&relations_end, ei, pi); } #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: eval loop 4, avma = 0x%lX\n", (ulong)avma); #endif PRINT_IF_VERBOSE("\bb"); if (is_pm1(Qx)) { mpqs_add_0(&relations_end); fprintf(FREL, "%s :%s\n", itostr(Y), relations); number_of_relations++; #ifdef MPQS_USE_HISTOGRAMS /* bump full relations counter at candidate's value */ if (h->do_histograms) h->histo_full[sa[x]-128]++; #endif #ifdef MPQS_DEBUG { pari_sp av1 = avma; GEN rhs = mpqs_factorback(h, relations); GEN Qx_2 = remii(sqri(Y), h->N); if (!equalii(Qx_2, rhs)) { PRINT_IF_VERBOSE("\b(!)\n"); err_printf("MPQS: %Ps @ %Ps :%s\n", Y, Qx, relations); err_printf("\tQx_2 = %Ps\n", Qx_2); err_printf("\t rhs = %Ps\n", rhs); pari_err_BUG("MPQS: wrong full relation found"); } else PRINT_IF_VERBOSE("\b(:)"); avma = av1; } #endif } else if (cmpis(Qx, h->lp_bound) > 0) { /* TODO: check for double large prime */ #ifdef MPQS_USE_HISTOGRAMS /* bump useless-candidates counter at candidate's value */ if (h->do_histograms) h->histo_drop[sa[x]-128]++; #endif PRINT_IF_VERBOSE("\b."); } else { /* if (mpqs_isprime(itos(Qx))) */ mpqs_add_0(&relations_end); fprintf(LPREL, "%s @ %s :%s\n", itostr(Qx), itostr(Y), relations); #ifdef MPQS_USE_HISTOGRAMS /* bump LP relations counter at candidate's value */ if (h->do_histograms) h->histo_lprl[sa[x]-128]++; #endif #ifdef MPQS_DEBUG { pari_sp av1 = avma; GEN rhs = mpqs_factorback(h, relations); GEN Qx_2 = remii(sqri(Y), h->N); rhs = modii(mulii(rhs, Qx), h->N); if (!equalii(Qx_2, rhs)) { PRINT_IF_VERBOSE("\b(!)\n"); err_printf("MPQS: %Ps @ %Ps :%s\n", Y, Qx, relations); err_printf("\tQx_2 = %Ps\n", Qx_2); err_printf("\t rhs = %Ps\n", rhs); pari_err_BUG("MPQS: wrong large prime relation found"); } else PRINT_IF_VERBOSE("\b(;)"); avma = av1; } #endif } #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: eval loop end, avma = 0x%lX\n", (ulong)avma); #endif } /* for */ PRINT_IF_VERBOSE("\n"); #ifdef MPQS_DEBUG_AVMA err_printf("MPQS DEBUG: leave eval cand, avma = 0x%lX\n", (ulong)avma); #endif return number_of_relations; } /*********************************************************************/ /** **/ /** COMBINING RELATIONS **/ /** **/ /*********************************************************************/ /* combines the large prime relations in COMB to full relations in FNEW. * FNEW is assumed to be open for writing / appending. */ typedef struct { long q; char Y[MPQS_STRING_LENGTH]; char E[MPQS_STRING_LENGTH]; } mpqs_lp_entry; static void mpqs_set_exponents(long *ei, char *r) { char *s, b[MPQS_STRING_LENGTH], *tok; long e; strcpy(b, r); s = paristrtok_r(b, " \n", &tok); while (s != NULL) { e = atol(s); if (!e) break; s = paristrtok_r(NULL, " \n", &tok); ei[ atol(s) ] += e; s = paristrtok_r(NULL, " \n", &tok); } } static void set_lp_entry(mpqs_lp_entry *e, char *buf) { char *s1, *s2; s1 = buf; s2 = strchr(s1, ' '); *s2 = '\0'; e->q = atol(s1); s1 = s2 + 3; s2 = strchr(s1, ' '); *s2 = '\0'; strcpy(e->Y, s1); s1 = s2 + 3; s2 = strchr(s1, '\n'); *s2 = '\0'; strcpy(e->E, s1); } static long mpqs_combine_large_primes(mpqs_handle_t *h, FILE *COMB, pariFILE *pFNEW, GEN *f) { pari_sp av0 = avma, av, av2; char new_relation[MPQS_STRING_LENGTH], buf[MPQS_STRING_LENGTH]; mpqs_lp_entry e[2]; /* we'll use the two alternatingly */ long *ei, ei_size = h->size_of_FB + 2; long old_q; GEN inv_q, Y1, Y2, new_Y, new_Y1; long i, l, c = 0; *f = NULL; if (!fgets(buf, MPQS_STRING_LENGTH, COMB)) return 0; /* should not happen */ ei = (long *) new_chunk(ei_size); av = avma; /* put first lp relation in row 0 of e */ set_lp_entry(&e[0], buf); i = 1; /* second relation will go into row 1 */ old_q = e[0].q; while (!invmod(utoipos(old_q), h->N, &inv_q)) /* can happen */ { inv_q = gcdii(inv_q, h->N); /* inv_q can no longer be 1 here (it could while we were doing this mod * kN instead of mod N), but never mind - we're not in the fast path * at this point. It could be N when N is quite small; or we might * just have found a divisor by sheer luck. */ if (is_pm1(inv_q) || equalii(inv_q, h->N)) /* pity */ { #ifdef MPQS_DEBUG err_printf("MPQS: skipping relation with non-invertible q\n"); #endif if (!fgets(buf, MPQS_STRING_LENGTH, COMB)) { avma = av0; return 0; } avma = av; set_lp_entry(&e[0], buf); old_q = e[0].q; continue; } *f = gerepileuptoint(av0, inv_q); return c; } Y1 = strtoi(e[0].Y); av2 = avma; /* preserve inv_q and Y1 */ while (fgets(buf, MPQS_STRING_LENGTH, COMB)) { set_lp_entry(&e[i], buf); if (e[i].q != old_q) { /* switch to combining a new bunch, swapping the rows */ old_q = e[i].q; avma = av; /* discard old inv_q and Y1 */ if (!invmod(utoipos(old_q), h->N, &inv_q)) /* can happen --GN */ { inv_q = gcdii(inv_q, h->N); if (is_pm1(inv_q) || equalii(inv_q, h->N)) /* pity */ { #ifdef MPQS_DEBUG err_printf("MPQS: skipping relation with non-invertible q\n"); #endif old_q = -1; /* sentinel */ av2 = avma = av; continue; /* discard this combination */ } *f = gerepileuptoint(av0, inv_q); return c; } Y1 = strtoi(e[i].Y); i = 1 - i; /* subsequent relations go to other row */ av2 = avma; /* preserve inv_q and Y1 */ continue; } /* count and combine the two we've got, and continue in the same row */ c++; memset((void *)ei, 0, ei_size * sizeof(long)); mpqs_set_exponents(ei, e[0].E); mpqs_set_exponents(ei, e[1].E); Y2 = strtoi(e[i].Y); new_Y = modii(mulii(mulii(Y1, Y2), inv_q), h->N); new_Y1 = subii(h->N, new_Y); if (abscmpii(new_Y1, new_Y) < 0) new_Y = new_Y1; strcpy(new_relation, itostr(new_Y)); strcat(new_relation, " :"); if (ei[1] & 1) strcat(new_relation, " 1 1"); for (l = 2; l < ei_size; l++) if (ei[l]) { sprintf(buf, " %ld %ld", ei[l], l); strcat(new_relation, buf); } strcat(new_relation, " 0"); if (DEBUGLEVEL >= 6) { err_printf("MPQS: combining\n"); err_printf(" {%ld @ %s : %s}\n", old_q, e[1-i].Y, e[1-i].E); err_printf(" * {%ld @ %s : %s}\n", e[i].q, e[i].Y, e[i].E); err_printf(" == {%s}\n", new_relation); } strcat(new_relation, "\n"); #ifdef MPQS_DEBUG { GEN Qx_2, prod; char *s = strchr(new_relation, ':') + 2; pari_sp av1 = avma; Qx_2 = modii(sqri(new_Y), h->N); prod = mpqs_factorback(h, s); if (!equalii(Qx_2, prod)) pari_err_BUG("MPQS: combined large prime relation is false"); avma = av1; } #endif pari_fputs(new_relation, pFNEW); avma = av2; } /* while */ if (DEBUGLEVEL >= 4) err_printf("MPQS: combined %ld full relation%s\n", c, (c!=1 ? "s" : "")); avma = av0; return c; } /*********************************************************************/ /** **/ /** FROM RELATIONS TO DIVISORS **/ /** **/ /*********************************************************************/ /* create and read an F2m from a relation file FREL. * Also record the position of each relation in the file for later use * rows = size_of_FB+1, cols = rel */ static GEN stream_read_F2m(pariFILE *pFREL, long rows, long cols, long *fpos) { FILE *FREL = pFREL->file; long i, e, p; char buf[MPQS_STRING_LENGTH], *s; GEN m; long space = 2*((nbits2nlong(rows)+3)*cols+1); if ((long)((GEN)avma - (GEN)pari_mainstack->bot) < space) { pari_sp av = avma; m = gclone(zero_F2m(rows, cols)); if (DEBUGLEVEL>=4) err_printf("MPQS: allocating %ld words for Gauss\n",space); avma = av; } else m = zero_F2m_copy(rows, cols); for (i = 0;; i++) { char *tok=NULL; if (i < cols && (fpos[i] = ftell(FREL)) < 0) pari_err_FILE("full relations file [ftell]", pFREL->name); if (!fgets(buf, MPQS_STRING_LENGTH, FREL)) break; s = strchr(buf, ':'); if (!s) pari_err_FILE("full relations file [strchr]", pFREL->name); s = paristrtok_r(s+2, " \n", &tok); while (s != NULL) { e = atol(s); if (!e) break; s = paristrtok_r(NULL, " \n", &tok); p = atol(s); if (e & 1) F2m_set(m, p, i+1); s = paristrtok_r(NULL, " \n", &tok); } } if (i != cols) { err_printf("MPQS: full relations file %s than expected", i > cols ? "longer" : "shorter"); pari_err(e_BUG, "MPQS [panicking]"); } return m; } /* NB: overwrites rel */ static GEN mpqs_add_relation(GEN Y_prod, GEN N, long *ei, char *rel) { pari_sp av = avma; GEN res; char *s, *tok=NULL; s = strchr(rel, ':') - 1; *s = '\0'; res = remii(mulii(Y_prod, strtoi(rel)), N); s = paristrtok_r(s + 3, " \n", &tok); while (s != NULL) { long e = atol(s), i; if (!e) break; s = paristrtok_r(NULL, " \n", &tok); i = atol(s); /* bug in g++-3.4.1: miscompiles ei[ atol(s) ] */ ei[i] += e; s = paristrtok_r(NULL, " \n", &tok); } return gerepileuptoint(av, res); } static char* mpqs_get_relation(char *buf, long pos, pariFILE *pFREL) { if (fseek(pFREL->file, pos, SEEK_SET)) pari_err_FILE("FREL file [fseek]", pFREL->name); if (!fgets(buf, MPQS_STRING_LENGTH, pFREL->file)) pari_err_FILE("FREL file [fgets]", pFREL->name); return buf; } static int split(GEN N, GEN *e, GEN *res) { ulong mask; long flag; GEN base; if (MR_Jaeschke(N)) { *e = gen_1; return 1; } /* probable prime */ if (Z_issquareall(N, &base)) { /* squares could cost us a lot of time */ /* GN20050707: as used now, this is always called with res!=NULL */ *res = base; *e = gen_2; if (DEBUGLEVEL >= 5) err_printf("MPQS: decomposed a square\n"); return 1; } mask = 7; /* 5th/7th powers aren't worth the trouble. OTOH once we have the hooks for * dealing with cubes, higher powers can be handled essentially for free) */ if ( (flag = is_357_power(N, &base, &mask)) ) { *res = base; *e = utoipos(flag); if (DEBUGLEVEL >= 5) err_printf("MPQS: decomposed a %s\n", (flag == 3 ? "cube" : (flag == 5 ? "5th power" : "7th power"))); return 1; } *e = gen_0; return 0; /* known composite */ } static GEN mpqs_solve_linear_system(mpqs_handle_t *h, pariFILE *pFREL, long rel) { GEN N = h->N, X, Y_prod, X_plus_Y, D1, res, new_res; mpqs_FB_entry_t *FB = h->FB; pari_sp av=avma, av2, av3; long *fpos, *ei; long i, j, H_cols, H_rows; long res_last, res_next, res_size, res_max; GEN m, ker_m; long done, rank; char buf[MPQS_STRING_LENGTH]; fpos = (long *) pari_malloc(rel * sizeof(long)); m = stream_read_F2m(pFREL, h->size_of_FB+1, rel, fpos); if (DEBUGLEVEL >= 7) err_printf("\\\\ MATRIX READ BY MPQS\nFREL=%Ps\n",m); ker_m = F2m_ker_sp(m,0); rank = lg(ker_m)-1; if (isclone(m)) gunclone(m); if (DEBUGLEVEL >= 4) { if (DEBUGLEVEL >= 7) { err_printf("\\\\ KERNEL COMPUTED BY MPQS\n"); err_printf("KERNEL=%Ps\n",ker_m); } err_printf("MPQS: Gauss done: kernel has rank %ld, taking gcds...\n", rank); } H_rows = rel; H_cols = rank; if (!H_cols) { /* trivial kernel. Fail gracefully: main loop may look for more relations */ if (DEBUGLEVEL >= 3) pari_warn(warner, "MPQS: no solutions found from linear system solver"); pari_free(fpos); /* ei not yet allocated */ avma = av; return NULL; /* no factors found */ } /* If the rank is r, we can expect up to 2^r pairwise coprime factors, * but it may happen that a kernel basis vector contributes nothing new to * the decomposition. We allocate room for up to eight factors initially * (certainly adequate when one or two basis vectors work), adjusting this * down at the end to what we actually found, or up if we are very lucky and * find more factors. In the upper half of our vector, we store information * about which factors we know to be composite (zero) or believe to be * composite (NULL) or suspect to be prime (one), or an exponent (two * or some t_INT) if it is a proper power */ av2 = avma; if (rank > (long)BITS_IN_LONG - 2) res_max = LONG_MAX; /* the common case, unfortunately */ else res_max = 1L<size_of_FB + 2) * sizeof(long)); for (i = 1; i <= H_cols; i++) { /* loop over kernel basis */ X = Y_prod = gen_1; memset((void *)ei, 0, (h->size_of_FB + 2) * sizeof(long)); av3 = avma; for (j = 1; j <= H_rows; j++) { if (F2m_coeff(ker_m, j, i)) Y_prod = mpqs_add_relation(Y_prod, N, ei, mpqs_get_relation(buf, fpos[j-1], pFREL)); if (gc_needed(av3,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"[1]: mpqs_solve_linear_system"); Y_prod = gerepileuptoint(av3, Y_prod); } } Y_prod = gerepileuptoint(av3, Y_prod); av3 = avma; for (j = 2; j <= h->size_of_FB + 1; j++) if (ei[j]) { if (ei[j] & 1) pari_err_BUG("MPQS (relation is a nonsquare)"); X = remii(mulii(X, Fp_powu(utoipos(FB[j].fbe_p), (ulong)ei[j]>>1, N)), N); if (gc_needed(av3,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"[2]: mpqs_solve_linear_system"); X = gerepileupto(av3, X); } } X = gerepileuptoint(av3, X); if (MPQS_DEBUGLEVEL >= 1) { if (!dvdii(subii(sqri(X), sqri(Y_prod)), N)) { /* shouldn't happen */ err_printf("MPQS: X^2 - Y^2 != 0 mod N\n"); err_printf("\tindex i = %ld\n", i); pari_warn(warner, "MPQS: wrong relation found after Gauss"); } } /* At this point, X^2 == Y^2 mod N. Indeed, something stronger is true: * We have gcd(X-Y, N) * gcd(X+Y, N) == N. Why? * First, N divides X^2 - Y^2, so it divides the lefthand side. * Second, let P be any prime factor of N. If P were to divide both * X-Y and X+Y, then it would divide their sum 2X. But X (in the present * backwards notation!) is a product of powers of FB primes, and no FB * prime is a divisor of N, or we would have found out about it already * whilst constructing the FB. * Therefore in the following it is sufficient to work with gcd(X+Y, N) * alone, and never look at gcd(X-Y, N). */ done = 0; /* (re-)counts probably-prime factors (or powers whose bases we * don't want to handle any further) */ X_plus_Y = addii(X, Y_prod); if (res_next < 3) { /* we still haven't decomposed the original N, and want both a gcd and * its cofactor. */ D1 = gcdii(X_plus_Y, N); if (is_pm1(D1) || equalii(D1,N)) { avma = av3; continue; } /* got something that works */ if (DEBUGLEVEL >= 5) err_printf("MPQS: splitting N after %ld kernel vector%s\n", i+1, (i? "s" : "")); /* GN20050707 Fixed: * Don't divide N in place. We still need it for future X and Y_prod * computations! */ gel(res,1) = diviiexact(N, D1); gel(res,2) = D1; res_last = res_next = 3; if ( split(gel(res,1), &gel(res,res_size+1), &gel(res,1)) ) done++; if ( split(D1, &gel(res,res_size+2), &gel(res,2)) ) done++; if (done == 2) break; /* both factors look prime or were powers */ /* GN20050707: moved following line down to here, was before the * two split() invocations. Very rare case anyway. */ if (res_max == 2) break; /* two out of two possible factors seen */ if (DEBUGLEVEL >= 5) err_printf("MPQS: got two factors, looking for more...\n"); } else { /* we already have factors */ for (j=1; j < res_next; j++) { /* loop over known-composite factors */ if (gel(res,res_size+j) && gel(res,res_size+j) != gen_0) { done++; continue; /* skip probable primes etc */ } /* actually, also skip square roots of squares etc. They are a lot * smaller than the original N, and should be easy to deal with later */ av3 = avma; D1 = gcdii(X_plus_Y, gel(res,j)); if (is_pm1(D1) || equalii(D1, gel(res,j))) { avma = av3; continue; } /* got one which splits this factor */ if (DEBUGLEVEL >= 5) err_printf("MPQS: resplitting a factor after %ld kernel vectors\n", i+1); /* always plural */ /* first make sure there's room for another factor */ if (res_next > res_size) { /* need to reallocate (_very_ rare case) */ long i1, size = 2*res_size; GEN RES; if (size > res_max) size = res_max; RES = cgetg(2*size+1, t_VEC); for (i1=2*size; i1>=res_next; i1--) gel(RES,i1) = NULL; for (i1=1; i1 res_max) { /* all possible factors seen, outer loop postprocessing will * proceed to break out of the outer loop below. */ break; } } /* loop over known composite factors */ if (res_next > res_last) { res_last = res_next - 1; /* we might have resplit more than one */ if (DEBUGLEVEL >= 5) err_printf("MPQS: got %ld factors%s\n", res_last, (done < res_last ? ", looking for more..." : "")); res_last = res_next; } /* break out of the outer loop when we have seen res_max factors, and * also when all current factors are probable primes */ if (res_next > res_max || done == res_next - 1) break; } /* end case of further splitting of existing factors */ if (gc_needed(av2,1)) { long i1; if(DEBUGMEM>1) pari_warn(warnmem,"[3]: mpqs_solve_linear_system"); /* gcopy would have a problem with our NULL pointers... */ new_res = cgetg(lg(res), t_VEC); for (i1=2*res_size; i1>=res_next; i1--) new_res[i1] = 0; for (i1=1; i1= 6) err_printf("MPQS: wrapping up vector of %ld factors\n", res_last); for (i=1,j=1; i <= res_last; i++) { GEN F = gel(res, res_size+i); icopyifstack(gel(res,i), gel(new_res,j++)); /* factor */ gel(new_res,j++) = /* exponent */ F ? (F == gen_0 ? gen_1 : (isonstack(F) ? icopy(F) : F)) : gen_1; /* F was NULL */ gel(new_res,j++) = /* class */ F == gen_0 ? gen_0 : /* known composite */ NULL; /* base of power or suspected prime -- mark as `unknown' */ if (DEBUGLEVEL >= 6) err_printf("\tpackaging %ld: %Ps ^%ld (%s)\n", i, res[i], itos(gel(new_res,j-2)), (F == gen_0 ? "comp." : "unknown")); } return gerepileupto(av, new_res); } /*********************************************************************/ /** **/ /** MAIN ENTRY POINT AND DRIVER ROUTINE **/ /** **/ /*********************************************************************/ /* All percentages below are actually fixed-point quantities scaled by 10 * (value of 1 means 0.1%, 1000 means 100%) */ /* Factors N using the self-initializing multipolynomial quadratic sieve * (SIMPQS). Returns one of the two factors, or (usually) a vector of factors * and exponents and information about which ones are still composite, or NULL * when something goes wrong or when we can't seem to make any headway. */ /* TODO: this function to be renamed mpqs_main() with several extra parameters, * with mpqs() as a wrapper for the standard case, so we can do partial runs * across several machines etc. (from gp or a dedicated C program). --GN */ static GEN mpqs_i(mpqs_handle_t *handle) { GEN N = handle->N, fact; /* will in the end hold our factor(s) */ mpqs_int32_t size_of_FB; /* size of the factor base */ mpqs_FB_entry_t *FB; /* factor base */ mpqs_int32_t M; /* sieve interval size [-M, M] */ /* local loop / auxiliary vars */ ulong p; /* already exists in the handle, keep for convenience */ long lp_bound; /* size limit for large primes */ long lp_scale; /* ...relative to largest FB prime */ /* bookkeeping */ long tc; /* # of candidates found in one iteration */ long tp; /* # of recently sorted LP rels */ long tff = 0; /* # recently found full rels from sieving */ long tfc; /* # full rels recently combined from LPs */ double tfc_ratio = 0; /* recent (tfc + tff) / tff */ ulong sort_interval; /* determine when to sort and merge */ ulong followup_sort_interval; /* temporary files (scaled percentages) */ long percentage = 0; /* scaled by 10, see comment above */ double net_yield; long total_full_relations = 0, total_partial_relations = 0, total_no_cand = 0; long vain_iterations = 0, good_iterations = 0, iterations = 0; #ifdef MPQS_USE_HISTOGRAMS long histo_checkpoint = MPQS_MIN_CANDS_FOR_HISTO; #endif pariFILE *pFNEW, *pLPNEW, *pCOMB, *pFREL, *pLPREL; char *dir, *COMB_str, *FREL_str, *FNEW_str, *LPREL_str, *LPNEW_str, *TMP_str; pari_timer T; /* END: global variables to disappear as soon as possible */ /******************************/ pari_sp av = avma; if (DEBUGLEVEL >= 4) { timer_start(&T); err_printf("MPQS: number to factor N = %Ps\n", N); } handle->digit_size_N = decimal_len(N); if (handle->digit_size_N > MPQS_MAX_DIGIT_SIZE_KN) { pari_warn(warner, "MPQS: number too big to be factored with MPQS,\n\tgiving up"); return NULL; } if (DEBUGLEVEL >= 4) err_printf("MPQS: factoring number of %ld decimal digits\n", handle->digit_size_N); p = mpqs_find_k(handle); if (p) { avma = av; return utoipos(p); } if (DEBUGLEVEL >= 5) err_printf("MPQS: found multiplier %ld for N\n", handle->_k->k); handle->kN = muliu(N, handle->_k->k); if (!mpqs_set_parameters(handle)) { pari_warn(warner, "MPQS: number too big to be factored with MPQS,\n\tgiving up"); return NULL; } size_of_FB = handle->size_of_FB; M = handle->M; sort_interval = handle->first_sort_point; followup_sort_interval = handle->sort_pt_interval; if (DEBUGLEVEL >= 5) err_printf("MPQS: creating factor base and allocating arrays...\n"); FB = mpqs_create_FB(handle, &p); if (p) { avma = av; return utoipos(p); } mpqs_sieve_array_ctor(handle); mpqs_poly_ctor(handle); lp_bound = handle->largest_FB_p; if (lp_bound > MPQS_LP_BOUND) lp_bound = MPQS_LP_BOUND; /* don't allow large primes to have room for two factors both bigger than * what the FB contains (...yet!) */ lp_scale = handle->lp_scale; if (lp_scale >= handle->largest_FB_p) lp_scale = handle->largest_FB_p - 1; lp_bound *= lp_scale; handle->lp_bound = lp_bound; handle->dkN = gtodouble(handle->kN); /* compute the threshold and fill in the byte-sized scaled logarithms */ mpqs_set_sieve_threshold(handle); if (!mpqs_locate_A_range(handle)) return NULL; if (DEBUGLEVEL >= 4) { err_printf("MPQS: sieving interval = [%ld, %ld]\n", -(long)M, (long)M); /* that was a little white lie, we stop one position short at the top */ err_printf("MPQS: size of factor base = %ld\n", (long)size_of_FB); err_printf("MPQS: striving for %ld relations\n", (long)handle->target_no_rels); err_printf("MPQS: coefficients A will be built from %ld primes each\n", (long)handle->omega_A); err_printf("MPQS: primes for A to be chosen near FB[%ld] = %ld\n", (long)handle->index2_FB, (long)FB[handle->index2_FB].fbe_p); err_printf("MPQS: smallest prime used for sieving FB[%ld] = %ld\n", (long)handle->index1_FB, (long)FB[handle->index1_FB].fbe_p); err_printf("MPQS: largest prime in FB = %ld\n", (long)handle->largest_FB_p); err_printf("MPQS: bound for `large primes' = %ld\n", (long)lp_bound); } if (DEBUGLEVEL >= 5) { err_printf("MPQS: sieve threshold = %u\n", (unsigned int)handle->sieve_threshold); } if (DEBUGLEVEL >= 4) { err_printf("MPQS: first sorting at %ld%%, then every %3.1f%% / %3.1f%%\n", sort_interval/10, followup_sort_interval/10., followup_sort_interval/20.); } /* main loop which * - computes polynomials and their zeros (SI) * - does the sieving * - tests candidates of the sieve array */ /* Let (A, B_i) the current pair of coeffs. If i == 0 a new A is generated */ handle->index_j = (mpqs_uint32_t)-1; /* increment below will have it start at 0 */ if (DEBUGLEVEL >= 5) err_printf("MPQS: starting main loop\n"); /* compute names for the temp files we'll need */ dir = pari_unique_dir("MPQS"); TMP_str = mpqs_get_filename(dir, "LPTMP"); FREL_str = mpqs_get_filename(dir, "FREL"); FNEW_str = mpqs_get_filename(dir, "FNEW"); LPREL_str = mpqs_get_filename(dir, "LPREL"); LPNEW_str = mpqs_get_filename(dir, "LPNEW"); COMB_str = mpqs_get_filename(dir, "COMB"); #define unlink_all()\ pari_unlink(FREL_str);\ pari_unlink(FNEW_str);\ pari_unlink(LPREL_str);\ pari_unlink(LPNEW_str);\ if (pCOMB) pari_unlink(COMB_str);\ while(rmdir(dir)) \ { if (errno != ENOTEMPTY && errno != EEXIST) break; } \ pari_free(dir); pFREL = pari_fopen_or_fail(FREL_str, WRITE); pari_fclose(pFREL); pLPREL = pari_fopen_or_fail(LPREL_str, WRITE); pari_fclose(pLPREL); pFNEW = pari_fopen_or_fail(FNEW_str, WRITE); pLPNEW= pari_fopen_or_fail(LPNEW_str, WRITE); pCOMB = NULL; for(;;) { /* FNEW and LPNEW are open for writing */ iterations++; /* self initialization: compute polynomial and its zeros */ mpqs_self_init(handle); if (handle->bin_index == 0) { /* have run out of primes for A */ /* We might change some parameters. For the moment, simply give up */ if (DEBUGLEVEL >= 2) err_printf("MPQS: Ran out of primes for A, giving up.\n"); pari_fclose(pFNEW); pari_fclose(pLPNEW); /* FREL, LPREL are closed at this point */ unlink_all(); avma = av; return NULL; } memset((void*)(handle->sieve_array), 0, (M << 1) * sizeof(unsigned char)); mpqs_sieve(handle); tc = mpqs_eval_sieve(handle); total_no_cand += tc; if (DEBUGLEVEL >= 6) err_printf("MPQS: found %lu candidate%s\n", tc, (tc==1? "" : "s")); if (tc) { long t = mpqs_eval_cand(handle, tc, pFNEW->file, pLPNEW->file); total_full_relations += t; tff += t; good_iterations++; } #ifdef MPQS_USE_HISTOGRAMS if (handle->do_histograms && !handle->done_histograms && total_no_cand >= histo_checkpoint) { int res = mpqs_eval_histograms(handle); if (res >= 0) { /* retry later */ if (res > 0) /* histo_checkpoint *= 2.6; */ handle->do_histograms = 0; /* no, don't retry later */ else histo_checkpoint += (MPQS_MIN_CANDS_FOR_HISTO /* >> 1 */); } else handle->done_histograms = 1; } #endif percentage = (long)((1000.0 * total_full_relations) / handle->target_no_rels); if ((ulong)percentage < sort_interval) continue; /* most main loops continue here! */ /* Extra processing when we have completed a sort interval: */ if (DEBUGLEVEL >= 3) { if (DEBUGLEVEL >= 4) err_printf("\nMPQS: passing the %3.1f%% sort point, time = %ld ms\n", sort_interval/10., timer_delay(&T)); else err_printf("\nMPQS: passing the %3.1f%% sort point\n", sort_interval/10.); err_flush(); } /* sort LPNEW and merge it into LPREL, diverting combinables into COMB */ pari_fclose(pLPNEW); (void)mpqs_sort_lp_file(LPNEW_str); pCOMB = pari_fopen_or_fail(COMB_str, WRITE); tp = mpqs_mergesort_lp_file(LPREL_str, LPNEW_str, TMP_str, pCOMB); pari_fclose(pCOMB); pLPNEW = pari_fopen_or_fail(LPNEW_str, WRITE); /* combine whatever there is to be combined */ tfc = 0; if (tp > 0) { /* build full relations out of large prime relations */ pCOMB = pari_fopen_or_fail(COMB_str, READ); tfc = mpqs_combine_large_primes(handle, pCOMB->file, pFNEW, &fact); pari_fclose(pCOMB); /* now FREL, LPREL are closed and FNEW, LPNEW are still open */ if (fact) { /* factor found during combining */ if (DEBUGLEVEL >= 4) { err_printf("\nMPQS: split N whilst combining, time = %ld ms\n", timer_delay(&T)); err_printf("MPQS: found factor = %Ps\n", fact); } pari_fclose(pLPNEW); pari_fclose(pFNEW); unlink_all(); return gerepileupto(av, fact); } total_partial_relations += tp; } /* sort FNEW and merge it into FREL */ pari_fclose(pFNEW); (void)mpqs_sort_lp_file(FNEW_str); /* definitive count (combinables combined, and duplicates removed) */ total_full_relations = mpqs_mergesort_lp_file(FREL_str, FNEW_str, TMP_str, NULL); /* FNEW stays closed until we need to reopen it for another iteration */ /* Due to the removal of duplicates, percentage may actually decrease at * this point. Looks funny in the diagnostics but is nothing to worry * about: we _are_ making progress. */ percentage = (long)((1000.0 * total_full_relations) / handle->target_no_rels); net_yield = (total_full_relations * 100.) / (total_no_cand ? total_no_cand : 1); vain_iterations = (long)((1000.0 * (iterations - good_iterations)) / iterations); /* Now estimate the current full relations yield rate: we directly see * each time through the main loop how many full relations we're getting * as such from the sieve (tff since the previous checkpoint), but * only at checkpoints do we see how many we're typically combining * (tfc). So we're really producing (tfc+tff)/tff as many full rels, * and when we get close to 100%, we should bias the next interval by * the inverse ratio. * Avoid drawing conclusions from too-small samples during very short * follow-on intervals (in this case we'll just re-use an earlier * estimated ratio). */ if ((tfc >= 16) && (tff >= 20)) tfc_ratio = (tfc + tff + 0.) / tff; /* floating-point division */ tff = 0; /* reset this count (tfc is always fresh) */ if (percentage >= 1000) /* when Gauss had failed */ sort_interval = percentage + 2; else if (percentage >= 820) { if (tfc_ratio > 1.) { if (percentage + (followup_sort_interval >> 1) * tfc_ratio > 994) { /* aim for a _slight_ overshoot */ sort_interval = (ulong)(percentage + 2 + (1000 - percentage) / tfc_ratio); } else if (percentage >= 980) sort_interval = percentage + 8; else sort_interval = percentage + (followup_sort_interval >> 1); } else { if (percentage >= 980) sort_interval = percentage + 10; else sort_interval = percentage + (followup_sort_interval >> 1); if (sort_interval >= 1000 && percentage < 1000) sort_interval = 1000; } } else sort_interval = percentage + followup_sort_interval; if (DEBUGLEVEL >= 4) { err_printf("MPQS: done sorting%s, time = %ld ms\n", tp > 0 ? " and combining" : "", timer_delay(&T)); err_printf("MPQS: found %3.1f%% of the required relations\n", percentage/10.); if (DEBUGLEVEL >= 5) { /* total_full_relations are always plural */ /* GN20050708: present code doesn't succeed in discarding all * dups, so don't lie about it... */ err_printf("MPQS: found %ld full relations\n", total_full_relations); if (lp_scale > 1) err_printf("MPQS: (%ld of these from partial relations)\n", total_partial_relations); err_printf("MPQS: Net yield: %4.3g full relations per 100 candidates\n", net_yield); err_printf("MPQS: %4.3g full relations per 100 polynomials\n", (total_full_relations * 100.) / iterations); err_printf("MPQS: %4.1f%% of the polynomials yielded no candidates\n", vain_iterations/10.); err_printf("MPQS: next sort point at %3.1f%%\n", sort_interval/10.); } } if (percentage < 1000) { pFNEW = pari_fopen_or_fail(FNEW_str, WRITE); /* LPNEW and FNEW are again open for writing */ continue; /* main loop */ } /* percentage >= 1000, which implies total_full_relations > size_of_FB: try finishing it off */ /* solve the system over F_2 */ /* present code does NOT in fact guarantee absence of dup FRELs, * therefore removing the adjective "distinct" for the time being */ if (DEBUGLEVEL >= 4) err_printf("\nMPQS: starting Gauss over F_2 on %ld relations\n", total_full_relations); pFREL = pari_fopen_or_fail(FREL_str, READ); fact = mpqs_solve_linear_system(handle, pFREL, total_full_relations); pari_fclose(pFREL); if (fact) { /* solution found */ if (DEBUGLEVEL >= 4) { err_printf("\nMPQS: time in Gauss and gcds = %ld ms\n", timer_delay(&T)); if (typ(fact) == t_INT) err_printf("MPQS: found factor = %Ps\n", fact); else { long j, nf = (lg(fact)-1)/3; if (nf == 2) /* GN20050707: Changed the arrangement of the two factors, * to match the debug diagnostics in mpqs_solve_linear_system() * above */ err_printf("MPQS: found factors = %Ps\n\tand %Ps\n", fact[1], fact[4]); else { /* GN20050707: Changed loop to scan upwards instead of downwards, * to match the debug diagnostics in mpqs_solve_linear_system() * above */ err_printf("MPQS: found %ld factors =\n", nf); for (j=1; j<=nf; j++) err_printf("\t%Ps%s\n", fact[3*j-2], (j= 4) { err_printf("\nMPQS: time in Gauss and gcds = %ld ms\n",timer_delay(&T)); err_printf("MPQS: no factors found.\n"); if (percentage <= MPQS_ADMIT_DEFEAT) err_printf("\nMPQS: restarting sieving ...\n"); else err_printf("\nMPQS: giving up.\n"); } if (percentage > MPQS_ADMIT_DEFEAT) { pari_fclose(pLPNEW); unlink_all(); avma = av; return NULL; } pFNEW = pari_fopen_or_fail(FNEW_str, WRITE); } } /* main loop */ } GEN mpqs(GEN N) { mpqs_handle_t *handle = mpqs_handle_ctor(N); GEN fact = mpqs_i(handle); mpqs_handle_dtor(handle); return fact; } pari-2.11.2/src/modules/part.c0000644000175000017500000002577313326135265014553 0ustar billbill/* Copyright (C) 2002 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Original code contributed by: Ralf Stephan (ralf@ark.in-berlin.de). * Updated by Bill Allombert (2014) to use Selberg formula for L * following http://dx.doi.org/10.1112/S1461157012001088 * * This program is basically the implementation of the script * * Psi(n, q) = my(a=sqrt(2/3)*Pi/q, b=n-1/24, c=sqrt(b)); * (sqrt(q)/(2*sqrt(2)*b*Pi))*(a*cosh(a*c)-(sinh(a*c)/c)) * L(n,q)=sqrt(k/3)*sum(l=0,2*k-1, if(((3*l^2+l)/2+n)%k==0,(-1)^l*cos((6*l+1)/(6*k)*Pi))) * part(n) = round(sum(q=1,5 + 0.24*sqrt(n),L(n,q)*Psi(n,q))) * * only faster. * * ------------------------------------------------------------------ * The first restriction depends on Pari's maximum precision of floating * point reals, which is 268435454 bits in 2.2.4, since the algorithm needs * high precision exponentials. For that engine, the maximum possible argument * would be in [5*10^15,10^16], the computation of which would need days on * a ~1-GHz computer. */ #include "pari.h" #include "paripriv.h" /****************************************************************/ /* Given c = sqrt(2/3)*Pi*sqrt(N-1/24) * Psi(N, q) = my(a = c/q); sqrt(q) * (a*cosh(a) - sinh(a)) */ static GEN psi(GEN c, ulong q, long prec) { GEN a = divru(c, q), ea = mpexp(a), invea = invr(ea); GEN cha = shiftr(addrr(ea, invea), -1); /* ch(a) */ GEN sha = shiftr(subrr(ea, invea), -1); /* sh(a) */ return mulrr(sqrtr(stor(q,prec)), subrr(mulrr(a,cha), sha)); } /* L(n,q)=sqrt(k/3)*sum(l=0,2*k-1, if(((3*l^2+l)/2+n)%k==0,(-1)^l*cos((6*l+1)/(6*k)*Pi))) * Never called with q < 3, so ignore this case */ static GEN L(GEN n, ulong k, long bitprec) { ulong r, l, m; long pr = nbits2prec(bitprec / k + k); GEN s = stor(0,pr), pi = mppi(pr); pari_sp av = avma; r = 2; m = umodiu(n,k); for (l = 0; l < 2*k; l++) { if (m == 0) { GEN c = mpcos(divru(mulru(pi, 6*l+1), 6*k)); if (odd(l)) subrrz(s, c, s); else addrrz(s, c, s); avma = av; } m += r; if (m >= k) m -= k; r += 3; if (r >= k) r -= k; } /* multiply by sqrt(k/3) */ return mulrr(s, sqrtr((k % 3)? rdivss(k,3,pr): utor(k/3,pr))); } /* Return a low precision estimate of log p(n). */ static GEN estim(GEN n) { pari_sp av = avma; GEN p1, pi = mppi (DEFAULTPREC); p1 = divru( itor(shifti(n,1), DEFAULTPREC), 3 ); p1 = mpexp( mulrr(pi, sqrtr(p1)) ); /* exp(Pi * sqrt(2N/3)) */ p1 = divri (shiftr(p1,-2), n); p1 = divrr(p1, sqrtr( stor(3,DEFAULTPREC) )); return gerepileupto(av, mplog(p1)); } /* c = sqrt(2/3)*Pi*sqrt(n-1/24); d = 1 / ((2*b)^(3/2) * Pi); */ static void pinit(GEN n, GEN *c, GEN *d, ulong prec) { GEN b = divru( itor( subiu(muliu(n,24), 1), prec ), 24 ); /* n - 1/24 */ GEN sqrtb = sqrtr(b), Pi = mppi(prec), pi2sqrt2, pisqrt2d3; pisqrt2d3 = mulrr(Pi, sqrtr( divru(stor(2, prec), 3) )); pi2sqrt2 = mulrr(Pi, sqrtr( stor(8, prec) )); *c = mulrr(pisqrt2d3, sqrtb); *d = invr( mulrr(pi2sqrt2, mulrr(b,sqrtb)) ); } /* part(n) = round(sum(q=1,5 + 0.24*sqrt(n), L(n,q)*Psi(n,q))) */ GEN numbpart(GEN n) { pari_sp ltop = avma, av; GEN sum, est, C, D, p1, p2; long prec, bitprec; ulong q; if (typ(n) != t_INT) pari_err_TYPE("partition function",n); if (signe(n) < 0) return gen_0; if (abscmpiu(n, 2) < 0) return gen_1; if (cmpii(n, uu32toi(0x38d7e, 0xa4c68000)) >= 0) pari_err_OVERFLOW("numbpart [n < 10^15]"); est = estim(n); bitprec = (long)(rtodbl(est)/M_LN2) + 32; prec = nbits2prec(bitprec); pinit(n, &C, &D, prec); sum = cgetr (prec); affsr(0, sum); /* Because N < 10^16 and q < sqrt(N), q fits into a long * In fact q < 2 LONG_MAX / 3 */ av = avma; togglesign(est); for (q = (ulong)(sqrt(gtodouble(n))*0.24 + 5); q >= 3; q--, avma=av) { GEN t = L(n, q, bitprec); if (abscmprr(t, mpexp(divru(est,q))) < 0) continue; t = mulrr(t, psi(gprec_w(C, nbits2prec(bitprec / q + 32)), q, prec)); affrr(addrr(sum, t), sum); } p1 = addrr(sum, psi(C, 1, prec)); p2 = psi(C, 2, prec); affrr(mod2(n)? subrr(p1,p2): addrr(p1,p2), sum); return gerepileuptoint (ltop, roundr(mulrr(D,sum))); } /* for loop over partitions of integer k. * nbounds can restrict partitions to have length between nmin and nmax * (the length is the number of non zero entries) and * abounds restrict to integers between amin and amax. * * Start from central partition. * By default, remove zero entries on the left. * * Algorithm: * * A partition of k is an increasing sequence v1,... vn with sum(vi)=k * The starting point is the minimal n-partition of k: a,...a,a+1,.. a+1 * (a+1 is repeated r times with k = a * n + r). * * The procedure to obtain the next partition: * - find the last index i*amax || *amin<0 || *amax<=0) pari_err_TYPE("forpart [expect 0<=min<=max, 0amin=1; if (abound) parse_interval(abound,&T->amin,&T->amax); else T->amax = k; /* strip leading zeros ? */ T->strip = (T->amin > 0) ? 1 : 0; /* bound on number of non-zero coefficients */ T->nmin=0; if (nbound) parse_interval(nbound,&T->nmin,&T->nmax); else T->nmax = k; /* non empty if nmin*amin <= k <= amax*nmax */ if ( T->amin*T->nmin > k || k > T->amax * T->nmax ) { T->nmin = T->nmax = 0; } else { /* to reach nmin one must have k <= nmin*amax, otherwise increase nmin */ if ( T->nmin * T->amax < k ) T->nmin = 1 + (k - 1) / T->amax; /* ceil( k/tmax ) */ /* decrease nmax (if strip): k <= amin*nmax */ if (T->strip && T->nmax > k/T->amin) T->nmax = k / T->amin; /* strip implies amin>0 */ /* fixme: take ceil( ) */ /* no need to change amin */ /* decrease amax if amax + (nmin-1)*amin > k */ if ( T->amax + (T->nmin-1)* T->amin > k ) T->amax = k - (T->nmin-1)* T->amin; } if ( T->amax < T->amin ) T->nmin = T->nmax = 0; T->v = zero_zv(T->nmax); /* partitions will be of length <= nmax */ T->k = k; } GEN forpart_next(forpart_t *T) { GEN v = T->v; long n = lg(v)-1; long i, s, a, k, vi, vn; if (n>0 && v[n]) { /* find index to increase: i s.t. v[i+1],...v[n] is central a,..a,a+1,..a+1 keep s = v[i] + v[i+1] + ... + v[n] */ s = a = v[n]; for(i = n-1; i>0 && v[i]+1 >= a; s += v[i--]); if (i == 0) { /* v is central [ a, a, .. a, a+1, .. a+1 ] */ if ((n+1) * T->amin > s || n == T->nmax) return NULL; i = 1; n++; setlg(v, n+1); vi = T->amin; } else { s += v[i]; vi = v[i]+1; } } else { /* init v */ s = T->k; if (T->amin == 0) T->amin = 1; if (T->strip) { n = T->nmin; setlg(T->v, n+1); } if (s==0) { if (n==0 && T->nmin==0) {T->nmin++; return v;} return NULL; } if (n==0) return NULL; vi = T->amin; i = T->strip ? 1 : n + 1 - T->nmin; /* first non-zero index */ if (s <= (n-i)*vi) return NULL; } /* now fill [ v[i],... v[n] ] with s, start at vi */ vn = s - (n-i)*vi; /* expected value for v[n] */ if (T->amax && vn > T->amax) { /* do not exceed amax */ long ai, q, r; vn -= vi; ai = T->amax - vi; q = vn / ai; /* number of nmax */ r = vn % ai; /* value before nmax */ /* fill [ v[i],... v[n] ] as [ vi,... vi, vi+r, amax,... amax ] */ while ( q-- ) v[n--] = T->amax; if ( n >= i ) v[n--] = vi + r; while ( n >= i ) v[n--] = vi; } else { /* fill as [ v[i], ... v[i], vn ] */ for ( k=i; kv; long n = lg(v)-1; long j, ni, q, r; long i, s; if (n>0 && v[n]) { /* find index to decrease: start of last constant sequence, excluding v[n] */ i = n-1; s = v[n]; while (i>1 && (v[i-1]==v[i] || v[i+1]==T->amax)) s+= v[i--]; if (!i) return NULL; /* amax condition: cannot decrease i if maximal on the right */ if ( v[i+1] == T->amax ) return NULL; /* amin condition: stop if below except if strip & try to remove */ if (v[i] == T->amin) { if (!T->strip) return NULL; s += v[i]; v[i] = 0; } else { v[i]--; s++; } /* zero case... */ if (v[i] == 0) { if (T->nmin > n-i) return NULL; /* need too many non zero coeffs */ /* reduce size of v ? */ if (T->strip) { i = 0; n--; setlg(v, n+1); } } } else { s = T->k; i = 0; if (s==0) { if (n==0 && T->nmin==0) {T->nmin++; return v;} return NULL; } if (n*T->amax < s || s < T->nmin*T->amin) return NULL; } /* set minimal partition of sum s starting from index i+1 */ ni = n-i; q = s / ni; r = s % ni; for(j=i+1; j<=n-r; j++) v[j]=q; for(j=n-r+1; j<=n; j++) v[j]=q + 1; return v; } static long countpart(long k, GEN abound, GEN nbound) { pari_sp av = avma; long n; forpart_t T; if (k<0) return 0; forpart_init(&T, k, abound, nbound); for (n=0; forpart_next(&T); n++) avma = av; return n; } GEN partitions(long k, GEN abound, GEN nbound) { GEN v; forpart_t T; long i, n = countpart(k,abound,nbound); if (n==0) return cgetg(1, t_VEC); forpart_init(&T, k, abound, nbound); v = cgetg(n+1, t_VEC); for (i=1; i<=n; i++) gel(v,i)=zv_copy(forpart_next(&T)); return v; } void forpart(void *E, long call(void*, GEN), long k, GEN abound, GEN nbound) { pari_sp av = avma; GEN v; forpart_t T; forpart_init(&T, k, abound, nbound); while ((v=forpart_next(&T))) if (call(E, v)) break; avma=av; } void forpart0(GEN k, GEN code, GEN abound, GEN nbound) { pari_sp av = avma; if (typ(k) != t_INT) pari_err_TYPE("forpart",k); if (signe(k)<0) return; push_lex(gen_0, code); forpart((void*)code, &gp_evalvoid, itos(k), abound, nbound); pop_lex(1); avma=av; } pari-2.11.2/src/modules/stark.c0000644000175000017500000030110113326135265014707 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* COMPUTATION OF STARK UNITS OF TOTALLY REAL FIELDS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" static const long EXTRA_PREC = DEFAULTPREC-2; /* ComputeCoeff */ typedef struct { GEN L0, L1, L11, L2; /* VECSMALL of p */ GEN L1ray, L11ray; /* precomputed isprincipalray(pr), pr | p */ GEN rayZ; /* precomputed isprincipalray(i), i < condZ */ long condZ; /* generates cond(bnr) \cap Z, assumed small */ } LISTray; /* Char evaluation */ typedef struct { long ord; GEN *val, chi; } CHI_t; /* RecCoeff */ typedef struct { GEN M, beta, B, U, nB; long v, G, N; } RC_data; /********************************************************************/ /* Miscellaneous functions */ /********************************************************************/ static GEN chi_get_c(GEN chi) { return gmael(chi,1,2); } static GEN chi_get_gdeg(GEN chi) { return gmael(chi,1,1); } static long chi_get_deg(GEN chi) { return itou(chi_get_gdeg(chi)); } /* Compute the image of logelt by character chi, as a complex number */ static ulong CharEval_n(GEN chi, GEN logelt) { GEN gn = ZV_dotproduct(chi_get_c(chi), logelt); return umodiu(gn, chi_get_deg(chi)); } /* Compute the image of logelt by character chi, as a complex number */ static GEN CharEval(GEN chi, GEN logelt) { ulong n = CharEval_n(chi, logelt), d = chi_get_deg(chi); long nn = Fl_center(n,d,d>>1); GEN x = gel(chi,2); x = gpowgs(x, labs(nn)); if (nn < 0) x = conj_i(x); return x; } /* return n such that C(elt) = z^n */ static ulong CHI_eval_n(CHI_t *C, GEN logelt) { GEN n = ZV_dotproduct(C->chi, logelt); return umodiu(n, C->ord); } /* return C(elt) */ static GEN CHI_eval(CHI_t *C, GEN logelt) { return C->val[CHI_eval_n(C, logelt)]; } static void init_CHI(CHI_t *c, GEN CHI, GEN z) { long i, d = chi_get_deg(CHI); GEN *v = (GEN*)new_chunk(d); v[0] = gen_1; if (d != 1) { v[1] = z; for (i=2; ichi = chi_get_c(CHI); c->ord = d; c->val = v; } /* as t_POLMOD */ static void init_CHI_alg(CHI_t *c, GEN CHI) { long d = chi_get_deg(CHI); GEN z; switch(d) { case 1: z = gen_1; break; case 2: z = gen_m1; break; default: z = mkpolmod(pol_x(0), polcyclo(d,0)); } init_CHI(c,CHI, z); } /* as t_COMPLEX */ static void init_CHI_C(CHI_t *c, GEN CHI) { init_CHI(c,CHI, gel(CHI,2)); } typedef struct { long r; /* rank = lg(gen) */ GEN j; /* current elt is gen[1]^j[1] ... gen[r]^j[r] */ GEN cyc; /* t_VECSMALL of elementary divisors */ } GROUP_t; static int NextElt(GROUP_t *G) { long i = 1; if (G->r == 0) return 0; /* no more elt */ while (++G->j[i] == G->cyc[i]) /* from 0 to cyc[i]-1 */ { G->j[i] = 0; if (++i > G->r) return 0; /* no more elt */ } return i; /* we have multiplied by gen[i] */ } /* Compute all the elements of a group given by its SNF */ static GEN EltsOfGroup(long order, GEN cyc) { long i; GEN rep; GROUP_t G; G.cyc = gtovecsmall(cyc); G.r = lg(cyc)-1; G.j = zero_zv(G.r); rep = cgetg(order + 1, t_VEC); gel(rep,order) = vecsmall_to_col(G.j); for (i = 1; i < order; i++) { (void)NextElt(&G); gel(rep,i) = vecsmall_to_col(G.j); } return rep; } /* enumerate all group elements */ GEN cyc2elts(GEN cyc) { long i, n; GEN z; GROUP_t G; G.cyc = typ(cyc)==t_VECSMALL? cyc: gtovecsmall(cyc); n = zv_prod(G.cyc); G.r = lg(cyc)-1; G.j = zero_zv(G.r); z = cgetg(n+1, t_VEC); gel(z,n) = leafcopy(G.j); /* trivial elt comes last */ for (i = 1; i < n; i++) { (void)NextElt(&G); gel(z,i) = leafcopy(G.j); } return z; } /* Let Qt as given by InitQuotient, compute a system of representatives of the quotient */ static GEN ComputeLift(GEN Qt) { GEN e, U = gel(Qt,3); long i, h = itos(gel(Qt,1)); e = EltsOfGroup(h, gel(Qt,2)); if (!RgM_isidentity(U)) { GEN Ui = ZM_inv(U,NULL); for (i = 1; i <= h; i++) gel(e,i) = ZM_ZC_mul(Ui, gel(e,i)); } return e; } /* nchi: a character given by a vector [d, (c_i)], e.g. from char_normalize * such that chi(x) = e((c . log(x)) / d) where log(x) on bnr.gen */ static GEN get_Char(GEN nchi, long prec) { return mkvec2(nchi, rootsof1_cx(gel(nchi,1), prec)); } /* prime divisors of conductor */ static GEN divcond(GEN bnr) {GEN bid = bnr_get_bid(bnr); return gel(bid_get_fact(bid),1);} /* vector of prime ideals dividing bnr but not bnrc */ static GEN get_prdiff(GEN bnr, GEN condc) { GEN prdiff, M = gel(condc,1), D = divcond(bnr), nf = bnr_get_nf(bnr); long nd, i, l = lg(D); prdiff = cgetg(l, t_COL); for (nd=1, i=1; i < l; i++) if (!idealval(nf, M, gel(D,i))) gel(prdiff,nd++) = gel(D,i); setlg(prdiff, nd); return prdiff; } #define ch_C(x) gel(x,1) #define ch_bnr(x) gel(x,2) #define ch_4(x) gel(x,3) #define ch_CHI(x) gel(x,4) #define ch_diff(x) gel(x,5) #define ch_cond(x) gel(x,6) #define ch_CHI0(x) gel(x,7) #define ch_comp(x) gel(x,8) static long ch_deg(GEN dtcr) { return chi_get_deg(ch_CHI(dtcr)); } static GEN GetDeg(GEN dataCR) { long i, l = lg(dataCR); GEN degs = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) degs[i] = eulerphiu(ch_deg(gel(dataCR,i))); return degs; } /********************************************************************/ /* 1rst part: find the field K */ /********************************************************************/ static GEN AllStark(GEN data, GEN nf, long flag, long prec); /* Columns of C [HNF] give the generators of a subgroup of the finite abelian * group A [ in terms of implicit generators ], compute data to work in A/C: * 1) order * 2) structure * 3) the matrix A ->> A/C * 4) the subgroup C */ static GEN InitQuotient(GEN C) { GEN U, D = ZM_snfall_i(C, &U, NULL, 1), h = ZV_prod(D); return mkvec5(h, D, U, C, cyc_normalize(D)); } /* lift chi character on A/C [Qt from InitQuotient] to character on A [cyc]*/ static GEN LiftChar(GEN Qt, GEN cyc, GEN chi) { GEN ncyc = gel(Qt,5), U = gel(Qt,3); GEN nchi = char_normalize(chi, ncyc); GEN c = ZV_ZM_mul(gel(nchi,2), U), d = gel(nchi,1); return char_denormalize(cyc, d, c); } /* Let s: A -> B given by P, and let cycA, cycB be the cyclic structure of * A and B, compute the kernel of s. */ static GEN ComputeKernel0(GEN P, GEN cycA, GEN cycB) { pari_sp av = avma; long nbA = lg(cycA)-1, rk; GEN U, DB = diagonal_shallow(cycB); rk = nbA + lg(cycB) - lg(ZM_hnfall_i(shallowconcat(P, DB), &U, 1)); U = matslice(U, 1,nbA, 1,rk); return gerepileupto(av, ZM_hnfmodid(U, cycA)); } /* Let m and n be two moduli such that n|m and let C be a congruence group modulo n, compute the corresponding congruence group modulo m ie the kernel of the map Clk(m) ->> Clk(n)/C */ static GEN ComputeKernel(GEN bnrm, GEN bnrn, GEN dtQ) { pari_sp av = avma; GEN P = ZM_mul(gel(dtQ,3), bnrsurjection(bnrm, bnrn)); return gerepileupto(av, ComputeKernel0(P, bnr_get_cyc(bnrm), gel(dtQ,2))); } static long cyc_is_cyclic(GEN cyc) { return lg(cyc) <= 2 || equali1(gel(cyc,2)); } /* Let H be a subgroup of cl(bnr)/sugbroup, return 1 if cl(bnr)/subgoup/H is cyclic and the signature of the corresponding field is equal to sig and no finite prime dividing cond(bnr) is totally split in this field. Return 0 otherwise. */ static long IsGoodSubgroup(GEN H, GEN bnr, GEN map) { pari_sp av = avma; GEN mod, modH, p1, p2, U, P, PH, bnrH, iH, qH; long j; p1 = InitQuotient(H); /* quotient is non cyclic */ if (!cyc_is_cyclic(gel(p1,2))) { avma = av; return 0; } p2 = ZM_hnfall_i(shallowconcat(map,H), &U, 0); setlg(U, lg(H)); for (j = 1; j < lg(U); j++) setlg(gel(U,j), lg(H)); p1 = ZM_hnfmodid(U, bnr_get_cyc(bnr)); /* H as a subgroup of bnr */ modH = bnrconductor_i(bnr, p1, 0); mod = bnr_get_mod(bnr); /* is the signature correct? */ if (!gequal(gel(modH,2), gel(mod,2))) { avma = av; return 0; } /* finite part are the same: OK */ if (gequal(gel(modH,1), gel(mod,1))) { avma = av; return 1; } /* need to check the splitting of primes dividing mod but not modH */ bnrH = Buchray(bnr, modH, nf_INIT); P = divcond(bnr); PH = divcond(bnrH); p2 = ZM_mul(bnrsurjection(bnr, bnrH), p1); /* H as a subgroup of bnrH */ iH = ZM_hnfmodid(p2, bnr_get_cyc(bnrH)); qH = InitQuotient(iH); for (j = 1; j < lg(P); j++) { GEN pr = gel(P, j), e; /* if pr divides modH, it is ramified, so it's good */ if (tablesearch(PH, pr, cmp_prime_ideal)) continue; /* inertia degree of pr in bnr(modH)/H is charorder(e, cycH) */ e = ZM_ZC_mul(gel(qH,3), isprincipalray(bnrH, pr)); e = vecmodii(e, gel(qH,2)); if (ZV_equal0(e)) { avma = av; return 0; } /* f = 1 */ } avma = av; return 1; } /* compute the list of characters to consider for AllStark and initialize precision-independent data to compute with them */ static GEN get_listCR(GEN bnr, GEN dtQ) { GEN listCR, vecchi, Mr; long hD, h, nc, i, tnc; hashtable *S; Mr = bnr_get_cyc(bnr); hD = itos(gel(dtQ,1)); h = hD >> 1; listCR = cgetg(h+1, t_VEC); /* non-conjugate chars */ nc = tnc = 1; vecchi = EltsOfGroup(hD, gel(dtQ,2)); S = hash_create(h, (ulong(*)(void*))&hash_GEN, (int(*)(void*,void*))&ZV_equal, 1); for (i = 1; tnc <= h; i++) { /* lift a character of D in Clk(m) */ GEN cond, lchi = LiftChar(dtQ, Mr, gel(vecchi,i)); if (hash_search(S, lchi)) continue; cond = bnrconductorofchar(bnr, lchi); if (gequal0(gel(cond,2))) continue; /* the infinite part of chi is non trivial */ gel(listCR,nc++) = mkvec2(lchi, cond); /* if chi is not real, add its conjugate character to S */ if (absequaliu(charorder(Mr,lchi), 2)) tnc++; else { hash_insert(S, charconj(Mr, lchi), (void*)1); tnc+=2; } } setlg(listCR, nc); return listCR; } static GEN InitChar(GEN bnr, GEN listCR, long prec); /* Given a conductor and a subgroups, return the corresponding complexity and precision required using quickpol. Fill data[5] with listCR */ static long CplxModulus(GEN data, long *newprec) { long pr, ex, dprec = DEFAULTPREC; pari_sp av; GEN pol, listCR, cpl, bnr = gel(data,1), nf = checknf(bnr); listCR = get_listCR(bnr, gel(data,3)); for (av = avma;; avma = av) { gel(data,5) = InitChar(bnr, listCR, dprec); pol = AllStark(data, nf, -1, dprec); pr = nbits2extraprec( gexpo(pol) ); if (pr < 0) pr = 0; dprec = maxss(dprec, pr) + EXTRA_PREC; if (!gequal0(leading_coeff(pol))) { cpl = RgX_fpnorml2(pol, DEFAULTPREC); if (!gequal0(cpl)) break; } if (DEBUGLEVEL>1) pari_warn(warnprec, "CplxModulus", dprec); } ex = gexpo(cpl); avma = av; if (DEBUGLEVEL>1) err_printf("cpl = 2^%ld\n", ex); gel(data,5) = listCR; *newprec = dprec; return ex; } /* return A \cap B in abelian group defined by cyc. NULL = whole group */ static GEN subgp_intersect(GEN cyc, GEN A, GEN B) { GEN H, U; long k, lH; if (!A) return B; if (!B) return A; H = ZM_hnfall_i(shallowconcat(A,B), &U, 1); setlg(U, lg(A)); lH = lg(H); for (k = 1; k < lg(U); k++) setlg(gel(U,k), lH); return ZM_hnfmodid(ZM_mul(A,U), cyc); } /* Let f be a conductor without infinite part and let C be a congruence group modulo f, compute (m,D) such that D is a congruence group of conductor m where m is a multiple of f divisible by all the infinite places but one, D is a subgroup of index 2 of Im(C) in Clk(m), and m is such that the intersection of the subgroups H of Clk(m)/D such that the quotient is cyclic and no prime divding m, but the one infinite prime, is totally split in the extension corresponding to H is trivial. Return bnr(m), D, the quotient Ck(m)/D and Clk(m)/Im(C) */ static GEN FindModulus(GEN bnr, GEN dtQ, long *newprec) { const long limnorm = 400; long n, i, narch, maxnorm, minnorm, N; long first = 1, pr, rb, oldcpl = -1, iscyc; pari_sp av = avma; GEN bnf, nf, f, arch, m, rep = NULL; bnf = bnr_get_bnf(bnr); nf = bnf_get_nf(bnf); N = nf_get_degree(nf); f = gel(bnr_get_mod(bnr), 1); /* if cpl < rb, it is not necessary to try another modulus */ rb = expi( powii(mulii(nf_get_disc(nf), ZM_det_triangular(f)), gmul2n(bnr_get_no(bnr), 3)) ); /* Initialization of the possible infinite part */ arch = const_vec(N, gen_1); /* narch = (N == 2)? 1: N; -- if N=2, only one case is necessary */ narch = N; m = mkvec2(NULL, arch); /* go from minnorm up to maxnorm. If necessary, increase these values. * If we cannot find a suitable conductor of norm < limnorm, stop */ maxnorm = 50; minnorm = 1; /* if the extension is cyclic then we _must_ find a suitable conductor */ iscyc = cyc_is_cyclic(gel(dtQ,2)); if (DEBUGLEVEL>1) err_printf("Looking for a modulus of norm: "); for(;;) { GEN listid = ideallist0(nf, maxnorm, 4+8); /* ideals of norm <= maxnorm */ pari_sp av1 = avma; for (n = minnorm; n <= maxnorm; n++, avma = av1) { GEN idnormn = gel(listid,n); long nbidnn = lg(idnormn) - 1; if (DEBUGLEVEL>1) err_printf(" %ld", n); for (i = 1; i <= nbidnn; i++) { /* finite part of the conductor */ long s; gel(m,1) = idealmul(nf, f, gel(idnormn,i)); for (s = 1; s <= narch; s++) { /* infinite part */ GEN candD, ImC, bnrm; long nbcand, c; gel(arch,N+1-s) = gen_0; /* compute Clk(m), check if m is a conductor */ bnrm = Buchray(bnf, m, nf_INIT); c = bnrisconductor(bnrm, NULL); gel(arch,N+1-s) = gen_1; if (!c) continue; /* compute Im(C) in Clk(m)... */ ImC = ComputeKernel(bnrm, bnr, dtQ); /* ... and its subgroups of index 2 with conductor m */ candD = subgrouplist_cond_sub(bnrm, ImC, mkvec(gen_2)); nbcand = lg(candD) - 1; for (c = 1; c <= nbcand; c++) { GEN D = gel(candD,c); /* check if the conductor is suitable */ long cpl; GEN p1 = InitQuotient(D), p2; GEN ord = gel(p1,1), cyc = gel(p1,2), map = gel(p1,3); if (!cyc_is_cyclic(cyc)) /* cyclic => suitable, else test */ { GEN lH = subgrouplist(cyc, NULL), IK = NULL; long j, ok = 0; for (j = 1; j < lg(lH); j++) { GEN H = gel(lH, j), IH = subgp_intersect(cyc, IK, H); /* if H > IK, no need to test H */ if (IK && gidentical(IH, IK)) continue; if (IsGoodSubgroup(H, bnrm, map)) { IK = IH; if (equalii(ord, ZM_det_triangular(IK))) { ok = 1; break; } } } if (!ok) continue; } p2 = cgetg(6, t_VEC); /* p2[5] filled in CplxModulus */ gel(p2,1) = bnrm; gel(p2,2) = D; gel(p2,3) = InitQuotient(D); gel(p2,4) = InitQuotient(ImC); if (DEBUGLEVEL>1) err_printf("\nTrying modulus = %Ps and subgroup = %Ps\n", bnr_get_mod(bnrm), D); cpl = CplxModulus(p2, &pr); if (oldcpl < 0 || cpl < oldcpl) { *newprec = pr; if (rep) gunclone(rep); rep = gclone(p2); oldcpl = cpl; } if (oldcpl < rb) goto END; /* OK */ if (DEBUGLEVEL>1) err_printf("Trying to find another modulus..."); first = 0; } } if (!first) goto END; /* OK */ } } /* if necessary compute more ideals */ minnorm = maxnorm; maxnorm <<= 1; if (!iscyc && maxnorm > limnorm) return NULL; } END: if (DEBUGLEVEL>1) err_printf("No, we're done!\nModulus = %Ps and subgroup = %Ps\n", bnr_get_mod(gel(rep,1)), gel(rep,2)); gel(rep,5) = InitChar(gel(rep,1), gel(rep,5), *newprec); return gerepilecopy(av, rep); } /********************************************************************/ /* 2nd part: compute W(X) */ /********************************************************************/ /* find ilambda s.t. Diff*f*ilambda integral and coprime to f and ilambda >> 0 at foo, fa = factorization of f */ static GEN get_ilambda(GEN nf, GEN fa, GEN foo) { GEN x, w, E2, P = gel(fa,1), E = gel(fa,2), D = nf_get_diff(nf); long i, l = lg(P); if (l == 1) return gen_1; w = cgetg(l, t_VEC); E2 = cgetg(l, t_COL); for (i = 1; i < l; i++) { GEN pr = gel(P,i), t = pr_get_tau(pr); long e = itou(gel(E,i)), v = idealval(nf, D, pr); if (v) { D = idealdivpowprime(nf, D, pr, utoipos(v)); e += v; } gel(E2,i) = stoi(e+1); if (typ(t) == t_MAT) t = gel(t,1); gel(w,i) = gdiv(nfpow(nf, t, stoi(e)), powiu(pr_get_p(pr),e)); } x = mkmat2(P, E2); return idealchinese(nf, mkvec2(x, foo), w); } /* compute the list of W(chi) such that Ld(s,chi) = W(chi) Ld(1 - s, chi*), * for all chi in LCHI. All chi have the same conductor (= cond(bnr)). * if check == 0 do not check the result */ static GEN ArtinNumber(GEN bnr, GEN LCHI, long check, long prec) { long ic, i, j, nz, nChar = lg(LCHI)-1; pari_sp av = avma, av2; GEN sqrtnc, cond, condZ, cond0, cond1, nf, T; GEN cyc, vN, vB, diff, vt, idh, zid, gen, z, nchi; GEN indW, W, classe, s0, s, den, ilambda, sarch; CHI_t **lC; GROUP_t G; lC = (CHI_t**)new_chunk(nChar + 1); indW = cgetg(nChar + 1, t_VECSMALL); W = cgetg(nChar + 1, t_VEC); for (ic = 0, i = 1; i <= nChar; i++) { GEN CHI = gel(LCHI,i); if (chi_get_deg(CHI) <= 2) { gel(W,i) = gen_1; continue; } ic++; indW[ic] = i; lC[ic] = (CHI_t*)new_chunk(sizeof(CHI_t)); init_CHI_C(lC[ic], CHI); } if (!ic) return W; nChar = ic; nf = bnr_get_nf(bnr); diff = nf_get_diff(nf); T = nf_get_Tr(nf); cond = bnr_get_mod(bnr); cond0 = gel(cond,1); condZ = gcoeff(cond0,1,1); cond1 = gel(cond,2); sqrtnc = gsqrt(idealnorm(nf, cond0), prec); ilambda = get_ilambda(nf, bid_get_fact(bnr_get_bid(bnr)), cond1); idh = idealmul(nf, ilambda, idealmul(nf, diff, cond0)); /* integral */ ilambda = Q_remove_denom(ilambda, &den); z = den? rootsof1_cx(den, prec): NULL; /* compute a system of generators of (Ok/cond)^*, we'll make them * cond1-positive in the main loop */ zid = Idealstar(nf, cond0, nf_GEN); cyc = abgrp_get_cyc(zid); gen = abgrp_get_gen(zid); nz = lg(gen) - 1; sarch = nfarchstar(nf, cond0, vec01_to_indices(cond1)); nchi = cgetg(nChar+1, t_VEC); for (ic = 1; ic <= nChar; ic++) gel(nchi,ic) = cgetg(nz + 1, t_VECSMALL); for (i = 1; i <= nz; i++) { if (is_bigint(gel(cyc,i))) pari_err_OVERFLOW("ArtinNumber [conductor too large]"); gel(gen,i) = set_sign_mod_divisor(nf, NULL, gel(gen,i), sarch); classe = isprincipalray(bnr, gel(gen,i)); for (ic = 1; ic <= nChar; ic++) { GEN n = gel(nchi,ic); n[i] = CHI_eval_n(lC[ic], classe); } } /* Sum chi(beta) * exp(2i * Pi * Tr(beta * ilambda) where beta runs through the classes of (Ok/cond0)^* and beta cond1-positive */ vt = gel(T,1); /* ( Tr(w_i) )_i */ if (typ(ilambda) == t_COL) vt = ZV_ZM_mul(vt, zk_multable(nf, ilambda)); else vt = ZC_Z_mul(vt, ilambda); /*vt = den . (Tr(w_i * ilambda))_i */ G.cyc = gtovecsmall(cyc); G.r = nz; G.j = zero_zv(nz); vN = zero_Flm_copy(nz, nChar); av2 = avma; vB = const_vec(nz, gen_1); s0 = z? powgi(z, modii(gel(vt,1), den)): gen_1; /* for beta = 1 */ s = const_vec(nChar, s0); while ( (i = NextElt(&G)) ) { GEN b = gel(vB,i); b = nfmuli(nf, b, gel(gen,i)); b = typ(b) == t_COL? FpC_red(b, condZ): modii(b, condZ); for (j=1; j<=i; j++) gel(vB,j) = b; for (ic = 1; ic <= nChar; ic++) { GEN v = gel(vN,ic), n = gel(nchi,ic); v[i] = Fl_add(v[i], n[i], lC[ic]->ord); for (j=1; jval[ v[i] ]; gel(s,ic) = gadd(gel(s,ic), gmul(val, s0)); } if (gc_needed(av2, 1)) { if (DEBUGMEM > 1) pari_warn(warnmem,"ArtinNumber"); gerepileall(av2, 2, &s, &vB); } } classe = isprincipalray(bnr, idh); z = powIs(- (lg(gel(sarch,1))-1)); for (ic = 1; ic <= nChar; ic++) { s0 = gmul(gel(s,ic), CHI_eval(lC[ic], classe)); s0 = gdiv(s0, sqrtnc); if (check && - expo(subrs(gnorm(s0), 1)) < prec2nbits(prec) >> 1) pari_err_BUG("ArtinNumber"); gel(W, indW[ic]) = gmul(s0, z); } return gerepilecopy(av, W); } static GEN ComputeAllArtinNumbers(GEN dataCR, GEN vChar, int check, long prec) { long j, k, cl = lg(dataCR) - 1, J = lg(vChar)-1; GEN W = cgetg(cl+1,t_VEC), WbyCond, LCHI; for (j = 1; j <= J; j++) { GEN LChar = gel(vChar,j), ldata = vecpermute(dataCR, LChar); GEN dtcr = gel(ldata,1), bnr = ch_bnr(dtcr); long l = lg(LChar); if (DEBUGLEVEL>1) err_printf("* Root Number: cond. no %ld/%ld (%ld chars)\n", j, J, l-1); LCHI = cgetg(l, t_VEC); for (k = 1; k < l; k++) gel(LCHI,k) = ch_CHI0(gel(ldata,k)); WbyCond = ArtinNumber(bnr, LCHI, check, prec); for (k = 1; k < l; k++) gel(W,LChar[k]) = gel(WbyCond,k); } return W; } static GEN SingleArtinNumber(GEN bnr, GEN chi, long prec) { return gel(ArtinNumber(bnr, mkvec(chi), 1, prec), 1); } /* compute the constant W of the functional equation of Lambda(chi). If flag = 1 then chi is assumed to be primitive */ GEN bnrrootnumber(GEN bnr, GEN chi, long flag, long prec) { pari_sp av = avma; GEN cyc; if (flag < 0 || flag > 1) pari_err_FLAG("bnrrootnumber"); checkbnr(bnr); if (flag) { cyc = bnr_get_cyc(bnr); if (!char_check(cyc,chi)) pari_err_TYPE("bnrrootnumber [character]", chi); } else { GEN z = bnrconductor_i(bnr, chi, 2); bnr = gel(z,2); chi = gel(z,3); cyc = bnr_get_cyc(bnr); } chi = char_normalize(chi, cyc_normalize(cyc)); chi = get_Char(chi, prec); return gerepilecopy(av, SingleArtinNumber(bnr, chi, prec)); } /********************************************************************/ /* 3rd part: initialize the characters */ /********************************************************************/ /* Let chi be a character, A(chi) corresponding to the primes dividing diff at s = flag. If s = 0, returns [r, A] where r is the order of vanishing at s = 0 corresponding to diff. No GC */ static GEN ComputeAChi(GEN dtcr, long *r, long flag, long prec) { GEN A, diff = ch_diff(dtcr), bnrc = ch_bnr(dtcr), chi = ch_CHI0(dtcr); long i, l = lg(diff); A = gen_1; *r = 0; for (i = 1; i < l; i++) { GEN pr = gel(diff,i), B; GEN z = CharEval(chi, isprincipalray(bnrc, pr)); if (flag) B = gsubsg(1, gdiv(z, pr_norm(pr))); else if (gequal1(z)) { B = glog(pr_norm(pr), prec); (*r)++; } else B = gsubsg(1, z); A = gmul(A, B); } return A; } /* simplified version of ComputeAchi: return 1 if L(0,chi) = 0 */ static int L_vanishes_at_0(GEN dtcr) { GEN diff = ch_diff(dtcr), bnrc = ch_bnr(dtcr), chi = ch_CHI0(dtcr); long i, l = lg(diff); for (i = 1; i < l; i++) { GEN pr = gel(diff,i); if (! CharEval_n(chi, isprincipalray(bnrc, pr))) return 1; } return 0; } static GEN _data4(GEN arch, long r1, long r2) { GEN z = cgetg(5, t_VECSMALL); long i, b, q = 0; for (i=1; i<=r1; i++) if (signe(gel(arch,i))) q++; z[1] = q; b = r1 - q; z[2] = b; z[3] = r2; z[4] = maxss(b+r2+1, r2+q); return z; } /* Given a list [chi, F = cond(chi)] of characters over Cl(bnr), compute a vector dataCR containing for each character: 2: the constant C(F) [t_REAL] 3: bnr(F) 4: [q, r1 - q, r2, rc] where q = number of real places in F rc = max{r1 + r2 - q + 1, r2 + q} 6: diff(chi) primes dividing m but not F 7: finite part of F 1: chi 5: [(c_i), z, d] in bnr(m) 8: [(c_i), z, d] in bnr(F) 9: if NULL then does not compute (for AllStark) */ static GEN InitChar(GEN bnr, GEN listCR, long prec) { GEN bnf = checkbnf(bnr), nf = bnf_get_nf(bnf); GEN modul, dk, C, dataCR, chi, cond, ncyc; long N, r1, r2, prec2, i, j, l; pari_sp av = avma; modul = bnr_get_mod(bnr); dk = nf_get_disc(nf); N = nf_get_degree(nf); nf_get_sign(nf, &r1,&r2); prec2 = precdbl(prec) + EXTRA_PREC; C = gmul2n(sqrtr_abs(divir(dk, powru(mppi(prec2),N))), -r2); ncyc = cyc_normalize( bnr_get_cyc(bnr) ); dataCR = cgetg_copy(listCR, &l); for (i = 1; i < l; i++) { GEN bnrc, olddtcr, dtcr = cgetg(9, t_VEC); gel(dataCR,i) = dtcr; chi = gmael(listCR, i, 1); cond = gmael(listCR, i, 2); /* do we already know the invariants of chi? */ olddtcr = NULL; for (j = 1; j < i; j++) if (gequal(cond, gmael(listCR,j,2))) { olddtcr = gel(dataCR,j); break; } if (!olddtcr) { ch_C(dtcr) = gmul(C, gsqrt(ZM_det_triangular(gel(cond,1)), prec2)); ch_4(dtcr) = _data4(gel(cond,2),r1,r2); ch_cond(dtcr) = cond; if (gequal(cond,modul)) { ch_bnr(dtcr) = bnr; ch_diff(dtcr) = cgetg(1, t_VEC); } else { ch_bnr(dtcr) = Buchray(bnf, cond, nf_INIT); ch_diff(dtcr) = get_prdiff(bnr, cond); } } else { ch_C(dtcr) = ch_C(olddtcr); ch_bnr(dtcr) = ch_bnr(olddtcr); ch_4(dtcr) = ch_4(olddtcr); ch_diff(dtcr) = ch_diff(olddtcr); ch_cond(dtcr) = ch_cond(olddtcr); } chi = char_normalize(chi,ncyc); ch_CHI(dtcr) = get_Char(chi, prec2); ch_comp(dtcr) = gen_1; /* compute this character (by default) */ bnrc = ch_bnr(dtcr); if (gequal(bnr_get_mod(bnr), bnr_get_mod(bnrc))) ch_CHI0(dtcr) = ch_CHI(dtcr); else { chi = bnrchar_primitive(bnr, chi, bnrc); ch_CHI0(dtcr) = get_Char(chi, prec2); } } return gerepilecopy(av, dataCR); } /* recompute dataCR with the new precision */ static GEN CharNewPrec(GEN dataCR, GEN nf, long prec) { GEN dk, C; long N, l, j, prec2; dk = nf_get_disc(nf); N = nf_get_degree(nf); prec2 = precdbl(prec) + EXTRA_PREC; C = sqrtr(divir(absi_shallow(dk), powru(mppi(prec2), N))); l = lg(dataCR); for (j = 1; j < l; j++) { GEN dtcr = gel(dataCR,j), f0 = gel(ch_cond(dtcr),1); ch_C(dtcr) = gmul(C, gsqrt(ZM_det_triangular(f0), prec2)); gmael(ch_bnr(dtcr), 1, 7) = nf; ch_CHI( dtcr) = get_Char(gel(ch_CHI(dtcr), 1), prec2); ch_CHI0(dtcr) = get_Char(gel(ch_CHI0(dtcr),1), prec2); } return dataCR; } /********************************************************************/ /* 4th part: compute the coefficients an(chi) */ /* */ /* matan entries are arrays of ints containing the coefficients of */ /* an(chi) as a polmod modulo polcyclo(order(chi)) */ /********************************************************************/ static void _0toCoeff(int *rep, long deg) { long i; for (i=0; i i - deg) c += c0[j] * c1[i-j]; T[i] = c; } for (i = 0; i < deg; i++) { c = T[i]; for (j = 0; j < deg; j++) c += reduc[j][i] * T[deg+j]; c0[i] = c; } } /* c0 <- c0 + c1 * c2 */ static void AddMulCoeff(int *c0, int *c1, int* c2, int** reduc, long deg) { long i, j; pari_sp av; int c, *t; if (IsZero(c2,deg)) return; if (!c1) /* c1 == 1 */ { for (i = 0; i < deg; i++) c0[i] += c2[i]; return; } av = avma; t = (int*)new_chunk(2*deg); /* = c1 * c2, not reduced */ for (i = 0; i < 2*deg; i++) { c = 0; for (j = 0; j <= i; j++) if (j < deg && j > i - deg) c += c1[j] * c2[i-j]; t[i] = c; } for (i = 0; i < deg; i++) { c = t[i]; for (j = 0; j < deg; j++) c += reduc[j][i] * t[deg+j]; c0[i] += c; } avma = av; } /* evaluate the Coeff. No Garbage collector */ static GEN EvalCoeff(GEN z, int* c, long deg) { long i,j; GEN e, r; if (!c) return gen_0; #if 0 /* standard Horner */ e = stoi(c[deg - 1]); for (i = deg - 2; i >= 0; i--) e = gadd(stoi(c[i]), gmul(z, e)); #else /* specific attention to sparse polynomials */ e = NULL; for (i = deg-1; i >=0; i=j-1) { for (j=i; c[j] == 0; j--) if (j==0) { if (!e) return NULL; if (i!=j) z = gpowgs(z,i-j+1); return gmul(e,z); } if (e) { r = (i==j)? z: gpowgs(z,i-j+1); e = gadd(gmul(e,r), stoi(c[j])); } else e = stoi(c[j]); } #endif return e; } /* copy the n * (m+1) array matan */ static void CopyCoeff(int** a, int** a2, long n, long m) { long i,j; for (i = 1; i <= n; i++) { int *b = a[i], *b2 = a2[i]; for (j = 0; j < m; j++) b2[j] = b[j]; } } static void an_AddMul(int **an,int **an2, long np, long n, long deg, GEN chi, int **reduc) { GEN chi2 = chi; long q, qk, k; int *c, *c2 = (int*)new_chunk(deg); CopyCoeff(an, an2, n/np, deg); for (q=np;;) { if (gequal1(chi2)) c = NULL; else { Polmod2Coeff(c2, chi2, deg); c = c2; } for(k = 1, qk = q; qk <= n; k++, qk += q) AddMulCoeff(an[qk], c, an2[k], reduc, deg); if (! (q = umuluu_le(q,np, n)) ) break; chi2 = gmul(chi2, chi); } } /* correct the coefficients an(chi) according with diff(chi) in place */ static void CorrectCoeff(GEN dtcr, int** an, int** reduc, long n, long deg) { pari_sp av = avma; long lg, j; pari_sp av1; int **an2; GEN bnrc, diff; CHI_t C; diff = ch_diff(dtcr); lg = lg(diff) - 1; if (!lg) return; if (DEBUGLEVEL>2) err_printf("diff(CHI) = %Ps", diff); bnrc = ch_bnr(dtcr); init_CHI_alg(&C, ch_CHI0(dtcr)); an2 = InitMatAn(n, deg, 0); av1 = avma; for (j = 1; j <= lg; j++) { GEN pr = gel(diff,j); long Np = upr_norm(pr); GEN chi = CHI_eval(&C, isprincipalray(bnrc, pr)); an_AddMul(an,an2,Np,n,deg,chi,reduc); avma = av1; } FreeMat(an2, n); avma = av; } /* compute the coefficients an in the general case */ static int** ComputeCoeff(GEN dtcr, LISTray *R, long n, long deg) { pari_sp av = avma, av2; long i, l; int **an, **reduc, **an2; GEN L; CHI_t C; init_CHI_alg(&C, ch_CHI(dtcr)); an = InitMatAn(n, deg, 0); an2 = InitMatAn(n, deg, 0); reduc = InitReduction(C.ord, deg); av2 = avma; L = R->L1; l = lg(L); for (i=1; iL1ray,i)); an_AddMul(an,an2,np,n,deg,chi,reduc); } FreeMat(an2, n); CorrectCoeff(dtcr, an, reduc, n, deg); FreeMat(reduc, deg-1); avma = av; return an; } /********************************************************************/ /* 5th part: compute L-functions at s=1 */ /********************************************************************/ static void deg11(LISTray *R, long p, GEN bnr, GEN pr) { GEN z = isprincipalray(bnr, pr); vecsmalltrunc_append(R->L1, p); vectrunc_append(R->L1ray, z); } static void deg12(LISTray *R, long p, GEN bnr, GEN Lpr) { GEN z = isprincipalray(bnr, gel(Lpr,1)); vecsmalltrunc_append(R->L11, p); vectrunc_append(R->L11ray, z); } static void deg0(LISTray *R, long p) { vecsmalltrunc_append(R->L0, p); } static void deg2(LISTray *R, long p) { vecsmalltrunc_append(R->L2, p); } static void InitPrimesQuad(GEN bnr, ulong N0, LISTray *R) { pari_sp av = avma; GEN bnf = bnr_get_bnf(bnr), cond = gel(bnr_get_mod(bnr), 1); long p,i,l, condZ = itos(gcoeff(cond,1,1)), contZ = itos(content(cond)); GEN prime, Lpr, nf = bnf_get_nf(bnf), dk = nf_get_disc(nf); forprime_t T; l = 1 + primepi_upper_bound(N0); R->L0 = vecsmalltrunc_init(l); R->L2 = vecsmalltrunc_init(l); R->condZ = condZ; R->L1 = vecsmalltrunc_init(l); R->L1ray = vectrunc_init(l); R->L11= vecsmalltrunc_init(l); R->L11ray= vectrunc_init(l); prime = utoipos(2); u_forprime_init(&T, 2, N0); while ( (p = u_forprime_next(&T)) ) { prime[2] = p; switch (kroiu(dk, p)) { case -1: /* inert */ if (condZ % p == 0) deg0(R,p); else deg2(R,p); break; case 1: /* split */ Lpr = idealprimedec(nf, prime); if (condZ % p != 0) deg12(R, p, bnr, Lpr); else if (contZ % p == 0) deg0(R,p); else { GEN pr = idealval(nf, cond, gel(Lpr,1))? gel(Lpr,2): gel(Lpr,1); deg11(R, p, bnr, pr); } break; default: /* ramified */ if (condZ % p == 0) deg0(R,p); else deg11(R, p, bnr, idealprimedec_galois(nf,prime)); break; } } /* precompute isprincipalray(x), x in Z */ R->rayZ = cgetg(condZ, t_VEC); for (i=1; irayZ,i) = (ugcd(i,condZ) == 1)? isprincipalray(bnr, utoipos(i)): gen_0; gerepileall(av, 7, &(R->L0), &(R->L2), &(R->rayZ), &(R->L1), &(R->L1ray), &(R->L11), &(R->L11ray) ); } static void InitPrimes(GEN bnr, ulong N0, LISTray *R) { GEN bnf = bnr_get_bnf(bnr), cond = gel(bnr_get_mod(bnr), 1); long p,j,k,l, condZ = itos(gcoeff(cond,1,1)), N = lg(cond)-1; GEN tmpray, tabpr, prime, BOUND, nf = bnf_get_nf(bnf); forprime_t T; R->condZ = condZ; l = primepi_upper_bound(N0) * N; tmpray = cgetg(N+1, t_VEC); R->L1 = vecsmalltrunc_init(l); R->L1ray = vectrunc_init(l); u_forprime_init(&T, 2, N0); prime = utoipos(2); BOUND = utoi(N0); while ( (p = u_forprime_next(&T)) ) { pari_sp av = avma; prime[2] = p; if (DEBUGLEVEL>1 && (p & 2047) == 1) err_printf("%ld ", p); tabpr = idealprimedec_limit_norm(nf, prime, BOUND); for (j = 1; j < lg(tabpr); j++) { GEN pr = gel(tabpr,j); if (condZ % p == 0 && idealval(nf, cond, pr)) { gel(tmpray,j) = NULL; continue; } vecsmalltrunc_append(R->L1, upowuu(p, pr_get_f(pr))); gel(tmpray,j) = gclone( isprincipalray(bnr, pr) ); } avma = av; for (k = 1; k < j; k++) { if (!tmpray[k]) continue; vectrunc_append(R->L1ray, ZC_copy(gel(tmpray,k))); gunclone(gel(tmpray,k)); } } } static GEN /* cf polcoef */ _sercoeff(GEN x, long n) { long i = n - valp(x); return (i < 0)? gen_0: gel(x,i+2); } static void affect_coeff(GEN q, long n, GEN y) { GEN x = _sercoeff(q,-n); if (x == gen_0) gel(y,n) = NULL; else affgr(x, gel(y,n)); } typedef struct { GEN c1, aij, bij, cS, cT, powracpi; long i0, a,b,c, r, rc1, rc2; } ST_t; /* compute the principal part at the integers s = 0, -1, -2, ..., -i0 of Gamma((s+1)/2)^a Gamma(s/2)^b Gamma(s)^c / (s - z) with z = 0 and 1 */ /* NOTE: surely not the best way to do this, but it's fast enough! */ static void ppgamma(ST_t *T, long prec) { GEN eul, gam,gamun,gamdm, an,bn,cn_evn,cn_odd, x,x2,X,Y, cf, sqpi; GEN p1, p2, aij, bij; long a = T->a; long b = T->b; long c = T->c, r = T->r, i0 = T->i0; long i,j, s,t; pari_sp av; aij = cgetg(i0+1, t_VEC); bij = cgetg(i0+1, t_VEC); for (i = 1; i <= i0; i++) { gel(aij,i) = p1 = cgetg(r+1, t_VEC); gel(bij,i) = p2 = cgetg(r+1, t_VEC); for (j=1; j<=r; j++) { gel(p1,j) = cgetr(prec); gel(p2,j) = cgetr(prec); } } av = avma; x = pol_x(0); x2 = gmul2n(x, -1); /* x/2 */ eul = mpeuler(prec); sqpi= sqrtr_abs(mppi(prec)); /* Gamma(1/2) */ /* expansion of log(Gamma(u)) at u = 1 */ gamun = cgetg(r+3, t_SER); gamun[1] = evalsigne(1) | _evalvalp(0) | evalvarn(0); gel(gamun,2) = gen_0; gel(gamun,3) = gneg(eul); for (i = 2; i <= r; i++) gel(gamun,i+2) = divrs(szeta(i,prec), odd(i)? -i: i); gamun = gexp(gamun, prec); /* Gamma(1 + x) */ gam = gdiv(gamun,x); /* Gamma(x) */ /* expansion of log(Gamma(u) / Gamma(1/2)) at u = 1/2 */ gamdm = cgetg(r+3, t_SER); gamdm[1] = evalsigne(1) | _evalvalp(0) | evalvarn(0); gel(gamdm,2) = gen_0; gel(gamdm,3) = gneg(gadd(gmul2n(mplog2(prec), 1), eul)); for (i = 2; i <= r; i++) gel(gamdm,i+2) = mulri(gel(gamun,i+2), int2um1(i)); gamdm = gmul(sqpi, gexp(gamdm, prec)); /* Gamma(1/2 + x) */ /* We simplify to get one of the following two expressions * if (b > a) : sqrt{Pi}^a 2^{a-au} Gamma(u)^{a+c} Gamma( u/2 )^{|b-a|} * if (b <= a): sqrt{Pi}^b 2^{b-bu} Gamma(u)^{b+c} Gamma((u+1)/2)^{|b-a|} */ if (b > a) { t = a; s = b; X = x2; Y = gsub(x2,ghalf); p1 = ser_unscale(gam, ghalf); p2 = gdiv(ser_unscale(gamdm,ghalf), Y); /* Gamma((x-1)/2) */ } else { t = b; s = a; X = gadd(x2,ghalf); Y = x2; p1 = ser_unscale(gamdm,ghalf); p2 = ser_unscale(gam,ghalf); } cf = powru(sqpi, t); an = gpowgs(gpow(gen_2, gsubsg(1,x), prec), t); /* 2^{t-tx} */ bn = gpowgs(gam, t+c); /* Gamma(x)^{t+c} */ cn_evn = gpowgs(p1, s-t); /* Gamma(X)^{s-t} */ cn_odd = gpowgs(p2, s-t); /* Gamma(Y)^{s-t} */ for (i = 0; i < i0/2; i++) { GEN C1,q1, A1 = gel(aij,2*i+1), B1 = gel(bij,2*i+1); GEN C2,q2, A2 = gel(aij,2*i+2), B2 = gel(bij,2*i+2); C1 = gmul(cf, gmul(bn, gmul(an, cn_evn))); p1 = gdiv(C1, gsubgs(x, 2*i)); q1 = gdiv(C1, gsubgs(x, 2*i+1)); /* an(x-u-1) = 2^t an(x-u) */ an = gmul2n(an, t); /* bn(x-u-1) = bn(x-u) / (x-u-1)^{t+c} */ bn = gdiv(bn, gpowgs(gsubgs(x, 2*i+1), t+c)); C2 = gmul(cf, gmul(bn, gmul(an, cn_odd))); p2 = gdiv(C2, gsubgs(x, 2*i+1)); q2 = gdiv(C2, gsubgs(x, 2*i+2)); for (j = 1; j <= r; j++) { affect_coeff(p1, j, A1); affect_coeff(q1, j, B1); affect_coeff(p2, j, A2); affect_coeff(q2, j, B2); } an = gmul2n(an, t); bn = gdiv(bn, gpowgs(gsubgs(x, 2*i+2), t+c)); /* cn_evn(x-2i-2) = cn_evn(x-2i) / (X - (i+1))^{s-t} */ /* cn_odd(x-2i-3) = cn_odd(x-2i-1)/ (Y - (i+1))^{s-t} */ cn_evn = gdiv(cn_evn, gpowgs(gsubgs(X,i+1), s-t)); cn_odd = gdiv(cn_odd, gpowgs(gsubgs(Y,i+1), s-t)); } T->aij = aij; T->bij = bij; avma = av; } static GEN _cond(GEN dtcr) { return mkvec2(ch_cond(dtcr), ch_4(dtcr)); } /* sort chars according to conductor */ static GEN sortChars(GEN dataCR) { const long cl = lg(dataCR) - 1; GEN vCond = cgetg(cl+1, t_VEC); GEN CC = cgetg(cl+1, t_VECSMALL); GEN nvCond = cgetg(cl+1, t_VECSMALL); long j,k, ncond; GEN vChar; for (j = 1; j <= cl; j++) nvCond[j] = 0; ncond = 0; for (j = 1; j <= cl; j++) { GEN cond = _cond(gel(dataCR,j)); for (k = 1; k <= ncond; k++) if (gequal(cond, gel(vCond,k))) break; if (k > ncond) gel(vCond,++ncond) = cond; nvCond[k]++; CC[j] = k; /* char j has conductor number k */ } vChar = cgetg(ncond+1, t_VEC); for (k = 1; k <= ncond; k++) { gel(vChar,k) = cgetg(nvCond[k]+1, t_VECSMALL); nvCond[k] = 0; } for (j = 1; j <= cl; j++) { k = CC[j]; nvCond[k]++; mael(vChar,k,nvCond[k]) = j; } return vChar; } /* Given W(chi), S(chi) and T(chi), return L(1, chi) if fl & 1, else [r(chi), c(chi)] where L(s, chi) ~ c(chi) s^r(chi) at s = 0. If fl & 2, adjust the value to get L_S(s, chi). */ static GEN GetValue(GEN dtcr, GEN W, GEN S, GEN T, long fl, long prec) { pari_sp av = avma; GEN cf, z, p1; long q, b, c, r; int isreal = (chi_get_deg(ch_CHI0(dtcr)) <= 2); p1 = ch_4(dtcr); q = p1[1]; b = p1[2]; c = p1[3]; if (fl & 1) { /* S(chi) + W(chi).T(chi)) / (C(chi) sqrt(Pi)^{r1 - q}) */ cf = gmul(ch_C(dtcr), powruhalf(mppi(prec), b)); z = gadd(S, gmul(W, T)); if (isreal) z = real_i(z); z = gdiv(z, cf); if (fl & 2) z = gmul(z, ComputeAChi(dtcr, &r, 1, prec)); } else { /* (W(chi).S(conj(chi)) + T(chi)) / (sqrt(Pi)^q 2^{r1 - q}) */ cf = gmul2n(powruhalf(mppi(prec), q), b); z = gadd(gmul(W, conj_i(S)), conj_i(T)); if (isreal) z = real_i(z); z = gdiv(z, cf); r = 0; if (fl & 2) z = gmul(z, ComputeAChi(dtcr, &r, 0, prec)); z = mkvec2(utoi(b + c + r), z); } return gerepilecopy(av, z); } /* return the order and the first non-zero term of L(s, chi0) at s = 0. If flag != 0, adjust the value to get L_S(s, chi0). */ static GEN GetValue1(GEN bnr, long flag, long prec) { GEN bnf = checkbnf(bnr), nf = bnf_get_nf(bnf); GEN h, R, c, diff; long i, l, r, r1, r2; pari_sp av = avma; nf_get_sign(nf, &r1,&r2); h = bnf_get_no(bnf); R = bnf_get_reg(bnf); c = gneg_i(gdivgs(mpmul(h, R), bnf_get_tuN(bnf))); r = r1 + r2 - 1; if (flag) { diff = divcond(bnr); l = lg(diff) - 1; r += l; for (i = 1; i <= l; i++) c = gmul(c, glog(pr_norm(gel(diff,i)), prec)); } return gerepilecopy(av, mkvec2(stoi(r), c)); } /********************************************************************/ /* 6th part: recover the coefficients */ /********************************************************************/ static long TestOne(GEN plg, RC_data *d) { long j, v = d->v; GEN z = gsub(d->beta, gel(plg,v)); if (expo(z) >= d->G) return 0; for (j = 1; j < lg(plg); j++) if (j != v && mpcmp(d->B, mpabs_shallow(gel(plg,j))) < 0) return 0; return 1; } static GEN chk_reccoeff_init(FP_chk_fun *chk, GEN r, GEN mat) { RC_data *d = (RC_data*)chk->data; (void)r; d->U = mat; return d->nB; } static GEN chk_reccoeff(void *data, GEN x) { RC_data *d = (RC_data*)data; GEN v = gmul(d->U, x), z = gel(v,1); if (!gequal1(z)) return NULL; *++v = evaltyp(t_COL) | evallg( lg(d->M) ); if (TestOne(gmul(d->M, v), d)) return v; return NULL; } /* Using Cohen's method */ static GEN RecCoeff3(GEN nf, RC_data *d, long prec) { GEN A, M, nB, cand, p1, B2, C2, tB, beta2, nf2, Bd; GEN beta = d->beta, B = d->B; long N = d->N, v = d->v, e, BIG; long i, j, k, ct = 0, prec2; FP_chk_fun chk = { &chk_reccoeff, &chk_reccoeff_init, NULL, NULL, 0 }; chk.data = (void*)d; d->G = minss(-10, -prec2nbits(prec) >> 4); BIG = maxss(32, -2*d->G); tB = sqrtnr(real2n(BIG-N,DEFAULTPREC), N-1); Bd = grndtoi(gmin_shallow(B, tB), &e); if (e > 0) return NULL; /* failure */ Bd = addiu(Bd, 1); prec2 = nbits2prec( expi(Bd) + 192 ); prec2 = maxss(precdbl(prec), prec2); B2 = sqri(Bd); C2 = shifti(B2, BIG<<1); LABrcf: ct++; beta2 = gprec_w(beta, prec2); nf2 = nfnewprec_shallow(nf, prec2); d->M = M = nf_get_M(nf2); A = cgetg(N+2, t_MAT); for (i = 1; i <= N+1; i++) gel(A,i) = cgetg(N+2, t_COL); gcoeff(A, 1, 1) = gadd(gmul(C2, gsqr(beta2)), B2); for (j = 2; j <= N+1; j++) { p1 = gmul(C2, gmul(gneg_i(beta2), gcoeff(M, v, j-1))); gcoeff(A, 1, j) = gcoeff(A, j, 1) = p1; } for (i = 2; i <= N+1; i++) for (j = i; j <= N+1; j++) { p1 = gen_0; for (k = 1; k <= N; k++) { GEN p2 = gmul(gcoeff(M, k, j-1), gcoeff(M, k, i-1)); if (k == v) p2 = gmul(C2, p2); p1 = gadd(p1,p2); } gcoeff(A, i, j) = gcoeff(A, j, i) = p1; } nB = mului(N+1, B2); d->nB = nB; cand = fincke_pohst(A, nB, -1, prec2, &chk); if (!cand) { if (ct > 3) return NULL; prec2 = precdbl(prec2); if (DEBUGLEVEL>1) pari_warn(warnprec,"RecCoeff", prec2); goto LABrcf; } cand = gel(cand,1); if (lg(cand) == 2) return gel(cand,1); if (DEBUGLEVEL>1) err_printf("RecCoeff3: no solution found!\n"); return NULL; } /* Using linear dependance relations */ static GEN RecCoeff2(GEN nf, RC_data *d, long prec) { pari_sp av; GEN vec, M = nf_get_M(nf), beta = d->beta; long bit, min, max, lM = lg(M); d->G = minss(-20, -prec2nbits(prec) >> 4); vec = shallowconcat(mkvec(gneg(beta)), row(M, d->v)); min = (long)prec2nbits_mul(prec, 0.75); max = (long)prec2nbits_mul(prec, 0.98); av = avma; for (bit = max; bit >= min; bit-=32, avma = av) { long e; GEN v = lindep_bit(vec, bit), z = gel(v,1); if (!signe(z)) continue; *++v = evaltyp(t_COL) | evallg(lM); v = grndtoi(gdiv(v, z), &e); if (e > 0) break; if (TestOne(RgM_RgC_mul(M, v), d)) return v; } /* failure */ return RecCoeff3(nf,d,prec); } /* Attempts to find a polynomial with coefficients in nf such that its coefficients are close to those of pol at the place v and less than B at all the other places */ static GEN RecCoeff(GEN nf, GEN pol, long v, long prec) { long j, md, cl = degpol(pol); pari_sp av = avma; RC_data d; /* if precision(pol) is too low, abort */ for (j = 2; j <= cl+1; j++) { GEN t = gel(pol, j); if (prec2nbits(gprecision(t)) - gexpo(t) < 34) return NULL; } md = cl/2; pol = leafcopy(pol); d.N = nf_get_degree(nf); d.v = v; for (j = 1; j <= cl; j++) { /* start with the coefficients in the middle, since they are the harder to recognize! */ long cf = md + (j%2? j/2: -j/2); GEN t, bound = shifti(binomial(utoipos(cl), cf), cl-cf); if (DEBUGLEVEL>1) err_printf("RecCoeff (cf = %ld, B = %Ps)\n", cf, bound); d.beta = real_i( gel(pol,cf+2) ); d.B = bound; if (! (t = RecCoeff2(nf, &d, prec)) ) return NULL; gel(pol, cf+2) = coltoalg(nf,t); } gel(pol,cl+2) = gen_1; return gerepilecopy(av, pol); } /* an[q * i] *= chi for all (i,p)=1 */ static void an_mul(int **an, long p, long q, long n, long deg, GEN chi, int **reduc) { pari_sp av; long c,i; int *T; if (gequal1(chi)) return; av = avma; T = (int*)new_chunk(deg); Polmod2Coeff(T,chi, deg); for (c = 1, i = q; i <= n; i += q, c++) if (c == p) c = 0; else MulCoeff(an[i], T, reduc, deg); avma = av; } /* an[q * i] = 0 for all (i,p)=1 */ static void an_set0_coprime(int **an, long p, long q, long n, long deg) { long c,i; for (c = 1, i = q; i <= n; i += q, c++) if (c == p) c = 0; else _0toCoeff(an[i], deg); } /* an[q * i] = 0 for all i */ static void an_set0(int **an, long p, long n, long deg) { long i; for (i = p; i <= n; i += p) _0toCoeff(an[i], deg); } /* compute the coefficients an for the quadratic case */ static int** computean(GEN dtcr, LISTray *R, long n, long deg) { pari_sp av = avma, av2; long i, p, q, condZ, l; int **an, **reduc; GEN L, chi, chi1; CHI_t C; init_CHI_alg(&C, ch_CHI(dtcr)); condZ= R->condZ; an = InitMatAn(n, deg, 1); reduc = InitReduction(C.ord, deg); av2 = avma; /* all pr | p divide cond */ L = R->L0; l = lg(L); for (i=1; iL2; l = lg(L); for (i=1; irayZ, p%condZ)); chi1 = chi; for (q=p;;) { an_set0_coprime(an, p,q,n,deg); /* v_p(q) odd */ if (! (q = umuluu_le(q,p, n)) ) break; an_mul(an,p,q,n,deg,chi,reduc); if (! (q = umuluu_le(q,p, n)) ) break; chi = gmul(chi, chi1); } } /* 1 prime of degree 1 */ L = R->L1; l = lg(L); for (i=1; iL1ray,i)); chi1 = chi; for(q=p;;) { an_mul(an,p,q,n,deg,chi,reduc); if (! (q = umuluu_le(q,p, n)) ) break; chi = gmul(chi, chi1); } } /* 2 primes of degree 1 */ L = R->L11; l = lg(L); for (i=1; iL11ray,i); /* use pr1 pr2 = (p) */ if (condZ == 1) ray2 = ZC_neg(ray1); else ray2 = ZC_sub(gel(R->rayZ, p%condZ), ray1); chi11 = CHI_eval(&C, ray1); chi12 = CHI_eval(&C, ray2); chi1 = gadd(chi11, chi12); chi2 = chi12; for(q=p;;) { an_mul(an,p,q,n,deg,chi1,reduc); if (! (q = umuluu_le(q,p, n)) ) break; chi2 = gmul(chi2, chi12); chi1 = gadd(chi2, gmul(chi1, chi11)); } } CorrectCoeff(dtcr, an, reduc, n, deg); FreeMat(reduc, deg-1); avma = av; return an; } /* return the vector of A^i/i for i = 1...n */ static GEN mpvecpowdiv(GEN A, long n) { pari_sp av = avma; long i; GEN v = powersr(A, n); GEN w = cgetg(n+1, t_VEC); gel(w,1) = rcopy(gel(v,2)); for (i=2; i<=n; i++) gel(w,i) = divru(gel(v,i+1), i); return gerepileupto(av, w); } static void GetST0(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec); /* compute S and T for the quadratic case. The following cases (cs) are: 1) bnr complex; 2) bnr real and no infinite place divide cond_chi (TBD); 3) bnr real and one infinite place divide cond_chi; 4) bnr real and both infinite places divide cond_chi (TBD) */ static void QuadGetST(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec) { pari_sp av = avma, av1, av2; long ncond, n, j, k, n0; GEN N0, C, T = *pT, S = *pS, an, degs, cs; LISTray LIST; /* initializations */ degs = GetDeg(dataCR); ncond = lg(vChar)-1; C = cgetg(ncond+1, t_VEC); N0 = cgetg(ncond+1, t_VECSMALL); cs = cgetg(ncond+1, t_VECSMALL); n0 = 0; for (j = 1; j <= ncond; j++) { /* FIXME: make sure that this value of c is correct for the general case */ long r1, r2, q; GEN dtcr = gel(dataCR, mael(vChar,j,1)), p1 = ch_4(dtcr), c = ch_C(dtcr); gel(C,j) = c; q = p1[1]; nf_get_sign(bnr_get_nf(ch_bnr(dtcr)), &r1, &r2); if (r1 == 2) /* real quadratic */ { cs[j] = 2 + q; /* FIXME: make sure that this value of N0 is correct for the general case */ N0[j] = (long)prec2nbits_mul(prec, 0.35 * gtodouble(c)); if (cs[j] == 2 || cs[j] == 4) /* NOT IMPLEMENTED YET */ { GetST0(bnr, pS, pT, dataCR, vChar, prec); return; } } else /* complex quadratic */ { cs[j] = 1; N0[j] = (long)prec2nbits_mul(prec, 0.7 * gtodouble(c)); } if (n0 < N0[j]) n0 = N0[j]; } if (DEBUGLEVEL>1) err_printf("N0 = %ld\n", n0); InitPrimesQuad(bnr, n0, &LIST); av1 = avma; /* loop over conductors */ for (j = 1; j <= ncond; j++) { GEN c0 = gel(C,j), c1 = divur(1, c0), c2 = divur(2, c0); GEN ec1 = mpexp(c1), ec2 = mpexp(c2), LChar = gel(vChar,j); GEN vf0, vf1, cf0, cf1; const long nChar = lg(LChar)-1, NN = N0[j]; if (DEBUGLEVEL>1) err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", j,ncond,NN); if (realprec(ec1) > prec) ec1 = rtor(ec1, prec); if (realprec(ec2) > prec) ec2 = rtor(ec2, prec); switch(cs[j]) { case 1: cf0 = gen_1; cf1 = c0; vf0 = mpveceint1(rtor(c1, prec), ec1, NN); vf1 = mpvecpowdiv(invr(ec1), NN); break; case 3: cf0 = sqrtr(mppi(prec)); cf1 = gmul2n(cf0, 1); cf0 = gmul(cf0, c0); vf0 = mpvecpowdiv(invr(ec2), NN); vf1 = mpveceint1(rtor(c2, prec), ec2, NN); break; default: cf0 = cf1 = NULL; /* FIXME: not implemented */ vf0 = vf1 = NULL; } for (k = 1; k <= nChar; k++) { const long t = LChar[k], d = degs[t]; const GEN dtcr = gel(dataCR, t), z = gel(ch_CHI(dtcr), 2); GEN p1 = gen_0, p2 = gen_0; int **matan; long c = 0; if (DEBUGLEVEL>1) err_printf("\tcharacter no: %ld (%ld/%ld)\n", t,k,nChar); if (isintzero( ch_comp(gel(dataCR, t)) )) { if (DEBUGLEVEL>1) err_printf("\t no need to compute this character\n"); continue; } av2 = avma; matan = computean(gel(dataCR,t), &LIST, NN, d); for (n = 1; n <= NN; n++) if ((an = EvalCoeff(z, matan[n], d))) { p1 = gadd(p1, gmul(an, gel(vf0,n))); p2 = gadd(p2, gmul(an, gel(vf1,n))); if (++c == 256) { gerepileall(av2,2, &p1,&p2); c = 0; } } gaffect(gmul(cf0, p1), gel(S,t)); gaffect(gmul(cf1, conj_i(p2)), gel(T,t)); FreeMat(matan,NN); avma = av2; } if (DEBUGLEVEL>1) err_printf("\n"); avma = av1; } avma = av; } /* s += t*u. All 3 of them t_REAL, except we allow s or u = NULL (for 0) */ static GEN _addmulrr(GEN s, GEN t, GEN u) { if (u) { GEN v = mulrr(t, u); return s? addrr(s, v): v; } return s; } /* s += t. Both real, except we allow s or t = NULL (for exact 0) */ static GEN _addrr(GEN s, GEN t) { return t? (s? addrr(s, t): t) : s; } /* S & T for the general case. This is time-critical: optimize */ static void get_cS_cT(ST_t *T, long n) { pari_sp av; GEN csurn, nsurc, lncsurn, A, B, s, t, Z, aij, bij; long i, j, r, i0; if (T->cS[n]) return; av = avma; aij = T->aij; i0= T->i0; bij = T->bij; r = T->r; Z = cgetg(r+1, t_VEC); gel(Z,1) = NULL; /* unused */ csurn = divru(T->c1, n); nsurc = invr(csurn); lncsurn = logr_abs(csurn); if (r > 1) { gel(Z,2) = lncsurn; /* r >= 2 */ for (i = 3; i <= r; i++) gel(Z,i) = divru(mulrr(gel(Z,i-1), lncsurn), i-1); /* Z[i] = ln^(i-1)(c1/n) / (i-1)! */ } /* i = i0 */ A = gel(aij,i0); t = _addrr(NULL, gel(A,1)); B = gel(bij,i0); s = _addrr(NULL, gel(B,1)); for (j = 2; j <= r; j++) { s = _addmulrr(s, gel(Z,j),gel(B,j)); t = _addmulrr(t, gel(Z,j),gel(A,j)); } for (i = i0 - 1; i > 1; i--) { A = gel(aij,i); if (t) t = mulrr(t, nsurc); B = gel(bij,i); if (s) s = mulrr(s, nsurc); for (j = odd(i)? T->rc2: T->rc1; j > 1; j--) { s = _addmulrr(s, gel(Z,j),gel(B,j)); t = _addmulrr(t, gel(Z,j),gel(A,j)); } s = _addrr(s, gel(B,1)); t = _addrr(t, gel(A,1)); } /* i = 1 */ A = gel(aij,1); if (t) t = mulrr(t, nsurc); B = gel(bij,1); if (s) s = mulrr(s, nsurc); s = _addrr(s, gel(B,1)); t = _addrr(t, gel(A,1)); for (j = 2; j <= r; j++) { s = _addmulrr(s, gel(Z,j),gel(B,j)); t = _addmulrr(t, gel(Z,j),gel(A,j)); } s = _addrr(s, T->b? mulrr(csurn, gel(T->powracpi,T->b+1)): csurn); if (!s) s = gen_0; if (!t) t = gen_0; gel(T->cS,n) = gclone(s); gel(T->cT,n) = gclone(t); avma = av; } static void clear_cScT(ST_t *T, long N) { GEN cS = T->cS, cT = T->cT; long i; for (i=1; i<=N; i++) if (cS[i]) { gunclone(gel(cS,i)); gunclone(gel(cT,i)); gel(cS,i) = gel(cT,i) = NULL; } } static void init_cScT(ST_t *T, GEN dtcr, long N, long prec) { GEN p1 = ch_4(dtcr); T->a = p1[1]; T->b = p1[2]; T->c = p1[3]; T->rc1 = T->a + T->c; T->rc2 = T->b + T->c; T->r = maxss(T->rc2+1, T->rc1); /* >= 2 */ ppgamma(T, prec); clear_cScT(T, N); } /* return a t_REAL */ static GEN zeta_get_limx(long r1, long r2, long bit) { pari_sp av = avma; GEN p1, p2, c0, c1, A0; long r = r1 + r2, N = r + r2; /* c1 = N 2^(-2r2 / N) */ c1 = mulrs(powrfrac(real2n(1, DEFAULTPREC), -2*r2, N), N); p1 = powru(Pi2n(1, DEFAULTPREC), r - 1); p2 = mulir(powuu(N,r), p1); shiftr_inplace(p2, -r2); c0 = sqrtr( divrr(p2, powru(c1, r+1)) ); A0 = logr_abs( gmul2n(c0, bit) ); p2 = divrr(A0, c1); p1 = divrr(mulur(N*(r+1), logr_abs(p2)), addsr(2*(r+1), gmul2n(A0,2))); return gerepileuptoleaf(av, divrr(addrs(p1, 1), powruhalf(p2, N))); } /* N_0 = floor( C_K / limx ). Large */ static long zeta_get_N0(GEN C, GEN limx) { long e; pari_sp av = avma; GEN z = gcvtoi(gdiv(C, limx), &e); /* avoid truncation error */ if (e >= 0 || is_bigint(z)) pari_err_OVERFLOW("zeta_get_N0 [need too many primes]"); if (DEBUGLEVEL>1) err_printf("\ninitzeta: N0 = %Ps\n", z); avma = av; return itos(z); } static GEN eval_i(long r1, long r2, GEN limx, long i) { GEN t = powru(limx, i); if (!r1) t = mulrr(t, powru(mpfactr(i , DEFAULTPREC), r2)); else if (!r2) t = mulrr(t, powru(mpfactr(i/2, DEFAULTPREC), r1)); else { GEN u1 = mpfactr(i/2, DEFAULTPREC); GEN u2 = mpfactr(i, DEFAULTPREC); if (r1 == r2) t = mulrr(t, powru(mulrr(u1,u2), r1)); else t = mulrr(t, mulrr(powru(u1,r1), powru(u2,r2))); } return t; } /* "small" even i such that limx^i ( (i\2)! )^r1 ( i! )^r2 > B. */ static long get_i0(long r1, long r2, GEN B, GEN limx) { long imin = 1, imax = 1400; while (mpcmp(eval_i(r1,r2,limx, imax), B) < 0) { imin = imax; imax *= 2; } while(imax - imin >= 4) { long m = (imax + imin) >> 1; if (mpcmp(eval_i(r1,r2,limx, m), B) >= 0) imax = m; else imin = m; } return imax & ~1; /* make it even */ } /* assume limx = zeta_get_limx(r1, r2, bit), a t_REAL */ static long zeta_get_i0(long r1, long r2, long bit, GEN limx) { pari_sp av = avma; GEN B = gmul(sqrtr( divrr(powrs(mppi(DEFAULTPREC), r2-3), limx) ), gmul2n(powuu(5, r1), bit + r2)); long i0 = get_i0(r1, r2, B, limx); if (DEBUGLEVEL>1) { err_printf("i0 = %ld\n",i0); err_flush(); } avma = av; return i0; } static void GetST0(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec) { pari_sp av = avma, av1, av2; long ncond, n, j, k, jc, n0, prec2, i0, r1, r2; GEN nf = checknf(bnr), T = *pT, S = *pS; GEN N0, C, an, degs, limx; LISTray LIST; ST_t cScT; /* initializations */ degs = GetDeg(dataCR); ncond = lg(vChar)-1; nf_get_sign(nf,&r1,&r2); C = cgetg(ncond+1, t_VEC); N0 = cgetg(ncond+1, t_VECSMALL); n0 = 0; limx = zeta_get_limx(r1, r2, prec2nbits(prec)); for (j = 1; j <= ncond; j++) { GEN dtcr = gel(dataCR, mael(vChar,j,1)), c = ch_C(dtcr); gel(C,j) = c; N0[j] = zeta_get_N0(c, limx); if (n0 < N0[j]) n0 = N0[j]; } i0 = zeta_get_i0(r1, r2, prec2nbits(prec), limx); InitPrimes(bnr, n0, &LIST); prec2 = precdbl(prec) + EXTRA_PREC; cScT.powracpi = powersr(sqrtr(mppi(prec2)), r1); cScT.cS = cgetg(n0+1, t_VEC); cScT.cT = cgetg(n0+1, t_VEC); for (j=1; j<=n0; j++) gel(cScT.cS,j) = gel(cScT.cT,j) = NULL; cScT.i0 = i0; av1 = avma; for (jc = 1; jc <= ncond; jc++) { const GEN LChar = gel(vChar,jc); const long nChar = lg(LChar)-1, NN = N0[jc]; if (DEBUGLEVEL>1) err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", jc,ncond,NN); cScT.c1 = gel(C,jc); init_cScT(&cScT, gel(dataCR, LChar[1]), NN, prec2); av2 = avma; for (k = 1; k <= nChar; k++) { const long t = LChar[k]; if (DEBUGLEVEL>1) err_printf("\tcharacter no: %ld (%ld/%ld)\n", t,k,nChar); if (!isintzero( ch_comp(gel(dataCR, t)) )) { const long d = degs[t]; const GEN dtcr = gel(dataCR, t), z = gel(ch_CHI(dtcr), 2); GEN p1 = gen_0, p2 = gen_0; long c = 0; int **matan = ComputeCoeff(gel(dataCR,t), &LIST, NN, d); for (n = 1; n <= NN; n++) if ((an = EvalCoeff(z, matan[n], d))) { get_cS_cT(&cScT, n); p1 = gadd(p1, gmul(an, gel(cScT.cS,n))); p2 = gadd(p2, gmul(an, gel(cScT.cT,n))); if (++c == 256) { gerepileall(av2,2, &p1,&p2); c = 0; } } gaffect(p1, gel(S,t)); gaffect(conj_i(p2), gel(T,t)); FreeMat(matan, NN); avma = av2; } else if (DEBUGLEVEL>1) err_printf("\t no need to compute this character\n"); } if (DEBUGLEVEL>1) err_printf("\n"); avma = av1; } clear_cScT(&cScT, n0); avma = av; } static void GetST(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec) { const long cl = lg(dataCR) - 1; GEN S, T, nf = checknf(bnr); long j; /* allocate memory for answer */ *pS = S = cgetg(cl+1, t_VEC); *pT = T = cgetg(cl+1, t_VEC); for (j = 1; j <= cl; j++) { gel(S,j) = cgetc(prec); gel(T,j) = cgetc(prec); } if (nf_get_degree(nf) == 2) QuadGetST(bnr, pS, pT, dataCR, vChar, prec); else GetST0(bnr, pS, pT, dataCR, vChar, prec); } /*******************************************************************/ /* */ /* Class fields of real quadratic fields using Stark units */ /* */ /*******************************************************************/ /* compute the Hilbert class field using genus class field theory when the exponent of the class group is exactly 2 (trivial group not covered) */ /* Cf Herz, Construction of class fields, LNM 21, Theorem 1 (VII-6) */ static GEN GenusFieldQuadReal(GEN disc) { long i, i0 = 0, l; pari_sp av = avma; GEN T = NULL, p0 = NULL, P; P = gel(Z_factor(disc), 1); l = lg(P); for (i = 1; i < l; i++) { GEN p = gel(P,i); if (mod4(p) == 3) { p0 = p; i0 = i; break; } } l--; /* remove last prime */ if (i0 == l) l--; /* ... remove p0 and last prime */ for (i = 1; i < l; i++) { GEN p = gel(P,i), d, t; if (i == i0) continue; if (absequaliu(p, 2)) switch (mod32(disc)) { case 8: d = gen_2; break; case 24: d = shifti(p0, 1); break; default: d = p0; break; } else d = (mod4(p) == 1)? p: mulii(p0, p); t = mkpoln(3, gen_1, gen_0, negi(d)); /* x^2 - d */ T = T? ZX_compositum_disjoint(T, t): t; } return gerepileupto(av, polredbest(T, 0)); } static GEN GenusFieldQuadImag(GEN disc) { long i, l; pari_sp av = avma; GEN T = NULL, P; P = gel(absZ_factor(disc), 1); l = lg(P); l--; /* remove last prime */ for (i = 1; i < l; i++) { GEN p = gel(P,i), d, t; if (absequaliu(p, 2)) switch (mod32(disc)) { case 24: d = gen_2; break; /* disc = 8 mod 32 */ case 8: d = gen_m2; break; /* disc =-8 mod 32 */ default: d = gen_m1; break; } else d = (mod4(p) == 1)? p: negi(p); t = mkpoln(3, gen_1, gen_0, negi(d)); /* x^2 - d */ T = T? ZX_compositum_disjoint(T, t): t; } return gerepileupto(av, polredbest(T, 0)); } /* if flag != 0, computes a fast and crude approximation of the result */ static GEN AllStark(GEN data, GEN nf, long flag, long newprec) { const long BND = 300; long cl, i, j, cpt = 0, N, h, v, n, r1, r2, den; pari_sp av, av2; int **matan; GEN bnr = gel(data,1), p1, p2, S, T, polrelnum, polrel, Lp, W, veczeta; GEN vChar, degs, C, dataCR, cond1, L1, an; LISTray LIST; pari_timer ti; nf_get_sign(nf, &r1,&r2); N = nf_get_degree(nf); cond1 = gel(bnr_get_mod(bnr), 2); dataCR = gel(data,5); vChar = sortChars(dataCR); v = 1; while (gequal1(gel(cond1,v))) v++; cl = lg(dataCR)-1; degs = GetDeg(dataCR); h = itos(ZM_det_triangular(gel(data,2))) >> 1; LABDOUB: if (DEBUGLEVEL) timer_start(&ti); av = avma; /* characters with rank > 1 should not be computed */ for (i = 1; i <= cl; i++) { GEN chi = gel(dataCR, i); if (L_vanishes_at_0(chi)) ch_comp(chi) = gen_0; } W = ComputeAllArtinNumbers(dataCR, vChar, (flag >= 0), newprec); if (DEBUGLEVEL) timer_printf(&ti,"Compute W"); Lp = cgetg(cl + 1, t_VEC); if (!flag) { GetST(bnr, &S, &T, dataCR, vChar, newprec); if (DEBUGLEVEL) timer_printf(&ti, "S&T"); for (i = 1; i <= cl; i++) { GEN chi = gel(dataCR, i), v = gen_0; if (!isintzero( ch_comp(chi) )) v = gel(GetValue(chi, gel(W,i), gel(S,i), gel(T,i), 2, newprec), 2); gel(Lp, i) = v; } } else { /* compute a crude approximation of the result */ C = cgetg(cl + 1, t_VEC); for (i = 1; i <= cl; i++) gel(C,i) = ch_C(gel(dataCR, i)); n = zeta_get_N0(vecmax(C), zeta_get_limx(r1, r2, prec2nbits(newprec))); if (n > BND) n = BND; if (DEBUGLEVEL) err_printf("N0 in QuickPol: %ld \n", n); InitPrimes(bnr, n, &LIST); L1 = cgetg(cl+1, t_VEC); /* use L(1) = sum (an / n) */ for (i = 1; i <= cl; i++) { GEN dtcr = gel(dataCR,i); matan = ComputeCoeff(dtcr, &LIST, n, degs[i]); av2 = avma; p1 = real_0(newprec); p2 = gel(ch_CHI(dtcr), 2); for (j = 1; j <= n; j++) if ( (an = EvalCoeff(p2, matan[j], degs[i])) ) p1 = gadd(p1, gdivgs(an, j)); gel(L1,i) = gerepileupto(av2, p1); FreeMat(matan, n); } p1 = gmul2n(powruhalf(mppi(newprec), N-2), 1); for (i = 1; i <= cl; i++) { long r; GEN WW, A = ComputeAChi(gel(dataCR,i), &r, 0, newprec); WW = gmul(gel(C,i), gmul(A, gel(W,i))); gel(Lp,i) = gdiv(gmul(WW, conj_i(gel(L1,i))), p1); } } p1 = ComputeLift(gel(data,4)); den = flag ? h: 2*h; veczeta = cgetg(h + 1, t_VEC); for (i = 1; i <= h; i++) { GEN z = gen_0, sig = gel(p1,i); for (j = 1; j <= cl; j++) { GEN dtcr = gel(dataCR,j), CHI = ch_CHI(dtcr); GEN t = mulreal(gel(Lp,j), CharEval(CHI, sig)); if (chi_get_deg(CHI) != 2) t = gmul2n(t, 1); /* character not real */ z = gadd(z, t); } gel(veczeta,i) = gdivgs(z, den); } for (j = 1; j <= h; j++) gel(veczeta,j) = gmul2n(gcosh(gel(veczeta,j), newprec), 1); polrelnum = roots_to_pol(veczeta, 0); if (DEBUGLEVEL) { if (DEBUGLEVEL>1) { err_printf("polrelnum = %Ps\n", polrelnum); err_printf("zetavalues = %Ps\n", veczeta); if (!flag) err_printf("Checking the square-root of the Stark unit...\n"); } timer_printf(&ti, "Compute %s", flag? "quickpol": "polrelnum"); } if (flag) return gerepilecopy(av, polrelnum); /* try to recognize this polynomial */ polrel = RecCoeff(nf, polrelnum, v, newprec); if (!polrel) { for (j = 1; j <= h; j++) gel(veczeta,j) = gsubgs(gsqr(gel(veczeta,j)), 2); polrelnum = roots_to_pol(veczeta, 0); if (DEBUGLEVEL) { if (DEBUGLEVEL>1) { err_printf("It's not a square...\n"); err_printf("polrelnum = %Ps\n", polrelnum); } timer_printf(&ti, "Compute polrelnum"); } polrel = RecCoeff(nf, polrelnum, v, newprec); } if (!polrel) /* FAILED */ { const long EXTRA_BITS = 64; long incr_pr; if (++cpt >= 3) pari_err_PREC( "stark (computation impossible)"); /* estimate needed precision */ incr_pr = prec2nbits(gprecision(polrelnum))- gexpo(polrelnum); if (incr_pr < 0) incr_pr = -incr_pr + EXTRA_BITS; newprec += nbits2extraprec(maxss(3*EXTRA_BITS, cpt*incr_pr)); if (DEBUGLEVEL) pari_warn(warnprec, "AllStark", newprec); nf = nfnewprec_shallow(nf, newprec); dataCR = CharNewPrec(dataCR, nf, newprec); gerepileall(av, 2, &nf, &dataCR); goto LABDOUB; } if (DEBUGLEVEL) { if (DEBUGLEVEL>1) err_printf("polrel = %Ps\n", polrel); timer_printf(&ti, "Recpolnum"); } return gerepilecopy(av, polrel); } /********************************************************************/ /* Main functions */ /********************************************************************/ static GEN get_subgroup(GEN H, GEN cyc, const char *s) { if (!H || gequal0(H)) return diagonal_shallow(cyc); if (typ(H) != t_MAT) pari_err_TYPE(stack_strcat(s," [subgroup]"), H); RgM_check_ZM(H, s); return ZM_hnfmodid(H, cyc); } GEN bnrstark(GEN bnr, GEN subgrp, long prec) { long N, newprec; pari_sp av = avma; GEN bnf, p1, cycbnr, nf, data, dtQ; /* check the bnr */ checkbnr(bnr); bnf = checkbnf(bnr); nf = bnf_get_nf(bnf); N = nf_get_degree(nf); if (N == 1) return galoissubcyclo(bnr, subgrp, 0, 0); /* check the bnf */ if (!nf_get_varn(nf)) pari_err_PRIORITY("bnrstark", nf_get_pol(nf), "=", 0); if (nf_get_r2(nf)) pari_err_DOMAIN("bnrstark", "r2", "!=", gen_0, nf); subgrp = get_subgroup(subgrp,bnr_get_cyc(bnr),"bnrstark"); /* compute bnr(conductor) */ p1 = bnrconductor_i(bnr, subgrp, 2); bnr = gel(p1,2); cycbnr = bnr_get_cyc(bnr); subgrp = gel(p1,3); if (gequal1( ZM_det_triangular(subgrp) )) { avma = av; return pol_x(0); } /* check the class field */ if (!gequal0(gel(bnr_get_mod(bnr), 2))) pari_err_DOMAIN("bnrstark", "r2(class field)", "!=", gen_0, bnr); /* find a suitable extension N */ dtQ = InitQuotient(subgrp); data = FindModulus(bnr, dtQ, &newprec); if (!data) { GEN vec, H, cyc = gel(dtQ,2), U = gel(dtQ,3), M = RgM_inv(U); long i, j = 1, l = lg(M); /* M = indep. generators of Cl_f/subgp, restrict to cyclic components */ vec = cgetg(l, t_VEC); for (i = 1; i < l; i++) { if (is_pm1(gel(cyc,i))) continue; H = ZM_hnfmodid(vecsplice(M,i), cycbnr); gel(vec,j++) = bnrstark(bnr, H, prec); } setlg(vec, j); return gerepilecopy(av, vec); } if (newprec > prec) { if (DEBUGLEVEL>1) err_printf("new precision: %ld\n", newprec); nf = nfnewprec_shallow(nf, newprec); } return gerepileupto(av, AllStark(data, nf, 0, newprec)); } /* For each character of Cl(bnr)/subgp, compute L(1, chi) (or equivalently * the first non-zero term c(chi) of the expansion at s = 0). * If flag & 1: compute the value at s = 1 (for non-trivial characters), * else compute the term c(chi) and return [r(chi), c(chi)] where r(chi) is * the order of L(s, chi) at s = 0. * If flag & 2: compute the value of the L-function L_S(s, chi) where S is the * set of places dividing the modulus of bnr (and the infinite places), * else * compute the value of the primitive L-function attached to chi, * If flag & 4: return also the character */ GEN bnrL1(GEN bnr, GEN subgp, long flag, long prec) { GEN cyc, L1, allCR, listCR; GEN indCR, invCR, Qt; long cl, i, nc; pari_sp av = avma; checkbnr(bnr); if (flag < 0 || flag > 8) pari_err_FLAG("bnrL1"); cyc = bnr_get_cyc(bnr); subgp = get_subgroup(subgp, cyc, "bnrL1"); Qt = InitQuotient(subgp); cl = itou(gel(Qt,1)); /* compute all characters */ allCR = EltsOfGroup(cl, gel(Qt,2)); /* make a list of all non-trivial characters modulo conjugation */ listCR = cgetg(cl, t_VEC); indCR = cgetg(cl, t_VECSMALL); invCR = cgetg(cl, t_VECSMALL); nc = 0; for (i = 1; i < cl; i++) { /* lift to a character on Cl(bnr) */ GEN lchi = LiftChar(Qt, cyc, gel(allCR,i)); GEN clchi = charconj(cyc, lchi); long j, a = 0; for (j = 1; j <= nc; j++) if (ZV_equal(gmael(listCR, j, 1), clchi)) { a = j; break; } if (!a) { nc++; gel(listCR,nc) = mkvec2(lchi, bnrconductorofchar(bnr, lchi)); indCR[i] = nc; invCR[nc] = i; } else indCR[i] = -invCR[a]; gel(allCR,i) = lchi; } settyp(allCR[cl], t_VEC); /* set correct type for trivial character */ setlg(listCR, nc + 1); L1 = cgetg((flag&1)? cl: cl+1, t_VEC); if (nc) { GEN dataCR = InitChar(bnr, listCR, prec); GEN W, S, T, vChar = sortChars(dataCR); GetST(bnr, &S, &T, dataCR, vChar, prec); W = ComputeAllArtinNumbers(dataCR, vChar, 1, prec); for (i = 1; i < cl; i++) { long a = indCR[i]; if (a > 0) gel(L1,i) = GetValue(gel(dataCR,a), gel(W,a), gel(S,a), gel(T,a), flag, prec); else gel(L1,i) = conj_i(gel(L1,-a)); } } if (!(flag & 1)) gel(L1,cl) = GetValue1(bnr, flag & 2, prec); else cl--; if (flag & 4) { for (i = 1; i <= cl; i++) gel(L1,i) = mkvec2(gel(allCR,i), gel(L1,i)); } return gerepilecopy(av, L1); } /*******************************************************************/ /* */ /* Hilbert and Ray Class field using Stark */ /* */ /*******************************************************************/ /* P in A[x,y], deg_y P < 2, return P0 and P1 in A[x] such that P = P0 + P1 y */ static void split_pol_quad(GEN P, GEN *gP0, GEN *gP1) { long i, l = lg(P); GEN P0 = cgetg(l, t_POL), P1 = cgetg(l, t_POL); P0[1] = P1[1] = P[1]; for (i = 2; i < l; i++) { GEN c = gel(P,i), c0 = c, c1 = gen_0; if (typ(c) == t_POL) /* write c = c1 y + c0 */ switch(degpol(c)) { case -1: c0 = gen_0; break; default: c1 = gel(c,3); /* fall through */ case 0: c0 = gel(c,2); break; } gel(P0,i) = c0; gel(P1,i) = c1; } *gP0 = normalizepol_lg(P0, l); *gP1 = normalizepol_lg(P1, l); } /* k = nf quadratic field, P relative equation of H_k (Hilbert class field) * return T in Z[X], such that H_k / Q is the compositum of Q[X]/(T) and k */ static GEN makescind(GEN nf, GEN P) { GEN Pp, p, pol, G, L, a, roo, P0,P1, Ny,Try, nfpol = nf_get_pol(nf); long i, is_P; P = lift_shallow(P); split_pol_quad(P, &P0, &P1); /* P = P0 + y P1, Norm_{k/Q}(P) = P0^2 + Tr y P0P1 + Ny P1^2, irreducible/Q */ Ny = gel(nfpol, 2); Try = negi(gel(nfpol, 3)); pol = RgX_add(RgX_sqr(P0), RgX_Rg_mul(RgX_sqr(P1), Ny)); if (signe(Try)) pol = RgX_add(pol, RgX_Rg_mul(RgX_mul(P0,P1), Try)); /* pol = rnfequation(nf, P); */ G = galoisinit(pol, NULL); L = gal_get_group(G); p = gal_get_p(G); a = FpX_oneroot(nfpol, p); /* P mod a prime \wp above p (which splits) */ Pp = FpXY_evalx(P, a, p); roo = gal_get_roots(G); is_P = gequal0( FpX_eval(Pp, remii(gel(roo,1),p), p) ); /* each roo[i] mod p is a root of P or (exclusive) tau(P) mod \wp */ /* record whether roo[1] is a root of P or tau(P) */ for (i = 1; i < lg(L); i++) { GEN perm = gel(L,i); long k = perm[1]; if (k == 1) continue; k = gequal0( FpX_eval(Pp, remii(gel(roo,k),p), p) ); /* roo[k] is a root of the other polynomial */ if (k != is_P) { long o = perm_order(perm); if (o != 2) perm = perm_pow(perm, o >> 1); /* perm has order two and doesn't belong to Gal(H_k/k) */ return galoisfixedfield(G, perm, 1, varn(P)); } } pari_err_BUG("makescind"); return NULL; /*LCOV_EXCL_LINE*/ } /* pbnf = NULL if no bnf is needed, f = NULL may be passed for a trivial * conductor */ static void quadray_init(GEN *pD, GEN f, GEN *pbnf, long prec) { GEN D = *pD, nf, bnf = NULL; if (typ(D) == t_INT) { int isfund; if (pbnf) { long v = f? gvar(f): NO_VARIABLE; if (v == NO_VARIABLE) v = 1; bnf = Buchall(quadpoly0(D, v), nf_FORCE, prec); nf = bnf_get_nf(bnf); isfund = equalii(D, nf_get_disc(nf)); } else isfund = Z_isfundamental(D); if (!isfund) pari_err_DOMAIN("quadray", "isfundamental(D)", "=",gen_0, D); } else { bnf = checkbnf(D); nf = bnf_get_nf(bnf); if (nf_get_degree(nf) != 2) pari_err_DOMAIN("quadray", "degree", "!=", gen_2, nf_get_pol(nf)); D = nf_get_disc(nf); } if (pbnf) *pbnf = bnf; *pD = D; } /* compute the polynomial over Q of the Hilbert class field of Q(sqrt(D)) where D is a positive fundamental discriminant */ static GEN quadhilbertreal(GEN D, long prec) { pari_sp av = avma; long newprec; GEN bnf; VOLATILE GEN bnr, dtQ, data, nf, cyc, M; pari_timer ti; if (DEBUGLEVEL) timer_start(&ti); (void)≺ /* prevent longjmp clobbering it */ (void)&bnf; /* prevent longjmp clobbering it, avoid warning due to * quadray_init call : discards qualifiers from pointer type */ quadray_init(&D, NULL, &bnf, prec); cyc = bnf_get_cyc(bnf); if (lg(cyc) == 1) { avma = av; return pol_x(0); } /* if the exponent of the class group is 2, use Genus Theory */ if (absequaliu(gel(cyc,1), 2)) return gerepileupto(av, GenusFieldQuadReal(D)); bnr = Buchray(bnf, gen_1, nf_INIT); M = diagonal_shallow(bnr_get_cyc(bnr)); dtQ = InitQuotient(M); nf = bnf_get_nf(bnf); for(;;) { VOLATILE GEN pol = NULL; pari_CATCH(e_PREC) { prec += EXTRA_PREC; if (DEBUGLEVEL) pari_warn(warnprec, "quadhilbertreal", prec); bnr = bnrnewprec_shallow(bnr, prec); bnf = bnr_get_bnf(bnr); nf = bnf_get_nf(bnf); } pari_TRY { /* find the modulus defining N */ pari_timer T; if (DEBUGLEVEL) timer_start(&T); data = FindModulus(bnr, dtQ, &newprec); if (DEBUGLEVEL) timer_printf(&T,"FindModulus"); if (!data) { long i, l = lg(M); GEN vec = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN t = gcoeff(M,i,i); gcoeff(M,i,i) = gen_1; gel(vec,i) = bnrstark(bnr, M, prec); gcoeff(M,i,i) = t; } return gerepileupto(av, vec); } if (newprec > prec) { if (DEBUGLEVEL>1) err_printf("new precision: %ld\n", newprec); nf = nfnewprec_shallow(nf, newprec); } pol = AllStark(data, nf, 0, newprec); } pari_ENDCATCH; if (pol) { pol = makescind(nf, pol); return gerepileupto(av, polredbest(pol, 0)); } } } /*******************************************************************/ /* */ /* Hilbert and Ray Class field using CM (Schertz) */ /* */ /*******************************************************************/ /* form^2 = 1 ? */ static int hasexp2(GEN form) { GEN a = gel(form,1), b = gel(form,2), c = gel(form,3); return !signe(b) || absequalii(a,b) || equalii(a,c); } static int uhasexp2(GEN form) { long a = form[1], b = form[2], c = form[3]; return !b || a == labs(b) || a == c; } GEN qfbforms(GEN D) { ulong d = itou(D), dover3 = d/3, t, b2, a, b, c, h; GEN L = cgetg((long)(sqrt((double)d) * log2(d)), t_VEC); b2 = b = (d&1); h = 0; if (!b) /* b = 0 treated separately to avoid special cases */ { t = d >> 2; /* (b^2 - D) / 4*/ for (a=1; a*a<=t; a++) if (c = t/a, t == c*a) gel(L,++h) = mkvecsmall3(a,0,c); b = 2; b2 = 4; } /* now b > 0, b = D (mod 2) */ for ( ; b2 <= dover3; b += 2, b2 = b*b) { t = (b2 + d) >> 2; /* (b^2 - D) / 4*/ /* b = a */ if (c = t/b, t == c*b) gel(L,++h) = mkvecsmall3(b,b,c); /* b < a < c */ for (a = b+1; a*a < t; a++) if (c = t/a, t == c*a) { gel(L,++h) = mkvecsmall3(a, b,c); gel(L,++h) = mkvecsmall3(a,-b,c); } /* a = c */ if (a * a == t) gel(L,++h) = mkvecsmall3(a,b,a); } setlg(L,h+1); return L; } /* gcd(n, 24) */ static long GCD24(long n) { switch(n % 24) { case 0: return 24; case 1: return 1; case 2: return 2; case 3: return 3; case 4: return 4; case 5: return 1; case 6: return 6; case 7: return 1; case 8: return 8; case 9: return 3; case 10: return 2; case 11: return 1; case 12: return 12; case 13: return 1; case 14: return 2; case 15: return 3; case 16: return 8; case 17: return 1; case 18: return 6; case 19: return 1; case 20: return 4; case 21: return 3; case 22: return 2; case 23: return 1; default: return 0; } } struct gpq_data { long p, q; GEN sqd; /* sqrt(D), t_REAL */ GEN u, D; GEN pq, pq2; /* p*q, 2*p*q */ GEN qfpq ; /* class of \P * \Q */ }; /* find P and Q two non principal prime ideals (above p <= q) such that * cl(P) = cl(Q) if P,Q have order 2 in Cl(K). * Ensure that e = 24 / gcd(24, (p-1)(q-1)) = 1 */ /* D t_INT, discriminant */ static void init_pq(GEN D, struct gpq_data *T) { const long Np = 6547; /* N.B. primepi(50000) = 5133 */ const ulong maxq = 50000; GEN listp = cgetg(Np + 1, t_VECSMALL); /* primes p */ GEN listP = cgetg(Np + 1, t_VEC); /* primeform(p) if of order 2, else NULL */ GEN gcd24 = cgetg(Np + 1, t_VECSMALL); /* gcd(p-1, 24) */ forprime_t S; long l = 1; double best = 0.; ulong q; u_forprime_init(&S, 2, ULONG_MAX); T->D = D; T->p = T->q = 0; for(;;) { GEN Q; long i, gcdq, mod; int order2, store; double t; q = u_forprime_next(&S); if (best > 0 && q >= maxq) { if (DEBUGLEVEL) pari_warn(warner,"possibly suboptimal (p,q) for D = %Ps", D); break; } if (kroiu(D, q) < 0) continue; /* inert */ Q = redimag(primeform_u(D, q)); if (is_pm1(gel(Q,1))) continue; /* Q | q is principal */ store = 1; order2 = hasexp2(Q); gcd24[l] = gcdq = GCD24(q-1); mod = 24 / gcdq; /* mod must divide p-1 otherwise e > 1 */ listp[l] = q; gel(listP,l) = order2 ? Q : NULL; t = (q+1)/(double)(q-1); for (i = 1; i < l; i++) /* try all (p, q), p < q in listp */ { long p = listp[i], gcdp = gcd24[i]; double b; /* P,Q order 2 => cl(Q) = cl(P) */ if (order2 && gel(listP,i) && !gequal(gel(listP,i), Q)) continue; if (gcdp % gcdq == 0) store = 0; /* already a better one in the list */ if ((p-1) % mod) continue; b = (t*(p+1)) / (p-1); /* (p+1)(q+1) / (p-1)(q-1) */ if (b > best) { store = 0; /* (p,q) always better than (q,r) for r >= q */ best = b; T->q = q; T->p = p; if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", p, q); } /* won't improve with this q as largest member */ if (best > 0) break; } /* if !store or (q,r) won't improve on current best pair, forget that q */ if (store && t*t > best) if (++l >= Np) pari_err_BUG("quadhilbert (not enough primes)"); if (!best) /* (p,q) with p < q always better than (q,q) */ { /* try (q,q) */ if (gcdq >= 12 && umodiu(D, q)) /* e = 1 and unramified */ { double b = (t*q) / (q-1); /* q(q+1) / (q-1)^2 */ if (b > best) { best = b; T->q = T->p = q; if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", q, q); } } } /* If (p1+1)(q+1) / (p1-1)(q-1) <= best, we can no longer improve * even with best p : stop */ if ((listp[1]+1)*t <= (listp[1]-1)*best) break; } if (DEBUGLEVEL>1) err_printf("(p, q) = %ld, %ld; gain = %f\n", T->p, T->q, 12*best); } static GEN gpq(GEN form, struct gpq_data *T) { pari_sp av = avma; long a = form[1], b = form[2], c = form[3]; long p = T->p, q = T->q; GEN form2, w, z; int fl, real = 0; form2 = qficomp(T->qfpq, mkvec3s(a, -b, c)); /* form2 and form yield complex conjugate roots : only compute for the * lexicographically smallest of the 2 */ fl = cmpis(gel(form2,1), a); if (fl <= 0) { if (fl < 0) return NULL; fl = cmpis(gel(form2,2), b); if (fl <= 0) { if (fl < 0) return NULL; /* form == form2 : real root */ real = 1; } } if (p == 2) { /* (a,b,c) = (1,1,0) mod 2 ? */ if (a % q == 0 && (a & b & 1) && !(c & 1)) { /* apply S : make sure that (a,b,c) represents odd values */ lswap(a,c); b = -b; } } if (a % p == 0 || a % q == 0) { /* apply T^k, look for c' = a k^2 + b k + c coprime to N */ while (c % p == 0 || c % q == 0) { c += a + b; b += a << 1; } lswap(a, c); b = -b; /* apply S */ } /* now (a,b,c) ~ form and (a,pq) = 1 */ /* gcd(2a, u) = 2, w = u mod 2pq, -b mod 2a */ w = Z_chinese(T->u, stoi(-b), T->pq2, utoipos(a << 1)); z = double_eta_quotient(utoipos(a), w, T->D, T->p, T->q, T->pq, T->sqd); if (real && typ(z) == t_COMPLEX) z = gcopy(gel(z, 1)); return gerepileupto(av, z); } /* returns an equation for the Hilbert class field of Q(sqrt(D)), D < 0 * fundamental discriminant */ static GEN quadhilbertimag(GEN D) { GEN L, P, Pi, Pr, qfp, u; pari_sp av = avma; long h, i, prec; struct gpq_data T; pari_timer ti; if (DEBUGLEVEL>1) timer_start(&ti); if (lgefint(D) == 3) switch (D[2]) { /* = |D|; special cases where e > 1 */ case 3: case 4: case 7: case 8: case 11: case 19: case 43: case 67: case 163: return pol_x(0); } L = qfbforms(D); h = lg(L)-1; if ((1L << vals(h)) == h) /* power of 2 */ { /* check whether > |Cl|/2 elements have order <= 2 ==> 2-elementary */ long lim = (h>>1) + 1; for (i=1; i <= lim; i++) if (!uhasexp2(gel(L,i))) break; if (i > lim) return GenusFieldQuadImag(D); } if (DEBUGLEVEL>1) timer_printf(&ti,"class number = %ld",h); init_pq(D, &T); qfp = primeform_u(D, T.p); T.pq = muluu(T.p, T.q); T.pq2 = shifti(T.pq,1); if (T.p == T.q) { GEN qfbp2 = qficompraw(qfp, qfp); u = gel(qfbp2,2); T.u = modii(u, T.pq2); T.qfpq = redimag(qfbp2); } else { GEN qfq = primeform_u(D, T.q), bp = gel(qfp,2), bq = gel(qfq,2); T.u = Z_chinese(bp, bq, utoipos(T.p << 1), utoipos(T.q << 1)); /* T.u = bp (mod 2p), T.u = bq (mod 2q) */ T.qfpq = qficomp(qfp, qfq); } /* u modulo 2pq */ prec = LOWDEFAULTPREC; Pr = cgetg(h+1,t_VEC); Pi = cgetg(h+1,t_VEC); for(;;) { long ex, exmax = 0, r1 = 0, r2 = 0; pari_sp av0 = avma; T.sqd = sqrtr_abs(itor(D, prec)); for (i=1; i<=h; i++) { GEN s = gpq(gel(L,i), &T); if (DEBUGLEVEL>3) err_printf("%ld ", i); if (!s) continue; if (typ(s) != t_COMPLEX) gel(Pr, ++r1) = s; /* real root */ else gel(Pi, ++r2) = s; ex = gexpo(s); if (ex > 0) exmax += ex; } if (DEBUGLEVEL>1) timer_printf(&ti,"roots"); setlg(Pr, r1+1); setlg(Pi, r2+1); P = roots_to_pol_r1(shallowconcat(Pr,Pi), 0, r1); P = grndtoi(P,&exmax); if (DEBUGLEVEL>1) timer_printf(&ti,"product, error bits = %ld",exmax); if (exmax <= -10) break; avma = av0; prec += nbits2extraprec(prec2nbits(DEFAULTPREC)+exmax); if (DEBUGLEVEL) pari_warn(warnprec,"quadhilbertimag",prec); } return gerepileupto(av,P); } GEN quadhilbert(GEN D, long prec) { GEN d = D; quadray_init(&d, NULL, NULL, 0); return (signe(d)>0)? quadhilbertreal(D,prec) : quadhilbertimag(d); } /* return a vector of all roots of 1 in bnf [not necessarily quadratic] */ static GEN getallrootsof1(GEN bnf) { GEN T, u, nf = bnf_get_nf(bnf), tu; long i, n = bnf_get_tuN(bnf); if (n == 2) { long N = nf_get_degree(nf); return mkvec2(scalarcol_shallow(gen_m1, N), scalarcol_shallow(gen_1, N)); } tu = poltobasis(nf, bnf_get_tuU(bnf)); T = zk_multable(nf, tu); u = cgetg(n+1, t_VEC); gel(u,1) = tu; for (i=2; i <= n; i++) gel(u,i) = ZM_ZC_mul(T, gel(u,i-1)); return u; } /* assume bnr has the right conductor */ static GEN get_lambda(GEN bnr) { GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf), pol = nf_get_pol(nf); GEN f = gel(bnr_get_mod(bnr), 1), labas, lamodf, u; long a, b, f2, i, lu, v = varn(pol); f2 = 2 * itos(gcoeff(f,1,1)); u = getallrootsof1(bnf); lu = lg(u); for (i=1; i1) err_printf("quadray: looking for [a,b] != unit mod 2f\n[a,b] = "); for (a=0; a1) err_printf("[%ld,%ld] ",a,b); labas = poltobasis(nf, la); lamodf = ZC_hnfrem(labas, f); for (i=1; i1) err_printf("\n"); err_printf("lambda = %Ps\n",la); } return labas; } pari_err_BUG("get_lambda"); return NULL; } static GEN to_approx(GEN nf, GEN a) { GEN M = nf_get_M(nf); return gadd(gel(a,1), gmul(gcoeff(M,1,2),gel(a,2))); } /* Z-basis for a (over C) */ static GEN get_om(GEN nf, GEN a) { return mkvec2(to_approx(nf,gel(a,2)), to_approx(nf,gel(a,1))); } /* Compute all elts in class group G = [|G|,c,g], c=cyclic factors, g=gens. * Set list[j + 1] = g1^e1...gk^ek where j is the integer * ek + ck [ e(k-1) + c(k-1) [... + c2 [e1]]...] */ static GEN getallelts(GEN bnr) { GEN nf, C, c, g, list, pows, gk; long lc, i, j, no; nf = bnr_get_nf(bnr); no = itos( bnr_get_no(bnr) ); c = bnr_get_cyc(bnr); g = bnr_get_gen_nocheck(bnr); lc = lg(c)-1; list = cgetg(no+1,t_VEC); gel(list,1) = matid(nf_get_degree(nf)); /* (1) */ if (!no) return list; pows = cgetg(lc+1,t_VEC); c = leafcopy(c); settyp(c, t_VECSMALL); for (i=1; i<=lc; i++) { long k = itos(gel(c,i)); c[i] = k; gk = cgetg(k, t_VEC); gel(gk,1) = gel(g,i); for (j=2; j j only involves g(k-i)...gk */ i = 1; for (j=1; j < C[1]; j++) gel(list, j+1) = gmael(pows,lc,j); while(j 1) a = idealmoddivisor(bnr, idealmul(nf, a, gel(list,k))); gel(list, ++j) = a; } return list; } /* x quadratic integer (approximate), recognize it. If error return NULL */ static GEN findbezk(GEN nf, GEN x) { GEN a,b, M = nf_get_M(nf), u = gcoeff(M,1,2); long ea, eb; /* u t_COMPLEX generator of nf.zk, write x ~ a + b u, a,b in Z */ b = grndtoi(mpdiv(imag_i(x), gel(u,2)), &eb); if (eb > -20) return NULL; a = grndtoi(mpsub(real_i(x), mpmul(b,gel(u,1))), &ea); if (ea > -20) return NULL; return signe(b)? coltoalg(nf, mkcol2(a,b)): a; } static GEN findbezk_pol(GEN nf, GEN x) { long i, lx = lg(x); GEN y = cgetg(lx,t_POL); for (i=2; i20 || gexpo(p2)> prec2nbits(minss(prec,realprec(p2)))-10) return NULL; return gexp(p1,prec); } /* Computes P_2(X)=polynomial in Z_K[X] closest to prod_gc(X-th2(gc)) where the product is over the ray class group bnr.*/ static GEN computeP2(GEN bnr, long prec) { long clrayno, i, first = 1; pari_sp av=avma, av2; GEN listray, P0, P, lanum, la = get_lambda(bnr); GEN nf = bnr_get_nf(bnr), f = gel(bnr_get_mod(bnr), 1); listray = getallelts(bnr); clrayno = lg(listray)-1; av2 = avma; PRECPB: if (!first) { if (DEBUGLEVEL) pari_warn(warnprec,"computeP2",prec); nf = gerepilecopy(av2, nfnewprec_shallow(checknf(bnr),prec)); } first = 0; lanum = to_approx(nf,la); P = cgetg(clrayno+1,t_VEC); for (i=1; i<=clrayno; i++) { GEN om = get_om(nf, idealdiv(nf,f,gel(listray,i))); GEN s = computeth2(om,lanum,prec); if (!s) { prec = precdbl(prec); goto PRECPB; } gel(P,i) = s; } P0 = roots_to_pol(P, 0); P = findbezk_pol(nf, P0); if (!P) { prec = get_prec(P0, prec); goto PRECPB; } return gerepilecopy(av, P); } #define nexta(a) (a>0 ? -a : 1-a) static GEN do_compo(GEN A0, GEN B) { long a, i, l = lg(B), v = fetch_var_higher(); GEN A, z; /* now v > x = pol_x(0) > nf variable */ B = leafcopy(B); setvarn(B, v); for (i = 2; i < l; i++) gel(B,i) = monomial(gel(B,i), l-i-1, 0); /* B := x^deg(B) B(v/x) */ A = A0 = leafcopy(A0); setvarn(A0, v); for (a = 0;; a = nexta(a)) { if (a) A = RgX_translate(A0, stoi(a)); z = resultant(A,B); /* in variable 0 */ if (issquarefree(z)) break; } (void)delete_var(); return z; } #undef nexta static GEN galoisapplypol(GEN nf, GEN s, GEN x) { long i, lx = lg(x); GEN y = cgetg(lx,t_POL); for (i=2; i>2); if (absequalui(ell,D)) /* ell = |D| */ { p2 = gcoeff(nffactor(nf,p2),1,1); return do_compo(p1,p2); } if (ell%4 == 3) ell = -ell; /* nf = K = Q(a), L = K(b) quadratic extension = Q(t) */ polLK = quadpoly(stoi(ell)); /* relative polynomial */ res = rnfequation2(nf, polLK); vx = nf_get_varn(nf); polL = gsubst(gel(res,1),0,pol_x(vx)); /* = charpoly(t) */ a = gsubst(lift_shallow(gel(res,2)), 0,pol_x(vx)); b = gsub(pol_x(vx), gmul(gel(res,3), a)); nfL = nfinit(polL, DEFAULTPREC); p1 = gcoeff(nffactor(nfL,p1),1,1); p2 = gcoeff(nffactor(nfL,p2),1,1); p3 = do_compo(p1,p2); /* relative equation over L */ /* compute non trivial s in Gal(L / K) */ sb= gneg(gadd(b, RgX_coeff(polLK,1))); /* s(b) = Tr(b) - b */ s = gadd(pol_x(vx), gsub(sb, b)); /* s(t) = t + s(b) - b */ p3 = gmul(p3, galoisapplypol(nfL, s, p3)); return findquad_pol(nf_get_pol(nf), a, p3); } /* I integral ideal in HNF. (x) = I, x small in Z ? */ static long isZ(GEN I) { GEN x = gcoeff(I,1,1); if (signe(gcoeff(I,1,2)) || !equalii(x, gcoeff(I,2,2))) return 0; return is_bigint(x)? -1: itos(x); } /* Treat special cases directly. return NULL if not special case */ static GEN treatspecialsigma(GEN bnr) { GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf); GEN f = gel(bnr_get_mod(bnr), 1), D = nf_get_disc(nf); GEN p1, p2; long Ds, fl, tryf, i = isZ(f); if (i == 1) return quadhilbertimag(D); /* f = 1 */ if (absequaliu(D,3)) /* Q(j) */ { if (i == 4 || i == 5 || i == 7) return polcyclo(i,0); if (!absequaliu(gcoeff(f,1,1),9) || !absequaliu(Z_content(f),3)) return NULL; /* f = P_3^3 */ p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf)); return gadd(pol_xn(3,0), p1); /* x^3+j */ } if (absequaliu(D,4)) /* Q(i) */ { if (i == 3 || i == 5) return polcyclo(i,0); if (i != 4) return NULL; p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf)); return gadd(pol_xn(2,0), p1); /* x^2+i */ } Ds = smodis(D,48); if (i) { if (i==2 && Ds%16== 8) return compocyclo(nf, 4,1); if (i==3 && Ds% 3== 1) return compocyclo(nf, 3,1); if (i==4 && Ds% 8== 1) return compocyclo(nf, 4,1); if (i==6 && Ds ==40) return compocyclo(nf,12,1); return NULL; } p1 = gcoeff(f,1,1); /* integer > 0 */ tryf = itou_or_0(p1); if (!tryf) return NULL; p2 = gcoeff(f,2,2); /* integer > 0 */ if (is_pm1(p2)) fl = 0; else { if (Ds % 16 != 8 || !absequaliu(Z_content(f),2)) return NULL; fl = 1; tryf >>= 1; } if (tryf <= 3 || umodiu(D, tryf) || !uisprime(tryf)) return NULL; if (fl) tryf <<= 2; return compocyclo(nf,tryf,2); } GEN quadray(GEN D, GEN f, long prec) { GEN bnr, y, bnf; pari_sp av = avma; if (isint1(f)) return quadhilbert(D, prec); quadray_init(&D, f, &bnf, prec); bnr = Buchray(bnf, f, nf_INIT|nf_GEN); if (is_pm1(bnr_get_no(bnr))) { avma = av; return pol_x(0); } if (signe(D) > 0) y = bnrstark(bnr,NULL,prec); else { bnr = gel(bnrconductor_i(bnr,NULL,2), 2); y = treatspecialsigma(bnr); if (!y) y = computeP2(bnr, prec); } return gerepileupto(av, y); } pari-2.11.2/src/modules/ellfromeqn.c0000644000175000017500000002315613201017466015734 0ustar billbill/* Copyright (C) 2015 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* This file is a C version by Bill Allombert of a GP script by Fernando Rodriguez-Villegas */ /* --------------- GP code --------------------------------------- */ /* http://www.ma.utexas.edu/users/villegas/cnt/jacobians.gp */ /* */ /* Description: Compute long Weierstrass equation for genus 1 curve */ /* given by a plane curve */ /* */ /* Original Author: Fernando Rodriguez-Villegas */ /* villegas@math.utexas.edu */ /* University of Texas at Austin */ /* */ /* Created: Tue Jun 7 2005 */ /* */ /*----------------------------------------------------------------- */ /* The mathematic behind this is described in On the Jacobians of plane cubics, Artin, Michael and Rodriguez-Villegas, Fernando and Tate, John, Advances in Mathematics, 198, 2005, 1, 366--382 DOI: 10.1016/j.aim.2005.06.004 URL: http://dx.doi.org/10.1016/j.aim.2005.06.004 PDF: http://www.sciencedirect.com/science/article/pii/S0001870805001775 */ /* Input: coefficients of a cubic */ /*t0*y^3+(s1+s0*x)*y^2 +(r2+r1*x+r0*x^2)*y+(q3+q2*x+q1*x^2+q0*x^3)=0*/ static GEN jac_cubic(GEN t0, GEN s0, GEN s1, GEN r0, GEN r1, GEN r2, GEN q0, GEN q1, GEN q2, GEN q3) { GEN p1 = cgetg(6, t_VEC); gel(p1, 1) = gcopy(r1); gel(p1, 2) = gneg(gadd(gadd(gmul(s0, q2), gmul(s1, q1)), gmul(r0, r2))); gel(p1, 3) = gadd(gmul(gsub(gmul(gmulsg(9, t0), q0), gmul(s0, r0)), q3), gadd(gmul(gsub(gmul(gneg(t0), q1), gmul(s1, r0)), q2), gsub(gmul(gmul(gneg(s0), r2), q1), gmul(gmul(s1, r2), q0)))); gel(p1, 4) = gadd(gmul(gadd(gmul(gadd(gmul(gmulsg(-3, t0), r0), gsqr(s0)), q1), gadd(gmul(gmul(gmulsg(-3, s1), s0), q0), gmul(s1, gsqr(r0)))), q3), gadd(gadd(gmul(gmul(t0, r0), gsqr(q2)), gmul(gadd(gmul(gmul(s1, s0), q1), gadd(gmul(gadd(gmul(gmulsg(-3, t0), r2), gsqr(s1)), q0), gmul(gmul(s0, r0), r2))), q2)), gadd(gadd(gmul(gmul(t0, r2), gsqr(q1)), gmul(gmul(gmul(s1, r0), r2), q1)), gmul(gmul(s0, gsqr(r2)), q0)))); gel(p1, 5) = gadd(gadd(gmul(gsub(gadd(gmul(gmulsg(-27, gsqr(t0)), gsqr(q0)), gmul(gsub(gmul(gmul(gmulsg(9, t0), s0), r0), gpowgs(s0, 3)), q0)), gmul(t0, gpowgs(r0, 3))), gsqr(q3)), gmul(gadd(gmul(gadd(gmul(gsub(gmul(gmulsg(9, gsqr(t0)), q0), gmul(gmul(t0, s0), r0)), q1), gadd(gmul(gadd(gmul(gmul(gmulsg(-3, t0), s0), r1), gadd(gmul(gmul(gmulsg(3, t0), s1), r0), gmul(gmulsg(2, s1), gsqr(s0)))), q0), gsub(gmul(gmul(t0, gsqr(r0)), r1), gmul(gmul(s1, s0), gsqr(r0))))), q2), gadd(gadd(gadd(gmul(gneg(gsqr(t0)), gpowgs(q1, 3)), gmul(gadd(gmul(gmul(t0, s0), r1), gsub(gmul(gmul(gmulsg(2, t0), s1), r0), gmul(s1, gsqr(s0)))), gsqr(q1))), gmul(gadd(gmul(gadd(gmul(gmul(gmulsg(3, t0), s0), r2), gadd(gmul(gmul(gmulsg(-3, t0), s1), r1), gmul(gmulsg(2, gsqr(s1)), s0))), q0), gadd(gmul(gsub(gmul(gmulsg(2, t0), gsqr(r0)), gmul(gsqr(s0), r0)), r2), gsub(gadd(gmul(gmul(gneg(t0), r0), gsqr(r1)), gmul(gmul(gmul(s1, s0), r0), r1)), gmul(gsqr(s1), gsqr(r0))))), q1)), gadd(gmul(gsub(gmul(gmul(gmulsg(9, t0), s1), r2), gpowgs(s1, 3)), gsqr(q0)), gmul(gadd(gmul(gsub(gmul(gadd(gmul(gmulsg(-3, t0), r0), gsqr(s0)), r1), gmul(gmul(s1, s0), r0)), r2), gadd(gsub(gmul(t0, gpowgs(r1, 3)), gmul(gmul(s1, s0), gsqr(r1))), gmul(gmul(gsqr(s1), r0), r1))), q0)))), q3)), gadd(gadd(gadd(gmul(gmul(gneg(gsqr(t0)), q0), gpowgs(q2, 3)), gmul(gadd(gmul(gmul(gmul(gneg(t0), s1), r0), q1), gsub(gmul(gadd(gmul(gmul(gmulsg(2, t0), s0), r2), gsub(gmul(gmul(t0, s1), r1), gmul(gsqr(s1), s0))), q0), gmul(gmul(t0, gsqr(r0)), r2))), gsqr(q2))), gmul(gadd(gadd(gmul(gmul(gmul(gneg(t0), s0), r2), gsqr(q1)), gmul(gadd(gmul(gmul(gmul(gneg(t0), s1), r2), q0), gmul(gsub(gmul(gmul(t0, r0), r1), gmul(gmul(s1, s0), r0)), r2)), q1)), gmul(gadd(gmul(gsub(gmul(gmulsg(2, t0), r0), gsqr(s0)), gsqr(r2)), gmul(gsub(gadd(gmul(gneg(t0), gsqr(r1)), gmul(gmul(s1, s0), r1)), gmul(gsqr(s1), r0)), r2)), q0)), q2)), gsub(gadd(gmul(gmul(gmul(gneg(t0), r0), gsqr(r2)), gsqr(q1)), gmul(gmul(gmul(gsub(gmul(t0, r1), gmul(s1, s0)), gsqr(r2)), q0), q1)), gmul(gmul(t0, gpowgs(r2, 3)), gsqr(q0))))); return p1; } /* Input: coefficients of an equation */ /* t0*y^2+(s0*x^2+s1*x+s2)*y+(r0*x^4+r1*x^3+r2*x^2+r3*x+r4)=0 */ static GEN jac_quart(GEN t0, GEN s0, GEN s1, GEN s2, GEN r0, GEN r1, GEN r2, GEN r3, GEN r4) { GEN p1 = cgetg(6, t_VEC); gel(p1, 1) = gcopy(s1); gel(p1, 2) = gsub(gmul(gneg(t0), r2), gmul(s0, s2)); gel(p1, 3) = gsub(gmul(gmul(gneg(t0), s2), r1), gmul(gmul(t0, s0), r3)); gel(p1, 4) = gadd(gadd(gadd(gmul(gneg(gsub(gmul(gmulsg(4, gsqr(t0)), r4), gmul(t0, gsqr(s2)))), r0), gmul(gmul(gsqr(t0), r1), r3)), gmul(gmul(gmul(t0, s0), s2), r2)), gmul(gmul(t0, gsqr(s0)), r4)); gel(p1, 5) = gsub(gsub(gsub(gmul(gneg(gadd(gsub(gadd(gmul(gneg(gsub(gmul(gmulsg(4, gpowgs(t0, 3)), r4), gmul(gsqr(t0), gsqr(s2)))), r2), gmul(gpowgs(t0, 3), gsqr(r3))), gmul(gmul(gmul(gsqr(t0), s1), s2), r3)), gmul(gmul(gsqr(t0), gsqr(s1)), r4))), r0), gmul(gmul(gpowgs(t0, 3), gsqr(r1)), r4)), gmul(gsub(gmul(gmul(gmul(gsqr(t0), s0), s2), r3), gmul(gmul(gmul(gsqr(t0), s0), s1), r4)), r1)), gmul(gmul(gmul(gsqr(t0), gsqr(s0)), r2), r4)); return p1; } /* Input: coefficients of an equation */ /* (t0*x^2+t1*x+t2)*y^2+(r0*x^2+r1*x+r2)*y+(s0*x^2+s1*x+s2)=0 */ static GEN jac_biquadr(GEN t0, GEN t1, GEN t2, GEN r0, GEN r1, GEN r2, GEN s0, GEN s1, GEN s2) { GEN p1 = cgetg(6, t_VEC); gel(p1, 1) = gcopy(r1); gel(p1, 2) = gneg(gadd(gadd(gadd(gmul(s2, t0), gmul(t2, s0)), gmul(t1, s1)), gmul(r2, r0))); gel(p1, 3) = gadd(gmul(gmul(gneg(r2), s1), t0), gadd(gmul(gmul(gneg(t1), r2), s0), gsub(gmul(gmul(gneg(t2), r0), s1), gmul(gmul(t1, r0), s2)))); gel(p1, 4) = gadd(gmul(gadd(gmul(gadd(gmul(gmulsg(-4, t2), s2), gsqr(r2)), s0), gadd(gadd(gmul(t2, gsqr(s1)), gmul(gmul(t1, s2), s1)), gmul(gmul(r2, r0), s2))), t0), gadd(gmul(gadd(gmul(gmul(t2, t1), s1), gadd(gmul(gsqr(t1), s2), gmul(gmul(t2, r2), r0))), s0), gadd(gmul(gmul(gmul(t1, r2), r0), s1), gmul(gmul(t2, gsqr(r0)), s2)))); gel(p1, 5) = gadd(gadd(gmul(gsub(gmul(gsub(gmul(gmulsg(4, t2), gsqr(s2)), gmul(gsqr(r2), s2)), s0), gmul(gmul(t2, s2), gsqr(s1))), gsqr(t0)), gmul(gadd(gadd(gmul(gsub(gmul(gmulsg(4, gsqr(t2)), s2), gmul(t2, gsqr(r2))), gsqr(s0)), gmul(gadd(gadd(gmul(gneg(gsqr(t2)), gsqr(s1)), gmul(gsub(gmul(gmul(t2, r2), r1), gmul(t1, gsqr(r2))), s1)), gadd(gmul(gneg(gsqr(t1)), gsqr(s2)), gmul(gadd(gmul(gneg(t2), gsqr(r1)), gmul(gmul(t1, r2), r1)), s2))), s0)), gsub(gadd(gmul(gmul(gmul(gneg(t2), r2), r0), gsqr(s1)), gmul(gmul(gmul(gsub(gmul(t2, r1), gmul(t1, r2)), r0), s2), s1)), gmul(gmul(t2, gsqr(r0)), gsqr(s2)))), t0)), gsub(gadd(gmul(gmul(gmul(gneg(t2), gsqr(t1)), s2), gsqr(s0)), gmul(gadd(gmul(gmul(gmul(gmul(gneg(t2), t1), r2), r0), s1), gmul(gadd(gmul(gneg(gsqr(t2)), gsqr(r0)), gmul(gsub(gmul(gmul(t2, t1), r1), gmul(gsqr(t1), r2)), r0)), s2)), s0)), gmul(gmul(gmul(gmul(t2, t1), gsqr(r0)), s2), s1))); return p1; } INLINE long dg(GEN P, long v) { if (typ(P)!=t_POL || varn(P)!=v || !signe(P)) return -1; return degpol(P); } INLINE GEN co(GEN P, long i, long v) { if (typ(P)!=t_POL || varn(P)!=v) return i==0 ? P: gen_0; if (i>degpol(P)) return gen_0; return gel(P, i+2); } GEN ellfromeqn(GEN P) { pari_sp av = avma; long vx, vy, dx, dy, dm; GEN r = gen_0; if (typ(P)!=t_POL) pari_err_TYPE("ellfromeqn",P); vx = varn(P); vy = gvar2(P); if (vy==NO_VARIABLE) pari_err_TYPE("ellfromeqn",P); dx = poldegree(P, vx); dy = poldegree(P, vy); dm = maxss(dx, dy); if (dm == 2) { GEN p_0 = co(P, 0, vx), p_1 = co(P, 1, vx), p_2 = co(P, 2, vx); r = jac_biquadr(co(p_2, 2, vy), co(p_2, 1, vy), co(p_2, 0, vy), co(p_1, 2, vy), co(p_1, 1, vy), co(p_1, 0, vy), co(p_0, 2, vy), co(p_0, 1, vy), co(p_0, 0, vy)); } else if (dm == 3) { GEN p_0 = co(P, 0, vx), p_1 = co(P, 1, vx), p_2 = co(P, 2, vx), p_3 = co(P, 3, vx); if (dg(p_3, vy) > 0 || dg(p_2, vy) > 1 || dg(p_1, vy) > 2) r = gen_0; /* genus > 1 */ else r = jac_cubic( co(p_3, 0, vy), co(p_2, 1, vy), co(p_2, 0, vy), co(p_1, 2, vy), co(p_1, 1, vy), co(p_1, 0, vy), co(p_0, 3, vy), co(p_0, 2, vy), co(p_0, 1, vy), co(p_0, 0, vy)); } else if (dm == 4 && dx == 2) { GEN p_0 = co(P, 0, vx), p_1 = co(P, 1, vx), p_2 = co(P, 2, vx); if (dg(p_2, vy) > 0 || dg(p_1, vy) > 2) r = gen_0; /* genus > 1 */ else r = jac_quart( co(p_2, 0, vy), co(p_1, 2, vy), co(p_1, 1, vy), co(p_1, 0, vy), co(p_0, 4, vy), co(p_0, 3, vy), co(p_0, 2, vy), co(p_0, 1, vy), co(p_0, 0, vy)); } else if (dm == 4 && dx == 4) { GEN p_0 = co(P, 0, vx), p_1 = co(P, 1, vx), p_2 = co(P, 2, vx), p_3 = co(P, 3, vx), p_4 = co(P, 4, vx); if (dg(p_4, vy) > 0 || dg(p_3, vy) > 0 || dg(p_2, vy) > 1 || dg(p_1, vy) > 1 || dg(p_0, vy) > 2) r = gen_0; /* genus > 1 */ else r = jac_quart(co(p_0, 2, vy), co(p_2, 1, vy), co(p_1, 1, vy), co(p_0, 1, vy), co(p_4, 0, vy), co(p_3, 0, vy), co(p_2, 0, vy), co(p_1, 0, vy), co(p_0, 0, vy)); } if (r==gen_0) pari_err_DOMAIN("ellfromeqn", "genus", "!=", gen_1,P); return gerepileupto(av, r); } pari-2.11.2/src/modules/forperm.c0000644000175000017500000000353513326135265015247 0ustar billbill/* Copyright (C) 2017 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* for loop over permutations in lexicographic order * This implements the algorithm L in D. Knuth "The Art Of Computer Programming" * Fascicle 2b */ #include "pari.h" #include "paripriv.h" void forperm_init(forperm_t *T, GEN k) { switch (typ(k)) { case t_INT: if (signe(k) < 0) pari_err_DOMAIN("forperm", "a", "<", gen_0, k); T->v = identity_perm(itou(k)); break; case t_VEC: T->v = vec_to_vecsmall(k); break; case t_VECSMALL: T->v = vecsmall_copy(k); break; default: pari_err_TYPE("forperm", k); return; /* LCOV_EXCL_LINE */ } T->first = 1; T->k = lg(T->v) - 1; } GEN forperm_next(forperm_t *T) { long k = T->k, m1, m2, *p, *q; GEN v = T->v; if (T->first) { T->first = 0; return v; } m1 = k-1; while (m1 > 0 && v[m1] >= v[m1+1]) m1--; if (m1 <= 0) return NULL; m2 = k; while (v[m1] >= v[m2]) m2--; lswap(v[m1], v[m2]); p = v + m1 + 1; q = v + k; while (p < q) { lswap(*p, *q); p++; q--; } return v; } void forperm(void *E, long call(void *, GEN), GEN k) { pari_sp av = avma; forperm_t T; GEN v; forperm_init(&T, k); while ((v = forperm_next(&T))) if (call(E, v)) break; avma = av; } void forperm0(GEN k, GEN code) { push_lex(gen_0, code); forperm((void *)code, &gp_evalvoid, k); pop_lex(1); } pari-2.11.2/src/modules/galois.c0000644000175000017500000022061213326135265015050 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /**************************************************************/ /* Galois group for degree in [8, 11] */ /**************************************************************/ #define NMAX 11 /* maximum degree */ typedef GEN PERM; typedef PERM *GROUP; typedef struct { PERM *a; long nm, nv; } resolv; /* resolvent */ typedef struct { long pr, prmax, N; GEN p, r, coef; } buildroot; static long isin_G_H(buildroot *BR, long n1, long n2); static long *par_vec; /* k-1 entries filled so far * m = maximal allowed value, n = sum to reach with remaining elements */ static void do_par(GEN T, long k, long n, long m) { long i; if (n <= 0) { GEN t = cgetg(k, t_VECSMALL); for (i=1; i 7) { err_printf("Partitions of %ld (%ld)\n",n, p); for (i=1; i<=p; i++) err_printf("i = %ld: %Ps\n",i,gel(T,i)); } T[0] = evallg(p + 1) | evaltyp(t_VEC); return T; } /* affect to the permutation x the N arguments that follow */ static void _aff(long N, PERM x,...) { va_list args; long i; va_start(args,x); for (i=1; i<=N; i++) x[i] = va_arg(args,int); va_end(args); } /* return an array of length |len| from the arguments (for galoismodulo) */ static GEN _gr(long len,...) { va_list args; long i, l = labs(len); GEN x = new_chunk(l+1); va_start(args,len); x[0] = len; for (i=1; i<=l; i++) x[i] = va_arg(args,int); va_end(args); return x; } /* return a VECSMALL of length l from the arguments (for galoismodulo11) */ static GEN _typ(long l,...) { va_list args; long i; GEN x = cgetg(l+1, t_VECSMALL); va_start(args,l); for (i=1; i<=l; i++) x[i] = va_arg(args,int); va_end(args); return x; } /* create a permutation with the N arguments of the function */ static PERM _cr(long N, long a,...) { static long x[NMAX+1]; va_list args; long i; va_start(args, a); x[0] = N; x[1] = a; for (i=2; i<=N; i++) x[i] = va_arg(args,int); va_end(args); return x; } static PERM permmul(PERM s1, PERM s2) { long i, n1 = s1[0]; PERM s3 = (PERM)stack_malloc((n1+1) * sizeof(long)); for (i=1; i<=n1; i++) s3[i] = s1[s2[i]]; s3[0] = n1; return s3; } static void printperm(PERM perm) { long i, n = perm[0]; err_printf("("); for (i=1; i<=n; i++) err_printf(" %d",perm[i]); err_printf(" )\n"); } static int raye(long *g, long num) { long i, nb = labs(g[0]); for (i=1; i<=nb; i++) if (g[i] == num) return 0; return 1; } /* we can never determine the group completely in there */ static long rayergroup11(long EVEN, long num, long *gr) { long r = 0; if (EVEN) switch(num) { case 2: case 5: if (gr[3]) { gr[3]=0; r++; } case 3: case 6: case 7: if (gr[2]) { gr[2]=0; r++; } case 4: if (gr[1]) { gr[1]=0; r++; } } else switch(num) { case 2: case 3: if (gr[1]) { gr[1]=0; r++; } } return r; } static long rayergroup(long EVEN, long **GR, long num, long *gr) { long i,nbgr,r; if (!GR) return rayergroup11(EVEN,num,gr); nbgr = lg(GR); r = 0 ; if (EVEN) { for (i=1; i 0 && raye(GR[i],num)) { gr[i]=0; r++; } } return r; } static long galmodp(long EVEN, GEN pol, GEN dpol, GEN TYP, long *gr, long **GR) { long i,k,l,n,nbremain; GEN p1, dtyp; forprime_t T; switch(degpol(pol)) { case 8: nbremain = EVEN? 28: 22; break; case 9: nbremain = EVEN? 18: 16; break; case 10: nbremain = EVEN? 12: 33; break; default: nbremain = EVEN? 5: 3; break; /* case 11 */ } u_forprime_init(&T, 2, ULONG_MAX); dtyp = new_chunk(NMAX+1); k = gr[0]; for (i=1; ir; long i, l = lg(r), p = BR->pr; if (p > BR->prmax) pari_err_BUG("fixprex [precision too large]"); for (i = 1; i < l; i++) preci(gel(r,i), p); } static long getpreci(buildroot *BR) { GEN x = gmael(BR->r,1,1); return (typ(x)==t_COMPLEX)? realprec(gel(x,1)): realprec(x); } #define setcard_obj(x,n) ((x)[0] = (PERM)(n)) #define getcard_obj(x) ((long)((x)[0])) /* allocate a list of m arrays of length n (index 0 is codeword) */ static PERM * alloc_pobj(long n, long m) { long i; PERM *g = (PERM*) stack_malloc( (m+1)*sizeof(PERM) + (n+1)*m * sizeof(long) ); PERM gpt = (PERM) (g + (m+1)); for (i=1; i<=m; i++) { g[i] = gpt; gpt += (n+1); } setcard_obj(g, m); return g; } static GROUP allocgroup(long n, long card) { GROUP gr = alloc_pobj(n,card); long i; for (i=1; i<=card; i++) gr[i][0] = n; return gr; } static pariFILE * galopen(const char *pre, long n, long n1, long n2) { pari_sp av = avma; char *s = stack_malloc(strlen(pari_datadir) + 3 + 4 * 20 + 1 + 3); pariFILE *f; (void)sprintf(s, "%s/galdata/%s%ld_%ld_%ld", pari_datadir, pre, n, n1, n2); f = pari_fopengz(s); if (!f) pari_err_FILE("galois file",s); avma = av; return f; } static char bin(char c) { if (c>='0' && c<='9') c -= '0'; else if (c>='A' && c<='Z') c -= 'A'-10; else if (c>='a' && c<='z') c -= 'a'-36; else pari_err_TYPE("bin [not alphanumeric]", stoi(c)); return c; } #define BUFFS 512 /* fill in g[i][j] (i<=n, j<=m) with (buffered) data from f->file */ static void read_obj(PERM *g, pariFILE *f, long n, long m) { long i, j, k, N = m*n; char *ch = stack_malloc(N); pari_fread_chars(ch, N, f->file); for (k = 0, i = 1; i <= n; i++) for (j = 1; j <= m; j++,k++) g[i][j] = bin(ch[k]); pari_fclose(f); } #undef BUFFS /* the first 8 bytes contain size data (possibly padded with \0) */ static GROUP lirecoset(long n1, long n2, long n) { GROUP gr; char c, ch[8]; long m, cardgr; pariFILE *f = galopen("COS", n, n1, n2); pari_fread_chars(&c, 1, f->file); m=bin(c); pari_fread_chars(&c, 1, f->file); pari_fread_chars(ch, 6, f->file); cardgr=atol(ch); gr=allocgroup(m,cardgr); read_obj(gr, f,cardgr,m); return gr; } static void lireresolv(long n1, long n2, long n, resolv *R) { char ch[5]; long nm, nv; pariFILE *f = galopen("RES", n, n1, n2); pari_fread_chars(ch,5,f->file); nm = atol(ch); pari_fread_chars(ch,3,f->file); nv = atol(ch); R->a = alloc_pobj(nv,nm); read_obj(R->a, f,nm,nv); R->nm = nm; R->nv = nv; } static int cmp_re(GEN x, GEN y) { if (typ(x) != t_COMPLEX) return -1; if (typ(y) != t_COMPLEX) return 1; /* t_REALS are smallest */ return gcmp(gel(x,1), gel(y,1)); } /* multiply the r o bb. Sort first to detect pairs of conjugate */ static GEN Monomial(GEN r, PERM bb, long nbv) { GEN t, R = cgetg(nbv + 1, t_VEC); long i, s = 1; for (i = 1; i <= nbv; i++) { t = gel(r,bb[i]); if (typ(t) == t_COMPLEX && signe(gel(t,1)) < 0) { s = -s; t = gneg(t); } gel(R,i) = t; } if (nbv > 2) gen_sort_inplace(R, (void*)&cmp_re, cmp_nodata, NULL); else if (nbv == 2 && typ(gel(R,2)) != t_COMPLEX) swap(gel(R,1), gel(R,2)); t = NULL; for (i=1; i<=nbv; i++) { GEN c = gel(R,i); if (typ(c) == t_COMPLEX && i < nbv) { /* detect conjugates */ GEN n = gel(R,++i); if (!abscmprr(gel(n,1), gel(c,1)) && !abscmprr(gel(n,2), gel(c,2)) && signe(gel(c,2)) != signe(gel(n,2))) c = addrr(sqrr(gel(c,1)), sqrr(gel(c,2))); else c = gmul(c,n); } t = t? gmul(t, c): c; } if (s < 0) t = gneg(t); return t; } /* sum(i = 1, R->nm, Monomial(r, R->a[i], R->nv)). Sort real / imaginary part * separately by increasing absolute values, to increase stability */ static GEN gpolynomial(GEN r, resolv *R) { GEN RE = cgetg(R->nm+1, t_VEC), IM = cgetg(R->nm+1, t_VEC), re, im; long i, k; for (i = k = 1; i <= R->nm; i++) { GEN m = Monomial(r,R->a[i], R->nv); if (typ(m) == t_REAL) gel(RE, i) = m; else { gel(RE, i) = gel(m,1); gel(IM, k++) = gel(m,2); } } setlg(IM, k); gen_sort_inplace(RE, (void*)&abscmprr, cmp_nodata, NULL); gen_sort_inplace(IM, (void*)&abscmprr, cmp_nodata, NULL); re = gel(RE,1); for (i = 2; i <= R->nm; i++) re = addrr(re, gel(RE,i)); if (k == 1) return re; im = gel(IM,1); for (i = 2; i < k; i++) im = addrr(im, gel(IM,i)); return mkcomplex(re, im); } static void zaux1(GEN *z, GEN *r) { GEN p2,p1; p2=gsub(r[1], gadd(r[2],r[5])); p2=gmul(p2, gsub(r[2],r[5])); p1=gmul(p2,r[1]); p2=gsub(r[3],gadd(r[2],r[4])); p2=gmul(p2,gsub(r[4],r[2])); p1=gadd(p1,gmul(p2,r[3])); p2=gmul(r[5],gsub(r[4],r[5])); z[1]=gadd(p1,gmul(p2,r[4])); p2=gsub(r[1],gadd(r[3],r[4])); p2=gmul(p2,gsub(r[3],r[4])); p1=gmul(p2,r[1]); p2=gsub(r[5],gadd(r[3],r[2])); p2=gmul(p2,gsub(r[2],r[3])); p1=gadd(p1,gmul(p2,r[5])); p2=gmul(r[4],gsub(r[2],r[4])); z[2]=gadd(p1,gmul(p2,r[2])); } static void zaux(GEN *z, GEN *r) { zaux1(z, r); zaux1(z+2, r+5); } static GEN gpoly(GEN rr, long n1, long n2) { const long N = lg(rr)-1; GEN p1,p2,z[6], *r = (GEN*)rr; /* syntaxic kludge */ long i,j; if (N==8) { if (n1==47 && n2==46) { p1=gsub(r[3],r[4]); for (i=1; i<3; i++) for (j=i+1; j<5; j++) p1 = gmul(p1,gsub(r[i],r[j])); for (i=5; i<8; i++) for (j=i+1; j<9; j++) p1 = gmul(p1,gsub(r[i],r[j])); p2=r[1]; for (i=2; i<5; i++) p2=gadd(p2,r[i]); for (i=5; i<9; i++) p2=gsub(p2,r[i]); } else /* n1==44 && n2==40 */ { for (i=1; i<5; i++) z[i] = gadd(r[2*i-1],r[2*i]); p1 = gsub(r[1],r[2]); for (i=2; i<5; i++) p1 = gmul(p1,gsub(r[2*i-1],r[2*i])); p2=gsub(z[3],z[4]); for (i=1; i<3; i++) for (j=i+1; j<5; j++) p2 = gmul(p2,gsub(z[i],z[j])); } return gmul(p1,p2); } if (N==9) { if (n1==31 && n2==29) { p1=gsub(r[2],r[3]); for (j=2; j<4; j++) p1 = gmul(p1,gsub(r[1],r[j])); for (i=4; i<6; i++) for (j=i+1; j<7; j++) p1 = gmul(p1,gsub(r[i],r[j])); p2 = gsub(r[8],r[9]); for (j=8; j<10; j++) p2 = gmul(p2,gsub(r[7],r[j])); } else /* ((n1==34 && n2==31) || (n1=33 && n2==30)) */ { p1=r[1]; for (i=2; i<4; i++) p1=gadd(p1,r[i]); p2=r[4]; for (i=5; i<7; i++) p2=gadd(p2,r[i]); p1=gmul(p1,p2); p2=r[7]; for (i=8; i<10; i++) p2=gadd(p2,r[i]); } return gmul(p1,p2); } if (N==10) { if ((n1==45 && n2==43) || (n1==44 && n2==42)) { p1=r[1]; for (i=2; i<6; i++) p1=gadd(p1,r[i]); p2=r[6]; for (i=7; i<11; i++) p2=gadd(p2,r[i]); return gmul(p1,p2); } else if ((n1==45 && n2==39) || (n1==44 && n2==37)) { p1 = gadd(r[1],r[2]); for (i=2; i<6; i++) p1 = gmul(p1,gadd(r[2*i-1],r[2*i])); return p1; } else if ((n1==43 && n2==41) || (n1==33 && n2==27)) { p1=gsub(r[4],r[5]); for (i=1; i<4; i++) for (j=i+1; j<6; j++) p1=gmul(p1,gsub(r[i],r[j])); p2=gsub(r[9],r[10]); for (i=6; i<9; i++) for (j=i+1; j<11; j++) p2=gmul(p2,gsub(r[i],r[j])); return gmul(p1,p2); } else if ((n1==43 && n2==33) || (n1==42 && n2==28) || (n1==41 && n2==27) || (n1==40 && n2==21)) { p2=gadd(r[2],r[5]); p2=gsub(p2,gadd(r[3],r[4])); p1=gmul(p2,r[1]); p2=gsub(r[3],gadd(r[4],r[5])); p1=gadd(p1,gmul(p2,r[2])); p2=gsub(r[4],r[5]); p1=gadd(p1,gmul(p2,r[3])); z[1]=gadd(p1,gmul(r[4],r[5])); p2=gadd(r[7],r[10]); p2=gsub(p2,gadd(r[8],r[9])); p1=gmul(p2,r[6]); p2=gsub(r[8],gadd(r[9],r[10])); p1=gadd(p1,gmul(p2,r[7])); p2=gsub(r[9],r[10]); p1=gadd(p1,gmul(p2,r[8])); z[2]=gadd(p1,gmul(r[9],r[10])); return gadd(gsqr(z[1]), gsqr(z[2])); } else if (n1==41 && n2==40) { p1=gsub(r[4],r[5]); for (i=1; i<4; i++) for (j=i+1; j<6; j++) p1 = gmul(p1,gsub(r[i],r[j])); p2=gsub(r[9],r[10]); for (i=6; i<9; i++) for (j=i+1; j<11; j++) p2 = gmul(p2,gsub(r[i],r[j])); return gadd(p1,p2); } else if ((n1==41 && n2==22) || (n1==40 && n2==11) || (n1==17 && n2==5) || (n1==10 && n2==4) || (n1==9 && n2==3) || (n1==6 && n2==1)) { p1=gadd(r[1],r[6]); for (i=2; i<6; i++) p1=gmul(p1,gadd(r[i],r[i+5])); return p1; } else if ((n1==39 && n2==38) || (n1==29 && n2==25)) { for (i=1; i<6; i++) z[i]=gadd(r[2*i-1],r[2*i]); p1=gsub(r[1],r[2]); for (i=2; i<6; i++) p1=gmul(p1,gsub(r[2*i-1],r[2*i])); p2=gsub(z[4],z[5]); for (i=1; i<4; i++) for (j=i+1; j<6; j++) p2=gmul(p2,gsub(z[i],z[j])); return gmul(p1,p2); } else if ((n1==39 && n2==36) || (n1==37 && n2==34) || (n1==29 && n2==23) || (n1==24 && n2==15)) { for (i=1; i<6; i++) z[i]=gadd(r[2*i-1],r[2*i]); p1=gsub(z[4],z[5]); p2=gmul(gsub(z[3],z[4]),gsub(z[3],z[5])); for (i=1; i<3; i++) for (j=i+1; j<6; j++) p2=gmul(p2,gsub(z[i],z[j])); return gmul(p1,p2); } else if ((n1==39 && n2==29) || (n1==38 && n2==25) || (n1==37 && n2==24) || (n1==36 && n2==23) || (n1==34 && n2==15)) { for (i=1; i<6; i++) z[i]=gadd(r[2*i-1],r[2*i]); p2=gadd(z[2],z[5]); p2=gsub(p2,gadd(z[3],z[4])); p1=gmul(p2,z[1]); p2=gsub(z[3],gadd(z[4],z[5])); p1=gadd(p1,gmul(p2,z[2])); p2=gsub(z[4],z[5]); p1=gadd(p1,gmul(p2,z[3])); p1=gadd(p1,gmul(z[4],z[5])); return gsqr(p1); } else if ((n1==39 && n2==22) || (n1==38 && n2==12) || (n1==36 && n2==11) || (n1==29 && n2== 5) || (n1==25 && n2== 4) || (n1==23 && n2== 3) || (n1==16 && n2== 2) || (n1==14 && n2== 1)) { p1=r[1]; for (i=2; i<6; i++) p1=gadd(p1,r[2*i-1]); p2=r[2]; for (i=2; i<6; i++) p2=gadd(p2,r[2*i]); return gmul(p1,p2); } else if (n1==28 && n2==18) { zaux(z, r); p1=gmul(z[1],gsub(z[3],z[4])); p2=gmul(z[2],gadd(z[3],z[4])); return gadd(p1,p2); } else if (n1==27 && n2==20) { zaux(z, r); p1=gmul(z[1],z[3]); p2=gmul(z[2],z[4]); p1 = gsub(p1,p2); p2=r[1]; for (i=2; i<6 ; i++) p2=gadd(p2,r[i]); for ( ; i<11; i++) p2=gsub(p2,r[i]); return gmul(p1,p2); } else if (n1==27 && n2==19) { zaux(z, r); p1=gmul(z[1],z[3]); p2=gmul(z[2],z[4]); return gsub(p1,p2); } else if ((n1==27 && n2==17) || (n1==21 && n2==9)) { zaux(z, r); p1=gmul(z[1],z[3]); p2=gmul(z[2],z[4]); return gadd(p1,p2); } else if (n1==23 && n2==16) { for (i=1; i<6; i++) z[i]=gadd(r[2*i-1],r[2*i]); p1=gsub(z[1],gadd(z[2],z[5])); p1=gmul(p1,gsub(z[2],z[5])); p2=gmul(p1,z[1]); p1=gsub(z[3],gadd(z[2],z[4])); p1=gmul( p1,gsub(z[4],z[2])); p2=gadd(p2,gmul(p1,z[3])); p1=gmul(z[5],gsub(z[4],z[5])); p2=gadd(p2,gmul(p1,z[4])); p1=gsub(r[1],r[2]); for (i=2; i<6; i++) p1=gmul(p1,gsub(r[2*i-1],r[2*i])); return gmul(p1,p2); } else if (n1==22 && n2==12) { for (i=1; i<6; i++) z[i]=gadd(r[i],r[i+5]); p1=gsub(r[1],r[6]); for (i=2; i<6; i++) p1=gmul(p1,gsub(r[i],r[i+5])); p2=gsub(z[4],z[5]); for (i=1; i<4; i++) for (j=i+1; j<6; j++) p2=gmul(p2,gsub(z[i],z[j])); return gmul(p1,p2); } else if ((n1==22 && n2==11) || (n1==5 && n2==3)) { for (i=1; i<6; i++) z[i]=gadd(r[i],r[i+5]); p1=gsub(z[4],z[5]); p2=gmul(gsub(z[3],z[4]),gsub(z[3],z[5])); for (i=1; i<3; i++) for (j=i+1; j<6; j++) p2=gmul(p2,gsub(z[i],z[j])); return gmul(p1,p2); } else if ((n1==22 && n2==5) || (n1==12 && n2==4) || (n1==11 && n2==3)) { for (i=1; i<6; i++) z[i]=gadd(r[i],r[i+5]); p2=gadd(z[2],z[5]); p2=gsub(p2,gadd(z[3],z[4])); p1=gmul(p2,z[1]); p2=gsub(z[3],gadd(z[4],z[5])); p1=gadd(p1,gmul(p2,z[2])); p2=gsub(z[4],z[5]); p1=gadd(p1,gmul(p2,z[3])); p1=gadd(p1,gmul(z[4],z[5])); return gsqr(p1); } else if (n1==21 && n2==10) { zaux(z, r); p1=gmul(z[1],z[4]); p2=gmul(z[2],z[3]); return gsub(p1,p2); } } pari_err_TYPE("gpoly [undefined invariant polynomial]", mkvecsmall2(n1,n2)); return NULL; /* LCOV_EXCL_LINE */ } /* a is a t_VECSMALL representing a polynomial */ static GEN new_pol(long N, GEN r, GEN a) { long i, j, l = lg(a); GEN x, z, v = cgetg(N+1, t_VEC); for (i=1; i<=N; i++) { z = gel(r,i); x = gaddsg(a[2], z); for (j = 3; j < l; j++) x = gaddsg(a[j], gmul(z,x)); gel(v,i) = x; } return gclone(v); } /* BR->r[l], BR->coef[l] hold data related to Tschirnausen transform of * degree l - 1 */ static void tschirn(buildroot *BR) { long i, k, v = varn(BR->p), l = lg(BR->r); GEN a, h, r; if (l >= BR->N) pari_err_BUG("tschirn"); if (DEBUGLEVEL) err_printf("\n$$$$$ Tschirnhaus transformation of degree %ld: $$$$$\n",l-1); a = gel(BR->coef,l); /* fill with random polynomial of degree <= l-1 */ do { a[1]=0; for (i=2; i < l+2; i++) a[i] = random_bits(3) + 1; h = Flx_to_ZX(Flx_renormalize(a,l+2)); } while (degpol(h) <= 0 || !ZX_is_squarefree(h)); setvarn(h, v); k = 0; (void)ZXQ_charpoly_sqf(BR->p, h, &k, v); a[2] += k; r = gel(BR->r,1); preci(r, BR->prmax); /* max accuracy original roots */ vectrunc_append(BR->r, new_pol(BR->N, r, a)); fixprec(BR); /* restore accuracy */ } static GEN sortroots(GEN newr, GEN oldr) { long e, e0, i, j, k, l = lg(newr); GEN r = cgetg(l, t_VEC), z = cgetg(l, t_VEC), t = const_vecsmall(l-1, 1); k = 0; /* gcc -Wall */ for (i=1; ir; long i, l = lg(r); for (i = 1; i < l; i++) gunclone(gel(r,i)); setlg(r, 1); } /* increase the roots accuracy */ static void moreprec(buildroot *BR) { long d = BR->pr - BR->prmax; if (d > 0) { /* recompute roots */ pari_sp av = avma; long l = lg(BR->r); GEN ro; if (d < BIGDEFAULTPREC-2) d = BIGDEFAULTPREC-2; BR->prmax = maxss(BR->prmax+d, (long)(BR->prmax * 1.2)); if (DEBUGLEVEL) { err_printf("$$$$$ New prec = %ld\n",BR->prmax); err_flush(); } ro = sortroots(QX_complex_roots(BR->p,BR->prmax), gel(BR->r,1)); delete_roots(BR); vectrunc_append(BR->r, gclone(ro)); for (d = 2; d < l; d++) vectrunc_append(BR->r, new_pol(BR->N, ro, gel(BR->coef,d))); avma = av; } fixprec(BR); } /* determine "sufficient" extra bit-precision such that we may decide * (heuristic) whether z is an integer. */ static GEN get_ro(long N, GEN rr, PERM S1, PERM S2, resolv *R) { GEN r = cgetg(N+1, t_VEC); long i; for (i=1; i<=N; i++) r[i] = rr[ S1[S2[i] ] ]; return R->a? gpolynomial(r, R): gpoly(r,R->nm,R->nv); } /* typ(z) = t_REAL, return zi = t_INT approximation */ static long sufprec_r(GEN z) { long p = bit_prec(z); /* bit accuracy of fractional part large enough ? */ return ( p - expo(z) > maxss(3*32, (long)0.2*p) ); } /* typ(z) = t_REAL or t_COMPLEX, return zi = t_INT approximation */ static long sufprec(GEN z) { if (typ(z) == t_REAL) return sufprec_r(z); else return sufprec_r(gel(z,2)) && sufprec_r(gel(z,1)); } static GEN get_ro_perm(PERM S1, PERM S2, long d, resolv *R, buildroot *BR) { GEN ro, roi; long e; for (;;) { ro = get_ro(BR->N, gel(BR->r, d), S1,S2,R); roi = grndtoi(ro, &e); if (e < 0) { if (e < -64 || sufprec(ro)) break; e = 0; } BR->pr += nbits2extraprec(e + 10); moreprec(BR); } if (e > -10 || typ(roi) == t_COMPLEX) return NULL; /* compute with 128 more bits */ BR->pr += MEDDEFAULTPREC-2; moreprec(BR); ro = get_ro(BR->N, gel(BR->r, d), S1,S2,R); BR->pr -= MEDDEFAULTPREC-2; fixprec(BR); /* ro closer to roi (32 more bits) ? */ return (gexpo(gsub(ro, roi)) < e - 32) ? roi: NULL; } static void dbg_rac(long nri,long nbracint,long numi[],GEN racint[],long multi[]) { long k; err_printf("\t# rational integer roots = %ld:",nbracint-nri); for (k = nri+1; k <= nbracint; k++) err_printf(" %ld^%ld", numi[k], multi[k]); err_printf("\n"); for (k = nri+1; k <= nbracint; k++) err_printf("\t%2ld: %Ps\n", numi[k], racint[k]); err_flush(); } #define M 2521 /* return NULL if not included, the permutation of the roots otherwise */ static PERM check_isin(buildroot *BR, resolv *R, GROUP tau, GROUP ss) { long nogr, nocos, init, i, j, k, l, d; pari_sp av1 = avma, av2; long nbgr,nbcos,nbracint,nbrac,lastnbri,lastnbrm; static long numi[M],numj[M],lastnum[M],multi[M],norac[M],lastnor[M]; GEN racint[M], roint; if (getpreci(BR) != BR->pr) fixprec(BR); nbcos = getcard_obj(ss); nbgr = getcard_obj(tau); lastnbri = lastnbrm = -1; nbracint = nbrac = 0; /* gcc -Wall*/ for (nogr=1; nogr<=nbgr; nogr++) { PERM T = tau[nogr]; if (DEBUGLEVEL) err_printf(" ----> Group # %ld/%ld:\n",nogr,nbgr); init = 0; d = 1; for (;;) { if (!init) { av2 = avma; nbrac = nbracint = 0; for (nocos=1; nocos<=nbcos; nocos++, avma = av2) { roint = get_ro_perm(T, ss[nocos], d, R, BR); if (!roint) continue; nbrac++; if (nbrac >= M) { pari_warn(warner, "more than %ld rational integer roots\n", M); avma = av1; goto NEXT; } for (j=1; j<=nbracint; j++) if (equalii(roint,racint[j])) { multi[j]++; break; } if (j > nbracint) { nbracint = j; multi[j] = 1; numi[j] = nocos; racint[j] = gerepileuptoint(av2,roint); av2 = avma; } numj[nbrac] = nocos; norac[nbrac] = j; } if (DEBUGLEVEL) dbg_rac(0,nbracint,numi,racint,multi); for (i=1; i<=nbracint; i++) if (multi[i]==1) return permmul(T, ss[numi[i]]); init = 1; } else { nbrac = nbracint = 0; for (l=1; l<=lastnbri; l++, avma = av1) { long nri = nbracint; av2 = avma; for (k=1; k<=lastnbrm; k++) if (lastnor[k]==l) { nocos = lastnum[k]; roint = get_ro_perm(T, ss[nocos], d, R, BR); if (!roint) { avma = av2; continue; } nbrac++; for (j=nri+1; j<=nbracint; j++) if (equalii(roint,racint[j])) { multi[j]++; break; } if (j > nbracint) { nbracint = j; multi[j] = 1; numi[j] = nocos; racint[j] = gerepileuptoint(av2,roint); av2=avma; } numj[nbrac] = nocos; norac[nbrac] = j; } if (DEBUGLEVEL) dbg_rac(nri,nbracint,numi,racint,multi); for (i=nri+1; i<=nbracint; i++) if (multi[i]==1) return permmul(T, ss[numi[i]]); } } avma = av1; if (!nbracint) break; lastnbri = nbracint; lastnbrm = nbrac; for (j=1; j<=nbrac; j++) { lastnum[j] = numj[j]; lastnor[j] = norac[j]; } NEXT: if (DEBUGLEVEL) { err_printf(" all integer roots are double roots\n"); err_printf(" Working with polynomial #%ld:\n", d+1); } if (++d >= lg(BR->r)) tschirn(BR); } } return NULL; } #undef M /* DEGREE 8 */ static long galoisprim8(long EVEN, buildroot *BR) { long rep; rep=isin_G_H(BR,50,43); if (rep) return EVEN? 37: 43; if (!EVEN) return 50; rep=isin_G_H(BR,49,48); if (!rep) return 49; rep=isin_G_H(BR,48,36); if (!rep) return 48; rep=isin_G_H(BR,36,25); return rep? 25: 36; } static long galoisimpodd8(buildroot *BR, long nh) { long rep; if (nh!=47) goto IMPODD_8_6; rep=isin_G_H(BR,47,46); if (!rep) goto IMPODD_8_5; rep=isin_G_H(BR,46,28); if (rep) goto IMPODD_8_7; else return 46; IMPODD_8_5: rep=isin_G_H(BR,47,35); if (rep) goto IMPODD_8_9; else return 47; IMPODD_8_6: rep=isin_G_H(BR,44,40); if (rep) goto IMPODD_8_10; else goto IMPODD_8_11; IMPODD_8_7: rep=isin_G_H(BR,28,21); if (rep) return 21; else goto IMPODD_8_33; IMPODD_8_9: rep=isin_G_H(BR,35,31); if (rep) goto IMPODD_8_13; else goto IMPODD_8_14; IMPODD_8_10: rep=isin_G_H(BR,40,26); if (rep) goto IMPODD_8_15; else goto IMPODD_8_16; IMPODD_8_11: rep=isin_G_H(BR,44,38); if (rep) goto IMPODD_8_17; else goto IMPODD_8_18; IMPODD_8_12: rep=isin_G_H(BR,16,7); if (rep) goto IMPODD_8_19; else return 16; IMPODD_8_13: rep=isin_G_H(BR,31,21); return rep? 21: 31; IMPODD_8_14: rep=isin_G_H(BR,35,30); if (rep) goto IMPODD_8_34; else goto IMPODD_8_20; IMPODD_8_15: rep=isin_G_H(BR,26,16); if (rep) goto IMPODD_8_12; else goto IMPODD_8_21; IMPODD_8_16: rep=isin_G_H(BR,40,23); if (rep) goto IMPODD_8_22; else return 40; IMPODD_8_17: rep=isin_G_H(BR,38,31); if (rep) goto IMPODD_8_13; else return 38; IMPODD_8_18: rep=isin_G_H(BR,44,35); if (rep) goto IMPODD_8_9; else return 44; IMPODD_8_19: rep=isin_G_H(BR,7,1); return rep? 1: 7; IMPODD_8_20: rep=isin_G_H(BR,35,28); if (rep) goto IMPODD_8_7; else goto IMPODD_8_23; IMPODD_8_21: rep=isin_G_H(BR,26,17); if (rep) goto IMPODD_8_24; else goto IMPODD_8_25; IMPODD_8_22: rep=isin_G_H(BR,23,8); if (rep) goto IMPODD_8_26; else return 23; IMPODD_8_23: rep=isin_G_H(BR,35,27); if (rep) goto IMPODD_8_27; else goto IMPODD_8_28; IMPODD_8_24: rep=isin_G_H(BR,17,7); if (rep) goto IMPODD_8_19; else return 17; IMPODD_8_25: rep=isin_G_H(BR,26,15); if (rep) goto IMPODD_8_29; else return 26; IMPODD_8_26: rep=isin_G_H(BR,8,1); return rep? 1: 8; IMPODD_8_27: rep=isin_G_H(BR,27,16); if (rep) goto IMPODD_8_12; else return 27; IMPODD_8_28: rep=isin_G_H(BR,35,26); if (rep) goto IMPODD_8_15; else return 35; IMPODD_8_29: rep=isin_G_H(BR,15,7); if (rep) goto IMPODD_8_19; rep=isin_G_H(BR,15,6); if (!rep) goto IMPODD_8_32; rep=isin_G_H(BR,6,1); return rep? 1: 6; IMPODD_8_32: rep=isin_G_H(BR,15,8); if (rep) goto IMPODD_8_26; else return 15; IMPODD_8_33: rep=isin_G_H(BR,28,16); if (rep) goto IMPODD_8_12; else return 28; IMPODD_8_34: rep=isin_G_H(BR,30,21); return rep? 21: 30; } static long galoisimpeven8(buildroot *BR, long nh) { long rep; if (nh!=45) goto IMPEVEN_8_6; rep=isin_G_H(BR,45,42); if (!rep) goto IMPEVEN_8_5; rep=isin_G_H(BR,42,34); if (rep) goto IMPEVEN_8_7; else goto IMPEVEN_8_8; IMPEVEN_8_5: rep=isin_G_H(BR,45,41); if (rep) goto IMPEVEN_8_9; else return 45; IMPEVEN_8_6: rep=isin_G_H(BR,39,32); if (rep) goto IMPEVEN_8_10; else goto IMPEVEN_8_11; IMPEVEN_8_7: rep=isin_G_H(BR,34,18); if (rep) goto IMPEVEN_8_21; else goto IMPEVEN_8_45; IMPEVEN_8_8: rep=isin_G_H(BR,42,33); if (rep) goto IMPEVEN_8_14; else return 42; IMPEVEN_8_9: rep=isin_G_H(BR,41,34); if (rep) goto IMPEVEN_8_7; else goto IMPEVEN_8_15; IMPEVEN_8_10: rep=isin_G_H(BR,32,22); if (rep) goto IMPEVEN_8_16; else goto IMPEVEN_8_17; IMPEVEN_8_11: rep=isin_G_H(BR,39,29); if (rep) goto IMPEVEN_8_18; else goto IMPEVEN_8_19; IMPEVEN_8_12: rep=isin_G_H(BR,14,4); return rep? 4: 14; IMPEVEN_8_14: rep=isin_G_H(BR,33,18); if (rep) goto IMPEVEN_8_21; else goto IMPEVEN_8_22; IMPEVEN_8_15: rep=isin_G_H(BR,41,33); if (rep) goto IMPEVEN_8_14; else goto IMPEVEN_8_23; IMPEVEN_8_16: rep=isin_G_H(BR,22,11); if (rep) goto IMPEVEN_8_24; else goto IMPEVEN_8_25; IMPEVEN_8_17: rep=isin_G_H(BR,32,13); if (rep) goto IMPEVEN_8_26; else goto IMPEVEN_8_27; IMPEVEN_8_18: rep=isin_G_H(BR,29,22); if (rep) goto IMPEVEN_8_16; else goto IMPEVEN_8_28; IMPEVEN_8_19: rep=isin_G_H(BR,39,24); if (rep) goto IMPEVEN_8_29; else return 39; IMPEVEN_8_20: rep=isin_G_H(BR,9,4); if (rep) return 4; else goto IMPEVEN_8_30; IMPEVEN_8_21: rep=isin_G_H(BR,18,10); if (rep) goto IMPEVEN_8_31; else goto IMPEVEN_8_32; IMPEVEN_8_22: rep=isin_G_H(BR,33,13); if (rep) goto IMPEVEN_8_26; else return 33; IMPEVEN_8_23: rep=isin_G_H(BR,41,29); if (rep) goto IMPEVEN_8_18; else goto IMPEVEN_8_33; IMPEVEN_8_24: rep=isin_G_H(BR,11,5); if (rep) return 5; else goto IMPEVEN_8_34; IMPEVEN_8_25: rep=isin_G_H(BR,22,9); if (rep) goto IMPEVEN_8_20; else return 22; IMPEVEN_8_26: rep=isin_G_H(BR,13,3); return rep? 3: 13; IMPEVEN_8_27: rep=isin_G_H(BR,32,12); if (rep) goto IMPEVEN_8_35; else return 32; IMPEVEN_8_28: rep=isin_G_H(BR,29,20); if (rep) goto IMPEVEN_8_36; else goto IMPEVEN_8_37; IMPEVEN_8_29: rep=isin_G_H(BR,24,14); if (rep) goto IMPEVEN_8_12; else goto IMPEVEN_8_38; IMPEVEN_8_30: rep=isin_G_H(BR,9,3); if (rep) return 3; else goto IMPEVEN_8_39; IMPEVEN_8_31: rep=isin_G_H(BR,10,2); return rep? 2: 10; IMPEVEN_8_32: rep=isin_G_H(BR,18,9); if (rep) goto IMPEVEN_8_20; else return 18; IMPEVEN_8_33: rep=isin_G_H(BR,41,24); if (rep) goto IMPEVEN_8_29; else return 41; IMPEVEN_8_34: rep=isin_G_H(BR,11,4); if (rep) return 4; else goto IMPEVEN_8_44; IMPEVEN_8_35: rep=isin_G_H(BR,12,5); return rep? 5: 12; IMPEVEN_8_36: rep=isin_G_H(BR,20,10); if (rep) goto IMPEVEN_8_31; else return 20; IMPEVEN_8_37: rep=isin_G_H(BR,29,19); if (rep) goto IMPEVEN_8_40; else goto IMPEVEN_8_41; IMPEVEN_8_38: rep=isin_G_H(BR,24,13); if (rep) goto IMPEVEN_8_26; else goto IMPEVEN_8_42; IMPEVEN_8_39: rep=isin_G_H(BR,9,2); return rep? 2: 9; IMPEVEN_8_40: rep=isin_G_H(BR,19,10); if (rep) goto IMPEVEN_8_31; else goto IMPEVEN_8_43; IMPEVEN_8_41: rep=isin_G_H(BR,29,18); if (rep) goto IMPEVEN_8_21; else return 29; IMPEVEN_8_42: rep=isin_G_H(BR,24,9); if (rep) goto IMPEVEN_8_20; else return 24; IMPEVEN_8_43: rep=isin_G_H(BR,19,9); if (rep) goto IMPEVEN_8_20; else return 19; IMPEVEN_8_44: rep=isin_G_H(BR,11,2); return rep? 2: 11; IMPEVEN_8_45: rep=isin_G_H(BR,34,14); if (rep) goto IMPEVEN_8_12; else return 34; } static long closure8(long EVEN, buildroot *BR) { long rep; if (!EVEN) { rep=isin_G_H(BR,50,47); if (rep) return galoisimpodd8(BR,47); rep=isin_G_H(BR,50,44); if (rep) return galoisimpodd8(BR,44); } else { rep=isin_G_H(BR,49,45); if (rep) return galoisimpeven8(BR,45); rep=isin_G_H(BR,49,39); if (rep) return galoisimpeven8(BR,39); } return galoisprim8(EVEN, BR); } static GROUP initgroup(long n, long nbgr) { GROUP t = allocgroup(n,nbgr); PERM ID = t[1]; long i; for (i = 1; i <= n; i++) ID[i] = i; return t; } static PERM data8(long N, long n1, long n2, GROUP *t) { switch(n1) { case 7: if (n2!=1) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 6, 5, 8, 7); return (*t)[1]; case 9: if (n2!=4) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 4, 3, 5, 6, 8, 7); return (*t)[1]; case 10: if (n2!=2) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 6, 5, 8, 7); return (*t)[1]; case 11: switch(n2) { case 2: *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 5, 6, 3, 4, 8, 7); return _cr(N, 1, 3, 5, 8, 2, 4, 6, 7); case 4: *t=initgroup(N,1); return _cr(N, 1, 3, 7, 5, 2, 4, 8, 6); }break; case 14: if (n2!=4) break; *t=initgroup(N,1); return _cr(N, 1, 2, 4, 3, 5, 6, 8, 7); case 15: if (n2!=6 && n2!=8) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 6, 5, 8, 7); return (*t)[1]; case 16: if (n2!=7) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 18: switch(n2) { case 9: *t=initgroup(N,3); _aff(N, (*t)[2], 1, 5, 3, 7, 2, 6, 4, 8); _aff(N, (*t)[3], 1, 2, 3, 4, 6, 5, 8, 7); return (*t)[1]; case 10: *t=initgroup(N,3); _aff(N, (*t)[2], 1, 6, 3, 8, 2, 5, 4, 7); _aff(N, (*t)[3], 1, 5, 3, 7, 2, 6, 4, 8); return (*t)[1]; }break; case 19: if (n2!=9) break; *t=initgroup(N,1); return _cr(N, 1, 5, 3, 8, 2, 6, 4, 7); case 20: if (n2!=10) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 22: switch(n2) { case 9: *t=initgroup(N,6); _aff(N, (*t)[2], 1, 2, 7, 8, 3, 4, 6, 5); _aff(N, (*t)[3], 1, 2, 7, 8, 3, 4, 5, 6); _aff(N, (*t)[4], 1, 2, 5, 6, 3, 4, 8, 7); _aff(N, (*t)[5], 1, 2, 5, 6, 3, 4, 7, 8); _aff(N, (*t)[6], 1, 2, 3, 4, 5, 6, 8, 7); return _cr(N, 1, 3, 5, 7, 2, 4, 6, 8); case 11: *t=initgroup(N,6); _aff(N, (*t)[2], 1, 2, 5, 6, 7, 8, 4, 3); _aff(N, (*t)[3], 1, 2, 5, 6, 7, 8, 3, 4); _aff(N, (*t)[4], 1, 2, 3, 4, 7, 8, 6, 5); _aff(N, (*t)[5], 1, 2, 3, 4, 7, 8, 5, 6); _aff(N, (*t)[6], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; }break; case 23: if (n2!=8) break; *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 6, 5, 8, 7); case 26: if (n2!=15 && n2!=17) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 28: if (n2!=21) break; *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 7, 8, 5, 6); case 29: if (n2!=18 && n2!=19) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 30: if (n2!=21) break; *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 7, 8, 5, 6); case 31: if (n2!=21) break; *t=initgroup(N,3); _aff(N, (*t)[2], 1, 2, 3, 4, 7, 8, 5, 6); _aff(N, (*t)[3], 1, 2, 5, 6, 7, 8, 3, 4); return (*t)[1]; case 32: if (n2!=12 && n2!=13) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 33: switch(n2) { case 13: *t=initgroup(N,1); return _cr(N, 1, 5, 2, 6, 3, 7, 4, 8); case 18: *t=initgroup(N,1); return _cr(N, 1, 2, 5, 6, 3, 4, 7, 8); }break; case 34: switch(n2) { case 14: *t=initgroup(N,3); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 8, 6, 7); _aff(N, (*t)[3], 1, 2, 3, 4, 5, 7, 8, 6); return _cr(N, 1, 5, 2, 6, 3, 7, 4, 8); case 18: *t=initgroup(N,1); return _cr(N, 1, 2, 5, 6, 3, 4, 8, 7); }break; case 39: if (n2!=24) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 40: if (n2!=23) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 41: switch(n2) { case 24: *t=initgroup(N,1); return _cr(N, 1, 5, 2, 6, 3, 7, 4, 8); case 29: *t=initgroup(N,1); return _cr(N, 1, 2, 5, 6, 3, 4, 7, 8); }break; case 42: if (n2!=34) break; *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 5, 6, 8, 7); case 45: if (n2!=41 && n2!=42) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; case 46: if (n2!=28) break; *t=initgroup(N,1); return _cr(N, 1, 2, 5, 6, 3, 4, 7, 8); case 47: if (n2!=35) break; *t=initgroup(N,1); return _cr(N, 1, 2, 5, 6, 3, 4, 7, 8); case 49: if (n2!=48) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 7); return (*t)[1]; } *t=initgroup(N,1); return (*t)[1]; } static long galoismodulo8(long EVEN, GEN pol, GEN dpol) { long res, gr[51]; pari_sp av = avma; long **GR = (long**)cgeti(49); GEN TYP = partitions_galois(8); /* List of possible types in group j: GR[j][0] = #GR[j] if * the group is odd, - #GR[j] if even */ GR[ 1]= _gr( 4, 1,5,15,22); GR[ 2]= _gr( -3, 1,5,15); GR[ 3]= _gr( -2, 1,5); GR[ 4]= _gr( -3, 1,5,15); GR[ 5]= _gr( -3, 1,5,15); GR[ 6]= _gr( 5, 1,4,5,15,22); GR[ 7]= _gr( 5, 1,3,5,15,22); GR[ 8]= _gr( 5, 1,4,5,15,22); GR[ 9]= _gr( -4, 1,3,5,15); GR[10]= _gr( -4, 1,3,5,15); GR[11]= _gr( -4, 1,3,5,15); GR[12]= _gr( -5, 1,5,9,15,20); GR[13]= _gr( -4, 1,5,9,20); GR[14]= _gr( -4, 1,5,9,15); GR[15]= _gr( 6, 1,3,4,5,15,22); GR[16]= _gr( 5, 1,3,5,15,22); GR[17]= _gr( 7, 1,3,5,11,13,15,22); GR[18]= _gr( -4, 1,3,5,15); GR[19]= _gr( -5, 1,3,5,12,15); GR[20]= _gr( -4, 1,3,5,15); GR[21]= _gr( 5, 1,3,5,13,15); GR[22]= _gr( -4, 1,3,5,15); GR[23]= _gr( 7, 1,4,5,9,15,20,22); GR[24]= _gr( -6, 1,3,5,9,15,20); GR[25]= _gr( -3, 1,5,21); GR[26]= _gr( 8, 1,3,4,5,11,13,15,22); GR[27]= _gr( 8, 1,2,3,4,5,13,15,22); GR[28]= _gr( 7, 1,3,5,12,13,15,22); GR[29]= _gr( -5, 1,3,5,12,15); GR[30]= _gr( 7, 1,3,4,5,11,13,15); GR[31]= _gr( 7, 1,2,3,4,5,13,15); GR[32]= _gr( -6, 1,3,5,9,15,20); GR[33]= _gr( -6, 1,3,5,9,15,20); GR[34]= _gr( -5, 1,3,5,9,15); GR[35]= _gr( 10, 1,2,3,4,5,11,12,13,15,22); GR[36]= _gr( -5, 1,5,9,20,21); GR[37]= _gr( -5, 1,5,9,15,21); GR[38]= _gr( 11, 1,2,3,4,5,9,10,13,15,19,20); GR[39]= _gr( -7, 1,3,5,9,12,15,20); GR[40]= _gr( 10, 1,3,4,5,9,11,13,15,20,22); GR[41]= _gr( -7, 1,3,5,9,12,15,20); GR[42]= _gr( -8, 1,3,5,6,8,9,15,20); GR[43]= _gr( 8, 1,4,5,9,15,19,21,22); GR[44]= _gr( 14, 1,2,3,4,5,9,10,11,12,13,15,19,20,22); GR[45]= _gr( -9, 1,3,5,6,8,9,12,15,20); GR[46]= _gr( 10, 1,3,5,6,8,9,12,13,15,22); GR[47]= _gr( 16, 1,2,3,4,5,6,7,8,9,11,12,13,14,15,20,22); GR[48]= _gr( -8, 1,3,5,9,12,15,20,21); gr[0]=51; res = galmodp(EVEN,pol,dpol,TYP,gr,GR); avma=av; if (!res) return 0; return EVEN? 49: 50; } /* DEGREE 9 */ static long galoisprim9(long EVEN, buildroot *BR) { long rep; if (!EVEN) { rep=isin_G_H(BR,34,26); if (!rep) return 34; rep=isin_G_H(BR,26,19); if (!rep) return 26; rep=isin_G_H(BR,19,16); if (rep) return 16; rep=isin_G_H(BR,19,15); return rep? 15: 19; } rep=isin_G_H(BR,33,32); if (!rep) goto PRIM_9_7; rep=isin_G_H(BR,32,27); return rep? 27: 32; PRIM_9_7: rep=isin_G_H(BR,33,23); if (!rep) return 33; rep=isin_G_H(BR,23,14); if (!rep) return 23; rep=isin_G_H(BR,14,9); return rep? 9: 14; } static long galoisimpodd9(buildroot *BR) { long rep; rep=isin_G_H(BR,31,29); if (!rep) goto IMPODD_9_5; rep=isin_G_H(BR,29,20); if (!rep) return 29; IMPODD_9_3: rep=isin_G_H(BR,20,12); if (!rep) return 20; IMPODD_9_4: rep=isin_G_H(BR,12,4); return rep? 4: 12; IMPODD_9_5: rep=isin_G_H(BR,31,28); if (!rep) goto IMPODD_9_9; rep=isin_G_H(BR,28,22); if (!rep) return 28; IMPODD_9_7: rep=isin_G_H(BR,22,13); if (!rep) return 22; IMPODD_9_8: rep=isin_G_H(BR,13,4); return rep? 4: 13; IMPODD_9_9: rep=isin_G_H(BR,31,24); if (!rep) return 31; rep=isin_G_H(BR,24,22); if (rep) goto IMPODD_9_7; rep=isin_G_H(BR,24,20); if (rep) goto IMPODD_9_3; rep=isin_G_H(BR,24,18); if (!rep) return 24; rep=isin_G_H(BR,18,13); if (rep) goto IMPODD_9_8; rep=isin_G_H(BR,18,12); if (rep) goto IMPODD_9_4; rep=isin_G_H(BR,18,8); if (!rep) return 18; rep=isin_G_H(BR,8,4); return rep? 4: 8; } static long galoisimpeven9(buildroot *BR) { long rep; rep=isin_G_H(BR,30,25); if (!rep) goto IMPEVEN_9_7; rep=isin_G_H(BR,25,17); if (!rep) return 25; IMPEVEN_9_3: rep=isin_G_H(BR,17,7); if (!rep) goto IMPEVEN_9_5; IMPEVEN_9_4: rep=isin_G_H(BR,7,2); return rep? 2: 7; IMPEVEN_9_5: rep=isin_G_H(BR,17,6); if (!rep) return 17; IMPEVEN_9_6: rep=isin_G_H(BR,6,1); return rep? 1: 6; IMPEVEN_9_7: rep=isin_G_H(BR,30,21); if (!rep) return 30; rep=isin_G_H(BR,21,17); if (rep) goto IMPEVEN_9_3; rep=isin_G_H(BR,21,11); if (!rep) goto IMPEVEN_9_13; rep=isin_G_H(BR,11,7); if (rep) goto IMPEVEN_9_4; rep=isin_G_H(BR,11,5); if (!rep) return 11; rep=isin_G_H(BR,5,2); return rep? 2: 5; IMPEVEN_9_13: rep=isin_G_H(BR,21,10); if (!rep) return 21; rep=isin_G_H(BR,10,6); if (rep) goto IMPEVEN_9_6; rep=isin_G_H(BR,10,3); if (!rep) return 10; rep=isin_G_H(BR,3,1); return rep? 1: 3; } static long closure9(long EVEN, buildroot *BR) { long rep; if (!EVEN) { rep=isin_G_H(BR,34,31); if (rep) return galoisimpodd9(BR); } else { rep=isin_G_H(BR,33,30); if (rep) return galoisimpeven9(BR); } return galoisprim9(EVEN, BR); } static PERM data9(long N, long n1, long n2, GROUP *t) { switch(n1) { case 6: if (n2!=1) break; *t=initgroup(N,3); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 9, 7); _aff(N, (*t)[3], 1, 2, 3, 4, 5, 6, 9, 7, 8); return (*t)[1]; case 7: if (n2!=2) break; *t=initgroup(N,3); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 9, 7); _aff(N, (*t)[3], 1, 2, 3, 4, 5, 6, 9, 7, 8); return (*t)[1]; case 8: if (n2!=4) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 4, 7, 2, 5, 8, 3, 6, 9); return (*t)[1]; case 12: if (n2!=4) break; *t=initgroup(N,3); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 9, 7); _aff(N, (*t)[3], 1, 2, 3, 4, 5, 6, 9, 7, 8); return (*t)[1]; case 13: if (n2!=4) break; *t=initgroup(N,1); return _cr(N, 1, 4, 7, 2, 5, 8, 3, 6, 9); case 14: if (n2!=9) break; *t=initgroup(N,3); _aff(N, (*t)[2], 1, 2, 3, 5, 6, 4, 9, 7, 8); _aff(N, (*t)[3], 1, 2, 3, 6, 4, 5, 8, 9, 7); return (*t)[1]; case 17: if (n2!=6) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 7, 8, 9, 4, 5, 6); return (*t)[1]; case 21: if (n2!=10) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 7, 8, 9, 4, 5, 6); return (*t)[1]; case 33: if (n2!=32) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 7, 9, 8); return (*t)[1]; } *t=initgroup(N,1); return (*t)[1]; } static long galoismodulo9(long EVEN, GEN pol, GEN dpol) { long res, gr[35]; pari_sp av = avma; long **GR = (long**) cgeti(33); GEN TYP = partitions_galois(9); /* 42 TYPES ORDONNES CROISSANT (T[1],...,T[30])*/ GR[ 1]= _gr( -3, 1,12,30); GR[ 2]= _gr( -2, 1,12); GR[ 3]= _gr( -4, 1,5,12,30); GR[ 4]= _gr( 4, 1,4,12,26); GR[ 5]= _gr( -3, 1,5,12); GR[ 6]= _gr( -4, 1,10,12,30); GR[ 7]= _gr( -3, 1,10,12); GR[ 8]= _gr( 5, 1,4,5,12,26); GR[ 9]= _gr( -4, 1,5,12,18); GR[10]= _gr( -6, 1,5,10,12,25,30); GR[11]= _gr( -5, 1,5,10,12,25); GR[12]= _gr( 5, 1,4,10,12,26); GR[13]= _gr( 5, 1,4,10,12,26); GR[14]= _gr( -4, 1,5,12,18); GR[15]= _gr( 5, 1,5,12,18,29); GR[16]= _gr( 6, 1,4,5,12,18,26); GR[17]= _gr( -5, 1,6,10,12,30); GR[18]= _gr( 7, 1,4,5,10,12,25,26); GR[19]= _gr( 7, 1,4,5,12,18,26,29); GR[20]= _gr( 9, 1,4,6,9,10,12,24,26,30); GR[21]= _gr( -7, 1,5,6,10,12,25,30); GR[22]= _gr( 7, 1,4,6,10,12,26,30); GR[23]= _gr( -6, 1,5,10,12,18,25); GR[24]= _gr( 11, 1,4,5,6,9,10,12,24,25,26,30); GR[25]= _gr( -7, 1,3,6,8,10,12,30); GR[26]= _gr( 9, 1,4,5,10,12,18,25,26,29); GR[27]= _gr( -5, 1,5,12,27,30); GR[28]= _gr( 12, 1,2,3,4,6,7,8,10,11,12,26,30); GR[29]= _gr( 12, 1,3,4,6,8,9,10,12,15,24,26,30); GR[30]= _gr(-11, 1,3,5,6,8,10,12,14,17,25,30); GR[31]= _gr( 19, 1,2,3,4,5,6,7,8,9,10,11,12,14,15,17,24,25,26,30); GR[32]= _gr( -7, 1,5,10,12,25,27,30); gr[0]=35; res = galmodp(EVEN,pol,dpol,TYP,gr,GR); avma=av; if (!res) return 0; return EVEN? 33: 34; } /* DEGREE 10 */ static long galoisprim10(long EVEN, buildroot *BR) { long rep; if (EVEN) { rep=isin_G_H(BR,44,31); if (!rep) return 44; rep=isin_G_H(BR,31,26); if (!rep) return 31; rep=isin_G_H(BR,26,7); return rep? 7: 26; } else { rep=isin_G_H(BR,45,35); if (!rep) return 45; rep=isin_G_H(BR,35,32); if (!rep) goto PRIM_10_7; rep=isin_G_H(BR,32,13); return rep? 13: 32; PRIM_10_7: rep=isin_G_H(BR,35,30); return rep? 30: 35; } } static long galoisimpeven10(buildroot *BR, long nogr) { long rep; if (nogr==42) { rep=isin_G_H(BR,42,28); if (!rep) return 42; rep=isin_G_H(BR,28,18); return rep? 18: 28; } else { rep=isin_G_H(BR,37,34); if (!rep) goto IMPEVEN_10_5; rep=isin_G_H(BR,34,15); if (rep) goto IMPEVEN_10_7; else return 34; IMPEVEN_10_5: rep=isin_G_H(BR,37,24); if (!rep) return 37; rep=isin_G_H(BR,24,15); if (!rep) return 24; IMPEVEN_10_7: rep=isin_G_H(BR,15,8); return rep? 8: 15; } } static long galoisimpodd10(buildroot *BR, long nogr) { long rep; if (nogr==43) { rep=isin_G_H(BR,43,41); if (!rep) goto IMPODD_10_3; rep=isin_G_H(BR,41,40); if (rep) goto IMPODD_10_4; else goto IMPODD_10_5; IMPODD_10_3: rep=isin_G_H(BR,43,33); if (rep) goto IMPODD_10_6; else return 43; IMPODD_10_4: rep=isin_G_H(BR,40,21); if (rep) goto IMPODD_10_7; else goto IMPODD_10_8; IMPODD_10_5: rep=isin_G_H(BR,41,27); if (rep) goto IMPODD_10_9; else goto IMPODD_10_10; IMPODD_10_6: rep=isin_G_H(BR,33,27); if (rep) goto IMPODD_10_9; else return 33; IMPODD_10_7: rep=isin_G_H(BR,21,10); if (rep) goto IMPODD_10_12; else goto IMPODD_10_13; IMPODD_10_8: rep=isin_G_H(BR,40,12); if (rep) goto IMPODD_10_14; else goto IMPODD_10_15; IMPODD_10_9: rep=isin_G_H(BR,27,21); if (rep) goto IMPODD_10_7; else goto IMPODD_10_16; IMPODD_10_10: rep=isin_G_H(BR,41,22); if (!rep) return 41; rep=isin_G_H(BR,22,12); if (rep) goto IMPODD_10_14; else goto IMPODD_10_18; IMPODD_10_12: rep=isin_G_H(BR,10,4); return rep? 4: 10; IMPODD_10_13: rep=isin_G_H(BR,21,9); if (rep) goto IMPODD_10_19; else return 21; IMPODD_10_14: rep=isin_G_H(BR,12,4); return rep? 4: 12; IMPODD_10_15: rep=isin_G_H(BR,40,11); if (rep) goto IMPODD_10_20; else return 40; IMPODD_10_16: rep=isin_G_H(BR,27,20); if (!rep) goto IMPODD_10_21; rep=isin_G_H(BR,20,10); if (rep) goto IMPODD_10_12; return 20; IMPODD_10_18: rep=isin_G_H(BR,22,11); if (rep) goto IMPODD_10_20; else goto IMPODD_10_23; IMPODD_10_19: rep=isin_G_H(BR,9,6); if (rep) goto IMPODD_10_24; else goto IMPODD_10_25; IMPODD_10_20: rep=isin_G_H(BR,11,3); if (rep) goto IMPODD_10_26; else return 11; IMPODD_10_21: rep=isin_G_H(BR,27,19); if (rep) goto IMPODD_10_27; rep=isin_G_H(BR,27,17); if (rep) goto IMPODD_10_28; else return 27; IMPODD_10_23: rep=isin_G_H(BR,22,5); if (rep) goto IMPODD_10_29; else return 22; IMPODD_10_24: rep=isin_G_H(BR,6,2); if (rep) return 2; else goto IMPODD_10_30; IMPODD_10_25: rep=isin_G_H(BR,9,3); if (!rep) return 9; IMPODD_10_26: rep=isin_G_H(BR,3,2); if (rep) return 2; else goto IMPODD_10_31; IMPODD_10_27: rep=isin_G_H(BR,19,9); if (rep) goto IMPODD_10_19; else return 19; IMPODD_10_28: rep=isin_G_H(BR,17,10); if (rep) goto IMPODD_10_12; else goto IMPODD_10_32; IMPODD_10_29: rep=isin_G_H(BR,5,4); if (rep) return 4; else goto IMPODD_10_33; IMPODD_10_30: rep=isin_G_H(BR,6,1); return rep? 1: 6; IMPODD_10_31: rep=isin_G_H(BR,3,1); return rep? 1: 3; IMPODD_10_32: rep=isin_G_H(BR,17,9); if (rep) goto IMPODD_10_19; else goto IMPODD_10_60; IMPODD_10_33: rep=isin_G_H(BR,5,3); if (rep) goto IMPODD_10_26; else return 5; IMPODD_10_60: rep=isin_G_H(BR,17,5); if (rep) goto IMPODD_10_29; else return 17; } else { rep=isin_G_H(BR,39,38); if (!rep) goto IMPODD_10_36; rep=isin_G_H(BR,38,25); if (rep) goto IMPODD_10_37; else goto IMPODD_10_38; IMPODD_10_36: rep=isin_G_H(BR,39,36); if (rep) goto IMPODD_10_39; else goto IMPODD_10_40; IMPODD_10_37: rep=isin_G_H(BR,25,4); return rep? 4: 25; IMPODD_10_38: rep=isin_G_H(BR,38,12); if (rep) goto IMPODD_10_41; else return 38; IMPODD_10_39: rep=isin_G_H(BR,36,23); if (rep) goto IMPODD_10_42; else goto IMPODD_10_43; IMPODD_10_40: rep=isin_G_H(BR,39,29); if (rep) goto IMPODD_10_44; else goto IMPODD_10_45; IMPODD_10_41: rep=isin_G_H(BR,12,4); return rep? 4: 12; IMPODD_10_42: rep=isin_G_H(BR,23,16); if (rep) goto IMPODD_10_46; else goto IMPODD_10_47; IMPODD_10_43: rep=isin_G_H(BR,36,11); if (rep) goto IMPODD_10_48; else return 36; IMPODD_10_44: rep=isin_G_H(BR,29,25); if (rep) goto IMPODD_10_37; else goto IMPODD_10_49; IMPODD_10_45: rep=isin_G_H(BR,39,22); if (rep) goto IMPODD_10_50; else return 39; IMPODD_10_46: rep=isin_G_H(BR,16,2); return rep? 2: 16; IMPODD_10_47: rep=isin_G_H(BR,23,14); if (rep) goto IMPODD_10_51; else goto IMPODD_10_52; IMPODD_10_48: rep=isin_G_H(BR,11,3); if (rep) goto IMPODD_10_53; else return 11; IMPODD_10_49: rep=isin_G_H(BR,29,23); if (rep) goto IMPODD_10_42; else goto IMPODD_10_54; IMPODD_10_50: rep=isin_G_H(BR,22,12); if (rep) goto IMPODD_10_41; else goto IMPODD_10_55; IMPODD_10_51: rep=isin_G_H(BR,14,1); return rep? 1: 14; IMPODD_10_52: rep=isin_G_H(BR,23,3); if (!rep) return 23; IMPODD_10_53: rep=isin_G_H(BR,3,2); if (rep) return 2; else goto IMPODD_10_57; IMPODD_10_54: rep=isin_G_H(BR,29,5); if (rep) goto IMPODD_10_58; else return 29; IMPODD_10_55: rep=isin_G_H(BR,22,11); if (rep) goto IMPODD_10_48; rep=isin_G_H(BR,22,5); if (rep) goto IMPODD_10_58; else return 22; IMPODD_10_57: rep=isin_G_H(BR,3,1); return rep? 1: 3; IMPODD_10_58: rep=isin_G_H(BR,5,4); if (rep) return 4; rep=isin_G_H(BR,5,3); if (rep) goto IMPODD_10_53; else return 5; } } static long closure10(long EVEN, buildroot *BR) { long rep; if (EVEN) { rep=isin_G_H(BR,44,42); if (rep) return galoisimpeven10(BR,42); rep=isin_G_H(BR,44,37); if (rep) return galoisimpeven10(BR,37); } else { rep=isin_G_H(BR,45,43); if (rep) return galoisimpodd10(BR,43); rep=isin_G_H(BR,45,39); if (rep) return galoisimpodd10(BR,39); } return galoisprim10(EVEN, BR); } static PERM data10(long N, long n1,long n2,GROUP *t) { switch(n1) { case 6: if (n2!=2) break; *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 5, 6, 10, 9, 8, 7); case 9: if (n2!=3 && n2!=6) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 10, 9, 8, 7); return (*t)[1]; case 10: *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 10, 9, 8, 7); return (*t)[1]; case 14: case 16:*t=initgroup(N,1); return _cr(N, 1, 3, 5, 7, 9, 2, 4, 6, 8, 10); case 17: if (n2!=5) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 10, 9, 8, 7); return (*t)[1]; case 19: case 20: *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 10, 7, 9); return (*t)[1]; case 21: if (n2!=10) break; *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 5, 6, 8, 10, 7, 9); case 23: if (n2!=3) break; *t=initgroup(N,1); return _cr(N, 1, 3, 5, 7, 9, 2, 4, 6, 8, 10); case 25: *t=initgroup(N,1); return _cr(N, 1, 3, 5, 7, 9, 2, 4, 6, 8, 10); case 26: *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 4, 9, 6, 8, 10, 3, 7, 5); return _cr(N, 1, 2, 3, 10, 6, 5, 7, 4, 8, 9); case 27: if (n2!=17 && n2!=21) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 10, 7, 9); return (*t)[1]; case 28: *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 8, 10, 7, 9); return (*t)[1]; case 29: if (n2!=5) break; *t=initgroup(N,1); return _cr(N, 1, 3, 5, 7, 9, 2, 4, 6, 8, 10); case 32: *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 4, 9, 6, 8, 10, 3, 7, 5); return _cr(N, 1, 2, 3, 10, 6, 5, 7, 4, 8, 9); case 36: if (n2!=11) break; *t=initgroup(N,1); return _cr(N, 1, 3, 5, 7, 9, 2, 4, 6, 8, 10); case 38: if (n2!=12) break; *t=initgroup(N,1); return _cr(N, 1, 3, 5, 7, 9, 2, 4, 6, 8, 10); case 39: if (n2!=22) break; *t=initgroup(N,1); return _cr(N, 1, 3, 5, 7, 9, 2, 4, 6, 8, 10); case 40: if (n2!=12) break; *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 5, 6, 7, 8, 10, 9); case 41: if (n2!=22 && n2!=40) break; *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 7, 8, 10, 9); return (*t)[1]; } *t=initgroup(N,1); return (*t)[1]; } static long galoismodulo10(long EVEN, GEN pol, GEN dpol) { long res, gr[46]; pari_sp av = avma; long **GR = (long**) cgeti(45); GEN TYP = partitions_galois(10); GR[ 1]= _gr( 4, 1,6,30,42); GR[ 2]= _gr( 3, 1,6,30); GR[ 3]= _gr( 5, 1,5,6,30,42); GR[ 4]= _gr( 4, 1,5,23,30); GR[ 5]= _gr( 7, 1,5,6,22,23,30,42); GR[ 6]= _gr( 5, 1,6,24,30,42); GR[ 7]= _gr( -4, 1,5,14,30); GR[ 8]= _gr( -4, 1,3,5,30); GR[ 9]= _gr( 6, 1,5,6,24,30,42); GR[10]= _gr( 5, 1,5,23,24,30); GR[11]= _gr( 7, 1,5,6,11,30,33,42); GR[12]= _gr( 7, 1,5,6,11,23,30,33); GR[13]= _gr( 7, 1,4,5,14,23,30,34); GR[14]= _gr( 8, 1,2,3,4,5,6,30,42); GR[15]= _gr( -6, 1,3,5,18,22,30); GR[16]= _gr( 7, 1,3,5,6,17,23,30); GR[17]= _gr( 8, 1,5,6,22,23,24,30,42); GR[18]= _gr( -6, 1,5,22,24,30,40); GR[19]= _gr( 7, 1,5,6,22,24,30,42); GR[20]= _gr( 6, 1,5,22,23,24,30); GR[21]= _gr( 9, 1,3,5,6,23,24,26,30,42); GR[22]= _gr( 11, 1,3,5,6,11,13,22,23,30,33,42); GR[23]= _gr( 12, 1,2,3,4,5,6,17,18,22,23,30,42); GR[24]= _gr( -7, 1,3,5,18,22,30,40); GR[25]= _gr( 8, 1,3,5,18,22,23,30,39); GR[26]= _gr( -5, 1,5,14,22,30); GR[27]= _gr( 10, 1,3,5,6,22,23,24,26,30,42); GR[28]= _gr( -8, 1,3,5,22,24,26,30,40); GR[29]= _gr( 14, 1,2,3,4,5,6,17,18,22,23,30,39,40,42); GR[30]= _gr( 8, 1,5,6,14,22,30,39,42); GR[31]= _gr( -6, 1,5,14,22,30,40); GR[32]= _gr( 8, 1,4,5,14,22,23,30,34); GR[33]= _gr( 14, 1,3,5,6,15,17,22,23,24,26,29,30,40,42); GR[34]= _gr( -9, 1,3,5,11,13,18,22,30,32); GR[35]= _gr( 12, 1,4,5,6,14,22,23,30,34,39,40,42); GR[36]= _gr( 18, 1,2,3,4,5,6,11,12,13,17,18,22,23,30,31,32,33,42); GR[37]= _gr(-12, 1,3,5,11,13,16,18,22,30,32,35,40); GR[38]= _gr( 18, 1,3,4,5,6,11,13,15,17,18,21,22,23,30,32,33,35,39); GR[39]= _gr( 24, 1,2,3,4,5,6,11,12,13,15,16,17,18,21,22,23,30,31,32,33,35,39,40,42); GR[40]= _gr( 14, 1,3,5,6,7,9,11,23,24,26,27,30,33,42); GR[41]= _gr( 18, 1,3,5,6,7,9,11,13,16,20,22,23,24,26,27,30,33,42); GR[42]= _gr(-17, 1,3,5,7,9,11,13,16,18,20,22,24,26,27,30,35,40); GR[43]= _gr( 32, 1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,33,35,40,42); GR[44]= _gr(-22, 1,3,5,7,9,11,13,14,16,18,20,22,24,26,27,30,32,35,36,38,40,41); gr[0]=46; res = galmodp(EVEN,pol,dpol,TYP,gr,GR); avma=av; if (!res) return 0; return EVEN? 44: 45; } /* DEGREE 11 */ static long closure11(long EVEN, buildroot *BR) { long rep; if (EVEN) { rep=isin_G_H(BR,7,6); if (!rep) return 7; rep=isin_G_H(BR,6,5); if (!rep) return 6; rep=isin_G_H(BR,5,3); if (!rep) return 5; rep=isin_G_H(BR,3,1); return rep? 1: 3; } else { GEN h = BR->p, r = compositum(h, h); r = gel(r,lg(r)-1); if (degpol(r) == 22) return 2; /* D11 */ h = leafcopy(h); setvarn(h, fetch_var()); setvarn(r, 0); r = nffactor(h, r); /* S11 (P10*P10*P90) or F_110[11] (11 factors of degree 10) */ (void)delete_var(); return (lgcols(r)-1 == 11)? 4: 8; } } static PERM data11(long N, long n1, GROUP *t) { switch(n1) { case 5: *t=initgroup(N,1); return _cr(N, 1, 2, 3, 7, 8, 6, 11, 5, 9, 4, 10); case 6: *t=initgroup(N,1); return _cr(N, 1, 2, 3, 4, 6, 10, 11, 9, 7, 5, 8); case 7: *t=initgroup(N,2); _aff(N, (*t)[2], 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 10); return (*t)[1]; } *t=initgroup(N,1); return (*t)[1]; } static long galoismodulo11(long EVEN, GEN pol, GEN dpol) { long res, gr[6] = {0, 1, 1, 1, 1, 1}; pari_sp av = avma; GEN TYP = cgetg(EVEN? 9: 6, t_VEC); gel(TYP,1) = _typ(1, 11); if (EVEN) { gel(TYP,2) = _typ(3, 8,2,1); gel(TYP,3) = _typ(3, 6,3,2); gel(TYP,4) = _typ(3, 5,5,1); gel(TYP,5) = _typ(5, 4,4,1,1,1); gel(TYP,6) = _typ(5, 3,3,3,1,1); gel(TYP,7) = _typ(7, 2,2,2,2,1,1,1); gel(TYP,8) = _typ(11, 1,1,1,1,1,1,1,1,1,1,1); } else { gel(TYP,2) = _typ(2, 10,1); gel(TYP,3) = _typ(3, 5,5,1); gel(TYP,4) = _typ(6, 2,2,2,2,2,1); gel(TYP,5) = _typ(11, 1,1,1,1,1,1,1,1,1,1,1); } res = galmodp(EVEN,pol,dpol,TYP,gr,NULL); avma=av; if (!res) return 0; return EVEN? 7: 8; } static void init_isin(long N, long n1, long n2, GROUP *tau, PERM *s0, resolv *R) { int fl = 1; if (DEBUGLEVEL) { err_printf("\n*** Entering isin_%ld_G_H_(%ld,%ld)\n",N,n1,n2); err_flush(); } switch(N) { case 8: if ((n1==47 && n2==46) || (n1==44 && n2==40)) fl=0; *s0=data8(N, n1,n2,tau); break; case 9: if ((n1==31 && n2==29) || (n1==34 && n2==31) || (n1==33 && n2==30)) fl=0; *s0=data9(N,n1,n2,tau); break; case 10: if ((n1==45 && (n2==43||n2==39)) || (n1==44 && (n2==42||n2==37)) || (n1==43 && (n2==41||n2==33)) || (n1==42 && n2==28) || (n1==41 && (n2==40||n2==27||n2==22)) || (n1==40 && (n2==21||n2==11)) || (n1==39 && (n2==38||n2==36||n2==29||n2==22)) || (n1==38 && (n2==25||n2==12)) || (n1==37 && (n2==34||n2==24)) || (n1==36 && (n2==23||n2==11)) || (n1==34 && n2==15) || (n1==33 && n2==27) || (n1==29 && (n2==25||n2==23||n2==5)) || (n1==28 && n2==18) || (n1==27 && (n2==20||n2==19||n2==17)) || (n1==25 && n2==4) || (n1==24 && n2==15) || (n1==23 && (n2==16||n2==3)) || (n1==22 && (n2==12||n2==11||n2==5)) || (n1==21 && (n2==10||n2==9)) || (n1==17 && n2==5) || (n1==16 && n2==2) || (n1==14 && n2==1) || (n1==12 && n2==4) || (n1==11 && n2==3) || (n1==10 && n2==4) || (n1== 9 && n2==3) || (n1== 6 && n2==1) || (n1== 5 && n2==3)) fl = 0; *s0=data10(N,n1,n2,tau); break; default: /* case 11: */ *s0=data11(N,n1,tau); break; } if (fl) lireresolv(n1,n2,N,R); else { R->a = NULL; R->nm = n1; R->nv = n2; } } static long isin_G_H(buildroot *BR, long n1, long n2) { pari_sp av = avma; const long N = BR->N; PERM s0, ww; GROUP tau, ss = lirecoset(n1,n2,N); resolv R; init_isin(N,n1,n2, &tau, &s0, &R); ww = check_isin(BR, &R, tau, ss); if (ww) { GEN z = cgetg(N+1, t_VEC); long i, j, l = lg(BR->r); s0 = permmul(ww, s0); if (DEBUGLEVEL) { err_printf("\n Output of isin_%ld_G_H(%ld,%ld): %ld",N,n1,n2,n2); err_printf("\n Reordering of the roots: "); printperm(s0); err_flush(); } for (i = 1; i < l; i++) { GEN p1 = gel(BR->r,i); for (j=1; j<=N; j++) gel(z,j) = gel(p1,s0[j]); for (j=1; j<=N; j++) gel(p1,j) = gel(z,j); } avma = av; return n2; } if (DEBUGLEVEL) { err_printf(" Output of isin_%ld_G_H(%ld,%ld): not included.\n",N,n1,n2); err_flush(); } avma = av; return 0; } static GEN polgaloisnamesbig(long n, long k) { pari_sp av = avma; char *s = stack_malloc(strlen(pari_datadir) + 13 + 20 + 3); pariFILE *f; GEN V; (void)sprintf(s, "%s/galdata/NAM%ld", pari_datadir, n); f = pari_fopengz(s); V = f? gp_read_stream(f->file): NULL; if (!V || typ(V)!=t_VEC || k>=lg(V)) pari_err_FILE("galois file %s",s); pari_fclose(f); return gerepilecopy(av, gel(V,k)); } /* pol a monic ZX */ static GEN galoisbig(GEN pol, long prec) { pari_sp av = avma; const long *tab; const long tab8[]={0, 8,8,8,8,8,16,16,16,16,16, 16,24,24,24,32,32,32,32,32,32, 32,32,48,48,56,64,64,64,64,64, 64,96,96,96,128,168,168,192,192,192, 192,288,336,384,576,576,1152,1344,20160,40320}; const long tab9[]={0, 9,9,18,18,18,27,27,36,36,54, 54,54,54,72,72,72,81,108,144,162, 162,162,216,324,324,432,504,648,648,648, 1296,1512,181440,362880}; const long tab10[]={0, 10,10,20,20,40,50,60,80,100,100, 120,120,120,160,160,160,200,200,200,200, 200,240,320,320,320,360,400,400,640,720, 720,720,800,960,1440, 1920,1920,1920,3840,7200,14400,14400,28800,1814400,3628800}; const long tab11[]={0, 11,22,55,110,660,7920,19958400,39916800}; GEN res, dpol = ZX_disc(pol); long t = 0, N = degpol(pol), EVEN = Z_issquare(dpol); if (DEBUGLEVEL) { err_printf("Galoisbig: polynomial #1 = %Ps\n", pol); err_printf("%s group\n", EVEN? "EVEN": "ODD"); err_flush(); } switch(N) { case 8: t = galoismodulo8(EVEN,pol,dpol); tab=tab8; break; case 9: t = galoismodulo9(EVEN,pol,dpol); tab=tab9; break; case 10:t = galoismodulo10(EVEN,pol,dpol); tab=tab10; break; case 11:t = galoismodulo11(EVEN,pol,dpol); tab=tab11; break; default: pari_err_IMPL("galois in degree > 11"); return NULL; /* LCOV_EXCL_LINE */ } if (!t) { buildroot BR; long i; GEN r, z = cgetg(N + 1, t_VEC); for (i = 1; i <= N; i++) { GEN v = cgetg(i+2,t_VECSMALL); gel(z,i) = v; v[1] = 0; } BR.coef = z; BR.p = pol; BR.pr = prec + nbits2extraprec((long)fujiwara_bound(pol)); BR.prmax = BR.pr + BIGDEFAULTPREC-2; BR.N = N; BR.r = vectrunc_init(N+1); r = gclone ( QX_complex_roots(BR.p, BR.prmax) ); vectrunc_append(BR.r, r); preci(r, BR.pr); switch(N) { case 8: t = closure8(EVEN, &BR); break; case 9: t = closure9(EVEN, &BR); break; case 10: t = closure10(EVEN, &BR); break; case 11: t = closure11(EVEN, &BR); break; } for (i = 1; i < lg(BR.r); i++) gunclone(gel(BR.r,i)); } avma = av; res = cgetg(5,t_VEC); gel(res,1) = stoi(tab[t]); gel(res,2) = stoi(EVEN? 1: -1); gel(res,3) = stoi(t); gel(res,4) = polgaloisnamesbig(N,t); return res; } /**************************************************************/ /* Galois group for degree <= 7 */ /**************************************************************/ /* exchange elements i and j in vector x */ static GEN transroot(GEN x, int i, int j) { x = leafcopy(x); swap(gel(x,i), gel(x,j)); return x; } /* x1*x2^2 + x2*x3^2 + x3*x4^2 + x4*x1^2 */ static GEN F4(GEN x) { return gadd( gmul(gel(x,1), gadd(gsqr(gel(x,2)), gmul(gel(x,4),gel(x,1)))), gmul(gel(x,3), gadd(gsqr(gel(x,4)), gmul(gel(x,2),gel(x,3))))); } static GEN roots_to_ZX(GEN z, long *e) { GEN a = roots_to_pol(z,0); GEN b = grndtoi(real_i(a),e); long e1 = gexpo(imag_i(a)); if (e1 > *e) *e = e1; return b; } static GEN polgaloisnames(long a, long b) { const char * const t[]={"S1", "S2", "A3", "S3", "C(4) = 4", "E(4) = 2[x]2", "D(4)", "A4", "S4", "C(5) = 5", "D(5) = 5:2", "F(5) = 5:4", "A5", "S5", "C(6) = 6 = 3[x]2", "D_6(6) = [3]2", "D(6) = S(3)[x]2", "A_4(6) = [2^2]3", "F_18(6) = [3^2]2 = 3 wr 2", "2A_4(6) = [2^3]3 = 2 wr 3", "S_4(6d) = [2^2]S(3)", "S_4(6c) = 1/2[2^3]S(3)", "F_18(6):2 = [1/2.S(3)^2]2", "F_36(6) = 1/2[S(3)^2]2", "2S_4(6) = [2^3]S(3) = 2 wr S(3)", "L(6) = PSL(2,5) = A_5(6)", "F_36(6):2 = [S(3)^2]2 = S(3) wr 2", "L(6):2 = PGL(2,5) = S_5(6)", "A6", "S6", "C(7) = 7", "D(7) = 7:2", "F_21(7) = 7:3", "F_42(7) = 7:6", "L(7) = L(3,2)", "A7", "S7"}; const long idx[]={0,1,2,4,9,14,30}; return strtoGENstr(t[idx[a-1]+b-1]); } static GEN galois_res(long d, long n, long s, long k) { GEN z = cgetg(5,t_VEC); long kk; if (new_galois_format) kk = k; else kk = (d == 6 && (k==6 || k==2))? 2: 1; gel(z,1) = stoi(n); gel(z,2) = stoi(s); gel(z,3) = stoi(kk); gel(z,4) = polgaloisnames(d,k); return z; } GEN polgalois(GEN x, long prec) { pari_sp av = avma, av1; long i,j,k,n,f,l,l2,e,e1,pr,ind; GEN x1,p1,p2,p3,p4,p5,w,z,ee; const int ind5[20]={2,5,3,4, 1,3,4,5, 1,5,2,4, 1,2,3,5, 1,4,2,3}; const int ind6[60]={3,5,4,6, 2,6,4,5, 2,3,5,6, 2,4,3,6, 2,5,3,4, 1,4,5,6, 1,5,3,6, 1,6,3,4, 1,3,4,5, 1,6,2,5, 1,2,4,6, 1,5,2,4, 1,3,2,6, 1,2,3,5, 1,4,2,3}; if (typ(x)!=t_POL) pari_err_TYPE("galois",x); n=degpol(x); if (n>11) pari_err_IMPL("galois of degree higher than 11"); x = Q_primpart(x); RgX_check_ZX(x, "galois"); if (!ZX_is_irred(x)) pari_err_IRREDPOL("galois",x); if (n<4) { if (n == 1) { avma = av; return galois_res(n,1, 1,1); } if (n == 2) { avma = av; return galois_res(n,2,-1,1); } /* n = 3 */ f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,3,1,1): galois_res(n,6,-1,2); } x1 = x = ZX_Q_normalize(x,NULL); av1=avma; if (n > 7) return galoisbig(x, prec); for(;;) { double fb = fujiwara_bound(x); switch(n) { case 4: z = cgetg(7,t_VEC); prec = nbits2prec((long)(fb*18.) + 64); for(;;) { p1=QX_complex_roots(x,prec); gel(z,1) = F4(p1); gel(z,2) = F4(transroot(p1,1,2)); gel(z,3) = F4(transroot(p1,1,3)); gel(z,4) = F4(transroot(p1,1,4)); gel(z,5) = F4(transroot(p1,2,3)); gel(z,6) = F4(transroot(p1,3,4)); p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec = precdbl(prec); } if (!ZX_is_squarefree(p5)) goto tchi; p2 = gel(ZX_factor(p5),1); switch(lg(p2)-1) { case 1: f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,12,1,4): galois_res(n,24,-1,5); case 2: avma = av; return galois_res(n,8,-1,3); case 3: avma = av; return (degpol(gel(p2,1))==2)? galois_res(n,4,1,2) : galois_res(n,4,-1,1); default: pari_err_BUG("galois (bug1)"); } case 5: z = cgetg(7,t_VEC); ee= cgetg(7,t_VECSMALL); w = cgetg(7,t_VECSMALL); prec = nbits2prec((long)(fb*21.) + 64); for(;;) { for(;;) { p1=QX_complex_roots(x,prec); for (l=1; l<=6; l++) { p2=(l==1)?p1: ((l<6)?transroot(p1,1,l): transroot(p1,2,5)); p3=gen_0; for (k=0,i=1; i<=5; i++,k+=4) { p5 = gadd(gmul(gel(p2,ind5[k]),gel(p2,ind5[k+1])), gmul(gel(p2,ind5[k+2]),gel(p2,ind5[k+3]))); p3 = gadd(p3, gmul(gsqr(gel(p2,i)),p5)); } gel(w,l) = grndtoi(real_i(p3),&e); e1 = gexpo(imag_i(p3)); if (e1>e) e=e1; ee[l]=e; gel(z,l) = p3; } p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec = precdbl(prec); } if (!ZX_is_squarefree(p5)) goto tchi; p3=gel(ZX_factor(p5),1); f=Z_issquare(ZX_disc(x)); if (lg(p3)-1==1) { avma = av; return f? galois_res(n,60,1,4): galois_res(n,120,-1,5); } if (!f) { avma = av; return galois_res(n,20,-1,3); } pr = - (prec2nbits(prec) >> 1); for (l=1; l<=6; l++) if (ee[l] <= pr && gequal0(poleval(p5,gel(w,l)))) break; if (l>6) pari_err_BUG("galois (bug4)"); p2=(l==6)? transroot(p1,2,5):transroot(p1,1,l); p3=gen_0; for (i=1; i<=5; i++) { j = (i == 5)? 1: i+1; p3 = gadd(p3,gmul(gmul(gel(p2,i),gel(p2,j)), gsub(gel(p2,j),gel(p2,i)))); } p5=gsqr(p3); p4=grndtoi(real_i(p5),&e); e1 = gexpo(imag_i(p5)); if (e1>e) e=e1; if (e <= -10) { if (gequal0(p4)) goto tchi; f = Z_issquare(p4); avma = av; return f? galois_res(n,5,1,1): galois_res(n,10,1,2); } prec = precdbl(prec); } case 6: z = cgetg(7, t_VEC); prec = nbits2prec((long) (fb * 42) + 64); for(;;) { for(;;) { p1=QX_complex_roots(x,prec); for (l=1; l<=6; l++) { p2=(l==1)?p1:transroot(p1,1,l); p3=gen_0; k=0; for (i=1; i<=5; i++) for (j=i+1; j<=6; j++) { p5=gadd(gmul(gel(p2,ind6[k]),gel(p2,ind6[k+1])), gmul(gel(p2,ind6[k+2]),gel(p2,ind6[k+3]))); p3=gadd(p3,gmul(gsqr(gmul(gel(p2,i),gel(p2,j))),p5)); k += 4; } gel(z,l) = p3; } p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec = precdbl(prec); } if (!ZX_is_squarefree(p5)) goto tchi; p2=gel(ZX_factor(p5),1); switch(lg(p2)-1) { case 1: z = cgetg(11,t_VEC); ind=0; p3=gadd(gmul(gmul(gel(p1,1),gel(p1,2)),gel(p1,3)), gmul(gmul(gel(p1,4),gel(p1,5)),gel(p1,6))); gel(z,++ind) = p3; for (i=1; i<=3; i++) for (j=4; j<=6; j++) { p2=transroot(p1,i,j); p3=gadd(gmul(gmul(gel(p2,1),gel(p2,2)),gel(p2,3)), gmul(gmul(gel(p2,4),gel(p2,5)),gel(p2,6))); gel(z,++ind) = p3; } p5 = roots_to_ZX(z, &e); if (e <= -10) { if (!ZX_is_squarefree(p5)) goto tchi; p2 = gel(ZX_factor(p5),1); f = Z_issquare(ZX_disc(x)); avma = av; if (lg(p2)-1==1) return f? galois_res(n,360,1,15): galois_res(n,720,-1,16); else return f? galois_res(n,36,1,10): galois_res(n,72,-1,13); } prec = precdbl(prec); break; case 2: l2=degpol(gel(p2,1)); if (l2>3) l2=6-l2; switch(l2) { case 1: f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,60,1,12): galois_res(n,120,-1,14); case 2: f = Z_issquare(ZX_disc(x)); if (f) { avma = av; return galois_res(n,24,1,7); } p3 = (degpol(gel(p2,1))==2)? gel(p2,2): gel(p2,1); f = Z_issquare(ZX_disc(p3)); avma = av; return f? galois_res(n,24,-1,6): galois_res(n,48,-1,11); case 3: f = Z_issquare(ZX_disc(gel(p2,1))) || Z_issquare(ZX_disc(gel(p2,2))); avma = av; return f? galois_res(n,18,-1,5): galois_res(n,36,-1,9); } case 3: for (l2=1; l2<=3; l2++) if (degpol(gel(p2,l2)) >= 3) p3 = gel(p2,l2); if (degpol(p3) == 3) { f = Z_issquare(ZX_disc(p3)); avma = av; return f? galois_res(n,6,-1,1): galois_res(n,12,-1,3); } else { f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,12,1,4): galois_res(n,24,-1,8); } case 4: avma = av; return galois_res(n,6,-1,2); default: pari_err_BUG("galois (bug3)"); } } case 7: z = cgetg(36,t_VEC); prec = nbits2prec((long)(fb*7.) + 64); for(;;) { ind = 0; p1=QX_complex_roots(x,prec); for (i=1; i<=5; i++) for (j=i+1; j<=6; j++) { GEN t = gadd(gel(p1,i),gel(p1,j)); for (k=j+1; k<=7; k++) gel(z,++ind) = gadd(t, gel(p1,k)); } p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec = precdbl(prec); } if (!ZX_is_squarefree(p5)) goto tchi; p2=gel(ZX_factor(p5),1); switch(lg(p2)-1) { case 1: f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,2520,1,6): galois_res(n,5040,-1,7); case 2: f = degpol(gel(p2,1)); avma = av; return (f==7 || f==28)? galois_res(n,168,1,5): galois_res(n,42,-1,4); case 3: avma = av; return galois_res(n,21,1,3); case 4: avma = av; return galois_res(n,14,-1,2); case 5: avma = av; return galois_res(n,7,1,1); default: pari_err_BUG("galois (bug2)"); } } tchi: avma = av1; x = tschirnhaus(x1); } } pari-2.11.2/src/systems/0000755000175000017500000000000013461316051013454 5ustar billbillpari-2.11.2/src/systems/darwin/0000755000175000017500000000000013461316051014740 5ustar billbillpari-2.11.2/src/systems/darwin/dlfcn.h0000644000175000017500000000436713201017466016211 0ustar billbill/* Copyright (c) 2002 Jorge Acereda & Peter O'Gorman Portions may be copyright others, see the AUTHORS file included with this distribution. Maintained by Peter O'Gorman Bug Reports and other queries should go to Permission is hereby granted, free of charge, to any person obtaining a copy of this software and attached documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _DLFCN_H_ #define _DLFCN_H_ #ifdef __cplusplus extern "C" { #endif /* * Structure filled in by dladdr(). */ typedef struct dl_info { const char *dli_fname; /* Pathname of shared object */ void *dli_fbase; /* Base address of shared object */ const char *dli_sname; /* Name of nearest symbol */ void *dli_saddr; /* Address of nearest symbol */ } Dl_info; extern void * dlopen(const char *path, int mode); extern void * dlsym(void * handle, const char *symbol); extern const char * dlerror(void); extern int dlclose(void * handle); extern int dladdr(void *, Dl_info *); #define RTLD_LAZY 0x1 #define RTLD_NOW 0x2 #define RTLD_LOCAL 0x4 #define RTLD_GLOBAL 0x8 #define RTLD_NOLOAD 0x10 #define RTLD_NODELETE 0x80 #ifdef __cplusplus } #endif #endif /* _DLFCN_H_ */ pari-2.11.2/src/systems/darwin/darwin.c0000644000175000017500000001417513201017466016400 0ustar billbill/* Copyright (c) 2002 Peter O'Gorman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and attached documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Modified for PARI/GP by the PARI group */ #include "pari.h" #ifndef HAS_DLOPEN #include #include #include #include #include #include #include #include #include "dlfcn.h" #define ERR_STR_LEN 256 static void *dlsymIntern(void *handle, const char *symbol); static const char *error(int setget, const char *str, ...); /* Set and get the error string for use by dlerror */ static const char *error(int setget, const char *str, ...) { static char errstr[ERR_STR_LEN]; static int err_filled = 0; const char *retval; va_list arg; if (setget == 0) { va_start(arg, str); strncpy(errstr, "dlsimple: ", ERR_STR_LEN); vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg); va_end(arg); err_filled = 1; retval = NULL; } else { retval = err_filled? errstr: NULL; err_filled = 0; } return retval; } /* dlopen */ void *dlopen(const char *path, int mode) { void *module = 0; NSObjectFileImage ofi = 0; NSObjectFileImageReturnCode ofirc; static int (*make_private_module_public) (NSModule module) = 0; unsigned int flags = NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE; /* If we got no path, the app wants the global namespace, use -1 as the marker in this case */ if (!path) return (void *)-1; /* Create the object file image, works for things linked with the -bundle arg to ld */ ofirc = NSCreateObjectFileImageFromFile(path, &ofi); switch (ofirc) { case NSObjectFileImageSuccess: /* It was okay, so use NSLinkModule to link in the image */ if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW; module = NSLinkModule(ofi, path,flags); /* Don't forget to destroy the object file image, unless you like leaks */ NSDestroyObjectFileImage(ofi); /* If the mode was global, then change the module, this avoids multiply defined symbol errors to first load private then make global. Silly, isn't it. */ if ((mode & RTLD_GLOBAL)) { if (!make_private_module_public) { _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (void**)&make_private_module_public); } make_private_module_public((NSModule)module); } break; case NSObjectFileImageInappropriateFile: /* It may have been a dynamic library rather than a bundle, try to load it */ module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); break; case NSObjectFileImageFailure: error(0,"Object file setup failure : \"%s\"", path); return 0; case NSObjectFileImageArch: error(0,"No object for this architecture : \"%s\"", path); return 0; case NSObjectFileImageFormat: error(0,"Bad object file format : \"%s\"", path); return 0; case NSObjectFileImageAccess: error(0,"Can't read object file : \"%s\"", path); return 0; } if (!module) error(0, "Can not open \"%s\"", path); return module; } static int is_mach_header(void *handle) { /* Check for both possible magic numbers depending on x86/ppc byte order */ return ((((struct mach_header *)handle)->magic == MH_MAGIC) || (((struct mach_header *)handle)->magic == MH_CIGAM)); } /* used by dlsym to find the symbol */ void *dlsymIntern(void *handle, const char *symbol) { NSSymbol nssym = NULL; if (handle == (void *)-1) { /* Global context */ if (NSIsSymbolNameDefined(symbol)) nssym = NSLookupAndBindSymbol(symbol); } else { if (is_mach_header(handle)) { /* library */ if (NSIsSymbolNameDefinedInImage((struct mach_header *)handle, symbol)) nssym = NSLookupSymbolInImage((struct mach_header *)handle, symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); } else /* bundle */ nssym = NSLookupSymbolInModule((NSModule)handle, symbol); } if (!nssym) { error(0, "Symbol \"%s\" Not found", symbol); return NULL; } return NSAddressOfSymbol(nssym); } const char *dlerror(void) { return error(1, (char *)NULL); } int dlclose(void *handle) { if (is_mach_header(handle)) { error(0, "Can't remove dynamic libraries on darwin"); return 0; } if (!NSUnLinkModule((NSModule)handle, 0)) { error(0, "unable to unlink module %s", NSNameOfModule((NSModule)handle)); return 1; } return 0; } /* dlsym, prepend the underscore and call dlsymIntern */ void *dlsym(void *handle, const char *symbol) { static char undersym[257]; /* Saves calls to malloc(3) */ int sym_len = strlen(symbol); void *value = NULL; char *malloc_sym = NULL; if (sym_len < 256) { snprintf(undersym, 256, "_%s", symbol); value = dlsymIntern(handle, undersym); } else { malloc_sym = (char*)malloc(sym_len + 2); if (malloc_sym) { sprintf(malloc_sym, "_%s", symbol); value = dlsymIntern(handle, malloc_sym); pari_free(malloc_sym); } else error(0, "Unable to allocate memory"); } return value; } #endif pari-2.11.2/src/systems/mingw/0000755000175000017500000000000013461316051014575 5ustar billbillpari-2.11.2/src/systems/mingw/mingw.h0000644000175000017500000000157713326135265016107 0ustar billbill/* Copyright (C) 2009 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ const char* win32_basedir(void); char* win32_datadir(void); void win32_ansi_fputs(const char* s, void* f); int win32_terminal_width(void); int win32_terminal_height(void); void win32_set_codepage(void); void win32_set_pdf_viewer(void); void win32_alarm(unsigned int s); long win32_timer(void); long win32_nbthreads(void); pari-2.11.2/src/systems/mingw/mingw.c0000644000175000017500000001202613326135265016071 0ustar billbill/* Copyright (C) 2009 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Originally written by Vasili Burdo */ #include "pwinver.h" #include #include #include "mingw.h" static const char * pariwin32_basedir = NULL; const char* win32_basedir(void) { if (pariwin32_basedir) return pariwin32_basedir; else { char basedir[1024]; char* slash; GetModuleFileNameA(0, basedir, sizeof(basedir) ); slash = strrchr(basedir, '\\'); if (slash) slash[1] = 0; pariwin32_basedir = strdup(basedir); return pariwin32_basedir; } } char* win32_datadir(void) { char datadir[1029]; const char * basedir = win32_basedir(); sprintf(datadir, "%sdata",basedir); return strdup(datadir); } static WORD win32_console_color(unsigned long c) { int shift, intense = 0; if( c >= 30 && c <= 37 ) { shift = 0; c -= 30; } else if( c >= 40 && c <= 47 ) { shift = 4; c -= 40; } else if( c >= 90 && c <= 97 ) { shift = 0; intense = 8; c -= 90; } else if(c >= 100 && c <= 107) { shift = 4; intense = 8; c -= 100; } else return 0; WORD w = 0; switch(c) { case 0: w = 0; break; /* black */ case 1: w = 4; break; /* red */ case 2: w = 2; break; /* green */ case 3: w = 6; break; /* yellow RG */ case 4: w = 1; break; /* blue */ case 5: w = 5; break; /* magenta RB */ case 6: w = 3; break; /* cyan GB */ case 7: w = 7; break; /* white RGB */ } return (w|intense) << shift; } void win32_ansi_fputs(const char* s, void* f) { WORD color; unsigned long c[3]; long nbarg; if( !(f == stdout || f == stderr) ) { fputs(s,f); return; } while(1) { char *p; p = strstr(s, "\x1b["); if( p > s ) fwrite(s,p-s,1,f); if( p ) p += 2; else { fputs(s,f); return; } nbarg = 0; c[nbarg++] = strtoul(p,&p,10); if( *p == ';' ) c[nbarg++] = strtoul(p+1,&p,10); if( *p == ';' ) c[nbarg++] = strtoul(p+1,&p,10); if( *p++ == 'm' ) { switch(nbarg) { case 1: color = 7; break; case 2: color = win32_console_color(c[1]); if (c[0]&4) color |= 0x8000; break; case 3: color = win32_console_color(c[1]) | win32_console_color(c[2]); if (c[0]&4) color |= 0x8000; } fflush(f); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color); } s = p; } } int win32_terminal_width(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi)) return 0; return sbi.srWindow.Right - sbi.srWindow.Left + 1; } int win32_terminal_height(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi)) return 0; return sbi.srWindow.Bottom - sbi.srWindow.Top + 1; } void win32_set_codepage(void) { SetConsoleCP( GetACP() ); SetConsoleOutputCP( GetACP() ); } void win32_set_pdf_viewer(void) { char *s = getenv("GP_PDF_VIEWER"); if (!s) { HKEY handle; const char *key = "AcroExch.Document\\shell\\open\\command"; const long SZ = 512; char str[SZ], *buf; int status; DWORD L = SZ; (void)RegOpenKeyEx(HKEY_CLASSES_ROOT, key, 0, KEY_READ, &handle); status = RegQueryValueEx(handle, NULL, 0, NULL, (LPBYTE)str, &L); RegCloseKey(handle); if (status) return; buf = malloc(strlen(str)+16); /*must not be freed*/ sprintf(buf,"GP_PDF_VIEWER=%s",str); putenv(buf); } } extern int win32ctrlc, win32alrm; static HANDLE hTimerQueue = NULL; static void CALLBACK win32_cb_alarm(void *lpParam, BOOLEAN TimerOrWaitFired) { (void) lpParam; (void) TimerOrWaitFired; win32ctrlc++; win32alrm = 1; } void win32_alarm(unsigned int s) { if (hTimerQueue) { HANDLE oldhTimerQueue = hTimerQueue; hTimerQueue = NULL; DeleteTimerQueue(oldhTimerQueue); } if (s) { void *arg = NULL; HANDLE hTimer = NULL; hTimerQueue = CreateTimerQueue(); CreateTimerQueueTimer( &hTimer, hTimerQueue, (WAITORTIMERCALLBACK)win32_cb_alarm, &arg , s*1000, 0, 0); } } #define WIN32_FILETIME_PER_MILLISECOND 10000 long win32_timer(void) { FILETIME lpCreation, lpExit, lpKernel, lpUser; LARGE_INTEGER time; GetProcessTimes( GetCurrentProcess(), &lpCreation, &lpExit, &lpKernel, &lpUser ); time.HighPart = lpUser.dwHighDateTime; time.LowPart = lpUser.dwLowDateTime; time.QuadPart /= WIN32_FILETIME_PER_MILLISECOND; return time.LowPart; } long win32_nbthreads(void) { SYSTEM_INFO system_info; GetSystemInfo(&system_info); return system_info.dwNumberOfProcessors; } pari-2.11.2/src/systems/mingw/pwinver.h0000644000175000017500000000002513201017466016435 0ustar billbill#define WINVER 0x501 pari-2.11.2/src/systems/emscripten/0000755000175000017500000000000013461316051015625 5ustar billbillpari-2.11.2/src/systems/emscripten/emscripten.h0000644000175000017500000000134013326135265020153 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ BEGINEXTERN void pari_emscripten_help(const char *s); void pari_emscripten_wget(const char *s); void pari_emscripten_plot_init(long width, long height); ENDEXTERN pari-2.11.2/src/systems/emscripten/emscripten.c0000644000175000017500000000503213447371554020157 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "../src/graph/rect.h" #include void pari_emscripten_wget(const char *s) { const char *name = stack_sprintf("/gpjs/root/%s",s); emscripten_async_wget(name,s,NULL,NULL); pari_err(e_MISC,"retry"); } void pari_emscripten_help(const char *s) { const char *url = "https://pari.math.u-bordeaux.fr/dochtml"; #if ((PARI_VERSION_CODE>>PARI_VERSION_SHIFT)&1) pari_err(e_MISC,"Help: %s/help-stable/%s",url,s); #else pari_err(e_MISC,"Help: %s/help/%s",url,s); #endif } static GEN emscripten_base64(const char *s) { static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; long i, j, ls = strlen(s), lt = ((ls+2)/3)*4; long n = nchar2nlong(lt+1); GEN g = cgetg(1+n, t_STR); char *t = GSTR(g); g[n] = 0L; for(i=j=0; i < ls; i+=3, j+=4) { char s0 = s[i], s1 = i+1> 2]; t[j+1] = base64[((s0 & 0x3) << 4) + ((s1 & 0xf0) >> 4)]; t[j+2] = i+1> 6)]: '='; t[j+3] = i+2 #include #include #include #include static ULONG retcode; static char fail[300]; static ULONG dllHandle; static char dllname[80]; static int handle_found; static int handle_loaded; #ifdef DLOPEN_INITTERM unsigned long _DLL_InitTerm(unsigned long modHandle, unsigned long flag) { switch (flag) { case 0: /* INIT */ /* Save handle */ dllHandle = modHandle; handle_found = 1; return TRUE; case 1: /* TERM */ handle_found = 0; dllHandle = (unsigned long)NULLHANDLE; return TRUE; } return FALSE; } #endif HMODULE find_myself(void) { static APIRET APIENTRY (*pDosQueryModFromEIP) (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf, ULONG * Offset, ULONG Address); HMODULE doscalls_h, mod; static int failed; ULONG obj, offset, rc; char buf[260]; if (failed) return 0; failed = 1; doscalls_h = (HMODULE)dlopen("DOSCALLS",0); if (!doscalls_h) return 0; /* {&doscalls_handle, NULL, 360}, */ /* DosQueryModFromEIP */ rc = DosQueryProcAddr(doscalls_h, 360, 0, (PFN*)&pDosQueryModFromEIP); if (rc) return 0; rc = pDosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, (ULONG)dlopen); if (rc) return 0; failed = 0; handle_found = 1; dllHandle = mod; return mod; } void * dlopen(char *path, int mode) { HMODULE handle; char tmp[260], *beg, *dot; ULONG rc; unsigned fpflag = _control87(0,0); fail[0] = 0; if (!path) { /* Our own handle. */ if (handle_found || find_myself()) { if (handle_loaded) return (void*)dllHandle; rc = DosQueryModuleName(dllHandle, sizeof(dllname), dllname); if (rc) { strcpy(fail, "can't find my DLL name by the handle"); retcode = rc; return 0; } rc = DosLoadModule((PSZ)fail, sizeof fail, (PSZ)dllname, &handle); if (rc) { strcpy(fail, "can't load my own DLL"); retcode = rc; return 0; } handle_loaded = 1; goto ret; } retcode = ERROR_MOD_NOT_FOUND; strcpy(fail, "can't load from myself: compiled without -DDLOPEN_INITTERM"); return 0; } if ((rc = DosLoadModule((PSZ)fail, sizeof fail, (PSZ)path, &handle)) == 0) goto ret; retcode = rc; /* Not found. Check for non-FAT name and try truncated name. */ /* Don't know if this helps though... */ for (beg = dot = path + strlen(path); beg > path && !strchr(":/\\", *(beg-1)); beg--) if (*beg == '.') dot = beg; if (dot - beg > 8) { int n = beg+8-path; memmove(tmp, path, n); memmove(tmp+n, dot, strlen(dot)+1); rc = DosLoadModule((PSZ)fail, sizeof fail, (PSZ)tmp, &handle); if (rc == 0) goto ret; retcode = rc; } handle = 0; ret: _control87(fpflag, MCW_EM); /* Some modules reset FP flags on load */ return (void *)handle; } #define ERROR_WRONG_PROCTYPE 0xffffffff void * dlsym(void *handle, char *symbol) { ULONG rc, type; PFN addr; fail[0] = 0; rc = DosQueryProcAddr((HMODULE)handle, 0, (PSZ)symbol, &addr); if (rc == 0) { rc = DosQueryProcType((HMODULE)handle, 0, (PSZ)symbol, &type); if (rc == 0 && type == PT_32BIT) return (void *)addr; rc = ERROR_WRONG_PROCTYPE; } retcode = rc; return NULL; } char * dlerror(void) { static char buf[700]; ULONG len; if (retcode == 0) return NULL; if (retcode == ERROR_WRONG_PROCTYPE) { strcpy(buf, "Wrong procedure type"); len = strlen(buf); } if ((retcode != ERROR_WRONG_PROCTYPE) && DosGetMessage(NULL, 0, buf, sizeof buf - 1, retcode, (PSZ)"OSO001.MSG", &len)) { if (fail[0]) sprintf(buf, "OS/2 system error code %d, possible problematic module: '%s'", (int)retcode, fail); else sprintf(buf, "OS/2 system error code %d", (int)retcode); } else { buf[len] = '\0'; if (len && buf[len - 1] == '\n') buf[--len] = 0; if (len && buf[len - 1] == '\r') buf[--len] = 0; if (len && buf[len - 1] == '.') buf[--len] = 0; if (fail[0] && len < 300) sprintf(buf + len, ", possible problematic module: '%s'", fail); } retcode = 0; return buf; } int dlclose(void *handle) { ULONG rc; if ((rc = DosFreeModule((HMODULE)handle)) == 0) return 0; retcode = rc; return 2; } void* get_stack(double fraction, long min) { int rc; TIB *tib; PIB *pib; char *s, *e; unsigned long d; if (!(_emx_env & 0x200)) return 0; /* not OS/2. */ rc = DosGetInfoBlocks(&tib, &pib); if (rc) return 0; /* ignore error */ s = (char*)tib->tib_pstack; e = (char*)tib->tib_pstacklimit; d = fraction * (e-s); if (min >= 3*(e-s)/4) min = 3*(e-s)/4; if (d < min) d = min; return (void*)(s + d); } pari-2.11.2/src/systems/os2/README0000644000175000017500000000416312314242551015042 0ustar billbillOn OS/2 the build goes the same way as on Unix, e.g., sh Configure make gp make bench With the current implementation of install(), one can load the functions from the PARI library only if the GP executable is build for dynamic linking. By default, the build will go to an AOUT-type executables (to simplify the logic of Configure, and enable restricted binary compatibility with DOS/Windows). Unfortunately, AOUT-type DLLs are very restricted; thus the build of dynamically linked target fails. To build with OMF-type target cd Oos2-ix86 make _O=.obj _A=.lib CC_FLAVOR="-Zomf -Zcrtdll -Zstack 8192" RLLIBS=-lreadline_import DLLD_IGNORE= AR=emxomfar bench This build constructs a working DLL. Both -Zomf and -Zcrtdll are crucial to have a functioning DLL (see EMX documentation for details). -Zstack 8192 forces the same C stack size as for AOUT build (and the same - 8M - as on many Unices, so you get fewer surprises when things work on Unix, but core on OS/2 due only to shorter C stack). (The standard Configure adds -Zsysv-signals option; in fact, this option is not needed - as checked with v2.3.5.) Use of the the readline-DLL (via the readline_import.lib library) is not only a convenience, but also statically linked readline library are often broken; sigh... To use the gnuplot-engine DLL gnpltdrw.DLL, one can give Configure the option --graphic=gnuplot-dynamic,gnpltdrw (requires linking with -Zcrtdll for graphics to work). Add -DOLD_SET_FEEDBACK_RECTANGLE gcc option if gnpltdrw.DLL supports mousing, but is an old build, so it won't report this capability. Thus the build process may look like this: sh Configure --graphic=gnuplot-dynamic,gnpltdrw make gp cd Oos2-ix86 make _O=.obj _A=.lib CC_FLAVOR="-Zomf -Zcrtdll -Zstack 8192 -DUSE_SET_FEEDBACK_RECTANGLE" RLLIBS=-lreadline_import DLLD_IGNORE= AR=emxomfar bench cd .. The statically build PARI library is in a file named similar to libpari-2_2.a, the library for linking with the PARI DLL is named as pari-2_2.a (or pari-2_2.lib). As a debugging tool, the constructed DLL reports its build options via the standard OS/2 way: bldlevel FULL_NAME_OF_THE_DLL pari-2.11.2/src/systems/os2/pari.def.base0000644000175000017500000000040111636712103016476 0ustar billbillLIBRARY '' INITINSTANCE TERMINSTANCE ; Can't put http://.../ in VENDOR, since it is split on : ; One should be be glad that .../ is good enough DESCRIPTION '@#:#@' CODE LOADONCALL DATA LOADONCALL NONSHARED MULTIPLE EXPORTS pari-2.11.2/src/systems/os2/dlfcn.h0000644000175000017500000000021411636712103015413 0ustar billbill#define RTLD_LAZY 1 #define RTLD_GLOBAL 1 void *dlopen(char *path, int mode); void *dlsym(void *handle, char *symbol); char *dlerror(void); pari-2.11.2/src/systems/cygwin/0000755000175000017500000000000013461316051014754 5ustar billbillpari-2.11.2/src/systems/cygwin/cygwin.c0000644000175000017500000000156113036414402016420 0ustar billbill/* Copyright (C) 2009 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Written by Vasili Burdo */ #include #include char* win32_datadir(void) { char datadir[1024]; char* slash; GetModuleFileNameA(0, datadir, sizeof(datadir) ); slash = strrchr(datadir, '\\'); if( slash ) *(slash+1) = 0; strcat(datadir, "data"); return strdup(datadir); } pari-2.11.2/src/language/0000755000175000017500000000000013461316051013530 5ustar billbillpari-2.11.2/src/language/hash.c0000644000175000017500000002143313447371554014637 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /********************************************************************/ /* */ /* GENERAL HASHTABLES */ /* */ /********************************************************************/ /* http://planetmath.org/encyclopedia/GoodHashTablePrimes.html */ static const ulong hashprimes[] = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; static const int hashprimes_len = numberof(hashprimes); INLINE void setlen(hashtable *h, ulong len) { h->maxnb = (ulong)ceil(len * 0.65); h->len = len; } static int get_prime_index(ulong len) { int i; for (i=0; i < hashprimes_len; i++) if (hashprimes[i] > len) return i; pari_err_OVERFLOW("hash table [too large]"); return -1; /* LCOV_EXCL_LINE */ } /* link hashentry e to hashtable h, setting e->hash / e->next */ INLINE void hash_link2(hashtable *h, hashentry *e, ulong hash) { ulong index; e->hash = hash; index = e->hash % h->len; e->next = h->table[index]; h->table[index] = e; } INLINE void hash_link(hashtable *h, hashentry *e) { hash_link2(h,e,h->hash(e->key));} hashtable * hash_create(ulong minsize, ulong (*hash)(void*), int (*eq)(void*,void*), int use_stack) { int i = get_prime_index(minsize); ulong len = hashprimes[i]; hashtable *h; if (use_stack) { h = (hashtable*)stack_malloc(sizeof(hashtable)); h->table = (hashentry**)stack_calloc(len * sizeof(hashentry*)); h->use_stack = 1; } else { h = (hashtable*)pari_malloc(sizeof(hashtable)); h->table = (hashentry**)pari_calloc(len * sizeof(hashentry*)); h->use_stack = 0; } h->pindex = i; h->nb = 0; h->hash = hash; h->eq = eq; setlen(h, len); return h; } void hash_init_GEN(hashtable *h, ulong minsize, int (*eq)(GEN,GEN), int use_stack) { int i = get_prime_index(minsize); ulong len = hashprimes[i]; if (use_stack) h->table = (hashentry**)stack_calloc(len * sizeof(hashentry*)); else h->table = (hashentry**)pari_calloc(len * sizeof(hashentry*)); h->use_stack = use_stack; h->pindex = i; h->nb = 0; h->hash = (ulong (*)(void*)) hash_GEN; h->eq = (int (*)(void*,void*)) eq; setlen(h, len); } void hash_insert2(hashtable *h, void *k, void *v, ulong hash) { hashentry *e; ulong index; if (h->use_stack) e = (hashentry*) stack_malloc(sizeof(hashentry)); else e = (hashentry*) pari_malloc(sizeof(hashentry)); if (++(h->nb) > h->maxnb && h->pindex < hashprimes_len-1) { /* double table size */ ulong i, newlen = hashprimes[++(h->pindex)]; hashentry *E, **newtable; if (h->use_stack) newtable = (hashentry**)stack_calloc(newlen*sizeof(hashentry*)); else newtable = (hashentry**)pari_calloc(newlen*sizeof(hashentry*)); for (i = 0; i < h->len; i++) while ( (E = h->table[i]) ) { h->table[i] = E->next; index = E->hash % newlen; E->next = newtable[index]; newtable[index] = E; } if (!h->use_stack) pari_free(h->table); h->table = newtable; setlen(h, newlen); } e->key = k; e->val = v; hash_link2(h, e, hash); } void hash_insert(hashtable *h, void *k, void *v) { hash_insert2(h,k,v,h->hash(k)); } void hash_insert_long(hashtable *h, void *k, long v) { hash_insert2(h,k,(void*)v,h->hash(k)); } /* the key 'k' may correspond to different values in the hash, return * one satisfying the selection callback */ hashentry * hash_select(hashtable *h, void *k, void *E,int(*select)(void *,hashentry *)) { ulong hash = h->hash(k); hashentry *e = h->table[ hash % h->len ]; while (e) { if (hash == e->hash && h->eq(k, e->key) && select(E,e)) return e; e = e->next; } return NULL; } GEN hash_keys(hashtable *h) { long k = 1; ulong i; GEN v = cgetg(h->nb+1, t_VECSMALL); for (i = 0; i < h->len; i++) { hashentry *e = h->table[i]; while (e) { v[k++] = (long)e->key; e = e->next; } } return v; } GEN hash_values(hashtable *h) { long k = 1; ulong i; GEN v = cgetg(h->nb+1, t_VECSMALL); for (i = 0; i < h->len; i++) { hashentry *e = h->table[i]; while (e) { v[k++] = (long)e->val; e = e->next; } } return v; } /* assume hash = h->hash(k) */ hashentry * hash_search2(hashtable *h, void *k, ulong hash) { hashentry *e = h->table[ hash % h->len ]; while (e) { if (hash == e->hash && h->eq(k, e->key)) return e; e = e->next; } return NULL; /* not found */ } /* returns entry attached to key k or NULL */ hashentry * hash_search(hashtable *h, void *k) { if (h->nb == 0) return NULL; return hash_search2(h, k, h->hash(k)); } int hash_haskey_long(hashtable *h, void *k, long *v) { hashentry * e = hash_search(h, k); if (e) { *v = (long) e->val; return 1; } else return 0; } hashentry * hash_remove_select(hashtable *h, void *k, void *E, int (*select)(void*,hashentry*)) { ulong hash = h->hash(k), index = hash % h->len; hashentry **pE = &(h->table[index]), *e = *pE; while (e) { if (hash == e->hash && h->eq(k, e->key) && select(E,e)) { *pE = e->next; h->nb--; return e; } pE = &(e->next); e = e->next; } return NULL; } hashentry * hash_remove(hashtable *h, void *k) { ulong hash = h->hash(k), index = hash % h->len; hashentry **pE = &(h->table[index]), *e = *pE; while (e) { if (hash == e->hash && h->eq(k, e->key)) { *pE = e->next; h->nb--; return e; } pE = &(e->next); e = e->next; } return NULL; } void hash_destroy(hashtable *h) { ulong i; if (h->use_stack) return; for (i = 0; i < h->len; i++) { hashentry *e = h->table[i]; while (e) { hashentry *f = e; e = e->next; pari_free(f); } } pari_free(h->table); pari_free(h); } static ulong hash_id(void *x) { return (ulong)x; } static int eq_id(void *x, void *y) { return x == y; } hashtable * hash_create_ulong(ulong s, long stack) { return hash_create(s, &hash_id, &eq_id, stack); } static int strequal(void *a, void *b) { return !strcmp((char*)a,(char*)b); } hashtable * hash_create_str(ulong s, long stack) { return hash_create(s, (ulong (*)(void *))&hash_str, strequal, stack); } hashtable * hashstr_import_static(hashentry *e, ulong size) { hashtable *h = hash_create_str(size, 0); for ( ; e->key; e++) { hash_link(h, e); h->nb++; } return h; } void hash_dbg(hashtable *h) { ulong n, Total = 0, Max = 0; hashentry *e, **table = h->table; for (n=0; n < h->len; n++) { ulong m=0; for (e=table[n]; e; e=e->next) m++; Total += m; if (Max < m) Max = m; pari_printf("%4ld:%2ld ",n,m); if (n%9 == 8) pari_putc('\n'); } pari_printf("\nTotal = %ld, Max = %ld\n", Total, Max); } /********************************************************************/ /* */ /* HASH FUNCTIONS */ /* */ /********************************************************************/ INLINE ulong glue(ulong h, ulong a) { return 404936533*h + a; } ulong hash_GEN(GEN x) { ulong h = x[0] & ~CLONEBIT; long tx = typ(x), lx, i; switch(tx) { /* non recursive types */ case t_INT: lx = lgefint(x); h &= TYPBITS; for (i = 1; i < lx; i++) h = glue(h, uel(x,i)); return h; case t_REAL: case t_STR: case t_VECSMALL: lx = lg(x); for (i = 1; i < lx; i++) h = glue(h, uel(x,i)); return h; /* one more special case */ case t_LIST: x = list_data(x); if (!x) return h; /* fall through */ default: if (lontyp[tx] == 2) { h = glue(h, x[1]); i = 2; } else i = 1; lx = lg(x); for (; i < lx; i++) h = glue(h, hash_GEN(gel(x,i))); return h; } } /* djb's hash */ ulong hash_str(const char *str) { ulong hash = 5381, c; while ( (c = (ulong)*str++) ) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ return hash; } /* hashvalue's underlying hash function */ ulong hash_str2(const char *s) { ulong n = 0, c; while ( (c = (ulong)*s++) ) n = (n<<1) ^ c; return n; } pari-2.11.2/src/language/parse.h0000644000175000017500000000523713201020711015005 0ustar billbill/* A Bison parser, made by GNU Bison 3.0.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_PARI_SRC_LANGUAGE_PARSE_H_INCLUDED # define YY_PARI_SRC_LANGUAGE_PARSE_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int pari_debug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { KPARROW = 258, KARROW = 259, KDOTDOT = 260, KPE = 261, KSE = 262, KME = 263, KDE = 264, KDRE = 265, KEUCE = 266, KMODE = 267, KAND = 268, KOR = 269, KID = 270, KEQ = 271, KNE = 272, KGE = 273, KLE = 274, KSRE = 275, KSLE = 276, KSR = 277, KSL = 278, KDR = 279, KPP = 280, KSS = 281, KINTEGER = 282, KREAL = 283, KENTRY = 284, KSTRING = 285, SEQ = 286, DEFFUNC = 287, INT = 288, LVAL = 289, SIGN = 290 }; #endif /* Value type. */ /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif int pari_parse (char **lex); #endif /* !YY_PARI_SRC_LANGUAGE_PARSE_H_INCLUDED */ pari-2.11.2/src/language/tree.h0000644000175000017500000000331513201017466014642 0ustar billbill/* Copyright (C) 2000-2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ BEGINEXTERN typedef enum {Fseq, Fmatrix,Frange, Fassign, Fmatcoeff, Fmatrixelts,Fmatrixlines, Fmat,Fvec,Fnoarg,Fnorange, Flistarg, Frefarg, Fvararg, Fconst,Fsmall, Ftag, Fentry,Fcall,Ffunction,Flambda } Ffunc; #define Flastfunc (Fdeffunc) #define FneedENTRY (Fconst) typedef struct node_s { Ffunc f; /*node function */ long x; /*node left child */ long y; /*node right child*/ const char *str; /*text start */ size_t len; /*text length */ long flags; /*flags from the copy optimizer*/ } node; typedef enum {CSTstr, CSTquote, CSTint, CSTreal, CSTmember, CSTentry} CSTtype; typedef enum {OPor, OPand, OPid, OPeq, OPne, OPge, OPg, OPle, OPl, OPs, OPp, OPsl, OPsr, OPmod, OPdr, OPeuc, OPd, OPm, OPpow, OPcat, OPss, OPpp, OPse ,OPpe ,OPsle ,OPsre ,OPmode ,OPdre ,OPeuce ,OPde ,OPme, OPpl, OPn, OPnb, OPfact, OPderiv, OPtrans, OPrange, OPcompr, OPcomprc, OPhist, OPhisttime, OPlength, OPnboperator} OPerator; extern THREAD node *pari_tree; ENDEXTERN pari-2.11.2/src/language/intnum.c0000644000175000017500000021564413457566442015242 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" static const long EXTRAPREC = #ifdef LONG_IS_64BIT 1; #else 2; #endif static GEN intlin(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab, long prec); /********************************************************************/ /** NUMERICAL INTEGRATION (Romberg) **/ /********************************************************************/ typedef struct { void *E; GEN (*f)(void *E, GEN); } invfun; /* 1/x^2 f(1/x) */ static GEN _invf(void *E, GEN x) { invfun *S = (invfun*)E; GEN y = ginv(x); return gmul(S->f(S->E, y), gsqr(y)); } /* h and s are arrays of the same length L > D. The h[i] are (decreasing) * step sizes, s[i] is the computed Riemann sum for step size h[i]. * Interpolate the last D+1 values so that s ~ polynomial in h of degree D. * Guess that limit_{h->0} = s(0) */ static GEN interp(GEN h, GEN s, long L, long bit, long D) { pari_sp av = avma; long e1,e2; GEN dss, ss = polint_i(h + L-D,s + L-D, gen_0, D+1, &dss); e1 = gexpo(ss); e2 = gexpo(dss); if (DEBUGLEVEL>2) { err_printf("romb: iteration %ld, guess: %Ps\n", L,ss); err_printf("romb: relative error < 2^-%ld [target %ld bits]\n",e1-e2,bit); } if (e1-e2 <= bit && (L <= 10 || e1 >= -bit)) { avma = av; return NULL; } return cxtoreal(ss); } static GEN qrom3(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, long bit) { const long JMAX = 25, KLOC = 4; GEN ss,s,h,p1,p2,qlint,del,x,sum; long j, j1, it, sig, prec = nbits2prec(bit); a = gtofp(a,prec); b = gtofp(b,prec); qlint = subrr(b,a); sig = signe(qlint); if (!sig) return gen_0; if (sig < 0) { setabssign(qlint); swap(a,b); } s = new_chunk(JMAX+KLOC-1); h = new_chunk(JMAX+KLOC-1); gel(h,0) = real_1(prec); p1 = eval(E, a); if (p1 == a) p1 = rcopy(p1); p2 = eval(E, b); gel(s,0) = gmul2n(gmul(qlint,gadd(p1,p2)),-1); for (it=1,j=1; j= KLOC && (ss = interp(h, s, j, bit-j-6, KLOC))) return gmulsg(sig,ss); } pari_err_IMPL("intnumromb recovery [too many iterations]"); return NULL; /* LCOV_EXCL_LINE */ } static GEN qrom2(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, long bit) { const long JMAX = 16, KLOC = 4; GEN ss,s,h,p1,qlint,del,ddel,x,sum; long j, j1, it, sig, prec = nbits2prec(bit); a = gtofp(a, prec); b = gtofp(b, prec); qlint = subrr(b,a); sig = signe(qlint); if (!sig) return gen_0; if (sig < 0) { setabssign(qlint); swap(a,b); } s = new_chunk(JMAX+KLOC-1); h = new_chunk(JMAX+KLOC-1); gel(h,0) = real_1(prec); p1 = shiftr(addrr(a,b),-1); gel(s,0) = gmul(qlint, eval(E, p1)); for (it=1, j=1; j= KLOC && (ss = interp(h, s, j, bit-(3*j/2)+3, KLOC))) return gmulsg(sig, ss); } pari_err_IMPL("intnumromb recovery [too many iterations]"); return NULL; /* LCOV_EXCL_LINE */ } /* integrate after change of variables x --> 1/x */ static GEN qromi(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long bit) { GEN A = ginv(b), B = ginv(a); invfun S; S.f = eval; S.E = E; return qrom2(&S, &_invf, A, B, bit); } /* a < b, assume b "small" (< 100 say) */ static GEN rom_bsmall(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long bit) { if (gcmpgs(a,-100) >= 0) return qrom2(E,eval,a,b,bit); if (gcmpgs(b, -1) < 0) return qromi(E,eval,a,b,bit); /* a<-100, b<-1 */ /* a<-100, b>=-1, split at -1 */ return gadd(qromi(E,eval,a,gen_m1,bit), qrom2(E,eval,gen_m1,b,bit)); } static GEN rombint(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long bit) { long l = gcmp(b,a); GEN z; if (!l) return gen_0; if (l < 0) swap(a,b); if (gcmpgs(b,100) >= 0) { if (gcmpgs(a,1) >= 0) z = qromi(E,eval,a,b,bit); else /* split at 1 */ z = gadd(rom_bsmall(E,eval,a,gen_1,bit), qromi(E,eval,gen_1,b,bit)); } else z = rom_bsmall(E,eval,a,b,bit); if (l < 0) z = gneg(z); return z; } GEN intnumromb_bitprec(void *E, GEN (*f)(void *, GEN), GEN a,GEN b, long fl, long B) { pari_sp av = avma; GEN z; switch(fl) { case 0: z = qrom3 (E, f, a, b, B); break; case 1: z = rombint(E, f, a, b, B); break; case 2: z = qromi (E, f, a, b, B); break; case 3: z = qrom2 (E, f, a, b, B); break; default: pari_err_FLAG("intnumromb"); return NULL; /* LCOV_EXCL_LINE */ } return gerepileupto(av, z); } GEN intnumromb(void *E, GEN (*f)(void *, GEN), GEN a, GEN b, long flag, long prec) { return intnumromb_bitprec(E,f,a,b,flag,prec2nbits(prec));} GEN intnumromb0_bitprec(GEN a, GEN b, GEN code, long flag, long bit) { EXPR_WRAP(code, intnumromb_bitprec(EXPR_ARG, a, b, flag, bit)); } /********************************************************************/ /** NUMERICAL INTEGRATION (Gauss-Legendre) **/ /********************************************************************/ GEN intnumgaussinit(long n, long prec) { pari_sp ltop = avma; GEN L, dp1, p1, p2, R, W; long prec0 = prec + EXTRAPRECWORD; long bitprec = prec2nbits(prec), i, d1; if (n <= 0) n = (long)(bitprec*0.2258); if (odd(n)) n++; if (n == 2) n = 4; /* n even >= 4, p1 is even */ prec = nbits2prec(3*bitprec/2 + 32); L = pollegendre(n, 0); /* L_n = p1(x^2) */ p1 = Q_remove_denom(RgX_deflate(L, 2), &dp1); d1 = vali(dp1); p2 = ZX_deriv(p1); /* L_n' = 2x p2(x^2) / 2^d1 */ R = ZX_Uspensky(p1, gen_0, 1, 3*bitprec/2 + 32); /* positive roots of p1 */ n >>= 1; W = cgetg(n+1, t_VEC); for (i = 1; i <= n; ++i) { GEN t, r2 = gel(R,i); if (typ(r2) != t_REAL) r2 = gtofp(r2, prec); gel(R,i) = sqrtr_abs(r2); /* positive root of L_n */ /* 2 / (L'(r)^2(1-r^2)) = 2^(2d1 - 1) / (1-r2)r2 (p2(r2))^2 */ t = mulrr(subrr(r2, sqrr(r2)), sqrr(poleval(p2, r2))); shiftr_inplace(t,1-2*d1); gel(W,i) = invr(t); } R = gprec_wtrunc(R,prec0); W = gprec_wtrunc(W,prec0); return gerepilecopy(ltop, mkvec2(R,W)); } GEN intnumgauss(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab, long prec) { pari_sp ltop = avma; GEN R, W, bma, bpa, S; long n, i, prec2 = prec + EXTRAPREC; if (!tab) tab = intnumgaussinit(0,prec); else if (typ(tab) != t_INT) { if (typ(tab) != t_VEC || lg(tab) != 3) pari_err_TYPE("intnumgauss",tab); } else tab = intnumgaussinit(itos(tab),prec); R = gel(tab,1); n = lg(R)-1; W = gel(tab,2); a = gprec_w(a, prec2); b = gprec_w(b, prec2); bma = gmul2n(gsub(b,a), -1); /* (b-a)/2 */ bpa = gadd(bma, a); /* (b+a)/2 */ S = gen_0; for (i = 1; i <= n; ++i) { GEN r = gel(R,i); GEN P = eval(E, gadd(bpa, gmul(bma, r))); GEN M = eval(E, gsub(bpa, gmul(bma, r))); S = gadd(S, gmul(gel(W,i), gadd(P,M))); S = gprec_wensure(S, prec2); } return gerepilecopy(ltop, gprec_wtrunc(gmul(bma,S), prec)); } GEN intnumgauss0(GEN a, GEN b, GEN code, GEN tab, long prec) { EXPR_WRAP(code, intnumgauss(EXPR_ARG, a, b, tab, prec)); } /********************************************************************/ /** DOUBLE EXPONENTIAL INTEGRATION **/ /********************************************************************/ typedef struct _intdata { long eps; /* bit accuracy of current precision */ long l; /* table lengths */ GEN tabx0; /* abscissa phi(0) for t = 0 */ GEN tabw0; /* weight phi'(0) for t = 0 */ GEN tabxp; /* table of abscissas phi(kh) for k > 0 */ GEN tabwp; /* table of weights phi'(kh) for k > 0 */ GEN tabxm; /* table of abscissas phi(kh) for k < 0, possibly empty */ GEN tabwm; /* table of weights phi'(kh) for k < 0, possibly empty */ GEN h; /* integration step */ } intdata; static const long LGTAB = 8; #define TABh(v) gel(v,1) #define TABx0(v) gel(v,2) #define TABw0(v) gel(v,3) #define TABxp(v) gel(v,4) #define TABwp(v) gel(v,5) #define TABxm(v) gel(v,6) #define TABwm(v) gel(v,7) static int isinR(GEN z) { return is_real_t(typ(z)); } static int isinC(GEN z) { return (typ(z) == t_COMPLEX)? isinR(gel(z,1)) && isinR(gel(z,2)): isinR(z); } static int checktabsimp(GEN tab) { long L, LN, LW; if (!tab || typ(tab) != t_VEC) return 0; if (lg(tab) != LGTAB) return 0; if (typ(TABxp(tab)) != t_VEC) return 0; if (typ(TABwp(tab)) != t_VEC) return 0; if (typ(TABxm(tab)) != t_VEC) return 0; if (typ(TABwm(tab)) != t_VEC) return 0; L = lg(TABxp(tab)); if (lg(TABwp(tab)) != L) return 0; LN = lg(TABxm(tab)); if (LN != 1 && LN != L) return 0; LW = lg(TABwm(tab)); if (LW != 1 && LW != L) return 0; return 1; } static int checktabdoub(GEN tab) { long L; if (typ(tab) != t_VEC) return 0; if (lg(tab) != LGTAB) return 0; L = lg(TABxp(tab)); if (lg(TABwp(tab)) != L) return 0; if (lg(TABxm(tab)) != L) return 0; if (lg(TABwm(tab)) != L) return 0; return 1; } static int checktab(GEN tab) { if (typ(tab) != t_VEC) return 0; if (lg(tab) != 3) return checktabsimp(tab); return checktabsimp(gel(tab,1)) && checktabsimp(gel(tab,2)); } /* the TUNE parameter is heuristic */ static void intinit_start(intdata *D, long m, double TUNE, long prec) { long l, n, bitprec = prec2nbits(prec); double d = bitprec*LOG10_2; GEN h, nh, pi = mppi(prec); n = (long)ceil(d*log(d) / TUNE); /* heuristic */ /* nh ~ log(2npi/log(n)) */ nh = logr_abs(divrr(mulur(2*n, pi), logr_abs(utor(n,prec)))); h = divru(nh, n); if (m > 0) { h = gmul2n(h,-m); n <<= m; } D->h = h; D->eps = bitprec; D->l = l = n+1; D->tabxp = cgetg(l, t_VEC); D->tabwp = cgetg(l, t_VEC); D->tabxm = cgetg(l, t_VEC); D->tabwm = cgetg(l, t_VEC); } static GEN intinit_end(intdata *D, long pnt, long mnt) { GEN v = cgetg(LGTAB, t_VEC); if (pnt < 0) pari_err_DOMAIN("intnuminit","table length","<",gen_0,stoi(pnt)); TABx0(v) = D->tabx0; TABw0(v) = D->tabw0; TABh(v) = D->h; TABxp(v) = D->tabxp; setlg(D->tabxp, pnt+1); TABwp(v) = D->tabwp; setlg(D->tabwp, pnt+1); TABxm(v) = D->tabxm; setlg(D->tabxm, mnt+1); TABwm(v) = D->tabwm; setlg(D->tabwm, mnt+1); return v; } /* divide by 2 in place */ static GEN divr2_ip(GEN x) { shiftr_inplace(x, -1); return x; } /* phi(t)=tanh((Pi/2)sinh(t)): from -1 to 1, hence also from a to b compact * interval */ static GEN inittanhsinh(long m, long prec) { GEN et, ex, pi = mppi(prec); long k, nt = -1; intdata D; intinit_start(&D, m, 1.86, prec); D.tabx0 = real_0(prec); D.tabw0 = Pi2n(-1,prec); et = ex = mpexp(D.h); for (k = 1; k < D.l; k++) { GEN xp, wp, ct, st, z; pari_sp av; gel(D.tabxp,k) = cgetr(prec); gel(D.tabwp,k) = cgetr(prec); av = avma; ct = divr2_ip(addrr(et, invr(et))); /* ch(kh) */ st = subrr(et, ct); /* sh(kh) */ z = invr( addrs(mpexp(mulrr(pi, st)), 1) ); shiftr_inplace(z, 1); xp = subsr(1, z); wp = divr2_ip(mulrr(mulrr(pi,ct), mulrr(z, subsr(2, z)))); if (expo(wp) < -D.eps) { nt = k-1; break; } affrr(xp, gel(D.tabxp,k)); if (absrnz_equal1(gel(D.tabxp,k))) { nt = k-1; break; } affrr(wp, gel(D.tabwp,k)); et = gerepileuptoleaf(av, mulrr(et, ex)); } return intinit_end(&D, nt, 0); } /* phi(t)=sinh(sinh(t)): from -oo to oo, slowly decreasing, at least * as 1/x^2. */ static GEN initsinhsinh(long m, long prec) { pari_sp av; GEN et, ct, st, ex; long k, nt = -1; intdata D; intinit_start(&D, m, 0.666, prec); D.tabx0 = real_0(prec); D.tabw0 = real_1(prec); et = ex = mpexp(D.h); for (k = 1; k < D.l; k++) { GEN xp, wp, ext, exu; gel(D.tabxp,k) = cgetr(prec); gel(D.tabwp,k) = cgetr(prec); av = avma; ct = divr2_ip(addrr(et, invr(et))); st = subrr(et, ct); ext = mpexp(st); exu = invr(ext); xp = divr2_ip(subrr(ext, exu)); wp = divr2_ip(mulrr(ct, addrr(ext, exu))); if (expo(wp) - 2*expo(xp) < -D.eps) { nt = k-1; break; } affrr(xp, gel(D.tabxp,k)); affrr(wp, gel(D.tabwp,k)); et = gerepileuptoleaf(av, mulrr(et, ex)); } return intinit_end(&D, nt, 0); } /* phi(t)=2sinh(t): from -oo to oo, exponentially decreasing as exp(-x) */ static GEN initsinh(long m, long prec) { pari_sp av; GEN et, ex, eti, xp, wp; long k, nt = -1; intdata D; intinit_start(&D, m, 1.0, prec); D.tabx0 = real_0(prec); D.tabw0 = real2n(1, prec); et = ex = mpexp(D.h); for (k = 1; k < D.l; k++) { gel(D.tabxp,k) = cgetr(prec); gel(D.tabwp,k) = cgetr(prec); av = avma; eti = invr(et); xp = subrr(et, eti); wp = addrr(et, eti); if (cmprs(xp, (long)(M_LN2*(expo(wp)+D.eps) + 1)) > 0) { nt = k-1; break; } affrr(xp, gel(D.tabxp,k)); affrr(wp, gel(D.tabwp,k)); et = gerepileuptoleaf(av, mulrr(et, ex)); } return intinit_end(&D, nt, 0); } /* phi(t)=exp(2sinh(t)): from 0 to oo, slowly decreasing at least as 1/x^2 */ static GEN initexpsinh(long m, long prec) { GEN et, ex; long k, nt = -1; intdata D; intinit_start(&D, m, 1.05, prec); D.tabx0 = real_1(prec); D.tabw0 = real2n(1, prec); ex = mpexp(D.h); et = real_1(prec); for (k = 1; k < D.l; k++) { GEN t, eti, xp; et = mulrr(et, ex); eti = invr(et); t = addrr(et, eti); xp = mpexp(subrr(et, eti)); gel(D.tabxp,k) = xp; gel(D.tabwp,k) = mulrr(xp, t); gel(D.tabxm,k) = invr(xp); gel(D.tabwm,k) = mulrr(gel(D.tabxm,k), t); if (expo(gel(D.tabxm,k)) < -D.eps) { nt = k-1; break; } } return intinit_end(&D, nt, nt); } /* phi(t)=exp(t-exp(-t)) : from 0 to +oo, exponentially decreasing. */ static GEN initexpexp(long m, long prec) { pari_sp av; GEN et, ex; long k, nt = -1; intdata D; intinit_start(&D, m, 1.76, prec); D.tabx0 = mpexp(real_m1(prec)); D.tabw0 = gmul2n(D.tabx0, 1); et = ex = mpexp(negr(D.h)); for (k = 1; k < D.l; k++) { GEN xp, xm, wp, wm, eti, kh; gel(D.tabxp,k) = cgetr(prec); gel(D.tabwp,k) = cgetr(prec); gel(D.tabxm,k) = cgetr(prec); gel(D.tabwm,k) = cgetr(prec); av = avma; eti = invr(et); kh = mulur(k,D.h); xp = mpexp(subrr(kh, et)); xm = mpexp(negr(addrr(kh, eti))); wp = mulrr(xp, addsr(1, et)); wm = mulrr(xm, addsr(1, eti)); if (expo(xm) < -D.eps && cmprs(xp, (long)(M_LN2*(expo(wp)+D.eps) + 1)) > 0) { nt = k-1; break; } affrr(xp, gel(D.tabxp,k)); affrr(wp, gel(D.tabwp,k)); affrr(xm, gel(D.tabxm,k)); affrr(wm, gel(D.tabwm,k)); et = gerepileuptoleaf(av, mulrr(et, ex)); } return intinit_end(&D, nt, nt); } /* phi(t)=(Pi/h)*t/(1-exp(-sinh(t))) from 0 to oo, sine oscillation */ static GEN initnumsine(long m, long prec) { pari_sp av; GEN invh, et, eti, ex, pi = mppi(prec); long exh, k, nt = -1; intdata D; intinit_start(&D, m, 0.666, prec); invh = invr(D.h); D.tabx0 = mulrr(pi, invh); D.tabw0 = gmul2n(D.tabx0,-1); exh = expo(invh); /* expo(1/h) */ et = ex = mpexp(D.h); for (k = 1; k < D.l; k++) { GEN xp,xm, wp,wm, ct,st, extp,extp1,extp2, extm,extm1,extm2, kct, kpi; gel(D.tabxp,k) = cgetr(prec); gel(D.tabwp,k) = cgetr(prec); gel(D.tabxm,k) = cgetr(prec); gel(D.tabwm,k) = cgetr(prec); av = avma; eti = invr(et); /* exp(-kh) */ ct = divr2_ip(addrr(et, eti)); /* ch(kh) */ st = divr2_ip(subrr(et, eti)); /* sh(kh) */ extp = mpexp(st); extp1 = subsr(1, extp); extp2 = invr(extp1); /* 1/(1-exp(sh(kh))) */ extm = invr(extp); extm1 = subsr(1, extm); extm2 = invr(extm1);/* 1/(1-exp(sh(-kh))) */ kpi = mulur(k, pi); kct = mulur(k, ct); extm1 = mulrr(extm1, invh); extp1 = mulrr(extp1, invh); xp = mulrr(kpi, extm2); /* phi(kh) */ wp = mulrr(subrr(extm1, mulrr(kct, extm)), mulrr(pi, sqrr(extm2))); xm = mulrr(negr(kpi), extp2); /* phi(-kh) */ wm = mulrr(addrr(extp1, mulrr(kct, extp)), mulrr(pi, sqrr(extp2))); if (expo(wm) < -D.eps && expo(extm) + exh + expu(10 * k) < -D.eps) { nt = k-1; break; } affrr(xp, gel(D.tabxp,k)); affrr(wp, gel(D.tabwp,k)); affrr(xm, gel(D.tabxm,k)); affrr(wm, gel(D.tabwm,k)); et = gerepileuptoleaf(av, mulrr(et, ex)); } return intinit_end(&D, nt, nt); } /* End of initialization functions. These functions can be executed once * and for all for a given accuracy and type of integral ([a,b], [a,oo[ or * ]-oo,a], ]-oo,oo[) */ /* The numbers below can be changed, but NOT the ordering */ enum { f_REG = 0, /* regular function */ f_SER = 1, /* power series */ f_SINGSER = 2, /* algebraic singularity, power series endpoint */ f_SING = 3, /* algebraic singularity */ f_YSLOW = 4, /* oo, slowly decreasing, at least x^(-2) */ f_YVSLO = 5, /* oo, very slowly decreasing, worse than x^(-2) */ f_YFAST = 6, /* oo, exponentially decreasing */ f_YOSCS = 7, /* oo, sine oscillating */ f_YOSCC = 8 /* oo, cosine oscillating */ }; /* is finite ? */ static int is_fin_f(long c) { return c == f_REG || c == f_SER || c == f_SING; } /* is oscillatory ? */ static int is_osc(long c) { long a = labs(c); return a == f_YOSCC|| a == f_YOSCS; } /* All inner functions such as intn, etc... must be called with a * valid 'tab' table. The wrapper intnum provides a higher level interface */ /* compute \int_a^b f(t)dt with [a,b] compact and f nonsingular. */ static GEN intn(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab) { GEN tabx0, tabw0, tabxp, tabwp; GEN bpa, bma, bmb, S; long i, prec; pari_sp ltop = avma, av; if (!checktabsimp(tab)) pari_err_TYPE("intnum",tab); tabx0 = TABx0(tab); tabw0 = TABw0(tab); prec = gprecision(tabw0); tabxp = TABxp(tab); tabwp = TABwp(tab); bpa = gmul2n(gadd(b, a), -1); /* (b+a)/2 */ bma = gsub(bpa, a); /* (b-a)/2 */ av = avma; bmb = gmul(bma, tabx0); /* (b-a)/2 phi(0) */ /* phi'(0) f( (b+a)/2 + (b-a)/2 * phi(0) ) */ S = gmul(tabw0, eval(E, gadd(bpa, bmb))); for (i = lg(tabxp)-1; i > 0; i--) { GEN SP, SM; bmb = gmul(bma, gel(tabxp,i)); SP = eval(E, gsub(bpa, bmb)); SM = eval(E, gadd(bpa, bmb)); S = gadd(S, gmul(gel(tabwp,i), gadd(SP, SM))); if ((i & 0x7f) == 1) S = gerepileupto(av, S); S = gprec_wensure(S, prec); } return gerepileupto(ltop, gmul(S, gmul(bma, TABh(tab)))); } /* compute \int_a^b f(t)dt with [a,b] compact, possible singularity with * exponent a[2] at lower extremity, b regular. Use tanh(sinh(t)). */ static GEN intnsing(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab) { GEN tabx0, tabw0, tabxp, tabwp, ea, ba, S; long i, prec; pari_sp ltop = avma, av; if (!checktabsimp(tab)) pari_err_TYPE("intnum",tab); tabx0 = TABx0(tab); tabw0 = TABw0(tab); prec = gprecision(tabw0); tabxp = TABxp(tab); tabwp = TABwp(tab); ea = ginv(gaddsg(1, gel(a,2))); a = gel(a,1); ba = gdiv(gsub(b, a), gpow(gen_2, ea, prec)); av = avma; S = gmul(gmul(tabw0, ba), eval(E, gadd(gmul(ba, addsr(1, tabx0)), a))); for (i = lg(tabxp)-1; i > 0; i--) { GEN p = addsr(1, gel(tabxp,i)); GEN m = subsr(1, gel(tabxp,i)); GEN bp = gmul(ba, gpow(p, ea, prec)); GEN bm = gmul(ba, gpow(m, ea, prec)); GEN SP = gmul(gdiv(bp, p), eval(E, gadd(bp, a))); GEN SM = gmul(gdiv(bm, m), eval(E, gadd(bm, a))); S = gadd(S, gmul(gel(tabwp,i), gadd(SP, SM))); if ((i & 0x7f) == 1) S = gerepileupto(av, S); S = gprec_wensure(S, prec); } return gerepileupto(ltop, gmul(gmul(S, TABh(tab)), ea)); } static GEN id(GEN x) { return x; } /* compute \int_a^oo f(t)dt if si>0 or \int_{-oo}^a f(t)dt if si<0$. * Use exp(2sinh(t)) for slowly decreasing functions, exp(1+t-exp(-t)) for * exponentially decreasing functions, and (pi/h)t/(1-exp(-sinh(t))) for * oscillating functions. */ static GEN intninfpm(void *E, GEN (*eval)(void*, GEN), GEN a, long sb, GEN tab) { GEN tabx0, tabw0, tabxp, tabwp, tabxm, tabwm; GEN S; long L, i, prec; pari_sp av = avma; if (!checktabdoub(tab)) pari_err_TYPE("intnum",tab); tabx0 = TABx0(tab); tabw0 = TABw0(tab); prec = gprecision(tabw0); tabxp = TABxp(tab); tabwp = TABwp(tab); L = lg(tabxp); tabxm = TABxm(tab); tabwm = TABwm(tab); if (gequal0(a)) { GEN (*NEG)(GEN) = sb > 0? id: gneg; S = gmul(tabw0, eval(E, NEG(tabx0))); for (i = 1; i < L; i++) { GEN SP = eval(E, NEG(gel(tabxp,i))); GEN SM = eval(E, NEG(gel(tabxm,i))); S = gadd(S, gadd(gmul(gel(tabwp,i), SP), gmul(gel(tabwm,i), SM))); if ((i & 0x7f) == 1) S = gerepileupto(av, S); S = gprec_wensure(S, prec); } } else if (gexpo(a) <= 0 || is_osc(sb)) { /* a small */ GEN (*ADD)(GEN,GEN) = sb > 0? gadd: gsub; S = gmul(tabw0, eval(E, ADD(a, tabx0))); for (i = 1; i < L; i++) { GEN SP = eval(E, ADD(a, gel(tabxp,i))); GEN SM = eval(E, ADD(a, gel(tabxm,i))); S = gadd(S, gadd(gmul(gel(tabwp,i), SP), gmul(gel(tabwm,i), SM))); if ((i & 0x7f) == 1) S = gerepileupto(av, S); S = gprec_wensure(S, prec); } } else { /* a large, |a|*\int_sgn(a)^{oo} f(|a|*x)dx (sb > 0)*/ GEN (*ADD)(long,GEN) = sb > 0? addsr: subsr; long sa = gsigne(a); GEN A = sa > 0? a: gneg(a); pari_sp av2 = avma; S = gmul(tabw0, eval(E, gmul(A, ADD(sa, tabx0)))); for (i = 1; i < L; i++) { GEN SP = eval(E, gmul(A, ADD(sa, gel(tabxp,i)))); GEN SM = eval(E, gmul(A, ADD(sa, gel(tabxm,i)))); S = gadd(S, gadd(gmul(gel(tabwp,i), SP), gmul(gel(tabwm,i), SM))); if ((i & 0x7f) == 1) S = gerepileupto(av2, S); S = gprec_wensure(S, prec); } S = gmul(S,A); } return gerepileupto(av, gmul(S, TABh(tab))); } /* Compute \int_{-oo}^oo f(t)dt * use sinh(sinh(t)) for slowly decreasing functions and sinh(t) for * exponentially decreasing functions. * HACK: in case TABwm(tab) contains something, assume function to be integrated * satisfies f(-x) = conj(f(x)). */ static GEN intninfinf(void *E, GEN (*eval)(void*, GEN), GEN tab) { GEN tabx0, tabw0, tabxp, tabwp, tabwm; GEN S; long L, i, prec, spf; pari_sp ltop = avma; if (!checktabsimp(tab)) pari_err_TYPE("intnum",tab); tabx0 = TABx0(tab); tabw0 = TABw0(tab); prec = gprecision(tabw0); tabxp = TABxp(tab); tabwp = TABwp(tab); L = lg(tabxp); tabwm = TABwm(tab); spf = (lg(tabwm) == lg(tabwp)); S = gmul(tabw0, eval(E, tabx0)); if (spf) S = gmul2n(real_i(S), -1); for (i = L-1; i > 0; i--) { GEN SP = eval(E, gel(tabxp,i)); if (spf) S = gadd(S, real_i(gmul(gel(tabwp,i), SP))); else { GEN SM = eval(E, negr(gel(tabxp,i))); S = gadd(S, gmul(gel(tabwp,i), gadd(SP,SM))); } if ((i & 0x7f) == 1) S = gerepileupto(ltop, S); S = gprec_wensure(S, prec); } if (spf) S = gmul2n(S,1); return gerepileupto(ltop, gmul(S, TABh(tab))); } /* general num integration routine int_a^b f(t)dt, where a and b are as follows: - a scalar : the scalar, no singularity worse than logarithmic at a. - [a, e] : the scalar a, singularity exponent -1 < e <= 0. - +oo: slowly decreasing function (at least O(t^-2)) - [[+oo], a], a nonnegative real : +oo, function behaving like exp(-a|t|) - [[+oo], e], e < -1 : +oo, function behaving like t^e - [[+oo], a*I], a > 0 real : +oo, function behaving like cos(at) - [[+oo], a*I], a < 0 real : +oo, function behaving like sin(at) and similarly at -oo */ static GEN f_getycplx(GEN a, long prec) { long s; GEN tmp, a2R, a2I; if (lg(a) == 2 || gequal0(gel(a,2))) return gen_1; a2R = real_i(gel(a,2)); a2I = imag_i(gel(a,2)); s = gsigne(a2I); if (s < 0) a2I = gneg(a2I); tmp = s ? ginv(a2I) : ginv(a2R); if (gprecision(tmp) < prec) tmp = gprec_w(tmp, prec); return tmp; } static void err_code(GEN a, const char *name) { char *s = stack_sprintf("intnum [incorrect %s]", name); pari_err_TYPE(s, a); } /* a = [[+/-oo], alpha]*/ static long code_aux(GEN a, const char *name) { GEN re, im, alpha = gel(a,2); long s; if (!isinC(alpha)) err_code(a, name); re = real_i(alpha); im = imag_i(alpha); s = gsigne(im); if (s) { if (!gequal0(re)) err_code(a, name); return s > 0 ? f_YOSCC : f_YOSCS; } if (gequal0(re) || gcmpgs(re, -2)<=0) return f_YSLOW; if (gsigne(re) > 0) return f_YFAST; if (gcmpgs(re, -1) >= 0) err_code(a, name); return f_YVSLO; } static long transcode(GEN a, const char *name) { GEN a1, a2; switch(typ(a)) { case t_VEC: break; case t_INFINITY: return inf_get_sign(a) == 1 ? f_YSLOW: -f_YSLOW; case t_SER: case t_POL: case t_RFRAC: return f_SER; default: if (!isinC(a)) err_code(a,name); return f_REG; } switch(lg(a)) { case 2: return gsigne(gel(a,1)) > 0 ? f_YSLOW : -f_YSLOW; case 3: break; default: err_code(a,name); } a1 = gel(a,1); a2 = gel(a,2); switch(typ(a1)) { case t_VEC: if (lg(a1) != 2) err_code(a,name); return gsigne(gel(a1,1)) * code_aux(a, name); case t_INFINITY: return inf_get_sign(a1) * code_aux(a, name); case t_SER: case t_POL: case t_RFRAC: if (!isinR(a2)) err_code(a,name); if (gcmpgs(a2, -1) <= 0) pari_err_IMPL("intnum with diverging non constant limit"); return gsigne(a2) < 0 ? f_SINGSER : f_SER; default: if (!isinC(a1) || !isinR(a2) || gcmpgs(a2, -1) <= 0) err_code(a,name); return gsigne(a2) < 0 ? f_SING : f_REG; } } /* computes the necessary tabs, knowing a, b and m */ static GEN homtab(GEN tab, GEN k) { GEN z; if (gequal0(k) || gequal(k, gen_1)) return tab; if (gsigne(k) < 0) k = gneg(k); z = cgetg(LGTAB, t_VEC); TABx0(z) = gmul(TABx0(tab), k); TABw0(z) = gmul(TABw0(tab), k); TABxp(z) = gmul(TABxp(tab), k); TABwp(z) = gmul(TABwp(tab), k); TABxm(z) = gmul(TABxm(tab), k); TABwm(z) = gmul(TABwm(tab), k); TABh(z) = rcopy(TABh(tab)); return z; } static GEN expvec(GEN v, GEN ea, long prec) { long lv = lg(v), i; GEN z = cgetg(lv, t_VEC); for (i = 1; i < lv; i++) gel(z,i) = gpow(gel(v,i),ea,prec); return z; } static GEN expscalpr(GEN vnew, GEN xold, GEN wold, GEN ea) { pari_sp av = avma; return gerepileupto(av, gdiv(gmul(gmul(vnew, wold), ea), xold)); } static GEN expvecpr(GEN vnew, GEN xold, GEN wold, GEN ea) { long lv = lg(vnew), i; GEN z = cgetg(lv, t_VEC); for (i = 1; i < lv; i++) gel(z,i) = expscalpr(gel(vnew,i), gel(xold,i), gel(wold,i), ea); return z; } /* here k < -1 */ static GEN exptab(GEN tab, GEN k, long prec) { GEN v, ea; if (gcmpgs(k, -2) <= 0) return tab; ea = ginv(gsubsg(-1, k)); v = cgetg(LGTAB, t_VEC); TABx0(v) = gpow(TABx0(tab), ea, prec); TABw0(v) = expscalpr(TABx0(v), TABx0(tab), TABw0(tab), ea); TABxp(v) = expvec(TABxp(tab), ea, prec); TABwp(v) = expvecpr(TABxp(v), TABxp(tab), TABwp(tab), ea); TABxm(v) = expvec(TABxm(tab), ea, prec); TABwm(v) = expvecpr(TABxm(v), TABxm(tab), TABwm(tab), ea); TABh(v) = rcopy(TABh(tab)); return v; } static GEN init_fin(GEN b, long codeb, long m, long l, long prec) { switch(labs(codeb)) { case f_REG: case f_SING: return inittanhsinh(m,l); case f_YSLOW: return initexpsinh(m,l); case f_YVSLO: return exptab(initexpsinh(m,l), gel(b,2), prec); case f_YFAST: return homtab(initexpexp(m,l), f_getycplx(b,l)); /* f_YOSCS, f_YOSCC */ default: return homtab(initnumsine(m,l),f_getycplx(b,l)); } } static GEN intnuminit_i(GEN a, GEN b, long m, long prec) { long codea, codeb, l; GEN T, kma, kmb, tmp; if (m > 30) pari_err_OVERFLOW("intnuminit [m]"); if (m < 0) pari_err_DOMAIN("intnuminit", "m", "<", gen_0, stoi(m)); l = prec+EXTRAPREC; codea = transcode(a, "a"); if (codea == f_SER) codea = f_REG; codeb = transcode(b, "b"); if (codeb == f_SER) codeb = f_REG; if (codea == f_SINGSER || codeb == f_SINGSER) pari_err_IMPL("intnuminit with singularity at non constant limit"); if (labs(codea) > labs(codeb)) { swap(a, b); lswap(codea, codeb); } if (codea == f_REG) { T = init_fin(b, codeb, m,l,prec); switch(labs(codeb)) { case f_YOSCS: if (gequal0(a)) break; case f_YOSCC: T = mkvec2(inittanhsinh(m,l), T); } return T; } if (codea == f_SING) { T = init_fin(b,codeb, m,l,prec); T = mkvec2(labs(codeb) == f_SING? T: inittanhsinh(m,l), T); return T; } /* now a and b are infinite */ if (codea * codeb > 0) return gen_0; kma = f_getycplx(a,l); codea = labs(codea); kmb = f_getycplx(b,l); codeb = labs(codeb); if (codea == f_YSLOW && codeb == f_YSLOW) return initsinhsinh(m, l); if (codea == f_YFAST && codeb == f_YFAST && gequal(kma, kmb)) return homtab(initsinh(m,l), kmb); T = cgetg(3, t_VEC); switch (codea) { case f_YSLOW: case f_YVSLO: tmp = initexpsinh(m,l); gel(T,1) = codea == f_YSLOW? tmp: exptab(tmp, gel(a,2), prec); switch (codeb) { case f_YVSLO: gel(T,2) = exptab(tmp, gel(b,2), prec); return T; case f_YFAST: gel(T,2) = homtab(initexpexp(m,l), kmb); return T; /* YOSC[CS] */ default: gel(T,2) = homtab(initnumsine(m,l), kmb); return T; } break; case f_YFAST: tmp = initexpexp(m, l); gel(T,1) = homtab(tmp, kma); switch (codeb) { case f_YFAST: gel(T,2) = homtab(tmp, kmb); return T; /* YOSC[CS] */ default: gel(T,2) = homtab(initnumsine(m, l), kmb); return T; } default: /* YOSC[CS] */ tmp = initnumsine(m, l); gel(T,1) = homtab(tmp,kma); if (codea == f_YOSCC && codeb == f_YOSCC && !gequal(kma, kmb)) gel(T,2) = mkvec2(inittanhsinh(m,l), homtab(tmp,kmb)); else gel(T,2) = homtab(tmp,kmb); return T; } } GEN intnuminit(GEN a, GEN b, long m, long prec) { pari_sp av = avma; return gerepilecopy(av, intnuminit_i(a,b,m,prec)); } static GEN intnuminit0(GEN a, GEN b, GEN tab, long prec) { long m; if (!tab) m = 0; else if (typ(tab) != t_INT) { if (!checktab(tab)) pari_err_TYPE("intnuminit0",tab); return tab; } else m = itos(tab); return intnuminit(a, b, m, prec); } /* Assigns the values of the function weighted by w[k] at quadrature points x[k] * [replacing the weights]. Return the index of the last non-zero coeff */ static long weight(void *E, GEN (*eval)(void *, GEN), GEN x, GEN w) { long k, l = lg(x); for (k = 1; k < l; k++) gel(w,k) = gmul(gel(w,k), eval(E, gel(x,k))); k--; while (k >= 1) if (!gequal0(gel(w,k--))) break; return k; } /* compute the necessary tabs, weights multiplied by f(t) */ static GEN intfuncinit_i(void *E, GEN (*eval)(void*, GEN), GEN tab) { GEN tabxp = TABxp(tab), tabwp = TABwp(tab); GEN tabxm = TABxm(tab), tabwm = TABwm(tab); long L, L0 = lg(tabxp); TABw0(tab) = gmul(TABw0(tab), eval(E, TABx0(tab))); if (lg(tabxm) == 1) { TABxm(tab) = tabxm = gneg(tabxp); TABwm(tab) = tabwm = leafcopy(tabwp); } /* update wp and wm in place */ L = minss(weight(E, eval, tabxp, tabwp), weight(E, eval, tabxm, tabwm)); if (L < L0) { /* catch up functions whose growth at oo was not adequately described */ setlg(tabxp, L+1); setlg(tabwp, L+1); if (lg(tabxm) > 1) { setlg(tabxm, L+1); setlg(tabwm, L+1); } } return tab; } GEN intfuncinit(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long m, long prec) { pari_sp av = avma; GEN tab = intnuminit_i(a, b, m, prec); if (lg(tab) == 3) pari_err_IMPL("intfuncinit with hard endpoint behavior"); if (is_fin_f(transcode(a,"intfuncinit")) || is_fin_f(transcode(b,"intfuncinit"))) pari_err_IMPL("intfuncinit with finite endpoints"); return gerepilecopy(av, intfuncinit_i(E, eval, tab)); } static GEN intnum_i(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab, long prec) { GEN S = gen_0, res1, res2, kma, kmb; long sb, sgns = 1, codea = transcode(a, "a"), codeb = transcode(b, "b"); if (codea == f_REG && typ(a) == t_VEC) a = gel(a,1); if (codeb == f_REG && typ(b) == t_VEC) b = gel(b,1); if (codea == f_REG && codeb == f_REG) return intn(E, eval, a, b, tab); if (codea == f_SER || codeb == f_SER) return intlin(E, eval, a, b, tab, prec); if (labs(codea) > labs(codeb)) { swap(a,b); lswap(codea,codeb); sgns = -1; } /* now labs(codea) <= labs(codeb) */ if (codeb == f_SING) { if (codea == f_REG) S = intnsing(E, eval, b, a, tab), sgns = -sgns; else { GEN c = gmul2n(gadd(gel(a,1), gel(b,1)), -1); res1 = intnsing(E, eval, a, c, gel(tab,1)); res2 = intnsing(E, eval, b, c, gel(tab,2)); S = gsub(res1, res2); } return (sgns < 0) ? gneg(S) : S; } /* now b is infinite */ sb = codeb > 0 ? 1 : -1; codeb = labs(codeb); if (codea == f_REG && codeb != f_YOSCC && (codeb != f_YOSCS || gequal0(a))) { S = intninfpm(E, eval, a, sb*codeb, tab); return sgns*sb < 0 ? gneg(S) : S; } if (is_fin_f(codea)) { /* either codea == f_SING or codea == f_REG and codeb = f_YOSCC * or (codeb == f_YOSCS and !gequal0(a)) */ GEN c = real_i(codea == f_SING? gel(a,1): a); switch(codeb) { case f_YOSCC: case f_YOSCS: { GEN pi2p = gmul(Pi2n(1,prec), f_getycplx(b, prec)); GEN pis2p = gmul2n(pi2p, -2); if (codeb == f_YOSCC) c = gadd(c, pis2p); c = gdiv(c, pi2p); c = sb > 0? addiu(gceil(c), 1): subiu(gfloor(c), 1); c = gmul(pi2p, c); if (codeb == f_YOSCC) c = gsub(c, pis2p); break; } default: c = sb > 0? addiu(gceil(c), 1): subiu(gfloor(c), 1); break; } res1 = codea==f_SING? intnsing(E, eval, a, c, gel(tab,1)) : intn (E, eval, a, c, gel(tab,1)); res2 = intninfpm(E, eval, c, sb*codeb, gel(tab,2)); if (sb < 0) res2 = gneg(res2); res1 = gadd(res1, res2); return sgns < 0 ? gneg(res1) : res1; } /* now a and b are infinite */ if (codea * sb > 0) { if (codea > 0) pari_warn(warner, "integral from oo to oo"); if (codea < 0) pari_warn(warner, "integral from -oo to -oo"); return gen_0; } if (sb < 0) sgns = -sgns; codea = labs(codea); kma = f_getycplx(a, prec); kmb = f_getycplx(b, prec); if ((codea == f_YSLOW && codeb == f_YSLOW) || (codea == f_YFAST && codeb == f_YFAST && gequal(kma, kmb))) S = intninfinf(E, eval, tab); else { GEN pis2 = Pi2n(-1, prec); GEN ca = (codea == f_YOSCC)? gmul(pis2, kma): gen_0; GEN cb = (codeb == f_YOSCC)? gmul(pis2, kmb): gen_0; GEN c = codea == f_YOSCC ? ca : cb; /*signe(a)=-sb*/ GEN SP, SN = intninfpm(E, eval, c, -sb*codea, gel(tab,1)); if (codea != f_YOSCC) SP = intninfpm(E, eval, cb, sb*codeb, gel(tab,2)); /* codea = codeb = f_YOSCC */ else if (gequal(kma, kmb)) SP = intninfpm(E, eval, cb, sb*codeb, gel(tab,2)); else { tab = gel(tab,2); SP = intninfpm(E, eval, cb, sb*codeb, gel(tab,2)); SP = gadd(SP, intn(E, eval, ca, cb, gel(tab,1))); } S = gadd(SN, SP); } if (sgns < 0) S = gneg(S); return S; } GEN intnum(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab, long prec) { pari_sp ltop = avma; long l = prec+EXTRAPREC; GEN na = NULL, nb = NULL, S; if (transcode(a,"a") == f_SINGSER) { long v = gvar(gel(a,1)); if (v != NO_VARIABLE) { na = cgetg(3,t_VEC); gel(na,1) = polcoeff0(gel(a,1),0,v); gel(na,2) = gel(a,2); } a = gel(a,1); } if (transcode(b,"b") == f_SINGSER) { long v = gvar(gel(b,1)); if (v != NO_VARIABLE) { nb = cgetg(3,t_VEC); gel(nb,1) = polcoeff0(gel(b,1),0,v); gel(nb,2) = gel(b,2); } b = gel(b,1); } if (na || nb) { if (tab && typ(tab) != t_INT) pari_err_IMPL("non integer tab argument"); S = intnum(E, eval, na ? na : a, nb ? nb : b, tab, prec); if (na) S = gsub(S, intnum(E, eval, na, a, tab, prec)); if (nb) S = gsub(S, intnum(E, eval, b, nb, tab, prec)); return gerepilecopy(ltop, S); } tab = intnuminit0(a, b, tab, prec); S = intnum_i(E, eval, gprec_w(a, l), gprec_w(b, l), tab, prec); return gerepilecopy(ltop, gprec_wtrunc(S, prec)); } typedef struct auxint_s { GEN a, R, mult; GEN (*f)(void*, GEN); GEN (*w)(GEN, long); long prec; void *E; } auxint_t; static GEN auxcirc(void *E, GEN t) { auxint_t *D = (auxint_t*) E; GEN s, c, z; mpsincos(mulrr(t, D->mult), &s, &c); z = mkcomplex(c,s); return gmul(z, D->f(D->E, gadd(D->a, gmul(D->R, z)))); } GEN intcirc(void *E, GEN (*eval)(void*, GEN), GEN a, GEN R, GEN tab, long prec) { auxint_t D; GEN z; D.a = a; D.R = R; D.mult = mppi(prec); D.f = eval; D.E = E; z = intnum(&D, &auxcirc, real_m1(prec), real_1(prec), tab, prec); return gmul2n(gmul(R, z), -1); } static GEN auxlin(void *E, GEN t) { auxint_t *D = (auxint_t*) E; return D->f(D->E, gadd(D->a, gmul(D->mult, t))); } static GEN intlin(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab, long prec) { auxint_t D; GEN z; if (typ(a) == t_VEC) a = gel(a,1); if (typ(b) == t_VEC) b = gel(b,1); z = toser_i(a); if (z) a = z; z = toser_i(b); if (z) b = z; D.a = a; D.mult = gsub(b,a); D.f = eval; D.E = E; z = intnum(&D, &auxlin, real_0(prec), real_1(prec), tab, prec); return gmul(D.mult, z); } GEN intnum0(GEN a, GEN b, GEN code, GEN tab, long prec) { EXPR_WRAP(code, intnum(EXPR_ARG, a, b, tab, prec)); } GEN intcirc0(GEN a, GEN R, GEN code, GEN tab, long prec) { EXPR_WRAP(code, intcirc(EXPR_ARG, a, R, tab, prec)); } GEN intfuncinit0(GEN a, GEN b, GEN code, long m, long prec) { EXPR_WRAP(code, intfuncinit(EXPR_ARG, a, b, m, prec)); } #if 0 /* Two variable integration */ typedef struct auxf_s { GEN x; GEN (*f)(void *, GEN, GEN); void *E; } auxf_t; typedef struct indi_s { GEN (*c)(void*, GEN); GEN (*d)(void*, GEN); GEN (*f)(void *, GEN, GEN); void *Ec; void *Ed; void *Ef; GEN tabintern; long prec; } indi_t; static GEN auxf(GEN y, void *E) { auxf_t *D = (auxf_t*) E; return D->f(D->E, D->x, y); } static GEN intnumdoubintern(GEN x, void *E) { indi_t *D = (indi_t*) E; GEN c = D->c(x, D->Ec), d = D->d(x, D->Ed); auxf_t A; A.x = x; A.f = D->f; A.E = D->Ef; return intnum(&A, &auxf, c, d, D->tabintern, D->prec); } GEN intnumdoub(void *Ef, GEN (*evalf)(void *, GEN, GEN), void *Ec, GEN (*evalc)(void*, GEN), void *Ed, GEN (*evald)(void*, GEN), GEN a, GEN b, GEN tabext, GEN tabint, long prec) { indi_t E; E.c = evalc; E.d = evald; E.f = evalf; E.Ec = Ec; E.Ed = Ed; E.Ef = Ef; E.prec = prec; if (typ(tabint) == t_INT) { GEN C = evalc(a, Ec), D = evald(a, Ed); if (typ(C) != t_VEC && typ(D) != t_VEC) { C = gen_0; D = gen_1; } E.tabintern = intnuminit0(C, D, tabint, prec); } else E.tabintern = tabint; return intnum(&E, &intnumdoubintern, a, b, tabext, prec); } GEN intnumdoub0(GEN a, GEN b, int nc, int nd, int nf, GEN tabext, GEN tabint, long prec) { GEN z; push_lex(NULL); push_lex(NULL); z = intnumdoub(chf, &gp_eval2, chc, &gp_eval, chd, &gp_eval, a, b, tabext, tabint, prec); pop_lex(1); pop_lex(1); return z; } #endif /* The quotient-difference algorithm. Given a vector M, convert the series * S = \sum_{n >= 0} M[n+1]z^n into a continued fraction. * Compute the c[n] such that * S = c[1] / (1 + c[2]z / (1+c[3]z/(1+...c[lim]z))), * Compute A[n] and B[n] such that * S = M[1]/ (1+A[1]*z+B[1]*z^2 / (1+A[2]*z+B[2]*z^2/ (1+...1/(1+A[lim\2]*z)))), * Assume lim <= #M. * Does not work for certain M. */ /* Given a continued fraction CF output by the quodif program, convert it into an Euler continued fraction A(n), B(n), where $1/(1+c[2]z/(1+c[3]z/(1+..c[lim]z))) =1/(1+A[1]*z+B[1]*z^2/(1+A[2]*z+B[2]*z^2/(1+...1/(1+A[lim\2]*z)))). */ static GEN contfrac_Euler(GEN CF) { long lima, limb, i, lim = lg(CF)-1; GEN A, B; lima = lim/2; limb = (lim - 1)/2; A = cgetg(lima+1, t_VEC); B = cgetg(limb+1, t_VEC); gel (A, 1) = gel(CF, 2); for (i=2; i <= lima; ++i) gel(A,i) = gadd(gel(CF, 2*i), gel(CF, 2*i-1)); for (i=1; i <= limb; ++i) gel(B,i) = gneg(gmul(gel(CF, 2*i+1), gel(CF, 2*i))); return mkvec2(A, B); } static GEN contfracinit_i(GEN M, long lim) { pari_sp av; GEN e, q, c; long lim2; long j, k; e = zerovec(lim); c = zerovec(lim+1); gel(c, 1) = gel(M, 1); q = cgetg(lim+1, t_VEC); for (k = 1; k <= lim; ++k) gel(q, k) = gdiv(gel(M, k+1), gel(M, k)); lim2 = lim/2; av = avma; for (j = 1; j <= lim2; ++j) { long l = lim - 2*j; gel(c, 2*j) = gneg(gel(q, 1)); for (k = 0; k <= l; ++k) gel(e, k+1) = gsub(gadd(gel(e, k+2), gel(q, k+2)), gel(q, k+1)); for (k = 0; k < l; ++k) gel(q, k+1) = gdiv(gmul(gel(q, k+2), gel(e, k+2)), gel(e, k+1)); gel(c, 2*j+1) = gneg(gel(e, 1)); if (gc_needed(av, 3)) { if (DEBUGMEM>1) pari_warn(warnmem,"contfracinit, %ld/%ld",j,lim2); gerepileall(av, 3, &e, &c, &q); } } if (odd(lim)) gel(c, lim+1) = gneg(gel(q, 1)); return c; } GEN contfracinit(GEN M, long lim) { pari_sp ltop = avma; GEN c; switch(typ(M)) { case t_RFRAC: if (lim < 0) pari_err_TYPE("contfracinit",M); M = gadd(M, zeroser(gvar(M), lim + 2)); /*fall through*/ case t_SER: M = gtovec(M); break; case t_POL: M = gtovecrev(M); break; case t_VEC: case t_COL: break; default: pari_err_TYPE("contfracinit", M); } if (lim < 0) lim = lg(M)-2; else if (lg(M)-1 <= lim) pari_err_COMPONENT("contfracinit", "<", stoi(lg(M)-1), stoi(lim)); if (lim < 0) retmkvec2(cgetg(1,t_VEC),cgetg(1,t_VEC)); c = contfracinit_i(M, lim); return gerepilecopy(ltop, contfrac_Euler(c)); } /* Evaluate at 1/tinv the nlim first terms of the continued fraction output by * contfracinit. */ /* Not stack clean */ GEN contfraceval_inv(GEN CF, GEN tinv, long nlim) { pari_sp btop; long j; GEN S = gen_0, S1, S2, A, B; if (typ(CF) != t_VEC || lg(CF) != 3) pari_err_TYPE("contfraceval", CF); A = gel(CF, 1); if (typ(A) != t_VEC) pari_err_TYPE("contfraceval", CF); B = gel(CF, 2); if (typ(B) != t_VEC) pari_err_TYPE("contfraceval", CF); if (nlim < 0) nlim = lg(A)-1; else if (lg(A) <= nlim) pari_err_COMPONENT("contfraceval", ">", stoi(lg(A)-1), stoi(nlim)); if (lg(B)+1 <= nlim) pari_err_COMPONENT("contfraceval", ">", stoi(lg(B)), stoi(nlim)); btop = avma; if (nlim <= 1) return lg(A)==1? gen_0: gdiv(tinv, gadd(gel(A, 1), tinv)); switch(nlim % 3) { case 2: S = gdiv(gel(B, nlim-1), gadd(gel(A, nlim), tinv)); nlim--; break; case 0: S1 = gadd(gel(A, nlim), tinv); S2 = gadd(gmul(gadd(gel(A, nlim-1), tinv), S1), gel(B, nlim-1)); S = gdiv(gmul(gel(B, nlim-2), S1), S2); nlim -= 2; break; } /* nlim = 1 (mod 3) */ for (j = nlim; j >= 4; j -= 3) { GEN S3; S1 = gadd(gadd(gel(A, j), tinv), S); S2 = gadd(gmul(gadd(gel(A, j-1), tinv), S1), gel(B, j-1)); S3 = gadd(gmul(gadd(gel(A, j-2), tinv), S2), gmul(gel(B, j-2), S1)); S = gdiv(gmul(gel(B, j-3), S2), S3); if (gc_needed(btop, 3)) S = gerepilecopy(btop, S); } return gdiv(tinv, gadd(gadd(gel(A, 1), tinv), S)); } GEN contfraceval(GEN CF, GEN t, long nlim) { pari_sp ltop = avma; return gerepileupto(ltop, contfraceval_inv(CF, ginv(t), nlim)); } /* MONIEN SUMMATION */ /* basic Newton, find x ~ z such that Q(x) = 0 */ static GEN monrefine(GEN Q, GEN QP, GEN z, long prec) { pari_sp av = avma; GEN pr = poleval(Q, z); for(;;) { GEN prnew; z = gsub(z, gdiv(pr, poleval(QP, z))); prnew = poleval(Q, z); if (gcmp(gabs(prnew, prec), gabs(pr, prec)) >= 0) break; pr = prnew; } z = gprec_w(z, 2*prec-2); z = gsub(z, gdiv(poleval(Q, z), poleval(QP, z))); return gerepileupto(av, z); } static GEN RX_realroots(GEN x, long prec) { return realroots(gprec_wtrunc(x,prec), NULL, prec); } /* (real) roots of Q, assuming QP = Q' and that half the roots are close to * k+1, ..., k+m, m = deg(Q)/2-1. N.B. All roots are real and >= 1 */ static GEN monroots(GEN Q, GEN QP, long k, long prec) { long j, n = degpol(Q), m = n/2 - 1; GEN v2, v1 = cgetg(m+1, t_VEC); for (j = 1; j <= m; ++j) gel(v1, j) = monrefine(Q, QP, stoi(k+j), prec); Q = gdivent(Q, roots_to_pol(v1, varn(Q))); v2 = RX_realroots(Q, prec); settyp(v2, t_VEC); return shallowconcat(v1, v2); } static void Pade(GEN M, GEN *pP, GEN *pQ) { pari_sp av = avma; long n = lg(M)-2, i; GEN v = contfracinit_i(M, n), P = pol_0(0), Q = pol_1(0); /* evaluate continued fraction => Pade approximants */ for (i = n-1; i >= 1; i--) { /* S = P/Q: S -> v[i]*x / (1+S) */ GEN R = RgX_shift_shallow(RgX_Rg_mul(Q,gel(v,i)), 1); Q = RgX_add(P,Q); P = R; if (gc_needed(av, 3)) { if (DEBUGMEM>1) pari_warn(warnmem,"Pade, %ld/%ld",i,n-1); gerepileall(av, 3, &P, &Q, &v); } } /* S -> 1+S */ *pP = RgX_add(P,Q); *pQ = Q; } static GEN veczetaprime(GEN a, GEN b, long N, long prec) { long newprec, fpr = prec2nbits(prec), pr = (long)ceil(fpr * 1.5); long l = nbits2prec(pr), e = fpr / 2; GEN eps, A, B; newprec = nbits2prec(pr + BITS_IN_LONG); a = gprec_w(a, newprec); b = gprec_w(b, newprec); eps = real2n(-e, l); A = veczeta(a, gsub(b, eps), N, newprec); B = veczeta(a, gadd(b, eps), N, newprec); return gmul2n(RgV_sub(B, A), e-1); } struct mon_w { GEN w, a, b; long n, j, prec; }; /* w(x) / x^(a*(j+k)+b), k >= 1; w a t_CLOSURE or t_INT [encodes log(x)^w] */ static GEN wrapmonw(void* E, GEN x) { struct mon_w *W = (struct mon_w*)E; long k, j = W->j, n = W->n, prec = W->prec, l = 2*n+4-j; GEN wx = typ(W->w) == t_CLOSURE? closure_callgen1prec(W->w, x, prec) : powgi(glog(x, prec), W->w); GEN v = cgetg(l, t_VEC); GEN xa = gpow(x, gneg(W->a), prec), w = gmul(wx, gpowgs(xa, j)); w = gdiv(w, gpow(x,W->b,prec)); for (k = 1; k < l; k++) { gel(v,k) = w; w = gmul(w, xa); } return v; } /* w(x) / x^(a*j+b) */ static GEN wrapmonw2(void* E, GEN x) { struct mon_w *W = (struct mon_w*)E; GEN wnx = closure_callgen1prec(W->w, x, W->prec); return gdiv(wnx, gpow(x, gadd(gmulgs(W->a, W->j), W->b), W->prec)); } static GEN M_from_wrapmon(struct mon_w *S, GEN wfast, GEN n0) { long j, N = 2*S->n+2; GEN M = cgetg(N+1, t_VEC), faj = gsub(wfast, S->b); for (j = 1; j <= N; j++) { faj = gsub(faj, S->a); if (gcmpgs(faj, -2) <= 0) { S->j = j; setlg(M,j); M = shallowconcat(M, sumnum((void*)S, wrapmonw, n0, NULL, S->prec)); break; } S->j = j; gel(M,j) = sumnum((void*)S, wrapmonw2, mkvec2(n0,faj), NULL, S->prec); } return M; } static void checkmonroots(GEN vr, long n) { if (lg(vr) != n+1) pari_err_IMPL("recovery when missing roots in sumnummonieninit"); } static GEN sumnummonieninit_i(GEN a, GEN b, GEN w, GEN n0, long prec) { GEN c, M, P, Q, Qp, vr, vabs, vwt, ga = gadd(a, b); double bit = 2*prec2nbits(prec) / gtodouble(ga), D = bit*M_LN2; double da = maxdd(1., gtodouble(a)); long n = (long)ceil(D / (da*(log(D)-1))); long j, prec2, prec0 = prec + EXTRAPRECWORD; double bit0 = ceil((2*n+1)*LOG2_10); int neg = 1; struct mon_w S; /* 2.05 is heuristic; with 2.03, sumnummonien(n=1,1/n^2) loses * 19 decimals at \p1500 */ prec = nbits2prec(maxdd(2.05*da*bit, bit0)); prec2 = nbits2prec(maxdd(1.3*da*bit, bit0)); S.w = w; S.a = a = gprec_w(a, 2*prec-2); S.b = b = gprec_w(b, 2*prec-2); S.n = n; S.j = 1; S.prec = prec; if (typ(w) == t_INT) { /* f(n) ~ \sum_{i > 0} f_i log(n)^k / n^(a*i + b); a > 0, a+b > 1 */ long k = itos(w); if (k == 0) M = veczeta(a, ga, 2*n+2, prec); else if (k == 1) M = veczetaprime(a, ga, 2*n+2, prec); else M = M_from_wrapmon(&S, gen_0, gen_1); if (odd(k)) neg = 0; } else { GEN wfast = gen_0; if (typ(w) == t_VEC) { wfast = gel(w,2); w = gel(w,1); } M = M_from_wrapmon(&S, wfast, n0); } /* M[j] = sum(n >= n0, w(n) / n^(a*j+b) */ Pade(M, &P,&Q); Qp = RgX_deriv(Q); if (gequal1(a)) a = NULL; if (!a && typ(w) == t_INT) { vabs = vr = monroots(Q, Qp, signe(w)? 1: 0, prec2); checkmonroots(vr, n); c = b; } else { vr = RX_realroots(Q, prec2); settyp(vr, t_VEC); checkmonroots(vr, n); if (!a) { vabs = vr; c = b; } else { GEN ai = ginv(a); vabs = cgetg(n+1, t_VEC); for (j = 1; j <= n; j++) gel(vabs,j) = gpow(gel(vr,j), ai, prec2); c = gdiv(b,a); } } vwt = cgetg(n+1, t_VEC); c = gsubgs(c,1); if (gequal0(c)) c = NULL; for (j = 1; j <= n; j++) { GEN r = gel(vr,j), t = gdiv(poleval(P,r), poleval(Qp,r)); if (c) t = gmul(t, gpow(r, c, prec)); gel(vwt,j) = neg? gneg(t): t; } if (typ(w) == t_INT && !equali1(n0)) { GEN h = subiu(n0,1); for (j = 1; j <= n; j++) gel(vabs,j) = gadd(gel(vabs,j), h); } return mkvec3(gprec_wtrunc(vabs,prec0), gprec_wtrunc(vwt,prec0), n0); } GEN sumnummonieninit(GEN asymp, GEN w, GEN n0, long prec) { pari_sp av = avma; const char *fun = "sumnummonieninit"; GEN a, b; if (!n0) n0 = gen_1; else if (typ(n0) != t_INT) pari_err_TYPE(fun, n0); if (!asymp) a = b = gen_1; else { if (typ(asymp) == t_VEC) { if (lg(asymp) != 3) pari_err_TYPE(fun, asymp); a = gel(asymp,1); b = gel(asymp,2); } else { a = gen_1; b = asymp; } if (gsigne(a) <= 0) pari_err_DOMAIN(fun, "a", "<=", gen_0, a); if (gcmpgs(gadd(a,b), 1) <= 0) pari_err_DOMAIN(fun, "a+b", "<=", gen_1, mkvec2(a,b)); } if (!w) w = gen_0; else switch(typ(w)) { case t_INT: if (signe(w) < 0) pari_err_IMPL("log power < 0 in sumnummonieninit"); case t_CLOSURE: break; case t_VEC: if (lg(w) == 3 && typ(gel(w,1)) == t_CLOSURE) break; default: pari_err_TYPE(fun, w); } return gerepilecopy(av, sumnummonieninit_i(a, b, w, n0, prec)); } GEN sumnummonien(void *E, GEN (*eval)(void*,GEN), GEN n0, GEN tab, long prec) { pari_sp av = avma; GEN vabs, vwt, S; long l, i; if (typ(n0) != t_INT) pari_err_TYPE("sumnummonien", n0); if (!tab) tab = sumnummonieninit_i(gen_1, gen_1, gen_0, n0, prec); else { if (lg(tab) != 4 || typ(tab) != t_VEC) pari_err_TYPE("sumnummonien", tab); if (!equalii(n0, gel(tab,3))) pari_err(e_MISC, "incompatible initial value %Ps != %Ps", gel(tab,3),n0); } vabs= gel(tab,1); l = lg(vabs); vwt = gel(tab,2); if (typ(vabs) != t_VEC || typ(vwt) != t_VEC || lg(vwt) != l) pari_err_TYPE("sumnummonien", tab); S = gen_0; for (i = 1; i < l; i++) { S = gadd(S, gmul(gel(vwt,i), eval(E, gel(vabs,i)))); S = gprec_wensure(S, prec); } return gerepilecopy(av, gprec_w(S, prec)); } static GEN get_oo(GEN fast) { return mkvec2(mkoo(), fast); } GEN sumnuminit(GEN fast, long prec) { pari_sp av; GEN s, v, d, C, res = cgetg(6, t_VEC); long bitprec = prec2nbits(prec), N, k, k2, m; double w; gel(res, 1) = d = mkfrac(gen_1, utoipos(4)); /* 1/4 */ av = avma; w = gtodouble(glambertW(ginv(d), LOWDEFAULTPREC)); N = (long)ceil(M_LN2*bitprec/(w*(1+w))+5); k = (long)ceil(N*w); if (k&1) k--; prec += EXTRAPRECWORD; k2 = k/2; s = RgX_to_ser(monomial(real_1(prec),1,0), k+3); s = gmul2n(gasinh(s, prec), 2); /* asinh(x)/d, d = 1/4 */ gel(s, 2) = utoipos(4); s = gsub(ser_inv(gexpm1(s,prec)), ser_inv(s)); C = matpascal(k-1); v = cgetg(k2+1, t_VEC); for (m = 1; m <= k2; m++) { pari_sp av = avma; GEN S = real_0(prec); long j; for (j = m; j <= k2; j++) { /* s[X^(2j-1)] * binomial(2*j-1, j-m) */ GEN t = gmul(gel(s,2*j+1), gcoeff(C, 2*j,j-m+1)); t = gmul2n(t, 1-2*j); S = odd(j)? gsub(S,t): gadd(S,t); } if (odd(m)) S = gneg(S); gel(v,m) = gerepileupto(av, S); } v = RgC_gtofp(v,prec); settyp(v, t_VEC); gel(res, 4) = gerepileupto(av, v); gel(res, 2) = utoi(N); gel(res, 3) = utoi(k); if (!fast) fast = get_oo(gen_0); gel(res, 5) = intnuminit(gel(res,2), fast, 0, prec - EXTRAPRECWORD); return res; } static int checksumtab(GEN T) { if (typ(T) != t_VEC || lg(T) != 6) return 0; return typ(gel(T,2))==t_INT && typ(gel(T,3))==t_INT && typ(gel(T,4))==t_VEC; } GEN sumnum(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec) { pari_sp av = avma, av2; GEN v, tabint, S, d, fast; long as, N, k, m, prec2; if (!a) { a = gen_1; fast = get_oo(gen_0); } else switch(typ(a)) { case t_VEC: if (lg(a) != 3) pari_err_TYPE("sumnum", a); fast = get_oo(gel(a,2)); a = gel(a,1); break; default: fast = get_oo(gen_0); } if (typ(a) != t_INT) pari_err_TYPE("sumnum", a); if (!tab) tab = sumnuminit(fast, prec); else if (!checksumtab(tab)) pari_err_TYPE("sumnum",tab); as = itos(a); d = gel(tab,1); N = maxss(as, itos(gel(tab,2))); k = itos(gel(tab,3)); v = gel(tab,4); tabint = gel(tab,5); prec2 = prec+EXTRAPRECWORD; av2 = avma; S = gmul(eval(E, stoi(N)), real2n(-1,prec2)); for (m = as; m < N; m++) { S = gadd(S, eval(E, stoi(m))); if (gc_needed(av, 2)) { if (DEBUGMEM>1) pari_warn(warnmem,"sumnum [1], %ld/%ld",m,N); S = gerepileupto(av2, S); } S = gprec_wensure(S, prec2); } for (m = 1; m <= k/2; m++) { GEN t = gmulsg(2*m-1, d); GEN s = gsub(eval(E, gsubsg(N,t)), eval(E, gaddsg(N,t))); S = gadd(S, gmul(gel(v,m), s)); if (gc_needed(av2, 2)) { if (DEBUGMEM>1) pari_warn(warnmem,"sumnum [2], %ld/%ld",m,k/2); S = gerepileupto(av2, S); } S = gprec_wensure(S, prec2); } S = gadd(S, intnum(E, eval,stoi(N), fast, tabint, prec2)); return gerepilecopy(av, gprec_w(S, prec)); } GEN sumnummonien0(GEN a, GEN code, GEN tab, long prec) { EXPR_WRAP(code, sumnummonien(EXPR_ARG, a, tab, prec)); } GEN sumnum0(GEN a, GEN code, GEN tab, long prec) { EXPR_WRAP(code, sumnum(EXPR_ARG, a, tab, prec)); } /* Abel-Plana summation */ static GEN intnumgauexpinit(long prec) { pari_sp ltop = avma; GEN V, N, E, P, Q, R, vabs, vwt; long l, n, k, j, prec2, prec0 = prec + EXTRAPRECWORD, bit = prec2nbits(prec); n = (long)ceil(bit*0.226); n |= 1; /* make n odd */ prec = nbits2prec(1.5*bit + 32); prec2 = maxss(prec0, nbits2prec(1.15*bit + 32)); V = cgetg(n + 4, t_VEC); for (k = 1; k <= n + 3; ++k) gel(V, k) = gtofp(gdivgs(bernfrac(2*k), odd(k)? 2*k: -2*k), prec); Pade(V, &P, &Q); N = RgX_recip(gsub(P, Q)); E = RgX_recip(Q); R = gdivgs(gdiv(N, RgX_deriv(E)), 2); vabs = RX_realroots(E,prec2); l = lg(vabs); settyp(vabs, t_VEC); vwt = cgetg(l, t_VEC); for (j = 1; j < l; ++j) { GEN a = gel(vabs,j); gel(vwt, j) = gprec_wtrunc(poleval(R, a), prec0); gel(vabs, j) = gprec_wtrunc(sqrtr_abs(a), prec0); } return gerepilecopy(ltop, mkvec2(vabs, vwt)); } /* Compute \int_{-oo}^oo w(x)f(x) dx, where w(x)=x/(exp(2pi x)-1) * for x>0 and w(-x)=w(x). For Abel-Plana (sumnumap). */ static GEN intnumgauexp(void *E, GEN (*eval)(void*,GEN), GEN gN, GEN tab, long prec) { pari_sp av = avma; GEN U = mkcomplex(gN, NULL), V = mkcomplex(gN, NULL), S = gen_0; GEN vabs = gel(tab, 1), vwt = gel(tab, 2); long l = lg(vabs), i; if (lg(vwt) != l || typ(vabs) != t_VEC || typ(vwt) != t_VEC) pari_err_TYPE("sumnumap", tab); for (i = 1; i < l; i++) { /* I * (w_i/a_i) * (f(N + I*a_i) - f(N - I*a_i)) */ GEN x = gel(vabs,i), w = gel(vwt,i), t; gel(U,2) = x; gel(V,2) = gneg(x); t = mulcxI(gsub(eval(E,U), eval(E,V))); S = gadd(S, gmul(gdiv(w,x), cxtoreal(t))); S = gprec_wensure(S, prec); } return gerepilecopy(av, gprec_w(S, prec)); } GEN sumnumapinit(GEN fast, long prec) { if (!fast) fast = mkoo(); retmkvec2(intnumgauexpinit(prec), intnuminit(gen_1, fast, 0, prec)); } typedef struct { GEN (*f)(void *E, GEN); void *E; long N; } expfn; /* f(Nx) */ static GEN _exfn(void *E, GEN x) { expfn *S = (expfn*)E; return S->f(S->E, gmulsg(S->N, x)); } GEN sumnumap(void *E, GEN (*eval)(void*,GEN), GEN a, GEN tab, long prec) { pari_sp av = avma; expfn T; GEN S, fast, gN; long as, m, N; if (!a) { a = gen_1; fast = get_oo(gen_0); } else switch(typ(a)) { case t_VEC: if (lg(a) != 3) pari_err_TYPE("sumnumap", a); fast = get_oo(gel(a,2)); a = gel(a,1); break; default: fast = get_oo(gen_0); } if (typ(a) != t_INT) pari_err_TYPE("sumnumap", a); if (!tab) tab = sumnumapinit(fast, prec); else if (typ(tab) != t_VEC || lg(tab) != 3) pari_err_TYPE("sumnumap",tab); as = itos(a); T.N = N = maxss(as + 1, (long)ceil(prec2nbits(prec)*0.327)); T.E = E; T.f = eval; gN = stoi(N); S = gtofp(gmul2n(eval(E, gN), -1), prec); for (m = as; m < N; ++m) { S = gadd(S, eval(E, stoi(m))); S = gprec_wensure(S, prec); } S = gadd(S, gmulsg(N, intnum(&T, &_exfn, gen_1, fast, gel(tab, 2), prec))); S = gadd(S, intnumgauexp(E, eval, gN, gel(tab, 1), prec)); return gerepileupto(av, S); } GEN sumnumap0(GEN a, GEN code, GEN tab, long prec) { EXPR_WRAP(code, sumnumap(EXPR_ARG, a, tab, prec)); } /* max (1, |zeros|), P a t_POL or scalar */ static GEN polmax(GEN P) { GEN r; if (typ(P) != t_POL || degpol(P) <= 0) return gen_1; r = polrootsbound(P, NULL); if (gcmpgs(r, 1) <= 0) return gen_1; return r; } /* max (1, |poles|), F a t_POL or t_RFRAC or scalar */ static GEN ratpolemax(GEN F) { if (typ(F) == t_POL) return gen_1; return polmax(gel(F, 2)); } /* max (1, |poles|, |zeros|), sets *p = max(1, |poles|)) */ static GEN ratpolemax2(GEN F, GEN *p) { GEN t; if (typ(F) == t_POL) { if (p) *p = gen_1; return polmax(F); } t = polmax(gel(F,2)); if (p) *p = t; return gmax_shallow(t, polmax(gel(F,1))); } static GEN sercoeff(GEN x, long n) { long N = n - valp(x); return (N < 0)? gen_0: gel(x,N+2); } /* Compute the integral from N to infinity of a rational function F, deg(F) < -1 * We must have N > 2 * r, r = max(1, |poles F|). */ static GEN intnumainfrat(GEN F, long N, double r, long prec) { long B = prec2nbits(prec), v, k, lim; GEN S, ser; pari_sp av = avma; lim = (long)ceil(B/log2(N/r)) + 1; ser = gmul(F, real_1(prec + EXTRAPREC)); ser = rfracrecip_to_ser_absolute(ser, lim); v = valp(ser); S = gdivgs(sercoeff(ser,lim+1), lim*N); /* goes down to 2, but coeffs are 0 in degree < v */ for (k = lim; k >= v; k--) /* S <- (S + coeff(ser,k)/(k-1)) / N */ S = gdivgs(gadd(S, gdivgs(sercoeff(ser,k), k-1)), N); if (v-2) S = gdiv(S, powuu(N, v-2)); return gerepilecopy(av, gprec_w(S, prec)); } static GEN rfrac_eval0(GEN R) { GEN N, n, D = gel(R,2), d = constant_coeff(D); if (gcmp0(d)) return NULL; N = gel(R,1); n = typ(N)==t_POL? constant_coeff(N): N; return gdiv(n, d); } static GEN rfrac_eval(GEN R, GEN a) { GEN D = gel(R,2), d = poleval(D,a); return gcmp0(d)? NULL: gdiv(poleval(gel(R,1),a), d); } /* R = \sum_i vR[i], eval at a omitting poles */ static GEN RFRAC_eval(GEN R, GEN vR, GEN a) { GEN S = rfrac_eval(R,a); if (!S && vR) { long i, l = lg(vR); for (i = 1; i < l; i++) { GEN z = rfrac_eval(gel(vR,i), a); if (z) S = S? gadd(S,z): z; } } return S; } static GEN add_RFRAC_eval(GEN S, GEN R, GEN vR, GEN a) { GEN z = RFRAC_eval(R, vR, a); return z? gadd(S, z): S; } static GEN add_sumrfrac(GEN S, GEN R, GEN vR, long b) { long m; for (m = b; m >= 1; m--) S = add_RFRAC_eval(S,R,vR,utoipos(m)); return S; } static void get_kN(long r, long B, long *pk, long *pN) { long k = maxss(50, (long)ceil(0.241*B)); GEN z; if (k&1L) k++; *pk = k; z = sqrtnr_abs(gmul2n(gtofp(bernfrac(k), LOWDEFAULTPREC), B), k); *pN = maxss(2*r, r + 1 + itos(gceil(z))); } /* F a t_RFRAC, F0 = F(0) or NULL [pole], vF a vector of t_RFRAC summing to F * or NULL [F atomic] */ static GEN sumnumrat_i(GEN F, GEN F0, GEN vF, long prec) { long B = prec2nbits(prec), vx, j, k, N; GEN S, S1, S2, intf, _1; double r; if (poldegree(F, -1) > -2) pari_err(e_MISC, "sum diverges in sumnumrat"); vx = varn(gel(F,2)); r = gtodouble(ratpolemax(F)); get_kN((long)ceil(r), B, &k,&N); intf = intnumainfrat(F, N, r, prec); /* N > ratpolemax(F) is not a pole */ _1 = real_1(prec); S1 = gmul2n(gmul(_1, gsubst(F, vx, utoipos(N))), -1); S1 = add_sumrfrac(S1, F, vF, N-1); if (F0) S1 = gadd(S1, F0); S = gmul(_1, gsubst(F, vx, gaddgs(pol_x(vx), N))); S = rfrac_to_ser(S, k + 2); S2 = gen_0; for (j = 2; j <= k; j += 2) S2 = gadd(S2, gmul(gdivgs(bernfrac(j),j), sercoeff(S, j-1))); return gadd(intf, gsub(S1, S2)); } /* sum_{n >= a} F(n) */ GEN sumnumrat(GEN F, GEN a, long prec) { pari_sp av = avma; long vx; GEN vF, F0; switch(typ(F)) { case t_RFRAC: break; case t_INT: case t_REAL: case t_COMPLEX: case t_POL: if (gequal0(F)) return real_0(prec); default: pari_err_TYPE("sumnumrat",F); } vx = varn(gel(F,2)); switch(typ(a)) { case t_INT: if (signe(a)) F = gsubst(F, vx, deg1pol_shallow(gen_1,a,vx)); F0 = rfrac_eval0(F); vF = NULL; break; case t_INFINITY: if (inf_get_sign(a) == -1) { /* F(x) + F(-x). Could divide degree by 2, as G(x^2): pb with poles */ GEN F2 = gsubst(F, vx, RgX_neg(pol_x(vx))); vF = mkvec2(F,F2); F = gadd(F, F2); if (gequal0(F)) { avma = av; return real_0(prec); } F0 = rfrac_eval0(gel(vF,1)); break; } default: pari_err_TYPE("sumnumrat",a); return NULL; /* LCOV_EXCL_LINE */ } return gerepileupto(av, sumnumrat_i(F, F0, vF, prec)); } static GEN _mpmul(GEN x, GEN y) { if (!x) return y; return y? mpmul(x, y): x; } /* prod_{n >= a} F(n) */ GEN prodnumrat(GEN F, long a, long prec) { pari_sp ltop = avma; long B = prec2nbits(prec), j, k, m, N, vx; GEN S, S1, S2, intf, G, F1 = gsubgs(F,1); double r; switch(typ(F1)) { case t_RFRAC: break; case t_INT: case t_REAL: case t_COMPLEX: case t_POL: if (gequal0(F1)) return real_1(prec); default: pari_err_TYPE("prodnumrat",F); } if (poldegree(F1,-1) > -2) pari_err(e_MISC, "product diverges in prodnumrat"); vx = varn(gel(F,2)); if (a) F = gsubst(F, vx, gaddgs(pol_x(vx), a)); r = gtodouble(ratpolemax2(F, NULL)); get_kN((long)ceil(r), B, &k,&N); G = gdiv(deriv(F, vx), F); intf = intnumainfrat(gmul(pol_x(vx),G), N, r, prec); intf = gneg(gadd(intf, gmulsg(N, glog(gsubst(F, vx, stoi(N)), prec)))); S = gmul(real_1(prec), gsubst(G, vx, gaddgs(pol_x(vx), N))); S = rfrac_to_ser(S, k + 2); S1 = gsqrt(gsubst(F, vx, utoipos(N)), prec); for (m = 0; m < N; m++) S1 = gmul(S1, gsubst(F, vx, utoi(m))); S2 = gen_0; for (j = 2; j <= k; j += 2) S2 = gadd(S2, gmul(gdivgs(bernfrac(j),j*(j-1)), sercoeff(S, j-2))); return gerepileupto(ltop, gmul(S1, gexp(gsub(intf, S2), prec))); } static GEN sdmob(GEN ser, long n) { GEN D = divisorsu(n), S = gen_0; long i, l = lg(D); for (i = 1; i < l; ++i) { long d = D[i], mob = moebiusu(d); if (mob) S = gadd(S, gdivgs(sercoeff(ser, n/d), mob*d)); } return S; } static GEN logzetan(GEN s, GEN P, long prec) { GEN negs = gneg(s), Z = gzeta(gprec_w(s,prec), prec); long i, l = lg(P); for (i = 1; i < l; i++) Z = gmul(Z, gsubsg(1, gpow(gel(P,i), negs, prec))); return glog(Z, prec); } static GEN sumlogzeta(GEN ser, GEN s, long N, long vF, long lim, long prec) { GEN z = gen_0, P = primes_interval(gen_2, utoipos(N)); long n; for (n = lim; n >= vF; n--) { GEN t = sdmob(ser, n); if (!gequal0(t)) { long e = gexpo(t), prec2 = e <= 0? prec: prec + nbits2prec(e); z = gadd(z, gmul(logzetan(gmulsg(n,s), P, prec2), t)); z = gprec_w(z, prec); } } return z; } /* sum_{p prime, p >= a} F(p^s), F rational function */ GEN sumeulerrat(GEN F, GEN s, long a, long prec) { pari_sp av = avma; forprime_t T; GEN r, ser, res, rsg; double rs, RS; long B = prec2nbits(prec), vx, vF, p, N, lim; switch(typ(F)) { case t_RFRAC: break; case t_INT: case t_REAL: case t_COMPLEX: case t_POL: if (gequal0(F)) return real_0(prec); default: pari_err_TYPE("sumeulerrat",F); } if (!s) s = gen_1; if (a < 2) a = 2; vx = varn(gel(F,2)); vF = -poldegree(F, -1); rsg = real_i(s); rs = gtodouble(rsg); r = ratpolemax(F); RS = maxdd(1./vF, dbllog2(r) / log2((double)a)); if (rs <= RS) pari_err_DOMAIN("sumeulerrat", "real(s)", "<=", dbltor(RS), dbltor(rs)); N = maxss(maxss(30, a), (long)ceil(2*gtodouble(r))); lim = (long)ceil(B / dbllog2(gdiv(gpow(stoi(N), rsg, LOWDEFAULTPREC), r)))+1; ser = gmul(real_1(prec + EXTRAPREC), F); ser = rfracrecip_to_ser_absolute(ser, lim); res = sumlogzeta(ser, s, N, vF, lim, prec); u_forprime_init(&T, a, N); while ( (p = u_forprime_next(&T)) ) res = gadd(res, gsubst(F, vx, gpow(utoipos(p), s, prec))); return gerepilecopy(av, gprec_w(res, prec)); } /* prod_{p prime, p >= a} F(p^s), F rational function */ GEN prodeulerrat(GEN F, GEN s, long a, long prec) { pari_sp ltop = avma; forprime_t T; GEN F1, r, r1, ser, res, rsg; double rs, RS; long B = prec2nbits(prec), vx = gvar(F), vF, p, N, lim; F1 = gsubgs(F, 1); switch(typ(F)) { case t_RFRAC: break; case t_INT: case t_REAL: case t_COMPLEX: case t_POL: if (gequal0(F1)) return real_1(prec); default: pari_err_TYPE("prodeulerrat",F); } if (!s) s = gen_1; vF = -poldegree(F1, -1); rsg = real_i(s); rs = gtodouble(rsg); r = ratpolemax2(F, &r1); RS = maxdd(1./vF, dbllog2(r1) / log2((double)a)); if (rs <= RS) pari_err_DOMAIN("prodeulerrat", "real(s)", "<=", dbltor(RS), dbltor(rs)); N = maxss(maxss(30, a), (long)ceil(2*gtodouble(r))); lim = (long)ceil(B / dbllog2(gdiv(gpow(stoi(N), rsg, LOWDEFAULTPREC), r)))+1; ser = gmul(real_1(prec + EXTRAPREC), F1); ser = gaddsg(1, rfracrecip_to_ser_absolute(ser, lim)); ser = glog(ser, 0); res = sumlogzeta(ser, s, N, vF, lim, prec); res = gexp(res, prec); u_forprime_init(&T, a, N); while ( (p = u_forprime_next(&T)) ) res = gmul(res, gsubst(F, vx, gpow(utoipos(p), s, prec))); return gerepilecopy(ltop, gprec_w(res, prec)); } /* Compute $\sum_{n\ge a}c(n)$ using Lagrange extrapolation. Assume that the $N$-th remainder term of the series has a regular asymptotic expansion in integral powers of $1/N$. */ static GEN sumnumlagrange1init(GEN c1, long flag, long prec) { pari_sp av = avma; GEN V, W, T; double c1d; long B = prec2nbits(prec), prec2; ulong n, N; c1d = c1 ? gtodouble(c1) : 0.332; N = (ulong)ceil(c1d*B); if ((N&1L) == 0) N++; prec2 = nbits2prec(B+(long)ceil(1.8444*N) + 16); W = vecbinome(N); T = vecpowuu(N, N); V = cgetg(N+1, t_VEC); gel(V,N) = gel(T,N); for (n = N-1; n >= 1; n--) { pari_sp av = avma; GEN t = mulii(gel(W, n+1), gel(T,n)); if (!odd(n)) togglesign_safe(&t); if (flag) t = addii(gel(V, n+1), t); gel(V, n) = gerepileuptoint(av, t); } V = gdiv(RgV_gtofp(V, prec2), mpfact(N)); return gerepilecopy(av, mkvec4(gen_1, stoi(prec2), gen_1, V)); } static GEN sumnumlagrange2init(GEN c1, long flag, long prec) { pari_sp av = avma; GEN V, W, T, told; double c1d = c1 ? gtodouble(c1) : 0.228; long B = prec2nbits(prec), prec2; ulong n, N; N = (ulong)ceil(c1d*B); if ((N&1L) == 0) N++; prec2 = nbits2prec(B+(long)ceil(1.18696*N) + 16); W = vecbinome(2*N); T = vecpowuu(N, 2*N); V = cgetg(N+1, t_VEC); gel(V, N) = told = gel(T,N); for (n = N-1; n >= 1; n--) { GEN tnew = mulii(gel(W, N-n+1), gel(T,n)); if (!odd(n)) togglesign_safe(&tnew); told = addii(told, tnew); if (flag) told = addii(gel(V, n+1), told); gel(V, n) = told; told = tnew; } V = gdiv(RgV_gtofp(V, prec2), mpfact(2*N)); return gerepilecopy(av, mkvec4(gen_2, stoi(prec2), gen_1, V)); } /* Used only for al = 2, 1, 1/2, 1/3, 1/4. */ static GEN sumnumlagrangeinit_i(GEN al, GEN c1, long flag, long prec) { pari_sp av = avma; GEN V, W; double c1d = 0.0, c2; long B = prec2nbits(prec), B1, prec2, dal; ulong j, n, N; if (typ(al) == t_INT) { switch(itos_or_0(al)) { case 1: return sumnumlagrange1init(c1, flag, prec); case 2: return sumnumlagrange2init(c1, flag, prec); default: pari_err_IMPL("sumnumlagrange for this alpha"); } } if (typ(al) != t_FRAC) pari_err_TYPE("sumnumlagrangeinit",al); dal = itos_or_0(gel(al,2)); if (dal > 4 || !equali1(gel(al,1))) pari_err_IMPL("sumnumlagrange for this alpha"); switch(dal) { case 2: c2 = 2.6441; c1d = 0.62; break; case 3: c2 = 3.1578; c1d = 1.18; break; case 4: c2 = 3.5364; c1d = 3.00; break; default: return NULL; /* LCOV_EXCL_LINE */ } if (c1) { c1d = gtodouble(c1); if (c1d <= 0) pari_err_DOMAIN("sumnumlagrangeinit", "c1", "<=", gen_0, c1); } N = (ulong)ceil(c1d*B); if ((N&1L) == 0) N++; B1 = B + (long)ceil(c2*N) + 16; prec2 = nbits2prec(B1); V = vecpowug(N, al, prec2); W = cgetg(N+1, t_VEC); for (n = 1; n <= N; ++n) { pari_sp av2 = avma; GEN t = NULL, vn = gel(V, n); for (j = 1; j <= N; j++) if (j != n) t = _mpmul(t, mpsub(vn, gel(V, j))); gel(W, n) = gerepileuptoleaf(av2, mpdiv(gpowgs(vn, N-1), t)); } if (flag) for (n = N-1; n >= 1; n--) gel(W, n) = gadd(gel(W, n+1), gel(W, n)); return gerepilecopy(av, mkvec4(al, stoi(prec2), gen_1, W)); } GEN sumnumlagrangeinit(GEN al, GEN c1, long prec) { pari_sp ltop = avma; GEN V, W, S, be; long n, prec2, fl, N; if (!al) return sumnumlagrange1init(c1, 1, prec); if (typ(al) != t_VEC) al = mkvec2(gen_1, al); else if (lg(al) != 3) pari_err_TYPE("sumnumlagrangeinit",al); be = gel(al,2); al = gel(al,1); if (gequal0(be)) return sumnumlagrangeinit_i(al, c1, 1, prec); V = sumnumlagrangeinit_i(al, c1, 0, prec); switch(typ(be)) { case t_CLOSURE: fl = 1; break; case t_INT: case t_FRAC: case t_REAL: fl = 0; break; default: pari_err_TYPE("sumnumlagrangeinit", be); return NULL; /* LCOV_EXCL_LINE */ } prec2 = itos(gel(V, 2)); W = gel(V, 4); N = lg(W) - 1; S = gen_0; V = cgetg(N+1, t_VEC); for (n = N; n >= 1; n--) { GEN tmp, gn = stoi(n); tmp = fl ? closure_callgen1prec(be, gn, prec2) : gpow(gn, gneg(be), prec2); tmp = gdiv(gel(W, n), tmp); S = gadd(S, tmp); gel(V, n) = (n == N)? tmp: gadd(gel(V, n+1), tmp); } return gerepilecopy(ltop, mkvec4(al, stoi(prec2), S, V)); } /* - sum_{n=1}^{as-1} f(n) */ static GEN sumaux(void *E, GEN (*eval)(void*,GEN,long), long as, long prec) { GEN S = gen_0; long n; if (as > 1) { for (n = 1; n < as; ++n) { S = gadd(S, eval(E, stoi(n), prec)); S = gprec_wensure(S, prec); } S = gneg(S); } else for (n = as; n <= 0; ++n) { S = gadd(S, eval(E, stoi(n), prec)); S = gprec_wensure(S, prec); } return S; } GEN sumnumlagrange(void *E, GEN (*eval)(void*,GEN,long), GEN a, GEN tab, long prec) { pari_sp av = avma; GEN s, S, al, V; long as, prec2; ulong n, l; if (typ(a) != t_INT) pari_err_TYPE("sumnumlagrange", a); if (!tab) tab = sumnumlagrangeinit(NULL, tab, prec); else if (lg(tab) != 5 || typ(gel(tab,2)) != t_INT || typ(gel(tab,4)) != t_VEC) pari_err_TYPE("sumnumlagrange", tab); as = itos(a); al = gel(tab, 1); prec2 = itos(gel(tab, 2)); S = gel(tab, 3); V = gel(tab, 4); l = lg(V); if (gequal(al, gen_2)) { s = sumaux(E, eval, as, prec2); as = 1; } else s = gen_0; for (n = 1; n < l; n++) { s = gadd(s, gmul(gel(V, n), eval(E, stoi(n+as-1), prec2))); s = gprec_wensure(s, prec); } if (!gequal1(S)) s = gdiv(s,S); return gerepilecopy(av, gprec_w(s, prec)); } GEN sumnumlagrange0(GEN a, GEN code, GEN tab, long prec) { EXPR_WRAP(code, sumnumlagrange(EXPR_ARGPREC, a, tab, prec)); } pari-2.11.2/src/language/init.h0000644000175000017500000065033113457701105014657 0ustar billbill/* This file is autogenerated from the database. */ /* See src/desc/gen_proto */ /* Do not edit*/ entree functions_basic[]={ {"!_",0,(void*)gnot,18,"G","!a: boolean operator \"not\"."}, {"#_",0,(void*)glength,18,"lG","#x: number of non code words in x, number of characters for a string."}, {"%",0,(void*)pari_get_hist,18,"D0,L,","last history item."}, {"%#",0,(void*)pari_get_histtime,18,"lD0,L,","time to compute last history item."}, {"+_",0,NULL,18,NULL,"+_: copy and return its argument"}, {"-_",0,(void*)gneg,18,"G","-_: negate argument"}, {"Catalan",0,(void*)mpcatalan,8,"p","Catalan=Catalan(): Catalan's number with current precision."}, {"Col",0,(void*)gtocol0,3,"GD0,L,","Col(x, {n}): transforms the object x into a column vector of dimension n."}, {"Colrev",0,(void*)gtocolrev0,3,"GD0,L,","Colrev(x, {n}): transforms the object x into a column vector of dimension n in reverse order with respect to Col(x, {n}). Empty vector if x is omitted."}, {"Euler",0,(void*)mpeuler,8,"p","Euler=Euler(): Euler's constant with current precision."}, {"I",0,(void*)gen_I,8,"","I=I(): square root of -1."}, {"List",0,(void*)gtolist,3,"DG","List({x=[]}): transforms the vector or list x into a list. Empty list if x is omitted."}, {"Map",0,(void*)gtomap,3,"DG","Map({x}): converts the matrix [a_1,b_1;a_2,b_2;...;a_n,b_n] to the map a_i->b_i."}, {"Mat",0,(void*)gtomat,3,"DG","Mat({x=[]}): transforms any GEN x into a matrix. Empty matrix if x is omitted."}, {"Mod",0,(void*)gmodulo,3,"GG","Mod(a,b): creates 'a modulo b'."}, {"O",0,(void*)ggrando,6,"","O(p^e): p-adic or power series zero with precision given by e."}, {"O(_^_)",0,(void*)ggrando,20,"GD1,L,","O(p^e): p-adic or power series zero with precision given by e."}, {"Pi",0,(void*)mppi,8,"p","Pi=Pi(): the constant pi, with current precision."}, {"Pol",0,(void*)gtopoly,3,"GDn","Pol(t,{v='x}): convert t (usually a vector or a power series) into a polynomial with variable v, starting with the leading coefficient."}, {"Polrev",0,(void*)gtopolyrev,3,"GDn","Polrev(t,{v='x}): convert t (usually a vector or a power series) into a polynomial with variable v, starting with the constant term."}, {"Qfb",0,(void*)Qfb0,3,"GGGDGp","Qfb(a,b,c,{D=0.}): binary quadratic form a*x^2+b*x*y+c*y^2. D is optional (0.0 by default) and initializes Shanks's distance if b^2-4*a*c>0."}, {"Ser",0,(void*)Ser0,3,"GDnDGDP","Ser(s,{v='x},{d=seriesprecision}): convert s into a power series with variable v and precision d, starting with the constant coefficient."}, {"Set",0,(void*)gtoset,3,"DG","Set({x=[]}): convert x into a set, i.e. a row vector with strictly increasing coefficients. Empty set if x is omitted."}, {"Str",0,(void*)Str,3,"s*","Str({x}*): concatenates its (string) argument into a single string."}, {"Strchr",0,(void*)Strchr,3,"G","Strchr(x): converts x to a string, translating each integer into a character."}, {"Strexpand",0,(void*)Strexpand,3,"s*","Strexpand({x}*): concatenates its (string) argument into a single string, performing tilde expansion."}, {"Strprintf",0,(void*)Strprintf,1,"ss*","Strprintf(fmt,{x}*): returns a string built from the remaining arguments according to the format fmt."}, {"Strtex",0,(void*)Strtex,3,"s*","Strtex({x}*): translates its (string) arguments to TeX format and returns the resulting string."}, {"Vec",0,(void*)gtovec0,3,"GD0,L,","Vec(x, {n}): transforms the object x into a vector of dimension n."}, {"Vecrev",0,(void*)gtovecrev0,3,"GD0,L,","Vecrev(x, {n}): transforms the object x into a vector of dimension n in reverse order with respect to Vec(x, {n})."}, {"Vecsmall",0,(void*)gtovecsmall0,3,"GD0,L,","Vecsmall(x, {n}): transforms the object x into a VECSMALL of dimension n."}, {"[_.._]",0,(void*)vecrange,20,"GG","[a..b] = [a,a+1,...,b]"}, {"[_|_<-_,_;_]",0,(void*)vecexpr1,20,"mGVDEDE","[a(x)|x<-b,c(x);...]"}, {"[_|_<-_,_]",0,(void*)vecexpr0,20,"GVDEDE","[a(x)|x<-b,c(x)] = apply(a,select(c,b))"}, {"_!",0,(void*)mpfact,18,"L","n!: factorial of n."}, {"_!=_",0,(void*)gne,18,"GG","a!=b: true if a and b are not equal."}, {"_%=_",0,(void*)gmode,18,"&G","x%=y: shortcut for x=x%y."}, {"_%_",0,(void*)gmod,18,"GG","x%y: Euclidean remainder of x and y."}, {"_&&_",0,(void*)andpari,18,"GE","a&&b: boolean operator \"and\"."}, {"_'",0,(void*)deriv,18,"GDn","x': derivative of x with respect to the main variable."}, {"_(_)",0,NULL,18,NULL,"f(a,b,...): evaluate the function f on a,b,..."}, {"_*=_",0,(void*)gmule,18,"&G","x*=y: shortcut for x=x*y."}, {"_*_",0,(void*)gmul,18,"GG","x*y: product of x and y."}, {"_++",0,(void*)gadd1e,18,"&","x++: set x to x+1."}, {"_+=_",0,(void*)gadde,18,"&G","x+=y: shortcut for x=x+y."}, {"_+_",0,(void*)gadd,18,"GG","x+y: sum of x and y."}, {"_--",0,(void*)gsub1e,18,"&","x--: set x to x-1."}, {"_-=_",0,(void*)gsube,18,"&G","x-=y: shortcut for x=x-y."}, {"_-_",0,(void*)gsub,18,"GG","x-y: difference of x and y."}, {"_.a1",0,(void*)member_a1,19,"mG","_.a1"}, {"_.a2",0,(void*)member_a2,19,"mG","_.a2"}, {"_.a3",0,(void*)member_a3,19,"mG","_.a3"}, {"_.a4",0,(void*)member_a4,19,"mG","_.a4"}, {"_.a6",0,(void*)member_a6,19,"mG","_.a6"}, {"_.area",0,(void*)member_area,19,"mG","_.area"}, {"_.b2",0,(void*)member_b2,19,"mG","_.b2"}, {"_.b4",0,(void*)member_b4,19,"mG","_.b4"}, {"_.b6",0,(void*)member_b6,19,"mG","_.b6"}, {"_.b8",0,(void*)member_b8,19,"mG","_.b8"}, {"_.bid",0,(void*)member_bid,19,"mG","_.bid"}, {"_.bnf",0,(void*)member_bnf,19,"mG","_.bnf"}, {"_.c4",0,(void*)member_c4,19,"mG","_.c4"}, {"_.c6",0,(void*)member_c6,19,"mG","_.c6"}, {"_.clgp",0,(void*)member_clgp,19,"mG","_.clgp"}, {"_.codiff",0,(void*)member_codiff,19,"mG","_.codiff"}, {"_.cyc",0,(void*)member_cyc,19,"mG","_.cyc"}, {"_.diff",0,(void*)member_diff,19,"mG","_.diff"}, {"_.disc",0,(void*)member_disc,19,"mG","_.disc"}, {"_.e",0,(void*)member_e,19,"mG","_.e"}, {"_.eta",0,(void*)member_eta,19,"mG","_.eta"}, {"_.f",0,(void*)member_f,19,"mG","_.f"}, {"_.fu",0,(void*)member_fu,19,"G","_.fu"}, {"_.futu",0,(void*)member_futu,19,"mG","_.futu"}, {"_.gen",0,(void*)member_gen,19,"mG","_.gen"}, {"_.group",0,(void*)member_group,19,"mG","_.group"}, {"_.index",0,(void*)member_index,19,"mG","_.index"}, {"_.j",0,(void*)member_j,19,"mG","_.j"}, {"_.mod",0,(void*)member_mod,19,"mG","_.mod"}, {"_.nf",0,(void*)member_nf,19,"mG","_.nf"}, {"_.no",0,(void*)member_no,19,"mG","_.no"}, {"_.omega",0,(void*)member_omega,19,"mG","_.omega"}, {"_.orders",0,(void*)member_orders,19,"mG","_.orders"}, {"_.p",0,(void*)member_p,19,"mG","_.p"}, {"_.pol",0,(void*)member_pol,19,"mG","_.pol"}, {"_.polabs",0,(void*)member_polabs,19,"mG","_.polabs"}, {"_.r1",0,(void*)member_r1,19,"mG","_.r1"}, {"_.r2",0,(void*)member_r2,19,"mG","_.r2"}, {"_.reg",0,(void*)member_reg,19,"mG","_.reg"}, {"_.roots",0,(void*)member_roots,19,"mG","_.roots"}, {"_.sign",0,(void*)member_sign,19,"mG","_.sign"}, {"_.t2",0,(void*)member_t2,19,"G","_.t2"}, {"_.tate",0,(void*)member_tate,19,"mG","_.tate"}, {"_.tu",0,(void*)member_tu,19,"G","_.tu"}, {"_.tufu",0,(void*)member_tufu,19,"mG","_.tufu"}, {"_.zk",0,(void*)member_zk,19,"mG","_.zk"}, {"_.zkst",0,(void*)member_zkst,19,"mG","_.zkst"}, {"_/=_",0,(void*)gdive,18,"&G","x/=y: shortcut for x=x/y."}, {"_/_",0,(void*)gdiv,18,"GG","x/y: quotient of x and y."}, {"_<<=_",0,(void*)gshiftle,18,"&L","x<<=y: shortcut for x=x<=_",0,(void*)gge,18,"GG","x>=y: return 1 if x is greater or equal to y, 0 otherwise."}, {"_>>=_",0,(void*)gshiftre,18,"&L","x>>=y: shortcut for x=x>>y."}, {"_>>_",0,(void*)gshift_right,18,"GL","x>>y: compute shift(x,-y)."}, {"_>_",0,(void*)ggt,18,"GG","x>y: return 1 if x is strictly greater than y, 0 otherwise."}, {"_F2xq_log_Coppersmith_worker",0,(void*)F2xq_log_Coppersmith_worker,20,"GLGG","F2xq_log_Coppersmith_worker: worker for F2xq_log_Coppersmith"}, {"_Flxq_log_Coppersmith_worker",0,(void*)Flxq_log_Coppersmith_worker,20,"GLGG","Flxq_log_Coppersmith_worker: worker for Flxq_log_Coppersmith"}, {"_Fp_log_sieve_worker",0,(void*)Fp_log_sieve_worker,20,"LLGGGGGG","Fp_log_sieve_worker: worker for Fp_log_sieve"}, {"_ZM_det_worker",0,(void*)ZM_det_worker,20,"GG","worker for ZM_det"}, {"_ZM_inv_worker",0,(void*)ZM_inv_worker,20,"GG","worker for ZM_inv"}, {"_ZX_ZXY_resultant_worker",0,(void*)ZX_ZXY_resultant_worker,20,"GGGGG","worker for ZX_ZXY_resultant"}, {"_ZX_resultant_worker",0,(void*)ZX_resultant_worker,20,"GGGG","worker for ZX_resultant"}, {"_ZabM_inv_worker",0,(void*)ZabM_inv_worker,20,"GGG","worker for ZabM_inv"}, {"_[_,]",0,NULL,18,NULL,"x[y,]: y-th row of x."}, {"_[_,_]",0,NULL,18,NULL,"x[i{,j}]: i coefficient of a vector, i,j coefficient of a matrix"}, {"_[_.._,_.._]",0,(void*)matslice0,18,"GD0,L,D0,L,D0,L,D0,L,","x[a..b,c..d] = [x[a,c], x[a+1,c], ...,x[b,c]; x[a,c+1],x[a+1,c+1],...,x[b,c+1]; ... ... ... x[a,d], x[a+1,d] ,...,x[b,d]]"}, {"_[_.._]",0,(void*)vecslice0,18,"GD0,L,L","x[a..b] = [x[a],x[a+1],...,x[b]]"}, {"_\\/=_",0,(void*)gdivrounde,18,"&G","x\\/=y: shortcut for x=x\\/y."}, {"_\\/_",0,(void*)gdivround,18,"GG","x\\/y: rounded Euclidean quotient of x and y."}, {"_\\=_",0,(void*)gdivente,18,"&G","x\\=y: shortcut for x=x\\y."}, {"_\\_",0,(void*)gdivent,18,"GG","x\\y: Euclidean quotient of x and y."}, {"_^_",0,(void*)gpow,18,"GGp","x^y: compute x to the power y."}, {"_^s",0,(void*)gpowgs,20,"GL","return x^n where n is a small integer"}, {"__",0,NULL,18,NULL,"__: integral concatenation of strings."}, {"_aprcl_step4_worker",0,(void*)aprcl_step4_worker,20,"UGGG","worker for isprime (APRCL step 4)"}, {"_aprcl_step6_worker",0,(void*)aprcl_step6_worker,20,"GLGGG","worker for isprime (APRCL step 6)"}, {"_derivfun",0,(void*)derivfun0,20,"GGp","_derivfun(closure,[args]) numerical derivation of closure with respect to the first variable at (args)."}, {"_eval_mnemonic",0,(void*)eval_mnemonic,20,"lGs","Convert a mnemonic string to a flag."}, {"_factor_Aurifeuille",0,(void*)factor_Aurifeuille,20,"GL","_factor_Aurifeuille(a,d): return an algebraic factor of Phi_d(a), a != 0"}, {"_factor_Aurifeuille_prime",0,(void*)factor_Aurifeuille_prime,20,"GL","_factor_Aurifeuille_prime(p,d): return an algebraic factor of Phi_d(p), p prime"}, {"_multi_if",0,(void*)ifpari_multi,20,"GE*","internal variant of if() that allows more than 3 arguments."}, {"_nxMV_polint_worker",0,(void*)nxMV_polint_center_tree_worker,20,"GGGGG","used for parallel chinese"}, {"_pareval_worker",0,(void*)pareval_worker,20,"G","_pareval_worker(C): evaluate the closure C."}, {"_parfor_worker",0,(void*)parfor_worker,20,"GG","_parfor_worker(i,C): evaluate the closure C on i and return [i,C(i)]"}, {"_parselect_worker",0,(void*)parselect_worker,20,"GG","_parselect_worker(d,C): evaluate the boolean closure C on d."}, {"_parvector_worker",0,(void*)parvector_worker,20,"GG","_parvector_worker(i,C): evaluate the closure C on i."}, {"_polint_worker",0,(void*)nmV_polint_center_tree_worker,20,"GGGGG","used for parallel chinese"}, {"_polmodular_worker",0,(void*)polmodular_worker,20,"UUUGGGGLGG","used by polmodular"}, {"_safecoeff",0,NULL,18,NULL,"safe version of x[a], x[,a] and x[a,b]. Must be lvalues."}, {"_void_if",0,(void*)ifpari_void,20,"vGDIDI","internal variant of if() that does not return a value."}, {"_||_",0,(void*)orpari,18,"GE","a||b: boolean operator \"or\" (inclusive)."}, {"_~",0,(void*)gtrans,18,"G","x~: transpose of x."}, {"abs",0,(void*)gabs,8,"Gp","abs(x): absolute value (or modulus) of x."}, {"acos",0,(void*)gacos,8,"Gp","acos(x): arc cosine of x."}, {"acosh",0,(void*)gacosh,8,"Gp","acosh(x): inverse hyperbolic cosine of x."}, {"addhelp",0,(void*)addhelp,1,"vrs","addhelp(sym,str): add/change help message for the symbol sym."}, {"addprimes",0,(void*)addprimes,5,"DG","addprimes({x=[]}): add primes in the vector x to the prime table to be used in trial division. x may also be a single integer. Composite \"primes\" are NOT allowed."}, {"agm",0,(void*)agm,8,"GGp","agm(x,y): arithmetic-geometric mean of x and y."}, {"alarm",0,(void*)gp_alarm,1,"D0,L,DE","alarm({s = 0},{code}): if code is omitted, trigger an \"e_ALARM\" exception after s seconds, cancelling any previously set alarm; stop a pending alarm if s = 0 or is omitted. Otherwise, evaluate code, aborting after s seconds."}, {"algadd",0,(void*)algadd,11,"GGG","algadd(al,x,y): element x+y in al."}, {"algalgtobasis",0,(void*)algalgtobasis,11,"GG","algalgtobasis(al,x): transforms the element x of the algebra al into a column vector on the integral basis of al."}, {"algaut",0,(void*)algaut,11,"mG","algaut(al): the stored automorphism of the splitting field of the cyclic algebra al."}, {"algb",0,(void*)algb,11,"mG","algb(al): the element b of the center of the cyclic algebra al used to define it."}, {"algbasis",0,(void*)algbasis,11,"mG","algbasis(al): basis of the stored order of the central simple algebra al."}, {"algbasistoalg",0,(void*)algbasistoalg,11,"GG","algbasistoalg(al,x): transforms the column vector x on the integral basis of al into an element of al in algebraic form."}, {"algcenter",0,(void*)algcenter,11,"mG","algcenter(al): center of the algebra al."}, {"algcentralproj",0,(void*)alg_centralproj,11,"GGD0,L,","algcentralproj(al,z,{maps=0}): projections of the algebra al on the orthogonal central idempotents z[i]."}, {"algchar",0,(void*)algchar,11,"mG","algchar(al): characteristic of the algebra al."}, {"algcharpoly",0,(void*)algcharpoly,11,"GGDnD0,L,","algcharpoly(al,b,{v='x},{abs=0}): (reduced) characteristic polynomial of b in al, with respect to the variable v."}, {"algdegree",0,(void*)algdegree,11,"lG","algdegree(al): degree of the central simple algebra al."}, {"algdep",0,(void*)algdep0,7,"GLD0,L,","algdep(z,k,{flag=0}): algebraic relations up to degree n of z, using lindep([1,z,...,z^(k-1)], flag)."}, {"algdim",0,(void*)algdim,11,"lGD0,L,","algdim(al,{abs=0}): dimension of the algebra al."}, {"algdisc",0,(void*)algdisc,11,"G","algdisc(al): discriminant of the stored order of the algebra al."}, {"algdivl",0,(void*)algdivl,11,"GGG","algdivl(al,x,y): element x\\y in al."}, {"algdivr",0,(void*)algdivr,11,"GGG","algdivr(al,x,y): element x/y in al."}, {"alggroup",0,(void*)alggroup,11,"GDG","alggroup(gal, {p=0}): constructs the group algebra of gal over Q (resp. Fp)."}, {"alggroupcenter",0,(void*)alggroupcenter,11,"GDGD&","alggroupcenter(gal,{p=0},{&cc}): constructs the center of the group algebra of gal over Q (resp. Fp), and sets cc to the conjugacy classes of gal."}, {"alghasse",0,(void*)alghasse,11,"GG","alghasse(al,pl): the hasse invariant of the central simple algebra al at the place pl."}, {"alghassef",0,(void*)alghassef,11,"mG","alghassef(al): the hasse invariant of the central simple algebra al at finite places."}, {"alghassei",0,(void*)alghassei,11,"mG","alghassei(al): the hasse invariant of the central simple algebra al at infinite places."}, {"algindex",0,(void*)algindex,11,"lGDG","algindex(al,{pl}): the index of the central simple algebra al. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case return the local index at the place pl instead."}, {"alginit",0,(void*)alginit,11,"GGDnD1,L,","alginit(B, C, {v}, {maxord = 1}): initializes the central simple algebra defined by data B, C. If maxord = 1, compute a maximal order."}, {"alginv",0,(void*)alginv,11,"GG","alginv(al,x): element 1/x in al."}, {"alginvbasis",0,(void*)alginvbasis,11,"mG","alginvbasis(al): basis of the natural order of the central simple algebra al in terms of the stored order."}, {"algisassociative",0,(void*)algisassociative,11,"iGD0,G,","algisassociative(mt,p=0): true (1) if the multiplication table mt is suitable for algtableinit(mt,p), false (0) otherwise."}, {"algiscommutative",0,(void*)algiscommutative,11,"iG","algiscommutative(al): test whether the algebra al is commutative."}, {"algisdivision",0,(void*)algisdivision,11,"iGDG","algisdivision(al,{pl}): tests whether the central simple algebra al is a division algebra. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case tests whether al is locally a division algebra at the place pl instead."}, {"algisdivl",0,(void*)algisdivl,11,"iGGGD&","algisdivl(al,x,y,{&z}): tests whether y is left divisible by x and sets z to the left quotient x\\y."}, {"algisinv",0,(void*)algisinv,11,"iGGD&","algisinv(al,x,{&ix}): tests whether x is invertible and sets ix to the inverse of x."}, {"algisramified",0,(void*)algisramified,11,"iGDG","algisramified(al,{pl}): tests whether the central simple algebra al is ramified, i.e. not isomorphic to a matrix ring over its center. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case tests whether al is locally ramified at the place pl instead."}, {"algissemisimple",0,(void*)algissemisimple,11,"iG","algissemisimple(al): test whether the algebra al is semisimple."}, {"algissimple",0,(void*)algissimple,11,"iGD0,L,","algissimple(al, {ss = 0}): test whether the algebra al is simple."}, {"algissplit",0,(void*)algissplit,11,"iGDG","algissplit(al,{pl}): tests whether the central simple algebra al is split, i.e. isomorphic to a matrix ring over its center. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case tests whether al is locally split at the place pl instead."}, {"alglatadd",0,(void*)alglatadd,11,"GGGD&","alglatadd(al,lat1,lat2,{&ptinter}): the sum of the lattices lat1 and lat2. If ptinter is present, set it to the intersection of the lattices."}, {"alglatcontains",0,(void*)alglatcontains,11,"iGGGD&","alglatcontains(al,lat,x,{&ptc}): tests whether the lattice lat contains the element x. If ptc is present, sets it to the coordinates of x on the basis of lat."}, {"alglatelement",0,(void*)alglatelement,11,"GGG","alglatelement(al,lat,c): returns the element of al whose coordinates on the Z-basis of lat are c."}, {"alglathnf",0,(void*)alglathnf,11,"GGD0,G,","alglathnf(al,m,{d=0}): the lattice generated by the columns of m, assuming that this lattice contains d times the integral basis of al."}, {"alglatindex",0,(void*)alglatindex,11,"GGG","alglatindex(al,lat1,lat2): the generalized index (lat2:lat1)."}, {"alglatinter",0,(void*)alglatinter,11,"GGGD&","alglatinter(al,lat1,lat2,{&ptsum}): the intersection of the lattices lat1 and lat2. If ptsum is present, sets it to the sum of the lattices."}, {"alglatlefttransporter",0,(void*)alglatlefttransporter,11,"GGG","alglatlefttransporter(al,lat1,lat2): the set of x in al such that x*lat1 is contained in lat2."}, {"alglatmul",0,(void*)alglatmul,11,"GGG","alglatmul(al,lat1,lat2): the lattice generated by the products of elements of lat1 and lat2."}, {"alglatrighttransporter",0,(void*)alglatrighttransporter,11,"GGG","alglatrighttransporter(al,lat1,lat2): the set of x in al such that lat1*x is contained in lat2."}, {"alglatsubset",0,(void*)alglatsubset,11,"iGGGD&","alglatsubset(al,lat1,lat2,{&ptindex}): tests whether lat1 is contained in lat2 and if true and ptindex is present, sets it to the index (lat2:lat1)."}, {"algmakeintegral",0,(void*)algmakeintegral,11,"GD0,L,","algmakeintegral(mt,{maps=0}): computes an integral multiplication table for an isomorphic algebra."}, {"algmul",0,(void*)algmul,11,"GGG","algmul(al,x,y): element x*y in al."}, {"algmultable",0,(void*)algmultable,11,"mG","algmultable(al): multiplication table of al over its prime subfield."}, {"algneg",0,(void*)algneg,11,"GG","algneg(al,x): element -x in al."}, {"algnorm",0,(void*)algnorm,11,"GGD0,L,","algnorm(al,x,{abs=0}): (reduced) norm of x."}, {"algpoleval",0,(void*)algpoleval,11,"GGG","algpoleval(al,T,b): T in K[X] evaluate T(b) in al."}, {"algpow",0,(void*)algpow,11,"GGG","algpow(al,x,n): element x^n in al."}, {"algprimesubalg",0,(void*)algprimesubalg,11,"G","algprimesubalg(al): prime subalgebra of the positive characteristic, semisimple algebra al."}, {"algquotient",0,(void*)alg_quotient,11,"GGD0,L,","algquotient(al,I,{maps=0}): quotient of the algebra al by the two-sided ideal I."}, {"algradical",0,(void*)algradical,11,"G","algradical(al): Jacobson radical of the algebra al."}, {"algramifiedplaces",0,(void*)algramifiedplaces,11,"G","algramifiedplaces(al): vector of the places of the center of al that ramify in al. Each place is described as an integer between 1 and r1 or as a prime ideal."}, {"algrandom",0,(void*)algrandom,11,"GG","algrandom(al,b): random element in al with coefficients in [-b,b]."}, {"algrelmultable",0,(void*)algrelmultable,11,"mG","algrelmultable(al): multiplication table of the central simple algebra al over its center."}, {"algsimpledec",0,(void*)algsimpledec,11,"GD0,L,","algsimpledec(al,{maps=0}): [J,dec] where J is the Jacobson radical of al and dec is the decomposition into simple algebras of the semisimple algebra al/J."}, {"algsplit",0,(void*)algsplit,11,"GDn","algsplit(al,{v='x}): computes an isomorphism between al and M_d(F_q)."}, {"algsplittingdata",0,(void*)algsplittingdata,11,"mG","algsplittingdata(al): data stored in the central simple algebra al to compute a splitting of al over an extension."}, {"algsplittingfield",0,(void*)algsplittingfield,11,"mG","algsplittingfield(al): the stored splitting field of the central simple algebra al."}, {"algsqr",0,(void*)algsqr,11,"GG","algsqr(al,x): element x^2 in al."}, {"algsub",0,(void*)algsub,11,"GGG","algsub(al,x,y): element x-y in al."}, {"algsubalg",0,(void*)algsubalg,11,"GG","algsubalg(al,B): subalgebra of al with basis B."}, {"algtableinit",0,(void*)algtableinit,11,"GDG","algtableinit(mt, {p=0}): initializes the associative algebra over Q (resp. Fp) defined by the multiplication table mt."}, {"algtensor",0,(void*)algtensor,11,"GGD1,L,","algtensor(al1,al2,{maxord=1}): tensor product of al1 and al2."}, {"algtomatrix",0,(void*)algtomatrix,11,"GGD0,L,","algtomatrix(al,x,{abs=1}): left multiplication table of x (table algebra or abs=1) or image of x under a splitting of al (CSA and abs=0)."}, {"algtrace",0,(void*)algtrace,11,"GGD0,L,","algtrace(al,x,{abs=0}): (reduced) trace of x."}, {"algtype",0,(void*)algtype,11,"lG","algtype(al): type of the algebra al."}, {"alias",0,(void*)alias0,1,"vrr","alias(newsym,sym): defines the symbol newsym as an alias for the symbol sym."}, {"allocatemem",0,(void*)gp_allocatemem,1,"vDG","allocatemem({s=0}): allocates a new stack of s bytes. doubles the stack if s is omitted."}, {"apply",0,(void*)apply0,1,"GG","apply(f, A): apply function f to each entry in A."}, {"arg",0,(void*)garg,8,"Gp","arg(x): argument of x, such that -pi= x."}, {"centerlift",0,(void*)centerlift0,3,"GDn","centerlift(x,{v}): centered lift of x. Same as lift except for intmod and padic components."}, {"characteristic",0,(void*)characteristic,3,"mG","characteristic(x): characteristic of the base ring over which x is defined."}, {"charconj",0,(void*)charconj0,5,"GG","charconj(cyc,chi): given a finite abelian group (by its elementary divisors cyc) and a character chi, return the conjugate character."}, {"chardiv",0,(void*)chardiv0,5,"GGG","chardiv(cyc, a,b): given a finite abelian group (by its elementary divisors cyc) and two characters a and b, return the character a/b."}, {"chareval",0,(void*)chareval,5,"GGGDG","chareval(G, chi, x, {z}): given an abelian group structure affording a discrete logarithm method, e.g. G = znstar(N,1) or a bnr structure, let x be an element of G and let chi be a character of G. This function returns the value of chi at x, where the encoding depends on the optional argument z; if z is omitted, we fix a canonical o-th root of 1, zeta_o, where o is the character order and return the rational number c/o where chi(x) = (zeta_o)^c."}, {"chargalois",0,(void*)chargalois,5,"GDG","chargalois(cyc,{ORD}): let cyc represent a finite abelian group G by its elementary divisors cyc, return a list of representatives for the Galois orbits of characters of G. If ORD is present, select characters depending on their orders: if ORD is a t_INT, restrict to orders less than this bound; if ORD is a t_VEC or t_VECSMALL, restrict to orders in the list."}, {"charker",0,(void*)charker0,5,"GG","charker(cyc,chi): given a finite abelian group (by its elementary divisors cyc) and a character chi, return its kernel."}, {"charmul",0,(void*)charmul0,5,"GGG","charmul(cyc, a,b): given a finite abelian group (by its elementary divisors cyc) and two characters a and b, return the product character ab."}, {"charorder",0,(void*)charorder0,5,"GG","charorder(cyc,chi): given a finite abelian group (by its elementary divisors cyc) and a character chi, return the order of chi."}, {"charpoly",0,(void*)charpoly0,7,"GDnD5,L,","charpoly(A,{v='x},{flag=5}): det(v*Id-A)=characteristic polynomial of the matrix or polmod A. flag is optional and ignored unless A is a matrix; it may be set to 0 (Le Verrier), 1 (Lagrange interpolation), 2 (Hessenberg form), 3 (Berkowitz), 4 (modular) if A is integral, or 5 (default, choose best method). Algorithms 0 (Le Verrier) and 1 (Lagrange) assume that n! is invertible, where n is the dimension of the matrix."}, {"charpow",0,(void*)charpow0,5,"GGG","charpow(cyc, a,n): given a finite abelian group (by its elementary divisors cyc) a character a and an integer n return the character a^n."}, {"chinese",0,(void*)chinese,5,"GDG","chinese(x,{y}): x,y being both intmods (or polmods) computes z in the same residue classes as x and y."}, {"cmp",0,(void*)cmp_universal,2,"iGG","cmp(x,y): compare two arbitrary objects x and y (1 if x>y, 0 if x=y, -1 if x=0} M[n+1]z^n, transform it into a continued fraction suitable for evaluation."}, {"contfracpnqn",0,(void*)contfracpnqn,5,"GD-1,L,","contfracpnqn(x, {n=-1}): [p_n,p_{n-1}; q_n,q_{n-1}] corresponding to the continued fraction x. If n >= 0 is present, returns all convergents from p_0/q_0 up to p_n/q_n."}, {"core",0,(void*)core0,5,"GD0,L,","core(n,{flag=0}): unique squarefree integer d dividing n such that n/d is a square. If (optional) flag is non-null, output the two-component row vector [d,f], where d is the unique squarefree integer dividing n such that n/d=f^2 is a square."}, {"coredisc",0,(void*)coredisc0,5,"GD0,L,","coredisc(n,{flag=0}): discriminant of the quadratic field Q(sqrt(n)). If (optional) flag is non-null, output a two-component row vector [d,f], where d is the discriminant of the quadratic field Q(sqrt(n)) and n=df^2. f may be a half integer."}, {"cos",0,(void*)gcos,8,"Gp","cos(x): cosine of x."}, {"cosh",0,(void*)gcosh,8,"Gp","cosh(x): hyperbolic cosine of x."}, {"cotan",0,(void*)gcotan,8,"Gp","cotan(x): cotangent of x."}, {"cotanh",0,(void*)gcotanh,8,"Gp","cotanh(x): hyperbolic cotangent of x."}, {"dbg_x",0,(void*)dbgGEN,1,"vGD-1,L,","dbg_x(A,{n}): print inner structure of A, complete if n is omitted, up to level n otherwise. Intended for debugging."}, {"default",0,(void*)default0,1,"DrDs","default({key},{val}): returns the current value of the default key. If val is present, set opt to val first. If no argument is given, print a list of all defaults as well as their values."}, {"denominator",0,(void*)denominator,3,"GDG","denominator(f,{D}): denominator of f."}, {"deriv",0,(void*)deriv,6,"GDn","deriv(x,{v}): derivative of x with respect to v, or to the main variable of x if v is omitted."}, {"derivnum",0,(void*)derivnum0,9,"V=GEDGp","derivnum(X=a,expr,{ind=1}): numerical derivation of expr with respect to X at X = a. The order of derivation is given by parameter 'ind'."}, {"diffop",0,(void*)diffop0,6,"GGGD1,L,","diffop(x,v,d,{n=1}): apply the differential operator D to x, where D is defined by D(v[i])=d[i], where v is a vector of variable names. D is 0 for variables outside of v unless they appear as modulus of a POLMOD. If the optional parameter n is given, return D^n(x) instead."}, {"digits",0,(void*)digits,3,"GDG","digits(x,{b=10}): gives the vector formed by the digits of x in base b (x and b integers)."}, {"dilog",0,(void*)dilog,8,"Gp","dilog(x): dilogarithm of x."}, {"dirdiv",0,(void*)dirdiv,5,"GG","dirdiv(x,y): division of the Dirichlet series x by the Dirichlet series y."}, {"direuler",0,(void*)direuler0,5,"V=GGEDG","direuler(p=a,b,expr,{c}): Dirichlet Euler product of expression expr from p=a to p=b, limited to b terms. Expr should be a polynomial or rational function in p and X, and X is understood to mean p^(-s). If c is present, output only the first c terms."}, {"dirmul",0,(void*)dirmul,5,"GG","dirmul(x,y): multiplication of the Dirichlet series x by the Dirichlet series y."}, {"dirzetak",0,(void*)dirzetak,10,"GG","dirzetak(nf,b): Dirichlet series of the Dedekind zeta function of the number field nf up to the bound b-1."}, {"divisors",0,(void*)divisors0,5,"GD0,L,","divisors(x,{flag=0}): gives a vector formed by the divisors of x in increasing order. If flag = 1, return pairs [d, factor(d)]."}, {"divisorslenstra",0,(void*)divisorslenstra,5,"GGG","divisorslenstra(N, r, s): finds all divisors d of N such that d = r (mod s). Assume that (r,s) = 1 and s^3 > N."}, {"divrem",0,(void*)divrem,2,"GGDn","divrem(x,y,{v}): euclidean division of x by y giving as a 2-dimensional column vector the quotient and the remainder, with respect to v (to main variable if v is omitted)."}, {"eint1",0,(void*)veceint1,8,"GDGp","eint1(x,{n}): exponential integral E1(x). If n is present and x > 0, computes the vector of the first n values of the exponential integral E1(n x)."}, {"ellL1",0,(void*)ellL1_bitprec,12,"GD0,L,b","ellL1(E, {r = 0}): returns the value at s=1 of the derivative of order r of the L-function of the elliptic curve E."}, {"elladd",0,(void*)elladd,12,"GGG","elladd(E,z1,z2): sum of the points z1 and z2 on elliptic curve E."}, {"ellak",0,(void*)akell,12,"GG","ellak(E,n): computes the n-th Fourier coefficient of the L-function of the elliptic curve E (assumes E is an integral model)."}, {"ellan",0,(void*)ellan,12,"GL","ellan(E,n): computes the first n Fourier coefficients of the L-function of the elliptic curve E defined over a number field (n<2^24 on a 32-bit machine)."}, {"ellanalyticrank",0,(void*)ellanalyticrank_bitprec,12,"GDGb","ellanalyticrank(E, {eps}): returns the order of vanishing at s=1 of the L-function of the elliptic curve E and the value of the first non-zero derivative. To determine this order, it is assumed that any value less than eps is zero. If no value of eps is given, 2^(-bitprecision/2) is used."}, {"ellap",0,(void*)ellap,12,"GDG","ellap(E,{p}): given an elliptic curve E defined over a finite field Fq, return the trace of Frobenius a_p = q+1-#E(Fq); for other fields of definition K, p must define a finite residue field, (p prime for K = Qp or Q; p a maximal ideal for K a number field), return the order of the (non-singular) reduction of E."}, {"ellbil",0,(void*)bilhell,12,"GGGp","ellbil(E,z1,z2): deprecated alias for ellheight(E,P,Q)."}, {"ellbsd",0,(void*)ellbsd,12,"Gp","ellbsd(E): E being an elliptic curve over a number field, returns a real number c such that the BSD conjecture predicts that lfun(E,1,r)/r! = c*R*S where r is the rank, R is the regulator and S is the cardinal of the Tate-Shafarevich group."}, {"ellcard",0,(void*)ellcard,12,"GDG","ellcard(E,{p}): given an elliptic curve E defined over a finite field Fq, return the order of the group E(Fq); for other fields of definition K, p must define a finite residue field, (p prime for K = Qp or Q; p a maximal ideal for K a number field), return the order of the (non-singular) reduction of E."}, {"ellchangecurve",0,(void*)ellchangecurve,12,"GG","ellchangecurve(E,v): change data on elliptic curve according to v=[u,r,s,t]."}, {"ellchangepoint",0,(void*)ellchangepoint,12,"GG","ellchangepoint(x,v): change data on point or vector of points x on an elliptic curve according to v=[u,r,s,t]."}, {"ellchangepointinv",0,(void*)ellchangepointinv,12,"GG","ellchangepointinv(x,v): change data on point or vector of points x on an elliptic curve according to v=[u,r,s,t], inverse of ellchangepoint."}, {"ellconvertname",0,(void*)ellconvertname,12,"G","ellconvertname(name): convert an elliptic curve name (as found in the elldata database) from a string to a triplet [conductor, isogeny class, index]. It will also convert a triplet back to a curve name."}, {"elldivpol",0,(void*)elldivpol,12,"GLDn","elldivpol(E,n,{v='x}): n-division polynomial f_n for the curve E in the variable v."}, {"elleisnum",0,(void*)elleisnum,12,"GLD0,L,p","elleisnum(w,k,{flag=0}): k being an even positive integer, computes the numerical value of the Eisenstein series of weight k at the lattice w, as given by ellperiods. When flag is non-zero and k=4 or 6, this gives the elliptic invariants g2 or g3 with the correct normalization."}, {"elleta",0,(void*)elleta,12,"Gp","elleta(w): w=[w1,w2], returns the vector [eta1,eta2] of quasi-periods attached to [w1,w2]."}, {"ellformaldifferential",0,(void*)ellformaldifferential,12,"GDPDn","ellformaldifferential(E, {n=seriesprecision}, {t = 'x}) : E elliptic curve, n integer. Returns n terms of the power series [f, g] such that omega = dx/(2y+a_1x+a_3) = f(t) dt and eta = x(t) * omega = g(t) dt in the local parameter t=-x/y."}, {"ellformalexp",0,(void*)ellformalexp,12,"GDPDn","ellformalexp(E, {n = seriesprecision}, {z = 'x}) : E elliptic curve, returns n terms of the formal elliptic exponential on E as a series in z."}, {"ellformallog",0,(void*)ellformallog,12,"GDPDn","ellformallog(E, {n = seriesprecision}, {v = 'x}): E elliptic curve, returns n terms of the elliptic logarithm as a series of t =-x/y."}, {"ellformalpoint",0,(void*)ellformalpoint,12,"GDPDn","ellformalpoint(E, {n = seriesprecision}, {v = 'x}): E elliptic curve, n integer; return the coordinates [x(t), y(t)] on the elliptic curve as a formal expansion in the formal parameter t = -x/y."}, {"ellformalw",0,(void*)ellformalw,12,"GDPDn","ellformalw(E, {n = seriesprecision}, {t = 'x}): E elliptic curve, n integer; returns n terms of the formal expansion of w = -1/y in the formal parameter t = -x/y."}, {"ellfromeqn",0,(void*)ellfromeqn,12,"G","ellfromeqn(P): given a genus 1 plane curve, defined by the affine equation f(x,y) = 0, return the coefficients [a1,a2,a3,a4,a6] of a Weierstrass equation for its Jacobian. This allows to recover a Weierstrass model for an elliptic curve given by a general plane cubic or by a binary quartic or biquadratic model."}, {"ellfromj",0,(void*)ellfromj,12,"G","ellfromj(j): returns the coefficients [a1,a2,a3,a4,a6] of a fixed elliptic curve with j-invariant j."}, {"ellgenerators",0,(void*)ellgenerators,12,"G","ellgenerators(E): if E is an elliptic curve over the rationals, return the generators of the Mordell-Weil group attached to the curve. This relies on the curve being referenced in the elldata database. If E is an elliptic curve over a finite field Fq as output by ellinit(), return a minimal set of generators for the group E(Fq)."}, {"ellglobalred",0,(void*)ellglobalred,12,"G","ellglobalred(E): E being an elliptic curve over a number field, returns [N, v, c, faN, L], where N is the conductor of E, c is the product of the local Tamagawa numbers c_p, faN is the factorization of N and L[i] is elllocalred(E, faN[i,1]); v is an obsolete field."}, {"ellgroup",0,(void*)ellgroup0,12,"GDGD0,L,","ellgroup(E,{p},{flag}): given an elliptic curve E defined over a finite field Fq, return the structure of the group E(Fq); for other fields of definition K, p must define a finite residue field (p prime for K = Qp or Q; p a maximal ideal for K a number field) and we return the structure of the (non-singular) reduction of E. If flag is 1, return also generators, the curve equation must be minimal at p."}, {"ellheegner",0,(void*)ellheegner,12,"G","ellheegner(E): return a rational non-torsion point on the elliptic curve E assumed to be of rank 1."}, {"ellheight",0,(void*)ellheight0,12,"GGDGp","ellheight(E,P,{Q}): canonical height of point P on elliptic curve E, resp. the value of the attached bilinear form at (P,Q)."}, {"ellheightmatrix",0,(void*)ellheightmatrix,12,"GGp","ellheightmatrix(E,x): gives the height matrix for vector of points x on elliptic curve E."}, {"ellidentify",0,(void*)ellidentify,12,"G","ellidentify(E): look up the elliptic curve E in the elldata database and return [[N, M, ...], C] where N is the name of the curve in Cremona's database, M the minimal model and C the coordinates change (see ellchangecurve)."}, {"ellinit",0,(void*)ellinit,12,"GDGp","ellinit(x,{D=1}): let x be a vector [a1,a2,a3,a4,a6], or [a4,a6] if a1=a2=a3=0, defining the curve Y^2 + a1.XY + a3.Y = X^3 + a2.X^2 + a4.X + a6; x can also be a string, in which case the curve with matching name is retrieved from the elldata database, if available. This function initializes an elliptic curve over the domain D (inferred from coefficients if omitted)."}, {"ellintegralmodel",0,(void*)ellintegralmodel,12,"GD&","ellintegralmodel(E,{&v}): given an elliptic curve E defined over a number field or Qp, returns an integral model. If v is present, sets the variable v to the corresponding change of variable."}, {"ellisdivisible",0,(void*)ellisdivisible,12,"lGGGD&","ellisdivisible(E,P,n,{&Q}): given E/K and P in E(K), checks whether P = [n]R for some R in E(K) and sets Q to one such R if so; the integer n >= 0 may be given as ellxn(E,n)."}, {"ellisogeny",0,(void*)ellisogeny,12,"GGD0,L,DnDn","ellisogeny(E, G, {only_image = 0}, {x = 'x}, {y = 'y}): compute the image and isogeny corresponding to the quotient of E by the subgroup G."}, {"ellisogenyapply",0,(void*)ellisogenyapply,12,"GG","ellisogenyapply(f, g): given an isogeny f and g either a point P (in the domain of f) or an isogeny, apply f to g: return the image of P under f or the composite isogeny f o g."}, {"ellisomat",0,(void*)ellisomat,12,"GD0,L,D0,L,","ellisomat(E, {p=0}, {fl=0}): E being an elliptic curve over a number field, return a list of representatives of the isomorphism classes of elliptic curves isogenous to E, with the corresponding isogenies from E and their dual, and the matrix of the degrees of the isogenies between the curves. If the flag fl is 1, the isogenies are not computed, which saves time. If p is set, it must be a prime number: in this case only isogenies of degree a power of p are considered. Currently CM curves over a number field are not fully supported."}, {"ellisoncurve",0,(void*)ellisoncurve,12,"GG","ellisoncurve(E,z): true(1) if z is on elliptic curve E, false(0) if not."}, {"ellisotree",0,(void*)ellisotree,12,"G","ellisotree(E): E being an elliptic curve over Q or a set of isogenous rational curves as given by ellisomat, return minimal models of the isomorphism classes of elliptic curves isogenous to E (or in the set) and the oriented graph of isogenies of prime degree (adjacency matrix)."}, {"ellissupersingular",0,(void*)ellissupersingular,12,"iGDG","ellissupersingular(E,{p}): return 1 if the elliptic curve E, defined over a number field or a finite field, is supersingular at p, and 0 otherwise."}, {"ellj",0,(void*)jell,12,"Gp","ellj(x): elliptic j invariant of x."}, {"elllocalred",0,(void*)elllocalred,12,"GDG","elllocalred(E,{p}): E being an elliptic curve, returns [f,kod,[u,r,s,t],c], where f is the conductor's exponent, kod is the Kodaira type for E at p, [u,r,s,t] is the change of variable needed to make E minimal at p, and c is the local Tamagawa number c_p."}, {"elllog",0,(void*)elllog,12,"GGGDG","elllog(E,P,G,{o}): return the discrete logarithm of the point P of the elliptic curve E in base G. If present, o represents the order of G. If not present, assume that G generates the curve."}, {"elllseries",0,(void*)elllseries,12,"GGDGp","elllseries(E,s,{A=1}): L-series at s of the elliptic curve E, where A a cut-off point close to 1."}, {"ellminimaldisc",0,(void*)ellminimaldisc,12,"G","ellminimaldisc(E): E being an elliptic curve defined over a number field output by ellinit, return the minimal discriminant ideal of E."}, {"ellminimalmodel",0,(void*)ellminimalmodel,12,"GD&","ellminimalmodel(E,{&v}): determines whether the elliptic curve E defined over a number field admits a global minimal model. If so return it and sets v to the corresponding change of variable. Else return the (non-principal) Weierstrass class of E."}, {"ellminimaltwist",0,(void*)ellminimaltwist0,12,"GD0,L,","ellminimaltwist(E, {flag=0}): E being an elliptic curve defined over Q, return a discriminant D such that the twist of E by D is minimal among all possible quadratic twists, i.e., if flag=0, its minimal model has minimal discriminant, or if flag=1, it has minimal conductor."}, {"ellmoddegree",0,(void*)ellmoddegree,12,"G","ellmoddegree(e): e being an elliptic curve defined over Q output by ellinit, compute the modular degree of e divided by the square of the Manin constant."}, {"ellmodulareqn",0,(void*)ellmodulareqn,12,"LDnDn","ellmodulareqn(N,{x},{y}): given a prime N < 500, return a vector [P, t] where P(x,y) is a modular equation of level N. This requires the package seadata. The equation is either of canonical type (t=0) or of Atkin type (t=1)."}, {"ellmul",0,(void*)ellmul,12,"GGG","ellmul(E,z,n): n times the point z on elliptic curve E (n in Z)."}, {"ellneg",0,(void*)ellneg,12,"GG","ellneg(E,z): opposite of the point z on elliptic curve E."}, {"ellnonsingularmultiple",0,(void*)ellnonsingularmultiple,12,"GG","ellnonsingularmultiple(E,P): given E/Q and P in E(Q), returns the pair [R,n] where n is the least positive integer such that R = [n]P has everywhere good reduction. More precisely, its image in a minimal model is everywhere non-singular."}, {"ellorder",0,(void*)ellorder,12,"GGDG","ellorder(E,z,{o}): order of the point z on the elliptic curve E over a number field or a finite field, 0 if non-torsion. The parameter o, if present, represents a non-zero multiple of the order of z."}, {"ellordinate",0,(void*)ellordinate,12,"GGp","ellordinate(E,x): y-coordinates corresponding to x-ordinate x on elliptic curve E."}, {"ellpadicL",0,(void*)ellpadicL,12,"GGLDGD0,L,DG","ellpadicL(E, p, n, {s = 0}, {r = 0}, {D = 1}): returns the value on a character of Z_p^* represented by an integer s or a vector [s1,s2] of the derivative of order r of the p-adic L-function of the elliptic curve E (twisted by D, if present)."}, {"ellpadicbsd",0,(void*)ellpadicbsd,12,"GGLDG","ellpadicbsd(E, p, n, {D = 1}): returns [r,Lp] where r is the (conjectural) analytic rank of the p-adic L-function attached to the quadratic twist E_D and Lp is (conjecturally) equal to the product of the p-adic regulator and the cardinal of the Tate-Shafarevich group."}, {"ellpadicfrobenius",0,(void*)ellpadicfrobenius,12,"GLL","ellpadicfrobenius(E,p,n): matrix of the Frobenius at p>2 in the standard basis of H^1_dR(E) to absolute p-adic precision p^n."}, {"ellpadicheight",0,(void*)ellpadicheight0,12,"GGLGDG","ellpadicheight(E,p,n, P,{Q}): E elliptic curve/Q, P in E(Q), p prime, n an integer; returns the cyclotomic p-adic heights of P. Resp. the value of the attached bilinear form at (P,Q)."}, {"ellpadicheightmatrix",0,(void*)ellpadicheightmatrix,12,"GGLG","ellpadicheightmatrix(E,p,n,Q): gives the height-pairing matrix for vector of points Q on elliptic curve E."}, {"ellpadiclog",0,(void*)ellpadiclog,12,"GGLG","ellpadiclog(E,p,n,P): returns the logarithm of P (in the kernel of reduction) to relative p-adic precision p^n."}, {"ellpadicregulator",0,(void*)ellpadicregulator,12,"GGLG","ellpadicregulator(E,p,n,S): E elliptic curve/Q, S a vector of points in E(Q), p prime, n an integer; returns the p-adic cyclotomic regulator of the points of S at precision p^n."}, {"ellpadics2",0,(void*)ellpadics2,12,"GGL","ellpadics2(E,p,n): returns s2 to absolute p-adic precision p^n."}, {"ellperiods",0,(void*)ellperiods,12,"GD0,L,p","ellperiods(w, {flag = 0}): w describes a complex period lattice ([w1,w2] or an ellinit structure). Returns normalized periods [W1,W2] generating the same lattice such that tau := W1/W2 satisfies Im(tau) > 0 and lies in the standard fundamental domain for SL2. If flag is 1, the return value is [[W1,W2], [e1,e2]], where e1, e2 are the quasi-periods attached to [W1,W2], satisfying e2 W1 - e1 W2 = 2*I*Pi."}, {"ellpointtoz",0,(void*)zell,12,"GGp","ellpointtoz(E,P): lattice point z corresponding to the point P on the elliptic curve E."}, {"ellpow",0,(void*)ellmul,12,"GGG","ellpow(E,z,n): deprecated alias for ellmul."}, {"ellratpoints",0,(void*)ellratpoints,12,"GGD0,L,","ellratpoints(E,h,{flag=0}): E being an integral model of an elliptic curve, return a vector containing the affine rational points on the curve of naive height less than h. If fl=1, stop as soon as a point is found."}, {"ellrootno",0,(void*)ellrootno,12,"lGDG","ellrootno(E,{p}): root number for the L-function of the elliptic curve E/Q at a prime p (including 0, for the infinite place); global root number if p is omitted. If p is omitted, the curve can also be defined over a number field."}, {"ellsea",0,(void*)ellsea,12,"GD0,L,","ellsea(E,{tors=0}): computes the order of the group E(Fq) for the elliptic curve E, defined over a finite field, using SEA algorithm, with early abort for curves (or their quadratic twist) with non-prime order."}, {"ellsearch",0,(void*)ellsearch,12,"G","ellsearch(N): returns all curves in the elldata database matching constraint N: given name (N = \"11a1\" or [11,0,1]), given isogeny class (N = \"11a\" or [11,0]), or given conductor (N = 11, \"11\", or [11])."}, {"ellsigma",0,(void*)ellsigma,12,"GDGD0,L,p","ellsigma(L,{z='x},{flag=0}): computes the value at z of the Weierstrass sigma function attached to the lattice L, as given by ellperiods(,1). If flag = 1, returns an arbitrary determination of the logarithm of sigma."}, {"ellsub",0,(void*)ellsub,12,"GGG","ellsub(E,z1,z2): difference of the points z1 and z2 on elliptic curve E."}, {"elltamagawa",0,(void*)elltamagawa,12,"G","elltamagawa(E): E being an elliptic curve over a number field, returns the global Tamagawa number of the curve."}, {"elltaniyama",0,(void*)elltaniyama,12,"GDP","elltaniyama(E, {d = seriesprecision}): modular parametrization of elliptic curve E/Q."}, {"elltatepairing",0,(void*)elltatepairing,12,"GGGG","elltatepairing(E, P, Q, m): computes the Tate pairing of the two points P and Q on the elliptic curve E. The point P must be of m-torsion."}, {"elltors",0,(void*)elltors,12,"G","elltors(E): torsion subgroup of elliptic curve E: order, structure, generators."}, {"elltwist",0,(void*)elltwist,12,"GDG","elltwist(E,{P}): returns the coefficients [a1,a2,a3,a4,a6] of the twist of the elliptic curve E by the quadratic extension defined by P (when P is a polynomial of degree 2) or quadpoly(P) (when P is an integer). If E is defined over a finite field, then P can be omitted."}, {"ellweilcurve",0,(void*)ellweilcurve,12,"GD&","ellweilcurve(E, {&ms}): let E be an elliptic curve over Q given by ellinit or a rational isogeny class given by ellisomat. Return a list of isomorphism classes of elliptic curves isogenous to E as given by ellisomat and the list of the Smith invariants of the lattice associated to E in H^1(E,Q) in the lattice associated to the modular form. If ms is present, it contains the output of msfromell(Emin,0) where Emin is the list of minimal models attached to the curves in the isogeny class."}, {"ellweilpairing",0,(void*)ellweilpairing,12,"GGGG","ellweilpairing(E, P, Q, m): computes the Weil pairing of the two points of m-torsion P and Q on the elliptic curve E."}, {"ellwp",0,(void*)ellwp0,12,"GDGD0,L,p","ellwp(w,{z='x},{flag=0}): computes the value at z of the Weierstrass P function attached to the lattice w, as given by ellperiods. Optional flag means 0 (default), compute only P(z), 1 compute [P(z),P'(z)]."}, {"ellxn",0,(void*)ellxn,12,"GLDn","ellxn(E,n,{v='x}): return the polynomials [phi_n, (psi_n)^2] in the variable v, where x([n]P) = phi_n/(psi_n)^2."}, {"ellzeta",0,(void*)ellzeta,12,"GDGp","ellzeta(w,{z='x}): computes the value at z of the Weierstrass Zeta function attached to the lattice w, as given by ellperiods(,1)."}, {"ellztopoint",0,(void*)pointell,12,"GGp","ellztopoint(E,z): inverse of ellpointtoz. Returns the coordinates of point P on the curve E corresponding to a complex or p-adic z."}, {"erfc",0,(void*)gerfc,8,"Gp","erfc(x): complementary error function."}, {"errname",0,(void*)errname,1,"G","errname(E): returns the type of the error message E."}, {"error",0,(void*)error0,1,"vs*","error({str}*): abort script with error message str."}, {"eta",0,(void*)eta0,8,"GD0,L,p","eta(z,{flag=0}): if flag=0, returns prod(n=1,oo, 1-q^n), where q = exp(2 i Pi z) if z is a complex scalar (belonging to the upper half plane); q = z if z is a p-adic number or can be converted to a power series. If flag is non-zero, the function only applies to complex scalars and returns the true eta function, with the factor q^(1/24) included."}, {"eulerphi",0,(void*)eulerphi,5,"G","eulerphi(x): Euler's totient function of x."}, {"eval",0,(void*)geval_gp,6,"GC","eval(x): evaluation of x, replacing variables by their value."}, {"exp",0,(void*)gexp,8,"Gp","exp(x): exponential of x."}, {"expm1",0,(void*)gexpm1,8,"Gp","expm1(x): exp(x)-1."}, {"exponent",0,(void*)gpexponent,3,"G","exponent(x): binary exponent of x"}, {"extern",0,(void*)gpextern,1,"s","extern(str): execute shell command str, and feeds the result to GP (as if loading from file)."}, {"externstr",0,(void*)externstr,1,"s","externstr(str): execute shell command str, and returns the result as a vector of GP strings, one component per output line."}, {"factor",0,(void*)factor0,5,"GDG","factor(x,{D}): factorization of x over domain D. If x and D are both integers, return partial factorization, using primes < D."}, {"factorback",0,(void*)factorback2,5,"GDG","factorback(f,{e}): given a factorization f, gives the factored object back. If e is present, f has to be a vector of the same length, and we return the product of the f[i]^e[i]."}, {"factorcantor",0,(void*)factmod,5,"GG","factorcantor(x,p): this function is obsolete, use factormod."}, {"factorff",0,(void*)factorff,5,"GDGDG","factorff(x,{p},{a}): obsolete, use factormod."}, {"factorial",0,(void*)mpfactr,5,"Lp","factorial(x): factorial of x, the result being given as a real number."}, {"factorint",0,(void*)factorint,5,"GD0,L,","factorint(x,{flag=0}): factor the integer x. flag is optional, whose binary digits mean 1: avoid MPQS, 2: avoid first-stage ECM (may fall back on it later), 4: avoid Pollard-Brent Rho and Shanks SQUFOF, 8: skip final ECM (huge composites will be declared prime)."}, {"factormod",0,(void*)factormod0,5,"GDGD0,L,","factormod(f,{D},{flag=0}): factors the polynomial f over the finite field defined by the domain D; flag is optional, and can be 0: default or 1: only the degrees of the irreducible factors are given."}, {"factormodDDF",0,(void*)factormodDDF,5,"GDG","factormodDDF(f,{D}): distinct-degree factorization of the squarefree polynomial f over the finite field defined by the domain D."}, {"factormodSQF",0,(void*)factormodSQF,5,"GDG","factormodSQF(f,{D}): squarefree factorization of the polynomial f over the finite field defined by the domain D."}, {"factornf",0,(void*)polfnf,10,"GG","factornf(x,t): this function is obsolete, use nffactor."}, {"factorpadic",0,(void*)factorpadic,6,"GGL","factorpadic(pol,p,r): p-adic factorization of the polynomial pol to precision r."}, {"ffcompomap",0,(void*)ffcompomap,5,"GG","ffcompomap(f, g): Let k, l, m be three finite fields and f a (partial) map from l to m and g a partial map from k to l, return the (partial) map f o g from k to m."}, {"ffembed",0,(void*)ffembed,5,"GG","ffembed(a, b): given two elements a and b in finite fields, return a map embedding the definition field of a to the definition field of b."}, {"ffextend",0,(void*)ffextend,5,"GGDn","ffextend(a, P, {v}): extend the field K of definition of a by a root of the polynomial P, assumed to be irreducible over K. Return [r, m] where r is a root of P in the extension field L and m is a map from K to L, see \\kbd{ffmap}. If v is given, the variable name is used to display the generator of L, else the name of the variable of P is used."}, {"fffrobenius",0,(void*)fffrobenius,5,"GD1,L,","fffrobenius(m,{n=1}): return the n-th power of the Frobenius map over the field of definition of m."}, {"ffgen",0,(void*)ffgen,5,"GDn","ffgen(k,{v = 'x}): return a generator of the finite field k (not necessarily a generator of its multiplicative group) as a t_FFELT. k can be given by its order q, the pair [p,f] with q=p^f, by an irreducible polynomial with t_INTMOD coefficients, or by a finite field element. If v is given, the variable name is used to display g, else the variable of the polynomial or finite field element, or x if only the order was given."}, {"ffinit",0,(void*)ffinit,5,"GLDn","ffinit(p,n,{v='x}): monic irreducible polynomial of degree n over F_p[v]."}, {"ffinvmap",0,(void*)ffinvmap,5,"G","ffinvmap(m): given a map m between finite fields, return a partial map that return the pre-images by the map m."}, {"fflog",0,(void*)fflog,5,"GGDG","fflog(x,g,{o}): return the discrete logarithm of the finite field element x in base g. If present, o must represents the multiplicative order of g. If no o is given, assume that g is a primitive root."}, {"ffmap",0,(void*)ffmap,5,"GG","ffmap(m, x): given a (partial) map m between two finite fields, return the image of x by m. The function is applied recursively to the component of vectors, matrices and polynomials. If m is a partial map that is not defined at x, return []"}, {"ffnbirred",0,(void*)ffnbirred0,5,"GLD0,L,","ffnbirred(q,n,{fl=0}): number of monic irreducible polynomials over F_q, of degree n (fl=0, default) or at most n (fl=1)."}, {"fforder",0,(void*)fforder,5,"GDG","fforder(x,{o}): multiplicative order of the finite field element x. Optional o represents a multiple of the order of the element."}, {"ffprimroot",0,(void*)ffprimroot,5,"GD&","ffprimroot(x, {&o}): return a primitive root of the multiplicative group of the definition field of the finite field element x (not necessarily the same as the field generated by x). If present, o is set to [ord, fa], where ord is the order of the group, and fa its factorization (useful in fflog and fforder)."}, {"fibonacci",0,(void*)fibo,4,"L","fibonacci(x): fibonacci number of index x (x C-integer)."}, {"fileclose",0,(void*)gp_fileclose,1,"vL","fileclose(n): close the file descriptor n."}, {"fileextern",0,(void*)gp_fileextern,1,"ls","fileextern(str): execute shell command str and returns a file descriptor attached to the command output as if it were read from a file."}, {"fileflush",0,(void*)gp_fileflush0,1,"vDG","fileflush({n}): flush the file descriptor n (all descriptors to output streams if n is omitted)."}, {"fileopen",0,(void*)gp_fileopen,1,"lsD\"r\",s,","fileopen(path, mode): open the file pointed to by 'path' and return a file descriptor which can be used with other file functions. The mode is \"r\" (default, read), \"w\" (write, truncate), \"a\" (write, append)."}, {"fileread",0,(void*)gp_fileread,1,"L","fileread(n): read a logical line from the file attached to the descriptor n, opened for reading with fileopen. Return 0 at end of file."}, {"filereadstr",0,(void*)gp_filereadstr,1,"L","filereadstr(n): read a raw line from the file attached to the descriptor n, opened for reading with fileopen. Discard the terminating newline. Return 0 at end of file."}, {"filewrite",0,(void*)gp_filewrite,1,"vLs","filewrite(n, s): write the string s to file attached to descriptor n, ending with a newline. The file must have been opened with fileopen in \"w\" or \"a\" mode."}, {"filewrite1",0,(void*)gp_filewrite1,1,"vLs","filewrite1(n, s): write the string s to file number n without ending with newline."}, {"floor",0,(void*)gfloor,3,"G","floor(x): floor of x = largest integer <= x."}, {"fold",0,(void*)fold0,1,"GG","fold(f, A): return f(...f(f(A[1],A[2]),A[3]),...,A[#A])."}, {"for",0,(void*)forpari,1,"vV=GGI","for(X=a,b,seq): the sequence is evaluated, X going from a up to b. If b is set to +oo, the loop will not stop."}, {"forcomposite",0,(void*)forcomposite,1,"vV=GDGI","forcomposite(n=a,{b},seq): the sequence is evaluated, n running over the composite numbers between a and b. Omitting b runs through composites >= a."}, {"fordiv",0,(void*)fordiv,1,"vGVI","fordiv(n,X,seq): the sequence is evaluated, X running over the divisors of n."}, {"fordivfactored",0,(void*)fordivfactored,1,"vGVI","fordivfactored(n,X,seq): the sequence is evaluated, X running over the [d, factor(d)], d a divisor of n."}, {"forell",0,(void*)forell0,1,"vVLLID0,L,","forell(E,a,b,seq,{flag=0}): execute seq for each elliptic curves E of conductor between a and b in the elldata database. If flag is non-zero, select only the first curve in each isogeny class."}, {"forfactored",0,(void*)forfactored,1,"vV=GGI","forfactored(N=a,b,seq): the sequence is evaluated, N is of the form [n, factor(n)], n going from a up to b."}, {"forpart",0,(void*)forpart0,1,"vV=GIDGDG","forpart(X=k,seq,{a=k},{n=k}): evaluate seq where the Vecsmall X goes over the partitions of k. Optional parameter n (n=nmax or n=[nmin,nmax]) restricts the length of the partition. Optional parameter a (a=amax or a=[amin,amax]) restricts the range of the parts. Zeros are removed unless one sets amin=0 to get X of fixed length nmax (=k by default)."}, {"forperm",0,(void*)forperm0,1,"vGVI","forperm(a,p,seq): the sequence is evaluated, p going through permutations of a."}, {"forprime",0,(void*)forprime,1,"vV=GDGI","forprime(p=a,{b},seq): the sequence is evaluated, p running over the primes between a and b. Omitting b runs through primes >= a."}, {"forprimestep",0,(void*)forprimestep,1,"vV=GDGGI","forprimestep(p=a,b,q,seq): the sequence is evaluated, p running over the primes in an arithmetic progression of the form a + k*q and less than b."}, {"forqfvec",0,(void*)forqfvec0,7,"vVGDGI","forqfvec(v,q,b,expr): q being a square and symmetric integral matrix representing an positive definite quadratic form, evaluate expr for all vectors v such that q(v)<=b."}, {"forsquarefree",0,(void*)forsquarefree,1,"vV=GGI","forsquarefree(N=a,b,seq): the sequence is evaluated, N is of the form [n, factor(n)], n going through squarefree integers from a up to b; one must have a*b >= 0."}, {"forstep",0,(void*)forstep,1,"vV=GGGI","forstep(X=a,b,s,seq): the sequence is evaluated, X going from a to b in steps of s (can be a vector of steps). If b is set to +oo the loop will not stop."}, {"forsubgroup",0,(void*)forsubgroup0,1,"vV=GDGI","forsubgroup(H=G,{bound},seq): execute seq for each subgroup H of the abelian group G, whose index is bounded by bound if not omitted. H is given as a left divisor of G in HNF form."}, {"forsubset",0,(void*)forsubset0,1,"vGVI","forsubset(nk, s, seq): if nk is an integer n, the sequence is evaluated, s going through all subsets of {1, 2, ..., n}; if nk is a pair [n,k] of integers s goes through k-subsets of {1, 2, ..., n}. The order is lexicographic among subsets of the same size and smaller subsets come first."}, {"forvec",0,(void*)forvec,1,"vV=GID0,L,","forvec(X=v,seq,{flag=0}): v being a vector of two-component vectors of length n, the sequence is evaluated with X[i] going from v[i][1] to v[i][2] for i=n,..,1 if flag is zero or omitted. If flag = 1 (resp. flag = 2), restrict to increasing (resp. strictly increasing) sequences."}, {"frac",0,(void*)gfrac,3,"G","frac(x): fractional part of x = x-floor(x)."}, {"fromdigits",0,(void*)fromdigits,3,"GDG","fromdigits(x,{b=10}): gives the integer formed by the elements of x seen as the digits of a number in base b."}, {"galoischardet",0,(void*)galoischardet,10,"GGD1,L,","galoischardet(gal, chi, {o=1}): return the determinant character of the character chi."}, {"galoischarpoly",0,(void*)galoischarpoly,10,"GGD1,L,","galoischarpoly(gal, chi, {o=1}): return the list of characteristic polynomials of the representation attached to the character chi."}, {"galoischartable",0,(void*)galoischartable,10,"G","galoischartable(gal): return the character table of the underlying group of gal."}, {"galoisconjclasses",0,(void*)galoisconjclasses,10,"G","galoisconjclasses(gal): gal being output by galoisinit, return the list of conjugacy classes."}, {"galoisexport",0,(void*)galoisexport,10,"GD0,L,","galoisexport(gal,{flag}): gal being a Galois group as output by galoisinit, output a string representing the underlying permutation group in GAP notation (default) or Magma notation (flag = 1)."}, {"galoisfixedfield",0,(void*)galoisfixedfield,10,"GGD0,L,Dn","galoisfixedfield(gal,perm,{flag},{v=y}): gal being a Galois group as output by galoisinit and perm a subgroup, an element of gal.group or a vector of such elements, return [P,x] such that P is a polynomial defining the fixed field of gal[1] by the subgroup generated by perm, and x is a root of P in gal expressed as a polmod in gal.pol. If flag is 1 return only P. If flag is 2 return [P,x,F] where F is the factorization of gal.pol over the field defined by P, where the variable v stands for a root of P."}, {"galoisgetgroup",0,(void*)galoisgetgroup,10,"LD0,L,","galoisgetgroup(a,{b}): query the galpol package for a group of order a with index b in the GAP4 Small Group library. If b is omitted, return the number of isomorphism classes of groups of order a."}, {"galoisgetname",0,(void*)galoisgetname,10,"LL","galoisgetname(a,b): query the galpol package for a string describing the group of order a with index b in the GAP4 Small Group library."}, {"galoisgetpol",0,(void*)galoisgetpol,10,"LD0,L,D1,L,","galoisgetpol(a,{b},{s}): query the galpol package for a polynomial with Galois group isomorphic to GAP4(a,b), totally real if s=1 (default) and totally complex if s=2. The output is a vector [pol, den] where pol is the polynomial and den is the common denominator of the conjugates expressed as a polynomial in a root of pol. If b and s are omitted, return the number of isomorphism classes of groups of order a."}, {"galoisidentify",0,(void*)galoisidentify,10,"G","galoisidentify(gal): gal being a Galois group as output by galoisinit, output the isomorphism class of the underlying abstract group as a two-components vector [o,i], where o is the group order, and i is the group index in the GAP4 small group library."}, {"galoisinit",0,(void*)galoisinit,10,"GDG","galoisinit(pol,{den}): pol being a polynomial or a number field as output by nfinit defining a Galois extension of Q, compute the Galois group and all necessary information for computing fixed fields. den is optional and has the same meaning as in nfgaloisconj(,4)(see manual)."}, {"galoisisabelian",0,(void*)galoisisabelian,10,"GD0,L,","galoisisabelian(gal,{flag=0}): gal being as output by galoisinit, return 0 if gal is not abelian, the HNF matrix of gal over gal.gen if flag=0, 1 if flag is 1, and the SNF of gal is flag=2."}, {"galoisisnormal",0,(void*)galoisisnormal,10,"lGG","galoisisnormal(gal,subgrp): gal being as output by galoisinit, and subgrp a subgroup of gal as output by galoissubgroups, return 1 if subgrp is a normal subgroup of gal, else return 0."}, {"galoispermtopol",0,(void*)galoispermtopol,10,"GG","galoispermtopol(gal,perm): gal being a Galois group as output by galoisinit and perm a element of gal.group, return the polynomial defining the corresponding Galois automorphism."}, {"galoissubcyclo",0,(void*)galoissubcyclo,10,"GDGD0,L,Dn","galoissubcyclo(N,H,{fl=0},{v}): compute a polynomial (in variable v) defining the subfield of Q(zeta_n) fixed by the subgroup H of (Z/nZ)*. N can be an integer n, znstar(n) or bnrinit(bnfinit(y),[n,[1]]). H can be given by a generator, a set of generator given by a vector or a HNF matrix (see manual). If flag is 1, output only the conductor of the abelian extension. If flag is 2 output [pol,f] where pol is the polynomial and f the conductor."}, {"galoissubfields",0,(void*)galoissubfields,10,"GD0,L,Dn","galoissubfields(G,{flag=0},{v}): output all the subfields of G. flag has the same meaning as for galoisfixedfield."}, {"galoissubgroups",0,(void*)galoissubgroups,10,"G","galoissubgroups(G): output all the subgroups of G."}, {"gamma",0,(void*)ggamma,8,"Gp","gamma(s): gamma function at s, a complex or p-adic number, or a series."}, {"gammah",0,(void*)ggammah,8,"Gp","gammah(x): gamma of x+1/2 (x integer)."}, {"gammamellininv",0,(void*)gammamellininv,8,"GGD0,L,b","gammamellininv(G,t,{m=0}): returns G(t), where G is as output by gammamellininvinit. The alternative syntax gammamellininv(A,t,m) is also available."}, {"gammamellininvasymp",0,(void*)gammamellininvasymp,8,"GDPD0,L,","gammamellininvasymp(A,n,{m=0}): return the first n terms of the asymptotic expansion at infinity of the m-th derivative K^m(t) of the inverse Mellin transform of the function f(s)=Gamma_R(s+a_1)*...*Gamma_R(s+a_d), where Vga is the vector [a_1,...,a_d] and Gamma_R(s)=Pi^(-s/2)*gamma(s/2). The result is a vector [M[1]...M[n]] with M[1]=1, such that K^m(t) = \\sqrt{2^{d+1}/d}t^{a+m(2/d-1)}e^{-d pi t^{2/d}}\\sum_{n\\ge0}M[n+1] (pi t^{2n/d})^{-n}, with a = (1-d+sum_ja_j)/d."}, {"gammamellininvinit",0,(void*)gammamellininvinit,8,"GD0,L,b","gammamellininvinit(A,{m=0}): initialize data for the computation by gammamellininv() of the m-th derivative of the inverse Mellin transform of the function f(s) = Gamma_R(s+a1)*...*Gamma_R(s+ad), where A is the vector [a1,...,ad] and Gamma_R(s) = Pi^(-s/2)*gamma(s/2)."}, {"gcd",0,(void*)ggcd0,5,"GDG","gcd(x,{y}): greatest common divisor of x and y."}, {"gcdext",0,(void*)gcdext0,5,"GG","gcdext(x,y): returns [u,v,d] such that d=gcd(x,y) and u*x+v*y=d."}, {"genus2red",0,(void*)genus2red,12,"GDG","genus2red(PQ,{p}): let PQ be a polynomial P, resp. a vector [P,Q] of polynomials, with rational coefficients. Determines the reduction at p > 2 of the (proper, smooth) hyperelliptic curve C/Q of genus 2 defined by y^2 = P, resp. y^2 + Q*y = P. More precisely, determines the special fiber X_p of the minimal regular model X of C over Z."}, {"getabstime",0,(void*)getabstime,1,"l","getabstime(): milliseconds of CPU time since startup."}, {"getcache",0,(void*)getcache,14,"","getcache(): returns information about various auto-growing caches. For each ressource, we report its name, its size, the number of cache misses (since the last extension) and the largest cache miss."}, {"getenv",0,(void*)gp_getenv,1,"s","getenv(s): value of the environment variable s, 0 if it is not defined."}, {"getheap",0,(void*)getheap,1,"","getheap(): 2-component vector giving the current number of objects in the heap and the space they occupy (in long words)."}, {"getrand",0,(void*)getrand,1,"","getrand(): current value of random number seed."}, {"getstack",0,(void*)getstack,1,"l","getstack(): current value of stack pointer avma."}, {"gettime",0,(void*)gettime,1,"l","gettime(): milliseconds of CPU time used since the last call to gettime."}, {"getwalltime",0,(void*)getwalltime,1,"","getwalltime(): time (in milliseconds) since the UNIX Epoch."}, {"global",0,NULL,1,NULL,"global(list of variables): obsolete. Scheduled for deletion."}, {"hammingweight",0,(void*)hammingweight,4,"lG","hammingweight(x): returns the Hamming weight of x."}, {"hilbert",0,(void*)hilbert,5,"lGGDG","hilbert(x,y,{p}): Hilbert symbol at p of x,y."}, {"hyperellcharpoly",0,(void*)hyperellcharpoly,12,"G","hyperellcharpoly(X): X being a non-singular hyperelliptic curve defined over a finite field, return the characteristic polynomial of the Frobenius automorphism. X can be given either by a squarefree polynomial P such that X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)*y=P(x) and Q^2+4P is squarefree."}, {"hyperellpadicfrobenius",0,(void*)hyperellpadicfrobenius,12,"GUL","hyperellpadicfrobenius(Q,p,n): Q being a rational polynomial of degree d and X being the curve defined by y^2=Q(x), return the matrix of the Frobenius at p>=d in the standard basis of H^1_dR(X) to absolute p-adic precision p^n."}, {"hyperellratpoints",0,(void*)hyperellratpoints,12,"GGD0,L,","hyperellratpoints(X,h,{flag=0}): X being a non-singular hyperelliptic curve given by an integral model, return a vector containing the affine rational points on the curve of naive height less than h. If fl=1, stop as soon as a point is found. X can be given either by a squarefree polynomial P such that X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)y=P(x) and Q^2+4P is squarefree."}, {"hyperu",0,(void*)hyperu,8,"GGGp","hyperu(a,b,x): U-confluent hypergeometric function."}, {"idealadd",0,(void*)idealadd,10,"GGG","idealadd(nf,x,y): sum of two ideals x and y in the number field defined by nf."}, {"idealaddtoone",0,(void*)idealaddtoone0,10,"GGDG","idealaddtoone(nf,x,{y}): if y is omitted, when the sum of the ideals in the number field K defined by nf and given in the vector x is equal to Z_K, gives a vector of elements of the corresponding ideals who sum to 1. Otherwise, x and y are ideals, and if they sum up to 1, find one element in each of them such that the sum is 1."}, {"idealappr",0,(void*)idealappr0,10,"GGD0,L,","idealappr(nf,x,{flag}): x being a fractional ideal, gives an element b such that v_p(b)=v_p(x) for all prime ideals p dividing x, and v_p(b)>=0 for all other p; x may also be a prime ideal factorization with possibly zero exponents. flag is deprecated (ignored), kept for backward compatibility."}, {"idealchinese",0,(void*)idealchinese,10,"GGDG","idealchinese(nf,x,{y}): x being a prime ideal factorization and y a vector of elements, gives an element b such that v_p(b-y_p)>=v_p(x) for all prime ideals p dividing x, and v_p(b)>=0 for all other p. If y is omitted, return a data structure which can be used in place of x in later calls."}, {"idealcoprime",0,(void*)idealcoprime,10,"GGG","idealcoprime(nf,x,y): gives an element b in nf such that b. x is an integral ideal coprime to the integral ideal y."}, {"idealdiv",0,(void*)idealdiv0,10,"GGGD0,L,","idealdiv(nf,x,y,{flag=0}): quotient x/y of two ideals x and y in HNF in the number field nf. If (optional) flag is non-null, the quotient is supposed to be an integral ideal (slightly faster)."}, {"idealfactor",0,(void*)gpidealfactor,10,"GGDG","idealfactor(nf,x,{lim}): factorization of the ideal x into prime ideals in the number field nf. If lim is set return partial factorization, using primes < lim."}, {"idealfactorback",0,(void*)idealfactorback,10,"GGDGD0,L,","idealfactorback(nf,f,{e},{flag = 0}): given a factorization f, gives the ideal product back. If e is present, f has to be a vector of the same length, and we return the product of the f[i]^e[i]. If flag is non-zero, perform idealred along the way."}, {"idealfrobenius",0,(void*)idealfrobenius,10,"GGG","idealfrobenius(nf,gal,pr): returns the Frobenius element (pr|nf/Q) attached to the unramified prime ideal pr in prid format, in the Galois group gal of the number field nf."}, {"idealhnf",0,(void*)idealhnf0,10,"GGDG","idealhnf(nf,u,{v}): hermite normal form of the ideal u in the number field nf if v is omitted. If called as idealhnf(nf,u,v), the ideal is given as uZ_K + vZ_K in the number field K defined by nf."}, {"idealintersect",0,(void*)idealintersect,10,"GGG","idealintersect(nf,A,B): intersection of two ideals A and B in the number field defined by nf."}, {"idealinv",0,(void*)idealinv,10,"GG","idealinv(nf,x): inverse of the ideal x in the number field nf."}, {"idealispower",0,(void*)idealispower,10,"lGGLD&","idealispower(nf,A,n,{&B}): return 1 if A = B^n is an n-th power else return 0."}, {"ideallist",0,(void*)ideallist0,10,"GLD4,L,","ideallist(nf,bound,{flag=4}): vector of vectors L of all idealstar of all ideals of norm<=bound. If (optional) flag is present, its binary digits are toggles meaning 1: give generators; 2: add units; 4: give only the ideals and not the bid."}, {"ideallistarch",0,(void*)ideallistarch,10,"GGG","ideallistarch(nf,list,arch): list is a vector of vectors of bid's as output by ideallist. Return a vector of vectors with the same number of components as the original list. The leaves give information about moduli whose finite part is as in original list, in the same order, and Archimedean part is now arch. The information contained is of the same kind as was present in the input."}, {"ideallog",0,(void*)ideallog,10,"DGGG","ideallog({nf},x,bid): if bid is a big ideal, as given by idealstar(nf,D,...), gives the vector of exponents on the generators bid.gen (even if these generators have not been explicitly computed)."}, {"idealmin",0,(void*)idealmin,10,"GGDG","idealmin(nf,ix,{vdir}): pseudo-minimum of the ideal ix in the direction vdir in the number field nf."}, {"idealmul",0,(void*)idealmul0,10,"GGGD0,L,","idealmul(nf,x,y,{flag=0}): product of the two ideals x and y in the number field nf. If (optional) flag is non-nul, reduce the result."}, {"idealnorm",0,(void*)idealnorm,10,"GG","idealnorm(nf,x): norm of the ideal x in the number field nf."}, {"idealnumden",0,(void*)idealnumden,10,"GG","idealnumden(nf,x): returns [A,B], where A,B are coprime integer ideals such that x = A/B."}, {"idealpow",0,(void*)idealpow0,10,"GGGD0,L,","idealpow(nf,x,k,{flag=0}): k-th power of the ideal x in HNF in the number field nf. If (optional) flag is non-null, reduce the result."}, {"idealprimedec",0,(void*)idealprimedec_limit_f,10,"GGD0,L,","idealprimedec(nf,p,{f=0}): prime ideal decomposition of the prime number p in the number field nf as a vector of prime ideals. If f is present and non-zero, restrict the result to primes of residue degree <= f."}, {"idealprincipalunits",0,(void*)idealprincipalunits,10,"GGL","idealprincipalunits(nf,pr,k): returns the structure [no, cyc, gen] of the multiplicative group (1 + pr) / (1 + pr^k)."}, {"idealramgroups",0,(void*)idealramgroups,10,"GGG","idealramgroups(nf,gal,pr): let pr be a prime ideal in prid format, and gal the Galois group of the number field nf, return a vector g such that g[1] is the decomposition group of pr, g[2] is the inertia group, g[i] is the (i-2)th ramification group of pr, all trivial subgroups being omitted."}, {"idealred",0,(void*)idealred0,10,"GGDG","idealred(nf,I,{v=0}): LLL reduction of the ideal I in the number field nf along direction v, in HNF."}, {"idealredmodpower",0,(void*)idealredmodpower,10,"GGUD0,U,","idealredmodpower(nf,x,n,{B=primelimit}): return b such that x * b^n = v is small."}, {"idealstar",0,(void*)idealstar0,10,"DGGD1,L,","idealstar({nf},N,{flag=1}): gives the structure of (Z_K/N)^*, where N is a modulus (an ideal in any form or a vector [f0, foo], where f0 is an ideal and foo is a {0,1}-vector with r1 components. flag is optional, and can be 0: simply gives the structure as an abelian group, i.e. a 3-component vector [h,d,g] where h is the order, d the orders of the cyclic factors and g the generators; if flag=1 (default), gives a bid structure used in ideallog to compute discrete logarithms; underlying generators are well-defined but not explicitly computed, which saves time; if flag=2, same as with flag=1 except that the generators are also given. If nf is omitted, N must be an integer and we return the structure of (Z/NZ)^*."}, {"idealtwoelt",0,(void*)idealtwoelt0,10,"GGDG","idealtwoelt(nf,x,{a}): two-element representation of an ideal x in the number field nf. If (optional) a is non-zero, first element will be equal to a."}, {"idealval",0,(void*)gpidealval,10,"GGG","idealval(nf,x,pr): valuation at pr given in idealprimedec format of the ideal x in the number field nf."}, {"if",0,(void*)ifpari,1,"GDEDE","if(a,{seq1},{seq2}): if a is nonzero, seq1 is evaluated, otherwise seq2. seq1 and seq2 are optional, and if seq2 is omitted, the preceding comma can be omitted also."}, {"iferr",0,(void*)iferrpari,1,"EVEDE","iferr(seq1,E,seq2,{pred}): evaluates the expression sequence seq1. If an error occurs, set the formal parameter E set to the error data. If pred is not present or evaluates to true, catch the error and evaluate seq2. Both pred and seq2 can reference E."}, {"imag",0,(void*)gimag,3,"G","imag(x): imaginary part of x."}, {"incgam",0,(void*)incgam0,8,"GGDGp","incgam(s,x,{g}): incomplete gamma function. g is optional and is the precomputed value of gamma(s)."}, {"incgamc",0,(void*)incgamc,8,"GGp","incgamc(s,x): complementary incomplete gamma function."}, {"inline",0,NULL,1,NULL,"inline(x,...,z): declares x,...,z as inline variables [EXPERIMENTAL]."}, {"input",0,(void*)gp_input,1,"","input(): read an expression from the input file or standard input."}, {"install",0,(void*)gpinstall,1,"vrrD\"\",r,D\"\",s,","install(name,code,{gpname},{lib}): load from dynamic library 'lib' the function 'name'. Assign to it the name 'gpname' in this GP session, with prototype 'code'. If 'lib' is omitted, all symbols known to gp (includes the whole 'libpari.so' and possibly others) are available. If 'gpname' is omitted, use 'name'."}, {"intcirc",0,(void*)intcirc0,9,"V=GGEDGp","intcirc(X=a,R,expr,{tab}): numerical integration of expr on the circle |z-a|=R, divided by 2*I*Pi. tab is as in intnum."}, {"intformal",0,(void*)integ,6,"GDn","intformal(x,{v}): formal integration of x with respect to v, or to the main variable of x if v is omitted."}, {"intfuncinit",0,(void*)intfuncinit0,9,"V=GGED0,L,p","intfuncinit(t=a,b,f,{m=0}): initialize tables for integrations from a to b using a weight f(t). For integral transforms such as Fourier or Mellin transforms."}, {"intnum",0,(void*)intnum0,9,"V=GGEDGp","intnum(X=a,b,expr,{tab}): numerical integration of expr from a to b with respect to X. Plus/minus infinity is coded as +oo/-oo. Finally tab is either omitted (let the program choose the integration step), a non-negative integer m (divide integration step by 2^m), or data precomputed with intnuminit."}, {"intnumgauss",0,(void*)intnumgauss0,9,"V=GGEDGp","intnumgauss(X=a,b,expr,{tab}): numerical integration of expr from a to b, a compact interval, with respect to X using Gauss-Legendre quadrature. tab is either omitted (and will be recomputed) or precomputed with intnumgaussinit."}, {"intnumgaussinit",0,(void*)intnumgaussinit,9,"D0,L,p","intnumgaussinit({n}): initialize tables for n-point Gauss-Legendre integration on a compact interval."}, {"intnuminit",0,(void*)intnuminit,9,"GGD0,L,p","intnuminit(a,b,{m=0}): initialize tables for integrations from a to b. See help for intnum for coding of a and b. Possible types: compact interval, semi-compact (one extremity at + or - infinity) or R, and very slowly, slowly or exponentially decreasing, or sine or cosine oscillating at infinities."}, {"intnumromb",0,(void*)intnumromb0_bitprec,9,"V=GGED0,L,b","intnumromb(X=a,b,expr,{flag=0}): numerical integration of expr (smooth in ]a,b[) from a to b with respect to X. flag is optional and mean 0: default. expr can be evaluated exactly on [a,b]; 1: general function; 2: a or b can be plus or minus infinity (chosen suitably), but of same sign; 3: expr has only limits at a or b."}, {"isfundamental",0,(void*)isfundamental,5,"lG","isfundamental(D): true(1) if D is a fundamental discriminant (including 1), false(0) if not."}, {"ispolygonal",0,(void*)ispolygonal,5,"lGGD&","ispolygonal(x,s,{&N}): true(1) if x is an s-gonal number, false(0) if not (s > 2). If N is given set it to n if x is the n-th s-gonal number."}, {"ispower",0,(void*)ispower,5,"lGDGD&","ispower(x,{k},{&n}): if k > 0 is given, return true (1) if x is a k-th power, false (0) if not. If k is omitted, return the maximal k >= 2 such that x = n^k is a perfect power, or 0 if no such k exist. If n is present, and the function returns a non-zero result, set n to the k-th root of x."}, {"ispowerful",0,(void*)ispowerful,5,"lG","ispowerful(x): true(1) if x is a powerful integer (valuation at all primes dividing x is greater than 1), false(0) if not."}, {"isprime",0,(void*)gisprime,5,"GD0,L,","isprime(x,{flag=0}): true(1) if x is a (proven) prime number, false(0) if not. If flag is 0 or omitted, use a combination of algorithms. If flag is 1, the primality is certified by the Pocklington-Lehmer Test. If flag is 2, the primality is certified using the APRCL test. If flag is 3, use ECPP."}, {"isprimepower",0,(void*)isprimepower,5,"lGD&","isprimepower(x,{&n}): if x = p^k is a prime power (p prime, k > 0), return k, else return 0. If n is present, and the function returns a non-zero result, set n to p, the k-th root of x."}, {"ispseudoprime",0,(void*)gispseudoprime,5,"GD0,L,","ispseudoprime(x,{flag}): true(1) if x is a strong pseudoprime, false(0) if not. If flag is 0 or omitted, use BPSW test, otherwise use strong Rabin-Miller test for flag randomly chosen bases."}, {"ispseudoprimepower",0,(void*)ispseudoprimepower,5,"lGD&","ispseudoprimepower(x,{&n}): if x = p^k is a pseudo-prime power (p pseudo-prime, k > 0), return k, else return 0. If n is present, and the function returns a non-zero result, set n to p, the k-th root of x."}, {"issquare",0,(void*)issquareall,5,"lGD&","issquare(x,{&n}): true(1) if x is a square, false(0) if not. If n is given puts the exact square root there if it was computed."}, {"issquarefree",0,(void*)issquarefree,5,"lG","issquarefree(x): true(1) if x is squarefree, false(0) if not."}, {"istotient",0,(void*)istotient,5,"lGD&","istotient(x,{&N}): true(1) if x = eulerphi(n) for some integer n, false(0) if not. If N is given, set N = n as well."}, {"kill",0,(void*)kill0,1,"vr","kill(sym): restores the symbol sym to its ``undefined'' status and kill attached help messages."}, {"kronecker",0,(void*)kronecker,5,"lGG","kronecker(x,y): kronecker symbol (x/y)."}, {"lambertw",0,(void*)glambertW,8,"Gp","lambertw(y): solution of the implicit equation x*exp(x)=y."}, {"laurentseries",0,(void*)laurentseries0,9,"GDPDnp","laurentseries(f, {M = seriesprecision}, {x='x}): expand f around 0 as a Laurent series in x to order M."}, {"lcm",0,(void*)glcm0,5,"GDG","lcm(x,{y}): least common multiple of x and y, i.e. x*y / gcd(x,y) up to units."}, {"length",0,(void*)glength,3,"lG","length(x): number of non code words in x, number of characters for a string."}, {"lex",0,(void*)lexcmp,2,"iGG","lex(x,y): compare x and y lexicographically (1 if x>y, 0 if x=y, -1 if xprod(i=1,#M[,1],eta(M[i,1]*z)^M[i,2])."}, {"lfungenus2",0,(void*)lfungenus2,13,"G","lfungenus2(F): returns the Ldata structure attached to the L-function attached to the genus-2 curve defined by y^2=F(x) or y^2+Q(x)*y=P(x) if F=[P,Q]. Currently, only odd conductors are supported, and the model needs to be minimal at 2."}, {"lfunhardy",0,(void*)lfunhardy,13,"GGb","lfunhardy(L,t): variant of the Hardy L-function attached to L, used for plotting on the critical line."}, {"lfuninit",0,(void*)lfuninit0,13,"GGD0,L,b","lfuninit(L,sdom,{der=0}): precompute data for evaluating the L-function given by 'L' (and its derivatives of order der, if set) in rectangular domain sdom = [center,w,h] centered on the real axis, |Re(s)-center| <= w, |Im(s)| <= h, where all three components of sdom are real and w,h are non-negative. The subdomain [k/2, 0, h] on the critical line can be encoded as [h] for brevity."}, {"lfunlambda",0,(void*)lfunlambda0,13,"GGD0,L,b","lfunlambda(L,s,{D=0}): compute the completed L function Lambda(s), or if D is set, the derivative of order D at s. L is either an Lmath, an Ldata or an Linit."}, {"lfunmf",0,(void*)lfunmf,14,"GDGb","lfunmf(mf,{F}): If F is a modular form in mf, output the L-functions corresponding to its complex embeddings. If F is omitted, output the L-functions corresponding to all eigenforms in the new space."}, {"lfunmfspec",0,(void*)lfunmfspec,13,"Gb","lfunmfspec(L): L corresponding to a modular form, returns [valeven,valodd,omminus,omplus], where valeven (resp., valodd) is the vector of even (resp., odd) periods, and omminus and omplus the corresponding real numbers omega^- and omega^+. For the moment, only for modular forms of even weight."}, {"lfunmul",0,(void*)lfunmul,13,"GGb","lfunmul(L1,L2): creates the Ldata structure (without initialization) corresponding to the product of the Dirichlet series given by L1 and L2."}, {"lfunorderzero",0,(void*)lfunorderzero,13,"lGD-1,L,b","lfunorderzero(L, {m = -1}): computes the order of the possible zero of the L-function at the center k/2 of the critical strip. If m is given and has a non-negative value, assumes the order is at most m."}, {"lfunqf",0,(void*)lfunqf,13,"Gp","lfunqf(Q): returns the Ldata structure attached to the theta function of the lattice attached to the definite positive quadratic form Q."}, {"lfunrootres",0,(void*)lfunrootres,13,"Gb","lfunrootres(data): given the Ldata attached to an L-function (or the output of lfunthetainit), compute the root number and the residues. In the present implementation, if the polar part is not already known completely, at most a single pole is allowed. The output is a 3-component vector [[[a_1, r_1],...,[a_n, r_n],[[b_1, R_1],...[b_m,R_m]], w], where r_i is the polar part of L(s) at a_i, R_i is is the polar part of Lambda(s) at b_i, or [0,0,r] if there is no pole, and w is the root number."}, {"lfunsympow",0,(void*)lfunsympow,13,"GU","lfunsympow(E, m): returns the Ldata structure attached to the L-function attached to m-th symmetric power of the elliptic curve E defined over the rationals."}, {"lfuntheta",0,(void*)lfuntheta,13,"GGD0,L,b","lfuntheta(data,t,{m=0}): compute the value of the m-th derivative at t of the theta function attached to the L-function given by data. data can be either the standard L-function data, or the output of lfunthetainit."}, {"lfunthetacost",0,(void*)lfunthetacost0,13,"lGDGD0,L,b","lfunthetacost(L,{tdom},{m=0}): estimates the cost of running lfunthetainit(L,tdom,m) at current bit precision. Returns the number of coefficients an that would be computed. Subsequent evaluation of lfuntheta computes that many values of gammamellininv. If L is already an Linit, then tdom and m are ignored."}, {"lfunthetainit",0,(void*)lfunthetainit,13,"GDGD0,L,b","lfunthetainit(L,{tdom},{m=0}): precompute data for evaluating the m-th derivative of theta functions with argument in domain tdom (by default t is real >= 1)."}, {"lfuntwist",0,(void*)lfuntwist,13,"GG","lfuntwist(L,chi): creates the Ldata structure (without initialization) corresponding to the twist of L by the primitive character attached to the Dirichlet L-function chi. This requires that the conductor of the character is coprime to the conductor of the L-function L."}, {"lfunzeros",0,(void*)lfunzeros,13,"GGD8,L,b","lfunzeros(L,lim,{divz=8}): lim being either an upper limit or a real interval, computes an ordered list of zeros of L(s) on the critical line up to the given upper limit or in the given interval. Use a naive algorithm which may miss some zeros. To use a finer search mesh, set divz to some integral value larger than the default (= 8)."}, {"lift",0,(void*)lift0,3,"GDn","lift(x,{v}): if v is omitted, lifts elements of Z/nZ to Z, of Qp to Q, and of K[x]/(P) to K[x]. Otherwise lift only polmods with main variable v."}, {"liftall",0,(void*)liftall,3,"G","liftall(x): lifts every element of Z/nZ to Z, of Qp to Q, and of K[x]/(P) to K[x]."}, {"liftint",0,(void*)liftint,3,"G","liftint(x): lifts every element of Z/nZ to Z, of Qp to Q, and of K[x]/(P) to K[x]."}, {"liftpol",0,(void*)liftpol,3,"G","liftpol(x): lifts every polmod component of x to polynomials."}, {"limitnum",0,(void*)limitnum0,9,"GD0,L,DGp","limitnum(expr,{k = 20},{alpha=1}): numerical limit of sequence expr using Lagrange-Zagier extrapolation; k is a multiplier so that we extrapolate from expr(k*n). Assume u(n) ~ sum a_i n^(-alpha*i)."}, {"lindep",0,(void*)lindep0,7,"GD0,L,","lindep(v,{flag=0}): integral linear dependencies between components of v. flag is optional, and can be 0: default, guess a suitable accuracy, or positive: accuracy to use for the computation, in decimal digits."}, {"listcreate",0,(void*)listcreate_gp,1,"D0,L,","listcreate({n}): this function is obsolete, use List()."}, {"listinsert",0,(void*)listinsert,1,"WGL","listinsert(L,x,n): insert x at index n in list L, shifting the remaining elements to the right."}, {"listkill",0,(void*)listkill,1,"vG","listkill(L): obsolete, retained for backward compatibility."}, {"listpop",0,(void*)listpop0,1,"vWD0,L,","listpop(list,{n}): removes n-th element from list. If n is omitted or greater than the current list length, removes last element."}, {"listput",0,(void*)listput0,1,"WGD0,L,","listput(list,x,{n}): sets n-th element of list equal to x. If n is omitted or greater than the current list length, appends x."}, {"listsort",0,(void*)listsort,1,"vWD0,L,","listsort(L,{flag=0}): sort the list L in place. If flag is non-zero, suppress all but one occurence of each element in list."}, {"lngamma",0,(void*)glngamma,8,"Gp","lngamma(x): logarithm of the gamma function of x."}, {"local",0,NULL,1,NULL,"local(x,...,z): declare x,...,z as (dynamically scoped) local variables."}, {"localbitprec",0,(void*)localbitprec,1,"vL","localbitprec(p): set the real precision to p bits in the dynamic scope."}, {"localprec",0,(void*)localprec,1,"vL","localprec(p): set the real precision to p in the dynamic scope."}, {"log",0,(void*)glog,8,"Gp","log(x): natural logarithm of x."}, {"log1p",0,(void*)glog1p,8,"Gp","log1p(x): log(1+x)"}, {"logint",0,(void*)logint0,5,"lGGD&","logint(x,b,{&z}): return the largest integer e so that b^e <= x, where the parameters b > 1 and x > 0 are both integers. If the parameter z is present, set it to b^e."}, {"mapdelete",0,(void*)mapdelete,1,"vGG","mapdelete(M,x): removes x from the domain of the map M."}, {"mapget",0,(void*)mapget,1,"GG","mapget(M,x): returns the image of x by the map M."}, {"mapisdefined",0,(void*)mapisdefined,1,"iGGD&","mapisdefined(M,x,{&z}): true (1) if x has an image by the map M, false (0) otherwise. If z is present, set it to the image of x, if it exists."}, {"mapput",0,(void*)mapput,1,"vWGG","mapput(M,x,y): associates x to y in the map M."}, {"matadjoint",0,(void*)matadjoint0,7,"GD0,L,","matadjoint(M,{flag=0}): adjoint matrix of M using Leverrier-Faddeev's algorithm. If flag is 1, compute the characteristic polynomial independently first."}, {"matalgtobasis",0,(void*)matalgtobasis,10,"GG","matalgtobasis(nf,x): nfalgtobasis applied to every element of the vector or matrix x."}, {"matbasistoalg",0,(void*)matbasistoalg,10,"GG","matbasistoalg(nf,x): nfbasistoalg applied to every element of the matrix or vector x."}, {"matcompanion",0,(void*)matcompanion,7,"G","matcompanion(x): companion matrix to polynomial x."}, {"matconcat",0,(void*)matconcat,7,"G","matconcat(v): concatenate the entries of v and return the resulting matrix."}, {"matdet",0,(void*)det0,7,"GD0,L,","matdet(x,{flag=0}): determinant of the matrix x using an appropriate algorithm depending on the coefficients. If (optional) flag is set to 1, use classical Gaussian elimination (usually worse than the default)."}, {"matdetint",0,(void*)detint,7,"G","matdetint(B): some multiple of the determinant of the lattice generated by the columns of B (0 if not of maximal rank). Useful with mathnfmod."}, {"matdetmod",0,(void*)matdetmod,7,"GG","matdetmod(x,d): determinant of the matrix x modulo d."}, {"matdiagonal",0,(void*)diagonal,7,"G","matdiagonal(x): creates the diagonal matrix whose diagonal entries are the entries of the vector x."}, {"mateigen",0,(void*)mateigen,7,"GD0,L,p","mateigen(x,{flag=0}): complex eigenvectors of the matrix x given as columns of a matrix H. If flag=1, return [L,H], where L contains the eigenvalues and H the corresponding eigenvectors."}, {"matfrobenius",0,(void*)matfrobenius,7,"GD0,L,Dn","matfrobenius(M,{flag},{v='x}): return the Frobenius form of the square matrix M. If flag is 1, return only the elementary divisors as a vector of polynomials in the variable v. If flag is 2, return a two-components vector [F,B] where F is the Frobenius form and B is the basis change so that M=B^-1*F*B."}, {"mathess",0,(void*)hess,7,"G","mathess(x): Hessenberg form of x."}, {"mathilbert",0,(void*)mathilbert,7,"L","mathilbert(n): Hilbert matrix of order n."}, {"mathnf",0,(void*)mathnf0,7,"GD0,L,","mathnf(M,{flag=0}): (upper triangular) Hermite normal form of M, basis for the lattice formed by the columns of M. flag is optional whose value range from 0 to 3 have a binary meaning. Bit 1: complete output, returns a 2-component vector [H,U] such that H is the HNF of M, and U is an invertible matrix such that MU=H. Bit 2: allow polynomial entries, otherwise assume that M is integral. These use a naive algorithm; larger values correspond to more involved algorithms and are restricted to integer matrices; flag = 4: returns [H,U] using LLL reduction along the way; flag = 5: return [H,U,P] where P is a permutation of row indices such that P applied to M U is H."}, {"mathnfmod",0,(void*)hnfmod,7,"GG","mathnfmod(x,d): (upper triangular) Hermite normal form of x, basis for the lattice formed by the columns of x, where d is a multiple of the non-zero determinant of this lattice."}, {"mathnfmodid",0,(void*)hnfmodid,7,"GG","mathnfmodid(x,d): (upper triangular) Hermite normal form of x concatenated with matdiagonal(d)."}, {"mathouseholder",0,(void*)mathouseholder,7,"GG","mathouseholder(Q,v): applies a sequence Q of Householder transforms to the vector or matrix v."}, {"matid",0,(void*)matid,7,"L","matid(n): identity matrix of order n."}, {"matimage",0,(void*)matimage0,7,"GD0,L,","matimage(x,{flag=0}): basis of the image of the matrix x. flag is optional and can be set to 0 or 1, corresponding to two different algorithms."}, {"matimagecompl",0,(void*)imagecompl,7,"G","matimagecompl(x): vector of column indices not corresponding to the indices given by the function matimage."}, {"matimagemod",0,(void*)matimagemod,7,"GGD&","matimagemod(x,d,&U): basis of the image of the matrix x modulo d."}, {"matindexrank",0,(void*)indexrank,7,"G","matindexrank(M): gives two extraction vectors (rows and columns) for the matrix M such that the extracted matrix is square of maximal rank."}, {"matintersect",0,(void*)intersect,7,"GG","matintersect(x,y): intersection of the vector spaces whose bases are the columns of x and y."}, {"matinverseimage",0,(void*)inverseimage,7,"GG","matinverseimage(x,y): an element of the inverse image of the vector y by the matrix x if one exists, the empty vector otherwise."}, {"matinvmod",0,(void*)matinvmod,7,"GG","matinvmod(x,d): left inverse of the matrix x modulo d."}, {"matisdiagonal",0,(void*)isdiagonal,7,"iG","matisdiagonal(x): true(1) if x is a diagonal matrix, false(0) otherwise."}, {"matker",0,(void*)matker0,7,"GD0,L,","matker(x,{flag=0}): basis of the kernel of the matrix x. flag is optional, and may be set to 0: default; non-zero: x is known to have integral entries."}, {"matkerint",0,(void*)matkerint0,7,"GD0,L,","matkerint(x,{flag=0}): LLL-reduced Z-basis of the kernel of the matrix x with integral entries. flag is deprecated, and may be set to 0 or 1 for backward compatibility."}, {"matkermod",0,(void*)matkermod,7,"GGD&","matkermod(x,d,&im): basis of the kernel of the matrix x modulo d."}, {"matmuldiagonal",0,(void*)matmuldiagonal,7,"GG","matmuldiagonal(x,d): product of matrix x by diagonal matrix whose diagonal coefficients are those of the vector d, equivalent but faster than x*matdiagonal(d)."}, {"matmultodiagonal",0,(void*)matmultodiagonal,7,"GG","matmultodiagonal(x,y): product of matrices x and y, knowing that the result will be a diagonal matrix. Much faster than general multiplication in that case."}, {"matpascal",0,(void*)matqpascal,7,"LDG","matpascal(n,{q}): Pascal triangle of order n if q is omitted. q-Pascal triangle otherwise."}, {"matpermanent",0,(void*)matpermanent,7,"G","matpermanent(x): permanent of the matrix x."}, {"matqr",0,(void*)matqr,7,"GD0,L,p","matqr(M,{flag=0}): returns [Q,R], the QR-decomposition of the square invertible matrix M. If flag=1, Q is given as a sequence of Householder transforms (faster and stabler)."}, {"matrank",0,(void*)rank,7,"lG","matrank(x): rank of the matrix x."}, {"matrix",0,(void*)matrice,7,"GDGDVDVDE","matrix(m,{n=m},{X},{Y},{expr=0}): m x n matrix of expression expr, where the row variable X goes from 1 to m and the column variable Y goes from 1 to n. By default, fill with 0s."}, {"matrixqz",0,(void*)matrixqz0,7,"GDG","matrixqz(A,{p=0}): if p>=0, transforms the rational or integral mxn (m>=n) matrix A into an integral matrix with gcd of maximal determinants coprime to p. If p=-1, finds a basis of the intersection with Z^n of the lattice spanned by the columns of A. If p=-2, finds a basis of the intersection with Z^n of the Q-vector space spanned by the columns of A."}, {"matsize",0,(void*)matsize,7,"G","matsize(x): number of rows and columns of the vector/matrix x as a 2-vector."}, {"matsnf",0,(void*)matsnf0,7,"GD0,L,","matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of the matrix X, expressed as a vector d. Binary digits of flag mean 1: returns [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned, 2: allow polynomial entries, otherwise assume X is integral, 4: removes all information corresponding to entries equal to 1 in d."}, {"matsolve",0,(void*)gauss,7,"GG","matsolve(M,B): solution of MX=B (M matrix, B column vector or matrix)."}, {"matsolvemod",0,(void*)matsolvemod,7,"GGGD0,L,","matsolvemod(M,D,B,{flag=0}): one solution of system of congruences MX=B mod D (M matrix, B and D column vectors). If (optional) flag is non-null return all solutions."}, {"matsupplement",0,(void*)suppl,7,"G","matsupplement(x): supplement the columns of the matrix x to an invertible matrix."}, {"mattranspose",0,(void*)gtrans,7,"G","mattranspose(x): x~ = transpose of x."}, {"max",0,(void*)gmax,2,"GG","max(x,y): maximum of x and y."}, {"mfDelta",0,(void*)mfDelta,14,"","mfDelta(): mf corresponding to the Ramanujan Delta function."}, {"mfEH",0,(void*)mfEH,14,"G","mfEH(k): k being in 1/2+Z, mf corresponding to the Cohen-Eisenstein series H_k of weight k on G_0(4)."}, {"mfEk",0,(void*)mfEk,14,"L","mfEk(k): mf corresponding to the standard Eisenstein series E_k."}, {"mfTheta",0,(void*)mfTheta,14,"DG","mfTheta({psi=1}): the unary theta function corresponding to the primitive Dirichlet character psi, hence of weight 1/2 if psi is even, of weight 3/2 if psi is odd."}, {"mfatkin",0,(void*)mfatkin,14,"GG","mfatkin(mfatk,F): Given an mfatk output by mfatk = mfatkininit(mf,Q) and a modular form F belonging to the space mf, returns the modular form C*F|W_Q, which has polmod coefficients in Q(F), and where mfatk[3]=C, mfatk[1]=mf2 (or 0 if mf2=mf) which is the space to which F|W_Q belongs."}, {"mfatkineigenvalues",0,(void*)mfatkineigenvalues,14,"GLp","mfatkineigenvalues(mf,Q): given a modular form space mf and a primitive divisor Q of the level of mf, outputs the corresponding Atkin-Lehner eigenvalues on the new space, grouped by orbit."}, {"mfatkininit",0,(void*)mfatkininit,14,"GLp","mfatkininit(mf,Q): initializes data necessary for working with Atkin--Lehner operators W_Q, for now only the function mfatkin. The result is a 4-component vector [mfB, CM, C, mf] where mfB is either 0 or the possibly different modular form space to which F|W_Q will belong (this does not depend on F in mf); CM is the matrix of W_Q on the basis of mf multiplied by a normalizing constant C."}, {"mfbasis",0,(void*)mfbasis,14,"GD4,L,","mfbasis(NK,{space=4}): If NK=[N,k,CHI] as in mfinit, gives a basis of the corresponding subspace of M_k(G_0(N),chi). NK can also be the output of mfinit, in which case space is ignored. To obtain the eigenforms use mfeigenbasis."}, {"mfbd",0,(void*)mfbd,14,"GL","mfbd(F,d): F being a generalized modular form, return B(d)(F), where B(d) is the expanding operator tau -> d tau."}, {"mfbracket",0,(void*)mfbracket,14,"GGD0,L,","mfbracket(F,G,{m=0}): compute the m-th Rankin-Cohen bracket of the generalized modular forms F and G."}, {"mfcoef",0,(void*)mfcoef,14,"GL","mfcoef(F,n): Compute the n-th Fourier coefficient a(n) of the modular form F."}, {"mfcoefs",0,(void*)mfcoefs,14,"GLD1,L,","mfcoefs(F,n,{d = 1}): Compute the vector of coefficients [a[0],a[d],...,a[nd]] of the modular form F."}, {"mfconductor",0,(void*)mfconductor,14,"lGG","mfconductor(mf,F): mf being output by mfinit for the cuspidal space and F a modular form, gives the smallest level on which F is defined."}, {"mfcosets",0,(void*)mfcosets,14,"G","mfcosets(N): list of right cosets of G_0(N)\\G, i.e., matrices ga_j in G such that G=U G_0(N)ga_j. The ga_j are chosen in the form [a,b;c,d] with c\\mid N. N can be either a positive integer or a modular form space."}, {"mfcuspisregular",0,(void*)mfcuspisregular,14,"lGG","mfcuspisregular(NK, cusp): In the space defined by NK = [N,k,CHI] or NK = mf, determine if cusp in canonical format (oo or denominator dividing N) is regular or not."}, {"mfcusps",0,(void*)mfcusps,14,"G","mfcusps(N): list of cusps of G_0(N) in the form a/b with b dividing N. N can be either an integer or a modular form space."}, {"mfcuspval",0,(void*)mfcuspval,14,"GGGb","mfcuspval(mf,F,cusp): valuation of modular form F in the space mf at cusp, which can be either oo or any rational number, and the result is either a rational number or oo if F is zero. If Q(F) != Q(chi), return the vector of valuations attached to the [Q(F):Q(chi)] complex embeddings of F."}, {"mfcuspwidth",0,(void*)mfcuspwidth,14,"lGG","mfcuspwidth(N, cusp): width of cusp in Gamma_0(N), N being either an integer or a modular form space."}, {"mfderiv",0,(void*)mfderiv,14,"GD1,L,","mfderiv(F,{m=1}): m-th formal derivative of the power series corresponding to the generalized modular form F, with respect to the differential operator q.d/dq (default m=1)."}, {"mfderivE2",0,(void*)mfderivE2,14,"GD1,L,","mfderivE2(F,{m=1}): compute the Serre derivative (q.d/dq)F - kE_2F/12 of the generalized modular form F of weight k; and if m > 1, the m-th iterate."}, {"mfdescribe",0,(void*)mfdescribe,14,"GD&","mfdescribe(F,{&G}): gives a human-readable description of F, which is either a modular form space or a modular form. If the address of G is given, puts into G the vector of parameters of the outmost operator defining F (the empty vector if F is a leaf or a modular form space)."}, {"mfdim",0,(void*)mfdim,14,"GD4,L,","mfdim(NK,{space=4}): If NK=[N,k,CHI] as in mfinit, gives the dimension of the corresponding subspace of M_k(G_0(N),chi). The subspace is described by a small integer 'space': 0 for the newspace, 1 for the cuspidal space, 2 for the oldspace, 3 for the space of Eisenstein series and 4 (default) for the full space M_k. NK can also be the output of mfinit, in which case space must be omitted."}, {"mfdiv",0,(void*)mfdiv,14,"GG","mfdiv(F,G): compute F/G for two modular forms F and G assuming that the quotient will not have poles at infinity. If this is the case, use mfshift before doing the division."}, {"mfeigenbasis",0,(void*)mfeigenbasis,14,"G","mfeigenbasis(mf): vector of the eigenforms for the space mf."}, {"mfeigensearch",0,(void*)mfeigensearch,14,"GDG","mfeigensearch(NK,{AP}): search for normalized rational eigen cuspforms with quadratic characters given a few initial coefficients. The meaning of the parameters is as follows: NK is of the form [N,k]: search given level N, weight k and quadratic character; note that the character is uniquely determined by (N,k). The level N can be replaced by a vector of allowed levels. AP is the search criterion, which can be omitted: a list of pairs [...,[p,a_p],...], where a_p is either a t_INT (exact match) or a t_INTMOD (match modulo the given integer). The result is a vector of newforms matching the search criteria, sorted by increasing level."}, {"mfeisenstein",0,(void*)mfeisenstein,14,"LDGDG","mfeisenstein(k,{CHI1},{CHI2}): create the Eisenstein E_k(CHI1,CHI2), where an omitted character is considered as trivial."}, {"mfembed",0,(void*)mfembed0,14,"GDGp","mfembed(f,{v}): if v is omitted, f must be a modular form or a modular form space with parameters [N,k,chi] and we return a vector of complex embeddings of Q(f) or Q(chi), respectively. If v is given, it must be a scalar in Q(f), or a vector/matrix of such, we apply the embeddings coefficientwise and return a vector of results. Finally f can be replaced by a single embedding produced by mfembed(f) and we apply that particular embedding to v. Note that, in our context, Q(chi) has a single canonical embeding given by s: Mod(t, polcyclo(n,t)) -> exp(2*I*Pi/n) and Q(f) has [Q(f):Q(chi)] induced embeddings attached to the complex roots of s(P) where P = mfparams(f)[4], as ordered by polroots. In the latter case, we only support an f with Q(f) = Q(chi) or an eigenform produced by mfeigenbasis."}, {"mfeval",0,(void*)mfeval,14,"GGGb","mfeval(mf,F,vtau): computes the numerical value of the modular form F at the point vtau or the vector vtau of points in the completed upper-half plane."}, {"mffields",0,(void*)mffields,14,"G","mffields(mf): If mf is output by mfinit, gives the vector of polynomials defining each Galois orbit of the new space."}, {"mffromell",0,(void*)mffromell,14,"G","mffromell(E): E being an elliptic curve defined over Q given by an integral model in ellinit format, computes a 3-component vector [mf,F,v], where F is the newform corresponding to E by modularity, mf is the newspace to which F belongs, and v gives the coefficients of F on mfbasis(mf)."}, {"mffrometaquo",0,(void*)mffrometaquo,14,"GD0,L,","mffrometaquo(eta,{flag=0}): modular form corresponding to the eta quotient matrix eta. If the valuation v at infinity is fractional, return 0. If the eta quotient is not holomorphic but simply meromorphic, return 0 if flag=0, return the eta quotient (divided by q to the power -v if v < 0, i.e., with valuation 0) if flag is set."}, {"mffromlfun",0,(void*)mffromlfun,14,"Gp","mffromlfun(L): L being an L-function representing a self-dual modular form, return [NK,space,v] where mf=mfinit(NK,space) contains the form and mftobasis(mf, v) containing it and v is mftobasis(mf,f)."}, {"mffromqf",0,(void*)mffromqf,14,"GDG","mffromqf(Q,{P}): Q being an even positive definite quadratic form and P a homogeneous spherical polynomial for Q, computes a 3-component vector [mf,F,coeffs], where F is the theta function corresponding to (Q, P), mf is the corresponding space of modular forms from mfinit, and coeffs are the coefficients of F on mfbasis(mf)."}, {"mfgaloistype",0,(void*)mfgaloistype,14,"GDG","mfgaloistype(NK,{F}): NK being either [N,1,CHI] or an mf output by mfinit in weight 1 , gives the vector of types of Galois representations attached to each cuspidal eigenform, unless the eigenform F is specified, in which case only for F. Types A_4, S_4, A_5 are represented by minus their cardinality -12, -24, or -60, and type D_n is represented by its cardinality, the integer 2*n."}, {"mfhecke",0,(void*)mfhecke,14,"GGL","mfhecke(mf,F,n): F being a modular form in space mf, returns T(n)F, where T(n) is the n-th Hecke operator. Warning: if F is of level M= 3/2, gives a basis B of the Kohnen + space of mf as a matrix whose columns are the coefficients of B on the basis of mf."}, {"mfkohnenbijection",0,(void*)mfkohnenbijection,14,"G","mfkohnenbijection(mf): mf being a cuspidal space of half-integral weight returns [mf2,M,K,shi], where M is a matrix giving a Hecke-module isomorphism from S_{2k-1}(N,CHI^2) given by mf2 to the Kohnen + space S_k+(4N,CHI), K is a basis of the Kohnen + space, and shi gives the linear combination of Shimura lifts giving M^(-1)."}, {"mfkohneneigenbasis",0,(void*)mfkohneneigenbasis,14,"GG","mfkohneneigenbasis(mf,bij): mf being a cuspidal space of half-integral weight k >= 3/2 and bij being the output of mfkohnenbijection(mf), outputs a 3-component vector [mf0,BNEW,BEIGEN], where BNEW and BEIGEN are two matrices whose columns are the coefficients of a basis of the Kohnen new space and of the eigenforms on the basis of mf respectively, and mf0 is the corresponding new space of integral weight 2k - 1."}, {"mflinear",0,(void*)mflinear,14,"GG","mflinear(vF,v): vF being a vector of modular forms and v a vector of coefficients of same length, compute the linear combination of the entries of vF with coefficients v."}, {"mfmanin",0,(void*)mfmanin,14,"Gb","mfmanin(FS): Given the modular symbol FS associated to an eigenform F by mfsymbol(mf,F), computes the even and odd special polynomials as well as the even and odd periods om+ and om- as a vector [[P+,P-],[om+,om-,r]], where r = imag(om+*conj(om-))/. If F has several embeddings into C, give the vector of results corresponding to each embedding."}, {"mfmul",0,(void*)mfmul,14,"GG","mfmul(F,G): Multiply the two forms F and G."}, {"mfnumcusps",0,(void*)mfnumcusps,14,"G","mfnumcusps(N): number of cusps of Gamma_0(N)"}, {"mfparams",0,(void*)mfparams,14,"G","mfparams(F): If F is a modular form space, returns [N,k,CHI,space]: level, weight, character, and space code. If F is a modular form, returns [N,k,CHI,P], where P is the (polynomial giving the) field of definition of F: in that case the level N may be a multiple of the level of F and the polynomial P may define a larger field than Q(F)."}, {"mfperiodpol",0,(void*)mfperiodpol,14,"GGD0,L,b","mfperiodpol(mf,f,{flag=0}): period polynomial of the cuspidal part of the form f, in other words integral from 0 to ioo of (X-tau)^(k-2)f(tau). If flag=0, ordinary period polynomial, if flag=1 or -1, even or odd part of that polynomial. f can also be the modular symbol output by mfsymbol(mf,f)."}, {"mfperiodpolbasis",0,(void*)mfperiodpolbasis,14,"LD0,L,","mfperiodpolbasis(k,{flag=0}): basis of period polynomials for weight k. If flag=1 or -1, basis of odd or even period polynomials."}, {"mfpetersson",0,(void*)mfpetersson,14,"GDG","mfpetersson(fs,{gs}): Petersson scalar product of the modular forms f and g belonging to the same modular form space mf, given by the corresponding \"modular symbols\" fs and gs output by mfsymbol (also in weight 1 and half-integral weight). If gs is omitted it is understood to be equal to fs. The scalar product is normalized by the factor 1/[G:G_0(N)]."}, {"mfpow",0,(void*)mfpow,14,"GL","mfpow(F,n): compute F^n"}, {"mfsearch",0,(void*)mfsearch,14,"GGD4,L,","mfsearch(NK,V,{space}): NK being of the form [N,k] with k possibly half-integral, search for a modular form with rational coefficients, of weight k and level N, whose initial coefficients a(0),... are equal to V; space specifies the modular form spaces in which to search. The output is a list of matching forms with that given level and weight. Note that the character is of the form (D/.), where D is a (positive or negative) fundamental discriminant dividing N. N can be replaced by a vector of allowed levels, in which case the list of forms is sorted by increasing level, then increasing |D|. If a form is found at level N, any multiple of N with the same D is not considered Note that this is very different from mfeigensearch, which only searches for rational eigenforms."}, {"mfshift",0,(void*)mfshift,14,"GL","mfshift(F,s): Divide the form F by q^s omitting the remainder if there is one; s can be negative."}, {"mfshimura",0,(void*)mfshimura,14,"GGD1,L,","mfshimura(mf, F, {D = 1}): F being a modular form of half-integral weight k >= 3/2 and D a (not necessarily fundamental) discriminant of suitable sign, computes the Shimura lift G of weight 2k-1 corresponding to D. This function returns [mf2,G,v], where mf2 is a modular form space containing G, and v the vector of coefficients of G on mf. By extension, D can also be a positive squarefree integer."}, {"mfslashexpansion",0,(void*)mfslashexpansion,14,"GGGLLD&p","mfslashexpansion(mf,f,g,n,flrat,{¶ms}): g being in M_2^+(Q), computes the Fourier expansion of f|_k g to n terms. f must belong to the space mf. If params is given, it is set to the parameters [alpha,w,A]. If flrat is 1, the program tries to rationalize the expression; if flag is 0, it does not."}, {"mfspace",0,(void*)mfspace,14,"lGDG","mfspace(mf,{f}): identify the modular space mf, resp. the modular form f in mf. Returns 0 (newspace), 1 (cuspidal space), 2 (old space), 3 (Eisenstein space) or 4 (full space). Return -1 when the form does not belong to the space."}, {"mfsplit",0,(void*)mfsplit,14,"GD0,L,D0,L,","mfsplit(mf,{dimlim=0},{flag=0}): mf containing the new space split the new space into Galois orbits of eigenforms of the newspace and return [vF,vK], where vF gives the (Galois orbit of) eigenforms in terms of mfbasis(mf) and vK is a list of polynomials defining each Galois orbit. If dimlim is set only the Galois orbits of dimension <= dimlim are computed (i.e. the rational eigenforms if dimlim = 1 and the character is real). Flag speeds up computations when the dimension is large: if flag = d > 0, when the dimension of the eigenspace is > d, only the Galois polynomial is computed."}, {"mfsturm",0,(void*)mfsturm,14,"lG","mfsturm(NK): Sturm bound for modular forms on G_0(N) and weight k, i.e., an upper bound for the order of the zero at infinity of a nonzero form. NK is either [N,k] or an mfinit (exact bound in the latter case)."}, {"mfsymbol",0,(void*)mfsymbol,14,"GDGb","mfsymbol(mf,f): Initialize data for working with all period polynomials of the modular form f: this is essential for efficiency for functions such as mfsymboleval, mfmanin, and mfpetersson. By abuse of language, initialize data for working with mfpetersson in weight 1 or half-integral weight (where no symbol exist)."}, {"mfsymboleval",0,(void*)mfsymboleval,14,"GGDGb","mfsymboleval(fs,path,{ga=id}): evaluation of the modular symbol fs output by mfsymbol on the given path, where path is either a vector [s1,s2] or an integral matrix [a,b;c,d] representing the path [a/c,b/d]. In both cases, s1 or s2 (or a/c or b/d) can also be elements of the upper half-plane. The result is the polynomial equal to the integral between s1 and s2 of (X-tau)^{k-2}F(tau). If ga in GL_2+(Q) is given, replace F by F|_k ga. If the integral diverges, the result will be a rational function."}, {"mftaylor",0,(void*)mftaylor,14,"GLD0,L,p","mftaylor(F,n,{flreal=0}): F being a modular form in M_k(SL_2(Z)), computes the first n+1 canonical Taylor expansion of F around tau=I. If flreal=0, computes only an algebraic equivalence class. If flreal is set, compute p_n such that for tau close enough to I we have f(tau)=(2I/(tau+I))^ksum_{n>=0}p_n((tau-I)/(tau+I))^n."}, {"mftobasis",0,(void*)mftobasis,14,"GGD0,L,","mftobasis(mf,F,{flag=0}): coefficients of the form F on the basis given by the mfbasis(mf). A q-expansion or vector of coefficients can also be given instead of F, but in this case an error message may occur if the expansion is too short. An error message is also given if F does not belong to the modular form space. If flag is set, instead of error messages return an output as an affine space of solutions if a q-expansion or vector of coefficients is given, or the empty column otherwise."}, {"mftocoset",0,(void*)mftocoset,14,"LGG","mftocoset(N,M,Lcosets): M being a matrix in SL_2(Z) and Lcosets being mfcosets(N), find the right coset of G_0(N) to which M belongs. The output is a pair [ga,i] such that M = ga * Lcosets[i], with ga in G_0(N)."}, {"mftonew",0,(void*)mftonew,14,"GG","mftonew(mf,F): mf being a full or cuspidal space with parameters [N,k,chi] and F a cusp form in that space, returns a vector of 3-component vectors [M,d,G], where f(chi) divides M divides N, d divides N/M, and G is a form in S_k^new(G_0(M),chi) such that F is equal to the sum of the B(d)(G) over all these 3-component vectors."}, {"mftraceform",0,(void*)mftraceform,14,"GD0,L,","mftraceform(NK,{space=0}): If NK=[N,k,CHI,.] as in mfinit with k integral, gives the trace form in the corresponding subspace of S_k(G_0(N),chi). The supported values for space are 0: the newspace (default), 1: the full cuspidal space."}, {"mftwist",0,(void*)mftwist,14,"GG","mftwist(F,D): returns the twist of the form F by the integer D, i.e., the form G such that mfcoef(G,n)=(D/n)mfcoef(F,n), where (D/n) is the Kronecker symbol."}, {"min",0,(void*)gmin,2,"GG","min(x,y): minimum of x and y."}, {"minpoly",0,(void*)minpoly,7,"GDn","minpoly(A,{v='x}): minimal polynomial of the matrix or polmod A."}, {"modreverse",0,(void*)modreverse,10,"G","modreverse(z): reverse polmod of the polmod z, if it exists."}, {"moebius",0,(void*)moebius,5,"lG","moebius(x): Moebius function of x."}, {"msatkinlehner",0,(void*)msatkinlehner,15,"GLDG","msatkinlehner(M,Q,{H}): M being a full modular symbol space of level N, as given by msinit, let Q | N, (Q,N/Q) = 1, and let H be a subspace stable under the Atkin-Lehner involution w_Q. Return the matrix of w_Q acting on H (M if omitted)."}, {"mscuspidal",0,(void*)mscuspidal,15,"GD0,L,","mscuspidal(M, {flag=0}): M being a full modular symbol space, as given by msinit, return its cuspidal part S. If flag = 1, return [S,E] its decomposition into Eisenstein and cuspidal parts."}, {"msdim",0,(void*)msdim,15,"lG","msdim(M): M being a modular symbol space or subspace, return its dimension as a Q-vector space."}, {"mseisenstein",0,(void*)mseisenstein,15,"G","mseisenstein(M): M being a full modular symbol space, as given by msinit, return its Eisenstein subspace."}, {"mseval",0,(void*)mseval,15,"GGDG","mseval(M,s,{p}): M being a full modular symbol space, as given by msinit, s being a modular symbol from M and p being a path between two elements in P^1(Q), return s(p)."}, {"msfromcusp",0,(void*)msfromcusp,15,"GG","msfromcusp(M, c): returns the modular symbol attached to the cusp c, where M is a modular symbol space of level N."}, {"msfromell",0,(void*)msfromell,15,"GD0,L,","msfromell(E, {sign=0}): return the [M, x], where M is msinit(N,2) and x is the modular symbol in M attached to the elliptic curve E/Q."}, {"msfromhecke",0,(void*)msfromhecke,15,"GGDG","msfromhecke(M, v, {H}): given a msinit M and a vector v of pairs [p, P] (where p is prime and P is a polynomial with integer coefficients), return a basis of all modular symbols such that P(Tp) * s = 0. If H is present, it must be a Hecke-stable subspace and we restrict to s in H."}, {"msgetlevel",0,(void*)msgetlevel,15,"lG","msgetlevel(M): M being a full modular symbol space, as given by msinit, return its level N."}, {"msgetsign",0,(void*)msgetsign,15,"lG","msgetsign(M): M being a full modular symbol space, as given by msinit, return its sign."}, {"msgetweight",0,(void*)msgetweight,15,"lG","msgetweight(M): M being a full modular symbol space, as given by msinit, return its weight k."}, {"mshecke",0,(void*)mshecke,15,"GLDG","mshecke(M,p,{H}): M being a full modular symbol space, as given by msinit, p being a prime number, and H being a Hecke-stable subspace (M if omitted), return the matrix of T_p acting on H (U_p if p divides the level)."}, {"msinit",0,(void*)msinit,15,"GGD0,L,","msinit(G, V, {sign=0}): given G a finite index subgroup of SL(2,Z) and a finite dimensional representation V of GL(2,Q), creates a space of modular symbols, the G-module Hom_G(Div^0(P^1 Q), V). This is canonically isomorphic to H^1_c(X(G), V), and allows to compute modular forms for G. If sign is present and non-zero, it must be +1 or -1 and we consider the subspace defined by Ker (Sigma - sign), where Sigma is induced by [-1,0;0,1]. Currently the only supported groups are the Gamma_0(N), coded by the integer N. The only supported representation is V_k = Q[X,Y]_{k-2}, coded by the integer k >= 2."}, {"msissymbol",0,(void*)msissymbol,15,"GG","msissymbol(M,s): M being a full modular symbol space, as given by msinit, check whether s is a modular symbol attached to M."}, {"mslattice",0,(void*)mslattice,15,"GDG","mslattice(M, {H}): M being a full modular symbol space, as given by msinit, H a Q-subspace or a matrix of modular symbols. Return the canonical integral structure of H."}, {"msnew",0,(void*)msnew,15,"G","msnew(M): M being a full modular symbol space, as given by msinit, return its new cuspidal subspace."}, {"msomseval",0,(void*)msomseval,15,"GGG","msomseval(Mp, PHI, path): return the vectors of moments of the p-adic distribution attached to the path 'path' via the overconvergent modular symbol 'PHI'."}, {"mspadicL",0,(void*)mspadicL,15,"GDGD0,L,","mspadicL(mu, {s = 0}, {r = 0}): given mu from mspadicmoments (p-adic distributions attached to an overconvergent symbol PHI) returns the value on a character of Z_p^* represented by s of the derivative of order r of the p-adic L-function attached to PHI."}, {"mspadicinit",0,(void*)mspadicinit,15,"GLLD-1,L,","mspadicinit(M, p, n, {flag}): M being a full modular symbol space, as given by msinit and a prime p, initialize technical data needed to compute with overconvergent modular symbols (modulo p^n). If flag is unset, allow all symbols; if flag = 0, restrict to ordinary symbols; else initialize for symbols phi such that Tp(phi) = a_p * phi, with v_p(a_p) >= flag."}, {"mspadicmoments",0,(void*)mspadicmoments,15,"GGD1,L,","mspadicmoments(Mp, PHI, {D = 1}): given Mp from mspadicinit, an overconvergent eigensymbol PHI, and optionally a fundamental discriminant D coprime to p, return the moments of the p-1 distributions PHI^D([0]-[oo]) | (a + pZp), 0 < a < p. To be used by mspadicL and mspadicseries."}, {"mspadicseries",0,(void*)mspadicseries,15,"GD0,L,","mspadicseries(mu, {i=0}): given mu from mspadicmoments, returns the attached p-adic series with maximal p-adic precision, depending on the precision of M (i-th Teichmueller component, if present)."}, {"mspathgens",0,(void*)mspathgens,15,"G","mspathgens(M): M being a full modular symbol space, as given by msinit, return a set of Z[G]-generators for Div^0(P^1 Q). The output is [g,R], where g is a minimal system of generators and R the vector of Z[G]-relations between the given generators."}, {"mspathlog",0,(void*)mspathlog,15,"GG","mspathlog(M,p): M being a full modular symbol space, as given by msinit and p being a path between two elements in P^1(Q), return (p_i) in Z[G] such that p = \\sum p_i g_i, and the g_i are fixed Z[G]-generators for Div^0(P^1 Q), see mspathgens."}, {"mspetersson",0,(void*)mspetersson,15,"GDGDG","mspetersson(M, {F}, {G=F}): M being a full modular symbol space, as given by msinit, calculate the intersection product {F,G} of modular symbols F and G on M."}, {"mspolygon",0,(void*)mspolygon,15,"GD0,L,","mspolygon(M, {flag = 0}): M being a full modular symbol space, as given by msinit or an integer > 1, return an hyperbolic polygon (Farey symbol) attached to the group Gamma_0(N). Binary digits of flag mean: 1=normalized polygon, 2=also add graphical representations."}, {"msqexpansion",0,(void*)msqexpansion,15,"GGDP","msqexpansion(M,projH,{B = seriesprecision}): M being a full modular symbol space, as given by msinit, and projH being a projector on a Hecke-simple subspace, return the Fourier coefficients [a_n, n <= B] of the corresponding normalized newform. If B omitted, use seriesprecision."}, {"mssplit",0,(void*)mssplit,15,"GDGD0,L,","mssplit(M,{H},{dimlim}): M being a full modular symbol space, as given by msinit, and H being a subspace (the new subspace if omitted), split H into Hecke-simple subspaces. If dimlim is present and positive, restrict to dim <= dimlim."}, {"msstar",0,(void*)msstar,15,"GDG","msstar(M,{H}): M being a full modular symbol space, as given by msinit, return the matrix of the * involution, induced by complex conjugation, acting on the (stable) subspace H (M if omitted)."}, {"mstooms",0,(void*)mstooms,15,"GG","mstooms(Mp, phi): given Mp from mspadicinit, lift the (classical) eigen symbol phi to a distribution-valued overconvergent symbol in the sense of Pollack and Stevens. The resulting overconvergent eigensymbol can then be used in mspadicmoments, then mspadicL or mspadicseries."}, {"my",0,NULL,1,NULL,"my(x,...,z): declare x,...,z as lexically-scoped local variables."}, {"newtonpoly",0,(void*)newtonpoly,10,"GG","newtonpoly(x,p): Newton polygon of polynomial x with respect to the prime p."}, {"next",0,(void*)next0,1,"D1,L,","next({n=1}): interrupt execution of current instruction sequence, and start another iteration from the n-th innermost enclosing loops."}, {"nextprime",0,(void*)nextprime,5,"G","nextprime(x): smallest pseudoprime >= x."}, {"nfalgtobasis",0,(void*)algtobasis,10,"GG","nfalgtobasis(nf,x): transforms the algebraic number x into a column vector on the integral basis nf.zk."}, {"nfbasis",0,(void*)nfbasis_gp,10,"G","nfbasis(T): integral basis of the field Q[a], where a is a root of the polynomial T, using the round 4 algorithm. An argument [T,listP] is possible, where listP is a list of primes (to get an order which is maximal at certain primes only) or a prime bound."}, {"nfbasistoalg",0,(void*)basistoalg,10,"GG","nfbasistoalg(nf,x): transforms the column vector x on the integral basis into an algebraic number."}, {"nfcertify",0,(void*)nfcertify,10,"G","nfcertify(nf): returns a vector of composite integers used to certify nf.zk and nf.disc unconditionally (both are correct when the output is the empty vector)."}, {"nfcompositum",0,(void*)nfcompositum,10,"GGGD0,L,","nfcompositum(nf,P,Q,{flag=0}): vector of all possible compositums of the number fields defined by the polynomials P and Q; flag is optional, whose binary digits mean 1: output for each compositum, not only the compositum polynomial pol, but a vector [R,a,b,k] where a (resp. b) is a root of P (resp. Q) expressed as a polynomial modulo R, and a small integer k such that al2+k*al1 is the chosen root of R; 2: assume that the number fields defined by P and Q are linearly disjoint."}, {"nfdetint",0,(void*)nfdetint,10,"GG","nfdetint(nf,x): multiple of the ideal determinant of the pseudo generating set x."}, {"nfdisc",0,(void*)nfdisc,10,"G","nfdisc(T): discriminant of the number field defined by the polynomial T. An argument [T,listP] is possible, where listP is a list of primes or a prime bound."}, {"nfeltadd",0,(void*)nfadd,10,"GGG","nfeltadd(nf,x,y): element x+y in nf."}, {"nfeltdiv",0,(void*)nfdiv,10,"GGG","nfeltdiv(nf,x,y): element x/y in nf."}, {"nfeltdiveuc",0,(void*)nfdiveuc,10,"GGG","nfeltdiveuc(nf,x,y): gives algebraic integer q such that x-qy is small."}, {"nfeltdivmodpr",0,(void*)nfdivmodpr,10,"GGGG","nfeltdivmodpr(nf,x,y,pr): this function is obsolete, use nfmodpr."}, {"nfeltdivrem",0,(void*)nfdivrem,10,"GGG","nfeltdivrem(nf,x,y): gives [q,r] such that r=x-qy is small."}, {"nfeltembed",0,(void*)nfeltembed,10,"GGDGp","nfeltembed(nf,x,{pl}): complex embeddings of x at places given by vector pl."}, {"nfeltmod",0,(void*)nfmod,10,"GGG","nfeltmod(nf,x,y): gives r such that r=x-qy is small with q algebraic integer."}, {"nfeltmul",0,(void*)nfmul,10,"GGG","nfeltmul(nf,x,y): element x.y in nf."}, {"nfeltmulmodpr",0,(void*)nfmulmodpr,10,"GGGG","nfeltmulmodpr(nf,x,y,pr): this function is obsolete, use nfmodpr."}, {"nfeltnorm",0,(void*)nfnorm,10,"GG","nfeltnorm(nf,x): norm of x."}, {"nfeltpow",0,(void*)nfpow,10,"GGG","nfeltpow(nf,x,k): element x^k in nf."}, {"nfeltpowmodpr",0,(void*)nfpowmodpr,10,"GGGG","nfeltpowmodpr(nf,x,k,pr): this function is obsolete, use nfmodpr."}, {"nfeltreduce",0,(void*)nfreduce,10,"GGG","nfeltreduce(nf,a,id): gives r such that a-r is in the ideal id and r is small."}, {"nfeltreducemodpr",0,(void*)nfreducemodpr,10,"GGG","nfeltreducemodpr(nf,x,pr): this function is obsolete, use nfmodpr."}, {"nfeltsign",0,(void*)nfeltsign,10,"GGDG","nfeltsign(nf,x,{pl}): signs of real embeddings of x at places given by vector pl."}, {"nfelttrace",0,(void*)nftrace,10,"GG","nfelttrace(nf,x): trace of x."}, {"nfeltval",0,(void*)gpnfvalrem,10,"GGGD&","nfeltval(nf,x,pr,{&y}): valuation of element x at the prime pr as output by idealprimedec."}, {"nffactor",0,(void*)nffactor,10,"GG","nffactor(nf,T): factor polynomial T in number field nf."}, {"nffactorback",0,(void*)nffactorback,10,"GGDG","nffactorback(nf,f,{e}): given a factorization f, returns the factored object back as an nf element."}, {"nffactormod",0,(void*)nffactormod,10,"GGG","nffactormod(nf,Q,pr): this routine is obsolete, use nfmodpr and factormod. Factor polynomial Q modulo prime ideal pr in number field nf."}, {"nfgaloisapply",0,(void*)galoisapply,10,"GGG","nfgaloisapply(nf,aut,x): apply the Galois automorphism aut to the object x (element or ideal) in the number field nf."}, {"nfgaloisconj",0,(void*)galoisconj0,10,"GD0,L,DGp","nfgaloisconj(nf,{flag=0},{d}): list of conjugates of a root of the polynomial x=nf.pol in the same number field. flag is optional (set to 0 by default), meaning 0: use combination of flag 4 and 1, always complete; 1: use nfroots; 4: use Allombert's algorithm, complete if the field is Galois of degree <= 35 (see manual for details). nf can be simply a polynomial."}, {"nfgrunwaldwang",0,(void*)nfgrunwaldwang,10,"GGGGDn","nfgrunwaldwang(nf,Lpr,Ld,pl,{v='x}): a polynomial in the variable v defining a cyclic extension of nf (given in nf or bnf form) with local behavior prescribed by Lpr, Ld and pl: the extension has local degree a multiple of Ld[i] at the prime Lpr[i], and the extension is complex at the i-th real place of nf if pl[i]=-1 (no condition if pl[i]=0). The extension has degree the LCM of the local degrees."}, {"nfhilbert",0,(void*)nfhilbert0,10,"lGGGDG","nfhilbert(nf,a,b,{pr}): if pr is omitted, global Hilbert symbol (a,b) in nf, that is 1 if X^2-aY^2-bZ^2 has a non-trivial solution (X,Y,Z) in nf, -1 otherwise. Otherwise compute the local symbol modulo the prime ideal pr."}, {"nfhnf",0,(void*)nfhnf0,10,"GGD0,L,","nfhnf(nf,x,{flag=0}): if x=[A,I], gives a pseudo-basis [B,J] of the module sum A_jI_j. If flag is non-zero, return [[B,J], U], where U is the transformation matrix such that AU = [0|B]."}, {"nfhnfmod",0,(void*)nfhnfmod,10,"GGG","nfhnfmod(nf,x,detx): if x=[A,I], and detx is a multiple of the ideal determinant of x, gives a pseudo-basis of the module sum A_jI_j."}, {"nfinit",0,(void*)nfinit0,10,"GD0,L,p","nfinit(pol,{flag=0}): pol being a nonconstant irreducible polynomial, gives the vector: [pol,[r1,r2],discf,index,[M,MC,T2,T,different] (see manual),r1+r2 first roots, integral basis, matrix of power basis in terms of integral basis, multiplication table of basis]. flag is optional and can be set to 0: default; 1: do not compute different; 2: first use polred to find a simpler polynomial; 3: outputs a two-element vector [nf,Mod(a,P)], where nf is as in 2 and Mod(a,P) is a polmod equal to Mod(x,pol) and P=nf.pol."}, {"nfisideal",0,(void*)isideal,10,"lGG","nfisideal(nf,x): true(1) if x is an ideal in the number field nf, false(0) if not."}, {"nfisincl",0,(void*)nfisincl,10,"GG","nfisincl(f,g): let f and g define number fields, either irreducible rational polynomials or number fields as output by nfinit; tests whether the number field f is isomorphic to a subfield of g. Return 0 if not, and otherwise all the isomorphisms."}, {"nfisisom",0,(void*)nfisisom,10,"GG","nfisisom(f,g): as nfisincl but tests whether f is isomorphic to g."}, {"nfislocalpower",0,(void*)nfislocalpower,10,"lGGGG","nfislocalpower(nf,pr,a,n): true(1) if a is an n-th power in the local field K_v, false(0) if not."}, {"nfkermodpr",0,(void*)nfkermodpr,10,"GGG","nfkermodpr(nf,x,pr): this function is obsolete, use nfmodpr."}, {"nfmodpr",0,(void*)nfmodpr,10,"GGG","nfmodpr(nf,x,pr): map x to the residue field mod pr."}, {"nfmodprinit",0,(void*)nfmodprinit,10,"GG","nfmodprinit(nf,pr): transform the prime ideal pr into modpr format necessary for all operations mod pr in the number field nf."}, {"nfmodprlift",0,(void*)nfmodprlift,10,"GGG","nfmodprlift(nf,x,pr): lift x from residue field mod pr to nf."}, {"nfnewprec",0,(void*)nfnewprec,10,"Gp","nfnewprec(nf): transform the number field data nf into new data using the current (usually larger) precision."}, {"nfpolsturm",0,(void*)nfpolsturm,10,"GGDG","nfpolsturm(nf, T, {pl}): number of distinct real roots of the polynomial s(T) where s runs through the real embeddings given by vector pl."}, {"nfroots",0,(void*)nfroots,10,"DGG","nfroots({nf},x): roots of polynomial x belonging to nf (Q if omitted) without multiplicity."}, {"nfrootsof1",0,(void*)rootsof1,10,"G","nfrootsof1(nf): number of roots of unity and primitive root of unity in the number field nf."}, {"nfsnf",0,(void*)nfsnf0,10,"GGD0,L,","nfsnf(nf,x,{flag=0}): if x=[A,I,J], outputs D=[d_1,...d_n] Smith normal form of x. If flag is non-zero return [D,U,V], where UAV = Id."}, {"nfsolvemodpr",0,(void*)nfsolvemodpr,10,"GGGG","nfsolvemodpr(nf,a,b,P): this function is obsolete, use nfmodpr."}, {"nfsplitting",0,(void*)nfsplitting,10,"GDG","nfsplitting(P,{d}): defining polynomial over Q for the splitting field of P, that is the smallest field over which P is totally split. P can also be given by a nf structure. If d is given, it must be a multiple of the splitting field degree."}, {"nfsubfields",0,(void*)nfsubfields,10,"GD0,L,","nfsubfields(pol,{d=0}): find all subfields of degree d of number field defined by pol (all subfields if d is null or omitted). Result is a vector of subfields, each being given by [g,h], where g is an absolute equation and h expresses one of the roots of g in terms of the root x of the polynomial defining nf."}, {"norm",0,(void*)gnorm,3,"G","norm(x): norm of x."}, {"norml2",0,(void*)gnorml2,7,"G","norml2(x): square of the L2-norm of x."}, {"normlp",0,(void*)gnormlp,7,"GDGp","normlp(x,{p=oo}): Lp-norm of x; sup norm if p is omitted."}, {"numbpart",0,(void*)numbpart,4,"G","numbpart(n): number of partitions of n."}, {"numdiv",0,(void*)numdiv,5,"G","numdiv(x): number of divisors of x."}, {"numerator",0,(void*)numerator,3,"GDG","numerator(f,{D}): numerator of f."}, {"numtoperm",0,(void*)numtoperm,4,"LG","numtoperm(n,k): permutation number k (mod n!) of n letters (n C-integer)."}, {"omega",0,(void*)omega,5,"lG","omega(x): number of distinct prime divisors of x."}, {"oo",0,(void*)mkoo,3,"","oo=oo(): infinity."}, {"padicappr",0,(void*)padicappr,6,"GG","padicappr(pol,a): p-adic roots of the polynomial pol congruent to a mod p."}, {"padicfields",0,(void*)padicfields0,6,"GGD0,L,","padicfields(p, N, {flag=0}): returns polynomials generating all the extensions of degree N of the field of p-adic rational numbers; N is allowed to be a 2-component vector [n,d], in which case, returns the extensions of degree n and discriminant p^d. flag is optional, and can be 0: default, 1: return also the ramification index, the residual degree, the valuation of the discriminant and the number of conjugate fields, or 2: return only the number of extensions in a fixed algebraic closure."}, {"padicprec",0,(void*)gppadicprec,3,"GG","padicprec(x,p): return the absolute p-adic precision of object x."}, {"parapply",0,(void*)parapply,1,"GG","parapply(f, x): parallel evaluation of f on the elements of x."}, {"pareval",0,(void*)pareval,1,"G","pareval(x): parallel evaluation of the elements of the vector of closures x."}, {"parfor",0,(void*)parfor0,1,"vV=GDGJDVDI","parfor(i=a,{b},expr1,{r},{expr2}): evaluates the expression expr1 in parallel for all i between a and b (if b is set to +oo, the loop will not stop), resulting in as many values; if the formal variables r and expr2 are present, evaluate sequentially expr2, in which r has been replaced by the different results obtained for expr1 and i with the corresponding arguments."}, {"parforprime",0,(void*)parforprime0,1,"vV=GDGJDVDI","parforprime(p=a,{b},expr1,{r},{expr2}): evaluates the expression expr1 in parallel for all primes p between a and b (if b is set to +oo, the loop will not stop), resulting in as many values; if the formal variables r and expr2 are present, evaluate sequentially expr2, in which r has been replaced by the different results obtained for expr1 and p with the corresponding arguments."}, {"parforvec",0,(void*)parforvec0,1,"vV=GJDVDID0,L,","parforvec(X=v,expr1,{j},{expr2},{flag}): evaluates the sequence expr2 (dependent on X and j) for X as generated by forvec, in random order, computed in parallel. Substitute for j the value of expr1 (dependent on X)."}, {"parploth",0,(void*)parploth,16,"V=GGJD0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096","parploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean: 1=Parametric, 2=Recursive, 4=no_Rescale, 8=no_X_axis, 16=no_Y_axis, 32=no_Frame, 64=no_Lines (do not join points), 128=Points_too (plot both lines and points), 256=Splines (use cubic splines), 512=no_X_ticks, 1024= no_Y_ticks, 2048=Same_ticks (plot all ticks with the same length), 4096=Complex (the two coordinates of each point are encoded as a complex number). n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box."}, {"parselect",0,(void*)parselect,1,"GGD0,L,","parselect(f, A, {flag = 0}): (parallel select) selects elements of A according to the selection function f which is tested in parallel. If flag is 1, return the indices of those elements (indirect selection)."}, {"parsum",0,(void*)parsum,1,"V=GGJDG","parsum(i=a,b,expr,{x}): x plus the sum (X goes from a to b) of expression expr, evaluated in parallel (in random order)."}, {"partitions",0,(void*)partitions,4,"LDGDG","partitions(k,{a=k},{n=k}): vector of partitions of the integer k. You can restrict the length of the partitions with parameter n (n=nmax or n=[nmin,nmax]), or the range of the parts with parameter a (a=amax or a=[amin,amax]). By default remove zeros, but one can set amin=0 to get X of fixed length nmax (=k by default)."}, {"parvector",0,(void*)parvector,1,"LVJ","parvector(N,i,expr): as vector(N,i,expr) but the evaluations of expr are done in parallel."}, {"permorder",0,(void*)permorder,4,"lG","permorder(x): order of the permutation x."}, {"permsign",0,(void*)permsign,4,"lG","permsign(x): signature of the permutation x."}, {"permtonum",0,(void*)permtonum,4,"G","permtonum(x): ordinal (between 1 and n!) of permutation x."}, {"plot",0,(void*)pariplot,16,"vV=GGEDGDGp","plot(X=a,b,expr,{Ymin},{Ymax}): crude plot of expression expr, X goes from a to b, with Y ranging from Ymin to Ymax. If Ymin (resp. Ymax) is not given, the minimum (resp. the maximum) of the expression is used instead."}, {"plotbox",0,(void*)plotbox,16,"vLGGD0,L,","plotbox(w,x2,y2,{filled=0}): if the cursor is at position (x1,y1), draw a box with diagonal (x1,y1) and (x2,y2) in rectwindow w (cursor does not move). If filled=1, fill the box."}, {"plotclip",0,(void*)plotclip,16,"vL","plotclip(w): clip the contents of the rectwindow to the bounding box (except strings)."}, {"plotcolor",0,(void*)plotcolor,16,"LG","plotcolor(w,c): in rectwindow w, set default color to c. Possible values for c are [R,G,B] values, a color name or an index in the graphcolormap default: factory settings are 1=black, 2=blue, 3=sienna, 4=red, 5=green, 6=grey, 7=gainsborough. Return [R,G,B] value attached to color."}, {"plotcopy",0,(void*)plotcopy,16,"vLLGGD0,L,","plotcopy(sourcew,destw,dx,dy,{flag=0}): copy the contents of rectwindow sourcew to rectwindow destw with offset (dx,dy). If flag's bit 1 is set, dx and dy express fractions of the size of the current output device, otherwise dx and dy are in pixels. dx and dy are relative positions of northwest corners if other bits of flag vanish, otherwise of: 2: southwest, 4: southeast, 6: northeast corners."}, {"plotcursor",0,(void*)plotcursor,16,"L","plotcursor(w): current position of cursor in rectwindow w."}, {"plotdraw",0,(void*)plotdraw,16,"vGD0,L,","plotdraw(w, {flag=0}): draw rectwindow w. More generally, w can be of the form [w1,x1,y1, w2,x2,y2,etc.]: draw rectwindows wi at given xi,yi positions. If flag!=0, the xi,yi express fractions of the size of the current output device."}, {"plotexport",0,(void*)plotexport,16,"GGD0,L,","plotexport(fmt, list, {flag=0}): draw vector of rectwindows list as in plotdraw, returning the resulting picture as a character string; fmt is either \"ps\" or \"svg\"."}, {"ploth",0,(void*)ploth0,16,"V=GGED0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096","ploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean: 1=Parametric, 2=Recursive, 4=no_Rescale, 8=no_X_axis, 16=no_Y_axis, 32=no_Frame, 64=no_Lines (do not join points), 128=Points_too (plot both lines and points), 256=Splines (use cubic splines), 512=no_X_ticks, 1024= no_Y_ticks, 2048=Same_ticks (plot all ticks with the same length), 4096=Complex (the two coordinates of each point are encoded as a complex number). n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box."}, {"plothexport",0,(void*)plothexport0,16,"GV=GGED0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096","plothexport(fmt, X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution, returning the resulting picture as a character string which can then be written to a file."}, {"plothraw",0,(void*)plothraw,16,"GGD0,L,","plothraw(X,Y,{flag=0}): plot in high resolution points whose x (resp. y) coordinates are in X (resp. Y). If flag is 1, join points, other non-0 flags should be combinations of bits 8,16,32,64,128,256 meaning the same as for ploth()."}, {"plothrawexport",0,(void*)plothrawexport,16,"GGGD0,L,","plothrawexport(fmt, X,Y,{flag=0}): plot in high resolution points whose x (resp. y) coordinates are in X (resp. Y), returning the resulting picture as a character string. If flag is 1, join points, other non-0 flags should be combinations of bits 8,16,32,64,128,256 meaning the same as for ploth()."}, {"plothsizes",0,(void*)plothsizes,16,"D0,L,","plothsizes({flag=0}): returns array of 8 elements: terminal width and height, sizes for ticks in horizontal and vertical directions, width and height of characters, width and height of display (if applicable). If flag=0, sizes of ticks and characters are in pixels, otherwise are fractions of the terminal size."}, {"plotinit",0,(void*)plotinit,16,"vLDGDGD0,L,","plotinit(w,{x},{y},{flag=0}): initialize rectwindow w to size x,y. If flag!=0, x and y express fractions of the size of the current output device. Omitting x or y means use the full size of the device."}, {"plotkill",0,(void*)plotkill,16,"vL","plotkill(w): erase the rectwindow w."}, {"plotlines",0,(void*)plotlines,16,"vLGGD0,L,","plotlines(w,X,Y,{flag=0}): draws an open polygon in rectwindow w where X and Y contain the x (resp. y) coordinates of the vertices. If X and Y are both single values (i.e not vectors), draw the corresponding line (and move cursor). If (optional) flag is non-zero, close the polygon."}, {"plotlinetype",0,(void*)plotlinetype,16,"vLL","plotlinetype(w,type): this function is obsolete; no graphing engine implement this functionality."}, {"plotmove",0,(void*)plotmove,16,"vLGG","plotmove(w,x,y): move cursor to position x,y in rectwindow w."}, {"plotpoints",0,(void*)plotpoints,16,"vLGG","plotpoints(w,X,Y): draws in rectwindow w the points whose x (resp y) coordinates are in X (resp Y). If X and Y are both single values (i.e not vectors), draw the corresponding point (and move cursor)."}, {"plotpointsize",0,(void*)plotpointsize,16,"vLG","plotpointsize(w,size): change the \"size\" of following points in rectwindow w. w=-1 changes global value."}, {"plotpointtype",0,(void*)plotpointtype,16,"vLL","plotpointtype(w,type): this function is obsolete; no graphing engine implement this functionality."}, {"plotrbox",0,(void*)plotrbox,16,"vLGGD0,L,","plotrbox(w,dx,dy,{filled}): if the cursor is at (x1,y1), draw a box with diagonal (x1,y1)-(x1+dx,y1+dy) in rectwindow w (cursor does not move). If filled=1, fill the box."}, {"plotrecth",0,(void*)plotrecth0,16,"LV=GGED0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096","plotrecth(w,X=a,b,expr,{flag=0},{n=0}): writes to rectwindow w the curve output of ploth(w,X=a,b,expr,flag,n). Returns a vector for the bounding box."}, {"plotrecthraw",0,(void*)plotrecthraw,16,"LGD0,L,","plotrecthraw(w,data,{flags=0}): plot graph(s) for data in rectwindow w, where data is a vector of vectors. If plot is parametric, length of data should be even, and pairs of entries give curves to plot. If not, first entry gives x-coordinate, and the other ones y-coordinates. Admits the same optional flags as plotrecth, save that recursive plot is meaningless."}, {"plotrline",0,(void*)plotrline,16,"vLGG","plotrline(w,dx,dy): if the cursor is at (x1,y1), draw a line from (x1,y1) to (x1+dx,y1+dy) (and move the cursor) in the rectwindow w."}, {"plotrmove",0,(void*)plotrmove,16,"vLGG","plotrmove(w,dx,dy): move cursor to position (dx,dy) relative to the present position in the rectwindow w."}, {"plotrpoint",0,(void*)plotrpoint,16,"vLGG","plotrpoint(w,dx,dy): draw a point (and move cursor) at position dx,dy relative to present position of the cursor in rectwindow w."}, {"plotscale",0,(void*)plotscale,16,"vLGGGG","plotscale(w,x1,x2,y1,y2): scale the coordinates in rectwindow w so that x goes from x1 to x2 and y from y1 to y2 (y2 0 if f = Phi_n, the n-th cyclotomic polynomial."}, {"poliscycloprod",0,(void*)poliscycloprod,6,"lG","poliscycloprod(f): returns 1 if f is a product of cyclotomic polynonials, and 0 otherwise."}, {"polisirreducible",0,(void*)isirreducible,6,"lG","polisirreducible(pol): true(1) if pol is an irreducible non-constant polynomial, false(0) if pol is reducible or constant."}, {"pollead",0,(void*)pollead,6,"GDn","pollead(x,{v}): leading coefficient of polynomial or series x, or x itself if x is a scalar. Error otherwise. With respect to the main variable of x if v is omitted, with respect to the variable v otherwise."}, {"pollegendre",0,(void*)pollegendre_eval,6,"LDG","pollegendre(n,{a='x}): legendre polynomial of degree n evaluated at a."}, {"polmodular",0,(void*)polmodular,6,"LD0,L,DGDnD0,L,","polmodular(L, {inv = 0}, {x = 'x}, {y = 'y}, {derivs = 0}): return the modular polynomial of level L and invariant inv."}, {"polrecip",0,(void*)polrecip,6,"G","polrecip(pol): reciprocal polynomial of pol."}, {"polred",0,(void*)polred0,10,"GD0,L,DG","polred(T,{flag=0}): deprecated, use polredbest. Reduction of the polynomial T (gives minimal polynomials only). The following binary digits of (optional) flag are significant 1: partial reduction, 2: gives also elements."}, {"polredabs",0,(void*)polredabs0,10,"GD0,L,","polredabs(T,{flag=0}): a smallest generating polynomial of the number field for the T2 norm on the roots, with smallest index for the minimal T2 norm. flag is optional, whose binary digit mean 1: give the element whose characteristic polynomial is the given polynomial. 4: give all polynomials of minimal T2 norm (give only one of P(x) and P(-x))."}, {"polredbest",0,(void*)polredbest,10,"GD0,L,","polredbest(T,{flag=0}): reduction of the polynomial T (gives minimal polynomials only). If flag=1, gives also elements."}, {"polredord",0,(void*)polredord,10,"G","polredord(x): this function is obsolete, use polredbest."}, {"polresultant",0,(void*)polresultant0,6,"GGDnD0,L,","polresultant(x,y,{v},{flag=0}): resultant of the polynomials x and y, with respect to the main variables of x and y if v is omitted, with respect to the variable v otherwise. flag is optional, and can be 0: default, uses either the subresultant algorithm, a modular algorithm or Sylvester's matrix, depending on the inputs; 1 uses Sylvester's matrix (should always be slower than the default)."}, {"polresultantext",0,(void*)polresultantext0,6,"GGDn","polresultantext(A,B,{v}): return [U,V,R] such that R=polresultant(A,B,v) and U*A+V*B = R, where A and B are polynomials."}, {"polroots",0,(void*)roots,6,"Gp","polroots(T): complex roots of the polynomial T using Schonhage's method, as modified by Gourdon."}, {"polrootsbound",0,(void*)polrootsbound,6,"GDG","polrootsbound(T, {tau = 0.01}): return a sharp upper bound for the modulus of the largest complex root of the polynomial T with relative error tau."}, {"polrootsff",0,(void*)polrootsff,6,"GDGDG","polrootsff(x,{p},{a}): obsolete, use polrootsmod."}, {"polrootsmod",0,(void*)polrootsmod,6,"GDG","polrootsmod(f,{D}): roots of the polynomial f over the finite field defined by the domain D."}, {"polrootspadic",0,(void*)rootpadic,6,"GGL","polrootspadic(x,p,r): p-adic roots of the polynomial x to precision r."}, {"polrootsreal",0,(void*)realroots,6,"GDGp","polrootsreal(T, {ab}): real roots of the polynomial T with real coefficients, using Uspensky's method. In interval ab = [a,b] if present."}, {"polsturm",0,(void*)sturmpart,6,"lGDGDG","polsturm(T,{ab}): number of distinct real roots of the polynomial T (in the interval ab = [a,b] if present)."}, {"polsubcyclo",0,(void*)polsubcyclo,6,"LLDn","polsubcyclo(n,d,{v='x}): finds an equation (in variable v) for the d-th degree subfields of Q(zeta_n). Output is a polynomial, or a vector of polynomials if there are several such fields or none."}, {"polsylvestermatrix",0,(void*)sylvestermatrix,6,"GG","polsylvestermatrix(x,y): forms the sylvester matrix attached to the two polynomials x and y. Warning: the polynomial coefficients are in columns, not in rows."}, {"polsym",0,(void*)polsym,6,"GL","polsym(x,n): column vector of symmetric powers of the roots of x up to n."}, {"poltchebi",0,(void*)polchebyshev1,6,"LDn","poltchebi(n,{v='x}): deprecated alias for polchebyshev."}, {"poltschirnhaus",0,(void*)tschirnhaus,10,"G","poltschirnhaus(x): random Tschirnhausen transformation of the polynomial x."}, {"polylog",0,(void*)polylog0,8,"LGD0,L,p","polylog(m,x,{flag=0}): m-th polylogarithm of x. flag is optional, and can be 0: default, 1: D_m~-modified m-th polylog of x, 2: D_m-modified m-th polylog of x, 3: P_m-modified m-th polylog of x."}, {"polzagier",0,(void*)polzag,6,"LL","polzagier(n,m): Zagier's polynomials of index n,m."}, {"powers",0,(void*)gpowers0,2,"GLDG","powers(x,n,{x0}): return the vector [1,x,...,x^n] if x0 is omitted, and [x0, x0*x, ..., x0*x^n] otherwise."}, {"precision",0,(void*)precision0,3,"GD0,L,","precision(x,{n}): if n is present, return x at precision n. If n is omitted, return real precision of object x."}, {"precprime",0,(void*)precprime,5,"G","precprime(x): largest pseudoprime <= x, 0 if x<=1."}, {"prime",0,(void*)prime,5,"L","prime(n): returns the n-th prime (n C-integer)."}, {"primecert",0,(void*)primecert,5,"GD0,L,","primecert(N, {flag=0}): If N is a prime, return a Primality Certificate. Return 0 otherwise. If flag = 0 return an ECPP certificate (Atkin-Morain); if flag = 1 return an N-1 certificate (Pocklington-Lehmer)"}, {"primecertexport",0,(void*)primecertexport,5,"GD0,L,","primecertexport(cert, {format = 0}): Returns a string suitable for print/write to display a primality certificate."}, {"primecertisvalid",0,(void*)primecertisvalid,5,"lG","primecertisvalid(cert): Verifies if cert is a valid PARI ECPP Primality certificate."}, {"primepi",0,(void*)primepi,5,"G","primepi(x): the prime counting function pi(x) = #{p <= x, p prime}."}, {"primes",0,(void*)primes0,5,"G","primes(n): returns the vector of the first n primes (integer), or the primes in interval n = [a,b]."}, {"print",0,(void*)print,1,"vs*","print({str}*): outputs its string arguments (in raw format) ending with a newline."}, {"print1",0,(void*)print1,1,"vs*","print1({str}*): outputs its string arguments (in raw format) without ending with newline."}, {"printf",0,(void*)printf0,1,"vss*","printf(fmt,{x}*): prints its arguments according to the format fmt."}, {"printp",0,(void*)printp,1,"vs*","printp({str}*): outputs its string arguments (in prettymatrix format) ending with a newline."}, {"printsep",0,(void*)printsep,1,"vss*","printsep(sep,{str}*): outputs its string arguments (in raw format), separated by 'sep', ending with a newline."}, {"printsep1",0,(void*)printsep1,1,"vss*","printsep1(sep,{str}*): outputs its string arguments (in raw format), separated by 'sep', without ending with a newline."}, {"printtex",0,(void*)printtex,1,"vs*","printtex({str}*): outputs its string arguments in TeX format."}, {"prod",0,(void*)produit,9,"V=GGEDG","prod(X=a,b,expr,{x=1}): x times the product (X runs from a to b) of expression."}, {"prodeuler",0,(void*)prodeuler0,9,"V=GGEp","prodeuler(X=a,b,expr): Euler product (X runs over the primes between a and b) of real or complex expression."}, {"prodeulerrat",0,(void*)prodeulerrat,9,"GDGD2,L,p","prodeulerrat(F,{s=1},{a=2}): product from primes p = a to infinity of F(p^s), where F is a rational function."}, {"prodinf",0,(void*)prodinf0,9,"V=GED0,L,p","prodinf(X=a,expr,{flag=0}): infinite product (X goes from a to infinity) of real or complex expression. flag can be 0 (default) or 1, in which case compute the product of the 1+expr instead."}, {"prodnumrat",0,(void*)prodnumrat,9,"GLp","prodnumrat(F,a): product from n = a to infinity of F(n), where F-1 is a rational function of degree less than or equal to -2."}, {"psdraw",0,(void*)psdraw,16,"vGD0,L,","psdraw(list, {flag=0}): obsolete function."}, {"psi",0,(void*)gpsi,8,"Gp","psi(x): psi-function at x."}, {"psploth",0,(void*)psploth0,16,"V=GGED0,L,D0,L,p","psploth(X=a,b,expr,{flags=0},{n=0}): obsolete function."}, {"psplothraw",0,(void*)psplothraw,16,"GGD0,L,","psplothraw(listx,listy,{flag=0}): obsolete function."}, {"qfauto",0,(void*)qfauto0,7,"GDG","qfauto(G,{fl}): automorphism group of the positive definite quadratic form G."}, {"qfautoexport",0,(void*)qfautoexport,7,"GD0,L,","qfautoexport(qfa,{flag}): qfa being an automorphism group as output by qfauto, output a string representing the underlying matrix group in GAP notation (default) or Magma notation (flag = 1)."}, {"qfbclassno",0,(void*)qfbclassno0,5,"GD0,L,","qfbclassno(D,{flag=0}): class number of discriminant D using Shanks's method by default. If (optional) flag is set to 1, use Euler products."}, {"qfbcompraw",0,(void*)qfbcompraw,5,"GG","qfbcompraw(x,y): Gaussian composition without reduction of the binary quadratic forms x and y."}, {"qfbhclassno",0,(void*)hclassno,5,"G","qfbhclassno(x): Hurwitz-Kronecker class number of x>0."}, {"qfbil",0,(void*)qfbil,7,"GGDG","qfbil(x,y,{q}): this function is obsolete, use qfeval."}, {"qfbnucomp",0,(void*)nucomp,5,"GGG","qfbnucomp(x,y,L): composite of primitive positive definite quadratic forms x and y using nucomp and nudupl, where L=[|D/4|^(1/4)] is precomputed."}, {"qfbnupow",0,(void*)nupow,5,"GGDG","qfbnupow(x,n,{L}): n-th power of primitive positive definite quadratic form x using nucomp and nudupl."}, {"qfbpowraw",0,(void*)qfbpowraw,5,"GL","qfbpowraw(x,n): n-th power without reduction of the binary quadratic form x."}, {"qfbprimeform",0,(void*)primeform,5,"GGp","qfbprimeform(x,p): returns the prime form of discriminant x, whose first coefficient is p."}, {"qfbred",0,(void*)qfbred0,5,"GD0,L,DGDGDG","qfbred(x,{flag=0},{d},{isd},{sd}): reduction of the binary quadratic form x. All other args. are optional. The arguments d, isd and sd, if present, supply the values of the discriminant, floor(sqrt(d)) and sqrt(d) respectively. If d<0, its value is not used and all references to Shanks's distance hereafter are meaningless. flag can be any of 0: default, uses Shanks's distance function d; 1: use d, do a single reduction step; 2: do not use d; 3: do not use d, single reduction step."}, {"qfbredsl2",0,(void*)qfbredsl2,5,"GDG","qfbredsl2(x,{data}): reduction of the binary quadratic form x, return [y,g] where y is reduced and g in Sl(2,Z) is such that g.x = y; data, if present, must be equal to [D, sqrtint(D)], where D > 0 is the discriminant of x."}, {"qfbsolve",0,(void*)qfbsolve,5,"GG","qfbsolve(Q,p): return [x,y] so that Q(x,y)=p where Q is a binary quadratic form and p a prime number, or 0 if there is no solution."}, {"qfeval",0,(void*)qfeval0,7,"DGGDG","qfeval({q},x,{y}): evaluate the quadratic form q (symmetric matrix) at x; if y is present, evaluate the polar form at (x,y); if q omitted, use the standard Euclidean form."}, {"qfgaussred",0,(void*)qfgaussred,7,"G","qfgaussred(q): square reduction of the (symmetric) matrix q (returns a square matrix whose i-th diagonal term is the coefficient of the i-th square in which the coefficient of the i-th variable is 1)."}, {"qfisom",0,(void*)qfisom0,7,"GGDGDG","qfisom(G,H,{fl},{grp}): find an isomorphism between the integral positive definite quadratic forms G and H if it exists. G can also be given by a qfisominit structure which is preferable if several forms need to be compared to G."}, {"qfisominit",0,(void*)qfisominit0,7,"GDGDG","qfisominit(G,{fl},{m}): G being a square and symmetric matrix representing an integral positive definite quadratic form, this function returns a structure allowing to compute isomorphisms between G and other quadratic form faster."}, {"qfjacobi",0,(void*)jacobi,7,"Gp","qfjacobi(A): eigenvalues and orthogonal matrix of eigenvectors of the real symmetric matrix A."}, {"qflll",0,(void*)qflll0,7,"GD0,L,","qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients."}, {"qflllgram",0,(void*)qflllgram0,7,"GD0,L,","qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix is G (gives the unimodular transformation matrix). flag is optional and can be 0: default,1: assumes x is integral, 4: assumes x is integral, returns [K,T], where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients."}, {"qfminim",0,(void*)qfminim0,7,"GDGDGD0,L,p","qfminim(x,{b},{m},{flag=0}): x being a square and symmetric matrix representing a positive definite quadratic form, this function deals with the vectors of x whose norm is less than or equal to b, enumerated using the Fincke-Pohst algorithm, storing at most m vectors (no limit if m is omitted). The function searches for the minimal non-zero vectors if b is omitted. The precise behavior depends on flag. 0: returns at most 2m vectors (unless m omitted), returns [N,M,mat] where N is the number of vectors enumerated, M the maximum norm among these, and mat lists half the vectors (the other half is given by -mat). 1: ignores m and returns the first vector whose norm is less than b. 2: as 0 but uses a more robust, slower implementation, valid for non integral quadratic forms."}, {"qfnorm",0,(void*)qfnorm,7,"GDG","qfnorm(x,{q}): this function is obsolete, use qfeval."}, {"qforbits",0,(void*)qforbits,7,"GG","qforbits(G,V): return the orbits of V under the action of the group of linear transformation generated by the set G, which must stabilize V."}, {"qfparam",0,(void*)qfparam,7,"GGD0,L,","qfparam(G, sol, {flag = 0}): coefficients of binary quadratic forms that parametrize the solutions of the ternary quadratic form G, using the particular solution sol."}, {"qfperfection",0,(void*)perf,7,"G","qfperfection(G): rank of matrix of xx~ for x minimal vectors of a gram matrix G."}, {"qfrep",0,(void*)qfrep0,7,"GGD0,L,","qfrep(q,B,{flag=0}): vector of (half) the number of vectors of norms from 1 to B for the integral and definite quadratic form q. If flag is 1, count vectors of even norm from 1 to 2B."}, {"qfsign",0,(void*)qfsign,7,"G","qfsign(x): signature of the symmetric matrix x."}, {"qfsolve",0,(void*)qfsolve,7,"G","qfsolve(G): solve over Q the quadratic equation X^t G X = 0, where G is a symmetric matrix."}, {"quadclassunit",0,(void*)quadclassunit0,5,"GD0,L,DGp","quadclassunit(D,{flag=0},{tech=[]}): compute the structure of the class group and the regulator of the quadratic field of discriminant D. See manual for the optional technical parameters."}, {"quaddisc",0,(void*)quaddisc,5,"G","quaddisc(x): discriminant of the quadratic field Q(sqrt(x))."}, {"quadgen",0,(void*)quadgen0,5,"GDn","quadgen(D,{v = 'w}): standard generator g of quadratic order of discriminant D. If v is given, the variable name is used to display g, else 'w' is used."}, {"quadhilbert",0,(void*)quadhilbert,5,"Gp","quadhilbert(D): relative equation for the Hilbert class field of the quadratic field of discriminant D (which can also be a bnf)."}, {"quadpoly",0,(void*)quadpoly0,5,"GDn","quadpoly(D,{v='x}): quadratic polynomial corresponding to the discriminant D, in variable v."}, {"quadray",0,(void*)quadray,5,"GGp","quadray(D,f): relative equation for the ray class field of conductor f for the quadratic field of discriminant D (which can also be a bnf)."}, {"quadregulator",0,(void*)quadregulator,5,"Gp","quadregulator(x): regulator of the real quadratic field of discriminant x."}, {"quadunit",0,(void*)quadunit0,5,"GDn","quadunit(D,{v = 'w}): fundamental unit u of the quadratic field of discriminant D where D must be positive. If v is given, the variable name is used to display u, else 'w' is used."}, {"ramanujantau",0,(void*)ramanujantau,5,"G","ramanujantau(n): compute the value of Ramanujan's tau function at n, assuming the GRH. Algorithm in O(n^{1/2+eps})."}, {"random",0,(void*)genrand,3,"DG","random({N=2^31}): random object, depending on the type of N. Integer between 0 and N-1 (t_INT), int mod N (t_INTMOD), element in a finite field (t_FFELT), point on an elliptic curve (ellinit mod p or over a finite field)."}, {"randomprime",0,(void*)randomprime,5,"DG","randomprime({N = 2^31}): returns a strong pseudo prime in [2, N-1]."}, {"read",0,(void*)gp_read_file,1,"D\"\",s,","read({filename}): read from the input file filename. If filename is omitted, reread last input file, be it from read() or \\r."}, {"readstr",0,(void*)readstr,1,"D\"\",s,","readstr({filename}): returns the vector of GP strings containing the lines in filename."}, {"readvec",0,(void*)gp_readvec_file,1,"D\"\",s,","readvec({filename}): create a vector whose components are the evaluation of all the expressions found in the input file filename."}, {"real",0,(void*)greal,3,"G","real(x): real part of x."}, {"removeprimes",0,(void*)removeprimes,5,"DG","removeprimes({x=[]}): remove primes in the vector x from the prime table. x can also be a single integer. List the current extra primes if x is omitted."}, {"return",0,(void*)return0,1,"DG","return({x=0}): return from current subroutine with result x."}, {"rnfalgtobasis",0,(void*)rnfalgtobasis,10,"GG","rnfalgtobasis(rnf,x): relative version of nfalgtobasis, where rnf is a relative numberfield."}, {"rnfbasis",0,(void*)rnfbasis,10,"GG","rnfbasis(bnf,M): given a projective Z_K-module M as output by rnfpseudobasis or rnfsteinitz, gives either a basis of M if it is free, or an n+1-element generating set."}, {"rnfbasistoalg",0,(void*)rnfbasistoalg,10,"GG","rnfbasistoalg(rnf,x): relative version of nfbasistoalg, where rnf is a relative numberfield."}, {"rnfcharpoly",0,(void*)rnfcharpoly,10,"GGGDn","rnfcharpoly(nf,T,a,{var='x}): characteristic polynomial of a over nf, where a belongs to the algebra defined by T over nf. Returns a polynomial in variable var (x by default)."}, {"rnfconductor",0,(void*)rnfconductor,10,"GG","rnfconductor(bnf,T): conductor of the Abelian extension of bnf defined by T. The result is [conductor,bnr,subgroup], where conductor is the conductor itself, bnr the attached bnr structure, and subgroup the HNF defining the norm group (Artin or Takagi group) on the given generators bnr.gen."}, {"rnfdedekind",0,(void*)rnfdedekind,10,"GGDGD0,L,","rnfdedekind(nf,pol,{pr},{flag=0}): relative Dedekind criterion over the number field K, represented by nf, applied to the order O_K[X]/(P), modulo the prime ideal pr (at all primes if pr omitted, in which case flag is automatically set to 1). P is assumed to be monic, irreducible, in O_K[X]. Returns [max,basis,v], where basis is a pseudo-basis of the enlarged order, max is 1 iff this order is pr-maximal, and v is the valuation at pr of the order discriminant. If flag is set, just return 1 if the order is maximal, and 0 if not."}, {"rnfdet",0,(void*)rnfdet,10,"GG","rnfdet(nf,M): given a pseudo-matrix M, compute its determinant."}, {"rnfdisc",0,(void*)rnfdiscf,10,"GG","rnfdisc(nf,T): given a polynomial T with coefficients in nf, gives a 2-component vector [D,d], where D is the relative ideal discriminant, and d is the relative discriminant in nf^*/nf*^2."}, {"rnfeltabstorel",0,(void*)rnfeltabstorel,10,"GG","rnfeltabstorel(rnf,x): transforms the element x from absolute to relative representation."}, {"rnfeltdown",0,(void*)rnfeltdown0,10,"GGD0,L,","rnfeltdown(rnf,x,{flag=0}): expresses x on the base field if possible; returns an error otherwise."}, {"rnfeltnorm",0,(void*)rnfeltnorm,10,"GG","rnfeltnorm(rnf,x): returns the relative norm N_{L/K}(x), as an element of K."}, {"rnfeltreltoabs",0,(void*)rnfeltreltoabs,10,"GG","rnfeltreltoabs(rnf,x): transforms the element x from relative to absolute representation."}, {"rnfelttrace",0,(void*)rnfelttrace,10,"GG","rnfelttrace(rnf,x): returns the relative trace Tr_{L/K}(x), as an element of K."}, {"rnfeltup",0,(void*)rnfeltup0,10,"GGD0,L,","rnfeltup(rnf,x,{flag=0}): expresses x (belonging to the base field) on the relative field. As a t_POLMOD if flag = 0 and as a t_COL on the absolute field integer basis if flag = 1."}, {"rnfequation",0,(void*)rnfequation0,10,"GGD0,L,","rnfequation(nf,pol,{flag=0}): given a pol with coefficients in nf, gives an absolute equation z of the number field defined by pol. flag is optional, and can be 0: default, or non-zero, gives [z,al,k], where z defines the absolute equation L/Q as in the default behavior, al expresses as an element of L a root of the polynomial defining the base field nf, and k is a small integer such that t = b + k al is a root of z, for b a root of pol."}, {"rnfhnfbasis",0,(void*)rnfhnfbasis,10,"GG","rnfhnfbasis(bnf,x): given an order x as output by rnfpseudobasis, gives either a true HNF basis of the order if it exists, zero otherwise."}, {"rnfidealabstorel",0,(void*)rnfidealabstorel,10,"GG","rnfidealabstorel(rnf,x): transforms the ideal x from absolute to relative representation."}, {"rnfidealdown",0,(void*)rnfidealdown,10,"GG","rnfidealdown(rnf,x): finds the intersection of the ideal x with the base field."}, {"rnfidealfactor",0,(void*)rnfidealfactor,10,"GG","rnfidealfactor(rnf,x): factor the ideal x into prime ideals in the number field nfinit(rnf)."}, {"rnfidealhnf",0,(void*)rnfidealhnf,10,"GG","rnfidealhnf(rnf,x): relative version of idealhnf, where rnf is a relative numberfield."}, {"rnfidealmul",0,(void*)rnfidealmul,10,"GGG","rnfidealmul(rnf,x,y): relative version of idealmul, where rnf is a relative numberfield."}, {"rnfidealnormabs",0,(void*)rnfidealnormabs,10,"GG","rnfidealnormabs(rnf,x): absolute norm of the ideal x."}, {"rnfidealnormrel",0,(void*)rnfidealnormrel,10,"GG","rnfidealnormrel(rnf,x): relative norm of the ideal x."}, {"rnfidealprimedec",0,(void*)rnfidealprimedec,10,"GG","rnfidealprimedec(rnf,pr): return prime ideal decomposition of the maximal ideal pr of K in L/K; pr is also allowed to be a prime number p, in which case return a pair of vectors [SK,SL], where SK contains the primes of K above p and SL[i] is the vector of primes of L above SK[i]."}, {"rnfidealreltoabs",0,(void*)rnfidealreltoabs0,10,"GGD0,L,","rnfidealreltoabs(rnf,x,{flag=0}): transforms the ideal x from relative to absolute representation. As a vector of t_POLMODs if flag = 0 and as an ideal in HNF in the absolute field if flag = 1."}, {"rnfidealtwoelt",0,(void*)rnfidealtwoelement,10,"GG","rnfidealtwoelt(rnf,x): relative version of idealtwoelt, where rnf is a relative numberfield."}, {"rnfidealup",0,(void*)rnfidealup0,10,"GGD0,L,","rnfidealup(rnf,x,{flag=0}): lifts the ideal x (of the base field) to the relative field. As a vector of t_POLMODs if flag = 0 and as an ideal in HNF in the absolute field if flag = 1."}, {"rnfinit",0,(void*)rnfinit0,10,"GGD0,L,","rnfinit(nf,T,{flag=0}): T being an irreducible polynomial defined over the number field nf, initializes a vector of data necessary for working in relative number fields (rnf functions). See manual for technical details."}, {"rnfisabelian",0,(void*)rnfisabelian,10,"lGG","rnfisabelian(nf,T): T being a relative polynomial with coefficients in nf, return 1 if it defines an abelian extension, and 0 otherwise."}, {"rnfisfree",0,(void*)rnfisfree,10,"lGG","rnfisfree(bnf,x): given an order x as output by rnfpseudobasis or rnfsteinitz, outputs true (1) or false (0) according to whether the order is free or not."}, {"rnfislocalcyclo",0,(void*)rnfislocalcyclo,10,"lG","rnfislocalcyclo(rnf): true(1) if the l-extension attached to rnf is locally cyclotomic (locally contained in the Z_l extension of K_v at all places v | l), false(0) if not."}, {"rnfisnorm",0,(void*)rnfisnorm,10,"GGD0,L,","rnfisnorm(T,a,{flag=0}): T is as output by rnfisnorminit applied to L/K. Tries to tell whether a is a norm from L/K. Returns a vector [x,q] where a=Norm(x)*q. Looks for a solution which is a S-integer, with S a list of places in K containing the ramified primes, generators of the class group of ext, as well as those primes dividing a. If L/K is Galois, omit flag, otherwise it is used to add more places to S: all the places above the primes p <= flag (resp. p | flag) if flag > 0 (resp. flag < 0). The answer is guaranteed (i.e a is a norm iff q=1) if L/K is Galois or, under GRH, if S contains all primes less than 12.log(disc(M))^2, where M is the normal closure of L/K."}, {"rnfisnorminit",0,(void*)rnfisnorminit,10,"GGD2,L,","rnfisnorminit(pol,polrel,{flag=2}): let K be defined by a root of pol, L/K the extension defined by polrel. Compute technical data needed by rnfisnorm to solve norm equations Nx = a, for x in L, and a in K. If flag=0, do not care whether L/K is Galois or not; if flag = 1, assume L/K is Galois; if flag = 2, determine whether L/K is Galois."}, {"rnfkummer",0,(void*)rnfkummer,10,"GDGD0,L,p","rnfkummer(bnr,{subgp},{d=0}): bnr being as output by bnrinit, finds a relative equation for the class field corresponding to the module in bnr and the given congruence subgroup (the ray class field if subgp is omitted). d can be zero (default), or positive, and in this case the output is the list of all relative equations of degree d for the given bnr, with the same conductor as (bnr, subgp)."}, {"rnflllgram",0,(void*)rnflllgram,10,"GGGp","rnflllgram(nf,pol,order): given a pol with coefficients in nf and an order as output by rnfpseudobasis or similar, gives [[neworder],U], where neworder is a reduced order and U is the unimodular transformation matrix."}, {"rnfnormgroup",0,(void*)rnfnormgroup,10,"GG","rnfnormgroup(bnr,pol): norm group (or Artin or Takagi group) corresponding to the Abelian extension of bnr.bnf defined by pol, where the module corresponding to bnr is assumed to be a multiple of the conductor. The result is the HNF defining the norm group on the generators in bnr.gen."}, {"rnfpolred",0,(void*)rnfpolred,10,"GGp","rnfpolred(nf,pol): given a pol with coefficients in nf, finds a list of relative polynomials defining some subfields, hopefully simpler."}, {"rnfpolredabs",0,(void*)rnfpolredabs,10,"GGD0,L,","rnfpolredabs(nf,pol,{flag=0}): given an irreducible pol with coefficients in nf, finds a canonical relative polynomial defining the same field. Binary digits of flag mean: 1: return also the element whose characteristic polynomial is the given polynomial, 2: return an absolute polynomial, 16: partial reduction."}, {"rnfpolredbest",0,(void*)rnfpolredbest,10,"GGD0,L,","rnfpolredbest(nf,pol,{flag=0}): given a pol with coefficients in nf, finds a relative polynomial P defining the same field, hopefully simpler than pol; flag can be 0: default, 1: return [P,a], where a is a root of pol 2: return an absolute polynomial Pabs, 3: return [Pabs, a,b], where a is a root of nf.pol and b is a root of pol."}, {"rnfpseudobasis",0,(void*)rnfpseudobasis,10,"GG","rnfpseudobasis(nf,T): given an irreducible polynomial T with coefficients in nf, returns [A,J,D,d] where [A,J] is a pseudo basis of the maximal order of the extension, D is the relative ideal discriminant, and d is the relative discriminant in nf^*/nf*^2."}, {"rnfsteinitz",0,(void*)rnfsteinitz,10,"GG","rnfsteinitz(nf,x): given an order x as output by rnfpseudobasis, gives [A,I,D,d] where (A,I) is a pseudo basis where all the ideals except perhaps the last are trivial."}, {"round",0,(void*)round0,3,"GD&","round(x,{&e}): take the nearest integer to all the coefficients of x. If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits."}, {"select",0,(void*)select0,1,"GGD0,L,","select(f, A, {flag = 0}): selects elements of A according to the selection function f. If flag is 1, return the indices of those elements (indirect selection)."}, {"self",0,(void*)pari_self,1,"m","self(): return the calling function or closure. Useful for defining anonymous recursive functions."}, {"seralgdep",0,(void*)seralgdep,7,"GLL","seralgdep(s,p,r): find a linear relation between powers (1,s, ..., s^p) of the series s, with polynomial coefficients of degree <= r."}, {"serchop",0,(void*)serchop,3,"GD0,L,","serchop(s,{n=0}): remove all terms of degree strictly less than n in series s."}, {"serconvol",0,(void*)convol,6,"GG","serconvol(x,y): convolution (or Hadamard product) of two power series."}, {"serlaplace",0,(void*)laplace,6,"G","serlaplace(x): replaces the power series sum of a_n*x^n/n! by sum of a_n*x^n. For the reverse operation, use serconvol(x,exp(X))."}, {"serprec",0,(void*)gpserprec,3,"Gn","serprec(x,v): return the absolute precision x with respect to power series in the variable v."}, {"serreverse",0,(void*)serreverse,6,"G","serreverse(s): reversion of the power series s."}, {"setbinop",0,(void*)setbinop,7,"GGDG","setbinop(f,X,{Y}): the set {f(x,y), x in X, y in Y}. If Y is omitted, assume that X = Y and that f is symmetric."}, {"setintersect",0,(void*)setintersect,7,"GG","setintersect(x,y): intersection of the sets x and y."}, {"setisset",0,(void*)setisset,7,"lG","setisset(x): true(1) if x is a set (row vector with strictly increasing entries), false(0) if not."}, {"setminus",0,(void*)setminus,7,"GG","setminus(x,y): set of elements of x not belonging to y."}, {"setrand",0,(void*)setrand,1,"vG","setrand(n): reset the seed of the random number generator to n."}, {"setsearch",0,(void*)setsearch,7,"lGGD0,L,","setsearch(S,x,{flag=0}): determines whether x belongs to the set (or sorted list) S. If flag is 0 or omitted, returns 0 if it does not, otherwise returns the index j such that x==S[j]. If flag is non-zero, return 0 if x belongs to S, otherwise the index j where it should be inserted."}, {"setunion",0,(void*)setunion,7,"GG","setunion(x,y): union of the sets x and y."}, {"shift",0,(void*)gshift,2,"GL","shift(x,n): shift x left n bits if n>=0, right -n bits if n<0."}, {"shiftmul",0,(void*)gmul2n,2,"GL","shiftmul(x,n): multiply x by 2^n (n>=0 or n<0)."}, {"sigma",0,(void*)sumdivk,5,"GD1,L,","sigma(x,{k=1}): sum of the k-th powers of the divisors of x. k is optional and if omitted is assumed to be equal to 1."}, {"sign",0,(void*)gsigne,2,"iG","sign(x): sign of x, of type integer, real or fraction."}, {"simplify",0,(void*)simplify,3,"G","simplify(x): simplify the object x as much as possible."}, {"sin",0,(void*)gsin,8,"Gp","sin(x): sine of x."}, {"sinc",0,(void*)gsinc,8,"Gp","sinc(x): sinc function of x."}, {"sinh",0,(void*)gsinh,8,"Gp","sinh(x): hyperbolic sine of x."}, {"sizebyte",0,(void*)gsizebyte,3,"lG","sizebyte(x): number of bytes occupied by the complete tree of the object x."}, {"sizedigit",0,(void*)sizedigit,3,"lG","sizedigit(x): rough upper bound for the number of decimal digits of (the components of) x. DEPRECATED."}, {"solve",0,(void*)zbrent0,9,"V=GGEp","solve(X=a,b,expr): real root of expression expr (X between a and b), where expr(a)*expr(b)<=0."}, {"solvestep",0,(void*)solvestep0,9,"V=GGGED0,L,p","solvestep(X=a,b,step,expr,{flag=0}): find zeros of a function in the real interval [a,b] by naive interval splitting."}, {"sqr",0,(void*)gsqr,8,"G","sqr(x): square of x. NOT identical to x*x."}, {"sqrt",0,(void*)gsqrt,8,"Gp","sqrt(x): square root of x."}, {"sqrtint",0,(void*)sqrtint,5,"G","sqrtint(x): integer square root of x, where x is a non-negative integer."}, {"sqrtn",0,(void*)gsqrtn,8,"GGD&p","sqrtn(x,n,{&z}): nth-root of x, n must be integer. If present, z is set to a suitable root of unity to recover all solutions. If it was not possible, z is set to zero."}, {"sqrtnint",0,(void*)sqrtnint,5,"GL","sqrtnint(x,n): integer n-th root of x, where x is non-negative integer."}, {"stirling",0,(void*)stirling,4,"LLD1,L,","stirling(n,k,{flag=1}): if flag=1 (default) return the Stirling number of the first kind s(n,k), if flag=2, return the Stirling number of the second kind S(n,k)."}, {"subgrouplist",0,(void*)subgrouplist0,10,"GDGD0,L,","subgrouplist(bnr,{bound},{flag=0}): bnr being as output by bnrinit or a list of cyclic components of a finite Abelian group G, outputs the list of subgroups of G (of index bounded by bound, if not omitted), given as HNF left divisors of the SNF matrix corresponding to G. If flag=0 (default) and bnr is as output by bnrinit, gives only the subgroups for which the modulus is the conductor."}, {"subst",0,(void*)gsubst,6,"GnG","subst(x,y,z): in expression x, replace the variable y by the expression z."}, {"substpol",0,(void*)gsubstpol,6,"GGG","substpol(x,y,z): in expression x, replace the polynomial y by the expression z, using remainder decomposition of x."}, {"substvec",0,(void*)gsubstvec,6,"GGG","substvec(x,v,w): in expression x, make a best effort to replace the variables v1,...,vn by the expression w1,...,wn."}, {"sum",0,(void*)somme,9,"V=GGEDG","sum(X=a,b,expr,{x=0}): x plus the sum (X goes from a to b) of expression expr."}, {"sumalt",0,(void*)sumalt0,9,"V=GED0,L,p","sumalt(X=a,expr,{flag=0}): Cohen-Villegas-Zagier's acceleration of alternating series expr, X starting at a. flag is optional, and can be 0: default, or 1: uses a slightly different method using Zagier's polynomials."}, {"sumdedekind",0,(void*)sumdedekind,5,"GG","sumdedekind(h,k): Dedekind sum attached to h,k."}, {"sumdigits",0,(void*)sumdigits0,5,"GDG","sumdigits(n,{B=10}): sum of digits in the integer |n|, when written in base B."}, {"sumdiv",0,(void*)sumdivexpr,9,"GVE","sumdiv(n,X,expr): sum of expression expr, X running over the divisors of n."}, {"sumdivmult",0,(void*)sumdivmultexpr,9,"GVE","sumdivmult(n,d,expr): sum of multiplicative function expr, d running over the divisors of n."}, {"sumeulerrat",0,(void*)sumeulerrat,9,"GDGD2,L,p","sumeulerrat(F,{s=1},{a=2}): sum from primes p = a to infinity of F(p^s), where F is a rational function."}, {"sumformal",0,(void*)sumformal,6,"GDn","sumformal(f,{v}): formal sum of f with respect to v, or to the main variable of f if v is omitted."}, {"suminf",0,(void*)suminf0,9,"V=GEp","suminf(X=a,expr): infinite sum (X goes from a to infinity) of real or complex expression expr."}, {"sumnum",0,(void*)sumnum0,9,"V=GEDGp","sumnum(n=a,f,{tab}): numerical summation of f(n) from n = a to +infinity using Euler-MacLaurin summation. Assume that f corresponds to a series with positive terms and is a C^oo function; a must be an integer, and tab, if given, is the output of sumnuminit."}, {"sumnumap",0,(void*)sumnumap0,9,"V=GEDGp","sumnumap(n=a,f,{tab}): numerical summation of f(n) from n = a to +infinity using Abel-Plana formula. Assume that f is holomorphic in the right half-plane Re(z) > a; a must be an integer, and tab, if given, is the output of sumnumapinit."}, {"sumnumapinit",0,(void*)sumnumapinit,9,"DGp","sumnumapinit({asymp}): initialize tables for Abel-Plana summation of a series."}, {"sumnuminit",0,(void*)sumnuminit,9,"DGp","sumnuminit({asymp}): initialize tables for Euler-MacLaurin delta summation of a series with positive terms."}, {"sumnumlagrange",0,(void*)sumnumlagrange0,9,"V=GEDGp","sumnumlagrange(n=a,f,{tab}): numerical summation of f(n) from n = a to +infinity using Lagrange summation. a must be an integer, and tab, if given, is the output of sumnumlagrangeinit."}, {"sumnumlagrangeinit",0,(void*)sumnumlagrangeinit,9,"DGDGp","sumnumlagrangeinit({asymp}, {c1}): initialize tables for Lagrange summation of a series."}, {"sumnummonien",0,(void*)sumnummonien0,9,"V=GEDGp","sumnummonien(n=a,f,{tab}): numerical summation from n = a to +infinity using Monien summation."}, {"sumnummonieninit",0,(void*)sumnummonieninit,9,"DGDGDGp","sumnummonieninit({asymp},{w},{n0 = 1}): initialize tables for Monien summation of a series with positive terms."}, {"sumnumrat",0,(void*)sumnumrat,9,"GGp","sumnumrat(F,a): sum from n = a to infinity of F(n), where F is a rational function of degree less than or equal to -2."}, {"sumpos",0,(void*)sumpos0,9,"V=GED0,L,p","sumpos(X=a,expr,{flag=0}): sum of positive (or negative) series expr, the formal variable X starting at a. flag is optional, and can be 0: default, or 1: uses a slightly different method using Zagier's polynomials."}, {"system",0,(void*)gpsystem,1,"vs","system(str): str being a string, execute the system command str."}, {"tan",0,(void*)gtan,8,"Gp","tan(x): tangent of x."}, {"tanh",0,(void*)gtanh,8,"Gp","tanh(x): hyperbolic tangent of x."}, {"taylor",0,(void*)tayl,6,"GnDP","taylor(x,t,{d=seriesprecision}): taylor expansion of x with respect to t, adding O(t^d) to all components of x."}, {"teichmuller",0,(void*)teichmuller,8,"GDG","teichmuller(x,{tab}): teichmuller character of p-adic number x. If x = [p,n], return the lifts of all teichmuller(i + O(p^n)) for i = 1, ..., p-1. Such a vector can be fed back to teichmuller, as the optional argument tab, to speed up later computations."}, {"theta",0,(void*)theta,8,"GGp","theta(q,z): Jacobi sine theta-function."}, {"thetanullk",0,(void*)thetanullk,8,"GLp","thetanullk(q,k): k-th derivative at z=0 of theta(q,z)."}, {"thue",0,(void*)thue,6,"GGDG","thue(tnf,a,{sol}): solve the equation P(x,y)=a, where tnf was created with thueinit(P), and sol, if present, contains the solutions of Norm(x)=a modulo units in the number field defined by P. If tnf was computed without assuming GRH (flag 1 in thueinit), the result is unconditional. If tnf is a polynomial, compute thue(thueinit(P,0), a)."}, {"thueinit",0,(void*)thueinit,6,"GD0,L,p","thueinit(P,{flag=0}): initialize the tnf corresponding to P, that will be used to solve Thue equations P(x,y) = some-integer. If flag is non-zero, certify the result unconditionaly. Otherwise, assume GRH (much faster of course)."}, {"trace",0,(void*)gtrace,7,"G","trace(x): trace of x."}, {"trap",0,(void*)trap0,1,"DrDEDE","trap({e}, {rec}, seq): this function is obsolete, use \"iferr\". Try to execute seq, trapping runtime error e (all of them if e omitted); sequence rec is executed if the error occurs and is the result of the command."}, {"truncate",0,(void*)trunc0,3,"GD&","truncate(x,{&e}): truncation of x; when x is a power series,take away the O(X^). If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits."}, {"type",0,(void*)type0,1,"G","type(x): return the type of the GEN x."}, {"uninline",0,NULL,1,NULL,"uninline(): forget all inline variables [EXPERIMENTAL]."}, {"until",0,(void*)untilpari,1,"vEI","until(a,seq): evaluate the expression sequence seq until a is nonzero."}, {"valuation",0,(void*)gpvaluation,3,"GG","valuation(x,p): valuation of x with respect to p."}, {"varhigher",0,(void*)varhigher,3,"sDn","varhigher(name,{v}): return a variable 'name' whose priority is higher than the priority of v (of all existing variables if v is omitted)."}, {"variable",0,(void*)gpolvar,3,"DG","variable({x}): main variable of object x. Gives p for p-adic x, 0 if no variable can be attached to x. Returns the list of user variables if x is omitted."}, {"variables",0,(void*)variables_vec,3,"DG","variables({x}): all variables occuring in object x, sorted by decreasing priority. Returns the list of user variables if x is omitted."}, {"varlower",0,(void*)varlower,3,"sDn","varlower(name,{v}): return a variable 'name' whose priority is lower than the priority of v (of all existing variables if v is omitted."}, {"vecextract",0,(void*)extract0,7,"GGDG","vecextract(x,y,{z}): extraction of the components of the matrix or vector x according to y and z. If z is omitted, y represents columns, otherwise y corresponds to rows and z to columns. y and z can be vectors (of indices), strings (indicating ranges as in \"1..10\") or masks (integers whose binary representation indicates the indices to extract, from left to right 1, 2, 4, 8, etc.)."}, {"vecmax",0,(void*)vecmax0,2,"GD&","vecmax(x,{&v}): largest entry in the vector/matrix x. If v is present, set it to the index of a largest entry (indirect max)."}, {"vecmin",0,(void*)vecmin0,2,"GD&","vecmin(x,{&v}): smallest entry in the vector/matrix x. If v is present, set it to the index of a smallest entry (indirect min)."}, {"vecprod",0,(void*)vecprod,7,"G","vecprod(v): return the product of the components of the vector v."}, {"vecsearch",0,(void*)vecsearch,7,"lGGDG","vecsearch(v,x,{cmpf}): determines whether x belongs to the sorted vector v. If the comparison function cmpf is explicitly given, assume that v was sorted according to vecsort(, cmpf)."}, {"vecsort",0,(void*)vecsort0,7,"GDGD0,L,","vecsort(x,{cmpf},{flag=0}): sorts the vector of vectors (or matrix) x in ascending order, according to the comparison function cmpf, if not omitted. (If cmpf is an integer k, sort according to the value of the k-th component of each entry.) Binary digits of flag (if present) mean: 1: indirect sorting, return the permutation instead of the permuted vector, 4: use descending instead of ascending order, 8: remove duplicate entries."}, {"vecsum",0,(void*)vecsum,7,"G","vecsum(v): return the sum of the components of the vector v."}, {"vector",0,(void*)vecteur,7,"GDVDE","vector(n,{X},{expr=0}): row vector with n components of expression expr (X ranges from 1 to n). By default, fill with 0s."}, {"vectorsmall",0,(void*)vecteursmall,7,"GDVDE","vectorsmall(n,{X},{expr=0}): VECSMALL with n components of expression expr (X ranges from 1 to n) which must be small integers. By default, fill with 0s."}, {"vectorv",0,(void*)vvecteur,7,"GDVDE","vectorv(n,{X},{expr=0}): column vector with n components of expression expr (X ranges from 1 to n). By default, fill with 0s."}, {"version",0,(void*)pari_version,1,"","version(): returns the PARI version as [major,minor,patch] or [major,minor,patch,VCSversion]."}, {"warning",0,(void*)warning0,1,"vs*","warning({str}*): display warning message str."}, {"weber",0,(void*)weber0,8,"GD0,L,p","weber(x,{flag=0}): one of Weber's f function of x. flag is optional, and can be 0: default, function f(x)=exp(-i*Pi/24)*eta((x+1)/2)/eta(x), 1: function f1(x)=eta(x/2)/eta(x) 2: function f2(x)=sqrt(2)*eta(2*x)/eta(x). Note that j = (f^24-16)^3/f^24 = (f1^24+16)^3/f1^24 = (f2^24+16)^3/f2^24."}, {"while",0,(void*)whilepari,1,"vEI","while(a,seq): while a is nonzero evaluate the expression sequence seq. Otherwise 0."}, {"write",0,(void*)write0,1,"vss*","write(filename,{str}*): appends the remaining arguments (same output as print) to filename."}, {"write1",0,(void*)write1,1,"vss*","write1(filename,{str}*): appends the remaining arguments (same output as print1) to filename."}, {"writebin",0,(void*)gpwritebin,1,"vsDG","writebin(filename,{x}): write x as a binary object to file filename. If x is omitted, write all session variables."}, {"writetex",0,(void*)writetex,1,"vss*","writetex(filename,{str}*): appends the remaining arguments (same format as print) to filename, in TeX format."}, {"zeta",0,(void*)gzeta,8,"Gp","zeta(s): Riemann zeta function at s with s a complex or a p-adic number."}, {"zetahurwitz",0,(void*)zetahurwitz,8,"GGD0,L,b","zetahurwitz(s,x,{der=0}): Hurwitz zeta function at s, x, with s not 1 and x not a negative or zero integer. s can be a scalar, polynomial, rational function, or power series. If der>0, compute the der'th derivative with respect to s."}, {"zetamult",0,(void*)zetamult0,8,"GDGp","zetamult(s, {T}): multiple zeta value at integral s = [s1,...,sk]; if given, T is the output of zetamultinit."}, {"zetamultall",0,(void*)zetamultall,8,"Lp","zetamultall(n): list of all multiple zeta values for weight up to n."}, {"zetamultconvert",0,(void*)zetamultconvert,8,"GD1,L,","zetamultconvert(a,{fl=1}): a being either an evec, avec, or index m, converts into evec (fl=0), avec (fl=1), or index m (fl=2)."}, {"zetamultinit",0,(void*)zetamultinit,8,"Lp","zetamultinit(maxw): initialize data to compute multiple zeta values at integral s = [s1,...,sk] for s1 + ... + sk <= maxw."}, {"znchar",0,(void*)znchar,5,"G","znchar(D): given a datum D describing a group G = (Z/NZ)^* and a Dirichlet character chi, return the pair [G,chi]."}, {"zncharconductor",0,(void*)zncharconductor,5,"GG","zncharconductor(G,chi): let G be znstar(q,1) and chi be a Dirichlet character on (Z/qZ)*. Return the conductor of chi."}, {"znchardecompose",0,(void*)znchardecompose,5,"GGG","znchardecompose(G, chi, Q): given a znstar G = (Z/NZ)^* and a Dirichlet character chi, return the product of local characters chi_p for p | (N,Q)."}, {"znchargauss",0,(void*)znchargauss,5,"GGDGb","znchargauss(G, chi, {a=1}): given a Dirichlet character chi on G = (Z/NZ)^*, return the complex Gauss sum g(chi,a)."}, {"zncharinduce",0,(void*)zncharinduce,5,"GGG","zncharinduce(G, chi, N): let G be znstar(q,1), let chi be a Dirichlet character mod q and let N be a multiple of q. Return the character modulo N extending chi."}, {"zncharisodd",0,(void*)zncharisodd,5,"lGG","zncharisodd(G, chi): let G be znstar(N,1), let chi be a Dirichlet character mod N, return 1 if and only if chi(-1) = -1 and 0 otherwise."}, {"znchartokronecker",0,(void*)znchartokronecker,5,"GGD0,L,","znchartokronecker(G, chi, {flag=0}): let G be znstar(N,1), let chi be a Dirichlet character mod N, return the discriminant D if chi is real equal to the Kronecker symbol (D/.) and 0 otherwise. If flag is set, return the fundamental discriminant attached to the corresponding primitive character."}, {"znchartoprimitive",0,(void*)znchartoprimitive,5,"GG","znchartoprimitive(G,chi): let G be znstar(q,1) and chi be a Dirichlet character on (Z/qZ)* of conductor q0. Return [G0,chi0], where chi0 is the primitive character attached to chi and G0 is znstar(q0)."}, {"znconreychar",0,(void*)znconreychar,5,"GG","znconreychar(G,m): Dirichlet character attached to m in (Z/qZ)* in Conrey's notation, where G is znstar(q,1)."}, {"znconreyconductor",0,(void*)znconreyconductor,5,"GGD&","znconreyconductor(G,chi, {&chi0}): let G be znstar(q,1) and chi be a Dirichlet character on (Z/qZ)* given by its Conrey logarithm. Return the conductor of chi, and set chi0 to (the Conrey logarithm of) the attached primitive character. If chi0 != chi, return the conductor and its factorization."}, {"znconreyexp",0,(void*)znconreyexp,5,"GG","znconreyexp(G, chi): Conrey exponential attached to G = znstar(q, 1). Returns the element m in (Z/qZ)^* attached to the character chi on G: znconreylog(G, m) = chi."}, {"znconreylog",0,(void*)znconreylog,5,"GG","znconreylog(G,m): Conrey logarithm attached to m in (Z/qZ)*, where G is znstar(q,1)."}, {"zncoppersmith",0,(void*)zncoppersmith,5,"GGGDG","zncoppersmith(P, N, X, {B=N}): finds all integers x with |x| <= X such that gcd(N, P(x)) >= B. X should be smaller than exp((log B)^2 / (deg(P) log N))."}, {"znlog",0,(void*)znlog0,5,"GGDG","znlog(x,g,{o}): return the discrete logarithm of x in (Z/nZ)* in base g. If present, o represents the multiplicative order of g. Return [] if no solution exist."}, {"znorder",0,(void*)znorder,5,"GDG","znorder(x,{o}): order of the integermod x in (Z/nZ)*. Optional o represents a multiple of the order of the element."}, {"znprimroot",0,(void*)znprimroot,5,"G","znprimroot(n): returns a primitive root of n when it exists."}, {"znstar",0,(void*)znstar0,5,"GD0,L,","znstar(n,{flag=0}): 3-component vector v = [no,cyc,gen], giving the structure of the abelian group (Z/nZ)^*; no is the order (i.e. eulerphi(n)), cyc is a vector of cyclic components, and gen is a vector giving the corresponding generators."}, {NULL,0,NULL,0,NULL,NULL} /* sentinel */ }; pari-2.11.2/src/language/es.c0000644000175000017500000040315113457607770014327 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /** **/ /** INPUT/OUTPUT SUBROUTINES **/ /** **/ /*******************************************************************/ #ifdef _WIN32 #include "../systems/mingw/pwinver.h" #include #include /* for getpid */ #include #include /* for setmode */ #include "../systems/mingw/mingw.h" #endif #include "paricfg.h" #ifdef HAS_STAT #include #endif #ifdef HAS_OPENDIR #include #endif #include "pari.h" #include "paripriv.h" #include "anal.h" #ifdef __EMSCRIPTEN__ #include "../systems/emscripten/emscripten.h" #endif typedef void (*OUT_FUN)(GEN, pariout_t *, pari_str *); static void bruti_sign(GEN g, pariout_t *T, pari_str *S, int addsign); static void matbruti(GEN g, pariout_t *T, pari_str *S); static void texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign); static void bruti(GEN g, pariout_t *T, pari_str *S) { bruti_sign(g,T,S,1); } static void texi(GEN g, pariout_t *T, pari_str *S) { texi_sign(g,T,S,1); } void pari_ask_confirm(const char *s) { if (!cb_pari_ask_confirm) pari_err(e_MISC,"Can't ask for confirmation. Please define cb_pari_ask_confirm()"); cb_pari_ask_confirm(s); } static char * strip_last_nl(char *s) { ulong l = strlen(s); char *t; if (l && s[l-1] != '\n') return s; if (l>1 && s[l-2] == '\r') l--; t = stack_malloc(l); memcpy(t, s, l-1); t[l-1] = 0; return t; } /********************************************************************/ /** **/ /** INPUT FILTER **/ /** **/ /********************************************************************/ #define ONE_LINE_COMMENT 2 #define MULTI_LINE_COMMENT 1 #define LBRACE '{' #define RBRACE '}' static int in_help(filtre_t *F) { char c; if (!F->buf) return (*F->s == '?'); c = *F->buf->buf; return c? (c == '?'): (*F->s == '?'); } /* Filter F->s into F->t */ static char * filtre0(filtre_t *F) { const char *s = F->s; char *t; char c; if (!F->t) F->t = (char*)pari_malloc(strlen(s)+1); t = F->t; if (F->more_input == 1) F->more_input = 0; while ((c = *s++)) { if (F->in_string) { *t++ = c; /* copy verbatim */ switch(c) { case '\\': /* in strings, \ is the escape character */ if (*s) *t++ = *s++; break; case '"': F->in_string = 0; } continue; } if (F->in_comment) { /* look for comment's end */ if (F->in_comment == MULTI_LINE_COMMENT) { while (c != '*' || *s != '/') { if (!*s) { if (!F->more_input) F->more_input = 1; goto END; } c = *s++; } s++; } else while (c != '\n' && *s) c = *s++; F->in_comment = 0; continue; } /* weed out comments and spaces */ if (c=='\\' && *s=='\\') { F->in_comment = ONE_LINE_COMMENT; continue; } if (isspace((int)c)) continue; *t++ = c; switch(c) { case '/': if (*s == '*') { t--; F->in_comment = MULTI_LINE_COMMENT; } break; case '\\': if (!*s) { if (in_help(F)) break; /* '?...\' */ t--; if (!F->more_input) F->more_input = 1; goto END; } if (*s == '\r') s++; /* DOS */ if (*s == '\n') { if (in_help(F)) break; /* '?...\' */ t--; s++; if (!*s) { if (!F->more_input) F->more_input = 1; goto END; } } /* skip \ */ break; case '"': F->in_string = 1; break; case LBRACE: t--; if (F->wait_for_brace) pari_err_IMPL("embedded braces (in parser)"); F->more_input = 2; F->wait_for_brace = 1; break; case RBRACE: if (!F->wait_for_brace) pari_err(e_MISC,"unexpected closing brace"); F->more_input = 0; t--; F->wait_for_brace = 0; break; } } if (t != F->t) /* non empty input */ { c = t[-1]; /* last char */ if (c == '=') { if (!in_help(F)) F->more_input = 2; } else if (! F->wait_for_brace) F->more_input = 0; else if (c == RBRACE) { F->more_input = 0; t--; F->wait_for_brace--;} } END: F->end = t; *t = 0; return F->t; } #undef ONE_LINE_COMMENT #undef MULTI_LINE_COMMENT char * gp_filter(const char *s) { filtre_t T; T.buf = NULL; T.s = s; T.in_string = 0; T.more_input = 0; T.t = NULL; T.in_comment= 0; T.wait_for_brace = 0; return filtre0(&T); } void init_filtre(filtre_t *F, Buffer *buf) { F->buf = buf; F->in_string = 0; F->in_comment = 0; } /********************************************************************/ /** **/ /** INPUT METHODS **/ /** **/ /********************************************************************/ /* create */ Buffer * new_buffer(void) { Buffer *b = (Buffer*) pari_malloc(sizeof(Buffer)); b->len = 1024; b->buf = (char*)pari_malloc(b->len); return b; } /* delete */ void delete_buffer(Buffer *b) { if (!b) return; pari_free((void*)b->buf); pari_free((void*)b); } /* resize */ void fix_buffer(Buffer *b, long newlbuf) { b->len = newlbuf; b->buf = (char*)pari_realloc((void*)b->buf, b->len); } static int gp_read_stream_buf(FILE *fi, Buffer *b) { input_method IM; filtre_t F; init_filtre(&F, b); IM.file = (void*)fi; IM.fgets = (fgets_t)&fgets; IM.getline = &file_input; IM.free = 0; return input_loop(&F,&IM); } GEN gp_read_stream(FILE *fi) { Buffer *b = new_buffer(); GEN x = gp_read_stream_buf(fi, b)? readseq(b->buf): gnil; delete_buffer(b); return x; } static GEN gp_read_from_input(input_method* IM, int loop, char *last) { Buffer *b = new_buffer(); GEN x = gnil; filtre_t F; if (last) *last = 0; do { char *s; init_filtre(&F, b); if (!input_loop(&F, IM)) break; s = b->buf; if (s[0]) { x = readseq(s); if (last) *last = s[strlen(s) - 1]; } } while (loop); delete_buffer(b); return x; } GEN gp_read_file(const char *s) { GEN x = gnil; FILE *f = switchin(s); if (file_is_binary(f)) { x = readbin(s,f, NULL); if (!x) pari_err_FILE("input file",s); } else { pari_sp av = avma; Buffer *b = new_buffer(); x = gnil; for (;;) { if (!gp_read_stream_buf(f, b)) break; if (*(b->buf)) { avma = av; x = readseq(b->buf); } } delete_buffer(b); } popinfile(); return x; } static char* string_gets(char *s, int size, const char **ptr) { /* f is actually a const char** */ const char *in = *ptr; int i; char c; /* Copy from in to s */ for (i = 0; i+1 < size && in[i] != 0;) { s[i] = c = in[i]; i++; if (c == '\n') break; } s[i] = 0; /* Terminating 0 byte */ if (i == 0) return NULL; *ptr += i; return s; } GEN gp_read_str_multiline(const char *s, char *last) { input_method IM; const char *ptr = s; IM.file = (void*)(&ptr); IM.fgets = (fgets_t)&string_gets; IM.getline = &file_input; IM.free = 0; return gp_read_from_input(&IM, 1, last); } void gp_embedded_init(long rsize, long vsize) { pari_init(rsize, 500000); paristack_setsize(rsize, vsize); } char * gp_embedded(const char *s) { char last, *res; struct gp_context state; VOLATILE long t = 0; gp_context_save(&state); timer_start(GP_DATA->T); pari_set_last_newline(1); pari_CATCH(CATCH_ALL) { GENbin* err = copy_bin(pari_err_last()); gp_context_restore(&state); res = pari_err2str(bin_copy(err)); } pari_TRY { GEN z = gp_read_str_multiline(s, &last); ulong n; t = timer_delay(GP_DATA->T); if (GP_DATA->simplify) z = simplify_shallow(z); pari_add_hist(z, t); n = pari_nb_hist(); parivstack_reset(); res = (z==gnil || last==';') ? stack_strdup("\n"): stack_sprintf("%%%lu = %Ps\n", n, pari_get_hist(n)); if (t && GP_DATA->chrono) res = stack_sprintf("%stime = %s", res, gp_format_time(t)); } pari_ENDCATCH; if (!pari_last_was_newline()) pari_putc('\n'); avma = pari_mainstack->top; return res; } GEN gp_readvec_stream(FILE *fi) { pari_sp ltop = avma; Buffer *b = new_buffer(); long i = 1, n = 16; GEN z = cgetg(n+1,t_VEC); for(;;) { if (!gp_read_stream_buf(fi, b)) break; if (!*(b->buf)) continue; if (i>n) { if (DEBUGLEVEL) err_printf("gp_readvec_stream: reaching %ld entries\n",n); n <<= 1; z = vec_lengthen(z,n); } gel(z,i++) = readseq(b->buf); } if (DEBUGLEVEL) err_printf("gp_readvec_stream: found %ld entries\n",i-1); setlg(z,i); delete_buffer(b); return gerepilecopy(ltop,z); } GEN gp_readvec_file(char *s) { GEN x = NULL; FILE *f = switchin(s); if (file_is_binary(f)) { int junk; x = readbin(s,f,&junk); if (!x) pari_err_FILE("input file",s); } else x = gp_readvec_stream(f); popinfile(); return x; } char * file_getline(Buffer *b, char **s0, input_method *IM) { const ulong MAX = (1UL << 31) - 1; ulong used0, used; **s0 = 0; /* paranoia */ used0 = used = *s0 - b->buf; for(;;) { ulong left = b->len - used, l, read; char *s; /* If little space left, double the buffer size before next read. */ if (left < 512) { fix_buffer(b, b->len << 1); left = b->len - used; *s0 = b->buf + used0; } /* # of chars read by fgets is an int; be careful */ read = minuu(left, MAX); s = b->buf + used; if (! IM->fgets(s, (int)read, IM->file)) return **s0? *s0: NULL; /* EOF */ l = strlen(s); if (l+1 < read || s[l-1] == '\n') return *s0; /* \n */ used += l; } } /* Read from file (up to '\n' or EOF) and copy at s0 (points in b->buf) */ char * file_input(char **s0, int junk, input_method *IM, filtre_t *F) { (void)junk; return file_getline(F->buf, s0, IM); } /* Read a "complete line" and filter it. Return: 0 if EOF, 1 otherwise */ int input_loop(filtre_t *F, input_method *IM) { Buffer *b = (Buffer*)F->buf; char *to_read, *s = b->buf; /* read first line */ if (! (to_read = IM->getline(&s,1, IM, F)) ) { if (F->in_string) { pari_warn(warner,"run-away string. Closing it"); F->in_string = 0; } if (F->in_comment) { pari_warn(warner,"run-away comment. Closing it"); F->in_comment = 0; } return 0; } /* buffer is not empty, init filter */ F->in_string = 0; F->more_input= 0; F->wait_for_brace = 0; for(;;) { if (GP_DATA->echo == 2) gp_echo_and_log("", strip_last_nl(to_read)); F->s = to_read; F->t = s; (void)filtre0(F); /* pre-processing of line, read by previous call to IM->getline */ if (IM->free) pari_free(to_read); if (! F->more_input) break; /* read continuation line */ s = F->end; to_read = IM->getline(&s,0, IM, F); if (!to_read) break; } return 1; } /********************************************************************/ /** **/ /** GENERAL PURPOSE PRINTING **/ /** **/ /********************************************************************/ PariOUT *pariOut, *pariErr; static void _fputs(const char *s, FILE *f ) { #ifdef _WIN32 win32_ansi_fputs(s, f); #else fputs(s, f); #endif } static void _putc_log(char c) { if (pari_logfile) (void)putc(c, pari_logfile); } static void _puts_log(const char *s) { FILE *f = pari_logfile; const char *p; if (!f) return; if (logstyle != logstyle_color) while ( (p = strchr(s, '\x1b')) ) { /* skip ANSI color escape sequence */ if ( p!=s ) fwrite(s, 1, p-s, f); s = strchr(p, 'm'); if (!s) return; s++; } fputs(s, f); } static void _flush_log(void) { if (pari_logfile != NULL) (void)fflush(pari_logfile); } static void normalOutC(char c) { putc(c, pari_outfile); _putc_log(c); } static void normalOutS(const char *s) { _fputs(s, pari_outfile); _puts_log(s); } static void normalOutF(void) { fflush(pari_outfile); _flush_log(); } static PariOUT defaultOut = {normalOutC, normalOutS, normalOutF}; static void normalErrC(char c) { putc(c, pari_errfile); _putc_log(c); } static void normalErrS(const char *s) { _fputs(s, pari_errfile); _puts_log(s); } static void normalErrF(void) { fflush(pari_errfile); _flush_log(); } static PariOUT defaultErr = {normalErrC, normalErrS, normalErrF}; /** GENERIC PRINTING **/ void resetout(int initerr) { pariOut = &defaultOut; if (initerr) pariErr = &defaultErr; } void initout(int initerr) { pari_infile = stdin; pari_outfile = stdout; pari_errfile = stderr; resetout(initerr); } static int last_was_newline = 1; static void set_last_newline(char c) { last_was_newline = (c == '\n'); } void out_putc(PariOUT *out, char c) { set_last_newline(c); out->putch(c); } void pari_putc(char c) { out_putc(pariOut, c); } void out_puts(PariOUT *out, const char *s) { if (*s) { set_last_newline(s[strlen(s)-1]); out->puts(s); } } void pari_puts(const char *s) { out_puts(pariOut, s); } int pari_last_was_newline(void) { return last_was_newline; } void pari_set_last_newline(int last) { last_was_newline = last; } void pari_flush(void) { pariOut->flush(); } void err_flush(void) { pariErr->flush(); } static GEN log10_2(void) { return divrr(mplog2(LOWDEFAULTPREC), mplog(utor(10,LOWDEFAULTPREC))); } /* e binary exponent, return exponent in base ten */ static long ex10(long e) { pari_sp av; GEN z; if (e >= 0) { if (e < 1e15) return (long)(e*LOG10_2); av = avma; z = mulur(e, log10_2()); z = floorr(z); e = itos(z); } else /* e < 0 */ { if (e > -1e15) return (long)(-(-e*LOG10_2)-1); av = avma; z = mulsr(e, log10_2()); z = floorr(z); e = itos(z) - 1; } avma = av; return e; } static char * zeros(char *b, long nb) { while (nb-- > 0) *b++ = '0'; *b = 0; return b; } /* # of decimal digits, assume l > 0 */ static long numdig(ulong l) { if (l < 100000) { if (l < 100) return (l < 10)? 1: 2; if (l < 10000) return (l < 1000)? 3: 4; return 5; } if (l < 10000000) return (l < 1000000)? 6: 7; if (l < 1000000000) return (l < 100000000)? 8: 9; return 10; } /* let ndig <= 9, x < 10^ndig, write in p[-ndig..-1] the decimal digits of x */ static void utodec(char *p, ulong x, long ndig) { switch(ndig) { case 9: *--p = x % 10 + '0'; x = x/10; case 8: *--p = x % 10 + '0'; x = x/10; case 7: *--p = x % 10 + '0'; x = x/10; case 6: *--p = x % 10 + '0'; x = x/10; case 5: *--p = x % 10 + '0'; x = x/10; case 4: *--p = x % 10 + '0'; x = x/10; case 3: *--p = x % 10 + '0'; x = x/10; case 2: *--p = x % 10 + '0'; x = x/10; case 1: *--p = x % 10 + '0'; x = x/10; } } /* convert abs(x) != 0 to str. Prepend '-' if (sx < 0) */ static char * itostr_sign(GEN x, int sx, long *len) { long l, d; ulong *res = convi(x, &l); /* l 9-digits words (< 10^9) + (optional) sign + \0 */ char *s = (char*)new_chunk(nchar2nlong(l*9 + 1 + 1)), *t = s; if (sx < 0) *t++ = '-'; d = numdig(*--res); t += d; utodec(t, *res, d); while (--l > 0) { t += 9; utodec(t, *--res, 9); } *t = 0; *len = t - s; return s; } /********************************************************************/ /** **/ /** WRITE A REAL NUMBER **/ /** **/ /********************************************************************/ /* 19 digits (if 64 bits, at most 2^60-1) + 1 sign */ static const long MAX_EXPO_LEN = 20; /* write z to buf, inserting '.' at 'point', 0 < point < strlen(z) */ static void wr_dec(char *buf, char *z, long point) { char *s = buf + point; strncpy(buf, z, point); /* integer part */ *s++ = '.'; z += point; while ( (*s++ = *z++) ) /* empty */; } static char * zerotostr(void) { char *s = (char*)new_chunk(1); s[0] = '0'; s[1] = 0; return s; } /* write a real 0 of exponent ex in format f */ static char * real0tostr_width_frac(long width_frac) { char *buf, *s; if (width_frac == 0) return zerotostr(); buf = s = stack_malloc(width_frac + 3); *s++ = '0'; *s++ = '.'; (void)zeros(s, width_frac); return buf; } /* write a real 0 of exponent ex */ static char * real0tostr(long ex, char format, char exp_char, long wanted_dec) { char *buf, *buf0; if (format == 'f') { long width_frac = wanted_dec; if (width_frac < 0) width_frac = (ex >= 0)? 0: (long)(-ex * LOG10_2); return real0tostr_width_frac(width_frac); } else { buf0 = buf = stack_malloc(3 + MAX_EXPO_LEN + 1); *buf++ = '0'; *buf++ = '.'; *buf++ = exp_char; sprintf(buf, "%ld", ex10(ex) + 1); } return buf0; } /* format f, width_frac >= 0: number of digits in fractional part, */ static char * absrtostr_width_frac(GEN x, int width_frac) { long beta, ls, point, lx, sx = signe(x); char *s, *buf; GEN z; if (!sx) return real0tostr_width_frac(width_frac); /* x != 0 */ lx = realprec(x); beta = width_frac; if (beta) /* >= 0 */ { /* z = |x| 10^beta, 10^b = 5^b * 2^b, 2^b goes into exponent */ if (beta > 4e9) lx++; z = mulrr(x, rpowuu(5UL, (ulong)beta, lx+1)); setsigne(z, 1); shiftr_inplace(z, beta); } else z = mpabs(x); z = roundr_safe(z); if (!signe(z)) return real0tostr_width_frac(width_frac); s = itostr_sign(z, 1, &ls); /* ls > 0, number of digits in s */ point = ls - beta; /* position of . in s; <= ls, may be < 0 */ if (point > 0) /* write integer_part.fractional_part */ { /* '.', trailing \0 */ buf = stack_malloc( ls + 1+1 ); if (ls == point) strcpy(buf, s); /* no '.' */ else wr_dec(buf, s, point); } else { /* point <= 0, fractional part must be written */ char *t; /* '0', '.', zeroes, trailing \0 */ buf = t = stack_malloc( 1 + 1 - point + ls + 1 ); *t++ = '0'; *t++ = '.'; t = zeros(t, -point); strcpy(t, s); } return buf; } /* Return t_REAL |x| in floating point format. * Allocate freely, the caller must clean the stack. * FORMAT: E/e (exponential), F/f (floating point), G/g * wanted_dec: number of significant digits to print (all if < 0). */ static char * absrtostr(GEN x, int sp, char FORMAT, long wanted_dec) { const char format = (char)tolower((int)FORMAT), exp_char = (format == FORMAT)? 'e': 'E'; long beta, ls, point, lx, sx = signe(x), ex = expo(x); char *s, *buf, *buf0; GEN z; if (!sx) return real0tostr(ex, format, exp_char, wanted_dec); /* x != 0 */ lx = realprec(x); if (wanted_dec >= 0) { /* reduce precision if possible */ long w = ndec2prec(wanted_dec); /* digits -> pari precision in words */ if (lx > w) lx = w; /* truncature with guard, no rounding */ } beta = ex10(prec2nbits(lx) - ex); if (beta) { /* z = |x| 10^beta, 10^b = 5^b * 2^b, 2^b goes into exponent */ if (beta > 0) { if (beta > 18) { lx++; x = rtor(x, lx); } z = mulrr(x, rpowuu(5UL, (ulong)beta, lx+1)); } else { if (beta < -18) { lx++; x = rtor(x, lx); } z = divrr(x, rpowuu(5UL, (ulong)-beta, lx+1)); } setsigne(z, 1); shiftr_inplace(z, beta); } else z = x; z = roundr_safe(z); if (!signe(z)) return real0tostr(ex, format, exp_char, wanted_dec); s = itostr_sign(z, 1, &ls); /* ls > 0, number of digits in s */ if (wanted_dec < 0) wanted_dec = ls; else if (ls > wanted_dec) { beta -= ls - wanted_dec; ls = wanted_dec; if (s[ls] >= '5') /* round up */ { long i; for (i = ls-1; i >= 0; s[i--] = '0') if (++s[i] <= '9') break; if (i < 0) { s[0] = '1'; beta--; } } s[ls] = 0; } /* '.', " E", exponent, trailing \0 */ point = ls - beta; /* position of . in s; < 0 or > 0 */ if (beta <= 0 || format == 'e' || (format == 'g' && point-1 < -4)) { /* e format */ buf0 = buf = stack_malloc(ls+1+2+MAX_EXPO_LEN + 1); wr_dec(buf, s, 1); buf += ls + 1; if (sp) *buf++ = ' '; *buf++ = exp_char; sprintf(buf, "%ld", point-1); } else if (point > 0) /* f format, write integer_part.fractional_part */ { buf0 = buf = stack_malloc(ls+1 + 1); wr_dec(buf, s, point); /* point < ls since beta > 0 */ } else /* f format, point <= 0, write fractional part */ { buf0 = buf = stack_malloc(2-point+ls + 1); *buf++ = '0'; *buf++ = '.'; buf = zeros(buf, -point); strcpy(buf, s); } return buf0; } /* vsnprintf implementation rewritten from snprintf.c to be found at * * http://www.nersc.gov/~scottc/misc/docs/snort-2.1.1-RC1/snprintf_8c-source.html * The original code was * Copyright (C) 1998-2002 Martin Roesch * available under the terms of the GNU GPL version 2 or later. It * was itself adapted from an original version by Patrick Powell. */ /* Modifications for format %Ps: R.Butel IMB/CNRS 2007/12/03 */ /* l = old len, L = new len */ static void str_alloc0(pari_str *S, long l, long L) { char *s; if (S->use_stack) { s = stack_malloc(L); memcpy(s, S->string, l); } else s = (char*)pari_realloc((void*)S->string, L); S->string = s; S->cur = s + l; S->end = s + L; S->size = L; } /* make sure S is large enough to write l further words (<= l * 20 chars). * To avoid automatic extension in between av = avma / avma = av pairs * [ would destroy S->string if (S->use_stack) ] */ static void str_alloc(pari_str *S, long l) { l *= 20; if (S->end - S->cur <= l) str_alloc0(S, S->cur - S->string, S->size + maxss(S->size, l)); } void str_putc(pari_str *S, char c) { *S->cur++ = c; if (S->cur == S->end) str_alloc0(S, S->size, S->size << 1); } void str_init(pari_str *S, int use_stack) { char *s; S->size = 1024; S->use_stack = use_stack; if (S->use_stack) s = (char*)stack_malloc(S->size); else s = (char*)pari_malloc(S->size); *s = 0; S->string = S->cur = s; S->end = S->string + S->size; } void str_puts(pari_str *S, const char *s) { while (*s) str_putc(S, *s++); } static void str_putscut(pari_str *S, const char *s, int cut) { if (cut < 0) str_puts(S, s); else { while (*s && cut-- > 0) str_putc(S, *s++); } } /* lbuf = strlen(buf), len < 0: unset */ static void outpad(pari_str *S, const char *buf, long lbuf, int sign, long ljust, long len, long zpad) { long padlen = len - lbuf; if (padlen < 0) padlen = 0; if (ljust) padlen = -padlen; if (padlen > 0) { if (zpad) { if (sign) { str_putc(S, sign); --padlen; } while (padlen > 0) { str_putc(S, '0'); --padlen; } } else { if (sign) --padlen; while (padlen > 0) { str_putc(S, ' '); --padlen; } if (sign) str_putc(S, sign); } } else if (sign) str_putc(S, sign); str_puts(S, buf); while (padlen < 0) { str_putc(S, ' '); ++padlen; } } /* len < 0 or maxwidth < 0: unset */ static void fmtstr(pari_str *S, const char *buf, int ljust, int len, int maxwidth) { int padlen, lbuf = strlen(buf); if (maxwidth >= 0 && lbuf > maxwidth) lbuf = maxwidth; padlen = len - lbuf; if (padlen < 0) padlen = 0; if (ljust) padlen = -padlen; while (padlen > 0) { str_putc(S, ' '); --padlen; } str_putscut(S, buf, maxwidth); while (padlen < 0) { str_putc(S, ' '); ++padlen; } } /* abs(base) is 8, 10, 16. If base < 0, some "alternate" form * -- print hex in uppercase * -- prefix octal with 0 * signvalue = -1: unsigned, otherwise ' ' or '+'. Leaves a messy stack if * S->use_stack */ static void fmtnum(pari_str *S, long lvalue, GEN gvalue, int base, int signvalue, int ljust, int len, int zpad) { int caps; char *buf0, *buf; long lbuf, mxl; GEN uvalue = NULL; ulong ulvalue = 0; pari_sp av = avma; if (gvalue) { long s, l; if (typ(gvalue) != t_INT) { long i, j, h; l = lg(gvalue); switch(typ(gvalue)) { case t_VEC: str_putc(S, '['); for (i = 1; i < l; i++) { fmtnum(S, 0, gel(gvalue,i), base, signvalue, ljust,len,zpad); if (i < l-1) str_putc(S, ','); } str_putc(S, ']'); return; case t_COL: str_putc(S, '['); for (i = 1; i < l; i++) { fmtnum(S, 0, gel(gvalue,i), base, signvalue, ljust,len,zpad); if (i < l-1) str_putc(S, ','); } str_putc(S, ']'); str_putc(S, '~'); return; case t_MAT: if (l == 1) str_puts(S, "[;]"); else { h = lgcols(gvalue); for (i=1; i 0) caps = 0; else { caps = 1; base = -base; } buf0 = buf = stack_malloc(mxl) + mxl; /* fill from the right */ *--buf = 0; /* trailing \0 */ if (gvalue) { if (base == 10) { long i, l, cnt; ulong *larray = convi(uvalue, &l); larray -= l; for (i = 0; i < l; i++) { cnt = 0; ulvalue = larray[i]; do { *--buf = '0' + ulvalue%10; ulvalue = ulvalue / 10; cnt++; } while (ulvalue); if (i + 1 < l) for (;cnt<9;cnt++) *--buf = '0'; } } else if (base == 16) { long i, l = lgefint(uvalue); GEN up = int_LSW(uvalue); for (i = 2; i < l; i++, up = int_nextW(up)) { ulong ucp = (ulong)*up; long j; for (j=0; j < BITS_IN_LONG/4; j++) { unsigned char cv = ucp & 0xF; *--buf = (caps? "0123456789ABCDEF":"0123456789abcdef")[cv]; ucp >>= 4; if (ucp == 0 && i+1 == l) break; } } /* loop on hex digits in word */ } else if (base == 8) { long i, l = lgefint(uvalue); GEN up = int_LSW(uvalue); ulong rem = 0; int shift = 0; int mask[3] = {0, 1, 3}; for (i = 2; i < l; i++, up = int_nextW(up)) { ulong ucp = (ulong)*up; long j, ldispo = BITS_IN_LONG; if (shift) { /* 0, 1 or 2 */ unsigned char cv = ((ucp & mask[shift]) <<(3-shift)) + rem; *--buf = "01234567"[cv]; ucp >>= shift; ldispo -= shift; }; shift = (shift + 3 - BITS_IN_LONG % 3) % 3; for (j=0; j < BITS_IN_LONG/3; j++) { unsigned char cv = ucp & 0x7; if (ucp == 0 && i+1 == l) { rem = 0; break; }; *--buf = "01234567"[cv]; ucp >>= 3; ldispo -= 3; rem = ucp; if (ldispo < 3) break; } } /* loop on hex digits in word */ if (rem) *--buf = "01234567"[rem]; } } else { /* not a gvalue, thus a standard integer */ do { *--buf = (caps? "0123456789ABCDEF":"0123456789abcdef")[ulvalue % (unsigned)base ]; ulvalue /= (unsigned)base; } while (ulvalue); } /* leading 0 if octal and alternate # form */ if (caps && base == 8) *--buf = '0'; lbuf = (buf0 - buf) - 1; END: outpad(S, buf, lbuf, signvalue, ljust, len, zpad); if (!S->use_stack) avma = av; } static GEN v_get_arg(GEN arg_vector, int *index, const char *save_fmt) { if (*index >= lg(arg_vector)) pari_err(e_MISC, "missing arg %d for printf format '%s'", *index, save_fmt); return gel(arg_vector, (*index)++); } static int dosign(int blank, int plus) { if (plus) return('+'); if (blank) return(' '); return 0; } /* x * 10 + 'digit whose char value is ch'. Do not check for overflow */ static int shift_add(int x, int ch) { if (x < 0) /* was unset */ x = ch - '0'; else x = x*10 + ch - '0'; return x; } static long get_sigd(GEN gvalue, char ch, int maxwidth) { long sigd, e; if (maxwidth < 0) return nbits2ndec(precreal); switch(ch) { case 'E': case 'e': sigd = maxwidth+1; break; case 'F': case 'f': e = gexpo(gvalue); if (e == -(long)HIGHEXPOBIT) /* exact 0 */ sigd = 0; else sigd = ex10(e) + 1 + maxwidth; break; /* 'g', 'G' */ default : sigd = maxwidth? maxwidth: 1; break; } return sigd; } static void fmtreal(pari_str *S, GEN gvalue, int space, int signvalue, int FORMAT, int maxwidth, int ljust, int len, int zpad) { pari_sp av = avma; long sigd; char *buf; if (typ(gvalue) == t_REAL) sigd = get_sigd(gvalue, FORMAT, maxwidth); else { long i, j, h, l = lg(gvalue); switch(typ(gvalue)) { case t_VEC: str_putc(S, '['); for (i = 1; i < l; i++) { fmtreal(S, gel(gvalue,i), space, signvalue, FORMAT, maxwidth, ljust,len,zpad); if (i < l-1) str_putc(S, ','); } str_putc(S, ']'); return; case t_COL: str_putc(S, '['); for (i = 1; i < l; i++) { fmtreal(S, gel(gvalue,i), space, signvalue, FORMAT, maxwidth, ljust,len,zpad); if (i < l-1) str_putc(S, ','); } str_putc(S, ']'); str_putc(S, '~'); return; case t_MAT: if (l == 1) str_puts(S, "[;]"); else { h = lgcols(gvalue); for (i=1; i= 0) buf = absrtostr_width_frac(gvalue, maxwidth); else buf = absrtostr(gvalue, space, FORMAT, sigd); if (signe(gvalue) < 0) signvalue = '-'; outpad(S, buf, strlen(buf), signvalue, ljust, len, zpad); if (!S->use_stack) avma = av; } /* Format handling "inspired" by the standard draft at -- http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf pages 274ff * fmt is a standard printf format, except 'P' is a "length modifier" * allowing GEN arguments. Use either the arg_vector or (if NULL) the va_list. * Appent output to the pari_str S, which must be initialized; clean if * !S->use_stack, else leaves objects of stack. */ static void str_arg_vprintf(pari_str *S, const char *fmt, GEN arg_vector, va_list args) { int GENflag = 0, longflag = 0, pointflag = 0; int print_plus, print_blank, with_sharp, ch, ljust, len, maxwidth, zpad; long lvalue; int index = 1; GEN gvalue; const char *save_fmt = fmt; while ((ch = *fmt++) != '\0') { switch(ch) { case '%': ljust = zpad = 0; len = maxwidth = -1; GENflag = longflag = pointflag = 0; print_plus = print_blank = with_sharp = 0; nextch: ch = *fmt++; switch(ch) { case 0: pari_err(e_MISC, "printf: end of format"); /*------------------------------------------------------------------------ -- flags ------------------------------------------------------------------------*/ case '-': ljust = 1; goto nextch; case '+': print_plus = 1; goto nextch; case '#': with_sharp = 1; goto nextch; case ' ': print_blank = 1; goto nextch; case '0': /* appears as a flag: set zero padding */ if (len < 0 && !pointflag) { zpad = '0'; goto nextch; } /* else part of a field width or precision */ /* fall through */ /*------------------------------------------------------------------------ -- maxwidth or precision ------------------------------------------------------------------------*/ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (pointflag) maxwidth = shift_add(maxwidth, ch); else len = shift_add(len, ch); goto nextch; case '*': { int *t = pointflag? &maxwidth: &len; if (arg_vector) *t = (int)gtolong( v_get_arg(arg_vector, &index, save_fmt) ); else *t = va_arg(args, int); goto nextch; } case '.': if (pointflag) pari_err(e_MISC, "two '.' in conversion specification"); pointflag = 1; goto nextch; /*------------------------------------------------------------------------ -- length modifiers ------------------------------------------------------------------------*/ case 'l': if (GENflag) pari_err(e_MISC, "P/l length modifiers in the same conversion"); #if !defined(_WIN64) if (longflag) pari_err_IMPL( "ll length modifier in printf"); #endif longflag = 1; goto nextch; case 'P': if (longflag) pari_err(e_MISC, "P/l length modifiers in the same conversion"); if (GENflag) pari_err(e_MISC, "'P' length modifier appears twice"); GENflag = 1; goto nextch; case 'h': /* dummy: va_arg promotes short into int */ goto nextch; /*------------------------------------------------------------------------ -- conversions ------------------------------------------------------------------------*/ case 'u': /* not a signed conversion: print_(blank|plus) ignored */ #define get_num_arg() \ if (arg_vector) { \ lvalue = 0; \ gvalue = v_get_arg(arg_vector, &index, save_fmt); \ } else { \ if (GENflag) { \ lvalue = 0; \ gvalue = va_arg(args, GEN); \ } else { \ lvalue = longflag? va_arg(args, long): va_arg(args, int); \ gvalue = NULL; \ } \ } get_num_arg(); fmtnum(S, lvalue, gvalue, 10, -1, ljust, len, zpad); break; case 'o': /* not a signed conversion: print_(blank|plus) ignored */ get_num_arg(); fmtnum(S, lvalue, gvalue, with_sharp? -8: 8, -1, ljust, len, zpad); break; case 'd': case 'i': get_num_arg(); fmtnum(S, lvalue, gvalue, 10, dosign(print_blank, print_plus), ljust, len, zpad); break; case 'p': str_putc(S, '0'); str_putc(S, 'x'); if (arg_vector) lvalue = (long)v_get_arg(arg_vector, &index, save_fmt); else lvalue = (long)va_arg(args, void*); fmtnum(S, lvalue, NULL, 16, -1, ljust, len, zpad); break; case 'x': /* not a signed conversion: print_(blank|plus) ignored */ if (with_sharp) { str_putc(S, '0'); str_putc(S, 'x'); } get_num_arg(); fmtnum(S, lvalue, gvalue, 16, -1, ljust, len, zpad); break; case 'X': /* not a signed conversion: print_(blank|plus) ignored */ if (with_sharp) { str_putc(S, '0'); str_putc(S, 'X'); } get_num_arg(); fmtnum(S, lvalue, gvalue,-16, -1, ljust, len, zpad); break; case 's': { char *strvalue; pari_sp av = avma; if (arg_vector) { gvalue = v_get_arg(arg_vector, &index, save_fmt); strvalue = NULL; } else { if (GENflag) { gvalue = va_arg(args, GEN); strvalue = NULL; } else { gvalue = NULL; strvalue = va_arg(args, char *); } } if (gvalue) strvalue = GENtostr_unquoted(gvalue); fmtstr(S, strvalue, ljust, len, maxwidth); if (!S->use_stack) avma = av; break; } case 'c': if (arg_vector) { gvalue = v_get_arg(arg_vector, &index, save_fmt); ch = (int)gtolong(gvalue); } else { if (GENflag) ch = (int)gtolong( va_arg(args,GEN) ); else ch = va_arg(args, int); } str_putc(S, ch); break; case '%': str_putc(S, ch); continue; case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': { pari_sp av = avma; if (arg_vector) gvalue = simplify_shallow( v_get_arg(arg_vector, &index, save_fmt) ); else { if (GENflag) gvalue = simplify_shallow( va_arg(args, GEN) ); else gvalue = dbltor( va_arg(args, double) ); } fmtreal(S, gvalue, GP_DATA->fmt->sp, dosign(print_blank,print_plus), ch, maxwidth, ljust, len, zpad); if (!S->use_stack) avma = av; break; } default: pari_err(e_MISC, "invalid conversion or specification %c in format `%s'", ch, save_fmt); } /* second switch on ch */ break; default: str_putc(S, ch); break; } /* first switch on ch */ } /* while loop on ch */ *S->cur = 0; } void decode_color(long n, long *c) { c[1] = n & 0xf; n >>= 4; /* foreground */ c[2] = n & 0xf; n >>= 4; /* background */ c[0] = n & 0xf; /* attribute */ } #define COLOR_LEN 16 /* start printing in "color" c */ /* terminal has to support ANSI color escape sequences */ void out_term_color(PariOUT *out, long c) { static char s[COLOR_LEN]; out->puts(term_get_color(s, c)); } void term_color(long c) { out_term_color(pariOut, c); } /* s must be able to store 12 chars (including final \0) */ char * term_get_color(char *s, long n) { long c[3], a; if (!s) s = stack_malloc(COLOR_LEN); if (disable_color) { *s = 0; return s; } if (n == c_NONE || (a = gp_colors[n]) == c_NONE) strcpy(s, "\x1b[0m"); /* reset */ else { decode_color(a,c); if (c[1]<8) c[1] += 30; else c[1] += 82; if (a & (1L<<12)) /* transparent background */ sprintf(s, "\x1b[%ld;%ldm", c[0], c[1]); else { if (c[2]<8) c[2] += 40; else c[2] += 92; sprintf(s, "\x1b[%ld;%ld;%ldm", c[0], c[1], c[2]); } } return s; } static long strlen_real(const char *s) { const char *t = s; long len = 0; while (*t) { if (t[0] == '\x1b' && t[1] == '[') { /* skip ANSI escape sequence */ t += 2; while (*t && *t++ != 'm') /* empty */; continue; } t++; len++; } return len; } #undef COLOR_LEN /********************************************************************/ /** **/ /** PRINTING BASED ON SCREEN WIDTH **/ /** **/ /********************************************************************/ #undef larg /* problems with SCO Unix headers (ioctl_arg) */ #ifdef HAS_TIOCGWINSZ # ifdef __sun # include # endif # include #endif static int term_width_intern(void) { #ifdef _WIN32 return win32_terminal_width(); #endif #ifdef HAS_TIOCGWINSZ { struct winsize s; if (!(GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS)) && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_col; } #endif { char *str; if ((str = os_getenv("COLUMNS"))) return atoi(str); } #ifdef __EMX__ { int scrsize[2]; _scrsize(scrsize); return scrsize[0]; } #endif return 0; } static int term_height_intern(void) { #ifdef _WIN32 return win32_terminal_height(); #endif #ifdef HAS_TIOCGWINSZ { struct winsize s; if (!(GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS)) && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_row; } #endif { char *str; if ((str = os_getenv("LINES"))) return atoi(str); } #ifdef __EMX__ { int scrsize[2]; _scrsize(scrsize); return scrsize[1]; } #endif return 0; } #define DFT_TERM_WIDTH 80 #define DFT_TERM_HEIGHT 20 int term_width(void) { int n = term_width_intern(); return (n>1)? n: DFT_TERM_WIDTH; } int term_height(void) { int n = term_height_intern(); return (n>1)? n: DFT_TERM_HEIGHT; } static ulong col_index; /* output string wrapped after MAX_WIDTH characters (for gp -test) */ static void putc_lw(char c) { if (c == '\n') col_index = 0; else if (col_index >= GP_DATA->linewrap) { normalOutC('\n'); col_index = 1; } else col_index++; normalOutC(c); } static void puts_lw(const char *s) { while (*s) putc_lw(*s++); } static PariOUT pariOut_lw= {putc_lw, puts_lw, normalOutF}; void init_linewrap(long w) { col_index=0; GP_DATA->linewrap=w; pariOut=&pariOut_lw; } /* output stopped after max_line have been printed, for default(lines,). * n = length of prefix already printed (print up to max_lin lines) */ void lim_lines_output(char *s, long n, long max_lin) { long lin, col, width; char c; if (!*s) return; width = term_width(); lin = 1; col = n; if (lin > max_lin) return; while ( (c = *s++) ) { if (lin >= max_lin) if (c == '\n' || col >= width-5) { pari_sp av = avma; pari_puts(term_get_color(NULL, c_ERR)); avma = av; pari_puts("[+++]"); return; } if (c == '\n') { col = -1; lin++; } else if (col == width) { col = 0; lin++; } set_last_newline(c); col++; pari_putc(c); } } static void new_line(PariOUT *out, const char *prefix) { out_putc(out, '\n'); if (prefix) out_puts(out, prefix); } #define is_blank(c) ((c) == ' ' || (c) == '\n' || (c) == '\t') /* output: < s wrapped at EOL > * < ... > * ^--- (no \n at the end) * If str is NULL, omit the arrow, end the text with '\n'. * If prefix is NULL, use "" */ void print_prefixed_text(PariOUT *out, const char *s, const char *prefix, const char *str) { const long prelen = prefix? strlen_real(prefix): 0; const long W = term_width(), ls = strlen(s); long linelen = prelen; char *word = (char*)pari_malloc(ls + 3); if (prefix) out_puts(out, prefix); for(;;) { long len; int blank = 0; char *u = word; while (*s && !is_blank(*s)) *u++ = *s++; *u = 0; /* finish "word" */ len = strlen_real(word); linelen += len; if (linelen >= W) { new_line(out, prefix); linelen = prelen + len; } out_puts(out, word); while (is_blank(*s)) { switch (*s) { case ' ': break; case '\t': linelen = (linelen & ~7UL) + 8; out_putc(out, '\t'); blank = 1; break; case '\n': linelen = W; blank = 1; break; } if (linelen >= W) { new_line(out, prefix); linelen = prelen; } s++; } if (!*s) break; if (!blank) { out_putc(out, ' '); linelen++; } } if (!str) out_putc(out, '\n'); else { long i,len = strlen_real(str); int space = (*str == ' ' && str[1]); if (linelen + len >= W) { new_line(out, prefix); linelen = prelen; if (space) { str++; len--; space = 0; } } out_term_color(out, c_OUTPUT); out_puts(out, str); if (!len || str[len-1] != '\n') out_putc(out, '\n'); if (space) { linelen++; len--; } out_term_color(out, c_ERR); if (prefix) { out_puts(out, prefix); linelen -= prelen; } for (i=0; i MAX_PAST) { past = MAX_PAST; strcpy(t, "..."); t += 3; } term_get_color(t, c_OUTPUT); t += strlen(t); memcpy(t, s - past, past); t[past] = 0; } /* suffix (past arrow) */ t = str; if (!past) *t++ = ' '; future = CONTEXT_LEN - past; strncpy(t, s, future); t[future] = 0; /* prefix '***' */ term_get_color(pre, c_ERR); strcat(pre, " *** "); /* now print */ print_prefixed_text(out, buf, pre, str); pari_free(buf); } /********************************************************************/ /** **/ /** GEN <---> CHARACTER STRINGS **/ /** **/ /********************************************************************/ static OUT_FUN get_fun(long flag) { switch(flag) { case f_RAW : return bruti; case f_TEX : return texi; default: return matbruti; } } char * stack_strdup(const char *s) { long n = strlen(s)+1; char *t = stack_malloc(n); memcpy(t,s,n); return t; } char * stack_strcat(const char *s, const char *t) { long ls = strlen(s), lt = strlen(t); long n = ls + lt + 1; char *u = stack_malloc(n); memcpy(u, s, ls); memcpy(u + ls,t, lt+1); return u; } char * pari_strdup(const char *s) { long n = strlen(s)+1; char *t = (char*)pari_malloc(n); memcpy(t,s,n); return t; } char * pari_strndup(const char *s, long n) { char *t = (char*)pari_malloc(n+1); memcpy(t,s,n); t[n] = 0; return t; } /* not stack clean */ static char * stack_GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out) { pari_str S; str_init(&S, 1); out(x, T, &S); *S.cur = 0; return S.string; } /* same but remove quotes "" around t_STR */ static char * stack_GENtostr_fun_unquoted(GEN x, pariout_t *T, OUT_FUN out) { return (typ(x)==t_STR)? GSTR(x): stack_GENtostr_fun(x, T, out); } /* stack-clean: pari-malloc'ed */ static char * GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out) { pari_sp av = avma; pari_str S; str_init(&S, 0); out(x, T, &S); *S.cur = 0; avma = av; return S.string; } /* returns a malloc-ed string, which should be freed after usage */ /* Returns pari_malloc()ed string */ char * GENtostr(GEN x) { return GENtostr_fun(x, GP_DATA->fmt, get_fun(GP_DATA->fmt->prettyp)); } char * GENtoTeXstr(GEN x) { return GENtostr_fun(x, GP_DATA->fmt, &texi); } char * GENtostr_unquoted(GEN x) { return stack_GENtostr_fun_unquoted(x, GP_DATA->fmt, &bruti); } /* alloc-ed on PARI stack */ char * GENtostr_raw(GEN x) { return stack_GENtostr_fun(x,GP_DATA->fmt,&bruti); } GEN GENtoGENstr(GEN x) { char *s = GENtostr_fun(x, GP_DATA->fmt, &bruti); GEN z = strtoGENstr(s); pari_free(s); return z; } GEN GENtoGENstr_nospace(GEN x) { pariout_t T = *(GP_DATA->fmt); char *s; GEN z; T.sp = 0; s = GENtostr_fun(x, &T, &bruti); z = strtoGENstr(s); pari_free(s); return z; } static char ltoc(long n) { if (n <= 0 || n > 255) pari_err(e_MISC, "out of range in integer -> character conversion (%ld)", n); return (char)n; } static char itoc(GEN x) { return ltoc(gtos(x)); } GEN Strchr(GEN g) { long i, l, len, t = typ(g); char *s; GEN x; if (is_vec_t(t)) { l = lg(g); len = nchar2nlong(l); x = cgetg(len+1, t_STR); s = GSTR(x); for (i=1; i0)? '+' : '-') #define putsigne(S, x) str_puts(S, (x>0)? " + " : " - ") #define sp_sign_sp(T,S, x) ((T)->sp? putsigne(S,x): putsigne_nosp(S,x)) #define semicolon_sp(T,S) ((T)->sp? str_puts(S, "; "): str_putc(S, ';')) #define comma_sp(T,S) ((T)->sp? str_puts(S, ", "): str_putc(S, ',')) /* print e to S (more efficient than sprintf) */ static void str_ulong(pari_str *S, ulong e) { if (e == 0) str_putc(S, '0'); else { char buf[21], *p = buf + numberof(buf); *--p = 0; if (e > 9) { do *--p = "0123456789"[e % 10]; while ((e /= 10) > 9); } *--p = "0123456789"[e]; str_puts(S, p); } } static void str_long(pari_str *S, long e) { if (e >= 0) str_ulong(S, (ulong)e); else { str_putc(S, '-'); str_ulong(S, -(ulong)e); } } static void wr_vecsmall(pariout_t *T, pari_str *S, GEN g) { long i, l; str_puts(S, "Vecsmall(["); l = lg(g); for (i=1; i 0) ? '+' : '-'; } static void blancs(long nb) { while (nb-- > 0) pari_putc(' '); } /* write an "address" */ static void str_addr(pari_str *S, ulong x) { char s[128]; sprintf(s,"%0*lx", BITS_IN_LONG/4, x); str_puts(S, s); } static void dbg_addr(ulong x) { pari_printf("[&=%0*lx] ", BITS_IN_LONG/4, x); } /* write a "word" */ static void dbg_word(ulong x) { pari_printf("%0*lx ", BITS_IN_LONG/4, x); } /* bl: indent level */ static void dbg(GEN x, long nb, long bl) { long tx,i,j,e,dx,lx; if (!x) { pari_puts("NULL\n"); return; } tx = typ(x); if (tx == t_INT && x == gen_0) { pari_puts("gen_0\n"); return; } dbg_addr((ulong)x); lx = lg(x); pari_printf("%s(lg=%ld%s):",type_name(tx)+2,lx,isclone(x)? ",CLONE" : ""); dbg_word(x[0]); if (! is_recursive_t(tx)) /* t_INT, t_REAL, t_STR, t_VECSMALL */ { if (tx == t_STR) pari_puts("chars:"); else if (tx == t_INT) { lx = lgefint(x); pari_printf("(%c,lgefint=%ld):", vsigne(x), lx); } else if (tx == t_REAL) pari_printf("(%c,expo=%ld):", vsigne(x), expo(x)); if (nb < 0) nb = lx; for (i=1; i < nb; i++) dbg_word(x[i]); pari_putc('\n'); return; } if (tx == t_PADIC) pari_printf("(precp=%ld,valp=%ld):", precp(x), valp(x)); else if (tx == t_POL) pari_printf("(%c,varn=%ld):", vsigne(x), varn(x)); else if (tx == t_SER) pari_printf("(%c,varn=%ld,prec=%ld,valp=%ld):", vsigne(x), varn(x), lg(x)-2, valp(x)); else if (tx == t_LIST) { pari_printf("(subtyp=%ld,lmax=%ld):", list_typ(x), list_nmax(x)); x = list_data(x); lx = x? lg(x): 1; tx = t_VEC; /* print list_data as vec */ } else if (tx == t_CLOSURE) pari_printf("(arity=%ld%s):", closure_arity(x), closure_is_variadic(x)?"+":""); for (i=1; iname); dbg_addr((ulong)ep); pari_printf(": hash = %ld [%ld]\n", ep->hash % functions_tblsz, ep->hash); pari_printf(" menu = %2ld, code = %-10s", ep->menu, ep->code? ep->code: "NULL"); if (ep->next) { pari_printf("next = %s ",(ep->next)->name); dbg_addr((ulong)ep->next); } pari_puts("\n"); } /* s = digit n : list of entrees in functions_hash[n] (s = $: last entry) * = range m-n: functions_hash[m..n] * = identifier: entree for that identifier */ void print_functions_hash(const char *s) { long m, n, Max, Total; entree *ep; if (isdigit((int)*s) || *s == '$') { m = functions_tblsz-1; n = atol(s); if (*s=='$') n = m; if (mnext) print_entree(ep); } return; } if (is_keyword_char((int)*s)) { ep = is_entry(s); if (!ep) pari_err(e_MISC,"no such function"); print_entree(ep); return; } if (*s=='-') { for (n=0; nnext) m++; pari_printf("%3ld:%3ld ",n,m); if (n%9 == 8) pari_putc('\n'); } pari_putc('\n'); return; } Max = Total = 0; for (n=0; nnext) { print_entree(ep); cnt++; } Total += cnt; if (cnt > Max) Max = cnt; } pari_printf("Total: %ld, Max: %ld\n", Total, Max); } /********************************************************************/ /** **/ /** FORMATTED OUTPUT **/ /** **/ /********************************************************************/ static const char * get_var(long v, char *buf) { entree *ep = varentries[v]; if (ep) return (char*)ep->name; sprintf(buf,"t%d",(int)v); return buf; } static void do_append(char **sp, char c, char *last, int count) { if (*sp + count > last) pari_err(e_MISC, "TeX variable name too long"); while (count--) *(*sp)++ = c; } static char * get_texvar(long v, char *buf, unsigned int len) { entree *ep = varentries[v]; char *t = buf, *e = buf + len - 1; const char *s; if (!ep) pari_err(e_MISC, "this object uses debugging variables"); s = ep->name; if (strlen(s) >= len) pari_err(e_MISC, "TeX variable name too long"); while (isalpha((int)*s)) *t++ = *s++; *t = 0; if (isdigit((int)*s) || *s == '_') { int seen1 = 0, seen = 0; /* Skip until the first non-underscore */ while (*s == '_') s++, seen++; /* Special-case integers and empty subscript */ if (*s == 0 || isdigit((unsigned char)*s)) seen++; do_append(&t, '_', e, 1); do_append(&t, '{', e, 1); do_append(&t, '[', e, seen - 1); while (1) { if (*s == '_') seen1++, s++; else { if (seen1) { do_append(&t, ']', e, (seen >= seen1 ? seen1 : seen) - 1); do_append(&t, ',', e, 1); do_append(&t, '[', e, seen1 - 1); if (seen1 > seen) seen = seen1; seen1 = 0; } if (*s == 0) break; do_append(&t, *s++, e, 1); } } do_append(&t, ']', e, seen - 1); do_append(&t, '}', e, 1); *t = 0; } return buf; } void dbg_pari_heap(void) { long nu, l, u, s; pari_sp av = avma; GEN adr = getheap(); pari_sp top = pari_mainstack->top, bot = pari_mainstack->bot; nu = (top-avma)/sizeof(long); l = pari_mainstack->size/sizeof(long); pari_printf("\n Top : %lx Bottom : %lx Current stack : %lx\n", top, bot, avma); pari_printf(" Used : %ld long words (%ld K)\n", nu, nu/1024*sizeof(long)); pari_printf(" Available : %ld long words (%ld K)\n", (l-nu), (l-nu)/1024*sizeof(long)); pari_printf(" Occupation of the PARI stack : %6.2f percent\n", 100.0*nu/l); pari_printf(" %ld objects on heap occupy %ld long words\n\n", itos(gel(adr,1)), itos(gel(adr,2))); u = pari_var_next(); s = MAXVARN - pari_var_next_temp(); pari_printf(" %ld variable names used (%ld user + %ld private) out of %d\n\n", u+s, u, s, MAXVARN); avma = av; } /* is to be printed as '0' */ static long isnull(GEN g) { long i; switch (typ(g)) { case t_INT: return !signe(g); case t_COMPLEX: return isnull(gel(g,1)) && isnull(gel(g,2)); case t_FFELT: return FF_equal0(g); case t_QUAD: return isnull(gel(g,2)) && isnull(gel(g,3)); case t_FRAC: case t_RFRAC: return isnull(gel(g,1)); case t_POL: for (i=lg(g)-1; i>1; i--) if (!isnull(gel(g,i))) return 0; return 1; } return 0; } /* 0 coeff to be omitted in t_POL ? */ static int isnull_for_pol(GEN g) { switch(typ(g)) { case t_INTMOD: return !signe(gel(g,2)); case t_POLMOD: return isnull(gel(g,2)); default: return isnull(g); } } /* return 1 or -1 if g is 1 or -1, 0 otherwise*/ static long isone(GEN g) { long i; switch (typ(g)) { case t_INT: return (signe(g) && is_pm1(g))? signe(g): 0; case t_FFELT: return FF_equal1(g); case t_COMPLEX: return isnull(gel(g,2))? isone(gel(g,1)): 0; case t_QUAD: return isnull(gel(g,3))? isone(gel(g,2)): 0; case t_FRAC: case t_RFRAC: return isone(gel(g,1)) * isone(gel(g,2)); case t_POL: if (!signe(g)) return 0; for (i=lg(g)-1; i>2; i--) if (!isnull(gel(g,i))) return 0; return isone(gel(g,2)); } return 0; } /* if g is a "monomial", return its sign, 0 otherwise */ static long isfactor(GEN g) { long i,deja,sig; switch(typ(g)) { case t_INT: case t_REAL: return (signe(g)<0)? -1: 1; case t_FRAC: case t_RFRAC: return isfactor(gel(g,1)); case t_FFELT: return isfactor(FF_to_FpXQ_i(g)); case t_COMPLEX: if (isnull(gel(g,1))) return isfactor(gel(g,2)); if (isnull(gel(g,2))) return isfactor(gel(g,1)); return 0; case t_PADIC: return !signe(gel(g,4)); case t_QUAD: if (isnull(gel(g,2))) return isfactor(gel(g,3)); if (isnull(gel(g,3))) return isfactor(gel(g,2)); return 0; case t_POL: deja = 0; sig = 1; for (i=lg(g)-1; i>1; i--) if (!isnull_for_pol(gel(g,i))) { if (deja) return 0; sig=isfactor(gel(g,i)); deja=1; } return sig? sig: 1; case t_SER: for (i=lg(g)-1; i>1; i--) if (!isnull(gel(g,i))) return 0; } return 1; } /* return 1 if g is a "truc" (see anal.c) */ static long isdenom(GEN g) { long i,deja; switch(typ(g)) { case t_FRAC: case t_RFRAC: return 0; case t_COMPLEX: return isnull(gel(g,2)); case t_PADIC: return !signe(gel(g,4)); case t_QUAD: return isnull(gel(g,3)); case t_POL: deja = 0; for (i=lg(g)-1; i>1; i--) if (!isnull(gel(g,i))) { if (deja) return 0; if (i==2) return isdenom(gel(g,2)); if (!isone(gel(g,i))) return 0; deja=1; } return 1; case t_SER: for (i=lg(g)-1; i>1; i--) if (!isnull(gel(g,i))) return 0; } return 1; } /********************************************************************/ /** **/ /** RAW OUTPUT **/ /** **/ /********************************************************************/ /* ^e */ static void texexpo(pari_str *S, long e) { if (e != 1) { str_putc(S, '^'); if (e >= 0 && e < 10) { str_putc(S, '0' + e); } else { str_putc(S, '{'); str_long(S, e); str_putc(S, '}'); } } } static void wrexpo(pari_str *S, long e) { if (e != 1) { str_putc(S, '^'); str_long(S, e); } } /* v^e */ static void VpowE(pari_str *S, const char *v, long e) { str_puts(S, v); wrexpo(S,e); } static void texVpowE(pari_str *S, const char *v, long e) { str_puts(S, v); texexpo(S,e); } static void monome(pari_str *S, const char *v, long e) { if (e) VpowE(S, v, e); else str_putc(S, '1'); } static void texnome(pari_str *S, const char *v, long e) { if (e) texVpowE(S, v, e); else str_putc(S, '1'); } /* ( a ) */ static void paren(pariout_t *T, pari_str *S, GEN a) { str_putc(S, '('); bruti(a,T,S); str_putc(S, ')'); } static void texparen(pariout_t *T, pari_str *S, GEN a) { if (T->TeXstyle & TEXSTYLE_PAREN) str_puts(S, " ("); else str_puts(S, " \\left("); texi(a,T,S); if (T->TeXstyle & TEXSTYLE_PAREN) str_puts(S, ") "); else str_puts(S, "\\right) "); } /* * v^d */ static void times_texnome(pari_str *S, const char *v, long d) { if (d) { str_puts(S, "\\*"); texnome(S,v,d); } } static void times_monome(pari_str *S, const char *v, long d) { if (d) { str_putc(S, '*'); monome(S,v,d); } } /* write a * v^d */ static void wr_monome(pariout_t *T, pari_str *S, GEN a, const char *v, long d) { long sig = isone(a); if (sig) { sp_sign_sp(T,S,sig); monome(S,v,d); } else { sig = isfactor(a); if (sig) { sp_sign_sp(T,S,sig); bruti_sign(a,T,S,0); } else { sp_sign_sp(T,S,1); paren(T,S, a); } times_monome(S, v, d); } } static void wr_texnome(pariout_t *T, pari_str *S, GEN a, const char *v, long d) { long sig = isone(a); str_putc(S, '\n'); /* Avoid TeX buffer overflow */ if (T->TeXstyle & TEXSTYLE_BREAK) str_puts(S, "\\PARIbreak "); if (sig) { putsigne(S,sig); texnome(S,v,d); } else { sig = isfactor(a); if (sig) { putsigne(S,sig); texi_sign(a,T,S,0); } else { str_puts(S, " +"); texparen(T,S, a); } times_texnome(S, v, d); } } static void wr_lead_monome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign) { long sig = isone(a); if (sig) { if (addsign && sig<0) str_putc(S, '-'); monome(S,v,d); } else { if (isfactor(a)) bruti_sign(a,T,S,addsign); else paren(T,S, a); times_monome(S, v, d); } } static void wr_lead_texnome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign) { long sig = isone(a); if (sig) { if (addsign && sig<0) str_putc(S, '-'); texnome(S,v,d); } else { if (isfactor(a)) texi_sign(a,T,S,addsign); else texparen(T,S, a); times_texnome(S, v, d); } } static void prints(GEN g, pariout_t *T, pari_str *S) { (void)T; str_long(S, (long)g); } static void quote_string(pari_str *S, char *s) { str_putc(S, '"'); while (*s) { char c=*s++; if (c=='\\' || c=='"' || c=='\033' || c=='\n' || c=='\t') { str_putc(S, '\\'); switch(c) { case '\\': case '"': break; case '\n': c='n'; break; case '\033': c='e'; break; case '\t': c='t'; break; } } str_putc(S, c); } str_putc(S, '"'); } static int print_0_or_pm1(GEN g, pari_str *S, int addsign) { long r; if (!g) { str_puts(S, "NULL"); return 1; } if (isnull(g)) { str_putc(S, '0'); return 1; } r = isone(g); if (r) { if (addsign && r<0) str_putc(S, '-'); str_putc(S, '1'); return 1; } return 0; } static void print_precontext(GEN g, pari_str *S, long tex) { if (lg(g)<8 || lg(gel(g,7))==1) return; else { long i, n = closure_arity(g); str_puts(S,"("); for(i=1; i<=n; i++) { str_puts(S,"v"); if (tex) str_puts(S,"_{"); str_ulong(S,i); if (tex) str_puts(S,"}"); if (i < n) str_puts(S,","); } str_puts(S,")->"); } } static void print_context(GEN g, pariout_t *T, pari_str *S, long tex) { GEN str = closure_get_text(g); if (lg(g)<8 || lg(gel(g,7))==1) return; if (typ(str)==t_VEC && lg(gel(closure_get_dbg(g),3)) >= 2) { GEN v = closure_get_frame(g), d = gmael(closure_get_dbg(g),3,1); long i, l = lg(v), n=0; for(i=1; iname); str_putc(S,'='); if (tex) texi(gel(v,l-i),T,S); else bruti(gel(v,l-i),T,S); if (--n) str_putc(S,','); } str_puts(S,");"); } else { GEN v = closure_get_frame(g); long i, l = lg(v), n = closure_arity(g); str_puts(S,"("); for(i=1; i<=n; i++) { str_puts(S,"v"); if (tex) str_puts(S,"_{"); str_ulong(S,i); if (tex) str_puts(S,"}"); str_puts(S,","); } for(i=1; isp, (char)toupper((int)T->format), T->sigd) ); avma = av; break; } case t_INTMOD: case t_POLMOD: str_puts(S, "Mod("); bruti(gel(g,2),T,S); comma_sp(T,S); bruti(gel(g,1),T,S); str_putc(S, ')'); break; case t_FFELT: bruti_sign(FF_to_FpXQ_i(g),T,S,addsign); break; case t_FRAC: case t_RFRAC: r = isfactor(gel(g,1)); if (!r) str_putc(S, '('); bruti_sign(gel(g,1),T,S,addsign); if (!r) str_putc(S, ')'); str_putc(S, '/'); r = isdenom(gel(g,2)); if (!r) str_putc(S, '('); bruti(gel(g,2),T,S); if (!r) str_putc(S, ')'); break; case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD); v = cxq_init(g, tg, &a, &b, buf); if (isnull(a)) { wr_lead_monome(T,S,b,v,1,addsign); return; } bruti_sign(a,T,S,addsign); if (!isnull(b)) wr_monome(T,S,b,v,1); break; case t_POL: v = get_var(varn(g), buf); /* hack: we want g[i] = coeff of degree i. */ i = degpol(g); g += 2; while (isnull(gel(g,i))) i--; wr_lead_monome(T,S,gel(g,i),v,i,addsign); while (i--) { a = gel(g,i); if (!isnull_for_pol(a)) wr_monome(T,S,a,v,i); } break; case t_SER: v = get_var(varn(g), buf); i = valp(g); l = lg(g)-2; if (l) { /* See normalize(): Mod(0,2)*x^i*(1+O(x)), has valp = i+1 */ if (l == 1 && !signe(g) && isexactzero(gel(g,2))) i--; /* hack: we want g[i] = coeff of degree i */ l += i; g -= i-2; wr_lead_monome(T,S,gel(g,i),v,i,addsign); while (++i < l) { a = gel(g,i); if (!isnull_for_pol(a)) wr_monome(T,S,a,v,i); } sp_sign_sp(T,S,1); } str_puts(S, "O("); VpowE(S, v, i); str_putc(S, ')'); break; case t_PADIC: { GEN p = gel(g,2); pari_sp av, av0; char *ev; str_alloc(S, (precp(g)+1) * lgefint(p)); /* careful! */ av0 = avma; ev = itostr(p); av = avma; i = valp(g); l = precp(g)+i; g = gel(g,4); for (; i=7) { GEN str = closure_get_text(g); if (typ(str)==t_STR) { print_precontext(g, S, 0); str_puts(S, GSTR(str)); print_context(g, T, S, 0); } else { str_putc(S,'('); str_puts(S,GSTR(gel(str,1))); str_puts(S,")->"); print_context(g, T, S, 0); str_puts(S,GSTR(gel(str,2))); } } else { str_puts(S,"{\""); str_puts(S,GSTR(closure_get_code(g))); str_puts(S,"\","); wr_vecsmall(T,S,closure_get_oper(g)); str_putc(S,','); bruti(gel(g,4),T,S); str_putc(S,','); bruti(gel(g,5),T,S); str_putc(S,'}'); } break; case t_INFINITY: str_puts(S, inf_get_sign(g) == 1? "+oo": "-oo"); break; case t_MAT: { OUT_FUN print; r = lg(g); if (r==1) { str_puts(S, "[;]"); return; } l = lgcols(g); if (l==1) { mat0n(S, r-1); return; } print = (typ(gel(g,1)) == t_VECSMALL)? prints: bruti; if (l==2) { str_puts(S, "Mat("); if (r == 2) { print(gcoeff(g,1,1),T,S); str_putc(S, ')'); return; } } str_putc(S, '['); for (i=1; iuse_stack)*/ av2 = avma; str_init(&str, 1); for (j=1; j w) { pad = NULL; break; } /* doesn't fit, abort padding */ } avma = av2; } for (i=1; i 0) str_putc(S, ' '); } print(gcoeff(g,i,j),T,S); if (juse_stack) avma = av; } /********************************************************************/ /** **/ /** TeX OUTPUT **/ /** **/ /********************************************************************/ /* this follows bruti_sign */ static void texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign) { long tg,i,j,l,r; GEN a,b; const char *v; char buf[67]; if (print_0_or_pm1(g, S, addsign)) return; tg = typ(g); switch(tg) { case t_INT: case t_REAL: case t_QFR: case t_QFI: bruti_intern(g, T, S, addsign); break; case t_INTMOD: case t_POLMOD: texi(gel(g,2),T,S); str_puts(S, " mod "); texi(gel(g,1),T,S); break; case t_FRAC: if (addsign && isfactor(gel(g,1)) < 0) str_putc(S, '-'); str_puts(S, "\\frac{"); texi_sign(gel(g,1),T,S,0); str_puts(S, "}{"); texi_sign(gel(g,2),T,S,0); str_puts(S, "}"); break; case t_RFRAC: str_puts(S, "\\frac{"); texi(gel(g,1),T,S); /* too complicated otherwise */ str_puts(S, "}{"); texi(gel(g,2),T,S); str_puts(S, "}"); break; case t_FFELT: bruti_sign(FF_to_FpXQ_i(g),T,S,addsign); break; case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD); v = cxq_init(g, tg, &a, &b, buf); if (isnull(a)) { wr_lead_texnome(T,S,b,v,1,addsign); break; } texi_sign(a,T,S,addsign); if (!isnull(b)) wr_texnome(T,S,b,v,1); break; case t_POL: v = get_texvar(varn(g), buf, sizeof(buf)); /* hack: we want g[i] = coeff of degree i. */ i = degpol(g); g += 2; while (isnull(gel(g,i))) i--; wr_lead_texnome(T,S,gel(g,i),v,i,addsign); while (i--) { a = gel(g,i); if (!isnull_for_pol(a)) wr_texnome(T,S,a,v,i); } break; case t_SER: v = get_texvar(varn(g), buf, sizeof(buf)); i = valp(g); if (lg(g)-2) { /* hack: we want g[i] = coeff of degree i. */ l = i + lg(g)-2; g -= i-2; wr_lead_texnome(T,S,gel(g,i),v,i,addsign); while (++i < l) { a = gel(g,i); if (!isnull_for_pol(a)) wr_texnome(T,S,a,v,i); } str_puts(S, "+ "); } str_puts(S, "O("); texnome(S,v,i); str_putc(S, ')'); break; case t_PADIC: { GEN p = gel(g,2); pari_sp av; char *ev; str_alloc(S, (precp(g)+1) * lgefint(p)); /* careful! */ av = avma; i = valp(g); l = precp(g)+i; g = gel(g,4); ev = itostr(p); for (; i=6) { GEN str = closure_get_text(g); if (typ(str)==t_STR) { print_precontext(g, S, 1); str_puts(S, GSTR(str)); print_context(g, T, S ,1); } else { str_putc(S,'('); str_puts(S,GSTR(gel(str,1))); str_puts(S,")\\mapsto "); print_context(g, T, S ,1); str_puts(S,GSTR(gel(str,2))); } } else { str_puts(S,"\\{\""); str_puts(S,GSTR(closure_get_code(g))); str_puts(S,"\","); texi(gel(g,3),T,S); str_putc(S,','); texi(gel(g,4),T,S); str_putc(S,','); texi(gel(g,5),T,S); str_puts(S,"\\}"); } break; case t_INFINITY: str_puts(S, inf_get_sign(g) == 1? "+\\infty": "-\\infty"); break; case t_MAT: { str_puts(S, "\\pmatrix{\n "); r = lg(g); if (r>1) { OUT_FUN print = (typ(gel(g,1)) == t_VECSMALL)? prints: texi; l = lgcols(g); for (i=1; iformat = f; T->sigd = sigd; T->sp = sp; } static void gen_output_fun(GEN x, pariout_t *T, OUT_FUN out) { pari_sp av = avma; pari_puts( stack_GENtostr_fun(x,T,out) ); avma = av; } void fputGEN_pariout(GEN x, pariout_t *T, FILE *out) { pari_sp av = avma; char *s = stack_GENtostr_fun(x, T, get_fun(T->prettyp)); if (*s) { set_last_newline(s[strlen(s)-1]); fputs(s, out); } avma = av; } void brute(GEN g, char f, long d) { pariout_t T; _initout(&T,f,d,0); gen_output_fun(g, &T, &bruti); } void matbrute(GEN g, char f, long d) { pariout_t T; _initout(&T,f,d,1); gen_output_fun(g, &T, &matbruti); } void texe(GEN g, char f, long d) { pariout_t T; _initout(&T,f,d,0); gen_output_fun(g, &T, &texi); } void gen_output(GEN x) { gen_output_fun(x, GP_DATA->fmt, get_fun(GP_DATA->fmt->prettyp)); pari_putc('\n'); pari_flush(); } void output(GEN x) { brute(x,'g',-1); pari_putc('\n'); pari_flush(); } void outmat(GEN x) { matbrute(x,'g',-1); pari_putc('\n'); pari_flush(); } /*******************************************************************/ /** FILES **/ /*******************************************************************/ /* to cache '~' expansion */ static char *homedir; /* last file read successfully from try_name() */ static THREAD char *last_filename; /* stack of temporary files (includes all infiles + some output) */ static THREAD pariFILE *last_tmp_file; /* stack of "permanent" (output) files */ static THREAD pariFILE *last_file; typedef struct gpfile { const char *name; FILE *fp; int type; long serial; } gpfile; static THREAD gpfile *gp_file; static THREAD pari_stack s_gp_file; static THREAD long gp_file_serial; #if defined(UNIX) || defined(__EMX__) # include # include /* for open */ # ifdef __EMX__ # include # endif # define HAVE_PIPES #endif #if defined(_WIN32) # define HAVE_PIPES #endif #ifndef O_RDONLY # define O_RDONLY 0 #endif pariFILE * newfile(FILE *f, const char *name, int type) { pariFILE *file = (pariFILE*) pari_malloc(strlen(name) + 1 + sizeof(pariFILE)); file->type = type; file->name = strcpy((char*)(file+1), name); file->file = f; file->next = NULL; if (type & mf_PERM) { file->prev = last_file; last_file = file; } else { file->prev = last_tmp_file; last_tmp_file = file; } if (file->prev) (file->prev)->next = file; if (DEBUGFILES) err_printf("I/O: new pariFILE %s (code %d) \n",name,type); return file; } static void pari_kill_file(pariFILE *f) { if ((f->type & mf_PIPE) == 0) { if (f->file != stdin && fclose(f->file)) pari_warn(warnfile, "close", f->name); } #ifdef HAVE_PIPES else { if (f->type & mf_FALSE) { if (f->file != stdin && fclose(f->file)) pari_warn(warnfile, "close", f->name); if (unlink(f->name)) pari_warn(warnfile, "delete", f->name); } else if (pclose(f->file) < 0) pari_warn(warnfile, "close pipe", f->name); } #endif if (DEBUGFILES) err_printf("I/O: closing file %s (code %d) \n",f->name,f->type); pari_free(f); } void pari_fclose(pariFILE *f) { if (f->next) (f->next)->prev = f->prev; else if (f == last_tmp_file) last_tmp_file = f->prev; else if (f == last_file) last_file = f->prev; if (f->prev) (f->prev)->next = f->next; pari_kill_file(f); } static pariFILE * pari_open_file(FILE *f, const char *s, const char *mode) { if (!f) pari_err_FILE("requested file", s); if (DEBUGFILES) err_printf("I/O: opening file %s (mode %s)\n", s, mode); return newfile(f,s,0); } pariFILE * pari_fopen_or_fail(const char *s, const char *mode) { return pari_open_file(fopen(s, mode), s, mode); } pariFILE * pari_fopen(const char *s, const char *mode) { FILE *f = fopen(s, mode); return f? pari_open_file(f, s, mode): NULL; } void pari_fread_chars(void *b, size_t n, FILE *f) { if (fread(b, sizeof(char), n, f) < n) pari_err_FILE("input file [fread]", "FILE*"); } /* FIXME: HAS_FDOPEN & allow standard open() flags */ #ifdef UNIX /* open tmpfile s (a priori for writing) avoiding symlink attacks */ pariFILE * pari_safefopen(const char *s, const char *mode) { long fd = open(s, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); if (fd == -1) pari_err(e_MISC,"tempfile %s already exists",s); return pari_open_file(fdopen(fd, mode), s, mode); } #else pariFILE * pari_safefopen(const char *s, const char *mode) { return pari_fopen_or_fail(s, mode); } #endif void pari_unlink(const char *s) { if (unlink(s)) pari_warn(warner, "I/O: can\'t remove file %s", s); else if (DEBUGFILES) err_printf("I/O: removed file %s\n", s); } /* Remove one INFILE from the stack. Reset pari_infile (to the most recent * infile) * Return -1, if we're trying to pop out stdin itself; 0 otherwise * Check for leaked file handlers (temporary files) */ int popinfile(void) { pariFILE *f = last_tmp_file, *g; while (f) { if (f->type & mf_IN) break; pari_warn(warner, "I/O: leaked file descriptor (%d): %s", f->type, f->name); g = f; f = f->prev; pari_fclose(g); } last_tmp_file = f; if (!f) return -1; pari_fclose(last_tmp_file); for (f = last_tmp_file; f; f = f->prev) if (f->type & mf_IN) { pari_infile = f->file; return 0; } pari_infile = stdin; return 0; } /* delete all "temp" files open since last reference point F */ void tmp_restore(pariFILE *F) { pariFILE *f = last_tmp_file; if (DEBUGFILES>1) err_printf("gp_context_restore: deleting open files...\n"); while (f) { pariFILE *g = f->prev; if (f == F) break; pari_fclose(f); f = g; } for (; f; f = f->prev) { if (f->type & mf_IN) { pari_infile = f->file; if (DEBUGFILES>1) err_printf("restoring pari_infile to %s\n", f->name); break; } } if (!f) { pari_infile = stdin; if (DEBUGFILES>1) err_printf("gp_context_restore: restoring pari_infile to stdin\n"); } if (DEBUGFILES>1) err_printf("done\n"); } void filestate_save(struct pari_filestate *file) { file->file = last_tmp_file; file->serial = gp_file_serial; } static void filestate_close(long serial) { long i; for (i = 0; i < s_gp_file.n; i++) if (gp_file[i].fp && gp_file[i].serial >= serial) gp_fileclose(i); gp_file_serial = serial; } void filestate_restore(struct pari_filestate *file) { tmp_restore(file->file); filestate_close(file->serial); } static void kill_file_stack(pariFILE **s) { pariFILE *f = *s; while (f) { pariFILE *t = f->prev; pari_kill_file(f); *s = f = t; /* have to update *s in case of ^C */ } } void killallfiles(void) { kill_file_stack(&last_tmp_file); pari_infile = stdin; } void pari_init_homedir(void) { homedir = NULL; } void pari_close_homedir(void) { if (homedir) pari_free(homedir); } void pari_init_files(void) { last_filename = NULL; last_tmp_file = NULL; last_file=NULL; pari_stack_init(&s_gp_file, sizeof(*gp_file), (void**)&gp_file); gp_file_serial = 0; } void pari_thread_close_files(void) { popinfile(); /* look for leaks */ kill_file_stack(&last_file); if (last_filename) pari_free(last_filename); kill_file_stack(&last_tmp_file); filestate_close(-1); pari_stack_delete(&s_gp_file); } void pari_close_files(void) { if (pari_logfile) { fclose(pari_logfile); pari_logfile = NULL; } pari_infile = stdin; } static int ok_pipe(FILE *f) { if (DEBUGFILES) err_printf("I/O: checking output pipe...\n"); pari_CATCH(CATCH_ALL) { return 0; } pari_TRY { int i; fprintf(f,"\n\n"); fflush(f); for (i=1; i<1000; i++) fprintf(f," \n"); fprintf(f,"\n"); fflush(f); } pari_ENDCATCH; return 1; } pariFILE * try_pipe(const char *cmd, int fl) { #ifndef HAVE_PIPES pari_err(e_ARCH,"pipes"); return NULL; #else FILE *file; const char *f; VOLATILE int flag = fl; # ifdef __EMX__ if (_osmode == DOS_MODE) /* no pipes under DOS */ { pari_sp av = avma; char *s; if (flag & mf_OUT) pari_err(e_ARCH,"pipes"); f = pari_unique_filename("pipe"); s = stack_malloc(strlen(cmd)+strlen(f)+4); sprintf(s,"%s > %s",cmd,f); file = system(s)? NULL: fopen(f,"r"); flag |= mf_FALSE; pari_free(f); avma = av; } else # endif { file = (FILE *) popen(cmd, (flag & mf_OUT)? "w": "r"); if (flag & mf_OUT) { if (!ok_pipe(file)) return NULL; flag |= mf_PERM; } f = cmd; } if (!file) pari_err(e_MISC,"[pipe:] '%s' failed",cmd); return newfile(file, f, mf_PIPE|flag); #endif } char * os_getenv(const char *s) { #ifdef HAS_GETENV return getenv(s); #else (void) s; return NULL; #endif } GEN gp_getenv(const char *s) { char *t = os_getenv(s); return t?strtoGENstr(t):gen_0; } /* FIXME: HAS_GETPWUID */ #if defined(UNIX) || defined(__EMX__) #include #include /* user = "": use current uid */ char * pari_get_homedir(const char *user) { struct passwd *p; char *dir = NULL; if (!*user) { if (homedir) dir = homedir; else { p = getpwuid(geteuid()); if (p) { dir = p->pw_dir; homedir = pari_strdup(dir); /* cache result */ } } } else { p = getpwnam(user); if (p) dir = p->pw_dir; /* warn, but don't kill session on startup (when expanding path) */ if (!dir) pari_warn(warner,"can't expand ~%s", user? user: ""); } return dir; } #else char * pari_get_homedir(const char *user) { (void) user; return NULL; } #endif /*******************************************************************/ /** **/ /** GP STANDARD INPUT AND OUTPUT **/ /** **/ /*******************************************************************/ #ifdef HAS_OPENDIR /* slow, but more portable than stat + S_ISDIR */ static int is_dir_opendir(const char *name) { DIR *d = opendir(name); if (d) { (void)closedir(d); return 1; } return 0; } #endif #ifdef HAS_STAT static int is_dir_stat(const char *name) { struct stat buf; if (stat(name, &buf)) return 0; return S_ISDIR(buf.st_mode); } #endif /* Does name point to a directory? */ int pari_is_dir(const char *name) { #ifdef HAS_STAT return is_dir_stat(name); #else # ifdef HAS_OPENDIR return is_dir_opendir(name); # else (void) name; return 0; # endif #endif } /* Does name point to a regular file? */ /* If unknown, assume that it is indeed regular. */ int pari_is_file(const char *name) { #ifdef HAS_STAT struct stat buf; if (stat(name, &buf)) return 1; return S_ISREG(buf.st_mode); #else (void) name; return 1; #endif } int pari_stdin_isatty(void) { #ifdef HAS_ISATTY return isatty( fileno(stdin) ); #else return 1; #endif } /* expand tildes in filenames, return a malloc'ed buffer */ static char * _path_expand(const char *s) { const char *t; char *ret, *dir = NULL; if (*s != '~') return pari_strdup(s); s++; /* skip ~ */ t = s; while (*t && *t != '/') t++; if (t == s) dir = pari_get_homedir(""); else { size_t len = t - s; char *user = (char*)pari_malloc(len+1); (void)memcpy(user,s,len); user[len] = 0; dir = pari_get_homedir(user); pari_free(user); } if (!dir) return pari_strdup(s); ret = (char*)pari_malloc(strlen(dir) + strlen(t) + 1); sprintf(ret,"%s%s",dir,t); return ret; } /* expand environment variables in str, return a malloc'ed buffer * assume no \ remain and str can be freed */ static char * _expand_env(char *str) { long i, l, len = 0, xlen = 16, xnum = 0; char *s = str, *s0 = s, *env; char **x = (char **)pari_malloc(xlen * sizeof(char*)); while (*s) { if (*s != '$') { s++; continue; } l = s - s0; if (l) { s0 = (char*)memcpy(pari_malloc(l+1), s0, l); s0[l] = 0; x[xnum++] = s0; len += l; } if (xnum > xlen - 3) /* need room for possibly two more elts */ { xlen <<= 1; x = (char **)pari_realloc((void*)x, xlen * sizeof(char*)); } s0 = ++s; /* skip $ */ while (is_keyword_char(*s)) s++; l = s - s0; env = (char*)memcpy(pari_malloc(l+1), s0, l); env[l] = 0; s0 = os_getenv(env); if (!s0) { pari_warn(warner,"undefined environment variable: %s",env); s0 = (char*)""; } l = strlen(s0); if (l) { s0 = (char*)memcpy(pari_malloc(l+1), s0, l); s0[l] = 0; x[xnum++] = s0; len += l; } pari_free(env); s0 = s; } l = s - s0; if (l) { s0 = (char*)memcpy(pari_malloc(l+1), s0, l); s0[l] = 0; x[xnum++] = s0; len += l; } s = (char*)pari_malloc(len+1); *s = 0; for (i = 0; i < xnum; i++) { (void)strcat(s, x[i]); pari_free(x[i]); } pari_free(str); pari_free(x); return s; } char * path_expand(const char *s) { #ifdef _WIN32 char *ss, *p; ss = pari_strdup(s); for (p = ss; *p != 0; ++p) if (*p == '\\') *p = '/'; p = _expand_env(_path_expand(ss)); pari_free(ss); return p; #else return _expand_env(_path_expand(s)); #endif } #ifdef HAS_STRFTIME # include void strftime_expand(const char *s, char *buf, long max) { time_t t; BLOCK_SIGINT_START t = time(NULL); (void)strftime(buf,max,s,localtime(&t)); BLOCK_SIGINT_END } #else void strftime_expand(const char *s, char *buf, long max) { strcpy(buf,s); } #endif /* name is a malloc'ed (existing) filename. Accept it as new pari_infile * (unzip if needed). */ static pariFILE * pari_get_infile(const char *name, FILE *file) { #ifdef ZCAT long l = strlen(name); const char *end = name + l-1; if (l > 2 && (!strncmp(end-1,".Z",2) #ifdef GNUZCAT || !strncmp(end-2,".gz",3) #endif )) { /* compressed file (compress or gzip) */ char *cmd = stack_malloc(strlen(ZCAT) + l + 4); sprintf(cmd,"%s \"%s\"",ZCAT,name); fclose(file); return try_pipe(cmd, mf_IN); } #endif return newfile(file, name, mf_IN); } pariFILE * pari_fopengz(const char *s) { pari_sp av = avma; char *name; long l; FILE *f = fopen(s, "r"); pariFILE *pf; if (f) return pari_get_infile(s, f); #ifdef __EMSCRIPTEN__ if (pari_is_dir(pari_datadir)) pari_emscripten_wget(s); #endif l = strlen(s); name = stack_malloc(l + 3 + 1); strcpy(name, s); (void)sprintf(name + l, ".gz"); f = fopen(name, "r"); pf = f ? pari_get_infile(name, f): NULL; avma = av; return pf; } static FILE* try_open(char *s) { if (!pari_is_dir(s)) return fopen(s, "r"); pari_warn(warner,"skipping directory %s",s); return NULL; } void forpath_init(forpath_t *T, gp_path *path, const char *s) { T->s = s; T->ls = strlen(s); T->dir = path->dirs; } char * forpath_next(forpath_t *T) { char *t, *dir = T->dir[0]; if (!dir) return NULL; /* done */ /* room for dir + '/' + s + '\0' */ t = (char*)pari_malloc(strlen(dir) + T->ls + 2); sprintf(t,"%s/%s", dir, T->s); T->dir++; return t; } /* If a file called "name" exists (possibly after appending ".gp") * record it in the file_stack (as a pipe if compressed). * name is malloc'ed, we free it before returning */ static FILE * try_name(char *name) { pari_sp av = avma; char *s = name; FILE *file = try_open(name); if (!file) { /* try appending ".gp" to name */ s = stack_malloc(strlen(name)+4); sprintf(s, "%s.gp", name); file = try_open(s); } if (file) { if (! last_tmp_file) { /* empty file stack, record this name */ if (last_filename) pari_free(last_filename); last_filename = pari_strdup(s); } file = pari_infile = pari_get_infile(s,file)->file; } pari_free(name); avma = av; return file; } static FILE * switchin_last(void) { char *s = last_filename; FILE *file; if (!s) pari_err(e_MISC,"You never gave me anything to read!"); file = try_open(s); if (!file) pari_err_FILE("input file",s); return pari_infile = pari_get_infile(s,file)->file; } /* return 1 if s starts by '/' or './' or '../' */ static int path_is_absolute(char *s) { #ifdef _WIN32 if( (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') ) { return *(s+1) == ':'; } #endif if (*s == '/') return 1; if (*s++ != '.') return 0; if (*s == '/') return 1; if (*s++ != '.') return 0; return *s == '/'; } /* If name = "", re-read last file */ FILE * switchin(const char *name) { FILE *f; char *s; if (!*name) return switchin_last(); s = path_expand(name); /* if s is an absolute path, don't use dir_list */ if (path_is_absolute(s)) { if ((f = try_name(s))) return f; } else { char *t; forpath_t T; forpath_init(&T, GP_DATA->path, s); while ( (t = forpath_next(&T)) ) if ((f = try_name(t))) { pari_free(s); return f; } pari_free(s); } pari_err_FILE("input file",name); return NULL; /*LCOV_EXCL_LINE*/ } static int is_magic_ok(FILE *f); static FILE * switchout_get_FILE(const char *name) { FILE* f; /* only for ordinary files (to avoid blocking on pipes). */ if (pari_is_file(name)) { f = fopen(name, "r"); if (f) { int magic = is_magic_ok(f); fclose(f); if (magic) pari_err_FILE("binary output file [ use writebin ! ]", name); } } f = fopen(name, "a"); if (!f) pari_err_FILE("output file",name); return f; } void switchout(const char *name) { if (name) pari_outfile = switchout_get_FILE(name); else if (pari_outfile != stdout) { fclose(pari_outfile); pari_outfile = stdout; } } /*******************************************************************/ /** **/ /** SYSTEM, READSTR/EXTERNSTR/EXTERN **/ /** **/ /*******************************************************************/ static void check_secure(const char *s) { if (GP_DATA->secure) pari_err(e_MISC, "[secure mode]: system commands not allowed\nTried to run '%s'",s); } void gpsystem(const char *s) { #ifdef HAS_SYSTEM check_secure(s); if (system(s) < 0) pari_err(e_MISC, "system(\"%s\") failed", s); #else pari_err(e_ARCH,"system"); #endif } static GEN get_lines(FILE *F) { pari_sp av = avma; long i, nz = 16; GEN z = cgetg(nz + 1, t_VEC); Buffer *b = new_buffer(); input_method IM; IM.fgets = (fgets_t)&fgets; IM.file = (void*)F; for(i = 1;;) { char *s = b->buf, *e; if (!file_getline(b, &s, &IM)) break; if (i > nz) { nz <<= 1; z = vec_lengthen(z, nz); } e = s + strlen(s)-1; if (*e == '\n') *e = 0; gel(z,i++) = strtoGENstr(s); } delete_buffer(b); setlg(z, i); return gerepilecopy(av, z); } GEN externstr(const char *s) { pariFILE *F; GEN z; check_secure(s); F = try_pipe(s, mf_IN); z = get_lines(F->file); pari_fclose(F); return z; } GEN gpextern(const char *s) { pariFILE *F; GEN z; check_secure(s); F = try_pipe(s, mf_IN); z = gp_read_stream(F->file); pari_fclose(F); return z; } GEN readstr(const char *s) { GEN z = get_lines(switchin(s)); popinfile(); return z; } /*******************************************************************/ /** **/ /** I/O IN BINARY FORM **/ /** **/ /*******************************************************************/ static void pari_fread_longs(void *a, size_t c, FILE *d) { if (fread(a,sizeof(long),c,d) < c) pari_err_FILE("input file [fread]", "FILE*"); } static void _fwrite(const void *a, size_t b, size_t c, FILE *d) { if (fwrite(a,b,c,d) < c) pari_err_FILE("output file [fwrite]", "FILE*"); } static void _lfwrite(const void *a, size_t b, FILE *c) { _fwrite(a,sizeof(long),b,c); } static void _cfwrite(const void *a, size_t b, FILE *c) { _fwrite(a,sizeof(char),b,c); } enum { BIN_GEN, NAM_GEN, VAR_GEN, RELINK_TABLE }; static long rd_long(FILE *f) { long L; pari_fread_longs(&L, 1UL, f); return L; } static void wr_long(long L, FILE *f) { _lfwrite(&L, 1UL, f); } /* append x to file f */ static void wrGEN(GEN x, FILE *f) { GENbin *p = copy_bin_canon(x); size_t L = p->len; wr_long(L,f); if (L) { wr_long((long)p->x,f); wr_long((long)p->base,f); _lfwrite(GENbinbase(p), L,f); } pari_free((void*)p); } static void wrstr(const char *s, FILE *f) { size_t L = strlen(s)+1; wr_long(L,f); _cfwrite(s, L, f); } static char * rdstr(FILE *f) { size_t L = (size_t)rd_long(f); char *s; if (!L) return NULL; s = (char*)pari_malloc(L); pari_fread_chars(s, L, f); return s; } static void writeGEN(GEN x, FILE *f) { fputc(BIN_GEN,f); wrGEN(x, f); } static void writenamedGEN(GEN x, const char *s, FILE *f) { fputc(x ? NAM_GEN : VAR_GEN,f); wrstr(s, f); if (x) wrGEN(x, f); } /* read a GEN from file f */ static GEN rdGEN(FILE *f) { size_t L = (size_t)rd_long(f); GENbin *p; if (!L) return gen_0; p = (GENbin*)pari_malloc(sizeof(GENbin) + L*sizeof(long)); p->len = L; p->x = (GEN)rd_long(f); p->base = (GEN)rd_long(f); p->rebase = &shiftaddress_canon; pari_fread_longs(GENbinbase(p), L,f); return bin_copy(p); } /* read a binary object in file f. Set *ptc to the object "type": * BIN_GEN: an anonymous GEN x; return x. * NAM_GEN: a named GEN x, with name v; set 'v to x (changevalue) and return x * VAR_GEN: a name v; create the (unassigned) variable v and return gnil * RELINK_TABLE: a relinking table for gen_relink(), to replace old adresses * in * the original session by new incarnations in the current session. * H is the current relinking table * */ static GEN readobj(FILE *f, int *ptc, hashtable *H) { int c = fgetc(f); GEN x = NULL; switch(c) { case BIN_GEN: x = rdGEN(f); if (H) gen_relink(x, H); break; case NAM_GEN: case VAR_GEN: { char *s = rdstr(f); if (!s) pari_err(e_MISC,"malformed binary file (no name)"); if (c == NAM_GEN) { x = rdGEN(f); if (H) gen_relink(x, H); err_printf("setting %s\n",s); changevalue(varentries[fetch_user_var(s)], x); } else { pari_var_create(fetch_entry(s)); x = gnil; } break; } case RELINK_TABLE: x = rdGEN(f); break; case EOF: break; default: pari_err(e_MISC,"unknown code in readobj"); } *ptc = c; return x; } #define MAGIC "\020\001\022\011-\007\020" /* ^P^A^R^I-^G^P */ #ifdef LONG_IS_64BIT # define ENDIAN_CHECK 0x0102030405060708L #else # define ENDIAN_CHECK 0x01020304L #endif static const long BINARY_VERSION = 1; /* since 2.2.9 */ static int is_magic_ok(FILE *f) { pari_sp av = avma; size_t L = strlen(MAGIC); char *s = stack_malloc(L); int r = (fread(s,1,L, f) == L && strncmp(s,MAGIC,L) == 0); avma = av; return r; } static int is_sizeoflong_ok(FILE *f) { char c; return (fread(&c,1,1, f) == 1 && c == (char)sizeof(long)); } static int is_long_ok(FILE *f, long L) { long c; return (fread(&c,sizeof(long),1, f) == 1 && c == L); } /* return 1 if valid binary file */ static int check_magic(const char *name, FILE *f) { if (!is_magic_ok(f)) pari_warn(warner, "%s is not a GP binary file",name); else if (!is_sizeoflong_ok(f)) pari_warn(warner, "%s not written for a %ld bit architecture", name, sizeof(long)*8); else if (!is_long_ok(f, ENDIAN_CHECK)) pari_warn(warner, "unexpected endianness in %s",name); else if (!is_long_ok(f, BINARY_VERSION)) pari_warn(warner, "%s written by an incompatible version of GP",name); else return 1; return 0; } static void write_magic(FILE *f) { fprintf(f, MAGIC); fprintf(f, "%c", (char)sizeof(long)); wr_long(ENDIAN_CHECK, f); wr_long(BINARY_VERSION, f); } int file_is_binary(FILE *f) { int r, c = fgetc(f); ungetc(c,f); r = (c != EOF && isprint(c) == 0 && isspace(c) == 0); #ifdef _WIN32 if (r) { setmode(fileno(f), _O_BINARY); rewind(f); } #endif return r; } void writebin(const char *name, GEN x) { FILE *f = fopen(name,"rb"); pari_sp av = avma; GEN V; int already = f? 1: 0; if (f) { int ok = check_magic(name,f); fclose(f); if (!ok) pari_err_FILE("binary output file",name); } f = fopen(name,"ab"); if (!f) pari_err_FILE("binary output file",name); if (!already) write_magic(f); V = copybin_unlink(x); if (lg(gel(V,1)) > 1) { fputc(RELINK_TABLE,f); wrGEN(V, f); } if (x) writeGEN(x,f); else { long v, maxv = pari_var_next(); for (v=0; vvalue,ep->name,f); } } avma = av; fclose(f); } /* read all objects in f. If f contains BIN_GEN that would be silently ignored * [i.e f contains more than one objet, not all of them 'named GENs'], return * them all in a vector and set 'vector'. */ GEN readbin(const char *name, FILE *f, int *vector) { pari_sp av = avma; hashtable *H = NULL; pari_stack s_obj; GEN obj, x, y; int cy; if (vector) *vector = 0; if (!check_magic(name,f)) return NULL; pari_stack_init(&s_obj, sizeof(GEN), (void**)&obj); /* HACK: push codeword so as to be able to treat s_obj.data as a t_VEC */ pari_stack_pushp(&s_obj, (void*) (evaltyp(t_VEC)|evallg(1))); x = gnil; while ((y = readobj(f, &cy, H))) { x = y; switch(cy) { case BIN_GEN: pari_stack_pushp(&s_obj, (void*)y); break; case RELINK_TABLE: if (H) hash_destroy(H); H = hash_from_link(gel(y,1),gel(y,2), 0); } } if (H) hash_destroy(H); switch(s_obj.n) /* >= 1 */ { case 1: break; /* nothing but the codeword */ case 2: x = gel(obj,1); break; /* read a single BIN_GEN */ default: /* more than one BIN_GEN */ setlg(obj, s_obj.n); if (DEBUGLEVEL) pari_warn(warner,"%ld unnamed objects read. Returning then in a vector", s_obj.n - 1); x = gerepilecopy(av, obj); if (vector) *vector = 1; } pari_stack_delete(&s_obj); return x; } /*******************************************************************/ /** **/ /** GP I/O **/ /** **/ /*******************************************************************/ /* print a vector of GENs, in output context 'out', using 'sep' as a * separator between sucessive entries [ NULL = no separator ]*/ void out_print0(PariOUT *out, const char *sep, GEN g, long flag) { pari_sp av = avma; OUT_FUN f = get_fun(flag); long i, l = lg(g); for (i = 1; i < l; i++, avma = av) { out_puts(out, stack_GENtostr_fun_unquoted(gel(g,i), GP_DATA->fmt, f)); if (sep && i+1 < l) out_puts(out, sep); } } static void str_print0(pari_str *S, GEN g, long flag) { pari_sp av = avma; OUT_FUN f = get_fun(flag); long i, l = lg(g); for (i = 1; i < l; i++) { GEN x = gel(g,i); if (typ(x) == t_STR) str_puts(S, GSTR(x)); else f(x, GP_DATA->fmt, S); if (!S->use_stack) avma = av; } *(S->cur) = 0; } /* see print0(). Returns pari_malloc()ed string */ char * RgV_to_str(GEN g, long flag) { pari_str S; str_init(&S,0); str_print0(&S, g, flag); return S.string; } static GEN Str_fun(GEN g, long flag) { char *t = RgV_to_str(g, flag); GEN z = strtoGENstr(t); pari_free(t); return z; } GEN Str(GEN g) { return Str_fun(g, f_RAW); } GEN Strtex(GEN g) { return Str_fun(g, f_TEX); } GEN Strexpand(GEN g) { char *s = RgV_to_str(g, f_RAW), *t = path_expand(s); GEN z = strtoGENstr(t); pari_free(t); pari_free(s); return z; } /* display s, followed by the element of g */ char * pari_sprint0(const char *s, GEN g, long flag) { pari_str S; str_init(&S, 0); str_puts(&S, s); str_print0(&S, g, flag); return S.string; } static void print0_file(FILE *out, GEN g, long flag) { pari_sp av = avma; pari_str S; str_init(&S, 1); str_print0(&S, g, flag); fputs(S.string, out); avma = av; } void print0(GEN g, long flag) { out_print0(pariOut, NULL, g, flag); } void printsep(const char *s, GEN g) { out_print0(pariOut, s, g, f_RAW); pari_putc('\n'); pari_flush(); } void printsep1(const char *s, GEN g) { out_print0(pariOut, s, g, f_RAW); pari_flush(); } static char * sm_dopr(const char *fmt, GEN arg_vector, va_list args) { pari_str s; str_init(&s, 0); str_arg_vprintf(&s, fmt, arg_vector, args); return s.string; } char * pari_vsprintf(const char *fmt, va_list ap) { return sm_dopr(fmt, NULL, ap); } /* dummy needed to pass an empty va_list to sm_dopr */ static char * dopr_arg_vector(GEN arg_vector, const char* fmt, ...) { va_list ap; char *s; va_start(ap, fmt); s = sm_dopr(fmt, arg_vector, ap); va_end(ap); return s; } /* GP only */ void printf0(const char *fmt, GEN args) { char *s = dopr_arg_vector(args, fmt); pari_puts(s); pari_free(s); pari_flush(); } /* GP only */ GEN Strprintf(const char *fmt, GEN args) { char *s = dopr_arg_vector(args, fmt); GEN z = strtoGENstr(s); pari_free(s); return z; } void out_vprintf(PariOUT *out, const char *fmt, va_list ap) { char *s = pari_vsprintf(fmt, ap); out_puts(out, s); pari_free(s); } void pari_vprintf(const char *fmt, va_list ap) { out_vprintf(pariOut, fmt, ap); } void err_printf(const char* fmt, ...) { va_list args; va_start(args, fmt); out_vprintf(pariErr,fmt,args); va_end(args); } /* variadic version of printf0 */ void out_printf(PariOUT *out, const char *fmt, ...) { va_list args; va_start(args,fmt); out_vprintf(out,fmt,args); va_end(args); } void pari_printf(const char *fmt, ...) /* variadic version of printf0 */ { va_list args; va_start(args,fmt); pari_vprintf(fmt,args); va_end(args); } GEN gvsprintf(const char *fmt, va_list ap) { char *s = pari_vsprintf(fmt, ap); GEN z = strtoGENstr(s); pari_free(s); return z; } char * pari_sprintf(const char *fmt, ...) /* variadic version of Strprintf */ { char *s; va_list ap; va_start(ap, fmt); s = pari_vsprintf(fmt, ap); va_end(ap); return s; } void str_printf(pari_str *S, const char *fmt, ...) { va_list ap; va_start(ap, fmt); str_arg_vprintf(S, fmt, NULL, ap); va_end(ap); } char * stack_sprintf(const char *fmt, ...) { char *s, *t; va_list ap; va_start(ap, fmt); s = pari_vsprintf(fmt, ap); va_end(ap); t = stack_strdup(s); pari_free(s); return t; } GEN gsprintf(const char *fmt, ...) /* variadic version of gvsprintf */ { GEN s; va_list ap; va_start(ap, fmt); s = gvsprintf(fmt, ap); va_end(ap); return s; } /* variadic version of fprintf0. FIXME: fprintf0 not yet available */ void pari_vfprintf(FILE *file, const char *fmt, va_list ap) { char *s = pari_vsprintf(fmt, ap); fputs(s, file); pari_free(s); } void pari_fprintf(FILE *file, const char *fmt, ...) { va_list ap; va_start(ap, fmt); pari_vfprintf(file, fmt, ap); va_end(ap); } void print (GEN g) { print0(g, f_RAW); pari_putc('\n'); pari_flush(); } void printp (GEN g) { print0(g, f_PRETTYMAT); pari_putc('\n'); pari_flush(); } void printtex(GEN g) { print0(g, f_TEX); pari_putc('\n'); pari_flush(); } void print1 (GEN g) { print0(g, f_RAW); pari_flush(); } void error0(GEN g) { if (lg(g)==2 && typ(gel(g,1))==t_ERROR) pari_err(0, gel(g,1)); else pari_err(e_USER, g); } void warning0(GEN g) { pari_warn(warnuser, g); } static char * wr_check(const char *s) { char *t = path_expand(s); if (GP_DATA->secure) { char *msg = pari_sprintf("[secure mode]: about to write to '%s'",t); pari_ask_confirm(msg); pari_free(msg); } return t; } /* write to file s */ static void wr(const char *s, GEN g, long flag, int addnl) { char *t = wr_check(s); FILE *out = switchout_get_FILE(t); pari_free(t); print0_file(out, g, flag); if (addnl) fputc('\n', out); fflush(out); if (fclose(out)) pari_warn(warnfile, "close", t); } void write0 (const char *s, GEN g) { wr(s, g, f_RAW, 1); } void writetex(const char *s, GEN g) { wr(s, g, f_TEX, 1); } void write1 (const char *s, GEN g) { wr(s, g, f_RAW, 0); } void gpwritebin(const char *s, GEN x) { char *t=wr_check(s); writebin(t, x); pari_free(t);} /*******************************************************************/ /** **/ /** HISTORY HANDLING **/ /** **/ /*******************************************************************/ /* history management function: * p > 0, called from %p or %#p * p <= 0, called from %` or %#` (|p| backquotes, possibly 0) */ static gp_hist_cell * history(long p) { gp_hist *H = GP_DATA->hist; ulong t = H->total, s = H->size; gp_hist_cell *c; if (!t) pari_err(e_MISC,"The result history is empty"); if (p <= 0) p += t; /* count |p| entries starting from last */ if (p <= 0 || p <= (long)(t - s) || (ulong)p > t) { long pmin = (long)(t - s) + 1; if (pmin <= 0) pmin = 1; pari_err(e_MISC,"History result %%%ld not available [%%%ld-%%%lu]", p,pmin,t); } c = H->v + ((p-1) % s); if (!c->z) pari_err(e_MISC,"History result %%%ld has been deleted (histsize changed)", p); return c; } GEN pari_get_hist(long p) { return history(p)->z; } long pari_get_histtime(long p) { return history(p)->t; } void pari_add_hist(GEN x, long time) { gp_hist *H = GP_DATA->hist; ulong i = H->total % H->size; H->total++; if (H->v[i].z) gunclone(H->v[i].z); H->v[i].t = time; H->v[i].z = gclone(x); } ulong pari_nb_hist(void) { return GP_DATA->hist->total; } /*******************************************************************/ /** **/ /** TEMPORARY FILES **/ /** **/ /*******************************************************************/ #ifndef R_OK # define R_OK 4 # define W_OK 2 # define X_OK 1 # define F_OK 0 #endif #ifdef __EMX__ #include static int unix_shell(void) { char *base, *sh = getenv("EMXSHELL"); if (!sh) { sh = getenv("COMSPEC"); if (!sh) return 0; } base = _getname(sh); return (stricmp (base, "cmd.exe") && stricmp (base, "4os2.exe") && stricmp (base, "command.com") && stricmp (base, "4dos.com")); } #endif /* check if s has rwx permissions for us */ static int pari_is_rwx(const char *s) { /* FIXME: HAS_ACCESS */ #if defined(UNIX) || defined (__EMX__) return access(s, R_OK | W_OK | X_OK) == 0; #else (void) s; return 1; #endif } #if defined(UNIX) || defined (__EMX__) #include #include static int pari_file_exists(const char *s) { int id = open(s, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); return id < 0 || close(id); } static int pari_dir_exists(const char *s) { return mkdir(s, 0777); } #elif defined(_WIN32) static int pari_file_exists(const char *s) { return GetFileAttributesA(s) != ~0UL; } static int pari_dir_exists(const char *s) { return mkdir(s); } #else static int pari_file_exists(const char *s) { return 0; } static int pari_dir_exists(const char *s) { return 0; } #endif static char * env_ok(const char *s) { char *t = os_getenv(s); if (t && !pari_is_rwx(t)) { pari_warn(warner,"%s is set (%s), but is not writable", s,t); t = NULL; } if (t && !pari_is_dir(t)) { pari_warn(warner,"%s is set (%s), but is not a directory", s,t); t = NULL; } return t; } static const char* pari_tmp_dir(void) { char *s; s = env_ok("GPTMPDIR"); if (s) return s; s = env_ok("TMPDIR"); if (s) return s; #if defined(_WIN32) || defined(__EMX__) s = env_ok("TMP"); if (s) return s; s = env_ok("TEMP"); if (s) return s; #endif #if defined(UNIX) || defined(__EMX__) if (pari_is_rwx("/tmp")) return "/tmp"; if (pari_is_rwx("/var/tmp")) return "/var/tmp"; #endif return "."; } /* loop through 26^2 variants [suffix 'aa' to 'zz'] */ static int get_file(char *buf, int test(const char *), const char *suf) { char c, d, *end = buf + strlen(buf) - 1; if (suf) end -= strlen(suf); for (d = 'a'; d <= 'z'; d++) { end[-1] = d; for (c = 'a'; c <= 'z'; c++) { *end = c; if (! test(buf)) return 1; if (DEBUGFILES) err_printf("I/O: file %s exists!\n", buf); } } return 0; } #if defined(__EMX__) || defined(_WIN32) static void swap_slash(char *s) { #ifdef __EMX__ if (!unix_shell()) #endif { char *t; for (t=s; *t; t++) if (*t == '/') *t = '\\'; } } #endif /* s truncated to 8 chars, suf possibly NULL */ static char * init_unique(const char *s, const char *suf) { const char *pre = pari_tmp_dir(); char *buf, salt[64]; size_t lpre, lsalt, lsuf; #ifdef UNIX sprintf(salt,"-%ld-%ld", (long)getuid(), (long)getpid()); #else sprintf(salt,"-%ld", (long)time(NULL)); #endif lsuf = suf? strlen(suf): 0; lsalt = strlen(salt); lpre = strlen(pre); /* room for prefix + '/' + s + salt + suf + '\0' */ buf = (char*) pari_malloc(lpre + 1 + 8 + lsalt + lsuf + 1); strcpy(buf, pre); if (buf[lpre-1] != '/') { (void)strcat(buf, "/"); lpre++; } #if defined(__EMX__) || defined(_WIN32) swap_slash(buf); #endif sprintf(buf + lpre, "%.8s%s", s, salt); if (lsuf) strcat(buf, suf); if (DEBUGFILES) err_printf("I/O: prefix for unique file/dir = %s\n", buf); return buf; } /* Return a "unique filename" built from the string s, possibly the user id * and the process pid (on Unix systems). A "temporary" directory name is * prepended. The name returned is pari_malloc'ed. It is DOS-safe * (s truncated to 8 chars) */ char* pari_unique_filename_suffix(const char *s, const char *suf) { char *buf = init_unique(s, suf); if (pari_file_exists(buf) && !get_file(buf, pari_file_exists, suf)) pari_err(e_MISC,"couldn't find a suitable name for a tempfile (%s)",s); return buf; } char* pari_unique_filename(const char *s) { return pari_unique_filename_suffix(s, NULL); } /* Create a "unique directory" and return its name built from the string * s, the user id and process pid (on Unix systems). A "temporary" * directory name is prepended. The name returned is pari_malloc'ed. * It is DOS-safe (truncated to 8 chars) */ char* pari_unique_dir(const char *s) { char *buf = init_unique(s, NULL); if (pari_dir_exists(buf) && !get_file(buf, pari_dir_exists, NULL)) pari_err(e_MISC,"couldn't find a suitable name for a tempdir (%s)",s); return buf; } static long get_free_gp_file(void) { long i, l = s_gp_file.n; for (i=0; i= s_gp_file.n || !gp_file[n].fp) pari_err_FILEDESC(s, n); } static long new_gp_file(const char *s, FILE *f, int t) { long n; n = get_free_gp_file(); gp_file[n].name = pari_strdup(s); gp_file[n].fp = f; gp_file[n].type = t; gp_file[n].serial = gp_file_serial++; if (DEBUGFILES) err_printf("fileopen:%ld (%ld)\n", n, gp_file[n].serial); return n; } #if defined(ZCAT) && defined(HAVE_PIPES) static long check_compress(const char *name) { long l = strlen(name); const char *end = name + l-1; if (l > 2 && (!strncmp(end-1,".Z",2) #ifdef GNUZCAT || !strncmp(end-2,".gz",3) #endif )) { /* compressed file (compress or gzip) */ char *cmd = stack_malloc(strlen(ZCAT) + l + 4); sprintf(cmd,"%s \"%s\"",ZCAT,name); return gp_fileextern(cmd); } return -1; } #endif long gp_fileopen(char *s, char *mode) { FILE *f; if (mode[0]==0 || mode[1]!=0) pari_err_TYPE("fileopen",strtoGENstr(mode)); switch (mode[0]) { case 'r': #if defined(ZCAT) && defined(HAVE_PIPES) { long n = check_compress(s); if (n >= 0) return n; } #endif f = fopen(s, "r"); if (!f) pari_err_FILE("requested file", s); return new_gp_file(s, f, mf_IN); case 'w': case 'a': f = fopen(s, mode[0]=='w' ? "w": "a"); if (!f) pari_err_FILE("requested file", s); return new_gp_file(s, f, mf_OUT); default: pari_err_TYPE("fileopen",strtoGENstr(mode)); return -1; /* LCOV_EXCL_LINE */ } } long gp_fileextern(char *s) { #ifndef HAVE_PIPES pari_err(e_ARCH,"pipes"); return NULL; #else FILE *f; check_secure(s); f = popen(s, "r"); if (!f) pari_err(e_MISC,"[pipe:] '%s' failed",s); return new_gp_file(s,f, mf_PIPE); #endif } void gp_fileclose(long n) { check_gp_file("fileclose", n); if (DEBUGFILES) err_printf("fileclose(%ld)\n",n); if (gp_file[n].type == mf_PIPE) pclose(gp_file[n].fp); else fclose(gp_file[n].fp); pari_free((void*)gp_file[n].name); gp_file[n].name = NULL; gp_file[n].fp = NULL; gp_file[n].type = mf_FALSE; gp_file[n].serial = -1; while (s_gp_file.n > 0 && !gp_file[s_gp_file.n-1].fp) s_gp_file.n--; } void gp_fileflush(long n) { check_gp_file("fileflush", n); if (DEBUGFILES) err_printf("fileflush(%ld)\n",n); if (gp_file[n].type == mf_OUT) (void)fflush(gp_file[n].fp); } void gp_fileflush0(GEN gn) { long i; if (gn) { if (typ(gn) != t_INT) pari_err_TYPE("fileflush",gn); gp_fileflush(itos(gn)); } else for (i = 0; i < s_gp_file.n; i++) if (gp_file[i].fp && gp_file[i].type == mf_OUT) gp_fileflush(i); } GEN gp_fileread(long n) { Buffer *b; FILE *fp; GEN z; int t; check_gp_file("fileread", n); t = gp_file[n].type; if (t!=mf_IN && t!=mf_PIPE) pari_err_FILEDESC("fileread",n); fp = gp_file[n].fp; b = new_buffer(); while(1) { if (!gp_read_stream_buf(fp, b)) { delete_buffer(b); return gen_0; } if (*(b->buf)) break; } z = strtoGENstr(b->buf); delete_buffer(b); return z; } void gp_filewrite(long n, const char *s) { FILE *fp; check_gp_file("filewrite", n); if (gp_file[n].type!=mf_OUT) pari_err_FILEDESC("filewrite",n); fp = gp_file[n].fp; fputs(s, fp); fputc('\n',fp); } void gp_filewrite1(long n, const char *s) { FILE *fp; check_gp_file("filewrite1", n); if (gp_file[n].type!=mf_OUT) pari_err_FILEDESC("filewrite1",n); fp = gp_file[n].fp; fputs(s, fp); } GEN gp_filereadstr(long n) { Buffer *b; char *s, *e; GEN z; int t; input_method IM; check_gp_file("filereadstr", n); t = gp_file[n].type; if (t!=mf_IN && t!=mf_PIPE) pari_err_FILEDESC("fileread",n); b = new_buffer(); IM.fgets = (fgets_t)&fgets; IM.file = (void*) gp_file[n].fp; s = b->buf; if (!file_getline(b, &s, &IM)) { delete_buffer(b); return gen_0; } e = s + strlen(s)-1; if (*e == '\n') *e = 0; z = strtoGENstr(s); delete_buffer(b); return z; } /*******************************************************************/ /** **/ /** INSTALL **/ /** **/ /*******************************************************************/ #ifdef HAS_DLOPEN #include /* see try_name() */ static void * try_dlopen(const char *s, int flag) { void *h = dlopen(s, flag); pari_free((void*)s); return h; } /* like dlopen, but using default(sopath) */ static void * gp_dlopen(const char *name, int flag) { void *handle; char *s; if (!name) return dlopen(NULL, flag); s = path_expand(name); /* if sopath empty or path is absolute, use dlopen */ if (!GP_DATA || *(GP_DATA->sopath->PATH)==0 || path_is_absolute(s)) return try_dlopen(s, flag); else { forpath_t T; char *t; forpath_init(&T, GP_DATA->sopath, s); while ( (t = forpath_next(&T)) ) { if ( (handle = try_dlopen(t,flag)) ) { pari_free(s); return handle; } (void)dlerror(); /* clear error message */ } pari_free(s); } return NULL; } static void * install0(const char *name, const char *lib) { void *handle; #ifndef RTLD_GLOBAL /* OSF1 has dlopen but not RTLD_GLOBAL*/ # define RTLD_GLOBAL 0 #endif handle = gp_dlopen(lib, RTLD_LAZY|RTLD_GLOBAL); if (!handle) { const char *s = dlerror(); if (s) err_printf("%s\n\n",s); if (lib) pari_err(e_MISC,"couldn't open dynamic library '%s'",lib); pari_err(e_MISC,"couldn't open dynamic symbol table of process"); } return dlsym(handle, name); } #else # ifdef _WIN32 static HMODULE try_LoadLibrary(const char *s) { void *h = LoadLibrary(s); pari_free((void*)s); return h; } /* like LoadLibrary, but using default(sopath) */ static HMODULE gp_LoadLibrary(const char *name) { HMODULE handle; char *s = path_expand(name); /* if sopath empty or path is absolute, use LoadLibrary */ if (!GP_DATA || *(GP_DATA->sopath->PATH)==0 || path_is_absolute(s)) return try_LoadLibrary(s); else { forpath_t T; char *t; forpath_init(&T, GP_DATA->sopath, s); while ( (t = forpath_next(&T)) ) if ( (handle = try_LoadLibrary(t)) ) { pari_free(s); return handle; } pari_free(s); } return NULL; } static void * install0(const char *name, const char *lib) { HMODULE handle; handle = gp_LoadLibrary(lib); if (!handle) { if (lib) pari_err(e_MISC,"couldn't open dynamic library '%s'",lib); pari_err(e_MISC,"couldn't open dynamic symbol table of process"); } return (void *) GetProcAddress(handle,name); } # else static void * install0(const char *name, const char *lib) { pari_err(e_ARCH,"install"); return NULL; } #endif #endif static char * dft_help(const char *gp, const char *s, const char *code) { return stack_sprintf("%s: installed function\nlibrary name: %s\nprototype: %s" , gp, s, code); } void gpinstall(const char *s, const char *code, const char *gpname, const char *lib) { pari_sp av = avma; const char *gp = *gpname? gpname: s; int update_help; void *f; entree *ep; if (GP_DATA->secure) { char *msg = pari_sprintf("[secure mode]: about to install '%s'", s); pari_ask_confirm(msg); pari_free(msg); } f = install0(s, *lib ?lib :pari_library_path); if (!f) { if (*lib) pari_err(e_MISC,"can't find symbol '%s' in library '%s'",s,lib); pari_err(e_MISC,"can't find symbol '%s' in dynamic symbol table of process",s); } ep = is_entry(gp); /* Delete help if 1) help is the default (don't delete user addhelp) * and 2) default help changes */ update_help = (ep && ep->valence == EpINSTALL && ep->help && strcmp(ep->code, code) && !strcmp(ep->help, dft_help(gp,s,ep->code))); ep = install(f,gp,code); if (update_help || !ep->help) addhelp(gp, dft_help(gp,s,code)); mt_broadcast(strtoclosure("install",4,strtoGENstr(s),strtoGENstr(code), strtoGENstr(gp),strtoGENstr(lib))); avma = av; } pari-2.11.2/src/language/anal.c0000644000175000017500000007240113326135265014621 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #include "anal.h" #include "parse.h" /*************************************************************************** ** ** ** Mnemonic codes parser ** ** ** ***************************************************************************/ /* TEMPLATE is assumed to be ";"-separated list of items. Each item * may have one of the following forms: id=value id==value id|value id&~value. * Each id consists of alphanum characters, dashes and underscores. * IDs are case-sensitive. * ARG consists of several IDs separated by punctuation (and optional * whitespace). Each modifies the return value in a "natural" way: an * ID from id=value should be the first in the sequence and sets RETVAL to * VALUE (and cannot be negated), ID from id|value bit-ORs RETVAL with * VALUE (and bit-ANDs RETVAL with ~VALUE if negated), ID from * id&~value behaves as if it were noid|value, ID from * id==value behaves the same as id=value, but should come alone. * For items of the form id|value and id&~value negated forms are * allowed: either when arg looks like no[-_]id, or when id looks like * this, and arg is not-negated. */ static int IS_ID(char c) { return isalnum((int)c) || c == '_'; } long eval_mnemonic(GEN str, const char *tmplate) { const char *arg, *etmplate; ulong retval = 0; if (typ(str)==t_INT) return itos(str); if (typ(str)!=t_STR) pari_err_TYPE("eval_mnemonic",str); arg = GSTR(str); etmplate = strchr(tmplate, '\n'); if (!etmplate) etmplate = tmplate + strlen(tmplate); while (1) { long numarg; const char *e, *id, *negated = NULL; int negate = 0; /* Arg has 'no' prefix removed */ ulong l; char *buf; static char b[80]; while (isspace((int)*arg)) arg++; if (!*arg) break; e = arg; while (IS_ID(*e)) e++; /* Now the ID is whatever is between arg and e. */ l = e - arg; if (l >= sizeof(b)) pari_err(e_MISC,"id too long in a mnemonic"); if (!l) pari_err(e_MISC,"mnemonic does not start with an id"); strncpy(b, arg, l); b[l] = 0; arg = e; e = buf = b; while ('0' <= *e && *e <= '9') e++; if (*e == 0) pari_err(e_MISC,"numeric id in a mnemonic"); FIND: id = tmplate; while ((id = strstr(id, buf)) && id < etmplate) { const char *s = id; id += l; if (s[l] != '|') continue; /* False positive */ if (s == tmplate || !IS_ID(s[-1])) break; /* Found as is */ /* If we found "no_ID", negate */ if (!negate && s >= tmplate+3 && (s == tmplate+3 || !IS_ID(s[-4])) && s[-3] == 'n' && s[-2] == 'o' && s[-1] == '_') { negated = id; break; } } if (!id && !negated && !negate && l > 3 && buf[0] == 'n' && buf[1] == 'o' && buf[2] == '_') { /* Try to find the flag without the prefix "no_". */ buf += 3; l -= 3; negate = 1; if (buf[0]) goto FIND; } /* Negated and AS_IS forms, prefer AS_IS otherwise use negated form */ if (!id) { if (!negated) pari_err(e_MISC,"Unrecognized id '%s' in mnemonic", b); id = negated; negate = 1; } if (*id++ != '|') pari_err(e_MISC,"Missing | in mnemonic template"); e = id; while (*e >= '0' && *e <= '9') e++; while (isspace((int)*e)) e++; if (*e && *e != ';' && *e != ',') pari_err(e_MISC, "Non-numeric argument in mnemonic template"); numarg = atol(id); if (negate) retval &= ~numarg; else retval |= numarg; while (isspace((int)*arg)) arg++; if (*arg && !ispunct((int)*arg++)) /* skip punctuation */ pari_err(e_MISC,"Junk after id in mnemonic"); } return retval; } /********************************************************************/ /** **/ /** HASH TABLE MANIPULATIONS **/ /** **/ /********************************************************************/ /* return hashing value for identifier s */ static ulong hashvalue(const char *s) { ulong n = 0, c; while ( (c = (ulong)*s++) ) n = (n<<1) ^ c; return n; } static ulong hashvalue_raw(const char *s, long len) { long n = 0, i; for(i=0; ihash = hash; hash %= functions_tblsz; ep->next = table[hash]; table[hash] = ep; } static entree * initep(const char *name, long len) { const long add = 4*sizeof(long); entree *ep = (entree *) pari_calloc(sizeof(entree) + add + len+1); entree *ep1 = initial_value(ep); char *u = (char *) ep1 + add; ep->name = u; memcpy(u, name,len); u[len]=0; ep->valence = EpNEW; ep->value = NULL; ep->menu = 0; ep->code = NULL; ep->help = NULL; ep->pvalue = NULL; ep->arity = 0; return ep; } /* Look for s of length len in T; if 'insert', insert if missing */ static entree * findentry(const char *s, long len, entree **T, int insert) { ulong hash = hashvalue_raw(s, len); entree *ep; for (ep = T[hash % functions_tblsz]; ep; ep = ep->next) if (ep->hash == hash) { const char *t = ep->name; if (!strncmp(t, s, len) && !t[len]) return ep; } /* not found */ if (insert) { ep = initep(s,len); insertep(ep, T, hash); } return ep; } entree * pari_is_default(const char *s) { return findentry(s, strlen(s), defaults_hash, 0); } entree * is_entry(const char *s) { return findentry(s, strlen(s), functions_hash, 0); } entree * fetch_entry_raw(const char *s, long len) { return findentry(s, len, functions_hash, 1); } entree * fetch_entry(const char *s) { return fetch_entry_raw(s, strlen(s)); } /*******************************************************************/ /* */ /* SYNTACTICAL ANALYZER FOR GP */ /* */ /*******************************************************************/ GEN readseq(char *t) { pari_sp av = avma; GEN x; if (gp_meta(t,0)) return gnil; x = pari_compile_str(t); return gerepileupto(av, closure_evalres(x)); } /* filtered readseq = remove blanks and comments */ GEN gp_read_str(const char *s) { char *t = gp_filter(s); GEN x = readseq(t); pari_free(t); return x; } GEN compile_str(const char *s) { char *t = gp_filter(s); GEN x = pari_compile_str(t); pari_free(t); return x; } static long check_proto(const char *code) { long arity = 0; const char *s = code, *old; if (*s == 'l' || *s == 'v' || *s == 'i' || *s == 'm' || *s == 'u') s++; while (*s && *s != '\n') switch (*s++) { case '&': case 'C': case 'G': case 'I': case 'J': case 'U': case 'L': case 'M': case 'P': case 'W': case 'f': case 'n': case 'p': case 'b': case 'r': arity++; break; case 'E': case 's': if (*s == '*') s++; arity++; break; case 'D': if (*s == 'G' || *s == '&' || *s == 'n' || *s == 'I' || *s == 'E' || *s == 'V' || *s == 'P' || *s == 's' || *s == 'r') { if (*s != 'V') arity++; s++; break; } old = s; while (*s && *s != ',') s++; if (*s != ',') pari_err(e_SYNTAX, "missing comma", old, code); break; case 'V': case '=': case ',': break; case '\n': break; /* Before the mnemonic */ case 'm': case 'l': case 'i': case 'v': pari_err(e_SYNTAX, "this code has to come first", s-1, code); default: pari_err(e_SYNTAX, "unknown parser code", s-1, code); } if (arity > 20) pari_err_IMPL("functions with more than 20 parameters"); return arity; } static void check_name(const char *name) { const char *s = name; if (isalpha((int)*s)) while (is_keyword_char(*++s)) /* empty */; if (*s) pari_err(e_SYNTAX,"not a valid identifier", s, name); } entree * install(void *f, const char *name, const char *code) { long arity = check_proto(code); entree *ep; check_name(name); ep = fetch_entry(name); if (ep->valence != EpNEW) { if (ep->valence != EpINSTALL) pari_err(e_MISC,"[install] identifier '%s' already in use", name); pari_warn(warner, "[install] updating '%s' prototype; module not reloaded", name); if (ep->code) pari_free((void*)ep->code); } else { ep->value = f; ep->valence = EpINSTALL; } ep->code = pari_strdup(code); ep->arity = arity; return ep; } static void killep(entree *ep) { GEN p = (GEN)initial_value(ep); freeep(ep); *p = 0; /* otherwise pari_var_create won't regenerate it */ ep->valence = EpNEW; ep->value = NULL; ep->pvalue = NULL; } /* Kill ep, i.e free all memory it references, and reset to initial value */ void kill0(const char *e) { entree *ep = is_entry(e); if (!ep || EpSTATIC(ep)) pari_err(e_MISC,"can't kill that"); killep(ep); } void addhelp(const char *e, char *s) { entree *ep = fetch_entry(e); void *f = (void *) ep->help; ep->help = pari_strdup(s); if (f && !EpSTATIC(ep)) pari_free(f); } GEN type0(GEN x) { const char *s = type_name(typ(x)); return strtoGENstr(s); } /*******************************************************************/ /* */ /* PARSER */ /* */ /*******************************************************************/ #ifdef LONG_IS_64BIT static const long MAX_DIGITS = 19; #else static const long MAX_DIGITS = 9; #endif static const long MAX_XDIGITS = BITS_IN_LONG>>2; static const long MAX_BDIGITS = BITS_IN_LONG; static int ishex(const char **s) { if (**s == '0' && ((*s)[1] == 'x' || (*s)[1] == 'X' )) { *s += 2; return 1; } else return 0; } static int isbin(const char **s) { if (**s == '0' && ((*s)[1] == 'b' || (*s)[1] == 'B' )) { *s += 2; return 1; } else return 0; } static ulong bin_number_len(const char *s, long n) { ulong m = 0; long i; for (i = 0; i < n; i++,s++) m = 2*m + (*s - '0'); return m; } static int pari_isbdigit(int c) { return c=='0' || c=='1'; } static ulong hex_number_len(const char *s, long n) { ulong m = 0; long i; for(i = 0; i < n; i++, s++) { ulong c; if( *s >= '0' && *s <= '9') c = *s - '0'; else if( *s >= 'A' && *s <= 'F') c = *s - 'A' + 10; else c = *s - 'a' + 10; m = 16*m + c; } return m; } static GEN strtobin_len(const char *s, long n, long B, ulong num(const char *s, long n)) { long i, l = (n+B-1)/B; GEN N, Np; N = cgetipos(l+2); Np = int_LSW(N); for (i=1; i 0)? (long)(n/LOG10_2): (long)-((-n)/LOG10_2 + 1); return real_0_bit(b); } static GEN real_read(pari_sp av, const char **s, GEN y, long prec) { long l, n = 0; switch(**s) { default: return y; /* integer */ case '.': { const char *old = ++*s; if (isalpha((int)**s) || **s=='.') { if (**s == 'E' || **s == 'e') { n = exponent(s); if (!signe(y)) { avma = av; return real_0_digits(n); } break; } --*s; return y; /* member */ } if (isdigit((int)**s)) y = real_read_more(y, s); n = old - *s; if (**s != 'E' && **s != 'e') { if (!signe(y)) { avma = av; return real_0(prec); } break; } } /* Fall through */ case 'E': case 'e': n += exponent(s); if (!signe(y)) { avma = av; return real_0_digits(n); } } l = nbits2prec(bit_accuracy(lgefint(y))); if (l < prec) l = prec; else prec = l; if (!n) return itor(y, prec); incrprec(l); y = itor(y, l); if (n > 0) y = mulrr(y, rpowuu(10UL, (ulong)n, l)); else y = divrr(y, rpowuu(10UL, (ulong)-n, l)); return gerepileuptoleaf(av, rtor(y, prec)); } static GEN int_read(const char **s) { GEN y; if (isbin(s)) y = bin_read(s); else if (ishex(s)) y = hex_read(s); else y = dec_read(s); return y; } GEN strtoi(const char *s) { return int_read(&s); } GEN strtor(const char *s, long prec) { pari_sp av = avma; GEN y = dec_read(&s); y = real_read(av, &s, y, prec); if (typ(y) == t_REAL) return y; return gerepileuptoleaf(av, itor(y, prec)); } static void skipdigits(char **lex) { while (isdigit((int)**lex)) ++*lex; } static int skipexponent(char **lex) { char *old=*lex; if ((**lex=='e' || **lex=='E')) { ++*lex; if ( **lex=='+' || **lex=='-' ) ++*lex; if (!isdigit((int)**lex)) { *lex=old; return KINTEGER; } skipdigits(lex); return KREAL; } return KINTEGER; } static int skipconstante(char **lex) { skipdigits(lex); if (**lex=='.') { char *old = ++*lex; if (**lex == '.') { --*lex; return KINTEGER; } if (isalpha((int)**lex)) { skipexponent(lex); if (*lex == old) { --*lex; /* member */ return KINTEGER; } return KREAL; } skipdigits(lex); skipexponent(lex); return KREAL; } return skipexponent(lex); } static void skipstring(char **lex) { while (**lex) { while (**lex == '\\') *lex+=2; if (**lex == '"') { if ((*lex)[1] != '"') break; *lex += 2; continue; } (*lex)++; } } int pari_lex(union token_value *yylval, struct node_loc *yylloc, char **lex) { (void) yylval; yylloc->start=*lex; if (!**lex) { yylloc->end=*lex; return 0; } if (isalpha((int)**lex)) { while (is_keyword_char(**lex)) ++*lex; yylloc->end=*lex; return KENTRY; } if (**lex=='"') { ++*lex; skipstring(lex); if (!**lex) compile_err("run-away string",*lex-1); ++*lex; yylloc->end=*lex; return KSTRING; } if (**lex == '.') { int token; if ((*lex)[1]== '.') { *lex+=2; yylloc->end = *lex; return KDOTDOT; } token=skipconstante(lex); if (token==KREAL) { yylloc->end = *lex; return token; } ++*lex; yylloc->end=*lex; return '.'; } if (isbin((const char**)lex)) { while (**lex=='0' || **lex=='1') ++*lex; return KINTEGER; } if (ishex((const char**)lex)) { while (isxdigit((int)**lex)) ++*lex; return KINTEGER; } if (isdigit((int)**lex)) { int token=skipconstante(lex); yylloc->end = *lex; return token; } if ((*lex)[1]=='=') switch (**lex) { case '=': if ((*lex)[2]=='=') { *lex+=3; yylloc->end = *lex; return KID; } else { *lex+=2; yylloc->end = *lex; return KEQ; } case '>': *lex+=2; yylloc->end = *lex; return KGE; case '<': *lex+=2; yylloc->end = *lex; return KLE; case '*': *lex+=2; yylloc->end = *lex; return KME; case '/': *lex+=2; yylloc->end = *lex; return KDE; case '%': if ((*lex)[2]=='=') break; *lex+=2; yylloc->end = *lex; return KMODE; case '!': if ((*lex)[2]=='=') break; *lex+=2; yylloc->end = *lex; return KNE; case '\\': *lex+=2; yylloc->end = *lex; return KEUCE; case '+': *lex+=2; yylloc->end = *lex; return KPE; case '-': *lex+=2; yylloc->end = *lex; return KSE; } if (**lex==')' && (*lex)[1]=='-' && (*lex)[2]=='>') { *lex+=3; yylloc->end = *lex; return KPARROW; } if (**lex=='-' && (*lex)[1]=='>') { *lex+=2; yylloc->end = *lex; return KARROW; } if (**lex=='<' && (*lex)[1]=='>') { *lex+=2; yylloc->end = *lex; return KNE; } if (**lex=='\\' && (*lex)[1]=='/') switch((*lex)[2]) { case '=': *lex+=3; yylloc->end = *lex; return KDRE; default: *lex+=2; yylloc->end = *lex; return KDR; } if ((*lex)[1]==**lex) switch (**lex) { case '&': *lex+=2; yylloc->end = *lex; return KAND; case '|': *lex+=2; yylloc->end = *lex; return KOR; case '+': *lex+=2; yylloc->end = *lex; return KPP; case '-': *lex+=2; yylloc->end = *lex; return KSS; case '>': if ((*lex)[2]=='=') { *lex+=3; yylloc->end = *lex; return KSRE;} *lex+=2; yylloc->end = *lex; return KSR; case '<': if ((*lex)[2]=='=') { *lex+=3; yylloc->end = *lex; return KSLE; } *lex+=2; yylloc->end = *lex; return KSL; } yylloc->end = *lex+1; return (unsigned char) *(*lex)++; } /********************************************************************/ /** **/ /** STRINGS **/ /** **/ /********************************************************************/ /* return the first n0 chars of s as a GEN [s may not be 0-terminated] */ GEN strntoGENstr(const char *s, long n0) { long n = nchar2nlong(n0+1); GEN x = cgetg(n+1, t_STR); char *t = GSTR(x); x[n] = 0; strncpy(t, s, n0); t[n0] = 0; return x; } GEN strtoGENstr(const char *s) { return strntoGENstr(s, strlen(s)); } GEN chartoGENstr(char c) { GEN x = cgetg(2, t_STR); char *t = GSTR(x); t[0] = c; t[1] = 0; return x; } /********************************************************************/ /* */ /* Formal variables management */ /* */ /********************************************************************/ static THREAD long max_priority, min_priority; static THREAD long max_avail; /* max variable not yet used */ static THREAD long nvar; /* first GP free variable */ static hashtable *h_polvar; static struct pari_varstate global_varstate; static long *global_varpriority; void varstate_save(struct pari_varstate *s) { s->nvar = nvar; s->max_avail = max_avail; s->max_priority = max_priority; s->min_priority = min_priority; } static void varentries_set(long v, entree *ep) { hash_insert(h_polvar, (void*)ep->name, (void*)v); varentries[v] = ep; } static int _given_value(void *E, hashentry *e) { return e->val == E; } static void varentries_unset(long v) { entree *ep = varentries[v]; if (ep) { hashentry *e = hash_remove_select(h_polvar, (void*)ep->name, (void*)v, _given_value); if (!e) pari_err_BUG("varentries_unset [unknown var]"); varentries[v] = NULL; pari_free(e); if (v <= nvar && ep == is_entry(ep->name)) { /* known to the GP interpreter; entree in functions_hash is permanent */ GEN p = (GEN)initial_value(ep); if (ep->value == p) { ep->value = NULL; ep->valence = EpNEW; } *p = 0; } else /* from name_var() or a direct pari_var_create() */ pari_free(ep); } } static void varentries_reset(long v, entree *ep) { varentries_unset(v); varentries_set(v, ep); } static void var_restore(struct pari_varstate *s) { nvar = s->nvar; max_avail = s->max_avail; max_priority = s->max_priority; min_priority = s->min_priority; } void varstate_restore(struct pari_varstate *s) { long i; for (i = nvar; i >= s->nvar; i--) { varentries_unset(i); varpriority[i] = -i; } for (i = max_avail+1; i <= s->max_avail; i++) { varentries_unset(i); varpriority[i] = -i; } var_restore(s); } void pari_thread_init_varstate(void) { long i; var_restore(&global_varstate); varpriority = (long*)newblock((MAXVARN+2)) + 1; varpriority[-1] = 1-LONG_MAX; for (i = 0; i < max_avail; i++) varpriority[i] = global_varpriority[i]; } void pari_pthread_init_varstate(void) { varstate_save(&global_varstate); global_varpriority = varpriority; } void pari_var_close(void) { free((void*)varentries); free((void*)(varpriority-1)); hash_destroy(h_polvar); } void pari_var_init(void) { long i; varentries = (entree**) pari_calloc((MAXVARN+1)*sizeof(entree*)); varpriority = (long*)pari_malloc((MAXVARN+2)*sizeof(long)) + 1; varpriority[-1] = 1-LONG_MAX; h_polvar = hash_create_str(100, 0); nvar = 0; max_avail = MAXVARN; max_priority = min_priority = 0; (void)fetch_user_var("x"); (void)fetch_user_var("y"); /* initialize so that people can use pol_x(i) directly */ for (i = 2; i <= (long)MAXVARN; i++) varpriority[i] = -i; /* reserve varnum 1..9 for static temps with predictable priority wrt x */ nvar = 10; min_priority = -MAXVARN; } long pari_var_next(void) { return nvar; } long pari_var_next_temp(void) { return max_avail; } long pari_var_create(entree *ep) { GEN p = (GEN)initial_value(ep); long v; if (*p) return varn(p); if (nvar == max_avail) pari_err(e_MISC,"no more variables available"); v = nvar++; /* set p = pol_x(v) */ p[0] = evaltyp(t_POL) | _evallg(4); p[1] = evalsigne(1) | evalvarn(v); gel(p,2) = gen_0; gel(p,3) = gen_1; varentries_set(v, ep); varpriority[v]= min_priority--; return v; } long delete_var(void) { /* user wants to delete one of his/her/its variables */ if (max_avail == MAXVARN) return 0; /* nothing to delete */ max_avail++; if (varpriority[max_avail] == min_priority) min_priority++; else if (varpriority[max_avail] == max_priority) max_priority--; return max_avail+1; } long fetch_var(void) { if (nvar == max_avail) pari_err(e_MISC,"no more variables available"); varpriority[max_avail] = min_priority--; return max_avail--; } long fetch_var_higher(void) { if (nvar == max_avail) pari_err(e_MISC,"no more variables available"); varpriority[max_avail] = ++max_priority; return max_avail--; } static int _higher(void *E, hashentry *e) { long v = (long)e->val; return (varncmp(v, (long)E) < 0); } static int _lower(void *E, hashentry *e) { long v = (long)e->val; return (varncmp(v, (long)E) > 0); } static GEN var_register(long v, const char *s) { varentries_reset(v, initep(s, strlen(s))); return pol_x(v); } GEN varhigher(const char *s, long w) { long v; if (w >= 0) { hashentry *e = hash_select(h_polvar, (void*)s, (void*)w, _higher); if (e) return pol_x((long)e->val); } /* no luck: need to create */ if (nvar == max_avail) pari_err(e_MISC,"no more variables available"); v = nvar++; varpriority[v]= ++max_priority; return var_register(v, s); } GEN varlower(const char *s, long w) { long v; if (w >= 0) { hashentry *e = hash_select(h_polvar, (void*)s, (void*)w, _lower); if (e) return pol_x((long)e->val); } /* no luck: need to create */ v = fetch_var(); return var_register(v, s); } long fetch_user_var(const char *s) { entree *ep = fetch_entry(s); long v; switch (EpVALENCE(ep)) { case EpVAR: return varn((GEN)initial_value(ep)); case EpNEW: break; default: pari_err(e_MISC, "%s already exists with incompatible valence", s); } v = pari_var_create(ep); ep->valence = EpVAR; ep->value = initial_value(ep); return v; } GEN fetch_var_value(long v, GEN t) { entree *ep = varentries[v]; if (!ep) return NULL; if (t) { long vn = localvars_find(t,ep); if (vn) return get_lex(vn); } return (GEN)ep->value; } void name_var(long n, const char *s) { entree *ep; char *u; if (n < pari_var_next()) pari_err(e_MISC, "renaming a GP variable is forbidden"); if (n > (long)MAXVARN) pari_err_OVERFLOW("variable number"); ep = (entree*)pari_malloc(sizeof(entree) + strlen(s) + 1); u = (char *)initial_value(ep); ep->valence = EpVAR; ep->name = u; strcpy(u,s); ep->value = gen_0; /* in case geval is called */ varentries_reset(n, ep); } static int cmp_by_var(void *E,GEN x, GEN y) { (void)E; return varncmp((long)x,(long)y); } GEN vars_sort_inplace(GEN z) { gen_sort_inplace(z,NULL,cmp_by_var,NULL); return z; } GEN vars_to_RgXV(GEN h) { long i, l = lg(h); GEN z = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(z,i) = pol_x(h[i]); return z; } GEN gpolvar(GEN x) { long v; if (!x) { GEN h = hash_values(h_polvar); return vars_to_RgXV(vars_sort_inplace(h)); } if (typ(x)==t_PADIC) return gcopy( gel(x,2) ); v = gvar(x); if (v==NO_VARIABLE) return gen_0; return pol_x(v); } static void fill_hashtable_single(entree **table, entree *ep) { EpSETSTATIC(ep); insertep(ep, table, hashvalue(ep->name)); if (ep->code) ep->arity = check_proto(ep->code); ep->pvalue = NULL; } void pari_fill_hashtable(entree **table, entree *ep) { for ( ; ep->name; ep++) fill_hashtable_single(table, ep); } void pari_add_function(entree *ep) { fill_hashtable_single(functions_hash, ep); } /********************************************************************/ /** **/ /** SIMPLE GP FUNCTIONS **/ /** **/ /********************************************************************/ #define ALIAS(ep) (entree *) ((GEN)ep->value)[1] entree * do_alias(entree *ep) { while (ep->valence == EpALIAS) ep = ALIAS(ep); return ep; } void alias0(const char *s, const char *old) { entree *ep, *e; GEN x; ep = fetch_entry(old); e = fetch_entry(s); if (EpVALENCE(e) != EpALIAS && EpVALENCE(e) != EpNEW) pari_err(e_MISC,"can't replace an existing symbol by an alias"); freeep(e); x = cgetg_block(2, t_VECSMALL); gel(x,1) = (GEN)ep; e->value=x; e->valence=EpALIAS; } GEN ifpari(GEN g, GEN a/*closure*/, GEN b/*closure*/) { if (gequal0(g)) /* false */ return b? closure_evalgen(b): gnil; else /* true */ return a? closure_evalgen(a): gnil; } void ifpari_void(GEN g, GEN a/*closure*/, GEN b/*closure*/) { if (gequal0(g)) /* false */ { if (b) closure_evalvoid(b); } else /* true */ { if (a) closure_evalvoid(a); } } GEN ifpari_multi(GEN g, GEN a/*closure*/) { long i, nb = lg(a)-1; if (!gequal0(g)) /* false */ return closure_evalgen(gel(a,1)); for(i=2;i (~0UL / 10)) pari_err(e_SYNTAX,"integer too large",s,s); n *= 10; m = n; n += *p++ - '0'; if (n < m) pari_err(e_SYNTAX,"integer too large",s,s); } if (n) { switch(*p) { case 'k': case 'K': n = umuluu_or_0(n,1000UL); p++; break; case 'm': case 'M': n = umuluu_or_0(n,1000000UL); p++; break; case 'g': case 'G': n = umuluu_or_0(n,1000000000UL); p++; break; #ifdef LONG_IS_64BIT case 't': case 'T': n = umuluu_or_0(n,1000000000000UL); p++; break; #endif } if (!n) pari_err(e_SYNTAX,"integer too large",s,s); } if (*p) pari_err(e_SYNTAX,"I was expecting an integer here", s, s); return n; } long get_int(const char *s, long dflt) { pari_sp av = avma; char *p = get_sep(s); long n; int minus = 0; if (*p == '-') { minus = 1; p++; } if (!isdigit((int)*p)) { avma = av; return dflt; } n = (long)my_int(p); if (n < 0) pari_err(e_SYNTAX,"integer too large",s,s); avma = av; return minus? -n: n; } ulong get_uint(const char *s) { pari_sp av = avma; char *p = get_sep(s); ulong u; if (*p == '-') pari_err(e_SYNTAX,"arguments must be positive integers",s,s); u = my_int(p); avma = av; return u; } #if defined(__EMX__) || defined(_WIN32) || defined(__CYGWIN32__) # define PATH_SEPARATOR ';' /* beware DOSish 'C:' disk drives */ #else # define PATH_SEPARATOR ':' #endif static const char * pari_default_path(void) { #if PATH_SEPARATOR == ';' return ".;C:;C:/gp"; #elif defined(UNIX) return ".:~:~/gp"; #else return "."; #endif } static void delete_dirs(gp_path *p) { char **v = p->dirs, **dirs; if (v) { p->dirs = NULL; /* in case of error */ for (dirs = v; *dirs; dirs++) pari_free(*dirs); pari_free(v); } } static void expand_path(gp_path *p) { char **dirs, *s, *v = p->PATH; int i, n = 0; delete_dirs(p); if (*v) { v = pari_strdup(v); for (s=v; *s; s++) if (*s == PATH_SEPARATOR) { *s = 0; if (s == v || s[-1] != 0) n++; /* ignore empty path components */ } dirs = (char**) pari_malloc((n + 2)*sizeof(char *)); for (s=v, i=0; i<=n; i++) { char *end, *f; while (!*s) s++; /* skip empty path components */ f = end = s + strlen(s); while (f > s && *--f == '/') *f = 0; /* skip trailing '/' */ dirs[i] = path_expand(s); s = end + 1; /* next path component */ } pari_free((void*)v); } else { dirs = (char**) pari_malloc(sizeof(char *)); i = 0; } dirs[i] = NULL; p->dirs = dirs; } void pari_init_paths(void) { expand_path(GP_DATA->path); expand_path(GP_DATA->sopath); } static void delete_path(gp_path *p) { delete_dirs(p); free(p->PATH); } void pari_close_paths(void) { delete_path(GP_DATA->path); delete_path(GP_DATA->sopath); } /********************************************************************/ /* */ /* DEFAULTS */ /* */ /********************************************************************/ long getrealprecision(void) { return GP_DATA->fmt->sigd; } long setrealprecision(long n, long *prec) { GP_DATA->fmt->sigd = n; *prec = ndec2prec(n); precreal = prec2nbits(*prec); return n; } GEN sd_toggle(const char *v, long flag, const char *s, int *ptn) { int state = *ptn; if (v) { int n = (int)get_int(v,0); if (n == state) return gnil; if (n != !state) { char *t = stack_malloc(64 + strlen(s)); (void)sprintf(t, "default: incorrect value for %s [0:off / 1:on]", s); pari_err(e_SYNTAX, t, v,v); } state = *ptn = n; } switch(flag) { case d_RETURN: return utoi(state); case d_ACKNOWLEDGE: if (state) pari_printf(" %s = 1 (on)\n", s); else pari_printf(" %s = 0 (off)\n", s); break; } return gnil; } static void sd_ulong_init(const char *v, const char *s, ulong *ptn, ulong Min, ulong Max) { if (v) { ulong n = get_uint(v); if (n > Max || n < Min) { char *buf = stack_malloc(strlen(s) + 2 * 20 + 40); (void)sprintf(buf, "default: incorrect value for %s [%lu-%lu]", s, Min, Max); pari_err(e_SYNTAX, buf, v,v); } *ptn = n; } } /* msg is NULL or NULL-terminated array with msg[0] != NULL. */ GEN sd_ulong(const char *v, long flag, const char *s, ulong *ptn, ulong Min, ulong Max, const char **msg) { ulong n = *ptn; sd_ulong_init(v, s, ptn, Min, Max); switch(flag) { case d_RETURN: return utoi(*ptn); case d_ACKNOWLEDGE: if (!v || *ptn != n) { if (!msg) /* no specific message */ pari_printf(" %s = %lu\n", s, *ptn); else if (!msg[1]) /* single message, always printed */ pari_printf(" %s = %lu %s\n", s, *ptn, msg[0]); else /* print (new)-n-th message */ pari_printf(" %s = %lu %s\n", s, *ptn, msg[*ptn]); } break; } return gnil; } static void err_intarray(char *t, char *p, const char *s) { char *b = stack_malloc(64 + strlen(s)); sprintf(b, "incorrect value for %s", s); pari_err(e_SYNTAX, b, p, t); } static GEN parse_intarray(const char *v, const char *s) { char *p, *t = gp_filter(v); long i, l; GEN w; if (*t != '[') err_intarray(t, t, s); if (t[1] == ']') { pari_free(t); return cgetalloc(t_VECSMALL, 1); } for (p = t+1, l=2; *p; p++) if (*p == ',') l++; else if (*p < '0' || *p > '9') break; if (*p != ']') err_intarray(t, p, s); w = cgetalloc(t_VECSMALL, l); for (p = t+1, i=0; *p; p++) { long n = 0; while (*p >= '0' && *p <= '9') n = 10*n + (*p++ -'0'); w[++i] = n; } pari_free(t); return w; } GEN sd_intarray(const char *v, long flag, GEN *pz, const char *s) { if (v) { GEN z = *pz; *pz = parse_intarray(v, s); pari_free(z); } switch(flag) { case d_RETURN: return zv_to_ZV(*pz); case d_ACKNOWLEDGE: pari_printf(" %s = %Ps\n", s, zv_to_ZV(*pz)); } return gnil; } GEN sd_realprecision(const char *v, long flag) { pariout_t *fmt = GP_DATA->fmt; if (v) { ulong newnb = fmt->sigd; long prec; sd_ulong_init(v, "realprecision", &newnb, 1, prec2ndec(LGBITS)); if (fmt->sigd == (long)newnb) return gnil; if (fmt->sigd >= 0) fmt->sigd = newnb; prec = ndec2nbits(newnb); if (prec == precreal) return gnil; precreal = prec; } if (flag == d_RETURN) return stoi(nbits2ndec(precreal)); if (flag == d_ACKNOWLEDGE) { long n = nbits2ndec(precreal); pari_printf(" realprecision = %ld significant digits", n); if (fmt->sigd < 0) pari_puts(" (all digits displayed)"); else if (n != fmt->sigd) pari_printf(" (%ld digits displayed)", fmt->sigd); pari_putc('\n'); } return gnil; } GEN sd_realbitprecision(const char *v, long flag) { pariout_t *fmt = GP_DATA->fmt; if (v) { ulong newnb = precreal; long n; sd_ulong_init(v, "realbitprecision", &newnb, 1, prec2nbits(LGBITS)); if ((long)newnb == precreal) return gnil; n = nbits2ndec(newnb); if (!n) n = 1; if (fmt->sigd >= 0) fmt->sigd = n; precreal = (long) newnb; } if (flag == d_RETURN) return stoi(precreal); if (flag == d_ACKNOWLEDGE) { pari_printf(" realbitprecision = %ld significant bits", precreal); if (fmt->sigd < 0) pari_puts(" (all digits displayed)"); else pari_printf(" (%ld decimal digits displayed)", fmt->sigd); pari_putc('\n'); } return gnil; } GEN sd_seriesprecision(const char *v, long flag) { const char *msg[] = {"significant terms", NULL}; return sd_ulong(v,flag,"seriesprecision",&precdl, 1,LGBITS,msg); } static long gp_get_color(char **st) { char *s, *v = *st; int trans; long c; if (isdigit((int)*v)) { c = atol(v); trans = 1; } /* color on transparent background */ else { if (*v == '[') { const char *a[3]; long i = 0; for (a[0] = s = ++v; *s && *s != ']'; s++) if (*s == ',') { *s = 0; a[++i] = s+1; } if (*s != ']') pari_err(e_SYNTAX,"expected character: ']'",s, *st); *s = 0; for (i++; i<3; i++) a[i] = ""; /* properties | color | background */ c = (atoi(a[2])<<8) | atoi(a[0]) | (atoi(a[1])<<4); trans = (*(a[1]) == 0); v = s + 1; } else { c = c_NONE; trans = 0; } } if (trans) c = c | (1L<<12); while (*v && *v++ != ',') /* empty */; if (c != c_NONE) disable_color = 0; *st = v; return c; } /* 1: error, 2: history, 3: prompt, 4: input, 5: output, 6: help, 7: timer */ GEN sd_colors(const char *v, long flag) { long c,l; if (v && !(GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS))) { char *v0, *s; disable_color=1; l = strlen(v); if (l <= 2 && strncmp(v, "no", l) == 0) v = ""; if (l <= 6 && strncmp(v, "darkbg", l) == 0) v = "1, 5, 3, 7, 6, 2, 3"; /* Assume recent ReadLine. */ if (l <= 7 && strncmp(v, "lightbg", l) == 0) v = "1, 6, 3, 4, 5, 2, 3"; /* Assume recent ReadLine. */ if (l <= 8 && strncmp(v, "brightfg", l) == 0) /* Good for windows consoles */ v = "9, 13, 11, 15, 14, 10, 11"; if (l <= 6 && strncmp(v, "boldfg", l) == 0) /* Good for darkbg consoles */ v = "[1,,1], [5,,1], [3,,1], [7,,1], [6,,1], , [2,,1]"; v0 = s = gp_filter(v); for (c=c_ERR; c < c_LAST; c++) gp_colors[c] = gp_get_color(&s); pari_free(v0); } if (flag == d_ACKNOWLEDGE || flag == d_RETURN) { char s[128], *t = s; long col[3], n; for (*t=0,c=c_ERR; c < c_LAST; c++) { n = gp_colors[c]; if (n == c_NONE) sprintf(t,"no"); else { decode_color(n,col); if (n & (1L<<12)) { if (col[0]) sprintf(t,"[%ld,,%ld]",col[1],col[0]); else sprintf(t,"%ld",col[1]); } else sprintf(t,"[%ld,%ld,%ld]",col[1],col[2],col[0]); } t += strlen(t); if (c < c_LAST - 1) { *t++=','; *t++=' '; } } if (flag==d_RETURN) return strtoGENstr(s); pari_printf(" colors = \"%s\"\n",s); } return gnil; } GEN sd_format(const char *v, long flag) { pariout_t *fmt = GP_DATA->fmt; if (v) { char c = *v; if (c!='e' && c!='f' && c!='g') pari_err(e_SYNTAX,"default: inexistent format",v,v); fmt->format = c; v++; if (isdigit((int)*v)) { while (isdigit((int)*v)) v++; } /* FIXME: skip obsolete field width */ if (*v++ == '.') { if (*v == '-') fmt->sigd = -1; else if (isdigit((int)*v)) fmt->sigd=atol(v); } } if (flag == d_RETURN) { char *s = stack_malloc(64); (void)sprintf(s, "%c.%ld", fmt->format, fmt->sigd); return strtoGENstr(s); } if (flag == d_ACKNOWLEDGE) pari_printf(" format = %c.%ld\n", fmt->format, fmt->sigd); return gnil; } GEN sd_compatible(const char *v, long flag) { const char *msg[] = { "(no backward compatibility)", "(no backward compatibility)", "(no backward compatibility)", "(no backward compatibility)", NULL }; ulong junk = 0; return sd_ulong(v,flag,"compatible",&junk, 0,3,msg); } GEN sd_secure(const char *v, long flag) { if (v && GP_DATA->secure) pari_ask_confirm("[secure mode]: About to modify the 'secure' flag"); return sd_toggle(v,flag,"secure", &(GP_DATA->secure)); } GEN sd_debug(const char *v, long flag) { return sd_ulong(v,flag,"debug",&DEBUGLEVEL, 0,20,NULL); } GEN sd_debugfiles(const char *v, long flag) { return sd_ulong(v,flag,"debugfiles",&DEBUGFILES, 0,20,NULL); } GEN sd_debugmem(const char *v, long flag) { return sd_ulong(v,flag,"debugmem",&DEBUGMEM, 0,20,NULL); } /* set D->hist to size = s / total = t */ static void init_hist(gp_data *D, size_t s, ulong t) { gp_hist *H = D->hist; H->total = t; H->size = s; H->v = (gp_hist_cell*)pari_calloc(s * sizeof(gp_hist_cell)); } GEN sd_histsize(const char *s, long flag) { gp_hist *H = GP_DATA->hist; ulong n = H->size; GEN r = sd_ulong(s,flag,"histsize",&n, 1, (LONG_MAX / sizeof(long)) - 1,NULL); if (n != H->size) { const ulong total = H->total; long g, h, k, kmin; gp_hist_cell *v = H->v, *w; /* v = old data, w = new one */ size_t sv = H->size, sw; init_hist(GP_DATA, n, total); if (!total) return r; w = H->v; sw= H->size; /* copy relevant history entries */ g = (total-1) % sv; h = k = (total-1) % sw; kmin = k - minss(sw, sv); for ( ; k > kmin; k--, g--, h--) { w[h] = v[g]; v[g].z = NULL; if (!g) g = sv; if (!h) h = sw; } /* clean up */ for ( ; v[g].z; g--) { gunclone(v[g].z); if (!g) g = sv; } pari_free((void*)v); } return r; } static void TeX_define(const char *s, const char *def) { fprintf(pari_logfile, "\\ifx\\%s\\undefined\n \\def\\%s{%s}\\fi\n", s,s,def); } static void TeX_define2(const char *s, const char *def) { fprintf(pari_logfile, "\\ifx\\%s\\undefined\n \\def\\%s#1#2{%s}\\fi\n", s,s,def); } static FILE * open_logfile(const char *s) { FILE *log = fopen(s, "a"); if (!log) pari_err_FILE("logfile",s); setbuf(log,(char *)NULL); return log; } GEN sd_log(const char *v, long flag) { const char *msg[] = { "(off)", "(on)", "(on with colors)", "(TeX output)", NULL }; ulong s = logstyle; GEN res = sd_ulong(v,flag,"log", &s, 0, 3, msg); if (!s != !logstyle) /* Compare converts to boolean */ { /* toggled LOG */ if (logstyle) { /* close log */ if (flag == d_ACKNOWLEDGE) pari_printf(" [logfile was \"%s\"]\n", current_logfile); if (pari_logfile) /* paranoia */ { fclose(pari_logfile); pari_logfile = NULL; } } else pari_logfile = open_logfile(current_logfile); } if (pari_logfile && s != logstyle && s == logstyle_TeX) { TeX_define("PARIbreak", "\\hskip 0pt plus \\hsize\\relax\\discretionary{}{}{}"); TeX_define("PARIpromptSTART", "\\vskip\\medskipamount\\bgroup\\bf"); TeX_define("PARIpromptEND", "\\egroup\\bgroup\\tt"); TeX_define("PARIinputEND", "\\egroup"); TeX_define2("PARIout", "\\vskip\\smallskipamount$\\displaystyle{\\tt\\%#1} = #2$"); } /* don't record new value until we are sure everything is fine */ logstyle = s; return res; } GEN sd_TeXstyle(const char *v, long flag) { const char *msg[] = { "(bits 0x2/0x4 control output of \\left/\\PARIbreak)", NULL }; ulong n = GP_DATA->fmt->TeXstyle; GEN z = sd_ulong(v,flag,"TeXstyle", &n, 0, 7, msg); GP_DATA->fmt->TeXstyle = n; return z; } GEN sd_nbthreads(const char *v, long flag) { return sd_ulong(v,flag,"nbthreads",&pari_mt_nbthreads, 1,LONG_MAX,NULL); } GEN sd_output(const char *v, long flag) { const char *msg[] = {"(raw)", "(prettymatrix)", "(prettyprint)", "(external prettyprint)", NULL}; ulong n = GP_DATA->fmt->prettyp; GEN z = sd_ulong(v,flag,"output", &n, 0,3,msg); GP_DATA->fmt->prettyp = n; GP_DATA->fmt->sp = (n != f_RAW); return z; } GEN sd_parisizemax(const char *v, long flag) { ulong size = pari_mainstack->vsize, n = size; GEN r = sd_ulong(v,flag,"parisizemax",&n, 0,LONG_MAX,NULL); if (n != size) { if (flag == d_INITRC) paristack_setsize(pari_mainstack->rsize, n); else parivstack_resize(n); } return r; } GEN sd_parisize(const char *v, long flag) { ulong rsize = pari_mainstack->rsize, n = rsize; GEN r = sd_ulong(v,flag,"parisize",&n, 10000,LONG_MAX,NULL); if (n != rsize) { if (flag == d_INITRC) paristack_setsize(n, pari_mainstack->vsize); else paristack_newrsize(n); } return r; } GEN sd_threadsizemax(const char *v, long flag) { ulong size = GP_DATA->threadsizemax, n = size; GEN r = sd_ulong(v,flag,"threadsizemax",&n, 0,LONG_MAX,NULL); if (n != size) GP_DATA->threadsizemax = n; return r; } GEN sd_threadsize(const char *v, long flag) { ulong size = GP_DATA->threadsize, n = size; GEN r = sd_ulong(v,flag,"threadsize",&n, 0,LONG_MAX,NULL); if (n != size) GP_DATA->threadsize = n; return r; } GEN sd_primelimit(const char *v, long flag) { return sd_ulong(v,flag,"primelimit",&(GP_DATA->primelimit), 0,2*(ulong)(LONG_MAX-1024) + 1,NULL); } GEN sd_simplify(const char *v, long flag) { return sd_toggle(v,flag,"simplify", &(GP_DATA->simplify)); } GEN sd_strictmatch(const char *v, long flag) { return sd_toggle(v,flag,"strictmatch", &(GP_DATA->strictmatch)); } GEN sd_strictargs(const char *v, long flag) { return sd_toggle(v,flag,"strictargs", &(GP_DATA->strictargs)); } GEN sd_string(const char *v, long flag, const char *s, char **pstr) { char *old = *pstr; if (v) { char *str, *ev = path_expand(v); long l = strlen(ev) + 256; str = (char *) pari_malloc(l); strftime_expand(ev,str, l-1); pari_free(ev); if (GP_DATA->secure) { char *msg=pari_sprintf("[secure mode]: About to change %s to '%s'",s,str); pari_ask_confirm(msg); pari_free(msg); } if (old) pari_free(old); *pstr = old = pari_strdup(str); pari_free(str); } else if (!old) old = (char*)""; if (flag == d_RETURN) return strtoGENstr(old); if (flag == d_ACKNOWLEDGE) pari_printf(" %s = \"%s\"\n",s,old); return gnil; } GEN sd_logfile(const char *v, long flag) { GEN r = sd_string(v, flag, "logfile", ¤t_logfile); if (v && pari_logfile) { FILE *log = open_logfile(current_logfile); fclose(pari_logfile); pari_logfile = log; } return r; } GEN sd_factor_add_primes(const char *v, long flag) { return sd_toggle(v,flag,"factor_add_primes", &factor_add_primes); } GEN sd_factor_proven(const char *v, long flag) { return sd_toggle(v,flag,"factor_proven", &factor_proven); } GEN sd_new_galois_format(const char *v, long flag) { return sd_toggle(v,flag,"new_galois_format", &new_galois_format); } GEN sd_datadir(const char *v, long flag) { const char *str; if (v) { if (pari_datadir) pari_free(pari_datadir); pari_datadir = path_expand(v); } str = pari_datadir? pari_datadir: "none"; if (flag == d_RETURN) return strtoGENstr(str); if (flag == d_ACKNOWLEDGE) pari_printf(" datadir = \"%s\"\n", str); return gnil; } static GEN sd_PATH(const char *v, long flag, const char* s, gp_path *p) { if (v) { pari_free((void*)p->PATH); p->PATH = pari_strdup(v); if (flag == d_INITRC) return gnil; expand_path(p); } if (flag == d_RETURN) return strtoGENstr(p->PATH); if (flag == d_ACKNOWLEDGE) pari_printf(" %s = \"%s\"\n", s, p->PATH); return gnil; } GEN sd_path(const char *v, long flag) { return sd_PATH(v, flag, "path", GP_DATA->path); } GEN sd_sopath(char *v, int flag) { return sd_PATH(v, flag, "sopath", GP_DATA->sopath); } static const char *DFT_PRETTYPRINTER = "tex2mail -TeX -noindent -ragged -by_par"; GEN sd_prettyprinter(const char *v, long flag) { gp_pp *pp = GP_DATA->pp; if (v && !(GP_DATA->flags & gpd_TEXMACS)) { char *old = pp->cmd; int cancel = (!strcmp(v,"no")); if (GP_DATA->secure) pari_err(e_MISC,"[secure mode]: can't modify 'prettyprinter' default (to %s)",v); if (!strcmp(v,"yes")) v = DFT_PRETTYPRINTER; if (old && strcmp(old,v) && pp->file) { pariFILE *f; if (cancel) f = NULL; else { f = try_pipe(v, mf_OUT); if (!f) { pari_warn(warner,"broken prettyprinter: '%s'",v); return gnil; } } pari_fclose(pp->file); pp->file = f; } pp->cmd = cancel? NULL: pari_strdup(v); if (old) pari_free(old); if (flag == d_INITRC) return gnil; } if (flag == d_RETURN) return strtoGENstr(pp->cmd? pp->cmd: ""); if (flag == d_ACKNOWLEDGE) pari_printf(" prettyprinter = \"%s\"\n",pp->cmd? pp->cmd: ""); return gnil; } /* compare entrees s1 s2 according to the attached function name */ static int compare_name(const void *s1, const void *s2) { entree *e1 = *(entree**)s1, *e2 = *(entree**)s2; return strcmp(e1->name, e2->name); } static void defaults_list(pari_stack *s) { entree *ep; long i; for (i = 0; i < functions_tblsz; i++) for (ep = defaults_hash[i]; ep; ep = ep->next) pari_stack_pushp(s, ep); } /* ep attached to function f of arity 2. Call f(v,flag) */ static GEN call_f2(entree *ep, const char *v, long flag) { return ((GEN (*)(const char*,long))ep->value)(v, flag); } GEN setdefault(const char *s, const char *v, long flag) { entree *ep; if (!s) { /* list all defaults */ pari_stack st; entree **L; long i; pari_stack_init(&st, sizeof(*L), (void**)&L); defaults_list(&st); qsort (L, st.n, sizeof(*L), compare_name); for (i = 0; i < st.n; i++) (void)call_f2(L[i], NULL, d_ACKNOWLEDGE); pari_stack_delete(&st); return gnil; } ep = pari_is_default(s); if (!ep) { pari_err(e_MISC,"unknown default: %s",s); return NULL; /* LCOV_EXCL_LINE */ } return call_f2(ep, v, flag); } GEN default0(const char *a, const char *b) { return setdefault(a,b, b? d_SILENT: d_RETURN); } /********************************************************************/ /* */ /* INITIALIZE GP_DATA */ /* */ /********************************************************************/ /* initialize path */ static void init_path(gp_path *path, const char *v) { path->PATH = pari_strdup(v); path->dirs = NULL; } /* initialize D->fmt */ static void init_fmt(gp_data *D) { #ifdef LONG_IS_64BIT static pariout_t DFLT_OUTPUT = { 'g', 38, 1, f_PRETTYMAT, 0 }; #else static pariout_t DFLT_OUTPUT = { 'g', 28, 1, f_PRETTYMAT, 0 }; #endif D->fmt = &DFLT_OUTPUT; } /* initialize D->pp */ static void init_pp(gp_data *D) { gp_pp *p = D->pp; p->cmd = pari_strdup(DFT_PRETTYPRINTER); p->file = NULL; } static char * init_help(void) { char *h = os_getenv("GPHELP"); if (!h) h = (char*)paricfg_gphelp; #ifdef _WIN32 win32_set_pdf_viewer(); #endif if (h) h = pari_strdup(h); return h; } static void init_graphs(gp_data *D) { const char *cols[] = { "", "white","black","blue","violetred","red","green","grey","gainsboro" }; const long N = 8; GEN c = cgetalloc(t_VECSMALL, 3), s; long i; c[1] = 4; c[2] = 5; D->graphcolors = c; c = (GEN)pari_malloc((N+1 + 4*N)*sizeof(long)); c[0] = evaltyp(t_VEC)|evallg(N+1); for (i = 1, s = c+N+1; i <= N; i++, s += 4) { GEN lp = s; lp[0] = evaltyp(t_STR)|evallg(4); strcpy(GSTR(lp), cols[i]); gel(c,i) = lp; } D->colormap = c; } gp_data * default_gp_data(void) { static gp_data __GPDATA, *D = &__GPDATA; static gp_hist __HIST; static gp_pp __PP; static gp_path __PATH, __SOPATH; static pari_timer __T; D->flags = 0; D->primelimit = 500000; /* GP-specific */ D->breakloop = 1; D->echo = 0; D->lim_lines = 0; D->linewrap = 0; D->recover = 1; D->chrono = 0; D->strictargs = 0; D->strictmatch = 1; D->simplify = 1; D->secure = 0; D->use_readline= 0; D->T = &__T; D->hist = &__HIST; D->pp = &__PP; D->path = &__PATH; D->sopath=&__SOPATH; init_fmt(D); init_hist(D, 5000, 0); init_path(D->path, pari_default_path()); init_path(D->sopath, ""); init_pp(D); init_graphs(D); D->plothsizes = cgetalloc(t_VECSMALL, 1); D->prompt_comment = (char*)"comment> "; D->prompt = pari_strdup("? "); D->prompt_cont = pari_strdup(""); D->help = init_help(); D->readline_state = DO_ARGS_COMPLETE; D->histfile = NULL; return D; } pari-2.11.2/src/language/init.c0000644000175000017500000021235013447371554014657 0ustar billbill/* Copyright (C) 2000-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* INITIALIZING THE SYSTEM, ERRORS, STACK MANAGEMENT */ /* */ /*******************************************************************/ /* _GNU_SOURCE is needed before first include to get RUSAGE_THREAD */ #undef _GNU_SOURCE /* avoid warning */ #define _GNU_SOURCE #include #if defined(_WIN32) || defined(__CYGWIN32__) # include "../systems/mingw/mingw.h" # include #endif #include "paricfg.h" #if defined(STACK_CHECK) && !defined(__EMX__) # include # include # include #endif #if defined(HAS_WAITPID) && defined(HAS_SETSID) # include #endif #ifdef HAS_MMAP # include #endif #if defined(USE_GETTIMEOFDAY) || defined(USE_GETRUSAGE) || defined(USE_TIMES) # include #endif #if defined(USE_GETRUSAGE) # include #endif #if defined(USE_FTIME) || defined(USE_FTIMEFORWALLTIME) # include #endif #if defined(USE_CLOCK_GETTIME) || defined(USE_TIMES) # include #endif #if defined(USE_TIMES) # include #endif #include "pari.h" #include "paripriv.h" #include "anal.h" const double LOG10_2 = 0.3010299956639812; /* log_10(2) */ const double LOG2_10 = 3.321928094887362; /* log_2(10) */ GEN gnil, gen_0, gen_1, gen_m1, gen_2, gen_m2, ghalf, err_e_STACK; static const ulong readonly_constants[] = { evaltyp(t_INT) | _evallg(2), /* gen_0 */ evallgefint(2), evaltyp(t_INT) | _evallg(2), /* gnil */ evallgefint(2), evaltyp(t_INT) | _evallg(3), /* gen_1 */ evalsigne(1) | evallgefint(3), 1, evaltyp(t_INT) | _evallg(3), /* gen_2 */ evalsigne(1) | evallgefint(3), 2, evaltyp(t_INT) | _evallg(3), /* gen_m1 */ evalsigne(-1) | evallgefint(3), 1, evaltyp(t_INT) | _evallg(3), /* gen_m2 */ evalsigne(-1) | evallgefint(3), 2, evaltyp(t_ERROR) | _evallg(2), /* err_e_STACK */ e_STACK, evaltyp(t_FRAC) | _evallg(3), /* ghalf */ (ulong)(readonly_constants+4), (ulong)(readonly_constants+7) }; THREAD GEN bernzone, primetab; byteptr diffptr; FILE *pari_outfile, *pari_errfile, *pari_logfile, *pari_infile; char *current_logfile, *current_psfile, *pari_datadir; long gp_colors[c_LAST]; int disable_color; ulong DEBUGFILES, DEBUGLEVEL, DEBUGMEM; long DEBUGVAR; ulong pari_mt_nbthreads; long precreal; ulong precdl, logstyle; gp_data *GP_DATA; entree **varentries; THREAD long *varpriority; THREAD pari_sp avma; THREAD struct pari_mainstack *pari_mainstack; static void ** MODULES; static pari_stack s_MODULES; const long functions_tblsz = 135; /* size of functions_hash */ entree **functions_hash, **defaults_hash; char *(*cb_pari_fgets_interactive)(char *s, int n, FILE *f); int (*cb_pari_get_line_interactive)(const char*, const char*, filtre_t *F); void (*cb_pari_quit)(long); void (*cb_pari_init_histfile)(void); void (*cb_pari_ask_confirm)(const char *); int (*cb_pari_handle_exception)(long); int (*cb_pari_err_handle)(GEN); int (*cb_pari_whatnow)(PariOUT *out, const char *, int); void (*cb_pari_sigint)(void); void (*cb_pari_pre_recover)(long); void (*cb_pari_err_recover)(long); int (*cb_pari_break_loop)(int); int (*cb_pari_is_interactive)(void); void (*cb_pari_start_output)(); const char * pari_library_path = NULL; static THREAD GEN global_err_data; THREAD jmp_buf *iferr_env; const long CATCH_ALL = -1; static void pari_init_timer(void); /*********************************************************************/ /* */ /* BLOCKS & CLONES */ /* */ /*********************************************************************/ /*#define DEBUG*/ static THREAD long next_block; static THREAD GEN cur_block; /* current block in block list */ #ifdef DEBUG static THREAD long NUM; #endif static void pari_init_blocks(void) { next_block = 0; cur_block = NULL; #ifdef DEBUG NUM = 0; #endif } static void pari_close_blocks(void) { while (cur_block) killblock(cur_block); } /* Return x, where: * x[-4]: reference count * x[-3]: adress of next block * x[-2]: adress of preceding block. * x[-1]: number of allocated blocs. * x[0..n-1]: malloc-ed memory. */ GEN newblock(size_t n) { long *x = (long *) pari_malloc((n + BL_HEAD)*sizeof(long)) + BL_HEAD; bl_size(x) = n; bl_refc(x) = 1; bl_next(x) = NULL; bl_prev(x) = cur_block; bl_num(x) = next_block++; if (cur_block) bl_next(cur_block) = x; #ifdef DEBUG err_printf("+ %ld\n", ++NUM); #endif if (DEBUGMEM > 2) err_printf("new block, size %6lu (no %ld): %08lx\n", n, next_block-1, x); return cur_block = x; } GEN gcloneref(GEN x) { if (isclone(x)) { ++bl_refc(x); return x; } else return gclone(x); } void gclone_refc(GEN x) { ++bl_refc(x); } void gunclone(GEN x) { if (--bl_refc(x) > 0) return; BLOCK_SIGINT_START; if (bl_next(x)) bl_prev(bl_next(x)) = bl_prev(x); else { cur_block = bl_prev(x); next_block = bl_num(x); } if (bl_prev(x)) bl_next(bl_prev(x)) = bl_next(x); if (DEBUGMEM > 2) err_printf("killing block (no %ld): %08lx\n", bl_num(x), x); free((void*)bl_base(x)); /* pari_free not needed: we already block */ BLOCK_SIGINT_END; #ifdef DEBUG err_printf("- %ld\n", NUM--); #endif } /* Recursively look for clones in the container and kill them. Then kill * container if clone. SIGINT could be blocked until it returns */ void gunclone_deep(GEN x) { long i, lx; GEN v; if (isclone(x) && bl_refc(x) > 1) { --bl_refc(x); return; } BLOCK_SIGINT_START; switch(typ(x)) { case t_VEC: case t_COL: case t_MAT: lx = lg(x); for (i=1;ivalue; if (bl_num(x) < loc) return 0; /* older */ if (DEBUGMEM>2) err_printf("popping %s (block no %ld)\n", ep->name, bl_num(x)); gunclone_deep(x); return 1; } /*********************************************************************/ /* */ /* C STACK SIZE CONTROL */ /* */ /*********************************************************************/ /* Avoid core dump on deep recursion. Adapted Perl code by Dominic Dunlop */ THREAD void *PARI_stack_limit = NULL; #ifdef STACK_CHECK # ifdef __EMX__ /* Emulate */ void pari_stackcheck_init(void *pari_stack_base) { (void) pari_stack_base; if (!pari_stack_base) { PARI_stack_limit = NULL; return; } PARI_stack_limit = get_stack(1./16, 32*1024); } # else /* !__EMX__ */ /* Set PARI_stack_limit to (a little above) the lowest safe address that can be * used on the stack. Leave PARI_stack_limit at its initial value (NULL) to * show no check should be made [init failed]. Assume stack grows downward. */ void pari_stackcheck_init(void *pari_stack_base) { struct rlimit rip; ulong size; if (!pari_stack_base) { PARI_stack_limit = NULL; return; } if (getrlimit(RLIMIT_STACK, &rip)) return; size = rip.rlim_cur; if (size == (ulong)RLIM_INFINITY || size > (ulong)pari_stack_base) PARI_stack_limit = (void*)(((ulong)pari_stack_base) / 16); else PARI_stack_limit = (void*)((ulong)pari_stack_base - (size/16)*15); } # endif /* !__EMX__ */ #else void pari_stackcheck_init(void *pari_stack_base) { (void) pari_stack_base; PARI_stack_limit = NULL; } #endif /* STACK_CHECK */ /*******************************************************************/ /* HEAP TRAVERSAL */ /*******************************************************************/ struct getheap_t { long n, l; }; /* x is a block, not necessarily a clone [x[0] may not be set] */ static void f_getheap(GEN x, void *D) { struct getheap_t *T = (struct getheap_t*)D; T->n++; T->l += bl_size(x) + BL_HEAD; } GEN getheap(void) { struct getheap_t T = { 0, 0 }; traverseheap(&f_getheap, &T); return mkvec2s(T.n, T.l); } void traverseheap( void(*f)(GEN, void *), void *data ) { GEN x; for (x = cur_block; x; x = bl_prev(x)) f(x, data); } /*********************************************************************/ /* DAEMON / FORK */ /*********************************************************************/ #if defined(HAS_WAITPID) && defined(HAS_SETSID) /* Properly fork a process, detaching from main process group without creating * zombies on exit. Parent returns 1, son returns 0 */ int pari_daemon(void) { pid_t pid = fork(); switch(pid) { case -1: return 1; /* father, fork failed */ case 0: (void)setsid(); /* son becomes process group leader */ if (fork()) _exit(0); /* now son exits, also when fork fails */ break; /* grandson: its father is the son, which exited, * hence father becomes 'init', that'll take care of it */ default: /* father, fork succeeded */ (void)waitpid(pid,NULL,0); /* wait for son to exit, immediate */ return 1; } /* grandson */ return 0; } #else int pari_daemon(void) { pari_err_IMPL("pari_daemon without waitpid & setsid"); return 0; } #endif /*********************************************************************/ /* */ /* SYSTEM INITIALIZATION */ /* */ /*********************************************************************/ static int try_to_recover = 0; THREAD VOLATILE int PARI_SIGINT_block = 0, PARI_SIGINT_pending = 0; /*********************************************************************/ /* SIGNAL HANDLERS */ /*********************************************************************/ static void dflt_sigint_fun(void) { pari_err(e_MISC, "user interrupt"); } #if defined(_WIN32) || defined(__CYGWIN32__) int win32ctrlc = 0, win32alrm = 0; void dowin32ctrlc(void) { win32ctrlc = 0; cb_pari_sigint(); } #endif static void pari_handle_SIGINT(void) { #ifdef _WIN32 if (++win32ctrlc >= 5) _exit(3); #else cb_pari_sigint(); #endif } typedef void (*pari_sighandler_t)(int); pari_sighandler_t os_signal(int sig, pari_sighandler_t f) { #ifdef HAS_SIGACTION struct sigaction sa, oldsa; sa.sa_handler = f; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NODEFER; if (sigaction(sig, &sa, &oldsa)) return NULL; return oldsa.sa_handler; #else return signal(sig,f); #endif } void pari_sighandler(int sig) { const char *msg; #ifndef HAS_SIGACTION /*SYSV reset the signal handler in the handler*/ (void)os_signal(sig,pari_sighandler); #endif switch(sig) { #ifdef SIGBREAK case SIGBREAK: if (PARI_SIGINT_block==1) { PARI_SIGINT_pending=SIGBREAK; mt_sigint(); } else pari_handle_SIGINT(); return; #endif #ifdef SIGINT case SIGINT: if (PARI_SIGINT_block==1) { PARI_SIGINT_pending=SIGINT; mt_sigint(); } else pari_handle_SIGINT(); return; #endif #ifdef SIGSEGV case SIGSEGV: msg="PARI/GP (Segmentation Fault)"; break; #endif #ifdef SIGBUS case SIGBUS: msg="PARI/GP (Bus Error)"; break; #endif #ifdef SIGFPE case SIGFPE: msg="PARI/GP (Floating Point Exception)"; break; #endif #ifdef SIGPIPE case SIGPIPE: { pariFILE *f = GP_DATA->pp->file; if (f && pari_outfile == f->file) { GP_DATA->pp->file = NULL; /* to avoid oo recursion on error */ pari_outfile = stdout; pari_fclose(f); pari_err(e_MISC, "Broken Pipe, resetting file stack..."); } return; /* LCOV_EXCL_LINE */ } #endif default: msg="signal handling"; break; } pari_err_BUG(msg); } void pari_sig_init(void (*f)(int)) { #ifdef SIGBUS (void)os_signal(SIGBUS,f); #endif #ifdef SIGFPE (void)os_signal(SIGFPE,f); #endif #ifdef SIGINT (void)os_signal(SIGINT,f); #endif #ifdef SIGBREAK (void)os_signal(SIGBREAK,f); #endif #ifdef SIGPIPE (void)os_signal(SIGPIPE,f); #endif #ifdef SIGSEGV (void)os_signal(SIGSEGV,f); #endif } /*********************************************************************/ /* STACK AND UNIVERSAL CONSTANTS */ /*********************************************************************/ static void init_universal_constants(void) { gen_0 = (GEN)readonly_constants; gnil = (GEN)readonly_constants+2; gen_1 = (GEN)readonly_constants+4; gen_2 = (GEN)readonly_constants+7; gen_m1 = (GEN)readonly_constants+10; gen_m2 = (GEN)readonly_constants+13; err_e_STACK = (GEN)readonly_constants+16; ghalf = (GEN)readonly_constants+18; } static void pari_init_errcatch(void) { iferr_env = NULL; global_err_data = NULL; } /*********************************************************************/ /* INIT DEFAULTS */ /*********************************************************************/ void pari_init_defaults(void) { long i; initout(1); #ifdef LONG_IS_64BIT precreal = 128; #else precreal = 96; #endif precdl = 16; DEBUGFILES = DEBUGLEVEL = 0; DEBUGMEM = 1; disable_color = 1; logstyle = logstyle_none; current_psfile = pari_strdup("pari.ps"); current_logfile= pari_strdup("pari.log"); pari_logfile = NULL; pari_datadir = os_getenv("GP_DATA_DIR"); if (!pari_datadir) { #if defined(_WIN32) || defined(__CYGWIN32__) if (paricfg_datadir[0]=='@' && paricfg_datadir[1]==0) pari_datadir = win32_datadir(); else #endif pari_datadir = pari_strdup(paricfg_datadir); } else pari_datadir= pari_strdup(pari_datadir); for (i=0; isize and * st->bot. If not enough system memory is available, this can fail. * Return 1 if successful, 0 if failed (in that case, st->size is not * changed) */ static int pari_mainstack_setsize(struct pari_mainstack *st, size_t size) { pari_sp newbot = st->top - size; /* Align newbot to pagesize */ pari_sp alignbot = newbot & ~(pari_sp)(PARI_STACK_ALIGN - 1); if (pari_mainstack_mextend(alignbot, st->top)) { /* Making the memory available did not work: limit vsize to the * current actual stack size. */ st->vsize = st->size; pari_warn(warnstack, st->vsize); return 0; } pari_mainstack_mreset(st->vbot, alignbot); st->bot = newbot; st->size = size; return 1; } #else #define PARI_STACK_ALIGN (0x40UL) static void * pari_mainstack_malloc(size_t s) { return malloc(s); /* NOT pari_malloc, e_MEM would be deadly */ } static void pari_mainstack_mfree(void *s, size_t size) { (void) size; free(s); } static int pari_mainstack_setsize(struct pari_mainstack *st, size_t size) { st->bot = st->top - size; st->size = size; return 1; } #endif static const size_t MIN_STACK = 500032UL; static size_t fix_size(size_t a) { size_t ps = PARI_STACK_ALIGN; size_t b = a & ~(ps - 1); /* Align */ if (b < a && b < ~(ps - 1)) b += ps; if (b < MIN_STACK) b = MIN_STACK; return b; } static void pari_mainstack_alloc(int numerr, struct pari_mainstack *st, size_t rsize, size_t vsize) { size_t sizemax = vsize ? vsize: rsize, s = fix_size(sizemax); for (;;) { st->vbot = (pari_sp)pari_mainstack_malloc(s); if (st->vbot) break; if (s == MIN_STACK) pari_err(e_MEM); /* no way out. Die */ s = fix_size(s >> 1); pari_warn(numerr, s); } st->vsize = vsize ? s: 0; st->rsize = minuu(rsize, s); st->top = st->vbot+s; if (!pari_mainstack_setsize(st, st->rsize)) { /* This should never happen since we only decrease the allocated space */ pari_err(e_MEM); } st->memused = 0; } static void pari_mainstack_free(struct pari_mainstack *st) { pari_mainstack_mfree((void*)st->vbot, st->vsize ? st->vsize : fix_size(st->rsize)); st->top = st->bot = st->vbot = 0; st->size = st->vsize = 0; } static void pari_mainstack_resize(struct pari_mainstack *st, size_t rsize, size_t vsize) { BLOCK_SIGINT_START; pari_mainstack_free(st); pari_mainstack_alloc(warnstack, st, rsize, vsize); BLOCK_SIGINT_END; } static void pari_mainstack_use(struct pari_mainstack *st) { pari_mainstack = st; avma = st->top; } static void paristack_alloc(size_t rsize, size_t vsize) { pari_mainstack_alloc(warnstack, pari_mainstack, rsize, vsize); pari_mainstack_use(pari_mainstack); } void paristack_setsize(size_t rsize, size_t vsize) { pari_mainstack_resize(pari_mainstack, rsize, vsize); pari_mainstack_use(pari_mainstack); } void parivstack_resize(ulong newsize) { size_t s; if (newsize && newsize < pari_mainstack->rsize) pari_err_DIM("stack sizes [parisizemax < parisize]"); if (newsize == pari_mainstack->vsize) return; evalstate_reset(); paristack_setsize(pari_mainstack->rsize, newsize); s = pari_mainstack->vsize ? pari_mainstack->vsize : pari_mainstack->rsize; if (DEBUGMEM) pari_warn(warner,"new maximum stack size = %lu (%.3f Mbytes)", s, s/1048576.); pari_init_errcatch(); cb_pari_err_recover(-1); } void paristack_newrsize(ulong newsize) { size_t s, vsize = pari_mainstack->vsize; if (!newsize) newsize = pari_mainstack->rsize << 1; if (newsize != pari_mainstack->rsize) pari_mainstack_resize(pari_mainstack, newsize, vsize); evalstate_reset(); s = pari_mainstack->rsize; if (DEBUGMEM) pari_warn(warner,"new stack size = %lu (%.3f Mbytes)", s, s/1048576.); pari_init_errcatch(); cb_pari_err_recover(-1); } void paristack_resize(ulong newsize) { long size = pari_mainstack->size; if (!newsize) newsize = 2 * size; newsize = minuu(newsize, pari_mainstack->vsize); if (newsize <= pari_mainstack->size) return; if (pari_mainstack_setsize(pari_mainstack, newsize)) { if (DEBUGMEM) pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size); } else { pari_mainstack_setsize(pari_mainstack, size); pari_err(e_STACK); } } void parivstack_reset(void) { pari_mainstack_setsize(pari_mainstack, pari_mainstack->rsize); if (avma < pari_mainstack->bot) pari_err_BUG("parivstack_reset [avma < bot]"); } /* Enlarge the stack if needed such that the unused portion of the stack * (between bot and avma) is large enough to contain x longs. */ void new_chunk_resize(size_t x) { if (pari_mainstack->vsize==0 || x > (avma-pari_mainstack->vbot) / sizeof(long)) pari_err(e_STACK); while (x > (avma-pari_mainstack->bot) / sizeof(long)) paristack_resize(0); } /*********************************************************************/ /* PARI THREAD */ /*********************************************************************/ /* Initial PARI thread structure t with a stack of size s and virtual size v * and argument arg */ void pari_thread_valloc(struct pari_thread *t, size_t s, size_t v, GEN arg) { pari_mainstack_alloc(warnstackthread, &t->st,s,v); t->data = arg; } /* Initial PARI thread structure t with a stack of size s and * argument arg */ void pari_thread_alloc(struct pari_thread *t, size_t s, GEN arg) { pari_mainstack_alloc(warnstackthread, &t->st,s,0); t->data = arg; } void pari_thread_free(struct pari_thread *t) { pari_mainstack_free(&t->st); } void pari_thread_init(void) { pari_init_blocks(); pari_init_errcatch(); pari_init_rand(); pari_init_floats(); pari_init_parser(); pari_init_compiler(); pari_init_evaluator(); pari_init_files(); pari_thread_init_primetab(); pari_thread_init_seadata(); } void pari_thread_sync(void) { pari_pthread_init_primetab(); pari_pthread_init_seadata(); pari_pthread_init_varstate(); } void pari_thread_close(void) { pari_thread_close_files(); pari_close_evaluator(); pari_close_compiler(); pari_close_parser(); pari_close_floats(); pari_close_blocks(); } GEN pari_thread_start(struct pari_thread *t) { pari_mainstack_use(&t->st); pari_thread_init(); pari_thread_init_varstate(); return t->data; } /*********************************************************************/ /* LIBPARI INIT / CLOSE */ /*********************************************************************/ static void pari_exit(void) { err_printf(" *** Error in the PARI system. End of program.\n"); exit(1); } static void dflt_err_recover(long errnum) { (void) errnum; pari_exit(); } static void dflt_pari_quit(long err) { (void)err; /*do nothing*/; } static int pari_err_display(GEN err); /* initialize PARI data. Initialize [new|old]fun to NULL for default set. */ void pari_init_opts(size_t parisize, ulong maxprime, ulong init_opts) { ulong u; pari_mt_nbthreads = 0; cb_pari_quit = dflt_pari_quit; cb_pari_init_histfile = NULL; cb_pari_get_line_interactive = NULL; cb_pari_fgets_interactive = NULL; cb_pari_whatnow = NULL; cb_pari_handle_exception = NULL; cb_pari_err_handle = pari_err_display; cb_pari_pre_recover = NULL; cb_pari_break_loop = NULL; cb_pari_is_interactive = NULL; cb_pari_start_output = NULL; cb_pari_sigint = dflt_sigint_fun; if (init_opts&INIT_JMPm) cb_pari_err_recover = dflt_err_recover; pari_stackcheck_init(&u); pari_init_homedir(); if (init_opts&INIT_DFTm) { pari_init_defaults(); GP_DATA = default_gp_data(); pari_init_paths(); } pari_mainstack = (struct pari_mainstack *) malloc(sizeof(*pari_mainstack)); paristack_alloc(parisize, 0); init_universal_constants(); diffptr = NULL; if (!(init_opts&INIT_noPRIMEm)) pari_init_primes(maxprime); if (!(init_opts&INIT_noINTGMPm)) pari_kernel_init(); pari_init_graphics(); pari_init_primetab(); pari_init_seadata(); pari_thread_init(); pari_init_functions(); pari_var_init(); pari_init_timer(); pari_init_buffers(); (void)getabstime(); try_to_recover = 1; if (!(init_opts&INIT_noIMTm)) pari_mt_init(); if ((init_opts&INIT_SIGm)) pari_sig_init(pari_sighandler); } void pari_init(size_t parisize, ulong maxprime) { pari_init_opts(parisize, maxprime, INIT_JMPm | INIT_SIGm | INIT_DFTm); } void pari_close_opts(ulong init_opts) { long i; BLOCK_SIGINT_START; if ((init_opts&INIT_SIGm)) pari_sig_init(SIG_DFL); if (!(init_opts&INIT_noIMTm)) pari_mt_close(); for (i = 0; i < functions_tblsz; i++) { entree *ep = functions_hash[i]; while (ep) { entree *EP = ep->next; if (!EpSTATIC(ep)) { freeep(ep); free(ep); } ep = EP; } } pari_var_close(); pari_close_mf(); pari_thread_close(); pari_close_files(); pari_close_homedir(); if (!(init_opts&INIT_noINTGMPm)) pari_kernel_close(); free((void*)functions_hash); free((void*)defaults_hash); if (diffptr) pari_close_primes(); free(current_logfile); free(current_psfile); pari_mainstack_free(pari_mainstack); free((void*)pari_mainstack); pari_stack_delete(&s_MODULES); if (pari_datadir) free(pari_datadir); if (init_opts&INIT_DFTm) { /* delete GP_DATA */ pari_close_paths(); if (GP_DATA->hist->v) free((void*)GP_DATA->hist->v); if (GP_DATA->pp->cmd) free((void*)GP_DATA->pp->cmd); if (GP_DATA->help) free((void*)GP_DATA->help); if (GP_DATA->plothsizes) free((void*)GP_DATA->plothsizes); if (GP_DATA->colormap) pari_free(GP_DATA->colormap); if (GP_DATA->graphcolors) pari_free(GP_DATA->graphcolors); free((void*)GP_DATA->prompt); free((void*)GP_DATA->prompt_cont); free((void*)GP_DATA->histfile); } BLOCK_SIGINT_END; } void pari_close(void) { pari_close_opts(INIT_JMPm | INIT_SIGm | INIT_DFTm); } /*******************************************************************/ /* */ /* ERROR RECOVERY */ /* */ /*******************************************************************/ void gp_context_save(struct gp_context* rec) { rec->prettyp = GP_DATA->fmt->prettyp; rec->listloc = next_block; rec->iferr_env = iferr_env; rec->err_data = global_err_data; varstate_save(&rec->var); evalstate_save(&rec->eval); parsestate_save(&rec->parse); filestate_save(&rec->file); } void gp_context_restore(struct gp_context* rec) { long i; if (!try_to_recover) return; /* disable gp_context_restore() and SIGINT */ try_to_recover = 0; BLOCK_SIGINT_START if (DEBUGMEM>2) err_printf("entering recover(), loc = %ld\n", rec->listloc); evalstate_restore(&rec->eval); parsestate_restore(&rec->parse); filestate_restore(&rec->file); global_err_data = rec->err_data; iferr_env = rec->iferr_env; GP_DATA->fmt->prettyp = rec->prettyp; for (i = 0; i < functions_tblsz; i++) { entree *ep = functions_hash[i]; while (ep) { entree *EP = ep->next; switch(EpVALENCE(ep)) { case EpVAR: while (pop_val_if_newer(ep,rec->listloc)) /* empty */; break; case EpNEW: break; } ep = EP; } } varstate_restore(&rec->var); if (DEBUGMEM>2) err_printf("leaving recover()\n"); BLOCK_SIGINT_END try_to_recover = 1; } static void err_recover(long numerr) { if (cb_pari_pre_recover) cb_pari_pre_recover(numerr); evalstate_reset(); killallfiles(); pari_init_errcatch(); cb_pari_err_recover(numerr); } static void err_init(void) { /* make sure pari_err msg starts at the beginning of line */ if (!pari_last_was_newline()) pari_putc('\n'); pariOut->flush(); pariErr->flush(); out_term_color(pariErr, c_ERR); } static void err_init_msg(int user) { const char *gp_function_name; out_puts(pariErr, " *** "); if (!user && (gp_function_name = closure_func_err())) out_printf(pariErr, "%s: ", gp_function_name); else out_puts(pariErr, " "); } void pari_warn(int numerr, ...) { char *ch1; va_list ap; va_start(ap,numerr); err_init(); err_init_msg(numerr==warnuser || numerr==warnstack); switch (numerr) { case warnuser: out_puts(pariErr, "user warning: "); out_print0(pariErr, NULL, va_arg(ap, GEN), f_RAW); break; case warnmem: out_puts(pariErr, "collecting garbage in "); ch1=va_arg(ap, char*); out_vprintf(pariErr, ch1,ap); out_putc(pariErr, '.'); break; case warner: out_puts(pariErr, "Warning: "); ch1=va_arg(ap, char*); out_vprintf(pariErr, ch1,ap); out_putc(pariErr, '.'); break; case warnprec: out_vprintf(pariErr, "Warning: increasing prec in %s; new prec = %ld", ap); break; case warnfile: out_puts(pariErr, "Warning: failed to "), ch1 = va_arg(ap, char*); out_printf(pariErr, "%s: %s", ch1, va_arg(ap, char*)); break; case warnstack: case warnstackthread: { ulong s = va_arg(ap, ulong); char buf[128]; const char * stk = numerr == warnstackthread || mt_is_thread() ? "thread": "PARI"; sprintf(buf,"Warning: not enough memory, new %s stack %lu", stk, s); out_puts(pariErr,buf); break; } } va_end(ap); out_term_color(pariErr, c_NONE); out_putc(pariErr, '\n'); pariErr->flush(); } void pari_sigint(const char *time_s) { int recover=0; BLOCK_SIGALRM_START err_init(); closure_err(0); err_init_msg(0); out_puts(pariErr, "user interrupt after "); out_puts(pariErr, time_s); out_term_color(pariErr, c_NONE); pariErr->flush(); if (cb_pari_handle_exception) recover = cb_pari_handle_exception(-1); if (!recover && !block) PARI_SIGINT_pending = 0; BLOCK_SIGINT_END if (!recover) err_recover(e_MISC); } #define retmkerr2(x,y)\ do { GEN _v = cgetg(3, t_ERROR);\ _v[1] = (x);\ gel(_v,2) = (y); return _v; } while(0) #define retmkerr3(x,y,z)\ do { GEN _v = cgetg(4, t_ERROR);\ _v[1] = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z); return _v; } while(0) #define retmkerr4(x,y,z,t)\ do { GEN _v = cgetg(5, t_ERROR);\ _v[1] = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t); return _v; } while(0) #define retmkerr5(x,y,z,t,u)\ do { GEN _v = cgetg(6, t_ERROR);\ _v[1] = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t);\ gel(_v,5) = (u); return _v; } while(0) #define retmkerr6(x,y,z,t,u,v)\ do { GEN _v = cgetg(7, t_ERROR);\ _v[1] = (x);\ gel(_v,2) = (y);\ gel(_v,3) = (z);\ gel(_v,4) = (t);\ gel(_v,5) = (u);\ gel(_v,6) = (v); return _v; } while(0) static GEN pari_err2GEN(long numerr, va_list ap) { switch ((enum err_list) numerr) { case e_SYNTAX: { const char *msg = va_arg(ap, char*); const char *s = va_arg(ap,char *); const char *entry = va_arg(ap,char *); retmkerr3(numerr,strtoGENstr(msg), mkvecsmall2((long)s,(long)entry)); } case e_MISC: case e_ALARM: { const char *ch1 = va_arg(ap, char*); retmkerr2(numerr, gvsprintf(ch1,ap)); } case e_NOTFUNC: case e_USER: retmkerr2(numerr,va_arg(ap, GEN)); case e_FILE: { const char *f = va_arg(ap, const char*); retmkerr3(numerr, strtoGENstr(f), strtoGENstr(va_arg(ap, char*))); } case e_FILEDESC: { const char *f = va_arg(ap, const char*); retmkerr3(numerr, strtoGENstr(f), stoi(va_arg(ap, long))); } case e_OVERFLOW: case e_IMPL: case e_DIM: case e_CONSTPOL: case e_ROOTS0: case e_FLAG: case e_PREC: case e_BUG: case e_ARCH: case e_PACKAGE: retmkerr2(numerr, strtoGENstr(va_arg(ap, char*))); case e_MODULUS: case e_VAR: { const char *f = va_arg(ap, const char*); GEN x = va_arg(ap, GEN); GEN y = va_arg(ap, GEN); retmkerr4(numerr, strtoGENstr(f), x,y); } case e_INV: case e_IRREDPOL: case e_PRIME: case e_SQRTN: case e_TYPE: { const char *f = va_arg(ap, const char*); GEN x = va_arg(ap, GEN); retmkerr3(numerr, strtoGENstr(f), x); } case e_COPRIME: case e_OP: case e_TYPE2: { const char *f = va_arg(ap, const char*); GEN x = va_arg(ap, GEN); GEN y = va_arg(ap, GEN); retmkerr4(numerr,strtoGENstr(f),x,y); } case e_COMPONENT: { const char *f= va_arg(ap, const char *); const char *op = va_arg(ap, const char *); GEN l = va_arg(ap, GEN); GEN x = va_arg(ap, GEN); retmkerr5(numerr,strtoGENstr(f),strtoGENstr(op),l,x); } case e_DOMAIN: { const char *f = va_arg(ap, const char*); const char *v = va_arg(ap, const char *); const char *op = va_arg(ap, const char *); GEN l = va_arg(ap, GEN); GEN x = va_arg(ap, GEN); retmkerr6(numerr,strtoGENstr(f),strtoGENstr(v),strtoGENstr(op),l,x); } case e_PRIORITY: { const char *f = va_arg(ap, const char*); GEN x = va_arg(ap, GEN); const char *op = va_arg(ap, const char *); long v = va_arg(ap, long); retmkerr5(numerr,strtoGENstr(f),x,strtoGENstr(op),stoi(v)); } case e_MAXPRIME: retmkerr2(numerr, utoi(va_arg(ap, ulong))); case e_STACK: return err_e_STACK; case e_STACKTHREAD: retmkerr3(numerr, utoi(va_arg(ap, ulong)), utoi(va_arg(ap, ulong))); default: return mkerr(numerr); } } static char * type_dim(GEN x) { char *v = stack_malloc(64); switch(typ(x)) { case t_MAT: { long l = lg(x), r = (l == 1)? 1: lgcols(x); sprintf(v, "t_MAT (%ldx%ld)", r-1,l-1); break; } case t_COL: sprintf(v, "t_COL (%ld elts)", lg(x)-1); break; case t_VEC: sprintf(v, "t_VEC (%ld elts)", lg(x)-1); break; default: v = (char*)type_name(typ(x)); } return v; } static char * gdisplay(GEN x) { char *s = GENtostr_raw(x); if (strlen(s) < 1600) return s; if (! GP_DATA->breakloop) return (char*)"(...)"; return stack_sprintf("\n *** (...) Huge %s omitted; you can access it via dbg_err()", type_name(typ(x))); } char * pari_err2str(GEN e) { long numerr = err_get_num(e); switch ((enum err_list) numerr) { case e_ALARM: return pari_sprintf("alarm interrupt after %Ps.",gel(e,2)); case e_MISC: return pari_sprintf("%Ps.",gel(e,2)); case e_ARCH: return pari_sprintf("sorry, '%Ps' not available on this system.",gel(e,2)); case e_BUG: return pari_sprintf("bug in %Ps, please report.",gel(e,2)); case e_CONSTPOL: return pari_sprintf("constant polynomial in %Ps.", gel(e,2)); case e_COPRIME: return pari_sprintf("elements not coprime in %Ps:\n %s\n %s", gel(e,2), gdisplay(gel(e,3)), gdisplay(gel(e,4))); case e_DIM: return pari_sprintf("inconsistent dimensions in %Ps.", gel(e,2)); case e_FILE: return pari_sprintf("error opening %Ps: `%Ps'.", gel(e,2), gel(e,3)); case e_FILEDESC: return pari_sprintf("invalid file descriptor in %Ps [%Ps]", gel(e,2), gel(e,3)); case e_FLAG: return pari_sprintf("invalid flag in %Ps.", gel(e,2)); case e_IMPL: return pari_sprintf("sorry, %Ps is not yet implemented.", gel(e,2)); case e_PACKAGE: return pari_sprintf("package %Ps is required, please install it.", gel(e,2)); case e_INV: return pari_sprintf("impossible inverse in %Ps: %s.", gel(e,2), gdisplay(gel(e,3))); case e_IRREDPOL: return pari_sprintf("not an irreducible polynomial in %Ps: %s.", gel(e,2), gdisplay(gel(e,3))); case e_MAXPRIME: { const char * msg = "not enough precomputed primes"; ulong c = itou(gel(e,2)); if (c) return pari_sprintf("%s, need primelimit ~ %lu.",msg, c); else return pari_strdup(msg); } case e_MEM: return pari_strdup("not enough memory"); case e_MODULUS: { GEN x = gel(e,3), y = gel(e,4); return pari_sprintf("inconsistent moduli in %Ps: %s != %s", gel(e,2), gdisplay(x), gdisplay(y)); } case e_NONE: return NULL; case e_NOTFUNC: return pari_strdup("not a function in function call"); case e_OP: case e_TYPE2: { pari_sp av = avma; char *v; const char *f, *op = GSTR(gel(e,2)); const char *what = numerr == e_OP? "inconsistent": "forbidden"; GEN x = gel(e,3); GEN y = gel(e,4); switch(*op) { case '+': f = "addition"; break; case '*': f = "multiplication"; break; case '/': case '%': case '\\': f = "division"; break; case '=': op = "-->"; f = "assignment"; break; default: f = op; op = ","; break; } v = pari_sprintf("%s %s %s %s %s.", what,f,type_dim(x),op,type_dim(y)); avma = av; return v; } case e_COMPONENT: { const char *f= GSTR(gel(e,2)); const char *op= GSTR(gel(e,3)); GEN l = gel(e,4); if (!*f) return pari_sprintf("non-existent component: index %s %Ps",op,l); return pari_sprintf("non-existent component in %s: index %s %Ps",f,op,l); } case e_DOMAIN: { const char *f = GSTR(gel(e,2)); const char *v = GSTR(gel(e,3)); const char *op= GSTR(gel(e,4)); GEN l = gel(e,5); if (!*op) return pari_sprintf("domain error in %s: %s out of range",f,v); return pari_sprintf("domain error in %s: %s %s %Ps",f,v,op,l); } case e_PRIORITY: { const char *f = GSTR(gel(e,2)); long vx = gvar(gel(e,3)); const char *op= GSTR(gel(e,4)); long v = itos(gel(e,5)); return pari_sprintf("incorrect priority in %s: variable %Ps %s %Ps",f, pol_x(vx), op, pol_x(v)); } case e_OVERFLOW: return pari_sprintf("overflow in %Ps.", gel(e,2)); case e_PREC: return pari_sprintf("precision too low in %Ps.", gel(e,2)); case e_PRIME: return pari_sprintf("not a prime number in %Ps: %s.", gel(e,2), gdisplay(gel(e,3))); case e_ROOTS0: return pari_sprintf("zero polynomial in %Ps.", gel(e,2)); case e_SQRTN: return pari_sprintf("not an n-th power residue in %Ps: %s.", gel(e,2), gdisplay(gel(e,3))); case e_STACK: case e_STACKTHREAD: { const char *stack = numerr == e_STACK? "PARI": "thread"; const char *var = numerr == e_STACK? "parisizemax": "threadsizemax"; size_t rsize = numerr == e_STACKTHREAD && GP_DATA->threadsize ? GP_DATA->threadsize: pari_mainstack->rsize; size_t vsize = numerr == e_STACK? pari_mainstack->vsize: GP_DATA->threadsizemax; char *buf = (char *) pari_malloc(512*sizeof(char)); if (vsize) { sprintf(buf, "the %s stack overflows !\n" " current stack size: %lu (%.3f Mbytes)\n" " [hint] you can increase '%s' using default()\n", stack, (ulong)vsize, (double)vsize/1048576., var); } else { sprintf(buf, "the %s stack overflows !\n" " current stack size: %lu (%.3f Mbytes)\n" " [hint] set '%s' to a non-zero value in your GPRC\n", stack, (ulong)rsize, (double)rsize/1048576., var); } return buf; } case e_SYNTAX: return pari_strdup(GSTR(gel(e,2))); case e_TYPE: return pari_sprintf("incorrect type in %Ps (%s).", gel(e,2), type_name(typ(gel(e,3)))); case e_USER: return pari_sprint0("user error: ", gel(e,2), f_RAW); case e_VAR: { GEN x = gel(e,3), y = gel(e,4); return pari_sprintf("inconsistent variables in %Ps, %Ps != %Ps.", gel(e,2), pol_x(varn(x)), pol_x(varn(y))); } } return NULL; /*LCOV_EXCL_LINE*/ } static int pari_err_display(GEN err) { long numerr=err_get_num(err); err_init(); if (numerr==e_SYNTAX) { const char *msg = GSTR(gel(err,2)); const char *s = (const char *) gmael(err,3,1); const char *entry = (const char *) gmael(err,3,2); print_errcontext(pariErr, msg, s, entry); } else { char *s = pari_err2str(err); closure_err(0); err_init_msg(numerr==e_USER); pariErr->puts(s); if (numerr==e_NOTFUNC) { GEN fun = gel(err,2); if (gequalX(fun)) { entree *ep = varentries[varn(fun)]; const char *s = ep->name; if (cb_pari_whatnow) cb_pari_whatnow(pariErr,s,1); } } pari_free(s); } out_term_color(pariErr, c_NONE); pariErr->flush(); return 0; } void pari_err(int numerr, ...) { va_list ap; GEN E; va_start(ap,numerr); if (numerr) E = pari_err2GEN(numerr,ap); else { E = va_arg(ap,GEN); numerr = err_get_num(E); } global_err_data = E; if (*iferr_env) longjmp(*iferr_env, numerr); mt_err_recover(numerr); va_end(ap); if (cb_pari_err_handle && cb_pari_err_handle(E)) return; if (cb_pari_handle_exception && cb_pari_handle_exception(numerr)) return; err_recover(numerr); } GEN pari_err_last(void) { return global_err_data; } const char * numerr_name(long numerr) { switch ((enum err_list) numerr) { case e_ALARM: return "e_ALARM"; case e_ARCH: return "e_ARCH"; case e_BUG: return "e_BUG"; case e_COMPONENT: return "e_COMPONENT"; case e_CONSTPOL: return "e_CONSTPOL"; case e_COPRIME: return "e_COPRIME"; case e_DIM: return "e_DIM"; case e_DOMAIN: return "e_DOMAIN"; case e_FILE: return "e_FILE"; case e_FILEDESC: return "e_FILEDESC"; case e_FLAG: return "e_FLAG"; case e_IMPL: return "e_IMPL"; case e_INV: return "e_INV"; case e_IRREDPOL: return "e_IRREDPOL"; case e_MAXPRIME: return "e_MAXPRIME"; case e_MEM: return "e_MEM"; case e_MISC: return "e_MISC"; case e_MODULUS: return "e_MODULUS"; case e_NONE: return "e_NONE"; case e_NOTFUNC: return "e_NOTFUNC"; case e_OP: return "e_OP"; case e_OVERFLOW: return "e_OVERFLOW"; case e_PACKAGE: return "e_PACKAGE"; case e_PREC: return "e_PREC"; case e_PRIME: return "e_PRIME"; case e_PRIORITY: return "e_PRIORITY"; case e_ROOTS0: return "e_ROOTS0"; case e_SQRTN: return "e_SQRTN"; case e_STACK: return "e_STACK"; case e_SYNTAX: return "e_SYNTAX"; case e_STACKTHREAD: return "e_STACKTHREAD"; case e_TYPE2: return "e_TYPE2"; case e_TYPE: return "e_TYPE"; case e_USER: return "e_USER"; case e_VAR: return "e_VAR"; } return "invalid error number"; } long name_numerr(const char *s) { if (!strcmp(s,"e_ALARM")) return e_ALARM; if (!strcmp(s,"e_ARCH")) return e_ARCH; if (!strcmp(s,"e_BUG")) return e_BUG; if (!strcmp(s,"e_COMPONENT")) return e_COMPONENT; if (!strcmp(s,"e_CONSTPOL")) return e_CONSTPOL; if (!strcmp(s,"e_COPRIME")) return e_COPRIME; if (!strcmp(s,"e_DIM")) return e_DIM; if (!strcmp(s,"e_DOMAIN")) return e_DOMAIN; if (!strcmp(s,"e_FILE")) return e_FILE; if (!strcmp(s,"e_FILEDESC")) return e_FILEDESC; if (!strcmp(s,"e_FLAG")) return e_FLAG; if (!strcmp(s,"e_IMPL")) return e_IMPL; if (!strcmp(s,"e_INV")) return e_INV; if (!strcmp(s,"e_IRREDPOL")) return e_IRREDPOL; if (!strcmp(s,"e_MAXPRIME")) return e_MAXPRIME; if (!strcmp(s,"e_MEM")) return e_MEM; if (!strcmp(s,"e_MISC")) return e_MISC; if (!strcmp(s,"e_MODULUS")) return e_MODULUS; if (!strcmp(s,"e_NONE")) return e_NONE; if (!strcmp(s,"e_NOTFUNC")) return e_NOTFUNC; if (!strcmp(s,"e_OP")) return e_OP; if (!strcmp(s,"e_OVERFLOW")) return e_OVERFLOW; if (!strcmp(s,"e_PACKAGE")) return e_PACKAGE; if (!strcmp(s,"e_PREC")) return e_PREC; if (!strcmp(s,"e_PRIME")) return e_PRIME; if (!strcmp(s,"e_PRIORITY")) return e_PRIORITY; if (!strcmp(s,"e_ROOTS0")) return e_ROOTS0; if (!strcmp(s,"e_SQRTN")) return e_SQRTN; if (!strcmp(s,"e_STACK")) return e_STACK; if (!strcmp(s,"e_SYNTAX")) return e_SYNTAX; if (!strcmp(s,"e_TYPE")) return e_TYPE; if (!strcmp(s,"e_TYPE2")) return e_TYPE2; if (!strcmp(s,"e_USER")) return e_USER; if (!strcmp(s,"e_VAR")) return e_VAR; pari_err(e_MISC,"unknown error name"); return -1; /* LCOV_EXCL_LINE */ } GEN errname(GEN err) { if (typ(err)!=t_ERROR) pari_err_TYPE("errname",err); return strtoGENstr(numerr_name(err_get_num(err))); } /* Try f (trapping error e), recover using r (break_loop, if NULL) */ GEN trap0(const char *e, GEN r, GEN f) { long numerr = CATCH_ALL; GEN x; if (!e || !*e) numerr = CATCH_ALL; else numerr = name_numerr(e); if (!f) { pari_warn(warner,"default handlers are no longer supported --> ignored"); return gnil; } x = closure_trapgen(f, numerr); if (x == (GEN)1L) x = r? closure_evalgen(r): gnil; return x; } /*******************************************************************/ /* */ /* CLONING & COPY */ /* Replicate an existing GEN */ /* */ /*******************************************************************/ /* lontyp[tx] = 0 (non recursive type) or number of codewords for type tx */ const long lontyp[] = { 0,0,0,1,1,2,1,2,1,1, 2,2,0,1,1,1,1,1,1,1, 2,0,0,2,2,1 }; static GEN list_internal_copy(GEN z, long nmax) { long i, l; GEN a; if (!z) return NULL; l = lg(z); a = newblock(nmax+1); for (i = 1; i < l; i++) gel(a,i) = gel(z,i)? gclone(gel(z,i)): gen_0; a[0] = z[0]; return a; } static void listassign(GEN x, GEN y) { long nmax = list_nmax(x); GEN L = list_data(x); if (!nmax && L) nmax = lg(L) + 32; /* not malloc'ed yet */ y[1] = evaltyp(list_typ(x))|evallg(nmax); list_data(y) = list_internal_copy(L, nmax); } /* transform a non-malloced list (e.g. from gtolist or gtomap) to a malloced * list suitable for listput */ GEN listinit(GEN x) { GEN y = cgetg(3, t_LIST); listassign(x, y); return y; } /* copy list on the PARI stack */ GEN listcopy(GEN x) { GEN y = mklist(), L = list_data(x); if (L) list_data(y) = gcopy(L); y[1] = evaltyp(list_typ(x)); return y; } GEN gcopy(GEN x) { long tx = typ(x), lx, i; GEN y; switch(tx) { /* non recursive types */ case t_INT: return signe(x)? icopy(x): gen_0; case t_REAL: case t_STR: case t_VECSMALL: return leafcopy(x); /* one more special case */ case t_LIST: return listcopy(x); } y = cgetg_copy(x, &lx); if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; } for (; irebase = &shiftaddress; p->len = t; p->x = gcopy_av0(x, &AVMA); p->base= (GEN)AVMA; return p; } /* same, writing t_INT in canonical native form */ GENbin* copy_bin_canon(GEN x) { long t = taille0_canon(x); GENbin *p = (GENbin*)pari_malloc(sizeof(GENbin) + t*sizeof(long)); pari_sp AVMA = (pari_sp)(GENbinbase(p) + t); p->rebase = &shiftaddress_canon; p->len = t; p->x = gcopy_av0_canon(x, &AVMA); p->base= (GEN)AVMA; return p; } GEN gclone(GEN x) { long i,lx,tx = typ(x), t = gsizeclone(x); GEN y = newblock(t); switch(tx) { /* non recursive types */ case t_INT: lx = lgefint(x); y[0] = evaltyp(t_INT)|evallg(lx); for (i=1; i y) { lswap(*x, *y); x = int_precW(x); y++; } break; } case t_REAL: case t_STR: case t_VECSMALL: break; /* one more special case */ case t_LIST: { GEN Lx = list_data(x); if (Lx) { pari_sp av = avma; GEN L = (GEN)((long)Lx+dec); shiftaddress_canon(L, dec); list_data(x) = list_internal_copy(L, lg(L)); avma = av; } break; } default: lx = lg(x); for (i=lontyp[tx]; i= lg(v)) pari_err_TYPE("obj_check", S); O = gel(v,K); return isintzero(O)? NULL: O; } GEN obj_checkbuild(GEN S, long tag, GEN (*build)(GEN)) { GEN O = obj_check(S, tag); if (!O) { pari_sp av = avma; O = obj_insert(S, tag, build(S)); avma = av; } return O; } GEN obj_checkbuild_prec(GEN S, long tag, GEN (*build)(GEN,long), long (*pr)(GEN), long prec) { pari_sp av = avma; GEN w = obj_check(S, tag); if (!w || pr(w) < prec) w = obj_insert(S, tag, build(S, prec)); avma = av; return gcopy(w); } GEN obj_checkbuild_realprec(GEN S, long tag, GEN (*build)(GEN,long), long prec) { return obj_checkbuild_prec(S,tag,build,gprecision,prec); } GEN obj_checkbuild_padicprec(GEN S, long tag, GEN (*build)(GEN,long), long prec) { return obj_checkbuild_prec(S,tag,build,padicprec_relative,prec); } /* Reset S [last position], freeing all clones */ void obj_free(GEN S) { GEN v = gel(S, lg(S)-1); long i; if (typ(v) != t_VEC) pari_err_TYPE("obj_free", S); for (i = 1; i < lg(v); i++) { GEN o = gel(v,i); gel(v,i) = gen_0; gunclone_deep(o); } } /*******************************************************************/ /* */ /* STACK MANAGEMENT */ /* */ /*******************************************************************/ INLINE void dec_gerepile(pari_sp *x, pari_sp av0, pari_sp av, pari_sp tetpil, size_t dec) { if (*x < av && *x >= av0) { /* update address if in stack */ if (*x < tetpil) *x += dec; else pari_err_BUG("gerepile, significant pointers lost"); } } void gerepileallsp(pari_sp av, pari_sp tetpil, int n, ...) { const pari_sp av0 = avma; const size_t dec = av-tetpil; int i; va_list a; va_start(a, n); (void)gerepile(av,tetpil,NULL); for (i=0; i av) { pari_warn(warner,"bad object %Ps",x); return 0; } tx = typ(x); if (! is_recursive_t(tx)) return 1; lx = lg(x); for (i=lontyp[tx]; iltop in gerepile"); /* dec_gerepile(&q, av0, av, tetpil, dec), saving 1 comparison */ if (q >= (GEN)av0 && q < (GEN)tetpil) q = (GEN) (((pari_sp)q) + dec); for (x = (GEN)av, a = (GEN)tetpil; a > (GEN)av0; ) *--x = *--a; avma = (pari_sp)x; while (x < (GEN)av) { const long tx = typ(x), lx = lg(x); if (! is_recursive_t(tx)) { x += lx; continue; } a = x + lontyp[tx]; x += lx; for ( ; a < x; a++) dec_gerepile((pari_sp*)a, av0, av, tetpil, dec); } return q; } void fill_stack(void) { GEN x = ((GEN)pari_mainstack->bot); while (x < (GEN)avma) *x++ = 0xfefefefeUL; } void debug_stack(void) { pari_sp top = pari_mainstack->top, bot = pari_mainstack->bot; GEN z; err_printf("bot=0x%lx\ttop=0x%lx\tavma=0x%lx\n", bot, top, avma); for (z = ((GEN)top)-1; z >= (GEN)avma; z--) err_printf("%p:\t0x%lx\t%lu\n",z,*z,*z); } void setdebugvar(long n) { DEBUGVAR=n; } long getdebugvar(void) { return DEBUGVAR; } long getstack(void) { return pari_mainstack->top-avma; } /*******************************************************************/ /* */ /* timer_delay */ /* */ /*******************************************************************/ #if defined(USE_CLOCK_GETTIME) #if defined(_POSIX_THREAD_CPUTIME) static THREAD clockid_t time_type = CLOCK_THREAD_CPUTIME_ID; #else static const THREAD clockid_t time_type = CLOCK_PROCESS_CPUTIME_ID; #endif static void pari_init_timer(void) { #if defined(_POSIX_THREAD_CPUTIME) time_type = CLOCK_PROCESS_CPUTIME_ID; #endif } void timer_start(pari_timer *T) { struct timespec t; clock_gettime(time_type,&t); T->us = t.tv_nsec / 1000; T->s = t.tv_sec; } #elif defined(USE_GETRUSAGE) #ifdef RUSAGE_THREAD static THREAD int rusage_type = RUSAGE_THREAD; #else static const THREAD int rusage_type = RUSAGE_SELF; #endif /*RUSAGE_THREAD*/ static void pari_init_timer(void) { #ifdef RUSAGE_THREAD rusage_type = RUSAGE_SELF; #endif } void timer_start(pari_timer *T) { struct rusage r; getrusage(rusage_type,&r); T->us = r.ru_utime.tv_usec; T->s = r.ru_utime.tv_sec; } #elif defined(USE_FTIME) static void pari_init_timer(void) { } void timer_start(pari_timer *T) { struct timeb t; ftime(&t); T->us = ((long)t.millitm) * 1000; T->s = t.time; } #else static void _get_time(pari_timer *T, long Ticks, long TickPerSecond) { T->us = (long) ((Ticks % TickPerSecond) * (1000000. / TickPerSecond)); T->s = Ticks / TickPerSecond; } # ifdef USE_TIMES static void pari_init_timer(void) { } void timer_start(pari_timer *T) { # ifdef _SC_CLK_TCK long tck = sysconf(_SC_CLK_TCK); # else long tck = CLK_TCK; # endif struct tms t; times(&t); _get_time(T, t.tms_utime, tck); } # elif defined(_WIN32) static void pari_init_timer(void) { } void timer_start(pari_timer *T) { _get_time(T, win32_timer(), 1000); } # else # include # ifndef CLOCKS_PER_SEC # define CLOCKS_PER_SEC 1000000 /* may be false on YOUR system */ # endif static void pari_init_timer(void) { } void timer_start(pari_timer *T) { _get_time(T, clock(), CLOCKS_PER_SEC); } # endif #endif static long timer_aux(pari_timer *T, pari_timer *U) { long s = T->s, us = T->us; timer_start(U); return 1000 * (U->s - s) + (U->us - us + 500) / 1000; } /* return delay, reset timer */ long timer_delay(pari_timer *T) { return timer_aux(T, T); } /* return delay, don't reset timer */ long timer_get(pari_timer *T) { pari_timer t; return timer_aux(T, &t); } static void timer_vprintf(pari_timer *T, const char *format, va_list args) { out_puts(pariErr, "Time "); out_vprintf(pariErr, format,args); out_printf(pariErr, ": %ld\n", timer_delay(T)); pariErr->flush(); } void timer_printf(pari_timer *T, const char *format, ...) { va_list args; va_start(args, format); timer_vprintf(T, format, args); va_end(args); } long timer(void) { static THREAD pari_timer T; return timer_delay(&T);} long gettime(void) { static THREAD pari_timer T; return timer_delay(&T);} static THREAD pari_timer timer2_T, abstimer_T; long timer2(void) { return timer_delay(&timer2_T);} void msgtimer(const char *format, ...) { va_list args; va_start(args, format); timer_vprintf(&timer2_T, format, args); va_end(args); } long getabstime(void) { return timer_get(&abstimer_T);} #if defined(USE_CLOCK_GETTIME) || defined(USE_GETTIMEOFDAY) \ || defined(USE_FTIMEFORWALLTIME) static GEN timetoi(ulong s, ulong m) { pari_sp av = avma; GEN r = addiu(muliu(utoi(s), 1000), m); return gerepileuptoint(av, r); } #endif GEN getwalltime(void) { #if defined(USE_CLOCK_GETTIME) struct timespec t; if (!clock_gettime(CLOCK_REALTIME,&t)) return timetoi(t.tv_sec, (t.tv_nsec + 500000)/1000000); #elif defined(USE_GETTIMEOFDAY) struct timeval tv; if (!gettimeofday(&tv, NULL)) return timetoi(tv.tv_sec, (tv.tv_usec + 500)/1000); #elif defined(USE_FTIMEFORWALLTIME) struct timeb tp; ftime(&tp); return timetoi(tp.time, tp.millitm); #endif return utoi(getabstime()); } /*******************************************************************/ /* */ /* FUNCTIONS KNOWN TO THE ANALYZER */ /* */ /*******************************************************************/ GEN pari_version(void) { const ulong mask = (1UL<>= PARI_VERSION_SHIFT; minor = n & mask; n >>= PARI_VERSION_SHIFT; major = n; if (*paricfg_vcsversion) { const char *ver = paricfg_vcsversion; const char *s = strchr(ver, '-'); char t[8]; const long len = s-ver; GEN v; if (!s || len > 6) pari_err_BUG("pari_version()"); /* paranoia */ memcpy(t, ver, len); t[len] = 0; v = cgetg(6, t_VEC); gel(v,1) = utoi(major); gel(v,2) = utoi(minor); gel(v,3) = utoi(patch); gel(v,4) = stoi( atoi(t) ); gel(v,5) = strtoGENstr(s+1); return v; } else { GEN v = cgetg(4, t_VEC); gel(v,1) = utoi(major); gel(v,2) = utoi(minor); gel(v,3) = utoi(patch); return v; } } /* List of GP functions: generated from the description system. * Format (struct entree) : * char *name : name (under GP). * ulong valence: (EpNEW, EpALIAS,EpVAR, EpINSTALL)|EpSTATIC * void *value : For PREDEFINED FUNCTIONS: C function to call. * For USER FUNCTIONS: pointer to defining data (block) = * entree*: NULL, list of entree (arguments), NULL * char* : function text * long menu : which help section do we belong to * 1: Standard monadic or dyadic OPERATORS * 2: CONVERSIONS and similar elementary functions * 3: functions related to COMBINATORICS * 4: TRANSCENDENTAL functions, etc. * char *code : GP prototype, aka Parser Code (see libpari's manual) * if NULL, use valence instead. * char *help : short help text (init to NULL). * void *pvalue : push_val history. * long arity : maximum number of arguments. * entree *next : next entree (init to NULL, used in hashing code). */ #include "init.h" #include "default.h" pari-2.11.2/src/language/parsec.h0000644000175000017500000001166413201017466015166 0ustar billbill/* Copyright (C) 2006-2008 The PARI group. This file is part of the PARI package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" BEGINEXTERN #include "parse.h" ENDEXTERN #include "anal.h" #include "tree.h" static THREAD int pari_once; static THREAD long pari_discarded; static THREAD const char *pari_lex_start; static THREAD GEN pari_lasterror; static void pari_error(YYLTYPE *yylloc, char **lex, const char *s) { (void) yylloc; (void) lex; if (pari_lasterror) cgiv(pari_lasterror); pari_lasterror=strtoGENstr(s); } static THREAD pari_stack s_node; THREAD node *pari_tree; void pari_init_parser(void) { long i; const char *opname[]={"_||_", "_&&_", "_===_", "_==_", "_!=_", "_>=_", "_>_", "_<=_", "_<_", "_-_","_+_","_<<_", "_>>_", "_%_", "_\\/_", "_\\_", "_/_", "_*_","_^_","__","_--","_++","_-=_", "_+=_", "_<<=_", "_>>=_", "_%=_", "_\\/=_", "_\\=_", "_/=_", "_*=_","+_","-_","!_","_!","_'","_~","[_.._]","[_|_<-_,_]","[_|_<-_,_;_]","%","%#","#_",""}; pari_stack_init(&s_node,sizeof(*pari_tree),(void **)&pari_tree); pari_stack_alloc(&s_node,OPnboperator); parsestate_reset(); for (i=0;inode = s_node.n; state->lex_start = pari_lex_start; state->once = pari_once; state->discarded = pari_discarded; state->lasterror = pari_lasterror; } void parsestate_restore(struct pari_parsestate *state) { s_node.n = state->node; pari_lex_start = state->lex_start; pari_once = state->once; pari_discarded = state->discarded; pari_lasterror = state->lasterror; } GEN pari_compile_str(const char *lex) { pari_sp ltop=avma; GEN code; struct pari_parsestate state; parsestate_save(&state); pari_lex_start = lex; pari_once=1; pari_discarded=0; pari_lasterror=NULL; if (pari_parse((char**)&lex) || pari_discarded) { if (pari_lasterror) compile_err(GSTR(pari_lasterror),lex-1); else /* should not happen */ compile_err("syntax error",lex-1); } avma=ltop; optimizenode(s_node.n-1); code=gp_closure(s_node.n-1); parsestate_restore(&state); return code; } static long newnode(Ffunc f, long x, long y, struct node_loc *loc) { long n=pari_stack_new(&s_node); pari_tree[n].f=f; pari_tree[n].x=x; pari_tree[n].y=y; pari_tree[n].str=loc->start; pari_tree[n].len=loc->end-loc->start; pari_tree[n].flags=0; return n; } static long newconst(long x, struct node_loc *loc) { return newnode(Fconst,x,-1,loc); } static long newopcall(OPerator op, long x, long y, struct node_loc *loc) { if (y==-1) return newnode(Ffunction,op,x,loc); else return newnode(Ffunction,op,newnode(Flistarg,x,y,loc),loc); } static long newopcall3(OPerator op, long x, long y, long z, struct node_loc *loc) { return newopcall(op,newnode(Flistarg,x,y,loc),z,loc); } static long countarg(long n) { long i; for(i=1; pari_tree[n].f==Flistarg; i++) n = pari_tree[n].x; return i; } static long addcurrexpr(long n, long currexpr, struct node_loc *loc) { long y, m = n; while (pari_tree[m].x==OPcomprc) { y = pari_tree[m].y; if (countarg(y)==4) y = pari_tree[y].x; m = pari_tree[y].y; } y = pari_tree[m].y; if (countarg(y)==4) y = pari_tree[y].x; pari_tree[y].y = currexpr; pari_tree[n].str=loc->start; pari_tree[n].len=loc->end-loc->start; return n; } static long newintnode(struct node_loc *loc) { if (loc->end-loc->start<=(long)(1+LOG10_2*BITS_IN_LONG)) { pari_sp ltop=avma; GEN g=strtoi(loc->start); long s; avma=ltop; if (signe(g)==0) return newnode(Fsmall,0,-1,loc); if ((s=itos_or_0(g))) return newnode(Fsmall,s,-1,loc); } return newconst(CSTint,loc); } static long newfunc(CSTtype t, struct node_loc *func, long args, long code, struct node_loc *loc) { long name=newnode(Fentry,newconst(t,func),-1,func); return newnode(Fassign,name,newnode(Flambda,args,code,loc),loc); } pari-2.11.2/src/language/members.c0000644000175000017500000003073613326135265015345 0ustar billbill/* Copyright (C) 2000-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /********************************************************************/ /** **/ /** MEMBER FUNCTIONS **/ /** **/ /********************************************************************/ INLINE int is_ell5(GEN x) { long lx; if (typ(x) != t_VEC) return 0; lx = lg(x); return lx == 17 || (lx == 6 && !is_vec_t(typ(gel(x,2)))); } INLINE int is_ell(GEN x) { long lx = lg(x); return (typ(x) == t_VEC && lx == 17); } static void member_err(const char *s, GEN y) { pari_err_TYPE(s,y); } GEN member_e(GEN x) { GEN y = get_prid(x); if (!y) member_err("e",x); return gel(y,3); } GEN member_f(GEN x) { GEN y = get_prid(x); if (!y) { if (typ(x) == t_FFELT) return utoipos(FF_f(x)); member_err("f",x); } return gel(y,4); } GEN member_p(GEN x) { long t; (void)get_nf(x,&t); switch(t) { case typ_GAL: return gal_get_p(x); case typ_ELL: switch(ell_get_type(x)) { case t_ELL_Fp: case t_ELL_Fq: return ellff_get_p(x); case t_ELL_Qp: return ellQp_get_p(x); default: member_err("p",x); } case typ_MODPR: x = get_prid(x); case typ_PRID: return pr_get_p(x); } switch(typ(x)) { case t_PADIC: return gel(x,2); case t_FFELT: return FF_p_i(x); } member_err("p",x); return NULL; } GEN member_bid(GEN x) { long t; (void)get_nf(x,&t); switch(t) { case typ_BNR: return bnr_get_bid(x); case typ_BIDZ: case typ_BID: return x; } member_err("bid",x); return NULL; } GEN member_bnf(GEN x) { long t; GEN y = get_bnf(x,&t); if (!y) { if (t == typ_ELL && ell_get_type(x) == t_ELL_NF) { y = ellnf_get_bnf(x); if (y) return y; } member_err("bnf",x); } return y; } GEN member_nf(GEN x) { long t; GEN y = get_nf(x,&t); if (!y) { if (t == typ_RNF) return gel(x,10); if (t == typ_ELL && ell_get_type(x) == t_ELL_NF) return ellnf_get_nf(x); member_err("nf",x); } return y; } /* integral basis */ GEN member_zk(GEN x) { long t; GEN y = get_nf(x,&t); if (!y) { switch(t) { case typ_Q: y = cgetg(3,t_VEC); gel(y,1) = gen_1; gel(y,2) = pol_x(varn(gel(x,1))); return y; case typ_RNF: return gel(x,7); } member_err("zk",x); } return nf_get_zk(y); } GEN member_disc(GEN x) /* discriminant */ { long t; GEN y = get_nf(x,&t); if (!y) { switch(t) { case typ_Q : return quad_disc(x); case typ_ELL: return ell_get_disc(x); case typ_RNF: return rnf_get_disc(x); } member_err("disc",x); } return nf_get_disc(y); } GEN member_pol(GEN x) /* polynomial */ { long t; GEN y = get_nf(x,&t); if (!y) { switch(t) { case typ_POL: return x; case typ_Q : return gel(x,1); case typ_GAL: return gal_get_pol(x); case typ_RNF: return rnf_get_pol(x); } if (typ(x)==t_POLMOD) return gel(x,2); if (typ(x)==t_FFELT) return FF_to_FpXQ(x); member_err("pol",x); } return nf_get_pol(y); } GEN member_polabs(GEN x) { long t; (void)get_nf(x,&t); if (t != typ_RNF) member_err("pol",x); return rnf_get_polabs(x); } GEN member_mod(GEN x) /* modulus */ { long t; (void)get_nf(x,&t); switch(t) { case typ_GAL: return gal_get_mod(x); case typ_BNR: return bnr_get_mod(x); case typ_BIDZ: return bid_get_ideal(x); case typ_BID: return bid_get_mod(x); } switch(typ(x)) { case t_INTMOD: case t_POLMOD: case t_QUAD: break; case t_PADIC: return gel(x,3); case t_FFELT: return FF_mod(x); case t_VEC: if (checkmf_i(x)) { GEN T = mf_get_field(x), CHI = mf_get_CHI(x), P = mfcharpol(CHI); return (degpol(T) == 1)? P: (degpol(P) > 1? gmodulo(T, P): T); } else if (checkMF_i(x)) return mfcharpol(MF_get_CHI(x)); default: member_err("mod",x); } return gel(x,1); } GEN member_sign(GEN x) /* signature */ { long t; GEN y = get_nf(x,&t); if (!y) member_err("sign",x); return gel(y,2); } GEN member_r1(GEN x) { return gel(member_sign(x), 1); } GEN member_r2(GEN x) { return gel(member_sign(x), 2); } GEN member_index(GEN x) { long t; GEN y = get_nf(x,&t); if (!y) { if (t == typ_RNF) return rnf_get_index(x); member_err("index",x); } return nf_get_index(y); } /* x assumed to be output by get_nf: ie a t_VEC with length 11 */ static GEN nfmats(GEN x) { GEN y; if (!x) return NULL; y = gel(x,5); if (typ(y) == t_VEC && lg(y) < 8) return NULL; return y; } GEN member_t2(GEN x) /* T2 matrix */ { long t; GEN y = nfmats(get_nf(x,&t)); if (!y) member_err("t2",x); return gram_matrix(gel(y,2)); } GEN member_diff(GEN x) /* different */ { long t; GEN y = nfmats(get_nf(x,&t)); if (!y) member_err("diff",x); return gel(y,5); } GEN member_codiff(GEN x) /* codifferent */ { long t; GEN T, d, Di, nf = get_nf(x,&t), y = nfmats(nf); if (!y) member_err("codiff",x); T = gel(y,4); Di = ZM_inv(T, &d); if (!d) return matid(lg(Di)-1); return RgM_Rg_div(ZM_hnfmodid(Di, d), d); } GEN member_roots(GEN x) /* roots */ { long t; GEN y = get_nf(x,&t); if (!y) { if (t == typ_GAL) return gal_get_roots(x); if (t == typ_ELL) switch(ell_get_type(x)) { case t_ELL_Qp: return mkcol( ellQp_root(x, ellQp_get_prec(x)) ); case t_ELL_Q: case t_ELL_Rg: return ellR_roots(x, ellR_get_prec(x)); } member_err("roots",x); } return nf_get_roots(y); } /* assume x output by get_bnf: ie a t_VEC with length 10 */ static GEN check_RES(GEN x, const char *s) { GEN y = gel(x,8); if (typ(y) != t_VEC || lg(y) < 4) member_err(s,x); return y; } /* y = get_bnf(x, &t) */ static GEN _member_clgp(GEN x, GEN y, long t) /* class group (3-component row vector) */ { if (!y) { switch(t) { case typ_QUA: return mkvec3(gel(x,1), gel(x,2), gel(x,3)); case typ_BIDZ: case typ_BID: return gel(x,2); } if (typ(x)==t_VEC) switch(lg(x)) { case 3: /* no gen */ case 4: return x; } member_err("clgp",x); } if (t==typ_BNR) return gel(x,5); y = check_RES(y, "clgp"); return gel(y,1); } static GEN _check_clgp(GEN x, GEN y, long t) { GEN c = _member_clgp(x,y,t); checkabgrp(c); return c; } GEN member_clgp(GEN x) { long t; GEN y = get_bnf(x,&t); return _check_clgp(x,y,t); } GEN member_reg(GEN x) /* regulator */ { long t; GEN y = get_bnf(x,&t); if (!y) { if (t == typ_QUA) return gel(x,4); member_err("reg",x); } if (t == typ_BNR) pari_err_IMPL("ray regulator"); y = check_RES(y, "reg"); return gel(y,2); } GEN member_fu(GEN x) /* fundamental units */ { long t; GEN y = get_bnf(x,&t); if (!y) { switch(t) { case typ_Q: x = quad_disc(x); return (signe(x)<0)? cgetg(1,t_VEC): quadunit(x); } member_err("fu",x); } if (t == typ_BNR) pari_err_IMPL("ray units"); return matbasistoalg(y, bnf_get_fu(y)); } /* torsion units. return [w,e] where w is the number of roots of 1, and e a * polmod (or integer) generator */ GEN member_tu(GEN x) { long t; GEN bnf = get_bnf(x,&t), res = cgetg(3,t_VEC); if (!bnf) { GEN y; if (t != typ_Q) member_err("tu",x); y = quad_disc(x); if (signe(y) > 0 || abscmpiu(y,4) > 0) return mkvec2(gen_m1, gen_2); gel(res,1) = utoipos((itos(y) == -4)? 4: 6); gel(res,2) = gcopy(x); } else { GEN z = bnf_get_tuU(bnf); if (t == typ_BNR) pari_err_IMPL("ray torsion units"); gel(res,1) = utoipos( bnf_get_tuN(bnf) ); gel(res,2) = typ(z)==t_INT? gen_m1: basistoalg(bnf,z); } return res; } GEN member_futu(GEN x) /* concatenation of fu and tu, w is lost */ { return shallowconcat(member_fu(x), gel(member_tu(x),2)); } GEN member_tufu(GEN x) /* concatenation of tu and fu, w is lost */ { return shallowconcat(gel(member_tu(x),2), member_fu(x)); } /* structure of (Z_K/m)^*, where x is an idealstarinit (with or without gen) * or a bnrinit (with or without gen) */ GEN member_zkst(GEN x) { long t; (void)get_nf(x,&t); switch(t) { case typ_BIDZ: case typ_BID: return bid_get_grp(x); case typ_BNR: { GEN bid = bnr_get_bid(x); if (typ(bid) == t_VEC && lg(bid) > 2) return bid_get_grp(bid); } } member_err("zkst",x); return NULL; /* LCOV_EXCL_LINE */ } GEN member_no(GEN x) /* number of elements of a group (of type clgp) */ { pari_sp av = avma; long t; GEN y = get_bnf(x,&t); if (t == typ_ELL) switch(ell_get_type(x)) { case t_ELL_Fp: case t_ELL_Fq: return ellcard(x, NULL); } x = _check_clgp(x,y,t); avma = av; return gel(x,1); } GEN member_cyc(GEN x) /* cyclic decomposition (SNF) of a group (of type clgp) */ { pari_sp av = avma; long t; GEN y = get_bnf(x,&t); if (t == typ_ELL) switch(ell_get_type(x)) { case t_ELL_Fp: case t_ELL_Fq: return ellgroup(x, NULL); } x = _check_clgp(x,y,t); avma = av; return gel(x,2); } /* SNF generators of a group (of type clgp), or generators of a prime * ideal */ GEN member_gen(GEN x) { pari_sp av; long t; GEN y = get_bnf(x,&t); switch(t) { case typ_MODPR: x = get_prid(x); case typ_PRID: return mkvec2(gel(x,1), gel(x,2)); case typ_GAL: return gal_get_gen(x); case typ_ELL: return ellgenerators(x); } av = avma; x = _check_clgp(x,y,t); if (lg(x)!=4) member_err("gen",x); avma = av; return gel(x,3); } GEN member_group(GEN x) { long t; (void)get_nf(x,&t); if (t == typ_GAL) return gal_get_group(x); if (t == typ_ELL) return ellgroup0(x, NULL, 1); member_err("group",x); return NULL; /* LCOV_EXCL_LINE */ } GEN member_orders(GEN x) { long t; (void)get_nf(x,&t); if (t == typ_GAL) return gal_get_orders(x); member_err("orders",x); return NULL; /* LCOV_EXCL_LINE */ } GEN member_a1(GEN x) { if (!is_ell5(x)) member_err("a1",x); return ell_get_a1(x); } GEN member_a2(GEN x) { if (!is_ell5(x)) member_err("a2",x); return ell_get_a2(x); } GEN member_a3(GEN x) { if (!is_ell5(x)) member_err("a3",x); return ell_get_a3(x); } GEN member_a4(GEN x) { if (!is_ell5(x)) member_err("a4",x); return ell_get_a4(x); } GEN member_a6(GEN x) { if (!is_ell5(x)) member_err("a6",x); return ell_get_a6(x); } GEN member_b2(GEN x) { if (!is_ell(x)) member_err("b2",x); return ell_get_b2(x); } GEN member_b4(GEN x) { if (!is_ell(x)) member_err("b4",x); return ell_get_b4(x); } GEN member_b6(GEN x) { if (!is_ell(x)) member_err("b6",x); return ell_get_b6(x); } GEN member_b8(GEN x) { if (!is_ell(x)) member_err("b8",x); return ell_get_b8(x); } GEN member_c4(GEN x) { if (!is_ell(x)) member_err("c4",x); return ell_get_c4(x); } GEN member_c6(GEN x) { if (!is_ell(x)) member_err("c6",x); return ell_get_c6(x); } GEN member_j(GEN x) { if (!is_ell(x)) member_err("j",x); return ell_get_j(x); } static int ell_is_complex(GEN x) { long t = ell_get_type(x); return t == t_ELL_Q || t == t_ELL_Rg; } static long ellnf_get_prec(GEN x) { return nf_get_prec(ellnf_get_nf(x)); } GEN member_omega(GEN x) { if (!is_ell(x)) member_err("omega",x); if (ell_get_type(x)==t_ELL_NF) return ellnf_vecomega(x, ellnf_get_prec(x)); if (!ell_is_complex(x)) pari_err_TYPE("omega [not defined over C]",x); return ellR_omega(x, ellR_get_prec(x)); } GEN member_eta(GEN x) { if (!is_ell(x)) member_err("eta",x); if (ell_get_type(x)==t_ELL_NF) return ellnf_veceta(x, ellnf_get_prec(x)); if (!ell_is_complex(x)) pari_err_TYPE("eta [not defined over C]",x); return ellR_eta(x, ellR_get_prec(x)); } GEN member_area(GEN x) { if (!is_ell(x)) member_err("area",x); if (ell_get_type(x)==t_ELL_NF) return ellnf_vecarea(x, ellnf_get_prec(x)); if (!ell_is_complex(x)) pari_err_TYPE("area [not defined over C]",x); return ellR_area(x, ellR_get_prec(x)); } GEN member_tate(GEN x) { long prec; if (!is_ell(x)) member_err("tate",x); if (ell_get_type(x) != t_ELL_Qp) pari_err_TYPE("tate [not defined over Qp]",x); prec = ellQp_get_prec(x); return ellQp_Tate_uniformization(x, prec); } pari-2.11.2/src/language/sumiter.c0000644000175000017500000014144013457566441015407 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" GEN iferrpari(GEN a, GEN b, GEN c) { GEN res; struct pari_evalstate state; evalstate_save(&state); pari_CATCH(CATCH_ALL) { GEN E; if (!b&&!c) return gnil; E = evalstate_restore_err(&state); if (c) { push_lex(E,c); res = closure_evalnobrk(c); pop_lex(1); if (gequal0(res)) pari_err(0, E); } if (!b) return gnil; push_lex(E,b); res = closure_evalgen(b); pop_lex(1); return res; } pari_TRY { res = closure_evalgen(a); } pari_ENDCATCH; return res; } /********************************************************************/ /** **/ /** ITERATIONS **/ /** **/ /********************************************************************/ static void forparii(GEN a, GEN b, GEN code) { pari_sp av, av0 = avma; GEN aa; if (gcmp(b,a) < 0) return; if (typ(b) != t_INFINITY) b = gfloor(b); aa = a = setloop(a); av=avma; push_lex(a,code); while (gcmp(a,b) <= 0) { closure_evalvoid(code); if (loop_break()) break; a = get_lex(-1); if (a == aa) { a = incloop(a); if (a != aa) { set_lex(-1,a); aa = a; } } else { /* 'code' modified a ! Be careful (and slow) from now on */ a = gaddgs(a,1); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"forparii"); a = gerepileupto(av,a); } set_lex(-1,a); } } pop_lex(1); avma = av0; } void forpari(GEN a, GEN b, GEN code) { pari_sp ltop=avma, av; if (typ(a) == t_INT) { forparii(a,b,code); return; } b = gcopy(b); /* Kludge to work-around the a+(a=2) bug */ av=avma; push_lex(a,code); while (gcmp(a,b) <= 0) { closure_evalvoid(code); if (loop_break()) break; a = get_lex(-1); a = gaddgs(a,1); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"forpari"); a = gerepileupto(av,a); } set_lex(-1, a); } pop_lex(1); avma = ltop; } /* 0 < a <= b. Using small consecutive chunks to 1) limit memory use, 2) allow * cheap early abort */ static int forfactoredpos(ulong a, ulong b, GEN code) { const ulong step = 1024; pari_sp av = avma; ulong x1; for(x1 = a;; x1 += step, avma = av) { /* beware overflow, fuse last two bins (avoid a tiny remainder) */ ulong j, lv, x2 = (b >= 2*step && b - 2*step >= x1)? x1-1 + step: b; GEN v = vecfactoru(x1, x2); lv = lg(v); for (j = 1; j < lv; j++) { ulong n = x1-1 + j; set_lex(-1, mkvec2(utoipos(n), Flm_to_ZM(gel(v,j)))); closure_evalvoid(code); if (loop_break()) return 1; } if (x2 == b) break; set_lex(-1, gen_0); } return 0; } /* vector of primes to squarefree factorization */ static GEN zv_to_ZM(GEN v) { return mkmat2(zc_to_ZC(v), const_col(lg(v)-1,gen_1)); } /* vector of primes to negative squarefree factorization */ static GEN zv_to_mZM(GEN v) { long i, l = lg(v); GEN w = cgetg(l+1, t_COL); gel(w,1) = gen_m1; for (i = 1; i < l; i++) gel(w,i+1) = utoipos(v[i]); return mkmat2(w, const_col(l,gen_1)); } /* 0 <= a <= b. Using small consecutive chunks to 1) limit memory use, 2) allow * cheap early abort */ static void forsquarefreepos(ulong a, ulong b, GEN code) { const ulong step = 1024; pari_sp av = avma; ulong x1; for(x1 = a;; x1 += step, avma = av) { /* beware overflow, fuse last two bins (avoid a tiny remainder) */ ulong j, lv, x2 = (b >= 2*step && b - 2*step >= x1)? x1-1 + step: b; GEN v = vecfactorsquarefreeu(x1, x2); lv = lg(v); for (j = 1; j < lv; j++) if (gel(v,j)) { ulong n = x1-1 + j; set_lex(-1, mkvec2(utoipos(n), zv_to_ZM(gel(v,j)))); closure_evalvoid(code); if (loop_break()) return; } if (x2 == b) break; set_lex(-1, gen_0); } } /* 0 <= a <= b. Loop from -b, ... -a through squarefree integers */ static void forsquarefreeneg(ulong a, ulong b, GEN code) { const ulong step = 1024; pari_sp av = avma; ulong x2; for(x2 = b;; x2 -= step, avma = av) { /* beware overflow, fuse last two bins (avoid a tiny remainder) */ ulong j, x1 = (x2 >= 2*step && x2-2*step >= a)? x2+1 - step: a; GEN v = vecfactorsquarefreeu(x1, x2); for (j = lg(v)-1; j > 0; j--) if (gel(v,j)) { ulong n = x1-1 + j; set_lex(-1, mkvec2(utoineg(n), zv_to_mZM(gel(v,j)))); closure_evalvoid(code); if (loop_break()) return; } if (x1 == a) break; set_lex(-1, gen_0); } } void forsquarefree(GEN a, GEN b, GEN code) { pari_sp av = avma; long s; if (typ(a) != t_INT) pari_err_TYPE("forsquarefree", a); if (typ(b) != t_INT) pari_err_TYPE("forsquarefree", b); if (cmpii(a,b) > 0) return; s = signe(a); if (s * signe(b) < 0) pari_err_TYPE("forsquarefree [!= signs]", mkvec2(a,b)); push_lex(NULL,code); if (s < 0) forsquarefreeneg(itou(b), itou(a), code); else forsquarefreepos(itou(a), itou(b), code); pop_lex(1); avma = av; } /* convert factoru(n) to factor(-n); M pre-allocated factorization matrix * with (-1)^1 already set */ static void Flm2negfact(GEN v, GEN M) { GEN p = gel(v,1), e = gel(v,2), P = gel(M,1), E = gel(M,2); long i, l = lg(p); for (i = 1; i < l; i++) { gel(P,i+1) = utoipos(p[i]); gel(E,i+1) = utoipos(e[i]); } setlg(P,l+1); setlg(E,l+1); } /* 0 < a <= b, from -b to -a */ static int forfactoredneg(ulong a, ulong b, GEN code) { const ulong step = 1024; GEN P, E, M; pari_sp av; ulong x2; P = cgetg(18, t_COL); gel(P,1) = gen_m1; E = cgetg(18, t_COL); gel(E,1) = gen_1; M = mkmat2(P,E); av = avma; for(x2 = b;; x2 -= step, avma = av) { /* beware overflow, fuse last two bins (avoid a tiny remainder) */ ulong j, x1 = (x2 >= 2*step && x2-2*step >= a)? x2+1 - step: a; GEN v = vecfactoru(x1, x2); for (j = lg(v)-1; j; j--) { /* run backward: from factor(x1..x2) to factor(-x2..-x1) */ ulong n = x1-1 + j; Flm2negfact(gel(v,j), M); set_lex(-1, mkvec2(utoineg(n), M)); closure_evalvoid(code); if (loop_break()) return 1; } if (x1 == a) break; set_lex(-1, gen_0); } return 0; } static int eval0(GEN code) { pari_sp av = avma; set_lex(-1, mkvec2(gen_0, mkmat2(mkcol(gen_0),mkcol(gen_1)))); closure_evalvoid(code); avma = av; return loop_break(); } void forfactored(GEN a, GEN b, GEN code) { pari_sp av = avma; long sa, sb, stop = 0; if (typ(a) != t_INT) pari_err_TYPE("forfactored", a); if (typ(b) != t_INT) pari_err_TYPE("forfactored", b); if (cmpii(a,b) > 0) return; push_lex(NULL,code); sa = signe(a); sb = signe(b); if (sa < 0) { stop = forfactoredneg((sb < 0)? b[2]: 1UL, itou(a), code); if (!stop && sb >= 0) stop = eval0(code); if (!stop && sb > 0) forfactoredpos(1UL, b[2], code); } else { if (!sa) stop = eval0(code); if (!stop && sb) forfactoredpos(sa? a[2]: 1UL, itou(b), code); } pop_lex(1); avma = av; } void whilepari(GEN a, GEN b) { pari_sp av = avma; for(;;) { GEN res = closure_evalnobrk(a); if (gequal0(res)) break; avma = av; closure_evalvoid(b); if (loop_break()) break; } avma = av; } void untilpari(GEN a, GEN b) { pari_sp av = avma; for(;;) { GEN res; closure_evalvoid(b); if (loop_break()) break; res = closure_evalnobrk(a); if (!gequal0(res)) break; avma = av; } avma = av; } static int negcmp(GEN x, GEN y) { return gcmp(y,x); } void forstep(GEN a, GEN b, GEN s, GEN code) { long ss, i; pari_sp av, av0 = avma; GEN v = NULL; int (*cmp)(GEN,GEN); b = gcopy(b); s = gcopy(s); av = avma; switch(typ(s)) { case t_VEC: case t_COL: ss = gsigne(vecsum(s)); v = s; break; case t_INTMOD: a = gadd(a, gmod(gsub(gel(s,2),a), gel(s,1))); s = gel(s,1); default: ss = gsigne(s); } if (!ss) pari_err_DOMAIN("forstep","step","=",gen_0,s); cmp = (ss > 0)? &gcmp: &negcmp; i = 0; push_lex(a,code); while (cmp(a,b) <= 0) { closure_evalvoid(code); if (loop_break()) break; if (v) { if (++i >= lg(v)) i = 1; s = gel(v,i); } a = get_lex(-1); a = gadd(a,s); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"forstep"); a = gerepileupto(av,a); } set_lex(-1,a); } pop_lex(1); avma = av0; } static void _fordiv(GEN a, GEN code, GEN (*D)(GEN)) { long i, l; pari_sp av2, av = avma; GEN t = D(a); push_lex(gen_0,code); l=lg(t); av2 = avma; for (i=1; ia [over integers]*/ static GEN _next_i(forvec_t *d) { long i = d->n; if (d->first) { d->first = 0; return (GEN)d->a; } for (;;) { if (cmpii(d->a[i], d->M[i]) < 0) { d->a[i] = incloop(d->a[i]); return (GEN)d->a; } d->a[i] = resetloop(d->a[i], d->m[i]); if (--i <= 0) return NULL; } } /* increment and return d->a [generic]*/ static GEN _next(forvec_t *d) { long i = d->n; if (d->first) { d->first = 0; return (GEN)d->a; } for (;;) { d->a[i] = gaddgs(d->a[i], 1); if (gcmp(d->a[i], d->M[i]) <= 0) return (GEN)d->a; d->a[i] = d->m[i]; if (--i <= 0) return NULL; } } /* non-decreasing order [over integers] */ static GEN _next_le_i(forvec_t *d) { long i = d->n; if (d->first) { d->first = 0; return (GEN)d->a; } for (;;) { if (cmpii(d->a[i], d->M[i]) < 0) { d->a[i] = incloop(d->a[i]); /* m[i] < a[i] <= M[i] <= M[i+1] */ while (i < d->n) { GEN t; i++; if (cmpii(d->a[i-1], d->a[i]) <= 0) continue; /* a[i] < a[i-1] <= M[i-1] <= M[i] */ t = d->a[i-1]; if (cmpii(t, d->m[i]) < 0) t = d->m[i]; d->a[i] = resetloop(d->a[i], t);/*a[i]:=max(a[i-1],m[i])*/ } return (GEN)d->a; } d->a[i] = resetloop(d->a[i], d->m[i]); if (--i <= 0) return NULL; } } /* non-decreasing order [generic] */ static GEN _next_le(forvec_t *d) { long i = d->n; if (d->first) { d->first = 0; return (GEN)d->a; } for (;;) { d->a[i] = gaddgs(d->a[i], 1); if (gcmp(d->a[i], d->M[i]) <= 0) { while (i < d->n) { GEN c; i++; if (gcmp(d->a[i-1], d->a[i]) <= 0) continue; /* M[i] >= M[i-1] >= a[i-1] > a[i] */ c = gceil(gsub(d->a[i-1], d->a[i])); d->a[i] = gadd(d->a[i], c); /* a[i-1] <= a[i] < M[i-1] + 1 => a[i] < M[i]+1 => a[i] <= M[i] */ } return (GEN)d->a; } d->a[i] = d->m[i]; if (--i <= 0) return NULL; } } /* strictly increasing order [over integers] */ static GEN _next_lt_i(forvec_t *d) { long i = d->n; if (d->first) { d->first = 0; return (GEN)d->a; } for (;;) { if (cmpii(d->a[i], d->M[i]) < 0) { d->a[i] = incloop(d->a[i]); /* m[i] < a[i] <= M[i] < M[i+1] */ while (i < d->n) { pari_sp av; GEN t; i++; if (cmpii(d->a[i-1], d->a[i]) < 0) continue; av = avma; /* M[i] > M[i-1] >= a[i-1] */ t = addiu(d->a[i-1],1); if (cmpii(t, d->m[i]) < 0) t = d->m[i]; d->a[i] = resetloop(d->a[i], t);/*a[i]:=max(a[i-1]+1,m[i]) <= M[i]*/ avma = av; } return (GEN)d->a; } d->a[i] = resetloop(d->a[i], d->m[i]); if (--i <= 0) return NULL; } } /* strictly increasing order [generic] */ static GEN _next_lt(forvec_t *d) { long i = d->n; if (d->first) { d->first = 0; return (GEN)d->a; } for (;;) { d->a[i] = gaddgs(d->a[i], 1); if (gcmp(d->a[i], d->M[i]) <= 0) { while (i < d->n) { GEN c; i++; if (gcmp(d->a[i-1], d->a[i]) < 0) continue; /* M[i] > M[i-1] >= a[i-1] >= a[i] */ c = addiu(gfloor(gsub(d->a[i-1], d->a[i])), 1); /* > a[i-1] - a[i] */ d->a[i] = gadd(d->a[i], c); /* a[i-1] < a[i] <= M[i-1] + 1 => a[i] < M[i]+1 => a[i] <= M[i] */ } return (GEN)d->a; } d->a[i] = d->m[i]; if (--i <= 0) return NULL; } } /* for forvec(v=[],) */ static GEN _next_void(forvec_t *d) { if (d->first) { d->first = 0; return (GEN)d->a; } return NULL; } /* Initialize minima (m) and maxima (M); guarantee M[i] - m[i] integer and * if flag = 1: m[i-1] <= m[i] <= M[i] <= M[i+1] * if flag = 2: m[i-1] < m[i] <= M[i] < M[i+1], * for all i */ int forvec_init(forvec_t *d, GEN x, long flag) { long i, tx = typ(x), l = lg(x), t = t_INT; if (!is_vec_t(tx)) pari_err_TYPE("forvec [not a vector]", x); d->first = 1; d->n = l - 1; d->a = (GEN*)cgetg(l,tx); d->m = (GEN*)cgetg(l,tx); d->M = (GEN*)cgetg(l,tx); if (l == 1) { d->next = &_next_void; return 1; } for (i = 1; i < l; i++) { GEN a, e = gel(x,i), m = gel(e,1), M = gel(e,2); tx = typ(e); if (! is_vec_t(tx) || lg(e)!=3) pari_err_TYPE("forvec [expected vector not of type [min,MAX]]",e); if (typ(m) != t_INT) t = t_REAL; if (i > 1) switch(flag) { case 1: /* a >= m[i-1] - m */ a = gceil(gsub(d->m[i-1], m)); if (typ(a) != t_INT) pari_err_TYPE("forvec",a); if (signe(a) > 0) m = gadd(m, a); else m = gcopy(m); break; case 2: /* a > m[i-1] - m */ a = gfloor(gsub(d->m[i-1], m)); if (typ(a) != t_INT) pari_err_TYPE("forvec",a); a = addiu(a, 1); if (signe(a) > 0) m = gadd(m, a); else m = gcopy(m); break; default: m = gcopy(m); break; } M = gadd(m, gfloor(gsub(M,m))); /* ensure M-m is an integer */ if (gcmp(m,M) > 0) { d->a = NULL; d->next = &_next; return 0; } d->m[i] = m; d->M[i] = M; } if (flag == 1) for (i = l-2; i >= 1; i--) { GEN M = d->M[i], a = gfloor(gsub(d->M[i+1], M)); if (typ(a) != t_INT) pari_err_TYPE("forvec",a); /* M[i]+a <= M[i+1] */ if (signe(a) < 0) d->M[i] = gadd(M, a); } else if (flag == 2) for (i = l-2; i >= 1; i--) { GEN M = d->M[i], a = gceil(gsub(d->M[i+1], M)); if (typ(a) != t_INT) pari_err_TYPE("forvec",a); a = subiu(a, 1); /* M[i]+a < M[i+1] */ if (signe(a) < 0) d->M[i] = gadd(M, a); } if (t == t_INT) { for (i = 1; i < l; i++) { d->a[i] = setloop(d->m[i]); if (typ(d->M[i]) != t_INT) d->M[i] = gfloor(d->M[i]); } } else { for (i = 1; i < l; i++) d->a[i] = d->m[i]; } switch(flag) { case 0: d->next = t==t_INT? &_next_i: &_next; break; case 1: d->next = t==t_INT? &_next_le_i: &_next_le; break; case 2: d->next = t==t_INT? &_next_lt_i: &_next_lt; break; default: pari_err_FLAG("forvec"); } return 1; } GEN forvec_next(forvec_t *d) { return d->next(d); } void forvec(GEN x, GEN code, long flag) { pari_sp av = avma; forvec_t T; GEN v; if (!forvec_init(&T, x, flag)) { avma = av; return; } push_lex((GEN)T.a, code); while ((v = forvec_next(&T))) { closure_evalvoid(code); if (loop_break()) break; } pop_lex(1); avma = av; } /********************************************************************/ /** **/ /** SUMS **/ /** **/ /********************************************************************/ GEN somme(GEN a, GEN b, GEN code, GEN x) { pari_sp av, av0 = avma; GEN p1; if (typ(a) != t_INT) pari_err_TYPE("sum",a); if (!x) x = gen_0; if (gcmp(b,a) < 0) return gcopy(x); b = gfloor(b); a = setloop(a); av=avma; push_lex(a,code); for(;;) { p1 = closure_evalnobrk(code); x=gadd(x,p1); if (cmpii(a,b) >= 0) break; a = incloop(a); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"sum"); x = gerepileupto(av,x); } set_lex(-1,a); } pop_lex(1); return gerepileupto(av0,x); } static GEN sum_init(GEN x0, GEN t) { long tp = typ(t); GEN x; if (is_vec_t(tp)) { x = const_vec(lg(t)-1, x0); settyp(x, tp); } else x = x0; return x; } GEN suminf(void *E, GEN (*eval)(void *, GEN), GEN a, long prec) { long fl = 0, G = prec2nbits(prec) + 5; pari_sp av0 = avma, av; GEN x = NULL, _1; if (typ(a) != t_INT) pari_err_TYPE("suminf",a); a = setloop(a); av = avma; for(;;) { GEN t = eval(E, a); if (!x) _1 = x = sum_init(real_1(prec), t); x = gadd(x,t); if (!gequal0(t) && gexpo(t) > gexpo(x)-G) fl = 0; else if (++fl == 3) break; a = incloop(a); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"suminf"); gerepileall(av,2, &x, &_1); } } return gerepileupto(av0, gsub(x, _1)); } GEN suminf0(GEN a, GEN code, long prec) { EXPR_WRAP(code, suminf(EXPR_ARG, a, prec)); } GEN sumdivexpr(GEN num, GEN code) { pari_sp av = avma; GEN y = gen_0, t = divisors(num); long i, l = lg(t); push_lex(gen_0, code); for (i=1; i= 0) break; a = incloop(a); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"prod"); x = gerepileupto(av,x); } set_lex(-1,a); } pop_lex(1); return gerepileupto(av0,x); } GEN prodinf(void *E, GEN (*eval)(void *, GEN), GEN a, long prec) { pari_sp av0 = avma, av; long fl,G; GEN p1,x = real_1(prec); if (typ(a) != t_INT) pari_err_TYPE("prodinf",a); a = setloop(a); av = avma; fl=0; G = -prec2nbits(prec)-5; for(;;) { p1 = eval(E, a); if (gequal0(p1)) { x = p1; break; } x = gmul(x,p1); a = incloop(a); p1 = gsubgs(p1, 1); if (gequal0(p1) || gexpo(p1) <= G) { if (++fl==3) break; } else fl=0; if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"prodinf"); x = gerepileupto(av,x); } } return gerepilecopy(av0,x); } GEN prodinf1(void *E, GEN (*eval)(void *, GEN), GEN a, long prec) { pari_sp av0 = avma, av; long fl,G; GEN p1,p2,x = real_1(prec); if (typ(a) != t_INT) pari_err_TYPE("prodinf1",a); a = setloop(a); av = avma; fl=0; G = -prec2nbits(prec)-5; for(;;) { p2 = eval(E, a); p1 = gaddgs(p2,1); if (gequal0(p1)) { x = p1; break; } x = gmul(x,p1); a = incloop(a); if (gequal0(p2) || gexpo(p2) <= G) { if (++fl==3) break; } else fl=0; if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"prodinf1"); x = gerepileupto(av,x); } } return gerepilecopy(av0,x); } GEN prodinf0(GEN a, GEN code, long flag, long prec) { switch(flag) { case 0: EXPR_WRAP(code, prodinf (EXPR_ARG, a, prec)); case 1: EXPR_WRAP(code, prodinf1(EXPR_ARG, a, prec)); } pari_err_FLAG("prodinf"); return NULL; /* LCOV_EXCL_LINE */ } GEN prodeuler(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, long prec) { pari_sp av, av0 = avma; GEN x = real_1(prec), prime; forprime_t T; av = avma; if (!forprime_init(&T, a,b)) { avma = av; return x; } av = avma; while ( (prime = forprime_next(&T)) ) { x = gmul(x, eval(E, prime)); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"prodeuler"); x = gerepilecopy(av, x); } } return gerepilecopy(av0,x); } GEN prodeuler0(GEN a, GEN b, GEN code, long prec) { EXPR_WRAP(code, prodeuler(EXPR_ARG, a, b, prec)); } GEN direuler0(GEN a, GEN b, GEN code, GEN c) { EXPR_WRAP(code, direuler(EXPR_ARG, a, b, c)); } /********************************************************************/ /** **/ /** VECTORS & MATRICES **/ /** **/ /********************************************************************/ INLINE GEN copyupto(GEN z, GEN t) { if (is_universal_constant(z) || (z>(GEN)pari_mainstack->bot && z<=t)) return z; else return gcopy(z); } GEN vecexpr0(GEN vec, GEN code, GEN pred) { switch(typ(vec)) { case t_LIST: { if (list_typ(vec)==t_LIST_MAP) vec = mapdomain_shallow(vec); else vec = list_data(vec); if (!vec) return cgetg(1, t_VEC); break; } case t_VEC: case t_COL: case t_MAT: break; default: pari_err_TYPE("[_|_<-_,_]",vec); } if (pred && code) EXPR_WRAP(code,vecselapply((void*)pred,&gp_evalbool,EXPR_ARGUPTO,vec)) else if (code) EXPR_WRAP(code,vecapply(EXPR_ARGUPTO,vec)) else EXPR_WRAP(pred,vecselect(EXPR_ARGBOOL,vec)) } GEN vecexpr1(GEN vec, GEN code, GEN pred) { GEN v = vecexpr0(vec, code, pred); return lg(v) == 1? v: shallowconcat1(v); } GEN vecteur(GEN nmax, GEN code) { GEN y, c; long i, m = gtos(nmax); if (m < 0) pari_err_DOMAIN("vector", "dimension", "<", gen_0, stoi(m)); if (!code) return zerovec(m); c = cgetipos(3); /* left on stack */ y = cgetg(m+1,t_VEC); push_lex(c, code); for (i=1; i<=m; i++) { c[2] = i; gel(y,i) = copyupto(closure_evalnobrk(code), y); set_lex(-1,c); } pop_lex(1); return y; } GEN vecteursmall(GEN nmax, GEN code) { pari_sp av; GEN y, c; long i, m = gtos(nmax); if (m < 0) pari_err_DOMAIN("vectorsmall", "dimension", "<", gen_0, stoi(m)); if (!code) return zero_zv(m); c = cgetipos(3); /* left on stack */ y = cgetg(m+1,t_VECSMALL); push_lex(c,code); av = avma; for (i = 1; i <= m; i++) { c[2] = i; y[i] = gtos(closure_evalnobrk(code)); avma = av; set_lex(-1,c); } pop_lex(1); return y; } GEN vvecteur(GEN nmax, GEN n) { GEN y = vecteur(nmax,n); settyp(y,t_COL); return y; } GEN matrice(GEN nlig, GEN ncol, GEN code) { GEN c1, c2, y; long i, m, n; n = gtos(nlig); m = ncol? gtos(ncol): n; if (m < 0) pari_err_DOMAIN("matrix", "nbcols", "<", gen_0, stoi(m)); if (n < 0) pari_err_DOMAIN("matrix", "nbrows", "<", gen_0, stoi(n)); if (!m) return cgetg(1,t_MAT); if (!code || !n) return zeromatcopy(n, m); c1 = cgetipos(3); push_lex(c1,code); c2 = cgetipos(3); push_lex(c2,NULL); /* c1,c2 left on stack */ y = cgetg(m+1,t_MAT); for (i = 1; i <= m; i++) { GEN z = cgetg(n+1,t_COL); long j; c2[2] = i; gel(y,i) = z; for (j = 1; j <= n; j++) { c1[2] = j; gel(z,j) = copyupto(closure_evalnobrk(code), y); set_lex(-2,c1); set_lex(-1,c2); } } pop_lex(2); return y; } /********************************************************************/ /** **/ /** SUMMING SERIES **/ /** **/ /********************************************************************/ /* h = (2+2x)g'- g; g has t_INT coeffs */ static GEN delt(GEN g, long n) { GEN h = cgetg(n+3,t_POL); long k; h[1] = g[1]; gel(h,2) = gel(g,2); for (k=1; k>1, D = (d+1)>>1; long i, k; pari_sp av = avma; GEN g, T; if (d <= 0 || m < 0) return pol_0(0); g = cgetg(d+2, t_POL); g[1] = evalsigne(1)|evalvarn(0); T = cgetg(d+1,t_VEC); /* T[k+1] = binomial(2d,2k+1), 0 <= k < d */ gel(T,1) = utoipos(d2); for (k = 1; k < D; k++) { long k2 = k<<1; gel(T,k+1) = diviiexact(mulii(gel(T,k), muluu(d2-k2+1, d2-k2)), muluu(k2,k2+1)); } for (; k < d; k++) gel(T,k+1) = gel(T,d-k); gel(g,2) = gel(T,d); /* binomial(2d, 2(d-1)+1) */ for (i = 1; i < d; i++) { pari_sp av2 = avma; GEN s, t = gel(T,d-i); /* binomial(2d, 2(d-1-i)+1) */ s = t; for (k = d-i; k < d; k++) { long k2 = k<<1; t = diviiexact(mulii(t, muluu(d2-k2+1, d-k)), muluu(k2+1,k-(d-i)+1)); s = addii(s, t); } /* g_i = sum_{d-1-i <= k < d}, binomial(2*d, 2*k+1)*binomial(k,d-1-i) */ gel(g,i+2) = gerepileuptoint(av2, s); } /* sum_{0 <= i < d} g_i x^i * (x+x^2)^r */ g = RgX_mulXn(gmul(g, gpowgs(deg1pol(gen_1,gen_1,0),r)), r); if (!odd(m)) g = delt(g, n); for (i=1; i<=r; i++) { g = delt(ZX_deriv(g), n); if (gc_needed(av,4)) { if (DEBUGMEM>1) pari_warn(warnmem,"polzag, i = %ld/%ld", i,r); g = gerepilecopy(av, g); } } return g; } GEN polzag(long n, long m) { pari_sp av = avma; GEN g = ZX_z_unscale(polzag1(n,m), -1); return gerepileupto(av, RgX_Rg_div(g,gel(g,2))); } GEN sumalt(void *E, GEN (*eval)(void *, GEN), GEN a, long prec) { ulong k, N; pari_sp av = avma, av2; GEN s, az, c, d; if (typ(a) != t_INT) pari_err_TYPE("sumalt",a); N = (ulong)(0.39322*(prec2nbits(prec) + 7)); /*0.39322 > 1/log_2(3+sqrt(8))*/ d = powru(addsr(3, sqrtr(stor(8,prec))), N); d = shiftr(addrr(d, invr(d)),-1); a = setloop(a); az = gen_m1; c = d; s = gen_0; av2 = avma; for (k=0; ; k++) /* k < N */ { c = addir(az,c); s = gadd(s, gmul(c, eval(E, a))); if (k==N-1) break; az = diviuuexact(muluui((N-k)<<1,N+k,az), k+1, (k<<1)+1); a = incloop(a); /* in place! */ if (gc_needed(av,4)) { if (DEBUGMEM>1) pari_warn(warnmem,"sumalt, k = %ld/%ld", k,N-1); gerepileall(av2, 3, &az,&c,&s); } } return gerepileupto(av, gdiv(s,d)); } GEN sumalt2(void *E, GEN (*eval)(void *, GEN), GEN a, long prec) { long k, N; pari_sp av = avma, av2; GEN s, dn, pol; if (typ(a) != t_INT) pari_err_TYPE("sumalt",a); N = (long)(0.307073*(prec2nbits(prec) + 5)); /*0.307073 > 1/log_2(\beta_B)*/ pol = ZX_div_by_X_1(polzag1(N,N>>1), &dn); a = setloop(a); N = degpol(pol); s = gen_0; av2 = avma; for (k=0; k<=N; k++) { GEN t = itor(gel(pol,k+2), prec+EXTRAPRECWORD); s = gadd(s, gmul(t, eval(E, a))); if (k == N) break; a = incloop(a); /* in place! */ if (gc_needed(av,4)) { if (DEBUGMEM>1) pari_warn(warnmem,"sumalt2, k = %ld/%ld", k,N-1); s = gerepileupto(av2, s); } } return gerepileupto(av, gdiv(s,dn)); } GEN sumalt0(GEN a, GEN code, long flag, long prec) { switch(flag) { case 0: EXPR_WRAP(code, sumalt (EXPR_ARG,a,prec)); case 1: EXPR_WRAP(code, sumalt2(EXPR_ARG,a,prec)); default: pari_err_FLAG("sumalt"); } return NULL; /* LCOV_EXCL_LINE */ } /* For k > 0, set S[k*2^i] <- g(k*2^i), k*2^i <= N = #S. * Only needed with k odd (but also works for g even). */ static void binsum(GEN S, ulong k, void *E, GEN (*f)(void *, GEN), GEN a, long G, long prec) { long e, i, N = lg(S)-1, l = expu(N / k); /* k 2^l <= N < k 2^(l+1) */ pari_sp av; GEN r, t = gen_0; gel(S, k << l) = cgetr(prec); av = avma; G -= l; r = utoipos(k< 0 */ for(i = l-1; i >= 0; i--) { /* t ~ g(2 * k*2^i) with error ~ 2^(G-i-1) */ GEN u; av = avma; u = gtofp(f(E, addiu(a, k << i)), prec); if (typ(u) != t_REAL) pari_err_TYPE("sumpos",u); t = addrr(gtofp(u,prec), mpshift(t,1)); /* ~ g(k*2^i) */ gel(S, k << i) = t = gerepileuptoleaf(av, t); } } /* For k > 0, let g(k) := \sum_{e >= 0} 2^e f(a + k*2^e). * Return [g(k), 1 <= k <= N] */ static GEN sumpos_init(void *E, GEN (*f)(void *, GEN), GEN a, long N, long prec) { GEN S = cgetg(N+1,t_VEC); long k, G = -prec2nbits(prec) - 5; for (k=1; k<=N; k+=2) binsum(S,k, E,f, a,G,prec); return S; } GEN sumpos(void *E, GEN (*eval)(void *, GEN), GEN a, long prec) { ulong k, N; pari_sp av = avma; GEN s, az, c, d, S; if (typ(a) != t_INT) pari_err_TYPE("sumpos",a); a = subiu(a,1); N = (ulong)(0.4*(prec2nbits(prec) + 7)); if (odd(N)) N++; /* extra precision for free */ d = powru(addsr(3, sqrtr(stor(8,prec))), N); d = shiftr(addrr(d, invr(d)),-1); az = gen_m1; c = d; S = sumpos_init(E, eval, a, N, prec); s = gen_0; for (k=0; k>1), &dn); s = gen_0; for (k=0; k 0) pari_err_DOMAIN("solve", "f(a)f(b)", ">", gen_0, mkvec2(fa, fb)); itmax = prec2nbits(prec) * 2 + 1; tol = real2n(5-prec2nbits(prec), LOWDEFAULTPREC); fc = fb; e = d = NULL; /* gcc -Wall */ for (iter = 1; iter <= itmax; ++iter) { GEN xm, tol1; if (gsigne(fb)*gsigne(fc) > 0) { c = a; fc = fa; e = d = subrr(b, a); } if (gcmp(gabs(fc, 0), gabs(fb, 0)) < 0) { a = b; b = c; c = a; fa = fb; fb = fc; fc = fa; } tol1 = abscmprr(tol, b) > 0? sqrr(tol): mulrr(tol, absr(b)); xm = shiftr(subrr(c, b), -1); if (abscmprr(xm, tol1) <= 0 || gequal0(fb)) break; /* SUCCESS */ if (abscmprr(e, tol1) >= 0 && gcmp(gabs(fa, 0), gabs(fb, 0)) > 0) { /* attempt interpolation */ GEN min1, min2, p, q, s = gdiv(fb, fa); if (cmprr(a, c) == 0) { p = gmul2n(gmul(xm, s), 1); q = gsubsg(1, s); } else { GEN r = gdiv(fb, fc); q = gdiv(fa, fc); p = gmul2n(gmul(gsub(q, r), gmul(xm, q)), 1); p = gmul(s, gsub(p, gmul(gsub(b, a), gsubgs(r, 1)))); q = gmul(gmul(gsubgs(q, 1), gsubgs(r, 1)), gsubgs(s, 1)); } if (gsigne(p) > 0) q = gneg_i(q); else p = gneg_i(p); min1 = gsub(gmulsg(3, gmul(xm,q)), gabs(gmul(q, tol1), 0)); min2 = gabs(gmul(e, q), 0); if (gcmp(gmul2n(p, 1), gmin_shallow(min1, min2)) < 0) { e = d; d = gdiv(p, q); } /* interpolation OK */ else { d = xm; e = d; } /* failed, use bisection */ } else { d = xm; e = d; } /* bound decreasing too slowly, use bisection */ a = b; fa = fb; if (gcmp(gabs(d, 0), tol1) > 0) b = gadd(b, d); else if (gsigne(xm) > 0) b = addrr(b, tol1); else b = subrr(b, tol1); if (realprec(b) < prec) b = rtor(b, prec); fb = eval(E, b); } if (iter > itmax) pari_err_IMPL("solve recovery [too many iterations]"); return gerepileuptoleaf(av, rcopy(b)); } GEN zbrent0(GEN a, GEN b, GEN code, long prec) { EXPR_WRAP(code, zbrent(EXPR_ARG, a, b, prec)); } /* x = solve_start(&D, a, b, prec) * while (x) { * y = ...(x); * x = solve_next(&D, y); * } * return D.res; */ /* Find zeros of a function in the real interval [a,b] by interval splitting */ GEN solvestep(void *E, GEN (*f)(void *,GEN), GEN a, GEN b, GEN step, long flag, long prec) { const long ITMAX = 10; pari_sp av = avma; GEN fa, ainit, binit; long sainit, it, bit = prec2nbits(prec) / 2, ct = 0, s = gcmp(a,b); if (!s) return gequal0(f(E, a)) ? gcopy(mkvec(a)): cgetg(1,t_VEC); if (s > 0) swap(a, b); if (flag&4) { if (gcmpgs(step,1)<=0) pari_err_DOMAIN("solvestep","step","<=",gen_1,step); if (gsigne(a) <= 0) pari_err_DOMAIN("solvestep","a","<=",gen_0,a); } else if (gsigne(step) <= 0) pari_err_DOMAIN("solvestep","step","<=",gen_0,step); ainit = a = gtofp(a, prec); fa = f(E, a); binit = b = gtofp(b, prec); step = gtofp(step, prec); sainit = gsigne(fa); if (gexpo(fa) < -bit) sainit = 0; for (it = 0; it < ITMAX; it++) { pari_sp av2 = avma; GEN v = cgetg(1, t_VEC); long sa; a = ainit; b = binit; sa = sainit; while (gcmp(a,b) < 0) { GEN fc, c = (flag&4)? gmul(a, step): gadd(a, step); long sc; if (gcmp(c,b) > 0) c = b; fc = f(E, c); sc = gsigne(fc); if (gexpo(fc) < -bit) sc = 0; if (!sc || sa*sc < 0) { long e; GEN z; z = sc? zbrent(E, f, a, c, prec): c; (void)grndtoi(z, &e); if (e <= -bit) ct = 1; if ((flag&1) && ((!(flag&8)) || ct)) return gerepileupto(av, z); v = gconcat(v, z); } a = c; fa = fc; sa = sc; } if ((!(flag&2) || lg(v) > 1) && (!(flag&8) || ct)) return gerepilecopy(av, v); step = (flag&4)? sqrtr(sqrtr(step)): gmul2n(step, -2); gerepileall(av2, 2, &fa, &step); } if (it == ITMAX) pari_err_IMPL("solvestep recovery [too many iterations]"); return NULL; } GEN solvestep0(GEN a, GEN b, GEN step, GEN code, long flag, long prec) { EXPR_WRAP(code, solvestep(EXPR_ARG, a,b, step, flag, prec)); } /********************************************************************/ /** Numerical derivation **/ /********************************************************************/ struct deriv_data { GEN code; GEN args; }; static GEN deriv_eval(void *E, GEN x, long prec) { struct deriv_data *data=(struct deriv_data *)E; gel(data->args,1)=x; return closure_callgenvecprec(data->code, data->args, prec); } /* Rationale: (f(2^-e) - f(-2^-e) + O(2^-b)) / (2 * 2^-e) = f'(0) + O(2^-2e) * since 2nd derivatives cancel. * prec(LHS) = b - e * prec(RHS) = 2e, equal when b = 3e = 3/2 b0 (b0 = required final bitprec) * * For f'(x), x far from 0: prec(LHS) = b - e - expo(x) * --> pr = 3/2 b0 + expo(x) */ GEN derivnum(void *E, GEN (*eval)(void *, GEN, long), GEN x, long prec) { long newprec, e, ex = gexpo(x), p = precision(x); long b0 = prec2nbits(p? p: prec), b = (long)ceil(b0 * 1.5 + maxss(0,ex)); GEN eps, u, v, y; pari_sp av = avma; newprec = nbits2prec(b + BITS_IN_LONG); switch(typ(x)) { case t_REAL: case t_COMPLEX: x = gprec_w(x, newprec); } e = b0/2; /* 1/2 required prec (in sig. bits) */ b -= e; /* >= b0 */ eps = real2n(-e, ex < -e? newprec: nbits2prec(b)); u = eval(E, gsub(x, eps), newprec); v = eval(E, gadd(x, eps), newprec); y = gmul2n(gsub(v,u), e-1); return gerepilecopy(av, gprec_wtrunc(y, nbits2prec(b0))); } /* Fornberg interpolation algorithm for finite differences coefficients * using N+1 equidistant grid points around 0 [ assume N even >= M ]. * Compute \delta[m]_{N,nu} for all derivation orders m = 0..M such that * h^m * f^{(m)}(0) = \sum_{nu = 0}^n delta[m]_{N,nu} f(a_nu) + O(h^{N-m+1}), * for step size h. * Return a = [0,-1,1...,-N2,N2] and vector of vectors d: d[m+1][nu+1] * = (M!/m!) * delta[m]_{N,nu}, nu = 0..N */ static void FD(long M, long N, GEN *pd, GEN *pa) { GEN d, a, b, W, Wp, t, F, Mfact; long N2, m, nu, i; if (odd(N)) N++; /* make it even */ N2 = N>>1; F = cgetg(N+2, t_VEC); a = cgetg(N+2, t_VEC); b = cgetg(N2+1, t_VEC); gel(a,1) = gen_0; for (i = 1; i <= N2; i++) { gel(a,2*i) = utoineg(i); gel(a,2*i+1) = utoipos(i); gel(b,i) = sqru(i); } /* w = \prod (X - a[i]) = x W(x^2) */ Mfact = mpfact(M); W = roots_to_pol(b, 0); Wp = ZX_deriv(W); t = gel(W,2); /* w'(0) */ t = diviiexact(t, Mfact); gel(F,1) = RgX_Rg_div(RgX_inflate(W,2), t); for (i = 1; i <= N2; i++) { /* t = w'(a_{2i}) = w'(a_{2i+1}) */ GEN r, t = mulii(shifti(gel(b,i),1), poleval(Wp, gel(b,i))); GEN U, S, T; U = RgX_inflate(RgX_div_by_X_x(W, gel(b,i), &r), 2); U = RgX_shift_shallow(U, 1); U = RgXn_red_shallow(U, M+1); /* higher terms not needed */ t = diviiexact(t, Mfact); U = RgX_Rg_div(U, t); S = RgX_shift_shallow(U,1); T = RgX_Rg_mul(U, gel(a,2*i+1)); gel(F,2*i) = RgX_sub(S, T); gel(F,2*i+1) = RgX_add(S, T); } /* F[i] = M! w(X) / ((X-a[i])w'(a[i])) + O(X^(M+1)) */ d = cgetg(M+2, t_VEC); for (m = 0; m <= M; m++) { GEN v = cgetg(N+2, t_VEC); /* coeff(F[nu],X^m) */ for (nu = 0; nu <= N; nu++) gel(v, nu+1) = gmael(F, nu+1, m+2); gel(d,m+1) = v; } *pd = d; *pa = a; } static void chk_ord(long m) { if (m < 0) pari_err_DOMAIN("derivnumk", "derivation order", "<", gen_0, stoi(m)); } GEN derivnumk(void *E, GEN (*eval)(void *, GEN, long), GEN x, GEN ind0, long prec) { GEN A, D, X, F, ind; long M, fpr, p, i, pr, l, lA, e, ex, eD, newprec; pari_sp av = avma; int allodd = 1; ind = gtovecsmall(ind0); l = lg(ind); F = cgetg(l, t_VEC); M = vecsmall_max(ind); chk_ord(M); if (!M) /* silly degenerate case */ { X = eval(E, x, prec); for (i = 1; i < l; i++) { chk_ord(ind[i]); gel(F,i) = X; } if (typ(ind0) == t_INT) F = gel(F,1); return gerepilecopy(av, F); } FD(M, 3*M-1, &D,&A); /* optimal if 'eval' uses quadratic time */ p = precision(x); fpr = p ? prec2nbits(p): prec2nbits(prec); eD = gexpo(gel(D,M)); e = (fpr + 3*M*log2((double)M)) / (2*M); ex = gexpo(x); if (ex < 0) ex = 0; /* near 0 */ pr = (long)ceil(fpr + e * M); /* ~ 3fpr/2 */ newprec = nbits2prec(pr + eD + ex + BITS_IN_LONG); switch(typ(x)) { case t_REAL: case t_COMPLEX: x = gprec_w(x, newprec); } lA = lg(A); X = cgetg(lA, t_VEC); for (i = 1; i < l; i++) if (!odd(ind[i])) { allodd = 0; break; } /* if only odd derivation orders, the value at 0 (A[1]) is not needed */ gel(X, 1) = gen_0; for (i = allodd? 2: 1; i < lA; i++) { GEN t = eval(E, gadd(x, gmul2n(gel(A,i), -e)), newprec); if (!gprecision(t)) t = is_scalar_t(typ(t))? gtofp(t, newprec): gmul(t, real_1(newprec)); gel(X, i) = t; } for (i = 1; i < l; i++) { GEN t; long m = ind[i]; chk_ord(m); t = gmul2n(RgV_dotproduct(gel(D,m+1), X), e*m); if (m < M) t = gdiv(t, mulu_interval(m+1,M)); gel(F,i) = t; } if (typ(ind0) == t_INT) F = gel(F,1); return gerepilecopy(av, gprec_w(F, nbits2prec(fpr))); } /* v(t') */ static long rfrac_val_deriv(GEN t) { long v = varn(gel(t,2)); return gvaluation(deriv(t, v), pol_x(v)); } GEN derivfunk(void *E, GEN (*eval)(void *, GEN, long), GEN x, GEN ind0, long prec) { pari_sp av; GEN ind, xp, ixp, F, G; long i, l, vx, M; if (!ind0) return derivfun(E, eval, x, prec); switch(typ(x)) { case t_REAL: case t_INT: case t_FRAC: case t_COMPLEX: return derivnumk(E,eval, x, ind0, prec); case t_POL: ind = gtovecsmall(ind0); M = vecsmall_max(ind); xp = RgX_deriv(x); x = RgX_to_ser(x, precdl+2 + M * (1+RgX_val(xp))); break; case t_RFRAC: ind = gtovecsmall(ind0); M = vecsmall_max(ind); x = rfrac_to_ser(x, precdl+2 + M * (1+rfrac_val_deriv(x))); xp = derivser(x); break; case t_SER: ind = gtovecsmall(ind0); M = vecsmall_max(ind); xp = derivser(x); break; default: pari_err_TYPE("numerical derivation",x); return NULL; /*LCOV_EXCL_LINE*/ } av = avma; chk_ord(M); vx = varn(x); ixp = M? ginv(xp): NULL; F = cgetg(M+2, t_VEC); gel(F,1) = eval(E, x, prec); for (i = 1; i <= M; i++) gel(F,i+1) = gmul(deriv(gel(F,i),vx), ixp); l = lg(ind); G = cgetg(l, t_VEC); for (i = 1; i < l; i++) { long m = ind[i]; chk_ord(m); gel(G,i) = gel(F,m+1); } if (typ(ind0) == t_INT) G = gel(G,1); return gerepilecopy(av, G); } GEN derivfun(void *E, GEN (*eval)(void *, GEN, long), GEN x, long prec) { pari_sp av = avma; GEN xp; long vx; switch(typ(x)) { case t_REAL: case t_INT: case t_FRAC: case t_COMPLEX: return derivnum(E,eval, x, prec); case t_POL: xp = RgX_deriv(x); x = RgX_to_ser(x, precdl+2+ (1 + RgX_val(xp))); break; case t_RFRAC: x = rfrac_to_ser(x, precdl+2+ (1 + rfrac_val_deriv(x))); /* fall through */ case t_SER: xp = derivser(x); break; default: pari_err_TYPE("formal derivation",x); return NULL; /*LCOV_EXCL_LINE*/ } vx = varn(x); return gerepileupto(av, gdiv(deriv(eval(E, x, prec),vx), xp)); } GEN laurentseries(void *E, GEN (*f)(void*,GEN x, long), long M, long v, long prec) { pari_sp av = avma; long d; if (v < 0) v = 0; d = maxss(M+1,1); for (;;) { long i, dr, vr; GEN s; s = cgetg(d+2, t_SER); s[1] = evalsigne(1) | evalvalp(1) | evalvarn(v); gel(s, 2) = gen_1; for (i = 3; i <= d+1; i++) gel(s, i) = gen_0; s = f(E, s, prec); if (typ(s) != t_SER || varn(s) != v) pari_err_TYPE("laurentseries", s); vr = valp(s); if (M < vr) { avma = av; return zeroser(v, M); } dr = lg(s) + vr - 3 - M; if (dr >= 0) return gerepileupto(av, s); avma = av; d -= dr; } } static GEN _evalclosprec(void *E, GEN x, long prec) { GEN s; push_localprec(prec); s = closure_callgen1((GEN)E, x); pop_localprec(); return s; } #define CLOS_ARGPREC __E, &_evalclosprec GEN laurentseries0(GEN f, long M, long v, long prec) { if (typ(f) != t_CLOSURE || closure_arity(f) != 1 || closure_is_variadic(f)) pari_err_TYPE("laurentseries",f); EXPR_WRAP(f, laurentseries(CLOS_ARGPREC,M,v,prec)); } GEN derivnum0(GEN a, GEN code, GEN ind, long prec) { EXPR_WRAP(code, derivfunk(EXPR_ARGPREC,a,ind,prec)); } GEN derivfun0(GEN code, GEN args, long prec) { struct deriv_data E; E.code=code; E.args=args; return derivfun((void*)&E, deriv_eval, gel(args,1), prec); } /********************************************************************/ /** Numerical extrapolation **/ /********************************************************************/ /* for t_CLOSURE */ static double fun_getmf(long mul) { const double A[] = {0, 0.331,0.260,0.228,0.210,0.198, 0.188,0.181,0.175,0.170,0.166 }; const double B[] = {0, 0.166,0.142,0.132,0.125,0.120, 0.116,0.113,0.111,0.109,0.107 }; if (mul <= 10) return A[mul]; if (mul <= 109) return B[mul/10]; else return 0.105; } /* for t_VEC */ static double vec_getmf(long mul) { const double A[] = {0, 0.2062, 0.1760, 0.1613, 0.1519, 0.1459, 0.1401, 0.1360, 0.1327, 0.1299, 0.1280 }; const double B[] = {0, 0.1280, 0.1133, 0.1064, 0.1019, 0.0987, 0.0962, 0.0942, 0.0925, 0.0911, 0.0899 }; if (mul <= 10) return A[mul]; if (mul <= 109) return B[mul/10]; else return 0.0899; } /* [u(n*muli), u <= N], muli = 1 unless f!=NULL */ static GEN get_u(void *E, GEN (*f)(void *, GEN, long), long N, long muli, long prec) { long n; GEN u = cgetg(N+1, t_VEC); if (f) { for (n = 1; n <= N; n++) gel(u,n) = f(E, stoi(muli*n), prec); } else { GEN v = (GEN)E; long t = lg(v)-1; if (t < N*muli) pari_err_COMPONENT("limitnum","<",stoi(N), stoi(t)); for (n = 1; n <= N; n++) gel(u,n) = gel(v, muli*n); } for (n = 1; n <= N; n++) { GEN un = gel(u,n); if (is_rational_t(typ(un))) gel(u,n) = gtofp(un, prec); } return u; } struct limit { long prec0; /* target accuracy */ long prec; /* working accuracy */ long N; /* number of terms */ GEN u; /* sequence to extrapolate */ GEN na; /* [n^alpha, n <= N] */ GEN nma; /* [n^-alpha, n <= N] or NULL (alpha = 1) */ GEN coef; /* or NULL (alpha != 1) */ }; static void limit_init(struct limit *L, void *E, GEN (*f)(void*,GEN,long), long muli, GEN alpha, long prec) { long bitprec = prec2nbits(prec), n, N; GEN na; if (muli <= 0) muli = 20; L->N = N = (long)ceil((f? fun_getmf(muli): vec_getmf(muli)) * bitprec); L->prec = nbits2prec(bitprec + (long)ceil(1.844*N)); L->prec0 = prec; L->u = get_u(E, f, N, muli, L->prec); if (alpha && !gequal1(alpha)) { long prec2 = gprecision(alpha); GEN nma; if (!prec2) prec2 = L->prec; na = vecpowug(N, alpha, prec2); L->coef = NULL; L->nma = nma = cgetg(N+1, t_VEC); for (n = 1; n <= N; n++) gel(nma, n) = ginv(gel(na, n)); if (muli != 1) na = gmul(na, gpow(utor(muli,prec2), alpha, prec2)); } else { GEN coef, C = vecbinomial(N), T = vecpowuu(N, N); na = cgetg(N+1, t_VEC); L->coef = coef = cgetg(N+1, t_VEC); L->nma = NULL; for (n = 1; n <= N; n++) { GEN c = mulii(gel(C,n+1), gel(T,n)); if (odd(N-n)) togglesign_safe(&c); gel(coef, n) = c; gel(na, n) = utoipos(n*muli); } } L->na = na; } /* Zagier/Lagrange extrapolation */ static GEN limitnum_i(struct limit *L) { pari_sp av = avma; GEN S; if (L->nma) S = polint(L->nma, L->u,gen_0,NULL); else S = gdiv(RgV_dotproduct(L->u,L->coef), mpfact(L->N)); return gerepilecopy(av, gprec_w(S, L->prec0)); } GEN limitnum(void *E, GEN (*f)(void *, GEN, long), long muli, GEN alpha, long prec) { struct limit L; limit_init(&L, E,f, muli, alpha, prec); return limitnum_i(&L); } GEN limitnum0(GEN u, long muli, GEN alpha, long prec) { void *E = (void*)u; GEN (*f)(void*,GEN,long) = NULL; switch(typ(u)) { case t_COL: case t_VEC: break; case t_CLOSURE: f = gp_callprec; break; default: pari_err_TYPE("limitnum", u); } return limitnum(E,f, muli,alpha, prec); } GEN asympnum(void *E, GEN (*f)(void *, GEN, long), long muli, GEN alpha, long prec) { const long MAX = 100; pari_sp av = avma; GEN u, vres = vectrunc_init(MAX); long i, B = prec2nbits(prec); double LB = 0.9*expu(B); /* 0.9 and 0.95 below are heuristic */ struct limit L; limit_init(&L, E,f, muli, alpha, prec); if (alpha) LB *= gtodouble(alpha); u = L.u; for(i = 1; i <= MAX; i++) { GEN a, s, v, p, q; long n; s = limitnum_i(&L); /* NOT bestappr: lindep properly ignores the lower bits */ v = lindep_bit(mkvec2(gen_1, s), maxss((long)(0.95*floor(B - i*LB)), 32)); if (lg(v) == 1) break; p = negi(gel(v,1)); q = gel(v,2); if (!signe(q)) break; a = gdiv(p,q); s = gsub(s, a); /* |s|q^2 > eps */ if (!gequal0(s) && gexpo(s) + 2*expi(q) > -17) break; vectrunc_append(vres, a); for (n = 1; n <= L.N; n++) gel(u,n) = gmul(gsub(gel(u,n), a), gel(L.na,n)); } return gerepilecopy(av, vres); } GEN asympnum0(GEN u, long muli, GEN alpha, long prec) { void *E = (void*)u; GEN (*f)(void*,GEN,long) = NULL; switch(typ(u)) { case t_COL: case t_VEC: break; case t_CLOSURE: f = gp_callprec; break; default: pari_err_TYPE("asympnum", u); } return asympnum(E,f, muli,alpha, prec); } pari-2.11.2/src/language/paricfg.c0000644000175000017500000000166613326135265015326 0ustar billbill/* Copyright (C) 2010 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" const char *paricfg_datadir = GPDATADIR; const char *paricfg_version = PARIVERSION; const char *paricfg_buildinfo = PARIINFO; const long paricfg_version_code = PARI_VERSION_CODE; const char *paricfg_vcsversion = PARI_VCSVERSION; const char *paricfg_compiledate = __DATE__; const char *paricfg_mt_engine = PARI_MT_ENGINE; const char *paricfg_gphelp = GPHELP; pari-2.11.2/src/language/forprime.c0000644000175000017500000010066413457566440015544 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /**********************************************************************/ /*** ***/ /*** Public prime table ***/ /*** ***/ /**********************************************************************/ static ulong _maxprime = 0; static ulong diffptrlen; /* Building/Rebuilding the diffptr table. The actual work is done by the * following two subroutines; the user entry point is the function * initprimes() below. initprimes1() is the old algorithm, called when * maxnum (size) is moderate. Must be called after pari_init_stack() )*/ static void initprimes1(ulong size, long *lenp, ulong *lastp, byteptr p1) { pari_sp av = avma; long k; byteptr q, r, s, p = (byteptr)stack_calloc(size+2), fin = p + size; for (r=q=p,k=1; r<=fin; ) { do { r+=k; k+=2; r+=k; } while (*++q); for (s=r; s<=fin; s+=k) *s = 1; } r = p1; *r++ = 2; *r++ = 1; /* 2 and 3 */ for (s=q=p+1; ; s=q) { do q++; while (*q); if (q > fin) break; *r++ = (unsigned char) ((q-s) << 1); } *r++ = 0; *lenp = r - p1; *lastp = ((s - p) << 1) + 1; avma = av; } /* Timing in ms (Athlon/850; reports 512K of secondary cache; looks like there is 64K of quickier cache too). arena| 30m 100m 300m 1000m 2000m <-- primelimit ================================================= 16K 1.1053 1.1407 1.2589 1.4368 1.6086 24K 1.0000 1.0625 1.1320 1.2443 1.3095 32K 1.0000 1.0469 1.0761 1.1336 1.1776 48K 1.0000 1.0000 1.0254 1.0445 1.0546 50K 1.0000 1.0000 1.0152 1.0345 1.0464 52K 1.0000 1.0000 1.0203 1.0273 1.0362 54K 1.0000 1.0000 1.0812 1.0216 1.0281 56K 1.0526 1.0000 1.0051 1.0144 1.0205 58K 1.0000 1.0000 1.0000 1.0086 1.0123 60K 0.9473 0.9844 1.0051 1.0014 1.0055 62K 1.0000 0.9844 0.9949 0.9971 0.9993 64K 1.0000 1.0000 1.0000 1.0000 1.0000 66K 1.2632 1.2187 1.2183 1.2055 1.1953 68K 1.4211 1.4844 1.4721 1.4425 1.4188 70K 1.7368 1.7188 1.7107 1.6767 1.6421 72K 1.9474 1.9531 1.9594 1.9023 1.8573 74K 2.2105 2.1875 2.1827 2.1207 2.0650 76K 2.4211 2.4219 2.4010 2.3305 2.2644 78K 2.5789 2.6250 2.6091 2.5330 2.4571 80K 2.8421 2.8125 2.8223 2.7213 2.6380 84K 3.1053 3.1875 3.1776 3.0819 2.9802 88K 3.5263 3.5312 3.5228 3.4124 3.2992 92K 3.7895 3.8438 3.8375 3.7213 3.5971 96K 4.0000 4.1093 4.1218 3.9986 3.9659 112K 4.3684 4.5781 4.5787 4.4583 4.6115 128K 4.7368 4.8750 4.9188 4.8075 4.8997 192K 5.5263 5.7188 5.8020 5.6911 5.7064 256K 6.0000 6.2187 6.3045 6.1954 6.1033 384K 6.7368 6.9531 7.0405 6.9181 6.7912 512K 7.3158 7.5156 7.6294 7.5000 7.4654 768K 9.1579 9.4531 9.6395 9.5014 9.1075 1024K 10.368 10.7497 10.9999 10.878 10.8201 1536K 12.579 13.3124 13.7660 13.747 13.4739 2048K 13.737 14.4839 15.0509 15.151 15.1282 3076K 14.789 15.5780 16.2993 16.513 16.3365 Now the same number relative to the model (1 + 0.36*sqrt(primelimit)/arena) * (arena <= 64 ? 1.05 : (arena-64)**0.38) [SLOW2_IN_ROOTS = 0.36, ALPHA = 0.38] arena| 30m 100m 300m 1000m 2000m <-- primelimit ================================================= 16K 1.014 0.9835 0.9942 0.9889 1.004 24K 0.9526 0.9758 0.9861 0.9942 0.981 32K 0.971 0.9939 0.9884 0.9849 0.9806 48K 0.9902 0.9825 0.996 0.9945 0.9885 50K 0.9917 0.9853 0.9906 0.9926 0.9907 52K 0.9932 0.9878 0.9999 0.9928 0.9903 54K 0.9945 0.9902 1.064 0.9939 0.9913 56K 1.048 0.9924 0.9925 0.993 0.9921 58K 0.9969 0.9945 0.9909 0.9932 0.9918 60K 0.9455 0.9809 0.9992 0.9915 0.9923 62K 0.9991 0.9827 0.9921 0.9924 0.9929 64K 1 1 1 1 1 66K 1.02 0.9849 0.9857 0.9772 0.9704 68K 0.8827 0.9232 0.9176 0.9025 0.8903 70K 0.9255 0.9177 0.9162 0.9029 0.8881 72K 0.9309 0.936 0.9429 0.9219 0.9052 74K 0.9715 0.9644 0.967 0.9477 0.9292 76K 0.9935 0.9975 0.9946 0.9751 0.9552 78K 0.9987 1.021 1.021 1.003 0.9819 80K 1.047 1.041 1.052 1.027 1.006 84K 1.052 1.086 1.092 1.075 1.053 88K 1.116 1.125 1.133 1.117 1.096 92K 1.132 1.156 1.167 1.155 1.134 96K 1.137 1.177 1.195 1.185 1.196 112K 1.067 1.13 1.148 1.15 1.217 128K 1.04 1.083 1.113 1.124 1.178 192K 0.9368 0.985 1.025 1.051 1.095 256K 0.8741 0.9224 0.9619 0.995 1.024 384K 0.8103 0.8533 0.8917 0.9282 0.9568 512K 0.7753 0.8135 0.8537 0.892 0.935 768K 0.8184 0.8638 0.9121 0.9586 0.9705 1024K 0.8241 0.8741 0.927 0.979 1.03 1536K 0.8505 0.9212 0.9882 1.056 1.096 2048K 0.8294 0.8954 0.9655 1.041 1.102 */ #ifndef SLOW2_IN_ROOTS /* SLOW2_IN_ROOTS below 3: some slowdown starts to be noticable * when things fit into the cache on Sparc. * The choice of 2.6 gives a slowdown of 1-2% on UltraSparcII, * but makes calculations for "maximum" of 436273009 * fit into 256K cache (still common for some architectures). * * One may change it when small caches become uncommon, but the gain * is not going to be very noticable... */ # ifdef i386 /* gcc defines this? */ # define SLOW2_IN_ROOTS 0.36 # else # define SLOW2_IN_ROOTS 2.6 # endif #endif #ifndef CACHE_ARENA # ifdef i386 /* gcc defines this? */ /* Due to smaller SLOW2_IN_ROOTS, smaller arena is OK; fit L1 cache */ # define CACHE_ARENA (63 * 1024UL) /* No slowdown even with 64K L1 cache */ # else # define CACHE_ARENA (200 * 1024UL) /* No slowdown even with 256K L2 cache */ # endif #endif #define CACHE_ALPHA (0.38) /* Cache performance model parameter */ #define CACHE_CUTOFF (0.018) /* Cache performance not smooth here */ static double slow2_in_roots = SLOW2_IN_ROOTS; typedef struct { ulong arena; double power; double cutoff; } cache_model_t; static cache_model_t cache_model = { CACHE_ARENA, CACHE_ALPHA, CACHE_CUTOFF }; /* Assume that some calculation requires a chunk of memory to be accessed often in more or less random fashion (as in sieving). Assume that the calculation can be done in steps by subdividing the chunk into smaller subchunks (arenas) and treating them separately. Assume that the overhead of subdivision is equivalent to the number of arenas. Find an optimal size of the arena taking into account the overhead of subdivision, and the overhead of arena not fitting into the cache. Assume that arenas of size slow2_in_roots slows down the calculation 2x (comparing to very big arenas; when cache hits do not matter). Since cache performance varies wildly with architecture, load, and wheather (especially with cache coloring enabled), use an idealized cache model based on benchmarks above. Assume that an independent region of FIXED_TO_CACHE bytes is accessed very often concurrently with the arena access. */ static ulong good_arena_size(ulong slow2_size, ulong total, ulong fixed_to_cache, cache_model_t *cache_model) { ulong asize, cache_arena = cache_model->arena; double Xmin, Xmax, A, B, C1, C2, D, V; double alpha = cache_model->power, cut_off = cache_model->cutoff; /* Estimated relative slowdown, with overhead = max((fixed_to_cache+arena)/cache_arena - 1, 0): 1 + slow2_size/arena due to initialization overhead; max(1, 4.63 * overhead^0.38 ) due to footprint > cache size. [The latter is hard to substantiate theoretically, but this function describes benchmarks pretty close; it does not hurt that one can minimize it explicitly too ;-). The switch between different choices of max() happens when overhead=0.018.] Thus the problem is minimizing (1 + slow2_size/arena)*overhead**0.29. This boils down to F=((X+A)/(X+B))X^alpha, X=overhead, B = (1 - fixed_to_cache/cache_arena), A = B + slow2_size/cache_arena, alpha = 0.38, and X>=0.018, X>-B. We need to find the rightmost root of (X+A)*(X+B) - alpha(A-B)X to the right of 0.018 (if such exists and is below Xmax). Then we manually check the remaining region [0, 0.018]. Since we cannot trust the purely-experimental cache-hit slowdown function, as a sanity check always prefer fitting into the cache (or "almost fitting") if F-law predicts that the larger value of the arena provides less than 10% speedup. */ /* The simplest case: we fit into cache */ asize = cache_arena - fixed_to_cache; if (total <= asize) return total; /* The simple case: fitting into cache doesn't slow us down more than 10% */ if (asize > 10 * slow2_size) return asize; /* Slowdown of not fitting into cache is significant. Try to optimize. Do not be afraid to spend some time on optimization - in trivial cases we do not reach this point; any gain we get should compensate the time spent on optimization. */ B = (1 - ((double)fixed_to_cache)/cache_arena); A = B + ((double)slow2_size)/cache_arena; C2 = A*B; C1 = (A + B - 1/alpha*(A - B))/2; D = C1*C1 - C2; if (D > 0) V = cut_off*cut_off + 2*C1*cut_off + C2; /* Value at CUT_OFF */ else V = 0; /* Peacify the warning */ Xmin = cut_off; Xmax = ((double)total - fixed_to_cache)/cache_arena; /* Two candidates */ if ( D <= 0 || (V >= 0 && C1 + cut_off >= 0) ) /* slowdown increasing */ Xmax = cut_off; /* Only one candidate */ else if (V >= 0 && /* slowdown concave down */ ((Xmax + C1) <= 0 || (Xmax*Xmax + 2*C1*Xmax + C2) <= 0)) /* DO NOTHING */; /* Keep both candidates */ else if (V <= 0 && (Xmax*Xmax + 2*C1*Xmax + C2) <= 0) /*slowdown decreasing*/ Xmin = cut_off; /* Only one candidate */ else /* Now we know: 2 roots, the largest is in CUT_OFF..Xmax */ Xmax = sqrt(D) - C1; if (Xmax != Xmin) { /* Xmin == CUT_OFF; Check which one is better */ double v1 = (cut_off + A)/(cut_off + B); double v2 = 2.33 * (Xmax + A)/(Xmax + B) * pow(Xmax, alpha); if (1.1 * v2 >= v1) /* Prefer fitting into the cache if slowdown < 10% */ V = v1; else { Xmin = Xmax; V = v2; } } else if (B > 0) /* We need V */ V = 2.33 * (Xmin + A)/(Xmin + B) * pow(Xmin, alpha); if (B > 0 && 1.1 * V > A/B) /* Now Xmin is the minumum. Compare with 0 */ Xmin = 0; asize = (ulong)((1 + Xmin)*cache_arena - fixed_to_cache); if (asize > total) asize = total; /* May happen due to approximations */ return asize; } /* Use as in install(set_optimize,lLDG) \\ Through some M too? set_optimize(2,1) \\ disable dependence on limit \\ 1: how much cache usable, 2: slowdown of setup, 3: alpha, 4: cutoff \\ 2,3,4 are in units of 0.001 { time_primes_arena(ar,limit) = \\ ar = arena size in K set_optimize(1,floor(ar*1024)); default(primelimit, 200 000); \\ 100000 results in *larger* malloc()! gettime; default(primelimit, floor(limit)); if(ar >= 1, ar=floor(ar)); print("arena "ar"K => "gettime"ms"); } */ long set_optimize(long what, GEN g) { long ret = 0; switch (what) { case 1: ret = (long)cache_model.arena; break; case 2: ret = (long)(slow2_in_roots * 1000); break; case 3: ret = (long)(cache_model.power * 1000); break; case 4: ret = (long)(cache_model.cutoff * 1000); break; default: pari_err_BUG("set_optimize"); break; } if (g != NULL) { ulong val = itou(g); switch (what) { case 1: cache_model.arena = val; break; case 2: slow2_in_roots = (double)val / 1000.; break; case 3: cache_model.power = (double)val / 1000.; break; case 4: cache_model.cutoff = (double)val / 1000.; break; } } return ret; } /* s is odd; prime differences (starting from 5-3=2) start at known_primes[2], terminated by a 0 byte. Checks n odd numbers starting at 'start', setting bytes starting at data to 0 (composite) or 1 (prime) */ static void sieve_chunk(byteptr known_primes, ulong s, byteptr data, ulong n) { ulong p, cnt = n-1, start = s, delta = 1; byteptr q; memset(data, 0, n); start >>= 1; /* (start - 1)/2 */ start += n; /* Corresponds to the end */ /* data corresponds to start, q runs over primediffs */ for (q = known_primes + 1, p = 3; delta; delta = *++q, p += delta) { /* first odd number >= start > p and divisible by p = last odd number <= start + 2p - 2 and 0 (mod p) = p + last number <= start + p - 2 and 0 (mod 2p) = p + start+p-2 - (start+p-2) % 2p = start + 2(p - 1 - ((start-1)/2 + (p-1)/2) % p). */ long off = cnt - ((start+(p>>1)) % p); while (off >= 0) { data[off] = 1; off -= p; } } } /* assume maxnum <= 436273289 < 2^29 */ static void initprimes0(ulong maxnum, long *lenp, ulong *lastp, byteptr p1) { pari_sp av = avma, bot = pari_mainstack->bot; long alloced, psize; byteptr q, end, p, end1, plast, curdiff; ulong last, remains, curlow, rootnum, asize; ulong prime_above; byteptr p_prime_above; maxnum |= 1; /* make it odd. */ /* base case */ if (maxnum < 1ul<<17) { initprimes1(maxnum>>1, lenp, lastp, p1); return; } /* Checked to be enough up to 40e6, attained at 155893 */ rootnum = usqrt(maxnum) | 1; initprimes1(rootnum>>1, &psize, &last, p1); end1 = p1 + psize - 1; remains = (maxnum - last) >> 1; /* number of odd numbers to check */ /* we access primes array of psize too; but we access it consecutively, * thus we do not include it in fixed_to_cache */ asize = good_arena_size((ulong)(rootnum * slow2_in_roots), remains+1, 0, &cache_model) - 1; /* enough room on the stack ? */ alloced = (((byteptr)avma) <= ((byteptr)bot) + asize); if (alloced) p = (byteptr)pari_malloc(asize+1); else p = (byteptr)stack_malloc(asize+1); end = p + asize; /* the 0 sentinel goes at end. */ curlow = last + 2; /* First candidate: know primes up to last (odd). */ curdiff = end1; /* During each iteration p..end-1 represents a range of odd numbers. plast is a pointer which represents the last prime seen, it may point before p..end-1. */ plast = p - 1; p_prime_above = p1 + 2; prime_above = 3; while (remains) { /* cycle over arenas; performance not crucial */ unsigned char was_delta; if (asize > remains) { asize = remains; end = p + asize; } /* Fake the upper limit appropriate for the given arena */ while (prime_above*prime_above <= curlow + (asize << 1) && *p_prime_above) prime_above += *p_prime_above++; was_delta = *p_prime_above; *p_prime_above = 0; /* sentinel for sieve_chunk */ sieve_chunk(p1, curlow, p, asize); *p_prime_above = was_delta; /* restore */ p[asize] = 0; /* sentinel */ for (q = p; ; plast = q++) { /* q runs over addresses corresponding to primes */ while (*q) q++; /* use sentinel at end */ if (q >= end) break; *curdiff++ = (unsigned char)(q-plast) << 1; /* < 255 for q < 436273291 */ } plast -= asize; remains -= asize; curlow += (asize<<1); } last = curlow - ((p - plast) << 1); *curdiff++ = 0; /* sentinel */ *lenp = curdiff - p1; *lastp = last; if (alloced) pari_free(p); else avma = av; } ulong maxprime(void) { return diffptr ? _maxprime : 0; } void maxprime_check(ulong c) { if (_maxprime < c) pari_err_MAXPRIME(c); } /* We ensure 65302 <= maxnum <= 436273289: the LHS ensures modular function * have enough fast primes to work, the RHS ensures that p_{n+1} - p_n < 255 * (N.B. RHS would be incorrect since initprimes0 would make it odd, thereby * increasing it by 1) */ byteptr initprimes(ulong maxnum, long *lenp, ulong *lastp) { byteptr t; if (maxnum < 65537) maxnum = 65537; else if (maxnum > 436273289) maxnum = 436273289; t = (byteptr)pari_malloc((size_t) (1.09 * maxnum/log((double)maxnum)) + 146); initprimes0(maxnum, lenp, lastp, t); return (byteptr)pari_realloc(t, *lenp); } void initprimetable(ulong maxnum) { long len; ulong last; byteptr p = initprimes(maxnum, &len, &last), old = diffptr; diffptrlen = minss(diffptrlen, len); _maxprime = minss(_maxprime,last); /*Protect against ^C*/ diffptr = p; diffptrlen = len; _maxprime = last; if (old) free(old); } /* all init_primepointer_xx routines set *ptr to the corresponding place * in prime table */ /* smallest p >= a */ ulong init_primepointer_geq(ulong a, byteptr *pd) { ulong n, p; prime_table_next_p(a, pd, &p, &n); return p; } /* largest p < a */ ulong init_primepointer_lt(ulong a, byteptr *pd) { ulong n, p; prime_table_next_p(a, pd, &p, &n); PREC_PRIME_VIADIFF(p, *pd); return p; } /* largest p <= a */ ulong init_primepointer_leq(ulong a, byteptr *pd) { ulong n, p; prime_table_next_p(a, pd, &p, &n); if (p != a) PREC_PRIME_VIADIFF(p, *pd); return p; } /* smallest p > a */ ulong init_primepointer_gt(ulong a, byteptr *pd) { ulong n, p; prime_table_next_p(a, pd, &p, &n); if (p == a) NEXT_PRIME_VIADIFF(p, *pd); return p; } /**********************************************************************/ /*** ***/ /*** forprime ***/ /*** ***/ /**********************************************************************/ /* return good chunk size for sieve, 16 | chunk + 2 */ static ulong optimize_chunk(ulong a, ulong b) { /* TODO: Optimize size (surely < 512k to stay in L2 cache, but not so large * as to force recalculating too often). */ ulong chunk = 0x80000UL; ulong tmp = (b - a) / chunk + 1; if (tmp == 1) chunk = b - a + 16; else chunk = (b - a) / tmp + 15; /* ensure 16 | chunk + 2 */ return (((chunk + 2)>>4)<<4) - 2; } static void sieve_init(forprime_t *T, ulong a, ulong b) { T->sieveb = b; T->chunk = optimize_chunk(a, b); T->isieve = (unsigned char*)stack_malloc(((T->chunk+2) >> 4) + 1); T->cache[0] = 0; /* >> 1 [only odds] + 3 [convert from bits to bytes] */ T->a = a; T->end = minuu(a + T->chunk, b); T->pos = T->maxpos = 0; } enum {PRST_none, PRST_diffptr, PRST_sieve, PRST_unextprime, PRST_nextprime}; static void u_forprime_set_prime_table(forprime_t *T, ulong a) { T->strategy = PRST_diffptr; if (a < 3) { T->p = 0; T->d = diffptr; } else T->p = init_primepointer_lt(a, &T->d); } /* Set p so that p + q the smallest integer = c (mod q) and > original p. * Assume 0 < c < q. Set p = 0 on overflow */ static void arith_set(forprime_t *T) { ulong r = T->p % T->q; /* 0 <= r <= min(p, q-1) */ pari_sp av = avma; GEN d = adduu(T->p - r, T->c); if (T->c > r) d = subiu(d, T->q); /* d = c mod q, d = c > r? p-r+c-q: p-r+c, so that * d <= p and d+q = c>r? p-r+c : p-r+c+q > p */ T->p = itou_or_0(d); avma = av; /* d = 0 is impossible */ } /* run through primes in arithmetic progression = c (mod q) */ static int u_forprime_sieve_arith_init(forprime_t *T, struct pari_sieve *psieve, ulong a, ulong b, ulong c, ulong q) { ulong maxp, maxp2; if (!odd(b) && b > 2) b--; if (a > b || b < 2) { T->strategy = PRST_diffptr; /* paranoia */ T->p = 0; /* empty */ T->b = 0; /* empty */ T->d = diffptr; return 0; } maxp = maxprime(); if (q != 1) { c %= q; if (ugcd(c,q) != 1) { a = maxuu(a,c); b = minuu(b,c); } if (odd(q) && (a > 2 || c != 2)) { /* only *odd* primes. If a <= c = 2, then p = 2 must be included :-( */ if (!odd(c)) c += q; q <<= 1; } } T->q = q; T->c = c; T->strategy = PRST_none; /* unknown */ T->psieve = psieve; /* unused for now */ T->isieve = NULL; /* unused for now */ T->b = b; if (maxp >= b) { /* [a,b] \subset prime table */ u_forprime_set_prime_table(T, a); return 1; } /* b > maxp */ if (a >= maxp) { T->p = a - 1; if (T->q > 1) arith_set(T); } else u_forprime_set_prime_table(T, a); maxp2 = (maxp & HIGHMASK)? 0 : maxp*maxp; /* FIXME: should sieve as well if q != 1, adapt sieve code */ if (q != 1 || (maxp2 && maxp2 <= a) || T->b - maxuu(a,maxp) < maxp / expu(b)) { if (T->strategy==PRST_none) T->strategy = PRST_unextprime; } else { /* worth sieving */ #ifdef LONG_IS_64BIT const ulong UPRIME_MAX = 18446744073709551557UL; #else const ulong UPRIME_MAX = 4294967291UL; #endif ulong sieveb; if (b > UPRIME_MAX) b = UPRIME_MAX; sieveb = b; if (maxp2 && maxp2 < b) sieveb = maxp2; if (T->strategy==PRST_none) T->strategy = PRST_sieve; sieve_init(T, maxuu(maxp+2, a), sieveb); } return 1; } int u_forprime_arith_init(forprime_t *T, ulong a, ulong b, ulong c, ulong q) { return u_forprime_sieve_arith_init(T, NULL, a, b, c, q); } /* will run through primes in [a,b] */ int u_forprime_init(forprime_t *T, ulong a, ulong b) { return u_forprime_arith_init(T, a,b, 0,1); } /* will run through primes in [a,b] */ static int u_forprime_sieve_init(forprime_t *T, struct pari_sieve *s, ulong b) { return u_forprime_sieve_arith_init(T, s, s->start, b, s->c, s->q); } /* now only run through primes <= c; assume c <= b above */ void u_forprime_restrict(forprime_t *T, ulong c) { T->b = c; } /* b = NULL: loop forever */ int forprimestep_init(forprime_t *T, GEN a, GEN b, GEN q) { long lb; a = gceil(a); if (typ(a) != t_INT) pari_err_TYPE("forprime_init",a); if (signe(a) <= 0) a = gen_1; if (b && typ(b) != t_INFINITY) { b = gfloor(b); if (typ(b) != t_INT) pari_err_TYPE("forprime_init",b); if (signe(b) < 0 || cmpii(a,b) > 0) { T->strategy = PRST_nextprime; /* paranoia */ T->bb = T->pp = gen_0; return 0; } lb = lgefint(b); T->bb = b; } else if (!b || inf_get_sign(b) > 0) { lb = lgefint(a) + 4; T->bb = NULL; } else /* b == -oo */ { T->strategy = PRST_nextprime; /* paranoia */ T->bb = T->pp = gen_0; return 0; } T->pp = cgeti(lb); T->c = 0; T->q = 1; /* a, b are positive integers, a <= b */ if (q) { switch(typ(q)) { case t_INT: break; case t_INTMOD: a = addii(a, modii(subii(gel(q,2),a), gel(q,1))); q = gel(q,1); break; default: pari_err_TYPE("forprimestep_init",q); } if (signe(q) <= 0) pari_err_TYPE("forprimestep_init (q <= 0)",q); if (equali1(q)) q = NULL; else { T->q = itou(q); T->c = umodiu(a, T->q); } } if (lgefint(a) == 3) /* lb == 3 implies b != NULL */ return u_forprime_arith_init(T, uel(a,2), lb == 3? uel(b,2): ULONG_MAX, T->c, T->q); T->strategy = PRST_nextprime; affii(subiu(a,T->q), T->pp); return 1; } int forprime_init(forprime_t *T, GEN a, GEN b) { return forprimestep_init(T,a,b,NULL); } /* assume a <= b <= maxprime()^2, a,b odd, sieve[n] corresponds to * a+16*n, a+16*n+2, ..., a+16*n+14 (bits 0 to 7) * maxpos = index of last sieve cell. * b-a+2 must be divisible by 16 for use by u_forprime_next */ static void sieve_block(ulong a, ulong b, ulong maxpos, unsigned char* sieve) { ulong p = 2, lim = usqrt(b), sz = (b-a) >> 1; byteptr d = diffptr+1; (void)memset(sieve, 0, maxpos+1); for (;;) { /* p is odd */ ulong k, r; NEXT_PRIME_VIADIFF(p, d); /* starts at p = 3 */ if (p > lim) break; /* solve a + 2k = 0 (mod p) */ r = a % p; if (r == 0) k = 0; else { k = p - r; if (odd(k)) k += p; k >>= 1; } /* m = a + 2k is the smallest odd m >= a, p | m */ /* position n (corresponds to a+2n) is sieve[n>>3], bit n&7 */ while (k <= sz) { sieve[k>>3] |= 1 << (k&7); k += p; /* 2k += 2p */ } } } static void pari_sieve_init(struct pari_sieve *s, ulong a, ulong b) { ulong maxpos= (b - a) >> 4; s->start = a; s->end = b; s->sieve = (unsigned char*) pari_malloc(maxpos+1); s->c = 0; s->q = 1; sieve_block(a, b, maxpos, s->sieve); s->maxpos = maxpos; /* must be last in case of SIGINT */ } static struct pari_sieve pari_sieve_modular; #ifdef LONG_IS_64BIT #define PARI_MODULAR_BASE ((1UL<<((BITS_IN_LONG-2)>>1))+1) #else #define PARI_MODULAR_BASE ((1UL<<(BITS_IN_LONG-1))+1) #endif void pari_init_primes(ulong maxprime) { ulong a = PARI_MODULAR_BASE, b = a + (1UL<<20)-2; initprimetable(maxprime); pari_sieve_init(&pari_sieve_modular, a, b); } void pari_close_primes(void) { pari_free(diffptr); pari_free(pari_sieve_modular.sieve); } void init_modular_small(forprime_t *S) { #ifdef LONG_IS_64BIT u_forprime_sieve_init(S, &pari_sieve_modular, ULONG_MAX); #else ulong a = (1UL<<((BITS_IN_LONG-2)>>1))+1; u_forprime_init(S, a, ULONG_MAX); #endif } void init_modular_big(forprime_t *S) { #ifdef LONG_IS_64BIT ulong a = (1UL<<(BITS_IN_LONG-1))+1; u_forprime_init(S, a, ULONG_MAX); #else u_forprime_sieve_init(S, &pari_sieve_modular, ULONG_MAX); #endif } /* T->cache is a 0-terminated list of primes, return the first one and * remove it from list. Most of the time the list contains a single prime */ static ulong shift_cache(forprime_t *T) { long i; T->p = T->cache[0]; for (i = 1;; i++) /* remove one prime from cache */ if (! (T->cache[i-1] = T->cache[i]) ) break; return T->p; } ulong u_forprime_next(forprime_t *T) { if (T->strategy == PRST_diffptr) { for(;;) { if (!*(T->d)) { T->strategy = T->isieve? PRST_sieve: PRST_unextprime; if (T->q != 1) { arith_set(T); if (!T->p) return 0; } /* T->p possibly not a prime if q != 1 */ break; } else { NEXT_PRIME_VIADIFF(T->p, T->d); if (T->p > T->b) return 0; if (T->q == 1 || T->p % T->q == T->c) return T->p; } } } if (T->strategy == PRST_sieve) { ulong n; if (T->cache[0]) return shift_cache(T); NEXT_CHUNK: if (T->psieve) { T->sieve = T->psieve->sieve; T->end = T->psieve->end; if (T->end > T->sieveb) T->end = T->sieveb; T->maxpos = T->psieve->maxpos; T->pos = 0; T->psieve = NULL; } for (n = T->pos; n < T->maxpos; n++) if (T->sieve[n] != 0xFF) { unsigned char mask = T->sieve[n]; ulong p = T->a + (n<<4); long i = 0; T->pos = n; if (!(mask & 1)) T->cache[i++] = p; if (!(mask & 2)) T->cache[i++] = p+2; if (!(mask & 4)) T->cache[i++] = p+4; if (!(mask & 8)) T->cache[i++] = p+6; if (!(mask & 16)) T->cache[i++] = p+8; if (!(mask & 32)) T->cache[i++] = p+10; if (!(mask & 64)) T->cache[i++] = p+12; if (!(mask &128)) T->cache[i++] = p+14; T->cache[i] = 0; T->pos = n+1; return shift_cache(T); } /* n = T->maxpos, last cell: check p <= b */ if (T->maxpos && n == T->maxpos && T->sieve[n] != 0xFF) { unsigned char mask = T->sieve[n]; ulong p = T->a + (n<<4); long i = 0; T->pos = n; if (!(mask & 1) && p <= T->sieveb) T->cache[i++] = p; if (!(mask & 2) && p <= T->sieveb-2) T->cache[i++] = p+2; if (!(mask & 4) && p <= T->sieveb-4) T->cache[i++] = p+4; if (!(mask & 8) && p <= T->sieveb-6) T->cache[i++] = p+6; if (!(mask & 16) && p <= T->sieveb-8) T->cache[i++] = p+8; if (!(mask & 32) && p <= T->sieveb-10) T->cache[i++] = p+10; if (!(mask & 64) && p <= T->sieveb-12) T->cache[i++] = p+12; if (!(mask &128) && p <= T->sieveb-14) T->cache[i++] = p+14; if (i) { T->cache[i] = 0; T->pos = n+1; return shift_cache(T); } } if (T->maxpos && T->end >= T->sieveb) /* done with sieves ? */ { if (T->sieveb == T->b && T->b != ULONG_MAX) return 0; T->strategy = PRST_unextprime; } else { /* initialize next chunk */ T->sieve = T->isieve; if (T->maxpos == 0) T->a |= 1; /* first time; ensure odd */ else T->a = (T->end + 2) | 1; T->end = T->a + T->chunk; /* may overflow */ if (T->end < T->a || T->end > T->sieveb) T->end = T->sieveb; /* end and a are odd; sieve[k] contains the a + 8*2k + (0,2,...,14). * The largest k is (end-a) >> 4 */ T->pos = 0; T->maxpos = (T->end - T->a) >> 4; sieve_block(T->a, T->end, T->maxpos, T->sieve); goto NEXT_CHUNK; } } if (T->strategy == PRST_unextprime) { if (T->q == 1) { #ifdef LONG_IS_64BIT if (T->p == (1UL<<63)) return T->p = 9223372036854775837UL; if (T->p == 9223372036854775837UL) return T->p = 9223372036854775907UL; #endif T->p = unextprime(T->p + 1); } else do { T->p += T->q; if (T->p < T->q || T->p > T->b) { T->p = 0; break; } /* overflow */ } while (!uisprime(T->p)); if (T->p && T->p <= T->b) return T->p; /* overflow ulong, switch to GEN */ T->strategy = PRST_nextprime; } return 0; /* overflow */ } GEN forprime_next(forprime_t *T) { pari_sp av; GEN p; if (T->strategy != PRST_nextprime) { ulong u = u_forprime_next(T); if (u) { affui(u, T->pp); return T->pp; } /* failure */ if (T->strategy != PRST_nextprime) return NULL; /* we're done */ /* overflow ulong, switch to GEN */ u = ULONG_MAX; if (T->q > 1) u -= (ULONG_MAX-T->c) % T->q; affui(u, T->pp); } av = avma; p = T->pp; if (T->q == 1) { p = nextprime(addiu(p, 1)); if (T->bb && abscmpii(p, T->bb) > 0) { avma = av; return NULL; } } else do { p = addiu(p, T->q); if (T->bb && abscmpii(p, T->bb) > 0) { avma = av; return NULL; } } while (!BPSW_psp(p)); affii(p, T->pp); avma = av; return T->pp; } void forprimestep(GEN a, GEN b, GEN q, GEN code) { pari_sp av = avma; forprime_t T; if (!forprimestep_init(&T, a,b,q)) { avma = av; return; } push_lex(T.pp,code); while(forprime_next(&T)) { closure_evalvoid(code); if (loop_break()) break; /* p changed in 'code', complain */ if (get_lex(-1) != T.pp) pari_err(e_MISC,"prime index read-only: was changed to %Ps", get_lex(-1)); } pop_lex(1); avma = av; } void forprime(GEN a, GEN b, GEN code) { return forprimestep(a,b,NULL,code); } int forcomposite_init(forcomposite_t *C, GEN a, GEN b) { pari_sp av = avma; a = gceil(a); if (typ(a)!=t_INT) pari_err_TYPE("forcomposite",a); if (b) { if (typ(b) == t_INFINITY) b = NULL; else { b = gfloor(b); if (typ(b)!=t_INT) pari_err_TYPE("forcomposite",b); } } if (signe(a) < 0) pari_err_DOMAIN("forcomposite", "a", "<", gen_0, a); if (abscmpiu(a, 4) < 0) a = utoipos(4); C->first = 1; if (!forprime_init(&C->T, a,b) && cmpii(a,b) > 0) { C->n = gen_1; /* in case caller forgets to check the return value */ C->b = gen_0; avma = av; return 0; } C->n = setloop(a); C->b = b; C->p = NULL; return 1; } GEN forcomposite_next(forcomposite_t *C) { if (C->first) /* first call ever */ { C->first = 0; C->p = forprime_next(&C->T); } else C->n = incloop(C->n); if (C->p) { if (cmpii(C->n, C->p) < 0) return C->n; C->n = incloop(C->n); /* n = p+1 */ C->p = forprime_next(&C->T); /* nextprime(p) > n */ if (C->p) return C->n; } if (!C->b || cmpii(C->n, C->b) <= 0) return C->n; return NULL; } void forcomposite(GEN a, GEN b, GEN code) { pari_sp av = avma; forcomposite_t T; GEN n; if (!forcomposite_init(&T,a,b)) return; push_lex(T.n,code); while((n = forcomposite_next(&T))) { closure_evalvoid(code); if (loop_break()) break; /* n changed in 'code', complain */ if (get_lex(-1) != n) pari_err(e_MISC,"index read-only: was changed to %Ps", get_lex(-1)); } pop_lex(1); avma = av; } pari-2.11.2/src/language/readline.c0000644000175000017500000002730313447371554015501 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* INTERFACE TO READLINE COMPLETION */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" /**************************************************************************/ static entree *current_ep = NULL; /* do we add () at the end of completed word? (is it a function?) */ static int add_paren(pari_rl_interface *rl, int end) { entree *ep; const char *s; if (end < 0 || (*rl->line_buffer)[end] == '(') return 0; /* not from command_generator or already there */ ep = do_alias(current_ep); /* current_ep set in command_generator */ if (EpVALENCE(ep) < EpNEW) { /* is it a constant masked as a function (e.g Pi)? */ s = ep->help; if (!s) return 1; while (is_keyword_char(*s)) s++; return (*s != '='); } switch(EpVALENCE(ep)) { case EpVAR: return typ((GEN)ep->value) == t_CLOSURE; case EpINSTALL: return 1; } return 0; } static void match_concat(char **matches, const char *s) { matches[0] = (char*)pari_realloc((void*)matches[0], strlen(matches[0])+strlen(s)+1); strcat(matches[0],s); } #define add_comma(x) (x==-2) /* from default_generator */ /* a single match, possibly modify matches[0] in place */ static void treat_single(pari_rl_interface *rl, int code, char **matches) { if (add_paren(rl, code)) { match_concat(matches,"()"); rl->back = 1; if (*rl->point == *rl->end) *rl->completion_append_character = '\0'; /* Do not append space. */ } else if (add_comma(code)) match_concat(matches,","); } #undef add_comma static char ** matches_for_emacs(const char *text, char **matches) { if (!matches) printf("@"); else { int i; printf("%s@", matches[0] + strlen(text)); if (matches[1]) print_fun_list(matches+1,0); /* we don't want readline to do anything, but insert some junk * which will be erased by emacs. */ for (i=0; matches[i]; i++) pari_free(matches[i]); pari_free(matches); } matches = (char **) pari_malloc(2*sizeof(char *)); matches[0] = (char*)pari_malloc(2); sprintf(matches[0],"_"); matches[1] = NULL; printf("@E_N_D"); pari_flush(); return matches; } /* Attempt to complete on the contents of TEXT. 'code' is used to * differentiate between callers when a single match is found. * Return the array of matches, NULL if there are none. */ static char ** get_matches(pari_rl_interface *rl, int code, const char *text, char *(*f)(const char*, int)) { char **matches = rl->completion_matches(text, f); if (matches && !matches[1]) treat_single(rl, code, matches); if (GP_DATA->flags & gpd_EMACS) matches = matches_for_emacs(text,matches); return matches; } static char * add_prefix(const char *name, const char *text, long junk) { char *s = strncpy((char*)pari_malloc(strlen(name)+1+junk),text,junk); strcpy(s+junk,name); return s; } static void init_prefix(const char *text, int *len, int *junk, char **TEXT) { long l = strlen(text), j = l-1; while (j >= 0 && is_keyword_char(text[j])) j--; if (j >= 7 && text[j] == '-' && !strncmp(text+(j-7),"refcard",7)) j -= 8; j++; *TEXT = (char*)text + j; *junk = j; *len = l - j; } static int is_internal(entree *ep) { return *ep->name == '_'; } /* Generator function for command completion. STATE lets us know whether * to start from scratch; without any state (i.e. STATE == 0), then we * start at the top of the list. */ static char * hashtable_generator(const char *text, int state, entree **hash) { static int hashpos, len, junk; static entree* ep; static char *TEXT; /* If this is a new word to complete, initialize now: * + indexes hashpos (GP hash list) and n (keywords specific to long help). * + file completion and keyword completion use different word boundaries, * have TEXT point to the keyword start. * + save the length of TEXT for efficiency. */ if (!state) { hashpos = 0; ep = hash[hashpos]; init_prefix(text, &len, &junk, &TEXT); } /* Return the next name which partially matches from the command list. */ for(;;) if (!ep) { if (++hashpos >= functions_tblsz) return NULL; /* no names matched */ ep = hash[hashpos]; } else if (is_internal(ep) || strncmp(ep->name,TEXT,len)) ep = ep->next; else break; current_ep = ep; ep = ep->next; return add_prefix(current_ep->name,text,junk); } /* Generator function for member completion. STATE lets us know whether * to start from scratch; without any state (i.e. STATE == 0), then we * start at the top of the list. */ static char * member_generator(const char *text, int state) { static int hashpos, len, junk; static entree* ep; static char *TEXT; entree **hash=functions_hash; /* If this is a new word to complete, initialize now: * + indexes hashpos (GP hash list) and n (keywords specific to long help). * + file completion and keyword completion use different word boundaries, * have TEXT point to the keyword start. * + save the length of TEXT for efficiency. */ if (!state) { hashpos = 0; ep = hash[hashpos]; init_prefix(text, &len, &junk, &TEXT); } /* Return the next name which partially matches from the command list. */ for(;;) if (!ep) { if (++hashpos >= functions_tblsz) return NULL; /* no names matched */ ep = hash[hashpos]; } else if (ep->name[0]=='_' && ep->name[1]=='.' && !strncmp(ep->name+2,TEXT,len)) break; else ep = ep->next; current_ep = ep; ep = ep->next; return add_prefix(current_ep->name+2,text,junk); } static char * command_generator(const char *text, int state) { return hashtable_generator(text,state, functions_hash); } static char * default_generator(const char *text,int state) { return hashtable_generator(text,state, defaults_hash); } static char * ext_help_generator(const char *text, int state) { static int len, junk, n, def, key; static char *TEXT; if (!state) { n = 0; def = key = 1; init_prefix(text, &len, &junk, &TEXT); } if (def) { char *s = default_generator(TEXT, state); if (s) return add_prefix(s, text, junk); def = 0; } if (key) { const char **L = gphelp_keyword_list(); for ( ; L[n]; n++) if (!strncmp(L[n],TEXT,len)) return add_prefix(L[n++], text, junk); key = 0; state = 0; } return command_generator(text, state); } /* add a space between \ and following text. Attempting completion now * would delete char. Hitting again will complete properly */ static char ** add_space(pari_rl_interface *rl, int start) { char **m; int p = *rl->point + 1; *rl->point = start + 2; rl->insert(1, ' '); *rl->point = p; /*better: fake an empty completion, but don't append ' ' after it! */ *rl->completion_append_character = '\0'; m = (char**)pari_malloc(2 * sizeof(char*)); m[0] = (char*)pari_malloc(1); *(m[0]) = 0; m[1] = NULL; return m; } char ** pari_completion(pari_rl_interface *rl, char *text, int START, int END) { int i, first=0, start=START; char *line = *rl->line_buffer; *rl->completion_append_character = ' '; current_ep = NULL; while (line[first] && isspace((int)line[first])) first++; if (line[first] == '?') { if (line[first+1] == '?') return get_matches(rl, -1, text, ext_help_generator); return get_matches(rl, -1, text, command_generator); } /* If the line does not begin by a backslash, then it is: * . an old command ( if preceded by "whatnow(" ). * . a default ( if preceded by "default(" ). * . a member function ( if preceded by "." + keyword_chars ) * . a file name (in current directory) ( if preceded by 'read' or 'writexx' ) * . a command */ if (start >=1 && line[start] != '~') start--; while (start && is_keyword_char(line[start])) start--; if (line[start] == '~') { char *(*f)(const char*, int); f = rl->username_completion_function; for(i=start+1;i<=END;i++) if (line[i] == '/') { f = rl->filename_completion_function; break; } return get_matches(rl, -1, text, f); } if (line[first] == '\\') { if (first == start) return add_space(rl, start); return get_matches(rl, -1, text, rl->filename_completion_function); } while (start && line[start] != '(' && line[start] != ',') start--; if (line[start] == '(' && start) { int iend, j,k; entree *ep; char buf[200]; i = start; while (i && isspace((int)line[i-1])) i--; iend = i; while (i && is_keyword_char(line[i-1])) i--; if (strncmp(line + i,"default",7) == 0) return get_matches(rl, -2, text, default_generator); if ( strncmp(line + i,"read",4) == 0 || strncmp(line + i,"write",5) == 0) return get_matches(rl, -1, text, rl->filename_completion_function); j = start + 1; while (j <= END && isspace((int)line[j])) j++; k = END; while (k > j && isspace((int)line[k])) k--; /* If we are in empty parens, insert the default arguments */ if ((GP_DATA->readline_state & DO_ARGS_COMPLETE) && k == j && (line[j] == ')' || !line[j]) && (iend - i < (long)sizeof(buf)) && ( strncpy(buf, line + i, iend - i), buf[iend - i] = 0, 1) && (ep = is_entry(buf)) && ep->help) { const char *s = ep->help; while (is_keyword_char(*s)) s++; if (*s++ == '(') { /* function call: insert arguments */ const char *e = s; while (*e && *e != ')' && *e != '(') e++; if (*e == ')') { /* we just skipped over the arguments in short help text */ char *str = strncpy((char*)pari_malloc(e-s + 1), s, e-s); char **ret = (char**)pari_malloc(sizeof(char*)*2); str[e-s] = 0; ret[0] = str; ret[1] = NULL; if (GP_DATA->flags & gpd_EMACS) ret = matches_for_emacs("",ret); return ret; } } } } for(i = END-1; i >= start; i--) if (!is_keyword_char(line[i])) { if (line[i] == '.') return get_matches(rl, -1, text, member_generator); break; } return get_matches(rl, END, text, command_generator); } static char * pari_completion_word(char *line, long end) { char *s = line + end, *found_quote = NULL; long i; *s = 0; /* truncate at cursor position */ for (i=0; i < end; i++) { /* first look for unclosed string */ switch(line[i]) { case '"': found_quote = found_quote? NULL: line + i; break; case '\\': i++; break; } } if (found_quote) return found_quote + 1; /* return next char after quote */ /* else find beginning of word */ while (s > line && is_keyword_char(s[-1])) s--; return s; } char ** pari_completion_matches(pari_rl_interface *rl, const char *s, long pos, long *wordpos) { char *text, *b; long w; if (*rl->line_buffer) pari_free(*rl->line_buffer); *rl->line_buffer = b = pari_strdup(s); text = pari_completion_word(b, pos); w = text - b; if (wordpos) *wordpos = w; /* text = start of expression we complete */ *rl->end = strlen(b)-1; *rl->point = pos; return pari_completion(rl, text, w, pos); } pari-2.11.2/src/language/gplib.c0000644000175000017500000014452413447371554015020 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /** **/ /** LIBRARY ROUTINES FOR PARI CALCULATOR **/ /** **/ /*******************************************************************/ #ifdef _WIN32 # include "../systems/mingw/pwinver.h" # include # include "../systems/mingw/mingw.h" # include #endif #include "pari.h" #include "paripriv.h" #ifdef __EMSCRIPTEN__ #include "../systems/emscripten/emscripten.h" #endif /********************************************************************/ /** **/ /** STRINGS **/ /** **/ /********************************************************************/ void pari_skip_space(char **s) { char *t = *s; while (isspace((int)*t)) t++; *s = t; } void pari_skip_alpha(char **s) { char *t = *s; while (isalpha((int)*t)) t++; *s = t; } /*******************************************************************/ /** **/ /** BUFFERS **/ /** **/ /*******************************************************************/ static Buffer **bufstack; static pari_stack s_bufstack; void pari_init_buffers(void) { pari_stack_init(&s_bufstack, sizeof(Buffer*), (void**)&bufstack); } void pop_buffer(void) { if (s_bufstack.n) delete_buffer( bufstack[ --s_bufstack.n ] ); } /* kill all buffers until B is met or nothing is left */ void kill_buffers_upto(Buffer *B) { while (s_bufstack.n) { if (bufstack[ s_bufstack.n-1 ] == B) break; pop_buffer(); } } void kill_buffers_upto_including(Buffer *B) { while (s_bufstack.n) { if (bufstack[ s_bufstack.n-1 ] == B) { pop_buffer(); break; } pop_buffer(); } } static int disable_exception_handler = 0; #define BLOCK_EH_START \ { \ int block=disable_exception_handler;\ disable_exception_handler = 1; #define BLOCK_EH_END \ disable_exception_handler = block;\ } /* numerr < 0: from SIGINT */ int gp_handle_exception(long numerr) { if (disable_exception_handler) disable_exception_handler = 0; else if (GP_DATA->breakloop && cb_pari_break_loop && cb_pari_break_loop(numerr)) return 1; return 0; } /********************************************************************/ /** **/ /** HELP **/ /** **/ /********************************************************************/ void pari_hit_return(void) { int c; if (GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS)) return; BLOCK_EH_START pari_puts("/*-- (type RETURN to continue) --*/"); pari_flush(); /* if called from a readline callback, may be in a funny TTY mode */ do c = fgetc(stdin); while (c >= 0 && c != '\n' && c != '\r'); pari_putc('\n'); BLOCK_EH_END } static int has_ext_help(void) { return (GP_DATA->help && *GP_DATA->help); } static int compare_str(char **s1, char **s2) { return strcmp(*s1, *s2); } /* Print all elements of list in columns, pausing every nbli lines * if nbli is non-zero. * list is a NULL terminated list of function names */ void print_fun_list(char **list, long nbli) { long i=0, j=0, maxlen=0, nbcol,len, w = term_width(); char **l; while (list[i]) i++; qsort (list, i, sizeof(char *), (QSCOMP)compare_str); for (l=list; *l; l++) { len = strlen(*l); if (len > maxlen) maxlen=len; } maxlen++; nbcol= w / maxlen; if (nbcol * maxlen == w) nbcol--; if (!nbcol) nbcol = 1; pari_putc('\n'); i=0; for (l=list; *l; l++) { pari_puts(*l); i++; if (i >= nbcol) { i=0; pari_putc('\n'); if (nbli && j++ > nbli) { j = 0; pari_hit_return(); } continue; } len = maxlen - strlen(*l); while (len--) pari_putc(' '); } if (i) pari_putc('\n'); } static const long MAX_SECTION = 16; static void commands(long n) { long i; entree *ep; char **t_L; pari_stack s_L; pari_stack_init(&s_L, sizeof(*t_L), (void**)&t_L); for (i = 0; i < functions_tblsz; i++) for (ep = functions_hash[i]; ep; ep = ep->next) { long m; switch (EpVALENCE(ep)) { case EpVAR: if (typ((GEN)ep->value) == t_CLOSURE) break; /* fall through */ case EpNEW: continue; } m = ep->menu; if (m == n || (n < 0 && m && m <= MAX_SECTION)) pari_stack_pushp(&s_L, (void*)ep->name); } pari_stack_pushp(&s_L, NULL); print_fun_list(t_L, term_height()-4); pari_stack_delete(&s_L); } void pari_center(const char *s) { pari_sp av = avma; long i, l = strlen(s), pad = term_width() - l; char *buf, *u; if (pad<0) pad=0; else pad >>= 1; u = buf = stack_malloc(l + pad + 2); for (i=0; i-request@pari.math.u-bordeaux.fr\n\ with a Subject: field containing the word 'subscribe'.\n\n"); print_text("An archive is kept at the WWW site mentioned above. You can also \ reach the authors at pari@math.u-bordeaux.fr (answer not guaranteed)."); } static void gentypes(void) { pari_puts("List of the PARI types:\n\ t_INT : long integers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\ t_REAL : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\ t_INTMOD : integermods [ code ] [ mod ] [ integer ]\n\ t_FRAC : irred. rationals [ code ] [ num. ] [ den. ]\n\ t_FFELT : finite field elt. [ code ] [ cod2 ] [ elt ] [ mod ] [ p ]\n\ t_COMPLEX: complex numbers [ code ] [ real ] [ imag ]\n\ t_PADIC : p-adic numbers [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ]\n\ t_QUAD : quadratic numbers [ cod1 ] [ mod ] [ real ] [ imag ]\n\ t_POLMOD : poly mod [ code ] [ mod ] [ polynomial ]\n\ -------------------------------------------------------------\n\ t_POL : polynomials [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\ t_SER : power series [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\ t_RFRAC : irred. rat. func. [ code ] [ num. ] [ den. ]\n\ t_QFR : real qfb [ code ] [ a ] [ b ] [ c ] [ del ]\n\ t_QFI : imaginary qfb [ code ] [ a ] [ b ] [ c ]\n\ t_VEC : row vector [ code ] [ x_1 ] ... [ x_k ]\n\ t_COL : column vector [ code ] [ x_1 ] ... [ x_k ]\n\ t_MAT : matrix [ code ] [ col_1 ] ... [ col_k ]\n\ t_LIST : list [ cod1 ] [ cod2 ][ vec ]\n\ t_STR : string [ code ] [ man_1 ] ... [ man_k ]\n\ t_VECSMALL: vec. small ints [ code ] [ x_1 ] ... [ x_k ]\n\ t_CLOSURE: functions [ code ] [ arity ] [ code ] [ operand ] [ data ] [ text ]\n\ t_ERROR : error context [ code ] [ errnum ] [ dat_1 ] ... [ dat_k ]\n\ t_INFINITY: a*infinity [ code ] [ a ]\n\ \n"); } static void menu_commands(void) { ulong i; const char *s[] = { "user-defined functions (aliases, installed and user functions)", "PROGRAMMING under GP", "Standard monadic or dyadic OPERATORS", "CONVERSIONS and similar elementary functions", "functions related to COMBINATORICS", "NUMBER THEORETICAL functions", "POLYNOMIALS and power series", "Vectors, matrices, LINEAR ALGEBRA and sets", "TRANSCENDENTAL functions", "SUMS, products, integrals and similar functions", "General NUMBER FIELDS", "Associative and central simple ALGEBRAS", "ELLIPTIC CURVES", "L-FUNCTIONS", "MODULAR FORMS", "MODULAR SYMBOLS", "GRAPHIC functions", "The PARI community" }; pari_puts("Help topics: for a list of relevant subtopics, type ?n for n in\n"); for (i = 0; i < numberof(s); i++) pari_printf(" %2lu: %s\n", i, s[i]); pari_puts("Also:\n\ ? functionname (short on-line help)\n\ ?\\ (keyboard shortcuts)\n\ ?. (member functions)\n"); if (has_ext_help()) pari_puts("\ Extended help (if available):\n\ ?? (opens the full user's manual in a dvi previewer)\n\ ?? tutorial / refcard / libpari (tutorial/reference card/libpari manual)\n\ ?? refcard-ell (or -lfun/-mf/-nf: specialized reference card)\n\ ?? keyword (long help text about \"keyword\" from the user's manual)\n\ ??? keyword (a propos: list of related functions)."); } static void slash_commands(void) { pari_puts("# : enable/disable timer\n\ ## : print time for last result\n\ \\\\ : comment up to end of line\n\ \\a {n} : print result in raw format (readable by PARI)\n\ \\B {n} : print result in beautified format\n\ \\c : list all commands (same effect as ?*)\n\ \\d : print all defaults\n\ \\e {n} : enable/disable echo (set echo=n)\n\ \\g {n} : set debugging level\n\ \\gf{n} : set file debugging level\n\ \\gm{n} : set memory debugging level\n\ \\h {m-n}: hashtable information\n\ \\l {f} : enable/disable logfile (set logfile=f)\n\ \\m {n} : print result in prettymatrix format\n\ \\o {n} : set output method (0=raw, 1=prettymatrix, 2=prettyprint, 3=2-dim)\n\ \\p {n} : change real precision\n\ \\pb{n} : change real bit precision\n\ \\ps{n} : change series precision\n\ \\q : quit completely this GP session\n\ \\r {f} : read in a file\n\ \\s : print stack information\n\ \\t : print the list of PARI types\n\ \\u : print the list of user-defined functions\n\ \\um : print the list of user-defined member functions\n\ \\v : print current version of GP\n\ \\w {nf} : write to a file\n\ \\x {n} : print complete inner structure of result\n\ \\y {n} : disable/enable automatic simplification (set simplify=n)\n\ \n\ {f}=optional filename. {n}=optional integer\n"); } static void member_commands(void) { pari_puts("\ Member functions, followed by relevant objects\n\n\ a1-a6, b2-b8, c4-c6 : coeff. of the curve. ell\n\ area : area ell\n\ bid : big ideal bid, bnr\n\ bnf : big number field bnf,bnr\n\ clgp : class group bid, bnf,bnr\n\ cyc : cyclic decomposition (SNF) bid, clgp,ell, bnf,bnr\n\ diff, codiff: different and codifferent nf,bnf,bnr\n\ disc : discriminant ell,nf,bnf,bnr,rnf\n\ e, f : inertia/residue degree prid\n\ fu : fundamental units bnf,bnr\n\ gen : generators bid,prid,clgp,ell, bnf,bnr, gal\n\ group: group ell, gal\n\ index: index nf,bnf,bnr\n\ j : j-invariant ell\n"); /* split: some compilers can't handle long constant strings */ pari_puts("\ mod : modulus bid, bnr, gal\n\ nf : number field nf,bnf,bnr,rnf\n\ no : number of elements bid, clgp,ell, bnf,bnr\n\ omega, eta: [w1,w2] and [eta1, eta2] ell\n\ orders: relative orders of generators gal\n\ p : rational prime prid, ell, rnf,gal\n\ pol : defining polynomial nf,bnf,bnr, gal\n\ polabs: defining polynomial over Q rnf\n\ reg : regulator bnf,bnr\n\ roots: roots ell,nf,bnf,bnr, gal\n\ sign,r1,r2 : signature nf,bnf,bnr\n\ t2 : t2 matrix nf,bnf,bnr\n\ tate : Tate's [u^2, u, q, [a,b], L, Ei] ell\n\ tu : torsion unit and its order bnf,bnr\n\ zk : integral basis nf,bnf,bnr,rnf\n\ zkst : structure of (Z_K/m)* bid, bnr\n"); } #define QUOTE "_QUOTE" #define DOUBQUOTE "_DOUBQUOTE" #define BACKQUOTE "_BACKQUOTE" static char * _cat(char *s, const char *t) { *s = 0; strcat(s,t); return s + strlen(t); } static char * filter_quotes(const char *s) { int i, l = strlen(s); int quote = 0; int backquote = 0; int doubquote = 0; char *str, *t; for (i=0; i < l; i++) switch(s[i]) { case '\'': quote++; break; case '`' : backquote++; break; case '"' : doubquote++; } str = (char*)pari_malloc(l + quote * (strlen(QUOTE)-1) + doubquote * (strlen(DOUBQUOTE)-1) + backquote * (strlen(BACKQUOTE)-1) + 1); t = str; for (i=0; i < l; i++) switch(s[i]) { case '\'': t = _cat(t, QUOTE); break; case '`' : t = _cat(t, BACKQUOTE); break; case '"' : t = _cat(t, DOUBQUOTE); break; default: *t++ = s[i]; } *t = 0; return str; } static int nl_read(char *s) { size_t l = strlen(s); return s[l-1] == '\n'; } /* query external help program for s. num < 0 [keyword] or chapter number */ static void external_help(const char *s, int num) { long nbli = term_height()-3, li = 0; char buf[256], *str; const char *opt = "", *ar = "", *cdir = ""; char *t, *help = GP_DATA->help; pariFILE *z; FILE *f; #ifdef __EMSCRIPTEN__ pari_emscripten_help(s); #endif if (!has_ext_help()) pari_err(e_MISC,"no external help program"); t = filter_quotes(s); if (num < 0) opt = "-k"; else if (t[strlen(t)-1] != '@') ar = stack_sprintf("@%d",num); #ifdef _WIN32 if (*help=='@') { const char *basedir = win32_basedir(); help++; cdir = stack_sprintf("%c:& cd %s & ", *basedir, basedir); } #endif str=stack_sprintf("%s%s -fromgp %s %c%s%s%c",cdir,help,opt, SHELL_Q,t,ar,SHELL_Q); z = try_pipe(str,0); f = z->file; pari_free(t); while (fgets(buf, numberof(buf), f)) { if (!strncmp("ugly_kludge_done",buf,16)) break; pari_puts(buf); if (nl_read(buf) && ++li > nbli) { pari_hit_return(); li = 0; } } pari_fclose(z); } const char ** gphelp_keyword_list(void) { static const char *L[]={ "operator", "libpari", "member", "integer", "real", "readline", "refcard", "refcard-nf", "refcard-ell", "refcard-mf", "refcard-lfun", "tutorial", "tutorial-mf", "mf", "nf", "bnf", "bnr", "ell", "rnf", "bid", "modulus", "prototype", "Lmath", "Ldata", "Linit", NULL}; return L; } static int ok_external_help(char **s) { const char **L; long n; if (!**s) return 1; if (!isalpha((int)**s)) return 3; /* operator or section number */ if (!strncmp(*s,"t_",2)) { *s += 2; return 2; } /* type name */ L = gphelp_keyword_list(); for (n=0; L[n]; n++) if (!strcmp(*s,L[n])) return 3; return 0; } static void cut_trailing_garbage(char *s) { char c; while ( (c = *s++) ) { if (c == '\\' && ! *s++) return; /* gobble next char, return if none. */ if (!is_keyword_char(c) && c != '@') { s[-1] = 0; return; } } } static void digit_help(char *s, long flag) { long n = atoi(s); if (n < 0 || n > MAX_SECTION+4) pari_err(e_SYNTAX,"no such section in help: ?",s,s); if (n == MAX_SECTION+1) community(); else if (flag & h_LONG) external_help(s,3); else commands(n); return; } long pari_community(void) { return MAX_SECTION+1; } static void simple_help(const char *s1, const char *s2) { pari_printf("%s: %s\n", s1, s2); } static void default_help(char *s, long flag) { if (flag & h_LONG) external_help(stack_strcat("se:def,",s),3); else simple_help(s,"default"); } static void help(const char *s0, int flag) { const long long_help = flag & h_LONG; long n; entree *ep; char *s = get_sep(s0); if (isdigit((int)*s)) { digit_help(s,flag); return; } if (flag & h_APROPOS) { external_help(s,-1); return; } /* Get meaningful answer on '\ps 5' (e.g. from ) */ if (*s == '\\') { char *t = s+1; pari_skip_alpha(&t); *t = '\0'; } if (isalpha((int)*s)) { char *t = s; if (!strncmp(s, "default", 7)) { /* special-case ?default(dft_name), e.g. default(log) */ t += 7; pari_skip_space(&t); if (*t == '(') { t++; pari_skip_space(&t); cut_trailing_garbage(t); if (pari_is_default(t)) { default_help(t,flag); return; } } } if (!strncmp(s, "refcard-", 8)) t += 8; else if (!strncmp(s, "tutorial-", 9)) t += 9; cut_trailing_garbage(t); } if (long_help && (n = ok_external_help(&s))) { external_help(s,n); return; } switch (*s) { case '*' : commands(-1); return; case '\0': menu_commands(); return; case '\\': slash_commands(); return; case '.' : member_commands(); return; } ep = is_entry(s); if (!ep) { if (pari_is_default(s)) default_help(s,flag); else if (long_help) external_help(s,3); else if (!cb_pari_whatnow || !cb_pari_whatnow(pariOut, s,1)) simple_help(s,"unknown identifier"); return; } if (EpVALENCE(ep) == EpALIAS) { pari_printf("%s is aliased to:\n\n",s); ep = do_alias(ep); } switch(EpVALENCE(ep)) { case EpVAR: if (!ep->help) { if (typ((GEN)ep->value)!=t_CLOSURE) simple_help(s, "user defined variable"); else { GEN str = closure_get_text((GEN)ep->value); if (typ(str) == t_VEC) pari_printf("%s =\n %Ps\n", ep->name, ep->value); } return; } break; case EpINSTALL: if (!ep->help) { simple_help(s, "installed function"); return; } break; case EpNEW: if (!ep->help) { simple_help(s, "new identifier"); return; }; break; default: /* built-in function */ if (!ep->help) pari_err_BUG("gp_help (no help found)"); /*paranoia*/ if (long_help) { external_help(ep->name,3); return; } } print_text(ep->help); } void gp_help(const char *s, long flag) { pari_sp av = avma; if ((flag & h_RL) == 0) { if (*s == '?') { flag |= h_LONG; s++; } if (*s == '?') { flag |= h_APROPOS; s++; } } term_color(c_HELP); help(s,flag); term_color(c_NONE); if ((flag & h_RL) == 0) pari_putc('\n'); avma = av; } /********************************************************************/ /** **/ /** GP HEADER **/ /** **/ /********************************************************************/ static char * what_readline(void) { #ifdef READLINE const char *v = READLINE; char *s = stack_malloc(3 + strlen(v) + 8); (void)sprintf(s, "v%s %s", v, GP_DATA->use_readline? "enabled": "disabled"); return s; #else return (char*)"not compiled in"; #endif } static char * what_cc(void) { char *s; #ifdef GCC_VERSION # ifdef __cplusplus # define Format "(C++) %s" # else # define Format "%s" # endif s = stack_malloc(6 + strlen(GCC_VERSION) + 1); (void)sprintf(s, Format, GCC_VERSION); #else # ifdef _MSC_VER s = stack_malloc(32); (void)sprintf(s, "MSVC-%i", _MSC_VER); # else s = NULL; # endif #endif return s; } static void convert_time(char *s, long delay) { if (delay >= 3600000) { sprintf(s, "%ldh, ", delay / 3600000); s+=strlen(s); delay %= 3600000; } if (delay >= 60000) { sprintf(s, "%ldmin, ", delay / 60000); s+=strlen(s); delay %= 60000; } if (delay >= 1000) { sprintf(s, "%ld,", delay / 1000); s+=strlen(s); delay %= 1000; if (delay < 100) { sprintf(s, "%s", (delay<10)? "00": "0"); s+=strlen(s); } } sprintf(s, "%ld ms", delay); s+=strlen(s); } /* Format a time of 'delay' ms */ const char * gp_format_time(long delay) { static char buf[64]; char *s = buf; term_get_color(s, c_TIME); convert_time(s + strlen(s), delay); s+=strlen(s); term_get_color(s, c_NONE); s+=strlen(s); s[0] = '.'; s[1] = '\n'; s[2] = 0; return buf; } /********************************************************************/ /* */ /* GPRC */ /* */ /********************************************************************/ /* LOCATE GPRC */ static void err_gprc(const char *s, char *t, char *u) { err_printf("\n"); pari_err(e_SYNTAX,s,t,u); } /* return $HOME or the closest we can find */ static const char * get_home(int *free_it) { char *drv, *pth = os_getenv("HOME"); if (pth) return pth; if ((drv = os_getenv("HOMEDRIVE")) && (pth = os_getenv("HOMEPATH"))) { /* looks like WinNT */ char *buf = (char*)pari_malloc(strlen(pth) + strlen(drv) + 1); sprintf(buf, "%s%s",drv,pth); *free_it = 1; return buf; } pth = pari_get_homedir(""); return pth? pth: "."; } static FILE * gprc_chk(const char *s) { FILE *f = fopen(s, "r"); if (f && !(GP_DATA->flags & gpd_QUIET)) err_printf("Reading GPRC: %s ...", s); return f; } /* Look for [._]gprc: $GPRC, then in $HOME, ., /etc, pari_datadir */ static FILE * gprc_get(void) { FILE *f = NULL; const char *gprc = os_getenv("GPRC"); if (gprc) f = gprc_chk(gprc); if (!f) { int free_it = 0; const char *home = get_home(&free_it); char *str, *s, c; long l; l = strlen(home); c = home[l-1]; /* + "/gprc.txt" + \0*/ str = strcpy((char*)pari_malloc(l+10), home); if (free_it) pari_free((void*)home); s = str + l; if (c != '/' && c != '\\') *s++ = '/'; #ifndef _WIN32 strcpy(s, ".gprc"); #else strcpy(s, "gprc.txt"); #endif f = gprc_chk(str); /* in $HOME */ if (!f) f = gprc_chk(s); /* in . */ #ifndef _WIN32 if (!f) f = gprc_chk("/etc/gprc"); #else if (!f) /* in basedir */ { const char *basedir = win32_basedir(); char *t = (char *) pari_malloc(strlen(basedir)+strlen(s)+2); sprintf(t, "%s/%s", basedir, s); f = gprc_chk(t); free(t); } #endif pari_free(str); } return f; } /* PREPROCESSOR */ static ulong read_uint(char **s) { long v = atol(*s); if (!isdigit((int)**s)) err_gprc("not an integer", *s, *s); while (isdigit((int)**s)) (*s)++; return v; } static ulong read_dot_uint(char **s) { if (**s != '.') return 0; (*s)++; return read_uint(s); } /* read a.b.c */ static long read_version(char **s) { long a, b, c; a = read_uint(s); b = read_dot_uint(s); c = read_dot_uint(s); return PARI_VERSION(a,b,c); } static int get_preproc_value(char **s) { if (!strncmp(*s,"EMACS",5)) { *s += 5; return GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS); } if (!strncmp(*s,"READL",5)) { *s += 5; return GP_DATA->use_readline; } if (!strncmp(*s,"VERSION",7)) { int less = 0, orequal = 0; long d; *s += 7; switch(**s) { case '<': (*s)++; less = 1; break; case '>': (*s)++; less = 0; break; default: return -1; } if (**s == '=') { (*s)++; orequal = 1; } d = paricfg_version_code - read_version(s); if (!d) return orequal; return less? (d < 0): (d > 0); } if (!strncmp(*s,"BITS_IN_LONG",12)) { *s += 12; if ((*s)[0] == '=' && (*s)[1] == '=') { *s += 2; return BITS_IN_LONG == read_uint(s); } } return -1; } /* PARSE GPRC */ /* 1) replace next separator by '\0' (t must be writable) * 2) return the next expression ("" if none) * see get_sep() */ static char * next_expr(char *t) { int outer = 1; char *s = t; for(;;) { char c; switch ((c = *s++)) { case '"': if (outer || (s >= t+2 && s[-2] != '\\')) outer = !outer; break; case '\0': return (char*)""; default: if (outer && c == ';') { s[-1] = 0; return s; } } } } Buffer * filtered_buffer(filtre_t *F) { Buffer *b = new_buffer(); init_filtre(F, b); pari_stack_pushp(&s_bufstack, (void*)b); return b; } /* parse src of the form s=t (or s="t"), set *ps to s, and *pt to t. * modifies src (replaces = by \0) */ void parse_key_val(char *src, char **ps, char **pt) { char *s_end, *t; t = src; while (*t && *t != '=') t++; if (*t != '=') err_gprc("missing '='",t,src); s_end = t; t++; if (*t == '"') (void)pari_translate_string(t, t, src); *s_end = 0; *ps = src; *pt = t; } void gp_initrc(pari_stack *p_A) { FILE *file = gprc_get(); Buffer *b; filtre_t F; VOLATILE long c = 0; jmp_buf *env; pari_stack s_env; if (!file) return; b = filtered_buffer(&F); pari_stack_init(&s_env, sizeof(*env), (void**)&env); (void)pari_stack_new(&s_env); for(;;) { char *nexts, *s, *t; if (setjmp(env[s_env.n-1])) err_printf("...skipping line %ld.\n", c); c++; if (!get_line_from_file(NULL,&F,file)) break; s = b->buf; if (*s == '#') { /* preprocessor directive */ int z, NOT = 0; s++; if (strncmp(s,"if",2)) err_gprc("unknown directive",s,b->buf); s += 2; if (!strncmp(s,"not",3)) { NOT = !NOT; s += 3; } if (*s == '!') { NOT = !NOT; s++; } t = s; z = get_preproc_value(&s); if (z < 0) err_gprc("unknown preprocessor variable",t,b->buf); if (NOT) z = !z; if (!*s) { /* make sure at least an expr follows the directive */ if (!get_line_from_file(NULL,&F,file)) break; s = b->buf; } if (!z) continue; /* dump current line */ } /* parse line */ for ( ; *s; s = nexts) { nexts = next_expr(s); if (!strncmp(s,"read",4) && (s[4] == ' ' || s[4] == '\t' || s[4] == '"')) { /* read file */ s += 4; t = (char*)pari_malloc(strlen(s) + 1); if (*s == '"') (void)pari_translate_string(s, t, s-4); else strcpy(t,s); pari_stack_pushp(p_A,t); } else { /* set default */ parse_key_val(s, &s,&t); (void)setdefault(s,t,d_INITRC); } } } pari_stack_delete(&s_env); pop_buffer(); if (!(GP_DATA->flags & gpd_QUIET)) err_printf("Done.\n\n"); fclose(file); } void gp_load_gprc(void) { pari_stack sA; char **A; long i; pari_stack_init(&sA,sizeof(*A),(void**)&A); gp_initrc(&sA); for (i = 0; i < sA.n; pari_free(A[i]),i++) { pari_CATCH(CATCH_ALL) { err_printf("... skipping file '%s'\n", A[i]); } pari_TRY { gp_read_file(A[i]); } pari_ENDCATCH; } pari_stack_delete(&sA); } /********************************************************************/ /* */ /* PROMPTS */ /* */ /********************************************************************/ /* if prompt is coloured, tell readline to ignore the ANSI escape sequences */ /* s must be able to store 14 chars (including final \0) */ #ifdef READLINE static void readline_prompt_color(char *s, int c) { #ifdef _WIN32 (void)s; (void)c; #else *s++ = '\001'; /*RL_PROMPT_START_IGNORE*/ term_get_color(s, c); s += strlen(s); *s++ = '\002'; /*RL_PROMPT_END_IGNORE*/ *s = 0; #endif } #endif /* s must be able to store 14 chars (including final \0) */ static void brace_color(char *s, int c, int force) { if (disable_color || (gp_colors[c] == c_NONE && !force)) return; #ifdef READLINE if (GP_DATA->use_readline) readline_prompt_color(s, c); else #endif term_get_color(s, c); } /* strlen(prompt) + 28 chars */ static const char * color_prompt(const char *prompt) { long n = strlen(prompt); char *t = stack_malloc(n + 28), *s = t; *s = 0; /* escape sequences bug readline, so use special bracing (if available) */ brace_color(s, c_PROMPT, 0); s += strlen(s); memcpy(s, prompt, n); s += n; *s = 0; brace_color(s, c_INPUT, 1); return t; } const char * gp_format_prompt(const char *prompt) { if (GP_DATA->flags & gpd_TEST) return prompt; else { char b[256]; /* longer is truncated */ strftime_expand(prompt, b, sizeof(b)); return color_prompt(b); } } /********************************************************************/ /* */ /* GP MAIN LOOP */ /* */ /********************************************************************/ static int is_interactive(void) { return cb_pari_is_interactive? cb_pari_is_interactive(): 0; } static char * strip_prompt(const char *s) { long l = strlen(s); char *t, *t0 = stack_malloc(l+1); t = t0; for (; *s; s++) { /* RL_PROMPT_START_IGNORE / RL_PROMPT_END_IGNORE */ if (*s == 1 || *s == 2) continue; if (*s == '\x1b') /* skip ANSI color escape sequence */ { while (*++s != 'm') if (!*s) goto end; continue; } *t = *s; t++; } end: *t = 0; return t0; } static void update_logfile(const char *prompt, const char *s) { pari_sp av; const char *p; if (!pari_logfile) return; av = avma; p = strip_prompt(prompt); /* raw prompt */ switch (logstyle) { case logstyle_TeX: fprintf(pari_logfile, "\\PARIpromptSTART|%s\\PARIpromptEND|%s\\PARIinputEND|%%\n", p, s); break; case logstyle_plain: fprintf(pari_logfile,"%s%s\n",p, s); break; case logstyle_color: fprintf(pari_logfile,"%s%s%s%s%s\n",term_get_color(NULL,c_PROMPT), p, term_get_color(NULL,c_INPUT), s, term_get_color(NULL,c_NONE)); break; } avma = av; } void gp_echo_and_log(const char *prompt, const char *s) { if (!is_interactive()) { if (!GP_DATA->echo) return; /* not pari_puts(): would duplicate in logfile */ fputs(prompt, pari_outfile); fputs(s, pari_outfile); fputc('\n', pari_outfile); pari_set_last_newline(1); } update_logfile(prompt, s); pari_flush(); } /* prompt = NULL --> from gprc. Return 1 if new input, and 0 if EOF */ int get_line_from_file(const char *prompt, filtre_t *F, FILE *file) { char *s; input_method IM; IM.file = (void*)file; if (file==stdin && cb_pari_fgets_interactive) IM.fgets = (fgets_t)cb_pari_fgets_interactive; else IM.fgets = (fgets_t)&fgets; IM.getline = &file_input; IM.free = 0; if (! input_loop(F,&IM)) { if (file==stdin && cb_pari_start_output) cb_pari_start_output(); return 0; } s = F->buf->buf; /* don't log if from gprc or empty input */ if (*s && prompt && GP_DATA->echo != 2) gp_echo_and_log(prompt, s); return 1; } /* return 0 if no line could be read (EOF). If PROMPT = NULL, expand and * color default prompt; otherwise, use PROMPT as-is. */ int gp_read_line(filtre_t *F, const char *PROMPT) { static const char *DFT_PROMPT = "? "; Buffer *b = (Buffer*)F->buf; const char *p; int res, interactive; if (b->len > 100000) fix_buffer(b, 100000); interactive = is_interactive(); if (interactive || pari_logfile || GP_DATA->echo) { p = PROMPT; if (!p) { p = F->in_comment? GP_DATA->prompt_comment: GP_DATA->prompt; p = gp_format_prompt(p); } } else p = DFT_PROMPT; if (interactive) { BLOCK_EH_START if (!pari_last_was_newline()) pari_putc('\n'); if (cb_pari_get_line_interactive) res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F); else { pari_puts(p); pari_flush(); res = get_line_from_file(p, F, pari_infile); } BLOCK_EH_END } else { /* in case UI fakes non-interactivity, e.g. TeXmacs */ if (cb_pari_start_output && cb_pari_get_line_interactive) res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F); else res = get_line_from_file(p, F, pari_infile); } if (!disable_color && p != DFT_PROMPT && (gp_colors[c_PROMPT] != c_NONE || gp_colors[c_INPUT] != c_NONE)) { term_color(c_NONE); pari_flush(); } return res; } /********************************************************************/ /* */ /* EXCEPTION HANDLER */ /* */ /********************************************************************/ static THREAD pari_timer ti_alarm; #if defined(_WIN32) || defined(SIGALRM) static void gp_alarm_fun(void) { char buf[64]; if (cb_pari_start_output) cb_pari_start_output(); convert_time(buf, timer_get(&ti_alarm)); pari_err(e_ALARM, buf); } #endif /* SIGALRM */ void gp_sigint_fun(void) { char buf[64]; #if defined(_WIN32) if (win32alrm) { win32alrm = 0; gp_alarm_fun(); return;} #endif if (cb_pari_start_output) cb_pari_start_output(); convert_time(buf, timer_get(GP_DATA->T)); pari_sigint(buf); } #ifdef SIGALRM void gp_alarm_handler(int sig) { #ifndef HAS_SIGACTION /*SYSV reset the signal handler in the handler*/ (void)os_signal(sig,gp_alarm_handler); #endif if (PARI_SIGINT_block) PARI_SIGINT_pending=sig; else gp_alarm_fun(); return; } #endif /* SIGALRM */ /********************************************************************/ /* */ /* GP-SPECIFIC ROUTINES */ /* */ /********************************************************************/ void gp_allocatemem(GEN z) { ulong newsize; if (!z) newsize = 0; else { if (typ(z) != t_INT) pari_err_TYPE("allocatemem",z); newsize = itou(z); if (signe(z) < 0) pari_err_DOMAIN("allocatemem","size","<",gen_0,z); } if (pari_mainstack->vsize) paristack_resize(newsize); else paristack_newrsize(newsize); } GEN gp_input(void) { filtre_t F; Buffer *b = filtered_buffer(&F); GEN x; while (! get_line_from_file("",&F,pari_infile)) if (popinfile()) { err_printf("no input ???"); cb_pari_quit(1); } x = readseq(b->buf); pop_buffer(); return x; } static GEN closure_alarmer(GEN C, long s) { struct pari_evalstate state; VOLATILE GEN x; if (!s) { pari_alarm(0); return closure_evalgen(C); } evalstate_save(&state); #if !defined(HAS_ALARM) && !defined(_WIN32) pari_err(e_ARCH,"alarm"); #endif pari_CATCH(CATCH_ALL) /* We need to stop the timer after any error */ { GEN E = pari_err_last(); if (err_get_num(E) != e_ALARM) { pari_alarm(0); pari_err(0, E); } x = evalstate_restore_err(&state); } pari_TRY { pari_alarm(s); x = closure_evalgen(C); pari_alarm(0); } pari_ENDCATCH; return x; } void pari_alarm(long s) { if (s < 0) pari_err_DOMAIN("alarm","delay","<",gen_0,stoi(s)); if (s) timer_start(&ti_alarm); #ifdef _WIN32 win32_alarm(s); #elif defined(HAS_ALARM) alarm(s); #else if (s) pari_err(e_ARCH,"alarm"); #endif } GEN gp_alarm(long s, GEN code) { if (!code) { pari_alarm(s); return gnil; } return closure_alarmer(code,s); } /*******************************************************************/ /** **/ /** EXTERNAL PRETTYPRINTER **/ /** **/ /*******************************************************************/ /* Wait for prettinprinter to finish, to prevent new prompt from overwriting * the output. Fill the output buffer, wait until it is read. * Better than sleep(2): give possibility to print */ static void prettyp_wait(FILE *out) { const char *s = " \n"; long i = 2000; fputs("\n\n", out); fflush(out); /* start translation */ while (--i) fputs(s, out); fputs("\n", out); fflush(out); } /* initialise external prettyprinter (tex2mail) */ static int prettyp_init(void) { gp_pp *pp = GP_DATA->pp; if (!pp->cmd) return 0; if (pp->file || (pp->file = try_pipe(pp->cmd, mf_OUT))) return 1; pari_warn(warner,"broken prettyprinter: '%s'",pp->cmd); pari_free(pp->cmd); pp->cmd = NULL; sd_output("1", d_SILENT); return 0; } /* n = history number. if n = 0 no history */ int tex2mail_output(GEN z, long n) { pariout_t T = *(GP_DATA->fmt); /* copy */ FILE *log = pari_logfile, *out; if (!prettyp_init()) return 0; out = GP_DATA->pp->file->file; /* Emit first: there may be lines before the prompt */ if (n) term_color(c_OUTPUT); pari_flush(); T.prettyp = f_TEX; /* history number */ if (n) { pari_sp av = avma; const char *c_hist = term_get_color(NULL, c_HIST); const char *c_out = term_get_color(NULL, c_OUTPUT); if (!(GP_DATA->flags & gpd_QUIET)) { if (*c_hist || *c_out) fprintf(out, "\\LITERALnoLENGTH{%s}\\%%%ld =\\LITERALnoLENGTH{%s} ", c_hist, n, c_out); else fprintf(out, "\\%%%ld = ", n); } if (log) { switch (logstyle) { case logstyle_plain: fprintf(log, "%%%ld = ", n); break; case logstyle_color: fprintf(log, "%s%%%ld = %s", c_hist, n, c_out); break; case logstyle_TeX: fprintf(log, "\\PARIout{%ld}", n); break; } } avma = av; } /* output */ fputGEN_pariout(z, &T, out); /* flush and restore, output to logfile */ prettyp_wait(out); if (log) { if (logstyle == logstyle_TeX) { T.TeXstyle |= TEXSTYLE_BREAK; fputGEN_pariout(z, &T, log); fputc('%', log); } else { T.prettyp = f_RAW; fputGEN_pariout(z, &T, log); } fputc('\n', log); fflush(log); } if (n) term_color(c_NONE); pari_flush(); return 1; } /*******************************************************************/ /** **/ /** GP-SPECIFIC DEFAULTS **/ /** **/ /*******************************************************************/ static long atocolor(const char *s) { long l = atol(s); if (l & ~0xff) pari_err(e_MISC, "invalid 8bit RGB code: %ld", l); return l; } GEN sd_graphcolormap(const char *v, long flag) { char *p, *q; long i, j, l, a, s, *lp; if (v) { char *t = gp_filter(v); if (*t != '[' || t[strlen(t)-1] != ']') pari_err(e_SYNTAX, "incorrect value for graphcolormap", t, t); for (s = 0, p = t+1, l = 2, a=0; *p; p++) if (*p == '[') { a++; while (*++p != ']') if (!*p || *p == '[') pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t); } else if (*p == '"') { s += sizeof(long)+1; while (*p && *++p != '"') s++; if (!*p) pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t); s = (s+sizeof(long)-1) & ~(sizeof(long)-1); } else if (*p == ',') l++; if (l < 4) pari_err(e_MISC, "too few colors (< 4) in graphcolormap"); if (GP_DATA->colormap) pari_free(GP_DATA->colormap); GP_DATA->colormap = (GEN)pari_malloc((l+4*a)*sizeof(long) + s); GP_DATA->colormap[0] = evaltyp(t_VEC)|evallg(l); for (p = t+1, i = 1, lp = GP_DATA->colormap+l; i < l; p++) switch(*p) { case '"': gel(GP_DATA->colormap, i) = lp; q = ++p; while (*q != '"') q++; *q = 0; j = 1 + nchar2nlong(q-p+1); lp[0] = evaltyp(t_STR)|evallg(j); strncpy(GSTR(lp), p, q-p+1); lp += j; p = q; break; case '[': { const char *ap[3]; gel(GP_DATA->colormap, i) = lp; lp[0] = evaltyp(t_VECSMALL)|_evallg(4); for (ap[0] = ++p, j=0; *p && *p != ']'; p++) if (*p == ',' && j<2) { *p++ = 0; ap[++j] = p; } while (j<2) ap[++j] = "0"; if (j>2 || *p != ']') { char buf[100]; sprintf(buf, "incorrect value for graphcolormap[%ld]: ", i); pari_err(e_SYNTAX, buf, p, t); } *p = '\0'; lp[1] = atocolor(ap[0]); lp[2] = atocolor(ap[1]); lp[3] = atocolor(ap[2]); lp += 4; break; } case ',': case ']': i++; break; default: pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t); } pari_free(t); } if (flag == d_RETURN || flag == d_ACKNOWLEDGE) { GEN C = cgetg(lg(GP_DATA->colormap), t_VEC); long i, l = lg(C); for (i = 1; i < l; i++) { GEN c = gel(GP_DATA->colormap, i); gel(C, i) = (typ(c) == t_STR)? gcopy(c): zv_to_ZV(c); } if (flag == d_RETURN) return C; pari_printf(" graphcolormap = %Ps\n", C); } return gnil; } GEN sd_graphcolors(const char *v, long flag) { return sd_intarray(v, flag, &(GP_DATA->graphcolors), "graphcolors"); } GEN sd_plothsizes(const char *v, long flag) { return sd_intarray(v, flag, &(GP_DATA->plothsizes), "plothsizes"); } GEN sd_help(const char *v, long flag) { const char *str; if (v) { if (GP_DATA->secure) pari_err(e_MISC,"[secure mode]: can't modify 'help' default (to %s)",v); if (GP_DATA->help) pari_free((void*)GP_DATA->help); #ifndef _WIN32 GP_DATA->help = path_expand(v); #else GP_DATA->help = pari_strdup(v); #endif } str = GP_DATA->help? GP_DATA->help: "none"; if (flag == d_RETURN) return strtoGENstr(str); if (flag == d_ACKNOWLEDGE) pari_printf(" help = \"%s\"\n", str); return gnil; } static GEN sd_prompt_set(const char *v, long flag, const char *how, char **p) { if (v) { if (*p) free(*p); *p = pari_strdup(v); } if (flag == d_RETURN) return strtoGENstr(*p); if (flag == d_ACKNOWLEDGE) pari_printf(" prompt%s = \"%s\"\n", how, *p); return gnil; } GEN sd_prompt(const char *v, long flag) { return sd_prompt_set(v, flag, "", &(GP_DATA->prompt)); } GEN sd_prompt_cont(const char *v, long flag) { return sd_prompt_set(v, flag, "_cont", &(GP_DATA->prompt_cont)); } GEN sd_breakloop(const char *v, long flag) { return sd_toggle(v,flag,"breakloop", &(GP_DATA->breakloop)); } GEN sd_echo(const char *v, long flag) { return sd_ulong(v,flag,"echo", &(GP_DATA->echo), 0,2,NULL); } GEN sd_timer(const char *v, long flag) { return sd_toggle(v,flag,"timer", &(GP_DATA->chrono)); } GEN sd_recover(const char *v, long flag) { return sd_toggle(v,flag,"recover", &(GP_DATA->recover)); } GEN sd_psfile(const char *v, long flag) { return sd_string(v, flag, "psfile", ¤t_psfile); } GEN sd_lines(const char *v, long flag) { return sd_ulong(v,flag,"lines",&(GP_DATA->lim_lines), 0,LONG_MAX,NULL); } GEN sd_linewrap(const char *v, long flag) { ulong old = GP_DATA->linewrap, n = GP_DATA->linewrap; GEN z = sd_ulong(v,flag,"linewrap",&n, 0,LONG_MAX,NULL); if (old) { if (!n) resetout(1); } else { if (n) init_linewrap(n); } GP_DATA->linewrap = n; return z; } /* readline-specific defaults */ GEN sd_readline(const char *v, long flag) { const char *msg[] = { "(bits 0x2/0x4 control matched-insert/arg-complete)", NULL}; ulong state = GP_DATA->readline_state; GEN res = sd_ulong(v,flag,"readline", &GP_DATA->readline_state, 0, 7, msg); if (state != GP_DATA->readline_state) (void)sd_toggle(GP_DATA->readline_state? "1": "0", d_SILENT, "readline", &(GP_DATA->use_readline)); return res; } GEN sd_histfile(const char *v, long flag) { char *old = GP_DATA->histfile; GEN r = sd_string(v, flag, "histfile", &GP_DATA->histfile); if (v && !*v) { free(GP_DATA->histfile); GP_DATA->histfile = NULL; } else if (GP_DATA->histfile != old && (!old || strcmp(old,GP_DATA->histfile))) { if (cb_pari_init_histfile) cb_pari_init_histfile(); } return r; } /********************************************************************/ /** **/ /** METACOMMANDS **/ /** **/ /********************************************************************/ void pari_print_version(void) { pari_sp av = avma; char *buf, *ver = what_cc(); const char *date = paricfg_compiledate; pari_center(paricfg_version); pari_center(paricfg_buildinfo); buf = stack_malloc(strlen(date) + 32 + (ver? strlen(ver): 0)); if (ver) (void)sprintf(buf, "compiled: %s, %s", date, ver); else (void)sprintf(buf, "compiled: %s", date); pari_center(buf); sprintf(buf, "threading engine: %s",paricfg_mt_engine); pari_center(buf); ver = what_readline(); buf = stack_malloc(strlen(ver) + 64); (void)sprintf(buf, "(readline %s, extended help%s enabled)", ver, has_ext_help()? "": " not"); pari_center(buf); avma = av; } static int cmp_epname(void *E, GEN e, GEN f) { (void)E; return strcmp(((entree*)e)->name, ((entree*)f)->name); } static void print_all_user_fun(int member) { pari_sp av = avma; long iL = 0, lL = 1024; GEN L = cgetg(lL+1, t_VECSMALL); entree *ep; int i; for (i = 0; i < functions_tblsz; i++) for (ep = functions_hash[i]; ep; ep = ep->next) { const char *f; int is_member; if (EpVALENCE(ep) != EpVAR || typ((GEN)ep->value)!=t_CLOSURE) continue; f = ep->name; is_member = (f[0] == '_' && f[1] == '.'); if (member != is_member) continue; if (iL >= lL) { GEN oL = L; long j; lL *= 2; L = cgetg(lL+1, t_VECSMALL); for (j = 1; j <= iL; j++) gel(L,j) = gel(oL,j); } L[++iL] = (long)ep; } if (iL) { setlg(L, iL+1); gen_sort_inplace(L, NULL, &cmp_epname, NULL); for (i = 1; i <= iL; i++) { ep = (entree*)L[i]; pari_printf("%s =\n %Ps\n\n", ep->name, ep->value); } } avma = av; } static char * get_name(const char *s) { char *t = get_sep(s); if (*t == '"') { long n = strlen(t)-1; if (t[n] == '"') { t[n] = 0; t++; } } return t; } static void escape(const char *tch, int ismain) { const char *s = tch; char c; switch ((c = *s++)) { case 'w': case 'x': case 'a': case 'b': case 'B': case 'm': { /* history things */ long d; GEN x; if (c != 'w' && c != 'x') d = get_int(s,0); else { d = atol(s); if (*s == '-') s++; while (isdigit((int)*s)) s++; } x = pari_get_hist(d); switch (c) { case 'B': /* prettyprinter */ if (tex2mail_output(x,0)) break; case 'b': /* fall through */ case 'm': matbrute(x, GP_DATA->fmt->format, -1); break; case 'a': brute(x, GP_DATA->fmt->format, -1); break; case 'x': dbgGEN(x, get_int(s, -1)); break; case 'w': s = get_name(s); if (!*s) s = current_logfile; write0(s, mkvec(x)); return; } pari_putc('\n'); return; } case 'c': commands(-1); break; case 'd': (void)setdefault(NULL,NULL,d_SILENT); break; case 'e': s = get_sep(s); if (!*s) s = (GP_DATA->echo)? "0": "1"; (void)sd_echo(s,d_ACKNOWLEDGE); break; case 'g': switch (*s) { case 'm': s++; (void)sd_debugmem(*s? s: NULL,d_ACKNOWLEDGE); break; case 'f': s++; (void)sd_debugfiles(*s? s: NULL,d_ACKNOWLEDGE); break; default : (void)sd_debug(*s? s: NULL,d_ACKNOWLEDGE); break; } break; case 'h': print_functions_hash(s); break; case 'l': s = get_name(s); if (*s) { (void)sd_logfile(s,d_ACKNOWLEDGE); if (pari_logfile) break; } (void)sd_log(pari_logfile?"0":"1",d_ACKNOWLEDGE); break; case 'o': (void)sd_output(*s? s: NULL,d_ACKNOWLEDGE); break; case 'p': switch (*s) { case 's': s++; (void)sd_seriesprecision(*s? s: NULL,d_ACKNOWLEDGE); break; case 'b' : s++; (void)sd_realbitprecision(*s? s: NULL,d_ACKNOWLEDGE); break; default : (void)sd_realprecision(*s? s: NULL,d_ACKNOWLEDGE); break; } break; case 'q': cb_pari_quit(0); break; case 'r': s = get_name(s); if (!ismain) { (void)gp_read_file(s); break; } switchin(s); if (file_is_binary(pari_infile)) { pari_sp av = avma; int vector; GEN x = readbin(s,pari_infile, &vector); popinfile(); if (!x) pari_err_FILE("input file",s); if (vector) /* many BIN_GEN */ { long i, l = lg(x); pari_warn(warner,"setting %ld history entries", l-1); for (i=1; isimplify)? "0": "1"; (void)sd_simplify(s,d_ACKNOWLEDGE); break; default: pari_err(e_SYNTAX,"unexpected character", tch,tch-1); } } static int chron(const char *s) { if (*s) { /* if "#" or "##" timer metacommand. Otherwise let the parser get it */ const char *t; if (*s == '#') s++; if (*s) return 0; t = gp_format_time(pari_get_histtime(0)); pari_printf(" *** last result computed in %s", t); } else { GP_DATA->chrono ^= 1; (void)sd_timer(NULL,d_ACKNOWLEDGE); } return 1; } /* return 0: can't interpret *buf as a metacommand * 1: did interpret *buf as a metacommand or empty command */ int gp_meta(const char *buf, int ismain) { switch(*buf++) { case '?': gp_help(buf, h_REGULAR); break; case '#': return chron(buf); case '\\': escape(buf, ismain); break; case '\0': break; default: return 0; } return 1; } pari-2.11.2/src/language/anal.h0000644000175000017500000000327513326135265014631 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*************************************************************************/ /* */ /* Declarations specific to the analyzer */ /* */ /*************************************************************************/ BEGINEXTERN /* functions */ void changevalue(entree *ep, GEN val); void freeep(entree *ep); void pari_fill_hashtable(entree **table, entree *ep); void compile_err(const char *msg, const char *str); void compile_varerr(const char *str); #ifdef STACK_CHECK extern THREAD void *PARI_stack_limit; #endif extern entree **varentries; struct node_loc { const char *start,*end; }; union token_value { long val; }; int pari_lex(union token_value *yylval, struct node_loc *yylloc, char **lex); int pari_parse(char **lex); entree* fetch_entry_raw(const char *s, long len); entree* fetch_entry(const char *s); void optimizenode(long n); void push_frame(GEN C, long lpc, long flag); GEN gp_closure(long n); long eval_mnemonic(GEN str, const char *tmplate); ENDEXTERN pari-2.11.2/src/language/eval.c0000644000175000017500000016351513326135265014644 0ustar billbill/* Copyright (C) 2006 The PARI group. This file is part of the PARI package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #include "anal.h" #include "opcode.h" /********************************************************************/ /* */ /* break/next/return handling */ /* */ /********************************************************************/ static THREAD long br_status, br_count; static THREAD GEN br_res; long loop_break(void) { switch(br_status) { case br_MULTINEXT : if (! --br_count) br_status = br_NEXT; return 1; case br_BREAK : if (! --br_count) br_status = br_NONE; /* fall through */ case br_RETURN: return 1; case br_NEXT: br_status = br_NONE; /* fall through */ } return 0; } static void reset_break(void) { br_status = br_NONE; if (br_res) { gunclone_deep(br_res); br_res = NULL; } } GEN return0(GEN x) { GEN y = br_res; br_res = (x && x != gnil)? gcloneref(x): NULL; if (y) gunclone_deep(y); br_status = br_RETURN; return NULL; } GEN next0(long n) { if (n < 1) pari_err_DOMAIN("next", "n", "<", gen_1, stoi(n)); if (n == 1) br_status = br_NEXT; else { br_count = n-1; br_status = br_MULTINEXT; } return NULL; } GEN break0(long n) { if (n < 1) pari_err_DOMAIN("break", "n", "<", gen_1, stoi(n)); br_count = n; br_status = br_BREAK; return NULL; } /*******************************************************************/ /* */ /* VARIABLES */ /* */ /*******************************************************************/ /* As a rule, ep->value is a clone (COPY). push_val and pop_val are private * functions for use in sumiter: we want a temporary ep->value, which is NOT * a clone (PUSH), to avoid unnecessary copies. */ enum {PUSH_VAL = 0, COPY_VAL = 1, DEFAULT_VAL = 2}; /* ep->args is the stack of old values (INITIAL if initial value, from * installep) */ typedef struct var_cell { struct var_cell *prev; /* cell attached to previous value on stack */ GEN value; /* last value (not including current one, in ep->value) */ char flag; /* status of _current_ ep->value: PUSH or COPY ? */ long valence; /* valence of entree* attached to 'value', to be restored * by pop_val */ } var_cell; #define INITIAL NULL /* Push x on value stack attached to ep. */ static void new_val_cell(entree *ep, GEN x, char flag) { var_cell *v = (var_cell*) pari_malloc(sizeof(var_cell)); v->value = (GEN)ep->value; v->prev = (var_cell*) ep->pvalue; v->flag = flag; v->valence= ep->valence; /* beware: f(p) = Nv = 0 * Nv = p; f(Nv) --> this call would destroy p [ isclone ] */ ep->value = (flag == COPY_VAL)? gclone(x): (x && isclone(x))? gcopy(x): x; /* Do this last. In case the clone is 'ed before completion ! */ ep->pvalue= (char*)v; ep->valence=EpVAR; } /* kill ep->value and replace by preceding one, poped from value stack */ static void pop_val(entree *ep) { var_cell *v = (var_cell*) ep->pvalue; if (v != INITIAL) { GEN old_val = (GEN) ep->value; /* protect against SIGINT */ ep->value = v->value; if (v->flag == COPY_VAL) gunclone_deep(old_val); ep->pvalue = (char*) v->prev; ep->valence=v->valence; pari_free((void*)v); } } void freeep(entree *ep) { if (EpSTATIC(ep)) return; /* gp function loaded at init time */ if (ep->help) {pari_free((void*)ep->help); ep->help=NULL;} if (ep->code) {pari_free((void*)ep->code); ep->code=NULL;} switch(EpVALENCE(ep)) { case EpVAR: while (ep->pvalue!=INITIAL) pop_val(ep); break; case EpALIAS: killblock((GEN)ep->value); ep->value=NULL; break; } } INLINE void pushvalue(entree *ep, GEN x) { new_val_cell(ep, x, COPY_VAL); } INLINE void zerovalue (entree *ep) { var_cell *v = (var_cell*) pari_malloc(sizeof(var_cell)); v->value = (GEN)ep->value; v->prev = (var_cell*) ep->pvalue; v->flag = PUSH_VAL; v->valence= ep->valence; ep->value = gen_0; ep->pvalue= (char*)v; ep->valence=EpVAR; } /* as above IF ep->value was PUSHed, or was created after block number 'loc' return 0 if not deleted, 1 otherwise [for recover()] */ int pop_val_if_newer(entree *ep, long loc) { var_cell *v = (var_cell*) ep->pvalue; if (v == INITIAL) return 0; if (v->flag == COPY_VAL && !pop_entree_block(ep, loc)) return 0; ep->value = v->value; ep->pvalue= (char*) v->prev; ep->valence=v->valence; pari_free((void*)v); return 1; } /* set new value of ep directly to val (COPY), do not save last value unless * it's INITIAL. */ void changevalue(entree *ep, GEN x) { var_cell *v = (var_cell*) ep->pvalue; if (v == INITIAL) new_val_cell(ep, x, COPY_VAL); else { GEN old_val = (GEN) ep->value; /* beware: gunclone_deep may destroy old x */ ep->value = (void *) gclone(x); if (v->flag == COPY_VAL) gunclone_deep(old_val); else v->flag = COPY_VAL; } } INLINE GEN copyvalue(entree *ep) { var_cell *v = (var_cell*) ep->pvalue; if (v && v->flag != COPY_VAL) { ep->value = (void*) gclone((GEN)ep->value); v->flag = COPY_VAL; } return (GEN) ep->value; } INLINE void err_var(GEN x) { pari_err_TYPE("evaluator [variable name expected]", x); } enum chk_VALUE { chk_ERROR, chk_NOCREATE, chk_CREATE }; INLINE void checkvalue(entree *ep, enum chk_VALUE flag) { if (MT_IS_THREAD) pari_err(e_MISC,"mt: global variable not supported: %s",ep->name); if (ep->valence==EpNEW) switch(flag) { case chk_ERROR: /* Do nothing until we can report a meaningful error message The extra variable will be cleaned-up anyway */ case chk_CREATE: pari_var_create(ep); ep->valence = EpVAR; ep->value = initial_value(ep); break; case chk_NOCREATE: break; } else if (ep->valence!=EpVAR) err_var(strtoGENstr(ep->name)); } INLINE GEN checkvalueptr(entree *ep) { checkvalue(ep, chk_NOCREATE); return ep->valence==EpNEW? gen_0: (GEN)ep->value; } /* make GP variables safe for avma = top */ static void lvar_make_safe(void) { long n; entree *ep; for (n = 0; n < functions_tblsz; n++) for (ep = functions_hash[n]; ep; ep = ep->next) if (EpVALENCE(ep) == EpVAR) { /* make sure ep->value is a COPY */ var_cell *v = (var_cell*)ep->pvalue; if (v && v->flag == PUSH_VAL) { GEN x = (GEN)ep->value; if (x) changevalue(ep, (GEN)ep->value); else pop_val(ep); } } } static void check_array_index(long c, long l) { if (c < 1) pari_err_COMPONENT("", "<", gen_1, stoi(c)); if (c >= l) pari_err_COMPONENT("", ">", stoi(l-1), stoi(c)); } GEN* safegel(GEN x, long l) { if (!is_matvec_t(typ(x))) pari_err_TYPE("safegel",x); check_array_index(l, lg(x)); return &(gel(x,l)); } GEN* safelistel(GEN x, long l) { GEN d; if (typ(x)!=t_LIST || list_typ(x)!=t_LIST_RAW) pari_err_TYPE("safelistel",x); d = list_data(x); check_array_index(l, lg(d)); return &(gel(d,l)); } long* safeel(GEN x, long l) { if (typ(x)!=t_VECSMALL) pari_err_TYPE("safeel",x); check_array_index(l, lg(x)); return &(x[l]); } GEN* safegcoeff(GEN x, long a, long b) { if (typ(x)!=t_MAT) pari_err_TYPE("safegcoeff", x); check_array_index(b, lg(x)); check_array_index(a, lg(gel(x,b))); return &(gcoeff(x,a,b)); } typedef struct matcomp { GEN *ptcell; GEN parent; int full_col, full_row; } matcomp; typedef struct gp_pointer { matcomp c; GEN x, ox; entree *ep; long vn; long sp; } gp_pointer; /* assign res at *pt in "simple array object" p and return it, or a copy.*/ static void change_compo(matcomp *c, GEN res) { GEN p = c->parent, *pt = c->ptcell; long i, t; if (typ(p) == t_VECSMALL) { if (typ(res) != t_INT || is_bigint(res)) pari_err_TYPE("t_VECSMALL assignment", res); *pt = (GEN)itos(res); return; } t = typ(res); if (c->full_row) { if (t != t_VEC) pari_err_TYPE("matrix row assignment", res); if (lg(res) != lg(p)) pari_err_DIM("matrix row assignment"); for (i=1; ifull_row,i); /* Protect against SIGINT */ gcoeff(p,c->full_row,i) = gclone(gel(res,i)); if (isclone(p1)) gunclone_deep(p1); } return; } if (c->full_col) { if (t != t_COL) pari_err_TYPE("matrix col assignment", res); if (lg(res) != lg(*pt)) pari_err_DIM("matrix col assignment"); } res = gclone(res); gunclone_deep(*pt); *pt = res; } /*************************************************************************** ** ** ** Byte-code evaluator ** ** ** ***************************************************************************/ struct var_lex { long flag; GEN value; }; struct trace { long pc; GEN closure; }; static THREAD long sp, rp, dbg_level; static THREAD long *st, *precs; static THREAD gp_pointer *ptrs; static THREAD entree **lvars; static THREAD struct var_lex *var; static THREAD struct trace *trace; static THREAD pari_stack s_st, s_ptrs, s_var, s_lvars, s_trace, s_prec; static void changelex(long vn, GEN x) { struct var_lex *v=var+s_var.n+vn; GEN old_val = v->value; v->value = gclone(x); if (v->flag == COPY_VAL) gunclone_deep(old_val); else v->flag = COPY_VAL; } INLINE GEN copylex(long vn) { struct var_lex *v = var+s_var.n+vn; if (v->flag!=COPY_VAL) { v->value = gclone(v->value); v->flag = COPY_VAL; } return v->value; } INLINE void pushlex(long vn, GEN x) { struct var_lex *v=var+s_var.n+vn; v->flag = PUSH_VAL; v->value = x; } INLINE void freelex(void) { struct var_lex *v=var+s_var.n-1; s_var.n--; if (v->flag == COPY_VAL) gunclone_deep(v->value); } INLINE void restore_vars(long nbmvar, long nblvar) { long j; for(j=1;j<=nbmvar;j++) freelex(); for(j=1;j<=nblvar;j++) { s_lvars.n--; pop_val(lvars[s_lvars.n]); } } INLINE void restore_trace(long nbtrace) { long j; for(j=1;j<=nbtrace;j++) { GEN C = trace[s_trace.n-j].closure; if (isclone(C)) gunclone(C); } s_trace.n-=nbtrace; } INLINE long trace_push(long pc, GEN C) { long tr; BLOCK_SIGINT_START tr = pari_stack_new(&s_trace); trace[tr].pc = pc; trace[tr].closure = C; BLOCK_SIGINT_END return tr; } void push_lex(GEN a, GEN C) { long vn=pari_stack_new(&s_var); struct var_lex *v=var+vn; v->flag = PUSH_VAL; v->value = a; if (C) (void) trace_push(-1, C); } GEN get_lex(long vn) { struct var_lex *v=var+s_var.n+vn; return v->value; } void set_lex(long vn, GEN x) { struct var_lex *v=var+s_var.n+vn; if (v->flag == COPY_VAL) { gunclone_deep(v->value); v->flag = PUSH_VAL; } v->value = x; } void pop_lex(long n) { long j; for(j=1; j<=n; j++) freelex(); s_trace.n--; } static THREAD pari_stack s_relocs; static THREAD entree **relocs; void pari_init_evaluator(void) { sp=0; pari_stack_init(&s_st,sizeof(*st),(void**)&st); pari_stack_alloc(&s_st,32); s_st.n=s_st.alloc; rp=0; pari_stack_init(&s_ptrs,sizeof(*ptrs),(void**)&ptrs); pari_stack_alloc(&s_ptrs,16); s_ptrs.n=s_ptrs.alloc; pari_stack_init(&s_var,sizeof(*var),(void**)&var); pari_stack_init(&s_lvars,sizeof(*lvars),(void**)&lvars); pari_stack_init(&s_trace,sizeof(*trace),(void**)&trace); br_res = NULL; pari_stack_init(&s_relocs,sizeof(*relocs),(void**)&relocs); pari_stack_init(&s_prec,sizeof(*precs),(void**)&precs); } void pari_close_evaluator(void) { pari_stack_delete(&s_st); pari_stack_delete(&s_ptrs); pari_stack_delete(&s_var); pari_stack_delete(&s_lvars); pari_stack_delete(&s_trace); pari_stack_delete(&s_relocs); pari_stack_delete(&s_prec); } static gp_pointer * new_ptr(void) { if (rp==s_ptrs.n-1) { long i; gp_pointer *old = ptrs; (void)pari_stack_new(&s_ptrs); if (old != ptrs) for(i=0; isp >= 0) gel(st,g->sp) = (GEN) &(g->x); } } return &ptrs[rp++]; } void push_localprec(long p) { long n = pari_stack_new(&s_prec); precs[n] = prec2nbits(p); } void push_localbitprec(long p) { long n = pari_stack_new(&s_prec); precs[n] = p; } void pop_localprec(void) { s_prec.n--; } long get_localbitprec(void) { return s_prec.n? precs[s_prec.n-1]: precreal; } long get_localprec(void) { return nbits2prec(get_localbitprec()); } void localprec(long p) { long pmax = prec2ndec(LGBITS); if (p < 1) pari_err_DOMAIN("localprec", "p", "<", gen_1, stoi(p)); if (p > pmax) pari_err_DOMAIN("localprec", "p", ">", utoi(pmax), stoi(p)); push_localprec(ndec2prec(p)); } void localbitprec(long p) { if (p < 1) pari_err_DOMAIN("localprec", "p", "<", gen_1, stoi(p)); if (p > (long)LGBITS) pari_err_DOMAIN("localbitprec", "p", ">", utoi(LGBITS), stoi(p)); push_localbitprec(p); } INLINE GEN copyupto(GEN z, GEN t) { if (is_universal_constant(z) || (z>(GEN)pari_mainstack->bot && z<=t)) return z; else return gcopy(z); } static void closure_eval(GEN C); INLINE GEN closure_return(GEN C) { pari_sp ltop=avma; closure_eval(C); if (br_status) { GEN z; avma=ltop; z=br_res?gcopy(br_res):gnil; reset_break(); return z; } return gerepileupto(ltop,gel(st,--sp)); } /* for the break_loop debugger. Not memory clean */ GEN closure_evalbrk(GEN C, long *status) { closure_eval(C); *status = br_status; if (br_status) { GEN z = br_res? gcopy(br_res): gnil; reset_break(); return z; } return gel(st,--sp); } INLINE long closure_varn(GEN x) { if (!x) return -1; if (!gequalX(x)) err_var(x); return varn(x); } INLINE void closure_castgen(GEN z, long mode) { switch (mode) { case Ggen: gel(st,sp++)=z; break; case Gsmall: st[sp++]=gtos(z); break; case Gusmall: st[sp++]=gtou(z); break; case Gvar: st[sp++]=closure_varn(z); break; case Gvoid: break; default: pari_err_BUG("closure_castgen, type unknown"); } } INLINE void closure_castlong(long z, long mode) { switch (mode) { case Gsmall: st[sp++]=z; break; case Gusmall: if (z < 0) pari_err_TYPE("stou [integer >=0 expected]", stoi(z)); st[sp++]=(ulong) z; break; case Ggen: gel(st,sp++)=stoi(z); break; case Gvar: err_var(stoi(z)); case Gvoid: break; default: pari_err_BUG("closure_castlong, type unknown"); } } const char * closure_func_err(void) { long fun=s_trace.n-1, pc; const char *code; GEN C, oper; if (fun < 0 || trace[fun].pc < 0) return NULL; pc = trace[fun].pc; C = trace[fun].closure; code = closure_codestr(C); oper = closure_get_oper(C); if (code[pc]==OCcallgen || code[pc]==OCcallgen2 || code[pc]==OCcallint || code[pc]==OCcalllong || code[pc]==OCcallvoid) return ((entree*)oper[pc])->name; return NULL; } /* return the next label for the call chain debugger closure_err(), * incorporating the name of the user of member function. Return NULL for an * anonymous (inline) closure. */ static char * get_next_label(const char *s, int member, char **next_fun) { const char *v, *t = s+1; char *u, *next_label; if (!is_keyword_char(*s)) return NULL; while (is_keyword_char(*t)) t++; /* e.g. (x->1/x)(0) instead of (x)->1/x */ if (t[0] == '-' && t[1] == '>') return NULL; next_label = (char*)pari_malloc(t - s + 32); sprintf(next_label, "in %sfunction ", member? "member ": ""); u = *next_fun = next_label + strlen(next_label); v = s; while (v < t) *u++ = *v++; *u++ = 0; return next_label; } static const char * get_arg_name(GEN C, long i) { GEN d = closure_get_dbg(C), frpc = gel(d,2), fram = gel(d,3); long j, l = lg(frpc); for (j=1; jname; return "(unnamed)"; } void closure_err(long level) { GEN base; const long lastfun = s_trace.n - 1 - level; char *next_label, *next_fun; long i = maxss(0, lastfun - 19); if (lastfun < 0) return; /*e.g. when called by gp_main_loop's simplify */ if (i > 0) while (lg(trace[i].closure)==6) i--; base = closure_get_text(trace[i].closure); /* gcc -Wall*/ next_label = pari_strdup(i == 0? "at top-level": "[...] at"); next_fun = next_label; for (; i <= lastfun; i++) { GEN C = trace[i].closure; if (lg(C) >= 7) base=closure_get_text(C); if ((i==lastfun || lg(trace[i+1].closure)>=7)) { GEN dbg = gel(closure_get_dbg(C),1); /* After a SIGINT, pc can be slightly off: ensure 0 <= pc < lg() */ long pc = minss(lg(dbg)-1, trace[i].pc>=0 ? trace[i].pc: 1); long offset = pc? dbg[pc]: 0; int member; const char *s, *sbase; if (typ(base)!=t_VEC) sbase = GSTR(base); else if (offset>=0) sbase = GSTR(gel(base,2)); else { sbase = GSTR(gel(base,1)); offset += strlen(sbase); } s = sbase + offset; member = offset>0 && (s[-1] == '.'); /* avoid "in function foo: foo" */ if (!next_fun || strcmp(next_fun, s)) { print_errcontext(pariErr, next_label, s, sbase); out_putc(pariErr, '\n'); } pari_free(next_label); if (i == lastfun) break; next_label = get_next_label(s, member, &next_fun); if (!next_label) { next_label = pari_strdup("in anonymous function"); next_fun = NULL; } } } } GEN pari_self(void) { long fun = s_trace.n - 1; if (fun > 0) while (lg(trace[fun].closure)==6) fun--; return fun >= 0 ? trace[fun].closure: NULL; } long closure_context(long start, long level) { const long lastfun = s_trace.n - 1 - level; long i, fun = lastfun; if (fun<0) return lastfun; while (fun>start && lg(trace[fun].closure)==6) fun--; for (i=fun; i <= lastfun; i++) push_frame(trace[i].closure, trace[i].pc,0); for ( ; i < s_trace.n; i++) push_frame(trace[i].closure, trace[i].pc,1); return s_trace.n-level; } INLINE void st_alloc(long n) { if (sp+n>s_st.n) { pari_stack_alloc(&s_st,n+16); s_st.n=s_st.alloc; if (DEBUGMEM>=2) pari_warn(warner,"doubling evaluator stack"); } } INLINE void ptr_proplock(gp_pointer *g, GEN C) { g->x = C; if (isclone(g->x)) { clone_unlock_deep(g->ox); g->ox = g->x; ++bl_refc(g->ox); } } static void closure_eval(GEN C) { const char *code=closure_codestr(C); GEN oper=closure_get_oper(C); GEN data=closure_get_data(C); long loper=lg(oper); long saved_sp=sp-closure_arity(C); long saved_rp=rp, saved_prec=s_prec.n; long j, nbmvar=0, nblvar=0; long pc, t; #ifdef STACK_CHECK GEN stackelt; if (PARI_stack_limit && (void*) &stackelt <= PARI_stack_limit) pari_err(e_MISC, "deep recursion"); #endif clone_lock(C); t = trace_push(0, C); if (lg(C)==8) { GEN z=closure_get_frame(C); long l=lg(z)-1; pari_stack_alloc(&s_var,l); s_var.n+=l; nbmvar+=l; for(j=1;j<=l;j++) { var[s_var.n-j].flag=PUSH_VAL; var[s_var.n-j].value=gel(z,j); } } for(pc=1;pcvalue; break; } case OCpushlex: gel(st,sp++)=var[s_var.n+operand].value; break; case OCsimpleptrdyn: { gp_pointer *g = new_ptr(); g->vn=0; g->ep = (entree*) operand; g->x = checkvalueptr(g->ep); g->ox = g->x; clone_lock(g->ox); g->sp = sp; gel(st,sp++) = (GEN)&(g->x); break; } case OCsimpleptrlex: { gp_pointer *g = new_ptr(); g->vn=operand; g->ep=(entree *)0x1L; g->x = (GEN) var[s_var.n+operand].value; g->ox = g->x; clone_lock(g->ox); g->sp = sp; gel(st,sp++) = (GEN)&(g->x); break; } case OCnewptrdyn: { entree *ep = (entree *)operand; gp_pointer *g = new_ptr(); matcomp *C; checkvalue(ep, chk_ERROR); g->sp = -1; g->x = copyvalue(ep); g->ox = g->x; clone_lock(g->ox); g->vn=0; g->ep=NULL; C=&g->c; C->full_col = C->full_row = 0; C->parent = (GEN) g->x; C->ptcell = (GEN *) &g->x; break; } case OCnewptrlex: { gp_pointer *g = new_ptr(); matcomp *C; g->sp = -1; g->x = copylex(operand); g->ox = g->x; clone_lock(g->ox); g->vn=0; g->ep=NULL; C=&g->c; C->full_col = C->full_row = 0; C->parent = (GEN) g->x; C->ptcell = (GEN *) &(g->x); break; } case OCpushptr: { gp_pointer *g = &ptrs[rp-1]; g->sp = sp; gel(st,sp++) = (GEN)&(g->x); } break; case OCendptr: for(j=0;jep) { if (g->vn) changelex(g->vn, g->x); else changevalue(g->ep, g->x); } else change_compo(&(g->c), g->x); clone_unlock_deep(g->ox); } break; case OCstoredyn: { entree *ep = (entree *)operand; checkvalue(ep, chk_NOCREATE); changevalue(ep, gel(st,--sp)); break; } case OCstorelex: changelex(operand,gel(st,--sp)); break; case OCstoreptr: { gp_pointer *g = &ptrs[--rp]; change_compo(&(g->c), gel(st,--sp)); clone_unlock_deep(g->ox); break; } case OCstackgen: { GEN z = gerepileupto(st[sp-2],gel(st,sp-1)); gmael(st,sp-3,operand) = copyupto(z,gel(st,sp-2)); st[sp-2] = avma; sp--; break; } case OCprecreal: st[sp++]=get_localprec(); break; case OCbitprecreal: st[sp++]=get_localbitprec(); break; case OCprecdl: st[sp++]=precdl; break; case OCavma: st[sp++]=avma; break; case OCcowvardyn: { entree *ep = (entree *)operand; checkvalue(ep, chk_ERROR); (void)copyvalue(ep); break; } case OCcowvarlex: (void)copylex(operand); break; case OCstoi: gel(st,sp-1)=stoi(st[sp-1]); break; case OCutoi: gel(st,sp-1)=utoi(st[sp-1]); break; case OCitos: st[sp+operand]=gtos(gel(st,sp+operand)); break; case OCitou: st[sp+operand]=gtou(gel(st,sp+operand)); break; case OCtostr: { GEN z = gel(st,sp+operand); st[sp+operand] = (long)GENtostr_unquoted(z); break; } case OCvarn: st[sp+operand] = closure_varn(gel(st,sp+operand)); break; case OCcopy: gel(st,sp-1) = gcopy(gel(st,sp-1)); break; case OCgerepile: { pari_sp av; GEN x; sp--; av = st[sp-1]; x = gel(st,sp); if (isonstack(x)) { pari_sp av2 = (pari_sp)(x + lg(x)); if ((long) (av - av2) > 1000000L) { if (DEBUGMEM>=2) pari_warn(warnmem,"eval: recovering %ld bytes", av - av2); x = gerepileupto(av, x); } } else avma = av; gel(st,sp-1) = x; break; } case OCcopyifclone: if (isclone(gel(st,sp-1))) gel(st,sp-1) = gcopy(gel(st,sp-1)); break; case OCcompo1: { GEN p=gel(st,sp-2); long c=st[sp-1]; sp-=2; switch(typ(p)) { case t_VEC: case t_COL: check_array_index(c, lg(p)); closure_castgen(gel(p,c),operand); break; case t_LIST: { long lx; if (list_typ(p)!=t_LIST_RAW) pari_err_TYPE("_[_] OCcompo1 [not a vector]", p); p = list_data(p); lx = p? lg(p): 1; check_array_index(c, lx); closure_castgen(gel(p,c),operand); break; } case t_VECSMALL: check_array_index(c,lg(p)); closure_castlong(p[c],operand); break; default: pari_err_TYPE("_[_] OCcompo1 [not a vector]", p); break; } break; } case OCcompo1ptr: { long c=st[sp-1]; long lx; gp_pointer *g = &ptrs[rp-1]; matcomp *C=&g->c; GEN p = g->x; sp--; switch(typ(p)) { case t_VEC: case t_COL: check_array_index(c, lg(p)); C->ptcell = (GEN *) p+c; ptr_proplock(g, *(C->ptcell)); break; case t_VECSMALL: check_array_index(c, lg(p)); C->ptcell = (GEN *) p+c; g->x = stoi(p[c]); break; case t_LIST: if (list_typ(p)!=t_LIST_RAW) pari_err_TYPE("&_[_] OCcompo1 [not a vector]", p); p = list_data(p); lx = p? lg(p): 1; check_array_index(c,lx); C->ptcell = (GEN *) p+c; ptr_proplock(g, *(C->ptcell)); break; default: pari_err_TYPE("&_[_] OCcompo1ptr [not a vector]", p); } C->parent = p; break; } case OCcompo2: { GEN p=gel(st,sp-3); long c=st[sp-2]; long d=st[sp-1]; if (typ(p)!=t_MAT) pari_err_TYPE("_[_,_] OCcompo2 [not a matrix]", p); check_array_index(d, lg(p)); check_array_index(c, lg(gel(p,d))); sp-=3; closure_castgen(gcoeff(p,c,d),operand); break; } case OCcompo2ptr: { long c=st[sp-2]; long d=st[sp-1]; gp_pointer *g = &ptrs[rp-1]; matcomp *C=&g->c; GEN p = g->x; sp-=2; if (typ(p)!=t_MAT) pari_err_TYPE("&_[_,_] OCcompo2ptr [not a matrix]", p); check_array_index(d, lg(p)); check_array_index(c, lg(gel(p,d))); C->ptcell = (GEN *) gel(p,d)+c; C->parent = p; ptr_proplock(g, *(C->ptcell)); break; } case OCcompoC: { GEN p=gel(st,sp-2); long c=st[sp-1]; if (typ(p)!=t_MAT) pari_err_TYPE("_[,_] OCcompoC [not a matrix]", p); check_array_index(c, lg(p)); sp--; gel(st,sp-1) = gel(p,c); break; } case OCcompoCptr: { long c=st[sp-1]; gp_pointer *g = &ptrs[rp-1]; matcomp *C=&g->c; GEN p = g->x; sp--; if (typ(p)!=t_MAT) pari_err_TYPE("&_[,_] OCcompoCptr [not a matrix]", p); check_array_index(c, lg(p)); C->ptcell = (GEN *) p+c; C->full_col = c; C->parent = p; ptr_proplock(g, *(C->ptcell)); break; } case OCcompoL: { GEN p=gel(st,sp-2); long r=st[sp-1]; sp--; if (typ(p)!=t_MAT) pari_err_TYPE("_[_,] OCcompoL [not a matrix]", p); check_array_index(r,lg(p) == 1? 1: lgcols(p)); gel(st,sp-1) = row(p,r); break; } case OCcompoLptr: { long r=st[sp-1]; gp_pointer *g = &ptrs[rp-1]; matcomp *C=&g->c; GEN p = g->x, p2; sp--; if (typ(p)!=t_MAT) pari_err_TYPE("&_[_,] OCcompoLptr [not a matrix]", p); check_array_index(r,lg(p) == 1? 1: lgcols(p)); p2 = rowcopy(p,r); C->full_row = r; /* record row number */ C->ptcell = &p2; C->parent = p; g->x = p2; break; } case OCdefaultarg: if (var[s_var.n+operand].flag==DEFAULT_VAL) { GEN z = gel(st,sp-1); if (typ(z)==t_CLOSURE) { pushlex(operand, closure_evalnobrk(z)); copylex(operand); } else pushlex(operand, z); } sp--; break; case OClocalvar: { long n = pari_stack_new(&s_lvars); entree *ep = (entree *)operand; checkvalue(ep, chk_NOCREATE); lvars[n] = ep; nblvar++; pushvalue(ep,gel(st,--sp)); break; } case OClocalvar0: { long n = pari_stack_new(&s_lvars); entree *ep = (entree *)operand; checkvalue(ep, chk_NOCREATE); lvars[n] = ep; nblvar++; zerovalue(ep); break; } #define EVAL_f(f) \ switch (ep->arity) \ { \ case 0: f(); break; \ case 1: sp--; f(st[sp]); break; \ case 2: sp-=2; f(st[sp],st[sp+1]); break; \ case 3: sp-=3; f(st[sp],st[sp+1],st[sp+2]); break; \ case 4: sp-=4; f(st[sp],st[sp+1],st[sp+2],st[sp+3]); break; \ case 5: sp-=5; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4]); break; \ case 6: sp-=6; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5]); break; \ case 7: sp-=7; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6]); break; \ case 8: sp-=8; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7]); break; \ case 9: sp-=9; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8]); break; \ case 10: sp-=10; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9]); break; \ case 11: sp-=11; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10]); break; \ case 12: sp-=12; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11]); break; \ case 13: sp-=13; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12]); break; \ case 14: sp-=14; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13]); break; \ case 15: sp-=15; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14]); break; \ case 16: sp-=16; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15]); break; \ case 17: sp-=17; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16]); break; \ case 18: sp-=18; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16],st[sp+17]); break; \ case 19: sp-=19; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16],st[sp+17],st[sp+18]); break; \ case 20: sp-=20; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16],st[sp+17],st[sp+18],st[sp+19]); break; \ default: \ pari_err_IMPL("functions with more than 20 parameters");\ goto endeval; /*LCOV_EXCL_LINE*/ \ } case OCcallgen: { entree *ep = (entree *)operand; GEN res; /* Macro Madness : evaluate function ep->value on arguments * st[sp-ep->arity .. sp]. Set res = result. */ EVAL_f(res = ((GEN (*)(ANYARG))ep->value)); if (br_status) goto endeval; gel(st,sp++)=res; break; } case OCcallgen2: /*same for ep->arity = 2. Is this optimization worth it ?*/ { entree *ep = (entree *)operand; GEN res; sp-=2; res = ((GEN (*)(GEN,GEN))ep->value)(gel(st,sp),gel(st,sp+1)); if (br_status) goto endeval; gel(st,sp++)=res; break; } case OCcalllong: { entree *ep = (entree *)operand; long res; EVAL_f(res = ((long (*)(ANYARG))ep->value)); if (br_status) goto endeval; st[sp++] = res; break; } case OCcallint: { entree *ep = (entree *)operand; long res; EVAL_f(res = ((int (*)(ANYARG))ep->value)); if (br_status) goto endeval; st[sp++] = res; break; } case OCcallvoid: { entree *ep = (entree *)operand; EVAL_f(((void (*)(ANYARG))ep->value)); if (br_status) goto endeval; break; } #undef EVAL_f case OCcalluser: { long n=operand; GEN fun = gel(st,sp-1-n); long arity, isvar; GEN z; if (typ(fun)!=t_CLOSURE) pari_err(e_NOTFUNC, fun); isvar = closure_is_variadic(fun); arity = closure_arity(fun); if (!isvar || n < arity) { st_alloc(arity-n); if (n>arity) pari_err(e_MISC,"too many parameters in user-defined function call"); for (j=n+1;j<=arity;j++) gel(st,sp++)=0; if (isvar) gel(st,sp-1) = cgetg(1,t_VEC); } else { GEN v; long j, m = n-arity+1; v = cgetg(m+1,t_VEC); sp-=m; for (j=1; j<=m; j++) gel(v,j) = gel(st,sp+j-1)? gcopy(gel(st,sp+j-1)): gen_0; gel(st,sp++)=v; } z = closure_return(fun); if (br_status) goto endeval; gel(st, sp-1) = z; break; } case OCnewframe: if (operand>0) nbmvar+=operand; else operand=-operand; pari_stack_alloc(&s_var,operand); s_var.n+=operand; for(j=1;j<=operand;j++) { var[s_var.n-j].flag=PUSH_VAL; var[s_var.n-j].value=gen_0; } break; case OCsaveframe: { GEN cl = (operand?gcopy:shallowcopy)(gel(st,sp-1)); long l = lg(gel(cl,7)); GEN v = cgetg(l, t_VEC); for(j=1; j>=1UL,j--) if ((operand&1L) && gel(st,j)==NULL) pari_err(e_MISC,"missing mandatory argument"); break; case OCcheckargs0: for (j=sp-1;operand;operand>>=1UL,j--) if ((operand&1L) && gel(st,j)) pari_err(e_MISC,"argument type not implemented"); break; case OCdefaultlong: sp--; if (st[sp+operand]) st[sp+operand]=gtos(gel(st,sp+operand)); else st[sp+operand]=st[sp]; break; case OCdefaultulong: sp--; if (st[sp+operand]) st[sp+operand]=gtou(gel(st,sp+operand)); else st[sp+operand]=st[sp]; break; case OCdefaultgen: sp--; if (!st[sp+operand]) st[sp+operand]=st[sp]; break; case OCvec: gel(st,sp++)=cgetg(operand,t_VEC); st[sp++]=avma; break; case OCcol: gel(st,sp++)=cgetg(operand,t_COL); st[sp++]=avma; break; case OCmat: { GEN z; long l=st[sp-1]; z=cgetg(operand,t_MAT); for(j=1;jsaved_rp ; ) { gp_pointer *g = &ptrs[--rp]; clone_unlock_deep(g->ox); } } s_prec.n = saved_prec; s_trace.n--; restore_vars(nbmvar, nblvar); clone_unlock(C); } GEN closure_evalgen(GEN C) { pari_sp ltop=avma; closure_eval(C); if (br_status) { avma=ltop; return NULL; } return gerepileupto(ltop,gel(st,--sp)); } void evalstate_save(struct pari_evalstate *state) { state->avma = avma; state->sp = sp; state->rp = rp; state->prec = s_prec.n; state->var = s_var.n; state->lvars= s_lvars.n; state->trace= s_trace.n; compilestate_save(&state->comp); mtstate_save(&state->pending_threads); } void evalstate_restore(struct pari_evalstate *state) { avma = state->avma; mtstate_restore(&state->pending_threads); sp = state->sp; rp = state->rp; s_prec.n = state->prec; restore_vars(s_var.n-state->var,s_lvars.n-state->lvars); restore_trace(s_trace.n-state->trace); reset_break(); compilestate_restore(&state->comp); } GEN evalstate_restore_err(struct pari_evalstate *state) { GENbin* err = copy_bin(pari_err_last()); evalstate_restore(state); return bin_copy(err); } void evalstate_reset(void) { mtstate_reset(); sp = 0; rp = 0; dbg_level = 0; restore_vars(s_var.n, s_lvars.n); s_trace.n = 0; reset_break(); compilestate_reset(); parsestate_reset(); avma = pari_mainstack->top; } void evalstate_clone(void) { long i; for (i = 1; i<=s_var.n; i++) copylex(-i); lvar_make_safe(); for (i = 0; i< s_trace.n; i++) { GEN C = trace[i].closure; if (isonstack(C)) trace[i].closure = gclone(C); } } GEN closure_trapgen(GEN C, long numerr) { VOLATILE GEN x; struct pari_evalstate state; evalstate_save(&state); pari_CATCH(numerr) { x = (GEN)1L; } pari_TRY { x = closure_evalgen(C); } pari_ENDCATCH; if (x == (GEN)1L) evalstate_restore(&state); return x; } GEN closure_evalnobrk(GEN C) { pari_sp ltop=avma; closure_eval(C); if (br_status) pari_err(e_MISC, "break not allowed here"); return gerepileupto(ltop,gel(st,--sp)); } void closure_evalvoid(GEN C) { pari_sp ltop=avma; closure_eval(C); avma=ltop; } GEN closure_evalres(GEN C) { return closure_return(C); } INLINE GEN closure_returnupto(GEN C) { pari_sp av=avma; return copyupto(closure_return(C),(GEN)av); } GEN pareval_worker(GEN C) { return closure_callgenall(C, 0); } GEN pareval(GEN C) { pari_sp av = avma; long l = lg(C), i; GEN worker; if (!is_vec_t(typ(C))) pari_err_TYPE("pareval",C); for (i=1; i1) pari_warn(warnmem,"sum"); x = gerepileupto(av2,x); } } } mt_queue_end(&pt); return gerepilecopy(av, x); } void parfor(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN)) { pari_sp av = avma, av2; long running, pending = 0; long status = br_NONE; GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code)); GEN done, stop = NULL; struct pari_mt pt; if (typ(a) != t_INT) pari_err_TYPE("parfor",a); if (b) { if (gcmp(b,a) < 0) return; if (typ(b) == t_INFINITY) { if (inf_get_sign(b) < 0) return; b = NULL; } else b = gfloor(b); } mt_queue_start(&pt, worker); a = mkvec(setloop(a)); av2 = avma; while ((running = (!stop && (!b || cmpii(gel(a,1),b) <= 0))) || pending) { mt_queue_submit(&pt, 0, running ? a: NULL); done = mt_queue_get(&pt, NULL, &pending); if (call && done && (!stop || cmpii(gel(done,1),stop) < 0)) if (call(E, gel(done,1), gel(done,2))) { status = br_status; br_status = br_NONE; stop = gerepileuptoint(av2, gel(done,1)); } gel(a,1) = incloop(gel(a,1)); if (!stop) avma = av2; } avma = av2; mt_queue_end(&pt); br_status = status; avma = av; } static long gp_evalvoid2(void *E, GEN x, GEN y) { GEN code =(GEN) E; push_lex(x, code); push_lex(y, NULL); closure_evalvoid(code); pop_lex(2); return loop_break(); } void parfor0(GEN a, GEN b, GEN code, GEN code2) { parfor(a, b, code, (void*)code2, code2 ? gp_evalvoid2: NULL); } void parforprime(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN)) { pari_sp av = avma, av2; long running, pending = 0; long status = br_NONE; GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code)); GEN v, done, stop = NULL; struct pari_mt pt; forprime_t T; if (!forprime_init(&T, a,b)) { avma = av; return; } mt_queue_start(&pt, worker); v = mkvec(gen_0); av2 = avma; while ((running = (!stop && forprime_next(&T))) || pending) { gel(v, 1) = T.pp; mt_queue_submit(&pt, 0, running ? v: NULL); done = mt_queue_get(&pt, NULL, &pending); if (call && done && (!stop || cmpii(gel(done,1),stop) < 0)) if (call(E, gel(done,1), gel(done,2))) { status = br_status; br_status = br_NONE; stop = gerepileuptoint(av2, gel(done,1)); } if (!stop) avma = av2; } avma = av2; mt_queue_end(&pt); br_status = status; avma = av; } void parforprime0(GEN a, GEN b, GEN code, GEN code2) { parforprime(a, b, code, (void*)code2, code2? gp_evalvoid2: NULL); } void parforvec(GEN x, GEN code, long flag, void *E, long call(void*, GEN, GEN)) { pari_sp av = avma, av2; long running, pending = 0; long status = br_NONE; GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code)); GEN done, stop = NULL; struct pari_mt pt; forvec_t T; GEN a, v = gen_0; if (!forvec_init(&T, x, flag)) { avma = av; return; } mt_queue_start(&pt, worker); a = mkvec(gen_0); av2 = avma; while ((running = (!stop && v && (v = forvec_next(&T)))) || pending) { gel(a, 1) = v; mt_queue_submit(&pt, 0, running ? a: NULL); done = mt_queue_get(&pt, NULL, &pending); if (call && done && (!stop || lexcmp(gel(done,1),stop) < 0)) if (call(E, gel(done,1), gel(done,2))) { status = br_status; br_status = br_NONE; stop = gerepilecopy(av2, gel(done,1)); } if (!stop) avma = av2; } avma = av2; mt_queue_end(&pt); br_status = status; avma = av; } void parforvec0(GEN x, GEN code, GEN code2, long flag) { parforvec(x, code, flag, (void*)code2, code2? gp_evalvoid2: NULL); } void closure_callvoid1(GEN C, GEN x) { long i, ar = closure_arity(C); gel(st,sp++) = x; for(i=2; i <= ar; i++) gel(st,sp++) = NULL; closure_evalvoid(C); } GEN closure_callgen1(GEN C, GEN x) { long i, ar = closure_arity(C); gel(st,sp++) = x; for(i=2; i<= ar; i++) gel(st,sp++) = NULL; return closure_returnupto(C); } GEN closure_callgen1prec(GEN C, GEN x, long prec) { GEN z; long i, ar = closure_arity(C); gel(st,sp++) = x; for(i=2; i<= ar; i++) gel(st,sp++) = NULL; push_localprec(prec); z = closure_returnupto(C); pop_localprec(); return z; } GEN closure_callgen2(GEN C, GEN x, GEN y) { long i, ar = closure_arity(C); st_alloc(ar); gel(st,sp++) = x; gel(st,sp++) = y; for(i=3; i<=ar; i++) gel(st,sp++) = NULL; return closure_returnupto(C); } GEN closure_callgenvec(GEN C, GEN args) { long i, l = lg(args)-1, ar = closure_arity(C); st_alloc(ar); if (l > ar) pari_err(e_MISC,"too many parameters in user-defined function call"); if (closure_is_variadic(C) && l==ar && typ(gel(args,l))!=t_VEC) pari_err_TYPE("call", gel(args,l)); for (i = 1; i <= l; i++) gel(st,sp++) = gel(args,i); for( ; i <= ar; i++) gel(st,sp++) = NULL; return closure_returnupto(C); } GEN closure_callgenvecprec(GEN C, GEN args, long prec) { GEN z; push_localprec(prec); z = closure_callgenvec(C, args); pop_localprec(); return z; } GEN closure_callgenall(GEN C, long n, ...) { va_list ap; long i, ar = closure_arity(C); va_start(ap,n); if (n > ar) pari_err(e_MISC,"too many parameters in user-defined function call"); st_alloc(ar); for (i = 1; i <=n; i++) gel(st,sp++) = va_arg(ap, GEN); for( ; i <=ar; i++) gel(st,sp++) = NULL; va_end(ap); return closure_returnupto(C); } GEN gp_eval(void *E, GEN x) { GEN code = (GEN)E; set_lex(-1,x); return closure_evalnobrk(code); } GEN gp_evalupto(void *E, GEN x) { pari_sp av = avma; return copyupto(gp_eval(E,x), (GEN)av); } GEN gp_evalprec(void *E, GEN x, long prec) { GEN z; push_localprec(prec); z = gp_eval(E, x); pop_localprec(); return z; } long gp_evalbool(void *E, GEN x) { pari_sp av = avma; long res = !gequal0(gp_eval(E,x)); avma = av; return res; } long gp_evalvoid(void *E, GEN x) { GEN code = (GEN)E; set_lex(-1,x); closure_evalvoid(code); return loop_break(); } GEN gp_call(void *E, GEN x) { GEN code = (GEN)E; return closure_callgen1(code, x); } GEN gp_callprec(void *E, GEN x, long prec) { GEN code = (GEN)E; return closure_callgen1prec(code, x, prec); } GEN gp_call2(void *E, GEN x, GEN y) { GEN code = (GEN)E; return closure_callgen2(code, x, y); } long gp_callbool(void *E, GEN x) { pari_sp av = avma; GEN code = (GEN)E; long res = !gequal0(closure_callgen1(code, x)); avma = av; return res; } long gp_callvoid(void *E, GEN x) { GEN code = (GEN)E; closure_callvoid1(code, x); return loop_break(); } INLINE const char * disassemble_cast(long mode) { switch (mode) { case Gsmall: return "small"; case Ggen: return "gen"; case Gvar: return "var"; case Gvoid: return "void"; default: return "unknown"; } } void closure_disassemble(GEN C) { const char * code; GEN oper; long i; if (typ(C)!=t_CLOSURE) pari_err_TYPE("disassemble",C); code=closure_codestr(C); oper=closure_get_oper(C); for(i=1;iname); break; } case OCpushdyn: { entree *ep = (entree *)operand; pari_printf("pushdyn\t\t%s\n",ep->name); break; } case OCpushlex: pari_printf("pushlex\t\t%ld\n",operand); break; case OCstoredyn: { entree *ep = (entree *)operand; pari_printf("storedyn\t%s\n",ep->name); break; } case OCstorelex: pari_printf("storelex\t%ld\n",operand); break; case OCstoreptr: pari_printf("storeptr\n"); break; case OCsimpleptrdyn: { entree *ep = (entree *)operand; pari_printf("simpleptrdyn\t%s\n",ep->name); break; } case OCsimpleptrlex: pari_printf("simpleptrlex\t%ld\n",operand); break; case OCnewptrdyn: { entree *ep = (entree *)operand; pari_printf("newptrdyn\t%s\n",ep->name); break; } case OCnewptrlex: pari_printf("newptrlex\t%ld\n",operand); break; case OCpushptr: pari_printf("pushptr\n"); break; case OCstackgen: pari_printf("stackgen\t%ld\n",operand); break; case OCendptr: pari_printf("endptr\t\t%ld\n",operand); break; case OCprecreal: pari_printf("precreal\n"); break; case OCbitprecreal: pari_printf("bitprecreal\n"); break; case OCprecdl: pari_printf("precdl\n"); break; case OCstoi: pari_printf("stoi\n"); break; case OCutoi: pari_printf("utoi\n"); break; case OCitos: pari_printf("itos\t\t%ld\n",operand); break; case OCitou: pari_printf("itou\t\t%ld\n",operand); break; case OCtostr: pari_printf("tostr\t\t%ld\n",operand); break; case OCvarn: pari_printf("varn\t\t%ld\n",operand); break; case OCcopy: pari_printf("copy\n"); break; case OCcopyifclone: pari_printf("copyifclone\n"); break; case OCcompo1: pari_printf("compo1\t\t%s\n",disassemble_cast(operand)); break; case OCcompo1ptr: pari_printf("compo1ptr\n"); break; case OCcompo2: pari_printf("compo2\t\t%s\n",disassemble_cast(operand)); break; case OCcompo2ptr: pari_printf("compo2ptr\n"); break; case OCcompoC: pari_printf("compoC\n"); break; case OCcompoCptr: pari_printf("compoCptr\n"); break; case OCcompoL: pari_printf("compoL\n"); break; case OCcompoLptr: pari_printf("compoLptr\n"); break; case OCcheckargs: pari_printf("checkargs\t0x%lx\n",operand); break; case OCcheckargs0: pari_printf("checkargs0\t0x%lx\n",operand); break; case OCcheckuserargs: pari_printf("checkuserargs\t%ld\n",operand); break; case OCdefaultlong: pari_printf("defaultlong\t%ld\n",operand); break; case OCdefaultulong: pari_printf("defaultulong\t%ld\n",operand); break; case OCdefaultgen: pari_printf("defaultgen\t%ld\n",operand); break; case OCgetargs: pari_printf("getargs\t\t%ld\n",operand); break; case OCdefaultarg: pari_printf("defaultarg\t%ld\n",operand); break; case OClocalvar: { entree *ep = (entree *)operand; pari_printf("localvar\t%s\n",ep->name); break; } case OClocalvar0: { entree *ep = (entree *)operand; pari_printf("localvar0\t%s\n",ep->name); break; } case OCcallgen: { entree *ep = (entree *)operand; pari_printf("callgen\t\t%s\n",ep->name); break; } case OCcallgen2: { entree *ep = (entree *)operand; pari_printf("callgen2\t%s\n",ep->name); break; } case OCcalllong: { entree *ep = (entree *)operand; pari_printf("calllong\t%s\n",ep->name); break; } case OCcallint: { entree *ep = (entree *)operand; pari_printf("callint\t\t%s\n",ep->name); break; } case OCcallvoid: { entree *ep = (entree *)operand; pari_printf("callvoid\t%s\n",ep->name); break; } case OCcalluser: pari_printf("calluser\t%ld\n",operand); break; case OCvec: pari_printf("vec\t\t%ld\n",operand); break; case OCcol: pari_printf("col\t\t%ld\n",operand); break; case OCmat: pari_printf("mat\t\t%ld\n",operand); break; case OCnewframe: pari_printf("newframe\t%ld\n",operand); break; case OCsaveframe: pari_printf("saveframe\t%ld\n", operand); break; case OCpop: pari_printf("pop\t\t%ld\n",operand); break; case OCdup: pari_printf("dup\t\t%ld\n",operand); break; case OCavma: pari_printf("avma\n",operand); break; case OCgerepile: pari_printf("gerepile\n",operand); break; case OCcowvardyn: { entree *ep = (entree *)operand; pari_printf("cowvardyn\t%s\n",ep->name); break; } case OCcowvarlex: pari_printf("cowvarlex\t%ld\n",operand); break; } } } static int opcode_need_relink(op_code opcode) { switch(opcode) { case OCpushlong: case OCpushgen: case OCpushgnil: case OCpushreal: case OCpushstoi: case OCpushlex: case OCstorelex: case OCstoreptr: case OCsimpleptrlex: case OCnewptrlex: case OCpushptr: case OCstackgen: case OCendptr: case OCprecreal: case OCbitprecreal: case OCprecdl: case OCstoi: case OCutoi: case OCitos: case OCitou: case OCtostr: case OCvarn: case OCcopy: case OCcopyifclone: case OCcompo1: case OCcompo1ptr: case OCcompo2: case OCcompo2ptr: case OCcompoC: case OCcompoCptr: case OCcompoL: case OCcompoLptr: case OCcheckargs: case OCcheckargs0: case OCcheckuserargs: case OCgetargs: case OCdefaultarg: case OCdefaultgen: case OCdefaultlong: case OCdefaultulong: case OCcalluser: case OCvec: case OCcol: case OCmat: case OCnewframe: case OCsaveframe: case OCdup: case OCpop: case OCavma: case OCgerepile: case OCcowvarlex: break; case OCpushvar: case OCpushdyn: case OCstoredyn: case OCsimpleptrdyn: case OCnewptrdyn: case OClocalvar: case OClocalvar0: case OCcallgen: case OCcallgen2: case OCcalllong: case OCcallint: case OCcallvoid: case OCcowvardyn: return 1; } return 0; } static void closure_relink(GEN C, hashtable *table) { const char *code = closure_codestr(C); GEN oper = closure_get_oper(C); GEN fram = gel(closure_get_dbg(C),3); long i, j; for(i=1;ival; for (i=1;ival; } void gen_relink(GEN x, hashtable *table) { long i, lx, tx = typ(x); switch(tx) { case t_CLOSURE: closure_relink(x, table); gen_relink(closure_get_data(x), table); if (lg(x)==8) gen_relink(closure_get_frame(x), table); break; case t_LIST: if (list_data(x)) gen_relink(list_data(x), table); break; case t_VEC: case t_COL: case t_MAT: case t_ERROR: lx = lg(x); for (i=lontyp[tx]; ivalue) continue; gen_unlink((GEN)ep->value); } } n = s_relocs.n-nold; v = cgetg(n+1, t_VECSMALL); for(i=0; iname); } gel(res,1) = vecsmall_copy(w); gel(res,2) = V; return res; } /* e = t_VECSMALL of entree *ep [ addresses ], * names = t_VEC of strtoGENstr(ep.names), * Return hashtable : ep => is_entry(ep.name) */ hashtable * hash_from_link(GEN e, GEN names, int use_stack) { long i, l = lg(e); hashtable *h = hash_create_ulong(l-1, use_stack); if (lg(names) != l) pari_err_DIM("hash_from_link"); for (i = 1; i < l; i++) { char *s = GSTR(gel(names,i)); hash_insert(h, (void*)e[i], (void*)fetch_entry(s)); } return h; } void bincopy_relink(GEN C, GEN V) { pari_sp av = avma; hashtable *table = hash_from_link(gel(V,1),gel(V,2),1); gen_relink(C, table); avma = av; } pari-2.11.2/src/language/default.h0000644000175000017500000000434513457701106015337 0ustar billbill/* This file is autogenerated from the database. */ /* See src/desc/gen_proto */ /* Do not edit*/ entree functions_default[]={ {"TeXstyle",0,(void*)sd_TeXstyle,21,"",""}, {"breakloop",0,(void*)sd_breakloop,21,"",""}, {"colors",0,(void*)sd_colors,21,"",""}, {"compatible",0,(void*)sd_compatible,21,"",""}, {"datadir",0,(void*)sd_datadir,21,"",""}, {"debug",0,(void*)sd_debug,21,"",""}, {"debugfiles",0,(void*)sd_debugfiles,21,"",""}, {"debugmem",0,(void*)sd_debugmem,21,"",""}, {"echo",0,(void*)sd_echo,21,"",""}, {"factor_add_primes",0,(void*)sd_factor_add_primes,21,"",""}, {"factor_proven",0,(void*)sd_factor_proven,21,"",""}, {"format",0,(void*)sd_format,21,"",""}, {"graphcolormap",0,(void*)sd_graphcolormap,21,"",""}, {"graphcolors",0,(void*)sd_graphcolors,21,"",""}, {"help",0,(void*)sd_help,21,"",""}, {"histfile",0,(void*)sd_histfile,21,"",""}, {"histsize",0,(void*)sd_histsize,21,"",""}, {"lines",0,(void*)sd_lines,21,"",""}, {"linewrap",0,(void*)sd_linewrap,21,"",""}, {"log",0,(void*)sd_log,21,"",""}, {"logfile",0,(void*)sd_logfile,21,"",""}, {"nbthreads",0,(void*)sd_nbthreads,21,"",""}, {"new_galois_format",0,(void*)sd_new_galois_format,21,"",""}, {"output",0,(void*)sd_output,21,"",""}, {"parisize",0,(void*)sd_parisize,21,"",""}, {"parisizemax",0,(void*)sd_parisizemax,21,"",""}, {"path",0,(void*)sd_path,21,"",""}, {"plothsizes",0,(void*)sd_plothsizes,21,"",""}, {"prettyprinter",0,(void*)sd_prettyprinter,21,"",""}, {"primelimit",0,(void*)sd_primelimit,21,"",""}, {"prompt",0,(void*)sd_prompt,21,"",""}, {"prompt_cont",0,(void*)sd_prompt_cont,21,"",""}, {"psfile",0,(void*)sd_psfile,21,"",""}, {"readline",0,(void*)sd_readline,21,"",""}, {"realbitprecision",0,(void*)sd_realbitprecision,21,"",""}, {"realprecision",0,(void*)sd_realprecision,21,"",""}, {"recover",0,(void*)sd_recover,21,"",""}, {"secure",0,(void*)sd_secure,21,"",""}, {"seriesprecision",0,(void*)sd_seriesprecision,21,"",""}, {"simplify",0,(void*)sd_simplify,21,"",""}, {"sopath",0,(void*)sd_sopath,21,"",""}, {"strictargs",0,(void*)sd_strictargs,21,"",""}, {"strictmatch",0,(void*)sd_strictmatch,21,"",""}, {"threadsize",0,(void*)sd_threadsize,21,"",""}, {"threadsizemax",0,(void*)sd_threadsizemax,21,"",""}, {"timer",0,(void*)sd_timer,21,"",""}, {NULL,0,NULL,0,NULL,NULL} /* sentinel */ }; pari-2.11.2/src/language/parse.y0000644000175000017500000002076213201017466015043 0ustar billbill%{ /* Copyright (C) 2006 The PARI group. This file is part of the PARI package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define YYSIZE_T size_t #define YYSTYPE union token_value #define YYLTYPE struct node_loc #define YYLLOC_DEFAULT(Current, Rhs, N) \ ((Current).start = ((N)?(Rhs)[1].start:(Rhs)[0].end), \ (Current).end = (Rhs)[N].end) #include "parsec.h" #define NOARG(x) newnode(Fnoarg,-1,-1,&(x)) #define NORANGE(x) newnode(Fnorange,-1,-1,&(x)) %} %error-verbose %name-prefix "pari_" %pure-parser %parse-param {char **lex} %lex-param {char **lex} %initial-action{ @$.start=@$.end=*lex; } %token KPARROW ")->" %token KARROW "->" %token KDOTDOT ".." %token KPE "+=" %token KSE "-=" %token KME "*=" %token KDE "/=" %token KDRE "\\/=" %token KEUCE "\\=" %token KMODE "%=" %token KAND "&&" %token KOR "||" %token KID "===" %token KEQ "==" %token KNE "!=" %token KGE ">=" %token KLE "<=" %token KSRE ">>=" %token KSLE "<<=" %token KSR ">>" %token KSL "<<" %token KDR "\\/" %token KPP "++" %token KSS "--" %token KINTEGER "integer" %token KREAL "real number" %token KENTRY "variable name" %token KSTRING "character string" %left SEQ DEFFUNC %left INT LVAL %right ")->" "->" %left ';' ',' ".." %right '=' "+=" "-=" "*=" "/=" "\\/=" "\\=" "%=" ">>=" "<<=" %left '&' "&&" "||" %left "===" "==" "!=" '>' ">=" '<' "<=" %left '+' '-' %left '%' "\\/" '\\' '/' '*' ">>" "<<" %left SIGN %right '^' %left '#' %left '!' '~' '[' '\'' %left '.' %left "++" "--" %left '(' %left ':' %type seq sequence %type range matrix matrix_index expr %type lvalue %type matrixelts matrixlines arg listarg definition %type funcid memberid %type backticks history %type compr in inseq %destructor { pari_discarded++; } seq matrix range matrix_index expr lvalue matrixelts matrixlines arg listarg definition funcid memberid backticks history compr in inseq %% sequence: seq {$$=$1;} /* skip the destructor */ ; seq: /**/ %prec SEQ {$$=NOARG(@$);} | expr %prec SEQ {$$=$1;} | seq ';' {$$=$1; @$=@1;} | seq ';' expr {$$=newnode(Fseq,$1,$3,&@$);} ; range: /* */ { $$=newnode(Frange,NORANGE(@$),NORANGE(@$),&@$); } | expr { $$=newnode(Frange,$1,NORANGE(@$),&@$); } | expr ".." expr { $$=newnode(Frange,$1,$3,&@$); } | '^' expr { $$=newnode(Frange,NORANGE(@$),$2,&@$); } ; matrix_index: '[' range ',' range ']' {$$=newnode(Fmatrix,$2,$4,&@$);} | '[' range ']' {$$=newnode(Fmatrix,$2,-1,&@$);} ; backticks: '`' {$$=1;} | backticks '`' {$$=$1+1;} ; history: '%' {$$=newopcall(OPhist,-1,-1,&@$);} | '%' KINTEGER {$$=newopcall(OPhist,newintnode(&@2),-1,&@$);} | '%' backticks {$$=newopcall(OPhist,newnode(Fsmall,-$2,-1,&@$),-1,&@$);} | '%' '#' {$$=newopcall(OPhisttime,-1,-1,&@$);} | '%' '#' KINTEGER {$$=newopcall(OPhisttime,newintnode(&@3),-1,&@$);} | '%' '#' backticks{$$=newopcall(OPhisttime,newnode(Fsmall,-$3,-1,&@$),-1,&@$);} ; expr: KINTEGER %prec INT {$$=newintnode(&@1);} | KREAL {$$=newconst(CSTreal,&@$);} | '.' {$$=newconst(CSTreal,&@$);} | KINTEGER '.' KENTRY {$$=newnode(Ffunction,newconst(CSTmember,&@3), newintnode(&@1),&@$);} | KSTRING {$$=newconst(CSTstr,&@$);} | '\'' KENTRY {$$=newconst(CSTquote,&@$);} | history {$$=$1;} | expr '(' listarg ')' {$$=newnode(Fcall,$1,$3,&@$);} | funcid {$$=$1;} | lvalue %prec LVAL {$$=$1;} | matrix {$$=$1;} | compr {$$=$1;} | definition {$$=$1;} | matrix '=' expr {$$=newnode(Fassign,$1,$3,&@$);} | lvalue '=' expr {$$=newnode(Fassign,$1,$3,&@$);} | lvalue "++" {$$=newopcall(OPpp,$1,-1,&@$);} | lvalue "--" {$$=newopcall(OPss,$1,-1,&@$);} | lvalue "*=" expr {$$=newopcall(OPme,$1,$3,&@$);} | lvalue "/=" expr {$$=newopcall(OPde,$1,$3,&@$);} | lvalue "\\/=" expr {$$=newopcall(OPdre,$1,$3,&@$);} | lvalue "\\=" expr {$$=newopcall(OPeuce,$1,$3,&@$);} | lvalue "%=" expr {$$=newopcall(OPmode,$1,$3,&@$);} | lvalue "<<=" expr {$$=newopcall(OPsle,$1,$3,&@$);} | lvalue ">>=" expr {$$=newopcall(OPsre,$1,$3,&@$);} | lvalue "+=" expr {$$=newopcall(OPpe,$1,$3,&@$);} | lvalue "-=" expr {$$=newopcall(OPse,$1,$3,&@$);} | '!' expr {$$=newopcall(OPnb,$2,-1,&@$);} | '#' expr {$$=newopcall(OPlength,$2,-1,&@$);} | expr "||" expr {$$=newopcall(OPor,$1,$3,&@$);} | expr "&&" expr {$$=newopcall(OPand,$1,$3,&@$);} | expr '&' expr {$$=newopcall(OPand,$1,$3,&@$);} | expr "===" expr {$$=newopcall(OPid,$1,$3,&@$);} | expr "==" expr {$$=newopcall(OPeq,$1,$3,&@$);} | expr "!=" expr {$$=newopcall(OPne,$1,$3,&@$);} | expr ">=" expr {$$=newopcall(OPge,$1,$3,&@$);} | expr '>' expr {$$=newopcall(OPg,$1,$3,&@$);} | expr "<=" expr {$$=newopcall(OPle,$1,$3,&@$);} | expr '<' expr {$$=newopcall(OPl,$1,$3,&@$);} | expr '-' expr {$$=newopcall(OPs,$1,$3,&@$);} | expr '+' expr {$$=newopcall(OPp,$1,$3,&@$);} | expr "<<" expr {$$=newopcall(OPsl,$1,$3,&@$);} | expr ">>" expr {$$=newopcall(OPsr,$1,$3,&@$);} | expr '%' expr {$$=newopcall(OPmod,$1,$3,&@$);} | expr "\\/" expr {$$=newopcall(OPdr,$1,$3,&@$);} | expr '\\' expr {$$=newopcall(OPeuc,$1,$3,&@$);} | expr '/' expr {$$=newopcall(OPd,$1,$3,&@$);} | expr '*' expr {$$=newopcall(OPm,$1,$3,&@$);} | '+' expr %prec SIGN {$$=$2;} | '-' expr %prec SIGN {$$=newopcall(OPn,$2,-1,&@$);} | expr '^' expr {$$=newopcall(OPpow,$1,$3,&@$);} | expr '~' {$$=newopcall(OPtrans,$1,-1,&@$);} | expr '\'' {$$=newopcall(OPderiv,$1,-1,&@$);} | expr '!' {$$=newopcall(OPfact,$1,-1,&@$);} | expr matrix_index {$$=newnode(Fmatcoeff,$1,$2,&@$);} | memberid {$$=$1;} | expr ':' KENTRY {$$=newnode(Ftag,$1,0,&@$);} | '(' expr ')' {$$=$2;} ; lvalue: KENTRY %prec LVAL {$$=newnode(Fentry,newconst(CSTentry,&@1),-1,&@$);} | lvalue matrix_index {$$=newnode(Fmatcoeff,$1,$2,&@$);} | lvalue ':' KENTRY {$$=newnode(Ftag,$1,newconst(CSTentry,&@2),&@$);} ; matrixelts: expr {$$=$1;} | matrixelts ',' expr {$$=newnode(Fmatrixelts,$1,$3,&@$);} ; matrixlines: matrixelts ';' matrixelts {$$=newnode(Fmatrixlines,$1,$3,&@$);} | matrixlines ';' matrixelts {$$=newnode(Fmatrixlines,$1,$3,&@$);} ; matrix: '[' ']' {$$=newnode(Fvec,-1,-1,&@$);} | '[' expr ".." expr ']' {$$=newopcall(OPrange,$2,$4,&@$);} | '[' ';' ']' {$$=newnode(Fmat,-1,-1,&@$);} | '[' matrixelts ']' {$$=newnode(Fvec,$2,-1,&@$);} | '[' matrixlines ']' {$$=newnode(Fmat,$2,-1,&@$);} | '[' error ']' {$$=-1; YYABORT;} ; in: lvalue '<' '-' expr {$$=newnode(Flistarg,$4,$1,&@$);} ; inseq: in {$$=newopcall(OPcompr,$1,-2,&@$);} | in ',' expr {$$=newopcall3(OPcompr,$1,-2,$3,&@$);} | in ';' inseq {$$=newopcall(OPcomprc,$1,$3,&@$);} | in ',' expr ';' inseq {$$=newopcall3(OPcomprc,$1,$5,$3,&@$);} ; compr: '[' expr '|' inseq ']' {$$=addcurrexpr($4,$2,&@$);} ; arg: seq {$$=$1;} | lvalue '[' ".." ']' {$$=newnode(Fvararg,$1,-1,&@$);} | '&' lvalue {$$=newnode(Frefarg,$2,-1,&@$);} | arg error {if (!pari_once) { yyerrok; } pari_once=1;} expr {pari_once=0; $$=newopcall(OPcat,$1,$4,&@$);} ; listarg: arg {$$=$1;} | listarg ',' arg {$$=newnode(Flistarg,$1,$3,&@$);} ; funcid: KENTRY '(' listarg ')' {$$=newnode(Ffunction,newconst(CSTentry,&@1),$3,&@$);} ; memberid: expr '.' KENTRY {$$=newnode(Ffunction,newconst(CSTmember,&@3),$1,&@$);} ; definition: KENTRY '(' listarg ')' '=' seq %prec DEFFUNC {$$=newfunc(CSTentry,&@1,$3,$6,&@$);} | expr '.' KENTRY '=' seq %prec DEFFUNC {$$=newfunc(CSTmember,&@3,$1,$5,&@$);} | lvalue "->" seq {$$=newnode(Flambda, $1,$3,&@$);} | '(' listarg ")->" seq {$$=newnode(Flambda, $2,$4,&@$);} ; %% pari-2.11.2/src/language/pariinl.c0000644000175000017500000000125413036414402015331 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define PARI_NO_MPINL_H #define INLINE #ifndef DISABLE_INLINE # define DISABLE_INLINE #endif #include "pari.h" pari-2.11.2/src/language/compile.c0000644000175000017500000016243313457574370015354 0ustar billbill/* Copyright (C) 2006 The PARI group. This file is part of the PARI package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #include "anal.h" #include "tree.h" #include "opcode.h" #define tree pari_tree enum COflags {COsafelex=1, COsafedyn=2}; /*************************************************************************** ** ** ** String constant expansion ** ** ** ***************************************************************************/ static char * translate(const char **src, char *s) { const char *t = *src; while (*t) { while (*t == '\\') { switch(*++t) { case 'e': *s='\033'; break; /* escape */ case 'n': *s='\n'; break; case 't': *s='\t'; break; default: *s=*t; if (!*t) { *src=s; return NULL; } } t++; s++; } if (*t == '"') { if (t[1] != '"') break; t += 2; continue; } *s++ = *t++; } *s=0; *src=t; return s; } static void matchQ(const char *s, char *entry) { if (*s != '"') pari_err(e_SYNTAX,"expected character: '\"' instead of",s,entry); } /* Read a "string" from src. Format then copy it, starting at s. Return * pointer to char following the end of the input string */ char * pari_translate_string(const char *src, char *s, char *entry) { matchQ(src, entry); src++; s = translate(&src, s); if (!s) pari_err(e_SYNTAX,"run-away string",src,entry); matchQ(src, entry); return (char*)src+1; } static GEN strntoGENexp(const char *str, long len) { GEN z = cgetg(1+nchar2nlong(len-1), t_STR); const char *t = str+1; if (!translate(&t, GSTR(z))) compile_err("run-away string",str); return z; } /*************************************************************************** ** ** ** Byte-code compiler ** ** ** ***************************************************************************/ typedef enum {Llocal, Lmy} Ltype; struct vars_s { Ltype type; /*Only Llocal and Lmy are allowed */ int inl; entree *ep; }; struct frame_s { long pc; GEN frame; }; static THREAD pari_stack s_opcode, s_operand, s_data, s_lvar; static THREAD pari_stack s_dbginfo, s_frame; static THREAD char *opcode; static THREAD long *operand; static THREAD GEN *data; static THREAD long offset; static THREAD struct vars_s *localvars; static THREAD const char **dbginfo, *dbgstart; static THREAD struct frame_s *frames; void pari_init_compiler(void) { pari_stack_init(&s_opcode,sizeof(*opcode),(void **)&opcode); pari_stack_init(&s_operand,sizeof(*operand),(void **)&operand); pari_stack_init(&s_data,sizeof(*data),(void **)&data); pari_stack_init(&s_lvar,sizeof(*localvars),(void **)&localvars); pari_stack_init(&s_dbginfo,sizeof(*dbginfo),(void **)&dbginfo); pari_stack_init(&s_frame,sizeof(*frames),(void **)&frames); offset=-1; } void pari_close_compiler(void) { pari_stack_delete(&s_opcode); pari_stack_delete(&s_operand); pari_stack_delete(&s_data); pari_stack_delete(&s_lvar); pari_stack_delete(&s_dbginfo); pari_stack_delete(&s_frame); } struct codepos { long opcode, data, localvars, frames; long offset; const char *dbgstart; }; static void getcodepos(struct codepos *pos) { pos->opcode=s_opcode.n; pos->data=s_data.n; pos->offset=offset; pos->localvars=s_lvar.n; pos->dbgstart=dbgstart; pos->frames=s_frame.n; offset=s_data.n-1; } void compilestate_reset(void) { s_opcode.n=0; s_operand.n=0; s_dbginfo.n=0; s_data.n=0; s_lvar.n=0; s_frame.n=0; offset=-1; dbgstart=NULL; } void compilestate_save(struct pari_compilestate *comp) { comp->opcode=s_opcode.n; comp->operand=s_operand.n; comp->data=s_data.n; comp->offset=offset; comp->localvars=s_lvar.n; comp->dbgstart=dbgstart; comp->dbginfo=s_dbginfo.n; comp->frames=s_frame.n; } void compilestate_restore(struct pari_compilestate *comp) { s_opcode.n=comp->opcode; s_operand.n=comp->operand; s_data.n=comp->data; offset=comp->offset; s_lvar.n=comp->localvars; dbgstart=comp->dbgstart; s_dbginfo.n=comp->dbginfo; s_frame.n=comp->frames; } static GEN getfunction(const struct codepos *pos, long arity, long nbmvar, GEN text, long gap) { long lop =s_opcode.n+1-pos->opcode; long ldat=s_data.n+1-pos->data; long lfram=s_frame.n+1-pos->frames; GEN cl=cgetg(nbmvar?8:(text?7:6),t_CLOSURE); GEN frpc, fram, dbg; char *s; long i; cl[1] = arity; gel(cl,2) = cgetg(nchar2nlong(lop)+1, t_STR); gel(cl,3) = cgetg(lop, t_VECSMALL); gel(cl,4) = cgetg(ldat, t_VEC); dbg = cgetg(lop, t_VECSMALL); frpc = cgetg(lfram, t_VECSMALL); fram = cgetg(lfram, t_VEC); gel(cl,5) = mkvec3(dbg, frpc, fram); if (text) gel(cl,6) = text; if (nbmvar) gel(cl,7) = zerovec(nbmvar); s=GSTR(gel(cl,2))-1; for(i=1;iopcode-1]; mael(cl, 3, i) = operand[i+pos->opcode-1]; dbg[i] = dbginfo[i+pos->opcode-1]-dbgstart; if (dbg[i]<0) dbg[i]+=gap; } s[i]=0; s_opcode.n=pos->opcode; s_operand.n=pos->opcode; s_dbginfo.n=pos->opcode; for(i=1;idata-1]) { gmael(cl, 4, i) = gcopy(data[i+pos->data-1]); gunclone(data[i+pos->data-1]); } s_data.n=pos->data; while (s_lvar.n>pos->localvars && !localvars[s_lvar.n-1].inl) s_lvar.n--; for(i=1;iframes-1; frpc[i] = frames[j].pc-pos->opcode+1; gel(fram, i) = gcopy(frames[j].frame); gunclone(frames[j].frame); } s_frame.n=pos->frames; offset=pos->offset; dbgstart=pos->dbgstart; return cl; } static GEN getclosure(struct codepos *pos) { return getfunction(pos,0,0,NULL,0); } static void op_push_loc(op_code o, long x, const char *loc) { long n=pari_stack_new(&s_opcode); long m=pari_stack_new(&s_operand); long d=pari_stack_new(&s_dbginfo); opcode[n]=o; operand[m]=x; dbginfo[d]=loc; } static void op_push(op_code o, long x, long n) { op_push_loc(o,x,tree[n].str); } static void op_insert_loc(long k, op_code o, long x, const char *loc) { long i; long n=pari_stack_new(&s_opcode); (void) pari_stack_new(&s_operand); (void) pari_stack_new(&s_dbginfo); for (i=n-1; i>=k; i--) { opcode[i+1] = opcode[i]; operand[i+1]= operand[i]; dbginfo[i+1]= dbginfo[i]; } opcode[k] = o; operand[k] = x; dbginfo[k] = loc; } static long data_push(GEN x) { long n=pari_stack_new(&s_data); data[n] = x?gclone(x):x; return n-offset; } static void var_push(entree *ep, Ltype type) { long n=pari_stack_new(&s_lvar); localvars[n].ep = ep; localvars[n].inl = 0; localvars[n].type = type; } static void frame_push(GEN x) { long n=pari_stack_new(&s_frame); frames[n].pc = s_opcode.n-1; frames[n].frame = gclone(x); } static GEN pack_localvars(void) { GEN pack=cgetg(3,t_VEC); long i,l=s_lvar.n; GEN t=cgetg(1+l,t_VECSMALL); GEN e=cgetg(1+l,t_VECSMALL); gel(pack,1)=t; gel(pack,2)=e; for(i=1;i<=l;i++) { t[i]=localvars[i-1].type; e[i]=(long)localvars[i-1].ep; } return pack; } void push_frame(GEN C, long lpc, long dummy) { const char *code=closure_codestr(C); GEN oper=closure_get_oper(C); GEN dbg=closure_get_dbg(C); GEN frpc=gel(dbg,2); GEN fram=gel(dbg,3); long pc, j=1, lfr = lg(frpc); if (lpc==-1) { long k; GEN e = gel(fram, 1); for(k=1; k0 && (code[pc]==OClocalvar || code[pc]==OClocalvar0)) var_push((entree*)oper[pc],Llocal); if (jname:"NULL")); } } GEN localvars_read_str(const char *x, GEN pack) { GEN code; long l=0; if (pack) { GEN t=gel(pack,1); GEN e=gel(pack,2); long i; l=lg(t)-1; for(i=1;i<=l;i++) var_push((entree*)e[i],(Ltype)t[i]); } code = compile_str(x); s_lvar.n -= l; return closure_evalres(code); } long localvars_find(GEN pack, entree *ep) { GEN t=gel(pack,1); GEN e=gel(pack,2); long i; long vn=0; for(i=lg(e)-1;i>=1;i--) { if(t[i]==Lmy) vn--; if(e[i]==(long)ep) return t[i]==Lmy?vn:0; } return 0; } /* Flags for copy optimisation: -- Freturn: The result will be returned. -- FLsurvive: The result must survive the closure. -- FLnocopy: The result will never be updated nor part of a user variable. -- FLnocopylex: The result will never be updated nor part of dynamic variable. */ enum FLflag {FLreturn=1, FLsurvive=2, FLnocopy=4, FLnocopylex=8}; static void addcopy(long n, long mode, long flag, long mask) { if (mode==Ggen && !(flag&mask)) { op_push(OCcopy,0,n); if (!(flag&FLsurvive) && DEBUGLEVEL) pari_warn(warner,"compiler generates copy for `%.*s'", tree[n].len,tree[n].str); } } static void compilenode(long n, int mode, long flag); typedef enum {PPend,PPstd,PPdefault,PPdefaultmulti,PPstar,PPauto} PPproto; static PPproto parseproto(char const **q, char *c, const char *str) { char const *p=*q; long i; switch(*p) { case 0: case '\n': return PPend; case 'D': switch(p[1]) { case 0: compile_err("function has incomplete prototype",str); case 'G': case '&': case 'W': case 'V': case 'I': case 'E': case 'J': case 'n': case 'P': case 'r': case 's': *c=p[1]; *q=p+2; return PPdefault; default: for(i=0;*p && i<2;p++) i+=*p==','; if (i<2) compile_err("function has incomplete prototype",str); *c=p[-2]; *q=p; return PPdefaultmulti; } break; case 'C': case 'p': case 'b': case 'P': case 'f': *c=*p; *q=p+1; return PPauto; case '&': *c='*'; *q=p+1; return PPstd; case 'V': if (p[1]=='=') { if (p[2]!='G') compile_err("function prototype is not supported",str); *c='='; p+=2; } else *c=*p; *q=p+1; return PPstd; case 'E': case 's': if (p[1]=='*') { *c=*p++; *q=p+1; return PPstar; } /*fall through*/ } *c=*p; *q=p+1; return PPstd; } static long detag(long n) { while (tree[n].f==Ftag) n=tree[n].x; return n; } /* return type for GP functions */ static op_code get_ret_type(const char **p, long arity, Gtype *t, long *flag) { *flag = 0; if (**p == 'v') { (*p)++; *t=Gvoid; return OCcallvoid; } else if (**p == 'i') { (*p)++; *t=Gsmall; return OCcallint; } else if (**p == 'l') { (*p)++; *t=Gsmall; return OCcalllong; } else if (**p == 'u') { (*p)++; *t=Gusmall; return OCcalllong; } else if (**p == 'm') { (*p)++; *flag = FLnocopy; } *t=Ggen; return arity==2?OCcallgen2:OCcallgen; } /*supported types: * type: Gusmall, Gsmall, Ggen, Gvoid, Gvec, Gclosure * mode: Gusmall, Gsmall, Ggen, Gvar, Gvoid */ static void compilecast_loc(int type, int mode, const char *loc) { if (type==mode) return; switch (mode) { case Gusmall: if (type==Ggen) op_push_loc(OCitou,-1,loc); else if (type==Gvoid) op_push_loc(OCpushlong,0,loc); else if (type!=Gsmall) compile_err("this should be a small integer >=0",loc); break; case Gsmall: if (type==Ggen) op_push_loc(OCitos,-1,loc); else if (type==Gvoid) op_push_loc(OCpushlong,0,loc); else if (type!=Gusmall) compile_err("this should be a small integer",loc); break; case Ggen: if (type==Gsmall) op_push_loc(OCstoi,0,loc); else if (type==Gusmall)op_push_loc(OCutoi,0,loc); else if (type==Gvoid) op_push_loc(OCpushgnil,0,loc); break; case Gvoid: op_push_loc(OCpop, 1,loc); break; case Gvar: if (type==Ggen) op_push_loc(OCvarn,-1,loc); else compile_varerr(loc); break; default: pari_err_BUG("compilecast [unknown type]"); } } static void compilecast(long n, int type, int mode) { compilecast_loc(type, mode, tree[n].str); } static entree * fetch_member_raw(const char *s, long len) { pari_sp av = avma; char *t = stack_malloc(len+2); entree *ep; t[0] = '_'; strncpy(t+1, s, len); t[++len] = 0; /* prepend '_' */ ep = fetch_entry_raw(t, len); avma = av; return ep; } static entree * getfunc(long n) { long x=tree[n].x; if (tree[x].x==CSTmember) /* str-1 points to '.' */ return do_alias(fetch_member_raw(tree[x].str - 1, tree[x].len + 1)); else return do_alias(fetch_entry_raw(tree[x].str, tree[x].len)); } static entree * getentry(long n) { n = detag(n); if (tree[n].f!=Fentry) { if (tree[n].f==Fseq) compile_err("unexpected character: ';'", tree[tree[n].y].str-1); compile_varerr(tree[n].str); } return getfunc(n); } /* match Fentry that are not actually EpSTATIC functions called without parens*/ static entree * getvar(long n) { entree *ep = getentry(n); if (EpSTATIC(do_alias(ep))) compile_varerr(tree[n].str); return ep; } static long getmvar(entree *ep) { long i; long vn=0; for(i=s_lvar.n-1;i>=0;i--) { if(localvars[i].type==Lmy) vn--; if(localvars[i].ep==ep) return localvars[i].type==Lmy?vn:0; } return 0; } static long ctxmvar(void) { pari_sp av=avma; long i, n=0; GEN ctx; for(i=s_lvar.n-1;i>=0;i--) if(localvars[i].type==Lmy) n++; if (n==0) return 0; ctx = cgetg(n+1,t_VECSMALL); for(n=0, i=0; iname, s); } INLINE int is_node_zero(long n) { n = detag(n); return (tree[n].f==Fsmall && tree[n].x==0); } static void str_defproto(const char *p, const char *q, const char *loc) { long len = p-4-q; if (q[1]!='"' || q[len]!='"') compile_err("default argument must be a string",loc); op_push_loc(OCpushgen,data_push(strntoGENexp(q+1,len)),loc); } static long countlisttogen(long n, Ffunc f) { long x,i; if (n==-1 || tree[n].f==Fnoarg) return 0; for(x=n, i=0; tree[x].f==f ;x=tree[x].x, i++); return i+1; } static GEN listtogen(long n, Ffunc f) { long x,i,nb = countlisttogen(n, f); GEN z=cgetg(nb+1, t_VECSMALL); if (nb) { for (x=n, i = nb-1; i>0; z[i+1]=tree[x].y, x=tree[x].x, i--); z[1]=x; } return z; } static long first_safe_arg(GEN arg, long mask) { long lnc, l=lg(arg); for (lnc=l-1; lnc>0 && (tree[arg[lnc]].flags&mask)==mask; lnc--); return lnc; } static void checkdups(GEN arg, GEN vep) { long l=vecsmall_duplicate(vep); if (l!=0) compile_err("variable declared twice",tree[arg[l]].str); } enum {MAT_range,MAT_std,MAT_line,MAT_column,VEC_std}; static int matindex_type(long n) { long x = tree[n].x, y = tree[n].y; long fxx = tree[tree[x].x].f, fxy = tree[tree[x].y].f; if (y==-1) { if (fxy!=Fnorange) return MAT_range; if (fxx==Fnorange) compile_err("missing index",tree[n].str); return VEC_std; } else { long fyx = tree[tree[y].x].f, fyy = tree[tree[y].y].f; if (fxy!=Fnorange || fyy!=Fnorange) return MAT_range; if (fxx==Fnorange && fyx==Fnorange) compile_err("missing index",tree[n].str); if (fxx==Fnorange) return MAT_column; if (fyx==Fnorange) return MAT_line; return MAT_std; } } static entree * getlvalue(long n) { while ((tree[n].f==Fmatcoeff && matindex_type(tree[n].y)!=MAT_range) || tree[n].f==Ftag) n=tree[n].x; return getvar(n); } INLINE void compilestore(long vn, entree *ep, long n) { if (vn) op_push(OCstorelex,vn,n); else op_push(OCstoredyn,(long)ep,n); } INLINE void compilenewptr(long vn, entree *ep, long n) { if (vn) op_push(OCnewptrlex,vn,n); else op_push(OCnewptrdyn,(long)ep,n); } static void compilelvalue(long n) { n = detag(n); if (tree[n].f==Fentry) return; else { long x = tree[n].x, y = tree[n].y; long yx = tree[y].x, yy = tree[y].y; long m = matindex_type(y); if (m == MAT_range) compile_err("not an lvalue",tree[n].str); if (m == VEC_std && tree[x].f==Fmatcoeff) { int mx = matindex_type(tree[x].y); if (mx==MAT_line) { int xy = tree[x].y, xyx = tree[xy].x; compilelvalue(tree[x].x); compilenode(tree[xyx].x,Gsmall,0); compilenode(tree[yx].x,Gsmall,0); op_push(OCcompo2ptr,0,y); return; } } compilelvalue(x); switch(m) { case VEC_std: compilenode(tree[yx].x,Gsmall,0); op_push(OCcompo1ptr,0,y); break; case MAT_std: compilenode(tree[yx].x,Gsmall,0); compilenode(tree[yy].x,Gsmall,0); op_push(OCcompo2ptr,0,y); break; case MAT_line: compilenode(tree[yx].x,Gsmall,0); op_push(OCcompoLptr,0,y); break; case MAT_column: compilenode(tree[yy].x,Gsmall,0); op_push(OCcompoCptr,0,y); break; } } } static void compilematcoeff(long n, int mode) { long x=tree[n].x, y=tree[n].y; long yx=tree[y].x, yy=tree[y].y; long m=matindex_type(y); compilenode(x,Ggen,FLnocopy); switch(m) { case VEC_std: compilenode(tree[yx].x,Gsmall,0); op_push(OCcompo1,mode,y); return; case MAT_std: compilenode(tree[yx].x,Gsmall,0); compilenode(tree[yy].x,Gsmall,0); op_push(OCcompo2,mode,y); return; case MAT_line: compilenode(tree[yx].x,Gsmall,0); op_push(OCcompoL,0,y); compilecast(n,Gvec,mode); return; case MAT_column: compilenode(tree[yy].x,Gsmall,0); op_push(OCcompoC,0,y); compilecast(n,Gvec,mode); return; case MAT_range: compilenode(tree[yx].x,Gsmall,0); compilenode(tree[yx].y,Gsmall,0); if (yy==-1) op_push(OCcallgen,(long)is_entry("_[_.._]"),n); else { compilenode(tree[yy].x,Gsmall,0); compilenode(tree[yy].y,Gsmall,0); op_push(OCcallgen,(long)is_entry("_[_.._,_.._]"),n); } compilecast(n,Gvec,mode); return; default: pari_err_BUG("compilematcoeff"); } } static void compilesmall(long n, long x, long mode) { if (mode==Ggen) op_push(OCpushstoi, x, n); else { if (mode==Gusmall && x < 0) compile_err("this should be a small integer >=0",tree[n].str); op_push(OCpushlong, x, n); compilecast(n,Gsmall,mode); } } static void compilevec(long n, long mode, op_code op) { pari_sp ltop=avma; long x=tree[n].x; long i; GEN arg=listtogen(x,Fmatrixelts); long l=lg(arg); op_push(op,l,n); for (i=1;i0;i--) { long y=tree[x].y; x=tree[y].x; stack[i+1]=tree[y].y; } stack[1]=x; return stack; } static GEN compilelambda(long n, long y, GEN vep, struct codepos *pos) { long nbmvar, lev = vep ? lg(vep)-1 : 0; GEN text=cgetg(3,t_VEC); gel(text,1)=strtoGENstr(lev? ((entree*) vep[1])->name: ""); gel(text,2)=strntoGENstr(tree[y].str,tree[y].len); dbgstart = tree[y].str; nbmvar=ctxmvar()-lev; if (lev) op_push(OCgetargs,lev,n); compilenode(y,Ggen,FLsurvive|FLreturn); return getfunction(pos,lev,nbmvar,text,2); } static void compilecall(long n, int mode, entree *ep) { pari_sp ltop=avma; long j; long x=tree[n].x; long y=tree[n].y; GEN arg=listtogen(y,Flistarg); long nb=lg(arg)-1; long lnc=first_safe_arg(arg, COsafelex|COsafedyn); long lnl=first_safe_arg(arg, COsafelex); long fl = lnl==0? (lnc==0? FLnocopy: FLnocopylex): 0; if (ep==NULL) compilenode(x, Ggen, fl); else { long vn=getmvar(ep); if (vn) op_push(OCpushlex,vn,n); else op_push(OCpushdyn,(long)ep,n); } for (j=1;j<=nb;j++) { long x = tree[arg[j]].x, f = tree[arg[j]].f; if (f==Fseq) compile_err("unexpected ';'", tree[x].str+tree[x].len); else if (f!=Fnoarg) compilenode(arg[j], Ggen,j>=lnl?FLnocopylex:0); else op_push(OCpushlong,0,n); } op_push(OCcalluser,nb,x); compilecast(n,Ggen,mode); avma=ltop; } static GEN compilefuncinline(long n, long c, long a, long flag, long isif, long lev, long *ev) { struct codepos pos; int type=c=='I'?Gvoid:Ggen; long rflag=c=='I'?0:FLsurvive; GEN vep = NULL; if (isif && (flag&FLreturn)) rflag|=FLreturn; getcodepos(&pos); if (lev) { long i; GEN varg=cgetg(lev+1,t_VECSMALL); vep=cgetg(lev+1,t_VECSMALL); for(i=0;i=0) n += countlisttogen(tree[x].x,Fmatrixelts)-1; } } return n; } static void compileuninline(GEN arg) { long j; if (lg(arg) > 1) compile_err("too many arguments",tree[arg[1]].str); for(j=0; j=0) { GEN vars = listtogen(tree[x].x,Fmatrixelts); long nv = lg(vars)-1; for (j=1; j<=nv; j++) { ver[++k] = vars[j]; vep[k] = (long)getvar(ver[k]); } continue; } else ver[++k] = x; } else ver[++k] = a; vep[k] = (long)getvar(ver[k]); } checkdups(ver,vep); for(i=1; i<=n; i++) var_push(NULL,Lmy); op_push_loc(OCnewframe,inl?-n:n,str); frame_push(vep); for (k=0, i=1; i=0) { GEN vars = listtogen(tree[x].x,Fmatrixelts); long nv = lg(vars)-1; compilenode(tree[a].y,Ggen,FLnocopy); if (nv > 1) op_push(OCdup,nv-1,x); for (j=1; j<=nv; j++) { long v = detag(vars[j]); op_push(OCpushlong,j,v); op_push(OCcompo1,Ggen,v); k++; op_push(OCstorelex,-n+k-1,a); localvars[s_lvar.n-n+k-1].ep=(entree*)vep[k]; localvars[s_lvar.n-n+k-1].inl=inl; } continue; } else if (!is_node_zero(tree[a].y)) { compilenode(tree[a].y,Ggen,FLnocopy); op_push(OCstorelex,-n+k,a); } } k++; localvars[s_lvar.n-n+k-1].ep=(entree*)vep[k]; localvars[s_lvar.n-n+k-1].inl=inl; } } static long localpush(op_code op, long a) { entree *ep = getvar(a); long vep = (long) ep; op_push(op,vep,a); var_push(ep,Llocal); return vep; } static void compilelocal(GEN arg) { long i, j, k, l = lg(arg); long n = countvar(arg); GEN vep = cgetg(n+1,t_VECSMALL); GEN ver = cgetg(n+1,t_VECSMALL); for(k=0, i=1; i=0) { GEN vars = listtogen(tree[x].x,Fmatrixelts); long nv = lg(vars)-1; compilenode(tree[a].y,Ggen,FLnocopy); if (nv > 1) op_push(OCdup,nv-1,x); for (j=1; j<=nv; j++) { long v = detag(vars[j]); op_push(OCpushlong,j,v); op_push(OCcompo1,Ggen,v); vep[++k] = localpush(OClocalvar, v); ver[k] = v; } continue; } else if (!is_node_zero(tree[a].y)) { compilenode(tree[a].y,Ggen,FLnocopy); ver[++k] = x; vep[k] = localpush(OClocalvar, ver[k]); continue; } else ver[++k] = x; } else ver[++k] = a; vep[k] = localpush(OClocalvar0, ver[k]); } checkdups(ver,vep); } static void compilefunc(entree *ep, long n, int mode, long flag) { pari_sp ltop=avma; long j; long x=tree[n].x, y=tree[n].y; op_code ret_op; long ret_flag; Gtype ret_typ; char const *p,*q; char c; const char *flags = NULL; const char *str; PPproto mod; GEN arg=listtogen(y,Flistarg); long lnc=first_safe_arg(arg, COsafelex|COsafedyn); long lnl=first_safe_arg(arg, COsafelex); long nbpointers=0, nbopcodes; long nb=lg(arg)-1, lev=0; long ev[20]; if (x>=OPnboperator) str=tree[x].str; else { if (nb==2) str=tree[arg[1]].str+tree[arg[1]].len; else if (nb==1) str=tree[arg[1]].str; else str=tree[n].str; while(*str==')') str++; } if (tree[n].f==Fassign) { nb=2; lnc=2; lnl=2; arg=mkvecsmall2(x,y); } else if (is_func_named(ep,"if")) { if (nb>=4) ep=is_entry("_multi_if"); else if (mode==Gvoid) ep=is_entry("_void_if"); } else if (is_func_named(ep,"return") && (flag&FLreturn) && nb<=1) { if (nb==0) op_push(OCpushgnil,0,n); else compilenode(arg[1],Ggen,FLsurvive|FLreturn); avma=ltop; return; } else if (is_func_named(ep,"inline")) { compilemy(arg, str, 1); compilecast(n,Gvoid,mode); avma=ltop; return; } else if (is_func_named(ep,"uninline")) { compileuninline(arg); compilecast(n,Gvoid,mode); avma=ltop; return; } else if (is_func_named(ep,"my")) { compilemy(arg, str, 0); compilecast(n,Gvoid,mode); avma=ltop; return; } else if (is_func_named(ep,"local")) { compilelocal(arg); compilecast(n,Gvoid,mode); avma=ltop; return; } /*We generate dummy code for global() for compatibility with gp2c*/ else if (is_func_named(ep,"global")) { long i; for (i=1;i<=nb;i++) { long a=arg[i]; long en; if (tree[a].f==Fassign) { compilenode(tree[a].y,Ggen,0); a=tree[a].x; en=(long)getvar(a); op_push(OCstoredyn,en,a); } else { en=(long)getvar(a); op_push(OCpushdyn,en,a); op_push(OCpop,1,a); } } compilecast(n,Gvoid,mode); avma=ltop; return; } else if (is_func_named(ep,"O")) { if (nb!=1) compile_err("wrong number of arguments", tree[n].str+tree[n].len-1); ep=is_entry("O(_^_)"); if (tree[arg[1]].f==Ffunction && tree[arg[1]].x==OPpow) { arg = listtogen(tree[arg[1]].y,Flistarg); nb = lg(arg)-1; lnc = first_safe_arg(arg,COsafelex|COsafedyn); lnl = first_safe_arg(arg,COsafelex); } } else if (x==OPn && tree[y].f==Fsmall) { avma=ltop; compilesmall(y, -tree[y].x, mode); return; } else if (x==OPtrans && tree[y].f==Fvec) { avma=ltop; compilevec(y, mode, OCcol); return; } else if (x==OPpow && nb==2 && tree[arg[2]].f==Fsmall) ep=is_entry("_^s"); else if (x==OPcat) compile_err("expected character: ',' or ')' instead of", tree[arg[1]].str+tree[arg[1]].len); p=ep->code; if (!ep->value) compile_err("unknown function",tree[n].str); nbopcodes = s_opcode.n; ret_op = get_ret_type(&p, ep->arity, &ret_typ, &ret_flag); j=1; if (*p) { q=p; while((mod=parseproto(&p,&c,tree[n].str))!=PPend) { if (j<=nb && tree[arg[j]].f!=Fnoarg && (mod==PPdefault || mod==PPdefaultmulti)) mod=PPstd; switch(mod) { case PPstd: if (j>nb) compile_err("too few arguments", tree[n].str+tree[n].len-1); if (c!='I' && c!='E' && c!='J') { long x = tree[arg[j]].x, f = tree[arg[j]].f; if (f==Fnoarg) compile_err("missing mandatory argument", tree[arg[j]].str); if (f==Fseq) compile_err("unexpected ';'", tree[x].str+tree[x].len); } switch(c) { case 'G': compilenode(arg[j],Ggen,j>=lnl?(j>=lnc?FLnocopy:FLnocopylex):0); j++; break; case 'W': { long a = arg[j]; entree *ep = getlvalue(a); long vn = getmvar(ep); if (vn) op_push(OCcowvarlex, vn, a); else op_push(OCcowvardyn, (long)ep, a); compilenode(arg[j++],Ggen,FLnocopy); break; } case 'M': if (tree[arg[j]].f!=Fsmall) { if (!flags) flags = ep->code; flags = strchr(flags, '\n'); /* Skip to the following '\n' */ if (!flags) compile_err("missing flag in string function signature", tree[n].str); flags++; if (tree[arg[j]].f==Fconst && tree[arg[j]].x==CSTstr) { GEN str=strntoGENexp(tree[arg[j]].str,tree[arg[j]].len); op_push(OCpushlong, eval_mnemonic(str, flags),n); j++; } else { compilenode(arg[j++],Ggen,0); op_push(OCpushlong,(long)flags,n); op_push(OCcallgen2,(long)is_entry("_eval_mnemonic"),n); } break; } case 'P': case 'L': compilenode(arg[j++],Gsmall,0); break; case 'U': compilenode(arg[j++],Gusmall,0); break; case 'n': compilenode(arg[j++],Gvar,0); break; case '&': case '*': { long vn, a=arg[j++]; entree *ep; if (c=='&') { if (tree[a].f!=Frefarg) compile_err("expected character: '&'", tree[a].str); a=tree[a].x; } a=detag(a); ep=getlvalue(a); vn=getmvar(ep); if (tree[a].f==Fentry) { if (vn) op_push(OCsimpleptrlex, vn,n); else op_push(OCsimpleptrdyn, (long)ep,n); } else { compilenewptr(vn, ep, a); compilelvalue(a); op_push(OCpushptr, 0, a); } nbpointers++; break; } case 'I': case 'E': case 'J': { long a = arg[j++]; GEN d = compilefuncinline(n, c, a, flag, is_func_named(ep,"if"), lev, ev); op_push(OCpushgen, data_push(d), a); if (lg(d)==8) op_push(OCsaveframe,FLsurvive,n); break; } case 'V': { long a = arg[j++]; (void)getvar(a); ev[lev++] = a; break; } case '=': { long a = arg[j++]; ev[lev++] = tree[a].x; compilenode(tree[a].y, Ggen, FLnocopy); } break; case 'r': { long a=arg[j++]; if (tree[a].f==Fentry) { op_push(OCpushgen, data_push(strntoGENstr(tree[tree[a].x].str, tree[tree[a].x].len)),n); op_push(OCtostr, -1,n); } else { compilenode(a,Ggen,FLnocopy); op_push(OCtostr, -1,n); } break; } case 's': { long a = arg[j++]; GEN g = cattovec(a, OPcat); long l, nb = lg(g)-1; if (nb==1) { compilenode(g[1], Ggen, FLnocopy); op_push(OCtostr, -1, a); } else { op_push(OCvec, nb+1, a); for(l=1; l<=nb; l++) { compilenode(g[l], Ggen, FLsurvive); op_push(OCstackgen,l, a); } op_push(OCpop, 1, a); op_push(OCcallgen,(long)is_entry("Str"), a); op_push(OCtostr, -1, a); } break; } default: pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c, tree[x].len, tree[x].str); } break; case PPauto: switch(c) { case 'p': op_push(OCprecreal,0,n); break; case 'b': op_push(OCbitprecreal,0,n); break; case 'P': op_push(OCprecdl,0,n); break; case 'C': op_push(OCpushgen,data_push(pack_localvars()),n); break; case 'f': { static long foo; op_push(OCpushlong,(long)&foo,n); break; } } break; case PPdefault: j++; switch(c) { case 'G': case '&': case 'E': case 'I': case 'r': case 's': op_push(OCpushlong,0,n); break; case 'n': op_push(OCpushlong,-1,n); break; case 'V': ev[lev++] = -1; break; case 'P': op_push(OCprecdl,0,n); break; default: pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c, tree[x].len, tree[x].str); } break; case PPdefaultmulti: j++; switch(c) { case 'G': op_push(OCpushstoi,strtol(q+1,NULL,10),n); break; case 'L': case 'M': op_push(OCpushlong,strtol(q+1,NULL,10),n); break; case 'U': op_push(OCpushlong,(long)strtoul(q+1,NULL,10),n); break; case 'r': case 's': str_defproto(p, q, tree[n].str); op_push(OCtostr, -1, n); break; default: pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c, tree[x].len, tree[x].str); } break; case PPstar: switch(c) { case 'E': { long k, n=nb+1-j; GEN g=cgetg(n+1,t_VEC); int ismif = is_func_named(ep,"_multi_if"); for(k=1; k<=n; k++) gel(g, k) = compilefuncinline(n, c, arg[j+k-1], flag, ismif && (k==n || odd(k)), lev, ev); op_push(OCpushgen, data_push(g), arg[j]); j=nb+1; break; } case 's': { long n=nb+1-j; long k,l,l1,m; GEN g=cgetg(n+1,t_VEC); for(l1=0,k=1;k<=n;k++) { gel(g,k)=cattovec(arg[j+k-1],OPcat); l1+=lg(gel(g,k))-1; } op_push_loc(OCvec, l1+1, str); for(m=1,k=1;k<=n;k++) for(l=1;lnbopcodes+128) { op_insert_loc(nbopcodes,OCavma,0,str); op_push_loc(OCgerepile,0,str); } compilecast(n,ret_typ,mode); if (nbpointers) op_push_loc(OCendptr,nbpointers, str); avma=ltop; } static void genclosurectx(const char *loc, long nbdata) { long i; GEN vep = cgetg(nbdata+1,t_VECSMALL); for(i = 1; i <= nbdata; i++) { vep[i] = 0; op_push_loc(OCpushlex,-i,loc); } frame_push(vep); } static GEN genclosure(entree *ep, const char *loc, long nbdata, int check) { pari_sp av = avma; struct codepos pos; long nb=0; const char *code=ep->code,*p,*q; char c; GEN text; long index=ep->arity; long arity=0, maskarg=0, maskarg0=0, stop=0, dovararg=0; PPproto mod; Gtype ret_typ; long ret_flag; op_code ret_op=get_ret_type(&code,ep->arity,&ret_typ,&ret_flag); p=code; while ((mod=parseproto(&p,&c,NULL))!=PPend) { if (mod==PPauto) stop=1; else { if (stop) return NULL; if (c=='V') continue; maskarg<<=1; maskarg0<<=1; arity++; switch(mod) { case PPstd: maskarg|=1L; break; case PPdefault: switch(c) { case '&': case 'E': case 'I': maskarg0|=1L; break; } break; default: break; } } } if (check && EpSTATIC(ep) && maskarg==0) return gen_0; getcodepos(&pos); dbgstart = loc; if (nbdata > arity) pari_err(e_MISC,"too many parameters for closure `%s'", ep->name); if (nbdata) genclosurectx(loc, nbdata); text = strtoGENstr(ep->name); arity -= nbdata; if (maskarg) op_push_loc(OCcheckargs,maskarg,loc); if (maskarg0) op_push_loc(OCcheckargs0,maskarg0,loc); p=code; while ((mod=parseproto(&p,&c,NULL))!=PPend) { switch(mod) { case PPauto: switch(c) { case 'p': op_push_loc(OCprecreal,0,loc); break; case 'b': op_push_loc(OCbitprecreal,0,loc); break; case 'P': op_push_loc(OCprecdl,0,loc); break; case 'C': op_push_loc(OCpushgen,data_push(pack_localvars()),loc); break; case 'f': { static long foo; op_push_loc(OCpushlong,(long)&foo,loc); break; } } default: break; } } q = p = code; while ((mod=parseproto(&p,&c,NULL))!=PPend) { switch(mod) { case PPstd: switch(c) { case 'G': break; case 'M': case 'L': op_push_loc(OCitos,-index,loc); break; case 'U': op_push_loc(OCitou,-index,loc); break; case 'n': op_push_loc(OCvarn,-index,loc); break; case '&': case '*': case 'I': case 'E': case 'V': case '=': return NULL; case 'r': case 's': op_push_loc(OCtostr,-index,loc); break; } break; case PPauto: break; case PPdefault: switch(c) { case 'G': case '&': case 'E': case 'I': case 'V': case 'r': case 's': break; case 'n': op_push_loc(OCvarn,-index,loc); break; case 'P': op_push_loc(OCprecdl,0,loc); op_push_loc(OCdefaultlong,-index,loc); break; default: pari_err(e_MISC,"Unknown prototype code `D%c' for `%s'",c,ep->name); } break; case PPdefaultmulti: switch(c) { case 'G': op_push_loc(OCpushstoi,strtol(q+1,NULL,10),loc); op_push_loc(OCdefaultgen,-index,loc); break; case 'L': case 'M': op_push_loc(OCpushlong,strtol(q+1,NULL,10),loc); op_push_loc(OCdefaultlong,-index,loc); break; case 'U': op_push_loc(OCpushlong,(long)strtoul(q+1,NULL,10),loc); op_push_loc(OCdefaultulong,-index,loc); break; case 'r': case 's': str_defproto(p, q, loc); op_push_loc(OCdefaultgen,-index,loc); op_push_loc(OCtostr,-index,loc); break; default: pari_err(e_MISC, "Unknown prototype code `D...,%c,' for `%s'",c,ep->name); } break; case PPstar: switch(c) { case 's': dovararg = 1; break; case 'E': return NULL; default: pari_err(e_MISC,"Unknown prototype code `%c*' for `%s'",c,ep->name); } break; default: return NULL; } index--; q = p; } op_push_loc(ret_op, (long) ep, loc); if (ret_flag==FLnocopy) op_push_loc(OCcopy,0,loc); compilecast_loc(ret_typ, Ggen, loc); if (dovararg) nb|=VARARGBITS; return gerepilecopy(av, getfunction(&pos,nb+arity,nbdata,text,0)); } GEN snm_closure(entree *ep, GEN data) { long i; long n = data ? lg(data)-1: 0; GEN C = genclosure(ep,ep->name,n,0); for(i=1; i<=n; i++) gmael(C,7,i) = gel(data,i); return C; } GEN strtoclosure(const char *s, long n, ...) { pari_sp av = avma; entree *ep = is_entry(s); GEN C; if (!ep) pari_err(e_NOTFUNC, strtoGENstr(s)); ep = do_alias(ep); if ((!EpSTATIC(ep) && EpVALENCE(ep)!=EpINSTALL) || !ep->value) pari_err(e_MISC,"not a built-in/install'ed function: \"%s\"",s); C = genclosure(ep,ep->name,n,0); if (!C) pari_err(e_MISC,"function prototype unsupported: \"%s\"",s); else { va_list ap; long i; va_start(ap,n); for(i=1; i<=n; i++) gmael(C,7,i) = va_arg(ap, GEN); va_end(ap); } return gerepilecopy(av, C); } GEN strtofunction(const char *s) { return strtoclosure(s, 0); } GEN call0(GEN fun, GEN args) { if (!is_vec_t(typ(args))) pari_err_TYPE("call",args); switch(typ(fun)) { case t_STR: fun = strtofunction(GSTR(fun)); case t_CLOSURE: /* fall through */ return closure_callgenvec(fun, args); default: pari_err_TYPE("call", fun); return NULL; /* LCOV_EXCL_LINE */ } } static void closurefunc(entree *ep, long n, long mode) { pari_sp ltop=avma; GEN C; if (!ep->value) compile_err("unknown function",tree[n].str); C = genclosure(ep,tree[n].str,0,1); if (!C) compile_err("sorry, closure not implemented",tree[n].str); if (C==gen_0) { compilefunc(ep,n,mode,0); return; } op_push(OCpushgen, data_push(C), n); compilecast(n,Gclosure,mode); avma=ltop; } static void compileseq(long n, int mode, long flag) { pari_sp av = avma; GEN L = listtogen(n, Fseq); long i, l = lg(L)-1; for(i = 1; i < l; i++) compilenode(L[i],Gvoid,0); compilenode(L[l],mode,flag&(FLreturn|FLsurvive)); avma = av; } static void compilenode(long n, int mode, long flag) { long x,y; #ifdef STACK_CHECK if (PARI_stack_limit && (void*) &x <= PARI_stack_limit) pari_err(e_MISC, "expression nested too deeply"); #endif if (n<0) pari_err_BUG("compilenode"); x=tree[n].x; y=tree[n].y; switch(tree[n].f) { case Fseq: compileseq(n, mode, flag); return; case Fmatcoeff: compilematcoeff(n,mode); if (mode==Ggen && !(flag&FLnocopy)) op_push(OCcopy,0,n); return; case Fassign: x = detag(x); if (tree[x].f==Fvec && tree[x].x>=0) { GEN vars = listtogen(tree[x].x,Fmatrixelts); long i, l = lg(vars)-1, d = mode==Gvoid? l-1: l; compilenode(y,Ggen,mode==Gvoid?0:flag&FLsurvive); if (d) op_push(OCdup, d, x); for(i=1; i<=l; i++) { long a = detag(vars[i]); entree *ep=getlvalue(a); long vn=getmvar(ep); op_push(OCpushlong,i,a); op_push(OCcompo1,Ggen,a); if (tree[a].f==Fentry) compilestore(vn,ep,n); else { compilenewptr(vn,ep,n); compilelvalue(a); op_push(OCstoreptr,0,a); } } if (mode!=Gvoid) compilecast(n,Ggen,mode); } else { entree *ep=getlvalue(x); long vn=getmvar(ep); if (tree[x].f!=Fentry) { compilenewptr(vn,ep,n); compilelvalue(x); } compilenode(y,Ggen,mode==Gvoid?FLnocopy:flag&FLsurvive); if (mode!=Gvoid) op_push(OCdup,1,n); if (tree[x].f==Fentry) compilestore(vn,ep,n); else op_push(OCstoreptr,0,x); if (mode!=Gvoid) compilecast(n,Ggen,mode); } return; case Fconst: { pari_sp ltop=avma; if (tree[n].x!=CSTquote) { if (mode==Gvoid) return; if (mode==Gvar) compile_varerr(tree[n].str); } if (mode==Gsmall) compile_err("this should be a small integer", tree[n].str); switch(tree[n].x) { case CSTreal: op_push(OCpushreal, data_push(strntoGENstr(tree[n].str,tree[n].len)),n); break; case CSTint: op_push(OCpushgen, data_push(strtoi((char*)tree[n].str)),n); compilecast(n,Ggen, mode); break; case CSTstr: op_push(OCpushgen, data_push(strntoGENexp(tree[n].str,tree[n].len)),n); break; case CSTquote: { /* skip ' */ entree *ep = fetch_entry_raw(tree[n].str+1,tree[n].len-1); if (EpSTATIC(ep)) compile_varerr(tree[n].str+1); op_push(OCpushvar, (long)ep,n); compilecast(n,Ggen, mode); break; } default: pari_err_BUG("compilenode, unsupported constant"); } avma=ltop; return; } case Fsmall: compilesmall(n, x, mode); return; case Fvec: compilevec(n, mode, OCvec); return; case Fmat: compilemat(n, mode); return; case Frefarg: compile_err("unexpected character '&':",tree[n].str); return; case Fentry: { entree *ep=getentry(n); long vn=getmvar(ep); if (vn) { op_push(OCpushlex,(long)vn,n); addcopy(n,mode,flag,FLnocopy|FLnocopylex); compilecast(n,Ggen,mode); } else if (ep->valence==EpVAR || ep->valence==EpNEW) { if (DEBUGLEVEL && mode==Gvoid) pari_warn(warner,"statement with no effect: `%s'",ep->name); op_push(OCpushdyn,(long)ep,n); addcopy(n,mode,flag,FLnocopy); compilecast(n,Ggen,mode); } else closurefunc(ep,n,mode); return; } case Ffunction: { entree *ep=getfunc(n); if (EpVALENCE(ep)==EpVAR || EpVALENCE(ep)==EpNEW) { if (tree[n].xstrictargs; GEN vep = cgetg_copy(arg, &lgarg); GEN text=cgetg(3,t_VEC); gel(text,1)=strntoGENstr(tree[x].str,tree[x].len); gel(text,2)=strntoGENstr(tree[y].str,tree[y].len); getcodepos(&pos); dbgstart=tree[x].str+tree[x].len; gap = tree[y].str-dbgstart; nbmvar=ctxmvar(); nb = lgarg-1; if (nb) { long i; for(i=1;i<=nb;i++) { long a=arg[i]; if (i==nb && tree[a].f==Fvararg) { dovararg=1; vep[i]=(long)getvar(tree[a].x); } else vep[i]=(long)getvar(tree[a].f==Fassign?tree[a].x:a); var_push(NULL,Lmy); } checkdups(arg,vep); op_push(OCgetargs,nb,x); frame_push(vep); for (i=1;i<=nb;i++) { long a=arg[i]; long y = tree[a].y; if (tree[a].f==Fassign && (strict || !is_node_zero(y))) { if (tree[y].f==Fsmall) compilenode(y, Ggen, 0); else { struct codepos lpos; getcodepos(&lpos); compilenode(y, Ggen, 0); op_push(OCpushgen, data_push(getclosure(&lpos)),a); } op_push(OCdefaultarg,-nb+i-1,a); } localvars[s_lvar.n-nb+i-1].ep=(entree*)vep[i]; } } if (strict) op_push(OCcheckuserargs,nb,x); dbgstart=tree[y].str; if (y>=0 && tree[y].f!=Fnoarg) compilenode(y,Ggen,FLsurvive|FLreturn); else compilecast(n,Gvoid,Ggen); if (dovararg) nb|=VARARGBITS; op_push(OCpushgen, data_push(getfunction(&pos,nb,nbmvar,text,gap)),n); if (nbmvar) op_push(OCsaveframe,!!(flag&FLsurvive),n); compilecast(n, Gclosure, mode); avma=ltop; return; } case Ftag: compilenode(x, mode,flag); return; case Fnoarg: compilecast(n,Gvoid,mode); return; case Fnorange: op_push(OCpushlong,LONG_MAX,n); compilecast(n,Gsmall,mode); return; default: pari_err_BUG("compilenode"); } } GEN gp_closure(long n) { struct codepos pos; getcodepos(&pos); dbgstart=tree[n].str; compilenode(n,Ggen,FLsurvive|FLreturn); return getfunction(&pos,0,0,strntoGENstr(tree[n].str,tree[n].len),0); } GEN closure_deriv(GEN G) { pari_sp ltop=avma; long i; struct codepos pos; const char *code; GEN text; long arity=closure_arity(G); if (arity==0 || closure_is_variadic(G)) pari_err_TYPE("derivfun",G); if (typ(gel(G,6))==t_STR) { code = GSTR(gel(G,6)); text = cgetg(1+nchar2nlong(2+strlen(code)),t_STR); sprintf(GSTR(text),"%s'",code); } else { code = GSTR(GENtoGENstr(G)); text = cgetg(1+nchar2nlong(4+strlen(code)),t_STR); sprintf(GSTR(text),"(%s)'",code); } getcodepos(&pos); dbgstart=code; op_push_loc(OCgetargs, arity,code); op_push_loc(OCpushgen,data_push(G),code); op_push_loc(OCvec,arity+1,code); for (i=1;i<=arity;i++) { op_push_loc(OCpushlex,i-arity-1,code); op_push_loc(OCstackgen,i,code); } op_push_loc(OCpop,1,code); op_push_loc(OCprecreal,0,code); op_push_loc(OCcallgen,(long)is_entry("_derivfun"),code); return gerepilecopy(ltop, getfunction(&pos,arity,0,text,0)); } static long vec_optimize(GEN arg) { long fl = COsafelex|COsafedyn; long i; for (i=1; i=0) { optimizenode(yy); fl&=tree[yy].flags; } tree[n].flags=fl; } static void optimizefunc(entree *ep, long n) { pari_sp av=avma; long j; long x=tree[n].x; long y=tree[n].y; Gtype t; PPproto mod; long fl=COsafelex|COsafedyn; const char *p; char c; GEN arg = listtogen(y,Flistarg); long nb=lg(arg)-1, ret_flag; if (is_func_named(ep,"if") && nb>=4) ep=is_entry("_multi_if"); p = ep->code; if (!p) fl=0; else (void) get_ret_type(&p, 2, &t, &ret_flag); if (p && *p) { j=1; while((mod=parseproto(&p,&c,tree[n].str))!=PPend) { if (j<=nb && tree[arg[j]].f!=Fnoarg && (mod==PPdefault || mod==PPdefaultmulti)) mod=PPstd; switch(mod) { case PPstd: if (j>nb) compile_err("too few arguments", tree[n].str+tree[n].len-1); if (tree[arg[j]].f==Fnoarg && c!='I' && c!='E') compile_err("missing mandatory argument", tree[arg[j]].str); switch(c) { case 'G': case 'n': case 'M': case 'L': case 'U': case 'P': optimizenode(arg[j]); fl&=tree[arg[j++]].flags; break; case 'I': case 'E': case 'J': optimizenode(arg[j]); fl&=tree[arg[j]].flags; tree[arg[j++]].flags=COsafelex|COsafedyn; break; case '&': case '*': { long a=arg[j]; if (c=='&') { if (tree[a].f!=Frefarg) compile_err("expected character: '&'", tree[a].str); a=tree[a].x; } optimizenode(a); tree[arg[j++]].flags=COsafelex|COsafedyn; fl=0; break; } case 'W': optimizenode(arg[j++]); fl=0; break; case 'V': case 'r': tree[arg[j++]].flags=COsafelex|COsafedyn; break; case '=': { long a=arg[j++], y=tree[a].y; if (tree[a].f!=Fassign) compile_err("expected character: '=' instead of", tree[a].str+tree[a].len); optimizenode(y); fl&=tree[y].flags; } break; case 's': fl &= vec_optimize(cattovec(arg[j++], OPcat)); break; default: pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c, tree[x].len, tree[x].str); } break; case PPauto: break; case PPdefault: case PPdefaultmulti: if (j<=nb) optimizenode(arg[j++]); break; case PPstar: switch(c) { case 'E': { long n=nb+1-j; long k; for(k=1;k<=n;k++) { optimizenode(arg[j+k-1]); fl &= tree[arg[j+k-1]].flags; } j=nb+1; break; } case 's': { long n=nb+1-j; long k; for(k=1;k<=n;k++) fl &= vec_optimize(cattovec(arg[j+k-1],OPcat)); j=nb+1; break; } default: pari_err(e_MISC,"Unknown prototype code `%c*' for `%.*s'",c, tree[x].len, tree[x].str); } break; default: pari_err_BUG("optimizefun [unknown PPproto]"); } } if (j<=nb) compile_err("too many arguments",tree[arg[j]].str); } else (void)vec_optimize(arg); avma=av; tree[n].flags=fl; } static void optimizecall(long n) { pari_sp av=avma; long x=tree[n].x; long y=tree[n].y; GEN arg=listtogen(y,Flistarg); optimizenode(x); tree[n].flags = COsafelex&tree[x].flags&vec_optimize(arg); avma=av; } static void optimizeseq(long n) { pari_sp av = avma; GEN L = listtogen(n, Fseq); long i, l = lg(L)-1, flags=-1L; for(i = 1; i <= l; i++) { optimizenode(L[i]); flags &= tree[L[i]].flags; } avma = av; tree[n].flags = flags; } void optimizenode(long n) { long x,y; #ifdef STACK_CHECK if (PARI_stack_limit && (void*) &x <= PARI_stack_limit) pari_err(e_MISC, "expression nested too deeply"); #endif if (n<0) pari_err_BUG("optimizenode"); x=tree[n].x; y=tree[n].y; switch(tree[n].f) { case Fseq: optimizeseq(n); return; case Frange: optimizenode(x); optimizenode(y); tree[n].flags=tree[x].flags&tree[y].flags; break; case Fmatcoeff: optimizematcoeff(n); break; case Fassign: optimizenode(x); optimizenode(y); tree[n].flags=0; break; case Fnoarg: case Fnorange: case Fsmall: case Fconst: case Fentry: tree[n].flags=COsafelex|COsafedyn; return; case Fvec: optimizevec(n); return; case Fmat: optimizemat(n); return; case Frefarg: compile_err("unexpected character '&'",tree[n].str); return; case Fvararg: compile_err("unexpected characters '..'",tree[n].str); return; case Ffunction: { entree *ep=getfunc(n); if (EpVALENCE(ep)==EpVAR || EpVALENCE(ep)==EpNEW) optimizecall(n); else optimizefunc(ep,n); return; } case Fcall: optimizecall(n); return; case Flambda: optimizenode(y); tree[n].flags=COsafelex|COsafedyn; return; case Ftag: optimizenode(x); tree[n].flags=tree[x].flags; return; default: pari_err_BUG("optimizenode"); } } pari-2.11.2/src/language/parse.c0000644000175000017500000026326113201020711015003 0ustar billbill/* A Bison parser, made by GNU Bison 3.0.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.0.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse pari_parse #define yylex pari_lex #define yyerror pari_error #define yydebug pari_debug #define yynerrs pari_nerrs /* Copy the first part of user declarations. */ #line 1 "../src/language/parse.y" /* yacc.c:339 */ /* Copyright (C) 2006 The PARI group. This file is part of the PARI package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define YYSIZE_T size_t #define YYSTYPE union token_value #define YYLTYPE struct node_loc #define YYLLOC_DEFAULT(Current, Rhs, N) \ ((Current).start = ((N)?(Rhs)[1].start:(Rhs)[0].end), \ (Current).end = (Rhs)[N].end) #include "parsec.h" #define NOARG(x) newnode(Fnoarg,-1,-1,&(x)) #define NORANGE(x) newnode(Fnorange,-1,-1,&(x)) #line 97 "../src/language/parse.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 1 #endif /* In a future release of Bison, this section will be replaced by #include "parse.h". */ #ifndef YY_PARI_SRC_LANGUAGE_PARSE_H_INCLUDED # define YY_PARI_SRC_LANGUAGE_PARSE_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int pari_debug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { KPARROW = 258, KARROW = 259, KDOTDOT = 260, KPE = 261, KSE = 262, KME = 263, KDE = 264, KDRE = 265, KEUCE = 266, KMODE = 267, KAND = 268, KOR = 269, KID = 270, KEQ = 271, KNE = 272, KGE = 273, KLE = 274, KSRE = 275, KSLE = 276, KSR = 277, KSL = 278, KDR = 279, KPP = 280, KSS = 281, KINTEGER = 282, KREAL = 283, KENTRY = 284, KSTRING = 285, SEQ = 286, DEFFUNC = 287, INT = 288, LVAL = 289, SIGN = 290 }; #endif /* Value type. */ /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif int pari_parse (char **lex); #endif /* !YY_PARI_SRC_LANGUAGE_PARSE_H_INCLUDED */ /* Copy the second part of user declarations. */ #line 192 "../src/language/parse.c" /* yacc.c:358 */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif #if !defined _Noreturn \ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) # if defined _MSC_VER && 1200 <= _MSC_VER # define _Noreturn __declspec (noreturn) # else # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 47 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 671 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 61 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 21 /* YYNRULES -- Number of rules. */ #define YYNRULES 109 /* YYNSTATES -- Number of states. */ #define YYNSTATES 192 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 290 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 2, 49, 2, 43, 38, 53, 55, 59, 46, 41, 36, 42, 54, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 56, 35, 40, 37, 39, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 52, 44, 57, 48, 2, 58, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 60, 2, 51, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 47 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { 0, 86, 86, 89, 90, 91, 92, 95, 96, 97, 98, 101, 102, 105, 106, 109, 110, 111, 112, 113, 114, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 177, 178, 179, 182, 183, 186, 187, 190, 191, 192, 193, 194, 195, 198, 201, 202, 203, 204, 207, 210, 211, 212, 213, 213, 217, 218, 221, 224, 227, 229, 231, 232 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 1 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "\")->\"", "\"->\"", "\"..\"", "\"+=\"", "\"-=\"", "\"*=\"", "\"/=\"", "\"\\\\/=\"", "\"\\\\=\"", "\"%=\"", "\"&&\"", "\"||\"", "\"===\"", "\"==\"", "\"!=\"", "\">=\"", "\"<=\"", "\">>=\"", "\"<<=\"", "\">>\"", "\"<<\"", "\"\\\\/\"", "\"++\"", "\"--\"", "\"integer\"", "\"real number\"", "\"variable name\"", "\"character string\"", "SEQ", "DEFFUNC", "INT", "LVAL", "';'", "','", "'='", "'&'", "'>'", "'<'", "'+'", "'-'", "'%'", "'\\\\'", "'/'", "'*'", "SIGN", "'^'", "'#'", "'!'", "'~'", "'['", "'\\''", "'.'", "'('", "':'", "']'", "'`'", "')'", "'|'", "$accept", "sequence", "seq", "range", "matrix_index", "backticks", "history", "expr", "lvalue", "matrixelts", "matrixlines", "matrix", "in", "inseq", "compr", "arg", "$@1", "listarg", "funcid", "memberid", "definition", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 59, 44, 61, 38, 62, 60, 43, 45, 37, 92, 47, 42, 290, 94, 35, 33, 126, 91, 39, 46, 40, 58, 93, 96, 41, 124 }; # endif #define YYPACT_NINF -165 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-165))) #define YYTABLE_NINF -104 #define yytable_value_is_error(Yytable_value) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { 616, -33, -165, -28, -165, 616, 616, -17, 616, 616, 84, 1, -165, 582, 31, 3, -165, 461, 141, 46, -165, -165, -165, -165, 60, 582, 150, 150, -165, 12, -165, 38, 190, 54, 42, 44, -165, 172, 36, 47, -165, 61, 3, 325, 227, 6, 33, -165, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, -165, -165, 599, -165, 73, 582, 74, -165, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, -165, -165, 616, 86, -165, 616, -165, -22, -165, 38, -165, -165, -165, 616, 61, 616, 616, -165, 616, -165, -165, -36, -165, 282, -165, 616, 582, 461, 503, 503, 538, 538, 538, 538, 538, 150, 150, 150, 503, 538, 538, 552, 552, 150, 150, 150, 150, 150, 616, 50, 252, 79, -19, -165, 3, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, -165, 461, 80, 372, -27, -12, 63, 461, 82, 461, 82, 64, 616, 3, 32, 461, 599, -165, 616, 616, -165, 616, -165, 87, 61, 616, -165, -165, 461, 65, 461, 3, 3, 616, -165, 417, -165, 461, 61, -165 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 3, 21, 22, 78, 25, 0, 0, 15, 0, 0, 0, 0, 23, 3, 0, 2, 27, 4, 30, 31, 32, 29, 75, 33, 0, 3, 68, 69, 16, 18, 13, 17, 48, 47, 0, 0, 85, 81, 0, 0, 26, 0, 97, 4, 30, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 71, 7, 72, 0, 3, 0, 74, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 79, 0, 24, 0, 19, 20, 14, 90, 87, 0, 0, 0, 0, 88, 0, 89, 78, 99, 77, 7, 100, 3, 3, 6, 50, 49, 52, 53, 54, 55, 57, 62, 61, 64, 51, 56, 58, 60, 59, 63, 65, 66, 67, 70, 0, 0, 8, 105, 0, 76, 108, 45, 46, 38, 39, 40, 41, 42, 44, 43, 35, 80, 34, 104, 0, 0, 92, 0, 81, 83, 82, 84, 0, 0, 109, 0, 10, 7, 12, 0, 3, 28, 3, 86, 0, 0, 0, 96, 98, 101, 0, 9, 107, 106, 0, 94, 93, 11, 91, 0, 95 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -165, -165, 11, -44, -16, 99, -165, -5, -7, -83, -165, -165, -165, -164, -165, 18, -165, -10, -165, -165, -165 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 14, 42, 136, 76, 31, 16, 17, 18, 38, 39, 19, 157, 158, 20, 45, 164, 46, 21, 22, 23 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { 26, 27, 91, 32, 33, 37, 44, 111, 43, -102, 28, 15, 186, 175, 113, 94, 71, 113, 44, 160, 90, 24, 162, 176, 177, 71, 191, 25, 91, 90, 40, 47, 29, 111, 108, -103, 112, 154, 48, 95, 172, 30, -102, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 139, -102, 137, 44, -103, 113, 30, 102, 103, 142, 143, 144, 145, 146, 147, 148, 149, 150, 105, 92, 151, 34, 168, 153, 141, 93, 107, -103, 91, 104, 156, 155, 97, 159, 161, 98, 159, 99, 138, 140, 106, 137, 44, 169, 73, 74, 75, 1, 2, 3, 4, 152, 171, 173, 103, 35, 178, 179, 188, 165, 181, 5, 6, 7, 96, 185, 167, 166, 0, 8, 9, 0, 10, 11, 12, 13, 91, 36, 0, 0, 0, 77, 0, 78, 79, 80, 81, 82, 83, 84, 0, 0, 0, 0, 0, 180, 0, 85, 86, 137, 0, 182, 87, 88, 0, 156, 0, 0, 187, 0, 0, 0, 0, 100, 89, 0, 189, 0, 183, 156, 184, 49, 50, 51, 52, 53, 54, 55, 0, 71, 56, 57, 58, 90, 68, 0, 69, 70, 71, 72, 73, 74, 75, 0, 0, 0, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 0, 0, 77, 101, 78, 79, 80, 81, 82, 83, 84, 69, 70, 71, 72, 73, 74, 75, 85, 86, 0, 0, 0, 87, 88, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 89, 49, 50, 51, 52, 53, 54, 55, 0, 0, 56, 57, 58, 0, 0, 110, 0, 0, 0, 90, 0, 0, 0, 163, 0, 0, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 0, 135, 8, 9, 0, 10, 11, 12, 13, 49, 50, 51, 52, 53, 54, 55, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 0, 0, 109, 49, 50, 51, 52, 53, 54, 55, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 174, 49, 50, 51, 52, 53, 54, 55, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 49, 50, 51, 52, 53, 54, 55, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 51, 52, 53, 54, 55, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 56, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 57, 58, 0, 0, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 64, 65, 66, 67, 0, 68, 0, 69, 70, 71, 72, 73, 74, 75, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 5, 6, 7, 1, 2, 3, 4, 0, 8, 9, 0, 10, 11, 12, 13, 0, 0, 5, 6, 7, 1, 2, 3, 4, 135, 8, 9, 0, 10, 11, 12, 13, 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 8, 9, 0, 10, 11, 12, 13 }; static const yytype_int16 yycheck[] = { 5, 6, 18, 8, 9, 10, 13, 1, 13, 3, 27, 0, 176, 40, 36, 25, 52, 36, 25, 102, 56, 54, 105, 35, 36, 52, 190, 55, 44, 56, 29, 0, 49, 1, 41, 3, 3, 59, 35, 27, 59, 58, 36, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 74, 59, 71, 74, 36, 36, 58, 35, 36, 78, 79, 80, 81, 82, 83, 84, 85, 86, 35, 37, 89, 1, 36, 92, 77, 29, 29, 59, 108, 57, 101, 100, 58, 102, 103, 57, 105, 57, 29, 29, 57, 110, 113, 57, 54, 55, 56, 27, 28, 29, 30, 29, 37, 37, 36, 35, 57, 57, 57, 112, 168, 41, 42, 43, 29, 42, 135, 113, -1, 49, 50, -1, 52, 53, 54, 55, 156, 57, -1, -1, -1, 4, -1, 6, 7, 8, 9, 10, 11, 12, -1, -1, -1, -1, -1, 164, -1, 20, 21, 168, -1, 170, 25, 26, -1, 176, -1, -1, 177, -1, -1, -1, -1, 5, 37, -1, 185, -1, 171, 190, 173, 13, 14, 15, 16, 17, 18, 19, -1, 52, 22, 23, 24, 56, 48, -1, 50, 51, 52, 53, 54, 55, 56, -1, -1, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, -1, -1, 4, 60, 6, 7, 8, 9, 10, 11, 12, 50, 51, 52, 53, 54, 55, 56, 20, 21, -1, -1, -1, 25, 26, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, 37, 13, 14, 15, 16, 17, 18, 19, -1, -1, 22, 23, 24, -1, -1, 52, -1, -1, -1, 56, -1, -1, -1, 5, -1, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, 27, 28, 29, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, 42, 43, -1, -1, -1, -1, 48, 49, 50, -1, 52, 53, 54, 55, 13, 14, 15, 16, 17, 18, 19, -1, -1, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, -1, -1, 59, 13, 14, 15, 16, 17, 18, 19, -1, -1, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, 57, 13, 14, 15, 16, 17, 18, 19, -1, -1, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 35, -1, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, 13, 14, 15, 16, 17, 18, 19, -1, -1, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, 15, 16, 17, 18, 19, -1, -1, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, 40, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, -1, -1, 41, 42, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, 43, 44, 45, 46, -1, 48, -1, 50, 51, 52, 53, 54, 55, 56, 27, 28, 29, 30, -1, -1, -1, -1, -1, -1, -1, 38, -1, -1, 41, 42, 43, 27, 28, 29, 30, -1, 49, 50, -1, 52, 53, 54, 55, -1, -1, 41, 42, 43, 27, 28, 29, 30, 48, 49, 50, -1, 52, 53, 54, 55, -1, -1, 41, 42, 43, -1, -1, -1, -1, -1, 49, 50, -1, 52, 53, 54, 55 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 27, 28, 29, 30, 41, 42, 43, 49, 50, 52, 53, 54, 55, 62, 63, 67, 68, 69, 72, 75, 79, 80, 81, 54, 55, 68, 68, 27, 49, 58, 66, 68, 68, 1, 35, 57, 68, 70, 71, 29, 38, 63, 68, 69, 76, 78, 0, 35, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 38, 39, 40, 41, 42, 43, 44, 45, 46, 48, 50, 51, 52, 53, 54, 55, 56, 65, 4, 6, 7, 8, 9, 10, 11, 12, 20, 21, 25, 26, 37, 56, 65, 37, 29, 78, 27, 66, 58, 57, 57, 5, 60, 35, 36, 57, 35, 57, 29, 69, 59, 52, 1, 3, 36, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 48, 64, 68, 29, 78, 29, 63, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 29, 68, 59, 68, 69, 73, 74, 68, 70, 68, 70, 5, 77, 63, 76, 68, 36, 57, 5, 37, 59, 37, 57, 40, 35, 36, 57, 57, 68, 64, 68, 63, 63, 42, 74, 68, 57, 68, 35, 74 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 66, 66, 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 70, 70, 71, 71, 72, 72, 72, 72, 72, 72, 73, 74, 74, 74, 74, 75, 76, 76, 76, 77, 76, 78, 78, 79, 80, 81, 81, 81, 81 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 0, 1, 2, 3, 0, 1, 3, 2, 5, 3, 1, 2, 1, 2, 2, 2, 3, 3, 1, 1, 1, 3, 1, 2, 1, 4, 1, 1, 1, 1, 1, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 2, 2, 2, 2, 1, 3, 3, 1, 2, 3, 1, 3, 3, 3, 2, 5, 3, 3, 3, 3, 4, 1, 3, 3, 5, 5, 1, 4, 2, 0, 4, 1, 3, 4, 3, 6, 5, 3, 4 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (&yylloc, lex, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (N) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (0) #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K]) /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL /* Print *YYLOCP on YYO. Private, do not rely on its existence. */ YY_ATTRIBUTE_UNUSED static unsigned yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) { unsigned res = 0; int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; if (0 <= yylocp->first_line) { res += YYFPRINTF (yyo, "%d", yylocp->first_line); if (0 <= yylocp->first_column) res += YYFPRINTF (yyo, ".%d", yylocp->first_column); } if (0 <= yylocp->last_line) { if (yylocp->first_line < yylocp->last_line) { res += YYFPRINTF (yyo, "-%d", yylocp->last_line); if (0 <= end_col) res += YYFPRINTF (yyo, ".%d", end_col); } else if (0 <= end_col && yylocp->first_column < end_col) res += YYFPRINTF (yyo, "-%d", end_col); } return res; } # define YY_LOCATION_PRINT(File, Loc) \ yy_location_print_ (File, &(Loc)) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value, Location, lex); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*----------------------------------------. | Print this symbol's value on YYOUTPUT. | `----------------------------------------*/ static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, char **lex) { FILE *yyo = yyoutput; YYUSE (yyo); YYUSE (yylocationp); YYUSE (lex); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, char **lex) { YYFPRINTF (yyoutput, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); YY_LOCATION_PRINT (yyoutput, *yylocationp); YYFPRINTF (yyoutput, ": "); yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, lex); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, char **lex) { unsigned long int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &(yyvsp[(yyi + 1) - (yynrhs)]) , &(yylsp[(yyi + 1) - (yynrhs)]) , lex); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, yylsp, Rule, lex); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, char **lex) { YYUSE (yyvaluep); YYUSE (yylocationp); YYUSE (lex); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN switch (yytype) { case 63: /* seq */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1322 "../src/language/parse.c" /* yacc.c:1257 */ break; case 64: /* range */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1328 "../src/language/parse.c" /* yacc.c:1257 */ break; case 65: /* matrix_index */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1334 "../src/language/parse.c" /* yacc.c:1257 */ break; case 66: /* backticks */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1340 "../src/language/parse.c" /* yacc.c:1257 */ break; case 67: /* history */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1346 "../src/language/parse.c" /* yacc.c:1257 */ break; case 68: /* expr */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1352 "../src/language/parse.c" /* yacc.c:1257 */ break; case 69: /* lvalue */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1358 "../src/language/parse.c" /* yacc.c:1257 */ break; case 70: /* matrixelts */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1364 "../src/language/parse.c" /* yacc.c:1257 */ break; case 71: /* matrixlines */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1370 "../src/language/parse.c" /* yacc.c:1257 */ break; case 72: /* matrix */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1376 "../src/language/parse.c" /* yacc.c:1257 */ break; case 73: /* in */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1382 "../src/language/parse.c" /* yacc.c:1257 */ break; case 74: /* inseq */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1388 "../src/language/parse.c" /* yacc.c:1257 */ break; case 75: /* compr */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1394 "../src/language/parse.c" /* yacc.c:1257 */ break; case 76: /* arg */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1400 "../src/language/parse.c" /* yacc.c:1257 */ break; case 78: /* listarg */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1406 "../src/language/parse.c" /* yacc.c:1257 */ break; case 79: /* funcid */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1412 "../src/language/parse.c" /* yacc.c:1257 */ break; case 80: /* memberid */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1418 "../src/language/parse.c" /* yacc.c:1257 */ break; case 81: /* definition */ #line 83 "../src/language/parse.y" /* yacc.c:1257 */ { pari_discarded++; } #line 1424 "../src/language/parse.c" /* yacc.c:1257 */ break; default: break; } YY_IGNORE_MAYBE_UNINITIALIZED_END } /*----------. | yyparse. | `----------*/ int yyparse (char **lex) { /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ YY_INITIAL_VALUE (static YYSTYPE yyval_default;) YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Location data for the lookahead symbol. */ static YYLTYPE yyloc_default # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL = { 1, 1, 1, 1 } # endif ; YYLTYPE yylloc = yyloc_default; /* Number of syntax errors so far. */ int yynerrs; int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. 'yyls': related to locations. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls; YYLTYPE *yylsp; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yylsp = yyls = yylsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* User initialization code. */ #line 30 "../src/language/parse.y" /* yacc.c:1429 */ { yylloc.start=yylloc.end=*lex; } #line 1535 "../src/language/parse.c" /* yacc.c:1429 */ yylsp[0] = yylloc; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyls = yyls1; yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (&yylval, &yylloc, lex); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: #line 86 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1724 "../src/language/parse.c" /* yacc.c:1646 */ break; case 3: #line 89 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=NOARG((yyloc));} #line 1730 "../src/language/parse.c" /* yacc.c:1646 */ break; case 4: #line 90 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1736 "../src/language/parse.c" /* yacc.c:1646 */ break; case 5: #line 91 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[-1].val); (yyloc)=(yylsp[-1]);} #line 1742 "../src/language/parse.c" /* yacc.c:1646 */ break; case 6: #line 92 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fseq,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1748 "../src/language/parse.c" /* yacc.c:1646 */ break; case 7: #line 95 "../src/language/parse.y" /* yacc.c:1646 */ { (yyval.val)=newnode(Frange,NORANGE((yyloc)),NORANGE((yyloc)),&(yyloc)); } #line 1754 "../src/language/parse.c" /* yacc.c:1646 */ break; case 8: #line 96 "../src/language/parse.y" /* yacc.c:1646 */ { (yyval.val)=newnode(Frange,(yyvsp[0].val),NORANGE((yyloc)),&(yyloc)); } #line 1760 "../src/language/parse.c" /* yacc.c:1646 */ break; case 9: #line 97 "../src/language/parse.y" /* yacc.c:1646 */ { (yyval.val)=newnode(Frange,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc)); } #line 1766 "../src/language/parse.c" /* yacc.c:1646 */ break; case 10: #line 98 "../src/language/parse.y" /* yacc.c:1646 */ { (yyval.val)=newnode(Frange,NORANGE((yyloc)),(yyvsp[0].val),&(yyloc)); } #line 1772 "../src/language/parse.c" /* yacc.c:1646 */ break; case 11: #line 101 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmatrix,(yyvsp[-3].val),(yyvsp[-1].val),&(yyloc));} #line 1778 "../src/language/parse.c" /* yacc.c:1646 */ break; case 12: #line 102 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmatrix,(yyvsp[-1].val),-1,&(yyloc));} #line 1784 "../src/language/parse.c" /* yacc.c:1646 */ break; case 13: #line 105 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=1;} #line 1790 "../src/language/parse.c" /* yacc.c:1646 */ break; case 14: #line 106 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[-1].val)+1;} #line 1796 "../src/language/parse.c" /* yacc.c:1646 */ break; case 15: #line 109 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPhist,-1,-1,&(yyloc));} #line 1802 "../src/language/parse.c" /* yacc.c:1646 */ break; case 16: #line 110 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPhist,newintnode(&(yylsp[0])),-1,&(yyloc));} #line 1808 "../src/language/parse.c" /* yacc.c:1646 */ break; case 17: #line 111 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPhist,newnode(Fsmall,-(yyvsp[0].val),-1,&(yyloc)),-1,&(yyloc));} #line 1814 "../src/language/parse.c" /* yacc.c:1646 */ break; case 18: #line 112 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPhisttime,-1,-1,&(yyloc));} #line 1820 "../src/language/parse.c" /* yacc.c:1646 */ break; case 19: #line 113 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPhisttime,newintnode(&(yylsp[0])),-1,&(yyloc));} #line 1826 "../src/language/parse.c" /* yacc.c:1646 */ break; case 20: #line 114 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPhisttime,newnode(Fsmall,-(yyvsp[0].val),-1,&(yyloc)),-1,&(yyloc));} #line 1832 "../src/language/parse.c" /* yacc.c:1646 */ break; case 21: #line 117 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newintnode(&(yylsp[0]));} #line 1838 "../src/language/parse.c" /* yacc.c:1646 */ break; case 22: #line 118 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newconst(CSTreal,&(yyloc));} #line 1844 "../src/language/parse.c" /* yacc.c:1646 */ break; case 23: #line 119 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newconst(CSTreal,&(yyloc));} #line 1850 "../src/language/parse.c" /* yacc.c:1646 */ break; case 24: #line 120 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Ffunction,newconst(CSTmember,&(yylsp[0])), newintnode(&(yylsp[-2])),&(yyloc));} #line 1857 "../src/language/parse.c" /* yacc.c:1646 */ break; case 25: #line 122 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newconst(CSTstr,&(yyloc));} #line 1863 "../src/language/parse.c" /* yacc.c:1646 */ break; case 26: #line 123 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newconst(CSTquote,&(yyloc));} #line 1869 "../src/language/parse.c" /* yacc.c:1646 */ break; case 27: #line 124 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1875 "../src/language/parse.c" /* yacc.c:1646 */ break; case 28: #line 125 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fcall,(yyvsp[-3].val),(yyvsp[-1].val),&(yyloc));} #line 1881 "../src/language/parse.c" /* yacc.c:1646 */ break; case 29: #line 126 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1887 "../src/language/parse.c" /* yacc.c:1646 */ break; case 30: #line 127 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1893 "../src/language/parse.c" /* yacc.c:1646 */ break; case 31: #line 128 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1899 "../src/language/parse.c" /* yacc.c:1646 */ break; case 32: #line 129 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1905 "../src/language/parse.c" /* yacc.c:1646 */ break; case 33: #line 130 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 1911 "../src/language/parse.c" /* yacc.c:1646 */ break; case 34: #line 131 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fassign,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1917 "../src/language/parse.c" /* yacc.c:1646 */ break; case 35: #line 132 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fassign,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1923 "../src/language/parse.c" /* yacc.c:1646 */ break; case 36: #line 133 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPpp,(yyvsp[-1].val),-1,&(yyloc));} #line 1929 "../src/language/parse.c" /* yacc.c:1646 */ break; case 37: #line 134 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPss,(yyvsp[-1].val),-1,&(yyloc));} #line 1935 "../src/language/parse.c" /* yacc.c:1646 */ break; case 38: #line 135 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPme,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1941 "../src/language/parse.c" /* yacc.c:1646 */ break; case 39: #line 136 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPde,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1947 "../src/language/parse.c" /* yacc.c:1646 */ break; case 40: #line 137 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPdre,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1953 "../src/language/parse.c" /* yacc.c:1646 */ break; case 41: #line 138 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPeuce,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1959 "../src/language/parse.c" /* yacc.c:1646 */ break; case 42: #line 139 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPmode,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1965 "../src/language/parse.c" /* yacc.c:1646 */ break; case 43: #line 140 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPsle,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1971 "../src/language/parse.c" /* yacc.c:1646 */ break; case 44: #line 141 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPsre,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1977 "../src/language/parse.c" /* yacc.c:1646 */ break; case 45: #line 142 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPpe,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1983 "../src/language/parse.c" /* yacc.c:1646 */ break; case 46: #line 143 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPse,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 1989 "../src/language/parse.c" /* yacc.c:1646 */ break; case 47: #line 144 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPnb,(yyvsp[0].val),-1,&(yyloc));} #line 1995 "../src/language/parse.c" /* yacc.c:1646 */ break; case 48: #line 145 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPlength,(yyvsp[0].val),-1,&(yyloc));} #line 2001 "../src/language/parse.c" /* yacc.c:1646 */ break; case 49: #line 146 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPor,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2007 "../src/language/parse.c" /* yacc.c:1646 */ break; case 50: #line 147 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPand,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2013 "../src/language/parse.c" /* yacc.c:1646 */ break; case 51: #line 148 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPand,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2019 "../src/language/parse.c" /* yacc.c:1646 */ break; case 52: #line 149 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPid,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2025 "../src/language/parse.c" /* yacc.c:1646 */ break; case 53: #line 150 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPeq,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2031 "../src/language/parse.c" /* yacc.c:1646 */ break; case 54: #line 151 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPne,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2037 "../src/language/parse.c" /* yacc.c:1646 */ break; case 55: #line 152 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPge,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2043 "../src/language/parse.c" /* yacc.c:1646 */ break; case 56: #line 153 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPg,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2049 "../src/language/parse.c" /* yacc.c:1646 */ break; case 57: #line 154 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPle,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2055 "../src/language/parse.c" /* yacc.c:1646 */ break; case 58: #line 155 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPl,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2061 "../src/language/parse.c" /* yacc.c:1646 */ break; case 59: #line 156 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPs,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2067 "../src/language/parse.c" /* yacc.c:1646 */ break; case 60: #line 157 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPp,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2073 "../src/language/parse.c" /* yacc.c:1646 */ break; case 61: #line 158 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPsl,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2079 "../src/language/parse.c" /* yacc.c:1646 */ break; case 62: #line 159 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPsr,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2085 "../src/language/parse.c" /* yacc.c:1646 */ break; case 63: #line 160 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPmod,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2091 "../src/language/parse.c" /* yacc.c:1646 */ break; case 64: #line 161 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPdr,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2097 "../src/language/parse.c" /* yacc.c:1646 */ break; case 65: #line 162 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPeuc,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2103 "../src/language/parse.c" /* yacc.c:1646 */ break; case 66: #line 163 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPd,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2109 "../src/language/parse.c" /* yacc.c:1646 */ break; case 67: #line 164 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPm,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2115 "../src/language/parse.c" /* yacc.c:1646 */ break; case 68: #line 165 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 2121 "../src/language/parse.c" /* yacc.c:1646 */ break; case 69: #line 166 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPn,(yyvsp[0].val),-1,&(yyloc));} #line 2127 "../src/language/parse.c" /* yacc.c:1646 */ break; case 70: #line 167 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPpow,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2133 "../src/language/parse.c" /* yacc.c:1646 */ break; case 71: #line 168 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPtrans,(yyvsp[-1].val),-1,&(yyloc));} #line 2139 "../src/language/parse.c" /* yacc.c:1646 */ break; case 72: #line 169 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPderiv,(yyvsp[-1].val),-1,&(yyloc));} #line 2145 "../src/language/parse.c" /* yacc.c:1646 */ break; case 73: #line 170 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPfact,(yyvsp[-1].val),-1,&(yyloc));} #line 2151 "../src/language/parse.c" /* yacc.c:1646 */ break; case 74: #line 171 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmatcoeff,(yyvsp[-1].val),(yyvsp[0].val),&(yyloc));} #line 2157 "../src/language/parse.c" /* yacc.c:1646 */ break; case 75: #line 172 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 2163 "../src/language/parse.c" /* yacc.c:1646 */ break; case 76: #line 173 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Ftag,(yyvsp[-2].val),0,&(yyloc));} #line 2169 "../src/language/parse.c" /* yacc.c:1646 */ break; case 77: #line 174 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[-1].val);} #line 2175 "../src/language/parse.c" /* yacc.c:1646 */ break; case 78: #line 177 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fentry,newconst(CSTentry,&(yylsp[0])),-1,&(yyloc));} #line 2181 "../src/language/parse.c" /* yacc.c:1646 */ break; case 79: #line 178 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmatcoeff,(yyvsp[-1].val),(yyvsp[0].val),&(yyloc));} #line 2187 "../src/language/parse.c" /* yacc.c:1646 */ break; case 80: #line 179 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Ftag,(yyvsp[-2].val),newconst(CSTentry,&(yylsp[-1])),&(yyloc));} #line 2193 "../src/language/parse.c" /* yacc.c:1646 */ break; case 81: #line 182 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 2199 "../src/language/parse.c" /* yacc.c:1646 */ break; case 82: #line 183 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmatrixelts,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2205 "../src/language/parse.c" /* yacc.c:1646 */ break; case 83: #line 186 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmatrixlines,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2211 "../src/language/parse.c" /* yacc.c:1646 */ break; case 84: #line 187 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmatrixlines,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2217 "../src/language/parse.c" /* yacc.c:1646 */ break; case 85: #line 190 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fvec,-1,-1,&(yyloc));} #line 2223 "../src/language/parse.c" /* yacc.c:1646 */ break; case 86: #line 191 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPrange,(yyvsp[-3].val),(yyvsp[-1].val),&(yyloc));} #line 2229 "../src/language/parse.c" /* yacc.c:1646 */ break; case 87: #line 192 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmat,-1,-1,&(yyloc));} #line 2235 "../src/language/parse.c" /* yacc.c:1646 */ break; case 88: #line 193 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fvec,(yyvsp[-1].val),-1,&(yyloc));} #line 2241 "../src/language/parse.c" /* yacc.c:1646 */ break; case 89: #line 194 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fmat,(yyvsp[-1].val),-1,&(yyloc));} #line 2247 "../src/language/parse.c" /* yacc.c:1646 */ break; case 90: #line 195 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=-1; YYABORT;} #line 2253 "../src/language/parse.c" /* yacc.c:1646 */ break; case 91: #line 198 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Flistarg,(yyvsp[0].val),(yyvsp[-3].val),&(yyloc));} #line 2259 "../src/language/parse.c" /* yacc.c:1646 */ break; case 92: #line 201 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPcompr,(yyvsp[0].val),-2,&(yyloc));} #line 2265 "../src/language/parse.c" /* yacc.c:1646 */ break; case 93: #line 202 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall3(OPcompr,(yyvsp[-2].val),-2,(yyvsp[0].val),&(yyloc));} #line 2271 "../src/language/parse.c" /* yacc.c:1646 */ break; case 94: #line 203 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall(OPcomprc,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2277 "../src/language/parse.c" /* yacc.c:1646 */ break; case 95: #line 204 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newopcall3(OPcomprc,(yyvsp[-4].val),(yyvsp[0].val),(yyvsp[-2].val),&(yyloc));} #line 2283 "../src/language/parse.c" /* yacc.c:1646 */ break; case 96: #line 207 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=addcurrexpr((yyvsp[-1].val),(yyvsp[-3].val),&(yyloc));} #line 2289 "../src/language/parse.c" /* yacc.c:1646 */ break; case 97: #line 210 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 2295 "../src/language/parse.c" /* yacc.c:1646 */ break; case 98: #line 211 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Fvararg,(yyvsp[-3].val),-1,&(yyloc));} #line 2301 "../src/language/parse.c" /* yacc.c:1646 */ break; case 99: #line 212 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Frefarg,(yyvsp[0].val),-1,&(yyloc));} #line 2307 "../src/language/parse.c" /* yacc.c:1646 */ break; case 100: #line 213 "../src/language/parse.y" /* yacc.c:1646 */ {if (!pari_once) { yyerrok; } pari_once=1;} #line 2313 "../src/language/parse.c" /* yacc.c:1646 */ break; case 101: #line 214 "../src/language/parse.y" /* yacc.c:1646 */ {pari_once=0; (yyval.val)=newopcall(OPcat,(yyvsp[-3].val),(yyvsp[0].val),&(yyloc));} #line 2319 "../src/language/parse.c" /* yacc.c:1646 */ break; case 102: #line 217 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=(yyvsp[0].val);} #line 2325 "../src/language/parse.c" /* yacc.c:1646 */ break; case 103: #line 218 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Flistarg,(yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2331 "../src/language/parse.c" /* yacc.c:1646 */ break; case 104: #line 221 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Ffunction,newconst(CSTentry,&(yylsp[-3])),(yyvsp[-1].val),&(yyloc));} #line 2337 "../src/language/parse.c" /* yacc.c:1646 */ break; case 105: #line 224 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Ffunction,newconst(CSTmember,&(yylsp[0])),(yyvsp[-2].val),&(yyloc));} #line 2343 "../src/language/parse.c" /* yacc.c:1646 */ break; case 106: #line 228 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newfunc(CSTentry,&(yylsp[-5]),(yyvsp[-3].val),(yyvsp[0].val),&(yyloc));} #line 2349 "../src/language/parse.c" /* yacc.c:1646 */ break; case 107: #line 230 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newfunc(CSTmember,&(yylsp[-2]),(yyvsp[-4].val),(yyvsp[0].val),&(yyloc));} #line 2355 "../src/language/parse.c" /* yacc.c:1646 */ break; case 108: #line 231 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Flambda, (yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2361 "../src/language/parse.c" /* yacc.c:1646 */ break; case 109: #line 232 "../src/language/parse.y" /* yacc.c:1646 */ {(yyval.val)=newnode(Flambda, (yyvsp[-2].val),(yyvsp[0].val),&(yyloc));} #line 2367 "../src/language/parse.c" /* yacc.c:1646 */ break; #line 2371 "../src/language/parse.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; *++yylsp = yyloc; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (&yylloc, lex, YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (&yylloc, lex, yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } yyerror_range[1] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, &yylloc, lex); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; yyerror_range[1] = yylsp[1-yylen]; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yyerror_range[1] = *yylsp; yydestruct ("Error: popping", yystos[yystate], yyvsp, yylsp, lex); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END yyerror_range[2] = yylloc; /* Using YYLLOC is tempting, but would change the location of the lookahead. YYLOC is available though. */ YYLLOC_DEFAULT (yyloc, yyerror_range, 2); *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (&yylloc, lex, YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc, lex); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp, yylsp, lex); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } #line 235 "../src/language/parse.y" /* yacc.c:1906 */ pari-2.11.2/src/test/0000755000175000017500000000000013461316051012724 5ustar billbillpari-2.11.2/src/test/32/0000755000175000017500000000000013461316051013150 5ustar billbillpari-2.11.2/src/test/32/gcdext0000644000175000017500000000455613326135265014371 0ustar billbill[0, 0, 0] [0, 0, 0] [0, 0, 0] [0, 1, 2] [0, 3 + 2*5 + 2*5^2 + O(5^3), 1] [0, 1, x] [0, 0, 0] [0, 0, 0] [0, 0, 0] [0, 1/2, 1] [0, 3 + 2*5 + 2*5^2 + O(5^3), 1] [0, 1, x] [0, 0, 0] [0, 0, 0] [0, 0, 0] [0, 1/2, 1] [0, 3 + 2*5 + 2*5^2 + O(5^3), 1] [0, 1, x] [1, 0, 2] [1/2, 0, 1] [1/2, 0, 1] [0, 1, 2] [1/2, 0, 1] [1/2, 0, 1] [3 + 2*5 + 2*5^2 + O(5^3), 0, 1] [3 + 2*5 + 2*5^2 + O(5^3), 0, 1] [3 + 2*5 + 2*5^2 + O(5^3), 0, 1] [3 + 2*5 + 2*5^2 + O(5^3), 0, 1] [3 + 2*5 + 2*5^2 + O(5^3), 0, 1] [3 + 2*5 + 2*5^2 + O(5^3), 0, 1] [1, 0, x] [1, 0, x] [1, 0, x] [0, 1/2, 1] [0, 3 + 2*5 + 2*5^2 + O(5^3), 1] [0, 1, x] [0, -3, 3*x + 5] [0, 1, (10*T^3 + 3*T + 5)*z^6 + (11*T^3 + 15*T^2 + 10*T + 13)*z^4 + (14*T^3 + 13*T^2 + 15)*z^2 + (9 + 13*T + 14*T^2 + 11*T^3 + O(T^20))] Mod(1, 7)*x x + a [(a^4 + 2*a^3 + a^2 + a + 1)*x^2 + (a^4 + 2*a^3 + a^2 + a + 2)*x + 1, (2*a^4 + a^3 + 2*a^2 + 2*a + 2)*x + (2*a^4 + a^3 + 2*a^2 + 2*a + 1), 1] 1 + I 1 1 2 w w Mod(2, 4) *** at top-level: gcd(1/2,Mod(2,4)) *** ^----------------- *** gcd: inconsistent gcd t_INTMOD , t_FRAC. Mod(1, 4) 2 Mod(1, 5) Mod(1, 5) 1/2 1/2 1 1 1 Mod(1, x^3) Mod(x, x^3) 1 *** at top-level: gcd(t,1/x) *** ^---------- *** gcd: inconsistent gcd t_POLMOD , t_RFRAC. 1 y x 1/x^2 1 1 1 0 1 1 error("forbidden multiplication t_REAL * t_FFELT.") error("forbidden gcd t_REAL , t_FFELT.") error("forbidden gcd t_REAL , t_FFELT.") 1 1 error("inconsistent gcd t_INTMOD , t_FFELT.") error("impossible inverse in FF_Z_Z_muldiv: 2.") error("inconsistent gcd t_FRAC , t_FFELT.") 1 1 1 error("inconsistent gcd t_FRAC , t_FFELT.") 0 1 error("inconsistent gcd t_FRAC , t_FFELT.") error("forbidden multiplication t_FFELT * t_COMPLEX.") error("forbidden gcd t_FFELT , t_COMPLEX.") error("forbidden gcd t_FFELT , t_COMPLEX.") error("forbidden multiplication t_FFELT * t_QUAD.") error("forbidden gcd t_FFELT , t_QUAD.") error("forbidden gcd t_FFELT , t_QUAD.") error("forbidden multiplication t_FFELT * t_PADIC.") 1 error("inconsistent gcd t_FFELT , t_PADIC.") error("forbidden multiplication t_FFELT * t_PADIC.") 1 error("inconsistent gcd t_FFELT , t_PADIC.") error("forbidden multiplication t_FFELT * t_PADIC.") error("inconsistent gcd t_FFELT , t_PADIC.") error("inconsistent gcd t_FFELT , t_PADIC.") 1 1 + I Mod(1, 3) 1 Mod(1, 13) 1 (-k + 0.E-38)/k 1/18446744073709551616 Mod(1, 2)*x + Mod(1, 2) x + 1 0 Mod(0, 3) Total time spent: 2 pari-2.11.2/src/test/32/mf0000644000175000017500000022410613447371554013517 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). [ "Factors" 0 0 0 0] [ "Divisors" 0 0 0 0] [ "H" 0 0 0 0] ["CorediscF" 0 0 0 0] [ "Dihedral" 0 0 0 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [Mod(-1/5*t - 2/5, t^2 + 1), Mod(1, t^2 + 1), Mod(4*t + 1, t^2 + 1), Mod(-9* t + 1, t^2 + 1), Mod(4*t - 15, t^2 + 1), Mod(1, t^2 + 1), Mod(-5*t + 37, t^2 + 1), Mod(49*t + 1, t^2 + 1), Mod(-60*t - 15, t^2 + 1), Mod(-9*t - 80, t^2 + 1), Mod(4*t + 1, t^2 + 1), Mod(122, t^2 + 1), Mod(139*t + 21, t^2 + 1), Mo d(-169*t + 1, t^2 + 1), Mod(53*t - 195, t^2 + 1), Mod(-9*t + 1, t^2 + 1)] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 1, 0, 8, 0, -26, 0, -48, 0, 73, 0, 120, 0, -170, 0, -208] 5 23 40000 20000 0 [0, 8]~ [16, -4]~ [16, -32, 256]~ [64/5, 4/5, 32/5]~ [ 0] [ 1] [ 0] [ -516] [ 0] [-10530] [ 0] [ 49304] [ 0] [ 89109] [ 0] [ 0 0 0 0] [ 1 0 0 1] [ -24 1 0 0] [ 252 0 0 -516] [ -1472 -24 1 0] [ 4830 0 0 -10530] [ -6048 252 0 0] [ -16744 0 0 49304] [ 84480 -1472 -24 0] [-113643 0 0 89109] [-115920 4830 0 0] [ 0 0 0 0] [ -24 1 0 0] [ -1472 -24 1 0] [ -6048 252 0 0] [ 84480 -1472 -24 0] [-115920 4830 0 0] [[43/64, 129/8, 1376, 21/64]~, [0, 1, 0; 768, 24, 0; 18432, 2048, 768; 0, -1 , 0]] [[43/64, -63/8, 800, 21/64]~, [1, 0; 24, 0; 2048, 768; -1, 0]] [[1, 0, 1472, 0]~, [0; 0; 768; 0]] [1, 0, 0, 0]~ [1, [1, 1]] [1, 0, 0, 0]~ [1, 0, 0, 0]~ [] [1] [] [] [0, 0] [] [0, 0] 0 10 0 1 0 0 0 1 [] [[1, Mod(0, 1), 0, 0]] 0 1 0 0 [[0, 0], [0, 0], [0, 0], [0, 0]] [[1, 0], [0, 0], [0, 0], [1, 0]] 77291 29586 65034 [[11/32, 1/64, 1/32; 1/32, -9/64, -5/32; -1/8, 3/16, 1/8; -5/32, 1/64, 1/32; -5/32, -7/64, 1/32; -1/8, 1/16, 1/8; -3/32, 3/64, -1/32; -1/16, 3/32, 1/16; -1/32, -3/64, -3/32; -1/32, 5/64, -3/32; 0, 0, 0], [y, y, y, y^4 - y^3 - 5* y^2 + 3*y + 4, y^4 - y^3 - 8*y^2 + 4*y + 12]] [y, y, y] [y, y, y] [y, y, y] [y, y, y, y^4 - y^3 - 5*y^2 + 3*y + 4, y^4 - y^3 - 8*y^2 + 4*y + 12] [y^40 + y^38 - 22*y^36 - 488*y^34 + 200*y^32 + 61712*y^30 + 53952*y^28 - 211 6352*y^26 - 23962624*y^24 + 95379456*y^22 + 2793799680*y^20 + 6104285184*y^1 8 - 98150907904*y^16 - 554788978688*y^14 + 905164357632*y^12 + 6626275544268 8*y^10 + 13743895347200*y^8 - 2146246697418752*y^6 - 6192449487634432*y^4 + 18014398509481984*y^2 + 1152921504606846976] [y, y^2 + Mod(-2*t, t^2 + t + 1), y^5 + Mod(t + 1, t^2 + t + 1)*y^4 + Mod(-3 7*t, t^2 + t + 1)*y^3 + 21*y^2 + Mod(-288*t - 288, t^2 + t + 1)*y + Mod(64*t , t^2 + t + 1)] [1, 1] 1 [[2, Mod(22, 23), 1, 0], [22, Mod(5, 23), 1, 0]] [] 0 6 2 [0, 3, -1, 0, 3, 1, -8, -1, -9, 1, -1, -2, 4, 10, 1, -2, 7, -2, 7, -4] [0, -1, 9, -8, -11, -1, 4, 1, 13, 7, 9, 8, -20, 6, -9, -8, -27, -6, 5, 20] [0, 2, 8, -8, -8, 0, -4, 0, 4, 8, 8, 6, -16, 16, -8, -10] [0, 0, -3, 28, -33, -28, 34, 6, -113, 88, 33, 128, 108, -62, -17, 6] [0, 1, 17, -16, -19, -1, 0, 1, 17, 15, 17, 14, -36, 22, -17, -18] [0, 3, -1, 0, 3, 1, -8, -1, -9, 1, -1, -2, 4, 10, 1, -2, 7, -2, 7, -4, 7, 2, 8, -8, -4, 3, 6, -12, -7, 4, -8, -4, -9, -12, -6, -3, 3, 14, 20, -6, -9, -1 0, 8, 0, 0, 5, -16, 4, 28, 3] [0, -8, 4, 4, -20, -8, 32, 8, 36, -12, 4, -4, -24, -20, -4, 4] [0, 0, 3, 0, -1, 0, 0, 0, 3, 0, 1, 0, -8, 0, -1, 0] [0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, -1, 0, 0, 0] [0, 3, -1, 0, 3, -1, 8, 0, -9, 1, 1, -2, -4, -10, 0, -2] [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 1/2, 1/3, 1/4, 3/4, 1/6, 1/8, 3/8, 1/12, 7/12, 1/16, 1/24, 7/24, 1/32, 1 /48, 1/96] [96, 24, 32, 6, 6, 8, 3, 3, 2, 2, 3, 1, 1, 3, 1, 1] [1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1] [1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1] 16 6442450944 15917322219892801768783872 97 10 88 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] "TR([96, 6, 1, y])" "CONST([])" [-2, -4] [0, 72, -2, -4, -12, -16, -90, -8, 424, -8, -300, -8, -396, -16, 944, -976] [0, 0] [0, 10, 0, 0, 0, -76, 0, 0, 0, 810, 0, 0, 0, 12, 0, 0] [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0] [Mod(0, t^2 + t + 1), Mod(1, t^2 + t + 1), Mod(-t - 1, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(t, t^2 + t + 1), Mod(-1, t^2 + t + 1), Mod(0, t^2 + t + 1) , Mod(0, t^2 + t + 1), Mod(1, t^2 + t + 1), Mod(t, t^2 + t + 1), Mod(t + 1, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(-t - 1, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(0, t^2 + t + 1)] [Mod(0, t^4 + t^3 + t^2 + t + 1), Mod(1, t^4 + t^3 + t^2 + t + 1), Mod(t^3, t^4 + t^3 + t^2 + t + 1), Mod(t^2 + t, t^4 + t^3 + t^2 + t + 1), Mod(t, t^4 + t^3 + t^2 + t + 1), Mod(0, t^4 + t^3 + t^2 + t + 1), Mod(-t^3 - t^2 - t, t ^4 + t^3 + t^2 + t + 1), Mod(0, t^4 + t^3 + t^2 + t + 1), Mod(-t^3 - t^2 - t - 1, t^4 + t^3 + t^2 + t + 1), Mod(-t - 1, t^4 + t^3 + t^2 + t + 1), Mod(0, t^4 + t^3 + t^2 + t + 1), Mod(-t^3 - t^2 - t - 1, t^4 + t^3 + t^2 + t + 1), Mod(t^3 + t^2, t^4 + t^3 + t^2 + t + 1), Mod(0, t^4 + t^3 + t^2 + t + 1), M od(0, t^4 + t^3 + t^2 + t + 1), Mod(0, t^4 + t^3 + t^2 + t + 1)] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2] [0, 2, -2, 0, -12, 0, 28, -16, 40, -2, -56, 0, -56, 0, 16, 112] [0, 1, -1, -1, -1, 1, 1, 0, 3, 1, -1, -4, 1, -2, 0, -1] [0, 2, 4, 0, -6, 0, -6, -4, -36, 18, -10, 28, -24, 96, 36, 30] [15, 4, 1, y] 8 [4, 1, [0, 4, 0, -48, 0, 216, 0, -352, 0, -396]] [4, 2, [0, 0, 7, 0, 0, 0, -84, 0, 0, 0]] 72 [3, 1, [0, 4, -24, 36, 16, 24, -216, -160, 672, 324]] [3, 2, [0, 0, 7, 0, -42, 0, 63, 0, 28, 0]] 6 62 16 10 [[2717/14336, 3993/28672, 185/14336, 2717/14336, 3993/28672, 185/14336; -103 /4608, 65/3072, -7/4608, 103/4608, -65/3072, 7/4608; 225/57344, -95/114688, -123/57344, 225/57344, -95/114688, -123/57344; 5/1024, -49/18432, 13/9216, - 5/1024, 49/18432, -13/9216; 1/2048, -5/12288, -1/6144, -1/2048, 5/12288, 1/6 144; 31/57344, -33/114688, -5/57344, 31/57344, -33/114688, -5/57344; -7/9216 , 1/18432, -1/3072, 7/9216, -1/18432, 1/3072; -5/28672, -1/57344, -1/28672, -5/28672, -1/57344, -1/28672; 1/2048, -1/36864, 1/18432, -1/2048, 1/36864, - 1/18432; -11/57344, -115/1032192, 9/57344, -11/57344, -115/1032192, 9/57344] , [y, y, y, y, y, y, y^2 - 31, y^2 - 31]] [[2717/14336, 3993/28672, 185/14336, 2717/14336, 3993/28672, 185/14336, Mod( -4227/888832*y + 4539/57344, y^2 - 31), Mod(-4227/888832*y + 4539/57344, y^2 - 31); -103/4608, 65/3072, -7/4608, 103/4608, -65/3072, 7/4608, Mod(-29/952 32*y + 179/6144, y^2 - 31), Mod(29/95232*y - 179/6144, y^2 - 31); 225/57344, -95/114688, -123/57344, 225/57344, -95/114688, -123/57344, Mod(785/3555328* y - 109/229376, y^2 - 31), Mod(785/3555328*y - 109/229376, y^2 - 31); 5/1024 , -49/18432, 13/9216, -5/1024, 49/18432, -13/9216, Mod(13/571392*y - 67/3686 4, y^2 - 31), Mod(-13/571392*y + 67/36864, y^2 - 31); 1/2048, -5/12288, -1/6 144, -1/2048, 5/12288, 1/6144, Mod(-13/380928*y + 1/24576, y^2 - 31), Mod(13 /380928*y - 1/24576, y^2 - 31); 31/57344, -33/114688, -5/57344, 31/57344, -3 3/114688, -5/57344, Mod(-81/3555328*y - 19/229376, y^2 - 31), Mod(-81/355532 8*y - 19/229376, y^2 - 31); -7/9216, 1/18432, -1/3072, 7/9216, -1/18432, 1/3 072, Mod(17/571392*y + 19/36864, y^2 - 31), Mod(-17/571392*y - 19/36864, y^2 - 31); -5/28672, -1/57344, -1/28672, -5/28672, -1/57344, -1/28672, Mod(-5/1 777664*y + 13/114688, y^2 - 31), Mod(-5/1777664*y + 13/114688, y^2 - 31); 1/ 2048, -1/36864, 1/18432, -1/2048, 1/36864, -1/18432, Mod(1/1142784*y - 19/73 728, y^2 - 31), Mod(-1/1142784*y + 19/73728, y^2 - 31); -11/57344, -115/1032 192, 9/57344, -11/57344, -115/1032192, 9/57344, Mod(461/31997952*y + 151/206 4384, y^2 - 31), Mod(461/31997952*y + 151/2064384, y^2 - 31)], [y, y, y, y, y, y, y^2 - 31, y^2 - 31]] [1, 1, 1, 1, 1, 1, 2, 2] [[2717/14336, 3993/28672, 185/14336, 2717/14336, 3993/28672, 185/14336; -103 /4608, 65/3072, -7/4608, 103/4608, -65/3072, 7/4608; 225/57344, -95/114688, -123/57344, 225/57344, -95/114688, -123/57344; 5/1024, -49/18432, 13/9216, - 5/1024, 49/18432, -13/9216; 1/2048, -5/12288, -1/6144, -1/2048, 5/12288, 1/6 144; 31/57344, -33/114688, -5/57344, 31/57344, -33/114688, -5/57344; -7/9216 , 1/18432, -1/3072, 7/9216, -1/18432, 1/3072; -5/28672, -1/57344, -1/28672, -5/28672, -1/57344, -1/28672; 1/2048, -1/36864, 1/18432, -1/2048, 1/36864, - 1/18432; -11/57344, -115/1032192, 9/57344, -11/57344, -115/1032192, 9/57344] , [y, y, y, y, y, y]] [[2717/14336, 3993/28672, 185/14336, 2717/14336, 3993/28672, 185/14336, Mod( -4227/888832*y + 4539/57344, y^2 - 31), Mod(-4227/888832*y + 4539/57344, y^2 - 31); -103/4608, 65/3072, -7/4608, 103/4608, -65/3072, 7/4608, Mod(-29/952 32*y + 179/6144, y^2 - 31), Mod(29/95232*y - 179/6144, y^2 - 31); 225/57344, -95/114688, -123/57344, 225/57344, -95/114688, -123/57344, Mod(785/3555328* y - 109/229376, y^2 - 31), Mod(785/3555328*y - 109/229376, y^2 - 31); 5/1024 , -49/18432, 13/9216, -5/1024, 49/18432, -13/9216, Mod(13/571392*y - 67/3686 4, y^2 - 31), Mod(-13/571392*y + 67/36864, y^2 - 31); 1/2048, -5/12288, -1/6 144, -1/2048, 5/12288, 1/6144, Mod(-13/380928*y + 1/24576, y^2 - 31), Mod(13 /380928*y - 1/24576, y^2 - 31); 31/57344, -33/114688, -5/57344, 31/57344, -3 3/114688, -5/57344, Mod(-81/3555328*y - 19/229376, y^2 - 31), Mod(-81/355532 8*y - 19/229376, y^2 - 31); -7/9216, 1/18432, -1/3072, 7/9216, -1/18432, 1/3 072, Mod(17/571392*y + 19/36864, y^2 - 31), Mod(-17/571392*y - 19/36864, y^2 - 31); -5/28672, -1/57344, -1/28672, -5/28672, -1/57344, -1/28672, Mod(-5/1 777664*y + 13/114688, y^2 - 31), Mod(-5/1777664*y + 13/114688, y^2 - 31); 1/ 2048, -1/36864, 1/18432, -1/2048, 1/36864, -1/18432, Mod(1/1142784*y - 19/73 728, y^2 - 31), Mod(-1/1142784*y + 19/73728, y^2 - 31); -11/57344, -115/1032 192, 9/57344, -11/57344, -115/1032192, 9/57344, Mod(461/31997952*y + 151/206 4384, y^2 - 31), Mod(461/31997952*y + 151/2064384, y^2 - 31)], [y, y, y, y, y, y, y^2 - 31, y^2 - 31]] [0, 1, 0, 9, 0, 26, 0, 36, 0, 81, y] [0, 1, 0, 9, 0, -14, 0, -100, 0, 81, y] [0, 1, 0, 9, 0, -86, 0, 180, 0, 81, y] [0, 1, 0, -9, 0, 26, 0, -36, 0, 81, y] [0, 1, 0, -9, 0, -14, 0, 100, 0, 81, y] [0, 1, 0, -9, 0, -86, 0, -180, 0, 81, y] [Mod(0, y^2 - 31), Mod(1, y^2 - 31), Mod(0, y^2 - 31), Mod(9, y^2 - 31), Mod (0, y^2 - 31), Mod(16*y + 18, y^2 - 31), Mod(0, y^2 - 31), Mod(16*y + 60, y^ 2 - 31), Mod(0, y^2 - 31), Mod(81, y^2 - 31), y^2 - 31] [Mod(0, y^2 - 31), Mod(1, y^2 - 31), Mod(0, y^2 - 31), Mod(-9, y^2 - 31), Mo d(0, y^2 - 31), Mod(16*y + 18, y^2 - 31), Mod(0, y^2 - 31), Mod(-16*y - 60, y^2 - 31), Mod(0, y^2 - 31), Mod(81, y^2 - 31), y^2 - 31] [Mod(0, y^2 - 31), Mod(0, y^2 - 31), Mod(1, y^2 - 31), Mod(0, y^2 - 31), Mod (-18, y^2 - 31), Mod(0, y^2 - 31), Mod(32*y + 117, y^2 - 31), Mod(0, y^2 - 3 1), Mod(-320*y - 444, y^2 - 31), Mod(0, y^2 - 31), Mod(864*y + 9502, y^2 - 3 1), Mod(0, y^2 - 31), Mod(-2304*y - 19690, y^2 - 31), Mod(0, y^2 - 31), Mod( 2592*y + 16536, y^2 - 31), 0] 22 [4, -7, 11, 0, 0, 0, 0, 0, 0, 0]~ [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 81 0 0 4887/7 0 0 0 45522/7 0] [1 0 0 0 0 -264 0 1422 0 0] [0 0 0 0 477/28 0 81 0 1269/7 0] [0 0 0 0 0 61 0 -152 0 81] [0 0 0 0 0 12 0 12 0 0] [0 0 0 0 171/28 0 0 0 27/7 0] [0 0 1 0 0 -7 0 40 0 0] [0 0 0 0 9/14 0 0 0 -27/7 0] [0 0 0 0 0 2 0 -19 0 0] [0 0 0 1 -95/28 0 0 0 -71/7 0] [[81, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 81, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 81, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 81, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 81, 0, 0, 0, 0 , 0; 0, 0, 0, 0, 0, 81, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 81, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 81, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 81, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 81], [0, 0, 0, 155223/7, -647676/7, 0, 1574721/7, 0, 2180790/7, 0; 0, 0, 8068, 0, 0, -45888, 0, -25888, 0, 86508; 0, 81, 0, 22293/28, -8640/7, 0, -6 0507/28, 0, -63009/14, 0; 0, 0, -288, 0, 0, 2656, 0, 4468, 0, -8424; 0, 0, - 27, 0, 0, -42, 0, -1482, 0, 81; 0, 0, 0, -909/28, 540/7, 0, -11421/28, 0, -1 791/14, 0; 1, 0, 120, 0, 0, -808, 0, -550, 0, 2592; 0, 0, 0, 549/14, -1674/7 , 0, 3159/14, 0, 801/7, 0; 0, 0, -63, 0, 0, 467, 0, 266, 0, -810; 0, 0, 0, - 167/28, 148/7, 0, 12393/28, 0, 8891/14, 0], [-2434/7, 0, 300738/7, 0, 0, 229 0482/7, 0, 16881306/7, 0, 11792304/7; 0, 4943, 0, 78792, -67632, 0, 416424, 0, 265872, 0; -747/28, 0, 39517/14, 0, 0, -329463/14, 0, 567081/14, 0, -1517 13/7; 0, -288, 0, -4237, -8472, 0, -39276, 0, -47928, 0; 0, -27, 0, -972, 16 43, 0, -2754, 0, 108, 0; -141/28, 0, -5811/14, 0, 0, -12575/14, 0, -11937/14 , 0, -58239/7; 0, 120, 0, 1320, -1440, 0, 13151, 0, 18000, 0; 39/14, 0, 1299 /7, 0, 0, -1269/7, 0, 15800/7, 0, 12312/7; 0, -63, 0, -618, 408, 0, -4356, 0 , -6337, 0; 153/28, 0, 2463/14, 0, 0, -13443/14, 0, -22899/14, 0, 37304/7]] 0.43212772973212385449512289817170941385 0.065367804723930579823031060437204674227 -3.2767866024378219074845099715117890907 0.34284913090478965797177570867964351435 -0.76125796339716986841247525017762663821 0.49159382167950494101715310718716918356 -0.49676146954567727676850448728844180079 -52.340285691058552832964253754168105742 1.0398936863409539900708802050121051862 183.58598430613706225199581706089347024 5.1579000625428403504184801623630511115 E-16 3.4870504895354529381700292194184810754 E-6 [1, 1] [1/23, 1/23] [1/23, 1/23] [12709878029020295059028381417601, 12709844797213685207966660148549] [0, -4186596901512170847892276510318430 - 1173029439813149005414471837402481 *I, (3714866976289080663253111389348917 + 2259060652327972078839134831842555 *I)*y] [0, 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920, 534612 , -370944, -577738, 401856, 1217160] [0] [633/1792 351/1024 10819/896 67047/1792 267993/1792 102867/896 5265/3584 -14 7319/896 -906249/1792 81] [19/256 -3/8 267/128 -17/16 -81/8 7013/128 -205/16 24615/128 -497/8 6117/64] [87/7168 -9/4096 -591/3584 1135/7168 -22815/7168 12357/3584 49113/14336 -457 77/3584 48943/7168 1215/128] [-1/512 1/16 -41/256 -5/32 59/16 -1447/256 143/32 -3613/256 283/16 -1063/128 ] [1/1024 3/256 -39/512 3/32 -3/64 -121/512 -3/128 -3/512 39/64 -321/256] [9/7168 9/4096 47/3584 -879/7168 799/7168 1371/3584 -7641/14336 -3407/3584 2 769/7168 81/128] [1/512 -1/128 25/256 1/16 -23/32 7/256 -55/64 637/256 -101/32 223/128] [-1/3584 9/2048 -27/1792 65/3584 255/3584 -171/1792 135/7168 111/1792 -79/35 84 0] [-1/1024 1/128 -9/512 1/64 1/4 -103/512 5/16 -733/512 23/16 -151/256] [-5/7168 19/4096 61/3584 171/7168 -1371/7168 -687/3584 3965/14336 2963/3584 4267/7168 -81/128] [1 0 0] [0 1 0] [0 0 1] [0, 0, 0, 18, 0, 224, 0, 440, 0, 0, 0, 840, 0, 192, 0, 900] [1] [17.981439237735731033658522362934698192, -14.465932470400861049133659073570 007347, -14.173043447523315720648161399342292854, -12.8444792338479425607250 88799397162586, -12.673296763439189428830632012708642221, 11.313822387102528 758430335085165159676, 15.809242390926312020182669681356476477, 19.952518856 726468490501784413242971475, 12.164217722077195145237910274949933293, 15.381 272600128290391693466194368971580] [149.32003336233083380416740549931024313, -145.22528341237431879984196577788 550379, -144.05206065368915254369133157416377264, -137.368077052425797668068 45719565543525, -136.68537976117761802503641918389974975, 132.33498216866595 894851650979950974707, 144.81477270149742577794938046771306641, 153.37574451 331022295236625862817598070, 133.99393725109713614517615928616029184, 140.82 191407690427938490321804273819109] [1750.8612976244284982995145051957076323, -1743.4610846371885006840699908522 210646, -1739.3285039438314041396755906212872382, -1706.54568655078571155570 67243660579136, -1704.1559309139961646459809162176700473, 1693.2006899626197 396492113391602468661, 1739.6937549158404780145317707347222603, 1760.8038249 508416117204235666645232767, 1696.9537629837898396249480554755379813, 1714.4 123077300799878900824934093074081] [-25289.463103882493149683693231641947547, 25271.306252281313102094765195122 776006, 25256.284246728344311859481152424676239, 25079.367724015404662920284 476322170148, 25070.741444350281949178792195757223585, -25040.19987820531753 6042355830671301459, -25256.861209437637891371256419970666372, -25318.141977 898178949067363044347232866, -25050.025763197973566457964437905037423, -2510 2.674289656622081201236099263608944] 0.15111211321192334885298629517871164534 -0.029981366891420022975489657187955538024 1 [0, 1, -4, 2, 8, -5, -8, 6, 0, -23] [0, t, -4*t^2, 2*t^3, -8*t^3 - 8*t^2 - 8*t - 8, -5, -8*t, 6*t^2, 0, 23*t^3 + 23*t^2 + 23*t + 23, 20] [0, 5, [1, 0; 0, 1]] [0, 1, -2, -1, 2, 1] [0, 1, [1, 0; 0, 1]] [1/4, 0, 0, 0, 0] [1/2, 11, [1, 0; 0, 1]] [0, 0.0083160068527003923763819239796690829905 + 0.0186369836048978260765912 63978546433841*I, 0.040773714507830673270468368068835601812 - 0.001864595582 8220482074272494197134258875*I, 0.046062126409693852745000230038901860300 - 0.13522737805608561952910766786281685190*I, -0.07682530715670062861328778204 2554261372 + 0.027600040327739509297577443995295764564*I, -0.125743903939079 05970350003436207154062 + 0.067798479979021507423866878355650878637*I] [0, 7, [1, 0; 0, 1]] [0, 0, 0, 0.66666666666666666666666666666666666667 + 0.E-38*I, 0, -4.0000000 000000000000000000000000000000 + 6.9282032302755091741097853660234894676*I, 0, -11.999999999999999999999999999999999999 - 20.784609690826527522329356098 070468402*I, 0, 0, 0, 20.000000000000000000000000000000000024 - 34.641016151 377545870548926830117447370*I, 0] [Mod(0, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(2/3, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(8*t, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(-24*t - 24, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod( 0, t^2 + t + 1), Mod(-40*t, t^2 + t + 1), Mod(0, t^2 + t + 1)] [-5/32, 81/32, 21/16, -597/8, 1215/32, 1689/8, -14813/16, -14337/16] [1/2, 1, [1, 0; 0, 1]] [Mod(0, t^2 + t + 1), Mod(0, t^2 + t + 1), Mod(2/3*t, t^2 + t + 1), Mod(-2/3 , t^2 + t + 1), Mod(4/3*t + 4/3, t^2 + t + 1)] 1 [Mod(61/256*t, t^2 + 1), Mod(-1/64*t, t^2 + 1), Mod(-1/64*t, t^2 + 1), Mod(9 1/8*t, t^2 + 1), Mod(-1/64*t, t^2 + 1), Mod(-7813/32*t, t^2 + 1)] [0, 1, [1, 0; 0, 1]] [Mod(0, t^2 + 1), Mod(-t, t^2 + 1), Mod(0, t^2 + 1), Mod(2*t, t^2 + 1)*y] [0, 1, [1, 0; 0, 1]] [0, 0, -0.026871677793768185811758182803469159206 - 0.0427660302192192146895 36937410383070596*I, 0, -0.016681611742316464491440499523538796306 - 0.04767 3307393570615953995380441278707349*I, 0] [ 0 1] [-1 0] 1 [1/4 1/4] [1/4 -1/4] 0.35355339059327376220042218105242451964 [x + Mod(-t, t^2 + 1) 2] [ x + Mod(t, t^2 + 1) 2] 1 [[I, -I, -I, I, I, -I]] [[0.33333333333333333333333333333333333334 + 0.94280904158206336586779248280 646538571*I, -0.33333333333333333333333333333333333334 + 0.94280904158206336 586779248280646538571*I]] [[-1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] [1, 0, 240, 0, 2160, 0, 6720, 0, 17520, 0, 30240] [0, -1, -1, 1, -1, -1, 1, 2, -1, 2, -1] [5/2*x, x, 2*x, 0, 3*x, 2*x] [ 3 3] [-1/3 -3] [1/4, -1/4]~ [0, 1, 0, -3, 0, -2, 0, -4, 0, 6, 0, 2, 0, -5, 0, 6] [0, 0, 0, 0, 0, 0, 0] [64/5, 4/5, 32/5]~ [1, 20, 180, 960, 3380, 8424, 16320, 28800, 52020, 88660, 129064, 175680, 26 2080, 386920, 489600, 600960] [1, 180, 3380, 16320, 52020, 129064, 262080] [0, 4, -16, 0, 64, -56, 0, 0, -256, 324, 224, 0, 0, -952, 0, 0] [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [3, 12, 12, 0, 12, 24, 0, 0, 12, 12, 24, 0, 0, 24, 0, 0] 23: [[22, [[0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0]]]] 31: [[30, [[0, 1, -1, 0, 0, -1, 0, -1, 1, 1, 1, 0, 0, 0, 1, 0]]]] 39: [[38, [[0, 1, 0, -1, -1, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0]]]] 44: [[21, [[0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1]]]] 46: [[45, [[0, 1, 0, -1, -1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0], [0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0]]]] 47: [[46, [[0, 1, 0, -1, 0, 0, -1, 0, -1, 1, 0, 0, 1, 0, 1, 0], [0, 0, 1, -1 , -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0]]]] 52: [[3, [[0, 1, -t - 1, 0, t, -1, 0, 0, 1, t, t + 1, 0, 0, -t - 1, 0, 0]]]] 55: [[54, [[0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0]]]] 56: [[13, [[0, 1, -1, 0, 1, 0, 0, -1, -1, -1, 0, 0, 0, 0, 1, 0]]]] 57: [[26, [[0, 1, 0, -t - 1, t, 0, 0, -1, 0, t, 0, 0, 1, -t, 0, 0]]]] 59: [[58, [[0, 1, 0, -1, 1, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 1]]]] 62: [[61, [[0, 1, 0, 0, -1, -1, 0, -1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0]]]] 63: [[55, [[0, 1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0]]]] 68: [[67, [[0, 1, -1, 0, 1, 0, 0, 0, -1, -1, 0, 0, 0, -2, 0, 0]]], [47, [[0, 1, t, 0, -1, -t - 1, 0, 0, -t, t, -t + 1, 0, 0, 0, 0, 0]]]] 69: [[22, [[0, 1, -1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, -1, 0, 0], [0, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0]]]] 71: [[70, [[0, 1, 0, 0, 0, -1, -1, 0, 0, 1, 0, 0, -1, 0, 0, -1], [0, 0, 1, 0 , -1, -1, -1, 0, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, -1, -1, 0, 0, 1, 0, 1 , 0, 0, 0, 0, -1]]]] 72: [[67, [[0, 1, -t - 1, -t - 1, t, 0, t, 0, 1, t, 0, t + 1, 1, 0, 0, 0]]]] 76: [[37, [[0, 1, 0, 0, 0, -1, 0, -1, 0, 1, 0, -1, 0, 0, 0, 0]]]] 77: [[69, [[0, 1, t^3 + t, 0, -t^3 - 1, 0, 0, -t^3 - t^2 - t - 1, -t, t^2, 0 , t^3, 0, 0, t^2 + 1, 0]]]] 78: [[77, [[0, 1, 0, -1, -1, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0], [0, 0, 1, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0]]]] 79: [[78, [[0, 1, 0, 0, 0, -1, 0, 0, -1, 1, -1, 0, 0, 0, 0, 0], [0, 0, 1, 0, -1, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0]]]] 80: [[79, [[0, 1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0]]]] 83: [[82, [[0, 1, 0, -1, 1, 0, 0, -1, 0, 0, 0, -1, -1, 0, 0, 0]]]] 84: [[65, [[0, 1, 0, -t - 1, 0, 0, 0, t, 0, t, 0, 0, 0, -1, 0, 0]]]] 87: [[86, [[0, 1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, -1, 0, 0], [0, 0, 1, -1 , 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, -1, 0]]]] 88: [[65, [[0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], [0, 0, 1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0]]], [59, [[0, 1, t^3, t^2 + t, t, 0, -t ^3 - t^2 - t, 0, -t^3 - t^2 - t - 1, -t - 1, 0, -t^3 - t^2 - t - 1, t^3 + t^ 2, 0, 0, 0]]]] 92: [[45, [[0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0], [0, 0, 1, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0]]]] 93: [[61, [[0, 1, -1, 0, 0, -1, 0, -1, 1, 1, 1, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1]]], [47, [[0, 1, 0, t^3, -t^3 - t^2 - t - 1, 0, 0, t^2 + t, 0, t, 0, 0, t^2, -t^3 - t - 1, 0, 0]]]] 94: [[93, [[0, 1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, -1, 1, -1, 0, 0 , -1, 0, 0, 0], [0, 0, 0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0]]]] 95: [[94, [[0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0], [0, 0, 1, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, 1, 0, 1], [0, 0, 0, 0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0]]]] 99: [[76, [[0, 1, 0, t, t, -t, 0, 0, 0, -t - 1, 0, -t - 1, -t - 1, 0, 0, t + 1]]]] 100: [[91, [[0, 1, t^3, 0, t, -t^3 - t^2 - t - 1, 0, 0, -t^3 - t^2 - t - 1, t^2, t^2, 0, 0, t^3 + t, 0, 0]]]] 103: [[102, [[0, 1, 0, 0, 0, 0, 0, -1, -1, 1, 0, 0, 0, 0, -1, 0], [0, 0, 1, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0]]]] 104: [[51, [[0, 1, 0, -1, 1, 0, 0, 0, 0, 0, -1, 0, -1, 0, -1, 0], [0, 0, 1, 0, 0, -1, -1, -1, 1, 0, 0, 0, 0, 1, 0, 1]]], [55, [[0, 1, 0, 0, 0, -1, 0, 0, 0, t, 0, 0, 0, -t - 1, 0, 0], [0, 0, 1, 0, -t - 1, 0, 0, 0, t, 0, -1, 0, 0, 0, 0, 0]]]] 107: [[106, [[0, 1, 0, -1, 1, 0, 0, 0, 0, 0, 0, -1, -1, -1, 0, 0]]]] 108: [[53, [[0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0]]]] 110: [[109, [[0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0]]]] 111: [[110, [[0, 1, 0, 0, 0, 0, 0, -1, 0, 1, -1, 0, -1, 0, 0, 0], [0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 1, -1, 0, 0, -1, 0, 0, 1 , 0, 0, 0, 0, 0]]], [101, [[0, 1, 0, -t - 1, t + 1, 0, 0, -t - 1, 0, t, 0, 0 , -t, t - 1, 0, 0]]], [26, [[0, 1, 0, t, t, 0, 0, -t, 0, -t - 1, 0, 0, -t - 1, -t, 0, 0]]]] 112: [[41, [[0, 1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0]]], [69, [[0, 1, t, 0, -1, 0, 0, t, -t , -t, 0, -t - 1, 0, 0, -1, 0]]]] 114: [[83, [[0, 1, 0, -t - 1, t, 0, 0, -1, 0, t, 0, 0, 1, -t, 0, 0], [0, 0, 1, 0, 0, 0, -t - 1, 0, t, 0, 0, 0, 0, 0, -1, 0]]]] 115: [[91, [[0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0], [0, 0, 0, 0 , 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1]]]] 116: [[115, [[0, 1, 0, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0], [0, 0, 1, -1, 0, 0, 0, 0, 1, 0, -1, -1, -1, 0, 0, 1]]], [103, [[0, 1, t^4, 0, t, -t^5 - t^4 - t^3 - t - 1, 0, 0, t^5, t^5, -t^5 - t^4 - t^2 - t - 1, 0, 0, t^3 + t , 0, 0]]]] 117: [[116, [[0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0], [0, 0, 0, 1 , 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0]]], [73, [[0, 1, 0, 0, -t, 0, 0, t - 1, 0, 0, 0, 0, 0, t, 0, 0]]]] 118: [[117, [[0, 1, 0, -1, 1, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 1], [0, 0, 1, 0, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, -1, 0]]]] 119: [[118, [[0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1], [0, 0, 1, 0 , -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, -2, -1, 0, 0, 1, 0, 2, 0, 1, 0], [0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0]]]] 120: [[29, [[0, 1, 0, 0, -1, 0, -1, 0, 0, -1, 1, 0, 0, 0, 0, 1], [0, 0, 1, 1 , 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0]]]] 124: [[61, [[0, 1, 0, 0, 0, -1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, -1, 0], [0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0]]], [87, [[0, 1, 0, 0, -1, t, -t - 1, 0, 0, 0, 0, 0, 0, -t, t + 1, 0], [0, 0, 1, t + 1, 0, 0, 0, -t - 1, -1, 0, t, -t, -t - 1, 0, 0, -1]]] ] 126: [[55, [[0, 1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0]]]] 127: [[126, [[0, 1, 0, 0, 0, 0, 0, 0, -1, 1, 0, -1, 0, -1, 0, 0], [0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0]]]] 128: [[63, [[0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0]]]] 129: [[41, [[0, 1, 0, t^4, -t^5 - t^4 - t^3 - t^2 - t - 1, 0, 0, t^5 + t^2, 0, t, 0, 0, t^3, t^3 + t, 0, 0]]]] 131: [[130, [[0, 1, 0, 0, 1, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1], [0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 1, 1, 0, 0]]]] 132: [[109, [[0, 1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1 , 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1]]]] 133: [[83, [[0, 1, -t - 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, t], [0, 0, 0 , 1, 0, -1, -t - 1, t, 0, 0, t + 1, 0, 0, -t - 1, 1, 0]]], [37, [[0, 1, 0, 0 , -t - 1, -t, 0, t, 0, t, 0, t + 1, 0, 0, 0, 0]]]] 135: [[134, [[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0]]]] 136: [[135, [[0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, -2, 0, 0], [0, 0, 1, 0 , -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]]], [67, [[0, 1, -1, 0, 1, 0, 0, 0, -1 , 1, 0, 0, 0, 0, 0, 0]]], [47, [[0, 1, 0, 0, 0, -t - 1, 0, 0, 0, t, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, t, 0, 0, 0, -1, 0, -t - 1, 0, 0, 0, 0, 0]]], [115, [ [0, 1, -t, -t - 1, -1, 0, t - 1, 0, t, t, 0, -t + 1, t + 1, 0, 0, 0]]], [43, [[0, 1, t^3, -t^3 + t^2, -t^2, 0, t^2 - t, 0, t, -t^2 + t - 1, 0, t^3 - 1, -t + 1, 0, 0, 0]]]] 138: [[91, [[0, 1, 0, 0, -1, 0, 0, 0, 1, -1, 0, 0, 0, -1, 0, 0], [0, 0, 1, 0 , -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0 , -1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0]]]] 139: [[138, [[0, 1, 0, 0, 1, -1, 0, -1, 0, 1, 0, -1, 0, -1, 0, 0]]]] 140: [[69, [[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1], [0, 0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0]]], [79, [[0, 1, 0, 0, -t - 1, t, -1, 0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 1, -t, 0, 0, 0, t, -t - 1, 0, t, 0, -1, 0 , 0, t + 1]]]] 141: [[46, [[0, 1, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 1, 0], [0, 0, 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0 , 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, 0]]]] 142: [[141, [[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, -1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, -1, 0, 0, -1, 0, 0, -1], [0, 0, 0, 0, 1, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0]]]] 143: [[142, [[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0], [0, 0, 1, 0 , 0, 0, 0, -2, -1, 0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, -1, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0]]]] 144: [[127, [[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0]]], [103, [[0, 1, 0, -t - 1, 0, 0, 0, 0, 0, t, 0, t + 1, 0, 0, 0, 0], [0, 0, 1, 0, -t - 1, 0, -t - 1, 0, t, 0, 0, 0, t, 0, 0, 0]]]] 145: [[99, [[0, 1, 0, 0, t, -t, 0, 0, 0, t, 0, -t - 1, 0, 0, 0, 0]]], [57, [ [0, 1, 0, 0, t, t, 0, -t - 1, 0, -t, 0, 0, 0, -t + 1, 0, 0]]]] 147: [[92, [[0, 1, 0, t^4, t^5, 0, 0, -t^5 - t^4 - t^3 - t^2 - t - 1, 0, t, 0, 0, t^2, t^3 + t^2, 0, 0]]]] 148: [[105, [[0, 1, 0, -t, 0, 0, 0, -1, 0, 0, 0, t, 0, 0, 0, 0]]], [63, [[0, 1, -t - 1, 0, t, -t, 0, 0, 1, -t - 1, -1, 0, 0, 2*t, 0, 0]]], [127, [[0, 1, t^5, 0, t, t^3 + t^2, 0, 0, -t^3 - 1, -t^5 - t^2, -t^5 - t^4 - t^2 - t, 0, 0, -t, 0, 0]]]] [1, 0, 0] [2, 0, 0] [3, 0, 0] [4, 0, 0] [5, 0, 0] [6, 0, 0] [7, 0, 0] [8, 0, 0] [9, 0, 0] [10, 0, 0] [11, 0, 0] [12, 0, 0] [13, 0, 0] [14, 0, 0] [15, 0, 0] [16, 0, 0] [17, 0, 0] [18, 0, 0] [19, 0, 0] [20, 0, 0] [21, 0, 0] [22, 0 , 0] [23, 1, 1] [24, 0, 0] [25, 0, 0] [26, 0, 0] [27, 0, 0] [28, 0, 0] [29, 0, 0] [30, 0, 0] [31, 1, 1] [32, 0, 0] [33, 0, 0] [34, 0, 0] [35, 0, 0] [36, 0, 0] [37, 0, 0] [38, 0, 0] [39, 1, 1] [40, 0, 0] [41, 0, 0] [42, 0, 0] [43 , 0, 0] [44, 1, 1] [45, 0, 0] [46, 2, 0] [47, 2, 2] [48, 0, 0] [49, 0, 0] [5 0, 0, 0] [51, 0, 0] [52, 2, 2] [53, 0, 0] [54, 0, 0] [55, 1, 1] [56, 1, 1] [ 57, 2, 2] [58, 0, 0] [59, 1, 1] [60, 0, 0] [61, 0, 0] [62, 2, 0] [63, 1, 1] [64, 0, 0] [65, 0, 0] [66, 0, 0] [67, 0, 0] [68, 3, 3] [69, 2, 0] [70, 0, 0] [71, 3, 3] [72, 2, 2] [73, 0, 0] [74, 0, 0] [75, 0, 0] [76, 1, 1] [77, 4, 4 ] [78, 2, 0] [79, 2, 2] [80, 1, 1] [81, 0, 0] [82, 0, 0] [83, 1, 1] [84, 2, 2] [85, 0, 0] [86, 0, 0] [87, 2, 2] [88, 6, 4] [89, 0, 0] [90, 0, 0] [91, 0, 0] [92, 3, 0] [93, 6, 4] [94, 4, 0] [95, 3, 3] [96, 0, 0] [97, 0, 0] [98, 0 , 0] [99, 2, 2] [100, 4, 4] [101, 0, 0] [102, 0, 0] [103, 2, 2] [104, 6, 2] [105, 0, 0] [106, 0, 0] [107, 1, 1] [108, 1, 1] [109, 0, 0] [110, 2, 0] [111 , 7, 7] [112, 4, 2] [113, 0, 0] [114, 4, 0] [115, 2, 0] [116, 8, 8] [117, 4, 2] [118, 2, 0] [119, 4, 4] [120, 2, 2] [121, 0, 0] [122, 0, 0] [123, 0, 0] [124, 7, 4] [125, 0, 0] [126, 2, 0] [127, 2, 2] [128, 1, 1] [129, 6, 6] [130 , 0, 0] [131, 2, 2] [132, 2, 0] [133, 6, 6] [134, 0, 0] [135, 2, 2] [136, 13 , 7] [137, 0, 0] [138, 4, 0] [139, 1, 1] [140, 6, 6] [141, 4, 0] [142, 6, 0] [143, 4, 4] [144, 5, 1] [145, 4, 4] [146, 0, 0] [147, 6, 6] [148, 10, 10] [ 149, 0, 0] [150, 0, 0] [[22, Mod(5, 23), 1, 0], [2, Mod(22, 23), 2, 1]] [[2, Mod(22, 23), 1, 1]] [[2, Mod(22, 23), 1, 1]] [] [[2, Mod(22, 23), 1, 0], [22, Mod(5, 23), 1, 0]] [[2, Mod(45, 46), 2, -1]] [[0, 0], [0, 0], [0, 0], [1, 1]] [[0, 0], [0, 0], [0, 0], [1, 1]] [[0, 0], [0, 0], [0, 0], [0, 0]] 98 193 95 127 320 [[1, Mod(1, 96), 2, 0], [2, Mod(95, 96), 4, 0], [2, Mod(49, 96), 2, 0], [2, Mod(47, 96), 2, 0], [8, Mod(37, 96), 8, 0], [8, Mod(59, 96), 14, 0]] [[1, Mod(1, 96), 9, 0], [2, Mod(95, 96), 8, 0], [2, Mod(49, 96), 8, 0], [2, Mod(47, 96), 8, 0], [4, Mod(25, 96), 12, 0], [4, Mod(71, 96), 12, 0], [8, Mo d(37, 96), 14, 0], [8, Mod(59, 96), 14, 0]] [[1, Mod(1, 96), 7, 0], [2, Mod(95, 96), 4, 0], [2, Mod(49, 96), 6, 0], [2, Mod(47, 96), 6, 0], [4, Mod(25, 96), 12, 0], [4, Mod(71, 96), 12, 0], [8, Mo d(37, 96), 6, 0]] [[1, Mod(1, 96), 15, 0], [2, Mod(95, 96), 16, 0], [2, Mod(49, 96), 16, 0], [ 2, Mod(47, 96), 16, 0], [4, Mod(25, 96), 8, 0], [4, Mod(71, 96), 8, 0], [8, Mod(37, 96), 4, 0], [8, Mod(59, 96), 4, 0]] [[1, Mod(1, 96), 24, 0], [2, Mod(95, 96), 24, 0], [2, Mod(49, 96), 24, 0], [ 2, Mod(47, 96), 24, 0], [4, Mod(25, 96), 20, 0], [4, Mod(71, 96), 20, 0], [8 , Mod(37, 96), 18, 0], [8, Mod(59, 96), 18, 0]] [[2, 0], [0, 0], [0, 0], [4, 0], [8, 0], [0, 0], [0, 0], [14, 0], [0, 0], [0 , 0], [0, 0], [0, 0], [2, 0], [0, 0], [0, 0], [2, 0]] [[9, 0], [0, 0], [0, 0], [8, 0], [14, 0], [0, 0], [0, 0], [14, 0], [12, 0], [0, 0], [0, 0], [12, 0], [8, 0], [0, 0], [0, 0], [8, 0]] [[7, 0], [0, 0], [0, 0], [4, 0], [6, 0], [0, 0], [0, 0], [0, 0], [12, 0], [0 , 0], [0, 0], [12, 0], [6, 0], [0, 0], [0, 0], [6, 0]] [[15, 0], [0, 0], [0, 0], [16, 0], [4, 0], [0, 0], [0, 0], [4, 0], [8, 0], [ 0, 0], [0, 0], [8, 0], [16, 0], [0, 0], [0, 0], [16, 0]] [[24, 0], [0, 0], [0, 0], [24, 0], [18, 0], [0, 0], [0, 0], [18, 0], [20, 0] , [0, 0], [0, 0], [20, 0], [24, 0], [0, 0], [0, 0], [24, 0]] 10 2 0 [1, 2, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0] [1/2 - 1/2*I, 0, 1/2 - 1/2*I, 1, -1.2548652488804080851212455162477386227 - 0.13774935502057657907313538946599934253*I] [0, 2, 0, 0, Mod(-2*t - 2, t^2 + t + 1), 0, 0, 0, 0, Mod(2*t, t^2 + t + 1), 0, 0, 0, 0, 0, 0] [196, 1/2, Mod(2, 7), y] [0, 2, 0, 0, Mod(4*t, t^2 + 1), 0, 0, 0, 0, Mod(-6*t, t^2 + 1), 0, 0, 0, 0, 0, 0] [100, 3/2, Mod(7, 20), y] [1, -264, -135432, -5196576, -69341448, -515625264, -2665843488, -1065335251 2, -35502821640, -102284205672, -264515760432, -622498190688, -1364917062432 , -2799587834736, -5465169838656, -10149567696576] [0, 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920, 534612 , -370944, -577738, 401856, 1217160] [1, 12, 1, 1] [1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920, 534612, - 370944, -577738, 401856, 1217160, 987136] [1/1728, 0, -1/20736, 0, 1/165888, 0, 1/497664, 0, -11/3981312, 0, 7/1592524 8] [0.0017853698506421519043430549603422623106, 0, -0.0171012292073417293156314 59010992410421, 0, 0.040951184469824320600328376773822139547, 0, 0.104600637 48004752177296678887319501733, 0, -0.59041770925463104960248994945766228175, 0, 0.23992339736027093580525099155844404883] 1 [1728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 1728, -41472, 435456, -2543616, 8346240, -10450944, -28933632, 145981440 , -196375104, -200309760, 923809536, -640991232, -998331264, 694407168, 2103 252480] [0, -504, -33264, -368928, -2130912, -7877520, -24349248] [0, -504, -8316, -40992, -133182, -1575504/5, -676368] [-1/2, -240, -30960, -525120, -3963120, -18750240, -67740480] [0, -8, 0, 0, 448, -960, 0, 0, 1920, -72, 0, 0, -11520, 10560, 0, 0] [0, -1, 24, -252, 1472, -4830, 6048, 16744, -84480, 113643, 115920] [y, y^2 + Mod(-t, t^2 + 1)*y + 32] [t^2 + 1, [1, I, -1, -I]] [0, 1, -4 - 4*I, -23 + 23*I, 32*I] [t^2 + 1, [1, I, -1, -I]] 2 [0, 1, 4 + 4*I, 23.894541729001368054461689919961782206 - 23.894541729001368 054461689919961782206*I, 32*I] [0, 1, 4 + 4*I, -32.894541729001368054461689919961782206 + 32.89454172900136 8054461689919961782206*I, 32*I] [ 1 I] [0.E-38 - 5.1789083458002736108923379839923564411*I 1/2] (-0.42032884322677921722469742108951886443 - 0.36665141119210363722276336624 357748307*I)*x^5 + (-0.18897096195310015252637690454628340018 + 0.2334775315 3997872645748275207133555666*I)*x^4 + (0.05669894077036206721138027675869498 5766 + 0.019851987390139195033288439780776993730*I)*x^3 + (-0.01778807113146 0726637976503215205801403 - 0.0066687070863864346224329592313502928776*I)*x^ 2 + (-0.00014285107000277589442425212918179977119 + 0.0094974404850612698333 714635028430975514*I)*x + (0.0017634098246564914212887661127367171167 - 3.84 93221223953106272210521959657558937 E-5*I) (-0.42032884322677921722469742108951886443 - 0.36665141119210363722276336624 357748307*I)*x^5 + (-0.18897096195310015252637690454628340018 + 0.2334775315 3997872645748275207133555666*I)*x^4 + (0.05669894077036206721138027675869498 5766 + 0.019851987390139195033288439780776993730*I)*x^3 + (-0.01778807113146 0726637976503215205801403 - 0.0066687070863864346224329592313502928776*I)*x^ 2 + (-0.00014285107000277589442425212918179977119 + 0.0094974404850612698333 714635028430975514*I)*x + (0.0017634098246564914212887661127367171167 - 3.84 93221223953106272210521959657558937 E-5*I) [(-0.11978968330084743941034336902296121263 + 0.6675712441890031614835686639 3309199760*I)*x^5 + (0.47459258827123214210389409418585137394 + 0.0738116455 79858397157878143011696499169*I)*x^4 + (0.0239881015411315413733797131896244 63396 - 0.19195836968288495139427189581460315486*I)*x^3 + (-0.06091879582539 5161943853589975161158104 - 0.0055897035583019227181012364528570531811*I)*x^ 2 + (-0.00093396277153707022978325343297000205630 + 0.0151596173238831031064 47349960285186585*I)*x + (0.0021431928592073859680903512704736845544 + 8.205 9193124110226533224704061362634241 E-5*I), (-0.62739345285811739127778056884 021600097 - 0.087390135179795679398135448226837566631*I)*x^5 + (0.0071366457 725152534775841805760933396780 + 0.40397833014354552911285996147380482698*I) *x^4 + (0.12891258393984629705652072463003358643 - 0.05228352106134393940156 8419229621475946*I)*x^3 + (-0.035464631571369665466140174106504828211 - 0.02 6028100099104453183586604526392274925*I)*x^2 + (-0.0033524403603294024998684 552942059280440 + 0.012329256529445897292427816673749766245*I)*x + (0.001991 1655001689021405322834054755664714 + 0.0002187595828686439236664039723449641 6014*I)] (-0.42032884322677921722469742108951886443 - 0.36665141119210363722276336624 357748307*I)*x^5 + (-0.18897096195310015252637690454628340018 + 0.2334775315 3997872645748275207133555666*I)*x^4 + (0.05669894077036206721138027675869498 5766 + 0.019851987390139195033288439780776993730*I)*x^3 + (-0.01778807113146 0726637976503215205801403 - 0.0066687070863864346224329592313502928776*I)*x^ 2 + (-0.00014285107000277589442425212918179977119 + 0.0094974404850612698333 714635028430975514*I)*x + (0.0017634098246564914212887661127367171167 - 3.84 93221223953106272210521959657558937 E-5*I) (0.63503857136548153723243364047328438986 + 3.514572428867635055012606515575 9628731*I)*x^5 + (-0.55372847947444593258698788340168966082 - 9.108921742882 8235118512107360613470523*I)*x^4 + (-0.5736853636153969172965804481164446308 3 + 9.3350094980459189288929480268625379486*I)*x^3 + (0.92067030358191022593 055872189272950582 - 4.7134500726338769290757263902171115959*I)*x^2 + (-0.40 943867072608376472339177571526455001 + 1.15651384868088764032207293563713484 07*I)*x + (0.059036856826078966302068066654747180072 - 0.1074704942638566941 6527151515690888886*I) (0.50591569408594293044173544719087511945 + 2.117281275622317566448200088099 4098275*I)*x^5 + (-0.50329189412202947783246908444432161287 - 5.590428274519 0468676320341127315401960*I)*x^4 + (-0.3497080814333576092739419971721942705 2 + 5.8131984654812768380493298366830104987*I)*x^3 + (0.67136183809998279160 852888055285137912 - 2.9619446659820968460170467417907610716*I)*x^2 + (-0.31 298236313441943447438431991727961780 + 0.72375422627359354753058812996616936 825*I)*x + (0.046021296425325344919105451970096214097 - 0.064981133287689249 704701491873473271745*I) (0.50591569408757962384361452599497966291 + 2.117281275639064594489871762594 8918260*I)*x^5 + (-0.50329189412193445432675932972323847027 - 5.590428274561 3236110866820457378951587*I)*x^4 + (-0.3497080814376803071251059760080492944 6 + 5.8131984655235440791534068179731335741*I)*x^3 + (0.67136183810425750258 930943563014705872 - 2.9619446660030143316765275738312612505*I)*x^2 + (-0.31 298236313601104936106517214476233040 + 0.72375422627871605117093909126879831 832*I)*x + (0.046021296425535731444176918743279766645 - 0.064981133288185583 919869819271833506431*I) (164.35262898335787004106106716673677130 + 27.238600223902468333759517924304 610904*I)*x^5 + (-271.95434178285557919428732408774729971 - 54.8341728611807 65120958234414937486873*I)*x^4 + (180.19514127347078229995469690124466357 + 41.691669235812561554783086959210566385*I)*x^3 + (-59.9543068680018830870208 43160703944761 - 15.111269706996669294559216350864552013*I)*x^2 + (10.065256 240339619831161098072464760373 + 2.6184808251354815164522274491363646980*I)* x + (-0.68672917564913976846740362654117485201 - 0.1732219127234492275765682 9146590865136*I) [(-37.400871663494856516636401987243309210 - 123.329800340743528756196753860 76255844*I)*x^5 + (53.268246125228312340154821977677892221 + 207.67678245211 016109263953978319052970*I)*x^4 + (-28.666898066293079278659311038421188987 - 139.64875858061674710101939900539440561*I)*x^3 + (6.8676880960045824324968 267496774844483 + 46.814934586818559059649732674905180429*I)*x^2 + (-0.59643 957211173608030883172017086163757 - 7.8046112726147121874007178376101555939* I)*x + (-0.0064055991688804413829736007101014212258 + 0.51526489380605352673 507681658732620789*I), (140.09242210378463676125436253030190949 - 46.3393403 38148920959200393601425458778*I)*x^5 + (-239.1537304828094629201233858532011 7138 + 64.836449022531128110429287661758992831*I)*x^4 + (162.744445131511330 16860078839933141537 - 33.558240643220739258219626272248254402*I)*x^3 + (-55 .079528297804953230956818685769222608 + 7.3487498203155016127222453918267226 450*I)*x^2 + (9.2420957758989707670959015639234112401 - 0.450495026534426142 94207267772156672859*I)*x + (-0.61189800800168155000144831291875936999 - 0.0 33316392602605981857006660342857673457*I)] 1.0024642466164642932880429736720212519 E-5 [1.0616767679426667234166859887525352956 E-5 0] [0 1.3579771881756813076319839557062773447 E-5] 1 1 [[((61893*t - 42501)*y + (-301056*t + 307452))*x^5 + ((-1166160*t + 897220)* y + (5999170*t - 11970090))*x^3 + ((2722848*t - 2437636)*y + (-14350096*t + 127683672))*x, ((-1556688*t + 1540416)*y + (8350926*t - 115713582))*x^5 + (( 775632*t - 254024)*y + (-3647414*t - 91773402))*x^4 + ((2332320*t - 1794440) *y + (-11998340*t + 23940180))*x^3 + ((-2332320*t + 1794440)*y + (11998340*t - 23940180))*x^2 + ((-775632*t + 254024)*y + (3647414*t + 91773402))*x + (( 1556688*t - 1540416)*y + (-8350926*t + 115713582)), ((-2034*t + 387138)*y + (-13420332*t - 9981516))*x^5 + ((-64862*t + 64184)*y + (-22679326*t - 186377 68))*x^4 + ((593250*t - 2384300)*y + (8836600*t + 627150))*x^3 + ((648620*t - 641840)*y + (5731360*t - 34684220))*x^2 + ((-1562112*t + 2572784)*y + (940 7024*t + 27149832))*x + 176849520, ((2034*t - 387138)*y + (-163429188*t + 99 81516))*x^5 + ((-2637646*t - 1497928)*y + (-49829158*t - 9230744))*x^4 + ((4 8590*t + 3032920)*y + (25847620*t + 5104210))*x^3 + ((3032920*t - 48590)*y + (5104210*t - 25847620))*x^2 + ((1497928*t - 2637646)*y + (9230744*t - 49829 158))*x + ((-387138*t - 2034)*y + (9981516*t + 163429188)), (-22106190*t + 2 2106190)*x^5 + ((1033724*t - 252668)*y + (4435702*t - 9139214))*x^4 + ((6452 30*t + 3390)*y + (20207790*t - 14476430))*x^3 + ((-2977550*t + 1791050)*y + (-8209450*t - 9463750))*x^2 + ((-258092*t - 1356)*y + (-8083116*t - 82634188 ))*x + ((1556688*t - 1540416)*y + (13755264*t + 93607392)), ((355683*t + 120 069)*y + (-2132976*t - 281868))*x^5 + ((-897220*t - 1166160)*y + (11970090*t + 5999170))*x^3 + ((-1432727*t + 2508939)*y + (-21158346*t - 99350278))*x, (-22106190*t + 22106190)*x^5 + ((-1033724*t + 252668)*y + (-4435702*t + 9139 214))*x^4 + ((645230*t + 3390)*y + (20207790*t - 14476430))*x^3 + ((2977550* t - 1791050)*y + (8209450*t + 9463750))*x^2 + ((-258092*t - 1356)*y + (-8083 116*t - 82634188))*x + ((-1556688*t + 1540416)*y + (-13755264*t - 93607392)) , ((2034*t - 387138)*y + (-163429188*t + 9981516))*x^5 + ((2637646*t + 14979 28)*y + (49829158*t + 9230744))*x^4 + ((48590*t + 3032920)*y + (25847620*t + 5104210))*x^3 + ((-3032920*t + 48590)*y + (-5104210*t + 25847620))*x^2 + (( 1497928*t - 2637646)*y + (9230744*t - 49829158))*x + ((387138*t + 2034)*y + (-9981516*t - 163429188)), ((-2034*t + 387138)*y + (-13420332*t - 9981516))* x^5 + ((64862*t - 64184)*y + (22679326*t + 18637768))*x^4 + ((593250*t - 238 4300)*y + (8836600*t + 627150))*x^3 + ((-648620*t + 641840)*y + (-5731360*t + 34684220))*x^2 + ((-1562112*t + 2572784)*y + (9407024*t + 27149832))*x - 1 76849520, ((-1556688*t + 1540416)*y + (8350926*t - 115713582))*x^5 + ((-7756 32*t + 254024)*y + (3647414*t + 91773402))*x^4 + ((2332320*t - 1794440)*y + (-11998340*t + 23940180))*x^3 + ((2332320*t - 1794440)*y + (-11998340*t + 23 940180))*x^2 + ((-775632*t + 254024)*y + (3647414*t + 91773402))*x + ((-1556 688*t + 1540416)*y + (8350926*t - 115713582)), ((-77568*t + 417576)*y + (-25 584*t - 2434032))*x^5 + ((268940*t - 2063380)*y + (5970920*t + 17969260))*x^ 3 + ((-71303*t + 1290121)*y + (-28333394*t - 35508442))*x, -176849520*x^5 + ((1562112*t - 2572784)*y + (-9407024*t - 27149832))*x^4 + ((-648620*t + 6418 40)*y + (-5731360*t + 34684220))*x^3 + ((-593250*t + 2384300)*y + (-8836600* t - 627150))*x^2 + ((64862*t - 64184)*y + (22679326*t + 18637768))*x + ((203 4*t - 387138)*y + (13420332*t + 9981516)), ((-1540416*t - 1556688)*y + (9360 7392*t - 13755264))*x^5 + ((1356*t - 258092)*y + (82634188*t - 8083116))*x^4 + ((1791050*t + 2977550)*y + (-9463750*t + 8209450))*x^3 + ((-3390*t + 6452 30)*y + (14476430*t + 20207790))*x^2 + ((-252668*t - 1033724)*y + (-9139214* t - 4435702))*x + (-22106190*t - 22106190), ((-1540416*t - 1556688)*y + (936 07392*t - 13755264))*x^5 + ((-1356*t + 258092)*y + (-82634188*t + 8083116))* x^4 + ((1791050*t + 2977550)*y + (-9463750*t + 8209450))*x^3 + ((3390*t - 64 5230)*y + (-14476430*t - 20207790))*x^2 + ((-252668*t - 1033724)*y + (-91392 14*t - 4435702))*x + (22106190*t + 22106190), -176849520*x^5 + ((-1562112*t + 2572784)*y + (9407024*t + 27149832))*x^4 + ((-648620*t + 641840)*y + (-573 1360*t + 34684220))*x^3 + ((593250*t - 2384300)*y + (8836600*t + 627150))*x^ 2 + ((64862*t - 64184)*y + (22679326*t + 18637768))*x + ((-2034*t + 387138)* y + (-13420332*t - 9981516)), ((71303*t - 1290121)*y + (28333394*t + 3550844 2))*x^4 + ((-268940*t + 2063380)*y + (-5970920*t - 17969260))*x^2 + ((77568* t - 417576)*y + (25584*t + 2434032)), ((1432727*t - 2508939)*y + (21158346*t + 99350278))*x^4 + ((897220*t + 1166160)*y + (-11970090*t - 5999170))*x^2 + ((-355683*t - 120069)*y + (2132976*t + 281868)), ((-2722848*t + 2437636)*y + (14350096*t - 127683672))*x^4 + ((1166160*t - 897220)*y + (-5999170*t + 11 970090))*x^2 + ((-61893*t + 42501)*y + (301056*t - 307452))], [((52*t - 46)* y + (-316*t + 398))*x^4 + ((-250*t + 250)*y + (1750*t - 7250))*x^2 + 30000, ((-198*t + 204)*y + (1434*t + 23148))*x^5 + ((-240*t + 270)*y + (1920*t - 12 510))*x^4 + ((270*t - 210)*y + (-1410*t - 3270))*x^3 + ((270*t - 210)*y + (- 1410*t - 3270))*x^2 + ((-240*t + 270)*y + (1920*t - 12510))*x + ((-198*t + 2 04)*y + (1434*t + 23148)), ((6*t + 42)*y + (3012*t + 2484))*x^5 + ((-25*t + 165)*y + (-2595*t - 1355))*x^4 + ((-65*t + 15)*y + (-2115*t - 325))*x^3 + (( 190*t - 510)*y + (-450*t - 1210))*x^2 + ((260*t - 300)*y + (-420*t - 18020)) *x + ((-168*t + 264)*y + (1944*t + 7368)), ((270*t + 210)*y + (10380*t + 540 ))*x^5 + ((-275*t - 425)*y + (-15425*t + 1775))*x^4 + ((-575*t - 175)*y + (- 3325*t + 125))*x^3 + ((-175*t + 575)*y + (125*t + 3325))*x^2 + ((425*t - 275 )*y + (-1775*t - 15425))*x + ((210*t - 270)*y + (540*t - 10380)), ((-54*t + 12)*y + (-678*t + 1164))*x^5 + ((-140*t + 10)*y + (-4400*t + 4610))*x^4 + (( 350*t - 160)*y + (380*t - 830))*x^3 + ((80*t + 50)*y + (1790*t + 2440))*x^2 + ((-380*t + 280)*y + (-2480*t - 7900))*x + ((144*t - 192)*y + (-2112*t - 21 984)), ((144*t + 58)*y + (-1112*t - 234))*x^4 + (-250*y + (2750*t + 4500))*x ^2 + (-3750*t - 26250), ((54*t - 12)*y + (678*t - 1164))*x^5 + ((-140*t + 10 )*y + (-4400*t + 4610))*x^4 + ((-350*t + 160)*y + (-380*t + 830))*x^3 + ((80 *t + 50)*y + (1790*t + 2440))*x^2 + ((380*t - 280)*y + (2480*t + 7900))*x + ((144*t - 192)*y + (-2112*t - 21984)), ((-270*t - 210)*y + (-10380*t - 540)) *x^5 + ((-275*t - 425)*y + (-15425*t + 1775))*x^4 + ((575*t + 175)*y + (3325 *t - 125))*x^3 + ((-175*t + 575)*y + (125*t + 3325))*x^2 + ((-425*t + 275)*y + (1775*t + 15425))*x + ((210*t - 270)*y + (540*t - 10380)), ((-6*t - 42)*y + (-3012*t - 2484))*x^5 + ((-25*t + 165)*y + (-2595*t - 1355))*x^4 + ((65*t - 15)*y + (2115*t + 325))*x^3 + ((190*t - 510)*y + (-450*t - 1210))*x^2 + ( (-260*t + 300)*y + (420*t + 18020))*x + ((-168*t + 264)*y + (1944*t + 7368)) , ((198*t - 204)*y + (-1434*t - 23148))*x^5 + ((-240*t + 270)*y + (1920*t - 12510))*x^4 + ((-270*t + 210)*y + (1410*t + 3270))*x^3 + ((270*t - 210)*y + (-1410*t - 3270))*x^2 + ((240*t - 270)*y + (-1920*t + 12510))*x + ((-198*t + 204)*y + (1434*t + 23148)), ((-12*t + 196)*y + (-164*t - 1428))*x^4 + (-250 *y + (2750*t + 4500))*x^2 + (-3750*t - 3750), ((-168*t + 264)*y + (1944*t + 7368))*x^5 + ((260*t - 300)*y + (-420*t - 18020))*x^4 + ((190*t - 510)*y + ( -450*t - 1210))*x^3 + ((-65*t + 15)*y + (-2115*t - 325))*x^2 + ((-25*t + 165 )*y + (-2595*t - 1355))*x + ((6*t + 42)*y + (3012*t + 2484)), ((-192*t - 144 )*y + (-21984*t + 2112))*x^5 + ((-280*t - 380)*y + (7900*t - 2480))*x^4 + (( 50*t - 80)*y + (2440*t - 1790))*x^3 + ((160*t + 350)*y + (830*t + 380))*x^2 + ((10*t + 140)*y + (4610*t + 4400))*x + ((-12*t - 54)*y + (-1164*t - 678)), ((192*t + 144)*y + (21984*t - 2112))*x^5 + ((-280*t - 380)*y + (7900*t - 24 80))*x^4 + ((-50*t + 80)*y + (-2440*t + 1790))*x^3 + ((160*t + 350)*y + (830 *t + 380))*x^2 + ((-10*t - 140)*y + (-4610*t - 4400))*x + ((-12*t - 54)*y + (-1164*t - 678)), ((168*t - 264)*y + (-1944*t - 7368))*x^5 + ((260*t - 300)* y + (-420*t - 18020))*x^4 + ((-190*t + 510)*y + (450*t + 1210))*x^3 + ((-65* t + 15)*y + (-2115*t - 325))*x^2 + ((25*t - 165)*y + (2595*t + 1355))*x + (( 6*t + 42)*y + (3012*t + 2484)), (-3750*t - 3750)*x^5 + (-250*y + (2750*t + 4 500))*x^3 + ((-12*t + 196)*y + (-164*t - 1428))*x, (-3750*t - 26250)*x^5 + ( -250*y + (2750*t + 4500))*x^3 + ((144*t + 58)*y + (-1112*t - 234))*x, 30000* x^5 + ((-250*t + 250)*y + (1750*t - 7250))*x^3 + ((52*t - 46)*y + (-316*t + 398))*x]] Mod(-904583688/27200667365, y^2 + Mod(-t, t^2 + 1)*y + 32)*y^2 + Mod(-485238 4244/5440133473, y^2 + Mod(-t, t^2 + 1)*y + 32) 0.0011925695879998878380848926233233473256*x^3 - 0.0034461762994896503999275 399407078201462*I*x^2 - 0.0029814239699997195952122315583083683139*x (0.0011925695879998878380848926233233473256*x^4 + 0.001788854381999831757127 3389349850209884*x^3 + 0.0011925695879998878380848926233233473255*x^2 + 0.00 17888543819998317571273389349850209884*x + 0.0011925695879998878380848926233 233473256)/x (0.0011925695879998878380848926233233473256*x^4 + 0.001788854381999831757127 3389349850209884*x^3 + 0.0017888543819998317571273389349850209884*x - 0.0011 925695879998878380848926233233473256)/x (0.0011925695879998878380848926233233473256*x^4 - 0.001788854381999831757127 3389349850209884*x^3 - 0.0017888543819998317571273389349850209884*x - 0.0011 925695879998878380848926233233473256)/x (0.0011925695879998878380848926233233473256*x^4 - 0.001788854381999831757127 3389349850209884*x^3 + 0.0011925695879998878380848926233233473255*x^2 - 0.00 17888543819998317571273389349850209884*x + 0.0011925695879998878380848926233 233473256)/x (-0.0029814239699997195952122315583083683139*x^2 + 0.00344617629948965039992 75399407078201462*I*x + 0.0011925695879998878380848926233233473256)/x (-0.0029814239699997195952122315583083683139*x^2 + 0.00344617629948965039992 75399407078201462*I*x + 0.0011925695879998878380848926233233473256)/x (0.13416407864998738178455042012387657413 - 0.086154407487241259998188498517 695503654*I)*x^2 + (-0.089442719099991587856366946749251049416 + 0.034461762 994896503999275399407078201462*I)*x + 0.017888543819998317571273389349850209 883 -0.062500000000000000000000000000000000000*I*x^2 - 0.00390625000000000000000 00000000000000000*I (0.029076134702187599205839917739040862356*x^3 + (-0.02180710102664069940437 9938304280646767 - 0.020833333333333333333333333333333333302*I)*x^2 + (0.005 4517752566601748510949845760701616916 + 0.0104166666666666666666666666666666 66659*I)*x + (-0.00045431460472168123759124871467251347431 - 0.0039062500000 000000000000000000000000000*I))/(-4*x + 1) -10.687500000000000000000000000000000000*I*x^2 + 8.0000000000000000000000000 000000000000*I*x - 2.0000000000000000000000000000000000000*I 0.023437500000000000000000000000000000000*I*x^2 + 0.031250000000000000000000 000000000000000*I*x + 0.093750000000000000000000000000000000000*I [[1], [1, 1]] [[0.70710678118654752440084436210484903928 + 0.70710678118654752440084436210 484903928*I], [-0.70710678118654752440084436210484903928 - 0.707106781186547 52440084436210484903928*I, -0.70710678118654752440084436210484903928 - 0.707 10678118654752440084436210484903928*I]] [[0.99595931395311210936063384855913482217 - 0.08980559531591707448838903035 9505357515*I], [0.53927595283868673281600574405026404173 + 0.842129115213294 66664554619540652632773*I, -0.85895466516104552261001111734173629157 + 0.512 05164114381683048538165804971399484*I]] [[-0.76775173011852704509198454449006172341 - 0.6407474392457674209160837770 1764443337*I], [-0.21414952481887583992521740447795630385 + 0.97680089118502 020368501019184890743540*I, -0.96944785623768905552448638076096150649 - 0.24 529748069670216936666745500978951118*I]] [10, 7, Mod(2, 5), 0] 3 [0, 3, 4*t + 4, 32*t - 32, 96*t, 155*t + 90, 112, -348*t - 348, 128*t - 128, -2177*t] 2 [0, 1, -4*t - 4, 23*t - 23, 32*t, 100*t - 75, 184, -247*t - 247, -128*t + 12 8, -329*t] [0, 1, 4*t + 4, (5*t + 5)*y + (2*t - 2), 32*t, (-5*t - 15)*y + (35*t + 80), 40*t*y - 16, (-55*t + 55)*y + (-78*t - 78), 128*t - 128, -90*y - 879*t] [0, 1, -2, -1, 2, 1, 2, -2, 0, -2, -2] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] [-1/12, -3/2, 16/3, -1/12, -27/4, 1/6, 4/3]~ [0, 0, -2399/5121840000, -479/13111910400000, 1/307310400000]~ [1, 0, 0, 0, 0, 0] 8 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]~ 13 x^12 + Mod(-4*t - 4, t^2 + t + 1)*x^11 + Mod(-4*t, t^2 + t + 1)*x^10 + Mod(- 40, t^2 + t + 1)*x^9 + Mod(27*t + 27, t^2 + t + 1)*x^8 + Mod(150*t, t^2 + t + 1)*x^7 + Mod(216, t^2 + t + 1)*x^6 + Mod(270*t + 270, t^2 + t + 1)*x^5 + M od(-675*t, t^2 + t + 1)*x^4 + Mod(54, t^2 + t + 1)*x^3 + Mod(-972*t - 972, t ^2 + t + 1)*x^2 + Mod(648*t, t^2 + t + 1)*x 1 [] [-24] [14] [14] [-12] [[33, 2, 1, y], [0, 1, 1, -1, -1, -2, -1, 4, -3, 1, -2]] [[38, 2, 1, y], [0, 1, 1, -1, 1, -4, -1, 3, 1, -2, -4]] [[39, 2, 1, y], [0, 1, 1, -1, -1, 2, -1, -4, -3, 1, 2]] [[34, 2, 1, y], [0, 1, 1, -2, 1, 0, -2, -4, 1, 1, 0]] [[38, 2, 1, y], [0, 1, -1, 1, 1, 0, -1, -1, -1, -2, 0]] [[11, 3, -11, y], [0, 1, 0, -5, 4, -1, 0, 0, 0, 16, 0]] [[12, 3, -3, y], [0, 1, 0, -3, 0, 0, 0, 2, 0, 9, 0]] [[16, 3, -4, y], [0, 1, 0, 0, 0, -6, 0, 0, 0, 9, 0]] [[38, 2, 1], [0, 1, 2, 3, 4, -5, -8, 1, -7, -5, 7]] [[40, 2, 8], [0, 1, 2, 3, 4, -4, -6, -1, -10, -1, 2]] [[40, 2, 40], [0, 1, 2, 3, 4, -8, -6, -7, 6, -1, -2]] 3 [0, 1, 2, 3, 4, 5] x^12 + 2*x^11 + 4*x^10 + 4*x^9 + 4*x^8 + 2*x^7 - 8*x^5 - 17*x^4 - 16*x^3 - 8 *x^2 + 16*x + 16 [2, 40, 20, 10, 8, 10, 4, 2] [[0, 0], [0, 0], [0, 0], [1, 1], [0, 0], [1, 1], [0, 0], [3, 3]] [[3, 3]] [[5, 5]] [[2, 2]] [[6, 6]] [[4, 4]] [[0, -1; 1, 0], [1, 0; 1, 1], [0, -1; 1, 2], [0, -1; 1, 3], [1, 0; 2, 1], [1 , 0; 4, 1]] [[-1, 1; -4, 3], 5] [[0, -1; 1, 0], [1, 0; 1, 1], [0, -1; 1, 2], [0, -1; 1, 3], [0, -1; 1, 4], [ 0, -1; 1, 5], [0, -1; 1, 6], [0, -1; 1, 7], [0, -1; 1, 8], [0, -1; 1, 9], [0 , -1; 1, 10], [0, -1; 1, 11], [0, -1; 1, 12], [0, -1; 1, 13], [0, -1; 1, 14] , [0, -1; 1, 15], [0, -1; 1, 16], [0, -1; 1, 17], [0, -1; 1, 18], [0, -1; 1, 19], [0, -1; 1, 20], [0, -1; 1, 21], [0, -1; 1, 22], [1, 0; 23, 1]] [0, 1, t^2 + t, 0, -t - 1, 0, 0, t^3, -t^2, -t^3 - t^2 - t - 1, 0] [10] 1 [0, 1, 0, 0, t, t, 0, 0, 0, 0, 0] [6] 6 10 3 [[0, 0, 0; 0, 0, 1; 0, -2, 0], [0, 0, 0; 0, 0, -1; 0, 2, 0]] 1.4557628922687093224624220035988692874 10000.000000000000000000001237896015010 1.9689399767614335374830916735439946588 [-1, -60.000000000000000000000000000000000000, 240.0000000000000000000000000 0000000000*x^-1 + O(x^0)] [-1, -378.00000000000000000000000000000000000, -504.000000000000000000000000 00000000001*x^-1 + O(x^0)] 0.0050835121083932868604942901374387473226 [1620/691, 1, 9/14, 9/14, 1, 1620/691] 0.0074154209298961305890064277459002287248 [1, 25/48, 5/12, 25/48, 1] [270000/43867, 1, 75/364, 15/308, 0, -15/308, -75/364, -1, -270000/43867] -0.43965042620884602281482782769927016562 [1, 11/60, 1/24, 1/120, -1/120, -1/24, -11/60, -1] 1.3407636701883001534150257403529284807 - 0.09169347814648177113546620833059 8109324*I 0.037077104649480652945032138729501143624 x^9 - 25/4*x^7 + 21/2*x^5 - 25/4*x^3 + x -0.0059589649895782378538355644158109773247*I -x^10 + 691/36*x^8 - 691/12*x^6 + 691/12*x^4 - 691/36*x^2 + 1 1.0353620568043209223478168122251645932 E-6 [[4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x], [-36*x^10 + 691*x^8 - 2073*x^6 + 2073*x^4 - 691*x^2 + 36]] 4096/691 -691/4096 0.0039083456561245989852473854813821138618 [[0, 0, 0, 1, 1, 0, 0, -1, -1, 0, 0, 0], [2, 0, 10, 5, -5, -10, -10, -5, 5, 10, 0, -2]] 24/5 0.00036417018656710457295477514743042437729 0.00049190307191092718531081143004073999661 0.11655892584877731533791261543544162961*x + 0.03444188571581440474103881572 3936163594 0.0010890395470223995019083365452957049165 (-1.3193074979773231773661743756435007224 - 0.047852089878877215068678875180 019315601*I)*x + (0.55369913164712442515829589611646024395 + 0.1378560105941 2197357057720849196966097*I) 2.7088661559067092169467726322243151834*x^4 + 10.836695978514012215743285363 808371991*x^3 + 25.296899951502000988317286862612207702*x^2 + 41.46298040535 0911775127337547706905296*x + 36.867636355501616095737218901200295353 0.68152665510891372423521870628322971562 (-23183.009401346887106321839878457037987 + 10141.03198768851019292105517715 0961372*I)*x^4 + (36768.014815457253142184985512097903984 - 15843.6719474121 59422532108270646842468*I)*x^3 + (-21653.185479189712080795697797411393243 + 9383.4655370867720981173021992677296843*I)*x^2 + (5567.82157171174936497454 45772875483392 - 2529.1579539358590353355113445052491948*I)*x + (-519.290436 33066550788943723994543165137 + 267.97049309982710940044149283381067824*I) 0 -7.5483533093124615800482309272746852303 E-5*I*x^4 - 0.000325960230614461968 18766920427560516720*x^3 + 0.00053071372195845519650854381590103954823*I*x^2 + 0.00038639246231107851592899900012773026572*x - 0.00010622771569710146301 261452001204110433*I -159.28538078371628604726626677227374955*I*x^4 - 37.413371571061889095904737 694744717500*x^3 + 4.0605244955720177153253400611368714530*I*x^2 + 0.2512588 6591932202962812257047290475386*x - 0.00775320874361027409750103740193487763 58*I -1.0529510950884198373348191584869623207 E-9*I*x^4 - 4.379386751919803419760 5690442523726760 E-9*x^3 + 6.8404573572594165822427167063489824371 E-9*I*x^2 + 4.7561506807037037564779077168765701622 E-9*x - 1.24219231762730610575003 87331529713560 E-9*I [x^8 - 3*x^6 + 3*x^4 - x^2, 4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x, x^10 - 1 ] [x^8 - 3*x^6 + 3*x^4 - x^2, x^10 - 1] [4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x] [] [] [0.027225824587703356565506853506344987181 + 0.00514822234043271905508741860 26406789545*I, 0.027225198325372166661822373393404529553 + 0.005147912007675 1226908071569776979202443*I, 0.027225932797583197568370599484048729614 + 0.0 051482759611568609455954291851306519135*I, 0.0272255959592292808469822068846 79062845 + 0.0051481090481140853554894307306409709784*I] 0.00013137888540468962216778728275879264699 [0, 1, -y, 2*y - 1, y - 1, -2*y] [[[0, 0, 0, y + 1, 1, -y, 1, y + 1, y + 1, y, y + 1, 0, 0, -y - 1, -y, -y - 1, -y - 1, -1, y, -1, -y - 1, 0, 0, 0], [4*y + 6, 0, 22*y + 22, 11, -11*y, 1 1*y + 11, 11*y, 22*y + 11, -11, -11*y - 11, -22*y - 11, -22*y - 22, -22*y - 22, -22*y - 11, -11*y - 11, -11, 22*y + 11, 11*y, 11*y + 11, -11*y, 11, 22*y + 22, 0, -4*y - 6]], [[0, 0, 0, 1, y + 1, y, y + 1, 1, 1, -y, 1, 0, 0, -1, y, -1, -1, -y - 1, -y, -y - 1, -1, 0, 0, 0], [2*y + 6, 0, 22, 11*y + 11, 11* y, 11, -11*y, -11*y + 11, -11*y - 11, -11, 11*y - 11, -22, -22, 11*y - 11, - 11, -11*y - 11, -11*y + 11, -11*y, 11, 11*y, 11*y + 11, 22, 0, -2*y - 6]]] [-192/55*y + 336/55, -48/55*y + 144/55] [[[x, x^2 + 2*x + 1, Mod(t, t^2 + t + 1)*x^2 + Mod(2*t + 1, t^2 + t + 1)*x + 2, Mod(-2*t, t^2 + t + 1)*x^2 + Mod(-t - 2, t^2 + t + 1)*x + Mod(t + 1, t^2 + t + 1), Mod(2*t, t^2 + t + 1)*x^2 + Mod(-t - 2, t^2 + t + 1)*x + Mod(-t - 1, t^2 + t + 1), Mod(-t, t^2 + t + 1)*x^2 + Mod(2*t + 1, t^2 + t + 1)*x - 2 , -x^2 + 2*x - 1, x], [Mod(47*t - 528, t^2 + t + 1)*x^2 + 3871, -3871*x^2 + 3871, Mod(-5293*t - 3792, t^2 + t + 1)*x^2 + Mod(2054*t - 3555, t^2 + t + 1) *x + Mod(2054*t + 316, t^2 + t + 1), Mod(1738*t + 2054, t^2 + t + 1)*x^2 + M od(-5609*t - 2054, t^2 + t + 1)*x + Mod(-1501*t - 5293, t^2 + t + 1), Mod(17 38*t + 2054, t^2 + t + 1)*x^2 + Mod(5609*t + 2054, t^2 + t + 1)*x + Mod(-150 1*t - 5293, t^2 + t + 1), Mod(-5293*t - 3792, t^2 + t + 1)*x^2 + Mod(-2054*t + 3555, t^2 + t + 1)*x + Mod(2054*t + 316, t^2 + t + 1), -3871*x^2 + 3871, -3871*x^2 + Mod(-47*t + 528, t^2 + t + 1)]], [0.0600760389692829045137557605 79766793352 + 0.0076557040727195254011353573267975581649*I, 3.80684584829863 11431726029948424993484 E-6 - 2.3063284341262122716050386345503232003 E-5*I, 3008/305809]] [0, 1/7] 0.012348139466200861797970297067148459977 [0, 1/2, 1/3, 1/4, 1/6, 1/12] [0, 1/2, 1/3, 1/4, 1/6, 1/12] [12, 3, 4, 3, 1, 1] [1, 0, 1, 1, 0, 1] [1, 0, 1, 1, 0, 1] [0, 1/4, 0, 0, 1/4, 0] [1/12, 1/6, 1/2, 2/3, 1/2, 2] [1/12, 1/6, 1/4, 2/3, 1/2, 1] 1 [3, 7, -3, y, 3, "F_7(-3)"] [15, 7, -15, y, 3, "F_7(-3, 5)"] [1, 4, 1, y, 3, "E_4"] [11, 1, -11, y, 3, "LIN([F_1(1, -11)], [2]~)", "F_1(1, -11)"] [4, 1/2, 1, y, 3, "THETA(1)"] [4, 1/2, 1, y, 1, "T_4(9)(THETA(1))", "THETA(1)"] [1, 12, 1, y, 0, "DELTA"] [11, 2, 1, y, 0, "ETAQUO([Vecsmall([1, 11]), Vecsmall([2, 2])], 1)"] [35, 2, 1, y, 0, "ELL([0, 1, 1, 9, 1])"] [385, 2, 1, y, -1, "LIN([ETAQUO([Vecsmall([1, 11]), Vecsmall([2, 2])], 1), E LL([0, 1, 1, 9, 1])], [1, 1])", "ETAQUO([Vecsmall([1, 11]), Vecsmall([2, 2]) ], 1)", "ELL([0, 1, 1, 9, 1])"] [3, 21, -3, y, -1, "POW(F_7(-3), 3)", "F_7(-3)"] [15, 14, 5, y, -1, "MUL(F_7(-3), F_7(-3, 5))", "F_7(-3)", "F_7(-3, 5)"] [1, 12, 1, y, 0, "MULRC_2(E_4, E_4)", "E_4", "E_4"] [385, 2, 1, y, -1, "LIN([ETAQUO([Vecsmall([1, 11]), Vecsmall([2, 2])], 1), E LL([0, 1, 1, 9, 1])], [1, -1])", "ETAQUO([Vecsmall([1, 11]), Vecsmall([2, 2] )], 1)", "ELL([0, 1, 1, 9, 1])"] [15, 0, 5, y, -1, "DIV(F_7(-3, 5), F_7(-3))", "F_7(-3, 5)", "F_7(-3)"] [1, 12, 1, y, -1, "SHIFT(DELTA, 1)", "DELTA"] [1, 6, 1, y, -1, "DER^1(E_4)", "E_4"] [1, 12, 1, y, 0, "DERE2^4(E_4)", "E_4"] [25, 4, 1, y, -1, "TWIST(E_4, 5)", "E_4"] [1, 12, 1, y, 0, "T_1(5)(DELTA)", "DELTA"] [3, 4, 1, y, 3, "B(3)(E_4)", "E_4"] [2, 2, 1, y, 3, "LIN([F_2(1), B(2)(F_2(1))], [1, -2])", "F_2(1)", "B(2)(F_2( 1))"] [3, 2, 1, y, 3, "LIN([F_2(1), B(3)(F_2(1))], [1, -3])", "F_2(1)", "B(3)(F_2( 1))"] [6, 2, 1, y, 3, "LIN([F_2(1), B(6)(F_2(1))], [1, -6])", "F_2(1)", "B(6)(F_2( 1))"] [1, 4, 1, y, 3, "F_4(1, 1)"] [2, 4, 1, y, 3, "B(2)(F_4(1, 1))", "F_4(1, 1)"] [3, 4, 1, y, 3, "B(3)(F_4(1, 1))", "F_4(1, 1)"] [4, 4, 1, y, 3, "B(4)(F_4(1, 1))", "F_4(1, 1)"] [6, 4, 1, y, 3, "B(6)(F_4(1, 1))", "F_4(1, 1)"] [8, 4, 1, y, 3, "B(8)(F_4(1, 1))", "F_4(1, 1)"] [12, 4, 1, y, 3, "B(12)(F_4(1, 1))", "F_4(1, 1)"] [24, 4, 1, y, 3, "B(24)(F_4(1, 1))", "F_4(1, 1)"] [6, 4, 1, y, 2, "TR^new([6, 4, 1, y])"] [12, 4, 1, y, 2, "B(2)(TR^new([6, 4, 1, y]))", "TR^new([6, 4, 1, y])"] [24, 4, 1, y, 1, "B(4)(TR^new([6, 4, 1, y]))", "TR^new([6, 4, 1, y])"] [8, 4, 1, y, 2, "TR^new([8, 4, 1, y])"] [24, 4, 1, y, 1, "B(3)(TR^new([8, 4, 1, y]))", "TR^new([8, 4, 1, y])"] [12, 4, 1, y, 2, "TR^new([12, 4, 1, y])"] [24, 4, 1, y, 1, "B(2)(TR^new([12, 4, 1, y]))", "TR^new([12, 4, 1, y])"] [24, 4, 1, y, 0, "TR^new([24, 4, 1, y])"] [1, 2, 3, 4, 6, 8, 12, 24, 6, 12, 24, 8, 24, 12, 24, 24] [23, 1, -23, y, 1, "LIN([DIH(-23, [1, 0; 0, 1], [3], [1])], [1]~)", "DIH(-23 , [1, 0; 0, 1], [3], [1])"] 0.035149946790370230814006345508484787440 23 []~ [[4, 1, -4], 4, [0.25000000000000000000000000000000000000, 1, 1, 0]] -3 [-3, -39] [Mod(575, 576), 1] [Mod(593, 900), 1] [Mod(575, 1152), 1] [Mod(1151, 1152), 1] 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 3 3 4 3 2 3 3 4 5 5 5 5 3 3 4 4 6 6 4 2 6 7 4 4 5 5 5 5 6 6 1 2 2 3 3 4 3 2 3 3 4 5 5 5 5 4 4 4 4 6 6 4 3 6 8 5 5 6 6 6 6 6 6 1 1 1 2 3 3 2 3 3 3 3 4 4 4 4 2 2 4 5 6 4 7 7 6 6 6 6 6 6 2 3 3 4 4 6 4 2 4 4 4 6 6 6 6 4 4 4 4 8 8 4 2 8 8 4 4 6 6 6 6 6 6 2 3 3 5 5 6 5 4 7 7 6 9 9 9 9 8 8 8 8 10 10 8 7 14 12 11 11 12 12 12 12 12 12 1 1 3 3 2 3 4 5 5 6 7 7 7 7 8 8 8 8 6 6 8 9 10 12 13 13 12 12 12 12 12 12 2 3 3 4 4 6 4 2 4 4 4 6 6 6 6 4 4 4 4 8 8 4 2 8 8 4 4 6 6 6 6 6 6 2 4 4 7 7 8 7 6 9 9 10 13 13 13 13 12 12 12 12 14 14 12 11 18 20 17 17 18 18 18 18 18 18 0 2 6 13 22 28 48 64 74 96 2 6 8 14 16 24 24 32 32 48 2 8 14 27 38 52 72 96 106 144 [[[0, 1, 0, 0, -4, 0, -6, 8, 0, 9, 4, 0, 12, -20, 0, -24], [0, 0, 1, 0, -2, -4, 3, 2, 4, 0, 0, 2, -6, 0, -8, -6], [0, 0, 0, 1, -2, 0, 0, 2, 0, 0, 0, 0, -2, 0, 0, -6]], [[0, 1, 0, 0, -2, -6, 0, 0, 12, 9, 0, 0, -18, 12, 0, 0], [0, 0, 1, 0, -2, -2, -3, 4, 8, 6, -2, -16, -6, 4, 14, 12], [0, 0, 0, 1, 0, -4, -2, 4, 8, 4, -8, -12, -8, 8, 24, 8]]] [ 0 0 0] [ 1 0 0] [ 0 1 0] [ 0 0 1] [-2 0 0] [ 0 0 0] [0 0 0 0] [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] [0 0 -1 0] [0, 1, 0, 0, 0, 0, 0, -3, -2, 1, 0, -6, 0, 0, 6, 12] [0, 0, 1, 0, 0, 0, 0, -3, -4, 4, 0, 0, 0, 0, -1, 2] [0, 0, 0, 1, 0, -1, 0, -1, 0, 0, -2, 0, 2, 1, 2, 0] [0, 0, 0, 0, 1, 0, 0, -1, -3, 2, 0, -2, 0, 0, 2, 4] [2]~ [0, 2]~ [Mod(-1/49*t^11 + 1/49*t^10 + 1/98*t^9 - 5/196*t^8 - 1/196*t^7 - 5/196*t^4 + 5/196*t^3 - 1/196*t^2 - 1/196*t + 1/49, t^12 - t^11 + t^9 - t^8 + t^6 - t^4 + t^3 - t + 1), Mod(-6/49*t^11 + 13/196*t^10 - 13/196*t^8 + 2/49*t^7 + 13/1 96*t^6 - 11/196*t^5 - 11/196*t^4 + 6/49*t^3 - 11/196*t^2 - 13/196*t + 4/49, t^12 - t^11 + t^9 - t^8 + t^6 - t^4 + t^3 - t + 1), Mod(1/196*t^11 - 5/196*t ^10 - 1/98*t^9 + 3/98*t^8 - 5/196*t^7 - 1/196*t^6 + 3/196*t^5 + 1/196*t^4 - 1/98*t^3 + 1/49*t^2 + 1/98*t - 1/98, t^12 - t^11 + t^9 - t^8 + t^6 - t^4 + t ^3 - t + 1), Mod(9/196*t^10 - 15/196*t^9 - 3/49*t^8 - 3/196*t^6 - 3/49*t^5 + 15/196*t^4 + 3/196*t^3 - 15/196*t^2 - 3/196, t^12 - t^11 + t^9 - t^8 + t^6 - t^4 + t^3 - t + 1), Mod(15/196*t^11 - 15/196*t^9 + 9/98*t^8 - 3/49*t^7 - 3 /49*t^6 + 15/196*t^5 - 3/49*t^3 + 3/49*t^2 + 9/196*t - 27/196, t^12 - t^11 + t^9 - t^8 + t^6 - t^4 + t^3 - t + 1), Mod(3/49*t^11 + 3/98*t^10 - 15/196*t^ 9 + 3/49*t^8 + 3/196*t^7 - 3/98*t^6 - 3/196*t^5 + 3/196*t^4 - 9/196*t^3 - 3/ 98*t^2 + 3/196*t + 3/196, t^12 - t^11 + t^9 - t^8 + t^6 - t^4 + t^3 - t + 1) ] [Mod(0, t^2 + t + 1) Mod(0, t^2 + t + 1) Mod(0, t^2 + t + 1) Mod(1, t^2 + t + 1)] [Mod(-2, t^2 + t + 1) Mod(-2*t - 2, t^2 + t + 1) Mod(0, t^2 + t + 1) Mod(0, t^2 + t + 1)] [Mod(2*t + 4, t^2 + t + 1) Mod(4*t + 2, t^2 + t + 1) Mod(4*t + 4, t^2 + t + 1) Mod(-t + 1, t^2 + t + 1)] [Mod(-8*t, t^2 + t + 1) Mod(4, t^2 + t + 1) Mod(-4*t + 4, t^2 + t + 1) Mod(- 4*t - 4, t^2 + t + 1)] [0, 1, 0, 0, 0, -t - 2, 0, 0, -2, 4*t, 0, 0, 2*t + 4, -4*t - 2, 0, 0] [0, 0, 1, 0, 0, 0, t - 1, 0, -2*t - 2, -2, -t - 2, 0, 4*t + 2, -2*t + 2, -2* t + 1, 4*t + 4] [0, 0, 0, 1, 0, -2*t - 2, 0, 3*t + 2, 0, 2*t - 2, -2, -2*t - 1, 4*t + 4, -2* t, -6*t - 4, t + 2] [0, 0, 0, 0, 1, t - 1, -t - 2, -2*t + 1, 0, t + 1, 4*t + 2, 1, -t + 1, -t - 2, -t - 3, t] [4, 1, -4, y] [1, 0, 0, 2, 0, 0, 0, 6, 6, 0, 0, 0, 8, 0, 0, 6] [0, 1, 0, -1, 1, 2, 4, -3, -3, 5, 2, 4, -4, 0, 8, -3] [0, 0, 1, 1, 0, 1, 0, 1, 2, 0, 1, 0, 2, 2, 0, 1] 2 [1, 12, 1, y] [4, 6, 1, y] [9, 4, 1, y] [16, 3, -4, y] [36, 2, 1, y] [144, 1, -4, y] [576, 1/2, 12, y] [64, 3/2, 1, y] [0, 1, 0, 0, 0, 0, 0, 0, -3, 0]~ [[0, 64, [1, 0; 0, 1]], [0, -0.031250000000000000000000000000000000000 - 0.0 31250000000000000000000000000000000000*I, 0, 0, 0, 0, 0, 0, 0, 0.09375000000 0000000000000000000000000000 + 0.093750000000000000000000000000000000000*I, 0]] [[0, 16, [1, 0; 0, 1]], [0, 0.10393370153781815463484854720223821959 + 0.069 446279127450278092853851743566609297*I, 0, 0, 0, 0, 0, 0, 0, -0.208338837382 35083427856155523069982789 + 0.31180110461345446390454564160671465878*I, 0]] 0.0018674427317079888144293843310939736875 [36, 5/2, 1, y] 2 [-1 0 0 2 0 0] [ 0 0 0 0 1 0] [9, 4, 1, y] [9, 4, 1, y] [0 -1 0 0 2 0 0 0 0 0 0 0 0 -6 0 0 8 0 0 0 0] [0 0 0 0 0 1 0 0 -2 0 0 0 0 0 0 0 0 1 0 0 2] [ -5/14 -1/14 1/2 3/2] [ 37/84 -1/84 1/2 1/2] [-17/84 5/84 -3/2 -9/2] [ 0 0 -1/2 -1/2] [[1, 1], [5, 1]] [[1, 3; 0, 0; 0, 0; 1, 3; 1, 1; 0, 0; 0, 0; 1, 1; -3, -9; 0, 0; 0, 0; -3, -3 ; 0, 0; 0, 0], [1, 0; 0, 0; 0, 0; 1, 0; 0, 1; 0, 0; 0, 0; 0, 1; -3, 0; 0, 0; 0, 0; 0, -3; 0, 0; 0, 0]] [Mat(Mod(-1/2*t^3 + 1/2*t^2 + 1/2*t - 1, t^4 - t^2 + 1)), [1; 0], [[-4, 1]]] [12, 12, 12, 12, 12] 4 0.0018371115455019092538663990739211073913 3.7500000000000000000000000000000000004 [4, 1/2, 1, y] [16, 1/2, 1, y] [1, -2]~ "F_4(-3, -4)" "F_3(5, -7)" "DERE2^3(MUL(F_4(-3, -4), F_3(5, -7)))" "DELTA" "E_2" "T_1(3)(E_2)" ["S_4^new(G_0(37, 1))", "S_4(G_0(37, 1))", "S_4^old(G_0(37, 1))", "E_4(G_0(3 7, 1))", "M_4(G_0(37, 1))"] ["S_3/2(G_0(16, 1))", "M_3/2(G_0(16, 1))"] ["F_4(-3, -4)", "F_3(1, -3)"] [1/24, 10, 90, 280, 730, 1260, 2520, 3440, 5850, 7570, 11340] [10]~ [0, 1, 0, 0, 0, -2, 0, 0, 0, -3, 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0] -125832074732008 -3268080304426/13 [691/32760, 0, -2017/252, 0, -361, 0, -3362, 0, -4130785/252, 0, -278854/5, 0, -152166, 0, -355688, 0] [-1/12, 9375/2, 14055] [-1/12, 1702, 0] [-1/12, 0, 0, 1/3, 1/2, 0, 0, 1, 1, 0, 0, 1, 4/3, 0, 0, 2] [1/120, -1/12, 0, 0, -7/12, -2/5, 0, 0, -1, -25/12, 0, 0, -2, -2, 0, 0] [-1/252, 0, 0, -2/9, -1/2, 0, 0, -16/7, -3, 0, 0, -6, -74/9, 0, 0, -16] [1/240, 1/120, 0, 0, 121/120, 2, 0, 0, 11, 2161/120, 0, 0, 46, 58, 0, 0] [-1/132, 0, 0, 2/3, 5/2, 0, 0, 32, 57, 0, 0, 2550/11, 1058/3, 0, 0, 992] [691/32760, -1/252, 0, 0, -2017/252, -134/5, 0, 0, -361, -176905/252, 0, 0, -3362, -66926/13, 0, 0] [-1/12, 0, 0, -14/3, -61/2, 0, 0, -1168, -2763, 0, 0, -21726, -115598/3, 0, 0, -165616] [-43867/14364, 0, 0, 1618/27, 1385/2, 0, 0, 565184/7, 250737, 0, 0, 3749250, 212490322/27, 0, 0, 52548032] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [-1/12, 1/2, 1, 4/3, 3/2, 2, 2, 2, 3, 5/2, 2, 4, 10/3, 2, 4, 4] [-1/12, 1/2, 1, 4/3, 3/2, 2, 2, 2, 3, 5/2, 2, 4, 10/3, 2, 4, 4] [-1/3, 0, 0, 4/3, 2, 0, 0, 4, 4, 0, 0, 4, 16/3, 0, 0, 8] [-1/12, 0, 0, 4/3, 5/2, 0, 0, 5, 3, 0, 0, 3, 16/3, 0, 0, 8] [-1/2, 0, 0, 2, 3, 0, 0, 6, 6, 0, 0, 6, 8, 0, 0, 12] [-10/3, 0, 0, 40/3, 20, 0, 0, 40, 40, 0, 0, 40, 160/3, 0, 0, 80] [-1/2, 0, 0, 2, 3, 0, 0, 6, 6, 0, 0, 6, 8, 0, 0, 12] [1, 2, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0] [4/3, 8/3, 0, 0, 8/3, 0, 0, 0, 0, 8/3, 0, 0, 0, 0, 0, 0] [0, -4, -8, 0, 0, 0, 16, 0, 0, 28, 16, 0, 0, 0, -32, 0] 4.7568284600108842668699998822419036612 + 4.75682846001088426686999988224190 36612*I 0 0.0061538599016729274239549224845781815123 0 +oo 0 [1, 24, 324, 3200, 25650, 176256, 1073720] [ "Factors" 50000 13 1000000000] [ "Divisors" 50000 5 1000000000] [ "H" 50000 3 200000000] ["CorediscF" 100000 3 200000000] [ "Dihedral" 1000 0 0] *** at top-level: mftobasis(mf0,L[1]) *** ^------------------- *** mftobasis: domain error in mftobasis: form does not belong to space *** at top-level: mfdim([4,1/2],0) *** ^---------------- *** mfdim: incorrect type in half-integral weight [new/old spaces] (t_INT). *** at top-level: mfdim([4,1/2],2) *** ^---------------- *** mfdim: incorrect type in half-integral weight [new/old spaces] (t_INT). *** at top-level: mfdim([4,1/2],5) *** ^---------------- *** mfdim: incorrect type in half-integral weight [incorrect space] (t_INT). *** at top-level: mfeisenstein(2,1.0) *** ^------------------- *** mfeisenstein: incorrect type in znchar (t_REAL). *** at top-level: mfeisenstein(2,[0,0]) *** ^--------------------- *** mfeisenstein: incorrect type in checkNF [chi] (t_VEC). *** at top-level: mfinit([1,1.0]) *** ^--------------- *** mfinit: incorrect type in checkNF [k] (t_VEC). *** at top-level: ...nit([14,6,Mod(9,14)],0));mfmul(L[1],L[2]) *** ^---------------- *** mfmul: incorrect type in mfsamefield [different fields] (t_VEC). *** at top-level: mfcuspwidth(0,0) *** ^---------------- *** mfcuspwidth: domain error in mfcuspwidth: N <= 0 *** at top-level: mfparams(mfadd(F2,F3)) *** ^------------- *** in function mfadd: mflinear([F,G],[1,1]) *** ^--------------------- *** mflinear: incorrect type in mflinear [different characters] (t_VEC). *** at top-level: mfparams(mfadd(F4,F6)) *** ^------------- *** in function mfadd: mflinear([F,G],[1,1]) *** ^--------------------- *** mflinear: incorrect type in mflinear [different weights] (t_VEC). *** at top-level: mfinit([23,1,Mod(22,45)],0) *** ^--------------------------- *** mfinit: incorrect type in checkNF [chi] (t_VEC). *** at top-level: mfinit([23,2,Mod(22,45)],0) *** ^--------------------------- *** mfinit: incorrect type in checkNF [chi] (t_VEC). *** at top-level: mfinit([7,1,-7],2) *** ^------------------ *** mfinit: sorry, mfinit in weight 1 for old space is not yet implemented. *** at top-level: mfinit([7,1,-7],5) *** ^------------------ *** mfinit: invalid flag in mfinit. *** at top-level: mfinit([1,2],5) *** ^--------------- *** mfinit: invalid flag in mfinit. *** at top-level: mfgaloistype([11,1,Mod(2,11)],mfeisenstein(1,1 *** ^---------------------------------------------- *** mfgaloistype: domain error in mfgaloistype: form not a cuspidal eigenform *** at top-level: mfdiv(D,mfpow(D,2)) *** ^------------------- *** mfdiv: domain error in mfdiv: ord(G) > ord(F) *** at top-level: mfeval(mfD,D,-I) *** ^---------------- *** mfeval: domain error in mfeval: imag(tau) <= 0 *** at top-level: mftonew(mfD,1) *** ^-------------- *** mftonew: incorrect type in mftobasis (t_INT). *** at top-level: T=mftraceform([96,6],4) *** ^--------------------- *** mftraceform: domain error in mftraceform: space = 4 *** at top-level: mfshimura(mfinit(T5),T5,-3) *** ^--------------------------- *** mfshimura: incorrect type in shimura [incorrect D] (t_INT). *** at top-level: mftonew(mf,E4) *** ^-------------- *** mftonew: incorrect type in mftonew [not a full or cuspidal space] (t_VEC). *** at top-level: mffields(mf) *** ^------------ *** mffields: incorrect type in mfsplit [space does not contain newspace] (t_VEC). *** at top-level: mfdiv(1,mfTheta()) *** ^------------------ *** mfdiv: incorrect type in mfdiv (t_INT). *** at top-level: mfdiv(D,mftraceform([1,3])) *** ^--------------------------- *** mfdiv: domain error in mfdiv: ord(G) > ord(F) *** at top-level: mfcosets(1.) *** ^------------ *** mfcosets: incorrect type in mfcosets (t_REAL). *** at top-level: ...([1,0]);F=mfbasis(mf)[1];mfsymbol(mf,F) *** ^-------------- *** mfsymbol: incorrect type in mfsymbol [k <= 0] (t_VEC). *** at top-level: mfmanin(FSbug) *** ^-------------- *** mfmanin: incorrect type in mfmanin [need integral k > 1] (t_VEC). *** at top-level: mfsymboleval(FSbug,[0,1]) *** ^------------------------- *** mfsymboleval: incorrect type in mfsymboleval [need integral k > 1] (t_VEC). *** at top-level: mfgaloistype([4,1,-4],x) *** ^------------------------ *** mfgaloistype: incorrect type in mfgaloistype (t_POL). Total time spent: 6392 pari-2.11.2/src/test/32/minim0000644000175000017500000000004313201017466014201 0ustar billbill1 1 78 77 136 Total time spent: 62 pari-2.11.2/src/test/32/subfields0000644000175000017500000000077313326135265015070 0ustar billbill1:[1, 2, 3, 3, 3, 6] 2:[1, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 8] 3:[1, 2, 2, 2, 4, 4, 4, 8] 4:[1, 2, 4, 8] 5:[1, 3, 3, 3, 3, 9] 6:[1, 5, 10] 7:[1, 5, 10] 8:[1, 2, 10] 9:[1, 3, 4, 12] 10:[1, 2, 3, 4, 6, 12] 11:[1, 3, 4, 4, 4, 4, 6, 6, 6, 12] 12:[1, 3, 15] 13:[1, 2, 4, 8, 16, 32] 14:[1, 3, 3, 3, 3, 9, 9, 9, 9, 27] 15:[1, 2, 4, 6, 6, 6, 12] 16:[1, 2, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24] 17:[1, 2, 2, 2, 4, 6, 6, 6, 12] Total time spent: 6176 pari-2.11.2/src/test/32/content0000644000175000017500000000240313326135265014552 0ustar billbilldenominator 1 1 1 3 1 6 1 1 3 1 1 x error("incorrect type in denom (t_QFI).") error("incorrect type in denom (t_QFR).") 4 2 1 1 1 1 (x)->denominator(x,1) 1 1 1 3 1 6 8 2 3 2 1 1 1 1 4 2 2 2 2 1 (x)->denominator(x,'y) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2*y 2*y 2*y 1 numerator 2 1.0000000000000000000000000000000000000 Mod(1, 3) 2 x 3 + 2*I O(2^-3) 2^-1 + O(2^3) w Mod(1/2*x, x^2) 2*x 2 error("incorrect type in numer (t_QFI).") error("incorrect type in numer (t_QFR).") [8, 3] [2, 4; 3, 8] 1/y*x + 1/2 [1/y*x + 1/2] 1/(2*y) + O(x^2) y + O(y^2) (x)->numerator(x,1) 2 1.0000000000000000000000000000000000000 Mod(1, 3) 2 x 3 + 2*I O(2^0) 1 + O(2^4) w Mod(x, x^2) 2*x 2/x Qfb(1, 2, 4) Qfb(-1, 2, 4, 0.E-38) [8, 3] [2, 4; 3, 8] 2/y*x + 1 [2/y*x + 1] 1/y + O(x^2) y + O(y^2) (x)->numerator(x,'y) 2 1.0000000000000000000000000000000000000 Mod(1, 3) 2/3 x (1/2 + 1/3*I) O(2^-3) (2^-1 + O(2^3)) 1/3*w Mod(1/2*x, x^2) 2*x 2/x Qfb(1, 2, 4) Qfb(-1, 2, 4, 0.E-38) [2, 3/4] [1, 2; 3/2, 4] 2*x + y [2*x + y] 1 + O(x^2) y + O(y^2) content 2 1 Mod(1, 3) 2/3 x 1/2 + 1/3*I 1/8 1/2 1/3*w 1/2 2 2 1 1 1/4 1/2 1/(2*y) 1/y*x + 1/2 1/(2*y) 1 (x)->content(x,1) 2 1 1 2/3 1 1/6 1 1 1 1/2 2 2 1 1 1/4 1/2 1/2 1/2 1 1 (x)->content(x,'y) 1 1 1 1 1 1 1 1 1 1/2 2 2 1 1 1 1 1/2 1/y*x + 1/2 1/2 1 Total time spent: 1 pari-2.11.2/src/test/32/pow0000644000175000017500000000435113326135265013711 0ustar billbillMod(1, 3) Mod(1, 3) 1 [;] [1] Mod(0, 1) Mod(1, 3) Qfb(1, 2, -1, 0.E-38) Qfb(-1, 2, 1, 0.E-38) Vecsmall([1, 2, 3]) O(2) *** at top-level: O(2)^-2 *** ^--- *** _^_: impossible inverse in powps: O(2). 4 9/4 1 1 -1 *** at top-level: 2^n *** ^-- *** _^_: overflow in lg(). *** at top-level: (1/2)^n *** ^-- *** _^_: overflow in lg(). Qfb(2, 0, -1, 0.E-38) Mod(x^2, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) O(x^0) x + O(x^4) [8.0000000000000000000000000000000000000, 27.0000000000000000000000000000000 00000] [8.0000000000000000000000000000000000000, 27.0000000000000000000000000000000 00000]~ [8.0000000000000000000000000000000000000] O(x^0) 0.E-19 *** at top-level: Mod(2,3)^(1/2) *** ^------ *** _^_: not an n-th power residue in gpow: Mod(2, 3). Mod(2, 3) *** at top-level: Mod(1,4)^(1/2) *** ^------ *** _^_: not a prime number in gpow: 4. 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + O(7^5) *** at top-level: (3+O(7^5))^(1/2) *** ^------ *** _^_: not an n-th power residue in gpow: 3 + O(7^5). 1 + 3*7 + 5*7^2 + O(7^3) 1 + O(2) 1 + O(2) *** at top-level: sqrt(Mod(2,4)) *** ^-------------- *** sqrt: not a prime number in Fl_sqrt [modulus]: 4. [[0, 0], [1.0000000000000000000000000000000000000, 1.00000000000000000000000 00000000000000]] [[0, 0]~, [1.0000000000000000000000000000000000000, 1.0000000000000000000000 000000000000000]~] [[0, 0; 0, 0], [1.0000000000000000000000000000000000000, 1.00000000000000000 00000000000000000000; 1.0000000000000000000000000000000000000, 1.00000000000 00000000000000000000000000]] Mod(0, 1) 0.49999999965342640984014059874318224111 [4.0000000000000000000000000000000000000]~ [Mod(1, 11), Mod(2, 11), Mod(4, 11), Mod(8, 11), Mod(5, 11), Mod(10, 11), Mo d(9, 11), Mod(7, 11), Mod(3, 11), Mod(6, 11), Mod(1, 11)] [1, 3.1415926535897932384626433832795028842, 9.86960440108935861883449099987 61511353, 31.006276680299820175476315067101395202, 97.4090910340024372364403 32688705111250, 306.01968478528145326274131004343560648, 961.389193575304437 03021944365241989886, 3020.2932277767920675142064930720418319] [2, 6, 18, 54, 162, 486] [] [1] Total time spent: 1 pari-2.11.2/src/test/32/qfbsolve0000644000175000017500000000000011636712103014702 0ustar billbillpari-2.11.2/src/test/32/err0000644000175000017500000007041413457566437013715 0ustar billbill *** at top-level: g(10) *** ^----- *** in function g: for(i=-N,N,f(i)) *** ^----- *** in function f: 1/x *** ^-- *** _/_: impossible inverse in gdiv: 0. *** at top-level: f(Mat(0),Col(1)) *** ^---------------- *** in function f: matsolve *** ^-------- *** matsolve: impossible inverse in gauss: Mat(0). *** at top-level: (matsolve)(Mat(0),Col(1)) *** ^------------------------ *** matsolve: impossible inverse in gauss: Mat(0). *** at top-level: g(I) *** ^---- *** in function g: [x.foo] *** ^---- *** in member function foo: 1/(1+a^2) *** ^-------- *** _/_: impossible inverse in gdiv: 0. *** at top-level: (x->1/x)(0) *** ^---------- *** in anonymous function: 1/x *** ^-- *** _/_: impossible inverse in gdiv: 0. 274177 274177 *** at top-level: ...=2;A=x^2+1;B=[x+t,x+t];r=polhensellift(A,B,[p, *** ^--------------------- *** polhensellift: elements not coprime in BuildTree: x + t x + t *** at top-level: M[,1]=1 *** ^------- *** incorrect type in matrix col assignment (t_INT). *** at top-level: M[,3]=1 *** ^------ *** non-existent component: index > 2 *** at top-level: M[,1]=[1,2] *** ^----------- *** incorrect type in matrix col assignment (t_VEC). *** at top-level: M[,1]=[1,2,3]~ *** ^-------------- *** inconsistent dimensions in matrix col assignment. *** at top-level: M[1,]=1 *** ^------- *** incorrect type in matrix row assignment (t_INT). *** at top-level: M[3,]=1 *** ^------ *** non-existent component: index > 2 *** at top-level: M[1,]=[1,2]~ *** ^------------ *** incorrect type in matrix row assignment (t_COL). *** at top-level: M[1,]=[1,2,3] *** ^------------- *** inconsistent dimensions in matrix row assignment. *** at top-level: [;][1,] *** ^---- *** non-existent component: index > 0 *** at top-level: [;][,1] *** ^---- *** non-existent component: index > 0 *** at top-level: 1[1] *** ^--- *** incorrect type in _[_] OCcompo1 [not a vector] (t_INT). *** at top-level: issquare(1,&v[1]) *** ^---- *** incorrect type in &_[_] OCcompo1ptr [not a vector] (t_POL). *** at top-level: 1[1,1] *** ^----- *** incorrect type in _[_,_] OCcompo2 [not a matrix] (t_INT). *** at top-level: 1[,1] *** ^---- *** incorrect type in _[,_] OCcompoC [not a matrix] (t_INT). *** at top-level: issquare(1,&v[,1]) *** ^----- *** incorrect type in &_[,_] OCcompoCptr [not a matrix] (t_POL). *** at top-level: 1[1,] *** ^---- *** incorrect type in _[_,] OCcompoL [not a matrix] (t_INT). *** at top-level: issquare(1,&v[1,]) *** ^----- *** incorrect type in &_[_,] OCcompoLptr [not a matrix] (t_POL). *** at top-level: v[2]=1 *** ^----- *** non-existent component: index > 1 *** at top-level: v[1]=Pi *** ^------- *** incorrect type in t_VECSMALL assignment (t_REAL). *** at top-level: v[1]=2^64 *** ^--------- *** incorrect type in t_VECSMALL assignment (t_INT). *** at top-level: v[Pi]=1 *** ^----- *** incorrect type in gtos [integer expected] (t_REAL). *** at top-level: M=[1.,0;0,1];qflll(M,1) *** ^---------- *** qflll: incorrect type in qflll [integer matrix] (t_MAT). *** at top-level: addprimes(1.) *** ^------------- *** addprimes: incorrect type in addprimes [integer vector] (t_VEC). *** at top-level: nfalgtobasis(nfinit(t^3-2),Mod(t,t^2+1)) *** ^---------------------------------------- *** nfalgtobasis: inconsistent moduli in algtobasis: t^3 - 2 != t^2 + 1 *** at top-level: vector(-1,i,0) *** ^-------------- *** vector: domain error in vector: dimension < 0 *** at top-level: vectorv(-1,i,0) *** ^--------------- *** vectorv: domain error in vector: dimension < 0 *** at top-level: vectorsmall(-1,i,0) *** ^------------------- *** vectorsmall: domain error in vectorsmall: dimension < 0 *** at top-level: matrix(-1,1,i,j,0) *** ^------------------ *** matrix: domain error in matrix: nbrows < 0 *** at top-level: matrix(1,-1,i,j,0) *** ^------------------ *** matrix: domain error in matrix: nbcols < 0 *** at top-level: next(-1) *** ^-------- *** next: domain error in next: n < 1 *** at top-level: break(-1) *** ^--------- *** break: domain error in break: n < 1 *** at top-level: v[-1] *** ^---- *** non-existent component: index < 1 *** at top-level: v[#v+1] *** ^------ *** non-existent component: index > 1 *** variable name expected: subst(x,1,0) *** ^---- *** at top-level: exp(1e40) *** ^--------- *** exp: overflow in expo(). *** at top-level: exp(-1e40) *** ^---------- *** exp: overflow in expo(). *** at top-level: exp(1/x) *** ^-------- *** exp: domain error in exp: valuation < 0 *** at top-level: cos(1/x) *** ^-------- *** cos: domain error in cos: valuation < 0 *** at top-level: sin(1/x) *** ^-------- *** sin: domain error in sin: valuation < 0 *** at top-level: tan(1/x) *** ^-------- *** tan: domain error in tan: valuation < 0 *** at top-level: cotan(1/x) *** ^---------- *** cotan: domain error in cotan: valuation < 0 *** at top-level: atan(1/x) *** ^--------- *** atan: domain error in atan: valuation < 0 *** at top-level: asin(1/x) *** ^--------- *** asin: domain error in asin: valuation < 0 *** at top-level: acos(1/x) *** ^--------- *** acos: domain error in acos: valuation < 0 *** at top-level: asinh(1/x) *** ^---------- *** asinh: domain error in asinh: valuation < 0 *** at top-level: acosh(1/x) *** ^---------- *** acosh: domain error in acosh: valuation < 0 *** at top-level: atanh(1/x) *** ^---------- *** atanh: domain error in atanh: valuation < 0 *** at top-level: lngamma(x) *** ^---------- *** lngamma: domain error in lngamma: valuation != 0 *** at top-level: besselj(2,1/x) *** ^-------------- *** besselj: domain error in besselj: valuation < 0 *** at top-level: besseljh(2,1/x) *** ^--------------- *** besseljh: domain error in besseljh: valuation < 0 *** at top-level: besselk(2,1/x) *** ^-------------- *** besselk: domain error in _kbessel1: valuation < 0 *** at top-level: besselk(1/3,O(x)) *** ^----------------- *** besselk: domain error in besselk: 2n mod Z != 0 *** at top-level: besseln(2,1/x) *** ^-------------- *** besseln: domain error in _kbessel1: valuation < 0 *** at top-level: besseln(1/3,O(x)) *** ^----------------- *** besseln: domain error in besseln: 2n mod Z != 0 *** at top-level: polylog(2,1/x) *** ^-------------- *** polylog: domain error in polylog: valuation < 0 *** at top-level: sqrt(x) *** ^------- *** sqrt: domain error in sqrtn: valuation != Mod(0, 2) *** at top-level: sqrt(2+O(2^2)) *** ^-------------- *** sqrt: not an n-th power residue in Qp_sqrt: 2 + O(2^2). *** at top-level: sqrtn(x,3) *** ^---------- *** sqrtn: domain error in sqrtn: valuation != Mod(0, 3) *** at top-level: sqrtn(2+O(2^2),3) *** ^----------------- *** sqrtn: not an n-th power residue in gsqrtn: 2 + O(2^2). *** at top-level: log(x) *** ^------ *** log: domain error in log: series valuation != 0 *** at top-level: log(0) *** ^------ *** log: domain error in log: argument = 0 *** at top-level: abs(x+O(x^2)) *** ^------------- *** abs: domain error in abs: series valuation != 0 *** at top-level: real(Vecsmall([])) *** ^------------------ *** real: incorrect type in greal/gimag (t_VECSMALL). *** at top-level: imag(Vecsmall([])) *** ^------------------ *** imag: incorrect type in greal/gimag (t_VECSMALL). *** at top-level: vecmax(Vecsmall([])) *** ^-------------------- *** vecmax: domain error in vecmax: empty argument = Vecsmall([]) *** at top-level: vecmax([]) *** ^---------- *** vecmax: domain error in vecmax: empty argument = [] *** at top-level: vecmax([],&i) *** ^------------- *** vecmax: domain error in vecmax: empty argument = [] *** at top-level: vecmin(Vecsmall([])) *** ^-------------------- *** vecmin: domain error in vecmin: empty argument = Vecsmall([]) *** at top-level: vecmin([]) *** ^---------- *** vecmin: domain error in vecmin: empty argument = [] *** unexpected character '&': vecmmin([],&i) *** ^--- *** at top-level: vecmax(matrix(0,2)) *** ^------------------- *** vecmax: domain error in vecmax: empty argument = matrix(0,2) *** at top-level: listput(L,x,-1) *** ^--------------- *** listput: non-existent component in listput: index < 0 *** at top-level: listinsert(L,x,-1) *** ^------------------ *** listinsert: non-existent component in listinsert: index <= 0 *** at top-level: listinsert(L,x,10) *** ^------------------ *** listinsert: non-existent component in listinsert: index > 1 *** at top-level: ellj(Mod(1,2)) *** ^-------------- *** ellj: incorrect type in modular function (t_INTMOD). *** at top-level: ellj(Qfb(1,1,1)) *** ^---------------- *** ellj: incorrect type in ellj (t_QFI). *** at top-level: eta(1+O(2)) *** ^----------- *** eta: domain error in eta: v_p(q) <= 0 *** at top-level: eta(1/x) *** ^-------- *** eta: domain error in eta: v_p(q) <= 0 *** at top-level: idealhnf(K,Qfb(1,1,1)) *** ^---------------------- *** idealhnf: domain error in idealhnf [Qfb]: disc(q) != -4 *** at top-level: idealfactor(K,[;]) *** ^------------------ *** idealfactor: domain error in idealfactor: ideal = 0 *** at top-level: idealdiv(K,2,0,1) *** ^----------------- *** idealdiv: impossible inverse in idealdivexact: 0. *** at top-level: valuation(Pi,2) *** ^--------------- *** valuation: inconsistent valuation t_REAL , t_INT. *** at top-level: x^Pi *** ^--- *** _^_: domain error in gpow [irrational exponent]: valuation != 0 *** at top-level: x^x *** ^-- *** _^_: domain error in gpow [irrational exponent]: valuation != 0 *** at top-level: 0^0. *** ^--- *** _^_: domain error in gpow(0,n): n <= 0 *** at top-level: agm([],[]) *** ^---------- *** agm: forbidden agm t_VEC (0 elts) , t_VEC (0 elts). *** at top-level: sin(1/2+O(2^1)) *** ^--------------- *** sin: domain error in gsin(t_PADIC): argument out of range *** at top-level: cos(1/9+O(3^1)) *** ^--------------- *** cos: domain error in gcos(t_PADIC): argument out of range *** at top-level: exp(1/9+O(3^1)) *** ^--------------- *** exp: domain error in gexp(t_PADIC): argument out of range *** at top-level: ...],Vecsmall([2,2,2,2,3])];galoissubgroups(G) *** ^------------------ *** galoissubgroups: sorry, group_quotient for a non-WSS group is not yet implemented. *** at top-level: bnrstark(bnrinit(bnfinit(y^2+1),2)) *** ^----------------------------------- *** bnrstark: domain error in bnrstark: r2 != 0 *** at top-level: bnrstark(bnrinit(bnfinit(y^2-2),[4,[1,1]])) *** ^------------------------------------------- *** bnrstark: domain error in bnrstark: r2(class field) != 0 *** at top-level: quadray(-16,1) *** ^-------------- *** quadray: domain error in quadray: isfundamental(D) = 0 *** at top-level: quadray(bnfinit(x^3-2),1) *** ^------------------------- *** quadray: domain error in quadray: degree != 2 *** at top-level: galoissubcyclo(-1) *** ^------------------ *** galoissubcyclo: domain error in galoissubcyclo: degree <= 0 *** at top-level: galoissubcyclo(6,Mod(1,3)) *** ^-------------------------- *** galoissubcyclo: inconsistent moduli in galoissubcyclo: 6 != 3 *** at top-level: galoissubcyclo(6,[;]) *** ^--------------------- *** galoissubcyclo: incorrect type in galoissubcyclo [H not in HNF] (t_MAT). *** at top-level: galoissubcyclo(6,Mat(1)) *** ^------------------------ *** galoissubcyclo: incorrect type in galoissubcyclo [N not a bnrinit or znstar] (t_MAT). *** at top-level: galoissubcyclo(znstar(5),matid(2)) *** ^---------------------------------- *** galoissubcyclo: inconsistent dimensions in galoissubcyclo. *** at top-level: galoissubcyclo([3,[3],[3]],Mat(3)) *** ^---------------------------------- *** galoissubcyclo: incorrect type in galoissubcyclo (t_VEC). *** at top-level: galoissubcyclo(bnrinit(bnfinit(y^2+1),1),2) *** ^------------------------------------------- *** galoissubcyclo: domain error in bnr_to_znstar: bnr != Q *** at top-level: polsubcyclo(-1,2) *** ^----------------- *** polsubcyclo: domain error in polsubcyclo: n <= 0 *** at top-level: polsubcyclo(2,-1) *** ^----------------- *** polsubcyclo: domain error in polsubcyclo: d <= 0 *** at top-level: random(-1) *** ^---------- *** random: domain error in random: N <= 0 *** at top-level: znprimroot(0) *** ^------------- *** znprimroot: domain error in znprimroot: argument = 0 *** at top-level: sqrtint(-1) *** ^----------- *** sqrtint: domain error in sqrtint: argument < 0 *** at top-level: sqrtnint(-1,2) *** ^-------------- *** sqrtnint: domain error in sqrtnint: x < 0 *** at top-level: sqrtnint(2,-2) *** ^-------------- *** sqrtnint: domain error in sqrtnint: n <= 0 *** at top-level: znprimroot(8) *** ^------------- *** znprimroot: domain error in znprimroot: argument = 8 *** at top-level: polroots(x^2+Mod(1,2)) *** ^---------------------- *** polroots: incorrect type in roots (t_INTMOD). *** at top-level: polroots(0) *** ^----------- *** polroots: zero polynomial in roots. *** at top-level: polroots(Mod(1,2)) *** ^------------------ *** polroots: incorrect type in roots (t_INTMOD). *** at top-level: polrootsmod(x,x) *** ^---------------- *** polrootsmod: incorrect type in factormod (t_POL). *** at top-level: prime(-2) *** ^--------- *** prime: domain error in prime: n <= 0 *** at top-level: addprimes(-1) *** ^------------- *** addprimes: domain error in addprimes: p < 2 *** at top-level: padicappr(x^2+1+O(3^5),1+O(5)) *** ^------------------------------ *** padicappr: inconsistent moduli in Zp_to_Z: 5 != 3 *** at top-level: factorpadic(x^2+1,2,-1) *** ^----------------------- *** factorpadic: domain error in factorpadic: precision <= 0 *** at top-level: polrootspadic(x^2+1,2,-1) *** ^------------------------- *** polrootspadic: domain error in rootpadic: precision <= 0 *** at top-level: ellinit([1+O(3),1+O(5)]) *** ^------------------------ *** ellinit: inconsistent moduli in ellinit: 3 != 5 *** at top-level: ellwp([1,I],I) *** ^-------------- *** ellwp: domain error in ellwp: argument = 0 *** at top-level: ellsigma([1,I],x,1) *** ^------------------- *** ellsigma: incorrect type in log(ellsigma) (t_SER). *** at top-level: ellsigma([1,I],1,1) *** ^------------------- *** ellsigma: domain error in log(ellsigma): argument = 0 *** at top-level: ellap(E) *** ^-------- *** ellap: incorrect type in ellap [can't determine p] (t_VEC). *** at top-level: ellap(E,1) *** ^---------- *** ellap: domain error in ellap: p < 2 *** at top-level: ellap(E,'x) *** ^----------- *** ellap: incorrect type in ellap (t_POL). *** at top-level: ellissupersingular(x,1) *** ^----------------------- *** ellissupersingular: incorrect type in checkell (t_POL). *** at top-level: elltaniyama(E,-1) *** ^----------------- *** elltaniyama: domain error in elltaniyama: precision < 0 *** at top-level: ellheight(E,[2,2]) *** ^------------------ *** ellheight: domain error in ellheight: point not on E *** at top-level: Qfb(0,0,0) *** ^---------- *** Qfb: domain error in Qfb: issquare(disc) = 1 *** at top-level: quadpoly(2) *** ^----------- *** quadpoly: domain error in quadpoly: disc % 4 > 1 *** at top-level: qfbprimeform(2,5) *** ^----------------- *** qfbprimeform: domain error in primeform: disc % 4 > 1 *** at top-level: qfbcomp(Qfb(1,1,1),Qfb(1,0,2)) *** ^------------------------------ *** not a function in function call *** at top-level: galoisinit(x^2) *** ^--------------- *** galoisinit: domain error in galoisinit: issquarefree(pol) = 0 *** at top-level: galoisinit(2*x) *** ^--------------- *** galoisinit: sorry, galoisinit(non-monic) is not yet implemented. *** at top-level: ellL1(1,-1) *** ^----------- *** ellL1: domain error in ellL1: derivative order < 0 *** at top-level: ellheegner(ellinit([0,-1,1,-10,-20])) *** ^------------------------------------- *** ellheegner: domain error in ellheegner: (analytic rank)%2 = 0 *** at top-level: ellheegner(ellinit([0,0,1,-7,6])) *** ^--------------------------------- *** ellheegner: domain error in ellheegner: analytic rank > 1 *** at top-level: substpol(x+O(x^2),x^3,x) *** ^------------------------ *** substpol: domain error in gdeflate: valuation(x) % 3 != 0 *** at top-level: intformal(1/(x^2+1)) *** ^-------------------- *** intformal: domain error in intformal: residue(series, pole) != 0 *** at top-level: component(x,-1) *** ^--------------- *** component: non-existent component: index < 1 *** at top-level: component(O(x),2) *** ^----------------- *** component: non-existent component: index > 0 *** at top-level: component(Vecsmall([]),1) *** ^------------------------- *** component: non-existent component: index > 0 *** at top-level: component(x->x,6) *** ^----------------- *** component: non-existent component: index > 5 *** at top-level: polcoef(O(x),2) *** ^--------------- *** polcoef: domain error in polcoef: t_SER = O(x) *** at top-level: polcoef(x+O(x^2),2) *** ^------------------- *** polcoef: domain error in polcoef: degree > 1 *** at top-level: polcoef([],2) *** ^------------- *** polcoef: incorrect type in polcoef (t_VEC). *** at top-level: matcompanion(0*x) *** ^----------------- *** matcompanion: domain error in matcompanion: polynomial = 0 *** at top-level: matrixqz(Mat([1,2])) *** ^-------------------- *** matrixqz: domain error in QM_minors_coprime: n > m *** at top-level: matrixqz(Mat(0)) *** ^---------------- *** matrixqz: domain error in QM_minors_coprime: rank(A) < 1 *** at top-level: vecextract([1],[-1]) *** ^-------------------- *** vecextract: non-existent component in vecextract: index <= 0 *** at top-level: vecextract([1],[2]) *** ^------------------- *** vecextract: non-existent component in vecextract: index >= 2 *** at top-level: idealfrobenius(K,galoisinit(K),idealprimedec(K *** ^---------------------------------------------- *** idealfrobenius: domain error in idealfrobenius: pr.e > 1 *** at top-level: nfisincl(x^2,x^2) *** ^----------------- *** nfisincl: not an irreducible polynomial in nfisincl: x^2. *** at top-level: polcompositum(x^2,x) *** ^-------------------- *** polcompositum: domain error in polcompositum: issquarefree(arg) = 0 *** at top-level: rnfdedekind(K,x^2+x-1/3) *** ^------------------------ *** rnfdedekind: incorrect type in rnfdedekind [non integral pol] (t_POL). *** at top-level: hilbert(Mod(1,2),1) *** ^------------------- *** hilbert: precision too low in hilbert. *** at top-level: hilbert(Mod(1,3),Mod(1,5)) *** ^-------------------------- *** hilbert: inconsistent moduli in hilbert: 5 != 3 *** at top-level: hilbert(Mod(1,3),2,0) *** ^--------------------- *** hilbert: inconsistent moduli in hilbert: 3 != "oo" *** at top-level: znorder(0) *** ^---------- *** znorder: incorrect type in znorder [t_INTMOD expected] (t_INT). *** at top-level: znorder(Mod(2,4)) *** ^----------------- *** znorder: elements not coprime in znorder: 2 4 *** at top-level: contfrac(1e100) *** ^--------------- *** contfrac: precision too low in gboundcf. *** at top-level: contfrac(1.,[1],10) *** ^------------------- *** contfrac: inconsistent dimensions in contfrac [too few denominators]. *** at top-level: contfrac(1,,-1) *** ^--------------- *** contfrac: domain error in gboundcf: nmax < 0 *** at top-level: contfracpnqn(matrix(3,1)) *** ^------------------------- *** contfracpnqn: inconsistent dimensions in pnqn [ nbrows != 1,2 ]. *** at top-level: divisors(1/2) *** ^------------- *** divisors: incorrect type in divisors [denominator] (t_FRAC). *** at top-level: idealstar(K,0) *** ^-------------- *** idealstar: domain error in idealfactor: ideal = 0 *** at top-level: idealstar(K,1/2) *** ^---------------- *** idealstar: domain error in Idealstar: denominator(ideal) != 1 *** at top-level: idealaddtoone(K,[[;]]) *** ^---------------------- *** idealaddtoone: domain error in idealaddmultoone: sum(ideals) != 1 *** at top-level: idealdiv(K,1,2,1) *** ^----------------- *** idealdiv: domain error in idealdivexact: denominator(x/y) != 1 *** at top-level: idealred(K,matid(2),[]) *** ^----------------------- *** idealred: inconsistent dimensions in idealred. *** at top-level: idealtwoelt(K,matid(2),1/2) *** ^--------------------------- *** idealtwoelt: domain error in idealtwoelt2: element mod ideal != 0 *** at top-level: rnf=rnfinit(K,x^2-y);rnfeltdown(rnf,x) *** ^----------------- *** rnfeltdown: domain error in rnfeltdown: element not in the base field *** at top-level: matid(-1) *** ^--------- *** matid: domain error in matid: size < 0 *** at top-level: polinterpolate([1,1],[2,3],Pi) *** ^------------------------------ *** polinterpolate: domain error in polinterpolate: X[1] = X[2] *** at top-level: modreverse(Mod(-x^3+9*x,x^4-10*x^2+1)) *** ^-------------------------------------- *** modreverse: domain error in modreverse: deg(minpoly(z)) < 4 [;] *** at top-level: concat([1,2],[3,4]~) *** ^-------------------- *** concat: inconsistent concatenation t_VEC (2 elts) , t_COL (2 elts). *** at top-level: concat([]) *** ^---------- *** concat: domain error in concat: vector = [] *** at top-level: concat(List()) *** ^-------------- *** concat: domain error in concat: vector = List([]) *** at top-level: mathnfmod([1;2],2) *** ^------------------ *** mathnfmod: domain error in ZM_hnfmod: nb lines > nb columns *** at top-level: removeprimes(2) *** ^--------------- *** removeprimes: domain error in removeprimes: prime not in primetable *** at top-level: forstep(a=1,2,0,) *** ^----------------- *** forstep: domain error in forstep: step = 0 *** at top-level: e.omega *** ^----- *** _.omega: incorrect type in omega [not defined over C] (t_VEC). *** at top-level: e.eta *** ^--- *** _.eta: incorrect type in eta [not defined over C] (t_VEC). *** at top-level: e.area *** ^---- *** _.area: incorrect type in area [not defined over C] (t_VEC). *** at top-level: e.tate *** ^---- *** _.tate: incorrect type in tate [not defined over Qp] (t_VEC). *** at top-level: ellorder(e,[0,0]*Mod(1,2)) *** ^-------------------------- *** ellorder: sorry, ellorder for curve with singular reduction is not yet implemented. *** at top-level: thue(x*(x^3-2),0) *** ^----------------- *** thue: domain error in thue: #sols = oo *** at top-level: direuler(p=2,10,2/(1-p*X)) *** ^---------- *** domain error in direuler: constant term != 1 *** at top-level: solve(x=0,1,x^2+1) *** ^------ *** domain error in solve: f(a)f(b) > 0 *** user warning: 1 *** at top-level: iferr(1/0,E,1,errname(E)=="e_DOMAIN") *** ^------------------------------------- *** iferr: impossible inverse in gdiv: 0. 4 *** at top-level: iferr(1/0,E,1,break()) *** ^-------- *** break not allowed here. (x)->trap(e_INV,INFINITY,1/x) 1/2 INFINITY *** at top-level: trap(e_INV,INFINITY,log(0)) *** ^------- *** log: domain error in log: argument = 0 *** at top-level: notafunc('a) *** ^------------ *** not a function in function call 1 *** at top-level: znlog(Mod(1,n),Mod(1,n+1)) *** ^-------------------------- *** znlog: inconsistent moduli in Rg_to_Fp: (...) != (...) *** at top-level: Mod(0,n)^(-1) *** ^----- *** _^_: impossible inverse in Fp_inv: (...). *** at top-level: a*b *** ^-- *** _*_: inconsistent multiplication t_POL * t_POL. *** at top-level: a%b *** ^-- *** _%_: inconsistent division t_POL % t_POL. *** at top-level: (a*x^2+b)^2 *** ^-- *** _^s: inconsistent multiplication t_POL * t_POL. *** at top-level: matrank(M) *** ^---------- *** matrank: inconsistent rank t_MAT (2x2) , t_POL. *** at top-level: matimage(M) *** ^----------- *** matimage: inconsistent image t_MAT (2x2) , t_POL. *** at top-level: matker(M) *** ^--------- *** matker: inconsistent ker t_MAT (2x2) , t_POL. *** incorrect value for plothsizes: [ *** ^ *** incorrect value for plothsizes: 1 *** ^- *** incorrect value for plothsizes: [2, *** ^ Total time spent: 4 pari-2.11.2/src/test/32/modsym0000644000175000017500000004145513326135265014422 0ustar billbill *** Warning: new stack size = 40000000 (38.147 Mbytes). 2 1 3 -1 1 0 11 2 [-2] [3 2] [0 -2] [3 1 1] [0 -2 0] [0 0 -2] [1 0] [0 1] 1 12 0 [1 0 0] [0 1 0] [0 0 1] [[-691, 0; 0, -1; 36, 0], [-1, 0; 0, -691], 691, Vecsmall([1, 2])] 3 [[0; 0; -1], Mat(-1), 1, Vecsmall([3])] [0, 1, 0]~ [4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x] -4*x^9 + 25*x^7 - 42*x^5 + 25*x^3 - 4*x [0, 0, -1]~ [0 -691] [1 0] [0 36] [-24 0 0] [ 0 -24 0] [108 0 2049] 1 [ 0 -1/120] [1/630 0] [ 0 3/6910] [[-691, 0; 0, -1; 36, 0], [-1, 0; 0, -691], 691, Vecsmall([1, 2])] [[[+oo, 0]], [[[[1, 1; [0, 1; -1, 0], 1], 1]], [[[1, 1; [0, -1; 1, -1], 1; [ -1, 1; -1, 0], 1], 1]]]] [Mat([[1, 1; 2, 3], 1])] 0 [[[1, 0; 0, 1], [0, 1; -1, 0]], Vecsmall([1, 2]), [[0, 1; -1, 0], [0, -1; 1, -1]]] [1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920, 534612, - 370944, -577738, 401856, 1217160, 987136] [1 0 0] [0 -1 0] [0 0 1] [[[-43780709, 1166927608; -199616, -774931811; 105162624, 125134377984], [-7 74931811, -1166927608; 199616, -43780709], 34160001533632527, Vecsmall([1, 2 ])]] 0 0 *** at top-level: mseval(W,xpm[1],[1]) *** ^-------------------- *** mseval: incorrect type in mspathlog (t_VEC). 1/2 [1/4, -1/2, -1/2] -1/2 [[1/6, -1/12, 0, -1/6, -1/3, 1/6, 1/4, 1/12, 0, 1/6, 1/12, -1/12, -1/12]~, [ 0, 1/4, 1/2, 0, 0, 0, -1/4, -1/4, -1/2, 0, 1/4, 1/4, -1/4]~, [1/6, 0; -1/3, 1/2; -1/2, 1; -1/6, 0; -1/3, 0; 1/6, 0; 1/2, -1/2; 1/3, -1/2; 1/2, -1; 1/6, 0; -1/6, 1/2; -1/3, 1/2; 1/6, -1/2]] [[0, 1/2, -1/2, 1/11, -1/2, 0, 3/11, -1/22, 0, 0, -3/22, -1/2, 0, -1/2, 0, - 2/11, -2/11, 0, -3/22, -1/22, -1/2, 3/11, 1/11]~, [0, 1/2, 3/2, -1, -1/2, -1 , 0, -1/2, -1, 1, -1/2, 1/2, 1, 1/2, -2, 0, 0, 1, 1/2, 1/2, 1/2, 0, 1]~, [0, 0; 0, 1; -2, 3; 12/11, -2; 0, -1; 1, -2; 3/11, 0; 5/11, -1; 1, -2; -1, 2; 4 /11, -1; -1, 1; -1, 2; -1, 1; 2, -4; -2/11, 0; -2/11, 0; -1, 2; -7/11, 1; -6 /11, 1; -1, 1; 3/11, 0; -10/11, 2]] [[1/2, -1/2, -1/2, -1/2, 1/2, 1/4, 1/2, 0, -1/4, -1/2, 0, -1/4, 1/4]~, [0, 1 /2, 0, 0, -1/2, 1/8, 0, 1/2, -3/8, -1/2, 0, 3/8, -1/8]~, [1/2, 0; -1, 1; -1/ 2, 0; -1/2, 0; 1, -1; 1/8, 1/4; 1/2, 0; -1/2, 1; 1/8, -3/4; 0, -1; 0, 0; -5/ 8, 3/4; 3/8, -1/4]] [[1, -1, 0, -1/2, 0, -1/2, 1/2, 1, -1/2, -1, 1/2, 0, 0, -1/2, 0, 1/2, -1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2, 1, -1]~, [0, 0, 2/5, 1/10, 0, -1/2, 1/10, 0 , 1/2, 0, -1/2, 0, -2/5, -1/10, 0, 1/2, -1/2, -1/2, -1/10, 1/2, -1/10, 1/2, -1/2, 0, -2/5]~, [1, 0; -1, 0; -2/5, 4/5; -3/5, 1/5; 0, 0; 0, -1; 2/5, 1/5; 1, 0; -1, 1; -1, 0; 1, -1; 0, 0; 2/5, -4/5; -2/5, -1/5; 0, 0; 0, 1; 0, -1; 1 , -1; 3/5, -1/5; -1, 1; 3/5, -1/5; -1, 1; 0, -1; 1, 0; -3/5, -4/5]] [[1/3, -1/2, 1/6, 0, -1/2, 1/6, 0]~, [0, 1/2, -1/6, -1/3, -1/2, 1/6, 1/3]~, [1/3, 0; -1, 1; 1/3, -1/3; 1/3, -2/3; 0, -1; 0, 1/3; -1/3, 2/3]] [[[1/4, -1/2, -1/2]~, [0, 1/2, -1/2]~, [1/4, 0; -1, 1; 0, -1]], [[1/4, -1/2, -1/2]~, [0, 1/2, -1/2]~, [1/4, 0; -1/2, 1/2; -1/2, -1/2]], [[1/2, -1, -1]~, [0, 1/2, -1/2]~, [1/2, 0; -1, 1/2; -1, -1/2]], [[1/8, -1/4, -1/4]~, [0, 1/2 , -1/2]~, [1/8, 0; -1/4, 1/2; -1/4, -1/2]]] [[[-2, -2; -7, -1; -8, 4; -1, -1; 4, 1; -6, 0; -2, 1; 4, 1; 2, -1; -1, -1; 1 1, -1; 9, -3; 8, -4; 5, 2; 8, 2; -2, 1; 4, 1; -8, 1; 1, 1; -1, -1], [1, -2; -7, 2], 12, Vecsmall([1, 2])], [[0, 0; 0, 0; 0, 0; -2, 3; 2, -3; 0, 0; 2, -3 ; 1, -5; 0, 0; -1, 5; -1, 5; -2, 3; -1, -2; -1, 5; -1, 5; 0, 0; -1, 5; 1, -5 ; -1, 5; 1, -5], [-5, -3; -1, -2], 7, Vecsmall([4, 8])], [[0, -4; 0, 2; 0, 4 ; 0, -6; -1, 3; 0, -4; -1, 3; 1, -3; 1, 1; 0, 2; 0, 2; 0, 2; 0, -4; 1, 3; 0, 4; 1, 1; -1, 3; 1, 1; -2, 0; 0, -2], [-3, -4; -1, 0], 4, Vecsmall([1, 5])], [[0, 0, 0; -14, -1, 2; -11, -1, -6; 2, -2, 6; 11, -5, -1; -28, -2, 4; -2, 2 , -6; 10, 2, 3; -1, -8, 7; 16, 8, -6; 16, 8, -6; 17, 7, -3; 1, -1, 3; 16, 8, -6; 4, -1, -5; 12, 9, -1; 15, 0, 1; -15, 0, -1; 3, -9, 2; -1, 1, -3], [-18, 2, 8; 54, -88, -106; 24, -30, 3], 246, Vecsmall([2, 3, 4])], [[0, 2, -4, -2 , -6, -6, -2, -2, 10, 2; -1, 3, 1, -3, 9, 11, 13, 5, 3, -2; 0, 2, -1, -2, 8, 20, 20, 10, -16, 0; 0, -6, 5, 6, -6, -24, -32, -14, 12, 0; 3, 0, 0, -2, -4, -6, -2, -2, -6, 0; 0, 5, -8, -5, -11, -7, 3, -1, 17, 3; -3, -1, 4, 5, 7, 5, -1, 1, -7, -2; -1, -3, -3, -1, 1, 23, 17, 9, 3, 2; 1, 0, 1, 2, -10, -32, -2 8, -14, 12, 0; -1, -2, 3, 6, 8, 16, 8, 8, -32, 0; -1, 0, 7, 4, 18, 18, 10, 8 , -30, -4; 2, -5, 2, 1, -1, -1, -3, -1, -5, 0; 1, 5, -7, -5, -5, 3, 13, 5, - 1, 2; 1, -2, 4, -2, 6, 2, -6, 0, -6, -2; 0, -4, 2, 4, -6, -10, -14, -6, 2, 0 ; 1, 2, 2, 0, 2, -12, -4, -2, -4, -2; 0, 0, -3, -4, -4, -4, -16, 0, 4, 2; 0, 0, 1, 4, 0, 4, 12, -2, -4, 0; 1, 0, 1, 2, 0, -2, -2, 0, -18, 0; 1, 2, -2, - 2, -4, -6, 2, 0, 2, -1], [7524, 1520, -4256, -1824, 2432, -3192, 608, 1216, 912, 912; 1794, 824, -1016, 24, 1112, -60, 368, 496, 408, 504; -2808, 640, 1 088, 1152, -128, 1680, -272, -208, 432, -432; 6696, 1280, -3752, -1800, 2024 , -3024, 824, 952, 864, 504; 1368, 0, -456, -456, 0, -912, 0, 0, 0, 0; 531, 68, -44, 168, 488, 150, 296, 280, -108, 336; 1746, 364, -772, -576, 520, -10 68, 364, 104, 240, -240; -3744, -312, 792, 624, -1488, 1632, -1224, -480, 12 0, -120; 753, 248, -536, -192, 224, -318, 20, 136, 156, 72; -324, 752, 640, 624, 32, 264, -160, -176, 576, -576], 912, Vecsmall([1, 2, 3, 4, 5, 6, 7, 8, 10, 11])]] 0 3 4 [] [[[480; -333; -869; 5082; 20933; 19965], Mat(1), 480, Vecsmall([1])], [[1868 80, -809440, 2610920; -45395, 179585, -543430; -931532, 3896816, -12312388; -5482620, 23280510, -74291580; -12944096, 55235048, -176685289; -10864953, 4 6410639, -148395852], [-311578267, 693784960, -96693630; -175661395, 4373882 00, -56555050; -32022627, 85940960, -10612280], 351095745000, Vecsmall([1, 2 , 3])]] [154, 24] x^2 - 9*x + 8 x^4 - 54*x^3 + 333*x^2 + 10692*x + 39204 x^3 - 84*x^2 + 2352*x - 21952 x^6 - 22*x^5 + 153*x^4 - 316*x^3 - 140*x^2 + 576*x + 324 x^4 - 113*x^3 - 1872*x^2 - 6208*x + 8192 [[[+oo, 0], [0, 1]], [[[[1, 1; [1, 1; 0, 1], -1], 1], [1, 2]], [[[1, 1; [1, -1; 2, -1], 1], 2]]]] [Mat([[1, 0; 0, 1], 1]), 0] [0, Mat([[1, 0; 0, 1], 1])] [Mat([[1, 1; 2, 3], -1]), 0] [0, 0] [8*x^6 - 34*x^4 + 17*x^2 - 1, 48*x^5 + 120*x^4 + 24*x^3 - 84*x^2 - 54*x - 9] 0 [] [2800*x^6 + 7704*x^5 + 8098*x^4 + 4272*x^3 + 1207*x^2 + 174*x + 10, 2800*x^6 + 7704*x^5 + 8098*x^4 + 4272*x^3 + 1207*x^2 + 174*x + 10] 8*x^6 - 34*x^4 + 17*x^2 - 1 48*x^5 + 120*x^4 + 24*x^3 - 84*x^2 - 54*x - 9 [[[1, 1; -5, 0; 0, -5], [0, -1; 5, 1], 5, Vecsmall([1, 2])], [[1; 0; 0], Mat (1), 1, Vecsmall([1])]] 2 1 1 1 [-1, 0, 0]~ [1, 0, 0]~ [-1, 0, 0]~ [-1 -1] [ 5 0] [ 0 5] [Mod(1, x^2 + x - 1), Mod(x, x^2 + x - 1), Mod(-2*x - 1, x^2 + x - 1), Mod(- x - 1, x^2 + x - 1), Mod(2*x, x^2 + x - 1), Mod(x - 2, x^2 + x - 1), Mod(2*x + 2, x^2 + x - 1), Mod(-2*x - 1, x^2 + x - 1), Mod(2, x^2 + x - 1), Mod(-2* x + 2, x^2 + x - 1), Mod(-2*x - 4, x^2 + x - 1), Mod(x + 3, x^2 + x - 1), Mo d(3, x^2 + x - 1), Mod(2, x^2 + x - 1), Mod(2*x - 4, x^2 + x - 1), Mod(3*x, x^2 + x - 1), Mod(-2*x + 2, x^2 + x - 1), Mod(2*x, x^2 + x - 1), Mod(-2, x^2 + x - 1), Mod(-2, x^2 + x - 1), Mod(-2*x - 6, x^2 + x - 1), Mod(-2*x - 2, x ^2 + x - 1), Mod(1, x^2 + x - 1), Mod(5, x^2 + x - 1), Mod(-4*x - 1, x^2 + x - 1), Mod(3*x, x^2 + x - 1), Mod(2*x + 1, x^2 + x - 1), Mod(-2*x - 4, x^2 + x - 1), Mod(-3, x^2 + x - 1), Mod(-6*x + 2, x^2 + x - 1)] [Mod(1, x^2 + x - 1), Mod(x, x^2 + x - 1), Mod(-2*x - 1, x^2 + x - 1), Mod(- x - 1, x^2 + x - 1), Mod(2*x, x^2 + x - 1), Mod(x - 2, x^2 + x - 1), Mod(2*x + 2, x^2 + x - 1), Mod(-2*x - 1, x^2 + x - 1), Mod(2, x^2 + x - 1), Mod(-2* x + 2, x^2 + x - 1), Mod(-2*x - 4, x^2 + x - 1), Mod(x + 3, x^2 + x - 1), Mo d(3, x^2 + x - 1), Mod(2, x^2 + x - 1), Mod(2*x - 4, x^2 + x - 1), Mod(3*x, x^2 + x - 1)] [[1, -2, 0, 2, -2, 0, -2, 0, 0, 4, 4, 0, 2, 4, 0, -4], [1, -1, 0, -1, 2, 0, 4, 3, 0, -2, -4, 0, 2, -4, 0, -1], [1, -1, 0, -1, 3, 0, -3, 3, 0, -3, 0, 0, 4, 3, 0, -1], [1, 1, 0, -1, -2, 0, 4, -3, 0, -2, 4, 0, 2, 4, 0, -1], [1, 1, 0, -1, 1, 0, -5, -3, 0, 1, 4, 0, -4, -5, 0, -1], [1, 2, 0, 2, 0, 0, 0, 0, 0, 0, 6, 0, 4, 0, 0, -4]] [1 0 0 0 0 0] [0 1 0 0 0 0] [0 0 1 0 0 0] [0 0 0 1 0 0] [0 0 0 0 1 0] [0 0 0 0 0 1] 1 [ 1 -2 0 4 -2 1] [ 0 0 0 2 -1 1/2] [ 6 -18 0 78 -36 16] [ 3 2 -1/2 18 -7 5/2] [12 12 -2 60 -23 8] [12 18 -2 48 -18 6] 1 [ 3 0 -1/3 24 -10 4] [ 0 0 0 -3 1 -1/3] [ 24 0 -3 288 -120 48] [ -2 -3 1/3 -32 13 -5] [-12 -12 2 -180 73 -28] [-18 -12 3 -252 102 -39] 1 [ 1 0 0 10 -4 5/3] [-1 0 1/6 -10 4 -3/2] [ 6 6 0 150 -60 24] [ 0 0 0 -24 10 -25/6] [ 0 0 0 -120 49 -20] [ 0 0 0 -150 60 -24] 1 *** at top-level: msatkinlehner(W,4) *** ^------------------ *** msatkinlehner: domain error in msatkinlehner: N % Q != 0 [1 0 0 0 0 0] [0 1 0 0 0 0] [0 0 1 -144 60 -24] [0 0 0 25 -10 4] [0 0 0 120 -49 20] [0 0 0 144 -60 25] 1 [1, 1] 1 0 [[-17150*x^4 + 6950*x^2 - 360, 1008420*x^6 + 3025260*x^5 + 3769570*x^4 + 246 2740*x^3 + 888440*x^2 + 168230*x + 13080, -1008420*x^6 - 3025260*x^5 - 37695 70*x^4 - 2531340*x^3 - 991340*x^2 - 222930*x - 23280], [346430*x^4 - 130490* x^2 + 6480, -25210500*x^6 - 75631500*x^5 - 93735040*x^4 - 60724720*x^3 - 216 87680*x^2 - 4061060*x - 311880, 25210500*x^6 + 75631500*x^5 + 93735040*x^4 + 62110440*x^3 + 23766260*x^2 + 5185800*x + 527820], [-201684*x^6 - 696290*x^ 4 + 214670*x^2 - 8628, 105279048*x^6 + 315232092*x^5 + 387699760*x^4 + 24862 0120*x^3 + 87804500*x^2 + 16247792*x + 1232136, -105279048*x^6 - 316442196*x ^5 - 390725020*x^4 - 255438960*x^3 - 95007500*x^2 - 19813716*x - 1915440]] 1 [[Mat([[1, 0; 0, 1], 1]), 0, 0, 0, 0], [0, Mat([[1, 0; 0, 1], 1]), 0, 0, 0], [0, 0, Mat([[1, 0; 0, 1], 1]), 0, 0], [0, 0, 0, Mat([[1, 0; 0, 1], 1]), 0], [0, 0, 0, 0, Mat([[1, 0; 0, 1], 1])]] [84, 10] 1 1 1 1 4 1 1 2 2 2 2 4 1 1 1 1 1 1 1 1 1 1 1 1 2 [ 2 -1 -1 2] [-1 2 1 -2] [ 1 -1 0 0] [ 0 0 0 -1] [-1] x^8 - 28*x^7 - 292*x^6 + 16496*x^5 - 115568*x^4 - 1800704*x^3 + 33061376*x^2 - 192352256*x + 396169216 -1/2 [1/2, 1/74] [ 0 0 0 -4312 440 -704] [ 0 0 0 792 -80 128] [ 0 0 0 0 0 0] [4312 -792 0 0 0 -88] [-440 80 0 0 0 8] [ 704 -128 0 88 -8 0] 1 1 1 [ 0 0 0 -2160 456 -96 -2304 678 -198 -576 492 -102] [ 0 0 0 360 -76 16 384 -113 33 96 -82 17] [ 0 0 0 0 0 0 0 0 0 0 0 0] [2160 -360 0 0 0 0 -5760 1680 -480 -2880 2400 -480] [-456 76 0 0 0 0 1176 -343 98 588 -490 98] [ 96 -16 0 0 0 0 -240 70 -20 -120 100 -20] [2304 -384 0 5760 -1176 240 0 -24 24 -2160 1752 -336] [-678 113 0 -1680 343 -70 24 0 -5 630 -511 98] [ 198 -33 0 480 -98 20 -24 5 0 -186 151 -29] [ 576 -96 0 2880 -588 120 2160 -630 186 0 -36 18] [-492 82 0 -2400 490 -100 -1752 511 -151 36 0 -9] [ 102 -17 0 480 -98 20 336 -98 29 -18 9 0] 1 1 1 [0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0] [0 0] [ 0 -51 765 2244 -969 7276 1122 0 -629 901] [ 51 0 -153 -629 545/2 -2057 -340 0 187 -272] [ -765 153 0 2686 -1173 8976 1734 0 -884 1360] [-2244 629 -2686 0 -51 969 1224 0 -357 833] [ 969 -545/2 1173 51 0 -255 -510 0 136 -340] [-7276 2057 -8976 -969 255 0 3570 0 -799 2295] [-1122 340 -1734 -1224 510 -3570 0 0 204 -85] [ 0 0 0 0 0 0 0 0 0 0] [ 629 -187 884 357 -136 799 -204 0 0 -170] [ -901 272 -1360 -833 340 -2295 85 0 170 0] [ 0 0 0 2128 -532 2641 1368 0 -1919 1463] [ 0 0 0 -456 229/2 -570 -285 0 399 -304] [ 0 0 0 1805 -456 2280 1083 0 -1520 1159] [-2128 456 -1805 0 19 -19 1463 0 -1672 1387] [ 532 -229/2 456 -19 0 -19 -380 0 437 -361] [-2641 570 -2280 19 19 0 1843 0 -2109 1748] [-1368 285 -1083 -1463 380 -1843 0 0 209 -76] [ 0 0 0 0 0 0 0 0 0 0] [ 1919 -399 1520 1672 -437 2109 -209 0 0 -133] [-1463 304 -1159 -1387 361 -1748 76 0 133 0] [ 0 0 91 -26 -130 52 52 0] [ 0 0 0 0 0 0 0 0] [-91 0 0 -65 -52 -13 130 -143] [ 26 0 65 0 -39 26 -39 65] [130 0 52 39 0 39 13 65] [-52 0 13 -26 -39 0 13 -26] [-52 0 -130 39 -13 -13 0 -52] [ 0 0 143 -65 -65 26 52 0] [[[[0, 33, 693, 54, 648, 486, 0]], [[0, 33, 693, 54, 648, 486, 0]]], 2 + 2*3 + 3^2 + 3^3 + 2*3^4 + 3^5 + O(3^6), Vecsmall([3, 6, 6, 1])] O(3^6) + (2 + 3 + 3^3 + O(3^4))*x + (2*3 + O(3^2))*x^2 + O(3^2)*x^3 + O(x^4) O(3^6) + O(3^4)*x + O(3^2)*x^2 + O(3^2)*x^3 + O(x^4) [[[[1243, 273, 2254, 1029, 0]], [[1234, 833, 294, 0, 0]], [[1243, 1295, 196, 1372, 0]], [[1243, 1295, 196, 1372, 0]], [[1234, 833, 294, 0, 0]], [[1243, 273, 2254, 1029, 0]]], 1 + 2*7 + 4*7^2 + 2*7^3 + O(7^4), Vecsmall([7, 4, 4, 1])] (6 + 3*7 + 5*7^2 + 3*7^3 + O(7^4)) + (6*7^2 + O(7^3))*x + (7 + O(7^2))*x^2 + O(7)*x^3 + O(x^4) 6 + 3*7 + 5*7^2 + 3*7^3 + O(7^4) [[[[6558, 5094, 2304, 5832, 2268, 0, 5103, 0], [3, 3024, 5508, 4374, 2916, 0 , 0, 0]], [[6558, 5094, 2304, 5832, 2268, 0, 5103, 0], [3, 3024, 5508, 4374, 2916, 0, 0, 0]]], [0, 1/36; 1/36, 0], Vecsmall([3, 8, 7, 1])] [(2*3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)) + (2 + 3^3 + O(3^4))*x + (1 + 2 *3 + O(3^2))*x^2 + (2*3^-1 + 1 + O(3))*x^3 + (2*3^-1 + O(3^0))*x^4 + O(x^5), (3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)) + (1 + 2*3 + 2*3^2 + 3^3 + O(3^4) )*x + (3^-2 + 3^-1 + O(3^2))*x^2 + (2*3^-2 + 2 + O(3))*x^3 + (3^-2 + 2*3^-1 + O(3^0))*x^4 + O(x^5)] [O(3^5) + O(3^4)*x + O(3^2)*x^2 + O(3)*x^3 + O(x^4), O(3^5) + O(3^4)*x + O(3 ^2)*x^2 + O(3)*x^3 + O(x^4)] [[[[6558, 2205, 5895, 972, 1296, 5832, 5103, 0], [3, 729, 459, 3645, 2673, 2 187, 4374, 0]], [[6558, 2205, 5895, 972, 1296, 5832, 5103, 0], [3, 729, 459, 3645, 2673, 2187, 4374, 0]]], [0, 1/18; 1/18, 0], Vecsmall([3, 8, 7, 1])] [[[[0, 1953, 729, 3888, 729, 3645, 0, 0], [0, 3312, 1863, 5994, 729, 1458, 0 , 0]], [[0, 1953, 729, 3888, 729, 3645, 0, 0], [0, 3312, 1863, 5994, 729, 14 58, 0, 0]]], [0, 1/18; 1/18, 1/18], Vecsmall([3, 8, 7, 1])] [[[[6546, 684, 5499, 4617, 2106, 5832, 5832, 0], [6, 5427, 2673, 2187, 1458, 0, 0, 0]], [[6546, 684, 5499, 4617, 2106, 5832, 5832, 0], [6, 5427, 2673, 2 187, 1458, 0, 0, 0]]], [0, 1/126; 1/126, 1/126], Vecsmall([3, 8, 7, 1])] (2 + 3 + 3^2 + O(3^3)) + (1 + O(3))*x + (1 + O(3))*x^2 + O(x^3) (2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 3^6 + O(3^7)) + (1 + 3 + 2*3^2 + 3^3 + O(3^5) )*x + (1 + 2*3 + O(3^3))*x^2 + (3 + O(3^2))*x^3 + O(3)*x^4 + O(x^5) O(3^7) + O(3^5)*x + O(3^3)*x^2 + O(3^2)*x^3 + O(3)*x^4 + O(x^5) (2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 3^6 + O(3^7)) + (1 + 3 + 2*3^2 + 3^3 + O(3^5) )*x + (1 + 2*3 + O(3^3))*x^2 + (3 + O(3^2))*x^3 + O(3)*x^4 + O(x^5) O(11^9) + O(11^8)*x + O(11^7)*x^2 + O(11^6)*x^3 + O(11^5)*x^4 + O(11^4)*x^5 + O(11^3)*x^6 + O(11^2)*x^7 + O(11)*x^8 + O(x^9) O(3^5) + O(3^3)*x + (1 + 2*3 + O(3^2))*x^2 + (1 + O(3))*x^3 + O(x^4) O(11^7) + (10 + 3*11 + 6*11^2 + 9*11^3 + 8*11^4 + 5*11^5 + O(11^6))*x + (6 + 3*11 + 2*11^2 + 6*11^3 + 6*11^4 + O(11^5))*x^2 + (2 + 2*11 + 11^2 + 10*11^3 + O(11^4))*x^3 + (5 + 8*11^2 + O(11^3))*x^4 + (4 + 10*11 + O(11^2))*x^5 + ( 1 + O(11))*x^6 + O(x^7) (2 + 2*3 + 2*3^2 + 3^4 + O(3^6)) + (1 + 2*3 + 3^2 + 3^3 + O(3^4))*x + (1 + 3 + O(3^2))*x^2 + (2 + O(3^2))*x^3 + O(x^4) [(2*3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)) + (2 + 3^3 + O(3^4))*x + (1 + 2 *3 + O(3^2))*x^2 + (2*3^-1 + 1 + O(3))*x^3 + (2*3^-1 + O(3^0))*x^4 + O(x^5), (3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)) + (1 + 2*3 + 2*3^2 + 3^3 + O(3^4) )*x + (3^-2 + 3^-1 + O(3^2))*x^2 + (2*3^-2 + 2 + O(3))*x^3 + (3^-2 + 2*3^-1 + O(3^0))*x^4 + O(x^5)] [O(5^19), 4 + 3*5 + 3*5^2 + 4*5^3 + 3*5^4 + 4*5^5 + 4*5^6 + 3*5^7 + 5^8 + 2* 5^10 + 3*5^13 + 3*5^14 + 3*5^16 + 5^18 + O(5^19), O(5^19), 2 + 2*5^2 + 3*5^3 + 3*5^4 + 5^5 + 3*5^6 + 3*5^7 + 2*5^8 + 5^9 + 4*5^10 + 4*5^11 + 4*5^12 + 3* 5^13 + 3*5^14 + 4*5^15 + 3*5^16 + 4*5^17 + 2*5^18 + O(5^19), O(5^19), 4 + 5 + 4*5^4 + 4*5^5 + 3*5^8 + 5^11 + 3*5^12 + 5^13 + 3*5^14 + 5^15 + 5^16 + 3*5^ 17 + 4*5^18 + O(5^19)] [1, -1, 1, -2, 0]: [1, 1] [1, -1, 1, -17, 30]: [2, 1] [1, -1, 1, -96608, -11533373]: [3, 1] [1, -1, 1, -1568, -4669]: [1, 1] [1, -1, 1, -95528, -11804669]: [6, 1] [1, -1, 1, 6112, -41533]: [2, 1] [1, 0, 1, 4, -6]: [1, 1] [1, 0, 1, -1, 0]: [1, 1/3] [1, 0, 1, -171, -874]: [3, 1] [1, 0, 1, -36, -70]: [2, 1] [1, 0, 1, -11, 12]: [2, 1/3] [1, 0, 1, -2731, -55146]: [6, 1] [[1, 1], [1, 1/3], [3, 1], [2, 1], [2, 1/3], [6, 1]] 5 [[[1/6, 0, -1/6, -1/3, -1/2]~, [0, 1/2, 0, 0, -1/2]~, [1/6, 0; -1/2, 1; -1/6 , 0; -1/3, 0; 0, -1]], [[1/18, 0, -1/18, -1/9, -1/6]~, [0, 1/2, 0, 0, -1/2]~ , [1/18, 0; -1/2, 1; -1/18, 0; -1/9, 0; 1/3, -1]], [[1/2, 0, -1/2, -1, -3/2] ~, [0, 1/2, 0, 0, -1/2]~, [1/2, 0; -1/2, 1; -1/2, 0; -1, 0; -1, -1]], [[1/3, 0, -1/3, -2/3, -1]~, [0, 1, 0, 0, -1]~, [1/3, 0; 0, 1; -1/3, 0; -2/3, 0; -1 , -1]], [[1/9, 0, -1/9, -2/9, -1/3]~, [0, 1, 0, 0, -1]~, [1/9, 0; 0, 1; -1/9 , 0; -2/9, 0; -1/3, -1]], [[1, 0, -1, -2, -3]~, [0, 1, 0, 0, -1]~, [1, 0; 0, 1; -1, 0; -2, 0; -3, -1]]] 1 1 Total time spent: 2016 pari-2.11.2/src/test/32/cxtrigo0000644000175000017500000000063313201017466014554 0ustar billbillatan: 0.0 + I*-1.0 is a pole ? atan: 0.0 + I*1.0 is a pole ? atanh: -1.0 + I*0.0 is a pole ? atanh: 1.0 + I*0.0 is a pole ? 0.E-1155 0.E-1155 0.E-1155 0.E-1155 0.E-1155 0.E-1155 1.1702607277107686407657936407619050318 -1.3130352854993313036361612469308478329*I 0.27390375020968549781950404333381912154 - 1.0057146343488479442511142161269 763393*I 1.5574077246549022305069748074583601731*I Total time spent: 258 pari-2.11.2/src/test/32/self0000644000175000017500000000003013201017466014015 0ustar billbill120 Total time spent: 0 pari-2.11.2/src/test/32/plotexport0000644000175000017500000000070713326135265015325 0ustar billbill" 0 2 rlineto 2 0 rlineto 0 -2 rlineto closepath fill} def\n/" " version='1.1' xmlns='http://www.w3.org/2000/svg'>=4-------------- ----------large p--------------- ----------huge p--------------- Total time spent: 430 pari-2.11.2/src/test/32/sumnum0000644000175000017500000000441313326135265014427 0ustar billbill *** Warning: new stack size = 40000000 (38.147 Mbytes). +oo +oo -38 1.6449340668482264364724151666460251892 0.39493406684822643647241516664602518922 1.6449340668482264364724151666460251892 -38 2.6123753486854883433485675679240716306 2.6123753486854883433485675679240716306 1.6123753486854883433485675679240716306 (n)->1/(n^2+1) -38 -38 -40 (n)->log(1+1/n)/n +oo -38 -36 (n)->lngamma(1+1/n)/n +oo +oo -37 (n)->sin(1/sqrt(n))/n^(3/2) +oo +oo -36 2.3979771206715998375659850036324914715 2.3979771206715998375659850036324914714 -37 -38 *** at top-level: sumnummonien(n=1,1/n^2,tab) *** ^---------- *** incompatible initial value 2 != 1. -38 +oo +oo +oo -36 +oo realprecision = 115 significant digits +oo +oo +oo +oo -115 -115 +oo +oo +oo +oo +oo -115 realprecision = 308 significant digits -307 -307 -307 -307 -307 -307 -307 [-307, -305] -307 +oo -408 realprecision = 38 significant digits 0.94536905472633293526609521540827019813 0.E-37 realprecision = 19 significant digits 1.644934066848226436 *** at top-level: sumnum(n=1,1/n^2,"bug") *** ^------------ *** incorrect type in sumnum (t_STR). *** at top-level: sumnumap(n=1,1/n^2,"bug") *** ^------------ *** incorrect type in sumnumap (t_STR). *** at top-level: intnumapinit(x,y) *** ^----------------- *** not a function in function call *** at top-level: sumnummonieninit([-1,1]) *** ^------------------------ *** sumnummonieninit: domain error in sumnummonieninit: a <= 0 *** at top-level: sumnummonieninit([1,-1]) *** ^------------------------ *** sumnummonieninit: domain error in sumnummonieninit: a+b <= 1 *** at top-level: sumnummonieninit(,[n->2^-n,oo]) *** ^------------------------------- *** sumnummonieninit: forbidden addition t_INT + t_INFINITY. *** at top-level: sumnumlagrangeinit([1/5,0]) *** ^--------------------------- *** sumnumlagrangeinit: sorry, sumnumlagrange for this alpha is not yet implemented. *** at top-level: sumnumlagrangeinit(x) *** ^--------------------- *** sumnumlagrangeinit: incorrect type in sumnumlagrangeinit (t_POL). Total time spent: 3939 pari-2.11.2/src/test/32/map0000644000175000017500000000372413447371554013673 0ustar billbillMap([1, 2; 3, 4; 5, 6]) [1, 3, 5] [5, 3, 1] [1 2] [3 4] [5 6] Map([1, 4; 3, 16; 5, 36]) Map([1, -2; 3, -4; 5, -6]) [1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1] [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1] -1 0 Map([;]) 0 Map(Mat([2, 3])) *** at top-level: mapget(M,7) *** ^----------- *** mapget: non-existent component in mapget: index not in map *** at top-level: mapdelete(M,7) *** ^-------------- *** mapdelete: non-existent component in mapdelete: index not in map *** at top-level: Vec(M,1) *** ^-------- *** Vec: incorrect type in gtovec (t_LIST). *** at top-level: Vec(M,-1) *** ^--------- *** Vec: incorrect type in gtovec (t_LIST). *** at top-level: Map([1,2;2,3;1,3;1,4]) *** ^---------------------- *** Map: domain error in Map: x is not one-to-one *** at top-level: mapdelete(1,1) *** ^-------------- *** mapdelete: incorrect type in mapdelete (t_INT). *** at top-level: mapdelete(L,1) *** ^-------------- *** mapdelete: incorrect type in mapdelete (t_LIST). *** at top-level: mapget(1,1) *** ^----------- *** mapget: incorrect type in mapget (t_INT). *** at top-level: mapget(L,1) *** ^----------- *** mapget: incorrect type in mapget (t_LIST). *** at top-level: mapisdefined(1,1) *** ^----------------- *** mapisdefined: incorrect type in mapisdefined (t_INT). *** at top-level: mapisdefined(L,1) *** ^----------------- *** mapisdefined: incorrect type in mapisdefined (t_LIST). *** too few arguments: mapput(1,1) *** ^- *** too few arguments: mapput(L,1) *** ^- *** at top-level: Map(1) *** ^------ *** Map: incorrect type in Map (t_INT). Total time spent: 25 pari-2.11.2/src/test/32/compat0000644000175000017500000047606313326135265014404 0ustar billbill *** too few arguments: abs() *** ^- *** at top-level: addell() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: addell(e,z1,z2) ===> elladd(e,z1,z2) elladd(E,z1,z2): sum of the points z1 and z2 on elliptic curve E. [] *** at top-level: adj() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: adj(x) ===> matadjoint(x) matadjoint(M,{flag=0}): adjoint matrix of M using Leverrier-Faddeev's algorithm. If flag is 1, compute the characteristic polynomial independently first. *** at top-level: akell() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: akell(e,n) ===> ellak(e,n) ellak(E,n): computes the n-th Fourier coefficient of the L-function of the elliptic curve E (assumes E is an integral model). *** at top-level: algdep2() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: algdep2(x,n,dec) ===> algdep(x,n,dec) algdep(z,k,{flag=0}): algebraic relations up to degree n of z, using lindep([1,z,...,z^(k-1)], flag). *** at top-level: algtobasis() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: algtobasis(nf,x) ===> nfalgtobasis(nf,x) nfalgtobasis(nf,x): transforms the algebraic number x into a column vector on the integral basis nf.zk. *** at top-level: anell() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: anell(e,n) ===> ellan(e,n) ellan(E,n): computes the first n Fourier coefficients of the L-function of the elliptic curve E defined over a number field (n<2^24 on a 32-bit machine). *** at top-level: apell() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: apell(e,n) ===> ellap(e,n) ellap(E,{p}): given an elliptic curve E defined over a finite field Fq, return the trace of Frobenius a_p = q+1-#E(Fq); for other fields of definition K, p must define a finite residue field, (p prime for K = Qp or Q; p a maximal ideal for K a number field), return the order of the (non-singular) reduction of E. *** at top-level: apell2() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: apell2(e,n) ===> ellap(e,n) ellap(E,{p}): given an elliptic curve E defined over a finite field Fq, return the trace of Frobenius a_p = q+1-#E(Fq); for other fields of definition K, p must define a finite residue field, (p prime for K = Qp or Q; p a maximal ideal for K a number field), return the order of the (non-singular) reduction of E. *** at top-level: apprpadic() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: apprpadic(x,a) ===> padicappr(x,a) padicappr(pol,a): p-adic roots of the polynomial pol congruent to a mod p. *** at top-level: assmat() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: assmat(x) ===> matcompanion(x) matcompanion(x): companion matrix to polynomial x. *** at top-level: basis() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: basis(x) ===> nfbasis(x) nfbasis(T): integral basis of the field Q[a], where a is a root of the polynomial T, using the round 4 algorithm. An argument [T,listP] is possible, where listP is a list of primes (to get an order which is maximal at certain primes only) or a prime bound. *** at top-level: basis2() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: basis2(x) ===> nfbasis(x,2) nfbasis(T): integral basis of the field Q[a], where a is a root of the polynomial T, using the round 4 algorithm. An argument [T,listP] is possible, where listP is a list of primes (to get an order which is maximal at certain primes only) or a prime bound. *** at top-level: basistoalg() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: basistoalg(nf,x) ===> nfbasistoalg(nf,x) nfbasistoalg(nf,x): transforms the column vector x on the integral basis into an algebraic number. *** at top-level: bilhell() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: bilhell(e,z1,z2) ===> ellbil(e,z1,z2) ellbil(E,z1,z2): deprecated alias for ellheight(E,P,Q). *** at top-level: bin() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: bin(x,y) ===> binomial(x,y) binomial(x,{k}): binomial coefficient x*(x-1)...*(x-k+1)/k! defined for k in Z and any x. If k is omitted and x an integer, return the vector [binomial(x,1),...,binomial(x,x)]. *** at top-level: boundcf() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: boundcf(x,lmax) ===> contfrac(x,,lmax) contfrac(x,{b},{nmax}): continued fraction expansion of x (x rational,real or rational function). b and nmax are both optional, where b is the vector of numerators of the continued fraction, and nmax is a bound for the number of terms in the continued fraction expansion. *** at top-level: boundfact() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: boundfact(x,lim) ===> factor(x,lim) factor(x,{D}): factorization of x over domain D. If x and D are both integers, return partial factorization, using primes < D. *** at top-level: buchcertify() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchcertify(bnf) ===> bnfcertify(bnf) bnfcertify(bnf,{flag = 0}): certify the correctness (i.e. remove the GRH) of the bnf data output by bnfinit. If flag is present, only certify that the class group is a quotient of the one computed in bnf (much simpler in general). *** at top-level: buchfu() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: buchgen() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: buchgenforcefu() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: buchgenfu() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: buchimag() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchimag(D,c1,c2,g) ===> quadclassunit(D,,[c1,c2,g]) quadclassunit(D,{flag=0},{tech=[]}): compute the structure of the class group and the regulator of the quadratic field of discriminant D. See manual for the optional technical parameters. *** at top-level: buchinit() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchinit(P) ===> bnfinit(P,2) bnfinit(P,{flag=0},{tech=[]}): compute the necessary data for future use in ideal and unit group computations, including fundamental units if they are not too large. flag and tech are both optional. flag can be any of 0: default, 1: insist on having fundamental units. See manual for details about tech. *** at top-level: buchinitforcefu() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchinitforcefu(P) ===> bnfinit(P,1) bnfinit(P,{flag=0},{tech=[]}): compute the necessary data for future use in ideal and unit group computations, including fundamental units if they are not too large. flag and tech are both optional. flag can be any of 0: default, 1: insist on having fundamental units. See manual for details about tech. *** at top-level: buchinitfu() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchinitfu(P) ===> bnfinit(P) bnfinit(P,{flag=0},{tech=[]}): compute the necessary data for future use in ideal and unit group computations, including fundamental units if they are not too large. flag and tech are both optional. flag can be any of 0: default, 1: insist on having fundamental units. See manual for details about tech. *** at top-level: buchnarrow() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchnarrow(bnf) ===> bnfnarrow(bnf) bnfnarrow(bnf): given a big number field as output by bnfinit, gives as a 3-component vector the structure of the narrow class group. *** at top-level: buchray() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchray(bnf,ideal) ===> bnrinit(bnf,ideal) bnrinit(bnf,f,{flag=0}): given a bnf as output by bnfinit and a modulus f, initializes data linked to the ray class group structure corresponding to this module. flag is optional, and can be 0: default, 1: compute also the generators. *** at top-level: buchrayinit() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchrayinit(bnf,ideal) ===> bnrinit(bnf,ideal) bnrinit(bnf,f,{flag=0}): given a bnf as output by bnfinit and a modulus f, initializes data linked to the ray class group structure corresponding to this module. flag is optional, and can be 0: default, 1: compute also the generators. *** at top-level: buchrayinitgen() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchrayinitgen(bnf,ideal) ===> bnrinit(bnf,ideal,1) bnrinit(bnf,f,{flag=0}): given a bnf as output by bnfinit and a modulus f, initializes data linked to the ray class group structure corresponding to this module. flag is optional, and can be 0: default, 1: compute also the generators. *** at top-level: buchreal() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: buchreal(D) ===> quadclassunit(D) quadclassunit(D,{flag=0},{tech=[]}): compute the structure of the class group and the regulator of the quadratic field of discriminant D. See manual for the optional technical parameters. *** at top-level: bytesize() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: bytesize(x) ===> sizebyte(x) sizebyte(x): number of bytes occupied by the complete tree of the object x. *** at top-level: cf() *** ^---- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: cf(x) ===> contfrac(x) contfrac(x,{b},{nmax}): continued fraction expansion of x (x rational,real or rational function). b and nmax are both optional, where b is the vector of numerators of the continued fraction, and nmax is a bound for the number of terms in the continued fraction expansion. *** at top-level: cf2() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: cf2(b,x) ===> contfrac(x,b) contfrac(x,{b},{nmax}): continued fraction expansion of x (x rational,real or rational function). b and nmax are both optional, where b is the vector of numerators of the continued fraction, and nmax is a bound for the number of terms in the continued fraction expansion. *** at top-level: changevar() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: char() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: char(x,y) ===> charpoly(x,y) charpoly(A,{v='x},{flag=5}): det(v*Id-A)=characteristic polynomial of the matrix or polmod A. flag is optional and ignored unless A is a matrix; it may be set to 0 (Le Verrier), 1 (Lagrange interpolation), 2 (Hessenberg form), 3 (Berkowitz), 4 (modular) if A is integral, or 5 (default, choose best method). Algorithms 0 (Le Verrier) and 1 (Lagrange) assume that n! is invertible, where n is the dimension of the matrix. *** at top-level: char1() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: char1(x,y) ===> charpoly(x,y,1) charpoly(A,{v='x},{flag=5}): det(v*Id-A)=characteristic polynomial of the matrix or polmod A. flag is optional and ignored unless A is a matrix; it may be set to 0 (Le Verrier), 1 (Lagrange interpolation), 2 (Hessenberg form), 3 (Berkowitz), 4 (modular) if A is integral, or 5 (default, choose best method). Algorithms 0 (Le Verrier) and 1 (Lagrange) assume that n! is invertible, where n is the dimension of the matrix. *** at top-level: char2() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: char2(x,y) ===> charpoly(x,y,2) charpoly(A,{v='x},{flag=5}): det(v*Id-A)=characteristic polynomial of the matrix or polmod A. flag is optional and ignored unless A is a matrix; it may be set to 0 (Le Verrier), 1 (Lagrange interpolation), 2 (Hessenberg form), 3 (Berkowitz), 4 (modular) if A is integral, or 5 (default, choose best method). Algorithms 0 (Le Verrier) and 1 (Lagrange) assume that n! is invertible, where n is the dimension of the matrix. *** at top-level: chell() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: chell(x,y) ===> ellchangecurve(x,y) ellchangecurve(E,v): change data on elliptic curve according to v=[u,r,s,t]. *** at top-level: chptell() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: chptell(x,y) ===> ellchangepoint(x,y) ellchangepoint(x,v): change data on point or vector of points x on an elliptic curve according to v=[u,r,s,t]. *** at top-level: classno() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: classno(x) ===> qfbclassno(x) qfbclassno(D,{flag=0}): class number of discriminant D using Shanks's method by default. If (optional) flag is set to 1, use Euler products. *** at top-level: classno2() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: classno2(x) ===> qfbclassno(x,1) qfbclassno(D,{flag=0}): class number of discriminant D using Shanks's method by default. If (optional) flag is set to 1, use Euler products. *** at top-level: coeff() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: coeff(x,s) ===> polcoeff(x,s) polcoeff(x,n,{v}): deprecated alias for polcoef. *** at top-level: compimag() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: compimag(x,y) ===> x*y x*y: product of x and y. *** at top-level: compo() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: compo(x,s) ===> component(x,s) component(x,n): the n'th component of the internal representation of x. For vectors or matrices, it is simpler to use x[]. For list objects such as nf, bnf, bnr or ell, it is much easier to use member functions starting with ".". *** at top-level: compositum() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: compositum(pol1,pol2) ===> polcompositum(pol1,pol2) polcompositum(P,Q,{flag=0}): vector of all possible compositums of the number fields defined by the polynomials P and Q; flag is optional, whose binary digits mean 1: output for each compositum, not only the compositum polynomial pol, but a vector [R,a,b,k] where a (resp. b) is a root of P (resp. Q) expressed as a polynomial modulo R, and a small integer k such that al2+k*al1 is the chosen root of R; 2: assume that the number fields defined by P and Q are linearly disjoint. *** at top-level: compositum2() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: compositum2(pol1,pol2) ===> polcompositum(pol1,pol2,1) polcompositum(P,Q,{flag=0}): vector of all possible compositums of the number fields defined by the polynomials P and Q; flag is optional, whose binary digits mean 1: output for each compositum, not only the compositum polynomial pol, but a vector [R,a,b,k] where a (resp. b) is a root of P (resp. Q) expressed as a polynomial modulo R, and a small integer k such that al2+k*al1 is the chosen root of R; 2: assume that the number fields defined by P and Q are linearly disjoint. *** at top-level: comprealraw() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: comprealraw(x,y) ===> qfbcompraw(x,y) qfbcompraw(x,y): Gaussian composition without reduction of the binary quadratic forms x and y. *** at top-level: conductor() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: conductor(a1) ===> bnrconductor(a1) bnrconductor(A,{B},{C},{flag=0}): conductor f of the subfield of the ray class field given by A,B,C. flag is optional and can be 0: default, 1: returns [f, Cl_f, H], H subgroup of the ray class group modulo f defining the extension, 2: returns [f, bnr(f), H]. *** at top-level: conductorofchar() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: conductorofchar(bnr,chi) ===> bnrconductorofchar(bnr,chi) bnrconductorofchar(bnr,chi): this function is obsolete, use bnrconductor. *** at top-level: convol() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: convol(x,y) ===> serconvol(x,y) serconvol(x,y): convolution (or Hadamard product) of two power series. *** at top-level: core2() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: core2(x) ===> core(x,1) core(n,{flag=0}): unique squarefree integer d dividing n such that n/d is a square. If (optional) flag is non-null, output the two-component row vector [d,f], where d is the unique squarefree integer dividing n such that n/d=f^2 is a square. *** at top-level: coredisc2() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: coredisc2(x) ===> coredisc(x,1) coredisc(n,{flag=0}): discriminant of the quadratic field Q(sqrt(n)). If (optional) flag is non-null, output a two-component row vector [d,f], where d is the discriminant of the quadratic field Q(sqrt(n)) and n=df^2. f may be a half integer. *** at top-level: cvtoi() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: cvtoi(x) ===> truncate(x,&e) truncate(x,{&e}): truncation of x; when x is a power series,take away the O(X^). If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits. *** at top-level: cyclo() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: cyclo(n) ===> polcyclo(n) polcyclo(n,{a = 'x}): n-th cyclotomic polynomial evaluated at a. *** at top-level: decodefactor() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: decodefactor(fa) ===> factorback(fa) factorback(f,{e}): given a factorization f, gives the factored object back. If e is present, f has to be a vector of the same length, and we return the product of the f[i]^e[i]. *** at top-level: decodemodule() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: decodemodule(nf,fa) ===> bnfdecodemodule(nf,fa) bnfdecodemodule(nf,m): given a coded module m as in bnrdisclist, gives the true module. *** at top-level: degree() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: degree(x) ===> poldegree(x) poldegree(x,{v}): degree of the polynomial or rational function x with respect to main variable if v is omitted, with respect to v otherwise. For scalar x, return 0 if x is non-zero and -oo otherwise. *** at top-level: denom() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: denom(x) ===> denominator(x) denominator(f,{D}): denominator of f. *** at top-level: deplin() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: deplin(x) ===> lindep(x,-1) lindep(v,{flag=0}): integral linear dependencies between components of v. flag is optional, and can be 0: default, guess a suitable accuracy, or positive: accuracy to use for the computation, in decimal digits. *** at top-level: det() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: det(x) ===> matdet(x) matdet(x,{flag=0}): determinant of the matrix x using an appropriate algorithm depending on the coefficients. If (optional) flag is set to 1, use classical Gaussian elimination (usually worse than the default). *** at top-level: det2() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: det2(x) ===> matdet(x,1) matdet(x,{flag=0}): determinant of the matrix x using an appropriate algorithm depending on the coefficients. If (optional) flag is set to 1, use classical Gaussian elimination (usually worse than the default). *** at top-level: detint() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: detint(x) ===> matdetint(x) matdetint(B): some multiple of the determinant of the lattice generated by the columns of B (0 if not of maximal rank). Useful with mathnfmod. *** at top-level: diagonal() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: diagonal(x) ===> matdiagonal(x) matdiagonal(x): creates the diagonal matrix whose diagonal entries are the entries of the vector x. *** at top-level: disc() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: disc(x) ===> poldisc(x) poldisc(pol,{v}): discriminant of the polynomial pol, with respect to main variable if v is omitted, with respect to v otherwise. *** at top-level: discf() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discf(x) ===> nfdisc(x) nfdisc(T): discriminant of the number field defined by the polynomial T. An argument [T,listP] is possible, where listP is a list of primes or a prime bound. *** at top-level: discf2() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discf2(x) ===> nfdisc(x,2) nfdisc(T): discriminant of the number field defined by the polynomial T. An argument [T,listP] is possible, where listP is a list of primes or a prime bound. *** at top-level: discrayabs() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayabs(bnr,subgroup) ===> bnrdisc(bnr,subgroup) bnrdisc(A,{B},{C},{flag=0}): absolute or relative [N,R1,discf] of the field defined by A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf, modulus] or [bnf,modulus,subgroup], where bnf is as output by bnfinit, bnr by bnrinit, and subgroup is the HNF matrix of a subgroup of the corresponding ray class group (if omitted, the trivial subgroup). flag is optional whose binary digits mean 1: give relative data; 2: return 0 if modulus is not the conductor. *** at top-level: discrayabscond() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayabscond(bnr) ===> bnrdisc(bnr,,,2) bnrdisc(A,{B},{C},{flag=0}): absolute or relative [N,R1,discf] of the field defined by A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf, modulus] or [bnf,modulus,subgroup], where bnf is as output by bnfinit, bnr by bnrinit, and subgroup is the HNF matrix of a subgroup of the corresponding ray class group (if omitted, the trivial subgroup). flag is optional whose binary digits mean 1: give relative data; 2: return 0 if modulus is not the conductor. *** at top-level: discrayabslist() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayabslist(bnf,list) ===> bnrdisclist(bnf,list) bnrdisclist(bnf,bound,{arch}): list of discriminants of ray class fields of all conductors up to norm bound. The ramified Archimedean places are given by arch; all possible values are taken if arch is omitted. Supports the alternative syntax bnrdisclist(bnf,list), where list is as output by ideallist or ideallistarch (with units). *** at top-level: discrayabslistarch() *** ^-------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayabslistarch(bnf,arch,bound) ===> bnrdisclist(bnf,bound,arch) bnrdisclist(bnf,bound,{arch}): list of discriminants of ray class fields of all conductors up to norm bound. The ramified Archimedean places are given by arch; all possible values are taken if arch is omitted. Supports the alternative syntax bnrdisclist(bnf,list), where list is as output by ideallist or ideallistarch (with units). *** at top-level: discrayabslistarchall() *** ^----------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayabslistarchall(bnf,bound) ===> bnrdisclist(bnf,bound,,1) bnrdisclist(bnf,bound,{arch}): list of discriminants of ray class fields of all conductors up to norm bound. The ramified Archimedean places are given by arch; all possible values are taken if arch is omitted. Supports the alternative syntax bnrdisclist(bnf,list), where list is as output by ideallist or ideallistarch (with units). *** at top-level: discrayabslistlong() *** ^-------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayabslistlong(bnf,bound) ===> bnrdisclist(bnf,bound) bnrdisclist(bnf,bound,{arch}): list of discriminants of ray class fields of all conductors up to norm bound. The ramified Archimedean places are given by arch; all possible values are taken if arch is omitted. Supports the alternative syntax bnrdisclist(bnf,list), where list is as output by ideallist or ideallistarch (with units). *** at top-level: discrayrel() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayrel(bnr,subgroup) ===> bnrdisc(bnr,subgroup,,1) bnrdisc(A,{B},{C},{flag=0}): absolute or relative [N,R1,discf] of the field defined by A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf, modulus] or [bnf,modulus,subgroup], where bnf is as output by bnfinit, bnr by bnrinit, and subgroup is the HNF matrix of a subgroup of the corresponding ray class group (if omitted, the trivial subgroup). flag is optional whose binary digits mean 1: give relative data; 2: return 0 if modulus is not the conductor. *** at top-level: discrayrelcond() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: discrayrelcond(bnr,subgroup) ===> bnrdisc(bnr,subgroup,,3) bnrdisc(A,{B},{C},{flag=0}): absolute or relative [N,R1,discf] of the field defined by A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf, modulus] or [bnf,modulus,subgroup], where bnf is as output by bnfinit, bnr by bnrinit, and subgroup is the HNF matrix of a subgroup of the corresponding ray class group (if omitted, the trivial subgroup). flag is optional whose binary digits mean 1: give relative data; 2: return 0 if modulus is not the conductor. *** at top-level: divres() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: divres(x,y) ===> divrem(x,y) divrem(x,y,{v}): euclidean division of x by y giving as a 2-dimensional column vector the quotient and the remainder, with respect to v (to main variable if v is omitted). *** at top-level: divsum() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: divsum(n,X,expr) ===> sumdiv(n,X,expr) sumdiv(n,X,expr): sum of expression expr, X running over the divisors of n. *** at top-level: eigen() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: eigen(x) ===> mateigen(x) mateigen(x,{flag=0}): complex eigenvectors of the matrix x given as columns of a matrix H. If flag=1, return [L,H], where L contains the eigenvalues and H the corresponding eigenvectors. *** at top-level: euler() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: euler ===> Euler Euler=Euler(): Euler's constant with current precision. *** at top-level: extract() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: extract(x,y) ===> vecextract(x,y) vecextract(x,y,{z}): extraction of the components of the matrix or vector x according to y and z. If z is omitted, y represents columns, otherwise y corresponds to rows and z to columns. y and z can be vectors (of indices), strings (indicating ranges as in "1..10") or masks (integers whose binary representation indicates the indices to extract, from left to right 1, 2, 4, 8, etc.). *** at top-level: fact() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: fact(x) ===> factorial(x) factorial(x): factorial of x, the result being given as a real number. *** at top-level: factcantor() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factcantor(x,p) ===> factorcantor(x,p) factorcantor(x,p): this function is obsolete, use factormod. *** at top-level: factfq() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factfq(x,p,a) ===> factorff(x,p,a) factorff(x,{p},{a}): obsolete, use factormod. *** at top-level: factmod() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factmod(x,p) ===> factormod(x,p) factormod(f,{D},{flag=0}): factors the polynomial f over the finite field defined by the domain D; flag is optional, and can be 0: default or 1: only the degrees of the irreducible factors are given. *** at top-level: factoredbasis() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factoredbasis(x,p) ===> nfbasis(x,,p) nfbasis(T): integral basis of the field Q[a], where a is a root of the polynomial T, using the round 4 algorithm. An argument [T,listP] is possible, where listP is a list of primes (to get an order which is maximal at certain primes only) or a prime bound. *** at top-level: factoreddiscf() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factoreddiscf(x,p) ===> nfdisc(x,,p) nfdisc(T): discriminant of the number field defined by the polynomial T. An argument [T,listP] is possible, where listP is a list of primes or a prime bound. *** at top-level: factoredpolred() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factoredpolred(x,p) ===> polred(x,,p) polred(T,{flag=0}): deprecated, use polredbest. Reduction of the polynomial T (gives minimal polynomials only). The following binary digits of (optional) flag are significant 1: partial reduction, 2: gives also elements. *** at top-level: factoredpolred2() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factoredpolred2(x,p) ===> polred(x,2,p) polred(T,{flag=0}): deprecated, use polredbest. Reduction of the polynomial T (gives minimal polynomials only). The following binary digits of (optional) flag are significant 1: partial reduction, 2: gives also elements. *** at top-level: factorpadic2() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factorpadic2(x,p,r) ===> factorpadic(x,p,r,1) factorpadic(pol,p,r): p-adic factorization of the polynomial pol to precision r. *** at top-level: factpol() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factpol(x,l,hint) ===> factor(x) factor(x,{D}): factorization of x over domain D. If x and D are both integers, return partial factorization, using primes < D. *** at top-level: factpol2() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: factpol2(x,l,hint) ===> factor(x) factor(x,{D}): factorization of x over domain D. If x and D are both integers, return partial factorization, using primes < D. *** at top-level: fibo() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: fibo(x) ===> fibonacci(x) fibonacci(x): fibonacci number of index x (x C-integer). *** at top-level: fpn() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: fpn(p,n) ===> ffinit(p,n) ffinit(p,n,{v='x}): monic irreducible polynomial of degree n over F_p[v]. *** at top-level: galois() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: galois(x) ===> polgalois(x) polgalois(T): Galois group of the polynomial T (see manual for group coding). Return [n, s, k, name] where n is the group order, s the signature, k the index and name is the GAP4 name of the transitive group. *** at top-level: galoisapply() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: galoisapply(nf,aut,x) ===> nfgaloisapply(nf,aut,x) nfgaloisapply(nf,aut,x): apply the Galois automorphism aut to the object x (element or ideal) in the number field nf. *** at top-level: galoisconj() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: galoisconj(nf) ===> nfgaloisconj(nf) nfgaloisconj(nf,{flag=0},{d}): list of conjugates of a root of the polynomial x=nf.pol in the same number field. flag is optional (set to 0 by default), meaning 0: use combination of flag 4 and 1, always complete; 1: use nfroots; 4: use Allombert's algorithm, complete if the field is Galois of degree <= 35 (see manual for details). nf can be simply a polynomial. *** at top-level: galoisconj1() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: galoisconj1(nf) ===> nfgaloisconj(nf,2) nfgaloisconj(nf,{flag=0},{d}): list of conjugates of a root of the polynomial x=nf.pol in the same number field. flag is optional (set to 0 by default), meaning 0: use combination of flag 4 and 1, always complete; 1: use nfroots; 4: use Allombert's algorithm, complete if the field is Galois of degree <= 35 (see manual for details). nf can be simply a polynomial. *** at top-level: galoisconjforce() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: galoisconjforce ===> nfgaloisconj(nf,1) nfgaloisconj(nf,{flag=0},{d}): list of conjugates of a root of the polynomial x=nf.pol in the same number field. flag is optional (set to 0 by default), meaning 0: use combination of flag 4 and 1, always complete; 1: use nfroots; 4: use Allombert's algorithm, complete if the field is Galois of degree <= 35 (see manual for details). nf can be simply a polynomial. *** at top-level: gamh() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: gamh(x) ===> gammah(x) gammah(x): gamma of x+1/2 (x integer). *** at top-level: gauss() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: gauss(a,b) ===> matsolve(a,b) matsolve(M,B): solution of MX=B (M matrix, B column vector or matrix). *** at top-level: gaussmodulo() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: gaussmodulo(M,D,Y) ===> matsolvemod(M,D,Y) matsolvemod(M,D,B,{flag=0}): one solution of system of congruences MX=B mod D (M matrix, B and D column vectors). If (optional) flag is non-null return all solutions. *** at top-level: gaussmodulo2() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: gaussmodulo2(M,D,Y) ===> matsolvemod(M,D,Y,1) matsolvemod(M,D,B,{flag=0}): one solution of system of congruences MX=B mod D (M matrix, B and D column vectors). If (optional) flag is non-null return all solutions. *** at top-level: globalred() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: globalred(x,y) ===> ellglobalred(x,y) ellglobalred(E): E being an elliptic curve over a number field, returns [N, v, c, faN, L], where N is the conductor of E, c is the product of the local Tamagawa numbers c_p, faN is the factorization of N and L[i] is elllocalred(E, faN[i,1]); v is an obsolete field. *** at top-level: goto() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: hclassno() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hclassno(x) ===> qfbhclassno(x) qfbhclassno(x): Hurwitz-Kronecker class number of x>0. *** at top-level: hell() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hell(e,x) ===> ellheight(e,x) ellheight(E,P,{Q}): canonical height of point P on elliptic curve E, resp. the value of the attached bilinear form at (P,Q). *** at top-level: hell2() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hell2(e,x) ===> ellheight(e,x,1) ellheight(E,P,{Q}): canonical height of point P on elliptic curve E, resp. the value of the attached bilinear form at (P,Q). *** at top-level: hermite() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hermite(x) ===> mathnf(x) mathnf(M,{flag=0}): (upper triangular) Hermite normal form of M, basis for the lattice formed by the columns of M. flag is optional whose value range from 0 to 3 have a binary meaning. Bit 1: complete output, returns a 2-component vector [H,U] such that H is the HNF of M, and U is an invertible matrix such that MU=H. Bit 2: allow polynomial entries, otherwise assume that M is integral. These use a naive algorithm; larger values correspond to more involved algorithms and are restricted to integer matrices; flag = 4: returns [H,U] using LLL reduction along the way; flag = 5: return [H,U,P] where P is a permutation of row indices such that P applied to M U is H. *** at top-level: hermite2() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hermite2(x) ===> mathnf(x,1) mathnf(M,{flag=0}): (upper triangular) Hermite normal form of M, basis for the lattice formed by the columns of M. flag is optional whose value range from 0 to 3 have a binary meaning. Bit 1: complete output, returns a 2-component vector [H,U] such that H is the HNF of M, and U is an invertible matrix such that MU=H. Bit 2: allow polynomial entries, otherwise assume that M is integral. These use a naive algorithm; larger values correspond to more involved algorithms and are restricted to integer matrices; flag = 4: returns [H,U] using LLL reduction along the way; flag = 5: return [H,U,P] where P is a permutation of row indices such that P applied to M U is H. *** at top-level: hermitehavas() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: hermitemod() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hermitemod(x,d) ===> mathnfmod(x,d) mathnfmod(x,d): (upper triangular) Hermite normal form of x, basis for the lattice formed by the columns of x, where d is a multiple of the non-zero determinant of this lattice. *** at top-level: hermitemodid() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hermitemodid(x,d) ===> mathnfmodid(x,d) mathnfmodid(x,d): (upper triangular) Hermite normal form of x concatenated with matdiagonal(d). *** at top-level: hermiteperm() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hermiteperm(x) ===> mathnf(x,3) mathnf(M,{flag=0}): (upper triangular) Hermite normal form of M, basis for the lattice formed by the columns of M. flag is optional whose value range from 0 to 3 have a binary meaning. Bit 1: complete output, returns a 2-component vector [H,U] such that H is the HNF of M, and U is an invertible matrix such that MU=H. Bit 2: allow polynomial entries, otherwise assume that M is integral. These use a naive algorithm; larger values correspond to more involved algorithms and are restricted to integer matrices; flag = 4: returns [H,U] using LLL reduction along the way; flag = 5: return [H,U,P] where P is a permutation of row indices such that P applied to M U is H. *** at top-level: hess() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hess(x) ===> mathess(x) mathess(x): Hessenberg form of x. *** at top-level: hilb() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hilb(x,y) ===> hilbert(x,y) hilbert(x,y,{p}): Hilbert symbol at p of x,y. *** at top-level: hilbp() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hilbp(x,y,p) ===> hilbert(x,y,p) hilbert(x,y,{p}): Hilbert symbol at p of x,y. *** at top-level: hvector() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: hvector(n,X,expr) ===> vector(n,X,expr) vector(n,{X},{expr=0}): row vector with n components of expression expr (X ranges from 1 to n). By default, fill with 0s. *** at top-level: i() *** ^--- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: i ===> I I=I(): square root of -1. *** at top-level: idealaddmultone() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealaddmultone(nf,list) ===> idealaddtoone(nf,list) idealaddtoone(nf,x,{y}): if y is omitted, when the sum of the ideals in the number field K defined by nf and given in the vector x is equal to Z_K, gives a vector of elements of the corresponding ideals who sum to 1. Otherwise, x and y are ideals, and if they sum up to 1, find one element in each of them such that the sum is 1. *** at top-level: idealaddone() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealaddone(nf,x,y) ===> idealaddtoone(nf,x,y) idealaddtoone(nf,x,{y}): if y is omitted, when the sum of the ideals in the number field K defined by nf and given in the vector x is equal to Z_K, gives a vector of elements of the corresponding ideals who sum to 1. Otherwise, x and y are ideals, and if they sum up to 1, find one element in each of them such that the sum is 1. *** at top-level: idealapprfact() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealapprfact(nf,x) ===> idealappr(nf,x,1) idealappr(nf,x,{flag}): x being a fractional ideal, gives an element b such that v_p(b)=v_p(x) for all prime ideals p dividing x, and v_p(b)>=0 for all other p; x may also be a prime ideal factorization with possibly zero exponents. flag is deprecated (ignored), kept for backward compatibility. *** at top-level: idealdivexact() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealdivexact(nf,x,y) ===> idealdiv(nf,x,y,1) idealdiv(nf,x,y,{flag=0}): quotient x/y of two ideals x and y in HNF in the number field nf. If (optional) flag is non-null, the quotient is supposed to be an integral ideal (slightly faster). *** at top-level: idealhermite() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealhermite(nf,x) ===> idealhnf(nf,x) idealhnf(nf,u,{v}): hermite normal form of the ideal u in the number field nf if v is omitted. If called as idealhnf(nf,u,v), the ideal is given as uZ_K + vZ_K in the number field K defined by nf. *** at top-level: idealhermite2() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealhermite2(nf,x) ===> idealhnf(nf,x) idealhnf(nf,u,{v}): hermite normal form of the ideal u in the number field nf if v is omitted. If called as idealhnf(nf,u,v), the ideal is given as uZ_K + vZ_K in the number field K defined by nf. *** at top-level: idealinv2() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealinv2(nf,x) ===> idealinv(nf,x,1) idealinv(nf,x): inverse of the ideal x in the number field nf. *** at top-level: ideallistarchgen() *** ^------------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallistarchgen(nf,list,arch) ===> ideallistarch(nf,list,arch) ideallistarch(nf,list,arch): list is a vector of vectors of bid's as output by ideallist. Return a vector of vectors with the same number of components as the original list. The leaves give information about moduli whose finite part is as in original list, in the same order, and Archimedean part is now arch. The information contained is of the same kind as was present in the input. *** at top-level: ideallistunit() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallistunit(nf,list) ===> ideallist(nf,list,2) ideallist(nf,bound,{flag=4}): vector of vectors L of all idealstar of all ideals of norm<=bound. If (optional) flag is present, its binary digits are toggles meaning 1: give generators; 2: add units; 4: give only the ideals and not the bid. *** at top-level: ideallistunitarch() *** ^------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallistunitarch ===> ideallistarch(nf,list,arch) ideallistarch(nf,list,arch): list is a vector of vectors of bid's as output by ideallist. Return a vector of vectors with the same number of components as the original list. The leaves give information about moduli whose finite part is as in original list, in the same order, and Archimedean part is now arch. The information contained is of the same kind as was present in the input. *** at top-level: ideallistunitarchgen() *** ^---------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallistunitarchgen ===> ideallistarch(nf,list,arch) ideallistarch(nf,list,arch): list is a vector of vectors of bid's as output by ideallist. Return a vector of vectors with the same number of components as the original list. The leaves give information about moduli whose finite part is as in original list, in the same order, and Archimedean part is now arch. The information contained is of the same kind as was present in the input. *** at top-level: ideallistunitgen() *** ^------------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallistunitgen ===> ideallist(nf,list,3) ideallist(nf,bound,{flag=4}): vector of vectors L of all idealstar of all ideals of norm<=bound. If (optional) flag is present, its binary digits are toggles meaning 1: give generators; 2: add units; 4: give only the ideals and not the bid. *** at top-level: ideallistzstar() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallistzstar(nf,bound) ===> ideallist(nf,bound) ideallist(nf,bound,{flag=4}): vector of vectors L of all idealstar of all ideals of norm<=bound. If (optional) flag is present, its binary digits are toggles meaning 1: give generators; 2: add units; 4: give only the ideals and not the bid. *** at top-level: ideallistzstargen() *** ^------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallistzstargen(nf,bound) ===> ideallist(nf,bound,1) ideallist(nf,bound,{flag=4}): vector of vectors L of all idealstar of all ideals of norm<=bound. If (optional) flag is present, its binary digits are toggles meaning 1: give generators; 2: add units; 4: give only the ideals and not the bid. *** at top-level: ideallllred() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ideallllred(nf,x,vdir) ===> idealred(nf,x,vdir) idealred(nf,I,{v=0}): LLL reduction of the ideal I in the number field nf along direction v, in HNF. *** at top-level: idealmulred() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealmulred(nf,x,y) ===> idealmul(nf,x,y,1) idealmul(nf,x,y,{flag=0}): product of the two ideals x and y in the number field nf. If (optional) flag is non-nul, reduce the result. *** at top-level: idealpowred() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealpowred(nf,x,y) ===> idealpow(nf,x,y,1) idealpow(nf,x,k,{flag=0}): k-th power of the ideal x in HNF in the number field nf. If (optional) flag is non-null, reduce the result. *** at top-level: idealtwoelt2() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idealtwoelt2(nf,x,a) ===> idealtwoelt(nf,x,a) idealtwoelt(nf,x,{a}): two-element representation of an ideal x in the number field nf. If (optional) a is non-zero, first element will be equal to a. *** at top-level: idmat() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: idmat(n) ===> matid(n) matid(n): identity matrix of order n. *** at top-level: image() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: image(x) ===> matimage(x) matimage(x,{flag=0}): basis of the image of the matrix x. flag is optional and can be set to 0 or 1, corresponding to two different algorithms. *** at top-level: image2() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: image2(x) ===> matimage(x,1) matimage(x,{flag=0}): basis of the image of the matrix x. flag is optional and can be set to 0 or 1, corresponding to two different algorithms. *** at top-level: imagecompl() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: imagecompl(x) ===> matimagecompl(x) matimagecompl(x): vector of column indices not corresponding to the indices given by the function matimage. *** at top-level: incgam1() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: incgam2() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: incgam3() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: incgam4() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: incgam4(s,x,y) ===> incgam(s,x,y) incgam(s,x,{g}): incomplete gamma function. g is optional and is the precomputed value of gamma(s). *** at top-level: indexrank() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: indexrank(x) ===> matindexrank(x) matindexrank(M): gives two extraction vectors (rows and columns) for the matrix M such that the extracted matrix is square of maximal rank. *** at top-level: indsort() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: indsort(x) ===> vecsort(x,,1) vecsort(x,{cmpf},{flag=0}): sorts the vector of vectors (or matrix) x in ascending order, according to the comparison function cmpf, if not omitted. (If cmpf is an integer k, sort according to the value of the k-th component of each entry.) Binary digits of flag (if present) mean: 1: indirect sorting, return the permutation instead of the permuted vector, 4: use descending instead of ascending order, 8: remove duplicate entries. *** at top-level: initalg() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: initalg(pol) ===> nfinit(pol) nfinit(pol,{flag=0}): pol being a nonconstant irreducible polynomial, gives the vector: [pol,[r1,r2],discf,index,[M,MC,T2,T,different] (see manual),r1+r2 first roots, integral basis, matrix of power basis in terms of integral basis, multiplication table of basis]. flag is optional and can be set to 0: default; 1: do not compute different; 2: first use polred to find a simpler polynomial; 3: outputs a two-element vector [nf,Mod(a,P)], where nf is as in 2 and Mod(a,P) is a polmod equal to Mod(x,pol) and P=nf.pol. *** at top-level: initalgred() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: initalgred(x) ===> nfinit(x,2) nfinit(pol,{flag=0}): pol being a nonconstant irreducible polynomial, gives the vector: [pol,[r1,r2],discf,index,[M,MC,T2,T,different] (see manual),r1+r2 first roots, integral basis, matrix of power basis in terms of integral basis, multiplication table of basis]. flag is optional and can be set to 0: default; 1: do not compute different; 2: first use polred to find a simpler polynomial; 3: outputs a two-element vector [nf,Mod(a,P)], where nf is as in 2 and Mod(a,P) is a polmod equal to Mod(x,pol) and P=nf.pol. *** at top-level: initalgred2() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: initalgred2(x) ===> nfinit(x,3) nfinit(pol,{flag=0}): pol being a nonconstant irreducible polynomial, gives the vector: [pol,[r1,r2],discf,index,[M,MC,T2,T,different] (see manual),r1+r2 first roots, integral basis, matrix of power basis in terms of integral basis, multiplication table of basis]. flag is optional and can be set to 0: default; 1: do not compute different; 2: first use polred to find a simpler polynomial; 3: outputs a two-element vector [nf,Mod(a,P)], where nf is as in 2 and Mod(a,P) is a polmod equal to Mod(x,pol) and P=nf.pol. *** at top-level: initell() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: initell(x) ===> ellinit(x) ellinit(x,{D=1}): let x be a vector [a1,a2,a3,a4,a6], or [a4,a6] if a1=a2=a3=0, defining the curve Y^2 + a1.XY + a3.Y = X^3 + a2.X^2 + a4.X + a6; x can also be a string, in which case the curve with matching name is retrieved from the elldata database, if available. This function initializes an elliptic curve over the domain D (inferred from coefficients if omitted). *** at top-level: initzeta() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: integ() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: integ(x,y) ===> intformal(x,y) intformal(x,{v}): formal integration of x with respect to v, or to the main variable of x if v is omitted. *** at top-level: intersect() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: intersect(x,y) ===> matintersect(x,y) matintersect(x,y): intersection of the vector spaces whose bases are the columns of x and y. *** at top-level: intgen() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: intgen(x=a,b,s) ===> intnum(x=a,b,s,1) intnum(X=a,b,expr,{tab}): numerical integration of expr from a to b with respect to X. Plus/minus infinity is coded as +oo/-oo. Finally tab is either omitted (let the program choose the integration step), a non-negative integer m (divide integration step by 2^m), or data precomputed with intnuminit. *** at top-level: intinf() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: intinf(x=a,b,s) ===> intnum(x=a,b,s,2) intnum(X=a,b,expr,{tab}): numerical integration of expr from a to b with respect to X. Plus/minus infinity is coded as +oo/-oo. Finally tab is either omitted (let the program choose the integration step), a non-negative integer m (divide integration step by 2^m), or data precomputed with intnuminit. *** at top-level: intopen() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: intopen(x=a,b,s) ===> intnum(x=a,b,s,3) intnum(X=a,b,expr,{tab}): numerical integration of expr from a to b with respect to X. Plus/minus infinity is coded as +oo/-oo. Finally tab is either omitted (let the program choose the integration step), a non-negative integer m (divide integration step by 2^m), or data precomputed with intnuminit. *** at top-level: inverseimage() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: inverseimage(x,y) ===> matinverseimage(x,y) matinverseimage(x,y): an element of the inverse image of the vector y by the matrix x if one exists, the empty vector otherwise. *** at top-level: isdiagonal() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isdiagonal(x) ===> matisdiagonal(x) matisdiagonal(x): true(1) if x is a diagonal matrix, false(0) otherwise. *** at top-level: isfund() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isfund(x) ===> isfundamental(x) isfundamental(D): true(1) if D is a fundamental discriminant (including 1), false(0) if not. *** at top-level: isideal() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isideal(nf,x) ===> nfisideal(nf,x) nfisideal(nf,x): true(1) if x is an ideal in the number field nf, false(0) if not. *** at top-level: isincl() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isincl(x,y) ===> nfisincl(x,y) nfisincl(f,g): let f and g define number fields, either irreducible rational polynomials or number fields as output by nfinit; tests whether the number field f is isomorphic to a subfield of g. Return 0 if not, and otherwise all the isomorphisms. *** at top-level: isinclfast() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isinclfast(nf1,nf2) ===> nfisincl(nf1,nf2,1) nfisincl(f,g): let f and g define number fields, either irreducible rational polynomials or number fields as output by nfinit; tests whether the number field f is isomorphic to a subfield of g. Return 0 if not, and otherwise all the isomorphisms. *** at top-level: isirreducible() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isirreducible(x) ===> polisirreducible(x) polisirreducible(pol): true(1) if pol is an irreducible non-constant polynomial, false(0) if pol is reducible or constant. *** at top-level: isisom() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isisom(x,y) ===> nfisisom(x,y) nfisisom(f,g): as nfisincl but tests whether f is isomorphic to g. *** at top-level: isisomfast() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isisomfast(x,y) ===> nfisisom(x,y) nfisisom(f,g): as nfisincl but tests whether f is isomorphic to g. *** at top-level: isoncurve() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isoncurve(e,x) ===> ellisoncurve(e,x) ellisoncurve(E,z): true(1) if z is on elliptic curve E, false(0) if not. *** at top-level: isprincipal() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isprincipal(bnf,x) ===> bnfisprincipal(bnf,x,0) bnfisprincipal(bnf,x,{flag=1}): bnf being output by bnfinit (with flag<=2), gives [v,alpha], where v is the vector of exponents on the class group generators and alpha is the generator of the resulting principal ideal. In particular x is principal if and only if v is the zero vector. flag is optional, whose binary digits mean 1: output [v,alpha] (only v if unset); 2: increase precision until alpha can be computed (do not insist if unset). *** at top-level: isprincipalforce() *** ^------------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isprincipalforce(bnf,x) ===> bnfisprincipal(bnf,x,2) bnfisprincipal(bnf,x,{flag=1}): bnf being output by bnfinit (with flag<=2), gives [v,alpha], where v is the vector of exponents on the class group generators and alpha is the generator of the resulting principal ideal. In particular x is principal if and only if v is the zero vector. flag is optional, whose binary digits mean 1: output [v,alpha] (only v if unset); 2: increase precision until alpha can be computed (do not insist if unset). *** at top-level: isprincipalgen() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isprincipalgen(bnf,x) ===> bnfisprincipal(bnf,x) bnfisprincipal(bnf,x,{flag=1}): bnf being output by bnfinit (with flag<=2), gives [v,alpha], where v is the vector of exponents on the class group generators and alpha is the generator of the resulting principal ideal. In particular x is principal if and only if v is the zero vector. flag is optional, whose binary digits mean 1: output [v,alpha] (only v if unset); 2: increase precision until alpha can be computed (do not insist if unset). *** at top-level: isprincipalgenforce() *** ^--------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isprincipalgenforce(bnf,x) ===> bnfisprincipal(bnf,x,3) bnfisprincipal(bnf,x,{flag=1}): bnf being output by bnfinit (with flag<=2), gives [v,alpha], where v is the vector of exponents on the class group generators and alpha is the generator of the resulting principal ideal. In particular x is principal if and only if v is the zero vector. flag is optional, whose binary digits mean 1: output [v,alpha] (only v if unset); 2: increase precision until alpha can be computed (do not insist if unset). *** at top-level: isprincipalray() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isprincipalray(bnf,x) ===> bnrisprincipal(bnf,x) bnrisprincipal(bnr,x,{flag=1}): bnr being output by bnrinit and x being an ideal coprime to bnr.mod, returns [v,alpha], where v is the vector of exponents on the ray class group generators and alpha is the generator of the resulting principal ideal. If (optional) flag is set to 0, output only v. *** at top-level: isprincipalraygen() *** ^------------------- *** not a function in function call *** at top-level: ispsp() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ispsp(x) ===> ispseudoprime(x) ispseudoprime(x,{flag}): true(1) if x is a strong pseudoprime, false(0) if not. If flag is 0 or omitted, use BPSW test, otherwise use strong Rabin-Miller test for flag randomly chosen bases. *** at top-level: isqrt() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isqrt(x) ===> sqrtint(x) sqrtint(x): integer square root of x, where x is a non-negative integer. *** at top-level: isset() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isset(x) ===> setisset(x) setisset(x): true(1) if x is a set (row vector with strictly increasing entries), false(0) if not. *** at top-level: issqfree() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: issqfree(x) ===> issquarefree(x) issquarefree(x): true(1) if x is squarefree, false(0) if not. *** at top-level: isunit() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: isunit(bnf,x) ===> bnfisunit(bnf,x) bnfisunit(bnf,x): bnf being output by bnfinit, gives the column vector of exponents of x on the fundamental units and the roots of unity if x is a unit, the empty vector otherwise. *** at top-level: jacobi() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: jacobi(x) ===> qfjacobi(x) qfjacobi(A): eigenvalues and orthogonal matrix of eigenvectors of the real symmetric matrix A. *** at top-level: jbesselh() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: jbesselh(n,x) ===> besseljh(n,x) besseljh(n,x): J-bessel function of index n+1/2 and argument x, where n is a non-negative integer. *** at top-level: jell() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: jell(x) ===> ellj(x) ellj(x): elliptic j invariant of x. *** at top-level: karamul() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: kbessel() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: kbessel(nu,x) ===> besselk(nu,x) besselk(nu,x): K-bessel function of index nu and argument x. *** at top-level: kbessel2() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: kbessel2(nu,x) ===> besselk(nu,x) besselk(nu,x): K-bessel function of index nu and argument x. *** at top-level: ker() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ker(x) ===> matker(x) matker(x,{flag=0}): basis of the kernel of the matrix x. flag is optional, and may be set to 0: default; non-zero: x is known to have integral entries. *** at top-level: keri() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: keri(x) ===> matker(x,1) matker(x,{flag=0}): basis of the kernel of the matrix x. flag is optional, and may be set to 0: default; non-zero: x is known to have integral entries. *** at top-level: kerint() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: kerint(x) ===> matkerint(x) matkerint(x,{flag=0}): LLL-reduced Z-basis of the kernel of the matrix x with integral entries. flag is deprecated, and may be set to 0 or 1 for backward compatibility. *** at top-level: kerint1() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: kerint1(x) ===> matkerint(x,1) matkerint(x,{flag=0}): LLL-reduced Z-basis of the kernel of the matrix x with integral entries. flag is deprecated, and may be set to 0 or 1 for backward compatibility. *** at top-level: kerint2() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: kro() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: kro(x,y) ===> kronecker(x,y) kronecker(x,y): kronecker symbol (x/y). *** at top-level: label() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: lambdak() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: laplace() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: laplace(x) ===> serlaplace(x) serlaplace(x): replaces the power series sum of a_n*x^n/n! by sum of a_n*x^n. For the reverse operation, use serconvol(x,exp(X)). *** at top-level: legendre() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: legendre(n) ===> pollegendre(n) pollegendre(n,{a='x}): legendre polynomial of degree n evaluated at a. *** at top-level: lexsort() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lexsort(x) ===> vecsort(x,,2) vecsort(x,{cmpf},{flag=0}): sorts the vector of vectors (or matrix) x in ascending order, according to the comparison function cmpf, if not omitted. (If cmpf is an integer k, sort according to the value of the k-th component of each entry.) Binary digits of flag (if present) mean: 1: indirect sorting, return the permutation instead of the permuted vector, 4: use descending instead of ascending order, 8: remove duplicate entries. *** at top-level: lindep2() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lindep2(x) ===> lindep(x,1) lindep(v,{flag=0}): integral linear dependencies between components of v. flag is optional, and can be 0: default, guess a suitable accuracy, or positive: accuracy to use for the computation, in decimal digits. *** at top-level: lll() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lll(x) ===> qflll(x) qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lll1() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: lllgen() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllgen(x) ===> qflll(x,8) qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllgram() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllgram(x) ===> qflllgram(x) qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix is G (gives the unimodular transformation matrix). flag is optional and can be 0: default,1: assumes x is integral, 4: assumes x is integral, returns [K,T], where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllgram1() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: lllgramgen() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllgramgen(x) ===> qflllgram(x,8) qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix is G (gives the unimodular transformation matrix). flag is optional and can be 0: default,1: assumes x is integral, 4: assumes x is integral, returns [K,T], where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllgramint() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllgramint(x) ===> qflllgram(x,1) qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix is G (gives the unimodular transformation matrix). flag is optional and can be 0: default,1: assumes x is integral, 4: assumes x is integral, returns [K,T], where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllgramkerim() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllgramkerim(x) ===> qflllgram(x,4) qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix is G (gives the unimodular transformation matrix). flag is optional and can be 0: default,1: assumes x is integral, 4: assumes x is integral, returns [K,T], where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllgramkerimgen() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllgramkerimgen(x) ===> qflllgram(x,5) qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix is G (gives the unimodular transformation matrix). flag is optional and can be 0: default,1: assumes x is integral, 4: assumes x is integral, returns [K,T], where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllint() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllint(x) ===> qflll(x,1) qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllintpartial() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllintpartial(x) ===> qflll(x,2) qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllkerim() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllkerim(x) ===> qflll(x,4) qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllkerimgen() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lllkerimgen(x) ===> qflll(x,5) qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. *** at top-level: lllrat() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: ln() *** ^---- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ln(x) ===> log(x) log(x): natural logarithm of x. *** at top-level: localred() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: localred(e) ===> elllocalred(e) elllocalred(E,{p}): E being an elliptic curve, returns [f,kod,[u,r,s,t],c], where f is the conductor's exponent, kod is the Kodaira type for E at p, [u,r,s,t] is the change of variable needed to make E minimal at p, and c is the local Tamagawa number c_p. *** at top-level: logagm() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: logagm(x) ===> log(x,1) log(x): natural logarithm of x. *** at top-level: lseriesell() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lseriesell(e,s,N,A) ===> elllseries(e,s,A) elllseries(E,s,{A=1}): L-series at s of the elliptic curve E, where A a cut-off point close to 1. *** at top-level: makebigbnf() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: makebigbnf(sbnf) ===> bnfinit(sbnf) bnfinit(P,{flag=0},{tech=[]}): compute the necessary data for future use in ideal and unit group computations, including fundamental units if they are not too large. flag and tech are both optional. flag can be any of 0: default, 1: insist on having fundamental units. See manual for details about tech. *** at top-level: mat() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: mat(x) ===> Mat(x) Mat({x=[]}): transforms any GEN x into a matrix. Empty matrix if x is omitted. *** at top-level: matextract() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: matextract(x,y,z) ===> vecextract(x,y,z) vecextract(x,y,{z}): extraction of the components of the matrix or vector x according to y and z. If z is omitted, y represents columns, otherwise y corresponds to rows and z to columns. y and z can be vectors (of indices), strings (indicating ranges as in "1..10") or masks (integers whose binary representation indicates the indices to extract, from left to right 1, 2, 4, 8, etc.). *** at top-level: mathell() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: mathell(e,x) ===> ellheightmatrix(e,x) ellheightmatrix(E,x): gives the height matrix for vector of points x on elliptic curve E. *** at top-level: matrixqz2() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: matrixqz2(x,p) ===> matrixqz(x,-1) matrixqz(A,{p=0}): if p>=0, transforms the rational or integral mxn (m>=n) matrix A into an integral matrix with gcd of maximal determinants coprime to p. If p=-1, finds a basis of the intersection with Z^n of the lattice spanned by the columns of A. If p=-2, finds a basis of the intersection with Z^n of the Q-vector space spanned by the columns of A. *** at top-level: matrixqz3() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: matrixqz3(x,p) ===> matrixqz(x,-2) matrixqz(A,{p=0}): if p>=0, transforms the rational or integral mxn (m>=n) matrix A into an integral matrix with gcd of maximal determinants coprime to p. If p=-1, finds a basis of the intersection with Z^n of the lattice spanned by the columns of A. If p=-2, finds a basis of the intersection with Z^n of the Q-vector space spanned by the columns of A. *** at top-level: minideal() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: minideal(nf,ix,vdir) ===> idealmin(nf,ix,vdir) idealmin(nf,ix,{vdir}): pseudo-minimum of the ideal ix in the direction vdir in the number field nf. *** at top-level: minim() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: minim(x,bound,maxnum) ===> qfminim(x,bound,maxnum) qfminim(x,{b},{m},{flag=0}): x being a square and symmetric matrix representing a positive definite quadratic form, this function deals with the vectors of x whose norm is less than or equal to b, enumerated using the Fincke-Pohst algorithm, storing at most m vectors (no limit if m is omitted). The function searches for the minimal non-zero vectors if b is omitted. The precise behavior depends on flag. 0: returns at most 2m vectors (unless m omitted), returns [N,M,mat] where N is the number of vectors enumerated, M the maximum norm among these, and mat lists half the vectors (the other half is given by -mat). 1: ignores m and returns the first vector whose norm is less than b. 2: as 0 but uses a more robust, slower implementation, valid for non integral quadratic forms. *** at top-level: minim2() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: minim2(x,bound) ===> qfminim(x,bound,,1) qfminim(x,{b},{m},{flag=0}): x being a square and symmetric matrix representing a positive definite quadratic form, this function deals with the vectors of x whose norm is less than or equal to b, enumerated using the Fincke-Pohst algorithm, storing at most m vectors (no limit if m is omitted). The function searches for the minimal non-zero vectors if b is omitted. The precise behavior depends on flag. 0: returns at most 2m vectors (unless m omitted), returns [N,M,mat] where N is the number of vectors enumerated, M the maximum norm among these, and mat lists half the vectors (the other half is given by -mat). 1: ignores m and returns the first vector whose norm is less than b. 2: as 0 but uses a more robust, slower implementation, valid for non integral quadratic forms. *** at top-level: mod() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: mod(x,y) ===> Mod(x,y) Mod(a,b): creates 'a modulo b'. *** at top-level: modp() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: modp(x,y,p) ===> Mod(x,y) Mod(a,b): creates 'a modulo b'. *** at top-level: modulargcd() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: modulargcd(x,y) ===> gcd(x,y,1) gcd(x,{y}): greatest common divisor of x and y. *** at top-level: mu() *** ^---- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: mu(n) ===> moebius(n) moebius(x): Moebius function of x. *** at top-level: nfdiv() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfdiv(nf,a,b) ===> nfeltdiv(nf,a,b) nfeltdiv(nf,x,y): element x/y in nf. *** at top-level: nfdiveuc() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfdiveuc(nf,a,b) ===> nfeltdiveuc(nf,a,b) nfeltdiveuc(nf,x,y): gives algebraic integer q such that x-qy is small. *** at top-level: nfdivres() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfdivres(nf,a,b) ===> nfeltdivrem(nf,a,b) nfeltdivrem(nf,x,y): gives [q,r] such that r=x-qy is small. *** at top-level: nfhermite() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfhermite(nf,x) ===> nfhnf(nf,x) nfhnf(nf,x,{flag=0}): if x=[A,I], gives a pseudo-basis [B,J] of the module sum A_jI_j. If flag is non-zero, return [[B,J], U], where U is the transformation matrix such that AU = [0|B]. *** at top-level: nfhermitemod() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfhermitemod(nf,x,detx) ===> nfhnfmod(nf,x,detx) nfhnfmod(nf,x,detx): if x=[A,I], and detx is a multiple of the ideal determinant of x, gives a pseudo-basis of the module sum A_jI_j. *** at top-level: nfmod() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfmod(nf,a,b) ===> nfeltmod(nf,a,b) nfeltmod(nf,x,y): gives r such that r=x-qy is small with q algebraic integer. *** at top-level: nfmul() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfmul(nf,a,b) ===> nfeltmul(nf,a,b) nfeltmul(nf,x,y): element x.y in nf. *** at top-level: nfpow() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfpow(nf,a,k) ===> nfeltpow(nf,a,k) nfeltpow(nf,x,k): element x^k in nf. *** at top-level: nfreduce() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfreduce(nf,a,id) ===> nfeltreduce(nf,a,id) nfeltreduce(nf,a,id): gives r such that a-r is in the ideal id and r is small. *** at top-level: nfsmith() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfsmith(nf,x) ===> nfsnf(nf,x) nfsnf(nf,x,{flag=0}): if x=[A,I,J], outputs D=[d_1,...d_n] Smith normal form of x. If flag is non-zero return [D,U,V], where UAV = Id. *** at top-level: nfval() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nfval(nf,a,pr) ===> nfeltval(nf,a,pr) nfeltval(nf,x,pr,{&y}): valuation of element x at the prime pr as output by idealprimedec. *** at top-level: nucomp() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nucomp(x,y,l) ===> qfbnucomp(x,y,l) qfbnucomp(x,y,L): composite of primitive positive definite quadratic forms x and y using nucomp and nudupl, where L=[|D/4|^(1/4)] is precomputed. *** at top-level: numer() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: numer(x) ===> numerator(x) numerator(f,{D}): numerator of f. *** at top-level: nupow() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: nupow(x,n) ===> qfbnupow(x,n) qfbnupow(x,n,{L}): n-th power of primitive positive definite quadratic form x using nucomp and nudupl. *** at top-level: o() *** ^--- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: o(x) ===> O(x) O(p^e): p-adic or power series zero with precision given by e. *** at top-level: ordell() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ordell(e,x) ===> ellordinate(e,x) ellordinate(E,x): y-coordinates corresponding to x-ordinate x on elliptic curve E. *** at top-level: order() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: order(x) ===> znorder(x) znorder(x,{o}): order of the integermod x in (Z/nZ)*. Optional o represents a multiple of the order of the element. *** at top-level: orderell() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: orderell(e,x) ===> ellorder(e,x) ellorder(E,z,{o}): order of the point z on the elliptic curve E over a number field or a finite field, 0 if non-torsion. The parameter o, if present, represents a non-zero multiple of the order of z. *** at top-level: ordred() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ordred(x) ===> polredord(x) polredord(x): this function is obsolete, use polredbest. *** at top-level: pascal() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: pascal(n) ===> matpascal(n) matpascal(n,{q}): Pascal triangle of order n if q is omitted. q-Pascal triangle otherwise. *** at top-level: perf() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: perf(a) ===> qfperfection(a) qfperfection(G): rank of matrix of xx~ for x minimal vectors of a gram matrix G. *** at top-level: permutation() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: permutation(n,k) ===> numtoperm(n,k) numtoperm(n,k): permutation number k (mod n!) of n letters (n C-integer). *** at top-level: permutation2num() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: permutation2num(vect) ===> permtonum(vect) permtonum(x): ordinal (between 1 and n!) of permutation x. *** at top-level: pf() *** ^---- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: pf(x,p) ===> qfbprimeform(x,p) qfbprimeform(x,p): returns the prime form of discriminant x, whose first coefficient is p. *** at top-level: phi() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: phi(x) ===> eulerphi(x) eulerphi(x): Euler's totient function of x. *** at top-level: pi() *** ^---- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: pi ===> Pi Pi=Pi(): the constant pi, with current precision. *** at top-level: pnqn() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: pnqn(x) ===> contfracpnqn(x) contfracpnqn(x, {n=-1}): [p_n,p_{n-1}; q_n,q_{n-1}] corresponding to the continued fraction x. If n >= 0 is present, returns all convergents from p_0/q_0 up to p_n/q_n. *** at top-level: pointell() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: pointell(e,z) ===> ellztopoint(e,z) ellztopoint(E,z): inverse of ellpointtoz. Returns the coordinates of point P on the curve E corresponding to a complex or p-adic z. *** at top-level: polint() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polint(xa,ya,x) ===> polinterpolate(xa,ya,p) polinterpolate(X,{Y},{t = 'x},{&e}): polynomial interpolation at t according to data vectors X, Y (i.e. given P of minimal degree such that P(X[i]) = Y[i] for all i, return P(t)). If Y is omitted, take P such that P(i) = X[i]. If present, e will contain an error estimate on the returned value. *** at top-level: polred2() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polred2(x) ===> polred(x,2) polred(T,{flag=0}): deprecated, use polredbest. Reduction of the polynomial T (gives minimal polynomials only). The following binary digits of (optional) flag are significant 1: partial reduction, 2: gives also elements. *** at top-level: polredabs2() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polredabs2(x) ===> polredabs(x,1) polredabs(T,{flag=0}): a smallest generating polynomial of the number field for the T2 norm on the roots, with smallest index for the minimal T2 norm. flag is optional, whose binary digit mean 1: give the element whose characteristic polynomial is the given polynomial. 4: give all polynomials of minimal T2 norm (give only one of P(x) and P(-x)). *** at top-level: polredabsall() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polredabsall(x) ===> polredabs(x,4) polredabs(T,{flag=0}): a smallest generating polynomial of the number field for the T2 norm on the roots, with smallest index for the minimal T2 norm. flag is optional, whose binary digit mean 1: give the element whose characteristic polynomial is the given polynomial. 4: give all polynomials of minimal T2 norm (give only one of P(x) and P(-x)). *** at top-level: polredabsfast() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polredabsfast(x) ===> polredabs(x,8) polredabs(T,{flag=0}): a smallest generating polynomial of the number field for the T2 norm on the roots, with smallest index for the minimal T2 norm. flag is optional, whose binary digit mean 1: give the element whose characteristic polynomial is the given polynomial. 4: give all polynomials of minimal T2 norm (give only one of P(x) and P(-x)). *** at top-level: polredabsnored() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polredabsnored(x) ===> polredabs(x,2) polredabs(T,{flag=0}): a smallest generating polynomial of the number field for the T2 norm on the roots, with smallest index for the minimal T2 norm. flag is optional, whose binary digit mean 1: give the element whose characteristic polynomial is the given polynomial. 4: give all polynomials of minimal T2 norm (give only one of P(x) and P(-x)). *** at top-level: polvar() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polvar(x) ===> variable(x) variable({x}): main variable of object x. Gives p for p-adic x, 0 if no variable can be attached to x. Returns the list of user variables if x is omitted. *** at top-level: poly() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: poly(x,v) ===> Pol(x,v) Pol(t,{v='x}): convert t (usually a vector or a power series) into a polynomial with variable v, starting with the leading coefficient. *** at top-level: polylogd() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polylogd(m,x) ===> polylog(m,x,1) polylog(m,x,{flag=0}): m-th polylogarithm of x. flag is optional, and can be 0: default, 1: D_m~-modified m-th polylog of x, 2: D_m-modified m-th polylog of x, 3: P_m-modified m-th polylog of x. *** at top-level: polylogdold() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polylogdold(m,x) ===> polylog(m,x,2) polylog(m,x,{flag=0}): m-th polylogarithm of x. flag is optional, and can be 0: default, 1: D_m~-modified m-th polylog of x, 2: D_m-modified m-th polylog of x, 3: P_m-modified m-th polylog of x. *** at top-level: polylogp() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polylogp(m,x) ===> polylog(m,x,3) polylog(m,x,{flag=0}): m-th polylogarithm of x. flag is optional, and can be 0: default, 1: D_m~-modified m-th polylog of x, 2: D_m-modified m-th polylog of x, 3: P_m-modified m-th polylog of x. *** at top-level: polyrev() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polyrev(x,v) ===> Polrev(x,v) Polrev(t,{v='x}): convert t (usually a vector or a power series) into a polynomial with variable v, starting with the constant term. *** at top-level: polzag() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: polzag(n,m) ===> polzagier(n,m) polzagier(n,m): Zagier's polynomials of index n,m. *** at top-level: powell() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: powell(e,x,n) ===> ellmul(e,x,n) ellmul(E,z,n): n times the point z on elliptic curve E (n in Z). *** at top-level: powrealraw() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: powrealraw(x,n) ===> qfbpowraw(x,n) qfbpowraw(x,n): n-th power without reduction of the binary quadratic form x. *** at top-level: prec() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: prec(x,n) ===> precision(x,n) precision(x,{n}): if n is present, return x at precision n. If n is omitted, return real precision of object x. *** at top-level: primedec() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: primedec(nf,p) ===> idealprimedec(nf,p) idealprimedec(nf,p,{f=0}): prime ideal decomposition of the prime number p in the number field nf as a vector of prime ideals. If f is present and non-zero, restrict the result to primes of residue degree <= f. *** at top-level: primroot() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: primroot(n) ===> znprimroot(n) znprimroot(n): returns a primitive root of n when it exists. *** at top-level: principalideal() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: principalidele() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: prodinf1() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: prodinf1(X=a,expr) ===> prodinf(X=a,expr,1) prodinf(X=a,expr,{flag=0}): infinite product (X goes from a to infinity) of real or complex expression. flag can be 0 (default) or 1, in which case compute the product of the 1+expr instead. *** at top-level: qfi() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: qfi(a,b,c) ===> Qfb(a,b,c) Qfb(a,b,c,{D=0.}): binary quadratic form a*x^2+b*x*y+c*y^2. D is optional (0.0 by default) and initializes Shanks's distance if b^2-4*a*c>0. *** at top-level: qfr() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: qfr(a,b,c,d) ===> Qfb(a,b,c,d) Qfb(a,b,c,{D=0.}): binary quadratic form a*x^2+b*x*y+c*y^2. D is optional (0.0 by default) and initializes Shanks's distance if b^2-4*a*c>0. 1546275796 *** at top-level: rank() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rank(x) ===> matrank(x) matrank(x): rank of the matrix x. *** at top-level: rayclassno() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rayclassno(bnf,x) ===> bnrclassno(bnf,x) bnrclassno(A,{B},{C}): relative degree of the class field defined by A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf,modulus], or [bnf,modulus,subgroup]. Faster than bnrinit if only the ray class number is wanted. *** at top-level: rayclassnolist() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rayclassnolist(bnf,liste) ===> bnrclassnolist(bnf,liste) bnrclassnolist(bnf,list): if list is as output by ideallist or similar, gives list of corresponding ray class numbers. *** at top-level: recip() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: recip(x) ===> polrecip(x) polrecip(pol): reciprocal polynomial of pol. *** at top-level: redimag() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: redimag(x) ===> qfbred(x) qfbred(x,{flag=0},{d},{isd},{sd}): reduction of the binary quadratic form x. All other args. are optional. The arguments d, isd and sd, if present, supply the values of the discriminant, floor(sqrt(d)) and sqrt(d) respectively. If d<0, its value is not used and all references to Shanks's distance hereafter are meaningless. flag can be any of 0: default, uses Shanks's distance function d; 1: use d, do a single reduction step; 2: do not use d; 3: do not use d, single reduction step. *** at top-level: redreal() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: redreal(x) ===> qfbred(x) qfbred(x,{flag=0},{d},{isd},{sd}): reduction of the binary quadratic form x. All other args. are optional. The arguments d, isd and sd, if present, supply the values of the discriminant, floor(sqrt(d)) and sqrt(d) respectively. If d<0, its value is not used and all references to Shanks's distance hereafter are meaningless. flag can be any of 0: default, uses Shanks's distance function d; 1: use d, do a single reduction step; 2: do not use d; 3: do not use d, single reduction step. *** at top-level: redrealnod() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: redrealnod(x,d) ===> qfbred(x,2,,d) qfbred(x,{flag=0},{d},{isd},{sd}): reduction of the binary quadratic form x. All other args. are optional. The arguments d, isd and sd, if present, supply the values of the discriminant, floor(sqrt(d)) and sqrt(d) respectively. If d<0, its value is not used and all references to Shanks's distance hereafter are meaningless. flag can be any of 0: default, uses Shanks's distance function d; 1: use d, do a single reduction step; 2: do not use d; 3: do not use d, single reduction step. *** at top-level: reduceddisc() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: reduceddisc(f) ===> poldiscreduced(f) poldiscreduced(f): vector of elementary divisors of Z[a]/f'(a)Z[a], where a is a root of the polynomial f. *** at top-level: regula() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: regula(x) ===> quadregulator(x) quadregulator(x): regulator of the real quadratic field of discriminant x. *** at top-level: reorder() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: resultant() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: resultant(x,y) ===> polresultant(x,y) polresultant(x,y,{v},{flag=0}): resultant of the polynomials x and y, with respect to the main variables of x and y if v is omitted, with respect to the variable v otherwise. flag is optional, and can be 0: default, uses either the subresultant algorithm, a modular algorithm or Sylvester's matrix, depending on the inputs; 1 uses Sylvester's matrix (should always be slower than the default). *** at top-level: resultant2() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: resultant2(x,y) ===> polresultant(x,y,1) polresultant(x,y,{v},{flag=0}): resultant of the polynomials x and y, with respect to the main variables of x and y if v is omitted, with respect to the variable v otherwise. flag is optional, and can be 0: default, uses either the subresultant algorithm, a modular algorithm or Sylvester's matrix, depending on the inputs; 1 uses Sylvester's matrix (should always be slower than the default). *** at top-level: reverse() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: reverse(x) ===> serreverse(x) serreverse(s): reversion of the power series s. *** at top-level: rhoreal() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rhoreal(x) ===> qfbred(x,1) qfbred(x,{flag=0},{d},{isd},{sd}): reduction of the binary quadratic form x. All other args. are optional. The arguments d, isd and sd, if present, supply the values of the discriminant, floor(sqrt(d)) and sqrt(d) respectively. If d<0, its value is not used and all references to Shanks's distance hereafter are meaningless. flag can be any of 0: default, uses Shanks's distance function d; 1: use d, do a single reduction step; 2: do not use d; 3: do not use d, single reduction step. *** at top-level: rhorealnod() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rhorealnod(x,d) ===> qfbred(x,3,,d) qfbred(x,{flag=0},{d},{isd},{sd}): reduction of the binary quadratic form x. All other args. are optional. The arguments d, isd and sd, if present, supply the values of the discriminant, floor(sqrt(d)) and sqrt(d) respectively. If d<0, its value is not used and all references to Shanks's distance hereafter are meaningless. flag can be any of 0: default, uses Shanks's distance function d; 1: use d, do a single reduction step; 2: do not use d; 3: do not use d, single reduction step. *** at top-level: rndtoi() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rndtoi(x) ===> round(x,&e) round(x,{&e}): take the nearest integer to all the coefficients of x. If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits. *** at top-level: rnfdiscf() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rnfdiscf(nf,pol) ===> rnfdisc(nf,pol) rnfdisc(nf,T): given a polynomial T with coefficients in nf, gives a 2-component vector [D,d], where D is the relative ideal discriminant, and d is the relative discriminant in nf^*/nf*^2. *** at top-level: rnfequation2() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rnfequation2(nf,pol) ===> rnfequation(nf,pol,1) rnfequation(nf,pol,{flag=0}): given a pol with coefficients in nf, gives an absolute equation z of the number field defined by pol. flag is optional, and can be 0: default, or non-zero, gives [z,al,k], where z defines the absolute equation L/Q as in the default behavior, al expresses as an element of L a root of the polynomial defining the base field nf, and k is a small integer such that t = b + k al is a root of z, for b a root of pol. *** at top-level: rnfhermitebasis() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rnfhermitebasis(bnf,order) ===> rnfhnfbasis(bnf,order) rnfhnfbasis(bnf,x): given an order x as output by rnfpseudobasis, gives either a true HNF basis of the order if it exists, zero otherwise. *** at top-level: rootmod() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rootmod(x,p) ===> polrootsmod(x,p) polrootsmod(f,{D}): roots of the polynomial f over the finite field defined by the domain D. *** at top-level: rootmod2() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rootmod2(x,p) ===> polrootsmod(x,p) polrootsmod(f,{D}): roots of the polynomial f over the finite field defined by the domain D. *** at top-level: rootpadic() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rootpadic(x,p,r) ===> polrootspadic(x,p,r) polrootspadic(x,p,r): p-adic roots of the polynomial x to precision r. *** at top-level: roots() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: roots(x) ===> polroots(x) polroots(T): complex roots of the polynomial T using Schonhage's method, as modified by Gourdon. *** at top-level: rootsof1() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rootsof1(nf) ===> nfrootsof1(nf) nfrootsof1(nf): number of roots of unity and primitive root of unity in the number field nf. *** at top-level: rootsold() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: rounderror() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rounderror(x) ===> round(x,&e) round(x,{&e}): take the nearest integer to all the coefficients of x. If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits. *** at top-level: series() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: series(x,v) ===> Ser(x,v) Ser(s,{v='x},{d=seriesprecision}): convert s into a power series with variable v and precision d, starting with the constant coefficient. *** at top-level: set() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: set(x) ===> Set(x) Set({x=[]}): convert x into a set, i.e. a row vector with strictly increasing coefficients. Empty set if x is omitted. *** at top-level: sigmak() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sigmak(k,x) ===> sigma(x,k) sigma(x,{k=1}): sum of the k-th powers of the divisors of x. k is optional and if omitted is assumed to be equal to 1. *** at top-level: signat() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: signat(x) ===> qfsign(x) qfsign(x): signature of the symmetric matrix x. *** at top-level: signunit() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: signunit(bnf) ===> bnfsignunit(bnf) bnfsignunit(bnf): matrix of signs of the real embeddings of the system of fundamental units found by bnfinit. *** at top-level: simplefactmod() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: simplefactmod(x,p) ===> factormod(x,p,1) factormod(f,{D},{flag=0}): factors the polynomial f over the finite field defined by the domain D; flag is optional, and can be 0: default or 1: only the degrees of the irreducible factors are given. *** at top-level: size() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: size(x) ===> sizedigit(x) sizedigit(x): rough upper bound for the number of decimal digits of (the components of) x. DEPRECATED. *** at top-level: smallbasis() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smallbasis(x) ===> nfbasis(x,1) nfbasis(T): integral basis of the field Q[a], where a is a root of the polynomial T, using the round 4 algorithm. An argument [T,listP] is possible, where listP is a list of primes (to get an order which is maximal at certain primes only) or a prime bound. *** at top-level: smallbuchinit() *** ^--------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smallbuchinit(x) ===> bnfcompress(x) bnfcompress(bnf): converts bnf to a much smaller sbnf, containing the same information. Use bnfinit(sbnf) to recover a true bnf. *** at top-level: smalldiscf() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smalldiscf(x) ===> nfdisc(x,1) nfdisc(T): discriminant of the number field defined by the polynomial T. An argument [T,listP] is possible, where listP is a list of primes or a prime bound. *** at top-level: smallfact() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smallfact(x) ===> factor(x,0) factor(x,{D}): factorization of x over domain D. If x and D are both integers, return partial factorization, using primes < D. *** at top-level: smallinitell() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smallinitell(x) ===> ellinit(x,1) ellinit(x,{D=1}): let x be a vector [a1,a2,a3,a4,a6], or [a4,a6] if a1=a2=a3=0, defining the curve Y^2 + a1.XY + a3.Y = X^3 + a2.X^2 + a4.X + a6; x can also be a string, in which case the curve with matching name is retrieved from the elldata database, if available. This function initializes an elliptic curve over the domain D (inferred from coefficients if omitted). *** at top-level: smallpolred() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smallpolred(x) ===> polred(x,1) polred(T,{flag=0}): deprecated, use polredbest. Reduction of the polynomial T (gives minimal polynomials only). The following binary digits of (optional) flag are significant 1: partial reduction, 2: gives also elements. *** at top-level: smallpolred2() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smallpolred2(x) ===> polred(x,3) polred(T,{flag=0}): deprecated, use polredbest. Reduction of the polynomial T (gives minimal polynomials only). The following binary digits of (optional) flag are significant 1: partial reduction, 2: gives also elements. *** at top-level: smith() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smith(x) ===> matsnf(x) matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of the matrix X, expressed as a vector d. Binary digits of flag mean 1: returns [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned, 2: allow polynomial entries, otherwise assume X is integral, 4: removes all information corresponding to entries equal to 1 in d. *** at top-level: smith2() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smith2(x) ===> matsnf(x,1) matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of the matrix X, expressed as a vector d. Binary digits of flag mean 1: returns [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned, 2: allow polynomial entries, otherwise assume X is integral, 4: removes all information corresponding to entries equal to 1 in d. *** at top-level: smithclean() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smithclean(x) ===> matsnf(x,4) matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of the matrix X, expressed as a vector d. Binary digits of flag mean 1: returns [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned, 2: allow polynomial entries, otherwise assume X is integral, 4: removes all information corresponding to entries equal to 1 in d. *** at top-level: smithpol() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: smithpol(x) ===> matsnf(x,2) matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of the matrix X, expressed as a vector d. Binary digits of flag mean 1: returns [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned, 2: allow polynomial entries, otherwise assume X is integral, 4: removes all information corresponding to entries equal to 1 in d. *** at top-level: sort() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sort(x) ===> vecsort(x) vecsort(x,{cmpf},{flag=0}): sorts the vector of vectors (or matrix) x in ascending order, according to the comparison function cmpf, if not omitted. (If cmpf is an integer k, sort according to the value of the k-th component of each entry.) Binary digits of flag (if present) mean: 1: indirect sorting, return the permutation instead of the permuted vector, 4: use descending instead of ascending order, 8: remove duplicate entries. *** at top-level: sqred() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sqred(x) ===> qfgaussred(x) qfgaussred(q): square reduction of the (symmetric) matrix q (returns a square matrix whose i-th diagonal term is the coefficient of the i-th square in which the coefficient of the i-th variable is 1). *** at top-level: srgcd() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: srgcd(x,y) ===> gcd(x,y,2) gcd(x,{y}): greatest common divisor of x and y. *** at top-level: sturm() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sturm(x) ===> polsturm(x) polsturm(T,{ab}): number of distinct real roots of the polynomial T (in the interval ab = [a,b] if present). *** at top-level: sturmpart() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sturmpart(x,a,b) ===> polsturm(x,a,b) polsturm(T,{ab}): number of distinct real roots of the polynomial T (in the interval ab = [a,b] if present). *** at top-level: subcyclo() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: subcyclo(p,d) ===> polsubcyclo(p,d) polsubcyclo(n,d,{v='x}): finds an equation (in variable v) for the d-th degree subfields of Q(zeta_n). Output is a polynomial, or a vector of polynomials if there are several such fields or none. *** at top-level: subell() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: subell(e,a,b) ===> ellsub(e,a,b) ellsub(E,z1,z2): difference of the points z1 and z2 on elliptic curve E. *** at top-level: sumalt2() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sumalt2(X=a,expr) ===> sumalt(X=a,expr,1) sumalt(X=a,expr,{flag=0}): Cohen-Villegas-Zagier's acceleration of alternating series expr, X starting at a. flag is optional, and can be 0: default, or 1: uses a slightly different method using Zagier's polynomials. *** at top-level: sumpos2() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sumpos2(X=a,expr) ===> sumpos(X=a,expr,1) sumpos(X=a,expr,{flag=0}): sum of positive (or negative) series expr, the formal variable X starting at a. flag is optional, and can be 0: default, or 1: uses a slightly different method using Zagier's polynomials. *** at top-level: supplement() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: supplement(x) ===> matsupplement(x) matsupplement(x): supplement the columns of the matrix x to an invertible matrix. *** at top-level: sylvestermatrix() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: sylvestermatrix(x,y) ===> polsylvestermatrix(x,y) polsylvestermatrix(x,y): forms the sylvester matrix attached to the two polynomials x and y. Warning: the polynomial coefficients are in columns, not in rows. *** at top-level: taniyama() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: taniyama(e) ===> elltaniyama(e) elltaniyama(E, {d = seriesprecision}): modular parametrization of elliptic curve E/Q. *** at top-level: tchebi() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: tchebi(n) ===> polchebyshev(n) polchebyshev(n,{flag=1},{a='x}): Chebychev polynomial of the first (flag = 1) or second (flag = 2) kind, of degree n, evaluated at a. *** at top-level: teich() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: teich(x) ===> teichmuller(x) teichmuller(x,{tab}): teichmuller character of p-adic number x. If x = [p,n], return the lifts of all teichmuller(i + O(p^n)) for i = 1, ..., p-1. Such a vector can be fed back to teichmuller, as the optional argument tab, to speed up later computations. *** at top-level: threetotwo() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: threetotwo2() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: torsell() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: torsell(e) ===> elltors(e) elltors(E): torsion subgroup of elliptic curve E: order, structure, generators. *** at top-level: trans() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: trans(x) ===> mattranspose(x) mattranspose(x): x~ = transpose of x. *** at top-level: trunc() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: trunc(x) ===> truncate(x) truncate(x,{&e}): truncation of x; when x is a power series,take away the O(X^). If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits. *** at top-level: tschirnhaus() *** ^------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: tschirnhaus(x) ===> poltschirnhaus(x) poltschirnhaus(x): random Tschirnhausen transformation of the polynomial x. *** at top-level: twototwo() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: unit() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: unit(x) ===> quadunit(x) quadunit(D,{v = 'w}): fundamental unit u of the quadratic field of discriminant D where D must be positive. If v is given, the variable name is used to display u, else 'w' is used. *** at top-level: vec() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: vec(x) ===> Vec(x) Vec(x, {n}): transforms the object x into a vector of dimension n. *** at top-level: vecindexsort() *** ^-------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: vecindexsort(x) ===> vecsort(x,,1) vecsort(x,{cmpf},{flag=0}): sorts the vector of vectors (or matrix) x in ascending order, according to the comparison function cmpf, if not omitted. (If cmpf is an integer k, sort according to the value of the k-th component of each entry.) Binary digits of flag (if present) mean: 1: indirect sorting, return the permutation instead of the permuted vector, 4: use descending instead of ascending order, 8: remove duplicate entries. *** at top-level: veclexsort() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: veclexsort(x) ===> vecsort(x,,2) vecsort(x,{cmpf},{flag=0}): sorts the vector of vectors (or matrix) x in ascending order, according to the comparison function cmpf, if not omitted. (If cmpf is an integer k, sort according to the value of the k-th component of each entry.) Binary digits of flag (if present) mean: 1: indirect sorting, return the permutation instead of the permuted vector, 4: use descending instead of ascending order, 8: remove duplicate entries. *** at top-level: vvector() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: vvector(n,X,expr) ===> vectorv(n,X,expr) vectorv(n,{X},{expr=0}): column vector with n components of expression expr (X ranges from 1 to n). By default, fill with 0s. *** at top-level: weipell() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: weipell(e) ===> ellwp(e) ellwp(w,{z='x},{flag=0}): computes the value at z of the Weierstrass P function attached to the lattice w, as given by ellperiods. Optional flag means 0 (default), compute only P(z), 1 compute [P(z),P'(z)]. *** at top-level: wf() *** ^---- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: wf(x) ===> weber(x) weber(x,{flag=0}): one of Weber's f function of x. flag is optional, and can be 0: default, function f(x)=exp(-i*Pi/24)*eta((x+1)/2)/eta(x), 1: function f1(x)=eta(x/2)/eta(x) 2: function f2(x)=sqrt(2)*eta(2*x)/eta(x). Note that j = (f^24-16)^3/f^24 = (f1^24+16)^3/f1^24 = (f2^24+16)^3/f2^24. *** at top-level: wf2() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: wf2(x) ===> weber(x,2) weber(x,{flag=0}): one of Weber's f function of x. flag is optional, and can be 0: default, function f(x)=exp(-i*Pi/24)*eta((x+1)/2)/eta(x), 1: function f1(x)=eta(x/2)/eta(x) 2: function f2(x)=sqrt(2)*eta(2*x)/eta(x). Note that j = (f^24-16)^3/f^24 = (f1^24+16)^3/f1^24 = (f2^24+16)^3/f2^24. *** at top-level: zell() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: zell(e,P) ===> ellpointtoz(e,P) ellpointtoz(E,P): lattice point z corresponding to the point P on the elliptic curve E. *** at top-level: zideallog() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: zideallog(nf,x,bid) ===> ideallog(nf,x,bid) ideallog({nf},x,bid): if bid is a big ideal, as given by idealstar(nf,D,...), gives the vector of exponents on the generators bid.gen (even if these generators have not been explicitly computed). *** at top-level: zidealstar() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: zidealstar(nf,I) ===> idealstar(nf,I) idealstar({nf},N,{flag=1}): gives the structure of (Z_K/N)^*, where N is a modulus (an ideal in any form or a vector [f0, foo], where f0 is an ideal and foo is a {0,1}-vector with r1 components. flag is optional, and can be 0: simply gives the structure as an abelian group, i.e. a 3-component vector [h,d,g] where h is the order, d the orders of the cyclic factors and g the generators; if flag=1 (default), gives a bid structure used in ideallog to compute discrete logarithms; underlying generators are well-defined but not explicitly computed, which saves time; if flag=2, same as with flag=1 except that the generators are also given. If nf is omitted, N must be an integer and we return the structure of (Z/NZ)^*. *** at top-level: zidealstarinit() *** ^---------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: zidealstarinit(nf,id) ===> idealstar(nf,id,1) idealstar({nf},N,{flag=1}): gives the structure of (Z_K/N)^*, where N is a modulus (an ideal in any form or a vector [f0, foo], where f0 is an ideal and foo is a {0,1}-vector with r1 components. flag is optional, and can be 0: simply gives the structure as an abelian group, i.e. a 3-component vector [h,d,g] where h is the order, d the orders of the cyclic factors and g the generators; if flag=1 (default), gives a bid structure used in ideallog to compute discrete logarithms; underlying generators are well-defined but not explicitly computed, which saves time; if flag=2, same as with flag=1 except that the generators are also given. If nf is omitted, N must be an integer and we return the structure of (Z/NZ)^*. *** at top-level: zidealstarinitgen() *** ^------------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: zidealstarinitgen(nf,id) ===> idealstar(nf,id,2) idealstar({nf},N,{flag=1}): gives the structure of (Z_K/N)^*, where N is a modulus (an ideal in any form or a vector [f0, foo], where f0 is an ideal and foo is a {0,1}-vector with r1 components. flag is optional, and can be 0: simply gives the structure as an abelian group, i.e. a 3-component vector [h,d,g] where h is the order, d the orders of the cyclic factors and g the generators; if flag=1 (default), gives a bid structure used in ideallog to compute discrete logarithms; underlying generators are well-defined but not explicitly computed, which saves time; if flag=2, same as with flag=1 except that the generators are also given. If nf is omitted, N must be an integer and we return the structure of (Z/NZ)^*. *** at top-level: box() *** ^----- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: box(x,a) ===> plotbox(x,a) plotbox(w,x2,y2,{filled=0}): if the cursor is at position (x1,y1), draw a box with diagonal (x1,y1) and (x2,y2) in rectwindow w (cursor does not move). If filled=1, fill the box. *** at top-level: color() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: color(w,c) ===> plotcolor(w,c) plotcolor(w,c): in rectwindow w, set default color to c. Possible values for c are [R,G,B] values, a color name or an index in the graphcolormap default: factory settings are 1=black, 2=blue, 3=sienna, 4=red, 5=green, 6=grey, 7=gainsborough. Return [R,G,B] value attached to color. *** at top-level: cursor() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: cursor(w) ===> plotcursor(w) plotcursor(w): current position of cursor in rectwindow w. *** at top-level: draw() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: draw(list) ===> plotdraw(list) plotdraw(w, {flag=0}): draw rectwindow w. More generally, w can be of the form [w1,x1,y1, w2,x2,y2,etc.]: draw rectwindows wi at given xi,yi positions. If flag!=0, the xi,yi express fractions of the size of the current output device. *** at top-level: initrect() *** ^---------- *** not a function in function call *** at top-level: killrect() *** ^---------- *** not a function in function call *** at top-level: line() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: line(w,x2,y2) ===> plotlines(w,x2,y2) plotlines(w,X,Y,{flag=0}): draws an open polygon in rectwindow w where X and Y contain the x (resp. y) coordinates of the vertices. If X and Y are both single values (i.e not vectors), draw the corresponding line (and move cursor). If (optional) flag is non-zero, close the polygon. *** at top-level: lines() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: lines(w,x2,y2) ===> plotlines(w,x2,y2) plotlines(w,X,Y,{flag=0}): draws an open polygon in rectwindow w where X and Y contain the x (resp. y) coordinates of the vertices. If X and Y are both single values (i.e not vectors), draw the corresponding line (and move cursor). If (optional) flag is non-zero, close the polygon. *** at top-level: move() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: move(w,x,y) ===> plotmove(w,x,y) plotmove(w,x,y): move cursor to position x,y in rectwindow w. *** at top-level: ploth2() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: ploth2(X=a,b,expr) ===> ploth(X=a,b,expr,1) ploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean: 1=Parametric, 2=Recursive, 4=no_Rescale, 8=no_X_axis, 16=no_Y_axis, 32=no_Frame, 64=no_Lines (do not join points), 128=Points_too (plot both lines and points), 256=Splines (use cubic splines), 512=no_X_ticks, 1024= no_Y_ticks, 2048=Same_ticks (plot all ticks with the same length), 4096=Complex (the two coordinates of each point are encoded as a complex number). n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box. *** at top-level: plothmult() *** ^----------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: plothmult(X=a,b,expr) ===> ploth(X=a,b,expr) ploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean: 1=Parametric, 2=Recursive, 4=no_Rescale, 8=no_X_axis, 16=no_Y_axis, 32=no_Frame, 64=no_Lines (do not join points), 128=Points_too (plot both lines and points), 256=Splines (use cubic splines), 512=no_X_ticks, 1024= no_Y_ticks, 2048=Same_ticks (plot all ticks with the same length), 4096=Complex (the two coordinates of each point are encoded as a complex number). n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box. *** at top-level: point() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: point(w,x,y) ===> plotpoints(w,x,y) plotpoints(w,X,Y): draws in rectwindow w the points whose x (resp y) coordinates are in X (resp Y). If X and Y are both single values (i.e not vectors), draw the corresponding point (and move cursor). *** at top-level: points() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: points(w,x,y) ===> plotpoints(w,x,y) plotpoints(w,X,Y): draws in rectwindow w the points whose x (resp y) coordinates are in X (resp Y). If X and Y are both single values (i.e not vectors), draw the corresponding point (and move cursor). *** at top-level: postdraw() *** ^---------- *** not a function in function call *** at top-level: postploth() *** ^----------- *** not a function in function call *** at top-level: postploth2() *** ^------------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: postploth2(X=a,b,expr) ===> psploth(X=a,b,expr,1) psploth(X=a,b,expr,{flags=0},{n=0}): obsolete function. *** at top-level: postplothraw() *** ^-------------- *** not a function in function call *** at top-level: pprint() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: pprint1() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. This function no longer exists *** at top-level: rbox() *** ^------ *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rbox(w,dx,dy) ===> plotrbox(w,dx,dy) plotrbox(w,dx,dy,{filled}): if the cursor is at (x1,y1), draw a box with diagonal (x1,y1)-(x1+dx,y1+dy) in rectwindow w (cursor does not move). If filled=1, fill the box. *** at top-level: read() *** ^------ *** read: You never gave me anything to read!. *** at top-level: rline() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rline(w,dx,dy) ===> plotrline(w,dx,dy) plotrline(w,dx,dy): if the cursor is at (x1,y1), draw a line from (x1,y1) to (x1+dx,y1+dy) (and move the cursor) in the rectwindow w. *** at top-level: rlines() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. *** at top-level: rlines() *** ^-------- *** bug in whatnow, please report. *** at top-level: rmove() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rmove(w,dx,dy) ===> plotrmove(w,dx,dy) plotrmove(w,dx,dy): move cursor to position (dx,dy) relative to the present position in the rectwindow w. *** at top-level: rpoint() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: rpoint(w,dx,dy) ===> plotrpoint(w,dx,dy) plotrpoint(w,dx,dy): draw a point (and move cursor) at position dx,dy relative to present position of the cursor in rectwindow w. *** at top-level: rpoints() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. *** at top-level: rpoints() *** ^--------- *** bug in whatnow, please report. *** at top-level: scale() *** ^------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: scale(w,x1,x2,y1,y2) ===> plotscale(w,x1,x2,y1,y2) plotscale(w,x1,x2,y1,y2): scale the coordinates in rectwindow w so that x goes from x1 to x2 and y from y1 to y2 (y2 default(realprecision,n) default({key},{val}): returns the current value of the default key. If val is present, set opt to val first. If no argument is given, print a list of all defaults as well as their values. *** at top-level: setserieslength() *** ^----------------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: setserieslength(n) ===> default(seriesprecision,n) default({key},{val}): returns the current value of the default key. If val is present, set opt to val first. If no argument is given, print a list of all defaults as well as their values. *** at top-level: settype() *** ^--------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: settype(x,t) ===> type(x,t) type(x): return the type of the GEN x. *** at top-level: string() *** ^-------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: string(w,x) ===> plotstring(w,x) plotstring(w,x,{flags=0}): draw in rectwindow w the string corresponding to x. Bits 1 and 2 of flag regulate horizontal alignment: left if 0, right if 2, center if 1. Bits 4 and 8 regulate vertical alignment: bottom if 0, top if 8, v-center if 4. Can insert additional gap between point and string: horizontal if bit 16 is set, vertical if bit 32 is set. *** at top-level: texprint() *** ^---------- *** not a function in function call A function with that name existed in GP-1.39.15. Please update your script. New syntax: texprint(x) ===> printtex(x) printtex({str}*): outputs its string arguments in TeX format. Total time spent: 0 pari-2.11.2/src/test/32/list0000644000175000017500000000250013447371554014060 0ustar billbillList([1, 2, 3, 3, 5]) List([1, 1, 2, 3, 3]) List([1, 2, 3, 3, 1, 2, 3, 3]) List([1, 1, 2, 2, 3, 3, 3, 3]) List([1, 2, 3]) List([1, 2]) List([2]) List([[1, 2, 3], 2]) 3 List([[3, 2, 3], 2]) List([Vecsmall([1, 2, 3]), 2]) 3 [List([0])] List([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) List([10, 9, 8, 7, 6, 5]) List([]) List([1, y + 1]) List([y, x]) List([y, y*x]) 128 Mod(0, 1) Mod(1, 3) Mod(22, 30) List([0, 1]) List([1, 2, 3]) 1 2 List([2, 2, 3]) 3 List([3, 2, 3]) *** variable name expected: listpop(1) *** ^-- *** at top-level: L='L;listpop(L) *** ^---------- *** listpop: incorrect type in listpop (t_POL). *** at top-level: listput(L,1) *** ^------------ *** listput: incorrect type in listput (t_POL). *** at top-level: listinsert(L,1,1) *** ^----------------- *** listinsert: incorrect type in listinsert (t_POL). *** at top-level: L=Map();listpop(L) *** ^---------- *** listpop: incorrect type in listpop (t_LIST). *** at top-level: listput(L,1) *** ^------------ *** listput: incorrect type in listput (t_POL). *** at top-level: listinsert(L,1,1) *** ^----------------- *** listinsert: incorrect type in listinsert (t_POL). Total time spent: 8 pari-2.11.2/src/test/32/ellmodulareqn0000644000175000017500000000142513201017466015741 0ustar billbill[x^3 + 48*x^2 + (-y + 768)*x + 4096, 0] [x^12 + (-y + 744)*x^11 + 196680*x^10 + (187*y + 21354080)*x^9 + (506*y + 83 0467440)*x^8 + (-11440*y + 16875327744)*x^7 + (-57442*y + 208564958976)*x^6 + (184184*y + 1678582287360)*x^5 + (1675784*y + 9031525113600)*x^4 + (186771 2*y + 32349979904000)*x^3 + (-8252640*y + 74246810880000)*x^2 + (-19849600*y + 98997734400000)*x + (y^2 - 8720000*y + 58411072000000), 1] [y^4 + 36*y^3 + 270*y^2 + (-z + 756)*y + 729, 0] *** at top-level: ellmodulareqn(1) *** ^---------------- *** ellmodulareqn: not a prime number in ellmodulareqn (level): 1. *** at top-level: ellmodulareqn(2,y,x) *** ^-------------------- *** ellmodulareqn: incorrect priority in ellmodulareqn: variable y >= x Total time spent: 38 pari-2.11.2/src/test/32/lambert0000644000175000017500000000155713326135265014537 0ustar billbill *** at top-level: do(-1) *** ^------ *** in function do: my(x=lambertw(y));exp(x)*x/y *** ^----------------------- *** lambertw: domain error in Lw: y < 0 *** at top-level: do(I) *** ^----- *** in function do: my(x=lambertw(y));exp(x)*x/y *** ^----------------------- *** lambertw: sorry, lambert(t_COMPLEX) is not yet implemented. 1.0000000000000000000000000000000000000 0.99999999999999999999999999999999999999999999999999999999999999999999999999 9999999999999999999999999999999999999999999999999999999999999999999999999999 9999999999999999999999999999999999999999999999999999999999999 x - 2*x^2 + 8*x^3 - 52*x^4 + O(x^5) *** at top-level: lambertw(1/x) *** ^------------- *** lambertw: domain error in lambertw: valuation < 0 Total time spent: 7 pari-2.11.2/src/test/32/addprimes0000644000175000017500000000243613036414402015045 0ustar billbill[[0, 1, 210, 4, 4, 48, 16, 576, 65000, 10922688], [0, -1, 210000630, 5, 5, 4 8000096, 32, 576002304, 65000390000650000, 10922786304486912881835264], [0, 1, 210007560020790, 6, 6, 48001632003072, 64, 576021888078336, 6500468009724 0468000708500000, 10923867696016192486063520726766954883717632], [0, 0, 2100 06930, 6, 7, 48001776007968009216, 96, 576023616144576254592, 65005070125906 093564391733467296447350000, 10923966011120401354532760288014407980573122245 052972159937408], [0, -1, -210000630, 5, 5, 48000096, 32, 576002304, 6500039 0000650000, 10922786304486912881835264]] Testing 210, addprimes = [1000003] Testing 210000630, addprimes = [1000003] Testing 210007560020790, addprimes = [1000003] Testing 210008190043470062370, addprimes = [1000003] Testing -210000630, addprimes = [1000003] Testing 210, addprimes = [1000003, 1000033] Testing 210000630, addprimes = [1000003, 1000033] Testing 210007560020790, addprimes = [1000003, 1000033] Testing 210008190043470062370, addprimes = [1000003, 1000033] Testing -210000630, addprimes = [1000003, 1000033] Testing 210, addprimes = [1000033] Testing 210000630, addprimes = [1000033] Testing 210007560020790, addprimes = [1000033] Testing 210008190043470062370, addprimes = [1000033] Testing -210000630, addprimes = [1000033] [] [1009] Total time spent: 12 pari-2.11.2/src/test/32/lindep0000644000175000017500000000141113326135265014351 0ustar billbill[-1, -1, 1]~ [1, -2]~ [1, -2, 1]~ [y, y, -1, -y^2]~ x^2 + (-y^3 - y^2 - 5*y - 1) 0 (y - 1)*x + 1 x + (-5*y - 1) []~ [1]~ []~ []~ 1 *** at top-level: algdep(1,-1) *** ^------------ *** algdep: domain error in algdep: degree < 0 x^2 - 2 [Mod(0, E^3), Mod(0, E^3), Mod(0, E^3)]~ [-1, -1, 1]~ [-1, -1, 1]~ []~ *** at top-level: lindep([[1,0,0]~,[0,1,0],[1,1,0]]) *** ^---------------------------------- *** lindep: incorrect type in lindep (t_VEC). [-1, -1, 1]~ Mod(-2*t^3 - 2*t^2 - 1, t^4 + t^3 + t^2 + t + 1) Mod(t, t^4 + t^3 + t^2 + t + 1)*x + Mod(2*t^3 + 2*t^2 + 1, t^4 + t^3 + t^2 + t + 1) [Mod(t^2 + 2, t^4 + t^3 + t^2 + t + 1)] Mod(-x + 1, x^2 - 2) Mod(-2*x + 1, 4*x^2 - 2) Mod(3*x + 1, x^3 - 2) "t_FRAC" Total time spent: 4 pari-2.11.2/src/test/32/print0000644000175000017500000000021513457572662014246 0ustar billbill1:2:3:4 0 0 1:2:3:40 0 [1, 0; 0, 1] 0 [1, 0; 0, 1]0 [1 0] [0 1] 2 2 z z 2\*z 2*z 2 + 3\*z 2 + 3*z 2 + 3\*I 2 + 3*I Total time spent: 0 pari-2.11.2/src/test/32/help0000644000175000017500000001440013326135265014030 0ustar billbillx: user defined variable sin(x): sine of x. f = ()->1 echo: default echo: default log: default new is aliased to: sin(x): sine of x. test1 test2 test3 test4 new is aliased to: test2 does_not_exist: unknown identifier Help topics: for a list of relevant subtopics, type ?n for n in 0: user-defined functions (aliases, installed and user functions) 1: PROGRAMMING under GP 2: Standard monadic or dyadic OPERATORS 3: CONVERSIONS and similar elementary functions 4: functions related to COMBINATORICS 5: NUMBER THEORETICAL functions 6: POLYNOMIALS and power series 7: Vectors, matrices, LINEAR ALGEBRA and sets 8: TRANSCENDENTAL functions 9: SUMS, products, integrals and similar functions 10: General NUMBER FIELDS 11: Associative and central simple ALGEBRAS 12: ELLIPTIC CURVES 13: L-FUNCTIONS 14: MODULAR FORMS 15: MODULAR SYMBOLS 16: GRAPHIC functions 17: The PARI community Also: ? functionname (short on-line help) ?\ (keyboard shortcuts) ?. (member functions) Extended help (if available): ?? (opens the full user's manual in a dvi previewer) ?? tutorial / refcard / libpari (tutorial/reference card/libpari manual) ?? refcard-ell (or -lfun/-mf/-nf: specialized reference card) ?? keyword (long help text about "keyword" from the user's manual) ??? keyword (a propos: list of related functions). Member functions, followed by relevant objects a1-a6, b2-b8, c4-c6 : coeff. of the curve. ell area : area ell bid : big ideal bid, bnr bnf : big number field bnf,bnr clgp : class group bid, bnf,bnr cyc : cyclic decomposition (SNF) bid, clgp,ell, bnf,bnr diff, codiff: different and codifferent nf,bnf,bnr disc : discriminant ell,nf,bnf,bnr,rnf e, f : inertia/residue degree prid fu : fundamental units bnf,bnr gen : generators bid,prid,clgp,ell, bnf,bnr, gal group: group ell, gal index: index nf,bnf,bnr j : j-invariant ell mod : modulus bid, bnr, gal nf : number field nf,bnf,bnr,rnf no : number of elements bid, clgp,ell, bnf,bnr omega, eta: [w1,w2] and [eta1, eta2] ell orders: relative orders of generators gal p : rational prime prid, ell, rnf,gal pol : defining polynomial nf,bnf,bnr, gal polabs: defining polynomial over Q rnf reg : regulator bnf,bnr roots: roots ell,nf,bnf,bnr, gal sign,r1,r2 : signature nf,bnf,bnr t2 : t2 matrix nf,bnf,bnr tate : Tate's [u^2, u, q, [a,b], L, Ei] ell tu : torsion unit and its order bnf,bnr zk : integral basis nf,bnf,bnr,rnf zkst : structure of (Z_K/m)* bid, bnr # : enable/disable timer ## : print time for last result \\ : comment up to end of line \a {n} : print result in raw format (readable by PARI) \B {n} : print result in beautified format \c : list all commands (same effect as ?*) \d : print all defaults \e {n} : enable/disable echo (set echo=n) \g {n} : set debugging level \gf{n} : set file debugging level \gm{n} : set memory debugging level \h {m-n}: hashtable information \l {f} : enable/disable logfile (set logfile=f) \m {n} : print result in prettymatrix format \o {n} : set output method (0=raw, 1=prettymatrix, 2=prettyprint, 3=2-dim) \p {n} : change real precision \pb{n} : change real bit precision \ps{n} : change series precision \q : quit completely this GP session \r {f} : read in a file \s : print stack information \t : print the list of PARI types \u : print the list of user-defined functions \um : print the list of user-defined member functions \v : print current version of GP \w {nf} : write to a file \x {n} : print complete inner structure of result \y {n} : disable/enable automatic simplification (set simplify=n) {f}=optional filename. {n}=optional integer cmp divrem lex max min powers shift shiftmul sign vecmax vecmin test6 List of the PARI types: t_INT : long integers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ] t_REAL : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ] t_INTMOD : integermods [ code ] [ mod ] [ integer ] t_FRAC : irred. rationals [ code ] [ num. ] [ den. ] t_FFELT : finite field elt. [ code ] [ cod2 ] [ elt ] [ mod ] [ p ] t_COMPLEX: complex numbers [ code ] [ real ] [ imag ] t_PADIC : p-adic numbers [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ] t_QUAD : quadratic numbers [ cod1 ] [ mod ] [ real ] [ imag ] t_POLMOD : poly mod [ code ] [ mod ] [ polynomial ] ------------------------------------------------------------- t_POL : polynomials [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ] t_SER : power series [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ] t_RFRAC : irred. rat. func. [ code ] [ num. ] [ den. ] t_QFR : real qfb [ code ] [ a ] [ b ] [ c ] [ del ] t_QFI : imaginary qfb [ code ] [ a ] [ b ] [ c ] t_VEC : row vector [ code ] [ x_1 ] ... [ x_k ] t_COL : column vector [ code ] [ x_1 ] ... [ x_k ] t_MAT : matrix [ code ] [ col_1 ] ... [ col_k ] t_LIST : list [ cod1 ] [ cod2 ][ vec ] t_STR : string [ code ] [ man_1 ] ... [ man_k ] t_VECSMALL: vec. small ints [ code ] [ x_1 ] ... [ x_k ] t_CLOSURE: functions [ code ] [ arity ] [ code ] [ operand ] [ data ] [ te xt ] t_ERROR : error context [ code ] [ errnum ] [ dat_1 ] ... [ dat_k ] t_INFINITY: a*infinity [ code ] [ a ] f = ()->1 g = ()->0 Total time spent: 0 pari-2.11.2/src/test/32/pol0000644000175000017500000001201513326135265013672 0ustar billbillMod(0, 3) Mod(0, 3) Mod(0, 3) Mod(0, 3)*y^15 + O(y^16) Mod(0, 3)*x^15 + O(x^16) Mod(0, 3)*x^4 + O(x^5) y x x y + O(y^17) y + O(x^16) y + O(x^5) 0 0 0 y^-1 + O(y^15) 1/y + O(x^16) 1/y + O(x^5) y x x y^-1 + y + O(y^15) ((y^2 + 1)/y) + O(x^16) ((y^2 + 1)/y) + O(x^5) y^2 + 2*y + 3 x^2 + 2*x + 3 3*x^2 + 2*x + 1 1 + 2*y + 3*y^2 + O(y^3) 1 + 2*x + 3*x^2 + O(x^3) 1 + 2*x + 3*x^2 + O(x^5) y^2 + 2*y x^2 + 2*x 2*x + 1 1 + 2*y + O(y^3) 1 + 2*x + O(x^3) 1 + 2*x + O(x^5) y^2 + 2*y + 4 x^2 + 2*x + 4 4*x^2 + 2*x + 1 1 + 2*y + 4*y^2 + O(y^3) 1 + 2*x + 4*x^2 + O(x^3) 1 + 2*x + 4*x^2 + O(x^5) y^2 + 2*y - 4 x^2 + 2*x - 4 -4*x^2 + 2*x + 1 1 + 2*y - 4*y^2 + O(y^3) 1 + 2*x - 4*x^2 + O(x^3) 1 + 2*x - 4*x^2 + O(x^5) 2*y^2 + y 2*x^2 + x 2*x^2 + x y + 2*y^2 + O(y^4) (y + 2*y^2 + O(y^4)) + O(x^16) (y + 2*y^2 + O(y^4)) + O(x ^5) 2 2 3 y + 2 y + 2 2 + x + O(x^2) 1 1 x + 2 1 z y x^2 + x + 1 -x^3 - 2*x^2 - x + 1 [4, 0, 0, 0, -2]~ x^2 + 1 2 [0 -1/2] [1 0] 2*x^2 + x + 1 6*x^3 + 2*x^2 1:x^8 + 14*x^7 + 49*x^6 + 24*x^5 + 178*x^4 + 70*x^3 + 144*x^2 + 120*x + 25 2:x^8 + 7*x^7 + 49/4*x^6 + 24/7*x^5 + 29/2*x^4 + 35/4*x^3 + 144/49*x^2 + 30/ 7*x + 25/16 3:Mod(1, 11)*x^8 + Mod(3, 11)*x^7 + Mod(5, 11)*x^6 + Mod(2, 11)*x^5 + Mod(2, 11)*x^4 + Mod(4, 11)*x^3 + Mod(1, 11)*x^2 + Mod(10, 11)*x + Mod(3, 11) 4:x^8 + (8*a + 3)*x^7 + (6*a^2 + 10*a + 5)*x^6 + (a^3 + 8*a^2 + 8*a + 2)*x^5 + (4*a^4 + 6*a^3 + 9*a^2 + 10*a + 2)*x^4 + (5*a^4 + 2*a^3 + 8*a^2 + 7*a + 1 0)*x^3 + (2*a^4 + 5*a^3 + 4*a^2 + 2*a + 2)*x^2 + (a^4 + a^3 + 6)*x + (4*a^4 + 3*a^3 + 10*a^2 + 2*a + 8) 5:x^8 + x^6 + b^2*x^4 + b^4*x^2 + (b^8 + b^6 + 1) 6:Mod(1, y^3 - y - 1)*x^8 + Mod(8*y + 14, y^3 - y - 1)*x^7 + Mod(28*y^2 + 98 *y + 49, y^3 - y - 1)*x^6 + Mod(294*y^2 + 350*y + 80, y^3 - y - 1)*x^5 + Mod (805*y^2 + 680*y + 668, y^3 - y - 1)*x^4 + Mod(786*y^2 + 2238*y + 1106, y^3 - y - 1)*x^3 + Mod(2125*y^2 + 1535*y + 706, y^3 - y - 1)*x^2 + Mod(738*y^2 + 1626*y + 1232, y^3 - y - 1)*x + Mod(425*y^2 + 521*y + 184, y^3 - y - 1) 7:Mod(1, 7*y^3 - y - 1)*x^8 + Mod(8*y + 14, 7*y^3 - y - 1)*x^7 + Mod(28*y^2 + 98*y + 49, 7*y^3 - y - 1)*x^6 + Mod(294*y^2 + 302*y + 32, 7*y^3 - y - 1)*x ^5 + Mod(745*y^2 + 200*y + 248, 7*y^3 - y - 1)*x^4 + Mod(318*y^2 + 6462/7*y + 1478/7, 7*y^3 - y - 1)*x^3 + Mod(8509/7*y^2 + 2495/7*y + 1294/7, 7*y^3 - y - 1)*x^2 + Mod(13302/49*y^2 + 143046/343*y + 78800/343, 7*y^3 - y - 1)*x + Mod(59837/343*y^2 + 54281/343*y + 12532/343, 7*y^3 - y - 1) 8:Mod(1, y^3 - y - 1)*x^8 + Mod(8/3*y + 14, y^3 - y - 1)*x^7 + Mod(28/9*y^2 + 98/3*y + 49, y^3 - y - 1)*x^6 + Mod(98/3*y^2 + 2702/27*y + 704/27, y^3 - y - 1)*x^5 + Mod(6685/81*y^2 + 4780/81*y + 5296/27, y^3 - y - 1)*x^4 + Mod(80 06/243*y^2 + 68018/243*y + 25886/243, y^3 - y - 1)*x^3 + Mod(94033/729*y^2 + 65063/729*y + 112366/729, y^3 - y - 1)*x^2 + Mod(57226/2187*y^2 + 274114/21 87*y + 323060/2187, y^3 - y - 1)*x + Mod(120569/6561*y^2 + 98495/2187*y + 18 2168/6561, y^3 - y - 1) 9:Mod(1, 7*y^3 - y - 1)*x^8 + Mod(8/3*y + 14, 7*y^3 - y - 1)*x^7 + Mod(28/9* y^2 + 98/3*y + 49, 7*y^3 - y - 1)*x^6 + Mod(98/3*y^2 + 2654/27*y + 656/27, 7 *y^3 - y - 1)*x^5 + Mod(6625/81*y^2 + 3460/81*y + 4876/27, 7*y^3 - y - 1)*x^ 4 + Mod(6698/243*y^2 + 414002/1701*y + 127898/1701, 7*y^3 - y - 1)*x^3 + Mod (613057/5103*y^2 + 370439/5103*y + 741442/5103, 7*y^3 - y - 1)*x^2 + Mod(254 1982/107163*y^2 + 75020926/750141*y + 92863436/750141, 7*y^3 - y - 1)*x + Mo d(36748685/2250423*y^2 + 30522647/750141*y + 57101732/2250423, 7*y^3 - y - 1 ) 10:Mod(Mod(1, 11), Mod(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11))*x^8 + Mod(M od(8, 11)*y + Mod(3, 11), Mod(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11))*x^7 + Mod(Mod(6, 11)*y^2 + Mod(10, 11)*y + Mod(5, 11), Mod(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11))*x^6 + Mod(Mod(8, 11)*y^2 + Mod(5, 11)*y + Mod(10, 11), Mod(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11))*x^5 + Mod(Mod(8, 11)*y^2 + Mod (2, 11)*y + Mod(6, 11), Mod(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11))*x^4 + Mod(Mod(10, 11)*y^2 + Mod(7, 11)*y + Mod(10, 11), Mod(7, 11)*y^3 + Mod(10, 1 1)*y + Mod(10, 11))*x^3 + Mod(Mod(4, 11)*y^2 + Mod(6, 11)*y + Mod(1, 11), Mo d(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11))*x^2 + Mod(Mod(5, 11)*y^2 + Mod(1 , 11)*y + Mod(9, 11), Mod(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11))*x + Mod( Mod(4, 11)*y^2 + Mod(9, 11)*y + Mod(7, 11), Mod(7, 11)*y^3 + Mod(10, 11)*y + Mod(10, 11)) done Mod(-6, y^2 - 2)*x^2 + Mod(48*z, y^2 - 2)*x + Mod(480*z + 600, y^2 - 2) 1.4284266449676411750 1.4142277045794296914 "t_INT" *** polroots: Warning: normalizing a polynomial with 0 leading term. [0.E-38 + 0.E-38*I]~ *** polrootsbound: Warning: normalizing a polynomial with 0 leading term. 0 0 *** at top-level: polrootsbound(Pol(0)) *** ^--------------------- *** polrootsbound: zero polynomial in roots. *** at top-level: polrootsbound(1) *** ^---------------- *** polrootsbound: incorrect type in polrootsbound (t_INT). *** at top-level: Pol("") *** ^------- *** Pol: incorrect type in gtopoly (t_STR). *** at top-level: (1/x)%x *** ^-- *** _%_: impossible inverse in Flx_divrem: Vecsmall([0]). Total time spent: 4 pari-2.11.2/src/test/32/whatnow0000644000175000017500000000123613455107437014575 0ustar billbillThis function no longer exists New syntax: char(x,y) ===> charpoly(x,y) charpoly(A,{v='x},{flag=5}): det(v*Id-A)=characteristic polynomial of the matrix or polmod A. flag is optional and ignored unless A is a matrix; it ma y be set to 0 (Le Verrier), 1 (Lagrange interpolation), 2 (Hessenberg form), 3 (Berkowitz), 4 (modular) if A is integral, or 5 (default, choose best method ). Algorithms 0 (Le Verrier) and 1 (Lagrange) assume that n! is invertible, whe re n is the dimension of the matrix. This function did not change As far as I can recall, this function never existed New syntax: compimag(x,y) ===> x*y x*y: product of x and y. Total time spent: 0 pari-2.11.2/src/test/32/krasner0000644000175000017500000002007013326135265014545 0ustar billbill[[0, 1, 3, 0], [2, 3, 1, 2]] [[0, 1, 5, 0], [4, 5, 1, 4]] [[0, 1, 7, 0], [6, 7, 1, 6]] [[0, 1, 9, 0], [6, 3, 3, 6], [8, 9, 1, 8]] [[0, 1, 11, 0], [10, 11, 1, 10]] [[0, 1, 13, 0], [12, 13, 1, 12]] [[0, 1, 15, 0], [10, 3, 5, 10], [12, 5, 3, 12], [14, 15, 1, 14]] [[0, 1, 17, 0], [16, 17, 1, 16]] [[0, 1, 19, 0], [18, 19, 1, 18]] [[0, 1, 21, 0], [14, 3, 7, 14], [18, 7, 3, 18], [18, 7, 3, 18], [18, 7, 3, 1 8], [20, 21, 1, 20]] [[0, 1, 23, 0], [22, 23, 1, 22]] [[0, 1, 25, 0], [20, 5, 5, 20], [24, 25, 1, 24]] [[0, 1, 27, 0], [18, 3, 9, 18], [24, 9, 3, 24], [26, 27, 1, 26]] [[0, 1, 29, 0], [28, 29, 1, 28]] [[0, 1, 31, 0], [30, 31, 1, 30]] [[0, 1, 33, 0], [22, 3, 11, 22], [30, 11, 3, 30], [32, 33, 1, 32]] [[0, 1, 35, 0], [28, 5, 7, 28], [30, 7, 5, 30], [34, 35, 1, 34]] [[0, 1, 37, 0], [36, 37, 1, 36]] [[0, 1, 39, 0], [26, 3, 13, 26], [36, 13, 3, 36], [38, 39, 1, 38]] [[0, 1, 41, 0], [40, 41, 1, 40]] [[0, 1, 43, 0], [42, 43, 1, 42]] [[0, 1, 45, 0], [30, 3, 15, 30], [36, 5, 9, 36], [40, 9, 5, 40], [42, 15, 3, 42], [44, 45, 1, 44]] [[0, 1, 47, 0], [46, 47, 1, 46]] [[0, 1, 49, 0], [42, 7, 7, 42], [48, 49, 1, 48]] [[0, 1, 2, 0], [1, 2, 1, 1], [1, 2, 1, 1]] [[0, 1, 4, 0], [2, 2, 2, 2], [2, 2, 2, 2], [3, 4, 1, 3], [3, 4, 1, 3]] [[0, 1, 5, 0], [4, 5, 1, 4]] [[0, 1, 7, 0], [6, 7, 1, 6]] [[0, 1, 8, 0], [4, 2, 4, 4], [4, 2, 4, 4], [6, 4, 2, 6], [6, 4, 2, 6], [6, 4 , 2, 6], [7, 8, 1, 7], [7, 8, 1, 7]] [[0, 1, 10, 0], [5, 2, 5, 5], [5, 2, 5, 5], [8, 5, 2, 8], [9, 10, 1, 9], [9, 10, 1, 9]] [[0, 1, 11, 0], [10, 11, 1, 10]] [[0, 1, 13, 0], [12, 13, 1, 12]] [[0, 1, 14, 0], [7, 2, 7, 7], [7, 2, 7, 7], [12, 7, 2, 12], [13, 14, 1, 13], [13, 14, 1, 13]] [[0, 1, 16, 0], [8, 2, 8, 8], [8, 2, 8, 8], [12, 4, 4, 12], [12, 4, 4, 12], [12, 4, 4, 12], [14, 8, 2, 14], [14, 8, 2, 14], [14, 8, 2, 14], [14, 8, 2, 1 4], [14, 8, 2, 14], [15, 16, 1, 15], [15, 16, 1, 15]] [[0, 1, 17, 0], [16, 17, 1, 16]] [[0, 1, 19, 0], [18, 19, 1, 18]] [[0, 1, 20, 0], [10, 2, 10, 10], [10, 2, 10, 10], [15, 4, 5, 15], [15, 4, 5, 15], [16, 5, 4, 16], [16, 5, 4, 16], [18, 10, 2, 18], [18, 10, 2, 18], [19, 20, 1, 19], [19, 20, 1, 19]] [[0, 1, 22, 0], [11, 2, 11, 11], [11, 2, 11, 11], [20, 11, 2, 20], [21, 22, 1, 21], [21, 22, 1, 21]] [[0, 1, 23, 0], [22, 23, 1, 22]] [[0, 1, 25, 0], [20, 5, 5, 20], [24, 25, 1, 24]] [[0, 1, 26, 0], [13, 2, 13, 13], [13, 2, 13, 13], [24, 13, 2, 24], [25, 26, 1, 25], [25, 26, 1, 25]] [[0, 1, 28, 0], [14, 2, 14, 14], [14, 2, 14, 14], [21, 4, 7, 21], [21, 4, 7, 21], [24, 7, 4, 24], [26, 14, 2, 26], [26, 14, 2, 26], [27, 28, 1, 27], [27 , 28, 1, 27]] [[0, 1, 29, 0], [28, 29, 1, 28]] [[0, 1, 31, 0], [30, 31, 1, 30]] [[0, 1, 32, 0], [16, 2, 16, 16], [16, 2, 16, 16], [24, 4, 8, 24], [24, 4, 8, 24], [24, 4, 8, 24], [28, 8, 4, 28], [28, 8, 4, 28], [28, 8, 4, 28], [28, 8 , 4, 28], [28, 8, 4, 28], [30, 16, 2, 30], [30, 16, 2, 30], [30, 16, 2, 30], [30, 16, 2, 30], [30, 16, 2, 30], [31, 32, 1, 31], [31, 32, 1, 31]] [[0, 1, 34, 0], [17, 2, 17, 17], [17, 2, 17, 17], [32, 17, 2, 32], [33, 34, 1, 33], [33, 34, 1, 33]] [[0, 1, 35, 0], [28, 5, 7, 28], [30, 7, 5, 30], [34, 35, 1, 34]] [[0, 1, 37, 0], [36, 37, 1, 36]] [[0, 1, 38, 0], [19, 2, 19, 19], [19, 2, 19, 19], [36, 19, 2, 36], [37, 38, 1, 37], [37, 38, 1, 37]] [[0, 1, 40, 0], [20, 2, 20, 20], [20, 2, 20, 20], [30, 4, 10, 30], [30, 4, 1 0, 30], [30, 4, 10, 30], [32, 5, 8, 32], [32, 5, 8, 32], [35, 8, 5, 35], [35 , 8, 5, 35], [36, 10, 4, 36], [36, 10, 4, 36], [36, 10, 4, 36], [36, 10, 4, 36], [38, 20, 2, 38], [38, 20, 2, 38], [38, 20, 2, 38], [39, 40, 1, 39], [39 , 40, 1, 39]] [[0, 1, 41, 0], [40, 41, 1, 40]] [[0, 1, 43, 0], [42, 43, 1, 42]] [[0, 1, 44, 0], [22, 2, 22, 22], [22, 2, 22, 22], [33, 4, 11, 33], [33, 4, 1 1, 33], [40, 11, 4, 40], [42, 22, 2, 42], [42, 22, 2, 42], [43, 44, 1, 43], [43, 44, 1, 43]] [[0, 1, 46, 0], [23, 2, 23, 23], [23, 2, 23, 23], [44, 23, 2, 44], [45, 46, 1, 45], [45, 46, 1, 45]] [[0, 1, 47, 0], [46, 47, 1, 46]] [[0, 1, 49, 0], [42, 7, 7, 42], [48, 49, 1, 48]] [[0, 1, 50, 0], [25, 2, 25, 25], [25, 2, 25, 25], [40, 5, 10, 40], [45, 10, 5, 45], [45, 10, 5, 45], [48, 25, 2, 48], [49, 50, 1, 49], [49, 50, 1, 49]] [[0, 1, 105, 0], [70, 3, 35, 70], [84, 5, 21, 84], [90, 7, 15, 90], [90, 7, 15, 90], [90, 7, 15, 90], [98, 15, 7, 98], [100, 21, 5, 100], [102, 35, 3, 1 02], [102, 35, 3, 102], [102, 35, 3, 102], [104, 105, 1, 104]] [[0, 1, 21, 0], [14, 3, 7, 14], [18, 7, 3, 18], [20, 21, 1, 20]] [[0, 1, 75, 0], [50, 3, 25, 50], [60, 5, 15, 60], [70, 15, 5, 70], [72, 25, 3, 72], [74, 75, 1, 74]] [[0, 1, 18, 0], [9, 2, 9, 9], [9, 2, 9, 9], [12, 3, 6, 12], [12, 3, 6, 12], [15, 6, 3, 15], [15, 6, 3, 15], [16, 9, 2, 16], [16, 9, 2, 16], [17, 18, 1, 17], [17, 18, 1, 17]] [[12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 2, 4, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12 , 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 4, 2, 12], [12, 8, 1, 12], [12, 8, 1, 12], [12, 8, 1, 12], [12, 8, 1, 12], [12, 8, 1, 12], [12, 8, 1, 12]] [[0, 1, 30, 0], [15, 2, 15, 15], [15, 2, 15, 15], [20, 3, 10, 20], [20, 3, 1 0, 20], [20, 3, 10, 20], [24, 5, 6, 24], [24, 5, 6, 24], [24, 5, 6, 24], [25 , 6, 5, 25], [25, 6, 5, 25], [25, 6, 5, 25], [25, 6, 5, 25], [25, 6, 5, 25], [25, 6, 5, 25], [27, 10, 3, 27], [27, 10, 3, 27], [28, 15, 2, 28], [28, 15, 2, 28], [28, 15, 2, 28], [28, 15, 2, 28], [28, 15, 2, 28], [28, 15, 2, 28], [28, 15, 2, 28], [28, 15, 2, 28], [28, 15, 2, 28], [29, 30, 1, 29], [29, 30 , 1, 29], [29, 30, 1, 29], [29, 30, 1, 29], [29, 30, 1, 29], [29, 30, 1, 29] ] [[0, 1, 8, 0], [4, 2, 4, 4], [4, 2, 4, 4], [6, 4, 2, 6], [6, 4, 2, 6], [6, 4 , 2, 6], [6, 4, 2, 6], [7, 8, 1, 7], [7, 8, 1, 7], [7, 8, 1, 7], [7, 8, 1, 7 ]] [[0, 1, 2, 0], [1, 2, 1, 1], [1, 2, 1, 1]] 15 [[0, 1, 4, 0], [4, 2, 2, 4], [4, 2, 2, 4], [4, 2, 2, 4], [4, 2, 2, 4], [4, 4 , 1, 4], [6, 2, 2, 6], [6, 2, 2, 6], [6, 2, 2, 6], [6, 2, 2, 6], [6, 2, 2, 6 ], [6, 2, 2, 6], [6, 4, 1, 6], [6, 4, 1, 6], [6, 4, 1, 6], [8, 4, 1, 8], [8, 4, 1, 8], [8, 4, 1, 8], [8, 4, 1, 8], [8, 4, 1, 8], [8, 4, 1, 8], [8, 4, 1, 8], [8, 4, 1, 8], [9, 4, 1, 9], [9, 4, 1, 9], [9, 4, 1, 9], [9, 4, 1, 9], [ 9, 4, 1, 9], [9, 4, 1, 9], [9, 4, 1, 9], [9, 4, 1, 9], [10, 4, 1, 10], [10, 4, 1, 10], [10, 4, 1, 10], [10, 4, 1, 10], [10, 4, 1, 10], [10, 4, 1, 10], [ 10, 4, 1, 10], [10, 4, 1, 10], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11 ], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1 , 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11], [ 11, 4, 1, 11], [11, 4, 1, 11], [11, 4, 1, 11]] [0, 2] [x^3 + 10*x^2 + 34*x + 41, x^3 + 6*x + 24, x^3 + 18*x^2 + 12*x + 12, x^3 + 2 4*x^2 + 15, x^3 + 75*x^2 + 63*x + 60, x^3 + 12*x^2 + 36*x + 51, x^3 + 6*x^2 + 18*x + 66, x^3 + 54*x^2 + 18*x + 3, x^3 + 18*x + 69, x^3 + 18*x^2 + 72*x + 48] [x^5 + 26*x^4 + 271*x^3 + 167*x^2 + 598*x + 191, x^5 + 20*x^3 + 5*x^2 + 5*x + 20, x^5 + 20*x^2 + 15*x + 10, x^5 + 20*x^4 + 20*x^3 + 15*x^2 + 10*x + 20, x^5 + 20*x^4 + 10*x^3 + 10*x^2 + 20*x + 10, x^5 + 115*x^4 + 5*x^3 + 20*x^2 + 70, x^5 + 60*x^4 + 65*x^3 + 95*x^2 + 100*x + 60, x^5 + 90*x^4 + 115*x^3 + 6 5*x^2 + 100*x + 120, x^5 + 70*x^4 + 90*x^3 + 70*x^2 + 50*x + 5, x^5 + 20*x^4 + 105*x^3 + 75*x^2 + 30, x^5 + 45*x^4 + 30*x^3 + 25*x^2 + 100*x + 115, x^5 + 55*x^4 + 115*x^3 + 75*x^2 + 25*x + 45, x^5 + 120*x^4 + 90*x^3 + 100*x^2 + 10, x^5 + 570*x^4 + 50*x^3 + 225*x^2 + 475*x + 180, x^5 + 355*x^4 + 275*x^3 + 575*x^2 + 150*x + 360, x^5 + 585*x^4 + 600*x^3 + 175*x^2 + 575*x + 265, x^ 5 + 330*x^4 + 400*x^3 + 100*x^2 + 550*x + 615, x^5 + 65*x^4 + 175*x^3 + 275* x^2 + 325*x + 215, x^5 + 15*x^4 + 500*x^3 + 175*x^2 + 425*x + 310, x^5 + 535 *x^4 + 375*x^3 + 175*x^2 + 375*x + 340, x^5 + 180*x^4 + 475*x^3 + 450*x^2 + 125*x + 95, x^5 + 275*x^4 + 25*x^3 + 50*x^2 + 25*x + 460, x^5 + 525*x^4 + 55 0*x^3 + 125*x^2 + 125*x + 395, x^5 + 525*x^4 + 25*x^3 + 300*x^2 + 75*x + 570 , x^5 + 525*x^3 + 100*x^2 + 475*x + 20, x^5 + 300*x^4 + 400*x^3 + 400*x^2 + 150*x + 90] Total time spent: 1360 pari-2.11.2/src/test/32/interpol0000644000175000017500000000071213201017466014727 0ustar billbillx + 1 Mod(1, 7)*x + Mod(1, 7) Mod(1, 7) -1/6*x^2 + 3/2*x + 2/3 Mod(3, 7) 2.5416666666666666666666666666666666667 0.041666666666666666666666666666666666667 0 0 2 Mod(0, 2) Mod(0, 2) Mod(1, 2) [0, 0] [0, x] [0, y] [0, z] [0, 0] [0, 0] [0, x] [0, y] [0, z] [0, 0] [1, 0] [1, x] [1, y] [1, z] [1, 0] [x, x] [x, x] [x, x] [x, z] [x, x] [x, x] [x^2, x] [y*x, x] [x*z, z] [x*z + x, z] [-x + 1, x] [0, x] [-x + y, x] [z - x, z] [z + (-x + 1), z] Total time spent: 0 pari-2.11.2/src/test/32/ellseaJ0000644000175000017500000000010413326135265014453 0ustar billbill18784748 72057593931167604 72057594037928000 Total time spent: 1077 pari-2.11.2/src/test/32/nfeltsign0000644000175000017500000000102713326135265015072 0ustar billbill[-1, -1, -1, 1, 1] -1 [-1, -1, -1, 1] [1, 1, 1, 1] [-1, -1, -1, -1] 0 [-1, 1, 1, 1, 1] *** at top-level: nfeltsign(nf,a,3) *** ^----------------- *** nfeltsign: domain error in nfeltsign: index > 2 *** at top-level: nfeltsign(nf,a,[-1..1]) *** ^----------------------- *** nfeltsign: domain error in nfeltsign: index <= 0 *** at top-level: nfeltsign(nf,a,[1..3]) *** ^---------------------- *** nfeltsign: domain error in nfeltsign: index > 2 Total time spent: 4 pari-2.11.2/src/test/32/forperm0000644000175000017500000001162513326135265014560 0ustar billbillVecsmall([1]) Vecsmall([1, 2, 3, 4]) Vecsmall([1, 2, 4, 3]) Vecsmall([1, 3, 2, 4]) Vecsmall([1, 3, 4, 2]) Vecsmall([1, 4, 2, 3]) Vecsmall([1, 4, 3, 2]) Vecsmall([2, 1, 3, 4]) Vecsmall([2, 1, 4, 3]) Vecsmall([2, 3, 1, 4]) Vecsmall([2, 3, 4, 1]) Vecsmall([2, 4, 1, 3]) Vecsmall([2, 4, 3, 1]) Vecsmall([3, 1, 2, 4]) Vecsmall([3, 1, 4, 2]) Vecsmall([3, 2, 1, 4]) Vecsmall([3, 2, 4, 1]) Vecsmall([3, 4, 1, 2]) Vecsmall([3, 4, 2, 1]) Vecsmall([4, 1, 2, 3]) Vecsmall([4, 1, 3, 2]) Vecsmall([4, 2, 1, 3]) Vecsmall([4, 2, 3, 1]) Vecsmall([4, 3, 1, 2]) Vecsmall([4, 3, 2, 1]) Vecsmall([1, 1, 1, 3]) Vecsmall([1, 1, 3, 1]) Vecsmall([1, 3, 1, 1]) Vecsmall([3, 1, 1, 1]) Vecsmall([1, 2, 1, 3, 1, 4]) Vecsmall([1, 2, 1, 3, 4, 1]) Vecsmall([1, 2, 1, 4, 1, 3]) Vecsmall([1, 2, 1, 4, 3, 1]) Vecsmall([1, 2, 3, 1, 1, 4]) Vecsmall([1, 2, 3, 1, 4, 1]) Vecsmall([1, 2, 3, 4, 1, 1]) Vecsmall([1, 2, 4, 1, 1, 3]) Vecsmall([1, 2, 4, 1, 3, 1]) Vecsmall([1, 2, 4, 3, 1, 1]) Vecsmall([1, 3, 1, 1, 2, 4]) Vecsmall([1, 3, 1, 1, 4, 2]) Vecsmall([1, 3, 1, 2, 1, 4]) Vecsmall([1, 3, 1, 2, 4, 1]) Vecsmall([1, 3, 1, 4, 1, 2]) Vecsmall([1, 3, 1, 4, 2, 1]) Vecsmall([1, 3, 2, 1, 1, 4]) Vecsmall([1, 3, 2, 1, 4, 1]) Vecsmall([1, 3, 2, 4, 1, 1]) Vecsmall([1, 3, 4, 1, 1, 2]) Vecsmall([1, 3, 4, 1, 2, 1]) Vecsmall([1, 3, 4, 2, 1, 1]) Vecsmall([1, 4, 1, 1, 2, 3]) Vecsmall([1, 4, 1, 1, 3, 2]) Vecsmall([1, 4, 1, 2, 1, 3]) Vecsmall([1, 4, 1, 2, 3, 1]) Vecsmall([1, 4, 1, 3, 1, 2]) Vecsmall([1, 4, 1, 3, 2, 1]) Vecsmall([1, 4, 2, 1, 1, 3]) Vecsmall([1, 4, 2, 1, 3, 1]) Vecsmall([1, 4, 2, 3, 1, 1]) Vecsmall([1, 4, 3, 1, 1, 2]) Vecsmall([1, 4, 3, 1, 2, 1]) Vecsmall([1, 4, 3, 2, 1, 1]) Vecsmall([2, 1, 1, 1, 3, 4]) Vecsmall([2, 1, 1, 1, 4, 3]) Vecsmall([2, 1, 1, 3, 1, 4]) Vecsmall([2, 1, 1, 3, 4, 1]) Vecsmall([2, 1, 1, 4, 1, 3]) Vecsmall([2, 1, 1, 4, 3, 1]) Vecsmall([2, 1, 3, 1, 1, 4]) Vecsmall([2, 1, 3, 1, 4, 1]) Vecsmall([2, 1, 3, 4, 1, 1]) Vecsmall([2, 1, 4, 1, 1, 3]) Vecsmall([2, 1, 4, 1, 3, 1]) Vecsmall([2, 1, 4, 3, 1, 1]) Vecsmall([2, 3, 1, 1, 1, 4]) Vecsmall([2, 3, 1, 1, 4, 1]) Vecsmall([2, 3, 1, 4, 1, 1]) Vecsmall([2, 3, 4, 1, 1, 1]) Vecsmall([2, 4, 1, 1, 1, 3]) Vecsmall([2, 4, 1, 1, 3, 1]) Vecsmall([2, 4, 1, 3, 1, 1]) Vecsmall([2, 4, 3, 1, 1, 1]) Vecsmall([3, 1, 1, 1, 2, 4]) Vecsmall([3, 1, 1, 1, 4, 2]) Vecsmall([3, 1, 1, 2, 1, 4]) Vecsmall([3, 1, 1, 2, 4, 1]) Vecsmall([3, 1, 1, 4, 1, 2]) Vecsmall([3, 1, 1, 4, 2, 1]) Vecsmall([3, 1, 2, 1, 1, 4]) Vecsmall([3, 1, 2, 1, 4, 1]) Vecsmall([3, 1, 2, 4, 1, 1]) Vecsmall([3, 1, 4, 1, 1, 2]) Vecsmall([3, 1, 4, 1, 2, 1]) Vecsmall([3, 1, 4, 2, 1, 1]) Vecsmall([3, 2, 1, 1, 1, 4]) Vecsmall([3, 2, 1, 1, 4, 1]) Vecsmall([3, 2, 1, 4, 1, 1]) Vecsmall([3, 2, 4, 1, 1, 1]) Vecsmall([3, 4, 1, 1, 1, 2]) Vecsmall([3, 4, 1, 1, 2, 1]) Vecsmall([3, 4, 1, 2, 1, 1]) Vecsmall([3, 4, 2, 1, 1, 1]) Vecsmall([4, 1, 1, 1, 2, 3]) Vecsmall([4, 1, 1, 1, 3, 2]) Vecsmall([4, 1, 1, 2, 1, 3]) Vecsmall([4, 1, 1, 2, 3, 1]) Vecsmall([4, 1, 1, 3, 1, 2]) Vecsmall([4, 1, 1, 3, 2, 1]) Vecsmall([4, 1, 2, 1, 1, 3]) Vecsmall([4, 1, 2, 1, 3, 1]) Vecsmall([4, 1, 2, 3, 1, 1]) Vecsmall([4, 1, 3, 1, 1, 2]) Vecsmall([4, 1, 3, 1, 2, 1]) Vecsmall([4, 1, 3, 2, 1, 1]) Vecsmall([4, 2, 1, 1, 1, 3]) Vecsmall([4, 2, 1, 1, 3, 1]) Vecsmall([4, 2, 1, 3, 1, 1]) Vecsmall([4, 2, 3, 1, 1, 1]) Vecsmall([4, 3, 1, 1, 1, 2]) Vecsmall([4, 3, 1, 1, 2, 1]) Vecsmall([4, 3, 1, 2, 1, 1]) Vecsmall([4, 3, 2, 1, 1, 1]) Vecsmall([1, 2, 3, 2, 3]) Vecsmall([1, 2, 3, 3, 2]) Vecsmall([1, 3, 2, 2, 3]) Vecsmall([1, 3, 2, 3, 2]) Vecsmall([1, 3, 3, 2, 2]) Vecsmall([2, 1, 2, 3, 3]) Vecsmall([2, 1, 3, 2, 3]) Vecsmall([2, 1, 3, 3, 2]) Vecsmall([2, 2, 1, 3, 3]) Vecsmall([2, 2, 3, 1, 3]) Vecsmall([2, 2, 3, 3, 1]) Vecsmall([2, 3, 1, 2, 3]) Vecsmall([2, 3, 1, 3, 2]) Vecsmall([2, 3, 2, 1, 3]) Vecsmall([2, 3, 2, 3, 1]) Vecsmall([2, 3, 3, 1, 2]) Vecsmall([2, 3, 3, 2, 1]) Vecsmall([3, 1, 2, 2, 3]) Vecsmall([3, 1, 2, 3, 2]) Vecsmall([3, 1, 3, 2, 2]) Vecsmall([3, 2, 1, 2, 3]) Vecsmall([3, 2, 1, 3, 2]) Vecsmall([3, 2, 2, 1, 3]) Vecsmall([3, 2, 2, 3, 1]) Vecsmall([3, 2, 3, 1, 2]) Vecsmall([3, 2, 3, 2, 1]) Vecsmall([3, 3, 1, 2, 2]) Vecsmall([3, 3, 2, 1, 2]) Vecsmall([3, 3, 2, 2, 1]) Vecsmall([]) Vecsmall([]) Vecsmall([]) Vecsmall([1]) *** variable name expected: forperm(p,3,) *** ^--- *** at top-level: forperm(1.0,q,) *** ^--------------- *** incorrect type in forperm (t_REAL). *** at top-level: forperm(-1,q,) *** ^-------------- *** domain error in forperm: a < 0 *** at top-level: permsign(Vecsmall([1,1])) *** ^------------------------- *** permsign: incorrect type in permsign (t_VECSMALL). *** at top-level: permsign(Vecsmall([1,2,1])) *** ^--------------------------- *** permsign: incorrect type in permsign (t_VECSMALL). *** at top-level: permorder(Vecsmall([1,2,1])) *** ^---------------------------- *** permorder: incorrect type in permorder (t_VECSMALL). Total time spent: 1 pari-2.11.2/src/test/32/sumdedekind0000644000175000017500000000015413036414402015364 0ustar billbill-1/18 0 1145846923/57826382 56713727820156410558782357164918483627/73786976294838206464 Total time spent: 4 pari-2.11.2/src/test/32/rnfkummer0000644000175000017500000001266213455133537015121 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). 1 x^3 + (76444126945687692063*y^3 + 95851038938815977768*y^2 + 116634231131091 141384*y - 106704642703262169792)*x + (6952769785407333647049967168852088370 36*y^3 + 1295719319620829728106935660641332757336*y^2 - 63164151046984158739 666320128496887188752*y + 34408889837655961514790658273160305237139) 2 x^3 + (-455492756088*y^3 + 72746635392*y^2 + 30103312785*y - 532729124469)*x + (-4059137465271111971*y^3 + 652777677080133659*y^2 + 262952422699146889*y - 4742293189040084766) 3 x^5 + (338906430826501923385346607707925/229919*y^3 - 1457798214872402183464 6220260998400/229919*y^2 - 202240490266682646928234413452546325/229919*y + 9 311818671232806283499820722904784405/229919)*x^3 + (-97462976500434619194588 15391166956054900191851407121368976375225/229919*y^3 + 419234752507246797754 440638037503934193147867526951273244896871800/229919*y^2 + 58160478163139363 18046410689887796592739326364262547764388484603275/229919*y - 26779001130318 2612612928927273255972900605400487205732555912057079030/229919)*x + (1383785 9122129794978630768313810944358518067010816386533939954568750960963976700/22 9919*y^3 - 59523232848017545627423707739853544444403314870247075668056585441 8672632321333000/229919*y^2 - 8257663906803008790492508500548575219481689071 133261565693002578393264223628510850/229919*y + 3802100637374297497910983850 11734464444507295841035234635984867875452558433080616962/229919) 4 x^5 + 110*x^3 - 385*x^2 + (-6875*y + 13310)*x + (20625*y + 32197) 5 x^5 + 3004517690*x^3 - 28917505076965983010807657580*x^2 - 80540351781678421 251251538235548863606045415*x + 31011472834856538584168163496443071927439210 5424319898991797804 6 x^3 + (6*y^4 - 6*y^3 + 6*y^2 - 6*y - 6)*x + (18*y^5 + 22*y^3 + 16*y^2 + 6*y + 2) 7 x^5 + (2651242035378*y^3 - 19026571842162*y^2 - 1328864307738*y + 9599617228 842)*x^3 + (1712487057528900654*y^3 - 12288891104244105681*y^2 - 86409097333 0321014*y + 6204301708161644826)*x^2 + (-1216197570148265224343471268*y^3 + 8727444064045036976185700532*y^2 + 614061119514588005662379478*y - 440650773 9442330907873247837)*x + (425688179509323393377701476368304/5*y^3 - 30547419 81935414899843123526195601/5*y^2 - 214930997073938684850136225507314/5*y + 1 542346655886842489025149662914996/5) 8 x^3 + (22049832980412*y - 801716887536675)*x + (321027751930293073102*y - 11 672350095308584241844) 9 [x^3 + (22049832980412*y - 801716887536675)*x + (321027751930293073102*y - 1 1672350095308584241844), x^3 + (22049832980412*y - 801716887536675)*x + (639 42266560265436863*y - 2324897198735088205455), x^3 + (22049832980412*y - 801 716887536675)*x + (257085485370027636239*y - 9347452896573496036389), x^3 - 3*x - 1] 10 x^5 - 10*x^3 + 20*x + 10 11 x^5 + (29680475428049860/9*y^3 + 34921354500260180/9*y^2 - 15477290427050761 40/3*y - 2577261173805358400)*x^3 + (-12081003902993919799182130/81*y^3 - 14 214245862026090743389440/81*y^2 + 629980400564212569840119770/27*y + 1165595 99110534944226492390)*x^2 + (-41713649969867415576551797389166070/27*y^3 - 4 9079370978551972052667611917864830/27*y^2 + 21752150855081820680445678911540 81150/9*y + 1207381363290003193446783411707755890)*x + (-1624409998713015666 0037949992862545643869538/81*y^3 - 19112453838427485951263179674887910269786 026/81*y^2 + 847070715893511796620187790773814796016991384/27*y + 1567258647 31306991463206177661754686074438714) 12 x^5 + (-81813555181352222150051800*y - 758707698512046332750174210)*x^3 + (- 694598776821165938962621533366567137400*y - 64414440636774569791913727277961 95123620)*x^2 + (3651173928959564866042051164348807026764233927500600*y + 33 859594077871137466555125791674382870971097682845385)*x + (349451144213144157 2099292477440773615835215850460100567473586200*y + 3240676594247150121910798 3039126788636208628338965287209013744796) 13 x^2 + (579005994260871660725675138161827610313714425601379330908*y^5 - 10665 838767241026781798972314566336490960682839047298886121*y^4 - 125451512411576 00984519055919161910715239885311867631785451*y^3 - 1073834268336903398192739 1139740391065234975927048788721099*y^2 - 14903158824521475429243429293262572 511122641600774314257887*y - 14998783880299450494129067945527908842599620490 145975145023) 14 1 15 x^2 + (-53140587696485690121168112086566519*y^5 - 98157358121814711167092564 297381805*y^4 - 1913471778408690519143587422326674*y^3 - 2075566936738425347 3741951752946058*y^2 - 12577008858253013499052611584073889*y - 8328381136606 8509872924242423547922) 16 x^2 + (8*y - 109) 17 x^2 - 5 18 x^3 + (-141*y^3 + 606*y^2 + 3507*y - 28437)*x + (-2491925/2*y^3 + 7854942*y^ 2 + 11241975/2*y - 165098584) 19 [x^3 - 3*x - 1] 20 x^3 - 3*x - 1 [] 21 x^5 - 10*x^3 + 5*x^2 + 10*x + 1 x^2 + (24/5*y^3 + 29/5*y^2 - 1329/5*y - 2344/5) x^2 + (-4*y^2 + 12*y - 13) x^2 + (-39*y - 78) [x^2 - 2, x^2 + (-2/3*y^5 - 4/3*y^2 + 2/3*y - 2/3), x^2 + (-4*y^6 + 2/3*y^5 - 86/3*y^2 + 100/3*y - 100/3), x^2 + (-2/3*y^4 - 4/3*y^3 - 2/3*y^2 - 2/3*y - 8/3), x^2 + (4/3*y^6 + 2/3*y^5 - 4/3*y^4 - 2*y^3 + 26/3*y^2 - 8/3*y - 2/3), x^2 + (-2/3*y^4 - 4/3*y^3 - 2/3*y^2 + 4/3*y - 2/3), x^2 + (-2/3*y^6 + 2/3*y ^4 - 14/3*y^2 + 6*y - 16/3), x^2 + (-2*y^6 - 14*y^2 + 14*y - 14), x^2 + (-1/ 3*y^5 - 2/3*y^2 + 1/3*y - 1/3), x^2 + (-1/3*y^4 - 2/3*y^3 - 1/3*y^2 - 1/3*y - 4/3), x^2 + (-1/3*y^4 - 2/3*y^3 - 1/3*y^2 + 2/3*y - 1/3), x^2 + (-y^6 - 7* y^2 + 7*y - 7), x^2 + (-2*y^6 + 1/3*y^5 - 43/3*y^2 + 50/3*y - 50/3), x^2 + ( -1/3*y^6 + 1/3*y^4 - 7/3*y^2 + 3*y - 8/3), x^2 + (2/3*y^6 + 1/3*y^5 - 2/3*y^ 4 - y^3 + 13/3*y^2 - 4/3*y - 1/3)] x^2 - 3 Total time spent: 4468 pari-2.11.2/src/test/32/io0000644000175000017500000000372313326135265013515 0ustar billbill["123", "456", "a7b", "\\frac{1}{2}"] [1, 3] 1 setting x setting y y List([]) 2 ["1+1"] 1:1 2:2 3:3 4:4 5:5 6:6 7:7 8:8 9:9 10:10 11:12345678910 1:1 2:2 3:3 4:4 5:5 6:6 7:7 8:8 9:9 10:10 11:12345678910 *** at top-level: ...ileopen(F));fileclose(f);fileread(f) *** ^----------- *** fileread: invalid file descriptor in fileread [0] *** at top-level: ...ileopen(F));fileclose(f);filereadstr(f) *** ^-------------- *** filereadstr: invalid file descriptor in filereadstr [0] *** at top-level: ...ileopen(F));fileclose(f);filewrite(f,"b") *** ^---------------- *** filewrite: invalid file descriptor in filewrite [0] *** at top-level: ...ileopen(F));fileclose(f);filewrite1(f,"b") *** ^----------------- *** filewrite1: invalid file descriptor in filewrite1 [0] *** at top-level: ...ileopen(F));fileclose(f);fileflush(f) *** ^------------ *** fileflush: invalid file descriptor in fileflush [0] *** at top-level: my(f=fileopen(F,"w"));fileread(f) *** ^----------- *** fileread: invalid file descriptor in fileread [0] *** at top-level: my(f=fileopen(F,"a"));filereadstr(f) *** ^-------------- *** filereadstr: invalid file descriptor in fileread [0] *** at top-level: my(f=fileopen(F));filewrite(f,"b") *** ^---------------- *** filewrite: invalid file descriptor in filewrite [0] *** at top-level: my(f=fileopen(F,"r"));filewrite1(f,"b") *** ^----------------- *** filewrite1: invalid file descriptor in filewrite1 [0] *** at top-level: fileflush('x) *** ^------------- *** fileflush: incorrect type in fileflush (t_POL). Total time spent: 2 pari-2.11.2/src/test/32/lex0000644000175000017500000000055113326135265013672 0ustar billbill[1, 1, 0] [1, 2, -1] [1, 3, -1] [1, 4, -1] [1, 5, -1] [1, 6, -1] [1, 7, -1] [2, 2, 0] [2, 3, 1] [2, 4, 1] [2, 5, 1] [2, 6, 1] [2, 7, 1] [3, 3, 0] [3, 4, -1] [3, 5, 1] [3, 6, -1] [3, 7, -1] [4, 4, 0] [4, 5, 1] [4, 6, 1] [4, 7, -1] [5, 5, 0] [5, 6, -1] [5, 7, -1] [6, 6, 0] [6, 7, -1] [7, 7, 0] -1 -1 1 -1 -1 0 1 1 -1 -1 1 -1 -1 1 -1 1 1 1 -1 Total time spent: 4 pari-2.11.2/src/test/32/parallel0000644000175000017500000000456313447371554014714 0ustar billbill[[1238926361552897, 1; 93461639715357977769163558199606896584051237541638188 580280321, 1], [13821503, 1; 61654440233248340616559, 1; 1473226532114531733 1353282383, 1]] [[1238926361552897, 1; 93461639715357977769163558199606896584051237541638188 580280321, 1], [13821503, 1; 61654440233248340616559, 1; 1473226532114531733 1353282383, 1]] [[1238926361552897, 1; 93461639715357977769163558199606896584051237541638188 580280321, 1], [13821503, 1; 61654440233248340616559, 1; 1473226532114531733 1353282383, 1]] 188 Vecsmall([188, 722, 752]) [414951556888099295851240786369116115101244623224243689999565732969065281141 2908146399707048947103794288197886611300789182395151075411775307886874834113 963687061181803401509523685563, 41495155688809929585124078636911611510124462 3224243689999565732969065281141290814639970704894710379428819788661130078918 2395151075411775307886874834113963687061181803401509523686097, 4149515568880 9929585124078636911611510124462322424368999956573296906528114129081463997070 4894710379428819788661130078918239515107541177530788687483411396368706118180 3401509523686127] Vecsmall([188, 722, 752]) Vecsmall([188, 722, 752]) [414951556888099295851240786369116115101244623224243689999565732969065281141 2908146399707048947103794288197886611300789182395151075411775307886874834113 963687061181803401509523685563, 41495155688809929585124078636911611510124462 3224243689999565732969065281141290814639970704894710379428819788661130078918 2395151075411775307886874834113963687061181803401509523686097, 4149515568880 9929585124078636911611510124462322424368999956573296906528114129081463997070 4894710379428819788661130078918239515107541177530788687483411396368706118180 3401509523686127] [188, 1] [414951556888099295851240786369116115101244623224243689999565732969065281141 2908146399707048947103794288197886611300789182395151075411775307886874834113 963687061181803401509523685563, 41495155688809929585124078636911611510124462 3224243689999565732969065281141290814639970704894710379428819788661130078918 2395151075411775307886874834113963687061181803401509523686097, 4149515568880 9929585124078636911611510124462322424368999956573296906528114129081463997070 4894710379428819788661130078918239515107541177530788687483411396368706118180 3401509523686127] -23 3 7432339208719 7432339208719 [75, 85070591730234615858594180193637120807] 4037913 4037913 122000794103870768 36 65 85 Total time spent: 37648 pari-2.11.2/src/test/32/solve0000644000175000017500000000236313201017466014227 0ustar billbill14.134725141734693790457251983562470271 [14.134725141734693790457251983562470271, 21.0220396387715549926284795938969 02777, 25.010857580145688763213790992562821819, 30.4248761258595132103118975 30584091320, 32.935061587739189690662368964074903489, 37.5861781588256712572 17763480705332822, 40.918719012147495187398126914633254396, 43.3270732809149 99519496122165406805783, 48.005150881167159727942472749427516042, 49.7738324 77672302181916784678563724058, 52.970321477714460644147296608880990064, 56.4 46247697063394804367759476706127553, 59.347044002602353079653648674992219031 , 60.831778524609809844259901824524003803, 65.112544048081606660875054253183 705029, 67.079810529494173714478828896522216771, 69.546401711173979252926857 526554738443, 72.067157674481907582522107969826168390, 75.704690699083933168 326916762030345923, 77.144840068874805372682664856304637016, 79.337375020249 367922763592877116228190, 82.910380854086030183164837494770609498, 84.735492 980517050105735311206827741417, 87.425274613125229406531667850919213252, 88. 809111207634465423682348079509378395, 92.49189927055848429625972524181068487 9, 94.651344040519886966597925815208153938, 95.87063422824530975874102921924 6781695, 98.831194218193692233324420138622327821] Total time spent: 120 pari-2.11.2/src/test/32/iterator0000644000175000017500000000540713457566440014750 0ustar billbill18446744073709551614 18446744073709551615 18446744073709551616 18446744073709551617 18446744073709551618 -18446744073709551618 -18446744073709551617 -18446744073709551616 -18446744073709551615 -18446744073709551614 2 3 4 5 6 7 8 9 10 4294967279 4294967291 4294967311 18446744073709551557 18446744073709551629 18446744073709551653 2 3 5 7 2 3 5 7 1267650600228229401496703205653 1267650600228229401496703205707 1267650600228229401496703205653 1267650600228229401496703205707 2 3 4294967311 18446744073709551557 18446744073709551629 18446744073709551653 2 7 17 2 7 17 1267650600228229401496703205653 1267650600228229401496703205707 1267650600228229401496703205653 1267650600228229401496703205707 18446744073709551533 18446744073709551653 18446744073709551923 0.50000000000000000000000000000000000000 1.5000000000000000000000000000000000000 2.5000000000000000000000000000000000000 3 6 9 12 5 3 1 1 2 5 6 9 10 2 5 8 210 *** at top-level: forprime(p=2,10,p=4) *** ^-- *** prime index read-only: was changed to 4. 4 10 4 6 8 9 10 6 8 9 10 6 8 9 10 12 6 8 9 6 8 9 6 *** at top-level: forcomposite(a=6,12,print(a);a=1) *** ^------------- *** index read-only: was changed to 1. [1, 5] [1, 6] [1, 7] [1, 8] [2, 5] [2, 7] [2, 8] [3, 5] [4, 5] [100000, [2, 5; 5, 5]] [100001, [11, 1; 9091, 1]] [100002, [2, 1; 3, 1; 7, 1; 2381, 1]] [100003, Mat([100003, 1])] [100004, [2, 2; 23, 1; 1087, 1]] [100005, [3, 1; 5, 1; 59, 1; 113, 1]] [100006, [2, 1; 31, 1; 1613, 1]] [100007, [97, 1; 1031, 1]] [100008, [2, 3; 3, 3; 463, 1]] [100009, [7, 2; 13, 1; 157, 1]] [100010, [2, 1; 5, 1; 73, 1; 137, 1]] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-1, Mat([-1, 1])] [-3, [-1, 1; 3, 1]] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-1, Mat([-1, 1])] [0, Mat([0, 1])] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-1, Mat([-1, 1])] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-1, Mat([-1, 1])] [0, Mat([0, 1])] [1, matrix(0,2)] [2, Mat([2, 1])] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-1, Mat([-1, 1])] [-3, [-1, 1; 3, 1]] [-2, [-1, 1; 2, 1]] [-1, Mat([-1, 1])] [0, Mat([0, 1])] [0, Mat([0, 1])] [1, matrix(0,2)] [2, Mat([2, 1])] [0, Mat([0, 1])] [100001, [11, 1; 9091, 1]] [100002, [2, 1; 3, 1; 7, 1; 2381, 1]] [100003, Mat([100003, 1])] [100005, [3, 1; 5, 1; 59, 1; 113, 1]] [100006, [2, 1; 31, 1; 1613, 1]] [100007, [97, 1; 1031, 1]] [100010, [2, 1; 5, 1; 73, 1; 137, 1]] [-100010, [-1, 1; 2, 1; 5, 1; 73, 1; 137, 1]] [-100007, [-1, 1; 97, 1; 1031, 1]] [-100006, [-1, 1; 2, 1; 31, 1; 1613, 1]] [-100005, [-1, 1; 3, 1; 5, 1; 59, 1; 113, 1]] [-100003, [-1, 1; 100003, 1]] [-100002, [-1, 1; 2, 1; 3, 1; 7, 1; 2381, 1]] [-100001, [-1, 1; 11, 1; 9091, 1]] 607926 607926 Total time spent: 5114 pari-2.11.2/src/test/32/contfrac0000644000175000017500000000200213326135265014672 0ustar billbill *** at top-level: contfrac(1,[],-1) *** ^----------------- *** contfrac: domain error in contfrac: nmax < 0 *** at top-level: contfracpnqn(Vecsmall([])) *** ^-------------------------- *** contfracpnqn: incorrect type in pnqn (t_VECSMALL). [1 0] [0 1] [;] [;] [2 1] [1 0] [2] [1] [2] [1] [10 3] [ 7 2] [1] [1] [1 3] [1 2] [1 3 10] [1 2 7] [144 22] [ 33 5] [4] [1] [4 22] [1 5] [4 22 144] [1 5 33] [[], []] [[-1], []] [[-1], [1/2]] [[], []] 0 [[-1, 1/3, 1/15, 1/35, 1/63, 1/99, 1/143, 1/195], [1/2, 1/36, 1/100, 1/196, 1/324, 1/484, 1/676, 1/900]] *** at top-level: contfraceval(e,1,10) *** ^-------------------- *** contfraceval: non-existent component in contfraceval: index > 8 410105312/150869313 517656/190435 410105312/150869313 [[-2], [1]] [[], []] *** at top-level: contfracinit(1) *** ^--------------- *** contfracinit: incorrect type in contfracinit (t_INT). Total time spent: 0 pari-2.11.2/src/test/32/asymp0000644000175000017500000000230513326135265014232 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). realprecision = 115 significant digits -oo -92 -oo -oo -oo [1, 1/12, 1/288, -139/51840, -571/2488320, 163879/209018880, 5246819/7524679 6800, -534703531/902961561600, -4483131259/86684309913600, 432261921612371/5 14904800886784000, 6232523202521089/86504006548979712000, -25834629665134204 969/13494625021640835072000, -1579029138854919086429/97161300155814012518400 00, 746590869962651602203151/116593560186976815022080000, 151151360102809790 3631961/2798245444487443560529920000, -8849272268392873147705987190261/29969 2087104605205332754432000000, -142801712490607530608130701097701/57540880724 084199423888850944000000] [0, 1, -1/2, 1/3, -1/4, 1/5, -1/6, 1/7, -1/8, 1/9, -1/10, 1/11, -1/12, 1/13, -1/14, 1/15, -1/16] [0, 1, -1/2, 1/3, -1/4, 1/5, -1/6, 1/7, -1/8, 1/9, -1/10, 1/11, -1/12, 1/13, -1/14, 1/15, -1/16] [1, 0, -1/6, 0, 1/120, 0, -1/5040, 0, 1/362880, 0, -1/39916800, 0, 1/6227020 800, 0, -1/1307674368000, 0] realprecision = 38 significant digits 1.0000000000000000000000000000000000000 -27 [0, -5/48, -7/64, -81/5120, -3/2048] [0, 1/12, 0, -1/360, 0, 1/1260, 0, -1/1680, 0, 1/1188, 0, -691/360360, 0, 1/ 156, 0] [] Total time spent: 247 pari-2.11.2/src/test/32/number0000644000175000017500000001302013326135265014365 0ustar billbill echo = 1 ? addprimes([nextprime(10^9),nextprime(10^10)]) [1000000007, 10000000019] ? bestappr(Pi,10000) 355/113 ? gcdext(123456789,987654321) [-8, 1, 9] ? bigomega(12345678987654321) 8 ? binomial(1.1,5) -0.0045457500000000000000000000000000000001 ? chinese(Mod(7,15),Mod(13,21)) Mod(97, 105) ? content([123,456,789,234]) 3 ? contfrac(Pi) [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, 1, 84, 2, 1 , 1, 15, 3, 13, 1, 4, 2, 6, 6] ? contfrac(Pi,5) [3, 7, 15, 1, 292] ? contfrac((exp(1)-1)/(exp(1)+1),[1,3,5,7,9]) [0, 6, 10, 42, 30] ? contfracpnqn([2,6,10,14,18,22,26]) [19318376 741721] [ 8927353 342762] ? contfracpnqn([1,1,1,1,1,1,1,1;1,1,1,1,1,1,1,1]) [34 21] [21 13] ? core(54713282649239) 5471 ? core(54713282649239,1) [5471, 100003] ? coredisc(54713282649239) 21884 ? coredisc(54713282649239,1) [21884, 100003/2] ? divisors(8!) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 28, 30, 32, 35, 36, 40, 42, 45, 48, 56, 60, 63, 64, 70, 72, 80, 84, 90, 96, 105, 112, 12 0, 126, 128, 140, 144, 160, 168, 180, 192, 210, 224, 240, 252, 280, 288, 315 , 320, 336, 360, 384, 420, 448, 480, 504, 560, 576, 630, 640, 672, 720, 840, 896, 960, 1008, 1120, 1152, 1260, 1344, 1440, 1680, 1920, 2016, 2240, 2520, 2688, 2880, 3360, 4032, 4480, 5040, 5760, 6720, 8064, 10080, 13440, 20160, 40320] ? eulerphi(257^2) 65792 ? factor(17!+1) [ 661 1] [ 537913 1] [1000357 1] ? factor(100!+1,0) [101 1] [14303 1] [149239 1] [432885273849892962613071800918658949059679308685024481795740765527568493010 727023757461397498800981521440877813288657839195622497225621499427628453 1] ? factor(40!+1,100000) [ 41 1] [ 59 1] [ 277 1] [1217669507565553887239873369513188900554127 1] ? factorback(factor(12354545545)) 12354545545 ? factor(230873846780665851254064061325864374115500032^6) [ 2 120] [ 3 6] [ 7 6] [ 23 6] [ 29 6] [500501 36] ? factorcantor(x^11+1,7) [Mod(1, 7)*x + Mod(1, 7) 1] [Mod(1, 7)*x^10 + Mod(6, 7)*x^9 + Mod(1, 7)*x^8 + Mod(6, 7)*x^7 + Mod(1, 7)* x^6 + Mod(6, 7)*x^5 + Mod(1, 7)*x^4 + Mod(6, 7)*x^3 + Mod(1, 7)*x^2 + Mod(6, 7)*x + Mod(1, 7) 1] ? centerlift(lift(factormod(x^3+x^2+x-1,[3,t^3+t^2+t-1]))) [ x - t 1] [x + (t^2 + t - 1) 1] [ x + (-t^2 - 1) 1] ? 10! 3628800 ? factorial(10) 3628800.0000000000000000000000000000000 ? factormod(x^11+1,7) [Mod(1, 7)*x + Mod(1, 7) 1] [Mod(1, 7)*x^10 + Mod(6, 7)*x^9 + Mod(1, 7)*x^8 + Mod(6, 7)*x^7 + Mod(1, 7)* x^6 + Mod(6, 7)*x^5 + Mod(1, 7)*x^4 + Mod(6, 7)*x^3 + Mod(1, 7)*x^2 + Mod(6, 7)*x + Mod(1, 7) 1] ? factormod(x^11+1,7,1) [ 1 1] [10 1] ? setrand(1);ffinit(2,11) Mod(1, 2)*x^11 + Mod(1, 2)*x^10 + Mod(1, 2)*x^8 + Mod(1, 2)*x^4 + Mod(1, 2)* x^3 + Mod(1, 2)*x^2 + Mod(1, 2) ? setrand(1);ffinit(7,4) Mod(1, 7)*x^4 + Mod(1, 7)*x^3 + Mod(1, 7)*x^2 + Mod(1, 7)*x + Mod(1, 7) ? fibonacci(100) 354224848179261915075 ? gcd(12345678,87654321) 9 ? gcd(x^10-1,x^15-1) x^5 - 1 ? hilbert(2/3,3/4,5) 1 ? hilbert(Mod(5,7),Mod(6,7)) 1 ? isfundamental(12345) 1 ? isprime(12345678901234567) 0 ? ispseudoprime(73!+1) 1 ? issquare(12345678987654321) 1 ? issquarefree(123456789876543219) 0 ? kronecker(5,7) -1 ? kronecker(3,18) 0 ? lcm(15,-21) 105 ? lift(chinese(Mod(7,15),Mod(4,21))) 67 ? modreverse(Mod(x^2+1,x^3-x-1)) Mod(x^2 - 3*x + 2, x^3 - 5*x^2 + 8*x - 5) ? moebius(3*5*7*11*13) -1 ? nextprime(100000000000000000000000) 100000000000000000000117 ? numdiv(2^99*3^49) 5000 ? omega(100!) 25 ? precprime(100000000000000000000000) 99999999999999999999977 ? prime(100) 541 ? primes(100) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 2 39, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 33 1, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421 , 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541] ? qfbclassno(-12391) 63 ? qfbclassno(1345) 6 ? qfbclassno(-12391,1) 63 ? qfbclassno(1345,1) 6 ? Qfb(2,1,3)*Qfb(2,1,3) Qfb(2, -1, 3) ? qfbcompraw(Qfb(5,3,-1,0.),Qfb(7,1,-1,0.)) Qfb(35, 43, 13, 0.E-38) ? qfbhclassno(2000003) 357 ? qfbnucomp(Qfb(2,1,9),Qfb(4,3,5),3) Qfb(2, -1, 9) ? form=Qfb(2,1,9);qfbnucomp(form,form,3) Qfb(4, -3, 5) ? qfbnupow(form,111) Qfb(2, -1, 9) ? qfbpowraw(Qfb(5,3,-1,0.),3) Qfb(125, 23, 1, 0.E-38) ? qfbprimeform(-44,3) Qfb(3, 2, 4) ? qfbred(Qfb(3,10,12),,-1) Qfb(3, -2, 4) ? qfbred(Qfb(3,10,-20,1.5)) Qfb(3, 16, -7, 1.5000000000000000000000000000000000000) ? qfbred(Qfb(3,10,-20,1.5),2,,18) Qfb(3, 16, -7, 1.5000000000000000000000000000000000000) ? qfbred(Qfb(3,10,-20,1.5),1) Qfb(-20, -10, 3, 2.1074451073987839947135880252731470616) ? qfbred(Qfb(3,10,-20,1.5),3,,18) Qfb(-20, -10, 3, 1.5000000000000000000000000000000000000) ? quaddisc(-252) -7 ? quadgen(-11) w ? quadpoly(-11) x^2 - x + 3 ? quadregulator(17) 2.0947125472611012942448228460655286535 ? quadunit(17) 3 + 2*w ? sigma(100) 217 ? sigma(100,2) 13671 ? sigma(100,-3) 1149823/1000000 ? sqrtint(10!^2+1) 3628800 ? znorder(Mod(33,2^16+1)) 2048 ? forprime(p=2,100,print(p," ",lift(znprimroot(p)))) 2 1 3 2 5 2 7 3 11 2 13 2 17 3 19 2 23 5 29 2 31 3 37 2 41 6 43 3 47 5 53 2 59 2 61 2 67 2 71 7 73 5 79 3 83 2 89 3 97 5 ? znstar(3120) [768, [12, 4, 4, 2, 2], [Mod(2641, 3120), Mod(2497, 3120), Mod(2341, 3120), Mod(1951, 3120), Mod(2081, 3120)]] ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 20 pari-2.11.2/src/test/32/galpol0000644000175000017500000000253313326135265014362 0ustar billbill5 C8:[[Vecsmall([4, 5, 8, 7, 3, 2, 6, 1])], Vecsmall([8])]:[x^8 - x^7 - 7*x^6 + 6*x^5 + 15*x^4 - 10*x^3 - 10*x^2 + 4*x + 1, 1] C4 x C2:[[Vecsmall([3, 1, 5, 7, 2, 4, 8, 6]), Vecsmall([4, 6, 7, 1, 8, 2, 3, 5])], Vecsmall([4, 2])]:[x^8 - 7*x^6 + 14*x^4 - 8*x^2 + 1, 1] D8:[[Vecsmall([6, 1, 5, 2, 7, 4, 8, 3]), Vecsmall([3, 5, 1, 7, 2, 8, 4, 6])] , Vecsmall([4, 2])]:[x^8 - 4*x^7 - 8*x^6 + 24*x^5 + 30*x^4 - 16*x^3 - 20*x^2 + 2, 3] Q8:[[Vecsmall([4, 6, 2, 8, 1, 7, 3, 5]), Vecsmall([2, 8, 5, 3, 6, 4, 1, 7])] , Vecsmall([4, 2])]:[x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9, 3] C2 x C2 x C2:[[Vecsmall([2, 1, 4, 3, 6, 5, 8, 7]), Vecsmall([5, 6, 7, 8, 1, 2, 3, 4]), Vecsmall([3, 4, 1, 2, 7, 8, 5, 6])], Vecsmall([2, 2, 2])]:[x^8 - 12*x^6 + 23*x^4 - 12*x^2 + 1, 7] [x^8 + 8*x^6 + 20*x^4 + 16*x^2 + 2, 1] [x^8 - x^7 + x^5 - x^4 + x^3 - x + 1, 1] [x^8 + 3*x^4 + 1, 1] [x^8 + 12*x^6 + 36*x^4 + 36*x^2 + 9, 3] [x^8 - x^4 + 1, 1] [96, 161] *** at top-level: galoisgetpol(8,6) *** ^----------------- *** galoisgetpol: domain error in galoisgetpol: group index > 5 *** at top-level: galoisgetpol(3,1,3) *** ^------------------- *** galoisgetpol: invalid flag in galoisgetpol. *** at top-level: galoisgetpol(3,1,2) *** ^------------------- *** galoisgetpol: domain error in galoisgetpol: s > 1 Total time spent: 2728 pari-2.11.2/src/test/32/mspadic0000644000175000017500000003572513326135265014535 0ustar billbill *** Warning: new stack size = 50000000 (47.684 Mbytes). [2^-1 + 1 + 2^2 + 2^4 + O(2^5), 1 + 2^2 + O(2^4)]~ [2*3^-1 + 1 + 3 + 3^2 + 3^3 + O(3^4), 3^-1 + 1 + 3 + 3^2 + 3^3 + O(3^4)]~ [1 + O(3^5), O(3^5)]~ 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^4) 1 + O(5^4) [1 + O(3^5), O(3^5)]~ [O(2^3), O(2^2)]~ 2^4 + 2^5 + O(2^6) [O(3^10), O(3^10)]~ [2 + 3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + O(3^9), 2*3 + 2*3^2 + 2*3^3 + 3^5 + 2*3^8 + O(3^9)]~ [2*5 + 5^2 + 5^4 + O(5^5), 3*5 + 3*5^2 + 2*5^4 + O(5^5)]~ [[[[2031, 1484, 1568, 0, 0]], [[2031, 1960, 1029, 343, 0]], [[2006, 1792, 17 64, 686, 0]], [[2006, 1792, 1764, 686, 0]], [[2031, 1960, 1029, 343, 0]], [[ 2031, 1484, 1568, 0, 0]]], 1 + 5*7 + 7^3 + O(7^4), Vecsmall([7, 4, 4, 1])] [[[[2017, 441, 2009, 0, 0]], [[2017, 2177, 1421, 1372, 0]], [[2009, 1715, 20 58, 0, 0]], [[2009, 1715, 2058, 0, 0]], [[2017, 2177, 1421, 1372, 0]], [[201 7, 441, 2009, 0, 0]]], 4 + 7 + 2*7^3 + O(7^4), Vecsmall([7, 4, 4, 1])] [[[[2184, 720, 117, 1458, 81, 0, 729], [3, 837, 1134, 0, 729, 0, 0]], [[2184 , 720, 117, 1458, 81, 0, 729], [3, 837, 1134, 0, 729, 0, 0]]], [0, 1/36; 1/3 6, 0], Vecsmall([3, 7, 6, 1])] [[[[3, 1617, 980, 0, 0]], [[0, 861, 1764, 686, 0]], [[2398, 1526, 490, 1029, 0]], [[2398, 1526, 490, 1029, 0]], [[0, 861, 1764, 686, 0]], [[3, 1617, 980 , 0, 0]]], 1/6, Vecsmall([7, 4, 4, 1])] [[[[28, 63, 0, 0, 0]], [[28, 63, 0, 0, 0]]], 2 + 2*3 + 3^2 + 3^3 + O(3^4), V ecsmall([3, 4, 4, 29])] [[[[63, 27, 0, 0, 0]], [[63, 27, 0, 0, 0]]], 2 + 3 + 3^2 + 3^3 + O(3^4), Vec small([3, 4, 4, 5])] [[[[1850, 2500, 1250, 0, 0]], [[2500, 125, 0, 0, 0]], [[625, 3000, 0, 0, 0]] , [[1275, 625, 1875, 0, 0]]], 3*5^-1 + 5 + O(5^3), Vecsmall([5, 5, 4, -3])] 0: 2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 3^6 + 3^7 + O(3^10) 3 + 2*3^4 + 2*3^5 + 2*3^6 + O(3^8) 3^4 + 2*3^7 + O(3^8) 3^3 + 2*3^5 + O(3^7) -2: 2 + 2*3 + 2*3^2 + 2*3^4 + 3^6 + 3^7 + 3^8 + 3^9 + O(3^10) 3 + 2*3^3 + 3^4 + 3^5 + 2*3^7 + O(3^8) 3^3 + 2*3^4 + 2*3^6 + 2*3^7 + O(3^8) 3^3 + 2*3^5 + 2*3^6 + O(3^7) [0, 1]: O(3^10) O(3^8) O(3^8) O(3^7) [1, 0]: 2 + 2*3 + 3^3 + 3^4 + 3^6 + 3^8 + O(3^10) 3 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 3^7 + O(3^8) 3^3 + 3^5 + 3^6 + 2*3^7 + O(3^8) 3^3 + 2*3^5 + 3^6 + O(3^7) [2, 0]: 2 + 3^3 + 3^4 + 3^6 + 3^8 + 3^9 + O(3^10) 3 + 2*3^3 + 3^4 + 3^5 + 3^7 + O(3^8) 2*3^3 + 2*3^4 + 2*3^6 + O(3^8) 3^3 + O(3^7) 0: [2^-1 + 2 + 2^2 + 2^5 + 2^6 + O(2^9), 2^-1 + 2^2 + 2^3 + 2^6 + 2^7 + O(2^8)] ~ [1 + 2^4 + 2^5 + 2^6 + 2^7 + O(2^8), 1 + 2^2 + 2^3 + 2^5 + O(2^7)]~ [2^2 + 2^4 + 2^5 + O(2^7), 2^2 + 2^3 + 2^4 + 2^5 + O(2^6)]~ [2^4 + O(2^5), O(2^4)]~ -2: [2^-1 + 2^2 + 2^3 + 2^5 + 2^7 + O(2^9), 2^-1 + 2 + 2^3 + 2^5 + 2^6 + O(2^8)] ~ [1 + 2^3 + 2^5 + O(2^8), 1 + 2^2 + 2^4 + 2^5 + 2^6 + O(2^7)]~ [2^2 + 2^4 + O(2^7), 2^2 + 2^3 + 2^4 + 2^5 + O(2^6)]~ [2^4 + O(2^5), O(2^4)]~ [0, 1]: [O(2^9), O(2^8)]~ [O(2^8), O(2^7)]~ [O(2^7), O(2^6)]~ [O(2^5), O(2^4)]~ [1, 0]: [2^-1 + 1 + 2^7 + 2^8 + O(2^9), 2^-1 + 1 + 2 + 2^2 + 2^3 + 2^4 + 2^7 + O(2^8 )]~ [1 + 2^2 + 2^3 + 2^7 + O(2^8), 1 + 2^3 + 2^4 + 2^5 + O(2^7)]~ [2^2 + 2^5 + O(2^7), 2^2 + 2^3 + 2^4 + 2^5 + O(2^6)]~ [2^4 + O(2^5), O(2^4)]~ [2, 0]: [2^-1 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + O(2^9), 2^-1 + 2 + 2^2 + 2^3 + 2^4 + O (2^8)]~ [1 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + O(2^8), 1 + 2^2 + 2^5 + 2^6 + O(2^7)]~ [2^2 + 2^4 + 2^6 + O(2^7), 2^2 + 2^3 + 2^4 + 2^5 + O(2^6)]~ [2^4 + O(2^5), O(2^4)]~ 0: 5 + 7 + 5*7^2 + 4*7^3 + 7^4 + 2*7^5 + 4*7^6 + 4*7^7 + 2*7^8 + 2*7^9 + O(7^10 ) 5*7 + 2*7^2 + 6*7^3 + 2*7^4 + 2*7^5 + O(7^9) 3*7^2 + 6*7^3 + 3*7^4 + 3*7^5 + 7^7 + 2*7^8 + O(7^9) 6*7^3 + 7^4 + 3*7^5 + 6*7^7 + O(7^9) -2: 3 + 3*7 + 5*7^2 + 4*7^3 + 2*7^4 + 7^5 + 5*7^6 + 4*7^7 + 5*7^8 + 2*7^9 + O(7^ 10) 7 + 4*7^2 + 3*7^3 + 6*7^4 + 4*7^5 + 7^6 + 2*7^7 + 7^8 + O(7^9) 2*7^2 + 2*7^3 + 5*7^4 + 4*7^5 + 6*7^6 + 6*7^7 + 7^8 + O(7^9) 6*7^3 + 6*7^4 + 6*7^5 + 7^6 + 6*7^7 + 4*7^8 + O(7^9) [0, 1]: O(7^10) O(7^9) O(7^9) O(7^9) [1, 0]: 5 + 6*7 + 5*7^2 + 4*7^3 + 6*7^4 + 5*7^5 + 7^6 + 5*7^7 + 2*7^8 + 3*7^9 + O(7^ 10) 5*7 + 5*7^2 + 7^3 + 7^4 + 7^5 + 5*7^6 + 5*7^8 + O(7^9) 3*7^2 + 5*7^3 + 3*7^4 + 7^5 + 2*7^6 + 7^7 + 5*7^8 + O(7^9) 6*7^3 + 4*7^4 + 6*7^5 + 6*7^6 + 3*7^7 + 3*7^8 + O(7^9) [2, 0]: 5 + 4*7 + 2*7^2 + 3*7^3 + 3*7^4 + 4*7^5 + 6*7^6 + 6*7^7 + 5*7^8 + O(7^10) 5*7 + 7^2 + 3*7^3 + 4*7^4 + 6*7^5 + 5*7^6 + 4*7^7 + 6*7^8 + O(7^9) 3*7^2 + 4*7^3 + 6*7^4 + 2*7^5 + 5*7^6 + O(7^9) 6*7^3 + 3*7^5 + 4*7^7 + 4*7^8 + O(7^9) 0: 1 + O(3^10) 2*3 + 2*3^5 + 2*3^6 + O(3^8) 2*3^3 + 3^4 + 2*3^5 + O(3^8) 2*3^3 + 2*3^5 + 2*3^6 + O(3^7) -2: 1 + 2*3 + 2*3^2 + 3^4 + 3^5 + 2*3^6 + 3^7 + 2*3^8 + 2*3^9 + O(3^10) 2*3 + 3^4 + 3^5 + 2*3^6 + 3^7 + O(3^8) 3^3 + 3^4 + 2*3^5 + 3^6 + 3^7 + O(3^8) 2*3^3 + 3^5 + O(3^7) [0, 1]: O(3^10) O(3^8) O(3^8) O(3^7) [1, 0]: 1 + 2*3 + 3^2 + 3^3 + 3^4 + 2*3^5 + 3^6 + 3^7 + 2*3^8 + 3^9 + O(3^10) 2*3 + 2*3^4 + 2*3^6 + 2*3^7 + O(3^8) 3^3 + O(3^8) 2*3^3 + 3^5 + O(3^7) [2, 0]: 1 + 3 + 3^3 + 3^5 + 2*3^6 + 2*3^7 + 3^8 + O(3^10) 2*3 + 2*3^3 + 2*3^5 + 3^6 + O(3^8) 2*3^4 + 3^6 + 2*3^7 + O(3^8) 2*3^3 + 2*3^5 + 3^6 + O(3^7) 0: O(11^10) 4*11 + 3*11^2 + 10*11^3 + 7*11^4 + 5*11^5 + 10*11^6 + 2*11^7 + 9*11^8 + 6*11 ^9 + O(11^10) 5*11^3 + 7*11^4 + 10*11^5 + 6*11^6 + 2*11^7 + 5*11^8 + 2*11^9 + O(11^10) 5*11^3 + 3*11^4 + 11^5 + 2*11^6 + 8*11^8 + 5*11^9 + O(11^10) -2: 6 + 5*11 + 5*11^2 + 2*11^3 + 9*11^4 + 11^5 + 9*11^6 + 7*11^7 + 3*11^8 + 8*11 ^9 + O(11^10) 2*11 + 11^2 + 8*11^3 + 4*11^4 + 4*11^5 + 10*11^6 + 10*11^7 + 11^8 + 8*11^9 + O(11^10) 11^2 + 11^4 + 8*11^5 + 7*11^6 + 5*11^7 + 2*11^8 + 6*11^9 + O(11^10) 7*11^4 + 7*11^5 + 2*11^6 + 9*11^7 + 5*11^8 + 9*11^9 + O(11^10) [0, 1]: O(11^10) O(11^10) O(11^10) O(11^10) [1, 0]: 4*11 + 3*11^2 + 6*11^3 + 8*11^4 + 3*11^5 + 6*11^6 + 11^7 + 4*11^8 + 4*11^9 + O(11^10) 4*11 + 3*11^2 + 11^3 + 6*11^4 + 3*11^5 + 11^6 + 11^7 + 10*11^8 + 8*11^9 + O( 11^10) 10*11^3 + 10*11^4 + 9*11^5 + 5*11^6 + 2*11^7 + 3*11^8 + 9*11^9 + O(11^10) 5*11^3 + 3*11^4 + 8*11^5 + 2*11^6 + 9*11^7 + 2*11^8 + 6*11^9 + O(11^10) [2, 0]: 8*11 + 6*11^2 + 6*11^4 + 2*11^5 + 7*11^7 + 6*11^8 + 9*11^9 + O(11^10) 4*11 + 3*11^2 + 8*11^3 + 7*11^4 + 9*11^5 + 3*11^6 + 2*11^7 + 8*11^8 + 4*11^9 + O(11^10) 4*11^3 + 3*11^4 + 5*11^5 + 4*11^6 + 7*11^7 + 6*11^8 + 8*11^9 + O(11^10) 5*11^3 + 3*11^4 + 4*11^5 + 11^6 + 10*11^7 + 4*11^8 + 5*11^9 + O(11^10) 0: [O(2^10), O(2^9)]~ [O(2^8), O(2^7)]~ [2^5 + 2^6 + O(2^7), 2^5 + O(2^6)]~ [O(2^5), O(2^4)]~ -2: [2^6 + 2^7 + 2^9 + O(2^10), 2^6 + 2^7 + 2^8 + O(2^9)]~ [2^6 + 2^7 + O(2^8), 2^6 + O(2^7)]~ [2^5 + 2^6 + O(2^7), 2^5 + O(2^6)]~ [O(2^5), O(2^4)]~ [0, 1]: [O(2^10), O(2^9)]~ [O(2^8), O(2^7)]~ [O(2^7), O(2^6)]~ [O(2^5), O(2^4)]~ [1, 0]: [2^4 + 2^6 + 2^7 + O(2^10), 2^4 + 2^7 + O(2^9)]~ [O(2^8), O(2^7)]~ [2^5 + O(2^7), 2^5 + O(2^6)]~ [O(2^5), O(2^4)]~ [2, 0]: [2^6 + 2^7 + O(2^10), 2^6 + 2^7 + 2^8 + O(2^9)]~ [2^6 + O(2^8), 2^6 + O(2^7)]~ [2^5 + 2^6 + O(2^7), 2^5 + O(2^6)]~ [O(2^5), O(2^4)]~ [[[[2, 51, 0, 54, 0]], [[79, 30, 0, 27, 0]]], 1 + 2*3 + O(3^4), Vecsmall([3, 4, 4, 5])] [[[[174, 425, 475, 0, 0]], [[172, 400, 300, 0, 0]], [[172, 400, 300, 0, 0]], [[174, 425, 475, 0, 0]]], 3 + 3*5 + 5^2 + O(5^4), Vecsmall([5, 4, 4, -3])] [[[[1467, 5778, 6237, 2430, 5832, 2187, 0, 0, 0]], [[1467, 5778, 6237, 2430, 5832, 2187, 0, 0, 0]]], 2 + 2*3 + 3^2 + 3^3 + 3^4 + 2*3^5 + 3^6 + 3^7 + O(3 ^8), Vecsmall([3, 8, 8, 1])] *** at top-level: Wp=mspadicinit(msinit(25,2,1),5,4,1) *** ^--------------------------------- *** mspadicinit: sorry, mspadicinit when p^2 | N is not yet implemented. *** at top-level: oms=mspadicmoments(Wp,phi) *** ^---------------------- *** mspadicmoments: incorrect type in mstooms [v_p(ap) > mspadicinit flag] (t_VEC). [[28704438, 43044921, 28698258, 43046631, 28697823, 31655514, 40406052, 4241 9955, 42962282, 42910380, 42995952, 43040223, 43042464, 43045218, 43046702, 43046610, 43046643, 43046718, 43046718]~, [43023393, 28707534, 43042941, 286 99164, 43046298, 30101157, 39895767, 42353352, 42893463, 42954543, 43041654, 43035273, 43040547, 43045290, 43046337, 43046703, 43046694, 43046703, 0]~] [[28697958, 0, 43046697, 0, 28697823, 0, 39183249, 0, 43037183, 0, 43045038, 0, 43041006, 0, 43046453, 0, 43046643, 0, 43046718]~, [28709478, 0, 4304650 5, 0, 28697823, 0, 38646180, 0, 42834513, 0, 43030584, 0, 43041276, 0, 43046 382, 0, 0, 0, 0]~] [3^-1 + 1 + 2*3 + 3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + O(3^7), 2*3^-1 + 2 + 2*3 + 2*3^2 + 3^3 + 2*3^4 + 3^5 + O(3^7)]~ [2 + 2*3 + O(3^9), O(3^9), O(3^9), O(3^9), 1 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + O(3^9)] [O(3^10), 2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10), O(3^10), 2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10), O(3^10)] [4*5 + 2*5^2 + 2*5^3 + 2*5^4 + 4*5^5 + 3*5^6 + 4*5^7 + 3*5^8 + 3*5^9 + 2*5^1 0 + 3*5^11 + 4*5^12 + O(5^13), O(5^13), 2 + 4*5^3 + 4*5^4 + 5^5 + 4*5^7 + 3* 5^8 + 5^9 + 4*5^10 + 3*5^12 + O(5^13), O(5^13), 5 + 4*5^2 + 4*5^4 + 3*5^5 + 3*5^6 + 2*5^7 + 5^8 + 4*5^9 + 3*5^11 + 5^12 + O(5^13)] [O(5^13), 1 + 5 + 5^2 + 5^4 + 5^7 + 3*5^8 + 4*5^9 + 2*5^10 + 4*5^11 + 4*5^12 + O(5^13), O(5^13), 3 + 4*5 + 2*5^2 + 5^3 + 5^4 + 3*5^5 + 5^6 + 5^7 + 2*5^8 + 3*5^9 + O(5^13), O(5^13)] [4 + 5 + 3*5^2 + 4*5^4 + 4*5^5 + 3*5^6 + 5^7 + 3*5^8 + 2*5^9 + 3*5^10 + 2*5^ 11 + 4*5^12 + O(5^13), O(5^13), 1 + 4*5 + 5^2 + 5^3 + 4*5^4 + 3*5^5 + 2*5^6 + 2*5^7 + 3*5^8 + 5^10 + 4*5^11 + 3*5^12 + O(5^13), O(5^13), 4 + 2*5 + 3*5^2 + 3*5^3 + 4*5^4 + 3*5^5 + 4*5^7 + 5^8 + 3*5^9 + 4*5^10 + 2*5^11 + 2*5^12 + O(5^13)] [3 + 5*7 + 7^2 + 7^3 + 4*7^4 + 4*7^5 + 3*7^6 + 5*7^7 + 2*7^8 + 3*7^9 + 2*7^1 0 + 6*7^11 + 3*7^12 + 4*7^13 + 5*7^14 + O(7^15), O(7^15), 3 + 4*7 + 5*7^2 + 6*7^3 + 2*7^4 + 7^5 + 7^6 + 4*7^8 + 5*7^10 + 5*7^12 + 4*7^13 + 3*7^14 + O(7^ 15), O(7^15), 6 + 5*7^2 + 4*7^3 + 3*7^4 + 6*7^5 + 7^6 + 2*7^7 + 3*7^8 + 4*7^ 9 + 2*7^11 + 5*7^12 + 7^14 + O(7^15), O(7^15), 3 + 3*7 + 7^2 + 5*7^4 + 3*7^5 + 4*7^6 + 2*7^7 + 6*7^8 + 6*7^10 + 2*7^11 + 7^12 + 3*7^13 + 4*7^14 + O(7^15 )] [O(7^15), 5 + 3*7 + 2*7^2 + 3*7^3 + 4*7^4 + 6*7^5 + 6*7^6 + 2*7^7 + 2*7^8 + 3*7^9 + 5*7^10 + 5*7^11 + 4*7^12 + 2*7^13 + 4*7^14 + O(7^15), O(7^15), 2 + 4 *7^3 + 6*7^4 + 3*7^5 + 7^6 + 3*7^7 + 4*7^8 + 7^9 + 5*7^10 + 3*7^11 + 2*7^12 + 4*7^13 + 5*7^14 + O(7^15), O(7^15), 6 + 5*7 + 7^2 + 4*7^3 + 3*7^4 + 7^5 + 6*7^6 + 7^7 + 5*7^9 + 3*7^10 + 4*7^11 + 3*7^12 + 6*7^13 + 5*7^14 + O(7^15), O(7^15)] [1 + 3 + 3^3 + 3^4 + 2*3^5 + 3^6 + 3^9 + O(3^11), O(3^11), 1 + 3^2 + 2*3^4 + 3^7 + 2*3^8 + 2*3^9 + 2*3^10 + O(3^11)] [1 + 7 + 3*7^2 + 7^3 + 3*7^4 + 5*7^5 + 5*7^6 + 6*7^8 + 7^9 + 5*7^10 + O(7^11 ), O(7^11), 4 + 2*7 + 6*7^2 + 3*7^3 + 3*7^4 + 4*7^5 + 7^6 + 7^7 + 7^9 + 3*7^ 10 + O(7^11)] [O(7^11), 6 + 4*7 + 3*7^2 + 2*7^3 + 6*7^4 + 5*7^5 + 5*7^6 + 6*7^7 + 6*7^8 + 2*7^9 + 2*7^10 + O(7^11), O(7^11)] [7 + 3*7^2 + 7^3 + 3*7^4 + 6*7^5 + 5*7^7 + 2*7^8 + 6*7^9 + 5*7^10 + O(7^11), O(7^11), 5*7 + 6*7^3 + 6*7^4 + 7^5 + 5*7^6 + 7^7 + 3*7^8 + 6*7^9 + 5*7^10 + O(7^11)] [4 + 7 + 4*7^2 + 7^3 + 2*7^5 + 4*7^7 + 4*7^8 + 7^10 + 4*7^11 + 7^12 + O(7^13 ), O(7^13), O(7^13), O(7^13), 5 + 5*7 + 7^2 + 7^3 + 3*7^4 + 3*7^5 + 5*7^6 + 3*7^7 + 2*7^9 + 6*7^10 + 3*7^11 + 4*7^12 + O(7^13)] [O(7^13), 2 + 3*7^2 + 6*7^3 + 5*7^4 + 5*7^6 + 5*7^7 + 6*7^8 + 5*7^9 + 4*7^10 + 5*7^11 + 6*7^12 + O(7^13), O(7^13), 4 + 2*7 + 5*7^2 + 3*7^3 + 3*7^6 + 2*7 ^7 + 6*7^8 + 6*7^9 + 2*7^10 + 2*7^11 + 6*7^12 + O(7^13), O(7^13)] [6*7^2 + 4*7^3 + 2*7^4 + 6*7^5 + 4*7^6 + 2*7^9 + O(7^10), O(7^10), O(7^10), O(7^10), 2*7^2 + 2*7^3 + 6*7^4 + 7^5 + 2*7^6 + 3*7^7 + 3*7^8 + 6*7^9 + O(7^1 0)] [O(7^10), 5*7 + 6*7^2 + 5*7^3 + 3*7^4 + 6*7^5 + 6*7^6 + 6*7^7 + 6*7^8 + 6*7^ 9 + O(7^10), O(7^10), 6*7 + 6*7^2 + 2*7^3 + 5*7^4 + 6*7^5 + 6*7^6 + 6*7^7 + 6*7^8 + 6*7^9 + O(7^10), O(7^10)] [[3^-1 + 1 + 2*3 + 3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3 ^9 + 2*3^10 + 2*3^11 + O(3^12), 2*3^-1 + 2 + 2*3 + 2*3^2 + 3^3 + 2*3^4 + 3^5 + O(3^12)]~, [O(3^12), O(3^12)]~, [3^-2 + 2*3^-1 + 1 + O(3^12), 3^-2 + 3^-1 + 1 + 2*3 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12)]~, [O(3^12), O(3^12)]~, [3^-1 + 2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12), 2*3^-1 + 1 + 3^3 + O(3^12)]~] [[3*5^-1 + 2*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + 4*5^6 + 4*5^7 + 4*5^8 + 4*5 ^9 + 4*5^10 + O(5^11), 3*5^-1 + 3 + 3*5 + 3*5^2 + O(5^13)]~, [O(5^11), O(5^1 3)]~, [3*5^-1 + 1 + O(5^11), 3*5^-1 + 4 + 2*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^ 5 + 4*5^6 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + 4*5^11 + 4*5^12 + O(5^13)]~] [[2 + 3^2 + 3^4 + 2*3^5 + O(3^13), 2 + 3^4 + 3^6 + 2*3^8 + 3^9 + 2*3^10 + 2* 3^11 + 2*3^12 + 2*3^13 + O(3^14)]~, [O(3^13), O(3^14)]~, [O(3^13), O(3^14)]~ , [O(3^13), O(3^14)]~, [1 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2* 3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + 2*3^12 + O(3^13), 1 + 2*3 + 3^4 + O( 3^14)]~] [[1 + 2 + 2^3 + 2^4 + O(2^18), 2 + 2^2 + 2^4 + 2^5 + 2^6 + 2^8 + 2^11 + 2^12 + 2^13 + 2^14 + 2^15 + 2^16 + 2^17 + O(2^18)]~, [O(2^18), O(2^18)]~, [2^-1 + 1 + 2^2 + 2^4 + 2^7 + 2^8 + 2^11 + 2^12 + 2^15 + 2^16 + O(2^18), 2^-1 + 2 + 2^4 + 2^8 + 2^10 + 2^11 + 2^14 + 2^15 + O(2^18)]~, [O(2^18), O(2^18)]~, [2 ^-1 + 1 + 2 + 2^5 + 2^9 + 2^13 + 2^17 + O(2^18), 2^-1 + 2^2 + 2^5 + 2^7 + 2^ 8 + 2^9 + 2^11 + 2^12 + 2^13 + 2^15 + 2^16 + 2^17 + O(2^18)]~, [O(2^18), O(2 ^18)]~, [1 + 2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + 2^11 + 2^12 + 2^13 + 2^14 + 2^15 + 2^16 + 2^17 + O(2^18), 2 + 2^2 + 2^3 + 2^4 + 2^5 + O(2^18)]~] [[2 + 2^6 + 2^7 + 2^9 + 2^10 + 2^12 + 2^13 + 2^15 + 2^16 + 2^17 + O(2^18), 2 ^4 + 2^5 + 2^6 + 2^8 + 2^11 + 2^12 + 2^15 + O(2^18)]~, [O(2^18), O(2^18)]~, [1 + 2 + 2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^10 + 2^12 + 2^14 + 2^16 + O(2^18), 1 + 2 + 2^2 + 2^3 + 2^4 + 2^6 + 2^7 + 2^9 + 2^10 + 2^14 + 2^15 + 2^16 + 2^17 + O(2^18)]~, [O(2^18), O(2^18)]~, [1 + 2 + 2^2 + 2^4 + 2^8 + 2^9 + 2^11 + 2 ^13 + 2^15 + 2^17 + O(2^18), 1 + 2 + 2^4 + 2^7 + 2^10 + 2^12 + 2^13 + 2^14 + 2^15 + 2^16 + 2^17 + O(2^18)]~, [O(2^18), O(2^18)]~, [2 + 2^3 + 2^5 + 2^6 + 2^8 + 2^9 + 2^10 + 2^11 + 2^12 + 2^13 + 2^14 + 2^15 + 2^16 + 2^17 + O(2^18) , 2^4 + 2^5 + 2^9 + 2^11 + 2^13 + O(2^18)]~] [2^6 + O(2^10), O(2^10), 2^6 + 2^8 + O(2^10), O(2^10), 2^6 + O(2^10), O(2^10 ), 2^6 + 2^8 + O(2^10)] [[2*7^-1 + 5 + 7 + 4*7^2 + O(7^17), 5*7^-1 + 5 + 6*7^2 + 5*7^3 + 4*7^4 + 2*7 ^5 + 2*7^7 + 2*7^9 + 6*7^10 + 6*7^11 + 6*7^12 + 6*7^13 + 6*7^14 + 6*7^15 + 6 *7^16 + O(7^17)]~, [O(7^17), O(7^17)]~, [5*7^-2 + 5*7^-1 + 2 + 4*7 + 6*7^2 + 6*7^3 + 6*7^4 + 6*7^5 + 6*7^6 + 6*7^7 + 6*7^8 + 6*7^9 + 6*7^10 + 6*7^11 + 6 *7^12 + 6*7^13 + 6*7^14 + 6*7^15 + 6*7^16 + O(7^17), 4*7^-2 + 1 + 6*7 + 2*7^ 2 + 6*7^3 + 6*7^4 + 6*7^5 + 2*7^6 + O(7^17)]~, [O(7^17), O(7^17)]~, [6*7^-2 + 5*7^-1 + 6*7 + 2*7^2 + 7^3 + 4*7^4 + 5*7^5 + 2*7^6 + 7^7 + 4*7^8 + 5*7^9 + 2*7^10 + 7^11 + 4*7^12 + 5*7^13 + 2*7^14 + 7^15 + 4*7^16 + O(7^17), 2*7^-2 + 7^-1 + 2 + 2*7 + 4*7^2 + 3*7^3 + 4*7^5 + 5*7^6 + 2*7^7 + 7^8 + 4*7^9 + 5*7 ^10 + 2*7^11 + 7^12 + 4*7^13 + 5*7^14 + 2*7^15 + 7^16 + O(7^17)]~, [O(7^17), O(7^17)]~, [6*7^-2 + 6*7^-1 + 4 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + 6*7^5 + 6*7 ^6 + 6*7^7 + 6*7^8 + 6*7^9 + 6*7^10 + 6*7^11 + 6*7^12 + 6*7^13 + 6*7^14 + 6* 7^15 + 6*7^16 + O(7^17), 2*7^-2 + 6*7^-1 + 6*7 + 7^2 + 2*7^3 + 2*7^4 + 2*7^5 + O(7^17)]~, [O(7^17), O(7^17)]~, [4*7^-1 + 2 + O(7^17), 3*7^-1 + 5 + 2*7 + 4*7^2 + 7^3 + 4*7^7 + 6*7^8 + 6*7^9 + 6*7^10 + 6*7^11 + 6*7^12 + 6*7^13 + 6 *7^14 + 6*7^15 + 6*7^16 + O(7^17)]~] Total time spent: 9597 pari-2.11.2/src/test/32/time0000644000175000017500000000003413201017466014026 0ustar billbill1 1 1 1 Total time spent: 0 pari-2.11.2/src/test/32/ratpoints0000644000175000017500000005124713326135265015135 0ustar billbill1:[] 2:[[0, 2, 1], [0, -2, 1]] 3:[[0, 2, 1], [0, -2, 1], [-2, 346, 5], [-2, -346, 5]] 4:[[0, 0, 1]] 5:[] 6:[[0, 0, 1], [-1, 0, 1]] 7:[[-3, 6, 2], [-3, -6, 2]] 8:[] 9:[] 10:[] 11:[] 12:[[3, 31, 2], [3, -31, 2], [2, 51, 3], [2, -51, 3]] 13:[] 14:[[0, 0, 1], [-1, 2, 1], [-1, -2, 1]] 15:[] 16:[] 17:[] 18:[[1, 0, 1]] 19:[[-1, 1, 1], [-1, -1, 1], [1, 20, 2], [1, -20, 2]] 20:[[-1, 3, 1], [-1, -3, 1]] 21:[[0, 2, 1], [0, -2, 1]] 22:[[-2, 7, 1], [-2, -7, 1], [0, 1, 1], [0, -1, 1]] 23:[[-1, 2, 1], [-1, -2, 1]] 24:[[1, 11, 2], [1, -11, 2]] 25:[] 26:[[1, 1, 1], [1, -1, 1]] 27:[] 28:[] 29:[[-3, 38, 1], [-3, -38, 1], [-1, 2, 1], [-1, -2, 1], [1, 2, 1], [1, -2, 1 ], [7, 602, 1], [7, -602, 1], [1, 513, 6], [1, -513, 6]] 30:[] 31:[[0, 2, 1], [0, -2, 1]] 32:[[1, 1, 1], [1, -1, 1]] 33:[] 34:[[0, 0, 1], [-1, 3, 2], [-1, -3, 2]] 35:[[-1, 3, 1], [-1, -3, 1]] 36:[] 37:[] 38:[[0, 0, 1], [-1, 3, 1], [-1, -3, 1]] 39:[[0, 2, 1], [0, -2, 1]] 40:[] 41:[[0, 1, 1], [0, -1, 1]] 42:[] 43:[[0, 1, 1], [0, -1, 1]] 44:[[1, 2, 1], [1, -2, 1]] 45:[[0, 3, 1], [0, -3, 1], [1, 23, 2], [1, -23, 2]] 46:[] 47:[] 48:[[0, 2, 1], [0, -2, 1]] 49:[[-1, 4, 1], [-1, -4, 1]] 50:[[1, 3, 1], [1, -3, 1]] 51:[] 52:[[1, 4, 1], [1, -4, 1]] 53:[[-1, 2, 1], [-1, -2, 1], [-1, 4, 2], [-1, -4, 2]] 54:[[-1, 1, 1], [-1, -1, 1]] 55:[[0, 0, 1]] 56:[[1, 3, 1], [1, -3, 1]] 57:[[-1, 4, 1], [-1, -4, 1], [0, 3, 1], [0, -3, 1], [2, 107, 3], [2, -107, 3 ], [38, 1939745, 83], [38, -1939745, 83]] 58:[[0, 1, 1], [0, -1, 1], [1, 3, 2], [1, -3, 2], [-13, 6499, 9], [-13, -649 9, 9], [-49, 198463, 12], [-49, -198463, 12]] 59:[[1, 0, 1]] 60:[] 61:[] 62:[[0, 3, 1], [0, -3, 1]] 63:[] 64:[] 65:[[0, 3, 1], [0, -3, 1]] 66:[[0, 0, 1]] 67:[] 68:[] 69:[] 70:[[1, 3, 1], [1, -3, 1]] 71:[[1, 0, 1]] 72:[] 73:[] 74:[[0, 0, 1]] 75:[[0, 3, 1], [0, -3, 1]] 76:[] 77:[[0, 3, 1], [0, -3, 1]] 78:[[-1, 4, 1], [-1, -4, 1]] 79:[] 80:[] 81:[] 82:[] 83:[] 84:[[-1, 2, 1], [-1, -2, 1]] 85:[] 86:[] 87:[] 88:[] 89:[] 90:[] 91:[] 92:[[1, 1, 1], [1, -1, 1]] 93:[] 94:[[-1, 0, 1]] 95:[[0, 3, 1], [0, -3, 1], [4, 23, 1], [4, -23, 1]] 96:[[0, 1, 1], [0, -1, 1]] 97:[[0, 2, 1], [0, -2, 1]] 98:[[-1, 2, 1], [-1, -2, 1], [1, 2, 1], [1, -2, 1]] 99:[] 100:[[2, 3461, 11], [2, -3461, 11]] 101:[[-1, 1, 1], [-1, -1, 1]] 102:[[0, 1, 1], [0, -1, 1]] 103:[] 104:[] 105:[] 106:[] 107:[] 108:[[-1, 5, 1], [-1, -5, 1]] 109:[[-1, 1, 1], [-1, -1, 1]] 110:[[-2, 8, 1], [-2, -8, 1], [-1, 1, 1], [-1, -1, 1], [2, 16, 1], [2, -16, 1]] 111:[[0, 3, 1], [0, -3, 1]] 112:[] 113:[[1, 144, 4], [1, -144, 4]] 114:[] 115:[[3, 82, 2], [3, -82, 2]] 116:[] 117:[[2, 4, 1], [2, -4, 1]] 118:[[-1, 2, 1], [-1, -2, 1]] 119:[] 120:[] 121:[[0, 0, 1], [1, 2, 1], [1, -2, 1], [-2, 16, 1], [-2, -16, 1]] 122:[[0, 2, 1], [0, -2, 1], [3, 23, 1], [3, -23, 1]] 123:[] 124:[] 125:[[1, 3, 1], [1, -3, 1]] 126:[] 127:[[-1, 1, 1], [-1, -1, 1]] 128:[] 129:[] 130:[] 131:[] 132:[[0, 3, 1], [0, -3, 1]] 133:[] 134:[[0, 1, 1], [0, -1, 1]] 135:[] 136:[] 137:[[0, 2, 1], [0, -2, 1]] 138:[] 139:[] 140:[[-1, 3, 1], [-1, -3, 1], [2, 3, 1], [2, -3, 1], [3, 6, 2], [3, -6, 2]] 141:[[0, 3, 1], [0, -3, 1], [1, 6, 1], [1, -6, 1], [-4, 419, 7], [-4, -419, 7]] 142:[[1, 2, 1], [1, -2, 1], [7, 2996, 10], [7, -2996, 10]] 143:[] 144:[[1, 2, 1], [1, -2, 1]] 145:[[0, 2, 1], [0, -2, 1]] 146:[] 147:[[3, 49, 2], [3, -49, 2]] 148:[[-1, 18, 2], [-1, -18, 2]] 149:[] 150:[] 151:[[0, 0, 1]] 152:[[0, 3, 1], [0, -3, 1]] 153:[] 154:[[0, 2, 1], [0, -2, 1]] 155:[[-1, 1, 1], [-1, -1, 1]] 156:[[-2, 22, 1], [-2, -22, 1]] 157:[] 158:[[0, 1, 1], [0, -1, 1]] 159:[[1, 1, 1], [1, -1, 1]] 160:[] 161:[] 162:[] 163:[] 164:[] 165:[] 166:[[-1, 1, 1], [-1, -1, 1], [0, 3, 1], [0, -3, 1]] 167:[] 168:[[3, 1, 1], [3, -1, 1]] 169:[] 170:[] 171:[[1, 4, 1], [1, -4, 1]] 172:[[-1, 1, 1], [-1, -1, 1]] 173:[[0, 3, 1], [0, -3, 1], [1, 0, 1]] 174:[] 175:[] 176:[[1, 5, 1], [1, -5, 1]] 177:[[10, 3648, 7], [10, -3648, 7]] 178:[[-20, 21952, 1], [-20, -21952, 1], [0, 2, 1], [0, -2, 1]] 179:[[-1, 2, 1], [-1, -2, 1]] 180:[] 181:[[1, 1, 1], [1, -1, 1], [-27, 1795891, 89], [-27, -1795891, 89]] 182:[[-1, 5, 2], [-1, -5, 2]] 183:[] 184:[] 185:[] 186:[] 187:[] 188:[] 189:[[-1, 9, 2], [-1, -9, 2]] 190:[] 191:[] 192:[] 193:[[1, 3, 1], [1, -3, 1]] 194:[[-1, 1, 2], [-1, -1, 2], [1, 1, 1], [1, -1, 1]] 195:[] 196:[[-1, 1, 1], [-1, -1, 1]] 197:[] 198:[] 199:[[0, 2, 1], [0, -2, 1]] 200:[] 201:[[7, 357, 4], [7, -357, 4]] 202:[[0, 1, 1], [0, -1, 1]] 203:[] 204:[] 205:[] 206:[[1, 3, 1], [1, -3, 1]] 207:[] 208:[[0, 0, 1]] 209:[[-2, 9, 1], [-2, -9, 1]] 210:[[1, 0, 1]] 211:[[-1, 7, 2], [-1, -7, 2]] 212:[[0, 2, 1], [0, -2, 1]] 213:[[0, 1, 1], [0, -1, 1]] 214:[[0, 2, 1], [0, -2, 1], [2, 12, 3], [2, -12, 3]] 215:[] 216:[] 217:[[-2, 3, 1], [-2, -3, 1], [-1, 0, 1], [0, 1, 1], [0, -1, 1], [-6, 133, 5 ], [-6, -133, 5]] 218:[] 219:[[-1, 75, 4], [-1, -75, 4]] 220:[] 221:[[-1, 3, 1], [-1, -3, 1]] 222:[] 223:[[1, 3, 1], [1, -3, 1]] 224:[] 225:[] 226:[] 227:[] 228:[[0, 3, 1], [0, -3, 1], [2, 21, 1], [2, -21, 1]] 229:[] 230:[] 231:[[0, 1, 1], [0, -1, 1], [1, 5, 2], [1, -5, 2]] 232:[] 233:[[0, 3, 1], [0, -3, 1]] 234:[] 235:[] 236:[[0, 2, 1], [0, -2, 1]] 237:[[-1, 1, 1], [-1, -1, 1], [1, 101, 4], [1, -101, 4]] 238:[[-1, 2, 1], [-1, -2, 1], [1, 13, 2], [1, -13, 2]] 239:[[-3, 58, 1], [-3, -58, 1]] 240:[[1, 4, 1], [1, -4, 1], [3, 1408, 8], [3, -1408, 8]] 241:[] 242:[[0, 1, 1], [0, -1, 1]] 243:[[1, 2, 1], [1, -2, 1]] 244:[] 245:[] 246:[[-2, 9, 1], [-2, -9, 1]] 247:[[1, 4, 1], [1, -4, 1]] 248:[[-1, 3, 1], [-1, -3, 1]] 249:[] 250:[] 251:[] 252:[] 253:[] 254:[] 255:[[-1, 1, 1], [-1, -1, 1]] 256:[] 257:[] 258:[] 259:[[0, 1, 1], [0, -1, 1]] 260:[] 261:[] 262:[] 263:[[0, 0, 1]] 264:[[0, 1, 1], [0, -1, 1]] 265:[] 266:[] 267:[[1, 1, 1], [1, -1, 1]] 268:[] 269:[] 270:[] 271:[] 272:[] 273:[[0, 2, 1], [0, -2, 1]] 274:[[-4, 114, 1], [-4, -114, 1]] 275:[[0, 3, 1], [0, -3, 1]] 276:[] 277:[] 278:[] 279:[] 280:[] 281:[] 282:[[0, 2, 1], [0, -2, 1]] 283:[[-1, 3, 1], [-1, -3, 1]] 284:[] 285:[] 286:[[0, 3, 1], [0, -3, 1]] 287:[[20, 25315, 19], [20, -25315, 19]] 288:[] 289:[[-1, 1, 1], [-1, -1, 1]] 290:[] 291:[[0, 3, 1], [0, -3, 1], [3, 291, 5], [3, -291, 5]] 292:[] 293:[] 294:[] 295:[] 296:[] 297:[] 298:[] 299:[] 300:[] 301:[] 302:[[0, 3, 1], [0, -3, 1]] 303:[] 304:[[-2, 37, 3], [-2, -37, 3]] 305:[[-1, 2, 1], [-1, -2, 1], [1, 2, 1], [1, -2, 1]] 306:[] 307:[] 308:[] 309:[] 310:[[0, 3, 1], [0, -3, 1]] 311:[] 312:[[0, 3, 1], [0, -3, 1]] 313:[] 314:[] 315:[] 316:[] 317:[[0, 2, 1], [0, -2, 1], [1, 0, 1]] 318:[] 319:[[0, 3, 1], [0, -3, 1], [-704, 40680297, 933], [-704, -40680297, 933]] 320:[[0, 0, 1]] 321:[[-1, 1, 1], [-1, -1, 1], [1, 5, 1], [1, -5, 1]] 322:[] 323:[[36, 131678, 1], [36, -131678, 1]] 324:[[0, 2, 1], [0, -2, 1]] 325:[] 326:[] 327:[] 328:[[-1, 1, 1], [-1, -1, 1], [1, 11, 2], [1, -11, 2], [1, 503, 6], [1, -503 , 6], [2, 13, 1], [2, -13, 1], [3, 113, 5], [3, -113, 5]] 329:[[0, 0, 1]] 330:[[1, 3, 1], [1, -3, 1]] 331:[] 332:[[1, 3, 1], [1, -3, 1]] 333:[] 334:[] 335:[] 336:[[-3, 10, 1], [-3, -10, 1], [0, 2, 1], [0, -2, 1], [-1, 46, 3], [-1, -46 , 3]] 337:[] 338:[[0, 0, 1]] 339:[] 340:[[0, 1, 1], [0, -1, 1], [-1, 16, 2], [-1, -16, 2]] 341:[[93, 594431, 28], [93, -594431, 28]] 342:[[0, 1, 1], [0, -1, 1]] 343:[[-1, 2, 1], [-1, -2, 1]] 344:[] 345:[[1, 0, 1]] 346:[[0, 2, 1], [0, -2, 1]] 347:[[0, 0, 1]] 348:[] 349:[[0, 2, 1], [0, -2, 1], [1, 5, 1], [1, -5, 1]] 350:[] 351:[[-1, 0, 1], [0, 2, 1], [0, -2, 1], [1, 0, 1]] 352:[[0, 2, 1], [0, -2, 1], [1, 0, 1]] 353:[] 354:[] 355:[] 356:[[0, 3, 1], [0, -3, 1]] 357:[[0, 2, 1], [0, -2, 1]] 358:[[0, 0, 1], [-1, 2, 1], [-1, -2, 1], [1, 11, 2], [1, -11, 2]] 359:[] 360:[] 361:[] 362:[] 363:[] 364:[] 365:[[1, 3, 1], [1, -3, 1]] 366:[] 367:[] 368:[[0, 0, 1]] 369:[] 370:[[0, 3, 1], [0, -3, 1]] 371:[[-1, 0, 1], [-2, 0, 7]] 372:[] 373:[] 374:[] 375:[[-1, 0, 1]] 376:[] 377:[] 378:[] 379:[[0, 0, 1]] 380:[] 381:[[0, 2, 1], [0, -2, 1]] 382:[] 383:[] 384:[[-2, 92, 3], [-2, -92, 3]] 385:[] 386:[[1, 0, 1]] 387:[[0, 0, 1]] 388:[] 389:[] 390:[[-1, 4, 1], [-1, -4, 1]] 391:[] 392:[[-4, 190, 1], [-4, -190, 1]] 393:[] 394:[[-1, 0, 1]] 395:[] 396:[[-1, 3, 1], [-1, -3, 1]] 397:[] 398:[] 399:[[-1, 2, 1], [-1, -2, 1]] 400:[[1, 2, 1], [1, -2, 1]] 401:[[-5, 159, 3], [-5, -159, 3]] 402:[] 403:[[-1, 3, 1], [-1, -3, 1]] 404:[[-2, 11, 1], [-2, -11, 1]] 405:[] 406:[] 407:[] 408:[[2, 6, 1], [2, -6, 1]] 409:[] 410:[] 411:[[-2, 13, 1], [-2, -13, 1]] 412:[] 413:[] 414:[[-5, 95, 4], [-5, -95, 4]] 415:[] 416:[] 417:[[-1, 6, 1], [-1, -6, 1]] 418:[[2, 1, 1], [2, -1, 1]] 419:[] 420:[[1, 2, 2], [1, -2, 2]] 421:[] 422:[] 423:[] 424:[[1, 1, 1], [1, -1, 1]] 425:[] 426:[] 427:[[-1, 2, 1], [-1, -2, 1], [0, 1, 1], [0, -1, 1]] 428:[] 429:[[-2, 9, 1], [-2, -9, 1], [0, 3, 1], [0, -3, 1]] 430:[] 431:[] 432:[[1, 5, 1], [1, -5, 1]] 433:[[4, 43, 5], [4, -43, 5]] 434:[] 435:[[1, 0, 1], [-3, 42, 4], [-3, -42, 4]] 436:[] 437:[] 438:[[1, 3, 1], [1, -3, 1]] 439:[[1, 0, 1]] 440:[[1, 2, 1], [1, -2, 1]] 441:[[5, 1735, 8], [5, -1735, 8], [-11, 7265, 16], [-11, -7265, 16]] 442:[] 443:[[0, 3, 1], [0, -3, 1]] 444:[[-2, 9, 1], [-2, -9, 1]] 445:[[1, 2, 1], [1, -2, 1]] 446:[[-1, 2, 1], [-1, -2, 1]] 447:[] 448:[] 449:[[0, 3, 1], [0, -3, 1]] 450:[] 451:[] 452:[] 453:[] 454:[[-1, 2, 1], [-1, -2, 1]] 455:[] 456:[] 457:[] 458:[] 459:[[-1, 0, 1]] 460:[] 461:[] 462:[[-1, 3, 1], [-1, -3, 1]] 463:[] 464:[] 465:[[0, 1, 1], [0, -1, 1]] 466:[[2, 11, 1], [2, -11, 1]] 467:[[0, 0, 1], [1, 10, 2], [1, -10, 2]] 468:[[-1, 460, 6], [-1, -460, 6]] 469:[[-2, 20, 1], [-2, -20, 1]] 470:[[-1, 3, 1], [-1, -3, 1], [-6, 368, 5], [-6, -368, 5]] 471:[[1, 3, 1], [1, -3, 1]] 472:[] 473:[] 474:[[0, 2, 1], [0, -2, 1]] 475:[[-1, 3, 1], [-1, -3, 1], [11, 2535, 1], [11, -2535, 1]] 476:[] 477:[[1, 19, 2], [1, -19, 2]] 478:[] 479:[[-1, 3, 1], [-1, -3, 1], [0, 2, 1], [0, -2, 1]] 480:[] 481:[] 482:[] 483:[] 484:[[1, 2, 1], [1, -2, 1], [-1, 11, 2], [-1, -11, 2]] 485:[] 486:[] 487:[[1, 3, 1], [1, -3, 1]] 488:[] 489:[[-2, 4, 1], [-2, -4, 1]] 490:[[-1, 27, 2], [-1, -27, 2]] 491:[] 492:[] 493:[] 494:[[0, 0, 1]] 495:[[0, 1, 1], [0, -1, 1]] 496:[] 497:[[-1, 3, 1], [-1, -3, 1], [0, 1, 1], [0, -1, 1], [3, 74, 2], [3, -74, 2] , [-8, 1591, 7], [-8, -1591, 7]] 498:[] 499:[] 500:[] 501:[[-1, 5, 1], [-1, -5, 1]] 502:[[-1, 4, 1], [-1, -4, 1]] 503:[[0, 1, 1], [0, -1, 1]] 504:[] 505:[[2, 76, 3], [2, -76, 3], [7, 7780, 15], [7, -7780, 15]] 506:[[0, 1, 1], [0, -1, 1], [1, 1, 1], [1, -1, 1], [3, 10, 2], [3, -10, 2]] 507:[[0, 1, 1], [0, -1, 1], [-4, 95, 3], [-4, -95, 3]] 508:[[1, 1, 1], [1, -1, 1], [-1, 55, 3], [-1, -55, 3], [2, 64, 3], [2, -64, 3]] 509:[[3, 57, 2], [3, -57, 2]] 510:[[2, 14, 1], [2, -14, 1]] 511:[[-1, 4, 1], [-1, -4, 1]] 512:[] 513:[[-3, 5, 1], [-3, -5, 1]] 514:[[0, 3, 1], [0, -3, 1]] 515:[] 516:[[0, 3, 1], [0, -3, 1]] 517:[[-1, 5, 1], [-1, -5, 1], [1, 1, 1], [1, -1, 1], [1, 22, 2], [1, -22, 2] ] 518:[] 519:[] 520:[[-1, 0, 1], [0, 1, 1], [0, -1, 1]] 521:[[-7, 521, 5], [-7, -521, 5]] 522:[] 523:[] 524:[] 525:[] 526:[[-2, 20, 1], [-2, -20, 1], [1, 2, 1], [1, -2, 1], [22, 31638, 15], [22, -31638, 15]] 527:[] 528:[] 529:[[1, 3, 1], [1, -3, 1]] 530:[] 531:[] 532:[[-1, 1, 1], [-1, -1, 1]] 533:[] 534:[] 535:[] 536:[] 537:[] 538:[[1, 4, 1], [1, -4, 1], [1, 23, 2], [1, -23, 2]] 539:[] 540:[] 541:[[0, 3, 1], [0, -3, 1], [-5, 257, 4], [-5, -257, 4]] 542:[] 543:[[-1, 3, 1], [-1, -3, 1]] 544:[] 545:[[-1, 0, 1], [0, 3, 1], [0, -3, 1]] 546:[[-1, 0, 1]] 547:[[0, 0, 1]] 548:[[0, 3, 1], [0, -3, 1], [-5, 348, 6], [-5, -348, 6]] 549:[] 550:[] 551:[] 552:[[-1, 1, 1], [-1, -1, 1]] 553:[] 554:[] 555:[] 556:[] 557:[[0, 3, 1], [0, -3, 1]] 558:[] 559:[[0, 3, 1], [0, -3, 1]] 560:[] 561:[[-1, 7, 2], [-1, -7, 2]] 562:[] 563:[] 564:[] 565:[] 566:[[3, 3, 2], [3, -3, 2]] 567:[] 568:[] 569:[] 570:[] 571:[] 572:[] 573:[] 574:[[0, 3, 1], [0, -3, 1]] 575:[] 576:[[1, 4, 1], [1, -4, 1]] 577:[] 578:[] 579:[] 580:[[1, 0, 1]] 581:[] 582:[[0, 1, 1], [0, -1, 1]] 583:[] 584:[[-1, 4, 1], [-1, -4, 1]] 585:[[0, 1, 1], [0, -1, 1]] 586:[[0, 1, 1], [0, -1, 1]] 587:[] 588:[] 589:[[4, 100, 1], [4, -100, 1]] 590:[[1, 0, 1], [-313, 27928221051, 2496], [-313, -27928221051, 2496]] 591:[] 592:[[0, 1, 1], [0, -1, 1]] 593:[] 594:[] 595:[] 596:[] 597:[] 598:[[0, 2, 1], [0, -2, 1]] 599:[] 600:[[1, 3, 1], [1, -3, 1]] 601:[] 602:[[-1, 0, 1]] 603:[] 604:[[-1, 4, 1], [-1, -4, 1]] 605:[[0, 3, 1], [0, -3, 1]] 606:[[1, 1, 1], [1, -1, 1]] 607:[] 608:[[-3, 81, 1], [-3, -81, 1]] 609:[[-47, 3295394, 104], [-47, -3295394, 104]] 610:[[0, 2, 1], [0, -2, 1]] 611:[[-1, 5, 1], [-1, -5, 1]] 612:[[1, 1, 1], [1, -1, 1]] 613:[[-1, 5, 1], [-1, -5, 1]] 614:[[1, 0, 1]] 615:[] 616:[[-1, 53, 4], [-1, -53, 4]] 617:[] 618:[[-2, 16, 1], [-2, -16, 1], [-1, 0, 1], [0, 2, 1], [0, -2, 1], [5, 198, 1], [5, -198, 1], [1, 27, 2], [1, -27, 2], [7, 5094, 11], [7, -5094, 11]] 619:[[0, 2, 1], [0, -2, 1], [3, 20, 4], [3, -20, 4]] 620:[] 621:[[0, 0, 1]] 622:[] 623:[] 624:[[1, 4, 1], [1, -4, 1]] 625:[] 626:[] 627:[] 628:[[0, 1, 1], [0, -1, 1], [-57, 543145, 112], [-57, -543145, 112]] 629:[[0, 3, 1], [0, -3, 1]] 630:[[0, 3, 1], [0, -3, 1]] 631:[] 632:[[-1, 2, 1], [-1, -2, 1], [1, 0, 1]] 633:[] 634:[] 635:[] 636:[] 637:[[0, 3, 1], [0, -3, 1]] 638:[[-1, 3, 1], [-1, -3, 1], [0, 3, 1], [0, -3, 1]] 639:[[-1, 3, 1], [-1, -3, 1]] 640:[] 641:[] 642:[[-4, 170, 1], [-4, -170, 1], [0, 2, 1], [0, -2, 1]] 643:[[-8, 604, 1], [-8, -604, 1], [-2, 22, 1], [-2, -22, 1], [-1, 5, 1], [-1 , -5, 1], [0, 0, 1], [1, 1, 1], [1, -1, 1], [-1, 381, 9], [-1, -381, 9], [1, 4, 2], [1, -4, 2], [-9, 3228, 8], [-9, -3228, 8], [-1, 95, 5], [-1, -95, 5] , [9, 1200, 10], [9, -1200, 10]] 644:[[0, 1, 1], [0, -1, 1], [1, 3, 1], [1, -3, 1]] 645:[] 646:[] 647:[[1, 1, 1], [1, -1, 1]] 648:[[0, 1, 1], [0, -1, 1]] 649:[[0, 1, 1], [0, -1, 1]] 650:[] 651:[[1, 0, 1], [-4, 123, 5], [-4, -123, 5]] 652:[] 653:[[0, 3, 1], [0, -3, 1]] 654:[] 655:[[0, 2, 1], [0, -2, 1]] 656:[] 657:[] 658:[[0, 1, 1], [0, -1, 1]] 659:[] 660:[] 661:[[0, 0, 1], [-1, 2, 1], [-1, -2, 1], [1, 8, 2], [1, -8, 2]] 662:[[0, 2, 1], [0, -2, 1], [1, 2, 1], [1, -2, 1]] 663:[[-1, 5, 1], [-1, -5, 1], [0, 3, 1], [0, -3, 1], [2, 17, 1], [2, -17, 1] ] 664:[[-1, 3, 1], [-1, -3, 1]] 665:[[-3, 112, 2], [-3, -112, 2]] 666:[] 667:[] 668:[] 669:[[-1, 2, 1], [-1, -2, 1]] 670:[[1, 2, 1], [1, -2, 1]] 671:[] 672:[] 673:[[-1, 1, 1], [-1, -1, 1], [-1, 7, 2], [-1, -7, 2]] 674:[] 675:[] 676:[[0, 1, 1], [0, -1, 1]] 677:[] 678:[[-1, 1, 1], [-1, -1, 1]] 679:[] 680:[] 681:[] 682:[[0, 0, 1]] 683:[[0, 3, 1], [0, -3, 1]] 684:[] 685:[] 686:[[1, 2, 1], [1, -2, 1]] 687:[] 688:[] 689:[[0, 0, 1]] 690:[[2, 5, 1], [2, -5, 1], [3, 50, 1], [3, -50, 1]] 691:[[0, 3, 1], [0, -3, 1]] 692:[[-1, 25, 3], [-1, -25, 3]] 693:[] 694:[] 695:[] 696:[] 697:[] 698:[] 699:[] 700:[[-1, 4, 1], [-1, -4, 1]] 701:[] 702:[[-1, 4, 1], [-1, -4, 1]] 703:[[0, 2, 1], [0, -2, 1], [1, 1, 1], [1, -1, 1], [63, 338641, 71], [63, -3 38641, 71], [168, 8223850, 205], [168, -8223850, 205]] 704:[[1, 2, 1], [1, -2, 1]] 705:[[4, 10, 3], [4, -10, 3]] 706:[] 707:[] 708:[] 709:[[0, 1, 1], [0, -1, 1]] 710:[[-1, 2, 1], [-1, -2, 1]] 711:[[0, 2, 1], [0, -2, 1]] 712:[[-1, 5, 1], [-1, -5, 1], [-2, 24, 1], [-2, -24, 1]] 713:[] 714:[[-4, 16, 1], [-4, -16, 1], [0, 2, 1], [0, -2, 1], [1, 187, 5], [1, -187 , 5]] 715:[] 716:[[-1, 3, 1], [-1, -3, 1]] 717:[] 718:[[-1, 0, 1], [0, 2, 1], [0, -2, 1]] 719:[[-1, 2, 1], [-1, -2, 1]] 720:[] 721:[] 722:[[-1, 3, 1], [-1, -3, 1]] 723:[] 724:[[1, 16, 2], [1, -16, 2], [-1, 71, 3], [-1, -71, 3], [-5, 820, 6], [-5, -820, 6], [71, 117115, 51], [71, -117115, 51]] 725:[] 726:[[1, 0, 1]] 727:[] 728:[] 729:[] 730:[] 731:[] 732:[[1, 5, 2], [1, -5, 2], [5, 209, 8], [5, -209, 8]] 733:[] 734:[] 735:[[-1, 1, 1], [-1, -1, 1], [1, 1, 1], [1, -1, 1], [4, 1, 1], [4, -1, 1]] 736:[] 737:[] 738:[[0, 1, 1], [0, -1, 1]] 739:[[1, 0, 1]] 740:[] 741:[[0, 2, 1], [0, -2, 1], [1, 0, 1], [10, 2328, 1], [10, -2328, 1], [-9, 7 67, 4], [-9, -767, 4]] 742:[] 743:[[1, 4, 1], [1, -4, 1]] 744:[[-1, 1, 1], [-1, -1, 1]] 745:[[-2, 10, 1], [-2, -10, 1], [1, 2, 1], [1, -2, 1]] 746:[] 747:[[3, 67, 1], [3, -67, 1], [-1, 4, 2], [-1, -4, 2]] 748:[] 749:[] 750:[[-2, 12, 1], [-2, -12, 1]] 751:[] 752:[] 753:[] 754:[[0, 1, 1], [0, -1, 1]] 755:[] 756:[] 757:[] 758:[] 759:[[0, 2, 1], [0, -2, 1]] 760:[[5, 2086, 13], [5, -2086, 13]] 761:[[0, 3, 1], [0, -3, 1]] 762:[] 763:[] 764:[[0, 1, 1], [0, -1, 1]] 765:[[-2, 23, 3], [-2, -23, 3]] 766:[] 767:[] 768:[[1, 4, 1], [1, -4, 1]] 769:[[-1, 537, 6], [-1, -537, 6], [41, 636063, 51], [41, -636063, 51]] 770:[] 771:[] 772:[[-1, 1, 1], [-1, -1, 1]] 773:[] 774:[] 775:[] 776:[[0, 3, 1], [0, -3, 1], [1, 25, 2], [1, -25, 2], [-1, 209, 4], [-1, -209 , 4]] 777:[[0, 2, 1], [0, -2, 1]] 778:[[2, 10, 1], [2, -10, 1]] 779:[[0, 1, 1], [0, -1, 1], [3, 241, 5], [3, -241, 5]] 780:[] 781:[] 782:[] 783:[] 784:[[0, 0, 1], [-3, 102, 2], [-3, -102, 2], [12, 34950, 23], [12, -34950, 2 3]] 785:[] 786:[[1, 2, 1], [1, -2, 1]] 787:[[-1, 3, 1], [-1, -3, 1]] 788:[[0, 2, 1], [0, -2, 1]] 789:[] 790:[] 791:[] 792:[[-1, 3, 1], [-1, -3, 1], [0, 1, 1], [0, -1, 1]] 793:[] 794:[] 795:[[0, 0, 1], [1, 0, 2]] 796:[[-2, 6, 1], [-2, -6, 1], [-1, 0, 1]] 797:[[0, 3, 1], [0, -3, 1]] 798:[[-1, 1, 1], [-1, -1, 1]] 799:[] 800:[[-1, 1, 1], [-1, -1, 1], [0, 3, 1], [0, -3, 1]] 801:[[-2, 17, 1], [-2, -17, 1], [5, 368, 1], [5, -368, 1]] 802:[] 803:[] 804:[[0, 1, 1], [0, -1, 1], [1, 0, 1]] 805:[[-1, 0, 1]] 806:[] 807:[[0, 2, 1], [0, -2, 1], [3, 2357, 10], [3, -2357, 10]] 808:[] 809:[] 810:[] 811:[[-1, 0, 1], [0, 3, 1], [0, -3, 1]] 812:[] 813:[] 814:[] 815:[] 816:[] 817:[] 818:[] 819:[] 820:[] 821:[[1, 3, 1], [1, -3, 1]] 822:[] 823:[[0, 3, 1], [0, -3, 1]] 824:[] 825:[[-1, 6, 1], [-1, -6, 1], [0, 3, 1], [0, -3, 1]] 826:[[-1, 70, 3], [-1, -70, 3]] 827:[] 828:[[1, 1, 1], [1, -1, 1]] 829:[] 830:[[0, 2, 1], [0, -2, 1]] 831:[[-1, 0, 1], [4, 190, 1], [4, -190, 1]] 832:[] 833:[[-2, 1, 1], [-2, -1, 1]] 834:[[-3, 27, 2], [-3, -27, 2], [-1, 9, 2], [-1, -9, 2]] 835:[[-1, 4, 1], [-1, -4, 1]] 836:[] 837:[[0, 2, 1], [0, -2, 1]] 838:[] 839:[] 840:[[1, 12, 2], [1, -12, 2], [-1, 180, 4], [-1, -180, 4], [4, 9039, 17], [4 , -9039, 17]] 841:[[0, 2, 1], [0, -2, 1], [-1, 25, 2], [-1, -25, 2]] 842:[] 843:[[-1, 4, 1], [-1, -4, 1]] 844:[] 845:[] 846:[[-1, 4, 1], [-1, -4, 1]] 847:[[3, 265, 5], [3, -265, 5]] 848:[] 849:[] 850:[] 851:[] 852:[] 853:[] 854:[[-1, 3, 1], [-1, -3, 1]] 855:[] 856:[[1, 3, 1], [1, -3, 1]] 857:[] 858:[[1, 11, 2], [1, -11, 2]] 859:[] 860:[] 861:[] 862:[] 863:[[2, 12, 1], [2, -12, 1]] 864:[[0, 2, 1], [0, -2, 1]] 865:[] 866:[[0, 2, 1], [0, -2, 1]] 867:[] 868:[] 869:[] 870:[] 871:[] 872:[] 873:[] 874:[[1, 2, 1], [1, -2, 1]] 875:[[13, 6807, 9], [13, -6807, 9]] 876:[] 877:[[-1, 1, 1], [-1, -1, 1]] 878:[[0, 2, 1], [0, -2, 1], [1, 2, 1], [1, -2, 1], [4, 154, 1], [4, -154, 1] ] 879:[[1, 24, 2], [1, -24, 2]] 880:[] 881:[] 882:[[1, 3, 1], [1, -3, 1]] 883:[[-1, 1, 1], [-1, -1, 1]] 884:[] 885:[[-3, 80, 2], [-3, -80, 2]] 886:[] 887:[[1, 0, 1]] 888:[] 889:[[-1, 4, 1], [-1, -4, 1]] 890:[] 891:[[0, 3, 1], [0, -3, 1], [92, 14946963, 209], [92, -14946963, 209]] 892:[] 893:[] 894:[] 895:[[-2, 27, 1], [-2, -27, 1]] 896:[] 897:[[0, 1, 1], [0, -1, 1], [-1, 12, 2], [-1, -12, 2], [3, 56, 2], [3, -56, 2]] 898:[[0, 1, 1], [0, -1, 1]] 899:[] 900:[[0, 3, 1], [0, -3, 1]] 901:[[0, 2, 1], [0, -2, 1]] 902:[[1, 0, 1]] 903:[] 904:[] 905:[[1, 0, 1]] 906:[] 907:[] 908:[] 909:[[-1, 3, 1], [-1, -3, 1]] 910:[[-1, 2, 1], [-1, -2, 1]] 911:[] 912:[] 913:[[-1, 1, 1], [-1, -1, 1]] 914:[] 915:[] 916:[] 917:[[-1, 3, 1], [-1, -3, 1], [0, 1, 1], [0, -1, 1]] 918:[[-1, 3, 1], [-1, -3, 1], [-1, 23, 2], [-1, -23, 2], [14, 4236, 13], [14 , -4236, 13]] 919:[] 920:[[0, 3, 1], [0, -3, 1]] 921:[] 922:[] 923:[] 924:[] 925:[] 926:[[-1, 1, 1], [-1, -1, 1], [1, 1, 1], [1, -1, 1]] 927:[] 928:[] 929:[[0, 2, 1], [0, -2, 1], [1, 0, 1], [7, 1990, 11], [7, -1990, 11]] 930:[] 931:[[0, 0, 1]] 932:[[-1, 14, 2], [-1, -14, 2]] 933:[] 934:[] 935:[[1, 1, 1], [1, -1, 1]] 936:[[0, 0, 1]] 937:[] 938:[] 939:[] 940:[] 941:[] 942:[[0, 1, 1], [0, -1, 1]] 943:[] 944:[[0, 2, 1], [0, -2, 1], [1, 2, 2], [1, -2, 2]] 945:[] 946:[[1, 1, 1], [1, -1, 1]] 947:[] 948:[[-2, 8, 1], [-2, -8, 1], [-1, 4, 1], [-1, -4, 1], [0, 2, 1], [0, -2, 1] , [3, 38, 1], [3, -38, 1], [6, 200, 1], [6, -200, 1], [127, 3151792, 49], [1 27, -3151792, 49], [1, 16, 2], [1, -16, 2], [325, 2360754224, 1058], [325, - 2360754224, 1058]] 949:[[3, 81, 4], [3, -81, 4]] 950:[] 951:[] 952:[[1, 2, 1], [1, -2, 1]] 953:[] 954:[[-1, 4, 1], [-1, -4, 1]] 955:[] 956:[[1, 2, 2], [1, -2, 2]] 957:[] 958:[] 959:[[1, 19, 2], [1, -19, 2]] 960:[] 961:[] 962:[] 963:[[-3, 39, 1], [-3, -39, 1], [-2, 9, 1], [-2, -9, 1]] 964:[] 965:[[2, 3, 1], [2, -3, 1]] 966:[[1, 1, 1], [1, -1, 1]] 967:[] 968:[] 969:[] 970:[[0, 1, 1], [0, -1, 1], [-3, 287, 5], [-3, -287, 5]] 971:[] 972:[[1, 2, 1], [1, -2, 1]] 973:[] 974:[] 975:[] 976:[[-1, 3, 1], [-1, -3, 1], [1, 1, 1], [1, -1, 1]] 977:[] 978:[[0, 2, 1], [0, -2, 1]] 979:[[0, 3, 1], [0, -3, 1], [1, 1, 1], [1, -1, 1]] 980:[[0, 2, 1], [0, -2, 1]] 981:[[-1, 1, 1], [-1, -1, 1]] 982:[] 983:[[1, 1, 1], [1, -1, 1], [-1, 23, 2], [-1, -23, 2]] 984:[[0, 0, 1], [-1, 0, 1], [3, 0, 2]] 985:[] 986:[[0, 3, 1], [0, -3, 1]] 987:[] 988:[] 989:[] 990:[] 991:[[-1, 3, 1], [-1, -3, 1]] 992:[] 993:[[1, 3, 1], [1, -3, 1]] 994:[] 995:[[1, 1, 1], [1, -1, 1]] 996:[[0, 0, 1]] 997:[] 998:[[0, 2, 1], [0, -2, 1]] 999:[] 1000:[[0, 2, 1], [0, -2, 1]] Total time spent: 4660 pari-2.11.2/src/test/32/ellissupersingular0000644000175000017500000000020213201017466017021 0ustar billbill[2, 3, 5, 47, 53, 59] [[1], [1], [0, 0], [0, 0], [0, 0], [0, 0]] [[0], [1], [0, 0], [0, 0], [1, 0], [0, 0]] Total time spent: 377 pari-2.11.2/src/test/32/qfbclassno0000644000175000017500000000016713201017466015232 0ustar billbill10125 11045 4802 1660 2136 2144 1508 2728 15376 7688 15376 76800 7688 8112 32448 641278838681600 Total time spent: 856 pari-2.11.2/src/test/32/nfislocalpower0000644000175000017500000000054413326135265016133 0ustar billbill0 1 0 0 0 1 0 1 1 1 0 0 1 *** at top-level: nfislocalpower(K,"",1,0) *** ^------------------------ *** nfislocalpower: incorrect type in checkprid (t_STR). *** at top-level: nfislocalpower(K,"","",0) *** ^------------------------- *** nfislocalpower: incorrect type in checkprid (t_STR). Total time spent: 4 pari-2.11.2/src/test/32/set0000644000175000017500000000077613036414402013675 0ustar billbill[1, 2, 3] [] [1, 2, 3] List([1, 2, 3]) [1] [-2, 1, 3, 5, 7, x, "1"] [-5, 2, 5, 7, "1"] [5, 7, "1"] 0 1 [-2, 1, 3, x] 3 7 0 3 *** at top-level: setsearch(1,3) *** ^-------------- *** setsearch: incorrect type in setsearch (t_INT). [-5, -2, 1, 2, 3, 5, 7, x, "1"] [3, 4, 5, 6, 7] [2, 3, 4, 5, 6] *** at top-level: setbinop(x->x,X) *** ^---------------- *** setbinop: incorrect type in setbinop [function needs exactly 2 arguments] (t_CLOSURE). Total time spent: 4 pari-2.11.2/src/test/32/multivar-mul0000644000175000017500000000002713326135265015536 0ustar billbillTotal time spent: 3744 pari-2.11.2/src/test/32/det0000644000175000017500000000066013457566441013670 0ustar billbill2645450238786014260762195151127593140777050579745670159192807728014078750989 2064506631325 2645450238786014260762195151127593140777050579745670159192807728014078750989 2064506631325 2645450238786014260762195151127593140777050579745670159192807728014078750989 2064506631325 2645450238786014260762195151127593140777050579745670159192807728014078750989 2064506631325 ((-y + 1)*x^2 + (y^2 - 1)*x + (-y^2 + y))/(y*x) Total time spent: 4 pari-2.11.2/src/test/32/ellisogeny0000644000175000017500000000063613326135265015260 0ustar billbill *** at top-level: ellisogenyapply(x,x) *** ^-------------------- *** ellisogenyapply: incorrect type in checkellisog (t_POL). *** at top-level: ellisogenyapply([f,g,h],1) *** ^-------------------------- *** ellisogenyapply: incorrect type in checkellpt (t_INT). 1 [0, 0, 0, Mod(-15*y^2 - 4, 4*y^3 + 4*y + 12), Mod(14*y + 66, 4*y^3 + 4*y + 1 2)] Total time spent: 84 pari-2.11.2/src/test/32/zncoppersmith0000644000175000017500000000050613036414402015776 0ustar billbill[100000000000] 1 [1339991002000615200] 1 [-997, -955, -913, -871, -829, -787, -745, -703, -661, -619, -577, -535, -49 3, -451, -409, -367, -325, -283, -241, -199, -157, -115, -73, -31, 11, 53, 9 5, 137, 179, 221, 263, 305, 347, 389, 431, 473, 515, 557, 599, 641, 683, 725 , 767, 809, 851, 893, 935, 977] Total time spent: 284 pari-2.11.2/src/test/32/zeta0000644000175000017500000000247513457566342014065 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). 2*5^-1 + 2*5 + 3*5^2 + 3*5^4 + 3*5^5 + 2*5^6 + 5^7 + 4*5^8 + O(5^9) 0.57721614942066140874800424251188396262 - 99.999271841202858157138397118797 159155*I 1.0000000000000000000000000000000000000 1.0000000000000000000000000000000000000 1.0000000000000000000000000000007888609 1.0000000004656629065033784072989233251 1.0000000000000000000000000000007731864 - 1.56474806799752292404311992386390 49803 E-31*I 1.0000000000000000006672083904260744090 - 5.54210563151691387135805391417775 67374 E-19*I -1.8236338315400224657144248914124703368 E1769 + 6.8223788001755144705322033 655798283436 E1768*I 2^-1 + 1 + 2^2 + 2^3 + 2^5 + 2^6 + 2^7 + O(2^9) 1.0000000000000000000000000000000000000 0.E-38 error("overflow in zeta [large negative argument].") 1.6449340668482264364724151666460251892 - 9.37548254315843753702574094567864 97790 E-102*I 100.57794333849687249028215428579024415 -0.50000000000000000000000000000000918939 1.0000000000000006280369842777336909811 0.0085169287778503305423585670283444869362 -0.50000000000000000000000000000000000000 + O(x) 1.0000000000000000000000000000000000000*x^-1 + 0.577215664901532860606512090 08240243104 + O(x) -1.4603545088095868128894991525152980125 - 3.9226461392091517274715314467145 995137*I*x + O(x^2) -2.006356455908584852 Total time spent: 12 pari-2.11.2/src/test/32/graph0000644000175000017500000000544113326135265014206 0ustar billbill echo = 1 ? plotinit(0,500,500) ? plotmove(0,0,0);plotbox(0,500,500) ? plotmove(0,200,150) ? plotcursor(0) [200, 150] ? write("pari.ps",plotexport("ps",0)) ? plotinit(1,700,700) ? plotkill(1) ? plotmove(0,0,900);plotlines(0,900,0) ? plotlines(0,vector(5,k,50*k),vector(5,k,10*k*k)) ? plotmove(0,243,583);plotcursor(0) [243, 583] ? plot(x=-5,5,sin(x),-1,1) 1 x""x_''''''''''''''''''''''''''''''''''_x""x'''''''''''''''''''| | x _ "_ | | x _ _ | | x _ | | _ " | | " x | | x _ | | " | | " x _ | | _ | | " x | ````````````x``````````````````_```````````````````````````````` | " | | " x _ | | _ | | " x | | x _ | | _ " | | " x | | " " x | | "_ " x | -1 |...................x__x".................................."x__x -5 5 ? plotpoints(0,225,334) ? plotpoints(0,vector(10,k,10*k),vector(10,k,5*k*k)) ? write("pari.ps",plotexport("ps",[0,20,20])) ? write("pari.ps",plothexport("ps",x=-5,5,sin(x))) ? write("pari.ps",plothexport("ps",t=0,2*Pi,[sin(5*t),sin(7*t)],1,100)) ? write("pari.ps",plothrawexport("ps",vector(100,k,k),vector(100,k,k*k/100))) ? plotmove(0,50,50);plotrbox(0,50,50) ? plotrline(0,200,150) ? plotcursor(0) [250, 200] ? plotrmove(0,5,5);plotcursor(0) [255, 205] ? plotrpoint(0,20,20) ? plotinit(3,600,600);plotscale(3,-7,7,-2,2);plotcursor(3) [-7, 2] ? plotmove(0,100,100);plotstring(0,Pi) ? plotmove(0,200,200);plotstring(0,"(0,0)") ? write("pari.ps",plotexport("ps",[0,10,10])) ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 5 pari-2.11.2/src/test/32/digits0000644000175000017500000000346613457566437014413 0ustar billbill[] [] 0 [7, 8, 8, 8, 6, 0, 9, 0, 5, 2, 2, 1, 0, 1, 1, 8, 0, 5, 4, 1, 1, 7, 2, 8, 5, 6, 5, 2, 8, 2, 7, 8, 6, 2, 2, 9, 6, 7, 3, 2, 0, 6, 4, 3, 5, 1, 0, 9, 0, 2, 3 , 0, 0, 4, 7, 7, 0, 2, 7, 8, 9, 3, 0, 6, 6, 4, 0, 6, 2, 5] 1234560123456012345601234560123456012345601234560123456012345601234560123456 012345601234560123456012 3 -3 0 12 135 1938780 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0] [[0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0 , 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0 , 0, 0, 1, 0, 1, 0, 0, 1, 0, 0]] [[1], [0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 , 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 , 0, 1]] [[], [1]] *** at top-level: binary(I) *** ^--------- *** binary: incorrect type in binary (t_COMPLEX). [16, 21, 21, 21, 19, 27, 43, 45, 45, 39] [1, 0, 3] [232830, 2764705149] 4 1 3 2 74565 90144042671290236482932261665 74565 219 13221424875890015231 219 Total time spent: 69 pari-2.11.2/src/test/32/padic0000644000175000017500000001067113457601746014175 0ustar billbill+oo [O(2)]~ *** at top-level: padicappr(x^2+1+O(3),Mod(-1+O(5^10),y^2-2)) *** ^------------------------------------------- *** padicappr: inconsistent moduli in Zp_to_Z: 5 != 3 *** at top-level: padicappr(x^2+1+O(3),-1+O(5^10)) *** ^-------------------------------- *** padicappr: inconsistent moduli in Zp_to_Z: 5 != 3 [Mod(0, t)]~ [Mod(0, t^2 + 1)]~ [(1 + O(3^5))*y^2 + O(3^5)*y + O(3^5) 1] [(1 + O(5^2))*x + O(5^2) 1] [(1 + O(5^2))*x + O(5^2) 1] [ (1 + O(5^2))*x + O(5^2) 1] [ (1 + O(5^2))*x + O(5^2) 1] [(1 + O(5^2))*x + (1 + O(5^2)) 1] [(1 + O(5^2))*x + (1 + O(5^2)) 1] [(1 + O(5^2))*x + (1 + O(5^2)) 1] [(1 + O(5^2))*x + (2 + O(5^2)) 1] [(1 + O(5^2))*x + O(5^2) 2] [(1 + O(2^5))*x + O(2^5) 1] [303091841983800080655794283008425100039742205409907463050265866099342335310 9435450473759394409290772958513969209043309887654107823563961950120902162328 9769326760830012577046380799009644065843091379678844848336197237093057023804 6689848912926486505130709901883062497124814860382257802988956439425088932461 0372025296688642620365911220110991569990328464459735660494309717728461213007 1801499708339544755377536878289360381720619549093067863866419820272280136477 2830800728859838435544923858759881340490985695391715382902245978494662272462 6052864155393228763598731308273292630444845297138100310999495119765776446322 3860052732483765519446500500094346234790611688099389032815052584811119320550 3704669618458110652816974131143493927907230211763195122366400692171033393720 271195569191, 13020836829112671085985220226774471665002775641446996088876884 3691338423847199876670450857336997350275120427670497827105902457829900805568 9719472368109783134615365374621272645318492298469870785155840876721739513480 5863213246980524738313176449660582809667252629484206997514702295002515061510 0684360909834392213592414944152124335972138550682495171014579333479279921333 5904066365587070683781105745761987654966795582331907184529593280396827369610 2019154579782144905432984081972843049020762285632803482844786928852456176727 9344982547780680381242398549057381848394717649769513041214735182126715458420 8350305350756518594813992253867533694908369935455537375264348437017294628673 7633210413290943225901496946252789071904264368534914051665187493778714162848 7537382321251210717887612]~ [2, 2, 2] [3, 2, 2] [6, 2, 2] [7, 2, 2] [10, 2, 2] [2, 2, 3] [3, 2, 3] [4, 2, 3] [5, 2, 3] [6, 2, 3] [7, 2, 3] [10, 2, 3] [2, 3, 3] [3, 3, 3] [4, 3, 3] [5, 3, 3] [6, 3, 3] [7, 3, 3] [8, 3, 3] [9, 3, 3] [10, 3, 3] [2, 11, 3] [3, 11, 3] [4, 11, 3] [5, 11, 3] [6, 11, 3] [7, 11, 3] [8, 11, 3] [9, 11, 3] [10, 11, 3] [2, 18446744073709551629, 3] [3, 18446744073709551629, 3] [4, 18446744073709551629, 3] [5, 18446744073709551629, 3] [6, 18446744073709551629, 3] [7, 18446744073709551629, 3] [8, 18446744073709551629, 3] [9, 18446744073709551629, 3] [10, 18446744073709551629, 3] [2^3 + O(2^6), 1 + 2^2 + O(2^6), 1 + 2 + 2^4 + 2^5 + O(2^6)]~ [Mod((1 + 2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + O(2^10))*y + ( 1 + 2^2 + 2^6 + 2^7 + O(2^10)), y^2 + y + 1), Mod((1 + 2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + O(2^10))*y + (1 + 2 + 2^4 + 2^5 + 2^8 + O(2^1 0)), y^2 + y + 1)]~ 1/2 3 + 3^2 + O(3^5) 2 + 2^2 + O(2^5) 1 + 2*3^2 + 3^3 + 3^4 + O(3^5) 1 + O(x) 3 + 2*3^3 + 3^4 + O(3^5) O(x) 3 + O(3^5) O(x) 3^-1 + O(3^3) O(x) 1 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + O(3^5) 1 + 2 + 2^2 + 2^3 + O(2^4) 18446744073709551627 + 18446744073709551628*18446744073709551629 + O(1844674 4073709551629^2) 3074457345618258605 + 15372286728091293024*18446744073709551629 + O(18446744 073709551629^2) 2*3^2 + 2*3^3 + O(3^5) 1 + O(2) 1 + 2^2 + O(2^3) 1 + 2 + 2^2 + 2^3 + 2^5 + 2^6 + O(2^7) 1 + 2 + 2^2 + 2^3 + 2^5 + 2^6 + 2^7 + O(2^8) 1 + 2^2 + 2^4 + O(2^5) 1 + 2^2 + 2^4 + 2^5 + O(2^6) 2 + 5 + 2*5^2 + O(5^3) 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^9 + O(2^10) 3 + 2*3^2 + 3^3 + 2*3^5 + 2*3^6 + 3^8 + O(3^10) 5 + 2*5^2 + 4*5^3 + 2*5^4 + 5^6 + 4*5^7 + 2*5^8 + 3*5^9 + O(5^10) 101 + 50*101^2 + 84*101^3 + 41*101^4 + 89*101^5 + 4*101^6 + 34*101^7 + 10*10 1^8 + 77*101^9 + O(101^10) []~ []~ []~ [4, 0, 0, 0] [+oo, 2, 1/2, 1/2] [+oo, 2, 1/2, 1/2] [(1 + O(2^3))*x^3 + (2 + 2^2 + O(2^3))*x^2 + O(2^3)*x + O(2^3) 1] [(1 + O(2^3))*x^6 + (2 + O(2^3))*x^5 + (2 + 2^2 + O(2^3))*x^4 + (2^2 + O(2^3 ))*x^3 + O(2^3)*x^2 + O(2^3)*x + O(2^3) 1] [ (1 + O(2^2))*x + O(2^2) 2] [(2 + O(2^2))*x^2 + O(2^2)*x + (1 + O(2^2)) 1] [O(2^2)]~ [O(3^10)]~ [4, 4, 4, 4, 4, 4, 4, 4] [4, 4, 4, 4, 4, 4, 4, 4] Total time spent: 8 pari-2.11.2/src/test/32/nfeltembed0000644000175000017500000000147113326135265015211 0ustar billbill[1.2599210498948731647672106072782283506, -0.6299605249474365823836053036391 1417529 + 1.0911236359717214035600726141898088813*I] [-0.62996052494743658238360530363911417529 + 1.09112363597172140356007261418 98088813*I] [1.2599210498948731647672106072782283506, -0.6299605249474365823836053036391 1417529 + 1.0911236359717214035600726141898088813*I] *** at top-level: nfeltembed(nf,2,[1..3]) *** ^----------------------- *** nfeltembed: domain error in nfeltembed: index > 2 [-1.3160740129524924608192189017969990552, 1.3160740129524924608192189017969 990552, 0.E-57 + 1.3160740129524924608192189017969990552*I] *** at top-level: nfeltembed(nf,y,[1,2,4]) *** ^------------------------ *** nfeltembed: inconsistent variables in nf_to_scalar_or_basis, y != x. Total time spent: 0 pari-2.11.2/src/test/32/extract0000644000175000017500000002403713326135265014561 0ustar billbill[36][37][38][39][40][41][42][43][44][45][46][47][48][49][50][51][52][53][54] [55][56][57][58][59][60][61][62][63][64][65][66][67][68][69][70][71][72][73] [74][75][76][77][78][79][80][81][82][83][84][85][86][87][88][89][90][91][92] [93][94][95][96][97][98][99][100] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] [2, 3, 4] [99, 98, 97] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] [1, 100] [100, 1] [3, 5] [0 1 0] [0 0 1] [0] [1] [0, 2] [0, 2] [0, 0] [0, 0] [0, 0] [0, 0] Vec [1] [1, 0] [1/x] [5, 4, 3, 2, 1] [1, 2] [1, 2] [1, 2] [1, 2, 3] [1, 2, 3, 4, 5] ["a", "b"] [[1, 3]~, [2, 4]~, [3, 5]~] ["e_INV", "gdiv", 0] (x)->my(f=Vec);f(x,4) [1, 0, 0, 0] [1, 0, 0, 0] [1/x, 0, 0, 0] [5, 4, 3, 2] [1, 2, 0, 0] [1, 2, 0, 0] [1, 2, 0, 0] [1, 2, 3, 0] [1, 2, 3, 4] error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") (x)->my(f=Vec);f(x,-4) [0, 0, 0, 1] [0, 0, 1, 0] [0, 0, 0, 1/x] [5, 4, 3, 2] [0, 0, 1, 2] [0, 0, 1, 2] [0, 0, 1, 2] [0, 1, 2, 3] [1, 2, 3, 4] error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") Vecrev [1] [0, 1] [1/x] [1, 2, 3, 4, 5] [2, 1] [2, 1] [2, 1] [3, 2, 1] [5, 4, 3, 2, 1] ["b", "a"] [[3, 5]~, [2, 4]~, [1, 3]~] [0, "gdiv", "e_INV"] (x)->my(f=Vecrev);f(x,4) [1, 0, 0, 0] [0, 1, 0, 0] [1/x, 0, 0, 0] [2, 3, 4, 5] [2, 1, 0, 0] [2, 1, 0, 0] [2, 1, 0, 0] [3, 2, 1, 0] [4, 3, 2, 1] error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") (x)->my(f=Vecrev);f(x,-4) [0, 0, 0, 1] [0, 0, 0, 1] [0, 0, 0, 1/x] [2, 3, 4, 5] [0, 0, 2, 1] [0, 0, 2, 1] [0, 0, 2, 1] [0, 3, 2, 1] [4, 3, 2, 1] error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") Col [1]~ [1, 0]~ [1/x]~ [5, 4, 3, 2, 1]~ [1, 2]~ [1, 2]~ [1, 2]~ [1, 2, 3]~ [1, 2, 3, 4, 5]~ ["a", "b"]~ [[1, 2, 3], [3, 4, 5]]~ ["e_INV", "gdiv", 0]~ (x)->my(f=Col);f(x,4) [1, 0, 0, 0]~ [1, 0, 0, 0]~ [1/x, 0, 0, 0]~ [5, 4, 3, 2]~ [1, 2, 0, 0]~ [1, 2, 0, 0]~ [1, 2, 0, 0]~ [1, 2, 3, 0]~ [1, 2, 3, 4]~ error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") (x)->my(f=Col);f(x,-4) [0, 0, 0, 1]~ [0, 0, 1, 0]~ [0, 0, 0, 1/x]~ [5, 4, 3, 2]~ [0, 0, 1, 2]~ [0, 0, 1, 2]~ [0, 0, 1, 2]~ [0, 1, 2, 3]~ [1, 2, 3, 4]~ error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") Colrev [1]~ [0, 1]~ [1/x]~ [1, 2, 3, 4, 5]~ [2, 1]~ [2, 1]~ [2, 1]~ [3, 2, 1]~ [5, 4, 3, 2, 1]~ ["b", "a"]~ [[3, 4, 5], [1, 2, 3]]~ [0, "gdiv", "e_INV"]~ (x)->my(f=Colrev);f(x,4) [1, 0, 0, 0]~ [0, 1, 0, 0]~ [1/x, 0, 0, 0]~ [2, 3, 4, 5]~ [2, 1, 0, 0]~ [2, 1, 0, 0]~ [2, 1, 0, 0]~ [3, 2, 1, 0]~ [4, 3, 2, 1]~ error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") (x)->my(f=Colrev);f(x,-4) [0, 0, 0, 1]~ [0, 0, 0, 1]~ [0, 0, 0, 1/x]~ [2, 3, 4, 5]~ [0, 0, 2, 1]~ [0, 0, 2, 1]~ [0, 0, 2, 1]~ [0, 3, 2, 1]~ [4, 3, 2, 1]~ error("incorrect type in gtovec (t_STR).") error("incorrect type in gtovec (t_MAT).") error("incorrect type in gtovec (t_ERROR).") Vecsmall Vecsmall([1]) Vecsmall([1, 0]) error("incorrect type in vectosmall (t_RFRAC).") Vecsmall([5, 4, 3, 2, 1]) Vecsmall([1, 2]) Vecsmall([1, 2]) Vecsmall([1, 2]) Vecsmall([1, 2, 3]) Vecsmall([1, 2, 3, 4, 5]) Vecsmall([97, 98]) error("incorrect type in vectosmall (t_MAT).") error("incorrect type in vectosmall (t_ERROR).") (x)->my(f=Vecsmall);f(x,4) Vecsmall([1, 0, 0, 0]) Vecsmall([1, 0, 0, 0]) error("incorrect type in gtovecsmall (t_RFRAC).") Vecsmall([5, 4, 3, 2]) Vecsmall([1, 2, 0, 0]) Vecsmall([1, 2, 0, 0]) Vecsmall([1, 2, 0, 0]) Vecsmall([1, 2, 3, 0]) Vecsmall([1, 2, 3, 4]) error("incorrect type in gtovecsmall (t_STR).") error("incorrect type in gtovecsmall (t_MAT).") error("incorrect type in gtovecsmall (t_ERROR).") (x)->my(f=Vecsmall);f(x,-4) Vecsmall([0, 0, 0, 1]) Vecsmall([0, 0, 1, 0]) error("incorrect type in gtovecsmall (t_RFRAC).") Vecsmall([5, 4, 3, 2]) Vecsmall([0, 0, 1, 2]) Vecsmall([0, 0, 1, 2]) Vecsmall([0, 0, 1, 2]) Vecsmall([0, 1, 2, 3]) Vecsmall([1, 2, 3, 4]) error("incorrect type in gtovecsmall (t_STR).") error("incorrect type in gtovecsmall (t_MAT).") error("incorrect type in gtovecsmall (t_ERROR).") (x)->component(x,2) error("incorrect type in component [leaf] (t_INT).") 1 x 2 2 2 2 2 2 error("incorrect type in component [leaf] (t_STR).") [2, 4]~ 0 (x)->component(x,10) error("incorrect type in component [leaf] (t_INT).") error("non-existent component: index > 2") error("non-existent component: index > 2") error("non-existent component: index > 5") error("non-existent component: index > 2") error("non-existent component: index > 2") error("non-existent component: index > 2") error("non-existent component: index > 3") error("non-existent component: index > 5") error("incorrect type in component [leaf] (t_STR).") error("non-existent component: index > 3") error("non-existent component: index > 2") (x)->polcoef(x,-1) 0 0 1 0 0 error("incorrect type in polcoef (t_VEC).") error("incorrect type in polcoef (t_VECSMALL).") error("incorrect type in polcoef (t_LIST).") error("incorrect type in polcoef (t_LIST).") error("incorrect type in polcoef (t_STR).") error("incorrect type in polcoef (t_MAT).") error("incorrect type in polcoef (t_ERROR).") (x)->polcoef(x,2) 0 0 0 3 2 error("incorrect type in polcoef (t_VEC).") error("incorrect type in polcoef (t_VECSMALL).") error("incorrect type in polcoef (t_LIST).") error("incorrect type in polcoef (t_LIST).") error("incorrect type in polcoef (t_STR).") error("incorrect type in polcoef (t_MAT).") error("incorrect type in polcoef (t_ERROR).") (x)->polcoef(x,10) 0 0 0 0 error("domain error in polcoef: degree > 2") error("incorrect type in polcoef (t_VEC).") error("incorrect type in polcoef (t_VECSMALL).") error("incorrect type in polcoef (t_LIST).") error("incorrect type in polcoef (t_LIST).") error("incorrect type in polcoef (t_STR).") error("incorrect type in polcoef (t_MAT).") error("incorrect type in polcoef (t_ERROR).") 0 O(x^2) 1 + x + O(x^2) y + O(y^2) 0 9 + 18*x + 36*x^2 + O(x^3) Vecsmall([4, 5, 3]) *** at top-level: vecextract([1],11) *** ^------------------ *** vecextract: incorrect type in vecextract [mask too large] (t_INT). *** at top-level: vecextract([1],"1..2") *** ^---------------------- *** vecextract: incorrect type in vecextract [incorrect range] (t_STR). *** at top-level: vecextract([1],1/2) *** ^------------------- *** vecextract: incorrect type in vecextract [mask] (t_FRAC). *** at top-level: vecextract(1,1) *** ^--------------- *** vecextract: incorrect type in extract (t_INT). *** at top-level: vecextract(matid(2),[3],[]) *** ^--------------------------- *** vecextract: incorrect type in vecextract [incorrect mask] (t_VEC). *** at top-level: [1][2..3] *** ^--------- *** _[_.._]: inconsistent dimensions in _[..]. *** at top-level: [1][-10..3] *** ^----------- *** _[_.._]: inconsistent dimensions in _[..]. *** at top-level: 1[1..2] *** ^------- *** _[_.._]: incorrect type in _[_.._] (t_INT). *** at top-level: [1/2..1] *** ^---- *** [_.._]: incorrect type in [_.._] (t_FRAC). *** at top-level: [1..1/2] *** ^------ *** [_.._]: incorrect type in [_.._] (t_FRAC). Total time spent: 2 pari-2.11.2/src/test/32/size0000644000175000017500000000026213201017466014045 0ustar billbill0 1 1 1 0 3 3 [1, 3] [3, 1] [2, 3] *** at top-level: matsize(1) *** ^---------- *** matsize: incorrect type in matsize (t_INT). 1 1 1 Total time spent: 0 pari-2.11.2/src/test/32/norm0000644000175000017500000000172013201017466014046 0ustar billbill1/4 *** at top-level: norml2(quadgen(5)) *** ^------------------ *** norml2: incorrect type in gnorml2 (t_QUAD). 1 1 1/2 1 (x)->normlp(x,1) 6 10 21 2.4142135623730950488016887242096980786 1.6180339887498948482045868343656381177 5 (x)->normlp(x,2) 3.7416573867739413855837487323165493018 5.4772255750516611345696978280080213395 9.5393920141694564915262158602322654026 1.7320508075688772935274463415058723670 1.6180339887498948482045868343656381177 5 (x)->normlp(x,2.5) 3.4585606563304871862271371438840799750 4.9402040006184485884345102892270748966 8.2976320964215261445777796306034959974 1.6273657035458510939647914767411763647 1.6180339887498948482045868343656381177 5 normlp 3 4 6 1.4142135623730950488016887242096980786 1.6180339887498948482045868343656381177 5.0000000000000000000000000000000000000 422481 1 *** at top-level: normlp(-1,-oo) *** ^-------------- *** normlp: domain error in normlp: p <= 0 Total time spent: 1 pari-2.11.2/src/test/32/classpoly0000644000175000017500000000000013201017466015072 0ustar billbillpari-2.11.2/src/test/32/round0000644000175000017500000000315213036414402014220 0ustar billbill1 1 2 -1 error("incorrect type in gceil (t_INTMOD).") error("incorrect type in gceil (t_QUAD).") error("incorrect type in gceil (t_POLMOD).") x error("incorrect type in gceil (t_SER).") 0 [2, 2] [1, 0; 0, 1] error("incorrect type in gceil (t_STR).") 1 1 -2 error("incorrect type in gfloor (t_INTMOD).") error("incorrect type in gfloor (t_QUAD).") error("incorrect type in gfloor (t_POLMOD).") x error("incorrect type in gfloor (t_SER).") 0 [1, 2] [0, 0; 0, 0] error("incorrect type in gfloor (t_STR).") 0 0.60000000000000000000000000000000000000 2/3 error("incorrect type in gfloor (t_INTMOD).") error("incorrect type in gfloor (t_QUAD).") error("incorrect type in gfloor (t_POLMOD).") 0 error("incorrect type in gfloor (t_SER).") 1/x [1/3, 0] [1/3, 0; 0, 1/3] error("incorrect type in gfloor (t_STR).") 1 2 -1 Mod(1, 3) w Mod(x + 1, x^2 + 1/2) x 1 + O(x^2) 1/x [1, 2] [0, 0; 0, 0] error("incorrect type in ground (t_STR).") [1, -oo] [2, -2] [-1, -oo] [Mod(1, 3), -oo] [w, -oo] [Mod(x + 1, x^2 + 1/2), -oo] [x, -oo] [1 + O(x^2), -oo] [1/x, -oo] [[1, 2], -oo] [[0, 0; 0, 0], -oo] error("incorrect type in grndtoi (t_STR).") 1 1 -1 error("incorrect type in gtrunc (t_INTMOD).") error("incorrect type in gtrunc (t_QUAD).") error("incorrect type in gtrunc (t_POLMOD).") x 1/3*x + 4/3 0 [1, 2] [0, 0; 0, 0] error("incorrect type in gtrunc (t_STR).") [1, -oo] [1, -1] [-1, -oo] error("incorrect type in gtrunc (t_INTMOD).") error("incorrect type in gtrunc (t_QUAD).") error("incorrect type in gtrunc (t_POLMOD).") [x, -oo] [1/3*x + 4/3, -oo] [0, -oo] [[1, 2], -oo] [[0, 0; 0, 0], -oo] error("incorrect type in gtrunc (t_STR).") Total time spent: 4 pari-2.11.2/src/test/32/lift0000644000175000017500000000143013201017466014027 0ustar billbilllift 1 2 x 3 8/3 x x + 2 1 + 2*x + 3*x^2 + O(x^4) (a)->lift(a,'x) 1 Mod(2, 3) x 3 + O(3^3) 2*3^-1 + 2 + O(3) x Mod(1, 3)*x + Mod(2, 3) Mod(1, 5) + Mod(2, 5)*x + Mod(3, 5)*x^2 + O(x^4) (a)->lift(a,'y) 1 Mod(2, 3) x 3 + O(3^3) 2*3^-1 + 2 + O(3) Mod(x, x^2) Mod(1, 3)*x + Mod(2, 3) Mod(1, 5) + Mod(2, 5)*x + Mod(3, 5)*x^2 + O(x^4) (a)->lift(a,'z) 1 Mod(2, 3) x 3 + O(3^3) 2*3^-1 + 2 + O(3) Mod(x, x^2) Mod(1, 3)*x + Mod(2, 3) Mod(1, 5) + Mod(2, 5)*x + Mod(3, 5)*x^2 + O(x^4) centerlift 1 -1 x 3 -1/3 x x - 1 1 + 2*x - 2*x^2 + O(x^4) liftall 1 2 x 3 8/3 x x + 2 1 + 2*x + 3*x^2 + O(x^4) liftint 1 2 x 3 8/3 Mod(x, x^2) x + 2 1 + 2*x + 3*x^2 + O(x^4) liftpol 1 Mod(2, 3) x 3 + O(3^3) 2*3^-1 + 2 + O(3) x Mod(1, 3)*x + Mod(2, 3) Mod(1, 5) + Mod(2, 5)*x + Mod(3, 5)*x^2 + O(x^4) Total time spent: 0 pari-2.11.2/src/test/32/subcyclo0000644000175000017500000000014513201017466014716 0ustar billbillx - 1 [x^2 + 2, x^2 + 262, x^2 - 262, x^2 - 2, x^2 - 131, x^2 + 1, x^2 + x + 33] Total time spent: 4 pari-2.11.2/src/test/32/qfisom0000644000175000017500000000113113326135265014373 0ustar billbill[2, [Mat(-1)]] 78382080 78382080 78382080 78382080 78382080 78382080 339738624 339738624 339738624 339738624 OK OK OK OK OK 3840 OK 3840 OK OK "Group([[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1]], [[0, 0, 0, 1], [0, 1, 1, 0], [0, -1, 0, 0], [1, -1, -1, 0]], [[-1, 0, 0, 0], [0, 0, -1, 1], [-1, 0, 1, 0], [-1, 1, 1, 0]])" "MatrixGroup<4, Integers() |[[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0 , 0, 0, -1]], [[0, 0, 0, 1], [0, 1, 1, 0], [0, -1, 0, 0], [1, -1, -1, 0]], [ [-1, 0, 0, 0], [0, 0, -1, 1], [-1, 0, 1, 0], [-1, 1, 1, 0]]>" [12, 4] [12, 4] [12, 4] Total time spent: 1372 pari-2.11.2/src/test/32/eval0000644000175000017500000000023113326135265014024 0ustar billbillVecsmall([1, 2, 3]) *** syntax error, unexpected '=', expecting $end: = *** ^- Total time spent: 0 pari-2.11.2/src/test/32/bit0000644000175000017500000001675213036414402013661 0ustar billbill4 3 2 3 100 *** at top-level: hammingweight(I) *** ^---------------- *** hammingweight: incorrect type in hammingweight (t_COMPLEX). [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] #bitand [0, 0, 0] [0, 3, 0] [0, -3, 0] [0, 36893488147419103231, 0] [0, 340282366920938463481821351505477763073, 0] [0, -340282366920938463481821351505477763073, 0] [0, I, error("forbidden bitwise and t_INT , t_COMPLEX.")] [3, 3, 3] [3, -3, 1] [3, 36893488147419103231, 3] [3, 340282366920938463481821351505477763073, 1] [3, -340282366920938463481821351505477763073, 3] [3, I, error("forbidden bitwise and t_INT , t_COMPLEX.")] [-3, -3, -3] [-3, 36893488147419103231, 36893488147419103229] [-3, 340282366920938463481821351505477763073, 340282366920938463481821351505 477763073] [-3, -340282366920938463481821351505477763073, -3402823669209384634818213515 05477763075] [-3, I, error("forbidden bitwise and t_INT , t_COMPLEX.")] [36893488147419103231, 36893488147419103231, 36893488147419103231] [36893488147419103231, 340282366920938463481821351505477763073, 184467440737 09551617] [36893488147419103231, -340282366920938463481821351505477763073, 18446744073 709551615] [36893488147419103231, I, error("forbidden bitwise and t_INT , t_COMPLEX.")] [340282366920938463481821351505477763073, 3402823669209384634818213515054777 63073, 340282366920938463481821351505477763073] [340282366920938463481821351505477763073, -340282366920938463481821351505477 763073, 1] [340282366920938463481821351505477763073, I, error("forbidden bitwise and t_ INT , t_COMPLEX.")] [-340282366920938463481821351505477763073, -34028236692093846348182135150547 7763073, -340282366920938463481821351505477763073] [-340282366920938463481821351505477763073, I, error("forbidden bitwise and t _INT , t_COMPLEX.")] [I, I, error("forbidden bitwise and t_COMPLEX , t_COMPLEX.")] #bitnegimply [0, 0, 0] [0, 3, 0] [0, -3, 0] [0, 36893488147419103231, 0] [0, 340282366920938463481821351505477763073, 0] [0, -340282366920938463481821351505477763073, 0] [0, I, error("forbidden bitwise negated imply t_INT , t_COMPLEX.")] [3, 3, 0] [3, -3, 2] [3, 36893488147419103231, 0] [3, 340282366920938463481821351505477763073, 2] [3, -340282366920938463481821351505477763073, 0] [3, I, error("forbidden bitwise negated imply t_INT , t_COMPLEX.")] [-3, -3, 0] [-3, 36893488147419103231, -36893488147419103232] [-3, 340282366920938463481821351505477763073, -34028236692093846348182135150 5477763076] [-3, -340282366920938463481821351505477763073, 34028236692093846348182135150 5477763072] [-3, I, error("forbidden bitwise negated imply t_INT , t_COMPLEX.")] [36893488147419103231, 36893488147419103231, 0] [36893488147419103231, 340282366920938463481821351505477763073, 184467440737 09551614] [36893488147419103231, -340282366920938463481821351505477763073, 18446744073 709551616] [36893488147419103231, I, error("forbidden bitwise negated imply t_INT , t_C OMPLEX.")] [340282366920938463481821351505477763073, 3402823669209384634818213515054777 63073, 0] [340282366920938463481821351505477763073, -340282366920938463481821351505477 763073, 340282366920938463481821351505477763072] [340282366920938463481821351505477763073, I, error("forbidden bitwise negate d imply t_INT , t_COMPLEX.")] [-340282366920938463481821351505477763073, -34028236692093846348182135150547 7763073, 0] [-340282366920938463481821351505477763073, I, error("forbidden bitwise negat ed imply t_INT , t_COMPLEX.")] [I, I, error("forbidden bitwise negated imply t_COMPLEX , t_COMPLEX.")] #bitor [0, 0, 0] [0, 3, 3] [0, -3, -3] [0, 36893488147419103231, 36893488147419103231] [0, 340282366920938463481821351505477763073, 3402823669209384634818213515054 77763073] [0, -340282366920938463481821351505477763073, -34028236692093846348182135150 5477763073] [0, I, error("forbidden bitwise or t_INT , t_COMPLEX.")] [3, 3, 3] [3, -3, -1] [3, 36893488147419103231, 36893488147419103231] [3, 340282366920938463481821351505477763073, 3402823669209384634818213515054 77763075] [3, -340282366920938463481821351505477763073, -34028236692093846348182135150 5477763073] [3, I, error("forbidden bitwise or t_INT , t_COMPLEX.")] [-3, -3, -3] [-3, 36893488147419103231, -1] [-3, 340282366920938463481821351505477763073, -3] [-3, -340282366920938463481821351505477763073, -1] [-3, I, error("forbidden bitwise or t_INT , t_COMPLEX.")] [36893488147419103231, 36893488147419103231, 36893488147419103231] [36893488147419103231, 340282366920938463481821351505477763073, 340282366920 938463500268095579187314687] [36893488147419103231, -340282366920938463481821351505477763073, -3402823669 20938463463374607431768211457] [36893488147419103231, I, error("forbidden bitwise or t_INT , t_COMPLEX.")] [340282366920938463481821351505477763073, 3402823669209384634818213515054777 63073, 340282366920938463481821351505477763073] [340282366920938463481821351505477763073, -340282366920938463481821351505477 763073, -1] [340282366920938463481821351505477763073, I, error("forbidden bitwise or t_I NT , t_COMPLEX.")] [-340282366920938463481821351505477763073, -34028236692093846348182135150547 7763073, -340282366920938463481821351505477763073] [-340282366920938463481821351505477763073, I, error("forbidden bitwise or t_ INT , t_COMPLEX.")] [I, I, error("forbidden bitwise or t_COMPLEX , t_COMPLEX.")] #bitxor [0, 0, 0] [0, 3, 3] [0, -3, -3] [0, 36893488147419103231, 36893488147419103231] [0, 340282366920938463481821351505477763073, 3402823669209384634818213515054 77763073] [0, -340282366920938463481821351505477763073, -34028236692093846348182135150 5477763073] [0, I, error("forbidden bitwise xor t_INT , t_COMPLEX.")] [3, 3, 0] [3, -3, -2] [3, 36893488147419103231, 36893488147419103228] [3, 340282366920938463481821351505477763073, 3402823669209384634818213515054 77763074] [3, -340282366920938463481821351505477763073, -34028236692093846348182135150 5477763076] [3, I, error("forbidden bitwise xor t_INT , t_COMPLEX.")] [-3, -3, 0] [-3, 36893488147419103231, -36893488147419103230] [-3, 340282366920938463481821351505477763073, -34028236692093846348182135150 5477763076] [-3, -340282366920938463481821351505477763073, 34028236692093846348182135150 5477763074] [-3, I, error("forbidden bitwise xor t_INT , t_COMPLEX.")] [36893488147419103231, 36893488147419103231, 0] [36893488147419103231, 340282366920938463481821351505477763073, 340282366920 938463481821351505477763070] [36893488147419103231, -340282366920938463481821351505477763073, -3402823669 20938463481821351505477763072] [36893488147419103231, I, error("forbidden bitwise xor t_INT , t_COMPLEX.")] [340282366920938463481821351505477763073, 3402823669209384634818213515054777 63073, 0] [340282366920938463481821351505477763073, -340282366920938463481821351505477 763073, -2] [340282366920938463481821351505477763073, I, error("forbidden bitwise xor t_ INT , t_COMPLEX.")] [-340282366920938463481821351505477763073, -34028236692093846348182135150547 7763073, 0] [-340282366920938463481821351505477763073, I, error("forbidden bitwise xor t _INT , t_COMPLEX.")] [I, I, error("forbidden bitwise xor t_COMPLEX , t_COMPLEX.")] #bitneg [0, 36893488147419103231, -1] [3, 36893488147419103228, -4] [-3, 2, 2] [36893488147419103231, 0, -36893488147419103232] [340282366920938463481821351505477763073, 18446744073709551614, -34028236692 0938463481821351505477763074] [-340282366920938463481821351505477763073, 18446744073709551616, 34028236692 0938463481821351505477763072] error("incorrect type in bitwise negation (t_COMPLEX).") 1 1 *** at top-level: bitneg(1,-2) *** ^------------ *** bitneg: domain error in bitwise negation: exponent < -1 340282366920938463463374607431768211454 Total time spent: 0 pari-2.11.2/src/test/32/bestappr0000644000175000017500000000063313326135265014723 0ustar billbill-1/7 -1/6 -1/7 [] -1/7 -1/7 [] "t_INT" 3/31 -1/48 (x^3 + 1)/(x^10 + 2) [] 1/(x + 1) 1/(x + 1) [] 1/(x^6 + 1) (x - 2)/(-x^2 + x) x^2/(-x + 1) 1/(-x^5 + x^4) x^10/(-x^11 + 11*x^10 - 55*x^9 + 165*x^8 - 330*x^7 + 462*x^6 - 462*x^5 + 330 *x^4 - 165*x^3 + 55*x^2 - 11*x + 1) (x^5 + x + 2)/(-x^11 + 11*x^10 - 55*x^9 + 165*x^8 - 330*x^7 + 462*x^6 - 462* x^5 + 330*x^4 - 165*x^3 + 55*x^2 - 11*x + 1) Total time spent: 1 pari-2.11.2/src/test/32/version0000644000175000017500000000003713447371554014575 0ustar billbill[2, 11, 2] Total time spent: 0 pari-2.11.2/src/test/32/qfsolve0000644000175000017500000000245613326135265014567 0ustar billbilldim=3 [2, 42762409] [3, 3617] [4, 5] [5, 43] [6, 31] [9, 5] [11, 7] [12, 3] [13, 17] [14, 19] [15, 73] [16, 79] [17, 38287] [18, 3774601] [19, 7] [20, 3] [21, 61] [22, 3] [23, 229] [24, 7] [25, 3] [27, 68196433] [28, 2393] [29, 13] [30, 145963897] [31, 71] [33, 433] [34, 3] [35, 409] [36, 3] [37, -1] [38, 11483] [41, 11] [44, -1] [45, 281] [46, 4363] [47, -1] [48, 7] [49, 41] [52, 5965507] [53, 13] [56, 135319] [57, 2473301] [58, 141613] [59, -1] [60, 109] [61, 3] [62, -1] [65, 5] [66, 13] [67, 11] [68, 271] [69, 7] [70, 642419] [73, 29] [74, 1951] [76, 3] [77, -1] [78, 107] [79, -1] [80, 48199741] [81, 89] [82, 11] [83, 157] [84, 197] [85, 5] [86, -1] [87, -1] [88, 11] [89, 29] [90, 7] [91, -1] [92, 3] [93, 17] [94, 7] [95, 3] [98, 31] [99, 19] dim=4 [20, 2] [71, 2] [81, 2] [96, 2] [100, 2] dim=5 dim=6 dim=7 dim=8 [-3 -10 3] [ 5 -6 -5] [-1 0 -1] [-3 2 11] [ 5 -26 27] [-1 4 -5] [-3 -16 -10] [ 5 4 -6] [-1 -2 -2] [1]~ -1 -2 [1, 0]~ [-42, 35]~ [-1 0 1] [ 0 2 0] [ 1 0 1] [0, 5, -1]~ 3 [-12 0 -1] [ 0 24 0] [ 0 0 24] [310 -62 3] [-62 16 -1] [-18 2 0] *** at top-level: qfsolve([1,0,0;0,1,1;0,0,1]) *** ^---------------------------- *** qfsolve: incorrect type in qfsolve [not symmetric] (t_MAT). [1, 1, -1, -2, 0, 0, -1]~ Total time spent: 2508 pari-2.11.2/src/test/32/binomial0000644000175000017500000000066713326135265014704 0ustar billbill1/2*x^2 - 1/2*x 20 [1, 6, 15, 20, 15, 6, 1] *** at top-level: binomial(1,2.) *** ^-------------- *** binomial: incorrect type in binomial (t_REAL). *** at top-level: binomial(-1) *** ^------------ *** binomial: incorrect type in binomial (t_INT). *** at top-level: binomial(1.) *** ^------------ *** binomial: incorrect type in binomial (t_REAL). Total time spent: 0 pari-2.11.2/src/test/32/bnfisintnorm0000644000175000017500000001164413326135265015617 0ustar billbill echo = 1 ? setrand(1);bnf=bnfinit(x^2+105); ? for(i=1,1000,do(i)) 1:1 4:1 9:1 16:1 25:1 36:1 49:1 64:1 81:1 100:1 105:1 106:2 109:2 114:2 121:3 130:2 141:2 144:1 154:2 169:3 186:2 196:1 205:2 225:1 226:2 249:2 256:1 274:2 289:1 301:2 324:1 330:2 361:3 394:2 400:1 420:1 421:2 424:2 429:4 436:2 441:1 445:2 456:2 466:2 469:2 484:3 501:2 505:2 520:2 529:1 541:2 546:2 564:2 576:1 589:4 616:2 625:1 634:2 645:2 676:3 681:2 709:2 729:1 730:2 744:2 781:4 784:1 820:2 834:2 841:1 861:2 889:2 900:1 904:2 945:1 946:4 949:4 954:2 961:3 970:2 981:2 994:2 996:2 ? setrand(1);bnf=bnfinit(x^2-65); ? for(i=1,1000,do(i-500)) -491:2 -490:6 -485:2 -484:3 -481:2 -469:4 -464:10 -454:4 -446:4 -441:3 -439:2 -419:2 -416:6 -415:2 -406:8 -404:6 -400:5 -394:4 -389:2 -386:4 -376:8 -365:2 -364:6 -361:1 -360:4 -350:4 -335:2 -334:4 -329:4 -326:4 -324:3 -316:6 -315:2 -311:2 -296:8 -290:4 -289:1 -274:4 -269:2 -261:2 -260:3 -259:4 -256:9 -251:2 -250:2 -244:6 -235:2 -234:2 -225:1 -224:12 -211:2 -199:2 -196:9 -194:4 -191:2 -185:2 -181:2 -179:2 -169:1 -166:4 -160:6 -146:4 -144:5 -140:6 -139:2 -134:4 -131:2 -126:4 -121:1 -116:6 -104:4 -101:2 -100:3 -94:4 -91:2 -90:2 -81:1 -79:2 -74:4 -65:1 -64:7 -61:2 -56:8 -49:3 -40:4 -36:3 -35:2 -29:2 -26:2 -25:1 -16:5 -14:4 -10:2 -9:1 -4:3 -1:1 0:1 1:1 4:3 9:1 10:2 14:4 16:5 25:1 26:2 29:2 35:2 36:3 40:4 49:3 56:8 61:2 64:7 65:1 74:4 79:2 81:1 90:2 91:2 94:4 100:3 101:2 104:4 116:6 121:1 126:4 131:2 134:4 139:2 140:6 144:5 146:4 160:6 166:4 169:1 179:2 181:2 185:2 191:2 194:4 196:9 199:2 211:2 224:12 225:1 234:2 235:2 244:6 250:2 251:2 256:9 259:4 260:3 261:2 269:2 274:4 289:1 290:4 296:8 311:2 315:2 316:6 324:3 326:4 329:4 334:4 335:2 350:4 360:4 361:1 364:6 365:2 376:8 386:4 389:2 394:4 400:5 404:6 406:8 415:2 416:6 419:2 439:2 441:3 446:4 454:4 464:10 469:4 481:2 484:3 485:2 490:6 491:2 ? setrand(1);bnf=bnfinit(x^5-37); ? for(i=1,1000,do(i-500)) -499:1 -497:3 -496:2 -494:1 -491:3 -490:1 -487:1 -486:1 -483:1 -481:1 -478:1 -477:1 -476:1 -475:1 -474:1 -468:1 -466:1 -465:4 -463:1 -461:1 -457:1 -455:1 -454:1 -452:1 -450:1 -448:2 -447:1 -446:1 -443:1 -442:1 -441:1 -439:1 -435:1 -434:1 -426:2 -425:1 -424:1 -419:1 -417:1 -416:2 -415:1 -412:1 -405:1 -403:1 -402:1 -400:2 -398:1 -394:1 -392:1 -386:1 -382:3 -381:1 -380:1 -373:1 -372:4 -371:1 -370:1 -365:1 -364:1 -361:1 -360:1 -359:1 -358:1 -355:3 -354:1 -350:1 -349:1 -348:1 -347:1 -345:1 -343:1 -342:1 -340:1 -338:1 -337:1 -333:1 -332:1 -327:1 -326:1 -325:1 -324:1 -323:1 -321:1 -320:2 -317:1 -315:1 -314:1 -313:1 -310:1 -306:1 -304:2 -296:1 -293:1 -292:1 -291:1 -289:1 -288:2 -284:3 -282:1 -281:3 -280:1 -279:1 -276:1 -274:1 -272:2 -269:1 -267:1 -266:1 -265:1 -260:1 -259:1 -258:1 -256:3 -252:1 -250:1 -248:1 -247:1 -245:1 -243:1 -239:1 -238:1 -237:1 -234:1 -233:1 -227:1 -226:1 -225:1 -224:2 -223:1 -221:1 -217:1 -213:2 -212:1 -208:2 -206:1 -201:1 -200:1 -199:1 -197:1 -196:1 -193:1 -191:3 -190:1 -186:4 -185:1 -182:1 -180:1 -179:1 -177:1 -175:1 -174:1 -171:1 -170:1 -169:1 -166:1 -163:1 -162:1 -160:2 -157:1 -155:1 -153:1 -152:1 -148:1 -146:1 -144:2 -142:3 -141:1 -140:1 -138:1 -137:1 -136:1 -133:1 -130:1 -129:1 -128:2 -126:1 -125:1 -124:1 -119:1 -117:1 -113:1 -112:2 -106:1 -104:1 -103:1 -100:1 -98:1 -95:1 -93:4 -91:1 -90:1 -87:1 -85:1 -83:1 -81:1 -80:2 -76:1 -74:1 -73:1 -72:1 -71:3 -70:1 -69:1 -68:1 -65:1 -64:2 -63:1 -62:1 -56:1 -53:1 -52:1 -50:1 -49:1 -45:1 -40:1 -38:1 -37:1 -36:1 -35:1 -34:1 -32:2 -31:1 -28:1 -26:1 -25:1 -20:1 -19:1 -18:1 -17:1 -16:2 -14:1 -13:1 -10:1 -9:1 -8:1 -7:1 -5:1 -4:1 -2:1 -1:1 0:1 1:1 2:1 4:1 5:1 7:1 8:1 9:1 10:1 13:1 14:1 16:2 17:1 18:1 19:1 20:1 25:1 26:1 28:1 31:1 32:2 34:1 35:1 36:1 37:1 38:1 40:1 45:1 49:1 50:1 52:1 53:1 56:1 62:1 63:1 64:2 65:1 68:1 69:1 70:1 71:3 72:1 73:1 74:1 76:1 80:2 81:1 83:1 85:1 87:1 90:1 91:1 93:4 95:1 98:1 100:1 103:1 104:1 106:1 112:2 113:1 117:1 119:1 124:1 125:1 126:1 128:2 129:1 130:1 133:1 136:1 137:1 138:1 140:1 141:1 142:3 144:2 146:1 148:1 152:1 153:1 155:1 157:1 160:2 162:1 163:1 166:1 169:1 170:1 171:1 174:1 175:1 177:1 179:1 180:1 182:1 185:1 186:4 190:1 191:3 193:1 196:1 197:1 199:1 200:1 201:1 206:1 208:2 212:1 213:2 217:1 221:1 223:1 224:2 225:1 226:1 227:1 233:1 234:1 237:1 238:1 239:1 243:1 245:1 247:1 248:1 250:1 252:1 256:3 258:1 259:1 260:1 265:1 266:1 267:1 269:1 272:2 274:1 276:1 279:1 280:1 281:3 282:1 284:3 288:2 289:1 291:1 292:1 293:1 296:1 304:2 306:1 310:1 313:1 314:1 315:1 317:1 320:2 321:1 323:1 324:1 325:1 326:1 327:1 332:1 333:1 337:1 338:1 340:1 342:1 343:1 345:1 347:1 348:1 349:1 350:1 354:1 355:3 358:1 359:1 360:1 361:1 364:1 365:1 370:1 371:1 372:4 373:1 380:1 381:1 382:3 386:1 392:1 394:1 398:1 400:2 402:1 403:1 405:1 412:1 415:1 416:2 417:1 419:1 424:1 425:1 426:2 434:1 435:1 439:1 441:1 442:1 443:1 446:1 447:1 448:2 450:1 452:1 454:1 455:1 457:1 461:1 463:1 465:4 466:1 468:1 474:1 475:1 476:1 477:1 478:1 481:1 483:1 486:1 487:1 490:1 491:3 494:1 496:2 497:3 499:1 500:1 ? bnfisintnorm(bnfinit(x^3+5),5) [-x] ? bnfisintnorm(bnfinit('y^2+93),54647) [] ? print("Total time spent: ",gettime); Total time spent: 588 pari-2.11.2/src/test/32/ell0000644000175000017500000010460113454730732013661 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). ellwp:1:x^-2 - 1/5*x^2 + 1/75*x^6 - 2/4875*x^10 + O(x^14) ellwp:I:x^-2 - 1/5*I*x^2 - 1/75*x^6 + 2/4875*I*x^10 + O(x^14) ellwp:z:x^-2 - 1/5*z*x^2 + 1/75*z^2*x^6 - 2/4875*z^3*x^10 + O(x^14) ellwp:Mod(z, z^2 + 5):x^-2 + Mod(-1/5*z, z^2 + 5)*x^2 + Mod(-1/15, z^2 + 5)* x^6 + Mod(2/975*z, z^2 + 5)*x^10 + O(x^14) ellwp:Mod(z, z^2 + 5):x^-2 + Mod(-1/5*z, z^2 + 5)*x^2 + Mod(-1/15, z^2 + 5)* x^6 + Mod(2/975*z, z^2 + 5)*x^10 + O(x^14) ellwp:Mod(4, 1009):Mod(1, 1009)*x^-2 + Mod(201, 1009)*x^2 + Mod(350, 1009)*x ^6 + Mod(345, 1009)*x^10 + O(x^14) ellwp:z:x^-2 + 807*z*x^2 + 148*z^2*x^6 + 368*z^3*x^10 + O(x^14) ellzeta:1:x^-1 + 1/15*x^3 - 1/525*x^7 + 2/53625*x^11 + O(x^15) ellzeta:I:x^-1 + 1/15*I*x^3 + 1/525*x^7 - 2/53625*I*x^11 + O(x^15) ellzeta:z:x^-1 + 1/15*z*x^3 - 1/525*z^2*x^7 + 2/53625*z^3*x^11 + O(x^15) ellzeta:Mod(z, z^2 + 5):x^-1 + Mod(1/15*z, z^2 + 5)*x^3 + Mod(1/105, z^2 + 5 )*x^7 + Mod(-2/10725*z, z^2 + 5)*x^11 + O(x^15) ellzeta:Mod(z, z^2 + 5):x^-1 + Mod(1/15*z, z^2 + 5)*x^3 + Mod(1/105, z^2 + 5 )*x^7 + Mod(-2/10725*z, z^2 + 5)*x^11 + O(x^15) ellzeta:Mod(4, 1009):Mod(1, 1009)*x^-1 + Mod(942, 1009)*x^3 + Mod(959, 1009) *x^7 + Mod(519, 1009)*x^11 + O(x^15) ellzeta:z:x^-1 + 740*z*x^3 + 123*z^2*x^7 + 150*z^3*x^11 + O(x^15) ellsigma:1:x + 1/60*x^5 - 1/10080*x^9 - 23/259459200*x^13 + O(x^17) ellsigma:I:x + 1/60*I*x^5 + 1/10080*x^9 + 23/259459200*I*x^13 + O(x^17) ellsigma:z:x + 1/60*z*x^5 - 1/10080*z^2*x^9 - 23/259459200*z^3*x^13 + O(x^17 ) ellsigma:Mod(z, z^2 + 5):x + Mod(1/60*z, z^2 + 5)*x^5 + Mod(1/2016, z^2 + 5) *x^9 + Mod(23/51891840*z, z^2 + 5)*x^13 + O(x^17) ellsigma:Mod(z, z^2 + 5):x + Mod(1/60*z, z^2 + 5)*x^5 + Mod(1/2016, z^2 + 5) *x^9 + Mod(23/51891840*z, z^2 + 5)*x^13 + O(x^17) ellsigma:Mod(4, 1009):x + Mod(740, 1009)*x^5 + Mod(607, 1009)*x^9 + Mod(802, 1009)*x^13 + O(x^17) ellsigma:z:x + 185*z*x^5 + 101*z^2*x^9 + 990*z^3*x^13 + O(x^17) ellformalw:1:x^3 + x^7 + 2*x^11 + 5*x^15 + O(x^19) ellformalw:I:x^3 + I*x^7 - 2*x^11 - 5*I*x^15 + O(x^19) ellformalw:z:x^3 + z*x^7 + 2*z^2*x^11 + 5*z^3*x^15 + O(x^19) ellformalw:Mod(z, z^2 + 5):x^3 + Mod(z, z^2 + 5)*x^7 + Mod(-10, z^2 + 5)*x^1 1 + Mod(-25*z, z^2 + 5)*x^15 + O(x^19) ellformalw:Mod(z, z^2 + 5):x^3 + Mod(z, z^2 + 5)*x^7 + Mod(-10, z^2 + 5)*x^1 1 + Mod(-25*z, z^2 + 5)*x^15 + O(x^19) ellformalw:Mod(4, 1009):x^3 + Mod(4, 1009)*x^7 + Mod(32, 1009)*x^11 + Mod(32 0, 1009)*x^15 + O(x^19) ellformalw:z:x^3 + z*x^7 + 2*z^2*x^11 + 5*z^3*x^15 + O(x^19) ellformalpoint:1:[x^-2 - x^2 - x^6 - 2*x^10 + O(x^14), -x^-3 + x + x^5 + 2*x ^9 + O(x^13)] ellformalpoint:I:[x^-2 - I*x^2 + x^6 + 2*I*x^10 + O(x^14), -x^-3 + I*x - x^5 - 2*I*x^9 + O(x^13)] ellformalpoint:z:[x^-2 - z*x^2 - z^2*x^6 - 2*z^3*x^10 + O(x^14), -x^-3 + z*x + z^2*x^5 + 2*z^3*x^9 + O(x^13)] ellformalpoint:Mod(z, z^2 + 5):[x^-2 + Mod(-z, z^2 + 5)*x^2 + Mod(5, z^2 + 5 )*x^6 + Mod(10*z, z^2 + 5)*x^10 + O(x^14), -x^-3 + Mod(z, z^2 + 5)*x + Mod(- 5, z^2 + 5)*x^5 + Mod(-10*z, z^2 + 5)*x^9 + O(x^13)] ellformalpoint:Mod(z, z^2 + 5):[x^-2 + Mod(-z, z^2 + 5)*x^2 + Mod(5, z^2 + 5 )*x^6 + Mod(10*z, z^2 + 5)*x^10 + O(x^14), -x^-3 + Mod(z, z^2 + 5)*x + Mod(- 5, z^2 + 5)*x^5 + Mod(-10*z, z^2 + 5)*x^9 + O(x^13)] ellformalpoint:Mod(4, 1009):[x^-2 + Mod(1005, 1009)*x^2 + Mod(993, 1009)*x^6 + Mod(881, 1009)*x^10 + O(x^14), -x^-3 + Mod(4, 1009)*x + Mod(16, 1009)*x^5 + Mod(128, 1009)*x^9 + O(x^13)] ellformalpoint:z:[x^-2 + 1008*z*x^2 + 1008*z^2*x^6 + 1007*z^3*x^10 + O(x^14) , -x^-3 + z*x + z^2*x^5 + 2*z^3*x^9 + O(x^13)] ellformaldifferential:1:[1 + 2*x^4 + 6*x^8 + 20*x^12 + O(x^16), x^-2 + x^2 + 3*x^6 + 10*x^10 + O(x^14)] ellformaldifferential:I:[1 + 2*I*x^4 - 6*x^8 - 20*I*x^12 + O(x^16), x^-2 + I *x^2 - 3*x^6 - 10*I*x^10 + O(x^14)] ellformaldifferential:z:[1 + 2*z*x^4 + 6*z^2*x^8 + 20*z^3*x^12 + O(x^16), x^ -2 + z*x^2 + 3*z^2*x^6 + 10*z^3*x^10 + O(x^14)] ellformaldifferential:Mod(z, z^2 + 5):[Mod(1, z^2 + 5) + Mod(2*z, z^2 + 5)*x ^4 + Mod(-30, z^2 + 5)*x^8 + Mod(-100*z, z^2 + 5)*x^12 + O(x^16), Mod(1, z^2 + 5)*x^-2 + Mod(z, z^2 + 5)*x^2 + Mod(-15, z^2 + 5)*x^6 + Mod(-50*z, z^2 + 5)*x^10 + O(x^14)] ellformaldifferential:Mod(z, z^2 + 5):[Mod(1, z^2 + 5) + Mod(2*z, z^2 + 5)*x ^4 + Mod(-30, z^2 + 5)*x^8 + Mod(-100*z, z^2 + 5)*x^12 + O(x^16), Mod(1, z^2 + 5)*x^-2 + Mod(z, z^2 + 5)*x^2 + Mod(-15, z^2 + 5)*x^6 + Mod(-50*z, z^2 + 5)*x^10 + O(x^14)] ellformaldifferential:Mod(4, 1009):[Mod(1, 1009) + Mod(8, 1009)*x^4 + Mod(96 , 1009)*x^8 + Mod(271, 1009)*x^12 + O(x^16), Mod(1, 1009)*x^-2 + Mod(4, 1009 )*x^2 + Mod(48, 1009)*x^6 + Mod(640, 1009)*x^10 + O(x^14)] ellformaldifferential:z:[1 + 2*z*x^4 + 6*z^2*x^8 + 20*z^3*x^12 + O(x^16), x^ -2 + z*x^2 + 3*z^2*x^6 + 10*z^3*x^10 + O(x^14)] ellformallog:1:x + 2/5*x^5 + 2/3*x^9 + 20/13*x^13 + O(x^17) ellformallog:I:x + 2/5*I*x^5 - 2/3*x^9 - 20/13*I*x^13 + O(x^17) ellformallog:z:x + 2/5*z*x^5 + 2/3*z^2*x^9 + 20/13*z^3*x^13 + O(x^17) ellformallog:Mod(z, z^2 + 5):Mod(1, z^2 + 5)*x + Mod(2/5*z, z^2 + 5)*x^5 + M od(-10/3, z^2 + 5)*x^9 + Mod(-100/13*z, z^2 + 5)*x^13 + O(x^17) ellformallog:Mod(z, z^2 + 5):Mod(1, z^2 + 5)*x + Mod(2/5*z, z^2 + 5)*x^5 + M od(-10/3, z^2 + 5)*x^9 + Mod(-100/13*z, z^2 + 5)*x^13 + O(x^17) ellformallog:Mod(4, 1009):Mod(1, 1009)*x + Mod(607, 1009)*x^5 + Mod(347, 100 9)*x^9 + Mod(797, 1009)*x^13 + O(x^17) ellformallog:z:x + 404*z*x^5 + 337*z^2*x^9 + 312*z^3*x^13 + O(x^17) ellformalexp:1:x - 2/5*x^5 + 2/15*x^9 - 44/975*x^13 + O(x^17) ellformalexp:I:x - 2/5*I*x^5 - 2/15*x^9 + 44/975*I*x^13 + O(x^17) ellformalexp:z:x - 2/5*z*x^5 + 2/15*z^2*x^9 - 44/975*z^3*x^13 + O(x^17) ellformalexp:Mod(z, z^2 + 5):x + Mod(-2/5*z, z^2 + 5)*x^5 + Mod(-2/3, z^2 + 5)*x^9 + Mod(44/195*z, z^2 + 5)*x^13 + O(x^17) ellformalexp:Mod(z, z^2 + 5):x + Mod(-2/5*z, z^2 + 5)*x^5 + Mod(-2/3, z^2 + 5)*x^9 + Mod(44/195*z, z^2 + 5)*x^13 + O(x^17) ellformalexp:Mod(4, 1009):x + Mod(402, 1009)*x^5 + Mod(473, 1009)*x^9 + Mod( 617, 1009)*x^13 + O(x^17) ellformalexp:z:x + 605*z*x^5 + 471*z^2*x^9 + 120*z^3*x^13 + O(x^17) (E)->ellisoncurve(E,[0,0]):1:1 (E)->ellisoncurve(E,[0,0]):I:1 (E)->ellisoncurve(E,[0,0]):z:1 (E)->ellisoncurve(E,[0,0]):Mod(z, z^2 + 5):1 (E)->ellisoncurve(E,[0,0]):Mod(z, z^2 + 5):1 (E)->ellisoncurve(E,[0,0]):Mod(4, 1009):1 (E)->ellisoncurve(E,[0,0]):z:1 (E)->ellordinate(E,0):1:[0] (E)->ellordinate(E,0):I:[0] (E)->ellordinate(E,0):z:[0] (E)->ellordinate(E,0):Mod(z, z^2 + 5):[0] (E)->ellordinate(E,0):Mod(z, z^2 + 5):[0] (E)->ellordinate(E,0):Mod(4, 1009):[Mod(0, 1009)] (E)->ellordinate(E,0):z:[0] (E)->elldivpol(E,5):1:5*x^12 + 62*x^10 - 105*x^8 - 300*x^6 - 125*x^4 - 50*x^ 2 + 1 (E)->elldivpol(E,5):I:5*x^12 + 62*I*x^10 + 105*x^8 + 300*I*x^6 - 125*x^4 - 5 0*I*x^2 - 1 (E)->elldivpol(E,5):z:5*x^12 + 62*z*x^10 - 105*z^2*x^8 - 300*z^3*x^6 - 125*z ^4*x^4 - 50*z^5*x^2 + z^6 (E)->elldivpol(E,5):Mod(z, z^2 + 5):Mod(5, z^2 + 5)*x^12 + Mod(62*z, z^2 + 5 )*x^10 + Mod(525, z^2 + 5)*x^8 + Mod(1500*z, z^2 + 5)*x^6 + Mod(-3125, z^2 + 5)*x^4 + Mod(-1250*z, z^2 + 5)*x^2 + Mod(-125, z^2 + 5) (E)->elldivpol(E,5):Mod(z, z^2 + 5):Mod(5, z^2 + 5)*x^12 + Mod(62*z, z^2 + 5 )*x^10 + Mod(525, z^2 + 5)*x^8 + Mod(1500*z, z^2 + 5)*x^6 + Mod(-3125, z^2 + 5)*x^4 + Mod(-1250*z, z^2 + 5)*x^2 + Mod(-125, z^2 + 5) (E)->elldivpol(E,5):Mod(4, 1009):Mod(5, 1009)*x^12 + Mod(248, 1009)*x^10 + M od(338, 1009)*x^8 + Mod(980, 1009)*x^6 + Mod(288, 1009)*x^4 + Mod(259, 1009) *x^2 + Mod(60, 1009) (E)->elldivpol(E,5):z:5*x^12 + 62*z*x^10 + 904*z^2*x^8 + 709*z^3*x^6 + 884*z ^4*x^4 + (50*z^4 + 809*z^3 + 859*z^2 + 150*z + 50)*x^2 + (5*z^4 + 1008*z^3 + 1003*z^2 + 2*z + 1) (E)->ellxn(E,3):1:[x^9 - 12*x^7 + 30*x^5 + 36*x^3 + 9*x, 9*x^8 + 36*x^6 + 30 *x^4 - 12*x^2 + 1] (E)->ellxn(E,3):I:[x^9 - 12*I*x^7 - 30*x^5 - 36*I*x^3 + 9*x, 9*x^8 + 36*I*x^ 6 - 30*x^4 + 12*I*x^2 + 1] (E)->ellxn(E,3):z:[x^9 - 12*z*x^7 + 30*z^2*x^5 + 36*z^3*x^3 + 9*z^4*x, 9*x^8 + 36*z*x^6 + 30*z^2*x^4 - 12*z^3*x^2 + z^4] (E)->ellxn(E,3):Mod(z, z^2 + 5):[Mod(1, z^2 + 5)*x^9 + Mod(-12*z, z^2 + 5)*x ^7 + Mod(-150, z^2 + 5)*x^5 + Mod(-180*z, z^2 + 5)*x^3 + Mod(225, z^2 + 5)*x , Mod(9, z^2 + 5)*x^8 + Mod(36*z, z^2 + 5)*x^6 + Mod(-150, z^2 + 5)*x^4 + Mo d(60*z, z^2 + 5)*x^2 + Mod(25, z^2 + 5)] (E)->ellxn(E,3):Mod(z, z^2 + 5):[Mod(1, z^2 + 5)*x^9 + Mod(-12*z, z^2 + 5)*x ^7 + Mod(-150, z^2 + 5)*x^5 + Mod(-180*z, z^2 + 5)*x^3 + Mod(225, z^2 + 5)*x , Mod(9, z^2 + 5)*x^8 + Mod(36*z, z^2 + 5)*x^6 + Mod(-150, z^2 + 5)*x^4 + Mo d(60*z, z^2 + 5)*x^2 + Mod(25, z^2 + 5)] (E)->ellxn(E,3):Mod(4, 1009):[Mod(1, 1009)*x^9 + Mod(961, 1009)*x^7 + Mod(48 0, 1009)*x^5 + Mod(286, 1009)*x^3 + Mod(286, 1009)*x, Mod(9, 1009)*x^8 + Mod (144, 1009)*x^6 + Mod(480, 1009)*x^4 + Mod(241, 1009)*x^2 + Mod(256, 1009)] (E)->ellxn(E,3):z:[x^9 + 997*z*x^7 + 30*z^2*x^5 + 36*z^3*x^3 + 9*z^4*x, 9*x^ 8 + 36*z*x^6 + 30*z^2*x^4 + 997*z^3*x^2 + z^4] (E)->ellmul(E,[0,0],0):1:[0] (E)->ellmul(E,[0,0],0):I:[0] (E)->ellmul(E,[0,0],0):z:[0] (E)->ellmul(E,[0,0],0):Mod(z, z^2 + 5):[0] (E)->ellmul(E,[0,0],0):Mod(z, z^2 + 5):[0] (E)->ellmul(E,[0,0],0):Mod(4, 1009):[0] (E)->ellmul(E,[0,0],0):z:[0] (E)->ellneg(E,[0,0]):1:[0, 0] (E)->ellneg(E,[0,0]):I:[0, 0] (E)->ellneg(E,[0,0]):z:[0, 0] (E)->ellneg(E,[0,0]):Mod(z, z^2 + 5):[0, 0] (E)->ellneg(E,[0,0]):Mod(z, z^2 + 5):[0, 0] (E)->ellneg(E,[0,0]):Mod(4, 1009):[0, Mod(0, 1009)] (E)->ellneg(E,[0,0]):z:[0, 0] -1 0 152 1031:[504, 2] 2053:[1008, 2] 4099:[4196] 8209:[8291] 16411:[8280, 2] 32771:[32545] 65537:[65115] 131101:[130579] 262147:[261873] 524309:[525362] 1048583:[1048721] 2097169:[2099343] 4194319:[4190448] 8388617:[4196176, 2] 16777259:[16776451] 33554467:[33556544] 67108879:[33553348, 2] 134217757:[134207016] 268435459:[268450764] 536870923:[536886729] 1073741827:[1073696739] 2147483659:[2147445985] 4294967311:[4294892145] 8589934609:[8589800815] 17179869209:[17179907771] 34359738421:[34359891299] 68719476767:[68719109932] 137438953481:[137439150447] 274877906951:[274876963417] 549755813911:[549755723143] 1099511627791:[1099510624080] 2199023255579:[1099512197774, 2] 4398046511119:[4398049864270] 8796093022237:[8796090641581] 17592186044423:[17592179180564] 35184372088891:[35184377696395] 70368744177679:[70368735914810] 140737488355333:[140737466844674] 281474976710677:[281474967245574] 562949953421381:[562949910045019] 1125899906842679:[562949923357406, 2] 2251799813685269:[2251799812875502] 4503599627370517:[4503599672855988] 9007199254740997:[9007199395723803] 18014398509482143:[18014398460825440] 36028797018963971:[18014398463069820, 2] 72057594037928017:[36028797145369816, 2] 144115188075855881:[144115187446866113] 288230376151711813:[288230375567209858] 576460752303423619:[576460752721346915] 1152921504606847009:[1152921506693313952] 2305843009213693967:[2305843010596733829] 4611686018427388039:[4611686021547019756] 9223372036854775837:[9223372041689460430] 15 1 1 163663 121661 1 1023 494 0 1728 j 0 Mod(0, 5) Mod(3, 5) Mod(1, 2)*j 0 Mod(1, 3)*j [0, D*a2, 0, D^2*a4, D^3*a6] [a1, T*a1^2 + a2, a3, a4, T*a3^2 + a6] [a1, a2, a3, a4, a6] [0, -a1^2 - 4*a2, 0, 8*a3*a1 + 16*a4, -16*a3^2 - 64*a6] [-a1, a1^2 + 5*a2, -5*a3, 10*a3*a1 + 25*a4, 25*a3^2 + 125*a6] -8 -4 [0, 0, 0, -11737467275460978540, -17351253812244416823734891600, 0, -2347493 4550921957080, -69405015248977667294939566400, -1377681380425173666806670582 14340531600, 563398429222126969920, 14991483293779176135706946342400, -26569 379066176956739643152125596317141644100461473562624000, -882216989/131072, V ecsmall([1]), [Vecsmall([128, -1])], [0, 0, 0, 0, 0, 0, 0, 0]] [1/512, 0, 0, 0] 133304232 133304232 [[-8, -1792], [24, -1792]] [[-4, -27], [12, -27]] [[-8, -64], [24, -64]] [[1, -11], [-3, -11]] [[24, -3456], [-8, -3456]] [[-8, -5184], [24, -5184]] [[24, -93312], [24, -93312], [-3, -93312], [-3, -93312]] [[-3, 11664], [-3, 11664], [24, 11664], [24, 11664]] [[-3, -34992], [-3, -34992], [24, -34992], [24, -34992]] [[1, 64], [1, 64], [-8, 64], [-8, 64]] [[1, -15], [-4, -15], [8, -15], [-8, -15]] [[1, -11648], [1, -11648], [-8, -11648], [-8, -11648]] 12 a a [5, -66, 148, 665, -15802] [3, -15, -40, 40, -181] [3, -15, -40, 40, -181] [5, -70, -300, 1956, -28305] 8*x^9 + 54*x^8 + 393*x^7 + 2373*x^6 + 6993*x^5 + 15267*x^4 + 19998*x^3 + 473 4*x^2 - 25880*x - 30932 [0, 0] [x, 1] [x^4 - 13*x^2 - 74*x - 41, 4*x^3 + 9*x^2 + 26*x + 37] [x^16 - 260*x^14 - 5968*x^13 - 39963*x^12 - 140444*x^11 - 195486*x^10 + 5215 64*x^9 + 5378114*x^8 + 23699984*x^7 + 74549288*x^6 + 183951360*x^5 + 3366091 54*x^4 + 444753656*x^3 + 432135644*x^2 + 255731272*x + 49749605, 16*x^15 + 1 80*x^14 + 1792*x^13 + 14753*x^12 + 84148*x^11 + 414370*x^10 + 1658348*x^9 + 4652985*x^8 + 9212312*x^7 + 10904612*x^6 + 434120*x^5 - 24648228*x^4 - 39304 176*x^3 - 13741184*x^2 + 25100064*x + 25859152] [x^25 - 650*x^23 - 23335*x^22 - 259290*x^21 - 1456154*x^20 - 2820445*x^19 + 20761370*x^18 + 277111495*x^17 + 2007242185*x^16 + 11282671667*x^15 + 529194 54495*x^14 + 207385350880*x^13 + 677127946605*x^12 + 1857857835015*x^11 + 43 12300313262*x^10 + 8526087679330*x^9 + 14394585463670*x^8 + 20512909438825*x ^7 + 23836827014955*x^6 + 20324637565929*x^5 + 7866409553255*x^4 - 796635515 1205*x^3 - 15373355872840*x^2 - 10304273387855*x - 2425203075812, 25*x^24 + 450*x^23 + 6865*x^22 + 90410*x^21 + 848806*x^20 + 6747580*x^19 + 45352495*x^ 18 + 229321140*x^17 + 838958290*x^16 + 2007441886*x^15 + 1506282910*x^14 - 1 1941908510*x^13 - 67097680775*x^12 - 197749423840*x^11 - 360107712461*x^10 - 248110872190*x^9 + 863441551840*x^8 + 3852505140470*x^7 + 8796991424540*x^6 + 14201708642530*x^5 + 17446507273700*x^4 + 16338035413000*x^3 + 1142822256 7925*x^2 + 5633997157650*x + 1472351694025] [0] [-23338430276487649199700397847721116081702650343430925719105465344187224269 2167848859501069746367317057135733659821516586965453870026354744714986684965 8323996212283434950398700511439/21452304628477972409549628569820513272484339 3023834534814913254065684077308619895779034479691808535960623339165042624323 5345631919723231687684699452030828176986716708998958804636224, -892721634620 8423324340896231392069270729522715981007828685033969863523382353428674866926 4734542739355918998020644016664732197288414787069129806148688960193235312780 7158822883693587635120259554260938849967680317634128924102700969620674883736 9307779952513049787052947107461/31420343828112469950094830391399473730286380 5713026983524763427660191121031569408909200906270720147570836507805210795709 8988916304745235223129078126602318052803199405011168522054272192266092941904 104143227672460543588095008724194999641591292020853488313837016518733957632] [-1, 1] [-1, -3] [833245230963211172586751702962398963656841653/30025043966406435914574252820 2802293592821136, -572865877831905829779071583256995923720966703129995025914 40045201397/5202660393781989115440421988056492168066969880055771334597510887 616] [-10325327/6270016, -17317169781/15700120064] [-10325327/6270016, -17317169781/15700120064] 16*x^33 + 20048*x^30 - 524864*x^27 - 20273280*x^24 - 35051520*x^21 - 1832755 20*x^18 - 818626560*x^15 - 1017937920*x^12 - 390856704*x^9 + 74973184*x^6 + 102760448*x^3 + 4194304 0 [1, 0] [-1, -1] [3.1096482423243803285501491221965830079, 1.55482412116219016427507456109829 15039 + 1.0643747452102737569438859937299427442*I] [6.2192964846487606571002982443931660158, 3.10964824232438032855014912219658 30079 + 2.1287494904205475138877719874598854884*I] [5.5614800275334595421263952543627169988, 2.78074001376672977106319762718135 84994 - 2.1374995527123861323185270948750077575*I] [6.2192964846487606571002982443931660158, 3.10964824232438032855014912219658 30079 + 2.1287494904205475138877719874598854884*I] [-1.1547274830668428355945002349018042438, -0.828886258466578582202749882549 09787812 + 0.52313677422798965199542236165917364573*I, -0.828886258466578582 20274988254909787812 - 0.52313677422798965199542236165917364573*I] [10351, [1/2, -1, -2, 5/4], 1, [11, 1; 941, 1], [[1, 5, 0, 1], [1, 5, 0, 1]] ] [10351, [1, -1, 0, -1], 1, [11, 1; 941, 1], [[1, 5, 0, 1], [1, 5, 0, 1]]] [0, 1, [18446744073709551629, -1020847100762815391828969860044649660923, -55 340232221128654887, 25108406941546723108427206932497066002105857518694949724 756], 1] *** at top-level: E.omega *** ^----- *** _.omega: incorrect type in omega [not defined over C] (t_VEC). [9, [9], [[Mod(3, 7), Mod(5, 7)]]] [0, 0, 0, 413748, 716503104, 0, 827496, 2866012416, -171187407504, -19859904 , -619058681856, -226311754192704000000, 97158364170048/2807086984375, Vecsm all([1]), [Vecsmall([128, -1])], [0, 0, 0, 0, 0, 0, 0, [[2, 3]~]]] [1/30, -13/150, -1/10, -79/500] 1 [36, [36], [[a^4 + a, a^3 + a + 1]]] 1 [3, [3], [[0, 2]]] 1 [4, [4], [[Mod(3, 5), Mod(3, 5)]]] [3^-1 + 2 + 2*3^2 + 2*3^5 + O(3^6)]~ [1 + 2*3 + 3^2 + 2*3^3 + 3^4 + 3^5 + 2*3^6 + 3^7 + 3^8 + O(3^10), 1 + 3 + 3^ 3 + 3^4 + 2*3^5 + 2*3^6 + 2*3^7 + O(3^10), 3 + 2*3^3 + 2*3^7 + O(3^8), [1 + 2*3 + 3^2 + 2*3^3 + 3^4 + 3^6 + 3^9 + O(3^10), 1 + 3 + 2*3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + 3^9 + O(3^10)], 2*3^2 + 3^4 + 3^5 + 3^6 + O(3^7), [[20563, 24 337, 40465, 16489, 23050], [21109, 27838, 25318, 29611, 23050], [3 + 2*3^2 + 2*3^4 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10), 3^2 + 2*3^3 + 3^4 + 3^6 + 3^7 + 2*3^8 + 2*3^9 + O(3^10), 3^4 + 2*3^5 + 2*3^6 + 2*3^8 + O(3^10), 3^8 + 2*3^9 + O(3^10)], 0]] error("inconsistent moduli in ellinit: 3 != 5") error("inconsistent moduli in ellinit: 3 != 5") error("incorrect type in elliptic curve base_ring (t_VEC).") [3^-1 + 2 + 2*3^2 + 2*3^5 + 2*3^6 + 2*3^7 + O(3^10)]~ [3^2 + 2*3^3 + 3^4 + 2*3^5 + 3^6 + 3^7 + 2*3^8 + 3^9 + 3^10 + O(3^12), 3 + 3 ^2 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + O(3^11), 3 + 2*3^3 + 2*3^7 + O(3^8) , [3^-2 + 2*3^-1 + 1 + 2*3 + 3^2 + 3^4 + 3^7 + O(3^8), 3^-2 + 3^-1 + 2 + 3 + 2*3^2 + 2*3^3 + 3^4 + 3^7 + O(3^8)], 2*3^2 + 3^4 + 3^5 + 3^6 + O(3^7)] [3^-4 + 3^-2 + O(3^0), 2*3^-6 + 2*3^-5 + 2*3^-4 + O(3^-2)] [2 + 2^6 + O(2^9), Mod(x, x^2 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^7 + 2^8 + O(2 ^9))), 2^3 + 2^4 + O(2^8), [2^-3 + 2^2 + 2^4 + 2^7 + 2^10 + O(2^11), 2^-3 + 2^2 + 2^5 + 2^6 + 2^10 + O(2^13)], 1, [[9377, 4065, 481], [8993, 7137, 1505] , [2^4 + 2^5 + O(2^11), 2^7 + O(2^9)], -3]] [1 + 2^2 + 2^7 + 2^9 + 2^11 + O(2^13), Mod(x, x^2 + (1 + 2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^8 + 2^10 + 2^12 + O(2^13))), 2^6 + 2^10 + 2^11 + O(2^12), [2^-2 + 1 + 2 + 2^4 + 2^9 + 2^10 + O(2^15), 2^-2 + 1 + 2 + 2^4 + 2^8 + 2^11 + 2^15 + O(2^16)], 1, [[6221, 7757], [140365, 7757], [2^8 + 2^10 + 2^11 + 2^12 + 2^ 13 + 2^14 + O(2^15)], -2]] x^-2 + 31/15*x^2 + 2501/756*x^4 + 961/675*x^6 + 77531/41580*x^8 + O(x^9) [5.0000000000000000000000000000000000000, 4.99999999999999999999999999999999 99998] [-12.064158953746718488850195394125882872 - 15.92520450223955742328295296854 0594886*I, 176.27130319116395732662786731582177463 - 31.20263982848450159665 8857828111044055*I] [0] [-1.2137559863387746413172077159498331998, -0.757861263970860955134912630669 68406624*I] [-1, -2*w] 4.9747357492884922209880132412724056589 - 3.14159265358979323846264338327950 28842*I 0.E-38 + 2.2847332495354101318966341082212062060*I [-0.11111111111111111111110856972094952393 - 1512366075204170948725763450259 63248351/100000000000000000000000000000000000000000000000000*I, 7.3468396926 392969248046033576390354864 E-40 + 1/100000000000000000000000000000000000000 00000000000*I] [-1, 1/2*I] [[-1, 1/2*I], [0.59200051084078635056480901325155142952, -6.5791855625999796 522076912731847814832*I]] [1, 1] x^-2 - 1/5*x^2 - 1/7*x^4 + 1/75*x^6 + 3/385*x^8 + 277/238875*x^10 - 2/5775*x ^12 + O(x^14) x^-2 - 1/5*x^2 - 1/7*x^4 + 1/75*x^6 + O(x^7) 8.9760336058655702799613054290253052730 -8.9795585687185301843619815765809019105 0.0070737179180847219897019688523688143770 - 4.54459013280902760664280136539 71181200*I [1, 2] x^-2 + 103.98999607107861876118376809420672237*x^2 - 649.9550420035218272005 1926719405777425*x^4 + 3604.6397609543155221247400145868915015*x^6 - 18433.3 15162997447301537872827568145124*x^8 + 90164.1927526450698484311468148077532 96*x^10 - 425973.41586156854974946172781042993149*x^12 + O(x^14) x^-2 + 103.98999607107861876118376809420672237*x^2 - 649.9550420035218272005 1926719405777425*x^4 + 3604.6397609543155221247400145868915015*x^6 + O(x^7) 15.663727422159594482268754503777038256 -39.480069718736152480166362703315829534 11.908171148288278998948804099769395642 + 1.97957325252946376553721096563444 46755*I [1, 3] x^-2 + 103.98999607107861876118376809420672237*x^2 - 649.9550420035218272005 1926719405777425*x^4 + 3604.6397609543155221247400145868915015*x^6 - 18433.3 15162997447301537872827568145124*x^8 + 90164.1927526450698484311468148077532 96*x^10 - 425973.41586156854974946172781042993149*x^12 + O(x^14) x^-2 + 103.98999607107861876118376809420672237*x^2 - 649.9550420035218272005 1926719405777425*x^4 + 3604.6397609543155221247400145868915015*x^6 + O(x^7) 15.663727422159594482268754503777038256 -39.480069718736152480166362703315829534 11.908171148288278998948804099769395642 + 1.97957325252946376553721096563444 46755*I [2, 1] x^-1 + 1/15*x^3 + 1/35*x^5 - 1/525*x^7 - 1/1155*x^9 - 277/2627625*x^11 + 2/7 5075*x^13 + O(x^15) x^-1 + 1/15*x^3 + 1/35*x^5 - 1/525*x^7 + O(x^8) 3.0025857981852417376980007365038576528 -3.0023507303355942712341893343171384978*I 1.4945837634650773441141478432745008118 - 1.49552579635851441107083905597206 14467*I [2, 2] x^-1 - 34.663332023692872920394589364735574123*x^3 + 129.9910084007043654401 0385343881155485*x^5 - 514.94853727918793173210571636955592878*x^7 + 2048.14 61292219385890597636475075716805*x^9 - 8196.74479569500634985737698316434120 88*x^11 + 32767.185835505273057650902139263840884*x^13 + O(x^15) x^-1 - 34.663332023692872920394589364735574123*x^3 + 129.9910084007043654401 0385343881155485*x^5 - 514.94853727918793173210571636955592878*x^7 + O(x^8) 2.0876703200272312306836757817491311900 -0.75844907585936710327841325497105198841*I 1.8018229730105461594800210664505892466 - 4.22108966565276293974646245627813 69158*I [2, 3] x^-1 - 34.663332023692872920394589364735574123*x^3 + 129.9910084007043654401 0385343881155485*x^5 - 514.94853727918793173210571636955592878*x^7 + 2048.14 61292219385890597636475075716805*x^9 - 8196.74479569500634985737698316434120 88*x^11 + 32767.185835505273057650902139263840884*x^13 + O(x^15) x^-1 - 34.663332023692872920394589364735574123*x^3 + 129.9910084007043654401 0385343881155485*x^5 - 514.94853727918793173210571636955592878*x^7 + O(x^8) 2.0876703200272312306836757817491311900 -0.75844907585936710327841325497105198841*I 1.8018229730105461594800210664505892466 - 4.22108966565276293974646245627813 69158*I [3, 1] x + 1/60*x^5 + 1/210*x^7 - 1/10080*x^9 - 1/138600*x^11 - 167/259459200*x^13 - 19/1513512000*x^15 + O(x^17) x + 1/60*x^5 + 1/210*x^7 - 1/10080*x^9 + O(x^10) 0.33340409272605175654322174351877926789 0.33339973807064633526799756411632693201*I 0.33307632454406929865753194192439552171 + 0.3330414840427217068846417452694 8964210*I [3, 2] x - 8.6658330059232182300986473411838935307*x^5 + 21.66516806678406090668397 5573135259142*x^7 - 26.820236316624371444380506060914371291*x^9 + 17.0678844 10182821575498030395896430672*x^11 + 0.9724196316598484235781214649285975622 3*x^13 - 15.440886182405758633317637416815798050*x^15 + O(x^17) x - 8.6658330059232182300986473411838935307*x^5 + 21.66516806678406090668397 5573135259142*x^7 - 26.820236316624371444380506060914371291*x^9 + O(x^10) 0.30631122697380979289268115078987850649 0.28630802922181366479814671169863862828*I 0.53021646242894349905972369056429285872 + 0.3781418838145237834855647058271 9409288*I [3, 3] x - 8.6658330059232182300986473411838935307*x^5 + 21.66516806678406090668397 5573135259142*x^7 - 26.820236316624371444380506060914371291*x^9 + 17.0678844 10182821575498030395896430672*x^11 + 0.9724196316598484235781214649285975622 3*x^13 - 15.440886182405758633317637416815798050*x^15 + O(x^17) x - 8.6658330059232182300986473411838935307*x^5 + 21.66516806678406090668397 5573135259142*x^7 - 26.820236316624371444380506060914371291*x^9 + O(x^10) 0.30631122697380979289268115078987850649 0.28630802922181366479814671169863862828*I 0.53021646242894349905972369056429285872 + 0.3781418838145237834855647058271 9409288*I [4, 1] 0 0 -1.0984000330177788282680372407424344829 -1.0984130942966868400436474225688716324 + 1.5707963267948966192313216916397 514421*I -0.75286232322707031868584884787482252469 + 0.785345859584418994173505759767 90041015*I [4, 2] 0 0 -1.1831536122930622250712755356827420688 -1.2506870224867757820652851907990498543 + 1.5707963267948966192313216916397 514421*I -0.42886850134944751864186009377385060418 + 0.619519575104929600932212172490 11490053*I [4, 3] 0 0 -1.1831536122930622250712755356827420688 -1.2506870224867757820652851907990498543 + 1.5707963267948966192313216916397 514421*I -0.42886850134944751864186009377385060418 + 0.619519575104929600932212172490 11490053*I [2.5135797437238231405782694715779164652, 1.25678987186191157028913473578895 82326 + 0.78959476569186174055147277865716603189*I] [3.1415926535897932384626433832795028842, 9.42477796076937971538793014983850 86526*I] (x)->elleisnum(x,2) -2.9936282668967606065680548947245432597 - 7.1637767384648910133063235008836 078048*I 157.90045350239951165298459055643475560 157.90045350239951165298459055643475560 (x)->real(elleisnum(x,4,1)) -3.9999999999999999999999999999999999999 2079.7999214215723752236753618841344474 2079.7999214215723752236753618841344474 (x)->real(elleisnum(x,6,1)) -4.0000000000000000000000000000000000000 -18198.741176098611161614539481433617679 -18198.741176098611161614539481433617679 (x)->real(elleisnum(x,10)) -41471.999999999999999999999999999999999 98106527293.111533926136928277796284706 98106527293.111533926136928277796284706 45515516542954982422.225456145489798060 2.0716622535417196510500376518804560198 E39 -1 [0] 347813742467679407541/38941611811810745401 [0.49999999999999999999999999999999999984 + 0.999999999999999999999999999999 99999995*I, 1.5617041082089070087003342842479112065 + 0.56028539298876740518 391807553710802963*I] *** at top-level: ellpointtoz(e,[Mod(3,'x^2+1),1]) *** ^-------------------------------- *** ellpointtoz: incorrect type in ellpointtoz (t_VEC). 3 + 11^2 + 2*11^3 + 3*11^4 + 6*11^5 + 10*11^6 + 8*11^7 + O(11^8) O(11^8) Mod((2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + O(3^9 )), x^2 + (1 + 3 + 2*3^4 + 3^8 + O(3^9))) Mod(O(3^9), x^2 + (1 + 3 + 2*3^4 + 3^8 + O(3^9))) *** at top-level: testzellQp(e,ellmul(e,[0,0],2)) *** ^------------------------------- *** in function testzellQp: my(a,q,Q);a=ellpointtoz(e,P);Q=ellztopoint(e,a *** ^---------------------------------- *** ellpointtoz: sorry, ellpointtoz when u not in Qp is not yet implemented. Mod((2 + 2*3 + 3^2 + 3^3 + 3^5 + 3^7 + O(3^10))*x + (1 + 3 + 2*3^2 + 2*3^4 + 2*3^5 + 3^6 + 3^8 + 2*3^9 + O(3^10)), x^2 + (3 + 3^3 + 2*3^4 + 3^5 + 2*3^6 + 3^7 + 2*3^8 + 3^9 + 2*3^10 + 3^11 + O(3^13))) Mod(O(3^10)*x + O(3^10), x^2 + (3 + 3^3 + 2*3^4 + 3^5 + 2*3^6 + 3^7 + 2*3^8 + 3^9 + 2*3^10 + 3^11 + O(3^13))) Mod((2^2 + 2^4 + 2^5 + 2^6 + 2^8 + O(2^10))*x + (1 + 2 + 2^2 + 2^8 + O(2^11) ), x^2 + (1 + 2^2 + 2^4 + 2^5 + 2^7 + 2^8 + 2^9 + O(2^11))) Mod(O(2^11)*x + O(2^9), x^2 + (1 + 2^2 + 2^4 + 2^5 + 2^7 + 2^8 + 2^9 + O(2^1 1))) 4*5 + 3*5^2 + 2*5^4 + 2*5^5 + 3*5^6 + 3*5^7 + 3*5^8 + 3*5^9 + 3*5^10 + O(5^1 1) O(5^10) 2 + O(2^8) O(2^9) 2^7 + 2^8 + 2^10 + 2^11 + 2^13 + 2^15 + O(2^18) O(2^15) [Mod(0, 11), Mod(0, 11), Mod(0, 11), Mod(1, 11), Mod(1, 11), Mod(0, 11), Mod (2, 11), Mod(4, 11), Mod(10, 11), Mod(7, 11), Mod(5, 11), Mod(10, 11), Mod(9 , 11), Vecsmall([3]), [11, [9, 5, [6, 0, 0, 0]]], [0, 0, 0, 0]] 1 [0.86602540378443864676372317075293618347 - 1/2*I, -0.8660254037844386467637 2317075293618348 - 1/2*I] [-2, 3] [0, 1] [1, 0, 0, 0] 0.035247504442186170440172838583518049039 *** at top-level: ellheight(E,[0.,0]) *** ^------------------- *** ellheight: incorrect type in ellheight [not a rational point] (t_VEC). [1, 0, 0, 0] [100000000000000000039, 0, 0, 0] [0, 0, 0, 1, 1, 0, 2, 4, -1, -48, -864, -496, 6912/31, Vecsmall([1]), [Vecsm all([128, -1])], [0, 0, 0, 0, 0, 0, 0, [[2]~]]] [0, 0, 0, 1/16, 1/64, 0, 1/8, 1/16, -1/256, -3, -27/2, -31/256, 6912/31, Vec small([1]), [Vecsmall([128, -1])], [0, 0, 0, 0, 0, 0, 0, [[2]~, [1/2, 0, 0, 0], [0, 0, 0, 1, 1, 0, 2, 4, -1, -48, -864, -496, 6912/31, Vecsmall([1]), [V ecsmall([128, -1])], [0, 0, 0, 0, 0, 0, 0, [[2]~]]]]]] 0 20 0 0 -16 0 -4 14 8 0 0 0 26 0 2 0 -28 11124672632 0 0 0 0 0 9623756642 1757839784 0 10364773916 0 -11268052540 -89 20565254 10819287710 0 0 0 8122434446 1728 0 0 -22 0 -14 0 -22 0 0 26 0 18 0 -14 2 0 0 -11632185758 0 11654847458 0 6266694946 12139026234 0 -765697030 0 -993589 2958 0 11860023378 -8888351742 0 -12108381446 0 -12120201878 -3375 16 0 -10 0 -22 24 0 -20 0 0 4 0 8 -18 -26 0 3823447300 13247194 -10908503128 0 1880681120 0 0 12050551284 10977324518 0 0 0 -948699894 0 0 9979357082 11495943932 0 8000 0 -18 6 22 0 0 0 2 0 0 18 0 0 22 0 0 -10793410270 0 0 30 0 0 0 2640064994 8901937002 0 0 0 0 8077589434 0 5325840 630 -5129549082 0 54000 20 0 0 16 0 4 -14 -8 0 0 0 26 0 2 0 -28 -11124672632 0 0 0 0 0 -9623756642 1757839784 0 10364773916 0 -11268052540 8 920565254 -10819287710 0 0 0 8122434446 -32768 0 0 3 0 0 0 23 16 0 0 21 25 -15 0 0 -20 7894594559 0 0 9919498893 0 0 -7887871151 0 0 0 0 0 491192422 -8259190543 0 0 0 12121352347 287496 0 0 22 0 -14 0 22 0 0 -26 0 -18 0 14 2 0 0 -11632185758 0 11654847458 0 -6266694946 -12139026234 0 -765697030 0 99358 92958 0 11860023378 8888351742 0 -12108381446 0 12120201878 -884736 0 7 23 -9 11 0 18 -24 0 0 0 0 17 0 -22 -25 0 -8412576737 0 0 0 0 8538343901 12113814432 -11651750401 12092421657 0 0 0 0 0 -11058211849 0 -1330007630 -12288000 20 0 0 -23 0 19 14 25 0 0 0 7 0 23 0 -11 -9788647777 0 0 0 0 0 11231998687 11288673199 0 304785419 0 -11268052540 268 1012851 10819287710 0 0 0 -11884260649 16581375 16 0 10 0 22 24 0 -20 0 0 -4 0 8 -18 -26 0 -3823447300 13247194 -10908503128 0 1880681120 0 0 12050551284 10977324518 0 0 0 948699894 0 0 9979357082 11495943932 0 -884736000 11 0 0 -13 0 0 0 0 -25 -2 0 -6 0 -27 -10 0 -12128231367 0 -9395300833 -435256334 0 0 0 -11932204400 -10588952138 0 0 0 0 0 0 -7319300662 0 0 -147197952000 -21 -16 0 0 -23 1 5 7 20 -25 0 11 0 13 0 -27 0 11781526319 1637387588 0 12146798315 0 -8198706882 0 3977562293 8890885111 -9549303299 -11553067388 9924967665 3852111021 0 5199002617 772472488 0 -262537412640768000 0 19 0 0 0 -21 0 0 4 -23 8 0 0 0 -25 -12 0 0 6564371741 0 0 2618909413 0 2136229176 0 0 0 4357107277 1635802689 30896 18289 0 -5064045658 0 0 4294985035 [0, 1, [5, 0, 0, 0], 1] 1 0 [6.2500000000000000000000000000000000000, -140.62500000000000000000000000000 000000] error("incorrect type in checkell (t_VEC).") [0, 0, 0, x^2, x, 0, 2*x^2, 4*x, -x^4, -48*x^2, -864*x, -64*x^6 - 432*x^2, - 6912*x^4/(-4*x^4 - 27), Vecsmall([0]), [Vecsmall([128, 0])], [0, 0, 0, 0]] *** at top-level: ellminimalmodel(E) *** ^------------------ *** ellminimalmodel: incorrect type in ellminimalmodel (E / number field) (t_VEC). *** at top-level: ellweilpairing(E,[0],[0],1) *** ^--------------------------- *** ellweilpairing: incorrect type in checkell over Fq (t_VEC). *** at top-level: ellinit([1]) *** ^------------ *** ellinit: incorrect type in ellxxx [not an elliptic curve (ell5)] (t_VEC). *** at top-level: ellinit([1,1],quadgen(5)) *** ^------------------------- *** ellinit: incorrect type in elliptic curve base_ring (t_QUAD). *** at top-level: ellinit([Mod(1,2),1],O(2)) *** ^-------------------------- *** ellinit: incorrect type in elliptic curve base_ring (t_VEC). *** at top-level: ellinit([O(2),1],ffgen(2^3)) *** ^---------------------------- *** ellinit: incorrect type in elliptic curve base_ring (t_VEC). *** at top-level: ellinit([O(2),1],1.) *** ^-------------------- *** ellinit: incorrect type in elliptic curve base_ring (t_VEC). [0, 0, 0, 1, 2, 0, 2, 8, -1, -48, -1728, -1792, 432/7, Vecsmall([0]), [Vecsm all([128, -1])], [0, 0, 0, 0]] [0, 0, 0, 0, 1, 0, 0, 4, 0, 0, 1, 3, 0, Vecsmall([4]), [0, [Vecsmall([0]), V ecsmall([0, 1]), [Vecsmall([0, 1]), Vecsmall([0]), Vecsmall([0]), Vecsmall([ 0])]]], [0, 0, 0, 0]] *** at top-level: ellinit([ffgen(5),1],3) *** ^----------------------- *** ellinit: inconsistent moduli in ellinit: 3 != 5 [0, 0, 0, 1.0000000000000000000000000000000000000, 1, 0, 2.00000000000000000 00000000000000000000, 4, -1.0000000000000000000000000000000000000, -48.00000 0000000000000000000000000000000, -864, -496.00000000000000000000000000000000 000, 222.96774193548387096774193548387096774, Vecsmall([0]), [Vecsmall([128, -1])], [0, 0, 0, 0]] *** at top-level: ellinit([1.,Mod(1,3)]) *** ^---------------------- *** ellinit: incorrect type in elliptic curve base_ring (t_VEC). 1 -1 1 1 2170814464 4 5.5851222210291762172101660392028515730 -21952 6 0.33022365934448053902826194612283487754 3.5069511370460869021391160508020304780 -52760 -52832 [[1, -1], 2] [[509051665/47782462464, -2265512629515497/10444864034930688], 12] ellformalw t^3 - t^5 + t^6 - t^7 - 3*t^8 + 9*t^9 - 2*t^10 - 21*t^11 + 45*t^12 - 21*t^13 - 140*t^14 + 339*t^15 - 91*t^16 - 1051*t^17 + 2394*t^18 + O(t^19) x^3 - x^5 + x^6 - x^7 + O(x^8) t^3 - t^5 + t^6 - t^7 + O(t^8) ellformalpoint [t^-2 + 1 - t + 2*t^2 + t^3 - 5*t^4 + 3*t^5 + 5*t^6 - 19*t^7 + 22*t^8 + 33*t ^9 - 129*t^10 + 111*t^11 + 228*t^12 - 855*t^13 + O(t^14), -t^-3 - t^-1 + 1 - 2*t - t^2 + 5*t^3 - 3*t^4 - 5*t^5 + 19*t^6 - 22*t^7 - 33*t^8 + 129*t^9 - 11 1*t^10 - 228*t^11 + 855*t^12 + O(t^13)] [x^-2 + 1 - x + 2*x^2 + O(x^3), -x^-3 - x^-1 + 1 - 2*x + O(x^2)] [t^-2 + 1 - t + 2*t^2 + O(t^3), -t^-3 - t^-1 + 1 - 2*t + O(t^2)] ellformaldifferential [1 - t^2 + 2*t^3 - 3*t^4 - 6*t^5 + 23*t^6 - 12*t^7 - 53*t^8 + 160*t^9 - 131* t^10 - 470*t^11 + 1471*t^12 - 882*t^13 - 4257*t^14 + 12628*t^15 + O(t^16), t ^-2 + t - 2*t^2 - 2*t^3 + 11*t^4 - 9*t^5 - 18*t^6 + 78*t^7 - 94*t^8 - 175*t^ 9 + 725*t^10 - 676*t^11 - 1603*t^12 + 6293*t^13 + O(t^14)] [1 - x^2 + 2*x^3 - 3*x^4 + O(x^5), x^-2 + x - 2*x^2 + O(x^3)] [1 - t^2 + 2*t^3 - 3*t^4 + O(t^5), t^-2 + t - 2*t^2 + O(t^3)] ellformallog t - 1/3*t^3 + 1/2*t^4 - 3/5*t^5 - t^6 + 23/7*t^7 - 3/2*t^8 - 53/9*t^9 + 16*t ^10 - 131/11*t^11 - 235/6*t^12 + 1471/13*t^13 - 63*t^14 - 1419/5*t^15 + 3157 /4*t^16 + O(t^17) x - 1/3*x^3 + 1/2*x^4 - 3/5*x^5 + O(x^6) t - 1/3*t^3 + 1/2*t^4 - 3/5*t^5 + O(t^6) ellformalexp t + 1/3*t^3 - 1/2*t^4 + 14/15*t^5 - 1/6*t^6 - 76/315*t^7 - 7/10*t^8 + 7547/1 1340*t^9 + 977/3780*t^10 - 5116/22275*t^11 - 78977/113400*t^12 + 3069607/608 1075*t^13 + 1651/2970*t^14 - 526660427/2554051500*t^15 - 5754943993/68108040 00*t^16 + O(t^17) x + 1/3*x^3 - 1/2*x^4 + 14/15*x^5 + O(x^6) t + 1/3*t^3 - 1/2*t^4 + 14/15*t^5 + O(t^6) *** at top-level: ellformalw(e,0) *** ^--------------- *** ellformalw: domain error in ellformalw: precision <= 0 *** at top-level: ellformalw(e,-1) *** ^---------------- *** ellformalw: domain error in ellformalw: precision <= 0 242.47010035195076100129810400142304776 0 [-0.52751724240790530394437835702346995884*I, -0.090507650025885335533571758 708283389896*I] 2 Total time spent: 548 pari-2.11.2/src/test/32/apply0000644000175000017500000000053613326135265014232 0ustar billbill[1, 4, 9, 16] [1 4] [9 16] 16*x^2 + 9*x + 4 4 + 9*x + 16*x^2 + O(x^3) List([1, 4, 9, 16]) List([1, 2]) [0, 1, 2] [0, 1, 2] [2, 3] [2, 3] [1, 3] 24 [[[1, 2], 3], 4] 256 -9/19 1: 2, 3 15 *** at top-level: call(Strprintf,["%d",10]) *** ^------------------------- *** call: incorrect type in call (t_INT). Total time spent: 1 pari-2.11.2/src/test/32/bnflog0000644000175000017500000000132113201017466014337 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). [2, 1] [1, 2] [1, 1] 225 64 432 [6, 1] [6, 1] [1, 2] [1024] [[4, 2], [4], [2]] [] [[5], [5], []] [2, 2] [[], [], [2]] [10, 2, 2] [[512, 2], [256], [2, 2]] [6, 2, 2] [[2, 2, 2], [], [2, 2, 2]] [4, 4] [[613], [613], []] [14] [[], [], []] [[3], [3], []] [[7], [], [7]] [273] [[4], [4], []] [[3], [], [3]] [[13, 13], [13], [13]] [14] [[2], [], [2]] [[9], [9], []] [[], [], []] [6, 6, 2] [[2, 2, 2], [], [2, 2, 2]] [[3], [], [3]] [150, 15] [[2, 2], [2], [2]] [[3, 3], [], [3, 3]] [[25, 5], [], [25, 5]] [105, 3] [[25, 5, 5], [25, 5, 5], []] [6, 2, 2, 2] [[2, 2, 2, 2], [], [2, 2, 2, 2]] [[3, 3], [3], [3]] [[5, 5], [5, 5], []] [[4], [2], [2]] Total time spent: 1752 pari-2.11.2/src/test/32/valuation0000644000175000017500000000143713201017466015102 0ustar billbill+oo +oo +oo +oo 0 0 0 0 0 -1 0 0 ERROR ERROR 0 0 0 ERROR 0 0 ERROR 0 0 0 ERROR ERROR 0 0 1 0 0 0 ERROR 1 0 0 0 0 ERROR 0 1 0 0 0 0 1 1 ERROR *** at top-level: valuation(0,1) *** ^-------------- *** valuation: domain error in gvaluation: p = 1 *** at top-level: valuation(0,-1) *** ^--------------- *** valuation: domain error in gvaluation: p = -1 *** at top-level: valuation(0,0) *** ^-------------- *** valuation: domain error in gvaluation: p = 0 *** at top-level: valuation(0,I) *** ^-------------- *** valuation: domain error in gvaluation: p = I 2 0 2 1.0000000000000000000000000000000000000 - 1.00000000000000000000000000000000 00000*x + O(x^2) 1 O(x) -oo -oo -oo Total time spent: 0 pari-2.11.2/src/test/32/nfsplitting0000644000175000017500000000665713326135265015460 0ustar billbill *** at top-level: nfsplitting(1) *** ^-------------- *** nfsplitting: incorrect type in checknf [please apply nfinit()] (t_INT). x x x y x^120 + 900*x^116 + 508450*x^112 + 3093750*x^110 + 233445700*x^108 + 6244625 000*x^106 + 86356219375*x^104 + 6147962343750*x^102 - 9942720082555*x^100 + 3349338126562500*x^98 - 1654757011326100*x^96 + 1309871930885937500*x^94 + 1 2436255994792015950*x^92 + 627622053389650906250*x^90 + 10990443401191124447 575*x^88 + 376988045414723757750000*x^86 + 5753330797521192519076250*x^84 + 177095246957480012540937500*x^82 + 2532236050928665494862464460*x^80 + 66602 887475268525125564843750*x^78 + 900151039266122540911840715400*x^76 + 176011 62771342375630639534375000*x^74 + 297430062665456220256577151477075*x^72 + 2 930309217240262538594060043562500*x^70 + 72799466070683508609604970583641825 *x^68 + 544024340743931708706461811877750000*x^66 + 815192787279703050465510 9860308253125*x^64 + 109815744628769444357250042241632031250*x^62 + 14587139 1991398970515017378630342573815*x^60 + 8649858988205592244458199943754150781 250*x^58 - 28260531870665143418958164521279483618600*x^56 - 4028396539193675 80525292500109637748437500*x^54 + 106953851435466039913768978932670329879545 0*x^52 - 117799258418763740543911272144086881778781250*x^50 + 21225667468078 1774826232152789145244306484575*x^48 - 1157371878847856250227888707333507692 960375000*x^46 - 60605754850991956455326492294916133973935406250*x^44 - 2931 8354970878696157506850322206226355212812500*x^42 + 2969007992022620344286139 006599749400952695117330*x^40 + 18940874618289173736585545257929220177884468 75000*x^38 - 462258652890221831497176176774279926624850728121600*x^36 - 7387 86176377220399331352006274159764367952001562500*x^34 - 271554668935406462553 6181765731364171583296080250050*x^32 + 9040698598507624900324513465462196895 3701672354656250*x^30 + 6671002781929457078914865848663080213892617538608397 00*x^28 + 8674210771396452568056517384098059387025568935299000000*x^26 + 398 10727829888294052738784121978440350534098819581529375*x^24 + 165091395418543 016833097401882144226762030772580167343750*x^22 + 27455383835034865960434299 3914027364500470431599325551949*x^20 + 5727389048071940962286881233887371037 10592833161132812500*x^18 + 680363944593316626764117242129370969026933149388 6975000*x^16 + 1207367254754819680587174702262138380906821896553743750000*x^ 14 + 1324631954910684324357431850891744535485699735726160156250*x^12 - 24458 13956434295007552447734476548803933624572506738281250*x^10 + 309719742207326 9812049512199025218992726116649855468750000*x^8 + 34385172087788316066248428 61577883803163997230102539062500*x^6 - 3386560639084519090735630415918618954 238015795898437500000*x^4 + 105395630279973820390312384403539563373280780029 2968750000*x^2 + 1865600384408017914532215685346909435223786258697509765625 x^4 + 2*x^2 + 4 x^2 + 1 x^32 - 10356*x^24 + 127847862*x^16 - 11069073684*x^8 + 565036352721 x^32 - 10356*x^24 + 127847862*x^16 - 11069073684*x^8 + 565036352721 x^32 - 10356*x^24 + 127847862*x^16 - 11069073684*x^8 + 565036352721 x^10 - 30*x^8 + 325*x^6 - 1500*x^4 + 2500*x^2 + 2000 x^22 + x^21 + x^20 + x^19 + x^18 + x^17 + x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1 x^42 + 48020*x^28 + 96001584*x^14 + 52706752 x^42 + 48020*x^28 + 96001584*x^14 + 52706752 *** nfsplitting: Warning: ignoring incorrect degree bound 43. x^42 + 48020*x^28 + 96001584*x^14 + 52706752 Total time spent: 220 pari-2.11.2/src/test/32/op0000644000175000017500000000013213201017466013505 0ustar billbill2 3 1 10 2 [2, 3, 1, 10, 2] 3 1 2 2 [2, 2, 2, 10, 2] [3, 3, 1, 10, 1] Total time spent: 0 pari-2.11.2/src/test/32/rnf0000644000175000017500000010004513375013132013656 0ustar billbill[[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [6, 6, 6, 6]] [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [6, 6, 6, 6]] [] [[1, 0, 0, 0, 0, [-361894/1129, 99/1129]~, [-724429/1129, 1480/1129]~, [-929 3266/21451, 168/1129]~, [-18602992/21451, 39304/21451]~; 0, 1, 0, 0, 0, [167 146/1129, -108/1129]~, [334588/1129, -808/1129]~, [15473737/21451, 392/1129] ~, [30974892/21451, -39940/21451]~; 0, 0, 1, 0, 0, [-253060/1129, 328/1129]~ , [-506568/1129, 1552/1129]~, [-5866950/21451, -227/1129]~, [-11744297/21451 , 12168/21451]~; 0, 0, 0, 1, 0, [-68390/1129, 171/1129]~, [-136901/1129, 584 /1129]~, [486725/21451, 165/1129]~, [974315/21451, 4540/21451]~; 0, 0, 0, 0, 1, [90512/1129, -384/1129]~, [181184/1129, -1088/1129]~, [-5551416/21451, - 403/1129]~, [-11112673/21451, 4368/21451]~; 0, 0, 0, 0, 0, [-564/1129, -1/11 29]~, -1, 9/19, [20340/21451, -36/21451]~; 0, 0, 0, 0, 0, 1, [2260/1129, -4/ 1129]~, 7/19, [15820/21451, -28/21451]~; 0, 0, 0, 0, 0, 0, 0, [-18619/21451, -1/1129]~, [-37271/21451, 28/21451]~; 0, 0, 0, 0, 0, 0, 0, 1/19, [2260/2145 1, -4/21451]~], [1, 1, 1, 1, 1, 1, 1, 1, [1, 0; 0, 1]], 1, 1] [[[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, 1]], [1, 0, 0; 0, 1, 0; 0, 0, 1]] [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 1; 0, 0, 0, 1, 0, 0, 0, 0, -1, -1, 1; 0, 0, 0, 0, 1, 0, 0, 0, 1, -1, 1; 0, 0, 0, 0, 0, 1, 0, 0, -1, 1, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1, -1, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, -1; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 ; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1/3, 1/3, 1/3], 6487513772307278389925284499624661, 648751 3772307278389925284499624661] [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 1; 0, 0, 0, 1, 0, 0, 0, 0, -1, -1, 1; 0, 0, 0, 0, 1, 0, 0, 0, 1, -1, 1; 0, 0, 0, 0, 0, 1, 0, 0, -1, 1, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1, -1, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, -1; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 ; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1/3, 1/3, 1/3], 6487513772307278389925284499624661, 648751 3772307278389925284499624661] [[1, -2018006054; 0, 1], [1, [1/1009003027, 3/4036012108; 0, 1/4036012108]], [4036, 3027; 0, 1009], [0, -1009]~] [[1, -2018006054; 0, 1], [1, [1/1009003027, 3/4036012108; 0, 1/4036012108]], [4036, 3027; 0, 1009], [0, -1009]~] [[1, -2018006054; 0, 1], [1, [1/1009003027, 3/4036012108; 0, 1/4036012108]], [4036, 3027; 0, 1009], [0, -1009]~] [[4036, 3027; 0, 1009], [0, -1009]~] [[4, 3; 0, 1], [0, -1009]~] [[4036, 3027; 0, 1009], [0, -1009]~] [[Mat(861), [1]], [[[;], [;], [;], [;], []~, 0, [y, [1, 0], 1, 1, [Mat(1), M at(1), Mat(1), Mat(1), 1, Mat(1), [1, 0], []], [0.E-57], [1], Mat(1), Mat(1) ], [[1, [], []], 1, 1, [2, -1], []], [[;], [], []], [0, 0, [-1]]], [[Mat(861 ), [1]], [960, [120, 2, 2, 2], [808, 286, 575, [-860]~]], [[[3, [3]~, 1, 1, 1], 1; [7, [7]~, 1, 1, 1], 1; [41, [41]~, 1, 1, 1], 1], [[3, [3]~, 1, 1, 1], 1; [7, [7]~, 1, 1, 1], 1; [41, [41]~, 1, 1, 1], 1]], [[[[2], [-286], Mat(3) , [[1, [1], [3, [3]~, 1, 1, 1]]~, 2, [2, Mat([2, 1])]]], [[6], [493], Mat(7) , [[1, [1], [7, [7]~, 1, 1, 1]]~, 3, [6, [2, 1; 3, 1]]]], [[40], [211], Mat( 41), [[1, [1], [41, [41]~, 1, 1, 1]]~, 6, [40, [2, 3; 5, 1]]]]], [[2], Vecsm all([1]), Mat(1/861), 861861/2000, Mat(861)]], [[0; 0; 1; 0], [-20; 1; 0; 0] , [3; -1; 0; 0], [0; 0; 0; 1]]], [], [[;], [1, 0, 0, 0; 0, 1, 0, -1; 0, 0, 1 , -1], [1, 0, 0; 0, -1, 0; 0, 0, -1; 0, 0, 0]], [480, [120, 2, 2], [808, 286 , 575]], [Mat([0, 0, 0, 1]), Mat(-2), 1]], [1, 0, 0; 0, 2, 0; 0, 0, 2]] [[Mat(861), [1]], [[[;], [;], [;], [;], []~, 0, [y, [1, 0], 1, 1, [Mat(1), M at(1), Mat(1), Mat(1), 1, Mat(1), [1, 0], []], [0.E-57], [1], Mat(1), Mat(1) ], [[1, [], []], 1, 1, [2, -1], []], [[;], [], []], [0, 0, [-1]]], [[Mat(861 ), [1]], [960, [120, 2, 2, 2], [808, 286, 575, [-860]~]], [[[3, [3]~, 1, 1, 1], 1; [7, [7]~, 1, 1, 1], 1; [41, [41]~, 1, 1, 1], 1], [[3, [3]~, 1, 1, 1], 1; [7, [7]~, 1, 1, 1], 1; [41, [41]~, 1, 1, 1], 1]], [[[[2], [-286], Mat(3) , [[1, [1], [3, [3]~, 1, 1, 1]]~, 2, [2, Mat([2, 1])]]], [[6], [493], Mat(7) , [[1, [1], [7, [7]~, 1, 1, 1]]~, 3, [6, [2, 1; 3, 1]]]], [[40], [211], Mat( 41), [[1, [1], [41, [41]~, 1, 1, 1]]~, 6, [40, [2, 3; 5, 1]]]]], [[2], Vecsm all([1]), Mat(1/861), 861861/2000, Mat(861)]], [[0; 0; 1; 0], [-20; 1; 0; 0] , [3; -1; 0; 0], [0; 0; 0; 1]]], [], [[;], [1, 0, 0, 0; 0, 1, 0, -1; 0, 0, 1 , -1], [1, 0, 0; 0, -1, 0; 0, 0, -1; 0, 0, 0]], [480, [120, 2, 2], [808, 286 , 575]], [Mat([0, 0, 0, 1]), Mat(-2), 1]], [1, 0, 0; 0, 2, 0; 0, 0, 2]] [Mat(117), [0]] [[8, 2; 0, 1], [2, 0; 0, 1], [1, 0; 0, 1]] 1 1 1 1 *** rnfisabelian: Warning: non-monic polynomial. Result of the form [nf,c]. *** rnfisabelian: Warning: non-monic polynomial. Result of the form [nf,c]. 0 *** rnfisabelian: Warning: non-monic polynomial. Result of the form [nf,c]. 1 1 [(-18*y^2 + 12*y + 12)*x^2 + (18*y^2 - 18*y - 8)*x + (-24*y^2 + 21*y + 15), 1] 2 2 [x, -1] *** rnfisnorm: Warning: useless flag in rnfisnorm: the extension is Galois. [1, 2] -28124/93*x^3 + 14062/31*x^2 + 562480/93*x + 166769/31 Mod(x^5 + x^2 + 2, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) Mod(z^2, z^3 + z^2 - 2*z - 1) [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, 1]] [[-9843, 391, -3472]~ [5826, -17043, -23934]~ [-183013449, -53300400, -56068 6734]~ [-4831228968, -2610454140, -9159229488]~] [[3393, 2719, 1883]~ [3799, -2741, -7311]~ [44971153, -74830626, -108534066] ~ [2330522034, 204707177, -1049209305]~] [[3690, -3485, 1185]~ [-7214, 11969, 18952]~ [135688819, 52627092, 452330447 ]~ [1633778037, 574919842, 6646910401]~] [[4169, 4338, 229]~ [722, 8865, 13444]~ [-106537503, 134281548, 137000286]~ [1060748979, 4131422295, 3026338070]~] [0 1 0 0] [0 0 1 0] [0 0 0 1] [[6017899359, 5241880500, 2055449334; 0, 87, 12; 0, 0, 3], [1, 0, 0; 0, 1, 0 ; 0, 0, 1], [1, 0, 0; 0, 1, 0; 0, 0, 1]] [1 [-8073, 4800, -5591]~ [-315011, 112392, -182676]~] [0 1 [-87, -173, -155]~] [0 0 1] [[165073371/2005966453, -120336277/2005966453, -220005359/2005966453]~ [436, -266, 285]~ 0] [[-36888191/2005966453, 61195737/2005966453, 56154718/2005966453]~ [-321, 17 8, -216]~ [-4, -4, -5]~] [[-137636147/2005966453, 99618172/2005966453, 248701141/2005966453]~ [-20, 3 7, 3]~ [7, 1, -3]~] [1 0 0] [0 1 0] [0 0 1] [[1, -1/2; 0, 1], [1, 1]] [Mod(1/6*y + 2/3, y^2 - 40), -3] [Mod(1/2*y + 4, y^2 - 40), 1] [Mod(-1, y^3 - 21), -2] [Mod(-y + 3, y^3 - 21), 1] [1, 1]: [2, 0]~ [1, 2]: Mod(2, x^2 + Mod(-y, y^3 - 21)) [1, 3]: 2 [1, 4]: 2 [1, 5]: 2 [1, 6]: 2 [1, 7]: 4 [1, 8]: 4 [2, 1]: [1/2, 0]~ [2, 2]: Mod(1/2, x^2 + Mod(-y, y^3 - 21)) [2, 3]: 1/2 [2, 4]: 1/2 [2, 5]: 1/2 [2, 6]: 1/2 [2, 7]: 1 [2, 8]: 1/4 [3, 1]: [Mod(y^2 + y, y^3 - 21), Mod(1, y^3 - 21)]~ [3, 2]: Mod(x + Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [3, 3]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [3, 4]: Mod(x^2 + x, x^6 - 21) [3, 5]: error("inconsistent variables in nf_to_scalar_or_basis, x != y.") [3, 6]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [3, 7]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [3, 8]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [4, 1]: [1, 0]~ [4, 2]: Mod(1, x^2 + Mod(-y, y^3 - 21)) [4, 3]: Mod(1, x^2 + Mod(-y, y^3 - 21)) [4, 4]: Mod(1, x^6 - 21) [4, 5]: 1 [4, 6]: 1 [4, 7]: 2 [4, 8]: 1 [5, 1]: [1/2, 0]~ [5, 2]: Mod(1/2, x^2 + Mod(-y, y^3 - 21)) [5, 3]: Mod(1/2, x^2 + Mod(-y, y^3 - 21)) [5, 4]: Mod(1/2, x^6 - 21) [5, 5]: 1/2 [5, 6]: 1/2 [5, 7]: 1 [5, 8]: 1/4 [6, 1]: [Mod(y, y^3 - 21), 0]~ [6, 2]: Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [6, 3]: Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [6, 4]: Mod(x^2, x^6 - 21) [6, 5]: Mod(x^2, x^6 - 21) [6, 6]: Mod(y, y^3 - 21) [6, 7]: Mod(2*y, y^3 - 21) [6, 8]: Mod(y^2, y^3 - 21) [7, 1]: error("inconsistent moduli in rnfalgtobasis: x^6 - 21 != y^3 - 21") [7, 2]: error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") [7, 3]: 1 [7, 4]: Mod(1, x^6 - 21) [7, 5]: Mod(1, x^6 - 21) [7, 6]: 1 [7, 7]: 2 [7, 8]: 1 [8, 1]: error("inconsistent moduli in rnfalgtobasis: x^6 - 21 != y^3 - 21") [8, 2]: error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") [8, 3]: 1/2 [8, 4]: Mod(1/2, x^6 - 21) [8, 5]: Mod(1/2, x^6 - 21) [8, 6]: 1/2 [8, 7]: 1 [8, 8]: 1/4 [9, 1]: error("inconsistent moduli in rnfalgtobasis: x^6 - 21 != y^3 - 21") [9, 2]: error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") [9, 3]: Mod(x, x^2 + Mod(-y, y^3 - 21)) [9, 4]: Mod(x, x^6 - 21) [9, 5]: Mod(x, x^6 - 21) [9, 6]: error("domain error in rnfeltdown: element not in the base field") [9, 7]: 0 [9, 8]: Mod(-y, y^3 - 21) [10, 1]: [Mod(y^2 + 1/2*y, y^3 - 21), Mod(1, y^3 - 21)]~ [10, 2]: Mod(x + Mod(1/2*y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [10, 3]: Mod(x + Mod(1/2*y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [10, 4]: Mod(1/2*x^2 + x, x^6 - 21) [10, 5]: error("inconsistent moduli in nf_to_scalar_or_basis: x^2 - y != y^3 - 21") [10, 6]: error("domain error in rnfeltdown: element not in the base field") [10, 7]: Mod(y, y^3 - 21) [10, 8]: Mod(1/4*y^2 - y, y^3 - 21) [11, 1]: [Mod(y, y^3 - 21), 0]~ [11, 2]: Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [11, 3]: Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [11, 4]: Mod(x^2, x^6 - 21) [11, 5]: Mod(x^2, x^6 - 21) [11, 6]: Mod(y, y^3 - 21) [11, 7]: Mod(2*y, y^3 - 21) [11, 8]: Mod(y^2, y^3 - 21) [12, 1]: error("incorrect priority in rnfalgtobasis: variable z >= y") [12, 2]: error("inconsistent variables in rnfbasistoalg, z != x.") [12, 3]: error("inconsistent variables in rnfeltabstorel, z != x.") [12, 4]: error("inconsistent variables in eltreltoabs, z != y.") [12, 5]: error("inconsistent variables in nf_to_scalar_or_basis, z != y.") [12, 6]: error("inconsistent variables in rnfeltabstorel, z != x.") [12, 7]: error("inconsistent variables in rnfeltabstorel, z != x.") [12, 8]: error("inconsistent variables in rnfeltabstorel, z != x.") [13, 1]: error("inconsistent moduli in rnfalgtobasis: y^2 + 1 != y^3 - 21") [13, 2]: error("inconsistent moduli in rnfbasistoalg: y^2 + 1 != y^3 - 21") [13, 3]: error("inconsistent moduli in rnfeltabstorel: y^2 + 1 != x^6 - 21") [13, 4]: error("inconsistent moduli in rnfeltreltoabs: y^2 + 1 != y^3 - 21") [13, 5]: error("inconsistent moduli in nf_to_scalar_or_basis: y^2 + 1 != y^3 - 21") [13, 6]: error("inconsistent moduli in rnfeltdown: y^2 + 1 != y^3 - 21") [13, 7]: error("inconsistent moduli in rnfeltabstorel: y^2 + 1 != x^6 - 21") [13, 8]: error("inconsistent moduli in rnfeltabstorel: y^2 + 1 != x^6 - 21") [14, 1]: error("inconsistent dimensions in rnfalgtobasis.") [14, 2]: error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts).") [14, 3]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [14, 4]: error("incorrect type in rnfeltreltoabs (t_COL).") [14, 5]: error("incorrect type in nf_to_scalar_or_basis (t_COL).") [14, 6]: error("incorrect type in rnfeltdown (t_COL).") [14, 7]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [14, 8]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [15, 1]: [1, 2]~ [15, 2]: Mod(2*x + Mod(-2*y^2 + 1, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [15, 3]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [15, 4]: error("incorrect type in rnfeltreltoabs (t_COL).") [15, 5]: error("incorrect type in nf_to_scalar_or_basis (t_COL).") [15, 6]: error("incorrect type in rnfeltdown (t_COL).") [15, 7]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [15, 8]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [16, 1]: [1, Mod(y, y^3 - 21)]~ [16, 2]: Mod(Mod(y, y^3 - 21)*x - 20, x^2 + Mod(-y, y^3 - 21)) [16, 3]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [16, 4]: error("incorrect type in rnfeltreltoabs (t_COL).") [16, 5]: error("incorrect type in nf_to_scalar_or_basis (t_COL).") [16, 6]: error("incorrect type in rnfeltdown (t_COL).") [16, 7]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [16, 8]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [17, 1]: error("incorrect type in rnfalgtobasis (t_COMPLEX).") [17, 2]: error("incorrect type in nf_to_scalar_or_alg (t_COMPLEX).") [17, 3]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [17, 4]: error("incorrect type in rnfeltreltoabs (t_COL).") [17, 5]: error("incorrect type in nf_to_scalar_or_basis (t_COL).") [17, 6]: error("incorrect type in rnfeltdown (t_COL).") [17, 7]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [17, 8]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [18, 1]: error("incorrect type in rnfalgtobasis [not in Q[X]] (t_POL).") [18, 2]: error("incorrect type in rnfbasistoalg [not in Q[X]] (t_POL).") [18, 3]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [18, 4]: error("incorrect type in poltobasis (t_POL).") [18, 5]: error("incorrect type in poltobasis (t_POL).") [18, 6]: error("incorrect type in rnfeltdown [not in Q[X]] (t_POL).") [18, 7]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [18, 8]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [19, 1]: [y, 0]~ [19, 2]: Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [19, 3]: Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) [19, 4]: Mod(x^2, x^6 - 21) [19, 5]: error("inconsistent variables in nf_to_scalar_or_basis, x != y.") [19, 6]: Mod(y, y^3 - 21) [19, 7]: Mod(2*y, y^3 - 21) [19, 8]: Mod(y^2, y^3 - 21) 1: x^2 - 4*x + 4 2: x^2 - x + 1/4 3: x^2 + Mod(-2*y, y^3 - 21)*x + Mod(y^2 - y, y^3 - 21) 4: x^2 - 2*x + 1 5: x^2 - x + 1/4 6: Mod(1, y^3 - 21)*x^2 + Mod(-2*y, y^3 - 21)*x + Mod(y^2, y^3 - 21) 7: error("inconsistent moduli in rnfcharpoly: x^6 - 21 != y^3 - 21") 8: error("inconsistent moduli in rnfcharpoly: x^6 - 21 != y^3 - 21") 9: error("inconsistent moduli in rnfcharpoly: x^6 - 21 != y^3 - 21") 10: x^2 + Mod(-y, y^3 - 21)*x + Mod(1/4*y^2 - y, y^3 - 21) 11: Mod(1, y^3 - 21)*x^2 + Mod(-2*y, y^3 - 21)*x + Mod(y^2, y^3 - 21) 12: error("incorrect priority in rnfcharpoly: variable z >= y") 13: error("inconsistent moduli in rnfcharpoly: y^2 + 1 != y^3 - 21") 14: error("incorrect type in rnfcharpoly (t_COL).") 15: error("incorrect type in rnfcharpoly (t_COL).") 16: error("incorrect type in rnfcharpoly (t_COL).") 17: error("incorrect type in rnfcharpoly (t_COL).") 18: error("incorrect type in rnfcharpoly [not in Q[X]] (t_POL).") 19: x^2 + Mod(-2*y, y^3 - 21)*x + Mod(y^2, y^3 - 21) [1, 1]: [2, 0]~ [1, 2]: Mod(2, x^2 + 1) [1, 3]: 2 [1, 4]: 2 [1, 5]: 2 [1, 6]: 2 [1, 7]: 4 [1, 8]: 4 [2, 1]: [1/2, 0]~ [2, 2]: Mod(1/2, x^2 + 1) [2, 3]: 1/2 [2, 4]: 1/2 [2, 5]: 1/2 [2, 6]: 1/2 [2, 7]: 1 [2, 8]: 1/4 [3, 1]: [-1, 1]~ [3, 2]: Mod(x - 1, x^2 + 1) [3, 3]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [3, 4]: Mod(x - 1, x^2 + 1) [3, 5]: error("inconsistent variables in nf_to_scalar_or_basis, x != y.") [3, 6]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [3, 7]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [3, 8]: error("incorrect type in rnfeltabstorel [not in Q[X]] (t_POL).") [4, 1]: [1/2, 0]~ [4, 2]: Mod(1/2, x^2 + 1) [4, 3]: Mod(1/2, x^2 + 1) [4, 4]: Mod(1/2, x^2 + 1) [4, 5]: 1/2 [4, 6]: 1/2 [4, 7]: 1 [4, 8]: 1/4 [5, 1]: [Mod(-1, y + 1), 0]~ [5, 2]: Mod(Mod(-1, y + 1), x^2 + 1) [5, 3]: Mod(-1, x^2 + 1) [5, 4]: -1 [5, 5]: -1 [5, 6]: -1 [5, 7]: -2 [5, 8]: 1 [6, 1]: [1, 1/2]~ [6, 2]: Mod(1/2*x + 1, x^2 + 1) [6, 3]: Mod(1/2*x + 1, x^2 + 1) [6, 4]: Mod(1/2*x + 1, x^2 + 1) [6, 5]: Mod(1/2*x + 1, x^2 + 1) [6, 6]: error("domain error in rnfeltdown: element not in the base field") [6, 7]: 2 [6, 8]: 5/4 [7, 1]: [0, 1]~ [7, 2]: Mod(x, x^2 + 1) [7, 3]: Mod(x, x^2 + 1) [7, 4]: Mod(x, x^2 + 1) [7, 5]: Mod(x, x^2 + 1) [7, 6]: error("domain error in rnfeltdown: element not in the base field") [7, 7]: 0 [7, 8]: 1 [8, 1]: [0, 1]~ [8, 2]: Mod(x, x^2 + 1) [8, 3]: Mod(x, x^2 + 1) [8, 4]: Mod(x, x^2 + 1) [8, 5]: Mod(x, x^2 + 1) [8, 6]: error("domain error in rnfeltdown: element not in the base field") [8, 7]: 0 [8, 8]: 1 [9, 1]: error("inconsistent moduli in rnfalgtobasis: x^2 - y != y + 1") [9, 2]: error("inconsistent moduli in rnfbasistoalg: x^2 - y != y + 1") [9, 3]: error("inconsistent moduli in rnfeltabstorel: x^2 - y != x^2 + 1") [9, 4]: error("inconsistent moduli in rnfeltreltoabs: x^2 - y != y + 1") [9, 5]: error("inconsistent moduli in nf_to_scalar_or_basis: x^2 - y != y + 1") [9, 6]: error("inconsistent moduli in rnfeltdown: x^2 - y != y + 1") [9, 7]: error("inconsistent moduli in rnfeltabstorel: x^2 - y != x^2 + 1") [9, 8]: error("inconsistent moduli in rnfeltabstorel: x^2 - y != x^2 + 1") [10, 1]: [0, 1]~ [10, 2]: Mod(x, x^2 + 1) [10, 3]: Mod(x, x^2 + 1) [10, 4]: Mod(x, x^2 + 1) [10, 5]: error("inconsistent variables in nf_to_scalar_or_basis, x != y.") [10, 6]: error("domain error in rnfeltdown: element not in the base field") [10, 7]: 0 [10, 8]: 1 [11, 1]: error("inconsistent dimensions in rnfalgtobasis.") [11, 2]: error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts).") [11, 3]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [11, 4]: error("incorrect type in rnfeltreltoabs (t_COL).") [11, 5]: 1 [11, 6]: 1 [11, 7]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [11, 8]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [12, 1]: [1, 2]~ [12, 2]: Mod(2*x + 1, x^2 + 1) [12, 3]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [12, 4]: error("incorrect type in rnfeltreltoabs (t_COL).") [12, 5]: error("incorrect type in nf_to_scalar_or_basis (t_COL).") [12, 6]: error("incorrect type in rnfeltdown (t_COL).") [12, 7]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [12, 8]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [13, 1]: error("inconsistent dimensions in rnfalgtobasis.") [13, 2]: error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts).") [13, 3]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [13, 4]: error("incorrect type in rnfeltreltoabs (t_COL).") [13, 5]: Mod(y, x^2 + 1) [13, 6]: error("incorrect type in rnfeltdown (t_COL).") [13, 7]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") [13, 8]: error("incorrect type in rnfeltabstorel, apply nfinit(rnf) (t_COL). ") 1: x^2 - 4*x + 4 2: x^2 - x + 1/4 3: x^2 + 2*x + 2 4: x^2 - x + 1/4 5: x^2 + 2*x + 1 6: x^2 - 2*x + 5/4 7: x^2 + 1 8: x^2 + 1 9: error("inconsistent moduli in rnfcharpoly: x^2 - y != y + 1") 10: x^2 + 1 11: error("incorrect type in rnfcharpoly (t_COL).") 12: error("incorrect type in rnfcharpoly (t_COL).") 13: error("incorrect type in rnfcharpoly (t_COL).") Mod(1, x^2 - 2) 0 [[1, -66328; 0, 1], [[280970, 12259, 35869; 0, 1, 0; 0, 0, 1], [1, 1/2, 1/2; 0, 1/2, 0; 0, 0, 1/2]]] 1 [280970, x^2 + 12259, x^4 + 35869, -x^4 + x - 66328, -1/2*x^4 + 1/2*x^3 - 33 164*x^2 + 1/2*x - 66349/2, 1/2*x^5 - 66329/2*x^4 - 21/2*x^2 + 1/2*x - 33164] 1 [[3, [0, 1, 0, 0, 0, 0]~, 6, 1]] [[[7, [0, 1, 0]~, 3, 1]], [[7, [0, 1, 0, 0, 0, 0]~, 6, 1]]] [[7, [0, 1, 0, 0, 0, 0]~, 6, 1] 6] [[3, [0, 1, 0, 0, 0, 0]~, 6, 1] 1] [[7, [0, 1, 0, 0, 0, 0]~, 6, 1] 1] [[3, [0, 1, 0, 0, 0, 0]~, 6, 1] 2] [[7, [0, 1, 0, 0, 0, 0]~, 6, 1] 2] 1 [18416, x^2 + 6979, x^4 + 3879, -9208*x^4 + 9208*x, -6979/2*x^4 + 1/2*x^3 + 6979/2*x - 21/2, 1/2*x^5 - 3879/2*x^4 - 21/2*x^2 + 3879/2*x] 1 1 1 [280970 12259 35869] [ 0 1 0] [ 0 0 1] [280970, x^2 + 12259, x^4 + 35869, -140485*x^4 + 140485*x, -12259/2*x^4 + 1/ 2*x^3 + 12259/2*x - 21/2, 1/2*x^5 - 35869/2*x^4 - 21/2*x^2 + 35869/2*x] 1 1: [[1, 0; 0, 1], [2, 1]] [2, 2*x^2, 2*x^4, -x^4 + x, x^3 - 21, x^5 - 21*x^2] error("incorrect type in rnfidealabstorel (t_INT).") 2 [2, 2*x^2, 2*x^4, -x^4 + x, x^3 - 21, x^5 - 21*x^2] [4, 0, 0; 0, 4, 0; 0, 0, 4] 64 [2, 0] 2: [[1, 0; 0, 1], [1/2, 1/4]] [1/2, 1/2*x^2, 1/2*x^4, -1/4*x^4 + 1/4*x, 1/4*x^3 - 21/4, 1/4*x^5 - 21/4*x^2 ] error("incorrect type in rnfidealabstorel (t_FRAC).") 1/2 [1/2, 1/2*x^2, 1/2*x^4, -1/4*x^4 + 1/4*x, 1/4*x^3 - 21/4, 1/4*x^5 - 21/4*x^2 ] [1/4, 0, 0; 0, 1/4, 0; 0, 0, 1/4] 1/64 [1/2, 0] 3: [[1, 42; 0, 1], [[210, 189, 189; 0, 1, 0; 0, 0, 1], [1, 1/2, 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [210, x^2 + 189, x^4 + 189, -x^4 + x + 42, -1/2*x^4 + 1/2*x^3 + 21*x^2 + 1/2 *x + 21/2, 1/2*x^5 + 41/2*x^4 - 21/2*x^2 + 1/2*x + 21] error("incorrect type in rnfidealabstorel (t_POL).") [210, 189, 189; 0, 1, 0; 0, 0, 1] error("inconsistent variables in nf_to_scalar_or_basis, x != y.") [420, 399, 399; 0, 1, 0; 0, 0, 1] 420 [210, Mod(x + Mod(105*y - 84, y^3 - 21), x^2 + Mod(-y, y^3 - 21))] 4: [[1, 0; 0, 1], [1, 1/2]] [1, x^2, x^4, -1/2*x^4 + 1/2*x, 1/2*x^3 - 21/2, 1/2*x^5 - 21/2*x^2] error("incorrect type in rnfidealabstorel (t_POLMOD).") 1 [1, x^2, x^4, -1/2*x^4 + 1/2*x, 1/2*x^3 - 21/2, 1/2*x^5 - 21/2*x^2] [1, 0, 0; 0, 1, 0; 0, 0, 1] 1 [1, 0] 5: [[1, 0; 0, 1], [1/2, 1/4]] [1/2, 1/2*x^2, 1/2*x^4, -1/4*x^4 + 1/4*x, 1/4*x^3 - 21/4, 1/4*x^5 - 21/4*x^2 ] error("incorrect type in rnfidealabstorel (t_POLMOD).") 1/2 [1/2, 1/2*x^2, 1/2*x^4, -1/4*x^4 + 1/4*x, 1/4*x^3 - 21/4, 1/4*x^5 - 21/4*x^2 ] [1/4, 0, 0; 0, 1/4, 0; 0, 0, 1/4] 1/64 [1/2, 0] 6: [[1, 0; 0, 1], [[21, 0, 0; 0, 1, 0; 0, 0, 1], [21/2, 0, 0; 0, 1/2, 0; 0, 0, 1/2]]] [21, x^2, x^4, -21/2*x^4 + 21/2*x, 1/2*x^3 - 21/2, 1/2*x^5 - 21/2*x^2] error("incorrect type in rnfidealabstorel (t_POLMOD).") [21, 0, 0; 0, 1, 0; 0, 0, 1] [21, x^2, x^4, -21/2*x^4 + 21/2*x, 1/2*x^3 - 21/2, 1/2*x^5 - 21/2*x^2] [21, 0, 0; 0, 21, 0; 0, 0, 1] 441 [21, Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21))] 7: error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("incorrect type in rnfidealabstorel (t_POLMOD).") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in nf_to_scalar_or_basis: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") 8: error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("incorrect type in rnfidealabstorel (t_POLMOD).") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in nf_to_scalar_or_basis: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") 9: error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("incorrect type in rnfidealabstorel (t_POLMOD).") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in nf_to_scalar_or_basis: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: x^6 - 21 != y^3 - 21") 10: [[1, -756; 0, 1], [[903/2, 84, 336; 0, 1/2, 0; 0, 0, 1/2], 1/4]] [903/2, 1/2*x^2 + 84, 1/2*x^4 + 336, -1/4*x^4 + 1/4*x - 189, 1/4*x^3 - 189*x ^2 - 21/4, 1/4*x^5 - 189*x^4 - 21/4*x^2] error("incorrect type in rnfidealabstorel (t_POLMOD).") [903/2, 84, 336; 0, 1/2, 0; 0, 0, 1/2] error("inconsistent moduli in nf_to_scalar_or_basis: x^2 - y != y^3 - 21") [903/4, 42, 168; 0, 1/4, 0; 0, 0, 1/4] 903/64 [903/2, Mod(1/2*x - 42, x^2 + Mod(-y, y^3 - 21))] 11: [[1, 0; 0, 1], [[21, 0, 0; 0, 1, 0; 0, 0, 1], [21/2, 0, 0; 0, 1/2, 0; 0, 0, 1/2]]] [21, x^2, x^4, -21/2*x^4 + 21/2*x, 1/2*x^3 - 21/2, 1/2*x^5 - 21/2*x^2] error("incorrect type in rnfidealabstorel (t_POL).") [21, 0, 0; 0, 1, 0; 0, 0, 1] [21, x^2, x^4, -21/2*x^4 + 21/2*x, 1/2*x^3 - 21/2, 1/2*x^5 - 21/2*x^2] [21, 0, 0; 0, 21, 0; 0, 0, 1] 441 [21, Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21))] 12: error("inconsistent variables in rnfbasistoalg, z != x.") error("inconsistent variables in rnfbasistoalg, z != x.") error("incorrect type in rnfidealabstorel (t_POL).") error("inconsistent variables in rnfbasistoalg, z != x.") error("inconsistent variables in nf_to_scalar_or_basis, z != y.") error("inconsistent variables in rnfbasistoalg, z != x.") error("inconsistent variables in rnfbasistoalg, z != x.") error("inconsistent variables in rnfbasistoalg, z != x.") 13: error("inconsistent moduli in rnfbasistoalg: y^2 + 1 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: y^2 + 1 != y^3 - 21") error("incorrect type in rnfidealabstorel (t_POLMOD).") error("inconsistent moduli in rnfbasistoalg: y^2 + 1 != y^3 - 21") error("inconsistent moduli in nf_to_scalar_or_basis: y^2 + 1 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: y^2 + 1 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: y^2 + 1 != y^3 - 21") error("inconsistent moduli in rnfbasistoalg: y^2 + 1 != y^3 - 21") 14: error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts). ") error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts). ") error("incorrect type in rnfidealabstorel (t_COL).") error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts). ") error("incorrect type in nf_to_scalar_or_basis (t_COL).") error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts). ") error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts). ") error("inconsistent operation 'RgV_RgC_mul' t_VEC (2 elts) , t_COL (1 elts). ") 15: [[1, -5371968; 0, 1], [[10743937, 8099895, 3524829; 0, 1, 0; 0, 0, 1], 1/2]] [10743937, x^2 + 8099895, x^4 + 3524829, -1/2*x^4 + 1/2*x - 2685984, 1/2*x^3 - 2685984*x^2 - 21/2, 1/2*x^5 - 2685984*x^4 - 21/2*x^2] error("incorrect type in rnfidealabstorel (t_COL).") [10743937, 8099895, 3524829; 0, 1, 0; 0, 0, 1] error("incorrect type in nf_to_scalar_or_basis (t_COL).") [10743937, 8099895, 3524829; 0, 1, 0; 0, 0, 1] 10743937 [10743937, Mod(x - 1847139, x^2 + Mod(-y, y^3 - 21))] 16: [[1, [0, 0, -18]~; 0, 1], [379, 1/2]] [379, 379*x^2, 379*x^4, -19/2*x^4 + 1/2*x, 1/2*x^3 - 399/2, 1/2*x^5 - 399/2* x^2] error("incorrect type in rnfidealabstorel (t_COL).") 379 error("incorrect type in nf_to_scalar_or_basis (t_COL).") [379, 0, 0; 0, 379, 0; 0, 0, 379] 54439939 [379, Mod(Mod(1/2*y, y^3 - 21)*x + 359/2, x^2 + Mod(-y, y^3 - 21))] 17: error("incorrect type in nf_to_scalar_or_alg (t_COMPLEX).") error("incorrect type in nf_to_scalar_or_alg (t_COMPLEX).") error("incorrect type in rnfidealabstorel (t_COL).") error("incorrect type in nf_to_scalar_or_alg (t_COMPLEX).") error("incorrect type in nf_to_scalar_or_basis (t_COL).") error("incorrect type in nf_to_scalar_or_alg (t_COMPLEX).") error("incorrect type in nf_to_scalar_or_alg (t_COMPLEX).") error("incorrect type in nf_to_scalar_or_alg (t_COMPLEX).") 18: error("incorrect type in rnfbasistoalg [not in Q[X]] (t_POL).") error("incorrect type in rnfbasistoalg [not in Q[X]] (t_POL).") error("incorrect type in rnfidealabstorel (t_POL).") error("incorrect type in rnfbasistoalg [not in Q[X]] (t_POL).") error("incorrect type in poltobasis (t_POL).") error("incorrect type in rnfbasistoalg [not in Q[X]] (t_POL).") error("incorrect type in rnfbasistoalg [not in Q[X]] (t_POL).") error("incorrect type in rnfbasistoalg [not in Q[X]] (t_POL).") 19: [[1, 0; 0, 1], [[21, 0, 0; 0, 1, 0; 0, 0, 1], [21/2, 0, 0; 0, 1/2, 0; 0, 0, 1/2]]] [21, x^2, x^4, -21/2*x^4 + 21/2*x, 1/2*x^3 - 21/2, 1/2*x^5 - 21/2*x^2] error("incorrect type in rnfidealabstorel (t_POL).") [21, 0, 0; 0, 1, 0; 0, 0, 1] error("inconsistent variables in nf_to_scalar_or_basis, x != y.") [21, 0, 0; 0, 21, 0; 0, 0, 1] 441 [21, Mod(Mod(y, y^3 - 21), x^2 + Mod(-y, y^3 - 21))] 20: [[;], []] [] [[;], []] [;] [] [;] 0 [0, 0] 21: [[;], []] [] [[;], []] [;] error("incorrect type in idealtyp (t_VEC).") [;] 0 [0, 0] 22: [[;], []] [] error("incorrect type in rnfidealabstorel (t_INT).") [;] [] [;] 0 [0, 0] 23: [[;], []] [] error("inconsistent dimensions in rnfidealabstorel.") [;] [] [;] 0 [0, 0] 24: error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") [2, x^2 + 1, x^4 + 1, -x^4 + x, -1/2*x^4 + 1/2*x^3 + 1/2*x - 21/2, 1/2*x^5 - 1/2*x^4 - 21/2*x^2 + 1/2*x] error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") 25: error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") error("incorrect type in idealhnf [wrong dimension] (t_MAT).") [18416, x^2 + 6979, x^4 + 3879, -9208*x^4 + 9208*x, -6979/2*x^4 + 1/2*x^3 + 6979/2*x - 21/2, 1/2*x^5 - 3879/2*x^4 - 21/2*x^2 + 3879/2*x] error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") error("inconsistent dimensions in rnfidealabstorel.") 26: [[1, -66328; 0, 1], [[280970, 12259, 35869; 0, 1, 0; 0, 0, 1], [1, 1/2, 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [280970, x^2 + 12259, x^4 + 35869, -x^4 + x - 66328, -1/2*x^4 + 1/2*x^3 - 33 164*x^2 + 1/2*x - 66349/2, 1/2*x^5 - 66329/2*x^4 - 21/2*x^2 + 1/2*x - 33164] [[1, -66328; 0, 1], [[280970, 12259, 35869; 0, 1, 0; 0, 0, 1], [1, 1/2, 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [280970, 12259, 35869; 0, 1, 0; 0, 0, 1] error("inconsistent dimensions in idealtwoelt.") [561940, 12259, 316839; 0, 1, 0; 0, 0, 1] 561940 [280970, Mod(x + Mod(-140485*y + 110026, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) ] 27: [[1, -66328; 0, 1], [[280970, 12259, 35869; 0, 1, 0; 0, 0, 1], [1, 1/2, 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [280970, x^2 + 12259, x^4 + 35869, -x^4 + x - 66328, -1/2*x^4 + 1/2*x^3 - 33 164*x^2 + 1/2*x - 66349/2, 1/2*x^5 - 66329/2*x^4 - 21/2*x^2 + 1/2*x - 33164] [[1, -66328; 0, 1], [[280970, 12259, 35869; 0, 1, 0; 0, 0, 1], [1, 1/2, 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [280970, 12259, 35869; 0, 1, 0; 0, 0, 1] error("incorrect type in idealtyp (t_VEC).") [561940, 12259, 316839; 0, 1, 0; 0, 0, 1] 561940 [280970, Mod(x + Mod(-140485*y + 110026, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) ] 28: [[1, -66328; 0, 1], [[280970, 12259, 35869; 0, 1, 0; 0, 0, 1], [1, 1/2, 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [280970, x^2 + 12259, x^4 + 35869, -x^4 + x - 66328, -1/2*x^4 + 1/2*x^3 - 33 164*x^2 + 1/2*x - 66349/2, 1/2*x^5 - 66329/2*x^4 - 21/2*x^2 + 1/2*x - 33164] error("inconsistent dimensions in rnfidealabstorel.") [280970, 12259, 35869; 0, 1, 0; 0, 0, 1] error("inconsistent dimensions in idealtwoelt.") [561940, 12259, 316839; 0, 1, 0; 0, 0, 1] 561940 [280970, Mod(x + Mod(-140485*y + 110026, y^3 - 21), x^2 + Mod(-y, y^3 - 21)) ] [[;], []] [[;], []] [[1, 0; 0, 1], [[21, 0, 0; 0, 21, 0; 0, 0, 1], [21/2, 0, 0; 0, 1/2, 0; 0, 0, 1/2]]] [[1, 0; 0, 1], [[21, 0, 0; 0, 21, 0; 0, 0, 1], [21/2, 0, 0; 0, 1/2, 0; 0, 0, 1/2]]] [[1, -347298; 0, 1], [[5900370, 2821959, 5374299; 0, 1, 0; 0, 0, 1], [1, 1/2 , 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [[1, -347298; 0, 1], [[5900370, 2821959, 5374299; 0, 1, 0; 0, 0, 1], [1, 1/2 , 1/2; 0, 1/2, 0; 0, 0, 1/2]]] [1 0 0] [0 1 0] [0 0 1] [280970 12259/2 316839/2] [ 0 1/2 0] [ 0 0 1/2] [1 -1 [-1/2, -1/2]~] [0 1 [1/2, 1/2]~] 1 0 0 1 1 1 [0, [[1, 0, -1; 0, 1, [0, -1]~; 0, 0, 1], [1, 1, 1/3]], 5] [0, [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, [1, 1/2; 0, 1/2]]], 2] [1, [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, 1]], 8] 0 1 0 0 1 *** at top-level: rnfdedekind(nf,P,pr2,1) *** ^----------------------- *** rnfdedekind: sorry, Dedekind in the difficult case is not yet implemented. *** at top-level: rnfdedekind(nf,P) *** ^----------------- *** rnfdedekind: sorry, Dedekind in the difficult case is not yet implemented. *** at top-level: rnfdedekind(nf,P,[pr2,pr3]) *** ^--------------------------- *** rnfdedekind: sorry, Dedekind in the difficult case is not yet implemented. *** at top-level: rnfislocalcyclo(rnfinit(K,x^6-y+1)) *** ^----------------------------------- *** rnfislocalcyclo: sorry, rnfislocalcyclo for non-l-extensions is not yet implemented. *** at top-level: rnfidealtwoelt(L,[[1;0],[1/104]]) *** ^--------------------------------- *** rnfidealtwoelt: incorrect type in idealtyp [non-square t_MAT] (t_MAT). Total time spent: 782 pari-2.11.2/src/test/32/cmp0000644000175000017500000000114313201017466013651 0ustar billbill(f,g)->[cmp(f,f),cmp(f,g),cmp(g,f)] [0, -1, 1] [0, -1, 1] [0, -1, 1] [0, -1, 1] [0, -1, 1] [0, -1, 1] [0, -1, 1] [0, -1, 1] *** at top-level: Mod(1,3)>0 *** ^-- *** _>_: forbidden comparison t_INTMOD , t_INT. -1 [1, 1, 0] [0, 1, 1] 1 0 *** at top-level: 1<='x *** ^---- *** _<=_: forbidden comparison t_INT , t_POL. *** at top-level: 1.<='x *** ^---- *** _<=_: forbidden comparison t_REAL , t_POL. *** at top-level: 1/2<='x *** ^---- *** _<=_: forbidden comparison t_FRAC , t_POL. Total time spent: 4 pari-2.11.2/src/test/32/character0000644000175000017500000000263613326135265015044 0ustar billbill [15 12] [ 0 1] [14, 4] 15 [20 0] [ 0 1] [20 0] [ 0 1] [20 0] [ 0 1] [0, 0] [0, 0]~ 1 [18, 0] [0, 18]~ 69 [3, 0] [0, 3]~ 33 [19, 0] [0, 19]~ [0, 19]~ 20 20 20 67 [13, 1] [1, 13]~ [1, 13]~ [1, 13]~ [1, 13]~ 23 [9, 1] [1, 9]~ [1, 9]~ [1, 9]~ [1, 9]~ * 100 1: [100, 1] 49: [20, 5] 51: [-100, -4] 99: [-20, -20] * 8 1: [4, 1] 3: [-8, -8] 5: [8, 8] 7: [-4, -4] * 5 1: [25, 1] 4: [5, 5] * 1 1: [1, 1] [[]~, []~, 0, 1] [[2]~, [2]~, 4, 2] [[0]~, [0]~, 1, 1] [[3]~, [3]~, 3, 4] [13, [0, 19]~, 13, 20] [[0, 19]~, [1, 0]~, 51, 20] [[10, 1], [1, 10]~, 99, 2] *** at top-level: znchar(0) *** ^--------- *** znchar: incorrect type in znchar (t_INT). *** at top-level: znchar(2) *** ^--------- *** znchar: incorrect type in znchar (t_INT). *** at top-level: znchar(3) *** ^--------- *** znchar: incorrect type in znchar (t_INT). *** at top-level: znchar([]~) *** ^----------- *** znchar: incorrect type in znchar (t_COL). *** at top-level: znchar([1,2,3]) *** ^--------------- *** znchar: incorrect type in znchar (t_VEC). *** at top-level: znchar([1,2]) *** ^------------- *** znchar: incorrect type in znchar (t_VEC). *** at top-level: znchar([znstar(100,1),[1,2,3]]) *** ^------------------------------- *** znchar: incorrect type in znchar (t_VEC). Total time spent: 0 pari-2.11.2/src/test/32/ploth0000644000175000017500000002712313457566440014244 0ustar billbill echo = 1 ? \p19 realprecision = 19 significant digits ? default(parisize,"20M"); *** Warning: new stack size = 20000000 (19.073 Mbytes). ? t=plothsizes(); ? plotinit(0,t[1]-11,t[2]-11) ? plotscale(0,0,1000,0,1000); ? plotbox(0,500,500) ? plotdraw(0) ? write("pari0.svg",plotexport("svg",0)) ? plotcolor(0,2); ? plotmove(0,0,900);plotlines(0,900,0) ? plotlines(0,vector(5,k,50*k),vector(5,k,10*k*k)) ? plotmove(0,243,583);plotcursor(0) [243, 583] ? plot(x=-1,1,floor(x)) 0 --------------------------------"""""""""""""""""""""""""""""""" | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | -1 ________________________________...............................| -1 1 ? plot(x=-1,1,-floor(x)) 1 """"""""""""""""""""""""""""""""'''''''''''''''''''''''''''''''| | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | | : | 0 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,________________________________ -1 1 ? plot(x=0,1,-0.29) 0.71 |''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''| | | | | | | | | | | | | | | | | | | | | | | | | | | | | ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, | | | | | | | | | | -0.29 ________________________________________________________________ 0 1 ? plot(x=-5,5,sin(x)) 0.9995545 x""x_''''''''''''''''''''''''''''''''''_x""x'''''''''''''''''''| | x _ "_ | | x _ _ | | x _ | | _ " | | " x | | x _ | | " | | " x _ | | _ | | " x | ````````````x``````````````````_```````````````````````````````` | " | | " x _ | | _ | | " x | | x _ | | _ " | | " x | | " " x | | "_ " x | -0.999555 |...................x__x".................................."x__x -5 5 ? ploth(x=-5,5,sin(x)) [-5.000000000000000000, 5.000000000000000000, -0.9999964107564721649, 0.9999 964107564721649] ? ploth(t=0,2*Pi,[sin(5*t),sin(7*t)]) [0.E-307, 6.283185307179586232, -0.9999987638285974256, 0.999998763828597425 6] ? ploth(t=0,2*Pi,[sin(5*t),sin(7*t)],"Parametric",100) [-0.9998741276738750683, 0.9998741276738750683, -0.9998741276738750683, 0.99 98741276738750683] ? ploth(t=0,2*Pi,[sin(5*t),sin(7*t)],"Parametric|Recursive",100) [-1.000000000000000000, 1.000000000000000000, -1.000000000000000000, 1.00000 0000000000000] ? plothraw(vector(501,k,k-1),vector(501,k,(k-1)*(k-1)/500)); ? plothraw(vector(501,k,k-1),vector(501,k,(k-1)*(k-1)/500),1); ? plotpoints(0,225,334) ? plotpoints(0,vector(10,k,10*k),vector(10,k,5*k*k)) ? write("pari1.svg",plothexport("svg",x=-5,5,sin(x))); ? write("pari2.svg",plothrawexport("svg",vector(501,k,k-1),vector(501,k,(k-1)*(k-1)/500),1)); ? plotmove(0,50,50);plotrbox(0,50,50) ? plotrline(0,150,100) ? plotcolor(0,4); ? plotcursor(0) [200, 150] ? plotrmove(0,5,5);plotcursor(0) [205, 155] ? plotrpoint(0,20,20) ? plotmove(0,100,100);plotstring(0,Pi) ? plotmove(0,200,200);plotstring(0,"(0,0)") ? plotdraw([0,10,10]) ? write("pari3.svg",plotexport("svg",[0,10,10])) ? ploth(x=0,1,x^3,"Splines") [0.E-307, 1.000000000000000000, 0.E-307, 1.000000000000000000] ? ploth(x=0,1,[x^2,x^3],"Parametric|Splines") [0.E-307, 0.9999999999999998890, 0.E-307, 0.9999999999999998890] ? plotinit(1); ? plotcopy(0,1,300,0); ? plotclip(1); ? plotdraw([1,10,10]); ? plotkill(1); ? plotinit(1); ? plotcopy(0,1,1/2,0,1); ? plotclip(1); ? plotdraw([1,10,10]); ? plotkill(1); ? plotinit(1); ? plotcopy(0,1,1/2,1/3,3); ? plotclip(1); ? plotdraw([1,10,10]); ? plotkill(1); ? plotinit(1); ? plotcopy(0,1,1/3,1/3,5); ? plotclip(1); ? plotdraw([1,10,10]); ? plotkill(1); ? plotinit(1); ? plotcopy(0,1,1/3,1/3,7); ? plotclip(1); ? plotdraw([1,10,10]); ? plotinit(-1) *** at top-level: plotinit(-1) *** ^------------ *** plotinit: domain error in graphic function: rectwindow < 0 ? plotinit(100) *** at top-level: plotinit(100) *** ^------------- *** plotinit: domain error in plotinit: rectwindow > 15 ? plotmove(-1,0,0) *** at top-level: plotmove(-1,0,0) *** ^---------------- *** plotmove: domain error in graphic function: rectwindow < 0 ? plotmove(100,0,0) *** at top-level: plotmove(100,0,0) *** ^----------------- *** plotmove: domain error in graphic function: rectwindow > 17 ? plotcopy(0,1,2,1,1) *** at top-level: plotcopy(0,1,2,1,1) *** ^------------------- *** plotcopy: domain error in plotcopy: dx > 1 ? plotcopy(0,1,-1,1,1) *** at top-level: plotcopy(0,1,-1,1,1) *** ^-------------------- *** plotcopy: domain error in plotcopy: dx < 0 ? plotcopy(0,1,1,2,1) *** at top-level: plotcopy(0,1,1,2,1) *** ^------------------- *** plotcopy: domain error in plotcopy: dy > 1 ? plotcopy(0,1,1,-1,1) *** at top-level: plotcopy(0,1,1,-1,1) *** ^-------------------- *** plotcopy: domain error in plotcopy: dy < 0 ? ploth(x=0,2*Pi,if(x<1,[cos(x),sin(x)],1),"Parametric") *** at top-level: ploth(x=0,2*Pi,if(x<1,[cos(x),sin(x)],1),"Para *** ^---------------------------- *** inconsistent dimensions in plotrecth. ? ploth(t=0,2*Pi,[sin(5*t),sin(7*t)],"Recursive",100) *** at top-level: ploth(t=0,2*Pi,[sin(5*t),sin(7*t)],"Recursive" *** ^------------------------------- *** incorrect type in ploth [multi-curves + recursive] (t_VEC). ? ploth(x=0,2*Pi,1,"Parametric") *** at top-level: ploth(x=0,2*Pi,1,"Parametric") *** ^--------------- *** incorrect type in ploth [not a t_VEC in parametric plot] (t_INT). ? ploth(x=0,1,x,,1) *** at top-level: ploth(x=0,1,x,,1) *** ^----- *** domain error in ploth: #points < 2 ? default(graphcolormap,["white","black","gray","violetred","red","green","blue","gainsboro","purple"]) ? default(graphcolors,[7,4,9,8,5,6]) ? ploth(X=-1,9,vector(6,k,sin(X+k))) *** at top-level: ploth(X=-1,9,vector(6,k,sin(X+k))) *** ^-------------- *** non-existent component in graphcolormap: index > 9 ? print("Total time spent: ",gettime); Total time spent: 100 pari-2.11.2/src/test/32/exact00000644000175000017500000000124711636712103014263 0ustar billbill *** at top-level: Mod(0,2)*x*1. *** ^--- *** _*_: forbidden multiplication t_REAL * t_INTMOD. Mod(0, 2) Mod(0, 2) Mod(0, 2)*x^15 + O(x^16) Mod(2, 4) + Mod(0, 4)*I Mod(0, 4) + Mod(0, 4)*I Mod(1, 2) + Mod(0, 2)*I Mod(0, 2) Mod(0, 2) Mod(0, 2) 1 Mod(0, 5) Mod(0, 5) 0 0 O(x^4) 0 0 O(x^4) Mod(0, 2) Mod(0, 2) Mod(0, 2)*x^3 + O(x^4) Mod(0, 2) Mod(0, 2) Mod(0, 2)*x^3 + O(x^4) x^3 1 1 + O(x^4) 1 x^3 x^3 + O(x^4) x^3 + 0.E-38*x 0.E-38*x^2 + 1 1 + 0.E-38*x^2 + O(x^4) 0.E-38*x^2 + 1 x^3 + 0 .E-38*x 0.E-38*x + x^3 + O(x^4) x^3 + 0.E-38 0.E-38*x^3 + 1 1 + 0.E-38*x^3 + O(x^4) 0.E-38*x^3 + 1 x^3 + 0.E -38 0.E-38 + x^3 + O(x^4) Total time spent: 8 pari-2.11.2/src/test/32/bnrisgalois0000644000175000017500000000144113326135265015415 0ustar billbill[[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 3], [1, 0, 0, 0; 0, 3, 1, 2; 0, 0, 1, 0; 0, 0, 0, 1], [3, 0, 2, 2; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [ 3, 1, 2, 1; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1]] [[4451, 7700, 7000, 5600; 8, 11, 8, 8; 5, 1, 3, 0; 0, 0, 0, 2], [3149, 3500, 7000, 5600; 0, 5, 0, 8; 3, 1, 1, 2; 0, 0, 0, 1]] [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 3], [1, 0, 0, 0; 0, 3, 1, 2; 0, 0, 1, 0; 0, 0, 0, 1], [3, 0, 2, 2; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [ 3, 1, 2, 1; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1]] [[1, 17, 18, 32, 30, 31, 8, 7, 9, 14, 15, 28, 29, 10, 11, 16, 2, 3, 19, 21, 20, 22, 23, 24, 27, 26, 25, 12, 13, 5, 6, 4], [1, 11, 10, 6, 5, 4, 7, 8, 9, 3, 2, 29, 28, 18, 17, 16, 15, 14, 26, 25, 27, 24, 23, 22, 20, 19, 21, 13, 12 , 30, 32, 31]] Total time spent: 532 pari-2.11.2/src/test/32/modfun0000644000175000017500000000634213447371554014405 0ustar billbill1 + 2 + 2^3 + 2^4 + 2^7 + 2^12 + 2^13 + 2^14 + 2^16 + 2^17 + 2^18 + 2^19 + O (2^20) 1 - x - 2*x^2 - 3*x^3 - 4*x^4 + O(x^5) 1 - x - 3*x^2 - 4*x^3 - 4*x^4 + O(x^5) 0.99812906992595851327996232224527387813 2^-1 + 2^5 + 2^7 + 2^8 + 2^10 + 2^12 + 2^16 + O(2^18) x^-1 + 743 + 196884*x + 21690644*x^2 + O(x^3) x^-1 + 744 + 196884*x + 21493760*x^2 + 864299970*x^3 + 20245856256*x^4 + 333 202640600*x^5 + 4252023300096*x^6 + 44656994071935*x^7 + 401490886656000*x^8 + 3176440229784420*x^9 + 22567393309593600*x^10 + 146211911499519294*x^11 + 874313719685775360*x^12 + 4872010111798142520*x^13 + 25497827389410525184*x ^14 + 126142916465781843075*x^15 + 593121772421445058560*x^16 + 266284241315 0775245160*x^17 + 11459912788444786513920*x^18 + 47438786801234168813250*x^1 9 + 189449976248893390028800*x^20 + 731811377318137519245696*x^21 + 27406307 12513624654929920*x^22 + 9971041659937182693533820*x^23 + 353074531865614270 99877376*x^24 + 121883284330422510433351500*x^25 + 4107899601903079091576381 44*x^26 + 1353563541518646878675077500*x^27 + 4365689224858876634610401280*x ^28 + 13798375834642999925542288376*x^29 + 42780782244213262567058227200*x^3 0 + 130233693825770295128044873221*x^31 + 389608006170995911894300098560*x^3 2 + 1146329398900810637779611090240*x^33 + 3319627709139267167263679606784*x ^34 + 9468166135702260431646263438600*x^35 + 2661436582575379626887215187558 4*x^36 + 73773169969725069760801792854360*x^37 + 201768789947228738648580043 776000*x^38 + 544763881751616630123165410477688*x^39 + 145268925443936216979 4355429376000*x^40 + 3827767751739363485065598331130120*x^41 + 9970416600217 443268739409968824320*x^42 + 25683334706395406994774011866319670*x^43 + 6545 2367731499268312170283695144960*x^44 + 165078821568186174782496283155142200* x^45 + 412189630805216773489544457234333696*x^46 + 1019253515891576791938652 011091437835*x^47 + 2496774105950716692603315123199672320*x^48 + 60605744154 13720999542378222812650932*x^49 + 14581598453215019997540391326153984000*x^5 0 + 34782974253512490652111111930326416268*x^51 + 82282309236048637946346570 669250805760*x^52 + 193075525467822574167329529658775261720*x^53 + 449497224 123337477155078537760754122752*x^54 + 10384830105879497940689251536859324358 25*x^55 + 2381407585309922413499951812839633584128*x^56 + 542144988987656472 3000378957979772088000*x^57 + 12255365475040820661535516233050165760000*x^58 + 27513411092859486460692553086168714659374*x^59 + 613542895053036136170693 38272284858777600*x^60 + 135925092428365503809701809166616289474168*x^61 + 2 99210983800076883665074958854523331870720*x^62 + 654553043491650303064385476 041569995365270*x^63 + 1423197635972716062310802114654243653681152*x^64 + 30 76095473477196763039615540128479523917200*x^65 + 661009177378287162744590921 5080641586954240*x^66 + 14123583372861184908287080245891873213544410*x^67 + O(x^68) 0.E-38 - 0.50432357748832834893222560519660217759*I 1.0905077326652576592070106557607079790 1.0811782878393746833655992417658285836 - 0.14233982193131805512395869109512 286588*I *** at top-level: eta(0) *** ^------ *** eta: domain error in modular function: Im(argument) <= 0 *** at top-level: eta(1/2) *** ^-------- *** eta: domain error in modular function: Im(argument) <= 0 Total time spent: 0 pari-2.11.2/src/test/32/algsplit0000644000175000017500000000311413326135265014717 0ustar billbillM_2(F_4) M_2(F_9) M_2(F_31^2) M_2(F_p^2) M_d(F_31^n) d=1 n=1 d=1 n=2 d=1 n=3 d=1 n=4 d=1 n=5 d=1 n=6 d=1 n=7 d=1 n=8 d=1 n=9 d=1 n=10 d=2 n=1 d=2 n=2 d=2 n=3 d=2 n=4 d=3 n=1 d=3 n=2 d=4 n=1 examples from documentation [2*a 0] [ 0 2] [1 2*a] [2 a + 2] 1 [0 0] [a 0] bad input *** at top-level: algsplit("toto") *** ^---------------- *** algsplit: incorrect type in checkalg [please apply alginit()] (t_STR). *** at top-level: algsplit(alginit(nfinit('y),[-1,-1])) *** ^------------------------------------- *** algsplit: sorry, splitting a characteristic 0 algebra over its center is not yet implemented. *** at top-level: algsplit(algtableinit([matid(3),[0,0,0;1,1,0;0 *** ^---------------------------------------------- *** algsplit: the algebra must be simple (alg_finite_csa_split 1). *** at top-level: algsplit(algtableinit([matid(2),[0,0;1,1]],2)) *** ^---------------------------------------------- *** algsplit: the algebra must be simple (alg_finite_csa_split 2). *** at top-level: algsplit(matblock([2,1,1,1],1,q)) *** ^--------------------------------- *** algsplit: the algebra must be simple (try_split 1). *** at top-level: algsplit(matblock([1,2,3],1,q)) *** ^------------------------------- *** algsplit: the algebra must be simple (try_split 2). *** at top-level: algsplit(algtableinit(mt,2)) *** ^---------------------------- *** algsplit: the algebra must be simple (alg_finite_csa_split 3). Total time spent: 604 pari-2.11.2/src/test/32/div0000644000175000017500000006171313326135265013673 0ustar billbill* [1, 1] 1 1 0 1 [1, 0]~ * [1, 2] 3/4 0 3 1 [0, 3]~ * [1, 3] 0.96774193548387096774193548387096774194 0 3 1 [0, 3]~ * [1, 4] 6 6 0 6 [6, 0]~ * [1, 5] 3/(x^2 + 1) 0 3 0 [0, 3]~ * [1, 6] Mod(-3*x, x^2 + 1) error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT % t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") * [1, 7] 0 error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT % t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") * [1, 8] -3 + 3*w error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT % t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") * [1, 9] 2*3 + 3^2 + 3^3 + O(3^4) error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT % t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") * [1, 10] Mod(0, 3) error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT % t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") * [1, 11] 3/18446744073709551617 0 3 0 [0, 3]~ * [2, 1] 4/3 1 1 1 [1, 1]~ * [2, 2] 1 1 0 1 [1, 0]~ * [2, 3] 1.2903225806451612903225806451612903226 1 0.90000000000000000000000000000000000000 1 [1, 0.90000000000000000000000000000000000000]~ * [2, 4] 8 8 0 8 [8, 0]~ * [2, 5] 4/(x^2 + 1) 0 4 0 [0, 4]~ * [2, 6] Mod(-4*x, x^2 + 1) error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT % t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") * [2, 7] 2*t^4 + 2*t^3 + t^2 error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT % t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") * [2, 8] -4 + 4*w error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT % t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") * [2, 9] 2 + O(3^3) error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT % t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") * [2, 10] Mod(2, 3) error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT % t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") * [2, 11] 4/18446744073709551617 0 4 0 [0, 4]~ * [3, 1] 1.0333333333333333333333333333333333333 1 0.099999999999999999999999999999999999995 1 [1, 0.099999999999999999999999999999999999995]~ * [3, 2] 0.77500000000000000000000000000000000000 0 3.1000000000000000000000000000000000000 1 [0, 3.1000000000000000000000000000000000000]~ * [3, 3] 1.0000000000000000000000000000000000000 1 0.E-37 1 [1, 0.E-37]~ * [3, 4] 6.2000000000000000000000000000000000000 6 0.099999999999999999999999999999999999995 6 [6, 0.099999999999999999999999999999999999995]~ * [3, 5] 3.1000000000000000000000000000000000000/(x^2 + 1) 0 3.1000000000000000000000000000000000000 0 [0, 3.1000000000000000000000000000000000000]~ * [3, 6] Mod(-3.1000000000000000000000000000000000000*x, x^2 + 1) error("forbidden division t_REAL \\ t_POLMOD.") error("forbidden division t_REAL % t_POLMOD.") error("forbidden division t_REAL \\ t_POLMOD.") error("forbidden division t_REAL \\ t_POLMOD.") * [3, 7] error("forbidden division t_REAL / t_FFELT.") error("forbidden division t_REAL \\ t_FFELT.") error("forbidden division t_REAL % t_FFELT.") error("forbidden division t_REAL \\ t_FFELT.") error("forbidden division t_REAL \\ t_FFELT.") * [3, 8] 1.9159053651246740294342191865334781649 error("forbidden division t_REAL \\ t_QUAD.") error("forbidden division t_REAL % t_QUAD.") error("forbidden division t_REAL \\ t_QUAD.") error("forbidden division t_REAL \\ t_QUAD.") * [3, 9] error("forbidden division t_REAL / t_PADIC.") error("forbidden division t_REAL \\ t_PADIC.") error("forbidden division t_REAL % t_PADIC.") error("forbidden division t_REAL \\ t_PADIC.") error("forbidden division t_REAL \\ t_PADIC.") * [3, 10] error("forbidden division t_REAL / t_INTMOD.") error("forbidden division t_REAL \\ t_INTMOD.") error("forbidden division t_REAL % t_INTMOD.") error("forbidden division t_REAL \\ t_INTMOD.") error("forbidden division t_REAL \\ t_INTMOD.") * [3, 11] 1.6805133673525318726204510291596823708 E-19 0 3.1000000000000000000000000000000000000 0 [0, 3.1000000000000000000000000000000000000]~ * [4, 1] 1/6 0 2 0 [0, 1/2]~ * [4, 2] 1/8 0 error("impossible inverse in Fl_inv: Mod(2, 4).") 0 [0, 1/2]~ * [4, 3] 0.16129032258064516129032258064516129032 0 1/2 0 [0, 1/2]~ * [4, 4] 1 1 0 1 [1, 0]~ * [4, 5] 1/(2*x^2 + 2) 0 1/2 0 [0, 1/2]~ * [4, 6] Mod(-1/2*x, x^2 + 1) error("forbidden division t_FRAC \\ t_POLMOD.") error("forbidden division t_FRAC % t_POLMOD.") error("forbidden division t_FRAC \\ t_POLMOD.") error("forbidden division t_FRAC \\ t_POLMOD.") * [4, 7] t^4 + t^3 + 2*t^2 error("forbidden division t_FRAC \\ t_FFELT.") error("forbidden division t_FRAC % t_FFELT.") error("forbidden division t_FRAC \\ t_FFELT.") error("forbidden division t_FRAC \\ t_FFELT.") * [4, 8] -1/2 + 1/2*w error("forbidden division t_FRAC \\ t_QUAD.") error("forbidden division t_FRAC % t_QUAD.") error("forbidden division t_FRAC \\ t_QUAD.") error("forbidden division t_FRAC \\ t_QUAD.") * [4, 9] 1 + 2*3 + O(3^3) error("forbidden division t_FRAC \\ t_PADIC.") error("forbidden division t_FRAC % t_PADIC.") error("forbidden division t_FRAC \\ t_PADIC.") error("forbidden division t_FRAC \\ t_PADIC.") * [4, 10] Mod(1, 3) error("forbidden division t_FRAC \\ t_INTMOD.") error("forbidden division t_FRAC % t_INTMOD.") error("forbidden division t_FRAC \\ t_INTMOD.") error("forbidden division t_FRAC \\ t_INTMOD.") * [4, 11] 1/36893488147419103234 0 9223372036854775809 0 [0, 1/2]~ * [5, 1] 1/3*x^2 + 1/3 1/3*x^2 + 1/3 0 1/3*x^2 + 1/3 [1/3*x^2 + 1/3, 0]~ * [5, 2] 1/4*x^2 + 1/4 1/4*x^2 + 1/4 0 1/4*x^2 + 1/4 [1/4*x^2 + 1/4, 0]~ * [5, 3] 0.32258064516129032258064516129032258065*x^2 + 0.322580645161290322580645161 29032258065 0.32258064516129032258064516129032258065*x^2 + 0.322580645161290322580645161 29032258065 0 0.32258064516129032258064516129032258065*x^2 + 0.322580645161290322580645161 29032258065 [0.32258064516129032258064516129032258065*x^2 + 0.32258064516129032258064516 129032258065, 0]~ * [5, 4] 2*x^2 + 2 2*x^2 + 2 0 2*x^2 + 2 [2*x^2 + 2, 0]~ * [5, 5] 1 1 0 1 [1, 0]~ * [5, 6] Mod(0, x^2 + 1) error("forbidden euclidean division t_POL , t_POLMOD.") error("forbidden euclidean division t_POL , t_POLMOD.") error("forbidden euclidean division t_POL , t_POLMOD.") error("forbidden euclidean division t_POL , t_POLMOD.") * [5, 7] (2*t^4 + 2*t^3 + t^2)*x^2 + (2*t^4 + 2*t^3 + t^2) (2*t^4 + 2*t^3 + t^2)*x^2 + (2*t^4 + 2*t^3 + t^2) 0 (2*t^4 + 2*t^3 + t^2)*x^2 + (2*t^4 + 2*t^3 + t^2) [(2*t^4 + 2*t^3 + t^2)*x^2 + (2*t^4 + 2*t^3 + t^2), 0]~ * [5, 8] (-1 + w)*x^2 + (-1 + w) (-1 + w)*x^2 + (-1 + w) 0 (-1 + w)*x^2 + (-1 + w) [(-1 + w)*x^2 + (-1 + w), 0]~ * [5, 9] (2 + 3 + 3^2 + O(3^3))*x^2 + (2 + 3 + 3^2 + O(3^3)) (2 + 3 + 3^2 + O(3^3))*x^2 + (2 + 3 + 3^2 + O(3^3)) 0 (2 + 3 + 3^2 + O(3^3))*x^2 + (2 + 3 + 3^2 + O(3^3)) [(2 + 3 + 3^2 + O(3^3))*x^2 + (2 + 3 + 3^2 + O(3^3)), 0]~ * [5, 10] Mod(2, 3)*x^2 + Mod(2, 3) Mod(2, 3)*x^2 + Mod(2, 3) Mod(0, 3) Mod(2, 3)*x^2 + Mod(2, 3) [Mod(2, 3)*x^2 + Mod(2, 3), Mod(0, 3)]~ * [5, 11] 1/18446744073709551617*x^2 + 1/18446744073709551617 1/18446744073709551617*x^2 + 1/18446744073709551617 0 1/18446744073709551617*x^2 + 1/18446744073709551617 [1/18446744073709551617*x^2 + 1/18446744073709551617, 0]~ * [6, 1] Mod(1/3*x, x^2 + 1) error("forbidden division t_POLMOD \\ t_INT.") Mod(0, x^2 + 1) error("forbidden division t_POLMOD \\ t_INT.") error("forbidden division t_POLMOD \\ t_INT.") * [6, 2] Mod(1/4*x, x^2 + 1) error("forbidden division t_POLMOD \\ t_INT.") Mod(0, x^2 + 1) error("forbidden division t_POLMOD \\ t_INT.") error("forbidden division t_POLMOD \\ t_INT.") * [6, 3] Mod(0.32258064516129032258064516129032258065*x, x^2 + 1) error("incorrect type in gfloor (t_POLMOD).") error("forbidden division t_POLMOD % t_REAL.") error("incorrect type in gfloor (t_POLMOD).") error("incorrect type in gfloor (t_POLMOD).") * [6, 4] Mod(2*x, x^2 + 1) error("incorrect type in gfloor (t_POLMOD).") error("forbidden division t_POLMOD % t_FRAC.") error("incorrect type in gfloor (t_POLMOD).") error("incorrect type in gfloor (t_POLMOD).") * [6, 5] error("impossible inverse in Flx_divrem: Vecsmall([0]).") error("forbidden euclidean division t_POLMOD , t_POL.") Mod(x, x^2 + 1) error("forbidden euclidean division t_POLMOD , t_POL.") error("forbidden euclidean division t_POLMOD , t_POL.") * [6, 6] Mod(1, x^2 + 1) error("forbidden division t_POLMOD \\ t_POLMOD.") error("forbidden division t_POLMOD % t_POLMOD.") error("forbidden division t_POLMOD \\ t_POLMOD.") error("forbidden division t_POLMOD \\ t_POLMOD.") * [6, 7] Mod((2*t^4 + 2*t^3 + t^2)*x, x^2 + 1) error("forbidden division t_POLMOD \\ t_FFELT.") error("forbidden division t_POLMOD % t_FFELT.") error("forbidden division t_POLMOD \\ t_FFELT.") error("forbidden division t_POLMOD \\ t_FFELT.") * [6, 8] Mod((-1 + w)*x, x^2 + 1) error("forbidden division t_POLMOD \\ t_QUAD.") error("forbidden division t_POLMOD % t_QUAD.") error("forbidden division t_POLMOD \\ t_QUAD.") error("forbidden division t_POLMOD \\ t_QUAD.") * [6, 9] Mod((2 + 3 + 3^2 + O(3^3))*x, x^2 + 1) error("forbidden division t_POLMOD \\ t_PADIC.") error("forbidden division t_POLMOD % t_PADIC.") error("forbidden division t_POLMOD \\ t_PADIC.") error("forbidden division t_POLMOD \\ t_PADIC.") * [6, 10] Mod(Mod(2, 3)*x, x^2 + 1) error("forbidden division t_POLMOD \\ t_INTMOD.") error("forbidden division t_POLMOD % t_INTMOD.") error("forbidden division t_POLMOD \\ t_INTMOD.") error("forbidden division t_POLMOD \\ t_INTMOD.") * [6, 11] Mod(1/18446744073709551617*x, x^2 + 1) error("forbidden division t_POLMOD \\ t_INT.") error("forbidden division t_POLMOD % t_INT.") error("forbidden division t_POLMOD \\ t_INT.") error("forbidden division t_POLMOD \\ t_INT.") * [7, 1] error("impossible inverse in Fl_inv: Mod(0, 3).") error("forbidden division t_FFELT \\ t_INT.") error("forbidden division t_FFELT % t_INT.") error("forbidden division t_FFELT \\ t_INT.") error("forbidden division t_FFELT \\ t_INT.") * [7, 2] t error("forbidden division t_FFELT \\ t_INT.") error("forbidden division t_FFELT % t_INT.") error("forbidden division t_FFELT \\ t_INT.") error("forbidden division t_FFELT \\ t_INT.") * [7, 3] error("forbidden division t_FFELT / t_REAL.") error("forbidden division t_FFELT / t_REAL.") error("forbidden division t_FFELT % t_REAL.") error("forbidden division t_FFELT / t_REAL.") error("forbidden division t_FFELT / t_REAL.") * [7, 4] 2*t error("incorrect type in gfloor (t_FFELT).") error("forbidden division t_FFELT % t_FRAC.") error("incorrect type in gfloor (t_FFELT).") error("incorrect type in gfloor (t_FFELT).") * [7, 5] t/(x^2 + 1) 0 t 0 [0, t]~ * [7, 6] Mod(2*t*x, x^2 + 1) error("forbidden division t_FFELT \\ t_POLMOD.") error("forbidden division t_FFELT % t_POLMOD.") error("forbidden division t_FFELT \\ t_POLMOD.") error("forbidden division t_FFELT \\ t_POLMOD.") * [7, 7] 1 error("forbidden division t_FFELT \\ t_FFELT.") error("forbidden division t_FFELT % t_FFELT.") error("forbidden division t_FFELT \\ t_FFELT.") error("forbidden division t_FFELT \\ t_FFELT.") * [7, 8] error("forbidden division t_FFELT / t_QUAD.") error("forbidden division t_FFELT \\ t_QUAD.") error("forbidden division t_FFELT % t_QUAD.") error("forbidden division t_FFELT \\ t_QUAD.") error("forbidden division t_FFELT \\ t_QUAD.") * [7, 9] error("forbidden division t_FFELT / t_PADIC.") error("forbidden division t_FFELT \\ t_PADIC.") error("forbidden division t_FFELT % t_PADIC.") error("forbidden division t_FFELT \\ t_PADIC.") error("forbidden division t_FFELT \\ t_PADIC.") * [7, 10] 2*t error("forbidden division t_FFELT \\ t_INTMOD.") error("forbidden division t_FFELT % t_INTMOD.") error("forbidden division t_FFELT \\ t_INTMOD.") error("forbidden division t_FFELT \\ t_INTMOD.") * [7, 11] 2*t error("forbidden division t_FFELT \\ t_INT.") error("forbidden division t_FFELT % t_INT.") error("forbidden division t_FFELT \\ t_INT.") error("forbidden division t_FFELT \\ t_INT.") * [8, 1] 1/3*w error("forbidden division t_QUAD \\ t_INT.") w error("forbidden division t_QUAD \\ t_INT.") error("forbidden division t_QUAD \\ t_INT.") * [8, 2] 1/4*w error("forbidden division t_QUAD \\ t_INT.") w error("forbidden division t_QUAD \\ t_INT.") error("forbidden division t_QUAD \\ t_INT.") * [8, 3] 0.52194644798383704780793123689214132830 0 error("forbidden division t_QUAD % t_REAL.") 0 [0, w]~ * [8, 4] 2*w error("incorrect type in gfloor (t_QUAD).") error("forbidden division t_QUAD % t_FRAC.") error("incorrect type in gfloor (t_QUAD).") error("incorrect type in gfloor (t_QUAD).") * [8, 5] w/(x^2 + 1) 0 w 0 [0, w]~ * [8, 6] Mod(-w*x, x^2 + 1) error("forbidden division t_QUAD \\ t_POLMOD.") error("forbidden division t_QUAD % t_POLMOD.") error("forbidden division t_QUAD \\ t_POLMOD.") error("forbidden division t_QUAD \\ t_POLMOD.") * [8, 7] error("forbidden division t_QUAD / t_FFELT.") error("forbidden division t_QUAD \\ t_FFELT.") error("forbidden division t_QUAD % t_FFELT.") error("forbidden division t_QUAD \\ t_FFELT.") error("forbidden division t_QUAD \\ t_FFELT.") * [8, 8] 1 error("forbidden division t_QUAD \\ t_QUAD.") error("forbidden division t_QUAD % t_QUAD.") error("forbidden division t_QUAD \\ t_QUAD.") error("forbidden division t_QUAD \\ t_QUAD.") * [8, 9] error("not an n-th power residue in Qp_sqrt: 5.") error("forbidden division t_QUAD \\ t_PADIC.") error("forbidden division t_QUAD % t_PADIC.") error("forbidden division t_QUAD \\ t_PADIC.") error("forbidden division t_QUAD \\ t_PADIC.") * [8, 10] Mod(0, 3) + Mod(2, 3)*w error("forbidden division t_QUAD \\ t_INTMOD.") error("forbidden division t_QUAD % t_INTMOD.") error("forbidden division t_QUAD \\ t_INTMOD.") error("forbidden division t_QUAD \\ t_INTMOD.") * [8, 11] 1/18446744073709551617*w error("forbidden division t_QUAD \\ t_INT.") w error("forbidden division t_QUAD \\ t_INT.") error("forbidden division t_QUAD \\ t_INT.") * [9, 1] 2*3^-1 + O(3^2) error("forbidden division t_PADIC \\ t_INT.") 2 error("forbidden division t_PADIC \\ t_INT.") error("forbidden division t_PADIC \\ t_INT.") * [9, 2] 2 + 3 + 3^2 + O(3^3) error("forbidden division t_PADIC \\ t_INT.") error("inconsistent t_PADIC , t_INTMOD.") error("forbidden division t_PADIC \\ t_INT.") error("forbidden division t_PADIC \\ t_INT.") * [9, 3] error("forbidden division t_PADIC / t_REAL.") error("forbidden division t_PADIC / t_REAL.") error("forbidden division t_PADIC % t_REAL.") error("forbidden division t_PADIC / t_REAL.") error("forbidden division t_PADIC / t_REAL.") * [9, 4] 1 + 3 + O(3^3) error("incorrect type in gfloor (t_PADIC).") error("forbidden division t_PADIC % t_FRAC.") error("incorrect type in gfloor (t_PADIC).") error("incorrect type in gfloor (t_PADIC).") * [9, 5] (2 + O(3^3))/(x^2 + 1) 0 2 + O(3^3) 0 [0, 2 + O(3^3)]~ * [9, 6] Mod((1 + 2*3 + 2*3^2 + O(3^3))*x, x^2 + 1) error("forbidden division t_PADIC \\ t_POLMOD.") error("forbidden division t_PADIC % t_POLMOD.") error("forbidden division t_PADIC \\ t_POLMOD.") error("forbidden division t_PADIC \\ t_POLMOD.") * [9, 7] error("forbidden division t_PADIC / t_FFELT.") error("forbidden division t_PADIC \\ t_FFELT.") error("forbidden division t_PADIC % t_FFELT.") error("forbidden division t_PADIC \\ t_FFELT.") error("forbidden division t_PADIC \\ t_FFELT.") * [9, 8] 1 + 2*3 + 2*3^2 + O(3^3) + (2 + O(3^3))*w error("forbidden division t_PADIC \\ t_QUAD.") error("forbidden division t_PADIC % t_QUAD.") error("forbidden division t_PADIC \\ t_QUAD.") error("forbidden division t_PADIC \\ t_QUAD.") * [9, 9] 1 + O(3^3) error("forbidden division t_PADIC \\ t_PADIC.") error("forbidden division t_PADIC % t_PADIC.") error("forbidden division t_PADIC \\ t_PADIC.") error("forbidden division t_PADIC \\ t_PADIC.") * [9, 10] Mod(1, 3) error("forbidden division t_PADIC \\ t_INTMOD.") error("forbidden division t_PADIC % t_INTMOD.") error("forbidden division t_PADIC \\ t_INTMOD.") error("forbidden division t_PADIC \\ t_INTMOD.") * [9, 11] 1 + 2*3 + 2*3^2 + O(3^3) error("forbidden division t_PADIC \\ t_INT.") error("inconsistent t_PADIC , t_INTMOD.") error("forbidden division t_PADIC \\ t_INT.") error("forbidden division t_PADIC \\ t_INT.") * [10, 1] error("impossible inverse in Fl_inv: Mod(0, 3).") error("forbidden division t_INTMOD \\ t_INT.") Mod(2, 3) error("forbidden division t_INTMOD \\ t_INT.") error("forbidden division t_INTMOD \\ t_INT.") * [10, 2] Mod(2, 3) error("forbidden division t_INTMOD \\ t_INT.") Mod(0, 1) error("forbidden division t_INTMOD \\ t_INT.") error("forbidden division t_INTMOD \\ t_INT.") * [10, 3] error("forbidden division t_INTMOD / t_REAL.") error("forbidden division t_INTMOD / t_REAL.") error("forbidden division t_INTMOD % t_REAL.") error("forbidden division t_INTMOD / t_REAL.") error("forbidden division t_INTMOD / t_REAL.") * [10, 4] Mod(1, 3) error("incorrect type in gfloor (t_INTMOD).") error("forbidden division t_INTMOD % t_FRAC.") error("incorrect type in gfloor (t_INTMOD).") error("incorrect type in gfloor (t_INTMOD).") * [10, 5] Mod(2, 3)/(x^2 + 1) 0 Mod(2, 3) 0 [0, Mod(2, 3)]~ * [10, 6] Mod(Mod(1, 3)*x, x^2 + 1) error("forbidden division t_INTMOD \\ t_POLMOD.") error("forbidden division t_INTMOD % t_POLMOD.") error("forbidden division t_INTMOD \\ t_POLMOD.") error("forbidden division t_INTMOD \\ t_POLMOD.") * [10, 7] t^4 + t^3 + 2*t^2 error("forbidden division t_INTMOD \\ t_FFELT.") error("forbidden division t_INTMOD % t_FFELT.") error("forbidden division t_INTMOD \\ t_FFELT.") error("forbidden division t_INTMOD \\ t_FFELT.") * [10, 8] Mod(1, 3) + Mod(2, 3)*w error("forbidden division t_INTMOD \\ t_QUAD.") error("forbidden division t_INTMOD % t_QUAD.") error("forbidden division t_INTMOD \\ t_QUAD.") error("forbidden division t_INTMOD \\ t_QUAD.") * [10, 9] Mod(1, 3) error("forbidden division t_INTMOD \\ t_PADIC.") error("forbidden division t_INTMOD % t_PADIC.") error("forbidden division t_INTMOD \\ t_PADIC.") error("forbidden division t_INTMOD \\ t_PADIC.") * [10, 10] Mod(1, 3) error("forbidden division t_INTMOD \\ t_INTMOD.") error("forbidden division t_INTMOD % t_INTMOD.") error("forbidden division t_INTMOD \\ t_INTMOD.") error("forbidden division t_INTMOD \\ t_INTMOD.") * [10, 11] Mod(1, 3) error("forbidden division t_INTMOD \\ t_INT.") Mod(0, 1) error("forbidden division t_INTMOD \\ t_INT.") error("forbidden division t_INTMOD \\ t_INT.") * [11, 1] 18446744073709551617/3 6148914691236517205 2 6148914691236517206 [6148914691236517205, 2]~ * [11, 2] 18446744073709551617/4 4611686018427387904 1 4611686018427387904 [4611686018427387904, 1]~ * [11, 3] 5950562604422436005.4838709677419354839 5950562604422436005 1.5000000000000000001 5950562604422436005 [5950562604422436005, 1.5000000000000000001]~ * [11, 4] 36893488147419103234 36893488147419103234 0 36893488147419103234 [36893488147419103234, 0]~ * [11, 5] 18446744073709551617/(x^2 + 1) 0 18446744073709551617 0 [0, 18446744073709551617]~ * [11, 6] Mod(-18446744073709551617*x, x^2 + 1) error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT % t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") * [11, 7] t^4 + t^3 + 2*t^2 error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT % t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") * [11, 8] -18446744073709551617 + 18446744073709551617*w error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT % t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") * [11, 9] 1 + 3 + 3^2 + O(3^3) error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT % t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") * [11, 10] Mod(1, 3) error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT % t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") * [11, 11] 1 1 0 1 [1, 0]~ * [1, 1] 1/3*x + O(x^2) error("forbidden division t_SER \\ t_INT.") error("forbidden division t_SER % t_INT.") error("forbidden division t_SER \\ t_INT.") * [1, 2] 1/4*x + O(x^2) error("forbidden division t_SER \\ t_INT.") error("forbidden division t_SER % t_INT.") error("forbidden division t_SER \\ t_INT.") * [1, 3] 0.32258064516129032258064516129032258065*x + O(x^2) error("incorrect type in gfloor (t_SER).") error("forbidden division t_SER % t_REAL.") error("incorrect type in gfloor (t_SER).") * [1, 4] 2*x + O(x^2) error("incorrect type in gfloor (t_SER).") error("forbidden division t_SER % t_FRAC.") error("incorrect type in gfloor (t_SER).") * [1, 5] x + O(x^2) error("forbidden euclidean division t_SER , t_POL.") error("forbidden division t_SER % t_POL.") error("forbidden euclidean division t_SER , t_POL.") * [1, 6] error("forbidden division t_SER % t_POL.") error("forbidden division t_SER \\ t_POLMOD.") error("forbidden division t_SER % t_POLMOD.") error("forbidden division t_SER \\ t_POLMOD.") * [1, 7] (2*t^4 + 2*t^3 + t^2)*x + O(x^2) error("forbidden division t_SER \\ t_FFELT.") error("forbidden division t_SER % t_FFELT.") error("forbidden division t_SER \\ t_FFELT.") * [1, 8] (-1 + w)*x + O(x^2) error("forbidden division t_SER \\ t_QUAD.") error("forbidden division t_SER % t_QUAD.") error("forbidden division t_SER \\ t_QUAD.") * [1, 9] (2 + 3 + 3^2 + O(3^3))*x + O(x^2) error("forbidden division t_SER \\ t_PADIC.") error("forbidden division t_SER % t_PADIC.") error("forbidden division t_SER \\ t_PADIC.") * [1, 10] Mod(2, 3)*x + O(x^2) error("forbidden division t_SER \\ t_INTMOD.") error("forbidden division t_SER % t_INTMOD.") error("forbidden division t_SER \\ t_INTMOD.") * [1, 11] 1/18446744073709551617*x + O(x^2) error("forbidden division t_SER \\ t_INT.") error("forbidden division t_SER % t_INT.") error("forbidden division t_SER \\ t_INT.") * [2, 1] [2/3, 1] [0, 1] [2, 0] [1, 1] * [2, 2] [1/2, 3/4] [0, 0] [2, 3] [1, 1] * [2, 3] [0.64516129032258064516129032258064516129, 0.9677419354838709677419354838709 6774194] [0, 0] [2, 3] [1, 1] * [2, 4] [4, 6] [4, 6] [0, 0] [4, 6] * [2, 5] [2/(x^2 + 1), 3/(x^2 + 1)] [0, 0] [2, 3] [0, 0] * [2, 6] [Mod(-2*x, x^2 + 1), Mod(-3*x, x^2 + 1)] error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT % t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") * [2, 7] [t^4 + t^3 + 2*t^2, 0] error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT % t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") * [2, 8] [-2 + 2*w, -3 + 3*w] error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT % t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") * [2, 9] [1 + O(3^3), 2*3 + 3^2 + 3^3 + O(3^4)] error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT % t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") * [2, 10] [Mod(1, 3), Mod(0, 3)] error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT % t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") * [2, 11] [2/18446744073709551617, 3/18446744073709551617] [0, 0] [2, 3] [0, 0] * [3, 1] Mat(2/3) Mat(0) Mat(2) Mat(1) * [3, 2] Mat(1/2) Mat(0) Mat(2) Mat(1) * [3, 3] Mat(0.64516129032258064516129032258064516129) Mat(0) Mat(2) Mat(1) * [3, 4] Mat(4) Mat(4) Mat(0) Mat(4) * [3, 5] Mat(2/(x^2 + 1)) Mat(0) Mat(2) Mat(0) * [3, 6] Mat(Mod(-2*x, x^2 + 1)) error("forbidden division t_INT \\ t_POLMOD.") error("forbidden division t_INT % t_POLMOD.") error("forbidden division t_INT \\ t_POLMOD.") * [3, 7] Mat(t^4 + t^3 + 2*t^2) error("forbidden division t_INT \\ t_FFELT.") error("forbidden division t_INT % t_FFELT.") error("forbidden division t_INT \\ t_FFELT.") * [3, 8] Mat(-2 + 2*w) error("forbidden division t_INT \\ t_QUAD.") error("forbidden division t_INT % t_QUAD.") error("forbidden division t_INT \\ t_QUAD.") * [3, 9] Mat(1 + O(3^3)) error("forbidden division t_INT \\ t_PADIC.") error("forbidden division t_INT % t_PADIC.") error("forbidden division t_INT \\ t_PADIC.") * [3, 10] Mat(Mod(1, 3)) error("forbidden division t_INT \\ t_INTMOD.") error("forbidden division t_INT % t_INTMOD.") error("forbidden division t_INT \\ t_INTMOD.") * [3, 11] Mat(2/18446744073709551617) Mat(0) Mat(2) Mat(0) [0, 1] Mat(0) [1, 1] Mat(1) [-x + y, x^2 + x]~ [[1, 1]~, [2, 1]~] [0, 1]~ [1, 0]~ *** at top-level: divrem(1,"a") *** ^------------- *** divrem: forbidden division t_INT \ t_STR. 2 x [] []~ [;] *** at top-level: [1]/0 *** ^-- *** _/_: impossible inverse in gdiv: 0. Mod(Mod(2, 3)*a + Mod(1, 3), Mod(1, 3)*a^3 + Mod(1, 3)*a^2 + Mod(1, 3)*a + M od(2, 3))*x^4 + Mod(Mod(2, 3)*a^2 + Mod(2, 3), Mod(1, 3)*a^3 + Mod(1, 3)*a^2 + Mod(1, 3)*a + Mod(2, 3))*x^3 + Mod(Mod(2, 3)*a, Mod(1, 3)*a^3 + Mod(1, 3) *a^2 + Mod(1, 3)*a + Mod(2, 3))*x^2 + Mod(Mod(1, 3)*a^2 + Mod(2, 3), Mod(1, 3)*a^3 + Mod(1, 3)*a^2 + Mod(1, 3)*a + Mod(2, 3))*x + Mod(Mod(1, 3)*a, Mod(1 , 3)*a^3 + Mod(1, 3)*a^2 + Mod(1, 3)*a + Mod(2, 3)) Total time spent: 0 pari-2.11.2/src/test/32/analyz0000644000175000017500000000033513326135265014400 0ustar billbill echo = 1 ? sum(x=0,50000,x); ? sum(x=1,1000,log(x)); ? sum(x=1,25,sum(y=1,100,x/y),0.0); ? sum(x=1,100,sum(y=1,100,x/y,0.0)); ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 17 pari-2.11.2/src/test/32/nfhilbert0000644000175000017500000000756213326135265015070 0ustar billbill[-1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1] [-1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1] -1 *** at top-level: nfhilbert(nf,Mod(0,3),3,pr) *** ^--------------------------- *** nfhilbert: domain error in nfhilbert: a = 0 *** at top-level: nfhilbert(nf,3,0.,pr) *** ^--------------------- *** nfhilbert: domain error in nfhilbert: b = 0 1 1 -1 [1, 2]: 1 [1, 3]: 1 [1, 4]: error("precision too low in hilbert.") [1, 5]: error("precision too low in hilbert.") [1, 6]: 1 [1, 7]: 1 [1, 8]: 0 [1, 9]: error("precision too low in hilbert.") [1, 10]: 1 [1, 11]: 1 [2, 3]: 1 [2, 4]: error("precision too low in hilbert.") [2, 5]: error("precision too low in hilbert.") [2, 6]: 1 [2, 7]: 1 [2, 8]: 0 [2, 9]: error("precision too low in hilbert.") [2, 10]: 1 [2, 11]: 1 [3, 4]: error("forbidden hilbert t_REAL , t_INTMOD.") [3, 5]: error("forbidden hilbert t_REAL , t_INTMOD.") [3, 6]: error("forbidden hilbert t_REAL , t_INTMOD.") [3, 7]: error("forbidden hilbert t_REAL , t_INTMOD.") [3, 8]: error("forbidden hilbert t_REAL , t_INTMOD.") [3, 9]: error("forbidden hilbert t_REAL , t_PADIC.") [3, 10]: error("forbidden hilbert t_REAL , t_PADIC.") [3, 11]: error("forbidden hilbert t_REAL , t_PADIC.") [4, 5]: error("precision too low in hilbert.") [4, 6]: error("precision too low in hilbert.") [4, 7]: error("precision too low in hilbert.") [4, 8]: error("precision too low in hilbert.") [4, 9]: error("precision too low in hilbert.") [4, 10]: error("precision too low in hilbert.") [4, 11]: error("precision too low in hilbert.") [5, 6]: error("precision too low in hilbert.") [5, 7]: error("precision too low in hilbert.") [5, 8]: error("precision too low in hilbert.") [5, 9]: error("precision too low in hilbert.") [5, 10]: error("precision too low in hilbert.") [5, 11]: error("precision too low in hilbert.") [6, 7]: error("inconsistent moduli in hilbert: 3 != 8") [6, 8]: error("inconsistent moduli in hilbert: 5 != 8") [6, 9]: error("inconsistent moduli in hilbert: 8 != 2") [6, 10]: error("inconsistent moduli in hilbert: 8 != 2") [6, 11]: error("inconsistent moduli in hilbert: 8 != 5") [7, 8]: error("inconsistent moduli in hilbert: 5 != 3") [7, 9]: error("inconsistent moduli in hilbert: 3 != 2") [7, 10]: error("inconsistent moduli in hilbert: 3 != 2") [7, 11]: error("inconsistent moduli in hilbert: 3 != 5") [8, 9]: error("inconsistent moduli in hilbert: 5 != 2") [8, 10]: error("inconsistent moduli in hilbert: 5 != 2") [8, 11]: 0 [9, 10]: error("precision too low in hilbert.") [9, 11]: error("precision too low in hilbert.") [10, 11]: error("inconsistent moduli in hilbert: 2 != 5") p = 0: 1: 1 2: 1 3: 1 4: error("inconsistent moduli in hilbert: 2 != \"oo\"") 5: error("inconsistent moduli in hilbert: 4 != \"oo\"") 6: error("inconsistent moduli in hilbert: 8 != \"oo\"") 7: error("inconsistent moduli in hilbert: 3 != \"oo\"") 8: error("inconsistent moduli in hilbert: 5 != \"oo\"") 9: error("inconsistent moduli in hilbert: 0 != 2") 10: error("inconsistent moduli in hilbert: 0 != 2") 11: error("inconsistent moduli in hilbert: 0 != 5") p = 2: 1: 1 2: -1 3: error("inconsistent moduli in hilbert: 2 != \"oo\"") 4: error("precision too low in hilbert.") 5: error("precision too low in hilbert.") 6: 1 7: error("precision too low in hilbert.") 8: error("precision too low in hilbert.") 9: error("precision too low in hilbert.") 10: 1 11: error("inconsistent moduli in hilbert: 2 != 5") p = 5: 1: 1 2: 1 3: error("inconsistent moduli in hilbert: 5 != \"oo\"") 4: error("inconsistent moduli in hilbert: 2 != 5") 5: error("inconsistent moduli in hilbert: 4 != 5") 6: error("inconsistent moduli in hilbert: 8 != 5") 7: error("inconsistent moduli in hilbert: 3 != 5") 8: error("precision too low in hilbert.") 9: error("inconsistent moduli in hilbert: 5 != 2") 10: error("inconsistent moduli in hilbert: 5 != 2") 11: 1 -1 -1 1 Total time spent: 344 pari-2.11.2/src/test/32/partition0000644000175000017500000001041113272053420015077 0ustar billbill1 8646071025430235692572306890072717030146724518193248646261116875039232350406 4122598473575016156709489555875867462346177817327218448788050480708550298957 4471483457937988438791783450144642834886864800778387328738323763398284354678 2467335026575150468969 1315427338504929671669092893786176891908548434593143202526362264344662102688 7135460507830403502328150530572701695452361942348769947362008712123081217734 3187588697310977671154801113558915889945842493651964099879750098080254447377 4788789260448084624118833910204856780861639068659823549617824714773817253043 9615105518523078574457183315543226124650052897717744601504125318067437912564 426796827005538082281337283642237399241533 *** at top-level: numbpart(10^15+2) *** ^----------------- *** numbpart: overflow in numbpart [n < 10^15]. [Vecsmall([])] [Vecsmall([1])] [Vecsmall([9]), Vecsmall([1, 8]), Vecsmall([2, 7]), Vecsmall([3, 6]), Vecsma ll([4, 5]), Vecsmall([1, 1, 7]), Vecsmall([1, 2, 6]), Vecsmall([1, 3, 5]), V ecsmall([1, 4, 4]), Vecsmall([2, 2, 5]), Vecsmall([2, 3, 4]), Vecsmall([3, 3 , 3]), Vecsmall([1, 1, 1, 6]), Vecsmall([1, 1, 2, 5]), Vecsmall([1, 1, 3, 4] ), Vecsmall([1, 2, 2, 4]), Vecsmall([1, 2, 3, 3]), Vecsmall([2, 2, 2, 3]), V ecsmall([1, 1, 1, 1, 5]), Vecsmall([1, 1, 1, 2, 4]), Vecsmall([1, 1, 1, 3, 3 ]), Vecsmall([1, 1, 2, 2, 3]), Vecsmall([1, 2, 2, 2, 2]), Vecsmall([1, 1, 1, 1, 1, 4]), Vecsmall([1, 1, 1, 1, 2, 3]), Vecsmall([1, 1, 1, 2, 2, 2]), Vecs mall([1, 1, 1, 1, 1, 1, 3]), Vecsmall([1, 1, 1, 1, 1, 2, 2]), Vecsmall([1, 1 , 1, 1, 1, 1, 1, 2]), Vecsmall([1, 1, 1, 1, 1, 1, 1, 1, 1])] [Vecsmall([3, 3, 3]), Vecsmall([1, 2, 3, 3]), Vecsmall([2, 2, 2, 3]), Vecsma ll([1, 1, 1, 3, 3]), Vecsmall([1, 1, 2, 2, 3]), Vecsmall([1, 2, 2, 2, 2]), V ecsmall([1, 1, 1, 1, 2, 3]), Vecsmall([1, 1, 1, 2, 2, 2]), Vecsmall([1, 1, 1 , 1, 1, 1, 3]), Vecsmall([1, 1, 1, 1, 1, 2, 2]), Vecsmall([1, 1, 1, 1, 1, 1, 1, 2]), Vecsmall([1, 1, 1, 1, 1, 1, 1, 1, 1])] [] [] [] [] [Vecsmall([0, 1, 1, 1])] [Vecsmall([0, 1, 1, 2]), Vecsmall([1, 1, 1, 1])] [Vecsmall([0, 1, 1, 3]), Vecsmall([0, 1, 2, 2]), Vecsmall([1, 1, 1, 2])] [1, 4] [2, 3] [1, 1, 3] [1, 2, 2] [0, 0, 1, 4] [0, 0, 2, 3] [0, 1, 1, 3] [0, 1, 2, 2] [1, 1, 1, 2] 451276 [9] [1, 8] [2, 7] [3, 6] [4, 5] [1, 1, 7] [1, 2, 6] [1, 3, 5] [1, 4, 4] [2, 2, 5] [2, 3, 4] [3, 3, 3] [1, 1, 1, 6] [1, 1, 2, 5] [1, 1, 3, 4] [1, 2, 2, 4] [1, 2, 3, 3] [2, 2, 2, 3] [1, 1, 1, 1, 5] [1, 1, 1, 2, 4] [1, 1, 1, 3, 3] [1, 1, 2, 2, 3] [1, 2, 2, 2, 2] [1, 1, 1, 1, 1, 4] [1, 1, 1, 1, 2, 3] [1, 1, 1, 2, 2, 2] [1, 1, 1, 1, 1, 1, 3] [1, 1, 1, 1, 1, 2, 2] [1, 1, 1, 1, 1, 1, 1, 2] [1, 1, 1, 1, 1, 1, 1, 1, 1] [11] [1, 10] [2, 9] [3, 8] [4, 7] [5, 6] [1, 1, 9] [1, 2, 8] [1, 3, 7] [1, 4, 6] [1, 5, 5] [2, 2, 7] [2, 3, 6] [2, 4, 5] [3, 3, 5] [3, 4, 4] [1, 1, 1, 8] [1, 1, 2, 7] [1, 1, 3, 6] [1, 1, 4, 5] [1, 2, 2, 6] [1, 2, 3, 5] [1, 2, 4, 4] [1, 3, 3, 4] [2, 2, 2, 5] [2, 2, 3, 4] [2, 3, 3, 3] [1, 1, 1, 1, 7] [1, 1, 1, 2, 6] [1, 1, 1, 3, 5] [1, 1, 1, 4, 4] [1, 1, 2, 2, 5] [1, 1, 2, 3, 4] [1, 1, 3, 3, 3] [1, 2, 2, 2, 4] [1, 2, 2, 3, 3] [2, 2, 2, 2, 3] [1, 11] [2, 10] [3, 9] [4, 8] [5, 7] [6, 6] [1, 1, 10] [1, 2, 9] [1, 3, 8] [1, 4, 7] [1, 5, 6] [2, 2, 8] [2, 3, 7] [2, 4, 6] [2, 5, 5] [3, 3, 6] [3, 4, 5] [4, 4, 4] [1, 1, 1, 9] [1, 1, 2, 8] [1, 1, 3, 7] [1, 1, 4, 6] [1, 1, 5, 5] [1, 2, 2, 7] [1, 2, 3, 6] [1, 2, 4, 5] [1, 3, 3, 5] [1, 3, 4, 4] [2, 2, 2, 6] [2, 2, 3, 5] [2, 2, 4, 4] [2, 3, 3, 4] [3, 3, 3, 3] [1, 1, 1, 1, 8] [1, 1, 1, 2, 7] [1, 1, 1, 3, 6] [1, 1, 1, 4, 5] [1, 1, 2, 2, 6] [1, 1, 2, 3, 5] [1, 1, 2, 4, 4] [1, 1, 3, 3, 4] [1, 2, 2, 2, 5] [1, 2, 2, 3, 4] [1, 2, 3, 3, 3] [2, 2, 2, 2, 4] [2, 2, 2, 3, 3] [1, 1, 1, 1, 1, 7] [1, 1, 1, 1, 2, 6] [1, 1, 1, 1, 3, 5] [1, 1, 1, 1, 4, 4] [1, 1, 1, 2, 2, 5] [1, 1, 1, 2, 3, 4] [1, 1, 1, 3, 3, 3] [1, 1, 2, 2, 2, 4] [1, 1, 2, 2, 3, 3] [1, 2, 2, 2, 2, 3] [2, 2, 2, 2, 2, 2] [5, 6, 6, 6] [3, 3, 5, 6, 6] [3, 4, 4, 6, 6] [3, 4, 5, 5, 6] [3, 5, 5, 5, 5] [4, 4, 4, 5, 6] [4, 4, 5, 5, 5] [3, 3, 3, 3, 5, 6] [3, 3, 3, 4, 4, 6] [3, 3, 3, 4, 5, 5] [3, 3, 4, 4, 4, 5] [3, 4, 4, 4, 4, 4] [3, 3, 3, 3, 3, 3, 5] [3, 3, 3, 3, 3, 4, 4] [0, 0, 0, 2, 3] [0, 0, 1, 1, 3] [0, 0, 1, 2, 2] [0, 1, 1, 1, 2] [1, 1, 1, 1, 1] [0, 0, 3, 3, 3, 3, 3] [0, 1, 2, 3, 3, 3, 3] [0, 2, 2, 2, 3, 3, 3] [1, 1, 1, 3, 3, 3, 3] [1, 1, 2, 2, 3, 3, 3] [1, 2, 2, 2, 2, 3, 3] [2, 2, 2, 2, 2, 2, 3] Total time spent: 2560 pari-2.11.2/src/test/32/bnfinit0000644000175000017500000000000011636712103014512 0ustar billbillpari-2.11.2/src/test/32/charpoly0000644000175000017500000001022213457566442014731 0ustar billbill(-y + 1)*x + (y^2 - 2*y - 1) (-y + 1)*x + (y^2 - 2*y - 1) (-y + 1)*x + (y^2 - 2*y - 1) (-y + 1)*x + (y^2 - 2*y - 1) x^4 - 16*x^2 x^4 - 16*x^2 x^2 - 4*x [1 14/39] [0 1] [1 0.35897435897435897435897435897435897438] [0 1] [[5/3, 21/10], [1, 14/39; 0, 1]] [0.025784835985469857086599615759958975735, 0.199915025473745745510054037511 86752336, 0.45186281535484114060969116665631585174, 429.32243732318594325679 365518007185765] -113 -x^2 + (-y - w)*x + (-y + (w^2 - w)) x - 1 x - 1.0000000000000000000000000000000000000 x + Mod(2, 3) x - 1/2 x + (2 + O(3)) x^2 + 1 x^2 - x - 1 Mod(1, 3)*x^2 + Mod(1, 3)*x + Mod(1, 3) Mod(1, 18446744073709551629)*x^2 + Mod(18446744073709551627, 184467440737095 51629)*x + Mod(1, 18446744073709551629) 1 x^6 - x^5 - 3*x^4 - 3*x^3 - 3*x^2 - x + 1 x^4 - 4*x^3 + 6*x^2 - 4*x + 1 x^4 - 4*x^3 + 6*x^2 - 4*x + 1 x^4 - 73786976294838206516*x^3 + 2041694201525630783657939720089299321846*x^ 2 - 25108406941546723108427206932497066002105857518694949724756*x + 11579208 9237316195749980275248795307917777354730270819790751905975615430356881 Mod(1, 3)*x^4 + Mod(1, 3)*x^3 + Mod(1, 3)*x^2 + Mod(1, 3)*x Mod(1, 18446744073709551629)*x^4 + Mod(18446744073709551600, 184467440737095 51629)*x^3 + Mod(46, 18446744073709551629)*x^2 + Mod(16, 1844674407370955162 9)*x [1 0] [0 1] [;] [1] [0 0 0] [0 0 0] [0 0 0] [Mod(0, 2) Mod(0, 2) Mod(0, 2)] [Mod(0, 2) Mod(0, 2) Mod(0, 2)] [Mod(0, 2) Mod(0, 2) Mod(0, 2)] *** at top-level: charpoly(x*matid(3)) *** ^-------------------- *** charpoly: incorrect priority in charpoly: variable x = x x^4 - 4*x^3 + 6*x^2 - 4*x + 2 x^2 x - 1 x - 1 x - 1 [] [[], [;]] [1] [[1], Mat(1)] [0.E-38, -3.1356028349282496289992466889123954235 E-39, -6.60051645074953159 00700991108611527795 E-40, 1.1073849293427036872827738448743471865 E-39, 2.0 000000000000000000000000000000000000, 2.500000000000000000000000000000000000 0, 2.5000000000000000000000000000000000000]~ [[0.E-38, -3.1356028349282496289992466889123954235 E-39, -6.6005164507495315 900700991108611527795 E-40, 1.1073849293427036872827738448743471865 E-39, 2. 0000000000000000000000000000000000000, 2.50000000000000000000000000000000000 00, 2.5000000000000000000000000000000000000]~, [0.70710678118654752440084436 210484903928, 0.E-38, 0.E-38, 0.E-38, 0.707106781186547524400844362104849039 29, 0.E-38, 0.E-38; 0.70710678118654752440084436210484903929, 0.E-38, 0.E-38 , 0.E-38, -0.70710678118654752440084436210484903928, 0.E-38, 0.E-38; 0.E-38, 0.23999696351543677575648770150590372098, -0.283622172709065437120208223985 82804906, 0.67967633521490150959346301374385356331, 0.E-38, 0.61582013154270 957217214628524015061291, 0.14410262172049431191936511310596050606; 0.E-38, 0.57468823740117602493745785679291224747, 0.48651107386360438477651495190903 150502, -0.18177019777953707317421657491323056668, 0.E-38, 0.053249148722421 216995940588902203986718, 0.63020990801504974979984540216856201701; 0.E-38, -0.24043700257187013561719500269086834184, 0.2838014394622370296006228261461 4643943, 0.67944594395243594261215492515632318777, 0.E-38, -0.58291034776025 522011810821578892183638, 0.24538852147975121227580790648499184101; 0.E-38, 0.74377206690669372496948296733199987942, -0.1583407288019554674288185058434 1540904, 0.14741548796449545166318703395156923765, 0.E-38, -0.41350755603228 008533391235202071506688, -0.47855146129147985876298725459512205052; 0.E-38, -0.033586419572483189091808052063575280391, 0.75976996171045044547062225467 793619648, 0.14704270707111516638694570644189499592, 0.E-38, 0.3273486235274 0451628393369366728230362, -0.54114958992381541523203116716439231357]] *** at top-level: charpoly(Mod('b,'b^2+Mod('a,'a^2+1)),'newvar) *** ^--------------------------------------------- *** charpoly: incorrect priority in RgXQ_charpoly: variable newvar < a *** at top-level: minpoly(Mod(y,x),'y) *** ^-------------------- *** minpoly: incorrect priority in minpoly: variable x < y *** at top-level: localbitprec(32);mateigen(merror*bitprecision( *** ^----------------------------- *** mateigen: precision too low in mateigen. Total time spent: 4 pari-2.11.2/src/test/32/concat0000644000175000017500000000233513036414402014342 0ustar billbill [1 2 5] [3 4 6] [1 2] [3 4] [7 8] [1 2 5] [3 4 6] [7 8 9] [1 2 4] [0 3 5] [0 0 6] [1 0 0] [2 3 0] [4 5 6] [5 0 7 8] [6 0 0 0] [1 2 9 0] [3 4 0 9] [;] "x2" [1] [;] *** at top-level: concat([;],[1]) *** ^--------------- *** concat: inconsistent concatenation t_MAT (0x0) , t_VEC (1 elts). [1] [;] *** at top-level: concat([1],[;]) *** ^--------------- *** concat: inconsistent concatenation t_VEC (1 elts) , t_MAT (0x0). [1, 2] [1, 2] [1 2] *** at top-level: concat(1,A) *** ^----------- *** concat: inconsistent concatenation t_INT , t_MAT (2x2). [2 1] *** at top-level: concat(A,1) *** ^----------- *** concat: inconsistent concatenation t_MAT (2x2) , t_INT. [1, 2] [1, 2, 1] *** at top-level: concat([1,2],[1,2]~) *** ^-------------------- *** concat: inconsistent concatenation t_VEC (2 elts) , t_COL (2 elts). [2 3] [1 0] [0 1] [1, 2] [3, 1, 2] [2, 3]~ [2, 3, 1]~ *** at top-level: concat([2,3]~,[1,2]) *** ^-------------------- *** concat: inconsistent concatenation t_COL (2 elts) , t_VEC (2 elts). [;] [1 2] [3 4] [1 2] [1, 2] [1 2] Total time spent: 0 pari-2.11.2/src/test/32/factormod0000644000175000017500000003737513457566437015114 0ustar billbill[x + 7, 1; x + 8, 1; x + 20, 1; x + 21, 1; x + 24, 1; x + 50, 1; x + 60, 1; x + 63, 1; x + 68, 1; x + 72, 1; x + 125, 1; x + 139, 1; x + 146, 1; x + 150 , 1; x + 170, 1; x + 180, 1; x + 189, 1; x + 193, 1; x + 204, 1; x + 212, 1; x + 216, 1; x + 239, 1; x + 293, 1; x + 338, 1; x + 343, 1; x + 346, 1; x + 364, 1; x + 365, 1; x + 375, 1; x + 377, 1; x + 392, 1; x + 406, 1; x + 412 , 1; x + 416, 1; x + 417, 1; x + 425, 1; x + 438, 1; x + 448, 1; x + 450, 1; x + 457, 1; x + 463, 1; x + 464, 1; x + 466, 1; x + 502, 1; x + 506, 1; x + 510, 1; x + 512, 1; x + 530, 1; x + 540, 1; x + 567, 1; x + 578, 1; x + 579 , 1; x + 612, 1; x + 614, 1; x + 622, 1; x + 636, 1; x + 648, 1; x + 682, 1; x + 716, 1; x + 717, 1; x + 751, 1; x + 767, 1; x + 769, 1; x + 778, 1; x + 791, 1; x + 814, 1; x + 826, 1; x + 844, 1; x + 845, 1; x + 865, 1; x + 874 , 1; x + 879, 1; x + 881, 1; x + 904, 1; x + 910, 1; x + 923, 1; x + 944, 1; x + 980, 1; x + 982, 1; x + 994, 1; x + 1014, 1; x + 1015, 1; x + 1029, 1; x + 1030, 1; x + 1038, 1; x + 1040, 1; x + 1057, 1; x + 1092, 1; x + 1095, 1 ; x + 1120, 1; x + 1125, 1; x + 1131, 1; x + 1136, 1; x + 1160, 1; x + 1165, 1; x + 1176, 1; x + 1178, 1; x + 1208, 1; x + 1218, 1; x + 1223, 1; x + 122 6, 1; x + 1236, 1; x + 1241, 1; x + 1248, 1; x + 1251, 1; x + 1255, 1; x + 1 265, 1; x + 1275, 1; x + 1279, 1; x + 1280, 1; x + 1282, 1; x + 1314, 1; x + 1325, 1; x + 1327, 1; x + 1344, 1; x + 1350, 1; x + 1371, 1; x + 1373, 1; x + 1389, 1; x + 1392, 1; x + 1398, 1; x + 1403, 1; x + 1406, 1; x + 1409, 1; x + 1417, 1; x + 1445, 1; x + 1468, 1; x + 1481, 1; x + 1506, 1; x + 1518, 1; x + 1522, 1; x + 1526, 1; x + 1530, 1; x + 1535, 1; x + 1536, 1; x + 1555 , 1; x + 1573, 1; x + 1590, 1; x + 1620, 1; x + 1658, 1; x + 1681, 1; x + 16 87, 1; x + 1694, 1; x + 1701, 1; x + 1705, 1; x + 1706, 1; x + 1721, 1; x + 1734, 1; x + 1737, 1; x + 1744, 1; x + 1756, 1; x + 1763, 1; x + 1783, 1; x + 1790, 1; x + 1802, 1; x + 1804, 1; x + 1826, 1; x + 1836, 1; x + 1842, 1; x + 1849, 1; x + 1866, 1; x + 1868, 1; x + 1882, 1; x + 1891, 1; x + 1892, 1 ; x + 1901, 1; x + 1908, 1; x + 1927, 1; x + 1928, 1; x + 1936, 1; x + 1942, 1; x + 1944, 1; x + 1945, 1; x + 2021, 1; x + 2035, 1; x + 2046, 1; x + 205 4, 1; x + 2065, 1; x + 2068, 1; x + 2110, 1; x + 2148, 1; x + 2151, 1; x + 2 164, 1; x + 2171, 1; x + 2185, 1; x + 2209, 1; x + 2212, 1; x + 2213, 1; x + 2231, 1; x + 2253, 1; x + 2257, 1; x + 2260, 1; x + 2275, 1; x + 2276, 1; x + 2291, 1; x + 2293, 1; x + 2301, 1; x + 2307, 1; x + 2334, 1; x + 2338, 1; x + 2360, 1; x + 2373, 1; x + 2429, 1; x + 2434, 1; x + 2442, 1; x + 2450, 1; x + 2455, 1; x + 2461, 1; x + 2478, 1; x + 2483, 1; x + 2485, 1; x + 2528 , 1; x + 2532, 1; x + 2535, 1; x + 2575, 1; x + 2593, 1; x + 2595, 1; x + 26 00, 1; x + 2602, 1; x + 2622, 1; x + 2626, 1; x + 2633, 1; x + 2637, 1; x + 2643, 1; x + 2672, 1; x + 2674, 1; x + 2689, 1; x + 2712, 1; x + 2717, 1; x + 2730, 1; x + 2769, 1; x + 2776, 1; x + 2800, 1; x + 2827, 1; x + 2828, 1; x + 2832, 1; x + 2840, 1; x + 2873, 1; x + 2894, 1; x + 2900, 1; x + 2926, 1 ; x + 2929, 1; x + 2940, 1; x + 2941, 1; x + 2945, 1; x + 2946, 1; x + 2947, 1; x + 2957, 1; x + 2982, 1; x + 3007, 1; x + 3017, 1; x + 3019, 1; x + 302 0, 1; x + 3028, 1; x + 3042, 1; x + 3045, 1; x + 3056, 1; x + 3065, 1; x + 3 087, 1; x + 3090, 1; x + 3094, 1; x + 3114, 1; x + 3116, 1; x + 3120, 1; x + 3121, 1; x + 3154, 1; x + 3163, 1; x + 3171, 1; x + 3200, 1; x + 3205, 1; x + 3221, 1; x + 3229, 1; x + 3232, 1; x + 3238, 1; x + 3268, 1; x + 3276, 1; x + 3278, 1; x + 3285, 1; x + 3317, 1; x + 3332, 1; x + 3338, 1; x + 3343, 1; x + 3344, 1; x + 3359, 1; x + 3360, 1; x + 3368, 1; x + 3375, 1; x + 3393 , 1; x + 3407, 1; x + 3408, 1; x + 3418, 1; x + 3448, 1; x + 3449, 1; x + 34 51, 1; x + 3454, 1; x + 3466, 1; x + 3469, 1; x + 3480, 1; x + 3495, 1; x + 3502, 1; x + 3511, 1; x + 3515, 1; x + 3528, 1; x + 3534, 1; x + 3536, 1; x + 3572, 1; x + 3578, 1; x + 3589, 1; x + 3607, 1; x + 3624, 1; x + 3654, 1; x + 3669, 1; x + 3670, 1; x + 3678, 1; x + 3708, 1; x + 3723, 1; x + 3744, 1 ; x + 3753, 1; x + 3758, 1; x + 3765, 1; x + 3769, 1; x + 3793, 1; x + 3795, 1; x + 3805, 1; x + 3808, 1; x + 3815, 1; x + 3821, 1; x + 3825, 1; x + 383 7, 1; x + 3840, 1; x + 3846, 1; x + 3869, 1; x + 3889, 1; x + 3929, 1; x + 3 941, 1; x + 3942, 1; x + 3944, 1; x + 3947, 1; x + 3959, 1; x + 3961, 1; x + 3975, 1; x + 3981, 1; x + 3982, 1; x + 4032, 1; x + 4050, 1; x + 4094, 1; x + 4099, 1; x + 4103, 1; x + 4113, 1; x + 4119, 1; x + 4138, 1; x + 4145, 1; x + 4153, 1; x + 4167, 1; x + 4176, 1; x + 4194, 1; x + 4209, 1; x + 4218, 1; x + 4222, 1; x + 4227, 1; x + 4235, 1; x + 4238, 1; x + 4251, 1; x + 4265 , 1; x + 4267, 1; x + 4273, 1; x + 4289, 1; x + 4301, 1; x + 4335, 1; x + 43 52, 1; x + 4360, 1; x + 4378, 1; x + 4390, 1; x + 4404, 1; x + 4411, 1; x + 4423, 1; x + 4443, 1; x + 4475, 1; x + 4483, 1; x + 4489, 1; x + 4499, 1; x + 4504, 1; x + 4505, 1; x + 4510, 1; x + 4518, 1; x + 4523, 1; x + 4538, 1; x + 4554, 1; x + 4564, 1; x + 4565, 1; x + 4566, 1; x + 4578, 1; x + 4590, 1 ; x + 4605, 1; x + 4608, 1; x + 4649, 1; x + 4661, 1; x + 4665, 1; x + 4670, 1; x + 4684, 1; x + 4693, 1; x + 4697, 1; x + 4705, 1; x + 4719, 1; x + 472 7, 1; x + 4730, 1; x + 4739, 1; x + 4770, 1; x + 4781, 1; x + 4820, 1; x + 4 834, 1; x + 4840, 1; x + 4855, 1; x + 4860, 1; x + 4883, 1; x + 4906, 1; x + 4913, 1; x + 4924, 1; x + 4939, 1; x + 4963, 1; x + 4974, 1; x + 4987, 1; x + 5002, 1; x + 5039, 1; x + 5043, 1; x + 5054, 1; x + 5061, 1; x + 5063, 1; x + 5078, 1; x + 5082, 1; x + 5102, 1; x + 5103, 1; x + 5115, 1; x + 5118, 1; x + 5135, 1; x + 5163, 1; x + 5170, 1; x + 5189, 1; x + 5202, 1; x + 5207 , 1; x + 5209, 1; x + 5211, 1; x + 5216, 1; x + 5219, 1; x + 5232, 1; x + 52 46, 1; x + 5268, 1; x + 5275, 1; x + 5287, 1; x + 5289, 1; x + 5349, 1; x + 5368, 1; x + 5370, 1; x + 5386, 1; x + 5406, 1; x + 5410, 1; x + 5411, 1; x + 5412, 1; x + 5416, 1; x + 5461, 1; x + 5464, 1; x + 5478, 1; x + 5508, 1; x + 5509, 1; x + 5518, 1; x + 5526, 1; x + 5530, 1; x + 5547, 1; x + 5588, 1 ; x + 5596, 1; x + 5598, 1; x + 5604, 1; x + 5609, 1; x + 5618, 1; x + 5646, 1; x + 5650, 1; x + 5653, 1; x + 5662, 1; x + 5672, 1; x + 5673, 1; x + 567 6, 1; x + 5690, 1; x + 5703, 1; x + 5724, 1; x + 5734, 1; x + 5776, 1; x + 5 781, 1; x + 5784, 1; x + 5789, 1; x + 5797, 1; x + 5808, 1; x + 5826, 1; x + 5832, 1; x + 5835, 1; x + 5836, 1; x + 5845, 1; x + 5900, 1; x + 5959, 1; x + 5966, 1; x + 5969, 1; x + 5987, 1; x + 5993, 1; x + 6026, 1; x + 6063, 1; x + 6085, 1; x + 6086, 1; x + 6092, 1; x + 6094, 1; x + 6105, 1; x + 6125, 1; x + 6127, 1; x + 6138, 1; x + 6151, 1; x + 6162, 1; x + 6164, 1; x + 6184 , 1; x + 6195, 1; x + 6197, 1; x + 6203, 1; x + 6204, 1; x + 6226, 1; x + 62 63, 1; x + 6296, 1; x + 6302, 1; x + 6320, 1; x + 6323, 1; x + 6330, 1; x + 6389, 1; x + 6444, 1; x + 6453, 1; x + 6454, 1; x + 6457, 1; x + 6463, 1; x + 6481, 1; x + 6492, 1; x + 6500, 1; x + 6505, 1; x + 6508, 1; x + 6513, 1; x + 6555, 1; x + 6565, 1; x + 6586, 1; x + 6599, 1; x + 6613, 1; x + 6616, 1 ; x + 6617, 1; x + 6627, 1; x + 6636, 1; x + 6639, 1; x + 6643, 1; x + 6671, 1; x + 6680, 1; x + 6685, 1; x + 6691, 1; x + 6693, 1; x + 6701, 1; x + 674 2, 1; x + 6759, 1; x + 6763, 1; x + 6771, 1; x + 6780, 1; x + 6781, 1; x + 6 811, 1; x + 6825, 1; x + 6828, 1; x + 6873, 1; x + 6877, 1; x + 6878, 1; x + 6879, 1; x + 6883, 1; x + 6903, 1; x + 6919, 1; x + 6921, 1; x + 6940, 1; x + 7000, 1; x + 7002, 1; x + 7014, 1; x + 7021, 1; x + 7043, 1; x + 7057, 1; x + 7070, 1; x + 7073, 1; x + 7078, 1; x + 7080, 1; x + 7082, 1; x + 7087, 1; x + 7100, 1; x + 7119, 1; x + 7126, 1; x + 7154, 1; x + 7171, 1; x + 7174 , 1; x + 7186, 1; x + 7187, 1; x + 7207, 1; x + 7211, 1; x + 7226, 1; x + 72 28, 1; x + 7235, 1; x + 7246, 1; x + 7250, 1; x + 7287, 1; x + 7302, 1; x + 7315, 1; x + 7326, 1; x + 7350, 1; x + 7365, 1; x + 7376, 1; x + 7383, 1; x + 7406, 1; x + 7429, 1; x + 7434, 1; x + 7449, 1; x + 7455, 1; x + 7469, 1; x + 7508, 1; x + 7519, 1; x + 7550, 1; x + 7559, 1; x + 7562, 1; x + 7570, 1 ; x + 7584, 1; x + 7592, 1; x + 7596, 1; x + 7605, 1; x + 7619, 1; x + 7624, 1; x + 7628, 1; x + 7640, 1; x + 7681, 1; x + 7684, 1; x + 7699, 1; x + 771 1, 1; x + 7723, 1; x + 7724, 1; x + 7725, 1; x + 7735, 1; x + 7751, 1; x + 7 766, 1; x + 7771, 1; x + 7779, 1; x + 7784, 1; x + 7785, 1; x + 7790, 1; x + 7800, 1; x + 7806, 1; x + 7814, 1; x + 7846, 1; x + 7866, 1; x + 7878, 1; x + 7885, 1; x + 7899, 1; x + 7911, 1; x + 7929, 1; x + 7937, 1; x + 7954, 1; x + 7988, 1; x + 8000, 1; x + 8016, 1; x + 8022, 1; x + 8024, 1; x + 8038, 1; x + 8051, 1; x + 8054, 1; x + 8062, 1; x + 8067, 1; x + 8071, 1; x + 8080 , 1; x + 8095, 1; x + 8113, 1; x + 8122, 1; x + 8136, 1; x + 8144, 1; x + 81 51, 1; x + 8170, 1; x + 8176, 1; x + 8186, 1; x + 8190, 1; x + 8195, 1; x + 8239, 1; x + 8257, 1; x + 8307, 1; x + 8308, 1; x + 8314, 1; x + 8328, 1; x + 8330, 1; x + 8342, 1; x + 8345, 1; x + 8347, 1; x + 8348, 1; x + 8360, 1; x + 8400, 1; x + 8420, 1; x + 8443, 1; x + 8449, 1; x + 8452, 1; x + 8464, 1 ; x + 8468, 1; x + 8474, 1; x + 8481, 1; x + 8484, 1; x + 8494, 1; x + 8496, 1; x + 8520, 1; x + 8524, 1; x + 8531, 1; x + 8536, 1; x + 8545, 1; x + 856 6, 1; x + 8581, 1; x + 8611, 1; x + 8619, 1; x + 8620, 1; x + 8635, 1; x + 8 665, 1; x + 8682, 1; x + 8700, 1; x + 8711, 1; x + 8717, 1; x + 8753, 1; x + 8755, 1; x + 8761, 1; x + 8774, 1; x + 8778, 1; x + 8787, 1; x + 8794, 1; x + 8809, 1; x + 8820, 1; x + 8823, 1; x + 8835, 1; x + 8838, 1; x + 8840, 1; x + 8841, 1; x + 8871, 1; x + 8881, 1; x + 8882, 1; x + 8896, 1; x + 8914, 1; x + 8921, 1; x + 8929, 1; x + 8930, 1; x + 8945, 1; x + 8946, 1; x + 8951 , 1; x + 8957, 1; x + 8972, 1; x + 9004, 1; x + 9011, 1; x + 9013, 1; x + 90 21, 1; x + 9051, 1; x + 9057, 1; x + 9060, 1; x + 9068, 1; x + 9084, 1; x + 9089, 1; x + 9118, 1; x + 9126, 1; x + 9135, 1; x + 9168, 1; x + 9169, 1; x + 9173, 1; x + 9175, 1; x + 9195, 1; x + 9199, 1; x + 9202, 1; x + 9224, 1; x + 9233, 1; x + 9244, 1; x + 9247, 1; x + 9261, 1; x + 9269, 1; x + 9270, 1 ; x + 9272, 1; x + 9282, 1; x + 9307, 1; x + 9332, 1; x + 9342, 1; x + 9343, 1; x + 9344, 1; x + 9348, 1; x + 9349, 1; x + 9360, 1; x + 9363, 1; x + 938 9, 1; x + 9395, 1; x + 9416, 1; x + 9449, 1; x + 9457, 1; x + 9461, 1; x + 9 462, 1; x + 9489, 1; x + 9513, 1; x + 9520, 1; x + 9559, 1; x + 9572, 1; x + 9577, 1; x + 9600, 1; x + 9615, 1; x + 9617, 1; x + 9646, 1; x + 9652, 1; x + 9656, 1; x + 9663, 1; x + 9667, 1; x + 9687, 1; x + 9689, 1; x + 9694, 1; x + 9696, 1; x + 9714, 1; x + 9754, 1; x + 9757, 1; x + 9761, 1; x + 9804, 1; x + 9806, 1; x + 9811, 1; x + 9828, 1; x + 9834, 1; x + 9839, 1; x + 9847 , 1; x + 9855, 1; x + 9860, 1; x + 9916, 1; x + 9929, 1; x + 9951, 1; x + 99 55, 1; x + 9982, 1; x + 9988, 1; x + 9996, 1; x + 9998, 1; x + 10013, 1; x + 10014, 1; x + 10029, 1; x + 10032, 1; x + 10036, 1; x + 10058, 1; x + 10076 , 1; x + 10077, 1; x + 10080, 1; x + 10104, 1; x + 10118, 1; x + 10125, 1; x + 10138, 1; x + 10141, 1; x + 10179, 1; x + 10221, 1; x + 10224, 1; x + 102 35, 1; x + 10243, 1; x + 10254, 1; x + 10268, 1; x + 10344, 1; x + 10345, 1; x + 10347, 1; x + 10353, 1; x + 10361, 1; x + 10362, 1; x + 10381, 1; x + 1 0388, 1; x + 10397, 1; x + 10398, 1; x + 10407, 1; x + 10421, 1; x + 10423, 1; x + 10440, 1; x + 10447, 1; x + 10453, 1; x + 10463, 1; x + 10485, 1; x + 10487, 1; x + 10499, 1; x + 10506, 1; x + 10526, 1; x + 10533, 1; x + 10545 , 1; x + 10552, 1; x + 10555, 1; x + 10568, 1; x + 10583, 1; x + 10584, 1; x + 10588, 1; x + 10595, 1; x + 10602, 1; x + 10608, 1; x + 10631, 1; x + 106 69, 1; x + 10699, 1; x + 10716, 1; x + 10734, 1; x + 10753, 1; x + 10754, 1; x + 10759, 1; x + 10763, 1; x + 10767, 1; x + 10771, 1; x + 10783, 1; x + 1 0808, 1; x + 10821, 1; x + 10844, 1; x + 10872, 1; x + 10880, 1; x + 10883, 1; x + 10886, 1; x + 10891, 1; x + 10897, 1; x + 10900, 1; x + 10916, 1; x + 10918, 1; x + 10939, 1; x + 10945, 1; x + 10962, 1; x + 10964, 1; x + 10975 , 1; x + 11007, 1; x + 11009, 1; x + 11010, 1; x + 11014, 1; x + 11024, 1; x + 11034, 1; x + 11038, 1; x + 11041, 1; x + 11048, 1; x + 11053, 1; x + 110 63, 1; x + 11066, 1; x + 11071, 1; x + 11081, 1; x + 11111, 1; x + 11113, 1; x + 11124, 1; x + 11129, 1; x + 11153, 1; x + 11158, 1; x + 11164, 1; x + 1 1169, 1; x + 11194, 1; x + 11197, 1; x + 11232, 1; x + 11249, 1; x + 11251, 1; x + 11259, 1; x + 11260, 1; x + 11274, 1; x + 11275, 1; x + 11295, 1; x + 11307, 1; x + 11309, 1; x + 11345, 1; x + 11366, 1; x + 11379, 1; x + 11385 , 1; x + 11408, 1; x + 11410, 1; x + 11415, 1; x + 11424, 1; x + 11444, 1; x + 11445, 1; x + 11463, 1; x + 11475, 1; x + 11498, 1; x + 11511, 1; x + 115 20, 1; x + 11522, 1; x + 11538, 1; x + 11572, 1; x + 11573, 1; x + 11607, 1; x + 11641, 1; x + 11653, 1; x + 11667, 1; x + 11675, 1; x + 11677, 1; x + 1 1710, 1; x + 11711, 1; x + 11722, 1; x + 11749, 1; x + 11759, 1; x + 11777, 1; x + 11779, 1; x + 11783, 1; x + 11787, 1; x + 11823, 1; x + 11825, 1; x + 11826, 1; x + 11832, 1; x + 11839, 1; x + 11841, 1; x + 11851, 1; x + 11864 , 1; x + 11872, 1; x + 11873, 1; x + 11877, 1; x + 11883, 1; x + 11897, 1; x + 11912, 1; x + 11914, 1; x + 11924, 1; x + 11925, 1; x + 11943, 1; x + 119 46, 1; x + 11951, 1; x + 11996, 1; x + 12050, 1; x + 12073, 1; x + 12077, 1; x + 12085, 1; x + 12096, 1; x + 12100, 1; x + 12109, 1; x + 12119, 1; x + 1 2139, 1; x + 12143, 1; x + 12150, 1; x + 12164, 1; x + 12217, 1; x + 12221, 1; x + 12226, 1; x + 12229, 1; x + 12239, 1; x + 12265, 1; x + 12268, 1; x + 12269, 1; x + 12281, 1; x + 12282, 1] [1 1 1] [1 1 1] [1 3 27] [1 1 1] [1 2 4 5 15 15 52 131 373 400] [4 1 1 1 1 1 1 1 1 1] [Mod(1, 41), Mod(3, 41), Mod(9, 41), Mod(14, 41), Mod(27, 41), Mod(32, 41), Mod(38, 41), Mod(40, 41)]~ [Mod(1, 5), Mod(2, 5)]~ []~ [ Mod(1, 2)*x 1] [Mod(1, 2)*x + Mod(1, 2) 2] [Mod(0, 2) 1] matrix(0,2) matrix(0,2) matrix(0,2) [1 1] [1 2] [2 1] [Mod(1, 2)*x^3 + Mod(1, 2)*x^2 + Mod(1, 2)*x 1] [ Mod(1, 2)*x + Mod(1, 2) 2] [ Mod(1, 2)*x^2 + Mod(1, 2)*x 1] [Mod(1, 2)*x^2 + Mod(1, 2)*x + Mod(1, 2) 2] [Mod(1, 7), Mod(2, 7), Mod(3, 7), Mod(5, 7), Mod(6, 7)]~ []~ [Mod(0, 18446744073709551629)]~ [Mod(9223372036854775814, 18446744073709551629)]~ [Mod(1, 18446744073709551629)*x + Mod(2370518075556110396, 18446744073709551 629) 1] [Mod(1, 18446744073709551629)*x + Mod(16076225998153441233, 1844674407370955 1629) 1] [1 1] [1 1] [2 1] [Mod(1, 18446744073709551629)*x^2 + Mod(2370518075556110396, 184467440737095 51629) 1] [Mod(1, 18446744073709551629)*x^2 + Mod(16076225998153441233, 18446744073709 551629) 1] [2 1] [2 1] [4 1] [Mod(1, 18446744073709551629)*x + Mod(2370518075556110396, 18446744073709551 629) 1] [Mod(1, 18446744073709551629)*x + Mod(16076225998153441233, 1844674407370955 1629) 1] [Mod(0, 18446744073709551629) 1] matrix(0,2) matrix(0,2) matrix(0,2) 1 0 0 [Mod(1, 100000000000000000039)*x + Mod(1, 100000000000000000039) 2] *** at top-level: polrootsmod(x^3-1,2^101-1) *** ^-------------------------- *** polrootsmod: not a prime number in polrootsmod: 2535301200456458802993406410751. *** at top-level: polrootsmod(x^10-1,1023) *** ^------------------------ *** polrootsmod: not a prime number in polrootsmod: 1023. *** at top-level: polrootsmod(Pol(0),p) *** ^--------------------- *** polrootsmod: zero polynomial in rootmod. *** at top-level: polrootsmod(Pol(0),2) *** ^--------------------- *** polrootsmod: zero polynomial in rootmod. *** at top-level: factormod(x,0) *** ^-------------- *** factormod: not a prime number in factormod: 0. *** at top-level: factormod(x^3+1,[y^2+1,2]) *** ^-------------------------- *** factormod: not an irreducible polynomial in FpX_ffintersect: y^2 + 1. *** at top-level: factormod(x^3+1,[y^2+1,5]) *** ^-------------------------- *** factormod: not an irreducible polynomial in FpX_ffintersect: y^2 + 1. Total time spent: 81 pari-2.11.2/src/test/32/arith0000644000175000017500000000004412314242551014177 0ustar billbill0 4162330905307 Total time spent: 4 pari-2.11.2/src/test/32/ellanal0000644000175000017500000000172013460025361014503 0ustar billbill[0, 0.25384186085591068433775892335090946104] [1, 0.30599977383405230182048368332167647445] [2, 1.5186330005768535404603852157894440381] [3, 10.391099400715804138751850510360917070] [5, 9997.0334671722554999496820788093288459] [-339/16, 691/64] [-3, 12] [69648970982596494254458225/166136231668185267540804, 5389624350896046150780 04307258785218335/67716816556077455999228495435742408] [553/17424, 25469/2299968] 31 [1317254400, 19916886528000] 0 2.8053554406276820682921020105298729343 98.900778292211279593460469548777701094 1.5186330005768535404603852157894440381 0 2.80535544062768206829210201052987293427393419289431401051573873877896370606 9444052334712747100820315923332165307854 98.9007782922112795934604695487777010937256627866976192105130347193178645983 4656024843050255154457301289878660746147 1.51863300057685354046038521578944403815619503298984870317161018509598214549 5561104880431870004657718333754298413639 2 2 4 8 1 2 72 1/5 3/2 138240 Total time spent: 2097 pari-2.11.2/src/test/32/alglattices0000644000175000017500000001172013326135265015376 0ustar billbill *** Warning: new stack size = 100000000 (95.367 Mbytes). 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4897369/8503056 [[48686, 0, 12094, 0, 64, 4654, 2480, 46456; 0, 48686, 0, 12094, 39440, 4409 4, 19034, 16804; 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 2, 0, 0, 0; 0, 0, 0, 0, 0, 2, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1], 1/6] [[21567898, 0, 3274056, 0, 10918080, 13754198, 6566870, 15552536; 0, 2156789 8, 0, 3274056, 4977580, 18731778, 303752, 15856288; 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 2, 0, 0, 0; 0, 0, 0, 0, 0, 2, 0, 0; 0, 0 , 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1], 1/6] [[14619, 0, 7817, 4873, 14379, 10635, 13499, 1326; 0, 14619, 9746, 7817, 290 7, 243, 8846, 7124; 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 3, 0, 1, 2; 0, 0, 0, 0, 0, 3, 2, 0; 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1], 1] [[21567898, 0, 3274056, 0, 10918080, 13754198, 6566870, 15552536; 0, 2156789 8, 0, 3274056, 4977580, 18731778, 303752, 15856288; 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 2, 0, 0, 0; 0, 0, 0, 0, 0, 2, 0, 0; 0, 0 , 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1], 1/60] [[14619, 0, 7817, 4873, 14379, 10635, 13499, 1326; 0, 14619, 9746, 7817, 290 7, 243, 8846, 7124; 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 3, 0, 1, 2; 0, 0, 0, 0, 0, 3, 2, 0; 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1], 1/10] [[1606638, 0, 705947, 535546, 1168464, 438174, 849493, 1545605; 0, 1606638, 1071092, 705947, 146058, 584232, 233498, 477025; 0, 0, 24343, 0, 0, 0, 24311 , 22015; 0, 0, 0, 24343, 0, 0, 19720, 22047; 0, 0, 0, 0, 146058, 0, 85279, 4 8686; 0, 0, 0, 0, 0, 146058, 48686, 133965; 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1], 3/24343] [[22, 0, 7, 0, 0, 0, 0, 0; 0, 22, 0, 7, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 22, 0, 7, 0; 0, 0, 0, 0, 0, 22, 0, 7; 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1], 9] 1 1 [23804, 219387, -5/6, 1/6, 23/3, 2/3, 0, 1/6]~ make integral 1 1 1 1 1 integral subalg [1 0] [0 0] [0 1/2] [0 0] 1 [1 0] [0 0] [0 1] [0 0] bug in subalg when first vector is not 1 1 image of lifts in algsimpledec 1 1 1 1 1 1 1 1 1 1 1 1 1 1 lattices in al_CSA 1 1 1 examples from docu 4 64 4 64 0 1 4 1 0 1 [-1, -2, -1, 1, 2, 0, 1, 1]~ 1 1 29584 0 0 0 1 0 1 0 bad inputs *** at top-level: alglathnf(al,0) *** ^--------------- *** alglathnf: incorrect type in alglathnf (t_INT). *** at top-level: alglathnf(al,Mat([0,0,0,0,0,0,0,0])) *** ^------------------------------------ *** alglathnf: inconsistent dimensions in alglathnf. *** at top-level: alglathnf(al,[0;0;0;0;0;0;0;0]) *** ^------------------------------- *** alglathnf: inconsistent dimensions in alglathnf. [] *** at top-level: alglathnf(al,fakemat) *** ^--------------------- *** alglathnf: incorrect type in alglathnf (t_VEC). *** at top-level: alglathnf(al,matid(8)*0) *** ^------------------------ *** alglathnf: impossible inverse in alglathnf [m does not have full rank]: [0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0]. *** at top-level: alglathnf(al,fakemat) *** ^--------------------- *** alglathnf: impossible inverse in alglathnf [m does not have full rank]: [0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 1]. *** at top-level: lat=alglathnf(al,matconcat([mt*0,mt*0])) *** ^------------------------------------ *** alglathnf: inconsistent dimensions in alglathnf. *** at top-level: lat1=alglathnf(al,a) *** ^--------------- *** alglathnf: inconsistent dimensions in alglathnf. *** at top-level: print(alglatelement(al,lat1,col~)) *** ^---------------------------- *** alglatelement: incorrect type in alglatelement (t_VEC). *** at top-level: alglatmul(al,a,b) *** ^----------------- *** alglatmul: incorrect type in alglatmul [one of lat1, lat2 has to be a lattice] (t_COL). *** at top-level: algmakeintegral(mt) *** ^------------------- *** algmakeintegral: incorrect type in algmakeintegral (t_VEC). *** at top-level: algmakeintegral(mt) *** ^------------------- *** algmakeintegral: incorrect type in algmakeintegral (t_VEC). *** at top-level: algmakeintegral('x,1) *** ^--------------------- *** algmakeintegral: incorrect type in algmakeintegral (t_POL). *** at top-level: alglatmul(al,lat1,[matdiagonal([1,1,0,1,1,1,1, *** ^---------------------------------------------- *** alglatmul: incorrect type in checklat [please apply alglathnf()] (t_VEC). Total time spent: 1220 pari-2.11.2/src/test/32/ellnf0000644000175000017500000002000013457566441014202 0ustar billbill1 [Mod(5/2*t^2 - 3/8*t + 7/4, t^3 - 2), Mod(3/8*t^2 - 67/16*t - 123/16, t^3 - 2)] [Mod(21112/25281*t^2 + 33953/25281*t + 54736/25281, t^3 - 2), Mod(2829824/13 39893*t^2 + 5014079/1339893*t + 5473088/1339893, t^3 - 2)] [Mod(-t, t^3 - 2), Mod(t, t^3 - 2)] [] 3*x^4 + Mod(6*t + 6, t^3 - 2)*x^2 + Mod(-12*t - 24, t^3 - 2)*x + Mod(-t^2 - 2*t - 1, t^3 - 2) [0, 0, 0, Mod(-3*t^2 + 5184*t, t^3 - 2), Mod(-6912*t^2 + 5971968*t + 4, t^3 - 2)] [] [Mod(0, 5), Mod(0, 5), Mod(0, 5), Mod(4, 5), Mod(0, 5), Mod(0, 5), Mod(3, 5) , Mod(0, 5), Mod(4, 5), Mod(3, 5), Mod(0, 5), Mod(4, 5), Mod(3, 5), Vecsmall ([3]), [5, [4, 0, [1, 0, 0, 0]]], [0, 0, 0, 0]] [0, 0, [1/289, 0, 0, 0], 1] [-1, -4, 6] [6, 18, 12] [[6], [18], [6, 2]] 6 [1, 0, 0, -2, -1, 0, 0, 0, -2, 0, 0, 0, -3, 0, 0, 4, 6, 0, 0, 2] [1, 0, 0, -2, -1, 0, 0, 0, -2, 0, 0, 0, -3, 0, 0, 4, 6, 0, 0, 2] [[65, 18; 0, 1], [1, 0, 0, 0], 2, [[5, [-2, 1]~, 1, 1, [2, -1; 1, 2]], 1; [1 3, [5, 1]~, 1, 1, [-5, -1; 1, -5]], 1], [[1, 5, [1, 0, 0, 0], 1], [1, 6, [1, 0, 0, 0], 2]]] [[65, 18; 0, 1], [1/17, 0, 0, 0], 2, [[5, [-2, 1]~, 1, 1, [2, -1; 1, 2]], 1; [13, [5, 1]~, 1, 1, [-5, -1; 1, -5]], 1], [[1, 5, [1, 0, 0, 0], 1], [1, 6, [1, 0, 0, 0], 2]]] [[65, 18; 0, 1], [1, 0, 0, 0], 2, [[5, [-2, 1]~, 1, 1, [2, -1; 1, 2]], 1; [1 3, [5, 1]~, 1, 1, [-5, -1; 1, -5]], 1], [[1, 5, [1, 0, 0, 0], 1], [1, 6, [1, 0, 0, 0], 2]]] [-1, [5]] [0, [10]] [-4, [30]] [5, [5], [[0, x + 1]]] [8, [8], [[2*x + 2, 1]]] [209844281729657331, [209844281729657331], [[40177873431401432, 112434066940 834542]]] [Mod(4*a + 29580, a^2 - 870), Mod(-56550*a - 218426550, a^2 - 870), Mod(5220 *a + 24220800, a^2 - 870), Mod(433703700*a - 321905785500, a^2 - 870), Mod(3 0478152852000*a + 1290691561617000, a^2 - 870)] [Mod(4*a + 29580, a^2 - 870), Mod(-56550*a - 218426550, a^2 - 870), Mod(5220 *a + 24220800, a^2 - 870), Mod(433703700*a - 321905785500, a^2 - 870), Mod(3 0478152852000*a + 1290691561617000, a^2 - 870)] [1/20880, 0, 0, 0] [Mod(0, a^2 - 870), Mod(0, a^2 - 870), Mod(0, a^2 - 870), Mod(a, a^2 - 870), Mod(1, a^2 - 870)] [Mod(1/20880*a, a^2 - 870), Mod(-1/501120*a - 41/167040, a^2 - 870), Mod(-1/ 10440*a - 17/24, a^2 - 870), Mod(5011/3487795200*a + 2077/12026880, a^2 - 87 0)] [0, 1]~ [1, 0, 0, 0] [[64000001644800020229280152976800751644426376663403572812780612976355750337 16572028, 0; 0, 640000016448000202292801529768007516444263766634035728127806 1297635575033716572028], [1, 0, 0, 0], 6, [[2, [0, 1]~, 2, 1, [0, 870; 1, 0] ], 4; [10000000019, [10000000019, 0]~, 1, 2, 1], 2; [20000000089, [200000000 89, 0]~, 1, 2, 1], 2; [40000000520000003750000013929460019555447, [400000005 20000003750000013929460019555447, 0]~, 1, 2, 1], 1], [[4, -1, [1, 1, 1, Mod( 1/435*a + 1, a^2 - 870)], 1], [2, -4, [1, 0, 0, 0], 3], [2, -3, [1, 0, 0, 0] , 2], [1, 5, [1, 0, 0, 0], 1]]] [[16000000182400000866400002194880003127714802377096080752773084, 0; 0, 1600 0000182400000866400002194880003127714802377096080752773084], [1, 0, 0, 0], 3 , [[2, [0, 1]~, 2, 1, [0, 870; 1, 0]], 4; [7, [-3, 1]~, 1, 1, [3, 870; 1, 3] ], 1; [7, [3, 1]~, 1, 1, [-3, 870; 1, -3]], 1; [103, [-47, 1]~, 1, 1, [47, 8 70; 1, 47]], 1; [103, [47, 1]~, 1, 1, [-47, 870; 1, -47]], 1; [1993, [-685, 1]~, 1, 1, [685, 870; 1, 685]], 1; [1993, [685, 1]~, 1, 1, [-685, 870; 1, -6 85]], 1; [10000000019, [10000000019, 0]~, 1, 2, 1], 2; [27836679629744327661 656297107448887, [27836679629744327661656297107448887, 0]~, 1, 2, 1], 1], [[ 4, -1, [1, 1, 1, Mod(1/435*a + 1, a^2 - 870)], 1], [1, 5, [1, 0, 0, 0], 1], [1, 5, [1, 0, 0, 0], 1], [1, 5, [1, 0, 0, 0], 1], [1, 5, [1, 0, 0, 0], 1], [ 1, 5, [1, 0, 0, 0], 1], [1, 5, [1, 0, 0, 0], 1], [2, -4, [1, 0, 0, 0], 3], [ 1, 5, [1, 0, 0, 0], 1]]] [1]~ [1]~ [1, [1, 0, 0, 0], 1, matrix(0,2), []] [[28, 0, 24; 0, 28, 16; 0, 0, 4], [1, 0, 0, 0], 6, [[2, [2, 0, 0]~, 1, 3, 1] , 2; [7, [1, 4, 0]~, 3, 1, [-2, 4, 3; 1, -2, 2; 2, 3, -3]], 2], [[2, -4, [1, Mod(1/8*z^2 + 3/4*z - 2, z^3 - 4*z^2 - 32*z + 64), Mod(1/16*z^2 + 1/4*z - 2 , z^3 - 4*z^2 - 32*z + 64), Mod(3/8*z^2 + z, z^3 - 4*z^2 - 32*z + 64)], 3], [2, -1, [1, 0, 0, 0], 2]]] [Mod(1, a^2 - 17), Mod(2, a^2 - 17), Mod(1, a^2 - 17), Mod(-66585651*a - 274 539700, a^2 - 17), Mod(-600624098797*a - 2476436600713, a^2 - 17)] [Mod(-4*a + 32, a^2 - 17), Mod(-192*a + 972, a^2 - 17), Mod(-2*a + 16, a^2 - 17), Mod(-6688*a + 29440, a^2 - 17)] [Mod(a, a^2 - 7), Mod(0, a^2 - 7), Mod(0, a^2 - 7), Mod(-9, a^2 - 7), Mod(0, a^2 - 7)] [2, -9, Mod(a, a^2 - 7), 0] 2268 2268 54 54 1 1 [9, [3, 3], [[Mod(-2, a^2 - a + 1), Mod(-3*a + 2, a^2 - a + 1)], [Mod(0, a^2 - a + 1), Mod(-a + 2, a^2 - a + 1)]]] [9, [3, 3], [[Mod(-9/4, a^2 - a + 1), Mod(-3*a + 1, a^2 - a + 1)], [Mod(-1/4 , a^2 - a + 1), Mod(-a + 2, a^2 - a + 1)]]] 1.3211372891561117704694923724477608437 1.3211372891561117704694923724477608437 [[3.2454018605082579620032350562420879904 + 1.111397817128820959029052707850 2348351*I, 1.6668632098170830019533312582971884208 - 0.486801726858514320058 78432460464226233*I]] [[3.2454018605082579620032350562420879904 + 1.111397817128820959029052707850 2348351*I, 1.6668632098170830019533312582971884208 - 0.486801726858514320058 78432460464226233*I]] [[3.3428093839915903612041140523628625748 - 0.475484699340869907792393249264 58939281*I, 1.8377117333570711477796051427229973887 + 0.56107170810617604791 234131325616570861*I]] [[3.3428093839915903612041140523628625748 - 0.475484699340869907792393249264 58939281*I, 1.8377117333570711477796051427229973887 + 0.56107170810617604791 234131325616570861*I]] [3.4324153628883011196857987711414818098] [3.4324153628883011196857987711414818098] [[1.4331498327481794699384519990689978958 E-7, -8.90022802078150157827725183 62365500525 E-8*I], [0.14948961573271587735193776533155518448 - 0.0364920854 87651217049327378480123927290*I, 0.025252400424922004835631005650622494292 - 0.077154497013473286414108150293274820223*I], [71131.7121340703744044981170 95975388071 + 31444.727244680220552887076625190441805*I, 19527.9820807200880 34284003590898052213 - 44174.617547686477264962272970191397890*I]] 81 2 1 [3, [3], [[Mod(75, a^2 - a - 22), Mod(-53*a + 276, a^2 - a - 22)]]] 0.029243259302535776270985513029724899123 0.029243259302535776270985513029724899123 0.029243259302535776270985513029724899123 [[0.36275979223366389123527228531236021016, 0.181379896116831945617636142656 18010508 - 0.98792397441408998992096074875409751608*I], [3.42226903540115887 19775751832202902106, 1.7111345177005794359887875916101451053 - 0.1047197318 4863928069787984196947537734*I]] [[9.0690068978198926646497340170387502852, 4.5345034489099463323248670085193 751426 - 7.3776203664257126727668408543261959548*I], [-196.67027839726644769 316107917450672666, -98.335139198633223846580539587253363331 + 7.85398337930 14079898062379028921755190*I]] [0.35837909570111076671922166110255577349, 0.3583790957011107667192216611025 5577349] 89 4 1 [10, [10], [[Mod(a^2, a^3 - a^2 + 1), Mod(-2*a^2 + 1, a^3 - a^2 + 1)]]] 0.33753547062081148560344962283967451356 [[3.5491769254598924808129220481653238934, -2.542655659111084982919736837317 6365643*I], [1.9499083977009059175943781181149776030 + 2.8338954531694537916 413166973195484122*I, 3.3837615464515224781027253345320644787 - 0.9298685032 8561627019201162339975284811*I]] [[0.67178899867737769984191766676172801075, 1.289047377476443975073193849195 0519406*I], [0.59569675561968713991027058840738833243 - 0.784496667533226302 75597445878594696512*I, 0.94830798409984778856147508826172748052 + 0.1986300 0529303555671904142603584000601*I]] [9.0243347947070770520143614245496848017, 11.4023848644128046507836413961968 47706] [4 0] [0 4] [1 0] [0 1] 10351 [27 0] [ 0 27] 0 2.6776858460184521884180352812357212922 -1 2.4789169415611595631185019889765914992 -1 2.7983467075796708218369484107296525132 -1 0.94644710225720189761360064296904262845 1.1306942438544073283221551692300185759 1 1.9118646495040059117224489068629589287 2.3989895152878390668263655479635937156 1 1.1553619177287290907122191262256779900 1.8108719765738961774239981105279304803 1 0.21953076079603813973615927742358668802 -1 0.047510692468775579593867285193171421867 -1 0.35764851040087134693652331655969825371 -1 0.092936445769006934770949560984704427756 -1 0 -128 Total time spent: 3348 pari-2.11.2/src/test/32/multiif0000644000175000017500000000014013201017466014537 0ustar billbill1 1 1 1 1 1 default 2 2 2 2 default default 3 3 default default default 1 2 Total time spent: 4 pari-2.11.2/src/test/32/modpr0000644000175000017500000000665413326135265014235 0ustar billbill *** at top-level: nfeltmulmodpr(nfinit(x),x,x,1) *** ^------------------------------ *** nfeltmulmodpr: incorrect type in checkprid (t_INT). [0, 1, 1, error("inconsistent variables in poltobasis, z != y."), 0, error(" incorrect type in Rg_to_ff (t_COL).")] y^2 + 1: [1, [1, 1], [2, [1, 1]~, 2, 1, [1, -1; 1, 1]]]~ *[1, 1]: error("impossible inverse in F2xq_inv: 0.") 0 *[1, 2]: 0 0 *[1, 3]: 0 0 *[1, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *[2, 2]: 1 1 *[2, 3]: 1 1 *[2, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *[3, 3]: 1 1 *[3, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *[4, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *1: [0, 0]~ *2: [1, 0]~ *3: [1, 0]~ *4: error("inconsistent variables in poltobasis, z != y.") *5: [0, 0]~ *6: error("incorrect type in Rg_to_ff (t_COL).") [0, error("impossible inverse in Fl_inv: Mod(0, 3)."), y, error("inconsisten t variables in poltobasis, z != y."), error("impossible inverse in Rg_to_ff: Mod(0, 3)."), error("incorrect type in Rg_to_ff (t_COL).")] y^2 + 1: [1, [1, 0; 0, 1], [3, [3, 0]~, 1, 2, 1], y^2 + 1]~ *[1, 1]: error("impossible inverse in Flxq_inv: 0.") 0 *[1, 2]: 0 0 *[2, 2]: 1 2 *1: [0, 0]~ *2: error("impossible inverse in Fl_inv: Mod(0, 3).") *3: [0, 1]~ *4: error("inconsistent variables in poltobasis, z != y.") *5: error("impossible inverse in Rg_to_ff: Mod(0, 3).") *6: error("incorrect type in Rg_to_ff (t_COL).") [0, error("impossible inverse in Fl_inv: Mod(0, 3)."), 0, error("inconsisten t variables in poltobasis, z != y."), error("incorrect type in Rg_to_ff (t_C OL)."), error("impossible inverse in Rg_to_ff: Mod(0, 3).")] y^3 - 9: [1, [1, 0, 0], [3, [0, 1, 0]~, 3, 1, [0, 3, 0; 0, 0, 3; 1, 0, 0]]]~ *[1, 1]: error("impossible inverse in Flxq_inv: 0.") 0 *[1, 2]: error("impossible inverse in Flxq_inv: 0.") 0 *[2, 2]: error("impossible inverse in Flxq_inv: 0.") 0 *1: [0, 0, 0]~ *2: error("impossible inverse in Fl_inv: Mod(0, 3).") *3: [0, 0, 0]~ *4: error("inconsistent variables in poltobasis, z != y.") *5: error("incorrect type in Rg_to_ff (t_COL).") *6: error("impossible inverse in Rg_to_ff: Mod(0, 3).") [0, 1, y, error("inconsistent variables in poltobasis, z != y."), error("inc orrect type in Rg_to_ff (t_COL)."), 0] y^3 - 9: [[0, -1, -1]~, [1, 1, 0; 0, 1, 1], [2, [3, 3, 1]~, 1, 2, [1, 3, 0; 0, 1, 3; 1, 0, 1]], y^2 + y + 1]~ *[1, 1]: error("impossible inverse in F2xq_inv: 0.") 0 *[1, 2]: 0 0 *[1, 3]: 0 0 *[1, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *[2, 2]: 1 1 *[2, 3]: y + 1 y *[2, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *[3, 3]: 1 y + 1 *[3, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *[4, 4]: error("impossible inverse in F2xq_inv: 0.") 0 *1: [0, 0, 0]~ *2: [1, 0, 0]~ *3: [0, 0, 1]~ *4: error("inconsistent variables in poltobasis, z != y.") *5: error("incorrect type in Rg_to_ff (t_COL).") *6: [0, 0, 0]~ y [1, 0]~ [x + 1 3] 1 [1, 1]~ [;] [0, 1]~ [1 1] [1 1] [1] [1] *** at top-level: LI(matsolve(m,v)) *** ^-------------- *** matsolve: impossible inverse in gauss: [1, 1; 1, 1]. *** at top-level: LI(matsolve(m,m)) *** ^-------------- *** matsolve: impossible inverse in gauss: [1, 1; 1, 1]. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]~ *** at top-level: nfmodpr(nfinit(x),[],[]~) *** ^------------------------- *** nfmodpr: incorrect type in checkprid (t_COL). Total time spent: 142 pari-2.11.2/src/test/32/member0000644000175000017500000002775513326135265014370 0ustar billbill.pol: x .a1: 0 .a2: 0 .a3: 0 .a4: 0 .a6: 0 NF .codiff: [1, 553/1105; 0, 1/1105] .diff: [1105, 553; 0, 1] .disc: 1105 .index: 2 .nf: [y^2 - 1105, [2, 0], 1105, 2, [[1, -17.12077013859466140231529077105260 9448; 1, 16.120770138594661402315290771052609448], [1, -17.12077013859466140 2315290771052609448; 1, 16.120770138594661402315290771052609448], [1, -17; 1 , 16], [2, -1; -1, 553], [1105, 553; 0, 1], [553, 1; 1, 2], [1105, [553, 276 ; 1, 552]], [5, 13, 17]], [-33.241540277189322804630581542105218897, 33.2415 40277189322804630581542105218897], [2, y - 1], [1, 1; 0, 2], [1, 0, 0, 276; 0, 1, 1, -1]] .pol: y^2 - 1105 .r1: 2 .r2: 0 .roots: [-33.241540277189322804630581542105218897, 33.2415402771893228046305 81542105218897] .sign: [2, 0] .t2: [2, -1.0000000000000000000000000000000000000; -1.0000000000000000000000 000000000000000, 553.00000000000000000000000000000000000] .zk: [1, 1/2*y - 1/2] NF chvar *** nfinit: Warning: non-monic polynomial. Result of the form [nf,c]. .codiff: [1/2, 0; 0, 1/4] .diff: [4, 0; 0, 2] .disc: -8 .index: 1 .nf: [y^2 + 2, [0, 1], -8, 1, [Mat([1, 0.E-57 + 1.41421356237309504880168872 42096980786*I]), [1, 1.4142135623730950488016887242096980786; 1, -1.41421356 23730950488016887242096980786], [1, 1; 1, -1], [2, 0; 0, -4], [4, 0; 0, 2], [2, 0; 0, -1], [2, [0, -2; 1, 0]], [2]], [0.E-57 + 1.41421356237309504880168 87242096980786*I], [1, y], [1, 0; 0, 1], [1, 0, 0, -2; 0, 1, 1, 0]] .pol: y^2 + 2 .r1: 0 .r2: 1 .roots: [0.E-57 + 1.4142135623730950488016887242096980786*I] .sign: [0, 1] .t2: [2, 0.E-57; 0.E-57, 4.0000000000000000000000000000000000000] .zk: [1, y] BNF .bnf: [[2, 0; 0, 2], [1, 1, 0; 1, 0, 1], [10.9503854058256053302677508250179 37393 + 3.1415926535897932384626433832795028842*I; -10.950385405825605330267 750825017937393 + 6.2831853071795864769252867665590057684*I], [-2.8070134016 636593080928506577483570863, -6.4656286076812397829259659980344686072, 6.314 0644011531557847583424971265245465, 0, 0; 2.80701340166365930809285065774835 70863 + 3.1415926535897932384626433832795028842*I, 6.46562860768123978292596 59980344686072 + 3.1415926535897932384626433832795028842*I, -6.3140644011531 557847583424971265245465, 0, 0], [[2, [-1, 1]~, 1, 1, [0, 276; 1, -1]], [3, [0, 2]~, 1, 1, [-1, -276; -1, 0]], [5, [1, 2]~, 2, 1, [1, 552; 2, -1]], [2, [2, 1]~, 1, 1, [1, 276; 1, 0]], [3, [2, 2]~, 1, 1, [0, -276; -1, 1]]], 0, [y ^2 - 1105, [2, 0], 1105, 2, [[1, -17.120770138594661402315290771052609448; 1 , 16.120770138594661402315290771052609448], [1, -17.120770138594661402315290 771052609448; 1, 16.120770138594661402315290771052609448], [1, -17; 1, 16], [2, -1; -1, 553], [1105, 553; 0, 1], [553, 1; 1, 2], [1105, [553, 276; 1, 55 2]], [5, 13, 17]], [-33.241540277189322804630581542105218897, 33.24154027718 9322804630581542105218897], [2, y - 1], [1, 1; 0, 2], [1, 0, 0, 276; 0, 1, 1 , -1]], [[4, [2, 2], [[2, 0; 0, 1], [3, 1; 0, 1]]], 10.950385405825605330267 750825017937393, 1, [2, -1], [857*y - 28488]], [[-1, 0; 0, -1], [[0, 0], [0, 0]], [[2.8070134016636593080928506577483570863, -2.807013401663659308092850 6577483570863 - 3.1415926535897932384626433832795028842*I], [6.4656286076812 397829259659980344686072, -6.4656286076812397829259659980344686072 - 3.14159 26535897932384626433832795028842*I]]], [0, 0, 0]] .clgp: [4, [2, 2], [[2, 0; 0, 1], [3, 1; 0, 1]]] .codiff: [1, 553/1105; 0, 1/1105] .cyc: [2, 2] .diff: [1105, 553; 0, 1] .disc: 1105 .fu: [Mod(857*y - 28488, y^2 - 1105)] .gen: [[2, 0; 0, 1], [3, 1; 0, 1]] .index: 2 .nf: [y^2 - 1105, [2, 0], 1105, 2, [[1, -17.12077013859466140231529077105260 9448; 1, 16.120770138594661402315290771052609448], [1, -17.12077013859466140 2315290771052609448; 1, 16.120770138594661402315290771052609448], [1, -17; 1 , 16], [2, -1; -1, 553], [1105, 553; 0, 1], [553, 1; 1, 2], [1105, [553, 276 ; 1, 552]], [5, 13, 17]], [-33.241540277189322804630581542105218897, 33.2415 40277189322804630581542105218897], [2, y - 1], [1, 1; 0, 2], [1, 0, 0, 276; 0, 1, 1, -1]] .no: 4 .pol: y^2 - 1105 .r1: 2 .r2: 0 .reg: 10.950385405825605330267750825017937393 .roots: [-33.241540277189322804630581542105218897, 33.2415402771893228046305 81542105218897] .sign: [2, 0] .t2: [2, -1.0000000000000000000000000000000000000; -1.0000000000000000000000 000000000000000, 553.00000000000000000000000000000000000] .tu: [2, -1] .zk: [1, 1/2*y - 1/2] BNR .bid: [[[4, 0; 0, 4], [0, 0]], [4, [2, 2], [[1, -2]~, [-1, -2]~]], [[[2, [-1 , 1]~, 1, 1, [0, 276; 1, -1]], 2; [2, [2, 1]~, 1, 1, [1, 276; 1, 0]], 2], [[ 2, [-1, 1]~, 1, 1, [0, 276; 1, -1]], 2; [2, [2, 1]~, 1, 1, [1, 276; 1, 0]], 2]], [[[[2], [[1, -2]~], [4, 1; 0, 1], [[[0, -1]~, [1, 1], [2, [-1, 1]~, 1, 1, [0, 276; 1, -1]]]~, 1, [1, matrix(0,2)]], [1, 1, [[[2], [3], Mat([1, -1]) , 2]]], [[0]~, Mat(1)]], [[2], [[-1, -2]~], [4, 0; 0, 1], [[[1, -1]~, [1, 0] , [2, [2, 1]~, 1, 1, [1, 276; 1, 0]]]~, 1, [1, matrix(0,2)]], [1, 1, [[[2], [3], Mat([1, 0]), 2]]], [[0]~, Mat(1)]]], [[], Vecsmall([])]], [[1; 0], [0; 1]]] .bnf: [[2, 0; 0, 2], [1, 1, 0; 1, 0, 1], [10.9503854058256053302677508250179 37393 + 3.1415926535897932384626433832795028842*I; -10.950385405825605330267 750825017937393 + 6.2831853071795864769252867665590057684*I], [-2.8070134016 636593080928506577483570863, -6.4656286076812397829259659980344686072, 6.314 0644011531557847583424971265245465, 0, 0; 2.80701340166365930809285065774835 70863 + 3.1415926535897932384626433832795028842*I, 6.46562860768123978292596 59980344686072 + 3.1415926535897932384626433832795028842*I, -6.3140644011531 557847583424971265245465, 0, 0], [[2, [-1, 1]~, 1, 1, [0, 276; 1, -1]], [3, [0, 2]~, 1, 1, [-1, -276; -1, 0]], [5, [1, 2]~, 2, 1, [1, 552; 2, -1]], [2, [2, 1]~, 1, 1, [1, 276; 1, 0]], [3, [2, 2]~, 1, 1, [0, -276; -1, 1]]], 0, [y ^2 - 1105, [2, 0], 1105, 2, [[1, -17.120770138594661402315290771052609448; 1 , 16.120770138594661402315290771052609448], [1, -17.120770138594661402315290 771052609448; 1, 16.120770138594661402315290771052609448], [1, -17; 1, 16], [2, -1; -1, 553], [1105, 553; 0, 1], [553, 1; 1, 2], [1105, [553, 276; 1, 55 2]], [5, 13, 17]], [-33.241540277189322804630581542105218897, 33.24154027718 9322804630581542105218897], [2, y - 1], [1, 1; 0, 2], [1, 0, 0, 276; 0, 1, 1 , -1]], [[4, [2, 2], [[2, 0; 0, 1], [3, 1; 0, 1]]], 10.950385405825605330267 750825017937393, 1, [2, -1], [857*y - 28488]], [[-1, 0; 0, -1], [[0, 0], [0, 0]], [[2.8070134016636593080928506577483570863, -2.807013401663659308092850 6577483570863 - 3.1415926535897932384626433832795028842*I], [6.4656286076812 397829259659980344686072, -6.4656286076812397829259659980344686072 - 3.14159 26535897932384626433832795028842*I]]], [0, [Mat([[16, -1]~, 1]), Mat([[-137, -8]~, 1])], [-1, [-27631, 1714]~]]] .clgp: [4, [2, 2]] .codiff: [1, 553/1105; 0, 1/1105] .cyc: [2, 2] .diff: [1105, 553; 0, 1] .disc: 1105 .index: 2 .mod: [[4, 0; 0, 4], [0, 0]] .nf: [y^2 - 1105, [2, 0], 1105, 2, [[1, -17.12077013859466140231529077105260 9448; 1, 16.120770138594661402315290771052609448], [1, -17.12077013859466140 2315290771052609448; 1, 16.120770138594661402315290771052609448], [1, -17; 1 , 16], [2, -1; -1, 553], [1105, 553; 0, 1], [553, 1; 1, 2], [1105, [553, 276 ; 1, 552]], [5, 13, 17]], [-33.241540277189322804630581542105218897, 33.2415 40277189322804630581542105218897], [2, y - 1], [1, 1; 0, 2], [1, 0, 0, 276; 0, 1, 1, -1]] .no: 4 .pol: y^2 - 1105 .r1: 2 .r2: 0 .roots: [-33.241540277189322804630581542105218897, 33.2415402771893228046305 81542105218897] .sign: [2, 0] .t2: [2, -1.0000000000000000000000000000000000000; -1.0000000000000000000000 000000000000000, 553.00000000000000000000000000000000000] .zk: [1, 1/2*y - 1/2] .zkst: [4, [2, 2], [[1, -2]~, [-1, -2]~]] RNF .disc: [[4420, 553; 0, 1], [1, 2]~] .index: [2, 0; 0, 1] .nf: [y^2 - 1105, [2, 0], 1105, 2, [[1, -17.12077013859466140231529077105260 9448; 1, 16.120770138594661402315290771052609448], [1, -17.12077013859466140 2315290771052609448; 1, 16.120770138594661402315290771052609448], [1, -17; 1 , 16], [2, -1; -1, 553], [1105, 553; 0, 1], [553, 1; 1, 2], [1105, [553, 276 ; 1, 552]], [5, 13, 17]], [-33.241540277189322804630581542105218897, 33.2415 40277189322804630581542105218897], [2, y - 1], [1, 1; 0, 2], [1, 0, 0, 276; 0, 1, 1, -1]] .pol: x^2 - y .polabs: x^4 - 1105 .zk: [[1, x - 1], [1, [1, 1/2; 0, 1/2]]] QUADCLASSUNIT .clgp: [4, [2, 2], [Qfb(2, 33, -2, 0.E-38), Qfb(3, 31, -12, 0.E-38)]] .cyc: [2, 2] .gen: [Qfb(2, 33, -2, 0.E-38), Qfb(3, 31, -12, 0.E-38)] .no: 4 .reg: 10.950385405825605330267750825017937393 GAL .gen: [Vecsmall([2, 1])] .group: [Vecsmall([1, 2]), Vecsmall([2, 1])] .mod: 1924481769277537925474295096745532701170466590649506396700122170162248 74137973943 .orders: Vecsmall([2]) .p: 7 .pol: x^2 - 680564733841876926926749214863536422912 .roots: [8115106970904773215875220506543554430286346080245400415743406046580 3070437569694, 1112971072187060603886773046091177258141831982624966355125781 56550421803700404249]~ ELL .a1: 1 .a2: 2 .a3: 3 .a4: 4 .a6: 5 .b2: 9 .b4: 11 .b6: 29 .b8: 35 .c4: -183 .c6: -3429 .area: 2.9719152678179096707716479509361896060 .disc: -10351 .eta: [3.1096482423243803285501491221965830079, 1.55482412116219016427507456 10982915039 + 1.0643747452102737569438859937299427442*I] .gen: [[1, 2]] .j: 6128487/10351 .omega: [2.7807400137667297710631976271813584994, 1.390370006883364885531598 8135906792497 - 1.0687497763561930661592635474375038788*I] .roots: [-1.6189099322673713423780009396072169751, -0.3155450338663143288109 9953019639151248 + 2.0925470969119586079816894466366945829*I, -0.31554503386 631432881099953019639151248 - 2.0925470969119586079816894466366945829*I, 0.E -38 + 4.1850941938239172159633788932733891659*I, -1.303364898401057013567001 4094108254626 + 2.0925470969119586079816894466366945829*I, -1.30336489840105 70135670014094108254626 - 2.0925470969119586079816894466366945829*I]~ ELLFp .a1: Mod(1, 13) .a2: Mod(2, 13) .a3: Mod(3, 13) .a4: Mod(4, 13) .a6: Mod(5, 13) .b2: Mod(9, 13) .b4: Mod(11, 13) .b6: Mod(3, 13) .b8: Mod(9, 13) .c4: Mod(12, 13) .c6: Mod(3, 13) .cyc: [13] .disc: Mod(10, 13) .gen: [[Mod(6, 13), Mod(12, 13)]] .group: [13, [13], [[Mod(6, 13), Mod(12, 13)]]] .j: Mod(9, 13) .no: 13 .p: 13 ELLFq .a1: 1 .a2: 2 .a3: 3 .a4: 4 .a6: 5 .b2: 9 .b4: 11 .b6: 3 .b8: 9 .c4: 12 .c6: 3 .cyc: [195] .disc: 10 .gen: [[6*x + 1, x + 6]] .group: [195, [195], [[6*x + 1, x + 6]]] .j: 9 .no: 195 .p: 13 ELLQp .a1: 1 .a2: 2 .a3: 3 .a4: 4 .a6: 5 .b2: 9 .b4: 11 .b6: 29 .b8: 35 .c4: -183 .c6: -3429 .disc: -10351 .group: [12, [12], [[10, 4]]] .j: 6128487/10351 .p: 11 .roots: [9 + O(11^2)]~ .tate: [6 + 8*11 + 5*11^2 + 8*11^4 + O(11^5), Mod(x, x^2 + (5 + 2*11 + 5*11^ 2 + 10*11^3 + 2*11^4 + O(11^5))), 3*11 + 7*11^2 + O(11^5), [6 + 3*11 + O(11^ 5), 6 + 11 + 9*11^2 + 11^3 + 2*11^4 + O(11^5)], 1, [[39, 134943, 48065, 1359 11], [31719, 92956, 62706, 135911], [2*11 + 2*11^2 + 9*11^3 + 8*11^4 + O(11^ 5), 6*11^2 + 9*11^3 + 2*11^4 + O(11^5), 10*11^4 + O(11^5)], 0]] FFELT .f: 3 .mod: x^3 + x^2 + 1 .p: 2 .pol: x .f: 3 .mod: x^3 + x^2 + x + 2 .p: 3 .pol: x .f: 2 .mod: x^2 + x + 1 .p: 18446744073709551629 .pol: x INTMOD .mod: 3 POLMOD .mod: x^2 + 1 .pol: x QFB QUAD .disc: -4 .fu: [] .mod: w^2 + 1 .pol: w^2 + 1 .tu: [4, w] .zk: [1, w] PRID .e: 1 .f: 1 .gen: [2, [-1, 1]~] .p: 2 PADIC .mod: 9 .p: 3 MODPR .e: 1 .f: 1 .gen: [2, [-1, 1]~] .p: 2 BID .bid: [[[4, 1; 0, 1], [0, 0]], [2, [2], [3]], [Mat([[2, [-1, 1]~, 1, 1, [0, 276; 1, -1]], 2]), Mat([[2, [-1, 1]~, 1, 1, [0, 276; 1, -1]], 2])], [[[[2], [3], [4, 1; 0, 1], [[[0, -1]~, [1, 1], [2, [-1, 1]~, 1, 1, [0, 276; 1, -1]]] ~, 1, [1, matrix(0,2)]], [1, 1, [[[2], [3], Mat([1, -1]), 2]]], [[0]~, Mat(1 )]]], [[], Vecsmall([])]], [Mat(1)]] .clgp: [2, [2], [3]] .cyc: [2] .gen: [3] .mod: [[4, 1; 0, 1], [0, 0]] .no: 2 .zkst: [2, [2], [3]] BID (nogen) .bid: [[[4, 1; 0, 1], [0, 0]], [2, [2]], [Mat([[2, [-1, 1]~, 1, 1, [0, 276; 1, -1]], 2]), Mat([[2, [-1, 1]~, 1, 1, [0, 276; 1, -1]], 2])], [[[[2], [3], [4, 1; 0, 1], [[[0, -1]~, [1, 1], [2, [-1, 1]~, 1, 1, [0, 276; 1, -1]]]~, 1, [1, matrix(0,2)]], [1, 1, [[[2], [3], Mat([1, -1]), 2]]], [[0]~, Mat(1)]]], [[], Vecsmall([])]], [Mat(1)]] .clgp: [2, [2]] .cyc: [2] .mod: [[4, 1; 0, 1], [0, 0]] .no: 2 .zkst: [2, [2]] [1/3 0 0] [ 0 1/6 0] [ 0 0 1/6] MF .mod: t^2 + t + 1 .mod: Mod(1, t^2 + t + 1)*y^2 + Mod(-2*t, t^2 + t + 1) Total time spent: 116 pari-2.11.2/src/test/32/ellweilpairing0000644000175000017500000001547313201017466016114 0ustar billbill[56, 46, [39, 3]] [63, 1, [18, 6]] [118, 118, [57, 3]] [144, 12, [12, 12]] [104, 1, [63, 3]] [108, 84, [57, 3]] [92, 1, [63, 3]] [98, 1, [16, 8]] [37, 136, [40, 4]] [148, 1, [72, 2]] [156, 28, [12, 12]] [4, 1, [5, 5]] [64, 108, [18, 6]] [107, 126, [18, 6]] [12, 12, [12, 12]] [178, 36, [14, 14]] [95, 98, [16, 8]] [148, 0, [72, 2]] [107, 37, [18, 6]] [104, 53, [63, 3]] [11, 7, [9, 3]] [92, 58, [63, 3]] [136, 0, [40, 4]] [156, 0, [30, 6]] [161, 36, [14, 14]] [144, 0, [30, 6]] [1, 0, [128]] [1, 0, [192]] [1, 112, [114]] [1, 126, [18, 6]] [156, 1, [12, 12]] [1, 1, [180]] [1, 1, [192]] [1, 3, [6]] [1, 2, [3, 3]] t^5 + t^3 + t^2 t^5 + t^4 + 1 t^4 + t^2 + 1 t^5 + t 2*t^5 + t^4 + t^3 + t t^3 + 2*t^2 + 2 2*t^5 + 2*t^4 + 2*t^3 + 2*t^2 2*t^5 + 2*t^2 + 1 3*t^5 + 3*t^4 + 2*t^3 + t^2 + 2*t + 3 2*t^4 + t^3 + 3*t 2*t^5 + t^4 + t^3 + 2*t^2 3*t^5 + 4*t^4 + 4*t^3 + 3*t^2 + 4 t 2*t^4 + 2*t^2 + 2*t + 1 4*t^3 + t + 1 [36893488147419103362, 36893488147419103362] 9688432087730133707 9688432087730133707 [0, 0, 0, 2, 0]:[2, 2] [0, 0, 1, 2, 2]:[2, 2] [0, 0, 2, 2, 2]:[2, 2] [1, 2, 0, 2, 0]:[2, 2] [1, 2, 1, 0, 2]:[2, 2] [1, 2, 2, 1, 2]:[2, 2] [2, 2, 0, 2, 0]:[2, 2] [2, 2, 1, 1, 2]:[2, 2] [2, 2, 2, 0, 2]:[2, 2] [0, 0, 0, 1, 0]:[2, 2] [0, 0, 0, 4, 0]:[4, 2] [0, 0, 1, 1, 1]:[2, 2] [0, 0, 1, 4, 1]:[4, 2] [0, 0, 2, 1, 4]:[2, 2] [0, 0, 2, 4, 4]:[4, 2] [0, 0, 3, 1, 4]:[2, 2] [0, 0, 3, 4, 4]:[4, 2] [0, 0, 4, 1, 1]:[2, 2] [0, 0, 4, 4, 1]:[4, 2] [0, 1, 0, 1, 1]:[4, 2] [0, 1, 0, 3, 0]:[2, 2] [0, 1, 1, 1, 2]:[4, 2] [0, 1, 1, 3, 1]:[2, 2] [0, 1, 2, 1, 0]:[4, 2] [0, 1, 2, 3, 4]:[2, 2] [0, 1, 3, 1, 0]:[4, 2] [0, 1, 3, 3, 4]:[2, 2] [0, 1, 4, 1, 2]:[4, 2] [0, 1, 4, 3, 1]:[2, 2] [0, 2, 0, 2, 0]:[4, 2] [0, 2, 0, 4, 3]:[2, 2] [0, 2, 1, 2, 1]:[4, 2] [0, 2, 1, 4, 4]:[2, 2] [0, 2, 2, 2, 4]:[4, 2] [0, 2, 2, 4, 2]:[2, 2] [0, 2, 3, 2, 4]:[4, 2] [0, 2, 3, 4, 2]:[2, 2] [0, 2, 4, 2, 1]:[4, 2] [0, 2, 4, 4, 4]:[2, 2] [0, 3, 0, 2, 0]:[4, 2] [0, 3, 0, 4, 2]:[2, 2] [0, 3, 1, 2, 1]:[4, 2] [0, 3, 1, 4, 3]:[2, 2] [0, 3, 2, 2, 4]:[4, 2] [0, 3, 2, 4, 1]:[2, 2] [0, 3, 3, 2, 4]:[4, 2] [0, 3, 3, 4, 1]:[2, 2] [0, 3, 4, 2, 1]:[4, 2] [0, 3, 4, 4, 3]:[2, 2] [0, 4, 0, 1, 4]:[4, 2] [0, 4, 0, 3, 0]:[2, 2] [0, 4, 1, 1, 0]:[4, 2] [0, 4, 1, 3, 1]:[2, 2] [0, 4, 2, 1, 3]:[4, 2] [0, 4, 2, 3, 4]:[2, 2] [0, 4, 3, 1, 3]:[4, 2] [0, 4, 3, 3, 4]:[2, 2] [0, 4, 4, 1, 0]:[4, 2] [0, 4, 4, 3, 1]:[2, 2] [1, 0, 0, 1, 4]:[4, 2] [1, 0, 0, 3, 0]:[2, 2] [1, 0, 1, 0, 1]:[2, 2] [1, 0, 1, 3, 0]:[4, 2] [1, 0, 2, 0, 3]:[4, 2] [1, 0, 2, 2, 4]:[2, 2] [1, 0, 3, 2, 3]:[4, 2] [1, 0, 3, 4, 4]:[2, 2] [1, 0, 4, 1, 1]:[2, 2] [1, 0, 4, 4, 0]:[4, 2] [1, 1, 0, 1, 0]:[2, 2] [1, 1, 0, 4, 0]:[4, 2] [1, 1, 1, 1, 1]:[4, 2] [1, 1, 1, 3, 1]:[2, 2] [1, 1, 2, 0, 4]:[2, 2] [1, 1, 2, 3, 4]:[4, 2] [1, 1, 3, 0, 4]:[4, 2] [1, 1, 3, 2, 4]:[2, 2] [1, 1, 4, 2, 1]:[4, 2] [1, 1, 4, 4, 1]:[2, 2] [1, 2, 0, 1, 1]:[4, 2] [1, 2, 0, 3, 0]:[2, 2] [1, 2, 1, 0, 1]:[2, 2] [1, 2, 1, 3, 2]:[4, 2] [1, 2, 2, 0, 0]:[4, 2] [1, 2, 2, 2, 4]:[2, 2] [1, 2, 3, 2, 0]:[4, 2] [1, 2, 3, 4, 4]:[2, 2] [1, 2, 4, 1, 1]:[2, 2] [1, 2, 4, 4, 2]:[4, 2] [1, 3, 0, 2, 0]:[4, 2] [1, 3, 0, 4, 3]:[2, 2] [1, 3, 1, 1, 4]:[2, 2] [1, 3, 1, 4, 1]:[4, 2] [1, 3, 2, 1, 4]:[4, 2] [1, 3, 2, 3, 2]:[2, 2] [1, 3, 3, 0, 2]:[2, 2] [1, 3, 3, 3, 4]:[4, 2] [1, 3, 4, 0, 1]:[4, 2] [1, 3, 4, 2, 4]:[2, 2] [1, 4, 0, 2, 0]:[4, 2] [1, 4, 0, 4, 2]:[2, 2] [1, 4, 1, 1, 3]:[2, 2] [1, 4, 1, 4, 1]:[4, 2] [1, 4, 2, 1, 4]:[4, 2] [1, 4, 2, 3, 1]:[2, 2] [1, 4, 3, 0, 1]:[2, 2] [1, 4, 3, 3, 4]:[4, 2] [1, 4, 4, 0, 1]:[4, 2] [1, 4, 4, 2, 3]:[2, 2] [2, 0, 0, 1, 1]:[4, 2] [2, 0, 0, 3, 0]:[2, 2] [2, 0, 1, 0, 2]:[4, 2] [2, 0, 1, 2, 1]:[2, 2] [2, 0, 2, 1, 4]:[2, 2] [2, 0, 2, 4, 0]:[4, 2] [2, 0, 3, 0, 4]:[2, 2] [2, 0, 3, 3, 0]:[4, 2] [2, 0, 4, 2, 2]:[4, 2] [2, 0, 4, 4, 1]:[2, 2] [2, 1, 0, 2, 0]:[4, 2] [2, 1, 0, 4, 3]:[2, 2] [2, 1, 1, 1, 1]:[4, 2] [2, 1, 1, 3, 4]:[2, 2] [2, 1, 2, 0, 4]:[4, 2] [2, 1, 2, 2, 2]:[2, 2] [2, 1, 3, 1, 2]:[2, 2] [2, 1, 3, 4, 4]:[4, 2] [2, 1, 4, 0, 4]:[2, 2] [2, 1, 4, 3, 1]:[4, 2] [2, 2, 0, 2, 0]:[4, 2] [2, 2, 0, 4, 2]:[2, 2] [2, 2, 1, 1, 1]:[4, 2] [2, 2, 1, 3, 3]:[2, 2] [2, 2, 2, 0, 4]:[4, 2] [2, 2, 2, 2, 1]:[2, 2] [2, 2, 3, 1, 1]:[2, 2] [2, 2, 3, 4, 4]:[4, 2] [2, 2, 4, 0, 3]:[2, 2] [2, 2, 4, 3, 1]:[4, 2] [2, 3, 0, 1, 4]:[4, 2] [2, 3, 0, 3, 0]:[2, 2] [2, 3, 1, 0, 0]:[4, 2] [2, 3, 1, 2, 1]:[2, 2] [2, 3, 2, 1, 4]:[2, 2] [2, 3, 2, 4, 3]:[4, 2] [2, 3, 3, 0, 4]:[2, 2] [2, 3, 3, 3, 3]:[4, 2] [2, 3, 4, 2, 0]:[4, 2] [2, 3, 4, 4, 1]:[2, 2] [2, 4, 0, 1, 0]:[2, 2] [2, 4, 0, 4, 0]:[4, 2] [2, 4, 1, 0, 1]:[2, 2] [2, 4, 1, 3, 1]:[4, 2] [2, 4, 2, 2, 4]:[4, 2] [2, 4, 2, 4, 4]:[2, 2] [2, 4, 3, 1, 4]:[4, 2] [2, 4, 3, 3, 4]:[2, 2] [2, 4, 4, 0, 1]:[4, 2] [2, 4, 4, 2, 1]:[2, 2] [3, 0, 0, 1, 1]:[4, 2] [3, 0, 0, 3, 0]:[2, 2] [3, 0, 1, 2, 2]:[4, 2] [3, 0, 1, 4, 1]:[2, 2] [3, 0, 2, 0, 4]:[2, 2] [3, 0, 2, 3, 0]:[4, 2] [3, 0, 3, 1, 4]:[2, 2] [3, 0, 3, 4, 0]:[4, 2] [3, 0, 4, 0, 2]:[4, 2] [3, 0, 4, 2, 1]:[2, 2] [3, 1, 0, 2, 0]:[4, 2] [3, 1, 0, 4, 3]:[2, 2] [3, 1, 1, 0, 4]:[2, 2] [3, 1, 1, 3, 1]:[4, 2] [3, 1, 2, 1, 2]:[2, 2] [3, 1, 2, 4, 4]:[4, 2] [3, 1, 3, 0, 4]:[4, 2] [3, 1, 3, 2, 2]:[2, 2] [3, 1, 4, 1, 1]:[4, 2] [3, 1, 4, 3, 4]:[2, 2] [3, 2, 0, 2, 0]:[4, 2] [3, 2, 0, 4, 2]:[2, 2] [3, 2, 1, 0, 3]:[2, 2] [3, 2, 1, 3, 1]:[4, 2] [3, 2, 2, 1, 1]:[2, 2] [3, 2, 2, 4, 4]:[4, 2] [3, 2, 3, 0, 4]:[4, 2] [3, 2, 3, 2, 1]:[2, 2] [3, 2, 4, 1, 1]:[4, 2] [3, 2, 4, 3, 3]:[2, 2] [3, 3, 0, 1, 4]:[4, 2] [3, 3, 0, 3, 0]:[2, 2] [3, 3, 1, 2, 0]:[4, 2] [3, 3, 1, 4, 1]:[2, 2] [3, 3, 2, 0, 4]:[2, 2] [3, 3, 2, 3, 3]:[4, 2] [3, 3, 3, 1, 4]:[2, 2] [3, 3, 3, 4, 3]:[4, 2] [3, 3, 4, 0, 0]:[4, 2] [3, 3, 4, 2, 1]:[2, 2] [3, 4, 0, 1, 0]:[2, 2] [3, 4, 0, 4, 0]:[4, 2] [3, 4, 1, 0, 1]:[4, 2] [3, 4, 1, 2, 1]:[2, 2] [3, 4, 2, 1, 4]:[4, 2] [3, 4, 2, 3, 4]:[2, 2] [3, 4, 3, 2, 4]:[4, 2] [3, 4, 3, 4, 4]:[2, 2] [3, 4, 4, 0, 1]:[2, 2] [3, 4, 4, 3, 1]:[4, 2] [4, 0, 0, 1, 4]:[4, 2] [4, 0, 0, 3, 0]:[2, 2] [4, 0, 1, 1, 1]:[2, 2] [4, 0, 1, 4, 0]:[4, 2] [4, 0, 2, 2, 3]:[4, 2] [4, 0, 2, 4, 4]:[2, 2] [4, 0, 3, 0, 3]:[4, 2] [4, 0, 3, 2, 4]:[2, 2] [4, 0, 4, 0, 1]:[2, 2] [4, 0, 4, 3, 0]:[4, 2] [4, 1, 0, 1, 0]:[2, 2] [4, 1, 0, 4, 0]:[4, 2] [4, 1, 1, 2, 1]:[4, 2] [4, 1, 1, 4, 1]:[2, 2] [4, 1, 2, 0, 4]:[4, 2] [4, 1, 2, 2, 4]:[2, 2] [4, 1, 3, 0, 4]:[2, 2] [4, 1, 3, 3, 4]:[4, 2] [4, 1, 4, 1, 1]:[4, 2] [4, 1, 4, 3, 1]:[2, 2] [4, 2, 0, 1, 1]:[4, 2] [4, 2, 0, 3, 0]:[2, 2] [4, 2, 1, 1, 1]:[2, 2] [4, 2, 1, 4, 2]:[4, 2] [4, 2, 2, 2, 0]:[4, 2] [4, 2, 2, 4, 4]:[2, 2] [4, 2, 3, 0, 0]:[4, 2] [4, 2, 3, 2, 4]:[2, 2] [4, 2, 4, 0, 1]:[2, 2] [4, 2, 4, 3, 2]:[4, 2] [4, 3, 0, 2, 0]:[4, 2] [4, 3, 0, 4, 3]:[2, 2] [4, 3, 1, 0, 1]:[4, 2] [4, 3, 1, 2, 4]:[2, 2] [4, 3, 2, 0, 2]:[2, 2] [4, 3, 2, 3, 4]:[4, 2] [4, 3, 3, 1, 4]:[4, 2] [4, 3, 3, 3, 2]:[2, 2] [4, 3, 4, 1, 4]:[2, 2] [4, 3, 4, 4, 1]:[4, 2] [4, 4, 0, 2, 0]:[4, 2] [4, 4, 0, 4, 2]:[2, 2] [4, 4, 1, 0, 1]:[4, 2] [4, 4, 1, 2, 3]:[2, 2] [4, 4, 2, 0, 1]:[2, 2] [4, 4, 2, 3, 4]:[4, 2] [4, 4, 3, 1, 4]:[4, 2] [4, 4, 3, 3, 1]:[2, 2] [4, 4, 4, 1, 3]:[2, 2] [4, 4, 4, 4, 1]:[4, 2] Total time spent: 84 pari-2.11.2/src/test/32/hyperell0000644000175000017500000000766113447371554014746 0ustar billbill1:1:x - 4 1:2:x - 4 2:1:x^2 - x - 20 2:2:x^2 - 5*x - 20 2:3:x^2 - x - 60 2:4:x^2 + 5*x - 20 3:1:x^3 - 55*x - 68 3:2:x^3 - 5*x^2 - 26*x + 128 3:3:x^3 + 2*x^2 - 51*x + 48 3:4:x^3 - 8*x^2 + 7*x + 30 3:5:x^3 - x^2 - 38*x + 72 3:6:x^3 + 6*x^2 - 13*x - 42 4:1:x^4 - 8*x^3 - 36*x^2 + 360*x - 464 4:2:x^4 - 10*x^3 + x^2 + 144*x - 136 4:3:x^4 + 8*x^3 - 21*x^2 - 116*x + 128 4:4:x^4 + 10*x^3 - 5*x^2 - 200*x - 208 4:5:x^4 - 8*x^3 - 41*x^2 + 246*x + 584 4:6:x^4 + 10*x^3 - 51*x^2 - 764*x - 1856 4:7:x^4 - 8*x^3 - 17*x^2 + 156*x + 24 4:8:x^4 - 10*x^3 - 18*x^2 + 320*x - 430 5:1:x^5 + 8*x^4 - 47*x^3 - 356*x^2 + 361*x + 1596 5:2:x^5 - 99*x^3 + 72*x^2 + 2085*x - 2968 5:3:x^5 - x^4 - 103*x^3 + 40*x^2 + 2464*x + 1536 5:4:x^5 - x^4 - 91*x^3 + 114*x^2 + 1761*x - 1496 5:5:x^5 - 8*x^4 - 68*x^3 + 500*x^2 + 1084*x - 6160 5:6:x^5 - 2*x^4 - 62*x^3 + 36*x^2 + 838*x + 616 5:7:x^5 + 5*x^4 - 75*x^3 - 250*x^2 + 1321*x + 852 5:8:x^5 - 5*x^4 - 57*x^3 + 254*x^2 + 372*x - 1168 5:9:x^5 + 2*x^4 - 65*x^3 - 162*x^2 + 509*x + 986 5:10:x^5 - 10*x^4 - 25*x^3 + 398*x^2 - 443*x - 1482 6:1:x^6 - 8*x^5 - 83*x^4 + 742*x^3 + 547*x^2 - 11058*x + 10184 6:2:x^6 - 10*x^5 - 71*x^4 + 900*x^3 - 193*x^2 - 14820*x + 25460 6:3:x^6 + 2*x^5 - 118*x^4 - 184*x^3 + 4023*x^2 + 4302*x - 35264 6:4:x^6 - 95*x^4 - 2*x^3 + 1927*x^2 - 720*x - 2992 6:5:x^6 + 5*x^5 - 112*x^4 - 583*x^3 + 2693*x^2 + 16639*x + 17196 6:6:x^6 + 6*x^5 - 76*x^4 - 405*x^3 + 1226*x^2 + 6194*x + 3960 6:7:x^6 - 114*x^4 + 27*x^3 + 3176*x^2 - 1940*x - 16768 6:8:x^6 + x^5 - 116*x^4 - 39*x^3 + 3557*x^2 - 849*x - 19852 6:9:x^6 + 2*x^5 - 115*x^4 - 108*x^3 + 3251*x^2 - 2214*x - 7692 6:10:x^6 + 8*x^5 - 84*x^4 - 640*x^3 + 1637*x^2 + 10084*x - 11062 6:11:x^6 + 8*x^5 - 89*x^4 - 750*x^3 + 1343*x^2 + 14698*x + 9316 6:12:x^6 + 2*x^5 - 117*x^4 - 240*x^3 + 3607*x^2 + 6492*x - 17696 1:1:x + 6 1:2:x - 2 1:3:x - 6 2:1:x^2 + 8*x - 2 2:2:x^2 - 18*x + 81 2:3:x^2 - 36 2:4:x^2 + 18*x + 81 2:5:x^2 + 8*x - 2 3:1:x^3 + 3*x^2 - 74*x - 48 3:2:x^3 - 2*x^2 - 76*x + 312 3:3:x^3 - 12*x^2 - 17*x + 346 3:4:x^3 + 6*x^2 + 12*x + 8 3:5:x^3 + 12*x^2 - 17*x - 346 3:6:x^3 + 2*x^2 - 76*x - 312 3:7:x^3 + 3*x^2 - 74*x - 48 4:1:x^4 + 7*x^3 - 69*x^2 - 314*x + 927 4:2:x^4 - 6*x^3 - 115*x^2 + 468*x + 2592 4:3:x^4 - 6*x^3 - 54*x^2 + 221*x - 70 4:4:x^4 + 6*x^3 - 44*x^2 - 320*x - 480 4:5:x^4 - 60*x^2 + 400 4:6:x^4 + 6*x^3 - 44*x^2 - 320*x - 480 4:7:x^4 + 6*x^3 - 54*x^2 - 221*x - 70 4:8:x^4 - 6*x^3 - 115*x^2 + 468*x + 2592 4:9:x^4 + 7*x^3 - 69*x^2 - 314*x + 927 5:1:x^5 + 12*x^4 - 81*x^3 - 1217*x^2 - 15*x + 19944 5:2:x^5 - 2*x^4 - 118*x^3 + 136*x^2 + 3304*x + 792 5:3:x^5 - 6*x^4 - 84*x^3 + 504*x^2 + 9*x - 54 5:4:x^5 + 22*x^4 + 46*x^3 - 2156*x^2 - 18639*x - 44874 5:5:x^5 + 3*x^4 - 115*x^3 - 123*x^2 + 3194*x - 2760 5:6:x^5 + 2*x^4 - 40*x^3 - 80*x^2 + 144*x + 288 5:7:x^5 + 3*x^4 - 115*x^3 - 123*x^2 + 3194*x - 2760 5:8:x^5 - 22*x^4 + 46*x^3 + 2156*x^2 - 18639*x + 44874 5:9:x^5 + 6*x^4 - 84*x^3 - 504*x^2 + 9*x + 54 5:10:x^5 - 2*x^4 - 118*x^3 + 136*x^2 + 3304*x + 792 5:11:x^5 - 12*x^4 - 81*x^3 + 1217*x^2 - 15*x - 19944 x^2 + 3*x x^2 - 5 x^2 + x - 5 x^4 + 3*x^3 - 3*x^2 - 9*x x^4 - 20*x^2 - 10*x + 50 x^4 + 4*x^3 - 14*x^2 - 42*x + 14 x^4 + 3*x^3 - 27*x^2 - 26*x + 47 x^2 - 54 x^2 + 25*x + 125 x^2 + 23*x - 265 x^4 - 9*x^2 - 2*x + 12 x^5 + 2*x^4 - 10*x^3 - 20*x^2 x^6 + 2*x^5 - 15*x^4 - 26*x^3 + 62*x^2 + 84*x - 51 x^2 - 47*x - 5490 x^2 + 47*x - 5490 x^2 - 47*x - 5490 x^2 - 42*x - 2356 x^2 + 42*x - 2356 x^3 + 4*x^2 - 164*x - 180 x^3 - 10*x^2 - 154*x + 1508 x^2 + 9*x - 135 x + 6 x^2 - x - 2 x^2 - 2*x - 1 x^2 - 2 x^2 - x - 4 x^2 - x - 2 x^2 - 2*x - 2 x^2 - 2 x^2 - 4 x^2 - 2 x^2 - 686 *** at top-level: hyperellcharpoly((256*a^5+5)*Mod(1,5)) *** ^-------------------------------------- *** hyperellcharpoly: domain error in hyperellpadicfrobenius: H is singular at 5 *** at top-level: hyperellcharpoly((256*a^5+5)*ffgen(5^2)) *** ^---------------------------------------- *** hyperellcharpoly: domain error in hyperellpadicfrobenius: H is singular at 5 Total time spent: 2072 pari-2.11.2/src/test/32/intnum0000644000175000017500000001471513457566442014435 0ustar billbill? allocatemem(20*10^6); *** Warning: new stack size = 20000000 (19.073 Mbytes). ? check(a,b)=my(t=abs((a-b)/b));if(t,ceil(log(t)/log(10)),-oo); ? \p96 realprecision = 96 significant digits ? check(intcirc(s=1,0.5,zeta(s)),1) -84 ? f(s)=gamma(s)^3; ? c=2; ? A=[-oo,3*Pi/2]; ? B=[+oo,3*Pi/2]; ? F(z)=my(a=-log(z));intnum(t=A,B,exp(a*I*t),T)*exp(a*c)/(2*Pi); ? T=intfuncinit(t=A,B,f(c+I*t)); ? ref=F(4); ? \p38 realprecision = 38 significant digits ? T=intfuncinit(t=A,B,f(c+I*t)); ? check(F(4),ref) -37 ? \p96 realprecision = 96 significant digits ? f(x)=1/(exp(x)-1)-exp(-x)/x; ? F=truncate(f(t+O(t^7))); ? g(x)=if(x>1e-18,f(x),subst(F,t,x)); ? check(intnum(x=0,[oo,1],f(x)),Euler) -oo ? check(intnum(x=0,[oo,1],g(x)),Euler) -oo ? check(intnum(x=0,1,1/sqrt(x)),2) -58 ? check(intnum(x=[0,-1/2],1,1/sqrt(x)),2) -oo ? check(intnum(x=100000,oo,1/(1+x^2)),atan(1/100000)) -oo ? check(intnum(x=0,1,x*cos(Pi*x)),-2/Pi^2) -oo ? check(intnum(x=0,1,x*cos(Pi*x),2),-2/Pi^2) -oo ? check(intnum(x=[0,-1/2],[oo,-3/2],1/(sqrt(x)+x^(3/2))),Pi) -oo ? check(intnum(x=[-oo,-3/2],[oo,-3/2],1/(1+abs(x)^(3/2))),8*Pi/sqrt(27)) -oo ? check(intnum(x=-oo,oo,1/(1+x^2)),Pi) -oo ? f(x)=if(x<0,1/(1+(-x)^(3/2)),1/(1+x^(5/2))); ? a=4*Pi/sqrt(27)+2*(Pi/5)/sin(2*Pi/5); ? check(intnum(x=[-oo,-3/2],[oo,-5/2],f(x)),a) -oo ? f(x)=if(x<0,1/(1+(-x)^(3/2)),exp(-x)); ? check(intnum(x=[-oo,-3/2],[oo,1],f(x)),4*Pi/sqrt(27)+1) -oo ? f(x)=if(x<0,1/(1+(-x)^(3/2)),sinc(x)); ? check(intnum(x=[-oo,-3/2],[oo,-I],f(x)),4*Pi/sqrt(27)+Pi/2) -oo ? f(x)=if(x<0,exp(2*x),1/(1+x^(3/2))); ? check(intnum(x=[-oo,2],[oo,-3/2],f(x)),1/2+4*Pi/sqrt(27)) -oo ? f(x)=if(x<0,exp(2*x),1/(1+x^(5/2))); ? check(intnum(x=[-oo,2],[oo,-5/2],f(x)),1/2+2*(Pi/5)/sin(2*Pi/5)) -oo ? f(x)=if(x<0,exp(2*x),exp(-x)); ? check(intnum(x=[-oo,2],[oo,1],f(x)),3/2) -oo ? f(x)=if(x<0,exp(2*x),sinc(x)); ? check(intnum(x=[-oo,2],[oo,-I],f(x)),1/2+Pi/2) -oo ? f(x)=if(x<0,2*sinc(2*x),1/(1+x^(3/2))); ? check(intnum(x=[-oo,-2*I],[oo,-3/2],f(x)),Pi/2+4*Pi/sqrt(27)) -oo ? f(x)=if(x<0,2*sinc(2*x),1/(1+x^(5/2))); ? check(intnum(x=[-oo,-2*I],[oo,-5/2],f(x)),Pi/2+2*(Pi/5)/sin(2*Pi/5)) -96 ? f(x)=if(x<0,2*sinc(2*x),exp(-x)); ? check(intnum(x=[-oo,-2*I],[oo,1],f(x)),Pi/2+1) -oo ? f(x)=if(x<0,2*sinc(2*x),sinc(x)); ? check(intnum(x=[-oo,-2*I],[oo,-I],f(x)),Pi) -oo ? f(x)=cos((3+tanh(x))*x)/sqrt(1+x^2); ? a=intnum(x=[-oo,2*I],[oo,4*I],f(x),1); ? check(intnum(x=[-oo,2*I],[oo,4*I],f(x)),a) -51 ? check(intnum(x=[0,-1/2],[1,-1/3],x^(-1/2)+(1-x)^(-1/3)),7/2) -oo ? T=intnuminit([0,-1/2],[1,-1/3]); ? check(intnum(x=[0,-1/2],[1,-1/3],x^(-1/2)+(1-x)^(-1/3),T),7/2) -oo ? check(intnum(x=0,[oo,1],sinc(x)),Pi/2) -2 ? check(intnum(x=0,[oo,-I],sinc(x)),Pi/2) -oo ? check(intnum(x=0,[oo,-2*I],2*sinc(2*x)),Pi/2) -oo ? A=intnum(x=0,1,sinc(x/2)^2/2)+intnum(x=1,oo,1/x^2)-intnum(x=1,[oo,I],cos(x)/x^2); ? check(A,Pi/2) -95 ? check(intnum(x=0,[oo,1],sin(x)^3*exp(-x)),3/10) -47 ? check(intnum(x=0,[oo,-I],sin(x)^3*exp(-x)),3/10) -85 ? tab=intnuminit(0,[oo,-I],1); ? check(intnum(x=0,oo,sin(x)^3*exp(-x),tab),3/10) -96 ? check(intnum(x=0,[oo,-I],x^2*sin(x)),-2) -oo ? tab=intnuminit(-1,1); ? check(intnum(x=-1,1,intnum(y=-sqrt(1-x^2),sqrt(1-x^2),x^2+y^2,tab),tab),Pi/2) -96 ? \p96 ? check(intnumgauss(x=0,1,sin(x)),1-cos(1)) -96 ? T=intnumgaussinit(); ? check(intnumgauss(x=0,1,1/(x+1),T),log(2)) -oo ? check(intnumgauss(x=0,1,1/(x+1)^(4/3),T),3-3/2^(1/3)) -95 ? check(intnumgauss(x=2,1,x,T),-3/2) -oo ? check(intnumgauss(x=-1,1,1/(1+x^2),20),Pi/2) -15 ? T=intnumgaussinit(100); ? check(intnumgauss(x=-2,2,1/(1+x^2),T),2*atan(2)) -41 ? check(intnumgauss(t=1,2,t,1),3/2) -oo ? checkps(a,b)=my(t=norml2(Vec(b-a)));if(t,ceil(log(t)/log(10)),-oo); ? checkps(intnum(t=0,x,exp(t)),exp(x)-1) -oo ? checkps(intnum(t=-x,0,exp(t)),1-exp(-x)) -oo ? checkps(intnum(t=-x,x,exp(t)),exp(x)-exp(-x)) -oo ? tab=intnuminit(1-x,1+y); ? norml2(apply(Vec,Vec(intnum(t=-x,y,exp(t),tab)-(exp(y)-exp(-x))))) 0.E-192 ? checkps(intnum(t=[0,-1/2],x^2,1/sqrt(t)),2*x) -115 ? checkps(intnum(t=1-x^2,[1,-1/2],1/sqrt(1-t)),2*x) -115 ? checkps(intnum(t=[x^2,-1/2],1,1/sqrt(t)),2-2*x) -115 ? checkps(intnum(t=0,[1-x^2,-1/2],1/sqrt(1-t)),2-2*x) -115 ? f(t)=(t^2*(1-t))^(1/3); ? checkps(intnum(t=[x^3,-1/3],[1-x^3,-2/3],(2/3*t-t^2)/(t^2*(1-t))^(2/3)),f(1-x^3)-f(x^3)) -77 ? \p38 realprecision = 38 significant digits ? intnum(x=-oo,[0,-1/2],1/sqrt(-x*(x^4+1))) 2.5189270468096534385807611189769924243 ? \pb20 realbitprecision = 20 significant bits (6 decimal digits displayed) ? intnumromb(x=0,1,sin(x)) 0.459698 ? intnumromb(x=0,1,sin(x),1) 0.459698 ? intnumromb(x=1,100,exp(-x^2),2) 0.139403 ? intnumromb(x=0,1,sinc(x),3) 0.946083 ? intnumromb(x=0,110,x,1) 6048.32 ? intnumromb(x=2,110,x,1) 6039.11 ? abs(intnumromb(x=-110,90,x,1)+1998.3)<1e-1 1 ? intnumromb(x=2,1,x,1) -1.50000 ? intnuminit(-oo,oo,1); ? intnuminit([x,-1/2],x) *** at top-level: intnuminit([x,-1/2],x) *** ^---------------------- *** intnuminit: sorry, intnuminit with singularity at non constant limit is not yet implemented. ? intnum(t=[x^2,-1/2],1,1/sqrt(t),intnuminit([0,-1/2],1)) *** at top-level: intnum(t=[x^2,-1/2],1,1/sqrt(t),intnuminit([0, *** ^------------------------ *** sorry, non integer tab argument is not yet implemented. ? intnumgauss(t=1,2,1,"") *** at top-level: intnumgauss(t=1,2,1,"") *** ^----- *** incorrect type in intnumgauss (t_STR). ? intnuminit([oo,1+I],[oo,""]) *** at top-level: intnuminit([oo,1+I],[oo,""]) *** ^---------------------------- *** intnuminit: incorrect type in intnum [incorrect a] (t_VEC). ? intnuminit([oo,1+I,2],[oo,1]) *** at top-level: intnuminit([oo,1+I,2],[oo,1]) *** ^----------------------------- *** intnuminit: incorrect type in intnum [incorrect a] (t_VEC). ? intnum(x=oo,oo,1) *** Warning: integral from oo to oo. 0 ? intnum(x=-oo,-oo,1) *** Warning: integral from -oo to -oo. 0 ? intnuminit(x=-oo,oo,-1); *** at top-level: intnuminit(x=-oo,oo,-1) *** ^----------------------- *** intnuminit: domain error in intnuminit: m < 0 ? intfuncinit(t=0,1,s); *** at top-level: intfuncinit(t=0,1,s) *** ^-- *** sorry, intfuncinit with finite endpoints is not yet implemented. ? intfuncinit(t=[-oo,I],[oo,I],s); *** at top-level: ...uncinit(t=[-oo,I],[oo,I],s) *** ^-- *** sorry, intfuncinit with hard endpoint behavior is not yet implemented. ? print("Total time spent: ",gettime); Total time spent: 2055 pari-2.11.2/src/test/32/ellisomat0000644000175000017500000001122613326135265015074 0ustar billbill *** Warning: new stack size = 48000000 (45.776 Mbytes). -32768:[1, 11; 11, 1]:[0, 0] -121:[1, 11; 11, 1]:[0, 0] -24729001:[1, 11; 11, 1]:[0, 0] -297756989/2:[1, 17; 17, 1]:[0, 0] -882216989/131072:[1, 17; 17, 1]:[0, 0] -884736:[1, 19; 19, 1]:[0, 0] -9317:[1, 37; 37, 1]:[0, 0] -162677523113838677:[1, 37; 37, 1]:[0, 0] -884736000:[1, 43; 43, 1]:[0, 0] -147197952000:[1, 67; 67, 1]:[0, 0] -262537412640768000:[1, 163; 163, 1]:[0, 0] 0:[1, 3, 2, 6; 3, 1, 6, 2; 2, 6, 1, 3; 6, 2, 3, 1]:[0, 0, 0, 0] 1728:[1, 2, 4, 4; 2, 1, 2, 2; 4, 2, 1, 4; 4, 2, 4, 1]:[0, 0, 0, 0] -3375:[1, 2, 7, 14; 2, 1, 14, 7; 7, 14, 1, 2; 14, 7, 2, 1]:[0, 0, 0, 0] 8000:[1, 2; 2, 1]:[0, 0] 54000:[1, 3, 2, 6; 3, 1, 6, 2; 2, 6, 1, 3; 6, 2, 3, 1]:[0, 0, 0, 0] 287496:[1, 2, 4, 4; 2, 1, 2, 2; 4, 2, 1, 4; 4, 2, 4, 1]:[0, 0, 0, 0] -12288000:[1, 3, 9, 27; 3, 1, 3, 9; 9, 3, 1, 3; 27, 9, 3, 1]:[0, 0, 0, 0] 16581375:[1, 2, 7, 14; 2, 1, 14, 7; 7, 14, 1, 2; 14, 7, 2, 1]:[0, 0, 0, 0] 9938375/21952:[1, 3, 3, 2, 6, 6; 3, 1, 9, 6, 2, 18; 3, 9, 1, 6, 18, 2; 2, 6, 6, 1, 3, 3; 6, 2, 18, 3, 1, 9; 6, 18, 2, 3, 9, 1]:[0, 0, 0, 0, 0, 0] 111284641/50625:[1, 2, 4, 4, 2, 2, 4, 4; 2, 1, 2, 2, 4, 4, 8, 8; 4, 2, 1, 4, 8, 8, 16, 16; 4, 2, 4, 1, 8, 8, 16, 16; 2, 4, 8, 8, 1, 4, 8, 8; 2, 4, 8, 8, 4, 1, 2, 2; 4, 8, 16, 16, 8, 2, 1, 4; 4, 8, 16, 16, 8, 2, 4, 1]:[0, 0, 0, 0 , 0, 0, 0, 0] -10218313/17576:[1, 3, 3; 3, 1, 9; 3, 9, 1]:[0, 0, 0] -25/2:[1, 3, 5, 15; 3, 1, 15, 5; 5, 15, 1, 3; 15, 5, 3, 1]:[0, 0, 0, 0] [[[[-31/3, -2501/108], [x - 1/3, y + 1/2, 1], [x + 1/3, y - 1/2, 1]], [[-234 61/3, -28748141/108], [x^5 - 127/3*x^4 + 2177*x^3 - 91861/3*x^2 + 171618*x - 980197/3, (y + 1/2)*x^6 + (-63*y - 63/2)*x^5 + (y + 1/2)*x^4 + (1977*y + 19 77/2)*x^3 + (7626*y + 3813)*x^2 + (11654*y + 5827)*x + (6682*y + 3341), x^2 - 21*x + 80], [1/25*x^5 + 127/15*x^4 + 30467/45*x^3 + 3309581/135*x^2 + 1445 85559/405*x + 4710599326/6075, (1/125*y - 1/2)*x^6 + (61/25*y - 305/2)*x^5 + (117098/375*y - 290702/15)*x^4 + (72436097/3375*y - 70930739/54)*x^3 + (281 9744498/3375*y - 33802537858/675)*x^2 + (176778054473/10125*y - 824769156301 /810)*x + (13938798626101/91125*y - 1572185782385639/182250), x^2 + 305/3*x + 116279/45]], [[-625/3, 296875/108], [x^5 + 5/3*x^4 + 85/3*x^3 - 935/3*x^2 - 2245/3*x - 3166/3, (y + 1/2)*x^6 + (3*y + 3/2)*x^5 + (-54*y - 27)*x^4 + (6 13*y + 613/2)*x^3 + (1752*y + 876)*x^2 + (8585*y + 8585/2)*x + (6451*y + 645 1/2), x^2 + x - 29/5], [1/25*x^5 - 1/3*x^4 + 325/9*x^3 + 34375/27*x^2 - 1562 500/81*x + 40234375/243, (1/125*y - 1/2)*x^6 + (-1/5*y + 25/2)*x^5 + (-35/3* y + 625/6)*x^4 + (-14375/27*y - 171875/54)*x^3 + (231250/27*y - 390625/27)*x ^2 + (-19062500/81*y + 19531250/81)*x + (792968750/729*y + 976562500/729), x ^2 - 25/3*x - 1250/9]]], [1, 5, 5; 5, 1, 25; 5, 25, 1]] [[[[215/48, -5291/864], [x + 1/12, 1/2*x + (y + 1/2), 1], [x - 1/12, -1/2*x + (y - 11/24), 1]], [[-1705/48, -57707/864], [x^3 - 23/12*x^2 + 53/6*x - 95/ 12, 1/2*x^4 + (y - 1)*x^3 + (-3*y - 4)*x^2 + (-5*y + 1)*x + (7*y + 7/2), x - 1], [1/4*x^3 + x^2 - 291/64*x - 41483/3456, -1/8*x^4 + (1/8*y - 61/48)*x^3 + (13/16*y - 791/384)*x^2 + (1705/384*y + 13429/3456)*x + (48919/6912*y + 32 8367/41472), x + 13/6]]], [1, 2; 2, 1]] [[[[215/48, -5291/864], [x + 1/12, 1/2*x + (y + 1/2), 1], [x - 1/12, -1/2*x + (y - 11/24), 1]], [[-675/16, 6831/32], [x^3 + 3/4*x^2 + 19/2*x - 311/12, 1 /2*x^4 + (y + 1)*x^3 + (y - 4)*x^2 + (-9*y + 23)*x + (55*y + 55/2), x + 1/3] , [1/9*x^3 - 1/4*x^2 - 141/16*x + 5613/64, -1/18*x^4 + (1/27*y - 1/3)*x^3 + (-1/12*y + 87/16)*x^2 + (49/16*y - 48)*x + (-3601/64*y + 16947/512), x - 3/4 ]], [[-8185/48, -742643/864], [x^3 - 47/12*x^2 + 116/3*x - 62/3, 1/2*x^4 + ( y - 5/2)*x^3 + (-6*y - 29/2)*x^2 + (-23*y - 59/2)*x + (-36*y - 18), x - 2], [1/9*x^3 + 47/36*x^2 - 3695/432*x - 1464769/15552, -1/18*x^4 + (1/27*y - 3/2 )*x^3 + (25/36*y - 3965/432)*x^2 + (10745/1296*y + 118411/7776)*x + (2098163 /46656*y + 21431725/124416), x + 25/4]]], [1, 3, 3; 3, 1, 9; 3, 9, 1]] [1, 13; 13, 1] [0, 0] [1, 2, 3, 6, 5, 10, 15, 30; 2, 1, 6, 3, 10, 5, 30, 15; 3, 6, 1, 2, 15, 30, 5 , 10; 6, 3, 2, 1, 30, 15, 10, 5; 5, 10, 15, 30, 1, 2, 3, 6; 10, 5, 30, 15, 2 , 1, 6, 3; 15, 30, 5, 10, 3, 6, 1, 2; 30, 15, 10, 5, 6, 3, 2, 1] [0, 0, 0, 0, 0, 0, 0, 0] [1, 2, 4, 4, 3, 3, 6, 6, 12, 12, 12, 12; 2, 1, 2, 2, 6, 6, 3, 3, 6, 6, 6, 6; 4, 2, 1, 4, 12, 12, 6, 6, 3, 3, 12, 12; 4, 2, 4, 1, 12, 12, 6, 6, 12, 12, 3 , 3; 3, 6, 12, 12, 1, 9, 2, 18, 4, 36, 36, 4; 3, 6, 12, 12, 9, 1, 18, 2, 36, 4, 4, 36; 6, 3, 6, 6, 2, 18, 1, 9, 2, 18, 18, 2; 6, 3, 6, 6, 18, 2, 9, 1, 1 8, 2, 2, 18; 12, 6, 3, 12, 4, 36, 2, 18, 1, 9, 36, 4; 12, 6, 3, 12, 36, 4, 1 8, 2, 9, 1, 4, 36; 12, 6, 12, 3, 36, 4, 18, 2, 36, 4, 1, 9; 12, 6, 12, 3, 4, 36, 2, 18, 4, 36, 9, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] Total time spent: 2640 pari-2.11.2/src/test/32/minmax0000644000175000017500000000014412314242551014362 0ustar billbill1: [1, 1, 0, 0] 2: [11, -3, 1, 4] 3: [11, -3, 1, 4] 4: [11, -3, [1, 1], [2, 2]] Total time spent: 0 pari-2.11.2/src/test/32/orthopol0000644000175000017500000000006613036414402014740 0ustar billbillU T L H 1 1 1 1 0 -1 209 1 1 1 1 Total time spent: 16 pari-2.11.2/src/test/32/elltors0000644000175000017500000001053613326135265014572 0ustar billbill[1, [], []] [2, [2], [[15, -8]]] [3, [3], [[5, 9]]] [4, [4], [[5, -2]]] [5, [5], [[5, 5]]] [6, [6], [[9, 23]]] [7, [7], [[-1, 2]]] [8, [8], [[2, 6]]] [9, [9], [[-3, 7]]] [10, [10], [[0, 9]]] [12, [12], [[-9, 49]]] [4, [2, 2], [[-29/4, 25/8], [-7, 3]]] [8, [4, 2], [[-2, 3], [-1, 0]]] [12, [6, 2], [[1, 2], [3, -2]]] [16, [8, 2], [[4, 58], [-36, 18]]] [16, [8, 2], [[117433600, 6734213027200], [352179456, -176089728]]] [4, [2, 2], [[-1377493124511464657, 0], [-691668349248679055, 0]]] [16, [8, 2], [[Mod(0, t^2 - 5), Mod(0, t^2 - 5)], [Mod(3/5*t + 17/15, t^2 - 5), Mod(209/225*t + 97/45, t^2 - 5)]]] 8 2 [1, [], []] [1, [], []] [25, [25], [[Mod(-t^7 - t^6 - t^5 - t^4 + 1, t^10 + t^9 + t^8 + t^7 + t^6 + t^5 + t^4 + t^3 + t^2 + t + 1), Mod(-t^9 - 2*t^8 - 2*t^7 - 3*t^6 - 3*t^5 - 2 *t^4 - 2*t^3 - t^2 - 1, t^10 + t^9 + t^8 + t^7 + t^6 + t^5 + t^4 + t^3 + t^2 + t + 1)]]] [11, [11], [[Mod(-78848, y^2 + 7), Mod(-5992448*y - 15454208, y^2 + 7)]]] [15, [15], [[Mod(0, y^2 + 7), Mod(-26*y + 14, y^2 + 7)]]] [20, [10, 2], [[831474369/262144, 519671480625/4194304], [Mod(-59375/256*y + 261214369/262144, y^2 + 2), Mod(0, y^2 + 2)]]] -536129/8192*y + 15673889/65536 -2001779325/262144*y + 115490749725/4194304 [24, [12, 2], [[Mod(-20655/8192*y + 15795/2048, y^2 - 13), Mod(300055185/209 7152*y - 270394605/524288, y^2 - 13)], [Mod(221/8*y - 6461/64, y^2 - 13), Mo d(0, y^2 - 13)]]] -313766195076761969526071169866614175160*y + 1735663223649526033628839600302 712469280 [14, [14], [[Mod(358950904714175557651106659750101468600*y - 224800911486294 2058383152194083021128800, y^2 + 11), Mod(-623358463905364610014856551413519 5275639238995135197696000*y + 7068212904273547655621435172436672299424081219 4549767368000, y^2 + 11)]]] [32, [16, 2], [[Mod(-5089/81696780*y^3 - 7/21780*y^2 - 898639/7426980*y - 12 37/1980, y^4 + 2002*y^2 + 116281), Mod(-8470441/296559311400*y^3 - 41923/790 61400*y^2 - 1494908191/26959937400*y - 7401793/7187400, y^4 + 2002*y^2 + 116 281)], [Mod(-1/900, y^4 + 2002*y^2 + 116281), 0]]] [9, [3, 3], [[Mod(-2, y^2 + 3), Mod(-3*y + 1, y^2 + 3)], [1, -5]]] [20, [20], [[Mod(-2*y^2 + 12*y + 12, y^3 - y^2 - 2*y - 2), Mod(52*y^2 - 8*y + 16, y^3 - y^2 - 2*y - 2)]]] [36, [6, 6], [[Mod(-7/32, y^4 + 5*y^2 + 1), Mod(7/512*y^3 + 7/128*y + 35/512 , y^4 + 5*y^2 + 1)], [Mod(1/128*y^3 + 3/64*y - 21/128, y^4 + 5*y^2 + 1), Mod (-1/512*y^3 - 3/256*y + 21/512, y^4 + 5*y^2 + 1)]]] [32, [8, 4], [[0, 0], [Mod(-37/3570750*y^3 - 30007/3570750*y + 222/575, y^4 + 541*y^2 + 72900), Mod(-731971/2463817500*y^3 - 888/1520875*y^2 - 194058451 /2463817500*y - 51282/1520875, y^4 + 541*y^2 + 72900)]]] [64, [8, 8], [[Mod(-3/7*y^15 + 34/7*y^14 - 191/7*y^13 + 97*y^12 - 241*y^11 + 446*y^10 - 4639/7*y^9 + 5844/7*y^8 - 6441/7*y^7 + 6214/7*y^6 - 751*y^5 + 38 25/7*y^4 - 2313/7*y^3 + 1054/7*y^2 - 317/7*y + 45/7, y^16 - 8*y^15 + 36*y^14 - 104*y^13 + 220*y^12 - 368*y^11 + 516*y^10 - 624*y^9 + 664*y^8 - 624*y^7 + 516*y^6 - 368*y^5 + 220*y^4 - 104*y^3 + 36*y^2 - 8*y + 1), Mod(-41/7*y^15 + 304/7*y^14 - 1269/7*y^13 + 3317/7*y^12 - 895*y^11 + 9434/7*y^10 - 1737*y^9 + 13604/7*y^8 - 13345/7*y^7 + 11526/7*y^6 - 8663/7*y^5 + 5395/7*y^4 - 2675/7 *y^3 + 984/7*y^2 - 223/7*y + 12/7, y^16 - 8*y^15 + 36*y^14 - 104*y^13 + 220* y^12 - 368*y^11 + 516*y^10 - 624*y^9 + 664*y^8 - 624*y^7 + 516*y^6 - 368*y^5 + 220*y^4 - 104*y^3 + 36*y^2 - 8*y + 1)], [Mod(-1006/329*y^15 + 763/47*y^14 - 17540/329*y^13 + 4104/47*y^12 - 29994/329*y^11 + 11747/329*y^10 + 2568/47 *y^9 - 60499/329*y^8 + 92956/329*y^7 - 16937/47*y^6 + 118390/329*y^5 - 10387 8/329*y^4 + 70088/329*y^3 - 5507/47*y^2 + 11498/329*y - 2228/329, y^16 - 8*y ^15 + 36*y^14 - 104*y^13 + 220*y^12 - 368*y^11 + 516*y^10 - 624*y^9 + 664*y^ 8 - 624*y^7 + 516*y^6 - 368*y^5 + 220*y^4 - 104*y^3 + 36*y^2 - 8*y + 1), Mod (-4412/329*y^15 + 35995/329*y^14 - 22978/47*y^13 + 459612/329*y^12 - 134990/ 47*y^11 + 1532149/329*y^10 - 2078812/329*y^9 + 2438613/329*y^8 - 358218/47*y ^7 + 2277477/329*y^6 - 256916/47*y^5 + 1211712/329*y^4 - 660116/329*y^3 + 27 1037/329*y^2 - 9730/47*y + 10205/329, y^16 - 8*y^15 + 36*y^14 - 104*y^13 + 2 20*y^12 - 368*y^11 + 516*y^10 - 624*y^9 + 664*y^8 - 624*y^7 + 516*y^6 - 368* y^5 + 220*y^4 - 104*y^3 + 36*y^2 - 8*y + 1)]]] [27, [9, 3], [[-3, -5], [Mod(-x^4 + 3*x^2, x^6 + 3), Mod(-3/2*x^5 + 1/2*x^4 + 9/2*x^3 - 3/2*x^2 - 3/2*x - 1/2, x^6 + 3)]]] [4, [2, 2], [[-2147484185, 0], [0, 0]]] 2 2 0 0 [1, [], []] [5, [5], [[114135566422431, 27065925164925932985472]]] Total time spent: 345 pari-2.11.2/src/test/32/zetahurwitz0000644000175000017500000001002313457566441015506 0ustar billbill-39 -oo -38 -oo -38 -38 -39 -37 6402373705731389.7030489318955969994839 - 0.03161451804298265316414244332077 7118203*I 7^-1 + 5 + 7 + 6*7^2 + 3*7^3 + O(7^4) 7^-1 + 4 + 7 + 6*7^2 + 3*7^3 + O(7^4) 2^-1 + O(2) 2^-1 + 2 + 2^2 + O(2^3) 2*5^-1 + 4 + 5 + 3*5^2 + O(5^4) -5.1928369229555125820137832704455696057 - 6.1349660138824147237884128986232 049582*I -0.083333333333333333333333333333333333333 - 0.16542114370045092921391966024 278064276*x^2 - 0.12510221205480019464554689634973506093*x^4 - 0.06375525415 3295382246666167409621832044*x^6 - 0.031145268034875919305019134807726637884 *x^8 - 0.015615426994125353615194111434674476549*x^10 - 0.007815030730337130 8864877076428010021454*x^12 - 0.0039060889627778945838882893488620841102*x^1 4 + O(x^16) 1.0000000000000000000000000000000000000*x^-1 - 0.422784335098467139393487909 91759756896 + 0.072815845483676724860586375874901319138*x - 0.00484518159643 61592422651930176062646795*x^2 - 0.00034230573671722431102667442379223071429 *x^3 + 9.6890419394470835727840424063586166704 E-5*x^4 + O(x^5) -0.50000000000000000000000000000000000000 - 1.918938533204672741780329736405 6176399*x - 1.5803938928558252862115621034473826501*x^2 - 0.2511340065366059 1458455559477961793877*x^3 - 1.0420268460244750927971944717696721958*x^4 - 1 .2355192659329334964334864657723974148*x^5 - 0.87257635058071572413411006048 346231123*x^6 - 1.0157624381355636661678145762947417024*x^7 - 1.011397423735 6739590562148571325170411*x^8 - 0.99428399592623009064922131173149736484*x^9 - 1.0001591493497346018358363230868245267*x^10 - 1.001197164231597443144712 3731856234327*x^11 - 0.99896194764310486791418180889565464565*x^12 - 1.00075 70168761786240672304402095851694*x^13 - 0.9994165959675638777241428089233952 4033*x^14 - 1.0004748436041855740380404973564299057*x^15 + O(x^16) -1.5000000000000000000000000000000000000 - 0.9189385332046727417803297364056 1763986*x - 1.0031782279542924256050500133649802191*x^2 - 1.0007851944770424 079601768022277292142*x^3 - 0.99987929950057116495780081365587523591*x^4 - 1 .0000019408963204560377998819816318312*x^5 - 1.00000130114601395962431150487 29797202*x^6 - 0.99999983138417361077993021705801540650*x^7 - 1.000000005764 6759799493944160637416597*x^8 - 1.0000000009110164892314165709218674222*x^9 - 0.99999999985029924058098862647927994292*x^10 - 1.000000000009406895665666 1769096478396*x^11 - 1.0000000000000409258263041583154763659*x^12 - 0.999999 99999993460095194108984774354353*x^13 - 1.0000000000000065439687498919193731 718*x^14 - 0.99999999999999969875751286332132050503*x^15 - 0.999999999999999 99601110529368894450336*x^16 + O(x^17) -0.91893853320467274178032973640561763986 - 2.006356455908584851210100026729 9604382*x - 3.0023555834311272238805304066831876427*x^2 - 3.9995171980022846 598312032546235009436*x^3 - 5.0000097044816022801889994099081591562*x^4 - 6. 0000078068760837577458690292378783213*x^5 - 6.999998819689215275459511519406 1078455*x^6 - 8.0000000461174078395951553285099332772*x^7 - 9.00000000819914 84030827491382968067996*x^8 - 9.9999999985029924058098862647927994293*x^9 - 11.000000000103475852322327946006126236*x^10 - 12.00000000000049110991564989 9785716391*x^11 - 12.999999999999149812375234168020666066*x^12 - 14.00000000 0000091615562498486871224405*x^13 - 14.999999999999995481362692949819807575* x^14 - 15.999999999999999936177684699023112054*x^15 + O(x^16) *** at top-level: zetahurwitz(1,Pi) *** ^----------------- *** zetahurwitz: domain error in zetahurwitz: s = 1 *** at top-level: zetahurwitz(1+O(x),1) *** ^--------------------- *** zetahurwitz: domain error in zetahurwitz: s = 1 *** at top-level: zetahurwitz(O(2)+x,1) *** ^--------------------- *** zetahurwitz: sorry, zetahurwitz(t_SER of t_PADIC) is not yet implemented. *** at top-level: zetahurwitz(y+x,1) *** ^------------------ *** zetahurwitz: incorrect type in zetahurwitz (t_POL). *** at top-level: zetahurwitz([],[]) *** ^------------------ *** zetahurwitz: incorrect type in zetahurwitz (t_VEC). Total time spent: 28 pari-2.11.2/src/test/32/bnr0000644000175000017500000000517313447371554013677 0ustar billbill[] [[4, 0, 0; 0, 2, 0; 0, 0, 2], [4, 0, 2; 0, 2, 1; 0, 0, 1], [4, 2, 0; 0, 1, 0 ; 0, 0, 2], [4, 0, 2; 0, 2, 0; 0, 0, 1], [2, 0, 0; 0, 2, 0; 0, 0, 2], [4, 0, 0; 0, 2, 1; 0, 0, 1], [4, 0, 0; 0, 1, 0; 0, 0, 2], [4, 0, 0; 0, 2, 0; 0, 0, 1], [2, 0, 1; 0, 2, 1; 0, 0, 1], [2, 0, 1; 0, 2, 0; 0, 0, 1], [2, 0, 0; 0, 2, 1; 0, 0, 1], [4, 0, 2; 0, 1, 0; 0, 0, 1], [4, 2, 2; 0, 1, 0; 0, 0, 1], [2 , 0, 0; 0, 1, 0; 0, 0, 2], [4, 2, 0; 0, 1, 0; 0, 0, 1], [2, 0, 0; 0, 2, 0; 0 , 0, 1], [4, 0, 0; 0, 1, 0; 0, 0, 1], [2, 0, 1; 0, 1, 0; 0, 0, 1]] [[2, 0, 1; 0, 1, 0; 0, 0, 1]] [[1, 0, 0; 0, 2, 1; 0, 0, 1], [2, 0, 1; 0, 1, 0; 0, 0, 1], [2, 1, 1; 0, 1, 0 ; 0, 0, 1], [1, 0, 0; 0, 1, 0; 0, 0, 2], [2, 1, 0; 0, 1, 0; 0, 0, 1], [1, 0, 0; 0, 2, 0; 0, 0, 1], [2, 0, 0; 0, 1, 0; 0, 0, 1], [1, 0, 0; 0, 1, 0; 0, 0, 1]] [[1, 0, 0; 0, 1, 0; 0, 0, 1], [0]] *** at top-level: bnrL1(bnrinit(Qi,10,1),1) *** ^------------------------- *** bnrL1: incorrect type in bnrL1 [subgroup] (t_INT). 0 [32, 0, 27656345068767491604576153420888539136] 0, 12, [24, 12, 40621487921685401825918161408203125] 0, 12, [24, 12, 40621487921685401825918161408203125] 1, 12, [24, 12, 40621487921685401825918161408203125] 1, 6, [12, 12, 18026977100265125] 12 2 12 2 [24, 12, 40621487921685401825918161408203125] [4, 4, 262205] [24, 12, 40621487921685401825918161408203125] [4, 4, 262205] [[5, 3; 0, 1], [1, 0]] [[5, 3; 0, 1], [0, 0]] [[5, 3; 0, 1], [1, 0]] [[5, 3; 0, 1], [0, 0]] [2, 2, [5, 3; 0, 1]] 0 0 [4, 4, 262205] [2, 2, [5, 3; 0, 1]] 6 18 9 9 9 *** at top-level: bnrclassno(bnf,[7,Vecsmall([1,2,3])]) *** ^------------------------------------- *** bnrclassno: incorrect type in Idealstar [incorrect archimedean component] (t_VECSMALL). 1.0000000000000000000000000000000000000 1 [[1, 0; 0, 1], [0, 0]] [[7, 0; 0, 7], [1, 1]] 3 1/3 6 1/3 -1 1/2 *** at top-level: chareval(1,chi,1) *** ^----------------- *** chareval: incorrect type in chareval (t_INT). 0 -1 1/2 1 [4, [2, 2], [[3, 2; 0, 1], [0, -1]~]] [4, [2, 2], [[3, 2, 0, -2, 0, 1]~, [2, 2, -1, 1, -1, 0]~]] [14, [14], [[3, 1; 0, 1]]] [16, [2, 2, 2, 2], [[11, 2; 0, 1], [2, 1; 0, 1], [3, 0; 0, 1], [0, -1]~]] [2, 2, 5] [1, 2, [1, 0; 0, 1]] 0 0 [2, 2, 5] [0, 0]~ 1 1 0.99595931395311210936063384855913482215 - 0.0898055953159170744883890303595 05357516*I 0.089805595315917074488389030359505357543 + 0.995959313953112109360633848559 13482212*I 1 1 0.99595931395311210936063384855913482215 + 0.0898055953159170744883890303595 05357517*I 0.089805595315917074488389030359505357521 - 0.995959313953112109360633848559 13482212*I [72, [12, 6], [[5, 4; 0, 1], [146, 71; 0, 1]]] [[0]~, 1] 3 Total time spent: 53 pari-2.11.2/src/test/32/alghasse0000644000175000017500000001111313326135265014665 0ustar billbill *** Warning: new stack size = 100000000 (95.367 Mbytes). Suite: all Suite: hasse sum to 0 cyclo construction: [[x^2 + x + 1, [1], [3, -3], 1, [], [], [[1, x], [1, 1]] , [1, 0; 0, 1], 1, [y, [1, 0], 1, 1, [Mat(1), Mat(1), Mat(1), Mat(1), 1, Mat (1), [1, 0], []], [0.E-57], [1], Mat(1), Mat(1)], [x^2 + x + 1, 0, 0, y, x^2 + x + 1], [[x^2 + x + 1, [0, 1], -3, 1, [Mat([1, -0.50000000000000000000000 000000000000000 + 0.86602540378443864676372317075293618347*I]), [1, 0.366025 40378443864676372317075293618347; 1, -1.366025403784438646763723170752936183 5], [1, 0; 1, -1], [2, -1; -1, -1], [3, 2; 0, 1], [1, -1; -1, -2], [3, [2, - 1; 1, 1]], []], [-0.50000000000000000000000000000000000000 + 0.8660254037844 3864676372317075293618347*I], [1, x], [1, 0; 0, 1], [1, 0, 0, -1; 0, 1, 1, - 1]], [[1; 0], Mat(1), 1, Vecsmall([1])]]], [-x - 1], Mod(-175624635, y), Vec small([1]), [[[3, [3]~, 1, 1, 1], [5, [5]~, 1, 1, 1], [11708309, [11708309]~ , 1, 1, 1]], Vecsmall([1, 1, 1])], 0, [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 2/3; 0, 0, 0, 1/3], [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, -2; 0, 0, 0, 3], [[1, 0, 0 , 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, -1, 0, 0; 1, -1, 0, 0; 0, 0, 1 , 1; 0, 0, -3, -2], [0, 0, -175624635, -117083090; 0, 0, 0, -58541545; 1, -2 , 0, 0; 0, 3, 0, 0], [0, 0, -58541545, -58541545; 0, 0, 58541545, 0; 0, -1, 0, 0; 1, 1, 0, 0]], 0, [4, -2, 0, 0]] cyclo ramified at infinity: 1 cyclo unramified at infinity: 1 cyclo 5: 1 cyclo 5 bis: 1 cyclo 7 bis no mo: 1 cyclo 11 no mo: 1 quat -1,-1 over Q: 1 quat -1,-1 over Q(sqrt(2)): 1 quat -1,-1 over Q(sqrt(60)): 1 Suite: algebra from Hasse invariants matrix algebra invariants: 1 algebra 1 invariants: 1 algebra 2 invariants: 1 test: [[J^2 + 5, [1], [20, -5], 1, [], [], [[1, J], [1, 1]], [1, 0; 0, 1], 1 , [y, [1, 0], 1, 1, [Mat(1), Mat(1), Mat(1), Mat(1), 1, Mat(1), [1, 0], []], [0.E-57], [1], Mat(1), Mat(1)], [J^2 + 5, 0, 0, y, J^2 + 5], [[J^2 + 5, [0, 1], -20, 1, [Mat([1, 0.E-77 + 2.2360679774997896964091736687312762354*I]), [1, 2.2360679774997896964091736687312762354; 1, -2.2360679774997896964091736 687312762354], [1, 2; 1, -2], [2, 0; 0, -10], [10, 0; 0, 2], [5, 0; 0, -1], [5, [0, -5; 1, 0]], []], [0.E-77 + 2.2360679774997896964091736687312762354*I ], [1, J], [1, 0; 0, 1], [1, 0, 0, -5; 0, 1, 1, 0]], [[1; 0], Mat(1), 1, Vec small([1])]]], [-J], Mod(-39, y), Vecsmall([1]), [[[13, [13]~, 1, 1, 1], [2, [2]~, 1, 1, 1], [5, [5]~, 1, 1, 1], [3, [3]~, 1, 1, 1]], Vecsmall([1, 0, 0, 0])], 0, [1, 0, 1/2, 1; 0, 1, 0, 3/10; 0, 0, 1/2, 1/3; 0, 0, 0, 1/30], [1, 0, -1, -20; 0, 1, 0, -9; 0, 0, 2, -20; 0, 0, 0, 30], [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, -5, 10, 5; 1, 0, 5, 4; 0, 0, 10, 7; 0, 0, -1 5, -10], [0, -10, -10, -10; 0, -4, 0, -2; 1, -10, 1, -2; 0, 15, 0, 5], [0, - 8, -4, -6; 0, -2, 2, 0; 0, -7, 4, 0; 1, 10, -4, 2]], 0, [4, 0, 2, 4]] degree 6 algebra over Q: 1 trivial finite conditions: [Vecsmall([1, 1]), [[[3, [3, 0]~, 1, 2, 1], [5, [ 1, 2]~, 2, 1, [1, 2; 2, -1]]], Vecsmall([0, 0])]] better accessors 1/2 0 3/4 0 1/4 1/2 2 1 4 1 4 2 4 0 0 1 0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 [1, [2, [2, 0, 0]~, 1, 3, 1], [5, [2, 0, 1]~, 1, 1, [-1, 2, -3; 1, -2, -2; - 2, -1, -1]], [5, [-1, 1, -2]~, 1, 2, [2, -1, 1; 0, 2, 1; 1, 0, 2]]] 1/2 0 0 1/2 0 2 1 1 2 1 2 0 0 0 0 0 0 0 1 1 0 1 0 1 0 0 1 0 1 [1, [5, [2, 0, 1]~, 1, 1, [-1, 2, -3; 1, -2, -2; -2, -1, -1]]] 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 [] Hasse inv 0 bug 3 9 1 0 [2, 0, 0, 2, 0, 0, 3, 0, 0]~ [0, 0, 0, -2, 0, 0, -3, 0, 0]~ [0, 0, 0, 0, 0, 0, 0, 0, 0]~ tests with splitting field that does not descend [1, [2, [2, 0]~, 1, 2, 1]] [1, 2] [1, [5, [1, 2]~, 2, 1, [1, 2; 2, -1]]] [1, 4, [3, [6, -2, 2, 0]~, 2, 2, [0, 3, -3, 0; 1, 0, 0, -3; -1, 0, 0, -3; 0, -1, -1, 0]], [5, [3, -2, 2, 0]~, 1, 2, [2, -6, 6, 0; -2, 2, 0, 6; 2, 0, 2, 6; 0, 2, 2, 2]]] [2, [3, [6, -2, 2, 0]~, 2, 2, [0, 3, -3, 0; 1, 0, 0, -3; -1, 0, 0, -3; 0, -1 , -1, 0]]] [1, 4, 5, [3, [-1, 0, -1, 0, 1, 0, 0, 0]~, 2, 2, [0, 0, 3, -3, 6, 3, 3, 0; 0 , 0, 0, 3, -3, 3, 0, -3; 1, 1, -2, 1, -1, 0, -3, 0; 0, 1, -1, 2, -1, 2, 0, - 6; 1, -1, 0, 0, 1, 2, 3, -3; 1, 2, 0, 0, 1, -1, 0, 3; 1, 0, -1, -1, 3, 1, 0, 0; 0, -1, 1, -2, 1, 1, 0, 0]]] degree bug *** at top-level: al=alginit(nf,[4,[[p2,p3],[1/2,1/2]],[0]]);alg *** ^------------------------------------------- *** alginit: sorry, nfgrunwaldwang for non-prime degree is not yet implemented. 2 2 2 2 2 2 2 2 2 2 *** at top-level: al=alginit(nf,[4,[[p2,p3],[0,0]],[0]]);algdegr *** ^------------------------------------------- *** alginit: sorry, nfgrunwaldwang for non-prime degree is not yet implemented. 2 2 2 2 2 2 2 2 2 2 Total time spent: 1612 pari-2.11.2/src/test/32/select0000644000175000017500000000065113201017466014354 0ustar billbill[2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] Vecsmall([2, 3, 5]) List([2, 3, 5]) List([2, 3, 5]) [1 2] [2 0] [0] [0] [] [1, 3] *** at top-level: select(x->x,v,1) *** ^---------------- *** select: incorrect type in select (t_VECSMALL). *** at top-level: select(x->x,v) *** ^-------------- *** select: incorrect type in select (t_VECSMALL). Total time spent: 0 pari-2.11.2/src/test/32/mathnf0000644000175000017500000000440213326135265014356 0ustar billbill echo = 1 ? mathnf([0,2]) [2] ? mathnf([0,2],1) [Mat(2), [1, 0; 0, 1]] ? mathnf([0,x]) [x] ? mathnf([0,x],1) [Mat(x), [1, 0; 0, 1]] ? mathnf([x;1]) [x] [1] ? mathnf([x;1],1) [[x; 1], Mat(1)] ? mathnf([x,x^2+1;x^3+x+1,x+2]*Mod(1,5)) [Mod(1, 5)*x^5 + Mod(2, 5)*x^3 + Mod(4, 5)*x + Mod(1, 5) Mod(4, 5)*x^4 + Mod (2, 5)*x^3 + Mod(4, 5)*x^2 + Mod(3, 5)*x] [0 1] ? v=[116085838,181081878,314252913,10346840]; ? [H,U]=mathnf(v,1);[v*U,norml2(U)] [[0, 0, 0, 1], 2833319] ? [H,U]=mathnf(v,5);[v*U,norml2(U)] [[0, 0, 0, 1], 765585180708864230567243002686057927228240493] ? M=[0,0,0,0,0,0,0,0,0,13;0,0,0,0,0,0,0,0,23,6;0,0,0,0,0,0,0,23,-4,-7;0,0,0,0,0,0,17,-3,5,-5;0,0,0,0,0,56,16,-16,-15,-17;0,0,0,0,57,24,-16,-25,2,-21;0,0,0,114,9,56,51,-52,25,-55;0,0,113,-31,-11,24,0,28,34,-16;0,50,3,2,16,-6,-2,7,-19,-21;118,43,51,23,37,-52,18,38,51,28];mathnf(M) [787850171872400 32189386376004 356588299060422 742392731867995 282253457851 430 665185047494955 664535243562463 744564809133574 113975061998590 52745901 3372200] [0 12 6 11 5 3 7 6 6 0] [0 0 3 1 2 1 1 0 0 0] [0 0 0 1 0 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0] [0 0 0 0 0 0 1 0 0 0] [0 0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 0 0 1] ? mathnf([]) [;] ? mathnf([],1) [[;], [;]] ? mathnf([;]) [;] ? mathnf([;],1) [[;], [;]] ? mathnfmodid(matrix(0,2),[]) [;] ? mathnfmodid([0,7;-1,0;-1,-1],[6,2,2]) [2 1 1] [0 1 0] [0 0 1] ? mathnfmodid([;],[2]) [2] ? matsolvemod([;],[]~,[]~,1) [[]~, [;]] ? matsolvemod([;],[],[]~,1) *** at top-level: matsolvemod([;],[],[]~,1) *** ^------------------------- *** matsolvemod: incorrect type in matsolvemod (D) (t_VEC). ? matsolvemod([;],[]~,[],1) *** at top-level: matsolvemod([;],[]~,[],1) *** ^------------------------- *** matsolvemod: incorrect type in matsolvemod (Y) (t_VEC). ? matsolvemod([;],2,[1]~,1) 0 ? matsolvemod([;],[2]~,[1]~,1) 0 ? matsolvemod([;],[2]~,1,1) 0 ? matsolvemod([;],1,1,1) [[]~, [;]] ? matsolvemod([1,2;3,4],1,2,1) [[0, 0]~, [1, 0; 0, 1]] ? matsolvemod([;],[2]~,[2,3]~,1) *** at top-level: matsolvemod([;],[2]~,[2,3]~,1) *** ^------------------------------ *** matsolvemod: inconsistent dimensions in matsolvemod [2]. ? print("Total time spent: ",gettime); Total time spent: 1 pari-2.11.2/src/test/32/logint0000644000175000017500000000022613326135265014375 0ustar billbill99 100 1267650600228229401496703205376 232 6901746346790563787434755862277025452451108972170386555162524223799296 146 116 100 1 3 Total time spent: 0 pari-2.11.2/src/test/32/idealramgroups0000644000175000017500000000157113326135265016123 0ustar billbill2:[[2, 1], [2, 1], [2, 1], [2, 1]] 3:[[15, 1]] 5:[[2, 1], [2, 1]] 7:[[2, 1]] 11:[[2, 1]] 13:[[15, 1]] 17:[[2, 1]] 19:[[10, 1], [5, 1]] 23:[[2, 1]] 29:[[2, 1]] 31:[[15, 1]] 37:[[15, 1], [3, 1]] [Vecsmall([6, 3, 2, 5, 4, 1]), [[[Vecsmall([6, 3, 2, 5, 4, 1])], Vecsmall([2 ])]]] [[[Vecsmall([2, 1, 4, 3, 6, 5, 8, 7]), Vecsmall([3, 4, 1, 2, 7, 8, 5, 6]), V ecsmall([5, 6, 7, 8, 1, 2, 3, 4])], Vecsmall([2, 2, 2])], [[Vecsmall([2, 1, 4, 3, 6, 5, 8, 7]), Vecsmall([3, 4, 1, 2, 7, 8, 5, 6])], Vecsmall([2, 2])], [[Vecsmall([2, 1, 4, 3, 6, 5, 8, 7]), Vecsmall([3, 4, 1, 2, 7, 8, 5, 6])], V ecsmall([2, 2])], [[Vecsmall([3, 4, 1, 2, 7, 8, 5, 6])], Vecsmall([2])], [[V ecsmall([3, 4, 1, 2, 7, 8, 5, 6])], Vecsmall([2])]] [[[Vecsmall([4, 6, 2, 8, 1, 7, 3, 5]), Vecsmall([2, 8, 5, 3, 6, 4, 1, 7])], Vecsmall([4, 2])], [[Vecsmall([4, 6, 2, 8, 1, 7, 3, 5])], Vecsmall([4])]] 8 Total time spent: 1106 pari-2.11.2/src/test/32/vararg0000644000175000017500000000156113244617205014364 0ustar billbill(s,v[..])->if(#v>0,print1(v[1]);for(i=2,#v,print1(s,v[i])));print() myprintsep = (s,v[..])->if(#v>0,print1(v[1]);for(i=2,#v,print1(s,v[i])));print() : : a, b, c, d a, 0, c, 0 a0b0c0d x=5 x=5 y=7 x=5 y=7 z=9 : *** at top-level: print1(":");myprintsep() *** ^------------ *** in function myprintsep: s,v[..] *** ^------- *** missing mandatory argument 's' in user function. : a, b, c, d *** at top-level: myprintsep(,a,b,c,d) *** ^-------------------- *** in function myprintsep: s,v[..] *** ^------- *** missing mandatory argument 's' in user function. a, 0, c, 0 *** at top-level: f(1) *** ^---- *** in function f: b,c *** ^--- *** missing mandatory argument 'c' in user function. Total time spent: 0 pari-2.11.2/src/test/32/real0000644000175000017500000000062113326135265014023 0ustar billbill5.9 E347063955532709820 1.7 E-347063955532709821 *** at top-level: 1.<<2^64 *** ^---- *** overflow in t_INT-->long assignment. *** at top-level: 1.>>2^64 *** ^---- *** overflow in t_INT-->long assignment. 0.E1 1 1 0 0 1 1 0 0 1 1 0 0 1 1 1 1 0 0 0 0 -oo 0 -1 1 3 4 1 1 2 [1, 1/2, 2, 2, 2/(x + 1)] [0, 0, 3, 3, 3/(x + 1)] Total time spent: 1 pari-2.11.2/src/test/32/deriv0000644000175000017500000000577313457566441014237 0ustar billbill-0.65364362086361191463916818309775038142 0.83373002513114904888388539433509447981 - 0.9888977057628650963821295408926 8618864*I 1 - 1/2*x^2 + 1/24*x^4 - 1/720*x^6 + 1/40320*x^8 - 1/3628800*x^10 + 1/479001 600*x^12 - 1/87178291200*x^14 + 1/20922789888000*x^16 + O(x^17) *** at top-level: sin'("") *** ^-------- *** in function sin: sin' *** ^---- *** _derivfun: incorrect type in formal derivation (t_STR). -0.65364362086361191463916818309775038142 1 + O(t^2) 1 - 1/2*t^2 + 1/24*t^4 - 1/720*t^6 + 1/40320*t^8 - 1/3628800*t^10 + 1/479001 600*t^12 - 1/87178291200*t^14 + 1/20922789888000*t^16 + O(t^17) 0.54030230586813971740093660744297660373 + 0.8414709848078965066525023216302 9899962*t - 1.1116221377419663653529706253517873015*t^2 + 1.2415281265413868 062780218754682257701*t^3 - 1.2086763551283186745359503800028237137*t^4 + 0. 99756648563165528612382129965904293175*t^5 - 0.60046085825628373309052750421 982407285*t^6 + 0.017967952623614463202494741978235548201*t^7 + 0.7405545097 7142910348016232166472688835*t^8 - 1.6567879034733145514106563113137871197*t ^9 + 2.7034410910737658601008510753655794704*t^10 - 3.8444448874661633307934 331097517525115*t^11 + 5.0353559133209458942259649372731155819*t^12 - 6.2239 703711772098957775971680803734805*t^13 + 7.351145435617212277584406723929509 9581*t^14 - 8.3518230734703734024304578550750879237*t^15 + O(t^16) 3.5962749997291581980860017516463603814 0 Mod(x, x^2 + 1) Mod(x, x^2 + 1) error("incorrect priority in intformal: variable x = x") Mod(1/2*y^2*x + y, x^2 + 1) Mod(0, 3) Mod(0, 3) Mod(0, 3) Mod(1, 3)*x Mod(1, 3)*y 0 0 0 t*x t*y y + O(x^2) y + O(x^2) x + O(x^3) x + 1/2*y*x^2 + O(x^4) y + 1/2*y^2*x + O(x^3) y/(x^2 + 2*y*x + y^2) y/(x^2 + 2*y*x + y^2) -x/(x^2 + 2*y*x + y^2) error("domain error in intformal: residue(series, pole) != 0") error("domain error in intformal: residue(series, pole) != 0") (-x^4 - 6*x^2 - 12*x + 3)/(3*x^6 + 9*x^4 + 9*x^2 + 3) (-x^4 - 6*x^2 - 12*x + 3)/(3*x^6 + 9*x^4 + 9*x^2 + 3) 0 error("domain error in intformal: residue(series, pole) != 0") (y*x^3 + 3*y*x + 3*y)/(3*x^4 + 6*x^2 + 3) [y] [y] [x] [1/2*y*x^2] [1/2*y^2*x] Mat(y) Mat(y) Mat(x) Mat(1/2*y*x^2) Mat(1/2*y^2*x) -Y*A + Y 0 0 x x O(x) O(x) x x 3.0000000000000000000000000000000000000*y 2.0000000000000000000000000000000000000*y -2.0000000000000000000000000000000000000 -2 + 12*t^2 - 30*t^4 + 56*t^6 - 90*t^8 + 132*t^10 - 182*t^12 + 240*t^14 - 30 6*t^16 + O(t^18) 6*t^4 - 20*t^6 + 42*t^8 - 72*t^10 + 110*t^12 - 156*t^14 + 210*t^16 + O(t^18) -52635599.000000000000000000000000000000 [1, 1, 1, 0, -3, -8, -3, 56, 217, 64, -2951, -12672, 5973, 309376] 1 + x^2 + 1/2*x^4 + 1/6*x^6 + 1/24*x^8 + 1/120*x^10 + 1/720*x^12 + 1/5040*x^ 14 + 1/40320*x^16 + O(x^18) 0 *** at top-level: derivnum(z=0,0,[0,-1]) *** ^--------- *** domain error in derivnumk: derivation order < 0 *** at top-level: derivnum(z=0,0,[1,-1]) *** ^--------- *** domain error in derivnumk: derivation order < 0 Total time spent: 4 pari-2.11.2/src/test/32/bbhnf0000644000175000017500000001276113457566437014205 0ustar billbillbb hermite Z/NZ imagemod [900 130 117 275 85] [ 0 4 0 0 0] [ 0 0 9 0 0] [ 0 0 0 25 0] [ 0 0 0 0 10] [870 11 1603 1016] [ 15 2 1 8] [ 0 5 3 0] [ 0 0 8 3] [ 0 0 0 3] kermod [1] [;] [3] [;] [3] [1] [2] [;] [3] [;] [;] [3] [0] [1] [1] [0] [3 0] [0 1] [3] [1] [1 0] [0 2] [3 0] [0 2] [0] [1] [3 0] [0 2] [;] [3 2] [0 2] [3 1] [0 1] [2] [1] invmod [12 4 10] [ 0 1 0] [ 0 0 1] [3 0 2] [0 3 1] [0 0 1] [30 29 2] [ 0 1 0] [ 0 0 1] [4 2 1 1] [0 1 0 0] [0 0 1 0] [0 0 0 1] [30 11] [ 0 1] [512 0 38 89] [ 0 512 414 178] [ 0 0 1 0] [ 0 0 0 1] 0 [1]~ []~ []~ 0 []~ []~ 0 0 [1]~ [-1, 1]~ [;] 0 0 [;] [0 0] [0 0] [0 0 0] [0 0 0] [[0]~, Mat(1)] [1 0] [0 2] [5 1] [3 4] [1 0] [0 2] [1 2 3] [5 1 4] [2 1] [2 1] [0 3] [0 0] [0 0] [1 1 3] [2 3 5] [1 0 5] [1 0 0] [0 1 0] [0 0 1] 18 8 8 6 [2 1] [0 2] [2 1] [0 4] [0 0] [2 1] []~ []~ []~ [[]~, [;]] [0]~ [0]~ [[0]~, [;]] 0 [[21, -4]~, [-110; 21]] 1 1 *** at top-level: matimagemod([],1) *** ^----------------- *** matimagemod: incorrect type in matimagemod (t_VEC). *** at top-level: matimagemod([;],'x) *** ^------------------- *** matimagemod: incorrect type in matimagemod (t_POL). *** at top-level: matimagemod([0,'x;1,0],1) *** ^------------------------- *** matimagemod: incorrect type in matimagemod (t_MAT). *** at top-level: matkermod([],1) *** ^--------------- *** matkermod: incorrect type in matkermod (t_VEC). *** at top-level: matkermod([;],'x) *** ^----------------- *** matkermod: incorrect type in matkermod (t_POL). *** at top-level: matkermod([0,'x;1,0],1) *** ^----------------------- *** matkermod: incorrect type in matkermod (t_MAT). *** at top-level: matinvmod([],1) *** ^--------------- *** matinvmod: incorrect type in matinvmod (t_VEC). *** at top-level: matinvmod([;],'x) *** ^----------------- *** matinvmod: incorrect type in matinvmod (t_POL). *** at top-level: matinvmod([0,'x;1,0],1) *** ^----------------------- *** matinvmod: incorrect type in matinvmod (t_MAT). *** at top-level: matdetmod([],1) *** ^--------------- *** matdetmod: incorrect type in matdetmod (t_VEC). *** at top-level: matdetmod(Mat([1,2]),1) *** ^----------------------- *** matdetmod: inconsistent dimensions in matdetmod. *** at top-level: matdetmod(Mat(1/2),3) *** ^--------------------- *** matdetmod: incorrect type in matdetmod (t_MAT). *** at top-level: matimagemod(Mat(1),-1) *** ^---------------------- *** matimagemod: domain error in matimagemod: d <= 0 *** at top-level: matdetmod(Mat(1),0) *** ^------------------- *** matdetmod: domain error in matdetmod: d <= 0 *** at top-level: matkermod(Mat(1),0) *** ^------------------- *** matkermod: domain error in makermod: d <= 0 *** at top-level: matinvmod(Mat(1),0) *** ^------------------- *** matinvmod: domain error in matinvmod: d <= 0 *** at top-level: matinvmod([1,2,3;4,5,6],1) *** ^-------------------------- *** matinvmod: impossible inverse in matinvmod: [1, 2, 3; 4, 5, 6]. *** at top-level: matsolvemod([;],[2,2]~,[1,2,3]~) *** ^-------------------------------- *** matsolvemod: inconsistent dimensions in matsolvemod [2]. *** at top-level: matsolvemod(Mat(1),[1,2]~,1) *** ^---------------------------- *** matsolvemod: inconsistent dimensions in matsolvemod [1]. *** at top-level: matsolvemod(Mat(1),2,[1,2]~) *** ^---------------------------- *** matsolvemod: inconsistent dimensions in matsolvemod [2]. *** at top-level: matsolvemod(Mat(1),[2],1) *** ^------------------------- *** matsolvemod: incorrect type in matsolvemod (D) (t_VEC). *** at top-level: matsolvemod(Mat(1),2,[1]) *** ^------------------------- *** matsolvemod: incorrect type in matsolvemod (Y) (t_VEC). *** at top-level: matsolvemod("a",2,1) *** ^-------------------- *** matsolvemod: incorrect type in matsolvemod (M) (t_STR). *** at top-level: matsolvemod(Mat(1),-2,1) *** ^------------------------ *** matsolvemod: domain error in matsolvemod: D < 0 *** at top-level: matsolvemod([1,2;3,4],[2,-3]~,1) *** ^-------------------------------- *** matsolvemod: domain error in matsolvemod: D[i] < 0 *** at top-level: matsolvemod(Mat(1/2),1,1) *** ^------------------------- *** matsolvemod: incorrect type in matsolvemod (M) (t_MAT). *** at top-level: matsolvemod(Mat(1),1/2,1) *** ^------------------------- *** matsolvemod: incorrect type in matsolvemod (D) (t_FRAC). *** at top-level: matsolvemod(Mat(1),1,1/2) *** ^------------------------- *** matsolvemod: incorrect type in matsolvemod (Y) (t_FRAC). *** at top-level: matsolvemod(Mat(1),[1/2]~,1) *** ^---------------------------- *** matsolvemod: incorrect type in matsolvemod (D) (t_COL). *** at top-level: matsolvemod(Mat(1),1,[1/2]~) *** ^---------------------------- *** matsolvemod: incorrect type in matsolvemod (Y) (t_COL). Total time spent: 683 pari-2.11.2/src/test/32/rfrac0000644000175000017500000000042613447371554014207 0ustar billbilly^2/x (32*b^4 + 128*b^3 + 80*b^2 + 16*b + 1)/(32*b^3 + 40*b^2 + 12*b + 1) (x^408 - x^306 - x^102 + 1)/(x^510 + 1) (-x^994 + x^497)/(x^1491 + 1) ((1 + O(3^5))*x + (1 + O(3^5)))/((1 + O(3^5))*x + (2 + O(3^5))) [1, 0] -1 0 0.E-38/x "t_POL" "t_POL" Mod(0, 2) Total time spent: 3282 pari-2.11.2/src/test/32/stark0000644000175000017500000001557013326135265014235 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). 321: x^3 - x^2 - 4*x + 1 520: x^4 - 2*x^3 - 5*x^2 + 6*x - 1 577: x^7 - x^6 - 10*x^5 + 13*x^4 + 10*x^3 - 7*x^2 - 2*x + 1 840: x^4 - 2*x^3 - 5*x^2 + 6*x - 1 904: x^8 - 3*x^7 - 17*x^6 + 44*x^5 + 112*x^4 - 206*x^3 - 357*x^2 + 315*x + 4 63 1009: x^7 - x^6 - 9*x^5 + 2*x^4 + 21*x^3 + x^2 - 13*x - 1 1129: x^9 - x^8 - 16*x^7 - 6*x^6 + 64*x^5 + 65*x^4 - 48*x^3 - 78*x^2 - 19*x + 1 1229: x^3 - 14*x - 19 1297: x^11 - 5*x^10 - 4*x^9 + 54*x^8 - 53*x^7 - 127*x^6 + 208*x^5 + 69*x^4 - 222*x^3 + 29*x^2 + 56*x - 5 1509: x^3 - x^2 - 7*x + 4 1901: x^3 - x^2 - 9*x - 4 1937: x^6 - 10*x^4 + 25*x^2 - 13 2305: x^16 - 2*x^15 - 39*x^14 - 10*x^13 + 324*x^12 + 118*x^11 - 1179*x^10 - 162*x^9 + 2095*x^8 - 363*x^7 - 1583*x^6 + 675*x^5 + 266*x^4 - 124*x^3 - 23*x ^2 + 6*x + 1 2584: x^8 - 3*x^7 - 15*x^6 + 54*x^5 + 16*x^4 - 220*x^3 + 271*x^2 - 119*x + 1 7 2920: x^12 - 4*x^11 - 22*x^10 + 80*x^9 + 217*x^8 - 600*x^7 - 1184*x^6 + 2028 *x^5 + 3419*x^4 - 3092*x^3 - 4712*x^2 + 1736*x + 2404 3281: x^6 - x^5 - 17*x^4 - 11*x^3 + 17*x^2 - x - 1 32569: x^3 - x^2 - 20*x + 13 [y^2 - 145, 1]: x^4 + Mod(-3/2*y - 43/2, y^2 - 145)*x^3 + Mod(20*y + 244, y^ 2 - 145)*x^2 + Mod(-84*y - 1012, y^2 - 145)*x + Mod(221/2*y + 2661/2, y^2 - 145) [y^2 - 229, 1]: x^3 + Mod(-y - 14, y^2 - 229)*x^2 + Mod(6*y + 87, y^2 - 229) *x + Mod(-10*y - 156, y^2 - 229) [y^2 - 401, 1]: x^5 + Mod(-11/2*y - 219/2, y^2 - 401)*x^4 + Mod(155/2*y + 30 91/2, y^2 - 401)*x^3 + Mod(-403*y - 8075, y^2 - 401)*x^2 + Mod(1789/2*y + 35 845/2, y^2 - 401)*x + Mod(-1421/2*y - 28437/2, y^2 - 401) [y^2 - 577, 1]: x^7 + Mod(-67/2*y - 1603/2, y^2 - 577)*x^6 + Mod(1967*y + 47 247, y^2 - 577)*x^5 + Mod(-77523/2*y - 1862195/2, y^2 - 577)*x^4 + Mod(29576 6*y + 7104534, y^2 - 577)*x^3 + Mod(-2094687/2*y - 50316095/2, y^2 - 577)*x^ 2 + Mod(1746805*y + 41959701, y^2 - 577)*x + Mod(-2224753/2*y - 53440401/2, y^2 - 577) [y^2 - 761, 1]: x^3 + Mod(731/2*y - 20167/2, y^2 - 761)*x^2 + Mod(-244695*y + 6750211, y^2 - 761)*x + Mod(21008185/2*y - 579536589/2, y^2 - 761) [y^3 - y^2 - 17*y - 16, 1]: x^4 + Mod(-2*y^2 - 10*y - 11, y^3 - y^2 - 17*y - 16)*x^3 + Mod(21*y^2 + 86*y + 68, y^3 - y^2 - 17*y - 16)*x^2 + Mod(-66*y^2 - 262*y - 204, y^3 - y^2 - 17*y - 16)*x + Mod(65*y^2 + 262*y + 209, y^3 - y^ 2 - 17*y - 16) [y^3 - 14*y - 7, 1]: x^3 + Mod(-5*y^2 - 21*y - 10, y^3 - 14*y - 7)*x^2 + Mod (25*y^2 + 98*y + 42, y^3 - 14*y - 7)*x + Mod(-30*y^2 - 119*y - 52, y^3 - 14* y - 7) [y^3 - y^2 - 16*y + 22, 1]: x^3 + Mod(-10*y^2 - 27*y + 60, y^3 - y^2 - 16*y + 22)*x^2 + Mod(171*y^2 + 464*y - 1016, y^3 - y^2 - 16*y + 22)*x + Mod(-715* y^2 - 1940*y + 4234, y^3 - y^2 - 16*y + 22) [y^3 - 36*y - 45, 1]: x^3 + Mod(149/3*y^2 - 65*y - 1704, y^3 - 36*y - 45)*x^ 2 + Mod(-1037*y^2 + 1361*y + 35544, y^3 - 36*y - 45)*x + Mod(4440*y^2 - 5829 *y - 152187, y^3 - 36*y - 45) [y^3 - 21*y - 35, 1]: x^3 + Mod(-4*y^2 + 12*y + 48, y^3 - 21*y - 35)*x^2 + M od(20*y^2 - 64*y - 219, y^3 - 21*y - 35)*x + Mod(-34*y^2 + 106*y + 381, y^3 - 21*y - 35) [y^3 - 12*y - 1, 1]: x^3 + Mod(-3*y^2 - 13*y - 4, y^3 - 12*y - 1)*x^2 + Mod( 16*y^2 + 54*y + 7, y^3 - 12*y - 1)*x + Mod(-18*y^2 - 65*y - 6, y^3 - 12*y - 1) [y^3 - y^2 - 17*y - 16, 1]: x^4 + Mod(-2*y^2 - 10*y - 11, y^3 - y^2 - 17*y - 16)*x^3 + Mod(21*y^2 + 86*y + 68, y^3 - y^2 - 17*y - 16)*x^2 + Mod(-66*y^2 - 262*y - 204, y^3 - y^2 - 17*y - 16)*x + Mod(65*y^2 + 262*y + 209, y^3 - y^ 2 - 17*y - 16) [y^3 - y^2 - 30*y - 27, 1]: x^3 + Mod(-250/3*y^2 - 1343/3*y - 350, y^3 - y^2 - 30*y - 27)*x^2 + Mod(3004/3*y^2 + 16139/3*y + 4244, y^3 - y^2 - 30*y - 27 )*x + Mod(-2729*y^2 - 14662*y - 11564, y^3 - y^2 - 30*y - 27) [y^3 - 14*y - 7, 1]: x^3 + Mod(-5*y^2 - 21*y - 10, y^3 - 14*y - 7)*x^2 + Mod (25*y^2 + 98*y + 42, y^3 - 14*y - 7)*x + Mod(-30*y^2 - 119*y - 52, y^3 - 14* y - 7) [y^3 - y^2 - 16*y + 22, 1]: x^3 + Mod(-10*y^2 - 27*y + 60, y^3 - y^2 - 16*y + 22)*x^2 + Mod(171*y^2 + 464*y - 1016, y^3 - y^2 - 16*y + 22)*x + Mod(-715* y^2 - 1940*y + 4234, y^3 - y^2 - 16*y + 22) [y^3 - y^2 - 30*y + 71, 1]: x^3 + Mod(-35*y^2 - 108*y + 604, y^3 - y^2 - 30* y + 71)*x^2 + Mod(194*y^2 + 599*y - 3364, y^3 - y^2 - 30*y + 71)*x + Mod(-25 9*y^2 - 800*y + 4495, y^3 - y^2 - 30*y + 71) [y^3 - y^2 - 16*y - 6, 1]: x^3 + Mod(-11*y^2 + 47*y + 22, y^3 - y^2 - 16*y - 6)*x^2 + Mod(293*y^2 - 1260*y - 532, y^3 - y^2 - 16*y - 6)*x + Mod(-1325*y^ 2 + 5696*y + 2410, y^3 - y^2 - 16*y - 6) [y^3 - 36*y - 45, 1]: x^3 + Mod(149/3*y^2 - 65*y - 1704, y^3 - 36*y - 45)*x^ 2 + Mod(-1037*y^2 + 1361*y + 35544, y^3 - 36*y - 45)*x + Mod(4440*y^2 - 5829 *y - 152187, y^3 - 36*y - 45) [y^3 - 12*y - 1, [5, y + 1]]: x^6 + Mod(-2*y^2 - 7*y - 2, y^3 - 12*y - 1)*x^ 5 + Mod(27*y^2 + 94*y + 1, y^3 - 12*y - 1)*x^4 + Mod(-149*y^2 - 521*y - 32, y^3 - 12*y - 1)*x^3 + Mod(410*y^2 + 1439*y + 127, y^3 - 12*y - 1)*x^2 + Mod( -557*y^2 - 1957*y - 178, y^3 - 12*y - 1)*x + Mod(298*y^2 + 1046*y + 89, y^3 - 12*y - 1) [y^3 - y^2 - 37*y + 64, 1]: x^3 + Mod(-20*y^2 - 91*y + 230, y^3 - y^2 - 37*y + 64)*x^2 + Mod(17039/3*y^2 + 25994*y - 195548/3, y^3 - y^2 - 37*y + 64)*x + Mod(-504718*y^2 - 2309993*y + 5792200, y^3 - y^2 - 37*y + 64) [y^3 - y^2 - 9*y + 8, 1]: x^3 + Mod(-y^2 - 3*y, y^3 - y^2 - 9*y + 8)*x^2 + M od(5*y^2 + 12*y - 11, y^3 - y^2 - 9*y + 8)*x + Mod(-6*y^2 - 13*y + 15, y^3 - y^2 - 9*y + 8) [y^3 - 21*y - 35, 1]: x^3 + Mod(-4*y^2 + 12*y + 48, y^3 - 21*y - 35)*x^2 + M od(20*y^2 - 64*y - 219, y^3 - 21*y - 35)*x + Mod(-34*y^2 + 106*y + 381, y^3 - 21*y - 35) [y^3 - y^2 - 16*y + 8, 1]: x^3 + Mod(-3/2*y^2 - 11/2*y, y^3 - y^2 - 16*y + 8 )*x^2 + Mod(10*y^2 + 34*y - 18, y^3 - y^2 - 16*y + 8)*x + Mod(-16*y^2 - 53*y + 32, y^3 - y^2 - 16*y + 8) [y^3 - y^2 - 4*y - 1, 7]: x^9 + Mod(3803*y^2 - 4845*y - 13885, y^3 - y^2 - 4 *y - 1)*x^8 + Mod(-11843718*y^2 + 15087600*y + 43242511, y^3 - y^2 - 4*y - 1 )*x^7 + Mod(2447928994*y^2 - 3118393621*y - 8937617416, y^3 - y^2 - 4*y - 1) *x^6 + Mod(-122752473137*y^2 + 156373216132*y + 448180745635, y^3 - y^2 - 4* y - 1)*x^5 + Mod(2291810549483*y^2 - 2919515812766*y - 8367614391752, y^3 - y^2 - 4*y - 1)*x^4 + Mod(-20378966548367*y^2 + 25960573005885*y + 7440551044 5644, y^3 - y^2 - 4*y - 1)*x^3 + Mod(92972141705228*y^2 - 118436333193067*y - 339449973794721, y^3 - y^2 - 4*y - 1)*x^2 + Mod(-210119040368961*y^2 + 267 668660944174*y + 767164243383345, y^3 - y^2 - 4*y - 1)*x + Mod(1864214244966 95*y^2 - 237480491909325*y - 680642034264572, y^3 - y^2 - 4*y - 1) [y^3 - y^2 - 7*y + 6, [29, y - 13]]: x^7 + Mod(-5*y^2 - 11*y + 7, y^3 - y^2 - 7*y + 6)*x^6 + Mod(143*y^2 + 254*y - 306, y^3 - y^2 - 7*y + 6)*x^5 + Mod(- 1762*y^2 - 3082*y + 3846, y^3 - y^2 - 7*y + 6)*x^4 + Mod(11513*y^2 + 20157*y - 25127, y^3 - y^2 - 7*y + 6)*x^3 + Mod(-39912*y^2 - 69904*y + 87044, y^3 - y^2 - 7*y + 6)*x^2 + Mod(67549*y^2 + 118318*y - 147287, y^3 - y^2 - 7*y + 6 )*x + Mod(-43616*y^2 - 76398*y + 95101, y^3 - y^2 - 7*y + 6) x^4 + Mod(-3780*y - 11952, y^2 - 10)*x^3 + Mod(455904*y + 1441692, y^2 - 10) *x^2 + Mod(-13756392*y - 43501536, y^2 - 10)*x + Mod(90632448*y + 286604964, y^2 - 10) x^4 - 15*x^2 + 17 Total time spent: 7517 pari-2.11.2/src/test/32/nfrootsof10000644000175000017500000000015313201017466015172 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). 46 46 18 2 2 2 4 68 170 Total time spent: 5876 pari-2.11.2/src/test/32/subst0000644000175000017500000000172713326135265014250 0ustar billbillY/x x + 1 0 O(x^2) *** at top-level: subst(x+O(x^2),x,Mod(1,3)) *** ^-------------------------- *** subst: forbidden substitution t_SER , t_INTMOD. Mod(0, 3) *** at top-level: subst(1/x+O(x^2),x,Mod(0,3)) *** ^---------------------------- *** subst: impossible inverse in gsubst: Mod(0, 3). Mod(2, 3) Mod(0, 3) [Mod(0, 3) 0] [ 0 Mod(0, 3)] Mod(1, 3) [1 0] [0 1] "t_POL" "t_INT" "t_POL" -1/-y Mod(y*x, y^2*x^2 + 1) y*x/(y^2*x^2 + 1) List([]) List([y*x^2]) x^2 + y^2*x^3 + O(x^4) [;] *** at top-level: subst(1,x,Mat([1,2])) *** ^--------------------- *** subst: forbidden substitution t_INT , t_MAT (1x2). 4*y^2 + O(y^3) 1 + O(x) x + O(x^2) *** at top-level: substpol(x+O(x^4),x^2,x) *** ^------------------------ *** substpol: domain error in gdeflate: valuation(x) % 2 != 0 1 (y + 1) + (y + 1)*x + O(x^2) Mod(1, y)/(Mod(1, y)*x) Mod(-a, a^2 - 2) Total time spent: 1 pari-2.11.2/src/test/32/fflog0000644000175000017500000000116213326135265014176 0ustar billbill[1, [1, matrix(0,2)]] 0 [2, [2, Mat([2, 1])]] 1 [2, [4294967290, [2, 1; 5, 1; 19, 1; 22605091, 1]]] 17 [2, [18446744073709551628, [2, 2; 7, 1; 658812288346769701, 1]]] 17 3 1234567891012345678 1234567891012345678 12345678910 2739979050900541 1234567891012345 123456789101 1 1 1 1 1 1 1 error("incorrect type in generic discrete logarithm (order factorization) (t _COMPLEX).") error("incorrect type in generic discrete logarithm (order factorization) (t _INT).") error("incorrect type in factorback [not a factorization] (t_MAT).") error("incorrect type in factorback [not an exponent vector] (t_COL).") Total time spent: 2948 pari-2.11.2/src/test/32/bnrL10000644000175000017500000000747713326135265014076 0ustar billbill *** Warning: new stack size = 10000000 (9.537 Mbytes). [[1, 0.38224508584003564132935849918485739404 + 0.E-38*I], [1, 0.38224508584 003564132935849918485739404 + 0.E-38*I], [0, -3/2]] [[[1], 0.69082574035845153597174938200391860974 - 0.141771150359113754753792 96778414429232*I], [[2], 0.45862410662771988186069579649547270634], [[3], 0. 69082574035845153597174938200391860974 + 0.141771150359113754753792967784144 29232*I]] [[[1], 0.86715515057683562588616895054751987122 - 0.645139937243558470804545 79289618230200*I], [[2], 0.69082574035845153597174938200391860974 - 0.141771 15035911375475379296778414429232*I], [[3], 0.7470647877230324158817433610245 1164904 - 0.39601652806157651701402473588976342836*I], [[4], 0.4586241066277 1988186069579649547270634], [[5], 0.74706478772303241588174336102451164904 + 0.39601652806157651701402473588976342836*I], [[6], 0.6908257403584515359717 4938200391860974 + 0.14177115035911375475379296778414429232*I], [[7], 0.8671 5515057683562588616895054751987122 + 0.6451399372435584708045457928961823020 0*I]] [[[1, 0], 0.74706478772303241588174336102451164904 + 0.396016528061576517014 02473588976342836*I], [[2, 0], 0.69082574035845153597174938200391860974 - 0. 14177115035911375475379296778414429232*I], [[3, 0], 0.8671551505768356258861 6895054751987122 + 0.64513993724355847080454579289618230200*I], [[4, 0], 0.4 5862410662771988186069579649547270634], [[5, 0], 0.8671551505768356258861689 5054751987122 - 0.64513993724355847080454579289618230200*I], [[6, 0], 0.6908 2574035845153597174938200391860974 + 0.1417711503591137547537929677841442923 2*I], [[7, 0], 0.74706478772303241588174336102451164904 - 0.3960165280615765 1701402473588976342836*I], [[0, 1], 0.47485156314700469763174924587287075804 ], [[1, 1], 0.86715515057683562588616895054751987122 - 0.6451399372435584708 0454579289618230201*I], [[2, 1], 1.0193283594419870077704818539447783577], [ [3, 1], 0.74706478772303241588174336102451164905 - 0.39601652806157651701402 473588976342836*I], [[4, 1], 2.2792875031056225486323963801897796381], [[5, 1], 0.74706478772303241588174336102451164905 + 0.396016528061576517014024735 88976342836*I], [[6, 1], 1.0193283594419870077704818539447783577], [[7, 1], 0.86715515057683562588616895054751987122 + 0.6451399372435584708045457928961 8230201*I]] [[[1, 0, 0], 0.83081832012833464173087318604481930961 - 0.514580721717982992 96449819908970897243*I], [[2, 0, 0], 0.4261659362390829298602231389837827437 9], [[3, 0, 0], 0.83081832012833464173087318604481930961 + 0.514580721717982 99296449819908970897243*I], [[0, 1, 0], 0.9793575685098820287146296687723227 8323], [[1, 1, 0], 0.84199935117030392785882419071906079523 + 0.220826643447 25718899163157856471416929*I], [[2, 1, 0], 0.6909346057430774286168910363376 2202463], [[3, 1, 0], 0.84199935117030392785882419071906079523 - 0.220826643 44725718899163157856471416929*I], [[0, 0, 1], 1.0152753479257958899423617407 042142699], [[1, 0, 1], 0.83081832012833464173087318604481930961 + 0.5145807 2171798299296449819908970897243*I], [[2, 0, 1], 1.52291302188869383491354261 10563214049], [[3, 0, 1], 0.83081832012833464173087318604481930961 - 0.51458 072171798299296449819908970897243*I], [[0, 1, 1], 1.522913021888693834913542 6110563214049], [[1, 1, 1], 0.84199935117030392785882419071906079523 - 0.220 82664344725718899163157856471416929*I], [[2, 1, 1], 0.7614565109443469174567 7130552816070246], [[3, 1, 1], 0.84199935117030392785882419071906079523 + 0. 22082664344725718899163157856471416929*I]] [0.90088685686467725961014440212013594076, 0.4063580640155376797096153264205 1751587, 0.40635806401553767970961532642051751587, 0.90088685686467725961014 440212013594076] [0, 0.6000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000 + 0.20000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000*I] Total time spent: 396 pari-2.11.2/src/test/32/incgam0000644000175000017500000000471613447371554014356 0ustar billbill9.5490782166243822777948933182313639488 E-306 6.4517096605632180286130396475945591199 E-43429453 1.0805427490386563567297010582115146397 E-14 8.3049286655793859421463034969090657184 E-24 0.E-38 -0.007604873640076879235921450085 -0.007604873640076879235921450085 1.4438595832024935822048821024627975338 E176 + 4.224359849833025384459047779 8091011921 E107*I -0.0096304981549875294045330406967324266080 + 0.0104448408245333075664155335 90425336553*I 3.6835977616820321802351926205081189877 E-46 0.033148544714002591996135923592143390256 [0.048900510708061119567239835228049522318, 0.003779352409848906478874860132 4664148561, 0.00036008245216265865929539411577179720024, 3.76656228439249017 72557995950752726710 E-5, 4.1569689296853242774028598102781906834 E-6] realprecision = 1001 significant digits (1000 digits displayed) 3.68359776168203218023519262050811898765522013690956761970324308577568037914 9250955037826947160993268362230577110061496836716989214907855071445311470563 2214214800120311153618035942174272929063643378947115395627352197174490634249 2683012033541722036066655328102708417224861577032395241919552543821704857579 1038133881414147745573634350151991309184589035264539926631750948004685156693 1899374361029305819637078712617022128735026710549374269865118275697787239064 9991027682952231969799549304090829468335748935154281470949071433111492071075 1767849583590888814450823588721920568263412763123076003634199144923928930230 2664745888505585350305095849977148442159142952183358896948374051498045266578 8430696482922647521423833733233609936621457658644695029880537347596251466117 5788754599498196161120801923825870392159899899969875656841020930930028966473 7128930613953196310035735416832096667412906792274453172606232569623655768685 0600705332240514673617947823961471228466621963387238011480537605649806838965 7919746393664 E-46 realprecision = 481 significant digits 4.75192490656016273728795810646514224344948226385534946774854953981091171184 5548377731754871666027106541752645628899410605265552482172045603954059223044 9909582386495215175154235730928812285673186372640110666892550763379643115805 1645655068324986893656866348640914630478382436361571896386505720797343025328 1801089025819604231751731641093222001525360979162684147070957434471241677012 3171321323534000876101297696945758112884328591356813522962187412618386959055 56983544264467232044835371 E-68 *** at top-level: eint1(0) *** ^-------- *** eint1: domain error in eint1: x = 0 Total time spent: 538 pari-2.11.2/src/test/32/elliptic0000644000175000017500000001202013326135265014701 0ustar billbill echo = 1 ? ellinit([-1,0]) [0, 0, 0, -1, 0, 0, -2, 0, -1, 48, 0, 64, 1728, Vecsmall([1]), [Vecsmall([12 8, 1])], [0, 0, 0, 0, 0, 0, 0, 0]] ? ellinit([-17,0],1) [0, 0, 0, -17, 0, 0, -34, 0, -289, 816, 0, 314432, 1728, Vecsmall([1]), [Vec small([128, 1])], [0, 0, 0, 0, 0, 0, 0, 0]] ? ellsub(%,[-1,4],[-4,2]) [9, -24] ? ellj(I) 1728.0000000000000000000000000000000000 ? acurve=ellinit([0,0,1,-1,0]) [0, 0, 1, -1, 0, 0, -2, 1, -1, 48, -216, 37, 110592/37, Vecsmall([1]), [Vecs mall([128, 1])], [0, 0, 0, 0, 0, 0, 0, 0]] ? apoint=[2,2] [2, 2] ? elladd(acurve,apoint,apoint) [21/25, -56/125] ? ellak(acurve,1000000007) 43800 ? ellan(acurve,100) [1, -2, -3, 2, -2, 6, -1, 0, 6, 4, -5, -6, -2, 2, 6, -4, 0, -12, 0, -4, 3, 1 0, 2, 0, -1, 4, -9, -2, 6, -12, -4, 8, 15, 0, 2, 12, -1, 0, 6, 0, -9, -6, 2, -10, -12, -4, -9, 12, -6, 2, 0, -4, 1, 18, 10, 0, 0, -12, 8, 12, -8, 8, -6, -8, 4, -30, 8, 0, -6, -4, 9, 0, -1, 2, 3, 0, 5, -12, 4, 8, 9, 18, -15, 6, 0 , -4, -18, 0, 4, 24, 2, 4, 12, 18, 0, -24, 4, 12, -30, -2] ? ellap(acurve,10007) 66 ? deu=direuler(p=2,100,1/(1-ellap(acurve,p)*x+if(acurve.disc%p,p,0)*x^2)) [1, -2, -3, 2, -2, 6, -1, 0, 6, 4, -5, -6, -2, 2, 6, -4, 0, -12, 0, -4, 3, 1 0, 2, 0, -1, 4, -9, -2, 6, -12, -4, 8, 15, 0, 2, 12, -1, 0, 6, 0, -9, -6, 2, -10, -12, -4, -9, 12, -6, 2, 0, -4, 1, 18, 10, 0, 0, -12, 8, 12, -8, 8, -6, -8, 4, -30, 8, 0, -6, -4, 9, 0, -1, 2, 3, 0, 5, -12, 4, 8, 9, 18, -15, 6, 0 , -4, -18, 0, 4, 24, 2, 4, 12, 18, 0, -24, 4, 12, -30, -2] ? ellan(acurve,100)==deu 1 ? ellisoncurve(acurve,apoint) 1 ? acurve=ellchangecurve(acurve,[-1,1,2,3]) [-4, -1, -7, -12, -12, 12, 4, 1, -1, 48, -216, 37, 110592/37, Vecsmall([1]), [Vecsmall([128, 1])], [0, 0, 0, 0, 0, 0, 0, 0]] ? apoint=ellchangepoint(apoint,[-1,1,2,3]) [1, 3] ? ellisoncurve(acurve,apoint) 1 ? ellglobalred(acurve) [37, [1, -1, 2, 2], 1, Mat([37, 1]), [[1, 5, 0, 1]]] ? ellheight(acurve,apoint) 0.81778253183950144377417759611107234575 ? ellordinate(acurve,1) [8, 3] ? ellpointtoz(acurve,apoint) 0.72491221490962306778878739838332384646 ? ellztopoint(acurve,%) [1.0000000000000000000000000000000000000, 3.00000000000000000000000000000000 00000] ? ellmul(acurve,apoint,10) [-28919032218753260057646013785951999/292736325329248127651484680640160000, 478051489392386968218136375373985436596569736643531551/158385319626308443937 475969221994173751192384064000000] ? ellwp(acurve,x+O(x^33)) x^-2 + 1/5*x^2 - 1/28*x^4 + 1/75*x^6 - 3/1540*x^8 + 1943/3822000*x^10 - 1/11 550*x^12 + 193/10510500*x^14 - 1269/392392000*x^16 + 21859/34684650000*x^18 - 1087/9669660000*x^20 + 22179331/1060517858400000*x^22 - 463/124093970000*x ^24 + 47495017/70175140035000000*x^26 - 34997918161/291117454720092000000*x^ 28 + O(x^30) ? q*Ser(ellan(acurve,100),q) q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + 6*q^6 - q^7 + 6*q^9 + 4*q^10 - 5*q^11 - 6*q^12 - 2*q^13 + 2*q^14 + 6*q^15 - 4*q^16 - 12*q^18 - 4*q^20 + 3*q^21 + 10* q^22 + 2*q^23 - q^25 + 4*q^26 - 9*q^27 - 2*q^28 + 6*q^29 - 12*q^30 - 4*q^31 + 8*q^32 + 15*q^33 + 2*q^35 + 12*q^36 - q^37 + 6*q^39 - 9*q^41 - 6*q^42 + 2* q^43 - 10*q^44 - 12*q^45 - 4*q^46 - 9*q^47 + 12*q^48 - 6*q^49 + 2*q^50 - 4*q ^52 + q^53 + 18*q^54 + 10*q^55 - 12*q^58 + 8*q^59 + 12*q^60 - 8*q^61 + 8*q^6 2 - 6*q^63 - 8*q^64 + 4*q^65 - 30*q^66 + 8*q^67 - 6*q^69 - 4*q^70 + 9*q^71 - q^73 + 2*q^74 + 3*q^75 + 5*q^77 - 12*q^78 + 4*q^79 + 8*q^80 + 9*q^81 + 18*q ^82 - 15*q^83 + 6*q^84 - 4*q^86 - 18*q^87 + 4*q^89 + 24*q^90 + 2*q^91 + 4*q^ 92 + 12*q^93 + 18*q^94 - 24*q^96 + 4*q^97 + 12*q^98 - 30*q^99 - 2*q^100 + O( q^101) ? bcurve=ellinit([-3,0]) [0, 0, 0, -3, 0, 0, -6, 0, -9, 144, 0, 1728, 1728, Vecsmall([1]), [Vecsmall( [128, 1])], [0, 0, 0, 0, 0, 0, 0, 0]] ? elllocalred(bcurve,2) [6, 2, [1, 0, 0, 0], 1] ? elltaniyama(bcurve) [x^-2 - x^2 + 3*x^6 - 2*x^10 + 7*x^14 + O(x^15), -x^-3 + 3*x - 3*x^5 + 8*x^9 - 9*x^13 + O(x^14)] ? ccurve=ellinit([0,0,-1,-1,0]) [0, 0, -1, -1, 0, 0, -2, 1, -1, 48, -216, 37, 110592/37, Vecsmall([1]), [Vec small([128, 1])], [0, 0, 0, 0, 0, 0, 0, 0]] ? l=elllseries(ccurve,2) 0.38157540826071121129371040958008663668 ? abs(elllseries(ccurve,2,1.2)-l)<1.4e-38 1 ? tcurve=ellinit([1,0,1,-19,26]); ? ellorder(tcurve,[1,2]) 6 ? elltors(tcurve) [12, [6, 2], [[1, 2], [3, -2]]] ? mcurve=ellinit([-17,0]); ? mpoints=[[-1,4],[-4,2]]~; ? mhbi=ellbil(mcurve,mpoints,[9,24]) [-0.72448571035980184146215805860545027440, 1.307328627832055544492943428892 1943056]~ ? ma=ellheightmatrix(mcurve,mpoints) [1.1721830987006970106016415566698834135 0.447697388340895169139483498064433 13906] [0.44769738834089516913948349806443313906 1.75502601617295071363242692695662 74446] ? matsolve(ma,mhbi) [-1.0000000000000000000000000000000000000, 1.0000000000000000000000000000000 000000]~ ? cmcurve=ellinit([0,-3/4,0,-2,-1]) [0, -3/4, 0, -2, -1, -3, -4, -4, -1, 105, 1323, -343, -3375, Vecsmall([1]), [Vecsmall([128, -1])], [0, 0, 0, 0, 0, 0, 0, 0]] ? ellmul(cmcurve,[x,y],quadgen(-7)) [((-2 + 3*w)*x^2 + (6 - w))/((-2 - 5*w)*x + (-4 - 2*w)), ((34 - 11*w)*y*x^2 + (40 - 28*w)*y*x + (22 + 23*w)*y)/((-90 - w)*x^2 + (-136 + 44*w)*x + (-40 + 28*w))] ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 26 pari-2.11.2/src/test/32/resultant0000644000175000017500000007343413457566441015146 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). 1127614608 911045 -23334121 15152875237197769342976 1 4789697380021054650345938381924768779764502171151476021251465336909773783338 1483478046719619493978767437813786102680708004930493639232124484712989030743 77376 5591778626126198515789740127923726924138993122908566507963011388676468961202 4477425313882678703984217553283789132475364222241284814412314235455434422980 7710892411505927222662178875831559611191917768447356156048451344207870859235 3421574869121809933510172523951949560305425573780083942051414584453903225103 9150588607156375894233737091156899560058104991022009737098022791771063870332 4543754376917999871790501326547853054436444495861161564399190140572883960196 4316196975817429852098537493490087741730840438498474174124950599821563462379 4776250318165223172258299094200163699119837367865451816040219464272808536682 6366448478399563694093511562444580982947874089384832363620244514399470126325 1221138634876570856880659380036429623915483515843179086549287327024998004564 7976338198194174093893290033883921204928495263532870000949040615012556044932 1818817854986256664488406380789052297112100244473983193254140610618060591371 899564340082899114785688720906351258905787053899776 7081072488122549108437740087055070486542322805098742006332199056679193928966 4483785295568554162322036400017122263928267064345800987077874888846659771496 6170549511731996859294513678297798592859196096017665960363670523570420377721 2919429331810768214726379757777338665118630273090090442002357392565485086331 5412450577546522243130333620009107379345899855572005517250317530197793851722 3355902478870693674755098498729934799138680215415329581514280083638477701043 9833756129716245879910591555562933614970015160148305939648207485535526079234 0506699237254741161806485754160707356885468112747818240990343439929195771261 5718119731260544392168170080797529909765466194544434766073431138630521097535 7468986434676998993972786577010278592120332643280493735615754118765736720057 2393565271488265393041765173848995399894723709392064991834838703664591278597 3082437298288444379811881610029611376601722270737965832251382983968232233649 8871844617255503719150928022965927019986189521620111495073311653079160054784 6857440559795860180426346941115122603046544514726275045580655957003854337394 2366607422738440023830359041009316801704138433518791880556684554000725519633 6314221737402120724621182545795068118781015520862409165116892715165782201744 7373528760095126876619409888737755809138526698545586130093257520346765161706 3668856674264264360780430404097555123190894892970707035925992771214318693453 9933063048724159581078642517219830228441155730464252333929338601304473477379 9924164123779424453250220315240908440937220701876898151966131532288459419998 7193319301791449277695747801099373571458888429427291702061589949699722004575 4707271425056836723915364693803883154598841808528064617757070166253079521282 9330993749058818913084870487521920089024720415354689556927595116643657782190 7772163668281509363539079928183803467678757273373526894367221203626621799795 0834794280858064768554880652430560684135485447762704940367795197161950331922 1933358870993764673870859837952485667866798702804457244640778314935644379077 1781507677136287186820379853171767323733496951804295617087357625661051104152 1796342712986360278714707030680719176226964227465901389213818171046492873465 0022790780563242373313610025898026386690016904386357791379547299812905227390 1289797056874223293654886944596148419408207352315947914652557188420178927934 2848619416825409009261520189608713137382207964171283558993905022859982486695 9083539842491853405079547629485109169490879476146913423588991526498785270327 3968511118988030085179508566878601698165562240004498473335561372165388144302 5299351926733300122236311522899635357333042443410986368545768414279154922277 9119056516432750446537012271038703954019716627215359282310427886580436806649 1128763133722567880219150198570570334214903477999954881887377115447377529450 4743238205391224700586995860603351466477628176669368096677069674459366626343 1922851858053123966451232560199488110901933493373773342297093283394419388248 4588916794714441254931339361853072424034331084764085081987592855543881808243 1779116507645535321440983529543254866843835344498356598259597110076846725320 6851381772957660420342635656117691678289746109819594274521914714099658185017 8103384766865875768775851148845968289169127685348378811992123602296633104373 2805377772394628665071343459476385073839007177030802143173978958766607853438 1299576637513893400073478172504247752287917016974831919723343256352815430862 2756735538729480299222282240438655236155081637699288961373884981739501718182 2681375497299984831021291189018514228948558064909058423273859290080459595571 1759917019292934458035585962564362223881131293139396977742617328161512636776 1481197065944479079708702464472102740839784622024302517281715139380530650311 1915971888668147117514765329906797514964395684832725088547469451338928840681 2720007091412810257156421902095403437335707368255329889993567282476060201844 5771396723720966942646908853851819209514039160674238448209530171041506333081 6987469227749752421380683026987025045039827341868747252476484201784372446710 3510248767574924856801643658855141372196574234941500177109628589376464368340 2999855256027646684276215612404965044584115542842898614670574653437772506535 4923273222262319450335041587329691932221764773887410781545905870741527518830 0856696173015051150711714497101540120133632210837848926748871140267926449098 1423419401755524300390263874468295460307895598999553133968897373983301216878 2734049667608533709411627027619810284143582046196764517591998490057580029106 3609272592147333011404236522621245214993427142890298259090018689952508140536 9654638037034014821665971679425142385118234439462497731669309557480650496918 1834649980677855020436832515946267480139639823701397028549118270169170519415 6721794171223686532838514733056067604528123664171806646382399462634890916813 6669485840561432308522405899924251087786067664162652793044413599537424129707 5477186898973633516352568883257904332028806586709401569864515982688222129153 1567052855728262995530434353630134178070106956944279797548165372439216825076 8326715576786303582598430095125742864236163720296213905787039885884463657834 4643437508267891744779261877500947228066699509369586576615123985367219743858 6658022062041430002005181878216355419666743135504759692658299056669357259645 1140384349942471935622171122262819380938871819723106690671480887238746092900 8259392457845570085120138974098112147614179833839988811199774487498092129908 2525330985586942998714786716070693999685611141806930181168204974764634546790 2491116660085873519752267226746027234992210672340901561111569016509087980484 7241366934438873990966498559499978863196895478498708930733440029703211754971 3174338633455354574979245770026845320172157118052425714203442756762690452556 2195168177038659757872091439804829007952032160043794866268382905222485457033 4877085046605283955920544774598658688901188561694172099986871239644906361688 0166806589820637842653846370311841209424194808154992103008317976618840646505 3524843776927351496372745683004763216358973783229858596853568141313750965802 6732704253827791291256677915251801050186660146187981397142021248163932831949 1242424936332974106235910726775448936949225963230406509254485317395735192765 9629100658168052496684342007876499412743472614751505477517198117059603151774 0513333347014771131213527388744277817255738469560576073881746517093241538950 8379623995721601203434646863118546318466543153575568871197413866654425349795 9709665081383739157130696886846685180184094150972054886673926466898476160056 9251865200870473249492728358926161261942133179621059876513623829755485965508 1765991185475814355042047437792982556193134305138749561348141122718465434028 5955347577189501961066057321746605591478524411065032570202848093134945388063 1469805925510862902366653958969425851152732736769061502994730346813692391400 2188444260504305088747166891225921799545810287134453936174360046753896543846 4725311018589188158298923975056694464632127746952940324604386896534946901154 0189748233921118167859285574717815593009931414748460169210424421915763646667 2549643791464812661184224613907766599594347549012695657501957708976598982379 6246315465707511680970636654737842632945349283341207033490434420327941078448 1247500527894528017587459786622669024443518026949815548731423263169447248228 5110467004911800020475713052104208484239152280018530719982927713299542152131 6714018358725068038634436774574546773146283899186292132944165251525364117406 2333682077664235142911764750699483904374984050720750763989372219539833457960 7517904946980952462925255681650144231984545917747245637003964519102283728734 7801223416232398530453943213234148790697908440512084299095779197332999945341 4964437542186365784691171021464796820401539232838986619037169900580166453697 8875543972648384797560654661388477062010340611513997845689183412371725641192 7259435812034642758959741241517961837062742047554891249269300463738657711558 2873355887128229794245851803952135238397923971740033612324297035200484275438 9156423664686366531825242597376576860994929676476159165395192353567061116835 0879052026395527993330789894200638408494686144201609307220354927475939107543 4100442246166647741053132902356715119673330523458821912870829882436969397956 9406895726081967239095445456258787542857469923106451553636440562462133562360 2668811067192149078795792377466748973463935910225355341714595027831656267131 7448279182843337911131360717637361214496493274000813932176510723999645466023 2577690480408703033440600514220628547543775356283381461661090490710822064909 4442349542870358299272174730711563333091694493018076280359800542459534086476 1753773084515412810070994263488287449786031849963340685709770929949412357769 8595467102933787819050340231630643521983014085233294591129365647969335691870 1645312144680039661515859963988461311015875682686126364930986339192596055528 5415821644430946059242051021689727062158285718368764970142254220221251016570 1562643814866019675250331401163912499653408827720323147052395354630909040950 2449569343309008357721192162211813923928897216896982491145981783817245900369 5174601436757895126770570726969854492290667489978001725658920553817006873736 9361312619106558444263836067946213531312792247596380264510333469355965494293 8057756424419773526095629957221330300887874765988164844737994868164641605222 2825624132991984850324866986619296607978229622915429194579009932988226000946 2799716898319535999601514182213198784020927602509705335937317436616464565386 2872053875185499951244257832174070631688990682874482631471691339296616648363 3357285120715643816652078133798755984077111980231423933018801082978392585421 0557410505624607436448090236794246925372257552335205668157924552625077577745 1444994285443412758408944565156472565466791294345215703318051430639461056798 9104112885134043465540265984546300434414876490392033240018221222923160975692 3574118451325235191746732118645012230660740739534589705361993281591810042848 1386376501091030428196191317149726249705003607276293632768455631898002411316 8723568666921731614366149245523567264036839088882693159534231662113318927190 2700597763458658138616263432657882123932584966891493766304566230992548511870 1578565808767928420814686276337773212621085152030353396508799832670048785694 9458195423731556131061003012038999565838203945938486770903260446305772890830 7066407095099849010110311279170801482672160151298019450205523688931455046837 2696701818054864809290668621005085842719448633255369262839048473607324076854 3876512651160078271451580705114404951011889183775018819798848974826562003664 6661732798500898437911439686901081863261839430043923237046283466602427871304 8506953093641642163367712127257564040734310940434747428181583577390637815785 0568728380279883244330109231305923546694823757987289677640095975011241184318 9915958392805871916668742980025522360460089258695511886998639786040952838129 9175637805687931816598611425185730113293288911861332695586714572145658115029 9844338849992973326251312720024106411331530108183020506081531934467942310766 5480466436597036298814762723036190616555337378880978653796168575503594499080 4938901966476145425173757988475188344145289435972780305559861056903328353435 7097324796734880384585281130228000670331841246489779777755289555189750148212 2460528569662635491485226214600657466593819032606384448441494814219184451373 2970238465927788712086864971958121372221766814952929308218481647008620534821 4870259320816045694040663489812592473817436697294095899807395498397055191786 4246700427676626086795906762335651942030658186154911718028023640965476401541 6331290138619972853394139193068857312592167829698870990849405149987021278969 3611178142790638697562338466404270499149409798871543973677872220822218818707 9274126492516822409042659368169703465936982972778620219021231830098682652554 0129952966507080659132966853812023584303362666270317227465529934100811015105 8868990725432564987605223395940547374046157871476155638971225706634706527197 2100070728017924350626608177098973079265381463675975950527323756525988663565 2792980895669484248299410038263537660623017805311298685765900580697924240570 4587261148427817001651793337528843665500553095898064074090246369336456936473 4373803950522485651344423864279448523115897237705822685322793258751461529039 8924994348239102187147135789338076432776608620822393601589765157207326701598 4974900600705558869601187220120358321975167707693820494316713534023111843805 9283173364786844421849556149175619273166387467854407493491717116722424505053 1728410586881113103309453413145528185963208374232941772791717539803691080384 2397504701077839217768067902076125594575708755459937027409745203440094884479 5140234505133742864665356178364606835448830939783260650214862842555014663195 6415594335179574317671856504206447373591062916029471992300116963386628460524 2847904416596141934741828146379809581664158905733011925952574996015569831756 9703063616018931599351925057216994635704120606881418401365121636867122399809 2774750147634980569429662641208390283422787696005105225767492395514821395148 2324024851334114743756051875991639774324459647227599873088565986456465788550 2092343371481239343113881272770926693174789149230168249996032172137615301356 4980996965817634459665187513080922525605201604845857286564525064751439629278 3000725290349331142295275597309690835948790615844571089136616960068195339705 6194453861378417806817597789190149182835100252960383932417019745974444767099 0624786637634290275002442959915995647243356991025785049598063354253091991467 2884054539571691939828506354835147188797863438910609128541007455256683557131 0562342964055240007307201315671721394884726343064451522335113780730215996618 7001991699723165212904103307749537867071104955163912366676956060671585948075 8856561990076412149919627753695230757225285324756951063606903236791929080189 3973661505448117852920548942305793298953857044793936910063454602785182803429 6064134170981414962838068243888581694538254933156788556169768331700594145992 0829625229407628504478197743358306906062714062770191995932116159202455454698 1833772637944551971708296532225251958444281762416016999602533345461193450313 0648189438004061438499414165320145166394394137001741494601734265729049916536 8786615510481765352709341172007999297661820452214994434444847483883226297140 1401674898781247484082998956186471711709567755084249521203388115453739850984 8201380092084758372275724538800301564602934678377853362331910728064061151092 9552063475242103758900477732246484302256511528132759160221241392285002767024 3669353741641622336731841455767829054402291230797389101828234070416279585998 4177436328311159747118290973201619007228947454290436250321638835917076230562 5908006734101378403247160809171990515159263712996771840506632764382172811486 1045805889911666828084633587319003655886973250316525236916645981137835447238 4293626020194196895754257039489866614124700604916502009470350933899248574263 2433831333725836823737934116481556444659294843962623404784927612972830908818 7995066167536899612315082598662649426372702024801212726876754386409528327484 0407885195827599897275621697816182411963589270076348733404107791216013908821 3312645242645005779272501822320994675104938946391158040143587955328884418481 8552189233778681399753847414887764033120998535989960058575892967832407772128 1486370558522744063535928001892364461867715745222791284527793212818188214212 5151430384435843528957786512789031489302505302683680671161908878734972360980 0169606010403993591690593687152871349591312158380146505938090653290650464244 2393715616059833231533447758770144994797243194913401125749757861887967071474 0668243840880239975410140487167665497226423304105183321456942712666755366048 4513930715943788103872965224019765145227252865954271143477545308093565624554 2038273819668351030692714185064237433409989989843369326821584267652829971183 1047748516522526723332327680235436145444057502299686617058124219054013357604 2058644381474119584378752212603826077589535634202050954327560432207418222041 2946673374895032454261423042963903275402019846909997207392220695906575618068 1181429287813762522813907938908102094558672580674959851503384043646005266215 3556850616430494449519453861414586052518051253449165323698938124942367235337 0262664752264544375885466166799033815620881800700646346140590254007360813756 6106251312723308725668659882494606260328217635132797924501855990617961457672 1019271798366689077713053020708507055485816592439719097528763798162719234761 5768842729973762210377565701985356010572319029207706749810973378297162497315 2429257893364899813089138087002591377752115806621791689735535324942239281389 7707658659115297091177669024303780469123021110257015997626532926986838094760 0251473914561276418783777747329910981979578981148252984143759266894331122042 9041445345958715283155660279310587345830247860448837525261315766198993992499 5959135476557955828889140898705619068986297758402572687925341338893322191018 4951574210527100911563052359377857775455187162182640677583563839405015418626 6271003135442406476904292013486173064280165102275860877358055961680377018117 9407258058194062595343490331433128277476287025562338780716296607863734421964 6398504753473310937624280680487514461999171822917905958714467444259409540096 5125686461106746954329208107230838711949699315085161624573548764472629924000 9388826927578163869644055897801290539733180405120167542888739695296935787527 2277231024000866999422003496826219681773340717008049883536929150209759419719 2476724495228873880421184843573662693488497521949703654293617023731876188021 8161101036337107718919946052334638989394796774173354409309562498787726965123 8501379728687520420137037318041140155292864410431179358106654346624235823545 3064016217648136175289259908242738578378187682097303323420320267640427880197 0546103037587443506906154893888189366292745693373465818296838130553615764337 2012379056702209339738530032711295715914291111593610024223834654681234489950 2995984070241882647259917195419249566653665169904729139657919194431471824505 6330324626778144078219820414708337050772319628837159448612020902643054481443 7785951186072214743077777545529851432900878096517420251324683967383472320646 7072171826870056133206946006956594590822413225672457103287494913610929672857 2802979513803760415959689167004444098745469704235693893440234078348358992130 2902412804083486203809602146349295979585966691897800454007145734217841442504 2509656059394416722763927807238311390512732351899114617488579954637344893472 6956418040020563753576439361112293250812538205606862069824031389592220753938 3931980444000396952790300025110413488020461314044867096400482555611861766557 8779872633208790282853041828436599000821439615909297936909400476874231409386 1107957033048878824727553773211614689966672780402203443704886999018746632918 4578570059506705179295259119648586493455744160376834283354774861549013613756 8914104974148435789675196156799768181676487349484914162264963803701991647308 7077370046772797817386919223496396655554669074903108105861101273892479122450 4487000094244471654652318170723070150479698387577348165943027364806795695771 1605973865900671088466048319535078791374564546245300366331708247635343933398 1970452195592950156793361600483926819755275149212838754795843185318110832468 1382112309145641859606129754154071672948878109857709847136184953440514957541 3641496697051930106770483801168708463106269498367706651154782577811514002639 5106563888263605829321212608718331459495599039042081814718848457860199057649 5346982843071231821350857965681984563335821957754569468382305016184024887604 8160723684261393716356258451730935748281676054966556038316792751070826540054 2473315712042588604514882868227176108332833877184166366265303737221912013662 4512167901067209682554392111071155499467651327936730515479173229263731514370 3330182513953368428655392818025057917570653783124434362274261551843983160477 7351162406242450929672186628419950329891867814208035883609977838886238833276 5330774679847630559105909002838233097431528046724187446177909715044255520881 8889404837062703651637318360772404220635983462926485432718138685237631857455 0598465166755132919094585655974966874524784130599703711634113352005177406926 9603316645497284293848590370977640427328887687375912505822778917514360380115 5682283488759427844250167972992511302878057532531484502529732162662116955639 7406173957119233848745104829248262313597011029557702426889396863083570940205 7509537898825756241704038780955282562441114537127841752209332467489719207566 1744264901601182958290811929305241680377823312435028072780502748828361181784 5922938685656775729737638617283841787967835602522574138712851435180707114732 7070864077169181369700790505644456673957432875813509347521540262444684384812 1628162757064794714790594967511664494982986431532091869678632267880119090181 3358285913239640118632956526316790292934199787619720599635756782126973040030 8849995749515739684821341699562520787829013184888043096654760631188226253631 8585742707987188915896804232114765200530074024419150347592072019161120869323 4748482955558033228065455570160118248780022998383870238441158071327622059726 4610703982594367716830470741988537826072641367377235148800000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000 6424194875218376701463113579276658235425909119319864401234806441094021127054 1375266956365232048220109345396592726319742460454879981062694340660155949810 0158596374952141691378161159043297105952129759212696862483103011107449914024 0094518530978010978915317583738701606420973822157506086835007914978002982268 5532998094510470979840507359084614024762021412168744501835585051640684574287 1078953105601656693485703971643934048397703383418980257911777900546820380805 4170495763626051350369423653552681147090272505727727116438873040672296148742 3911117072924868470426691405643972081983053358547587471903955838256977365810 7214608397690540588379230455866567931949997177575434025237758134753480761133 28381591924887486184484485922972282971065248302182867907169925597 5666658170985421428568776023708028963706995520080659357168692551584779660342 8845370048005616413297301438788684948250159498753561703887501771998471467047 0572365820592328518742718645259795706159687456606230246406028480921554259928 5340467680010491452771885463865912263236353978700007220144125780098160197203 2031201691364593717086444953556041504587784874247426094277154056141748358043 3092986242590451866923730053842550530645976252654457481607935574398512975433 5958612625992295737052292037154444584538830158625476522119502606425844311713 7568524432625716058524905583126467948164530845151327970412952427667083285696 1654438323710321253566705831201432914714319143016623815060881384835591899090 2471009192031544760372901915755330058532299670144074706793928555485848393159 1828050109715302094839971124460319775966476623121401249450851220197356866122 8030237845317849716956219074680650465917640347731788333583546848508416734340 3898157780073751187903396667377222823979111370825580014201215182931295599914 4605197631998749857550713081687598984457233392295649568376711423487711804910 2828628167987521424766213383686969797280488819530652810103906518166447659272 3960381547488477643959422660036664159679049695106798176262658899212922595345 2454875526563586504128373884988804533889790263675488058966242204666913885135 4761573671014826411947138132267980759790003000518532492673507771928777973799 4462263269300516966805110216380798756683709747323283623552894566069041854716 5029737260856017571432569467896308128832457972079937266842795609362963233465 6327577377986418531570275825779937665992342542699460636407443029919577857433 8281851600006090764198717337191559381124541561638319703069586167725629299517 5076255282960787602293050101970033429356854625906232924704291310702886456251 8632469985653278132588227168080017020040737658591877433454971545485013311503 6561434485127084618089632304423817006708918171546906346335387536183560949225 6036074667890092069337996522372744178148163354405930752765169071704137022745 3128090263426824477803494585851173850223374121732489365069889497237403158227 9840839631127334319988930212402475223960918680308467061859410851679902975904 4661251441881460358726937406012647950645653613408222529039998067223110238643 6584292316840781276633771054531894956472312394322235029051864341558369191090 2082097544642694038762391681516198232954168712855564402707363812139413162515 0480689998678584944350427513554851672228063533753307926177250358938882470874 0552103661088094930068257811242447871657269388113518991542989510629246336165 8479986550036211371919196414464310026701922662394921566955076574453643730934 1341714157231194704091874372904256798372091118444460231449307037375034411885 3676576076869932519269429557331764241054721425368240513547145593868968757079 8413509507002710738565824220172607150332145236704442306962285332528127656564 2590547122402610145691024371453366639652111607302939245318506315359461958010 0338927812940593249471506386124415697212645252323776162585064558232775462345 0951607701158724151244612836110221471968264848258590874666079962640426472074 3487324130608218105825409790022539148520998476124281291687889066415082363438 6377246876252328877677745106379993913801568088315491443230018175530767089172 2280158309314854025846942336224310461844675465480506733085433084145387991886 9163462389952637245366258421425459491140903882880003377713821451634188188884 1270198600409570953154950542534700105045291091093642996156632611959521886490 8877592687889204374862069654416936978853484961795533371115377921813664130820 8894785497117037657605284341185537822982652138954441751771331074319374402086 3465730168436263997343397576043651046145427257983216065136429702161412662944 2533223411458043954241454056372388815682513236663702933669435298342603484167 4852785108888112467902247752587923476008872710917234044426046543641356109789 5876614276812058803783525798121627107430819643445666863755934345575064341943 2421032153639761995700534388812500609556342126624454207517606357454052961253 1916416611193320507596890878455922703579754346646730035078177578839631475550 5154158684730661893835639483595803909842534400000000 -146466598037214168132166946505504582163231930504557323838755829912078704914 7232527937922846836370373882122793776918426462873008206004301364448376259630 0479960292079047337203318689620054594788601914812264756266003542446303110405 9560079971360943834135331209843652685215567853268091899077562013277846536466 1786518361349621668764106591611342239895640346016543607765851182771101386113 1718339502303309148563294578063244261544184459699371894760765768843605074654 7819950060859169704099256831302939154372463310228820624840543133303743930037 6832934573832667131007316074052766767211417435693835817229175698303748426224 8164061481748353716219313553054565951525041510277959943506642274215459240400 3413401913246940636306835336167263971847965958219668263615363229308670003786 1280039502702514466128151473480194115101423711109540716126364366215022998077 3438647003907052554543859418494105956511786638237430891776264628858558346877 0999659442974447178448949336232579513990920556348752372589170183967760081282 1068289815831941416139365959202771157717021073756071068631224445237941841902 1010658333344411773566886865763298166211226814014383373536918777417377201936 0194260907892936117931560105492485208945051722728459321506684015902216398736 1437975998395864293392034350055095596731285567989250747678871045484053969091 7738158228784687166822861537430240167501324801433542590655581872680422750854 3569243672323920014911105847183250923458086240362287243614402774812893620769 8958454584510734797308369548615843411537874069109470839942512266512001813365 1686265685135225872723370661848625082264317185263751868490644013658070593769 5212774412568374551078701167623193603318820391281854674000166562224088265619 7825432639193103479385714210231933101171528480116302844082573381791300062745 3330296747551928284460293572813648085075110582219522739451115791229369187172 3294412418856265068263073465221599276551549319404148769602303854312999142835 4606621084918266578016717978376941310421414846182410260276675218940359642915 0789105727294502216051212140336002972753983918342578254176884786051351324666 191659726146306072405158680 5826600558186537404838856131370471039379659134 58076907875090050502110574307657256807287717388760005394175044663 2615551406650875838181122330253797985104602070241678014791853540448034257062 39419 1177939634036131600533146804222733342399463976109814236899724042387935525345 792616589264996745575 227719861472038658791603995367201962254031696071197510053300364489 1025559083270339613328225485791293069513108821161587766318899893534558082149 559351 4618707505262750497822661744140123902029723820123390596302244701544184757399 151666179549811431957 1973 [2, -2, 4] y^4 + 2*y^3 + 3*y^2 + 2*y + 1 1 1 y^4 [-2*x^2 - y*x, x^2, x^4] [-18*y, 6*y^2 + 4, 4] Mod(0, 3) Mod(1, 3) Mod(0, 2) [-x + 1, 1, 1] x^4 + 2*y*x^2 + y^2 x^20 - 10*x^16 + 20*x^15 + 40*x^12 + 2600*x^11 + 150*x^10 - 80*x^8 + 12400*x ^7 - 17000*x^6 + 500*x^5 + 80*x^4 + 5600*x^3 + 11000*x^2 + 5000*x + 593 [[x^2 + 3*x + 3, Mod(1, x^2 + 3*x + 3), Mod(x + 1, x^2 + 3*x + 3), -1]] [[x + 1, Mod(1, x + 1), Mod(0, x + 1), -1]] z^2 Mod(2, 3) Mod(41170744616631889845480363679839550251, 17014118346046923173168730371588 4105727) Mod(1, 3)*z^3*y^3 2 4 y^2 (x^3 + 1)/x^3 Total time spent: 5562 pari-2.11.2/src/test/32/dirmul0000644000175000017500000000202113201017466014362 0ustar billbill[0, 0, 0, 1] [0, 1] [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] [1, 4, 6, 12] [1, 0, 0, 0] [1/2, 0, 0, 0] [1, 3, 4, 7, 6, 12, 8, 15, 13, 18] [] [1] [1, 3] [1, 3, 4] [1, 0, 0, 1, 0, 0, 0, 0, 1, 0] [1, 1, 1, 0, 1, 1, 1, 1, 0, 1] *** at top-level: direuler(p=I,10.5,1/((1-X)*(1-p*X))) *** ^------------------ *** incorrect type in gceil (t_COMPLEX). *** at top-level: direuler(p=2.5,I,1/((1-X)*(1-p*X))) *** ^------------------ *** incorrect type in gfloor (t_COMPLEX). *** at top-level: direuler(p=2,10,1/((1-X)*(1-p*X)),I) *** ^-------------------- *** incorrect type in gfloor (t_COMPLEX). [1] [1, 3] [1, 3, 0, 7, 0] *** at top-level: direuler(p=2,10,1/2) *** ^---- *** domain error in direuler: constant term != 1 *** at top-level: direuler(p=2,10,1/(x-2)) *** ^-------- *** domain error in direuler: constant term != 1 Total time spent: 0 pari-2.11.2/src/test/32/sqrtn0000644000175000017500000000424313457566441014264 0ustar billbill0.E-38 0.E-12 0.E-12 + 0.E-12*I 0.79370052598409973737585281963615413020 1.1739849967053285099666839718862667420 2 + O(17^100) 1010311380446684911802268122009368691535646607849018888903290947605488591556 607742 125907569 31622776601683793319988935444327185337 3300034791125284639 *** at top-level: sqrtn(Mod(0,3),-2) *** ^------------------ *** sqrtn: impossible inverse in Fl_sqrtn: Mod(0, 3). *** at top-level: sqrtn(O(3),-2) *** ^-------------- *** sqrtn: impossible inverse in ginv: O(3). *** at top-level: sqrtn(0*ffgen((2^64+13)^2),-2) *** ^------------------------------ *** sqrtn: impossible inverse in FpXQ_sqrtn: 0. *** at top-level: sqrtn(0*ffgen(3^2),-2) *** ^---------------------- *** sqrtn: impossible inverse in Flxq_sqrtn: Vecsmall([0]). *** at top-level: sqrtn(0*ffgen(2^2),-2) *** ^---------------------- *** sqrtn: impossible inverse in F2xq_sqrtn: Vecsmall([0]). 9 1.0717734625362931642130063250233420229 0.80901699437494742410229341718281905886 + 0.5877852522924731291687059546390 7276860*I 1 + 3^2 + 2*3^4 + 2*3^5 + 3^6 + O(3^8) 2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + O(3^8) 1 + O(3^2) 1 1 1 *** at top-level: sqrtn(Mod(2,4),3) *** ^----------------- *** sqrtn: impossible inverse in Fl_inv: Mod(2, 4). *** at top-level: sqrtn(Mod(2,4),3,&z) *** ^-------------------- *** sqrtn: impossible inverse in Fl_inv: Mod(2, 4). 1.0000000000000000000000000000000000000 0 error("not an n-th power residue in Qp_sqrt: 1 + 2 + O(2^2).") error("not an n-th power residue in Qp_sqrt: 1 + 2 + O(2^3).") error("not an n-th power residue in gsqrt: Mod(2, 11).") error("not a prime number in Fl_sqrt [modulus]: 33.") 0.E-5 + 0.E-5*I [1 + O(3), 1] [1 + O(2), -1] [2 + O(2^3), 1 + 2 + O(2^2)] [2.0000000000000000000000000000000000000, 3.00000000000000000000000000000000 00000] error("not an n-th power residue in gsqrtn: Mod(2, 7).") [0, 0] Mod(2, 21) error("not a prime number in sqrtn [modulus]: 35.") [Mod(99, 101), Mod(100, 101)] error("not an n-th power residue in gsqrtn: Mod(3, 19).") 0.E-38 Total time spent: 100 pari-2.11.2/src/test/32/modpoly0000644000175000017500000000000013201017466014544 0ustar billbillpari-2.11.2/src/test/32/polmod0000644000175000017500000000557213326135265014404 0ustar billbillMod(x + 1/3, 2*x^2 + x + 1) Mod(15/16*x + 21/32, 2*x^2 + x + 1) Mod(1/2*x - 1/4, 2*x^2 + x + 1) Mod(-2*x, 2*x^2 + x + 1) Mod(-1/4*x - 3/8, 2*x^2 + x + 1) Mod(1, 2*x^2 + x + 1) Mod(4/3*x^2 - 1/6, 2*x^3 + x + 1) Mod(-39/103*x^2 + 93/103*x + 183/206, 2*x^3 + x + 1) Mod(3/2*x^2 - 1/2*x - 3/4, 2*x^3 + x + 1) Mod(2*x^2 - 2*x + 2, 2*x^3 + x + 1) Mod(-5/4*x^2 - 9/4*x - 7/8, 2*x^3 + x + 1) Mod(1, 2*x^3 + x + 1) Mod(Mod(6, 17)*x^2 + Mod(7, 17)*x + Mod(4, 17), Mod(2, 17)*x^3 + Mod(1, 17)* x + Mod(1, 17)) Mod(Mod(3, 17)*x^2 + Mod(16, 17)*x + Mod(6, 17), Mod(2, 17)*x^3 + Mod(1, 17) *x + Mod(1, 17)) Mod(Mod(15, 17)*x^2 + Mod(13, 17)*x + Mod(8, 17), Mod(2, 17)*x^3 + Mod(1, 17 )*x + Mod(1, 17)) Mod(Mod(8, 17)*x^2 + Mod(13, 17)*x + Mod(1, 17), Mod(2, 17)*x^3 + Mod(1, 17) *x + Mod(1, 17)) Mod(Mod(16, 17)*x^2 + Mod(10, 17), Mod(2, 17)*x^3 + Mod(1, 17)*x + Mod(1, 17 )) Mod(Mod(1, 17), Mod(2, 17)*x^3 + Mod(1, 17)*x + Mod(1, 17)) Mod(Mod(9223372036854775829, 18446744073709551629)*x^2 + Mod(7, 184467440737 09551629)*x + Mod(9223372036854775827, 18446744073709551629), Mod(2, 1844674 4073709551629)*x^3 + Mod(1, 18446744073709551629)*x + Mod(1, 184467440737095 51629)) Mod(Mod(9746969576064872258, 18446744073709551629)*x^2 + Mod(103913973166311 44804, 18446744073709551629)*x + Mod(12445510739686138545, 18446744073709551 629), Mod(2, 18446744073709551629)*x^3 + Mod(1, 18446744073709551629)*x + Mo d(1, 18446744073709551629)) Mod(Mod(9223372036854775821, 18446744073709551629)*x^2 + Mod(922337203685477 5819, 18446744073709551629)*x + Mod(8, 18446744073709551629), Mod(2, 1844674 4073709551629)*x^3 + Mod(1, 18446744073709551629)*x + Mod(1, 184467440737095 51629)) Mod(Mod(11980875016945378893, 18446744073709551629)*x^2 + Mod(95086309658296 65788, 18446744073709551629)*x + Mod(6656041676080766052, 184467440737095516 29), Mod(2, 18446744073709551629)*x^3 + Mod(1, 18446744073709551629)*x + Mod (1, 18446744073709551629)) Mod(Mod(4611686018427387936, 18446744073709551629)*x^2 + Mod(461168601842738 7920, 18446744073709551629)*x + Mod(9223372036854775833, 1844674407370955162 9), Mod(2, 18446744073709551629)*x^3 + Mod(1, 18446744073709551629)*x + Mod( 1, 18446744073709551629)) Mod(Mod(1, 18446744073709551629), Mod(2, 18446744073709551629)*x^3 + Mod(1, 18446744073709551629)*x + Mod(1, 18446744073709551629)) Mod(1/4, t)*x^2 + Mod(1, t)*x + Mod(1, t) Mod(0, 1) Mod(Mod(0, 2), 1) Mod(y, x) Mod(1/y, x) Mod(O(y), x) Mod(1, y)*x Mod(1, y)/(Mod(1, y)*x) Mod(1, y) *** at top-level: Mod(1+O(y),y+1) *** ^--------------- *** Mod: forbidden division t_SER % t_POL. Mod(0, 7) Mod(0, 7) Mod(0, 1) Mod(-1, x - 1) 36893488147419103232 a [Mod(1/2*x, x^2 - 2)] Mod(Mod(0, 7), 7*y + 1) 524287/2*z^21 + 405549*z^20 + 1/2*z^19 + 237477/2*z^18 + 524287/2*z^17 + 524 287/2*z^14 + 237477/2*z^12 + 524287/2*z^11 + 1/2*z^10 + 118739*z^9 + 524287/ 2*z^7 + 1/2*z^4 + 118739*z^3 + 524287/2*z^2 + 286811/2*z + 524287/2 Total time spent: 4 pari-2.11.2/src/test/32/ellff0000644000175000017500000000037513326135265014176 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). [[Mod(325254531735269032, 18446744073709551557), Mod(2692423357974964052, 18 446744073709551557)]] 18446744078921414430 93 88 [0] [0] Mod(1, 2)*a1^2*x^2 + Mod(1, 2)*a3^2 Total time spent: 5552 pari-2.11.2/src/test/32/program0000644000175000017500000000447613326135265014563 0ustar billbill1 echo = 1 ? alias(ln,log) ? ln(2) 0.69314718055994530941723212145817656807 ? for(x=1,5,print(x!)) 1 2 6 24 120 ? fordiv(10,x,print(x)) 1 2 5 10 ? forprime(p=1,30,print(p)) 2 3 5 7 11 13 17 19 23 29 ? forstep(x=0,2.9,Pi/12,print(sin(x))) 0.E-38 0.25881904510252076234889883762404832835 0.50000000000000000000000000000000000000 0.70710678118654752440084436210484903928 0.86602540378443864676372317075293618347 0.96592582628906828674974319972889736763 1.0000000000000000000000000000000000000 0.96592582628906828674974319972889736764 0.86602540378443864676372317075293618348 0.70710678118654752440084436210484903931 0.50000000000000000000000000000000000003 0.25881904510252076234889883762404832839 ? forvec(x=[[1,3],[-2,2]],print1([x[1],x[2]]," "));print(" "); [1, -2] [1, -1] [1, 0] [1, 1] [1, 2] [2, -2] [2, -1] [2, 0] [2, 1] [2, 2] [3 , -2] [3, -1] [3, 0] [3, 1] [3, 2] ? if(3<2,print("bof"),print("ok")); ok ? kill(y);print(x+y); x + y ? f(u)=u+1; ? print(f(5));kill(f); 6 ? f=12 12 ? g(u)=if(u,,return(17));u+2 (u)->if(u,,return(17));u+2 ? g(2) 4 ? g(0) 17 ? n=33;until(n==1,print1(n," ");if(n%2,n=3*n+1,n=n/2));print(1) 33 100 50 25 76 38 19 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 ? m=5;while(m<20,print1(m," ");m=m+1);print() 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ? default(seriesprecision,12) ? print((x-12*y)/(y+13*x)); (x - 12*y)/(13*x + y) ? print([1,2;3,4]) [1, 2; 3, 4] ? print1(x+y);print(x+y); x + yx + y ? print((x-12*y)/(y+13*x)); (x - 12*y)/(13*x + y) ? print([1,2;3,4]) [1, 2; 3, 4] ? print1(x+y);print1(" equals ");print(x+y); x + y equals x + y ? print1("give a value for s? ");s=input();print(1/(s^2+1)) give a value for s? printtex((x+y)^3/(x-y)^2) \frac{x^3 + 3\*y\*x^2 + 3\*y^2\*x + y^3}{x^2 - 2\*y\*x + y^2} 1 ? for(i=1,100,for(j=1,25,if(i+j==32,break(2)));print(i)) 1 2 3 4 5 6 ? u=v=p=q=1;for(k=1,400,w=u+v;u=v;v=w;p*=w;q=lcm(q,w);if(k%50==0,print(k" "log(p)/log(q)))); 50 1.5612291269030992792061717254933840846 100 1.6013353755908753487111410311704818784 150 1.6069155486736591275233947740278385687 200 1.6186599989915284815081751756012014738 250 1.6262847062047467650860809884971000430 300 1.6278227768451030011920245320536334380 350 1.6321059051729866681896522731053701088 400 1.6324242855329314481714056192369470068 ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 5 pari-2.11.2/src/test/32/diffop0000644000175000017500000000077613201017466014354 0ustar billbill(X^11 + 55*X^9 + 990*X^7 + 6930*X^5 + 17325*X^3 + 10395*X)*E Mod(((512*C^8 - 130560*C^6 + 1693440*C^4 - 4838400*C^2 + 3628800)/C^11)*S, S ^2 + (C^2 - 1)) 240*q + 4320*q^2 + 20160*q^3 + 70080*q^4 + 151200*q^5 + 362880*q^6 + 577920* q^7 + 1123200*q^8 + 1635120*q^9 + 2721600*q^10 + 3516480*q^11 + 5886720*q^12 + 6857760*q^13 + 10402560*q^14 + 12700800*q^15 + O(q^16) Mod(1, x^2 - y) Mod(0, x^2 + y) ((Mod(2, 3)*llx + Mod(2, 3))*lx^4 + Mod(1, 3)*lx^2 + Mod(2, 3))/(Mod(1, 3)*l lx^2*lx^6*x^6) Total time spent: 0 pari-2.11.2/src/test/32/nfcompositum0000644000175000017500000000145713326135265015633 0ustar billbill *** Warning: new stack size = 100000000 (95.367 Mbytes). Suite: compositum of relative extensions compositum of degrees 2 and 3 over quadratic field: 1 compositum of degrees 2 and 4 over quadratic field: 1 compositum of degrees 5 and 7 over quadratic field: 1 compositum of degrees 2 and 3 over degree 5 field: 1 compositum of degrees 2 and 4 over degree 5 field: 1 compositum of degrees 5 and 4 over degree 5 field: 1 *** at top-level: nfcompositum(nfinit(x),w^2+1,w^2+1) *** ^----------------------------------- *** nfcompositum: incorrect priority in polcompositum: variable x >= w *** at top-level: nfcompositum(x,w^2+1,w^2+1) *** ^--------------------------- *** nfcompositum: incorrect type in checknf [please apply nfinit()] (t_POL). Total time spent: 940 pari-2.11.2/src/test/32/forvec0000644000175000017500000000310713326135265014366 0ustar billbill[3/2, 3/2, 3/2] [3/2, 3/2, 5/2] [3/2, 5/2, 3/2] [3/2, 5/2, 5/2] [5/2, 3/2, 3/2] [5/2, 3/2, 5/2] [5/2, 5/2, 3/2] [5/2, 5/2, 5/2] [3/2, 3/2, 3/2] [3/2, 3/2, 5/2] [3/2, 3/2, 7/2] [3/2, 5/2, 5/2] [3/2, 5/2, 7/2] [3/2, 7/2, 7/2] [5/2, 5/2, 5/2] [5/2, 5/2, 7/2] [5/2, 7/2, 7/2] [7/2, 7/2, 7/2] [3/2, 5/2, 7/2] [1, 1, 1] [1, 1, 2] [1, 1, 3] [1, 2, 1] [1, 2, 2] [1, 2, 3] [1, 3, 1] [1, 3, 2] [1, 3, 3] [2, 1, 1] [2, 1, 2] [2, 1, 3] [2, 2, 1] [2, 2, 2] [2, 2, 3] [2, 3, 1] [2, 3, 2] [2, 3, 3] [3, 1, 1] [3, 1, 2] [3, 1, 3] [3, 2, 1] [3, 2, 2] [3, 2, 3] [3, 3, 1] [3, 3, 2] [3, 3, 3] [1, 1, 1] [1, 1, 2] [1, 1, 3] [1, 2, 2] [1, 2, 3] [1, 3, 3] [2, 2, 2] [2, 2, 3] [2, 3, 3] [3, 3, 3] [1, 2, 3] [1, 1] [3/2, 3/2, 3/2] [3/2, 3/2, 5/2] [3/2, 3/2, 7/2] [3/2, 5/2, 5/2] [3/2, 5/2, 7/2] [3/2, 7/2, 7/2] [5/2, 5/2, 5/2] [5/2, 5/2, 7/2] [5/2, 7/2, 7/2] [7/2, 7/2, 7/2] [3/2, 2, 5/2] [3/2, 2, 7/2] [3/2, 2, 9/2] [3/2, 3, 7/2] [3/2, 3, 9/2] [3/2, 4, 9/2] [5/2, 3, 7/2] [5/2, 3, 9/2] [5/2, 4, 9/2] [] *** at top-level: forvec(v=[1],) *** ^-------------- *** forvec: incorrect type in forvec [expected vector not of type [min,MAX]] (t_INT). *** at top-level: forvec(v=[[1]],) *** ^---------------- *** forvec: incorrect type in forvec [expected vector not of type [min,MAX]] (t_VEC). *** at top-level: forvec(v=[[1,I]],) *** ^------------------ *** forvec: incorrect type in gfloor (t_COMPLEX). *** at top-level: forvec(v=[[1,1],[1,1]],,3) *** ^-------------------------- *** forvec: invalid flag in forvec. Total time spent: 0 pari-2.11.2/src/test/32/printf0000644000175000017500000002731713326135265014415 0ustar billbill[1.0000000000000000000000000000000000000, 2.00000000000000000000000000000000 00000] 2.5000000000000000000000000000000000000 "string" 1000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000001 %0.12ld for 1 : 1 %ld for medium : 10000000000000000000100000000000000000001 %ld for big : 12532566399657183181075548323827342061649850750809861714634950 0752097059631738116432448839054351520763198615919551594076685828989467263022 7617908382708545798300151112466612039846243589298325716157180147040963056680 9750761327366302322689525054138592715842608868449408241676861770818959228693 6039922311125683719215046689156738352590137241554510185855964549927575493247 3911325485343784979788060849510858742020118363623157274201095547829887915300 8828971184455050023048563841318994713214224394733419925930073562249293741945 3650061490302105127920314430401636855677549136337481321811349678427076091437 3450453993373486112611680559293554029928231924911903600270361122831809358727 7521451746401317827465710073632156460683825273960115641462844554366314469605 0650160812621814327062666195172701780200286645023823083185928061371310300829 284071141207731280600001 %ld for very big : 955872885674440970277216219337772744771565088008376702328 0974773688280268898473796935187284691567817630339154703241830944055836706177 8809896056537787803996812085304655368999238720837283566913503724303376966199 2663921364613620578078079956465825388253571736411644948206142873619873902998 9324013720616227984952217113628421798278427274142950039049698146988876476074 8939673178886152066176070650100465366222106170273181288184814238180677916113 9684997815338572295836554681424837278459728932615631869144483961065493749103 9440849607597072892720960637713500992934377088954488639521019698524851190029 1396723345810969718342617610081591495344841181777365972361910710227844455871 0596976906677394315185249714607867087670127235754713322083182486995225340569 5472246371195637391184890765488286905297801802857817902007091052166469500735 8517047069777274928903320771601018941992164314045858885325103919749607054488 9716525591702409353851295924370666649874439353143103187877095721819476871104 6039621541420996552337447405835520269309421928095461368238705472240356556168 3129303880551193588007845178971366661918797743038379406063588297944215992646 3691785340362496774349413524560068683544691371721027653642635405810344391477 8552857183108973243687481777037313832906066461962417663222739497894271864945 7391622038713205017081287426068599398078599136506248490477428409273845322293 9485952504181333605883065410971257816284281979689677087852619367458015841421 6117184233630606194460758031603508715854504925822065735415717117642951641517 0445161262958756852411254262131565398676464291882351960512281733196470348829 7690518593597258112492554340486265712974508286368276821774451328996893631934 4348417912106139777376465001699264700607259391929003413720980579337938903285 2410694501172153015867959754936696154432352039610821684585660293442216332255 5070580750071570579340084075728526850951081388750387834675278083942728330312 9711486511315300779788820180840619721223715240178672367496637042272860292245 0067577330084637312473407306058275594314586875447869409332649806214474569067 0799154712883103337029383119878973056652922226725046494001644377943743452783 5338666583328256991155261024818087422713163540831882172167350724012550758316 3850231515419634983097154734421315315036556738503952579851113060316168285064 4412325371035901826210793778328430197276032260968667239887228910011826161802 3097733175960455531908934464156879721834606048691762387934893989942083292678 6114165436117688507634248134379080283752266998295759671652312537861057724541 2889100481703172021091464154836384754183307922685257765508608568562975782300 6971972040325406985944302869772198927623772954412851810428791278029990247190 8061321027142210255474075271028994680673537259392939342492022814681786038589 5053727937460469006290862306302596599241161335993054628084062016336294286371 0165693652750247998589876833218400433596639923643807793537485122586379078832 9952053631976486273900477504002455220369355782732974197522274191043597836052 1374994258036101231726093072258297440735657687656653417040524326319232166510 8439492869411835325894574661493440023985420450317689828201344808075337883055 2236604912047688409349395104864407345150328046921038566652090310866567690216 4572259483873093955981046211889222995200260181463334023494439942826046007589 3236653915339309050400710399118863480174135729126354272327526198931847020456 6728795325066963336117780662108205792489168581971029055585610731736547385276 6380276425506456602527540117971724098601448357463139833373628747458351815403 5433419999067815905003867353801202355724147944135805427332705248973655994186 5041130611413678219355893476567393224303909082190781300190833131836924007165 5654227122516796281838018086974384712482708966565668013921060459766010941761 0550107899541363062705900288745023359281714958359096826397307447904564333619 7694074509803666398360812784827236941956828332814974205954617687782092087303 0997251851490998934287793587314012691376625709193571373268588370102514439184 2763124051970683992048284118502185564135882596329582052566937100416646790947 1498445969988310316737367710893103311537634234857638996253794816827403174591 3409235603550443259621347217893233554496027667610159114124614916154055763095 1198325464161885467428416604670527897561905627890990303514190544175156737750 5869860752456948939764228528356856339078838226722969646304926903904720271260 7550621174274970352102351832642427284726879688473896768703167609747279566439 5578498800392719274981059063029204606278954141664029984815148568896796636434 2663259247454948386361302515198028514970927235946532045204096515486837699846 6925997198878817815883151755772929011530954905662647277529146304631954871875 7981842193591589605589369634076907345944834305812025808883916881139977347406 6104158312454962651296646292425018112638301705729188098557570438397461077275 1107669799661841774127735327529629987980135495274197751725763357367533317639 2595386396318128625002625818616041303229327960689610743787729001226196109507 5078523249740107441649074205707503339857610479405501354002538172669003503829 4356191810667246935208576620655055471197756731578925829743450128512240334555 0857364422106089400098097980710060066914254172300542199332763840179799715395 2104179819732919053768526215633403666084738829519651771281993035539758359068 8781450433887737655547586394649717798423766234759515768872575211201196790591 1773213950669559781858266965876148843986997239366002767913524466843361409330 3498345026183151219733115820351724151015788117079632416971637874342694800810 9209865880902821016061611090832735445696838927030768843853697669522942154966 7227488553970025901787267380707303012994912546555721617521680092662101142028 4912848777979814836521707093537471826821110236198096852733094988389478392581 8255430850346483797946697754305745787159147586676699909367391555177886905439 4354984318116361381459652470477414950669405827757863125230111000328882575478 0655518167212766883031211722120463766886341101457050139738519752913754699466 0984654027027880833056766431641756531642291956384797536599138648642741701263 5420756335784238406846840625370460253690959084071991825552481499175959058377 5949053421792234142884606332226448167839120570370707535455711251191807387373 1274143941499679321050883552677572347377971057431359097681006230800441905433 4051844084001679240936517390705136670076739932448640186313345352369221610604 4837426872832723526396728877036669789154090875467323512305194341580241450118 1685347224120973539459000033751051887902883571810921667754470616753277989433 4539341149484795033723281521701291803170133581206157279751790372163062541903 1411202633562600785638810288281580443225667903452442889326189645233595744838 8704292410919276051488657556172485434602528126371477338338731272695247871214 8531344208588042196247695295308496482430546116548334405206970596956241690495 9592823688304857706697333346755997888475028602837035242143266422559083501581 6744458763490333085563144012365643054194157661033194309985104088529575754028 2534806827228478629743216744688778020961699159280663882846234689310077081736 6024364166838206543521287616625394911441500124016866024811204707786292528961 1603281589332853085867183258825475535891673425352359526353307011017102021845 6229639266689296722655890932615138528947513810895234272775643400016991462766 4682562543427367805737384621907606506084956620139938655220574272932080283397 5080497672363160478194130557651083752225518739812293257597020321852115872321 0423508984903210022531681471604161527283425018665371038789874350824128553133 1838974789640955121321093762374555239210706518217412878830898523103817418183 7246685831115344213967160913112271567741324804620469079393138672209754183205 9576782459769012214555724662882616655925264453429317826369579546710887759595 4276881268091161226599431968684120556631276490437760589000224109022110256760 5022075066636881862874245112440744177946359096747914603998880496920718236536 5846712087804226663296973642180785685584316325681616712576674198500848437376 7270481096010523945334771956720006714196133587212624400370608940242114233954 9257662158399796716927732769103582352343826936693477382089998797977999286844 0635047656175995670212747442387427529440977381337458352545813688850563539619 3029768685508418714596477252230715588593206795794876020845605080470098683651 9496988775827449061579572659785772724941721637757846265570487428940047668565 5266879736209501456715267417789381173273996244782286259433553292793669397502 3309431808302492895087313521101191124546218312241301713223117215210051730192 4058849195801312549213512806000001 31 in base 16 == 1f %X for medium : 1D6329F1C35CA4BFB125BCBF2D63100001 %#X for medium : 0X1D6329F1C35CA4BFB125BCBF2D63100001 %x for 0: 0 %#X for 0: 0X0 %10s for "string" : string %.4s for "string" : stri %*.*s for "string" : st %s for 1 : 1 %s for aa : [1.0000000000000000000000000000000000000, 2.00000000000000000000 00000000000000000] %s for 4/3 : 4/3 %s inter %.2s %4.2f for aa, bb, aa : [1.000000000000000000000000000000000000 0, 2.0000000000000000000000000000000000000] inter 2. [1.00,2.00] "%s inter %.2s %4.2f for aa, bb, aa : [1.00000000000000000000000000000000000 00, 2.0000000000000000000000000000000000000] inter 2. [1.00,2.00]\n" %10.5s for 3.5 : 3.500 %10f for Pi : 3.1415926536| %20.10f for 2.7 : 2.7000000000| %+20.10f for 2.7: +2.7000000000| %-20.10f for 2.7: 2.7000000000 | %-*.*f for 2.7: 2.7000000000 | %20.10e for 2.7 : 2.7000000000 e0| %+20.10E for 2.7: +2.7000000000 E0| %-20.10e for 2.7: 2.7000000000 e0 | %-20.10E for ii : 1.0000000000 E100 | %e for 1+0*I : 1.0000000000000000000000000000000000000 E0 %8.3g for 3.14159: 3.14 %8.3G for ii : 1.00 E100 %8.3g for ii : 1.00 e100 %-20.10g for 4/3 : 1.333333333 | %20.13e for 4/3 : 1.3333333333333 e0| %e for 4/3 : 1.3333333333333333333333333333333333333 e0| *** at top-level: printf("%missing argument to format\n") *** ^--------------------------------------- *** printf: invalid conversion or specification m in format `%missing argument to format '. *** at top-level: printf("%d missing argument to format\n") *** ^----------------------------------------- *** printf: missing arg 1 for printf format '%d missing argument to format '. %-20.10g for aa : [1.000000000 ,2.000000000 ] 1.0000000000000000000000000000000000000 E38 0.99999999999999999999999999999999999999770976478687585326332384035105970783 05024613172747796087832576 0 0.000050 b b a a [1.00] [2.00] *** at top-level: printf("%c",'x) *** ^--------------- *** printf: incorrect type in gtolong (t_POL). -0.0000000000000000000000000000000000000029387 [2 1] [3 1] [5 1] [7 1] Total time spent: 0 pari-2.11.2/src/test/32/lfuntype0000644000175000017500000005263413326135265014761 0ustar billbill1 (lfun(2+2*I)): 0.86735182963599306498433134373508012832 - 0.27512723880785 764861866064309963878366*I 1 (lfun): 1.6449340668482264364724151666460251892 1 (lfuncreate): 1.6449340668482264364724151666460251892 1 (lfunderiv): 1.9892802342989010234208586874215163815 1 (lfunlambda): 0.52359877559829887307710723054658381403 1 (lfunderivlambda): 1.7505408751756119544313430121943867084 1 (lfuncheckfeq): -124 1 (lfunhardy): -0.96200848724404057880841099553380466848 1 (lfunorderzero): 0 1 (lfuntheta): 6.9746847124179912793574557227733860848 E-6 1 (lfunan): [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 2 (lfun(2+2*I)): 1.1233314114077833561582504428550435835 - 0.205723934240089 57916898605857624221327*I 2 (lfun): 1.1266824413000205751592654900629088681 2 (lfuncreate): 1.1266824413000205751592654900629088681 2 (lfunderiv): -0.073966539477079629182643885150638146555 2 (lfunlambda): 307.34947482475061378201159711485734531 2 (lfunderivlambda): 2028.4436121153168471302904406930171615 2 (lfuncheckfeq): -126 2 (lfunhardy): -32.018714245905908906772024097979947352 2 (lfunorderzero): 0 2 (lfuntheta): 0.64488044392253325202054921399500268289 2 (lfunan): [1, 1, -1, 1, -1, -1, -1, 1, 1, -1] 3 (lfun(2+2*I)): 0.86735182963599306498433134373508012832 - 0.27512723880785 764861866064309963878366*I 3 (lfun): 1.6449340668482264364724151666460251892 3 (lfuncreate): 1.6449340668482264364724151666460251892 3 (lfunderiv): 1.9892802342989010234208586874215163815 3 (lfunlambda): 0.52359877559829887307710723054658381403 3 (lfunderivlambda): 1.7505408751756119544313430121943867084 3 (lfuncheckfeq): -124 3 (lfunhardy): -0.96200848724404057880841099553380466848 3 (lfunorderzero): 0 3 (lfuntheta): 6.9746847124179912793574557227733860848 E-6 3 (lfunan): [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 4 (lfun(2+2*I)): 0.86735182963599306498433134373508012832 - 0.27512723880785 764861866064309963878366*I 4 (lfun): 1.6449340668482264364724151666460251892 4 (lfuncreate): 1.6449340668482264364724151666460251892 4 (lfunderiv): 1.9892802342989010234208586874215163815 4 (lfunlambda): 0.52359877559829887307710723054658381403 4 (lfunderivlambda): 1.7505408751756119544313430121943867084 4 (lfuncheckfeq): -124 4 (lfunhardy): -0.96200848724404057880841099553380466848 4 (lfunorderzero): 0 4 (lfuntheta): 6.9746847124179912793574557227733860848 E-6 4 (lfunan): [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 5 (lfun(2+2*I)): 0.94991647591129072043581963833883739774 + 0.03585105823427 7443293287918437084238484*I 5 (lfun): 1.1100010060250153929372222560595385375 5 (lfuncreate): 1.1100010060250153929372222560595385375 5 (lfunderiv): 0.66985260944239582916060974832249875293 5 (lfunlambda): 0.41169121016707136240079852448689476625 5 (lfunderivlambda): 1.0217697192872996687480118838767986988 5 (lfuncheckfeq): -124 5 (lfunhardy): -3.6466012956392990113851960814374302626 5 (lfunorderzero): 0 5 (lfuntheta): 0.015798831739815398531916606977185172990 5 (lfunan): [1, 0, 0, 0, 1, 0, 1, 1, 0, 0] 6 (lfun(2+2*I)): 0.96046911396271941245734106936390276916 - 0.19913331853054 320497393259062063479030*I 6 (lfun): 1.4401597158776080801495064365138846123 6 (lfuncreate): 1.4401597158776080801495064365138846123 6 (lfunderiv): 1.2079049332895341520216765453021425233 6 (lfunlambda): 15.139485785201416763757736219721592777 6 (lfunderivlambda): 33.440587260542738156400195687111808794 6 (lfuncheckfeq): -124 6 (lfunhardy): -4.0882933850254632425733862599048558633 6 (lfunorderzero): 0 6 (lfuntheta): 1.1375713725509771962438425200438560299 6 (lfunan): [1, 1, 0, 1, 0, 0, 2, 1, 2, 0] 7 (lfun(2+2*I)): 0.88705172216113322480409469919534965612 - 0.09990678085842 8073943765393502858953796*I 7 (lfun): 1.2199870868057000148286320542635728879 7 (lfuncreate): 1.2199870868057000148286320542635728879 7 (lfunderiv): 0.76279628494731231763615969761776115936 7 (lfunlambda): 5.5505341159944627753280928032151833524 7 (lfunderivlambda): 16.424727310701215600165088962170900302 7 (lfuncheckfeq): -124 7 (lfunhardy): -33.351091907649273629818419728456878713 7 (lfunorderzero): 0 7 (lfuntheta): 0.36149966339864669981432842318357647672 7 (lfunan): [1, 0, 1, 1, 0, 0, 0, 0, 1, 0] 8 (lfun(2+2*I)): 1.0101495968934043412732800200854418054 + 0.004609503326023 2147701632196287121437829*I 8 (lfun): 1.0252001241345418724140560939356526952 8 (lfuncreate): 1.0252001241345418724140560939356526952 8 (lfunderiv): 0.29024384665957598438544288826949641263 8 (lfunlambda): 49.048985289902361654934745411419681479 8 (lfunderivlambda): 122.70316145654544382956158595378438704 8 (lfuncheckfeq): -124 8 (lfunhardy): -416.09983196508983799680981895045379214 8 (lfunorderzero): 0 8 (lfuntheta): 3.4408766070486585094477767051533947296 8 (lfunan): [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] 9 (lfun(2+2*I)): 0.94991647591129072043581963833883739774 + 0.03585105823427 7443293287918437084238484*I 9 (lfun): 1.1100010060250153929372222560595385375 9 (lfuncreate): 1.1100010060250153929372222560595385375 9 (lfunderiv): 0.66985260944239582916060974832249875293 9 (lfunlambda): 0.41169121016707136240079852448689476625 9 (lfunderivlambda): 1.0217697192872996687480118838767986988 9 (lfuncheckfeq): -124 9 (lfunhardy): -3.6466012956392990113851960814374302626 9 (lfunorderzero): 0 9 (lfuntheta): 0.015798831739815398531916606977185172990 9 (lfunan): [1, 0, 0, 0, 1, 0, 1, 1, 0, 0] 10 (lfun(2+2*I)): 0.96046911396271941245734106936390276916 - 0.1991333185305 4320497393259062063479030*I 10 (lfun): 1.4401597158776080801495064365138846123 10 (lfuncreate): 1.4401597158776080801495064365138846123 10 (lfunderiv): 1.2079049332895341520216765453021425233 10 (lfunlambda): 15.139485785201416763757736219721592777 10 (lfunderivlambda): 33.440587260542738156400195687111808794 10 (lfuncheckfeq): -124 10 (lfunhardy): -4.0882933850254632425733862599048558633 10 (lfunorderzero): 0 10 (lfuntheta): 1.1375713725509771962438425200438560299 10 (lfunan): [1, 1, 0, 1, 0, 0, 2, 1, 2, 0] 11 (lfun(2+2*I)): 1.0101495968934043412732800200854418054 + 0.00460950332602 32147701632196287121437829*I 11 (lfun): 1.0252001241345418724140560939356526952 11 (lfuncreate): 1.0252001241345418724140560939356526952 11 (lfunderiv): 0.29024384665957598438544288826949641263 11 (lfunlambda): 49.048985289902361654934745411419681479 11 (lfunderivlambda): 122.70316145654544382956158595378438704 11 (lfuncheckfeq): -124 11 (lfunhardy): -416.09983196508983799680981895045379214 11 (lfunorderzero): 0 11 (lfuntheta): 3.4408766070486585094477767051533947296 11 (lfunan): [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] 12 (lfun(2+2*I)): 1.1253218963557071550693052856154296376 - 0.19811927124022 079554887193782410084230*I 12 (lfun): 1.1264614928374354582658928874128263889 12 (lfuncreate): 1.1264614928374354582658928874128263889 12 (lfunderiv): -0.10664330325574414917137228626962922306 12 (lfunlambda): 6.0955851027836191952110423376698748409 12 (lfunderivlambda): 3.7433308797907653080501083741412594803 12 (lfuncheckfeq): -126 12 (lfunhardy): 7.7257057464347992184653892456526767355 12 (lfunorderzero): 0 12 (lfuntheta): 1.0563976349426781093403848049102677979 12 (lfunan): [1, 1, -1, 1, -1, -1, -1, 1, 1, -1] 13 (lfun(2+2*I)): 1.0366273282049135932270814089727935794 + 0.08598041394827 8313963891368691632639062*I 13 (lfun): 0.91596559417721901505460351493238411078 13 (lfuncreate): 0.91596559417721901505460351493238411078 13 (lfunderiv): -0.074415212435678234968463235419624378152 13 (lfunlambda): 0.58312180806163756027676891293678983773 13 (lfunderivlambda): 0.11461361270605074146108788204186899939 13 (lfuncheckfeq): -127 13 (lfunhardy): 1.1188781062286078283093507637195622642 13 (lfunorderzero): 0 13 (lfuntheta): 0.086427836524391208443231605210323282841 13 (lfunan): [1, 0, -1, 0, 1, 0, -1, 0, 1, 0] 14 (lfun(2+2*I)): 1.1233314114077833561582504428550435835 - 0.20572393424008 957916898605857624221327*I 14 (lfun): 1.1266824413000205751592654900629088681 14 (lfuncreate): 1.1266824413000205751592654900629088681 14 (lfunderiv): -0.073966539477079629182643885150638146555 14 (lfunlambda): 307.34947482475061378201159711485734531 14 (lfunderivlambda): 2028.4436121153168471302904406930171615 14 (lfuncheckfeq): -126 14 (lfunhardy): -32.018714245905908906772024097979947352 14 (lfunorderzero): 0 14 (lfuntheta): 0.64488044392253325202054921399500268289 14 (lfunan): [1, 1, -1, 1, -1, -1, -1, 1, 1, -1] 15 (lfun(2+2*I)): 1.1899347435430418620272738925933102302 + 0.13284931798399 008158139344550778717503*I 15 (lfun): 0.95871612271688315539193642933117852641 + 0.14556587678508959046 170451181198645372*I 15 (lfuncreate): 0.95871612271688315539193642933117852641 + 0.14556587678508 959046170451181198645372*I 15 (lfunderiv): -0.059141321804795456439850793792381255731 + 0.0061186575828 237615678208745373111870021*I 15 (lfunlambda): 0.76292204976144041869087066615444364971 + 0.11583764417926 391071741847670955038937*I 15 (lfunderivlambda): 0.19928889238023943688189401030203636553 + 0.014134398 189618376193588831806358170666*I 15 (lfuncheckfeq): -127 15 (lfunhardy): 1.5591777703301761172588208954327252551 15 (lfunorderzero): 0 15 (lfuntheta): 0.14490184193508174938690941658301401010 + 0.000154027540511 12997934085459682226059462*I 15 (lfunan): [1, I, -I, -1, 0, 1, I, -I, -1, 0] 16 (lfun(2+2*I)): 0.81260447883761526408104144169608149511 + 0.5144166513337 4637809100837010866265633*I 16 (lfun): 0.54604803621501351833412666043344433859 16 (lfuncreate): 0.54604803621501351833412666043344433859 16 (lfunderiv): -0.095957311923813606000713880504095971510 16 (lfunlambda): 0.30429428345183609897245459495726899126 16 (lfunderivlambda): 0.095266257729556417098633725894681176014 16 (lfuncheckfeq): -127 16 (lfunhardy): 0.97613504532230008589418374710889823825 16 (lfunorderzero): 0 16 (lfuntheta): 0.043171973528082749943827357182478083529 16 (lfunan): [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] 17 (lfun(2+2*I)): 1.0544108896702584763970017458267826847 - 0.04379652183085 4397224379011005489686310*I 17 (lfun): 0.85415099058271070490531884226581179146 17 (lfuncreate): 0.85415099058271070490531884226581179146 17 (lfunderiv): -0.56368025436957145796165019177868545250 17 (lfunlambda): 21.462810165028656830342316601064230458 17 (lfunderivlambda): 84.686002725623067381430447870497647113 17 (lfuncheckfeq): -123 17 (lfunhardy): 7.7431197030007111287831790642229368607 17 (lfunorderzero): 1 17 (lfuntheta): 0.84521747322794073828148208807828496968 17 (lfunan): [1, 0, 0, 0, -3, 0, 3, 0, -3, 0] 18 (lfun(2+2*I)): 0.98312302696660097223527176346483215206 - 0.1427950673893 8341065723807966678967160*I 18 (lfun): 0.82757526074455562700765359269996549955 18 (lfuncreate): 0.82757526074455562700765359269996549955 18 (lfunderiv): -0.87512118124347393325952081941890290952 18 (lfunlambda): 378.67068685244416028912739442353179344 18 (lfunderivlambda): 4720.9665435827617633763166279999891270 18 (lfuncheckfeq): -127 18 (lfunhardy): -15.149647103802510158707354941231055482 18 (lfunorderzero): 2 18 (lfuntheta): -7.6688743804622365519219315981408517165 18 (lfunan): [1, 0, 0, 0, 1, 0, -5, 0, -3, 0] 19 (lfun(2+2*I)): 0.98627253010480952593175189385314157899 + 0.3801943625589 2826912755460379882393981*I 19 (lfun): 0.66147518792106974272752063397962688979 19 (lfuncreate): 0.66147518792106974272752063397962688979 19 (lfunderiv): -0.14384139549317635426356865639499369619 19 (lfunlambda): 0.50266086742650446274974513333867258927 19 (lfunderivlambda): 0.19442331022115954163350803417532382469 19 (lfuncheckfeq): -127 19 (lfunhardy): 1.4076935244557198875463930525207828840 19 (lfunorderzero): 0 19 (lfuntheta): 0.074804214825265387726031644781601219253 19 (lfunan): [1, -1, -1, -1, 1, 1, 0, 3, 1, -1] 20 (lfun(2+2*I)): 0.94255444322004905127830492051658000648 + 0.3126778218091 7321626495545838012354813*I 20 (lfun): 0.71564612886082497549611412954606651956 20 (lfuncreate): 0.71564612886082497549611412954606651956 20 (lfunderiv): -0.10407894584023904016468453592994890959 20 (lfunlambda): 0.21753033853570730528434199705036653995 20 (lfunderivlambda): 0.089237881186363955097754401634415704592 20 (lfuncheckfeq): -127 20 (lfunhardy): 0.91836381109207465259393909159615943678 20 (lfunorderzero): 0 20 (lfuntheta): 0.037630673702661307416849865951733658142 20 (lfunan): [1, -1, -1, 1, 0, 1, 0, -1, 1, 0] 21 (lfun(2+2*I)): 0.98315688287807993848728217136059188364 + 0.3531949622611 9600256485776532890264370*I 21 (lfun): 0.67479969464784155829709087304704402380 21 (lfuncreate): 0.67479969464784155829709087304704402380 21 (lfunderiv): -0.14445905207331063984929465902657559948 21 (lfunlambda): 0.78627229350688518181479057787879442122 21 (lfunderivlambda): 0.43960077502814326043064320757682369479 21 (lfuncheckfeq): -127 21 (lfunhardy): 3.7906123947888162118912745573290423840 21 (lfunorderzero): 0 21 (lfuntheta): 0.13420087505683188828132600694374189569 21 (lfunan): [1, -1, -1, 0, 0, 1, 0, 1, 0, 0] 22 (lfun(2+2*I)): 0.96298216848967988043139203558640711798 - 0.2342009590489 5188293534871602747646966*I 22 (lfun): 1.4318824514464387465676045965741854843 22 (lfuncreate): 1.4318824514464387465676045965741854843 22 (lfunderiv): 1.1422304123026129533330985802463952101 22 (lfunlambda): 1.1759743869874435481612945489432475212 22 (lfunderivlambda): 2.4084264843810884136659888848787984212 22 (lfuncheckfeq): -124 22 (lfunhardy): -7.5183989759241169055381813793310826092 22 (lfunorderzero): 0 22 (lfuntheta): 0.082926332933319155259202716459188391609 22 (lfunan): [1, 1, 0, 1, 1, 0, 0, 1, 0, 1] 23 (lfun(2+2*I)): 1.0554498431937466016399059838514723665 - 0.02784638539565 8970273799631703681748409*I 23 (lfun): 0.93316836286939013447125902611036854752 23 (lfuncreate): 0.93316836286939013447125902611036854752 23 (lfunderiv): -0.20133842629482530350224118884420836660 23 (lfunlambda): 22.150738128072135257046224387043103356 23 (lfunderivlambda): 67.856243754653225347348872059210166995 23 (lfuncheckfeq): -125 23 (lfunhardy): 34.264753605661655413113407773581100347 23 (lfunorderzero): 0 23 (lfuntheta): 1.4615812546350410806241912565112410208 23 (lfunan): [1, 0, 0, 0, -1, 0, -1, 0, 0, 0] 24 (lfun(2+2*I)): 0.31472576404209958223490432211550805736 - 0.2316796487505 2068322446450582306984884*I 24 (lfun): -0.50000000000000000000000000000000000000 24 (lfuncreate): -0.50000000000000000000000000000000000000 24 (lfunderiv): -2.0063564559085848512101000267299604382 24 (lfunlambda): -1.0000000000000000000000000000000000000*x^-1 + O(x^0) 24 (lfunderivlambda): -2.0000000000000000000000000000000000000*x^-3 + O(x^0) 24 (lfuncheckfeq): -125 *** lfunhardy: Warning: lfuninit: insufficient initialization. 24 (lfunhardy): -0.56003058147354490789526675361134629435 *** lfunorderzero: Warning: lfuninit: insufficient initialization. 24 (lfunorderzero): 0 24 (lfuntheta): 1.7436711781044978198393639306933465212 E-6 24 (lfunan): [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 25 (lfun(2+2*I)): 4.5022051938493762630318608209969624314 - 4.32986359287055 56420242996824232187809*I 25 (lfun): 9.8696044010893586188344909998761511354*x^-1 + O(x^0) 25 (lfuncreate): 9.8696044010893586188344909998761511354*x^-1 + O(x^0) 25 (lfunderiv): 19.739208802178717237668981999752302271*x^-3 + O(x^0) 25 (lfunlambda): 2*x^-1 + O(x^0) 25 (lfunderivlambda): 4.0000000000000000000000000000000000000*x^-3 + O(x^0) 25 (lfuncheckfeq): -127 25 (lfunhardy): -2.5469113466196770062933385045593301523 25 (lfunorderzero): 0 25 (lfuntheta): 0.030046893520745694160538411115727227082 25 (lfunan): [8, 24, 32, 24, 48, 96, 64, 24, 104, 144] 26 (lfun(2+2*I)): 1.1880469326252707442140202415265756569 + 0.01694679050176 8770099808695642642617468*I 26 (lfun): 0.93105766066370458950111047246090696916 26 (lfuncreate): 0.93105766066370458950111047246090696916 26 (lfunderiv): -0.19875301303842881461288412642672936246 26 (lfunlambda): 2.2168928091162464996705548722606546078 26 (lfunderivlambda): 1.8835751442729164002985938822801004139 26 (lfuncheckfeq): -127 26 (lfunhardy): 7.1739599307895241834661105153799234554 26 (lfunorderzero): 0 26 (lfuntheta): 0.33740734290941194013785615355015968564 26 (lfunan): [1, 0.61803398874989484820458683436563811772, -1.61803398874989 48482045868343656381177, -0.61803398874989484820458683436563811772, 0, -1, 0 .61803398874989484820458683436563811772, -1, 1.61803398874989484820458683436 56381177, 0] 27 (lfun(2+2*I)): 1.1880469326252707442140202415265756569 + 0.01694679050176 8770099808695642642617468*I 27 (lfun): 0.93105766066370458950111047246090696916 27 (lfuncreate): 0.93105766066370458950111047246090696916 27 (lfunderiv): -0.19875301303842881461288412642672936246 27 (lfunlambda): 2.2168928091162464996705548722606546078 27 (lfunderivlambda): 1.8835751442729164002985938822801004139 27 (lfuncheckfeq): -127 27 (lfunhardy): 7.1739599307895241834661105153799234554 27 (lfunorderzero): 0 27 (lfuntheta): 0.33740734290941194013785615355015968564 27 (lfunan): [1, 0.61803398874989484820458683436563811772, -1.61803398874989 48482045868343656381177, -0.61803398874989484820458683436563811772, 0, -1, 0 .61803398874989484820458683436563811772, -1, 1.61803398874989484820458683436 56381177, 0] 28 (lfun(2+2*I)): 1.9709547810947362615140933407643026874 + 0.72125054242112 098881193565176429637104*I 28 (lfun): 1.3421676621839102797814972773640152026 28 (lfuncreate): 1.3421676621839102797814972773640152026 28 (lfunderiv): -0.28946712907827258818400985023033597034 28 (lfunlambda): 2.5158152993104480556746720628152471027 28 (lfunderivlambda): 2.1502397959728439200455523877452901447 28 (lfuncheckfeq): -127 28 (lfunhardy): 2.8845771022027583283290641748300159470 + 3.3202488042440264 704057081842186911048*I 28 (lfunorderzero): 0 28 (lfuntheta): 0.43438208556947019708203926615081402208 28 (lfunan): [2, -2, -2, 0, -2, 6, -2, 0, 4, 4] 29 (lfun(2+2*I)): 1.0524106447704187331819351953723618488 - 0.16089557470379 850303874135108164140543*I 29 (lfun): 2.0146245621496746305832568735923972175*x^-1 + O(x^0) 29 (lfuncreate): 2.0146245621496746305832568735923972175*x^-1 + O(x^0) 29 (lfunderiv): 4.0292491242993492611665137471847944349*x^-3 + O(x^0) 29 (lfunlambda): 4.8989794855663561963945681494117827839*x^-1 + O(x^0) 29 (lfunderivlambda): 9.7979589711327123927891362988235655679*x^-3 + O(x^0) 29 (lfuncheckfeq): -125 29 (lfunhardy): -0.23300237492132396248442589209445787109 + 0.88370872535843 915306365540030722110823*I 29 (lfunorderzero): 0 29 (lfuntheta): 0.82431888141964267810269311237633779885 29 (lfunan): [2, 2, 6, 8, 8, 16, 16, 14, 22, 24] 30 (lfun(2+2*I)): 1.0521576652554627042407515608421088843 + 0.14805527106487 078431325175340697023643*I 30 (lfun): 0.80975110660967140814479315394793589558 30 (lfuncreate): 0.80975110660967140814479315394793589558 30 (lfunderiv): -0.23055349934262096841259422808073776709 30 (lfunlambda): 2.8450867706015258379523360911003279317 30 (lfunderivlambda): 5.7204259750670336214223157097792822772 30 (lfuncheckfeq): -126 30 (lfunhardy): 4.8275994526484248940007934411523183648 30 (lfunorderzero): 0 30 (lfuntheta): 0.25552955884387935277949460024860170847 30 (lfunan): [1, 0, -2, 0, 0, 0, 6, 0, -3, 0] 31 (lfun(2+2*I)): 0.89253352046148531026753260212060664880 + 0.3697591309493 4705287751044283901184889*I 31 (lfun): 0.66175089770929725476564677769939622855 31 (lfuncreate): 0.66175089770929725476564677769939622855 31 (lfunderiv): -0.10019890783843543927935189577270339064 31 (lfunlambda): 0.19557068134325499033294643094375330160 31 (lfunderivlambda): 0.074923901241117305308856177568943698543 31 (lfuncheckfeq): -127 31 (lfunhardy): 0.86445110850417919069718227732914939116 31 (lfunorderzero): 0 31 (lfuntheta): 0.033524995531193573780800227953209178608 31 (lfunan): [1.0000000000000000000000000000000000000, -1.414213562373095048 8016887242096980786, -0.57735026918962576450914878050195745565, 1.0000000000 000000000000000000000000000, 0.44721359549995793928183473374625524709, 0.816 49658092772603273242802490196379732, -0.755928946018454454429033072468360121 63, 0, -0.66666666666666666666666666666666666667, -0.63245553203367586639977 870888654370674] 32 (lfun(2+2*I)): 0.71683178219623482123876107149063323079 - 0.0670150707037 18642997575342076561776944*I 32 (lfun): 0.92706368000081250207056652952022500618 - 0.46364938145483682270 246750309170364992*I 32 (lfuncreate): 0.92706368000081250207056652952022500618 - 0.46364938145483 682270246750309170364992*I 32 (lfunderiv): -0.14325687414515242351441502322514384981 - 0.39616475368926 266017359177755101860385*I 32 (lfunlambda): 12.915538538306770007023725703267817117 - 6.459406817055752 7749411446673463446509*I 32 (lfunderivlambda): 35.119341345499317617173671937045221290 - 7.6130893486 359329343104104880084980135*I 32 (lfuncheckfeq): -128 32 (lfunhardy): -6.0689473021581631216399042218295179710 32 (lfunorderzero): 0 32 (lfuntheta): 0.79138040414598215782025151996013400677 - 0.693572792187828 34814370540240036393563*I 32 (lfunan): [1, -2*I, I, -2, 0, 2, -2*I, 0, 2, 0] 33 (lfun(2+2*I)): 1.5440136714872304773986991780907589211 - 0.30661960725519 029288002589339018937061*I 33 (lfun): 1.0575992445909578493475116523231674725 33 (lfuncreate): 1.0575992445909578493475116523231674725 33 (lfunderiv): -0.40874788643585924772279469406166841139 33 (lfunlambda): 2.0636065064337882642106195341697561190 33 (lfunderivlambda): 1.5118482678149543000643643698970410347 33 (lfuncheckfeq): -124 33 (lfunhardy): 2.5141116494240547692059934356337208455 33 (lfunorderzero): 0 33 (lfuntheta): 0.23289067751256198570325301650715050859 33 (lfunan): [1, 2, -2, 0, -4, -4, -3, 0, 10, -8] 34 (lfun(2+2*I)): 0.30340585010904366530335696337431398948 - 0.8007738353880 8323710294579089327329218*I 34 (lfun): 1.1402308683647332165019665302206510242 34 (lfuncreate): 1.1402308683647332165019665302206510242 34 (lfunderiv): -1.1167497502735277462260515370661007526 34 (lfunlambda): 24.473226847609759135198967167899023747 34 (lfunderivlambda): 30.738683436715312670539707545652132287 34 (lfuncheckfeq): -124 34 (lfunhardy): 2.7897642304056560145420743528588027342 34 (lfunorderzero): 0 34 (lfuntheta): 1.7720013953042806303430908084396944474 34 (lfunan): [1, 0, 5, 0, -9, 0, 20, 0, -5, 0] Total time spent: 3492 pari-2.11.2/src/test/32/combinat0000644000175000017500000001132013326135265014672 0ustar billbill[3628800, -10628640, 12753576, -8409500, 3416930, -902055, 157773, -18150, 1 320, -55] [-39916800, 120543840, -150917976, 105258076, -45995730, 13339535, -2637558, 357423, -32670, 1925, -66] [1, 1023, 28501, 145750, 246730, 179487, 63987, 11880, 1155, 55] [1, 2047, 86526, 611501, 1379400, 1323652, 627396, 159027, 22275, 1705, 66] [Vecsmall([1, 2, 3, 4, 5]), Vecsmall([1, 2, 3, 5, 4]), Vecsmall([1, 2, 4, 3, 5]), Vecsmall([1, 2, 4, 5, 3]), Vecsmall([1, 2, 5, 3, 4]), Vecsmall([1, 2, 5, 4, 3]), Vecsmall([1, 3, 2, 4, 5]), Vecsmall([1, 3, 2, 5, 4]), Vecsmall([1 , 3, 4, 2, 5]), Vecsmall([1, 3, 4, 5, 2]), Vecsmall([1, 3, 5, 2, 4]), Vecsma ll([1, 3, 5, 4, 2]), Vecsmall([1, 4, 2, 3, 5]), Vecsmall([1, 4, 2, 5, 3]), V ecsmall([1, 4, 3, 2, 5]), Vecsmall([1, 4, 3, 5, 2]), Vecsmall([1, 4, 5, 2, 3 ]), Vecsmall([1, 4, 5, 3, 2]), Vecsmall([1, 5, 2, 3, 4]), Vecsmall([1, 5, 2, 4, 3]), Vecsmall([1, 5, 3, 2, 4]), Vecsmall([1, 5, 3, 4, 2]), Vecsmall([1, 5, 4, 2, 3]), Vecsmall([1, 5, 4, 3, 2]), Vecsmall([2, 1, 3, 4, 5]), Vecsmall ([2, 1, 3, 5, 4]), Vecsmall([2, 1, 4, 3, 5]), Vecsmall([2, 1, 4, 5, 3]), Vec small([2, 1, 5, 3, 4]), Vecsmall([2, 1, 5, 4, 3]), Vecsmall([2, 3, 1, 4, 5]) , Vecsmall([2, 3, 1, 5, 4]), Vecsmall([2, 3, 4, 1, 5]), Vecsmall([2, 3, 4, 5 , 1]), Vecsmall([2, 3, 5, 1, 4]), Vecsmall([2, 3, 5, 4, 1]), Vecsmall([2, 4, 1, 3, 5]), Vecsmall([2, 4, 1, 5, 3]), Vecsmall([2, 4, 3, 1, 5]), Vecsmall([ 2, 4, 3, 5, 1]), Vecsmall([2, 4, 5, 1, 3]), Vecsmall([2, 4, 5, 3, 1]), Vecsm all([2, 5, 1, 3, 4]), Vecsmall([2, 5, 1, 4, 3]), Vecsmall([2, 5, 3, 1, 4]), Vecsmall([2, 5, 3, 4, 1]), Vecsmall([2, 5, 4, 1, 3]), Vecsmall([2, 5, 4, 3, 1]), Vecsmall([3, 1, 2, 4, 5]), Vecsmall([3, 1, 2, 5, 4]), Vecsmall([3, 1, 4 , 2, 5]), Vecsmall([3, 1, 4, 5, 2]), Vecsmall([3, 1, 5, 2, 4]), Vecsmall([3, 1, 5, 4, 2]), Vecsmall([3, 2, 1, 4, 5]), Vecsmall([3, 2, 1, 5, 4]), Vecsmal l([3, 2, 4, 1, 5]), Vecsmall([3, 2, 4, 5, 1]), Vecsmall([3, 2, 5, 1, 4]), Ve csmall([3, 2, 5, 4, 1]), Vecsmall([3, 4, 1, 2, 5]), Vecsmall([3, 4, 1, 5, 2] ), Vecsmall([3, 4, 2, 1, 5]), Vecsmall([3, 4, 2, 5, 1]), Vecsmall([3, 4, 5, 1, 2]), Vecsmall([3, 4, 5, 2, 1]), Vecsmall([3, 5, 1, 2, 4]), Vecsmall([3, 5 , 1, 4, 2]), Vecsmall([3, 5, 2, 1, 4]), Vecsmall([3, 5, 2, 4, 1]), Vecsmall( [3, 5, 4, 1, 2]), Vecsmall([3, 5, 4, 2, 1]), Vecsmall([4, 1, 2, 3, 5]), Vecs mall([4, 1, 2, 5, 3]), Vecsmall([4, 1, 3, 2, 5]), Vecsmall([4, 1, 3, 5, 2]), Vecsmall([4, 1, 5, 2, 3]), Vecsmall([4, 1, 5, 3, 2]), Vecsmall([4, 2, 1, 3, 5]), Vecsmall([4, 2, 1, 5, 3]), Vecsmall([4, 2, 3, 1, 5]), Vecsmall([4, 2, 3, 5, 1]), Vecsmall([4, 2, 5, 1, 3]), Vecsmall([4, 2, 5, 3, 1]), Vecsmall([4 , 3, 1, 2, 5]), Vecsmall([4, 3, 1, 5, 2]), Vecsmall([4, 3, 2, 1, 5]), Vecsma ll([4, 3, 2, 5, 1]), Vecsmall([4, 3, 5, 1, 2]), Vecsmall([4, 3, 5, 2, 1]), V ecsmall([4, 5, 1, 2, 3]), Vecsmall([4, 5, 1, 3, 2]), Vecsmall([4, 5, 2, 1, 3 ]), Vecsmall([4, 5, 2, 3, 1]), Vecsmall([4, 5, 3, 1, 2]), Vecsmall([4, 5, 3, 2, 1]), Vecsmall([5, 1, 2, 3, 4]), Vecsmall([5, 1, 2, 4, 3]), Vecsmall([5, 1, 3, 2, 4]), Vecsmall([5, 1, 3, 4, 2]), Vecsmall([5, 1, 4, 2, 3]), Vecsmall ([5, 1, 4, 3, 2]), Vecsmall([5, 2, 1, 3, 4]), Vecsmall([5, 2, 1, 4, 3]), Vec small([5, 2, 3, 1, 4]), Vecsmall([5, 2, 3, 4, 1]), Vecsmall([5, 2, 4, 1, 3]) , Vecsmall([5, 2, 4, 3, 1]), Vecsmall([5, 3, 1, 2, 4]), Vecsmall([5, 3, 1, 4 , 2]), Vecsmall([5, 3, 2, 1, 4]), Vecsmall([5, 3, 2, 4, 1]), Vecsmall([5, 3, 4, 1, 2]), Vecsmall([5, 3, 4, 2, 1]), Vecsmall([5, 4, 1, 2, 3]), Vecsmall([ 5, 4, 1, 3, 2]), Vecsmall([5, 4, 2, 1, 3]), Vecsmall([5, 4, 2, 3, 1]), Vecsm all([5, 4, 3, 1, 2]), Vecsmall([5, 4, 3, 2, 1])] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 2 1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 4 0, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 5 9, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 7 8, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 9 7, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 2 1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 4 0, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 5 9, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 7 8, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 9 7, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119] 0 ["e_TYPE", "permsign", Vecsmall([1, 3, 0])] *** at top-level: permtonum(1) *** ^------------ *** permtonum: incorrect type in permtonum (t_INT). 0 Vecsmall([]) Total time spent: 3 pari-2.11.2/src/test/32/quadclassunit0000644000175000017500000004223013272054410015752 0ustar billbill? test(D)=for(d=D,D+10^3,if(!isfundamental(d),next);print(d," ",quadclassunit(d).cyc)); ? setrand(1);test(10^15);test(-10^15) 1000000000000001 [4, 4, 2, 2, 2] 1000000000000005 [2, 2, 2, 2] 1000000000000009 [2, 2] 1000000000000012 [32, 2] 1000000000000013 [] 1000000000000021 [2] 1000000000000024 [4] 1000000000000028 [2] 1000000000000029 [6, 2] 1000000000000033 [] 1000000000000037 [] 1000000000000040 [8, 2, 2, 2] 1000000000000041 [2, 2, 2, 2] 1000000000000045 [4, 2] 1000000000000049 [2] 1000000000000056 [2, 2, 2] 1000000000000057 [2] 1000000000000060 [6, 2, 2, 2] 1000000000000061 [2] 1000000000000065 [4, 2, 2] 1000000000000069 [] 1000000000000076 [2] 1000000000000077 [6, 2] 1000000000000081 [2, 2] 1000000000000085 [2, 2] 1000000000000088 [13] 1000000000000093 [] 1000000000000097 [4, 4] 1000000000000101 [12, 2, 2] 1000000000000104 [2] 1000000000000105 [2, 2, 2] 1000000000000108 [2] 1000000000000109 [4] 1000000000000113 [2, 2] 1000000000000117 [] 1000000000000120 [12, 2] 1000000000000121 [2] 1000000000000124 [8, 2, 2] 1000000000000129 [6] 1000000000000133 [2, 2, 2] 1000000000000136 [4] 1000000000000137 [4, 2] 1000000000000140 [2, 2, 2, 2] 1000000000000145 [4] 1000000000000149 [2, 2] 1000000000000153 [] 1000000000000156 [2, 2, 2, 2] 1000000000000157 [22, 2, 2] 1000000000000165 [2, 2, 2] 1000000000000168 [334] 1000000000000169 [] 1000000000000172 [3] 1000000000000173 [2, 2] 1000000000000177 [2] 1000000000000181 [2] 1000000000000184 [2, 2, 2, 2] 1000000000000185 [8, 2, 2, 2] 1000000000000189 [22] 1000000000000193 [2] 1000000000000201 [2] 1000000000000204 [4, 2, 2] 1000000000000205 [2] 1000000000000209 [2, 2, 2] 1000000000000216 [2, 2, 2] 1000000000000217 [7] 1000000000000220 [8, 2, 2] 1000000000000221 [2, 2, 2, 2] 1000000000000229 [2] 1000000000000232 [6, 2] 1000000000000236 [8, 4] 1000000000000237 [4] 1000000000000241 [] 1000000000000245 [2, 2, 2] 1000000000000248 [2, 2, 2] 1000000000000249 [] 1000000000000252 [2] 1000000000000253 [76] 1000000000000257 [2, 2] 1000000000000261 [2] 1000000000000264 [2, 2] 1000000000000265 [2, 2, 2] 1000000000000268 [2, 2] 1000000000000273 [] 1000000000000277 [4, 2] 1000000000000280 [2, 2] 1000000000000281 [2, 2, 2] 1000000000000284 [4, 2] 1000000000000285 [2] 1000000000000289 [] 1000000000000293 [] 1000000000000297 [] 1000000000000301 [2] 1000000000000309 [14, 2, 2, 2] 1000000000000312 [2, 2] 1000000000000313 [6, 6] 1000000000000316 [2, 2] 1000000000000317 [2, 2] 1000000000000321 [3] 1000000000000328 [4, 2, 2] 1000000000000329 [2] 1000000000000333 [4] 1000000000000344 [2, 2, 2] 1000000000000345 [8, 2, 2] 1000000000000349 [] 1000000000000353 [8, 2, 2] 1000000000000357 [] 1000000000000360 [2, 2, 2] 1000000000000361 [4] 1000000000000364 [4, 2] 1000000000000365 [6, 2, 2] 1000000000000369 [4, 2] 1000000000000373 [2, 2] 1000000000000376 [26, 2] 1000000000000380 [2, 2] 1000000000000381 [2] 1000000000000385 [2] 1000000000000389 [2, 2] 1000000000000392 [2] 1000000000000393 [3] 1000000000000396 [2, 2] 1000000000000397 [4] 1000000000000401 [3] 1000000000000405 [2, 2, 2] 1000000000000408 [2, 2] 1000000000000409 [6, 2] 1000000000000412 [2, 2] 1000000000000417 [6] 1000000000000421 [2] 1000000000000424 [2, 2] 1000000000000428 [12, 2, 2] 1000000000000429 [] 1000000000000433 [] 1000000000000437 [] 1000000000000444 [] 1000000000000445 [2, 2, 2, 2] 1000000000000453 [2, 2] 1000000000000456 [2, 2] 1000000000000457 [4] 1000000000000460 [6, 2, 2, 2] 1000000000000461 [4] 1000000000000465 [4, 2] 1000000000000469 [158] 1000000000000472 [] 1000000000000473 [] 1000000000000477 [2, 2] 1000000000000481 [2] 1000000000000488 [12, 2, 2] 1000000000000489 [2, 2, 2] 1000000000000492 [24] 1000000000000493 [] 1000000000000497 [] 1000000000000501 [12] 1000000000000504 [24] 1000000000000505 [2, 2, 2] 1000000000000508 [2, 2] 1000000000000509 [2] 1000000000000513 [] 1000000000000517 [2] 1000000000000520 [10, 2] 1000000000000524 [6, 2, 2, 2, 2] 1000000000000529 [2, 2] 1000000000000537 [2, 2, 2] 1000000000000540 [6, 2, 2] 1000000000000541 [27] 1000000000000545 [2, 2, 2] 1000000000000549 [2] 1000000000000552 [2] 1000000000000553 [14] 1000000000000556 [2, 2] 1000000000000561 [6, 2] 1000000000000565 [2, 2] 1000000000000568 [2] 1000000000000569 [] 1000000000000572 [36, 2, 2, 2, 2] 1000000000000577 [4, 2] 1000000000000581 [6, 3] 1000000000000585 [2, 2] 1000000000000588 [2] 1000000000000589 [36, 2] 1000000000000597 [4] 1000000000000601 [54, 2] 1000000000000604 [4, 2] 1000000000000605 [4, 2] 1000000000000609 [16] 1000000000000613 [] 1000000000000616 [2, 2, 2] 1000000000000617 [4, 2, 2, 2] 1000000000000621 [12, 2] 1000000000000632 [2] 1000000000000633 [2] 1000000000000636 [2] 1000000000000637 [2] 1000000000000641 [2] 1000000000000645 [2, 2] 1000000000000648 [10, 2, 2] 1000000000000649 [14] 1000000000000652 [2, 2] 1000000000000653 [8] 1000000000000657 [3] 1000000000000661 [2] 1000000000000664 [4, 2] 1000000000000668 [4, 2, 2] 1000000000000669 [36] 1000000000000673 [2] 1000000000000677 [2, 2, 2] 1000000000000681 [9] 1000000000000684 [12, 2] 1000000000000685 [4, 2, 2] 1000000000000689 [4] 1000000000000693 [] 1000000000000696 [2, 2, 2] 1000000000000697 [] 1000000000000705 [12, 2, 2] 1000000000000709 [36] 1000000000000712 [4, 2, 2] 1000000000000713 [4, 2] 1000000000000716 [2, 2, 2] 1000000000000717 [8, 4] 1000000000000721 [] 1000000000000732 [2, 2] 1000000000000733 [2] 1000000000000741 [] 1000000000000744 [2, 2] 1000000000000745 [6] 1000000000000748 [2] 1000000000000749 [8, 2] 1000000000000753 [2, 2] 1000000000000757 [] 1000000000000760 [2, 2, 2] 1000000000000761 [14] 1000000000000765 [2] 1000000000000769 [] 1000000000000776 [4, 2, 2] 1000000000000777 [] 1000000000000780 [6, 2, 2, 2] 1000000000000781 [2, 2, 2] 1000000000000785 [6, 2] 1000000000000789 [6] 1000000000000792 [10, 2] 1000000000000793 [2, 2] 1000000000000796 [] 1000000000000797 [2] 1000000000000801 [4] 1000000000000805 [4, 2] 1000000000000808 [2, 2] 1000000000000812 [2, 2, 2, 2] 1000000000000813 [8, 2] 1000000000000817 [2, 2] 1000000000000821 [2, 2] 1000000000000824 [4, 2] 1000000000000828 [2, 2] 1000000000000829 [] 1000000000000833 [2, 2, 2] 1000000000000837 [12, 2] 1000000000000840 [2, 2] 1000000000000841 [2] 1000000000000844 [2, 2, 2] 1000000000000849 [2] 1000000000000853 [6] 1000000000000856 [2] 1000000000000857 [3] 1000000000000860 [4, 2, 2, 2] 1000000000000861 [6] 1000000000000865 [32, 2, 2] 1000000000000869 [16, 2, 2, 2] 1000000000000873 [] 1000000000000877 [2] 1000000000000885 [2, 2, 2] 1000000000000888 [13] 1000000000000889 [54, 2] 1000000000000892 [30, 2, 2] 1000000000000893 [2] 1000000000000897 [2, 2, 2] 1000000000000904 [2, 2, 2] 1000000000000905 [2, 2, 2] 1000000000000909 [2, 2, 2] 1000000000000913 [8] 1000000000000920 [2, 2] 1000000000000921 [] 1000000000000924 [2, 2, 2, 2] 1000000000000929 [4] 1000000000000933 [] 1000000000000936 [2, 2] 1000000000000937 [2, 2] 1000000000000941 [6] 1000000000000945 [4] 1000000000000949 [] 1000000000000952 [4] 1000000000000956 [2, 2] 1000000000000957 [2, 2] 1000000000000961 [2, 2, 2, 2] 1000000000000965 [2, 2] 1000000000000968 [2, 2, 2] 1000000000000969 [2] 1000000000000972 [2] 1000000000000973 [6] 1000000000000977 [64, 2] 1000000000000981 [2, 2] 1000000000000984 [2, 2, 2] 1000000000000985 [2, 2] 1000000000000988 [108] 1000000000000993 [] 1000000000000997 [12] -999999999999995 [3872378, 2] -999999999999992 [2471436, 2, 2, 2] -999999999999991 [9144306, 2] -999999999999988 [1124902, 2, 2] -999999999999987 [913748, 2, 2, 2] -999999999999983 [13126428, 2] -999999999999979 [2148058, 2, 2] -999999999999976 [2984712, 2, 2] -999999999999971 [7798614, 2] -999999999999967 [11253252] -999999999999960 [481528, 2, 2, 2, 2] -999999999999959 [25233340, 2] -999999999999956 [9820206, 2] -999999999999955 [2185542, 2] -999999999999951 [11807322, 2] -999999999999947 [7261653] -999999999999944 [7665042, 2] -999999999999943 [17982820] -999999999999940 [1458740, 2, 2] -999999999999939 [1705720, 2, 2] -999999999999935 [3815348, 2, 2, 2] -999999999999931 [377454, 2, 2, 2, 2] -999999999999928 [3090498, 2] -999999999999924 [275778, 2, 2, 2, 2, 2, 2] -999999999999923 [2614376, 2, 2] -999999999999919 [20175156] -999999999999915 [878588, 2, 2, 2] -999999999999912 [3618208, 2] -999999999999911 [31532754] -999999999999908 [12931036] -999999999999907 [3859738] -999999999999903 [448308, 2, 2, 2, 2, 2] -999999999999899 [21701582] -999999999999895 [4135150, 2, 2] -999999999999892 [1620700, 2, 2] -999999999999887 [10190276, 2, 2] -999999999999883 [2498825] -999999999999880 [1139478, 2, 2, 2] -999999999999879 [9394500, 2] -999999999999876 [1305236, 2, 2, 2] -999999999999871 [13406168, 2] -999999999999867 [4308820, 2] -999999999999863 [7643020, 2] -999999999999860 [4852422, 2, 2] -999999999999859 [3024070, 2] -999999999999851 [1199052, 4, 2] -999999999999848 [6290596, 2] -999999999999844 [5296516, 2] -999999999999843 [3731152, 2] -999999999999839 [42706704] -999999999999835 [1378294, 2, 2] -999999999999832 [974764, 2, 2, 2] -999999999999831 [21097546, 2] -999999999999827 [7464103] -999999999999823 [4886300, 2] -999999999999816 [3866004, 2, 2] -999999999999815 [8445968, 2, 2] -999999999999812 [1381066, 2, 2, 2] -999999999999811 [3696512, 2] -999999999999807 [3253596, 2, 2] -999999999999803 [7540922, 2] -999999999999799 [17550154] -999999999999796 [2206538, 2, 2] -999999999999795 [1527752, 2, 2] -999999999999791 [31405878] -999999999999787 [5207448] -999999999999780 [760782, 2, 2, 2, 2] -999999999999779 [11011782] -999999999999771 [3947234, 2] -999999999999768 [1192776, 2, 2, 2] -999999999999767 [1232812, 2, 2, 2, 2] -999999999999764 [7211408, 2] -999999999999763 [1285040, 2, 2] -999999999999759 [3402540, 2, 2, 2] -999999999999755 [3392056, 4] -999999999999752 [3435556, 2, 2] -999999999999751 [2159360, 2, 2, 2] -999999999999748 [3957274, 2] -999999999999743 [11495572, 2] -999999999999739 [4758772] -999999999999736 [4989568, 2] -999999999999735 [2123290, 2, 2, 2] -999999999999732 [2033166, 2, 2] -999999999999731 [15293774] -999999999999727 [9307746] -999999999999723 [499770, 2, 2, 2] -999999999999719 [11514202, 2, 2] -999999999999716 [1035944, 8, 2] -999999999999707 [1111128, 2, 2, 2] -999999999999704 [3465724, 2, 2] -999999999999703 [10063644, 2] -999999999999699 [2335196, 2, 2] -999999999999695 [7306262, 2, 2] -999999999999691 [1922812, 2, 2] -999999999999688 [480138, 6, 2] -999999999999687 [3846148, 2, 2] -999999999999683 [3139616, 2] -999999999999679 [5354308, 2, 2] -999999999999672 [2178978, 2, 2] -999999999999671 [21071960, 2] -999999999999668 [6288672, 2] -999999999999667 [2443850, 2] -999999999999663 [2452980, 2, 2, 2] -999999999999659 [11343307] -999999999999656 [20023842] -999999999999655 [3183568, 4] -999999999999652 [2245500, 2] -999999999999647 [6567154, 2, 2] -999999999999643 [3389457] -999999999999640 [181472, 4, 2, 2, 2, 2] -999999999999636 [3131420, 2, 2] -999999999999635 [4518528, 2] -999999999999631 [889308, 2, 2, 2, 2] -999999999999627 [368676, 2, 2, 2, 2] -999999999999624 [3148536, 2, 2] -999999999999623 [7549890, 2, 2] -999999999999620 [6700476, 2] -999999999999619 [6401220] -999999999999615 [16746558, 2] -999999999999611 [6632280, 2] -999999999999608 [3452468, 4] -999999999999607 [4112552, 2, 2] -999999999999604 [1056580, 2, 2, 2] -999999999999599 [39104546] -999999999999595 [173704, 4, 2, 2, 2] -999999999999592 [1255062, 2, 2] -999999999999591 [16457136, 2] -999999999999588 [1333928, 2, 2, 2] -999999999999587 [7930856] -999999999999583 [8857554] -999999999999579 [2607088, 2, 2] -999999999999572 [1824280, 2, 2, 2] -999999999999571 [7737015] -999999999999563 [5842726, 2] -999999999999560 [787644, 2, 2, 2, 2] -999999999999556 [3220034, 2, 2] -999999999999555 [200052, 4, 2, 2, 2] -999999999999551 [34658682] -999999999999547 [1902240, 2] -999999999999544 [2464376, 4] -999999999999543 [11437680] -999999999999539 [1482104, 2, 2, 2] -999999999999535 [4463256, 2, 2] -999999999999528 [1134018, 2, 2, 2] -999999999999527 [22589484] -999999999999524 [2781866, 2, 2, 2] -999999999999523 [1317604, 4] -999999999999519 [851520, 4, 2, 2, 2] -999999999999515 [6167982] -999999999999512 [676026, 2, 2, 2, 2] -999999999999508 [4069512, 2] -999999999999507 [287934, 2, 2, 2, 2] -999999999999503 [18452280, 2] -999999999999499 [4420082] -999999999999496 [8867516] -999999999999492 [1799496, 2, 2] -999999999999491 [12931961] -999999999999487 [13431888] -999999999999483 [2954944, 2] -999999999999480 [658258, 2, 2, 2, 2] -999999999999479 [42634930] -999999999999476 [530106, 2, 2, 2, 2, 2] -999999999999471 [21070792] -999999999999467 [2013918, 2, 2] -999999999999464 [9339422, 2] -999999999999463 [12087026] -999999999999460 [1021798, 2, 2, 2] -999999999999451 [3551814, 2] -999999999999448 [871296, 2, 2, 2] -999999999999447 [2331996, 4, 2] -999999999999444 [760910, 2, 2, 2, 2] -999999999999443 [4886894, 2] -999999999999439 [7887366, 3] -999999999999435 [3573078, 2] -999999999999431 [36933388] -999999999999428 [5934232, 2] -999999999999427 [946428, 2, 2] -999999999999419 [7505708, 2] -999999999999416 [2201616, 6, 2] -999999999999415 [7505874, 2] -999999999999412 [3733110, 2] -999999999999411 [8423382] -999999999999407 [3056636, 2, 2, 2] -999999999999403 [438314, 2, 2, 2] -999999999999399 [5204266, 2, 2] -999999999999395 [440000, 4, 4, 2] -999999999999391 [14843488, 2] -999999999999384 [2002552, 2, 2, 2] -999999999999383 [19605798] -999999999999380 [2144856, 2, 2, 2] -999999999999379 [5267274] -999999999999371 [6940440, 2] -999999999999368 [1560324, 2, 2, 2] -999999999999367 [15851448] -999999999999364 [984184, 2, 2, 2] -999999999999363 [3479512, 2] -999999999999359 [10558080, 4] -999999999999355 [5188556] -999999999999348 [1472778, 2, 2, 2] -999999999999347 [2888262, 3] -999999999999343 [1765078, 2, 2, 2] -999999999999339 [2666192, 2, 2] -999999999999336 [2780706, 2, 2] -999999999999335 [8120196, 2, 2] -999999999999332 [12013212] -999999999999331 [3435240] -999999999999327 [2825256, 4, 2] -999999999999323 [8120472] -999999999999320 [7587430, 2] -999999999999319 [3528900, 2, 2] -999999999999316 [2926406, 2, 2] -999999999999311 [37355466] -999999999999307 [1562448, 4] -999999999999304 [6246412, 2] -999999999999303 [2311596, 2, 2, 2] -999999999999299 [5152654, 2, 2] -999999999999295 [3017552, 2, 2] -999999999999291 [682078, 2, 2, 2] -999999999999287 [6563352, 2, 2] -999999999999284 [3932520, 2, 2] -999999999999283 [6236089] -999999999999272 [4838350, 2, 2] -999999999999271 [19947218] -999999999999268 [948156, 2, 2] -999999999999267 [813228, 2, 2] -999999999999263 [27501864] -999999999999256 [1905422, 2, 2] -999999999999255 [3073434, 2, 2, 2] -999999999999247 [3166660, 2, 2] -999999999999240 [515266, 2, 2, 2, 2] -999999999999239 [2062240, 8, 2] -999999999999236 [1284828, 4, 2, 2] -999999999999235 [329016, 6, 2] -999999999999227 [11870444] -999999999999224 [2451664, 4, 2] -999999999999223 [4068880, 4] -999999999999219 [1892074, 2, 2] -999999999999215 [11095728, 2, 2] -999999999999211 [3135780, 2] -999999999999208 [982388, 2, 2, 2] -999999999999204 [4434704, 2, 2] -999999999999203 [1940982, 3] -999999999999199 [23272893] -999999999999195 [1021548, 2, 2, 2] -999999999999192 [4345186, 2] -999999999999191 [31434168] -999999999999188 [3242488, 2, 2] -999999999999187 [2881940, 2] -999999999999183 [17566220] -999999999999179 [2219256, 2, 2] -999999999999176 [7857696, 2] -999999999999172 [1647452, 2, 2] -999999999999167 [5533268, 2, 2] -999999999999163 [3285527] -999999999999160 [2366136, 2, 2] -999999999999159 [16819386, 2] -999999999999156 [757280, 2, 2, 2, 2] -999999999999155 [2575746, 2, 2] -999999999999151 [9783152, 2] -999999999999147 [210532, 4, 2, 2, 2] -999999999999143 [3668170, 2, 2, 2] -999999999999140 [2439050, 2, 2, 2] -999999999999139 [4723660, 2] -999999999999131 [2175188, 2, 2, 2] -999999999999128 [4662970, 2] -999999999999127 [11240510] -999999999999124 [313380, 6, 2, 2] -999999999999123 [580976, 2, 2, 2] -999999999999119 [27047100] -999999999999115 [2647620, 2] -999999999999107 [2325772, 2, 2] -999999999999103 [14333463] -999999999999096 [3888906, 2, 2] -999999999999095 [40990872] -999999999999092 [1314992, 4, 2] -999999999999091 [1503646, 2, 2] -999999999999087 [9765916, 2] -999999999999083 [11734392] -999999999999080 [909790, 2, 2, 2, 2] -999999999999079 [18131164] -999999999999076 [5363012, 2] -999999999999071 [30434221] -999999999999067 [2822928] -999999999999064 [4215872, 2] -999999999999060 [929084, 2, 2, 2] -999999999999059 [2815234, 2, 2] -999999999999055 [9636108, 2] -999999999999051 [4857524, 2] -999999999999048 [1242132, 2, 2, 2] -999999999999047 [24219706] -999999999999044 [2202860, 2, 2, 2] -999999999999043 [3834587] -999999999999039 [2550480, 8] -999999999999035 [816218, 2, 2, 2, 2] -999999999999032 [9616060] -999999999999031 [19377240] -999999999999028 [937052, 4, 2] -999999999999023 [24634500] -999999999999019 [8268794] -999999999999016 [2220068, 2, 2] -999999999999015 [1964780, 2, 2, 2] -999999999999012 [2168582, 2, 2] -999999999999011 [10976478] -999999999999007 [2903838, 2, 2] -999999999999003 [4036316, 2] ? setrand(11);quadclassunit(-8419588).cyc [176, 2] ? setrand(2);quadclassunit(-1459008).cyc [16, 4, 2, 2] ? setrand(7);quadclassunit(-3799812).cyc [54, 2, 2, 2] ? setrand(1);quadclassunit(-13163208).cyc [156, 2, 2] ? setrand(38);quadclassunit(-29920).cyc [4, 2, 2, 2] ? quadclassunit(-13163208,,[0.1]).cyc [156, 2, 2] ? setrand(1);quadclassunit((2^70+25)).cyc [17] ? setrand(1);quadclassunit(8*3*5*7).cyc [2, 2] ? setrand(1);quadclassunit(-612556842419).cyc [192199] ? setrand(2);quadclassunit(-699,,[6,6]).cyc [10] ? print("Total time spent: ",gettime); Total time spent: 3304 pari-2.11.2/src/test/32/qfb0000644000175000017500000000272013326135265013652 0ustar billbill[-1, 6, 6] Qfb(-2, -34, 17, -1.2031810657666797073140254201751247272) Qfb(-2, 34, 17, 3.6095431973000391219420762605253741816) Qfb(1, 34, -34, 0.E-38) Qfb(-2, 34, 17, 1.2031810657666797073140254201751247272) Qfb(17, 34, -2, -2.9945542852277529726974917240067615601) Qfb(17, 34, -2, -22194773194531041164.334277319893643413) Qfb(1, -1, 6) Qfb(8, 13, 6) Qfb(1, 1, 6) Qfb(1009, 60, 99108027750247771) Qfb(1, 0, 100000000000000000039) Qfb(1, 0, 100000000000000000039) Qfb(1, 1, 6) [Qfb(1, 1, 6), [22479, 76177; -39508, -133885]] [Qfb(4, 3, -3, 0.E-38), [127327, -416128; -148995, 486943]] Qfb(4, 3, -3, 0.E-38) 4 -3 3/2 [Qfb(4, 3, -3, 0.E-38), [127327, -416128; -148995, 486943]] *** at top-level: qfbredsl2(q,[D]) *** ^---------------- *** qfbredsl2: incorrect type in qfbredsl2 (t_VEC). Qfb(18446744073709551629, 4741036151112220792, 304625896260305173) Qfb(18446744073709551629, 7562574061564804959, 775103267656920011, 0.E-38) *** at top-level: qfbredsl2(q,[D,1.]) *** ^------------------- *** qfbredsl2: incorrect type in qfbredsl2 (t_VEC). *** at top-level: f*g *** ^-- *** _*_: inconsistent exact division t_INT , t_INT. *** at top-level: f/g *** ^-- *** _/_: inconsistent exact division t_INT , t_INT. Qfb(-1, 12, 0, 0.34657359027997265470861606072908828404) *** at top-level: f/g *** ^-- *** _/_: inconsistent exact division t_INT , t_INT. Total time spent: 1 pari-2.11.2/src/test/32/polclass0000644000175000017500000000012413326135265014716 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). Total time spent: 13512 pari-2.11.2/src/test/32/env0000644000175000017500000000006613036414402013662 0ustar billbill"/root" 1 "XXX, YYY, XXX" "XXX" 0 Total time spent: 0 pari-2.11.2/src/test/32/gammamellininv0000644000175000017500000000045713201017466016101 0ustar billbill2.9297691204814688720898602967358431836 E-19976 2.41 e-35 3.68 e-40 [1] [1, -3/64, 105/8192, -3465/524288, 675675/134217728, -43648605/8589934592, 7 027425405/1099511627776, -677644592625/70368744177664, 609202488769875/36028 797018963968, -78180986058800625/2305843009213693952] Total time spent: 3660 pari-2.11.2/src/test/32/quaddisc0000644000175000017500000000135313326135265014700 0ustar billbill-4 -11 -8 -388 -24 -95 -376 -372 -23 -91 -40 -356 -88 -87 -344 -340 -84 -83 -328 -4 -20 -79 -312 -308 -19 -3 -296 -292 -8 -71 -280 -276 -68 -67 -264 -26 0 -4 -7 -248 -244 -15 -59 -232 -228 -56 -55 -24 -212 -52 -51 -8 -4 -3 -47 -1 84 -20 -11 -43 -168 -164 -40 -39 -152 -148 -4 -35 -136 -132 -8 -31 -120 -116 -7 -3 -104 -4 -24 -23 -88 -84 -20 -19 -8 -68 -4 -15 -56 -52 -3 -11 -40 -4 - 8 -7 -24 -20 -4 -3 -8 -4 0 1 8 12 1 5 24 28 8 1 40 44 12 13 56 60 1 17 8 76 5 21 88 92 24 1 104 12 28 2 9 120 124 8 33 136 140 1 37 152 156 40 41 168 172 44 5 184 188 12 1 8 204 13 53 24 220 56 57 232 236 60 61 248 28 1 65 264 268 17 69 280 284 8 73 296 12 76 77 312 316 5 1 328 332 21 85 344 348 88 89 40 364 92 93 376 380 24 97 8 44 1 Total time spent: 1 pari-2.11.2/src/test/32/galoisinit0000644000175000017500000001360613326135265015251 0ustar billbill[2, 1] [16, 10] [20, 3] [24, 12] [4, 2] [4, 2] [4, 2] [4, 2] [12, 3] [24, 12] [54, 11] [54, 14] [64, 66] [8, 5] [4, 2] [14, 1] *** at top-level: do(x^48+688253440*x^36+64889579202*x^24+688253 *** ^---------------------------------------------- *** in function do: galoisidentify(galoisinit(p)) *** ^----------------------------- *** galoisidentify: incorrect type in checkgal (t_INT). [x]~ [-x, x]~ [-x, x, -x^3, x^3]~ [11 0 0 10 7 1] [ 0 11 0 6 1 1] [ 0 0 11 7 1 5] [ 0 0 0 1 0 0] [ 0 0 0 0 1 0] [ 0 0 0 0 0 1] [11, [9, 10, 5, 10, 6, 10]~, 1, 3, [10, 0, 0, -1, -4, 1; 4, 10, 0, -1, -5, - 3; 5, 4, 10, -1, -5, -4; 1, 5, 4, 9, -5, -4; 0, 1, 5, 3, 5, -4; 0, 0, 1, 4, -1, 6]] Mod(x^4 + x^2, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) 1/2 [1, 1] [1, 1/2] [1, Mod(x^2, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1)] [1, Mod(x^2, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1)] [1, [0, 0, 0, 0, 0, 0]~] [1, [;]] [1, [1, 2; Mod(x^2, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1), 3]] [25343300/14121030321*x^11 + 162850/4707010107*x^9 - 251993549/4707010107*x^ 7 - 9261852590/14121030321*x^5 + 13704094421/4707010107*x^3 + 21375212764/52 3001123*x, -25343300/14121030321*x^11 - 162850/4707010107*x^9 + 251993549/47 07010107*x^7 + 9261852590/14121030321*x^5 - 13704094421/4707010107*x^3 - 213 75212764/523001123*x, -6335825/14121030321*x^11 - 174397/1046002246*x^10 - 8 1425/9414020214*x^9 + 2174305/3138006738*x^8 + 251993549/18828040428*x^7 + 2 776168/523001123*x^6 + 4630926295/28242060642*x^5 + 33788356/523001123*x^4 - 13704094421/18828040428*x^3 - 645447089/1569003369*x^2 - 20852211641/209200 4492*x - 2869448765/1046002246] "Group((1, 5)(2, 10)(3, 11)(4, 6)(7, 9)(8, 12), (1, 8)(2, 3)(4, 7)(5, 12)(6, 9)(10, 11), (1, 2, 7)(3, 9, 12)(4, 5, 11)(6, 8, 10))" "PermutationGroup<12|[5, 10, 11, 6, 1, 4, 9, 12, 7, 2, 3, 8], [8, 3, 2, 7, 1 2, 9, 4, 1, 6, 11, 10, 5], [2, 7, 9, 5, 11, 8, 1, 10, 12, 6, 4, 3]>" [[[Vecsmall([10, 7, 11, 9, 6, 5, 2, 12, 4, 1, 3, 8]), Vecsmall([12, 1, 9, 5, 3, 11, 10, 2, 6, 8, 4, 7]), Vecsmall([3, 9, 10, 2, 8, 12, 4, 6, 7, 11, 1, 5 ])], Vecsmall([2, 3, 2])], [[Vecsmall([10, 7, 11, 9, 6, 5, 2, 12, 4, 1, 3, 8 ]), Vecsmall([12, 1, 9, 5, 3, 11, 10, 2, 6, 8, 4, 7])], Vecsmall([2, 3])], [ [Vecsmall([10, 7, 11, 9, 6, 5, 2, 12, 4, 1, 3, 8]), Vecsmall([3, 9, 10, 2, 8 , 12, 4, 6, 7, 11, 1, 5])], Vecsmall([2, 2])], [[Vecsmall([10, 7, 11, 9, 6, 5, 2, 12, 4, 1, 3, 8]), Vecsmall([6, 11, 2, 12, 1, 10, 3, 4, 8, 5, 7, 9])], Vecsmall([2, 2])], [[Vecsmall([10, 7, 11, 9, 6, 5, 2, 12, 4, 1, 3, 8]), Vecs mall([9, 6, 8, 1, 2, 7, 5, 11, 10, 4, 12, 3])], Vecsmall([2, 2])], [[Vecsmal l([10, 7, 11, 9, 6, 5, 2, 12, 4, 1, 3, 8])], Vecsmall([2])], [[Vecsmall([8, 10, 4, 6, 11, 3, 1, 7, 5, 12, 9, 2])], Vecsmall([3])], [[], Vecsmall([])]] [1, 1, 0, 0, 0, 1, 1, 1] [0, [2, 1; 0, 3], [2, 1; 0, 2], [2, 1; 0, 2], [2, 1; 0, 2], Mat(2), Mat(3), [;]] [0, 1, 1, 1, 1, 1, 1, 1] [0, [6], [4], [4], [4], [2], [3], []] [1, 6, 3, 2, 3, 6, 4, 4, 4, 4, 4, 4] [1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1] [x^12 - 24*x^10 - 10*x^9 + 216*x^8 + 180*x^7 - 844*x^6 - 1080*x^5 + 1056*x^4 + 2200*x^3 + 720*x^2 - 240*x - 80, x^2 - 30*x + 180, x^4 - 30*x^3 + 180*x^2 + 1080*x - 6480, x^6 - 18*x^4 + 20*x^3 + 36*x^2 - 60*x + 20, x^4 - 30*x^3 + 180*x^2 + 1080*x - 6480, x^2 - 30*x + 180, x^3 - 30*x + 50, x^3 - 12*x + 14 , x^3 - 12*x - 4, x^3 - 30*x + 50, x^3 - 12*x + 14, x^3 - 12*x - 4] [x^2 - 30*x + 180, Mod(3/4*x^9 - 27/2*x^7 - 9/2*x^6 + 81*x^5 + 54*x^4 - 162* x^3 - 162*x^2 + 30, x^12 - 24*x^10 - 10*x^9 + 216*x^8 + 180*x^7 - 844*x^6 - 1080*x^5 + 1056*x^4 + 2200*x^3 + 720*x^2 - 240*x - 80)] [y^2 - 30*y + 180, Mod(3/4*x^9 - 27/2*x^7 - 9/2*x^6 + 81*x^5 + 54*x^4 - 162* x^3 - 162*x^2 + 30, x^12 - 24*x^10 - 10*x^9 + 216*x^8 + 180*x^7 - 844*x^6 - 1080*x^5 + 1056*x^4 + 2200*x^3 + 720*x^2 - 240*x - 80), [x^6 - 12*x^4 - 1/3* y*x^3 + 36*x^2 + 2*y*x + (4/3*y - 20), x^6 - 12*x^4 + (1/3*y - 10)*x^3 + 36* x^2 + (-2*y + 60)*x + (-4/3*y + 20)]] x^2 + x - 4 x - 1 1 [x - 1, 1] x^6 + 21*x^4 + 116*x^2 + 64 x^6 + 21*x^4 + 116*x^2 + 64 [x^8 - x^6 + x^4 - x^2 + 1, [101, 2, 10201], [7607, 567, 5596, 6117, 2594, 9 634, 4605, 4084], [2678, 1546, 2875, 8203, 2678, 1546, 2875, 8203; 9382, 964 6, 819, 555, 819, 555, 9382, 9646; 197, 6657, 10004, 3544, 197, 6657, 10004, 3544; 9497, 1523, 9233, 149, 704, 8678, 968, 10052; 4676, 9069, 1329, 5328, 4676, 9069, 1329, 5328; 8870, 8166, 9689, 8721, 1331, 2035, 512, 1480; 9069 , 1329, 5328, 4676, 9069, 1329, 5328, 4676; 10052, 704, 8678, 968, 149, 9497 , 1523, 9233], 1, [Vecsmall([1, 2, 3, 4, 5, 6, 7, 8]), Vecsmall([2, 3, 4, 1, 6, 7, 8, 5]), Vecsmall([3, 4, 1, 2, 7, 8, 5, 6]), Vecsmall([4, 1, 2, 3, 8, 5, 6, 7]), Vecsmall([5, 6, 7, 8, 1, 2, 3, 4]), Vecsmall([6, 7, 8, 5, 2, 3, 4 , 1]), Vecsmall([7, 8, 5, 6, 3, 4, 1, 2]), Vecsmall([8, 5, 6, 7, 4, 1, 2, 3] )], [Vecsmall([2, 3, 4, 1, 6, 7, 8, 5]), Vecsmall([5, 6, 7, 8, 1, 2, 3, 4])] , Vecsmall([4, 2])] [[x, Mod(0, x^8 - x^6 + x^4 - x^2 + 1)], [x^2 + 1, Mod(-x^5, x^8 - x^6 + x^4 - x^2 + 1)], [x^2 - 2*x - 4, Mod(-2*x^6 + 2*x^4 + 2, x^8 - x^6 + x^4 - x^2 + 1)], [x^2 + 5, Mod(2*x^7 - x^5 + 2*x^3, x^8 - x^6 + x^4 - x^2 + 1)], [x^4 + 3*x^2 + 1, Mod(x^7 - x^5 + x^3, x^8 - x^6 + x^4 - x^2 + 1)], [x^4 - 2*x^3 + 4*x^2 - 8*x + 16, Mod(2*x^2, x^8 - x^6 + x^4 - x^2 + 1)], [x^4 - 5*x^2 + 5 , Mod(-x^7 + x^5 - x^3 + 2*x, x^8 - x^6 + x^4 - x^2 + 1)], [x^8 - x^6 + x^4 - x^2 + 1, Mod(x, x^8 - x^6 + x^4 - x^2 + 1)]] [[z, Mod(0, x^6 + 108), [x^6 + 108]], [z^2 + 972, Mod(3*x^3, x^6 + 108), [x^ 3 - 1/3*z, x^3 + 1/3*z]], [z^3 + 54, Mod(1/12*x^4 + 3/2*x, x^6 + 108), [x^2 - z*x + 1/3*z^2, x^2 + 1/3*z^2, x^2 + z*x + 1/3*z^2]], [z^3 + 864, Mod(2*x^2 , x^6 + 108), [x^2 - 1/2*z, x^2 - 1/24*z^2*x - 1/2*z, x^2 + 1/24*z^2*x - 1/2 *z]], [z^3 - 54, Mod(-1/12*x^4 + 3/2*x, x^6 + 108), [x^2 - z*x + 1/3*z^2, x^ 2 + z*x + 1/3*z^2, x^2 + 1/3*z^2]], [z^6 + 108, Mod(x, x^6 + 108), [x - z, x + (-1/12*z^4 + 1/2*z), x + (1/12*z^4 + 1/2*z), x + (-1/12*z^4 - 1/2*z), x + (1/12*z^4 - 1/2*z), x + z]]] Total time spent: 1790 pari-2.11.2/src/test/32/str0000644000175000017500000000056713326135265013721 0ustar billbillVecsmall([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]) "hello world!" "\\pmatrix{\n \\frac{1}{2}\\cr\n }" "\\frac{x^3\n + 3\\*y\\*x^2\n + 3\\*y^2\\*x\n + y^3}{x^2\n - 2\\*y\\*x\n + y ^2}" "x" "1/2" "ab1" 1 *** at top-level: Strchr(-1) *** ^---------- *** Strchr: out of range in integer -> character conversion (-1). Total time spent: 0 pari-2.11.2/src/test/32/agm0000644000175000017500000000065113326135265013647 0ustar billbill *** at top-level: agm(1,2+O(5)) *** ^------------- *** agm: not an n-th power residue in Qp_sqrt: 3 + O(5). 0.59907011736779610371996124614016193911 + 0.5990701173677961037199612461401 6193911*I 0.0052400175398595973401348278731495151168 + 0.00293778732531728227546892438 58414176183*I -0.00028140660159115806090031594700401853703 - 0.000120146984355561255780668 97634319815694*I Total time spent: 52 pari-2.11.2/src/test/32/lll0000644000175000017500000000324213036414402013654 0ustar billbill [1 0] [0 1] [ 0 0 -8 5] [ 8 -5 26 -16] [ 13 -8 -5 3] [-21 13 8 -5] [;] [;] [;] [[;], [;]] [[;], [;]] [;] Mat(1) Mat(1) Mat(1) [[;], Mat(1)] [[;], Mat(1)] Mat(1) [;] [;] Mat(1) [Mat(1), [;]] [Mat(1), [;]] [;] [1; 0] [1; 0] error("impossible inverse in dvmdii: 0.") [[-2; 1], [1; 0]] [[-2; 1], [1; 0]] [1; 0] error("incorrect type in rescale_to_int (t_POL).") error("incorrect type in qflll [integer matrix] (t_MAT).") error("incorrect type in qflll [integer matrix] (t_MAT).") error("incorrect type in qflll [integer matrix] (t_MAT).") [[x + 1; -x], [-1; 1]] [-1; 1] error("incorrect type in rescale_to_int (t_POL).") error("incorrect type in qflll [integer matrix] (t_MAT).") error("incorrect type in qflll [integer matrix] (t_MAT).") error("incorrect type in qflll [integer matrix] (t_MAT).") [[;], [-x^2 + 852*x + 833561, x^5 + 1052503*x^4 - 898292021*x^3 - 8780356471 55*x^2 + 1; 1, -x^3 - 1053355*x^2]] [-x^2 + 852*x + 833561, x^5 + 1052503*x^4 - 898292021*x^3 - 878035647155*x^2 + 1; 1, -x^3 - 1053355*x^2] [;] [;] [[;], [;]] [[;], [;]] Mat(1) Mat(1) [[;], Mat(1)] [[;], Mat(1)] [;] [;] [Mat(1), [;]] [Mat(1), [;]] [1; 0] [1; 0] [[-2; 1], [1; 0]] [[-2; 1], [1; 0]] error("incorrect type in rescale_to_int (t_POL).") error("incorrect type in qflllgram [integer matrix] (t_MAT).") error("incorrect type in qflllgram [integer matrix] (t_MAT).") [[x + 1; -x], [-1; 1]] error("incorrect type in rescale_to_int (t_POL).") error("incorrect type in qflllgram [integer matrix] (t_MAT).") error("incorrect type in qflllgram [integer matrix] (t_MAT).") [[;], [-x^2 + 852*x + 833561, x^5 + 1052503*x^4 - 898292021*x^3 - 8780356471 55*x^2 + 1; 1, -x^3 - 1053355*x^2]] Total time spent: 8 pari-2.11.2/src/test/32/forsubset0000644000175000017500000000067413326135265015124 0ustar billbillVecsmall([]) Vecsmall([1]) Vecsmall([2]) Vecsmall([3]) Vecsmall([4]) Vecsmall([1, 2]) Vecsmall([1, 3]) Vecsmall([1, 4]) Vecsmall([2, 3]) Vecsmall([2, 4]) Vecsmall([3, 4]) Vecsmall([1, 2, 3]) Vecsmall([1, 2, 4]) Vecsmall([1, 3, 4]) Vecsmall([2, 3, 4]) Vecsmall([1, 2, 3, 4]) Vecsmall([]) Vecsmall([]) *** at top-level: forsubset('x,s,) *** ^---------------- *** incorrect type in forsubset (t_POL). Total time spent: 0 pari-2.11.2/src/test/32/sumiter0000644000175000017500000000232013326135265014566 0ustar billbill realprecision = 19 significant digits echo = 1 ? intnum(x=0,Pi,sin(x)) 2.000000000000000000 ? intnum(x=0,4,exp(-x^2)) 0.8862269117895689458 ? intnum(x=1,[1],1/(1+x^2))-Pi/4 0.E-19 ? intnum(x=-0.5,0.5,1/sqrt(1-x^2))-Pi/3 0.E-18 ? intnum(x=0,[[1],-I],sin(x)/x)-Pi/2 0.E-18 ? \p38 realprecision = 38 significant digits ? prod(k=1,10,1+1/k!) 3335784368058308553334783/905932868585678438400000 ? prod(k=1,10,1+1./k!) 3.6821540356142043935732308433185262946 ? Pi^2/6*prodeuler(p=2,10000,1-p^-2) 1.0000098157493066238697591433298145222 ? prodinf(n=0,(1+2^-n)/(1+2^(-n+1))) 0.33333333333333333333333333333333333329 ? prodinf(n=0,-2^-n/(1+2^(-n+1)),1) 0.33333333333333333333333333333333333329 ? solve(x=1,4,sin(x)) 3.1415926535897932384626433832795028842 ? sum(k=1,10,2^-k) 1023/1024 ? sum(k=1,10,2.^-k) 0.99902343750000000000000000000000000000 ? 4*sumalt(n=0,(-1)^n/(2*n+1)) 3.1415926535897932384626433832795028842 ? 4*sumalt(n=0,(-1)^n/(2*n+1),1) 3.1415926535897932384626433832795028842 ? sumdiv(8!,x,x) 159120 ? suminf(n=1,2.^-n) 0.99999999999999999999999999999999999999 ? 6/Pi^2*sumpos(n=1,n^-2) 0.99999999999999999999999999999999999999 ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 8 pari-2.11.2/src/test/32/prec0000644000175000017500000000056313201017466014030 0ustar billbill+oo +oo I 77 57 128 1 + O(x) 1 + O(3^5) 1 38 +oo 3 +oo 2 +oo *** at top-level: padicprec(0,"") *** ^--------------- *** padicprec: incorrect type in padicprec (t_STR). 1 1 2 *** at top-level: padicprec(O(2^2),3) *** ^------------------- *** padicprec: inconsistent moduli in padicprec: 2 != 3 2 3 3 3 4 Total time spent: 4 pari-2.11.2/src/test/32/ellratpoints0000644000175000017500000000173213326135265015624 0ustar billbill201 173 203 217 201 209 143 183 137 127 [[-5, 1]] [] [[-3, 0], [-3, -1], [-2, 3], [-2, -4], [-1, 3], [-1, -4], [0, 2], [0, -3], [ 1, 0], [1, -1], [2, 0], [2, -1], [3, 3], [3, -4], [4, 6], [4, -7], [8, 21], [8, -22], [11, 35], [11, -36], [14, 51], [14, -52], [21, 95], [21, -96], [37 , 224], [37, -225], [52, 374], [52, -375], [93, 896], [93, -897], [342, 6324 ], [342, -6325], [406, 8180], [406, -8181], [816, 23309], [816, -23310]] [[-26/9, 28/27], [-26/9, -55/27], [4/9, 35/27], [4/9, -62/27], [7/9, 17/27], [7/9, -44/27], [25/9, 64/27], [25/9, -91/27], [31/9, 116/27], [31/9, -143/2 7]] [[-4, 831896], [-4, -831896], [-1, 3128], [-1, -3128], [0, 15740], [0, -1574 0], [4, 167392], [4, -167392], [5, 399050], [5, -399050], [6, 886754], [6, - 886754]] 470 8 *** at top-level: E=ellinit([0,0,1,-7,6]);ellratpoints(E,[10^5,[ *** ^---------------------- *** ellratpoints: incorrect type in hyperellratpoints (t_VEC). Total time spent: 84 pari-2.11.2/src/test/32/mat0000644000175000017500000004021413326135265013663 0ustar billbillerror("inconsistent addition t_MAT (1x1) + t_MAT (0x1).") error("impossible inverse in gdiv: [Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(0, 2)].") [0, 2] 1 1 [[;], [;]] [[], [;]] *** at top-level: mathouseholder(1,1) *** ^------------------- *** mathouseholder: incorrect type in mathouseholder (t_INT). *** at top-level: mathouseholder(q,1) *** ^------------------- *** mathouseholder: incorrect type in mathouseholder (t_INT). [-3.3612877988091253174761851599065654319, -3.976856899758389008450416890680 9665041, 2.9389389601206943824942150128578581054, 1.772259568771888526939788 0627029321445, -0.93302137188052358042404010605293659373, -0.441231719485000 70444920875205386881091, -0.19040285081078176048183742278228946814, 0.075729 288512033916496344069514741014185, 0.027956052637213235642340429324234659900 , 0.0096284368977104218404148935213290063312, -0.003106198327161964249988204 5902715205667, -0.00094157426540918912117035392430195067794, -0.000268854775 30463015261353875607132041931, -7.2459011321751905080067220992031631462 E-5, 1.8462089149768956890169300433744512910 E-5, 4.4528901897458304967947732271 708068875 E-6, 1.0176789800383226364895152347151747510 E-6, 2.20552412091014 57554655197057289803706 E-7, -4.5349036687475247266974601071424129857 E-8, - 8.8492541140723057133731328535614376294 E-9, -1.6389333061355481368271925736 504820724 E-9, -2.8805272156166119158730325675280896976 E-10, -4.80266664969 65909745773739693929989064 E-11, 7.5916176882374260025503147422014772958 E-1 2, -1.1367331397963498149955520074031835155 E-12, -1.61050664103939094109404 49194291021230 E-13, 2.1558223640276402145487596709860808075 E-14, 2.7214689 692178509667012624472480322726 E-15, -3.232659043848202709644832083123995151 3 E-16, -2.9855883849239760043478182416536329854 E-17, -1.664898755959816497 7470350196661697536 E-17, 2.8771625420725328021428672070297279667 E-18, -1.0 319233712195941381068955784281641143 E-18, 1.6356182814790027911170768841203 266890 E-18, 8.0811640833543317283367798799396420333 E-19, -1.05792311976124 33100847548785453343223 E-19, 3.1212834491595151717446703076475681855 E-20, -6.2236951167032034426610950988624421246 E-20, -4.30278526231190452813726222 95990239750 E-20, -2.7525464198315767914815519496564758696 E-20]~ [;] [1] [1 2 3] [2 3 4] [1 1] [1 5] [1 0] [0 1] error("incorrect type in diagonal (t_MAT).") [1 0 0 0 0] [1 1 0 0 0] [1 3/2 1 0 0] [1 7/4 7/4 1 0] [1 15/8 35/16 15/8 1] [ 4 6] [10 12] [0 -2] [2 4] [0 0] [Mod(0, 2) Mod(0, 2)] [Mod(0, 2) Mod(0, 2)] [Mod(0, 2) Mod(0, 2)] [Mod(0, 7) Mod(5, 7)] [Mod(2, 7) Mod(4, 7)] [Mod(0, 7) Mod(0, 7)] [Mod(0, 18446744073709551629) Mod(18446744073709551627, 18446744073709551629 )] [Mod(2, 18446744073709551629) Mod(4, 18446744073709551629 )] [Mod(0, 18446744073709551629) Mod(0, 18446744073709551629 )] [Mod(0, 3037000507) Mod(3037000505, 3037000507)] [Mod(2, 3037000507) Mod(4, 3037000507)] [Mod(0, 3037000507) Mod(0, 3037000507)] [Mod(0, 2), Mod(0, 2), Mod(0, 2)]~ [Mod(0, 7), Mod(2, 7), Mod(0, 7)]~ [Mod(0, 18446744073709551629), Mod(2, 18446744073709551629), Mod(0, 18446744 073709551629)]~ [Mod(0, 3037000507), Mod(2, 3037000507), Mod(0, 3037000507)]~ matdet: Mod(1, 2) Mod(1, 7) Mod(29, 3037000507) Mod(29, 18446744073709551629) 29 + O(101^3) matrank: 3 3 3 3 3 matadjoint: [Mod(1, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(1, 2), Mod(1, 2); Mod(0, 2) , Mod(1, 2), Mod(0, 2)] [Mod(6, 7), Mod(0, 7), Mod(1, 7); Mod(6, 7), Mod(3, 7), Mod(1, 7); Mod(1, 7) , Mod(2, 7), Mod(1, 7)] [Mod(69, 3037000507), Mod(14, 3037000507), Mod(3037000473, 3037000507); Mod( 3037000499, 3037000507), Mod(3, 3037000507), Mod(1, 3037000507); Mod(3037000 501, 3037000507), Mod(3037000502, 3037000507), Mod(8, 3037000507)] [Mod(69, 18446744073709551629), Mod(14, 18446744073709551629), Mod(184467440 73709551595, 18446744073709551629); Mod(18446744073709551621, 18446744073709 551629), Mod(3, 18446744073709551629), Mod(1, 18446744073709551629); Mod(184 46744073709551623, 18446744073709551629), Mod(18446744073709551624, 18446744 073709551629), Mod(8, 18446744073709551629)] [69 + O(101^3), 14 + O(101^3), 67 + 100*101 + 100*101^2 + O(101^3); 93 + 100 *101 + 100*101^2 + O(101^3), 3 + O(101^3), 1 + O(101^3); 95 + 100*101 + 100* 101^2 + O(101^3), 96 + 100*101 + 100*101^2 + O(101^3), 8 + O(101^3)] matimage: [Mod(1, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(0, 2), Mod(1, 2); Mod(0, 2) , Mod(1, 2), Mod(1, 2)] [Mod(1, 7), Mod(2, 7), Mod(4, 7); Mod(2, 7), Mod(5, 7), Mod(0, 7); Mod(2, 7) , Mod(2, 7), Mod(4, 7)] [Mod(1, 3037000507), Mod(2, 3037000507), Mod(4, 3037000507); Mod(2, 30370005 07), Mod(12, 3037000507), Mod(7, 3037000507); Mod(2, 3037000507), Mod(9, 303 7000507), Mod(11, 3037000507)] [Mod(1, 18446744073709551629), Mod(2, 18446744073709551629), Mod(4, 18446744 073709551629); Mod(2, 18446744073709551629), Mod(12, 18446744073709551629), Mod(7, 18446744073709551629); Mod(2, 18446744073709551629), Mod(9, 184467440 73709551629), Mod(11, 18446744073709551629)] [1 + O(101^3), 2 + O(101^3), 4 + O(101^3); 2 + O(101^3), 12 + O(101^3), 7 + O(101^3); 2 + O(101^3), 9 + O(101^3), 11 + O(101^3)] matimagecompl: Vecsmall([]) Vecsmall([]) Vecsmall([]) Vecsmall([]) Vecsmall([]) matindexrank: [Vecsmall([1, 2, 3]), Vecsmall([1, 2, 3])] [Vecsmall([1, 2, 3]), Vecsmall([1, 2, 3])] [Vecsmall([1, 2, 3]), Vecsmall([1, 2, 3])] [Vecsmall([1, 2, 3]), Vecsmall([1, 2, 3])] [Vecsmall([1, 2, 3]), Vecsmall([1, 2, 3])] matker: [;] [;] [;] [;] [;] lindep: []~ []~ []~ []~ []~ (x)->matsolve(x,vectorv(#x,i,i)): [Mod(1, 2), Mod(1, 2), Mod(0, 2)]~ [Mod(2, 7), Mod(1, 7), Mod(1, 7)]~ [Mod(2827552196, 3037000507), Mod(1256689865, 3037000507), Mod(942517399, 30 37000507)]~ [Mod(16538460204015460081, 18446744073709551629), Mod(11449703218164549287, 18446744073709551629), Mod(17810649450478187780, 18446744073709551629)]~ [66 + 69*101 + 62*101^2 + O(101^3), 7 + 87*101 + 27*101^2 + O(101^3), 56 + 9 0*101 + 20*101^2 + O(101^3)]~ (x)->matsolve(x,matrix(#x,#x,i,j,i+j)): [Mod(0, 2), Mod(1, 2), Mod(0, 2); Mod(1, 2), Mod(1, 2), Mod(1, 2); Mod(1, 2) , Mod(0, 2), Mod(1, 2)] [Mod(2, 7), Mod(2, 7), Mod(2, 7); Mod(4, 7), Mod(0, 7), Mod(3, 7); Mod(5, 7) , Mod(2, 7), Mod(6, 7)] [Mod(628344934, 3037000507), Mod(1466138179, 3037000507), Mod(2303931424, 30 37000507); Mod(2303931419, 3037000507), Mod(314172466, 3037000507), Mod(1361 414020, 3037000507); Mod(209448311, 3037000507), Mod(2513379730, 3037000507) , Mod(1780310642, 3037000507)] [Mod(5724851609082274645, 18446744073709551629), Mod(13357987087858640838, 1 8446744073709551629), Mod(2544378492925455402, 18446744073709551629); Mod(25 44378492925455397, 18446744073709551629), Mod(12085797841395913136, 18446744 073709551629), Mod(3180473116156819246, 18446744073709551629); Mod(190828386 9694091548, 18446744073709551629), Mod(4452662362619546945, 1844674407370955 1629), Mod(6997040855545002342, 18446744073709551629)] [5 + 94*101 + 13*101^2 + O(101^3), 45 + 17*101 + 66*101^2 + O(101^3), 85 + 4 1*101 + 17*101^2 + O(101^3); 80 + 41*101 + 17*101^2 + O(101^3), 52 + 97*101 + 6*101^2 + O(101^3), 24 + 52*101 + 97*101^2 + O(101^3); 35 + 31*101 + 38*10 1^2 + O(101^3), 14 + 73*101 + 55*101^2 + O(101^3), 94 + 13*101 + 73*101^2 + O(101^3)] (x)->x^(-1): [Mod(1, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(1, 2), Mod(1, 2); Mod(0, 2) , Mod(1, 2), Mod(0, 2)] [Mod(6, 7), Mod(0, 7), Mod(1, 7); Mod(6, 7), Mod(3, 7), Mod(1, 7); Mod(1, 7) , Mod(2, 7), Mod(1, 7)] [Mod(1675586489, 3037000507), Mod(2408655575, 3037000507), Mod(2827552195, 3 037000507); Mod(2094483108, 3037000507), Mod(733069088, 3037000507), Mod(125 6689865, 3037000507); Mod(1570862331, 3037000507), Mod(2827552196, 303700050 7), Mod(942517399, 3037000507)] [Mod(15266270957552732385, 18446744073709551629), Mod(12721892464627276986, 18446744073709551629), Mod(16538460204015460080, 18446744073709551629); Mod( 636094623231363849, 18446744073709551629), Mod(15902365580784096232, 1844674 4073709551629), Mod(11449703218164549287, 18446744073709551629); Mod(5088756 985850910794, 18446744073709551629), Mod(16538460204015460081, 1844674407370 9551629), Mod(17810649450478187780, 18446744073709551629)] [79 + 48*101 + 3*101^2 + O(101^3), 98 + 6*101 + 87*101^2 + O(101^3), 65 + 69 *101 + 62*101^2 + O(101^3); 45 + 10*101 + 80*101^2 + O(101^3), 21 + 59*101 + 83*101^2 + O(101^3), 7 + 87*101 + 27*101^2 + O(101^3); 59 + 83*101 + 34*101 ^2 + O(101^3), 66 + 69*101 + 62*101^2 + O(101^3), 56 + 90*101 + 20*101^2 + O (101^3)] (x)->x^2: [Mod(1, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(1, 2), Mod(1, 2); Mod(0, 2) , Mod(1, 2), Mod(0, 2)] [Mod(6, 7), Mod(6, 7), Mod(6, 7); Mod(5, 7), Mod(1, 7), Mod(1, 7); Mod(0, 7) , Mod(1, 7), Mod(3, 7)] [Mod(13, 3037000507), Mod(62, 3037000507), Mod(62, 3037000507); Mod(40, 3037 000507), Mod(211, 3037000507), Mod(169, 3037000507); Mod(42, 3037000507), Mo d(211, 3037000507), Mod(192, 3037000507)] [Mod(13, 18446744073709551629), Mod(62, 18446744073709551629), Mod(62, 18446 744073709551629); Mod(40, 18446744073709551629), Mod(211, 184467440737095516 29), Mod(169, 18446744073709551629); Mod(42, 18446744073709551629), Mod(211, 18446744073709551629), Mod(192, 18446744073709551629)] [13 + O(101^3), 62 + O(101^3), 62 + O(101^3); 40 + O(101^3), 9 + 2*101 + O(1 01^3), 68 + 101 + O(101^3); 42 + O(101^3), 9 + 2*101 + O(101^3), 91 + 101 + O(101^3)] (x)->A*x: [Mod(1, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(1, 2), Mod(1, 2); Mod(0, 2) , Mod(1, 2), Mod(0, 2)] [Mod(6, 7), Mod(6, 7), Mod(6, 7); Mod(5, 7), Mod(1, 7), Mod(1, 7); Mod(0, 7) , Mod(1, 7), Mod(3, 7)] [Mod(13, 3037000507), Mod(62, 3037000507), Mod(62, 3037000507); Mod(40, 3037 000507), Mod(211, 3037000507), Mod(169, 3037000507); Mod(42, 3037000507), Mo d(211, 3037000507), Mod(192, 3037000507)] [Mod(13, 18446744073709551629), Mod(62, 18446744073709551629), Mod(62, 18446 744073709551629); Mod(40, 18446744073709551629), Mod(211, 184467440737095516 29), Mod(169, 18446744073709551629); Mod(42, 18446744073709551629), Mod(211, 18446744073709551629), Mod(192, 18446744073709551629)] [13 + O(101^3), 62 + O(101^3), 62 + O(101^3); 40 + O(101^3), 9 + 2*101 + O(1 01^3), 68 + 101 + O(101^3); 42 + O(101^3), 9 + 2*101 + O(101^3), 91 + 101 + O(101^3)] [;] matdet: 1 1 1 1 1 matrank: 0 0 0 0 0 matadjoint: [;] [;] [;] [;] [;] matimage: [;] [;] [;] [;] [;] matimagecompl: Vecsmall([]) Vecsmall([]) Vecsmall([]) Vecsmall([]) Vecsmall([]) matindexrank: [Vecsmall([]), Vecsmall([])] [Vecsmall([]), Vecsmall([])] [Vecsmall([]), Vecsmall([])] [Vecsmall([]), Vecsmall([])] [Vecsmall([]), Vecsmall([])] matker: [;] [;] [;] [;] [;] lindep: []~ []~ []~ []~ []~ (x)->matsolve(x,vectorv(#x,i,i)): []~ []~ []~ []~ []~ (x)->matsolve(x,matrix(#x,#x,i,j,i+j)): [;] [;] [;] [;] [;] (x)->x^(-1): [;] [;] [;] [;] [;] (x)->x^2: [;] [;] [;] [;] [;] (x)->A*x: [;] [;] [;] [;] [;] Mod(3037000506, 3037000507) Mod(18446744073709551628, 18446744073709551629) [Mod(3, 18446744073709551629), Mod(1, 18446744073709551629), Mod(18446744073 709551628, 18446744073709551629)]~ *** at top-level: matsolve([1,0;0,0]*Mod(1,2),[1,1]~) *** ^----------------------------------- *** matsolve: impossible inverse in gauss: [Mod(1, 2), Mod(0, 2); Mod(0, 2), Mod(0, 2)]. *** at top-level: matsolve([1,0;0,0]*Mod(1,3),[1,1]~) *** ^----------------------------------- *** matsolve: impossible inverse in gauss: [Mod(1, 3), Mod(0, 3); Mod(0, 3), Mod(0, 3)]. [1 2] [3 4] [2 4] [6 8] [Mod(1, 2) Mod(0, 2)] [Mod(1, 2) Mod(0, 2)] [Mod(1, 3) Mod(2, 3)] [Mod(0, 3) Mod(1, 3)] [Mod(1, 18446744073709551629) Mod(2, 18446744073709551629)] [Mod(3, 18446744073709551629) Mod(4, 18446744073709551629)] [1 0] [1 0] [-1.0000000000000000000000000000000000000*I] [ 1] [-1] [ 1] 3 0 error("inconsistent dimensions in gtrace.") [1 0] [0 1] [;] 19009323 [2 0] [0 2] [1 0] [0 1] lindep: [1, 0, 1]~ [1, -2, 1]~ [1, -2, 1]~ [1, -2, 1]~ [3 + O(101^3), 95 + 100*101 + 100*101^2 + O(101^3), 3 + O(101^3)]~ matsupplement: [Mod(1, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(1, 2), Mod(0, 2); Mod(1, 2) , Mod(0, 2), Mod(1, 2)] [Mod(1, 7), Mod(2, 7), Mod(0, 7); Mod(4, 7), Mod(5, 7), Mod(0, 7); Mod(0, 7) , Mod(1, 7), Mod(1, 7)] [Mod(1, 3037000507), Mod(2, 3037000507), Mod(0, 3037000507); Mod(4, 30370005 07), Mod(5, 3037000507), Mod(0, 3037000507); Mod(7, 3037000507), Mod(8, 3037 000507), Mod(1, 3037000507)] [Mod(1, 18446744073709551629), Mod(2, 18446744073709551629), Mod(0, 18446744 073709551629); Mod(4, 18446744073709551629), Mod(5, 18446744073709551629), M od(0, 18446744073709551629); Mod(7, 18446744073709551629), Mod(8, 1844674407 3709551629), Mod(1, 18446744073709551629)] [1 + O(101^3), 2 + O(101^3), 0; 4 + O(101^3), 5 + O(101^3), 0; 7 + O(101^3), 8 + O(101^3), 1] matsupplement: [Mod(1, 2), Mod(0, 2), Mod(0, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(1, 2) , Mod(0, 2), Mod(0, 2), Mod(0, 2); Mod(0, 2), Mod(0, 2), Mod(1, 2), Mod(0, 2 ), Mod(0, 2); Mod(0, 2), Mod(0, 2), Mod(0, 2), Mod(1, 2), Mod(0, 2); Mod(0, 2), Mod(0, 2), Mod(0, 2), Mod(0, 2), Mod(1, 2)] [Mod(1, 7), Mod(0, 7), Mod(0, 7), Mod(0, 7), Mod(0, 7); Mod(0, 7), Mod(1, 7) , Mod(0, 7), Mod(0, 7), Mod(0, 7); Mod(0, 7), Mod(0, 7), Mod(1, 7), Mod(0, 7 ), Mod(0, 7); Mod(0, 7), Mod(0, 7), Mod(0, 7), Mod(1, 7), Mod(0, 7); Mod(0, 7), Mod(0, 7), Mod(0, 7), Mod(0, 7), Mod(1, 7)] [Mod(1, 3037000507), Mod(0, 3037000507), Mod(0, 3037000507), Mod(0, 30370005 07), Mod(0, 3037000507); Mod(0, 3037000507), Mod(1, 3037000507), Mod(0, 3037 000507), Mod(0, 3037000507), Mod(0, 3037000507); Mod(0, 3037000507), Mod(0, 3037000507), Mod(1, 3037000507), Mod(0, 3037000507), Mod(0, 3037000507); Mod (0, 3037000507), Mod(0, 3037000507), Mod(0, 3037000507), Mod(1, 3037000507), Mod(0, 3037000507); Mod(0, 3037000507), Mod(0, 3037000507), Mod(0, 30370005 07), Mod(0, 3037000507), Mod(1, 3037000507)] [Mod(1, 18446744073709551629), Mod(0, 18446744073709551629), Mod(0, 18446744 073709551629), Mod(0, 18446744073709551629), Mod(0, 18446744073709551629); M od(0, 18446744073709551629), Mod(1, 18446744073709551629), Mod(0, 1844674407 3709551629), Mod(0, 18446744073709551629), Mod(0, 18446744073709551629); Mod (0, 18446744073709551629), Mod(0, 18446744073709551629), Mod(1, 184467440737 09551629), Mod(0, 18446744073709551629), Mod(0, 18446744073709551629); Mod(0 , 18446744073709551629), Mod(0, 18446744073709551629), Mod(0, 18446744073709 551629), Mod(1, 18446744073709551629), Mod(0, 18446744073709551629); Mod(0, 18446744073709551629), Mod(0, 18446744073709551629), Mod(0, 1844674407370955 1629), Mod(0, 18446744073709551629), Mod(1, 18446744073709551629)] [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1] *** Warning: new stack size = 1000000 (0.954 Mbytes). 68 2 68 [-2/3 -2/3] [-7/9 -7/9] [ 1 0] [ 0 1] 0 2 17 *** at top-level: vecsum(1) *** ^--------- *** vecsum: incorrect type in vecsum (t_INT). 1 6 *** at top-level: 1~ *** ^-- *** _~: incorrect type in gtrans (t_INT). 0 0 0 Vecsmall([0, 0, 0]) Vecsmall([3, 12, 27]) 3 0 Vecsmall([2, 2, 0, -4, -10]) 2 *** at top-level: vectorsmall(3,i,i^100) *** ^------ *** overflow in t_INT-->long assignment. [1 0 0] [0 0 1] [1 0 0] [0 0 1] [1 0 0] [0 0 1] [1 0] [1 0] [1 2] [0 1] [1 2] [3 4] [1 0 0] [0 0 1] [1 0 0] [0 0 1] [1 0 0] [0 0 1] *** at top-level: m[1,]=[1,2] *** ^----------- *** inconsistent dimensions in matrix row assignment. *** at top-level: m[1,]=[1,2,3,4] *** ^--------------- *** inconsistent dimensions in matrix row assignment. *** at top-level: m[1,]=[1,2,3]~ *** ^-------------- *** incorrect type in matrix row assignment (t_COL). [1, 2, 3] [1 2 3] [1 2 3] [2, 4, 6] [2 4 6] [1 2 3] [;] [;] [;] [;] [;] *** Warning: new stack size = 8000000 (7.629 Mbytes). [0 -1 0] [0 1 1] [ -2 1 0] [3/2 -1/2 0] *** at top-level: [1,2,3;4,5,6]^-1 *** ^--- *** _^_: impossible inverse in ginv: [1, 2, 3; 4, 5, 6]. *** at top-level: [1,2,3;4,5,6;7,8,9]^-1 *** ^--- *** _^_: impossible inverse in ZM_inv: [1, 2, 3; 4, 5, 6; 7, 8, 9]. [;] *** at top-level: 1/Mat([0,0]~) *** ^------------ *** _/_: impossible inverse in ZM_inv: [0; 0]. Total time spent: 962 pari-2.11.2/src/test/32/polygonal0000644000175000017500000000000012314242551015064 0ustar billbillpari-2.11.2/src/test/32/polylog0000644000175000017500000000242513326135265014571 0ustar billbill1.0496589501864398696458324932101000704 2.0886953792151632708518141489041442185 - 4.27563394103876217704892645569519 63565*I 4.3226178452644705784020044544722613393 - 2.90951877177225946407469488966471 03179*I [-0.20561675835602830455905189583075314865 - 0.91596559417721901505460351493 238411077*I, -0.20561675835602830455905189583075314865 + 0.91596559417721901 505460351493238411077*I]~ [0.58224052646501250590265632015968010874, 0.7275863077163333895135362968404 8110789] x + 1/4*x^2 + 1/9*x^3 + 1/16*x^4 + O(x^5) 0.58224052646501250590265632015968010874 + 1.3862943611198906188344642429163 531362*x + 0.61370563888010938116553575708364686385*x^2 + 0.5150591481598541 5844595232388847084820*x^3 + 0.56074461109355209566440484750062706103*x^4 + O(x^5) -2.3699397969983658319855374253503230488 0.87901454183427816216335165300236244393 0.34657359027997265470861606072908828404 320 *** at top-level: polylog(3,2,5) *** ^-------------- *** polylog: invalid flag in polylog. *** at top-level: polylog(2,Mod(1,2),0) *** ^--------------------- *** polylog: sorry, padic polylogarithm is not yet implemented. *** at top-level: polylog(3,"",0) *** ^--------------- *** polylog: incorrect type in gpolylog (t_STR). Total time spent: 2 pari-2.11.2/src/test/32/galois0000644000175000017500000001454313036414402014355 0ustar billbill[2, -1, 1, "S2"]1 [3, 1, 1, "A3"]1 [6, -1, 2, "S3"]1 [4, -1, 1, "C(4) = 4"]1 [4, 1, 2, "E(4) = 2[x]2"]1 [8, -1, 3, "D(4)"]1 [12, 1, 4, "A4"]1 [24, -1, 5, "S4"]1 [5, 1, 1, "C(5) = 5"]1 [10, 1, 2, "D(5) = 5:2"]1 [20, -1, 3, "F(5) = 5:4"]1 [60, 1, 4, "A5"]1 [120, -1, 5, "S5"]1 [6, -1, 1, "C(6) = 6 = 3[x]2"]1 [6, -1, 2, "D_6(6) = [3]2"]1 [12, -1, 3, "D(6) = S(3)[x]2"]1 [12, 1, 4, "A_4(6) = [2^2]3"]1 [18, -1, 5, "F_18(6) = [3^2]2 = 3 wr 2"]1 [24, -1, 6, "2A_4(6) = [2^3]3 = 2 wr 3"]1 [24, 1, 7, "S_4(6d) = [2^2]S(3)"]1 [24, -1, 8, "S_4(6c) = 1/2[2^3]S(3)"]1 [36, -1, 9, "F_18(6):2 = [1/2.S(3)^2]2"]1 [36, 1, 10, "F_36(6) = 1/2[S(3)^2]2"]1 [48, -1, 11, "2S_4(6) = [2^3]S(3) = 2 wr S(3)"]1 [60, 1, 12, "L(6) = PSL(2,5) = A_5(6)"]1 [72, -1, 13, "F_36(6):2 = [S(3)^2]2 = S(3) wr 2"]1 [120, -1, 14, "L(6):2 = PGL(2,5) = S_5(6)"]1 [360, 1, 15, "A6"]1 [720, -1, 16, "S6"]1 [7, 1, 1, "C(7) = 7"]1 [14, -1, 2, "D(7) = 7:2"]1 [21, 1, 3, "F_21(7) = 7:3"]1 [42, -1, 4, "F_42(7) = 7:6"]1 [168, 1, 5, "L(7) = L(3,2)"]1 [2520, 1, 6, "A7"]1 [5040, -1, 7, "S7"]1 [8, -1, 1, "C(8)=8"]1 [8, 1, 2, "4[x]2"]1 [8, 1, 3, "E(8)=2[x]2[x]2"]1 [8, 1, 4, "D_8(8)=[4]2"]1 [8, 1, 5, "Q_8(8)"]1 [16, -1, 6, "D(8)"]1 [16, -1, 7, "1/2[2^3]4"]1 [16, -1, 8, "2D_8(8)=[D(4)]2"]1 [16, 1, 9, "E(8):2=D(4)[x]2"]1 [16, 1, 10, "[2^2]4"]1 [16, 1, 11, "1/2[2^3]E(4)=Q_8:2"]1 [24, 1, 12, "2A_4(8)=[2]A(4)=SL(2,3)"]1 [24, 1, 13, "E(8):3=A(4)[x]2"]1 [24, 1, 14, "S(4)[1/2]2=1/2(S_4[x]2)"]1 [32, -1, 15, "[1/4.cD(4)^2]2"]1 [32, -1, 16, "1/2[2^4]4"]1 [32, -1, 17, "[4^2]2"]1 [32, 1, 18, "E(8):E_4=[2^2]D(4)"]1 [32, 1, 19, "E(8):4=[1/4.eD(4)^2]2"]1 [32, 1, 20, "[2^3]4"]1 [32, -1, 21, "1/2[2^4]E(4)=[1/4.dD(4)^2]2"]1 [32, 1, 22, "E(8):D_4=[2^3]2^2"]1 [48, -1, 23, "2S_4(8)=GL(2,3)"]1 [48, 1, 24, "E(8):D_6=S(4)[x]2"]1 [56, 1, 25, "E(8):7=F_56(8)"]1 [64, -1, 26, "1/2[2^4]eD(4)"]1 [64, -1, 27, "[2^4]4"]1 [64, -1, 28, "1/2[2^4]dD(4)"]1 [64, 1, 29, "E(8):D_8=[2^3]D(4)"]1 [64, -1, 30, "1/2[2^4]cD(4)"]1 [64, -1, 31, "[2^4]E(4)"]1 [96, 1, 32, "[2^3]A(4)"]1 [96, 1, 33, "E(8):A_4=[1/3.A(4)^2]2=E(4):6"]1 [96, 1, 34, "1/2[E(4)^2:S_3]2=E(4)^2:D_6"]1 [128, -1, 35, "[2^4]D(4)"]1 [168, 1, 36, "E(8):F_21"]1 [168, 1, 37, "L(8)=PSL(2,7)"]1 [192, -1, 38, "[2^4]A(4)"]1 [192, 1, 39, "[2^3]S(4)"]1 [192, -1, 40, "1/2[2^4]S(4)"]1 [192, 1, 41, "E(8):S_4=[E(4)^2:S_3]2=E(4)^2:D_12"]1 [288, 1, 42, "[A(4)^2]2"]1 [336, -1, 43, "L(8):2=PGL(2,7)"]1 [384, -1, 44, "[2^4]S(4)"]1 [576, 1, 45, "[1/2.S(4)^2]2"]1 [576, -1, 46, "1/2[S(4)^2]2"]1 [1152, -1, 47, "[S(4)^2]2"]1 [1344, 1, 48, "E(8):L_7=AL(8)"]1 [20160, 1, 49, "A8"]1 [40320, -1, 50, "S8"]1 [9, 1, 1, "C(9)=9"]1 [9, 1, 2, "E(9)=3[x]3"]1 [18, 1, 3, "D(9)=9:2"]1 [18, -1, 4, "S(3)[x]3"]1 [18, 1, 5, "S(3)[1/2]S(3)=3^2:2"]1 [27, 1, 6, "1/3[3^3]3"]1 [27, 1, 7, "E(9):3=[3^2]3"]1 [36, -1, 8, "S(3)[x]S(3)=E(9):D_4"]1 [36, 1, 9, "E(9):4"]1 [54, 1, 10, "[3^2]S(3)_6"]1 [54, 1, 11, "E(9):6=1/2[3^2:2]S(3)"]1 [54, -1, 12, "[3^2]S(3)"]1 [54, -1, 13, "E(9):D_6=[3^2:2]3=[1/2.S(3)^2]3"]1 [72, 1, 14, "M(9)=E(9):Q_8"]1 [72, -1, 15, "E(9):8"]1 [72, -1, 16, "E(9):D_8"]1 [81, 1, 17, "[3^3]3=3wr3"]1 [108, -1, 18, "E(9):D_12=[3^2:2]S(3)=[1/2.S(3)^2]S(3)"]1 [144, -1, 19, "E(9):2D_8"]1 [162, -1, 20, "[3^3]S(3)=3wrS(3)"]1 [162, 1, 21, "1/2.[3^3:2]S(3)"]1 [162, -1, 22, "[3^3:2]3"]1 [216, 1, 23, "E(9):2A_4"]1 [324, -1, 24, "[3^3:2]S(3)"]1 [324, 1, 25, "[1/2.S(3)^3]3"]1 [432, -1, 26, "E(9):2S_4"]1 [504, 1, 27, "L(9)=PSL(2,8)"]1 [648, -1, 28, "[S(3)^3]3=S(3)wr3"]1 [648, -1, 29, "[1/2.S(3)^3]S(3)"]1 [648, 1, 30, "1/2[S(3)^3]S(3)"]1 [1296, -1, 31, "[S(3)^3]S(3)=S(3)wrS(3)"]1 [1512, 1, 32, "L(9):3=P|L(2,8)"]1 [181440, 1, 33, "A9"]1 [362880, -1, 34, "S9"]1 [10, -1, 1, "C(10)=5[x]2"]1 [10, -1, 2, "D(10)=5:2"]1 [20, -1, 3, "D_10(10)=[D(5)]2"]1 [20, -1, 4, "1/2[F(5)]2"]1 [40, -1, 5, "F(5)[x]2"]1 [50, -1, 6, "[5^2]2"]1 [60, 1, 7, "A_5(10)"]1 [80, 1, 8, "[2^4]5"]1 [100, -1, 9, "[1/2.D(5)^2]2"]1 [100, -1, 10, "1/2[D(5)^2]2"]1 [120, -1, 11, "A(5)[x]2"]1 [120, -1, 12, "1/2[S(5)]2=S_5(10a)"]1 [120, -1, 13, "S_5(10d)"]1 [160, -1, 14, "[2^5]5"]1 [160, 1, 15, "[2^4]D(5)"]1 [160, -1, 16, "1/2[2^5]D(5)"]1 [200, -1, 17, "[5^2:4]2"]1 [200, 1, 18, "[5^2:4]2_2"]1 [200, -1, 19, "[5^2:4_2]2"]1 [200, -1, 20, "[5^2:4_2]2_2"]1 [200, -1, 21, "[D(5)^2]2"]1 [240, -1, 22, "S(5)[x]2"]1 [320, -1, 23, "[2^5]D(5)"]1 [320, 1, 24, "[2^4]F(5)"]1 [320, -1, 25, "1/2[2^5]F(5)"]1 [360, 1, 26, "L(10)=PSL(2,9)"]1 [400, -1, 27, "[1/2.F(5)^2]2"]1 [400, 1, 28, "1/2[F(5)^2]2"]1 [640, -1, 29, "[2^5]F(5)"]1 [720, -1, 30, "L(10):2=PGL(2,9)"]1 [720, 1, 31, "M(10)=L(10)'2"]1 [720, -1, 32, "S_6(10)=L(10):2"]1 [800, -1, 33, "[F(5)^2]2"]1 [960, 1, 34, "[2^4]A(5)"]1 [1440, -1, 35, "L(10).2^2=P|L(2,9)"]1 [1920, -1, 36, "[2^5]A(5)"]1 [1920, 1, 37, "[2^4]S(5)"]1 [1920, -1, 38, "1/2[2^5]S(5)"]1 [3840, -1, 39, "[2^5]S(5)"]1 [7200, -1, 40, "[A(5)^2]2"]1 [14400, -1, 41, "[1/2.S(5)^2]2=[A(5):2]2"]1 [14400, 1, 42, "1/2[S(5)^2]2"]1 [28800, -1, 43, "[S(5)^2]2"]1 [1814400, 1, 44, "A10"]1 [3628800, -1, 45, "S10"]1 [11, 1, 1, "C(11)=11"]1 [22, -1, 2, "D(11)=11:2"]1 [55, 1, 3, "F_55(11)=11:5"]1 [110, -1, 4, "F_110(11)=11:10"]1 [660, 1, 5, "L(11)=PSL(2,11)(11)"]1 [7920, 1, 6, "M(11)"]1 [19958400, 1, 7, "A11"]1 [39916800, -1, 8, "S11"]1 [2, -1, 1, "S2"]1 [3, 1, 1, "A3"]1 [6, -1, 1, "S3"]1 [4, -1, 1, "C(4) = 4"]1 [4, 1, 1, "E(4) = 2[x]2"]1 [8, -1, 1, "D(4)"]1 [12, 1, 1, "A4"]1 [24, -1, 1, "S4"]1 [5, 1, 1, "C(5) = 5"]1 [10, 1, 1, "D(5) = 5:2"]1 [20, -1, 1, "F(5) = 5:4"]1 [60, 1, 1, "A5"]1 [120, -1, 1, "S5"]1 [6, -1, 1, "C(6) = 6 = 3[x]2"]1 [6, -1, 2, "D_6(6) = [3]2"]1 [12, -1, 1, "D(6) = S(3)[x]2"]1 [12, 1, 1, "A_4(6) = [2^2]3"]1 [18, -1, 1, "F_18(6) = [3^2]2 = 3 wr 2"]1 [24, -1, 2, "2A_4(6) = [2^3]3 = 2 wr 3"]1 [24, 1, 1, "S_4(6d) = [2^2]S(3)"]1 [24, -1, 1, "S_4(6c) = 1/2[2^3]S(3)"]1 [36, -1, 1, "F_18(6):2 = [1/2.S(3)^2]2"]1 [36, 1, 1, "F_36(6) = 1/2[S(3)^2]2"]1 [48, -1, 1, "2S_4(6) = [2^3]S(3) = 2 wr S(3)"]1 [60, 1, 1, "L(6) = PSL(2,5) = A_5(6)"]1 [72, -1, 1, "F_36(6):2 = [S(3)^2]2 = S(3) wr 2"]1 [120, -1, 1, "L(6):2 = PGL(2,5) = S_5(6)"]1 [360, 1, 1, "A6"]1 [720, -1, 1, "S6"]1 [7, 1, 1, "C(7) = 7"]1 [14, -1, 1, "D(7) = 7:2"]1 [21, 1, 1, "F_21(7) = 7:3"]1 [42, -1, 1, "F_42(7) = 7:6"]1 [168, 1, 1, "L(7) = L(3,2)"]1 [2520, 1, 1, "A7"]1 [5040, -1, 1, "S7"]1 [16, -1, 7, "1/2[2^3]4"] [10, -1, 1, "C(10)=5[x]2"] [32, -1, 21, "1/2[2^4]E(4)=[1/4.dD(4)^2]2"] [32, -1, 15, "[1/4.cD(4)^2]2"] [8, 1, 2, "4[x]2"] [16, -1, 7, "1/2[2^3]4"] [16, -1, 7, "1/2[2^3]4"] [16, -1, 8, "2D_8(8)=[D(4)]2"] [8, 1, 2, "4[x]2"] [39916800, -1, 8, "S11"] Total time spent: 7552 pari-2.11.2/src/test/32/rootsreal0000644000175000017500000000560413457566440015130 0ustar billbill[1.0000000000000000000000000000000000000, 2.00000000000000000000000000000000 00000, 3.0000000000000000000000000000000000000]~ [1.0000000000000000000000000000000000000]~ [2.0000000000000000000000000000000000000, 3.00000000000000000000000000000000 00000]~ [1.0000000000000000000000000000000000000, 2.00000000000000000000000000000000 00000, 3.0000000000000000000000000000000000000]~ [2.0000000000000000000000000000000000000, 3.00000000000000000000000000000000 00000]~ [1.0000000000000000000000000000000000000, 2.00000000000000000000000000000000 00000]~ 1 2 3 2 2 3 2 2 2 [-22.176420046821213834911725420609849287, -1.220401103882337235735459354425 6902868]~ [-0.98480775301220805936674302458952301367, -0.86602540378443864676372317075 293618347, -0.64278760968653932632264340990726343291, -0.3420201433256687330 4409961468225958076, 0.E-38, 0.34202014332566873304409961468225958076, 0.642 78760968653932632264340990726343291, 0.8660254037844386467637231707529361834 7, 0.98480775301220805936674302458952301367]~ [-0.98768834059513772619004024769343726076, -0.89100652418836786235970957141 362631277, -0.70710678118654752440084436210484903928, -0.4539904997395467915 6040836635787119898, -0.15643446504023086901010531946716689231, 0.1564344650 4023086901010531946716689231, 0.45399049973954679156040836635787119898, 0.70 710678118654752440084436210484903928, 0.891006524188367862359709571413626312 77, 0.98768834059513772619004024769343726076]~ []~ []~ *** at top-level: polrootsreal(0) *** ^--------------- *** polrootsreal: zero polynomial in realroots. *** at top-level: polrootsreal(Pol(0)) *** ^-------------------- *** polrootsreal: zero polynomial in realroots. *** at top-level: polrootsreal(Mod(1,2)) *** ^---------------------- *** polrootsreal: incorrect type in realroots (t_INTMOD). [0.E-38 + 0.E-38*I, 1.0000000000000000000000000000000000000 + 0.E-38*I, 2.00 00000000000000000000000000000000000 + 0.E-38*I, 3.00000000000000000000000000 00000000000 + 0.E-38*I]~ []~ [1.0000000000000000000000000000000000000]~ []~ 1 0 3 2 3 []~ []~ [0.E-38]~ [1.2599210498948731647672106072782283506]~ [-1.2599210498948731647672106072782283506]~ 2 [0.E-38]~ 1 2 [-2.0000000000000000000000000000000000000]~ 1 1 1 1 1 1 1 1 1 [0.59441447601624956642908249516963028371]~ [-1.1451026912004224304268100262663119669, 0.4760236029181340344691576771197 9045497, 3.6690790882822883959576523491465215119]~ [0.E-38, 0.E-38, 1.0000000000000000000000000000000000000]~ [0.E-38, 0.E-38, 1.0000000000000000000000000000000000000, 2.0000000000000000 000000000000000000000, 2.0000000000000000000000000000000000000, 2.0000000000 000000000000000000000000000, 3.0000000000000000000000000000000000000, 3.0000 000000000000000000000000000000000]~ 19 2 [-1.0000000000000000000000000000000000000, 1.0000000000000000000000000000000 000000]~ 2 [0.025327233692927898289899330575272612041]~ []~ Total time spent: 93 pari-2.11.2/src/test/32/memory0000644000175000017500000000045713326135265014417 0ustar billbill *** Warning: new stack size = 1048576 (1.000 Mbytes). *** at top-level: vector(100000,k,k) *** ^-- *** the PARI stack overflows ! current stack size: 1048576 (1.000 Mbytes) [hint] set 'parisizemax' to a non-zero value in your GPRC Total time spent: 10 pari-2.11.2/src/test/32/zetamult0000644000175000017500000000620113326135265014745 0ustar billbill *** Warning: new stack size = 10000000 (9.537 Mbytes). -38 -38 -38 -38 1.2020569031595942853997381615114499908 1 360.000000000000000000000000000000000000000000000000000000 1814400.00000000000000000000000000000000000000000000000000 43589145600.0000000000000000000000000000000000000000000000 3201186852864000.00000000000000000000000000000000000000000 562000363888803840000.000000000000000000000000000000000000 201645730563302817792000000.000000000000000000000000000000 132626429906095529318154240000000.000000000000000000000000 147616399519802070423809304821760000000.000000000000000000 261511308733300555880003612050037145600000000.000000000000 702503058876439949271571303122255784968192000000000.000000 [3360, 46830, -6615, 210, -2]~ [48, 2667, -299, 3, 0]~ [480, -13650, 1455, -8, 0]~ [5040, -201915, 25200, -504, 2]~ [1.64493406684822643647241516664602518921894990120679843774, 1.2020569031595 9428539973816151144999076498629234049888179, 1.20205690315959428539973816151 144999076498629234049888179, 1.082323233711138191516003696541167902774750951 91872690768, 0.270580808427784547879000924135291975693687737979681726921, 0. 811742425283353643637002772405875927081063213939045180762, 1.082323233711138 19151600369654116790277475095191872690768, 1.0369277551433699263313654864570 3416805708091950191281197, 0.09655115998944373446564553142894276403201037234 36914152526, 0.228810397603353759768746148941688791932509342719882160229, 0. 0965511599894437344656455314289427640320103723436914152526, 0.71156619755057 2432096973806086402612092561204438339236492, 0.22881039760335375976874614894 1688791932509342719882160229, 0.71156619755057243209697380608640261209256120 4438339236492, 1.03692775514336992633136548645703416805708091950191281197] Vecsmall([0, 0, 1, 1, 0, 0, 1, 1]) Vecsmall([3, 1, 3, 1]) 89 Vecsmall([0, 0, 1, 1, 0, 0, 1, 1]) Vecsmall([3, 1, 3, 1]) 89 Vecsmall([0, 0, 1, 1, 0, 0, 1, 1]) Vecsmall([3, 1, 3, 1]) 89 *** at top-level: zetamult([1,2]) *** ^--------------- *** zetamult: incorrect type in zetamultconvert (t_VECSMALL). *** at top-level: zetamult("a") *** ^------------- *** zetamult: incorrect type in zetamultconvert (t_STR). *** at top-level: zetamultall(0) *** ^-------------- *** zetamultall: domain error in zetamultall: k < 1 *** at top-level: zetamultall(64) *** ^--------------- *** zetamultall: overflow in zetamultall. *** at top-level: zetamult([0,2,1]) *** ^----------------- *** zetamult: incorrect type in zetamultconvert (t_VECSMALL). *** at top-level: zetamult([0,1,0]) *** ^----------------- *** zetamult: incorrect type in zetamultconvert (t_VECSMALL). *** at top-level: zetamult([0,-1,1]) *** ^------------------ *** zetamult: incorrect type in zetamultconvert (t_VECSMALL). *** at top-level: zetamult([1,-1,1]) *** ^------------------ *** zetamult: incorrect type in zetamultconvert (t_VECSMALL). *** at top-level: zetamult([1,0,1]) *** ^----------------- *** zetamult: incorrect type in zetamultconvert (t_VECSMALL). Total time spent: 26 pari-2.11.2/src/test/32/modular0000644000175000017500000000754713326135265014561 0ustar billbill1: Mod(1, 2)*x^8 + Mod(1, 2)*x^6 + Mod(1, 2)*x^4 + Mod(1, 2)*x^2 + Mod(1, 2) 2: Mod(1, 3)*x^8 + Mod(1, 3)*x^6 + Mod(1, 3)*x^4 + Mod(1, 3)*x^2 + Mod(1, 3) 3: Mod(1, 4294967295)*x^8 + Mod(1, 4294967295)*x^6 + Mod(1, 4294967295)*x^4 + Mod(1, 4294967295)*x^2 + Mod(1, 4294967295) 4: Mod(1, 18446744073709551615)*x^8 + Mod(1, 18446744073709551615)*x^6 + Mod (1, 18446744073709551615)*x^4 + Mod(1, 18446744073709551615)*x^2 + Mod(1, 18 446744073709551615) 5: Mod(1, 100000000000000000000)*x^8 + Mod(1, 100000000000000000000)*x^6 + M od(1, 100000000000000000000)*x^4 + Mod(1, 100000000000000000000)*x^2 + Mod(1 , 100000000000000000000) 1: Mod(1, 2)*x^8 + Mod(1, 2)*x^6 + Mod(1, 2)*x^4 + Mod(1, 2)*x^2 + Mod(1, 2) 2: Mod(1, 3)*x^8 + Mod(1, 3)*x^7 + Mod(2, 3)*x^5 + Mod(2, 3)*x^4 + Mod(2, 3) *x^3 + Mod(1, 3)*x + Mod(1, 3) 3: Mod(1, 4294967295)*x^8 + Mod(4294967293, 4294967295)*x^7 + Mod(3, 4294967 295)*x^6 + Mod(4294967291, 4294967295)*x^5 + Mod(5, 4294967295)*x^4 + Mod(42 94967291, 4294967295)*x^3 + Mod(3, 4294967295)*x^2 + Mod(4294967293, 4294967 295)*x + Mod(1, 4294967295) 4: Mod(1, 18446744073709551615)*x^8 + Mod(18446744073709551613, 184467440737 09551615)*x^7 + Mod(3, 18446744073709551615)*x^6 + Mod(18446744073709551611, 18446744073709551615)*x^5 + Mod(5, 18446744073709551615)*x^4 + Mod(18446744 073709551611, 18446744073709551615)*x^3 + Mod(3, 18446744073709551615)*x^2 + Mod(18446744073709551613, 18446744073709551615)*x + Mod(1, 1844674407370955 1615) 5: Mod(1, 100000000000000000000)*x^8 + Mod(99999999999999999998, 10000000000 0000000000)*x^7 + Mod(3, 100000000000000000000)*x^6 + Mod(999999999999999999 96, 100000000000000000000)*x^5 + Mod(5, 100000000000000000000)*x^4 + Mod(999 99999999999999996, 100000000000000000000)*x^3 + Mod(3, 100000000000000000000 )*x^2 + Mod(99999999999999999998, 100000000000000000000)*x + Mod(1, 10000000 0000000000000) 1: [Mod(1, 2), Mod(0, 2); Mod(1, 2), Mod(0, 2)] 2: [Mod(0, 3), Mod(0, 3); Mod(2, 3), Mod(2, 3)] 3: [Mod(4294967286, 4294967295), Mod(6, 4294967295); Mod(4294967276, 4294967 295), Mod(14, 4294967295)] 4: [Mod(18446744073709551606, 18446744073709551615), Mod(6, 1844674407370955 1615); Mod(18446744073709551596, 18446744073709551615), Mod(14, 184467440737 09551615)] 5: [Mod(99999999999999999991, 100000000000000000000), Mod(6, 100000000000000 000000); Mod(99999999999999999981, 100000000000000000000), Mod(14, 100000000 000000000000)] 1: [Mod(1, 2), Mod(0, 2); Mod(1, 2), Mod(0, 2)] 2: [Mod(1, 3), Mod(1, 3); Mod(0, 3), Mod(1, 3)] 3: [Mod(7, 4294967295), Mod(10, 4294967295); Mod(15, 4294967295), Mod(22, 42 94967295)] 4: [Mod(7, 18446744073709551615), Mod(10, 18446744073709551615); Mod(15, 184 46744073709551615), Mod(22, 18446744073709551615)] 5: [Mod(7, 100000000000000000000), Mod(10, 100000000000000000000); Mod(15, 1 00000000000000000000), Mod(22, 100000000000000000000)] Mod(Mod(1, y), x) Mod(Mod(1, y), x) error("forbidden division t_INT % t_STR.") error("impossible inverse in %: 0.") error("impossible inverse in %: 0.") error("inconsistent division t_SER % t_POL.") Mod(x, x^2) Mod(x, x^2) Mod(x, x^2) Mod(1, 3) Mod(-x, x^2 + 1) [Mod(1, 2), Mod(0, 2)] Mod(1, 2)*x Mod(1, y)*x Mod(0, 2) Mod(0, 2) Mod(2, 7) Mod(4, 7) debug = 1 *** _+_: Warning: coercing quotient rings; moduli 2 and 3 -> 1. Mod(0, 1) *** _-_: Warning: coercing quotient rings; moduli 2 and 3 -> 1. Mod(0, 1) *** _*_: Warning: coercing quotient rings; moduli 2 and 3 -> 1. Mod(0, 1) *** _/_: Warning: coercing quotient rings; moduli 2 and 3 -> 1. Mod(0, 1) Mod(0, 2) Mod(0, 2) Mod(1, 2) Mod(1, 2) *** _+_: Warning: coercing quotient rings; moduli x and x + 1 -> 1. Mod(0, 1) *** _-_: Warning: coercing quotient rings; moduli x and x + 1 -> 1. Mod(0, 1) *** _*_: Warning: coercing quotient rings; moduli x and x + 1 -> 1. Mod(0, 1) *** _/_: Warning: coercing quotient rings; moduli x and x + 1 -> 1. Mod(0, 1) Mod(2, x) Mod(0, x) Mod(1, x) Mod(1, x) 1 1 1 1 1 1 1 Total time spent: 1 pari-2.11.2/src/test/32/equal0000644000175000017500000000071113326135265014207 0ustar billbill[1, 0, 1, 0] [0, 0] [1, 0] [0, 1] [1, 0] [0, 1] [0, 0, 1] [0, 0, 1] [0, 0, 1] [0, 0, 0, 0, 1] 1 0 [0, 0, 0, 1] 0 [0, 1] [0, 0, 0, 1] [1, 1] 1 1 0 [0, 1] [0, 1] 1 0 [0, 1] [0, 1] 1 0 0 1 0 [0, 0] [1, 1] [1, 1] [0, 0] [1, 0] [0, 1] [0, 0] [1, 0] [0, 1] [0, 0] [0, 0] [1, 0] [0, 1] [1, 0] [0, 0] [1, 0] [0, 0] [1, 0] [0, 1] [0, 0] [0, 0] [0, 0] [0, 0] [1, 0] [0, 0] [0, 0] [1, 0] [0, 1] [1, 1] [1, 0] [0, 0] [1, 0] [0, 0] [0, 0] [0, 1] 1 1 Total time spent: 4 pari-2.11.2/src/test/32/ramanujantau0000644000175000017500000000020313326135265015562 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). 1 -804352952075176386846143824455748 0 0 0 -6048 Total time spent: 280 pari-2.11.2/src/test/32/log0000644000175000017500000000030613201017466013653 0ustar billbill9.9999999999999999999999999999950000000 E-31 -5.7721566490153286060651209008157996401 E-31 69.077552789821370520539743640530349012 error("not a prime number in p-adic log: 33.") Total time spent: 1 pari-2.11.2/src/test/32/chinese0000644000175000017500000000045013201017466014510 0ustar billbillMod(x, x^2 + 1) Mod(x, x^4 - 1) Mod(2, 3)*x^2 + Mod(1, 6)*x + Mod(1, 6) [Mod(1, 4), Mod(1, 6)] *** at top-level: chinese(1) *** ^---------- *** chinese: incorrect type in association (t_INT). Mod(0, 1) Mod(x + 1, x^2) Mod(x + 1, 2*x^2) Mod(x + 1, x^2) Total time spent: 0 pari-2.11.2/src/test/32/ff0000644000175000017500000004667113457566441013523 0ustar billbill *** Warning: new stack size = 10000000 (9.537 Mbytes). ? test(2,20) [a, a^2 + a + 1, a^19 + a^18 + a^17 + a^15 + a^14 + a^13 + a^12 + a^8 + a^7 + a^6 + a^4 + a^2 + 1, 0, a + 1, 0, 0, 0, 0, a^19 + a^16 + a^15 + a^11 + a^8 + a^5 + a^4 + a^3 + a^2 + a, a, a^2, a^12 + a^9 + a^6 + a^4 + a^3 + a^2 + a , a^18 + a^17 + a^16 + a^14 + a^13 + a^12 + a^11 + a^10 + a^9 + a^8 + a^7 + a^4 + a^3 + a^2 + 1, a^18 + a^17 + a^16 + a^14 + a^13 + a^12 + a^11 + a^10 + a^9 + a^8 + a^7 + a^4 + a^3 + a^2 + 1, a^16 + a^12 + a^9 + a^6 + a^4 + a^3 + a^2 + a + 1, 0, Mod(1, 2), Mod(0, 2), Mod(1, 2)*x^20 + Mod(1, 2)*x^17 + Mo d(1, 2)*x^16 + Mod(1, 2)*x^12 + Mod(1, 2)*x^9 + Mod(1, 2)*x^6 + Mod(1, 2)*x^ 5 + Mod(1, 2)*x^4 + Mod(1, 2)*x^3 + Mod(1, 2)*x^2 + Mod(1, 2), Mod(1, 2)*x^2 0 + Mod(1, 2)*x^17 + Mod(1, 2)*x^16 + Mod(1, 2)*x^12 + Mod(1, 2)*x^9 + Mod(1 , 2)*x^6 + Mod(1, 2)*x^5 + Mod(1, 2)*x^4 + Mod(1, 2)*x^3 + Mod(1, 2)*x^2 + M od(1, 2), [a, a^2, a^4, a^8, a^16, a^16 + a^12 + a^9 + a^6 + a^4 + a^3 + a^2 , a^16 + a^12 + a^9 + a^6 + a^4 + a^3 + a + 1, a^16 + a^12 + a^9 + a^6 + a^3 + a^2 + a, a^16 + a^12 + a^9 + a^8 + a^6 + a^4 + a^3 + a^2 + a + 1, a^12 + a^9 + a^6 + a^4 + a^3 + a^2 + a, a + 1, a^2 + 1, a^4 + 1, a^8 + 1, a^16 + 1, a^16 + a^12 + a^9 + a^6 + a^4 + a^3 + a^2 + 1, a^16 + a^12 + a^9 + a^6 + a^ 4 + a^3 + a, a^16 + a^12 + a^9 + a^6 + a^3 + a^2 + a + 1, a^16 + a^12 + a^9 + a^8 + a^6 + a^4 + a^3 + a^2 + a]~, [x^3 + (a^17 + a^16 + a^10 + a^7 + a^3) , 1; x^3 + (a^17 + a^16 + a^10 + a^7 + a^3 + a), 1], [], a/x, 1, a^18 + a^17 + a^16 + a^15 + a^12 + a^8 + a^2, 1048575, a, [x + (a^18 + a^16 + a^13 + a^ 9 + a^8 + a^7 + a^6 + a^4 + a^2 + a), 1; x + (a^18 + a^16 + a^13 + a^9 + a^8 + a^7 + a^6 + a^4 + a^2 + a + 1), 1], [a^18 + a^16 + a^13 + a^9 + a^8 + a^7 + a^6 + a^4 + a^2 + a, a^18 + a^16 + a^13 + a^9 + a^8 + a^7 + a^6 + a^4 + a ^2 + a + 1]~] ? test(7,7) [a, a^2 + 3*a + 1, a^6 + 2*a^4 + 5*a^3 + 2*a^2 + 5*a + 1, 3*a + 3, a + 3, 5* a^6 + 3*a^4 + 4*a^3 + 3*a^2 + 4*a, 2*a + 2, 2*a + 2, 4*a + 4, 6*a^6 + 6*a^5 + 5*a^4 + 2, 6*a, a^2, 3*a^6 + 5*a^5 + 3*a^3 + a^2 + 2*a + 6, 4*a^2 + 4*a + 4, 4*a^2 + 4*a + 4, 4, 3*a^6 + 3*a^5 + 5*a^4 + 2*a^3 + 3*a^2 + a + 4, Mod(1, 7), Mod(6, 7), Mod(1, 7)*x^7 + Mod(1, 7)*x^6 + Mod(2, 7)*x^5 + Mod(5, 7)*x + Mod(1, 7), Mod(1, 7)*x^7 + Mod(1, 7)*x^6 + Mod(2, 7)*x^5 + Mod(5, 7)*x + M od(1, 7), [a, 6*a^6 + 5*a^5 + 2*a + 6, 5*a^6 + 6*a^5 + 2*a^3 + 4*a^2 + 3*a + 5, 3*a^6 + 5*a^2 + 5, 6*a^6 + 2*a^5 + 5*a^4 + 5*a^3 + 5*a^2 + a + 5, 2*a^6 + 5*a^2 + 6, 6*a^6 + a^5 + 2*a^4 + 2*a^2]~, [x^2 + (a^6 + 6*a^5 + 4*a^4 + 5* a^3 + 4)*x + 4, 1; x^2 + (2*a^6 + 5*a^5 + a^4 + 3*a^3 + 1)*x + 2, 1; x^2 + ( 4*a^6 + 3*a^5 + 2*a^4 + 6*a^3 + 2)*x + 1, 1], a^6 + 4*a^5 + 4*a^4 + 6*a^2 + a + 4, a/x, (x + a)/(x + 6*a), 5*a^6 + 6*a^5 + 4*a^4 + 2*a^3 + 6*a^2 + 3*a + 5, 274514, a, [x + (2*a^6 + 6*a^5 + 5*a^2 + 2*a + 1), 1; x + (5*a^6 + a^5 + 2*a^2 + 5*a), 1], [2*a^6 + 6*a^5 + 5*a^2 + 2*a, 5*a^6 + a^5 + 2*a^2 + 5*a + 6]~] ? test(precprime(2^32),3) [a, a^2 + 3*a + 1, 3435973833*a^2 + 3435973833, 2863311528*a + 2863311528, a + 3435973833, 3579139409*a^2 + 2863311528, 3579139410*a + 3579139410, 1024* a + 1024, 859832319*a + 859832319, 4294967290*a^2 + 4294967290*a + 4, 429496 7290*a, a^2, 3885163399*a^2 + 2553150559*a + 523234686, a^2 + a + 1, a^2 + a + 1, 1, 4264202413*a^2 + 356078407*a + 3929909005, Mod(25, 4294967291), Mod (4294967290, 4294967291), Mod(1, 4294967291)*x^3 + Mod(1, 4294967291)*x^2 + Mod(4294967287, 4294967291)*x + Mod(1, 4294967291), Mod(1, 4294967291)*x^3 + Mod(1, 4294967291)*x^2 + Mod(4294967287, 4294967291)*x + Mod(1, 4294967291) , [a, a^2 + a + 4294967288, 4294967290*a^2 + 4294967289*a + 2]~, [x + (34444 7023*a^2 + 1616586690*a + 252460086), 1; x + (3340051543*a^2 + 1627577691*a + 2021233148), 1; x^2 + (954915748*a^2 + 2667389600*a + 2273734143)*x + (816 322992*a^2 + 830924795*a + 1995175223), 1; x^2 + (3950520268*a^2 + 267838060 1*a + 4042507205)*x + (1642837480*a^2 + 2548350348*a + 1670376662), 1], 3618 892287*a^2 + 1482857269*a + 1021597254, a/x, (x + a)/(x + 4294967290*a), 349 0383416*a^2 + 1759576229*a + 3092551593, 36893488070109691946, a, [x + (1365 670490*a^2 + 3373566631*a + 4083593885), 1; x + (2929296801*a^2 + 921400660* a + 211373407), 1], [1365670490*a^2 + 3373566631*a + 4083593884, 2929296801* a^2 + 921400660*a + 211373406]~] ? test(nextprime(2^32),3) [a, a^2 + 3*a + 1, a^2 + 4294967310, 1431655771*a + 1431655771, a + 34359738 49, 3579139425*a^2 + 1431655772, 715827886*a + 715827886, 1024*a + 1024, 114 5044996*a + 1145044996, a^2 + a + 4294967309, 4294967310*a, a^2, 264190711*a ^2 + 2629464558*a + 2494776416, 2086193154*a^2 + 2086193154*a + 2086193154, 2208774156*a^2 + 2208774156*a + 2208774156, 2086193154, 996804783*a^2 + 2908 221018*a + 1206110100, Mod(13, 4294967311), Mod(4294967310, 4294967311), Mod (1, 4294967311)*x^3 + Mod(1, 4294967311)*x^2 + Mod(4294967309, 4294967311)*x + Mod(4294967310, 4294967311), Mod(1, 4294967311)*x^3 + Mod(1, 4294967311)* x^2 + Mod(4294967309, 4294967311)*x + Mod(4294967310, 4294967311), [a, a^2 + 4294967309, 4294967310*a^2 + 4294967310*a + 1]~, [x^2 + (2086193155*a^2 + 1 22581001)*x + 2086193154, 1; x^2 + (2208774157*a^2 + 4172386308)*x + 2208774 156, 1; x^2 + (4294967310*a^2 + 2)*x + 1, 1], 1484088443*a^2 + 1141114953*a + 4283364322, a/x, (x + a)/(x + 4294967310*a), 1892124804*a^2 + 446887574*a + 1010425087, 6148914735617846011, a, [x + (268392743*a^2 + 2459390605*a + 1 304316255), 1; x + (4026574568*a^2 + 1835576706*a + 2990651057), 1], [268392 743*a^2 + 2459390605*a + 1304316254, 4026574568*a^2 + 1835576706*a + 2990651 056]~] ? default(echo,0); ? ftest(2,1005,7); ? ffgen(ffinit(2^32-5,101),'a)^10000 2904925334*a^100 + 700105542*a^99 + 1727200511*a^98 + 1173808205*a^97 + 9542 0994*a^96 + 3202419959*a^95 + 2481924190*a^94 + 3126863204*a^93 + 2955970830 *a^92 + 2548647191*a^91 + 1047527349*a^90 + 1607847794*a^89 + 1136036718*a^8 8 + 2224103182*a^87 + 234809824*a^86 + 1334629770*a^85 + 3694521682*a^84 + 2 888958800*a^83 + 2981717284*a^82 + 3586954794*a^81 + 956529198*a^80 + 193357 785*a^79 + 2461870083*a^78 + 2884929899*a^77 + 2136433918*a^76 + 3711607228* a^75 + 332814573*a^74 + 2094440266*a^73 + 933657478*a^72 + 2778340755*a^71 + 3169750773*a^70 + 2171979949*a^69 + 1221433421*a^68 + 901860002*a^67 + 2970 90232*a^66 + 3539970492*a^65 + 2076910613*a^64 + 2401092275*a^63 + 171183351 4*a^62 + 3584831951*a^61 + 2855998596*a^60 + 347617911*a^59 + 2423948087*a^5 8 + 2221962383*a^57 + 2749975174*a^56 + 1550735992*a^55 + 2529466701*a^54 + 2598855843*a^53 + 4023905766*a^52 + 1486945524*a^51 + 2441781373*a^50 + 1138 122930*a^49 + 2066584358*a^48 + 1722922056*a^47 + 3744247345*a^46 + 29285190 73*a^45 + 1223452975*a^44 + 2713760803*a^43 + 2142407081*a^42 + 756824586*a^ 41 + 3732788422*a^40 + 1164553813*a^39 + 771729217*a^38 + 3634297024*a^37 + 2421113272*a^36 + 2598325671*a^35 + 3513778816*a^34 + 1539027125*a^33 + 3689 734857*a^32 + 4188593390*a^31 + 2825758998*a^30 + 3192363801*a^29 + 36501544 35*a^28 + 1334480978*a^27 + 2009094380*a^26 + 151875699*a^25 + 3435707889*a^ 24 + 661453301*a^23 + 416421795*a^22 + 3246563523*a^21 + 985317917*a^20 + 33 10261776*a^19 + 4234321367*a^18 + 380085156*a^17 + 1049653093*a^16 + 6266755 65*a^15 + 1603594749*a^14 + 3130157282*a^13 + 844750099*a^12 + 3495279283*a^ 11 + 1036502501*a^10 + 576151557*a^9 + 1040168751*a^8 + 1714788152*a^7 + 234 0199159*a^6 + 4175283296*a^5 + 2975302344*a^4 + 2428563952*a^3 + 443574314*a ^2 + 3215614405*a + 2183237283 ? ffgen(ffinit(2^64-59,101),'a)^10000 11357361951151958121*a^100 + 5792035517727999732*a^99 + 7489923161672088612* a^98 + 198291789480115765*a^97 + 7027135568582861768*a^96 + 7299386875942518 369*a^95 + 10681924511986429849*a^94 + 14721409711812770068*a^93 + 177845253 02221024156*a^92 + 7804341282953434235*a^91 + 6253292858501893536*a^90 + 375 2205311837838488*a^89 + 12205965799946763222*a^88 + 7579185967234550243*a^87 + 7660231629286376323*a^86 + 8927589722637637677*a^85 + 6783475681455269614 *a^84 + 11968255844292754829*a^83 + 5819238353489370105*a^82 + 6918133330273 010048*a^81 + 8900778062932659277*a^80 + 15250824442906974876*a^79 + 2484274 759583929736*a^78 + 12662494501202465352*a^77 + 1658627870779087936*a^76 + 1 3011592420351927994*a^75 + 1429162280240510446*a^74 + 8085544061123262008*a^ 73 + 12999730205733779276*a^72 + 14782490105219029716*a^71 + 970562341709006 1989*a^70 + 10676813376503700642*a^69 + 13433094161603852463*a^68 + 17199289 874783012603*a^67 + 4285333119776358644*a^66 + 16021251868058308047*a^65 + 1 5495498503350376322*a^64 + 5966197018829209744*a^63 + 12345332784539353625*a ^62 + 14865549204004875095*a^61 + 8272995682833482264*a^60 + 121032254702015 79677*a^59 + 17479835254811511245*a^58 + 3057285969116272639*a^57 + 14559795 162132711775*a^56 + 13046944472429221491*a^55 + 1019495020975929944*a^54 + 1 6803291081324517730*a^53 + 17710829803474400119*a^52 + 2594650197306879903*a ^51 + 12847996295434431851*a^50 + 9729674550253550622*a^49 + 109429518884359 53217*a^48 + 508631243443378452*a^47 + 4416164175737874514*a^46 + 4138550054 669964040*a^45 + 91535476336245596*a^44 + 11254247175995051473*a^43 + 336718 1085033412978*a^42 + 11302910178987761836*a^41 + 14219471129414354857*a^40 + 3472640334363308855*a^39 + 44279726220391285*a^38 + 8772473950884549985*a^3 7 + 6773120702751407339*a^36 + 6996688466561413845*a^35 + 546584401725025696 5*a^34 + 7818703010175000236*a^33 + 13304920141834573258*a^32 + 114357960485 84276*a^31 + 4331469251417299625*a^30 + 17686902244060347692*a^29 + 17607783 19947200401*a^28 + 3012511890706784509*a^27 + 18319341252918336566*a^26 + 10 018340880050704466*a^25 + 3681292000887380307*a^24 + 6241896558174496327*a^2 3 + 9334414729239110374*a^22 + 14900454697774091776*a^21 + 77193581568725477 10*a^20 + 7957196232563221737*a^19 + 14008909657978711585*a^18 + 43480361564 79613902*a^17 + 1768274872694937073*a^16 + 6926632468462411736*a^15 + 138466 31025657876514*a^14 + 16445358444805977559*a^13 + 3015896265596741617*a^12 + 3099427746327195442*a^11 + 7091419183460950797*a^10 + 13541704365745256080* a^9 + 9319609099157088592*a^8 + 3845681432811214920*a^7 + 380965757660125686 6*a^6 + 14250915374958368396*a^5 + 5948030384875855137*a^4 + 434385110189972 4971*a^3 + 16736030436363202463*a^2 + 11764704170600631014*a + 1394491261297 3941130 ? for(i=1,10,print(ffnbirred(11,i))); 11 55 440 3630 32208 295020 2783880 26793030 261994040 2593726344 ? for(i=1,10,print(ffnbirred(11,i,1))); 11 66 506 4136 36344 331364 3115244 29908274 291902314 2885628658 ? t=ffgen(2^64)^((2^64-1)\5);1/t x^58 + x^57 + x^56 + x^52 + x^51 + x^49 + x^46 + x^45 + x^42 + x^39 + x^36 + x^35 + x^32 + x^30 + x^29 + x^25 + x^23 + x^22 + x^21 + x^20 + x^19 + x^12 + x^8 + x^7 + x^6 + x^2 ? sqrt(Mod(-1,4296540161)) Mod(1086811600, 4296540161) ? sqrt(Mod(-1,18446744073944432641)) Mod(6687681666819568403, 18446744073944432641) ? centerlift(factorcantor(prod(i=-10,10,(x^2-i)),2^64+13)[,1]) [x, x + 1, x + 2, x + 3, x + 248527397336721375, x + 2370518075556110396, x + 2888582621843189425, x + 4741036151112220792, x + 5193293969518580612, x + 6494187761904104278, x + 7111554226668331188, x + 7312212166335540022, x + 7562574061564804959, x - 7562574061564804959, x - 7312212166335540022, x - 7 111554226668331188, x - 6494187761904104278, x - 5193293969518580612, x - 47 41036151112220792, x - 2888582621843189425, x - 2370518075556110396, x - 248 527397336721375, x - 3, x - 2, x - 1, x^2 + 2, x^2 + 3, x^2 + 8, x^2 + 10, x ^2 - 10, x^2 - 8, x^2 - 3, x^2 - 2]~ ? conjvec(Mod(x,x^2+Mod(1,3))) [Mod(Mod(1, 3)*x, Mod(1, 3)*x^2 + Mod(1, 3)), Mod(Mod(2, 3)*x, Mod(1, 3)*x^2 + Mod(1, 3))]~ ? default(echo,0); ? test(2^5) [t^4 + t^3; t^4 + t^3; 1] [t, t^2; t + 1, t^2 + 1] 2 t^4 + t^2 [1, 0, 0; 0, 1, 0; 0, 0, 1] [t^2 + t, t^4 + t^3 + 1, t^4 + t^3 + t]~ 1 1 1 1 [0, 1]~ []~ [;] [Vecsmall([1]), Vecsmall([2])] [0, 1; t, 0] []~ [1, 1]~ ? test(7^5) [3*t^4 + 5*t^3 + 6*t^2 + 2*t; 4*t^4 + 2*t^3 + t^2 + 5*t; 1] [t, t^2; t + 1, t^2 + 1] 2 6*t^4 + 2*t^3 + 4*t^2 + 2*t + 2 [1, 0, 0; 0, 1, 0; 0, 0, 1] [3*t^2 + 3*t, 6*t^4 + 5*t^3 + 4*t^2 + 5*t + 6, 6*t^4 + 5*t^3 + 4*t^2 + 6*t]~ 1 1 1 1 [0, 1]~ []~ [;] [Vecsmall([1]), Vecsmall([2])] [0, 1; t, 0] []~ [6, 1]~ ? test((2^64+13)^5) [3*t^4 + 5*t^3 + 18446744073709551621*t^2 + 18446744073709551617*t; 18446744 073709551626*t^4 + 18446744073709551624*t^3 + 8*t^2 + 12*t; 1] [t, t^2; t + 1, t^2 + 1] 2 18446744073709551628*t^4 + 2*t^3 + 18446744073709551626*t^2 + 2*t + 2 [1, 0, 0; 0, 1, 0; 0, 0, 1] [3*t^2 + 3*t, 18446744073709551628*t^4 + 5*t^3 + 4*t^2 + 1844674407370955162 7*t + 18446744073709551628, 18446744073709551628*t^4 + 5*t^3 + 4*t^2 + 18446 744073709551628*t]~ 1 1 1 1 [0, 1]~ []~ [;] [Vecsmall([1]), Vecsmall([2])] [0, 1; t, 0] []~ [18446744073709551628, 1]~ ? default(echo,0); ? test(nextprime(2^7)^5) ? test(nextprime(2^15)^5) ? test(nextprime(2^31)^5) ? test(nextprime(2^63)^5) ? test(nextprime(2^80)^5) ? test(nextprime(2^7)^5,27) ? test(nextprime(2^15)^5,27) ? test(nextprime(2^31)^5,27) ? test(nextprime(2^63)^5,27) ? test(nextprime(2^80)^2,27) ? my(a=ffgen([2,100]));(0*a*x)*x 0 ? default(echo,0); ? test(2,1,5,3) error("domain error in ffcompomap: m domain does not contain codomain of [b, c^12 + c^10 + c^9 + c^5 + c^3 + c^2]") error("domain error in ffcompomap: m domain does not contain codomain of [b, b^5 + b^4 + b^2 + b + 1]") error("domain error in ffmap: m domain does not contain b^4 + b^3 + 1") error("domain error in ffmap: m domain does not contain c^12 + c^10 + c^9 + c^5 + c^3 + c^2") error("incorrect type in ffextend (t_POL).") ? test(2,5,5,3) error("domain error in ffcompomap: m domain does not contain codomain of [b, c^70 + c^69 + c^67 + c^66 + c^64 + c^60 + c^58 + c^57 + c^56 + c^54 + c^51 + c^50 + c^48 + c^47 + c^45 + c^44 + c^42 + c^40 + c^39 + c^37 + c^34 + c^32 + c^31 + c^30 + c^29 + c^28 + c^24 + c^20 + c^18 + c^15 + c^13 + c^9 + c^8 + c^7 + c^4 + c^3 + c^2 + c + 1]") error("domain error in ffcompomap: m domain does not contain codomain of [b, b^5 + (a^4 + a^3 + a^2 + 1)*b^4 + (a^4 + a^3 + a^2)*b^3 + (a^4 + a^2 + a + 1)*b^2 + (a^3 + a^2)*b + (a^4 + a^3)]") error("domain error in ffmap: m domain does not contain b^23 + b^22 + b^20 + b^19 + b^18 + b^14 + b^13 + b^12 + b^9 + b^8 + b^7 + b^4 + b + 1") error("domain error in ffmap: m domain does not contain c^70 + c^69 + c^67 + c^66 + c^64 + c^60 + c^58 + c^57 + c^56 + c^54 + c^51 + c^50 + c^48 + c^47 + c^45 + c^44 + c^42 + c^40 + c^39 + c^37 + c^34 + c^32 + c^31 + c^30 + c^29 + c^28 + c^24 + c^20 + c^18 + c^15 + c^13 + c^9 + c^8 + c^7 + c^4 + c^3 + c ^2 + c + 1") error("incorrect type in ffextend (t_POL).") ? test(3,1,2,3) error("domain error in ffcompomap: m domain does not contain codomain of [b, c^4 + c^2 + c]") error("domain error in ffcompomap: m domain does not contain codomain of [b, b^2 + b + 2]") error("domain error in ffmap: m domain does not contain 2") error("domain error in ffmap: m domain does not contain c^4 + c^2 + c") error("incorrect type in ffextend (t_POL).") ? test(3,10,2,3) error("domain error in ffcompomap: m domain does not contain codomain of [b, 2*c^55 + 2*c^53 + c^52 + 2*c^50 + 2*c^47 + c^46 + 2*c^45 + c^43 + 2*c^42 + c^41 + 2*c^39 + 2*c^37 + 2*c^35 + c^34 + 2*c^32 + c^31 + 2*c^30 + 2*c^28 + c ^26 + c^25 + c^23 + c^21 + 2*c^20 + c^19 + 2*c^18 + c^17 + c^15 + c^14 + c^1 3 + 2*c^12 + 2*c^11 + 2*c^9 + c^8 + c^6 + c^5 + 2*c^4 + c^3 + 2*c^2 + 1]") error("domain error in ffcompomap: m domain does not contain codomain of [b, b^2 + (2*a^9 + 2*a^7 + 2*a^6)*b + (2*a^9 + 2*a^2)]") error("domain error in ffmap: m domain does not contain 2*b^19 + b^18 + 2*b^ 17 + b^16 + b^14 + 2*b^13 + b^12 + 2*b^11 + b^10 + 2*b^9 + 2*b^8 + b^7 + 2*b ^6 + b^3 + 2*b^2") error("domain error in ffmap: m domain does not contain 2*c^55 + 2*c^53 + c^ 52 + 2*c^50 + 2*c^47 + c^46 + 2*c^45 + c^43 + 2*c^42 + c^41 + 2*c^39 + 2*c^3 7 + 2*c^35 + c^34 + 2*c^32 + c^31 + 2*c^30 + 2*c^28 + c^26 + c^25 + c^23 + c ^21 + 2*c^20 + c^19 + 2*c^18 + c^17 + c^15 + c^14 + c^13 + 2*c^12 + 2*c^11 + 2*c^9 + c^8 + c^6 + c^5 + 2*c^4 + c^3 + 2*c^2 + 1") error("incorrect type in ffextend (t_POL).") ? test(nextprime(2^100),1,3,2) error("domain error in ffcompomap: m domain does not contain codomain of [b, 568210514509985430766932066568*c^5 + 227284205803994172306772826627*c^4 + 4 66744351204630889558551340395*c^3 + 82525812821688360182816323954*c^2 + 4153 34828463251255346305105801*c + 117700749434211267801721642361]") error("domain error in ffcompomap: m domain does not contain codomain of [b, b^3 + b^2 + 1267650600228229401496703205649*b + 1]") error("domain error in ffmap: m domain does not contain b^2 + 12676506002282 29401496703205652*b + 1") error("domain error in ffmap: m domain does not contain 56821051450998543076 6932066568*c^5 + 227284205803994172306772826627*c^4 + 4667443512046308895585 51340395*c^3 + 82525812821688360182816323954*c^2 + 4153348284632512553463051 05801*c + 117700749434211267801721642361") error("incorrect type in ffextend (t_POL).") ? test(nextprime(2^100),3,3,2) error("domain error in ffcompomap: m domain does not contain codomain of [b, 46484092795487340755616362656*c^17 + 1055644262063180547422327045544*c^16 + 346641065720009000378954983294*c^15 + 639520333054888837052043648112*c^14 + 957675960342270992241528178704*c^13 + 696402750970714831280062285793*c^12 + 1102408057754003899068126760036*c^11 + 767540362444860636247634715531*c^10 + 1149362134291872086981828566611*c^9 + 430243837953824360545080751371*c^8 + 789576238369354582328704492347*c^7 + 602440036890400798835137474014*c^6 + 5 80523431234345594424300815049*c^5 + 604254505049932046775583257110*c^4 + 105 6639807179138440960522156332*c^3 + 565071891011786154985459862809*c^2 + 2007 4844311373213928728633027*c + 370341892320446299776532835998]") error("domain error in ffcompomap: m domain does not contain codomain of [b, b^3 + (1137416257572846559662200662715*a^2 + 503912325036190431090267314273 *a + 558673802978212002533596733572)*b^2 + (633503932536656128571933348442*a ^2 + 1136773522417929415309364153946*a + 168613510166980621382925613526)*b + (633503932536656128571933348442*a^2 + 1136773522417929415309364153946*a + 1 68613510166980621382925613525)]") error("domain error in ffmap: m domain does not contain b^8 + b^7 + 12676506 00228229401496703205646*b^6 + 1267650600228229401496703205647*b^5 + 15*b^4 + 10*b^3 + 1267650600228229401496703205643*b^2 + 1267650600228229401496703205 650*b + 4") error("domain error in ffmap: m domain does not contain 46484092795487340755 616362656*c^17 + 1055644262063180547422327045544*c^16 + 34664106572000900037 8954983294*c^15 + 639520333054888837052043648112*c^14 + 95767596034227099224 1528178704*c^13 + 696402750970714831280062285793*c^12 + 11024080577540038990 68126760036*c^11 + 767540362444860636247634715531*c^10 + 1149362134291872086 981828566611*c^9 + 430243837953824360545080751371*c^8 + 78957623836935458232 8704492347*c^7 + 602440036890400798835137474014*c^6 + 5805234312343455944243 00815049*c^5 + 604254505049932046775583257110*c^4 + 105663980717913844096052 2156332*c^3 + 565071891011786154985459862809*c^2 + 2007484431137321392872863 3027*c + 370341892320446299776532835998") error("incorrect type in ffextend (t_POL).") ? ffgen(x^2+x+Mod(1,3)) *** at top-level: ffgen(x^2+x+Mod(1,3)) *** ^--------------------- *** ffgen: not an irreducible polynomial in ffgen: x^2 + x + 1. ? ffembed(ffgen([3,5],'b),ffgen([3,6],'a)); *** at top-level: ffembed(ffgen([3,5],'b),ffgen([3,6],'a)) *** ^---------------------------------------- *** ffembed: domain error in ffembed: b is not a subfield of a ? a=ffgen(3^3,'a);ffinvmap(ffextend(a,x^2+x+a)); *** at top-level: a=ffgen(3^3,'a);ffinvmap(ffextend(a,x^2+x+a)) *** ^----------------------------- *** ffinvmap: incorrect type in ffinvmap (t_VEC). ? print("Total time spent: ",gettime); Total time spent: 1676 pari-2.11.2/src/test/32/disc0000644000175000017500000000442013457566441014034 0ustar billbillMod(1, 2) Mod(1, 3) Mod(1, 3) -27*d^2*a^2 + (18*d*c*b - 4*c^3)*a + (-4*d*b^3 + c^2*b^2) Mod(2, 3)*c^3*a + (Mod(2, 3)*d*b^3 + Mod(1, 3)*c^2*b^2) Mod(2, 3)*c^3*a -4/x 0 0:1 0:1 0:1 Mod(Mod(0, 2), Mod(1, 2)*a^5 + Mod(1, 2)*a^4 + Mod(1, 2)*a^2 + Mod(1, 2)*a + Mod(1, 2)):Mod(Mod(1, 2), Mod(1, 2)*a^5 + Mod(1, 2)*a^4 + Mod(1, 2)*a^2 + M od(1, 2)*a + Mod(1, 2)) Mod(Mod(0, 3), Mod(1, 3)*a^5 + Mod(1, 3)*a^4 + Mod(2, 3)*a^3 + Mod(1, 3)):Mo d(Mod(1, 3), Mod(1, 3)*a^5 + Mod(1, 3)*a^4 + Mod(2, 3)*a^3 + Mod(1, 3)) Mod(Mod(0, 1267650600228229401496703205653), Mod(1, 126765060022822940149670 3205653)*a^3 + Mod(1, 1267650600228229401496703205653)*a^2 + Mod(12676506002 28229401496703205649, 1267650600228229401496703205653)*a + Mod(1, 1267650600 228229401496703205653)):Mod(Mod(1, 1267650600228229401496703205653), Mod(1, 1267650600228229401496703205653)*a^3 + Mod(1, 126765060022822940149670320565 3)*a^2 + Mod(1267650600228229401496703205649, 126765060022822940149670320565 3)*a + Mod(1, 1267650600228229401496703205653)) -146651015482972629339265779949471898228001932467822308156964313865094187865 0737725517311213972696938502546040565323278550679151618571557171893805575874 8427882056024408462365432062266407566752265468717307291 [0, Mat([0, 1])] [1, matrix(0,2)] [-4, Mat([2, 2])] [590696737518324963052366967566873816746861391761774240121952378042565253754 9745139928713041938024683034295373144229922138673743670575043095617043762369 710294827008, [2, 20; 3, 6; 19, 2; 29, 2; 37, 2; 47, 4; 83, 4; 2153, 4; 1038 43, 2; 4596226147103257, 3; 1889060957497626097155386071807, 2]] [590696737518324963052366967566873816746861391761774240121952378042565253754 9745139928713041938024683034295373144229922138673743670575043095617043762369 710294827008, [2, 20; 3, 6; 19, 2; 29, 2; 37, 2; 47, 4; 83, 4; 2153, 4; 1038 43, 2; 606528662981, 2; 4596226147103257, 3; 3114545235526325747, 2]] [374863741084558898826492744180004639816476168031283822100788706103545903812 8391139862076816170261639908101111519233533818009116577269022156451759608638 2788345856, [2, 66; 3, 6; 13, 20; 131, 2; 233, 4; 547, 2; 4441, 4; 60527, 4; 163561, 2; 647113, 4; 314542445630843, 2]] 2*a + 1 *** at top-level: poldisc(x^2/y^2,y) *** ^------------------ *** poldisc: incorrect type in polresultant (t_RFRAC). Total time spent: 104 pari-2.11.2/src/test/32/alggroup0000644000175000017500000000721013326135265014721 0ustar billbill *** Warning: new stack size = 100000000 (95.367 Mbytes). 2 x^3 - 21*x + 7 1 5 ordering S1 1 [1] [1] S2 1 [1, 1] [1, 1] S3 1 [1, 1, 4] [1, 1, 1] S4 1 [1, 1, 4, 9, 9] [1, 1, 1, 1, 1] S1 1 [1] [1] S2 1 [1, 1] [1, 1] S3 1 [1, 1, 4] [1, 1, 1] D8 1 [1, 1, 1, 1, 4] [1, 1, 1, 1, 1] D10 1 [1, 1, 4, 4] [1, 1, 1, 1] D12 1 [1, 1, 1, 1, 4, 4] [1, 1, 1, 1, 1, 1] D14 1 [1, 1, 12] [1, 1, 3] D16 1 [1, 1, 1, 1, 4, 8] [1, 1, 1, 1, 1, 2] D18 1 [1, 1, 4, 12] [1, 1, 1, 3] D20 [1, 1, 1, 1, 4, 4, 4, 4] [1, 1, 1, 1, 1, 1, 1, 1] D22 [1, 1, 20] [1, 1, 5] D24 [1, 1, 1, 1, 4, 4, 4, 8] [1, 1, 1, 1, 1, 1, 1, 2] D26 [1, 1, 24] [1, 1, 6] D28 [1, 1, 1, 1, 12, 12] [1, 1, 1, 1, 3, 3] D30 [1, 1, 4, 4, 4, 4, 4, 4, 4] [1, 1, 1, 1, 1, 1, 1, 1, 1] D32 [1, 1, 1, 1, 4, 8, 16] [1, 1, 1, 1, 1, 2, 4] D8 1 [1, 1, 1, 1, 4] [1, 1, 1, 1, 1] D10 1 [1, 1, 8] [1, 1, 2] D12 1 [1, 1, 1, 1, 4, 4] [1, 1, 1, 1, 1, 1] D14 1 [1, 1, 12] [1, 1, 3] D16 1 [1, 1, 1, 1, 4, 8] [1, 1, 1, 1, 1, 2] D18 1 [1, 1, 4, 12] [1, 1, 1, 3] D20 [1, 1, 1, 1, 8, 8] [1, 1, 1, 1, 2, 2] D22 [1, 1, 20] [1, 1, 5] D24 [1, 1, 1, 1, 4, 4, 4, 8] [1, 1, 1, 1, 1, 1, 1, 2] alggroup [0, 0, 0, 0, 0, 0, [1, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0; 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0; 0, 1 , 0, 0, 0, 0; 0, 0, 1, 0, 0, 0; 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 1], [[1, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0; 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 1], [0, 0, 1, 0, 0, 0; 1, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1; 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 1, 0], [0, 1, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0; 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 1; 0, 0, 0, 1, 0, 0], [0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 1; 0 , 0, 0, 0, 1, 0; 1, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0; 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0; 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 1; 0, 1, 0, 0, 0, 0; 1, 0, 0 , 0, 0, 0; 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1; 0, 0, 0, 0, 1, 0; 0, 0, 0, 1, 0, 0; 0, 0, 1, 0, 0, 0; 0, 1, 0, 0, 0, 0; 1, 0, 0, 0, 0, 0]], 0, [6, 0, 0 , 0, 0, 0]] 1 [0, 0, 0, 0, 0, 0, [1, 0; 0, 1], [1, 0; 0, 1], [[1, 0; 0, 1], [0, 1; 1, 0]], 0, [2, 0]] S1 1 1 1 S2 1 1 1 S3 1 1 1 S4 1 1 1 S5 1 1 1 S1 1 1 1 S2 1 1 1 S3 1 1 1 S4 1 1 1 D6 1 1 1 1 D8 1 1 1 1 D10 1 1 1 1 D12 1 1 1 1 D14 1 1 1 1 D16 1 1 1 1 D18 1 1 1 1 D20 1 1 1 1 D22 1 1 1 1 D24 1 1 1 1 D26 1 1 1 1 D28 1 1 1 1 D30 1 1 1 1 D32 1 1 1 1 D34 1 1 1 1 D36 1 1 1 1 D38 1 1 1 1 D40 1 1 1 1 D10 1 1 D14 1 1 D22 1 1 D26 1 1 D34 1 1 D38 1 1 D46 1 1 D58 1 1 *** at top-level: alggroupcenter(['x,'y]) *** ^----------------------- *** alggroupcenter: incorrect type in checkgroupelts (element) (t_POL). *** at top-level: alggroupcenter('x,1) *** ^-------------------- *** alggroupcenter: incorrect type in checkgroupelts (t_POL). *** at top-level: alggroup("a") *** ^------------- *** alggroup: incorrect type in checkgroupelts (t_STR). *** at top-level: alggroup(["a"]) *** ^--------------- *** alggroup: incorrect type in checkgroupelts (element) (t_STR). *** at top-level: alggroup(["a","b","c"]) *** ^----------------------- *** alggroup: incorrect type in checkgroupelts (element) (t_STR). *** at top-level: alggroup([Vecsmall([1]),Vecsmall([1,2]),Vecsma *** ^---------------------------------------------- *** alggroup: inconsistent dimensions in checkgroupelts [length of permutations]. *** at top-level: alggroup([Vecsmall([1]),Vecsmall([2,3]),Vecsma *** ^---------------------------------------------- *** alggroup: inconsistent dimensions in checkgroupelts [length of permutations]. Total time spent: 804 pari-2.11.2/src/test/32/ranges0000644000175000017500000000426613447371554014377 0ustar billbill[1267650600228229401496703205376, 1267650600228229401496703205377, 126765060 0228229401496703205378, 1267650600228229401496703205379] [5, 10, 26, 50, 122, 170, 290, 362, 530, 842, 962, 1370] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] [2, 5, 10, 17, 26, 37, 50, 65, 82, 101, 5, 13, 29, 53, 85, 10, 13, 25, 34, 5 8, 73, 109, 17, 25, 41, 65, 97, 26, 29, 34, 41, 61, 74, 89, 106, 37, 61, 85, 50, 53, 58, 65, 74, 85, 113, 130, 149, 65, 73, 89, 113, 145, 82, 85, 97, 10 6, 130, 145, 181, 101, 109, 149, 181] [13, 29, 53, 13, 34, 58, 29, 34, 74, 53, 58, 74] [[1, 1, 1], [2, 1, 1], [2, 2, 1], [2, 2, 2], [3, 1, 1], [3, 2, 1], [3, 2, 2] , [3, 3, 1], [3, 3, 2], [3, 3, 3], [4, 1, 1], [4, 2, 1], [4, 2, 2], [4, 3, 1 ], [4, 3, 2], [4, 3, 3], [4, 4, 1], [4, 4, 2], [4, 4, 3], [4, 4, 4], [5, 1, 1], [5, 2, 1], [5, 2, 2], [5, 3, 1], [5, 3, 2], [5, 3, 3], [5, 4, 1], [5, 4, 2], [5, 4, 3], [5, 4, 4], [5, 5, 1], [5, 5, 2], [5, 5, 3], [5, 5, 4], [5, 5 , 5]] [7, 11, 13, 17] [2, 3] [1, 2, 3, 4] [3, 4, 5] [1, 2, 4, 5] [] [] [] [] [] Vecsmall([2, 3]) Vecsmall([1, 2, 3, 4]) Vecsmall([3, 4, 5]) Vecsmall([1, 2, 4, 5]) [7 12] [8 13] [1, 2]~ [1, 6, 11, 16] [1 6 11 16 21] [2 7 12 17 22] [3 8 13 18 23] [1 6 11] [2 7 12] [3 8 13] [4 9 14] [5 10 15] [1 6 11 16] [2 7 12 17] [3 8 13 18] [4 9 14 19] [5 10 15 20] [1 6 11 16] [2 7 12 17] [3 8 13 18] [4 9 14 19] [13 18 23] [14 19 24] [15 20 25] [ 6 11] [ 7 12] [ 9 14] [10 15] [1, 3, 4, 5]~ [1, 6, 11, 21] [1 6 11 16 21] [2 7 12 17 22] [4 9 14 19 24] [5 10 15 20 25] [1 6 16 21] [2 7 17 22] [3 8 18 23] [4 9 19 24] [5 10 20 25] [1 6 11 16] [2 7 12 17] [3 8 13 18] [4 9 14 19] [1 6 11 21] [2 7 12 22] [3 8 13 23] [4 9 14 24] [13 18 23] [14 19 24] [15 20 25] [;] [1, [2, 2]] [3, [1, 4]] [0, 3, 4, [3, 4], 0, I] [0, 3, 4, [3, 4], 0, I] [] [2, 3, 3, 4, 4, 4, 5, 5, 5, 5] [2, 3, 3, 4, 4, 4, 5, 5, 5, 5] [0, 1, 2, 3, 4, 5] 123 *** this should be a small integer: vector(3)[1..2]! *** ^---------------- Total time spent: 0 pari-2.11.2/src/test/32/zn0000644000175000017500000001452113447371554013542 0ustar billbillMod(1, 2) Mod(3, 4) Mod(5, 9223372036854775837) Mod(5, 85070591730234616400799229995519050569) Mod(5, 170141183460469232801598459991038101138) Mod(5, 170141183460469232801598459991038101138) Mod(5, 170141183460469232801598459991038101138) [2, [2], [-1]] [1, [], []] [4, [4], [Mod(7, 10)]] [6, [6], [Mod(3, 14)]] [216, [36, 6], [Mod(2, 247), Mod(160, 247)]] [216, [36, 6], [Mod(2, 247), Mod(160, 247)]] [216, [36, 6], [Mod(2, 247), Mod(160, 247)]] [2, [2], [-1]] Mod(84, 148) [599, 599, 599, 599] [1000000003700000003419, 1000000003700000003419, 1000000003700000003419, 100 0000003700000003419] [8000000029600000027360, [1000000003700000003420, 2, 2, 2], [697836335347937 5237713, 5000000019000000018049, 15000000057000000054151, 100000000380000000 36101]] [392658269393604457523, 74265827068860445865, 1, 1]~ [392658269393604457523, 74265827068860445865, 1, 1]~ Mod(3, 20000000076000000072200) *** at top-level: znlog(Mod(3,N/2),G) *** ^------------------- *** znlog: inconsistent moduli in Rg_to_Fp: 10000000038000000036100 != 20000000076000000072200 *** at top-level: znlog(G,3) *** ^---------- *** znlog: incorrect type in znlog (t_INT). [] [] [] [] 0 0 [] [] [] 1 48 [] [] [] 194 Mod(1, 2) 945843084768538962295343 34034873 error("incorrect type in generic discrete logarithm (order factorization) (t _COMPLEX).") error("incorrect type in generic discrete logarithm (order factorization) (t _INT).") error("incorrect type in generic discrete logarithm (order factorization) (t _MAT).") error("incorrect type in generic discrete logarithm (order factorization) (t _MAT).") [] [[4, 0, 0]] [[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 0, 0]] [[0, 0, 1], [0, 0, 0]] [[2, 3, 0], [4, 2, 0], [6, 1, 0], [0, 0, 1], [2, 3, 1], [4, 2, 1], [6, 1, 1] , [0, 0, 0]] [[2, 1, 0], [4, 0, 0], [6, 3, 0], [0, 2, 1], [2, 1, 1], [4, 0, 1], [6, 3, 1] , [0, 2, 0]] *** at top-level: bnrchar(bnr,H,[0,1/2,1/2]) *** ^-------------------------- *** bnrchar: incorrect type in bnrchar [inconsistent values] (t_VEC). [[1, 3, 1], [2, 2, 1], [3, 1, 1], [4, 0, 1], [5, 3, 1], [6, 2, 1], [7, 1, 1] , [0, 2, 0], [1, 1, 0], [2, 0, 0], [3, 3, 0], [4, 2, 0], [5, 1, 0], [6, 0, 0 ], [7, 3, 0], [0, 0, 1]] [0, 0] [1, 1] [0, 1] [1, 0] [0, 1, 0, 1] [-1, 1, -1, 1] [[0], [1], [3], [2]] [0, 0] [1, 1] [16, 1] [12, 1] 10 10 10 0 -1 -1 9/10 9/10 9/10 1 2 x x^2 1 [1, 16]~ [1, 16]~ [1, matrix(0,2)] [25, Mat([5, 2])] 75 75 [1, 1]~ 1:[1, matrix(0,2)]:[]~ 4:[25, Mat([5, 2])]:[2]~ 7:[5, Mat([5, 1])]:[1]~ 13:[25, Mat([5, 2])]:[19]~ 16:[25, Mat([5, 2])]:[4]~ 19:[25, Mat([5, 2])]:[18]~ 22:[25, Mat([5, 2])]:[17]~ 26:[3, Mat([3, 1])]:[1]~ 28:[25, Mat([5, 2])]:[7]~ 31:[25, Mat([5, 2])]:[8]~ 32:[15, [3, 1; 5, 1]]:[1, 1]~ 34:[25, Mat([5, 2])]:[14]~ 37:[25, Mat([5, 2])]:[9]~ 43:[5, Mat([5, 1])]:[3]~ 46:[25, Mat([5, 2])]:[12]~ 49:[5, Mat([5, 1])]:[2]~ 52:[25, Mat([5, 2])]:[1]~ 58:[25, Mat([5, 2])]:[3]~ 61:[25, Mat([5, 2])]:[16]~ 64:[25, Mat([5, 2])]:[6]~ 67:[25, Mat([5, 2])]:[13]~ 68:[15, [3, 1; 5, 1]]:[1, 3]~ 73:[25, Mat([5, 2])]:[11]~ 74:[15, [3, 1; 5, 1]]:[1, 2]~ [[1, matrix(0,2)], []~] [8, [1, 1]~] [8, [0, 1]~] [[4, Mat([2, 2])], [1]~] [[1, matrix(0,2)], []~] [48, [0, 1, 1]~] [[8, Mat([2, 3])], [1, 1]~] [48, [1, 1, 1]~] [[16, Mat([2, 4])], [0, 3]~] [[3, Mat([3, 1])], [1]~] [[16, Mat([2, 4])], [1, 3]~] [[24, [2, 3; 3, 1]], [1, 1, 1]~] [[8, Mat([2, 3])], [0, 1]~] [48, [0, 3, 1]~] [[4, Mat([2, 2])], [1]~] [48, [1, 3, 1]~] [[16, Mat([2, 4])], [0, 1]~] [[24, [2, 3; 3, 1]], [0, 1, 1]~] [[16, Mat([2, 4])], [1, 1]~] [[12, [2, 2; 3, 1]], [1, 1]~] [0, 0, 0]~, [0, 0, 0]~ [0, 1, 0]~, [0, 0, 1]~ [1, 2, 0]~, [0, 0, 0]~ [1, 1, 0]~, [0, 0, 1]~ [0, 3, 0]~, [0, 0, 0]~ [0, 0, 0]~, [0, 0, 1]~ [1, 3, 0]~, [0, 0, 0]~ [1, 2, 0]~, [0, 0, 1]~ [0, 2, 0]~, [0, 0, 0]~ [0, 3, 0]~, [0, 0, 1]~ [1, 0, 0]~, [0, 0, 0]~ [1, 3, 0]~, [0, 0, 1]~ [0, 1, 0]~, [0, 0, 0]~ [0, 2, 0]~, [0, 0, 1]~ [1, 1, 0]~, [0, 0, 0]~ [1, 0, 0]~, [0, 0, 1]~ [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [10, 0, 0], [10, 1, 0], [10, 0, 1], [10, 1, 1]] [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 1, 0], [1, 0, 1] , [1, 1, 1], [2, 0, 0], [2, 1, 0], [2, 0, 1], [2, 1, 1], [4, 0, 0], [4, 1, 0 ], [4, 0, 1], [4, 1, 1]] [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [2, 0, 0], [2, 1, 0], [2, 0, 1] , [2, 1, 1], [4, 0, 0], [4, 1, 0], [4, 0, 1], [4, 1, 1]] [[0, 0, 0], [2, 0, 0], [2, 1, 0], [2, 0, 1], [2, 1, 1]] [[5, 0], [5, 1], [5, 2], [5, 3], [10, 1], [20, 1]] [[6, 0], [6, 1], [6, 2], [6, 3], [6, 4], [6, 5], [12, 1], [12, 3], [12, 5], [18, 1], [18, 2], [36, 1]] 126000 1 125 126000 11 1 []~ 125 [14]~ [[125, Mat([5, 3])], [14]~] [[31500, [2, 2; 3, 2; 5, 3; 7, 1]], [1, 1, 1, 1]~] 1009 82127 [0, 3, 3, 0, 2]~ 1 65501 [] []~ [1, []~] 0 0 0 [0]~ [0]~ [] []~ [[1, matrix(0,2)], []~] -1 -1 0 -1 0 *** at top-level: zncharinduce(G2,[]~,3) *** ^---------------------- *** zncharinduce: domain error in zncharinduce: N % q != 0 [0]~ [0]~ [15, [3, 1; 5, 1]] [11] 45 1.7320508075688772935274463415058723670*I 0 2.2360679774997896964091736687312762354 0 -16.104201132412986864073866738029737749 + 6.3761042876342817490516477498551 864451*I -16.104201132412986864073866738029737749 - 6.3761042876342817490516477498551 864448*I [0, 0, 0, 0, 0, 0, 0, 0, 0, 23.511410091698925166748238185562910744 - 38.042 260651806142884657573335175285736*I, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76.084521303612285769315146670350571472 + 47.0228201833978 50333496476371125821489*I] -4.5898860806696040374567274190849232043 + 24.061025451266108103399220192776 614357*I -4.5898860806696040374567274190849232043 - 24.061025451266108103399220192776 614357*I 0 4.0000000000000000000000000000000000000*I *** at top-level: znprimroot(8) *** ^------------- *** znprimroot: domain error in znprimroot: argument = 8 *** at top-level: znstar(0,1) *** ^----------- *** znstar: sorry, znstar(0,1) is not yet implemented. *** at top-level: znconreychar(G8,2) *** ^------------------ *** znconreychar: elements not coprime in znconreylog: 2 8 *** at top-level: znconreychar(znstar(8),2) *** ^------------------------- *** znconreychar: incorrect type in znconreychar (t_VEC). *** at top-level: znconreyexp(znstar(192,1),[2,8,1,1]~) *** ^------------------------------------- *** znconreyexp: incorrect type in znconreyexp (t_COL). Total time spent: 1358 pari-2.11.2/src/test/32/subgroup0000644000175000017500000000202513326135265014746 0ustar billbill[53835600, 29] [5, 0; 0, 1] [10, 0; 0, 1] [[12, 0; 0, 1]] [] [] *** at top-level: forsubgroup(h=[2,3],2,print(h)) *** ^--------- *** incorrect type in forsubgroup [not a group] (t_VEC). [] group: 1 1 1 1 alpha_lambda(mu,p) = 1 countsub = 1 alpha_lambda(mu,p) = 15 subgroup: 1 countsub = 15 alpha_lambda(mu,p) = 35 subgroup: 1 1 countsub = 35 alpha_lambda(mu,p) = 15 subgroup: 1 1 1 countsub = 15 alpha_lambda(mu,p) = 1 subgroup: 1 1 1 1 countsub = 1 nb subgroup = 67 67 *** at top-level: subgrouplist(1) *** ^--------------- *** subgrouplist: incorrect type in subgrouplist (t_INT). *** at top-level: subgrouplist([2,2],[2]~) *** ^------------------------ *** subgrouplist: sorry, exact type in subgrouplist is not yet implemented. *** at top-level: subgrouplist([2,2],-1) *** ^---------------------- *** subgrouplist: domain error in subgroup: index bound <= 0 Total time spent: 0 pari-2.11.2/src/test/32/thue0000644000175000017500000000261313326135265014050 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). [] [[0, -1]] [[-4, -3], [-4, 3], [4, -3], [4, 3]] [[1, 1]] [[-1, -1], [-1, 0], [0, -1], [0, 1], [1, 0], [1, 1]] [[-4, -2], [1868, 514]] [] [[5, 1]] [[-1, -1], [1, 1]] [[-1, -1], [1, 1]] *** at top-level: thueinit(x^0) *** ^------------- *** thueinit: constant polynomial in thueinit. [[-4, -1], [-2, -2], [2, 2], [4, 1]] [[0, 3], [3, -276], [3, 0]] [[0, 3], [3, 0], [19, 2], [27, 3]] [[-1, -1], [-1, 1], [1, -1], [1, 1]] [[0, 0]] [[0, 0]] [[0, 0]] [[-1, -1], [-1, 1], [1, -1], [1, 1]] [] [[0, 1], [1, -537825], [1, 0], [1, 1], [537824, 1]] [[44, -131]] [[-17711, -28657], [2584, 4181], [4181, 6765], [10946, 17711]] [] [[0, -1], [0, 1]] [[0, 1]] [[-8, 6], [-2, -2], [-2, 0], [0, -2], [2, -2]] [[-2, -1], [-1, -2], [1, 2], [2, 1]] [] [] [[-12100, 5500], [-12100, 6600], [-11000, 1100], [-11000, 9900], [-9900, -11 00], [-9900, 11000], [-6600, -5500], [-6600, 12100], [-5500, -6600], [-5500, 12100], [-1100, -9900], [-1100, 11000], [1100, -11000], [1100, 9900], [5500 , -12100], [5500, 6600], [6600, -12100], [6600, 5500], [9900, -11000], [9900 , 1100], [11000, -9900], [11000, -1100], [12100, -6600], [12100, -5500]] 44 44 2 2 24 6 [] [] [[0, 1]] [] [] [[739, -219]] [[739, -219]] [[-774658, -365105], [-774658, 365105], [774658, -365105], [774658, 365105]] [[-1, 0], [1, 0]] [[-1, 0], [1, 0]] [[-1, 0], [1, 0]] Total time spent: 4896 pari-2.11.2/src/test/32/factorff0000644000175000017500000001225313326135265014676 0ustar billbill[t, t^2 + 1, -t^2 - t + 1]~ [t, t^2 + 1, -t^2 - t + 1]~ [Mod(Mod(1, 2), Mod(1, 2)*y^2 + Mod(1, 2)*y + Mod(1, 2))]~ [x + 1 6] [x + t 6] [1 6] [1 6] []~ []~ [x + a 1] [x, x + 1, x + 2, x + a, x + (a + 1), x + (a + 2), x + (2*a + 1), x + (2*a + 2), x + a^2, x + (a^2 + 1), x + (a^2 + 2), x + (a^2 + a), x + (a^2 + a + 1) , x + (a^2 + a + 2), x + (a^2 + 2*a), x + (a^2 + 2*a + 1), x + (a^2 + 2*a + 2), x + 2*a^2, x + (2*a^2 + 1), x + (2*a^2 + 2), x + (2*a^2 + a), x + (2*a^2 + a + 1), x + (2*a^2 + a + 2), x + (2*a^2 + 2*a), x + (2*a^2 + 2*a + 1), x + (2*a^2 + 2*a + 2)]~ check 2 Mat([0, 1]) matrix(0,2) Mat([0, 1]) matrix(0,2) matrix(0,2) matrix(0,2) Mat([x + (a^2 + a), 1]) Mat([1, 1]) Mat([x + (a^2 + a), 1]) Mat([x + a, 2]) Mat([1, 2]) Mat([x + a, 2]) Mat([x^2 + x + a, 1]) Mat([2, 1]) Mat([x^2 + x + a, 1]) Mat([x + (a^2 + 1), 2]) Mat([1, 2]) Mat([x + (a^2 + 1), 2]) [x + (a^2 + a + 1), 1; x^2 + (a^2 + a + 1)*x + a^2, 1] [1, 1; 2, 1] [x + (a^2 + a + 1), 1; x^2 + (a^2 + a + 1)*x + a^2, 1] check 3 Mat([0, 1]) matrix(0,2) Mat([0, 1]) matrix(0,2) matrix(0,2) matrix(0,2) Mat([x + (2*a^2 + 2*a + 2), 1]) Mat([1, 1]) Mat([x + (2*a^2 + 2*a + 2), 1]) [x + a, 1; x + 2*a, 1] [1, 1; 1, 1] [x + a, 1; x + 2*a, 1] Mat([x^2 + x + a, 1]) Mat([2, 1]) Mat([x^2 + x + a, 1]) Mat([x^2 + (a^2 + a + 1), 1]) Mat([2, 1]) Mat([x^2 + (a^2 + a + 1), 1]) [x + 2*a, 1; x^2 + a*x + (2*a^2 + a + 1), 1] [1, 1; 2, 1] [x + 2*a, 1; x^2 + a*x + (2*a^2 + a + 1), 1] check 1267650600228229401496703205653 Mat([0, 1]) matrix(0,2) Mat([0, 1]) matrix(0,2) matrix(0,2) matrix(0,2) Mat([x + (a^2 + a + 1267650600228229401496703205649), 1]) Mat([1, 1]) Mat([x + (a^2 + a + 1267650600228229401496703205649), 1]) [x + a, 1; x + 1267650600228229401496703205652*a, 1] [1, 1; 1, 1] [x + a, 1; x + 1267650600228229401496703205652*a, 1] Mat([x^2 + x + a, 1]) Mat([2, 1]) Mat([x^2 + x + a, 1]) [x + (248056872368006019846473856603*a^2 + 632070353960340619554852923412*a + 686373698767074524134118021946), 1; x + (1019593727860223381650229349050*a ^2 + 635580246267888781941850282241*a + 581276901461154877362585183707), 1] [1, 1; 1, 1] [x + (248056872368006019846473856603*a^2 + 632070353960340619554852923412*a + 686373698767074524134118021946), 1; x + (1019593727860223381650229349050*a ^2 + 635580246267888781941850282241*a + 581276901461154877362585183707), 1] [x + (444781501243445200409703971769*a^2 + 380007214266207022733465160082*a + 1196315968196929648722484158008), 1; x^2 + (822869098984784201086999233884 *a^2 + 887643385962022378763238045571*a + 71334632031299752774219047645)*x + (920324322169569708634203378635*a^2 + 325733854995540949882328420355*a + 52 2626156517642858900111418754), 1] [1, 1; 2, 1] [x + (444781501243445200409703971769*a^2 + 380007214266207022733465160082*a + 1196315968196929648722484158008), 1; x^2 + (822869098984784201086999233884 *a^2 + 887643385962022378763238045571*a + 71334632031299752774219047645)*x + (920324322169569708634203378635*a^2 + 325733854995540949882328420355*a + 52 2626156517642858900111418754), 1] [ x + 1 1] [ x + 2 1] [ x + 3 1] [ x + 4 1] [ x + (t^3 + 4*t) 1] [ x + (t^3 + 4*t + 1) 1] [ x + (t^3 + 4*t + 2) 1] [ x + (t^3 + 4*t + 3) 1] [ x + (t^3 + 4*t + 4) 1] [ x + (2*t^3 + 3*t) 1] [x + (2*t^3 + 3*t + 1) 1] [x + (2*t^3 + 3*t + 2) 1] [x + (2*t^3 + 3*t + 3) 1] [x + (2*t^3 + 3*t + 4) 1] [ x + (3*t^3 + 2*t) 1] [x + (3*t^3 + 2*t + 1) 1] [x + (3*t^3 + 2*t + 2) 1] [x + (3*t^3 + 2*t + 3) 1] [x + (3*t^3 + 2*t + 4) 1] [ x + (4*t^3 + t) 1] [ x + (4*t^3 + t + 1) 1] [ x + (4*t^3 + t + 2) 1] [ x + (4*t^3 + t + 3) 1] [ x + (4*t^3 + t + 4) 1] [0 1] matrix(0,2) matrix(0,2) matrix(0,2) matrix(0,2) matrix(0,2) [x^4 + 4*t 1] [4 1] [x + t 1] [x + a 1] [1, a, a + 1, a^2]~ [ x + 79228162514264337593543950396 1] [ x + 79228162514264337593543950396*a 1] [x + (79228162514264337593543950396*a + 79228162514264337593543950396) 1] [ x + 79228162514264337593543950396*a^2 1] [ x^2 + (2*a + 1)*x + (a^2 + a + 1) 1] [ x^4 + x^3 + x^2 + x + 1 1] [1 1] [1 1] [1 1] [1 1] [2 1] [4 1] [x^4 + (79228162514264337593543950396*a^2 + 79228162514264337593543950395*a + 79228162514264337593543950395)*x^3 + (a^2 + 11*a + 79228162514264337593543 950396)*x^2 + (79228162514264337593543950393*a^2 + 7922816251426433759354395 0389*a + 2)*x + (4*a^2 + 79228162514264337593543950396*a) 1] [x^2 + (2*a + 1)*x + (a^2 + a + 1) 2] [x^4 + x^3 + x^2 + x + 1 4] [x^10 + 79228162514264337593543950396*a^2*x^9 + (792281625142643375935439503 95*a^2 + 79228162514264337593543950395*a)*x^8 + (8*a^2 + 7922816251426433759 3543950393*a + 79228162514264337593543950396)*x^7 + (4*a^2 + 12*a + 79228162 514264337593543950394)*x^6 + (79228162514264337593543950377*a^2 + 9*a + 7922 8162514264337593543950395)*x^5 + a^2*x^4 + (2*a^2 + 2*a)*x^3 + (792281625142 64337593543950389*a^2 + 4*a + 1)*x^2 + (79228162514264337593543950393*a^2 + 79228162514264337593543950385*a + 3)*x + (20*a^2 + 7922816251426433759354395 0388*a + 1) 1] 3 3 107 37 4096 3584 5832 200 1000 200 Total time spent: 3316 pari-2.11.2/src/test/32/trans20000644000175000017500000001347013457553246014327 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). 5.0431656433600286513118821892854247103 [0.54030230586813971740093660744297660373 - 0.841470984807896506652502321630 29899962*I, 0.54030230586813971740093660744297660373 + 0.8414709848078965066 5250232163029899962*I]~ error("incorrect type in exp (t_STR).") O(2^0) error("impossible inverse in powp: O(2^0).") 0 1 2 + O(x^2) 2.8284271247461900976033774484193961571 + O(x^2) Mod(1, y) + Mod(1/2, y)*x + O(x^2) 2 + 1/4*x + O(x^2) error("domain error in gpow [irrational exponent]: valuation != 0") O(x^0) 1 + 0.50000000000000000000000000000000000000*x + O(x^2) error("overflow in sqrtn [valuation].") error("incorrect type in gpow (t_STR).") error("incorrect type in gpow(0,n) (t_INTMOD).") x^196608 error("overflow in pow_monome [degree].") error("overflow in gpow.") 1.0000000000000000000000000000000000000 0.E-38 1 + 1/2*x - 1/16*x^2 + 1/32*x^3 - 21/1024*x^4 + 31/2048*x^5 - 195/16384*x^6 + 319/32768*x^7 - 34325/4194304*x^8 + 58899/8388608*x^9 + O(x^10) [1.0000000000000000000000000000000000000, 1.45679103104690686918643238326508 19750] 3 + 2*3^2 + 3^3 + O(3^4) error("incorrect type in exp (t_INTMOD).") 1 + O(3^5) 1 + 3 + 3^2 + 2*3^3 + 2*3^4 + O(3^5) 0.54030230586813971740093660744297660373 + 0.8414709848078965066525023216302 9899962*I error("incorrect type in log (t_INTMOD).") error("domain error in Qp_log: argument = 0") O(3^4) 1.5707963267948966192313216916397514421*I error("incorrect type in cos (t_INTMOD).") 1 + O(3^5) 1 + 3^2 + 2*3^4 + O(3^6) 1.5430806348152437784779056207570616826 error("incorrect type in sin (t_INTMOD).") O(3^5) 3 + 3^2 + 3^3 + 2*3^4 + O(3^5) 1.1752011936438014568823818505956008152*I error("incorrect type in tan (t_INTMOD).") O(3^5) 3 + 3^2 + 3^4 + O(3^5) 0.76159415595576488811945828260479359041*I error("incorrect type in cotan (t_INTMOD).") error("impossible inverse in divpp: O(3^5).") 3^-1 + 2 + 3^2 + O(3^3) -1.3130352854993313036361612469308478329*I 0.27175258531951171652884372249858892071 + 1.0839233273386945434757520612119 717214*I -0.45765755436028576375027741043204727643 1.5707963267948966192313216916397514421 + O(x) -1.5707963267948966192313216916397514421 + O(x) 1.5707963267948966192313216916397514421*I + O(x) -1.5707963267948966192313216916397514421*I + O(x) O(x) 1.4142135623730950488016887242096980786*x + O(x^2) 1.3169578969248167086250463473079684440 + 0.57735026918962576450914878050195 745565*x - 0.19245008972987525483638292683398581855*x^2 + O(x^3) O(x) 0.84147098480789650665250232163029899962*I 1.6 e-38 4.9 e-39 3.1 e-39 0.e-38 0.e-38 0.e-38 0.e-38 0.e-38 0.e-57 6.3 e-39 0.e-38 0.e-38 0.e-38 4.2 e-39 0.e-38 0.e-38 -0.20484755831421800270211268209700671730 - 1.024400881608445881724860454410 8866770*I 2.2048475583142180027021126820970067173 - 1.02440088160844588172486045441088 66770*I 3 + O(3^2) x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + 1/5040*x^7 + 1/40 320*x^8 + 1/362880*x^9 + 1/3628800*x^10 + 1/39916800*x^11 + 1/479001600*x^12 + 1/6227020800*x^13 + 1/87178291200*x^14 + 1/1307674368000*x^15 + 1/2092278 9888000*x^16 + O(x^17) O(x) 1.0000000000000000000050000000000000000 E-20 + 1.000000000000000000010000000 0000000000*x + O(x^2) 1.1170000166126746685453698198370956101 1.7182818284590452353602874713526624978 x - 1/2*x^2 + 1/3*x^3 - 1/4*x^4 + O(x^5) 9.9999999995000000000333333333308333333 E-11 + 0.999999999900000000009999999 99900000000*x - 0.49999999990000000001499999999800000000*x^2 + 0.33333333323 333333335333333333000000000*x^3 - 0.24999999990000000002499999999500000000*x ^4 + O(x^5) O(x) 9.9999999995000000000333333333308333333 E-11 9.9999999995000000000333333333308333333 E-11 9.9999999999999999999500000000000000000 E-21 9.9999999999999999999333333333433333333 E-11 + 9.999999999000000000066666666 6666666667 E-11*I 9.9999999999999999999999999999999999999 E-21 + 9.999999999999999999900000000 0000000000 E-21*I 4*5 + 3*5^2 + O(5^3) 74.445568222817551305703193915436427255 + 1.58602795576098137135242138363547 30014*I -74.445568222817551305703193915436427255 + 1.5555646978288118671102219996440 298828*I 1 1.0000000000000000000000000000000000000 0.95885107720840600054657587043114277616 1101.3232874703393377236524554846364403 0.96671074810035670154056228439966270092 - 0.3317468333156205932854800814081 5291940*I 1 + O(3^2) 1 + 3 + 3^2 + O(3^3) *** at top-level: sinc(2+O(3^2)) *** ^-------------- *** sinc: domain error in gsinc(t_PADIC): argument out of range 1 - 1/6*x^2 + 1/120*x^4 - 1/5040*x^6 + 1/362880*x^8 - 1/39916800*x^10 + 1/62 27020800*x^12 - 1/1307674368000*x^14 + O(x^16) *** at top-level: sinc(1/x) *** ^--------- *** sinc: domain error in sinc: valuation < 0 1.0000000000000000000000000000000000000 1 + O(3^4) 1 + (3^-1 + 1 + 3 + O(3^2))*x^2 + (3^-1 + 2 + 2*3 + O(3^2))*x^4 + (3^-2 + 3^ -1 + O(3))*x^6 + (3^-4 + 3^-3 + 3^-2 + O(3^-1))*x^8 + (3^-4 + 2*3^-3 + O(3^- 1))*x^10 + (2*3^-5 + 2*3^-4 + 3^-3 + O(3^-2))*x^12 + (3^-6 + 3^-5 + O(3^-3)) *x^14 + O(x^16) 1 - 1.6449340668482264364724151666460251892*x^2 + 0.811742425283353643637002 77240587592708*x^4 - 0.19075182412208421369647211183579759898*x^6 + 0.026147 847817654800504653261419496157949*x^8 - 0.0023460810354558236375089358411726 226961*x^10 + 0.00014842879303107100368487273566815058771*x^12 - 6.975873661 6563804745344485568159551740 E-6*x^14 + O(x^16) 0.E-2003 exp: [320, 320, 320] expm1: [320, 320, 320] log: [320, 320, 320] arg: [320, 320, 320] cos: [320, 320, 320] sin: [320, 320, 320] tan: [320, 320, 320] cotan: [320, 320, 320] sinc: [320, 320, 320] cosh: [320, 320, 320] sinh: [320, 320, 320] tanh: [320, 320, 320] cotanh: [320, 320, 320] acos: [320, 320, 320] asin: [320, 320, 320] atan: [320, 320, 320] acosh: [320, 320, 320] asinh: [320, 320, 320] atanh: [320, 320, 320] sqrt: [320, 320, 320] (x)->sqrtn(x,3): [320, 320, 320] gamma: [320, 320, 320] lngamma: [320, 320, 320] psi: [320, 320, 320] zeta: [320, 320, 320] Total time spent: 23 pari-2.11.2/src/test/32/matsnf0000644000175000017500000001670213201017466014371 0ustar billbillx^2 + 10*x + 27 x^2 + 10/3*x + 3 x^2 + 10/a*x + 27/a^2 x^2 + 10*a*x + 27*a^2 [2, 1] [X^2 + 10*X + 27, X^2 + 10*X + 27, 1, 1] x^2 - 2*a*x + (a^2 - d^2) (M)->my([F,B]=matfrobenius(M,2));if(M!=B^-1*F*B,error("matfrobenius:",M));F Mat(1) [0, -1; 1, 2] [0, 0, 1; 1, 0, -3; 0, 1, 3] [0, 0, 0, -1; 1, 0, 0, 4; 0, 1, 0, -6; 0, 0, 1, 4] [0, 0, 0, 0, 1; 1, 0, 0, 0, -5; 0, 1, 0, 0, 10; 0, 0, 1, 0, -10; 0, 0, 0, 1, 5] [0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 6; 0, 1, 0, 0, 0, -15; 0, 0, 1, 0, 0, 20; 0, 0, 0, 1, 0, -15; 0, 0, 0, 0, 1, 6] [0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, -7; 0, 1, 0, 0, 0, 0, 21; 0, 0, 1, 0 , 0, 0, -35; 0, 0, 0, 1, 0, 0, 35; 0, 0, 0, 0, 1, 0, -21; 0, 0, 0, 0, 0, 1, 7] [0, 0, 0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 0, 0, 8; 0, 1, 0, 0, 0, 0, 0, -28; 0, 0, 1, 0, 0, 0, 0, 56; 0, 0, 0, 1, 0, 0, 0, -70; 0, 0, 0, 0, 1, 0, 0, 56; 0, 0, 0, 0, 0, 1, 0, -28; 0, 0, 0, 0, 0, 0, 1, 8] [0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, -9; 0, 1, 0, 0, 0, 0, 0, 0, 36; 0, 0, 1, 0, 0, 0, 0, 0, -84; 0, 0, 0, 1, 0, 0, 0, 0, 126; 0, 0, 0, 0 , 1, 0, 0, 0, -126; 0, 0, 0, 0, 0, 1, 0, 0, 84; 0, 0, 0, 0, 0, 0, 1, 0, -36; 0, 0, 0, 0, 0, 0, 0, 1, 9] [0, 0, 0, 0, 0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 10; 0, 1, 0, 0, 0 , 0, 0, 0, 0, -45; 0, 0, 1, 0, 0, 0, 0, 0, 0, 120; 0, 0, 0, 1, 0, 0, 0, 0, 0 , -210; 0, 0, 0, 0, 1, 0, 0, 0, 0, 252; 0, 0, 0, 0, 0, 1, 0, 0, 0, -210; 0, 0, 0, 0, 0, 0, 1, 0, 0, 120; 0, 0, 0, 0, 0, 0, 0, 1, 0, -45; 0, 0, 0, 0, 0, 0, 0, 0, 1, 10] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11; 0, 1, 0 , 0, 0, 0, 0, 0, 0, 0, 55; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -165; 0, 0, 0, 1, 0 , 0, 0, 0, 0, 0, 330; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -462; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 462; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -330; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 165; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -55; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12; 0 , 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -66; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 220; 0 , 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -495; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 792; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -924; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 792; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -495; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 220 ; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -66; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -13; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 , 0, -286; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 715; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1287; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1716; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1716; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1287; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -715; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 286; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -78; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 , 13] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -91; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 364; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1001; 0, 0, 0 , 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2002; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -3003; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3432; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -3003; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2002; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1001; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 364; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -91; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 1365; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3003; 0, 0, 0, 0, 0, 1, 0 , 0, 0, 0, 0, 0, 0, 0, 5005; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -6435 ; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 6435; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -5005; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3003; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1365; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 455; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -105; 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 1, 15] [0, -1; 1, 2] [0, 0, 1; 1, 0, -3; 0, 1, 3] [0, 0, 0, -1; 1, 0, 0, 4; 0, 1, 0, -6; 0, 0, 1, 4] [0, 0, 0, 0, 1; 1, 0, 0, 0, -5; 0, 1, 0, 0, 10; 0, 0, 1, 0, -10; 0, 0, 0, 1, 5] [0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 6; 0, 1, 0, 0, 0, -15; 0, 0, 1, 0, 0, 20; 0, 0, 0, 1, 0, -15; 0, 0, 0, 0, 1, 6] [0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, -7; 0, 1, 0, 0, 0, 0, 21; 0, 0, 1, 0 , 0, 0, -35; 0, 0, 0, 1, 0, 0, 35; 0, 0, 0, 0, 1, 0, -21; 0, 0, 0, 0, 0, 1, 7] [0, 0, 0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 0, 0, 8; 0, 1, 0, 0, 0, 0, 0, -28; 0, 0, 1, 0, 0, 0, 0, 56; 0, 0, 0, 1, 0, 0, 0, -70; 0, 0, 0, 0, 1, 0, 0, 56; 0, 0, 0, 0, 0, 1, 0, -28; 0, 0, 0, 0, 0, 0, 1, 8] [0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, -9; 0, 1, 0, 0, 0, 0, 0, 0, 36; 0, 0, 1, 0, 0, 0, 0, 0, -84; 0, 0, 0, 1, 0, 0, 0, 0, 126; 0, 0, 0, 0 , 1, 0, 0, 0, -126; 0, 0, 0, 0, 0, 1, 0, 0, 84; 0, 0, 0, 0, 0, 0, 1, 0, -36; 0, 0, 0, 0, 0, 0, 0, 1, 9] [0, 0, 0, 0, 0, 0, 0, 0, 0, -1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 10; 0, 1, 0, 0, 0 , 0, 0, 0, 0, -45; 0, 0, 1, 0, 0, 0, 0, 0, 0, 120; 0, 0, 0, 1, 0, 0, 0, 0, 0 , -210; 0, 0, 0, 0, 1, 0, 0, 0, 0, 252; 0, 0, 0, 0, 0, 1, 0, 0, 0, -210; 0, 0, 0, 0, 0, 0, 1, 0, 0, 120; 0, 0, 0, 0, 0, 0, 0, 1, 0, -45; 0, 0, 0, 0, 0, 0, 0, 0, 1, 10] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11; 0, 1, 0 , 0, 0, 0, 0, 0, 0, 0, 55; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -165; 0, 0, 0, 1, 0 , 0, 0, 0, 0, 0, 330; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -462; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 462; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -330; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 165; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -55; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11] Mat(1) [0, -1/12; 1, 4/3] [0, 0, 1/2160; 1, 0, -127/720; 0, 1, 23/15] [0, 0, 0, -1/6048000; 1, 0, 0, 41/23625; 0, 1, 0, -3341/12600; 0, 0, 1, 176/ 105] [0, 0, 0, 0, 1/266716800000; 1, 0, 0, 0, -61501/53343360000; 0, 1, 0, 0, 852 401/222264000; 0, 0, 1, 0, -735781/2116800; 0, 0, 0, 1, 563/315] [0, 0, 0, 0, 0, -1/186313420339200000; 1, 0, 0, 0, 0, 3529/70573265280000; 0 , 1, 0, 0, 0, -10828423/2688505344000; 0, 0, 1, 0, 0, 18344719/2750517000; 0 , 0, 0, 1, 0, -14806217/34927200; 0, 0, 0, 0, 1, 6508/3465] [0, 0, 0, 0, 0, 0, 1/2067909047925770649600000; 1, 0, 0, 0, 0, 0, -8237351/5 9083115655022018560000; 0, 1, 0, 0, 0, 0, 509709971/1758426061161369600; 0, 0, 1, 0, 0, 0, -126867217979/12687056718336000; 0, 0, 0, 1, 0, 0, 2804123885 /276900047424; 0, 0, 0, 0, 1, 0, -197708437/399567168; 0, 0, 0, 0, 0, 1, 880 69/45045] [0, 0, 0, 0, 0, 0, 0, -1/365356847125734485878112256000000; 1, 0, 0, 0, 0, 0 , 0, 442037/17839689801061254193267200000; 0, 1, 0, 0, 0, 0, 0, -12581527408 69/906142974022158943150080000; 0, 0, 1, 0, 0, 0, 0, 725120398661/6688626213 66980040000; 0, 0, 0, 1, 0, 0, 0, -3571285252517/176488178798131200; 0, 0, 0 , 0, 1, 0, 0, 85934726089/6093243231075; 0, 0, 0, 0, 0, 1, 0, -6070382321/10 821610800; 0, 0, 0, 0, 0, 0, 1, 91072/45045] [0, x, x] [0, x^2 + x, 1] [0, 0] [[1, 0, 0; 0, -2, 1], [;], [;]] [] [matrix(0,1), [1, 0; 0, -2; 0, 1], matrix(0,2)] [Mod(1, 3)*x^4 + Mod(2, 3)*x + Mod(2, 3), 1, 1] [0 0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0 -8] [0 1 0 0 0 0 0 0 2] [0 0 1 0 0 0 0 0 4] [0 0 0 1 0 0 0 0 5] [0 0 0 0 1 0 0 0 4] [0 0 0 0 0 1 0 0 13] [0 0 0 0 0 0 1 0 5] [0 0 0 0 0 0 0 1 2] x^9 - 2*x^8 - 5*x^7 - 13*x^6 - 4*x^5 - 5*x^4 - 4*x^3 - 2*x^2 + 8*x [[0, 0, 0, 1; 1, 9, -27, 0; 0, 1, 0, 0], [-1; 1], [0; 0; 3]] Total time spent: 16 pari-2.11.2/src/test/32/nfields0000644000175000017500000007222613326135265014536 0ustar billbill echo = 1 ? p2=Pol([1,3021,-786303,-6826636057,-546603588746,3853890514072057]); ? fa=[11699,6;2392997,2;4987333019653,2]; ? setrand(1);N=10^8;a=matrix(3,5,j,k,vectorv(5,l,random\N)); ? nfpol=x^5-5*x^3+5*x+25;nf=nfinit(nfpol) [x^5 - 5*x^3 + 5*x + 25, [1, 2], 595125, 45, [[1, -1.08911514572050482502495 27946671612684, -2.4285174907194186068992069565359418365, 0.7194669112891317 8943997506477288225734, -2.5558200350691694950646071159426779972; 1, -0.1383 8372073406036365047976417441696637 - 0.4918163765776864349975328551474152510 7*I, 1.9647119211288133163138753392090569931 + 0.809714924188978951282940822 19556466857*I, -0.072312766896812300380582649294307897122 + 2.19808037538462 76641195195160383234878*I, -0.98796319352507039803950539735452837195 + 1.570 1452385894131769052374806001981109*I; 1, 1.682941293594312776162956161507997 6006 + 2.0500351226010726172974286983598602164*I, -0.75045317576910401286427 186094108607489 + 1.3101462685358123283560773619310445916*I, -0.787420688747 75359433940488309213323155 + 2.1336633893126618034168454610457936018*I, 1.26 58732110596551455718089553258673705 - 2.716479010374315056657802803578983483 5*I], [1, -1.0891151457205048250249527946671612684, -2.428517490719418606899 2069565359418365, 0.71946691128913178943997506477288225734, -2.5558200350691 694950646071159426779972; 1, -0.63020009731174679864801261932183221744, 2.77 44268453177922675968161614046216617, 2.1257676084878153637389368667440155906 , 0.58218204506434277886573208324566973893; 1, 0.353432655843626071347053090 97299828470, 1.1549969969398343650309345170134923246, -2.2703931422814399645 001021653326313849, -2.5581084321144835749447428779547264828; 1, 3.732976416 1953853934603848598678578170, 0.55969309276670831549180550098995851667, 1.34 62427005649082090774405779536603703, -1.450605799314659911085993848253116112 9; 1, -0.36709382900675984113447253685186261580, -2.060599444304916341220349 2228721306665, -2.9210840780604153977562503441379268334, 3.98235222143397020 22296117589048508540], [1, -1, -2, 1, -3; 1, -1, 3, 2, 1; 1, 0, 1, -2, -3; 1 , 4, 1, 1, -1; 1, 0, -2, -3, 4], [5, 2, 0, -1, -2; 2, -2, -5, -10, 20; 0, -5 , 10, -10, 5; -1, -10, -10, -17, 1; -2, 20, 5, 1, -8], [345, 0, 200, 110, 17 7; 0, 345, 95, 1, 145; 0, 0, 5, 4, 3; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [63, 3, 0, -6, -9; 3, 8, -5, -1, 16; 0, -5, 22, -10, 0; -6, -1, -10, -14, -9; -9, 1 6, 0, -9, -2], [345, [138, 117, 330, 288, -636; -172, -88, 65, 118, -116; 53 , 1, 138, -173, 65; 1, -172, 54, 191, 106; 0, 118, 173, 225, -34]], [3, 5, 2 3]], [-2.4285174907194186068992069565359418365, 1.96471192112881331631387533 92090569931 + 0.80971492418897895128294082219556466857*I, -0.750453175769104 01286427186094108607489 + 1.3101462685358123283560773619310445916*I], [15, x ^4 - 10*x^2 + 5*x + 20, 15*x, 2*x^4 - 5*x^2 + 10*x - 5, -x^4 + 5*x^3 + 5*x^2 - 20*x - 10], [1, 0, 3, 1, 10; 0, 0, -2, 1, -5; 0, 1, 0, 3, -5; 0, 0, 1, 1, 10; 0, 0, 0, 3, 0], [1, 0, 0, 0, 0, 0, -1, -1, -2, 4, 0, -1, 3, -1, 1, 0, - 2, -1, -3, -1, 0, 4, 1, -1, -1; 0, 1, 0, 0, 0, 1, 1, -1, -1, 1, 0, -1, -2, - 1, 1, 0, -1, -1, -1, 3, 0, 1, 1, 3, -3; 0, 0, 1, 0, 0, 0, 0, 0, 1, -1, 1, 0, 0, 0, -2, 0, 1, 0, -1, -1, 0, -1, -2, -1, -1; 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 2, 1, 0, 1, 0, 0, 0, 0, 2, 0, -1; 0, 0, 0, 0, 1, 0, -1, -1, -1, 1, 0, -1, 0, 1, 0, 0, -1, 1, 0, 0, 1, 1, 0, 0, -1]] ? nfinit(nfpol,2) [x^5 - 2*x^4 + 3*x^3 + 8*x^2 + 3*x + 2, [1, 2], 595125, 4, [[1, -1.089115145 7205048250249527946671612684, -2.4285174907194186068992069565359418365, 0.71 946691128913178943997506477288225734, -2.55582003506916949506460711594267799 72; 1, -0.13838372073406036365047976417441696637 + 0.49181637657768643499753 285514741525107*I, 1.9647119211288133163138753392090569931 - 0.8097149241889 7895128294082219556466857*I, -0.072312766896812300380582649294307897122 - 2. 1980803753846276641195195160383234878*I, -0.98796319352507039803950539735452 837195 - 1.5701452385894131769052374806001981109*I; 1, 1.6829412935943127761 629561615079976006 + 2.0500351226010726172974286983598602164*I, -0.750453175 76910401286427186094108607489 + 1.3101462685358123283560773619310445916*I, - 0.78742068874775359433940488309213323155 + 2.1336633893126618034168454610457 936018*I, 1.2658732110596551455718089553258673705 - 2.7164790103743150566578 028035789834835*I], [1, -1.0891151457205048250249527946671612684, -2.4285174 907194186068992069565359418365, 0.71946691128913178943997506477288225734, -2 .5558200350691694950646071159426779972; 1, 0.3534326558436260713470530909729 9828470, 1.1549969969398343650309345170134923246, -2.27039314228143996450010 21653326313849, -2.5581084321144835749447428779547264828; 1, -0.630200097311 74679864801261932183221744, 2.7744268453177922675968161614046216617, 2.12576 76084878153637389368667440155906, 0.58218204506434277886573208324566973893; 1, 3.7329764161953853934603848598678578170, 0.559693092766708315491805500989 95851667, 1.3462427005649082090774405779536603703, -1.4506057993146599110859 938482531161129; 1, -0.36709382900675984113447253685186261580, -2.0605994443 049163412203492228721306665, -2.9210840780604153977562503441379268334, 3.982 3522214339702022296117589048508540], [1, -1, -2, 1, -3; 1, 0, 1, -2, -3; 1, -1, 3, 2, 1; 1, 4, 1, 1, -1; 1, 0, -2, -3, 4], [5, 2, 0, -1, -2; 2, -2, -5, -10, 20; 0, -5, 10, -10, 5; -1, -10, -10, -17, 1; -2, 20, 5, 1, -8], [345, 0 , 200, 110, 177; 0, 345, 95, 1, 145; 0, 0, 5, 4, 3; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [63, 3, 0, -6, -9; 3, 8, -5, -1, 16; 0, -5, 22, -10, 0; -6, -1, -10, -14, -9; -9, 16, 0, -9, -2], [345, [138, 117, 330, 288, -636; -172, -88, 65, 118, -116; 53, 1, 138, -173, 65; 1, -172, 54, 191, 106; 0, 118, 173, 225, - 34]], [3, 5, 23]], [-1.0891151457205048250249527946671612684, -0.13838372073 406036365047976417441696637 + 0.49181637657768643499753285514741525107*I, 1. 6829412935943127761629561615079976006 + 2.0500351226010726172974286983598602 164*I], [2, 2*x, -x^4 + 3*x^3 - 5*x^2 - 4*x + 2, -x^4 + 2*x^3 - 2*x^2 - 9*x - 2, -x^4 + 2*x^3 - 4*x^2 - 7*x - 4], [1, 0, -1, -7, -14; 0, 1, 1, -2, -15; 0, 0, 0, 2, 4; 0, 0, 1, 1, -2; 0, 0, -1, -3, -4], [1, 0, 0, 0, 0, 0, -1, -1, -2, 4, 0, -1, 3, -1, 1, 0, -2, -1, -3, -1, 0, 4, 1, -1, -1; 0, 1, 0, 0, 0, 1, 1, -1, -1, 1, 0, -1, -2, -1, 1, 0, -1, -1, -1, 3, 0, 1, 1, 3, -3; 0, 0, 1 , 0, 0, 0, 0, 0, 1, -1, 1, 0, 0, 0, -2, 0, 1, 0, -1, -1, 0, -1, -2, -1, -1; 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 2, 1, 0, 1, 0, 0, 0, 0, 2, 0, -1; 0, 0, 0, 0, 1, 0, -1, -1, -1, 1, 0, -1, 0, 1, 0, 0, -1, 1, 0, 0, 1, 1, 0, 0, -1]] ? nfinit(nfpol,3)[2] Mod(-1/2*x^4 + 3/2*x^3 - 5/2*x^2 - 2*x + 1, x^5 - 2*x^4 + 3*x^3 + 8*x^2 + 3* x + 2) ? nf3=nfinit(x^6+108); ? setrand(1);bnf2=bnfinit(y^3-y-1);nf2=bnf2[7]; ? setrand(1);bnf=bnfinit(x^2-x-57,,[0.2,0.2]) [Mat(3), Mat([1, 1, 2]), [-2.7124653051843439746808795106061300699 + 3.14159 26535897932384626433832795028842*I; 2.7124653051843439746808795106061300699] , [1.7903417566977293763292119206302198761, 1.289761953065273502503008607239 5031017 + 3.1415926535897932384626433832795028842*I, 0.E-57, 0.5005798036324 5587382620331339071677436; -1.7903417566977293763292119206302198761, -1.2897 619530652735025030086072395031017, 0.E-57, -0.500579803632455873826203313390 71677436 + 3.1415926535897932384626433832795028842*I], [[3, [-1, 1]~, 1, 1, [0, 57; 1, 1]], [5, [-2, 1]~, 1, 1, [1, 57; 1, 2]], [3, [0, 1]~, 1, 1, [-1, 57; 1, 0]], [5, [1, 1]~, 1, 1, [-2, 57; 1, -1]]], 0, [x^2 - x - 57, [2, 0], 229, 1, [[1, -7.0663729752107779635959310246705326059; 1, 8.0663729752107779 635959310246705326059], [1, -7.0663729752107779635959310246705326059; 1, 8.0 663729752107779635959310246705326059], [1, -7; 1, 8], [2, 1; 1, 115], [229, 114; 0, 1], [115, -1; -1, 2], [229, [114, 57; 1, 115]], [229]], [-7.06637297 52107779635959310246705326059, 8.0663729752107779635959310246705326059], [1, x], [1, 0; 0, 1], [1, 0, 0, 57; 0, 1, 1, 1]], [[3, [3], [[3, 2; 0, 1]]], 2. 7124653051843439746808795106061300699, 1, [2, -1], [x + 7]], [Mat(1), [[0, 0 ]], [[1.7903417566977293763292119206302198761, -1.79034175669772937632921192 06302198761]]], [0, 0, 0]] ? dobnf(x^2-x-100000,1) [[5], [Mod(379554884019013781006303254896369154068336082609238336*x + 119836 165644250789990462835950022871665178127611316131167, x^2 - x - 100000)]] ? \p19 realprecision = 19 significant digits ? setrand(1);sbnf=bnfcompress(bnfinit(x^3-x^2-14*x-1)) [x^3 - x^2 - 14*x - 1, 3, 10889, [1, x, x^2 - x - 9], [-3.233732695981516673 , -0.07182350902743636345, 4.305556205008953036], 0, Mat(2), Mat([1, 1, 0, 1 , 0, 1]), [9, 15, 16, 17, 39, 33, 10], [2, -1], [[0, 1, 0]~, [5, 3, 1]~], [[ 4, -1, 0]~, [-1, 1, 0]~, [2, 1, 0]~, [3, 1, 0]~, [-10, -5, -1]~, [-1, -1, 0] ~, [-3, 0, 0]~]] ? K=bnfinit(sbnf);bnfisprincipal(K,idealprimedec(K,3)[2]) [[1]~, [-7/3, -4/3, -1/3]~] ? \p38 realprecision = 38 significant digits ? bnr=bnrinit(bnf,[[5,3;0,1],[1,0]],1);bnr.cyc [12] ? bnr2=bnrinit(bnf,[[25,13;0,1],[1,1]]);bnr2.bid [[[25, 13; 0, 1], [1, 1]], [80, [20, 2, 2], [17, [2, 2]~, [0, -2]~]], [Mat([ [5, [-2, 1]~, 1, 1, [1, 57; 1, 2]], 2]), Mat([[5, [-2, 1]~, 1, 1, [1, 57; 1, 2]], 2])], [[[[20], [17], [25, 13; 0, 1], [[[2, 2]~, [1, 2], [5, [-2, 1]~, 1, 1, [1, 57; 1, 2]]]~, 2, [4, Mat([2, 2])]], [4, 7, [[[5], [6], Mat([1, -13 ]), 5]]], [[-15]~, Mat(16)]]], [[2, 2], Vecsmall([1, 2]), [-0.04528654880364 0718227839951807630066450, -0.034713451196359281772160048192369933551; -0.01 0397655620934129810079722893872882085, 0.05039765562093412981007972289387288 2085], 16.099559462816166945393896537005798909, [-12, 1; 1, 2]]], [[1; 0; 0] , [0, 0; 1, 0; 0, 1]]] ? rnfinit(nf2,x^5-x-2) [x^5 - x - 2, [83718587879473471, -18162091535584830*x^14 + 6593998738955900 *x^13 + 89125883511340690*x^12 - 123429972713895380*x^11 - 86184686128261590 *x^10 + 508290939376248430*x^9 - 88425050961683595*x^8 - 806556841120532680* x^7 - 2575481228604156570*x^6 + 2756771576006241774*x^5 - 289772792762362859 5*x^4 + 4379071886234238350*x^3 - 4957913590225421420*x^2 - 9814084760206994 84*x + 24006278056864075, 39516536165538345*x^14 - 6500512476832995*x^13 - 1 96215472046117185*x^12 + 229902227480108910*x^11 + 237380704030959181*x^10 - 1064931988160773805*x^9 - 20657086671714300*x^8 + 1772885205999206010*x^7 + 5952033217241102348*x^6 - 4838840187320655696*x^5 + 5180390720553188700*x^4 - 8374015687535120430*x^3 + 8907744727915040221*x^2 + 4155976664123434381*x + 318920215718580450], [49744, 3109], 1, [], [], [[1, x, x^2, x^3, x^4], [1 , 1, 1, 1, 1]], [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], 1, [y^3 - y - 1, [1, 1], -23, 1, [[1, 0.7548776662466927600 4950889635852869189, 1.3247179572447460259609088544780973407; 1, -0.87743883 312334638002475444817926434595 - 0.74486176661974423659317042860439236724*I, -0.66235897862237301298045442723904867037 + 0.56227951206230124389918214490 937306150*I], [1, 0.75487766624669276004950889635852869189, 1.32471795724474 60259609088544780973407; 1, -1.6223005997430906166179248767836567132, -0.100 07946656007176908127228232967560887; 1, -0.132577066503602143431584019574871 97871, -1.2246384906846742568796365721484217319], [1, 1, 1; 1, -2, 0; 1, 0, -1], [3, -1, 0; -1, 1, 3; 0, 3, 2], [23, 16, 13; 0, 1, 0; 0, 0, 1], [7, -2, 3; -2, -6, 9; 3, 9, -2], [23, [10, 1, 8; 7, 3, 1; 1, 7, 10]], [23]], [1.3247 179572447460259609088544780973407, -0.66235897862237301298045442723904867037 + 0.56227951206230124389918214490937306150*I], [1, y^2 - 1, y], [1, 0, 1; 0 , 0, 1; 0, 1, 0], [1, 0, 0, 0, 0, 1, 0, 1, 1; 0, 1, 0, 1, -1, 0, 0, 0, 1; 0, 0, 1, 0, 1, 0, 1, 0, 0]], [x^15 - 5*x^13 + 5*x^12 + 7*x^11 - 26*x^10 - 5*x^ 9 + 45*x^8 + 158*x^7 - 98*x^6 + 110*x^5 - 190*x^4 + 189*x^3 + 144*x^2 + 25*x + 1, 39516536165538345/83718587879473471*x^14 - 6500512476832995/8371858787 9473471*x^13 - 196215472046117185/83718587879473471*x^12 + 22990222748010891 0/83718587879473471*x^11 + 237380704030959181/83718587879473471*x^10 - 10649 31988160773805/83718587879473471*x^9 - 20657086671714300/83718587879473471*x ^8 + 1772885205999206010/83718587879473471*x^7 + 5952033217241102348/8371858 7879473471*x^6 - 4838840187320655696/83718587879473471*x^5 + 518039072055318 8700/83718587879473471*x^4 - 8374015687535120430/83718587879473471*x^3 + 890 7744727915040221/83718587879473471*x^2 + 4155976664123434381/837185878794734 71*x + 318920215718580450/83718587879473471, -1, y^3 - y - 1, x^5 - x - 2], [0, 0]] ? bnfcertify(bnf) 1 ? dobnf(x^4+24*x^2+585*x+1791,,[0.1,0.1]) [[4], [Mod(8/147*x^3 - 41/147*x^2 + 132/49*x + 908/49, x^4 + 24*x^2 + 585*x + 1791)]] ? bnrconductor(bnf,[[25,13;0,1],[1,1]]) [[5, 3; 0, 1], [1, 0]] ? bnrconductorofchar(bnr,[2]) [[5, 3; 0, 1], [0, 0]] ? bnfisprincipal(bnf,[5,1;0,1],0) [1]~ ? bnfisprincipal(bnf,[5,1;0,1]) [[1]~, [-2, -1/3]~] ? bnfisunit(bnf,Mod(3405*x-27466,x^2-x-57)) [-4, Mod(1, 2)]~ ? bnfnarrow(bnf) [3, [3], [[3, 2; 0, 1]]] ? bnfsignunit(bnf) [-1] [ 1] ? bnrclassno(bnf,[[5,3;0,1],[1,0]]) 12 ? lu=ideallist(bnf,55,3); ? bnrclassnolist(bnf,lu) [[3], [], [3, 3], [3], [6, 6], [], [], [], [3, 3, 3], [], [3, 3], [3, 3], [] , [], [12, 6, 6, 12], [3], [3, 3], [], [9, 9], [6, 6], [], [], [], [], [6, 1 2, 6], [], [3, 3, 3, 3], [], [], [], [], [], [3, 6, 6, 3], [], [], [9, 3, 9] , [6, 6], [], [], [], [], [], [3, 3], [3, 3], [12, 12, 6, 6, 12, 12], [], [] , [6, 6], [9], [], [3, 3, 3, 3], [], [3, 3], [], [6, 12, 12, 6]] ? bnrdisc(bnr,Mat(6)) [12, 12, 18026977100265125] ? bnrdisc(bnr) [24, 12, 40621487921685401825918161408203125] ? bnrdisc(bnr2,,,2) 0 ? bnrdisc(bnr,Mat(6),,1) [6, 2, [125, 13; 0, 1]] ? bnrdisc(bnr,,,1) [12, 1, [1953125, 1160888; 0, 1]] ? bnrdisc(bnr2,,,3) 0 ? bnrdisclist(bnf,lu) [[[6, 6, Mat([229, 3])]], [], [[], []], [[]], [[12, 12, [5, 3; 229, 6]], [12 , 12, [5, 3; 229, 6]]], [], [], [], [[], [], []], [], [[], []], [[], []], [] , [], [[24, 24, [3, 6; 5, 9; 229, 12]], [], [], [24, 24, [3, 6; 5, 9; 229, 1 2]]], [[]], [[], []], [], [[18, 18, [19, 6; 229, 9]], [18, 18, [19, 6; 229, 9]]], [[], []], [], [], [], [], [[], [24, 24, [5, 12; 229, 12]], []], [], [[ ], [], [], []], [], [], [], [], [], [[], [12, 12, [3, 3; 11, 3; 229, 6]], [1 2, 12, [3, 3; 11, 3; 229, 6]], []], [], [], [[18, 18, [2, 12; 3, 12; 229, 9] ], [], [18, 18, [2, 12; 3, 12; 229, 9]]], [[12, 12, [37, 3; 229, 6]], [12, 1 2, [37, 3; 229, 6]]], [], [], [], [], [], [[], []], [[], []], [[], [], [], [ ], [], []], [], [], [[12, 12, [2, 12; 3, 3; 229, 6]], [12, 12, [2, 12; 3, 3; 229, 6]]], [[18, 18, [7, 12; 229, 9]]], [], [[], [], [], []], [], [[], []], [], [[], [24, 24, [5, 9; 11, 6; 229, 12]], [24, 24, [5, 9; 11, 6; 229, 12]] , []]] ? bnrdisclist(bnf,20) [[[[Vecsmall([]), Vecsmall([])], [[6, 6, Mat([229, 3])], [0, 0, 0], [0, 0, 0 ], [0, 0, 0]]]], [], [[[Vecsmall([12]), Vecsmall([1])], [[0, 0, 0], [12, 6, [-1, 1; 3, 3; 229, 6]], [0, 0, 0], [0, 0, 0]]], [[Vecsmall([13]), Vecsmall([ 1])], [[0, 0, 0], [0, 0, 0], [12, 6, [-1, 1; 3, 3; 229, 6]], [0, 0, 0]]]], [ [[Vecsmall([10]), Vecsmall([1])], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0 ]]]], [[[Vecsmall([20]), Vecsmall([1])], [[12, 12, [5, 3; 229, 6]], [24, 12, [5, 9; 229, 12]], [0, 0, 0], [0, 0, 0]]], [[Vecsmall([21]), Vecsmall([1])], [[12, 12, [5, 3; 229, 6]], [0, 0, 0], [24, 12, [5, 9; 229, 12]], [0, 0, 0]] ]], [], [], [], [[[Vecsmall([12]), Vecsmall([2])], [[0, 0, 0], [0, 0, 0], [0 , 0, 0], [0, 0, 0]]], [[Vecsmall([12, 13]), Vecsmall([1, 1])], [[0, 0, 0], [ 0, 0, 0], [0, 0, 0], [24, 0, [3, 12; 229, 12]]]], [[Vecsmall([13]), Vecsmall ([2])], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]]], [], [[[Vecsmall([44] ), Vecsmall([1])], [[0, 0, 0], [0, 0, 0], [12, 6, [-1, 1; 11, 3; 229, 6]], [ 0, 0, 0]]], [[Vecsmall([45]), Vecsmall([1])], [[0, 0, 0], [12, 6, [-1, 1; 11 , 3; 229, 6]], [0, 0, 0], [0, 0, 0]]]], [[[Vecsmall([10, 12]), Vecsmall([1, 1])], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]], [[Vecsmall([10, 13]), V ecsmall([1, 1])], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]]], [], [], [[ [Vecsmall([12, 20]), Vecsmall([1, 1])], [[24, 24, [3, 6; 5, 9; 229, 12]], [4 8, 24, [3, 12; 5, 18; 229, 24]], [0, 0, 0], [0, 0, 0]]], [[Vecsmall([13, 20] ), Vecsmall([1, 1])], [[0, 0, 0], [0, 0, 0], [24, 12, [3, 6; 5, 6; 229, 12]] , [48, 0, [3, 12; 5, 18; 229, 24]]]], [[Vecsmall([12, 21]), Vecsmall([1, 1]) ], [[0, 0, 0], [24, 12, [3, 6; 5, 6; 229, 12]], [0, 0, 0], [48, 0, [3, 12; 5 , 18; 229, 24]]]], [[Vecsmall([13, 21]), Vecsmall([1, 1])], [[24, 24, [3, 6; 5, 9; 229, 12]], [0, 0, 0], [48, 24, [3, 12; 5, 18; 229, 24]], [0, 0, 0]]]] , [[[Vecsmall([10]), Vecsmall([2])], [[0, 0, 0], [12, 6, [-1, 1; 2, 12; 229, 6]], [12, 6, [-1, 1; 2, 12; 229, 6]], [24, 0, [2, 36; 229, 12]]]]], [[[Vecs mall([68]), Vecsmall([1])], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [12, 0, [17, 3 ; 229, 6]]]], [[Vecsmall([69]), Vecsmall([1])], [[0, 0, 0], [0, 0, 0], [0, 0 , 0], [12, 0, [17, 3; 229, 6]]]]], [], [[[Vecsmall([76]), Vecsmall([1])], [[ 18, 18, [19, 6; 229, 9]], [36, 18, [-1, 1; 19, 15; 229, 18]], [0, 0, 0], [0, 0, 0]]], [[Vecsmall([77]), Vecsmall([1])], [[18, 18, [19, 6; 229, 9]], [0, 0, 0], [36, 18, [-1, 1; 19, 15; 229, 18]], [0, 0, 0]]]], [[[Vecsmall([10, 20 ]), Vecsmall([1, 1])], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]], [[Vecs mall([10, 21]), Vecsmall([1, 1])], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]]]] ? bnrisprincipal(bnr,idealprimedec(bnf,7)[1]) [[9]~, [32879/6561, 13958/19683]~] ? dirzetak(nfinit(x^3-10*x+8),30) [1, 2, 0, 3, 1, 0, 0, 4, 0, 2, 1, 0, 0, 0, 0, 5, 1, 0, 0, 3, 0, 2, 0, 0, 2, 0, 1, 0, 1, 0] ? factornf(x^3+x^2-2*x-1,t^3+t^2-2*t-1) [ x + Mod(-t, t^3 + t^2 - 2*t - 1) 1] [ x + Mod(-t^2 + 2, t^3 + t^2 - 2*t - 1) 1] [x + Mod(t^2 + t - 1, t^3 + t^2 - 2*t - 1) 1] ? vp=idealprimedec(nf,3)[1] [3, [1, 0, 1, 0, 0]~, 1, 1, [1, 4, -1, 6, -4; -1, 2, 4, 3, -5; -1, -1, 1, 0, 4; -1, -1, -2, 0, -2; 0, 3, 0, 0, 0]] ? idx=idealhnf(nf,vp) [3 2 1 0 1] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? idealred(nf,idx,[1,5,6]) [3 2 1 0 1] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? idy=idealdiv(nf,5,idealprimedec(nf,5)[1]) [5 0 0 0 2] [0 5 0 0 2] [0 0 5 0 1] [0 0 0 5 2] [0 0 0 0 1] ? idx2=idealmul(nf,idx,idx) [9 5 7 0 4] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? idt=idealmul(nf,idx,idx,1) [9 5 7 0 4] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? idz=idealintersect(nf,idx,idy) [15 10 5 0 12] [ 0 5 0 0 2] [ 0 0 5 0 1] [ 0 0 0 5 2] [ 0 0 0 0 1] ? aid=[idx,idy,idz,1,idx]; ? idealadd(nf,idx,idy) [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? idealaddtoone(nf,idx,idy) [[6, 0, 0, 0, 0]~, [-5, 0, 0, 0, 0]~] ? idealaddtoone(nf,[idy,idx]) [[-5, 0, 0, 0, 0]~, [6, 0, 0, 0, 0]~] ? idealappr(nf,idy) [-1, 4, 2, -1, -3]~ ? idealappr(nf,idealfactor(nf,idy)) [-1, 4, 2, -1, -3]~ ? idealcoprime(nf,idx,idx) [-1/3, 1/3, 1/3, 1/3, 0]~ ? idealdiv(nf,idy,idt) [5 0 0 10/3 41/9] [0 5 0 5/3 31/9] [0 0 5 5/3 13/9] [0 0 0 5/3 1/9] [0 0 0 0 1/3] ? idealdiv(nf,idx2,idx,1) [3 2 1 0 1] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? idealfactor(nf,idz) [[3, [1, 0, 1, 0, 0]~, 1, 1, [1, 4, -1, 6, -4; -1, 2, 4, 3, -5; -1, -1, 1, 0 , 4; -1, -1, -2, 0, -2; 0, 3, 0, 0, 0]] 1] [[5, [-1, 0, 0, 0, 2]~, 4, 1, [2, -3, 0, -12, 6; 2, 2, -5, -2, 6; 1, 1, 0, - 1, -7; 2, 2, 5, 3, 1; 1, -4, 0, -1, 3]] 3] [[5, [2, 0, 0, 0, -2]~, 1, 1, [2, 1, 10, -4, 2; 0, 0, -5, 0, 0; 3, -1, 0, -1 , -7; 0, 0, 5, 5, 5; 1, -2, 0, 3, 1]] 1] ? idealhnf(nf,vp[2],3) [3 2 1 0 1] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? ideallist(bnf,20) [[[1, 0; 0, 1]], [], [[3, 2; 0, 1], [3, 0; 0, 1]], [[2, 0; 0, 2]], [[5, 3; 0 , 1], [5, 1; 0, 1]], [], [], [], [[9, 5; 0, 1], [3, 0; 0, 3], [9, 3; 0, 1]], [], [[11, 9; 0, 1], [11, 1; 0, 1]], [[6, 4; 0, 2], [6, 0; 0, 2]], [], [], [ [15, 8; 0, 1], [15, 3; 0, 1], [15, 11; 0, 1], [15, 6; 0, 1]], [[4, 0; 0, 4]] , [[17, 14; 0, 1], [17, 2; 0, 1]], [], [[19, 18; 0, 1], [19, 0; 0, 1]], [[10 , 6; 0, 2], [10, 2; 0, 2]]] ? bid=idealstar(nf2,54) [[[54, 0, 0; 0, 54, 0; 0, 0, 54], [0]], [132678, [1638, 9, 9]], [[[2, [2, 0, 0]~, 1, 3, 1], 1; [3, [3, 0, 0]~, 1, 3, 1], 3], [[2, [2, 0, 0]~, 1, 3, 1], 1; [3, [3, 0, 0]~, 1, 3, 1], 3]], [[[[7], [[1, -27, -27]~], [2, 0, 0; 0, 2, 0; 0, 0, 2], [[1, [1, 1, 0; 0, 0, 1; 0, 1, 0], [2, [2, 0, 0]~, 1, 3, 1], y^3 + y + 1]~, y^2 + y, [7, Mat([7, 1])]]], [[234, 9, 9], [[23, 26, -12]~, [1, -24, 0]~, [1, 0, -24]~], [27, 0, 0; 0, 27, 0; 0, 0, 27], [[1, [1, 2, 0; 0, 0 , 1; 0, 1, 0], [3, [3, 0, 0]~, 1, 3, 1], y^3 + 2*y + 2]~, 2*y^2, [26, [2, 1; 13, 1]]], [26, [-1, -7, -3]~, [[[3, 3, 3], [4, [1, 3, 0]~, [1, 0, 3]~], [1, 0, 0; 0, 1, 0; 0, 0, 1], 3], [[3, 3, 3], [10, [1, 9, 0]~, [1, 0, 9]~], [1, 0, 0; 0, 1, 0; 0, 0, 1], 9]]], [[-207, 0, 0]~, [208, 0, 0, 156, 0, 0; 0, 1, 0, 0, -6, 0; 0, 0, 1, 0, 0, -6]]]], [[], Vecsmall([])]], [[-234; 0; 0], [7, -182, 182; 3, -5, 5; 0, 1, 0]]] ? ideallog(nf2,y,bid) [946, 2, 3]~ ? idealmin(nf,idx,[1,2,3]) [1, 0, 1, 0, 0]~ ? idealnorm(nf,idt) 9 ? idp=idealpow(nf,idx,7) [2187 1436 1807 630 1822] [ 0 1 0 0 0] [ 0 0 1 0 0] [ 0 0 0 1 0] [ 0 0 0 0 1] ? idealpow(nf,idx,5,1) [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? idealprimedec(nf,2) [[2, [3, 0, 1, 0, 0]~, 1, 1, [0, 2, 0, -4, -2; 0, 0, 0, 2, 0; 0, 0, -2, -2, -2; 1, 0, 3, 0, -1; 1, 0, 1, 0, -1]], [2, [12, -4, -2, 11, 3]~, 1, 4, [1, -1 , 3, -1, 1; 0, 0, -2, -1, 1; 1, 0, 1, 0, -2; 0, 0, 1, 2, 2; 0, -1, 0, 1, 1]] ] ? idealprimedec(nf,3) [[3, [1, 0, 1, 0, 0]~, 1, 1, [1, 4, -1, 6, -4; -1, 2, 4, 3, -5; -1, -1, 1, 0 , 4; -1, -1, -2, 0, -2; 0, 3, 0, 0, 0]], [3, [1, 1, 1, 0, 0]~, 2, 2, [0, -6, 3, -9, 9; 2, -1, -7, -5, 7; 2, 1, 0, 1, -7; 1, 2, 3, 2, 4; 0, -5, -1, 0, 2] ]] ? idealprimedec(nf,11) [[11, [11, 0, 0, 0, 0]~, 1, 5, 1]] ? idealtwoelt(nf,idy) [5, [2, 2, 1, 2, 1]~] ? idealtwoelt(nf,idy,10) [-1, 4, 2, 4, 2]~ ? idealstar(nf2,54) [[[54, 0, 0; 0, 54, 0; 0, 0, 54], [0]], [132678, [1638, 9, 9]], [[[2, [2, 0, 0]~, 1, 3, 1], 1; [3, [3, 0, 0]~, 1, 3, 1], 3], [[2, [2, 0, 0]~, 1, 3, 1], 1; [3, [3, 0, 0]~, 1, 3, 1], 3]], [[[[7], [[1, -27, -27]~], [2, 0, 0; 0, 2, 0; 0, 0, 2], [[1, [1, 1, 0; 0, 0, 1; 0, 1, 0], [2, [2, 0, 0]~, 1, 3, 1], y^3 + y + 1]~, y^2 + y, [7, Mat([7, 1])]]], [[234, 9, 9], [[23, 26, -12]~, [1, -24, 0]~, [1, 0, -24]~], [27, 0, 0; 0, 27, 0; 0, 0, 27], [[1, [1, 2, 0; 0, 0 , 1; 0, 1, 0], [3, [3, 0, 0]~, 1, 3, 1], y^3 + 2*y + 2]~, 2*y^2, [26, [2, 1; 13, 1]]], [26, [-1, -7, -3]~, [[[3, 3, 3], [4, [1, 3, 0]~, [1, 0, 3]~], [1, 0, 0; 0, 1, 0; 0, 0, 1], 3], [[3, 3, 3], [10, [1, 9, 0]~, [1, 0, 9]~], [1, 0, 0; 0, 1, 0; 0, 0, 1], 9]]], [[-207, 0, 0]~, [208, 0, 0, 156, 0, 0; 0, 1, 0, 0, -6, 0; 0, 0, 1, 0, 0, -6]]]], [[], Vecsmall([])]], [[-234; 0; 0], [7, -182, 182; 3, -5, 5; 0, 1, 0]]] ? idealval(nf,idp,vp) 7 ? ba=nfalgtobasis(nf,x^3+5) [6, 1, 3, 1, 3]~ ? bb=nfalgtobasis(nf,x^3+x) [1, 1, 4, 1, 3]~ ? bc=matalgtobasis(nf,[x^2+x;x^2+1]) [[3, -2, 1, 1, 0]~] [[4, -2, 0, 1, 0]~] ? matbasistoalg(nf,bc) [Mod(x^2 + x, x^5 - 5*x^3 + 5*x + 25)] [Mod(x^2 + 1, x^5 - 5*x^3 + 5*x + 25)] ? nfbasis(x^3+4*x+5) [1, x, 1/7*x^2 - 1/7*x - 2/7] ? nfbasistoalg(nf,ba) Mod(x^3 + 5, x^5 - 5*x^3 + 5*x + 25) ? nfdisc(x^3+4*x+12) -1036 ? nfeltdiv(nf,ba,bb) [584/373, 66/373, -32/373, -105/373, 120/373]~ ? nfeltdiveuc(nf,ba,bb) [2, 0, 0, 0, 0]~ ? nfeltdivrem(nf,ba,bb) [[2, 0, 0, 0, 0]~, [4, -1, -5, -1, -3]~] ? nfeltmod(nf,ba,bb) [4, -1, -5, -1, -3]~ ? nfeltmul(nf,ba,bb) [50, -15, -35, 60, 15]~ ? nfeltpow(nf,bb,5) [-291920, 136855, 230560, -178520, 74190]~ ? nfeltreduce(nf,ba,idx) [1, 0, 0, 0, 0]~ ? nfeltval(nf,ba,vp) 0 ? nffactor(nf2,x^3+x) [ x 1] [x^2 + 1 1] ? aut=nfgaloisconj(nf3) [-x, x, -1/12*x^4 - 1/2*x, -1/12*x^4 + 1/2*x, 1/12*x^4 - 1/2*x, 1/12*x^4 + 1 /2*x]~ ? nfgaloisapply(nf3,aut[5],Mod(x^5,x^6+108)) Mod(-1/2*x^5 + 9*x^2, x^6 + 108) ? nfhilbert(nf,3,5) -1 ? nfhilbert(nf,3,5,vp) -1 ? nfhnf(nf,[a,aid]) [[1, 1, 4; 0, 1, 0; 0, 0, 1], [[15, 2, 10, 12, 4; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], 1, 1]] ? da=nfdetint(nf,[a,aid]) [15 10 5 0 12] [ 0 5 0 0 2] [ 0 0 5 0 1] [ 0 0 0 5 2] [ 0 0 0 0 1] ? nfhnfmod(nf,[a,aid],da) [[1, 1, 4; 0, 1, 0; 0, 0, 1], [[15, 2, 10, 12, 4; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], 1, 1]] ? nfisideal(bnf[7],[5,1;0,1]) 1 ? nfisincl(x^2+1,x^4+1) [-x^2, x^2] ? nfisincl(x^2+1,nfinit(x^4+1)) [-x^2, x^2] ? nfisisom(x^3+x^2-2*x-1,x^3+x^2-2*x-1) [x, -x^2 - x + 1, x^2 - 2] ? nfisisom(x^3-2,nfinit(x^3-6*x^2-6*x-30)) [-1/25*x^2 + 13/25*x - 2/5] ? nfroots(nf2,x+2) [Mod(-2, y^3 - y - 1)] ? nfrootsof1(nf) [2, -1] ? nfsnf(nf,[a[,1..3],[1,1,1],[idealinv(nf,idx),idealinv(nf,idy),1]]) [[15706993357777254170417850, 1636878763571210697462070, 1307908830618593502 9427775, 1815705333955314515809980, 7581330311082212790621785; 0, 5, 0, 0, 0 ; 0, 0, 5, 0, 0; 0, 0, 0, 5, 0; 0, 0, 0, 0, 5], [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1]] ? nfsubfields(nf) [[x, 0], [x^5 - 5*x^3 + 5*x + 25, x]] ? polcompositum(x^4-4*x+2,x^3-x-1) [x^12 - 4*x^10 + 8*x^9 + 12*x^8 + 12*x^7 + 138*x^6 + 132*x^5 - 43*x^4 + 58*x ^2 - 128*x - 5] ? polcompositum(x^4-4*x+2,x^3-x-1,1) [[x^12 - 4*x^10 + 8*x^9 + 12*x^8 + 12*x^7 + 138*x^6 + 132*x^5 - 43*x^4 + 58* x^2 - 128*x - 5, Mod(-279140305176/29063006931199*x^11 + 129916611552/290630 06931199*x^10 + 1272919322296/29063006931199*x^9 - 2813750209005/29063006931 199*x^8 - 2859411937992/29063006931199*x^7 - 414533880536/29063006931199*x^6 - 35713977492936/29063006931199*x^5 - 17432607267590/29063006931199*x^4 + 4 9785595543672/29063006931199*x^3 + 9423768373204/29063006931199*x^2 - 427797 76146743/29063006931199*x + 37962587857138/29063006931199, x^12 - 4*x^10 + 8 *x^9 + 12*x^8 + 12*x^7 + 138*x^6 + 132*x^5 - 43*x^4 + 58*x^2 - 128*x - 5), M od(-279140305176/29063006931199*x^11 + 129916611552/29063006931199*x^10 + 12 72919322296/29063006931199*x^9 - 2813750209005/29063006931199*x^8 - 28594119 37992/29063006931199*x^7 - 414533880536/29063006931199*x^6 - 35713977492936/ 29063006931199*x^5 - 17432607267590/29063006931199*x^4 + 49785595543672/2906 3006931199*x^3 + 9423768373204/29063006931199*x^2 - 13716769215544/290630069 31199*x + 37962587857138/29063006931199, x^12 - 4*x^10 + 8*x^9 + 12*x^8 + 12 *x^7 + 138*x^6 + 132*x^5 - 43*x^4 + 58*x^2 - 128*x - 5), -1]] ? polgalois(x^6-3*x^2-1) [12, 1, 1, "A_4(6) = [2^2]3"] ? polred(x^5-2*x^4-4*x^3-96*x^2-352*x-568) [x, x^5 - x^4 + 2*x^3 - 4*x^2 + x - 1] ? polred(x^4-28*x^3-458*x^2+9156*x-25321,3) [ 0 x] [ 1/115*x^2 - 14/115*x - 212/115 x^2 - 2*x - 9] [ -1/115*x^2 + 14/115*x + 442/115 x^2 - 2*x - 9] [ 1/115*x^2 - 14/115*x - 327/115 x^2 - 10] [1/4485*x^3 - 7/1495*x^2 - 1034/4485*x + 7924/4485 x^4 - 8*x^2 + 6] ? polred(x^4+576,1) [x, x^2 - 3*x + 3, x^2 - 2*x + 2, x^2 - x + 1, x^2 + 1, x^4 - x^2 + 1] ? polred(x^4+576,3) [ 0 x] [ -1/192*x^3 - 1/8*x + 3/2 x^2 - 3*x + 3] [ 1/24*x^2 + 1 x^2 - 2*x + 2] [ -1/24*x^2 + 1 x^2 - 2*x + 2] [ -1/192*x^3 - 1/8*x + 1/2 x^2 - x + 1] [ 1/192*x^3 + 1/8*x + 1/2 x^2 - x + 1] [ 1/24*x^2 x^2 + 1] [1/192*x^3 + 1/48*x^2 - 1/8*x x^4 - x^2 + 1] ? polred(p2,0,fa) [x, x^5 - 80*x^3 - 223*x^2 + 800*x + 2671] ? polred(p2,1,fa) [x, x^5 - 80*x^3 - 223*x^2 + 800*x + 2671] ? polredabs(x^5-2*x^4-4*x^3-96*x^2-352*x-568) x^5 - x^4 + 2*x^3 - 4*x^2 + x - 1 ? polredabs(x^5-2*x^4-4*x^3-96*x^2-352*x-568,1) [x^5 - x^4 + 2*x^3 - 4*x^2 + x - 1, Mod(2*x^4 - x^3 + 3*x^2 - 3*x - 1, x^5 - x^4 + 2*x^3 - 4*x^2 + x - 1)] ? polredord(x^3-12*x+45*x-1) [x, x^3 + 33*x - 1] ? polsubcyclo(31,5) x^5 + x^4 - 12*x^3 - 21*x^2 + x + 5 ? setrand(1);poltschirnhaus(x^5-x-1) x^5 + 10*x^4 + 32*x^3 - 100*x^2 - 879*x - 1457 ? p=x^5-5*x+y;aa=rnfpseudobasis(nf2,p) [[1, 0, 0, -2, [3, 1, 0]~; 0, 1, 0, 2, [0, -1, 0]~; 0, 0, 1, 1, [-5, -2, 0]~ ; 0, 0, 0, 1, -2; 0, 0, 0, 0, 1], [1, 1, 1, [1, 0, 2/5; 0, 1, 3/5; 0, 0, 1/5 ], [1, 0, 22/25; 0, 1, 8/25; 0, 0, 1/25]], [416134375, 202396875, 60056800; 0, 3125, 2700; 0, 0, 25], [-63, -172, 56]~] ? rnfbasis(bnf2,aa) [1 0 0 [-66/25, -24/25, -3/25]~ [-202/25, 97/25, -241/25]~] [0 1 0 [48/25, -3/25, 9/25]~ [61/25, -121/25, 238/25]~] [0 0 1 [51/25, 39/25, 8/25]~ [267/25, 38/25, 136/25]~] [0 0 0 [37/25, 18/25, -4/25]~ [124/25, -64/25, 117/25]~] [0 0 0 [-6/25, -9/25, 2/25]~ [-47/25, -8/25, -1/25]~] ? rnfdisc(nf2,p) [[416134375, 202396875, 60056800; 0, 3125, 2700; 0, 0, 25], [-63, -172, 56]~ ] ? rnfequation(nf2,p) x^15 - 15*x^11 + 75*x^7 - x^5 - 125*x^3 + 5*x + 1 ? rnfequation(nf2,p,1) [x^15 - 15*x^11 + 75*x^7 - x^5 - 125*x^3 + 5*x + 1, Mod(-x^5 + 5*x, x^15 - 1 5*x^11 + 75*x^7 - x^5 - 125*x^3 + 5*x + 1), 0] ? rnfhnfbasis(bnf2,aa) [1 0 0 [-6/5, -4/5, 2/5]~ [3/25, -8/25, 24/25]~] [0 1 0 [6/5, 4/5, -2/5]~ [-9/25, -1/25, 3/25]~] [0 0 1 [3/5, 2/5, -1/5]~ [-8/25, 13/25, -39/25]~] [0 0 0 [3/5, 2/5, -1/5]~ [4/25, 6/25, -18/25]~] [0 0 0 0 [-2/25, -3/25, 9/25]~] ? rnfisfree(bnf2,aa) 1 ? rnfsteinitz(nf2,aa) [[1, 0, 0, [-66/25, -24/25, -3/25]~, [69/125, 1/5, 3/125]~; 0, 1, 0, [48/25, -3/25, 9/25]~, [-48/125, 2/125, -9/125]~; 0, 0, 1, [51/25, 39/25, 8/25]~, [ -56/125, -41/125, -8/125]~; 0, 0, 0, [37/25, 18/25, -4/25]~, [-39/125, -18/1 25, 4/125]~; 0, 0, 0, [-6/25, -9/25, 2/25]~, [7/125, 9/125, -2/125]~], [1, 1 , 1, 1, [125, 0, 22; 0, 125, 108; 0, 0, 1]], [416134375, 202396875, 60056800 ; 0, 3125, 2700; 0, 0, 25], [-63, -172, 56]~] ? setrand(1);quadclassunit(1-10^7,,[1,1]) [2416, [1208, 2], [Qfb(277, 55, 9028), Qfb(1700, 1249, 1700)], 1] ? setrand(1);quadclassunit(10^9-3,,[0.5,0.5]) [4, [4], [Qfb(211, 31405, -16263, 0.E-38)], 2800.625251907016076486370621737 0745514] ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 44 pari-2.11.2/src/test/32/language0000644000175000017500000000003013213263002014637 0ustar billbill[1] Total time spent: 0 pari-2.11.2/src/test/32/quadray0000644000175000017500000024472313326135265014563 0ustar billbill-15: x^2 - x + 1 -35: x^2 - x - 1 -51: x^2 - x + 1 -91: x^2 - x + 2 -115: x^2 - x - 1 -123: x^2 - x + 1 -187: x^2 - x + 3 -195: x^4 - x^3 + 2*x^2 + x + 1 -235: x^2 - x - 1 -267: x^2 - x + 1 -403: x^2 - x - 3 -427: x^2 - x + 2 -435: x^4 - x^3 + 2*x^2 + x + 1 -483: x^4 - x^3 - x^2 - 2*x + 4 -555: x^4 - x^3 + 2*x^2 + x + 1 -595: x^4 - x^3 + 5*x^2 + 2*x + 4 -627: x^4 - x^3 - 2*x^2 - 3*x + 9 -715: x^4 - x^3 + 8*x^2 + 3*x + 9 -795: x^4 - x^3 + 2*x^2 + x + 1 -1155: x^8 + 15*x^6 + 32*x^4 + 15*x^2 + 1 -1435: x^4 - x^3 + 5*x^2 + 2*x + 4 -1995: x^8 + 15*x^6 + 32*x^4 + 15*x^2 + 1 -3003: x^8 - 9*x^6 + 80*x^4 - 9*x^2 + 1 -3315: x^8 + 9*x^6 + 77*x^4 + 36*x^2 + 16 -20: x^2 + 1 -24: x^2 - 2 -40: x^2 + 2 -52: x^2 + 1 -84: x^4 - x^2 + 1 -88: x^2 - 2 -120: x^4 + 2*x^2 + 4 -132: x^4 - x^2 + 1 -148: x^2 + 1 -168: x^4 - 2*x^3 + x^2 - 6*x + 9 -228: x^4 - x^2 + 1 -232: x^2 + 2 -280: x^4 - 2*x^3 - 5*x^2 + 6*x - 1 -312: x^4 + 2*x^2 + 4 -340: x^4 + 3*x^2 + 1 -372: x^4 - x^2 + 1 -408: x^4 + 2*x^2 + 4 -420: x^8 - 3*x^6 + 8*x^4 - 3*x^2 + 1 -520: x^4 + 6*x^2 + 4 -532: x^4 - 3*x^2 + 4 -660: x^8 - 3*x^6 + 8*x^4 - 3*x^2 + 1 -708: x^4 - x^2 + 1 -760: x^4 - 2*x^3 - 5*x^2 + 6*x - 1 -840: x^8 - 4*x^7 - 2*x^6 + 20*x^5 - 3*x^4 - 32*x^3 + 64*x^2 - 44*x + 19 -1012: x^4 - 5*x^2 + 9 -1092: x^8 + 3*x^6 + 5*x^4 + 12*x^2 + 16 -1320: x^8 - 4*x^7 - 2*x^6 + 20*x^5 - 3*x^4 - 32*x^3 + 64*x^2 - 44*x + 19 -1380: x^8 - 3*x^6 + 8*x^4 - 3*x^2 + 1 -1428: x^8 + 3*x^6 + 5*x^4 + 12*x^2 + 16 -1540: x^8 - 4*x^7 + 20*x^6 - 46*x^5 + 93*x^4 - 114*x^3 + 92*x^2 - 42*x + 9 -1848: x^8 - 2*x^7 + 3*x^6 - 14*x^5 + 65*x^4 - 64*x^3 + 46*x^2 + 24*x + 4 -5460: x^16 + 9*x^14 + 44*x^12 + 261*x^10 + 1029*x^8 + 1044*x^6 + 704*x^4 + 576*x^2 + 256 x^20 + 27*x^19 + 601*x^18 - 4014*x^17 + 9878*x^16 - 12222*x^15 + 8299*x^14 + 513*x^13 - 12221*x^12 + 18036*x^11 - 17652*x^10 + 18036*x^9 - 12221*x^8 + 5 13*x^7 + 8299*x^6 - 12222*x^5 + 9878*x^4 - 4014*x^3 + 601*x^2 + 27*x + 1 x^88 - 40020669926358941160*x^87 + 24818793423306608856949584839454391158484 *x^86 - 451973748435231895940407803697160552367624*x^85 + 121004331374769746 054948634032289469332999202*x^84 + 10059034519705811655247252004833057160111 397504*x^83 + 351284965440856373689297063590147136894509846260*x^82 + 707678 7287183022340559185242964779073439110772112*x^81 + 7424864222152380159098443 6783829317747047323123243*x^80 + 3016669049298212175376092685252207677089225 7842640*x^79 - 8503049963424563714394067134889147531482230019127096*x^78 - 6 465786499366041070602916523486769538280412443510592*x^77 + 42150640446078238 28889410160434091263108115351306399268*x^76 + 119525498598846149476451596656 291689313170011135603889064*x^75 + 20718604339256925426029633374659465824208 08944831769026648*x^74 + 270442350108592451558861828173327053458397647311211 61439752*x^73 + 285289444253762620585561596576563633155859094294552566693317 *x^72 + 2511360320483460798105377398519192324398612242438706127652544*x^71 + 18767162620094934148004508464072766541604227783326918296860524*x^70 + 12042 3236654140529086575067911655764408706511359484732574173280*x^69 + 6698817371 51097381424117880193907743151768744395737304965311638*x^68 + 326030488372458 1257592451461949148632593587481718123636435123040*x^67 + 1401218174432359703 4445628272252822116949974099153581386829916444*x^66 + 5367567444185487660948 9208131197694348596313231643993076280314304*x^65 + 1849586073448214933624859 71605260396892443743494472396759635803315*x^64 + 578456213592452525292885126 678569328965911834184953238551507495512*x^63 + 16556817033476544452278210145 76515450466671643615335188802513429760*x^62 + 436878840618787239769625306249 7812500894047454768846457782824580152*x^61 + 1068901472860957747029160191079 1767817886254017900185293235705392064*x^60 + 2434351573155431230076300160060 7496079487124511808873652848483412160*x^59 + 5169291351655811457272426459136 7158576380942435990299052219843612304*x^58 + 1022998330750281135258911239455 74251052215437006684583051817380710576*x^57 + 188216797464058241448403558395 102741401235865324690992824034126437157*x^56 + 32060490325705765556225025226 1154391117300969466803557524988405580272*x^55 + 5026257120330186308702396982 13303008551061011852403188260952091908532*x^54 + 719344126023656757735145641 575616692987264009491520118662670217955328*x^53 + 92863816021928333070040902 0325566534550048821651703177989079236808666*x^52 + 1060255920795694954480037 612092276836813066528658822564102146651872808*x^51 + 10301589215685511855337 00012926850740762293883499745887488519869745108*x^50 + 771562428494427189300 153767022260995609490878443644218508155682351496*x^49 + 27346597807333111348 9250648988966144580871198921998690911757680224167*x^48 - 3923005119785941970 23702549831167038133623220261146198494006317061248*x^47 - 107531566077276356 7397744183394797701786847214693166357365831146616968*x^46 - 1589451619928021 606930471659130946568147974811578111348229080651241920*x^45 - 17807285584553 57793403089789263493950243261264268279117584476244784076*x^44 - 158945161992 8021606930471659130946568147974811578111348229080651241920*x^43 - 1075315660 772763567397744183394797701786847214693166357365831146616968*x^42 - 39230051 1978594197023702549831167038133623220261146198494006317061248*x^41 + 2734659 78073331113489250648988966144580871198921998690911757680224167*x^40 + 771562 428494427189300153767022260995609490878443644218508155682351496*x^39 + 10301 58921568551185533700012926850740762293883499745887488519869745108*x^38 + 106 0255920795694954480037612092276836813066528658822564102146651872808*x^37 + 9 28638160219283330700409020325566534550048821651703177989079236808666*x^36 + 719344126023656757735145641575616692987264009491520118662670217955328*x^35 + 502625712033018630870239698213303008551061011852403188260952091908532*x^34 + 320604903257057655562250252261154391117300969466803557524988405580272*x^33 + 188216797464058241448403558395102741401235865324690992824034126437157*x^3 2 + 102299833075028113525891123945574251052215437006684583051817380710576*x^ 31 + 51692913516558114572724264591367158576380942435990299052219843612304*x^ 30 + 24343515731554312300763001600607496079487124511808873652848483412160*x^ 29 + 10689014728609577470291601910791767817886254017900185293235705392064*x^ 28 + 4368788406187872397696253062497812500894047454768846457782824580152*x^2 7 + 1655681703347654445227821014576515450466671643615335188802513429760*x^26 + 578456213592452525292885126678569328965911834184953238551507495512*x^25 + 184958607344821493362485971605260396892443743494472396759635803315*x^24 + 5 3675674441854876609489208131197694348596313231643993076280314304*x^23 + 1401 2181744323597034445628272252822116949974099153581386829916444*x^22 + 3260304 883724581257592451461949148632593587481718123636435123040*x^21 + 66988173715 1097381424117880193907743151768744395737304965311638*x^20 + 1204232366541405 29086575067911655764408706511359484732574173280*x^19 + 187671626200949341480 04508464072766541604227783326918296860524*x^18 + 251136032048346079810537739 8519192324398612242438706127652544*x^17 + 2852894442537626205855615965765636 33155859094294552566693317*x^16 + 270442350108592451558861828173327053458397 64731121161439752*x^15 + 207186043392569254260296333746594658242080894483176 9026648*x^14 + 119525498598846149476451596656291689313170011135603889064*x^1 3 + 4215064044607823828889410160434091263108115351306399268*x^12 - 646578649 9366041070602916523486769538280412443510592*x^11 - 8503049963424563714394067 134889147531482230019127096*x^10 + 30166690492982121753760926852522076770892 257842640*x^9 + 74248642221523801590984436783829317747047323123243*x^8 + 707 6787287183022340559185242964779073439110772112*x^7 + 35128496544085637368929 7063590147136894509846260*x^6 + 10059034519705811655247252004833057160111397 504*x^5 + 121004331374769746054948634032289469332999202*x^4 - 45197374843523 1895940407803697160552367624*x^3 + 24818793423306608856949584839454391158484 *x^2 - 40020669926358941160*x + 1 x^180 - 51943580593235209115083942712389400740668999369044471856895869572767 632154790719027854950985687*x^179 + 2547067915519807589841747083394507454979 0011527047653789753822310509943417124290253283094780925633779566003695241876 25607464220675698078104131248853904115685519116107718359916443145223952387*x ^178 + 856553204115408701571995615320558014258368114267533599476048702248757 8902931990647387774030794984717551258507939754932426394582122894184128382067 3569718022270291080598668993546776793532380154605306*x^177 + 762080502049470 4596056107304576599883142953678664313128034639146864833136453854583485947432 8177873097803164055573630934557797549232895603414584717394309407907786380469 1683834066404398393999145427753183790*x^176 + 308956387636466960153212938167 7324702311668880384172270669030644914696644648416192123216702361395347555520 1495693461977412751821857739072346944409047470651675235147675440424833117756 620892810879743135932320774*x^175 + 4884082662966665508762665969667649569784 5383873744492103182446854649967702283785050616521253612447115822047297077954 9614257317623478309277167745811150568304415956966429217813229788441116863100 4611840186992685967179*x^174 + 124005751296377747143710892598982088036932674 2142684503704154223658839486788375142268292156393058732202380086677633411654 8906703591687073852643697697716348962297583421466683339923965234468615997649 73368284228647193399*x^173 + 77807342164244792507055296791047457009683139076 6947550930281827860194252415153283906741350015821421760488076097868784697023 0684361377176470035198102530788844464458277074023468487612291349831916437723 0037354352780222249*x^172 - 266780829858115272388789250462200876445272313022 9458822467054384295379499065005972497338635889603051515741573734931874924695 7762408306245748926170958653384087543385833522528441856486249210097660034861 41241557823792412532*x^171 + 14828387316468627026106844845255173547861518903 8589804985538974108300682790820861191991101023068971076505863346789787263249 0126030705881134291752595991307720023292738164624564498269365143236280388326 494814603159167594322356*x^170 + 2072714630254694525113015470563866763470442 2896220054319081495621750749375349838158314700070013284414958575563065629489 9298590460673967042987581924280852650108640761845803254699501956119005286958 261737898381117495750422003980*x^169 + 4082791913658668250669500487553396688 5085691856416081922391794020222319071345465620337482939902695391053957179581 6611178564058054521757672875527012214760684410920857152888054853976552319787 6482624865506579220641586389147210551*x^168 + 259189082653047933938409996483 4388754704904320561628999269016762833054641395201768798413743705844841716523 7122469823713043234758088183799986341785098434142194216335145773402440120312 8996614247360365624068492442391061043753826375*x^167 + 187953325502846394560 1845576629993961992277419183089685715578164443785846738744772926323542142109 3239442057010359289122214569790614009609800219235849343052099855997036406115 0923659276590113217049579865275822653265241753456459305677*x^166 - 991521344 5331010597888861249891641758957210552260378821158082129353375249195112911754 5101896722210096101308894624313777264446536224444928929934283573873319884763 96421078624456037269503565600020449431475165029149896378441501395456086*x^16 5 + 870693463207410936114722926699616258456056310070174066271951439226764821 3754498248686363880077592953938815295745097173153881494887680426204688519814 5897926708879854493196612672343274340176910775178567635481360192954408109761 462192666*x^164 + 3291269524452623301119531480681600174871375032940729132937 0111633092058003369070348946123426594086592059620504463833497832222752798945 6786539655327366403796168376108709100410788811433213881703418728731545343808 0442501304279059153710266*x^163 - 484246978651008470853848049302633937841710 0550099032573348884254048698254002568503682165709558099310997622779159632947 3025430835921039731844769840401840637061784295187888579980063280775750740026 326213445261209232925320378956182578938287*x^162 + 2366596557978274147475255 9694980204169227021539516608112189319106501133980328077568567038119905399100 7262473707379165967733688444634721899783534252243520926838729652205328556398 93844358125373580233579396300331967493836532017339326648417*x^161 - 17861170 0215272735065228998593221635895564621730723507909826896490382687997403628306 4372396936244334959016553113715105764010891971421665085465778102274753181053 1359367179288752406620535700142801097476915172283884503644920276078920893715 961*x^160 + 5442886569416213072883949195207003561672975168183342200753916623 1352236561897735153650345477157913505173224695785900066453147636135746522196 8827923591138659172463973059604218652821751160134239388400400287612441644522 959559654240096950196384*x^159 - 1878459194456192332344340381238953837099207 3242518317157665963817987346890603378811086853859511458448823118145390556032 4154260960085054869261002833248663395080605671172589053299559751809388877985 0319337022684143396368259434426190698508218580*x^158 - 184127686942437509991 1682977301117955663562464265148547217904344728959181240974449884065092029207 1219636898969097801966235466592457246648086083637230209961453625153292993135 3654541155851737335657948991190630601809654864812836013412428233332508*x^157 + 6272745337714289642780597731451440214649776184728899306566105704002623998 3846347725688034820317498349655377903497224390190783460776334008364647848917 2185092927745795075828017034702156144511828098427591206009505705409852728295 6922223630676347544*x^156 - 130604497267883349741727434418972048161536102040 0079797720405754446746742329603550983122106752795162131799337624121456619065 4040984420476843424034832196407821304821044910660899700295392042290695059542 0192036616889048813209519926849958791965413764*x^155 + 193926478941415365968 2053039191650223015193274556301436638340272814361000782491228757908126714135 5744831221609082890601733276886531625139761625422579999591146356457708488690 66496229883200724281039999541182828857613242844117034223500903997780849964*x ^154 - 208974081851580435134258388853435474877812078509775426825496895616316 4247844796032344219123951883470813854035626246176679417061266672681500232259 0819881630082047200072248185982748889171705144305698252911851141436968395735 658717414968653352018931248*x^153 + 1672646641882017449123000870294181985430 0761766363953593948968045530794890931499833945021531203099422476121576329491 5115325960697513628674724029981734640823975379662772003784140453861998461512 834247290509716832865395591217427305274661390000337103156*x^152 - 1133671449 3365295420476716878286616778916616227898741966819659317216135015136322466563 9827520548877905001507920274192410200096811676503284991805981968482979122155 1667739765953276248859306767909175625527281202034750975189910458947747942582 531447345892*x^151 + 9686019535728726397130721344019529061590234306774474243 9775684839133142925738217830167297947427381690011105467748624943273307935251 9499655312785116384255798310740712404573339361423884780107379495371631287103 7645627569348897599991117672316256550430096*x^150 - 119041422102704367724958 8670984575013578769595187713509039012506017888268506357273229685836102923546 0042880742312037127040383670254597841508519424535302963725051506007472454825 8974287875801351389617602402488639578930420752407411968308213028222350043652 *x^149 + 1390123122192263005517637294725114792837919558648428420458046731138 9247265920089325134952307005121333495864776226593824308305802270042865765522 1706646232757561716861576911604612712092794424651617086755060497490406116694 4942837594012909743669233042838778*x^148 - 123556176727604048392495454055977 6399401450331126081896858806346942631913417189093648332266104142047071085393 9823740200206373338590719973268754644225041558662153246796876936041537325415 712055287848699094590808089508684909536725801531454334504662219155298*x^147 + 78338857321405672298333791473025282082268588399811517655878927064487660842 9607987213338588537735184368455093544029691810855962878302724567812912958403 0825298526758499964573195767901492416707505928731723979119497738428625056534 2370732550549861221973628014*x^146 - 337429582052616696434247676773381390391 7055420548509812685321889562165936397719575630122778103303140528950818170117 1026255806634894861047352747650017243235019037703269391120793396636598558834 3500355068020592838333693543614719695933939552850201760137124456*x^145 + 126 7022512449095517765635963857489440320956185849532448394191453064873093377283 3265337003928417799194535821386624283453961529673399508105934582815314275613 7678638219426069444953840237686338226443443810754745407998159540925231095791 4375045407870857103723132*x^144 - 153719609646143637199240438779331521362833 0310998022856189520090149655383700607165028197046414621578662674582267335714 8666559983310416796564643262431404031085708670498514131879172395315308884725 086995597751964859239544450069420287019254955379338574827976392*x^143 + 2752 6304730305492309519611803297873567100995379403820014027217572772469997269963 1748009334990330332456740707557146239264293783419594063347012801512753255648 8881765170905842263824483323437412768565907107652500759762684840263032684703 37380600828996170962184046*x^142 - 35523095157828313337139462591351702816577 1657314332343178845563474958542277571903631744992145135630234735095041102708 2345107273636547410151070834277389339249300538652341339871040322822838485719 858336476359261521139254885461283464480406069617193177086233150446*x^141 + 3 4465803554989246489275769454764022910035142135182748059069252044933640478411 7307420416885830806110765171489332421312130211574457885515807957701177125587 6661225789242989640797022695297712572706533434600560766081391785453226598427 1205078552129981020849945722662*x^140 - 268373722516115839581073071008494919 0456447093682830001175926782807962713700083271168738651540876330140533486735 6212670696857859739463338404796759488859624213038265846572508064515479105995 6333436847011768914542767112707721040710586854450242752202162514502517912*x^ 139 + 1742444297891369493991077844263622734267621349666334184372478600323885 9274274057411635646353155281298451648136704209002938845039923935043096379256 4945721786177563429720654144039386133241554831725367065310144005542392522004 1645737733894132094639323829473024157820*x^138 - 963039078892037951990470202 7468142690696595830419680618831266273162745223389393610063433083213953579433 1498149151107810908751113241849208570338521838179678717281819508263987198750 1951924824700995996767534695158748257780864272656666861530432230128739030598 8300028*x^137 + 457447376242160839222865523212081512251204172769554541536513 6010675335568757571514112103791600745366139173664147588418919365588570555754 7201003803879915712080042312095406320055413204732204964260573379515119902554 321889204610298573371864198642424001195728006133182*x^136 - 1868860578136529 9491100566653843653174297026478659238845320831747624530880395790502643308730 5462268585078679776019946603866991516563272428283420299615035631054324035580 7669631492489263529234747091359176119230324423792605912297491073916656362078 32174634098946284598*x^135 + 65093076668803329116252899967129264121954195081 3165825173825622033622982444205859242607493663511833086292972086895883603422 4352287091011138657074487961579204189764700353920301472872505685227133477493 45517047708745645767806883427498415677547239236298519819304443846*x^134 - 18 8737857214948682414768736751123125995536055732425264657481481197221465136381 8263080004881765201151009039934832304971738613022285488660591980899059758561 7366670880266091842937662126151457793355558304191543211766144762254313419741 75714575265820939899419742919508060*x^133 + 42953889394645520155740965583894 8254975167613584775116826651538942451816286881091436166450578237021021126058 7376408754507104013237607018922017023401049094197048725524392809860540776061 0681787413121689140926769612819886834513469809393226136437731088172895759675 25206*x^132 - 63261727328918865906350940397161109868277289808692349026207015 7309911965921420948111081525007085507792610014228611379115265836635218591862 4482685303352489099685390524441351132050179570452776530090912230189731431879 125807895290459527651483474680605068851138729175634*x^131 - 1119917054839792 2751688900486058857057243360132605635779686384574213339264438353376214516815 2207498910643644483743753772520064969246600402986900436948848152659373181329 5043050789946887406470007794027558566892567839570362080341591028664006259784 979214096682612622692*x^130 + 4271314220049466852560738338393246245128105321 7108326600567680720579375803199815405014779522998261575404021302604267102318 9973496984002749534274370752056057799997646445393423249459072172570153388076 90270224780252688493775073451490812831750493851260007482523315136586*x^129 - 148023590100710673141860886464816208028643509093283015533625006596766946972 6741578398020050334876578221252235677233082465182051389340632694789790351225 9115953643872578590861494318898368229141353955324644187699428307147375218229 1248178529493117079561875143739124185634*x^128 + 246175641614565897679653848 5278045743286736401969417596627545851445013857575343959525966011452777041860 1869322995580927692188758796260764328940765798775338277071600497396412898284 6342663264119335560750008714258096212502569271025201095741906534219351860811 124404494196*x^127 + 1990565893680671595442880060323376805411690898242032023 4239133079106312028397798694740007864603898415855926572783576585034622967997 5575446479539827712484639591071048813727255731760017261708300771575388890158 591817638333201062459001177511936169630253047386566741135222*x^126 - 3016573 2341675486865253308430441797191448447887193219597832133129727214089635223501 3420645212244383261917032590855201496548201420356430642227248391186457171733 8876314939133108407277975244227776960656325124355051502725255975073566061339 620994099300340563608380613367050*x^125 + 1257948144362960333134666662231940 3520935251787268873160231319726921665830921964289640164226960267401382195941 0507546787902030963701849030258171787071185516798073095493413189997247441301 2363645824641255038770075189157898962912949013449974648054148641764400320533 8871882*x^124 - 366475271260105058017315536083033948306360270631496526170966 8533370069635382315040133597595175856841519762702237383805014287542574172530 6210807276260801506088986006283626986882464595447299254658758485568943925875 853699462405048328247959368186852953798221740253247284792*x^123 + 8471667404 0018254168541029547267006611224730675524513635334023354380604251758054675593 5413776225446989659313910683079873583112382327573250917778108062870743163021 6965584066720515779759514188951805094972301673794254962048375194153324360075 8727975735045108792516939770864*x^122 - 161146935717428461799784793801173853 4799737191324944707968337975196134044400893575466678041623869973266066574271 1435647219232676062975775017270732119064549881937724549671623652481177104960 6102487507016989267838733791065664530366349655384775511706599600386112512946 557632*x^121 + 2522694849864480951479825412582961761101029175375006299005032 3620295897587695065324670940000207944207812042399077482469097012869133985212 6354595110186421998141347799854111539239085705015451817020704883026517132793 698058647769011690212936405831828960609809154392310067086*x^120 - 3123954350 9500414655822246820581466016766786100370771446195101114970617420873338985187 2315673998753642061765284674623730429562551231647203516276142369010876697525 2061798837483708658347309888670578337964579148520979957165473678360131302986 17785547855899873691057926811306*x^119 + 26093073450128435322247521043157618 8712392067239030279298185926981851613832003883595362112194063431825921469777 7131659026396971729721032938463093179955600695600080670675651357367571081793 3768796854158042814794986008423382503555686761603718155957955520619915926285 1046258*x^118 - 546620888417310306456913297002373587712583541328636451073449 6886209350963457906027266059482196156973048570086277940148682564568467798438 0285254978737341206009503937974698380503149962544290779617099637261387918629 06553536781663415296571417609896418531671323802662549340*x^117 - 50182021729 3272384861232464186597002893681068429473599603378492391207630929901153313074 7556376877685127771266174954090809732508146930392545806488414232849981602588 1335383921214771830072947665323419883309028215410288472590477875403748309525 8171403839074803113722901930619*x^116 + 118406103336876158577917454186709740 5449294198484094378541103762383848536861007244183348157579457933081098099434 7987985778741196393539613217121527222032672240767536916435194526743758819619 0063225181878442213678933572194923238652257406338724947439730929871504295850 1899245*x^115 - 176734272677759520180709847378647130652166835479092271077232 7067981192822476939413912953115815829947318808933249885514336602487836197536 9611127131928890515684844943744748937382837125994011164383657897820620204611 77419977223148716322298719262705865767989172293892727336803*x^114 + 17753024 8530519942716171951800965388948822797211110233322549229100349316200278964800 3343785390491378071036048329384421918922891522117638503012421231548652255160 9599399433846703918342084346728100760000876417162144138571778762943474072695 63098844605653811371200441716482612*x^113 - 68055808039422415389652936779491 5026270001374161671086886435342385993661681436002138177107204224273906832078 4550021770688659201646483026969760576245696112286845508450285259619203332272 0607576466516522822599227539775561873960850804338603845784871088630793662781 4494090172*x^112 - 171345855168993153971261857965957509597335839923271917993 0591415159154748543112880240425751510004701705465610982555391151034624958936 9879115829869566643976034053215829935761929815383663545384160654490729816046 26649741228358475390951398611771434975819632467920927623648602*x^111 + 47552 8035498943149856772358089912005247194452214038396267610512853006205877224336 1926512880782786766025384282981294577511242497413537295024045772317451006411 5818078293866049727834002439604775548744427611299658913382859972919684056285 23953865800092933414124830547621130787*x^110 - 67242845398127603346764378735 8630417913935967603492325560313387832908161625682986070993808856191981689362 7337618874976711707752413017492294772666895660870194024839210050819796389750 1107885069331081963929674153546422780993129544541729439872603263786386221427 59365186532673*x^109 + 55277967193070494108505087891929956655236889687657826 8175977451438771610569912425740087266827286735858716699401268464277514456005 1393232906738794805715412356740750890873873435323228244674952180988795091974 844777831874994317609349719963129292674653332785827444869904448205*x^108 - 4 1613159149582603037007821378021268206873842361757130321500129691291418451571 4472352328413744363607247454062853765212695133675510221970937823367502714872 5264869179155436190999803707918965482858909915679294544758294286168029187155 42674704594105656661109974298786084926216*x^107 - 64968550520798695907403393 0416095844971770756779773877908365468264830766792721054670459397639118998550 4854765543268865886038920660387928909044011453689430024047009170672072811027 5782636138143658008315348604258233043465414839888086317182504579245353574551 48087384017967480*x^106 + 10988704303885892826315283975311210242722783884449 6602821133827001873720461030281740372523131562861261636562127194114761297380 7567084209038324237434507186912029498523360122835533024309739840677831689412 3866277910335992520712968840312446267340837533424627065123680989778324*x^105 - 1037769081322395498728280928797930421673181636784651943232652987200370379 9887100753154281880152957110034253066824316513009332837888828809575782813589 8395431699875068691882278140209738486991188655032931569583339555950811469751 14819216369493334147767991300084429910831005417*x^104 + 69810186616581919293 4087787107108500858284600224749854536503416055380938630777674032345768445107 9032740625501338477163577149719360331436837611189692791831261366092124431433 6123841173727343108316374825964917374812406255193704152752318584125714566685 03155908009579048097943*x^103 - 62618742936856051264116083169826991776205278 5386210430790988069604384137878194361389699073225403863192706786752381073990 4629809810678656127043145873535279223707645117591581849318483810783264428888 878968101286898381392510682070079334990623735577742545874102235967038827767* x^102 + 88547713577136747022744956480711506392268841458610902634308115200722 8001393811863713127092848888453031249274119846056297769374759830206187529701 1903856417069237945552069729259203293736154678785007420066778201855082685563 641521979888163226986534911148352808279115809917358*x^101 - 4630158507380629 2388093315791533391137484806668109034703107450628858742143410102799736933423 6907074978067722826731138207487756769203481925052544349731537665931451375605 6491082785764360244007240454153410730447743408991269401214809728107755411693 172395012634341107448006498*x^100 - 1987106430336286502255096633621975778269 2749388116010785359867801694785712027822174277716791024889732874123796999017 1165326722657523135611227287116367063127157679861619224054599116072941563451 0018552431779605085569288059085092991937490866241369045567079522410549051673 8430*x^99 + 6116111486479868423461963851524196927490094772654137109281820240 9655601335862868609893744275312622546677599324483201519748792880440223783865 4698142956751915407410209991596924924552268184253687896341372281276522326101 46924043615114529192462392320461821295874662972625510705*x^98 - 858543407202 8582480876325305001979394403680268817452625497746550339718414937826890236809 6758090513332370728027354524452052318746523877507900393006790670253886201007 7151654142173689494119764321155798594114038476768325934248961469594904974057 82950778627016658691250674749383*x^97 + 490657445429729269017920968754688301 6620517611911217595219014813015157155188541123765870476789021829481317185682 2346556428383215072814614042291152340886085128841976463982340477579191182175 5499560251631802981685749888173758813318700520169103214089237413133223676806 81136483*x^96 + 588480356039113348615320015128938548650997950279831325677040 1070851758771375890193257175605171144175873327958813862484089151772708967824 5090710382325088735952719657758536202632425695397040762304230638936597396706 141037241892685559313526162149365318736429347633086308123732*x^95 - 17860801 0792691455581088588394658008616948993017279794644452692311940825238452683644 2319855428360563553746309477403369295008059059368147822762461583481089204503 0764049052795948146830428753094428042821800841448746792034840653376273350188 2132907610936220993092559868115464848*x^94 + 2080698898949934438755286742414 6744709766506973468237223938818775848985645787102709849630670421667929387077 1839075966340916755041077369098858794090822988106295163721588178394959186872 9508222800790599280424915420728365948473247641413622178547384599468880111768 92625701864148*x^93 - 855864218009308575944636024731111359775112255204531345 0227262959123310950664276060293965525931786616911167403341188615339530286675 6775269831884121745448799689118137607558616438099756213430487533482486835346 075682903923880766231253716972279618549611306311532332784130069552*x^92 - 13 6808840532983525733371616856915983783270410509211401019532102689258560876086 9527424128221769318567475482882108641281228508725452571176264919548871309015 8567261995935441375507973903437038954795573527871968541716126334097932463611 5855437833626026464694567238228672113384692*x^91 + 3083618181674886298656898 1166117178805224503007958449196073139881830099761716540415100166992970870487 3373126707079788137630463247890473378063608477167239399012803238136948080412 0312330266139820196748423629961267609185986608819581540758534872341667324689 62725982670350394704*x^90 - 289813403115309877208771459417444034084104076525 9424539591515173961928303088393009380304940043691096832523560373895822112785 5808066054703063840814273369617911574459101343616657558236169574623914019563 0152780337575962071156042744164046198739767637262303611768624103749962308*x^ 89 + 72613516630962625965473064217525199676649443527570426575481770740043888 6779646591936295747831851104939101651758342323554432645301127945581635380942 7667424563537772502070799105048465507245059623491244896462413185145901940314 5696053808385861551596378474452839548918080875392*x^88 + 2007137579167957439 0719911721927558340943820520648172319420534796396724837614574044411853430783 6722420021463109835306685189533078441109841798470591234934768692554906817588 1207883501035322616933512472492706367178783380343756988188031103657790713917 44233368892636267232901060*x^87 - 341583527690850438763926482860330447741875 4305316360798807536901393938873869395520682617524619723932218997197449552997 7902796418727196784273654618816384850023400797434252298928612530838816162641 9574193744111685493591811397803624718762999077541037470623557200013418602943 344*x^86 + 26018106816532769824515089189721783374074645569591071162155828403 0232272450337410678138897855399057733160129008028400975157648521806369052132 6598794386401757044711814737218799723053160173284842744313272283592926991658 43454191912138368855662104946473338105764358284022377572*x^85 - 285687497537 0233084322274278589877961032877493803575239781590446839383349838850110790540 3648812210524131836405185194224569727115488819662642038492004860753207681555 8064901322408777764393214575140844637199884061193474482510361153824419358509 00211274244171508240172003554579*x^84 - 185573110599032244389576804101570527 0843481327670529736455724859117579642729259313496498283495085435901054470028 2535196961772216663035884293412871166129440632779930980074617184610893507366 8787347778013694399060652311121162557391893749324368007933315027120013043270 445299679*x^83 + 25050117171467230890654410834087578617559538489554781281579 3157881185513898265592143907721703598168076058572348175071967137401886379765 0888321554412070999395502650926168357968511833244292802087783872357923454661 96695362647033860816591741894381954763538781291764410558313991*x^82 - 156624 0805166486574430551541640026858587070051407347684313586931160679067646271535 7829110559493831623647655992465253608722147473274284815377360979913488645232 4593004096825642014547164807256580851492214151707379016954878586353260655456 252800749153240368998676635038282783458*x^81 - 11012223211385811697215073324 1921762613953353874156837170764058477228457541142548719349032469796569578235 3672680465156231420291792630380279912309212851197963260878119761617542365940 8318430631980819407521411635240395800739279192347581702754335107271855384807 48046492479002*x^80 + 111235651556599161905998900669481587907856029607842384 7058721145611490097096177499329308286485980098377201553695581299300616429252 2896328548114223502627261314995818846022537138353738293647104367494387573394 8393580977308270455034395646105894483336815886915572733813700662098*x^79 - 1 2379020348161516025309044646747619580648761934003227421750700116671436042176 9234916272072233533611217288217765756191391217561297135624913793687875324800 7048123566476086580476470670309837456621193106958657582668447487991539286833 57031134988178799550492266664939630915472321*x^78 + 644986875872857655262996 2870357260072805613051355925273289691398310869281737114462536081840128975833 0126180055099077158183624456453836279081213829170321954905360807167962624432 0834840220201004905145194463702511094693925819892194681047038159942946067231 75356042055357536463*x^77 + 632358398592670498095591997355631111077729590643 2790651615164768723582162467454648690012209970035792209695666782959269273807 2446931808206460612526556054521554052793022216016750971388084812894581490191 87488153428597505906544272968607176655503312813518126744417345713254937*x^76 - 4407859464775144416487947396167367671725803977033500362272840558411894622 4142347820758760948628866949429655387790156661766965605123758771588193309114 1713374027265271324050920162934924792826148476476160753572716996003978356956 83804000368513801138734053137773265487620770740*x^75 + 416372459606780296337 1450264046151575655550849081038974416037216542290125884466463363808042083850 9725418382508403123824265992064946980309513636360132567064198384175231861989 9012223863450049443691606628550828159458118620199310401445249248178059313891 70550354597821348040080*x^74 - 184161864081127040151143217561783123125395859 3984003709177376821791781406937773897678496561663900933927169138471529228790 5120635576312602740572720848588646957621039854850944227105781066695720878550 615756344477554232044466772542846688611602947158650463473157163999798684880* x^73 - 294578669269207164351858864041819495442047310529305439637416055593898 7162766090787137613214756965908109965354836546249973970248312691190106013609 0096047571535265598414402965513205463264379299412109566296535132357163168956 32417972107859793797811490919775354115913639814509*x^72 + 116883470301786694 7940105919928790584076295711500240939987022716541425069544597244574520104343 0843831048650119597248348399831622778255382707463446772861932339155184508820 8691492120804327123688321050527154392082194558601074437356409645501206599517 48548591269958013706855735*x^71 - 962337617562843751668517056379887654984035 3607775335999245012386540197534720757701144759975007037123456361469330484819 1315697282222826434358396253666199318705803758613569124925030815057449171128 4560115497697369485081240160416963318875432658639303154335108578568393415001 1*x^70 + 3726752627853214173014791913150187098796942009506244634835348186874 6218248319652489347706949219918369593434279794434225414007742000717921598981 1967637764507611718683775885631603729498673872931482040372125187697058620137 8729901384977948736920393075869570682078658147246402*x^69 + 6664265109721472 5027167403028506905386766457143598965411785702251914095207487701546804662501 9973661173639310250173508615816977744154467727637322113813424769329746934178 2443037607433520297691194068563933234561377974297855282622664908800977935892 66781529161410379918516384*x^68 - 207155588658254864820236483929333843353850 2314782709935428769719703150188593756759875477634107095955930003335004909963 7806096997987389425073233030518177133541278388985086967790086225554199073757 9183726492903476789901947898423219398782945711055270770359481994540571424130 4*x^67 + 1533378023324702195795907021652744267401738630185227412509325644190 9317029060634416164456507736338956677716876820335111092883359676091733924360 7562229802747370137957394804745995747839571913841959663322372004062970960303 2739266325572053308062722007360886556152476819257995*x^66 - 5448017961352466 8954308761386777114515861425568699050923629567132295720176133619693154821070 6679446412666455188970580511515741859257380970964727783399666659463150181605 5832418778533170218818696428046565610812780388008951253152709903494726503303 47825776795872045310257331*x^65 - 782824212320460720852470872605130544762708 5270844370030560427574258798403117425649643063954946491985881365052474110155 1061361746263419716606571746236356433610334478429319747526941053865615635278 723792660268903548758991779230812111021711115289261014249648789576891768349* x^64 + 241834633150739573689757316859489557852802058328995612290604847372968 8962517428202844726500527178649942306770989823832330134459212595922531552449 0113231117621334324551438466322046602200466264537273693298034252254721421676 4952766269941267448422272698762518675998018630028*x^63 - 1666339352730570520 3639407453322817405171376787484109204948738088424073980877086807482951938601 8865103399869046069476520137316208493195695957902129110473449041403464176591 9862359175005557769808809061623387720644388156956972127266850675533756707525 90808120744985654078946*x^62 + 570449220804489887130193887685456156518623172 5938262332193484731157547462002602737462832660959996983966122744124822282431 6513410409807491982186685917971756931992668327222699312497837591559016609364 497532211515388699725043424503916154248093353508075820460159560673674726*x^6 1 + 379845061301619031112865499569621029871812941926085546779444789597593099 2185392685054292994780700584857914762885227739218300244363323904098764703684 3361325604313463057739669057343485520202139735014463468397975802705055082320 02067235766810391945048746973605012517899250*x^60 - 179994905002158006799826 1581248012266767598208187591516407746996243019260988129520947344375845837479 4375473622136858584586366278763492407789131148115802682216654123834671962143 5349323536462397163996997039950567353507544138641982512459740031444726096910 94329488186488560*x^59 + 119982265165997044452636805135365752758447406488957 0849779495733478576958767846719905517427473004995721810584114866176087023280 6873265056291159390228424704274613300367658551594974395489222878733856100659 323368722107547660243619913236809974787583082322603729616639857984*x^58 - 41 4498343303395026162273181308147077705273369693379285169454980456825999696414 1108191789225342382926105642661506635099783996258510012027273821755928691169 8167108483458843302305307979514403727827680023751217095370719902334212472094 52432417836264144119102122277397817768*x^57 + 151296257711150774319086699562 0621904293538949888063494638380250947255821384926730801679647950967103397199 8232664074317796747475932212744662087954481765782241246318995396862540981468 8990486802544852254612284845621149784604770996714678404380352987098024383778 212981782*x^56 + 77172024931648750131579375330854241317819193485030367789630 0194979153932088946756095579709069441269038355362032598061536345375371499825 7603589364289068081989344439616890875432673156016666549955986167393531518011 67940120441305635456765616769010583292909919688853748166*x^55 - 533362214813 2692571383637474154386631336646003027379100089536309803633081806433335487865 3788348099478071550518684140405592181062300213393211342562869431261195244746 4055597603055279266341016276936298547770626014341819185195774706572228813839 188337921892972222814214310*x^54 + 19809672028428641640899800622402763302466 1074260655961612294389483118237887223011979572958763434751014838641676318160 5147310285574152096915663041869066749730025370705253261451722595574825909044 34743256388662636089294615411424475808328353443007431056186153291193660236*x ^53 - 3298236730725312112107997188999732021783635308764336412988146411506139 7104102160872908196077077455976298299221998872649597890835291998156291479044 1156752915907868097785637632834657415730880385603530195196698224915641474164 13441042710366926553820042101416886262527990*x^52 - 101449365782699643760207 3313704763252338242187697491537141888115893684195480412346735267432884547401 4326674844047109008343871306484926351769633249049418818884494773111342516465 1364847880469035878140408781793697844423605606532175548895998431434178111893 10391299541374*x^51 + 997010027853800903810835659831173696396465410573075578 3905356009776229418935908969084901777161285772610734056245264176199983282362 9243150822898802087782083582569387718010137408195023053062329504663705594403 79207927321560114457596629472924327212630999737789491694628*x^50 - 400136364 1205954524277253466159627211505461211798229164611000835355077955105452940106 5043117114065854192422518937652264386811681003511656062957851230278085993229 0192913573475644905186402717704749806127538925050731511982133457968662243173 0574757902251581738927743514*x^49 + 9180213565693093847510479570029388499565 5962139940688297118935762169143151779122206282849955988804045093690808202777 1911618936765072016334219087961215540705432215522135777876375064000492729289 146413824719753030999530625757538495495631483556564886408485696916274754*x^4 8 - 501301210215460642688466550524464459820491039666763299722186435065388308 0998476722426260605286629208716991084876566352805637002187528368901275570021 1644840502467709341605696416994819511376212841122712589602930316113642419950 349056502832731819476610421210838732740*x^47 - 54944298141158889585149685718 7336779616988953202758365462768772698687661348560047998087075022182507327394 7519184487938281971887003668567460606612213622645012761958365390879314022191 3390146402903001771434654731924912308476740943900732699364805260630537589779 248726*x^46 + 26686242659774581832060629132908634079744101584587342617793147 5307484074819549903437909197788777407246096377950996274109900334593209284669 9285933458439326397108293597155087876694426014357663784876151672816297841341 0567270026180297395204928647366053260719567023642*x^45 - 7052486107172135206 1948720744051909520509772591994862049253916379923010961566356969081325001527 6292596993146766741009335610467932996827331500592308883886627814990767499859 2394117000761761120597925240350755933951486120638079133147944601048042610283 120648681977182*x^44 + 12094887988138431717848391295686703675228636456392942 8682928139939229340261144090919567211768947492261796729623549396284079133495 0340419054279131563933305486551030416968393033147914495046708454093512499973 890279938140031139050906270219603864516933692949758319412*x^43 - 13249348861 2052453833911384927269989662957662727807923412036942065407705141769113172260 4562201840504522929158651370739513572711063413085138434059101868053588204820 3501768317607444088231087593813985100365809682458092656030031376932623184206 7770517384807361785676*x^42 + 1335101451287203762576138569495941477971504274 6021839256417498499034598980956043459656243655749784623012085862698394648682 7521666667680743107938078657228707393173302010891133955653957891206671708545 21488797288438881522832497235465398261203063264934026405622216*x^41 - 499475 9281308667412284807719782367452360187792248198012964464639579785518460647882 3014472001994317756006942461078978073213429085061547197216262635883812900592 1762751571689421659752686372945957018076639346750248956405331139984740983345 9224825604519148808410998*x^40 + 2123055922106609642987166390747900882690095 8265815080171818541132693855937048009649851884749195950160943998565872859377 2466719457136622623105718221481729397353928547971338648745934933818733937555 9722029289477935787063071140468460122494931142480075599166922066*x^39 - 5735 6058097105987281579532842451121455107789722350655401468909089438850594255611 7398406496524366947519084716044767896958134185399473668974877433779111152344 5537408221196487932870899207582741017935334684933397499648658504512170298450 81211351675478818348250014*x^38 + 101323645478522769412770862955451494838700 8662851023057079588279613730397359405727823936580260643332082414004528447161 9032650746240307864113277781931187876839372237162972094621638339957461376513 5960868446031017264818726765755631590746592742117108410287162304*x^37 - 1158 2691707749694320983466811601420819483438159197492729367460974781919497846083 2310429882055944418973561703899132956324878554694827218593251972032733158957 9073374625050919799091874768764116278381338067763168272226788014070435497357 3342854568112725548119716*x^36 + 8305639013155526915236550603371532656184411 8485479725403465416008780582431421160189594698593377625798613038172701584227 4206678281269713323953843252700015484543752538426082787722637328521354532797 854400197712614233087564302182567125978130820395479367756272*x^35 - 72553146 6299857240224175450027827480387792541339702494044488085609115659954701904593 4063182032757400157986647557124710638076669642745888083114891044280939887931 1080380921785649390927188469314188121124356596001115383235298455028416330896 607528890361908254*x^34 + 19860798394812096491425064118869331882474934679022 5013755600349219086403728983462588925205132120800514991648137327905331386108 2705026046100093497647310070721575578185071569257102022328094661667732591461 4871110127674403701118049341045392289086401193314942*x^33 - 4504073630957286 8996977652497679946908816176921415580423759147328165686549644634042466661073 3511461352309328969240076472657648713663010059789108519959246932375899814162 7806075361906437084097330297847347043691634727928126429902493759079959944869 550465866*x^32 + 69070920659658480551690757737221770374761684950145185121047 2484618737300993281417864275556465857656908421568917719365815679023157411215 6057258090256560697376971566576951036121500346489928053597706896717897892051 06698965797835172312757476105925970954316*x^31 - 950505499088700807538705994 4852731534709761992249213459182019380991510107647264892021396558868144681611 0662751219780692605034863184825513108322135455467480199290708985357993844600 052787576017748490330946803622885911462082828385374632295839177766961104*x^3 0 + 146871001034451764467214379577713350818960453105454365246878113141243396 2615951663537883759634270986980824512323040156750516514483187596408739659469 9598984366473798855873087478723052705650039925818705324797901096311128210246 360020474709693712139627212*x^29 - 21967157682673292571077015450821069674087 1544590587052875727692154504672915643984006806321437086319058849365052767208 2180148377519601579902888730828514202452285184145954435822512134773040530752 315307032862652438081839581459737476241460047819927741316*x^28 + 25868119256 5279242165718547565481040416951897690007278140339301372610232089805802058986 0750808024571604981879223368087235334407689838584104951724530561739372122119 8951117323168039502216475583876368959953874029365022369810172602125325497095 6445408416*x^27 - 2428059268010321918244811964086129262156487932219116205050 4070649327791508268466838408282079070232219613570494028527410574628542390142 2207371899314254390315983442044698383945383757774385604939274532392556556337 58840387565176697754574091764000708652*x^26 + 228044964584692160131546765047 2366230486843363280069375103638842382972106217168205477299195570432297721283 4433913421328769323459813505283451769698919188569838637736110033080505201432 29246149018773191614239310593408598408683107352357568527200654044*x^25 - 240 6358660663137122033270184955011680904324977408022614274765749948013776439046 4906763369553397919412224096925386397722165397929814334230617641557808733911 0574280678118160005286224756835902809740658092872319513670690482675603106255 535345368222072*x^24 + 17662623687632442866313848276740533318473562530568602 6085380981148726634500393960831149553262597329458902932994016704916196167706 1802977969263820447192793617562366039417910781021352992596284460784056551089 2584667589514772071439777359014056460388*x^23 - 1017233748361584303945573233 3032677102808866261456706104325822118295706056417248083910297875201722536975 2472365095568346621934137039403008509886158851525905826470428214804919613199 4864749556380390451533567703437432891192535285335888731490497100*x^22 + 6962 4456632649901142038343508876142609309013148113719161965752973745996685396900 6242981394546059022035086880100336674301708003625923297490632324135942177919 6475754925837957964115788320422751182797666627301620661963625816748809270833 0371586416*x^21 - 5935499297476735425457730389595586123363077244239039067258 8757027689826646450579634779345685940054648366379750425264531723684895242726 1296842788479967443307602969542957303586075752713784702233094467073009888400 4709831827016377193151480549079*x^20 - 9924231276887632055264945002835855931 6153619298064184888082607712523327637455849379369518935749807342918090562216 3515240369483362753072379694694969114717331800146736581921176222284191504989 22256734920743781356158658426818610320388361445943*x^19 - 223034910041976985 5872625998444601823522405237422212480311276936526222907234872314934718146257 7999956125097315186127418244514895084164378747477418159356551630505131305135 965903638935951781824035858082445936492127698502477328282539866049529*x^18 - 236643075076678358536974434180237346813030211220576398492261042505158468477 4245106684856714329733460194522211899691204030539339797067532556065266564996 8995125799175143049170891303055998502994776437035748429866958228412329271509 6914727786*x^17 + 2542147127057127485965235153724151047113766830500853009593 4057432271073053439213859505464662101818485064985498169276132525055092922810 7659183430955698520972071635491614118402866501132808889569521209673251362824 76709756655755991836417802*x^16 + 183111149787713493280210397619912322103096 5247871179773154030195420556994309371058325110985700072545919333159157805938 6224014037352998052003315867311050614119923950889255536852768279112155091364 24174340648729576596630358137790527045198*x^15 - 449821041069912943789836264 5632599818971731559621159648780555694409049475593695526598586098851324811318 2519341945707916157927951713037252573987087918917682037480599453640794209186 225479459166338434922942612532823032751347335799704869*x^14 - 22982911151946 0414712287398340054262339910173840391365052883789755652220150460120847132485 5387525455121237089427182900348837425717452397567606502432587339063493335218 99975599619910693111772391894198334123224235975702158966025975889*x^13 + 425 1167449102860417605682557582269062328643891986101063790164447568501066388281 7083671619051397999677516644732430950231634364346445730340715448369087696718 20523719962939869299988336933823914482320626610429276999595557594057384713*x ^12 - 2634769415254884935578685134629261396873246071233388299830258283684407 2876185708249044979665212650744995875688959242932243838420517823860588878429 2448997291893491640954677331782979368685632076417137547307030222199889038379 76940*x^11 - 178196131047104477494733878949091986680056821951080835036094383 8004052330411696017910506157765585633940095861000688753523141138483928490467 4511256960034750139170510478764583267207761340591670181326537548133703111264 9106926204*x^10 + 1825000405670995013845885918902187142186986666482440933839 6462521386957836588377301330171147216240982523247505481312286617417272521511 8638399348219471080155689525455946137646839420547370091703312293991788729921 1491191185252*x^9 - 65201626996640512322761674559318066561117950070675294766 3169824762769899024352909587195016688965354038529484926750838814982572946010 1979637110489360349176312329919783316622660007379629280095704481299477431710 45016069129*x^8 - 1437891149083999662420144342263678250208894256538560561654 8933951961391248431401653150798776891480895285823868174684751112400557598552 7985918610201118598268431458892734242196304467884366814923258790382419891488 25558929*x^7 - 1428280930363758251384969101052572662110879466805595758704451 0527911033933582902662199662263051097627055254401259144549052189981714948608 3243967370749726951525986876271444939969618263711803265644040382245363794511 71*x^6 - 1170826372197459055177820600881979710066693446685651498813175990981 0745762172031150515086932467894419392120220600061432329279936873889655682224 7191725072125442393957901078704198243471395495180025340969870794174*x^5 - 11 8223168675776843350634299306552668061864957826207103017499838634433318705119 3832689526795798631026606743575718322278065328528551578753575871762638217620 241416850427234233281589721441720700844787815627946*x^4 - 953048457007008296 1795451881320794184817199918350969024576327248906812630041977334151670173523 3419849726478663631547211301749427543946011643243124123502481796513891248511 161398944690550172434214114*x^3 - 254706791524256177472181318251041912950779 4390935955929617768730635253624759862293118182940797954335902313821207678848 027543595348285081414397619295455292216447729433614628265514361363667915*x^2 + 7114590568532928191072122754665584122789751912529693393245247725975835948 7615527828928204048113*x - 1 x^240 + (-15*y - 36)*x^239 + (499*y + 430)*x^238 + (-6344*y - 983)*x^237 + ( 35389*y - 20411)*x^236 + (-40904*y + 178707)*x^235 + (-424808*y - 438197)*x^ 234 + (1415485*y - 635208)*x^233 + (1438139*y + 2974605)*x^232 + (-5864817*y + 6566480)*x^231 + (-25462020*y - 12961894)*x^230 + (19238389*y - 79956654) *x^229 + (247313433*y - 30224897)*x^228 + (294927621*y + 801098945)*x^227 + (-2353679384*y + 1069498319)*x^226 + (-3266832488*y - 5793469739)*x^225 + (1 2761071756*y - 10152009124)*x^224 + (28891772141*y + 27706877778)*x^223 + (- 56780498004*y + 70327470888)*x^222 + (-156989267296*y - 100643285180)*x^221 + (163182970660*y - 341901790078)*x^220 + (692925090103*y + 282970748175)*x^ 219 + (-520851483678*y + 1249500770581)*x^218 + (-2100987167651*y - 97780636 3155)*x^217 + (2144907137575*y - 3501192827999)*x^216 + (5741131351957*y + 5 368774573391)*x^215 + (-12949633488740*y + 9667592872104)*x^214 + (-18978818 705192*y - 28988343801763)*x^213 + (61143701295650*y - 42854297857883)*x^212 + (99522339968066*y + 118416217970085)*x^211 + (-203990291010201*y + 226088 796680855)*x^210 + (-487486417978576*y - 306059642167156)*x^209 + (371437987 605861*y - 969565907346414)*x^208 + (1761877237395113*y + 250996844693464)*x ^207 + (347587448455796*y + 2909203449118066)*x^206 + (-4262623171412271*y + 1900082482875272)*x^205 + (-5112561845313059*y - 5258998337190094)*x^204 + (4703077156935772*y - 10817923562329066)*x^203 + (19596724151621886*y + 4579 71706716061)*x^202 + (10779811934500297*y + 31310302362591686)*x^201 + (-444 71188376651271*y + 33091705261026148)*x^200 + (-70367728073948453*y - 553681 43890230595)*x^199 + (58047935399898944*y - 125056052810735004)*x^198 + (196 220179915190037*y + 46078797156864550)*x^197 + (-15612945533449050*y + 27845 2806220656846)*x^196 + (-364966710997667886*y + 30164046307811567)*x^195 + ( -76920393658091100*y - 455669527002677921)*x^194 + (569724473209147360*y - 1 04273935104641941)*x^193 + (107554480539021407*y + 761016430421970356)*x^192 + (-1120756441763956820*y + 138805435659787599)*x^191 + (-36744368496876235 9*y - 1741313178847717412)*x^190 + (2626931562224608194*y - 1142827140366519 672)*x^189 + (3001549496003468616*y + 3542726921147289593)*x^188 + (-3816304 655625513057*y + 6563685064488706687)*x^187 + (-12280102244383760786*y - 216 9956083918876046)*x^186 + (-3280308295039992672*y - 20013773166146345265)*x^ 185 + (28534969871679714183*y - 14758677431499660732)*x^184 + (3420538527727 7312731*y + 35129207175233160758)*x^183 + (-35562575528916824663*y + 6232129 2808100809456)*x^182 + (-97526968113689340266*y - 24577168539715006795)*x^18 1 + (-2924482708853224503*y - 135200656059538396115)*x^180 + (16755988046047 3073606*y - 50231770182088582728)*x^179 + (117217186558944665294*y + 1844313 16627662099968)*x^178 + (-175018700423712057769*y + 199325075624692888658)*x ^177 + (-287672838056258651793*y - 130006789216819808906)*x^176 + (433136887 58928043819*y - 370488386653834436323)*x^175 + (435685264104825475131*y - 87 230951613648934063)*x^174 + (260789110179489506909*y + 473346146286012258862 )*x^173 + (-477453708065915165092*y + 475828532275903297714)*x^172 + (-73312 5023480253537968*y - 445824632107486741239)*x^171 + (377925441616168009977*y - 1037951764481934863694)*x^170 + (1401192440853964064557*y + 2712041812199 21501426)*x^169 + (-116817470274758714683*y + 1837817520966021102844)*x^168 + (-2362860273074857968126*y + 103875680474127044027)*x^167 + (-421763202246 558569481*y - 2985437596461812106201)*x^166 + (3701454711020661872373*y - 87 8419497758685431399)*x^165 + (1521006793930665203185*y + 4486769840934475059 679)*x^164 + (-5292413186031800428648*y + 2393646591871321675898)*x^163 + (- 3527560907713404811933*y - 6046342849737077241029)*x^162 + (6659475347960239 461641*y - 4934471883467342725819)*x^161 + (6606218484397706362957*y + 70346 33694928572084799)*x^160 + (-7071251229918632950519*y + 85221454139378375409 88)*x^159 + (-10654172673396879304988*y - 6660938661086516468010)*x^158 + (5 677741559220425296264*y - 12963319200223537566424)*x^157 + (1537868439480061 5926642*y + 3975042669473795569897)*x^156 + (-1409491575820818236069*y + 177 68498236629148702410)*x^155 + (-19928654122136236656860*y + 2108177954625221 499359)*x^154 + (-6549200784773657451762*y - 21617243705895522615660)*x^153 + (22645379524677683996954*y - 11738628703873244299229)*x^152 + (17408053637 884918322314*y + 22982504260819896781381)*x^151 + (-22809630522578701355929* y + 23340226072231874490562)*x^150 + (-29550558164952915082604*y - 224392369 77615542871417)*x^149 + (22094525765620020809639*y - 36386527353264595233550 )*x^148 + (44442209345887020103552*y + 21630493829993114594971)*x^147 + (-20 362621509381561401708*y + 54254830555411448139989)*x^146 + (-659133869795653 69752671*y - 17161940478911028975987)*x^145 + (10842803083053018739937*y - 7 8798826823995559998884)*x^144 + (91671114659094334230114*y + 699010605156960 463896)*x^143 + (13121977610624125288643*y + 103143317388027280663819)*x^142 + (-112336281183122778011108*y + 29666952173920616332098)*x^141 + (-4771339 6391497944676658*y - 119352040791078382516354)*x^140 + (12522214489937288097 8343*y - 66535424263344578690303)*x^139 + (86443391588395703449231*y + 13128 8792905554584140170)*x^138 + (-138308631379146285689943*y + 1087117764446364 01209940)*x^137 + (-134836856528001466894586*y - 145826834678543169365085)*x ^136 + (152261003156819774060466*y - 165525545074570372890946)*x^135 + (2000 19883617103704090631*y + 155735524429003454571137)*x^134 + (-155214006426713 875482591*y + 236255888142978579163439)*x^133 + (-271843213937284128310312*y - 151199785544397594300869)*x^132 + (145501652264843306972923*y - 305326875 506321100258855)*x^131 + (336932852565943631529246*y + 140097781638111061499 104)*x^130 + (-135773050794564515416176*y + 368242715265481945864410)*x^129 + (-400908655930869378612741*y - 131401561676926670933942)*x^128 + (12442649 3872813948801626*y - 435145712814328666799539)*x^127 + (46899879143136708390 7400*y + 112351662733835870233203)*x^126 + (-94381628626117531492779*y + 498 937937395927788353831)*x^125 + (-521540559152841029573809*y - 72188367562634 255595303)*x^124 + (49231480359271694594387*y - 535280543629519838165745)*x^ 123 + (541321200409785903521904*y + 28961946371400127296768)*x^122 + (-12936 229773088822436824*y + 542775176498979507958864)*x^121 - 5428178716207228568 54615*y*x^120 + (-12936229773088822436824*y - 542775176498979507958864)*x^11 9 + (541321200409785903521904*y - 28961946371400127296768)*x^118 + (49231480 359271694594387*y + 535280543629519838165745)*x^117 + (-52154055915284102957 3809*y + 72188367562634255595303)*x^116 + (-94381628626117531492779*y - 4989 37937395927788353831)*x^115 + (468998791431367083907400*y - 1123516627338358 70233203)*x^114 + (124426493872813948801626*y + 435145712814328666799539)*x^ 113 + (-400908655930869378612741*y + 131401561676926670933942)*x^112 + (-135 773050794564515416176*y - 368242715265481945864410)*x^111 + (336932852565943 631529246*y - 140097781638111061499104)*x^110 + (145501652264843306972923*y + 305326875506321100258855)*x^109 + (-271843213937284128310312*y + 151199785 544397594300869)*x^108 + (-155214006426713875482591*y - 23625588814297857916 3439)*x^107 + (200019883617103704090631*y - 155735524429003454571137)*x^106 + (152261003156819774060466*y + 165525545074570372890946)*x^105 + (-13483685 6528001466894586*y + 145826834678543169365085)*x^104 + (-1383086313791462856 89943*y - 108711776444636401209940)*x^103 + (86443391588395703449231*y - 131 288792905554584140170)*x^102 + (125222144899372880978343*y + 665354242633445 78690303)*x^101 + (-47713396391497944676658*y + 119352040791078382516354)*x^ 100 + (-112336281183122778011108*y - 29666952173920616332098)*x^99 + (131219 77610624125288643*y - 103143317388027280663819)*x^98 + (91671114659094334230 114*y - 699010605156960463896)*x^97 + (10842803083053018739937*y + 787988268 23995559998884)*x^96 + (-65913386979565369752671*y + 17161940478911028975987 )*x^95 + (-20362621509381561401708*y - 54254830555411448139989)*x^94 + (4444 2209345887020103552*y - 21630493829993114594971)*x^93 + (2209452576562002080 9639*y + 36386527353264595233550)*x^92 + (-29550558164952915082604*y + 22439 236977615542871417)*x^91 + (-22809630522578701355929*y - 2334022607223187449 0562)*x^90 + (17408053637884918322314*y - 22982504260819896781381)*x^89 + (2 2645379524677683996954*y + 11738628703873244299229)*x^88 + (-654920078477365 7451762*y + 21617243705895522615660)*x^87 + (-19928654122136236656860*y - 21 08177954625221499359)*x^86 + (-1409491575820818236069*y - 177684982366291487 02410)*x^85 + (15378684394800615926642*y - 3975042669473795569897)*x^84 + (5 677741559220425296264*y + 12963319200223537566424)*x^83 + (-1065417267339687 9304988*y + 6660938661086516468010)*x^82 + (-7071251229918632950519*y - 8522 145413937837540988)*x^81 + (6606218484397706362957*y - 703463369492857208479 9)*x^80 + (6659475347960239461641*y + 4934471883467342725819)*x^79 + (-35275 60907713404811933*y + 6046342849737077241029)*x^78 + (-529241318603180042864 8*y - 2393646591871321675898)*x^77 + (1521006793930665203185*y - 44867698409 34475059679)*x^76 + (3701454711020661872373*y + 878419497758685431399)*x^75 + (-421763202246558569481*y + 2985437596461812106201)*x^74 + (-2362860273074 857968126*y - 103875680474127044027)*x^73 + (-116817470274758714683*y - 1837 817520966021102844)*x^72 + (1401192440853964064557*y - 271204181219921501426 )*x^71 + (377925441616168009977*y + 1037951764481934863694)*x^70 + (-7331250 23480253537968*y + 445824632107486741239)*x^69 + (-477453708065915165092*y - 475828532275903297714)*x^68 + (260789110179489506909*y - 473346146286012258 862)*x^67 + (435685264104825475131*y + 87230951613648934063)*x^66 + (4331368 8758928043819*y + 370488386653834436323)*x^65 + (-287672838056258651793*y + 130006789216819808906)*x^64 + (-175018700423712057769*y - 199325075624692888 658)*x^63 + (117217186558944665294*y - 184431316627662099968)*x^62 + (167559 880460473073606*y + 50231770182088582728)*x^61 + (-2924482708853224503*y + 1 35200656059538396115)*x^60 + (-97526968113689340266*y + 24577168539715006795 )*x^59 + (-35562575528916824663*y - 62321292808100809456)*x^58 + (3420538527 7277312731*y - 35129207175233160758)*x^57 + (28534969871679714183*y + 147586 77431499660732)*x^56 + (-3280308295039992672*y + 20013773166146345265)*x^55 + (-12280102244383760786*y + 2169956083918876046)*x^54 + (-38163046556255130 57*y - 6563685064488706687)*x^53 + (3001549496003468616*y - 3542726921147289 593)*x^52 + (2626931562224608194*y + 1142827140366519672)*x^51 + (-367443684 968762359*y + 1741313178847717412)*x^50 + (-1120756441763956820*y - 13880543 5659787599)*x^49 + (107554480539021407*y - 761016430421970356)*x^48 + (56972 4473209147360*y + 104273935104641941)*x^47 + (-76920393658091100*y + 4556695 27002677921)*x^46 + (-364966710997667886*y - 30164046307811567)*x^45 + (-156 12945533449050*y - 278452806220656846)*x^44 + (196220179915190037*y - 460787 97156864550)*x^43 + (58047935399898944*y + 125056052810735004)*x^42 + (-7036 7728073948453*y + 55368143890230595)*x^41 + (-44471188376651271*y - 33091705 261026148)*x^40 + (10779811934500297*y - 31310302362591686)*x^39 + (19596724 151621886*y - 457971706716061)*x^38 + (4703077156935772*y + 1081792356232906 6)*x^37 + (-5112561845313059*y + 5258998337190094)*x^36 + (-4262623171412271 *y - 1900082482875272)*x^35 + (347587448455796*y - 2909203449118066)*x^34 + (1761877237395113*y - 250996844693464)*x^33 + (371437987605861*y + 969565907 346414)*x^32 + (-487486417978576*y + 306059642167156)*x^31 + (-2039902910102 01*y - 226088796680855)*x^30 + (99522339968066*y - 118416217970085)*x^29 + ( 61143701295650*y + 42854297857883)*x^28 + (-18978818705192*y + 2898834380176 3)*x^27 + (-12949633488740*y - 9667592872104)*x^26 + (5741131351957*y - 5368 774573391)*x^25 + (2144907137575*y + 3501192827999)*x^24 + (-2100987167651*y + 977806363155)*x^23 + (-520851483678*y - 1249500770581)*x^22 + (6929250901 03*y - 282970748175)*x^21 + (163182970660*y + 341901790078)*x^20 + (-1569892 67296*y + 100643285180)*x^19 + (-56780498004*y - 70327470888)*x^18 + (288917 72141*y - 27706877778)*x^17 + (12761071756*y + 10152009124)*x^16 + (-3266832 488*y + 5793469739)*x^15 + (-2353679384*y - 1069498319)*x^14 + (294927621*y - 801098945)*x^13 + (247313433*y + 30224897)*x^12 + (19238389*y + 79956654)* x^11 + (-25462020*y + 12961894)*x^10 + (-5864817*y - 6566480)*x^9 + (1438139 *y - 2974605)*x^8 + (1415485*y + 635208)*x^7 + (-424808*y + 438197)*x^6 + (- 40904*y - 178707)*x^5 + (35389*y + 20411)*x^4 + (-6344*y + 983)*x^3 + (499*y - 430)*x^2 + (-15*y + 36)*x - 1 x^3 + (-y - 1)*x^2 + (y - 2)*x + 1 x^6 + (-y - 1)*x^5 + (y - 2)*x^4 + 5*x^3 + (-y - 1)*x^2 + (y - 2)*x + 1 x^15 + (-13*y - 28)*x^14 + (-35*y + 71)*x^13 + (-96*y + 193)*x^12 + (-5*y - 196)*x^11 + (-239*y - 365)*x^10 + (120*y + 1489)*x^9 + (-261*y - 2084)*x^8 + (-261*y + 2345)*x^7 + (120*y - 1609)*x^6 + (-239*y + 604)*x^5 + (-5*y + 201 )*x^4 + (-96*y - 97)*x^3 + (-35*y - 36)*x^2 + (-13*y + 41)*x - 1 x^64 - 2869316*y*x^63 - 14321320456*x^62 + 157634598028*y*x^61 - 20284120752 9344*x^60 - 187341502817748*y*x^59 + 42513677421330536*x^58 + 89659277585427 48*y*x^57 - 581758105735037800*x^56 - 22856296353162116*y*x^55 - 17452945591 56518504*x^54 - 264489521649865972*y*x^53 + 3806496834205999360*x^52 - 74814 8105793479444*y*x^51 + 34464709754552397448*x^50 - 807085220707689700*y*x^49 + 112558678351798157916*x^48 + 885683152130937644*y*x^47 + 3063853398816684 17048*x^46 + 13203419547826420924*y*x^45 + 419863456051485069824*x^44 + 3434 3465258453402972*y*x^43 + 465608689069031605064*x^42 + 80309592889200941068* y*x^41 - 360175722030581287640*x^40 + 110486596140091600940*y*x^39 - 1490512 424563931678536*x^38 + 143957811491089032572*y*x^37 - 3739364774219046032256 *x^36 + 100323919847689168220*y*x^35 - 4985975135633301110936*x^34 + 5481611 3881156185292*y*x^33 - 6135008383051601995834*x^32 - 54816113881156185292*y* x^31 - 4985975135633301110936*x^30 - 100323919847689168220*y*x^29 - 37393647 74219046032256*x^28 - 143957811491089032572*y*x^27 - 1490512424563931678536* x^26 - 110486596140091600940*y*x^25 - 360175722030581287640*x^24 - 803095928 89200941068*y*x^23 + 465608689069031605064*x^22 - 34343465258453402972*y*x^2 1 + 419863456051485069824*x^20 - 13203419547826420924*y*x^19 + 3063853398816 68417048*x^18 - 885683152130937644*y*x^17 + 112558678351798157916*x^16 + 807 085220707689700*y*x^15 + 34464709754552397448*x^14 + 748148105793479444*y*x^ 13 + 3806496834205999360*x^12 + 264489521649865972*y*x^11 - 1745294559156518 504*x^10 + 22856296353162116*y*x^9 - 581758105735037800*x^8 - 89659277585427 48*y*x^7 + 42513677421330536*x^6 + 187341502817748*y*x^5 - 202841207529344*x ^4 - 157634598028*y*x^3 - 14321320456*x^2 + 2869316*y*x + 1 x^21 + (-13*y - 229)*x^20 + (234*y - 100)*x^19 + (-480*y + 8370)*x^18 + (-17 35*y - 16719)*x^17 + (4913*y - 7834)*x^16 + (-2688*y + 51064)*x^15 + (-3960* y - 34104)*x^14 + (1782*y - 32956)*x^13 + (8448*y + 5262)*x^12 + (-6380*y + 97204)*x^11 + (-6380*y - 90824)*x^10 + (8448*y - 13710)*x^9 + (1782*y + 3117 4)*x^8 + (-3960*y + 38064)*x^7 + (-2688*y - 48376)*x^6 + (4913*y + 2921)*x^5 + (-1735*y + 18454)*x^4 + (-480*y - 7890)*x^3 + (234*y - 134)*x^2 + (-13*y + 242)*x - 1 x^6 - 2*y*x^5 + (-y - 7)*x^4 - 4*x^3 + (y - 8)*x^2 + (2*y - 2)*x + 1 x^240 + (-15*y - 36)*x^239 + (499*y + 430)*x^238 + (-6344*y - 983)*x^237 + ( 35389*y - 20411)*x^236 + (-40904*y + 178707)*x^235 + (-424808*y - 438197)*x^ 234 + (1415485*y - 635208)*x^233 + (1438139*y + 2974605)*x^232 + (-5864817*y + 6566480)*x^231 + (-25462020*y - 12961894)*x^230 + (19238389*y - 79956654) *x^229 + (247313433*y - 30224897)*x^228 + (294927621*y + 801098945)*x^227 + (-2353679384*y + 1069498319)*x^226 + (-3266832488*y - 5793469739)*x^225 + (1 2761071756*y - 10152009124)*x^224 + (28891772141*y + 27706877778)*x^223 + (- 56780498004*y + 70327470888)*x^222 + (-156989267296*y - 100643285180)*x^221 + (163182970660*y - 341901790078)*x^220 + (692925090103*y + 282970748175)*x^ 219 + (-520851483678*y + 1249500770581)*x^218 + (-2100987167651*y - 97780636 3155)*x^217 + (2144907137575*y - 3501192827999)*x^216 + (5741131351957*y + 5 368774573391)*x^215 + (-12949633488740*y + 9667592872104)*x^214 + (-18978818 705192*y - 28988343801763)*x^213 + (61143701295650*y - 42854297857883)*x^212 + (99522339968066*y + 118416217970085)*x^211 + (-203990291010201*y + 226088 796680855)*x^210 + (-487486417978576*y - 306059642167156)*x^209 + (371437987 605861*y - 969565907346414)*x^208 + (1761877237395113*y + 250996844693464)*x ^207 + (347587448455796*y + 2909203449118066)*x^206 + (-4262623171412271*y + 1900082482875272)*x^205 + (-5112561845313059*y - 5258998337190094)*x^204 + (4703077156935772*y - 10817923562329066)*x^203 + (19596724151621886*y + 4579 71706716061)*x^202 + (10779811934500297*y + 31310302362591686)*x^201 + (-444 71188376651271*y + 33091705261026148)*x^200 + (-70367728073948453*y - 553681 43890230595)*x^199 + (58047935399898944*y - 125056052810735004)*x^198 + (196 220179915190037*y + 46078797156864550)*x^197 + (-15612945533449050*y + 27845 2806220656846)*x^196 + (-364966710997667886*y + 30164046307811567)*x^195 + ( -76920393658091100*y - 455669527002677921)*x^194 + (569724473209147360*y - 1 04273935104641941)*x^193 + (107554480539021407*y + 761016430421970356)*x^192 + (-1120756441763956820*y + 138805435659787599)*x^191 + (-36744368496876235 9*y - 1741313178847717412)*x^190 + (2626931562224608194*y - 1142827140366519 672)*x^189 + (3001549496003468616*y + 3542726921147289593)*x^188 + (-3816304 655625513057*y + 6563685064488706687)*x^187 + (-12280102244383760786*y - 216 9956083918876046)*x^186 + (-3280308295039992672*y - 20013773166146345265)*x^ 185 + (28534969871679714183*y - 14758677431499660732)*x^184 + (3420538527727 7312731*y + 35129207175233160758)*x^183 + (-35562575528916824663*y + 6232129 2808100809456)*x^182 + (-97526968113689340266*y - 24577168539715006795)*x^18 1 + (-2924482708853224503*y - 135200656059538396115)*x^180 + (16755988046047 3073606*y - 50231770182088582728)*x^179 + (117217186558944665294*y + 1844313 16627662099968)*x^178 + (-175018700423712057769*y + 199325075624692888658)*x ^177 + (-287672838056258651793*y - 130006789216819808906)*x^176 + (433136887 58928043819*y - 370488386653834436323)*x^175 + (435685264104825475131*y - 87 230951613648934063)*x^174 + (260789110179489506909*y + 473346146286012258862 )*x^173 + (-477453708065915165092*y + 475828532275903297714)*x^172 + (-73312 5023480253537968*y - 445824632107486741239)*x^171 + (377925441616168009977*y - 1037951764481934863694)*x^170 + (1401192440853964064557*y + 2712041812199 21501426)*x^169 + (-116817470274758714683*y + 1837817520966021102844)*x^168 + (-2362860273074857968126*y + 103875680474127044027)*x^167 + (-421763202246 558569481*y - 2985437596461812106201)*x^166 + (3701454711020661872373*y - 87 8419497758685431399)*x^165 + (1521006793930665203185*y + 4486769840934475059 679)*x^164 + (-5292413186031800428648*y + 2393646591871321675898)*x^163 + (- 3527560907713404811933*y - 6046342849737077241029)*x^162 + (6659475347960239 461641*y - 4934471883467342725819)*x^161 + (6606218484397706362957*y + 70346 33694928572084799)*x^160 + (-7071251229918632950519*y + 85221454139378375409 88)*x^159 + (-10654172673396879304988*y - 6660938661086516468010)*x^158 + (5 677741559220425296264*y - 12963319200223537566424)*x^157 + (1537868439480061 5926642*y + 3975042669473795569897)*x^156 + (-1409491575820818236069*y + 177 68498236629148702410)*x^155 + (-19928654122136236656860*y + 2108177954625221 499359)*x^154 + (-6549200784773657451762*y - 21617243705895522615660)*x^153 + (22645379524677683996954*y - 11738628703873244299229)*x^152 + (17408053637 884918322314*y + 22982504260819896781381)*x^151 + (-22809630522578701355929* y + 23340226072231874490562)*x^150 + (-29550558164952915082604*y - 224392369 77615542871417)*x^149 + (22094525765620020809639*y - 36386527353264595233550 )*x^148 + (44442209345887020103552*y + 21630493829993114594971)*x^147 + (-20 362621509381561401708*y + 54254830555411448139989)*x^146 + (-659133869795653 69752671*y - 17161940478911028975987)*x^145 + (10842803083053018739937*y - 7 8798826823995559998884)*x^144 + (91671114659094334230114*y + 699010605156960 463896)*x^143 + (13121977610624125288643*y + 103143317388027280663819)*x^142 + (-112336281183122778011108*y + 29666952173920616332098)*x^141 + (-4771339 6391497944676658*y - 119352040791078382516354)*x^140 + (12522214489937288097 8343*y - 66535424263344578690303)*x^139 + (86443391588395703449231*y + 13128 8792905554584140170)*x^138 + (-138308631379146285689943*y + 1087117764446364 01209940)*x^137 + (-134836856528001466894586*y - 145826834678543169365085)*x ^136 + (152261003156819774060466*y - 165525545074570372890946)*x^135 + (2000 19883617103704090631*y + 155735524429003454571137)*x^134 + (-155214006426713 875482591*y + 236255888142978579163439)*x^133 + (-271843213937284128310312*y - 151199785544397594300869)*x^132 + (145501652264843306972923*y - 305326875 506321100258855)*x^131 + (336932852565943631529246*y + 140097781638111061499 104)*x^130 + (-135773050794564515416176*y + 368242715265481945864410)*x^129 + (-400908655930869378612741*y - 131401561676926670933942)*x^128 + (12442649 3872813948801626*y - 435145712814328666799539)*x^127 + (46899879143136708390 7400*y + 112351662733835870233203)*x^126 + (-94381628626117531492779*y + 498 937937395927788353831)*x^125 + (-521540559152841029573809*y - 72188367562634 255595303)*x^124 + (49231480359271694594387*y - 535280543629519838165745)*x^ 123 + (541321200409785903521904*y + 28961946371400127296768)*x^122 + (-12936 229773088822436824*y + 542775176498979507958864)*x^121 - 5428178716207228568 54615*y*x^120 + (-12936229773088822436824*y - 542775176498979507958864)*x^11 9 + (541321200409785903521904*y - 28961946371400127296768)*x^118 + (49231480 359271694594387*y + 535280543629519838165745)*x^117 + (-52154055915284102957 3809*y + 72188367562634255595303)*x^116 + (-94381628626117531492779*y - 4989 37937395927788353831)*x^115 + (468998791431367083907400*y - 1123516627338358 70233203)*x^114 + (124426493872813948801626*y + 435145712814328666799539)*x^ 113 + (-400908655930869378612741*y + 131401561676926670933942)*x^112 + (-135 773050794564515416176*y - 368242715265481945864410)*x^111 + (336932852565943 631529246*y - 140097781638111061499104)*x^110 + (145501652264843306972923*y + 305326875506321100258855)*x^109 + (-271843213937284128310312*y + 151199785 544397594300869)*x^108 + (-155214006426713875482591*y - 23625588814297857916 3439)*x^107 + (200019883617103704090631*y - 155735524429003454571137)*x^106 + (152261003156819774060466*y + 165525545074570372890946)*x^105 + (-13483685 6528001466894586*y + 145826834678543169365085)*x^104 + (-1383086313791462856 89943*y - 108711776444636401209940)*x^103 + (86443391588395703449231*y - 131 288792905554584140170)*x^102 + (125222144899372880978343*y + 665354242633445 78690303)*x^101 + (-47713396391497944676658*y + 119352040791078382516354)*x^ 100 + (-112336281183122778011108*y - 29666952173920616332098)*x^99 + (131219 77610624125288643*y - 103143317388027280663819)*x^98 + (91671114659094334230 114*y - 699010605156960463896)*x^97 + (10842803083053018739937*y + 787988268 23995559998884)*x^96 + (-65913386979565369752671*y + 17161940478911028975987 )*x^95 + (-20362621509381561401708*y - 54254830555411448139989)*x^94 + (4444 2209345887020103552*y - 21630493829993114594971)*x^93 + (2209452576562002080 9639*y + 36386527353264595233550)*x^92 + (-29550558164952915082604*y + 22439 236977615542871417)*x^91 + (-22809630522578701355929*y - 2334022607223187449 0562)*x^90 + (17408053637884918322314*y - 22982504260819896781381)*x^89 + (2 2645379524677683996954*y + 11738628703873244299229)*x^88 + (-654920078477365 7451762*y + 21617243705895522615660)*x^87 + (-19928654122136236656860*y - 21 08177954625221499359)*x^86 + (-1409491575820818236069*y - 177684982366291487 02410)*x^85 + (15378684394800615926642*y - 3975042669473795569897)*x^84 + (5 677741559220425296264*y + 12963319200223537566424)*x^83 + (-1065417267339687 9304988*y + 6660938661086516468010)*x^82 + (-7071251229918632950519*y - 8522 145413937837540988)*x^81 + (6606218484397706362957*y - 703463369492857208479 9)*x^80 + (6659475347960239461641*y + 4934471883467342725819)*x^79 + (-35275 60907713404811933*y + 6046342849737077241029)*x^78 + (-529241318603180042864 8*y - 2393646591871321675898)*x^77 + (1521006793930665203185*y - 44867698409 34475059679)*x^76 + (3701454711020661872373*y + 878419497758685431399)*x^75 + (-421763202246558569481*y + 2985437596461812106201)*x^74 + (-2362860273074 857968126*y - 103875680474127044027)*x^73 + (-116817470274758714683*y - 1837 817520966021102844)*x^72 + (1401192440853964064557*y - 271204181219921501426 )*x^71 + (377925441616168009977*y + 1037951764481934863694)*x^70 + (-7331250 23480253537968*y + 445824632107486741239)*x^69 + (-477453708065915165092*y - 475828532275903297714)*x^68 + (260789110179489506909*y - 473346146286012258 862)*x^67 + (435685264104825475131*y + 87230951613648934063)*x^66 + (4331368 8758928043819*y + 370488386653834436323)*x^65 + (-287672838056258651793*y + 130006789216819808906)*x^64 + (-175018700423712057769*y - 199325075624692888 658)*x^63 + (117217186558944665294*y - 184431316627662099968)*x^62 + (167559 880460473073606*y + 50231770182088582728)*x^61 + (-2924482708853224503*y + 1 35200656059538396115)*x^60 + (-97526968113689340266*y + 24577168539715006795 )*x^59 + (-35562575528916824663*y - 62321292808100809456)*x^58 + (3420538527 7277312731*y - 35129207175233160758)*x^57 + (28534969871679714183*y + 147586 77431499660732)*x^56 + (-3280308295039992672*y + 20013773166146345265)*x^55 + (-12280102244383760786*y + 2169956083918876046)*x^54 + (-38163046556255130 57*y - 6563685064488706687)*x^53 + (3001549496003468616*y - 3542726921147289 593)*x^52 + (2626931562224608194*y + 1142827140366519672)*x^51 + (-367443684 968762359*y + 1741313178847717412)*x^50 + (-1120756441763956820*y - 13880543 5659787599)*x^49 + (107554480539021407*y - 761016430421970356)*x^48 + (56972 4473209147360*y + 104273935104641941)*x^47 + (-76920393658091100*y + 4556695 27002677921)*x^46 + (-364966710997667886*y - 30164046307811567)*x^45 + (-156 12945533449050*y - 278452806220656846)*x^44 + (196220179915190037*y - 460787 97156864550)*x^43 + (58047935399898944*y + 125056052810735004)*x^42 + (-7036 7728073948453*y + 55368143890230595)*x^41 + (-44471188376651271*y - 33091705 261026148)*x^40 + (10779811934500297*y - 31310302362591686)*x^39 + (19596724 151621886*y - 457971706716061)*x^38 + (4703077156935772*y + 1081792356232906 6)*x^37 + (-5112561845313059*y + 5258998337190094)*x^36 + (-4262623171412271 *y - 1900082482875272)*x^35 + (347587448455796*y - 2909203449118066)*x^34 + (1761877237395113*y - 250996844693464)*x^33 + (371437987605861*y + 969565907 346414)*x^32 + (-487486417978576*y + 306059642167156)*x^31 + (-2039902910102 01*y - 226088796680855)*x^30 + (99522339968066*y - 118416217970085)*x^29 + ( 61143701295650*y + 42854297857883)*x^28 + (-18978818705192*y + 2898834380176 3)*x^27 + (-12949633488740*y - 9667592872104)*x^26 + (5741131351957*y - 5368 774573391)*x^25 + (2144907137575*y + 3501192827999)*x^24 + (-2100987167651*y + 977806363155)*x^23 + (-520851483678*y - 1249500770581)*x^22 + (6929250901 03*y - 282970748175)*x^21 + (163182970660*y + 341901790078)*x^20 + (-1569892 67296*y + 100643285180)*x^19 + (-56780498004*y - 70327470888)*x^18 + (288917 72141*y - 27706877778)*x^17 + (12761071756*y + 10152009124)*x^16 + (-3266832 488*y + 5793469739)*x^15 + (-2353679384*y - 1069498319)*x^14 + (294927621*y - 801098945)*x^13 + (247313433*y + 30224897)*x^12 + (19238389*y + 79956654)* x^11 + (-25462020*y + 12961894)*x^10 + (-5864817*y - 6566480)*x^9 + (1438139 *y - 2974605)*x^8 + (1415485*y + 635208)*x^7 + (-424808*y + 438197)*x^6 + (- 40904*y - 178707)*x^5 + (35389*y + 20411)*x^4 + (-6344*y + 983)*x^3 + (499*y - 430)*x^2 + (-15*y + 36)*x - 1 x^6 + (-2*y - 2)*x^5 + (2*y - 4)*x^4 + 14*x^3 + (-2*y - 2)*x^2 + (2*y - 4)*x + 1 x^8 + 9*x^6 - 16*x^4 + 9*x^2 + 1 x^20 + 6*x^19 + 24*x^18 + 46*x^17 + 57*x^16 + 51*x^15 + 37*x^14 + 21*x^13 + 12*x^12 + 3*x^11 - 11*x^10 - 3*x^9 + 15*x^8 + 14*x^7 + 9*x^6 + 15*x^5 + 15*x ^4 + 6*x^3 + 3*x^2 + 3*x + 1 x^20 + 12*x^18 + 6*x^16 - 5*x^14 - 9*x^12 + 17*x^10 - 9*x^8 + 6*x^4 - 3*x^2 + 1 x^24 + 4*x^22 + 8*x^20 + 20*x^18 + 32*x^16 - 12*x^14 - 42*x^12 - 12*x^10 + 3 2*x^8 + 20*x^6 + 8*x^4 + 4*x^2 + 1 x^21 - 7*x^20 + (3*y + 16)*x^19 + (-22*y - 3)*x^18 + (64*y - 46)*x^17 + (-80 *y + 89)*x^16 + (14*y - 133)*x^15 + (57*y + 244)*x^14 + (-56*y - 259)*x^13 + (132*y - 3)*x^12 + (-317*y + 204)*x^11 + (317*y - 113)*x^10 + (-132*y + 129 )*x^9 + (56*y - 315)*x^8 + (-57*y + 301)*x^7 + (-14*y - 119)*x^6 + (80*y + 9 )*x^5 + (-64*y + 18)*x^4 + (22*y - 25)*x^3 + (-3*y + 19)*x^2 - 7*x + 1 x^4 - y*x^3 - 3*x^2 + y*x + 1 x^4 + (-1/4*y + 1/2)*x^3 - 2*x^2 + (1/4*y + 1/2)*x + 1 x^2 - x + 1 Total time spent: 518 pari-2.11.2/src/test/32/sumformal0000644000175000017500000000040512314242551015076 0ustar billbill *** at top-level: sumformal(1/n) *** ^-------------- *** sumformal: incorrect type in sumformal [not a t_POL] (t_RFRAC). 0 x 1/2*n^2 + 1/2*n 1/3*n^3 + 1/2*n^2 + 1/6*n 1/2*y*x^2 + (1/2*y + 1)*x (1/2*y^2 + 1/2*y)*x + y Total time spent: 4 pari-2.11.2/src/test/32/factor0000644000175000017500000001470113457566440014372 0ustar billbill [x^2 + I 1] [x + 1.0000000000000000000000000000000000000 1] [x - 1.0000000000000000000000000000000000000 1] [x + (0.45508986056222734130435775782246856962 - 1.0986841134678099660398011 952406783785*I) 1] [x + (-0.45508986056222734130435775782246856962 + 1.098684113467809966039801 1952406783785*I) 1] [Mod(1, 5)*x + Mod(2, 5) 1] [Mod(1, 5)*x + Mod(3, 5) 1] [Mod(1, 3)*x^2 + (Mod(1, 3) + Mod(1, 3)*I) 1] *** at top-level: factor(x^2+Mod(1,5)*I) *** ^---------------------- *** factor: sorry, factor for general polynomials is not yet implemented. [(1 + O(5))*x^2 + O(5)*x + (2 + O(5)) 1] *** at top-level: factor(x^2+(1+O(3))+I) *** ^---------------------- *** factor: sorry, factor for general polynomial is not yet implemented. [(1 + O(5))*x + (2 + O(5)) 1] [(1 + O(5))*x + (3 + O(5)) 1] [ x + (1 - w) 1] [x + (-1 + w) 1] *** at top-level: factor(x^2+quadgen(-3)*Mod(1,3)) *** ^-------------------------------- *** factor: sorry, factor for general polynomial is not yet implemented. [Mod(1, 5)*x + (Mod(4, 5) + Mod(1, 5)*w) 1] [Mod(1, 5)*x + (Mod(1, 5) + Mod(4, 5)*w) 1] *** at top-level: factor(x^2+quadgen(-3)*(1+O(5))) *** ^-------------------------------- *** factor: sorry, factor for general polynomial is not yet implemented. *** at top-level: factor(x^2+quadgen(-3)*(1+O(3))) *** ^---------- *** _*_: not an n-th power residue in Qp_sqrt: -3. [x^2 + Mod(y, y^2 + 1) 1] [Mod(Mod(1, 3), Mod(1, 3)*y^2 + Mod(1, 3))*x + Mod(Mod(1, 3)*y + Mod(1, 3), Mod(1, 3)*y^2 + Mod(1, 3)) 1] [Mod(Mod(1, 3), Mod(1, 3)*y^2 + Mod(1, 3))*x + Mod(Mod(2, 3)*y + Mod(2, 3), Mod(1, 3)*y^2 + Mod(1, 3)) 1] *** at top-level: factor(x^2+Mod(y*Mod(1,5),y^2+1)) *** ^--------------------------------- *** factor: sorry, factor for general polynomial is not yet implemented. *** at top-level: factor(x^2+Mod(y*(1+O(3)),y^2+1)) *** ^--------------------------------- *** factor: sorry, factor for general polynomial is not yet implemented. [ I 1] [ 3 -1] [ 1 + I -2] [15 + 2*I 1] [ 1 + I 1] [ 2 + I 4] [1 + 2*I 4] [ -I 1] [ 1 + I 1] [2 + 3*I 1] [ -I 1] [ 3 1] [ 1 + I 1] [2 + 3*I 1] [ -1 1] [1 + I 5] [ -1 1] [1 + 2*I -2] [15 1] [31271192761826143388782348951 1] [31274945109847936339856761591 -1] [ 500009 1] [ 500029 -1] [ 500041 1] [ 500057 -1] [ 500069 1] [ 500083 -1] [250110012091 1] [250115013209 -1] [ x - 2.0000000000000000000000000000000000000 1] [x^2 + 0.E-38*x + 1.0000000000000000000000000000000000000 1] [x - 2 -1] [x + 1 2] [x + 2 -1] [ x -1] [x^2 + 1 1] [ x + Mod(-a, a^2 - 2) 1] [x + Mod(3*a, a^2 - 2) 1] [289*x^4 + 1 8] [19*x^2 + 1 16] [ y -2] [y*x - 1 1] [y*x + 1 1] [y 1] [x -1] [ x + y 2] [x^2 - y*x + y^2 2] [ x^4 + y^4 1] [ x + y 1] [x^2 - y*x + y^2 1] [Mod(1, 7)*x + Mod(6, 7)*y 7] [Mod(1, 7)*x^7 + Mod(6, 7)*y 1] [x^2 + y*x + y^2 1] [x^3 + (y^2 - 1) 1] [Mod(1, 13)*x + Mod(5, 13)*y 1] [Mod(1, 13)*x + Mod(8, 13)*y 1] [ x + I*y 1] [x^2 + (y^2 + I) 1] [Mod(1, 7)*x + (Mod(1, 7)*y + Mod(1, 7)*z) 1] [Mod(1, 7)*x + (Mod(4, 7)*y + Mod(2, 7)*z) 1] [Mod(1, 7)*x + (Mod(2, 7)*y + Mod(4, 7)*z) 1] [ x + (y + 1) 1] [x + (-19*y + 18) 1] [ x + (18*y - 19) 1] [ y 1] [ x 1] [x + y 1] [4*x^3 + (-4*t^2 + 8)*x^2 + (-4*t^3 - 4*t^2 + 4*t + 4)*x + (t^6 + 2*t^5 - t^ 4 - 4*t^3 - t^2 + 2*t + 1) 1] [2*x^6 + (-4*t^2 + 8)*x^5 + (-10*t^3 - 10*t^2 + 10*t + 10)*x^4 + (10*t^6 + 2 0*t^5 - 10*t^4 - 40*t^3 - 10*t^2 + 20*t + 10)*x^3 + (-10*t^8 - 20*t^7 + 20*t ^6 + 60*t^5 - 60*t^3 - 20*t^2 + 20*t + 10)*x^2 + (4*t^10 + 10*t^9 - 10*t^8 - 40*t^7 + 60*t^5 + 20*t^4 - 40*t^3 - 20*t^2 + 10*t + 6)*x + (-t^12 - 2*t^11 + 4*t^10 + 10*t^9 - 5*t^8 - 20*t^7 + 20*t^5 + 5*t^4 - 10*t^3 - 4*t^2 + 2*t + 1) 1] *** factor: Warning: normalizing a polynomial with 0 leading term. [x + 1.0000000000000000000000000000000000000 1] *** factor: Warning: normalizing a polynomial with 0 leading term. [x + (0.E-38 + 1.0000000000000000000000000000000000000*I) 1] [x - I 1] [x + I 1] [x + 1.0000000000000000000000000000000000000 1] [x - 1.0000000000000000000000000000000000000 1] [x + (0.45508986056222734130435775782246856962 - 1.0986841134678099660398011 952406783785*I) 1] [x + (-0.45508986056222734130435775782246856962 + 1.098684113467809966039801 1952406783785*I) 1] [Mod(1, 5)*x + Mod(2, 5) 1] [Mod(1, 5)*x + Mod(3, 5) 1] [Mod(1, 3)*x + (Mod(0, 3) + Mod(1, 3)*I) 1] [Mod(1, 3)*x + (Mod(0, 3) + Mod(2, 3)*I) 1] [(1 + O(5))*x + (2 + O(5)) 1] [(1 + O(5))*x + (3 + O(5)) 1] [(1 + O(5^2))*x + O(5^2) 1] [(1 + O(5^2))*x + O(5^2) 1] *** at top-level: factor(x^2+(1+O(3)),I) *** ^---------------------- *** factor: sorry, factor for general polynomial is not yet implemented. [x + (1 - w) 1] [ x + w 1] [ x + (1 - w) 1] [x + (-1 + w) 1] [ x + (1 - w) 1] [x + (-1 + w) 1] [ x + (1 - w) 1] [x + (-1 + w) 1] [ x + (1 - w) 1] [x + (-1 + w) 1] [x^2 + Mod(y, y^2 + 1) 1] [Mod(Mod(1, 3), Mod(1, 3)*y^2 + Mod(1, 3))*x + Mod(Mod(1, 3)*y + Mod(1, 3), Mod(1, 3)*y^2 + Mod(1, 3)) 1] [Mod(Mod(1, 3), Mod(1, 3)*y^2 + Mod(1, 3))*x + Mod(Mod(2, 3)*y + Mod(2, 3), Mod(1, 3)*y^2 + Mod(1, 3)) 1] *** at top-level: factor(x^2+Mod(y,y^2+1),Mod(1,5)) *** ^--------------------------------- *** factor: sorry, factor for general polynomial is not yet implemented. *** at top-level: factor(x^2+Mod(y,y^2+1),O(3)) *** ^----------------------------- *** factor: sorry, factor for general polynomial is not yet implemented. [ 1 + I -2] [ 2 + I 1] [1 + 2*I 1] [ x + Mod(-a, a^2 - 2) 1] [x + Mod(3*a, a^2 - 2) 1] [ Mod(1, 2)*y 1] [ Mod(1, 2)*x 1] [Mod(1, 2)*y*x + Mod(1, 2) 1] [Mod(1, 2)*z^3 + Mod(1, 2)*z + Mod(1, 2) 1] [Mod(1, 2)*y^2 + Mod(1, 2)*y + Mod(1, 2) 1] [ Mod(1, 2)*x 1] [ Mod(1, 2)*y*x + Mod(1, 2) 1] [ x -2] [x + y -3] [ x + y 1] [x + (-1 + w)*y 1] [ x - w*y 1] [Mod(1, 7)*x + Mod(6, 7)*y 7] [Mod(1, 7)*x^7 + Mod(6, 7)*y 1] [Mod(1, 13)*x + Mod(5, 13)*y 1] [Mod(1, 13)*x + Mod(8, 13)*y 1] [Mod(1, 7)*x + (Mod(1, 7)*y + Mod(1, 7)*z) 1] [Mod(1, 7)*x + (Mod(4, 7)*y + Mod(2, 7)*z) 1] [Mod(1, 7)*x + (Mod(2, 7)*y + Mod(4, 7)*z) 1] Total time spent: 292 pari-2.11.2/src/test/32/history0000644000175000017500000000057213201017466014600 0ustar billbill2 3 4 5 *** at top-level: %`````` *** ^------- *** %: History result %-1 not available [%1-%5]. 0 3 3 1 1 1 *** at top-level: %`` *** ^--- *** %: History result %11 not available [%13-%13]. *** at top-level: %`` *** ^--- *** %: History result %12 has been deleted (histsize changed). 1 Total time spent: 0 pari-2.11.2/src/test/32/genus2red0000644000175000017500000012050213326135265014777 0ustar billbillType: [I{0-0-0}], p. 155 [1, Mat([7, 0]), x^5 + x^3 - 2*x^2 + 3*x + 1, [7, [1, []], ["(tame) [I{0-0-0 }] page 155", []]]] Type: [I*{0-0-0}], p. 155 [2401, Mat([7, 4]), 7*x^5 + 7*x^3 - 14*x^2 + 21*x + 7, [7, [1, []], ["(tame) [I*{0-0-0}] page 155", [2, 2, 2, 2]]]] Type: [II], p. 155 [49, Mat([7, 2]), x^6 + 28*x^4 - 49*x^2 + 343, [7, [1, []], ["(tame) [II] pa ge 155", []]]] [9, Mat([3, 2]), x^6 + 12*x^4 - 9*x^2 + 27, [3, [1, []], ["[II] page 155", [ ]]]] Type: [III], p. 155 [2401, Mat([7, 4]), x^6 + 28*x^3 + 49, [7, [1, []], ["[III] page 155", [3, 3 ]]]] Type: [IV], p. 155 [2401, Mat([7, 4]), 7*x^6 + 245*x^3 + 343, [7, [4, []], ["[III*{3}] page 184 ", []]]] Type: [V], p. 156 [2401, Mat([7, 4]), x^6 + 7, [7, [1, []], ["[V] page 156", [3]]]] Type: [V*], p. 156 [2401, Mat([7, 4]), 7*x^6 + 49, [7, [1, []], ["[V*] page 156", [3]]]] Type: [VI], p. 156 [2401, Mat([7, 4]), x^5 + 21*x^3 + 49*x, [7, [1, []], ["(tame) [VI] page 156 ", [2, 2]]]] Type: [VII], p. 156 [2401, Mat([7, 4]), x^5 + 7*x, [7, [1, []], ["[VII] page 156", [2]]]] Type: [VII*], p. 156 [2401, Mat([7, 4]), 7*x^5 + 49*x, [7, [1, []], ["[VII*] page 156", [2]]]] Type: [VIII-1], p. 156 [2401, Mat([7, 4]), x^5 + 7, [7, [1, []], ["[VIII-1] page 156", []]]] Type: [VIII-2], p. 157 [2401, Mat([7, 4]), x^5 + 343, [7, [1, []], ["[VIII-2] page 157", []]]] Type: [VIII-3], p. 157 [2401, Mat([7, 4]), 7*x^5 + 343, [7, [1, []], ["[VIII-3] page 157", []]]] Type: [VIII-4], p. 157 [2401, Mat([7, 4]), 7*x^6 + 49*x, [7, [1, []], ["[VIII-4] page 157", []]]] Type: [IX-1], p. 157 [2401, Mat([7, 4]), x^5 + 49, [7, [1, []], ["[IX-1] page 157", [5]]]] Type: [IX-2], p. 157 [2401, Mat([7, 4]), x^6 + 7*x, [7, [1, []], ["[IX-2] page 157", [5]]]] Type: [IX-3], p. 157 [2401, Mat([7, 4]), 7*x^5 + 49, [7, [1, []], ["[IX-3] page 157", [5]]]] Type: [IX-4], p. 158 [2401, Mat([7, 4]), x^6 + 49*x, [7, [1, []], ["[IX-4] page 158", [5]]]] Type: [I{0}-I{0}-10], p. 158 [1, Mat([7, 0]), 508021860739623365322188197652216501772434524836001*x^6 + 5 080218607396233653221881976522165257101144141196013*x^4 + 508021860739623365 322188197652216501772434524836002*x^3 + 2393767988928360030*x^2 + 2393767988 92836013*x + 1, [7, [5, [Mod(2, 7), Mod(5, 7)]], ["(tame) [I{0}-I{0}-10] pag e 158", []]]] [1, Mat([3, 0]), 42391158275216203514294433201*x^6 + 42391158275216203510807 648800*x^4 + 42391158275216203514294433202*x^3 - 3486784401*x^2 - 3486784400 *x + 1, [3, [5, [Mod(0, 3), Mod(1, 3)]], ["[I{0}-I{0}-10] page 158", []]]] Type: [I{0}*-I{0}*-10], p. 158 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 24893071176241544900787221684958 6097837332861811440640*x^4 + 17425149823369080494630608325843912106803538735 9467068*x^3 - 6551443127975383932596363883779423529*x^2 + 410531210101213754 7000*x + 66885, [7, [5, [Mod(2, 7), Mod(2, 7)]], ["(tame) [I*{0}-I*{0}-10] p age 158", [2, 2, 2, 2]]]] [81, Mat([3, 4]), 42391158275216203514294433201*x^6 - 36472996377170786403*x ^5 + 381520424476945831607729192403*x^4 + 1144561273102580527491412618835*x^ 3 - 984770902371897590535*x^2 - 564859072647*x + 945, [3, [5, [Mod(0, 3), Mo d(0, 3)]], ["[I*{0}-I*{0}-10] page 158", [2, 2, 2, 2]]]] Type: [I{0}-I{0}*-10], p. 159 [49, Mat([7, 2]), 508021860739623365322188197652216501772434524836001*x^6 + 248930711762415449007872216849586086107869716062476493*x^4 + 174251498233690 814305510551794710260107945042018748344*x^3 + 117294631457489641470*x^2 + 82 106242020242749519*x + 343, [7, [5, [Mod(2, 7), Mod(5, 7)]], ["(tame) [I{0}- I*{0}-10] page 159", [2, 2]]]] [9, Mat([3, 2]), 42391158275216203514294433201*x^6 + 38152042447694583162516 3114408*x^4 + 1144561273430837494885949696428*x^3 - 31381059609*x^2 - 941431 78818*x + 27, [3, [5, [Mod(0, 3), Mod(1, 3)]], ["[I{0}-I*{0}-10] page 159", [2, 2]]]] Type: [2I{0}-11], p. 159 [49, Mat([7, 2]), x^6 - 21*x^4 + 574743694141699243350*x^2 + 265173084183644 7612787128678837, [7, [5, [Mod(2, 7), Mod(2, 7)]], ["(tame) [2I{0}-11] page 159", []]]] [9, Mat([3, 2]), x^6 - 9*x^4 - 282429536454*x^2 + 150095482585608537, [3, [5 , [Mod(0, 3), Mod(0, 3)]], ["[2I{0}-11] page 159", []]]] Type: [2I{0}*-10], p. 159 [2401, Mat([7, 4]), x^6 - 21*x^4 + 82106242020242749176*x^2 + 54116956037952 111668959660849*x - 574743694141699243546, [7, [5, [Mod(2, 7), Mod(2, 7)]], ["(tame) [2I*{0}-10] page 159", [2, 2]]]] Type: [2I{0}*-10], p. 159 [2401, Mat([7, 4]), x^6 - 21*x^4 + 82106242020242749176*x^2 + 54116956037952 111668959660849*x - 574743694141699243546, [7, [5, [Mod(2, 7), Mod(2, 7)]], ["(tame) [2I*{0}-10] page 159", [2, 2]]]] Type: [I{0}-II-10], p. 159 [49, Mat([7, 2]), 6366805760909027985741435139224001*x^5 + 23937679889283600 3*x^4 + x^3 + 44567640326363195900190045974568007*x^2 + 1675637592249852021* x + 7, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I{0}-II-10] page 159", []] ]] Type: [I{0}-II*-10], p. 160 [49, Mat([7, 2]), 6366805760909027985741435139224001*x^5 + 23937679889283600 3*x^4 + x^3 + 107006904423598033356356300384937784807*x^2 + 4023205858991894 702421*x + 16807, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I{0}-II*-10] pa ge 160", []]]] [243, Mat([3, 5]), 12157665459056928801*x^5 + 10460353203*x^4 + x^3 + 295431 2706550833698643*x^2 + 2541865828329*x + 243, [3, [5, [Mod(0, 3), Mod(0, 3)] ], ["[I{0}-II*-10] pages 159-177", []]]] Type: [I{0}-IV-10], p. 160 [49, Mat([7, 2]), 6366805760909027985741435139224001*x^5 + 23937679889283600 3*x^4 + x^3 + 311973482284542371301330321821976049*x^2 + 1172946314574896414 7*x + 49, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I{0}-IV-10] page 160", [3]]]] [243, Mat([3, 5]), 12157665459056928801*x^5 + 10460353203*x^4 + x^3 + 109418 989131512359209*x^2 + 94143178827*x + 9, [3, [5, [Mod(0, 3), Mod(0, 3)]], [" [I{0}-IV-10] pages 159-177", [3]]]] Type: [I{0}-IV*-10], p. 160 [49, Mat([7, 2]), 6366805760909027985741435139224001*x^5 + 23937679889283600 3*x^4 + x^3 + 15286700631942576193765185769276826401*x^2 + 57474369414169924 3203*x + 2401, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I{0}-IV*-10] page 160", [3]]]] [243, Mat([3, 5]), 12157665459056928801*x^5 + 10460353203*x^4 + x^3 + 984770 902183611232881*x^2 + 847288609443*x + 81, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[I{0}-IV*-10] pages 159-177", [3]]]] Type: [I{0}*-II-10], p. 160 [2401, Mat([7, 4]), 311973482284542371301330321821976049*x^5 + 1675637592249 852021*x^4 + x^3 + 2183814375991796599109312252753832343*x^2 + 1172946314574 8964147*x + 7, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I*{0}-II-10] page 160", [2, 2]]]] [2187, Mat([3, 7]), 109418989131512359209*x^5 + 31381059609*x^4 + x^3 + 3282 56967394537077627*x^2 + 94143178827*x + 3, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[I*{0}-II-10] pages 159-177", [2, 2]]]] Type: [I{0}*-II*-10], p. 160-161 [2401, Mat([7, 4]), 311973482284542371301330321821976049*x^5 + 1675637592249 852021*x^4 + x^3 + 5243338316756303634461458718861951455543*x^2 + 2816244101 2943262916947*x + 16807, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I*{0}-II *-10] page 160", [2, 2]]]] [2187, Mat([3, 7]), 109418989131512359209*x^5 + 31381059609*x^4 + x^3 + 2658 8814358957503287787*x^2 + 7625597484987*x + 243, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[I*{0}-II*-10] pages 159-177", [2, 2]]]] Type: [I{0}*-IV-10], p. 161 [2401, Mat([7, 4]), 311973482284542371301330321821976049*x^5 + 1675637592249 852021*x^4 + x^3 + 15286700631942576193765185769276826401*x^2 + 821062420202 42749029*x + 49, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I*{0}-IV-10] pag e 161", [6, 2]]]] Type: [I{0}*-IV*-10], p. 161 [2401, Mat([7, 4]), 311973482284542371301330321821976049*x^5 + 1675637592249 852021*x^4 + x^3 + 749048330965186233494494102694564493649*x^2 + 40232058589 91894702421*x + 2401, [7, [5, [Mod(0, 7), Mod(2, 7)]], ["(tame) [I*{0}-IV*-1 0] page 161", [6, 2]]]] Type: [I{0}-III-10], p. 161 [49, Mat([7, 2]), 6366805760909027985741435139224001*x^5 + 23937679889283600 3*x^4 + 44567640326363195900190045974568008*x^3 + 1675637592249852021*x^2 + 7*x, [7, [5, [Mod(2, 7), Mod(6, 7)]], ["(tame) [I{0}-III-10] page 161", [2]] ]] Type: [I{0}-III*-10], p. 162 [49, Mat([7, 2]), 6366805760909027985741435139224001*x^5 + 23937679889283600 3*x^4 + 2183814375991796599109312252753832344*x^3 + 82106242020242749029*x^2 + 343*x, [7, [5, [Mod(2, 7), Mod(6, 7)]], ["(tame) [I{0}-III*-10] page 162" , [2]]]] Type: [I{0}*-III-10], p. 162 [2401, Mat([7, 4]), 311973482284542371301330321821976049*x^5 + 1675637592249 852021*x^4 + 2183814375991796599109312252753832344*x^3 + 1172946314574896414 7*x^2 + 7*x, [7, [5, [Mod(2, 7), Mod(6, 7)]], ["(tame) [I*{0}-III-10] page 1 62", [2, 2, 2]]]] Type: [I{0}*-III*-10], p. 162 [2401, Mat([7, 4]), 311973482284542371301330321821976049*x^5 + 1675637592249 852021*x^4 + 107006904423598033356356300384937784808*x^3 + 57474369414169924 3203*x^2 + 343*x, [7, [5, [Mod(2, 7), Mod(6, 7)]], ["(tame) [I*{0}-III*-10] page 162", [2, 2, 2]]]] Type: [2II-10], p. 162 [2401, Mat([7, 4]), x^6 - 21*x^4 + 147*x^2 + 7730993719707444524137094407*x - 343, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [2II-10] page 162", []]]] [59049, Mat([3, 10]), x^6 - 9*x^4 + 27*x^2 + 5559060566555523*x - 27, [3, [5 , [Mod(0, 3), Mod(0, 3)]], ["[2II-10] page 162", []]]] Type: [2II*-10], p. 163 [2401, Mat([7, 4]), x^6 - 21*x^4 + 147*x^2 + 378818692265664781682717625943* x - 343, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [2II*-10] page 163", []]] ] [59049, Mat([3, 10]), x^6 - 9*x^4 + 27*x^2 + 50031545098999707*x - 27, [3, [ 5, [Mod(0, 3), Mod(0, 3)]], ["[2II*-10] page 163", []]]] Type: [II-II-10], p. 163 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 3556153 025177363557255317383565515512407041673852013*x^3 - 133702920979089587700570 137923704021*x^2 + 1675637592249852021*x + 42, [7, [5, [Mod(0, 7), Mod(0, 7) ]], ["(tame) [II-II-10] page 163", []]]] Type: [II-II*-10], p. 163 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 3556153 025177363557255317383565515512407041673868813*x^3 - 133702920979089587700570 137923704021*x^2 + 1675637592249852021*x + 117642, [7, [5, [Mod(0, 7), Mod(0 , 7)]], ["(tame) [II-II*-10] page 163", []]]] Type: [II*-II*-10], p. 163 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 8538323 413450849900970017037940802745289307058918685613*x^3 - 321020713270794100069 068901154813354421*x^2 + 4023205858991894702421*x + 282458442, [7, [5, [Mod( 0, 7), Mod(0, 7)]], ["(tame) [II*-II*-10] page 163", []]]] Type: [II*-II*-(-1)], p. 163 [2401, Mat([7, 4]), 7*x^6 - 21*x^5 + 21*x^4 + 679*x^3 - 1029*x^2 + 1029*x + 16464, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [II*-II*--1] page 163", []] ]] Type: [II-IV-10], p. 164 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 3556153 025177363557255317383565515512407041673852055*x^3 - 133702920979089587700570 137923704021*x^2 + 1675637592249852021*x + 336, [7, [5, [Mod(0, 7), Mod(0, 7 )]], ["(tame) [II-IV-10] page 164", [3]]]] Type: [II-IV*-10], p. 164 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 3556153 025177363557255317383565515512407041673854407*x^3 - 133702920979089587700570 137923704021*x^2 + 1675637592249852021*x + 16800, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [II-IV*-10] page 164", [3]]]] Type: [II*-IV-10], p. 164 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 8538323 413450849900970017037940802745289307058918668855*x^3 - 321020713270794100069 068901154813354421*x^2 + 4023205858991894702421*x + 806736, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [II*-IV-10] page 164", [3]]]] Type: [II*-IV-(-1)], p. 164 [2401, Mat([7, 4]), x^6 + 56*x^3 + 343, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["[ II*-IV-(-1)] page 164", [3]]]] Type: [II*-IV*-10], p. 164-165 [2401, Mat([7, 4]), 174251498233690814305510551794710260107945042018748343*x ^6 - 935920446853627113903990965465928147*x^5 + 1675637592249852021*x^4 + 41 8377847259091645147530834859099334519176045887014771591*x^3 - 22471449928955 58700483482308083693480947*x^2 + 4023205858991894702421*x + 115248, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [II*-IV*-10] page 164", [3]]]] Type: [2IV-10], p. 165 [2401, Mat([7, 4]), x^6 - 21*x^4 + 147*x^2 + 54116956037952111668959660506, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [2IV-10] page 165", [3]]]] [59049, Mat([3, 10]), x^6 - 9*x^4 + 27*x^2 + 16677181699666542, [3, [5, [Mod (0, 3), Mod(0, 3)]], ["[2IV-10] page 165", [3]]]] Type: [2IV*-10], p. 165 [2401, Mat([7, 4]), x^6 - 21*x^4 + 147*x^2 + 378818692265664781682717625600, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [2IV*-10] page 165", [3]]]] [59049, Mat([3, 10]), x^6 - 9*x^4 + 27*x^2 + 50031545098999680, [3, [5, [Mod (0, 3), Mod(0, 3)]], ["[2IV*-10] page 165", [3]]]] Type: [IV-IV-10], p. 165 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 2489307 1176241544900787221684958608586849291716964097*x^3 - 93592044685362711390399 0965465928147*x^2 + 11729463145748964147*x + 2352, [7, [5, [Mod(0, 7), Mod(0 , 7)]], ["(tame) [IV-IV-10] page 165", [3, 3]]]] Type: [IV-IV*-10], p. 165 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 239376798892836003*x^4 + 2489307 1176241544900787221684958608586849291716966449*x^3 - 93592044685362711390399 0965465928147*x^2 + 11729463145748964147*x + 117600, [7, [5, [Mod(0, 7), Mod (0, 7)]], ["(tame) [IV-IV*-10] page 165", [3, 3]]]] Type: [IV*-IV*-10], p. 166 [2401, Mat([7, 4]), 174251498233690814305510551794710260107945042018748343*x ^6 - 935920446853627113903990965465928147*x^5 + 1675637592249852021*x^4 + 41 8377847259091645147530834859099334519176045887014771549*x^3 - 22471449928955 58700483482308083693480947*x^2 + 4023205858991894702421*x + 14406, [7, [5, [ Mod(0, 7), Mod(0, 7)]], ["(tame) [IV*-IV*-10] page 166", [3, 3]]]] Type: [II-III-10], p. 166 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 35561530251773635572553173835655 15751783840566688010*x^4 - 133702920979089587700570137923704015*x^3 + 167563 7592249852021*x^2 + 42*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], ["(tame) [II-III- 10] page 166", [2]]]] Type: [II-III*-10], p. 166 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 17425149823369081430551055179471 0260347321840911584346*x^4 - 6551443127975389797327936758261497023*x^3 + 821 06242020242749029*x^2 + 2058*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], ["(tame) [I I-III*-10] page 166", [2]]]] Type: [II*-III-10], p. 166 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 35561530251773635572553173835655 15751783840566688010*x^4 - 133702920979089587700570137923687215*x^3 + 167563 7592249852021*x^2 + 117642*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], ["(tame) [II* -III-10] page 166", [2]]]] Type: [II*-III-(-1)], p. 167 [2401, Mat([7, 4]), x^5 + 7*x^3 + 49*x^2 + 343, [7, [5, [Mod(0, 7), Mod(6, 7 )]], ["[II*-III-(-1)] page 167", [2]]]] Type: [II*-III*-10], p. 167 [2401, Mat([7, 4]), 174251498233690814305510551794710260107945042018748343*x ^6 - 935920446853627113903990965465928147*x^5 + 5976826389415594930679011926 5585619218700787004680533670*x^4 - 321020713270794100069068901154813354373*x ^3 + 574743694141699243203*x^2 + 16464*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], [ "(tame) [II*-III*-10] page 167", [2]]]] Type: [IV-III-10], p. 167 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 35561530251773635572553173835655 15751783840566688010*x^4 - 133702920979089587700570137923703973*x^3 + 167563 7592249852021*x^2 + 336*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], ["(tame) [III-IV -10] page 167", [6]]]] [2187, Mat([3, 7]), 42391158275216203514294433201*x^6 - 36472996377170786403 *x^5 + 127173474825648610553343652806*x^4 - 109418989131512359201*x^3 + 3138 1059609*x^2 + 24*x, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[III-IV-10] pages 161 -177", [6]]]] Type: [IV-III*-10], p. 167 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 17425149823369081430551055179471 0260347321840911584346*x^4 - 6551443127975389797327936758261496981*x^3 + 821 06242020242749029*x^2 + 16464*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], ["(tame) [ III*-IV-10] page 167", [6]]]] [2187, Mat([3, 7]), 42391158275216203514294433201*x^6 - 36472996377170786403 *x^5 + 1144561273430837494896410049630*x^4 - 984770902183611232873*x^3 + 282 429536481*x^2 + 216*x, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[III*-IV-10] pages 162-177", [6]]]] Type: [IV-III*-(-1)], p. 167 [2401, Mat([7, 4]), x^6 + 7*x^4 + 7*x^3 + 49*x, [7, [5, [Mod(0, 7), Mod(6, 7 )]], ["[IV-III*-(-1)] page 167", [6]]]] Type: [IV*-III-10], p. 168 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 35561530251773635572553173835655 15751783840566688010*x^4 - 133702920979089587700570137923701621*x^3 + 167563 7592249852021*x^2 + 16800*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], ["(tame) [III- IV*-10] page 168", [6]]]] Type: [IV*-III*-10], p. 168 [2401, Mat([7, 4]), 174251498233690814305510551794710260107945042018748343*x ^6 - 935920446853627113903990965465928147*x^5 + 5976826389415594930679011926 5585619218700787004680533670*x^4 - 321020713270794100069068901154813354415*x ^3 + 574743694141699243203*x^2 + 2058*x, [7, [5, [Mod(0, 7), Mod(6, 7)]], [" (tame) [III*-IV*-10] page 168", [6]]]] Type: [2III-10], p. 168 [2401, Mat([7, 4]), x^6 - 21*x^4 + 3909821048582988049*x^3 + 147*x^2 - 27368 747340080916343*x - 343, [7, [5, [Mod(6, 7), Mod(6, 7)]], ["(tame) [2III-10] page 168", [2]]]] [81, Mat([3, 4]), x^6 - 9*x^4 + 31381059609*x^3 + 27*x^2 - 94143178827*x - 2 7, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[2III-10] page 168", [2]]]] Type: [2III*-10], p. 168 [2401, Mat([7, 4]), x^6 - 21*x^4 + 27368747340080916343*x^3 + 147*x^2 - 1915 81231380566414401*x - 343, [7, [5, [Mod(6, 7), Mod(6, 7)]], ["(tame) [2III*- 10] page 168", [2]]]] [81, Mat([3, 4]), x^6 - 9*x^4 + 94143178827*x^3 + 27*x^2 - 282429536481*x - 27, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[2III*-10] page 168", [2]]]] Type: [III-III-10], p. 169 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 35561530251773635572553173835655 16310329704649972017*x^4 - 133702920979089587700570137923704029*x^3 + 558545 8640832840070*x^2 - 56*x, [7, [5, [Mod(6, 7), Mod(6, 7)]], ["(tame) [III-III -10] page 169", [2, 2]]]] Type: [III-III*-10], p. 169 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 - 19100417282727083957224305417672003*x^5 + 35561530251773635572553173835655 43120531180647604353*x^4 - 133702920979089587700570137923704365*x^3 + 193256 868972816266422*x^2 - 2408*x, [7, [5, [Mod(6, 7), Mod(6, 7)]], ["(tame) [III -III*-10] page 169", [2, 2]]]] Type: [III*-III*-{10}], p. 169 [2401, Mat([7, 4]), 174251498233690814305510551794710260107945042018748343*x ^6 - 935920446853627113903990965465928147*x^5 + 5976826389415594930679011926 5585619222610608053263521719*x^4 - 321020713270794100069068901154813354429*x ^3 + 1915812313805664144010*x^2 - 2744*x, [7, [5, [Mod(6, 7), Mod(6, 7)]], [ "(tame) [III*-III*-10] page 169", [2, 2]]]] Type: [I{9-0-0}], p. 170 [7, Mat([7, 1]), x^5 + 40353610*x^3 + x^2 + 121060821*x + 40353607, [7, [2, [Mod(2, 7)]], ["(tame) [I{9-0-0}] page 170", [9]]]] Type: [I{9}-I{0}-10], p. 170 [7, Mat([7, 1]), 6366805760909027985741435139224001*x^5 - 159584532595224002 *x^4 + 19100417282727083957224305458025611*x^3 + 636680576090902750698783735 3551995*x^2 - 159584532474163178*x + 40353608, [7, [6, [Mod(2, 7)]], ["(tame ) [I{0}-I{9}-10] page 170", [9]]]] [3, Mat([3, 1]), 12157665459056928801*x^5 - 6973568802*x^4 - 121576654590569 09117*x^3 + 12157665466030497603*x^2 - 6973588486*x + 19684, [3, [6, [Mod(0, 3)]], ["(tame) [I{0}-I{9}-10] page 170", [9]]]] Type: [I{0}-I*{9}-10], p. 170 [49, Mat([7, 2]), x^6 + 4*x^5 + 19100417282727083957224307394998728*x^4 + 50 8021860739623479924691894014720245118274940175011*x^3 + 35561530629451293191 48051483501814963799504492542834*x^2 + 1004525211269079266605816908070627976 335864597950580018666977*x + 70316764788835530156201894723072969620825817394 84589084102397, [7, [6, [Mod(2, 7)]], ["(tame) [I{0}-I*{9}-10] page 170", [4 ]]]] [9, Mat([3, 2]), x^6 - 12157665459056751660*x^4 + 42391158250900872596180575 607*x^3 + 127171321168158531362286712374*x^2 + 75094665106723368777956004270 53229*x + 22528399551400256301066821173173441, [3, [6, [Mod(0, 3)]], ["[I{0} -I*{9}-10] page 170", [4]]]] Type: [I{9}-I{0}*-10], p. 171 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 - 1595845325952240 02*x^4 + 935920446853627113903990965506281755*x^3 + 218381437599179657565038 5961255904049*x^2 - 54737494674229852310*x + 13841287544, [7, [6, [Mod(2, 7) ]], ["(tame) [I{9}-I*{0}-10] page 170", [18, 2]]]] Type: [I*{9-0-0}], p. 171 [2401, Mat([7, 4]), 7*x^5 + 282475270*x^3 + 7*x^2 + 847425747*x + 282475249, [7, [2, [Mod(2, 7)]], ["(tame) [I*{9-0-0}] page 171", [4, 2, 2]]]] Type: [I*{9}-I{0}*-10], p. 171 [2401, Mat([7, 4]), x^6 + 4*x^5 + 935920446853627113903990967443254872*x^4 + 174251498233690819921033232916472943531890842723624217*x^3 + 12197604894864 56222471317833459850493873847680657395212*x^2 + 3445521474652941218234561596 37489836481536621034944927824583035*x + 241186503225705876208378720213726101 0629601295382324365507824195, [7, [6, [Mod(2, 7)]], ["(tame) [I*{0}-I*{9}-10 ] page 171", [4, 2, 2]]]] Type: [II{9-0}], p. 171 [343, Mat([7, 3]), x^6 - 2*x^5 + 5764823*x^4 - 42*x^3 + 121060891*x^2 - 98*x + 282475298, [7, [2, [Mod(0, 7)]], ["(tame) [II{9-0}] page 171", [36]]]] Type: [II*{9-0}], p. 172 [49, Mat([7, 2]), 7*x^6 - 14*x^5 + 40353761*x^4 - 294*x^3 + 847426237*x^2 - 686*x + 1977327086, [7, [2, [Mod(0, 7)]], ["(tame) [II*{9-0}] page 172", []] ]] Type: [II-I{9}-10], p. 172 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 - 1595845325952240 02*x^4 + 40353608*x^3 + 44567640326363195900190045974568007*x^2 - 1117091728 166568014*x + 282475256, [7, [6, [Mod(0, 7)]], ["(tame) [I{9}-II-10] page 17 2", [9]]]] Type: [II*-I{9}-10], p. 172 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 - 1595845325952240 02*x^4 + 40353608*x^3 + 107006904423598033356356300384937784807*x^2 - 268213 7239327929801614*x + 678223089656, [7, [6, [Mod(0, 7)]], ["(tame) [I{9}-II*- 10] page 172", [9]]]] Type: [IV-I{9}-10], p. 173 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 - 1595845325952240 02*x^4 + 40353608*x^3 + 311973482284542371301330321821976049*x^2 - 781964209 7165976098*x + 1977326792, [7, [6, [Mod(0, 7)]], ["(tame) [I{9}-IV-10] page 173", [9, 3]]]] Type: [IV*-I{9}-10], p. 173 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 - 1595845325952240 02*x^4 + 40353608*x^3 + 15286700631942576193765185769276826401*x^2 - 3831624 62761132828802*x + 96889012808, [7, [6, [Mod(0, 7)]], ["(tame) [I{9}-IV*-10] page 173", [9, 3]]]] Type: [II-I*{9}-10], p. 173 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 + 25467223043636111942965740556896004*x^5 + 157775381157130877341310732*x^4 + 3556153025177363557255317383565515512407053537812471*x^3 + 178270561305452 783600760183898272028*x^2 + 1104427668099916141389175124*x + 83047723248, [7 , [6, [Mod(0, 7)]], ["(tame) [I*{9}-II-10] page 173", [4]]]] Type: [II*-I*{9}-10], p. 174 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 + 25467223043636111942965740556896004*x^5 + 157775381157130877341310732*x^4 + 8538323413450849900970017037940802745289307070782629271*x^3 + 428027617694 392133425425201539751139228*x^2 + 2651730831107898655475409472724*x + 199397 583518448, [7, [6, [Mod(0, 7)]], ["(tame) [I*{9}-II*-10] page 174", [4]]]] Type: [II*-I*{9}-(-1)], p. 174 [2401, Mat([7, 4]), 7*x^5 - 14*x^4 + 282475256*x^3 + 343*x^2 - 686*x + 13841 287544, [7, [6, [Mod(0, 7)]], ["(tame) [I*{9}-II*--1] page 174", [4]]]] Type: [IV-I*{9}-10], p. 174 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 + 25467223043636111942965740556896004*x^5 + 157775381157130877341310732*x^4 + 24893071176241544900787221684958608586849303580924513*x^3 + 12478939291381 69485205321287287904196*x^2 + 7730993676699412989724225868*x + 581334062736, [7, [6, [Mod(0, 7)]], ["(tame) [I*{9}-IV-10] page 174", [12]]]] Type: [IV*-I*{9}-10], p. 174 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 + 25467223043636111942965740556896004*x^5 + 157775381157130877341310732*x^4 + 1219760487635835700138573862562971820755615305995198865*x^3 + 611468025277 70304775060743077107305604*x^2 + 378818690158271236496487067532*x + 28485369 074064, [7, [6, [Mod(0, 7)]], ["(tame) [I*{9}-IV*-10] page 174", [12]]]] Type: [IV*-I*{9}-(-1)], p. 175 [2401, Mat([7, 4]), 7*x^5 - 14*x^4 + 282475256*x^3 + 49*x^2 - 98*x + 1977326 792, [7, [6, [Mod(0, 7)]], ["(tame) [I*{9}-IV*--1] page 174", [12]]]] [2187, Mat([3, 7]), 3*x^5 - 6*x^4 + 59052*x^3 + 9*x^2 - 18*x + 177156, [3, [ 6, [Mod(0, 3)]], ["[I*{9}-IV*--1] pages 159-177", [12]]]] Type: [IV-II{9}], p. 175 [343, Mat([7, 3]), x^6 - 2*x^5 + 40353608*x^4 + 7*x^3 - 14*x^2 + 282475256*x , [7, [2, [Mod(0, 7)]], ["(tame) [II{9}-IV] page 175", [29]]]] [729, Mat([3, 6]), x^6 - 2*x^5 + 19684*x^4 + 3*x^3 - 6*x^2 + 59052*x, [3, [6 , [Mod(0, 3)]], ["[IV-II{9}] page 175", [29]]]] Type: [IV*-II{9}], p. 175 [343, Mat([7, 3]), x^6 - 2*x^5 + 5764802*x^4 + 49*x^3 - 98*x^2 + 282475298*x , [7, [2, [Mod(0, 7)]], ["(tame) [II{9}-IV*] page 175", [28]]]] [729, Mat([3, 6]), x^6 - 2*x^5 + 6562*x^4 + 9*x^3 - 18*x^2 + 59058*x, [3, [6 , [Mod(0, 3)]], ["[IV*-II{9}] page 175", [28]]]] Type: [IV*-II{0}], p. 175 [343, Mat([7, 3]), 7*x^5 + 49*x^3 + 49*x^2 + 343, [7, [2, [Mod(0, 7)]], ["[I V*-II{0}] page 175", []]]] [729, Mat([3, 6]), 3*x^5 + 9*x^3 + 9*x^2 + 27, [3, [6, [Mod(0, 3)]], ["[IV*- II{0}] page 175", []]]] Type: [II-II*{9}], p. 176 [2401, Mat([7, 4]), x^5 + 282475249*x^3 + 7*x^2 + 1977326743, [7, [2, [Mod(0 , 7)]], ["[II-II*{9}] page 176", [2, 2]]]] [2187, Mat([3, 7]), x^5 + 59049*x^3 + 3*x^2 + 177147, [3, [6, [Mod(0, 3)]], ["[II-II*{9}] page 176", [2, 2]]]] Type: [II*-II*{9}], p. 176 [2401, Mat([7, 4]), 7*x^6 - 14*x^5 + 282475256*x^4 + 49*x^3 - 98*x^2 + 19773 26792*x, [7, [2, [Mod(0, 7)]], ["(tame) [II*-II*{9}] page 176", [2, 2]]]] [2187, Mat([3, 7]), 3*x^6 - 6*x^5 + 59052*x^4 + 9*x^3 - 18*x^2 + 177156*x, [ 3, [6, [Mod(0, 3)]], ["[II*-II*{9}] page 176", [2, 2]]]] Type: [III-I{9}-10], p. 176 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 - 1595845325952240 02*x^4 + 44567640326363195900190046014921615*x^3 - 1117091728166568014*x^2 + 282475256*x, [7, [6, [Mod(6, 7)]], ["(tame) [I{9}-III-10] page 176", [18]]] ] [27, Mat([3, 3]), 12157665459056928801*x^5 - 6973568802*x^4 + 36472996377170 806087*x^3 - 20920706406*x^2 + 59052*x, [3, [6, [Mod(0, 3)]], ["[I{9}-III-10 ] pages 159-177", [18]]]] Type: [III*-I{9}-10], p. 176 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 - 1595845325952240 02*x^4 + 2183814375991796599109312252794185951*x^3 - 54737494680161832686*x^ 2 + 13841287544*x, [7, [6, [Mod(6, 7)]], ["(tame) [I{9}-III*-10] page 176", [18]]]] [27, Mat([3, 3]), 12157665459056928801*x^5 - 6973568802*x^4 + 32825696739453 7097311*x^3 - 188286357654*x^2 + 531468*x, [3, [6, [Mod(0, 3)]], ["[I{9}-III *-10] pages 159-177", [18]]]] Type: [III-I*{9}-10], p. 177 [2401, Mat([7, 4]), x^6 + 4*x^5 + 44567640326363195900190047951894732*x^4 + 267405841958179175401140283756715034*x^3 + 881247867777497128998513653865824 60699453771*x^2 + 528748722538339171106362420127476948226402066*x - 61687350 9628062366290756156815389740634465608, [7, [6, [Mod(6, 7)]], ["(tame) [I*{9} -III-10] page 177", [4, 2]]]] [81, Mat([3, 4]), x^6 + 36472996377170963544*x^4 + 72945992754341572814*x^3 + 6460972470237541785510147*x^2 + 12922163778453346599281658*x - 19383245667 680019897328164, [3, [6, [Mod(0, 3)]], ["[I*{9}-III-10] pages 159-177", [4, 2]]]] Type: [III*-I*{9}-10], p. 177 [2401, Mat([7, 4]), x^6 + 4*x^5 + 2183814375991796599109312254731159068*x^4 + 13102886255950779594655873524432301050*x^3 + 43181145521097359320927169039 42542282683541067*x^2 + 25908687404378619384211758586246368564860027954*x - 30226801971775055948247051683954096626707029144, [7, [6, [Mod(6, 7)]], ["(ta me) [I*{9}-III*-10] page 177", [4, 2]]]] [81, Mat([3, 4]), x^6 + 328256967394537254768*x^4 + 656513934789074155262*x^ 3 + 58148752232137876078094403*x^2 + 116299474006080119382197514*x - 1744492 11009120179071701948, [3, [6, [Mod(0, 3)]], ["[I*{9}-III*-10] pages 159-177" , [4, 2]]]] Type: [III*-I*{9}-(-1)], p. 177 [2401, Mat([7, 4]), 7*x^5 - 14*x^4 + 282475305*x^3 - 98*x^2 + 1977326792*x, [7, [6, [Mod(6, 7)]], ["(tame) [I*{9}-III*--1] page 177", [4, 2]]]] Type: [III-II{9}], p. 177 [343, Mat([7, 3]), x^6 - 2*x^5 + 40353608*x^4 + 7*x^2 - 14*x + 282475256, [7 , [2, [Mod(6, 7)]], ["(tame) [II{9}-III] page 177", [19]]]] Type: [III*-II{9}], p. 178 [343, Mat([7, 3]), x^6 - 2*x^5 + 5764802*x^4 + 343*x^2 - 686*x + 1977327086, [7, [2, [Mod(6, 7)]], ["(tame) [II{9}-III*] page 178", [19]]]] Type: [III*-II{0}], p. 178 [343, Mat([7, 3]), 7*x^6 + 49*x^4 + 49*x^2 + 343, [7, [2, [Mod(6, 7)]], ["(t ame) [II{0}-III*] page 178", []]]] Type: [III-II*{9}], p. 178 [2401, Mat([7, 4]), x^6 + 282475249*x^4 + 7*x^2 + 1977326743, [7, [2, [Mod(6 , 7)]], ["(tame) [II*{9}-III] page 178", [8]]]] Type: [III*-II*{9}], p. 178 [2401, Mat([7, 4]), 282475249*x^6 + 7*x^4 + 1977326743*x^2 + 49, [7, [2, [Mo d(6, 7)]], ["(tame) [II*{9}-III*] page 178", [8]]]] Type: [I{9-8-0}], p. 179 [49, Mat([7, 2]), x^5 + x^4 + 46118407*x^3 + 34588805*x^2 + 232630473633600* x - 232630554340814, [7, [3, []], ["(tame) [I{8-9-0}] page 179", [72]]]] Type: [I{9}-I{8}-10}], p. 179 [49, Mat([7, 2]), 6366805760909027985741435139224001*x^5 + 63668057609090278 26156902543999999*x^4 + 256923577521058878088611317639703031862407*x^3 + 256 923577521058871648799965597876173411195*x^2 - 6439811511393728899334400*x + 232630554340814, [7, [7, []], ["(tame) [I{8}-I{9}-10] page 179", [72]]]] Type: [I*{9-8-0}], p. 180 [2401, Mat([7, 4]), 7*x^5 + 7*x^4 + 322828849*x^3 + 242121635*x^2 + 16284133 15435200*x - 1628413880385698, [7, [3, []], ["(tame) [I*{8-9-0}] page 180", [4, 2, 2]]]] [81, Mat([3, 4]), 3*x^5 + 3*x^4 + 78729*x^3 + 39363*x^2 + 387361440*x - 3874 79538, [3, [3, []], ["(tame) [I*{8-9-0}] page 180", [4, 2, 2]]]] Type: [I*{9}-I*{8}-10], p. 180 [2401, Mat([7, 4]), 508021860739623365322188197652216501772434524836001*x^6 + 3556153025177363582722540427201627455372782230748011*x^5 + 100452521126907 9039999221712767258830172664699912235178878009*x^4 + 70316764788835533303515 71935604422778407017230014542438128339*x^3 + 3524991484034604193284089402685 37457526303138*x^2 + 311973470135837957969478408827349338*x + 23458926374545 651500, [7, [7, []], ["(tame) [I*{8}-I*{9}-10] page 180", [4, 2, 2]]]] Type: [I{9}-I*{8}-10], p. 180 [343, Mat([7, 3]), 6366805760909027985741435139224001*x^5 + 4456764032636319 5740605513379344005*x^4 + 1798465042647412146620279223477921223036843*x^3 + 12589255298531884981263281802603029551507501*x^2 - 3155507640582927177622370 94*x + 79792268274938744, [7, [7, []], ["(tame) [I{9}-I*{8}-10] page 180", [ 18, 2]]]] [27, Mat([3, 3]), 12157665459056928801*x^5 + 36472996370197217601*x^4 + 7178 97987691831668083527*x^3 + 2153693962663775502180501*x^2 - 1235345630247378* x + 3486961548, [3, [7, []], ["[I{9}-I*{8}-10] page 180", [18, 2]]]] Type: [2I{8}-10], p. 181 [343, Mat([7, 3]), x^6 + 1977326722*x^4 + 9387480337620071731394*x^2 + 18562 115855305211939015772541728, [7, [7, []], ["(tame) [2I{8}-10] page 181", [8] ]]] [27, Mat([3, 3]), x^6 + 177138*x^4 + 2541864765474*x^2 + 450276280295106672, [3, [7, []], ["[2I{8}-10] page 181", [8]]]] Type: [2I{9}-10}], p. 181 [343, Mat([7, 3]), x^6 + 1977326722*x^4 + 9387480337647754305649*x^3 - 27682 574255*x^2 + 18562115855305211938918883531664*x + 96889010064, [7, [7, []], ["(tame) [2I{9}-10] page 181", [9]]]] Type: [2I{8}-0], p. 181 [343, Mat([7, 3]), x^6 - 7*x^4 + 117600*x^2 + 823886, [7, [3, []], ["(tame) [2I{8}-0] page 181", [8]]]] Type: [2I{9}-0], p. 181 [343, Mat([7, 3]), x^6 - 7*x^4 + 117649*x^3 - 49*x^2 + 823543*x + 343, [7, [ 3, []], ["(tame) [2I{9}-0] page 181", [9]]]] Type: [2I*{8}-10}], p. 181 [2401, Mat([7, 4]), x^6 + 1977326743*x^5 - 21*x^4 - 27682574402*x^3 + 657123 62363534280139690*x^2 + 129934811447123020117269034708856*x - 45998653654473 9960977144, [7, [7, []], ["(tame) [2I*{8}-10] page 181", [2, 2]]]] [81, Mat([3, 4]), x^6 + 177147*x^5 - 9*x^4 - 1062882*x^3 + 7625597485014*x^2 + 1350851717674586412*x - 22876792454988, [3, [7, []], ["[2I*{8}-10] pages 159, 181", [2, 2]]]] Type: [2I*{9}-10}], p. 181 [2401, Mat([7, 4]), x^6 + 1977326743*x^5 - 21*x^4 + 65712362363506597565141* x^3 + 129934811447123020117172145698596*x^2 - 459986536544643071966394*x - 3 43, [7, [7, []], ["(tame) [2I*{9}-10] page 181", [4]]]] Type: [II{9-8}], p. 182 [343, Mat([7, 3]), x^6 - 2*x^5 + 46118416*x^4 - 80707228*x^3 + 2326308771696 77*x^2 - 564950498*x + 1628413880385698, [7, [3, []], ["[II{9-8}] page 182", [36]]]] [27, Mat([3, 3]), x^6 - 2*x^5 + 26248*x^4 - 39372*x^3 + 129238581*x^2 - 1180 98*x + 387479538, [3, [3, []], ["[II{9-8}] page 182", [36]]]] Type: [III{8}], p. 182 [2401, Mat([7, 4]), 2402*x^5 - 14*x^3 + 49*x, [7, [3, []], ["(tame) [III{8}] page 182", [2, 2]]]] Type: [III{9}], p. 182 [2401, Mat([7, 4]), x^5 + 16807*x^4 - 14*x^3 + 49*x, [7, [3, []], ["(tame) [ III{9}] page 182", [4]]]] Type: [I{9-8-5}], pp. 182-183 [49, Mat([7, 2]), x^6 - 6*x^5 + 46135228*x^4 - 265214472*x^3 + 2334061737433 69*x^2 - 931878986337810*x + 3910752249023424154, [7, [4, []], ["(tame) [I{5 -8-9}] page 182", [157]]]] Type: [I*{9-8-5}], pp. 183 [2401, Mat([7, 4]), 7*x^6 - 42*x^5 + 322946596*x^4 - 1856501304*x^3 + 163384 3216203583*x^2 - 6523152904364670*x + 27375265743163969078, [7, [4, []], ["( tame) [I*{5-8-9}] page 183", [4, 4]]]] Type: [II{9-8}], p. 183 [343, Mat([7, 3]), x^6 - 2*x^5 + 5764788*x^4 + 28*x^3 - 80589530*x^2 - 23539 6*x + 678505665796, [7, [4, []], ["(tame) [II{9-8}] page 183", [44]]]] [27, Mat([3, 3]), x^6 - 2*x^5 + 6556*x^4 + 12*x^3 - 38634*x^2 - 1476*x + 484 2756, [3, [4, []], ["(tame) [II{9-8}] page 183", [44]]]] Type: [II{9-9}], p. 183 [343, Mat([7, 3]), x^6 - 2*x^5 + 5764788*x^4 + 117677*x^3 - 80942477*x^2 + 6 78223190400*x + 282475298, [7, [4, []], ["(tame) [II{9-9}] page 183", [45]]] ] [27, Mat([3, 3]), x^6 - 2*x^5 + 6556*x^4 + 741*x^3 - 40821*x^2 + 4783680*x + 59058, [3, [4, []], ["(tame) [II{9-9}] page 183", [45]]]] Type: [II*{9-8}], p. 184 [343, Mat([7, 3]), 7*x^6 - 14*x^5 + 40353516*x^4 + 196*x^3 - 564126710*x^2 - 1647772*x + 4749539660572, [7, [4, []], ["(tame) [II*{9-8}] page 184", [8]] ]] Type: [II*{9-9}], p. 184 [343, Mat([7, 3]), 7*x^6 - 14*x^5 + 40353516*x^4 + 823739*x^3 - 566597339*x^ 2 + 4747562332800*x + 1977327086, [7, [4, []], ["(tame) [II*{9-9}] page 184" , [9]]]] Type: [III{12}], p. 184 [2401, Mat([7, 4]), x^6 - 14*x^3 + 117698, [7, [4, []], ["[III{12}] page 184 ", [3, 3]]]] [59049, Mat([3, 10]), x^6 - 6*x^3 + 738, [3, [4, []], ["[III{12}] page 184", [3, 3]]]] Type: [III{13}], p. 184 [2401, Mat([7, 4]), x^6 - 14*x^3 + 117649*x + 49, [7, [4, []], ["[III{13}] p age 184", [9]]]] [59049, Mat([3, 10]), x^6 - 6*x^3 + 729*x + 9, [3, [4, []], ["[III{13}] page 184", [9]]]] Type: [III{14}], p. 184 [2401, Mat([7, 4]), x^6 - 14*x^3 + 117649*x^2 + 49, [7, [4, []], ["[III{14}] page 184", [9]]]] [59049, Mat([3, 10]), x^6 - 6*x^3 + 729*x^2 + 9, [3, [4, []], ["[III{14}] pa ge 184", [9]]]] Type: [III*{6}], p. 184 [2401, Mat([7, 4]), 7*x^6 - 98*x^3 + 17150, [7, [4, []], ["[III*{6}] page 18 4", []]]] [59049, Mat([3, 10]), 3*x^6 - 18*x^3 + 270, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[III*{6}] page 184", []]]] Type: [III*{7}], p. 184 [2401, Mat([7, 4]), 7*x^6 - 98*x^3 + 16807*x + 343, [7, [4, []], ["[III*{7}] page 184", []]]] [59049, Mat([3, 10]), 3*x^6 - 18*x^3 + 243*x + 27, [3, [5, [Mod(0, 3), Mod(0 , 3)]], ["[III*{7}] page 184", []]]] Type: [III{8}], p. 184 [2401, Mat([7, 4]), x^6 - 14*x^3 + 2401*x^2 + 49, [7, [4, []], ["[III{8}] pa ge 184", [9]]]] [59049, Mat([3, 10]), x^6 - 6*x^3 + 81*x^2 + 9, [3, [5, [Mod(0, 3), Mod(0, 3 )]], ["[III{8}] page 184", [9]]]] echo = 1 ? genus2red(-x^6-6*x^2-7,3) [81, Mat([3, 4]), -x^6 - 6*x^2 - 7, [3, [7, []], ["(tame) [I*{1}-I*{1}-0] pa ge 180", [4, 4]]]] ? genus2red(-9*x^6+6*x^5-8*x^4-5*x^3+5*x^2-10*x+3,3) [9, Mat([3, 2]), -9*x^6 + 6*x^5 - 8*x^4 - 5*x^3 + 5*x^2 - 10*x + 3, [3, [3, []], ["(tame) [I{2-8-0}] page 179", [8, 2]]]] ? genus2red(3*x^6+3*x^4+3*x^3+x^2-5*x-5,3) [27, Mat([3, 3]), -5*x^6 - 5*x^5 + x^4 + 3*x^3 + 3*x^2 + 3, [3, [2, [Mod(0, 3)]], ["(tame) [II{4}-III] page 177", [9]]]] ? genus2red(-3*x^6+6*x^5-1*x^4+6*x^3-6*x^2-1*x-6,3) [3, Mat([3, 1]), -2187*x^6 - 2430*x^5 - 1089*x^4 - 242*x^3 - 26*x^2 - x, [3, [6, [Mod(2, 3)]], ["(tame) [I{0}-I{1}-1] page 170", []]]] ? genus2red((x^3+2*x+1)*(x^3+3^2*x^2+3^8),3) [3, Mat([3, 1]), 729*x^6 + 729*x^5 + 18*x^4 + 6580*x^3 + x^2 + 162*x + 9, [3 , [6, [Mod(1, 3)]], ["(tame) [I{0}-I{2}-1] page 170", [2]]]] ? P=x^6+4*x^5-24*x^4-16*x^3-52*x^2-48*x; ? genus2red(P,3) [9, Mat([3, 2]), 729*x^6 + 2268*x^5 + 2664*x^4 + 1520*x^3 + 428*x^2 + 48*x, [3, [7, []], ["(tame) [I{2}-I{2}-1] page 179", [2, 2]]]] ? P=x^6+4*x^5+24*x^4+32*x^3+56*x^2+48*x+24; ? genus2red(P,3) [9, Mat([3, 2]), 729*x^6 + 2268*x^5 + 3096*x^4 + 2336*x^3 + 1016*x^2 + 240*x + 24, [3, [7, []], ["(tame) [I{1}-I{1}-1] page 179", []]]] ? P=24*x^5+56*x^4+76*x^3+33*x^2-4*x-20; ? genus2red(P,3) [9, Mat([3, 2]), 1944*x^5 + 5904*x^4 + 7196*x^3 + 4397*x^2 + 1346*x + 165, [ 3, [7, []], ["(tame) [I{2}-I{2}-1] page 179", [2, 2]]]] ? P=-3*x^6+6*x^5-25*x^4+36*x^3-69*x^2+38*x-39; ? genus2red(P,3) [9, Mat([3, 2]), -2187*x^6 - 6804*x^5 - 9000*x^4 - 6464*x^3 - 2656*x^2 - 592 *x - 56, [3, [7, []], ["(tame) [I{1}-I{1}-1] page 179", []]]] ? P=-5*x^5+5*x^4+10*x^3-7; ? genus2red([P,1],3) [9, Mat([3, 2]), -1620*x^5 - 2520*x^4 - 1520*x^3 - 440*x^2 - 60*x - 3, [3, [ 7, []], ["(tame) [I{1}-I{2}-1] page 179", [2]]]] ? P=-5*x^6-3*x^5-10*x^4-10*x^3-7; ? genus2red([P,1],3) [3, Mat([3, 1]), -14580*x^6 - 59292*x^5 - 100800*x^4 - 91720*x^3 - 47120*x^2 - 12960*x - 1491, [3, [6, [Mod(1, 3)]], ["(tame) [I{0}-I{1}-1] page 170", [ ]]]] ? P=3*x^5+5*x^4+5*x-4; ? genus2red([P,1],3) [3, Mat([3, 1]), 972*x^5 + 1260*x^4 + 640*x^3 + 160*x^2 + 20*x + 1, [3, [6, [Mod(1, 3)]], ["(tame) [I{0}-I{2}-1] page 170", [2]]]] ? Q=x^2+x;P=-9*x^6+6*x^5-8*x^4-5*x^3+5*x^2-10*x+3; ? genus2red([P,Q],3) [3, Mat([3, 1]), -26244*x^6 - 138024*x^5 - 302679*x^4 - 354290*x^3 - 233475* x^2 - 82136*x - 12052, [3, [6, [Mod(0, 3)]], ["(tame) [I{0}-I{12}-1] page 17 0", [12]]]] ? Q=x^3+1;P=-7*x^6+5*x^3+5*x^2-6*x+1; ? genus2red([P,Q],3) [3, Mat([3, 1]), -27*x^6 + 22*x^3 + 20*x^2 - 24*x + 5, [3, [6, [Mod(2, 3)]], ["(tame) [I{0}-I{1}-1] page 170", []]]] ? genus2red(27*x^5+97*x^4+118*x^3+60*x^2+13*x+1,3) [729, Mat([3, 6]), 27*x^5 + 367*x^4 + 1974*x^3 + 5256*x^2 + 6933*x + 3627, [ 3, [6, [Mod(0, 3)]], ["[IV-II{6}] page 175", [20]]]] ? genus2red([-x^6-3*x^4-10*x^2-1,x],3) [729, Mat([3, 6]), -4*x^6 - 12*x^4 - 39*x^2 - 4, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[IV*-IV*-0] pages 160-175", [3, 3]]]] ? genus2red([-60*x^6-203*x^5-291*x^4-244*x^3-129*x^2-41*x-7,x^3+x^2+x+1]) [729, [2, -1; 3, 6], -239*x^6 - 810*x^5 - 1161*x^4 - 972*x^3 - 513*x^2 - 162 *x - 27, [[2, [5, [Mod(0, 2), Mod(0, 2)]], []], [3, [5, [Mod(0, 3), Mod(0, 3 )]], ["[2IV*-0] page 165", [3]]]]] ? genus2red(6*x^6+5*x^4+x^2+1,7) [2401, Mat([7, 4]), 6*x^6 + 180*x^5 + 2255*x^4 + 15100*x^3 + 57001*x^2 + 115 010*x + 96901, [7, [5, [Mod(0, 7), Mod(0, 7)]], ["(tame) [II-II-0] page 163" , []]]] ? genus2red([1,x^3-1]) [18225, [3, 6; 5, 2], x^6 - 2*x^3 + 5, [[3, [5, [Mod(0, 3), Mod(0, 3)]], ["[ II-II-0] pages 159-174", []]], [5, [5, [Mod(0, 5), Mod(0, 5)]], ["[I{0}-II-0 ] page 159", []]]]] ? genus2red(x^5+1/5,5) [1953125, Mat([5, 9]), 5*x^6 + 25*x, [5, [1, []], ["[VIII-4] page 157", []]] ] ? genus2red(273*x^6-38933/5*x^5-4483763/4*x^4+371954149/10*x^3+569046245/4*x^2+12389355*x-42117075,5) [125, Mat([5, 3]), 682500*x^6 - 3893300*x^5 - 112094075*x^4 + 743908298*x^3 + 569046245*x^2 + 9911484*x - 6738732, [5, [6, [Mod(3, 5)]], ["(tame) [I{4}- I*{0}-0] page 170", [4, 2, 2]]]] ? genus2red(177*x^6+126*x^5-63*x^4+72*x+84,3) [729, Mat([3, 6]), 1593*x^6 + 6750*x^5 + 11817*x^4 + 10952*x^3 + 5672*x^2 + 1560*x + 180, [3, [6, [Mod(0, 3)]], ["[I{5}-IV*-0] pages 159-177", [15]]]] ? genus2red(3*(4*x^6+6*x^5+3*x^4+8*x^3+9*x^2-3),3) [59049, Mat([3, 10]), 108*x^6 + 270*x^5 + 279*x^4 + 160*x^3 + 57*x^2 + 12*x + 1, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[II-IV*-0] pages 159-174", [3]]]] ? genus2red(x^6+27,3) [81, Mat([3, 4]), x^6 + 27, [3, [5, [Mod(0, 3), Mod(0, 3)]], ["[2I*{0}-0] pa ges 159, 181", [2, 2]]]] ? print("Total time spent: ",gettime); Total time spent: 72 pari-2.11.2/src/test/32/nffactor0000644000175000017500000014502613447371554014722 0ustar billbill *** Warning: new stack size = 16000000 (15.259 Mbytes). [x^72 - 291*x^70 + 168*x^69 + 40380*x^68 - 48588*x^67 - 3528919*x^66 + 66721 20*x^65 + 215657160*x^64 - 575538144*x^63 - 9642387423*x^62 + 34735086786*x^ 61 + 318475831783*x^60 - 1543992152304*x^59 - 7526047084203*x^58 + 517099213 23996*x^57 + 110268119466273*x^56 - 1306863903654948*x^55 - 197687339387338* x^54 + 24340617020480994*x^53 - 37674206381844006*x^52 - 309388136734870296* x^51 + 1097175021601270233*x^50 + 1965430743178095924*x^49 - 170577413076819 44498*x^48 + 12695705864721864408*x^47 + 149941210123858078557*x^46 - 449449 010694960248724*x^45 - 360137445013361079753*x^44 + 4743771886303072354536*x ^43 - 7957480107528139931362*x^42 - 20006312987061736459890*x^41 + 103127662 005251951018025*x^40 - 57922725775374790826892*x^39 - 5753749773364770608784 06*x^38 + 1141042155363070337681952*x^37 + 2107623272811930164219492*x^36 - 8555883275792119671168984*x^35 - 6622038332271478648217502*x^34 + 6778849907 3804904961005264*x^33 - 62194621346216574281355513*x^32 - 298503076979390816 950994616*x^31 + 935868776923024509133161567*x^30 - 602191893688026944562387 144*x^29 - 2378403718028116295265005703*x^28 + 7144715267789671188060423636* x^27 - 8264313767410946129053876314*x^26 - 2988303993119955116599622124*x^25 + 36320303706133493815706370331*x^24 - 93405543373036036850518472592*x^23 + 137892731303549623166716872621*x^22 - 73374564495372153466268524626*x^21 - 180690507689854149951443988039*x^20 + 506199649638427572646328975856*x^19 - 511453665473658325356669209047*x^18 - 183193264910244539106552118338*x^17 + 1423840911419731272911578335897*x^16 - 2367314022969857609246689985844*x^15 + 2236677523353346112926136338695*x^14 - 1548489683091587051973217338168*x^1 3 + 2105049137205776145162583648404*x^12 - 4754348311294629767834593856064*x ^11 + 7567806891220394207855512254933*x^10 - 7605431066578089163623568649610 *x^9 + 3882625664788999249342771140339*x^8 + 1356469287400668040516453202076 *x^7 - 3841355512345259545848813224621*x^6 + 2330504083587501732658867007532 *x^5 - 169172628407290891217225606775*x^4 - 398965703199322569698936377044*x ^3 + 198978398979453484569202793808*x^2 - 60597282938946837445378411698*x + 12280639561039083425818958713]~ [x^48 + 12*x^46 + 948*x^44 + 7200*x^42 + 152361*x^40 + 815832*x^38 + 9475380 *x^36 + 44654004*x^34 + 299137536*x^32 + 1335241260*x^30 + 5029216452*x^28 + 15282825984*x^26 + 37737671337*x^24 + 79579803672*x^22 + 143658877428*x^20 + 222699104460*x^18 + 303698198961*x^16 + 348787956312*x^14 + 312863646960*x ^12 + 212893847424*x^10 + 111407984496*x^8 + 43762394880*x^6 + 11836253952*x ^4 + 1904684544*x^2 + 136048896]~ [x^48 - 104*x^46 + 4664*x^44 - 122476*x^42 + 2137838*x^40 - 26567700*x^38 + 245144964*x^36 - 1725955872*x^34 + 9441692003*x^32 - 40611588644*x^30 + 1383 56971048*x^28 - 374714866240*x^26 + 807289826646*x^24 - 1380693858220*x^22 + 1866021172640*x^20 - 1978766780068*x^18 + 1630151673857*x^16 - 102950530102 4*x^14 + 489498952012*x^12 - 170832297056*x^10 + 42133382284*x^8 - 690450713 6*x^6 + 669868016*x^4 - 28899680*x^2 + 16]~ [x^64 - 6384*x^62 + 18261761*x^60 - 31231019568*x^58 + 35925400902280*x^56 - 29635423138225800*x^54 + 18244443900381139917*x^52 - 8609789775431197305288 *x^50 + 3173715440318358526295493*x^48 - 926253189958924421506713024*x^46 + 216130107574547887816493973792*x^44 - 40600173780591579547211667354912*x^42 + 6168621134132051706341715912515370*x^40 - 76013943427734813586799139295141 5744*x^38 + 76052955647065900426700689494084391434*x^36 - 617531184355441677 2593815034596603661344*x^34 + 406137362468726923132369140307868626461744*x^3 2 - 21559959594011538596615817038079394912524336*x^30 + 91912201022866770299 8458013093798368177514170*x^28 - 3125139901367629320825272825691018301064633 1888*x^26 + 840017792466500823059432352741453680599704357258*x^24 - 17651171 087877975905738341268934550365403253370816*x^22 + 28594069425611136664663397 3109729677687028435758880*x^20 - 3510138236669349338216717168753743720690200 440965920*x^18 + 31970659328447652254136627725804141367170891626180389*x^16 - 210577501276259853380917767547980363666145460503950096*x^14 + 972633665701 140285445722173171004563157651576027463941*x^12 - 30387893683293821798844628 51269146550248145196800679728*x^10 + 615892792889658839667059092889638564907 5890120481042824*x^8 - 76951350792700777906576936340585240393085356418600329 04*x^6 + 5510293734552561962521574495431679567021222445632508873*x^4 - 19987 78331104544904932086470347413669495129560426038280*x^2 + 2738927449953408337 77347939263771534786080723599733441]~ [x^8 + (-1531349/22619785297920*y^14 + 559416343/10977248747520*y^12 - 25247 684591/1995863408640*y^10 + 103982297321/80715064320*y^8 - 76714376249/12229 55520*y^6 + 111774992009/74186640*y^4 - 26292202739/1686060*y^2 + 1564021312 /54549)*x^6 + (19000645309/37322645741568*y^14 - 96552535399/249482926080*y^ 12 + 536960987254321/5488624373760*y^10 - 4194944378809/407651840*y^8 + 5247 721708074653/10089383040*y^6 - 10860233882239/843030*y^4 + 630194805031381/4 636665*y^2 - 796961577488/2755)*x^4 + (-29172555558095/18661322870784*y^14 + 5062445860141/4248161280*y^12 - 92318704732060083/304923576320*y^10 + 64819 3176741591037/20178766080*y^8 - 8268979844194150111/5044691520*y^6 + 1896413 90835405983/4636665*y^4 - 223283186783900366/515185*y^2 + 8946625664367872/9 405)*x^2 + (41018074761203773/23326653588480*y^14 - 409009053454624763/30492 3576320*y^12 + 117044119382956746521/343039023360*y^10 - 2927890424340695147 291/80715064320*y^8 + 4678762405288733527739/2522345760*y^6 - 38206315875334 762391/824296*y^4 + 2278645136881067296952/4636665*y^2 - 2967400235256172868 48/272745), x^8 + (-16146091/248817638277120*y^14 + 48843457/997931704320*y^ 12 - 267727721489/21954497495040*y^10 + 9174250019/7337733120*y^8 - 82557283 8631/13452510720*y^6 + 10012035071/6744240*y^4 - 286258292621/18546660*y^2 + 140187040/4959)*x^6 + (1723176289/3392967794688*y^14 - 1059662276341/274431 2186880*y^12 + 48715274000629/498965852160*y^10 - 69104247053959/6726255360* y^8 + 476508837255737/917216640*y^6 - 238731150890387/18546660*y^4 + 5725141 8840649/421515*y^2 - 26269467866896/90915)*x^4 + (-29113232197835/1866132287 0784*y^14 + 1631934517436717/1372156093440*y^12 - 92145545361015407/30492357 6320*y^10 + 323550303468175019/10089383040*y^8 - 8257197132303274099/5044691 520*y^6 + 378862459377191059/9273330*y^4 - 223115572203411654/515185*y^2 + 2 59332507639972352/272745)*x^2 + (40511288842122127/23326653588480*y^14 - 454 626079701495571/343039023360*y^12 + 231451885839430725263/686078046720*y^10 - 60389017554715183063/1681563840*y^8 + 2319938341838169992923/1261172880*y^ 6 - 42704610621363386060/927333*y^4 + 2268063476824046324248/4636665*y^2 - 9 8528590048656718144/90915), x^8 + (181633/186613228707840*y^14 - 6489/138601 62560*y^12 - 45386471/5488624373760*y^10 + 178250659/7337733120*y^8 - 259150 32257/10089383040*y^6 + 126060163/1498720*y^4 - 4457231129/4636665*y^2 + 945 4484/4959)*x^6 + (-11712673/1169988894720*y^14 + 2040142733/274431218688*y^1 2 - 93021416071/52522721280*y^10 + 1688263641205/10762008576*y^8 - 890698149 9371/1834433280*y^6 + 14859994827859/296746560*y^4 - 27539242721/421515*y^2 - 10412804654/90915)*x^4 + (-65739851389/2915831698560*y^14 + 8080067384671/ 548862437376*y^12 - 615919067582923/228692682240*y^10 + 7139625968047/558581 76*y^8 - 12035658240536459/5044691520*y^6 + 2909281718459207/148373280*y^4 - 114027481266257/1545555*y^2 + 26994839222348/272745)*x^2 + (351875661187594 13/746452914831360*y^14 - 175794408000830383/5488624373760*y^12 + 2827285081 9680893321/4390899499008*y^10 - 44274526240947916361/107620085760*y^8 + 4488 83263777097920391/40357532160*y^6 - 2698220779200958903/20465280*y^4 + 28100 59487221296958/4636665*y^2 - 81508587175798061/90915), x^8 + (3074279/248817 638277120*y^14 - 127157047/10977248747520*y^12 + 86499746437/21954497495040* y^10 - 2843672497/4747944960*y^8 + 109487803351/2690502144*y^6 - 89990421617 /74186640*y^4 + 52396810109/3709332*y^2 - 13670576288/272745)*x^6 + (-361812 87281/186613228707840*y^14 + 446988241097/2744312186880*y^12 - 2791944232079 /57774993408*y^10 + 85916604196211/13452510720*y^8 - 3999057670537517/100893 83040*y^6 + 3070998321176/272745*y^4 - 593787426492949/4636665*y^2 + 3730615 4735728/90915)*x^4 + (64206977604683/93306614353920*y^14 - 781339956430123/1 372156093440*y^12 + 151234315443075961/914770728960*y^10 - 42955239518225908 7/20178766080*y^8 + 1307386034599317571/1008938304*y^6 - 168786176615470804/ 4636665*y^4 + 127255299187877218/309111*y^2 - 351207138657683456/272745)*x^2 + (-18530706211095341/23326653588480*y^14 + 1798847927551103773/27443121868 80*y^12 - 16252626552763832987/85759755840*y^10 + 653145277562478020663/2690 5021440*y^8 - 742591759365166575365/504469152*y^6 + 1530656313511014482581/3 7093320*y^4 - 432314981823305760184/927333*y^2 + 131680859590220167616/90915 ), x^8 + (3692011/248817638277120*y^14 - 8644699/645720514560*y^12 + 9566281 9793/21954497495040*y^10 - 51309940321/80715064320*y^8 + 113348313275/269050 2144*y^6 - 91885783933/74186640*y^4 + 53072545513/3709332*y^2 - 13761686272/ 272745)*x^6 + (-1260198851/6434938920960*y^14 + 450923192773/2744312186880*y ^12 - 53418556138459/1097724874752*y^10 + 43167277559347/6726255360*y^8 - 40 11960654104563/10089383040*y^6 + 209270128922867/18546660*y^4 - 594571618949 411/4636665*y^2 + 37329116221552/90915)*x^4 + (3385038072653/4910874439680*y ^14 - 782493705352717/1372156093440*y^12 + 151409707529271949/914770728960*y ^10 - 214941552982993939/10089383040*y^8 + 1308011461994334679/1008938304*y^ 6 - 337682297591934347/9273330*y^4 + 127297072825004458/309111*y^2 - 3513766 27887928064/272745)*x^2 + (-18884591927033039/23326653588480*y^14 + 76223129 967189533/114346341120*y^12 - 131815203944675271599/686078046720*y^10 + 1236 67566697208858791/5044691520*y^8 - 373763922533488473487/252234576*y^6 + 116 278861122276976/2805*y^4 - 433850608352102566712/927333*y^2 + 39636262539108 2293312/272745), x^8 + (1192483/67859355893760*y^14 - 46386469/3659082915840 *y^12 + 5757671539/1995863408640*y^10 - 9816397597/40357532160*y^8 + 3150430 0903/3668866560*y^6 - 6499115329/49457760*y^4 + 1346529151/1686060*y^2 - 127 928104/54549)*x^6 + (-377107043/23326653588480*y^14 + 1193294195/99793170432 *y^12 - 3898646479517/1372156093440*y^10 + 83324546651/326121472*y^8 - 90270 807160297/10089383040*y^6 + 203979621263/1586880*y^4 - 6453521496733/9273330 *y^2 + 3740713928/2755)*x^4 + (-55838547409/2455437219840*y^14 + 81535888034 65/548862437376*y^12 - 1244323126435859/457385364480*y^10 + 2090484253417429 /16143012864*y^8 - 12134063030016491/5044691520*y^6 + 165453933807769/872784 0*y^4 - 93498888636323/1545555*y^2 + 14213849400992/272745)*x^2 + (118472423 79734429/248817638277120*y^14 - 177668994581955997/5488624373760*y^12 + 2861 1858755746067827/4390899499008*y^10 - 134874618655070911657/322860257280*y^8 + 152404618518667558583/13452510720*y^6 - 4203829397104185047/31236480*y^4 + 2871462472553380217/4636665*y^2 - 250004160368295232/272745), x^8 + (64582 73/186613228707840*y^14 - 3719191/152461788160*y^12 + 29024100473/5488624373 760*y^10 - 32135840999/80715064320*y^8 + 23297956603/2017876608*y^6 - 211350 0871/16485920*y^4 + 408266029/927333*y^2 - 316594868/272745)*x^6 + (-1110768 17459/373226457415680*y^14 + 18106275053/85759755840*y^12 - 509560146214411/ 10977248747520*y^10 + 195109797344857/53810042880*y^8 - 2298235154532701/201 78766080*y^6 + 87655160117623/59349312*y^4 - 32564739888281/4636665*y^2 + 96 8008850258/90915)*x^4 + (83518124920963/93306614353920*y^14 - 91728776500189 /144437483520*y^12 + 42591591062192407/304923576320*y^10 - 88154696029372417 3/80715064320*y^8 + 86773202255301785/252234576*y^6 - 665429827885409833/148 373280*y^4 + 2218979482348247/103037*y^2 - 8878201815711796/272745)*x^2 + (- 246642305436057809/248817638277120*y^14 + 3860028638255806541/5488624373760* y^12 - 3395672666468176433467/21954497495040*y^10 + 3904062052800146734661/3 22860257280*y^8 - 1024736920815948655471/2690502144*y^6 + 294713641271965414 9381/593493120*y^4 - 22118315020431326588/927333*y^2 + 9833627869746746873/2 72745), x^8 + (38996983/746452914831360*y^14 - 45610777/1219694305280*y^12 + 184040442823/21954497495040*y^10 - 6929849477/10089383040*y^8 + 19138097395 1/8071506432*y^6 - 6002605199/16485920*y^4 + 8595505583/3709332*y^2 - 144096 9832/272745)*x^6 + (-56627432063/186613228707840*y^14 + 1182421824943/548862 4373760*y^12 - 260406121516747/5488624373760*y^10 + 200262331426543/53810042 880*y^8 - 297480952643123/2522345760*y^6 + 92330503999361/59349312*y^4 - 710 13869059163/9273330*y^2 + 1098811062152/90915)*x^4 + (83613652919587/9330661 4353920*y^14 - 1744863264395929/2744312186880*y^12 + 42642092214501583/30492 3576320*y^10 - 882655350615967327/80715064320*y^8 + 173789516969368021/50446 9152*y^6 - 666541614309814567/148373280*y^4 + 2223816735480437/103037*y^2 - 306949426473056/9405)*x^2 + (-742452471836109913/746452914831360*y^14 + 3873 208908206849579/5488624373760*y^12 - 3407275945042823422193/21954497495040*y ^10 + 1305807204358253484253/107620085760*y^8 - 3084740075192713038863/80715 06432*y^6 + 173955024027274456667/34911360*y^4 - 22194121937138006191/927333 *y^2 + 3289110492164463424/90915)]~ [x^2 + (-872560111/1750783970525184*y^18 - 103213549/291797328420864*y^16 - 4176139757/7204872306688*y^14 - 4416978655/10807308460032*y^12 - 13066402491 575/72949332105216*y^10 - 215588492387/1736888859648*y^8 - 892238763206647/1 09423998157824*y^6 - 89512294102405/18237333026304*y^4 - 18290521472141/2532 96292032*y^2 - 284080544581/14072016224), x^2 + (872560111/1750783970525184* y^18 - 103213549/291797328420864*y^16 + 4176139757/7204872306688*y^14 - 4416 978655/10807308460032*y^12 + 13066402491575/72949332105216*y^10 - 2155884923 87/1736888859648*y^8 + 892238763206647/109423998157824*y^6 - 89512294102405/ 18237333026304*y^4 + 18290521472141/253296292032*y^2 - 284080544581/14072016 224), x^2 + (-10955729699/63028222938906624*y^19 + 1635275/72949332105216*y^ 17 - 471200483153/2334378627366912*y^15 + 68074817/2701827115008*y^13 - 1631 44665311371/2626175955787776*y^11 + 10788711995/1519777752192*y^9 - 10805585 507756651/3939263933681664*y^7 + 476476835441/4559333256576*y^5 - 6980744239 9435/3039555504384*y^3 - 4848316573/3518004056*y)*x + (-240314803/1313087977 893888*y^18 + 2177899/20842666315776*y^16 - 10352388961/48632888070144*y^14 + 650809375/5403654230016*y^12 - 3599460371687/54711999078912*y^10 + 2204400 27581/6079111008768*y^8 - 35061053609941/11723999802624*y^6 + 11692976745493 /9118666513152*y^4 - 1447968833323/63324073008*y^2 - 24126350651/7036008112) , x^2 + (-4768637809/63028222938906624*y^19 - 116295749/1750783970525184*y^1 7 - 205045552843/2334378627366912*y^15 - 4961577191/64843850760192*y^13 - 10 134809023919/375167993683968*y^11 - 1681738838629/72949332105216*y^9 - 46714 70958726025/3939263933681664*y^7 - 93324108785933/109423998157824*y^5 - 2896 7498100409/3039555504384*y^3 - 245294011997/84432097344*y)*x + (-496188853/1 750783970525184*y^18 + 8017631/48632888070144*y^16 - 338265737/1029267472384 *y^14 + 338938437/1801218076672*y^12 - 7349975872277/72949332105216*y^10 + 1 12959067435/2026370336256*y^8 - 471966038240125/109423998157824*y^6 + 558940 2408335/3039555504384*y^4 - 8241706316231/253296292032*y^2 + 1651761915/1005 144016), x^2 + (-550587305/9004031848415232*y^19 - 8520109/250111995789312*y ^17 - 165341932517/2334378627366912*y^15 - 2570761369/64843850760192*y^13 - 56851147336519/2626175955787776*y^11 - 895619999627/72949332105216*y^9 - 356 0831957116295/3939263933681664*y^7 - 62314525927891/109423998157824*y^5 - 18 560457963575/3039555504384*y^3 - 371119778467/84432097344*y)*x + (496188853/ 1750783970525184*y^18 + 8017631/48632888070144*y^16 + 338265737/102926747238 4*y^14 + 338938437/1801218076672*y^12 + 7349975872277/72949332105216*y^10 + 112959067435/2026370336256*y^8 + 471966038240125/109423998157824*y^6 + 55894 02408335/3039555504384*y^4 + 8241706316231/253296292032*y^2 + 1651761915/100 5144016), x^2 + (-21512837/1313087977893888*y^19 - 102134281/175078397052518 4*y^17 - 932348591/48632888070144*y^15 - 4407863827/64843850760192*y^13 - 16 4654686001/27355999539456*y^11 - 1540975821641/72949332105216*y^9 - 25030796 719091/82067998618368*y^7 - 110013175606897/109423998157824*y^5 - 7018393859 /2261574036*y^3 - 296247471259/28144032448*y)*x + (240314803/131308797789388 8*y^18 + 2177899/20842666315776*y^16 + 10352388961/48632888070144*y^14 + 650 809375/5403654230016*y^12 + 3599460371687/54711999078912*y^10 + 220440027581 /6079111008768*y^8 + 35061053609941/11723999802624*y^6 + 11692976745493/9118 666513152*y^4 + 1447968833323/63324073008*y^2 - 24126350651/7036008112), x^2 + (21512837/1313087977893888*y^19 + 102134281/1750783970525184*y^17 + 93234 8591/48632888070144*y^15 + 4407863827/64843850760192*y^13 + 164654686001/273 55999539456*y^11 + 1540975821641/72949332105216*y^9 + 25030796719091/8206799 8618368*y^7 + 110013175606897/109423998157824*y^5 + 7018393859/2261574036*y^ 3 + 296247471259/28144032448*y)*x + (240314803/1313087977893888*y^18 + 21778 99/20842666315776*y^16 + 10352388961/48632888070144*y^14 + 650809375/5403654 230016*y^12 + 3599460371687/54711999078912*y^10 + 220440027581/6079111008768 *y^8 + 35061053609941/11723999802624*y^6 + 11692976745493/9118666513152*y^4 + 1447968833323/63324073008*y^2 - 24126350651/7036008112), x^2 + (550587305/ 9004031848415232*y^19 + 8520109/250111995789312*y^17 + 165341932517/23343786 27366912*y^15 + 2570761369/64843850760192*y^13 + 56851147336519/262617595578 7776*y^11 + 895619999627/72949332105216*y^9 + 3560831957116295/3939263933681 664*y^7 + 62314525927891/109423998157824*y^5 + 18560457963575/3039555504384* y^3 + 371119778467/84432097344*y)*x + (496188853/1750783970525184*y^18 + 801 7631/48632888070144*y^16 + 338265737/1029267472384*y^14 + 338938437/18012180 76672*y^12 + 7349975872277/72949332105216*y^10 + 112959067435/2026370336256* y^8 + 471966038240125/109423998157824*y^6 + 5589402408335/3039555504384*y^4 + 8241706316231/253296292032*y^2 + 1651761915/1005144016), x^2 + (4768637809 /63028222938906624*y^19 + 116295749/1750783970525184*y^17 + 205045552843/233 4378627366912*y^15 + 4961577191/64843850760192*y^13 + 10134809023919/3751679 93683968*y^11 + 1681738838629/72949332105216*y^9 + 4671470958726025/39392639 33681664*y^7 + 93324108785933/109423998157824*y^5 + 28967498100409/303955550 4384*y^3 + 245294011997/84432097344*y)*x + (-496188853/1750783970525184*y^18 + 8017631/48632888070144*y^16 - 338265737/1029267472384*y^14 + 338938437/18 01218076672*y^12 - 7349975872277/72949332105216*y^10 + 112959067435/20263703 36256*y^8 - 471966038240125/109423998157824*y^6 + 5589402408335/303955550438 4*y^4 - 8241706316231/253296292032*y^2 + 1651761915/1005144016), x^2 + (1095 5729699/63028222938906624*y^19 - 1635275/72949332105216*y^17 + 471200483153/ 2334378627366912*y^15 - 68074817/2701827115008*y^13 + 163144665311371/262617 5955787776*y^11 - 10788711995/1519777752192*y^9 + 10805585507756651/39392639 33681664*y^7 - 476476835441/4559333256576*y^5 + 69807442399435/3039555504384 *y^3 + 4848316573/3518004056*y)*x + (-240314803/1313087977893888*y^18 + 2177 899/20842666315776*y^16 - 10352388961/48632888070144*y^14 + 650809375/540365 4230016*y^12 - 3599460371687/54711999078912*y^10 + 220440027581/607911100876 8*y^8 - 35061053609941/11723999802624*y^6 + 11692976745493/9118666513152*y^4 - 1447968833323/63324073008*y^2 - 24126350651/7036008112)]~ [x^24 + 69]~ [x^7 - 2*y*x^6 + y^2*x^5 - 28*x^3 + 4*y^2*x + 16/7*y^3, x^7 + 2*y*x^6 + y^2* x^5 - 28*x^3 + 4*y^2*x - 16/7*y^3, x^7 - 2/7*y^3*x^6 - y^2*x^5 - 28*x^3 - 4* y^2*x + 16*y, x^7 + 2/7*y^3*x^6 - y^2*x^5 - 28*x^3 - 4*y^2*x - 16*y]~ [x^2 + (-12035/386*y^15 + 8337/386*y^14 + 566267/772*y^13 - 392327/772*y^12 - 4449119/772*y^11 + 3083327/772*y^10 + 7320431/386*y^9 - 2537889/193*y^8 - 9975849/386*y^7 + 3461954/193*y^6 + 10712085/772*y^5 - 7445851/772*y^4 - 190 5321/772*y^3 + 1322419/772*y^2 + 25961/386*y - 17735/386), x^2 + (-7909/772* y^15 - 1879/772*y^14 + 93535/386*y^13 + 44921/772*y^12 - 371330/193*y^11 - 9 0974/193*y^10 + 4991389/772*y^9 + 317305/193*y^8 - 7127131/772*y^7 - 1947859 /772*y^6 + 2110371/386*y^5 + 1295397/772*y^4 - 224091/193*y^3 - 160649/386*y ^2 + 19739/772*y + 4029/386), x^2 + (7909/772*y^15 - 1879/772*y^14 - 93535/3 86*y^13 + 44921/772*y^12 + 371330/193*y^11 - 90974/193*y^10 - 4991389/772*y^ 9 + 317305/193*y^8 + 7127131/772*y^7 - 1947859/772*y^6 - 2110371/386*y^5 + 1 295397/772*y^4 + 224091/193*y^3 - 160649/386*y^2 - 19739/772*y + 4029/386), x^2 + (12035/386*y^15 + 8337/386*y^14 - 566267/772*y^13 - 392327/772*y^12 + 4449119/772*y^11 + 3083327/772*y^10 - 7320431/386*y^9 - 2537889/193*y^8 + 99 75849/386*y^7 + 3461954/193*y^6 - 10712085/772*y^5 - 7445851/772*y^4 + 19053 21/772*y^3 + 1322419/772*y^2 - 25961/386*y - 17735/386), x^4 + (541/386*y^14 - 12373/386*y^12 + 46089/193*y^10 - 137477/193*y^8 + 311469/386*y^6 - 14604 9/386*y^4 + 12308/193*y^2 - 686/193)*x^2 + (-765/772*y^14 + 8659/386*y^12 - 126401/772*y^10 + 90322/193*y^8 - 369401/772*y^6 + 38430/193*y^4 - 23865/772 *y^2 + 553/386), x^4 + (2052/193*y^14 - 96741/386*y^12 + 763031/386*y^10 - 1 265475/193*y^8 + 1759047/193*y^6 - 2000657/386*y^4 + 430823/386*y^2 - 13920/ 193)*x^2 + (-28293/772*y^14 + 166359/193*y^12 - 5225705/772*y^10 + 4295689/1 93*y^8 - 23400329/772*y^6 + 6320077/386*y^4 - 2369321/772*y^2 + 45727/386), x^4 + (-5155/193*y^15 - 15405/772*y^14 + 241769/386*y^13 + 180325/386*y^12 - 944044/193*y^11 - 2807115/772*y^10 + 3072303/193*y^9 + 2267740/193*y^8 - 41 02400/193*y^7 - 11896515/772*y^6 + 4334901/386*y^5 + 2988835/386*y^4 - 43236 3/193*y^3 - 1014845/772*y^2 + 23130/193*y + 3602/193)*x^2 + (14406/193*y^15 + 38997/772*y^14 - 338423/193*y^13 - 455769/386*y^12 + 2652454/193*y^11 + 70 72893/772*y^10 - 8698762/193*y^9 - 11354279/386*y^8 + 23683093/386*y^7 + 293 19183/772*y^6 - 13169735/386*y^5 - 7082173/386*y^4 + 3014249/386*y^3 + 21677 71/772*y^2 - 244333/386*y + 2027/386), x^4 + (-4705/193*y^15 - 4035/772*y^14 + 220691/386*y^13 + 47935/386*y^12 - 1722817/386*y^11 - 767525/772*y^10 + 5 588151/386*y^9 + 654320/193*y^8 - 3658160/193*y^7 - 3833005/772*y^6 + 341354 7/386*y^5 + 1159745/386*y^4 - 194425/386*y^3 - 441715/772*y^2 - 129025/386*y - 9518/193)*x^2 + (69045/772*y^15 + 17477/772*y^14 - 1634153/772*y^13 - 208 093/386*y^12 + 12990539/772*y^11 + 3347413/772*y^10 - 43749763/772*y^9 - 576 5109/386*y^8 + 62724993/772*y^7 + 17320883/772*y^6 - 37352513/772*y^5 - 5621 249/386*y^4 + 7969659/772*y^3 + 2742727/772*y^2 - 182407/772*y - 34007/386), x^4 + (4705/193*y^15 - 4035/772*y^14 - 220691/386*y^13 + 47935/386*y^12 + 1 722817/386*y^11 - 767525/772*y^10 - 5588151/386*y^9 + 654320/193*y^8 + 36581 60/193*y^7 - 3833005/772*y^6 - 3413547/386*y^5 + 1159745/386*y^4 + 194425/38 6*y^3 - 441715/772*y^2 + 129025/386*y - 9518/193)*x^2 + (-69045/772*y^15 + 1 7477/772*y^14 + 1634153/772*y^13 - 208093/386*y^12 - 12990539/772*y^11 + 334 7413/772*y^10 + 43749763/772*y^9 - 5765109/386*y^8 - 62724993/772*y^7 + 1732 0883/772*y^6 + 37352513/772*y^5 - 5621249/386*y^4 - 7969659/772*y^3 + 274272 7/772*y^2 + 182407/772*y - 34007/386), x^4 + (5155/193*y^15 - 15405/772*y^14 - 241769/386*y^13 + 180325/386*y^12 + 944044/193*y^11 - 2807115/772*y^10 - 3072303/193*y^9 + 2267740/193*y^8 + 4102400/193*y^7 - 11896515/772*y^6 - 433 4901/386*y^5 + 2988835/386*y^4 + 432363/193*y^3 - 1014845/772*y^2 - 23130/19 3*y + 3602/193)*x^2 + (-14406/193*y^15 + 38997/772*y^14 + 338423/193*y^13 - 455769/386*y^12 - 2652454/193*y^11 + 7072893/772*y^10 + 8698762/193*y^9 - 11 354279/386*y^8 - 23683093/386*y^7 + 29319183/772*y^6 + 13169735/386*y^5 - 70 82173/386*y^4 - 3014249/386*y^3 + 2167771/772*y^2 + 244333/386*y + 2027/386) ]~ [x^4 - 4*y*x^3 + (-1/2*y^14 + 1/2*y^10 - 7/2*y^6 + 15/2*y^2)*x^2 + (y^15 - y ^11 + 7*y^7 - 7*y^3)*x + (1/2*y^12 - y^8 + 5/2*y^4 - 2), x^4 + 4*y*x^3 + (-1 /2*y^14 + 1/2*y^10 - 7/2*y^6 + 15/2*y^2)*x^2 + (-y^15 + y^11 - 7*y^7 + 7*y^3 )*x + (1/2*y^12 - y^8 + 5/2*y^4 - 2), x^4 + (-2*y^11 - 10*y^3)*x^3 + (9/2*y^ 14 - 1/2*y^10 + 55/2*y^6 - 7/2*y^2)*x^2 + (3*y^13 + y^9 + 17*y^5 + 3*y)*x + (1/2*y^12 + y^8 + 5/2*y^4 + 4), x^4 + (2*y^11 + 10*y^3)*x^3 + (9/2*y^14 - 1/ 2*y^10 + 55/2*y^6 - 7/2*y^2)*x^2 + (-3*y^13 - y^9 - 17*y^5 - 3*y)*x + (1/2*y ^12 + y^8 + 5/2*y^4 + 4), x^4 + (-2*y^13 - 10*y^5)*x^3 + (1/2*y^14 - 1/2*y^1 0 + 7/2*y^6 - 15/2*y^2)*x^2 + (3*y^15 + y^11 + 17*y^7 + 3*y^3)*x + (1/2*y^12 - y^8 + 5/2*y^4 - 2), x^4 + (-y^13 - y^9 - 7*y^5 - 3*y)*x^3 + (7/2*y^14 - 1 /2*y^10 + 37/2*y^6 - 3/2*y^2)*x^2 + (-y^15 + y^11 - 7*y^7 + 7*y^3)*x + (-1/2 *y^12 - y^8 - 5/2*y^4 - 2), x^4 + (-y^13 + y^9 - 7*y^5 + 3*y)*x^3 + (-7/2*y^ 14 + 1/2*y^10 - 37/2*y^6 + 3/2*y^2)*x^2 + (-3*y^15 - y^11 - 17*y^7 - 3*y^3)* x + (-1/2*y^12 - y^8 - 5/2*y^4 - 2), x^4 + (y^13 - y^9 + 7*y^5 - 3*y)*x^3 + (-7/2*y^14 + 1/2*y^10 - 37/2*y^6 + 3/2*y^2)*x^2 + (3*y^15 + y^11 + 17*y^7 + 3*y^3)*x + (-1/2*y^12 - y^8 - 5/2*y^4 - 2), x^4 + (y^13 + y^9 + 7*y^5 + 3*y) *x^3 + (7/2*y^14 - 1/2*y^10 + 37/2*y^6 - 3/2*y^2)*x^2 + (y^15 - y^11 + 7*y^7 - 7*y^3)*x + (-1/2*y^12 - y^8 - 5/2*y^4 - 2), x^4 + (2*y^13 + 10*y^5)*x^3 + (1/2*y^14 - 1/2*y^10 + 7/2*y^6 - 15/2*y^2)*x^2 + (-3*y^15 - y^11 - 17*y^7 - 3*y^3)*x + (1/2*y^12 - y^8 + 5/2*y^4 - 2), x^4 + (-4*y^15 - 24*y^7)*x^3 + ( -9/2*y^14 + 1/2*y^10 - 55/2*y^6 + 7/2*y^2)*x^2 + (-y^13 + y^9 - 7*y^5 + 7*y) *x + (1/2*y^12 + y^8 + 5/2*y^4 + 4), x^4 + (-3*y^15 - y^11 - 17*y^7 - 7*y^3) *x^3 + (3/2*y^14 - 5/2*y^10 + 17/2*y^6 - 23/2*y^2)*x^2 + (3*y^13 + y^9 + 17* y^5 + 3*y)*x + (-1/2*y^12 + y^8 - 5/2*y^4 + 4), x^4 + (-3*y^15 + y^11 - 17*y ^7 + 7*y^3)*x^3 + (-3/2*y^14 + 5/2*y^10 - 17/2*y^6 + 23/2*y^2)*x^2 + (-y^13 + y^9 - 7*y^5 + 7*y)*x + (-1/2*y^12 + y^8 - 5/2*y^4 + 4), x^4 + (3*y^15 - y^ 11 + 17*y^7 - 7*y^3)*x^3 + (-3/2*y^14 + 5/2*y^10 - 17/2*y^6 + 23/2*y^2)*x^2 + (y^13 - y^9 + 7*y^5 - 7*y)*x + (-1/2*y^12 + y^8 - 5/2*y^4 + 4), x^4 + (3*y ^15 + y^11 + 17*y^7 + 7*y^3)*x^3 + (3/2*y^14 - 5/2*y^10 + 17/2*y^6 - 23/2*y^ 2)*x^2 + (-3*y^13 - y^9 - 17*y^5 - 3*y)*x + (-1/2*y^12 + y^8 - 5/2*y^4 + 4), x^4 + (4*y^15 + 24*y^7)*x^3 + (-9/2*y^14 + 1/2*y^10 - 55/2*y^6 + 7/2*y^2)*x ^2 + (y^13 - y^9 + 7*y^5 - 7*y)*x + (1/2*y^12 + y^8 + 5/2*y^4 + 4)]~ [x^64 + 192*x^62 + 17568*x^60 + 1019520*x^58 + 42131676*x^56 + 1319651424*x^ 54 + 32559096528*x^52 + 649228312512*x^50 + 10651553826426*x^48 + 1456394385 52224*x^46 + 1674922821206832*x^44 + 16307859539653056*x^42 + 13502367773216 7696*x^40 + 953248899971965824*x^38 + 5745239175305568960*x^36 + 29556064271 185194240*x^34 + 129595725382952883843*x^32 + 483002100692576612640*x^30 + 1 523870714370199019760*x^28 + 4047489983524093705152*x^26 + 89858128286488620 19536*x^24 + 16525310345394167002752*x^22 + 24893927149975603242048*x^20 + 3 0294355815129821928192*x^18 + 29274561574319887883226*x^16 + 219878017711043 40121824*x^14 + 12494344840480632094992*x^12 + 5187763623118143696192*x^10 + 1502211081063677383836*x^8 + 283567347515314680480*x^6 + 311461554388845258 72*x^4 + 1543354925530003776*x^2 + 8057044481403681]~ [x + (-7/16*y^29 - 5/32*y^25 - 97/8*y^21 - 139/32*y^17 - 435/16*y^13 - 323/3 2*y^9 - 21/4*y^5 - 77/32*y), x + (-11/32*y^29 - 1/8*y^25 - 309/32*y^21 - 55/ 16*y^17 - 797/32*y^13 - 7*y^9 - 355/32*y^5 + 9/16*y), x + (11/32*y^29 + 1/8* y^25 + 309/32*y^21 + 55/16*y^17 + 797/32*y^13 + 7*y^9 + 355/32*y^5 - 9/16*y) , x + (7/16*y^29 + 5/32*y^25 + 97/8*y^21 + 139/32*y^17 + 435/16*y^13 + 323/3 2*y^9 + 21/4*y^5 + 77/32*y), x + (-21/32*y^31 - 587/32*y^23 + 1/16*y^19 - 14 43/32*y^15 + 13/8*y^11 - 541/32*y^7 + 21/16*y^3), x + (-5/16*y^31 - 5/32*y^2 7 - 35/4*y^23 - 139/32*y^19 - 349/16*y^15 - 323/32*y^11 - 57/8*y^7 - 109/32* y^3), x + (5/16*y^31 + 5/32*y^27 + 35/4*y^23 + 139/32*y^19 + 349/16*y^15 + 3 23/32*y^11 + 57/8*y^7 + 109/32*y^3), x + (21/32*y^31 + 587/32*y^23 - 1/16*y^ 19 + 1443/32*y^15 - 13/8*y^11 + 541/32*y^7 - 21/16*y^3), x^4 + (-13/4*y^24 - 91*y^16 - 909/4*y^8 - 169/2), x^4 + (-1/4*y^24 - 7*y^16 - 57/4*y^8 - 1/2)]~ [8711099/70204123*y^14 - 3396450/70204123*y^13 - 230089978/70204123*y^12 + 7 1459644/70204123*y^11 + 2039293754/70204123*y^10 - 522502724/70204123*y^9 - 7578045032/70204123*y^8 + 136410216/6382193*y^7 + 11598831422/70204123*y^6 - 1582740050/70204123*y^5 - 6466526698/70204123*y^4 + 712163508/70204123*y^3 + 865017354/70204123*y^2 - 11706800/70204123*y + 7921687/70204123] [y, -123209112482/559553426209*y^11 - 236161397417/559553426209*y^10 + 52225 05497467/559553426209*y^9 + 7627164004768/559553426209*y^8 - 68684785347690/ 559553426209*y^7 - 98327585435469/559553426209*y^6 + 334508906676131/5595534 26209*y^5 + 508054669424553/559553426209*y^4 - 499853398148011/559553426209* y^3 - 780815391953932/559553426209*y^2 + 222263541657120/559553426209*y + 69 71304961116/11905392047, -176690268281/1119106852418*y^11 - 641210922141/223 8213704836*y^10 + 3748626002639/559553426209*y^9 + 20339566453621/2238213704 836*y^8 - 49228932581896/559553426209*y^7 - 262748733927015/2238213704836*y^ 6 + 958463738831775/2238213704836*y^5 + 1369627950576313/2238213704836*y^4 - 1439017147702531/2238213704836*y^3 - 2121737405539667/2238213704836*y^2 + 6 35967216650047/2238213704836*y + 19194169373855/47621568188, -68393259315/11 19106852418*y^11 - 143769468519/1119106852418*y^10 + 2890095068571/111910685 2418*y^9 + 4773072512403/1119106852418*y^8 - 38008182942981/1119106852418*y^ 7 - 30714902181882/559553426209*y^6 + 92097658832451/559553426209*y^5 + 1570 24332093039/559553426209*y^4 - 134021586074273/559553426209*y^3 - 2404025913 19962/559553426209*y^2 + 58771325675463/559553426209*y + 4293056883813/23810 784094, -26071422312/559553426209*y^11 - 45431912634/559553426209*y^10 + 110 4266993455/559553426209*y^9 + 1416464504385/559553426209*y^8 - 1440773326506 3/559553426209*y^7 - 18255285107310/559553426209*y^6 + 69227537719650/559553 426209*y^5 + 94877281869432/559553426209*y^4 - 100252280561328/559553426209* y^3 - 143113043669604/559553426209*y^2 + 41073387952215/559553426209*y + 128 0223975324/11905392047, -16163557893/1119106852418*y^11 - 64908872441/223821 3704836*y^10 + 685522417391/1119106852418*y^9 + 2130089587017/2238213704836* y^8 - 4531221497592/559553426209*y^7 - 27490869176393/2238213704836*y^6 + 89 319951302323/2238213704836*y^5 + 141812611520979/2238213704836*y^4 - 1390748 45426265/2238213704836*y^3 - 220351698213059/2238213704836*y^2 + 72725691407 453/2238213704836*y + 2005246545505/47621568188, 9609209575/2238213704836*y^ 11 + 25387385845/559553426209*y^10 - 383645617715/2238213704836*y^9 - 208031 3216715/1119106852418*y^8 + 6033944605985/2238213704836*y^7 + 53081257123225 /2238213704836*y^6 - 33975296862719/2238213704836*y^5 - 255089221619815/2238 213704836*y^4 + 47525895430055/2238213704836*y^3 + 398412597852115/223821370 4836*y^2 - 30904572571305/2238213704836*y - 890343326655/11905392047, 522817 60559/2238213704836*y^11 + 14008471016/559553426209*y^10 - 2227004686929/223 8213704836*y^9 - 336992949231/559553426209*y^8 + 28726688292139/223821370483 6*y^7 + 17917872421753/2238213704836*y^6 - 137376604832131/2238213704836*y^5 - 105226511459813/2238213704836*y^4 + 207364021022899/2238213704836*y^3 + 1 70780696189363/2238213704836*y^2 - 84647799904795/2238213704836*y - 44402858 6648/11905392047, 106577461171/2238213704836*y^11 + 236835106673/22382137048 36*y^10 - 4499294217001/2238213704836*y^9 - 8003166405117/2238213704836*y^8 + 59306288158573/2238213704836*y^7 + 25836461923340/559553426209*y^6 - 72093 028502701/559553426209*y^5 - 264172433170095/1119106852418*y^4 + 21076054618 3675/1119106852418*y^3 + 203797855675948/559553426209*y^2 - 94758333876515/1 119106852418*y - 7259569285101/47621568188, 175225361355/2238213704836*y^11 + 367043962553/2238213704836*y^10 - 7404910374729/2238213704836*y^9 - 121761 49738023/2238213704836*y^8 + 97370244941211/2238213704836*y^7 + 784051152149 35/1119106852418*y^6 - 117954333048705/559553426209*y^5 - 401317015113399/11 19106852418*y^4 + 171430955359538/559553426209*y^3 + 307321505664217/5595534 26209*y^2 - 148696095658675/1119106852418*y - 10923889360787/47621568188, 18 4746017659/1119106852418*y^11 + 182236626649/559553426209*y^10 - 78287971960 99/1119106852418*y^9 - 5941166792275/559553426209*y^8 + 103098612489213/1119 106852418*y^7 + 153130332934513/1119106852418*y^6 - 502641225832273/11191068 52418*y^5 - 789225051651289/1119106852418*y^4 + 749848149414089/111910685241 8*y^3 + 1216440499421323/1119106852418*y^2 - 334431034048089/1119106852418*y - 5475399545957/11905392047, 421608384/2321798449*y^11 + 1306271719/4643596 898*y^10 - 17925705039/2321798449*y^9 - 38874965891/4643596898*y^8 + 2342247 56928/2321798449*y^7 + 502105436649/4643596898*y^6 - 2270324281083/464359689 8*y^5 - 2658757184017/4643596898*y^4 + 3428983243105/4643596898*y^3 + 405157 9820087/4643596898*y^2 - 1510458181035/4643596898*y - 36134279083/98799934] [x + (-y + 1) 1] [x^2 + (y + 2)*x + (y^2 + y + 1) 1] [x^2 + (y + 2)*x + (1/25*y^8 - 3/5*y^5 - 87/25*y^2 + y + 1) 1] [x^2 + (-2/15*y^7 + 7/3*y^4 + 79/15*y + 2)*x + (1/25*y^8 - 2/15*y^7 - 3/5*y^ 5 + 7/3*y^4 - 87/25*y^2 + 79/15*y + 1) 1] [x^2 + (2/15*y^7 - 7/3*y^4 - 94/15*y + 2)*x + (1/25*y^8 + 2/15*y^7 - 3/5*y^5 - 7/3*y^4 - 87/25*y^2 - 94/15*y + 1) 1] [ x - y 3] [ x^2 + y 4] [x^3 - y*x + y 5] [x - y 1] [x + y 1] [x - y 1] [x + y 1] [ x + 1 3] [2*x + 1 2] 9 [x - y, x + y, x + (-373/2372*y^15 - 69/2372*y^13 + 2205/593*y^11 - 56641/47 44*y^9 + 30823/1186*y^7 - 16782/593*y^5 + 11109/593*y^3 - 15285/2372*y), x + (373/2372*y^15 + 69/2372*y^13 - 2205/593*y^11 + 56641/4744*y^9 - 30823/1186 *y^7 + 16782/593*y^5 - 11109/593*y^3 + 15285/2372*y), x^4 + (-231/1186*y^14 - 313/1186*y^12 + 10535/2372*y^10 - 5568/593*y^8 + 10658/593*y^6 - 4133/593* y^4 + 1731/1186*y^2 - 648/593)*x^2 + (81/1186*y^14 + 181/2372*y^12 - 937/593 *y^10 + 4313/1186*y^8 - 4207/593*y^6 + 5463/1186*y^4 - 1270/593*y^2 + 1883/5 93), x^4 + (-93/1186*y^14 - 49/1186*y^12 + 4457/2372*y^10 - 3058/593*y^8 + 6 170/593*y^6 - 6793/593*y^4 + 8429/1186*y^2 - 2140/593)*x^2 + (81/1186*y^14 + 181/2372*y^12 - 937/593*y^10 + 4313/1186*y^8 - 4207/593*y^6 + 5463/1186*y^4 - 1270/593*y^2 + 1883/593), x^4 + (159/2372*y^14 + 281/1186*y^12 - 3437/237 2*y^10 - 217/593*y^8 + 4085/1186*y^6 - 8339/593*y^4 + 12947/1186*y^2 + 146/5 93)*x^2 + (-81/1186*y^14 - 181/2372*y^12 + 937/593*y^10 - 4313/1186*y^8 + 42 07/593*y^6 - 5463/1186*y^4 + 1270/593*y^2 + 489/593)]~ [Mod(-y, y^16 - 24*y^12 + 80*y^10 - 172*y^8 + 192*y^6 - 112*y^4 + 32*y^2 + 4 ), Mod(y, y^16 - 24*y^12 + 80*y^10 - 172*y^8 + 192*y^6 - 112*y^4 + 32*y^2 + 4), Mod(-373/2372*y^15 - 69/2372*y^13 + 2205/593*y^11 - 56641/4744*y^9 + 308 23/1186*y^7 - 16782/593*y^5 + 11109/593*y^3 - 15285/2372*y, y^16 - 24*y^12 + 80*y^10 - 172*y^8 + 192*y^6 - 112*y^4 + 32*y^2 + 4), Mod(373/2372*y^15 + 69 /2372*y^13 - 2205/593*y^11 + 56641/4744*y^9 - 30823/1186*y^7 + 16782/593*y^5 - 11109/593*y^3 + 15285/2372*y, y^16 - 24*y^12 + 80*y^10 - 172*y^8 + 192*y^ 6 - 112*y^4 + 32*y^2 + 4)] 36 9 x^6 - x^5 - 76*x^4 + 60*x^3 + 1140*x^2 + 1155*x - 695 a^36 - 140*a^34 + 8402*a^32 - 288950*a^30 + 6406703*a^28 - 97539585*a^26 + 1 059042259*a^24 - 8396309325*a^22 + 49297808195*a^20 - 215811263825*a^18 + 70 4643601819*a^16 - 1705347924285*a^14 + 3017070472643*a^12 - 3809285900925*a^ 10 + 3299709349267*a^8 - 1836758642090*a^6 + 585303753211*a^4 - 85409835875* a^2 + 3969153125 [28870969412445129304/150333898582544875079637735*a^34 - 2391040639738112524 6214047/902003391495269250477826410000*a^32 + 1408280580925577743188914959/9 02003391495269250477826410000*a^30 - 47270903738475878949122441507/902003391 495269250477826410000*a^28 + 1016201980774469757442024408441/902003391495269 250477826410000*a^26 - 1653232481585973809555097282799/100222599055029916719 758490000*a^24 + 30766570387863948626786349252629/18040067829905385009556528 2000*a^22 - 25494617146287004973995153489163/20044519811005983343951698000*a ^20 + 54269387427573548559506499935047/7843507752132776091111534000*a^18 - 4 967271194565117464292207548275283/180400678299053850095565282000*a^16 + 1439 0821273796469411671423134660909/180400678299053850095565282000*a^14 - 166375 51485416921371399599192940627/100222599055029916719758490000*a^12 + 21844296 4149682251745527062058729581/902003391495269250477826410000*a^10 - 715047828 08114491609686387087461101/300667797165089750159275470000*a^8 + 132463576654 385501140215626560461749/902003391495269250477826410000*a^6 - 45521136780059 303695022254815264059/902003391495269250477826410000*a^4 + 48834547745749769 48426917348117/644288136782335178912733150*a^2 - 31947174916220852422727719/ 91469478158982811558152, 3251350527072966578858963/4510016957476346252389132 050000*a^34 - 224934549971331898950636911/2255008478738173126194566025000*a^ 32 + 8860674919294055555049660713/1503338985825448750796377350000*a^30 - 995 57773024274624590944467659/501112995275149583598792450000*a^28 + 19366458770 607880120052179046813/4510016957476346252389132050000*a^26 - 285516842858115 285212427862265807/4510016957476346252389132050000*a^24 + 595519111738991674 011764093345989/902003391495269250477826410000*a^22 - 4489547975447934229698 580858261951/902003391495269250477826410000*a^20 + 1076139228842461035371382 151402807/39217538760663880455557670000*a^18 - 11124367147850754939979966580 304871/100222599055029916719758490000*a^16 + 1479061897966350800416026745438 951477/4510016957476346252389132050000*a^14 - 315025857271480248157232912303 3742463/4510016957476346252389132050000*a^12 + 47206506294320482873673946762 98685961/4510016957476346252389132050000*a^10 - 4777649748033279268548939533 863439719/4510016957476346252389132050000*a^8 + 3048859768911341351494073063 483963897/4510016957476346252389132050000*a^6 - 5426099614227091504278277319 81252029/2255008478738173126194566025000*a^4 + 64587456786717997350050100662 819/1718101698086227143767288400*a^2 - 165798995832125073281674123/914694781 58982811558152, -704379081794904012990253/9020033914952692504778264100000*a^ 35 - 185571858472598531261171/501112995275149583598792450000*a^34 + 48715152 518881440798956651/4510016957476346252389132050000*a^33 + 462092978647254762 515957747/9020033914952692504778264100000*a^32 - 143866499279758588432618534 1/2255008478738173126194566025000*a^31 - 13648984531486738963024628227/45100 16957476346252389132050000*a^30 + 96938310360867353475048806483/451001695747 6346252389132050000*a^29 + 919883530735586552464580524411/902003391495269250 4778264100000*a^28 - 232651976540261816658545907611/501112995275149583598792 450000*a^27 - 19875071662837802701492211372933/90200339149526925047782641000 00*a^26 + 30845327236112782336432658557121/4510016957476346252389132050000*a ^25 + 97629122086975105817272227332809/3006677971650897501592754700000*a^24 - 21424985574841499437846887948389/300667797165089750159275470000*a^23 - 610 575128275733935942680874074229/1804006782990538500955652820000*a^22 + 484017 286454879828969736789559843/902003391495269250477826410000*a^21 + 1533419100 031007894056656543524977/601335594330179500318550940000*a^20 - 1158671856773 61369373967739807791/39217538760663880455557670000*a^19 - 110190466434352089 3720157677667127/78435077521327760911115340000*a^18 + 1537709883158934201041 232269889911/128857627356467035782546630000*a^17 + 1024351631773365912595517 71572103159/1804006782990538500955652820000*a^16 - 5292233983819996489701399 1241504027/1503338985825448750796377350000*a^15 - 15119400756767591614096930 48855920037/9020033914952692504778264100000*a^14 + 4823557309278799269424083 0453221347/644288136782335178912733150000*a^13 + 107239762638007600223629533 3324062521/3006677971650897501592754700000*a^12 - 16846944747925094111730588 2802587131/1503338985825448750796377350000*a^11 - 48160226697757002253310017 91553165721/9020033914952692504778264100000*a^10 + 1491287229390570953499395 745247369/13148737485353779161484350000*a^9 + 162299919830912395515658180697 4277013/3006677971650897501592754700000*a^8 - 327237997164237860693483056003 293031/4510016957476346252389132050000*a^7 - 3103794645076791741342476648584 879777/9020033914952692504778264100000*a^6 + 2348322029477720044136044070025 03923/9020033914952692504778264100000*a^5 + 11035578261555912186076185579856 11613/9020033914952692504778264100000*a^4 - 37526865321657483383315681982802 9/90200339149526925047782641000*a^3 - 49201004178902125753179356208497/25771 52547129340715650932600*a^2 + 455861078300944766857933289/213428782370959893 6356880*a + 336438999245457567382406693/365877912635931246232608, -457997268 286495201285601/9020033914952692504778264100000*a^35 - 155437231387909379055 577/1804006782990538500955652820000*a^34 + 63219462123808708551299959/902003 3914952692504778264100000*a^33 + 10732815328231466161638631/9020033914952692 50477826410000*a^32 - 1241268191638711501136747401/3006677971650897501592754 700000*a^31 - 162691836407833782279946/231996757071828510925366875*a^30 + 41 671559320168530327971893369/3006677971650897501592754700000*a^29 + 472202100 3894765857767375379/200445198110059833439516980000*a^28 - 268827453299542151 9377197948701/9020033914952692504778264100000*a^27 - 91447940232848524115401 7943217/1804006782990538500955652820000*a^26 + 39380597302365530060214378192 779/9020033914952692504778264100000*a^25 + 13404987653711757838118111598667/ 1804006782990538500955652820000*a^24 - 81492696927754851227554074520033/1804 006782990538500955652820000*a^23 - 27755367080515496240602993106981/36080135 6598107700191130564000*a^22 + 608451862766595678082876478420347/180400678299 0538500955652820000*a^21 + 207309689387565154271678626939871/360801356598107 700191130564000*a^20 - 144141144819342089103549365967439/7843507752132776091 1115340000*a^19 - 49116300327361576889751394682183/1568701550426555218222306 8000*a^18 + 163228993853205803064485212811743/22271688678895537048835220000* a^17 + 1501366475076386034781931026134473/120267118866035900063710188000*a^1 6 - 192040496313746347169675964373314529/9020033914952692504778264100000*a^1 5 - 65378470826900674859623854989910833/1804006782990538500955652820000*a^14 + 400908998300724067746255602794046311/9020033914952692504778264100000*a^13 + 136351102083667187315285017348776623/1804006782990538500955652820000*a^12 - 586838332855949729229685411031808997/9020033914952692504778264100000*a^11 - 199368556080951864152805639007833629/1804006782990538500955652820000*a^10 + 578030985689012831826453965281320943/9020033914952692504778264100000*a^9 + 196244779045524955444897983850505039/1804006782990538500955652820000*a^8 - 357480334490463612280117630223936969/9020033914952692504778264100000*a^7 - 121476601421295423170534909540278573/1804006782990538500955652820000*a^6 + 3 0624370220614590128641706307930719/2255008478738173126194566025000*a^5 + 104 63389029506180036157409002660637/451001695747634625238913205000*a^4 - 861866 1493592985666542036187341/4295254245215567859418221000*a^3 - 266859198823298 552776653451403/76360075470498984167435040*a^2 + 591232823580313844716106279 /6402863471128796809070640*a + 59236281207552249649513295/365877912635931246 232608, 457997268286495201285601/9020033914952692504778264100000*a^35 - 1554 37231387909379055577/1804006782990538500955652820000*a^34 - 6321946212380870 8551299959/9020033914952692504778264100000*a^33 + 10732815328231466161638631 /902003391495269250477826410000*a^32 + 1241268191638711501136747401/30066779 71650897501592754700000*a^31 - 162691836407833782279946/23199675707182851092 5366875*a^30 - 41671559320168530327971893369/3006677971650897501592754700000 *a^29 + 4722021003894765857767375379/200445198110059833439516980000*a^28 + 2 688274532995421519377197948701/9020033914952692504778264100000*a^27 - 914479 402328485241154017943217/1804006782990538500955652820000*a^26 - 393805973023 65530060214378192779/9020033914952692504778264100000*a^25 + 1340498765371175 7838118111598667/1804006782990538500955652820000*a^24 + 81492696927754851227 554074520033/1804006782990538500955652820000*a^23 - 277553670805154962406029 93106981/360801356598107700191130564000*a^22 - 60845186276659567808287647842 0347/1804006782990538500955652820000*a^21 + 20730968938756515427167862693987 1/360801356598107700191130564000*a^20 + 144141144819342089103549365967439/78 435077521327760911115340000*a^19 - 49116300327361576889751394682183/15687015 504265552182223068000*a^18 - 163228993853205803064485212811743/2227168867889 5537048835220000*a^17 + 1501366475076386034781931026134473/12026711886603590 0063710188000*a^16 + 192040496313746347169675964373314529/902003391495269250 4778264100000*a^15 - 65378470826900674859623854989910833/1804006782990538500 955652820000*a^14 - 400908998300724067746255602794046311/9020033914952692504 778264100000*a^13 + 136351102083667187315285017348776623/1804006782990538500 955652820000*a^12 + 586838332855949729229685411031808997/9020033914952692504 778264100000*a^11 - 199368556080951864152805639007833629/1804006782990538500 955652820000*a^10 - 578030985689012831826453965281320943/9020033914952692504 778264100000*a^9 + 196244779045524955444897983850505039/18040067829905385009 55652820000*a^8 + 357480334490463612280117630223936969/902003391495269250477 8264100000*a^7 - 121476601421295423170534909540278573/1804006782990538500955 652820000*a^6 - 30624370220614590128641706307930719/225500847873817312619456 6025000*a^5 + 10463389029506180036157409002660637/45100169574763462523891320 5000*a^4 + 8618661493592985666542036187341/4295254245215567859418221000*a^3 - 266859198823298552776653451403/76360075470498984167435040*a^2 - 5912328235 80313844716106279/6402863471128796809070640*a + 59236281207552249649513295/3 65877912635931246232608, 704379081794904012990253/90200339149526925047782641 00000*a^35 - 185571858472598531261171/501112995275149583598792450000*a^34 - 48715152518881440798956651/4510016957476346252389132050000*a^33 + 4620929786 47254762515957747/9020033914952692504778264100000*a^32 + 1438664992797585884 326185341/2255008478738173126194566025000*a^31 - 136489845314867389630246282 27/4510016957476346252389132050000*a^30 - 96938310360867353475048806483/4510 016957476346252389132050000*a^29 + 919883530735586552464580524411/9020033914 952692504778264100000*a^28 + 232651976540261816658545907611/5011129952751495 83598792450000*a^27 - 19875071662837802701492211372933/902003391495269250477 8264100000*a^26 - 30845327236112782336432658557121/4510016957476346252389132 050000*a^25 + 97629122086975105817272227332809/30066779716508975015927547000 00*a^24 + 21424985574841499437846887948389/300667797165089750159275470000*a^ 23 - 610575128275733935942680874074229/1804006782990538500955652820000*a^22 - 484017286454879828969736789559843/902003391495269250477826410000*a^21 + 15 33419100031007894056656543524977/601335594330179500318550940000*a^20 + 11586 7185677361369373967739807791/39217538760663880455557670000*a^19 - 1101904664 343520893720157677667127/78435077521327760911115340000*a^18 - 15377098831589 34201041232269889911/128857627356467035782546630000*a^17 + 10243516317733659 1259551771572103159/1804006782990538500955652820000*a^16 + 52922339838199964 897013991241504027/1503338985825448750796377350000*a^15 - 151194007567675916 1409693048855920037/9020033914952692504778264100000*a^14 - 48235573092787992 694240830453221347/644288136782335178912733150000*a^13 + 1072397626380076002 236295333324062521/3006677971650897501592754700000*a^12 + 168469447479250941 117305882802587131/1503338985825448750796377350000*a^11 - 481602266977570022 5331001791553165721/9020033914952692504778264100000*a^10 - 14912872293905709 53499395745247369/13148737485353779161484350000*a^9 + 1622999198309123955156 581806974277013/3006677971650897501592754700000*a^8 + 3272379971642378606934 83056003293031/4510016957476346252389132050000*a^7 - 31037946450767917413424 76648584879777/9020033914952692504778264100000*a^6 - 23483220294777200441360 4407002503923/9020033914952692504778264100000*a^5 + 110355782615559121860761 8557985611613/9020033914952692504778264100000*a^4 + 375268653216574833833156 819828029/90200339149526925047782641000*a^3 - 492010041789021257531793562084 97/2577152547129340715650932600*a^2 - 455861078300944766857933289/2134287823 709598936356880*a + 336438999245457567382406693/365877912635931246232608] [x^12 - x^11 + 7/13*x^10 - 3/13*x^9 + 15/169*x^8 - 5/169*x^7 + 19/2197*x^6 - 5/2197*x^5 + 15/28561*x^4 - 3/28561*x^3 + 7/371293*x^2 - 1/371293*x + 1/482 6809, x^12 + x^11 + 7/13*x^10 + 3/13*x^9 + 15/169*x^8 + 5/169*x^7 + 19/2197* x^6 + 5/2197*x^5 + 15/28561*x^4 + 3/28561*x^3 + 7/371293*x^2 + 1/371293*x + 1/4826809]~ [x - 3, x + (-1/2*y + 1/2), x + (1/2*y + 1/2)]~ [x + (-y^7 - 1) 1] [ x + (y^7 + 1) 1] [x + (-2*y^3 + y), x + (-4/3*y^3 + 2/3*y), x + (-2/3*y^3 + 1/3*y)]~ [x + (-1/3*y - 1/3), x + (2/3*y + 2/3)]~ *** nffactor: Warning: non-monic polynomial. Result of the form [nf,c]. [x + (-2/3*y + 1/3) 1] [ x + (2/3*y - 1/3) 1] *** nfroots: Warning: non-monic polynomial. Result of the form [nf,c]. [-2/3*y + 1/3, 2/3*y - 1/3] [x + (-26388279066648/85070591730466729623209871765718171955*t^5 + 131941395 333267/85070591730466729623209871765718171955*t^4 + 967140655690823730462717 32/85070591730466729623209871765718171955*t^3 - 290142196708032170441048136/ 85070591730466729623209871765718171955*t^2 - 7443676776386824622360021639744 6118676/85070591730466729623209871765718171955*t + 7443676776373163760598366 6543681076444/85070591730466729623209871765718171955) 1] [x^2 + (26388279066648/85070591730466729623209871765718171955*t^5 - 13194139 5333267/85070591730466729623209871765718171955*t^4 - 96714065569082373046271 732/85070591730466729623209871765718171955*t^3 + 290142196708032170441048136 /85070591730466729623209871765718171955*t^2 + 744367677638682462236002163974 46118676/85070591730466729623209871765718171955*t - 744367677637316376059836 66543681076444/85070591730466729623209871765718171955)*x + (54/8507059173046 6729623209871765718171955*t^5 + 19342813113869251167387394/85070591730466729 623209871765718171955*t^4 - 77371252455674916762549976/850705917304667296232 09871765718171955*t^3 - 42535295865117307932921126639575760427/8507059173046 6729623209871765718171955*t^2 + 85070591730773796781391952391721450758/85070 591730466729623209871765718171955*t + 23384026197336981987123709535795926763 206176932728/85070591730466729623209871765718171955) 1] x^6 + 10/7*x^5 - 867/49*x^4 - 76/245*x^3 + 3148/35*x^2 - 25944/245*x + 48771 /1225 [ x - 1 1] [ x + 1 1] [x^2 - 5 1] [x^2 - 2 1] [ x + 1 1] [ x^2 + 1 1] [ x^4 - x^3 + x^2 - x + 1 1] [ x^4 + 1 1] [ x^4 + x^3 + x^2 + x + 1 1] [ x^8 - x^6 + x^4 - x^2 + 1 1] [ x^8 + 1 1] [ x^16 - x^12 + x^8 - x^4 + 1 1] [x^32 - x^24 + x^16 - x^8 + 1 1] 10 10 [x + (-314226370217524044*y + 1473852319020386314), x + (314226370217524044* y - 1473852319020386314)]~ [0] [-1/2] [-1/2, 1/2] [-1] [Mod(-1/55*y^3 + 1/110*y^2 - 57/110*y + 1/110, y^4 + 57*y^2 + 661), Mod(1/55 *y^3 + 1/110*y^2 + 57/110*y + 1/110, y^4 + 57*y^2 + 661)] [Mod(-1/55*y^3 + 1/110*y^2 - 57/110*y + 1/110, y^4 + 57*y^2 + 661), Mod(1/55 *y^3 + 1/110*y^2 + 57/110*y + 1/110, y^4 + 57*y^2 + 661)] [Mod(-1/55*y^3 + 1/110*y^2 - 57/110*y + 1/110, y^4 + 57*y^2 + 661), Mod(1/55 *y^3 + 1/110*y^2 + 57/110*y + 1/110, y^4 + 57*y^2 + 661)] [Mod(-44*a + 328/3, a^2 - a + 3), Mod(-40*a - 80/3, a^2 - a + 3)] [-2, 2] [x^4 - 10/121*x^2 + 1/14641 1] [ x - 1 1] [ x + 1 1] [x + Mod(-y^5, y^8 - y^6 + y^4 - y^2 + 1) 1] [ x + Mod(y^5, y^8 - y^6 + y^4 - y^2 + 1) 1] 2 [1, 1, 4, 4, 5, 5]~ *** at top-level: polhensellift(x^2+x+1,[x+a,x+a+1],2,10) *** ^--------------------------------------- *** polhensellift: incorrect type in polhensellift [not in Z[X]] (t_POL). Total time spent: 9405 pari-2.11.2/src/test/32/ellpadic0000644000175000017500000000607013326135265014661 0ustar billbill *** Warning: new stack size = 20000000 (19.073 Mbytes). [[0, 0, 0, -11, -890], [1/2, 0, 0, 0]] [0, 1, [1/2, 0, 0, 0], 1] [0, 1, [1/6, 0, 0, 0], 1] [0, 1, [3/2, 0, 0, 0], 1] [2^-2 + 2^-1 + 1 + 2 + O(2^2), 1 + 2 + 2^2 + 2^3 + O(2^4)] [3 + 2*3^2 + 3^4 + O(3^5), 2*3^4 + 3^5 + O(3^8)] [3*5 + 5^2 + 2*5^3 + 3*5^4 + O(5^5), 5^2 + 4*5^4 + O(5^6)] [0, 0] *** at top-level: ellpadicheight(E,19,0,P) *** ^------------------------ *** ellpadicheight: domain error in ellpadicheight: precision <= 0 [1, 1] [10, 10] [[10], [10]] [0, 0] 6 + 9*11 + 6*11^3 + 11^4 + O(11^5) 1 [1930 1588] [ 65 1195] [1, [], []] [2, [2], [[0, 0]]] [3, [3], [[0, 1]]] [2, [2], [[0, 1]]] [3, [3], [[0, 0]]] [4, [4], [[1, 2]]] [4, [4], [[0, 3]]] [5, [5], [[4, 3]]] [6, [6], [[4, 2]]] [2*3^2 + 2*3^3 + 3^4 + 3^5 + 3^6 + O(3^7), 2*3^2 + 3^4 + 2*3^5 + 3^6 + O(3^7 )] *** at top-level: ellpadiclog(E,3,5,P) *** ^-------------------- *** ellpadiclog: domain error in ellpadiclog: P not in the kernel of reduction at 3 2*3 + 2*3^2 + 3^5 + O(3^6) [2^3 + 2^5 + O(2^7), 2^5 + 2^6 + O(2^7)] [2^3 + 2^5 + O(2^6), O(2^5)] [[2364, 3100, 759; 3100, 3119, 902; 759, 902, 19675], [25225, 46975, 36525; 46975, 61850, 20400; 36525, 20400, 60475]] 3 + 3^2 + 3^3 + 3^4 + 3^5 + O(3^6) 2*3^2 + 3^4 + O(3^6) 5 + 5^2 + 4*5^3 + 2*5^4 + O(5^5) O(5^7) 2 + 4*43 + 19*43^2 + 15*43^3 + 35*43^4 + 3*43^5 + O(43^6) 4 + 3*5^2 + 4*5^3 + 5^4 + 2*5^5 + O(5^6) 4 + 3*5 + 3*5^3 + 3*5^4 + 4*5^5 + O(5^6) [1, 7 + 7^2 + 3*7^3 + 7^4 + 6*7^5 + 2*7^6 + 4*7^7 + 5*7^8 + O(7^9)] [1, 37 + 9*37^2 + 29*37^3 + 35*37^4 + 16*37^5 + 29*37^6 + 16*37^7 + 18*37^8 + 31*37^9 + O(37^10)] [2, 2*7 + 7^2 + 5*7^3 + O(7^4)] 2*7 + 7^2 + 5*7^3 + 6*7^4 + 2*7^5 + O(7^6) [1, 7 + 7^2 + 2*7^3 + 4*7^4 + O(7^5)] [4*5 + 4*5^2 + 2*5^3 + 5^4 + 2*5^5 + 3*5^6 + O(5^7) 4 + 5^2 + 2*5^4 + 5^5 + 5^6 + O(5^7)] [5 + 2*5^2 + 3*5^3 + 4*5^4 + 5^5 + 5^6 + O(5^7) 5 + 2*5^3 + 3*5^4 + 2*5^5 + 5^6 + O(5^7)] [ 2*3^4 + O(3^5) 1 + 3 + 2*3^2 + 3^3 + 3^4 + O(3^5)] [2*3 + 3^3 + 3^4 + O(3^5) 3^4 + O(3^5)] *** at top-level: ellap(Ep,2) *** ^----------- *** ellap: inconsistent moduli in ellap: 2 != 11 *** at top-level: ellpadics2(Ep,2,5) *** ^------------------ *** ellpadics2: incorrect type in ellpadicfrobenius (t_INT). *** at top-level: ellcard(Ep,2) *** ^------------- *** ellcard: inconsistent moduli in ellcard: 2 != 11 *** at top-level: ellgroup(Ep,2) *** ^-------------- *** ellgroup: inconsistent moduli in ellgroup: 2 != 11 *** at top-level: ellissupersingular(Ep,2) *** ^------------------------ *** ellissupersingular: inconsistent moduli in ellissupersingular: 2 != 11 *** at top-level: elllocalred(Ep,2) *** ^----------------- *** elllocalred: inconsistent moduli in elllocalred: 2 != 11 *** at top-level: ellgroup(ellinit([5^6,5^6]),5,1) *** ^-------------------------------- *** ellgroup: incorrect type in ellgroup [not a p-minimal curve] (t_VEC). Total time spent: 358 pari-2.11.2/src/test/32/variable0000644000175000017500000000056113201017466014662 0ustar billbill0 3 x x y y y z 0 y [x, y, z] [y, x, y, z, y] [y, x, y, z, y] [y, y, x, y, z, y] [y, y, x, y, z, y] [y, y, x, y, z, y, y] [y, y, x, y, z, y, y, tt] *** at top-level: varhigher("zzz",y);1/0 *** ^-- *** _/_: impossible inverse in gdiv: 0. [y, y, x, y, z, y, y, tt] [y, x, y, z, y] [y, y, x, y, z, y, y, tt] Total time spent: 0 pari-2.11.2/src/test/32/galoischartable0000644000175000017500000000144413326135265016230 0ustar billbill[1, 1, 1, 1]~:[1, 1, 1, 1]~:[-x + 1, -x + 1, -x + 1, -x + 1]~ [1, -1, 1, 1]~:[1, -1, 1, 1]~:[-x + 1, x + 1, -x + 1, -x + 1]~ [2, 0, -y^3 - y^2 - 1, y^3 + y^2]~:[1, -1, 1, 1]~:[x^2 - 2*x + 1, -x^2 + 1, x^2 + (y^3 + y^2 + 1)*x + 1, x^2 + (-y^3 - y^2)*x + 1]~ [2, 0, y^3 + y^2, -y^3 - y^2 - 1]~:[1, -1, 1, 1]~:[x^2 - 2*x + 1, -x^2 + 1, x^2 + (-y^3 - y^2)*x + 1, x^2 + (y^3 + y^2 + 1)*x + 1]~ [1, 1, 1, 1]~:[1, 1, 1, 1]~:[-x + 1, -x + 1, -x + 1, -x + 1]~ [1, -1, 1, 1]~:[1, -1, 1, 1]~:[-x + 1, x + 1, -x + 1, -x + 1]~ [2, 0, -y^3 - y^2 - 1, y^3 + y^2]~:[1, -1, 1, 1]~:[x^2 - 2*x + 1, -x^2 + 1, x^2 + (y^3 + y^2 + 1)*x + 1, x^2 + (-y^3 - y^2)*x + 1]~ [2, 0, y^3 + y^2, -y^3 - y^2 - 1]~:[1, -1, 1, 1]~:[x^2 - 2*x + 1, -x^2 + 1, x^2 + (-y^3 - y^2)*x + 1, x^2 + (y^3 + y^2 + 1)*x + 1]~ Total time spent: 712 pari-2.11.2/src/test/32/sumdiv0000644000175000017500000000345013457610667014423 0ustar billbill3628800 20993420690550 3628800 20993420690550 3628800 20993420690550 3628800 20993420690550 0 0 7 [7, 720] 4 15 829440 270 15334088 20993420690550 57335533287534038504 273823/64800 1 error("domain error in moebius: argument = 0") 0 [0, 1] error("domain error in omega: argument = 0") error("domain error in bigomega: argument = 0") 2 error("domain error in numdiv: argument = 0") error("domain error in sumdiv: argument = 0") error("domain error in sumdivk: argument = 0") error("domain error in sumdivk: argument = 0") error("domain error in sumdivk: argument = 0") 1 error("incorrect type in moebius (t_MAT).") 0 [0, 1] error("incorrect type in omega (t_MAT).") error("incorrect type in bigomega (t_MAT).") 2 error("incorrect type in numdiv (t_MAT).") error("incorrect type in sumdiv (t_MAT).") error("incorrect type in sumdivk (t_MAT).") error("incorrect type in sumdivk (t_MAT).") error("incorrect type in sumdivk (t_MAT).") 0 -1 -2 [-2, 1] 1 1 1 2 3 5 9 -3/2 0 -1 -2 [-2, 1] 1 1 1 2 3 5 9 -3/2 1 1 1 [1, 1] 0 0 1 1 1 1 1 1 [1] 1 0 [0, 1] *** at top-level: divisors(fa) *** ^------------ *** divisors: domain error in divisors: argument = 0 [30, 2] [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60, 120] x^10 + 16*x^9 + 115*x^8 + 491*x^7 + 1387*x^6 + 2729*x^5 + 3822*x^4 + 3805*x^ 3 + 2616*x^2 + 1146*x + 252 x^10 + 16*x^9 + 115*x^8 + 491*x^7 + 1387*x^6 + 2729*x^5 + 3822*x^4 + 3805*x^ 3 + 2616*x^2 + 1146*x + 252 x^10 + 16*x^9 + 115*x^8 + 491*x^7 + 1387*x^6 + 2729*x^5 + 3822*x^4 + 3805*x^ 3 + 2616*x^2 + 1146*x + 252 x^10 + 16*x^9 + 115*x^8 + 491*x^7 + 1387*x^6 + 2729*x^5 + 3822*x^4 + 3805*x^ 3 + 2616*x^2 + 1146*x + 252 *** at top-level: divisors([1,2]) *** ^--------------- *** divisors: incorrect type in divisors (t_VEC). 0 762104756900678410271641 Total time spent: 0 pari-2.11.2/src/test/32/nf0000644000175000017500000005556213447371554013530 0ustar billbill *** Warning: new stack size = 60000000 (57.220 Mbytes). [85997496, [42998748, 2], [[408188227, 99620635; 0, 1], [2, 1; 0, 1]]] 12.340047278667903334059769086970462209 4.1894250945222025884896456921310573069 *** bnfinit: Warning: non-monic polynomial in bnfinit, using polredbest. [1, [], []] *** bnfinit: Warning: non-monic polynomial in bnfinit, using polredbest. [1, [], []] [2, -1] 20915648110955829231381594293324156411897455346679838307589120000 571459344155975480004612560667633185714077696 [54898, [54898], [[17, 15; 0, 1]]] [26, [26], [[19, 15, 18, 5; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1]]] [1, [], []] [3, 3] 20/3 -5 13 0 5/2 -1 1024/243 -1 31 -11 1/32 15853839 1736217747 Mod(4/3, y^5 - 4*y^3 + 2*y + 11) Mod(-1, y^5 - 4*y^3 + 2*y + 11) Mod(y^2 + y + 1, y^5 - 4*y^3 + 2*y + 11) Mod(y, y^5 - 4*y^3 + 2*y + 11) Mod(1/2, y^5 - 4*y^3 + 2*y + 11) Mod(5*y^4 + 4*y^3 - 12*y^2 - y - 5, y^5 - 4*y^3 + 2*y + 11) [4/3, 0, 0, 0, 0]~ [-1, 0, 0, 0, 0]~ [3, 1, 1, 0, 0]~ [0, 1, 0, 0, 0]~ [1/2, 0, 0, 0, 0]~ [1, 2, 3, 4, 5]~ (f)->for(i=1,#v,for(j=1,#v,print(f(nf,v[i],v[j])))) 8/3 1/3 [13/3, 1, 1, 0, 0]~ [4/3, 1, 0, 0, 0]~ 11/6 [7/3, 2, 3, 4, 5]~ 1/3 -2 [2, 1, 1, 0, 0]~ [-1, 1, 0, 0, 0]~ -1/2 [0, 2, 3, 4, 5]~ [13/3, 1, 1, 0, 0]~ [2, 1, 1, 0, 0]~ [6, 2, 2, 0, 0]~ [3, 2, 1, 0, 0]~ [7/2, 1, 1, 0, 0]~ [4, 3, 4, 4, 5]~ [4/3, 1, 0, 0, 0]~ [-1, 1, 0, 0, 0]~ [3, 2, 1, 0, 0]~ [0, 2, 0, 0, 0]~ [1/2, 1, 0, 0, 0]~ [1, 3, 3, 4, 5]~ 11/6 -1/2 [7/2, 1, 1, 0, 0]~ [1/2, 1, 0, 0, 0]~ 1 [3/2, 2, 3, 4, 5]~ [7/3, 2, 3, 4, 5]~ [0, 2, 3, 4, 5]~ [4, 3, 4, 4, 5]~ [1, 3, 3, 4, 5]~ [3/2, 2, 3, 4, 5]~ [2, 4, 6, 8, 10]~ 1 -4/3 [-64/93, 16/31, 16/93, -8/31, 4/93]~ [0, 4/33, 4/33, 0, -4/33]~ 8/3 [1587988/47561517, -165136/5284613, 41300/5284613, -212540/47561517, -78712/ 47561517]~ -3/4 1 [16/31, -12/31, -4/31, 6/31, -1/31]~ [0, -1/11, -1/11, 0, 1/11]~ -2 [-396997/15853839, 123852/5284613, -30975/5284613, 53135/15853839, 19678/158 53839]~ [9/4, 3/4, 3/4, 0, 0]~ [-3, -1, -1, 0, 0]~ [1, 0, 0, 0, 0]~ [1, 12/11, 1/11, 0, -1/11]~ [6, 2, 2, 0, 0]~ [1249690/15853839, -222317/5284613, 39600/5284613, -477392/15853839, 434/158 53839]~ [0, 3/4, 0, 0, 0]~ [0, -1, 0, 0, 0]~ [3/31, -10/31, 7/31, 5/31, -6/31]~ [1, 0, 0, 0, 0]~ [0, 2, 0, 0, 0]~ [-672280/15853839, 150044/5284613, -148123/5284613, 73247/15853839, -53135/1 5853839]~ 3/8 -1/2 [-8/31, 6/31, 2/31, -3/31, 1/62]~ [0, 1/22, 1/22, 0, -1/22]~ 1 [396997/31707678, -61926/5284613, 30975/10569226, -53135/31707678, -9839/158 53839]~ [3/4, 3/2, 9/4, 3, 15/4]~ [-1, -2, -3, -4, -5]~ [-314/31, -59/31, 311/31, 14/31, -85/31]~ [7, -27/11, 39/11, 5, 5/11]~ [2, 4, 6, 8, 10]~ [1, 0, 0, 0, 0]~ 1 -1 [-1, 1, 0, 0, 0]~ [0, 0, 0, 0, 0]~ 3 [0, 0, 0, 0, 0]~ -1 1 [1, 0, 0, 0, 0]~ [0, 0, 0, 0, 0]~ -2 [0, 0, 0, 0, 0]~ [2, 1, 1, 0, 0]~ [-3, -1, -1, 0, 0]~ [1, 0, 0, 0, 0]~ [1, 1, 0, 0, 0]~ [6, 2, 2, 0, 0]~ [0, 0, 0, 0, 0]~ [0, 1, 0, 0, 0]~ [0, -1, 0, 0, 0]~ [0, 0, 0, 0, 0]~ [1, 0, 0, 0, 0]~ [0, 2, 0, 0, 0]~ [0, 0, 0, 0, 0]~ 0 0 [0, 0, 0, 0, 0]~ [0, 0, 0, 0, 0]~ 1 [0, 0, 0, 0, 0]~ [1, 2, 2, 3, 4]~ [-1, -2, -3, -4, -5]~ [-10, -2, 10, 0, -3]~ [7, -2, 4, 5, 0]~ [2, 4, 6, 8, 10]~ [1, 0, 0, 0, 0]~ [1, 0] [-1, 1/3] [[-1, 1, 0, 0, 0]~, [7/3, -2, 0, -1, 0]~] [[0, 0, 0, 0, 0]~, 4/3] [3, -1/6] [[0, 0, 0, 0, 0]~, 4/3] [-1, 1/3] [1, 0] [[1, 0, 0, 0, 0]~, [-4, -1, -1, 0, 0]~] [[0, 0, 0, 0, 0]~, -1] [-2, 0] [[0, 0, 0, 0, 0]~, -1] [[2, 1, 1, 0, 0]~, [1/3, -1/3, -1/3, 0, 0]~] [[-3, -1, -1, 0, 0]~, [0, 0, 0, 0, 0]~] [[1, 0, 0, 0, 0]~, [0, 0, 0, 0, 0]~] [[1, 1, 0, 0, 0]~, [1, 0, 0, 0, 0]~] [[6, 2, 2, 0, 0]~, [0, 0, 0, 0, 0]~] [[0, 0, 0, 0, 0]~, [3, 1, 1, 0, 0]~] [[0, 1, 0, 0, 0]~, [0, -1/3, 0, 0, 0]~] [[0, -1, 0, 0, 0]~, [0, 0, 0, 0, 0]~] [[0, 0, 0, 0, 0]~, [0, 1, 0, 0, 0]~] [[1, 0, 0, 0, 0]~, [0, 0, 0, 0, 0]~] [[0, 2, 0, 0, 0]~, [0, 0, 0, 0, 0]~] [[0, 0, 0, 0, 0]~, [0, 1, 0, 0, 0]~] [0, 1/2] [0, 1/2] [[0, 0, 0, 0, 0]~, 1/2] [[0, 0, 0, 0, 0]~, 1/2] [1, 0] [[0, 0, 0, 0, 0]~, 1/2] [[1, 2, 2, 3, 4]~, [-1/3, -2/3, 1/3, 0, -1/3]~] [[-1, -2, -3, -4, -5]~, [0, 0, 0, 0, 0]~] [[-10, -2, 10, 0, -3]~, [-6, -2, 1, 2, 1]~] [[7, -2, 4, 5, 0]~, [-5, 0, 0, 0, 0]~] [[2, 4, 6, 8, 10]~, [0, 0, 0, 0, 0]~] [[1, 0, 0, 0, 0]~, [0, 0, 0, 0, 0]~] 0 1/3 [7/3, -2, 0, -1, 0]~ 4/3 -1/6 4/3 1/3 0 [-4, -1, -1, 0, 0]~ -1 0 -1 [1/3, -1/3, -1/3, 0, 0]~ [0, 0, 0, 0, 0]~ [0, 0, 0, 0, 0]~ [1, 0, 0, 0, 0]~ [0, 0, 0, 0, 0]~ [3, 1, 1, 0, 0]~ [0, -1/3, 0, 0, 0]~ [0, 0, 0, 0, 0]~ [0, 1, 0, 0, 0]~ [0, 0, 0, 0, 0]~ [0, 0, 0, 0, 0]~ [0, 1, 0, 0, 0]~ 1/2 1/2 1/2 1/2 0 1/2 [-1/3, -2/3, 1/3, 0, -1/3]~ [0, 0, 0, 0, 0]~ [-6, -2, 1, 2, 1]~ [-5, 0, 0, 0, 0]~ [0, 0, 0, 0, 0]~ [0, 0, 0, 0, 0]~ 16/9 -4/3 [4, 4/3, 4/3, 0, 0]~ [0, 4/3, 0, 0, 0]~ 2/3 [4/3, 8/3, 4, 16/3, 20/3]~ -4/3 1 [-3, -1, -1, 0, 0]~ [0, -1, 0, 0, 0]~ -1/2 [-1, -2, -3, -4, -5]~ [4, 4/3, 4/3, 0, 0]~ [-3, -1, -1, 0, 0]~ [13, 5, 6, 2, 1]~ [2, 3, 1, 1, 0]~ [3/2, 1/2, 1/2, 0, 0]~ [-58, -42, 23, 27, 17]~ [0, 4/3, 0, 0, 0]~ [0, -1, 0, 0, 0]~ [2, 3, 1, 1, 0]~ [2, 0, 1, 0, 0]~ [0, 1/2, 0, 0, 0]~ [-33, -3, 11, 8, 4]~ 2/3 -1/2 [3/2, 1/2, 1/2, 0, 0]~ [0, 1/2, 0, 0, 0]~ 1/4 [1/2, 1, 3/2, 2, 5/2]~ [4/3, 8/3, 4, 16/3, 20/3]~ [-1, -2, -3, -4, -5]~ [-58, -42, 23, 27, 17]~ [-33, -3, 11, 8, 4]~ [1/2, 1, 3/2, 2, 5/2]~ [-1071, -384, -251, -155, 20]~ [1] [1, 1/2*x - 1/2] [2, Mod(0, 2)]~ [x^2 + x + 1, [0, 1], -3, 1, [Mat([1, -0.50000000000000000000000000000000000 000 + 0.86602540378443864676372317075293618347*I]), [1, 0.366025403784438646 76372317075293618347; 1, -1.3660254037844386467637231707529361835], [1, 0; 1 , -1], [2, -1; -1, -1], [3, 2; 0, 1], [1, -1; -1, -2], [3, [2, -1; 1, 1]], [ 3]~], [-0.50000000000000000000000000000000000000 + 0.86602540378443864676372 317075293618347*I], [1, x], [1, 0; 0, 1], [1, 0, 0, -1; 0, 1, 1, -1]] 2 [0, Mod(0, 2), 1, 0, 0, 0, 0]~ [0, Mod(1, 2), 1, 0, 1, 0, 0]~ []~ []~ 388 [2 0] [0 1] *** bnfisprincipal: Warning: precision too low for generators, not given. [[]~, [-16275043782306513717209797591668600538906793729160424387141562023303 069241961, -3992515767463859376807521115314587378342597458337773390379448027 181914746015, 40263088752008514039400780199135662260965092541683607359784818 2049497266399, 3875196415920480829978279850511752676499384722019721458357455 29259111353576, 524613164482816169908873750526849574668376660999341089640759 880949016596504]~] [[[[[1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], Vecsmall([1])], [2, [2]], [matrix(0,2), matrix(0,2)], [[], [[2], Vecsma ll([1]), Mat(1), 20.85619222793697806338436677312547069840936189148609965738 5606105759553686957605190193844727221233577865144297166021560180960373224372 600900514567409428535493879667818173119, [1; 0; 0; 0; 0]]], [Mat(1)]]], [[[[ 2, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], Vecsmall([1])], [2, [2]], [Mat([[2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -1 0, -60; 0, 0, -100, 0, -20; 0, 0, 0, -10, -100; 0, 2, -2, 0, 2; 1, 0, 0, -10 , 0]], 1]), matrix(0,2)], [[], [[2], Vecsmall([1]), Mat(1/2), 21.35619222793 6978063384366773125470698409361891486099657385606105759553686957605190193844 7272212335778651442971660215601809603732243726009005145674094285354938796678 18173119, [2; 0; 0; 0; 0]]], [Mat(1)]]], [], [[[[2, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 2, 0; 0, 0, 0, 0, 1], Vecsmall([1])], [4, [2, 2]] , [Mat([[2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -10, -60; 0, 0, -100, 0, - 20; 0, 0, 0, -10, -100; 0, 2, -2, 0, 2; 1, 0, 0, -10, 0]], 2]), Mat([[2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -10, -60; 0, 0, -100, 0, -20; 0, 0, 0, -1 0, -100; 0, 2, -2, 0, 2; 1, 0, 0, -10, 0]], 2])], [[[[2], [[-1, 0, 0, -1, 0] ~], [2, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 2, 0; 0, 0, 0, 0, 1], [[[1, 0, -1, 0, 0]~, [1, 0, 0, 0, 0], [2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -10, -60; 0, 0, -100, 0, -20; 0, 0, 0, -10, -100; 0, 2, -2, 0, 2; 1 , 0, 0, -10, 0]]]~, 1, [1, matrix(0,2)]], [1, 1, [[[2], [[1, 0, 0, 1, 0]~], Mat([0, 0, 0, 2, 0]), 2]]], [[0]~, Mat(1)]]], [[2], Vecsmall([1]), Mat(1/2), 41.368578564704732409417461169787335389425015098066066992052113922491767356 2518479971386990773198806459616749645245612672289886701908980504482902220220 62722979243788174152853, [2; 0; 0; 0; 0]]], [[1; 0], [0; 1]]], [[[2, 0, 1, 0 , 0; 0, 2, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], Vecsmall([ 1])], [6, [6]], [Mat([[2, [1, 2, 1, 0, 0]~, 1, 2, [0, -80, -20, 0, 0; 0, -1, -100, -10, -120; 1, 0, -1, -20, -100; 0, 2, 0, 0, 0; 1, 1, -1, -10, 0]], 1] ), Mat([[2, [1, 2, 1, 0, 0]~, 1, 2, [0, -80, -20, 0, 0; 0, -1, -100, -10, -1 20; 1, 0, -1, -20, -100; 0, 2, 0, 0, 0; 1, 1, -1, -10, 0]], 1])], [[[[3], [[ 1, 1, 0, 0, 0]~], [2, 0, 1, 0, 0; 0, 2, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [[[0, 0, -1, 0, -1]~, [1, 0, 1, 0, 0; 0, 1, 0, 0, 0], [2, [1, 2, 1, 0, 0]~, 1, 2, [0, -80, -20, 0, 0; 0, -1, -100, -10, -120; 1, 0, - 1, -20, -100; 0, 2, 0, 0, 0; 1, 1, -1, -10, 0]], x^2 + x + 1, [1, 0; 0, 1; 0 , 0; 0, 0; 0, 0]]~, x + 1, [3, Mat([3, 1])]]]], [[2], Vecsmall([1]), Mat(1/2 ), 21.9561427071251651311029092693376679934648273587965202418363934409277005 5508085947230952445471265103162532611846023078065155339896128119468225362650 5116814177943190107524899, [2; 0; 0; 0; 0]]], [Mat(-2), Mat(-3)]]]] [[[[[[1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0 , 1], Vecsmall([1])], [2, [2], [[-21, 0, 0, 0, 0]~]], [matrix(0,2), matrix(0 ,2)], [[], [[2], Vecsmall([1]), Mat(1), 20.856192227936978063384366773125470 6984093618914860996573856061057595536869576051901938447272212335778651442971 66021560180960373224372600900514567409428535493879667818173119, [1; 0; 0; 0; 0]]], [Mat(1)]], [Mat([1, 1, 1])]]], [[[[[2, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], Vecsmall([1])], [2, [2], [[-21, 0 , 0, 0, 0]~]], [Mat([[2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -10, -60; 0, 0, -100, 0, -20; 0, 0, 0, -10, -100; 0, 2, -2, 0, 2; 1, 0, 0, -10, 0]], 1]), matrix(0,2)], [[], [[2], Vecsmall([1]), Mat(1/2), 21.3561922279369780633843 6677312547069840936189148609965738560610575955368695760519019384472722123357 7865144297166021560180960373224372600900514567409428535493879667818173119, [ 2; 0; 0; 0; 0]]], [Mat(1)]], [[], Mat([1, 1, 1])]]], [], [[[[[2, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 2, 0; 0, 0, 0, 0, 1], Vecsmall([1])] , [4, [2, 2], [[81, 0, 0, -1, 0]~, [-41, 0, 0, 0, 0]~]], [Mat([[2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -10, -60; 0, 0, -100, 0, -20; 0, 0, 0, -10, -10 0; 0, 2, -2, 0, 2; 1, 0, 0, -10, 0]], 2]), Mat([[2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -10, -60; 0, 0, -100, 0, -20; 0, 0, 0, -10, -100; 0, 2, -2, 0, 2; 1, 0, 0, -10, 0]], 2])], [[[[2], [[-1, 0, 0, -1, 0]~], [2, 0, 0, 0, 0; 0 , 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 2, 0; 0, 0, 0, 0, 1], [[[1, 0, -1, 0, 0]~, [1, 0, 0, 0, 0], [2, [0, 0, 1, -1, 0]~, 3, 1, [0, -80, 60, -10, -60; 0, 0, -100, 0, -20; 0, 0, 0, -10, -100; 0, 2, -2, 0, 2; 1, 0, 0, -10, 0]]]~, 1 , [1, matrix(0,2)]], [1, 1, [[[2], [[1, 0, 0, 1, 0]~], Mat([0, 0, 0, 2, 0]), 2]]], [[0]~, Mat(1)]]], [[2], Vecsmall([1]), Mat(1/2), 41.36857856470473240 9417461169787335389425015098066066992052113922491767356251847997138699077319 8806459616749645245612672289886701908980504482902220220627229792437881741528 53, [2; 0; 0; 0; 0]]], [[1; 0], [0; 1]]], [Mat([0, 0, 0]), Mat([1, 1, 1])]], [[[[2, 0, 1, 0, 0; 0, 2, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], Vecsmall([1])], [6, [6], [[-21, 1, 0, 0, 0]~]], [Mat([[2, [1, 2, 1, 0, 0]~, 1, 2, [0, -80, -20, 0, 0; 0, -1, -100, -10, -120; 1, 0, -1, -20, -100; 0, 2, 0, 0, 0; 1, 1, -1, -10, 0]], 1]), Mat([[2, [1, 2, 1, 0, 0]~, 1, 2, [0, -80, -20, 0, 0; 0, -1, -100, -10, -120; 1, 0, -1, -20, -100; 0, 2, 0, 0, 0; 1, 1, -1, -10, 0]], 1])], [[[[3], [[1, 1, 0, 0, 0]~], [2, 0, 1, 0, 0; 0, 2, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [[[0, 0, -1, 0, -1]~ , [1, 0, 1, 0, 0; 0, 1, 0, 0, 0], [2, [1, 2, 1, 0, 0]~, 1, 2, [0, -80, -20, 0, 0; 0, -1, -100, -10, -120; 1, 0, -1, -20, -100; 0, 2, 0, 0, 0; 1, 1, -1, -10, 0]], x^2 + x + 1, [1, 0; 0, 1; 0, 0; 0, 0; 0, 0]]~, x + 1, [3, Mat([3, 1])]]]], [[2], Vecsmall([1]), Mat(1/2), 21.956142707125165131102909269337667 9934648273587965202418363934409277005550808594723095244547126510316253261184 60230780651553398961281194682253626505116814177943190107524899, [2; 0; 0; 0; 0]]], [Mat(-2), Mat(-3)]], [Mat([0, 1, 0]), Mat([1, 1, 1])]]]] [[[5, 1, [2, 2; 5, 2; 39821, 1; 161141, 1]]], [[]], [], [[10, 2, [2, 6; 5, 4 ; 39821, 2; 161141, 2]], []]] [[[0, 0, 0]], [[10, 0, [-1, 1; 2, 5; 5, 4; 39821, 2; 161141, 2]]], [], [[], []]] [[[[Vecsmall([]), Vecsmall([])], 0, 0, 0]], [[[Vecsmall([50]), Vecsmall([1]) ], 0, 0, 0]], [], [[[Vecsmall([50]), Vecsmall([2])], 0, 0, 0], [[Vecsmall([5 6]), Vecsmall([1])], 0, 0, 0]]] 2 [6416795761] [x^7 - x^6 + x^5 - x^4 - x^3 - x^2, x^9 + x^8 + x^7 + x^6 + 2*x^4 + 2*x^3 + x^2 + x + 1, x^10 + x^9 - x^8 - x^3 - x^2 - x, x^10 + x^9 + 2*x^7 + x^6 + x^ 5 + x^4 + 2*x^2 + x + 1, -x^11 - 2*x^10 - x^8 - 2*x^7 - x^6 - x^5 - 2*x^4 - x^3 - 2*x^2 - x - 1, -x^11 - x^10 - 2*x^9 - x^8 - 2*x^7 - x^6 - 2*x^5 - x^4 - x^2 - 2*x - 1, -x^11 - x^10 - x^9 + x^8 - x^7 + x^6, -x^11 - x^9 - x^6 + x ^4 - x^3 + x, x^11 - x^10 + x^6 - x^5 - x^2 - x, x^11 - x^8 - x^7 + x^5 - x^ 4 - x, x^11 + x^10 + 2*x^8 + x^7 + x^4 + x^3 + 2*x^2 + x + 1, x^11 + 2*x^10 + x^9 + x^7 + x^5 + x^3 + x^2 + 2*x + 1] [-x^2, x^2] [-x^2, x^2] [-x^2, x^2] 0 [35952239140236636613554193911666/20990466712995598590763903143048989*x^20 + 219201047314343953199542006623468/20990466712995598590763903143048989*x^19 - 544094474369607287844071682948984/20990466712995598590763903143048989*x^18 - 1301738076793130194798253391725406/20990466712995598590763903143048989*x^ 17 + 4323784229146831865769550863399188/20990466712995598590763903143048989* x^16 + 1180785226777964111519743237847228/2099046671299559859076390314304898 9*x^15 - 16009478553791306868545675624906176/2099046671299559859076390314304 8989*x^14 + 11661369832298820433335186698644800/2099046671299559859076390314 3048989*x^13 + 24577904562406269454374516161861844/2099046671299559859076390 3143048989*x^12 - 2841411922644145137800873408789776/12347333360585646229861 11949591117*x^11 + 40513760532585028733891495151094508/209904667129955985907 63903143048989*x^10 + 77137274588135205291798303592401638/209904667129955985 90763903143048989*x^9 - 9612104031689093945033225402487055/12347333360585646 22986111949591117*x^8 + 844775560812208284237807638227260/209904667129955985 90763903143048989*x^7 - 153457335161602039094310022600574514/209904667129955 98590763903143048989*x^6 + 454725983158981264651921915989314030/209904667129 95598590763903143048989*x^5 - 247595736314170743760908290075787460/209904667 12995598590763903143048989*x^4 + 246411488365177430998635983532374564/209904 66712995598590763903143048989*x^3 - 300616800198203967230858561992730353/209 90466712995598590763903143048989*x^2 + 62128367926034523995700779963870389/2 0990466712995598590763903143048989*x + 73920020404088609656492594951950857/2 0990466712995598590763903143048989] 0 [-z^2, z^2] 0 [-1/2*x, 1/2*x] [-2*x, 2*x] [-z, z] x^2 + 1 1 [x^10 + Mod(-5/2*y + 5/2, y^2 - 5)*x^9 + Mod(-5*y + 20, y^2 - 5)*x^8 + Mod(- 20*y + 30, y^2 - 5)*x^7 + Mod(-45/2*y + 145/2, y^2 - 5)*x^6 + Mod(-71/2*y + 121/2, y^2 - 5)*x^5 + Mod(-20*y + 60, y^2 - 5)*x^4 + Mod(-25*y + 5, y^2 - 5) *x^3 + 45*x^2 + Mod(-5*y + 15, y^2 - 5)*x + Mod(-2*y + 6, y^2 - 5), x^10 + M od(5/2*y + 5/2, y^2 - 5)*x^9 + Mod(5*y + 20, y^2 - 5)*x^8 + Mod(20*y + 30, y ^2 - 5)*x^7 + Mod(45/2*y + 145/2, y^2 - 5)*x^6 + Mod(79/2*y + 121/2, y^2 - 5 )*x^5 + Mod(25*y + 85, y^2 - 5)*x^4 + Mod(15*y + 55, y^2 - 5)*x^3 + Mod(10*y - 5, y^2 - 5)*x^2 - 10*x + Mod(-2*y + 6, y^2 - 5)] [x^10 + Mod(-5/2*y + 5/2, y^2 - 5)*x^9 + Mod(-5*y + 20, y^2 - 5)*x^8 + Mod(- 20*y + 30, y^2 - 5)*x^7 + Mod(-45/2*y + 145/2, y^2 - 5)*x^6 + Mod(-71/2*y + 121/2, y^2 - 5)*x^5 + Mod(-20*y + 60, y^2 - 5)*x^4 + Mod(-25*y + 5, y^2 - 5) *x^3 + 45*x^2 + Mod(-5*y + 15, y^2 - 5)*x + Mod(-2*y + 6, y^2 - 5), Mod(Mod( 26/2945*y - 653/5890, y^2 - 5)*x^9 + Mod(1633/5890*y - 869/2945, y^2 - 5)*x^ 8 + Mod(2951/5890*y - 5939/2945, y^2 - 5)*x^7 + Mod(21757/11780*y - 29451/11 780, y^2 - 5)*x^6 + Mod(18733/11780*y - 69587/11780, y^2 - 5)*x^5 + Mod(1445 /589*y - 9436/2945, y^2 - 5)*x^4 + Mod(7893/11780*y - 34679/11780, y^2 - 5)* x^3 + Mod(9461/5890*y + 3919/2945, y^2 - 5)*x^2 + Mod(-8383/11780*y - 54699/ 11780, y^2 - 5)*x + Mod(261/589*y - 2467/2945, y^2 - 5), x^10 + Mod(-5/2*y + 5/2, y^2 - 5)*x^9 + Mod(-5*y + 20, y^2 - 5)*x^8 + Mod(-20*y + 30, y^2 - 5)* x^7 + Mod(-45/2*y + 145/2, y^2 - 5)*x^6 + Mod(-71/2*y + 121/2, y^2 - 5)*x^5 + Mod(-20*y + 60, y^2 - 5)*x^4 + Mod(-25*y + 5, y^2 - 5)*x^3 + 45*x^2 + Mod( -5*y + 15, y^2 - 5)*x + Mod(-2*y + 6, y^2 - 5)), Mod(Mod(26/2945*y - 653/589 0, y^2 - 5)*x^9 + Mod(1633/5890*y - 869/2945, y^2 - 5)*x^8 + Mod(2951/5890*y - 5939/2945, y^2 - 5)*x^7 + Mod(21757/11780*y - 29451/11780, y^2 - 5)*x^6 + Mod(18733/11780*y - 69587/11780, y^2 - 5)*x^5 + Mod(1445/589*y - 9436/2945, y^2 - 5)*x^4 + Mod(7893/11780*y - 34679/11780, y^2 - 5)*x^3 + Mod(9461/5890 *y + 3919/2945, y^2 - 5)*x^2 + Mod(-8383/11780*y - 42919/11780, y^2 - 5)*x + Mod(261/589*y - 2467/2945, y^2 - 5), x^10 + Mod(-5/2*y + 5/2, y^2 - 5)*x^9 + Mod(-5*y + 20, y^2 - 5)*x^8 + Mod(-20*y + 30, y^2 - 5)*x^7 + Mod(-45/2*y + 145/2, y^2 - 5)*x^6 + Mod(-71/2*y + 121/2, y^2 - 5)*x^5 + Mod(-20*y + 60, y ^2 - 5)*x^4 + Mod(-25*y + 5, y^2 - 5)*x^3 + 45*x^2 + Mod(-5*y + 15, y^2 - 5) *x + Mod(-2*y + 6, y^2 - 5)), -1] Mod(0, x^10 + Mod(-5/2*y + 5/2, y^2 - 5)*x^9 + Mod(-5*y + 20, y^2 - 5)*x^8 + Mod(-20*y + 30, y^2 - 5)*x^7 + Mod(-45/2*y + 145/2, y^2 - 5)*x^6 + Mod(-71/ 2*y + 121/2, y^2 - 5)*x^5 + Mod(-20*y + 60, y^2 - 5)*x^4 + Mod(-25*y + 5, y^ 2 - 5)*x^3 + 45*x^2 + Mod(-5*y + 15, y^2 - 5)*x + Mod(-2*y + 6, y^2 - 5)) 1 [Mod(1, y^2 - 5)*x^5 + Mod(y, y^2 - 5), x^10 + Mod(77*y - 275, y^2 - 5)*x^5 + Mod(-41525*y + 96630, y^2 - 5), x^10 + Mod(77*y + 275, y^2 - 5)*x^5 + Mod( 41525*y + 96630, y^2 - 5)] x^10 + 5*x^9 + 15*x^8 + 30*x^7 + 45*x^6 + Mod(2*y + 51, y^2 - 5)*x^5 + Mod(5 *y + 45, y^2 - 5)*x^4 + Mod(-10*y + 30, y^2 - 5)*x^3 + Mod(-20*y + 15, y^2 - 5)*x^2 + Mod(-5*y + 5, y^2 - 5)*x + Mod(y + 6, y^2 - 5) [x^10 + 5*x^9 + 15*x^8 + 30*x^7 + 45*x^6 + Mod(2*y + 51, y^2 - 5)*x^5 + Mod( 5*y + 45, y^2 - 5)*x^4 + Mod(-10*y + 30, y^2 - 5)*x^3 + Mod(-20*y + 15, y^2 - 5)*x^2 + Mod(-5*y + 5, y^2 - 5)*x + Mod(y + 6, y^2 - 5), Mod(-32280/622201 *x^9 + Mod(22275/622201*y - 145260/622201, y^2 - 5)*x^8 + Mod(89100/622201*y - 397350/622201, y^2 - 5)*x^7 + Mod(244100/622201*y - 22995/20071, y^2 - 5) *x^6 + Mod(420450/622201*y - 918351/622201, y^2 - 5)*x^5 + Mod(510720/622201 *y - 852705/622201, y^2 - 5)*x^4 + Mod(424640/622201*y - 238275/622201, y^2 - 5)*x^3 + Mod(871950/622201*y + 235710/622201, y^2 - 5)*x^2 + Mod(714855/62 2201*y - 1610346/622201, y^2 - 5)*x + Mod(-62626/622201*y - 860751/622201, y ^2 - 5), x^10 + 5*x^9 + 15*x^8 + 30*x^7 + 45*x^6 + Mod(2*y + 51, y^2 - 5)*x^ 5 + Mod(5*y + 45, y^2 - 5)*x^4 + Mod(-10*y + 30, y^2 - 5)*x^3 + Mod(-20*y + 15, y^2 - 5)*x^2 + Mod(-5*y + 5, y^2 - 5)*x + Mod(y + 6, y^2 - 5)), Mod(-322 80/622201*x^9 + Mod(22275/622201*y - 145260/622201, y^2 - 5)*x^8 + Mod(89100 /622201*y - 397350/622201, y^2 - 5)*x^7 + Mod(244100/622201*y - 22995/20071, y^2 - 5)*x^6 + Mod(420450/622201*y - 918351/622201, y^2 - 5)*x^5 + Mod(5107 20/622201*y - 852705/622201, y^2 - 5)*x^4 + Mod(424640/622201*y - 238275/622 201, y^2 - 5)*x^3 + Mod(871950/622201*y + 235710/622201, y^2 - 5)*x^2 + Mod( 714855/622201*y - 988145/622201, y^2 - 5)*x + Mod(-62626/622201*y - 860751/6 22201, y^2 - 5), x^10 + 5*x^9 + 15*x^8 + 30*x^7 + 45*x^6 + Mod(2*y + 51, y^2 - 5)*x^5 + Mod(5*y + 45, y^2 - 5)*x^4 + Mod(-10*y + 30, y^2 - 5)*x^3 + Mod( -20*y + 15, y^2 - 5)*x^2 + Mod(-5*y + 5, y^2 - 5)*x + Mod(y + 6, y^2 - 5)), -1] [x^2 + x + 1, Mod(0, x^2 + x + 1), Mod(x, x^2 + x + 1), -1] [25339, [10960, 0, 0, -3420]~] [x^3 - 3*x^2 + 3*x + 1, x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1] [x^3 - 3*x^2 + 3*x + 1, x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1] [[4]~, [33/343, 2/2401]~] Mod(1/2*x - 1/2, x^2 + 23) [1, 2]~ [1, 1/2*x - 1/2] Mod(0, x) Mod(-6/5, x) *** at top-level: nfinit([y^3+2,[1,x]]) *** ^--------------------- *** nfinit: incorrect type in nfbasic_init (t_VEC). *** at top-level: nfinit([y^3+2,[1,x,x^2]]) *** ^------------------------- *** nfinit: incorrect type in nfbasic_init (t_VEC). *** at top-level: nfinit([y^3+2,[1,y^5,y]]) *** ^------------------------- *** nfinit: incorrect type in nfbasic_init (t_VEC). *** at top-level: nfdisc([y^2+2,matid(3)]) *** ^------------------------ *** nfdisc: incorrect type in nfmaxord (t_MAT). *** at top-level: nfdisc([2*y^2+1,matid(3)]) *** ^-------------------------- *** nfdisc: incorrect type in nfbasis [factorization expected] (t_MAT). *** at top-level: nfdisc([y^2+2,""]) *** ^------------------ *** nfdisc: incorrect type in nfmaxord (t_STR). *** at top-level: nfnewprec(x) *** ^------------ *** nfnewprec: incorrect type in nfnewprec (t_POL). *** at top-level: nfnewprec(quadgen(5)) *** ^--------------------- *** nfnewprec: incorrect type in nfnewprec (t_QUAD). *** at top-level: nfnewprec(vector(5)) *** ^-------------------- *** nfnewprec: incorrect type in nfnewprec (t_VEC). *** at top-level: nfnewprec(vector(6)) *** ^-------------------- *** nfnewprec: incorrect type in nfnewprec (t_VEC). *** at top-level: nfnewprec(vector(8)) *** ^-------------------- *** nfnewprec: incorrect type in nfnewprec (t_VEC). *** at top-level: nfnewprec(vector(9)) *** ^-------------------- *** nfnewprec: incorrect type in nfnewprec (t_VEC). *** at top-level: nfnewprec(vector(16)) *** ^--------------------- *** nfnewprec: incorrect type in nfnewprec (t_VEC). *** at top-level: nfcompositum(nfinit(x-1),x^3-2,x^3-1) *** ^------------------------------------- *** nfcompositum: incorrect priority in polcompositum: variable x >= x *** at top-level: nfcompositum(nfinit(x^2+1),x^3-2,x^3-1) *** ^--------------------------------------- *** nfcompositum: incorrect priority in polcompositum: variable x >= x *** at top-level: nfcompositum(nfinit(x-1),y^3-2,y^3-1) *** ^------------------------------------- *** nfcompositum: incorrect priority in polcompositum: variable x >= y *** at top-level: nfcompositum(bnfinit(x),x^3-2,x^3-1) *** ^------------------------------------ *** nfcompositum: incorrect priority in polcompositum: variable x >= x *** at top-level: nfisincl(y^2+1,z^4+z^2+1) *** ^------------------------- *** nfisincl: not an irreducible polynomial in nfisincl: z^4 + z^2 + 1. *** at top-level: nfisisom(x,x^0) *** ^--------------- *** nfisisom: not an irreducible polynomial in nfisincl: 1. *** at top-level: idealhnf(nf,3,('a^2+1)*Mod(1,3)) *** ^-------------------------------- *** idealhnf: incorrect type in nf_to_scalar_or_basis (t_INTMOD). *** at top-level: nfalgtobasis(nf,['a,'a]~) *** ^------------------------- *** nfalgtobasis: incorrect type in nfalgtobasis (t_COL). Total time spent: 13920 pari-2.11.2/src/test/32/bern0000644000175000017500000000253213326135265014031 0ustar billbill-1/2 1/6 0 -1/30 0 1/42 0 -1/30 0 5/66 0 -691/2730 0 7/6 0 -3617/510 0 43867/798 0 -174611/330 1 x - 1/2 x^2 - x + 1/6 x^3 - 3/2*x^2 + 1/2*x x^4 - 2*x^3 + x^2 - 1/30 x^5 - 5/2*x^4 + 5/3*x^3 - 1/6*x *** at top-level: bernfrac(-1) *** ^------------ *** bernfrac: domain error in bernfrac: index < 0 *** at top-level: bernreal(-1) *** ^------------ *** bernreal: domain error in bernreal: index < 0 *** at top-level: bernpol(-1) *** ^----------- *** bernpol: domain error in bernpol: index < 0 [1, 1/6, -1/30, 1/42, -1/30, 5/66, -691/2730, 7/6, -3617/510, 43867/798, -17 4611/330, 854513/138, -236364091/2730, 8553103/6, -23749461029/870, 86158412 76005/14322, -7709321041217/510, 2577687858367/6, -26315271553053477373/1919 190, 2929993913841559/6, -261082718496449122051/13530, 152009764391807080269 1/1806, -27833269579301024235023/690, 596451111593912163277961/282, -5609403 368997817686249127547/46410, 495057205241079648212477525/66, -80116571813548 9957347924991853/1590, 29149963634884862421418123812691/798, -24793929293132 26753685415739663229/870, 84483613348880041862046775994036021/354, -12152331 40483755572040304994079820246041491/56786730] 601580873.90064236838430386817483591677 3.7508755436454409098345241010481418931 E218 601580873.90064236838430386817483591677 Total time spent: 1 pari-2.11.2/src/test/32/qf0000644000175000017500000000352113326135265013510 0ustar billbill [7/2 1 8/7 11/7] [ -1 -7/2 -4/7 -5/7] [ 0 0 -24/7 -29/24] [ 0 0 0 -311/168] [12, 1] 266 Vecsmall([0, 0, 0, 0, 0, 0, 0, 133, 0, 165, 0, 638, 0, 396, 0, 4268]) Vecsmall([0, 0, 0, 133, 165, 638, 396, 4268]) [8, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]~] [8, [2, 2, -1, -1, 1, 1, -2, 0, -1, -1, -1, -1]~] [] [] [0, 0, [;]] [0, 0, [;]] [] [0, 0, [;]] *** at top-level: qfminim(L~*L,10^16)[2] *** ^---------------------- *** qfminim: precision too low in qfminim. 10000000000000000.000 [0, 1]~ [1, 0]~ [1, -1]~ [1, -1]~ 14 23 2 -13 [66 78 90] [78 93 108] [90 108 126] [35 67 99] [67 110 153] [99 153 207] *** at top-level: qfeval(,1) *** ^---------- *** qfeval: incorrect type in qfeval (t_INT). *** at top-level: qfeval(,1,1) *** ^------------ *** qfeval: incorrect type in qfeval (t_INT). *** at top-level: qfeval(Mat(1),x) *** ^---------------- *** qfeval: inconsistent dimensions in qfeval. *** at top-level: qfeval(Mat(x~),x) *** ^----------------- *** qfeval: inconsistent dimensions in qfeval. *** at top-level: qfeval(,1,1) *** ^------------ *** qfeval: incorrect type in qfeval (t_INT). *** at top-level: qfeval(,[1],[1,2]) *** ^------------------ *** qfeval: inconsistent dimensions in qfeval. *** at top-level: qfeval(q,[1,2],[1,2]) *** ^--------------------- *** qfeval: inconsistent dimensions in qfevalb. *** at top-level: qfeval(Mat([1,2]),[1,2],[1,2]) *** ^------------------------------ *** qfeval: inconsistent operation 'RgV_RgM_mul' t_VEC (2 elts) , t_MAT (1x2). *** at top-level: qfeval(1,1) *** ^----------- *** qfeval: incorrect type in qfeval (t_INT). Total time spent: 16 pari-2.11.2/src/test/32/prime0000644000175000017500000000256213326135265014222 0ustar billbill8161 17863 38873 84017 180503 386093 821641 1742537 3681131 7754077 16290047 172 309 564 1028 1900 3512 6542 12251 23000 43390 82025 155611 295947 56416 3 1077871 2063689 3957809 8161 17863 38873 84017 180503 386093 821641 1742537 3681131 7754077 16290047 172 309 564 1028 1900 3512 6542 12251 23000 43390 82025 155611 295947 56416 3 1077871 2063689 3957809 203280221 0 200000 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229] [2, 3, 5] [11, 13, 17, 19] [4294967197, 4294967231, 4294967279, 4294967291, 4294967311, 4294967357, 429 4967371, 4294967377, 4294967387, 4294967389] [18446744073709551521, 18446744073709551533, 18446744073709551557, 184467440 73709551629, 18446744073709551653, 18446744073709551667, 1844674407370955169 7, 18446744073709551709] 5758 61938 2 4294967311 18446744073709551629 3 2 *** at top-level: primes([1,Pol(2)]) *** ^------------------ *** primes: incorrect type in primes_interval (t_POL). *** at top-level: nextprime(x) *** ^------------ *** nextprime: incorrect type in nextprime (t_POL). *** at top-level: precprime(x) *** ^------------ *** precprime: incorrect type in nextprime (t_POL). Total time spent: 900 pari-2.11.2/src/test/32/ideal0000644000175000017500000001044113455056357014166 0ustar billbill[;] [1, 0] *** at top-level: idealaddtoone(Q,2,[;]) *** ^---------------------- *** idealaddtoone: elements not coprime in idealaddtoone: Mat(2) [;] *** at top-level: idealaddtoone(Q,[;],[;]) *** ^------------------------ *** idealaddtoone: elements not coprime in idealaddtoone: [;] [;] [1, 0] [[1]~, 0] *** at top-level: idealaddtoone(Q,[1,[;],Mat(1/2)]) *** ^--------------------------------- *** idealaddtoone: incorrect type in idealaddmultoone [integer matrix] (t_MAT). *** at top-level: ideallog(Q,2,zQ) *** ^---------------- *** ideallog: elements not coprime in zlog_prk1: 2 Mat(4) [2, [2], [5]] *** at top-level: ideallog(,0,z) *** ^-------------- *** ideallog: elements not coprime in znconreylog: 0 6 *** at top-level: ideallog(,2,z) *** ^-------------- *** ideallog: elements not coprime in znconreylog: 2 6 *** at top-level: ideallog(,3,z) *** ^-------------- *** ideallog: elements not coprime in znconreylog: 3 6 *** at top-level: ideallog(Q,3,z) *** ^--------------- *** ideallog: incorrect type in checkbid (t_VEC). *** at top-level: ideallog(,3,zQ) *** ^--------------- *** ideallog: incorrect type in znconreylog (t_MAT). [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] 0 [512, [16, 8, 4], [[3, 2]~, 5, [0, -1]~]] [1, [], []] [1/2 0] [ 0 1/2] [1]~ [5 2] [0 1] [2 1] [0 1] [2 0 0] [0 1 0] [0 0 1] [1/12 0 0] [ 0 1/12 0] [ 0 0 1/12] [2 0 0] [0 2 0] [0 0 2] [1/6 0 0] [ 0 1/6 0] [ 0 0 1/6] [1/3 0 0] [ 0 1/6 0] [ 0 0 1/6] [1 0 0] [0 1 0] [0 0 1/2] 0 0 1 1 [1725 35 1704] [ 0 5 4] [ 0 0 1] *** at top-level: idealmul(K,[2,1;0,1],[2,1;0,1]) *** ^------------------------------- *** idealmul: inconsistent dimensions in idealmul. *** at top-level: idealmul(K,matid(4),matid(4)) *** ^----------------------------- *** idealmul: inconsistent dimensions in idealmul. 5 [1 0 0] [0 1 0] [0 0 1/2] [1 0 0] [0 1 0] [0 0 1] [1/2 0 0] [ 0 1/2 0] [ 0 0 1/2] [1 0 0] [0 1 0] [0 0 1] [1 0 0] [0 1/2 0] [0 0 1/2] 7 8 9 10 11 [1 0 0] [0 1 0] [0 0 1] [[1, 0, 0; 0, 1, 0; 0, 0, 1], Mat([2, 1])] [[1, 0, 0; 0, 1, 0; 0, 0, 1], Mat([2, 1])] matrix(0,2) [[2, [2, 0, 0, 0]~, 1, 4, 1] 1] matrix(0,2) [[2, [2, 0, 0, 0]~, 1, 4, 1] -1] [[2, [2, 0, 0, 0]~, 1, 4, 1] 4] [[67452192952521724999, [-16711321285323715217, 1]~, 1, 1, [1671132128532371 5218, -1; 1, 16711321285323715217]] 1] [[762234946175168528650011228121, [-63146078120386376378131819641, 1]~, 1, 1 , [63146078120386376378131819642, -1; 1, 63146078120386376378131819641]] -1] [ [13, [-3, 1]~, 1, 1, [4, -1; 1, 3]] 2] [[13, [4, 1]~, 1, 1, [-3, -1; 1, -4]] 2] [ [3, [-1, 1]~, 2, 1, [-1, -1; 1, -2]] 1] [[37, [-10, 1]~, 1, 1, [11, -1; 1, 10]] 1] matrix(0,2) [[37, [-10, 1]~, 1, 1, [11, -1; 1, 10]] 1] [ [3, [-1, 1]~, 2, 1, [-1, -1; 1, -2]] 1] [ [37, [-10, 1]~, 1, 1, [11, -1; 1, 10]] 1] [[1093, [-151, 1]~, 1, 1, [152, -1; 1, 151]] 1] [67452192952521724999 19368419142280277485321497629511555041951889852345/762 234946175168528650011228121] [0 1/762234946175168528650011228121] [[67452192952521724999, 50740871667198009782; 0, 1], [7622349461751685286500 11228121, 699088868054782152271879408480; 0, 1]] [[67452192952521724999, 50740871667198009782; 0, 1], 1] [1, 1] [1, 2] [[1, 0; 0, 1], [2, 0; 0, 2]] [18, 9]~ [-85124952/2401, 33204681/2401]~ [249/2401, 1644/2401]~ [7, 14]~ [0, 14]~ [1, 0] [2, [0, -4]~] [3, [8/125, 0]~] [4, [0, 1]~] [9, 4]~ [15, 4]~ [-3, 4]~ [-15, 4]~ [-2]~ [2]~ [0]~ 1 [75 22 41] [ 0 1 0] [ 0 0 1] 0 1 1 [2] 1 [10 0 0] [ 0 5 0] [ 0 0 5] [] *** nfinit: Warning: non-monic polynomial. Result of the form [nf,c]. [[2, [0, 1]~, 2, 1, [0, -2; 1, 0]]] [17, 20, 12, 14, -12, 11]~ [30, 40, 28, 10, -16, 10]~ [-57, -88, -18, -74, -33, 19]~ [-12, -9, -5, -6, -2, 5]~ 1 1 [-1/18, -1/9, 0, 0, 0, 0]~ 1 [0, -2, 2, 1, -1, 0]~ *** at top-level: idealred(nf,[2,Mat(1)]) *** ^----------------------- *** idealred: incorrect type in idealtyp [extended ideal] (t_VEC). Total time spent: 154 pari-2.11.2/src/test/32/matpermanent0000644000175000017500000000150413326135265015574 0ustar billbill1 a 1 (j*e + h*f)*a + ((j*d + g*f)*b + (h*d + g*e)*c) 450 225/4 450.00000000000000000000000000000000000 2432902008176640000 5923651457692698111014016643988523721001231402487426778059781745358246359177 62560000 3083006079469106283548010402121540337574621576466658968216372244601693632059 0710729600180853543474258186192116072131181104815025761774130562338354193365 1962372270527617850320061887552530356998486431159949171842025616672790485876 08238404756881640802750401375601950720000000 *** at top-level: matpermanent(matrix(64)) *** ^------------------------ *** matpermanent: sorry, large matrix permanent is not yet implemented. *** at top-level: matpermanent(matrix(2,3)) *** ^------------------------- *** matpermanent: inconsistent dimensions in matpermanent. Total time spent: 2132 pari-2.11.2/src/test/32/trans0000644000175000017500000006641113326135265014240 0ustar billbill realprecision = 2003 significant digits (2000 digits displayed) echo = 1 ? abs(-0.01) 0.01000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000 ? agm(1,2) 1.45679103104690686918643238326508197497386394322130559079417238326792645458 0250900257473712818448444328189401816036799935576243074340124511691213249952 2793768970211976726893728266666782707432902072384564600963133367494416649516 4008269322390862633767383824102548872626451365906604088758851004667281309474 3978935512911720175447186956416035641113070606125170400972745374521370401420 1441576823232389645029091322392292018630204591966775362115295609984320494009 6186133886391108403038148862815907317011423554730230353362620898683561308007 5985703121250813571733533606272496417145565136129415437696905495272776402217 1898328404019382434954163396634111712470749200493994758236553202742331569542 1876892595105619103413471250457295583940482770732998417330233202020190654108 3764475690954512308594220997449412380273230046465841574004772512701790771147 6178286660643441589473410355454995401702603050129297014707762364655074858504 2893120294754259839628734570376126531045680923276419320475962493117272367678 4849010063883831645335627155765372880260543270126668904548807658246837332956 7456063204392060008273159252979241205175727929568980698371820180811180125021 3108997246951100317036787543001787446227930192106015685776149083936743191510 5478717272782446538831715921363968336746689231345994523668360452657260101103 3970534995271323625630073974543738138730451563908543487241207008447748794693 7515044344604858428093017239592603673212918887571985640286492629881099516041 7385214470404976503137921156910217010840121652176385776278443131535045190731 0748437504378670908384466987679450508904899924299954903140622820681590930451 6140452345824869722715061998188837843566441517471116059500690242314345907596 6810454416997061373268370421830924936517791683419258027937814913005585514983 9054216129918366396073532425917284089191304056017436113358867622552811309835 6883812066118653768412057434259281956810028485877428124011968982035483804304 1113162808407169939503577633814675423251711145297625856010709698328986771681 3002707534621244314382491 ? agm(1+O(7^5),8+O(7^5)) 1 + 4*7 + 6*7^2 + 5*7^3 + 2*7^4 + O(7^5) ? 4*arg(3+3*I) 3.14159265358979323846264338327950288419716939937510582097494459230781640628 6208998628034825342117067982148086513282306647093844609550582231725359408128 4811174502841027019385211055596446229489549303819644288109756659334461284756 4823378678316527120190914564856692346034861045432664821339360726024914127372 4587006606315588174881520920962829254091715364367892590360011330530548820466 5213841469519415116094330572703657595919530921861173819326117931051185480744 6237996274956735188575272489122793818301194912983367336244065664308602139494 6395224737190702179860943702770539217176293176752384674818467669405132000568 1271452635608277857713427577896091736371787214684409012249534301465495853710 5079227968925892354201995611212902196086403441815981362977477130996051870721 1349999998372978049951059731732816096318595024459455346908302642522308253344 6850352619311881710100031378387528865875332083814206171776691473035982534904 2875546873115956286388235378759375195778185778053217122680661300192787661119 5909216420198938095257201065485863278865936153381827968230301952035301852968 9957736225994138912497217752834791315155748572424541506959508295331168617278 5588907509838175463746493931925506040092770167113900984882401285836160356370 7660104710181942955596198946767837449448255379774726847104047534646208046684 2590694912933136770289891521047521620569660240580381501935112533824300355876 4024749647326391419927260426992279678235478163600934172164121992458631503028 6182974555706749838505494588586926995690927210797509302955321165344987202755 9602364806654991198818347977535663698074265425278625518184175746728909777727 9380008164706001614524919217321721477235014144197356854816136115735255213347 5741849468438523323907394143334547762416862518983569485562099219222184272550 2542568876717904946016534668049886272327917860857843838279679766814541009538 8378636095068006422512520511739298489608412848862694560424196528502221066118 6306744278622039194945047123713786960956364371917287467764657573962413890865 8326459958133904780275901 ? bernreal(12) -0.2531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 3553113553113553113553113553113553113553113553113553113553113553113553113553 1135531135531135531135531135531135531135531135531135531135531135531135531135 5311355311355311355311355311355311355311355311355311355311355311355311355311 355311355311355311355311355 ? bernvec(6) [1, 1/6, -1/30, 1/42, -1/30, 5/66, -691/2730] ? eta(q) 1 - q - q^2 + q^5 + q^7 - q^12 - q^15 + O(q^17) ? gammah(10) 1133278.38894878556733457416558889247556029830827515977660872341452948339005 6004153717630538727607290658350271700893237334889580173178076577597995379664 6009714415152490764416630481375706606053932396039541459764525989187023837695 1671610855238044170151137400635358652611835795089229729903867565432085491785 4385740637379886563030379410949122020517030255827739818376409926875136586189 2723863412249690833216320407918186480305202146014474770321625907339955121137 5592642390902407584016964257200480120814533383602757695668466603948271024098 9327940404023866529740516995285324916879158647845355052036653927090566136730 0094575478250332011940143726954935586482054200041299507288301750480889450074 6343904971296912338686722783533463981407672637863409944118391772608796763236 9447079178552767334696553209914181695759970997941993901164691598147347830004 4823839605663115658079374350293361148126253885222073444191541294051101114944 2148757269775793389728426903218921936202601614618932645339512192242743521391 3623655029508006651504215607326378350230912034475135438952688674605137188671 8291478726407002040566684129567384943465438236552781293212272474626739330722 3823357944724162685811265841905467657996783321819427448381523647154314724898 8856361879313902224622692050075011483135711717132961476630033785190129658511 7517708668749218485078393526224163290497667641778463362558549256811856160652 4106684792418747471383982225174086085681964985490608637796815226536639176681 1441751691654768874563756211537865821827254193841183086848150171014212517613 4162649414056791266931385305249721381461657257845049119527820872404022311592 3493153739717855496390762049815239940623016182617392553134094087438136687759 5419535805662758475769269988659439227267578534611414012815013931015921875970 6336658641047462598114625941565529553227923237890531007539153745378752638260 5084066808355122734552729235496172099847732335381840125710668124155748264901 6432532465927671474115401431858884909633728259417038958526362232126251606829 1066841997114282966060548 ? Pi 3.14159265358979323846264338327950288419716939937510582097494459230781640628 6208998628034825342117067982148086513282306647093844609550582231725359408128 4811174502841027019385211055596446229489549303819644288109756659334461284756 4823378678316527120190914564856692346034861045432664821339360726024914127372 4587006606315588174881520920962829254091715364367892590360011330530548820466 5213841469519415116094330572703657595919530921861173819326117931051185480744 6237996274956735188575272489122793818301194912983367336244065664308602139494 6395224737190702179860943702770539217176293176752384674818467669405132000568 1271452635608277857713427577896091736371787214684409012249534301465495853710 5079227968925892354201995611212902196086403441815981362977477130996051870721 1349999998372978049951059731732816096318595024459455346908302642522308253344 6850352619311881710100031378387528865875332083814206171776691473035982534904 2875546873115956286388235378759375195778185778053217122680661300192787661119 5909216420198938095257201065485863278865936153381827968230301952035301852968 9957736225994138912497217752834791315155748572424541506959508295331168617278 5588907509838175463746493931925506040092770167113900984882401285836160356370 7660104710181942955596198946767837449448255379774726847104047534646208046684 2590694912933136770289891521047521620569660240580381501935112533824300355876 4024749647326391419927260426992279678235478163600934172164121992458631503028 6182974555706749838505494588586926995690927210797509302955321165344987202755 9602364806654991198818347977535663698074265425278625518184175746728909777727 9380008164706001614524919217321721477235014144197356854816136115735255213347 5741849468438523323907394143334547762416862518983569485562099219222184272550 2542568876717904946016534668049886272327917860857843838279679766814541009538 8378636095068006422512520511739298489608412848862694560424196528502221066118 6306744278622039194945047123713786960956364371917287467764657573962413890865 8326459958133904780275901 ? precision(Pi,38) 3.14159265358979323846264338327950288420 ? sqr(1+O(2)) 1 + O(2^3) ? sqrt(13+O(127^12)) 34 + 125*127 + 83*127^2 + 107*127^3 + 53*127^4 + 42*127^5 + 22*127^6 + 98*12 7^7 + 127^8 + 23*127^9 + 122*127^10 + 79*127^11 + O(127^12) ? teichmuller(7+O(127^12)) 7 + 57*127 + 58*127^2 + 83*127^3 + 52*127^4 + 109*127^5 + 74*127^6 + 16*127^ 7 + 60*127^8 + 47*127^9 + 65*127^10 + 5*127^11 + O(127^12) ? \p500 realprecision = 500 significant digits ? Catalan 0.91596559417721901505460351493238411077414937428167213426649811962176301977 6254769479356512926115106248574422619196199579035898803325859059431594737481 1584069953320287733194605190387274781640878659090247064841521630002287276409 4238825995774150881639747025248201156070764488380787337048990086477511322599 7134340748540755323076856533576809583526021938232395080072068035576104823573 3942319149829836189977069036404180862179411019175327431499782339761055122477 9530324875371878665828082360570225594194818097 ? Euler 0.57721566490153286060651209008240243104215933593992359880576723488486772677 7664670936947063291746749514631447249807082480960504014486542836224173997644 9235362535003337429373377376739427925952582470949160087352039481656708532331 5177661152862119950150798479374508570574002992135478614669402960432542151905 8775535267331399254012967420513754139549111685102807984234877587205038431093 9973613725530608893312676001724795378367592713515772261027349291394079843010 3417771778088154957066107501016191663340152279 ? acos(0.5) 1.04719755119659774615421446109316762806572313312503527365831486410260546876 2069666209344941780705689327382695504427435549031281536516860743908453136042 8270391500947009006461737018532148743163183101273214762703252219778153761585 4941126226105509040063638188285564115344953681810888273779786908674971375790 8195668868771862724960506973654276418030571788122630863453337110176849606822 1737947156506471705364776857567885865306510307287057939775372643683728493581 541266542498557839619175749637426460610039831 ? acosh(3) 1.76274717403908605046521864995958461805632065652327082150659121730675436844 4052175667413783820512085713479632384212984377524145023953183875054510925531 5808184431573607257943924806147148192510979557431265247356130135260657908083 2711638011905460870335948934683023103172356012785221262668194525145789831496 9445764001529311893860982812579887622449034763169345542526389217689105106337 1787365189299048490338319777210134365908031791918295896639410019154526845141 480345838118685682417318463628901744528191443 ? 3*asin(sqrt(3)/2) 3.14159265358979323846264338327950288419716939937510582097494459230781640628 6208998628034825342117067982148086513282306647093844609550582231725359408128 4811174502841027019385211055596446229489549303819644288109756659334461284756 4823378678316527120190914564856692346034861045432664821339360726024914127372 4587006606315588174881520920962829254091715364367892590360011330530548820466 5213841469519415116094330572703657595919530921861173819326117931051185480744 623799627495673518857527248912279381830119491 ? asinh(0.5) 0.48121182505960344749775891342436842313518433438566051966101816884016386760 8221774412009429122723474997231839958293656411272568323726737622753059241864 4097541824170072118371502238239374691872752432791930187970790035617267969445 4575230534543418876528553256490207399693496618755630102123996367930820635997 7988509980156825797852649328666651116241713808272592788479026096533113247227 5149314064985088932176366002566661953210679681757661847307351598603984845754 5412056323413570047800639487224315261789680045 ? 3*atan(sqrt(3)) 3.14159265358979323846264338327950288419716939937510582097494459230781640628 6208998628034825342117067982148086513282306647093844609550582231725359408128 4811174502841027019385211055596446229489549303819644288109756659334461284756 4823378678316527120190914564856692346034861045432664821339360726024914127372 4587006606315588174881520920962829254091715364367892590360011330530548820466 5213841469519415116094330572703657595919530921861173819326117931051185480744 623799627495673518857527248912279381830119491 ? atanh(0.5) 0.54930614433405484569762261846126285232374527891137472586734716681874714660 9304483436807877406866044393985014532978932871184002112965259910526400935383 6387053015813845916906835896868494221804799518712851583979557605727959588753 3567352747008338779011110158512647344878034505326075282143406901815868664928 8891183495827396065909074510015051911815061124326374099112995548726245448229 0267335044229825428742220595094285438237474335398065429147058010830605920007 0491275719597438444683992471511278657676648427 ? besseljh(1,1) 0.24029783912342701089584304474193368045758480608072900860700721913956804181 9821642483230581867706826873304134469286897059613333800107373387969440858132 2409671228346463513063730101700769785661236389472736777787130860593313537501 4950471611773181090861874975058165031596147120593670107339079838226694509538 1174862561382806604491442967609698710345402983618630021989455840750069855186 9089492304665506543890102558566214670131694260158621630986009048855189842820 0103186464147214505293464124112486584095535336 ? cos(1) 0.54030230586813971740093660744297660373231042061792222767009725538110039477 4471764517951856087183089343571731160030089097860633760021663456406512265417 3185847179711644744794942331179245513932543359435177567028925963757361543275 4964175449177511513122273010063135707823223677140151746899593667873067422762 0245077637440675874981617842720216455851115632968890571081242729331698685247 1456894904342375433094423024093596239583182454728173664078071243433621748100 3220271297578822917644683598726994264913443918 ? cosh(1) 1.54308063481524377847790562075706168260152911236586370473740221471076906304 9223698964264726435543035587046858604423527565032194694709586290763493942377 3472069151633480026408029059364105029494057980033657762593319443209506958499 1368981037430548471273929845616039038581747145363600451873630682751434880120 2720574972705524471670706447103271142282939448411677273102139632958667273012 2826261409857215459162042522453939258584439199475134380734969475319971032521 055637731102374474158960765443652715148207669 ? exp(1) 2.71828182845904523536028747135266249775724709369995957496696762772407663035 3547594571382178525166427427466391932003059921817413596629043572900334295260 5956307381323286279434907632338298807531952510190115738341879307021540891499 3488416750924476146066808226480016847741185374234544243710753907774499206955 1702761838606261331384583000752044933826560297606737113200709328709127443747 0472306969772093101416928368190255151086574637721112523897844250569536967707 854499699679468644549059879316368892300987931 ? exp(1.123) 3.07406257154898987680161138009760625104248179708261339399712186197767466996 4935625311477807765382361174054209564400933143178772679923822312458571526893 0949675915002937652898704613739372482459452568993085662295138072557500421797 5971600253639265100975969190654549368799844236165029593059925114588814911583 9185488320031389051117206437605098919216790228388886978184284707042848120462 1182818728513135542290354814654148922271957843494116542832234810156127014491 955053641170027738831683277094167546025000529 ? incgam(4,1,6) 5.88607105874307714552838032258337387913297809650828535212538882715938393191 8396853714356389534714299946037204429503923331951612684642064138026457431905 5805294751098780374098407782238580023298615198035196589516153270359568407982 7992725182985932743696823436032979670756942663882506560584119323653928852565 9814209708876601791309278295271957611829097587465878928057118995331313636440 2883453599077405070514506827481973857316860179666499801153515201126481557348 108412200404484860301786425134984607926838502 ? incgamc(2,1) 0.26424111765711535680895245967707826510837773793646433098432639660507700851 0200393285705451308160712506745349446312009583506048414419741982746692821011 8024338156112652453237699027220177497087673100245600426310480841205053949002 1500909352126758407037897070495877541155382167014686679926985084543258893429 2523223786390424776086340213091005298521362801566765133992860125583585795444 9639568300115324366185686646564753267835392477541687524855810599859189805331 4864484749494393924622766968581269240091451873 ? log(2) 0.69314718055994530941723212145817656807550013436025525412068000949339362196 9694715605863326996418687542001481020570685733685520235758130557032670751635 0759619307275708283714351903070386238916734711233501153644979552391204751726 8157493206515552473413952588295045300709532636664265410423915781495204374043 0385500801944170641671518644712839968171784546957026271631064546150257207402 4816377733896385506952606683411372738737229289564935470257626520988596932019 6505855476470330679365443254763274495125040607 ? sin(Pi/6) 0.50000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000 ? sinh(1) 1.17520119364380145688238185059560081515571798133409587022956541301330756730 4323895607117452089623391840419533327579532356785218901919457282136840352883 2484238229689806253026878572974193778037894530156457975748559863812033933000 2119435713493927674792878380863977809159438228870943791837123225023064326834 8982186865900736859713876553648773791543620849195059840098569695750460170734 7646045559914877642254885845736315892502135438245978143162874775249565935186 798861968577094170390099113872716177152780263 ? sqr(tan(Pi/3)) 3.00000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000 ? tanh(1) 0.76159415595576488811945828260479359041276859725793655159681050012195324457 6638483458947521673676714421902759701554077532368309114762485413297006669611 3211253965101376080877764393409926042066795531174758011305900662577831975245 1237997591796119707757354591410814335043351567518059703276048802963895774140 4110555282743457474128870116732022433666141820426521385314984008017809424940 5971665020197077111278076211510055741702778683601321201082307883017522102475 0850545493659202265152413525903793814306804484 ? thetanullk(0.5,7) -804.63037320243369422783730584965684022502842525603918290428537089203649185 3005202838354617419978916066838351498344792388634514250685494567531066970308 1395985000299687911464724641787835671746030420666636980738176244141521534964 5910468287548147547821547802569972386188420035275376210374637455233928908304 8519707951113024675783203592515011343853492633432924541927657918744234297707 8009339159045897789510058204677594956471190358977738843586880213576194151544 6040652826323066997075899093444932117587282486 ? \p210 realprecision = 211 significant digits (210 digits displayed) ? dilog(0.5) 0.58224052646501250590265632015968010874419847480612642543434704787317104407 1683200816840318587915857185644360650489146599186798136823369642378773825725 010992996274322284433100379999291599248198351965163954430361 ? eint1(2) 0.04890051070806111956723983522804952231449218496302311632732287371169292871 4152191279268961007451641767339733440496339126093474911387068904573480132428 0606565260878276314803271231475388617592828799527149833070515 ? lngamma(10^50*I) -157079632679489661923132169163975144209858469968811.93673753887608474948977 0941153418951907406847934940095420371647821881900698782085734298414871973667 351244826946727013485797329023211606491949054831345082284018 + 1141292546497 0228420089957273421821038005507443143864.09476847610738955343272591658130426 4976155641647932550343141949832879612722439831043441291767982893579577059574 3877177782974245137531522747279687821610884364*I ? polylog(5,0.5) 0.50840057924226870745910884925858994131954112566482164872449779635262539422 8780242619384210049344955062253148566177885373776251290109126927256295587733 653575441097747430180753135597085935261518462072899907112039 ? polylog(-4,t) (t^4 + 11*t^3 + 11*t^2 + t)/(-t^5 + 5*t^4 - 10*t^3 + 10*t^2 - 5*t + 1) ? polylog(5,0.5,1) 1.03379274554168906408344764673478841754654188263517803810922886849674521856 8302490767987790059233900087664928281011147504065464055196977752510643903051 08453214093020806938180803753912648028281347292317330014656 ? polylog(5,0.5,2) 1.03445942344901048625461825783418822628308099519811715037388226488478462874 5613316541842884367897989911634714028478465772399056966065341954518002332809 93803867195735501893802985262734041524337126856608372430479 ? polylog(5,0.5,3) 0.94956934899649226018699647701016092398772870595673235481511016276008056001 9780143078976018486726179185715990894178927384257428042889858760164776911430 334108913396327982261675208743365007260765477862866539420350 ? psi(1) -0.5772156649015328606065120900824024310421593359399235988057672348848677267 7766467093694706329174674951463144724980708248096050401448654283622417399764 4923536253500333742937337737673942792595258247094916008735204 ? round(prod(k=1,17,x-exp(2*I*Pi*k/17)),&e) x^17 - 1 ? e -693 ? theta(0.5,3) 0.08080641825189469129987168321046629852436630463736585818145355698789812007 7007090242373481570553349455066987093523256662570622075796055596272586626054 1756288186798491280103427257359418016911094472073083250230198 ? weber(I) 1.18920711500272106671749997056047591529297209246381741301900222471946666822 6917159870781344538137673716037394774769213186063726361789847756785360862538 01777507015151140355709227316234286888992417544607190871050 ? weber(I,1) 1.09050773266525765920701065576070797899270271854006712178566764768330053084 8841840338211140494203119891451619262918090010347769026116087255320275930582 70136445935603377184958072509793552467405409688916300069889 ? weber(I,2) 1.09050773266525765920701065576070797899270271854006712178566764768330053084 8841840338211140494203119891451619262918090010347769026116087255320275930582 70136445935603377184958072509793552467405409688916300069889 ? zeta(3) 1.20205690315959428539973816151144999076498629234049888179227155534183820578 6313090186455873609335258146199157795260719418491995998673283213776396837207 90016145394178294936006671919157552224249424396156390966410 ? \p38 realprecision = 38 significant digits ? besselk(1+I,1) 0.32545977186584141085464640324923711950 + 0.2894280370259921276345671592415 2302743*I ? erfc(2) 0.0046777349810472658379307436327470713891 ? gamma(10.5) 1133278.3889487855673345741655888924756 ? hyperu(1,1,1) 0.59634736232319407434107849936927937607 ? incgam(2,1) 0.73575888234288464319104754032292173489 ? zeta(0.5+14.1347251*I) 5.2043097453468479398562848599360610966 E-9 - 3.2690639869786982176409251733 763732423 E-8*I ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 22 pari-2.11.2/src/test/32/ser0000644000175000017500000001144513447371554013706 0ustar billbillx + x^2 + O(x^5) x + x^2 - 1/3*x^3 - x^4 + O(x^5) O(x^5) [0.78539816339744830961566084581987572105 + O(x^16)] x + x^2 + 1/6*x^3 + 1/2*x^4 + O(x^5) O(x^5) [1.5707963267948966192313216916397514421 + O(x^8)] 1.5707963267948966192313216916397514421 - x - x^2 - 1/6*x^3 - 1/2*x^4 + O(x^ 5) 1.5707963267948966192313216916397514421 + O(x^5) [O(x^8)] 1 + 1/2*x^2 + x^3 + 13/24*x^4 + O(x^5) 1 + O(x^5) [1.5430806348152437784779056207570616826 + O(x^16)] x + x^2 + 1/6*x^3 + 1/2*x^4 + O(x^5) O(x^5) [1.1752011936438014568823818505956008152 + O(x^16)] x + x^2 - 1/3*x^3 - x^4 + O(x^5) O(x^5) [0.76159415595576488811945828260479359041 + O(x^16)] x^-1 - 1 + 4/3*x - 2/3*x^2 + O(x^3) O(x^5) [1.3130352854993313036361612469308478329 + O(x^16)] 1.5707963267948966192313216916397514421*I - 1.000000000000000000000000000000 0000000*I*x - 1.0000000000000000000000000000000000000*I*x^2 - 0.166666666666 66666666666666666666666667*I*x^3 - 0.50000000000000000000000000000000000000* I*x^4 + O(x^5) 1.5707963267948966192313216916397514421*I + O(x^5) [O(x^8)] x + x^2 - 1/6*x^3 - 1/2*x^4 + O(x^5) O(x^5) [0.88137358701954302523260932497979230903 + O(x^16)] x + x^2 + 1/3*x^3 + x^4 + O(x^5) O(x^5) *** at top-level: ...rint(f[i](O(x^5)));print(f[i]([Pol(1)]));) *** ^----------------- *** in function f: atanh *** ^----- *** atanh: impossible inverse in div_ser: O(x^16). O(x^-2) O(x^-2) 2 + O(x^2) 1 + O(x^2) 1 O(x^0) 2*x + O(x^2) 2*x - 8/3*x^3 + 32/5*x^5 - 128/7*x^7 + 512/9*x^9 - 2048/11*x^11 + 8192/13*x^ 13 - 32768/15*x^15 + O(x^17) error("domain error in sqrtn: valuation != Mod(0, 2)") ((1 + O(y^4))*x + y^3)/(y^3*x) x + 2*x^2 + O(x^3) 2*x^2 + O(x^3) O(x^100) x + O(x^2) Mod(0, 3)*x + O(x^2) Mod(0, 3)*x + O(x^2) 1 + 2*x + 3*x^2 + O(x^3) 1 + 2*x + 3*x^2 + O(x^6) 1 + 2*x - 5*x^2 + O(x^3) 1 + 2*y + O(y^2) 1 + 2*y + 3*y^2 + O(y^5) 1 + 2*y + 3*y^2 + O(y^5) O(x^3) 1 + 2*y + 3*y^2 + O(y^5) x + O(x^4) O(x^3) x + x^2 + O(x^3) O(x^2) O(x^0) O(x^0) O(x^-1) O(x^0) y + x + O(x^2) (y + O(y^17)) + (1 + O(y^16))*x + O(x^2) Mod(0, 7)*x^15 + O(x^16) Mod(1, 7)*x^2 + Mod(1, 7)*x^4 + O(x^5) Mod(0, 7)*x^15 + O(x^16) Mod(1, 7) + O(x^16) Mod(1, 7)*x + O(x^16) Mod(0, 7)*x^14 + O(x^15) Mod(0, 7)*x^14 + O(x^15) Mod(0, 7)*x^15 + O(x^16) Mod(0, 7)*x^15 + O(x^16) Mod(0, 7)*x^15 + O(x^16) Mod(0, 7)*x^15 + O(x^16) O(x^16) Mod(0, 7)*x^15 + O(x^16) O(x^16) 0 Mod(0, 4)*x + O(x^2) (1 + O(y^2))*x^3 (Mod(1, 3) + O(y^2))*x^3 O(x) O(3) + O(x) O(3^2) + O(x) O(3^3) + O(x) 1 + O(x) *** _+_: Warning: normalizing a series with 0 leading term. x^-1 + O(x) [0, 1, 1] [0, 1, 1] [0, 1, 1] Mod(0, 9)*x + O(x^2) 0.E-38*x^-1 + O(x^0) O(x^0) Mod(0, 2)*x^-1 + O(x^0) 1 + O(y) 1 + y^2 + O(y^4) 1 1 0 1 + O(x^200) 1 1 + x^3 + O(x^6) 1 + x^2 + O(x^4) 1 + x^3 + 4*x^4 + O(x^5) 0 Mod(0, 3) O(3^2)*x^2 + O(x^3) 1 Mod(1, 3) 1 + O(3)*x + O(x^2) 1 + z^2 + O(z^3) y^2 + (1 + z^2 + O(z^3)) x^-1 - 1/6*x + 1/120*x^3 + O(x^4) t^-1 - 1/6*t + 1/120*t^3 + O(t^4) -1/2*x + 1/24*x^3 - 1/720*x^5 + 1/40320*x^7 - 1/3628800*x^9 + 1/479001600*x^ 11 - 1/87178291200*x^13 + 1/20922789888000*x^15 - 1/6402373705728000*x^17 + O(x^18) *** at top-level: subst(x^-1+O(x),x,Mod(0,3)) *** ^--------------------------- *** subst: impossible inverse in gsubst: Mod(0, 3). *** at top-level: subst(O(x^-1),x,Mod(0,3)) *** ^------------------------- *** subst: impossible inverse in gsubst: Mod(0, 3). *** at top-level: subst(x^-1+O(x),x,0*x) *** ^---------------------- *** subst: impossible inverse in gsubst: 0. *** at top-level: subst(O(x^-1),x,0*x) *** ^-------------------- *** subst: impossible inverse in gsubst: 0. *** at top-level: Ser(1/x,y) *** ^---------- *** Ser: incorrect priority in Ser: variable x < y *** at top-level: Ser(x,y) *** ^-------- *** Ser: incorrect priority in Ser: variable x < y *** at top-level: Ser([x],y) *** ^---------- *** Ser: incorrect priority in Ser: variable x <= y *** at top-level: Ser(x,,-5) *** ^---------- *** Ser: domain error in Ser: precision < 0 *** at top-level: Ser("") *** ^------- *** Ser: incorrect type in Ser (t_STR). *** _/_: Warning: normalizing a series with 0 leading term. *** at top-level: O(13^-5)/Mat(Mod(2,26)*y*x+(Mod(1,2)*y^-1+O(y^ *** ^-------------------------------------- *** _/_: impossible inverse in div_ser: O(13^0) + O(13^0)*y + O(13^0)*y^2 + O(13^0)*y^3 + O(y^4). *** at top-level: laurentseries(1) *** ^---------------- *** laurentseries: incorrect type in laurentseries (t_INT). *** at top-level: laurentseries((x,y)->1) *** ^----------------------- *** laurentseries: incorrect type in laurentseries (t_CLOSURE). Total time spent: 16 pari-2.11.2/src/test/32/bessel0000644000175000017500000004277013457427126014375 0ustar billbill1.8572024140248075150290504794684852507 E-10 1 - 1/46*x^2 + 1/4600*x^4 - 1/745200*x^6 + O(x^7) besselh1 [1, 1]: error("incorrect type in isint (t_POL).") [1, 2]: error("incorrect type in isint (t_POL).") [1, 3]: error("incorrect type in isint (t_POL).") [1, 4]: error("incorrect type in isint (t_POL).") [2, 1]: 1 + (-1/4 - 1/2*I)*x^2 + (1/64 + 3/64*I)*x^4 + (-1/2304 - 11/6912*I) *x^6 + O(x^7) [2, 2]: 0.76519768655796655144971752610266322091 + 0.08825696421567695798292 6766023515162828*I [2, 3]: 0.93846980724081290422840467359971262557 - 0.44451873350670655714839 847506833191038*I [2, 4]: 0.22744989480229475542017649479538153049 - 0.05105545867308961813450 6215898455430057*I [3, 1]: 4*I*x^-2 + (1 + I) + (-1/8 - 5/16*I)*x^2 + O(x^3) [3, 2]: 0.44005058574493351595968220371891491313 - 0.78121282130028871654715 000004796482055*I [3, 3]: 0.24226845767487388638395457614153164080 - 1.47147239267024306918858 46353232974532*I [3, 4]: -0.015640669069980772062382408481746291203 - 0.292666506764257448350 36876789097604882*I [4, 1]: (1 - I) + (-1/6 + 1/2*I)*x^2 + (1/120 - 1/24*I)*x^4 + (-1/5040 + 1/7 20*I)*x^6 + O(x^7) [4, 2]: 0.67139670714180309041636401204046708054 - 0.43109886801837607952052 096729853340009*I [4, 3]: 0.54097378993452809133091313466411641349 - 0.99024588024340488002335 195542348755756*I [4, 4]: 0.14085110084956896263172093887132583804 - 0.20269003235062497321863 218183621826188*I [5, 1]: error("domain error in besseln: 2n mod Z != 0") [5, 2]: 0.26938214945091836540555327716757818205 - 1.03976259800634355895849 86807324939546*I [5, 3]: 0.10940542017270712675781308031594165118 - 2.26083223277617932197371 42212172870084*I [5, 4]: -0.19118520534054547001908105095911444129 - 0.3150944893490879685794 3764282485894340*I [6, 1]: 380507258880*I*x^-20 + 10569646080*I*x^-18 + 165150720*I*x^-16 + O(x ^-15) [6, 2]: 2.6306151236874532069978536877905029441 E-10 - 121618014.27868918928 813042666797114529*I [6, 3]: 2.6131773608228030862436154291215029458 E-13 - 121963623349.56963053 464019824934463602*I [6, 4]: -3689851.3824160519844673516400513272729 - 205195.348659968658569759 91788233215816*I [7, 1]: error("domain error in besseln: 2n mod Z != 0") [7, 2]: 0.58245577631758767297591196874548910891 - 1.44030896971971272914426 26374028590791*I [7, 3]: 0.38021680508212671683351192801028812479 - 0.98141687216350076398947 866786133576037*I [7, 4]: 0.20154312205360321787812231235059586177 - 0.76783553572168519458542 835586375224028*I besselh2 [1, 1]: error("incorrect type in isint (t_POL).") [1, 2]: error("incorrect type in isint (t_POL).") [1, 3]: error("incorrect type in isint (t_POL).") [1, 4]: error("incorrect type in isint (t_POL).") [2, 1]: 1 + (-1/4 + 1/2*I)*x^2 + (1/64 - 3/64*I)*x^4 + (-1/2304 + 11/6912*I) *x^6 + O(x^7) [2, 2]: 0.76519768655796655144971752610266322091 - 0.08825696421567695798292 6766023515162828*I [2, 3]: 0.93846980724081290422840467359971262557 + 0.44451873350670655714839 847506833191038*I [2, 4]: 1.6477670588097637977792999000562559034 - 0.942004436545154646198413 22655202096895*I [3, 1]: -4*I*x^-2 + (1 - I) + (-1/8 + 5/16*I)*x^2 + O(x^3) [3, 2]: 0.44005058574493351595968220371891491313 + 0.78121282130028871654715 000004796482055*I [3, 3]: 0.24226845767487388638395457614153164080 + 1.47147239267024306918858 46353232974532*I [3, 4]: 1.2439613389157879924008217252327509830 + 1.022722564418433025377072 5711483489108*I [4, 1]: (1 + I) + (-1/6 - 1/2*I)*x^2 + (1/120 + 1/24*I)*x^4 + (-1/5040 - 1/7 20*I)*x^6 + O(x^7) [4, 2]: 0.67139670714180309041636401204046708054 + 0.43109886801837607952052 096729853340009*I [4, 3]: 0.54097378993452809133091313466411641349 + 0.99024588024340488002335 195542348755756*I [4, 4]: 1.7949514649306922611370433739385788319 + 0.323099244779188375242885 44204680075863*I [5, 1]: error("domain error in besseln: 2n mod Z != 0") [5, 2]: 0.26938214945091836540555327716757818205 + 1.03976259800634355895849 86807324939546*I [5, 3]: 0.10940542017270712675781308031594165118 + 2.26083223277617932197371 42212172870084*I [5, 4]: 0.79927619103677503777576265264156481050 + 1.08771932295608823645995 14526225738913*I [6, 1]: -380507258880*I*x^-20 - 10569646080*I*x^-18 - 165150720*I*x^-16 + O( x^-15) [6, 2]: 2.6306151236874532069978536877905029441 E-10 + 121618014.27868918928 813042666797114529*I [6, 3]: 2.6131773608228030862436154291215029458 E-13 + 121963623349.56963053 464019824934463602*I [6, 4]: 3689851.3824160527671366489980962693903 + 205195.3486599858655861754 3080013707678*I [7, 1]: error("domain error in besseln: 2n mod Z != 0") [7, 2]: -0.053793008222511491987048146883432543616 + 0.334151434861435901321 42313893855556329*I [7, 3]: -0.56713133425013005304402421178983091608 + 0.3472809452441059847447 3666211692428234*I [7, 4]: 0.56669526894058228371774833075826997077 + 0.56952668509437225367197 037537154780157*I besseli [1, 1]: error("incorrect type in isint (t_POL).") [1, 2]: error("incorrect type in isint (t_POL).") [1, 3]: error("incorrect type in isint (t_POL).") [1, 4]: error("incorrect type in isint (t_POL).") [2, 1]: 1 + 1/4*x^2 + 1/64*x^4 + 1/2304*x^6 + O(x^7) [2, 2]: 1.2660658777520083355982446252147175376 [2, 3]: 1.0634833707413235192631844154453565293 [2, 4]: 0.93760847680602927659973819742581871695 + 0.49652994760912213216645 972122523819950*I [3, 1]: 1 + 1/8*x^2 + 1/192*x^4 + 1/9216*x^6 + O(x^7) [3, 2]: 0.56515910399248502720769602760986330733 [3, 3]: 0.25789430539089631636247965952320963419 [3, 4]: 0.36502802882708778851335190162868643100 + 0.61416033492290361016921 965837550234589*I [4, 1]: 1 + 1/6*x^2 + 1/120*x^4 + 1/5040*x^6 + O(x^7) [4, 2]: 0.93767488824548764671726288439139336783 [4, 3]: 0.58799308679041632548887344016323449809 [4, 4]: 0.72698064596355457190337225790772836581 + 0.64183847533798587174998 976767935220305*I [5, 1]: 1 + 0.10355339059327376220042218105242451964*x^2 + 0.003791260736238 8304125791589473295974330*x^4 + 7.1572974488511092712416929822558597732 E-5* x^6 + O(x^7) [5, 2]: 0.33140333780825958195735832301263837654 [5, 3]: 0.11521946070729671962775067900799783493 [5, 4]: 0.12322584912763267310364477086934931491 + 0.47591631113525426300712 693607959667758*I [6, 1]: 1 + 1/44*x^2 + 1/4224*x^4 + 1/658944*x^6 + O(x^7) [6, 2]: 2.7529480398368736252357102010027635344 E-10 [6, 3]: 2.6430419258812795384721773266572060848 E-13 [6, 4]: -3.9133464867902247105872448856946075458 E-10 + 8.603508207756458902 4593151718189946275 E-9*I [7, 1]: 1 + (1/10 - 1/20*I)*x^2 + (1/320 - 1/320*I)*x^4 + (1/21760 - 1/13056 *I)*x^6 + O(x^7) [7, 2]: 0.25369454079993178519197028239401935067 - 0.70438419774772610421577 993808361942912*I [7, 3]: -0.10655105565636707643885659348968940182 - 0.3307637608360080173839 7259495461028707*I [7, 4]: 0.47875240945839830415507917927631039129 + 0.07128046026390996971374 9689821284593892*I besselj [1, 1]: error("incorrect type in isint (t_POL).") [1, 2]: error("incorrect type in isint (t_POL).") [1, 3]: error("incorrect type in isint (t_POL).") [1, 4]: error("incorrect type in isint (t_POL).") [2, 1]: 1 - 1/4*x^2 + 1/64*x^4 - 1/2304*x^6 + O(x^7) [2, 2]: 0.76519768655796655144971752610266322091 [2, 3]: 0.93846980724081290422840467359971262557 [2, 4]: 0.93760847680602927659973819742581871695 - 0.49652994760912213216645 972122523819950*I [3, 1]: 1 - 1/8*x^2 + 1/192*x^4 - 1/9216*x^6 + O(x^7) [3, 2]: 0.44005058574493351595968220371891491313 [3, 3]: 0.24226845767487388638395457614153164080 [3, 4]: 0.61416033492290361016921965837550234589 + 0.36502802882708778851335 190162868643100*I [4, 1]: 1 - 1/6*x^2 + 1/120*x^4 - 1/5040*x^6 + O(x^7) [4, 2]: 0.67139670714180309041636401204046708054 [4, 3]: 0.54097378993452809133091313466411641349 [4, 4]: 0.96790128289013061188438215640495233496 + 0.06020460621428170101212 6630105291248378*I [5, 1]: 1 - 0.10355339059327376220042218105242451964*x^2 + 0.003791260736238 8304125791589473295974330*x^4 - 7.1572974488511092712416929822558597732 E-5* x^6 + O(x^7) [5, 2]: 0.26938214945091836540555327716757818205 [5, 3]: 0.10940542017270712675781308031594165118 [5, 4]: 0.30404549284811478387834080084122518461 + 0.38631241680350013394025 690489885747395*I [6, 1]: 1 - 1/44*x^2 + 1/4224*x^4 - 1/658944*x^6 + O(x^7) [6, 2]: 2.6306151236874532069978536877905029441 E-10 [6, 3]: 2.6131773608228030862436154291215029458 E-13 [6, 4]: 3.9133464867902247105872448856946075458 E-10 + 8.6035082077564589024 593151718189946275 E-9*I [7, 1]: 1 + (-1/10 + 1/20*I)*x^2 + (1/320 - 1/320*I)*x^4 + (-1/21760 + 1/130 56*I)*x^6 + O(x^7) [7, 2]: 0.26433138404753809049443191093102828265 - 0.55307876742913841391141 974923215175792*I [7, 3]: -0.093457264584001668105256141889771395645 - 0.317067963459697389622 37100287220573902*I [7, 4]: 0.38411919549709275079793532155443291627 - 0.09915442531365647045672 8990246102219357*I besseljh [1, 1]: error("incorrect type in jbesselh (t_POL).") [1, 2]: error("incorrect type in jbesselh (t_POL).") [1, 3]: error("incorrect type in jbesselh (t_POL).") [1, 4]: error("incorrect type in jbesselh (t_POL).") [2, 1]: 1 - 1/6*x^2 + 1/120*x^4 - 1/5040*x^6 + O(x^7) [2, 2]: 0.67139670714180309041636401204046708055 [2, 3]: 0.54097378993452809133091313466411641349 [2, 4]: 0.96790128289013061188438215640495233496 + 0.06020460621428170101212 6630105291248379*I [3, 1]: 1 - 1/10*x^2 + 1/280*x^4 - 1/15120*x^6 + O(x^7) [3, 2]: 0.24029783912342701089584304474193368046 [3, 3]: 0.091701699625651302638474313904745269419 [3, 4]: 0.25115830598729948221749558131361228142 + 0.37320184370263719381653 345438379595363*I [4, 1]: error("incorrect type in jbesselh (t_FRAC).") [4, 2]: error("incorrect type in jbesselh (t_FRAC).") [4, 3]: error("incorrect type in jbesselh (t_FRAC).") [4, 4]: error("incorrect type in jbesselh (t_FRAC).") [5, 1]: error("incorrect type in jbesselh (t_REAL).") [5, 2]: error("incorrect type in jbesselh (t_REAL).") [5, 3]: error("incorrect type in jbesselh (t_REAL).") [5, 4]: error("incorrect type in jbesselh (t_REAL).") [6, 1]: 1 - 1/46*x^2 + 1/4600*x^4 - 1/745200*x^6 + O(x^7) [6, 2]: 5.6781874776346222994224383562334313034 E-11 [6, 3]: 3.9855051571881421614590449651836245138 E-14 [6, 4]: -7.5567733209249243890627329164720828368 E-10 + 2.075203626533608360 9444796696375043842 E-9*I [7, 1]: error("incorrect type in jbesselh (t_COMPLEX).") [7, 2]: error("incorrect type in jbesselh (t_COMPLEX).") [7, 3]: error("incorrect type in jbesselh (t_COMPLEX).") [7, 4]: error("incorrect type in jbesselh (t_COMPLEX).") besselk [1, 1]: error("incorrect type in isint (t_POL).") [1, 2]: error("incorrect type in isint (t_POL).") [1, 3]: error("incorrect type in isint (t_POL).") [1, 4]: error("incorrect type in isint (t_POL).") [2, 1]: 1/2*x^2 + 3/64*x^4 + 11/6912*x^6 + O(x^7) [2, 2]: 0.42102443824070833333562737921260903614 [2, 3]: 0.92441907122766586178192416753021698954 [2, 4]: 0.080197726946517818726968736564279166834 - 0.3572774592853302506059 4569325002398166*I [3, 1]: -4*x^-2 + 1 + 5/16*x^2 + O(x^3) [3, 2]: 0.60190723019723457473754000153561733926 [3, 3]: 1.6564411200033008936964454031740915115 [3, 4]: 0.024568305523740348612477346185201235995 - 0.4597194738011893647760 4300851857199811*I [4, 1]: 1/2*x^-1 - 1 + 1/4*x - 1/6*x^2 + 1/48*x^3 - 1/120*x^4 + O(x^5) [4, 2]: 0.46106850444789455843957587387569458969 [4, 3]: 1.0750476034999202387227558602482085118 [4, 4]: 0.068685783419996419480057426969766668173 - 0.3815782598126830739602 7449697029326916*I [5, 1]: error("domain error in besselk: 2n mod Z != 0") [5, 2]: 0.84808712130706055249297377794312403937 [5, 3]: 2.8356740750874926233948621504947623564 [5, 4]: -0.060833677914566850837201614245364256444 - 0.575727321703454299901 71626792018756559*I [6, 1]: 380507258880*x^-20 - 10569646080*x^-18 + 165150720*x^-16 + O(x^-15) [6, 2]: 180713289.90102945469159786130234001591 [6, 3]: 188937569319.90025964462417816833870273 [6, 4]: -322320.09995047688108832869622332914303 - 5796004.99791820584997486 34606037942199*I [7, 1]: error("domain error in besselk: 2n mod Z != 0") [7, 2]: 0.32545977186584141085464640324923711950 + 0.28942803702599212763456 715924152302743*I [7, 3]: 0.38335176781651847215073123333424046031 + 0.96679218008775594813220 288497987441031*I [7, 4]: 0.31594457269950863123935043154373419884 - 0.40665811731437652111601 397817696670098*I besseln [1, 1]: error("incorrect type in isint (t_POL).") [1, 2]: error("incorrect type in isint (t_POL).") [1, 3]: error("incorrect type in isint (t_POL).") [1, 4]: error("incorrect type in isint (t_POL).") [2, 1]: -1/2*x^2 + 3/64*x^4 - 11/6912*x^6 + O(x^7) [2, 2]: 0.088256964215676957982926766023515162828 [2, 3]: -0.44451873350670655714839847506833191038 [2, 4]: 0.44547448893603251403195350532678276945 + 0.71015858200373452117956 170263043718646*I [3, 1]: 4*x^-2 + 1 - 5/16*x^2 + O(x^3) [3, 2]: -0.78121282130028871654715000004796482055 [3, 3]: -1.4714723926702430691885846353232974532 [3, 4]: -0.65769453559134523686372066951966247983 + 0.6298010039928843822316 0206685724863709*I [4, 1]: -1 + 1/2*x^2 - 1/24*x^4 + 1/720*x^6 + O(x^7) [4, 2]: -0.43109886801837607952052096729853340009 [4, 3]: -0.99024588024340488002335195542348755756 [4, 4]: -0.26289463856490667423075881194150951025 + 0.8270501820405616492526 6121753362649691*I [5, 1]: error("domain error in besseln: 2n mod Z != 0") [5, 2]: -1.0397625980063435589584986807324939546 [5, 3]: -2.2608322327761793219737142212172870084 [5, 4]: -0.70140690615258810251969454772371641734 + 0.4952306981886602538974 2185180033962590*I [6, 1]: 380507258880*x^-20 + 10569646080*x^-18 + 165150720*x^-16 + O(x^-15) [6, 2]: -121618014.27868918928813042666797114529 [6, 3]: -121963623349.56963053464019824934463602 [6, 4]: -205195.34865997726207796767434123461747 + 3689851.38241605237580200 03190737983316*I [7, 1]: error("domain error in besseln: 2n mod Z != 0") [7, 2]: -0.88723020229057431523284288817070732122 - 0.3181243922700495824814 8005781446082626*I [7, 3]: -0.66434890870380337436710766498913002135 - 0.4736740696661283849387 6806990005952044*I [7, 4]: -0.66868111040802872412869936561765002092 + 0.1825760734434895329198 1300920383705450*I [0.38318604387456485808270441031554362198 - 1.130318207984970054415392055219 7266147*I, -0.38318604387456485808270441031554362198 + 0.E-38*I]~ [-0.38318604387456485808270441031554362198 + 0.E-38*I, 0.3831860438745648580 8270441031554362198 + 1.1303182079849700544153920552197266147*I]~ [0.E-39 - 0.44005058574493351595968220371891491313*I, 0.E-39 + 0.44005058574 493351595968220371891491313*I]~ [0.E-38 - 0.56515910399248502720769602760986330733*I, 0.E-38 + 0.56515910399 248502720769602760986330733*I]~ [-0.20755374871029735167013412472066868268 - 0.20755374871029735167013412472 066868268*I, -0.20755374871029735167013412472066868268 + 0.20755374871029735 167013412472066868268*I]~ [-0.69122984369208426288314166384697051872 + 1.22712623014357148924328078170 72674867*I, -0.69122984369208426288314166384697051872 - 1.227126230143571489 2432807817072674867*I]~ [-0.56515910399248502720769602760986330733 - 0.38318604387456485808270441031 554362198*I, -0.56515910399248502720769602760986330733 + 0.38318604387456485 808270441031554362198*I]~ [0.44005058574493351595968220371891491313 - 0.781212821300288716547150000047 96482055*I] [0.44005058574493351595968220371891491313 + 0.781212821300288716547150000047 96482055*I] [0.56515910399248502720769602760986330733] [0.44005058574493351595968220371891491313] [0.24029783912342701089584304474193368046] [0.60190723019723457473754000153561733926] [-0.78121282130028871654715000004796482055] [0.44005058574493351595968220371891491313 - 0.781212821300288716547150000047 96482055*I]~ [0.44005058574493351595968220371891491313 + 0.781212821300288716547150000047 96482055*I]~ [0.56515910399248502720769602760986330733]~ [0.44005058574493351595968220371891491313]~ [0.24029783912342701089584304474193368046]~ [0.60190723019723457473754000153561733926]~ [-0.78121282130028871654715000004796482055]~ Mat(0.44005058574493351595968220371891491313 - 0.781212821300288716547150000 04796482055*I) Mat(0.44005058574493351595968220371891491313 + 0.781212821300288716547150000 04796482055*I) Mat(0.56515910399248502720769602760986330733) Mat(0.44005058574493351595968220371891491313) Mat(0.24029783912342701089584304474193368046) Mat(0.60190723019723457473754000153561733926) Mat(-0.78121282130028871654715000004796482055) 0.E-96 5.3192304053524357058659474657917582463 E-127 2.0125228237125015700004500237283661172 E-436 5.7412378153505365740198971395908944617 E-10 2.0105123109834969409015328783614871604 E-436 + 0.E-475*I 11.628856980944362293418444710423341176 error("forbidden multiplication t_REAL * t_PADIC.") error("forbidden multiplication t_REAL * t_PADIC.") error("forbidden multiplication t_REAL * t_PADIC.") error("forbidden multiplication t_REAL * t_PADIC.") error("incorrect type in jbesselh (t_PADIC).") error("incorrect type in isint (t_PADIC).") error("incorrect type in isint (t_PADIC).") error("forbidden multiplication t_REAL * t_STR.") error("forbidden multiplication t_REAL * t_STR.") error("forbidden multiplication t_REAL * t_STR.") error("forbidden multiplication t_REAL * t_STR.") error("incorrect type in jbesselh (t_STR).") error("incorrect type in gexpo (t_STR).") error("incorrect type in isint (t_STR).") error("sorry, p-adic jbessel function is not yet implemented.") error("sorry, p-adic jbessel function is not yet implemented.") error("sorry, p-adic jbessel function is not yet implemented.") error("sorry, p-adic jbessel function is not yet implemented.") error("sorry, p-adic jbesselh function is not yet implemented.") error("sorry, p-adic besselk is not yet implemented.") error("sorry, p-adic besseln is not yet implemented.") error("incorrect type in jbessel (t_STR).") error("incorrect type in jbessel (t_STR).") error("incorrect type in jbessel (t_STR).") error("incorrect type in jbessel (t_STR).") error("incorrect type in besseljh (t_STR).") error("incorrect type in besselk (t_STR).") error("incorrect type in besseln (t_STR).") Total time spent: 42 pari-2.11.2/src/test/32/polyser0000644000175000017500000001426013326135265014601 0ustar billbill echo = 1 ? apol=y^3+5*y+1 y^3 + 5*y + 1 ? deriv((x+y)^5,y) 5*x^4 + 20*y*x^3 + 30*y^2*x^2 + 20*y^3*x + 5*y^4 ? ((x+y)^5)' 5*x^4 + 20*y*x^3 + 30*y^2*x^2 + 20*y^3*x + 5*y^4 ? dz=vector(30,k,1);dd=vector(30,k,k==1);dm=dirdiv(dd,dz) [1, -1, -1, 0, -1, 1, -1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1, 0, -1, 0, 1, 1, - 1, 0, 0, 1, 0, 0, -1, -1] ? direuler(s=1,40,1+s*X+s^2*X) [1, 6, 12, 0, 30, 72, 56, 0, 0, 180, 132, 0, 182, 336, 360, 0, 306, 0, 380, 0, 672, 792, 552, 0, 0, 1092, 0, 0, 870, 2160, 992, 0, 1584, 1836, 1680, 0, 1406, 2280, 2184, 0] ? dirmul(abs(dm),dz) [1, 2, 2, 2, 2, 4, 2, 2, 2, 4, 2, 4, 2, 4, 4, 2, 2, 4, 2, 4, 4, 4, 2, 4, 2, 4, 2, 4, 2, 8] ? zz=yy;yy=xx;eval(zz) xx ? factorpadic(apol,7,8) [(1 + O(7^8))*y + (6 + 2*7^2 + 2*7^3 + 3*7^4 + 2*7^5 + 6*7^6 + O(7^8)) 1] [(1 + O(7^8))*y^2 + (1 + 6*7 + 4*7^2 + 4*7^3 + 3*7^4 + 4*7^5 + 6*7^7 + O(7^8 ))*y + (6 + 5*7 + 3*7^2 + 6*7^3 + 7^4 + 3*7^5 + 2*7^6 + 5*7^7 + O(7^8)) 1] ? intformal(sin(x)) 1/2*x^2 - 1/24*x^4 + 1/720*x^6 - 1/40320*x^8 + 1/3628800*x^10 - 1/479001600* x^12 + 1/87178291200*x^14 - 1/20922789888000*x^16 + O(x^18) ? intformal((-x^2-2*a*x+8*a)/(x^4-14*x^3+(2*a+49)*x^2-14*a*x+a^2)) (x + a)/(x^2 - 7*x + a) ? newtonpoly(x^4+3*x^3+27*x^2+9*x+81,3) [2, 2/3, 2/3, 2/3] ? padicappr(apol,1+O(7^8)) [1 + 6*7 + 4*7^2 + 4*7^3 + 3*7^4 + 4*7^5 + 6*7^7 + O(7^8)]~ ? padicappr(x^3+5*x+1,Mod(x*(1+O(7^8)),x^2+x-1)) [Mod((1 + 3*7 + 3*7^2 + 4*7^3 + 4*7^4 + 4*7^5 + 2*7^6 + 3*7^7 + O(7^8))*x + (2*7 + 6*7^2 + 6*7^3 + 3*7^4 + 3*7^5 + 4*7^6 + 5*7^7 + O(7^8)), x^2 + x - 1) ]~ ? Pol(sin(x)) -1/1307674368000*x^15 + 1/6227020800*x^13 - 1/39916800*x^11 + 1/362880*x^9 - 1/5040*x^7 + 1/120*x^5 - 1/6*x^3 + x ? Pol([1,2,3,4,5]) x^4 + 2*x^3 + 3*x^2 + 4*x + 5 ? Polrev([1,2,3,4,5]) 5*x^4 + 4*x^3 + 3*x^2 + 2*x + 1 ? polcoeff(sin(x),7) -1/5040 ? polcyclo(105) x^48 + x^47 + x^46 - x^43 - x^42 - 2*x^41 - x^40 - x^39 + x^36 + x^35 + x^34 + x^33 + x^32 + x^31 - x^28 - x^26 - x^24 - x^22 - x^20 + x^17 + x^16 + x^1 5 + x^14 + x^13 + x^12 - x^9 - x^8 - 2*x^7 - x^6 - x^5 + x^2 + x + 1 ? pcy=polcyclo(405) x^216 - x^189 + x^135 - x^108 + x^81 - x^27 + 1 ? pcy*pcy x^432 - 2*x^405 + x^378 + 2*x^351 - 4*x^324 + 4*x^297 - x^270 - 4*x^243 + 7* x^216 - 4*x^189 - x^162 + 4*x^135 - 4*x^108 + 2*x^81 + x^54 - 2*x^27 + 1 ? poldegree(x^3/(x-1)) 2 ? poldisc(x^3+4*x+12) -4144 ? poldiscreduced(x^3+4*x+12) [1036, 4, 1] ? polinterpolate([0,2,3],[0,4,9],5) 25 ? polisirreducible(x^5+3*x^3+5*x^2+15) 0 ? pollegendre(10) 46189/256*x^10 - 109395/256*x^8 + 45045/128*x^6 - 15015/128*x^4 + 3465/256*x ^2 - 63/256 ? zpol=0.3+pollegendre(10) 46189/256*x^10 - 109395/256*x^8 + 45045/128*x^6 - 15015/128*x^4 + 3465/256*x ^2 + 0.053906250000000000000000000000000000001 ? polrecip(3*x^7-5*x^3+6*x-9) -9*x^7 + 6*x^6 - 5*x^4 + 3 ? polresultant(x^3-1,x^3+1) 8 ? polresultant(x^3-1.,x^3+1.,,1) 8.0000000000000000000000000000000000000 ? polroots(x^5-5*x^2-5*x-5) [2.0509134529831982130058170163696514536 + 0.E-38*I, -0.67063790319207539268 663382582902335603 - 0.84813118358634026680538906224199030918*I, -0.67063790 319207539268663382582902335603 + 0.84813118358634026680538906224199030918*I, -0.35481882329952371381627468235580237078 - 1.39980287391035466982975228340 62081965*I, -0.35481882329952371381627468235580237078 + 1.399802873910354669 8297522834062081965*I]~ ? polroots(x^4-1000000000000000000000) [-177827.94100389228012254211951926848447 + 0.E-38*I, 177827.941003892280122 54211951926848447 + 0.E-38*I, 0.E-38 - 177827.941003892280122542119519268484 47*I, 0.E-38 + 177827.94100389228012254211951926848447*I]~ ? polrootsmod(x^16-1,41) [Mod(1, 41), Mod(3, 41), Mod(9, 41), Mod(14, 41), Mod(27, 41), Mod(32, 41), Mod(38, 41), Mod(40, 41)]~ ? polrootspadic(x^4+1,41,6) [3 + 22*41 + 27*41^2 + 15*41^3 + 27*41^4 + 33*41^5 + O(41^6), 14 + 20*41 + 2 5*41^2 + 24*41^3 + 4*41^4 + 18*41^5 + O(41^6), 27 + 20*41 + 15*41^2 + 16*41^ 3 + 36*41^4 + 22*41^5 + O(41^6), 38 + 18*41 + 13*41^2 + 25*41^3 + 13*41^4 + 7*41^5 + O(41^6)]~ ? polsturm(zpol) 4 ? polsturm(zpol,0.91,1) 1 ? polsylvestermatrix(a2*x^2+a1*x+a0,b1*x+b0) [a2 b1 0] [a1 b0 b1] [a0 0 b0] ? polsym(x^17-1,17) [17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17]~ ? poltchebi(10) 512*x^10 - 1280*x^8 + 1120*x^6 - 400*x^4 + 50*x^2 - 1 ? polzagier(6,3) 4608*x^6 - 13824*x^5 + 46144/3*x^4 - 23168/3*x^3 + 5032/3*x^2 - 120*x + 1 ? serconvol(sin(x),x*cos(x)) x + 1/12*x^3 + 1/2880*x^5 + 1/3628800*x^7 + 1/14631321600*x^9 + 1/1448500838 40000*x^11 + 1/2982752926433280000*x^13 + 1/114000816848279961600000*x^15 + O(x^17) ? serlaplace(x*exp(x*y)/(exp(x)-1)) 1 + (y - 1/2)*x + (y^2 - y + 1/6)*x^2 + (y^3 - 3/2*y^2 + 1/2*y)*x^3 + (y^4 - 2*y^3 + y^2 - 1/30)*x^4 + (y^5 - 5/2*y^4 + 5/3*y^3 - 1/6*y)*x^5 + (y^6 - 3* y^5 + 5/2*y^4 - 1/2*y^2 + 1/42)*x^6 + (y^7 - 7/2*y^6 + 7/2*y^5 - 7/6*y^3 + 1 /6*y)*x^7 + (y^8 - 4*y^7 + 14/3*y^6 - 7/3*y^4 + 2/3*y^2 - 1/30)*x^8 + (y^9 - 9/2*y^8 + 6*y^7 - 21/5*y^5 + 2*y^3 - 3/10*y)*x^9 + (y^10 - 5*y^9 + 15/2*y^8 - 7*y^6 + 5*y^4 - 3/2*y^2 + 5/66)*x^10 + (y^11 - 11/2*y^10 + 55/6*y^9 - 11* y^7 + 11*y^5 - 11/2*y^3 + 5/6*y)*x^11 + (y^12 - 6*y^11 + 11*y^10 - 33/2*y^8 + 22*y^6 - 33/2*y^4 + 5*y^2 - 691/2730)*x^12 + (y^13 - 13/2*y^12 + 13*y^11 - 143/6*y^9 + 286/7*y^7 - 429/10*y^5 + 65/3*y^3 - 691/210*y)*x^13 + (y^14 - 7 *y^13 + 91/6*y^12 - 1001/30*y^10 + 143/2*y^8 - 1001/10*y^6 + 455/6*y^4 - 691 /30*y^2 + 7/6)*x^14 + (y^15 - 15/2*y^14 + 35/2*y^13 - 91/2*y^11 + 715/6*y^9 - 429/2*y^7 + 455/2*y^5 - 691/6*y^3 + 35/2*y)*x^15 + O(x^16) ? serreverse(tan(x)) x - 1/3*x^3 + 1/5*x^5 - 1/7*x^7 + 1/9*x^9 - 1/11*x^11 + 1/13*x^13 - 1/15*x^1 5 + O(x^17) ? subst(sin(x),x,y) y - 1/6*y^3 + 1/120*y^5 - 1/5040*y^7 + 1/362880*y^9 - 1/39916800*y^11 + 1/62 27020800*y^13 - 1/1307674368000*y^15 + O(y^17) ? subst(sin(x),x,x+x^2) x + x^2 - 1/6*x^3 - 1/2*x^4 - 59/120*x^5 - 1/8*x^6 + 419/5040*x^7 + 59/720*x ^8 + 13609/362880*x^9 + 19/13440*x^10 - 273241/39916800*x^11 - 14281/3628800 *x^12 - 6495059/6227020800*x^13 + 69301/479001600*x^14 + 26537089/1188794880 00*x^15 + 1528727/17435658240*x^16 + O(x^17) ? taylor(y/(x-y),y) (O(y^16)*x^15 + y*x^14 + y^2*x^13 + y^3*x^12 + y^4*x^11 + y^5*x^10 + y^6*x^9 + y^7*x^8 + y^8*x^7 + y^9*x^6 + y^10*x^5 + y^11*x^4 + y^12*x^3 + y^13*x^2 + y^14*x + y^15)/x^15 ? variable(name^4-other) name ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 5 pari-2.11.2/src/test/32/sumnumrat0000644000175000017500000000552313447371554015150 0ustar billbill realprecision = 115 significant digits 0.E-115 3.28986813369645287294483033329205037843789980241359687547111645874001494080 6401747667257801239517410608008637924674 0.45224742004106549850654336483224793417323134323989242173641893035116502736 39108744489575443549068582228062276669208*y 0.30683697542290869391786213828290734801742482783565174497642694808825913036 03651451009491129226235190125664092098724 1.26136274645318147698799551222314132362637346328706942198906377178189999150 1230866228427233973980799199951451197768 3.67607791037497772069569749202826066650715634682763027747800359355744732411 1022073213255926590323023528755113952481 0.38905955531696837171041438969249635813838671424662604898213163770917329090 28320667369090321673956106194704282531992 0.38905955531696837171041438969249635813838671424662604898213163770917329090 28320667369090321673956106194704282531990 1.00000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000 1.00000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0.47168061361299786807523563308048208742592638200698688363573725541773211675 96827440962100273769490230313011322456824 1.00000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0.E-115 1.00000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000 1.00000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0.E-115 *** at top-level: sumnumrat(1/x^2,oo) *** ^------------------- *** sumnumrat: incorrect type in sumnumrat (t_INFINITY). *** at top-level: sumnumrat(1.0,1) *** ^---------------- *** sumnumrat: incorrect type in sumnumrat (t_REAL). *** at top-level: sumnumrat(1/x,10) *** ^----------------- *** sumnumrat: sum diverges in sumnumrat. *** at top-level: prodnumrat(1+1/x,10) *** ^-------------------- *** prodnumrat: product diverges in prodnumrat. *** at top-level: prodnumrat(2,1) *** ^--------------- *** prodnumrat: incorrect type in prodnumrat (t_INT). *** at top-level: sumeulerrat(1) *** ^-------------- *** sumeulerrat: incorrect type in sumeulerrat (t_INT). *** at top-level: sumeulerrat(1/p) *** ^---------------- *** sumeulerrat: domain error in sumeulerrat: real(s) <= 1.0000000000000000000 *** at top-level: prodeulerrat(2) *** ^--------------- *** prodeulerrat: incorrect type in prodeulerrat (t_INT). *** at top-level: prodeulerrat(1+1/p) *** ^------------------- *** prodeulerrat: domain error in prodeulerrat: real(s) <= 1.0000000000000000000 Total time spent: 16 pari-2.11.2/src/test/32/debugger0000644000175000017500000000722613326135265014674 0ustar billbill echo = 1 ? default(breakloop,1) ? my(bound=100,step=20,halt=41);check(B)=my(bi=[B^2]);for(i=1,bound,my(p=i+step,N=p^2);if(i==halt,error("check:",N))) (B)->my(bound=100,step=20,halt=41);my(bi=[B^2]);for(i=1,bound,my(p=i+step,N= p^2);if(i==halt,error("check:",N))) ? check(1000); *** at top-level: check(1000) *** ^----------- *** in function check: ...i+step,N=p^2);if(i==halt,error("check:",N))) *** ^------------------- *** user error: check:3721 *** Break loop: type 'break' to go back to GP prompt break> [bound,step,halt,i,p,N,bi,B] [100, 20, 41, 41, 61, 3721, [1000000], 1000] break> break ? [bound,step,halt,i,p,N,bi,B] [bound, step, halt, i, p, N, bi, B] ? my(p=120);for(i=1,100,1/0) *** at top-level: my(p=120);for(i=1,100,1/0) *** ^--- *** _/_: impossible inverse in gdiv: 0. *** Break loop: type 'break' to go back to GP prompt break> [p,i] [120, 1] break> dbg_err() error("impossible inverse in gdiv: 0.") break> break ? fun(N)=check(N^2+1); ? fun(20); *** at top-level: fun(20) *** ^------- *** in function fun: check(N^2+1) *** ^------------ *** in function check: ...i+step,N=p^2);if(i==halt,error("check:",N))) *** ^------------------- *** user error: check:3721 *** Break loop: type 'break' to go back to GP prompt break> N 3721 break> dbg_up(4) *** at top-level: fun(20) *** ^------- *** in function fun: check(N^2+1) *** ^------------ break> N 20 break> break ? f(N,x)=my(z=x^2+1);breakpoint();gcd(N,z^2+1-z); ? f(221,3) *** at top-level: f(221,3) *** ^-------- *** in function f: my(z=x^2+1);breakpoint();gcd(N,z^2+1-z) *** ^--------------------------- *** Break loop: to continue; 'break' to go back to GP prompt break> z 10 13 ? z z ? iferrname("e_VAR",vector(10000,i,1/(i-100)),E,Vec(E)) *** at top-level: ...("e_VAR",vector(10000,i,1/(i-100)),E,Vec(E)) *** ^------------------- *** _/_: impossible inverse in gdiv: 0. *** Break loop: type 'break' to go back to GP prompt break> i 100 break> break ? f()=1/0 ()->1/0 ? f(); *** at top-level: f() *** ^--- *** in function f: 1/0 *** ^-- *** _/_: impossible inverse in gdiv: 0. *** Break loop: type 'break' to go back to GP prompt break> allocatemem(10^7) *** Warning: new stack size = 10000000 (9.537 Mbytes). ? for(i=1,10,if(i==2,1/0)); *** at top-level: for(i=1,10,if(i==2,1/0)) *** ^---- *** _/_: impossible inverse in gdiv: 0. *** Break loop: type 'break' to go back to GP prompt break> i 2 break> N=5 5 break> M=6;1/0 *** at top-level: for(i=1,10,if(i==2,1/0)) *** ^---- *** in anonymous function: M=6;1/0 *** ^-- *** _/_: impossible inverse in gdiv: 0. *** Break loop: type 'break' to go back to GP prompt break[2]> break *** at top-level: for(i=1,10,if(i==2,1/0)) *** ^---- break> N 5 break> M M break> break ? F1(T)=1/0; ? F1(2) *** at top-level: F1(2) *** ^----- *** in function F1: 1/0 *** ^-- *** _/_: impossible inverse in gdiv: 0. *** Break loop: type 'break' to go back to GP prompt break> dbg_up *** at top-level: F1(2) *** ^----- break> T T break> break ? print("Total time spent: ",gettime); Total time spent: 1 pari-2.11.2/src/test/32/kernel0000644000175000017500000000261213201017466014354 0ustar billbillINT: 187654321 conv:signe: 1, 0b2f60b1 +:signe: 1, 0a72ff63 -:signe: 1, 0bebc1ff *:signe: -1, 00083b0b 5e0e86ee /:signe: -1, 0000000f rem:signe: 1, 0025ad1f pow: signe: 1, 007d1b13 db833a61 signe: 1, 00003d23 74418fff 02bee98c c29618c1 signe: 1, 0e99ea50 3d586253 467c3cea a7f1a742 85bba548 639e3a9d 8890c181 signe: 1, 00d5322a b115c7b2 9cf0c571 1679c253 8cea7ca0 1cbe7596 78ae7d09 c969dc26 cd42e2ad 51204d31 635bced8 66d36dbb 0351ebad 5363c301 signe: 1, 0000b18c 84df6289 66df9491 766a39a4 0685a8a3 cfc68c74 4d9dcb91 02634462 b398839e 1a6892ef 5efe0281 bcae4afb eb64fcab f930fa7a 00f01335 2a5dc7c3 4295b5c3 b031c96e a5c19079 8e647dac 09e2091e 67abbc58 c118d1b7 76f5e31c e97a9180 140e859c 64a53cad 0d508601 invmod:signe: 1, 000089fe 3c4ba859 b9472dac d0585e64 b5311881 edf8024b aaf6ce9e 98d94a2d b253c748 bc185be1 6de1e5f8 831bbecd a3d629dc 0fc9440e b0ab325d 53dd21c5 9fb7fc20 cc22d98c e8fe6eca 928c7f4f a3861061 a7ab0bdc 71deda26 17a28387 77487563 9f0f88ac 424ca4d5 3dcae2a5 REAL: 187654321.000000 conv1:signe: 1, expo: 27, b2f60b10 00000000 conv2:signe: 1, expo: 27, b2f60b10 00000000 +:signe: 1, expo: 27, a72ff630 00000000 -:signe: 1, expo: 27, bebc1ff0 00000000 *:signe: -1, expo: 51, 83b0b5e0 e86ee000 /:signe: -1, expo: 3, f3333482 0be1df0a gcc bug?:signe: 1, expo: 0, c0000000 00000000 pari-2.11.2/src/test/32/algebras0000644000175000017500000023737513375013132014672 0ustar billbill *** Warning: new stack size = 100000000 (95.367 Mbytes). contains nfabs: 1 [[x^4 + x^3 + x^2 + x + 1, [1], [125, 5], 1, [], [], [[1, x, x^2, x^3], [1, 1, 1, 1]], [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], 1, [y, [1, 0], 1, 1, [Mat(1), Mat(1), Mat(1), Mat(1), 1, Mat(1), [1, 0], []], [0.E-57], [1] , Mat(1), Mat(1)], [x^4 + x^3 + x^2 + x + 1, 0, 0, y, x^4 + x^3 + x^2 + x + 1], [0, [[1; 0; 0; 0], Mat(1), 1, Vecsmall([1])]]], [x^2, -x^3 - x^2 - x - 1 , x^3], Mod(3, y), Vecsmall([0]), [[[3, [3]~, 1, 1, 1], [5, [5]~, 1, 1, 1]], Vecsmall([3, 1])], 0, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0 , 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 ; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 , 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, -1, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0 , 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 , 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1; 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, -1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0], [0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0 , 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1], [0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0; 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 , 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0 , 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0; 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, -1, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 3, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 , 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0; 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0; 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 1 , 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0 , 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3; 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, -3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 3, 0, -3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -3; 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, -1, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3 , 0, 0, 0; 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, -1, 0 , 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0; 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0], [0, 0, 0 , 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 , 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1 , 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] , [0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 3, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3; 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 3, -3, 0, 0; 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0 , 0; 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0 ; 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0 , -3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, -3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, -3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -3; 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0; 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, -3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0; 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, -3, 0, 0, 3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0; 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, -1, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0 , 0, 0; 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0 , -1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 , 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0 , 0; 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 3, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0 , -3, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0; 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0; 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0; 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, - 3, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, -3; 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, -3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 3, -3; 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 3, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0 , 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0 , 0, 3, 0, -3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 3; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0; 0, -1, 1, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0; 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], 0, [16, -4, -4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] Suite: all Suite: get degree: 1 center: 1 splitting: 1 automorphism: 1 b: 1 trivial hasse invariants: 1 charac: 1 dim: 1 absdim: 1 basis: 1 invbasis: 1 basis*invbasis: 1 iscyclic: 1 radical: 1 Suite: operations radical: 1 addition: 1 negation: 1 soustraction: 1 multiplication: 1 non-commutativity: 0 left division: 1 right division: 1 noncommutative left division: 1 noncommutative right division: 1 division by non-invertible: error("impossible inverse in algdivl: [Mod(Mod(- 1, i^2 + 1)*s, s^2 + 2), Mod(Mod(i - 1, i^2 + 1), s^2 + 2)]~.") nilpotent: 1 square: 1 square j: 1 inverse: 1 powers: 1 negative powers: 1 multiplication table j: 1 multiplication table: 1 characteristic polynomial: 1 characteristic polynomial j: 1 trace zero: 1 trace commutator: 1 trace: 1 norm zero: 1 norm one: 1 norm j: 1 norm is multiplicative a*b: 1 norm is multiplicative b*a: 1 poleval: 1 poleval b: 1 Suite: tensor product of cyclic algebras radical 1: 1 radical 2: 1 radical 3: 1 tensor of degree 2 and 3 no mo: 1 Suite: Grunwald-Wang A quadratic over Q, 2 large inert, imaginary: 1 A quartic over Q, 2 large inert, imaginary: error("sorry, nfgrunwaldwang for non-prime degree is not yet implemented.") A : degree 4 over Q(i), local degrees [4,1,1]: 1 A degree 3 over Q(j), local degrees [3,3] larger primes: 1 A : degree 3 over Q(sqrt(5)), local degrees [3,3] [0,0], larger primes: 1 A : degree 5 over Q(sqrt(7)), local degrees [5,5,5,5,5,5,5] [0,0]: 1 A : degree 9 over Q(zeta_9), local degrees [9,9,9,9]: 1 A degree 2 over totally real sextic, local degrees [2,2] [2,2,2,2,2,2], larg er primes: 1 A degree 2 over totally real sextic, local degrees [] [2,2,2,2,2,2]: 1 Suite: more operations construct algebra: [[x^3 - 21*x + 7, [1], [49, 1], 27, [], [], [[1, x + 1, x ^2 - x - 2], [1, 1/3, Mat(1/9)]], [1, -1, 1; 0, 1, 1; 0, 0, 1], 27, [y, [1, 0], 1, 1, [Mat(1), Mat(1), Mat(1), Mat(1), 1, Mat(1), [1, 0], []], [0.E-57], [1], Mat(1), Mat(1)], [x^3 - 21*x + 7, 0, 0, y, x^3 - 21*x + 7], [[x^3 - 21 *x + 7, [3, 0], 49, 27, [[1, -1.2469796037174670610500097680084796213, 1.801 9377358048382524722046390148901023; 1, 0.44504186791262880857780512899358951 893, -1.2469796037174670610500097680084796213; 1, 1.801937735804838252472204 6390148901023, 0.44504186791262880857780512899358951893], [1, -1.24697960371 74670610500097680084796213, 1.8019377358048382524722046390148901023; 1, 0.44 504186791262880857780512899358951893, -1.24697960371746706105000976800847962 13; 1, 1.8019377358048382524722046390148901023, 0.44504186791262880857780512 899358951893], [1, -1, 2; 1, 0, -1; 1, 2, 0], [3, 1, 1; 1, 5, -2; 1, -2, 5], [7, 0, 5; 0, 7, 5; 0, 0, 1], [3, -1, -1; -1, 2, 1; -1, 1, 2], [7, [2, 1, -1 ; 1, 3, 1; 0, 1, 2]], []], [-4.7409388111524011831500293040254388638, 0.3351 2560373788642573341538698076855680, 4.4058132074145147574166139170446703070] , [9, 3*x + 3, x^2 - x - 11], [1, -1, 10; 0, 3, 3; 0, 0, 9], [1, 0, 0, 0, 1, -1, 0, -1, 2; 0, 1, 0, 1, 1, 1, 0, 1, -1; 0, 0, 1, 0, 1, 0, 1, 0, 0]], [[1; 0; 0], Mat(1), 1, Vecsmall([1])]]], [-1/3*x^2 - 2/3*x + 14/3, 1/3*x^2 - 1/3 *x - 14/3], Mod(-6, y), Vecsmall([0]), [[[2, [2]~, 1, 1, 1], [3, [3]~, 1, 1, 1], [7, [7]~, 1, 1, 1]], Vecsmall([1, 2, 0])], 0, [1, 0, 0, 0, 0, 4/7, 0, 4 /7, 5/7; 0, 1, 0, 0, 0, 4/7, 0, 2/7, 5/7; 0, 0, 1, 0, 0, 5/7, 0, 0, 1/7; 0, 0, 0, 1, 0, 5/7, 0, 1/7, 5/7; 0, 0, 0, 0, 1, 5/7, 0, 4/7, 5/7; 0, 0, 0, 0, 0 , 1/7, 0, 0, 1/7; 0, 0, 0, 0, 0, 0, 1, 2/7, 5/7; 0, 0, 0, 0, 0, 0, 0, 1/7, 5 /7; 0, 0, 0, 0, 0, 0, 0, 0, 1/7], [1, 0, 0, 0, 0, -4, 0, -4, 19; 0, 1, 0, 0, 0, -4, 0, -2, 9; 0, 0, 1, 0, 0, -5, 0, 0, 4; 0, 0, 0, 1, 0, -5, 0, -1, 5; 0 , 0, 0, 0, 1, -5, 0, -4, 20; 0, 0, 0, 0, 0, 7, 0, 0, -7; 0, 0, 0, 0, 0, 0, 1 , -2, 5; 0, 0, 0, 0, 0, 0, 0, 7, -35; 0, 0, 0, 0, 0, 0, 0, 0, 7], [[1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0 ; 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 1, -1, 4, 4, 5, 19, 8, 17; 1, 1, 1, 4, 4, 7, 9, 6, 12; 0, 1, 0, 5, 5, 7, 4, 5, 10; 0, 0, 0, 6, 5, 7, 5, 5, 10; 0, 0, 0, 4, 4, 5, 20, 8, 17; 0, 0, 0, -7, -7, -9, -7, -7, -14; 0, 0, 0, 0, 0, 0, 5, 1, 2; 0, 0, 0, 0, 0, 0, -35, -9, -21; 0, 0, 0, 0, 0, 0, 7, 2, 5], [0, -1, 2, 0, -4, -2, -15, -9, -22; 0, 1, -1, 0, -4, -3, -7, -5, -11; 1, 0, 0, 0, -5, -3, -4, -4, -8; 0, 0, 0, 0, -4, -3, -4, -4, -8; 0, 0, 0, 1, -4, -2, -16, -9, -22; 0, 0, 0, 0, 7, 5, 7, 7, 14; 0, 0, 0, 0, 0, 0, -2, -1, -3; 0, 0, 0, 0, 0, 0, 28, 12, 35; 0, 0, 0, 0, 0, 0, -7, -3, -9], [0, 0, -4, 0, -4, -3, -6, -4, -5; 0, 0, -4, 0, - 2, -3, 0, -2, -5; 0, 0, -5, 0, 0, -3, 0, 0, -1; 1, 0, -5, 0, -1, -3, 0, 0, 0 ; 0, 1, -5, 0, -4, -3, 0, -2, 0; 0, 0, 7, 0, 0, 4, 0, 0, 0; 0, 0, 0, 1, -2, 0, 0, -1, 0; 0, 0, 0, 0, 7, 0, 0, 4, 0; 0, 0, 0, 0, 0, 1, 0, 0, 1], [0, -4, 0, -15, -15, -21, 0, -11, -19; 0, -4, 0, -7, -7, -11, 0, -7, -15; 0, -5, 0, -4, -4, -8, -6, -6, -13; 0, -4, -1, -4, -4, -8, 0, -4, -8; 1, -4, 1, -16, -1 6, -21, 0, -12, -22; 0, 7, 0, 7, 7, 13, 0, 7, 14; 0, 0, 0, -2, -3, -3, 0, -2 , -3; 0, 0, 0, 28, 28, 35, 0, 20, 35; 0, 0, 0, -7, -7, -9, 0, -5, -9], [0, - 3, -2, -9, -12, -15, -5, -12, -23; 0, -1, -3, -3, -6, -8, 1, -6, -14; 0, -3, -3, 0, -3, -6, -4, -4, -9; 0, -3, -4, 1, -3, -6, 0, -3, -6; 0, -2, -3, -9, -12, -15, 0, -11, -21; 1, 5, 5, 1, 5, 11, 1, 6, 12; 0, 0, 0, -1, -3, -2, 2, -2, -3; 0, 0, 0, 21, 21, 23, 0, 19, 36; 0, 0, 0, -5, -4, -5, -1, -4, -8], [0 , -4, 19, -6, 0, 7, 0, -2, -1; 0, -2, 9, 0, -6, 1, 0, -4, -1; 0, 0, 4, 0, 0, 2, 0, 0, 4; 0, -1, 5, 0, 0, 3, -6, -2, 0; 0, -4, 20, 0, 0, 12, 0, -2, 0; 0, 0, -7, 0, 0, -5, 0, 0, -7; 1, -2, 5, 0, 0, 3, 0, 0, 0; 0, 7, -35, 0, 0, -21 , 0, 2, 0; 0, 0, 7, 0, 0, 5, 0, 0, 1], [0, -1, 4, -10, -8, -9, 8, -4, -4; 0, -1, 2, -2, -4, -3, 6, -2, -2; 0, -2, 1, 0, 0, -1, 2, 0, 1; 0, -2, 0, 0, -1, -2, 4, 0, 2; 0, -1, 5, -8, -8, -7, 10, -4, -4; 0, 3, -1, 2, 2, 4, -8, 0, -3 ; 0, 0, 1, -1, -2, -1, 2, -1, -1; 1, -2, -9, 16, 17, 13, -10, 10, 12; 0, 1, 2, -4, -4, -3, 2, -2, -2], [0, 5, 8, -17, -10, -7, 20, -2, 3; 0, 2, 3, 1, -4 , 2, 20, 2, 9; 0, 0, 0, 5, 4, 5, 16, 7, 17; 0, -1, -1, 2, 0, 0, 15, 4, 13; 0 , 6, 9, -9, -9, 0, 30, 1, 10; 0, 0, 0, 0, 0, 0, -28, -7, -21; 0, 1, 2, -1, - 3, 0, 4, -1, 0; 0, -14, -21, 21, 21, 0, -21, 7, 0; 1, 5, 5, -5, -4, 2, 4, 0, 3]], 0, [9, 3, 3, 0, 0, 9, 0, 6, 9]] norm(u): 1 norm(t): 1 trace(u): 1 trace(t): 1 u+t: 1 u*t: 1 u^3: 1 w^-1 L: 1 w^-1 R: 1 w^-1*u: [Mod(0, x^3 - 21*x + 7), Mod(Mod(1, y), x^3 - 21*x + 7), Mod(0, x^3 - 21*x + 7)]~ u*w^-1: [Mod(0, x^3 - 21*x + 7), Mod(Mod(1, y), x^3 - 21*x + 7), Mod(0, x^3 - 21*x + 7)]~ charpol(w): Y^3 - 21*Y^2 + 1179*Y + 9447301/28 eval charpol: 1 trace(w): 1 norm(w): 1 dim: 1 absdim: 1 iscommutative: 1 issemisimple: 1 issimple: 1 algleftmultable w+ww: 1 algleftmultable w*ww: 1 alg(basis(w)): 1 alg(basis(ww)): 1 basis(w)+ww: 1 basis(w)-ww: 1 w+basis(ww): 1 w-basis(ww): 1 basis(w)*ww: 1 w*basis(ww): 1 basis(w)^2: 1 basis(ww)^2: 1 basis(w)\ww: 1 w\basis(ww): 1 basis(ww)\w: 1 wwbasis(w): 1 basis(w)^-1: 1 basis(ww)^-1: 1 basis(w)/ww: 1 w/basis(ww): 1 basis(ww)/w: 1 ww/basis(w): 1 trace(basis(w)): 1 trace(basis(ww)): 1 alg(basis(w)) 2: 1 alg(basis(ww)) 2: 1 basis(w)+ww 2: 1 basis(w)-ww 2: 1 w+basis(ww) 2: 1 w-basis(ww) 2: 1 basis(w)*ww 2: 1 w*basis(ww) 2: 1 basis(w)^2 2: 1 basis(ww)^2 2: 1 basis(w)ww 2: 1 wbasis(ww) 2: 1 basis(ww)w 2: 1 wwbasis(w) 2: 1 basis(w)^-1 2: 1 basis(ww)^-1 2: 1 basis(w)/ww 2: 1 w/basis(ww) 2: 1 basis(ww)/w 2: 1 ww/basis(w) 2: 1 trace(basis(w)) 2: 1 trace(basis(ww)) 2: 1 alg(basis(w)) 3: 1 alg(basis(ww)) 3: 1 basis(w)+ww 3: 1 basis(w)-ww 3: 1 w+basis(ww) 3: 1 w-basis(ww) 3: 1 basis(w)*ww 3: 1 w*basis(ww) 3: 1 basis(w)^2 3: 1 basis(ww)^2 3: 1 basis(w)ww 3: 1 wbasis(ww) 3: 1 basis(ww)w 3: 1 wwbasis(w) 3: 1 basis(w)^-1 3: 1 basis(ww)^-1 3: 1 basis(w)/ww 3: 1 w/basis(ww) 3: 1 basis(ww)/w 3: 1 ww/basis(w) 3: 1 trace(basis(w)) 3: 1 trace(basis(ww)) 3: 1 radical: 1 iscommutative cyc 3: 1 issemisimple cyc 3: 1 issimple cyc 3: 1 algleftmultable/Q w+ww: 1 algleftmultable/Q w*ww: 1 alg(basis(w))/Q: 1 alg(basis(ww))/Q: 1 basis(w)+ww/Q: 1 basis(w)-ww/Q: 1 w+basis(ww)/Q: 1 w-basis(ww)/Q: 1 basis(w)*ww/Q: 1 w*basis(ww)/Q: 1 basis(w)^2/Q: 1 basis(ww)^2/Q: 1 basis(w)ww/Q: 1 wbasis(ww)/Q: 1 basis(ww)w/Q: 1 wwbasis(w)/Q: 1 basis(w)^-1/Q: 1 basis(ww)^-1/Q: 1 basis(w)/ww/Q: 1 w/basis(ww)/Q: 1 basis(ww)/w/Q: 1 ww/basis(w)/Q: 1 trace(basis(w))/Q: 1 trace(basis(ww))/Q: 1 radical/Q: 1 iscommutative /Q: 1 issemisimple /Q: 1 issimple /Q: 1 Suite: table algebra algisassociative 0.0: 1 algisassociative 0.1: error("incorrect type in algisassociative (mult. table ) (t_VEC).") algisassociative 0.2: 1 algisassociative 0.3: error("incorrect type in algisassociative (mult. table ) (t_POL).") construction 0: [0, 0, 0, 0, 0, 0, [1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 0, 0; 0, 1, 0; 0, 0, 1], [[1, 0, 0; 0, 1, 0; 0, 0, 1], [0, 0, 0; 1, 0, 1; 0, 0, 0], [0, 0, 0; 0, 0, 0; 1, 0, 1]], 0, [3, 0, 1]] iscyclic 0: 1 dim 0: 1 dim 0b: 1 char 0: 1 a+b 0: 1 a-b 0: 1 a*b 0: 1 b*a 0: 1 a^2 0: 1 b^2 0: 1 e^691691 0: 1 d^101 0: 1 multable(a) 0: 1 multable(b) 0: 1 divl(d,a) 0: 1 divl(d,b) 0: 1 d^-1 0: 1 divr(a,d) 0: 1 divr(b,d) 0: 1 rad(al) 0: 1 ss(al) 0: 1 proj(a) idem 0: 1 idemproj 0: [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]], [0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]]] simple components 0: 1 center al 0: 1 center ss 0: 1 primesubalg ss 0: error("domain error in algprimesubalg: characteristic = 0" ) x^3 - 2*x^2 + x charpol annihil(a) 0: 1 x^3 - x^2 charpol annihil(b) 0: 1 x^3 charpol annihil(c) 0: 1 x^3 - 4*x^2 + 5*x - 2 charpol annihil(d) 0: 1 x^3 - 3*x^2 + 3*x - 1 charpol annihil(e) 0: 1 random 0: [1, 0, 0]~ algsimpledec 0: 1 alg_decomposition 0: 1 iscommutative 0: 1 issemisimple 0: 1 issimple 0: 1 issimple ss 0: 1 isdivision 0: 1 algisassociative 2: 1 construction 2: [0, 0, 0, 0, 0, 0, [1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 0, 0; 0, 1, 0; 0, 0, 1], [[1, 0, 0; 0, 1, 0; 0, 0, 1], [0, 0, 0; 1, 0, 1; 0, 0, 0], [0, 0, 0; 0, 0, 0; 1, 0, 1]], 2, [1, 0, 1]] iscyclic 2: 1 dim 2: 1 char 2: 1 a+b 2: 1 a-b 2: 1 a*b 2: 1 b*a 2: 1 a^2 2: 1 b^2 2: 1 multable(a) 2: 1 multable(b) 2: 1 divl(un,a) 2: 1 divl(un,b) 2: 1 un^-1 2: 1 divr(a,un) 2: 1 divr(b,un) 2: 1 rad(al) 2: 1 ss(al) 2: 1 proj(a) idem 2: 1 idemproj 2: [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 2, [1]], [0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 2, [1]]] simple components 2: 1 center al 2: 1 center ss 2: 1 primesubalg ss 2: 1 x^3 + x charpol annihil(a) 2: 1 x^3 + x^2 charpol annihil(b) 2: 1 x^3 charpol annihil(c) 2: 1 random 2: [1, 0, 0]~ algsimpledec 2: 1 alg_decomposition 2: 1 iscommutative 2: 1 issemisimple 2: 1 issimple 2: 1 issimple ss 2: 1 matrix trace 2: 1 matrix norm 2: 1 norm 2: 1 construction 3: [0, 0, 0, 0, 0, 0, [1, 0; 0, 1], [1, 0; 0, 1], [[1, 0; 0, 1] , [0, 0; 1, 0]], 3, [2, 0]] iscyclic 3: 1 dim 3: 1 char 3: 1 a+b 3: 1 a-b 3: 1 a*b 3: 1 b*a 3: 1 a^2 3: 1 b^2 3: 1 a^691691 3: 1 multable(a) 3: 1 multable(b) 3: 1 algdivl(a,b) 3: 1 a^-1 3: 1 algdivr(b,a) 3: 1 rad(al) 3: 1 ss(al) 3: 1 center al 3: 1 center ss 3: 1 primesubalg ss 3: 1 x^2 + x + 1 charpol annihil(a) 3: 1 x^2 charpol annihil(b) 3: 1 random 3: [1, 0]~ algsimpledec 3: 1 alg_decomposition 3: 1 iscommutative 3: 1 issemisimple 3: 1 issemisimple ss 3: 1 issimple 3: 1 issimple ss 3: 1 construction 3c: [0, 0, 0, 0, 0, 0, [1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 0, 0; 0 , 1, 0; 0, 0, 1], [[1, 0, 0; 0, 1, 0; 0, 0, 1], [0, 0, 0; 1, 0, 0; 0, 1, 0], [0, 0, 0; 0, 0, 0; 1, 0, 0]], 3, [0, 0, 0]] iscyclic 3c: 1 dim 3c: 1 char 3c: 1 a+b 3c: 1 a-b 3c: 1 a*b 3c: 1 b*a 3c: 1 a^2 3c: 1 b^2 3c: 1 a^691691 3c: 1 multable(a) 3c: 1 multable(b) 3c: 1 algdivl(a,b) 3c: 1 a^-1 3c: 1 algdivr(b,a) 3c: 1 rad(al) 3c: 1 ss(al) 3c: 1 center al 3c: 1 center ss 3c: 1 primesubalg ss 3c: 1 x^3 + 2 charpol annihil(a) 3c: 1 x^3 charpol annihil(b) 3c: 1 random 3c: [1, 0, 0]~ algsimpledec 3c: 1 alg_decomposition 3c: 1 iscommutative 3c: 1 issemisimple 3c: 1 issemisimple ss 3c: 1 issimple 3c: 1 issimple ss 3c: 1 construction 2b: [0, 0, 0, 0, 0, 0, [1, 0; 0, 1], [1, 0; 0, 1], [[1, 0; 0, 1 ], [0, 1; 1, 1]], 2, [0, 1]] iscyclic 2b: 1 dim 2b: 1 char 2b: 1 a+b 2b: 1 a-b 2b: 1 a*b 2b: 1 b*a 2b: 1 a^2 2b: 1 b^2 2b: 1 a^691691 2b: 1 multable(a) 2b: 1 multable(b) 2b: 1 divl(a,b) 2b: 1 a^-1 2b: 1 divr(b,a) 2b: 1 rad(al) 2b: 1 center al 2b: 1 primesubalg al 2b: 1 x^2 + x + 1 charpol annihil(a) 2b: 1 x^2 + x + 1 charpol annihil(b) 2b: 1 random 2b: [1, 0]~ algsimpledec 2b: 1 alg_decomposition 2b: 1 iscommutative 2b: 1 issemisimple 2b: 1 issimple 2b: 1 issimple,1 2b: 1 construction 3b: [0, 0, 0, 0, 0, 0, [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, 1, 0, 0; 1, 0, 0, 0; 0, 0, 1, 0; 0, 0 , 0, 2], [0, 0, 0, 2; 0, 0, 0, 2; 1, 2, 0, 0; 0, 0, 0, 0], [0, 0, 2, 0; 0, 0 , 1, 0; 0, 0, 0, 0; 1, 1, 0, 0]], 3, [1, 0, 0, 0]] iscyclic 3b: 1 dim 3b: 1 char 3b: 1 a+b 3b: 1 a-b 3b: 1 a*b 3b: 1 b*a 3b: 1 a^2 3b: 1 b^2 3b: 1 a^691691 3b: 1 b^691691 3b: 1 multable(a) 3b: 1 multable(b) 3b: 1 divl(a,b) 3b: 1 a^-1 3b: 1 divr(b,a) 3b: 1 rad(al) 3b: 1 center al 3b: 1 primesubalg al 3b: 1 x^4 + x^2 + 1 charpol annihil(a) 3b: 1 x^4 + 2*x^3 + x^2 charpol annihil(b) 3b: 1 x^4 charpol annihil(c) 3b: 1 random 3b: [1, 0, 0, 1]~ algsimpledec 3b: 1 alg_decomposition 3b: 1 iscommutative 3b: 1 issemisimple 3b: 1 issimple 3b: 1 construction 2c: [0, 0, 0, 0, 0, 0, [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, 0, 1, 0; 1, 0, 0, 1; 0, 0, 0, 0; 0, 0 , 1, 0], [0, 0, 0, 0; 0, 0, 0, 0; 1, 0, 0, 0; 0, 1, 0, 0], [0, 0, 0, 0; 0, 0 , 0, 0; 0, 0, 1, 0; 1, 0, 0, 1]], 2, [0, 0, 0, 0]] iscyclic 2c: 1 dim 2c: 1 char 2c: 1 a+b 2c: 1 a-b 2c: 1 a*b 2c: 1 b*a 2c: 1 a^2 2c: 1 b^2 2c: 1 a^691691 2c: 1 b^691691 2c: 1 c^691691 2c: 1 multable(a) 2c: 1 multable(b) 2c: 1 divl(c,a) 2c: 1 divl(c,b) 2c: 1 c^-1 2c: 1 divr(a,c) 2c: 1 divr(b,c) 2c: 1 rad(al) 2c: 1 center al 2c: 1 primesubalg al 2c: 1 x^4 charpol annihil(a) 2c: 1 x^4 + x^2 charpol annihil(b) 2c: 1 x^4 + x^2 + 1 charpol annihil(c) 2c: 1 random 2c: [1, 0, 0, 1]~ algsimpledec 2c: 1 alg_decomposition 2c: 1 iscommutative 2c: 1 issemisimple 2c: 1 issimple 2c: 1 construction 5: [0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 5, [1]] iscyclic 5: 1 dim 5: 1 char 5: 1 a+b 5: 1 a-b 5: 1 a*b 5: 1 b*a 5: 1 a^2 5: 1 b^2 5: 1 a^691691 5: 1 multable(a) 5: 1 multable(b) 5: 1 divl(a,b) 5: 1 a^-1 5: 1 divr(a,b) 5: 1 rad(al) 5: 1 center al 5: 1 primesubalg al 5: 1 x + 3 charpol annihil(a) 5: 1 x + 2 charpol annihil(b) 5: 1 random 5: [1]~ algsimpledec 5: 1 alg_decomposition 5: 1 iscommutative 5: 1 issemisimple 5: 1 issimple 5: 1 construction 0b: [0, 0, 0, 0, 0, 0, [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [[1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [0, 0, 1, 0, 0; 1, 0, 0, 1, 0; 0, 0, 0, 0, 0; 0, 0, -1, 0, 0; 0, 1, -1, -1, 1], [0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 1 , 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 0, 0, 0], [0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 0, 0, 1, 0, 0; 1, 0, 0, 1, 0; 0, 0, 0, 0, 0], [0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 1, 1, 0, 0, 1]], 0, [5, 1, 0, 2, 1]] iscyclic 0b: 1 dim 0b: 1 char 0b: 1 a+b 0b: 1 a-b 0b: 1 a*b 0b: 1 b*a 0b: 1 a^2 0b: 1 b^2 0b: 1 a^691691 0b: 1 b^691 0b: 1 multable(a) 0b: 1 multable(b) 0b: 1 divl(b,a) 0b: 1 b^-1 0b: 1 divr(a,b) 0b: 1 rad(al) 0b: 1 idemproj 0b: [[0, 0, 0, 0, 0, 0, [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, 0, 1, 0; 1, 0, 0, 1; 0, 0, 0, 0; 0, 0, - 1, 0], [0, 0, 0, 0; 0, 0, 0, 0; 1, 0, 0, 0; 0, 1, 0, 0], [0, 0, 0, 0; 0, 0, 0, 0; 0, 0, 1, 0; 1, 0, 0, 1]], 0, [4, 0, 0, 2]], [0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]]] simple components 0b: 1 mt M2 component 0b: 1 center al 0b: 1 primesubalg al 0b: error("domain error in algprimesubalg: characteristic = 0 ") x^5 - 4*x^4 + 6*x^3 - 4*x^2 + x charpol annihil(a) 0b: 1 x^5 - 6*x^4 + 14*x^3 - 16*x^2 + 9*x - 2 charpol annihil(b) 0b: 1 random 0b: [1, 0, 0, 1, 1]~ algsimpledec 0b: 1 alg_decomposition 0b: 1 subalg M2(Q): 1 iscommutative 0b: 1 issemisimple 0b: 1 issimple 0b: 1 construction 3d: [0, 0, 0, 0, 0, 0, [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [[1, 0, 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 1, 0, 0; 0, 0, 0, 1, 0; 0, 0, 0, 0, 1], [0, 0, 1, 0, 0; 1, 0, 0, 1, 0; 0, 0, 0, 0, 0; 0, 0, 2, 0, 0; 0, 1, 2, 2, 1], [0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 1, 0 , 0, 0, 0; 0, 1, 0, 0, 0; 0, 0, 0, 0, 0], [0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 0, 0, 1, 0, 0; 1, 0, 0, 1, 0; 0, 0, 0, 0, 0], [0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 1, 1, 0, 0, 1]], 3, [2, 1, 0, 2, 1]] iscyclic 3d: 1 dim 3d: 1 char 3d: 1 a+b 3d: 1 a-b 3d: 1 a*b 3d: 1 b*a 3d: 1 a^2 3d: 1 b^2 3d: 1 a^691691 3d: 1 b^691 3d: 1 multable(a) 3d: 1 multable(b) 3d: 1 divl(b,a) 3d: 1 b^-1 3d: 1 divr(a,b) 3d: 1 rad(al) 3d: 1 idemproj 3d: [[0, 0, 0, 0, 0, 0, [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, 0, 1, 0; 1, 0, 0, 1; 0, 0, 0, 0; 0, 0, 2 , 0], [0, 0, 0, 0; 0, 0, 0, 0; 1, 0, 0, 0; 0, 1, 0, 0], [0, 0, 0, 0; 0, 0, 0 , 0; 0, 0, 1, 0; 1, 0, 0, 1]], 3, [1, 0, 0, 2]], [0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 3, [1]]] simple components 3d: 1 mt M2 component 3d: 1 center al 3d: 1 primesubalg al 3d: 1 x^5 + 2*x^4 + 2*x^2 + x charpol annihil(a) 3d: 1 x^5 + 2*x^3 + 2*x^2 + 1 charpol annihil(b) 3d: 1 random 3d: [1, 0, 0, 1, 1]~ algsimpledec 3d: 1 alg_decomposition 3d: 1 subalg M2(F3): 1 iscommutative 3d: 1 issemisimple 3d: 1 issimple 3d: 1 issimple,1 3d: 1 maxorder assoc: 1 natorder assoc: 1 spl(1): 1 spl(i): 1 spl(j): 1 spl(k): 1 spl(basis(1)): 1 spl(basis(i)): 1 spl(basis(j)): 1 spl(basis(k)): 1 spl(a*1): 1 spl(a*i): 1 spl(a*j): 1 spl(a*k): 1 spl(b*1): 1 spl(b*i): 1 spl(b*j): 1 spl(b*k): 1 nattomax 1: 1 nattomax 2: 1 ord*invord=id: 1 spl additive: 1 spl multiplicative: 1 changebasis bug 1: 1 changebasis bug 2: 1 changebasis bug 3: 1 changebasis bug 4: 1 algtableinit segfault bug: 1 center of CSA: 1 radical of CSA: 1 decomposition of CSA: 1 alg_decomposition of CSA: 1 alsimple bug 0 tests for al_CSA: 1 1 algebra: csa getcenter: 1 csa getsplitting: 1 getrelmultable: 1 getsplittingdata: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 hasse invariants: hassei csa: error("sorry, computation of Hasse invariants over table CSA is not yet implemented.") hassef cas: error("sorry, computation of Hasse invariants over table CSA is not yet implemented.") hasse csa: error("sorry, computation of Hasse invariants over table CSA is n ot yet implemented.") csa splitting pol: 1 csa basis: 1 csa invbasis: 1 csa absdim: 1 csa char: 1 csa deg: 1 csa dim: 1 csa absdim: 1 csa type: 1 csa iscommutative: 1 csa issemisimple: 1 elements: [0, Mod(y, y^3 - y + 1), 0, 0]~ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]~ csa add: 1 csa neg: 1 csa neg 2: 1 csa sub: 1 csa mul: 1 csa mul 2: 1 csa sqr: 1 csa sqr 2: 1 csa mt: 1 csa inv: 1 csa inv 2: 1 csa divl: 1 csa pow: 1 csa mul 3: 1 csa mul 4: 1 csa pow 2: 1 csa sub 2: 1 csa sub 3: 1 csa inv 3: 1 csa inv 4: 1 csa inv 5: 1 csa trace: 1 csa trace 2: 1 1 testcharpol 1 1 1 testcharpol2 1 1 1 testnorm 1 1 1 testnorm2 1 1 1 examples from docu 0 [2, 2]~ 0 1 [Mod(Mod(-1/3, y), x^2 + 1), Mod(Mod(2/3, y), x^2 + 1)]~ 0 1 1 [Mod(-2/5*x - 1/5, x^2 + 1), 0]~ [0, 2, 0, -1, 2, 0, 0, 0]~ [Mod(Mod(y, y^2 - 5), x^2 - 2), 1]~ [Mod(Mod(-1/2*y - 2, y^2 - 5)*x + Mod(-1/4*y + 5/4, y^2 - 5), x^2 - 2), Mod( Mod(-3/4*y + 7/4, y^2 - 5), x^2 - 2)]~ [0, 1, 0, 0, 2, -3, 0, 0]~ [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 2, [1]], [0, 0, 0, 0, 0, 0, [1 , 0; 0, 1], [1, 0; 0, 1], [[1, 0; 0, 1], [0, 1; 1, 1]], 2, [0, 1]]] [1 0] [0 1] [0 0] [0, 0, 0, 0, 0, 0, [1, 0; 0, 1], [1, 0; 0, 1], [[1, 0; 0, 1], [0, 1; 1, 1]], 2, [0, 1]] [[0, 0, 0, 0, 0, 0, [1, 0; 0, 1], [1, 0; 0, 1], [[1, 0; 0, 1], [0, 1; 1, 1]] , 2, [0, 1]], [1, 0; 0, 0; 0, 1]] 1 0 0 0 0 1 [[[2, [2, 0]~, 1, 2, 1], [3, [3, 0]~, 1, 2, 1]], Vecsmall([0, 1])] 12960000 12960000 12 y^3 - y + 1 2 4 -1/3*x^2 + 1/3*x + 26/3 Mod(-77, y) 13 1 [[[2, [2, 0]~, 1, 2, 1], [19, [10, 2]~, 1, 1, [-8, 2; 2, -10]]], Vecsmall([0 , 1])] Vecsmall([1, 0]) 1/2 0 1/2 0 2 1 2 1 2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 [1, [2, [2, 0]~, 1, 2, 1]] x^2 + Mod(-y + 13, y^2 - 5) [1 0 0 -1] [0 1 0 -1] [0 0 1 -1] [0 0 0 2] [1 0 0 1/2] [0 1 0 1/2] [0 0 1 1/2] [0 0 0 1/2] [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, -1, 1, 0; 1, 0, 1, 1; 0, 0, 1, 1; 0, 0, -2, -1], [0, -1, -1, -1; 0, -1, 0, -1; 1, -1, 0, 0; 0, 2, 0, 1], [0, -1, 0, -1; 0, 0, 1, 0; 0, -1, 1, 0; 1, 1, -1, 1]] [1/2, -1/2, 0, 0]~ [2, 3, 5, -4]~ [0 -1 1 0] [1 0 1 1] [0 0 1 1] [0 0 -2 -1] [-1 0 0 -1] [-1 0 1 0] [-1 -1 0 -1] [ 2 0 0 1] [-1, -1, 0, 0]~ [Mod(x + 1, x^2 + 1) Mod(x - 1, x^2 + 1)] [Mod(x + 1, x^2 + 1) Mod(-x + 1, x^2 + 1)] [8, -8, 0, 0]~ [0, 1, -1, 0]~ 11 3 [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, y, 0, 0; 1, 0, 0, 0; 0, 0, 0, y; 0, 0, 1, 0], [0, 0, y^2, 0; 0, 0, 0, -y^2; 1, 0, 0, 0; 0, -1, 0, 0], [0, 0, 0, -5; 0, 0, y^2, 0; 0, -y, 0, 0; 1, 0, 0, 0]] x^2 - y [[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]~, [1, 0; 0, -1; 0, 0; 0, 0; 0, 0; 0, 0 ; 0, 1; 0, 0; 0, 0; 0, 0; 0, 0; 0, 0], [1, Mod(x^2, x^6 - 5), Mod(x^4, x^6 - 5), Mod(x, x^6 - 5), Mod(1/2*x^4 + 1/2*x^3 + 1/2*x + 1/2, x^6 - 5), Mod(1/2 *x^5 + 1/2*x^4 + 1/2*x^2 + 1/2*x, x^6 - 5), Mod(x^2, x^6 - 5), Mod(x^4, x^6 - 5), Mod(x^4 + x^2 + 1, x^6 - 5), 3, Mod(x^2, x^6 - 5), Mod(x^4, x^6 - 5); 0, 0, 0, 0, 0, 0, 1, Mod(x^2, x^6 - 5), Mod(1/10*x^4 + 1/2*x^2 + 1/2, x^6 - 5), Mod(1/2*x^4 - 1/2*x, x^6 - 5), Mod(-1/10*x^3 + 1/2, x^6 - 5), Mod(-1/10* x^5 + 1/2*x^2, x^6 - 5)]] 2 18 18 1 1 1 matrices over algebras [[1, 0, 2, 2, 2, 2, 0, -2]~ [-2, -1, 1, 0, -1, -2, -1, 1]~] [[1, 2, 0, -2, 2, 1, 2, 2]~ [2, -2, -2, 0, -2, 2, -1, 2]~] [[-2, 0, -2, 2, 0, 2, 0, -2]~ [0, 2, -1, 0, -2, -2, -1, -1]~] [[0, 2, 0, -2, -1, 1, 1, -1]~ [0, 2, 0, 2, 0, 1, 0, 1]~] mul alM: [[30, 1, -15, 6, -9, -30, -41, 37]~, [62, -3, -20, 6, -11, -16, -49 , 20]~; [247, 49, -39, 122, -43, 31, -265, 73]~, [168, 74, -22, 68, -91, 48, -136, 32]~] sqr alM: 1 divl alM: 1 divr alM: 1 isinv alM: 1 isinv alM 2: 1 inv alM: 1 inv alM 2: 1 neg alM: 1 sub alM: 1 add alM: 1 algtobasis basistoalg alM 1: 1 algtobasis basistoalg alM 2: 1 algleftmultable add alM: 1 algleftmultable mul alM: 1 algleftmultable sqr alM: 1 algsplitm add alM: 1 algsplitm mul alM: 1 algsplitm sqr alM: 1 algsplitm sqr alM 2: 1 algtrace alM: 1 algtrace alM 2: 1 algtrace prod alM: 1 algnorm alM: 1 algnorm alM 2: 1 algcharpoly alM: 1 algcharpoly alM 2: 1 pow alM: 1 pow alM 2: 1 pow 0 alM: 1 [[Mod(Mod(-1/2*y - 1/2, y^2 - 5)*x + Mod(1/2*y + 1/2, y^2 - 5), x^2 + 1), Mo d(Mod(1/14*y + 3/14, y^2 - 5)*x + Mod(-1/14*y + 3/14, y^2 - 5), x^2 + 1)]~ [ Mod(-2*x + Mod(3/4*y - 17/4, y^2 - 5), x^2 + 1), Mod(Mod(-1/28*y - 3/4, y^2 - 5)*x - 6/7, x^2 + 1)]~] [[Mod(13/2*x + Mod(1/2*y + 4, y^2 - 5), x^2 + 1), Mod(Mod(-1/14*y + 11/7, y^ 2 - 5)*x + Mod(1/7*y + 53/14, y^2 - 5), x^2 + 1)]~ [Mod(Mod(-1/4*y - 3/4, y^ 2 - 5)*x + Mod(-1/2*y + 7/2, y^2 - 5), x^2 + 1), Mod(Mod(-1/14*y + 23/14, y^ 2 - 5)*x + Mod(1/28*y + 43/28, y^2 - 5), x^2 + 1)]~] [[Mod(Mod(-1/2*y - 3/2, y^2 - 5)*x + Mod(-3/2*y - 1/2, y^2 - 5), x^2 + 1), M od(Mod(1/14*y + 3/14, y^2 - 5)*x + Mod(-1/14*y - 11/14, y^2 - 5), x^2 + 1)]~ [Mod(Mod(1/2*y - 1, y^2 - 5)*x + Mod(-3/4*y - 7/4, y^2 - 5), x^2 + 1), Mod( Mod(1/28*y - 43/28, y^2 - 5)*x + Mod(-1/14*y - 22/7, y^2 - 5), x^2 + 1)]~] [[Mod(Mod(y + 5/2, y^2 - 5)*x + Mod(-1/4*y + 5/4, y^2 - 5), x^2 + 1), Mod(Mo d(1/28*y + 1/4, y^2 - 5)*x - 9/14, x^2 + 1)]~ [Mod(Mod(-5/4*y + 9/4, y^2 - 5 )*x + Mod(1/4*y + 3/4, y^2 - 5), x^2 + 1), Mod(Mod(-1/28*y + 25/28, y^2 - 5) *x + Mod(1/28*y + 39/28, y^2 - 5), x^2 + 1)]~] mul scalar alM: 1 [ [2, 1, 0, 2]~ [-1, -1, 2, -1]~] [[2, 1, -1, -2]~ [1, -1, 0, -1]~] [ [-2, 2, 2, 1]~ [-2, -2, 2, 1]~] [[-1, -2, 1, 1]~ [0, 1, 0, -1]~] mul alM t: [[-10, 4, 7, 3]~, [-4, -13, -3, -1]~; [-4, 5, 5, 11]~, [2, -2, 7, 5]~] sqr alM t: 1 divl alM t: 1 divr alM t: 1 isinv alM t: 1 isinv alM t 2: 1 inv alM t: 1 inv alM t 2: 1 neg alM t: 1 sub alM t: 1 add alM t: 1 algleftmultable add alM t: 1 algleftmultable mul alM t: 1 algleftmultable sqr alM t: 1 algtrace alM t: 1 algtrace alM t 2: 1 algtrace prod alM t: 1 algnorm alM t: 1 algnorm alM t 2: 1 algcharpoly alM t: 1 algcharpoly alM t 2: 1 pow alM t: 1 pow alM 2 t: 1 pow 0 alM t: 1 csa al2 al2 contains nfabs: 1 [[x^2 + (-2*y^2 + 2*y)*x + (6*y^2 - 5*y + 5), [292133, -1964*x^5 + 4725*x^4 - 14044*x^3 - 95698*x^2 - 164828*x - 456632, -1406*x^5 + 4870*x^4 - 7674*x^3 - 64939*x^2 - 119188*x + 52103], [[412, 92, 376; 0, 4, 0; 0, 0, 4], [-9, -7 , 6]~], 1, [], [], [[1, x], [1, 1]], [1, 0; 0, 1], 1, [y^3 - y + 1, [1, 1], -23, 1, [[1, 0.75487766624669276004950889635852869189, -1.324717957244746025 9609088544780973407; 1, -0.87743883312334638002475444817926434595 + 0.744861 76661974423659317042860439236724*I, 0.66235897862237301298045442723904867037 + 0.56227951206230124389918214490937306150*I], [1, 0.7548776662466927600495 0889635852869189, -1.3247179572447460259609088544780973407; 1, -0.1325770665 0360214343158401957487197871, 1.2246384906846742568796365721484217319; 1, -1 .6223005997430906166179248767836567132, 0.1000794665600717690812722823296756 0887], [1, 1, -1; 1, 0, 1; 1, -2, 0], [3, -1, 0; -1, 1, -3; 0, -3, 2], [23, 16, 10; 0, 1, 0; 0, 0, 1], [7, -2, -3; -2, -6, -9; -3, -9, -2], [23, [-10, - 1, 8; -7, -3, 1; 1, 7, -10]], [23]], [-1.32471795724474602596090885447809734 07, 0.66235897862237301298045442723904867037 + 0.562279512062301243899182144 90937306150*I], [1, y^2 - 1, y], [1, 0, 1; 0, 0, 1; 0, 1, 0], [1, 0, 0, 0, 0 , -1, 0, -1, 1; 0, 1, 0, 1, -1, 0, 0, 0, 1; 0, 0, 1, 0, -1, 0, 1, 0, 0]], [x ^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191, -1406/292133*x^5 + 4870 /292133*x^4 - 7674/292133*x^3 - 64939/292133*x^2 - 119188/292133*x + 52103/2 92133, 0, y^3 - y + 1, x^2 + (-2*y^2 + 2*y)*x + (6*y^2 - 5*y + 5)], [0, [[1, 0, 0; 0, -1, 0; 0, 0, 1; 0, 0, 0; 0, 0, 0; 0, 0, 0], [1, 0, 0; 0, -1, 0; 0, 0, 1], 1, Vecsmall([1, 2, 3])]]], [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, 0, 1, 0; 1, 0, 0, 1; 0, 0, 0, 0; 0, 0, -1, 0], [0, 0, 0, 0; 0, 0, 0, 0; 1, 0, 0, 0; 0, 1, 0, 0], [0, 0, 0, 0; 0, 0, 0, 0; 0, 0, 1, 0; 1, 0 , 0, 1]], [[0, 1, -1, -1, -2, 2, 0, 0, -2, 2, 0, 0]~, [1, 0; 0, 0; 0, 0; 0, 0; 0, 0; 0, 0; 0, 1; 0, 0; 0, 0; 0, 0; 0, 0; 0, 0], [1, Mod(-1964/292133*x^5 + 4725/292133*x^4 - 14044/292133*x^3 - 95698/292133*x^2 - 164828/292133*x - 456632/292133, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(- 1406/292133*x^5 + 4870/292133*x^4 - 7674/292133*x^3 - 64939/292133*x^2 - 119 188/292133*x + 52103/292133, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(-516/6719059*x^5 + 59549/6719059*x^4 - 144104/6719059*x^3 + 5636 9/6719059*x^2 + 2656099/6719059*x + 5563831/6719059, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(-54291/6719059*x^5 + 210489/6719059*x^4 - 786258/6719059*x^3 - 905381/6719059*x^2 - 6840464/6719059*x - 4510816/6719 059, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(-48132/67190 59*x^5 + 241931/6719059*x^4 - 785055/6719059*x^3 - 523468/6719059*x^2 - 1628 025/6719059*x + 4121552/6719059, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 3 6*x + 191), 0, 0, 0, 0, 0, 0; 0, 0, 0, Mod(-499864/154538357*x^5 - 232506/15 4538357*x^4 + 2075504/154538357*x^3 - 39252216/154538357*x^2 - 107292314/154 538357*x - 129681996/154538357, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36 *x + 191), Mod(1153778/154538357*x^5 - 4109402/154538357*x^4 + 13244560/1545 38357*x^3 + 24564582/154538357*x^2 + 151883496/154538357*x - 10149974/154538 357, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(171940/15453 8357*x^5 - 3019052/154538357*x^4 + 13537158/154538357*x^3 - 30710744/1545383 57*x^2 - 25903390/154538357*x - 175396598/154538357, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), 1, Mod(-1964/292133*x^5 + 4725/292133*x^4 - 14044/292133*x^3 - 95698/292133*x^2 - 164828/292133*x - 456632/292133, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(-1406/292133*x^5 + 487 0/292133*x^4 - 7674/292133*x^3 - 64939/292133*x^2 - 119188/292133*x + 52103/ 292133, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(-516/6719 059*x^5 + 59549/6719059*x^4 - 144104/6719059*x^3 + 56369/6719059*x^2 + 26560 99/6719059*x + 5563831/6719059, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36 *x + 191), Mod(-54291/6719059*x^5 + 210489/6719059*x^4 - 786258/6719059*x^3 - 905381/6719059*x^2 - 6840464/6719059*x - 4510816/6719059, x^6 - 4*x^5 + 15 *x^4 + 14*x^3 + 120*x^2 + 36*x + 191), Mod(-48132/6719059*x^5 + 241931/67190 59*x^4 - 785055/6719059*x^3 - 523468/6719059*x^2 - 1628025/6719059*x + 41215 52/6719059, x^6 - 4*x^5 + 15*x^4 + 14*x^3 + 120*x^2 + 36*x + 191)]], 0, 0, 0 , [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 , 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0 , 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 , 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0 , 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 0, 0, 0 , 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0 ], [0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0 , 0, 0, 1, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0 ; 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1; 1, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0 ; 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0 , 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0; 0, 0, 0 , 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, -1, 1; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1 , -1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0; 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 , 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, -1, 0, 0, 0 , 0, 0, 0, 0; 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0 , 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 , 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0; 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1; 1, - 1, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0; 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, -1, 1; 0, 0, 1, 0, 0, 0, 0 , 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]], 0, [12, -4, 0, 0, 0, 0, 0, 0, 0, 6, -2, 0]] csa al3 al3 contains nfabs: 1 trivial algebra over a quadratic field [[x, [1, -x], [1, 1], 1, [], [], [[1], [1]], Mat(1), 1, [y^2 + 1, [0, 1], -4 , 1, [Mat([1, 0.E-57 + 1.0000000000000000000000000000000000000*I]), [1, 1.00 00000000000000000000000000000000000; 1, -1.000000000000000000000000000000000 0000], [1, 1; 1, -1], [2, 0; 0, -2], [2, 0; 0, 2], [1, 0; 0, -1], [1, [0, -1 ; 1, 0]], [2]], [0.E-57 + 1.0000000000000000000000000000000000000*I], [1, y] , [1, 0; 0, 1], [1, 0, 0, -1; 0, 1, 1, 0]], [x^2 + 1, -x, -1, y^2 + 1, x], [ [x^2 + 1, [0, 1], -4, 1, [Mat([1, 0.E-77 + 1.0000000000000000000000000000000 000000*I]), [1, 1.0000000000000000000000000000000000000; 1, -1.0000000000000 000000000000000000000000], [1, 1; 1, -1], [2, 0; 0, -2], [2, 0; 0, 2], [1, 0 ; 0, -1], [1, [0, -1; 1, 0]], []], [0.E-77 + 1.00000000000000000000000000000 00000000*I], [1, x], [1, 0; 0, 1], [1, 0, 0, -1; 0, 1, 1, 0]], [[1, 0; 0, -1 ], [1, 0; 0, -1], 1, Vecsmall([1, 2])]]], [Mod(y, y^2 + 1)], Mod(1, y^2 + 1) , Vecsmall([]), [[], Vecsmall([])], 0, [1, 0; 0, 1], [1, 0; 0, 1], [[1, 0; 0 , 1], [0, -1; 1, 0]], 0, [2, 0]] [y]~ [-2*y + 1]~ [-3, 1]~ [-y + 1]~ [-3, 2]~ [Mod(Mod(y + 2, y^2 + 1), x)]~ [-1/5, 7/5]~ [-1/5, 7/5]~ [Mod(Mod(-y, y^2 + 1), x)]~ [1, 2]~ [Mod(Mod(y, y^2 + 1), x)] [ 0 1] [-1 0] x + Mod(2*y - 1, y^2 + 1) Mod(-y - 3, y^2 + 1) Mod(-y - 3, y^2 + 1) 1 1 1 0 0 1 1 1 0 [] trivial algebra over Q [[x, [1], [1, 1], 1, [], [], [[1], [1]], Mat(1), 1, [y, [1, 0], 1, 1, [Mat(1 ), Mat(1), Mat(1), Mat(1), 1, Mat(1), [1, 0], []], [0.E-57], [1], Mat(1), Ma t(1)], [x, 0, 0, y, x], [[x, [1, 0], 1, 1, [Mat(1), Mat(1), Mat(1), Mat(1), 1, Mat(1), [1, 0], []], [0.E-77], [1], Mat(1), Mat(1)], [Mat(1), Mat(1), 1, Vecsmall([1])]]], [0], Mod(1, y), Vecsmall([0]), [[], Vecsmall([])], 0, Mat( 1), Mat(1), [Mat(1)], 0, [1]] [-2]~ [1/3]~ [4/5]~ [-5/3]~ [14/5]~ [-2/3]~ [12/5]~ [12/5]~ [-1/2]~ [1/3]~ [-2] [Mod(1/3, x)] x - 1/3 4/5 4/5 1 1 1 0 0 1 1 1 0 [] trivial CSA over Q [Mod(9, y)]~ [4]~ nontrivial CSA over Q [Mod(0, y), Mod(12, y), Mod(6, y), Mod(12, y)]~ [-81, 27, 36, 45]~ empty matrices -v: 1 v^(-1): 1 v^n: 1 v^0: 1 mt(v)1 spl(v)1 trace(v): 1 norm(v): 1 charpoly(v): 1 v+v: 1 v-v: 1 v*v: 1 v/v: 1 v\v: 1 v*nv: 1 v*v 2: 1 trace(v) char 2: 1 [0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]] [12]~ [-1/7]~ [83/7]~ [85/7]~ [-12/7]~ [-12]~ [1/12]~ [1/49]~ [-1/84]~ 12 -1/7 x - 12 [-1/7] [1]~ 1 1 1 1 trivial tensor product 1 1 splitting a nasty commutative algebra 1 1 1 1 non associative algebra 0 csa without maximal order simplify bug #1671 testing simplify: degree 1 cyclic over Q 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 testing simplify: degree 1 cyclic over Q(i) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 testing simplify: degree 1 csa over Q 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 testing simplify: degree 1 csa over Q(i) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 testing simplify: quatalg over Q(s5) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 testing simplify: quatalg csa over Q 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 [1 0] [0 0] [0 1/2] [0 0] *** at top-level: algsplittingfield(almt) *** ^----------------------- *** algsplittingfield: incorrect type in alg_get_splittingfield [use alginit] (t_VEC). *** at top-level: algdegree(almt) *** ^--------------- *** algdegree: incorrect type in alg_get_degree [use alginit] (t_VEC). *** at top-level: alghassei(almt) *** ^--------------- *** alghassei: incorrect type in alg_get_hasse_i [use alginit] (t_VEC). *** at top-level: alghassef(almt) *** ^--------------- *** alghassef: incorrect type in alg_get_hasse_f [use alginit] (t_VEC). *** at top-level: algrandom(1,1) *** ^-------------- *** algrandom: incorrect type in checkalg [please apply alginit()] (t_INT). *** at top-level: algrandom(1,I) *** ^-------------- *** algrandom: incorrect type in algrandom (t_COMPLEX). 0 *** at top-level: algdim([1,[1],0,0,0,0,0,0,0,0]) *** ^------------------------------- *** algdim: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algdim([1,[1],0,0,0,0,0,0,0,0],1) *** ^--------------------------------- *** algdim: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algtensor(al,al2) *** ^----------------- *** algtensor: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algtensor(al2,al) *** ^----------------- *** algtensor: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algtensor(1,z,1) *** ^---------------- *** algtensor: incorrect type in checkalg [please apply alginit()] (t_INT). *** at top-level: algisassociative([1],0) *** ^----------------------- *** algisassociative: incorrect type in algisassociative (mult. table) (t_VEC). *** at top-level: algisassociative([[1,0;0,2],[0,0;0,0]]) *** ^--------------------------------------- *** algisassociative: incorrect type in algisassociative (mult. table) (t_VEC). *** at top-level: algmul(almt,a,b) *** ^---------------- *** algmul: incorrect type in alg_model (t_COL). *** at top-level: algtomatrix(almt,a,1) *** ^--------------------- *** algtomatrix: incorrect type in alg_model (t_COL). *** at top-level: alginv(almt,a) *** ^-------------- *** alginv: incorrect type in alg_model (t_COL). *** at top-level: algalgtobasis(almt,a) *** ^--------------------- *** algalgtobasis: incorrect type in algalgtobasis [use alginit] (t_VEC). *** at top-level: algbasistoalg(almt,[0,0,0,0]~) *** ^------------------------------ *** algbasistoalg: incorrect type in algbasistoalg [use alginit] (t_VEC). *** at top-level: algpoleval(almt,1,a) *** ^-------------------- *** algpoleval: incorrect type in algpoleval (t_INT). *** at top-level: algadd(almt,[zero;zero],m) *** ^-------------------------- *** algadd: inconsistent dimensions in alM_add (rows). *** at top-level: algadd(almt,[zero;zero;zero],[zero;zero]) *** ^----------------------------------------- *** algadd: inconsistent dimensions in alM_add (columns). *** at top-level: algsub(almt,[zero;zero],m) *** ^-------------------------- *** algsub: inconsistent dimensions in alM_sub (rows). *** at top-level: algsub(almt,[zero;zero;zero],[zero;zero]) *** ^----------------------------------------- *** algsub: inconsistent dimensions in alM_sub (columns). *** at top-level: algmul(almt,m,[zero;zero;zero]) *** ^------------------------------- *** algmul: inconsistent dimensions in alM_mul. *** at top-level: algsqr(almt,[zero;zero]) *** ^------------------------ *** algsqr: inconsistent dimensions in alM_mul. *** at top-level: algdivl(almt,m,zero) *** ^-------------------- *** algdivl: forbidden division t_MAT (1x2) \ t_COL (4 elts). *** at top-level: algdivl(almt,m,[zero,zero;zero,zero]) *** ^------------------------------------- *** algdivl: inconsistent dimensions in algdivl. *** at top-level: algdivl(almt,m,m) *** ^----------------- *** algdivl: inconsistent dimensions in algdivl (nonsquare). *** at top-level: alginv(almt,m) *** ^-------------- *** alginv: inconsistent dimensions in alginv_i (nonsquare). *** at top-level: algtomatrix(almt,m,1) *** ^--------------------- *** algtomatrix: inconsistent dimensions in algleftmultable_mat (nonsquare). *** at top-level: algpow(almt,m,3) *** ^---------------- *** algpow: inconsistent dimensions in alM_mul. *** at top-level: algtrace(almt,m) *** ^---------------- *** algtrace: inconsistent dimensions in algtrace_mat (nonsquare). *** at top-level: algcharpoly(almt,m) *** ^------------------- *** algcharpoly: inconsistent dimensions in algleftmultable_mat (nonsquare). *** at top-level: algcharpoly(alginit(nfinit(y),[-1,-1]),m) *** ^----------------------------------------- *** algcharpoly: incorrect type in easychar (t_MAT). *** at top-level: algnorm(almt,m) *** ^--------------- *** algnorm: inconsistent dimensions in algleftmultable_mat (nonsquare). *** at top-level: algnorm(alginit(nfinit(y),[-1,-1]),m) *** ^------------------------------------- *** algnorm: inconsistent dimensions in det. *** at top-level: alginit(nfinit(y),[2,[[],[]],[x]]) *** ^---------------------------------- *** alginit: incorrect type in Hasse invariant (t_POL). *** at top-level: alginit(nfinit(y),[2,[],[1,1]]) *** ^------------------------------- *** alginit: incorrect type in checkhasse [hf] (t_VECSMALL). *** at top-level: alginit(nfinit(y),[2,[[],[]],Vecsmall([1])]) *** ^-------------------------------------------- *** alginit: domain error in checkhasse: sum(Hasse invariants) != 0 *** at top-level: alginit(y,[2,[[],[]],[1]]) *** ^-------------------------- *** alginit: incorrect type in alginit (t_POL). *** at top-level: alginit(nfinit(y),y) *** ^-------------------- *** alginit: incorrect type in alginit (t_POL). *** at top-level: alginit(nfinit(y),[1,2,3,4]) *** ^---------------------------- *** alginit: incorrect type in alginit (t_VEC). *** at top-level: algtableinit(mt,y) *** ^------------------ *** algtableinit: incorrect type in algtableinit (t_POL). *** at top-level: alginit(nfinit(y^2+1),-3) *** ^------------------------- *** alginit: domain error in alg_matrix: n <= 0 *** at top-level: alginit(nfinit(x^2+1),3) *** ^------------------------ *** alginit: incorrect priority in alginit: variable x >= x *** at top-level: alginit(nfinit(highvar^2+1),3) *** ^------------------------------ *** alginit: incorrect priority in alginit: variable x >= highvar *** at top-level: ...t(nfinit(y^2-2),[-1,-1]);algrandom(al,-10) *** ^----------------- *** algrandom: domain error in algrandom: b < 0 *** at top-level: algrelmultable(al) *** ^------------------ *** algrelmultable: incorrect type in alg_get_relmultable [algebra not given via mult. table] (t_VEC). *** at top-level: algsplittingdata(al) *** ^-------------------- *** algsplittingdata: incorrect type in alg_get_splittingdata [algebra not given via mult. table] (t_VEC). *** at top-level: alghasse(almt,1) *** ^---------------- *** alghasse: incorrect type in alghasse [use alginit] (t_VEC). *** at top-level: algindex(almt,1) *** ^---------------- *** algindex: incorrect type in algindex [use alginit] (t_VEC). *** at top-level: algisdivision(almt) *** ^------------------- *** algisdivision: sorry, algisdivision for table algebras is not yet implemented. *** at top-level: algissplit(almt) *** ^---------------- *** algissplit: incorrect type in algissplit [use alginit] (t_VEC). *** at top-level: algisramified(almt) *** ^------------------- *** algisramified: incorrect type in algisramified [use alginit] (t_VEC). *** at top-level: algramifiedplaces(almt) *** ^----------------------- *** algramifiedplaces: incorrect type in algramifiedplaces [use alginit] (t_VEC). *** at top-level: alghasse(al,-1) *** ^--------------- *** alghasse: domain error in is_place_emb: pl <= 0 *** at top-level: alghasse(al,3) *** ^-------------- *** alghasse: domain error in is_place_emb: pl > 2 *** at top-level: alghasse(al,2^100) *** ^------------------ *** alghasse: domain error in is_place_emb: pl > 2 *** at top-level: alghasse(al,[]) *** ^--------------- *** alghasse: incorrect type in is_place_emb (t_VEC). *** at top-level: alghasse(al,1/3) *** ^---------------- *** alghasse: incorrect type in is_place_emb (t_FRAC). *** at top-level: algtableinit([matid(2),[0,1/2;1,0]]) *** ^------------------------------------ *** algtableinit: domain error in algtableinit: denominator(mt) != 1 *** at top-level: alginit(Q,[matid(2),[0,1/2;1,0]]) *** ^--------------------------------- *** alginit: domain error in alg_csa_table: denominator(mt) != 1 *** at top-level: alginit(Q,[-1/2,-1]) *** ^-------------------- *** alginit: domain error in alg_hilbert: denominator(a) != 1 *** at top-level: alginit(Q,[-1,-1/2]) *** ^-------------------- *** alginit: domain error in alg_hilbert: denominator(b) != 1 *** at top-level: alginit(rnfinit(Q,x^2+1),[-x,-1/2]) *** ^----------------------------------- *** alginit: domain error in alg_cyclic: denominator(b) != 1 *** at top-level: algsqr([0,0,0,0,0,0,0,0,0,0,0],[]~) *** ^----------------------------------- *** algsqr: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algsqr([0,0,0,0,0,0,0,0,[],0,0],[]~) *** ^------------------------------------ *** algsqr: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algsqr([0,0,0,0,0,0,0,0,[0],0,0],[]~) *** ^------------------------------------- *** algsqr: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algsqr([0,0,0,0,0,0,0,0,[[;]],0,0],[]~) *** ^--------------------------------------- *** algsqr: incorrect type in alg_model (t_COL). *** at top-level: algsqr([[],0,0,0,0,0,0,0,[[;]],0,0],[]~) *** ^---------------------------------------- *** algsqr: incorrect type in checkalg [please apply alginit()] (t_VEC). *** at top-level: algsqr([[],[0],0,0,0,0,0,0,[[;]],0,0],[]~) *** ^------------------------------------------ *** algsqr: incorrect type in checkrnf (t_VEC). *** at top-level: algdim([[],[0],0,0,0,0,0,0,[[;]],0,0]) *** ^-------------------------------------- *** algdim: incorrect type in checkrnf (t_VEC). *** at top-level: algdegree([[],[0],0,0,0,0,0,0,[[;]],0,0]) *** ^----------------------------------------- *** algdegree: incorrect type in checkrnf (t_VEC). *** at top-level: algdegree([rnfinit(nfinit(y),x),[[]],0,0,0,0,0 *** ^---------------------------------------------- *** algdegree: incorrect type in alg_get_degree [use alginit] (t_VEC). *** at top-level: algcenter([rnfinit(nfinit(y),x),[[]],0,0,0,0,0 *** ^---------------------------------------------- *** algcenter: incorrect type in alg_get_center [use alginit] (t_VEC). *** at top-level: algcentralproj(almt,0) *** ^---------------------- *** algcentralproj: incorrect type in alcentralproj (t_INT). *** at top-level: algcentralproj(almt,[zero,zero]) *** ^-------------------------------- *** algcentralproj: incorrect type in alcentralproj [z[i]'s not surjective] (t_VEC). *** at top-level: algsubalg(almt,0) *** ^----------------- *** algsubalg: incorrect type in algsubalg (t_INT). *** at top-level: algisassociative([]) *** ^-------------------- *** algisassociative: incorrect type in algisassociative (mult. table) (t_VEC). *** at top-level: algisassociative([matid(2),Mat([1,1])]) *** ^--------------------------------------- *** algisassociative: incorrect type in algisassociative (mult. table) (t_VEC). *** at top-level: algisassociative([[1,2;3,4],matid(2)]) *** ^-------------------------------------- *** algisassociative: incorrect type in algisassociative (mult. table) (t_VEC). *** at top-level: algisassociative([matid(1)],[]) *** ^------------------------------- *** algisassociative: incorrect type in algisassociative (t_VEC). *** at top-level: algsqr(algtableinit([matid(1)]),[1,2]~) *** ^--------------------------------------- *** algsqr: incorrect type in alg_model (t_COL). *** at top-level: algsqr(al,vector(691)~) *** ^----------------------- *** algsqr: incorrect type in alg_model (t_COL). *** at top-level: algsqr(al,[1,2,3,4,5,6,7,f^2]~) *** ^------------------------------- *** algsqr: incorrect type in checkalgx (t_POL). *** at top-level: algsqr(al,[f^3,[]]~) *** ^-------------------- *** algsqr: incorrect type in checkalgx (t_VEC). *** at top-level: algmul(al,[;],[1,2]~) *** ^--------------------- *** algmul: incorrect type in algmul (t_COL). *** at top-level: algdivl(al,[;],matid(1)) *** ^------------------------ *** algdivl: impossible inverse in algdivl: [;]. *** at top-level: algdivl(al,matid(1),matrix(1,2)) *** ^-------------------------------- *** algdivl: inconsistent dimensions in algdivl (nonsquare). *** at top-level: alginv(al,[0,0]~) *** ^----------------- *** alginv: impossible inverse in alginv: [0, 0]~. *** at top-level: algalgtobasis(al0mt,[1]~) *** ^------------------------- *** algalgtobasis: incorrect type in algalgtobasis [use alginit] (t_VEC). *** at top-level: algbasistoalg(al0mt,[1]~) *** ^------------------------- *** algbasistoalg: incorrect type in algbasistoalg [use alginit] (t_VEC). *** at top-level: nfgrunwaldwang(nfinit(y),0,[],[],'x) *** ^------------------------------------ *** nfgrunwaldwang: incorrect type in nfgrunwaldwang (t_INT). *** at top-level: nfgrunwaldwang(nfinit(y),[2],'x-'x,[1]) *** ^--------------------------------------- *** nfgrunwaldwang: incorrect type in nfgrunwaldwang (t_POL). *** at top-level: alginit(rnfinit(nfinit(y),x),0) *** ^------------------------------- *** alginit: incorrect type in alginit (t_INT). *** at top-level: alginit(rnfinit(nfinit(y),x),[1,2,3,4]) *** ^--------------------------------------- *** alginit: incorrect type in alginit (t_VEC). *** at top-level: alginit(nfinit(y),[matid(2),matid(2)]) *** ^-------------------------------------- *** alginit: incorrect type in alg_csa_table (t_VEC). *** at top-level: alginit(nfinit(y),[matid(2),[0,1;1,0]]) *** ^--------------------------------------- *** alginit: domain error in alg_csa_table: (nonsquare) dimension != 1 *** at top-level: nfgrunwaldwang(nfinit(y),0,[],[0]) *** ^---------------------------------- *** nfgrunwaldwang: incorrect type in nfgrunwaldwang (t_INT). *** at top-level: nfgrunwaldwang(nfinit(y),[2],[],[0]) *** ^------------------------------------ *** nfgrunwaldwang: inconsistent dimensions in nfgrunwaldwang [#Lpr != #Ld]. *** at top-level: nfgrunwaldwang(nfinit(y),[2],[2],[]) *** ^------------------------------------ *** nfgrunwaldwang: domain error in nfgrunwaldwang [pl should have r1 components]: #pl != 1 *** at top-level: nfgrunwaldwang(nfinit(y),[2],[6],[0]) *** ^------------------------------------- *** nfgrunwaldwang: sorry, nfgrunwaldwang for non prime-power local degrees (a) is not yet implemented. *** at top-level: nfgrunwaldwang(nfinit(y),[2,3],[2,3],[0]) *** ^----------------------------------------- *** nfgrunwaldwang: sorry, nfgrunwaldwang for non prime-power local degrees (b) is not yet implemented. *** at top-level: nfgrunwaldwang(nfinit(y),[2],[3],[-1]) *** ^-------------------------------------- *** nfgrunwaldwang: sorry, nfgrunwaldwang for non prime-power local degrees (c) is not yet implemented. *** at top-level: nfgrunwaldwang(nfinit(y),[[]~],[3],[-1]) *** ^---------------------------------------- *** nfgrunwaldwang: incorrect type in checkprid (t_COL). *** at top-level: nfgrunwaldwang(nfinit(y),[2],[9],[0]) *** ^------------------------------------- *** nfgrunwaldwang: sorry, nfgrunwaldwang for non-prime degree is not yet implemented. *** at top-level: algdegree(A) *** ^------------ *** algdegree: incorrect type in alg_get_degree [use alginit] (t_VEC). *** at top-level: algsub(A,1,1) *** ^------------- *** algsub: incorrect type in alg_model (t_INT). *** at top-level: algadd(A,1,1) *** ^------------- *** algadd: incorrect type in alg_model (t_INT). *** at top-level: algneg(A,1) *** ^----------- *** algneg: incorrect type in alg_model (t_INT). *** at top-level: algmul(A,1,1) *** ^------------- *** algmul: incorrect type in alg_model (t_INT). *** at top-level: algsqr(A,1) *** ^----------- *** algsqr: incorrect type in alg_model (t_INT). *** at top-level: algdivl(A,1,1) *** ^-------------- *** algdivl: incorrect type in alg_model (t_INT). *** at top-level: algdivr(A,1,1) *** ^-------------- *** algdivr: incorrect type in alg_model (t_INT). *** at top-level: alginv(A,1) *** ^----------- *** alginv: incorrect type in alg_model (t_INT). *** at top-level: ...;PR=idealprimedec(K,2);A=alginit(K,[3,[PR,[1]] *** ^--------------------- *** alginit: domain error in checkhasse: Hasse invariant at real place [must be 0 or 1/2] != 0 *** at top-level: ...;P3=idealprimedec(K,3);A=alginit(K,[3,[concat( *** ^--------------------- *** alginit: domain error in checkhasse: Hasse invariant at real place [must be 0 or 1/2] != 0 *** at top-level: algtensor(alginit(nfinit(y),2),alginit(nfinit( *** ^---------------------------------------------- *** algtensor: inconsistent tensor product [not the same center] t_VEC (11 elts) , t_VEC (11 elts). *** at top-level: algtensor(alginit(nfinit(y),2),alginit(nfinit( *** ^---------------------------------------------- *** algtensor: sorry, tensor of cylic algebras of non-coprime degrees is not yet implemented. *** at top-level: alginit(nf,[2,[[p2,p2],[1/2,1/2]],[0]]) *** ^--------------------------------------- *** alginit: error in checkhasse [duplicate prime ideal]. *** at top-level: alginit(nf,[2,[[p2,p3],[1/2,1/2]],[0,0]]) *** ^----------------------------------------- *** alginit: domain error in checkhasse [hi should have r1 components]: #hi != 1 *** at top-level: alginit(nf,[2,[[p2,p3],[1/2,1/2],0],[0]]) *** ^----------------------------------------- *** alginit: incorrect type in Hasse invariant (t_VEC). *** at top-level: alginit(nf,[2,[0,[1/2,1/2]],[0]]) *** ^--------------------------------- *** alginit: incorrect type in Hasse invariant (t_VEC). *** at top-level: alginit(nf,[2,[[p2,p3],0],[0]]) *** ^------------------------------- *** alginit: incorrect type in Hasse invariant (t_INT). *** at top-level: alginit(nf,[2,[[p2,p3],[1/2,1/2,0]],[0]]) *** ^----------------------------------------- *** alginit: inconsistent dimensions in checkhasse [Lpr and Lh should have same length]. *** at top-level: alginit(nf,[2,[[p2,p3],[1/2,1/2]],[1/3]]) *** ^----------------------------------------- *** alginit: domain error in hasseconvert [degree should be a denominator of the invariant]: denom(h) ndiv 2 *** at top-level: algcharpoly(al,a,'z) *** ^-------------------- *** algcharpoly: incorrect priority in algredcharpoly: variable z >= y *** at top-level: algcharpoly(al,[1,2,3]~) *** ^------------------------ *** algcharpoly: incorrect type in alg_model (t_COL). *** at top-level: algindex(1,1) *** ^------------- *** algindex: incorrect type in checkalg [please apply alginit()] (t_INT). *** at top-level: algsqr(al,[Mod(1,y),Mod(2,y)]~) *** ^------------------------------- *** algsqr: incorrect type in alg_model (t_COL). *** at top-level: algsqr(al,[Mod(1,y),Mod(2,y)]~) *** ^------------------------------- *** algsqr: incorrect type in alg_model (t_COL). *** at top-level: alfail=alginit(nf,[0,0],'x) *** ^-------------------- *** alginit: domain error in rnfequation: issquarefree(B) = 0 *** at top-level: algb(al) *** ^-------- *** algb: incorrect type in alg_get_b [non-cyclic algebra] (t_VEC). *** at top-level: algaut(al) *** ^---------- *** algaut: incorrect type in alg_get_aut [non-cyclic algebra] (t_VEC). *** at top-level: algtableinit([Mat(1)],1) *** ^------------------------ *** algtableinit: not a prime number in algtableinit: 1. *** at top-level: algtableinit([Mat(1)],4) *** ^------------------------ *** algtableinit: not a prime number in algtableinit: 4. *** at top-level: algpoleval(al,x+1,"toto") *** ^------------------------- *** algpoleval: incorrect type in alg_model (t_STR). *** at top-level: algpoleval(al,x+1,[1,2,3]) *** ^-------------------------- *** algpoleval: incorrect type in algpoleval [vector must be of length 2] (t_VEC). *** at top-level: algpoleval(al,x+1,[1,2]) *** ^------------------------ *** algpoleval: incorrect type in algpoleval [mx must be the multiplication table of x] (t_INT). *** at top-level: algpoleval(al,x+1,[a,mb]) *** ^------------------------- *** algpoleval: incorrect type in algpoleval [mx must be the multiplication table of x] (t_MAT). *** at top-level: algpoleval(al,x+1,[1,mb]) *** ^------------------------- *** algpoleval: incorrect type in algpoleval [mx must be the multiplication table of x] (t_MAT). *** at top-level: alginit(nfinit(y),["a",[[],[]],[]]) *** ^----------------------------------- *** alginit: incorrect type in alginit [degree should be an integer] (t_STR). *** at top-level: alginit(nfinit(y),[1,[[],[]],[]]) *** ^--------------------------------- *** alginit: domain error in alg_hasse: degree <= 1 *** at top-level: alginit(nfinit(y),[0,[[],[]],[]]) *** ^--------------------------------- *** alginit: domain error in alg_hasse: degree <= 1 new algsimpledec 0 [0, [[[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]], Mat([1, 1, 0]), [0; 1; 0]], [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]], Mat([1, 0 , 0]), [1; -1; -1]], [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]], Mat([1, 0, 1]), [0; 0; 1]]]] 0 [0, [[[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 5, [1]], Mat([1, 1, 0]), [0; 1; 0]], [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 5, [1]], Mat([1, 0 , 1]), [0; 0; 1]], [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 5, [1]], Ma t([1, 0, 0]), [1; 4; 4]]]] [[0; 0; 1], [[[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]], Mat([1, 0, 0]), [1; -1; 0]], [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 0, [1]], Mat([1, 1, 0]), [0; 1; 0]]]] [[0; 0; 1], [[[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 5, [1]], Mat([1, 1, 0]), [0; 1; 0]], [[0, 0, 0, 0, 0, 0, Mat(1), Mat(1), [Mat(1)], 5, [1]], M at([1, 0, 0]), [1; 4; 0]]]] norm(,1) 16 Mod(-y + 1, y^2 - 5) 16 16/6561 223225143999841/5764801 1 1 trace(,1) Mod(2*y + 2, y^2 - 5) 8 8 1 1 1 1 charpoly(,1) x^2 - 2*y*x - 4*y x^8 - 40*x^6 - 160*x^5 + 240*x^4 + 3200*x^3 + 9600*x^2 + 12800*x + 6400 x^8 - 40*x^6 - 160*x^5 + 240*x^4 + 3200*x^3 + 9600*x^2 + 12800*x + 6400 1 1 1 more al_MAT tests add 1 1 1 1 alg/basis 1 1 1 1 1 1 1 1 charpoly 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 inv/div 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 mul 1 1 1 neg 1 1 1 norm 1 1 1 pow 1 1 1 sqr 1 1 1 sub 1 1 1 trace 1 1 1 algtomatrix 1 1 1 1 1 1 1 1 algleftmultable 1 1 1 1 1 1 1 1 1 1 1 1 more al_CSA tests 1 1 1 1 charpoly 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 inv/div 1 1 1 1 1 1 1 1 mul 1 1 1 neg 1 1 1 norm 1 1 1 pow 1 1 1 sqr 1 1 1 sub 1 1 1 trace 1 1 1 algtomatrix 1 1 1 1 1 1 1 1 algleftmultable 1 1 1 1 1 1 1 1 1 1 csa pol/polmod bugs [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, -1, 0, 0; 1, 0, 0, 0; 0, 0, 0, -1; 0, 0, 1, 0], [0, 0, y, 0; 0, 0, 0, -y; 1, 0, 0, 0; 0, -1, 0, 0 ], [0, 0, 0, y; 0, 0, y, 0; 0, 1, 0, 0; 1, 0, 0, 0]] [Mod(1000/9*y + 4400/81, y^2 - 5), Mod(1000/9*y, y^2 - 5), Mod(1000/9*y, y^2 - 5), Mod(1000/27*y, y^2 - 5)]~ [Mod(927/1936*y + 2025/1936, y^2 - 5), Mod(-729/1936*y - 8343/9680, y^2 - 5) , Mod(-729/1936*y - 8343/9680, y^2 - 5), Mod(-243/1936*y - 2781/9680, y^2 - 5)]~ [Mod(50/9*y, y^2 - 5), Mod(10, y^2 - 5), Mod(10, y^2 - 5), Mod(10/3, y^2 - 5 )]~ 1 1 1 1 1 1 1 csa: denom over Z[y] but not over ZK [[1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1], [0, -1, 0, 0; 1, 0, 0, 0; 0, 0, 0, -1; 0, 0, 1, 0], [0, 0, 1/2*y - 1/2, 0; 0, 0, 0, -1/2*y + 1/2; 1, 0, 0, 0; 0, -1, 0, 0], [0, 0, 0, 1/2*y - 1/2; 0, 0, 1/2*y - 1/2, 0; 0, 1, 0, 0; 1, 0, 0, 0]] *** at top-level: al=alginit(nf,mt*Mod(1,nf.pol)) *** ^---------------------------- *** alginit: domain error in alg_csa_table: denominator(mt) != 1 al_MAT over al_CSA 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 algleftmultable 1 1 1 1 1 1 nfgrunwaldwang SEGV #1669 x^2 + Mod(-17, y) *** at top-level: nfgrunwaldwang(nfinit(x),[2,3],[1,2],Vecsmall( *** ^---------------------------------------------- *** nfgrunwaldwang: incorrect priority in nfgrunwaldwang: variable x >= x [1] [1] [1] [1/2] [1/2] 1 *** at top-level: algpoleval(al,pol,a)==0 *** ^----------------------- *** algpoleval: sorry, algpoleval with x in basis form and pol not in Q[x] is not yet implemented. *** at top-level: algpoleval(al,pol,[;]) *** ^---------------------- *** algpoleval: incorrect type in algpoleval (t_MAT). 1 1 *** at top-level: al2=algtensor(al,al) *** ^---------------- *** algtensor: sorry, tensor of non-cyclic algebras is not yet implemented. *** at top-level: al2=algtensor(al,al) *** ^---------------- *** algtensor: sorry, tensor of non-cyclic algebras is not yet implemented. Total time spent: 1300 pari-2.11.2/src/test/32/objets0000644000175000017500000000416513326135265014375 0ustar billbill echo = 1 ? +3 3 ? -5 -5 ? 5+3 8 ? 5-3 2 ? 5/3 5/3 ? 5\3 1 ? 5\/3 2 ? 5%3 2 ? 5^3 125 ? binary(65537) [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] ? bittest(10^100,100) 1 ? ceil(-2.5) -2 ? centerlift(Mod(456,555)) -99 ? component(1+O(7^4),3) 1 ? conj(1+I) 1 - I ? conjvec(Mod(x^2+x+1,x^3-x-1)) [4.0795956234914387860104177508366260326, 0.46020218825428060699479112458168 698369 + 0.18258225455744299269398828369501930574*I, 0.460202188254280606994 79112458168698369 - 0.18258225455744299269398828369501930574*I]~ ? truncate(1.7,&e) 1 ? e -1 ? denominator(12345/54321) 18107 ? divrem(345,123) [2, 99]~ ? divrem(x^7-1,x^5+1) [x^2, -x^2 - 1]~ ? floor(-1/2) -1 ? floor(-2.5) -3 ? frac(-2.7) 0.30000000000000000000000000000000000000 ? I^2 -1 ? imag(2+3*I) 3 ? lex([1,3],[1,3,5]) -1 ? max(2,3) 3 ? min(2,3) 2 ? Mod(-12,7) Mod(2, 7) ? norm(1+I) 2 ? norm(Mod(x+5,x^3+x+1)) 129 ? numerator((x+1)/(x-1)) x + 1 ? 1/(1+x)+O(x^20) 1 - x + x^2 - x^3 + x^4 - x^5 + x^6 - x^7 + x^8 - x^9 + x^10 - x^11 + x^12 - x^13 + x^14 - x^15 + x^16 - x^17 + x^18 - x^19 + O(x^20) ? numtoperm(7,1035) Vecsmall([2, 4, 6, 1, 5, 7, 3]) ? permtonum([4,7,1,6,3,5,2]) 2781 ? 37. 37.000000000000000000000000000000000000 ? real(5-7*I) 5 ? shift(1,50) 1125899906842624 ? shift([3,4,-11,-12],-2) [0, 1, -2, -3] ? shiftmul([3,4,-11,-12],-2) [3/4, 1, -11/4, -3] ? sign(-1) -1 ? sign(0) 0 ? sign(0.) 0 ? simplify(((x+I+1)^2-x^2-2*x*(I+1))^2) -4 ? sizedigit([1.3*10^5,2*I*Pi*exp(4*Pi)]) 7 ? truncate(-2.7) -2 ? truncate(sin(x^2)) -1/5040*x^14 + 1/120*x^10 - 1/6*x^6 + x^2 ? type(Mod(x,x^2+1)) "t_POLMOD" ? valuation(6^10000-1,5) 5 ? \p57 realprecision = 57 significant digits ? Pi 3.14159265358979323846264338327950288419716939937510582098 ? \p38 realprecision = 38 significant digits ? O(x^12) O(x^12) ? padicno=(5/3)*127+O(127^5) 44*127 + 42*127^2 + 42*127^3 + 42*127^4 + O(127^5) ? padicprec(padicno,127) 5 ? length(divisors(1000)) 16 ? Mod(10873,49649)^-1 *** at top-level: Mod(10873,49649)^-1 *** ^--- *** _^_: impossible inverse in Fp_inv: Mod(131, 49649). ? (1+I)*(1+1/2*I) 1/2 + 3/2*I ? print("Total time spent: ",gettime); Total time spent: 1 pari-2.11.2/src/test/32/ispower0000644000175000017500000002677613457566441014624 0ustar billbill[101, 6] [5, 2160] [3, 21218] [5, 21218] [5, 84872] [21, 21218] [35, 21218] [105, 21218] [100003, 103] [121, 541] [2, 2] [3, 2] [2, 3] [4, 2] [2, 5] [3, 3] [5, 2] [2, 6] [2, 7] [6, 2] [4, 3] [2, 10] [2, 11] [3, 5] [7, 2] [2, 12] [2, 13] [2, 14] [3, 6] [2, 15] [5, 3] [8, 2] [2, 17] [2, 18] [3, 7] [2, 19] [2, 20] [2, 21] [2, 22] [9, 2] [2, 23] [2, 24] [4, 5] [2, 26] [6, 3] [2, 28] [2, 29] [2, 30] [2, 31] [3, 10] [10, 2] [2, 33] [2, 34] [2, 35] [4, 6] [3, 11] [2, 37] [2, 38] [2, 39] [2, 40] [2, 41] [3, 12] [2, 42] [2, 43] [2, 44] [2, 45] [11, 2] [2, 46] [7, 3] [3, 13] [2, 47] [2, 48] [4, 7] [2, 50] [2, 51] [2, 52] [3, 14] [2, 53] [2, 54] [2, 55] [5, 5] [2, 56] [2, 57] [2, 58] [3, 15] [2, 59] [2, 60] [2, 61] [2, 62] [2, 63] [12, 2] [2, 65] [2, 66] [2, 67] [2, 68] [2, 69] [2, 70] [3, 17] [2, 71] [2, 72] [2, 73] [2, 74] [2, 75] [2, 76] [3, 18] [2, 77] [2, 78] [2, 79] [2, 80] [8, 3] [2, 82] [3, 19] [2, 83] [2, 84] [2, 85] [2, 86] [2, 87] [2, 88] [5, 6] [2, 89] [3, 20] [2, 90] [13, 2] [2, 91] [2, 92] [2, 93] [2, 94] [2, 95] [2, 96] [3, 21] [2, 97] [2, 98] [2, 99] [4, 10] [2, 101] [2, 102] [2, 103] [3, 22] [2, 104] [2, 105] [2, 106] [2, 107] [2, 108] [2, 109] [2, 110] [3, 23] [2, 111] [2, 112] [2, 113] [2, 114] [2, 115] [2, 116] [2, 117] [3, 24] [2, 118] [2, 119] [2, 120] [4, 11] [2, 122] [2, 123] [2, 124] [6, 5] [2, 126] [2, 127] [14, 2] [2, 129] [5, 7] [2, 130] [2, 131] [2, 132] [3, 26] [2, 133] [2, 134] [2, 135] [2, 136] [2, 137] [2, 138] [2, 139] [2, 140] [9, 3] [2, 141] [2, 142] [2, 143] [4, 12] [2, 145] [2, 146] [2, 147] [2, 148] [3, 28] [2, 149] [2, 150] [2, 151] [2, 152] [2, 153] [2, 154] [2, 155] [2, 156] [3, 29] [2, 157] [2, 158] [2, 159] [2, 160] [2, 161] [2, 162] [2, 163] [2, 164] [3, 30] [2, 165] [2, 166] [2, 167] [2, 168] [4, 13] [2, 170] [2, 171] [2, 172] [3, 31] [2, 173] [2, 174] [2, 175] [2, 176] [2, 177] [2, 178] [2, 179] [2, 180] [2, 181] [15, 2] [2, 182] [2, 183] [2, 184] [2, 185] [2, 186] [2, 187] [2, 188] [2, 189] [3, 33] [2, 190] [2, 191] [2, 192] [2, 193] [2, 194] [2, 195] [4, 14] [2, 197] [2, 198] [3, 34] [2, 199] [2, 200] [2, 201] [2, 202] [2, 203] [2, 204] [2, 205] [2, 206] [2, 207] [3, 35] [2, 208] [2, 209] [2, 210] [2, 211] [2, 212] [2, 213] [2, 214] [2, 215] [6, 6] [2, 217] [2, 218] [2, 219] [2, 220] [2, 221] [2, 222] [2, 223] [2, 224] [4, 15] [3, 37] [2, 226] [2, 227] [2, 228] [2, 229] [2, 230] [2, 231] [2, 232] [2, 233] [2, 234] [3, 38] [2, 235] [2, 236] [2, 237] [2, 238] [2, 239] [2, 240] [2, 241] [2, 242] [10, 3] [3, 39] [2, 244] [2, 245] [2, 246] [2, 247] [2, 248] [2, 249] [2, 250] [2, 251] [2, 252] [3, 40] [2, 253] [2, 254] [2, 255] [16, 2] [2, 257] [2, 258] [2, 259] [2, 260] [2, 261] [2, 262] [3, 41] [2, 263] [2, 264] [2, 265] [2, 266] [2, 267] [2, 268] [2, 269] [2, 270] [2, 271] [2, 272] [3, 42] [2, 273] [2, 274] [2, 275] [2, 276] [2, 277] [2, 278] [2, 279] [7, 5] [2, 280] [2, 281] [3, 43] [2, 282] [2, 283] [2, 284] [2, 285] [2, 286] [2, 287] [2, 288] [4, 17] [2, 290] [2, 291] [3, 44] [2, 292] [2, 293] [2, 294] [2, 295] [2, 296] [2, 297] [2, 298] [2, 299] [2, 300] [2, 301] [3, 45] [2, 302] [2, 303] [2, 304] [2, 305] [2, 306] [2, 307] [2, 308] [2, 309] [2, 310] [2, 311] [3, 46] [2, 312] [2, 313] [2, 314] [2, 315] [2, 316] [5, 10] [2, 317] [2, 318] [2, 319] [2, 320] [2, 321] [2, 322] [3, 47] [2, 323] [4, 18] [2, 325] [2, 326] [2, 327] [2, 328] [2, 329] [2, 330] [2, 331] [2, 332] [3, 48] [2, 333] [2, 334] [2, 335] [2, 336] [2, 337] [2, 338] [2, 339] [2, 340] [2, 341] [2, 342] [6, 7] [2, 344] [2, 345] [2, 346] [2, 347] [2, 348] [2, 349] [2, 350] [2, 351] [2, 352] [2, 353] [3, 50] [2, 354] [2, 355] [2, 356] [2, 357] [2, 358] [2, 359] [2, 360] [4, 19] [2, 362] [17, 2] [2, 363] [2, 364] [3, 51] [2, 365] [2, 366] [2, 367] [2, 368] [2, 369] [2, 370] [2, 371] [2, 372] [2, 373] [2, 374] [3, 52] [2, 375] [2, 376] [2, 377] [2, 378] [2, 379] [2, 380] [2, 381] [2, 382] [2, 383] [2, 384] [2, 385] [3, 53] [2, 386] [2, 387] [2, 388] [2, 389] [2, 390] [2, 391] [2, 392] [2, 393] [2, 394] [2, 395] [2, 396] [3, 54] [2, 397] [2, 398] [2, 399] [4, 20] [2, 401] [5, 11] [2, 402] [2, 403] [2, 404] [2, 405] [2, 406] [2, 407] [3, 55] [2, 408] [2, 409] [2, 410] [2, 411] [2, 412] [2, 413] [2, 414] [2, 415] [2, 416] [2, 417] [2, 418] [2, 419] [3, 56] [2, 420] [11, 3] [2, 421] [2, 422] [2, 423] [2, 424] [2, 425] [2, 426] [2, 427] [2, 428] [2, 429] [2, 430] [3, 57] [2, 431] [2, 432] [2, 433] [2, 434] [2, 435] [2, 436] [2, 437] [2, 438] [2, 439] [2, 440] [4, 21] [3, 58] [2, 442] [2, 443] [2, 444] [2, 445] [2, 446] [2, 447] [2, 448] [2, 449] [2, 450] [2, 451] [2, 452] [2, 453] [3, 59] [2, 454] [2, 455] [2, 456] [2, 457] [2, 458] [2, 459] [2, 460] [2, 461] [2, 462] [2, 463] [2, 464] [3, 60] [2, 465] [2, 466] [2, 467] [2, 468] [2, 469] [2, 470] [2, 471] [2, 472] [2, 473] [2, 474] [2, 475] [2, 476] [3, 61] [2, 477] [2, 478] [2, 479] [2, 480] [2, 481] [2, 482] [2, 483] [4, 22] [2, 485] [2, 486] [2, 487] [2, 488] [3, 62] [2, 489] [2, 490] [2, 491] [2, 492] [2, 493] [2, 494] [2, 495] [2, 496] [2, 497] [2, 498] [5, 12] [2, 499] [2, 500] [3, 63] [2, 501] [2, 502] [2, 503] [2, 504] [2, 505] [2, 506] [2, 507] [2, 508] [2, 509] [2, 510] [2, 511] [18, 2] [2, 513] [2, 514] [2, 515] [2, 516] [2, 517] [2, 518] [2, 519] [2, 520] [2, 521] [2, 522] [2, 523] [2, 524] [3, 65] [2, 525] [2, 526] [2, 527] [2, 528] [4, 23] [7, 6] [2, 530] [2, 531] [2, 532] [2, 533] [2, 534] [2, 535] [2, 536] [3, 66] [2, 537] [2, 538] [2, 539] [2, 540] [2, 541] [2, 542] [2, 543] [2, 544] [2, 545] [2, 546] [2, 547] [2, 548] [3, 67] [2, 549] [2, 550] [2, 551] [2, 552] [2, 553] [2, 554] [2, 555] [2, 556] [2, 557] [2, 558] [2, 559] [2, 560] [3, 68] [2, 561] [2, 562] [2, 563] [2, 564] [2, 565] [2, 566] [2, 567] [2, 568] [2, 569] [2, 570] [2, 571] [2, 572] [2, 573] [3, 69] [2, 574] [2, 575] [4, 24] [2, 577] [2, 578] [2, 579] [2, 580] [2, 581] [2, 582] [2, 583] [2, 584] [2, 585] [3, 70] [2, 586] [2, 587] [2, 588] [2, 589] [2, 590] [2, 591] [2, 592] [2, 593] [2, 594] [2, 595] [2, 596] [2, 597] [2, 598] [3, 71] [2, 599] [2, 600] [2, 601] [2, 602] [2, 603] [2, 604] [2, 605] [2, 606] [2, 607] [2, 608] [2, 609] [5, 13] [2, 610] [3, 72] [2, 611] [2, 612] [2, 613] [2, 614] [2, 615] [2, 616] [2, 617] [2, 618] [2, 619] [2, 620] [2, 621] [2, 622] [2, 623] [3, 73] [2, 624] [8, 5] [2, 626] [2, 627] [2, 628] [2, 629] [2, 630] [2, 631] [2, 632] [2, 633] [2, 634] [2, 635] [2, 636] [3, 74] [2, 637] [2, 638] [2, 639] [2, 640] [2, 641] [2, 642] [2, 643] [2, 644] [2, 645] [2, 646] [2, 647] [2, 648] [2, 649] [3, 75] [2, 650] [2, 651] [2, 652] [2, 653] [2, 654] [2, 655] [2, 656] [2, 657] [2, 658] [2, 659] [2, 660] [2, 661] [2, 662] [3, 76] [2, 663] [2, 664] [2, 665] [2, 666] [2, 667] [2, 668] [2, 669] [2, 670] [2, 671] [2, 672] [2, 673] [2, 674] [2, 675] [3, 77] [4, 26] [2, 677] [2, 678] [2, 679] [2, 680] [2, 681] [2, 682] [2, 683] [2, 684] [2, 685] [2, 686] [2, 687] [2, 688] [3, 78] [2, 689] [2, 690] [2, 691] [2, 692] [2, 693] [2, 694] [2, 695] [2, 696] [2, 697] [2, 698] [2, 699] [2, 700] [2, 701] [2, 702] [3, 79] [2, 703] [2, 704] [2, 705] [2, 706] [2, 707] [2, 708] [2, 709] [2, 710] [2, 711] [2, 712] [2, 713] [2, 714] [2, 715] [3, 80] [2, 716] [2, 717] [2, 718] [2, 719] [2, 720] [2, 721] [2, 722] [2, 723] [2, 724] [19, 2] [2, 725] [2, 726] [2, 727] [2, 728] [12, 3] [2, 730] [2, 731] [2, 732] [2, 733] [5, 14] [2, 734] [2, 735] [2, 736] [2, 737] [2, 738] [2, 739] [2, 740] [2, 741] [2, 742] [3, 82] [2, 743] [2, 744] [2, 745] [2, 746] [2, 747] [2, 748] [2, 749] [2, 750] [2, 751] [2, 752] [2, 753] [2, 754] [2, 755] [2, 756] [3, 83] [2, 757] [2, 758] [2, 759] [2, 760] [2, 761] [2, 762] [2, 763] [2, 764] [2, 765] [2, 766] [2, 767] [2, 768] [2, 769] [3, 84] [2, 770] [2, 771] [2, 772] [2, 773] [2, 774] [2, 775] [2, 776] [2, 777] [2, 778] [2, 779] [2, 780] [2, 781] [2, 782] [2, 783] [3, 85] [4, 28] [2, 785] [2, 786] [2, 787] [2, 788] [2, 789] [2, 790] [2, 791] [2, 792] [2, 793] [2, 794] [2, 795] [2, 796] [2, 797] [3, 86] [2, 798] [2, 799] [2, 800] [2, 801] [2, 802] [2, 803] [2, 804] [2, 805] [2, 806] [2, 807] [2, 808] [2, 809] [2, 810] [2, 811] [3, 87] [2, 812] [2, 813] [2, 814] [2, 815] [2, 816] [2, 817] [2, 818] [2, 819] [2, 820] [2, 821] [2, 822] [2, 823] [2, 824] [2, 825] [3, 88] [2, 826] [2, 827] [2, 828] [2, 829] [2, 830] [2, 831] [2, 832] [2, 833] [2, 834] [2, 835] [2, 836] [2, 837] [2, 838] [2, 839] [3, 89] [2, 840] [4, 29] [2, 842] [2, 843] [2, 844] [2, 845] [2, 846] [2, 847] [2, 848] [2, 849] [2, 850] [2, 851] [2, 852] [2, 853] [3, 90] [2, 854] [2, 855] [2, 856] [2, 857] [2, 858] [2, 859] [2, 860] [2, 861] [2, 862] [2, 863] [2, 864] [2, 865] [2, 866] [2, 867] [2, 868] [3, 91] [2, 869] [2, 870] [2, 871] [5, 15] [2, 872] [2, 873] [2, 874] [2, 875] [2, 876] [2, 877] [2, 878] [2, 879] [2, 880] [2, 881] [2, 882] [3, 92] [2, 883] [2, 884] [2, 885] [2, 886] [2, 887] [2, 888] [2, 889] [2, 890] [2, 891] [2, 892] [2, 893] [2, 894] [2, 895] [2, 896] [3, 93] [2, 897] [2, 898] [2, 899] [4, 30] [2, 901] [2, 902] [2, 903] [2, 904] [2, 905] [2, 906] [2, 907] [7, 7] [2, 908] [2, 909] [2, 910] [2, 911] [3, 94] [2, 912] [2, 913] [2, 914] [2, 915] [2, 916] [2, 917] [2, 918] [2, 919] [2, 920] [2, 921] [2, 922] [2, 923] [2, 924] [2, 925] [3, 95] [2, 926] [2, 927] [2, 928] [2, 929] [2, 930] [2, 931] [2, 932] [2, 933] [2, 934] [2, 935] [2, 936] [2, 937] [2, 938] [2, 939] [2, 940] [3, 96] [2, 941] [2, 942] [2, 943] [2, 944] [2, 945] [2, 946] [2, 947] [2, 948] [2, 949] [2, 950] [2, 951] [2, 952] [2, 953] [2, 954] [2, 955] [3, 97] [2, 956] [2, 957] [2, 958] [2, 959] [2, 960] [4, 31] [2, 962] [2, 963] [2, 964] [2, 965] [2, 966] [2, 967] [2, 968] [2, 969] [2, 970] [3, 98] [2, 971] [2, 972] [2, 973] [2, 974] [2, 975] [2, 976] [2, 977] [2, 978] [2, 979] [2, 980] [2, 981] [2, 982] [2, 983] [2, 984] [2, 985] [3, 99] [2, 986] [2, 987] [2, 988] [2, 989] [2, 990] [2, 991] [2, 992] [2, 993] [2, 994] [2, 995] [2, 996] [2, 997] [2, 998] [2, 999] [6, 10] [3, -4] [3, -2] [3, -21218] [3, -1/4] 0 0 3 1 [1431, 5737585] [1278, 6780590] [983, 36262840] [508, 2044406843184] [274, 3873816255479006870044] [228, 34028236692093846346337460743176821665314] 10 10 1267650600228229401496703205653 121 1 [0, 0, 1, 0] [0, 0, 0, 0] [0, 0, Mod(735321672858813933, 1000039000207000297), 0] [0, 0, 0, 0] [Mod(766696600158900228, 1000039000207000297), Mod(9366110197497040718447998 65730, 1000113004462069006305361406593), Mod(6, 1000039000207000297), Mod(30 66786400635600912, 8000312001656002376)] [Mod(761273567620851421, 1000039000207000297), Mod(6350198471236493446056154 0863, 1000113004462069006305361406593), Mod(542283254184885017, 100003900020 7000297), Mod(4933525601020401464, 8000312001656002376)] Mod(583, 875) 1 Mod(0, 2) 0 0 1 Mod(Mod(1, 2)*y^2 + Mod(1, 2)*y + Mod(1, 2), Mod(1, 2)*y^3 + Mod(1, 2)*y^2 + Mod(1, 2)) 0 Mod(Mod(2, 5)*y^2 + Mod(4, 5), Mod(1, 5)*y^3 + Mod(1, 5)*y^2 + Mod(1, 5)) Mod(2, 5) 0 1 0 1 1 y 0 1 Mod(1, 2)*x + Mod(1, 2) t*x^2 + (t + 1)*x + 1 Mod(1, 5)*x^2 + Mod(3, 5)*x + Mod(2, 5) 2/x 1 1.2247448713915890490986420373529456960 1 0 1 1 t^2 + t + 1 1 0 1 1 1/2 x + 1/2 1/2 1 *** at top-level: issquare(Mod(1,4)*(x+1)^2) *** ^-------------------------- *** issquare: sorry, issquare for even characteristic != 2 is not yet implemented. 0 0 -2 1 -2/3 1 0 0 0 2 x + 2 0 11 1 1 1/(2*x) 1 + 1/3*x + O(x^2) -2/3 121 121 187 1 5 51 [0, 1, 1, 1, 1, 1] [0, 1, 1, 1, 1, 1] [0, 1, 1, 1, 1, 1] [0, 1, 1, 1, 1, 1] [0, 1, 1, 1, 1, 1] [0, 1, 1, 1, 1, 1] [0, 1, 1, 1, 1, 1] [0, 1, 1, 1, 1, 1] *** at top-level: ispower(Mod(x,x^2+1),2,&y) *** ^-------------------------- *** ispower: sorry, ispower for general t_POLMOD is not yet implemented. *** at top-level: ispower(Mod(x,x^2+1),2) *** ^----------------------- *** ispower: sorry, ispower for general t_POLMOD is not yet implemented. 11 29 101 1 Total time spent: 3174 pari-2.11.2/src/test/32/gamma0000644000175000017500000001570313272130645014166 0ustar billbill(0.65296549642016672783864624794608469715 + 0.343065839816545357588735986978 31148676*I) + (0.19044897540645184469078131473790885364 + 0.5805524673194769 2349794265298068695525*I)*x + (0.090862784286733058570355592072096462602 + 0 .21088392899265350361451872767550590408*I)*x^2 + (0.034253752000523576920016 074597694397590 + 0.15168994440796279268955277197772465641*I)*x^3 + (-0.0093 139210540785894159197859484392067432 + 0.03306465179643991397682862055127742 8299*I)*x^4 + (0.0066762623841895560506752315759505427095 + 0.01516404667566 6586697065188398143396917*I)*x^5 + O(x^6) 1 - 0.57721566490153286060651209008240243104*x + 0.9890559953279725553953956 5150063470794*x^2 - 0.90747907608088628901656016735627511493*x^3 + 0.9817280 8683440018733638029402185085036*x^4 - 0.981995068903145202104701413791374675 51*x^5 + O(x^6) 1 + 0.42278433509846713939348790991759756896*x + 0.4118403304264396947888835 6141823227689*x^2 + 0.081576919247086266378835484144359593009*x^3 + 0.074249 010753513898319820126665575735431*x^4 - 0.0002669820687450147683211197695238 2515602*x^5 + O(x^6) 0.50000000000000000000000000000000000000*x^-1 + 0.46139216754923356969674395 495879878448 + 0.93661624898783663224281375818851553069*x + 0.72048875166669 501900756857612523634633*x^2 + 1.1032890464233243060581361321045221793*x^3 + O(x^4) (-0.30434960902188368417660077077485938103 + 0.48375784292991511172812918802 297918039*I) + (0.59465032062247697727187848272191072247 + 0.576674047468581 17413405079475000049045*I)*x + (0.23150004831138189314916325909209289721 - 0 .14711677137965943279150680857845149795*I)*x^2 + (-0.02190784473534413804389 4242836567535805 + 0.044442141724177702067115896271895013565*I)*x^3 + (-0.00 095310203972899907556180572534221362410 - 0.01322027411091502743411636095975 8682565*I)*x^4 + (0.0023292347420337443292606199295988510753 + 0.00349489957 19835964464884744063791902941*I)*x^5 + O(x^6) -0.57721566490153286060651209008240243104*x + 0.8224670334241132182362075833 2301259461*x^2 - 0.40068563438653142846657938717048333025*x^3 + 0.2705808084 2778454787900092413529197569*x^4 - 0.20738555102867398526627309729140683361* x^5 + O(x^6) *** at top-level: lngamma(-2+x) *** ^------------- *** lngamma: domain error in intformal: residue(series, pole) != 0 0.42278433509846713939348790991759756896*x + 0.32246703342411321823620758332 301259461*x^2 - 0.067352301053198095133246053837149996921*x^3 + 0.0205808084 27784547879000924135291975694*x^4 - 0.00738555102867398526627309729140683361 08*x^5 + O(x^6) 0.E-38 0.E-38 (0.59465032062247697727187848272191072247 + 0.576674047468581174134050794750 00049045*I) + (0.46300009662276378629832651818418579441 - 0.2942335427593188 6558301361715690299591*I)*x + (-0.065723534206032414131682728509702607416 + 0.13332642517253310620134768881568504070*I)*x^2 + (-0.0038124081589159963022 472229013688544964 - 0.052881096443660109736465443839034730260*I)*x^3 + (0.0 11646173710168721646303099647994255377 + 0.017474497859917982232442372031895 951470*I)*x^4 + (-0.0077757069690405743408170730434310459472 - 0.00403456423 41327827815714280332882428196*I)*x^5 + O(x^6) -0.57721566490153286060651209008240243104 + 1.644934066848226436472415166646 0251892*x - 1.2020569031595942853997381615114499908*x^2 + 1.0823232337111381 915160036965411679028*x^3 - 1.0369277551433699263313654864570341681*x^4 + 1. 0173430619844491397145179297909205279*x^5 + O(x^6) -x^-1 + 0.92278433509846713939348790991759756896 + 2.89493406684822643647241 51666460251892*x - 0.077056903159594285399738161511449990762*x^2 + 2.1448232 337111381915160036965411679028*x^3 + O(x^4) -3.5449077018110320545963349666822903656 - 0.1293535897955400553154795370758 8123112*x - 15.838884621997332891305490359174586834*x^2 - 0.0882351409230713 74511750322744686276244*x^3 - 63.934119924167817737375290277713885431*x^4 - 0.042848354492868684268292005312709223076*x^5 + O(x^6) 1 - 0.57721566490153286060651209008240243104*a*x + O(x^2) -0.57721566490153286060651209008240243104*a*x + O(x^2) *** at top-level: gamma(O(x)) *** ^----------- *** gamma: domain error in gamma: argument = 0 *** at top-level: lngamma(O(x)) *** ^------------- *** lngamma: domain error in lngamma: argument = 0 *** at top-level: psi(O(x)) *** ^--------- *** psi: domain error in psi: argument = 0 *** gamma: Warning: normalizing a series with 0 leading term. 2*x^-1 + O(x^0) -x^-1 - 0.57721566490153286060651209008240243104 + 1.64493406684822643647241 51666460251892*x - 1.2020569031595942853997381615114499908*x^2 + 1.082323233 7111381915160036965411679028*x^3 - 1.0369277551433699263313654864570341681*x ^4 + 1.0173430619844491397145179297909205279*x^5 + O(x^6) x^-1 - 0.57721566490153286060651209008240243104 + 0.989055995327972555395395 65150063470794*x - 0.90747907608088628901656016735627511493*x^2 + 0.98172808 683440018733638029402185085036*x^3 - 0.9819950689031452021047014137913746755 1*x^4 + O(x^5) 4.0238726007709377354370243392300398572 E2564 277.25887222397812376689284858327062723 0.70315664064524318722569033366791109947 -x^-1 + O(x^0) 0.036489973978576520559023667001244432804 + 0.467401100272339654708622749969 03778383*x + O(x^2) x^-1 + O(x^0) 9999999999999999.5772156649015330017905 9999999999999999.4227843350984672382991 36.841361487904730902009429765103126607 - 6.28318530717958647692528676655900 57684*I 36.841361487904730886566296784796549486 170141183460469231740910675752738881536 1001.0000000000000000000000000000000000 8.4592930575197658134779513864578051837 E92 8.4592930575197658134779513864578051837 E92 + 417.27460269708707626917373711 782229398*I 799877009219260410589.21059353880333769 + 88.7228391116729996053515014380223 25492*I -864.73828787067971564321683481711497423 - 631.46012337154844093099132003918 007972*I 3.2007257594901922498857741835634344245 E867 3.0616681090421088936612867355651954590 E867 - 9.193770672812704213454512890 0883765323 E866*I 8459293057519765813477951386457805183660969095271154721136672171659780563637 16339197618169691.8420416798032146865778 + 417.27460269708707626917373711782 2293981451080884873662980649365715022960425756218794729722851598595227020005 2467288*I 8459293057519765813477951386457805183660969095271154721136672171659780563637 16339197618169691.8420416798032146865778 + 41727.460269708707626917373711782 2293981451080884873662980649365715022960425756218794729722851598595227020005 2467288*I 8459293057519765813477951386457805183660969095271154721136672171659780563637 16339197618169691.8420416798032146865778407117373385742831330551204346169684 432 + 417274.602697087076269173737117822293981451080884873662980649365715022 9604257562187947297228515985952270200052467287642139293693997776338197086953 142287383*I 0.99999999999999999999999999999942278433509846713939348790991858662495316863 6615471796845732492343995375856774526593328777198552545340369146294559716293 3800 -1000000.5772166539584356686368774405975327324364299837039157908236471064277 4207952925289528676019700485467432997942048345744111188601460149907155979685 1143 Total time spent: 20 pari-2.11.2/src/test/32/aurifeuille0000644000175000017500000000031311636712103015376 0ustar billbill2818034765526617919871 13851033738067865242961762796990508103341 2818034765526617919871 48975219025052205901 288943522443730350379346314566889 73194743542229 97 13 818201 13 1741 31 Total time spent: 16 pari-2.11.2/src/test/32/nfsign0000644000175000017500000000000013326135265014353 0ustar billbillpari-2.11.2/src/test/32/cyclo0000644000175000017500000000343513036414402014206 0ustar billbill *** Warning: new stack size = 8000000 (7.629 Mbytes). *** at top-level: poliscyclo(1) *** ^------------- *** poliscyclo: incorrect type in poliscyclo (t_INT). 0 0 100000 12345 [x - 1, x + 1] [x - 1, x^2 + x + 1] [x - 1, x^2 + 1] [x - 1, x^4 + x^3 + x^2 + x + 1] [x - 1, x^2 - x + 1] [x - 1, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1] [x - 1, x^4 + 1] [x - 1, x^6 + x^3 + 1] [x - 1, x^4 - x^3 + x^2 - x + 1] [x + 1, x^2 + x + 1] [x + 1, x^2 + 1] [x + 1, x^4 + x^3 + x^2 + x + 1] [x + 1, x^2 - x + 1] [x + 1, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1] [x + 1, x^4 + 1] [x + 1, x^6 + x^3 + 1] [x + 1, x^4 - x^3 + x^2 - x + 1] [x^2 + 1, x^2 + x + 1] [x^6 + 2*x^5 + 3*x^4 + 3*x^3 + 3*x^2 + 2*x + 1] [x^4 + x^2 + 1] [x^8 + 2*x^7 + 3*x^6 + 3*x^5 + 3*x^4 + 3*x^3 + 3*x^2 + 2*x + 1] [x^4 + 1, x^2 + x + 1] [x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1] [x^2 + x + 1, x^4 - x^3 + x^2 - x + 1] [x^2 + 1, x^4 + x^3 + x^2 + x + 1] [x^2 + 1, x^2 - x + 1] [x^2 + 1, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1] [x^2 + 1, x^4 + 1] [x^2 + 1, x^6 + x^3 + 1] [x^2 + 1, x^4 - x^3 + x^2 - x + 1] [x^4 + x^3 + x^2 + x + 1, x^2 - x + 1] [x^10 + 2*x^9 + 3*x^8 + 4*x^7 + 5*x^6 + 5*x^5 + 5*x^4 + 4*x^3 + 3*x^2 + 2*x + 1] [x^4 + 1, x^4 + x^3 + x^2 + x + 1] [x^10 + x^9 + x^8 + 2*x^7 + 2*x^6 + x^5 + 2*x^4 + 2*x^3 + x^2 + x + 1] [x^8 + x^6 + x^4 + x^2 + 1] [x^6 + x^5 + x^4 + x^3 + x^2 + x + 1, x^2 - x + 1] [x^4 + 1, x^2 - x + 1] [x^6 + x^3 + 1, x^2 - x + 1] [x^6 - 2*x^5 + 3*x^4 - 3*x^3 + 3*x^2 - 2*x + 1] [x^4 + 1, x^6 + x^5 + x^4 + x^3 + x^2 + x + 1] [x^12 + x^11 + x^10 + 2*x^9 + 2*x^8 + 2*x^7 + 3*x^6 + 2*x^5 + 2*x^4 + 2*x^3 + x^2 + x + 1] [x^6 + x^5 + x^4 + x^3 + x^2 + x + 1, x^4 - x^3 + x^2 - x + 1] [x^4 + 1, x^6 + x^3 + 1] [x^4 + 1, x^4 - x^3 + x^2 - x + 1] [x^6 + x^3 + 1, x^4 - x^3 + x^2 - x + 1] 1 1 Total time spent: 532 pari-2.11.2/src/test/32/characteristic0000644000175000017500000000064013326135265016071 0ustar billbill0 0 6 0 3 0 3 0 3 2 0 0 2 *** at top-level: characteristic([ffgen(2),ffgen(3)]) *** ^----------------------------------- *** characteristic: inconsistent moduli in characteristic: 2 != 3 *** at top-level: characteristic([ffgen(2),Mod(1,3)]) *** ^----------------------------------- *** characteristic: inconsistent moduli in characteristic: 2 != 3 Total time spent: 0 pari-2.11.2/src/test/32/polred0000644000175000017500000001122613326135265014370 0ustar billbillx^7 + Mod(7*y - 7, y^2 - y - 1)*x^6 + Mod(-21*y + 28, y^2 - y - 1)*x^5 - 35* x^4 + Mod(35*y - 49, y^2 - y - 1)*x^3 + Mod(-7*y + 84, y^2 - y - 1)*x^2 + Mo d(-14*y + 21, y^2 - y - 1)*x + Mod(-y - 43, y^2 - y - 1) x^8 + Mod(-5265231366756*y - 11544453645457, y^2 - y - 7)*x^7 + Mod(28411458 5416607426786*y + 622944640581258439174, y^2 - y - 7)*x^6 + Mod(-88698486784 831757442657946*y - 194478741347464554095950854, y^2 - y - 7)*x^5 + Mod(1457 861838374320941446687517087*y + 3196482213651741289611519839129, y^2 - y - 7 )*x^4 + Mod(-3466536016262523445329224834043387*y - 760066587058933027706659 6588522840, y^2 - y - 7)*x^3 + Mod(500059251848756466420835983321373618*y + 1096421116344588264250099626740668170, y^2 - y - 7)*x^2 + Mod(-1916208944621 5341153510282273347908836*y - 42014460135353505823787366140454468112, y^2 - y - 7)*x + Mod(100691810991091652032034511974871062155*y + 22077509296238717 8747302102119022589688, y^2 - y - 7) x^8 + Mod(-8*y + 1, y^2 - y - 7)*x^7 + Mod(21*y + 189, y^2 - y - 7)*x^6 + Mo d(-385*y - 251, y^2 - y - 7)*x^5 + Mod(695*y + 2955, y^2 - y - 7)*x^4 + Mod( -2451*y - 3350, y^2 - y - 7)*x^3 + Mod(2402*y + 6871, y^2 - y - 7)*x^2 + Mod (-2050*y - 3861, y^2 - y - 7)*x + Mod(565*y + 1331, y^2 - y - 7) x^8 + Mod(-8*y + 1, y^2 - y - 7)*x^7 + Mod(21*y + 189, y^2 - y - 7)*x^6 + Mo d(-385*y - 251, y^2 - y - 7)*x^5 + Mod(695*y + 2955, y^2 - y - 7)*x^4 + Mod( -2451*y - 3350, y^2 - y - 7)*x^3 + Mod(2402*y + 6871, y^2 - y - 7)*x^2 + Mod (-2050*y - 3861, y^2 - y - 7)*x + Mod(565*y + 1331, y^2 - y - 7) x^8 + Mod(-8*y + 1, y^2 - y - 7)*x^7 + Mod(21*y + 189, y^2 - y - 7)*x^6 + Mo d(-385*y - 251, y^2 - y - 7)*x^5 + Mod(695*y + 2955, y^2 - y - 7)*x^4 + Mod( -2451*y - 3350, y^2 - y - 7)*x^3 + Mod(2402*y + 6871, y^2 - y - 7)*x^2 + Mod (-2050*y - 3861, y^2 - y - 7)*x + Mod(565*y + 1331, y^2 - y - 7) x^8 + Mod(-8*y + 1, y^2 - y - 7)*x^7 + Mod(21*y + 189, y^2 - y - 7)*x^6 + Mo d(-385*y - 251, y^2 - y - 7)*x^5 + Mod(695*y + 2955, y^2 - y - 7)*x^4 + Mod( -2451*y - 3350, y^2 - y - 7)*x^3 + Mod(2402*y + 6871, y^2 - y - 7)*x^2 + Mod (-2050*y - 3861, y^2 - y - 7)*x + Mod(565*y + 1331, y^2 - y - 7) x^3 + Mod(y^2 - 2, y^3 - y - 1)*x^2 + Mod(-y + 1, y^3 - y - 1)*x + Mod(y - 1 , y^3 - y - 1) x^9 - 4*x^8 + 8*x^7 - 9*x^6 + 7*x^5 - 3*x^4 - x^3 + 4*x^2 - 3*x + 1 Mod(0, x^3 + Mod(y^2 - y - 2, y^3 - y - 1)*x^2 + Mod(-y^2 + y + 1, y^3 - y - 1)*x + Mod(y^2, y^3 - y - 1)) Mod(0, x^9 - 4*x^8 + 8*x^7 - 9*x^6 + 7*x^5 - 3*x^4 - x^3 + 4*x^2 - 3*x + 1) Mod(0, x^9 - 4*x^8 + 8*x^7 - 9*x^6 + 7*x^5 - 3*x^4 - x^3 + 4*x^2 - 3*x + 1) *** nfinit: Warning: non-monic polynomial. Result of the form [nf,c]. x^2 - 3646554366 304 x^4 + 1000000000000000000000*x^2 + 1 x^4 + 146077*x^2 + 2629386 [y^4 - 2*y^3 - 16*y^2 - 5*y + 4, Mod(-2/3*y^3 + 5/3*y^2 + 28/3*y + 2/3, y^4 - 2*y^3 - 16*y^2 - 5*y + 4)] x^9 - 4*x^7 - 3*x^6 + 9*x^5 + 8*x^4 - 6*x^3 - 9*x^2 - 4*x - 1 x^5 - 13*x^3 - 3*x^2 + 5*x + 1 x^6 + 21471450*x^2 + 71643071500 x^6 - 12*x^4 - 24*x^3 + 21651666*x^2 - 257657256*x + 71814482884 x^4 + 146077*x^2 + 10517544 x [x, Mod(-1/2, x)] *** at top-level: polred([x,[1]]) *** ^--------------- *** polred: domain error in gvaluation: p = 1 [x] [x] [ 0 x] [2*x x^2 + 1] x + 1 [x + 1, Mod(-1/2, x + 1)] [x^2 + 1, Mod(1/2*x, x^2 + 1)] [2*x + 1] [x, x^2 + 1] [x^8 - 4*x^7 + 24*x^6 - 58*x^5 + 126*x^4 - 160*x^3 + 160*x^2 - 89*x + 26, Mo d(-68/135*x^7 + 208/135*x^6 - 1378/135*x^5 + 56/3*x^4 - 194/5*x^3 + 4976/135 *x^2 - 4492/135*x + 1856/135, x^8 - 4*x^7 + 24*x^6 - 58*x^5 + 126*x^4 - 160* x^3 + 160*x^2 - 89*x + 26)] x^16 - 4*x^15 - 334*x^14 + 264*x^13 + 32231*x^12 + 57392*x^11 - 1031422*x^10 - 3628868*x^9 + 7185297*x^8 + 42417784*x^7 + 11283472*x^6 - 137773504*x^5 - 127243504*x^4 + 69059728*x^3 + 56307944*x^2 - 6264432*x + 6436 *** Warning: new stack size = 25165824 (24.000 Mbytes). x^5 + 5*x - 1 [x^12 - 2*x^11 - 11*x^9 + 13*x^8 + 5, Mod(0, x^12 - 2*x^11 - 11*x^9 + 13*x^8 + 5)] x^15 - 15*x^13 - 2*x^12 + 78*x^11 - 10*x^10 - 393*x^9 + 81*x^8 + 939*x^7 - 3 73*x^6 - 822*x^5 + 723*x^4 - 1588*x^3 - 57*x^2 + 127*x - 13 1 x^4 + Mod(-1/24*z^3 - 1/8*z^2 - 59/24*z - 27/8, z^4 + 50*z^2 + 45)*x^3 + Mod (1/12*z^3 + 41/12*z + 5/2, z^4 + 50*z^2 + 45)*x^2 + Mod(-1/24*z^3 - 1/8*z^2 - 59/24*z - 27/8, z^4 + 50*z^2 + 45)*x + 1 x^4 + Mod(-1/24*z^3 - 1/8*z^2 - 59/24*z - 27/8, z^4 + 50*z^2 + 45)*x^3 + Mod (1/12*z^3 + 41/12*z + 5/2, z^4 + 50*z^2 + 45)*x^2 + Mod(-1/24*z^3 - 1/8*z^2 - 59/24*z - 27/8, z^4 + 50*z^2 + 45)*x + 1 [y^2 + Mod(t^3, t^4 + t^3 + t^2 + t + 1)*y + Mod(8*t^2 - 46*t + 8, t^4 + t^3 + t^2 + t + 1), Mod(Mod(-t, t^4 + t^3 + t^2 + t + 1)*y + Mod(-t^2 - t, t^4 + t^3 + t^2 + t + 1), y^2 + Mod(t^3, t^4 + t^3 + t^2 + t + 1)*y + Mod(8*t^2 - 46*t + 8, t^4 + t^3 + t^2 + t + 1))] Total time spent: 6916 pari-2.11.2/src/test/32/ellsea0000644000175000017500000000154413326135265014352 0ustar billbill *** Warning: new stack size = 16000000 (15.259 Mbytes). 1: -18627161351017007203 2: 18827282990304904850 3: -311256626765211726406998 4: -1156815323986765479761266 5: 8021839135157401454666601928 6: 69384671472347162238655401774 7: -28652256072001057705168347198 8: 1271547588042840381566950172346 9: 1854715558584444 10: 20420247695 11: -4742075250 1:896615193897208487551655423042 2:1160030981035862058695525039892 3:529656639561669286549173325490 4:817701636704152445708337225413 5:983440823277044783790077069060 6:383857664397975740685677977539 -40969318 -110835623989511 0 1048845330393999479019082 0 1237940049661719722719792298 486 1267650600228229268303269105757 1267650600228228204181264322228 0 0 0 1048845330396436420140511 0 1048845330395135782279169 1048845330395135782279169 1048845330396436420140511 1048845330396436420140511 Total time spent: 6916 pari-2.11.2/src/test/32/nfpolsturm0000644000175000017500000000125713326135265015317 0ustar billbill[0, 0, 0, 2, 2] 0 [0, 0, 0, 2] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] [0, 2, 2, 2, 2] *** at top-level: nfpolsturm(nf,a,3) *** ^------------------ *** nfpolsturm: domain error in nfpolsturm: index > 2 *** at top-level: nfpolsturm(nf,a,[-1..1]) *** ^------------------------ *** nfpolsturm: domain error in nfpolsturm: index <= 0 *** at top-level: nfpolsturm(nf,a,[1..3]) *** ^----------------------- *** nfpolsturm: domain error in nfpolsturm: index > 2 *** at top-level: nfpolsturm(nf,0,1) *** ^------------------ *** nfpolsturm: zero polynomial in nfpolsturm. Total time spent: 4 pari-2.11.2/src/test/32/polmodular0000644000175000017500000000012413201017466015246 0ustar billbill *** Warning: new stack size = 32000000 (30.518 Mbytes). Total time spent: 22185 pari-2.11.2/src/test/32/install0000644000175000017500000000020413326135265014543 0ustar billbill"t_CLOSURE" 3 addii: installed function library name: addii prototype: GG addii: new identifier 5 "t_CLOSURE" Total time spent: 0 pari-2.11.2/src/test/32/lfun0000644000175000017500000003024313457566441014060 0ustar billbill *** Warning: new stack size = 32000000 (30.518 Mbytes). [688, 201] 371 1:-0.33333333333333333333333333333333333333 2:0 3:19.233333333333333333333333333333333333 4:0 5:-52083.825396825396825396825396825396826 6:0 7:1357464617.6166666666666666666666666667 8:0 9:-179843066266647.30303030303030303030303 10:0 1:0.33063066328223158676532076242927218282 2:0.65737655586117037348678949547515310666 3:0.83891994700224752688923802043332022788 4:0.92491465281539828015714800144878813258 5:0.96452286982609889100272493876597162334 6:0.98297145977262401505413785166918148202 7:0.99172249343786354566494479026158994548 8:0.99593957135944435652980046461493771761 9:0.99799568488420794431041938185291613541 10:0.99900642043725868624437550798777108358 [441, 365] 0.65054897266021897189117007748600082029 + 0.3797872612825021141546006883142 4264203*I 1.0197948617829165568371172783583479161 + 0.01753787982678033377468853770967 0993431*x - 0.30423568247445724453438996641387297307*x^2 + O(x^3) -1.0000000000000000000000000000000000000*x^-2 + 0.07281584548367672486058637 5874901319140 + O(x) 2.0000000000000000000000000000000000000*x^-3 + O(x^0) -0.93754825431584375370257409456786497791 + 1.989280234298901023420858687421 5163815*x^2 - 3.0000729014215224328219706087689241919*x^4 + O(x^6) 1.9892802342989010234208586874215163815 - 6.00014580284304486564394121753784 83838*x^2 + 12.000743196868230785490141705105642697*x^4 + O(x^6) -2.15800131645680564826065544584339217*x - 2.1019724905481294182200201711445 8153*x^2 - 0.529685033171161239709892386112460416*x^3 - 4.738573771869464928 37424643722475375*x^4 - 3.21952194221326633226406870366478753*x^5 + O(x^6) -2.15800131645680564826065544584339217 - 4.203944981096258836440040342289163 06*x - 1.58905509951348371912967715833738125*x^2 - 18.9542950874778597134969 857488990150*x^3 - 16.0976097110663316613203435183239376*x^4 - 21.4034953961 473607584436264229933443*x^5 + O(x^6) 1.1179816853477385178979715038469170225 1.0000000000000000000000000000000000000*x^-2 + 1.154431329803065721213024180 1648048621*x^-1 + O(x^0) 0.61685027506808491367715568749225944596*x^-2 + 1.01511996319472488016374193 63106928091*x^-1 + O(x^0) 1.0000000000000000000000000000000000000*x^-1 + O(x^0) 0.72399875382322394120054853672842760345*x^-1 + O(x^0) 246.96037648704266640450758953126840719 1.00000000000000000000000000000000000000000000000000000*x^-1 + O(x^0) 4.59057737496905265921181053582421504989219703475223909 - 3.1894012475791441 3416113592649224080101489871517943905*I 4.59057737496905265921181053582421504989219703475223909 - 3.1894012475791441 3416113592649224080101489871517943905*I -0.918938533204672741780329736405617639861397473637783413 -0.500000000000000000000000000000000000000000000000000000 - 0.91893853320467 2741780329736405617639861397473637783413*x - 1.00317822795429242560505001336 498021909949745508045994*x^2 - 1.0007851944770424079601768022277292142436346 1138266336*x^3 - 0.999879299500571164957800813655875235912130830621737643*x^ 4 - 1.00000194089632045603779988198163183123243380977058752*x^5 - 1.00000130 114601395962431150487297972022050535126287236*x^6 - 0.9999998313841736107799 30217058015406504287266515799803*x^7 - 1.00000000576467597994939441606374165 964458982012538704*x^8 - 1.0000000009110164892314165709218674221759786407713 7178*x^9 - 0.999999999850299240580988626479279942923194971996409274*x^10 - 1 .00000000000940689566566617690964783960902526136635510*x^11 - 1.000000000000 04092582630415831547636589331713210684094*x^12 - 0.9999999999999346009519410 89847743543530991534013594552*x^13 - 1.0000000000000065439687498919193731717 8549879786061140*x^14 - 0.99999999999999969875751286332132050502895615410010 3971*x^15 + O(x^16) [14.1347251417346937904572519835624702707842571156992432] [14.1347251417346937904572519835624702707842571156992432] [14.1347251417346937904572519835624702707842571156992432, 21.022039638771554 9926284795938969027773343405249027818, 25.0108575801456887632137909925628218 186595496725579967] 1.64493406684822643647241516664602518921894990120679844 0.E-57 0.E-57 + 0.E-57*I 1.08642943411465667904756436036751417209703758075237284 + 0.5814393878814690 50796952624011344061904995756625692378*I [0, 0, 0, 2.05247285847993976968922276314372344628278531045671612, 3.2624435 5597875746635580364385504003255536470999182746, 4.47055151331009795091782387 950075730310480986858048883, 4.754431515963405864151635593968863195363908404 79441418, 6.01192275298639519014642522248844223795049139992228727, 6.6225046 1340770678139848771792480632419572890704427238, 7.34281497953964814691434021 056204069773310740821664643, 7.706794648113253444646515057103424471764811099 99985019, 8.47680194262350037741231085806780599121287634323800435, 9.3821789 1117193954907921307162820430752270478042951828, 10.2034632426606570779547130 495062951265229955572895373, 10.49585360108396305215840613479582203063682050 06846644, 11.0334412351426994365984023609574093781284435634924994, 11.686948 0908853117520467071200624951073279924875106987, 12.2872289038249291759599430 438941349597652754843369265, 12.97272258207285515566187612538460946756424085 17308260, 13.1516366031527298638457029894321422485191693385770427, 14.941560 3295484662604761276988412262910822900346167548, 15.5153470765360805167423831 611671659141843411546141532, 15.89479293723708546650440371159237688468390847 47857619, 16.4404849010636539204980820326139388267735297782205584, 16.643129 4008115360154817747496027260477191373350164541, 17.4115213614943714989213104 465137362699445863767902588, 18.07306090799612896897975201392338100448825380 23845260, 18.5597395171897437816282533768115505690861265963563642, 19.031282 9499859520841448378360117311970316861384451388, 19.4973491720207997554477267 895497007883582413152228914, 19.97454966422489875085184165206182695782541275 69183433] [0, 0, 0, 2.05247285847993976968922276314372344628278531045671612] [[1, 25/48, 5/12, 25/48, 1], [1620/691, 1, 9/14, 9/14, 1, 1620/691], 0.00741 542092989613058900642774590022872478364665364735552, 0.005083512108393286860 49429013743874732263404552491812001] 2.99829512187626747049837118353413149411569186966170254 - 0.0193445925339772 841452384712897772364256641021849529530*I 2.99829512187626747049837118353413149411569186966170254 - 0.0193445925339772 841452384712897772364256641021849529530*I 2.99829512187626747049837118353413149411569186966170254 - 0.0193445925339772 841452384712897772364256641021849529530*I 973 0.177455993247329238699202652214156646711252940222106816 [0.201954787411261026528684690029341772176043691915844168, 0] 0.97906557276284488612288786018111182197046845456987142630213045542848319630 07533965134607035430513178949168014263879 -189 -189 -190 -191 1.97848884347766873530779261857994032392637450942515837 + 0.0609239674747025 097814469640574145327771779577841455860*I 1.30351764627548230978276542627689204122406359796082825 - 0.0344294367015510 576149187463564582588308663091234952457*I *** lfunzeros: Warning: lfuninit: insufficient initialization. [1.76524528537434114004961734014687322242921043467451418, 2.9001948143989959 3853720458684428845871417117642020713, 4.80912824766302432457595530706768541 000593962088321171, 6.05385187632329316110398877826905838861120455439163616, 7.03104718941202758893296505461247399284219178321418886, 8.0611446646958964 5370426023193369987671312157987402508, 10.4138094136894319447888631663520554 801158568510225716, 11.5429326942529531377771432204175144625871573059960913, 12.2634871694527156193695773489858842238381199251462399, 13.523913779157256 8249199285782562251878941627912318795, 14.6267210920659865269412411659252020 114704423226886093, 15.2588679023455946128303693291132825994525235298638847, 17.1471665979791684669746630513532371198945899053737963, 17.924261776515709 3404867459600570383531919623979762348, 19.2057886412953906115542482837931510 878888441286200350] -189 1.97848884347766873530779261857994032392637450942515837 + 0.0609239674747025 097814469640574145327771779577841455860*I -191 x^3 - x - 1 Curve y^2+(x^3+x^2+1)*y = x^2+x -58 Curve y^2+(x^3+1)*y = x^2+x Curve y^2+(x^2+x)*y = x^6+3*x^5+6*x^4+7*x^3+6*x^2+3*x+1 *** lfungenus2: Warning: unknown valuation of conductor at 2. -58 Curve y^2=x^5 + x -125 [0, 0, -1] 2.1541265970381460760215439978358922308 Curve y^2=x^5 + 1 -126 [0, 0, 1] 1.0314071041733177562983179141216861078 *** lfungenus2: Warning: unknown valuation of conductor at 2. [[Vecsmall([15]), [3*x^5 + 60*x^4 + 480*x^3 + 1920*x^2 + 3840*x + 3075, [[2, 1], [3, 1], [5, 1]]]], 0, [0, 0, 1, 1], 2, 50625, 0] Elliptic curves over number fields -124 1.3894051168795718563026565631765059398 -125 1.7561367497808959311966399691482152395 -124 2.7749792286446646504296418681816946545 -124 4.4552267729872870508917049939747968543 -126 8.2306621809152393859013012963081422203 -2 -22 Grossencharacter -126 1.0000000000000000000000000000000000000 tensor product realbitprecision = 64 significant bits (19 decimal digits displayed) -59 1.774264741132682166 check all formats -191 -191 -191 -191 [1, -2, -3, 2, -2, 6, -1, 0, 6, 4] [1, -1, 1, 1, -1, -1, -1, -1, 1, 1] [1, -1, 0, 1, 1, 0, 0, -1, 0, -1] 0.E-57 1/240 -1/504 1/480 -1/264 691/65520 -1/24 3617/16320 -43867/28728 1.00000000000000000000000000000000000000000000000000000 -1.07637023438345995368832251445133621778701931610742695 0.661475187921069742727520633979626889791045796292710056 0.146374542091265989413000913274996215907067384190621201 0.934830053608610054115427799558087197935200286533499400 0.661475187921069742727520633979626889791045796292710056 0.953260474794660686250509013566383496014986229687151072 + 16.29021572039039 07929631726451921643054665845864660536*I 0 1.00000000000000000000000000000000000000000000000000000 -184 1.00000000000000000000000000000000000000000000000000000 -178 zeta(s-a) -189 1.00000000000000000000000000000000000000000000000000000*x^-1 + O(x^0) 1.64493406684822643647241516664602518921894990120679844 -188 -0.500000000000000000000000000000000000000000000000000000 1.00000000000000000000000000000000000000000000000000000*x^-1 + O(x^0) zeta(s)*zeta(s-a) -184 1.64493406684822643647241516664602518921894990120679844*x^-1 + O(x^0) 1.97730435029729611819708544148512557208215146666013421 -186 -0.822467033424113218236207583323012594609474950603399219 1.20205690315959428539973816151144999076498629234049888*x^-1 + O(x^0) *** lfunconductor: Warning: #an = 598 < 1444, results may be imprecise. 61 1.01542133944024439298806668944681826497337332941038810 [[147, 202], [147, 202], [147, 202]] -188 [[11, 195], [6, 195]] 1 1 4 857 120 [8, 2108] [[[1, 0.54657288114990636157071248041210027593*x^-1 + O(x^0)]], [[1, 6.64934 60830715850476062965515423576642*x^-1 + O(x^0)], [0, -6.64934608307158504760 62965515423576642*x^-1 + O(x^0)]], 1] 1 5077 725.0000000000000000 24217.00000000000000 28614069.00000000000 -64 -57 1 [6, 186] [[12, 125], [11, 125], [5, 124]] 1.000000000000000019 0.83214280825734611779852282418300471522 + 0.0378612661512960987252330268197 96281464*I 0.83214280825734611779852282418300471522 + 0.0378612661512960987252330268197 96281464*I -126 [1, -127] 1.6449340668482264364724151666460251892 1:-54 2:-35 3:-43 4:-31 5:-38 6:-25 7:-22 0 *** lfun: Warning: #an = 1 < 5, results may be imprecise. *** lfun: Warning: #an = 1 < 8, results may be imprecise. 1.6449321944727952165464885195862083681 *** at top-level: lfuntheta(1,0) *** ^-------------- *** lfuntheta: domain error in lfunthetainit: t = 0 *** at top-level: lfunhardy(1,I) *** ^-------------- *** lfunhardy: incorrect type in lfunhardy (t_COMPLEX). *** at top-level: lfun(1,2,-1) *** ^------------ *** lfun: domain error in lfun: D <= 0 *** at top-level: lfunan(lfuncreate([1,0,[0],1,1,1,1]),10) *** ^---------------------------------------- *** lfunan: incorrect type in vecan_closure (t_INT). *** at top-level: ...t(x^2+1);G=galoisinit(N);lfunartin(N,G,[1]~,2) *** ^--------------------- *** lfunartin: inconsistent dimensions in lfunartin. *** at top-level: ...t(x^2+1);G=galoisinit(N);lfunartin(N,G,[1,1,1] *** ^--------------------- *** lfunartin: inconsistent dimensions in lfunartin. *** at top-level: localbitprec(16);lfun(Lt,12) *** ^----------- *** lfun: incorrect type in vecan_closure (t_INT). Total time spent: 9506 pari-2.11.2/src/test/32/linear0000644000175000017500000003773613326135265014373 0ustar billbill echo = 1 ? algdep(2*cos(2*Pi/13),6) x^6 + x^5 - 5*x^4 - 4*x^3 + 6*x^2 + 3*x - 1 ? algdep(2*cos(2*Pi/13),6,15) x^6 + x^5 - 5*x^4 - 4*x^3 + 6*x^2 + 3*x - 1 ? charpoly([1,2;3,4],z) z^2 - 5*z - 2 ? charpoly(Mod(x^2+x+1,x^3+5*x+1),z) z^3 + 7*z^2 + 16*z - 19 ? charpoly([1,2;3,4],z,1) z^2 - 5*z - 2 ? charpoly(Mod(1,8191)*[1,2;3,4],z,2) z^2 + Mod(8186, 8191)*z + Mod(8189, 8191) ? lindep(Mod(1,7)*[2,-1;1,3]) [-3, 1]~ ? lindep([(1-3*sqrt(2))/(3-2*sqrt(3)),1,sqrt(2),sqrt(3),sqrt(6)]) [3, 3, -9, 2, -6]~ ? lindep([(1-3*sqrt(2))/(3-2*sqrt(3)),1,sqrt(2),sqrt(3),sqrt(6)],14) [-3, -3, 9, -2, 6]~ ? matadjoint([1,2;3,4]) [ 4 -2] [-3 1] ? matcompanion(x^5-12*x^3+0.0005) [0 0 0 0 -0.00050000000000000000000000000000000000000] [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 12] [0 0 0 1 0] ? matdet([1,2,3;1,5,6;9,8,7]) -30 ? matdet([1,2,3;1,5,6;9,8,7],1) -30 ? matdetint([1,2,3;4,5,6]) 3 ? matdiagonal([2,4,6]) [2 0 0] [0 4 0] [0 0 6] ? mateigen([1,2,3;4,5,6;7,8,9]) [1 -1.2833494518006402717978106547571267252 0.283349451800640271797810654757 12672521] [-2 -0.14167472590032013589890532737856336261 0.6416747259003201358989053273 7856336260] [1 1 1] ? mathess(mathilbert(7)) [1 90281/58800 -1919947/4344340 4858466341/1095033030 -77651417539/819678732 6 3386888964/106615355 1/2] [1/3 43/48 38789/5585580 268214641/109503303 -581330123627/126464718744 4365 450643/274153770 1/4] [0 217/2880 442223/7447440 53953931/292008808 -32242849453/168619624992 1475 457901/1827691800 1/80] [0 0 1604444/264539275 24208141/149362505292 847880210129/47916076768560 -45 44407141/103873817300 -29/40920] [0 0 0 9773092581/35395807550620 -24363634138919/107305824577186620 72118203 606917/60481351061158500 55899/3088554700] [0 0 0 0 67201501179065/8543442888354179988 -9970556426629/74082861999267660 0 -3229/13661312210] [0 0 0 0 0 -258198800769/9279048099409000 -13183/38381527800] ? mathilbert(5) [ 1 1/2 1/3 1/4 1/5] [1/2 1/3 1/4 1/5 1/6] [1/3 1/4 1/5 1/6 1/7] [1/4 1/5 1/6 1/7 1/8] [1/5 1/6 1/7 1/8 1/9] ? amat=1/mathilbert(7) [ 49 -1176 8820 -29400 48510 -38808 12012] [ -1176 37632 -317520 1128960 -1940400 1596672 -504504] [ 8820 -317520 2857680 -10584000 18711000 -15717240 5045040] [-29400 1128960 -10584000 40320000 -72765000 62092800 -20180160] [ 48510 -1940400 18711000 -72765000 133402500 -115259760 37837800] [-38808 1596672 -15717240 62092800 -115259760 100590336 -33297264] [ 12012 -504504 5045040 -20180160 37837800 -33297264 11099088] ? mathnf(amat) [420 0 0 0 210 168 175] [ 0 840 0 0 0 0 504] [ 0 0 2520 0 0 0 1260] [ 0 0 0 2520 0 0 840] [ 0 0 0 0 13860 0 6930] [ 0 0 0 0 0 5544 0] [ 0 0 0 0 0 0 12012] ? mathnf(amat,1) [[420, 0, 0, 0, 210, 168, 175; 0, 840, 0, 0, 0, 0, 504; 0, 0, 2520, 0, 0, 0, 1260; 0, 0, 0, 2520, 0, 0, 840; 0, 0, 0, 0, 13860, 0, 6930; 0, 0, 0, 0, 0, 5544, 0; 0, 0, 0, 0, 0, 0, 12012], [420, 420, 840, 630, 2982, 1092, 4159; 21 0, 280, 630, 504, 2415, 876, 3395; 140, 210, 504, 420, 2050, 749, 2901; 105, 168, 420, 360, 1785, 658, 2542; 84, 140, 360, 315, 1582, 588, 2266; 70, 120 , 315, 280, 1421, 532, 2046; 60, 105, 280, 252, 1290, 486, 1866]] ? mathnf(amat,4) [[420, 0, 0, 0, 210, 168, 175; 0, 840, 0, 0, 0, 0, 504; 0, 0, 2520, 0, 0, 0, 1260; 0, 0, 0, 2520, 0, 0, 840; 0, 0, 0, 0, 13860, 0, 6930; 0, 0, 0, 0, 0, 5544, 0; 0, 0, 0, 0, 0, 0, 12012], [420, 420, 840, 630, 2982, 1092, 4159; 21 0, 280, 630, 504, 2415, 876, 3395; 140, 210, 504, 420, 2050, 749, 2901; 105, 168, 420, 360, 1785, 658, 2542; 84, 140, 360, 315, 1582, 588, 2266; 70, 120 , 315, 280, 1421, 532, 2046; 60, 105, 280, 252, 1290, 486, 1866]] ? mathnf(amat,5) [[360360, 0, 0, 0, 0, 144144, 300300; 0, 27720, 0, 0, 0, 0, 22176; 0, 0, 277 20, 0, 0, 0, 6930; 0, 0, 0, 2520, 0, 0, 840; 0, 0, 0, 0, 2520, 0, 1260; 0, 0 , 0, 0, 0, 168, 0; 0, 0, 0, 0, 0, 0, 7], [51480, 4620, 5544, 630, 840, 20676 , 48619; 45045, 3960, 4620, 504, 630, 18074, 42347; 40040, 3465, 3960, 420, 504, 16058, 37523; 36036, 3080, 3465, 360, 420, 14448, 33692; 32760, 2772, 3 080, 315, 360, 13132, 30574; 30030, 2520, 2772, 280, 315, 12036, 27986; 2772 0, 2310, 2520, 252, 280, 11109, 25803], Vecsmall([7, 6, 5, 4, 3, 2, 1])] ? mathnfmod(amat,matdetint(amat)) [420 0 0 0 210 168 175] [ 0 840 0 0 0 0 504] [ 0 0 2520 0 0 0 1260] [ 0 0 0 2520 0 0 840] [ 0 0 0 0 13860 0 6930] [ 0 0 0 0 0 5544 0] [ 0 0 0 0 0 0 12012] ? mathnfmodid(amat,123456789*10^100) [60 0 0 0 30 24 35] [ 0 120 0 0 0 0 24] [ 0 0 360 0 0 0 180] [ 0 0 0 360 0 0 240] [ 0 0 0 0 180 0 90] [ 0 0 0 0 0 72 0] [ 0 0 0 0 0 0 12] ? matid(5) [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1] ? matimage([1,3,5;2,4,6;3,5,7]) [1 3] [2 4] [3 5] ? matimage([1,3,5;2,4,6;3,5,7],1) [3 5] [4 6] [5 7] ? matimage(Pi*[1,3,5;2,4,6;3,5,7]) [3.1415926535897932384626433832795028842 9.424777960769379715387930149838508 6526] [6.2831853071795864769252867665590057684 12.56637061435917295385057353311801 1537] [9.4247779607693797153879301498385086526 15.70796326794896619231321691639751 4421] ? matimagecompl([1,3,5;2,4,6;3,5,7]) Vecsmall([3]) ? matimagecompl(Pi*[1,3,5;2,4,6;3,5,7]) Vecsmall([3]) ? matindexrank([1,1,1;1,1,1;1,1,2]) [Vecsmall([1, 3]), Vecsmall([1, 3])] ? matintersect([1,2;3,4;5,6],[2,3;7,8;8,9]) [-1] [-1] [-1] ? matinverseimage([1,1;2,3;5,7],[2,2,6]~) [4, -2]~ ? matisdiagonal([1,0,0;0,5,0;0,0,0]) 1 ? matker(matrix(4,4,x,y,x/y)) [-1/2 -1/3 -1/4] [ 1 0 0] [ 0 1 0] [ 0 0 1] ? matker(matrix(4,4,x,y,sin(x+y))) [1.0000000000000000000000000000000000000 1.080604611736279434801873214885953 2075] [-1.0806046117362794348018732148859532075 -0.1677063269057152260048635409984 7562047] [1 0] [0 1] ? matker(matrix(4,4,x,y,x+y),1) [ 1 2] [-2 -3] [ 1 0] [ 0 1] ? matkerint(matrix(4,4,x,y,x*y)) [-1 -1 -1] [-1 0 1] [ 1 -1 1] [ 0 1 -1] ? matkerint(matrix(4,4,x,y,x*y),1) [-1 -1 -1] [-1 0 1] [ 1 -1 1] [ 0 1 -1] ? matkerint(matrix(4,6,x,y,2520/(x+y))) [ -3 -1] [ 30 15] [-70 -70] [ 0 140] [126 -126] [-84 42] ? matmuldiagonal(amat,[1,2,3,4,5,6,7]) [ 49 -2352 26460 -117600 242550 -232848 84084] [ -1176 75264 -952560 4515840 -9702000 9580032 -3531528] [ 8820 -635040 8573040 -42336000 93555000 -94303440 35315280] [-29400 2257920 -31752000 161280000 -363825000 372556800 -141261120] [ 48510 -3880800 56133000 -291060000 667012500 -691558560 264864600] [-38808 3193344 -47151720 248371200 -576298800 603542016 -233080848] [ 12012 -1009008 15135120 -80720640 189189000 -199783584 77693616] ? matmultodiagonal(amat^-1,%) [1 0 0 0 0 0 0] [0 2 0 0 0 0 0] [0 0 3 0 0 0 0] [0 0 0 4 0 0 0] [0 0 0 0 5 0 0] [0 0 0 0 0 6 0] [0 0 0 0 0 0 7] ? matpascal(8) [1 0 0 0 0 0 0 0 0] [1 1 0 0 0 0 0 0 0] [1 2 1 0 0 0 0 0 0] [1 3 3 1 0 0 0 0 0] [1 4 6 4 1 0 0 0 0] [1 5 10 10 5 1 0 0 0] [1 6 15 20 15 6 1 0 0] [1 7 21 35 35 21 7 1 0] [1 8 28 56 70 56 28 8 1] ? matrank(matrix(5,5,x,y,x+y)) 2 ? matrix(5,5,x,y,gcd(x,y)) [1 1 1 1 1] [1 2 1 2 1] [1 1 3 1 1] [1 2 1 4 1] [1 1 1 1 5] ? matrixqz([1,3;3,5;5,7],0) [1 1] [3 2] [5 3] ? matrixqz([1/3,1/4,1/6;1/2,1/4,-1/4;1/3,1,0],-1) [19 12 2] [ 0 1 0] [ 0 0 1] ? matrixqz([1,3;3,5;5,7],-2) [2 -1] [1 0] [0 1] ? matsize([1,2;3,4;5,6]) [3, 2] ? matsnf(1/mathilbert(6)) [27720, 2520, 2520, 840, 210, 6] ? matsnf(x*matid(5)-matrix(5,5,j,k,1),2) [x^2 - 5*x, x, x, x, 1] ? matsolve(mathilbert(10),[1,2,3,4,5,6,7,8,9,0]~) [9236800, -831303990, 18288515520, -170691240720, 832112321040, -23298940665 00, 3883123564320, -3803844432960, 2020775945760, -449057772020]~ ? matsolvemod([2,3;5,4],[7,11]~,[1,4]~) [25, 0]~ ? matsolvemod([2,3;5,4],[7,11]~,[1,4]~,1) [[25, 0]~, [77, 30; 0, 1]] ? matsupplement([1,3;2,4;3,6]) [1 3 0] [2 4 0] [3 6 1] ? mattranspose(vector(2,x,x)) [1, 2]~ ? %*%~ [1 2] [2 4] ? norml2(vector(10,x,x)) 385 ? qfgaussred(mathilbert(5)) [1 1/2 1/3 1/4 1/5] [0 1/12 1 9/10 4/5] [0 0 1/180 3/2 12/7] [0 0 0 1/2800 2] [0 0 0 0 1/44100] ? qfjacobi(mathilbert(6)) [[1.0827994845655497685388772372251778091 E-7, 1.257075712262519492298239799 6498755378 E-5, 0.00061574835418265769764919938428527140434, 0.0163215213198 75822124345079564191505890, 0.24236087057520955213572841585070114077, 1.6188 998589243390969705881471257800713]~, [-0.00124819408408217511693981630463878 36342, 0.011144320930724710530678340374220998345, -0.06222658815019768177515 2126611810492941, 0.24032536934252330399154228873240534569, -0.6145448282925 8676899320019644273870646, 0.74871921887909485900280109200517845109; 0.03560 6642944287635266122848131812051370, -0.1797327572407600375877689780374064077 9, 0.49083920971092436297498316169060045043, -0.6976513752773701229620833504 6678265583, 0.21108248167867048675227675845247769095, 0.44071750324351206127 160083580231701802; -0.24067907958842295837736719558855680218, 0.60421220675 295973004426567844103061740, -0.53547692162107486593474491750949545605, -0.2 3138937333290388042251363554209048307, 0.36589360730302614149086554211117169 623, 0.32069686982225190106359024326699463107; 0.625460386549227244577534410 39459331707, -0.44357471627623954554460416705180104473, -0.41703769221897886 840494514780771076351, 0.13286315850933553530333839628101576048, 0.394706776 09501756783094636145991581709, 0.25431138634047419251788312792590944672; -0. 68980719929383668419801738006926828754, -0.441536641012289662221436497529772 04448, 0.047034018933115649705614518466541245344, 0.362714921464871475252994 57604461742112, 0.38819043387388642863111448825992418974, 0.2115308400789652 4664213667673977991960; 0.27160545336631286930015536176213646338, 0.45911481 681642960284551392793050867151, 0.54068156310385293880022293448123781988, 0. 50276286675751538489260566368647786274, 0.3706959077673628086177550108480739 4603, 0.18144297664876947372217005457727093716]] ? m=1/mathilbert(7) [ 49 -1176 8820 -29400 48510 -38808 12012] [ -1176 37632 -317520 1128960 -1940400 1596672 -504504] [ 8820 -317520 2857680 -10584000 18711000 -15717240 5045040] [-29400 1128960 -10584000 40320000 -72765000 62092800 -20180160] [ 48510 -1940400 18711000 -72765000 133402500 -115259760 37837800] [-38808 1596672 -15717240 62092800 -115259760 100590336 -33297264] [ 12012 -504504 5045040 -20180160 37837800 -33297264 11099088] ? mp=concat(m,matid(7)) [49 -1176 8820 -29400 48510 -38808 12012 1 0 0 0 0 0 0] [-1176 37632 -317520 1128960 -1940400 1596672 -504504 0 1 0 0 0 0 0] [8820 -317520 2857680 -10584000 18711000 -15717240 5045040 0 0 1 0 0 0 0] [-29400 1128960 -10584000 40320000 -72765000 62092800 -20180160 0 0 0 1 0 0 0] [48510 -1940400 18711000 -72765000 133402500 -115259760 37837800 0 0 0 0 1 0 0] [-38808 1596672 -15717240 62092800 -115259760 100590336 -33297264 0 0 0 0 0 1 0] [12012 -504504 5045040 -20180160 37837800 -33297264 11099088 0 0 0 0 0 0 1] ? qflll(m) [-420 -420 840 630 -1092 757 2982] [-210 -280 630 504 -876 700 2415] [-140 -210 504 420 -749 641 2050] [-105 -168 420 360 -658 589 1785] [ -84 -140 360 315 -588 544 1582] [ -70 -120 315 280 -532 505 1421] [ -60 -105 280 252 -486 471 1290] ? qflllgram(m) [1 1 27 -27 69 0 141] [0 1 4 -23 34 -24 49] [0 1 3 -22 18 -24 23] [0 1 3 -21 10 -19 13] [0 1 3 -20 6 -14 8] [0 1 3 -19 4 -10 5] [0 1 3 -18 3 -7 3] ? qflllgram(m,1) [1 1 27 -27 69 0 141] [0 1 4 -23 34 -24 49] [0 1 3 -22 18 -24 23] [0 1 3 -21 10 -19 13] [0 1 3 -20 6 -14 8] [0 1 3 -19 4 -10 5] [0 1 3 -18 3 -7 3] ? qflllgram(mp~*mp,4) [[-420, -420, 840, 630, 2982, -1092, 757; -210, -280, 630, 504, 2415, -876, 700; -140, -210, 504, 420, 2050, -749, 641; -105, -168, 420, 360, 1785, -658 , 589; -84, -140, 360, 315, 1582, -588, 544; -70, -120, 315, 280, 1421, -532 , 505; -60, -105, 280, 252, 1290, -486, 471; 420, 0, 0, 0, -210, 168, 35; 0, 840, 0, 0, 0, 0, 336; 0, 0, -2520, 0, 0, 0, -1260; 0, 0, 0, -2520, 0, 0, -8 40; 0, 0, 0, 0, -13860, 0, 6930; 0, 0, 0, 0, 0, 5544, 0; 0, 0, 0, 0, 0, 0, - 12012], [0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0 , 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 1]] ? qflll(m,1) [-420 -420 840 630 -1092 757 2982] [-210 -280 630 504 -876 700 2415] [-140 -210 504 420 -749 641 2050] [-105 -168 420 360 -658 589 1785] [ -84 -140 360 315 -588 544 1582] [ -70 -120 315 280 -532 505 1421] [ -60 -105 280 252 -486 471 1290] ? qflll(m,2) [-420 -420 -630 840 1092 2982 -83] [-210 -280 -504 630 876 2415 70] [-140 -210 -420 504 749 2050 137] [-105 -168 -360 420 658 1785 169] [ -84 -140 -315 360 588 1582 184] [ -70 -120 -280 315 532 1421 190] [ -60 -105 -252 280 486 1290 191] ? qflll(mp,4) [[-420, -420, 840, 630, 2982, -1092, 757; -210, -280, 630, 504, 2415, -876, 700; -140, -210, 504, 420, 2050, -749, 641; -105, -168, 420, 360, 1785, -658 , 589; -84, -140, 360, 315, 1582, -588, 544; -70, -120, 315, 280, 1421, -532 , 505; -60, -105, 280, 252, 1290, -486, 471; 420, 0, 0, 0, -210, 168, 35; 0, 840, 0, 0, 0, 0, 336; 0, 0, -2520, 0, 0, 0, -1260; 0, 0, 0, -2520, 0, 0, -8 40; 0, 0, 0, 0, -13860, 0, 6930; 0, 0, 0, 0, 0, 5544, 0; 0, 0, 0, 0, 0, 0, - 12012], [0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0 , 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 1]] ? qfminim([2,1;1,2],4,6) [6, 2, [0, 1, 1; 1, -1, 0]] ? qfperfection([2,0,1;0,2,1;1,1,2]) 6 ? qfsign(mathilbert(5)-0.11*matid(5)) [2, 3] ? trace(1+I) 2 ? trace(Mod(x+5,x^3+x+1)) 15 ? Vec(sin(x)) [1, 0, -1/6, 0, 1/120, 0, -1/5040, 0, 1/362880, 0, -1/39916800, 0, 1/6227020 800, 0, -1/1307674368000, 0] ? vecmax([-3,7,-2,11]) 11 ? vecmin([-3,7,-2,11]) -3 ? concat([1,2],[3,4]) [1, 2, 3, 4] ? concat(Mat(vector(4,x,x)~),vector(4,x,10+x)~) [1 11] [2 12] [3 13] [4 14] ? vecextract([1,2,3,4,5,6,7,8,9,10],1000) [4, 6, 7, 8, 9, 10] ? vecextract(matrix(15,15,x,y,x+y),vector(5,x,3*x),vector(3,y,3*y)) [ 6 9 12] [ 9 12 15] [12 15 18] [15 18 21] [18 21 24] ? round((1.*mathilbert(7))^(-1)<<77)/2^77 [49 -1176 8820 -29400 48510 -38808 12012] [-1176 37632 -317520 1128960 -1940400 1596672 -504504] [8820 -317520 2857680 -10584000 18711000 -15717240 5045040] [-29400 1128960 -10584000 6092986130857731040519127040001/151115727451828646 838272 -10995935908032311487186862080001/151115727451828646838272 9383198641 520905802399455641601/151115727451828646838272 -20180160] [48510 -1940400 18711000 -10995935908032311487186862080001/15111572745182864 6838272 10079607915696285529921290240001/75557863725914323419136 -8708781239 161590697851994767361/75557863725914323419136 37837800] [-38808 1596672 -15717240 9383198641520905802399455641601/151115727451828646 838272 -8708781239161590697851994767361/75557863725914323419136 152007817992 63867399887118139393/151115727451828646838272 -33297264] [12012 -504504 5045040 -20180160 37837800 -33297264 11099088] ? vecsort([8,7,6,5],,1) Vecsmall([4, 3, 2, 1]) ? vecsort([[1,5],[2,4],[1,5,1],[1,4,2]]) [[1, 4, 2], [1, 5], [1, 5, 1], [2, 4]] ? vecsort(vector(17,x,5*x%17)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] ? vecsort([[1,8,5],[2,5,8],[3,6,-6],[4,8,6]],2) [[2, 5, 8], [3, 6, -6], [1, 8, 5], [4, 8, 6]] ? vecsort([[1,8,5],[2,5,8],[3,6,-6],[4,8,6]],[2,1]) [[2, 5, 8], [3, 6, -6], [1, 8, 5], [4, 8, 6]] ? vector(10,x,1/x) [1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10] ? if(getheap()!=HEAP,getheap()) ? print("Total time spent: ",gettime); Total time spent: 8 pari-2.11.2/src/test/in/0000755000175000017500000000000013461316051013332 5ustar billbillpari-2.11.2/src/test/in/gcdext0000644000175000017500000000446213326135265014547 0ustar billbill{ a=[0,0*x,O(5^3),2,2+O(5^3),x]; for(i=1,#a, for(j=1,#a, print(gcdext(a[i],a[j])))); } gcdext(-1/3*x - 5/9,-x - 5/3) z;T; FF=Mod((O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z^7+((2+2^3+O(2^4))*T^3+O(2^4)*T^2+(1+2+O(2^4))*T+(1+2^2+O(2^4)))*z^6+(O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z^5+((1+2+2^3+O(2^4))*T^3+(1+2+2^2+2^3+O(2^4))*T^2+(2+2^3+O(2^4))*T+(1+2^2+2^3+O(2^4)))*z^4+(O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z^3+((2+2^2+2^3+O(2^4))*T^3+(1+2^2+2^3+O(2^4))*T^2+O(2^4)*T+(1+2+2^2+2^3+O(2^4)))*z^2+(O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z+((1+2^3+O(2^4))+(1+2^2+2^3+O(2^4))*T+(2+2^2+2^3+O(2^4))*T^2+(1+2+2^3+O(2^4))*T^3+O(T^20)),(1+O(2^4))*z^8+(1+O(2^4))); GG=Mod((O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z^7+((2+2^3+O(2^4))*T^3+O(2^4)*T^2+(1+2+O(2^4))*T+(1+2^2+O(2^4)))*z^6+(O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z^5+((1+2+2^3+O(2^4))*T^3+(1+2+2^2+2^3+O(2^4))*T^2+(2+2^3+O(2^4))*T+(1+2^2+2^3+O(2^4)))*z^4+(O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z^3+((2+2^2+2^3+O(2^4))*T^3+(1+2^2+2^3+O(2^4))*T^2+O(2^4)*T+(1+2+2^2+2^3+O(2^4)))*z^2+(O(2^4)*T^3+O(2^4)*T^2+O(2^4)*T+O(2^4))*z+((1+2^3+O(2^4))+(1+2^2+2^3+O(2^4))*T+(2+2^2+2^3+O(2^4))*T^2+(1+2+2^3+O(2^4))*T^3+O(T^20)),(1+O(2^4))*z^8+(1+O(2^4))); AA=truncate(lift(lift(FF))); BB=truncate(lift(lift(GG))); gcdext(AA,BB) gcd(x*Mod(1,7),x*Mod(1,7)) a=ffgen([3,5],'a); gcd((x^2+a*x+1)*(x+a),(x^3+a*x^2+a*x)*(x+a)) gcdext(x^2+a*x+1,x^3+a*x^2+a*x) gcd(2*I, 1+I) gcd(I*1., I+1.) gcd(1+O(2),1+O(3)) gcd(2+O(2^2),4+O(2^3)) w=quadgen(5); gcd(w,2*w) gcd(2*w,w) gcd(2,Mod(2,4)) gcd(1/2,Mod(2,4)) gcd(1/3,Mod(2,4)) gcd(Mod(2,4), 2+O(2^3)) gcd(Mod(2,5), I) gcd(Mod(2,5), w) gcd(1/2, 1/(I+1)) gcd(1/2, 2+O(2^3)) gcd(I, 2+O(2^3)) gcd(I, w) gcd(w, 2+O(2^3)) t = Mod(x^2,x^3); gcd(t,y) gcd(t,x) gcd(t,1/y) gcd(t,1/x) gcd(t,1/(x+1)) gcd(Pol(0), y) gcd(x+O(x^5), x^2+O(x^3)) gcd(x+O(x^5), 1/x^2) v=[1,2,1.,Mod(1,2),1/2,1/3,2/3,I,quadgen(5), 1+O(2),2+O(2^2),1/2+O(2)]; { t1=ffgen(2^3); t0=0*t1; t2=ffgen(3^3); for (i=1,#v, print(iferr(gcd(t0,v[i]),E,E)); print(iferr(gcd(t1,v[i]),E,E)); print(iferr(gcd(t2,v[i]),E,E)); ) } gcd(0,1.+I) gcd(0,1+I) gcd(0,Mod(1,3)+I) gcd(1/2, 1.+I) gcd(1,Mod(2,13)/(13*y+1)) default(realprecision,38); gcd(Pol(0.),x) (k+1.)/k - (2*k+1.)/k gcd(1/(2^64*y),Mod(x^2,2^64*x^3)) gcd(Mod(1,2)*x+Mod(1,2),Mod(0,2)) gcd(Mod(1,2)*x+Mod(1,2), 0*ffgen(2^3)) lcm(Pol(0),0) lcm(0,Mod(0,3)) pari-2.11.2/src/test/in/mf0000644000175000017500000004727413447371554013712 0ustar billbilldefault(parisize, "20M"); default(realprecision, 38); getcache() Z4=znstar(4,1); Z5=znstar(5,1); Z8=znstar(8,1); vec(f)=mfcoefs(f,15); vec(mfeisenstein(2,[Z5,2])) vec(mfeisenstein(3,[Z5,2])) vec(mfeisenstein(2,[Z8,3],[Z8,5])) vec(mfeisenstein(3,[Z8,3],[Z8,5])) mfdim(mfinit([12,2],3)) mfdim(mfinit([225,2],3)) mfdim([10^9,4], 3) mfdim([10^9,1,Mod(3,4)], 3) mfdim([1,2],3) Th=1+2*sum(n=1,4,q^(n^2),O(q^20)); mf=mfinit([4,2]);mftobasis(mf,Th^4) mf=mfinit([4,3,[Z4,3]]);mftobasis(mf,Th^6) mf=mfinit([4,4]);mftobasis(mf,Th^8) mf=mfinit([4,5,[Z4,3]]);mftobasis(mf,Th^10) mf=mfinit([4,12],1); mfcoefs(mfinit(mf,0),10) mfcoefs(mf,10) mfcoefs(mf,5,2) D=q*eta(q)^24; mftobasis(mf,D+O(q^2),1) mftobasis(mf,D+O(q^3),1) mftobasis(mf,D+O(q^4),1) mftobasis(mf,D+O(q^5),1) v=mftonew(mf,D); [#v, v[1][1..2]] v2=concat(0,Vec(D)); mftobasis(mf,v2) mftobasis(mf,v2~) apply(mfdim, mfinit([1,0,0], 1)) apply(mfdim, mfinit([1,0,0])) apply(mfdim, mfinit([1,-1,0])) apply(mfdim, mfinit([1,-1,[]])) apply(mfdim, mfinit([1,-1,[1,1]])) apply(mfdim, mfinit([1,1,0],0)) apply(mfdim, mfinit([1,1,[1,1]],1)) mfdim([2,-1,-1]) mfdim([11,2,-1]) mfdim(mfinit([1,0,1], 1)) mfdim(mfinit([1,0,1])) mfdim(mfinit([4,0,-4], 1)) mfdim(mfinit([4,0,-4])) mfdim([1,0],1) mfdim([1,0]) mfdim([1,0,0],1) mfdim([1,0,0]) mfdim([1,0,1],1) mfdim([1,0,1]) mfdim([4,0,-4],1) mfdim([4,0,-4]) mfdim([4,0,[1,-4,-4,1]],1) mfdim([4,0,[1,-4,-4,1]]) N=7^3*13^3;mfdim([N,2,Mod(107,N)]) N=5^3*13^3;mfdim([N,2,Mod(101,N)]) N=5^3*17^3;mfdim([N,2,Mod(101,N)]) mf=mfinit([155,2],0); mfsplit(mf,,1) mfsplit(mf, 1)[2] mfsplit(mf, 2)[2] mfsplit(mf, 3)[2] mfsplit(mf, 4)[2] mffields(mfinit([104,4,104],0)) mffields(mfinit([35,4,Mod(11,35)],0)) L=mfinit([23,1,0],3); vector(#L,i,mfdim(L[i])) #mfbasis([23,1,-23],0) mfdim([23,1,0],3) mfdim([23,1,0],2) mfdim([23,1,-1],2) L=mfinit([35,2,0],0); #L mf=L[1]; #mfinit([296,1,0],0) mfadd(F,G) = mflinear([F,G],[1,1]); [f,g] = mfbasis(mf); mfcoefs(f,19) mfcoefs(g,19) vec(mfadd(f,g)) vec(mfmul(f,g)) vec(mflinear([f,g],[1,2])) mfcoefs(f,49) vec(mfhecke(mf,g,3)) f2=mfbd(f,2); vec(f2) vec(mfbd(f2,3)) vec(mftwist(f,-7)) vec(mfEk(0)) T=mfcusps(96) apply(x->mfcuspwidth(96,x),T) apply(x->mfcuspisregular([96,2,Mod(7,96)],x), T) apply(x->mfcuspisregular([96,1/2,Mod(7,96)],x), T) mfnumcusps(96) mfnumcusps(2^64) mfnumcusps(factor(6^64)) mfsturm([96,6]) mfdim([96,6],0) mfdim([96,6]) vec(mftraceform([1,0])) T=mftraceform([96,6],1); mfdescribe(T) mfdescribe(mflinear([T],[0])) [mfcoef(T,2), mfcoef(T,3)] vec(T) T=mftraceform([96,6]); [mfcoef(T,2), mfcoef(T,3)] vec(T) T=mftraceform([23,1,-23]); vec(T) T=mftraceform([52,1,Mod(3,52)]); vec(T) T=mftraceform([88,1,Mod(59,88)],0); vec(T) T=mftraceform([88,1,Mod(65,88)],0); vec(T) T=mftraceform([88,1,Mod(65,88)],1); vec(T) T=mftraceform([8,4,8],0); vec(T) T=mftraceform([15,2]); vec(T) T=mftraceform([15,4]); vec(T) mf = mfinit([15,4],1); mfparams(mflinear(mf,[1,0,1,0])) mf=mfinit([16,6]); B = mfbasis(mf); F = mflinear([B[7],B[8]],[4,7]); mfconductor(mf,F) V=mftonew(mf,F); for (i=1,#V,v=V[i];print([v[1],v[2],mfcoefs(v[3],9)])) mf=mfinit([96,6],1);#mf[3] F=mflinear([mf[3][1],mf[3][2]],[4,7]); V=mftonew(mf,F); for (i=1,#V,v=V[i];print([v[1],v[2],mfcoefs(v[3],9)])) mfconductor(mf,F) #mfinit([96,6],2)[3] #mfinit([96,6],3)[2] mf=mfinit(mf,0);#mf[3] mfsplit(mf,,1) mfsplit(mf,,2) [poldegree(p) | p<-mffields(mf)] mfsplit(mf,1) mfsplit(mf,2) LC=mfeigenbasis(mf); for(i=1,#LC,print(concat(mfcoefs(LC[i],9), mfparams(LC[i])[4]))) f=LC[#LC]; vec(mfmul(f,f)) mfsturm(mf) F=mflinear(mfbasis(mf)[1..3],[4,-7,11]); mftobasis(mf,F) mfheckemat(mf,2) mfheckemat(mf,3) mfheckemat(mf, [9,15,25]) b = mfbasis(mf); for(i=1,#b,print(mfeval(mf,b[i],I/2))) D=mfDelta(); mfD = mfinit(D,1); mfeval(mfD,D,I/10) mfeval(mfD,D,1+2*I) mf23=mfinit([23,2],0);F=mfeigenbasis(mf23)[1]; mfcuspval(mf23,F,oo) mfcuspval(mf23,F,0) mfcuspval(mf23,F,1/2) \\ to make it identical in 32/64 bits round(mfeval(mf23,F,I/50) * 1e35) round(mfslashexpansion(mf23,F,[1,0;1,1],2,0) * 1e35) vec(mfdiv(mfpow(D,3),mfpow(D,2))) mfcoefs(D,0) \\ #2078 mfa = mfatkininit(mf,32); mfa[2] mfatkininit(mfinit([12,11,-3],0), 4)[2] vec(mfatkin(mfa,mf[3][1])) mfatkininit(mfinit([3,7,-3],0), 3)[2] L=[lfuninit(l,[3,4,0],1) | l<-concat(lfunmf(mf))]; vector(#L,i,lfun(L[i],2)) vector(#L,i,lfun(L[i],1)) vector(#L,i,lfun(L[i],0,1)) vector(#L,i,lfun(L[i],-1,1)) mf=mfinit([163,4],3); f=mfbasis(mf)[2]; mfeval(mf,f,I/400) real(mfeval(mf,f,1.5+I/400)) mf=mfinit([5,4],0); vF=mfeigenbasis(mf); #vF F=vF[1]; liftpol(mfcoefs(F, 9)) R=mfslashexpansion(mf,F,[1,0;1,1],10,0,¶ms); lift(bestapprnf(R*25,polcyclo(5,'t))) params mf=mfinit([11,2],1);F=mfbasis(mf)[1]; mfslashexpansion(mf,F,[1,0;0,1],5,0,¶ms) params mf=mfinit([44,3,-4],4);F=mfbasis(mf)[1]; mfslashexpansion(mf,F,[1,0;2,1],4,0,¶ms) params mf=mfinit([7,4,Mod(2,7)], 0); F=mfbasis(mf)[1]; mfslashexpansion(mf,F,[1,0;1,1],5,0,¶ms) params mf=mfinit([12,8],0);F=mfbasis(mf)[1]; mfslashexpansion(mf,F,[1,0;2,1],12,0) mfslashexpansion(mf,F,[1,0;2,1],12,1) mf=mfinit([12,7,-4],0);F=mfbasis(mf)[1]; mfslashexpansion(mf,F,[1,0;6,1],7,1,&A) A mf=mfinit([12,3,-4],0);F=mfbasis(mf)[1]; V=mfslashexpansion(mf,F,[1,1;4,5],4,1) mf=mfinit([12,3,-4],1); mfslashexpansion(mf,F,[1,1;4,5],4,1)==V mf=mfinit([4,7,-4]); B=mfbasis(mf); mfslashexpansion(mf,B[1],[0,-1;4,0],5,1,&A) A mf=mfinit([256,2]);f=mfeigenbasis(mf)[5]; mfslashexpansion(mf,f,[1,0;64,1],3,1,&A) A mf=mfinit([28,3/2],1);F=mfbasis(mf)[1];mf2=mfinit([56,3/2],1); mfslashexpansion(mf2,F,[1,0;1,1],5,0) mf=mfinit([96,2,8], 0); mfa = mfatkininit(mf,3); mfa[2] mfa[3] mfa = mfatkininit(mf,32); mfa[2] mfa[3] mf=mfinit([45,3,Mod(2,5)],0); mfa = mfatkininit(mf,9); factor(charpoly(mfa[2])) mfa[3] mf=mfinit([12,7,Mod(3,4)],0); mfatkineigenvalues(mf,3) mf=mfinit([24,3,-3],0); mfatkineigenvalues(mf,24) mf=mfinit([5,60],0); mfatkineigenvalues(mf,5) E4=mfEk(4); mf=mfinit([2,4]); mfslashexpansion(mf,E4,[0,-1;1,0],10,0) mf=mfinit([58,2], 0); F=mfeigenbasis(mf)[1]; round(mfslashexpansion(mf,F,[0,-1;58,0],10,0)) mf=mfinit([79,1,-79]); F=mfbasis(mf)[1]; 79 * lift(bestapprnf(mfslashexpansion(mf,F,[0,-1;1,0],5,0), x^2+79)) mf=mfinit([24,3,-3], 0); mfatkininit(mf,24)[2] [mf,F,coe]=mffromell(ellinit([-1,1]));coe vec(F) mfcoefs(F,6,2) [mf,F,coe]=mffromqf(2*matid(10));coe vec(F) mfcoefs(F,6,2) [mf,F,coe]=mffromqf(2*matid(2),x^4-6*x^2*y^2+y^4); vec(F) [mf,F,coe]=mffromqf(Mat); vec(F) [mf,F,coe]=mffromqf(2*matid(2),(x+I*y)^3); vec(F) [mf,F,coe]=mffromqf(2*matid(2),3); vec(F) mfwt1all(N,mf)= { for(i=1,#mf, my(vtf = mf[i][3], [G,c] = mf[i][1][3], chi = znconreyexp(G,c)); mf[i] = [chi, vector(#vtf,j,lift(vec(vtf[j])))] );print(N,": ",mf); } for(N=1,150,my(mf=mfinit([N,1,0],1));if(#mf,mfwt1all(N,mf))); for(N=1,150,print1([N,mfdim([N,1,-1],1),mfdim([N,1,-1],0)]," ")); mfdim([23,1,0]) mfdim([23,1,0],0) mfdim([23,1,0],1) mfdim([23,1,0],2) mfdim([23,1,0],3) mfdim([46,1,0],2) G=znstar(23,1); w=[[G,v] | v<-chargalois(G)]; mfdim([23,1,w],0) mfdim([23,1,w],1) mfdim([23,1,w],2) mfdim([96,2,-1],0) mfdim([96,2,-1],1) mfdim([96,2,-1],2) mfdim([96,2,-1],3) mfdim([96,2,-1],4) mfdim([96,2,0],0) mfdim([96,2,0],1) mfdim([96,2,0],2) mfdim([96,2,0],3) mfdim([96,2,0],4) G=znstar(96,1); w=[[G,v] | v<-chargalois(G)]; mfdim([96,2,w],0) mfdim([96,2,w],1) mfdim([96,2,w],2) mfdim([96,2,w],3) mfdim([96,2,w],4) mfdim([240,1,-1],1) \\ regressions mfdim(mfinit([154,1,0],1)[1]) mfinit([248,1,0],1); mfdim([455,1,Mod(94,455)],0) T=mfTheta();vec(T) mfT = mfinit(T); mfeval(mfT,T,[0,1/2,1,oo, (38+I)/85.]) T=mfTheta(Mod(2,7)); vec(T) mfparams(T) T=mfTheta(Mod(2,5)); vec(T) mfparams(T) E=mfEk(10); vec(E) D=mfDelta(); vec(D) mfparams(mfD) vec(mfshift(D,1)) mftaylor(D,10) mftaylor(D,10,1) E4=mfEk(4); E6=mfEk(6); N=mflinear([mfmul(mfmul(E4,E4),E4), mfmul(E6,E6)], [1,-1]); mf=mfinit(N); vec(N) == vec(mflinear(mf,N)) vec(mfdiv(N, D)) N=mflinear([mfpow(E4,3), mfpow(E6,2)], [1,-1]); vec(N) mfcoefs(mfderiv(E6),6) mfcoefs(mfderiv(E6,-1),6) mfcoefs(mfderivE2(E6),6) f = mfbracket(mfbd(E4,4), mfTheta(), 1); vec(f) mfcoefs(mfbracket(E4,E6,1),10)/(-3456) mf = mfinit([7,3,Mod(6,7)], 0); mfeigenbasis(mf); mf=mfinit([10,7,[Z5,2]], 0); mffields(mf) [f1,f2]=mfeigenbasis(mf); vE=mfembed(f1) mfembed(vE,mfcoefs(f1,4)) mfembed(mf) vE=mfembed(f2); #vE mfembed(vE[1],mfcoefs(f2,4)) mfembed(vE[2],mfcoefs(f2,4)) mfembed(vE[1], [1,t;y,1/2]) mfperiodpol(mf,f1) f1=mfsymbol(mf,f1); f2=mfsymbol(mf,f2); mfperiodpol(mf,f1) mfperiodpol(mf,f2) mfsymboleval(f1,[0,oo]) mfsymboleval(f1,[1/2 + I/10000,oo]) mfsymboleval(f1,[1/2 + I/20,oo]) mfsymboleval(f1,[1/2 + I/(20+1e-10),oo]) mfsymboleval(f1,[1/3,1/2]) mfsymboleval(f2,[1/3,1/2]) mfpetersson(f1) m=mfpetersson(f2); if (abs(m[2,1]) < 1e-38, m[2,1]=0); if (abs(m[1,2]) < 1e-38, m[1,2]=0); m normlp(mfpetersson(f1,f2)) < 1e-38 normlp(mfpetersson(f2,f1)) < 1e-38 L=mfmanin(f2)[1]; liftpol(L[1]) L[2][3] FS5=mfsymbol(mfeisenstein(4,1,5)); FS3=FS5[3]; for(i=1,#FS3,print(FS3[i])); mfsymboleval(FS5,[0,oo]) mfsymboleval(FS5,[1/5,oo]) FS16=mfsymbol(mfeisenstein(4,-4,-4)); mfsymboleval(FS16,[0,oo]) mfsymboleval(FS16,[1/4,oo]) mfsymboleval(FS16,[1/4,oo],[0,-1;1,4]) mfsymboleval(FS16,[0,oo],[0,-1;1,2]) mfatkineigenvalues(mf,1) mfatkineigenvalues(mf,2) mfatkineigenvalues(mf,5) mfatkineigenvalues(mf,10) mfparams(mf) #mfbasis(mf) liftpol(mfcoefs(mfbasis(mf)[1], 9)) F = mfeigenbasis(mf); #F liftpol(mfcoefs(F[1], 9)) liftpol(mfcoefs(F[2], 9)) mfcoefs(mffrometaquo([1,2;11,2]),10) f=mffrometaquo([864,6;432,-3;288,-2;144,1]); mfcoefs(f,11,12) mfcoefs(f,12,12) F=mffrometaquo([1,8;2,-2;4,2;6,2;12,2]); mf=mfinit([12,6],1); mftobasis(mf,F) F=mffrometaquo([1,-16;2,68]); mf=mfinit([4,26],1); F2=mfhecke(mf,F,2); mf2=mfinit([2,26],1); mftobasis(mf2,F2) mfcoefs(mffrometaquo(matrix(0,2)),5) mfdim(mfinit([24,4,Mod(23,24)],1),1) data = [63,2, Mod(46,63)]; B=mfbasis(mfinit(data,3)); MF = mfinit(data,4); lift(mftobasis(MF,B[3])) mfsturm(MF) charpoly(mfheckemat(MF,2)) mfsturm(mfinit([1,4])) mfgaloistype([11,1,1]) mfgaloistype([148,1,Mod(105,148)]) mfgaloistype([71,1, -71]) mf = mfinit([71,1, -71]); mfgaloistype(mf) mfgaloistype([124,1, Mod(67,124)]) \\ slow: ~ 10s, but needed to reproduce regression /* mf=mfsplit(mfinit([633,1,Mod(71,633)],1)); mfgaloistype(mf, mfeigenbasis(mf)[2]) mf=mfsplit(mfinit([675,1,Mod(161,675)],1)); mfgaloistype(mf, mfeigenbasis(mf)[1]) */ see(L) = for(i=1,#L, my(f=L[i]); print([mfparams(f), mfcoefs(f,10)])); L=mfeigensearch([[1..40],2],[[2,1],[3,-1]]); see(L) L=mfeigensearch([[1..40],2],[[2,Mod(1,3)],[3,Mod(2,4)]]); see(L) L=mfeigensearch([[1..38],2],[[2,-1],[11,-6]]); see(L) L=mfeigensearch([[1..16],3],[[2,0]]); see(L) V=mfsearch([[11..40],2],[0,1,2,3,4],1); for(i=1,#V,print([mfparams(V[i])[1..3],mfcoefs(V[i],10)])); V=mfsearch([60,2],[0,1,2,3,4,5,6], 1); #V mfcoefs(V[1],5) charpoly(mfheckemat(mfinit([106,2],1),2)) G=znstar(164,1); L=[chi | chi <- chargalois(G,164), zncharisodd(G,chi)]; apply(chi->charorder(G,chi),L) mfdim([164, 1, apply(x->[G,x], L)],0) mfdim([667, 1, [Mod(45,667)]],0) mfdim([329, 1, [Mod(46,329)]],0) mfdim([484, 1, [Mod(3,484)]],0) mfdim([191, 1, [Mod(190,191)]],0) mfdim([195, 1, [Mod(194,195)]],0) N=4; L=mfcosets(N) mftocoset(N, [1,1;2,3], L) mfcosets(mf23) /* regressions */ mf=mfinit([77,1, Mod(20,77)],0); lift(mfcoefs(mf[3][1],10)) mfgaloistype(mf) mf=mfinit([196,1,Mod(67,196)],0);mfdim(mf) mf=mfinit([297,1, Mod(10,297)],0); lift(mfcoefs(mf[3][1],10)) mfgaloistype(mf) mf=mfinit([416,1, Mod(159,416)],1);mfdim(mf) \\ oo loop in Zab_indexrank mf=mfinit([72,2,Mod(11,72)],0);mfdim(mf) \\ division by 1 in mfheckematwt1 mf=mfinit([283,1,-283],0); mfdim(mf) mfheckemat(mf,[2,3]) \\ Tests lfunmf E4=mfEk(4);E6=mfEk(6);D=mfDelta(); mf=mfinit([1,4],3); mfeval(mf,E4,I) mfeval(mf,E4,I/10) mf12=mfinit([1,12],3); mfeval(mf12,mfEk(12),I) L4=lfunmf(mf, E4); [lfun(L4,0),lfun(L4,1)*Pi^2/zeta(3),lfun(L4,4)/zeta(4)] L6=lfunmf(mfinit([1,6],3), E6); [lfun(L6,0),lfun(L6,1)*Pi^4/zeta(5),lfun(L6,6)/zeta(6)] L12=lfunmf(mfinit([1,12],0), D); omp=lfunlambda(L12,3) vector(6,i,bestappr(lfunlambda(L12,2*i-1)/omp)) omm=lfunlambda(L12,2) vector(5,i,bestappr(lfunlambda(L12,2*i)/omm)) L18=lfunmf(mfinit([1,18],0), mfmul(D,E6)); omp=lfunlambda(L18,3); vector(9,i,bestappr(lfunlambda(L18,2*i-1)/omp)) omm=lfunlambda(L18,2) vector(8,i,bestappr(lfunlambda(L18,2*i)/omm)) mf = mfinit([25,3,Mod(2,5)],0); F = mfbasis(mf)[1]; L=lfunmf(mf,F); lfun(L,1) mf=mfinit(D); PP=mfperiodpol(mf,D,-1);cP=polcoeff(PP,1) PP/=cP;bestappr(PP) PM=mfperiodpol(mf,D,1);cM=polcoeff(PM,0) PM/=cM;bestappr(PM) Ds = mfsymbol(mf,D); DS=mfpetersson(Ds) [pols,oms]=mfmanin(Ds); pols oms[3] bestappr(DS/(oms[1]*oms[2]/I), 10^8) mf=mfinit([11,2],1); fs=mfsymbol(mf,mfbasis(mf)[1]); DS=mfpetersson(fs) [pols,oms]=mfmanin(fs); pols oms[3] mf=mfinit([11,4],1); fs=mfsymbol(mf,mfbasis(mf)[1]); mfpetersson(fs) real(mfpetersson(fs, mfsymbol(mf,mfbasis(mf)[2]))) mf=mfinit([12,3,-4],1); fs=mfsymbol(mf,mfbasis(mf)[1]); real(subst(fs[3][24],x,x/I)) mfpetersson(fs) mfsymboleval(fs,[2/5,3/4]) mf=mfinit([12,6,12],1); fs=mfsymbol(mf,mfbasis(mf)[5]); real(subst(fs[3][14],x,x/I)) mfpetersson(fs) mfsymboleval(fs,[2,3;5,4]) mfsymboleval(fs,[0,0]) mfsymboleval(fs,[I,2*I]) mfsymboleval(fs,[0,oo],[2,0;0,1]) mfsymboleval(fs,[I,2*I],[2,0;0,1]) mfperiodpolbasis(12) mfperiodpolbasis(12,1) mfperiodpolbasis(12,-1) mfperiodpolbasis(2) mfperiodpolbasis(-1) mf=mfinit([23,4],0); [f1,f2]=mfeigenbasis(mf); F=mfsymbol(mf,f1); mfeval(mf,f2,0.9995346163+0.02156773223*I) \\ regression mfpetersson(F) mf=mfinit([23,2],0); f = mfeigenbasis(mf)[1]; F = mfsymbol(mf, f); mfslashexpansion(mf,f,[1,0;0,1],5,1) mfcuspisregular(mf,1/2); L=liftpol(mfmanin(F)); [v[1] | v<-L] [v[2][3] | v<-L] mf=mfinit([7,4,Mod(2,7)], 0); F=mfsymbol(mf, mfeigenbasis(mf)[1]); L=mfmanin(F) mfcusps(mf) mf = mfinit([37,2],4); f=mfbasis(mf)[2]; s=mfsymbol(mf,f); mfpetersson(s) T=mfTheta();mf=mfinit([12,1/2]);CU12=mfcusps(12) mfcusps(mf) apply(x->mfcuspwidth(mf,x), CU12) apply(x->mfcuspisregular(mf,x), CU12) apply(x->mfcuspisregular([12,2,-4],x), CU12) apply(x->mfcuspval(mf,T,x),CU12) mf=mfinit([12,6,12],1);F=mfbasis(mf)[5]; apply(x->mfcuspval(mf,F,x),CU12) mf=mfinit([12,3,-4],1);F=mfbasis(mf)[1]; apply(x->mfcuspval(mf,F,x),CU12) D=mfDelta();F=mfderiv(D); G=mfmul(D,mfEk(2));mfisequal(F,G) p(mf,f) = mfdescribe(f,&g); concat([mfparams(f), mfspace(mf,f), [mfdescribe(f)], apply(mfdescribe,g[1])]); F2=mfeisenstein(7,-3); p(mfinit(F2,3),F2) F3=mfeisenstein(7,-3,5); p(mfinit(F3,3),F3) F4=mfEk(4); p(mfinit(F4,3),F4) [mf,F5]=mffromqf([2,1;1,6]); p(mf,F5) T=mfTheta(); mfT = mfinit(T); p(mfT, T) p(mfT, mfhecke(mfT,T,9)) F6=mfDelta(); p(mfD,F6) F7=mffrometaquo([1,2;11,2]); p(mfinit(F7),F7) [mf,F8]=mffromell(ellinit([0,1,1,9,1])); p(mf,F8) p(mf,mfadd(F7,F8)) p(mf,mfpow(F2,3)) p(mf,mfmul(F2,F3)) p(mfD,mfbracket(F4,F4,2)) p(mf,mflinear([F7,F8],[1,-1])) p(mf,mfdiv(F3,F2)) p(mf,mfshift(F6,1)) p(mf,mfderiv(F4)) p(mfD,mfderivE2(F4,4)) p(mf,mftwist(F4,5)) p(mfD,mfhecke(mfD,F6,5)) p(mfinit([3,4],3),mfbd(F4,3)) mf=mfinit([6,2],3);B=mfbasis(mf); for(i=1,#B,print(p(mf,B[i]))); mf=mfinit([24,4]);B=mfbasis(mf); for(i=1,#B,print(p(mf,B[i]))); apply(x->mfconductor(mf,x),B) mf=mfinit([23,1,-23],1); f=mfbasis(mf)[1]; p(mf,f) mfpetersson(mfsymbol(mf,f)) mf=mfinit([92,1,-23],1); mfconductor(mf,f) mf=mfinit([96,2]); L=mfbasis(mf); mf0=mfinit(mf,0); mftobasis(mf0,L[1],1) mffromlfun(lfuncreate(x^2+1)) F=mffromell(ellinit([0,1]))[2]; mfisCM(F) mf = mfinit([39,1,-39],0); F=mfeigenbasis(mf)[1]; mfisCM(F) \\ Half-integral weight dim2(N,k,space)= { my(L=mfdim([N,k+1/2,0],space)); if (!k && space==1, for(i=1,#L,print1(L[i][2..3]," ")), for(i=1,#L,print1(L[i][3]," ")) ); } for(N=1,300,dim2(4*N,0,1));print(); for(N=1,10,dim2(4*N,0,3)); for(N=1,10,dim2(4*N,0,4)); for(N=1,10,dim2(4*N,1,1)); for(N=1,10,dim2(4*N,1,3)); for(N=1,10,dim2(4*N,1,4)); for(N=1,10,dim2(4*N,2,1)); for(N=1,10,dim2(4*N,2,3)); for(N=1,10,dim2(4*N,2,4)); for(N=1,10,dim2(4*N,3,1)); for(N=1,10,dim2(4*N,3,3)); for(N=1,10,dim2(4*N,3,4)); for(N=1,10,print1(mfdim([4*N,3+1/2,-1],1)," ")); for(N=1,10,print1(mfdim([4*N,3+1/2,-1],3)," ")); for(N=1,10,print1(mfdim([4*N,3+1/2,-1],4)," ")); L=mfinit([12,7/2,0],1); vector(#L,i,[vec(f) | f<-mfbasis(L[i])]) mf=mfinit([24,5/2],1); mfcoefs(mf,5) mf=mfinit([28,5/2],1); B=mfbasis(mf); mfcoefs(mf,5) for(i=1,#B,print(vec(B[i]))); mf=mfinit([28,5/2,Mod(2,7)],1); B=mfbasis(mf); [G,chi] = znchar(mf); chi [G,chi] = znchar(B[1]); chi mfslashexpansion(mf, B[1], [1,0;2,1], 5, 1) mfheckemat(mf,4) for(i=1,#B,print(lift(vec(B[i])))); T=mfTheta(); T2=mfmul(T,T); mfparams(T2) mf=mfinit([20,3/2]); B=mfbasis(mf); for(i=1,#B,print(lift(vec(B[i])))); mf=mfinit([4,5/2]);#mfbasis(mf) mfparams(mffrometaquo([1,24])) mfparams(mffrometaquo([2,12])) mfparams(mffrometaquo([3,8])) mfparams(mffrometaquo([4,6])) mfparams(mffrometaquo([6,4])) mfparams(mffrometaquo([12,2])) mfparams(mffrometaquo([24,1])) F=mffrometaquo([8,3]);mfparams(F) mf=mfinit([64,3/2]); mftobasis(mf,F) V=mfslashexpansion(mf,F,[0,-1;1,0],10,0,&A); [A,V] V=mfslashexpansion(mf,F,[-1,0;2,-1],10,0,&A); [A,V] mfeval(mf,F,I) mf=mfinit([36,5/2],1);mfparams(mfbasis(mf)[3]) K=mfkohnenbasis(mf); nbcol=matsize(K)[2] K~ mfparams(mfshimura(mf,mflinear(mf,K[,1]))[2]) mfparams(mfshimura(mf,mflinear(mf,K[,2]),5)[2]) (mfcoefs(mf,20)*K)~ mf=mfinit([60,5/2],1);bij=mfkohnenbijection(mf);bij[2] bij[4] mfkohneneigenbasis(mf,bij)[2..3] mf=mfinit([52,3/2,Mod(15,52)],1);mfkohnenbijection(mf)[2..4] mf=mfinit([12,5/2]); apply(x->mfconductor(mf,x),mfbasis(mf)) mfconductor(mf,mflinear(mf,[0,1,2,4,8])) mf=mfinit([12,5/2],1); F=mfbasis(mf)[1]; FSbug = mfsymbol(mf,F); mfpetersson(FSbug) T5S=mfsymbol(mfTheta(5));Pi/mfpetersson(T5S) F=mffrometaquo([1,-2;2,5;4,-2]);mfparams(F) F=mffrometaquo([1,2;2,-1]);mfparams(F) mf=mfinit(F);mftobasis(mf,F) E1=mfeisenstein(4,-3,-4); mfdescribe(E1) E2=mfeisenstein(3,5,-7); mfdescribe(E2) E3=mfderivE2(mfmul(E1,E2), 3); mfdescribe(E3) mfdescribe(mfDelta()) mfdescribe(mfEk(2)) mfdescribe(mfhecke(mfinit([1,2]),mfEk(2),3)) [mfdescribe(mfinit([37,4],i)) | i<-[0..4]] [mfdescribe(mfinit([16,3/2],i)) | i<-[1,4]] E=mfmul(mfeisenstein(4,-3,-4),mfeisenstein(3,1,-3)); mfdescribe(E,&g); apply(mfdescribe,g[1]) T5=mfpow(T,5); [mf,TSHI,res]=mfshimura(mfinit(T5),T5); mfcoefs(TSHI,10) mftobasis(mfinit(TSHI,4),TSHI) F4=mfmul(mfbd(T,4),mffrometaquo([8,1;16,1])); F4S=mfshimura(mfinit(F4),F4)[2];mfcoefs(F4S,20) EH=mfEH(13/2); mfdescribe(EH); mfcoef(EH,1001) mfcoef(EH,13*5^2) mfcoefs(EH,15,2) EH=mfEH(3/2); \\ to test hclassno6u mfcoefs(EH,2,10^8) mfcoefs(EH,2,10^8+3) mf=mfinit(EH); vec(EH) vec(mfEH(5/2)) vec(mfEH(7/2)) vec(mfEH(9/2)) vec(mfEH(11/2)) vec(mfEH(13/2)) vec(mfEH(15/2)) vec(mfEH(19/2)) vec(mfhecke(mf, EH, 6)) vec(mfhecke(mf, EH, 4)) mf2=mfinit([12,3/2]); vec(mfhecke(mf2, EH, 4)) vec(mfhecke(mf, EH, 9)) vec(mfhecke(mf2, EH, 9)) vec(mfhecke(mf, EH, 25)) vec(mfhecke(mf, EH, 3^6)) vec(mfhecke(mf2, EH, 25)) vec(mfhecke(mfT, mfTheta(),4)) vec(mfhecke(mfT, mfTheta(),3^4)) mf=mfinit([32,5/2,8],1); F=mfbasis(mf)[1]; mfa = mfatkininit(mf,32); vec(mfatkin(mfa,F)) mfa[3] mffrometaquo([1,1],1) mf=mfinit([11,4]);B=mfbasis(mf)[1..2]; FE1=mflinear(B,[1,-1]);FE2=mflinear(B,[1,-11^4]); FE1S=mfsymbol(mf,FE1);FE2S=mfsymbol(mf,FE2); real(mfpetersson(FE1S,FE2S)) E=mfeisenstein(3); mf=mfinit([3,3]); ES=mfsymbol(mf,E); mfsymboleval(ES,[1,I]) mfcuspval(mf,E,1/2) mffrometaquo([1,-24]) mfcoefs(mffrometaquo([1,-24],1),6) getcache()[,1..4] \\ ERRORS, leave at end of bench mftobasis(mf0,L[1]) mfdim([4,1/2],0) mfdim([4,1/2],2) mfdim([4,1/2],5) mfeisenstein(2,1.0) mfeisenstein(2,[0,0]) mfinit([1,1.0]) L=mfeigenbasis(mfinit([14,6,Mod(9,14)],0)); mfmul(L[1],L[2]) mfcuspwidth(0,0) mfparams(mfadd(F2,F3)) mfparams(mfadd(F4,F6)) mfinit([23,1,Mod(22,45)],0); mfinit([23,2,Mod(22,45)],0); mfinit([7,1,-7],2); mfinit([7,1,-7],5); mfinit([1,2],5) mfgaloistype([11,1,Mod(2,11)], mfeisenstein(1,1,Mod(2,11))) D=mfDelta(); mfdiv(D,mfpow(D,2)) mfeval(mfD,D,-I) mftonew(mfD,1) T=mftraceform([96,6],4); mfshimura(mfinit(T5),T5,-3) mf=mfinit([1,4],3); mftonew(mf,E4) mffields(mf) mfdiv(1,mfTheta()) mfdiv(D,mftraceform([1,3])) mfcosets(1.) mf=mfinit([1,0]);F=mfbasis(mf)[1];mfsymbol(mf,F); mf=mfinit([12,5/2],1); F=mfbasis(mf)[1]; mfmanin(FSbug) mfsymboleval(FSbug,[0,1]) mfgaloistype([4,1,-4],x) pari-2.11.2/src/test/in/minim0000644000175000017500000001000513201017466014362 0ustar billbill{d=[4,2,-2,-2,2,1,-2,2,2; 2,4,-2,0,0,0,-1,0,2; -2,-2,4,2,-2,1,1,-1,-2; -2,0,2,4,-3,1,0,-2,0; 2,0,-2,-3,4,-1,0,2,0; 1,0,1,1,-1,4,0,-1,1; -2,-1,1,0,0,0,4,-2,-2; 2,0,-1,-2,2,-1,-2,4,0; 2,2,-2,0,0,1,-2,0,4];} qfperfection(d) {d=[4,2,-2,2,2,-2,-1,0;2,4,-2,0,2,-2,1,-1; -2,-2,4,-2,0,2,1,-1; 2,0,-2,4,1,0,-2,0; 2,2,0,1,4,-1,1,-2;-2,-2,2,0,-1,4,-1,-1; -1,1,1,-2,1,-1,4,0;0,-1,-1,0,-2,-1,0,4];} qfperfection(d) d=[2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1;-1,2,1,0,1,1,1,1,1,1,1,1;-1,1,2,1,1,1,1,1, 1,1,1,1;-1,0,1,2,1,1,1,1,1,1,1,1;-1,1,1,1,2,1,1,1,1,1,1,1;-1,1,1,1,1,2,1,1,1,1,1 ,1;-1,1,1,1,1,1,2,1,1,1,1,1;-1,1,1,1,1,1,1,2,1,1,1,1;-1,1,1,1,1,1,1,1,2,1,1,1;-1 ,1,1,1,1,1,1,1,1,2,1,1;-1,1,1,1,1,1,1,1,1,1,2,1;-1,1,1,1,1,1,1,1,1,1,1,2]; qfperfection(d) d=[84,-42,42,-34,49,42,44,-5,42,-42,42,34;-42,84,-42,-8,-44,-42,-47,-20,-22,0,-17,8;42,-42,84,-34,49,42,47,-22,22,-42,22,20;-34,-8,-34,84,3,-34,-31,0,8,34,-5,-42;49,-44,49,3,98,49,49,-27,49,-27,49,-8;42,-42,42,-34,49,84,42,-8,22,-20,24,-8;44,-47,47,-31,49,42,94,20,2,-22,2,25;-5,-20,-22,0,-27,-8,20,84,-42,42,-5,-8;42,-22,22,8,49,22,2,-42,84,-42,42,9;-42,0,-42,34,-27,-20,-22,42,-42,84,-5,-28;42,-17,22,-5,49,24,2,-5,42,-5,84,1;34,8,20,-42,-8,-8,25,-8,9,-28,1,84]; qfperfection(d) d = [11870535336,4926369655,32404766,5833735188,-260286973,1176994945,-938673930,1133212506,-1074526606,-70224083,-516302409,2824815072,-4372545965,-3541960809,-934179491,1051267712;4926369655,11870535336,-1490432686,-875900356,3641011352,-133471097,5248732172,5339909303,1977366972,2112029217,1618397291,1453763043,-5074494971,3402204872,-6089917,-2536340118;32404766,-1490432686,11870535336,123881942,1472835948,538053943,-2072520281,-2111014772,-243328180,66329388,-1668343637,5366171257,-1644082716,1999937160,1862466413,-2684624269;5833735188,-875900356,123881942,11870535336,-4482992193,724356870,-2581885607,-1123344860,-5909559285,-374057682,-1737269060,1373350629,-685882364,-2860185796,1915679243,-2582189975;-260286973,3641011352,1472835948,-4482992193,11870535336,-3382162923,-2727082036,-172926336,3957014148,4123782659,-869026456,-712184755,1975235830,598346444,-803583682,764543726;1176994945,-133471097,538053943,724356870,-3382162923,11870535336,4149099372,-1345152733,3238996158,-1859449765,788927568,627981303,-1997619722,-5100674624,1082079081,-4600113518;-938673930,5248732172,-2072520281,-2581885607,-2727082036,4149099372,11870535336,2778219046,565855490,-4509773947,2630869581,161812815,-2518706476,2620761340,1350174537,-1070307221;1133212506,5339909303,-2111014772,-1123344860,-172926336,-1345152733,2778219046,11870535336,1405373352,-94842121,5935267668,1644886404,-4169157373,1191448802,400673054,-137185759;-1074526606,1977366972,-243328180,-5909559285,3957014148,3238996158,565855490,1405373352,11870535336,-1017421319,-2747041871,-2019274686,1090295757,2591545854,433617674,63706423;-70224083,2112029217,66329388,-374057682,4123782659,-1859449765,-4509773947,-94842121,-1017421319,11870535336,-570490848,1731611845,-2658074571,-1297231573,-350469672,-40728837;-516302409,1618397291,-1668343637,-1737269060,-869026456,788927568,2630869581,5935267668,-2747041871,-570490848,11870535336,2791532769,26571128,-1302311714,1214830887,1283425367;2824815072,1453763043,5366171257,1373350629,-712184755,627981303,161812815,1644886404,-2019274686,1731611845,2791532769,11870535336,-3163139204,110178163,-49759695,-1512817003;-4372545965,-5074494971,-1644082716,-685882364,1975235830,-1997619722,-2518706476,-4169157373,1090295757,-2658074571,26571128,-3163139204,11870535336,-55032693,-2820423865,4651789746;-3541960809,3402204872,1999937160,-2860185796,598346444,-5100674624,2620761340,1191448802,2591545854,-1297231573,-1302311714,110178163,-55032693,11870535336,5683626972,-2169747194;-934179491,-6089917,1862466413,1915679243,-803583682,1082079081,1350174537,400673054,433617674,-350469672,1214830887,-49759695,-2820423865,5683626972,11870535336,-5697137302;1051267712,-2536340118,-2684624269,-2582189975,764543726,-4600113518,-1070307221,-137185759,63706423,-40728837,1283425367,-1512817003,4651789746,-2169747194,-5697137302,11870535336]; qfperfection(d) pari-2.11.2/src/test/in/subfields0000644000175000017500000000657013326135265015253 0ustar billbill/* test(n)= { p = x^n-x-1; c = p; for (i=1,n-3, c = polcompositum(p, c); c = c[#c]); c; } nfsubfields(test(5)); */ /* From Hulpke and Klueners's papers */ {v=[ x^6 + 108, x^8 - 12*x^6 + 23*x^4 - 12*x^2 + 1, x^8 - 10*x^4 + 1, x^8 + 4*x^6 + 10*x^4 + 12*x^2 + 7, x^9 - 18*x^8 + 117*x^7 - 348*x^6 + 396*x^5 + 288*x^4 + 3012*x^3 + 576*x^2 + 576*x - 512, x^10 + 38*x^9 - 99*x^8 + 1334*x^7 - 4272*x^6 + 9244*x^5 - 8297*x^4 + 1222*x^3 + 1023*x^2 - 74*x + 1, x^10 - 20*x^9 + 80*x^8 + 200*x^7 - 3770*x^6 + 872*x^5 + 29080*x^4 + 36280*x^3 - 456615*x^2 + 541260*x - 517448, x^10 - 10*x^8 + 20*x^7 + 235*x^6 + 606*x^5 + 800*x^4 + 600*x^3 + 270*x^2 + 70*x + 16, x^12 + 6*x^9 + 4*x^8 + 8*x^6 - 4*x^5 - 12*x^4 + 8*x^3 - 8*x + 8, x^12 + 9*x^11 + 3*x^10 - 73*x^9 - 177*x^8 - 267*x^7 - 315*x^6 - 267*x^5 - 177*x^4 - 73*x^3 + 3*x^2 + 9*x + 1, x^12 - 34734*x^11 + 401000259*x^10 - 1456627492885*x^9 - 2537142937228035*x^8 + 187620727556 79375516*x^7 - 812368636358864062944*x^6 - 70132863629758257512231931*x^5 + 25834472514 893102332821062085*x^4 + 76623280610352450247247939584745*x^3 - 45080885015422662132 515763499758450*x^2 - 2070499552240812214288316981071818900*x - 5505057590977785454 85364826246753544, x^15 + 20*x^12 + 125*x^11 + 503*x^10 + 1650*x^9 + 3430*x^8 + 4690*x^7 + 4335*x^6 + 2904*x^5 + 1400*x^4 + 485*x^3 + 100*x^2 + 15*x + 1, x^32-2, x^27 - 120*x^25 - 63*x^24 + 5673*x^23 + 5181*x^22 - 138003*x^21 - 167184*x^20 + 1865730*x^19 + 2668613*x^18 - 14070078*x^17 - 21889917*x^16 + 57688596*x^15 + 89482089*x^14 - 132575217*x^13 - 190829625*x^12 + 164200812*x^11 + 215956974*x^10 - 86796519*x^9 - 129504396*x^8 + 1575183*x^7 + 32931993*x^6 + 9928740*x^5 + 49968*x^4 - 372144*x^3 - 50736*x^2 - 1344*x + 64, x^12 - 3*x^10 + 8*x^8 - 14*x^6 + 21*x^4 - 23*x^2 + 26, x^24 +8*x^23 -32*x^22 -298*x^21+624*x^20+4592*x^19-8845*x^18-31488*x^17+76813*x^16+ 65924*x^15 - 265616*x^14 + 48348*x^13 + 385639*x^12 - 394984*x^11 - 20946*x^10 + 369102*x^9 - 362877*x^8+183396*x^7+434501*x^6-194418*x^5+450637*x^4+125800*x^3-16401*x^2-45880*x+ 115151 /* x^60 + 36*x^59 + 579*x^58 + 5379*x^57 + 30720*x^56 + 100695*x^55 + 98167*x^54 - 611235*x^53 - 2499942*x^52 - 1083381*x^51 + 15524106*x^50 + 36302361*x^49 - 22772747*x^48 - 205016994*x^47 - 194408478*x^46 + 417482280*x^45 + 954044226*x^44 + 281620485*x^43 - 366211766*x^42 - 1033459767*x^41 - 8746987110*x^40 - 15534020046*x^39 + 23906439759*x^38 + 104232578583*x^37 + 31342660390*x^36 - 364771340802*x^35 - 547716092637*x^34 + 583582152900*x^33 + 2306558029146*x^32 + 998482693677*x^31 - 3932078004617*x^30 - 5195646620046*x^29 + 2421428069304*x^28 + 10559164336236*x^27 + 3475972372302*x^26 - 22874708335419*x^25 - 33428241525914*x^24 + 21431451023271*x^23 + 90595197659892*x^22 + 50882107959528*x^21 - 67090205528313*x^20 - 117796269461541*x^19 - 74369954660792*x^18 + 25377774560496*x^17 + 126851217660123*x^16 + 104232393296166*x^15 - 29072256729168*x^14 - 83163550972215*x^13 - 24296640395870*x^12 + 14633584964262*x^11 + 8865283658688*x^10 + 5364852154893*x^9 - 1565702171883*x^8 - 7601782249737*x^7 - 2106132289551*x^6 + 3369356619543*x^5 +3717661159674*x^4 +1754791133184*x^3 +573470363592*x^2 +74954438640*x + 3285118944 */ ,x^12-4*x^11-14*x^10+44*x^9+226*x^8+380*x^7-542*x^6-2620*x^5+4249*x^4-6312*x^3+13056*x^2-67392*x+97344 /* #1758 */ ];} { for (i=1,#v, P = v[i]; S = nfsubfields(v[i]); print(i,":", apply(x->poldegree(x[1]),S)); for(j=1,#S,s=S[j];if(subst(s[1],x,Mod(s[2],P)),error([P,s])))) } pari-2.11.2/src/test/in/content0000644000175000017500000000073513326135265014742 0ustar billbilldefault(realprecision,38); o=[2,1.0,Mod(1,3),2/3,ffgen(2^3),1/2+I/3,2+O(2^-3),1/2+O(2^3),quadgen(5)/3,Mod(x/2,x^2),2*x,2/x, Qfb(1,2,4),Qfb(-1,2,4),[2,3/4], [1,2;3/2,4], 1/2+x/y, [1/2+x/y], 1/(2*y) + O(x^2), y+O(y^2)]; test(f)= print(f); [ print(iferr(f(p),E,E)) | p<-o ]; test(denominator); test(x->denominator(x,1)); test(x->denominator(x,'y)); test(numerator); test(x->numerator(x,1)); test(x->numerator(x,'y)); test(content); test(x->content(x,1)); test(x->content(x,'y)); pari-2.11.2/src/test/in/pow0000644000175000017500000000122113326135265014064 0ustar billbilldefault(realprecision,38); (Mod(1,3)+I)^0 (Mod(1,9)+I*Mod(1,3))^0 (1/x)^0 [;]^0 Mat(2)^0 Mod(0,1)^0 Mod(2,3)^0 Qfb(2,0,-1)^0 Qfb(2,0,-1)^1 Vecsmall([3,2,1])^0 O(2)^1 O(2)^-2 (1/2)^-2 (-2/3)^-2 n=2^64; 1^n (-1)^n (-1)^(n+1) 2^n (1/2)^n Qfb(2,0,-1)^n Mod(x,polcyclo(7))^n O(x)^(1/2) (x^3+O(x^6))^(1/3) [2,3]^3. [2,3]~^3. Mat(2)^3. O(x^0)^(1/3) 0.^(1/2) Mod(2,3)^(1/2) Mod(2,3)^(1/3) Mod(1,4)^(1/2) (2+O(7^5))^(1/2) (3+O(7^5))^(1/2) a=2+O(7^3); a^a sqrt(1+O(2)) sqrt(1+O(2^3)) sqrt(Mod(2,4)) [0,1]^[1,2] [0,1]^[1,2]~ [0,1]^[1,1;2,3] (x+Mod(0,1))^0 2^(-1-10^-9) 2^Mod(2,(I*1E-28*x+1)) powers(Mod(2,11),10) powers(Pi,7) powers(3, 5, 2) powers(3,-1) powers(3,0) pari-2.11.2/src/test/in/qfbsolve0000644000175000017500000000115113036414402015071 0ustar billbillqfbeval(V,v)= { my(x,y); V=Vec(V);x=v[1];y=v[2]; V[1]*x^2+V[2]*x*y+V[3]*y^2; } bqfb(N=10000)= { my(p,d,r,V,q,q2,Q,Q2); for(i=1,N, until(!issquare(d) && (d%4==0 || d%4==1),d=random(4000)-2000); until(p==1 || kronecker(d,p)>=0, p=random(1000)-100; if(p<3,p=1,p=nextprime(p))); q=qfbprimeform(d,p); V=Vec(q); q2=Qfb(V[3],V[2],V[1]); until(Q!=0||Q2!=0,r=nextprime(random(30000)); Q=qfbsolve(q,r);Q2=qfbsolve(q2,r)); if(Q2==0||qfbeval(q2,Q2)!=r,print("qfbsolve(",q2,",",r,")!=",Q2);break); if(Q==0||qfbeval(q,Q)!=r,print("qfbsolve(",q,",",r,")!=",Q);break)); } bqfb(); pari-2.11.2/src/test/in/err0000644000175000017500000001316313447371554014066 0ustar billbillf(x) = 1/x; g(N) = for(i = -N, N, f(i)); g(10) print(); f=matsolve; f(Mat(0), Col(1)) print(); (matsolve)(Mat(0), Col(1)) print(); a.foo=1/(1+a^2); g(x)=[x.foo]; g(I) print(); (x->1/x)(0) print(); ecm(N,t,B)= { for(a=1,t, iferr( my(E=ellinit([0,0,0,a,1]*Mod(1,N))); ellmul(E,[0,1]*Mod(1,N),B), err,if(errname(err)=="e_INV",return(gcd(lift(component(err,2)),N)) ,error(err)))); } ecm(2^64+1,10,200!) ecm2(N,t,B)= { for(a=1,t, iferr( my(E=ellinit([0,0,0,a,1]*Mod(1,N))); ellmul(E,[0,1]*Mod(1,N),B), err,return(gcd(lift(component(err,2)),N)) ,errname(err)=="e_INV")); } ecm2(2^64+1,10,200!) rev(A) = my(B=Ser(A)); serreverse(B); iferr(rev([0,0,0,2,2,4,8,4,16,12]),E,0); \\ e_COPRIME T=t^2-2;p=2;A=x^2+1;B=[x+t,x+t];r=polhensellift(A,B,[p,T],6) \\ e_DIM / e_TYPE M = matid(2); M[,1] = 1 M[,3] = 1 M[,1] = [1,2] M[,1] = [1,2,3]~ M[1,] = 1 M[3,] = 1 M[1,] = [1,2]~ M[1,] = [1,2,3] [;][1,] [;][,1] 1[1] issquare(1,&v[1]) 1[1,1] 1[,1] issquare(1,&v[,1]) 1[1,] issquare(1,&v[1,]) v=Vecsmall([1]); v[2] = 1 v[1] = Pi v[1] = 2^64 v[Pi] = 1 \\ RgM_check_ZM M = [1.,0;0,1]; qflll(M,1) \\ RgV_check_ZV addprimes(1.) \\e_MODULUS nfalgtobasis(nfinit(t^3-2),Mod(t,t^2+1)) \\e_DIM vector(-1,i,0) vectorv(-1,i,0) vectorsmall(-1,i,0) matrix(-1,1,i,j,0) matrix(1,-1,i,j,0) next(-1) break(-1) v[-1] v[#v+1] subst(x,1,0) exp(1e40) exp(-1e40) exp(1/x) cos(1/x) sin(1/x) tan(1/x) cotan(1/x) atan(1/x) asin(1/x) acos(1/x) asinh(1/x) acosh(1/x) atanh(1/x) lngamma(x) besselj(2,1/x) besseljh(2,1/x) besselk(2,1/x) besselk(1/3,O(x)) besseln(2,1/x) besseln(1/3,O(x)) polylog(2,1/x) sqrt(x) sqrt(2+O(2^2)) sqrtn(x,3) sqrtn(2+O(2^2),3) log(x) log(0) abs(x+O(x^2)) real(Vecsmall([])) imag(Vecsmall([])) vecmax(Vecsmall([])) vecmax([]) vecmax([], &i) vecmin(Vecsmall([])) vecmin([]) vecmmin([], &i) vecmax(matrix(0,2)) L=List(); listput(L, x, -1) listinsert(L,x,-1) listinsert(L,x,10) listpop(L) ellj(Mod(1,2)) ellj(Qfb(1,1,1)) eta(1+O(2)) eta(1/x) K = nfinit(y^2+1); idealhnf(K, Qfb(1,1,1)) idealfactor(K, [;]) idealval(K, [;], idealprimedec(K,2)[1]); idealdiv(K,2,0, 1); valuation(Pi,2) x^Pi x^x 0^0. agm([],[]) sin(1/2+O(2^1)) cos(1/9+O(3^1)) exp(1/9+O(3^1)) G=[[Vecsmall([6,11,14,16,17,1,21,24,26,27,2,29,30,3,31,4,5,34,36,37,7,39,40,8,41,9,10,42,12,13,15,44,45,18,46,19,20,47,22,23,25,28,48,32,33,35,38,43]),Vecsmall([5,10,13,15,1,17,20,23,25,2,27,28,3,30,4,31,6,33,35,7,37,38,8,40,9,41,11,12,42,14,16,43,18,45,19,46,21,22,47,24,26,29,32,48,34,36,39,44]),Vecsmall([15,25,28,1,4,31,35,38,2,9,41,3,12,42,5,6,16,43,7,19,46,8,22,47,10,11,26,13,14,29,17,18,32,48,20,21,36,23,24,39,27,30,33,34,44,37,40,45]),Vecsmall([30,40,1,42,14,13,45,2,47,24,23,4,5,6,29,28,3,7,48,34,33,9,10,11,39,38,8,15,16,17,12,19,20,21,44,43,18,25,26,27,22,31,35,36,37,32,41,46]),Vecsmall([7,1,44,18,37,20,2,29,3,17,5,35,43,48,45,33,21,39,8,27,10,15,28,42,30,13,6,36,19,32,34,25,38,47,40,23,11,16,4,12,14,46,26,9,22,24,31,41])],Vecsmall([2,2,2,2,3])]; galoissubgroups(G) bnrstark(bnrinit(bnfinit(y^2+1),2)) bnrstark(bnrinit(bnfinit(y^2-2),[4,[1,1]])) quadray(-16,1) quadray(bnfinit(x^3-2),1) galoissubcyclo(-1) galoissubcyclo(6,Mod(1,3)) galoissubcyclo(6,[;]) galoissubcyclo(6,Mat(1)) galoissubcyclo(znstar(5),matid(2)) galoissubcyclo( [3, [3], [3]], Mat(3)) galoissubcyclo(bnrinit(bnfinit(y^2+1),1), 2) polsubcyclo(-1,2); polsubcyclo(2,-1); random(-1) znprimroot(0) sqrtint(-1) sqrtnint(-1,2) sqrtnint(2,-2) znprimroot(8) polroots(x^2+Mod(1,2)) polroots(0) polroots(Mod(1,2)) polrootsmod(x,x) prime(-2) addprimes(-1) padicappr(x^2+1+O(3^5), 1+O(5)) factorpadic(x^2+1,2,-1) polrootspadic(x^2+1,2,-1) ellinit([1+O(3),1+O(5)]) ellwp([1,I],I) ellsigma([1,I],x,1) ellsigma([1,I],1,1) E=ellinit([1,1]); ellap(E) ellap(E,1) ellap(E,'x) ellissupersingular(x,1) elltaniyama(E,-1) ellheight(E,[2,2]) Qfb(0,0,0) quadpoly(2) qfbprimeform(2,5) qfbcomp(Qfb(1,1,1),Qfb(1,0,2)) \\qfbcompraw(Qfb(21,1,2),Qfb(112,0,2)) galoisinit(x^2) galoisinit(2*x) ellL1(1,-1) ellheegner(ellinit([0,-1,1,-10,-20])) ellheegner(ellinit([0,0,1,-7,6])) substpol(x+O(x^2),x^3,x) intformal(1/(x^2+1)) component(x,-1) component(O(x),2) component(Vecsmall([]),1) component(x->x,6) polcoef(O(x),2) polcoef(x+O(x^2),2) polcoef([],2) matcompanion(0*x) matrixqz(Mat([1,2])) matrixqz(Mat(0)) vecextract([1],[-1]); vecextract([1],[2]); idealfrobenius(K,galoisinit(K),idealprimedec(K,2)[1]) nfisincl(x^2,x^2) polcompositum(x^2,x) rnfdedekind(K, x^2+x-1/3) hilbert(Mod(1,2),1) hilbert(Mod(1,3),Mod(1,5)) hilbert(Mod(1,3),2,0) znorder(0) znorder(Mod(2,4)) contfrac(1e100) contfrac(1.,[1],10) contfrac(1,,-1) contfracpnqn(matrix(3,1)); divisors(1/2) idealstar(K,0) idealstar(K,1/2) idealaddtoone(K,[[;]]) idealdiv(K,1,2,1) idealred(K,matid(2),[]) idealtwoelt(K,matid(2),1/2) rnf=rnfinit(K,x^2-y); rnfeltdown(rnf, x) matid(-1) polinterpolate([1,1],[2,3],Pi) modreverse(Mod(-x^3+9*x,x^4-10*x^2+1)) rnfnormgroup(bnrinit(bnfinit(K),9), x^3-2) concat([1,2],[3,4]~) concat([]) concat(List()) mathnfmod([1;2],2) removeprimes(2) forstep(a=1,2,0,) e=ellinit([1,1+O(31^2)]); e.omega e.eta e.area e=ellinit([0,1]); e.tate ellorder(e, [0,0]*Mod(1,2)) thue(x*(x^3-2),0); direuler(p=2, 10, 2/(1-p*X)) solve(x=0,1,x^2+1) warning(1) iferr(1/0,E,1,errname(E)=="e_DOMAIN") iferr(1/0,E,return(4)) iferr(1/0,E,1,break()) \\ backward compatibility. Eventually remove inv(x) = trap (e_INV, INFINITY, 1/x) inv(2) inv(0) trap (e_INV, INFINITY, log(0)) a=1; notafunc('a) a n=1<<10000; znlog(Mod(1,n),Mod(1,n+1)) Mod(0,n)^(-1) a=Mod(1,7)*x+y; b=Mod(1,7*y^2+7)*x+4; a*b a%b (a*x^2+b)^2 M=[Mod(1,7),1;0,Mod(x,7*x^2+7)]; matrank(M) matimage(M) matker(M); default(plothsizes,"[") default(plothsizes,"1") default(plothsizes,"[2,") default(plothsizes,"[2,]") default(plothsizes,"[2,3]") \\ succeeds pari-2.11.2/src/test/in/modsym0000644000175000017500000001267413326135265014605 0ustar billbillallocatemem(40*10^6) W2 = msinit(11,2,-1); W1 = msinit(11,2,1); W = msinit(11,2); msdim(W1) msdim(W2) msdim(W) msgetsign(W2) msgetsign(W1) msgetsign(W) msgetlevel(W) msgetweight(W) mshecke(W2, 2) mshecke(W1, 2) mshecke(W, 2) mshecke(W1, 11) M=msinit(1,12); msgetlevel(M) msgetweight(M) msgetsign(M) msatkinlehner(M,1) mscuspidal(M) msdim(M) mseisenstein(M) D = [0,1,0]~ \\ Delta mseval(M,D) mseval(M,D,[0,oo]) msfromcusp(M,0) msfromhecke(M, [[2,-24]]) mshecke(M,2) msissymbol(M,D) mslattice(M) msnew(M) mspathgens(M) mspathlog(M,[1/2,1/3]) mspetersson(M,D) mspolygon(M) msqexpansion(M,D) msstar(M) M=msinit(1,32,1); mssplit(M) E = ellinit([1,2]); [W,xpm] = msfromell(E); mseval(W,xpm[1],[1/2,1/3]) mseval(W,xpm[1],[1,1;2,3]) mseval(W,xpm[1],[1]) \\ BUG E = ellinit([0,-1,1,-10,-20]); [W,xpm] = msfromell(E,1); mseval(W,xpm,[1/2,1/3]) E=ellinit([1,-1,1,-1,-14]); [W,xpm] = msfromell(E,1); mseval(W,xpm) mseval(W,xpm,[0,1/3]) check_twist(e) = msfromell(ellinit(e))[2]; check_twist([0,1]) \\36a1 check_twist([0,-1,1,-7,10]) \\121b1 check_twist([1,-1,0,0,-5]) \\45a1 check_twist([0,0,1,-3,-5]) \\99d1 check_twist([0,0,1,0,-7]) \\27a1 \\17a1-4 vE=[[1,-1,1,-1,-14],[1,-1,1,-6,-4],[1,-1,1,-91,-310],[1,-1,1,-1,0]]; msfromell([ellinit(e)|e<-vE])[2] W = msinit(227,2,1); Wnew = msnew(W); mssplit(W, Wnew) #mssplit(W, Wnew, 1) #mssplit(W, Wnew, 2) #mssplit(W, Wnew, 3) W=msinit(12,2,1); mssplit(W) W = msinit(11,6,1); mssplit(W) W = msinit(1000,2,1); matsize( msnew(W)[1] ) W = msinit(2, 4); charpoly(mshecke(W, 2)) W = msinit(3, 6); charpoly(mshecke(W, 2)) W = msinit(4, 4); charpoly(mshecke(W, 3)) W = msinit(11, 4); charpoly(mshecke(W, 2)) W = msinit(2, 8); charpoly(mshecke(W, 2)) [g,R]=mspathgens(W) mspathlog(W,g[1]) mspathlog(W,g[2]) mspathlog(W,[1/3,1/2]) mseval(W,[0,0]) s=msnew(W)[1][,1]; mseval(W,s) mseval(W,s,[0,0]) mseval(W,[;],[1/3,1/2]) mseval(W,Mat([s,s]),[1/3,1/2]) mseval(W,s,g[1]) mseval(W,s,g[2]) W = msinit(11, 2); T = mshecke(W, 3); [S,E] = mscuspidal(W, 1) msdim(S) msdim(E) E == mseisenstein(W) S == mscuspidal(W) msfromcusp(W,1) msfromcusp(W,oo) msfromcusp(W,1/2) msfromhecke(W, [[2,-2],[3,-1]]) W = msinit(23,2, 1); V = mssplit(W); msqexpansion(W, V[1], 30) msqexpansion(W, V[1]) M=msinit(603,2,1);;V=mssplit(M,,1); Set([v|v<-vector(#V,i,msqexpansion(M,V[i]))]) W = msinit(6,4); m=msatkinlehner(W,1) matdet(m) m=msatkinlehner(W,2) matdet(m) m=msatkinlehner(W,3) matdet(m) m=msatkinlehner(W,6) matdet(m) msatkinlehner(W,4) msstar(W) N = msnew(W)[1]; s = N[,1]; msissymbol(W,s) msissymbol(W,N) S = mseval(W,s); msissymbol(W,S) T=S; T[3]++; msissymbol(W,T) M = msinit(7,8, 1); N = msnew(M)[1]; s = N[,1]; S = mseval(M,s); mseval(M,N) msissymbol(M, S) W=msinit(17,2); G=mspathgens(W)[1]; vector(#G,i,mspathlog(W,G[i])) W=msinit(96,6,1); matsize(msnew(W)[1]) \\ used to be too slow check(N,k)= { M=msinit(N,k,1); S=mssplit(M); for(i=1, #S, f = msqexpansion(M,S[i],2)[1]; mod = if(type(f)=="t_INT", x, f.mod); if(polsturm(mod)!=poldegree(mod), error([N,k,i],":",f,": not real")); print(poldegree(mod)); ); } check(49,4) check(49,6) check(64,4) check(64,6) M=msinit(14,2,1); S=mscuspidal(M); mshecke(M,2) mshecke(M,2,S) M = msinit(23,4); S = msfromhecke(M, [[5, x^4-14*x^3-244*x^2+4832*x-19904]]); charpoly(mshecke(M,5,S)) [M,xpm] = msfromell(ellinit([0,-1,1,-10,-20])); mspetersson(M, xpm[1],xpm[2]) [M,xpm] = msfromell(ellinit([1,1,0,-9825,-412250])); \\1225e1, #1906 [content(xpm[1]), content(xpm[2])] M = msinit(11,4); n = msdim(M); A = matid(n); T=matrix(n,n,i,j,mspetersson(M,A[,i],A[,j])) mspetersson(M, A, A) == T mspetersson(M, A) == T mspetersson(M) == T M = msinit(12,4); n = msdim(M); A = matid(n); T=matrix(n,n,i,j,mspetersson(M,A[,i],A[,j])) mspetersson(M, A, A) == T mspetersson(M, A) == T mspetersson(M) == T M = msinit(11,4,1); mspetersson(M) M = msinit(11,4,-1); mspetersson(M) M = msinit(17,4); mspetersson(M) M = msinit(19,4); mspetersson(M) M = msinit(13,4); mspetersson(M) \\ mspadic from now on ellpadicmoments(e,p,n, D=1) = { e = ellinit(e); my(Wp, [M,xpm]=msfromell(e,sign(D))); Wp = mspadicinit(M, p, n); mspadicmoments(Wp, xpm, D) }; msseries(e,p,n,i=0,D=1)={ my(M = ellpadicmoments(e,p,n,D)); mspadicseries(M,i) }; /* good ordinary */ M=ellpadicmoments([0,1,1,0,0],3,4) \\ 43a1 mspadicseries(M) mspadicseries(M,1) M=ellpadicmoments([0,1,1,-9,-15],7,2) \\ 19a1 mspadicseries(M) mspadicL(M,0) /* supersingular */ M=ellpadicmoments([1,-1,1,-1,-14],3,5) \\ 17a1 mspadicseries(M) mspadicseries(M,1) ellpadicmoments([1,-1,0,4,-3],3,5) \\ 73a1 ellpadicmoments([1,-1,1,0,0],3,5) \\ 53a1 ,a_3=-3 rank 1 ellpadicmoments([1,-1,1,-3,3],3,5) \\ 26b1 ,a_3=-3 rank 0 E11a1=[0,-1,1,-10,-20]; E15a1=[1,1,1,-10,-10]; E17a1=[1,-1,1,-1,-14]; E43a1=[0,1,1,0,0]; E389a1=[0,1,1,-2,0]; msseries(E11a1,3,1) msseries(E11a1,3,5) msseries(E11a1,3,5,1) \\ 1-teich component -> 0 msseries(E11a1,3,5,2) \\ 2-teich component msseries(E15a1,11,7,7) \\ 2 real connected comp. msseries(E389a1,3,3) \\ 2 real connected comp. msseries(E11a1,11,7) \\ split -> trivial zero msseries(E43a1,3,4,0,-19) \\ twist msseries(E17a1,3,5) \\ supersingular M=msinit(3,6,-1); xpm=[-1]~; Wp = mspadicinit(M,5,10); oms = mspadicmoments(Wp, xpm, 1); vector(6,j,mspadicL(oms,j-1)) testweil(E)= { my([e,s]=ellweilcurve(ellinit(E))); for(i=1,#e, print(e[i][1..5], ": ",s[i])); } testweil([1,-1,1,-2,0]) testweil([1,-1,1,-96608,-11533373]) testweil([1,0,1,4,-6]) E=ellinit([1,0,1,4,-6]); [e,s]=ellweilcurve(E,&ms); s msdim(ms[1]) ms[2] ellweilcurve(ellisomat(E)) == [e,s] ellweilcurve(ellisomat(E,,1)) == [e,s] pari-2.11.2/src/test/in/cxtrigo0000644000175000017500000000176413201017466014744 0ustar billbillASIN(z) = -I*log(I*z + sqrt(1 - z^2)); ACOS(z) = -I*log(z + I*sqrt(1 - z^2)); ATAN(z) = (log(1+I*z) - log(1-I*z))/(2*I); ASINH(z) = log(z + sqrt(1 + z^2)); ACOSH(z) = 2*log(sqrt((z-1)/2) + sqrt((z+1)/2)); ATANH(z) = (log(1+z) - log(1-z))/2; fun = [asin,acos,atan,asinh,acosh,atanh]; FUN = [ASIN,ACOS,ATAN,ASINH,ACOSH,ATANH]; test(f, F, N = 4) = { my (h = 1./ N); forstep (re = -N, N, h, forstep (im = -N, N, h, iferr( my(mr, cr, dt); mr = f(re+im*I); cr = F(re+im*I); dt = mr - cr; if (abs(dt) > 1e-10, printf("%s(%.1f + I*%.1f):\t%.2g + I*%.2g\n", f, re, im, real(dt), imag(dt)); ), ERR, printf ("%s: %.1f + I*%.1f is a pole ?\n", f, re, im)) ) ); } for(k = 1, #fun, test(fun[k], FUN[k])); default(realprecision,1155); a=sqrt(2)/2; sin(asin(a)) - a cos(acos(a)) - a tan(atan(a)) - a sinh(asinh(a)) - a cosh(acosh(a)) - a tanh(atanh(a)) - a default(realprecision,38); a *= 1.; cotan(a) cotan(I) cotan(a+I) tanh(I) pari-2.11.2/src/test/in/self0000644000175000017500000000004113201017466014201 0ustar billbill(n->if(n==0,1,n*self()(n-1)))(5) pari-2.11.2/src/test/in/plotexport0000644000175000017500000000150413326135265015503 0ustar billbilldefault(realprecision,38); \\ platform independent test(s)= concat(Vec(s)[30..88]); plotinit(0,500,500) plotmove(0,0,0);plotbox(0,500,500) test(plotexport("ps",[0,0,0])) plotmove(0,0,900);plotlines(0,900,0) plotlines(0,vector(5,k,50*k),vector(5,k,10*k*k)) plotmove(0,243,583); plotpoints(0,225,334) plotpoints(0,vector(10,k,10*k),vector(10,k,5*k*k)) test(plotexport("svg",[0,20,20])) test(plothexport("svg",x=-5,5,sin(x))) test(plothexport("svg",t=0,2*Pi,[sin(5*t),sin(7*t)],1,100)) test(plothrawexport("svg",vector(100,k,k),vector(100,k,k*k/100))) plotmove(0,50,50);plotrbox(0,50,50) plotrline(0,200,150) plotrmove(0,5,5); plotrpoint(0,20,20) plotinit(3,600,600);plotscale(3,-7,7,-2,2); test(plotexport("svg",[0,0,0])) plotmove(0,100,100);plotstring(0,Pi); plotmove(0,200,200);plotstring(0,"(0,0)"); test(plotexport("svg",[0,10,10])) pari-2.11.2/src/test/in/random0000644000175000017500000000130213326135265014537 0ustar billbillff(p,f) = ffgen(p^f, 'a); doell(a)= { my(e, P); e = ellinit([1,1,3,4,5]*a); P = random(e); [P, ellisoncurve(e,P)]; } doff(p,f)=my(a = ff(p,f)); print(random(a)); doell(a); setrand(2^33 + 3) random() setrand(1); random(Mod(1,3)) doff(2,3) doff(precprime(2^32), 3) doff(nextprime(2^64), 3) default(realprecision,38) random(1.) random(x^5*Mod(1,7)) randomprime(2) randomprime([0,1]) randomprime([2.5,2.4]) randomprime([2.4,2.5]) randomprime() randomprime(10) randomprime([2^100, 2^100 + 2^20]) for (i=1,10, a = random([15,20]); if (a < 15 || a > 20, print(a))) s=getrand(); v=vector(10,i,random()); setrand(s); w=vector(10,i,random()); if(v != w,error("setrand")); random("") setrand(2^65) setrand(-1) pari-2.11.2/src/test/in/quad0000644000175000017500000000047013457700327014220 0ustar billbilldefault(realprecision,38); w=quadgen(5); w^0 w+1. w+(I+0.) 1.*w (I+0.)*w norm(w) norml2(w) trace(w) trace(1+0*w) w < 1 1 < w w < 1. 1. < w w < 3/2 3/2 < w w < w w <= w w <= +oo w <= -oo quadgen(-8) < 1 test(a)=[sign(z) | z<-[a,a-1,a-2,1-a,2-a]] test(w) test(quadgen(8)) sign(quadgen(-8)) quadgen(2^64+1) * 1. pari-2.11.2/src/test/in/mspolygon0000644000175000017500000000135613326135265015317 0ustar billbilltry(a, as, N)= { my(as1 = Mat([as[,2],-as[,1]])); my(g = a * as1^(-1)); if (matdet(g) != 1, error("not in Gamma0(N)")); if (denominator(g) == 1 && g[2,1] % N == 0, return); g = as1 * [0,-1;1,-1] * as1^(-1); if (g[2,1] % N, error("not in Gamma0(N)")); } check(A, N)= { my ([V,Ast] = A); for (i = 1, #V, my(d = Ast[i] - i); if (d <= 0, next); if (d == 1, try(V[i],V[i+1], N), d == 2, try(V[i],V[i+2], N), error("d > 2"))); } do(N) = check(mspolygon(N,1), N); for (N = 2, 40, do(N)) do(49) do(217) do(247) M = msinit(12,2); mspolygon(M,1) mspolygon(M) mspolygon(1) testlattice(N, k) = mslattice(msinit(N,k)); testlattice(11,2) testlattice(11,4) testlattice(30,4) M = msinit(8,4); mslattice(M, mseisenstein(M)[1]) pari-2.11.2/src/test/in/lfunartin0000644000175000017500000000124713326135265015271 0ustar billbill\\ package: galpol testartin(P)= { N = nfinit(P); G = galoisinit(N); [T, o] = galoischartable(G); for(i=1,#T, L = lfunartin(N,G,T[,i],o); if(lfuncheckfeq(L)>-40,print(["error:",galoisidentify(G),i]))); } checkartin(m)= { for(n=1,m, for(i=1,galoisgetpol(n), testartin(galoisgetpol(n,i)[1]))); } localbitprec(64);checkartin(15) \\ Old interface testold(P,R,o)= { N = nfinit(P); G = galoisinit(N); for(i=1,#T, L = lfunartin(N,G,R,o); if(lfuncheckfeq(L)>-40,print(["error:",galoisidentify(G),i]))); } P = x^10-2*x^9-20*x^8+2*x^7+69*x^6-x^5-69*x^4+2*x^3+20*x^2-2*x-1; R = [[a^3-a^2+a-1,0;0,-a],[0,1;1,0]]; localbitprec(64);testold(P,R,10) pari-2.11.2/src/test/in/isprime0000644000175000017500000000427013447371554014745 0ustar billbilldefault(parisize,"60M") isprime(5368962301599408606279497323618896374219) isprime(4309513411435775833571) isprime(26959946667150639794667015087019630673557916260026308143510066298881) p=10^6+3; q=10^6+33; isprime(1+24*p*q, 1) \\ isprime(1+232*p^2*q^3, 1) /* need N-1 + ECPP */ isprime([2,3,4]) isprime([2,3,4],1) isprime([2,3,4],2) isprime([2,3,4],3) ispseudoprime([1,3,4,5],2) \\isprime(2^3515+159, 2) 10 min \\isprime(2^2000+841, 2) 1 min \\isprime(2^1600+895, 2) 27s isprime(2^1000+297, 2) p=2^256+5721; isprime(p) addprimes([38430950967054905712282083,237470764391881188851670682297783,1029859]); isprime(p,1) setrand(1); c=primecert(p);apply(x->x[1],c) primecertisvalid(c) c[1][1]++; primecertisvalid(c) c=primecert(p,1) primecertisvalid(c) c[2][4][1]++; primecertisvalid(c) isprime(18446744073709551557, 3) isprime(437256732647720373392867051041, 3) isprime(10^472+69169) split(s)= { my(V=Vec(s),L=List(),a=1); for(i=1,#V, if(V[i]=="\n", listput(L,concat(V[a..i])); a=i+1)); Vec(L); } \\ would trigger umr in 2.2.11: red_montgomery() isprime(85070591730234615857870057863360474949); primecert(1) primecert(2) primecert(18446744073709551557); primecert(18446744073709551629); primecertisvalid(primecert(18446744073709551557)) primecertisvalid(primecert(18446744073709551629)) cert = [[100000000000000000000000000000000069, 546867911035452074, 2963504668391148, 0, [33871007718198692871763537900223244, 37634983931409678910567952612637528]], [33743830764501150277, -11610830419, 734208843, 0, [16662256621764551072, 717141744113721531]]]; primecertexport(cert) primecertexport(cert,2) concat(split(primecertexport(cert,1))[^6]) primecert(104847485105117585996751891729845662843364912851385667939830682169316283979217507303783276087270751367988006094556790411454173939259895051951577787259); primecertisvalid(primecert(16285004170961712447000975451705488808641461042245717587564868626116060638362995676584291019647333487131164585910692526519723394628478390124381641415798852319473605083279694798821564187404325769317838108581838244806431287065930206020985599594140650596158360451027455871094479408389113611410568437054557)) \\ Errors, keep at end of file primecertexport([0],1) primecertexport([],1) pari-2.11.2/src/test/in/round40000644000175000017500000024002313326135265014477 0ustar billbillallocatemem(10 * 10^6) { v = [ [1,0,-363,0,53550,0,-4091823,0,170172414,0,-3663509067,0,33703350345,0,-63300912912,0,32451860736], [1,-6,18,-30,42,-174,738,-2514,6885,-14348,21720,-29856,48284,-47064,-27768,139824,-135588,56256,78464,-60528,18864,47296,73728,-109056,80656], [1,2,3,-3,122,-1], [1,1,-2,-26,39,-1], [1,0,3888,-12], [1,0,-12,-84,-196,2856,6328,-42336,-64820,352464,298928,-1776096,-262416,5458656,-1875872,-6688416,7866576], [1,0,57,0,1197,0,13681,0,136854,0,1048044,0,4603892,0,11460015,0,16001100,0,11131014,0,2739339,0,-368793,0,-7569], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16], [1,0,-432,0,68688,0,-4717440,0,112637304,0,409406400,0,2774305728,0,4041156096,0,11224978704], [1,0,160,0,11216,0,455360,0,11928052,0,212540000,0,2645190320,0,23223642560,0,143402547926,0,613283590880,0,1764753386480,0,3275906117440,0,3788371498452,0,2940754348320,0,1769278869776,0,73445288000,0,87782430961], [1,0,0,0,-42,0,560,0,-1645,0,2352,0,10290,0,10192,0,3969], [1,0,0,0,576], [1,-43,624,-3816,11173,-15800,9408,-1152,-256], [1,-28,141,0,-887,336,1436], [1,-171,3222,1079,-25200,-9024,34304], [1,-124,1109,-2208,-1504,2048,256], [1,-347283,25076856,-419348507,1408022154,-1607716596,540519736], [1,-130544,2518160,-15612096,27910496,42272512,-146951936,78195712,1806592], [1,-219,2951,-12762,6701,80815,-139748,-128864,354688,42752,-263168], [1,-20819,4970290,-185332015,974972214,1853069313,-4527488547,-3894160116,4476129404], [1,-155,2836,-14379,14428,13117,-9421], [1,-262286,3014265745,-8638841144522,-7230469691722,19997484886500,5356591151857], [1,-599,17808,-98580,-253979,537680,1226232,464832,18896], [1,-29999376,561121360,-119997504,-4488970656,479990016,8977941760,1919960064,256], [1,-25283692,99985153436,-3431807998368,5805487078640,46121794880,-628204481984], [1,-271,14191,-320438,3790080,-25112800,92495160,-167147800,50530009,301971239,-450938136,211398894,-16216756,-8116135,1041461], [1,-16555440,793241872,-6812040640,18249197408,-12596399360,-9598940928,7536655360,2589634816], [1,-3335,1068872,-29372236,170603861,-25778864,-465050888,178972480,-13193008], [1,-511,60996,-2085405,31489262,-239889832,934179225,-1604993848,-72959248,4517839616,-6762846464,4114843648,-916779008], [1,-295,3558,-5031,-24914,17697,28397], [1,-20167,13515214,-589415581,409276760,689575296,-490712576], [1,-1423,112198,-2946382,25666342,-2017279,-128707766,38702420,141457873], [1,-13921853102206569014202396016,13823607745009668573058211237056109158822,-82639509138390410981775119083025418818311274199568,7191389922579887711216370122117810510341770052031768545,-6403782491712680689180662417515214438745217916122612992,-16491332368693741394107994410424645158974225360655824008,12504550730163409756349966122713154452136883600552704256,-700835788721071887889404301240818143183667934525633904], [1,-2265,351933,-10876260,113882619,-320899050,-624685627,2393614800,1152858000,-3523888640,-151501056,1315123200,-232738816], [1,-711,98421,-3240421,25070664,-58439271,31703851,28789266,-19416303], [1,-506,49087,-1669640,17231279,47336349,-144695555,-359331616,176538278,650890177,224030107], [1,-189958896599609331973768440700,687813619771577743504399928302877897734798,-860743693595930793317020644139268141132387039380,2604128524727083170656936316847150343534889684322129,280304933578645057171094798274221018642041201687880,-8574385501054918331765273413936458875072943056877128,-479436876642637253489428928646435311733187408834720,6755064609347154305550891307820436374837227182458896], [1,-4690816,910531264,-11915116288,18021615232,54853406720,-82373120000,-64180142080,54969143296], [1,-6649860,1576752264,-22267257600,-85164579264,-77640519936,-18089594368], [1,-33050180802,1659048077186129481,-272574365342594573834910,11095950373591662695013161508,58710086095790534948543753694,105952057692427053452669684769,70434206621571881660299570170,9218882946199589918384363001], [1,-329544091788,469019476748118,-61449507761159844,363555883847040681,-209190672257869480,-1016729503227038920,1359941005734916512,-457890480465748336], [1,-1150160,1331537926,-601897862304,133574881579623,-15016280356014512,791282768405768068,-14453225350510767424,3154149235832315999,242466621761228454864,224495153622717846854,-670291322259768317344,-916062740958336644647,48963442301119929008,327298375561074497040,32908217054793357184,-23393721242771438528], [1,-2851,158608,-1924400,1243901,34900240,22503032,-108662912,-119975344], [1,-11111186112955398247507018336,243445863707559988779970226428228863828166,-414424563629922001757819169028157495238172960,1123139273032476660541621993600473674277033409,498129315610741879775567628417300033144884288,-2159960274391288199445420339203867726147763080,161278633821087460912298650651190604277783808,333627755901815676223362327425185259040194704], [1,-14504420704,1182354951470244,-23480009042438862560,27882235470885485836070,-9087586203362364155630944,599651930510874648548788156,-3678137244259701713858840096,7016885534906558207253820945,1533248468172570268668346560,-20993688867208520156247602216,24208677107524343574382863104,-8499807937568973364674358384], [1,-2913,1474630,-174340074,5392477240,-26251520300,-34286734387,209569240200,193605730560,-244321588224,-184759603200,14498496512,10333454336], [1,-2181,137643,-694573,1252707,-898221,209611], [1,-973,167753,-3919581,16265742,49310580,-279670537,-250608765,1769132170,725790142,-5312558309,-1392312472,7380239894,1386140637,-3489374699], [1,-1212,22194,-55328,-30951,115500,-2908], [1,-4773835280837163132310630467298960,9870109995525906834183518595974886029184804344444758,-1782775404778879896945364961485617187018000556874876449394160,89883389132977359805126346146881786926610135522042323723472323569,72714593243136238897319878334430413252438964969406750065955662080,-321968360190732413575930663497507427814725029860845628527928503688,-312452766852442968760965441219058671845140150026306340120175130880,41087519521030021203246250696563962180882228355460884053944990096], [1,-49896695,527277779708,-120568048624615,452535974730544,1625411298707505,-1448067181855113,-2752052546805840,2221923470234796], [1,-1046,20228,-68392,-265619,904512,1991640,-2358154,-6146747,-2463528,407228], [1,-549625252,1238278325058,-15329043153964,28925414899409,130312025889136,-32291232291184,-108323448091520,-24340205012416], [1,-2949,16059,10208,-83400,-25584,78256], [1,-3640278,2282599369,-18694808796,-4328145452,125291204160,-18186492672,-205081362432,13073301504], [1,-3152,285561,-9564226,152595945,-1188640275,3575524815,4816808889,-47197026465,33049819979,215848146317,-258582345090,-504831954170,649899122769,650345190624,-691225563843,-408430121580,242381088477,57377645757], [1,-15395,20249992,-239327620,273434573,856975880,-760838848,-750006400,143449856], [1,-2003677328,3012846911824,-25136484060736,32567282104928,90286574332160,-166925807110912,-30270493268992,97725572006144], [1,-61640944,166625534272,-3562612049536,15797138088064,236548072448,-60906347638784,18108824379392,56198906318848], [1,-21383884,35000497050,-11829222158080,237367247198299,-217929167425584,-553512315641022,292541289325812,110433041508969], [1,-23869184,4853367907,-14052765056,-26838500008,56069168640,30654626608], [1,-225138,52033917,-248800311,97200810,921552876,-1066931352], [1,-88696708256,4437008017160880,-23039907832217560704,26485741273275758734176,42379932318953038254592,-58866917909043924655360,-68089115862472243066880,20476771544555918463232], [1,-421636160003888,1902246275640252720,-166497940584948453440,3590656805496104164192,-18533569942452269505792,40219147880321276111616,-39862736608896158137344,14916521497035956080896], [1,-3320,224698,-424748,-1157911,905628,951268], [1,-64961,187497640,-8356326784,-15832630267,65698325576,143412228032,-26731714048,-127433961472], [1,-232394051587274973485503996066296,4038758106150313180814013396186630354012,-18284722485505087322089714887666913243539528,93595182799438815963839033321760695064344070,209067053454541747659819712614587487150583608,-588680842304077969068594235539671561808141348,-538836714977811176095248603569636252559381624,867715345720344138137761716498628626987199041], [1,-53655,319168490,-186349285325,21120443415975,-686099144383750,4735314251803625,2204357656605000,-26162347980297500,12824037220300000,33965267757150000,-36652423750000000,9889099639000000], [1,-125472786714116,674561716001370442,-230527140127968669608,8169775848285148195,1888371575828384127208,1007346199547631496042,-3767048153290292678684,-3343242731361766639199], [1,-34088504,1506866218,-1104149192,-12689882023,4007782176,25448506156], [1,-243443804696372,2923285683273533645014,-103724188690208930700257484,219554589005762032602647336897,-27447284989915966720818474455448,820411316616154701751838916778832,2735010684783093171601973097236320,1536067156806457414066577673199968,-1646791109769306193071759068458624,-1348134788310032629244426609918208,-193806232242166413772905190324736,-7677311000369732927493903060736], [1,-5331,3275258,-663977892,41259312682,9981725432,-375222796900,-231422557815,575556116832,210741891801,-134691222781], [1,-5138,96044,-353472,-420203,3742600,-2116288,-11951190,13094613,11859720,-16211204], [1,-532733417840,4744177349160832,-8413021486831026176,22311336993776500736,-7638962491965308928,-7352121709731774464], [1,-7637967984048,3386340581184784,-42324961034160576,122919529892620128,-58964720593317120,-192640220764305152,245607942083017728,-76666118683840256], [1,-2006,1008774,-17353883,-7844872,51013821,14640013], [1,-12474419222154,2431008594310441359,-6912314557744523417164,33605190900312985781583,-52569003547113031969674,25970935931836648827073], [1,-161443012754157099829832920,10138436074617165816404765780234617807802044,-20060069047647004218617188450114148708733068200,660050897576330492829543886032989254940435324134,-974098875961622456132597564420652229994235789160,-2264260286588310696319122780977992700907740060420,4240004472781140599100651710696566992990808375400,-1414274241286414395747708743194177178965032607775], [1,-1553722352,901513660416,-152989098177664,6553256584676096,-109901782972756992,685652288206471168,-43714124749955072,-9422339586035687424,8817974156500074496,44807770136073207808,-45324909008823779328,-87566115761309089792,86042657488023584768,51374273094909689856,-59775177056420102144,12687790985866903552], [1,-165086,69953110,-9018434345,392237516455,-5982463478261,18025737017474,55747520697647,-168806685673984,-244753603799872,393573790098944,502650387525632,-215239123238912,-336114163122176,-57002141155328], [1,-93823428592,34799861952304,-443389708735808,779896340053856,1393944632569600,-1484337524757760,-2345449331993600,-694036275654400], [1,-61061,2315481,-35028903,275610780,-1232308077,3218060943,-4849095216,3959990439,-1499118593,179027083], [1,-5695,92812,-488095,780736,805481,-2779721,525584,1541164], [1,-8235528536,78777096091648,-14962965975823424,752649877179796160,-12880180969335749632,38155186289451728896,469400924480987815936,702074460321333391360,-715079303427341254656,-2125387453139301433344,-1140826580450709602304,-3849685126809911296], [1,-5406403952479432,6865958511876428164654,-71567316451693131796818392,1752342108645328326901864169,-5653754613528818355093017840,2811073291210554121492866968,7423802461456459480849518400,-6565509149627058490734170224], [1,-151343,1368301504,-21253251016,26539419173,96661676120,-105696181312,-91329016192,40152391424], [1,-807505248612,37556725718396046,-265013994507552057420,318993321672688235401233,978883284203583405618744,4557622950652832660664,-2130952270988696435076960,-1494408400545790896087024], [1,-9448903436,104730633623688,-53760865135709952,4832151934763017856,-84739601628184897024,-42812862492100717568,184460624879942123520,71427552535240871936,-98041653705232138240,-30794067428621123584], [1,-79582678925,8620909385125051,-236507758358268974098,174874878867315968757470,-18058520227439698846912507,645254756102974107764676912,-7870697647323874283979696891,11521347153009947384786791458,34576202721355388442595149476,-70344554343965963219721213592,-10740194212304372050166074384,62770663206984074836346600032,-16345615646987859185051367488,569708459683633657748324224], [1,-456523770,8737152129501,-982742700549550,27196974696122506,-267044865205988930,534419840754543701,3738689503783264990,-4543932463986286454,-15278585690067252590,8496454288061882845,19353624370456339750,-1008847637476820975], [1,-34856,3760018,-13969928,-5409343,51565824,-37781504], [1,-301640751830458520553597141376,328952494035105106001631823186510670131969344412,-133358741515025683238080442729603137995456051732608,1955525927172552794216114449002457559485718278748870,9397121011646773996373023708967458825619733367758208,13257860889783058889903253607299903955098315590042012,6433754692163674744311497881625324357727770698216576,492667067892517490964245788797821843444034967148801], [1,-512577532102040,43768111570354384,-683727333405049120,2702203304894313824,-3908326472950549120,1831103370543136000,-49811703475904000,-49563059750240000], [1,-4442,2971547,-533338420,2818485691,606965289,-20799684871,16060220236,40016291866,-40620996767,-6838744349], [1,-1661445000,648950992194,-9056465203448,-52361475864447,-82213976895840,-37808675256052], [1,-3549,1055643,2390843,-2763021,-10087077,-6219557], [1,-523628898243604618995885416807147298909363801451789372900,367600369666309006452842123621050246321452143630580273014679831593578783458649152654286,-3343275983768744237278154637602147245967274497790433362036635892377724426950499872902658229340,1832082009549845619949867091376004679654159119363411909937509445666660442613413884422767828119857,7972083317253398926405060410933145316118484573008126052905764693835293798003418767254772929076840,11794511604384984730506391635816484705277974441262698427609855343001177151538798564737754260305528,6870707586084866428566813547262155529526409904008120571289108710304360279945306394092746374847840,1364739780535919594206700656372505401403107870453922666372253727638308252150474474123624152944400], [1,-223216,303477256,-17417922005,277522832382,-594271046752,-5464816647875,5815492998512,37144434715472,-2497746038784,-79766894614784,-25810480361472,32744553869312], [1,-7391,100628,-303943,-80708,1274729,-1168709], [1,-11102485161464,638119123854694146704,-1090684976797347138361401856,5790691092346201260104535212544,-2905557524355781158067995198312448,-1740704435184319464552349984251904,8456003228780781810129632899235840,611694445981518923832996667392000,-1827580422204898657895630230781952,296569960368897491493657596919808], [1,-382595410,10131435161569707,-339358625351926857460,1944397043581582983327025,-377576456004292682578424730,18893558349780213971828050325,-114503495274862313003240421015,-941511767079645429966258595415,170925446090929041685072722405,7547994422752820490440513334577,4952842395416051576334911693070,-20605333735289498909471577909366,-17080193694570124063317347368550,22769567946872826808692277299420,13826681275125601697987763384700,-10810372895085097433637727654775], [1,-317966635855342617399169385408829217452748440,13678545113125269147071264087266524532070024308404763646867605208904755730954,-15684278338411526690829309518564793208753920587856759367478501240440935756809346120,612415923065287098473685281157727791918451722108963506485602685360057577081310228969,537814306804262126760386283977264831761888559875268935565912225023248124597985989680,-1990656139061697921305239415958192303820860550542494738202435034180069987344650996640,-2055469177845059349200042772439815497299423127890291811872672651394061790113952185600,-318082857370566991270588466777928875794349614537780585539495916100466479816098809600], [1,-416659279474111237,330377843894082003274229160,-62905768010062743987970346108852670,16821570317735641478410538460455385145365,-1198558791812587254354860392504583675770158336,18870041073230571748664972200517215466193250634297,-3110266503818994429391891213184926395344435891196215,46333969996580915198177746519714350753415778619811755,-71051745585560409536489422446312023987208684949679585,-171670385086621478643416705514305417043725434872977218,353998192629745372651831816938706517212108845354144981,38406503908964266753393497382125776817470966499185790,-335208974242087685397896701245395328967475262796476705,183830028342252095617620250485464751517776308230766835,-28324287359035373403013837385189183497723403582130478,-370669783454900697332687258050823467831694680481879], [1,-2942,425807,-21480253,510509165,-6192552408,36292590688,-53610411500,-425058743459,1751257692002,873280257113,-13398050061528,6817766400536,51340604838743,-41334969659574,-115572213676468,88181505312905,157994239939799,-76512548098590,-116800296271737,13943948986543,27978407467337,1658082397889], [1,-235975492672,591805571783776,-382200656154472448,73171728402630615744,-2825821907089361173504,22281146497688453411328,32388399560710497509376,-589295596207800671283712,-475154989792559233744896,5936410136560770774966272,9110311309239759390113792,-15457901130275180849086464,-36773863935231836576546816,-392960681613067998593024,38539327581294094379384832,21102849638169519181594624], [1,-22,135,-317,90,941,-1851,1519,-580,83], [1,-480,13575,-57397,-15045,155166,-22856,-113661,22119,20089], [1,-5349,69225,30959,-693771,-198237,1904389,513114,-1472148,-541304], [1,-45,339,-792,-186,2907,-2911,-765,2280,-829], [1,-1999,44014,-243753,270704,621536,-1193984,115712,409600,32768], [1,-2154,83832,-98620,-727088,628528,1715120,-1208288,-1009216,688192], [1,-84,180,796,-1713,-2337,5216,1461,-5232,1819], [1,-28714,389720,-442556,-3374000,506160,5449392,774688,-540736,3136], [1,-131061,64254945,-433211377,-295697859,2231628243,196751629,-2475058518,468570444,325387336], [1,-43228917,3217754381,-36758007254,-59567284560,289702061749,332943277127,-581210582241,-584264535430,52410165263], [1,-31323,7353216,-107319715,116275089,383163324,-599105591,-198697686,666629724,-267848648], [1,-170,447,951,-2186,-2265,2785,2117,-798,-433], [1,-97,920,-2507,191,7795,-7979,-2434,5592,-1609], [1,-25601,4735751,-157811795,73527676,713816792,-217322176,-919714240,50378496,268434944], [1,-404,4704,3918,-92546,-153360,222561,511962,102988,-113801], [1,-431,5515,-29560,84442,-134947,110307,-22471,-27036,14251], [1,-129254964843,35178418165170,-223350030592755,251360581683972,960227812394016,-2217902130474495,-80657197605174,3263837746063692,-2051179019383688], [1,-10430037,3613650129,-255462258585,649253166885,405120779307,-2141143390203,901824939450,1197088044012,-731164579192], [1,-50244,30294557,-672636955,-5671628428,-15674959992,-18431496640,-7309777088,1356664064,746926592], [1,-339,4344,10623,-36633,-85575,53843,193416,92484,2087], [1,-31428,5168421,-69645814,-94901634,121411929,57346600,-76184430,18720885,-1242287], [1,-1322,9117,-14806,-25436,87546,-32311,-75542,33116,26104], [1,-189471444,37709676681,-165918005985,34691048736,558925368933,-498161898711,-154612190805,146945330826,-21509240369], [1,-2147,464267,-6245532,12094236,28528805,-87534615,6524347,127671918,-83816513], [1,-2783342,8025984,23658900,-59547440,-78387408,138067248,117240288,-97770944,-60103616], [1,-1255489,64926593,-338839895,426458329,692772093,-1921085372,734227214,1055601045,-717464063], [1,-36319094,630812278698,-1655815071045331,-6028129014962075,246012746225435,22671225935869189,25087340269832470,2776221409366657,-4230997679557999], [1,-873711251373,753411928367685,-13806936287537310,-111661195235268408,-270166294338135339,-191717097502403145,179751315005491911,323631491466547362,124064847445413967], [1,-14849018,494063251800,-710653227516,-3713349421616,4822039295664,4687257735600,-9757306885344,4980576448960,-802641509312], [1,-33175596,143698989,797637285,-324064356,-3785215656,-2493975360,2377896000,1441632000,-683840000], [1,-1929,14472,20253,-156633,-129093,449669,289806,-258072,24407], [1,-614748,2204740,20504164,7285904,-146034016,-334984464,-302768000,-123461056,-18857792], [1,-3029,22091,-40644,-47982,203135,-80355,-209549,146292,22027], [1,-3981,1369677,-17835518,-21602640,14896077,19095023,-1882569,-3453006,-58337], [1,-56691,2221227,-15141714,16322598,55966149,-107613132,13226364,54559296,-19694537], [1,-14521960,647012999,-4984218590,-36502752545,-43863546837,79899788485,212682283274,154229646540,36019185544], [1,-158662082,2623228504,-11293514652,2847667984,61874154160,-78720960080,-54521566560,105714608064,-17136358336], [1,-196587,3209851035,-169981929492,1004435496252,-2429211599883,2941338597321,-1853910108045,570724116606,-66727824497], [1,-911,5074,-2190,-29204,37810,39031,-64347,-13824,25019], [1,-7845,71310,-122285,-330972,945684,133568,-1565232,369216,616384], [1,-145515609,153019764729,-3709746066522,1393445404674,19486365429555,-8829957473691,-23095161469062,11557736900892,833570519624], [1,-1279836,7972421733,-33976650387,-87081745548,139649755464,254306919488,-38030593728,-154168849152,-46733991424], [1,-1983,670992,-4138497,3171843,9255633,-5546089,-7199220,876864,930959], [1,-22338,412581,-1979142,682380,7847946,-7588855,-3039222,2196060,626552], [1,-22113768108,3796190022029887441,-60498021996410510930523,-71963443045623180847600,487699550239607072040156,523305125593515644446032,-1131228403974427035526864,-946796045857905092061056,584092504774559261558848], [1,-16954592,118348117057,-461615145371,-96594517766,2084887420818,-1349388002526,-2335232607204,2081484755957,104568589897], [1,-10489,2707211,-104488860,245611206,380234947,-1177729795,106009611,667160224,62376107], [1,-45837,369335901,-31624086134,-169410056472,-164382128003,465586425823,980522077951,392287249570,-132604621897], [1,-463038,45146493216,-1001353353260,-1082922317616,5505441329328,3829125921584,-6282318595872,-885395763648,497609171008], [1,-841,13536,9553,-157013,-163985,275717,183350,-197524,13031], [1,-15461,715359,-5328764,15402786,-16694517,-5169563,23976863,-13678964,443227], [1,-862775,10856170258,-3134053418062,-1375422646243,19989421509103,3876108599660,-31488084661671,5161577814899,4115642633441], [1,-50213409,41604993225,-1178945921599,1767674719401,4428816426693,-5499446500460,-5981060846562,3930075321357,2711088130897], [1,-14509669203,854596766777094810,-7066981747963431235083291,46268306243972593019173548,-119361738755744810792850960,153452578934040181394048337,-101367063741886754383215702,31015690796531163812304780,-2923893082958254149947912], [1,-734,33756,-127241,-72904,584650,-73590,-605936,-25506,23491], [1,-73853860518,13777317132366702,-115071949708121348242,160844716195874633181,682814078330976048036,-833639776266212564111,-943177567400978615382,831764080222499743356,66392226304335963256], [1,-694758725855,106254756427419398,-3784025583829693170297,-13131948767566391974232,-12527679077150368308464,-1542996140822612863744,1578487928494511479040,-80007592280225568768,597456985245478912], [1,-17515,10964993,-247423288,310805648,1085556229,-1447110681,-631704583,509927518,170424799], [1,-8336,239429,-1115012,1550830,675992,-3307903,2496650,-569892,13592], [1,-5629442086276204273505,386546651233719446359200330993497888059691,-72838371990626194759378155526759022817640816485447,-68944817078273525878833279122529093499192548461768,532698119339953491504511496245901043962109891591692,399760666506683453127871057655514820189115908767536,-1251030146293132816263700188101197788442427262158608,-574105270447410879019496275688738988931548783376384,933502079102512278754584352311502694379008136095296], [1,-89444164815,3805216350344442726,-19525076579766367621887201,10677494665576920234465120,172915220543339268243570816,-75371913447675512226165760,-481724974617695286501519360,133078578075456026880442368,404416685885850617500663808], [1,-5017340872,54242041495381,-5530836376965691,-11636668895078592,11075773964676508,38232904505954064,23198971246434608,2517662503984512,53606420009024], [1,-39793,797843,-4481430,9023194,-3106271,-9102293,6350523,2351580,-1467437], [1,-34677,757365,-2384830,-8575564,7310693,25880563,2552523,-19252762,-8564513], [1,-958954166,5186058440675,-5517238669966482,15054662708038354,6305516444274500,-46821935177109565,37215625652899170,-4390922315873148,-2421624954194536], [1,-6299100,13352120109,-51758626611,-417163766490,-393905254122,823253994102,1291197091500,235580470281,-131269473631], [1,-68277338,5340670808,-96736086908,-116282155376,520304803568,350815905584,-710962872544,-144532807488,203482129472], [1,-1001,222000,-9506853,78349585,-284295243,538163385,-539633442,256936366,-38830541], [1,-38919,34177467,-59964732,-1118422710,-2838483267,-2244178117,692405229,1753197504,630872507], [1,-17126633628,18516619842741,-5017128507606003,8455548998534724,25861081463217288,-49455246822756288,-20953146111899328,72565428488438016,-31456789981646336], [1,-1263537,9873936,-28868559,36398475,-12468609,-10015971,4721094,1594332,-10529], [1,-19146870,1769475136,5281209652,-10032427760,-40835782480,-6739762640,71055695712,63912971840,15410458688], [1,-7447032,4924412571,-359721985189,117617755923,2143792138494,-1486073631188,-2975007994749,3230985686523,-741473702423], [1,-517106,58273606,-1373815122,-4952974364,4913608780,27153942409,6950089002,-34145062392,-20469346393], [1,-3757,1530645,-28029222,2359216,144391005,61784671,-203472129,-207072198,-54303129], [1,-173780,45443268,-1790226588,-8863383152,-4818339936,30375498864,42501629952,-3312569792,-19727103296], [1,-2400825,190198232783,-22943866813291,24838048578516,112066877369032,-119639920213824,-123200993753280,100605510714624,35506136494592], [1,-25753,6751411,-44524192,68742386,111823375,-385704903,257283371,63338444,-67180373], [1,-284655,209650037,-38162364134,-163511305238,-14981588021,711289445675,760350260231,-313829615616,-502101723341], [1,-68325922,137056373910552,-11145282232549212,21173555959782288,42902777425768240,-99554991522541136,10187009777496736,51567358997901760,-19350004011936704], [1,-11733462,65284119,-55303584,-232858944,336527964,205314537,-268417494,-148242276,-18541736], [1,-258893,79530727,-4243301484,-11876635766,16008454795,57961696909,6993684303,-48619490844,-16019695837], [1,-18001,4498247,-188001200,-52454414,551685395,-309521095,-64332897,57315780,-7370757], [1,-1435968130,714533588440,-8231837770332,40163539982096,-106986363839824,167944712628400,-155368804314976,78443060916160,-16677501283264], [1,-405158247,18670761978019422,27304726717430303,-407622516493630984,-1469519465184311920,-1133627454427613440,1794923858940870912,3248244532977154048,1358504654641917952], [1,-404792,2745549,-2331396,-17521082,28819704,34082865,-69811830,-19635428,46786072], [1,-68548140398,1451627133858028890,-5095232432365659132155182,3088999911253813409361703,38873934921503404756228124,-21888154468509856869401849,-79286358464811742369152944,38737113817267168448327653,19271373881512324513129886], [1,-233746,2998825,-13950594,28124252,-19043266,-12805079,21860330,-5429540,-1331272], [1,-10355,21543,160412,-124146,-768627,10747,1106549,390000,-98893], [1,-238089,2428653591,-52281136592,55494790434,272982489999,-244755630607,-464342035173,229499404284,232532331139], [1,-9804802050650,16692730784125432,-2541495071565357628,21109219806111169040,-72218607566697081616,126705850231213211952,-117594235131211600096,52634612644066947776,-8014881018162450368], [1,-1546315729274,288782232725785318,-11969666848599934914420,-27130970349234930466201,47347882539110061930082,124498595190336220679942,-1304964757812833452501,-64114240217284796166421,11258025941338821246113], [1,-84967786647367,333964189732653895352180494,-9366745551868952432186167003262289,-22234121711987296225427381730172744,19539169743580452197619049789466096,51305696359169176802147610083269888,-17680157436544518186836737589196544,-26000314945482248211133277039052800,4518541019882267511313091077443584], [1,-7748673829668,83640796005524661,-937392562807456731,-4611558327627410100,288178943379431256,19088931030202667712,14002224746809121856,-11962021354522502400,-8709955859254358528], [1,-843304,33763525,-106394721,-151759084,340324475,-121861811,-28549267,13500892,493667], [1,-576711,9817828593,-1467968536170,1986116686590,2315529499551,-1792787441257,-759829031733,199468065048,18428192267], [1,-67782267991926,3118994381718067776,-4510225427657444408844,-9065205219388262002800,14548147545483838825008,26311576762212059385392,-13479025960226694184608,-13821453446321155975104,1249714021685870356544], [1,-116597,11204304,-75508472,143658084,90374012,-590670119,595390427,-100047640,-72256661], [1,-3749259036,554393241540,-10928530910172,-39909926964720,20361183490848,153596163158000,62626956568704,-84859519298496,-23307365582656], [1,-2485415052,131251617492,-500838205596,-311199622896,1007849076384,593369475824,-435068972160,-386665742016,-74265379648], [1,-235161,314874197,-3066156650,1109853192,24058441897,-22580421725,-49502851657,52464975134,9173335783], [1,-1315854,125620602,-575073054,-177194175,3317366889,-1778517616,-5030239005,3601178400,766593875], [1,-264278631900,6391720172245021,-1626519277074267211,2468549508074110996,7490117873595926920,-9983338376585959872,-7051946118841625792,5426902073117889792,1165973386759172608], [1,-79480668163070691548277,579797667303611907678285,871006426643549798058665,-5664575884052113261186899,-2721765628562603760591507,18297656442680378045473468,795444294656219988472938,-19650372769147029403078227,4906440383881879319836057], [1,-17361556040,19571584838731,-1912255610523653,-6599847690074333,-1764459194463858,10908227354203500,5823874326739107,-3161768996970613,-458530154815991], [1,-942677402975,306729542653406,-2223101555541649,-3021993537312,7932499451339520,-2016256763813888,-5852785072668672,743954651807744,853725799251968], [1,-388145,847961035,-14279672808,5155032058,75179631715,-45679619663,-98354672793,40080406380,43812242819], [1,-449715623374,5733757254592,-14174764915308,-36178039104112,88431316773488,56172051631024,-118680037031968,-12225526217408,30136055145536], [1,-6233425,50543493135,-277319344376,37556421978,1194329803539,-616149265735,-956720534777,-149559849324,-308254333], [1,-6720205764,466584698229,-850591371171,-5544923326524,-2245384789368,3411810485312,216995495232,-119747460864,6720270848], [1,-68026878750,236661304531200,-24579892325699628,77376432563312400,2783150175184752,-213772569953649232,171920098000293600,41445518831184192,-55371652962821056], [1,-618153,190453312,-13900878563,20306957207,79305438779,-96593023923,-148646368490,107484573608,96104956471], [1,-3837199411252,15987954244320349,-4697757619575778443,2802514151170278956,38842254787450812632,-17674389726474822464,-102961225717149802432,26969461377075245824,86730122212734152192], [1,-312562763163,346886487839985702,-93018430645583163427,-387503893699644070202,-227171488895637052053,1059383162575032981336,1901280189644540086305,1023913564393379937375,106567992233337642217], [1,-361474931790,611242743954816096,1973129339163640404,-4210002821826072816,-21443528944285721232,-15903091278377251408,17306737477063294944,15843200491976309568,-4434448077967904704], [1,-3778306,8394069,18391906,-34113836,-39223526,37637081,36203162,-3782500,-3555784], [1,-191995,18675888,-415738733,-487665149,3237735637,2525439827,-7701107584,-3455492344,5556122951], [1,-3528390465674391,295399734866669842800558,-2387118057773104769342178715473,-7115146127465248916444129922720,11963803174219131542545857515424,51351848128578616328477557919744,7113243674866320054741354132480,-92257589727819000341535933628416,-68487179831190246952800572440576], [1,-45037547,172457645883975,-1790412841228672560,2627143167768991192,9869078575652884449,-12596759728507943955,-11343571983898538301,8920514581505543602,836831771418477463], [1,-14544930060140,137330449552913,-154735085579409,-876479584619080,1181245400641645,1927455097458009,-1718524722383285,-1592842129577062,-167254737213209], [1,-1873500886,25283363424,-29198798220,-138943513968,158616778288,124060717360,-125965364384,-21725034944,16468307008], [1,-3806541,20782949919,-25366811811144,71965988436246,12103674791283,-142770198449983,57267830343243,20593396170576,-4139930393533], [1,-60381,329921913,-102719400354,-307998071508,131405772501,985414316087,568240988175,-134586047862,-1251538057], [1,-19205016,82891756860,-75612791103068,-22071609728016,593620957189344,99885969101168,-1527816117229632,-114091235429184,1291999661947072], [1,-5057480,64075800525,-114778121458632,342619789089451,253607005501671,-1403010587394510,423528819767088,1315290786628078,-789115629856541], [1,-17285705759,3645479098061046,-977455946035418697,574017488559447304,3349789413247368432,-3569470539005100288,-1037838976341249792,2354542035384567808,-697220011518488576], [1,-6736624153863,183177091628494320483286,-6180182788352798530510347577,2716240087955115185667279592,22390195136916081365570958960,-6868581589286990272316103936,-23220089103784231280127389440,2774463146325228316623759360,6830897897415504340570279936], [1,-284114632574,23328357826240,-297773293976816,-1110327740162464,569323040643840,4056968008207104,1629816222242048,-1887449511731968,-365569572674048], [1,-61113734390,16008403307648,-87192050722668,-8774403711472,522877371403184,-217607455565136,-1064677625078688,341515181013568,772225254630464], [1,-575283,495123480,-94146773163,-254138442099,329023946235,1060550521751,-194008114416,-860201958138,231411895019], [1,-8715488748,5970471668822748,-131516946743691692,-362146003783658160,550507485957558816,1689675762706695152,-133240171325456256,-1367117267311120704,41605663243747264], [1,-754302766,204635138688,307739257524,-2886558712752,-9696999595088,-10366769647184,-2966994334496,924587406400,210205089856], [1,-298841222,38173752800,-1269934926572,7899038846608,-16724081597392,-866792844880,54216158908256,-76186873466304,33725611694144], [1,-2022907274,153018343932907460,320981614532593515,-1651825547656661424,-5520681723930583807,-2507330145920455952,7612874974670639605,9523512831628249435,3051738873709998473], [1,-345693,380929328,-8222062311,40755162175,-80293086305,60679695873,375595674,-15404928472,1789630471], [1,-1171530,41629156263,-9975372520038,4403806572024,63987965950752,-13186797282636,-112717060634367,-8838630882576,39713414160403], [1,-15249215987703345643683789,65999669051011969127587880853,-57965945899301298379214742190,-480754726560884120624717949336,46654331036366608056055398309,922676089806829907322011185351,525899145779582992611381401751,803706295997501863197084450,-6533057249290496498299013153], [1,-3,-85,330,1854,-8885,-7333,67837,-61572,-15731], [1,-18999317,14188004237,-654799572422,-142273400912,3076892255165,436752369839,-2186399517169,-425979209310,-20092498369], [1,-55267655,19031864097901,-1323773104630459478,7816233223528156410,-13003751961452721333,-4361156381824269353,29106395680462736587,-19234804081092308268,-410206599790220149], [1,-412277031461850,21678032306781299848248,-2461595077336056893741948,10570781888949923022591312,-10667200780571632434652752,-10137987860380589840189776,21329690948753641253058336,-8768906897999430259248192,500089379074200034412608], [1,-6974625030,7921875723488,-1938747773729292,1214230999079824,4740127316419120,-2454499565586384,-1488131163123616,296470031713856,27233217614912], [1,-792296275135581,7157731383572903793,-14192905336051175984266,-56193023159687986802166,3245304106744257077607,240118027162073934066565,219593747170291395284346,-127601727583918000465764,-153555585114394714772984], [1,-67379282,4783160426852,-37576960879135497,120962277105887128,40492542396123880,-423592117788419911,293306304698596826,64540471360047660,-29466075743752904], [1,-885599,1922958558,-14798379535,23102811288,29078205681,-91476357427,46833416626,23835146496,-18433878713], [1,-37874815979,112053086952040606,-1544680561043401411,-6722143771571041474,-749983562147267093,20680704519842468816,14958350042389121649,-13882577924450532001,-12578727178554392743], [1,-31069515170,993008647032,-6402959118300,-2905149336944,48134362508976,-26066596030032,-84622776300384,86427873915328,-16089254473664], [1,-104969409,2035692788899,-1999021285887904,4277012701797850,6490533958588179,-18781551224385823,6497216849011975,7256037158527100,-3779402883441125], [1,-4555508548662,2674415374271232,-81556857978611852,-155911831259546544,195164499853718640,353033807605799600,-121630137797124768,-160738427156398272,53457532904521792], [1,-292626982,11992564939200,-330201914364588,80624084150032,1942305209216560,-245628921486416,-3461988496574112,-175512680818624,1550860071386176], [1,-173228820876,1791731502684,-1014936656748,-18417922724208,19590235822176,60388707916784,-68861940059520,-61536451698240,71275249001408], [1,-11246620216342,99851364475552,328388289229524,-393490018444528,-2024960633935312,-1892179994121296,-20385701464480,686502512699968,229322168012864], [1,-1237071828105,226330377674255,-1028826653892667,-1243355993777356,7113712215592584,1502735894044352,-14186021241027776,-227811750892288,8154199934755328], [1,-2880325,13051731,61229670,-55416886,-332621863,-257926005,24693879,68374404,11869747], [1,-1216510579279377834,226162806214537461603432492,-91363300579643873512882902453,-190363013774198779059661199340,320772368294364761476370276040,621146801883650894342167055082,-209967955680511453135279973748,-206835781623241247022061648872,46846125166425639252867787039], [1,-16051762116,19087414262829,-126691360247643,-707884372586988,204692259817224,3682390171810368,2263521694089024,-4668341182458624,-4304362700713472], [1,-7418819767071,2646922977548674967694,-83245372936799845908873,498860138779433263629168,-1152057925399851778938048,848492435332317598462976,783476452275007945113600,-1568089294433419059658752,672589256230703474671616], [1,-7250282,838327455,-23386012735,-34079059949,85710931608,65998729223,-89276257757,3941198888,4945836787], [1,-658926378322,18624546237015928,-2062234561069619292,-10800530029643230576,-14347395422084489296,13569364360070177968,50870831766432498080,45071763330662993344,13380496521121534016], [1,-87653,78349445,-12327824838,-54682458328,-36903462411,115909907863,154880615935,24370087762,-3917426209], [1,-438085,117367249,-765249018,-902080036,6285923837,1004191351,-14765116657,2699080210,7161771479], [1,-89381858,-142394209,799646068,1526254980,-1546314144,-4251799647,-1262470950,1268754300,579015000], [1,-1678781529,6313135911903,-888987461357292,461137299708870,4475062911662451,-2137281952110171,-4379994405324045,79551555963984,364326732434611], [1,-5621468032962190117,19721495932848051225969410979081,-494435239021384832364087405797378646465,-3503664529435812829750998396559356043915,-9124243100343144417050357428842011111837,-9526368450086740816186714808892443240283,-486694537840218958297274619641538468550,5828567877426929283173978233126673295980,2905667579994707534468750797365702380296], [1,-814194057585,414056472969393,-19420820935146007,-135767377725635751,-267506949366593571,44028334994232964,753808838498392206,873256330986976101,315197368076799697], [1,-48907,2168113,-15522118,40915117,-21872408,-102803829,224647094,-179223282,51380371], [1,-1019523,5276891832,-512500692083,-2386438662987,-2722713064845,1113611574359,2316252243144,-228547173210,-175243581101], [1,-335795,8955359,-4221018,-218609410,-604886039,-661683308,-298461804,-23856012,12327687], [1,-8493477,119548048545,-1039122579942,1104300080064,4829469460413,-7772017130269,-3487646723661,6666637397586,1090822908167], [1,-24148314,10369842460185,-66358173654029330,-184211899158470751,179153716075265505,863191377824078990,425853472285376526,-508078822351279560,-363722086791200321], [1,-91217336,11790289341,-293572970004,1239757219462,-1181507394248,-2289699741743,4943392317978,-2519232117732,117157404888], [1,-251463513,10440593464,-14265126137,-210419757524,-221483555932,501196160416,1091475057552,697417217984,146211954368], [1,-25940023070,16615613882984966,-829888106638892401149,3107103253174297644999,-337341923594596490527,-10542300455562618582368,12615050591111237515880,-3682983838644978274608,316368182375400330512], [1,-344710145293,506731498334954649,-1305002432564881675,-27770714167595284139,-100974973531681593551,-159136863919579149436,-110396521799745595710,-17097447266803771775,9483928020957047641], [1,-19910899,1108243349,-1950406148,-38850153660,-82634407987,34083615647,288974196125,324929315398,117212127463], [1,-9615,1189381,-10892942,-70419271,-89261804,65855479,155687606,9425986,-52554269], [1,-1147627924054,4374439941008582,-1169722829354124386,-612087790189978155,8807145419930617852,3294095723624945425,-21200736991273111062,-4444970550839273348,16300547401929510392], [1,-7771959873865200,24298758098496889106127,-13467349983140240629450854,-31435123124322071864978217,31200803159740556829335643,120465025183103142530732661,82581065775122714689153866,16184315122000165922082828,-210904929440283813831032], [1,-76777,759763,-2575014,2781966,2455221,-7052269,3554543,904532,-762341], [1,-129121,120356183,-1587001214,7055600862,-14501253063,14635813347,-6580536485,811733712,33502771], [1,-53749,13871545,-212064370,-371996812,1399479345,1662006187,-2712066489,-1696167522,1758914271], [1,-709961863,5807333837354195,-30105496773035385164,118414882271428824296,-124409004468477171111,-6841469921742780647,45908280183240492363,185601242150477146,-3309039887809200593], [1,-449844927,501967196801922,-72847833684086316098,188158281820054449237,-42630456470973039012,-106990492719289674022,32807845530580852935,13035007653546210654,-3390566962302687329], [1,-23035292,118489036601663,-48932375051930605557,8568147074136076147,390559380607279426130,-92321152949709386920,-955466384049168573505,215934908717498580239,651139902668687666017], [1,-1682208809185979027263740087665,38460669002109216521306017047488771434208899615232339,-789215380710611948301225849906279583250175442757096555490324572457729702,1298256148668053925249650971384686586826702470064914229044090274999256215,6030329823121832098863396859553835498131032809403984593479645183753512324,-9490084470419754437453910267860740292415249457134746840897452481872148103,-12394600943847745519754407531435779729178452247379772195631334665755880166,17341080285216312802767349120791681272978457502031451943896949208999010428,3296271969194505878859122633527852637478172298602731294774862093346579128], [1,-1144265495309835730,49923475084524347869216,-15995488733125357472577758,-48796962740367288699108596,55713495918778048738211031,264166134873195160170026981,71070428772729452084221562,-287282783333568985533701572,-168386733883938686911812856], [1,-57220933917748482791055,421432683704137008041973785434926,-19706728990556038367918172669771186953673,-12723424145005161802854383220896287885368,127580657871872145892123207192434478107408,65741687506553976917267947208625253170432,-225142929942783048993990402047872349206272,-69761989665958342964660248694611335247872,78030709323948095525370311539795889876992], [1,-439201344361100057172,298682339369083510723957169,-1993819825297374478439136896,-413303435630088983138297958,14748097505558080719171177748,-9462024177248915246648070223,-26659710763054612986043303206,25359544965613546263800593388,-1888978298649312011654077384], [1,-5802127263,287719052234104404,-28057294707841304943420,35994973074431882507118,93560769205410381354270,-68930980457931982724892,-75581789160975641071308,-2168783935945534218663,1123856354218638808457], [1,0,-1125,-8187,418527,6063246,-29628708,-1114750107,-8016271533,-19159072973], [1,-291018221130686,6177811912283862896672,-24098188560084773665644,-55048694056791696049840,168071111174651808652720,115168131681977741268528,-310410872603033686377248,-2220471709185131354560,40713723811892150741056], [1,-45742676674,13285226508600,-884300379122844,-7924935686070000,-26863342798122320,-44887054617934160,-37686285269143904,-13497695087511104,-823934867294144], [1,-6812707,29260293621,-3863681916534,-33899272787250,-111278748580121,-166973063735213,-96219537975701,14879138337040,25557866840803], [1,-452685,258015456,-32640097359,-100508736369,-549156225,290122084313,369635601162,172652033112,26034334007], [1,-828120321,19196894484243,-2089902600280579,-8925328592739468,-8315112977750355,6139800082126669,8199504364294929,-793429782322065,-1642176313344791], [1,-29399280246084,41736821359896213,-8689441224824011203,25748899993528535340,13652429148325027992,-79459998887124758848,4683397865515364928,63322739270171112192,-2397673249658495488], [1,-25665087553029947767,5002010563050666885419506918,-4640397039631951425031718106690993,13276249105588143916264279701500984,1544827222563604148108556918471440,-40633243602231836771322648275415296,48647018551609709297127556195926272,-20092948136529590566080329583429632,1899626379682900076985335069339648], [1,-4637070372,267390918364691973,-3359070220125120611,-8105967729252032076,14433914809537703496,29396438188961407040,-16037510797635992256,-27512591734201443072,319497287955931648], [1,-740389088691,5004042945081330,-151636472754243634,-523513097234815119,412846622368142655,2424331629274400332,849682242734634177,-1814618342964912189,-649092289960547063], [1,-22667808,21478629458,-159734672882,310522791150,312843358201,-1596160761077,1087057090346,1013551660772,-1068737159384], [1,-118268599457732021762,13399423901526523925888893396,-37425136346633436638727167810220927,91910191137993644964843610826806732,158700085555037722899767217847608640,-466718969360496984942243557276658311,-57994110985325353303034094257966982,489803170996960297784106903074766828,-101196279482189530047794770391958856], [1,-8381463,4529381481,-7123725636,-40365253980,58609388961,112828469567,-139876332639,-95346809970,79811896607], [1,-190623987134302,10493332733817654112,-200976379697735153132,-362113359089685425264,1357637176890689247600,2000562870652299770800,-2241151875769637504288,-3021369928455051919552,-180984330143355512768], [1,-545911781686038,1730369425087127616,-272632842836862857356,888993602871827854480,191956349995970603696,-2594867433851352350928,969701493484050638176,1269690910288337998400,40768664618894583872], [1,-85874508818,1654204738629592,-716784590322130460,5627245910316387344,-17839758794358300240,28737683622515717296,-24297806085710613088,9830990459438087104,-1346093235942890432], [1,-27076783192750,24271758572883968,-243037537579443116,-2310073161266346160,-5326182729140894160,-675777809414818256,13147788338535368160,17552314353524427328,7070510147611960384], [1,-21155105313,1070254921430139,-8712148588351133312,-8310650783259700974,24696514940072822943,6983175715238778641,-12380078215276546173,-800178352897745916,349756210435254643], [1,-12385688757,1916080199393019,-58741618673592542228,26929663025166493266,239986041238361005407,-12316995824222759299,-248523201105492395517,-58399583014201665996,11162188846705939387], [1,-15580412921,10623466568,154966313561,-51279535173,-535328756625,-20329193443,668167599734,246541089532,-85980663233], [1,-1891790001388,574801216007853,-13941273621114531,67799559326838492,-108653948402398568,-13754837500374848,207321333594705472,-191671749190377728,52120943273655808], [1,-762692554055132,188338536604999496013685,-46929736652845070757445419374,-57831423295578968941024692602,204770636072818689433603599849,160466853240255751165397666568,-263630344100570306422895267718,-45159126601739526691377711235,65450970623725405682676537889], [1,-3106123,810597809,-1876412892,-9309480837,20165946328,35098753439,-71648543976,-43488201116,84488560031], [1,-3918735787722242231421117,80084232039976969048861461,-429331637992124079459325854,831075230218880302651032120,-408725236905283779167498811,-420414034582254809217609993,361175537167240879449700119,35761097653507891045200210,-48640722933604597956528257], [1,-112011082963371,5899066359243887720046,-14995174545778923704947,-34251476632829243370858,109639206542080354146123,10175095996245722651752,-196595181254681388459807,130116571613861427796599,-11528618720994558355439], [1,-3246166543941725424,151410873803245034545931959,-110953078534039896467952064542,609107951424251899808848415239,-1121115269275985262145454134649,637639391393057012614116747237,232557885323381458359435104522,-260101647651275389179436402868,16856809039625836040762310344], [1,-120054372,126025066500,-1421354175318,1353917591943,6080973645663,-8845904223982,-1484583717465,5457878297754,-1388894309713], [1,-46957890382377078,570204983223035855740524,-25672873250292003289796170440,33292485242970903574364959872,150518964306624020618101483008,-181040742420192126948708179968,-213632903931162431063281238016,195891936156400167131409285120,69566168302856134094250573824], [1,-32613422196,13293195120138093,-1451198812942745283,-11756808143248997588,-32085693547566336488,-24881695260413271872,37363082983377837632,77251669176633041664,37728923163711151616], [1,-1177876571708,6366485452947343117,-46575653986899163507,118087889720953902204,-102687859188394641768,-32784338554941935424,82031747722754312768,-13088162495314385152,-9550737546785669632], [1,-106193595,4410985912,-41256964077,-99838531933,157099639053,265867078099,-92388561848,5247677968,166889743], [1,-23408585484,71423272387788501,-5957416320204490299,6046568575728367188,17271011510560257480,-12692446337212757440,-7771006242052503744,5134862897421219072,49153182042931712], [1,-694029721,183524338905,-6882896399490,8710775797688,20599308065701,-29781479801389,-10134047490425,24318968190922,-7450233496889], [1,-902673908688158,1392214421567394848,-15624512933141859116,45976911448034913616,-1847088925044495568,-164925717518358482896,157602672401859580640,105528690493768488000,-141810055562534205376], [1,-145135715,1186849347,-1232951040,-9840395474,18746113329,23583433803,-57550208091,-12643422272,45915585619], [1,-1137129,2442823,10556386,-17706290,-32192263,32586259,30777579,-11138776,-8089213], [1,-466028963406063,64934307251398103646,-6795302529775113006487,-20111248346049663289440,10166165643444478722408,51213693101581443134377,-4938111472168085906118,-31715758212696299786004,3018843864850336077112], [1,-9987419931184017,766560303506581526663724687,-73777573791928694859141506558885353,240702694079437759281909426824308596,105453916148765716102467506033386794,-909588225036127831694292097476051563,434609095030391040744938868028123509,574516931945941600135504148887557936,-282567548391085032510183482287898684], [1,-619200324,247155304503,-14227997035842,-2932198663218,80360375375082,12041228088737,-110627350073286,-22984587133092,12136738671032], [1,-194430045483,10930146184233981,-37004080723791054054,169726782696692480550,-121850854246462427577,-419088703965457667649,644180698259593014915,-130415057098479078768,-77994015988756051997], [1,-37014675,150133071037,-89620040871142,-4246798262090,640816272972087,147122927011511,-1170139960911845,-531617720804872,159192200026963], [1,-1085703,3628104285,-197606400462,-400590842046,571459462659,1475071012244,732972054948,15568335054,-9004627981], [1,-4805757,162271526,-1207375811,3240587248,-3189146408,-248324480,2064628672,-711019520,-103058944], [1,-8082773729841,7260177718541589,28691529131451941,-20557898848641255,-213364185531482127,-184371916552970420,329892988876405854,601797085412257449,259979183434469281], [1,-327891526494659045215108397,12415949753135545692786849440153069,-2528824608659201824230894171119626984446,-19867650886035452536415225545819645157008,-59490878386915725860364903888898567091339,-80096469746659429846156883572389294365529,-36334678633058706082811834269602763167737,16048305290574653957540109247696824131978,14598909565142137515897772375275790462111], [1,-1046380114073260670,20461446800168814236788782402,-1395232429054800226055784119164,-11814830543579397346428451421,5187235222648332575642588530166,-236870611278038562893157010142,-4651363385403742416925139405309,150561742385028119335244624551,1038951692548448313014037731009], [1,-14044369,12712692256,-286283415627,368099638175,1245716824619,-1974026678075,-427395032890,1130080662208,-32110434817], [1,-5189841843,23667382972401,-12751055463010026,-70854790453915134,-97420334705757141,102420442025729991,333086507171382423,198625307893879704,-5385976036858301], [1,-100447264,2367460909,-11647735164,-22659089650,114239885504,72479652193,-359640790390,-77397327524,373442503832], [1,-2137478889,106206931677635,-137342518370245600,-548950403860134704,-806850507473777605,-509923887572030632,-99145665684287766,22120067430795354,6701494189754083], [1,-76845191,309627891,1178754408,-2684467622,-5638221435,7036965267,8677867233,-5024074076,-329883557], [1,-73349517645,9184526794530,-275174935414557,624089227488372,736671369199572,-2530554989347968,497043204973776,1702306987221312,-627298115144768], [1,-314188397798636593619823,335970190538190385985388108,-2414209575658577982978368202,-5403727205452820242763021868,12933423122404575469588280664,19593247481667281142338815857,-15129693407601610182001856262,-13604065318256732137470719220,7457050262510409218629063672], [1,-19613331564964,221825287915904845,-928652730777886419,-692577743679720820,4056206153338650200,-326088834466007360,-3929148676265343424,2185149010484329216,-265604387866161664], [1,-3981185570,76011080711988933,-23874049544574829458,-136138771723302192998,-240844682398345291548,-76918201009868870223,155033768170795859610,109760640295897249900,18782705380108675000], [1,-172918841552596,3326082333651752197,-77606226984224548443,-323486630754573011620,43392800154469323992,1311641451694761581248,833149624842987031616,-1354833569202833797376,-1213199124937137459712], [1,-219939,25656614,-148980261,300996296,-192818528,-86227968,120957952,-15949824,-1933312], [1,-325039,3248407325,-61496266078,208103854874,26916787075,-960970439460,946207281740,582283091062,-831729129029], [1,-27077552910,996329801790,-7650375746856,21540998233233,-18800807089122,-20061209044887,49042182145770,-30149768524068,5007823431256], [1,-28751530871839,10574092487997798958822,-1064233181826773349067411689,3086017265431827206232691784,2585812762794672936236166800,-12627806321822040150419161856,2591019949720475543671503104,12609645435265892314981599232,-6595161125977310121290272768], [1,-1167525,31775760,-249446135,758488911,-920336241,222836969,228398058,-23167992,-466673], [1,-25887144925806,3228307717735968,-83460145644098736,-31254690807457824,701552749826173440,32196751623863552,-1808979773357928192,147213095097255168,1319250460887229952], [1,-186067,8007080296,-1865934302217,3966801254303,9764014243985,-22965783804461,-7322978196952,29716362405820,-11181475114489], [1,-9105950887403324,17666285281338173839583953,-570225555961995219052493620,333720143634492832572686024,1257498900967760044752503413,-71646383269843578661102537,-323577514416177359919299151,25676111897036233933151855,5136184155827329813126817], [1,-407428497251464,1169129660369347454339,-12408323314263781106933,-22924663153724183062269,56734592730273345953278,88457730891209789862388,-46732029534409282400013,-57420744657176302056509,17302177255596979365593], [1,-213213855519,5423797965783991833,-1071312540597931185690,-498371991342578083170,5827169960992863316359,3468725904869426685603,-6569781497332253668557,-5369231464981086373632,-798079038447414756797], [1,-39145644316170,43098838479383974936,-1393381401798061080472636,-3902984552673438037505456,3794052851460402331786032,17307395339038214282812080,7735210768810043394014240,-7927441531908453543449664,-4759108912905967023018944], [1,-71587718645955734,417709663167480853549472,-121646909545951504366970700,178902787378484431960104912,289349589287143068373753968,-622054227198478243591683920,331988161251811787761431392,-68106746864077162624351936,4673098904747061778490432], [1,-4705121338830,188778652339574912,-86569198544652853100,134884524756528912976,310097710221151687856,-423514086093021322192,-287314421675886646304,299569972394547221568,-18948072597586879424], [1,-871311988917,41911926136054575,-17588024008736068228,-120949716225573676494,-238622182867805315625,121301920871698218781,1024479863088054971979,1286847499723222294116,524750985381154767083], [1,-660365,155219491,-1477944460,-1948890582,9157180447,10047668573,-12801064069,-17022201300,-4708346837], [1,-162440766,9725435232,-139472754732,-141447952944,651832308528,463200875056,-409455676704,-139580609472,31344580672], [1,-73991769,3779656539275,-1588324550621888,-2850700671540006,6639439780940335,12458178772978345,-3001336183876405,-7186195488461548,1228560936643291], [1,-602280,185127438,-8032330614,4655899242,36336791775,-13888605445,-34794992070,566261220,5905586312], [1,-793305427,10722262867,-37799372520,13250340782,134903221145,-150273057893,-117445140091,161375702896,16536355067], [1,-7241081574,25886115248064,-786523151946252,1487821004382864,4799922480477360,-12254503026731984,-3204019391007648,23648365707528768,-14001538998804416], [1,-68709109711103355268342,794212042694172998959675623203456,-199639739058313536433860442701516,-12256667642945599347878098666683632,-5135370218322307255753488643369808,55826302577396829528549641891338800,42093919672649181457791027580818272,-78094346463401717012162246496433600,-73603759196961759355613981208833984], [1,-3333295274727,34572781123653309,-11642536353513403198,-23346644708711384862,50795498459103908163,109640146196378460331,-23335310666994177381,-69139738612718500884,14647493405052447371], [1,-113,1176,-3819,-386,23467,-28696,-29832,52809,20412,-29249,-13190,-223], [1,-1572,41840,-301023,589524,1129931,-5022917,2678727,7731400,-10207822,3007737,369710,-116575], [1,-46755835,1206514419,-5981923871,-20191272521,74416768475,265724484731,116877948397,-443728589789,-721745657080,-459066275673,-134096733890,-14549748671], [1,-264906556,164181027958,-18724183114540,70479317370001,72968634377264,-492727397394752,41734123101312,1145261155531392,-311954756027392,-1066408976920576,177404063801344,324503752118272], [1,-5714993505410139272296507009782216,49344904230148839293333660593889114227590536,-75912374820652001820427996265214005713100104096,7989457304633369412761744707841570955171670040304,-15974027141958161121922623941579887028811517171968,-74507683121314337453815413692153070376569859762432,171572955584394974398431302183548180568510573755392,196203312057724991575518132602141074697099154452224,-592343421549858666594462955237479564143319009110016,-21950313161471530090788036532799002703196428335104,665588107659149680139605375551402393227427753877504,-327313607586270398972920248639723917317625964130304], [1,-229977242,5072291958437,-111384225021100,762216494900532,-1477672431507456,-1588524670358112,8220409292590464,-6523629466987136,-5815313742183936,11727602200559872,-6334684476656640,1139431063577600], [1,-6882808231898278414037342656,3455143367204290127157342521604388436332,-36661537168170277066262237535877306066556,49588942370382232589832601858597528091646,356029612847288265291799825046259689332740,-524595811862855775985469194571914871611070,-1025519268248587041651819209950715500501700,1453885449064670671053483316089032783488877,747401846174933080367524379803979196331968,-1239203088628559715562735153436589082944258,371531325751546776299376086652334941513708,-25967762675439783998636643093161918358399], [1,-776227,35260611,-410113332,1237367010,2841962582,-15400560964,-1522071034,58779614473,-20028404187,-89273582271,28252161234,49612618017], [1,-136450,5782301,-48188974,-56158306,391808464,181381185,-993288620,-120590148,904251232,-106435088,-198059200,24040000], [1,-185290035842832019128,489482814788592695857251131528,-123165591405668541618484310233779552,1382699398509947087245384403121233136,1451187676274817203561770378629695744,-13349894710179599610890326621200296192,-7161656140212798022704305275356945408,43064097291752964399345748822207213312,16507693434261046711880963152245303296,-50477638084627481625862451247360866304,-13250359536841308975630870347363442688,14228047455441382330877775957566296064], [1,-75175041843787104,61342026170367580199808,-459463266498901473284181276,1317681283458970522968876746,914122129345622228984628000,-4650476380148947381939741522,1679357874014236559395086036,1961391076946617638906024301,-625118212064863116606332772,-340301790330722833417811686,37393240021622932269078624,16301182707955190633537041], [1,-103236086,1999763737347,-18474454131370,23989959263891,154675342323716,-361052854031686,-347070912266276,1292028449255827,25369597086578,-1592955973471413,278906963487694,623764364353873], [1,-32005221058803772,4637628625018039965419958,-3717203173067266200276095100,515928600836885426751576737537,2320049127272374987480220302912,-336813174821028838294852909072,-15025829957190389847037460506240,-18686879576562303590015975665568,15747418480602911176531575123968,45665292986239411427949932910848,29894966333608668824087612589056,5838410116627764613546230919424], [1,-88609157169,692928400278227226000,-18639810502615504141898100307,205777952269910958141151211118,-482100482299731057868364980215,-544825876501103943774907374028,3041454447812245838666224632240,-2257391223497009459404058192895,-2899875613277346059907829946934,4886609292155880670960692388815,-2131600168767190456076052602130,207947193981122938848112605041], [1,-3183024216747548838268,347142389627273461829262758,-441720998655169990664213630864,4524051142705909842996317944557,21516534920861500399431369303444,12595830718870799466701805370122,-52288927013806481740769778432036,-93644009415943389791426854732746,-59025104012256737349525392054516,-14575361103996761413374764908204,-565750002074801746316160856768,165811130561518571726921110129], [1,-81149837561968,58618864154304079578,-10830571585373935637269404,559883747296995376809712124049,-704021501828066365749085402734,-2399148964611094599666442234758,3316182464824620576759571538086,1774891982677587277011080687322,-3555103338212968630407231466105,821712824228692877635550872675,183505222060318667427166134250,6885453722596067903626375625], [1,-1563597153071082805844103218753996,67018408332460754570119044177545638014970296054,-37099623251162852103090511887535812015226342243484,2192103164616289787313759550176665641270606908066305,3243664850340545232184241866506929046611370635737776,-10514814844966903945501503146066088655871990118947664,-14593405378288550597224538554184727096639754156996160,8248342728040074458071264923080698568212480136102752,10243276134747222494276314221993162945870371455561984,-1845163538579634478672993723514426190163328408691456,-1777735033500819774671164457229092452663819911004160,154226446779924775048387201885796557892082364170496], [1,-31223691959794830602,42765558803732842831684673,-2162188858003428992663539272,22770781950430057176647472882,102451102783461555146628667630,-112668144173957992900965272712,-704253264672437025442827529992,-120308852756586442278247401279,1487503938885226109640060456728,941700250082578881601264792984,-685422721638535434474056198048,-502933781105705055904786490864], [1,-115413570,287574254057,-58930369951719,352419522365346,1169402955316028,-2959989895389245,-6672131819310801,7192141635813067,12811780547077466,-4190604601917150,-4269036523999336,678648868147889], [1,-20591096196457859900,1840165796772256356932562727958,-131023868085871742456573444328908,701541835202696113652263210173297,-977060642871327547379950033689264,-894856974044186745852632084570176,2756921144494190878619328965507456,-668446399254552912794190974754176,-1496860430561691770146268333923328,603516994619292536597205769392128,-11814503100330293795716197736448,-1872632051224425073935746363392], [1,0,-1820,0,136936,0,-219035,0,32426,0,-1245,0,1], [1,-1838,110466,-1457530,-594624,21403672,7660335,-108811868,-64537506,201749902,118477401,-163628568,-66610521,54780838,6013838,-2634629], [1,-31231,3740300,-91245378,298050327,934268992,-4401788427,-2431740698,23399074654,-4515560125,-58297569578,31288267422,67359582176,-48602354979,-27725192380,22560578171], [1,-40906,4286270,-77984287,300321740,106381441,-2061594435,1180829506,5534987315,-3707589161,-8142120477,3490266018,6790116438,-312434143,-2360372242,-631502281], [1,-18809,1007298,-19194788,162121198,-636963643,1090404363,-104031362,-2310502773,3004164956,-1048406868,-331692206,203203153,-8625326,-3759294,39563], [1,-280247649,12370143747059,-850996907727117,17385934340695578,-104953177346379097,159438058163777720,405739918822250928,-1435006226138656256,743609052920692224,1986922299122192384,-2872064678639902720,712942514844729344,923102855384727552,-660573116061712384,124295145963126784], [1,-147688084208955,162514697333979754370332,-143071328373556693619330813,814498028407902816901453997,1196611416136583566907442618,-9230269879970666415572781126,-5425788355021335902884454579,39559829432680865697441913757,21760961992967478375384616236,-74241951529995456358177390411,-53798271555346409210041704986,46955989795933394809385282456,49835178466379490784238600176,6845569936271203166407322128,-2455600842687476406035136544], [1,-55984,12125520,-753020810,14698113542,-10692173035,-119906892189,96604699315,352327599777,-246807485043,-429478006526,248789197002,163568577073,-96696233259,13402072876,-354876733], [1,-1558704,11732227927,-17345399656327,7366503686195955,-219574743844310286,1050340456599871611,-735317912369847266,-4907175335868488768,9266149963815066786,3225135837007914497,-18338172819145680515,7818339608856537238,8690381388382833077,-5833601680346328990,-53861918546721361], [1,-47014,1305366,-11961382,38360176,27298817,-406153819,532893405,1091715987,-2802659689,-217964548,4576634412,-1968144183,-2321534605,992713950,510072919], [1,-1468556417308,8300573606061360977,-2705938416133717124406,88913013089260833668088,-724328419046932245976481,1018249670823443732932416,4943137677182200075532416,-13176958801527732381953024,-3702816671601945471262720,34434714043481702461800448,-19941833091022080943325184,-15466571196576506123911168,11141321908580043460706304,2504851002933833130573824,-1206197920399232258277376], [1,-145550294,227269379365,-25771911970426,342428330853015,-1911328449126942,5363840743877974,-6826775727050422,-822314470569433,12964880540399583,-11801460015689989,-2874370303777420,9159227460645875,-2583732509408625,-1835556642885000,850347584171875], [1,-89808081674911266815048,79128424242713365122209007041188013157,-3052605634288681896804299927151469576341541685931943,24591740445889625411404075364678274009623245146424112178428077240,-17295013047448966608202709921007706026591999795959417294752856173802683699,32065934259538323730519329339477925731742492637748351705129217070213658440,180607570389961128875518521066867058106924267586859262925565140714113736839,-310783026814865911699927351862274732318782062129735230464762961875076241643,-702304544416243133992984157877194404768211184446016846306225029609718535980,1058727794193198264458438705495642936140864153797692639517740426916759598389,1221126278789507833801318925491932404091838452610087168109897350161355693478,-1440615126322106993870227378444982950194867821903521311858465280054265740520,-826267695361720929583800717830386241328018992164187448340917881743650769552,584055962731112025260083552274427498515225164253321542720142989848153502736,28668284880261406684208154295930066873387643924604067624639811913733221856], [1,-388076989,1079758962665,-281006949020358,2301148841669910,-3410848405792517,-17769471739473636,56921951799902635,9594228172805605,-213590792333203357,191641376766491029,201891846345306138,-385039239395541241,133476271288119771,48496821572762834,-23740268125285297], [1,-47962447,344298998595169,-1598332423506290719,104781036499703828895,-749710308556203862066,-4349324659762972691351,-632975120607203069430,18754307769062652874915,19566916842088227057339,-11596690452466850281895,-21211124126666080071840,-2795072395379003358055,5387658101225234848338,2195619029190942811826,204373679742809086883], [1,-16518941628,5965603522057334479,-7902534202340150038231033,1563180197295523061482407892335,-46882526739774604073556748947752515,199012743910932707366382724114583796,193796820300599395174342295123702072,-1867627039195345259033198899684724864,1248034401840430437165453602838706816,5205132319166130315425869956472064512,-7581715285764862346487806635495281664,-2219003884964290099007728441527504896,9678066934299569255447806826446049280,-5773320352397120248544510362810892288,1009574104375918576911526017373011968], [1,-214049722596,3515714950664743487,-1352763252743625525233897,134556838299926508927771395895,-694229409087478927613911873976723,-1102057343661796638891548804391356,4122358655749500542829101852368056,6567735440113497250488420670505856,-7532406362362521310529100542616960,-12841282877968992332152198801927680,3381821301827390538283885749808128,8356624089583657435604470882791424,1493225778137995040855190707687424,-199261734637216839574037309931520,-1830221442717099448219317600256], [1,-743770101390697,179419980281548028514163,-47209784662238068446421397693,1248977050905179806682070021106,1138108288107148036661401765271,-16195729635522542904392224321224,-10335199330314339547964315816528,79093290025996932849843874650624,45994798119262657358160806641152,-176564325311670661882126639722496,-104241905119071943248240054968320,168410248253547783422319967862784,106300676916113531032996015702016,-43266322876251150948515193552896,-27685068885118507173495257956352], [1,-1139079482,9939596145423448,-1902335933481257389,117425735899567780910,-2203383527933426907249,-8743264574237991049024,12590871955008258625152,64511776855381108698112,-7620215622544895725568,-160648619168498645729280,-43192155000817402511360,142877658633594204061696,44786017920496170958848,-34610078159668865138688,-5023825047731467976704], [1,-28249891883667623002,209333791113233162830035670621,-206080823889129581613504494878551149,745711151920412521002496959709010921922,-349900362184470467941911122602681421536801,25866755459018097671760805134724063035040394,-218360750504778413337426314748621266761874617,726694460005575886021746251339899033147125897,-948101347386199003904663020605411105820179610,-351473235980877001164810248335701001104968716,2263115345811528628293565339506776266436277322,-1628043327174614390095620802286856399277274247,-1058795307729955319256746357017277202924597536,1647620403823835898580119036145445721584451129,-123241927747452934984757753685795984657593930,-445672242624063036022259389581035096502293254,70659594429098734590418715111126748446091156,39508671506444537160482623431102153222427649], [1,-38916737668,1528799614490356,-2959843739298189104,150572195870418370016,-1887499327892869844416,10111591039381440766592,-24333285436127064356608,9015500577097486903296,83798762809040412580864,-175225989236014069346304,72431666294194247462912,184152647584566164135936,-277161654443569499160576,123482629056011438227456,28344410041864025210880,-47905841572526876590080,17103424167689825288192,-2096255434680407687168], [1,-1275747,575090691,-21949658774,205310705256,49953112230,-4602380202278,-1053036804867,33434535620298,15540401250227,-109588439593713,-70375383550812,174662374195533,138502456852110,-125360405379972,-123681682521918,23360045823231,40926121982052,7767192570581], [1,-191284643876,6341580163006836,-1934761696042349496,164849740308816714448,-4754806011233115697888,31297720637036736916912,40563063715135443568640,-447349624075426149585792,-106666893295835639752960,2465625625557089016418048,238299557470283831347200,-6723424858005364092543232,-1437413580211248751588352,9098140489377774130455552,4194676060685113931065344,-4594013743663310745149440,-3833217510275099671912448,-745788684857196104839168], [1,-11750704,1200072194,-27059115460,275329643437,-1507066331248,4350637026294,-3402695953616,-19674226511210,71635260352328,-81896826447748,-72414392799636,335995637293393,-374570043319420,6375222215324,412780308002080,-455545471094544,219580211621952,-41955549898176], [1,-205266599,3059043580551,-7377470986131672,255750467781184134,-1632953660152413431,1068348929913192629,15919951883702020817,-32949097618499452897,-41812738164568952022,160392472026537870106,-19845888168060926647,-288196883084542066323,200932996304757155217,155961581801981478736,-191793894011410484713,20117729114239674902,27921588898947726276,-6338062216813197688], [1,-45609411820,264233335559214594,-66441505779889023806,1651301768353913905227,-5702509244843790310454,-17718742162923383793609,94554646423607253705100,41437587470866244656495,-576600445583458394851654,185162070050586644716796,1716238691984098960776328,-1138541205600600045107878,-2575616331400632645628288,2165795832813798728006237,1728370435725705408915414,-1598090764684425326864451,-311652308942791826171932,277546280986572881143364], [1,-1504162,19478258228,-1774538541554,33455987402844,43770320753508,-1315720656188287,-2806299428446827,13190626459075508,39866462208944136,-42146184067179328,-226648796078997568,-47571258714568960,562561066722199040,515663033658126336,-448457920894472192,-815336848346726400,-205333486181974016,175547802745831424,85189809140924416,6179324718743552,-953640242118656], [1,-2914968254,729565958618632,-37698933666991280689,557592894223395782959240,-1616283511372600082985105238,97042988438726838461737336436,-232284398484404334687457106105,-6732183788640945316473023556024,-21348108851313726862647539943344,9922779856397149629502473433344,151080206871502990665840133664512,191217808340180216960353992423424,-216777783257003298753858212900864,-657568359287067519413657902383104,-264659148877840769934330259767296,519913318612345880722233221447680,525921319263424904995708534259712,19307792423762224049692793110528,-124791473356889212827540555563008,-16503846133252696483685908611072,10339744705904321576640217874432], [1,-480959,127971287,-6210024988,117387642442,-974058483871,2716073861918,7176144743881,-48663748603594,18221811396627,253842407160806,-280982367878873,-541503028206526,840715026571134,401195003303691,-937048907916075,29239682420856,364610731756647,-90373942881826,-27466833161452,8779464511312,-163262489641], [1,-39941932898,6210764439806586,-5769357270954813832,1526235405765947359933,-105496607496711652450502,450637888725327737131320,9650202211913359888961239,31737300783657595070950160,-10913973852576470640831520,-245106653555832534199738368,-427683566166591584370447360,43660237154569010897502208,877952103594834582382673920,792609270976277877255831552,-195542552331371677253369856,-644898095720832121314476032,-295879994185715924103856128,-3536321127891585200029696,19459832831021097932554240,1829846937231585372536832,7561943891893450440704], [1,-86337736,7598242460043,-167569983434765540,17305983969682532799,-292019419313169397092,2075131431123040068658,-6665424416191304282566,2295068132975694200659,52514343624238390352037,-155524020328280599942642,72098535485922177259119,502162464846325947972732,-1081612566036474720415173,329934201842389030200420,1737975836203010588034872,-2616168718135781832784509,780663560042069680589185,1552368103386097794485265,-1884069429357675284396666,861632370133018734294910,-149417527248961307018797], [1,-75050219,2577820557210,-8708771477008617,10240537455834038070,-4171566442262579317992,166242467088694549400458,-1033863257761812234666121,-8510117703992561276196134,-1712218241553391418046499,59073478059006844802989434,62496120000886690394671741,-133496170027675884289942785,-206919534061107404384206114,87453839145789156887240569,220760986134809816904048267,7507090977497795083539865,-78187519420065641576046009,-14126847417965732398061212,2838691415177922884136661,323334550937520096385754,-26940726295898710940521], [1,-17381757580476,43726977976046475,-38587155046755611490,14404264950505670063217,-1992519320820093070368720,21131148543713011874724917,-40503643542455943304425426,-221092172903838528916304883,686267541176044244116291476,934545360515028736247232153,-3842393422466848354481305014,-2297337276469143012081280444,10852822516123803157100624352,4469779496649171224523959382,-16461707981027715595966487388,-7275510508518637850373793095,11989066274939596734697677612,6820828079009357932513725593,-2377962517799535371613331494,-1864695755179413468652723812,-215224289114498638277938504], [1,0,57,0,1197,0,13681,0,136854,0,1048044,0,4603892,0,11460015,0,16001100,0,11131014,0,2739339,0,-368793,0,-7569], [1,0,0,0,-18,0,0,0,9], [-23708160,-225566208,-1131314688,-3968372736,-7276863744,-1112932224,22694392512,49279399488,50845741200,22483386864], [1,0,-2688,0,3413088,0,-2724744960,0,1535600481660,0,-650301043097664,0,215057090579702112,0,-56979500534544010752,0,12312194148189466704810,0,-2197264040603188502904000,0,326768343229764821604655296,0,-40745795222319658376664019968,0,4276794417515300890531785084048,0,-378647131200860936657636244230400,0,28286761991498448324281307379182240,0,-1780798310985522419497792899399649536,0,94205009985586665787286958769846028883,0,-4168270688350510971203431806915951526848,0,153256282053016072956650306840248729289280,0,-4641329002870144811569747153738728312276480,0,114452317987845573283355038818157554058821648,0,-2263985500383570937855397654604966209249105664,0,35234824323208949432122287222843195049195649184,0,-420671474677100937747713465131110877388775747840,0,3726806815195567658159272381046654302782322548810,0,-23439111687336557701224954796394993807990875876416,0,98647323369477358239247622147334076753681287255648,0,-257022322568849250028056718999196809455429653200128,0,377528109863340174709450199038785141413258084463900,0,-293678194586629498753778041508197163621948960832960,0,112835081178121597247315790519267337889550215700672,0,-17664834640659843760086846517563699616091492848896,0,464167528830919430707812939827867130195290216481], [1,0,-17229669740904638767885350393332951562413714341828385758128479090081583244187998208,0,-71235119005677090243907227200286049434393307742277600967494975973115889925067636736,0,-5259378713381781018295191965451438296538249792128869065118144857985370794902945792,0,-67185232557396629198034682141700718381157435991581841393585439368871735885394083840] ]; } B=8*10^4;for (j = 1, #v, print (j, "\tdisc = ", nfdisc([Pol(v[j]),B]))); \\ regression cases: nfdisc([x^64+2^16, 2]) { setrand(4); nfdisc([x^16+55217847968*x^14+11568829819230010799488*x^12+19573246544559873463135725971456*x^10+115798873240393273382017613115315418501120*x^8+9751010259434557755318401766641355472978476793856*x^6+2904119935452194825826787270394602800779367044985691045888*x^4+6769347776028701650273803177165355131571803342503490887843053568*x^2+63248430005730803250826766342470963758035727918152866840245543135870976,100]) } { \\ #682 setrand(3);nfdisc(x^16-60984*x^12+11303671896*x^8-20089501740000*x^4 +108519183506250000) } { nfdisc([x^24-550424160*x^22+23447555340004224*x^20-254383477518162636864000 *x^18+862812576554550932720517161472*x^16-1110768959838047114430666510009753 600*x^14+541867253550600812790187039808706018508800*x^12-8880986872306708993 8371545135871969866802135040*x^10+502809538666033468057546874414277270924367 6318040064*x^8-104322413758462359374825625780272604972404212502794076160*x^6 +694786520666433058606640970483690360770938934881316184784896*x^4-1330062293 022709810755455132342051017217797022292939901816012800*x^2+16121742882523614 4296369045049933195993063619592571720690380570624,100]) } { nfdisc(x^72-75690*x^66+2229471657*x^60-36061389458264*x^54+392606586400579 074*x^48+539504008591676523876*x^42-426714543074858418197350*x^36-4006505099 33584626955407768*x^30+394042536990878794791484268061*x^24-91837221214280331 370349672199754*x^18+6951526052977952270050730689115037*x^12+785336155384304 5069776294861433728*x^6+4160868820129268027225702088135675904) } f=x^3 - 17298759218009623610183566031041339386720075700346652258609213718601496711017550 61362121841699226629974891813971909562156420018402691827454215309735885355556958 2565670693186076986600637143595083773458690435867304359843677566038921950799648* x^2 + 18711064803260370378157988406301782093292956776803873824168436875360414402394604 63586013733720488993651052248629894449551488639706757608435718517657626971261696 197926369466104020743029503447382758370181747288622353407958575237402147782740*x - 12656647741002885497431100319705272363568484609743163724263941366068388136613989 08689606630749523725171680318089454979912662201922998310310302859164016403007659 6050019301107038128290274152242961922293776060278436798656129125675827400300576; d=poldisc(f); e=valuation(d,2); valuation(nfdisc([f, [2,e; d/2^e,1]]),2) valuation(nfdisc([f, [2]]), 2) T = (x+1)^2 + 3*5^2*7^31; P = [[7], [5,7], factor(poldisc(T)), 7, 2]; for (i=1,#P, print(nfbasis([T,P[i]]), ", ", nfdisc([T,P[i]]))); p=10^100+267; q=10^120+79; T=polcompositum(x^2-p,x^2-q,2); nfdisc([T,[2,p,q]]) \\#1710 nfdisc(x^10-29080*x^5-25772600) \\#1735 P=x^10-2*x^9+12*x^8-12*x^7-181*x^6-4*x^5-6899*x^4+9780*x^3+6360*x^2+702*x-45; setrand(3); nfdisc(P) setrand(138); nfdisc(P) \\#2011 {nfdisc([ x^8 - 1852391133887779557197954101589261582189937135300705361732122605016667 5063444487117209600000002*x^6 + 66046032206948280681505445107777407158857150 7786666214157824890103497236708061373121624051677103378820065953589806447932 3040479517382543883335153986997613941795159674242391254234108671759292877251 5031154397064403303886209889075200000016*x^4 - 61171542244308866675691121761 6327714005525597151441388699040484267060775757052196963817130148238195987896 6448748825708153340901285158840187363891895981048830978300458035511777195248 8895145381018279012769938416424729156645871771884187596259840899356835906874 7730396358706617053542591613414581062482029464867475302414234419200000000*x^ 2 + 109051959257031239482474293713904499500234667691020023406541348336965128 5433328371966513980373672720867274391022554420298936550273060002685473689170 1545816271286317334966430106620557285909297145868903907602494913712472583649 0320168126428075024986655173099965777776148070297038169609742633321238475716 0277240403200637394323973803072310856025374382648070080573188733759065218101 9265646095092838488158448902084901164447371316596773535481703804984969764903 32160000000000000000, 500000])} pari-2.11.2/src/test/in/sort0000644000175000017500000000143013326135265014250 0ustar billbilldefault(realprecision,38); v = [[1,2], [4,1], [3,4], [1,3/2], [5/2,1.]]; a = [1,2]; b = [5,2]; w = vecsort(v) vecsearch(w, a) vecsearch(w, b) K = [ 1, 2, 3, [2,1], [3,1], (x,y)->x[1] - y[1] ]; { for (i = 1, #K, iferr (w = vecsort(v, K[i]); print(w); print(vecsearch(w, a, K[i])); print(vecsearch(w, b, K[i])), E, print(E)) ) } v = [x^2+1, x^3-2, x+1, x^2+27]; f(x)=poldisc(x); vecsort(v, f) vecsort(v, f, 1) vecsort(v, f, 1+4) vecsort(v, f, 1+4+8) vecsearch(v, x+10, f) T=vecsort(Vecsmall([4,3,2,1])) vecsearch(T,-1) vecsearch(T,5) vecsearch(T,3) vecsort(List([4,3,2,1])) v=[4,3,4,1,4,2,3]; vecsort(v,, 8) vecsort(v,, 8+1) vecsort(v,, 8+4) vecsort(v,, 8+4+1) vecsort(List(),,4) \\Errors vecsearch(Vecsmall(1),1,1) vecsort(Vecsmall(1),1) pari-2.11.2/src/test/in/divisors0000644000175000017500000000072113326135265015125 0ustar billbilldivisorslenstra(245784, 1, 65) divisorslenstra(245784, 19, 65) divisorslenstra(288288, 1, 71) divisorslenstra(288288, 28, 71) divisorslenstra(2841696, 2, 175) divisorslenstra(2841696, 23, 175) divisorslenstra(1680,1,13) divisorslenstra(4,1,2) \\ #1930 divisorslenstra(2,1,2) divisors(1) divisors(12) divisors(1, 1) divisors(12, 1) { for (i=1,100, d = divisors(i,1); for(j=1,#d, if (factorback(d[j][2])!=d[j][1],error(i)))); } fordivfactored(100, d, print(d)) pari-2.11.2/src/test/in/factorint0000644000175000017500000000011112141040641015230 0ustar billbillfactorint(-33623546348886051018593728804851,1) factorint(691160558642,1) pari-2.11.2/src/test/in/idealappr0000644000175000017500000000030513036414402015211 0ustar billbillidealaddtoone(nfinit(x),[1,[;]]); K=nfinit(x^2+23); A=idealhnf(K,x/2); idealtwoelt(K, 3, 6) idealtwoelt(K, A) idealtwoelt(K, A, x) idealtwoelt(K, [;]) idealtwoelt(K, [;], 1) idealtwoelt(K, [;], 0) pari-2.11.2/src/test/in/ellglobalred0000644000175000017500000000106513201017466015707 0ustar billbill\\package:elldata { forell(E,1,9999, N = ellconvertname(E[1])[1]; M = ellglobalred( ellinit(E[2], 1) )[1]; if (N != M, print(E," bad for N = ",N)) ); } ellidentify(ellinit([1,1])) ellsearch("11a1") ellsearch("11a") ellsearch("11b") ellsearch("11") ellsearch([11,0,1]) ellsearch([11,0]) ellsearch([11]) ellsearch(11) ellinit("11a1").j iferr(ellsearch([0,0,0,0]),E,E) iferr(ellsearch([0,0,0]),E,E) iferr(ellsearch("curve"),E,E) iferr(ellsearch(I),E,E) c=0;forell(E,1,100,c++); c c=0;forell(E,1,100,c++,1); c ellidentify(ellinit([1,1],nfinit('a^2-5))) pari-2.11.2/src/test/in/ffisom0000644000175000017500000001174713326135265014560 0ustar billbillfpisom2(l,P,Q)= { my(L, x=variable(P)); L = polrootsmod(P, [l,subst(Q,x,MAXVARN)]); subst(lift(L),MAXVARN,x)*Mod(1,Q); } fptest(l,P,Q)= [ if(subst(P,x,c),error([a,l,P,Q])) | c<-fpisom2(l,P,Q)]; print("-------------e=0--------------"); fptest(13,x^4+2*x^2+2*x+1,x^4+2*x^3+2*x^2+1); fptest(131,x^10+126*x^5+78,x^10+128*x^5+70); fptest(11,x^3+2*x^2+6*x+7,x^3+5*x^2+3*x+6); fptest(1009,x^17+x+25,x^17+42*x^16+61*x^15+952*x^14+113*x^13+398*x^12+694*x^11+238*x^10+465*x^9+308*x^8+545*x^7+145*x^6+79*x^5+896*x^4+515*x^3+63*x^2+808*x+1008); fptest(1009,x^16+x^15+964*x^14+911*x^13+650*x^12+165*x^11+451*x^10+957*x^9+342*x^8+616*x^7+212*x^6+595*x^5+130*x^4+63*x^3+340*x^2+537*x+694,x^16+11); fptest(1009,x^20+595*x^19+863*x^18+194*x^17+127*x^16+364*x^15+31*x^14+869*x^13+422*x^12+663*x^11+669*x^10+28*x^9+9*x^8+937*x^7+35*x^6+292*x^5+302*x^4+441*x^3+863*x^2+118*x+1,x^20+919*x^19+582*x^18+634*x^17+881*x^16+563*x^15+966*x^14+892*x^13+894*x^12+40*x^11+322*x^10+961*x^9+431*x^8+172*x^7+641*x^6+599*x^5+1001*x^4+718*x^3+582*x^2+851*x+1); fptest(23,x^20+x+5,x^20+4*x^19+15*x^18+17*x^17+6*x^16+3*x^15+8*x^14+16*x^13+11*x^12+20*x^11+x^10+20*x^9+11*x^8+16*x^7+8*x^6+3*x^5+6*x^4+17*x^3+15*x^2+4*x+1); fptest(10007,x^30+9557*x^29+7812*x^28+7090*x^27+7645*x^26+4110*x^25+3307*x^24+5763*x^23+7900*x^22+3872*x^21+8123*x^20+4076*x^19+3265*x^18+3777*x^17+3398*x^16+5674*x^15+4018*x^14+6820*x^13+6479*x^12+984*x^11+5652*x^10+1129*x^9+7573*x^8+1822*x^7+837*x^6+4169*x^5+4787*x^4+1616*x^3+5185*x^2+2649*x+1933,x^30+x+2); fptest(67108879,x^30+67107859*x^29+502860*x^28+41752426*x^27+47923483*x^26+56252217*x^25+29702433*x^24+34566275*x^23+43724662*x^22+43031233*x^21+6098024*x^20+7989587*x^19+27885185*x^18+50348895*x^17+46982824*x^16+27081672*x^15+64032686*x^14+24948096*x^13+22483934*x^12+62577008*x^11+33925741*x^10+21192636*x^9+60947997*x^8+24913164*x^7+28577178*x^6+19817925*x^5+12532882*x^4+28467302*x^3+18972253*x^2+4366256*x+32457808,x^30+50150808*x^29+63186895*x^28+49093281*x^27+9998922*x^26+33903391*x^25+64572368*x^24+18465285*x^23+9365844*x^22+146044*x^21+52005244*x^20+51914117*x^19+50853399*x^18+47731827*x^17+63045151*x^16+30915147*x^15+52060592*x^14+54056376*x^13+50213837*x^12+47827172*x^11+33322080*x^10+37183875*x^9+59905379*x^8+12524247*x^7+53983516*x^6+18456131*x^5+47473382*x^4+30607833*x^3+17662487*x^2+66659374*x+2497577); print("-------------e=1--------------"); fptest(11,x^11+x^9+9*x^7+3*x^6+8*x^5+7*x^4+5*x^3+x^2+10*x+3,x^11+10*x+1); fptest(7,x^14+x+4,x^14+5*x^8+5*x^7+x^2+2*x+5); fptest(5,x^30+4*x^26+4*x^25+3*x^20+3*x^16+3*x^12+3*x^8+4*x^6+3*x^4+x^2+x+4,x^30+x^3+x+3); fptest(7,x^35+2*x^2+x+6,x^35+2*x^28+6*x^24+3*x^23+4*x^22+4*x^21+3*x^17+5*x^16+2*x^15+x^14+5*x^13+x^12+4*x^11+4*x^10+5*x^9+4*x^8+3*x^7+2*x^6+6*x^5+3*x^4+x^3+2*x^2+2*x+3); print("-------------e=2--------------"); fptest(2,x^4+x+1,x^4+x^3+1); fptest(5,x^25+2*x^3+3*x+2,x^25+2*x^19+3*x^17+4*x^16+2*x^15+x^14+x^13+3*x^12+2*x^11+4*x^10+2*x^8+4*x^7+4*x^5+2*x^4+3*x^3+2*x+2); fptest(3,x^18+x^3+2*x+1,x^18+x^17+2*x^16+2*x^15+x^14+x^13+x^12+x^11+x^10+2*x^9+x^7+2*x^5+x^4+2*x^3+1); fptest(2,x^20+x^3+1,x^20+x^14+x^13+x^10+x^7+x^5+x^4+x^3+x^2+x+1); print("-------------e=3--------------"); fptest(2,x^8+x^4+x^3+x+1,x^8+x^6+x^5+x^3+1); fptest(3,x^27+x^5+x^3+x^2+2*x+2,x^27+x^25+2*x^24+x^23+x^22+x^20+x^17+2*x^15+2*x^13+x^12+2*x^11+2*x^10+x^9+2*x^8+x^7+2*x^6+2*x^5+2*x^4+2); fptest(2,x^40+x^5+x^4+x^3+1,x^40+x^38+x^37+x^36+x^35+x^34+x^32+x^31+x^30+x^29+x^28+x^25+x^23+x^19+x^16+x^15+x^13+x^11+x^10+x^9+x^7+x^5+x^3+x^2+1); print("-------------e>=4--------------"); fptest(2,x^16+x^15+x^14+x^12+x^7+x^6+x^5+x^2+1,x^16+x^5+x^3+x+1); fptest(2,x^32+x^7+x^3+x^2+1,x^32+x^29+x^28+x^27+x^25+x^24+x^22+x^18+x^17+x^15+x^14+x^13+x^11+x^5+x^4+x^3+1); fptest(2,x^64+x^4+x^3+x+1,x^64+x^59+x^57+x^56+x^53+x^52+x^51+x^48+x^47+x^46+x^45+x^42+x^40+x^39+x^35+x^33+x^32+x^30+x^29+x^26+x^25+x^24+x^22+x^21+x^20+x^18+x^17+x^14+x^13+x^11+x^10+x^7+x^5+x^2+1); fptest(2,x^48+x^5+x^3+x^2+1,x^48+x^46+x^45+x^43+x^42+x^40+x^39+x^38+x^37+x^35+x^34+x^33+x^31+x^29+x^25+x^19+x^18+x^16+x^12+x^9+x^4+x^3+1); print("----------large p---------------"); fptest(300007,x^29+111826*x^28+192245*x^27+118259*x^26+116591*x^25+90193*x^24+179240*x^23+218526*x^22+105853*x^21+39775*x^20+120877*x^19+141649*x^18+95990*x^17+253141*x^16+113157*x^15+174998*x^14+231363*x^13+45405*x^12+279688*x^11+260746*x^10+295341*x^9+186647*x^8+1286*x^7+5846*x^6+226308*x^5+155249*x^4+161003*x^3+892*x^2+124319*x+45791 ,x^29+144375*x^28+258947*x^27+2448*x^26+213576*x^25+275912*x^24+295000*x^23+16021*x^22+62890*x^21+223177*x^20+133874*x^19+291070*x^18+268346*x^17+231097*x^16+27675*x^15+181579*x^14+144969*x^13+37193*x^12+236074*x^11+44381*x^10+87819*x^9+180121*x^8+195512*x^7+82624*x^6+113318*x^5+67595*x^4+26623*x^3+13359*x^2+191742*x+143596); print("----------huge p---------------"); p=nextprime(3^64);P=ffinit(p,19);Q=poltschirnhaus(P);fptest(p,P,Q); p=nextprime(3^66);P=ffinit(p,19);Q=poltschirnhaus(P);fptest(p,P,Q); p=1208925819614629174706189; P=x^3+154950186819311566804335*x^2+793256884583803289109038*x+629557146926040851399629; Q=factormod(polcyclo(13),p)[3,1]; fptest(p,P,Q); pari-2.11.2/src/test/in/sumnum0000644000175000017500000000701713326135265014614 0ustar billbilldefault(realprecision,38); allocatemem(40 * 10^6); check(a,b)=my(c=abs(a-b)); if(!c,oo, ceil(log(c)/log(10))); check(sumnummonien(n=1,1/n^2), Pi^2/6) check(sumnummonien(n=1,log(1+1/n)/n), sumpos(n=1,log(1+1/n)/n)) tab=sumnummonieninit(,1); check(sumnummonien(n=1, 1/n^2, tab), -zeta'(2)) sumnummonien(n=0,1/(n+1)^2) sumnummonien(n=2,1/(n+1)^2) tab=sumnummonieninit(1,,0); sumnummonien(n=0,1/(n+1)^2,tab) tab=sumnummonieninit([3,0]); check(sumnummonien(n=1,n^-3,tab), zeta(3)) tab=sumnummonieninit([1,1/2],,0); sumnummonien(n=0,1/(n+1)^(3/2),tab) tab=sumnummonieninit([1/2,1],n->1); sumnummonien(n=1,1/n^(3/2),tab) tab=sumnummonieninit([1/2,1],n->1,2); sumnummonien(n=2,1/n^(3/2),tab) TEST=[n->1/(n^2+1), n->log(1+1/n)/n, n->lngamma(1+1/n)/n, n->sin(1/sqrt(n))/n^(3/2)]; FUN=[f->sumnum(n=1,f(n)), f->sumnummonien(n=1,f(n)), f->sumnumap(n=1,f(n))]; localprec(57); V=[sumnummonien(n=1,f(n)) | f<-TEST]; { for (i = 1, #TEST, my (f = TEST[i]); print(f); for (j = 1, #FUN, my (SUM = FUN[j]); my (t = check(SUM(f), V[i])); print(t); ) ) } sumnum(n = [1, -3/2], sin(1/sqrt(n))/n) sumnumap(n = [1, -3/2], sin(1/sqrt(n))/n) tab=sumnummonieninit(,n->log(n)^2); check(sumnummonien(n=1, 1/n^2, tab), zeta''(2)) tab=sumnummonieninit(,n->log(n),2); check(sumnummonien(n=2,1/n^2,tab), -zeta'(2)) sumnummonien(n=1,1/n^2,tab) \\error tab=sumnummonieninit([1,2]); check(sumnummonien(n=1, 1/n^3, tab), zeta(3)) tab=sumnummonieninit([1,1/2]); check(sumnummonien(n=1, 1/n^(3/2), tab), zeta(3/2)) localprec(57); V = sumnum(n=[1,-3/2], sin(1/sqrt(n))/n); tmon=sumnummonieninit([1/2,1]); check(sumnummonien(n=1, sin(1/sqrt(n))/n, tmon), V) check(sumnum(n=[1,-3/2], sin(1/sqrt(n))/n), V) T=sumnumapinit([oo,-3/2]); check(sumnumap(n=[1,-3/2], sin(1/sqrt(n))/n, T), V) { localprec(77); tmon=sumnummonieninit([1/2,1]); check(sumnummonien(n=1,n^(-3/2), tmon), zeta(3/2)) } \p115 z2 = zeta(2); z3 = zeta(3); z32 = zeta(3/2); z73 = zeta(7/3); check(sumnumlagrange(n=1,n^-2),z2) check(sumnumlagrange(n=2,n^-2),z2-1) tab=sumnumlagrangeinit([1,0]); check(sumnumlagrange(n=1,n^-2,tab),z2) check(sumnumlagrange(n=2,n^-2,tab),z2-1) tab=sumnumlagrangeinit([2,0]); check(sumnumlagrange(n=1,n^-3,tab),z3) check(sumnumlagrange(n=2,n^-3,tab),z3-1) tab=sumnumlagrangeinit([1/2,0]); check(sumnumlagrange(n=1,n^(-3/2),tab),z32) check(sumnumlagrange(n=2,n^(-3/2),tab),z32-1) tab=sumnumlagrangeinit([1/3,0]); check(sumnumlagrange(n=1,n^(-7/3),tab),z73) check(sumnumlagrange(n=2,n^(-7/3),tab),z73-1) tab=sumnumlagrangeinit(1/3); check(sumnumlagrange(n=1,n^(-7/3),tab),z73) check(sumnumlagrange(n=2,n^(-7/3),tab),z73-1) \p 308 a = sumpos(n=1, 1/(n^3+n+1)); b = sumpos(n=1, 1/(n^3+n+1), 1); check(a, b) tab = sumnuminit(); b = sumnum(n=1, 1/(n^3+n+1), tab); check(a, b) a = sumpos(n=1,1/(n^2+1)); b = sumpos(n=1,1/(n^2+1), 1); check(a, b) b = sumnum(n=1,1/(n^2+1), tab); check(a, b) check(sumnum(n=[1,-4/3],n^(-4/3)), zeta(4/3)) tab = sumnuminit([+oo,-3/2]); check(sumnum(n=1,1/(n*sqrt(n)),tab), zeta(3/2)) \\ check(suminf(n=1, 2^(-n)), 1) check(suminf(n=1, [2^(-n),3^(-n)]), [1,1/2]) check(sumpos(n=1, 2^(-n)), 1) check(sumnum(n=[1, 1],2^(-n)), 1) check(sumnumap(n=[1, 1],2^(-n)), 1) \p38 f(x) = -log(cos(x)); F = truncate( f(t + O(t^16)) ); g(x) = if (x > 1e-2, f(x), subst(F,t,x)); sumpos(n=1,g(1/n)) sumpos(n=0,0) \\#1729 \p19 sumpos(n=1,1/n^2) \\ ERRORS: keep them at end of file sumnum(n=1,1/n^2,"bug"); sumnumap(n=1,1/n^2,"bug"); intnumapinit(x,y) sumnummonieninit([-1,1]); sumnummonieninit([1,-1]); sumnummonieninit(,[n->2^-n,oo]); sumnumlagrangeinit([1/5,0]) sumnumlagrangeinit(x) pari-2.11.2/src/test/in/map0000644000175000017500000000261513447371554014053 0ustar billbillshankslog(a,g,card)= { my(M=Map()); my(h=a,B=sqrtint(card)+1); for(i=0,B-1, mapput(M,h,i); h*=g); g2=h*a^-1; h=1; for(i=0,B,my(j); if(mapisdefined(M,h,&j), return(i*B-j)); h*=g2); error("shankslog: not found"); } if(Mod(2,1000003)^shankslog(Mod(3,1000003),Mod(2,1000003),1000002)!=3, error("shankslog")); tablelog(g,card)= { my(M=Map()); my(h=1); for(i=0,card-1, mapput(M,h,i);h*=g); M; } tablelogdel(g,card)= { my(M=Map()); my(h=1); for(i=0,card-1, mapput(M,h,i);h*=g); h=1; for(i=0,card-1, mapdelete(M,h);h*=g); #M; } a=ffgen(5^5,'a); g=ffprimroot(a); T=tablelog(g,5^5-1); if(g^mapget(T,a^2+a+1)!=a^2+a+1,error("shankslog")); if(tablelogdel(g,5^5-1),error("mapdelete")); M=Map([1,2;3,4;5,6]) Vec(M) Vecrev(M) Mat(M) apply(sqr,M) for(i=0,2,mapput(M, 2*i+1, -mapget(M,2*i+1)));M M0=Map(matrix(10,2,i,j,i)); M1=Map(matrix(10,2,i,j,if(j==1,i,i*x^0))); M2=Map(matrix(10,2,i,j,11-i)); M3=Map(matrix(10,2,i,j,12-i)); M4=Map(matrix(10,2,i,j,i*x^0)); MV=[M0,M1,M2,M3,M4]; [a==b|a<-MV;b<-MV] [a===b|a<-MV;b<-MV] cmp(M0,M1) cmp(M0,M0) M=Map(); mapput(M,2,3); mapdelete(M,2); M mapisdefined(M,2) mapput(M,2,3);M M=Map([1,2;3,4;5,6]); mapget(M,7) mapdelete(M,7) Vec(M,1) Vec(M,-1) Map([1,2;2,3;1,3;1,4]) \\ Errors, keep at end L=List(); mapdelete(1,1) mapdelete(L,1) mapget(1,1) mapget(L,1) mapisdefined(1,1) mapisdefined(L,1) mapput(1,1) mapput(L,1) Map(1) pari-2.11.2/src/test/in/compat0000644000175000017500000001032413201017466014540 0ustar billbillabs() addell() addprimes() adj() akell() algdep2() algtobasis() anell() apell() apell2() apprpadic() assmat() basis() basis2() basistoalg() bilhell() bin() boundcf() boundfact() buchcertify() buchfu() buchgen() buchgenforcefu() buchgenfu() buchimag() buchinit() buchinitforcefu() buchinitfu() buchnarrow() buchray() buchrayinit() buchrayinitgen() buchreal() bytesize() cf() cf2() changevar() char() char1() char2() chell() chptell() classno() classno2() coeff() compimag() compo() compositum() compositum2() comprealraw() conductor() conductorofchar() convol() core2() coredisc2() cvtoi() cyclo() decodefactor() decodemodule() degree() denom() deplin() det() det2() detint() diagonal() disc() discf() discf2() discrayabs() discrayabscond() discrayabslist() discrayabslistarch() discrayabslistarchall() discrayabslistlong() discrayrel() discrayrelcond() divres() divsum() eigen() euler() extract() fact() factcantor() factfq() factmod() factoredbasis() factoreddiscf() factoredpolred() factoredpolred2() factorpadic2() factpol() factpol2() fibo() fpn() galois() galoisapply() galoisconj() galoisconj1() galoisconjforce() gamh() gauss() gaussmodulo() gaussmodulo2() globalred() goto() hclassno() hell() hell2() hermite() hermite2() hermitehavas() hermitemod() hermitemodid() hermiteperm() hess() hilb() hilbp() hvector() i() idealaddmultone() idealaddone() idealapprfact() idealdivexact() idealhermite() idealhermite2() idealinv2() ideallistarchgen() ideallistunit() ideallistunitarch() ideallistunitarchgen() ideallistunitgen() ideallistzstar() ideallistzstargen() ideallllred() idealmulred() idealpowred() idealtwoelt2() idmat() image() image2() imagecompl() incgam1() incgam2() incgam3() incgam4() indexrank() indsort() initalg() initalgred() initalgred2() initell() initzeta() integ() intersect() intgen() intinf() intopen() inverseimage() isdiagonal() isfund() isideal() isincl() isinclfast() isirreducible() isisom() isisomfast() isoncurve() isprincipal() isprincipalforce() isprincipalgen() isprincipalgenforce() isprincipalray() isprincipalraygen() ispsp() isqrt() isset() issqfree() isunit() jacobi() jbesselh() jell() karamul() kbessel() kbessel2() ker() keri() kerint() kerint1() kerint2() kro() label() lambdak() laplace() legendre() lexsort() lindep2() lll() lll1() lllgen() lllgram() lllgram1() lllgramgen() lllgramint() lllgramkerim() lllgramkerimgen() lllint() lllintpartial() lllkerim() lllkerimgen() lllrat() ln() localred() logagm() lseriesell() makebigbnf() mat() matextract() mathell() matrixqz2() matrixqz3() minideal() minim() minim2() mod() modp() modulargcd() mu() nfdiv() nfdiveuc() nfdivres() nfhermite() nfhermitemod() nfmod() nfmul() nfpow() nfreduce() nfsmith() nfval() nucomp() numer() nupow() o() ordell() order() orderell() ordred() pascal() perf() permutation() permutation2num() pf() phi() pi() pnqn() pointell() polint() polred2() polredabs2() polredabsall() polredabsfast() polredabsnored() polvar() poly() polylogd() polylogdold() polylogp() polyrev() polzag() powell() powrealraw() prec() primedec() primroot() principalideal() principalidele() prodinf1() qfi() qfr() random() rank() rayclassno() rayclassnolist() recip() redimag() redreal() redrealnod() reduceddisc() regula() reorder() resultant() resultant2() reverse() rhoreal() rhorealnod() rndtoi() rnfdiscf() rnfequation2() rnfhermitebasis() rootmod() rootmod2() rootpadic() roots() rootsof1() rootsold() rounderror() series() set() sigmak() signat() signunit() simplefactmod() size() smallbasis() smallbuchinit() smalldiscf() smallfact() smallinitell() smallpolred() smallpolred2() smith() smith2() smithclean() smithpol() sort() sqred() srgcd() sturm() sturmpart() subcyclo() subell() sumalt2() sumpos2() supplement() sylvestermatrix() taniyama() tchebi() teich() threetotwo() threetotwo2() torsell() trans() trunc() tschirnhaus() twototwo() unit() vec() vecindexsort() veclexsort() vvector() weipell() wf() wf2() zell() zideallog() zidealstar() zidealstarinit() zidealstarinitgen() box() color() cursor() draw() initrect() killrect() line() lines() move() ploth2() plothmult() point() points() postdraw() postploth() postploth2() postplothraw() pprint() pprint1() print() print1() rbox() read() rline() rlines() rmove() rpoint() rpoints() scale() setprecision() setserieslength() settype() string() texprint() pari-2.11.2/src/test/in/list0000644000175000017500000000155713447371554014255 0ustar billbillL = List(); for (i=1,10^5,listput(L,i)) L = List([1,2,3]); for (i=1,5000,listinsert(L,i,3)) L = List([1,2,3,3]); concat(L,5) concat(1,L) L = concat(L,L) listsort(L); L listsort(L,1); L listpop(L); L listpop(L,1); L \\ L = List([[1,2,3], 2]) L[1][1] = 3 L L = List([Vecsmall([1,2,3]), 2]) L[1][1] = 3 L = List(); listput(L,1); listpop(L); listpop(L); matdiagonal(List([0])) g(L)=for(i=1,5,listput(L,5-i));L; l=List([10,9,8,7,6,5]); g(l) l listkill(l) listcreate() subst(List([x,x^2+y]),x,1) substvec(List([x,y]), [x,y], [y,x]) substpol(List([x^2,x^3]), x^2, y) getheap()[1] chinese(List()) chinese(List([Mod(1,3)])) chinese(List([Mod(0,2),Mod(1,3),Mod(2,5)])) liftint(List([0,1])) L = List([1,2,3]); List(L) L[1] L[1]*=2 L L[1]=3 L \\ Errors, keep at end of file listpop(1) L='L; listpop(L) listput(L,1) listinsert(L,1,1) L=Map(); listpop(L) listput(L,1) listinsert(L,1,1) pari-2.11.2/src/test/in/ellmodulareqn0000644000175000017500000000017313201017466016122 0ustar billbill\\package:seadata ellmodulareqn(2) ellmodulareqn(11) ellmodulareqn(3,y,z) \\ errors ellmodulareqn(1) ellmodulareqn(2,y,x) pari-2.11.2/src/test/in/lambert0000644000175000017500000000105613326135265014713 0ustar billbilldo(y)=my(x = lambertw(y)); exp(x)*x / y; do(-1) do(I) default(realprecision,38); do(2) default(realprecision,211); do(1e14) do(y)= { my(x = lambertw(y), e = normlp(Vec(exp(x)*x - y))); if (e > 2e-37, error([e, y])); } default(realprecision,38); do(O(x^10)) do(O(x^30)) do(3+O(x^10)) do(3+O(x^30)) do(x) do(x+O(x^10)) do(x+O(x^30)) do(3+O(x)) do(3+x) do(3+x+O(x^10)) do(3+x+O(x^30)) do(x^2-2*x^3) do(x^2-2*x^3+O(x^10)) do(x^2-2*x^3+O(x^30)) do(3+x^2-2*x^3) do(3+x^2-2*x^3+O(x^10)) do(3+x^2-2*x^3+O(x^30)) serlaplace(sin(lambertw(x + O(x^5)))) lambertw(1/x) pari-2.11.2/src/test/in/addprimes0000644000175000017500000000113713036414402015224 0ustar billbillp = nextprime(10^6); q = nextprime(p+1); a = 2*3*5*7; sigma2(x) = sigma(x, 2); sigma3(x) = sigma(x, 3); fun = [ispowerful, moebius, core, omega, bigomega, eulerphi, numdiv, sigma, sigma2, sigma3]; vec(n) = vector(#fun, i, fun[i](n)); args = [a, a*p, a*p*q, a*p^2*q, -a*p]; vals = vector(#args, i, vec(args[i])) TEST() = { for (i=1,#args, my(n = args[i]); print("Testing ", n, ", addprimes = ", addprimes()); if (vec(n) != vals[i], error(n)) ); } addprimes(p); TEST(); addprimes([p,q]); TEST(); removeprimes(p); TEST(); removeprimes(addprimes()) addprimes([p,q,1009]); removeprimes([p,q]) pari-2.11.2/src/test/in/lindep0000644000175000017500000000161013326135265014534 0ustar billbilllindep([sqrt(2), sqrt(3), sqrt(2)+sqrt(3)]) lindep([1, 2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)]) lindep([1,2,3;4,5,6;7,8,9]) lindep([x*y, x^2 + y, x^2*y + x*y^2, 1]) z = sqrt(1+5*y+y^2+y^3); seralgdep(z, 2,3) seralgdep(z, 2,2) seralgdep(1/(1-y+O(y^5)), 1,1) seralgdep(1+5*y+O(y^3), 1,10) lindep([]) lindep([0]) lindep([1]) lindep([1,I]) algdep(1,0) algdep(1,-1) z=sqrt(2+O(7^4)); algdep(z,2) lindep(Mod([E*x, E*x + E, E^2*x^2 + E*x + 2*E], E^3)) lindep([[1,0,0],[0,1,0],[1,1,0]]) lindep([[1,0,0]~,[0,1,0]~,[1,1,0]~]) lindep([[1,0,0]~,[0,1,0]~,[1,1,1]~]) lindep([[1,0,0]~,[0,1,0],[1,1,0]]) lindep([[1,0,0]~,[0,1,0]~,[1,1,0]~]) T=polcyclo(5,'t); zT = polroots(T)[1]; bestapprnf(sqrt(5), T) bestapprnf(x*zT+sqrt(5), T, zT) bestapprnf([exp(2*I*Pi/5)+2], T, zT) z=sqrt(2); bestapprnf(z+1, x^2-2) bestapprnf(z+1, 4*x^2-2) T=x^3-2; vT=polroots(T); z=3*2^(1/3)+1; bestapprnf(z, T, vT[1]) type(bestapprnf(z, T, vT[2])) pari-2.11.2/src/test/in/print0000644000175000017500000000063213457572662014433 0ustar billbillprintsep(":", 1,2,3,4);print(0); printsep(":");print(0); printsep1(":", 1,2,3,4);print(0); printsep1(":");print(0); printsep(":",matid(2));print(0); printsep1(":",matid(2));print(0); printp(matid(2)) q = 2 + 0*quadgen(-3,z); printtex(q) print(q) q = quadgen(-3,z); printtex(q) print(q) q = 2*quadgen(-3,z); printtex(q) print(q) q = 2 + 3*quadgen(-3,'z); printtex(q) print(q) q = 2 + 3*I; printtex(q) print(q) pari-2.11.2/src/test/in/help0000644000175000017500000000041313326135265014211 0ustar billbillf()=1; ?x ?sin ?f ?echo ?default(echo) ?default(log) alias(new,sin) ?new addhelp(x,"test1") addhelp(sin,"test2") addhelp(f,"test3") addhelp(echo,"test4") addhelp(new,"test5") addhelp(addii,"test6") ?x ?sin ?f ?echo ?new ?does_not_exist ? ?. ?\ ?2 ?addii \t g()=0; \u pari-2.11.2/src/test/in/pol0000644000175000017500000000334313326135265014060 0ustar billbillo = [Mod(0,3),y,1/y, (y^2+1)/y, [1,2,3], Vecsmall([1,2,0]), Qfb(1,2,4), Qfb(1,2,-4), y+2*y^2+O(y^4)]; { for (i=1,#o, my (v = o[i]); printsep(" ", Pol(v,y), Pol(v,x), Polrev(v)); printsep(" ", Ser(v,y), Ser(v,x), Ser(v,,5)); ) } o = [2*x+3*y, 2+x+y+O(x^2), 2+x+y+O(y^2)]; { for (i=1,#o, my (v = o[i]); printsep(" ",pollead(v), pollead(v,x), pollead(v,y)) ) } polrecip(1) pollead(z,y) pollead(y,z) polgraeffe(x^2+x+1) polgraeffe(x^3+x+1) polsym(2*x^4+1,4) norm(I*x+1) trace(I*x+1) matcompanion(2*x^2+1) serlaplace(1+x+x^2) serlaplace(x^2+x^3) test()= { my(P,a,V); P=x^4+7*x^3+12*x+5;Q=7*y^3-y-1;Q1=y^3-y-1; a=ffgen([11,5],'a); b=ffgen([2,10],'b); V=[P, x^4+7/2*x^3+12/7*x+5/4, P*Mod(1,11), subst(P,x,x+a), subst(P,x,x+b), subst(P,x,x+y)*Mod(1,Q1), subst(P,x,x+y)*Mod(1,Q), subst(P,x,x+y/3)*Mod(1,Q1), subst(P,x,x+y/3)*Mod(1,Q), subst(P,x,x+y)*Mod(Mod(1,11),Q*Mod(1,11)) ]; for(i=1,#V, my(R=V[i],R2=R^2); if(R2!=R*(R+1)-R,error(R)); if((R+1)^2%R!=1,error(R)); if(R^2%R!=0,error(R)); if(Mod(R,R2+R-1)^-1*R!=1,error(R)); print(i,":" R2)); print("done"); } test() check(A)=if(A^2+A!=A*(A+1),error(A)); A=Mod(-6,y^2-2)*x+Mod(48*z+60,y^2-2);B=Mod(1,y^2-2)*x+Mod(10,y^2-2); A*B A=Mod(1,z^2-z-1)*y+(Mod(1/2*z+1/2,z^2-z-1)*x+Mod(1/2*z+1/2,z^2-z-1)); check(A) A=x^2+y*z*x+Mod(1,y^2+3); check(A) A=x^4+x*y^5+Mod(1,y^2+1); check(A) A=x^4+x*y^5+Mod(1,5*y^2+y+1); check(A) T=x^2+2; polrootsbound(T) polrootsbound(T, 1e-5) \\#1651 f1=(x-1)/(x*x-x); type(subst(1/f1,x,1)) \\#1690 default(realprecision,38); P(x,y)=(x+1)*y^2+(x^2-x+1)*y+(x^2+x); T = P(exp(I*Pi),y); polroots(T) polrootsbound(T) polrootsbound('x) \\ Errors polrootsbound(Pol(0)) polrootsbound(1) Pol("") (1/x) % x pari-2.11.2/src/test/in/whatnow0000644000175000017500000000013213036414402014735 0ustar billbillwhatnow(changevar) whatnow(char) whatnow(allocatemem) whatnow(proveGRH) whatnow(compimag) pari-2.11.2/src/test/in/krasner0000644000175000017500000000107113211621223014712 0ustar billbillfilter_output(p, v) = { vecsort(vector(#v, j, if (type(v[j]) == type([]), my([D,e,f,d]=v[j]); [valuation(poldisc(D), p), e, f, d] , valuation(poldisc(v[j]), p))) , cmp); } do(p,N,flag)=filter_output(p, padicfields(p,N,flag)); p = 2; for (d = 2, 50, if (d%p, print(do(p,d,1)))) p = 3; for (d = 2, 50, if (d%p, print(do(p,d,1)))) do(2, 105, 1) do(5, 21, 1) do(23, 75, 1) do(23459, 18, 1) do(2, [8,12], 1) do(2^21+17, 30, 1) do(2^64+13, 8, 1) do(2^64+13, 2, 1) padicfields(2^64+13, 8, 2) do(2, 4, 1) do(2, 3, 0) padicfields(3,3) padicfields(5,5) pari-2.11.2/src/test/in/interpol0000644000175000017500000000256713201017466015123 0ustar billbilldefault(realprecision, 38); polinterpolate([2,3,4]) polinterpolate([2,3,4] * Mod(1,7)) polinterpolate([2,3,4] * Mod(1,7),, 0) polinterpolate([1,2,4], [2,3,4]) polinterpolate([1,2,4] * Mod(1,7), [2,3,4], 0) polinterpolate([1,2,4], [2,3,4], 1.5) polinterpolate([1,2,4], [2,3,4], 1.5, &e); e polinterpolate([1,2],[0,0]) polinterpolate([],[]) polinterpolate([1],[2]) polinterpolate([],[],Mod(1,2)) polinterpolate([0],[0],Mod(1,2)) polinterpolate([1],[1],Mod(1,2)) z = varhigher("z", x); \\ so variable ordering is z < x < y test(a,b,v) = my(f = polinterpolate(a,b,v)); [f, variable(f)]; test([], [], 1) test([], [], x) test([], [], y) test([], [], z) test([], [], z + 1) \\ expect [0, z], currently returns [0, 0] test([0], [0], 1) test([0], [0], x) test([0], [0], y) test([0], [0], z) test([0], [0], z + 1) \\ expect [0, z], currently returns [0, 0] test([1], [1], 1) test([1], [1], x) test([1], [1], y) test([1], [1], z) test([1], [1], z + 1) \\ expect [1, z], currently returns [1, 0] test([1], [x], 1) test([1], [x], x) test([1], [x], y) test([1], [x], z) test([1], [x], z + 1) \\ expect [x, z], currently returns [x, x] test([0, 1], [0, x], 1) test([0, 1], [0, x], x) test([0, 1], [0, x], y) test([0, 1], [0, x], z) test([0, 1], [0, x], z + 1) test([x, x + 1], [0, 1], 1) test([x, x + 1], [0, 1], x) test([x, x + 1], [0, 1], y) test([x, x + 1], [0, 1], z) test([x, x + 1], [0, 1], z + 1) pari-2.11.2/src/test/in/ellseaJ0000644000175000017500000000024113326135265014637 0ustar billbilldefault(datadir,"nonexistent"); \\ disable cache p=72057594037928017; ellap(ellinit([2,3],p)) ellsea(ellinit([0,1],p)) \\ j=0 ellsea(ellinit([1,0],p)) \\ j=1728 pari-2.11.2/src/test/in/nfeltsign0000644000175000017500000000100213326135265015245 0ustar billbillnf = nfinit(polsubcyclo(11,5)); t = nf.zk[2]; nfeltsign(nf, t) nfeltsign(nf, t, 1) nfeltsign(nf, t, [1..4]) nfeltsign(nf, [1,0,0,0,0]~, [1..4]) nfeltsign(nf, [-1/2,0,0,0,0]~, [1..4]) nfeltsign(nf, 0, 1) nfeltsign(nf, x+950385237198502187979577282097391163977102921506573742575513/495253880608585631635195731645995689515566957889181807495428) nf=nfinit(a^2-2); for(n=1,100,if(nfeltsign(nf,Mod(a+1,a^2-2)^n)!=[(-1)^n,1],print(n))) \\ Errors nfeltsign(nf, a, 3) nfeltsign(nf, a, [-1..1]) nfeltsign(nf, a, [1..3]) pari-2.11.2/src/test/in/forperm0000644000175000017500000000113513326135265014735 0ustar billbilltest(N) = /* compatibility with numtoperm */ { my(i,p); i = 0; forperm(N, p, if (Vecsmall(numtoperm(N,i)) != p, error([N,i,p])); i++ ); } test(1); test(2); test(3); test(4); test(5); forperm([1],p,print(p)) forperm(4,q,print(q)) forperm([1,1,1,3],q,print(q)) forperm([1,2,1,3,1,4],q,print(q)) forperm(Vecsmall([1,2,3,2,3]),q,print(q)) \\ corner cases forperm([],p,print(p)) forperm(Vecsmall([]),p,print(p)) forperm(0,p,print(p)) forperm(1,p,print(p)) \\ errors forperm(p,3,) forperm(1.0,q,) forperm(-1,q,) permsign(Vecsmall([1,1])) permsign(Vecsmall([1,2,1])) permorder(Vecsmall([1,2,1])) pari-2.11.2/src/test/in/sumdedekind0000644000175000017500000000013413036414402015544 0ustar billbillsumdedekind(-2,-3) sumdedekind(2, 4) sumdedekind(123186,28913191) sumdedekind(2^64+1, 2^65) pari-2.11.2/src/test/in/rnfkummer0000644000175000017500000000462613455133537015304 0ustar billbilldefault(realprecision,38); allocatemem(20*10^6) count = 0; do(nf,f, H = 0, flag = 0)= setrand(1); print(count++); lift(rnfkummer(bnrinit(bnfinit(nf,1),f), H, flag)); \\1 do(y^4+12*y^3+15*y^2+15*y-15,1) do(y^4-13*y^3+2*y^2+2*y-15,1) P=do(y^4-y^3-2404*y^2+2404*y+1154401, 5, matdiagonal([5,1])); if(polcoeff(polcoeff(P, 0), 0)<0,-subst(P,x,-x),P) do(quadpoly(-8,y), 11, [5,2;0,1]) \\ behaviour depend on kernel (bnfinit(Kz) too complicated \\do(quadpoly(181433,y),1) \\5 do(quadpoly(-1752,y), 19, matdiagonal([5,1,1])) do(nf=nfinit(y^6-2*y^5+3*y^4+y^2+3*y+1), idealprimedec(nf,2)[1]) do(y^4-52*y^2+26, 3, Mat(5)) do(quadpoly(5288,y), 9, [1,0;0,3]) do(quadpoly(5288,y), 9, [1,0;0,3], 3) \\10 do(y^4+y^3-9*y^2-9*y+11, 10, Mat(5)) do(y^4-y^3-159*y^2-441*y+1701, 10, Mat(5)) do(quadpoly(344,y),11,matdiagonal([5,1])) /* \\ used to be very slow (>20h). Now ~ 7mn do(quadpoly(17,y),311,Mat(13)) do(nf=nfinit(y^4-y^3+2*y+1), idealprimedec(nf,463)[2]); do(y^2+5393946914743),1,,3); */ /* 0 eq. OK at \p200 */ do(y^6-19*y^5-11*y^4-6*y^3-15*y^2-11*y+15, 4, [2,1,1; 0,1,0;0,0,1]) /* more than 1 eq. OK at \p200 */ P=do(y^6+8*y^5-7*y^4+y^3+4*y^2-9*y+10, 8, [2,1,1,1,1;0,1,0,0,0;0,0,1,0,0;0,0,0,1,0;0,0,0,0,1]); (P==x^2+(1/4*y^5+9/4*y^4+1/2*y^3+3/4*y^2+7/4*y-3/2)) || (P==x^2+(-1/4*y^5-7/4*y^4+7/2*y^3-15/4*y^2+11/4*y-3/2)) /* 1 eq. Wrong result at \p28. OK at \p200 */ \\15 do(y^6-9*y^5-20*y^4-4*y^2-y-17, 17, [2,0,1;0,1,0;0,0,1]) setrand(1); for(i=1,10,rnfkummer(bnrinit(bnfinit(quadpoly(2540,y)),9),[3,1;0,1])) do(quadpoly(689,y), 2, Mat(2)) do(y^8-76*y^6+1425*y^4-5776*y^2+5776, 5, matdiagonal([2,1])) do(y^4 - 34*y^2 + 1189, 5, matdiagonal([3,1,1])) do(y, [36,[1]], matdiagonal([3,1]), 3) \\20 do(y, [36,[1]], matdiagonal([3,1])) K=bnrinit(bnfinit(y^4-y^3+16*y^2-16*y+61),[89,9,52,85;0,1,0,0;0,0,1,0;0,0,0,1]); rnfkummer(K,,5) \\ #1632 do(quadpoly(3409,y),25,[5,1;0,1]) \\ #1744 lift(rnfkummer(bnrinit(bnfinit(y^4-62*y^2+186,1),744),[1,0,0,0;0,1,0,0;0,0,2,1;0,0,0,1])) \\ #1760 mod=[[385,0,305;0,385,265;0,0,5],[0]]; bnr=bnrinit(bnfinit(y^3-y^2+1),mod); lift(rnfkummer(bnr,[1,0,0;0,2,1;0,0,1])) mod=[[429,234,78;0,39,0;0,0,39],[0]]; bnr=bnrinit(bnfinit(y^3+y-1,1),mod); lift(rnfkummer(bnr,[2,1,1;0,1,0;0,0,1])) \\ #1864 bnr=bnrinit(bnfinit(y^7+7*y^3-7*y^2+7*y+1,1),8); L=subgrouplist(bnr,[2],1); apply(z->lift(rnfkummer(bnr,z)),L) \\ #1873 rnfkummer(bnrinit(bnfinit(y^6-2*y^5+8*y^4-18*y^3+24*y^2-18*y+6),168),matdiagonal([2,1,1,1,1,1,1,1])) pari-2.11.2/src/test/in/io0000644000175000017500000000216613326135265013677 0ustar billbillF="io-testfile"; del()=system(Str("rm -f ", F)); del() write(F, 123) write(F, 456) write1(F, "a",7) write1(F, "b") write(F) writetex(F, 1/2) readstr(F) del() \\ write(F, 1) write(F, "1+2") readvec(F) del() \\ writebin(F,1) read(F) del() writebin(F) read(F) del() L=List();writebin(F,L) read(F) del() \\ write(F,"1+1") extern("cat "F) externstr("cat "F) del() { my(f=fileopen(F,"w")); for(i=1,10, filewrite(f,i)); fileclose(f); my(f=fileopen(F,"a")); for(i=1,10, filewrite1(f,i); fileflush(f)); filewrite1(f,"\n"); fileclose(f); my(i=0,l,f=fileopen(F)); while(l=fileread(f), print(i++,":",eval(l))); fileclose(f); my(i=0,l,f=fileopen(F,"r")); while(l=filereadstr(f), print(i++,":",l)); fileflush(); fileclose(f); } my(f=fileopen(F));fileclose(f);fileread(f) my(f=fileopen(F));fileclose(f);filereadstr(f) my(f=fileopen(F));fileclose(f);filewrite(f,"b") my(f=fileopen(F));fileclose(f);filewrite1(f,"b") my(f=fileopen(F));fileclose(f);fileflush(f) my(f=fileopen(F,"w"));fileread(f) my(f=fileopen(F,"a"));filereadstr(f) my(f=fileopen(F));filewrite(f,"b"); my(f=fileopen(F,"r"));filewrite1(f,"b"); fileflush('x) pari-2.11.2/src/test/in/lex0000644000175000017500000000143013326135265014051 0ustar billbillv = [0, 2, [1,2], [1,2;3,4], [1,0;1,2], [1,2,3]~, [1,2,3;4,5,6]]; isvec(x) = type(x) == "t_VEC" || type(x) == "t_COL"; { for (i = 1, #v, for (j = i, #v, s = lex(v[i],v[j]); print([i,j,s]); if (s != -lex(v[j], v[i]), error(2)); if (isvec(v[i]) && lex(Vecsmall(v[i]), v[j]) != s, error(3)); if (isvec(v[j]) && lex(v[i], Vecsmall(v[j])) != s, error(4)); ) ); } lex(1,[1]) lex(1,[2]) lex(1,[0]) lex([1],Mat(1)) lex([1],Mat([1,0]~)) v = Vecsmall([1,2,3]); lex(v, [1,2,3]) lex(v, [1,2]) lex(v, Vecsmall([1,2])) lex(v, Vecsmall([1,2,3,4])) lex(v, Vecsmall([1,2,4])) lex(v, Vecsmall([1,2,2])) lex(v, [1,2,4]) lex(v, [4,2,3]) lex(v, [0,2,3]) lex(v, [[1,2,3],2,3]) lex(v, [[0,2,3],2,3]) lex(v, [[],2,3]) lex(v, [Vecsmall([]),2,3]) lex(v, [Vecsmall(1),2,3]) pari-2.11.2/src/test/in/parallel0000644000175000017500000000373113455326605015066 0ustar billbillV=[2^256 + 1, 2^193 - 1]; parapply(factor,V) my(V=[2^256 + 1, 2^193 - 1]); parvector(#V,i,factor(V[i])) fun(V)=pareval(vector(#V,i,()->factor(V[i]))); fun(V) parfirst(fun,V)=parfor(i=1,#V,fun(V[i]),j,if(j,return([i,j]))); parfirst(isprime, [2^600..2^600+1000])[1] parselect(isprime, [2^600..2^600+1000],1) parselect(isprime, [2^600..2^600+1000]) isfermatprime(p)=Mod(2,p)^(p-1)==1; select(x->x==1,parapply(isfermatprime,[2^600..2^600+1000]),1) parselect(isfermatprime,[2^600..2^600+1000],1) select(isfermatprime,[2^600..2^600+1000]) parfirst(isfermatprime,[2^600..2^600+1000]) parselect(isfermatprime,[2^600..2^600+1000]) /* Disable tests that depends on ellsea findp(E,n)= { my(check(p) = my(c=ellcard(E,p)); if(isprime(c),c,0)); parforprime(p=2^n,,check(p),card,if(card,return([p,card]))); } my(E=ellinit([1,3])); findp(E,80) */ parsum(i=1,10000,moebius(i)) parsum(i=1,100,issquare(poldisc('x^36+i!+1))) inline(ell,ell2); ell(a,B,N)=my(E=ellinit([0,0,0,a,1]*Mod(1,N))); ellpow(E,[0,1]*Mod(1,N),B); ecm(N,t,B)= iferr(parvector(t,a,ell(a,B,N)),err,gcd(lift(component(err,2)),N),errname(err)=="e_INV"); ecm(2^101-1,500,600!) ell2(a,B,N)=iferr(ell(a,B,N),err,return(gcd(lift(component(err,2)),N)),errname(err)=="e_INV");0; ecm2(N,t,B)=my(z);parfirst(a->ell2(a,B,N),[1..t])[2]; ecm2(2^101-1,500,600!) uninline(); inline(chkell); chkell(n)=a->my(E=ellinit([1,0,0,0,ffgen(2^n)^a]),N=ellcard(E)/4);if(isprime(N),N); ellp(n)=parfirst(chkell(n),[1..10000]); ellp(128) uninline(); my(N=1);until(type(A)=="t_ERROR",A=alarm(1,parfor(i=1,10,for(i=1,N,isprime(i))));N*=2); my(s,L=List());parfor(x=1,10,x!,f,s+=f);s my(s,L=List());parfor(x=1,oo,if(x<=10,x!),f,s+=f;if(x>=10,break));s my(s);parforprime(p=2,20,p!,f,s+=f);s my(s);parforvec(v=[[1,3],[1,3]],factorback(v),f,s+=f);s my(s);parforvec(v=[[1,4],[1,4]],factorback(v),f,s+=f,1);s my(s);parforvec(v=[[1,5],[1,5]],factorback(v),f,s+=f,2);s test(f)=my(f=f,CS);CS=vector(10,n,[n,n]);F=parapply(u->f(u[1],u[2])+f(u[2],u[1]),CS); for(i=1,100,test((x,y)->x+y)); pari-2.11.2/src/test/in/solve0000644000175000017500000000023313201017466014403 0ustar billbilldefault(realprecision,38); hardy(x)=real(zeta(1/2+I*x)*exp(I*(arg(gamma((1/2+I*x)/2))-log(Pi)/2*x))); solve(x=1,20,hardy(x)) solvestep(x=1,100,1,hardy(x)) pari-2.11.2/src/test/in/iterator0000644000175000017500000000506513457566440015132 0ustar billbilldefault(realprecision,38); N = 1<<64; for(a=N-2, N+2, print(a)) for(a=-N-2, -N+2, print(a)) for(n=2,oo,if(n>10,break);print(n)) forprime(p=2^32-50,2^32+30,print(p)) forprime(p=2^64-70,2^64+50,print(p)) forprime(n=2,,if(n>10,break);print(n)) /*backward compat */ forprime(n=2,oo,if(n>10,break);print(n)) forprime(n=2^100,,if(n>2^100+400,break);print(n)) forprime(n=2^100,oo,if(n>2^100+400,break);print(n)) forprimestep(a=1,10,Mod(2,4),print(a)) forprimestep(a=3,10,Mod(2,4),print(a)) forprimestep(a=0,1,Mod(2,4),print(a)) forprimestep(a=1,10,Mod(3,6),print(a)) forprimestep(p=2^32-50,2^32+30,Mod(1,3),print(p)) forprimestep(p=2^64-70,2^64+50,Mod(2,3), print(p)) forprimestep(n=2,,5,if(n>20,break);print(n)) /*backward compat */ forprimestep(n=2,oo,5,if(n>20,break);print(n)) forprimestep(n=2^100,,Mod(2,3),if(n>2^100+400,break);print(n)) forprimestep(n=2^100,oo,Mod(2,3),if(n>2^100+400,break);print(n)) p=18446744073709551533; forprimestep(i=p,p+400,10,print(i)) for(a=0.5,3,print(a)) for(a=1,10, print(a+=2)) forstep(a=5,1,-2,print1(a," ")) forstep(a=1,10,[1,3],print1(a," ")) forstep(a=1,10,Mod(2,3),print1(a," ")) my(s=1,a=0);forstep(i=1,20,s,s++;a+=i);a forprime(p=2,10,p=4) forcomposite(a=2,4,print(a)) forcomposite(a=10,10,print(a)) forcomposite(a=2,10,print(a)) forcomposite(a=5,11,print(a)) forcomposite(a=6,12,print(a)) forcomposite(a=6,,print(a); if (a>8, break)) forcomposite(a=6,oo,print(a); if(a>8,break)) forcomposite(a=6,12,print(a); a=1) forcomposite(a=2,3,print(a)) { for(i=1,4,for(j=5,8, if ([i,j]==[2,6], next, [i,j]==[3,6], next(2), [i,j]==[4,6], next(3)); print([i,j]))) } forfactored(N=10^5,10^5+10,print(N)) c=0;forfactored(N=1,10^6, my([n,f]=N); if (factorback(f)!=n || c++!=n,error(N))) c=-10^6-1;forfactored(N=-10^6,-1, my([n,f]=N); if (factorback(f)!=n || c++!=n,error(N))) forfactored(x=-3,-1,print(x)) forfactored(x=-3,-1, if (x[1]==-2,break); print(x)) forfactored(x=-3,0,print(x)) forfactored(x=-3,0, if (x[1]==-1, break); print(x)) forfactored(x=-3,0, if (x[1]==0, break); print(x)) forfactored(x=-3,2,print(x)) forfactored(x=-3,2, if (x[1]==-1, break);print(x)) forfactored(x=-3,2, if (x[1]==0, break);print(x)) forfactored(x=-3,2, if (x[1]==1, break);print(x)) forfactored(x=0,2,print(x)) forfactored(x=0,2, if (x[1]==0, break);print(x)) forfactored(x=0,2, if (x[1]==1, break);print(x)) forfactored(x=1,-1,print(x)) forsquarefree(N=10^5,10^5+10,print(N)) forsquarefree(N=-10^5-10,-10^5,print(N)) c=0;forsquarefree(N=1,10^6, my([n,f]=N); if (factorback(f)!=n,error(N)); c++);c c=0;forsquarefree(N=-10^6,-1, my([n,f]=N); if (factorback(f)!=n,error(N));c++);c pari-2.11.2/src/test/in/contfrac0000644000175000017500000000111313201017466015050 0ustar billbillcontfrac(1,[],-1) contfracpnqn(Vecsmall([])) contfracpnqn([]) contfracpnqn([],0) contfracpnqn([],1) contfracpnqn([2]) contfracpnqn([2],0) contfracpnqn([2],1) v=[1,2,3]; contfracpnqn(v) contfracpnqn(v,0) contfracpnqn(v,1) contfracpnqn(v,2) v=[1,2,3;4,5,6]; contfracpnqn(v) contfracpnqn(v,0) contfracpnqn(v,1) contfracpnqn(v,2) s=exp(x); contfracinit(s,0) contfracinit(s,1) contfracinit(s,2) e=contfracinit([]) contfraceval(e,1) e=contfracinit(s) contfraceval(e,1,10) contfraceval(e,1, 8) contfraceval(e,1, 6) contfraceval(e,1) contfracinit([1,2,3]) contfracinit(Pol(0)) contfracinit(1); pari-2.11.2/src/test/in/asymp0000644000175000017500000000146013326135265014415 0ustar billbilldefault(parisize, 20M); check(a,b) = my(t = abs((a-b)/b)); if (t, ceil(log(t)/log(10)), -oo); default(realprecision, 211); pi=Pi; \p115 v = vector(1120,n,n*sin(1/n)); check(limitnum(n -> n*sin(1/n)), 1) check(limitnum(v), 1) check(limitnum(n -> n^2*sin(1/n^2),,2), 1) check(limitnum(n -> n^2*sin(1/n^2),10,2), 1) check(limitnum(n -> (1+1/n)^n), exp(1)) f(n) = n! / (n^n*exp(-n)*sqrt(2*Pi*n)); asympnum(f) asympnum(n->log(1+1/n^2),,2)[1..17] \p115 asympnum(n->log(1+1/n^pi),,pi)[1..17] asympnum(v) \p38 log(limitnum(n->(1+1/n)^n)) h(n)=my(a=1,A=1,B=1.); vector(n, i, a=B/i;A+=a;B+=A; a); H=h(160000); b(n)=log(H[n])-(2*sqrt(n)-3/4*log(n)); C=-1/2-log(2*sqrt(Pi)); check(limitnum(n->b(n^2)), C) asympnum(n->b(n^2)-C) asympnum(n->lngamma(n+1)-(n+1/2)*log(n)+n-1/2*log(2*Pi)) asympnum(a->a^(-5/2)*if(a%40==0,I,0)) pari-2.11.2/src/test/in/number0000644000175000017500000000404613326135265014557 0ustar billbillHEAP=[93, if(sizebyte(0)==16,2810,2850)]; default(realprecision,154); Pi; default(realprecision,38); \e addprimes([nextprime(10^9),nextprime(10^10)]) bestappr(Pi,10000) gcdext(123456789,987654321) bigomega(12345678987654321) binomial(1.1,5) chinese(Mod(7,15),Mod(13,21)) content([123,456,789,234]) contfrac(Pi) contfrac(Pi,5) contfrac((exp(1)-1)/(exp(1)+1),[1,3,5,7,9]) contfracpnqn([2,6,10,14,18,22,26]) contfracpnqn([1,1,1,1,1,1,1,1;1,1,1,1,1,1,1,1]) core(54713282649239) core(54713282649239,1) coredisc(54713282649239) coredisc(54713282649239,1) divisors(8!) eulerphi(257^2) factor(17!+1) factor(100!+1,0) factor(40!+1,100000) factorback(factor(12354545545)) factor(230873846780665851254064061325864374115500032^6) factorcantor(x^11+1,7) centerlift(lift(factormod(x^3+x^2+x-1,[3,t^3+t^2+t-1]))) 10! factorial(10) factormod(x^11+1,7) factormod(x^11+1,7,1) setrand(1);ffinit(2,11) setrand(1);ffinit(7,4) fibonacci(100) gcd(12345678,87654321) gcd(x^10-1,x^15-1) hilbert(2/3,3/4,5) hilbert(Mod(5,7),Mod(6,7)) isfundamental(12345) isprime(12345678901234567) ispseudoprime(73!+1) issquare(12345678987654321) issquarefree(123456789876543219) kronecker(5,7) kronecker(3,18) lcm(15,-21) lift(chinese(Mod(7,15),Mod(4,21))) modreverse(Mod(x^2+1,x^3-x-1)) moebius(3*5*7*11*13) nextprime(100000000000000000000000) numdiv(2^99*3^49) omega(100!) precprime(100000000000000000000000) prime(100) primes(100) qfbclassno(-12391) qfbclassno(1345) qfbclassno(-12391,1) qfbclassno(1345,1) Qfb(2,1,3)*Qfb(2,1,3) qfbcompraw(Qfb(5,3,-1,0.),Qfb(7,1,-1,0.)) qfbhclassno(2000003) qfbnucomp(Qfb(2,1,9),Qfb(4,3,5),3) form=Qfb(2,1,9);qfbnucomp(form,form,3) qfbnupow(form,111) qfbpowraw(Qfb(5,3,-1,0.),3) qfbprimeform(-44,3) qfbred(Qfb(3,10,12),,-1) qfbred(Qfb(3,10,-20,1.5)) qfbred(Qfb(3,10,-20,1.5),2,,18) qfbred(Qfb(3,10,-20,1.5),1) qfbred(Qfb(3,10,-20,1.5),3,,18) quaddisc(-252) quadgen(-11) quadpoly(-11) quadregulator(17) quadunit(17) sigma(100) sigma(100,2) sigma(100,-3) sqrtint(10!^2+1) znorder(Mod(33,2^16+1)) forprime(p=2,100,print(p," ",lift(znprimroot(p)))) znstar(3120) if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/galpol0000644000175000017500000000114113326135265014536 0ustar billbill\\ package: galpol galoisgetpol(8) for(i=1,5,printsep(":",galoisgetname(8,i),galoisgetgroup(8,i),galoisgetpol(8,i))) for(i=1,5,print(galoisgetpol(8,i,2))) test(n,k)= if(galoisidentify(galoisinit(galoisgetpol(n,k)[1])) != [n,k], error([n,k])); test(8,3) test(18,5) test(27,3) test(45,2) test(30,4) test(32,4) test(32,13) test(32,30) test(32,32) test(42,2) test(48,12) test(64,3) test(64,14) test(64,16) test(64,48) test(64,51) test(64,70) test(64,68) test(64,80) test(64,44) galoisidentify(galoisinit(polcyclo(390))) \\ Errors, keep at end of file galoisgetpol(8,6) galoisgetpol(3,1,3) galoisgetpol(3,1,2) pari-2.11.2/src/test/in/mspadic0000644000175000017500000000676313326135265014717 0ustar billbilldefault(parisize, "50M"); { elldata= Map([ \\ rank 0 "11a1",[0,-1,1,-10,-20]; "14a1",[1,0,1,4,-6]; "15a1",[1,1,1,-10,-10]; "17a1",[1,-1,1,-1,-14]; "19a1",[0,1,1,-9,-15]; "26b1",[1,-1,1,-3,3]; "33a1",[1,1,0,-11,0]; "43a1",[0,1,1,0,0]; \\ rank 1 "37a1",[0,0,1,-1,0]; "53a1",[1,-1,1,0,0]; \\ rank 2 "389a1",[0,1,1,-2,0] ]); } myellinit(s)= ellinit(if(type(s)=="t_STR",mapget(elldata,s),s)); \\ a2 = 0 e=myellinit("19a1"); ellpadicL(e, 2, 5) \\ a3 = 0 e=myellinit("17a1");p=3; L=ellpadicL(e,p,4) F=[0,-p;1,ellap(e,p)]; (1-p^{-1}*F)^-2*L / bestappr(ellL1(e)/e.omega[1]) \\ a5 = -2 p=5; L=ellpadicL(e,p,4) al=polrootspadic(x^2-ellap(e,p)*x+p,p,7)[2]; (1-al^(-1))^(-2)*L / bestappr(ellL1(e)/e.omega[1]) \\ a3 = -3 != 0 e=myellinit("26b1");p=3; L=ellpadicL(e,p,4); F=[0,-p;1,ellap(e,p)]; (1-p^{-1}*F)^-2*L / bestappr(ellL1(e)/e.omega[1]) \\ huge memory 1001a1 e=ellinit([0,-1,1,-15881,778423]);p=2;n=3; ellpadicL(e,p,n) E=myellinit("53a1");P=[0,0]; ellpadicL(E,2,10,,2) ellpadicL(E,3,10) ellpadicL(E,3,10,,1) ellpadicL(E,5,5,,2) testord(s, p, n, D = 1) = { my(e = myellinit(s)); my([M,xp] = msfromell(e,1)); Wp = mspadicinit(M, p, n, 0); mspadicmoments(Wp, xp, D); } testss(s, p, n) = { my(e = myellinit(s)); my([M,xp] = msfromell(e,1)); Wp = mspadicinit(M, p, n); mspadicmoments(Wp,xp); } testord("11a1", 7, 4) testord("17a1", 7, 4) testss("17a1", 3, 4) testord("14a1", 7, 4) testord("43a1", 3, 4, 29) e=myellinit("11a1"); [M,phi]=msfromell(e,1); Wp = mspadicinit(M, 3, 4, 0); mspadicmoments(Wp, phi, 5) Wp = mspadicinit(M, 5, 4, 0); mspadicmoments(Wp, phi, -3) vchar = [0,-2,[0,1],[1,0],[2,0]]; test(M,phi,p)= { my(Wp, mu, ap); ap = mshecke(M,p,phi)[1,1]; Wp = mspadicinit(M,p,10, valuation(ap,p)); mu=mspadicmoments(Wp,phi); for (i=1,#vchar, print(vchar[i],":"); for(r=0,3, print(mspadicL(mu,vchar[i],r))); ); } test(M,phi,3); test(M,phi,2); test(M,phi,7); e=myellinit("33a1"); [M,phi]=msfromell(e,1); test(M,phi,3) test(M,phi,11) e=myellinit("389a1"); [M,phi]=msfromell(e,1); test(M,phi,2) [M,phi]=msfromell(e,-1); Wp = mspadicinit(M, 3, 4, 0); mspadicmoments(Wp, phi, 5) Wp = mspadicinit(M, 5, 4, 0); mspadicmoments(Wp, phi, -3) \\==== W = msinit(50,4,1); phi = mssplit(W, msnew(W), 1)[1]; Wp = mspadicinit(W, 3, 6, 0); mspadicmoments(Wp, phi) Wp=mspadicinit(msinit(25,2,1),5,4, 1); \\ must fail p^2 | N M=msinit(4,6,1); phi=-[1,8,1,-32]~; \\ v_p(ap) = 1 Wp=mspadicinit(M,3,5, 2); oms=mspadicmoments(Wp, phi); \\ must fail Wp=mspadicinit(M,3,5, 1); PHI=mstooms(Wp,phi); msomseval(Wp,PHI,[1/2,1/3]) msomseval(Wp,PHI,[0,oo]) oms=mspadicmoments(Wp, PHI); \\ now succeeds mspadicL(oms) msnewsymb(N,k,s=1) = { my(xpm,M); M=msinit(N,k,s); xpm = mssplit(M,msnew(M),1)[1]; [M,xpm]; }; testmspadicL(N,k,p,signe=1,D=1) = { my([M,xpm]=msnewsymb(N,k,signe)); my(ap = mshecke(M,p,xpm)[1,1]); my(Wp,oms); Wp = mspadicinit(M,p,10, if(ap,valuation(ap,p), k-1)); oms = mspadicmoments(Wp, xpm, D); vector(k-1,j, mspadicL(oms,j-1)); } \\ ordinary testmspadicL(3,6,3) testmspadicL(3,6,3,-1) testmspadicL(3,6,5) testmspadicL(3,6,5,-1) testmspadicL(3,6,5,-1, -3) testmspadicL(3,8,7) testmspadicL(3,8,7,-1) testmspadicL(5,4,3) testmspadicL(5,4,7) testmspadicL(5,4,7,-1) testmspadicL(5,4,7,1, 5) testmspadicL(11,6,7) testmspadicL(11,6,7,-1) testmspadicL(14,6,7) testmspadicL(14,6,7,-1) \\supersingular testmspadicL(4,6,3) \\ ap=12 testmspadicL(9,4,5) \\ ap=0 testmspadicL(17,6,3) \\ ap=-18 testmspadicL(3,8,2) \\ testmspadicL(5,8,2) testmspadicL(10,8,2) testmspadicL(3,10,7) \\ ap=9128, valuation 1 pari-2.11.2/src/test/in/time0000644000175000017500000000035513201017466014216 0ustar billbillgettime(); WT=getwalltime(); T=getabstime(); for(i=1,2*10^6,) T2=getabstime(); t2=gettime(); WT2=getwalltime(); abs(t2 - (T2-T)) < 5 abs((WT2-WT) - (T2-T)) < 5 for(i=1,2*10^6,) t3=gettime(); abs(t2+t3 - (getabstime() - T)) < 5 %#5==T2-T pari-2.11.2/src/test/in/ratpoints0000644000175000017500000005330713326135265015316 0ustar billbillaffine2proj(P)= { my([X,Y]=P); my(x=numerator(X),z=denominator(X),y=Y*z^3); [x,y,z]; } { V=[ [-10,-8,1,-2,0,-5,-4], [4,-6,-4,-7,-8,5,-3], [4,-8,2,-3,-1,0,-6], [0,5,6,2,-7,4,-8], [-5,10,-9,-6,7,-1,3], [0,-8,-6,-9,-8,-6,-9], [-6,5,7,-10,-1,1,-2], [-2,9,-3,-3,-4,-2,-3], [7,-7,-2,5,-1,8,7], [-6,10,-6,9,-3,-7,-2], [-3,-8,10,6,3,7,-7], [-5,5,8,7,-2,2,-3], [-8,5,9,-6,-2,-6,-1], [0,6,0,-9,6,2,-3], [2,1,-5,9,-9,1,-2], [-5,8,-4,-5,10,-10,-5], [-2,3,1,4,-5,7,3], [-8,-8,4,8,7,3,-6], [6,6,-5,-8,-5,-5,-2], [6,-10,-6,-6,-7,-8,-8], [4,10,-9,-1,6,10,3], [1,2,7,3,-7,-9,-2], [-7,-5,-2,0,-3,-9,2], [3,1,-7,-3,4,7,3], [-3,7,6,-3,-1,7,-8], [-8,-3,0,-3,4,7,4], [10,10,5,-7,0,3,-2], [-7,-3,10,-4,-3,-7,3], [7,-8,-2,7,-4,1,3], [3,-3,-9,-10,5,-2,-1], [4,9,-7,8,-3,1,10], [-4,-9,-7,-3,9,7,8], [-2,5,7,4,0,6,4], [0,1,1,-1,4,4,9], [8,4,-4,1,-3,-10,3], [-10,-10,-3,9,7,0,-4], [-7,-1,7,-9,9,-5,-7], [0,5,1,-4,10,-2,-3], [4,6,-6,1,-7,-8,-9], [2,-7,-4,3,-2,-8,2], [1,8,-8,-5,-2,9,-4], [-6,9,-10,2,9,5,2], [1,-4,-6,-9,-1,-3,-4], [-2,4,3,1,-2,-10,10], [9,5,-10,1,-10,-10,5], [-1,6,-3,4,-6,-6,-2], [3,4,-6,-6,-9,5,-1], [4,-8,-2,6,6,3,8], [2,0,3,0,10,4,5], [-10,3,0,1,5,8,2], [8,6,-2,5,-3,3,-9], [10,-10,-3,-4,8,8,7], [6,10,-4,-3,-9,-10,8], [-5,-1,-3,-4,5,10,9], [0,8,10,10,-8,8,-2], [8,-4,-2,-10,-1,9,9], [9,2,5,1,4,9,10], [1,-2,6,-7,-4,-8,1], [-6,8,-2,0,7,-5,-2], [-4,-5,-7,8,-4,-4,-1], [6,9,-9,3,-8,10,10], [9,-5,5,2,2,1,1], [-7,-2,1,8,2,-8,-1], [5,-6,7,-7,6,-6,9], [9,10,4,1,-1,7,-7], [0,1,10,7,-9,-8,9], [-10,9,5,-9,4,-3,6], [-7,-6,5,9,-7,-10,-7], [-8,-5,6,-7,-1,-4,-2], [-4,7,6,0,3,1,-4], [2,4,5,7,-10,-9,1], [-3,9,-5,9,2,-8,2], [7,2,10,-1,-4,-10,-2], [0,-4,-9,-4,-4,-6,-10], [9,1,-4,-4,4,7,6], [-2,-1,6,8,4,-8,-10], [9,-8,-5,9,2,-5,8], [5,0,10,-10,2,5,-6], [6,0,9,-7,-8,0,-2], [6,3,-6,3,8,10,-9], [-7,-2,-6,-1,10,-2,-5], [-7,3,-5,9,1,-8,6], [-5,7,-8,10,1,-9,1], [6,-6,-7,0,6,3,-4], [-2,-2,-10,-7,-5,-3,0], [-6,-6,-3,-4,-9,-10,6], [7,-6,0,10,-1,1,-8], [10,9,-9,2,1,9,-3], [-6,-4,-9,5,-10,10,8], [-10,-8,-10,8,-1,-9,9], [3,-3,-9,-4,-6,-8,-4], [-2,8,9,-6,5,-7,-6], [6,9,-9,3,7,10,-5], [6,10,2,-5,0,-6,-9], [9,-6,6,-9,-8,7,-1], [1,0,-9,7,-10,-7,-10], [4,-3,3,5,-4,-5,2], [-9,-3,8,-6,2,9,3], [10,-4,1,4,10,1,-5], [5,10,0,-8,-9,6,3], [-9,5,-4,-5,4,-4,6], [1,-2,5,-5,-9,3,2], [-8,-3,6,1,9,0,10], [-3,-5,-3,-7,5,-4,-8], [-7,8,7,1,-3,10,-4], [8,0,8,9,9,-7,0], [-5,-8,-3,10,-9,4,-8], [3,-9,10,3,4,-9,-7], [6,-8,-1,10,2,-5,-9], [8,4,-6,-1,3,3,2], [9,5,9,4,5,3,-9], [-3,4,-5,9,-7,8,-7], [3,9,-5,8,0,1,-4], [-1,3,10,0,-3,2,1], [7,-10,0,8,-10,3,10], [7,-6,-4,2,0,-4,0], [-8,4,-8,6,10,-9,2], [-1,-10,-5,-2,1,9,6], [-10,-4,2,9,4,7,-3], [5,1,4,2,-7,4,-4], [0,4,2,-10,-3,5,6], [4,4,3,6,4,3,-1], [-10,10,-10,8,-8,-6,-9], [7,7,10,-9,-5,-1,-3], [-7,10,4,-3,1,1,3], [-10,5,-8,4,1,4,-4], [-3,1,-1,8,10,4,8], [2,10,3,-7,-1,-3,-6], [-7,8,0,7,10,2,-6], [-3,-4,-5,-2,1,-1,-5], [-2,10,-4,8,-7,-4,-2], [9,0,10,8,-4,4,-7], [3,9,-5,0,1,4,7], [1,10,4,9,1,-10,5], [7,-6,-10,10,-8,2,-7], [7,-3,7,10,-7,-6,6], [4,4,2,4,10,-1,3], [-4,-6,10,10,7,-5,-9], [6,-8,1,-9,2,8,-7], [3,-5,-6,-5,7,3,-2], [9,8,-7,8,7,3,8], [7,4,-4,6,4,-7,-6], [-3,10,-1,1,4,-9,0], [-3,5,-2,-6,9,-6,7], [4,7,3,9,4,2,-7], [-10,-3,1,10,5,-9,5], [-5,5,-9,7,10,2,-3], [7,1,0,6,-5,9,-6], [-5,1,-7,-9,-1,9,-4], [7,-6,-9,5,-2,-3,-6], [0,6,9,-5,8,-5,10], [9,10,-2,9,9,-3,5], [-4,7,8,0,-6,-1,-1], [4,5,7,-3,5,-9,4], [-5,-7,8,5,-8,-5,-1], [-10,5,-10,0,-2,2,10], [7,7,5,-9,-10,2,1], [1,-10,-8,1,3,4,-8], [-8,4,10,1,-10,2,2], [7,2,-4,-2,-10,-3,3], [3,-5,-6,-2,-5,2,9], [-3,-6,-9,-7,-3,3,-8], [-6,-4,0,-1,9,-3,-8], [-7,9,9,-7,4,0,-1], [2,4,4,1,-9,10,-10], [9,-1,-8,6,8,1,-2], [10,-10,5,10,9,-10,-3], [10,0,-10,-6,6,-7,2], [10,0,-1,3,10,2,-3], [-10,10,-2,7,5,-9,10], [-2,-8,7,-6,6,9,10], [6,5,2,-1,3,2,-4], [9,5,-10,-6,-1,3,0], [-2,-10,5,4,8,-6,-5], [8,-4,-3,2,4,-5,-5], [2,4,10,-4,8,-2,7], [-4,10,8,9,1,-2,8], [4,5,6,4,-8,9,8], [-3,-6,4,1,6,2,-6], [-8,8,-9,9,-7,-1,-3], [7,-2,-9,10,1,4,-10], [-1,-5,-5,-7,-9,4,-3], [-3,8,2,0,-6,9,9], [-4,5,0,-10,-4,-6,-8], [-10,-6,-7,-6,-9,-2,4], [-2,-5,-1,0,8,3,-10], [-4,-3,6,9,-5,1,-8], [2,0,6,8,-8,-2,-9], [2,4,2,-7,-2,-4,-7], [2,-7,-4,7,-2,9,7], [3,-7,-3,0,1,1,-4], [-4,-7,1,7,1,-4,-3], [8,7,-4,-3,0,-2,3], [-3,-7,1,8,3,-2,1], [3,0,-7,2,-6,5,-7], [-4,-2,-6,-3,-6,-2,10], [5,10,1,10,10,-6,-4], [-4,6,5,-10,2,6,-3], [4,-5,2,3,-10,3,8], [-5,4,-10,4,6,0,-2], [-7,-3,-9,7,-3,2,1], [1,-9,-9,2,8,8,7], [-7,1,-7,-7,1,-6,-10], [-9,1,-2,-5,3,5,-3], [-3,-9,-3,9,6,-9,4], [-2,9,-9,5,5,-7,8], [5,-10,8,-8,-3,-8,-10], [0,1,-7,7,6,3,-8], [-1,-9,4,-8,-5,-6,-2], [-6,5,1,8,-8,3,-3], [6,8,-4,1,3,9,-1], [4,-6,7,10,-9,-7,-8], [1,7,-3,3,0,-10,-1], [4,-6,-2,3,-1,7,-6], [5,-8,-2,-4,-6,10,-5], [10,-3,2,-1,-6,-8,-1], [1,2,-5,-10,-7,-4,-1], [7,-8,4,0,5,4,1], [3,6,-2,2,6,-6,1], [8,-4,6,1,-9,8,-8], [-4,-6,8,5,-5,-4,5], [-7,-3,8,-6,1,-6,-4], [8,-4,-10,-3,10,4,4], [-4,4,3,-7,1,-3,-8], [6,-5,-4,-5,-7,-5,9], [-10,6,-9,-8,2,2,2], [-7,1,10,-9,10,-2,-4], [9,0,-8,8,-3,10,2], [3,-4,2,8,10,2,-1], [2,8,-8,6,-6,7,8], [1,5,-8,-4,-8,-7,7], [-3,4,-5,-6,-10,-1,7], [9,-6,-3,3,-6,-1,-1], [-6,4,-10,6,-10,-4,-1], [-4,-7,-4,4,-2,-8,7], [4,8,-2,-2,-3,-7,-5], [5,-10,0,2,-9,-4,-7], [8,-7,-5,-6,0,7,-5], [7,-9,4,10,-7,1,6], [10,-8,1,8,0,-3,8], [3,3,2,-2,-6,-2,-10], [1,0,-8,5,6,-1,-8], [-5,6,0,10,7,-4,-10], [10,-5,2,5,6,8,7], [7,2,7,-6,-8,-2,2], [3,7,3,8,-3,-4,1], [8,-2,9,0,-5,9,-3], [6,0,5,-6,-9,-3,-2], [-5,-8,-10,2,1,-2,-1], [3,1,-9,5,-10,8,-8], [6,-7,-4,-8,-2,-1,-4], [-1,0,0,5,-2,-9,2], [-7,10,-2,-2,-7,-7,-2], [6,4,-3,-3,-1,-9,5], [10,6,5,4,-1,-1,-4], [-8,-4,-2,7,3,9,1], [5,0,3,-6,0,10,-2], [5,-10,7,7,5,2,5], [1,3,4,-10,3,2,-8], [-2,-1,4,-10,-10,-3,-7], [-9,1,6,1,4,0,9], [6,9,10,-4,2,6,10], [0,2,-3,-1,-4,6,-1], [1,-4,-7,-2,3,1,6], [-1,-4,0,-2,-3,4,8], [-8,4,-9,-4,-5,5,-6], [-1,4,6,-9,6,-5,0], [-6,-1,-3,5,-6,4,-7], [6,-10,10,2,3,5,1], [-10,-8,-1,7,-8,-2,5], [3,-2,3,8,4,7,10], [7,-4,8,5,-1,3,5], [4,10,7,0,5,-3,5], [-8,-3,-8,7,-3,-10,1], [9,7,2,3,-7,-3,-3], [-9,-7,-2,9,-2,-4,4], [-4,-7,3,9,5,4,-5], [3,3,4,10,-6,2,5], [-9,2,9,0,-9,2,3], [-6,-7,-1,-1,-7,-10,1], [-6,8,9,-10,-3,-4,8], [4,9,7,-4,4,1,10], [6,6,4,-5,-2,-8,-6], [-8,5,10,-2,1,1,3], [-3,-2,2,-3,0,8,-4], [9,2,6,8,9,8,-1], [5,9,5,-10,10,3,-8], [-4,1,-9,-4,-2,0,-9], [10,7,4,3,-4,-7,-6], [-5,9,-6,-9,-6,-6,4], [9,0,-6,3,-9,-8,-6], [-4,0,4,-5,8,-10,9], [3,-7,5,5,9,-6,-10], [-4,-5,2,9,5,-3,-10], [5,6,0,2,-6,10,0], [-7,-8,-1,10,-10,-3,-8], [-9,6,2,-2,3,7,-9], [-7,-3,-10,-6,-6,9,1], [3,-10,9,2,10,7,9], [-5,9,-9,9,-7,1,-5], [6,-2,3,-3,3,-8,-8], [9,-7,1,-9,-9,-6,-5], [-3,-2,-5,1,0,0,-8], [3,3,-6,-7,3,-8,-2], [10,-9,-8,1,-4,8,6], [-8,3,5,3,-4,-8,0], [-3,3,-9,-7,5,-5,-8], [8,10,-1,9,7,10,-3], [-2,1,10,9,-2,-6,1], [9,4,-6,9,-7,2,4], [7,-8,-6,2,-6,2,-2], [9,-9,0,8,4,0,-9], [-4,-6,-3,6,9,9,9], [-3,-6,-2,-7,6,0,10], [5,-4,-7,0,-3,8,-8], [7,1,5,-2,-7,-7,-7], [4,-3,5,-6,7,-1,-6], [6,-2,-4,4,-9,7,8], [9,4,-3,8,1,7,3], [0,-2,-8,-9,-2,4,10], [-3,6,9,8,-3,-2,10], [-8,-10,7,-8,6,6,-5], [-8,-5,0,9,-9,-1,8], [4,-1,10,1,5,-8,1], [-4,5,4,0,-4,-9,-1], [-9,8,-6,-8,2,-7,-6], [-7,-8,8,9,5,6,9], [7,-9,-3,2,-5,6,1], [0,1,-1,0,-1,-5,0], [3,-9,2,0,5,6,2], [8,-7,-3,3,-8,-5,-4], [10,8,-9,-7,3,2,2], [10,5,3,-2,-6,9,-5], [-10,7,5,-1,-6,3,-6], [-10,-9,-1,-4,-10,-1,-1], [4,7,10,-4,-1,3,1], [-8,-7,0,-6,0,-6,4], [0,2,-4,10,-7,2,9], [8,-8,-1,9,5,-8,7], [1,-10,-8,1,0,-5,-2], [10,9,-10,6,8,9,-3], [1,-3,-8,4,-7,-10,0], [6,-7,-1,4,-1,-2,-5], [8,6,-4,2,-2,-7,-6], [10,-2,7,-10,-6,9,-8], [4,2,9,6,-2,1,4], [0,9,-4,-5,3,-4,-6], [2,4,-4,-10,-9,-1,-1], [4,6,10,2,2,-5,6], [-9,3,-1,-9,-7,3,-10], [4,9,-6,-5,3,-4,-1], [4,9,-10,-7,-8,9,3], [-2,8,0,8,5,5,-7], [-7,9,1,-3,2,9,-8], [-4,-1,-10,6,8,-6,-2], [9,7,4,0,2,8,-4], [4,9,-7,10,10,-10,-4], [0,6,0,-8,-1,-2,1], [-4,3,-5,1,-2,-9,-2], [-7,-5,-8,-5,7,-5,8], [8,1,-10,-8,-9,-10,6], [-8,-3,-2,4,-5,2,-2], [-5,-1,9,0,-6,-8,-5], [-2,-7,-1,-3,7,-9,7], [2,4,2,0,6,2,-7], [7,-3,-1,7,-5,4,-2], [-9,-8,-1,-2,10,-7,-4], [0,-10,10,7,-8,-10,3], [2,8,2,-4,4,0,-7], [9,6,7,-8,10,-8,-10], [-2,-9,-7,0,-2,-9,-7], [-3,8,1,3,7,1,-2], [-9,-2,-2,1,4,0,4], [-9,4,-5,2,-9,7,2], [-2,-9,5,2,-1,4,-5], [2,2,-7,-10,5,-7,6], [5,-7,2,-4,0,-1,-1], [8,-1,2,10,10,-5,4], [0,9,-2,-4,2,-5,-1], [-9,4,-6,1,-7,-7,-3], [4,-1,5,-4,3,-7,2], [-3,9,-5,6,5,2,0], [6,7,-4,9,-9,9,-4], [8,-6,-5,-7,-3,2,7], [-6,-8,1,2,8,5,-7], [5,9,-7,2,-6,-8,5], [0,-2,-7,-5,-9,-7,-7], [-6,5,10,6,0,6,0], [10,4,-6,0,-5,-8,4], [-1,-3,-9,-7,1,-9,6], [-3,-8,-4,-1,1,-7,5], [-4,-6,7,10,7,6,10], [8,7,-1,-8,-10,1,-9], [3,7,1,8,1,-4,6], [-7,1,-3,9,0,10,-7], [-7,-6,8,-7,-6,2,3], [3,0,4,-3,-5,-8,-2], [6,1,2,-3,1,7,9], [3,-6,5,9,-1,5,5], [6,4,-3,6,0,-5,-4], [-1,-4,1,-9,3,3,0], [-2,-7,-8,-2,0,-2,-5], [8,0,-3,1,-4,-3,6], [-1,-7,-9,10,-4,-5,2], [6,-4,-2,-1,-4,4,-2], [3,-2,-7,-1,-9,2,-7], [-9,-8,-8,-10,-7,6,-10], [10,9,-4,1,5,-4,1], [5,10,-9,-3,-3,-6,-10], [10,6,-10,-7,3,8,-2], [-7,10,5,6,-8,-1,5], [-8,-8,-10,-6,6,-8,-8], [-3,-8,9,-1,3,1,4], [-10,-8,-9,8,-1,-10,1], [3,-8,5,1,3,-10,-1], [-8,5,1,9,-9,0,-3], [8,-9,10,-10,-1,-10,-10], [-1,5,-10,-4,-8,-10,8], [-6,9,-8,10,-10,-3,4], [3,-10,2,9,4,1,10], [8,6,8,4,1,4,-9], [3,-10,8,-5,-2,-10,8], [10,-5,-3,7,-1,6,-2], [6,-10,-4,-9,0,8,10], [2,10,-6,6,10,10,-1], [7,-8,4,-10,3,9,3], [1,2,-3,-10,3,10,5], [-5,-8,-6,9,-1,9,-6], [9,-10,9,-6,8,3,-1], [-7,1,-8,0,-10,-4,4], [-10,1,0,3,4,3,10], [10,-3,10,2,7,-4,3], [-3,9,-6,-3,7,0,-6], [-9,-3,0,1,4,1,-4], [6,2,-4,6,0,-6,-4], [7,-5,5,4,-9,6,-6], [-10,-10,4,-2,7,-2,-7], [8,-8,2,-6,10,2,1], [5,-10,-2,1,-10,8,8], [8,6,3,-9,-5,8,-7], [5,2,8,8,0,6,-7], [-4,3,-10,4,-3,4,-1], [9,-3,-8,0,-8,-9,-6], [-5,9,-6,-8,2,3,2], [-1,10,-2,4,10,-9,-8], [-5,-10,8,-7,-5,8,-3], [-10,8,-4,8,4,-2,-7], [-8,4,-1,-10,4,3,-4], [9,-1,1,-9,9,4,-1], [-7,-7,9,0,6,-3,-7], [-2,-4,-8,3,9,9,-4], [3,9,9,5,-9,8,7], [-3,-4,-9,1,-2,4,9], [-5,2,3,-6,-10,-9,3], [-3,10,5,7,2,1,0], [3,-10,9,-1,2,-2,-4], [3,3,-6,-1,-6,3,-6], [8,6,-9,7,-3,-4,2], [-5,-1,4,-1,5,-1,-7], [-8,8,0,-7,-8,-10,1], [-1,0,10,2,8,-5,8], [-2,-2,-8,-4,9,-8,-4], [-10,-8,-1,8,2,0,2], [-10,7,-4,3,-4,-6,1], [1,2,-7,-3,-9,-7,2], [-3,10,2,-6,-5,9,-1], [0,4,-9,9,9,7,-6], [5,2,-5,-3,-10,-9,10], [-10,9,3,2,5,-5,3], [-2,5,10,-10,5,3,-6], [-9,1,0,5,8,10,-6], [2,-6,-5,6,2,9,3], [-4,9,-8,-2,0,-10,0], [4,6,-9,-3,-2,-4,2], [-8,-7,2,10,9,-5,4], [-5,4,-5,6,6,2,-1], [3,10,-3,-6,-10,-7,-1], [8,6,-1,-1,9,1,-5], [4,-8,-2,-9,-6,3,-1], [8,-8,-7,-6,-10,3,-6], [-1,6,7,-2,6,-10,1], [5,1,6,-6,-5,-10,-8], [-3,6,9,-3,-4,-9,-3], [3,8,8,-10,-7,-1,3], [10,0,-7,-4,7,-8,9], [2,-9,2,-9,-8,10,8], [-9,8,-3,5,1,-2,9], [-7,4,-7,10,-2,5,-1], [10,-1,-5,3,1,-1,0], [10,3,5,-10,10,7,-1], [2,-5,0,3,4,-7,-3], [-5,-6,-9,7,-1,-9,9], [8,6,-8,-10,3,1,8], [0,1,-1,5,4,0,10], [1,3,-1,-9,9,-6,-3], [-7,0,1,8,7,8,4], [1,8,0,-1,9,-2,4], [-1,-8,-8,-3,-10,3,-10], [7,0,-8,3,0,-6,-4], [5,-3,-10,-10,8,-8,8], [-4,-2,7,-7,0,-4,9], [10,2,5,-2,-4,-7,-2], [1,6,1,1,-1,-6,6], [-1,-7,4,-1,-1,-6,-6], [2,7,-1,1,-2,7,10], [1,-6,2,-3,9,2,-4], [1,10,6,-8,6,7,1], [6,5,-3,-7,-6,8,-2], [6,-1,-10,-4,5,3,3], [10,1,4,-1,7,10,-4], [7,2,-6,-9,6,-8,-6], [-5,8,0,-3,7,5,-10], [-2,0,0,8,-9,-4,0], [9,-8,-6,1,6,10,1], [-6,-7,3,-9,-9,6,-4], [9,-2,-2,6,4,9,10], [8,1,0,-4,-5,-9,10], [-8,-2,6,9,0,6,6], [10,10,4,1,9,-6,4], [1,9,-1,2,10,9,10], [2,-9,-6,-10,0,1,-1], [-2,-1,-3,4,-5,6,-6], [-3,7,9,5,8,9,-2], [-5,5,8,10,8,7,9], [-2,5,-10,3,4,10,-2], [-10,-1,-6,10,6,-1,6], [7,4,-1,-2,9,2,10], [5,-8,-7,4,10,-8,-3], [2,-2,6,4,5,-1,-5], [8,2,-4,6,6,1,2], [-9,2,-3,7,6,2,3], [2,4,1,-2,-8,-10,-2], [-6,-1,5,9,10,5,-1], [-10,9,10,2,-7,-3,-8], [2,-2,2,9,-2,0,-1], [-6,-1,6,7,-8,0,-8], [-4,-1,0,7,1,-4,-2], [10,-6,2,2,10,-5,3], [8,-10,-4,3,2,4,10], [-9,3,1,-5,-10,-6,-5], [9,-3,-2,-2,-8,-1,5], [-5,3,-5,2,3,10,-2], [5,-10,0,-7,1,8,-6], [5,-6,-3,3,-7,0,7], [9,4,1,1,-7,-8,-6], [2,5,-5,-10,1,0,-3], [0,8,9,-5,2,8,10], [9,10,10,2,2,7,-6], [-4,-2,-6,4,10,4,5], [-8,-5,-8,4,8,-10,-6], [-3,-4,7,-1,-10,7,6], [-7,-5,-2,0,-6,-4,7], [-7,5,2,-7,-5,1,-3], [-6,0,8,-4,10,-4,-5], [-10,-5,-8,-1,5,4,6], [-7,-7,2,-5,8,0,2], [9,-7,-7,2,-4,-1,4], [10,-2,-7,-9,7,-5,0], [9,-9,9,7,0,2,5], [2,6,3,10,3,1,8], [7,8,-8,0,-6,-4,1], [-3,7,-10,4,5,4,1], [-9,0,-7,-10,-8,8,9], [3,-8,9,-5,2,-4,1], [-10,-1,5,4,6,-5,4], [-6,-2,-4,8,-1,-8,5], [-7,-7,-7,-4,-7,-4,-8], [-3,-10,0,7,-9,1,-4], [-7,9,-8,3,8,8,-2], [-2,-10,-5,7,-10,-10,-9], [7,-2,9,1,3,4,6], [10,-9,-10,-4,1,6,0], [-4,10,1,9,-7,-4,-8], [9,2,4,-8,-5,-5,1], [-2,-3,-9,1,-6,-4,3], [3,-3,-3,6,2,4,7], [5,-3,-9,2,10,8,-6], [-9,-4,2,0,-10,-8,-9], [3,9,1,3,-8,-5,3], [-2,-6,10,1,9,-4,-8], [-10,3,-10,2,3,8,1], [1,-3,-1,-4,0,-5,2], [-7,5,10,8,2,-7,-3], [-5,-6,9,-3,-10,-8,5], [1,9,3,-4,-5,-2,-6], [1,9,-1,-1,-10,-3,-3], [10,4,3,7,-1,-2,-9], [-4,-7,1,-3,5,6,8], [8,10,-2,4,-6,-5,4], [2,-10,-3,-9,5,6,9], [-3,8,2,-1,-9,0,-2], [1,-6,-8,-1,2,1,-2], [-3,3,5,-4,10,-9,-10], [-8,0,-2,5,-10,0,1], [6,-5,-1,-6,0,0,-10], [-10,0,3,1,0,7,6], [7,-6,1,-6,9,3,2], [4,-8,3,-3,-4,-10,9], [-2,10,-8,-1,1,8,-5], [-3,7,8,-1,-2,3,-3], [-7,-6,-5,4,6,-4,3], [2,9,-1,-1,3,-4,0], [-5,-1,-10,0,-6,-3,-7], [6,1,7,3,1,-9,-3], [9,-7,0,-8,6,10,-3], [-8,0,-3,-2,3,8,3], [-9,-4,8,-2,0,7,-10], [-6,7,-6,0,4,-8,6], [6,-7,0,4,-2,5,-4], [4,-5,5,-9,-7,8,3], [8,-2,-9,-2,9,-5,8], [5,1,10,10,-10,-6,-9], [10,3,9,-4,1,-4,0], [-4,-2,5,2,-7,9,-3], [2,-5,3,8,8,2,9], [-1,-4,10,-4,0,4,9], [5,7,-3,-10,-3,-8,7], [4,10,6,7,1,-3,3], [4,-3,-8,9,-9,5,4], [-8,1,-7,-9,4,-2,-9], [0,5,-9,-8,0,1,-8], [-5,-5,3,6,2,-10,-3], [-4,-1,2,4,7,-4,-7], [8,1,-5,9,1,1,1], [-2,7,9,5,-1,-4,7], [-8,6,8,-9,-7,-5,2], [-10,9,2,-8,-10,5,-5], [1,7,6,-2,9,-8,1], [9,8,8,9,-1,-6,-3], [9,-3,-1,6,7,-3,7], [-8,0,-2,10,-2,-2,-5], [-10,0,9,5,10,-7,-7], [-8,-6,-6,-1,-9,-4,-7], [-5,8,-6,-1,10,-3,2], [3,-8,-6,10,10,-3,0], [-8,6,4,0,-1,-8,-1], [9,2,2,-5,8,-8,-1], [9,-9,-6,8,-10,-10,5], [-6,-3,-7,5,8,-10,6], [-3,-8,-2,-9,1,-6,7], [-3,-7,-1,2,1,7,0], [4,4,-1,8,-9,-7,6], [0,-2,4,0,9,-10,0], [1,-1,5,-2,2,10,-6], [2,5,2,5,-6,5,8], [-6,-1,-3,6,0,2,10], [-1,0,5,9,-4,-5,-3], [1,-8,-4,-3,5,3,-4], [1,9,-7,-9,-10,4,3], [-5,6,-7,-10,7,-5,1], [5,1,-4,-8,-3,10,-1], [-10,8,4,-9,-2,3,-8], [9,6,9,5,8,-6,1], [5,-5,-7,-8,-10,0,-3], [4,-9,-10,2,10,-6,-7], [7,-3,2,-6,0,6,-4], [5,5,1,2,10,7,-7], [1,8,7,8,-3,-1,-9], [-7,9,7,1,-10,7,8], [-3,2,-6,3,3,-1,-7], [0,-2,6,6,3,-9,-10], [4,-5,7,-8,-6,9,3], [9,-10,3,8,6,-2,3], [-7,-6,10,1,-6,-6,1], [10,2,-3,-10,2,-5,10], [10,9,-7,-10,2,8,-6], [-1,6,-5,1,-2,0,-5], [-5,-4,3,3,0,-8,-2], [-4,5,7,6,2,-7,3], [-10,2,4,-4,6,6,0], [2,6,0,3,1,-6,6], [-3,1,-7,2,-9,4,1], [5,7,-3,4,6,-5,-1], [-9,4,9,-10,-7,10,6], [-1,1,-9,-6,-4,-3,-5], [1,-6,2,8,-3,-3,-8], [2,-8,-8,-10,4,-9,-1], [-10,-2,2,-5,5,2,-1], [8,-1,-7,-1,-9,-4,7], [-10,6,-7,-10,6,7,7], [-1,-6,9,-10,-2,-4,-8], [0,5,-9,-10,-7,-5,-7], [9,2,1,-1,0,-4,-5], [3,1,-4,-8,-3,-9,7], [-10,-9,-1,7,-2,-1,-7], [-10,7,2,2,8,2,-7], [2,2,10,-5,-10,6,8], [5,-9,-8,1,-10,-1,6], [0,-5,-3,10,8,-9,-6], [7,-3,2,-10,-8,-7,7], [9,5,6,1,0,0,10], [3,3,-8,7,2,6,4], [2,10,-3,7,4,-4,-8], [-4,6,7,4,0,8,7], [-5,5,8,-7,-9,-2,-1], [-3,-6,-8,-6,4,2,-1], [5,-7,-5,5,8,-3,-10], [6,-1,0,-8,10,7,10], [6,10,3,-7,-8,-6,-2], [-9,-10,4,6,3,-8,6], [-1,8,-1,-2,-10,-6,-1], [-2,2,6,-7,-5,-4,8], [4,-8,5,2,1,-8,5], [8,1,-8,-6,-4,6,7], [8,1,9,3,8,-7,-5], [-8,10,-6,-7,-6,-2,-5], [-5,0,6,-3,5,10,-6], [10,-7,3,-9,-7,-6,-5], [1,-7,-1,4,3,-10,-4], [7,5,2,7,9,-2,-4], [4,-4,4,9,-5,-10,-9], [2,-1,5,1,9,-5,4], [-7,4,-5,-8,-10,6,6], [4,-7,-10,6,-5,-6,-1], [-4,-6,7,4,-8,8,-5], [7,-2,-4,-4,-5,-7,-2], [10,3,-6,3,10,6,-8], [4,1,7,-4,-1,10,-3], [8,0,6,-5,1,7,-9], [-5,-2,8,7,4,1,9], [-5,0,7,9,-3,5,0], [-5,-4,1,-4,-3,-1,7], [-7,5,8,3,-7,-1,-9], [5,-4,4,-2,5,-1,-2], [-7,-3,7,7,1,6,8], [-1,-1,-10,7,-6,7,4], [8,6,8,9,-8,-9,5], [-8,0,8,0,-10,10,7], [-10,2,-9,4,6,-9,-5], [-3,-3,9,8,9,-3,-5], [6,7,10,2,9,6,10], [-1,5,-5,2,2,-4,-7], [5,2,-3,-6,-4,1,7], [5,6,10,-3,8,-5,2], [-7,-6,2,-4,9,10,-3], [-9,3,3,-3,-6,7,-3], [8,8,-7,9,5,-2,-8], [1,-3,-5,-2,-4,0,6], [10,3,6,1,-10,-3,-7], [2,-1,-10,7,-3,9,4], [4,-2,-4,0,-8,5,5], [-3,0,-3,-3,5,-1,3], [5,6,3,7,10,-9,-6], [-5,7,6,7,4,-3,7], [-8,8,-9,4,6,1,2], [-8,-7,-10,2,-5,-2,4], [-2,0,10,4,2,-1,6], [-10,-5,-4,-2,0,10,8], [7,0,7,5,6,-2,-2], [8,-2,5,-10,10,-10,-7], [10,-2,-5,0,-10,3,9], [2,3,10,2,-10,7,-8], [8,-7,5,-9,1,1,-7], [1,1,8,3,9,9,8], [10,10,-8,7,-6,10,10], [-2,-10,-5,-8,-8,6,-6], [-5,-6,3,-8,-2,-5,-5], [-1,-1,3,5,7,2,2], [4,-5,-5,-6,3,5,7], [-1,7,-2,-6,-4,-4,-10], [9,10,2,-6,-3,-8,-7], [3,0,8,9,0,-5,4], [-9,4,-6,10,-7,6,10], [1,-8,-10,-6,5,-1,-6], [-1,-7,0,0,-6,8,-8], [-7,-7,-6,9,-9,-9,6], [8,-2,-2,6,10,6,7], [-1,6,8,-9,8,7,-3], [8,10,-4,9,1,6,9], [3,8,-2,-7,-7,-1,-8], [-6,9,-8,-4,-6,0,2], [-2,-6,-9,7,5,1,9], [-5,1,-7,-1,-10,8,7], [-7,8,-1,1,-10,-2,-9], [6,-5,3,-3,-2,-1,-4], [9,-5,9,10,-1,-10,9], [4,-1,5,3,-7,9,-8], [8,-2,6,-5,3,-2,2], [1,-1,5,4,3,7,-6], [-10,-7,5,4,3,-2,-10], [-4,8,-8,3,-5,-1,4], [-7,-7,0,-2,-4,-7,5], [3,3,7,-7,-10,-9,6], [0,9,7,8,10,-9,6], [-7,1,-9,1,-5,-4,-2], [-1,10,-9,-5,-3,3,9], [-3,2,6,-3,1,-7,-3], [4,10,8,3,2,7,-1], [3,-3,3,-10,-3,8,10], [-3,7,8,-5,3,4,-4], [-5,2,4,-4,-4,9,10], [1,-1,1,-2,4,5,5], [2,9,10,8,-4,-10,2], [3,-9,2,-3,-7,-3,6], [0,-2,4,-6,10,1,6], [2,-3,5,7,0,8,5], [9,7,4,5,-10,8,8], [6,9,8,6,-8,-8,2], [2,-8,3,6,7,10,-9], [9,3,-4,-9,-10,2,2], [-1,5,1,3,6,7,7], [-10,6,-8,10,5,10,-7], [-10,8,2,2,2,-1,2], [1,7,10,-6,-1,-8,-3], [2,-9,8,-4,-9,4,-10], [7,4,-9,7,5,10,9], [4,8,-8,-2,-7,-3,-9], [-5,0,7,-1,-8,-9,7], [-10,-7,-7,1,3,7,-5], [-9,-5,0,-2,-8,2,-2], [9,9,10,5,-6,1,2], [6,10,-2,6,-6,-2,-1], [-4,-5,4,-10,-3,0,9], [-9,-5,-2,-2,7,-7,3], [5,4,-7,7,-5,6,2], [5,-6,-6,-4,-7,-5,-8], [-10,-9,-10,-1,-6,-1,8], [2,-10,2,-6,8,-9,-3], [-8,5,5,-2,2,-7,10], [-3,-3,6,3,-9,-8,3], [2,-6,3,1,8,-8,9], [-3,-7,2,0,-2,10,-8], [9,-9,-2,-8,-4,5,-8], [-5,-4,-10,-5,-1,7,10], [9,-1,8,-8,4,-2,4], [7,0,-2,3,6,2,-8], [-9,7,6,0,3,7,-2], [10,7,-8,-7,-10,1,8], [-9,9,9,1,-7,9,6], [4,8,-8,-9,2,-1,-1], [-8,7,7,-2,-3,0,9], [8,-3,-1,0,-9,5,6], [5,-10,-8,-1,8,-2,-3], [-3,-5,10,5,-5,-8,-3], [10,1,-2,-3,8,-8,-10], [3,9,-9,0,10,0,2], [4,1,-5,-6,-9,-1,6], [-8,4,1,10,1,-3,6], [-7,5,8,-3,10,4,5], [5,-9,10,-3,-3,-2,-8], [4,-10,-2,-6,10,8,9], [-8,5,9,-2,-4,-4,-3], [7,-4,1,-9,-6,-6,-5], [-9,10,-2,4,-4,-8,2], [-4,7,1,-2,-4,-9,10], [-10,-8,10,-7,3,5,3], [7,6,-10,-5,-5,-7,-5], [3,9,6,9,-6,-5,-3], [2,-6,-4,3,-2,-2,6], [-3,-6,4,8,3,0,5], [-5,1,-8,-5,6,5,3], [-7,-3,1,7,2,1,6], [-8,0,8,-8,10,-6,-2], [-4,-6,-10,5,10,-2,10], [8,6,5,9,-2,-7,2], [10,-6,7,-10,1,3,4], [2,-6,-8,-2,2,1,9], [8,-9,-3,-6,-4,6,-3], [7,-2,-10,7,0,-3,-10], [8,1,3,3,-4,2,-6], [-1,-10,9,1,8,10,0], [-6,9,-10,-9,-6,10,-5], [-4,0,-5,3,-9,1,4], [4,-3,-5,-6,0,8,5], [10,5,-6,-9,6,-4,6], [4,7,1,-1,0,-4,7], [-8,-2,-1,-7,7,4,9], [10,-7,-4,2,7,-9,7], [-2,10,-6,-6,-3,1,5], [7,-9,-9,5,-4,5,-5], [-1,2,-5,-5,-8,-1,-3], [-5,-9,4,4,6,-4,1], [-5,-1,-2,5,2,-3,-1], [-5,9,2,-2,7,-6,-1], [-1,-10,-7,6,-9,9,9], [-4,6,-1,-10,10,2,5], [3,7,-4,5,3,-9,2], [4,4,-7,4,0,-9,8], [6,8,-6,-1,10,2,-4], [-3,-6,-7,6,0,-10,8], [-5,6,-10,10,-9,-3,-6], [3,3,-7,2,2,6,0], [2,-3,-7,-10,6,3,-10], [-5,4,-3,-1,8,0,-6], [10,-9,-2,-9,1,-3,2], [7,8,0,-2,-3,0,5], [-6,6,9,-4,1,0,-6], [-3,2,5,-5,3,4,9], [2,-5,-9,-7,0,-7,4], [-9,1,-7,7,0,-1,-3], [9,-8,-10,-8,-5,5,-10], [-9,-5,-4,4,-10,6,-5], [10,-4,-10,-2,-7,7,-2], [3,-9,1,-9,-5,5,0], [-9,3,8,1,9,-2,8], [2,0,-10,2,-9,4,-9], [1,-1,7,7,5,10,-8], [1,0,5,-10,2,2,-1], [-8,4,5,-5,2,-9,5], [9,10,3,-7,8,7,7], [4,-3,-10,2,6,-5,-8], [-2,-4,7,-6,10,-2,-3], [7,0,-1,5,-7,5,3], [-8,3,5,8,5,-7,8], [3,-5,-2,6,2,2,-6], [-10,-7,4,-1,1,-8,-8], [10,-4,9,6,10,-6,6], [-10,-1,2,8,0,-3,-8], [6,2,4,1,7,2,-3], [7,-5,6,6,1,9,0], [-10,6,8,-4,7,0,8], [10,3,7,0,10,8,-10], [2,-9,-6,-6,-6,-3,-7], [-7,9,1,6,8,10,-7], [-10,0,-8,-1,4,8,1], [-2,5,-10,6,-7,3,3], [1,-1,-4,3,7,-7,0], [8,2,3,-2,6,-1,-9], [5,0,0,-7,-1,-9,9], [9,-7,-4,1,-9,-2,-10], [-9,-10,9,-9,-9,4,-7], [8,6,-3,2,-7,1,1], [-10,-4,-6,-10,-5,-4,-8], [-7,5,-7,10,-9,-9,7], [-3,10,-8,-9,-9,4,8], [-10,1,-6,5,7,-6,10], [10,-6,5,-1,-8,3,-5], [-3,2,-3,10,-4,10,-7], [4,4,-9,-7,7,-2,3], [10,2,-6,-1,8,10,1], [0,2,9,-7,1,10,2], [5,0,-8,-7,-10,8,4], [10,7,-4,9,7,6,8], [2,-3,-1,2,9,8,-5], [10,-2,-2,-7,9,-7,0], [0,5,-7,-5,0,-1,-3], [3,1,6,0,-2,-5,0], [5,-2,-10,7,4,5,5], [-2,-10,4,7,10,-7,8], [-7,-2,-1,-8,-3,0,7], [-4,3,-10,1,1,1,10], [1,4,-4,-7,0,1,-8], [3,4,-2,10,-10,7,6], [4,-5,-9,2,10,-1,-2], [-7,6,-5,6,-8,-4,-6], [-3,9,-1,-7,0,5,-2], [-7,0,8,-2,-2,-6,-5], [4,0,1,-7,8,4,0], [-6,8,9,0,-4,-7,-3], [-7,-1,-5,-6,7,1,7], [-4,-9,-1,8,-10,0,3], [7,-1,10,-7,2,-3,-4], [-9,5,-5,-6,9,-1,0], [10,4,5,-9,3,2,-5], [5,-10,9,5,7,0,3], [3,-3,0,-10,0,-6,0], [-8,3,2,-5,-5,2,-1], [-4,-10,-10,10,-4,4,3], [6,1,-9,5,6,8,9], [-8,2,3,5,7,7,5], [-4,0,7,-3,6,-8,-5], [6,9,8,7,9,0,-9], [-9,9,-7,9,-7,-10,0], [-1,7,6,-6,4,-6,6], [-9,-9,-7,8,-6,9,-3], [5,-7,-1,-8,3,6,3], [-1,-2,-10,2,-10,10,3], [-5,-6,3,2,6,5,-7], [-8,1,8,-1,7,-2,3], [1,-6,-4,-8,2,2,6], [3,0,1,6,-1,-1,-2], [-10,0,1,8,2,0,3], [6,-5,-6,7,9,-9,-10], [-10,-10,-10,-5,-5,6,0], [8,-4,-8,1,-10,8,-3], [7,-3,3,-6,1,5,-6], [8,10,10,7,6,-3,0], [4,-6,6,-3,6,0,7], [9,-7,-3,10,-2,-2,-4], [4,-1,-4,-8,-3,7,-7], [-8,2,9,-4,0,-5,-7], [-2,9,7,7,3,7,-5], [8,5,10,-5,-8,-6,-3], [0,6,-10,-5,-6,-7,10], [-9,-2,3,-10,5,-9,-1], [9,-4,-6,-10,10,7,8], [-7,-4,-1,-1,4,7,-7], [-9,-3,-5,-2,-7,-5,7], [-6,8,4,-3,10,-7,9], [-10,-2,4,1,8,-2,-3], [3,-3,-7,-2,9,8,7], [8,9,8,9,9,9,-1], [-3,10,6,-4,3,1,-4], [5,1,1,5,-10,-4,-2], [-7,7,3,2,1,-5,0], [0,-4,-10,-2,9,-3,-3], [2,8,-7,-4,5,7,-9], [4,-4,4,4,0,5,5], [5,-2,2,-3,9,3,8], [4,3,-8,3,-9,4,6] ]; for(i=1,#V, print1(i,":"); my(L=hyperellratpoints(Polrev(V[i]),16383)); print(apply(affine2proj,L))); } pari-2.11.2/src/test/in/ellissupersingular0000644000175000017500000000245013201017466017212 0ustar billbillp = 7; e = 5; q = p^e; g = ffprimroot(ffgen(q)); S = [g^n | n <- [1 .. q - 1], ellissupersingular(g^n)]; if (S != [6] || ellissupersingular(0 * g^0), error("Bad result")); p = 7; e = 4; q = p^e; g = ffprimroot(ffgen(q)); S = [g^n | n <- [1 .. q - 1], ellissupersingular(g^n)]; if (S != [6] || ellissupersingular(0 * g^0), error("Bad result")); S = [g^n | n <- [1 .. q - 1], ellissupersingular(ellinit(ellfromj(g^n)))]; if (S != [6] || ellissupersingular(0 * g^0), error("Bad result")); p = 43; one = Mod(1, p); S = [lift(j) | j <- [0 .. p - 1] * one, ellissupersingular(j)]; if (S != [8, 41], error("Bad result")); e = 2; q = p^e; T = ffgen(q, 't); one = T^0; g = (28*T + 6) * one; \\ Fix primitive root: always get the same ordering in S S = [g^n | n <- [1 .. q - 1], ellissupersingular(g^n)]; if (S != [41, 8, 38*T + 31, 5*T + 36]*one, error("Bad result")); { if([j | p<-primes(5);j<-[0..p-1],ellissupersingular(Mod(j,p))]!=[0,0,0,6,0,1], error("Bad result")); } E=ellinit([1,0,1,-6,4]); if([ellissupersingular(E,p)|p<-primes(5)]!=[0,0,1,0,0], error("Bad result")); iferr(ellissupersingular(""), err, Vec(err)); K = nfinit(y^3-2); f(E,p) = [ ellissupersingular(E, P) | P <- idealprimedec(E.nf,p) ]; P = [2,3,5,47,53,59] E = ellinit([y,1],K); [f(E,p) | p <- P] E = ellinit([1,y,1,y,y+1],K); [f(E,p) | p <- P] pari-2.11.2/src/test/in/qfbclassno0000644000175000017500000000056113201017466015412 0ustar billbillqfbclassno(-44507759) qfbclassno(-57403799) qfbclassno(-94361767) qfbclassno(-111385627) qfbclassno(-136801204) qfbclassno(-185415288) qfbclassno(-198154147) qfbclassno(-223045972) qfbclassno(-1253840791) qfbclassno(-1382998299) qfbclassno(-1567139127) qfbclassno(-1788799151) qfbclassno(-1850979435) qfbclassno(-4386842803) qfbclassno(-5082406399) qfbclassno(1-2^100) pari-2.11.2/src/test/in/nfislocalpower0000644000175000017500000000106513211621335016303 0ustar billbillK=bnfinit(y^2+1); P=idealprimedec(K,2)[1]; nfislocalpower(K,P,2,2) nfislocalpower(K,P,-1,2) nfislocalpower(K,P,-1,4) P=idealprimedec(K,5)[1]; nfislocalpower(K,P,P.gen[2],2) nfislocalpower(K,P,P.gen[2],5) nfislocalpower(K,P,y,5) nfislocalpower(K,P,y,10) nfislocalpower(K,P,Mod(y+1,K.pol)^10,10) N=nfinit(x^2-155);pr=idealprimedec(N,5)[1]; nfislocalpower(N,pr,20*x-249,5) K=nfinit(y^3-2); P=idealprimedec(K,3)[1]; nfislocalpower(K,P,2^18,54) nfislocalpower(K,P,y,3) nfislocalpower(K,P,y,0) nfislocalpower(K,P,1,0) nfislocalpower(K,"",1,0) nfislocalpower(K,"","",0) pari-2.11.2/src/test/in/set0000644000175000017500000000061213036414402014044 0ustar billbillSet(Vecsmall([1,2,1,3])) Set(List([])) L=List([1,3,1,2,3]); Set(L) listsort(L,1); L Set(1) a=Set([5,-2,7,3,5,1,x,"1"]) b=Set([7,5,-5,7,2,"1"]) setintersect(a,b) setisset([-3,5,7,7]) setisset(a) setminus(a,b) setsearch(a,3) setsearch(a,"1") setsearch(b,3) setsearch(L,3) setsearch(1,3) setunion(a,b) X = [1,2,3]; Y = [2,3,4]; setbinop((x,y)->x+y, X,Y) setbinop((x,y)->x+y, X) setbinop(x->x, X) pari-2.11.2/src/test/in/multivar-mul0000644000175000017500000000077213036414402015716 0ustar billbill/* Multivariable Laurent polynomial bug finding */ /* 05 Jul 2007 Michael Somos */ x;y;z; pol(N, v)= { my(t = vector(N+1)); t[N+1] = 1; for (i=1,#v, my(n = v[i]); if (n < 1, t[1] = 1 , t[(n-1) \ 2 + 1] = if (n%2,1/y,1/z))); Polrev(t); } /* Attempt to multiply two polynomials in x */ f(N,M,v,w)= iferr(pol(N,v)*pol(M,w); 0, E, 1); {doit(N,M)= forvec(v=[[0,2*N],[0,2*N],[0,2*N]], forvec(w=[[0,2*M],[0,2*M]], if(f(N,M,v,w), print([N,M],v,w)),2),2); } doit(9,9); pari-2.11.2/src/test/in/det0000644000175000017500000000211613457566441014050 0ustar billbillM=[8, 520037431316, 0, 520037431316, 0, 520035574851, 0, 965887922181; 520037431316, 38628881218179226412880, 4958989308, 38629 323366757228004016, 73478513407, 38628858533840109643628, 4243910044575227, 71751970539224190286968; 0, 4958989308, 0, 4957132843, 0, 5710115047, -5940688, 0; 520037431316, 38629323366757228004016, 4957132843, 38629765515335229595152, 74231495611, 38629300680212375365180, 4243835813079616, 71752791774805257538227; 0, 73478513407, 0, 74231495611, -5940688, 0, 1856465, 0; 520035574851, 38628858533840109643628, 5710115047, 38629300680212375365180, 0, 38628836591317537513845, 4243835813079616, 71751920822489123831004; 0, 4243910044575227, -5940688, 4243835813079616, 1856465, 4243835813079616, -752982204, 7881921412974726; 965887922181, 71751970539224190286968, 0, 71752791774805257538227, 0, 71751920822489123831004, 7881921412974726, 133277068316447073113823]; matdet(M) matdet(M,1) centerlift(chinese(apply(p->matdet(M*Mod(1,p)),primes(200)))) centerlift(chinese(apply(p->matdet(M*Mod(1,p)),vector(5,i,nextprime(2^(128+i)))))) \\ #2128 matdet([x,1/x,1;y,1/y,1;1,1,1]) pari-2.11.2/src/test/in/ellisogeny0000644000175000017500000002033413326135265015437 0ustar billbillx; y; t; ellhyperellipticpolynomials(E, x = 'x) = { my (one = E.j^0); x *= one; return([x^3 + E.a2 * x^2 + E.a4 * x + E.a6, E.a1 * x + E.a3]); } elldefiningequation(E, x = 'x, y = 'y) = { my (one = E.j^0); x *= one; y *= one; my (eqns = ellhyperellipticpolynomials(E, x)); return(y^2 + eqns[2]*y - eqns[1]); } ellbasechar(E) = iferr(E.p, unused_param, 0); ffone(p, n = 1, v = 't) = ffgen(p^n, v)^0; num_isog(E, isog) = { my([x,y,d] = isog); my(d2 = d^2, d3 = d2*d, d4 = d2^2, d6 = d3^2); ((x + E.a2*d2)*x + E.a4*d4)*x + E.a6*d6 - y*(y + E.a1*d*x + d3*E.a3); } isog_satisfies_eqns(E, F, isog) = { if (Mod(num_isog(F,isog), elldefiningequation(E)) != 0, error("Isogeny polynomials don't satisfy the curve equations")); } kernel_poly_from_generator(E, P, ord = 0, x = 'x, check = 1) = { if (check && ! ellisoncurve(E, P), error("Given point is not on given curve.")); if (!ord, ord = ellorder(E, P)); my (one = E.j^0, rP = P, res = Pol([one], x)); for (r = 1, ord \ 2, res *= x - rP[1]; rP = elladd(E, rP, P)); res; } check_ker_pol_from_gen() = { my (x = 'x, one = ffone(101)); my (data = [ [1, [1, 1], [0], 1, Pol([1], x)], [one, [37, 42], [85, 0], 2, x + 16], [one, [37, 42], [89, 71], 3, x + 12], [one, [37, 42], [21, 9], 5, x^2 + 12*x + 14], [one, [37, 42], [58, 59], 18, x^9 + 100*x^8 + 68*x^7 + 59*x^6 + 49*x^5 + 86*x^4 + 98*x^3 + 12*x^2 + 70*x + 56] ]); for (i = 1, #data, my ([rg_one, ainvs, pt, ord, expected] = data[i], E = ellinit(ainvs * rg_one)); pt *= rg_one; my (res = kernel_poly_from_generator(E, pt, ord, x)); if (res != expected || Mod(elldivpol(E, ord, x), res) != 0, error("kernel polynomial is incorrect"))); } check_data(E, P, ord) = { my (p = ellbasechar(E), M = [7, 13, 3, 4]); if (p != 0, my (n = (E.j).f); t = ffgen(p^n, 't); if ( p == 2, M = [t, t+1, t, 1] * t^0, p == 3, M = [t, t+1, 2*t, t+2] * t^0)); E = ellchangecurve(E, M); P = ellchangepoint(P, M); if (!ellisoncurve(E, P) || ellorder(E, P) != ord, error("Broken data: ", ord, "-torsion")); my (F, G, FF, GG, ker); F = ellisogeny(E, P); FF = ellisogeny(E, P, 1); if (F[1] != FF, error("Got different curve when only computing image")); ker = kernel_poly_from_generator(E, P, ord, 'x); G = ellisogeny(E, ker); GG = ellisogeny(E, ker, 1); if (G[1] != GG, error("Got different curve when only computing image")); if (F[1][1..5] != G[1][1..5], error("Different curves obtained for same kernel")); if (F[2] != G[2], error("Different isogenies obtained for same kernel")); isog_satisfies_eqns(E, F[1], F[2]); } tatecrv(b, c, p = 0, n = 1) = { my (one = if (p == 0, 1, ffone(p, n))); ellinit([1 - c, -b, -b, 0, 0] * one); } do_tate(b, c, ord, p = 0, n = 1) = { my (E, P = [0, 0], t, M = Vec([1,0,0,1])); E = tatecrv(b, c, p, n); check_data(E, P, ord); } check_apply(E, ker, P, fP) = { my ([F, f] = ellisogeny(E, ker)); if (ellisogenyapply(f, P) != fP, error("Wrong image of point")); } check_compose() = { my (one = ffone(101), E = ellinit([6, 53, 85, 32, 34] * one), P = [84, 71] * one, \\ order 5 [F, f] = ellisogeny(E, P), Q = [89, 44] * one, \\ order 2 [G, g] = ellisogeny(ellinit(F), Q), gof = ellisogenyapply(g, f)); isog_satisfies_eqns(E, ellinit(G), gof); } check_prio_err(E, ker, var1, var2, tst, msg) = { my (got_err = 0); iferr(ellisogeny(E, ker, 0, var1, var2), err, got_err = 1, errname(err) == "e_PRIORITY" && variable(component(err, 2)) == tst); if (! got_err, error(msg)); } check_errs() = { my (E = ellinit([8, 5]), P = [0, 0], got_err = 0); \\ ellisoncurve(E, P) = 0 iferr(ellisogeny(E, P), err, got_err = 1, errname(err) == "e_DOMAIN" && component(err, 4) == E && component(err, 5) == P); if (! got_err, error("No error when P not on E")); my (var1 = 'var1, var2 = 'var2); check_prio_err(E, P, var2, var1, 'var2, "No error with bad variable order"); iferr(ellisogeny(E, "banana bread"), err, got_err = 1, errname(err) == "e_TYPE" && component(err, 2) == "banana bread"); if (! got_err, error("No error with bad kernel type")); check_prio_err(E, ['pvx, 0], 'x, 'g1, 'pvx, "No error with bad x-point base field variable order"); check_prio_err(E, [0, 'pvy], 'x, 'g2, 'pvy, "No error with bad y-point base field variable order"); check_prio_err(E, 'x * 'asdf, 'x, 'g3, 'asdf, "No error with bad kernel variable order"); check_prio_err(ellinit(['a4, 'a6]), [0], 'x, 'g4, 'a4, "No error with bad j-invariant variable order"); my (t = ffgen(2^2, 't), one = t^0, E = ellinit([t, t + 1, 0, t, t] * one), div2 = elldivpol(E, 2)); div2 /= polcoeff(div2, poldegree(div2)); iferr(ellisogeny(E, div2), err, got_err = 1, errname(err) == "e_DOMAIN" && component(err, 4) == E && component(err, 5) == div2); if (! got_err, error("No error when quotienting E by E[2] in char 2")); } check_ker_pol_from_gen(); check_compose(); check_errs(); P = [0, 0]; E = ellinit([0, 3, 0, 7, 0]); \\ Doing "1-torsion" check_data(E, [0], 1); check_apply(E, [0], P, P); check_apply(E, P, [0], [0]); \\ Doing 2-torsion check_data(E, P, 2); one = ffone(1009); E = ellinit([0, 3, 0, 7, 0] * one); check_data(E, [0], 1); check_apply(E, [0], P, P); check_data(E, P * one, 2); check_apply(E, P, P, [0]); in = [149, 125] * one; out = [833, 506] * one; check_apply(E, P, in, out); check_apply(E, P, [0], [0]); \\ Doing 3-torsion... E = ellinit([1, 0, 1, 0, 0]); check_data(E, P, 3); E = ellinit([1, 0, 1, 0, 0] * ffone(1009)); check_data(E, P, 3); t = ffgen(2^4, 't); one = t^0; E = ellinit([t^3+t^2+1,t^3+t+1,t^3+t^2+t+1,t^3+t+1,t^3+t+1]*one); Q = [t^2+t+1,t^3+t^2+1]*one; check_data(E, Q, 3); Q = [t^2+t,t^3+t^2+1]*one; check_data(E, Q, 2); Q = [t^3+t,t^3+t^2]; check_data(E, Q, 6); t = ffgen(2^5, 't); E = ellinit([t^3+t^2+1,t^4+t^3+t,t^4+1,t^3+1,t^2+t]); Q = [t^4+t^3+t^2,t^3+t^2]; check_data(E, Q, 3); t = ffgen(3^2, 't); one = t^0; Q = [t, 1] * one; E = ellinit([2,2*t,t+2,2*t,2*t+1]*one); check_data(E, Q, 3); \\ Quotient by full 2-torsion. Arbitrary E here; just need char(k) != 2. E = ellinit([0, 3, 0, 7, 0] * ffone(1009)); ker = elldivpol(E, 2) * E.j^0; F = ellisogeny(E, ker); FF = ellisogeny(E, ker, 1); if (F[1] != FF, error("Got different curve when only computing image")); isog_satisfies_eqns(E, F[1], F[2]); \\ See Kubert 1976 for why all this works. Data was selected randomly. \\ Doing 4-torsion... b = -128/7; c = 0; do_tate(b, c, 4); \\ Doing 5-torsion... b = 121/13; c = b; do_tate(b, c, 5); do_tate(b, c, 5, 2, 7); \\ Doing 6-torsion... c = -7/2; b = c + c^2; do_tate(b, c, 6); do_tate(b, c, 6, 3, 3); \\ Doing 7-torsion... d = 21/11; c = d^2 - d; b = d * c; do_tate(b, c, 7); t = ffgen(2^3, 't); d = t; c = d^2 - d; b = d * c; do_tate(b, c, 7, 2, 3); \\ We do these two over a finite field to (1) avoid stack overflow \\ and (2) to make them run a bit faster. \\ Doing 8-torsion... d = 11/7; b = (2 * d - 1) * (d - 1); c = b/d; do_tate(b, c, 8); do_tate(b, c, 8, 1009); t = ffgen(2^3, 't); d = t; b = (2 * d - 1) * (d - 1); c = b/d; do_tate(b, c, 8, 2, 3); \\ Doing 9-torsion... f = 1/7; d = f * (f - 1) + 1; c = f * (d - 1); b = c * d; do_tate(b, c, 9); do_tate(b, c, 9, 61, 2); t = ffgen(3^3, 't); f = t; d = f * (f - 1) + 1; c = f * (d - 1); b = c * d; do_tate(b, c, 9, 3, 3); \\ Francois Brunault's example E = ellinit([0, -1, 1, 0, 0]); z = Mod('t, polcyclo(11, 't)); a = z + 1/z; xP = a*(a - 1)*(a + 2); \\ [25]P = 0 on E. P = [xP, a*xP]; F = ellisogeny(E, P, 0, 'x, 'y); G = ellisogeny(E, kernel_poly_from_generator(E, P, 25, 'x), 0, 'x, 'y); if (F[1] != G[1], error("Different curves obtained for same kernel")); if (F[2] != G[2], error("Different isogenies obtained for same kernel")); isog_satisfies_eqns(E, F[1], F[2]); ellisogenyapply(x,x) ellisogenyapply([f,g,h],1) E = ellinit([-11/16,-445/32]); [e2,iso2] = ellisogeny(E,[5/2,0]); [e4,iso4] = ellisogeny(E,[27/4,17]); E2 = ellinit(e2); [e4p,iso2p] = ellisogeny(E2,[11, 0]); [e4,iso4] == [e4p,ellisogenyapply(iso2p,iso2)] E=ellinit([1,3]); ellisogeny(E,x-Mod(y,elldivpol(E,2,y)),1) pari-2.11.2/src/test/in/zncoppersmith0000644000175000017500000000064513036414402016164 0ustar billbillp = 10^30+57; q = 10^31+33; N = p*q; p0 = p % 10^20; z = zncoppersmith(10^19*x + p0, N, 10^12, 10^29) gcd(z[1]*10^19 + p0, N) == p setrand(1); P = 4625048078322670354774415943228839104529734663852281547523640; e = 3; X = floor(N^0.3); x0 = 1339991002000615200; C = lift( (Mod(x0,N) + P)^e ); z = zncoppersmith((P+x)^3 - C, N, X) z[1] == x0 zncoppersmith(Pol([192378,19237198,912831923,12938719]), 2*3*5*7, 1000.5, 29.5) pari-2.11.2/src/test/in/zeta0000644000175000017500000000060113457560102014220 0ustar billbilldefault(realprecision,38); allocatemem(20*10^6); zeta(3+O(5^10)) zeta(1 + I/100) zeta(1000.5) zeta(1000) zeta(100) zeta(31) zeta(100+100*I) zeta(60+I) zeta(-1000+I) zeta(2+O(2^10)) zeta(2^64) zeta(-2^64) iferr(zeta(-1-2^64),E,E) zeta(2+1e-101*I) zeta(1.01) zeta(1e-32) zeta(50.5) zeta(-2.5) zeta(O(x)) default(seriesprecision,3) zeta(1+x) zeta(1/2+I*x+O(x^2)) localprec(19); zeta''(0) pari-2.11.2/src/test/in/graph0000644000175000017500000000200313326135265014357 0ustar billbillHEAP=[32, if(sizebyte(0)==16,274,276)]; default(realprecision,38); \e plotinit(0,500,500) plotmove(0,0,0);plotbox(0,500,500) plotmove(0,200,150) plotcursor(0) write("pari.ps", plotexport("ps", 0)) plotinit(1,700,700) plotkill(1) plotmove(0,0,900);plotlines(0,900,0) plotlines(0,vector(5,k,50*k),vector(5,k,10*k*k)) plotmove(0,243,583);plotcursor(0) plot(x=-5,5,sin(x),-1,1) plotpoints(0,225,334) plotpoints(0,vector(10,k,10*k),vector(10,k,5*k*k)) write("pari.ps", plotexport("ps", [0,20,20])) write("pari.ps", plothexport("ps",x=-5,5,sin(x))) write("pari.ps", plothexport("ps",t=0,2*Pi,[sin(5*t),sin(7*t)],1,100)) write("pari.ps", plothrawexport("ps",vector(100,k,k),vector(100,k,k*k/100))) plotmove(0,50,50);plotrbox(0,50,50) plotrline(0,200,150) plotcursor(0) plotrmove(0,5,5);plotcursor(0) plotrpoint(0,20,20) plotinit(3,600,600);plotscale(3,-7,7,-2,2);plotcursor(3) plotmove(0,100,100);plotstring(0,Pi) plotmove(0,200,200);plotstring(0,"(0,0)") write("pari.ps", plotexport("ps", [0,10,10])) if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/digits0000644000175000017500000000154213457566437014566 0ustar billbillbinary(0) digits(0) fromdigits([]) digits(5^100) fromdigits(vector(100,i,i%7)) fromdigits([1,0,-1],2) fromdigits([1,1,0,1],-2) check(a,b)=my(v=digits(a,b));if(subst(Pol(v),'x,b)!=a || vecmax(v)>=b || fromdigits(v,b)!=a,error([a,b])); check(5^100,2) check(5^100,3) check(3^100,2^64-1) check(3^100,2^128+1) sumdigits(0) sumdigits(129) sumdigits(123456789123456789123456789) sumdigits(100000!) default(realprecision,38); binary(0.) binary(0.005) binary(1.1) binary([0,1]) binary(I) vector(10, i, sumdigits(123456789, i+1)) digits(2^128+3, 2^64) digits(999999999999999,4294967295) sumdigits(2^128+3, 2^64) sumdigits(-3,3) sumdigits(-3,10) sumdigits(-3,2) 0x12345 0x1234567890ABCDEF987654321 0x0000000000000000012345 0b11011011 0b1011011101111011111011111101111111011111111011111111101111111111 0b000000000000000000000000000000000000000000000000000000000000000011011011 pari-2.11.2/src/test/in/padic0000644000175000017500000000463413457600745014357 0ustar billbillpadicprec(1,2) padicappr(x,O(2)) padicappr(x^2+1+O(3), Mod(-1+O(5^10),y^2-2)) padicappr(x^2+1+O(3), -1+O(5^10)) padicappr('x,Mod(0,'t)+O(7^10)) padicappr(x^2+Mod(O(3^2),t^2+1),Mod(0,t^2+1)+O(3^2)) factorpadic(y^2+3^5,3,5) factor(x^2*(1+O(5^2))) factorpadic(x^2*(x+1)^3*(x+2)*(1+O(5^2)), 5, 2) factorpadic(x^2, 5, 2) factorpadic(3*x + O(2^5),2,5) p=2^64+13; liftint(padicappr((x-1)^30+p^30, 1+O(p^40))) test(p, e = 1)= { my (N = 7*p^2); for (i=0,10,if (!ispower(i+O(p^e), N), print([i,p,e]))); for (i=1,10,if (!ispower((i+O(p^e))^N, N), error([i,p,e]))); } test(2) test(2,2) test(2,3) test(3) test(3,3) test(11,3) test(nextprime(2^64),3) polrootspadic(x^3-x+8, 2, 6) f = subst(x^3-x+8, x, x + Mod(y,y^2+y+1)); padicappr(f, Mod(1+O(2^10)-y, y^2+y+1)) \\#1424 lift(1/2 + O(2)) s=3+3^2+O(3^5) t=2+2^2+O(2^5) f=[cosh,sinh,tanh,cotanh]; { for (i=1,#f, print(f[i](s)); print(f[i](O(x))); ) } gamma(s) gamma(t) p=2^64+13; gamma(3 + O(p^2)) gamma(-3 + O(p^2)) lngamma(17+O(3^5)) gamma(1/5+O(2^2)) gamma(1/5+O(2^3)) gamma(123+O(2^7)) gamma(123+O(2^8)) gamma(29+O(2^5)) gamma(29+O(2^6)) I + O(5^3) log(1+4+O(2^10)) log(1+3+O(3^10)) log(1+5+O(5^10)) log(1+101+O(101^10)) T = x^12 + 208*x^6 + 64; phi = polcyclo(9); prec = 10; p = 3; v = factorpadic(T, p, prec)[,1]; liftall( padicappr(phi, Mod(-2+O(p^prec), v[1])) ) T = teichmuller([17,10]); for(i=1,16,if (teichmuller(i+O(17^10),T) != teichmuller(i+O(17^10)), error(i))) \\#1793 padicappr(x^3+1,-2+O(2^5)) padicappr(x^3+1,Mod(-2+O(2^5),y^3+3)) newtonpoly(x^4+3*x^2+27*x+x+81,3) newtonpoly(x^4+3*x^2+27*x,3) newtonpoly(x^4+y*x^2+y^3*x,y) \\#1863 f=x^9+42*x^7-16*x^6+504*x^5-336*x^4+1560*x^3-1008*x^2+64; factorpadic(f,2,3) \\#1876 factorpadic(2*x^4+x^2,2,2) polrootspadic(2*x^4+x^2,2,2) \\#1905 polrootspadic(x,3,10) T = y^32 - 8*y^31 + 132*y^30 - 872*y^29 + 7978*y^28 - 43984*y^27 + 278592*y^26 - 1280230*y^25 + 6016836*y^24 - 22767800*y^23 + 83696182*y^22 - 259841076*y^21 + 772364746*y^20 - 1922859142*y^19 + 4097944748*y^18 - 7433491240*y^17 + 18853991151*y^16 - 45141140592*y^15 + 200971321044*y^14 - 495395957226*y^13 + 841610071252*y^12 - 313005796720*y^11 - 2973750987680*y^10 + 5018975002436*y^9 + 29214528458769*y^8 - 73301518803394*y^7 + 195023156598096*y^6 - 265879507425724*y^5 + 441249179094943*y^4 - 310432057395848*y^3 + 286093590632140*y^2 - 68137080187062*y + 169311946842369; fa=factorpadic(T,2,1); [poldegree(P) | P <- fa[,1]] fa=factorpadic(T,2,15); [poldegree(P) | P <- fa[,1]] pari-2.11.2/src/test/in/nfeltembed0000644000175000017500000000035213326135265015370 0ustar billbilldefault(realprecision,38); nf = nfinit('y^3 - 2); nfeltembed(nf, y) nfeltembed(nf, y, [2]) nfeltembed(nf, y, [1,2]) nfeltembed(nf, 2, [1..3]) nf=nfinit(x^4-3); [nfeltembed(nf,x,i) | i <- [1..3]] \\Errors nfeltembed(nf, y, [1,2,4]) pari-2.11.2/src/test/in/extract0000644000175000017500000000245613326135265014744 0ustar billbillA=vector(100,i,i); for(i=35,99, print1(vecextract(A,1<f(x,4)); test(x->f(x,-4))) | f <- fun]; test(x->component(x,2)); test(x->component(x,10)); test(x->polcoef(x,-1)); test(x->polcoef(x,2)); test(x->polcoef(x,10)); polcoef(O(x),0) s=x*(y+O(x))+y; polcoef(s,0,y) polcoef(s,1,y) s=y+O(y^2); polcoef(s,0,x) polcoef(s,1,x) s=1/(1-2*x+O(x^3)) * 1/(1-3*y+O(y^3)); polcoef(s,2,y) vecextract(Vecsmall([3,4,5]),[2,3,1]) vecextract([1], 11) vecextract([1], "1..2") vecextract([1], 1/2) vecextract(1, 1) vecextract(matid(2),[3],[]) [1][2..3] [1][-10..3] 1[1..2] [1/2..1] [1..1/2] pari-2.11.2/src/test/in/size0000644000175000017500000000053413326135265014237 0ustar billbilldefault(realprecision,38) long_is_64 = (#(2^32) == 1); #0. #1 #1. == if (long_is_64==1, 2, 4) length([x]) length(List()) length(List([1,2,3])) length("abc") matsize([1,2,3]) matsize([1,2,3]~) matsize(matrix(2,3)) matsize(1) sizebyte(0) == if (long_is_64, 16, 8) sizebyte(x+1) == if (long_is_64, 80, 40) sizebyte([x,y]) == if (long_is_64, 136, 68) pari-2.11.2/src/test/in/norm0000644000175000017500000000072213201017466014231 0ustar billbillnorml2(-1/2) norml2(quadgen(5)) norml2(quadgen(-3)) normlp(-1, 1) normlp(-1/2, 1) normlp(I, 1) default(realprecision,38); F = [x->normlp(x,1), x->normlp(x,2), x->normlp(x,2.5), normlp]; { for(i=1, #F, my(f = F[i]); print(f); print(f([1,-2,3])); print(f([1,-2;-3,4])); print(f([[1,2],[3,4],5,6])); print(f((1+I) + I*x^2)); print(f(-quadgen(5))); print(f(3+4*I)); ) } normlp([95800,217519,414560], 4) normlp(-1,oo) normlp(-1,-oo) pari-2.11.2/src/test/in/round0000644000175000017500000000055313201017466014407 0ustar billbilldefault(realprecision,38); round((1e-40 + x) / (1e-39 + x)) v=[1,1.6,-4/3,Mod(1,3),quadgen(5),Mod(4/3+x,x^2+1/2),x,4/3+x/3+O(x^2),1/x,[4/3,2],matid(2)/3,""]; test(f)= for(i=1,#v, print(iferr(f(v[i]),E,E))); test(ceil) test(floor) test(frac) test(round) round(0,&E); test(x->[round(x,&e), if(e==E,-oo,e)]) test(truncate) test(x->[truncate(x,&e), if(e==E,-oo,e)]) pari-2.11.2/src/test/in/lift0000644000175000017500000000053213201017466014213 0ustar billbillv=[Mod(y,y^2+1), Mod(1,z), Mod(2,3), 1+O(3)]; T=Pol(v,'x); Z=[1, Mod(5,3), "x", 3+O(3^3), -1/3+O(3), Mod(x,x^2), x*Mod(1,3) + Mod(2,3), (1+2*x+3*x^2+O(x^4))*Mod(1,5)]; F=[lift, a->lift(a,'x), a->lift(a,'y), a->lift(a,'z), centerlift,liftall,liftint,liftpol]; { for(i=1,#F, my (f=F[i]); print(f); for (j=1,#Z, print(f(Z[j]))) ) } pari-2.11.2/src/test/in/subcyclo0000644000175000017500000000004511636712103015077 0ustar billbillpolsubcyclo(8,1) polsubcyclo(1048,2) pari-2.11.2/src/test/in/qfisom0000644000175000017500000000537713326135265014575 0ustar billbillmaxdiag(M)=vecmax(vector(#M,i,M[i,i])); in(M,fl)=if(fl,qfisominit(M,fl),qfisominit(M)); checkauto(M,f,fl)= { my(G=if(f,qfauto(in(M,fl)),if(fl,qfauto(M,fl),qfauto(M)))); for(j=1,#G[2],my(Q=G[2][j]); if(M!=Q~*M*Q ,error(v))); print(G[1]); } checkisom(M,N,f,fl)= { my(Q=if(f==0,if(fl,qfisom(M,N,fl),qfisom(M,N)), f==1,qfisom(in(M,fl),N), f==2,qfisom(in(M,fl),N,,qfauto(N)))); if(Q==0 || M!=Q~*N*Q ,error(N),print("OK")); } qfauto(Mat(1)) M=[4,-2,-1,1,1,-2,-2,-2,-1,-1,-1,-1;-2,4,-1,-2,-2,2,2,0,-1,-1,-1,-1;-1,-1,4,-1,-1,1,1,2,0,0,2,2;1,-2,-1,4,1,-1,-1,0,2,2,-1,-1;1,-2,-1,1,4,-1,-1,-1,1,1,0,0;-2,2,1,-1,-1,4,1,0,-1,-1,-1,-1;-2,2,1,-1,-1,1,4,2,1,1,0,0;-2,0,2,0,-1,0,2,4,2,2,2,2;-1,-1,0,2,1,-1,1,2,4,2,1,0;-1,-1,0,2,1,-1,1,2,2,4,0,1;-1,-1,2,-1,0,-1,0,2,1,0,4,2;-1,-1,2,-1,0,-1,0,2,0,1,2,4]; qfauto(qfisominit(M,,qfminim(M,maxdiag(M))))[1] qfauto(qfisominit(M,,qfminim(M,maxdiag(M))[3]))[1] checkauto(M,0) checkauto(M,0,[1,1]) checkauto(M,1) checkauto(M,1,[1,1]) N1=[2,0,-1,-1,-1,1,0,0,0,0,-1,0,-1,1,0,0;0,2,1,1,1,-1,0,0,-1,1,-1,0,0,0,1,1;-1,1,4,2,2,-2,0,1,1,0,-1,1,-1,1,-1,-1;-1,1,2,4,2,-2,0,1,-1,0,1,1,1,1,1,1;-1,1,2,2,4,-2,0,1,-1,0,-1,1,-1,1,1,1;1,-1,-2,-2,-2,4,-1,0,1,0,1,0,1,-1,-1,-1;0,0,0,0,0,-1,2,-1,-1,0,-1,0,-1,0,1,0;0,0,1,1,1,0,-1,2,1,0,0,1,0,1,-1,0;0,-1,1,-1,-1,1,-1,1,4,0,0,0,0,0,-3,-2;0,1,0,0,0,0,0,0,0,2,-1,0,0,-1,0,0;-1,-1,-1,1,-1,1,-1,0,0,-1,4,0,3,-1,0,0;0,0,1,1,1,0,0,1,0,0,0,2,0,1,0,0;-1,0,-1,1,-1,1,-1,0,0,0,3,0,4,-1,0,1;1,0,1,1,1,-1,0,1,0,-1,-1,1,-1,4,0,0;0,1,-1,1,1,-1,1,-1,-3,0,0,0,0,0,4,2;0,1,-1,1,1,-1,0,0,-2,0,0,0,1,0,2,4]; N2=[6,-4,4,-2,2,-1,1,1,-1,2,1,-2,3,-1,1,0;-4,8,-6,2,-1,0,0,-1,2,-4,0,3,-3,0,-2,-1;4,-6,8,-4,1,1,2,2,-2,5,3,-4,2,1,2,2;-2,2,-4,4,-1,0,-2,-2,1,-3,-3,2,-1,-1,-1,-1;2,-1,1,-1,2,0,1,0,0,1,1,-1,1,0,0,0;-1,0,1,0,0,2,1,0,0,1,1,-1,-1,1,0,1;1,0,2,-2,1,1,4,2,0,2,3,-2,0,1,0,1;1,-1,2,-2,0,0,2,4,-1,1,1,-2,1,0,1,0;-1,2,-2,1,0,0,0,-1,2,-1,0,1,-1,0,0,0;2,-4,5,-3,1,1,2,1,-1,6,4,-3,0,2,1,2;1,0,3,-3,1,1,3,1,0,4,6,-2,-2,2,0,2;-2,3,-4,2,-1,-1,-2,-2,1,-3,-2,4,-1,-1,-1,-1;3,-3,2,-1,1,-1,0,1,-1,0,-2,-1,4,-1,1,-1;-1,0,1,-1,0,1,1,0,0,2,2,-1,-1,2,0,1;1,-2,2,-1,0,0,0,1,0,1,0,-1,1,0,2,0;0,-1,2,-1,0,1,1,0,0,2,2,-1,-1,1,0,2]; checkauto(N1,0) checkauto(N1,0,[1,1]); checkauto(N1,1) checkauto(N1,1,[1,1]); checkisom(N1,N2,0) checkisom(N1,N2,0,[1,1]) checkisom(N1,N2,1) checkisom(N1,N2,1,[1,1]) checkisom(N1,N2,2) L1=[3,-2,-1,1,1;-2,2,0,-1,-1;-1,0,2,1,1;1,-1,1,2,2;1,-1,1,2,3]; L2=matid(5); checkauto(L1,0) checkisom(L1,L2,0) checkauto(L1,1) checkisom(L1,L2,1) checkisom(L1,L2,2) G= [1152,[[-1,0,0,0;0,-1,0,0;0,0,-1,0;0,0,0,-1],[0,0,0,1;0,1,1,0;0,-1,0,0;1,-1,-1,0],[-1,0,0,0;0,0,-1,1;-1,0,1,0;-1,1,1,0]]]; qfautoexport(G) qfautoexport(G,1) Q=qfminim(N1);G=qfauto(N1); apply(length,qforbits(G[2],Q[3])) apply(length,qforbits(G,Q[3])) apply(length,qforbits(G,Q)) pari-2.11.2/src/test/in/eval0000644000175000017500000000005513326135265014212 0ustar billbilleval(Vecsmall([1,2,3])) eval("\\") eval("=") pari-2.11.2/src/test/in/bit0000644000175000017500000000123313036414402014027 0ustar billbillhammingweight(15) hammingweight(x^100 + 2*x + 1) hammingweight([Mod(1,2), 2, Mod(0,3)]) hammingweight(Vecsmall([0,1,2,3])) hammingweight(matid(100)) hammingweight(I) N = 2^128+2^64+1; [bittest(N, i) | i<-[60..70]] { args = [0, 3, -3, 2^65-1, N, -N, I]; funs = [bitand, bitnegimply, bitor, bitxor]; for (a=1,#funs, my (f = funs[a]); print("#", f); for (i=1,#args, for (j=i,#args, my(u=args[i], v=args[j]); print([u,v,iferr(f(u,v),E,E)]) ) ) ); print("#bitneg"); for (i=1, #args, my (u=args[i]); print(iferr([u, bitneg(u,65),bitneg(u)],E,E)) ) } bittest(-1,10) bitneg(-2,64) bitneg(1,-2) bitneg(1,128) pari-2.11.2/src/test/in/bestappr0000644000175000017500000000117713326135265015111 0ustar billbillbestappr(-1./7, 7) bestappr(-1./7, 6) bestappr(Mod(-1/7,100)) bestappr(Mod(-1/7,100), 6) bestappr(Mod(-1/7,100), 7) bestappr(-1/7 + O(5^10)) bestappr(-1/7 + O(5^10), 6) type( bestappr(1+0.*I) ) bestappr(Mod(10,307), 40) bestappr(-1/48.) bestapprPade((x^3+1)/(x^10+2)) bestapprPade((x^3+1)/(x^10+2), 4) bestapprPade(1/(1+x+O(x^10))) bestapprPade(1/(1+x+O(x^10)), 5) bestapprPade(1/(1+x^6+O(x^13)), 5) bestapprPade(1/(1+x^6+O(x^13))) bestapprPade(Mod(x^3+x^2+x+1, x^5-2)) bestapprPade(x^2+x^3+x^4+O(x^5)) bestapprPade(x^-4+x^-3+x^-2+O(x^-1)) bestapprPade(x^10/(1-x)^11+O(x^22)) \\#1945 bestapprPade(Mod((x^5+x+2)/(1-x)^11,x^20),12) \\#1946 pari-2.11.2/src/test/in/version0000644000175000017500000000002013201017466014732 0ustar billbillversion()[1..3] pari-2.11.2/src/test/in/qfsolve0000644000175000017500000025330313201017466014742 0ustar billbill{M=[[-634,-706,-200;-706,527,-110;-200,-110,-997],[-670,164,205;164,-391,-509;205,-509,-117],[586,-448,120;-448,-342,-233;120,-233,-851],[-387,-147,450;-147,-808,-22;450,-22,-119],[739,-44,-48;-44,-739,-134;-48,-134,459],[-519,-45,-514;-45,324,178;-514,178,-83],[-482,-683,18;-683,705,852;18,852,315],[808,-16,555;-16,-723,-538;555,-538,-66],[243,205,-14;205,-119,853;-14,853,891],[-220,10,-564;10,-440,-9;-564,-9,413],[383,66,53;66,-962,-104;53,-104,300],[-845,257,264;257,-7,-866;264,-866,259],[-76,676,371;676,-541,-332;371,-332,-417],[111,-203,-57;-203,-634,-30;-57,-30,275],[-926,-548,-178;-548,483,141;-178,141,-953],[-810,-164,648;-164,-802,-612;648,-612,-274],[818,88,630;88,369,524;630,524,-565],[-165,99,-70;99,83,-716;-70,-716,-493],[-183,56,320;56,509,-931;320,-931,-543],[19,799,-94;799,-866,-658;-94,-658,-604],[-859,-569,525;-569,476,217;525,217,-852],[-527,708,47;708,22,-79;47,-79,902],[360,-425,126;-425,-578,-411;126,-411,581],[2,821,59;821,-893,524;59,524,-788],[470,155,-752;155,-679,-683;-752,-683,-584],[398,107,-644;107,-840,374;-644,374,-274],[-839,8,-410;8,-451,-774;-410,-774,801],[-556,-134,-368;-134,183,566;-368,566,686],[-62,354,-396;354,313,350;-396,350,-891],[518,163,17;163,821,332;17,332,-593],[574,-155,19;-155,424,305;19,305,-978],[-720,873,341;873,-131,-116;341,-116,-414],[417,-39,201;-39,910,-9;201,-9,-538],[-34,-193,-22;-193,-632,362;-22,362,-778],[36,-748,-131;-748,-21,147;-131,147,-143],[-236,-560,-211;-560,803,-632;-211,-632,620],[708,-76,-360;-76,814,248;-360,248,263],[790,-271,-338;-271,-114,-400;-338,-400,-12],[-744,-737,-70;-737,-270,-754;-70,-754,816],[-845,520,141;520,-559,73;141,73,132],[-276,406,-305;406,153,-349;-305,-349,41],[632,62,653;62,-125,439;653,439,-256],[-598,-39,-488;-39,-36,461;-488,461,-506],[406,99,-178;99,747,-99;-178,-99,781],[686,-38,-491;-38,-330,-564;-491,-564,253],[427,69,-615;69,933,215;-615,215,-558],[290,-326,-365;-326,928,208;-365,208,754],[-149,-113,197;-113,877,292;197,292,233],[-701,-265,776;-265,911,-259;776,-259,-531],[81,-169,-170;-169,445,-107;-170,-107,632],[-433,153,215;153,15,-362;215,-362,-77],[-108,10,-734;10,-133,-88;-734,-88,-154],[-48,-365,-68;-365,413,-217;-68,-217,-436],[162,-63,184;-63,-728,-240;184,-240,-845],[-96,-233,-747;-233,951,833;-747,833,-30],[-314,-311,-656;-311,322,-663;-656,-663,-639],[-106,-465,-662;-465,-111,53;-662,53,-97],[-410,166,-445;166,-565,104;-445,104,823],[180,-312,19;-312,984,-10;19,-10,701],[-165,936,-247;936,103,743;-247,743,-414],[-571,451,-527;451,419,-499;-527,-499,-473],[-680,182,651;182,-194,-89;651,-89,-889],[670,75,246;75,72,609;246,609,-58],[-929,-764,508;-764,-984,-405;508,-405,-915],[102,736,116;736,634,722;116,722,-656],[33,214,-533;214,-205,-453;-533,-453,844],[235,270,-692;270,68,-323;-692,-323,729],[945,236,5;236,-506,329;5,329,866],[885,-737,539;-737,908,146;539,146,314],[-179,-252,-29;-252,-966,442;-29,442,-116],[-496,-25,-581;-25,-90,-136;-581,-136,492],[513,432,-290;432,-708,47;-290,47,-933],[364,-386,-310;-386,-460,224;-310,224,-363],[-124,214,795;214,-930,-213;795,-213,818],[69,-552,-189;-552,807,-300;-189,-300,249],[-977,-141,-158;-141,169,199;-158,199,-355],[929,268,383;268,945,618;383,618,943],[177,-329,-78;-329,-953,216;-78,216,644],[-335,-314,-76;-314,-572,-229;-76,-229,-214],[609,-226,65;-226,578,271;65,271,-938],[962,-213,483;-213,-159,383;483,383,473],[-821,-501,368;-501,-602,489;368,489,461],[-636,-385,597;-385,-913,903;597,903,849],[967,350,-825;350,352,475;-825,475,974],[-982,7,98;7,-563,-840;98,-840,-726],[-504,81,-124;81,-470,191;-124,191,-846],[756,273,253;273,932,348;253,348,331],[52,-645,783;-645,-606,-565;783,-565,918],[22,-781,-238;-781,-382,-637;-238,-637,-618],[-405,497,-397;497,-489,-593;-397,-593,-916],[-856,5,85;5,-866,-24;85,-24,-540],[764,-153,9;-153,362,-127;9,-127,-1000],[-551,-637,624;-637,-864,361;624,361,12],[-522,203,-199;203,-239,-581;-199,-581,-228],[724,644,245;644,71,456;245,456,983],[-369,-142,164;-142,-644,302;164,302,580],[-485,-786,-362;-786,-207,-326;-362,-326,-257],[373,-271,514;-271,734,390;514,390,-410],[-223,-301,32;-301,-480,-549;32,-549,358],[-501,82,-557;82,609,-296;-557,-296,962];[394,-209,-606,-399;-209,-552,157,-626;-606,157,144,-188;-399,-626,-188,293],[-870,-559,-338,-156;-559,931,293,-7;-338,293,-920,46;-156,-7,46,-563],[703,435,-32,-310;435,-313,103,-144;-32,103,-262,64;-310,-144,64,-769],[523,481,141,-252;481,-291,-403,7;141,-403,-625,-556;-252,7,-556,847],[473,331,-38,-36;331,-346,-409,58;-38,-409,-864,-20;-36,58,-20,-299],[847,138,609,-195;138,-215,232,-257;609,232,953,220;-195,-257,220,63],[544,-494,56,-441;-494,-73,154,-847;56,154,-427,565;-441,-847,565,-503],[-548,200,253,353;200,-582,142,278;253,142,-514,-577;353,278,-577,-555],[-954,-835,-720,-541;-835,-642,116,74;-720,116,-939,168;-541,74,168,32],[-921,16,-253,-807;16,559,-16,-401;-253,-16,604,591;-807,-401,591,848],[-184,326,-437,151;326,-560,373,-103;-437,373,-913,-731;151,-103,-731,735],[637,57,-209,785;57,708,463,-909;-209,463,197,-275;785,-909,-275,751],[901,175,-364,245;175,14,141,811;-364,141,-104,-499;245,811,-499,-705],[-184,942,-258,171;942,-149,-629,366;-258,-629,-935,216;171,366,216,986],[661,647,-235,-432;647,-176,177,192;-235,177,-123,379;-432,192,379,-760],[-957,440,-161,-888;440,2,-148,-48;-161,-148,-598,-743;-888,-48,-743,550],[959,720,-158,225;720,-588,-46,258;-158,-46,530,-753;225,258,-753,367],[291,-64,-481,-53;-64,829,386,305;-481,386,638,213;-53,305,213,22],[949,-74,304,129;-74,-143,-673,-167;304,-673,545,-43;129,-167,-43,-485],[217,861,-669,-333;861,884,-12,675;-669,-12,110,-540;-333,675,-540,67],[957,-415,416,493;-415,862,148,-308;416,148,453,-253;493,-308,-253,-822],[-838,-392,-57,-288;-392,-83,130,323;-57,130,87,199;-288,323,199,-464],[-43,256,-625,-195;256,-320,362,1;-625,362,-611,-142;-195,1,-142,-538],[-524,-608,-260,-17;-608,-211,-123,-438;-260,-123,633,-264;-17,-438,-264,659],[139,-93,776,-239;-93,384,67,-639;776,67,-561,-645;-239,-639,-645,895],[704,-399,-485,-425;-399,-519,748,163;-485,748,-182,-274;-425,163,-274,834],[67,-693,-88,664;-693,987,39,-62;-88,39,-915,-327;664,-62,-327,-434],[-901,102,-239,-270;102,-311,-212,591;-239,-212,771,-105;-270,591,-105,502],[-58,-876,422,-195;-876,-105,-761,-819;422,-761,-760,379;-195,-819,379,117],[995,22,48,-495;22,519,368,-411;48,368,-925,720;-495,-411,720,632],[445,-738,-222,299;-738,-786,-232,-352;-222,-232,-619,-341;299,-352,-341,81],[-490,495,1,-342;495,-222,192,608;1,192,6,-412;-342,608,-412,-723],[684,-101,124,-102;-101,395,-184,413;124,-184,-731,14;-102,413,14,-945],[102,-118,-635,-737;-118,-652,37,575;-635,37,-879,-84;-737,575,-84,748],[732,-244,-50,270;-244,-277,53,574;-50,53,-224,683;270,574,683,223],[466,-48,-330,-472;-48,-834,699,-489;-330,699,-318,745;-472,-489,745,859],[252,72,115,248;72,-846,11,-645;115,11,289,281;248,-645,281,-276],[270,537,-17,345;537,289,-338,489;-17,-338,429,-701;345,489,-701,-214],[731,812,-291,-457;812,-9,-77,294;-291,-77,217,156;-457,294,156,-646],[246,160,-739,53;160,560,-7,437;-739,-7,-803,13;53,437,13,4],[789,-415,-730,436;-415,905,-467,34;-730,-467,97,-35;436,34,-35,128],[111,120,-205,-83;120,358,-58,284;-205,-58,-131,-463;-83,284,-463,825],[96,-218,-174,-75;-218,-200,378,201;-174,378,-221,-29;-75,201,-29,169],[841,-443,244,834;-443,-46,774,-48;244,774,188,194;834,-48,194,-966],[-622,430,-699,-145;430,-977,30,-116;-699,30,-781,-447;-145,-116,-447,452],[787,-20,-232,-250;-20,-50,310,-314;-232,310,-106,422;-250,-314,422,-894],[17,275,-251,-497;275,-581,-179,196;-251,-179,-643,-558;-497,196,-558,-114],[-867,-236,-249,300;-236,318,-308,237;-249,-308,721,-321;300,237,-321,531],[738,575,-59,145;575,721,-480,442;-59,-480,592,170;145,442,170,-757],[201,121,-379,162;121,-469,-132,378;-379,-132,-272,309;162,378,309,-280],[908,109,-209,-921;109,-203,495,371;-209,495,350,240;-921,371,240,-571],[93,29,-738,-360;29,-715,287,-725;-738,287,-523,-109;-360,-725,-109,16],[-97,-86,131,-369;-86,231,-168,30;131,-168,-751,-484;-369,30,-484,-399],[-815,-360,-481,-48;-360,320,326,191;-481,326,555,548;-48,191,548,-707],[96,235,-680,612;235,748,-74,-298;-680,-74,-648,-670;612,-298,-670,622],[-39,-344,297,-252;-344,834,-77,41;297,-77,-60,-279;-252,41,-279,645],[914,196,209,-238;196,-7,44,447;209,44,16,-194;-238,447,-194,-632],[-314,163,756,341;163,982,-61,288;756,-61,706,-76;341,288,-76,-321],[-492,-316,-59,-350;-316,-861,-647,-270;-59,-647,837,-90;-350,-270,-90,-629],[-565,450,97,156;450,984,-271,-315;97,-271,583,-40;156,-315,-40,-110],[-496,-37,98,-453;-37,-152,-81,-349;98,-81,-811,-292;-453,-349,-292,-688],[953,281,-556,904;281,311,-557,-644;-556,-557,845,100;904,-644,100,-359],[-643,497,-310,-229;497,-925,172,255;-310,172,-151,350;-229,255,350,854],[863,150,318,-30;150,-522,-464,-274;318,-464,-942,-256;-30,-274,-256,228],[-211,493,-509,-6;493,215,344,-548;-509,344,227,-727;-6,-548,-727,-682],[-276,-9,204,515;-9,-80,-2,-211;204,-2,-842,43;515,-211,43,543],[-169,669,215,22;669,92,370,18;215,370,684,123;22,18,123,707],[-577,-130,-286,-189;-130,-529,-189,-770;-286,-189,381,-12;-189,-770,-12,-169],[952,-268,40,545;-268,-710,-236,196;40,-236,-559,-115;545,196,-115,571],[418,132,-154,278;132,928,116,-122;-154,116,538,-528;278,-122,-528,37],[782,83,-31,351;83,-662,-39,-609;-31,-39,-414,-249;351,-609,-249,215],[318,532,-172,-248;532,-783,-399,10;-172,-399,-877,823;-248,10,823,-748],[-68,233,-456,-484;233,225,-375,455;-456,-375,-324,188;-484,455,188,-250],[-684,-179,65,466;-179,647,-392,-1;65,-392,-222,292;466,-1,292,-251],[-592,447,-605,51;447,-233,430,67;-605,430,-573,-263;51,67,-263,-506],[-43,308,-326,-746;308,-241,-537,-197;-326,-537,-407,34;-746,-197,34,112],[112,95,137,533;95,317,807,711;137,807,4,26;533,711,26,-792],[755,-108,121,-537;-108,-730,-485,-202;121,-485,753,29;-537,-202,29,965],[-54,235,113,192;235,320,-837,-258;113,-837,398,-498;192,-258,-498,683],[-852,55,-567,102;55,612,-594,460;-567,-594,29,-501;102,460,-501,-213],[4,-100,473,-28;-100,202,64,48;473,64,-593,-616;-28,48,-616,-834],[-692,-666,531,-306;-666,559,49,-619;531,49,-390,-730;-306,-619,-730,324],[-641,-381,108,62;-381,118,-110,-194;108,-110,697,329;62,-194,329,-869],[281,752,-869,350;752,-545,-169,138;-869,-169,782,-376;350,138,-376,97],[-58,647,-85,391;647,-968,459,-166;-85,459,469,323;391,-166,323,-104],[-20,728,757,569;728,531,530,-500;757,530,-47,101;569,-500,101,-500],[-980,413,-81,602;413,647,118,30;-81,118,-787,-709;602,30,-709,582],[518,-59,335,247;-59,-184,460,-518;335,460,510,-216;247,-518,-216,-7],[762,-305,724,-25;-305,-328,805,414;724,805,-942,-83;-25,414,-83,-88],[388,-318,-111,416;-318,146,-678,742;-111,-678,35,543;416,742,543,891],[402,5,-176,845;5,-56,-427,-745;-176,-427,217,196;845,-745,196,363],[981,159,-168,186;159,760,-718,816;-168,-718,356,-245;186,816,-245,244],[495,-302,243,-33;-302,-118,97,-204;243,97,20,192;-33,-204,192,153],[954,-725,339,422;-725,-4,-230,712;339,-230,-57,-11;422,712,-11,-690],[765,-702,29,-644;-702,789,-366,75;29,-366,49,-479;-644,75,-479,575],[-62,381,327,631;381,577,-512,-672;327,-512,146,158;631,-672,158,126],[-947,541,87,-893;541,-495,-41,-665;87,-41,861,60;-893,-665,60,175],[-910,488,-479,-431;488,991,143,229;-479,143,783,-356;-431,229,-356,-333],[846,-356,-144,-336;-356,888,-228,-471;-144,-228,-194,-647;-336,-471,-647,-724],[-10,454,119,65;454,468,-597,260;119,-597,567,-110;65,260,-110,106];[-564,568,485,513,7;568,-526,612,-346,460;485,612,183,-757,-36;513,-346,-757,-536,505;7,460,-36,505,693],[-379,-94,-635,347,-257;-94,-489,84,-418,229;-635,84,361,-107,-17;347,-418,-107,-48,-715;-257,229,-17,-715,-966],[533,-388,15,340,-489;-388,-366,-37,-836,-93;15,-37,627,328,-271;340,-836,328,-576,-812;-489,-93,-271,-812,-769],[-518,-276,-221,336,787;-276,307,463,342,374;-221,463,-417,499,428;336,342,499,-572,-117;787,374,428,-117,-648],[-63,-268,835,-443,-432;-268,-811,713,-136,-363;835,713,58,151,791;-443,-136,151,-517,-412;-432,-363,791,-412,104],[-95,-786,24,-81,-432;-786,744,139,312,251;24,139,423,298,479;-81,312,298,-672,-239;-432,251,479,-239,9],[888,-546,-211,69,-50;-546,220,59,432,76;-211,59,454,552,432;69,432,552,283,-368;-50,76,432,-368,614],[-164,-64,-626,247,-567;-64,116,-387,584,-334;-626,-387,555,-430,553;247,584,-430,213,-966;-567,-334,553,-966,929],[626,493,-33,391,-355;493,868,-572,193,394;-33,-572,252,-258,-172;391,193,-258,-822,349;-355,394,-172,349,359],[-554,412,-131,31,507;412,794,-428,-31,44;-131,-428,683,-157,330;31,-31,-157,-780,464;507,44,330,464,-750],[45,210,831,-678,-52;210,-539,157,219,-94;831,157,452,698,-380;-678,219,698,-203,-513;-52,-94,-380,-513,-221],[148,-171,-445,202,659;-171,-531,551,-48,-440;-445,551,502,18,-69;202,-48,18,240,-437;659,-440,-69,-437,-778],[-544,-88,-52,-34,-341;-88,238,517,527,306;-52,517,-192,403,79;-34,527,403,210,471;-341,306,79,471,781],[463,-680,-929,668,294;-680,-264,682,-498,864;-929,682,-503,-903,-562;668,-498,-903,438,-217;294,864,-562,-217,-58],[-66,-495,-201,-401,-128;-495,171,570,-139,-745;-201,570,614,-566,356;-401,-139,-566,-818,-797;-128,-745,356,-797,967],[-768,345,73,-335,-489;345,-478,52,211,-100;73,52,94,0,264;-335,211,0,619,-695;-489,-100,264,-695,447],[-239,-24,198,-123,-152;-24,374,-611,-425,-191;198,-611,589,-615,336;-123,-425,-615,26,-782;-152,-191,336,-782,950],[-336,670,8,196,86;670,857,144,-710,-682;8,144,648,-21,854;196,-710,-21,936,923;86,-682,854,923,-368],[-536,235,-207,-112,-499;235,-391,-900,106,189;-207,-900,346,-359,581;-112,106,-359,-461,-341;-499,189,581,-341,269],[-264,431,731,73,-190;431,-513,-131,-101,-23;731,-131,-223,119,245;73,-101,119,-553,511;-190,-23,245,511,530],[943,-212,171,-448,-45;-212,-613,286,-453,-603;171,286,-36,-8,-134;-448,-453,-8,-452,-372;-45,-603,-134,-372,-610],[434,-204,457,47,-340;-204,-163,705,327,49;457,705,-463,-555,-40;47,327,-555,-996,-402;-340,49,-40,-402,421],[202,-242,-953,-143,-284;-242,161,225,-197,-828;-953,225,151,-407,808;-143,-197,-407,535,348;-284,-828,808,348,-688],[-668,725,-427,528,330;725,813,-586,-488,209;-427,-586,951,107,-254;528,-488,107,2,-472;330,209,-254,-472,294],[-839,-247,50,445,-82;-247,114,-527,-150,-201;50,-527,-504,-233,96;445,-150,-233,863,697;-82,-201,96,697,254],[-975,-683,-223,410,591;-683,-56,-133,-592,424;-223,-133,-633,174,-339;410,-592,174,453,-286;591,424,-339,-286,-850],[69,75,609,39,182;75,36,292,587,251;609,292,-678,151,-196;39,587,151,-906,-435;182,251,-196,-435,948],[-102,251,-928,478,-2;251,-622,449,-307,-166;-928,449,-832,512,0;478,-307,512,925,491;-2,-166,0,491,646],[14,768,-575,216,555;768,-196,422,772,-823;-575,422,-373,684,305;216,772,684,904,569;555,-823,305,569,15],[741,-172,99,-82,-553;-172,-787,573,320,225;99,573,-672,-740,569;-82,320,-740,-198,-943;-553,225,569,-943,-413],[-981,21,38,19,43;21,-55,-303,568,243;38,-303,-376,-55,-721;19,568,-55,83,-402;43,243,-721,-402,943],[710,97,-685,411,71;97,-324,773,-582,597;-685,773,-692,393,-204;411,-582,393,410,11;71,597,-204,11,-238],[-765,404,-10,-80,251;404,-195,2,167,304;-10,2,369,328,308;-80,167,328,-859,-281;251,304,308,-281,151],[126,584,513,334,-25;584,-358,-99,27,329;513,-99,793,-106,195;334,27,-106,-532,-18;-25,329,195,-18,617],[732,-546,81,-379,-399;-546,-205,79,19,-73;81,79,987,-435,575;-379,19,-435,999,-90;-399,-73,575,-90,-341],[-373,-891,190,539,327;-891,-997,-89,185,433;190,-89,778,-1,-337;539,185,-1,394,-141;327,433,-337,-141,281],[-624,102,-778,200,-350;102,-748,-333,146,-243;-778,-333,-10,90,145;200,146,90,-728,146;-350,-243,145,146,-166],[-848,-806,255,240,283;-806,373,744,858,404;255,744,-504,55,-867;240,858,55,950,101;283,404,-867,101,427],[302,-557,-629,100,8;-557,-627,502,60,226;-629,502,-812,748,352;100,60,748,658,330;8,226,352,330,-252],[280,575,579,-515,257;575,-355,-201,203,163;579,-201,689,-540,58;-515,203,-540,737,-342;257,163,58,-342,485],[491,353,76,-533,337;353,756,-358,-237,105;76,-358,-301,350,-232;-533,-237,350,905,558;337,105,-232,558,616],[-594,299,-104,-275,37;299,883,503,695,592;-104,503,-275,199,248;-275,695,199,21,-32;37,592,248,-32,692],[-79,448,106,323,-45;448,-967,649,351,400;106,649,-458,-435,275;323,351,-435,-117,-759;-45,400,275,-759,-165],[-740,-85,540,-27,244;-85,-934,472,575,171;540,472,-947,476,550;-27,575,476,-582,566;244,171,550,566,-509],[831,-113,-331,92,-472;-113,89,110,-295,93;-331,110,338,665,-273;92,-295,665,-754,558;-472,93,-273,558,-883],[277,-733,-472,67,638;-733,170,-229,160,-805;-472,-229,510,-61,-135;67,160,-61,-89,-231;638,-805,-135,-231,769],[567,517,-261,-38,357;517,386,2,777,226;-261,2,590,-394,-296;-38,777,-394,188,-236;357,226,-296,-236,209],[-697,-632,494,513,-241;-632,95,-245,487,100;494,-245,-37,0,15;513,487,0,717,-33;-241,100,15,-33,440],[-474,-135,-35,-406,-241;-135,-128,402,-26,-170;-35,402,-933,-41,-138;-406,-26,-41,791,-167;-241,-170,-138,-167,-286],[-854,-121,-48,-570,419;-121,-59,22,-196,368;-48,22,-194,-258,-46;-570,-196,-258,497,6;419,368,-46,6,-124],[-306,470,671,-322,41;470,988,-964,131,193;671,-964,-218,175,378;-322,131,175,470,-50;41,193,378,-50,506],[478,-324,-581,89,540;-324,-885,-57,-600,-464;-581,-57,785,-69,-182;89,-600,-69,-595,157;540,-464,-182,157,-322],[-724,62,466,-176,570;62,-735,181,-420,-19;466,181,53,-293,-14;-176,-420,-293,-990,344;570,-19,-14,344,-771],[-429,13,-134,543,-175;13,-200,-702,291,-202;-134,-702,684,-389,321;543,291,-389,-510,189;-175,-202,321,189,-713],[919,83,-70,309,-566;83,-977,402,-190,-312;-70,402,-829,-533,106;309,-190,-533,-306,-35;-566,-312,106,-35,-599],[-620,-223,29,-150,-213;-223,248,497,-768,-305;29,497,-657,798,0;-150,-768,798,930,30;-213,-305,0,30,-51],[-965,53,-98,155,195;53,-349,634,225,948;-98,634,-847,125,573;155,225,125,33,507;195,948,573,507,-390],[-526,338,50,394,607;338,435,-100,590,403;50,-100,-480,-228,792;394,590,-228,-377,-478;607,403,792,-478,514],[-293,280,-137,60,247;280,-6,116,-506,177;-137,116,-906,764,452;60,-506,764,-420,275;247,177,452,275,294],[307,490,-31,-208,347;490,-456,726,-453,113;-31,726,-892,450,-532;-208,-453,450,-393,-230;347,113,-532,-230,-417],[700,408,-90,-330,249;408,325,-344,-6,64;-90,-344,608,358,-550;-330,-6,358,342,388;249,64,-550,388,628],[-668,-7,558,-90,3;-7,805,67,158,8;558,67,178,-635,401;-90,158,-635,-163,-413;3,8,401,-413,-501],[-940,319,-177,-311,170;319,-588,749,843,403;-177,749,-134,-381,-577;-311,843,-381,-709,-161;170,403,-577,-161,995],[458,-800,-2,-551,-101;-800,-832,477,-256,329;-2,477,384,-263,183;-551,-256,-263,800,-468;-101,329,183,-468,-321],[-198,-129,-271,347,-584;-129,182,36,-962,-226;-271,36,-274,-336,-522;347,-962,-336,456,-115;-584,-226,-522,-115,557],[360,283,902,651,-69;283,-673,-326,-867,39;902,-326,199,130,582;651,-867,130,471,37;-69,39,582,37,796],[-795,-20,-143,-308,554;-20,-521,609,174,563;-143,609,-539,44,159;-308,174,44,122,-707;554,563,159,-707,-584],[-885,550,178,-421,145;550,-413,-180,-757,578;178,-180,-501,208,345;-421,-757,208,-882,136;145,578,345,136,-705],[188,552,-114,248,-867;552,-594,-348,266,-172;-114,-348,-428,604,242;248,266,604,617,-81;-867,-172,242,-81,867],[702,361,239,-502,172;361,-932,-89,-486,-789;239,-89,991,91,349;-502,-486,91,447,280;172,-789,349,280,-236],[-717,-249,-608,-505,97;-249,-222,-65,157,505;-608,-65,-796,697,614;-505,157,697,187,139;97,505,614,139,-747],[829,126,59,-147,-5;126,-239,-261,-327,475;59,-261,-13,-210,-417;-147,-327,-210,594,-249;-5,475,-417,-249,637],[710,116,-118,709,285;116,-847,-351,28,-535;-118,-351,-348,232,-256;709,28,232,479,-382;285,-535,-256,-382,906],[-383,-85,563,-666,563;-85,924,974,356,211;563,974,14,250,-510;-666,356,250,458,166;563,211,-510,166,753],[-968,18,-75,638,-462;18,-37,79,-504,-92;-75,79,-543,72,253;638,-504,72,-896,929;-462,-92,253,929,-319],[614,-856,-127,541,-245;-856,-676,816,-940,-298;-127,816,-220,-522,140;541,-940,-522,878,581;-245,-298,140,581,245],[-85,-34,-122,-478,-115;-34,-759,-367,-193,603;-122,-367,605,276,79;-478,-193,276,798,508;-115,603,79,508,592],[-333,-138,-112,-263,179;-138,817,756,-48,391;-112,756,969,-731,752;-263,-48,-731,156,-321;179,391,752,-321,-712],[477,249,-294,-37,336;249,440,-302,622,-527;-294,-302,-692,-319,-269;-37,622,-319,685,-541;336,-527,-269,-541,-967],[-873,138,-286,-799,317;138,779,-78,13,-300;-286,-78,394,24,61;-799,13,24,-578,-441;317,-300,61,-441,178],[731,432,388,128,763;432,-160,-144,-97,24;388,-144,888,330,135;128,-97,330,-884,-301;763,24,135,-301,-902],[903,29,435,-334,522;29,876,526,26,449;435,526,-16,162,27;-334,26,162,-659,-382;522,449,27,-382,262],[-379,-816,431,-196,-632;-816,-939,-65,-621,111;431,-65,254,247,-416;-196,-621,247,-377,-50;-632,111,-416,-50,493],[-140,-350,-271,364,-657;-350,-321,-101,-87,-648;-271,-101,117,-376,-616;364,-87,-376,-331,26;-657,-648,-616,26,-793],[-846,962,-39,798,-742;962,-844,404,123,562;-39,404,-536,44,-729;798,123,44,-552,71;-742,562,-729,71,-458],[-943,-160,-175,148,-289;-160,625,624,-87,123;-175,624,-198,-23,-459;148,-87,-23,-854,291;-289,123,-459,291,119],[125,24,-75,172,605;24,-192,-385,707,129;-75,-385,-106,-110,-81;172,707,-110,179,239;605,129,-81,239,-216],[329,-86,307,-776,-546;-86,818,256,100,-332;307,256,-805,-398,321;-776,100,-398,-761,-576;-546,-332,321,-576,-2],[934,-696,-129,-171,-99;-696,-882,385,-535,-707;-129,385,488,305,8;-171,-535,305,-27,465;-99,-707,8,465,-329],[-279,11,260,-35,-333;11,175,-854,-246,-126;260,-854,-31,487,43;-35,-246,487,-775,195;-333,-126,43,195,-956],[-999,613,-166,-58,808;613,-518,-574,-664,416;-166,-574,-387,313,95;-58,-664,313,872,-34;808,416,95,-34,851],[-746,-456,-738,326,418;-456,418,848,62,483;-738,848,-980,104,-547;326,62,104,118,-18;418,483,-547,-18,301],[268,-302,-195,725,103;-302,-931,-885,812,-278;-195,-885,-3,-572,-280;725,812,-572,719,867;103,-278,-280,867,551],[544,230,-284,344,-698;230,-593,-370,-322,576;-284,-370,-979,-118,-9;344,-322,-118,942,714;-698,576,-9,714,-851],[301,-368,-694,45,212;-368,388,110,-530,-364;-694,110,271,-9,418;45,-530,-9,-838,-239;212,-364,418,-239,-448],[-243,224,27,249,337;224,317,-432,-383,133;27,-432,-681,779,-89;249,-383,779,844,405;337,133,-89,405,138],[481,61,-452,385,-156;61,-549,-691,-389,-36;-452,-691,597,345,-685;385,-389,345,-748,598;-156,-36,-685,598,-745],[-586,846,126,-357,704;846,-840,746,-6,203;126,746,673,-556,-262;-357,-6,-556,556,-206;704,203,-262,-206,663],[796,-218,-314,-352,214;-218,-973,649,-525,410;-314,649,-108,-642,-177;-352,-525,-642,139,-568;214,410,-177,-568,-655],[540,393,834,299,-166;393,153,35,109,150;834,35,-660,-529,569;299,109,-529,695,558;-166,150,569,558,989];[250,623,394,139,394,-485;623,950,605,-643,19,-311;394,605,-188,799,386,-600;139,-643,799,248,659,-616;394,19,386,659,236,-145;-485,-311,-600,-616,-145,-743],[899,543,-487,324,-284,-752;543,-305,-138,-108,-66,-360;-487,-138,-936,121,573,506;324,-108,121,164,-5,-438;-284,-66,573,-5,-878,151;-752,-360,506,-438,151,-891],[-349,136,-393,659,-232,488;136,42,806,279,327,313;-393,806,687,588,-121,223;659,279,588,109,-205,714;-232,327,-121,-205,684,-747;488,313,223,714,-747,192],[932,463,-748,68,-150,-264;463,-444,384,866,726,125;-748,384,-31,-160,804,179;68,866,-160,-498,159,-183;-150,726,804,159,794,463;-264,125,179,-183,463,-507],[519,132,272,-150,56,-96;132,451,38,560,-365,190;272,38,-686,135,-238,-510;-150,560,135,353,-129,240;56,-365,-238,-129,571,-256;-96,190,-510,240,-256,-627],[-694,137,-268,131,-429,-201;137,-130,-69,-39,-130,336;-268,-69,622,-515,174,453;131,-39,-515,-333,165,-316;-429,-130,174,165,853,836;-201,336,453,-316,836,-31],[920,-703,166,174,-451,124;-703,-651,56,297,-34,-24;166,56,530,148,14,516;174,297,148,503,317,82;-451,-34,14,317,934,350;124,-24,516,82,350,-921],[284,333,-642,510,563,441;333,909,442,561,-372,-319;-642,442,72,684,46,-802;510,561,684,-936,-48,285;563,-372,46,-48,546,221;441,-319,-802,285,221,-149],[556,-200,75,-156,529,264;-200,-689,-314,98,-144,-60;75,-314,110,-517,-399,81;-156,98,-517,768,471,706;529,-144,-399,471,-607,134;264,-60,81,706,134,-336],[-31,76,-13,412,-442,-71;76,-179,-306,469,-82,-107;-13,-306,-505,162,71,253;412,469,162,-376,190,231;-442,-82,71,190,-374,-517;-71,-107,253,231,-517,467],[-52,334,-360,-86,-466,80;334,478,43,-203,500,-33;-360,43,294,417,-590,-507;-86,-203,417,305,772,480;-466,500,-590,772,-476,180;80,-33,-507,480,180,-603],[-534,-134,-366,388,-656,-393;-134,-847,565,-148,372,137;-366,565,-550,-68,-262,-716;388,-148,-68,-832,254,162;-656,372,-262,254,-795,47;-393,137,-716,162,47,870],[-49,385,306,-659,479,-423;385,811,-288,5,608,-839;306,-288,-851,-383,-206,117;-659,5,-383,-936,408,569;479,608,-206,408,-438,-203;-423,-839,117,569,-203,-584],[138,-137,32,189,-635,168;-137,-782,19,-224,-133,-523;32,19,726,-57,271,-138;189,-224,-57,-884,-565,-630;-635,-133,271,-565,-305,529;168,-523,-138,-630,529,390],[-875,-791,-144,511,108,-164;-791,-59,-596,6,-520,534;-144,-596,-721,355,201,-129;511,6,355,738,-58,-318;108,-520,201,-58,-41,436;-164,534,-129,-318,436,-743],[457,540,-477,847,412,-89;540,-196,305,841,20,176;-477,305,293,-290,-627,-747;847,841,-290,-962,-147,33;412,20,-627,-147,-651,824;-89,176,-747,33,824,-472],[440,36,42,-257,307,556;36,112,-417,496,-199,298;42,-417,-624,417,395,195;-257,496,417,291,407,142;307,-199,395,407,-724,-167;556,298,195,142,-167,486],[-56,311,800,-536,-91,451;311,724,-120,403,159,339;800,-120,-169,-600,304,-562;-536,403,-600,-444,-404,-475;-91,159,304,-404,886,163;451,339,-562,-475,163,701],[831,-9,-193,250,-259,-177;-9,-279,-447,671,-344,243;-193,-447,119,250,-220,-13;250,671,250,-404,359,-171;-259,-344,-220,359,-77,-141;-177,243,-13,-171,-141,-71],[-290,-385,-7,232,300,-595;-385,715,544,-108,-746,-590;-7,544,365,-105,-187,-159;232,-108,-105,-923,582,334;300,-746,-187,582,-281,651;-595,-590,-159,334,651,322],[-907,229,-390,78,347,-413;229,945,-480,151,-738,711;-390,-480,-89,-188,-693,6;78,151,-188,656,-586,443;347,-738,-693,-586,-751,-396;-413,711,6,443,-396,-17],[-915,-17,591,161,16,-448;-17,177,300,723,326,0;591,300,489,-680,-591,279;161,723,-680,-119,-371,-937;16,326,-591,-371,-724,-244;-448,0,279,-937,-244,-270],[-376,-205,333,-491,171,364;-205,968,120,251,-80,-334;333,120,-33,-346,-517,-757;-491,251,-346,-74,-261,618;171,-80,-517,-261,-537,169;364,-334,-757,618,169,-464],[-158,-435,-280,29,549,-51;-435,-742,427,308,817,-432;-280,427,-317,544,472,-361;29,308,544,-951,256,35;549,817,472,256,907,284;-51,-432,-361,35,284,460],[-497,-300,-715,433,44,-341;-300,296,-76,-900,-319,-644;-715,-76,239,710,-30,-232;433,-900,710,-780,25,-612;44,-319,-30,25,-91,677;-341,-644,-232,-612,677,963],[-483,-373,254,58,112,-472;-373,781,-720,645,432,442;254,-720,227,145,719,-242;58,645,145,-265,-308,-19;112,432,719,-308,-110,305;-472,442,-242,-19,305,-641],[426,717,-190,194,600,-397;717,-324,392,98,238,68;-190,392,-313,316,-723,535;194,98,316,721,419,483;600,238,-723,419,-820,9;-397,68,535,483,9,737],[-682,519,-724,-204,-606,-348;519,-484,299,23,-49,-319;-724,299,-794,342,-498,36;-204,23,342,276,611,332;-606,-49,-498,611,-962,-432;-348,-319,36,332,-432,-955],[971,-610,-29,-607,146,-692;-610,-906,-177,217,536,-522;-29,-177,398,-61,49,-333;-607,217,-61,-421,-69,-21;146,536,49,-69,578,754;-692,-522,-333,-21,754,-889],[137,612,379,731,-89,149;612,-706,-257,-698,507,290;379,-257,110,407,455,260;731,-698,407,659,82,-404;-89,507,455,82,-618,-136;149,290,260,-404,-136,-790],[714,-226,-159,177,-129,450;-226,381,-254,-349,-409,95;-159,-254,-961,129,446,-302;177,-349,129,-396,-198,-214;-129,-409,446,-198,415,-123;450,95,-302,-214,-123,415],[141,699,-683,-890,449,-692;699,-533,-356,293,-166,268;-683,-356,-473,32,-16,151;-890,293,32,-183,240,335;449,-166,-16,240,-534,-122;-692,268,151,335,-122,266],[-307,377,889,-520,-105,-446;377,900,305,302,43,297;889,305,-834,187,-880,294;-520,302,187,-446,-649,-515;-105,43,-880,-649,662,-387;-446,297,294,-515,-387,-570],[-526,-630,488,-512,101,-657;-630,212,-529,-261,-16,7;488,-529,429,172,105,-875;-512,-261,172,-720,172,230;101,-16,105,172,724,-11;-657,7,-875,230,-11,833],[704,840,-58,-261,667,-482;840,-160,90,-382,-89,462;-58,90,-133,59,281,-62;-261,-382,59,-485,784,4;667,-89,281,784,-563,67;-482,462,-62,4,67,-634],[-462,-146,772,494,397,834;-146,174,23,377,15,528;772,23,-445,-144,116,-225;494,377,-144,660,-471,-251;397,15,116,-471,455,-443;834,528,-225,-251,-443,580],[-48,-185,267,-414,206,-165;-185,592,-46,269,84,-306;267,-46,251,-64,-640,82;-414,269,-64,878,-529,-361;206,84,-640,-529,840,48;-165,-306,82,-361,48,929],[376,830,212,-693,32,-372;830,-39,37,-397,140,74;212,37,384,-533,621,577;-693,-397,-533,492,348,-103;32,140,621,348,-107,169;-372,74,577,-103,169,-106],[-460,583,225,-2,687,55;583,724,294,-832,17,-361;225,294,-714,86,-234,272;-2,-832,86,-598,199,-81;687,17,-234,199,-370,-394;55,-361,272,-81,-394,-16],[-352,-297,28,362,-321,-290;-297,972,10,227,-145,526;28,10,-794,-10,397,305;362,227,-10,-94,-400,-430;-321,-145,397,-400,869,352;-290,526,305,-430,352,-93],[-699,-128,29,418,-137,946;-128,-946,293,336,152,-100;29,293,473,-603,233,-260;418,336,-603,883,882,-183;-137,152,233,882,248,-197;946,-100,-260,-183,-197,-688],[696,-143,489,-228,405,549;-143,-919,749,-176,-471,-816;489,749,-221,-272,598,671;-228,-176,-272,652,-51,-6;405,-471,598,-51,563,-734;549,-816,671,-6,-734,360],[-521,405,92,352,-158,-111;405,-696,-361,115,-444,-459;92,-361,871,142,267,-36;352,115,142,905,253,-199;-158,-444,267,253,-320,189;-111,-459,-36,-199,189,-46],[-790,367,117,-43,175,409;367,654,131,-823,-37,377;117,131,89,-14,-185,-317;-43,-823,-14,963,241,767;175,-37,-185,241,-141,-149;409,377,-317,767,-149,811],[-250,666,475,-73,701,-21;666,-136,214,213,-718,185;475,214,-42,456,177,-302;-73,213,456,191,15,231;701,-718,177,15,-331,-490;-21,185,-302,231,-490,-339],[-20,-312,-255,12,-45,123;-312,415,-415,311,-577,424;-255,-415,700,229,-535,222;12,311,229,763,-800,986;-45,-577,-535,-800,784,-45;123,424,222,986,-45,689],[85,-623,-81,-82,440,358;-623,-864,244,108,-61,210;-81,244,-158,46,215,-33;-82,108,46,-955,-36,-402;440,-61,215,-36,-236,-879;358,210,-33,-402,-879,-70],[-750,-192,-92,279,-99,-155;-192,658,-202,628,-366,-563;-92,-202,194,203,38,335;279,628,203,-276,-149,-27;-99,-366,38,-149,550,-79;-155,-563,335,-27,-79,-310],[959,206,-23,-249,793,256;206,-19,-578,284,-8,539;-23,-578,318,-396,292,538;-249,284,-396,394,581,112;793,-8,292,581,721,-371;256,539,538,112,-371,-869],[157,372,-914,641,146,-734;372,-704,130,631,250,466;-914,130,-789,526,675,-252;641,631,526,-341,155,93;146,250,675,155,-321,-845;-734,466,-252,93,-845,18],[408,179,-258,-35,370,-745;179,753,-494,-183,-725,512;-258,-494,255,447,-200,-648;-35,-183,447,912,596,125;370,-725,-200,596,-262,250;-745,512,-648,125,250,-767],[770,-730,289,36,-314,-199;-730,259,-746,740,286,-508;289,-746,580,251,-401,103;36,740,251,764,372,167;-314,286,-401,372,-269,-853;-199,-508,103,167,-853,-34],[-579,325,661,-348,645,-729;325,433,871,801,221,-631;661,871,846,-124,27,433;-348,801,-124,-251,-990,-97;645,221,27,-990,-957,-618;-729,-631,433,-97,-618,-373],[221,204,482,-309,-150,-760;204,-265,-487,-295,26,-244;482,-487,-961,-108,-113,405;-309,-295,-108,-800,-369,-21;-150,26,-113,-369,122,475;-760,-244,405,-21,475,347],[-820,32,-50,356,-705,-243;32,-651,543,121,-684,-186;-50,543,186,-247,656,-244;356,121,-247,350,100,247;-705,-684,656,100,-680,906;-243,-186,-244,247,906,-469],[431,-287,357,-430,-130,373;-287,-248,500,113,895,-59;357,500,60,-576,82,192;-430,113,-576,-478,-772,369;-130,895,82,-772,-462,268;373,-59,192,369,268,-734],[-352,-378,98,-49,374,623;-378,-999,197,68,266,180;98,197,701,-208,-129,-412;-49,68,-208,863,-117,442;374,266,-129,-117,-518,694;623,180,-412,442,694,501],[924,168,-46,550,41,84;168,608,-653,-514,-201,693;-46,-653,-744,751,158,-75;550,-514,751,-549,143,-563;41,-201,158,143,-564,-356;84,693,-75,-563,-356,731],[993,644,-32,-19,-163,372;644,467,-377,297,387,-321;-32,-377,920,76,-455,808;-19,297,76,649,-450,71;-163,387,-455,-450,284,-158;372,-321,808,71,-158,529],[246,248,608,-198,-18,405;248,-359,243,479,-563,-14;608,243,-109,140,314,98;-198,479,140,488,264,321;-18,-563,314,264,-853,-387;405,-14,98,321,-387,616],[-637,-606,-12,-32,902,-41;-606,912,162,-371,-284,-739;-12,162,-909,-711,34,-326;-32,-371,-711,379,-626,151;902,-284,34,-626,-716,125;-41,-739,-326,151,125,-764],[-538,-632,-235,904,480,53;-632,-156,-336,-342,82,-172;-235,-336,-24,123,129,-444;904,-342,123,-125,-151,83;480,82,129,-151,70,-48;53,-172,-444,83,-48,-537],[497,-860,-57,197,-237,-131;-860,-312,-391,202,329,550;-57,-391,139,165,49,578;197,202,165,-771,580,131;-237,329,49,580,643,164;-131,550,578,131,164,-341],[-735,583,120,164,-565,-76;583,-174,-174,389,-674,-180;120,-174,464,375,-454,-451;164,389,375,-605,-317,-821;-565,-674,-454,-317,456,-456;-76,-180,-451,-821,-456,-373],[687,580,851,459,139,-93;580,-476,-912,455,-605,381;851,-912,-532,663,140,-736;459,455,663,665,-312,223;139,-605,140,-312,-724,-185;-93,381,-736,223,-185,132],[160,-532,608,-331,-600,60;-532,613,853,310,296,44;608,853,35,54,212,-7;-331,310,54,519,480,33;-600,296,212,480,293,689;60,44,-7,33,689,266],[579,4,-562,-731,175,-782;4,318,392,468,-568,-563;-562,392,-891,348,256,7;-731,468,348,327,-178,-422;175,-568,256,-178,837,-723;-782,-563,7,-422,-723,-238],[-739,453,742,543,-791,-417;453,793,169,-102,-156,-188;742,169,-17,108,-351,-553;543,-102,108,-599,-18,195;-791,-156,-351,-18,-223,-114;-417,-188,-553,195,-114,-322],[-678,-308,-290,52,175,14;-308,-988,-705,135,-705,-532;-290,-705,-291,-494,-87,-725;52,135,-494,-500,-506,-189;175,-705,-87,-506,-943,-583;14,-532,-725,-189,-583,995],[-837,134,-213,-67,200,104;134,-490,-400,635,199,-255;-213,-400,682,59,-221,322;-67,635,59,-797,284,-399;200,199,-221,284,881,577;104,-255,322,-399,577,477],[555,14,-887,-202,695,528;14,-927,330,-314,375,-391;-887,330,-134,464,446,346;-202,-314,464,-313,345,363;695,375,446,345,-79,-184;528,-391,346,363,-184,780],[422,58,282,210,-461,94;58,796,706,258,588,-301;282,706,-838,-252,291,-204;210,258,-252,-718,-112,414;-461,588,291,-112,-480,-630;94,-301,-204,414,-630,-889],[-256,759,-214,685,465,-315;759,-944,538,57,-482,299;-214,538,307,640,-137,403;685,57,640,-235,367,213;465,-482,-137,367,188,33;-315,299,403,213,33,-175],[-880,-536,-590,-111,127,-279;-536,749,-180,-387,331,44;-590,-180,-735,-445,347,-44;-111,-387,-445,704,-43,-22;127,331,347,-43,-197,215;-279,44,-44,-22,215,-766],[356,180,416,168,658,-14;180,-229,-316,-408,-834,-724;416,-316,408,-197,-218,-406;168,-408,-197,-754,88,429;658,-834,-218,88,-244,587;-14,-724,-406,429,587,-556],[-968,504,-302,-234,-393,667;504,-948,-680,598,-100,770;-302,-680,-94,-419,135,-350;-234,598,-419,-386,303,350;-393,-100,135,303,-116,69;667,770,-350,350,69,411],[385,259,177,46,13,120;259,-467,445,-398,210,189;177,445,560,58,-26,560;46,-398,58,-874,224,63;13,210,-26,224,-628,156;120,189,560,63,156,-497],[-124,429,577,-223,-36,405;429,343,-398,-302,448,-48;577,-398,920,304,768,570;-223,-302,304,-55,-415,-71;-36,448,768,-415,906,-490;405,-48,570,-71,-490,-330],[714,684,-730,-19,290,-210;684,-984,59,256,72,280;-730,59,-122,46,-7,936;-19,256,46,-177,-697,-104;290,72,-7,-697,-812,502;-210,280,936,-104,502,956],[-835,240,277,73,220,448;240,921,286,617,309,52;277,286,3,202,21,42;73,617,202,966,233,-318;220,309,21,233,540,-165;448,52,42,-318,-165,-601],[826,58,-448,7,570,254;58,-803,-45,327,496,-321;-448,-45,753,861,396,313;7,327,861,-277,-240,-484;570,496,396,-240,-350,605;254,-321,313,-484,605,477],[-847,-687,565,-182,719,62;-687,299,138,-496,-38,-438;565,138,256,-156,416,41;-182,-496,-156,-816,580,-533;719,-38,416,580,610,118;62,-438,41,-533,118,-910],[-646,-187,760,489,-95,91;-187,-112,-162,-729,-435,-220;760,-162,-249,197,65,180;489,-729,197,-196,-9,250;-95,-435,65,-9,245,520;91,-220,180,250,520,682],[368,-508,-170,198,508,-43;-508,-900,203,-730,-33,-499;-170,203,-192,-47,151,-75;198,-730,-47,82,-271,-61;508,-33,151,-271,324,737;-43,-499,-75,-61,737,417],[982,350,-168,63,808,-314;350,372,-245,-844,427,-780;-168,-245,350,195,122,322;63,-844,195,-138,-112,434;808,427,122,-112,-418,460;-314,-780,322,434,460,-548],[-754,146,14,154,313,436;146,798,668,499,-626,241;14,668,-954,-68,372,386;154,499,-68,-798,619,-444;313,-626,372,619,588,-121;436,241,386,-444,-121,-831],[-822,-100,-182,39,-913,-73;-100,-374,-379,-64,254,-58;-182,-379,-974,-473,-71,-805;39,-64,-473,-169,335,-471;-913,254,-71,335,320,-419;-73,-58,-805,-471,-419,-161],[-649,-296,877,-659,-394,522;-296,804,-65,456,87,-811;877,-65,931,365,284,113;-659,456,365,73,-174,184;-394,87,284,-174,920,498;522,-811,113,184,498,-483],[288,-408,-114,771,519,-372;-408,-362,-282,565,-94,-137;-114,-282,180,-813,-311,-227;771,565,-813,-306,175,-422;519,-94,-311,175,438,5;-372,-137,-227,-422,5,76],[-298,145,-880,-215,268,-450;145,390,415,-316,-284,-189;-880,415,-89,-21,615,-306;-215,-316,-21,486,576,-214;268,-284,615,576,456,258;-450,-189,-306,-214,258,132],[453,260,-81,-494,-121,164;260,-679,662,-549,-175,625;-81,662,-590,-494,144,349;-494,-549,-494,-510,144,-489;-121,-175,144,144,355,546;164,625,349,-489,546,-822],[-326,-26,-165,-218,342,-278;-26,961,-454,-298,-621,-509;-165,-454,927,-413,-84,-789;-218,-298,-413,603,478,709;342,-621,-84,478,549,-67;-278,-509,-789,709,-67,-356],[888,443,211,186,-204,-166;443,518,339,768,635,-52;211,339,626,-115,854,-179;186,768,-115,910,278,-208;-204,635,854,278,-616,663;-166,-52,-179,-208,663,-371],[13,149,-183,503,388,145;149,174,-481,287,-14,744;-183,-481,11,487,209,73;503,287,487,421,469,-933;388,-14,209,469,463,-219;145,744,73,-933,-219,945],[996,129,-245,-267,-30,-569;129,-399,-692,96,-24,70;-245,-692,508,-256,-412,-59;-267,96,-256,-3,286,-96;-30,-24,-412,286,-964,131;-569,70,-59,-96,131,677],[-568,492,-797,-185,-77,-181;492,-608,237,-143,488,270;-797,237,-19,834,473,-442;-185,-143,834,74,-505,714;-77,488,473,-505,-343,-615;-181,270,-442,714,-615,-168],[825,-302,-377,296,221,542;-302,166,174,-89,44,-213;-377,174,-190,195,-711,26;296,-89,195,425,388,190;221,44,-711,388,669,-69;542,-213,26,190,-69,-292],[302,-942,-32,-165,458,115;-942,-9,-21,447,-412,346;-32,-21,728,-513,-514,-422;-165,447,-513,477,390,315;458,-412,-514,390,173,-532;115,346,-422,315,-532,-499],[370,599,-62,-34,-115,57;599,319,433,423,358,-417;-62,433,-994,-74,147,-352;-34,423,-74,886,128,-472;-115,358,147,128,976,-150;57,-417,-352,-472,-150,-775],[946,-23,-247,-316,628,-800;-23,4,290,-227,-567,-930;-247,290,-403,-185,-505,162;-316,-227,-185,-181,485,2;628,-567,-505,485,603,-833;-800,-930,162,2,-833,382];[-657,218,-1,-499,774,297,-562;218,670,298,71,678,450,417;-1,298,-906,345,-505,-13,146;-499,71,345,-163,-45,-350,-9;774,678,-505,-45,464,68,-744;297,450,-13,-350,68,883,-33;-562,417,146,-9,-744,-33,-653],[-651,277,-344,-557,-100,-5,30;277,173,742,649,426,637,138;-344,742,349,-680,182,-76,-124;-557,649,-680,727,235,513,882;-100,426,182,235,252,-194,-8;-5,637,-76,513,-194,-40,-555;30,138,-124,882,-8,-555,984],[-278,169,-928,416,-189,-786,198;169,-688,123,604,-852,-286,421;-928,123,495,-55,-54,172,149;416,604,-55,156,-103,-362,215;-189,-852,-54,-103,-976,80,67;-786,-286,172,-362,80,-328,445;198,421,149,215,67,445,517],[753,310,-161,167,18,192,-314;310,-549,163,639,67,-150,664;-161,163,871,155,248,-423,194;167,639,155,589,-765,-850,-131;18,67,248,-765,-223,-49,-580;192,-150,-423,-850,-49,-803,440;-314,664,194,-131,-580,440,-791],[-898,-426,-688,-411,-129,-434,-26;-426,287,-618,-166,355,-45,-437;-688,-618,-43,-143,394,-406,-272;-411,-166,-143,-714,548,-679,-178;-129,355,394,548,792,348,291;-434,-45,-406,-679,348,338,-506;-26,-437,-272,-178,291,-506,-872],[-669,-536,-125,567,-808,511,-118;-536,197,84,-11,-443,627,-430;-125,84,286,499,-314,9,-34;567,-11,499,-476,11,-699,-53;-808,-443,-314,11,935,18,261;511,627,9,-699,18,634,11;-118,-430,-34,-53,261,11,-169],[-379,96,11,-80,-343,-385,-744;96,681,62,-343,-10,-240,-9;11,62,-642,-767,183,-421,-800;-80,-343,-767,-259,73,-665,-382;-343,-10,183,73,761,-111,-300;-385,-240,-421,-665,-111,195,-170;-744,-9,-800,-382,-300,-170,662],[876,196,80,-115,-372,220,206;196,343,477,60,-128,751,-298;80,477,256,433,496,-477,143;-115,60,433,522,345,-800,338;-372,-128,496,345,-362,86,575;220,751,-477,-800,86,697,123;206,-298,143,338,575,123,-616],[-205,-318,175,-27,-488,270,-295;-318,-753,-278,-529,199,-352,787;175,-278,-968,-412,450,198,602;-27,-529,-412,778,285,-105,941;-488,199,450,285,455,-842,-66;270,-352,198,-105,-842,380,-103;-295,787,602,941,-66,-103,-790],[-462,-521,403,76,-219,-161,-546;-521,-472,179,-303,552,606,-494;403,179,-991,-245,514,337,133;76,-303,-245,-514,87,-233,31;-219,552,514,87,561,151,462;-161,606,337,-233,151,-74,16;-546,-494,133,31,462,16,-631],[505,53,-114,-406,664,319,-243;53,-983,-393,166,-180,-68,-172;-114,-393,-995,-463,-266,127,-821;-406,166,-463,262,13,36,150;664,-180,-266,13,423,42,-635;319,-68,127,36,42,968,480;-243,-172,-821,150,-635,480,-782],[302,-223,276,-96,85,-138,-263;-223,-793,-501,-293,422,529,382;276,-501,-943,207,514,-70,771;-96,-293,207,586,11,338,756;85,422,514,11,120,-390,411;-138,529,-70,338,-390,-419,302;-263,382,771,756,411,302,481],[335,-465,13,-133,-195,16,593;-465,-737,108,-543,-28,-65,-2;13,108,-416,881,-60,863,225;-133,-543,881,-122,-191,-803,463;-195,-28,-60,-191,69,190,312;16,-65,863,-803,190,-573,-331;593,-2,225,463,312,-331,561],[557,-886,-442,139,-237,575,-334;-886,-165,-99,-578,-587,250,123;-442,-99,20,-206,398,-509,-613;139,-578,-206,696,-250,476,52;-237,-587,398,-250,543,-176,742;575,250,-509,476,-176,-668,162;-334,123,-613,52,742,162,-72],[-256,738,-236,-81,521,512,-67;738,300,67,62,-520,34,235;-236,67,780,-469,140,-228,-247;-81,62,-469,-822,502,649,-368;521,-520,140,502,333,-809,84;512,34,-228,649,-809,-75,657;-67,235,-247,-368,84,657,483],[254,-269,69,341,-754,473,147;-269,660,-699,-134,-24,-67,-45;69,-699,35,-307,-16,-47,-528;341,-134,-307,438,342,-610,-74;-754,-24,-16,342,526,-721,646;473,-67,-47,-610,-721,-454,127;147,-45,-528,-74,646,127,-659],[-407,581,-416,67,66,-379,187;581,633,417,225,-352,62,-64;-416,417,85,-214,722,488,518;67,225,-214,-15,95,265,-36;66,-352,722,95,709,98,-614;-379,62,488,265,98,977,-111;187,-64,518,-36,-614,-111,-144],[168,-149,226,-257,-324,-242,256;-149,-395,-559,7,-415,305,667;226,-559,-737,263,-112,-876,431;-257,7,263,-693,-145,436,617;-324,-415,-112,-145,-8,848,-685;-242,305,-876,436,848,-331,-33;256,667,431,617,-685,-33,781],[-493,150,-108,-195,-30,-562,-557;150,-58,-320,79,-129,-456,191;-108,-320,82,441,-625,151,-112;-195,79,441,625,505,134,188;-30,-129,-625,505,113,788,-446;-562,-456,151,134,788,931,52;-557,191,-112,188,-446,52,-693],[-257,20,262,-274,5,446,-284;20,734,-134,-390,-164,378,335;262,-134,990,643,-3,411,-69;-274,-390,643,398,612,218,-65;5,-164,-3,612,443,634,-337;446,378,411,218,634,200,-841;-284,335,-69,-65,-337,-841,340],[-414,-84,167,142,7,298,-197;-84,-576,795,356,596,289,368;167,795,-594,250,428,-7,44;142,356,250,-481,-357,527,-336;7,596,428,-357,-906,-321,140;298,289,-7,527,-321,804,408;-197,368,44,-336,140,408,668],[35,557,-451,383,189,-443,-533;557,832,995,177,-357,273,139;-451,995,-184,442,40,-357,348;383,177,442,226,-487,-215,-284;189,-357,40,-487,398,-83,151;-443,273,-357,-215,-83,-241,-542;-533,139,348,-284,151,-542,831],[956,-222,-121,-224,-8,-422,-439;-222,965,799,-60,127,808,-458;-121,799,548,-769,25,-235,42;-224,-60,-769,-396,350,-309,433;-8,127,25,350,879,276,339;-422,808,-235,-309,276,-39,-29;-439,-458,42,433,339,-29,-717],[-747,583,508,-311,-22,-100,-176;583,558,777,487,25,626,-218;508,777,446,33,-254,-526,-197;-311,487,33,-865,942,-591,-153;-22,25,-254,942,-566,-310,192;-100,626,-526,-591,-310,750,59;-176,-218,-197,-153,192,59,-920],[667,-531,-248,620,-72,-156,-279;-531,665,-153,-237,-231,91,265;-248,-153,-1,306,-352,-492,202;620,-237,306,-891,-340,1,618;-72,-231,-352,-340,779,68,764;-156,91,-492,1,68,137,33;-279,265,202,618,764,33,653],[386,163,-387,-254,-208,-40,737;163,-296,-546,225,-17,99,-15;-387,-546,571,-72,-895,-100,291;-254,225,-72,-195,-222,478,-592;-208,-17,-895,-222,318,-708,-336;-40,99,-100,478,-708,-883,-148;737,-15,291,-592,-336,-148,-698],[431,-211,-112,160,-3,841,366;-211,198,79,-453,-183,223,183;-112,79,243,-204,480,168,-648;160,-453,-204,169,-80,-52,-341;-3,-183,480,-80,-577,274,55;841,223,168,-52,274,-702,-478;366,183,-648,-341,55,-478,928],[431,21,-4,646,197,366,-363;21,48,904,207,-20,476,597;-4,904,-660,754,211,347,407;646,207,754,-647,-10,-39,387;197,-20,211,-10,726,-372,2;366,476,347,-39,-372,-308,274;-363,597,407,387,2,274,77],[709,192,222,174,-105,-173,364;192,-471,-174,-116,-107,338,-4;222,-174,-911,256,118,-443,412;174,-116,256,781,249,-525,-98;-105,-107,118,249,-658,-81,-154;-173,338,-443,-525,-81,854,719;364,-4,412,-98,-154,719,739],[708,-639,135,400,-524,462,384;-639,-711,90,-302,-496,858,-220;135,90,929,324,212,876,-833;400,-302,324,525,335,-20,-493;-524,-496,212,335,67,491,399;462,858,876,-20,491,640,249;384,-220,-833,-493,399,249,421],[-365,216,-176,275,9,-248,-76;216,459,-334,167,121,427,255;-176,-334,-151,146,-879,-846,-181;275,167,146,-387,-162,149,24;9,121,-879,-162,402,768,560;-248,427,-846,149,768,-290,-195;-76,255,-181,24,560,-195,-123],[-225,283,143,-512,790,-529,-203;283,-405,91,328,236,451,-197;143,91,707,294,-156,-39,413;-512,328,294,-517,641,-27,630;790,236,-156,641,892,474,-414;-529,451,-39,-27,474,494,728;-203,-197,413,630,-414,728,445],[293,247,547,-187,-63,-225,-510;247,525,-182,861,-350,482,515;547,-182,-140,-139,-91,-749,303;-187,861,-139,-856,-402,-307,-198;-63,-350,-91,-402,-432,-406,-440;-225,482,-749,-307,-406,665,-243;-510,515,303,-198,-440,-243,313],[431,282,150,482,-570,-252,294;282,224,240,90,-700,-554,-81;150,240,-516,-74,62,373,328;482,90,-74,-313,189,-54,-730;-570,-700,62,189,402,-26,-282;-252,-554,373,-54,-26,-709,-683;294,-81,328,-730,-282,-683,110],[-174,143,517,614,-145,-362,-519;143,741,383,-381,22,-514,-678;517,383,849,-409,-496,-56,497;614,-381,-409,659,-347,340,736;-145,22,-496,-347,526,296,137;-362,-514,-56,340,296,648,95;-519,-678,497,736,137,95,-934],[318,-645,275,-730,-326,633,107;-645,-247,-156,-53,116,-511,-162;275,-156,-630,-570,262,-343,526;-730,-53,-570,-631,690,329,-312;-326,116,262,690,-455,-207,-152;633,-511,-343,329,-207,-711,-496;107,-162,526,-312,-152,-496,-417],[-101,-812,-33,66,-774,363,378;-812,681,-71,-263,-128,747,547;-33,-71,641,531,613,-531,-99;66,-263,531,579,167,-450,0;-774,-128,613,167,638,-645,-153;363,747,-531,-450,-645,304,-43;378,547,-99,0,-153,-43,408],[-386,189,698,382,-278,-611,609;189,-601,2,-478,344,261,301;698,2,710,-587,-393,-304,255;382,-478,-587,98,-652,-87,87;-278,344,-393,-652,-788,-168,-508;-611,261,-304,-87,-168,792,-22;609,301,255,87,-508,-22,672],[1,-104,-86,40,-647,816,-352;-104,406,-81,-537,493,80,-435;-86,-81,-284,-66,554,-623,680;40,-537,-66,-356,29,-443,248;-647,493,554,29,746,138,685;816,80,-623,-443,138,424,34;-352,-435,680,248,685,34,922],[-682,-50,318,-106,241,743,-780;-50,926,20,385,-582,626,237;318,20,-374,-88,-69,-122,-824;-106,385,-88,-49,-469,390,398;241,-582,-69,-469,-978,-624,-206;743,626,-122,390,-624,557,538;-780,237,-824,398,-206,538,868],[-910,-842,182,171,273,-403,17;-842,737,478,-363,723,319,-225;182,478,99,507,-469,54,-186;171,-363,507,427,-128,271,-239;273,723,-469,-128,-682,-455,-389;-403,319,54,271,-455,712,-162;17,-225,-186,-239,-389,-162,892],[-364,164,-488,-562,-12,-482,416;164,652,-86,436,180,-102,20;-488,-86,-351,-471,-252,346,250;-562,436,-471,758,516,-14,163;-12,180,-252,516,204,-524,-219;-482,-102,346,-14,-524,306,101;416,20,250,163,-219,101,-523],[-916,-771,265,-35,-501,783,587;-771,-632,15,187,687,-308,-32;265,15,103,-346,-254,91,89;-35,187,-346,707,-63,14,436;-501,687,-254,-63,440,-502,-91;783,-308,91,14,-502,405,-182;587,-32,89,436,-91,-182,-450],[-53,-809,-515,-200,44,-145,326;-809,-948,512,-124,-898,-316,322;-515,512,936,153,-148,-146,206;-200,-124,153,959,-152,-321,7;44,-898,-148,-152,71,-76,-786;-145,-316,-146,-321,-76,817,-700;326,322,206,7,-786,-700,-662],[-302,67,-462,263,105,8,292;67,327,-823,-42,-113,527,30;-462,-823,417,55,860,-10,425;263,-42,55,173,281,-394,122;105,-113,860,281,-854,-221,-99;8,527,-10,-394,-221,227,-182;292,30,425,122,-99,-182,-346],[-119,795,-290,-384,121,-469,430;795,-552,645,-722,-394,-170,51;-290,645,600,-222,12,-297,117;-384,-722,-222,-454,-223,-475,-789;121,-394,12,-223,-411,321,529;-469,-170,-297,-475,321,-873,182;430,51,117,-789,529,182,-349],[117,509,-692,-458,-347,-602,203;509,279,-346,393,-879,798,-496;-692,-346,-973,97,-705,-283,62;-458,393,97,-21,-167,-709,-206;-347,-879,-705,-167,-400,-300,-501;-602,798,-283,-709,-300,-803,-620;203,-496,62,-206,-501,-620,920],[975,303,-34,653,-515,-128,-160;303,-703,-62,-749,-24,-40,-108;-34,-62,-391,-85,254,-713,-443;653,-749,-85,597,298,-433,-134;-515,-24,254,298,-460,738,375;-128,-40,-713,-433,738,312,487;-160,-108,-443,-134,375,487,-620],[-981,789,214,562,462,-166,172;789,-829,323,554,-240,35,-524;214,323,491,-355,881,-401,74;562,554,-355,639,-211,10,80;462,-240,881,-211,-383,-868,100;-166,35,-401,10,-868,-229,-605;172,-524,74,80,100,-605,-209],[429,863,-528,200,-44,-239,687;863,-427,684,-810,364,101,-64;-528,684,-196,102,247,-284,-142;200,-810,102,-89,-719,-163,137;-44,364,247,-719,775,-524,247;-239,101,-284,-163,-524,-630,37;687,-64,-142,137,247,37,766],[442,-92,461,-146,-273,75,326;-92,721,243,-13,-137,49,325;461,243,-944,-341,-654,63,-261;-146,-13,-341,-232,-147,518,-381;-273,-137,-654,-147,-976,366,-674;75,49,63,518,366,835,584;326,325,-261,-381,-674,584,-946],[458,294,-391,31,-493,233,-911;294,-262,327,-369,388,-85,-94;-391,327,491,-2,275,45,-40;31,-369,-2,-769,-802,-38,108;-493,388,275,-802,65,-592,706;233,-85,45,-38,-592,696,-294;-911,-94,-40,108,706,-294,419],[991,340,-589,-442,-22,210,897;340,258,-15,-71,-366,29,-201;-589,-15,-888,148,149,-278,246;-442,-71,148,-834,-182,-161,-222;-22,-366,149,-182,-625,-676,111;210,29,-278,-161,-676,38,342;897,-201,246,-222,111,342,798],[736,29,739,-519,-41,174,-774;29,-184,24,-309,826,9,-527;739,24,135,-420,306,589,353;-519,-309,-420,-441,-63,-146,-272;-41,826,306,-63,-953,-569,-297;174,9,589,-146,-569,652,-511;-774,-527,353,-272,-297,-511,-479],[-109,587,6,96,377,-33,-97;587,-609,-191,364,-276,-540,-52;6,-191,500,-21,158,-698,249;96,364,-21,746,-2,-430,-804;377,-276,158,-2,498,-389,626;-33,-540,-698,-430,-389,968,-594;-97,-52,249,-804,626,-594,216],[-571,-349,-384,108,271,604,-1;-349,-949,-190,-891,-93,-143,173;-384,-190,652,-74,-346,-159,618;108,-891,-74,-925,-782,-1,345;271,-93,-346,-782,-244,496,485;604,-143,-159,-1,496,724,166;-1,173,618,345,485,166,604],[-613,73,540,200,372,355,166;73,-962,190,-582,-117,-596,393;540,190,155,18,-327,-89,762;200,-582,18,805,-3,529,-308;372,-117,-327,-3,-604,-88,-450;355,-596,-89,529,-88,679,-111;166,393,762,-308,-450,-111,-247],[330,524,-107,-556,-84,57,783;524,663,-148,373,685,-204,405;-107,-148,-216,104,-264,471,51;-556,373,104,-862,97,-167,-661;-84,685,-264,97,261,745,-393;57,-204,471,-167,745,785,54;783,405,51,-661,-393,54,436],[977,-115,278,768,-817,-844,183;-115,287,178,-402,-558,-397,-558;278,178,-402,123,-708,158,-99;768,-402,123,140,-676,245,-9;-817,-558,-708,-676,985,228,187;-844,-397,158,245,228,-950,129;183,-558,-99,-9,187,129,-905],[-418,19,223,349,-143,561,784;19,200,-698,444,18,633,39;223,-698,-923,-365,419,-71,-104;349,444,-365,-116,64,-278,348;-143,18,419,64,-115,-772,526;561,633,-71,-278,-772,-62,360;784,39,-104,348,526,360,495],[-996,-141,409,84,635,-241,327;-141,607,111,-622,154,-49,-450;409,111,-233,-522,114,-388,-35;84,-622,-522,-496,-648,-210,-180;635,154,114,-648,178,-530,-75;-241,-49,-388,-210,-530,-505,-88;327,-450,-35,-180,-75,-88,505],[-505,-167,448,452,616,-300,473;-167,978,237,580,-364,334,104;448,237,948,74,-536,-860,-344;452,580,74,926,-758,31,581;616,-364,-536,-758,-472,-269,300;-300,334,-860,31,-269,464,-374;473,104,-344,581,300,-374,536],[-924,506,-147,-140,841,-163,-94;506,899,168,-373,-132,-214,618;-147,168,701,-230,-200,100,-632;-140,-373,-230,-86,122,-541,-169;841,-132,-200,122,815,874,-462;-163,-214,100,-541,874,521,521;-94,618,-632,-169,-462,521,998],[960,-103,392,192,-61,280,-369;-103,122,-804,-260,-197,314,76;392,-804,348,161,568,-213,10;192,-260,161,634,166,-222,738;-61,-197,568,166,574,179,-130;280,314,-213,-222,179,354,-241;-369,76,10,738,-130,-241,754],[844,283,407,-361,-784,-629,-443;283,895,-741,377,552,545,-356;407,-741,-446,713,-37,-642,-95;-361,377,713,-706,-509,790,-129;-784,552,-37,-509,929,-216,831;-629,545,-642,790,-216,-381,126;-443,-356,-95,-129,831,126,864],[-44,-613,-265,-59,-454,86,-523;-613,695,-185,100,70,-185,261;-265,-185,516,-915,-514,-305,-183;-59,100,-915,-479,673,-599,9;-454,70,-514,673,-97,147,443;86,-185,-305,-599,147,-52,171;-523,261,-183,9,443,171,40],[615,-292,734,37,350,511,-512;-292,394,773,-557,158,-754,212;734,773,466,406,412,519,-125;37,-557,406,964,117,-569,99;350,158,412,117,-131,-741,134;511,-754,519,-569,-741,-996,32;-512,212,-125,99,134,32,34],[-355,-682,-504,-263,483,226,392;-682,-581,45,142,631,-117,-233;-504,45,334,327,765,-196,-286;-263,142,327,-785,367,98,-324;483,631,765,367,482,-40,468;226,-117,-196,98,-40,151,495;392,-233,-286,-324,468,495,-171],[-691,-179,-303,319,211,-212,59;-179,-148,-340,-622,-170,332,323;-303,-340,-233,52,734,-50,-470;319,-622,52,-522,-204,344,-554;211,-170,734,-204,753,37,133;-212,332,-50,344,37,704,260;59,323,-470,-554,133,260,-214],[-430,244,-408,98,568,-419,-263;244,-498,-523,854,-242,436,573;-408,-523,761,-390,554,-762,-188;98,854,-390,526,196,-723,-193;568,-242,554,196,-930,-118,-299;-419,436,-762,-723,-118,-244,409;-263,573,-188,-193,-299,409,-954],[-735,487,539,-167,200,167,212;487,-195,356,-722,-42,338,77;539,356,37,-497,723,-74,388;-167,-722,-497,-702,-357,-134,-83;200,-42,723,-357,-229,-666,547;167,338,-74,-134,-666,482,-26;212,77,388,-83,547,-26,-699],[-560,-459,8,-566,424,-163,266;-459,40,251,-484,847,-77,-806;8,251,-120,431,23,-32,-17;-566,-484,431,114,-392,-411,-456;424,847,23,-392,492,-92,-128;-163,-77,-32,-411,-92,-644,47;266,-806,-17,-456,-128,47,-358],[-616,38,400,782,-451,-560,243;38,641,-945,-72,-426,-80,-308;400,-945,493,161,150,652,-130;782,-72,161,-182,-392,99,236;-451,-426,150,-392,-164,-7,155;-560,-80,652,99,-7,114,-744;243,-308,-130,236,155,-744,558],[-987,-215,49,-444,-384,-381,-367;-215,-468,61,-421,541,86,432;49,61,21,-308,862,-435,239;-444,-421,-308,-762,-189,62,-520;-384,541,862,-189,33,-358,-566;-381,86,-435,62,-358,-652,504;-367,432,239,-520,-566,504,223],[122,769,689,-167,-441,471,-585;769,217,-172,-209,-408,-284,370;689,-172,-762,714,380,131,-200;-167,-209,714,228,-157,153,-664;-441,-408,380,-157,70,476,-347;471,-284,131,153,476,-505,-284;-585,370,-200,-664,-347,-284,-925],[-435,-265,190,-229,366,212,-510;-265,972,-244,142,-542,304,-272;190,-244,492,-69,-610,555,-292;-229,142,-69,110,-380,-179,-362;366,-542,-610,-380,-600,-228,-80;212,304,555,-179,-228,-465,-65;-510,-272,-292,-362,-80,-65,-722],[-177,-233,784,85,183,-223,-84;-233,817,78,344,391,559,-496;784,78,839,224,330,371,230;85,344,224,-278,412,-272,197;183,391,330,412,639,-809,-132;-223,559,371,-272,-809,109,454;-84,-496,230,197,-132,454,-8],[466,393,20,79,-620,-613,-319;393,48,32,520,13,38,-394;20,32,-607,-369,-263,-144,701;79,520,-369,-666,399,-87,536;-620,13,-263,399,-198,640,-619;-613,38,-144,-87,640,-184,751;-319,-394,701,536,-619,751,-506],[-102,-407,-405,-138,-542,-43,669;-407,955,-156,256,-752,-475,-266;-405,-156,759,54,272,-562,123;-138,256,54,555,-155,-458,520;-542,-752,272,-155,432,678,-187;-43,-475,-562,-458,678,-679,863;669,-266,123,520,-187,863,999],[336,672,-224,-42,-744,803,26;672,-74,-277,402,-180,-131,-288;-224,-277,28,-862,-359,-183,-623;-42,402,-862,-49,-396,-288,-147;-744,-180,-359,-396,-399,401,425;803,-131,-183,-288,401,-523,402;26,-288,-623,-147,425,402,671],[343,302,451,869,-728,461,469;302,-479,-552,-94,99,335,343;451,-552,123,137,-22,-150,371;869,-94,137,-567,29,107,749;-728,99,-22,29,-921,126,78;461,335,-150,107,126,-967,774;469,343,371,749,78,774,-392],[304,146,-18,-752,-8,-481,-790;146,133,175,113,212,-370,-62;-18,175,-586,-334,-677,353,-505;-752,113,-334,-440,-592,431,180;-8,212,-677,-592,79,282,350;-481,-370,353,431,282,569,262;-790,-62,-505,180,350,262,725],[-892,304,-153,-826,-17,209,-21;304,-228,-16,751,167,590,495;-153,-16,339,94,-287,-176,-335;-826,751,94,759,-44,338,-62;-17,167,-287,-44,823,-262,72;209,590,-176,338,-262,166,-551;-21,495,-335,-62,72,-551,267],[858,408,-336,620,83,95,247;408,-973,229,-540,326,126,153;-336,229,379,-102,-37,-334,-233;620,-540,-102,51,-72,-782,372;83,326,-37,-72,778,-571,863;95,126,-334,-782,-571,884,101;247,153,-233,372,863,101,292],[805,581,525,-453,374,-453,64;581,665,155,36,-90,357,-181;525,155,-944,691,-432,-147,-299;-453,36,691,-785,-199,514,-43;374,-90,-432,-199,-278,-559,-390;-453,357,-147,514,-559,501,-89;64,-181,-299,-43,-390,-89,821],[-217,-496,-326,151,715,-222,58;-496,-627,281,-323,-691,-42,20;-326,281,754,-327,269,61,-702;151,-323,-327,418,544,349,-7;715,-691,269,544,-52,-146,-94;-222,-42,61,349,-146,23,656;58,20,-702,-7,-94,656,416],[258,-267,-600,-364,-541,52,-36;-267,-964,-55,343,-169,-401,-160;-600,-55,962,143,-364,136,231;-364,343,143,-814,-149,83,547;-541,-169,-364,-149,-297,441,-664;52,-401,136,83,441,-648,125;-36,-160,231,547,-664,125,-186],[708,-24,600,480,556,-701,628;-24,498,-49,-41,94,-69,407;600,-49,-836,281,641,-636,-372;480,-41,281,173,-193,18,351;556,94,641,-193,-414,-33,59;-701,-69,-636,18,-33,58,-212;628,407,-372,351,59,-212,838],[404,379,-164,490,-372,-323,-178;379,121,-352,-507,-379,-58,-253;-164,-352,936,760,534,-648,463;490,-507,760,540,-221,-193,-283;-372,-379,534,-221,965,114,-500;-323,-58,-648,-193,114,588,516;-178,-253,463,-283,-500,516,133],[-274,-8,774,69,632,746,-742;-8,550,834,-903,291,-438,-107;774,834,902,-160,-580,423,-143;69,-903,-160,852,453,216,-372;632,291,-580,453,562,211,56;746,-438,423,216,211,288,-255;-742,-107,-143,-372,56,-255,381],[29,-608,-241,-79,639,-259,44;-608,-80,727,279,150,-707,11;-241,727,-964,-562,-228,271,299;-79,279,-562,233,-245,-250,-16;639,150,-228,-245,208,-249,566;-259,-707,271,-250,-249,-498,342;44,11,299,-16,566,342,502],[-372,69,-132,48,802,42,-573;69,349,-147,702,-346,177,-132;-132,-147,-588,-729,-253,211,373;48,702,-729,-885,994,206,-391;802,-346,-253,994,-654,286,-125;42,177,211,206,286,-412,5;-573,-132,373,-391,-125,5,917],[857,-510,115,216,-52,263,11;-510,906,25,-444,-200,801,-659;115,25,832,493,-543,-283,-80;216,-444,493,-723,-89,-383,-48;-52,-200,-543,-89,228,641,179;263,801,-283,-383,641,-984,390;11,-659,-80,-48,179,390,314],[-786,-107,592,-837,329,-489,-279;-107,326,699,517,-347,109,-273;592,699,852,366,499,16,-329;-837,517,366,939,-584,-909,494;329,-347,499,-584,-172,-535,-62;-489,109,16,-909,-535,-147,223;-279,-273,-329,494,-62,223,442],[-529,-343,-828,-312,-108,143,-370;-343,583,-181,167,-353,654,490;-828,-181,586,334,-153,-633,214;-312,167,334,538,635,-73,-251;-108,-353,-153,635,338,-2,-38;143,654,-633,-73,-2,732,543;-370,490,214,-251,-38,543,-691],[-791,-269,-24,310,42,44,-620;-269,64,-128,341,635,482,-346;-24,-128,-745,451,-170,232,-236;310,341,451,403,466,-26,-684;42,635,-170,466,-274,510,-103;44,482,232,-26,510,35,-232;-620,-346,-236,-684,-103,-232,736],[-410,-80,172,-425,205,677,232;-80,373,214,214,-24,232,-602;172,214,771,493,250,-99,546;-425,214,493,881,-773,-465,-210;205,-24,250,-773,-858,231,664;677,232,-99,-465,231,337,-335;232,-602,546,-210,664,-335,-405],[268,-65,-243,164,-411,352,-74;-65,-70,-191,22,81,89,508;-243,-191,-211,140,-200,-766,687;164,22,140,572,30,-779,441;-411,81,-200,30,-903,-329,510;352,89,-766,-779,-329,276,352;-74,508,687,441,510,352,-884],[183,-42,-185,-223,389,-71,312;-42,365,387,-828,-348,91,-815;-185,387,-561,484,-238,-10,374;-223,-828,484,-835,383,2,397;389,-348,-238,383,-852,-936,152;-71,91,-10,2,-936,834,-652;312,-815,374,397,152,-652,-485],[577,44,346,411,287,817,385;44,293,-391,67,455,-125,-706;346,-391,-393,690,600,-139,601;411,67,690,-29,112,301,-324;287,455,600,112,431,296,-877;817,-125,-139,301,296,-373,255;385,-706,601,-324,-877,255,-210];[808,-278,875,-231,-399,765,-565,50;-278,221,592,-213,177,-142,857,-69;875,592,-413,56,-105,-81,-184,406;-231,-213,56,-429,-157,175,484,135;-399,177,-105,-157,997,663,302,59;765,-142,-81,175,663,-39,137,106;-565,857,-184,484,302,137,-521,-252;50,-69,406,135,59,106,-252,399],[161,157,43,-345,453,649,77,-136;157,-768,194,-548,480,-97,-710,-429;43,194,-445,490,285,-678,923,637;-345,-548,490,215,271,-107,926,102;453,480,285,271,739,-373,-185,-466;649,-97,-678,-107,-373,755,464,-453;77,-710,923,926,-185,464,-617,-261;-136,-429,637,102,-466,-453,-261,-779],[743,-327,77,563,9,-897,132,362;-327,-673,511,210,-354,-168,-545,301;77,511,514,525,-511,-457,122,-456;563,210,525,236,132,29,199,266;9,-354,-511,132,94,158,286,-78;-897,-168,-457,29,158,738,10,-492;132,-545,122,199,286,10,242,-381;362,301,-456,266,-78,-492,-381,767],[551,505,-571,261,236,-131,341,85;505,641,-277,-294,298,-125,11,271;-571,-277,416,390,-95,-423,166,-278;261,-294,390,-219,-483,582,476,-175;236,298,-95,-483,736,-212,209,49;-131,-125,-423,582,-212,-712,-294,110;341,11,166,476,209,-294,-524,-50;85,271,-278,-175,49,110,-50,-539],[475,359,-523,-420,609,-527,-78,-101;359,953,646,-263,-266,-137,5,307;-523,646,348,289,453,-535,-289,-657;-420,-263,289,963,-124,-118,-1,-70;609,-266,453,-124,-338,470,831,300;-527,-137,-535,-118,470,-970,226,517;-78,5,-289,-1,831,226,-634,404;-101,307,-657,-70,300,517,404,366],[980,164,-93,192,119,-740,245,657;164,844,-4,-506,111,284,-440,-335;-93,-4,474,41,7,583,308,434;192,-506,41,52,-17,477,-103,147;119,111,7,-17,3,-449,-606,-38;-740,284,583,477,-449,288,186,-168;245,-440,308,-103,-606,186,588,-283;657,-335,434,147,-38,-168,-283,-608],[702,374,72,726,26,-251,-277,-646;374,-197,772,48,42,-921,-95,183;72,772,-944,671,685,-164,-307,-742;726,48,671,212,86,57,173,606;26,42,685,86,-552,-80,-561,-73;-251,-921,-164,57,-80,72,497,195;-277,-95,-307,173,-561,497,-715,-35;-646,183,-742,606,-73,195,-35,384],[311,-486,254,208,305,101,379,-147;-486,-706,1,375,-160,249,566,-784;254,1,965,-582,-576,72,367,355;208,375,-582,-634,-189,771,-100,526;305,-160,-576,-189,766,-326,-797,366;101,249,72,771,-326,-275,-288,498;379,566,367,-100,-797,-288,-796,295;-147,-784,355,526,366,498,295,-216],[621,385,545,-215,-193,652,-102,-335;385,663,-954,337,-89,-287,-52,295;545,-954,228,-68,-319,-537,54,548;-215,337,-68,128,-189,-89,-541,578;-193,-89,-319,-189,-471,340,-24,-53;652,-287,-537,-89,340,232,201,-740;-102,-52,54,-541,-24,201,-425,-527;-335,295,548,578,-53,-740,-527,935],[-757,829,-286,395,13,484,72,535;829,-659,-621,-139,-267,-51,833,-148;-286,-621,973,-667,136,-158,-20,-334;395,-139,-667,820,-595,275,54,196;13,-267,136,-595,450,157,-109,879;484,-51,-158,275,157,797,686,22;72,833,-20,54,-109,686,209,-440;535,-148,-334,196,879,22,-440,-811],[-810,-857,-276,-493,-173,-325,372,514;-857,171,228,152,592,-219,-809,-613;-276,228,737,-440,158,-63,-17,-24;-493,152,-440,465,392,592,-11,268;-173,592,158,392,-113,158,-58,-431;-325,-219,-63,592,158,593,164,241;372,-809,-17,-11,-58,164,-75,-227;514,-613,-24,268,-431,241,-227,-207],[-320,220,-310,312,251,-597,-2,-48;220,-268,-316,-874,-290,284,-485,327;-310,-316,-550,899,-626,180,-659,263;312,-874,899,187,-23,-716,166,726;251,-290,-626,-23,-140,-255,146,-160;-597,284,180,-716,-255,-256,429,-32;-2,-485,-659,166,146,429,717,38;-48,327,263,726,-160,-32,38,-834],[-26,222,-112,-333,-202,214,90,-711;222,436,-141,344,-370,108,-703,-562;-112,-141,494,-214,11,-781,-221,231;-333,344,-214,865,175,-617,-41,414;-202,-370,11,175,569,182,-413,-311;214,108,-781,-617,182,-617,409,-260;90,-703,-221,-41,-413,409,209,-42;-711,-562,231,414,-311,-260,-42,481],[-564,30,35,-156,437,-180,-133,-249;30,-287,-632,-442,-332,631,-502,-67;35,-632,-917,-31,-191,495,-541,-644;-156,-442,-31,-83,312,-212,116,192;437,-332,-191,312,-299,-112,-316,232;-180,631,495,-212,-112,264,226,-87;-133,-502,-541,116,-316,226,754,-95;-249,-67,-644,192,232,-87,-95,598],[-912,-37,407,599,368,434,324,26;-37,-10,-78,-400,-21,187,-151,603;407,-78,-198,817,111,-796,859,-436;599,-400,817,968,-805,154,-479,592;368,-21,111,-805,-57,-376,-632,-17;434,187,-796,154,-376,743,369,280;324,-151,859,-479,-632,369,-851,658;26,603,-436,592,-17,280,658,-803],[-211,212,428,-720,-651,188,708,-289;212,-780,-18,-345,265,194,-487,48;428,-18,-501,38,343,685,285,25;-720,-345,38,744,244,519,672,425;-651,265,343,244,941,-318,-56,-181;188,194,685,519,-318,12,-413,161;708,-487,285,672,-56,-413,276,-549;-289,48,25,425,-181,161,-549,604],[-262,150,242,-310,314,-665,312,805;150,-403,-540,80,-676,-607,128,-249;242,-540,-208,-712,-542,-247,358,147;-310,80,-712,-127,337,-608,-614,579;314,-676,-542,337,545,-175,-746,-36;-665,-607,-247,-608,-175,-653,74,245;312,128,358,-614,-746,74,-934,564;805,-249,147,579,-36,245,564,86],[-621,172,354,106,936,-47,258,-305;172,-331,95,-233,-331,445,-542,40;354,95,-677,117,-16,-298,162,247;106,-233,117,372,367,-647,-232,-136;936,-331,-16,367,523,274,375,8;-47,445,-298,-647,274,707,-765,291;258,-542,162,-232,375,-765,36,-485;-305,40,247,-136,8,291,-485,-453],[845,-105,-231,350,329,-442,755,132;-105,399,674,634,123,34,-145,94;-231,674,-531,427,170,683,-181,-350;350,634,427,439,450,333,654,65;329,123,170,450,27,209,373,-483;-442,34,683,333,209,359,808,-578;755,-145,-181,654,373,808,235,-349;132,94,-350,65,-483,-578,-349,353],[-54,-425,166,21,458,-478,-71,-682;-425,837,-567,179,-231,166,-555,-1;166,-567,572,71,329,-143,132,-98;21,179,71,766,447,548,-249,-499;458,-231,329,447,-82,-770,-182,-82;-478,166,-143,548,-770,-679,303,55;-71,-555,132,-249,-182,303,-210,-606;-682,-1,-98,-499,-82,55,-606,-368],[-721,246,-538,945,-96,391,-352,-225;246,-99,-25,127,-123,-252,421,-586;-538,-25,836,-549,-188,242,-514,-467;945,127,-549,-67,-54,-308,-641,-797;-96,-123,-188,-54,690,-45,498,393;391,-252,242,-308,-45,233,728,-371;-352,421,-514,-641,498,728,323,-365;-225,-586,-467,-797,393,-371,-365,728],[-585,-371,752,-334,482,193,-119,-166;-371,-666,736,37,-634,575,65,-174;752,736,893,938,124,325,-414,233;-334,37,938,-467,62,-672,100,416;482,-634,124,62,19,-618,-522,180;193,575,325,-672,-618,-131,253,120;-119,65,-414,100,-522,253,-644,-289;-166,-174,233,416,180,120,-289,598],[-834,14,-85,202,-197,503,-44,-425;14,-689,522,-656,108,-258,56,378;-85,522,-379,-334,-421,540,-321,-436;202,-656,-334,521,-642,475,228,-493;-197,108,-421,-642,-881,-119,-114,177;503,-258,540,475,-119,-137,-41,-60;-44,56,-321,228,-114,-41,432,141;-425,378,-436,-493,177,-60,141,759],[-177,-670,-708,580,-790,-437,-319,-249;-670,173,836,-376,-175,52,366,163;-708,836,-848,-301,-568,384,-254,-718;580,-376,-301,892,-36,310,110,-594;-790,-175,-568,-36,-118,-368,-4,-50;-437,52,384,310,-368,-714,19,-852;-319,366,-254,110,-4,19,2,-241;-249,163,-718,-594,-50,-852,-241,8],[-188,-684,-298,581,626,-102,640,-271;-684,-286,-288,6,563,375,-501,454;-298,-288,-904,-198,816,454,-228,-953;581,6,-198,-901,369,393,169,-407;626,563,816,369,-598,53,-48,223;-102,375,454,393,53,-426,-349,3;640,-501,-228,169,-48,-349,-775,91;-271,454,-953,-407,223,3,91,469],[-406,180,601,-134,-338,-95,63,-351;180,932,-550,469,-303,-40,61,657;601,-550,-144,32,-116,-137,-494,-200;-134,469,32,-249,-351,-722,47,-786;-338,-303,-116,-351,811,238,108,-360;-95,-40,-137,-722,238,905,-138,729;63,61,-494,47,108,-138,-307,-188;-351,657,-200,-786,-360,729,-188,-372],[-301,-656,-404,122,-19,-420,519,32;-656,597,-843,358,-870,-408,-391,-86;-404,-843,489,47,384,-497,260,-724;122,358,47,-27,-191,369,-31,261;-19,-870,384,-191,-545,-383,-707,59;-420,-408,-497,369,-383,-550,514,-45;519,-391,260,-31,-707,514,654,-187;32,-86,-724,261,59,-45,-187,-161],[-353,-129,579,82,195,1,272,-273;-129,9,195,812,-184,51,440,82;579,195,-69,-472,-465,312,104,111;82,812,-472,361,659,-204,267,-156;195,-184,-465,659,-714,62,401,868;1,51,312,-204,62,-976,-556,-353;272,440,104,267,401,-556,-326,-96;-273,82,111,-156,868,-353,-96,-597],[91,-161,609,247,729,447,479,-399;-161,209,-393,-128,-19,-315,465,436;609,-393,-513,321,366,186,423,-297;247,-128,321,-119,124,636,-287,-577;729,-19,366,124,-71,335,552,-241;447,-315,186,636,335,519,310,422;479,465,423,-287,552,310,775,366;-399,436,-297,-577,-241,422,366,-355],[864,442,244,-155,-133,-41,-487,571;442,472,-683,-97,-649,-19,-485,-208;244,-683,-671,-128,-199,-608,150,-536;-155,-97,-128,-925,85,167,-183,-527;-133,-649,-199,85,233,279,-334,135;-41,-19,-608,167,279,69,-373,0;-487,-485,150,-183,-334,-373,-106,-426;571,-208,-536,-527,135,0,-426,523],[-277,799,399,46,-158,-105,-472,-446;799,-725,-636,528,427,918,-580,-205;399,-636,340,250,-379,298,78,-671;46,528,250,856,-187,-67,428,-623;-158,427,-379,-187,-784,-648,-372,-213;-105,918,298,-67,-648,271,-176,126;-472,-580,78,428,-372,-176,-837,585;-446,-205,-671,-623,-213,126,585,-866],[384,-598,-133,-338,148,490,-16,-371;-598,-995,648,-350,342,400,-125,32;-133,648,996,505,0,-19,486,334;-338,-350,505,699,-188,238,-14,-539;148,342,0,-188,138,72,-665,-298;490,400,-19,238,72,-151,484,656;-16,-125,486,-14,-665,484,781,90;-371,32,334,-539,-298,656,90,-913],[92,-103,-494,-476,-657,645,189,167;-103,-454,650,198,-5,483,-364,151;-494,650,-948,373,-314,704,-66,-189;-476,198,373,438,325,289,-566,-82;-657,-5,-314,325,52,-318,726,-194;645,483,704,289,-318,22,-205,572;189,-364,-66,-566,726,-205,416,-656;167,151,-189,-82,-194,572,-656,48],[256,-683,-311,472,475,156,8,-81;-683,-560,272,-892,197,-847,-241,-426;-311,272,-332,240,-20,-498,-603,-791;472,-892,240,-68,-38,543,340,-54;475,197,-20,-38,-489,-220,526,-790;156,-847,-498,543,-220,404,33,-444;8,-241,-603,340,526,33,855,-374;-81,-426,-791,-54,-790,-444,-374,-140],[834,120,-67,-684,-158,287,-257,0;120,696,454,-382,221,298,-420,430;-67,454,-831,61,505,88,29,-217;-684,-382,61,723,-59,907,-77,-198;-158,221,505,-59,-790,-96,-243,-44;287,298,88,907,-96,-375,326,338;-257,-420,29,-77,-243,326,-742,542;0,430,-217,-198,-44,338,542,487],[-73,376,-251,-591,142,88,-240,-553;376,392,-586,-685,-342,62,860,219;-251,-586,-980,358,-652,-34,-337,-669;-591,-685,358,-594,66,-704,-283,-462;142,-342,-652,66,185,23,-832,-505;88,62,-34,-704,23,-48,187,363;-240,860,-337,-283,-832,187,-309,-78;-553,219,-669,-462,-505,363,-78,-382],[704,123,-420,-628,168,47,-187,-517;123,-936,335,460,-331,160,-13,300;-420,335,-344,653,525,-826,-226,-89;-628,460,653,-237,111,633,256,44;168,-331,525,111,-218,-414,-423,103;47,160,-826,633,-414,-976,254,455;-187,-13,-226,256,-423,254,726,-701;-517,300,-89,44,103,455,-701,118],[74,-582,-710,287,45,-329,81,-158;-582,483,48,-32,-267,807,-673,-380;-710,48,657,667,-217,-765,-42,921;287,-32,667,-183,-549,724,-303,-390;45,-267,-217,-549,960,295,-273,141;-329,807,-765,724,295,-575,-576,-53;81,-673,-42,-303,-273,-576,-285,-94;-158,-380,921,-390,141,-53,-94,-403],[-363,-189,12,113,-405,265,-209,-520;-189,-265,-291,-8,655,-267,803,235;12,-291,379,316,615,-94,78,148;113,-8,316,804,764,533,-529,-432;-405,655,615,764,-433,-79,-430,-441;265,-267,-94,533,-79,147,-8,-616;-209,803,78,-529,-430,-8,964,-121;-520,235,148,-432,-441,-616,-121,230],[-715,-69,-734,299,-234,696,-106,718;-69,657,-278,445,109,408,-494,-33;-734,-278,447,31,-49,8,84,356;299,445,31,-354,352,-757,34,672;-234,109,-49,352,-899,523,27,240;696,408,8,-757,523,-903,-324,-774;-106,-494,84,34,27,-324,358,-217;718,-33,356,672,240,-774,-217,527],[-583,-373,75,-445,158,99,-393,319;-373,-531,89,-168,206,-120,582,184;75,89,666,118,341,107,76,-283;-445,-168,118,870,91,47,-477,-305;158,206,341,91,-961,84,77,-237;99,-120,107,47,84,647,-663,81;-393,582,76,-477,77,-663,98,-171;319,184,-283,-305,-237,81,-171,128],[-921,-483,442,-562,500,-511,-292,248;-483,-903,107,-330,515,-219,-111,3;442,107,-303,-132,-487,19,564,830;-562,-330,-132,-18,235,-14,-436,354;500,515,-487,235,-836,97,-343,-125;-511,-219,19,-14,97,811,-63,-162;-292,-111,564,-436,-343,-63,39,100;248,3,830,354,-125,-162,100,-238],[429,75,-149,-102,567,-56,350,788;75,-27,-189,302,-275,-157,-136,319;-149,-189,475,-172,82,98,-54,-680;-102,302,-172,192,288,249,728,-21;567,-275,82,288,421,-188,-834,-563;-56,-157,98,249,-188,989,-245,661;350,-136,-54,728,-834,-245,716,-165;788,319,-680,-21,-563,661,-165,-625],[771,-671,-414,135,-676,-505,-283,-540;-671,228,755,322,-429,-87,-218,-102;-414,755,678,120,-281,-41,62,-28;135,322,120,-69,-160,158,73,-533;-676,-429,-281,-160,677,-133,-518,821;-505,-87,-41,158,-133,-701,87,164;-283,-218,62,73,-518,87,-494,-727;-540,-102,-28,-533,821,164,-727,8],[7,-57,-530,89,212,72,221,-397;-57,-984,-288,-134,-115,-237,16,-609;-530,-288,-355,-75,487,-208,320,48;89,-134,-75,-20,-223,-303,-62,-119;212,-115,487,-223,-657,-306,248,-290;72,-237,-208,-303,-306,375,-375,154;221,16,320,-62,248,-375,-568,-201;-397,-609,48,-119,-290,154,-201,-626],[-320,-26,261,617,-684,-155,-3,-251;-26,-683,-415,890,596,106,194,-555;261,-415,-11,184,106,611,159,-57;617,890,184,122,-552,755,644,-332;-684,596,106,-552,164,-389,-260,-35;-155,106,611,755,-389,90,442,196;-3,194,159,644,-260,442,7,83;-251,-555,-57,-332,-35,196,83,-862],[-115,-242,247,-150,-239,-13,340,-158;-242,889,-712,172,-772,48,37,172;247,-712,749,333,-221,-244,-206,-474;-150,172,333,36,389,374,-73,-204;-239,-772,-221,389,599,-311,36,-293;-13,48,-244,374,-311,-985,-43,-149;340,37,-206,-73,36,-43,-949,633;-158,172,-474,-204,-293,-149,633,-202],[185,390,-301,-518,11,382,285,112;390,166,-418,66,-113,-163,-552,-874;-301,-418,-736,317,-216,713,-36,-508;-518,66,317,-191,865,108,964,218;11,-113,-216,865,-994,-528,234,-54;382,-163,713,108,-528,-481,509,742;285,-552,-36,964,234,509,-181,-354;112,-874,-508,218,-54,742,-354,606],[225,-41,-323,-325,857,2,-111,852;-41,-296,-186,181,-1,77,-152,-513;-323,-186,-964,372,-599,-264,24,-232;-325,181,372,-285,22,225,-502,-88;857,-1,-599,22,-500,354,352,114;2,77,-264,225,354,247,77,-245;-111,-152,24,-502,352,77,823,272;852,-513,-232,-88,114,-245,272,-640],[-882,182,-721,-2,708,658,-128,-405;182,-600,-779,-15,-33,-307,3,500;-721,-779,726,14,816,30,79,-513;-2,-15,14,-937,-385,-212,106,-673;708,-33,816,-385,652,857,125,-490;658,-307,30,-212,857,327,478,-519;-128,3,79,106,125,478,604,348;-405,500,-513,-673,-490,-519,348,-49],[-247,279,-233,300,-596,536,107,119;279,-955,-57,-108,-312,-241,-470,-649;-233,-57,968,-576,-494,160,-80,254;300,-108,-576,-275,258,-208,-187,-574;-596,-312,-494,258,312,301,262,202;536,-241,160,-208,301,-13,-220,-389;107,-470,-80,-187,262,-220,292,412;119,-649,254,-574,202,-389,412,428],[-992,-65,97,-390,110,-593,65,469;-65,849,100,813,302,-85,1,445;97,100,-914,841,-808,149,-604,-588;-390,813,841,-444,-129,338,276,-397;110,302,-808,-129,672,316,-197,88;-593,-85,149,338,316,350,-83,-642;65,1,-604,276,-197,-83,-872,249;469,445,-588,-397,88,-642,249,900],[-518,-140,218,137,-57,-375,618,614;-140,-544,255,156,-208,424,45,-306;218,255,851,-169,-208,100,432,-277;137,156,-169,276,-540,435,-567,591;-57,-208,-208,-540,-706,360,79,-168;-375,424,100,435,360,-959,-542,39;618,45,432,-567,79,-542,243,-547;614,-306,-277,591,-168,39,-547,985],[659,-3,124,177,-179,-29,764,-387;-3,-481,302,172,-11,23,30,-255;124,302,-722,255,-99,496,247,-661;177,172,255,-551,584,364,27,83;-179,-11,-99,584,-849,-119,-627,91;-29,23,496,364,-119,-189,195,-173;764,30,247,27,-627,195,-196,-547;-387,-255,-661,83,91,-173,-547,558],[-467,572,-60,174,-365,155,-386,-903;572,-724,298,97,302,-434,-77,173;-60,298,-941,-511,178,212,434,191;174,97,-511,-928,831,-352,584,114;-365,302,178,831,-165,-25,-308,-87;155,-434,212,-352,-25,-254,-314,-740;-386,-77,434,584,-308,-314,236,173;-903,173,191,114,-87,-740,173,-567],[584,220,-533,423,173,214,-377,623;220,662,-31,912,-94,45,606,512;-533,-31,-451,-122,-411,65,393,855;423,912,-122,-142,348,-541,449,368;173,-94,-411,348,934,376,213,-579;214,45,65,-541,376,700,116,432;-377,606,393,449,213,116,-404,-43;623,512,855,368,-579,432,-43,-804],[542,64,-578,858,-678,-686,373,-98;64,314,-421,610,-603,-73,414,-411;-578,-421,-644,-311,-172,136,198,-320;858,610,-311,639,941,-22,142,397;-678,-603,-172,941,-831,304,-262,-155;-686,-73,136,-22,304,463,-216,-88;373,414,198,142,-262,-216,236,-381;-98,-411,-320,397,-155,-88,-381,-264],[773,-819,-786,105,-88,-614,-700,-859;-819,-558,-403,725,-163,-168,-124,-35;-786,-403,-618,-257,-685,369,357,471;105,725,-257,430,-530,473,-178,347;-88,-163,-685,-530,-794,197,144,708;-614,-168,369,473,197,-255,282,237;-700,-124,357,-178,144,282,757,451;-859,-35,471,347,708,237,451,134],[-829,21,-560,-575,193,-236,-375,-315;21,-125,31,-537,-127,-577,-390,-607;-560,31,801,-352,13,-126,-42,169;-575,-537,-352,509,231,25,-174,122;193,-127,13,231,201,550,134,419;-236,-577,-126,25,550,-591,-149,-534;-375,-390,-42,-174,134,-149,-158,-290;-315,-607,169,122,419,-534,-290,412],[311,371,379,404,213,474,314,-104;371,683,-450,107,66,-27,35,37;379,-450,-232,17,-94,115,603,-1;404,107,17,-500,768,634,-765,14;213,66,-94,768,-80,62,-318,-243;474,-27,115,634,62,486,-331,594;314,35,603,-765,-318,-331,910,-389;-104,37,-1,14,-243,594,-389,-788],[-796,156,607,220,-460,23,-736,-365;156,620,-547,-507,-226,418,40,-217;607,-547,-238,283,-676,-375,77,263;220,-507,283,-262,-30,46,130,-325;-460,-226,-676,-30,-83,7,434,-307;23,418,-375,46,7,-664,756,-274;-736,40,77,130,434,756,601,65;-365,-217,263,-325,-307,-274,65,867],[332,-160,-560,30,-455,505,-16,-30;-160,227,293,157,-68,-201,-32,341;-560,293,-676,682,392,85,60,385;30,157,682,350,585,-1,-314,-117;-455,-68,392,585,571,224,-112,720;505,-201,85,-1,224,-69,-83,-237;-16,-32,60,-314,-112,-83,-20,333;-30,341,385,-117,720,-237,333,-638],[-257,400,-726,473,104,-420,-104,-332;400,-219,-591,389,-249,-163,230,-100;-726,-591,-491,-311,-280,605,-699,89;473,389,-311,-729,203,-358,451,-77;104,-249,-280,203,-113,-682,544,330;-420,-163,605,-358,-682,551,609,-65;-104,230,-699,451,544,609,921,-452;-332,-100,89,-77,330,-65,-452,575],[-172,-171,-32,549,-113,328,-33,-219;-171,-630,843,-273,-135,-17,-395,-30;-32,843,-249,-309,50,-250,481,525;549,-273,-309,-945,521,766,134,488;-113,-135,50,521,808,-341,311,485;328,-17,-250,766,-341,-684,846,-132;-33,-395,481,134,311,846,-536,-541;-219,-30,525,488,485,-132,-541,-235],[-7,-168,267,44,525,215,739,74;-168,-792,105,575,643,-374,-272,613;267,105,911,841,-72,316,-390,-109;44,575,841,-348,142,53,-49,-176;525,643,-72,142,369,463,269,-86;215,-374,316,53,463,-217,197,-37;739,-272,-390,-49,269,197,-922,32;74,613,-109,-176,-86,-37,32,595],[-211,856,-146,-570,-229,-636,-109,282;856,-94,-63,409,-620,234,498,641;-146,-63,134,90,533,93,156,-454;-570,409,90,-568,-617,-89,33,-511;-229,-620,533,-617,396,-278,526,-220;-636,234,93,-89,-278,456,-308,700;-109,498,156,33,526,-308,-456,-540;282,641,-454,-511,-220,700,-540,-886],[143,-192,-28,-357,370,50,359,143;-192,-232,729,-314,767,55,108,-599;-28,729,-278,12,-316,803,-842,869;-357,-314,12,-420,552,-467,634,388;370,767,-316,552,-500,-42,212,-277;50,55,803,-467,-42,392,885,98;359,108,-842,634,212,885,-183,-117;143,-599,869,388,-277,98,-117,938],[-801,780,-373,306,688,-182,573,-120;780,-749,424,-128,-456,584,116,-312;-373,424,-407,-389,-408,153,-533,48;306,-128,-389,571,-142,687,-170,-137;688,-456,-408,-142,17,-236,-234,507;-182,584,153,687,-236,-819,-447,865;573,116,-533,-170,-234,-447,-451,-411;-120,-312,48,-137,507,865,-411,459],[-157,-171,263,17,-728,-193,762,257;-171,-413,-239,-868,431,364,-566,-172;263,-239,-37,-585,311,362,-186,715;17,-868,-585,797,-416,-674,138,-520;-728,431,311,-416,-918,-227,-483,483;-193,364,362,-674,-227,-581,-508,923;762,-566,-186,138,-483,-508,42,-343;257,-172,715,-520,483,923,-343,-720],[367,329,361,-44,320,-128,349,580;329,-827,370,37,412,-234,358,399;361,370,-232,231,-103,-208,778,-174;-44,37,231,471,-605,450,-70,-310;320,412,-103,-605,416,229,143,-225;-128,-234,-208,450,229,-617,561,771;349,358,778,-70,143,561,-742,6;580,399,-174,-310,-225,771,6,-852],[-229,-391,772,601,-348,-207,312,952;-391,-368,-245,265,170,252,694,109;772,-245,893,-441,156,235,-210,-620;601,265,-441,838,585,-262,753,-32;-348,170,156,585,465,476,-52,-421;-207,252,235,-262,476,986,-370,-203;312,694,-210,753,-52,-370,-897,521;952,109,-620,-32,-421,-203,521,506],[-895,-403,690,-490,130,-670,-27,837;-403,-392,384,-401,932,195,-213,-813;690,384,658,205,448,-825,182,-445;-490,-401,205,-742,-179,-657,-368,36;130,932,448,-179,-606,717,-29,176;-670,195,-825,-657,717,-861,271,-35;-27,-213,182,-368,-29,271,541,369;837,-813,-445,36,176,-35,369,-628],[-208,-129,8,142,-466,103,11,-558;-129,136,84,631,198,715,-292,-724;8,84,-917,-178,-648,-243,868,-444;142,631,-178,-893,-614,792,146,-291;-466,198,-648,-614,22,83,-180,245;103,715,-243,792,83,-465,22,413;11,-292,868,146,-180,22,-818,895;-558,-724,-444,-291,245,413,895,617],[-749,13,400,364,-214,-750,632,-364;13,-929,664,398,-182,30,80,115;400,664,-703,58,84,472,-419,-60;364,398,58,-487,162,-686,-466,-577;-214,-182,84,162,138,504,674,759;-750,30,472,-686,504,439,770,311;632,80,-419,-466,674,770,859,393;-364,115,-60,-577,759,311,393,787],[-780,366,-190,-207,963,-465,-393,-877;366,-624,-844,-177,571,-282,-3,430;-190,-844,-927,753,440,-517,-286,378;-207,-177,753,-189,540,-9,322,889;963,571,440,540,-286,141,272,219;-465,-282,-517,-9,141,411,268,-27;-393,-3,-286,322,272,268,-738,-192;-877,430,378,889,219,-27,-192,462],[-969,275,-875,-677,-65,29,-457,281;275,-833,262,116,-111,-162,-803,262;-875,262,773,56,-424,277,613,-156;-677,116,56,-825,187,-17,-92,-595;-65,-111,-424,187,401,49,-206,235;29,-162,277,-17,49,4,-2,-491;-457,-803,613,-92,-206,-2,87,-117;281,262,-156,-595,235,-491,-117,746],[662,-401,-344,169,-494,-266,58,-462;-401,282,-394,-578,583,-777,129,-408;-344,-394,130,-422,-675,-224,-202,844;169,-578,-422,-772,46,-336,285,193;-494,583,-675,46,257,519,-626,361;-266,-777,-224,-336,519,-710,-395,-567;58,129,-202,285,-626,-395,197,-529;-462,-408,844,193,361,-567,-529,825],[771,-245,-364,456,818,466,-355,418;-245,683,63,841,-615,-647,-229,-571;-364,63,-904,-357,-173,248,-72,-122;456,841,-357,551,-822,-150,-466,-277;818,-615,-173,-822,26,-44,590,-105;466,-647,248,-150,-44,697,-201,462;-355,-229,-72,-466,590,-201,200,-273;418,-571,-122,-277,-105,462,-273,-389],[965,-217,305,-118,-647,45,-167,309;-217,400,-58,-466,871,47,24,-351;305,-58,600,440,81,-628,392,-551;-118,-466,440,821,30,408,-66,334;-647,871,81,30,372,-576,599,-252;45,47,-628,408,-576,-48,120,-643;-167,24,392,-66,599,120,376,-424;309,-351,-551,334,-252,-643,-424,353],[-551,-129,218,172,224,294,-114,759;-129,786,-11,-40,-258,-180,216,-302;218,-11,-593,339,-345,464,297,-39;172,-40,339,918,403,-652,524,-436;224,-258,-345,403,304,-88,731,-248;294,-180,464,-652,-88,-967,180,-17;-114,216,297,524,731,180,-709,369;759,-302,-39,-436,-248,-17,369,671],[751,511,288,32,-487,-406,560,-452;511,694,174,-578,-261,78,740,-114;288,174,-655,-159,93,-592,171,-450;32,-578,-159,-300,-98,-871,-337,414;-487,-261,93,-98,-360,130,114,734;-406,78,-592,-871,130,-107,-67,-138;560,740,171,-337,114,-67,-524,-192;-452,-114,-450,414,734,-138,-192,-172],[-409,-70,-354,16,302,674,-392,37;-70,812,-82,-106,-660,443,52,-681;-354,-82,-971,-380,676,0,78,-649;16,-106,-380,209,826,238,-415,-588;302,-660,676,826,691,-912,-414,392;674,443,0,238,-912,271,-704,-648;-392,52,78,-415,-414,-704,-564,238;37,-681,-649,-588,392,-648,238,143],[49,-361,-254,183,596,77,-489,223;-361,690,-97,731,-794,321,218,-377;-254,-97,-213,-178,50,-583,-87,-61;183,731,-178,-75,478,-828,194,635;596,-794,50,478,443,-66,-569,482;77,321,-583,-828,-66,-710,-145,152;-489,218,-87,194,-569,-145,-186,76;223,-377,-61,635,482,152,76,280],[12,-62,256,-318,-301,163,517,676;-62,140,-179,192,722,422,-51,460;256,-179,865,256,-222,223,512,-360;-318,192,256,-693,-478,-147,-717,-12;-301,722,-222,-478,356,-483,-401,58;163,422,223,-147,-483,615,-348,208;517,-51,512,-717,-401,-348,-94,658;676,460,-360,-12,58,208,658,774],[-482,-99,101,290,699,779,444,4;-99,-530,-619,805,-731,303,494,432;101,-619,35,-658,283,-201,776,133;290,805,-658,149,-429,40,117,-153;699,-731,283,-429,501,-178,-100,457;779,303,-201,40,-178,795,7,151;444,494,776,117,-100,7,790,-32;4,432,133,-153,457,151,-32,450],[-102,-121,606,747,-445,650,-248,-322;-121,-324,623,449,-222,79,-5,284;606,623,638,-378,-312,306,-624,223;747,449,-378,426,317,-322,-254,789;-445,-222,-312,317,80,-69,-729,-560;650,79,306,-322,-69,-4,19,290;-248,-5,-624,-254,-729,19,-786,717;-322,284,223,789,-560,290,717,536],[769,728,83,-893,-123,303,-727,73;728,2,44,-400,-118,-698,-106,462;83,44,611,395,-65,253,-311,-104;-893,-400,395,-888,-445,221,-342,454;-123,-118,-65,-445,-498,-643,-461,396;303,-698,253,221,-643,-309,-84,-275;-727,-106,-311,-342,-461,-84,-77,-83;73,462,-104,454,396,-275,-83,-915],[-264,-34,-773,-380,-165,-238,-451,233;-34,411,276,-418,-599,-411,-329,-122;-773,276,-527,-522,-863,-540,-534,-267;-380,-418,-522,-922,143,-219,-640,719;-165,-599,-863,143,-8,-426,-780,688;-238,-411,-540,-219,-426,956,578,525;-451,-329,-534,-640,-780,578,-482,611;233,-122,-267,719,688,525,611,-91],[-727,-204,-407,561,715,523,97,403;-204,321,6,-311,-835,-57,-320,-651;-407,6,-734,328,-513,-315,-684,467;561,-311,328,472,389,-406,158,144;715,-835,-513,389,-670,293,-288,243;523,-57,-315,-406,293,-126,-424,3;97,-320,-684,158,-288,-424,-20,-409;403,-651,467,144,243,3,-409,-404],[585,-649,-20,-788,-492,233,-3,-459;-649,592,-444,-52,108,-208,60,-471;-20,-444,-670,-284,112,-614,437,-51;-788,-52,-284,-851,-380,-418,-83,313;-492,108,112,-380,659,484,-148,-851;233,-208,-614,-418,484,-878,-229,-51;-3,60,437,-83,-148,-229,856,-48;-459,-471,-51,313,-851,-51,-48,-736],[-632,792,-88,-409,-516,253,57,7;792,-950,26,-138,-687,-384,-321,221;-88,26,395,-111,124,78,-866,9;-409,-138,-111,485,-381,-61,-227,-21;-516,-687,124,-381,-621,-608,-847,-447;253,-384,78,-61,-608,-807,-31,289;57,-321,-866,-227,-847,-31,-293,1;7,221,9,-21,-447,289,1,537],[-809,-182,-507,-173,66,-252,384,362;-182,973,76,-203,132,-386,-237,-167;-507,76,768,580,-290,-558,479,-341;-173,-203,580,561,346,469,-259,55;66,132,-290,346,-992,-268,-890,-687;-252,-386,-558,469,-268,770,382,-15;384,-237,479,-259,-890,382,735,-448;362,-167,-341,55,-687,-15,-448,-161],[862,-108,755,-38,-596,137,-448,-350;-108,763,-551,-180,-255,-748,-630,298;755,-551,543,495,442,833,91,-214;-38,-180,495,24,-157,-970,-101,-680;-596,-255,442,-157,468,-23,830,-133;137,-748,833,-970,-23,-377,-425,67;-448,-630,91,-101,830,-425,-360,-172;-350,298,-214,-680,-133,67,-172,-555],[445,-67,205,766,-107,-244,645,-225;-67,-335,16,578,-516,561,37,159;205,16,566,-155,79,35,336,12;766,578,-155,-980,-589,-244,278,-707;-107,-516,79,-589,604,149,-175,487;-244,561,35,-244,149,996,333,-445;645,37,336,278,-175,333,552,167;-225,159,12,-707,487,-445,167,-196],[719,465,663,-460,488,254,289,543;465,696,-397,462,-45,-60,-52,-414;663,-397,-498,-795,-1,85,-641,542;-460,462,-795,448,149,-162,-191,103;488,-45,-1,149,846,-310,151,-451;254,-60,85,-162,-310,-209,329,-401;289,-52,-641,-191,151,329,523,-535;543,-414,542,103,-451,-401,-535,-482],[686,168,490,158,-28,-255,-603,-335;168,81,80,586,-518,-173,-347,-52;490,80,681,-523,-47,726,175,-173;158,586,-523,-623,633,-510,-341,240;-28,-518,-47,633,-244,6,163,680;-255,-173,726,-510,6,-38,-308,536;-603,-347,175,-341,163,-308,373,-285;-335,-52,-173,240,680,536,-285,928],[-645,493,252,544,490,-55,678,489;493,300,175,264,592,-118,-149,162;252,175,506,-71,-783,476,-311,-383;544,264,-71,807,15,310,5,-54;490,592,-783,15,-208,-24,24,602;-55,-118,476,310,-24,-661,-438,622;678,-149,-311,5,24,-438,-191,-717;489,162,-383,-54,602,622,-717,633],[-649,492,-617,-501,436,492,68,420;492,-527,158,451,-751,-511,-27,362;-617,158,47,-742,287,-440,-207,-633;-501,451,-742,60,3,591,-272,576;436,-751,287,3,987,171,-341,216;492,-511,-440,591,171,754,-589,72;68,-27,-207,-272,-341,-589,-457,-540;420,362,-633,576,216,72,-540,-671],[-987,-794,-212,262,437,361,75,10;-794,-864,54,258,-749,196,-740,559;-212,54,-981,347,117,-94,-148,270;262,258,347,-102,186,251,-199,617;437,-749,117,186,308,-212,244,-56;361,196,-94,251,-212,630,404,-369;75,-740,-148,-199,244,404,-236,-387;10,559,270,617,-56,-369,-387,216],[460,-64,-595,-579,468,780,626,353;-64,-439,223,-29,-324,286,748,-228;-595,223,727,867,481,106,670,90;-579,-29,867,120,-139,-151,35,144;468,-324,481,-139,-673,229,347,552;780,286,106,-151,229,319,273,210;626,748,670,35,347,273,646,-330;353,-228,90,144,552,210,-330,-173]];} TEST(deb=1,fin=6)= { for(i=deb,fin, print("dim=",i+2); for(j=1,100, Q=M[i,j]; s=qfsolve(Q); if(type(s)=="t_INT", print([j,s]), if(s~*Q*s, error(Q))); ); ); } TEST() G = [1,0,0;0,1,0;0,0,-34]; qfparam(G, qfsolve(G)) qfparam(G, qfsolve(G),1) qfparam(G, qfsolve(G),2) qfsolve(Mat(0)) qfsolve(Mat(1)) qfsolve([1,2;2,1]) qfsolve([0,1;1,1]) qfsolve([35, 46; 46, 60]) qfparam(matdiagonal([1,1,-1]),[1,0,1]) qfsolve(matdiagonal([1,1,-25])) qfsolve([1,0,0;0,3,0;0,0,-2]) qfparam([0,0,-12;0,-12,0;-12,0,-1],[1,0,0]~,3) q=[-1,-4,-8;-4,-15,-31;-8,-31,-62]/4; qfparam(q,qfsolve(q)) \\#1661 qfsolve([1,0,0;0,1,1;0,0,1]); \\#1725 qfsolve(matdiagonal([1,1,1,1,1,1,-7])) pari-2.11.2/src/test/in/binomial0000644000175000017500000000013313326135265015052 0ustar billbillbinomial(x,2) binomial(6,3) binomial(6) \\errors binomial(1,2.) binomial(-1) binomial(1.) pari-2.11.2/src/test/in/bnfisintnorm0000644000175000017500000000064512314242551015771 0ustar billbilldo(i)= { my(t = bnfisintnorm(bnf,i)); for (k=1,#t, if (nfeltnorm(bnf,t[k])!=i, error([i,k]))); if (#t, print(i,":",#t)); } default(realprecision,38); \e setrand(1); bnf=bnfinit(x^2+105); for(i=1,1000, do(i)) setrand(1); bnf=bnfinit(x^2-65); for(i=1,1000, do(i-500)) setrand(1); bnf=bnfinit(x^5-37); for(i=1,1000, do(i-500)) /* regression tests: */ bnfisintnorm(bnfinit(x^3+5), 5) bnfisintnorm(bnfinit('y^2+93),54647) pari-2.11.2/src/test/in/ell0000644000175000017500000002624113454730732014046 0ustar billbilldefault(parisize,"20M"); default(realprecision,38); /* Test generic */ F={ [ellwp, ellzeta, ellsigma, ellformalw, ellformalpoint, ellformaldifferential, ellformallog, ellformalexp, E->ellisoncurve(E,[0,0]), E->ellordinate(E,0), E->elldivpol(E,5), E->ellxn(E,3), E->ellmul(E,[0,0],0), E->ellneg(E,[0,0]) ]; } L={ [1,I,'z,Mod('z,'z^2+5), ellinit([0,0,0,'z,0],nfinit('z^2+5)), Mod(4,1009),ffgen([1009,5],'z)]; } L=apply(x->if(type(x)=="t_VEC",x,ellinit([x,0])),L); for(j=1,#F,for(i=1,#L, print(F[j],":",L[i][4],":",F[j](L[i])))); ellap(ellinit([1,0,1,4,-6]), 2) ellap(ellinit([0,17]), 2) ellap(ellinit([0, 0, 1, -1, 0]),2486246173) testgroup(v,p)= { my(E,F,G,g); E=ellinit(v); if(!E || E.disc%p==0, next); G=ellgroup(E,p,1); if (G.no == 1, return); g=G.gen; if (!ellisoncurve(E,g), error(E, G)); F=vector(#g,i, ellorder(E,g[i],G.no)); if ((p <= 3 && F!=G.cyc) || (p > 3 && F[1] != G.cyc[1]), print("error:",v,":",F,":",G)); } { for(x=10,63, my(p,E,G,g); p=nextprime(2^x);E=ellinit([0,0,1,2,3]); G = ellgroup(E,p,1); if (!ellisoncurve(E,G.gen), error(E)); if(ellorder(E,G.gen[1])!=G.cyc[1], error(E)); print(p,":",ellgroup(E,p))); for(p=2,3, forvec(v=vector(5,i,[0,p-1]), testgroup(v,p))); forvec(v=vector(2,i,[0,4]), testgroup(v,5)); } setrand(1) a=ffgen(2^8,'a); E=ellinit([a,1,0,0,1]); P=[a^3,ellordinate(E,a^3)[1]]; Q=ellmul(E,P,113); e=elllog(E,P,Q,242) ellmul(E,Q,e) == P ellpow(E,Q,e) == P p=655637; E=ellinit([123,47], p); X=1;until(Y!=[],X++;Y=ellordinate(E,X)); P=[X,Y[1]]; Q=ellmul(E,P,113); o=ellorder(E,P, p+1-ellap(E,p)) e=elllog(E,P,Q,o) ellmul(E,Q,e) == P p=1073741827; E=ellinit([1,3], p); G=[Mod(1050932506,p),Mod(12325986,p)]; P=ellmul(E,G,1023); elllog(E,P,G) ellorder(ellinit([0,2],1),[-1,-1]*Mod(1,997)) ellinit([a1,a2,a3,a4,a6]*Mod(1,5)); ellinit([a1,a2,a3,a4,a6]); ellinit(ellfromj(0)).j ellinit(ellfromj(1728)).j ellinit(ellfromj(j)).j ellinit(ellfromj(Mod(0,2))).j ellinit(ellfromj(Mod(0,5))).j ellinit(ellfromj(Mod(3,5))).j ellinit(ellfromj(j*Mod(1,2))).j ellinit(ellfromj(Mod(0,3))).j ellinit(ellfromj(j*Mod(1,3))).j elltwist(ellinit([0,a2,0,a4,a6]),x^2-D/4) lift(elltwist(ellinit([a1,a2,a3,a4,a6]*Mod(1,2)),x^2+x+T)) elltwist(ellinit([a1,a2,a3,a4,a6]),1) elltwist(ellinit([a1,a2,a3,a4,a6]),-4) elltwist(ellinit([a1,a2,a3,a4,a6]),5) e = ellinit([4,0]); ellminimaltwist(e) ellminimaltwist(e,1) e = ellinit(ellfromj(-882216989/131072)); e = ellintegralmodel(e,&v) v ellminimaltwist(e) ellminimaltwist(e,1) twisttest(c4,c6, T)= { my(e = ellinit([c4/-48, c6/-864])); vector(#T, i, my (et = ellinit(elltwist(e, T[i]))); my (d = ellminimaltwist(et)); et = ellinit(elltwist(et,d)); [d, ellminimalmodel(et).disc]); } T3 = [1,-3]; twisttest(-4*3,8*3^3, T3) twisttest(0,8*3^3, T3) twisttest(-4*3,0, T3) twisttest(16,-8*19, T3) twisttest(-4*3^4, 8*3^6, T3) twisttest(4*3^6, 16*3^9, T3) T2 = [1,-4,8,-8]; a=2;b=3; twisttest(3*2^a, 9*2^b, T2) a=4;b=5; twisttest(3*2^a, 9*2^b, T2) b=5; twisttest(0, 9*2^b, T2) a=4; twisttest(3*2^a, 0, T2) twisttest(1, -161, T2) d=2; twisttest(-17*2^(2*d), 2^(3*d), T2) ellminimaltwist(ellinit([216,-432]),1) a=ffgen(2^5,'a);ellinit(ellfromj(a)).j a=ffgen(3^5,'a);ellinit(ellfromj(a)).j ellfromeqn(y^3+(3+2*x)*y^2 +(6+5*x+4*x^2)*y+(10+9*x+8*x^2+7*x^3)) ellfromeqn(y^2+(2*x^2+3*x+4)*y+(5*x^4+6*x^3+7*x^2+8*x+9)) ellfromeqn(x^2+(2*y^2+3*y+4)*x+(5*y^4+6*y^3+7*y^2+8*y+9)) ellfromeqn((x^2+2*x+3)*y^2+(4*x^2+5*x+6)*y+(7*x^2+8*x+9)) e = ellinit([1,2,3,5,7]); elldivpol(e,4) ellxn(e,0) ellxn(e,1) ellxn(e,2) ellxn(e,4) ellxn(e,5) P=[-1,1]; Q=ellmul(e,P,20); if (ellisdivisible(e,Q,0,&A), A) if (ellisdivisible(e,[0],0,&A), A) if (ellisdivisible(e,Q,1,&A), A) if (ellisdivisible(e,Q,20,&A), A) if (ellisdivisible(e,Q,-20,&A), A) if (ellisdivisible(e,Q,2,&A), A) if (ellisdivisible(e,Q,5,&A), A) if (ellisdivisible(e,Q, ellxn(e,5), &A), A) if (ellisdivisible(e,Q,11,&A), A) if (ellisdivisible(e,Q,22,&A), A) e = ellinit([0,1]); elldivpol(e,8) \\ #2106 e = ellinit([0,0,1,-1,0]); P = [0,0]; K = nfinit(nfsplitting(elldivpol(e, 3))); eK = ellinit([0,0,1,-1,0], K); ellisdivisible(eK, P, 3) P6 = ellmul(eK, P, 6); if (ellisdivisible(eK, P6, 3, &Q), Q) if (ellisdivisible(eK, P6, 2, &Q), Q) e = ellinit([1.,2,3,4,5]); e.eta E = ellchangecurve(e, [2,3,4,5]); E.eta e = ellinit([1,2,3,4,5]); e.eta; e.roots; E = ellchangecurve(e, [2,3,4,5]); E.omega E.eta E.roots ellglobalred(E) ellglobalred(e) p = 2^64+13; E = ellchangecurve(e, [1/p, 2,3,4]); elllocalred(E,p) E = ellchangecurve(e, [1,0,0,0]); E = ellchangecurve(e, [2,3,4,5]*Mod(1,7)); E.omega E.group ellminimalmodel(ellinit([1/5,1/4,1/3,1/2,1],1),&v) v j=ffgen(2^5,'a);e = ellinit(ellfromj(j)); e.group; elllog(e,e.gen[1],e.gen[1]) E = ellchangecurve(e,[3,7,1,0]); E.group e = ellinit(ellfromj(Mod(1,3))); e.group; elllog(e,e.gen[1],e.gen[1]) E = ellchangecurve(e,[2,7,1,0]); E.group e = ellinit(ellfromj(Mod(1,5))); e.group; elllog(e,e.gen[1],e.gen[1]) E = ellchangecurve(e,[2,7,1,0]); E.group e = ellinit(ellfromj(1/3) * (1 + O(3^10))); e.roots e = ellinit(ellfromj(1/3), O(3^5)); e.tate iferr(ellinit(e,O(5)),E,E) iferr(ellinit(e,5),E,E) iferr(ellinit(e,1.0),E,E) e.roots E = ellchangecurve(e,[3,1,1,2]); E.tate ellztopoint(e,3) e = ellinit(ellfromj(11/8), O(2^5)); e.tate e = ellinit([1,0,1,4,-6], O(2^5)); e.tate e = ellinit([0,-1,1,-10,-20]); \\#1185 ellwp(e,x+O(x^12)) \\#1683 ellztopoint(e,3*e.omega[1]/5) ellwp(e, 0.1 + 0.2*I, 1) \\#1683 e = ellinit([1,1,0,-1740,22184]); z=-3.0059315873096303229151114945365166621 + 0.E-36*I/2; ellztopoint(e,z) \\#1800 ellztopoint(ellinit([-1,0]), I) \\#1186 ellmul(ellinit([3,0]), [1,2], -quadgen(-4)) \\#2060 ellzeta([1,I],2/10+I) \\#2061 ellsigma([1,I],1/2+I) logsigma(e,z='x)=if(type(z) != "t_POL" && type(z) != "t_SER", ellsigma(e,z,1)); v = [ellwp,ellzeta,ellsigma,logsigma]; ellperiods([1,0.1 + I/10^50]) e = ellinit([1,1]); w = ellperiods([1,I/2]) w2 = ellperiods([1,I/2], 1) u = [e,w,w2]; { for (i = 1, #v, my(f = v[i]); for (j = 1, #u, my (a = u[j]); print([i,j]); print(f(a)); print(f(a, x+O(x^10))); print(f(a, 1/3)); print(f(a, I/3)); print(f(a, (1+I)/3)); ) ) } elleta(e) elleta([1,I]) v = [x->elleisnum(x,2),x->real(elleisnum(x,4,1)),x->real(elleisnum(x,6,1)),x->real(elleisnum(x,10))]; { for (i = 1, #v, my(f = v[i]); print(f); print(f(e)); print(f(w)); print(f(w2)); ) } elleisnum([1,I/2^30],2) elleisnum([1,I/2^30],4) \\ #1257 ellrootno(ellinit([0,-1,1,217,-282])) \\ #1296 e=ellinit([0,-1,0,-33,62]); ellztopoint(e,-2.5261979245524788020279452840822073870+0.E-36*I) \\ #1308 ellinit([108/91,11664/8281,-6561/8281,708588/753571,-14348907/68574961]).disc e=ellinit([1,3.+I]); x=1/2+I; y=ellordinate(e,x)[1]; ellztopoint(e,ellpointtoz(e,[x,y])) testzellQp(e, P)= { my(a,q,Q); a = ellpointtoz(e,P); Q = ellztopoint(e,a); if (liftall(Q-P),error([e,P])); print(a); q = e.tate[3]; a = a^2; if (type(a) == "t_PADIC", a /= q^(valuation(a,a.p) \ valuation(q,a.p)); /* reduce mod q^Z */ ); a - ellpointtoz(e, elladd(e,P,P)); } e=ellinit([0,-1,1,0,0], O(11^5)); \\ BIB #1840 ellpointtoz(e,[Mod(3,'x^2+1),1]); testzellQp(e, [0,0]) e=ellinit([1,1,1,-10,-10], O(3^5)); testzellQp(e, [3,-2]) testzellQp(e, ellmul(e,[0,0],2)) \\ not on curve ! e=ellinit(ellfromj(2/9), O(3^10)); x=2; y=ellordinate(e,x)[1]; testzellQp(e, [x,y]) e=ellinit(ellfromj(1/4), O(2^10)); x=1/2; y=ellordinate(e,x)[1]; testzellQp(e, [x,y]) e=ellinit([1,-1,1,98,126],O(5^10)); testzellQp(e, [1,14]) e=ellinit([1,1,1,3,-5],O(2^10)); testzellQp(e,[5,10]) e=ellinit([1,-1,1,-48,147], O(2^10)); testzellQp(e,[13,-47]) ellinit([1,1], Mod(1,11)) ellrootno(ellinit([31^4,31^6]), 31) e=ellinit([1,0,0,1,1]); ellordinate(e, I) E=ellchangecurve(e,[1/(2^4*3^4*5^2*7),2,3,4]); forprime(p=2,11, if (ellap(e,p) != ellap(E,p),error(p))); for(k=2,50, if (ellak(e,k) != ellak(E,k),error(k))); if (ellan(e,100) != ellan(E,100),error("ellan")); P=ellchangepoint([0,1],[1,2,3,4]) ellchangepointinv(P,[1,2,3,4]) \\#1416 E=ellinit([155818018413/16,-78179511999813417/32]); ellminimalmodel(E,&v); E2=ellchangecurve(E,v); ellminimalmodel(E2,&w); w \\#1432 E=ellinit([-3,-60,480,0,0]); ellheight(E,[0,0]) ellheight(E,[0.,0]) p=10^20+39; q=10^21+117; e = ellinit([p^3*q^4,p^6*q^4]); ellminimalmodel(e,&v); v e = ellinit([p^4*q^4,p^6*q^4]); ellminimalmodel(e,&v); v e=ellminimalmodel(ellinit([1,1])); e=ellchangecurve(e,1) e=ellchangecurve(e,[2,0,0,0]) ellinit(ellinit([0,1]*Mod(1,5),ffgen(5^2))); J=[0,1728,-3375,8000,54000,-32768,287496,-884736,-12288000,16581375,-884736000,-147197952000,-262537412640768000]; { for (i=1,#J, my(e = ellinit(ellfromj(J[i]))); my(v = ellan(e,200)); print("\n", e.j); forprime(p = 127, 200, print1(v[p]," ")); print(); forprime(p = 2^65, 2^65+1000, print1(ellap(e,p)," ")); ); } p=2^32+15; ellcard(ellinit([1,2,3,4,5], p)) E=ellinit([625,15625]); elllocalred(E,5) ellisoncurve(E,[0.,125.]) ellisoncurve(E,[1e-50,125+1e-50]) elladd(E,[0.,125.],[0.,125+1e-38]) iferr(ellmul([0,1,0,2,-15],[2,1],5),E,E) x='x; E=ellinit([x^2,x]) ellminimalmodel(E) ellweilpairing(E,[0],[0],1) ellinit([1]) ellinit([1,1],quadgen(5)) ellinit([Mod(1,2),1],O(2)) ellinit([O(2),1],ffgen(2^3)) ellinit([O(2),1],1.) ellinit([1,2],1.) ellinit([ffgen(5),1],5) ellinit([ffgen(5),1],3) ellinit([1.,1],precision(1.,60)) ellinit([1.,Mod(1,3)]) \\#1527 E = ellinit([0,0,0,-82,0]); ellrootno(E,2) ellrootno(E) ellrootno(E,2) E=ellinit([0,20,0,-352,512]); ellrootno(E,2) E.disc elltamagawa(E) ellbsd(E) E=ellinit([1,0,1,4,-6]); E.disc elltamagawa(E) ellbsd(E) ellbsd(ellinit([-5*36^4,0])) \\#1558 ellap(ellinit([-1137195,489565862]),2038074751) ellap(ellinit([582304190,64196421]),2147438927) e=ellinit([0,-1,1,-2,2]); P=[2,-2]; ellnonsingularmultiple(e, P) e=ellinit([-111,214]); P=[35,-198]; v = [4*3,12,214,12]; e=ellchangecurve(e,v); P=ellchangepoint(P,v); ellnonsingularmultiple(e,P) e=ellinit([0,-1,1,-2,2]); test(f)=print(f(e,,'t)); print(f(e,5)); print(f(e,5,'t)); F=[ellformalw,ellformalpoint,ellformaldifferential,ellformallog,ellformalexp]; for(i=1,#F,print(F[i]);test(F[i])); ellformalw(e,0) ellformalw(e,-1) \\#1637 U=[-245369975623514803521420211420402474815373720177518420696215292670924086780233779586506792145074717/4069861969699146045958032034788970995470603578576,-696053034387689435413673877713244121475782562610666903528251447608130654196417305610237634015759861/4069861969699146045958032034788970995470603578576,-49356694805693369953216822105035107974083562942605713355717183776373331122267882948881129025418396548321363993080002121985116427859996985649385099335/4069861969699146045958032034788970995470603578576,5996724761485351384753083917633373954904218466995628499407992841502416127074022935350022919212488198205525833829916828282709837728834438536000230267/1017465492424786511489508008697242748867650894644,-1943033527672518505867347410801184866534773028979571976479290969993491996577167508758887358085512124817167326269402804641328588524702957475568608101932310746684310251168033629279636817525659690186705/4069861969699146045958032034788970995470603578576]; E=ellinit(U); P=[283188771261789732541662405743402980051199109235,39175522019721182331498476245534716069785193060995]; ellheight(E,P) \\#1648 ellinit([0,0,0,0,1]).a1 E=ellinit([-22032-15552*x,0], nfinit(x^2-2)); P=[-72*x-108,0]; ellpointtoz(E,P) E=ellinit([134199387,91266697],3031140653); P = [911071793,1086747416]; Q = ellmul(E,P,2); elllog(E,Q,P) pari-2.11.2/src/test/in/apply0000644000175000017500000000117113326135265014410 0ustar billbillapply(x->x^2, [1,2,3,4]) apply(x->x^2, [1,2;3,4]) apply(x->x^2, 4*x^2 + 3*x+ 2) apply(x->x^2, 4*x^2 + 3*x+ 2 + O(x^3)) apply(x->x^2, List([1,2,3,4])) L = List([Mod(1,3), Mod(2,4)]); apply(lift, L) f(x)=L=0;x-1; L=List(); apply(f, L); L=[1,2,3]; apply(f, L) L=[1,2,3]; [f(x) | x<-L] L=[1,2,3]; [x | x<-L, f(x)] L=[1,2,3]; select(f, L) [x|x<-Map([1,2;3,4])] fold((x,y)->x*y, [1,2,3,4]) fold((x,y)->[x,y], [1,2,3,4]) fold((x,f)->f(x), [2,sqr,sqr,sqr]) fold((x,y)->(x+y)/(1-x*y),[1..5]) printfnl(format,args[..]) = call(printf,[format,args]);print(); printfnl("%s: %s, %s",1,2,3) call("_*_",[3,5]) \\errors call(Strprintf, ["%d", 10]) pari-2.11.2/src/test/in/bnflog0000644000175000017500000000263513201017466014532 0ustar billbilldefault(parisize,"20M"); K=bnfinit(y^2+1); P2 = idealprimedec(K,2)[1]; bnflogef(K, P2) P3 = idealprimedec(K,3)[1]; bnflogef(K, P3) P5 = idealprimedec(K,5)[1]; bnflogef(K, P5) bnflogdegree(K, 6, 2) bnflogdegree(K, 6, 3) bnflogdegree(K, 6*idealmul(K,P2,P5), 5) K = bnfinit(polcompositum(y^2+y+1,y^3-2, 2)); bnflogef(K, idealprimedec(K,2)[1]) bnflogef(K, idealprimedec(K,3)[1]) bnflogef(K, idealprimedec(K,5)[1]) K = bnfinit(y^2+521951); K.cyc bnflog(K, 2) T0 = polcompositum(y^2+1,y^2-11,2); K = bnfinit(T0); K.cyc bnflog(K, 5) K = bnfinit(polcompositum(y^2+1,y^2-78,2)); K.cyc bnflog(K, 2) K = bnfinit(polcompositum(y^2+1,y^2-455,2)); K.cyc bnflog(K, 2) K = bnfinit(polcompositum(y^2+1,y^2-1173,2)); K.cyc bnflog(K, 2) K = bnfinit(polcompositum(y^2+1,y^2-1227,2)); K.cyc bnflog(K, 613) K = bnfinit(y^4+13*y^2-12*y+52); K.cyc bnflog(K, 2) bnflog(K, 3) bnflog(K, 7) K = bnfinit(polcompositum(y^2+3,y^2-1234577,2), 1); K.cyc bnflog(K, 2) bnflog(K, 3) bnflog(K, 13) K = bnfinit(polcompositum(y^2+y+1,y^2-303,2)); K.cyc bnflog(K, 2) bnflog(K, 3) bnflog(K, 5) K = bnfinit(y^5+2*y^4+18*y^3+34*y^2+17*y+3^10, 1); K.cyc bnflog(K, 2) bnflog(K, 3) K = bnfinit(polcompositum(polcyclo(5,y),y^2-5029,2)); K.cyc bnflog(K, 2) bnflog(K, 3) bnflog(K, 5) K = bnfinit(polcompositum(T0,y^2+499,2)); K.cyc bnflog(K, 5) K = bnfinit(polcompositum(T0,y^3+3*y^2+2*y+125,2), 1); K.cyc bnflog(K, 2) bnflog(K, 3) bnflog(K, 5) F=bnfinit(x^2-4565649,1); bnflog(F,2) pari-2.11.2/src/test/in/valuation0000644000175000017500000000111713201017466015257 0ustar billbilldefault(realprecision,38); a = [0, 1, 1/3, 1.0, Mod(1,2), Mod(1,3), ffgen(Mod(1,3)*(x^2+1)), 2*I, 3 + O(3^2), Mod(x,x^2+1), 2*x + 2, 3*(x +O(x^2)) ]; b = [2, 3, x, x^2+1 ]; { for (i = 1, #a, for(j = 1, #b, v = iferr(valuation(a[i],b[j]), E, "ERROR"); print1(v, " ") ); print() ) } valuation(0,1) valuation(0,-1) valuation(0,0) valuation(0,I) z=1+'x; valuation(Mod(z^2,z^3), z) valuation(y+O(y^2),x) \\ #1319 s=Mod(1,3)*(1+x); valuation((s+O(x^2)) - s,x) \\ #1336 1./(x+1)+O(x^2) \\ #1345 valuation(0*x,3) == oo 1+O(x)-1 poldegree(0) poldegree(Pol(Mod(0,3))) poldegree(0./x) pari-2.11.2/src/test/in/nfsplitting0000644000175000017500000000051213326135265015622 0ustar billbillnfsplitting(1) nfsplitting(Pol(0)) nfsplitting(Pol(1)) nfsplitting(x) nfsplitting(y) nfsplitting(x^5-x-1) nfsplitting(x^6-8) nfsplitting((x^2+1)^2) nfsplitting(x^8+3) nfsplitting(x^8+3,32) nfsplitting(nfinit(x^8+3)) nfsplitting(x^5+5/4*x+1) nfsplitting(polcyclo(23)) nfsplitting(x^7-2) nfsplitting(x^7-2,42) nfsplitting(x^7-2,43) pari-2.11.2/src/test/in/op0000644000175000017500000000017313201017466013674 0ustar billbilla = 5; a \= 2 b = 5; b \/= 2 c = 5; c >>= 2 d = 5; d <<= 1 e = 5; e %= 3 m=[a,b,c,d,e] a++ e-- m[2]-- m[3]++ m [a,b,c,d,e] pari-2.11.2/src/test/in/rnf0000644000175000017500000001274613447371554014071 0ustar billbillnf=nfinit(y^2+1); rnfidealmul(rnfinit(nf,x^4-x-1),2,3) rnfidealmul(rnfinit(nf,[x^4-x-1,10^3]),2,3) rnfidealup(rnfinit(nf,x),[;]) nf=nfinit(quadpoly(1129,y));ord=rnfpseudobasis(nf,quadray(1129,1));rnfsteinitz(nf,ord) rnflllgram(nf,x^3+2,rnfpseudobasis(nf,x^3+2)) nf=nfinit(y^2-y-4);T=x^11-11*x^10+31*x^9-26*x^8+36*x^7+7*x^6+15*x^5-27*x^4+26*x^3+20*x^2-33*x+42; rnfpseudobasis(nf,T) rnfpseudobasis(nf,[T,10^3]) T = x^2+1009^3*(10^6+3)^2*y; rnfpseudobasis(nf,T) rnfpseudobasis(nf,[T,100]) rnfpseudobasis(nf,[T,1010]) rnfdisc(nf,T) rnfdisc(nf,[T,100]) rnfdisc(nf,[T,1010]) Q = bnfinit(y); T=x^4+x^3-71*x^2+72*x+5184; rnfconductor(Q,T) rnfconductor(Q,[T,10^3]) rnfconductor(Q,galoissubcyclo(117,116))[1] K=bnfinit(quadpoly(1596,y),1); rnfbasis(K,rnfsteinitz(K,rnfpseudobasis(K,quadray(K,1)))); K = nfinit(x^2-x+2); M = [1, 0, x; 0, x, 0; 0,0,2+x]; N = [1, 1, 1]; nfsnf(K, [M, N, N]) rnfisabelian(y,x) rnfisabelian(y^2+23,x^3+x^2-1) T = polcyclo(7, x+Mod(y, nf.pol)); rnfisabelian(nf.pol, T) rnfisabelian(nf, T) rnfisabelian(a^2+1,5*x^3+2) rnfisabelian(4*a^2+1, 9*x^2 + (12*a+3)*x + 2*a) rnfisabelian(y^4+2,polsubcyclo(13,6)) pol = y^3+y^2-2*y-1; bnf = bnfinit(pol); T=rnfisnorminit(bnf, x^3-y); do(T,u,flag=0)=liftpol(rnfisnorm(T,u,flag)); do(T,y) [a,b]=rnfisnorm(T,2,100); liftpol(norm(a)*b) [a,b]=rnfisnorm(T,2,-2*3*5*7); liftpol(norm(a)*b) T=rnfisnorminit(y^2+23, x^2-y); do(T,y) do(T,2,100) \\#1157 rnfisnorminit(y,x^2-Mod(2+y,y)); \\#1778 K = bnfinit(x^4-2*x^3-27*x^2+28*x+53); t = varhigher("t"); L = rnfisnorminit(K,t^2-310*x^3+465*x^2+11005*x-274660); [a,b]=rnfisnorm(L,-28124/93*x^3+14062/31*x^2+562480/93*x+166769/31); liftpol(norm(a)*b) \\#1255 K = nfinit(z^3+z^2-2*z-1); rnf = rnfinit(K, x^2+Mod(-z,z^3+z^2-2*z-1)*x+1); a = rnfeltup(rnf,z^2) rnfeltdown(rnf, a) setrand(1);a=matrix(3,4,j,k,vectorv(3,l,random(21))); idx=idealprimedec(K,3)[1]; aid=[idx,1,1,1]; [A,U]=nfhnf(K,[a,aid],1); A U lift(matbasistoalg(K,a)*matbasistoalg(K,U)) a=a[,1..3]; [A,U,V]=nfsnf(K,[a, aid[1..3], [1,1,1]],1); A U V lift(matbasistoalg(K,U)*matbasistoalg(K,a)*matbasistoalg(K,V)) nf=nfinit(y); A = [[1,1/2;0,1],[1,1]]; nfhnfmod(nf, A, nfdetint(nf,A)) K=bnfinit(y^2-40); bnfisnorm(K,2, 0) bnfisnorm(K,6, 0) K=bnfinit(y^3-21); bnfisnorm(K,2) bnfisnorm(K,6) L=rnfinit(K,x^2-y); v = [2,1/2,x+y,Mod(1,K.pol),Mod(1/2,K.pol),Mod(y,K.pol),Mod(1,L.polabs),Mod(1/2,L.polabs),Mod(x,L.polabs),Mod(x+y/2,L.pol),y,z,Mod(y+1/2,y^2+1),[1]~,[1,2]~,[1,y]~,[1,I]~, y+I,x^2]; f=[rnfalgtobasis,rnfbasistoalg,rnfeltabstorel,rnfeltreltoabs,rnfeltup,rnfeltdown,rnfelttrace,rnfeltnorm]; test(L,v) = { for (i=1,#v, for (j=1,#f, print([i,j], ": ", iferr(f[j](L,v[i]), E,E))) ); my (K = L.nf); for (i=1,#v, print(i, ": ", iferr(rnfcharpoly(K,x^2-y,v[i]),E,E)) ); } test(L,v); KQ = nfinit(y+1); LQ = rnfinit(KQ, x^2-y); vQ = [2,1/2,x+y, Mod(1/2,KQ.pol), y, Mod(Mod(x/2+1,KQ.pol),LQ.pol), Mod(x,LQ.pol), Mod(x,LQ.polabs), Mod(x+y/2,x^2-y), x, [1]~,[1,2]~,[y]~]; test(LQ, vQ); nf = nfinit(y); rnf = rnfinit(nf,x^2-2); rel = Mod(Mod(1,y)+0*y,x^2-2); a = rnfeltreltoabs(rnf,rel) variable(lift(a)) Labs = nfinit(L); idL = idealhnf(Labs, x^3+x^2+10); idK = idealhnf(K, y^2+10*y+5); id = rnfidealabstorel(L,Labs.zk*idL) rnfidealnormabs(L,id) == idealnorm(Labs, idL) m = rnfidealreltoabs(L, id) mathnf(matalgtobasis(Labs,m)) == idL P3 = idealprimedec(K,3); \\ pr[5] depends on 32/64-bit arch strip5(pr)=pr[1..4]; apply(strip5, rnfidealprimedec(L, P3[1])) my(v=rnfidealprimedec(L,7)); [apply(strip5, v[1]), apply(strip5, v[2][1])] rnffa(rnf,id)=my(fa=rnfidealfactor(rnf,id)); fa[,1] = apply(strip5,fa[,1]); fa; rnffa(L,7) rnffa(L,x) rnffa(L,y) rnfidealfactor(L,id) == rnfidealfactor(L,idL) m = rnfidealup(L, idK) mabs = rnfidealup(L, idK, 1); mathnf( Mat(apply(x->nfalgtobasis(Labs,x), m)) ) == mabs rnfidealdown(L, m) == idK rnfidealdown(L, mabs) == idK m = rnfidealdown(L, Labs.zk*idL) M=rnfidealup(L, m) mathnf(matalgtobasis(Labs,M)) == rnfidealup(L, m, 1) \\ V=concat(v, [[;], [], 0, [[;],[]], idealprimedec(K,2)[1], idK, idL, Labs.zk*idL, id]); f=[rnfidealhnf,rnfidealreltoabs,rnfidealabstorel,rnfidealdown,rnfidealup,rnfidealnormrel,rnfidealnormabs,rnfidealtwoelt]; { for (i=1,#V, print(i,":"); for (j=1, #f, print(iferr(f[j](L,V[i]),E,E)) ) ) } rnfidealmul(L, 0,1) rnfidealmul(L, 1,0) rnfidealmul(L, x,y) rnfidealmul(L, y,x) rnfidealmul(L, id,x) rnfidealmul(L, x,id) rnfdet(K,[[;],[]]) rnfdet(K,id) rnfbasis(bnfinit(y^2-1105),x^2-y) \\#1508 K=nfinit(y); L=rnfinit(K,x^3-2); rnfeltdown(L,Mod(Mod(1,K.pol),L.polabs)) k1=bnfinit(y^3+y^2-2*y-1); u=x^3+y*x^2+(y-2)*x+(y^2-y-1); rnfconductor(k1,u) K = nfinit(y^2+y+1); rnfislocalcyclo(rnfinit(K, x^3-2)) rnfislocalcyclo(rnfinit(K, x)) rnfislocalcyclo(rnfinit(K, x^3 - y)) rnfislocalcyclo(rnfinit(K, x^3 - y + 3^6)) nf=nfinit(y^2+9); \\ 3 divides index P=idealprimedec(nf,3)[1]; rnfdedekind(nf, (x+y/3)^3+3*y, P) nf = nfinit(y^2-3); P = x^3 - 2*y; pr3 = idealprimedec(nf,3)[1]; pr2 = idealprimedec(nf,2)[1]; rnfdedekind(nf, P, pr2) rnfdedekind(nf, P, pr3) rnfdedekind(nf, P, pr2, 1) rnfdedekind(nf, P, pr3, 1) rnfdedekind(nf, P) rnfdedekind(nf, P, [pr2,pr3]) P = (y+1)*x^4 + x^2 + x + 2; rnfdedekind(nf, P, pr3, 1) t = 't; T = polcyclo(9,t); pol = y^2 + Mod(t^5+t^2+t-1, T)*y + Mod(1-t, T); Qchi=nfinit([T,10^6]); rnfinit(Qchi,[pol,10^6]); \\ segv in 2.11 \\ Errors, keep at end of file rnfdedekind(nf, P, pr2, 1) rnfdedekind(nf, P) rnfdedekind(nf, P, [pr2,pr3]) rnfislocalcyclo(rnfinit(K, x^6-y+1)) \\#1530 L=rnfinit(nfinit(y^2-3),x^2+23); rnfidealtwoelt(L, [[1;0], [1/104]]) \\#2093 nf = nfinit(y); rnf = rnfinit(nf,x^2+5); rnfidealup(rnf,Mat(3),1); pari-2.11.2/src/test/in/cmp0000644000175000017500000000112713201017466014035 0ustar billbilltest(f,g)=[cmp(f,f), cmp(f,g), cmp(g,f)] test(()->1, ()->2) test(1.,2.) test(1,2) test(Vecsmall([1,2]),Vecsmall([1,3])) test(List([1,2]),List([1,3])) test(x,x+1) test(x,y) test(O(x),x+O(x^2)) v=[-oo, 1/2, 1, oo]; for (i=1, #v, for(j=i+1,#v, if( v[i] >= v[j], error([i,j])))); for (i=1, #v, for(j=i+1,#v, if( !(v[i] < v[j]), error([i,j])))); for (i=1, #v, if(!(v[i] == v[i]), error(i))); for (i=1, #v, if(!(v[i] === v[i]), error(i))); Mod(1,3) > 0 lex(Vecsmall([1,2]),Vecsmall([1,3])) ["x"<="y", "x"<="x", "x"<="w"] [oo <= -oo, oo <= oo, -oo <= -oo] 1. <= oo 1. <= -oo 1 <= 'x 1. <= 'x 1/2 <= 'x pari-2.11.2/src/test/in/character0000644000175000017500000000250713326135265015223 0ustar billbillG=[15,5]; chi=[1,1]; charker(G,chi) charconj(G,chi) charorder(G,chi) G=znstar(100,1); a=[1,0]; A=znconreylog(G,a); m=znconreyexp(G,a); charker(G,a) charker(G,A) charker(G,m) charpow(G,a,0) charpow(G,A,0) charpow(G,m,0) charpow(G,a,-2) charpow(G,A,-2) charpow(G,m,-2) charpow(G,a,3) charpow(G,A,3) charpow(G,m,3) charconj(G,a) charconj(G,A) charconj(G,m) charorder(G,a) charorder(G,A) charorder(G,m) b=[12,1]; B=znconreylog(G,b); n=znconreyexp(G,b); charmul(G,n,m) charmul(G,a,b) charmul(G,A,B) charmul(G,a,B) charmul(G,a,n) charmul(G,m,B) chardiv(G,n,m) chardiv(G,a,b) chardiv(G,A,B) chardiv(G,a,B) chardiv(G,a,n) chardiv(G,m,B) test(G)= { my(N = G.mod,D); print("* ",N); for(i=1,N, if(gcd(N,i)!=1,next); D = znchartokronecker(G,i);if (!D,next); D0 = znchartokronecker(G,i,1); print(i,": ",[D,D0]); chi = znconreylog(G,i); if (vector(N,j,kronecker(D,j)) != vector(N,j,chareval(G,chi,j,[-1,2])), error(D)) ); } test(G) test(znstar(8,1)) test(znstar(5,1)) test(znstar(1,1)) test(D) = { my([G,cyc]=znchar(D), C = znconreylog(G,cyc)); [cyc, C, znconreyexp(G,C), charorder(G,cyc)]; } test(1) test(5) test(Mod(1,5)) test(Mod(3,5)) G = znstar(100,1); test([G,13]) test([G,[0,19]~]) test([G,[2, [1,1]]]) \\ Errors znchar(0) znchar(2) znchar(3) znchar([]~) znchar([1,2,3]) znchar([1,2]) znchar([znstar(100,1), [1,2,3]]) pari-2.11.2/src/test/in/ploth0000644000175000017500000000420513457566440014422 0ustar billbill\e \p19 default(parisize,"20M"); t=plothsizes(); plotinit(0,t[1]-11,t[2]-11) plotscale(0,0,1000,0,1000); plotbox(0,500,500) plotdraw(0) write("pari0.svg", plotexport("svg", 0)) plotcolor(0,2); plotmove(0,0,900); plotlines(0,900,0) plotlines(0,vector(5,k,50*k),vector(5,k,10*k*k)) plotmove(0,243,583); plotcursor(0) plot(x=-1,1,floor(x)) plot(x=-1,1,-floor(x)) plot(x=0,1,-0.29) plot(x=-5,5,sin(x)) ploth(x=-5,5,sin(x)) ploth(t=0,2*Pi,[sin(5*t),sin(7*t)]) ploth(t=0,2*Pi,[sin(5*t),sin(7*t)],"Parametric",100) ploth(t=0,2*Pi,[sin(5*t),sin(7*t)],"Parametric|Recursive",100) plothraw(vector(501,k,k-1),vector(501,k,(k-1)*(k-1)/500)); plothraw(vector(501,k,k-1),vector(501,k,(k-1)*(k-1)/500),1); plotpoints(0,225,334) plotpoints(0,vector(10,k,10*k),vector(10,k,5*k*k)) write("pari1.svg", plothexport("svg", x=-5,5,sin(x))); write("pari2.svg", plothrawexport("svg", vector(501,k,k-1),vector(501,k,(k-1)*(k-1)/500),1)); plotmove(0,50,50);plotrbox(0,50,50) plotrline(0,150,100) plotcolor(0,4); plotcursor(0) plotrmove(0,5,5); plotcursor(0) plotrpoint(0,20,20) plotmove(0,100,100); plotstring(0,Pi) plotmove(0,200,200); plotstring(0,"(0,0)") plotdraw([0,10,10]) write("pari3.svg", plotexport("svg",[0,10,10])) ploth(x=0,1, x^3,"Splines") ploth(x=0,1, [x^2,x^3],"Parametric|Splines") plotinit(1); plotcopy(0,1, 300,0); plotclip(1); plotdraw([1,10,10]); plotkill(1); plotinit(1); plotcopy(0,1, 1/2,0, 1); plotclip(1); plotdraw([1,10,10]); plotkill(1); plotinit(1); plotcopy(0,1, 1/2,1/3, 3); plotclip(1); plotdraw([1,10,10]); plotkill(1); plotinit(1); plotcopy(0,1, 1/3,1/3, 5); plotclip(1); plotdraw([1,10,10]); plotkill(1); plotinit(1); plotcopy(0,1, 1/3,1/3, 7); plotclip(1); plotdraw([1,10,10]); /*errors*/ plotinit(-1) plotinit(100) plotmove(-1,0,0) plotmove(100,0,0) plotcopy(0,1,2,1,1) plotcopy(0,1,-1,1,1) plotcopy(0,1,1,2,1) plotcopy(0,1,1,-1,1) ploth(x=0,2*Pi,if (x <1, [cos(x),sin(x)], 1),"Parametric") ploth(t=0,2*Pi,[sin(5*t),sin(7*t)],"Recursive",100) ploth(x=0,2*Pi,1,"Parametric") ploth(x=0,1,x,,1) default(graphcolormap,["white","black","gray","violetred","red","green","blue","gainsboro","purple"]) default(graphcolors,[7,4,9,8,5,6]) ploth(X=-1,9,vector(6,k,sin(X+k))) pari-2.11.2/src/test/in/exact00000644000175000017500000000112411636712103014437 0ustar billbilldefault(realprecision,38); Mod(0,2)*x*1. Pol(Mod(0,2)) + 2 Mod(1,2)+Pol(Mod(1,2)) Ser(Mod(1,2)) + 1 (2+0*I)+I*Mod(0,4) a=b=Mod(2, 4) + Mod(2, 4)*I; a*b (Mod(0,2)+I)^2 Mod(0,2)/x a=Mod(1, 2)*x^10 + Mod(1, 2); 2*a a+a valuation(Mod(0,101),101) gcd(Mod(0,5),10) gcd(Mod(0,5),Mod(0,10)) { v = [[0,0,0,0], [0,0,0,Mod(0,2)], [1,0,0,Mod(0,2)], [1,0,0.,Mod(0,2)], [1,0,Mod(0,2),0.]]; for (i = 1, #v, w = v[i]; print1(Pol(w), " "); print1(Polrev(w), " "); print1(Ser(w), " "); w = vecextract(w, "-1..1"); print1(Pol(w), " "); print1(Polrev(w), " "); print1(Ser(w), " "); print(); ) } pari-2.11.2/src/test/in/bnrisgalois0000644000175000017500000000041013201017466015564 0ustar billbillK=bnfinit(a^4-3*a^2+253009);B=bnrinit(K,9,1);G=galoisinit(K); S=vecsort(subgrouplist(B,3)); map=Map();for(i=1,#S,mapput(map,S[i],i)); [H|H<-S, bnrisgalois(B,G,H)] M=bnrgaloismatrix(B,G) [H|H<-S, bnrisgalois(B,M,H)] [[mapget(map,bnrgaloisapply(B,m,s))|s<-S]| m<-M] pari-2.11.2/src/test/in/modfun0000644000175000017500000000033213447371554014560 0ustar billbilldefault(realprecision,38) eta(2+O(2^20)) eta(x+x^2+x^3+x^4+O(x^5)) eta(x+2*x^2+ O(x^5)) eta(I) ellj(2+O(2^20)) ellj(x+x^2+x^3+x^4+O(x^5)) ellj(x+O(x^70)) theta(1/2,I) weber(1.0*I,1) weber(1+I) \\errors eta(0) eta(1/2) pari-2.11.2/src/test/in/algsplit0000644000175000017500000001165713326135265015114 0ustar billbillsetrand(1) vec2mat(d,n,V) = { my(M = matrix(d,d), x = 'x, c); for(i=0,d^2*n-1, c = V[i+1]; M[i\(n*d) + 1, (i\n)%d + 1] += c*x^(i%n) ); c = polcoeff(M[1,1],0); for(i=2,d,M[i,i]+=c); M }; mat2vec(d,n,M) = { my(V = vector(d^2*n), c = polcoeff(M[1,1],0)); for(i=2,d,M[i,i]-=c); for(i=1,d, for(j=1,d, for(k=0,n-1, V[n*d*(i-1) + n*(j-1) + k + 1] = polcoeff(M[i,j],k); ) ) ); V }; matalg(d,n,p) = { my(pol = ffinit(p,n), mtx, N=d^2*n, x, basis, mt=vector(N)); basis = vector(N,i,vec2mat(d,n,vector(N,k,k==i))); basis = basis*Mod(1,p)*Mod(1,pol); for(i=1,N, x = basis[i]; mtx = matconcat(vector(N,j,mat2vec(d,n,liftall(x*basis[j]))~)); mt[i] = mtx; ); algtableinit(mt,p) }; smallchg(mt,p) = { my(i,j,N=#mt,c); if(N==1, return(mt)); if(p, c=random([1,p-1]), c=1); i = random([2,N]); j=i; while(j==i,j=random([1,N])); for(k=1,N, mt[k][,i] += c*mt[k][,j]; mt[k][j,] -= c*mt[k][i,]; ); mt[i] += c*mt[j]; if(p,mt%p,mt) }; chg(mt,nb=3*#mt,p=0) = { for(c=1,nb,mt=smallchg(mt,p)); mt }; test2(d,n,p,nb=1) = { my(al,mt,mt2,res,map,x,y,Mx,My); setrand(1); al = matalg(d,n,p); mt = algmultable(al); mt2 = mt; for(c=1,nb, if(c>1, mt2 = chg(mt2,#mt\4 + 5,p)); al = algtableinit(mt2,p); res = algsplit(al,'t); map = res[1]; mapi = res[2]; x = algrandom(al,10); y = algrandom(al,10); Mx = map*x; My = map*y; if(Mx*My != map*algmul(al,x,y), print("FAIL"); return(0)); ); [al,map,mapi] }; print("M_2(F_4)"); test2(2,2,2,200); print("M_2(F_9)"); test2(2,2,3,100); q = 31; print("M_2(F_31^2)"); test2(2,2,q,30); p = nextprime(10^20); print("M_2(F_p^2)"); test2(2,2,p,30); print("M_d(F_31^n)"); for(d=1,4,for(n=1,min(18\(d^2),10),print("d=",d," n=",n);if(!test2(d,n,q,10), break(2)))); isblock(M,L) = { my(d,mini,nxt); d = #M[,1]; mini=L[1]; nxt=2; for(j=1,d, if(j>mini, mini += L[nxt]; nxt += 1; ); for(i=mini+1,d, if(M[i,j]!=0,return(0)); ); ); 1 }; matblock(L,n,p) = { d = sum(i=1,#L,L[i]); al0 = matalg(d,n,p); basis = [b | b<-Vec(matid(d^2*n)), isblock(vec2mat(d,n,b),L)]; basis = Mat(basis); algsubalg(al0,basis)[1]; }; print("examples from documentation"); al0 = alginit(nfinit(y^2+7), [-1,-1]); al = algtableinit(algmultable(al0), 3); \\isomorphic to M_2(F_9) [map,mapi] = algsplit(al, 'a); x = [1,2,1,0,0,0,0,0]~; fx = map*x y = [0,0,0,0,1,0,0,1]~; fy = map*y map*algmul(al,x,y) == fx*fy map*mapi[,6] print("bad input"); algsplit("toto"); algsplit(alginit(nfinit('y),[-1,-1])); algsplit(algtableinit([matid(3),[0,0,0;1,1,0;0,0,1],[0,0,0;0,0,0;1,0,0]],2)); algsplit(algtableinit([matid(2),[0,0;1,1]],2)); algsplit(matblock([2,1,1,1],1,q)); algsplit(matblock([1,2,3],1,q)); {mt=[[1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 1; 0, 0, 0, 1, 0, 0, 1, 0, 0; 0, 1, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0, 1; 0, 0, 0, 0, 1, 1, 0, 0, 0; 1, 0, 0, 0, 1, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 1, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1; 0, 0, 0, 0, 0, 0, 0, 0, 1; 1, 0, 0, 0, 0, 0, 0, 0, 0; 0, 1, 1, 0, 0, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 1; 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 1, 0; 0, 1, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 1; 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 1, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1; 0, 0, 0, 0, 1, 0, 0, 0, 0; 1, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 1, 0, 0, 0, 0, 1; 0, 1, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1; 0, 0, 0, 1, 0, 0, 1, 0, 0; 0, 0, 0, 0, 1, 1, 0, 0, 0; 0, 1, 1, 0, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0, 0, 1, 0; 1, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 1, 1, 0, 0, 0; 0, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1; 0, 1, 1, 0, 0, 0, 0, 0, 0; 1, 0, 0, 0, 0, 1, 0, 0, 0; 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 1, 0; 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 1; 0, 0, 0, 0, 1, 1, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 1, 0; 0, 1, 0, 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 0; 1, 0, 0, 0, 1, 0, 0, 0, 0]]}; algsplit(algtableinit(mt,2)); pari-2.11.2/src/test/in/div0000644000175000017500000000150613326135265014047 0ustar billbilldefault(realprecision,38); v=[3,4,3.1,1/2,x^2+1, Mod(x,x^2+1),ffgen(3^5,'t),quadgen(5),2+O(3^3),Mod(2,3), 2^64 + 1]; { for (i=1,#v, for(j=1,#v, print("* ",[i,j]); print(iferr(v[i]/v[j],E,E)); print(iferr(v[i]\v[j],E,E)); print(iferr(v[i]%v[j],E,E)); print(iferr(v[i]\/v[j],E,E)); print(iferr(divrem(v[i],v[j]),E,E)); ) ) } w=[x + O(x^2),[2,3],Mat(2)]; { for (i=1,#w, for(j=1,#v, print("* ",[i,j]); print(iferr(w[i]/v[j],E,E)); print(iferr(w[i]\v[j],E,E)); print(iferr(w[i]%v[j],E,E)); print(iferr(w[i]\/v[j],E,E)); ) ) } for (i=2,#w, print(w[i]%2)) for (i=2,#w, print(w[i]\2)) divrem(x+y^2,y+x,y) divrem([3,5],2) divrem(1,x) divrem(1,Pol(1)) divrem(1,"a") (5/3) \/ 1 floor((x^2+1)/x) []/0 []~/0 [;]/0 [1]/0 m=Mod(1,ffinit(3,3,a));P=(x^8+a*x^2+x+a)*m;Q=(x^5+4*x^3+a*x+(a^2+1))*m;P%Q pari-2.11.2/src/test/in/analyz0000644000175000017500000000032213326135265014556 0ustar billbillHEAP=[10, if(sizebyte(0)==16,94,102)]; default(realprecision,38); \e sum(x=0,50000,x); sum(x=1,1000,log(x)); sum(x=1,25,sum(y=1,100,x/y),0.0); sum(x=1,100,sum(y=1,100,x/y,0.0)); if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/nfhilbert0000644000175000017500000000301313036414402015224 0ustar billbillnf=nfinit(y^3-1009); P = primes(20); pr = idealprimedec(nf,1009)[1]; a = y^11*(y+1)*101; b = y^5*(y+3)*19; vector(#P, i, nfhilbert(nf, a, P[i]*b, pr)) pr = idealprimedec(nf,19)[1]; a = 19^11*(y+1)*101; b = 19^5*(y+3)*19; vector(#P, i, nfhilbert(nf, a, (1+P[i]*y)*b, pr)) /* old regression cases: */ nf=nfinit(y^2+1); pr=idealprimedec(nf,2)[1]; nfhilbert(nf, [1,1]~, 3, pr) nfhilbert(nf, Mod(0,3), 3, pr) nfhilbert(nf, 3, 0., pr) nfhilbert(nf,[1,-2]~,[1,-2]~, pr) nf=nfinit(y^2+3); nfhilbert(nf,[3,0]~,[3,0]~,idealprimedec(nf,2)[1]) \\ #1147 K = nfinit(x^5-23); p = idealprimedec(K, 2)[1]; nfhilbert(K,x,-x^2-5*x,p) K = nfinit(x^8 + 2*x^7 + 3*x^6 + 3*x^4 + 3*x^2 + 2*x + 3); p = idealprimedec(K, 2)[1]; { for (j = 1,10, setrand(j); a = vectorv(8,i,random(7)); b = vectorv(8,i,random(7)); c = vectorv(8,i,random(7)); d = nfeltmul(K,b,c); if (nfhilbert(K, a,b,p) * nfhilbert(K, a,c,p) != nfhilbert(K, a,d,p), error([a,b,c])) ) } L = [2, 3, 1.0, Mod(1,2), Mod(1,4), Mod(1,8), Mod(1,3), Mod(0,5), 1 + O(2^2), 1 + O(2^3), 1 + O(5)]; for (i=1,#L, for(j=i+1,#L, print([i,j], ": ", iferr(hilbert(L[i],L[j]), E, E)))) print("p = 0:"); for (i=1,#L, print(i, ": ", iferr(hilbert(L[i],L[i], 0), E, E))) print("p = 2:"); for (i=1,#L, print(i, ": ", iferr(hilbert(L[i],L[i], 2), E, E))) print("p = 5:"); for (i=1,#L, print(i, ": ", iferr(hilbert(L[i],L[i], 5), E, E))) \\#1251 hilbert(-1,-1,0) \\#1261 K=nfinit(y^2+5); P=idealprimedec(K,2)[1]; nfhilbert(K,2*y,2,P) \\#1569 K=nfinit(x^3-4*x+2); nfhilbert(K,2,-2, idealprimedec(K,2)[1]) pari-2.11.2/src/test/in/partition0000644000175000017500000000163213272053420015266 0ustar billbilltest(N) = /* pentagonal numbers recurrence */ { my(s,t,p); p = vector(N); p[1] = 1; for (n=1, N-1, s = 0; t = n+1; for (k=1, n, t -= 2*k-1; /* n+1 - k(3k-1)/2 */ if (t<=0,break); s -= (-1)^k*p[t]; t -= k; /* n+1 - k(3k+1)/2 */ if (t<=0,break); s -= (-1)^k*p[t] ); p[n+1] = s; if (s != numbpart(n), error([n, s])) ); } test(10^4); numbpart(0) numbpart(52602) numbpart(147007) numbpart(10^15+2) partitions(0) partitions(1) partitions(9) partitions(9,3) partitions(-1) partitions(5,[3,4],[1,2]) for(i=1,5,print(partitions(i,[0,5],[3,4]))) forpart(v=-1,) forpart(v=5,print(Vec(v)),4,3) forpart(v=5,print(Vec(v)),[0,5],[2,4]) my(i=0); forpart(x=55,i++); i forpart(x=9,print(Vec(x))); forpart(x=11,print(Vec(x)),,5); forpart(x=12,print(Vec(x)),,[2,6]); forpart(x=23,print(Vec(x)),[3,6]); forpart(x=5, print(Vec(x)),[0,3]); forpart(x=15, print(Vec(x)),[0,3],7); pari-2.11.2/src/test/in/charpoly0000644000175000017500000000475513457566442015131 0ustar billbillcharpoly([x,x+1;1,2],y,0) charpoly([x,x+1;1,2],y,1) charpoly([x,x+1;1,2],y,2) charpoly([x,x+1;1,2],y,3) charpoly([0,0,2,2;0,0,2,2;2,2,0,0;2,2,0,0]) charpoly([0,0,2,2;0,0,2,2;2,2,0,0;2,2,0,0],,4) minpoly(matrix(4,4,i,j,i/j)) default(realprecision,38); A=[5/3,7/45;0,21/10]; mateigen(A) mateigen(A*1.) mateigen(A,1) merror=[224,221,13,2;201,199,12,2;100,99,6,1;85,84,5,1]; [D,M]=mateigen(merror,1); D exponent(merror*M - M*matdiagonal(D)) M=[x,x+y;x+1,1];charpoly(M,w) v=[1,1.,Mod(1,3),1/2,1+O(3),I,quadgen(5),matid(2)*Mod(1,3),matid(2)*Mod(1,2^64+13)]; for(i=1,#v,print(charpoly(v[i]))) { \\ #2010 g(s2,s3)=s6=s2*s3;[2,0,0,-s6+3,2*s3-3*s2,3*s3-3*s2; 0,-2,0,s3-s2,-s6+2,-s6+3; 0,0,-1,s3-2*s2,-s6+1,-s6+3; 0,0,s3,2*s6-6,-5*s3+6*s2,-6*s3+7*s2; -2*s3,2,-s6+5,-7*s3+10*s2,8*s6-21,9*s6-27; 2*s3,-2,s6-5,8*s3-11*s2,-9*s6+23,-10*s6+30]/2; } exponent(charpoly(g(sqrt(2),sqrt(3))) - (x^6-x^5-3*x^4-3*x^3-3*x^2-x+1)) < -120 centerlift(charpoly(g(sqrt(2+O(23^10)), sqrt(3+O(23^10))))) charpoly(matid(4),,0) charpoly(matid(4),,3) charpoly(matid(4)*(2^64+13)) m=[1,2,3,4;5,6,7,8;9,10,11,12;1,5,7,11]; charpoly(m*Mod(1,3)) charpoly(m*Mod(1,2^64+13)) matadjoint(matid(2),1) matadjoint([;]) matadjoint(Mat(1)) matadjoint([x,0,0;0,0,0;0,0,0]) matadjoint([Mod(1,2)*x,0,0;0,0,0;0,0,0]) charpoly(x*matid(3)) minpoly(Mod(x+1,x^4+1)) minpoly(Mod(x,x^2)) minpoly(Mod(1,x^2+x+1)) minpoly(Mod(1,x^24+1)) minpoly(Mod(1,x^2)) a=[1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0;0,1,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0;0,0,1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0;-1,-1,-1,4,0,0,0,0,-1,0,0,0,0,0,0,0,0;0,0,0,0,1,0,0,-1,0,0,0,0,0,0,0,0,0;0,0,0,0,0,1,0,-1,0,0,0,0,0,0,0,0,0;0,0,0,0,0,0,1,-1,0,0,0,0,0,0,0,0,0;0,0,0,0,-1,-1,-1,4,-1,0,0,0,0,0,0,0,0;0,0,0,-1,0,0,0,-1,4,-1,-1,0,0,0,0,0,0;0,0,0,0,0,0,0,0,-1,1,0,0,0,0,0,0,0;0,0,0,0,0,0,0,0,-1,0,4,-1,-1,-1,0,0,0;0,0,0,0,0,0,0,0,0,0,-1,1,0,0,0,0,0;0,0,0,0,0,0,0,0,0,0,-1,0,1,0,0,0,0;0,0,0,0,0,0,0,0,0,0,-1,0,0,3,-1,0,-1;0,0,0,0,0,0,0,0,0,0,0,0,0,-1,3,-2,0;0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,2,0;0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,1]; mateigen(a); mateigen([;]) mateigen([;],1) mateigen(Mat(1)) mateigen(Mat(1),1) t=sqrt(5); M=[1,-1,0,0,0,0,0;-1,1,0,0,0,0,0;0,0,1,(t-1)/4,(-t-1)/4,(-t-1)/4,(t-1)/4;0,0,(t-1)/4,1,(t-1)/4,(-t-1)/4,(-t-1)/4;0,0,(-t-1)/4,(t-1)/4,1,(t-1)/4,(-t-1)/4;0,0,(-t-1)/4,(-t-1)/4,(t-1)/4,1,(t-1)/4;0,0,(t-1)/4,(-t-1)/4,(-t-1)/4,(t-1)/4,1]; mateigen(M) mateigen(M,1) \\ Errors, keep at end of file charpoly(Mod('b, 'b^2 + Mod('a,'a^2+1)), 'newvar) minpoly(Mod(y,x), 'y) localbitprec(32);mateigen(merror*bitprecision(1.,64)) pari-2.11.2/src/test/in/concat0000644000175000017500000000120113036414402014513 0ustar billbillA=[1,2;3,4]; B=[5,6]~; C=[7,8]; D=9; matconcat([A, B]) matconcat([A, C]~) matconcat([A, B; C, D]) matconcat([1, [2,3]~, [4,5,6]~]) matconcat([1, [2,3], [4,5,6]]~) matconcat([B, C; A, D]) matconcat([]) concat("x",2) concat([;],1) concat([;],[]) concat([;],[1]) concat(1,[;]) concat([],[;]) concat([1],[;]) concat(1,2) concat(1,[2]) concat(1,Mat(2)) concat(1,A) concat(Mat(2),1) concat(A,1) concat([1,2],[]~) concat([1,2],[1]~) concat([1,2],[1,2]~) concat([2,3], matid(2)) concat([]~,[1,2]) concat([3]~,[1,2]) concat([2,3]~,[]) concat([2,3]~,[1]) concat([2,3]~,[1,2]) concat([;],[]) concat(A,[1,2]) concat(List([[1],[2]])) concat([1]~,Mat(2)) pari-2.11.2/src/test/in/factormod0000644000175000017500000000250313457566437015257 0ustar billbillprint(lift(factorcantor(x^1024+1,12289))) check(P,p)= { my(F=factormod(P,p)); my(G=factorcantor(P,p)); if(F!=G || factorback(F)!=P,error(P)); F[,1]=apply(poldegree,F[,1]); F~; } setrand(4); check(y^3-3*y-1,2238004061) \\#1451 check(x^31+x^30+x^29+x^28+x^26+x^24+x^23+x^21+x^16+x^15+x^14+x^11+x^10+x^9+x^8+x^7+x^3+x^2+x,2) localbitprec(1000);check(Polrev(binary(round(Pi*2^1000))),2) polrootsmod(x^16-1,41) polrootsmod(x^5+x^2-4*x+2,5) polrootsmod(Pol(1),2) factorcantor(x^3+x,2) factormod(Pol(0),2) factormod(Pol(0),2,1) factormod(Pol(1),2) factormod(Pol(1),2,1) f=(x^2+x+1)*(x^3+x); factormod(f,2,1) factormodSQF(f,2) factormodDDF(x^4+x,2) polrootsmod(x^5+4*x^4+2*x^3+x^2+4*x+2,7) p=2^64+13; polrootsmod(Pol(1),p) polrootsmod(x,p) polrootsmod(2*x+1,p) factormod(x^2+1,p) factormod(x^2+1,p,1) factormod(x^2+3,p,1) factormod(x^4+1,p) factormod(x^4+1,p,1) factormod(x^4+3,p,1) factorcantor(x^2+1,p) factorcantor(Pol(0),p) factorcantor(Pol(1),p) factormodSQF(Pol(1),p) factormodDDF(Pol(1),p) polisirreducible((x^2+x+1)*Mod(1,2)) polisirreducible((x^2+1)*Mod(1,p)) polisirreducible(Mod(x^4+x^2+x,2)) \\#2037 factormod((x+1)^2, 10^20+39) \\ errors, keep at end of file polrootsmod(x^3-1, 2^101-1) polrootsmod(x^10-1, 1023) polrootsmod(Pol(0),p) polrootsmod(Pol(0),2) factormod(x,0) factormod(x^3+1,[y^2+1,2]) factormod(x^3+1,[y^2+1,5]) pari-2.11.2/src/test/in/arith0000644000175000017500000000031013326135265014364 0ustar billbill\\#1304 issquarefree(0) \\#1412 core(4*10^15+27) { forfactored(d=-100,100, if (issquarefree(d[1]) != issquarefree(d[2]), error(d)); if (isfundamental(d[1]) != isfundamental(d[2]), error(d)) ); } pari-2.11.2/src/test/in/ellanal0000644000175000017500000000172113460025361014666 0ustar billbilldefault(realprecision,38); rk(x)=x=ellinit(x);ellanalyticrank(x); rk([0, -1, 1, -10, -20]) rk([0, 0, 1, -1, 0]) rk([0, 1, 1, -2, 0]) rk([0, 0, 1, -7, 6]) rk([-5187, 176830]) he(x)=x=ellinit(x);ellheegner(x); he([1, 1, 0, -1297, -18530]) he([0, -1, 1, -33, 93]) he([-157^2,0]) he([0,0,-9/484,0,-27/234256]) getheap()[1] E=ellinit([0,-1437004800,0,458885065605120000,0]); ellglobalred(E); ellheegner(E) L = ellinit([0,0,1,7,6]); ellL1(L) ellL1(L,1) ellL1(L,3) ellL1(ellinit([0,1,1,-2,0]),2) default(realprecision,115); ellL1(L) ellL1(L,1) ellL1(L,3) ellL1(ellinit([0,1,1,-2,0]),2) ellmoddegree(ellinit([0,1,0,-4,-4])) ellmoddegree(ellinit([-4,0])) ellmoddegree(ellinit([0,-1,0,4,-4])) ellmoddegree(ellinit([0,-1,0,-8,-16])) ellmoddegree(ellinit([0,0,1,0,-7])) ellmoddegree(ellinit([1,-1,0,0,-5])) ellmoddegree(ellinit([1,-1,0,-69,-208])) ellmoddegree(ellinit([0, -1, 1, 0, 0])) ellmoddegree(ellinit([-4,-3])) ellmoddegree(ellinit([1,-1,0,-363204,-84000240])) \\ small E.area pari-2.11.2/src/test/in/alglattices0000644000175000017500000002143113326135265015560 0ustar billbilldefault(realprecision,38); default(parisize,100M); \\Tests for lattices, orders and makeintegral in algebras Sn(n) = [Vecsmall(numtoperm(n,i)) | i <- [0..n!-1]]; D2n(n)= { [[vectorsmall(2*n,i,if(i==n,1,i==2*n,n+1,i+1)), vectorsmall(2*n,i,if(i==1,n+1,i==n+1,1,2*n+2-i))],Vecsmall([n,2])]; } firstprime1mod(n) = { p = 2; while(p%n!=1, p=nextprime(p+1)); p; } al = alginit(nfinit(y^2+7), [-1,-1]); a = [1,1,-1/2,1,1/3,-1,1,1]~; mt = algtomatrix(al,a,1); lat = alglathnf(al,mt); print(type(lat)=="t_VEC"); print(#lat == 2); print(type(lat[1])=="t_MAT"); print(type(lat[2])=="t_FRAC"); print(type(lat[1][1,1])=="t_INT"); print(lat[1][2,1]==0); c = [1,1,-1,1,0,-1,1,1]~; mt = algtomatrix(al,c,1); lat = alglathnf(al,mt); print(lat[2]==1); print(lat == alglathnf(al,c)) lat = alglathnf(al,matid(8)*2); print(lat[2]==2); b = [1,0,-1,1,0,-1,2,1]~; mtb = algtomatrix(al,b,1); lat = alglathnf(al,matconcat([mt,mtb])); print(lat==[1,1]); print(lat == alglathnf(al,[mt,mtb])); lat = alglathnf(al,matconcat([7*mt/2,7*mtb/2]),21/2); print(lat==[1,7/2]); lat1 = alglathnf(al,a); lat2 = alglathnf(al,c); N = algdim(al,1); lat3 = [11*matid(N),1]; lat4 = [3*matid(N),1]; print(alglatinter(al,lat3,lat4) == [matid(N),33]); print(alglatadd(al,lat3,lat4) == [matid(N),1]); print(alglatadd(al,lat1,alglatadd(al,lat2,lat3)) == alglatadd(al,alglatadd(al,lat1,lat2),lat3)); print(alglatinter(al,lat1,alglatinter(al,lat2,lat3)) == alglatinter(al,alglatinter(al,lat1,lat2),lat3)); {print(alglatinter(al, alglatadd(al,lat1,lat2), lat3) == alglatadd(al, alglatinter(al,lat1,lat3),alglatinter(al,lat2,lat3)));} inter1 = alglatinter(al,lat1,lat2,&sum1); sum2 = alglatadd(al,lat1,lat2,&inter2); print(inter1==inter2); print(sum1==sum2); print(sum1[2]==1/6); print(inter1[2]==1); print(alglatindex(al,lat1,lat2)); print(alglatmul(al,lat1,lat2)); print(alglatmul(al,b,lat1)); print(alglatmul(al,lat2,b)); print(alglatmul(al,b/10,lat1)); print(alglatmul(al,lat2,b/10)); print(alglatlefttransporter(al,lat1,lat2)); print(alglatrighttransporter(al,lat1,lat2)); setrand(88); aa = algrandom(al,10); print(alglathnf(al,aa/10,matdet(algtomatrix(al,aa,1))/10)==alglathnf(al,aa/10)); print(alglatcontains(al,lat1,a)); col = [3,6,-5,1,23,2,0,1]~; print(alglatelement(al,lat1,col)); testlataddinter()= { my(lat=[0,0,0],int12,int23,sum12,index,elt1, elt2,tr12L,tr23R,col1,col2); my(lat=[0,0,0],int12,int23,sum12,index,elt,tr12L,tr23R); elt1=algrandom(al,5)/random([1,8]); elt2=algrandom(al,5)/random([1,8]); elt=algrandom(al,5); for(i=1,3,lat[i]=alglathnf(al,algrandom(al,2)/random([1,8]))); sum12 = alglatadd(al,lat[1],lat[2],&int12); if(alglatadd(al,lat[1],alglatadd(al,lat[2],lat[3],&int23)) != alglatadd(al,sum12,lat[3]), print("error (add)",lat); return(0) ); if(alglatinter(al,lat[1],int23) != alglatinter(al,int12,lat[3]), print("error (inter)",lat); return(0) ); if(!alglatsubset(al,lat[1],sum12,&index) || (index!=alglatindex(al,lat[1],sum12)), print("error (subset/index)",lat); return(0) ); if(alglatsubset(al,lat[1],lat[2]) != (lat[2]==sum12), print("error (subset)",lat); return(0) ); if(alglatindex(al,lat[2],lat[3])*alglatindex(al,lat[3],lat[2])!=1, print("error (index)", lat); return(0) ); if(alglatmul(al,lat[1],alglatmul(al,lat[2],lat[3])) != alglatmul(al,alglatmul(al,lat[1],lat[2]),lat[3]), print("error (latmul)", lat); return(0) ); if((alglatmul(al,elt1,alglatmul(al,elt2,lat1)) != alglatmul(al,algmul(al,elt1,elt2),lat1)) || (alglatmul(al,alglatmul(al,lat2,elt1),elt2) != alglatmul(al,lat2,algmul(al,elt1,elt2))), print("error (latmul elt)", lat, elt1, elt2); return(0) ); tr12L = alglatlefttransporter(al,lat[1],lat[2]); tr12L = tr12L[1]*tr12L[2]; for(i=1,8, if(!alglatsubset(al,alglatmul(al,tr12L[,i],lat[1]),lat[2]), print("error (left transporter)", lat, i); return(0) ) ); tr23R = alglatrighttransporter(al,lat[2],lat[3]); tr23R = tr23R[1]*tr23R[2]; for(i=1,8, if(!alglatsubset(al,alglatmul(al,lat[2],tr23R[,i]),lat[3]), print("error (right transporter)", lat, i); return(0) ) ); for(i=1,5, col1 = [random([-10,10]) | j <- [1..8]]~; if(!alglatcontains(al,lat1,alglatelement(al,lat1,col1),&col2) || col1!=col2, print("error (latelement)", lat, col1); return(0) ); if(alglatcontains(al,lat1,col1,&col2) && col1!=alglatelement(al,lat1,col2), print("error (latcontains)", lat, col1); return(0) ) ); 1 }; setrand(1); nb = 250; for(i=1,nb,if(!testlataddinter(),print(i);break())); print("make integral"); mt = [matid(2),[0,-1/4;1,0]]; mt2 = algmakeintegral(mt); algisassociative(mt2) al = algtableinit(mt2); algissimple(al) {mt = [matid(4), [0,-1,0,0;1,0,0,0;0,0,0,-3;0,0,1/3,0], [0,0,2/9,0;0,0,0,-2/3;1,0,0,0;0,-1/3,0,0], [0,0,0,2;0,0,2/3,0;0,3,0,0;1,0,0,0]];} mt2 = algmakeintegral(mt); algisassociative(mt2) al = algtableinit(mt2); algissimple(al) mt = algmultable(alginit(nfinit(y),[-3,7])); mt == algmakeintegral(mt) print("integral subalg"); m = matcompanion(x^4+1); mt = [m^i | i <- [0..3]]; al = algtableinit(mt); B = [1,0;0,0;0,1/2;0,0] al2 = algsubalg(al,B); algisassociative(al2[1]) al2[2] print("bug in subalg when first vector is not 1"); mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; A = algtableinit(mt,2); B = algsubalg(A,[0,1; 0,0; 1,0]); algissimple(B[1]) print("image of lifts in algsimpledec"); testidem(al)={ dec = algsimpledec(al,1)[2]; Le = [d[3][,1] | d <- dec]; for(i=1,#Le, ei = Le[i]; if(algsqr(al,ei)!=ei, print(0); return;); for(j=i+1,#Le, ej = Le[j]; if(algmul(al,ei,ej)!=0, print(0); return;); ); ); print(1); } {for(n=2,4, al = alggroup(Sn(n),7); testidem(al); );} {for(n=2,5, al = alggroupcenter(Sn(n),11); testidem(al); );} {for(n=2,4, p = firstprime1mod(2*n); al = alggroup(D2n(n),p); testidem(al); );} {for(n=2,5, al = alggroupcenter(Sn(n),11); testidem(al); );} /* \\needs galpol package {for(i=1,267, print("i=",i); [pol,den] = galoisgetpol(64,i,1); gal = galoisinit(pol,den); al = alggroupcenter(gal,193); testidem(al); );}*/ print("lattices in al_CSA"); setrand(1); nf = nfinit(y^2-7); a = y; b = y+1; ab = lift(Mod(a*b,nf.pol)); mti = [0,a,0,0;1,0,0,0;0,0,0,a;0,0,1,0]; mtj = [0,0,b,0;0,0,0,-b;1,0,0,0;0,-1,0,0]; mtk = [0,0,0,-ab;0,0,b,0;0,-a,0,0;1,0,0,0]; mt = [matid(4),mti,mtj,mtk]; al = alginit(nf,mt); x1 = [0,2/7,7,-1,0,0,1/5,-5]~; x2 = [-1/7-3*y,y+3/5,y,20+y]~; lat1 = alglathnf(al,x1); lat2 = alglathnf(al,x2); lat3 = alglathnf(al,concat([8/5*matid(8),[1,0,0,1,0,1,1,1]~])); alglatsubset(al,alglatmul(al,alglatlefttransporter(al,lat1,lat3),lat1),lat3) alglatadd(al,lat1,alglatadd(al,lat2,lat3))==alglatadd(al,alglatadd(al,lat1,lat2),lat3) {alglatinter(al,lat1,alglatinter(al,lat2,lat3)) == alglatinter(al,alglatinter(al,lat1,lat2),lat3)} print("examples from docu") al = alginit(nfinit(y^2+7), [-1,-1]); lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); latsum = alglatadd(al,lat1,lat2,&latinter); matdet(latsum[1]) matdet(latinter[1]) latinter = alglatinter(al,lat1,lat2,&latsum); matdet(latsum[1]) matdet(latinter[1]) alglatsubset(al,lat1,lat2) alglatsubset(al,lat1,latsum,&index) index alglatindex(al,lat1,lat2) lat1==lat2 a1 = [1,-1,0,1,2,0,1,2]~; a2 = [0,1,2,-1,0,0,3,1]~; lat1 = alglathnf(al,a1); alglatcontains(al,lat1,a1,&c) c c = [1..8]~; elt = alglatelement(al,lat1,c); alglatcontains(al,lat1,elt,&c2) c==c2 lat2 = alglathnf(al,a2); lat3 = alglatmul(al,lat1,lat2); matdet(lat3[1]) lat3 == alglathnf(al, algmul(al,a1,a2)) lat3 == alglatmul(al, lat1, a2) lat3 == alglatmul(al, a1, lat2) lat1 = alglathnf(al,[1,-1,0,1,2,0,5,2]~); lat2 = alglathnf(al,[0,1,-2,-1,0,0,3,1]~); tr = alglatlefttransporter(al,lat1,lat2); alglatsubset(al,alglatmul(al,tr[1][,7]*tr[2],lat1),lat2) alglatsubset(al,alglatmul(al,lat1,tr[1][,7]*tr[2]),lat2) lat1 = alglathnf(al,matdiagonal([1,3,7,1,2,8,5,2])); lat2 = alglathnf(al,matdiagonal([5,3,8,1,9,8,7,1])); tr = alglatrighttransporter(al,lat1,lat2); alglatsubset(al,alglatmul(al,lat1,tr[1][,8]*tr[2]),lat2) alglatsubset(al,alglatmul(al,tr[1][,8]*tr[2],lat1),lat2) \\end examples print("bad inputs"); al = alginit(nfinit(y^2+7), [-1,-1]); alglathnf(al,0); alglathnf(al,Mat([0,0,0,0,0,0,0,0])); alglathnf(al,[0;0;0;0;0;0;0;0]); fakemat = matid(8); fakemat[5,6] = [] alglathnf(al,fakemat); alglathnf(al,matid(8)*0); fakemat = matid(8); fakemat[1,1] = 0; alglathnf(al,fakemat); lat = alglathnf(al,matconcat([mt*0,mt*0])); a = [[0,0]~,[0,0]~;[0,0]~,[0,0]~]; lat1 = alglathnf(al,a); lat2 = alglathnf(al,c); col = [3,6,-5,1,23,2,0,1]~; print(alglatelement(al,lat1,col~)); a = [1,1,-1/2,1,1/3,-1,1,1]~; b = [1,0,-1,1,0,-1,2,1]~; alglatmul(al,a,b); mt = [matid(2),[0,-1/4;1/2,0]]; algmakeintegral(mt); mt = [[1,0;-1,1],[0,-1/4;1,0]]; algmakeintegral(mt); algmakeintegral('x,1); alglatmul(al,lat1,[matdiagonal([1,1,0,1,1,1,1,1]),1]); \\end bad inputs pari-2.11.2/src/test/in/ellnf0000644000175000017500000001325613457566441014403 0ustar billbill\\package:elldata default(realprecision,38); K=nfinit(t^3-2); e=ellinit([t+1,t^2 - (t^3+(t+1)*t)], K); P=[t,t]; ellisoncurve(e, P) elladd(e, P,P) ellmul(e, P,3) ellordinate(e, t) ellordinate(e, t+1) elldivpol(e, 3) ellfromj(Mod(t,t^3-2)) ellinit(e, idealprimedec(K,2)[1]) ellinit(e, idealprimedec(K,5)[1]) { K = nfinit(t); forell(E, 1, 1000, my(e,N,f,v); v = [1/60,7131/3600,11/12,5/12]; e = ellchangecurve(ellinit(E[2],1), v); eK= ellchangecurve(ellinit(E[2],K), v); N = ellconvertname(E[1])[1]; f = factor(N)[,1]; for(i=1, #f, my(p = f[i], P,A,B); P=idealprimedec(K,p)[1]; A=elllocalred(e,P.p); A[3]=0; B=elllocalred(eK,P); B[3]=0; if(A!=B, error(E[2])); if(ellap(e,p) != ellap(eK,P),error(E[2])) ) ) } e = ellchangecurve(ellinit([1,0],K),[17^2,0,0,0]); P = idealprimedec(K,17)[1]; elllocalred(e,P) nf4=nfinit(a^2+1); P17 = idealprimedec(nf4,17)[1]; P13 = idealprimedec(nf4,13)[1]; P5 = idealprimedec(nf4,5)[1]; E=ellinit([1+a,0,1,0,0],nf4); E2 = ellchangecurve(E, [17,0,0,0]); [ellap(E2, P5), ellap(E2, P13), ellap(E2, P17)] [ellcard(E2, P5), ellcard(E2, P13), ellcard(E2, P17)] [ellgroup(E2, P5), ellgroup(E2, P13), ellgroup(E2, P17)] E3 = ellchangecurve(E, [1/17,a,a+1,0]); ellap(E3, P17) ellan(E2,20) ellan(E3,20) ellglobalred(E) ellglobalred(E2) ellglobalred(E3) K=nfinit(x^4+20*x^2+16); E = ellinit([-1377/256*x^6-6885/32*x^4+729/4*x^3-4131/2*x^2+14013/4*x+5589/4, -1863/16*x^6-9315/2*x^4-5589/2*x^3-44712*x^2-53460*x+33534], K); P2 = idealprimedec(K,2)[1]; [ellap(E,P2), ellgroup(E,P2)] P3 = idealprimedec(K,3)[1]; [ellap(E,P3), ellgroup(E,P3)] P5 = idealprimedec(K,5)[1]; [ellap(E,P5), ellgroup(E,P5)] E = ellinit([1/4*x^2+3,-7/4*x^2-1,-3/16*x^3-5/4*x^2-1/2,-1/4*x^3-3/4*x^2-x,-3/16*x^3-1/4*x^2-3/2*x+1/2],K); ellgroup(E,P2,1) ellgroup(E,P3,1) P=idealprimedec(K,209844281664738991)[1]; ellgroup(E,P,1) K=bnfinit(a^2 - 2*3*5*29); e = ellinit([a,1], K); E = ellchangecurve(e, Mod([2^3 * 3 * a, a+123, 17*a+2, 16*a+3], K.pol)); ellintegralmodel(E)[1..5] ellintegralmodel(E, &v)[1..5] v ellminimalmodel(E, &v)[1..5] v ellminimalmodel(ellinit([a^4,(a+2)^6], K)) p=2*10^10+89; q=10^10+19; P=nfbasistoalg(K, bnfisprincipal(K, idealprimedec(K,p)[1])[2]); Q=nfbasistoalg(K, bnfisprincipal(K, idealprimedec(K,q)[1])[2]); e = ellinit([P^3*Q^4,P^6*Q^4], K); ellminimalmodel(e,&v); v ellglobalred(e) e = ellinit([P^4*Q^4,P^6*Q^4], K); ellglobalred(e) K=bnfinit(a^2-65); u=Mod(8+a,K.pol); e = ellinit([1,40*u+1,0,25*u^2,0], K); ellminimalmodel(e) e = ellinit([1,10*u+1,0,25*u^2,0], K); ellminimalmodel(e) ellglobalred(e) E=ellinit([0,-1,0,-15/16*z^2+5/2*z+8,5/16*z^2-9*z+14],nfinit(z^3-4*z^2-32*z+64)); ellglobalred(E) E=ellinit([-3850829794560*a-15877538149168,-8352767604912215040*a-34439343881478343808],bnfinit(a^2-17)); ellminimalmodel(E,&v)[1..5] v \\ #1899 E=ellinit([0,34,0,225,0],bnfinit(a^2-7)); ellminimalmodel(E, &v)[1..5] v K = nfinit(a^2 - a + 1); E = ellinit([1, -1, 0, -3*a, -3*a + 3],K); /* Same curve, non integral model */ E2 = ellinit([(144*a+9)/-48,(3240*a-2565)/-864],K); idealnorm(K,ellglobalred(E)[1]) idealnorm(K,ellglobalred(E2)[1]) elltamagawa(E) elltamagawa(E2) ellrootno(E) ellrootno(E2) elltors(E) elltors(E2) ellbsd(E) ellbsd(E2) E.omega E2.omega E.eta E2.eta E.area E2.area K=bnfinit(t^5 - 8*t^4 - 2*t^3 + 2*t^2 + t - 8); E=ellinit([-10, -6, -10, -7, -8],K); Emin=ellminimalmodel(E); Emin.omega K = nfinit(a^2 - a - 22); E = ellinit([0, 0, 1, -1590*a - 8580, 92750*a + 359875],K); idealnorm(K,ellglobalred(E)[1]) elltamagawa(E) ellrootno(E) elltors(E) ellbsd(E) ellbsd(ellchangecurve(E,[1/Mod(a,K.pol),0,0,0])) ellbsd(ellchangecurve(E,[Mod(a,K.pol),0,0,0])) E.omega E.eta E.area K = nfinit(a^3 - a^2 + 1); E = ellinit([a + 1, -a^2 - a - 1, a^2 + a, -a^2, -a^2 + 1],K); idealnorm(K,ellglobalred(E)[1]) elltamagawa(E) ellrootno(E) elltors(E) ellbsd(E) E.omega E.eta E.area K = nfinit(a^2-a-57); E = ellinit([a,-a,a,-5692-820*a,-259213-36720*a],K); ellminimaldisc(E) K = nfinit(a^2-26); E = ellinit([a,a-1,a+1,4*a+10,2*a+6],K); ellminimaldisc(E) E = ellinit([1,2,3,4,5]); ellminimaldisc(E) nf2=nfinit(a^2-2); nf3=nfinit(a^2-a-1); E=ellinit([0, 0, 0, -3/2*a - 3/16, 7/8*a + 7/32],nf3); ellminimaldisc(E) ellheight(E,[-a+11/4,3*a-9/2]) E=ellinit([0,0,1,-5*a-25,-15*a-49], nf3); ellheight(E,[-4*a+3,-a+1]) ellrootno(E) E=ellinit([a+1,a-1,a,6*a+2,14*a+34],nf2); ellheight(E,[-3/2*a+1/2,-9/4*a-3/2]) ellheight(E,[-a+1,-3*a-3]); ellrootno(E) E=ellinit([0,a+1,0,18*a-27,-55*a+78],nf2); ellheight(E,[2*a-5,-2*a+5]) ellrootno(E) E=ellinit([0,a+a^2,0,a^3,(a+1)^2],nf3); ellheight(E,[-a,a+1]) ellheight(E,[-a^2,a+1]) ellrootno(E) E=ellinit([0,a+a^2,0,a^3,(a+1)^2],nfinit(a^2-a-3)); ellheight(E,[-a,a+1]) ellheight(E,[-a^2,a+1]) ellrootno(E) E=ellinit([0,1,0,a*(1-a),(a+1)^2],nf3); ellheight(E,[-a,a+1]) ellheight(E,[a-1,a+1]) ellrootno(E) E=ellinit([0,a,1,a+1,0],nf4); ellheight(E,[0,0]) ellrootno(E) E=ellinit([1,a+1,0,-2*a-1,1],nf4); ellheight(E,[-2*a,-2*a-1]) ellrootno(E) E = ellinit([x+1,-x+1,0,7*x-46,-22*x+118], nfinit(x^2-x+3)); ellheight(E,[3,-2*x+2]) ellrootno(E) E = ellinit([x+1,-1,x,-x^2,0], nfinit(x^3-x^2+1)); ellheight(E,[0,-x]) ellrootno(E) E = ellinit([-22032-15552*a,0],nf2); ellheight(E,[-72*a-108,0]) \\#2001 E=ellinit([0,-1,0,-49,141]); K=nfinit(t^5-8*t^4-2*t^3+7*t^2+6*t-10); EK=ellinit(E,K); v=[-10389455*t^4+94207180*t^3-74647193*t^2-43748717*t+61159408,2455284431170392*t^4-11016432463258648*t^3-93170850675195967*t^2+178129308340634152*t-98800231481430471,0,2728467290019334591152803*t^4-22989796437900272628924775*t^3+2354051986650548020107980*t^2+37608622876236967823113454*t-29191600123918022419958490]; Emin=ellchangecurve(EK,Mod(v,K.pol)); u=nfeltembed(K,v[1]); A1 = Emin.area; A2 = apply(x->abs(x)^2,u) * E.area; exponent(vector(3,i,(A1[i]-A2[i])/A2[i])) pari-2.11.2/src/test/in/multiif0000644000175000017500000000061313201017466014726 0ustar billbillf(x)= { if(x==1,print(1)); if(x==1,print(1) ,print("default")); if(x==1,print(1) ,x==2,print(2)); if(x==1,print(1) ,x==2,print(2) ,print("default")); if(x==1,print(1) ,x==2,print(2) ,x==3,print(3)); if(x==1,print(1) ,x==2,print(2) ,x==3,print(3) ,print("default")); } for(i=1,4,f(i)); g(x)=if(x,return(1),return(2),return(3)); g(1) g(0) pari-2.11.2/src/test/in/modpr0000644000175000017500000000236713326135265014414 0ustar billbillnfeltmulmodpr(nfinit(x),x,x,1); v=[0,1/3,y,z,[1,1/3]~, [1,1,1/3]~]; test(P) = { my(f, V = apply(t->iferr(nfmodpr(K,t,P),E,E),v)); print(V); V = select(t->type(t)!="t_ERROR", V); print(K.pol, ": ", P); f=[(x,y)->x/y, (x,y)->x*y]; for (i=1,#V, for (j=i,#V, print("*",[i,j],":"); for (k=1, #f, print(iferr(f[k](V[i],V[j]), E,E))) ) ); for(i=1,#v, print("*",i,":"); print(iferr(nfeltreducemodpr(K,v[i],P), E,E)); ); } K=nfinit(y^2+1); P = nfmodprinit(K,idealprimedec(K,2)[1]); test(P); P = nfmodprinit(K,idealprimedec(K,3)[1]); test(P); K=nfinit(y^3-9); P = nfmodprinit(K,idealprimedec(K,3)[1]); test(P); P = nfmodprinit(K,idealprimedec(K,2)[2]); test(P); K=nfinit(y^2-1105); P7=nfmodprinit(K,idealprimedec(K,7)[1]); nfmodprlift(K,nfmodpr(K,y,P7),P7) P = nfmodprinit(K,idealprimedec(K,2)[1]); nfeltreducemodpr(K,(-y+1)/2,P) nffactormod(K, x^3+y*x^2+y*x+1, P) nfmodprlift(K,1,P) PU(x)=apply(t->nfmodpr(K,t,P),x); LI(x)=nfmodprlift(K,x,P); m=PU([1,y;[1/2,1/2]~,1]); v = PU([1,y]~) LI(matker(m)) LI(matsolve(m,v)) m=PU([y,y^2;y^2,y^3]) LI(matker(m)) LI(matsolve(m,v)) LI(matsolve(m,m)) K=nfinit(charpoly(Mod(2*x+1,polcyclo(51)))); P=idealprimedec(K,2)[1]; nfeltreducemodpr(K,P.gen[2],nfmodprinit(K,P)) nfmodpr(nfinit(x),[],[]~) pari-2.11.2/src/test/in/member0000644000175000017500000000315313326135265014534 0ustar billbill\\package:elldata default(realprecision,38); { members=[ a1, a2, a3, a4, a6, b2, b4, b6, b8, c4, c6, area, bid, bnf, clgp, codiff, cyc, diff, disc, e, eta, f, fu, gen, group, index, j, mod, nf, no, omega, orders, p, pol, polabs, r1, r2, reg, roots, sign, t2, tate, tu, zk, zkst ];} \\ tufu, futu omitted test(s)= { for (i=1, #members, my (m = members[i]); iferr( print(".", m, ": ", eval(Str("s.", m))), E, n = errname(E); if (n != "e_IMPL" && n != "e_TYPE" && n != "e_MISC", error(E)))); } test(x) test(vector(5)) test(vector(20)) test([]~) print("NF"); test( NF = nfinit(y^2-1105) ) print("NF chvar"); test( nfinit(2*y^2+1) ) print("BNF");test( BNF = bnfinit(NF) ) print("BNR");test( bnrinit(BNF, 4) ) print("RNF");test( rnfinit(NF, x^2-y) ) print("QUADCLASSUNIT"); test( quadclassunit(1105) ) print("GAL"); test( galoisinit(x^2-2^129) ) print("ELL");test( ellinit([1,2,3,4,5]) ) print("ELLFp");test( ellinit([1,2,3,4,5], 13) ) print("ELLFq");test( ellinit([1,2,3,4,5], ffgen(13^2)) ) print("ELLQp");test( ellinit([1,2,3,4,5], O(11^2)) ) print("FFELT"); test( ffgen(2^3) ) test( ffgen(3^3) ) test( ffgen((2^64+13)^2) ) print("INTMOD");test( Mod(1,3) ) print("POLMOD");test( Mod(x,x^2+1) ) print("QFB");test( Qfb(1,2,3) ) print("QUAD"); test( quadgen(-4) ) P=idealprimedec(NF,2)[1]; print("PRID"); test(P) print("PADIC"); test(2 + O(3^2)) print("MODPR"); test(nfmodprinit(NF,P)) A=idealpow(NF,P,2); print("BID"); test(idealstar(NF,A,2)) print("BID (nogen)"); test(idealstar(NF,idealpow(NF,A,1))) nfinit(y^3-2).codiff print("MF"); mf=mfinit([31, 2, Mod(25,31)], 0); [f]=mfeigenbasis(mf); test(mf) test(f) pari-2.11.2/src/test/in/ellweilpairing0000644000175000017500000000723413201017466016272 0ustar billbillweil(E,P,Q,m,p)=lift(ellweilpairing(E,P,Q,m)); tate(E,P,Q,m,p)=if(p%m!=1,return(0));lift(elltatepairing(E,P,Q,m)^((p-1)/m)); check(v,P,Q,m,p)= { my (E=ellinit(v*Mod(1,p))); P*=Mod(1,p); Q*=Mod(1,p); print([weil(E,P,Q,m,p),tate(E,P,Q,m,p),ellgroup(E)]); } check([0,0,1,0,0],[0,0],[57,46],3,103) check([0,0,1,0,0],[64,63],[0,0],3,109) check([0,0,1,0,0],[0,0],[150,32],3,151) check([0,0,1,0,0],[0,156],[13,144],3,157) check([0,0,1,0,0],[0,0],[59,58],3,163) check([0,0,1,0,0],[192,84],[0,192],3,193) check([0,0,1,0,0],[198,92],[0,0],3,199) check([0,0,0,1,0],[1,51],[72,9],4,113) check([0,0,0,1,0],[88,56],[1,31],4,137) check([1,0,0,0,3],[13,6],[147,89],4,149) check([0,0,1,0,0],[5,58],[36,128],4,157) check([0,0,1,0,3],[30,1],[26,1],5,31) check([0,0,1,0,0],[58,107],[22,76],6,109) check([0,0,1,0,0],[90,4],[32,1],6,127) check([0,0,1,0,0],[138,60],[62,155],6,157) check([0,0,0,1,0],[47,53],[160,147],7,197) check([0,0,0,1,0],[50,80],[16,65],8,113) check([1,0,0,0,3],[25,82],[23,49],8,149) check([0,0,1,0,0],[10,67],[88,35],9,127) check([0,0,1,0,0],[102,32],[87,55],9,163) check([0,0,1,0,0],[12,11],[17,5],9,19) check([0,0,1,0,0],[190,47],[194,169],9,199) check([0,0,0,1,0],[28,34],[22,11],10,137) check([0,0,0,1,0],[94,84],[10,142],10,157) check([0,0,0,1,0],[159,29],[115,100],14,197) check([0,0,0,1,0],[154,21],[58,126],15,157) check([0,0,0,1,0],[121,63],[121,64],16,127); check([0,0,0,1,0],[18,104],[177,153],16,191); check([0,0,1,0,0],[16,56],[16,56],2,113); check([0,0,1,0,0],[66,63],[66,63],2,127); check([0,0,1,0,0],[126,78],[89,78],2,157); check([0,0,1,0,0],[150,89],[150,89],2,179); check([0,0,1,0,0],[22,95],[22,95],2,191); check([0,0,0,1,3],[4,1],[4,6],6,7); check([0,0,0,0,2],[3,1],[3,1], 3,7); t=ffgen(Mod(1,2)*(t^6+t^5+t^3+t^2+1)); E=ellinit([0,0,1,0,0],t); P=[t^2+t+1,t+1]; Q=[t^5+t^3+t^2,t^5+t^4+t^3+t^2+t+1]; ellweilpairing(E,P,Q,3) elltatepairing(E,P,Q,3) elltatepairing(E,P,P,3) elltatepairing(E,Q,Q,3) t=ffgen(ffinit(3,6),'t); E=ellinit([0,0,0,1,0],t); P=[2*t^5+2*t^4+t^2+2*t+2,2*t^5+t^4+t^3+2*t^2+1]; Q=[t^4+t^3+t^2+t+2,t^5+2*t^4+2*t^2+t]; ellweilpairing(E,P,Q,28) elltatepairing(E,P,Q,28) elltatepairing(E,P,P,28) elltatepairing(E,Q,Q,28) t=ffgen(ffinit(5,6),'t); E=ellinit([0,0,1,0,0],t); P=[4*t^5+4*t^4+3*t^3+2*t^2+2*t,4*t^5+4*t^4+2*t^3+2*t^2+4]; Q=[t^5+2*t^4+4*t^3+2*t^2+4*t+1,2*t^5+t^4+3*t+1]; ellweilpairing(E,P,Q,126) elltatepairing(E,P,Q,126) elltatepairing(E,P,P,126) elltatepairing(E,Q,Q,126) t=ffgen(2^4,'t); E=ellinit([1,0,0,0,t^3+t^2+t+1]); Q=[t^3+t^2,t+1]; elltatepairing(E,Q,Q,5)^3 t=ffgen(3^6,'t); E=ellinit([0,2*t^5+2*t^3+t^2+t+1,0,0,t^3+2*t^2+t]); Q=[2*t^5+2*t^4+t^3+2*t^2+2*t+1,2*t^5+t^2]; elltatepairing(E,Q,Q,8)^91 t=ffgen(5^4,'t); E=ellinit([0,0,0,4*t^3+4*t^2+4*t+1,3*t^3+2]); Q=[3*t^3+2*t^2+1,3*t^2+4*t]; elltatepairing(E,Q,Q,48)^13 p=nextprime(2^65); t=ffgen(p^2,'t); E=ellinit([t^2,0]); [N]=ellgroup(E) d=(p^2-1)/N; P=[14078684373865444404*t+24675141949190748313,34082614562121616748*t+9184592839883218620]; Q=[3606608601291892434*t+22502667145150289531,23709671617839429105*t+22495649567796533868]; ellweilpairing(E,P,Q,N) elltatepairing(E,P,Q,N)^d test(p) = { forvec(v=vector(5,i,[0,p-1]), E=ellinit(v*Mod(1,p)); if (!#E, next); G=ellgroup(E);if(#G>1,print(v,":",G)), ); } test(3); test(5); check2(E)= { E=ellinit(E); my([n,D,G] = ellgroup(E,,1)); my(o = D[1], [P,Q] = G); my(z = ellweilpairing(E,P,Q,o)); forvec(v=vector(4,i,[0,o-1]), my(Pk, Qj, d, w); Pk = elladd(E, ellmul(E,P,v[1]),ellmul(E,Q,v[2])); Qj = elladd(E, ellmul(E,P,v[3]),ellmul(E,Q,v[4])); d = v[1]*v[4]-v[2]*v[3]; w = ellweilpairing(E,Pk,Qj,o); if(w != z^d, error(v,[Pk,Qj],[w,z^d]))); } a=ffgen(2^4,'a); check2([0, a^2, a^3, 0, 0]); check2([0, a^2, a^3, a^4, 0]); pari-2.11.2/src/test/in/hyperell0000644000175000017500000000445713447371554015130 0ustar billbillcheckfeq(P,q)= { for(i=0,poldegree(P),if (type(polcoeff(P,i))!="t_INT",error(dbg_x(P)))); my(M=minpoly(Mod(x+q/x,P))); if(poldegree(M)!=poldegree(P)/2,error([P,q,M])); M; } { for(g=1,6, for(n=1,2*g, H=hyperellcharpoly(n*(x^(2*g+1)-2*x^n+1)*Mod(1,19)); printsep(":",g,n,checkfeq(H,19)))) } { for(g=1,5, for(n=1,2*g+1, H=hyperellcharpoly(n*(x^(2*g+2)-3*x^n+1)*Mod(1,29)); printsep(":",g,n,checkfeq(H,29)))) } { forprime(p=3,7, H=hyperellcharpoly((x^6+x+1)*Mod(1,p)); print(checkfeq(H,p))); forprime(p=3,11, H=hyperellcharpoly((x^10+x+1)*Mod(1,p)); print(checkfeq(H,p))); forprime(p=3,7, g=ffgen(ffinit(p,3),'g); H=hyperellcharpoly((x^6+g*x+1)); print(checkfeq(H,p^3))); } { my(a,P,Q,E); a=ffgen([5,5],'a); setrand(3); for (i=1, 10, P=random(a*x^3); H=hyperellcharpoly(P); E=ellinit(ellfromeqn('y^2-P)); if(ellap(E)!=-polcoeff(H,1),error(H))); } P=hyperellcharpoly(Mod(1,3)*(x^10+x^4+x^3+2*x^2+x));checkfeq(P,3) P=hyperellcharpoly(Mod(1,3)*(x^12+x^4+1));checkfeq(P,3) P=hyperellcharpoly(Mod(1,3)*(x^14+x^4+2));checkfeq(P,3) g=ffgen(ffinit(79,2),'g); P=hyperellcharpoly(x^5+g*x^3+2*x+5);checkfeq(P,79^2) P=hyperellcharpoly(g*(x^5+g*x^3+2*x+5));checkfeq(P,79^2) P=hyperellcharpoly(x^5+Mod('g,g.mod*Mod(1,79))*x^3+2*x+5);checkfeq(P,79^2) P=hyperellcharpoly(x^6+g*x^3+2*x+5);checkfeq(P,79^2) P=hyperellcharpoly(g*(x^6+g*x^3+2*x+5));checkfeq(P,79^2) P=hyperellcharpoly((x^7+x^3+2*x+5)*Mod(1,79));checkfeq(P,79) P=hyperellcharpoly((x^8+x^3+2*x+5)*Mod(1,79));checkfeq(P,79) P=hyperellcharpoly([x^5+x+1,x]*Mod(1,79));checkfeq(P,79) P=hyperellcharpoly((x^3+x+1)*ffgen(3^2)^0);checkfeq(P,9) P=hyperellcharpoly([x^5+x+1,x+1]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^5+x+1,x^2+x+1]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^5+x+1,x^3]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^6+x^5+x^4+1,x+1]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^6+x+1,x^2]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^6+x+1,x^3]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^2+x+1,x^3]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^3+x+1,x^3]*Mod(1,2));checkfeq(P,2) P=hyperellcharpoly([x^4+x+1,x^3]*Mod(1,2));checkfeq(P,2) g=ffgen(ffinit(7,3),'g);P=hyperellcharpoly(x^5+g);checkfeq(P,7^3) hyperellcharpoly((256*a^5+5)*Mod(1,5)) hyperellcharpoly((256*a^5+5)*ffgen(5^2)) pari-2.11.2/src/test/in/intnum0000644000175000017500000001117313457566442014612 0ustar billbilldefault(echo,1); allocatemem(20 * 10^6); check(a,b) = my(t = abs((a-b)/b)); if (t, ceil(log(t)/log(10)), -oo); \p96 check(intcirc(s=1, 0.5, zeta(s)), 1) f(s) = gamma(s)^3; \\ f(c+it) decrease as exp(-3Pi|t|/2) c = 2; \\ arbitrary A = [-oo,3*Pi/2]; B = [+oo,3*Pi/2]; F(z) = { my (a = -log(z)); intnum(t=A,B, exp(a*I*t), T)*exp(a*c) / (2*Pi); } T = intfuncinit(t=A,B, f(c + I*t)); ref=F(4); \p38 T = intfuncinit(t=A,B, f(c + I*t)); check(F(4), ref) \p96 f(x) = 1/(exp(x)-1) - exp(-x)/x; F = truncate( f(t + O(t^7)) ); g(x) = if (x > 1e-18, f(x), subst(F,t,x)); check(intnum(x = 0, [oo,1], f(x)), Euler) check(intnum(x = 0, [oo,1], g(x)), Euler) check(intnum(x = 0, 1, 1/sqrt(x)), 2) check(intnum(x = [0,-1/2], 1, 1/sqrt(x)), 2) check(intnum(x = 100000, oo, 1/(1+x^2)), atan(1/100000)) check(intnum(x=0,1,x*cos(Pi*x)), -2/Pi^2) check(intnum(x=0,1,x*cos(Pi*x),2), -2/Pi^2) check(intnum(x = [0,-1/2], [oo,-3/2], 1/(sqrt(x)+x^(3/2))), Pi) check(intnum(x = [-oo,-3/2], [oo,-3/2], 1/(1+abs(x)^(3/2))), 8*Pi/sqrt(27)) check(intnum(x = -oo, oo, 1/(1+x^2)), Pi) f(x)=if (x<0,1/(1+(-x)^(3/2)), 1/(1+x^(5/2))); a=4*Pi/sqrt(27) + 2*(Pi/5)/sin(2*Pi/5); check(intnum(x = [-oo,-3/2], [oo,-5/2], f(x)),a) f(x)=if (x<0,1/(1+(-x)^(3/2)), exp(-x)); check(intnum(x = [-oo,-3/2], [oo,1], f(x)), 4*Pi/sqrt(27)+1) f(x)=if (x<0,1/(1+(-x)^(3/2)), sinc(x)); check(intnum(x = [-oo,-3/2], [oo,-I], f(x)), 4*Pi/sqrt(27)+Pi/2) f(x)=if (x<0,exp(2*x), 1/(1+x^(3/2))); check(intnum(x = [-oo,2], [oo,-3/2], f(x)), 1/2+4*Pi/sqrt(27)) f(x)=if (x<0,exp(2*x), 1/(1+x^(5/2))); check(intnum(x = [-oo,2], [oo,-5/2], f(x)), 1/2+2*(Pi/5)/sin(2*Pi/5)) f(x)=if (x<0,exp(2*x), exp(-x)); check(intnum(x = [-oo,2], [oo,1], f(x)), 3/2) f(x)=if (x<0,exp(2*x), sinc(x)); check(intnum(x = [-oo,2], [oo,-I], f(x)), 1/2+Pi/2) f(x)=if (x<0,2*sinc(2*x), 1/(1+x^(3/2))); check(intnum(x = [-oo,-2*I], [oo,-3/2], f(x)), Pi/2+4*Pi/sqrt(27)) f(x)=if (x<0,2*sinc(2*x), 1/(1+x^(5/2))); check(intnum(x = [-oo,-2*I], [oo,-5/2], f(x)), Pi/2+2*(Pi/5)/sin(2*Pi/5)) f(x)=if (x<0,2*sinc(2*x), exp(-x)); check(intnum(x = [-oo,-2*I], [oo,1], f(x)), Pi/2+1) f(x)=if (x<0,2*sinc(2*x), sinc(x)); check(intnum(x = [-oo,-2*I], [oo,-I], f(x)), Pi) f(x)=cos((3+tanh(x))*x)/sqrt(1+x^2); a = intnum(x = [-oo,2*I], [oo,4*I], f(x), 1); check(intnum(x = [-oo,2*I], [oo,4*I], f(x)), a) check(intnum(x=[0,-1/2],[1,-1/3], x^(-1/2) + (1-x)^(-1/3)), 7/2) T=intnuminit([0,-1/2],[1,-1/3]); check(intnum(x=[0,-1/2],[1,-1/3], x^(-1/2) + (1-x)^(-1/3), T), 7/2) check(intnum(x = 0, [oo,1], sinc(x)), Pi/2) check(intnum(x = 0, [oo,-I], sinc(x)), Pi/2) check(intnum(x = 0, [oo,-2*I], 2*sinc(2*x)), Pi/2) A=intnum(x=0,1,sinc(x/2)^2/2)+intnum(x=1,oo,1/x^2)-intnum(x=1,[oo,I],cos(x)/x^2); check(A, Pi/2) check(intnum(x = 0, [oo, 1], sin(x)^3*exp(-x)), 3/10) check(intnum(x = 0, [oo,-I], sin(x)^3*exp(-x)), 3/10) tab = intnuminit(0,[oo,-I], 1); check(intnum(x = 0, oo, sin(x)^3*exp(-x), tab), 3/10) check(intnum(x = 0, [oo, -I], x^2*sin(x)), -2) tab = intnuminit(-1,1); check(intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2),x^2+y^2,tab),tab), Pi/2) \p96 check(intnumgauss(x=0,1,sin(x)), 1-cos(1)) T=intnumgaussinit(); check(intnumgauss(x=0,1,1/(x+1),T), log(2)) check(intnumgauss(x=0,1,1/(x+1)^(4/3),T), 3-3/2^(1/3)) check(intnumgauss(x=2,1,x,T),-3/2) check(intnumgauss(x=-1,1,1/(1+x^2), 20), Pi/2) T=intnumgaussinit(100); check(intnumgauss(x=-2,2,1/(1+x^2), T), 2*atan(2)) check(intnumgauss(t=1,2,t,1),3/2) \\ Power series checkps(a,b) = my(t = norml2(Vec(b-a))); if (t, ceil(log(t)/log(10)), -oo); checkps(intnum(t=0,x,exp(t)),exp(x)-1) checkps(intnum(t=-x,0,exp(t)),1-exp(-x)) checkps(intnum(t=-x,x,exp(t)),exp(x)-exp(-x)) tab = intnuminit(1-x,1+y); norml2(apply(Vec,Vec(intnum(t=-x,y,exp(t),tab)-(exp(y)-exp(-x))))) checkps(intnum(t=[0,-1/2],x^2,1/sqrt(t)),2*x) checkps(intnum(t=1-x^2,[1,-1/2],1/sqrt(1-t)),2*x) checkps(intnum(t=[x^2,-1/2],1,1/sqrt(t)),2-2*x) checkps(intnum(t=0,[1-x^2,-1/2],1/sqrt(1-t)),2-2*x) f(t)=(t^2*(1-t))^(1/3); checkps(intnum(t=[x^3,-1/3],[1-x^3,-2/3],(2/3*t-t^2)/(t^2*(1-t))^(2/3)),f(1-x^3)-f(x^3)) \p38 intnum(x=-oo,[0,-1/2],1/sqrt(-x*(x^4+1))) \pb20 intnumromb(x=0,1,sin(x)) intnumromb(x=0,1,sin(x), 1) intnumromb(x=1,100,exp(-x^2), 2) intnumromb(x=0,1,sinc(x), 3) \\ wrong result at this accuracy intnumromb(x=0,110,x, 1) \\ wrong result at this accuracy intnumromb(x=2,110,x, 1) \\ wrong result abs(intnumromb(x=-110,90,x, 1)+1998.3) < 1e-1 intnumromb(x=2,1,x, 1) intnuminit(-oo,oo,1); \\ Errors intnuminit([x,-1/2],x) intnum(t=[x^2,-1/2],1,1/sqrt(t),intnuminit([0,-1/2],1)) intnumgauss(t=1,2,1,"") intnuminit([oo,1+I],[oo,""]) intnuminit([oo,1+I,2],[oo,1]) intnum(x=oo,oo,1) intnum(x=-oo,-oo,1) intnuminit(x=-oo,oo,-1); intfuncinit(t=0,1,s); intfuncinit(t=[-oo,I],[oo,I],s); pari-2.11.2/src/test/in/ellisomat0000644000175000017500000000237713326135265015265 0ustar billbilldefault(parisize,"48M"); eq(E) = Y^2+E.a1*X*Y+E.a3*Y - (X^3 + E.a2*X^2 + E.a4*X + E.a6); checkiso(E1,E2,iso)= { my(EE1 = eq(E1)); my([x,y,z]=substvec(iso,['x,'y],Mod([X,Y], EE1))); my(z2=sqr(z),z4=sqr(z2),z6=z2*z4); lift(y^2+E2.a1*x*y*z+E2.a3*y*z*z2 - (x^3+E2.a2*x^2*z2+E2.a4*x*z4+E2.a6*z^6)); } checkisov(E,V)= { apply(v->my(E2=ellinit(v[1])); checkiso(E,E2,v[2]), V); } check(V)= { for(i=1,#V, my(E=ellinit(ellfromj(V[i]))); my(Et=ellminimalmodel(ellinit(elltwist(E,ellminimaltwist(E,1))))); my([L,M]=ellisomat(Et), [L2, M2] = ellisomat(Et,, 1)); if (M!=M2, error("ellisomat:",i)); print(V[i],":",M,":",checkisov(Et,L))); } check([-2^15,-11^2,-11*131^3,-17^2*101^3/2,-17*373^3*2^-17,-96^3,-7*11^3,-7*137^3*2083^3,-960^3,-5280^3,-640320^3]) check([0,1728,-3375, 8000, 54000, 287496, -12288000, 16581375]) check([9938375/21952, 111284641/50625, -10218313/17576, -25/2]); ellisomat(ellinit([0,-1,1,-10,-20])) ellisomat(ellinit([1,0,1,4,-6]),2) ellisomat(ellinit([1,0,1,4,-6]),3) chk(E)= { my([L,M]=ellisomat(E));print(M);apply(l->checkiso(E,ellinit(l[1]),l[2]),L); } nf=nfinit(phi^2-phi-1); chk(ellinit([0,1,phi,-47*phi+31,560*phi-803],nf)) chk(ellinit([phi+1,1,phi+1,6*phi-1,13*phi+2],nf)) nf=nfinit(a^2-2); chk(ellinit([a,-1,0,18,46],nf)) pari-2.11.2/src/test/in/minmax0000644000175000017500000000027712314242552014554 0ustar billbillv = [-3,7,-2,11]; obj = [1, v, Vecsmall(v), [-3,7;-2,11]]; { for (i = 1, #obj, my (o = obj[i], u,v); vecmin(o, &u); vecmax(o, &v); print(i, ": ", [vecmax(o), vecmin(o), u, v]); ) } pari-2.11.2/src/test/in/orthopol0000644000175000017500000000156413036414402015126 0ustar billbillU(n)=polchebyshev(n,2); T(n)=polchebyshev(n,1); L(n)=pollegendre(n); H(n)=polhermite(n); print("U");for (n=-50,50, if (U(n+1)+U(n-1)-2*x*U(n), print(n))) print("T");for (n=-50,50, if (T(n+1)+T(n-1)-2*x*T(n), print(n))) print("L");for (n=-50,50, if ((n+1)*L(n+1)-(2*n+1)*x*L(n)+n*L(n-1), print(n))) print("H");for (n=0,100, Hn=H(n); if (H(n+1)-2*x*Hn+Hn', print(n))) T=polchebyshev(5,1,x); subst(T,x,2) == polchebyshev(5,1,2) U=polchebyshev(5,2,x); subst(U,x,2) == polchebyshev(5,2,2) H=polhermite(5); subst(H,x,2) == polhermite(5,2) L=pollegendre(5); subst(L,x,2) == pollegendre(5,2) polchebyshev(-1,2,2) polchebyshev(-2,2,2) polchebyshev(4,2,2) z=Mod(2,2^64+13); N=1000; T=polchebyshev(N,1);subst(T,x,z) == polchebyshev(N,1,z) T=polchebyshev(N,2);subst(T,x,z) == polchebyshev(N,2,z) T=polhermite(N);subst(T,x,z) == polhermite(N,z) T=pollegendre(N);subst(T,x,z) == pollegendre(N,z) pari-2.11.2/src/test/in/elltors0000644000175000017500000000514713326135265014756 0ustar billbilldo(e)=elltors(ellinit(e)); do([0, -1, 1, -7820, -263580]) do([1, 0, 1, -171, -874]) do([0, 1, 1, -9, -15]) do([1, 1, 1, -80, 242]) do([0, -1, 1, -10, -20]) do([1, 0, 1, 4, -6]) do([1, -1, 1, -3, 3]) do([1, 1, 1, 35, -28]) do([1, -1, 1, -14, 29]) do([1, 0, 0, -45, 81]) do([1, -1, 1, -122, 1721]) do([1, 1, 1, -135, -660]) do([1, 1, 1, -10, -10]) do([1, 0, 1, -19, 26]) do([1, 0, 0, -1070, 7812]) do([1,0,0,-372368141774940800,87459461608665181808640000]) do([0,706607569223786457,0,-1866575649655837263252847197205171425,-1298198297451307472292414787720779720378300792679274425]) K=nfinit(t^2-5); s=Mod(t,K.pol); E=ellinit([-31/60*s-1/12, -11/9*s-8/3, -11/9*s-8/3, 0, 0], K); T=elltors(E) ellorder(E,T.gen[1]) ellorder(E,T.gen[2]) K=nfinit(t^4+18*t^2-324*t-27);E=ellinit([1,3],K); elltors(E) do(v,K)= { my(e=ellinit(v,K), t=elltors(e)); if (apply(p->ellorder(e,p),t.gen) != t.cyc, error(v)); t; } K=nfinit(t^8-998*t^6+44424*t^4+5106934*t^2+126046063); do([1,3],K) K=nfinit(polcyclo(11,t)); do([0,-1,1,0,0],K) \\ [11] K = nfinit(y^2+7); a1=-209*y-579; a2=26752*y+147840; a3=-10486784*y-57953280; do([a1,a2,a3,0,0],K) \\ [15] a1=(-2*y+15); a2=26*y-14; a3=26*y-14; do([a1,a2,a3,0,0],K) \\ [10,2] a2=-261214369/131072; a4=75626226572068161/68719476736; K=nfinit(y^2+2); do([0,a2,0,a4,0],K) \\ [12,2] K=nfinit(y^2-13); a2=(-4289032*y+15673889)/65536 a4=(-32028469200*y+115490749725)/4194304 do([0,a2,0,a4,0],K) \\ [14] K=nfinit(y^2+11); a1=-2601888534886283704*y+154252733407512581857; a2=-313766195076761969526071169866614175160*y+1735663223649526033628839600302712469280 a3=-43286504429925775681153399339981518914403432663035092419000*y+239448337641930912934754848966237361950084593095601008052000; do([a1,a2,a3,0,0],K) \\ [16,2] K=nfinit(y^4+2002*y^2+116281); a2=12974641/13176900; a4=16/14641; do([0,a2,0,a4,0],K) \\ [3,3] K=nfinit(y^2+3); do([1,-1,0,12,8],K) \\ [20] K=nfinit(y^3-y^2-2*y-2); a=(-5*y^2-y)/2; b=-14*y^2-12*y-8; do([a,b,b,0,0],K) \\ [6,6] K=nfinit(y^4+5*y^2+1); a=9/8; b=7/64; do([a,b,b,0,0],K) \\ [8,4] K=nfinit(y^4+541*y^2+72900); a=431/690; b=-259/529; do([a,b,b,0,0],K) \\ [8,8] K=nfinit(y^16-8*y^15+36*y^14-104*y^13+220*y^12-368*y^11+516*y^10-624*y^9+664*y^8-624*y^7+516*y^6-368*y^5+220*y^4-104*y^3+36*y^2-8*y+1); do([-1,0],K) \\ [9,3] K=nfinit(x^6+3); do([1,-1,1,-14,29],K) E = ellinit([-2147484185^2,0]); elltors(E) ellorder(E, [0,0]) ellorder(E, [2147484185, 0]) ellorder(E, [2147484185/3, 1/11]) E = ellinit([1,1]); P = [72, 611]; ellorder (E, ellmul(E, P, 20)) \\#1660 do([2,x],nfinit(x^2+2)) \\#1920 E=ellinit([0,1,1,-1805632198953220354072743054330,937164323059943920996847199260009653476285734]); elltors(E) pari-2.11.2/src/test/in/zetahurwitz0000644000175000017500000000151113457566441015672 0ustar billbilldefault(realprecision,38); check(a,b)=my(c=abs(a-b)); if(!c,-oo, ceil(log(c)/log(10))); f(s,x)=check(zetahurwitz(s,x)+zetahurwitz(s,x+1/2), 2^s*zetahurwitz(s,2*x)); f(Pi,Pi) f(Pi,Pi+I*log(2)) check(zetahurwitz(Pi,1),zeta(Pi)) s = Pi+I*log(2); check(zetahurwitz(s,1), zeta(s)) check(zetahurwitz(s,3), zeta(s)-1-1/2^s) check((zetahurwitz(s,1/4)-zetahurwitz(s,3/4))/4^s, lfun(-4,s)) check(zetahurwitz(-3.4,1), zeta(-3.4)) check(zetahurwitz(2.1,1,2), zeta''(2.1)) zetahurwitz(2, I, 18) zetahurwitz(7+O(7^5),1) zetahurwitz(7+O(7^5),2) zetahurwitz(3+O(2^5),1/2) zetahurwitz(3+O(2^5),1/4) zetahurwitz(3,2+O(5^5)) zetahurwitz(-2.3,Pi+I*log(2)) zetahurwitz(-1+x^2,1) zetahurwitz(1+x + O(x^7),2) zetahurwitz(x,1+x) zetahurwitz(x,2) zetahurwitz(x,2,1) zetahurwitz(1,Pi) zetahurwitz(1+O(x),1) zetahurwitz(O(2)+x,1) zetahurwitz(y+x,1) zetahurwitz([],[]) pari-2.11.2/src/test/in/bnr0000644000175000017500000000474713447371554014067 0ustar billbilldefault(realprecision,38); K=bnfinit(x^3-x-1); subgrouplist(bnrinit(K,10)) K=bnrinit(K,20); default(realprecision,77); nfnewprec(K); default(realprecision,38); subgrouplist(K) subgrouplist(K, 2) subgrouplist(K, 2, 1) bnrconductor(bnfinit(K),4,Mat(3)) Qi = bnfinit(x^2+1); bnrL1(bnrinit(Qi,10,1),1); bnrisconductor(bnrinit(Qi,x-5),[1]) setrand(5);bnrL1(bnrinit(bnfinit(y^2+6),1,1),0); bnrL1(bnrinit(bnfinit(x),[5,[1]])); \\ #1399 bnrdisc(bnfinit(y^2+1), 12) setrand(1);bnf=bnfinit(x^2-x-57); test(m)= { print(bnrisconductor(bnf,m), ", ", bnrclassno(bnf,m), ", ", bnrdisc(bnf,m)); } test([[25,13;0,1],[1,1]]) test([[25,13;0,1],[1,0]]) test([[5,3;0,1],[1,0]]) test([5,3;0,1]) m=[idealfactor(bnf,[5,3;0,1]),[1,0]]; H=Mat(2); bnr=bnrinit(bnf, idealstar(bnf,m,2)); f=[bnrclassno,bnrdisc,bnrconductor]; { for (i=1,#f, print(f[i](bnr)); print(f[i](bnr,H)); print(f[i](bnf,m)); print(f[i](bnf,m,H)); ) } bnrdisc(bnf,m,H,1) bnrdisc(bnf,m,H,2) bnrdisc(bnf,m,H,3) bnrdisc(bnf,[5,3;0,1],H,2) bnrdisc(bnf,[5,3;0,1],H,3) bnrclassno(bnf, idealprimedec(bnf,5)[1]) bnr=bnrinit(bnf,[7,[1,1]]); bnrclassno(bnf,[7,Vecsmall([1,2])]) bnrclassno(bnf,[7,Vecsmall([1])]) bnrclassno(bnf,[7,Vecsmall([2])]) bnrclassno(bnf,[7,Vecsmall([])]) bnrclassno(bnf,[7,Vecsmall([1,2,3])]) bnrrootnumber(bnr, [2,1]) bnrrootnumber(bnr, [0,0]) bnrconductor(bnr,[0,0]) chi=[1,0]; bnrconductor(bnr,chi) charorder(bnf,[1]) chareval(bnf,[1], idealprimedec(bnf,3)[1]) charorder(bnr,chi) chareval(bnr,chi,2) chareval(bnr,chi,1/7) chareval(bnr,chi,x+1) chareval(1,chi,1) L=idealprimedec(bnf,3); bnr=bnrinit(bnf,[L[1],[1,1]]); chi=[3]; chareval(bnr,chi,1) chareval(bnr,chi,L[1].gen[2]) chareval(bnr,chi,L[2].gen[2]) bnr=bnrinit(bnfinit(x^2-97),1); bnrrootnumber(bnr,[]) narrow(T)=bnfnarrow(bnfinit(T)); narrow(x^2-460) narrow(x^6-x^5-12*x^4+5*x^3+23*x^2-6*x-9) narrow(x^2-9004) narrow(x^2-7980) \\#1804 K=bnfinit(y^2-5); bnr = bnrinit(K,[1,[1,1]]); bnrdisc(bnr) bnrdisc(bnr,,,1) bnrdisc(bnr,,,2) bnrdisc(K,[1,[1,0]],,2) bnrdisc(K,[1,[0,0]],,2) ideallog(K,1/2,idealstar(K,[1,[1,1]])) setrand(1); F = bnfinit(x^3-3); f = idealmul(F, idealprimedec(F,3)[1], 5); bnr = bnrinit(F, [f, [1]]); C = bnr.cyc; forvec(c = vector(#C,i,[0,C[i]-1]), print(bnrrootnumber(bnr,c))) bnf=bnfinit(x^2+69); id = [9,0;0,3]; bnrinit(bnf,id,1).clgp bnf=bnfinit(x^2-x+6);bnr=bnrinit(bnf,[29,18;0,1],1); bnrisprincipal(bnr,1) bnrinit(bnf,idealfactor(bnf,1)).no \\ #1890 bnf=bnfinit(x^2-486); P2 = idealprimedec(bnf,2)[1]; P3 = idealprimedec(bnf,3)[1]; bnrinit(bnf, [[P2,1;P3,15],[1,1]], 1); pari-2.11.2/src/test/in/alghasse0000644000175000017500000001677713326135265015074 0ustar billbilldefault(realprecision,38); default(parisize,100M); \\Tests related to hasse invariants in algebras do(name, test) = { setrand(1); print(name,": ", iferr(test(), E, E)); } gusuite(name, tests) = print("Suite: ", name); tests(); searchin(hf,pr,h) = { my(i,n); for(i=1,#hf[1], if(hf[1][i]==pr, return(hf[2][i]==h)) ); return(h==0); }; samehasse(hf1,hi1,hf2,hi2) = { my(i,n); if(hi1 != hi2, return(0)); n = #hf1[1]; for(i=1,n, if(!searchin(hf2,hf1[1][i],hf1[2][i]), return(0)); ); n = #hf2[1]; for(i=1,n, if(!searchin(hf1,hf2[1][i],hf2[2][i]), return(0)); ); return(1); }; hassetriv(hf,hi) = samehasse(hf,hi,[[],Vecsmall([])],Vecsmall(vector(#hi,i,0))); altriv(al) = hassetriv(alghassef(al),alghassei(al)); alsame(al,hf,hi) = samehasse(alghassef(al),alghassei(al),hf,hi); alcheckhasse(al) = { my(n,h); n = algdegree(al); h = Mod(0,n); for(i=1, #alghassef(al)[1], h += alghassef(al)[2][i]); for(i=1, #alghassei(al), h += (n/2)*alghassei(al)[i]); return(h == Mod(0,n)); }; al_cyclotomic(p,b,mo=1) = { my(Q,F,pc,r); Q = nfinit(y); pc = polcyclo(p,x); F = rnfinit(Q,pc); r = lift(znprimroot(p)); return(alginit(F, [Mod(Mod(1,y)*x^r,pc), b], 'x, mo)); }; hasse0() = gusuite("hasse sum to 0", ()->{ do("cyclo construction", ()->al_cyclotomic(3,-175624635)); do("cyclo ramified at infinity", ()->alcheckhasse(al_cyclotomic(3,-175624635))); do("cyclo unramified at infinity", ()->alcheckhasse(al_cyclotomic(3,2763764))); do("cyclo 5", ()->alcheckhasse(al_cyclotomic(5,7861623))); do("cyclo 5 bis", ()->alcheckhasse(al_cyclotomic(5,6569846846546548798*25))); do("cyclo 7 bis no mo", ()->alcheckhasse(al_cyclotomic(7,168656465154165487*7^3,0))); do("cyclo 11 no mo", ()->alcheckhasse(al_cyclotomic(11,87165765,0))); do("quat -1,-1 over Q", ()->alcheckhasse(alginit(nfinit(y),[-1,-1]))); do("quat -1,-1 over Q(sqrt(2))", ()->alcheckhasse(alginit(nfinit(y^2-2),[-1,-1],x))); do("quat -1,-1 over Q(sqrt(60))", ()->alcheckhasse(alginit(nfinit(y^2-60),[-1,-1],x))); }); alfromhasse() = gusuite("algebra from Hasse invariants", ()->{ my(nf, pr7, pr13, finvm, finv, finv1, finv2, iinvm, iinv, iinv1, iinv2, d1,\ d2, d, dm, mai, al); nf = nfinit(y^3+y^2-2*y-1); pr7 = idealprimedec(nf,7); pr13 = idealprimedec(nf,13); J = varhigher("J"); al = alginit(nf,3,J); do("matrix algebra invariants", ()->altriv(al)); d1 = 3; finv1 = [pr13,Vecsmall([1,1,1])]; iinv1 = Vecsmall([0,0,0]); al = alginit(nf,[d1,finv1,iinv1],J); do("algebra 1 invariants", ()->alsame(al,finv1,iinv1)); d2 = 2; finv2 = [pr7,Vecsmall([1])]; iinv2 = Vecsmall([1,0,0]); al = alginit(nf,[d2,finv2,iinv2],J); do("algebra 2 invariants", ()->alsame(al,finv2,iinv2)); nf = nfinit(y); p13 = idealprimedec(nf,13)[1]; finv1 = [[p13],[Mod(1,2)]]; iinv1 = Vecsmall([1]); do("test", ()->alginit(nf,[2,finv1,iinv1],J)); d = 6; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; p7 = idealprimedec(nf,7)[1]; p11 = idealprimedec(nf,11)[1]; finv = [[p3,p5,p7,p11], Vecsmall([3,2,2,2])]; iinv = Vecsmall([3]); al = alginit(nf,[d,finv,iinv],J,0); do("degree 6 algebra over Q", ()->alsame(al,finv,iinv)); nf = nfinit(y^2-5); finv1 = [[],[]]; iinv1 = Vecsmall([1,1]); do("trivial finite conditions", ()->my(al=alginit(nf,[2,finv1,iinv1])); [alghassei(al),alghassef(al)]); }); all() = gusuite("all", ()->{ hasse0(); alfromhasse(); }); all(); \\better accessors for hasse invariants print("better accessors"); setrand(1); x='x; nf = nfinit(y^3-y+1); rnf = rnfinit(nf, polcyclo(5,x)); al = alginit(rnf, [x^2,-2],, 0); alghasse(al,1) alghasse(al,2) alghasse(al,idealprimedec(nf,2)[1]) alghasse(al,idealprimedec(nf,3)[1]) alghasse(al,idealprimedec(nf,5)[1]) alghasse(al,idealprimedec(nf,5)[2]) algindex(al,1) algindex(al,2) algindex(al,idealprimedec(nf,2)[1]) algindex(al,idealprimedec(nf,3)[1]) algindex(al,idealprimedec(nf,5)[1]) algindex(al,idealprimedec(nf,5)[2]) algindex(al) algisdivision(al,1) algisdivision(al,2) algisdivision(al,idealprimedec(nf,2)[1]) algisdivision(al,idealprimedec(nf,3)[1]) algisdivision(al,idealprimedec(nf,5)[1]) algisdivision(al,idealprimedec(nf,5)[2]) algisdivision(al) algissplit(al,1) algissplit(al,2) algissplit(al,idealprimedec(nf,2)[1]) algissplit(al,idealprimedec(nf,3)[1]) algissplit(al,idealprimedec(nf,5)[1]) algissplit(al,idealprimedec(nf,5)[2]) algissplit(al) algisramified(al,1) algisramified(al,2) algisramified(al,idealprimedec(nf,2)[1]) algisramified(al,idealprimedec(nf,3)[1]) algisramified(al,idealprimedec(nf,5)[1]) algisramified(al,idealprimedec(nf,5)[2]) algisramified(al) algramifiedplaces(al) print(" "); al = 0; al = alginit(rnf, [x^2,-1],, 0); alghasse(al,1) alghasse(al,2) alghasse(al,idealprimedec(nf,2)[1]) alghasse(al,idealprimedec(nf,5)[1]) alghasse(al,idealprimedec(nf,5)[2]) algindex(al,1) algindex(al,2) algindex(al,idealprimedec(nf,2)[1]) algindex(al,idealprimedec(nf,5)[1]) algindex(al,idealprimedec(nf,5)[2]) algindex(al) algisdivision(al,1) algisdivision(al,2) algisdivision(al,idealprimedec(nf,2)[1]) algisdivision(al,idealprimedec(nf,5)[1]) algisdivision(al,idealprimedec(nf,5)[2]) algisdivision(al) algissplit(al,1) algissplit(al,2) algissplit(al,idealprimedec(nf,2)[1]) algissplit(al,idealprimedec(nf,5)[1]) algissplit(al,idealprimedec(nf,5)[2]) algissplit(al) algisramified(al,1) algisramified(al,2) algisramified(al,idealprimedec(nf,2)[1]) algisramified(al,idealprimedec(nf,5)[1]) algisramified(al,idealprimedec(nf,5)[2]) algisramified(al) algramifiedplaces(al) print(" "); al = 0; al = alginit(rnf, [x^2, 1],, 0); alghasse(al,1) alghasse(al,2) alghasse(al,idealprimedec(nf,2)[1]) alghasse(al,idealprimedec(nf,5)[2]) algindex(al,1) algindex(al,2) algindex(al,idealprimedec(nf,2)[1]) algindex(al,idealprimedec(nf,5)[2]) algindex(al) algisdivision(al,1) algisdivision(al,2) algisdivision(al,idealprimedec(nf,2)[1]) algisdivision(al,idealprimedec(nf,5)[2]) algisdivision(al) algissplit(al,1) algissplit(al,2) algissplit(al,idealprimedec(nf,2)[1]) algissplit(al,idealprimedec(nf,5)[2]) algissplit(al) algisramified(al,1) algisramified(al,2) algisramified(al,idealprimedec(nf,2)[1]) algisramified(al,idealprimedec(nf,5)[2]) algisramified(al) algramifiedplaces(al) print("Hasse inv 0 bug"); setrand(1); a='a; K=nfinit(a);PR=idealprimedec(K,2);A=alginit(K,[3,[PR,[0]],[0]],,0); algdegree(A) algdim(A) algindex(A) algisdivision(A) algadd(A,[1,0,0,0,0,0,0,0,0]~,[1,2,3]~) algsub(A,[1,0,0,0,0,0,0,0,0]~,[1,2,3]~) algmul(A,[0,0,0,0,0,0,0,0,0]~,[1,2,3]~) print("\ntests with splitting field that does not descend"); setrand(1); nf = nfinit(y^2-5); al = alginit(nf,[y,-1]); algramifiedplaces(al) al = alginit(nf,[-3+y,-1]); algramifiedplaces(al) al = alginit(nf,[-3+y,y]); algramifiedplaces(al) nf = nfinit(y^4 - 10*y^2 + 1); p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; al = alginit(nf, [2, [[p3,p5],[1/2,1/2]], [1/2,0,0,1/2]]); algramifiedplaces(al) al = alginit(nf, [2, [[p3],[1/2]], [0,1/2,0,0]]); algramifiedplaces(al) nf = nfinit(y^8 - 40*y^6 + 352*y^4 - 960*y^2 + 576); p3 = idealprimedec(nf,3)[1]; al = alginit(nf, [2,[[p3],[1/2]], [1/2,0,0,1/2,1/2,0,0,0]]); algramifiedplaces(al) print("degree bug"); nf = nfinit(y); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; al = alginit(nf, [4,[[p2,p3],[1/2,1/2]],[0]]); algdegree(al) {for(i=1,10, al = alginit(nf, [2,[[p2,p3],[0,0]],[0]]); print1(algdegree(al)," "); )}; al = alginit(nf, [4,[[p2,p3],[0,0]],[0]]); algdegree(al) nf = nfinit(z^2+1); p31 = idealprimedec(nf,31)[1]; p2 = idealprimedec(nf,2)[1]; {for(i=1,10, al = alginit(nf, [2, [[p31,p2], [0, 0]], []]); print1(algdegree(al)," "); )}; pari-2.11.2/src/test/in/select0000644000175000017500000000043613201017466014537 0ustar billbillselect(isprime, vector(50,i,i^2+1)) select(isprime, List([1,2,3,4,5]), 1) select(isprime, List([1,2,3,4,5])) select(x->(x<100), %) select(x->x, [0,1,2;0,2,0]) select(x->!x, [0,1,2;0,2,0]) [x|x<-List(),x%2] [x|x<-List([1..4]), x%2] v=Vecsmall([1,2,3]); select(x->x,v,1) select(x->x,v) pari-2.11.2/src/test/in/mathnf0000644000175000017500000000167013326135265014544 0ustar billbill\e mathnf([0,2]) mathnf([0,2], 1) mathnf([0,x]) mathnf([0,x], 1) mathnf([x;1]) mathnf([x;1], 1) mathnf([x,x^2+1; x^3+x+1, x+2]*Mod(1,5)) v=[116085838, 181081878, 314252913,10346840]; [H,U]=mathnf(v, 1); [v*U, norml2(U)] [H,U]=mathnf(v, 5); [v*U, norml2(U)] M=[0,0,0,0,0,0,0,0,0,13;0,0,0,0,0,0,0,0,23,6;0,0,0,0,0,0,0,23,-4,-7;0,0,0,0,0,0,17,-3,5,-5;0,0,0,0,0,56,16,-16,-15,-17;0,0,0,0,57,24,-16,-25,2,-21;0,0,0,114,9,56,51,-52,25,-55;0,0,113,-31,-11,24,0,28,34,-16;0,50,3,2,16,-6,-2,7,-19,-21;118,43,51,23,37,-52,18,38,51,28]; mathnf(M) mathnf([]) mathnf([],1) mathnf([;]) mathnf([;],1) mathnfmodid(matrix(0,2), []) mathnfmodid([0,7;-1,0;-1,-1], [6,2,2]) mathnfmodid([;],[2]) matsolvemod([;],[]~,[]~,1) matsolvemod([;],[],[]~,1) matsolvemod([;],[]~,[],1) matsolvemod([;],2,[1]~,1) matsolvemod([;],[2]~,[1]~,1) matsolvemod([;],[2]~,1,1) matsolvemod([;],1,1,1) matsolvemod([1,2;3,4],1,2,1) \\ Errors, keep at end of file matsolvemod([;],[2]~,[2,3]~,1) pari-2.11.2/src/test/in/logint0000644000175000017500000000022313326135265014554 0ustar billbilllogint(2^99,2) logint(2^100,2,&z) z logint(5^100,2,&z) z logint(5^100,3) logint(5^100,4) logint(5^100,5) logint(2^64-1, 2^32) logint(2^64-1, 2^16) pari-2.11.2/src/test/in/idealramgroups0000644000175000017500000000165513326135265016310 0ustar billbill{ K=nfinit(x^30 - 240*x^28 + 24364*x^26 - 1366520*x^24 + 46492470*x^22 - 994986280*x^20 + 13527103660*x^18 - 116596891080*x^16 + 634140564945*x^14 - 2144111162280*x^12 + 4349007947424*x^10 - 4933119511040*x^8 + 2746986107136*x^6 - 564152514560*x^4 + 40138752000*x^2 - 409600000); G=galoisinit(K); forprime(p=2,37, pr = idealprimedec(K,p)[1]; print(pr.p,":", apply(galoisidentify,idealramgroups(K,G,pr)))) } K=nfinit(x^6 + 12*x^5 + 60*x^4 + 376*x^3 + 80268*x^2 + 4569240*x + 66227068); G=galoisinit(K); D=idealprimedec(K,29)[1]; [idealfrobenius(K,G,D),idealramgroups(K,G,D)] K=nfinit(polcyclo(24)); G=galoisinit(K); P=idealprimedec(K,2)[1]; idealramgroups(K,G,P) \\#1755 P=x^8-12*x^6+36*x^4-36*x^2+9;N=nfinit(P);G=galoisinit(N); idealramgroups(N,G,idealprimedec(N,3)[1]) \\#1908 P=x^12+60*x^10+1260*x^8+10900*x^6+34200*x^4+9000*x^2+500;N=nfinit(P); G=galoisinit(N); pr=idealprimedec(N,2)[1]; ram=idealramgroups(N,G,pr); #ram pari-2.11.2/src/test/in/vararg0000644000175000017500000000115113244617205014541 0ustar billbillmyprintsep(s,v[..])=if(#v>0,print1(v[1]);for(i=2,#v,print1(s,v[i])));print(); print(myprintsep) ?myprintsep print1(":");myprintsep() print1(":");myprintsep(", ") myprintsep(", ",a,b,c,d) myprintsep(", ",a,,c,) myprintsep(,a,b,c,d) myprintf = printf; myprintf("x=%d\n",5) myprintf("x=%d y=%d\n",5,7) myprintf("x=%d y=%d z=%d\n",5,7,9) default(strictargs,1) myprintsep(s,v[..])=if(#v>0,print1(v[1]);for(i=2,#v,print1(s,v[i])));print(); print1(":");myprintsep() print1(":");myprintsep(", ") myprintsep(", ",a,b,c,d) myprintsep(,a,b,c,d) myprintsep(", ",a,,c,) make_function(a) = (b,c)->123; f=make_function(456); f(1) pari-2.11.2/src/test/in/real0000644000175000017500000000121313326135265014203 0ustar billbill{ if (sizebyte(0)==16, \\ #1322 default(realprecision,2); print(1. << 2^60); print(1. >> 2^60); , \\ can't be tested on 32-bit kernel: fake answer print("5.9 E347063955532709820"); print("1.7 E-347063955532709821"); ); } 1. << 2^64 1. >> 2^64 1+0e1 0e1==1 0e1==1. 0e1<1 0e1<1. 0e1<=1 0e1<=1. 0e1>1 0e1>1. 0e1>=1 0e1>=1. 0e-1==1 0e-1==1. 0e-1<1 0e-1<1. 0e-1<=1 0e-1<=1. 0e-1>1 0e-1>1. 0e-1>=1 0e-1>=1. exponent(0) exponent(-1) exponent(1/2) exponent(2.0) exponent([-10,5,11]) exponent([-10,5;11,16.0]) exponent(2.*x - 1.) exponent(2.*x - 1. + O(x^2)) exponent(quadgen(-15)) v=[1,1/2,2+3*quadgen(-3),2+3*I, (2+3*I)/(x+1)]; real(v) imag(v) pari-2.11.2/src/test/in/deriv0000644000175000017500000000160613457566441014410 0ustar billbilldefault(realprecision,38); sin'(4) sin'(1+I) sin'(x) sin'("") derivnum(x=4,sin(x)) derivnum(x=t^2+O(t^4),sin(x)) derivnum(x=t,sin(x)) derivnum(x=1/(1+t),sin(x)) derivnum(x=1,Pi^x) v=[Mod(x*y+1,x^2+1), Mod(1,3), ffgen(2^3,'t), 1+x*y+O(x^3), x/(x+y), (x^3/3+x+1) / (x^2+1)^2, [x*y], Mat(x*y)]; { for (i=1,#v, my(u=v[i]); print(deriv(u,'x)); print(u'); print(deriv(u,'y)); iferr(print(intformal(u,'x)),E,print(E)); iferr(print(intformal(u,'y)),E,print(E)); ) } intformal(1-A,Y) a=intformal(Pol(0,x), y) b=intformal(Pol(0,y), x) variable(a) variable(b) a=intformal(O(x), y) b=intformal(O(y), x) variable(a) variable(b) f(x) = (x^2+x)*'y; f'(1) f''(1) derivnum(x=0,1/(x^2+1),2) derivnum(x=t,1/(x^2+1),2) derivnum(x=1/t,1/(x^2+1),2) derivnum(x=0,exp(sin(x)),16) round( derivnum(x=0,exp(sin(x)),[0..13]) ) derivnum(t=x^2,exp(t),4) derivnum(z=0,0,0) derivnum(z=0,0,[0,-1]) derivnum(z=0,0,[1,-1]) pari-2.11.2/src/test/in/bbhnf0000644000175000017500000001176413457566437014371 0ustar billbillranddistinct(n) = { my(i=0,j=0); while(i==j, i = random([1,n]); j = random([1,n]); ); [i,j]; } randSLn(n,nb,B,A = matid(n)) = { my(i,j,a,tmp); for(count=1,nb, [i,j] = randdistinct(n); a = random([-B,B]); A[,i] = A[,i] + a*A[,j]; [i,j] = randdistinct(n); ); A; } rmzerocol(A) = { my(L=[]); for(i=1,#A, if(A[,i]!=0, L = concat(L,[A[,i]])) ); matconcat(L); } print("bb hermite Z/NZ"); N=1800; nb = 500; setrand(1); print("imagemod"); {for(m=1,4, for(n=1,4, for(count=1,nb, A = matrix(m,n,i,j,random([0,N-1])); h1 = mathnfmodid(A,N); h2 = matimagemod(A,N,&U); if(rmzerocol(h1%N)!=h2, print("fail: ", A)); if(A*(U*Mod(1,N))!=h2, print("fail2: ", A, "\n", h2, "\n", U)); ); ); );} {M = matdiagonal([900,4,9,25,10]);M[1,]=[900,2*65,9*13,25*11,5*17];} H = matimagemod(M,N) nb = 250; {for(count=1,nb, A = randSLn(5,50,N,M); if(H != matimagemod(A,N), print("fail3: ", A); ); );} {M = [11,28,-1; 2,1,89; 5,78,15; 0,8,3; 0,0,3 ];} H = matimagemod(M,N) {for(count=1,300, A = randSLn(3,30,N,M); if(H != matimagemod(A,N), print("fail4: ", A); ); );} print("kermod"); d=1800; nb=250; setrand(1); {for(m=1,5, for(n=1,5, for(count=1,nb, M = matrix(m,n,i,j,random([0,d-1])); K = matkermod(M,d,&im); if((M*K)%d!=0, print("fail:", M)); K2 = matsolvemod(M,d,0,1)[2]; K3 = matimagemod(K2,d); if(K!=K3, print("fail2:", M, K, K3)); im2 = matimagemod(M,d); if(im!=im2, print("fail3:", M, im, im2)); ); ); );} d = 6; matkermod(Mat([0]),d) matkermod(Mat([1]),d) matkermod(Mat([2]),d) matkermod([1;0],d) matkermod([2;0],d) matkermod([0;0],d) matkermod([3;0],d) matkermod([0;1],d) matkermod([0;2],d) matkermod([1;3],d) matkermod([2;3],d) matkermod([2;4],d) matkermod(Mat([1,0]),d) matkermod(Mat([0,1]),d) matkermod(Mat([2,0]),d) matkermod(Mat([1,3]),d) matkermod(Mat([0,3]),d) matkermod(Mat([2,3]),d) matkermod([1,0;0,0],d) matkermod([2,0;0,3],d) matkermod([1,1;0,1],d) matkermod([2,1;0,3],d) matkermod([4,2;4,2],d) matkermod([2,2;3,0],d) print("invmod"); d=1800; nb=100; setrand(1); {for(m=1,5, for(n=1,5, for(count=1,nb, M = matrix(m,n,i,j,random([0,d-1])); U = 0; iferr(U = matinvmod(M,d),E, if(errname(E)!="e_INV", print(E)) ); if(U!=0 && (U*M)%d != 1, printsep(" ", "fail 1800:", M, U, (U*M)%d)); ); ); );} d=31; nb=100; setrand(1); {for(m=1,5, for(n=1,5, for(count=1,nb, M = matrix(m,n,i,j,random([0,d-1])); U = 0; iferr(U = matinvmod(M,d),E, if(errname(E)!="e_INV", print(E)) ); if(U!=0 && (U*M)%d != 1, printsep(" ", "fail 31:", M, U, (U*M)%d)); ); ); );} \\matsolvemod aff2lin(X) = mathnf(matconcat([X[2],X[1];0,1])); M = [1,2;3,4]; aff2lin(matsolvemod(M, [3,4]~, [1,2]~, 1)) aff2lin(matsolvemod(M, 3, [1,1]~, 1)) aff2lin(matsolvemod([1,1;1,1], [15,6]~, [2,2]~, 1)) aff2lin(matsolvemod(Mat([2,4,6]), 8, [2]~, 1)) aff2lin(matsolvemod([3;5;7], [2,3,5]~, [-1,-2,-3]~, 1)) aff2lin(matsolvemod([7,8,6;1,11,16],512,[-1,-1]~,1)) matsolvemod([1,1;1,1], 32, [17,1]~) matsolvemod(Mat(1),2,[1]~) matsolvemod([;],2,1) matsolvemod([;],2,0) matsolvemod([;],[2,2]~,1) matsolvemod([;],[2,2]~,0) matsolvemod([;],[2,2]~,[0,0]~) matsolvemod([;],[2,2]~,[1,2]~) matsolvemod([;],2,[1,2]~) matsolvemod(Mat(1),2,1) matsolvemod([1,2;3,4],0,1) \\zero ring matimagemod([1,2;3,4],1) matdetmod(Mat(3),1) matdetmod([;],1) matkermod([1,2;3,4],1) matinvmod([1,2;3,4],1) matinvmod([1,2;3,4;5,6],1) matsolvemod(Mat(1),1,[1]~,1) \\examples from docu A = [2,1;0,2]; matimagemod(A,6,&U) U (A*U)%6 A = [1,2,3;5,1,4] K = matkermod(A,6) (A*K)%6 A = [3,1,2;1,2,1;3,1,1]; U = matinvmod(A,6) (U*A)%6 A = [4,2,3; 4,5,6; 7,8,9]; matdetmod(A,27) \\end examples matdetmod([0,1;1,0],9) matdetmod([7,1;1,0],9) matdetmod([6,0;0,1],9) matimagemod([1;2],4) matimagemod([4,1;0,4],8,&U) U matsolvemod(matrix(1,0),0,[0]~) matsolvemod(matrix(1,0),0,0) matsolvemod(matrix(1,0),[0]~,[0]~) matsolvemod(matrix(1,0),[0]~,[0]~,1) matsolvemod(Mat([1]),[0]~,[0]~) matsolvemod(Mat([1]),[0]~,0) matsolvemod(Mat([1]),0,0,1) matsolvemod(Mat([2]),0,1,1) matsolvemod(Mat([21,110]),0,1,1) \\matdetmod fixes M = [21,7,7;23,2,7;20,21,31]; n=36; matdetmod(M,n) == matdet(M)%n M = matrix(11,11,i,j,if(jif(abs(imag(x[2])) < 1e-38, real(x),x), v); setrand(1); filter( bnrL1(bnrinit(K,[5,[1,1]]),,5) ) setrand(1); K=bnfinit(x^2-168);\\#1601 setrand(1); bnrL1(bnrinit(K,[6,[1,1]]),,5) P=x^5-x^4-5*x^3+4*x^2+3*x-1; S=x^10-26*x^8+233*x^6-832*x^4+1024*x^2-401; bnf=bnfinit(a^2-401*25); cond=rnfconductor(bnf,P); bnr=bnrinit(bnf,cond[1]); real(bnrL1(bnr,cond[3],1)) default(realprecision,100); bnrL1(bnrinit(bnfinit(Q),[5,[1]],1))[1] pari-2.11.2/src/test/in/incgam0000644000175000017500000000175013447371554014533 0ustar billbillVs=[0,10^-10,10^-100,200,-21/2,1/2,10-I,1+128*I,60,30+60*I]; Vx=[19+236*I,1/10,-1/10,I/10,-I/10,1/10-I/10,50,100,-100,100+1001*I]; test(fun, p) = { my (P = 1/10.^(p-1)); for (i=1,#Vs, for (j=1,#Vx, my (v,w, s = Vs[i], x = Vx[j]); localprec(p); v = fun(s, x); localprec(p + 38); w = fun(s, x); e = abs((v-w)/w); \\ e = if (abs(w) < 1, abs(v-w), abs((v-w)/w)); if (e > P, printf("%9s, %13s: %.1e\n", s,x,e)); ) ); } test(incgam, 19) test(incgam, 38) test(incgam, 77) test(incgam, 96) test(incgam, 115) Vs=[1/10+1/5*I,-1/10,-1/10+2/5*I,2/5*I,-2/5*I,-1,-20,-200001/10000]; Vx=[11/10,13/10,1/10000]; test(incgam, 38) test(incgam, 76) default(realprecision, 38); incgam(-1000.4,2) incgam(1/2,10^8) incgam(-3,20) incgam(1/5,50) incgamc(2,0) printf("%.28Pg\n", imag(incgam(110.0,I))) printf("%.28Pg\n", imag(incgam(110,I))) incgam(110.0,10*I) eint1(-0.3-95*I) eint1(100) incgam(-10+1e-100,1) eint1(2,5) \p1000 eint1(100) \p481 eint1(150) eint1(0) pari-2.11.2/src/test/in/elliptic0000644000175000017500000000230413326135265015067 0ustar billbillHEAP=[76, if(sizebyte(0)==16,4255,4403)]; default(realprecision,154); Pi; default(realprecision,38); \e ellinit([-1,0]) ellinit([-17,0],1) ellsub(%,[-1,4],[-4,2]) ellj(I) \\ acurve=ellinit([0,0,1,-1,0]) apoint=[2,2] elladd(acurve,apoint,apoint) ellak(acurve,1000000007) ellan(acurve,100) ellap(acurve,10007) deu=direuler(p=2,100,1/(1-ellap(acurve,p)*x+if(acurve.disc%p,p,0)*x^2)) ellan(acurve,100)==deu ellisoncurve(acurve,apoint) acurve=ellchangecurve(acurve,[-1,1,2,3]) apoint=ellchangepoint(apoint,[-1,1,2,3]) ellisoncurve(acurve,apoint) ellglobalred(acurve) ellheight(acurve,apoint) ellordinate(acurve,1) ellpointtoz(acurve,apoint) ellztopoint(acurve,%) ellmul(acurve,apoint,10) ellwp(acurve, x+O(x^33)) q*Ser(ellan(acurve,100),q) \\ bcurve=ellinit([-3,0]) elllocalred(bcurve,2) elltaniyama(bcurve) \\ ccurve=ellinit([0,0,-1,-1,0]) l=elllseries(ccurve,2) abs(elllseries(ccurve,2,1.2)-l) < 1.4e-38 \\ tcurve=ellinit([1,0,1,-19,26]); ellorder(tcurve,[1,2]) elltors(tcurve) \\ mcurve=ellinit([-17,0]); mpoints=[[-1,4],[-4,2]]~; mhbi=ellbil(mcurve,mpoints,[9,24]) ma=ellheightmatrix(mcurve,mpoints) matsolve(ma,mhbi) \\ cmcurve=ellinit([0,-3/4,0,-2,-1]) ellmul(cmcurve,[x,y],quadgen(-7)) if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/resultant0000644000175000017500000000507013457566441015317 0ustar billbillk;c;d;e;f;g;junk2;junk3;b;h;j;a;z;x2;x3;x4;x1; allocatemem(20*10^6); do(P,Q)=my(v=variable()); substvec(polresultant(P,Q), v, vector(#v,i,i)); P = Pol([k,c,d,e,f,g]); Q = P'; do(P,Q) P = Pol([1,b,c,d,e]); Q = Pol([1,g,h,k,j]); do(P,Q) P = x^7 + x^3 + b*x^2 + c*x + d; Q = x^7 + x^3 + f*x^2 + g*x + h; do(P,Q) P = x^20 + a*x^5 + b; Q = x^20 + c*x^5 + d; do(P,Q) P = (x+a)^8; Q = (x+z)^8; do(P,Q) P = x^50 + 5*a*x^40 + 4*a*x^30 + a*x^20 + 2*a*x^10 + 3*a; Q = x^45 + 2*b*x^35 + b*x^25 + 4*b*x^15 + 5*b*x^5 + 6*b; do(P,Q) P = polcyclo(31); P = subst(P, x, a*x); Q = polcyclo(29); Q = subst(Q, x, a*x); do(P,Q) P = 1 + Polrev( vector(101, j, b^(101-j)) ); Q = 1 + Polrev( vector(101, j, b^(j-1)) ); do(P,Q) P = 1 + Polrev( vector(301,i,1) ); Q = 1 + Polrev( vector(201,i,i-1) ); do(P,Q) P = 1 + Polrev( vector(301,j, (j-1)^5) ); Q = 1 + Polrev( vector(301,j, (j-1)^4) ); do(P,Q) n = 110; polrandom(d, fudge) = x^d + Polrev(vector(d+1, i, round(2^32*sin(i+fudge)))); P = polrandom(n,0); Q = polrandom(n,1/2); do(P,Q) polresultant(-27673*x^2+322883101*x-1876122109136,x^4+4503599627370517) P=-27673*x^2+322883101*x-1876122109136; for(n=2,3,for(l=1,3,print(polresultant(P*x^l+1,n*x^4+4503599627370517)))) polresultant(z^1746-1, polcyclo(1973, z)) for(i=1,15,if(rnfequation(polcyclo(17,'y),x+y^i,1)[2]^17!=1,print("error",i))) \\ #1233 polresultantext(x^2+1, x^2-1) \\ #1234 polresultant(x^4+x^2+1, x^4-y, x, 0) p1=x2*(x3-x4);p2=x2*(x3-2*x4);polresultant(p1,p2,x1) polresultant(x,x,y) A = x*y; B = (x+y)^2; polresultant(A, B) polresultantext(A, B, y) \\ #1509 polresultantext(y^3+y,3*y^2+1,y) poldisc(x^3 + Mod(2,3)*x^2) poldisc(x^3 + Mod(2,3)*x^2+1) norm(Mod(Pol(Mod(0,2)), 3*x)) polresultantext(x+1, x^2) \\#1614 polresultant(1+x*z^2,1+y*z^4,z) polcompositum(x^5-5,x^4-2,2) polcompositum(x-1, x^2+x+1, 1) polcompositum(x-1, x, 1) polresultant(x^2+1,z,x) P=polcyclo(101);Q=P'; polresultant(P*Mod(1,3),Q) polresultant(P*Mod(1,2^127-1),Q) polresultant(Mod(1,3)*x*y*z,Mod(1,3)*(x^2+1)*y*z) polresultant(x,2) polresultant(x^2,2) polresultant(x^2,y) polresultant(y^2+1/x, y/x+1, y) check(P,Q)= { my(d=poldegree(P),e=poldegree(Q)); if(polresultant(P,Q)*y^(d*e)!=polresultant(subst(P,x,'x/y)*y^d,subst(Q,'x,x/y)*y^e),error(P)); } test(a)=check(a^0*x^6+(a^9+a^8+a^7+a^6+a^4+a^3+a)*x+(a^9+a^8+a^7+2*a^6+a^4+a^2),a^0*x^7+(a^8+a^7+a^6+a^4+a^3+a)*x+(a^9+a^7+2*a^6+a^4+a^2)); test(ffgen(2^10,'a)); test(ffgen(3^10,'a)); test(ffgen([nextprime(2^100),5],'a)); test(Mod(Mod(1,2),ffinit(2,5,'a))); test(Mod(Mod(1,3),ffinit(3,5,'a))); my(p=nextprime(2^100)); test(Mod(Mod(1,nextprime(2^100)),ffinit(p,3,'a))); pari-2.11.2/src/test/in/dirmul0000644000175000017500000000130113201017466014544 0ustar billbilldirmul([0,1],[0,1]) dirdiv([0,1,1,1,1],[1]) dirmul(vector(10,n,moebius(n)),vector(10,n,1)) dirmul([1,2,3,4],[1,2,3,4]) dirdiv([1,2,3,4],[1,2,3,4]) dirdiv([1,2,3,4],2*[1,2,3,4]) direuler(p=1.5,10.5,1/((1-X)*(1-p*X))) direuler(p=2,10,1/((1-X)*(1-p*X)), -1) direuler(p=2,10,1/((1-X)*(1-p*X)), 1) direuler(p=2,10,1/((1-X)*(1-p*X)), 2) direuler(p=2,10,1/((1-X)*(1-p*X)), 3.5) direuler(p=2,10,-1/(X^2-1)) direuler(p=2,10,(X^2-1)/(X^3+X-1)) direuler(p=I,10.5,1/((1-X)*(1-p*X))) direuler(p=2.5,I,1/((1-X)*(1-p*X))) direuler(p=2,10,1/((1-X)*(1-p*X)), I) direuler(p=2,1,1/((1-X)*(1-p*X)), 1) direuler(p=2,2,1/((1-X)*(1-p*X)), 2) direuler(p=2,2,1/((1-X)*(1-p*X)), 5) direuler(p=2,10,1/2) direuler(p=2,10,1/(x-2)) pari-2.11.2/src/test/in/sqrtn0000644000175000017500000000251213457566441014443 0ustar billbilldefault(realprecision,38); sqrt(0) sqrtn(0.,3) sqrtn(0.*I,3) sqrtn(1/2,3) sqrtn(quadgen(5),3) sqrtn(8+O(17^100), 3) test(b, M)= { my (B = b); for (i=2, M, B *= b; \\ b^i a = sqrtnint(B + 1, i); if (a != b, error([b, B, i])); ); } test(2, 100); test(2^32+1, 10); test(2^64+1, 10); a=10^1000000; sqrtnint(a,12345) sqrtnint(a,123456) sqrtnint(10^300,8) sqrtnint(10^500,27) sqrtn(Mod(0,3),-2) sqrtn(O(3),-2) sqrtn(0*ffgen((2^64+13)^2),-2) sqrtn(0*ffgen(3^2),-2) sqrtn(0*ffgen(2^2),-2) sqrtnint(10^1000,1001) sqrtn(2., 10, &z) z sqrtn(10+O(3^8), 10, &z) z sqrtn(1+O(3^3), -3) sqrtn(1,1) sqrtn(1,-1,&z) z sqrtn(Mod(2,4),3) sqrtn(Mod(2,4),3,&z) sqrtn(1, 3) sqrtint(0) iferr(sqrt(3+O(2^2)),E,E) iferr(sqrt(3+O(2^3)),E,E) iferr(sqrt(Mod(2,11)),E,E) iferr(sqrt(Mod(2,33)),E,E) sqrt(0.e-10+1e-10*I) [sqrtn(27+O(3^4),3,&z), z] [sqrtn(16+O(2^5),4,&z), z] [sqrtn(2^6+O(2^9),6,&z), z] sqrtn([8,27],3) iferr(sqrtn(Mod(2,7),3),E,E) [sqrtn(Mod(2,7),3,&z),z] iferr(sqrtn(Mod(2,21),3),E,E) iferr(sqrtn(Mod(6,35),6),E,E) [sqrtn(Mod(64,101),6,&z),z] iferr(sqrtn(Mod(3,19),4),E,E) sqrtn(0,3) check(a)= { for(d=-5,5,if(d, my(u=sqrtn(a^d,d,&z)); if(u^d!=a^d,error("sqrtn ",[a,d])); if (z^d!=1,error("sqrtn(&z)",[a,d])))); } check(Mod(3,101)); check(Mod(nextprime(2^65),nextprime(2^100))); check(ffgen([3,7])); check(ffgen([nextprime(2^100),3])); pari-2.11.2/src/test/in/polmod0000644000175000017500000000163613326135265014563 0ustar billbilltest() = { print(a*b); print(a/b); print(sqr(a)); print(a^-1); print(a^3); print(a^0); } T=2*x^2 + x + 1; a = Mod(x+1/2, T); b = Mod(x/3+1, T); test(); T=2*x^3 + x + 1; a = Mod(x^2+x+1/2, T); b = Mod(x^2+x/3+1, T); test(); modp(p) = { t = T*Mod(1,p); a = Mod((x^2+x+3) * Mod(1,p), t); b = Mod((3*x^2+2*x+5) * Mod(1,p), t); } modp(17); test(); modp(18446744073709551629); test(); (Mod(1/2, 't)*'x + Mod(1, 't)) ^ 2 Mod(Mod(x,x^2+1),x) Mod(Mod(0,2),y^0)*x*x Mod(y,x) Mod(1/y,x) Mod(O(y),x) Mod(x,y) Mod(1/x,y) Mod(1+O(y),y) Mod(1+O(y),y+1) Mod(1,7*x^0) Mod(2,13)+Mod(0,7*x^0) modreverse(Mod(0,Pol(1))) modreverse(Mod(1,x+1)) norm(Mod(2^65,3*x+1)) norm(Mod('a,3*x+1)) Mat(1/2*x) * Mat(Mod(1,x^2-2)) (Mod(5,7)*x+Mod(y^0,7*y+1))*x \\#1743 pi=Mod(z^7-1,z^24 +763670323290*z^16+335841304485*z^8+1); liftall(1/(pi*(1+O(2^20)))) \\#1748 pi=Mod(O(7^12)*z^8+z^7-1,z^24 +763670323290*z^16+335841304485*z^8+1); 1/pi; pari-2.11.2/src/test/in/ellff0000644000175000017500000000664413326135265014365 0ustar billbilldefault(parisize,"20M"); test(p,n=0,v='a,w=1)= { my(a=if(n,ffgen(p^n,v),p)); my(E=ellinit([w,1,1-w,0,a+3],a)); my(G=ellgenerators(E)); if (#G==0,return); [d1]=ellgroup(E); my(P=random(E)); G=G[1]; if(ellorder(E,G)!=d1,error([p,n,0])); if(ellmul(E,G,d1)!=[0],error([p,n,1])); if(ellmul(E,P,d1)!=[0],error([p,n,2])); if(d1%ellorder(E,P)!=0,error([p,n,3])); if (d1<10^7, P=ellmul(E,G,1023); if(elllog(E,P,G)!=1023%d1,error([p,n,4])); ); } test(2); test(2,78); test(2,100); test(2,255); test(2,1,,0); test(2,2,,0); test(2,4,,0); test(2,6,,0); test(2,101,,0); test(3,,,0); test(3,50,,0); test(3,51,,1); test(5); test(5,3,,0); test(5,6,,0); test(5,50,,0); test(7,3); test(7,51); test(11,2); test(11,12); test(11,18); test(11,19,,5); test(13,41); test(17,2); test(1009,3); test(1013,7); test(1009,11,'x); test(17); test(41); test(1073741827); test(nextprime(2^65),2); p=18446744073709551557; e=ellinit([3,3],p);N=ellcard(e); setrand(1); g=ellgenerators(e) ellorder(e,g[1]) a=ffgen(101^3,'a); E=ellinit([1,3],a); E.j E.disc P=random(E);Q=random(E); R=elladd(E,P,Q); elladd(E,ellsub(E,R,P),ellneg(E,Q)) N=ellcard(E);ellmul(E,P,N) checkorder(E, N)= { for(i=1,4, P=random(E); if(ellmul(E,P,N)!=[0],error(a))); } check(a)= { my(E,Et,P,N); E=ellinit(ellfromj(a),a); Et=ellinit(elltwist(E)); if (ellap(Et)!=-ellap(E),error("twist:",a)); N=ellcard(E); if ((N==1)!=(#random(E)==1),error(a)); checkorder(E, N); ellgenerators(E); } { for(a=1,8, g = ffprimroot(ffgen(2^a,'t)); for(i=0,2^a-2, check(g^i))); for(a=1,6, g = ffprimroot(ffgen(3^a,'t)); for(i=0,3^a-2, check(g^i))); for(a=1,4, g = ffprimroot(ffgen(5^a,'t)); for(i=0,5^a-2, check(g^i))); } testss(n,N)= { my(a); a=ffprimroot(ffgen([2,n],'a)); for(i=1,N, E=ellinit([0,0,random(a),random(a),random(a)]); if(#E, checkorder(E,ellcard(E)))); } for(i=1,8,testss(i,min(1000,2^(3*i)))); checkt(p,n,f,B=100)= { my(a=ffgen(p^n,'a)); for(i=1,B, my(E,Et,N,b); until(b,b=random(a)); E=ellinit(if(f==0,[0,b],f==1,[b,0],[b^2,b^3])); if(#E==0,next); Et=ellinit(elltwist(E)); if (ellap(Et)!=-ellap(E),error("twist:",[p,n,f])); N=ellcard(E); if(#ellmul(E,random(E),N)>1,error([p,n,f],b))); } checkt(3,5,0); checkt(3,6,0); checkt(3,5,1); checkt(3,6,1); checkt(3,5,2); checkt(3,6,2); checkt(7,5,0); checkt(7,6,0); checkt(11,5,0); checkt(11,6,0); checkt(7,5,1); checkt(7,6,1); checkt(13,5,1); checkt(13,6,1); checkt(11,6,2); checkt(13,5,2); checkt(18446744073709551667,2,0,10); checkt(18446744073709551667,3,0,10); checkt(18446744073709551667,2,1,10); checkt(18446744073709551667,3,1,10); checkt(18446744073709551667,2,2,10); checkt(18446744073709551667,3,2,10); checkt(18446744073709551629,2,0,10); checkt(18446744073709551629,3,0,10); checkt(18446744073709551629,2,1,10); checkt(18446744073709551629,3,1,10); checkt(18446744073709551629,2,2,10); checkt(18446744073709551629,3,2,10); E=ellinit([a1,a2,a3,a4,a6]*Mod(1,2)); elldivpol(E,2) check(q)= { my(g,E,x = 1,y); g = ffprimroot(ffgen(q,'t)); E = ellinit(ellfromj(g)); for(i=1,10, x *= g; y = ellordinate(E,x); for(i=1,#y, if (!ellisoncurve(E,[x,y[i]]), error([x,y]))) ); } check(2^4) check(3^4) check((2^64+13)^4) checkext(p)= { b=ffgen(p,'a); E=ellinit([1,0,0,0,1],p); a=ffgen(p^6,'b); F=ellinit(E,a); P=random(F); if (!ellisoncurve(F,P),error(p)); if(!ellisoncurve(F,ellmul(F,P,2)),error(p)); } checkext(5) checkext(3) checkext(2) pari-2.11.2/src/test/in/program0000644000175000017500000000201713326135265014732 0ustar billbillHEAP=[48, if(sizebyte(0)==16,1961,3393)]; STACK=if(sizebyte(0)==16, 232, 128); STACK == getstack default(realprecision,38); \e alias(ln,log) ln(2) for(x=1,5,print(x!)) fordiv(10,x,print(x)) forprime(p=1,30,print(p)) forstep(x=0,2.9,Pi/12,print(sin(x))) forvec(x=[[1,3],[-2,2]],print1([x[1],x[2]]," "));print(" "); if(3<2,print("bof"),print("ok")); kill(y);print(x+y); f(u)=u+1; print(f(5));kill(f); f=12 g(u)=if(u,,return(17));u+2 g(2) g(0) n=33;until(n==1,print1(n," ");if(n%2,n=3*n+1,n=n/2));print(1) m=5;while(m<20,print1(m," ");m=m+1);print() \\ default(seriesprecision,12) print((x-12*y)/(y+13*x)); print([1,2;3,4]) print1(x+y);print(x+y); print((x-12*y)/(y+13*x)); print([1,2;3,4]) print1(x+y);print1(" equals ");print(x+y); print1("give a value for s? ");s=input();print(1/(s^2+1)) printtex((x+y)^3/(x-y)^2) for(i=1,100,for(j=1,25,if(i+j==32,break(2)));print(i)) { u=v=p=q=1; for (k=1,400, w=u+v; u=v; v=w; p *= w; q=lcm(q,w); if (k%50==0, print(k" "log(p)/log(q)) ) ); } if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/diffop0000644000175000017500000000042213036414402014517 0ustar billbilldiffop(E*X,[X,E],[1,X*E],10) diffop(Mod(S/C,S^2+C^2-1),[C],[-S],10) E4(n)=1+240*sum(i=1,n,sigma(i,3)*q^i)+O(q^(n+1)); diffop(E4(15),[q],[q]) diffop(Mod(y,x^2-y),[y],[1]) diffop(Mod(10^100,x^2+y),[y],[1]) diffop(lllx,[x,lx,llx,lllx],[1,1/x,1/(x*lx),1/(x*lx*llx)],6)*Mod(1,3) pari-2.11.2/src/test/in/nfcompositum0000644000175000017500000000340013326135265016003 0ustar billbilldefault(realprecision,38); default(parisize,100M); do(name, test) = { setrand(1); print(name,": ", iferr(test(), E, E)); } gusuite(name, tests) = print("Suite: ", name); tests(); nfcompo() = gusuite("compositum of relative extensions", ()->{ my(nf, pol, ii); pol = y^2+1; nf = nfinit(pol); ii = Mod(y,pol); do("compositum of degrees 2 and 3 over quadratic field", (()->my(L=nfcompositum(nf,x^2-ii,x^3-5,3), a=Mod(L[2],L[1]), b=Mod(L[3],L[1])); polisirreducible(L[1]) && a^2-ii==0 && b^3-5==0 && b+L[4]*a==Mod(x,L[1]))); do("compositum of degrees 2 and 4 over quadratic field", (()->my(L=nfcompositum(nf,x^2-ii,x^4-5,3), a=Mod(L[2],L[1]), b=Mod(L[3],L[1])); polisirreducible(L[1]) && a^2-ii==0 && b^4-5==0 && b+L[4]*a==Mod(x,L[1]))); do("compositum of degrees 5 and 7 over quadratic field", (()->my(L=nfcompositum(nf,x^5+ii*x+1,x^7-5*x+ii,3), a=Mod(L[2],L[1]), b=Mod(L[3],L[1])); polisirreducible(L[1]) && a^5+ii*a+1==0 && b^7-5*b+ii==0 && b+L[4]*a==Mod(x,L[1]))); pol = y^5-2; nf = nfinit(pol); ii = Mod(y,pol); do("compositum of degrees 2 and 3 over degree 5 field", (()->my(L=nfcompositum(nf,x^2-ii,x^3-5,3), a=Mod(L[2],L[1]), b=Mod(L[3],L[1])); polisirreducible(L[1]) && a^2-ii==0 && b^3-5==0 && b+L[4]*a==Mod(x,L[1]))); do("compositum of degrees 2 and 4 over degree 5 field", (()->my(L=nfcompositum(nf,x^2-ii,x^4-5,3), a=Mod(L[2],L[1]), b=Mod(L[3],L[1])); polisirreducible(L[1]) && a^2-ii==0 && b^4-5==0 && b+L[4]*a==Mod(x,L[1]))); do("compositum of degrees 5 and 4 over degree 5 field", (()->my(L=nfcompositum(nf,x^5+ii*x+1,x^4-5*x+ii,3), a=Mod(L[2],L[1]), b=Mod(L[3],L[1])); polisirreducible(L[1]) && a^5+ii*a+1==0 && b^4-5*b+ii==0 && b+L[4]*a==Mod(x,L[1]))); }); nfcompo(); \\bad input nfcompositum(nfinit(x),w^2+1,w^2+1) nfcompositum(x,w^2+1,w^2+1) pari-2.11.2/src/test/in/forvec0000644000175000017500000000076513201017466014551 0ustar billbillV=vector(3,i,[3/2,3]); forvec(v=V,print(v)) print() V=vector(3,i,[3/2,4]); forvec(v=V,print(v),1) print() forvec(v=V,print(v),2) V=vector(3,i,[1,3]); forvec(v=V,print(v)) print() forvec(v=V,print(v),1) print() forvec(v=V,print(v),2) forvec(v=[[1,2],[0,1]],print(v),1) forvec(v=[[1,2],[0,1]],print(v),2) forvec(v=vector(3,i,[3/2,7/2]),print(v),1) print() forvec(v=[[3/2,3],[2,4],[3/2,5]],print(v),2) forvec(v=[],print(v)) forvec(v=[1],) forvec(v=[[1]],) forvec(v=[[1,I]],) forvec(v=[[1,1],[1,1]],,3) pari-2.11.2/src/test/in/printf0000644000175000017500000000451313201017466014562 0ustar billbilldefault(realprecision,38); aa=[1.0,2.0] bb=2.5 str="string" ii=10^100+1 /* d conversions */ printf("%%0.12ld for 1 : %0.12ld\n", 1) printf("%%ld for medium : %ld\n", 10^40+10^20+1) printf("%%ld for big : %ld\n", 7^1000) printf("%%ld for very big : %ld\n", 7^10000) /* x conversions */ printf("31 in base 16 == %x\n", 31) printf("%%X for medium : %X\n", 10^40+10^20+1) printf("%%#X for medium : %#X\n", 10^40+10^20+1) printf("%%x for 0: %x\n", 0) printf("%%#X for 0: %#X\n", 0) /* s conversion */ printf("%%10s for \"string\" : %10s\n", str) printf("%%.4s for \"string\" : %.4s\n", str) printf("%%*.*s for \"string\" : %*.*s\n", 10,2, str) printf("%%s for 1 : %s\n", 1) printf("%%s for aa : %s\n", aa) /* same as %Z */ printf("%%s for 4/3 : %s\n", 4/3) printf("%%s inter %%.2s %%4.2f for aa, bb, aa : %4s inter %.2s %4.2f\n", aa, bb, aa) Strprintf("%%s inter %%.2s %%4.2f for aa, bb, aa : %4s inter %.2s %4.2f\n", aa, bb, aa) printf("%%10.5s for 3.5 : %10.5s", 3.5) /* f conversion */ printf("%%10f for Pi : %.10f|\n", Pi) printf("%%20.10f for 2.7 : %20.10f|\n", 2.7) printf("%%+20.10f for 2.7: %+20.10f|\n", 2.7) printf("%%-20.10f for 2.7: %-20.10f|\n", 2.7) printf("%%-*.*f for 2.7: %-*.*f|\n", 20, 10, 2.7) /* e conversion */ printf("%%20.10e for 2.7 : %20.10e|\n", 2.7) printf("%%+20.10E for 2.7: %+20.10E|\n", 2.7) printf("%%-20.10e for 2.7: %-20.10e|\n", 2.7) printf("%%-20.10E for ii : %-20.10E|\n", ii) printf("%%e for 1+0*I : %E\n", 1+0*I) /* g conversion */ printf("%%8.3g for 3.14159: %8.3g\n", 3.14159) printf("%%8.3G for ii : %8.3G\n", ii) printf("%%8.3g for ii : %8.3g\n", ii) printf("%%-20.10g for 4/3 : %-20.10g|\n", 4/3) printf("%%20.13e for 4/3 : %20.13e|\n", 4/3) printf("%%e for 4/3 : %e|\n", 4/3) /* error tests */ printf("%missing argument to format\n") /* ERROR : %m is not a valid format */ printf("%d missing argument to format\n") /* ERROR : missing argument(s) to format */ printf("%%-20.10g for aa : %-20.10g\n", aa) /* ERROR : aa is not a t_REAL */ \\regression tests 10^38 + 1. printf("%.100f",1.) printf("%1.0f",0) printf("%.6f",5e-5) \\ conversions using gtolong() printf("%c",97.5) printf("%c",97+1/2) printf("%c",97 + 0.*I) printf("%c",97 +0*quadgen(5)) printf("%1.2f",Mat([1.,2.])) printf("%c",'x) default(format,"f.5") -0.00000000000000000000000000000000000000293873587705572 printf("%d",factor(2*3*5*7)) pari-2.11.2/src/test/in/lfuntype0000644000175000017500000000437313326135265015140 0ustar billbilldefault(realprecision,38); zet=1; Z(a)=lfuncreate([(p,n)->1/(1-p^a*x),0,[-a],2*a+1,1,1,[[a+1,1/x+O(1)]]]); N=nfinit(x^10-2*x^8-9*x^6+57*x^4-69*x^2+47); G=galoisinit(N); E=ellinit([0,-1,1,-10,-20]); \\ 11a1 VALL={ [zet, lfuncreate([n->vector(n,i,kronecker(i,857)),0,[0],1,857,1]), lfunthetainit(zet), lfuninit(zet,[1,1,2],2), \\5 lfuninit(x^3-x-1,[1,1,2],2), lfuninit(x^4-2,[1,1,2],2), lfuninit(x^6+108,[1,1,2],2), lfuninit(polsubcyclo(11,5),[1,1,2],2), x^3-x-1, \\10 x^4-2, polsubcyclo(11,5), 17, -4, 857, \\15 [znstar(5,1),2], E, ellinit([1,1]), ellinit([-7,3]), lfunetaquo([1,1;3,1;5,1;15,1]), \\20 lfunmul(-4,-3), lfundiv(x^3-x-1,1), bnfinit(x^4+2*x^2+5), [bnrinit(bnfinit(x^3+x^2+2*x+1),4),[1]], Z(2), \\25 lfunqf(matid(4)), lfunartin(N,G,[2,0,-y^3-y^2-1,y^3+y^2],5), lfunartin(N,G,[['a,0;0,'a^4],[0,1;1,0]],5), if(1,my(E1=ellinit([0,0,1,-1,0]),E2=ellinit([0,1,1,-23,-50])); lfuncreate([n->lfunan(E1,n)+lfunan(E2,n),n->-lfunan(E1,n)+lfunan(E2,n),[0,1],2,37,1])), lfunqf(matdiagonal([1,2,3,4])), if(1,my(K3=nfinit(a^2-a-9)); ellinit([0,2,1,-19-8*a,28+11*a],K3)), if(1,my(E=ellinit([0,-1,1,-10,-20])); \\11a1 lfuncreate([n->my(V=ellan(E,n));vector(n,i,V[i]/sqrt(i)),0,[1/2,3/2],1,11,1])), lfuntwist(E, Mod(2,5)), lfunsympow(E,2), lfunsympow(E,3) ]; } chk(s,i,a,b) = { my(e,eps); round((a-b)/b,&e); eps=10^(-precision(1.)); if(type(a)=="t_COMPLEX" && abs(imag(a))-120, error("bug in lfuntype:", s, ":", i, ":", e) ,print(i," (",s,"): ",a)); } { for(i=1,#VALL, ldata=VALL[i]; L=lfuninit(ldata,[1,1,2],2); a=lfun(L,2+2*I); b=lfun(ldata,2+2*I); chk("lfun(2+2*I)",i,a,b); a=lfun(L,2); b=lfun(ldata,2); chk("lfun",i,a,b); b=lfun(lfuncreate(ldata),2); chk("lfuncreate",i,a,b); a=lfun(L,2,2); b=lfun(ldata,2,2); chk("lfunderiv",i,a,b); a=lfunlambda(L,2); b=lfunlambda(ldata,2); chk("lfunlambda",i,a,b); a=lfunlambda(L,2,2); b=lfunlambda(ldata,2,2); chk("lfunderivlambda",i,a,b); a=lfuncheckfeq(L); b=lfuncheckfeq(ldata); chk("lfuncheckfeq",i,a,b); a=lfunhardy(L,2); b=lfunhardy(ldata,2); chk("lfunhardy",i,a,b); print(i," (lfunorderzero): ",lfunorderzero(L)); L=lfunthetainit(ldata); a=lfuntheta(L,2); b=lfuntheta(ldata,2); chk("lfuntheta",i,a,b); print(i," (lfunan): ",lfunan(ldata,10)); ) } pari-2.11.2/src/test/in/combinat0000644000175000017500000000056213201017466015054 0ustar billbillvector(10, k, stirling(11,k)) vector(11, k, stirling(12,k)) vector(10, k, stirling(11,k, 2)) vector(11, k, stirling(12,k, 2)) v = vector(5!,i,numtoperm(5, i-1)) if(vecsort(v,lex)!=v,error("numtoperm")); vector(#v, i, permtonum(v[i])) vector(#v, i, permtonum(Vecsmall(v[i]))) stirling(100,0) iferr(permtonum([1,3,0]), E, Vec(E)) permtonum(1) permtonum([]) numtoperm(0,0) pari-2.11.2/src/test/in/quadclassunit0000644000175000017500000000125213272054410016133 0ustar billbilldefault(realprecision,38); default(echo,1); test(D) = { for (d = D, D+10^3, if (!isfundamental(d),next); print(d, " ", quadclassunit(d).cyc) ); } setrand(1); test(10^15); test(-10^15) \\ #1195 setrand(11);quadclassunit(-8419588).cyc setrand(2);quadclassunit(-1459008).cyc setrand(7);quadclassunit(-3799812).cyc setrand(1); quadclassunit(-13163208).cyc \\ #1195 with non-fundamental discriminants [oo loop] setrand(38);quadclassunit(-29920).cyc quadclassunit(-13163208,,[0.1]).cyc setrand(1); quadclassunit((2^70+25)).cyc setrand(1); quadclassunit(8*3*5*7).cyc \\ #1700 setrand(1);quadclassunit(-612556842419).cyc \\ #2015 setrand(2); quadclassunit(-699,,[6,6]).cyc pari-2.11.2/src/test/in/qfb0000644000175000017500000000146713326135265014043 0ustar billbillvec(x) = [component(x,1), component(x,2), component(x,3)]; vec( qfbred(Qfb(6,6,-1),1) ) default(realprecision,38) q=Qfb(7, 30, -14)^2; qfbpowraw(q,-1) q*q^2 q^0 q^1 q^-1 q^-(2^64+1) q=Qfb(2, 1, 3); q2=q*q; q3=qfbcompraw(q,q2) qfbpowraw(q,3) qfbred(q3,1) q=Qfb(1009, 60, 99108027750247771) qfbnupow(q, 8839368315) L = sqrtnint(abs(poldisc(q)), 4); qfbnupow(q, 8839368315,L) q=Qfb(22000957029,25035917443,7122385192); qfbred(q) qfbredsl2(q) q=Qfb(1099511627776,1879224363605,802966544317); [qr,U]=qfbredsl2(q) qfeval(q,U) qfeval(q,U[,1]) qfeval(q,U[,2]) qfeval(q,U[,1],U[,2]) D=poldisc(q); qfbredsl2(q,[D,sqrtint(D)]) qfbredsl2(q,[D]); p=2^64+13; qfbprimeform(-4,p) qfbprimeform(5,p) \\ Errors, keep at end of file qfbredsl2(q,[D,1.]); f=Qfb(12,5,3);g=Qfb(5,5,2); f*g f/g f=Qfb(8,14,1);g=Qfb(4,12,6); f*g \\ should fail f/g pari-2.11.2/src/test/in/polclass0000644000175000017500000003224713326135265015113 0ustar billbilldefault(parisize,"20M"); hash_base = 2^64; init_h = 5381; split_Z(n) = { my (bits = 8, base = 2^bits, sgn = sign(n) % base, res = []); n = abs(n); while (n != 0, res = concat(res, bitand(n, base - 1)); n = shift(n, -bits)); res = concat(res, sgn); } glue(h, a) = bitand((((h << 5) + h) + a), hash_base - 1); hash_Z(n) = { my (v = split_Z(n), h = init_h); for (i = 1, #v, h = glue(h, v[i])); h; } hash_ZX(pol) = { my (v = Vec(pol), h = init_h); for (i = 1, #v, h = glue(h, hash_Z(v[i]))); h; } check_disc(D, hash, seed = 0) = { if (seed != 0, setrand(seed)); my (h = hash_ZX(polclass(D[1], D[2]))); if (h != hash, error("Wrong class polynomial for D = ", D[1], ", inv = ", D[2]), "hash = ", h); } { D = [[[-3, 0], 199415601], [[-4, 0], 392824566], [[-7, 0], 392666638], [[-8, 0], 392685999], [[-11, 0], 392619250], [[-20, 0], 427908603366], [[-23, 0], 466294765623259], [[-39, 0], 16505852200663133551], [[-47, 0], 6402944422652024363], [[-87, 0], 4174888675786545598], [[-71, 0], 9700283236680509421], [[-95, 0], 13008454496997756490], [[-56, 0], 11998671908550620494], [[-264, 0], 12912619012374504058], [[-152, 0], 10731008721722142465], [[-3792, 0], 7620467061686776546], [[-7139, 0], 12274439570299924406], [[-163, 0], 249740438023929931], [[-24, 0], 7166885172778], [[-40, 0], 236296854599224], [[-131, 0], 8331420221009258450], [[-451, 0], 14359598510137794606], [[-356, 0], 4527984144770046237], [[-120, 0], 6891115741722954474], [[-311, 0], 15021837413190908510], [[-335, 0], 17672415898312866530], [[-519, 0], 13506744947615842737], [[-84, 0], 4664273993601588884], [[-271, 0], 4652420391100252414], [[-167, 0], 2826053336532203363], [[-231, 0], 6425030865187792225], [[-280, 0], 6063510379317462346], [[-251, 0], 5232582682029074054], [[-1620, 0], 1232737106430825415], [[-391, 5], 14572212426390106882], [[-20111, 1], 5411404000905873008], [[-392, 5], 1938827148297849283], [[-343, 1], 257546238364177159], [[-2783, 1], 10996804753710941904], [[-391, 1], 12637340198398619526], [[-5599, 1], 15562216764308300369], [[-224, 0], 10018273001722667737], [[-288, 0], 15500427279901381447], [[-644, 0], 16119498756774694982], [[-7139, 0], 12274439570299924406], [[-215, 9], 7528041078664363719], [[-371, 9], 8506587209427855528], [[-539, 9], 8748779700064132114], [[-671, 9], 5929593196577825871], [[-280, 10], 6774102711], [[-344, 10], 3407806631764244633], [[-440, 10], 8033768874193878], [[-920, 10], 8900106068891464863], [[-327, 14], 820264988495455618], [[-847, 14], 8900106376097441137], [[-2415, 14], 4702919368381193176], [[-3471, 14], 4207077986598738230], [[-3519, 14], 7023161748919318882], [[-6655, 14], 11728172978868873828], [[-71, 15], 265107590925814617], [[-7391, 21], 18207206522799977933], [[-260, 24], 7377189545749], [[-312, 26], 6774103800], [[-168, 27], 6774105724], [[-6776, 28], 969506930726366988], [[-164, 35], 8506586868542907145], [[-280, 35], 6774107067], [[-527, 6], 16357965504658585322], [[-47, 6], 243447500721580], [[-42955, 35], 14052068170087575320], [[-5032, 27], 16716694557985895220 /*twist is 3867221821476957240*/], [[-49348, 27], 10861324145157519298], [[-204456,27], 15931382689715710614], [[-31460, 15], 17615562111387810148], [[-207480, 26], 7872480165757364895], [[-943024, 35], 17468381263281201818], \\ N.B. These tests don't come from an independent source [[-487, 4], 265345096494820938], [[-487, 8], 772539374239967193], [[-4, 5], 205098588] ]; for (i = 1, #D, check_disc(D[i][1], D[i][2])); DR = [[[-75, 0], 7797221584007659, 376671349665989785645468855509664073846994182881400101766546260394720617934366189060409433769160357181533432220573885805924825693540852008021952564459774590810585211475243394327684717245750110745945026072328072760225571953639433771639283459668005522842154890829456908826675941553773883099694408386765914172430146193260890042281309331937613624260297092915479077192844416843235737033853226359061755041806842898913531132580673421160537655521664429456369047671439914653309055536929498242296184145972586723145667150625185761830949962500298373529056584928040536064567524870263474685887743703040527814911203719509822876332870699144742892184561609398829910546156826731793518047498225315541275444481177788292169213637463551669277949522309499858775613218022974443961718597909705550334907908272096681310881421925063809112518357896869373327907899703426268496281560228765042197657321214742009561132906624005191491690624145861907151224119699824761808776256630533762728719441507893787757775848664794475988539811278575134333922682568740464050564864294502794430114540622076105981748851862287121587354249984704456793486070616857344028549087804854311807866277937114409612028264996212844411377427435191858159128965207532045931755537411540995454270687742541089492939476560082], [[-243, 0], 10890205224450786941, 819816539003337703951551030334491985811219590735808650180084142425889087428278968474816967078788694496520947544632247845148293960128431184216429913375564738983435120171372870463833059539919475240115755341447859856740148463438091631147817394080277037577189318264494706821721345983257007207604976565659002445459533752756403439594595147954877184727959282333598933690523890222486574862338277271651603375551722191624435592552060776002053134461739050123189055598823370045610053376263074127907593363552123382309729600820747663525085476951111221315643502593164457035295391801162246544107314533457417879806021098968509300182682540829561660369718219958918702187270446232698794813755480218436460242299594360809397850298336439084244705407778140537600292162873108406078811122401339560541945962750458360813545456362536413450759306402982253681310730782288761995853476768379157689767510249258235383040592111399964287410641000424797854996084393758288398059903384898037630395150017169041181270749377250772914279451145788567644479020046227191205609636239269452021245993971524029995510112434006315050031017396470300928176256241735855429441793194487014544763039598262470846572824386988540861783118073704736780177053813565445211750595008551163984105886194036038475757862082957], [[-588, 0], 879637271447453785, 722172781875446948725027515502840397805803222574263498938157594834753683539692286353539379550260903961870953681724730652335944539054343214809842109182109376376073404934944783430561780090926711128352240351787729618963067414744940653491552049787247397068335298858059915825702852961307136083870626600760767835946633951456834700248463253765418088580513814400067434333278000748727896494114214077094766308557268821917667449381466097345351641374194851269731747888023854019055881132865422068901694215525217069307365686664460579110497068925420022191531596796819270908424786079485895699300312731851621077417224747357440195326283221688405149148310871267542131565275881843830667704094780810055193197890989350423968947844027604016370949415740373443463212927661990707144843034492549347563234263847345087343863729913728036463982329922404548652813756727386840999876115923084606166024940965586010450200229416349092936572815279513133323207117397659789511994921332289638592093388560749212300029278651884171306493436892928038820455609679624565527968832712465530213919299178940798157452403212185383817925419187972425719729474468729656592316632439083960654603463616738116233198556419632548161066690834007443366276926895963450902134482716015380443358800099100412263111150979648], [[-1936, 0], 12042224483327737942, 1216866102333088130226524487913144208763734959917103691345969409207516868291718354363183168079965162895868164110454068295852403913687063897316076456732180244314693491111859072668845951826176461315221230058882016799221709155152952471964012736330885451089911136340521851921137288731711645985018653207987024594821449521955479976072917497655704811136469355917733730202537028759098395693891168127853723688728461687547524692980924681009739778062916688599274600924902816402188733597929385212483531422542423979111917373373585978124654150004913998429781081552019917407337230736817542160592949209643774691682024891032738521704689750777805611535687724288457092597016530770301762651133083255869909365609188976361538992126091328095544442922892343390321793772426187309802431464642021666763994457491312667884863871652314337261276496152417457940894836459814316686634775678387158467697914839871436783832178376515625541434789638029419363540511603683658124001143169292488167504419402598460417472547700995407928658213724085415458907242448196429214332894114471850475375711280198098487532816256589287927692486819421805100968297601956068629138524802993613615898230916542578235706687386704879350698179214328913835629864793298388274831137006096634798081307397384701672353002489976], [[-9464, 27], 5838598543968928741, 971139859541539616455075472900871966684445886977524219712621182627452641738170743950581780568829461151266154948079688625260075517281608241987838943732170482046768221929691266245633815142295331012266345361025063298703781829470762291189612365408932129643179104583139454418787386761923101185430770632737852524773963710654122518627917169712709368494827992636945238166518387075005445361264151396088968297095892419521699242270065142895617766430928838221156081322779436189777855217319420550761746571111854615106199425776868531293331645201061020372749829651516464252654687468052692567240414198030892065484818978998288613402083443724834071908030625335571589293504087111354767090827145185368562125001952066613125853368107092130625039931744896896188108648729699937618898649396661193004024196233594623490493378529132432237889029945152360812025808575506573780427329930694881608767838773009911886208424710101255863975363472239340897484025133403045878621608134224132652043064579135366914626745922900237622551009882486999845852791398666923911380143191687845115969658901039215688660195638057312524743660482333830320630523279502463305903338291861973365480740971894854961817219983334320080191073956364702303641228818622994573234724106246909630786570309531361965607975717738], [[-224, 35], 8748776263983593377, 1216866102333088130226524487913144208763734959917103691345969409207516868291718354363183168079965162895868164110454068295852403913687063897316076456732180244314693491111859072668845951826176461315221230058882016799221709155152952471964012736330885451089911136340521851921137288731711645985018653207987024594821449521955479976072917497655704811136469355917733730202537028759098395693891168127853723688728461687547524692980924681009739778062916688599274600924902816402188733597929385212483531422542423979111917373373585978124654150004913998429781081552019917407337230736817542160592949209643774691682024891032738521704689750777805611535687724288457092597016530770301762651133083255869909365609188976361538992126091328095544442922892343390321793772426187309802431464642021666763994457491312667884863871652314337261276496152417457940894836459814316686634775678387158467697914839871436783832178376515625541434789638029419363540511603683658124001143169292488167504419402598460417472547700995407928658213724085415458907242448196429214332894114471850475375711280198098487532816256589287927692486819421805100968297601956068629138524802993613615898230916542578235706687386704879350698179214328913835629864793298388274831137006096634798081307397384701672353002489976], [[-7391, 21], 18207206522799977933, 1216866102333088130226524487913144208763734959917103691345969409207516868291718354363183168079965162895868164110454068295852403913687063897316076456732180244314693491111859072668845951826176461315221230058882016799221709155152952471964012736330885451089911136340521851921137288731711645985018653207987024594821449521955479976072917497655704811136469355917733730202537028759098395693891168127853723688728461687547524692980924681009739778062916688599274600924902816402188733597929385212483531422542423979111917373373585978124654150004913998429781081552019917407337230736817542160592949209643774691682024891032738521704689750777805611535687724288457092597016530770301762651133083255869909365609188976361538992126091328095544442922892343390321793772426187309802431464642021666763994457491312667884863871652314337261276496152417457940894836459814316686634775678387158467697914839871436783832178376515625541434789638029419363540511603683658124001143169292488167504419402598460417472547700995407928658213724085415458907242448196429214332894114471850475375711280198098487532816256589287927692486819421805100968297601956068629138524802993613615898230916542578235706687386704879350698179214328913835629864793298388274831137006096634798081307397384701672353002489976]]; for (i = 1, #DR, check_disc(DR[i][1], DR[i][2], DR[i][3])); my (got_err = 0); iferr(polclass(-5), err, got_err = 1, errname(err) == "e_DOMAIN"); if ( ! got_err, error("No error when given non discriminant")); my (got_err = 0); iferr(polclass(-3,7), err, got_err = 1, errname(err) == "e_DOMAIN"); if ( ! got_err, error("No error when given bad invariant")); if (variable(polclass(-7, , 'z)) != 'z, error("Didn't use user-provided variable")); } pari-2.11.2/src/test/in/env0000644000175000017500000000016013036414402014037 0ustar billbillStrexpand("~root") #Strexpand("~") > 1 Strexpand("$AAA, $BBB, $AAA") getenv("AAA") getenv("__DOES_NOT_EXIST__") pari-2.11.2/src/test/in/gammamellininv0000644000175000017500000000321013201017466016251 0ustar billbilldefault(realprecision,38); f(t)=4*besselk(0,2*Pi*t); G = gammamellininvinit([0,0]); g(t)=gammamellininv(G,t); { for(a=1,30, for(b=-5,5, my(z = a/12+I*b/6, eps = abs(f(z)-g(z))); if(eps > 10^-30, error(z,":",eps)) ) ) } GR(s)=Pi^-(s/2)*gamma(s/2); gmellininv(Vga)= { my(c,A,B,T); localprec(precision(1.)+19); my(f(s) = prod(i=1,#Vga,GR(s+Vga[i]))); c = 1; A = [-oo,Pi/2]; B = [+oo,Pi/2]; T = intfuncinit(t=A,B, f(c + I*t)); z->my(a=-log(z));intnum(t=A,B, exp(a*I*t), T)*exp(a*c) / (2*Pi); } chk(Vga,f,t) = abs(f(t)-gammamellininv(Vga,t)); L=[[0],[1],[1/2],[3/2],[0,0],[0,1/2],[0,1],[0,2],[0,3],[0,0,0],[0,0,1/2],[0,0,1],[0,1,1],[0,1,2],[0,1,3/2],[0,0,0,0,0]]; M=apply(gmellininv,L); S=[1/2,3/2,2,3,4]; S2=concat(S,apply(x->I+x,S)); { for(i=1,#L, my(G = gammamellininvinit(L[i])); for(j=1,#S, my(eps = chk(G,M[i],S2[j])); if(eps > 10^-29, error([1,i,j],":",eps)) ) ); } chkd(v0,v1,t) = abs(derivnum(s=t,gammamellininv(v0,s)) - gammamellininv(v1,t)); { for(i=1,#L, my(v0); if(1, localprec(86); v0 = gammamellininvinit(L[i])); my(v1= gammamellininvinit(L[i], 1)); for(j=1,#S2, if(j<=#S || denominator(L[i])==1, my(eps = chkd(v0,v1,S2[j])); if(eps > 10^-29, error([2,i,j], ":", eps)) ) ) ); } { my(d = abs(gammamellininv([0,1/2,1,3/2],5)-2^(3/2)*exp(-4*Pi*sqrt(5)))); if (d > 1E-49, error([0,1/2,1,3/2],":",5,":",d)); } gammamellininv([0],121.) G = gammamellininvinit([1], 2); a(z) = 4*Pi*z*exp(-Pi*z^2)*(2*Pi*z^2-3); f(z) = printf("%.3g\n", abs(a(z) - gammamellininv(G,z))); f(I) f(2+I) gammamellininvasymp([0],10) gammamellininvasymp([0,1/2],10) pari-2.11.2/src/test/in/quaddisc0000644000175000017500000000017613326135265015064 0ustar billbillf(a,b)= { forfactored(d = a, b, D=quaddisc(d); if (D != quaddisc(d[1]), error(d)); print1(D," ")); } f(-100,0) f(1,100) pari-2.11.2/src/test/in/galoisinit0000644000175000017500000001000213326135265015416 0ustar billbilldo(p)=galoisidentify(galoisinit(p)); do(algdep(I,3)) do(galoissubcyclo(bnrinit(bnfinit(y),[1232,[1]]),[4,0,0,0;0,2,0,1;0,0,2,1;0,0,0,1])) do(x^20-40*x^18+605*x^16-4600*x^14+19500*x^12-48250*x^10+70425*x^8-59500*x^6+27625*x^4-6250*x^2+500) do(x^24-12*x^23+6*x^22+440*x^21-1659*x^20-2352*x^19+24274*x^18-34812*x^17-66078*x^16+249212*x^15-192066*x^14-234528*x^13+515149*x^12-234528*x^11-192066*x^10+249212*x^9-66078*x^8-34812*x^7+24274*x^6-2352*x^5-1659*x^4+440*x^3+6*x^2-12*x+1) do(x^4+272*x^3+40256*x^2+1740800*x+25397248) do(x^4+5264*x^3+8034856*x^2+4205424384*x+504485485632) do(x^4+884*x^3-1972*x^2-884*x+1) do(x^4-42*x^2+144) do(x^12-30*x^8-370*x^6+1665*x^4+23166*x^2+81) do(x^24+3*x^22+22*x^20+31*x^18+138*x^16+85*x^14+297*x^12+149*x^10+249*x^8+238*x^6+98*x^4+16*x^2+1) do(x^54+4288*x^45+4739337*x^36+88723254*x^27+799530047*x^18-256778413*x^9+40353607) do(x^54-3762*x^52+6515505*x^50-6911246832*x^48+5039176931676*x^46-2686817670557400*x^44+1087963170065343636*x^42-342933852097598081616*x^40+85549691240003522127726*x^38-17077123231759966515087980*x^36+2746482620444718167893994910*x^34-357137314570021313085512898384*x^32+37572202145621696209178550611604*x^30-3191423993701636005506286262264824*x^28+217847326568033953619436917061987732*x^26-11861321463900503282422713802261870896*x^24+509777643921195165950639871535287639897*x^22-17055767879920589218196924743211626177266*x^20+436388466866294213576027352329957260889977*x^18-8349444825290714596926947944336750514846016*x^16+116184424651196907257566920202449108391711560*x^14-1136293058944245287715303626629567362322332192*x^12+7487695030927212135931358829137467901174408592*x^10-31501276144455609227993784616018089442301260032*x^8+78778033600362485611603755865500353002845187584*x^6-106406869975806738331854667483688298979911757824*x^4+68731119007852853614250618123508690506961555456*x^2-15696850241826982459503429282145309404169764864) do(x^64-3645070*x^56+3769245010705*x^48+120173739648338450*x^40+2124098086173949323364*x^32+16674620185061962554229010*x^24+87774696936415565369888312017*x^16+56323712629998864272734706*x^8+78032457926322172553281) do(x^8-4*x^7-126*x^6+392*x^5+4853*x^4-10364*x^3-58244*x^2+63492*x+197761) do(y^4+1) p=x^14-271*x^13+14191*x^12-320438*x^11+3790080*x^10-25112800*x^9+92495160*x^8-167147800*x^7+50530009*x^6+301971239*x^5-450938136*x^4+211398894*x^3-16216756*x^2-8116135*x+1041461; do(p) do(x^48+688253440*x^36+64889579202*x^24+688253440*x^12+1); \\\\\\\\\\\ nfgaloisconj(x^3-x-1) nfgaloisconj(x^24+2814) nfgaloisconj(x^4+1) nf=nfinit(polcyclo(7)); s = nfgaloisconj(nf)[2]; pr = idealprimedec(nf,11)[1]; nfgaloisapply(nf,s,idealhnf(nf,pr)) nfgaloisapply(nf,s,pr) nfgaloisapply(nf,s,x^2+x) nfgaloisapply(nf,s,1/2) v=[1,1/2,Mod(x,nf.pol),x,vectorv(6),[;],[1,2;x,3]]; for (i=1,#v, print(nfgaloisapply(nf,s,[1,v[i]]))) galoistest(P,f)= { my(G,F,L); G=galoisinit(P); F=galoissubfields(G,f); for (i=1,#F, my(L=F[i]); if (subst(L[1],variable(L[1]),L[2])!=0, error("galoissubfields1")); if (f==2 && factorback(L[3]*Mod(1,L[1]))!=P, error("galoissubfields2"))); } galoistest(x^4 + 431452248691495692750746750*x^3+447244936830156353775324765*x^2+5580140636706480467906000*x - 238676773812533681600,2); galoistest(polcyclo(88)); G=galoisinit(x); galoisexport(G); galoisexport(G,1); G=galoisinit(x^12-30*x^8-370*x^6+1665*x^4+23166*x^2+81); galoispermtopol(G,G.gen) galoisexport(G) galoisexport(G, 1) G=galoisinit(x^12-24*x^10-10*x^9+216*x^8+180*x^7-844*x^6-1080*x^5+1056*x^4+2200*x^3+720*x^2-240*x-80); L=galoissubgroups(G) apply(H->galoisisnormal(G,H),L) apply(H->galoisisabelian(H),L) apply(H->galoisisabelian(H,1),L) apply(H->galoisisabelian(H,2),L) apply(permorder,G.group) apply(permsign,G.group) vector(#G.group, i, galoisfixedfield(G,G.group[i],1)) galoisfixedfield(G,G.group[2]) galoisfixedfield(G,G.group[2],2,y) galoissubcyclo(17,2) galoissubcyclo(1,1) galoissubcyclo(1,1,1) galoissubcyclo(1,1,2) galoissubcyclo(znstar(124),[3,0;0,2]) galoissubcyclo(znstar(124,1),[3,0;0,2]) G=galoisinit(polcyclo(20)) galoissubfields(G) G=galoisinit(x^6+108); galoissubfields(G,2,z) pari-2.11.2/src/test/in/str0000644000175000017500000000031113326135265014066 0ustar billbillv=Vecsmall("hello world!") Strchr(v) Strtex(Mat(1/2)) Strtex((x+y)^3/(x-y)^2) Str(x) Str(1/2) Str("a","b",1) v = Vecsmall([1..255]); Vecsmall(Strchr(v)) == v \\ Errors, keep at end of file Strchr(-1) pari-2.11.2/src/test/in/agm0000644000175000017500000000073513326135265014034 0ustar billbilldefault(realprecision,38); gagm(a,b)= { my(prec=10^(1-precision(a*1.))); while(norm(a-b)>prec^2, aa = (a+b)/2; bb = sqrt(a*b); if (norm(aa-bb)>norm(aa+bb), bb=-bb); a=aa;b=bb); a; } testagm(x)= { my(e = norm(agm(x,1)-gagm(x,1))); if(e > 1.E-75, printf("error %s: %s\n",x,e)); } for(i=-6,6,for(j=-6,6,testagm(1/6+i/3+j*I/3))); agm(1,2+O(5)) localbitprec(192); a = 1.0; s = agm(a, a*I + x + O(x^200)); polcoeff(s, 0) polcoeff(s, 10) polcoeff(s, 100) pari-2.11.2/src/test/in/lll0000644000175000017500000000131013036414402014030 0ustar billbillqflllgram(matid(2)*1.) m=[219902325555200,60779507942430,113687426768697,93478400051083;219902325555200 ,60779507942430,61044718855924,60943417301157;214748364800,155393376570,17984250 9148,115833849065;214748364800,155393376570,134851934330,188630128295]; qflll(m, 1) M=[x, x^3 - 852*x^2 - 833561*x; x^3 + 1053355*x^2, x^5 + 1052503*x^4 - 898292021*x^3 - 878035647155*x^2 + 1]; test()= { for(i=1,#v, for (j=1,#f, print(iferr(f[j](v[i]),E,E)); ) ); } v=[[;],Mat(1),Mat(0),Mat([1,2]), [x, x+1; x^2, x^2+x], M]; f=[qflll,x->qflll(x,1),x->qflll(x,2),x->qflll(x,4),x->qflll(x,5),x->qflll(x,8)]; test(); v=vector(#v,i,v[i]~*v[i]); f=[qflllgram,x->qflllgram(x,1),x->qflllgram(x,4),x->qflllgram(x,5)]; test(); pari-2.11.2/src/test/in/forsubset0000644000175000017500000000115213326135265015276 0ustar billbilltest(N) = /* check cardinalities and compatibility of forksubset/forallsubset */ { my(l1,l2,l3,k); l1 = []; forsubset(N, s, l1 = concat(l1,s)); if (#l1 != 2^N, error(N)); l2 = []; for (k = 0, N, l3 = []; forsubset([N,k], s, l3 = concat(l3,s)); if (#l3 != binomial(N,k), error([N,k])); l2 = concat(l2, l3); ); if (l1 != l2, error("size ", N)); } test(0); test(1); test(2); test(3); test(4); test(5); forsubset(4,s,print(s)); \\ corner cases forsubset([0,0],s,print(s)) forsubset(0,s,print(s)) forsubset([0,1],s,print(s)) forsubset(-1,s,) forsubset([2,-1],s,) \\ errors forsubset('x,s,) pari-2.11.2/src/test/in/sumiter0000644000175000017500000000106013326135265014750 0ustar billbillHEAP=[24, if(sizebyte(0)==16,227,255)]; \p 19 \e intnum(x=0,Pi,sin(x)) intnum(x=0,4,exp(-x^2)) intnum(x=1,[1],1/(1+x^2)) - Pi/4 intnum(x=-0.5,0.5,1/sqrt(1-x^2)) - Pi/3 intnum(x=0,[[1],-I],sin(x)/x) - Pi/2 \p 38 prod(k=1,10,1+1/k!) prod(k=1,10,1+1./k!) Pi^2/6*prodeuler(p=2,10000,1-p^-2) prodinf(n=0,(1+2^-n)/(1+2^(-n+1))) prodinf(n=0,-2^-n/(1+2^(-n+1)),1) solve(x=1,4,sin(x)) sum(k=1,10,2^-k) sum(k=1,10,2.^-k) 4*sumalt(n=0,(-1)^n/(2*n+1)) 4*sumalt(n=0,(-1)^n/(2*n+1),1) sumdiv(8!,x,x) suminf(n=1,2.^-n) 6/Pi^2*sumpos(n=1,n^-2) if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/prec0000644000175000017500000000120313201017466014202 0ustar billbillprecision(0) bitprecision(0) precision(I,3) default(realprecision,38); t=(precision(1.,77)*x+1); precision(t) localprec(57);precision(1.) localbitprec(128);bitprecision(1.) bitprecision(1 + O(x), 10) bitprecision(1 + O(3^5), 10) bitprecision(1, 10) precision(1./t) precision(Qfb(1,0,-2)); serprec(1,x) serprec(x+O(x^3),x) serprec(x+O(x^3),y) serprec((1+O(y^2))*x+y + O(y^3), y) padicprec(0,2) padicprec(0,"") padicprec(1,2) == padicprec(0,2) padicprec(1/2,2)== padicprec(0,2) padicprec(Mod(1,9),3) padicprec(O(2^2),3) padicprec(O(2^2),2) t=1+O(2^3); padicprec(t,2) padicprec((x+2)*t, 2) padicprec((1+2*x+O(x^2))*t, 2) padicprec([2,4]*t, 2) pari-2.11.2/src/test/in/ellratpoints0000644000175000017500000000203413326135265016002 0ustar billbillW= {[ [0, 0, 1, -79, 342], [1, 0, 0, -22, 219], [0, 0, 1, -247, 1476], [1, -1, 0, -415, 3481], [0, 0, 0, -532, 4420], [1, 1, 0, -2582, 48720], [0, 0, 1, -7077, 235516], [1, -1, 0, -2326, 43456], [1, -1, 0, -16249, 799549], [1, -1, 1, -63147, 6081915] ]; } check(E)= { E=ellinit(E); L=ellratpoints(E,1000); if(#L!=#Set(L),error([E,L])); for(i=1,#L,if(!ellisoncurve(E,L[i]),error([E,L[i]]))); #L+1; } for(i=1,#W,print(check(W[i]))) E=ellinit([-25,1]);ellratpoints(E,10,1) E=ellinit([-25,2]);ellratpoints(E,10,1) E=ellinit([0,0,1,-7,6]);ellratpoints(E,[10^5,1]) E=ellinit([0,0,1,-7,6]);ellratpoints(E,[10^5,[5,10]]) checkhyp(P,Q)= { L=hyperellratpoints([P,Q],10000); if(#L!=#Set(L),error([P,Q,L])); for(i=1,#L, my([x,y]=L[i]); if(y^2+y*subst(Q,'x,x)!=subst(P,'x,x),error([P,Q,L[i]]))); #L; } P=82342800 *x^6 - 470135160 *x^5 + 52485681 *x^4 + 2396040466 *x^3 + 567207969 *x^2 - 985905640 *x + 247747600; hyperellratpoints(P,[10,1]) checkhyp(P,0) checkhyp(-x^6+x^3+x+1,2*x^3) E=ellinit([0,0,1,-7,6]);ellratpoints(E,[10^5,[5]]) pari-2.11.2/src/test/in/mat0000644000175000017500000001376113326135265014054 0ustar billbilliferr(Mat([1]) + matrix(0,1),E,E) iferr(1/matrix(2,2,i,j,Mod(0, 2)),E,E) test(n)= { until(matrank(M)==n,M=matrix(n,n,i,j,random(Mod(1,2)))); if(M^-1*M!=matid(n),error("F2m")); } test(200) test(2) matsize(matrix(0, 0) * matrix(0, 2)) default(realprecision,38); h=mathilbert(40); [Q,R] = matqr(h); vecmax(abs(h-Q*R)) < 1e-37 [q,R] = matqr(h,1); vecmax(abs(mathouseholder(q,h)-R)) < 1e-37 matqr([;]) matqr([;],1) mathouseholder(1,1) mathouseholder(q,1) mathouseholder(q, vectorv(40,i,1)) Mat(List()) Mat(List([1])) Mat([[1,2,3],[2,3,4]]~) Mat(Qfb(1,2,5)) matdiagonal(matid(2)) iferr(matdiagonal([1,2;3,4]),E,E) matpascal(4,1/2) A=[1,2,3;4,5,6];B=[4,6;10,12] matinverseimage(A,B) matinverseimage(A*Mod(1,2),B) matinverseimage(A*Mod(1,7),B) matinverseimage(A*Mod(1,2^64+13),B) matinverseimage(A*Mod(1,3037000507),B) B=[4,10]~; matinverseimage(A*Mod(1,2),B) matinverseimage(A*Mod(1,7),B) matinverseimage(A*Mod(1,2^64+13),B) matinverseimage(A*Mod(1,3037000507),B) test(f)= { print(f,":"); print(f(A*Mod(1,2))); print(f(A*Mod(1,7))); print(f(A*Mod(1,3037000507))); print(f(A*Mod(1,2^64+13))); print(f(A*(1+O(101^3)))); } testall()= { test(matdet); test(matrank); test(matadjoint); test(matimage); test(matimagecompl); test(matindexrank); test(matker); test(lindep); test(x->matsolve(x,vectorv(#x,i,i))); test(x->matsolve(x,matrix(#x,#x,i,j,i+j))); test(x->x^(-1)); test(x->x^2); test(x->A*x); } A = [1,2,4;2,12,7;2,9,11]; testall(); A = [;] testall(); A=[0,1,0;1,0,1;2,0,3]; matdet(A*Mod(1,3037000507)) matdet(A*Mod(1,2^64+13)) matsolve(A*Mod(1,2^64+13),[1,2,3]~) matsolve([1,0;0,0]*Mod(1,2),[1,1]~) matsolve([1,0;0,0]*Mod(1,3),[1,1]~) m=[1,0;0,0;0,1]; b=[1,2;0,0;3,4]; matsolve(m,b) matsolve(m/2,b) matsolve(m*Mod(1,2),b) matsolve(m*Mod(1,3),b) matsolve(m*Mod(1,2^64+13),b) matsolve(m*ffgen(2^3)^0,b) matker([1.,I;I,-1.]) matkerint(Mat([1,1])) trace(matid(3)) trace([;]) iferr(trace(Mat([1,2])),E,E) matrixqz([1/3,1/4;1/2,1/3]) matrixqz(matrix(2,2),-1) m=[1,-4,6,1;-13,14,-8,-3;0,0,0,0;0,0,0,0;7,-9,3,2;-7,9,7,4;0,0,0,0;0,0,0,0;10,-2,-2,0;0,0,-4,-4;0,0,0,0;0,0,0,0;-7,9,-7,-4;-4,-3,7,3;0,0,0,0;0,0,0,0;-5,1,9,4;1,-4,-10,-5;0,0,0,0;0,0,0,0;-13,14,-8,-5;-3,-7,7,4;0,0,0,0;0,0,0,0;-18,15,5,3;8,6,-6,-2;0,0,0,0;0,0,0,0;0,0,0,0;4,3,3,1;0,0,0,0;0,0,0,0;11,-6,4,3;-7,9,7,2;0,0,0,0;0,0,0,0;-5,1,7,4;4,3,1,1;0,0,0,0;0,0,0,0;-6,5,-9,-7;-9,-2,10,7;0,0,0,0;0,0,0,0;-1,4,-4,-1;-20,4,6,4;0,0,0,0;0,0,0,0;0,0,-8,-4;9,2,6,3;0,0,0,0;0,0,0,0;0,0,0,0;0,0,0,0;3,7,1,0;6,-5,-7,-5;0,0,0,0;0,0,0,0;-11,6,8,5;0,0,-6,-4;0,0,0,0;0,0,0,0;-12,10,10,6;0,0,-8,-4;0,0,0,0;0,0,0,0;-5,1,3,2;-6,5,-7,-3;0,0,0,0;0,0,0,0;10,-2,-6,-4;-4,-3,3,1;0,0,0,0;0,0,0,0;0,0,0,0;0,0,0,0;0,0,0,0;0,0,0,0;-2,8,0,-2;2,-8,-4,-2;0,0,0,0;0,0,0,0]; a=matrixqz(m,-2);matdet(a~*a) matrixqz([2,0;0,2;1,0;0,1],-2) A=[1,2,3;4,5,6;7,8,9]; test(lindep) test(matsupplement) A=matrix(5,1); test(matsupplement) default(parisize,10^6); \\ need to exercise gerepile in matker+matimage p=2^64+13; A=matrix(70,70,i,j, i+j); Ap=Mod(A,p); #matker(Ap) #matimage(Ap) #matker(A) matker([3,0,2,2;1,3,3,3]) vecsum([]) vecsum([2]) vecsum(primes(4)) vecsum(1) vecprod([]) vecprod([1,2,3]) 1~ content([]) content([;]) content(matrix(0,2)) vectorsmall(3) v=vectorsmall(3,i,3*i^2) content(v) content(vectorsmall(0)) v=vectorsmall(5,i,(3-i)*i) content(v) vectorsmall(3,i,i^100) m=[1,0;0,0;0,1]; b=[1,2;0,0;3,4]; liftint(Mod(m,2)^(-1)) liftint(Mod(m,3)^(-1)) liftint(Mod(m,2^64+13)^(-1)) liftint(matsolve(Mod(m,2),b)) liftint(matsolve(Mod(m,3),b)) liftint(matsolve(Mod(m,2^64+13),b)) (m*ffgen(2^2)^0)^(-1) (m*ffgen(3^2)^0)^(-1) (m*ffgen((2^64+13)^2)^0)^(-1) m=[1,2,3;4,5,6]; m[1,]=[1,2] m[1,]=[1,2,3,4] m[1,]=[1,2,3]~ m[2,]=[1,2,3] m m[1,]*=2 m test(t) = { N = [1, 2; -1, -2]*t^0; print(matinverseimage(N, N^0)); } test(Mod(1, 3)); test(Mod(1, nextprime(2^64))); test(ffgen(2^17)); test(ffgen(2017^3)); test(ffgen(nextprime(2^64)^3)); p = nextprime(2^63); q = nextprime(p + 1); { forvec(v = vector(8, i, [0, 2]), matker([p^v[1]*q^v[2], p^v[3]*q^v[4]; p^v[5]*q^v[6], p^v[7]*q^v[8]], 1)); } test(x,u=1) = { n = 22; r = 12; M = matrix(n, n, i, j, random(x)*u); P = matrix(n, r, i, j, if(2*i >= 3*j + 8, random(x)*u, 0)); N = P*matrix(r, n, i, j, random(x)*u); S = matsupplement(P); Q = N[,1..r]; R = mattranspose(P); X = matsolve(M, N); K = matker(N); J = matimage(N); if (M*X != N, error("M*X == N")); if (N*K != 0,error("N*K == 0")); if (N*lindep(N) != 0, error("lindep(N)")); if (R*lindep(R) != 0, error("lindep(R)")); if (matimage(J) != J, error("matimage(J)")); if (matdet(S) == 0, error("matsupplement(S)")); if (matrank(J) != r, error("matrank(J)")); if (matrank(K) != n - r, error("matrank(K)")); if (matrank(N) != r, error("matrank(N)")); if (J^-1 * J != matid(r), error("J^-1 * J")); if (matdet(M^-1) != matdet(M)^-1, error("matdet")); if (P*matinverseimage(P, Q) != Q, error("matinverseimage")); if(#lindep(J), error("lindep(J)")); if(#matker(K), error("matker(K)")); if(#matker(M), error("matker(M)")); if(#matinverseimage(N, M),error("matinverseimage(N, M)")); if(#matinverseimage(P, M),error("matinverseimage(P, M)")); iferr(N^-1, e,, errname(e) == "e_INV"); iferr(matsolve(N, M), e,, errname(e) == "e_INV"); } p=nextprime(2^65); test(Mod(1, 8161)); test(Mod(1, p)); default(parisize,8*10^6); test(ffgen([2017,3])); test(ffgen([p,2])); test(x^3*Mod(1,17),Mod(1,ffinit(17,4))); test(x^2*Mod(1,p),Mod(1,ffinit(p,3))); test(x,u=1) = { my(R = matrix(5, 5, i, j, random(x)*u)); if(R^2+R!=R*(R+1),error([x,u])); } test(10*x^3,Mod(1,x^4+7*x^3+12*x+5)); test(10*x^3,Mod(1,(x^4+7*x^3+12*x+5)/7)); test(10*x^3,Mod(1,5*x^4+7*x^3+12*x+5)); test(10*x^3,Mod(1/11,x^4+7*x^3+12*x+5)); test(10*x^3,Mod(1/11,(x^4+7*x^3+12*x+5)/7)); test(10*x^3,Mod(1/11,5*x^4+7*x^3+12*x+5)); [0,0;-1,0;1,1]^(-1) [1,2;3,4;5,6]^-1 [1,2,3;4,5,6]^-1 [1,2,3;4,5,6;7,8,9]^-1 A=[0,0;-10,200;-4,80;0,0;-10,200;-4,80;-50,1000;-80,1600;-28,560]; B=[0,1;0,0;0,0;-3,-2;20,10;25,-10;-8,-6;30,20;25,-15]; matintersect(A,B) \\ Errors, keep at end of file 1/Mat([0,0]~) pari-2.11.2/src/test/in/polygonal0000644000175000017500000000024212314242552015257 0ustar billbillP(n,s)=((s-2)*n^2-(s-4)*n)>>1; test(s)=for(n=0,10, if (!ispolygonal(P(n,s),s,&N) || N != n, error([n,s]))); for (s=4,10, test(s)) for (s=2^64, 2^64+10, test(s)) pari-2.11.2/src/test/in/polylog0000644000175000017500000000046713326135265014757 0ustar billbilldefault(realprecision,38); polylog(3,0.9) polylog(2,3.9) polylog(3,3.9) polylog(2,Mod(x,x^2+1)) polylog(2,[0.5,0.6]) polylog(2,x+O(x^5)) polylog(2,1/2+x+O(x^5)) dilog(-4) polylog(2,1.1+I,1) polylog(1,2,3) localbitprec(320);bitprecision(dilog(2.0)) \\errors polylog(3,2,5) polylog(2,Mod(1,2),0) polylog(3,"",0) pari-2.11.2/src/test/in/galois0000644000175000017500000002061713036414402014536 0ustar billbill\\package:galdata test(a)= { my(x, y, z); for (i=1, 10000, z = eval(Str("T", a, "_", i)); if (poldegree(z) == 1, break); \\ undefined x = polgalois(z); y = polgalois(poltschirnhaus( poltschirnhaus(z) )); print(x, x==y) ); } { T1_1 = x; T2_1 = x^2+x+1; T3_1 = x^3+x^2-2*x-1; T3_2 = x^3+2; T4_1 = x^4+x^3+x^2+x+1; T4_2 = x^4+1; T4_3 = x^4-2; T4_4 = x^4+8*x+12; T4_5 = x^4+x+1; T5_1 = x^5+x^4-4*x^3-3*x^2+3*x+1; T5_2 = x^5-5*x+12; T5_3 = x^5+2; T5_4 = x^5+20*x+16; T5_5 = x^5-x+1; T6_1 = x^6+x^5+x^4+x^3+x^2+x+1; T6_2 = x^6+108; T6_3 = x^6+2; T6_4 = x^6-3*x^2-1; T6_5 = x^6+3*x^3+3; T6_6 = x^6-3*x^2+1; T6_7 = x^6-4*x^2-1; T6_8 = x^6-3*x^5+6*x^4-7*x^3+2*x^2+x-4; T6_9 = x^6+2*x^3-2; T6_10= x^6+6*x^4+2*x^3+9*x^2+6*x-4; T6_11= x^6+2*x^2+2; T6_12= x^6-2*x^5-5*x^2-2*x-1; T6_13= x^6+2*x^4+2*x^3+x^2+2*x+2; T6_14= x^6-x^5-10*x^4+30*x^3-31*x^2+7*x+9; T6_15= x^6+24*x-20; T6_16= x^6+x+1; T7_1 = x^7+x^6-12*x^5-7*x^4+28*x^3+14*x^2-9*x+1; T7_2 = x^7+7*x^3+7*x^2+7*x-1; T7_3 = x^7-14*x^5+56*x^3-56*x+22; T7_4 = x^7+2; T7_5 = x^7-7*x^3+14*x^2-7*x+1; T7_6 = x^7+7*x^4+14*x+3; T7_7 = x^7+x+1; T8_50 = x^8-x-1; T8_49 = x^8-2*x^6-2*x^5-x^4-x^3+4*x^2+4*x-2; T8_48 = x^8-2*x^6-2*x^5+2*x^4+4*x^2+2; T8_47 = x^8+x^2+2*x+1; T8_46 = x^8-4*x^5-9*x^4-16*x^2-12*x+9; T8_45 = x^8-2*x^6-2*x^5+4*x^3+2*x^2+2; T8_44 = x^8+x^2-1; T8_43 = x^8-x^7+7*x^2-x+1; T8_42 = x^8-2*x^6+2*x^5+3*x^4-2*x^3+x^2+4*x+2; T8_41 = x^8-4*x^5+3*x^4+16*x^2+12*x+9; T8_40 = x^8+8*x^6+18*x^4-1; T8_39 = x^8+x^2+1; T8_38 = x^8-4*x^6+28; T8_37 = x^8-4*x^7+28*x^5-21*x^4-70*x^3+189*x^2-173*x+69; T8_36 = x^8-4*x^7+112*x^4+224*x^3-112*x^2-736*x+536; T8_35 = x^8+4*x^2-1; T8_34 = x^8+4*x^7+5*x^6+x^5+x^4-2*x^3-x^2+3*x+2; T8_33 = x^8-8*x^6+18*x^4-16*x^3-40*x^2+8*x+23; T8_32 = x^8-8*x^6+18*x^4+4; T8_31 = x^8+2*x^6+x^4+14; T8_30 = x^8+4*x^6+4*x^4-2; T8_29 = x^8+x^4+2*x^2+1; T8_28 = x^8+4*x^6+2; T8_27 = x^8+5*x^6+3*x^4-6*x^2-4; T8_26 = x^8+2*x^4-2; T8_25 = x^8-x^7+29*x^2+29; T8_24 = x^8-4*x^2+4; T8_23 = x^8-8*x^6+12*x^4-12; T8_22 = x^8+x^4+4; T8_21 = x^8+2*x^4+4*x^2+2; T8_20 = x^8+x^6-6*x^4-x^2+1; T8_19 = x^8+4*x^4+4*x^2+1; T8_18 = x^8+2*x^6+2*x^2+1; T8_17 = x^8+2*x^4+2; T8_16 = x^8+4*x^4+2; T8_15 = x^8+3; T8_14 = x^8+2*x^7+4*x^6-2*x^5+2*x^4-2*x^3+4*x^2+2*x+1; T8_13 = x^8+4*x^6+8*x^4+4; T8_12 = x^8-22*x^6+135*x^4-150*x^2+1; T8_11 = x^8+9; T8_10 = x^8+2*x^6+4*x^4+3*x^2+1; T8_9 = x^8+4*x^4+1; T8_8 = x^8-2; T8_7 = x^8+x^7-28*x^6-7*x^5+70*x^4+7*x^3-28*x^2-x+1; T8_6 = x^8+2; T8_5 = x^8-12*x^6+36*x^4-36*x^2+9; T8_4 = x^8+3*x^4+1; T8_3 = x^8-x^4+1; T8_2 = x^8+1; T8_1 = x^8+x^7-7*x^6-6*x^5+15*x^4+10*x^3-10*x^2-4*x+1; T9_34 = x^9-x-1; T9_33 = x^9+27*x-24; T9_32 = x^9+x^7+2*x^5+4*x^3-x^2+x+1; T9_31 = x^9-2*x^7-2*x^6-x^5-x^4+4*x^3+5*x^2+4*x+1; T9_30 = x^9+2*x^5+4*x^4+4*x^3+4*x^2+x+1; T9_29 = x^9-6*x^6-18*x^5+36*x^4-36*x^3+108*x^2-144*x+48; T9_28 = x^9-2*x^7-2*x^6-x^5-2*x^4+3*x^2+3*x+1; T9_27 = x^9-36*x^6-54*x^5+432*x^3+324*x^2-243*x-1152; T9_26 = x^9-x^7+5*x^6+x^5-2*x^4+4*x^3+3*x^2-x-1; T9_25 = x^9-9*x^6-9*x^4+24*x^3+9*x^2-9*x+1; T9_24 = x^9-2*x^6-2*x^3-2; T9_23 = x^9+9*x^7-60*x^6+72*x^5+354*x^3-495*x^2+2124*x-845; T9_22 = x^9-12*x^6-27*x^5-18*x^4+9*x^3+36*x-8; T9_21 = x^9+3*x^6+3*x^3-2; T9_20 = x^9-2*x^7-2*x^6-2*x^5+x^4+4*x^3+3*x^2+3*x+1; T9_19 = x^9-3*x^8-24*x^5-24*x^4-48*x+16; T9_18 = x^9-2*x^6-2*x^3-1; T9_17 = x^9-17*x^7-6*x^6+87*x^5+47*x^4-143*x^3-69*x^2+72*x+27; T9_16 = x^9-2*x^7+3*x^6+x^5-x^4-2*x^3+x+1; T9_15 = x^9-9*x^7-21*x^6+72*x^5+99*x^4-99*x^3-585*x^2+549*x+166; T9_14 = x^9-30*x^6+45*x^5+126*x^4-240*x^3-90*x^2+405*x+80; T9_13 = x^9-2*x^6-x^3+1; T9_12 = x^9+x^8+x^7+4*x^6-2*x^5-x^4+3*x^3+x^2-1; T9_11 = x^9-x^6+5*x^3+1; T9_10 = x^9-2; T9_9 = x^9-3*x^8+3*x^7-15*x^6+33*x^5-3*x^4+24*x^3+6*x^2-4; T9_8 = x^9-6*x^6+8*x^3-8; T9_7 = x^9-232*x^7-9*x^6+7485*x^5+8631*x^4-3097*x^3-738*x^2+325*x-27; T9_6 = x^9+x^8-32*x^7-84*x^6-14*x^5+112*x^4+84*x^3+4*x^2-8*x-1; T9_5 = x^9+3*x^6+3*x^3-1; T9_4 = x^9+4*x^6+3*x^3-1; T9_3 = x^9+9*x^7-6*x^6+27*x^5-36*x^4+27*x^3-54*x^2-32; T9_2 = x^9-15*x^7+4*x^6+54*x^5-12*x^4-38*x^3+9*x^2+6*x-1; T9_1 = x^9-9*x^7+27*x^5-30*x^3+9*x-1; T10_45 = x^10-x-1; T10_44 = x^10-2*x^8-2*x^7-2*x^3+2*x^2+x-1; T10_43 = x^10-2*x^8-2*x^7-2*x^6-2*x^5-x^4-2*x^3+3*x^2-2*x+1; T10_42 = x^10-32*x^5-200*x^2+256; T10_41 = x^10+2*x^9+4*x^8-x^6+x^4-2*x-1; T10_40 = x^10+x^9-x^8-x^7-2*x^6+2*x^3+3*x^2+x+1; T10_39 = x^10-2*x^8-2*x^7-2*x^6-2*x^5+2*x^4-2*x^3+2*x^2-1; T10_38 = x^10-2*x^8-x^6-2*x^4+2*x^2-2; T10_37 = x^10-2*x^8-2*x^7-x^6-x^5-x^4-2*x^3-2*x^2+1; T10_36 = x^10-2*x^8-x^6+3*x^4-x^2+2; T10_35 = x^10+300*x^6-18*x^5+10000*x^2-200*x+81; T10_34 = x^10-x^8-2*x^6-x^4+x^2-1; T10_33 = x^10-2*x^9+12*x^8-20*x^7+66*x^6-20*x^5+228*x^4+84*x^3+276*x^2+120*x+100; T10_32 = x^10-9*x^8+27*x^6+2*x^5-27*x^4-9*x^3+8*x+1; T10_31 = x^10-1800*x^8-24000*x^7+1422000*x^6+30960000*x^5-462480000*x^4-14500800000*x^3+12996000000*x^2+2414368000000*x-12197187420489; T10_30 = x^10+90*x^6-648*x^5+1080*x^4-2160*x^3+3645*x^2+5400*x+12960; T10_29 = x^10+2*x^8-2*x^6-x^2+2; T10_28 = x^10-10*x^7+10*x^6+36*x^5+50*x^4-10*x^3-1; T10_27 = x^10+3*x^6-2*x^5+x^2+2*x+1; T10_26 = x^10-15*x^8-75*x^6-6*x^5-165*x^4-30*x^3-180*x^2-50*x-90; T10_25 = x^10-2*x^8-2*x^6-x^2-2; T10_24 = x^10+x^8-x^4+3*x^2-1; T10_23 = x^10-2*x^8-x^7+3*x^6+2*x^5-2*x^4-2*x^3+2*x^2+3*x+1; T10_22 = x^10-2*x^8-2*x^7-x^6+x^4-2*x^3+2*x^2-1; T10_21 = x^10+x^6-2*x^5-x^4+3*x^2-2*x+1; T10_20 = x^10-3*x^9+x^8+36*x^7-39*x^6-105*x^5+99*x^4+180*x^3-45*x^2-135*x-45; T10_19 = x^10-10*x^8+35*x^6-2*x^5-50*x^4+10*x^3+25*x^2-10*x+2; T10_18 = x^10+60*x^6-240*x^5+850*x^2-5440*x-1088; T10_17 = x^10-2*x^5-2; T10_16 = x^10+7*x^8+17*x^6-31*x^4-40*x^2+127; T10_15 = x^10-x^8-2*x^6+x^4+3*x^2-1; T10_14 = x^10+x^8-4*x^6-3*x^4+3*x^2+1; T10_13 = x^10-2*x^8-x^7-2*x^6+x^5+3*x^4-2*x^3-x^2+x+1; T10_12 = x^10+2*x^9+3*x^8-x^6-2*x^5-x^4+3*x^2+2*x+1; T10_11 = x^10+10*x^6+25*x^2-8; T10_10 = x^10-2*x^5-4; T10_9 = x^10-50*x^8-100*x^7+865*x^6+4036*x^5+4100*x^4+16400*x^2+13120*x+2624; T10_8 = x^10-4*x^8+2*x^6+5*x^4-2*x^2-1; T10_7 = x^10-2*x^5-15*x^4-10*x^3-15*x^2-5; T10_6 = x^10+5*x^8-33*x^7-67*x^6+132*x^5-375*x^4+1551*x^3+5505*x^2-8987*x+4291; T10_5 = x^10-2; T10_4 = x^10-x^5-1; T10_3 = x^10-x^8-x^6+3*x^4+2*x^2+1; T10_2 = x^10-35*x^6+130*x^4+160; T10_1 = x^10-x^9+x^8-x^7+x^6-x^5+x^4-x^3+x^2-x+1; T11_8 = x^11-x-1; T11_7 = x^11+x^10+2*x^9+2*x^8+x^6-x^5+2*x^4+2*x^3+x^2-1; T11_6 = x^11-x^10-121*x^9+65*x^8+5345*x^7-481*x^6-96739*x^5-23689*x^4+413690*x^3-493810*x^2+26910*x-856170; T11_5 = x^11-898*x^9-3080*x^8+293480*x^7+4185984*x^6-145552352*x^5+1474999680*x^4-16923164544*x^3+177410331648*x^2-709199732736*x+63589515264; T11_4 = x^11-2; T11_3 = x^11-33*x^9+396*x^7-2079*x^5+4455*x^3-2673*x-243; T11_2 = x^11-x^10+5*x^8+8*x^5+6*x^4-x^3+x^2+3*x+1; T11_1 = x^11+x^10-10*x^9-9*x^8+36*x^7+28*x^6-56*x^5-35*x^4+35*x^3+15*x^2-6*x-1; } default(realprecision, 38); default(new_galois_format, 1) for (i = 1, 11, test(i)) default(new_galois_format, 0) for (i = 1, 7, test(i)) \\ miscellaneous tests setrand(3);polgalois(x^8-24447832222819253258096747170722821932737551721814653244372785289945042560370884249414339208601850*x^4+24447832222819253258096747170722821932737551721825709426404304862673539625219608619381278993545125*x^2+24447832222819253258096747170722821932737551721825709426404304862673539625219608619381278993545125) polgalois(polzagier(11,0)/polzagier(1,0)) polgalois(x^8-1864259299553450972214799899167226732549697977945716*x^6+331143259018657601105207922631212331088735421305543663274125986698777318014979969*x^4-2225286541902342283500014249183311190477390*x^2+5) polgalois(x^8+162644002617632464507038884216211529274267271168000002) polgalois(x^8+2^2^12) setrand(5);polgalois(x^8-3911867303938246274330482940384509030446487325649036998411199166662010711465575565062431210085563041214249877058238647352476889609806751307308111079477582030570450*x^4-3911867303938246274330482940384509030446487325649036998411199166662010711465575569485025077906938222890835591100732814736005780908137290944485033156820540880540405*x^2+3911867303938246274330482940384509030446487325649036998411199166662010711465575569485025077906938222890835591100732814736005780908137290944485033156820540880540405) setrand(15);polgalois(x^8-1642492255488433999638100059165477791152530*x^4-1642492255488433999640965798385546876573045*x^2+1642492255488433999640965798385546876573045) setrand(4);polgalois(x^8-264*x^6+25410*x^4-1054152*x^2+15856203) setrand(15);polgalois(x^8-3512859249280433994187541000*x^6+1542522513156886787688759313741174472421584953335229070*x^4-60930543678769127629182898645000*x^2+300849025) setrand(1); polgalois(x^11+627*x^4-584) pari-2.11.2/src/test/in/rootsreal0000644000175000017500000000327213457566440015311 0ustar billbilldefault(realprecision,38); T=x^3-6*x^2+11*x-6; polrootsreal(T) polrootsreal(T, [-oo,3/2]) polrootsreal(T, [3/2,6]) polrootsreal(T, [-oo,+oo]) polrootsreal(T, [2,3]) polrootsreal(T, [1,2]) polsturm(T, [-oo,3/2]) polsturm(T, [3/2,6]) polsturm(T, [-oo,+oo]) polsturm(T, [2,3]) polsturm(T, [1,2]) polsturm(T, [1,+oo]) polsturm(T, 2,3) polsturm(T, 2.,3) polsturm(T,,2) polrootsreal(x^10 + 23*x^9 + 19*x^8 + 18*x^7 + 39*x^6 + 41*x^5 + 46*x^4 + 24*x^3 - 4*x^2 + 2*x + 42) polrootsreal(polchebyshev(9)) polrootsreal(polchebyshev(10)) polrootsreal(x^0) polrootsreal(1) polrootsreal(0) polrootsreal(Pol(0)) polrootsreal(Mod(1,2)) polroots(T*x+0.) polroots(1) polrootsreal(T,[1,1]) polrootsreal(T,[0,0]) polsturm(T,[1,1]) polsturm(T,[2,1]) U=(x^2-1)*(x-2); polsturm(U) polsturm(U,[-oo,1]) polsturm(U,[-1,+oo]) polrootsreal(x,[1,2]) polrootsreal(x,[-2,-1]) polrootsreal(x,[-1,1]) polrootsreal(x^3-2) polrootsreal(x^3+2) \\#1605 polsturm(33*x^2-4*x-1) polrootsreal(4*x) polsturm(-4*x) polsturm((x^4-2)^2) \\#1807 T=x^3+x^2-x+2; polrootsreal(T) polsturm(T) polsturm(T,[-3,-1]) polsturm(T,[-2,-1]) polsturm(T,[-oo,-2]) polsturm(T,[-2,oo]) T=4*x^3-2*x^2-x-1; polsturm(T,[0,oo]) polsturm(T,[0,1]) polsturm(T,[0,2]) polsturm(T,[1,3]) \\#1808 polrootsreal(3*x^3-4*x^2+3*x-1) \\#1809 polrootsreal(x^3-3*x^2-3*x+2) \\#1810 polrootsreal(x^3-x^2) polrootsreal((x^3-x^2)*(x-2)^3*(x-3)^2) default(realprecision,19); #polroots((x+1)^2 * (x-1)^7 * (x^2-x+1)^5 * 1.0) \\#1884 default(realprecision,38); polsturm(x^2-1,[-1,1]) polrootsreal(x^2-1,[-1,1]) polsturm((x-1)^2*(x+2)*1.) \\#2112 pol=-x^4-2*x^3-x^2/3-x/100+1/2000; polrootsreal(pol,[1/100,oo]) pol=-x^4-2*x^3-x^2/3-x/100+1/1000; polrootsreal(pol,[1/10,oo]) \\ one extra root pari-2.11.2/src/test/in/memory0000644000175000017500000000007713326135265014577 0ustar billbilldefault(parisize, 2^20); vector(100000, k, k); \\ #1881 pari-2.11.2/src/test/in/zetamult0000644000175000017500000000223313326135265015130 0ustar billbilldefault(parisize,"10M"); default(realprecision,38); test(a,b)= if(a==b,oo, ceil(log(abs(a-b))/log(10))); test(zetamult([2,1]), zeta(3)) test(zetamult([4,2]), (zeta(3)^2 - 4*zeta(6)/3)) test(zetamult([4,4]), (zeta(4)^2 - zeta(8))/2) test(zetamult([2,2,2]), zeta(2)^3/6 + zeta(6)/3 - zeta(2)*zeta(4)/2) zetamult(2) zetamult([]) default(realprecision,57); T=zetamultinit(30); for(k=1,10, print(Pi^(4*k) / zetamult(vector(2*k, j, 1+2*(j%2))))); v = [zeta(9),Pi^2*zeta(7),Pi^4*zeta(5),Pi^6*zeta(3)]; LD=[2,2,2,2]; { for(i=1,4, LE=LD; LE[i]=3; z = lindep(concat(zetamult(LE),v)); if (z[1] < 0, z = -z); print(z); ); } zetamultall(5) avec=[3,1,3,1]; evec=[0,0,1,1,0,0,1,1]; a=89; zetamultconvert(avec,0) zetamultconvert(avec,1) zetamultconvert(avec,2) zetamultconvert(evec,0) zetamultconvert(evec,1) zetamultconvert(evec,2) zetamultconvert(a,0) zetamultconvert(a,1) zetamultconvert(a,2) { for (i = 1, 2^10, a = zetamultconvert(i); if (zetamultconvert(a,2) != i, error(i)) ); } \\ Errors, keep at end of file zetamult([1,2]) zetamult("a") zetamultall(0) zetamultall(64) zetamult([0,2,1]) zetamult([0,1,0]) zetamult([0,-1,1]) zetamult([1,-1,1]) zetamult([1,0,1]) pari-2.11.2/src/test/in/modular0000644000175000017500000000151213201017466014717 0ustar billbillv = [2,3,2^32-1,2^64-1,10^20]; f(a,b,p)=(a*Mod(1,p)) * (b*Mod(1,p)); g(a,p)=sqr(a*Mod(1,p)); test(a,b)= { for (i=1,#v,print(i, ": ", f(a,b,v[i]))); for (i=1,#v,print(i, ": ", g(a,v[i]))); } test(polcyclo(10),polcyclo(5)); test([1,2;3,4], [-1,2;-4,2]); Mod(Mod(1,y),x) Mod(Mod(1,x),y) iferr(Mod(1,"a"),E,E) iferr(Mod(0,0),E,E) iferr(Mod(0,Pol(0)),E,E) iferr(Mod(x+O(x^2), x^3), E,E) Mod(x+O(x^2), x^2) Mod(x+O(x^3), x^2) Mod(Mod(x,x^3), x^2) Mod(Mod(1,12), 9) Mod(1/x,x^2+1) Mod([5,6],2) Mod(3*x,2) Mod(x,y) Mod(Pol(0),2) Pol(0)*Mod(1,2) k=100000000000000000000; Mod(3,7)^-k Mod(3,7)^k \g1 a=Mod(1,2);b=Mod(1,3); a+b a-b a*b a/b a+a a-a a*a a/a a=Mod(1,x);b=Mod(1,x+1); a+b a-b a*b a/b a+a a-a a*a a/a \\#1652 p=436^56-35;lift(Mod(271,p)^((p-1)/2)) \\#1717 Mod(0,1)==0 Mod(0,1)==1 Mod(0,1)==-1 Mod(0,x^0)==0 Mod(0,x^0)==1 Mod(0,x^0)==-1 pari-2.11.2/src/test/in/equal0000644000175000017500000000252013326135265014371 0ustar billbill[O(3)===O(3), 1+O(3)===2+O(3), 1+O(3)==O(3^-1), 1+O(3)==2+O(3)] [O(x)===O(y), 2+O(x)===1+O(x)] [1.===1., 1.===-1.] f(x)=1; g(x)=1; h()=1; my(y=1);e(x)=y; [e===f,e===e] [f===g, f===h] [3/2===-3/2, 3/2===3/2] m=Mod(1,2); [Mod(1,3)===m, m===Mod(0,2), m===m] m=Mod(1,x); [m===Mod(Pol(1),x), m===Mod(1,y), m===m] t=ffgen(8); [t===t+1, t===ffgen(4), t===t] q=Qfb(1,2,3); [q===Qfb(1,2,2), q===Qfb(1,3,3), q===Qfb(2,2,3), Qfb(1,0,-2)===Qfb(1,0,-2,1.), q===q] Qfb(1,0,-2)==Qfb(1,0,-2,1.) 1/x===1/y [[1,2,3]===[1,2], [1,2,3]===[1,2,4], [1,2,3]===[1,2,3.], [1,2]===[1,2]] quadgen(5)==quadgen(13) ["ab"==="ac", "ab"==="ab"] L=List([1,2]); [L===List([]), L===List([2,1]), L===List([1]), L===L] [[]==0, []~==0] oo===oo -oo===-oo oo===-oo [I===1+I, I===I] w=quadgen(5); [w===1+w, w===w] w==w quadgen(5)===quadgen(13) f()=1; g()=0; [f==g,f==f] [f===g,f===f] List()==List() List(1)==List() List()==List(1) List(1)==List(1) List(2)==List(1) g=ffgen(2^3); h=ffgen(3^3); q=quadgen(5); v=[g,g^0,-g^0,h,h^0,-h^0,\ q,1+0*q,-1+0*q,\ O(x),x+O(x^2),1+O(x),-1+O(x),1+O(x^2),1+x+O(x^2),0./x+1+O(x^2),0./x+1+x+O(x^2),\ (x+0.)/x,(-x+0.)/x,(2*x+0.)/x,\ [], [1], []~, [1]~, [2]~, [1,1]~, [1,0]~,[-1,0]~,\ [;],Mat(1),Mat(2), matid(2), [1,0;0,2], [1,1;0,1], -matid(2)]; for (i=1,#v, print([v[i]==1,v[i]==-1])) A=Ser(vector(40000,i,i==1)); A==A Mod(Mod(y,y^2+1),x^2-2) == Mod(y,y^2+1) pari-2.11.2/src/test/in/ramanujantau0000644000175000017500000000034413326135265015752 0ustar billbilldefault(parisize,"20M"); tauvec(N) = Vec(q*eta(q + O(q^N))^24); N = 10^3; vector(N, n, ramanujantau(n)) == tauvec(N) ramanujantau(10^6+3) ramanujantau(-1) ramanujantau(factor(-1)) ramanujantau(factor(0)) ramanujantau(factor(6)) pari-2.11.2/src/test/in/log0000644000175000017500000000014313201017466014034 0ustar billbilldefault(realprecision,38); log(1+10^-30) lngamma(1+10^-30) lngamma(10^-30) iferr(log(2+O(33)),E,E) pari-2.11.2/src/test/in/chinese0000644000175000017500000000045413201017466014676 0ustar billbillchinese(Mod(x,x^2+1),Mod(x,x^2+1)) chinese(Mod(x,x^2+1),Mod(x,x^2-1)) chinese(Mod(1,2)*x+Mod(1,2), Mod(2,3)*x^2+Mod(1,3)*x+Mod(1,3)) chinese([Mod(1,2),Mod(1,3)], [Mod(1,4),Mod(1,2)]) chinese(1) chinese([]) chinese(Mod(1+x,x^2),Mod(0,1)) chinese(Mod(1+x,x^2),Mod(1,2)) chinese(Mod(0,1),Mod(1+x,x^2)) pari-2.11.2/src/test/in/ff0000644000175000017500000001025413457566441013671 0ustar billbilldefault(parisize,"10M") jell(x)=if(#x,x.j,[]); { test(p,f) = setrand(1); a = ffgen([p,f], 'a); [ ffgen(a^2+a+3), a^2+3*a+1, a/(1+a), 2*(a+1)/3, 1/5+a, if (6*a, 5/6/(a+1)), if (6*a, 5/6*(a+1)), shiftmul(a+1,10), if (2*a, shiftmul(a+1,-10)), a^-1, -a, sqr(a), sqrt(a^(2^10)), sqrtn((a^2+a+1)^3,3), sqrtn((a^2+a+1)^3,3,&z), z, if (ispower(a,3), a^(2/3)), norm(a^2+1), trace(a), charpoly(a), minpoly(a), conjvec(a), factor(x^6-a*x^3+1), jell(ellinit([a,1])), a/x, (x+a)/(x-a), if(1,setrand(1);b=ffprimroot(a)), fforder(a), b^fflog(a,b), factormod(x^2+x+a), polrootsmod(x^2+x+a) ]; } default(echo,1); test(2, 20) test(7, 7) test(precprime(2^32), 3) test(nextprime(2^32), 3) default(echo,0); ftest(p,n,r)= { my(a=ffgen(ffinit(p,n),'a)^r); if(sqrtn(a,r)^r!=a,error([p,n,r])); } default(echo,1); ftest(2,1005,7); ffgen(ffinit(2^32-5,101),'a)^10000 ffgen(ffinit(2^64-59,101),'a)^10000 for(i=1,10,print(ffnbirred(11,i))); for(i=1,10,print(ffnbirred(11,i,1))); t = ffgen(2^64)^((2^64-1)\5);1/t sqrt(Mod(-1,4296540161)) sqrt(Mod(-1,18446744073944432641)) centerlift(factorcantor(prod(i=-10,10,(x^2-i)),2^64+13)[,1]) conjvec(Mod(x, x^2+Mod(1,3))) default(echo,0); test(q)= { my(t = ffgen(q,'t), m=[t,t^2,1+t^3; 1+t,1+t^2,1+t^3]); print(matker(m)); print(matimage(m)); print(matrank(m)); my(M = [t,2*t^0,3*t^0; t,t^2,1+t^3; 1+t,1+t^2,1+t^3]); print(matdet(M)); print(M^(-1)*M); my(v = [t^0, t^1, t^2]~); print(M*v); print(M*matsolve(M, v) == v); print(M*matinverseimage(M, v) == v); print(matsolve(M, matid(3)*t^0) == M^(-1)); print(matinverseimage(M, matid(3)*t^0) == M^(-1)); my(N = t*[0, 1; 0, 0]); iferr(N^-1, e,, errname(e) == "e_INV"); iferr(matsolve(N, t*[0, 1]~), e,, errname(e) == "e_INV"); print(matinverseimage(N, t*[1, 0]~)); print(matinverseimage(N, t*[0, 1]~)); print(matinverseimage(N, N^0)); print(matindexrank(N)); print(matsupplement(t*[0; 1])); print(lindep(t*[1; 1])); print(lindep(t*[0, 0; 1, 1])); } default(echo,1); test(2^5) test(7^5) test((2^64+13)^5) default(echo,0); test(q, n=10)={ my(t = ffgen(q, 't), M = matrix(n, n, i, j, random(t))); if(subst(charpoly(M), 'x, M) != 0, error("test:",[q,n])); } default(echo,1); test(nextprime(2^7)^5) test(nextprime(2^15)^5) test(nextprime(2^31)^5) test(nextprime(2^63)^5) test(nextprime(2^80)^5) test(nextprime(2^7)^5, 27) test(nextprime(2^15)^5, 27) test(nextprime(2^31)^5, 27) test(nextprime(2^63)^5, 27) test(nextprime(2^80)^2, 27) my(a=ffgen([2,100]));(0*a*x)*x default(echo,0); test(p=3,f=10,d=2,e=2)= { my(Pa,Pb); my(q = p^f); my(a = ffgen([p,f],'a), b = ffgen([p,d*f],'b), c = ffgen([p,e*d*f],'c)); my(m = ffembed(a, b), n = ffembed(b, c), k = ffembed(a, c)); my(rm = ffinvmap(m), rn = ffinvmap(n), rk = ffinvmap(k)); my(nm = ffcompomap(n,m), rmrn =ffcompomap(rm,rn)); my(rnk = ffcompomap(rn,k), rkn = ffcompomap(rk,n)); my(rmm = ffcompomap(rm,m), mrm = ffcompomap(m,rm)); my(fr=fffrobenius(b,f)); my(z = b); for(i=1,d-1,z = b + ffmap(fr,z)); if (ffmap(m,ffmap(rm,z))!=z,error("fffrobenius")); if (minpoly(ffmap(m,a),'a) != a.mod,error("minpoly")); Pa = a^2+a+3; Pb = ffmap(m,Pa); if (ffmap(rm,Pb)!=Pa, error("ffmap")); if (ffmap(rm,b)!=[],error("ffmap")); my(Qa = [Pa,x^2+x*Pa+1], Qb = ffmap(m,Qa), Qc = ffmap(n,Qb)); if (ffmap(rm,Qb)!=Qa,error("ffmap: rm")); if (ffmap(nm,Qa)!=Qc,error("ffmap: n o m")); if (ffmap(rmm,Qa)!=Qa,error("ffmap: rm o m")); if (ffmap(mrm,Qb)!=Qb,error("ffmap: m o m")); if (ffmap(rmrn,Qc)!=Qa,error("ffmap: rm o rn")); if (ffmap(rnk,Qa)!=ffmap(rn,ffmap(k,Qa)),error("ffmap: rn o k")); if (ffmap(rkn,Qb)!=ffmap(rk,ffmap(n,Qb)),error("ffmap: rk o n")); iferr(ffcompomap(m,n),E,print(E)); iferr(ffcompomap(rn,rm),E,print(E)); iferr(ffcompomap(m,rn),E,print(E)); iferr(ffcompomap(rm,n),E,print(E)); R=factor(b.mod*a^0)[1,1]; [d,l]=ffextend(a,R); if(subst(ffmap(l,R),'b,d),error("ffextend")); if(minpoly(ffmap(l,a))!=minpoly(a),error("ffextend")); iferr(ffextend(a,x^2+b*x+1),E,print(E)); } default(echo,1); test(2,1,5,3) test(2,5,5,3) test(3,1,2,3) test(3,10,2,3) test(nextprime(2^100),1,3,2) test(nextprime(2^100),3,3,2) /* error */ ffgen(x^2+x+Mod(1,3)) ffembed(ffgen([3,5],'b),ffgen([3,6],'a)); a=ffgen(3^3,'a); ffinvmap(ffextend(a,x^2+x+a)); pari-2.11.2/src/test/in/disc0000644000175000017500000000531113457566441014216 0ustar billbillpoldisc(Mod(1, 2)*x) poldisc(Mod(1, 3)*(2*x^3+x^2+5)) poldisc(Mod(1, 3)*(2*x^3+x+5)) poldisc((a*x^3+b*x^2+c*x+d)) poldisc((a*x^3+b*x^2+c*x+d)*Mod(1,3)) poldisc((a*x^3+c*x+d)*Mod(1,3)) poldisc(y^2/x+1, y) poldisc(x, y) check(P)= { my(d=poldegree(P)); if(poldisc(P)*y^(d*(d-1))!=poldisc(subst(P,x,x/y)*y^d),error(P)); } test(a)= { check(a^0*x^6+(a^9+a^8+a^7+a^6+a^4+a^3+a)*x+(a^9+a^8+a^7+2*a^6+a^4+a^2)); print(a^0*x^0*0,":",a^0*x^0); } test(ffgen(2^10,'a)); test(ffgen(3^10,'a)); test(ffgen([nextprime(2^100),5],'a)); test(Mod(Mod(1,2),ffinit(2,5,'a))); test(Mod(Mod(1,3),ffinit(3,5,'a))); my(p=nextprime(2^100)); test(Mod(Mod(1,nextprime(2^100)),ffinit(p,3,'a))); \\ #1830 p=Pol([1,12,-41,-1046,-1152,39768,128414,-829340,-4525890,8899442,94079590,4385944,-1307089619,-1852433280,12494993027,34801502551,-77942248052,-390957423498,215189990152,3107265788332,1420485007463,-18347443916369,-23277245912959,80992666070621,174175172136656,-256947893746801,-907981487991468,484717098540915,3624070471203629,223320207786810,-11495832122433637,-5970240860086125,29459554866159718,27626780885543732,-61174934576020682,-85453537075841594,101601090502467492,205071787088061635,-128623032844198712,-402298722797595630,103257810302253206,661593554032027685,13023738437946757,-924770373478411117,-228669477020600489,1106930103187315214,501417832370076217,-1137744012688843614,-748484700066174875,1002096690610670198,887074929263872304,-749681502970099140,-878282874862417133,466192451440777121,743397334132464078,-228293327650766293,-544343133811559511,73246386276267014,346915388490966115,2655042441806609,-192876875700267550,-25542640982995001,93481097097188652,23309890824202258,-39341812220193672,-14459562353785875,14260775252163516,7110363380474628,-4385795657650451,-2904911553101253,1111356927314961,1003888928894249,-216866559082696,-295159994592569,25722943511905,73725762974324,1493634668853,-15527611742629,-1817577645774,2717078090720,579368368367,-384681131682,-124276266074,41834786710,20049074850,-3059594663,-2480136051,67764972,231104576,16656470,-15345258,-2573079,629755,190125,-7992,-7579,-537,116,21,1]); poldisc(p) poldiscfactors(x^0) poldiscfactors(x) poldiscfactors(x^2+1) T=x^4 - 36769809176826048*x^3 + 341005843447471336362247372459582*x^2 - 55175428449449617975400382424484477584006986048*x + 2251690401007462966577022376495167683872612094945483390567809; poldiscfactors(T) poldiscfactors(T,1) T=y^24+4*y^23-14*y^22-72*y^21+79*y^20+596*y^19-26*y^18-2440*y^17-913*y^16+6004*y^15+4594*y^14-6872*y^13-3220*y^12+14436*y^11+20340*y^10+10564*y^9+21950*y^8+28292*y^7+38580*y^6+31312*y^5+64413*y^4+46004*y^3+48710*y^2+18852*y+22307; poldiscfactors(T) a=ffgen(3^2,'a);poldisc(x^6+a*x+y) \\ ERRORS, keep at end of file poldisc(x^2/y^2, y) pari-2.11.2/src/test/in/alggroup0000644000175000017500000000573013326135265015110 0ustar billbilldefault(realprecision,38); default(parisize,100M); \\examples from docu nf = nfinit(y^2+1); PR = idealprimedec(nf,5); #PR hi = []; hf = [PR, [1/3,-1/3]]; A = alginit(nf, [3,hf,hi]); algsplittingfield(A).pol K = nfsplitting(x^4+x+1); gal = galoisinit(K); al = alggroupcenter(gal,,&cc); algiscommutative(al) #cc[3] \\end examples \\test ordering in simpledec print("ordering"); Sn(n) = [Vecsmall(numtoperm(n,i)) | i <- [0..n!-1]]; D2n(n)= { [[vectorsmall(2*n,i,if(i==n,1,i==2*n,n+1,i+1)), vectorsmall(2*n,i,if(i==1,n+1,i==n+1,1,2*n+2-i))],Vecsmall([n,2])]; } testordering(al)={ my(jac, ss, dec); jac=algradical(al); if(jac==0, ss=al, ss=algquotient(al,jac)); dec=algsimpledec(ss)[2]; print(apply(algdim,dec)); print([#algcenter(x) | x<-dec]); }; setrand(1); {for(n=1,4, print("S",n); al = alggroup(Sn(n),7); print(algisassociative(al)); testordering(al); );} {for(n=1,3, print("S",n); al = alggroup(Sn(n)); print(algisassociative(al)); testordering(al); );} {for(n=4,16, print("D",2*n); al = alggroup(D2n(n),691); if(n<10,print(algisassociative(al))); testordering(al); );} {for(n=4,12, print("D",2*n); al = alggroup(D2n(n)); if(n<10,print(algisassociative(al))); testordering(al); );} \\alggroup print("alggroup"); K = nfsplitting(x^3-x+1); gal = galoisinit(K); al = alggroup(gal) algissemisimple(al) alggroup([Vecsmall([2,1]),Vecsmall([1,2])]); alggroup([Vecsmall([1,2])]); alggroup([Vecsmall([1,2,3]), Vecsmall([1,3,2])]) gal = galoisinit(nfsplitting(x^4+7)); alggroup(gal); gal = galoisinit(nfsplitting(x^6+7)); alggroup(gal); \\alggroupcenter {for(n=1,5, print("S",n); al = alggroupcenter(Sn(n),7); print(algisassociative(al)); print(algiscommutative(al)); print(algdim(al) == #algsimpledec(al)[2]); );} {for(n=1,4, print("S",n); al = alggroupcenter(Sn(n)); print(algisassociative(al)); print(algiscommutative(al)); print(algdim(al) == #algsimpledec(al)[2]); );} conjD2neven(n)=2+(n-2)/2+2; conjD2nodd(n)=1+(n-1)/2+1; conjD2n(n)=if(n%2,conjD2nodd(n),conjD2neven(n)); firstprime1mod(n) = { p = 2; while(p%n!=1, p=nextprime(p+1)); p; } {for(n=3,20, print("D",2*n); p = firstprime1mod(2*n); al = alggroupcenter(D2n(n),p); print(algdim(al) == conjD2n(n)); print(algisassociative(al)); print(algiscommutative(al)); print(algdim(al) == #algsimpledec(al)[2]); );} {forprime(p=5,30, print("D",2*p); al = alggroupcenter(D2n(p)); print(algdim(al) == conjD2n(p)); print(algdim(al) > #algsimpledec(al)[2]); );} alggroupcenter(Sn(3),0); \\Bill: random slow cases G=galoisinit(x^24-24*x^22+253*x^20-1540*x^18+5984*x^16-15488*x^14+27026*x^12-31448*x^10+23540*x^8-10528*x^6+2416*x^4-192*x^2+1); al = alggroup(G); setrand(8690); algsimpledec(al)[2]; setrand(1294); algsimpledec(al)[2]; \\bad inputs alggroupcenter(['x,'y]); alggroupcenter('x,1); \\Bill's bug alggroup("a"); alggroup(["a"]); alggroup(["a", "b", "c"]); alggroup([Vecsmall([1]), Vecsmall([1,2]), Vecsmall([1,2,3])]); alggroup([Vecsmall([1]), Vecsmall([2,3]), Vecsmall([1,2,3])]); pari-2.11.2/src/test/in/ranges0000644000175000017500000000201113447371554014543 0ustar billbill[2^100..2^100+3] [x^2+1|x<-[1..40],isprime(x)] [x|x<-primes(40)] [x|x<-[1..40],isprime(x)] [a^2+b^2|a<-[1..10];b<-[1..10],gcd(a,b)==1] [a^2+b^2|a<-[1..10],isprime(a);b<-[1..10],a!=b && isprime(b)] [[a,b,c]|a<-[1..5];b<-[1..a];c<-[1..b]] primes(100)[4..7] V=[1..5]; V[2..3] V[1..-2] V[-3..-1] V[^3] V[6..5] V[6..-1] V[1..0] V[0..-1] V[-1..-2] V=Vecsmall(V); V[2..3] V[1..-2] V[-3..-1] V[^3] M=matrix(5,5,i,j,i+5*j-5); M[2..3,2..3] M[1..2,1] M[1,1..4] M[1..3,] M[,1..3] M[1..5,1..-2] M[1..-2,1..-2] M[-3..-1,-3..-1] M[^3,2..3] M[^2,1] M[1,^4] M[^3,] M[,^3] M[^5,1..-2] M[1..-2,^-2] M[-3..-1,-3..-1] Mat()[1..0,1..0] f(v,c=0)=my(a,b=[1,2]);[a,b[c]]=v;[a,b]; f([1,2],1) f([3,4],2) g(v)= { my(a,[b,c]=v,d=v,e=0,f=I); [a,b,c,d,e,f]; } h(v)= { local(a,[b,c]=v,d=v,e=0,f=I); [a,b,c,d,e,f]; } g([3,4]) h([3,4]) \\ #1552 [x|x<-[];y<-[]] [x|x<-[1..5];y<-[1..x-1];z<-[1]] [x|x<-[1..5];y<-[1..x], y 1e-38,print(x))) log1p(x + O(x^5)) log1p(1e-10 + x + O(x^5)) log1p(O(x)) log1p(1/10^10) log1p(1e-10) log1p(1e-20) log1p(1e-10*(1+I)) log1p(1e-20*(1+I)) log1p(2+O(5^3)) a=-1633048355459347662258066616498.+ 107206003159399666971219664801296.*I; acosh(a) asinh(a) localprec(1000); abs(sinh(1e-500)-1e-500) < 2e-1500 sinc(0) sinc(1/2) sinc(10*I) sinc(1+I) sinc(O(3^2)) sinc(3+O(3^4)) sinc(2+O(3^2)) sinc(x) sinc(1/x) sinc(0.*I) sinc(O(3^4)*I) sinc((1+O(3^3)) * x) sinc(Pi * x) localprec(2003); log(exp(1.5)) - 1.5 localbitprec(320); obj=[1.2, 2.1*I, 1+1.1*I]; { fun=[exp,expm1,log,arg, cos,sin,tan,cotan,sinc, cosh,sinh,tanh,cotanh, acos,asin,atan, acosh,asinh,atanh, sqrt,x->sqrtn(x,3), gamma,lngamma,psi,zeta]; for (i=1, #fun, my (f = fun[i]); print1(f,": " ); print([bitprecision(f(p)) | p<-obj])); } pari-2.11.2/src/test/in/matsnf0000644000175000017500000000253013201017466014545 0ustar billbillminpoly([-5,0,-1,1;0,-5,-1,-1;1,1,-5,0;-1,1,0,-5]) minpoly([-5,0,-1,1;0,-5,-1,-1;1,1,-5,0;-1,1,0,-5]/3) minpoly([-5,0,-1,1;0,-5,-1,-1;1,1,-5,0;-1,1,0,-5]/a) minpoly([-5,0,-1,1;0,-5,-1,-1;1,1,-5,0;-1,1,0,-5]*a) matsnf([1,2;3,4],2) matsnf([-X-5,-1,-1,0;0,X^2+10*X+26,-1,-X-5;1,-X-5,-X-5,1;-1,0,0,1],2) minpoly([a+4/51*d,29/51*d,55/17*d,-9/17*d;-11/51*d,a+35/51*d,-11/17*d,12/17*d;23/51*d,1/51*d,a+6/17*d,-5/17*d;11/17*d,16/17*d,33/17*d,a-19/17*d]) checkfrobenius(M)= { my([F,B] = matfrobenius(M,2)); if(M!=B^-1*F*B, error("matfrobenius:",M)); F } { for(i=1,15, print(checkfrobenius(matrix(i,i,k,j,k>=j)))); for(i=1,10, print(checkfrobenius(matpascal(i)))); for(i=1,8, print(checkfrobenius(mathilbert(i)))); } matsnf(matdiagonal([x,0,x]), 2) matsnf(matdiagonal([1+x,0,x]), 2) \\Bug #1208 matsnf([0;1;2], 4) matsnf([0;1;2], 5) matsnf(Mat([0,1,2]), 4) matsnf(Mat([0,1,2]), 5) m=[2*x^6+x^5+2*x^4+2*x^3+x^2+2*x+2,2*x^5+x^3+2*x^2+2,x^3+x^2+x;2*x^6+x^3+x+2,2*x^5+2*x^4+x^3+2*x,x^3+2*x^2+2*x;2*x^6+x^4+x^3+2*x^2+2,2*x^5+2*x^4+2*x^3+x^2+2,x^3+2*x^2+x+2];matsnf(m*Mod(1,3), 2) default(realprecision,38); m=[1,0,0,1,1,1,1,1,0;1,0,0,1,1,0,1,0,0;0,0,0,0,1,0,0,1,0;0,0,0,0,1,1, 0,0,1;0,1,0,0,0,1,1,0,1;1,1,1,0,0,0,1,1,0;0,0,1,0,0,1,0,1,1;0,0,1,1,1,1,0,1,0;0, 1,0,0,0,0,1,1,0]*1.; round(matfrobenius(m)) round(minpoly(m)) matsnf([27,0;0,3;1,1;0,0],1+4) pari-2.11.2/src/test/in/nfields0000644000175000017500000000715013326135265014712 0ustar billbillHEAP=[170, if(sizebyte(0)==16,95778,97421)]; default(realprecision,154); Pi; default(realprecision,38); dobnf(T,flag=0,tech=[])= setrand(1); my(K = bnfinit(T,flag,tech)); [K.cyc,K.fu]; \e \\ Initialisations diverses p2=Pol([1,3021,-786303,-6826636057,-546603588746,3853890514072057]); fa=[11699,6;2392997,2;4987333019653,2]; setrand(1);N=10^8;a=matrix(3,5,j,k,vectorv(5,l,random\N)); nfpol=x^5-5*x^3+5*x+25; nf=nfinit(nfpol) nfinit(nfpol,2) nfinit(nfpol,3)[2] nf3=nfinit(x^6+108); setrand(1);bnf2=bnfinit(y^3-y-1);nf2=bnf2[7]; setrand(1);bnf=bnfinit(x^2-x-57,,[0.2,0.2]) dobnf(x^2-x-100000,1) \p19 setrand(1);sbnf=bnfcompress(bnfinit(x^3-x^2-14*x-1)) K=bnfinit(sbnf); bnfisprincipal(K, idealprimedec(K,3)[2]) \p38 bnr=bnrinit(bnf,[[5,3;0,1],[1,0]],1); bnr.cyc bnr2=bnrinit(bnf,[[25,13;0,1],[1,1]]); bnr2.bid rnfinit(nf2,x^5-x-2) \\ bnfcertify(bnf) dobnf(x^4+24*x^2+585*x+1791,,[0.1,0.1]) bnrconductor(bnf,[[25,13;0,1],[1,1]]) bnrconductorofchar(bnr,[2]) bnfisprincipal(bnf,[5,1;0,1],0) bnfisprincipal(bnf,[5,1;0,1]) bnfisunit(bnf,Mod(3405*x-27466,x^2-x-57)) bnfnarrow(bnf) bnfsignunit(bnf) bnrclassno(bnf,[[5,3;0,1],[1,0]]) lu=ideallist(bnf,55,3); bnrclassnolist(bnf,lu) bnrdisc(bnr,Mat(6)) bnrdisc(bnr) bnrdisc(bnr2,,,2) bnrdisc(bnr,Mat(6),,1) bnrdisc(bnr,,,1) bnrdisc(bnr2,,,3) bnrdisclist(bnf,lu) bnrdisclist(bnf,20) bnrisprincipal(bnr,idealprimedec(bnf,7)[1]) dirzetak(nfinit(x^3-10*x+8), 30) factornf(x^3+x^2-2*x-1,t^3+t^2-2*t-1) \\ vp=idealprimedec(nf,3)[1] idx=idealhnf(nf,vp) idealred(nf,idx,[1,5,6]) idy=idealdiv(nf,5,idealprimedec(nf,5)[1]) idx2=idealmul(nf,idx,idx) idt=idealmul(nf,idx,idx,1) idz=idealintersect(nf,idx,idy) aid=[idx,idy,idz,1,idx]; idealadd(nf,idx,idy) idealaddtoone(nf,idx,idy) idealaddtoone(nf,[idy,idx]) idealappr(nf,idy) idealappr(nf,idealfactor(nf,idy)) idealcoprime(nf,idx,idx) idealdiv(nf,idy,idt) idealdiv(nf,idx2,idx,1) idealfactor(nf,idz) idealhnf(nf,vp[2],3) ideallist(bnf,20) bid=idealstar(nf2,54) ideallog(nf2,y,bid) idealmin(nf,idx,[1,2,3]) idealnorm(nf,idt) idp=idealpow(nf,idx,7) idealpow(nf,idx,5,1) idealprimedec(nf,2) idealprimedec(nf,3) idealprimedec(nf,11) idealtwoelt(nf,idy) idealtwoelt(nf,idy,10) idealstar(nf2,54) idealval(nf,idp,vp) \\ ba=nfalgtobasis(nf,x^3+5) bb=nfalgtobasis(nf,x^3+x) bc=matalgtobasis(nf,[x^2+x;x^2+1]) matbasistoalg(nf,bc) nfbasis(x^3+4*x+5) nfbasistoalg(nf,ba) nfdisc(x^3+4*x+12) nfeltdiv(nf,ba,bb) nfeltdiveuc(nf,ba,bb) nfeltdivrem(nf,ba,bb) nfeltmod(nf,ba,bb) nfeltmul(nf,ba,bb) nfeltpow(nf,bb,5) nfeltreduce(nf,ba,idx) nfeltval(nf,ba,vp) nffactor(nf2,x^3+x) aut=nfgaloisconj(nf3) nfgaloisapply(nf3,aut[5],Mod(x^5,x^6+108)) nfhilbert(nf,3,5) nfhilbert(nf,3,5,vp) nfhnf(nf,[a,aid]) da=nfdetint(nf,[a,aid]) nfhnfmod(nf,[a,aid],da) nfisideal(bnf[7],[5,1;0,1]) nfisincl(x^2+1,x^4+1) nfisincl(x^2+1,nfinit(x^4+1)) nfisisom(x^3+x^2-2*x-1,x^3+x^2-2*x-1) nfisisom(x^3-2,nfinit(x^3-6*x^2-6*x-30)) nfroots(nf2,x+2) nfrootsof1(nf) nfsnf(nf,[a[,1..3], [1,1,1], [idealinv(nf,idx),idealinv(nf,idy),1]]) nfsubfields(nf) polcompositum(x^4-4*x+2,x^3-x-1) polcompositum(x^4-4*x+2,x^3-x-1,1) polgalois(x^6-3*x^2-1) polred(x^5-2*x^4-4*x^3-96*x^2-352*x-568) polred(x^4-28*x^3-458*x^2+9156*x-25321,3) polred(x^4+576,1) polred(x^4+576,3) polred(p2,0,fa) polred(p2,1,fa) polredabs(x^5-2*x^4-4*x^3-96*x^2-352*x-568) polredabs(x^5-2*x^4-4*x^3-96*x^2-352*x-568,1) polredord(x^3-12*x+45*x-1) polsubcyclo(31,5) setrand(1);poltschirnhaus(x^5-x-1) \\ p=x^5-5*x+y; aa=rnfpseudobasis(nf2,p) rnfbasis(bnf2,aa) rnfdisc(nf2,p) rnfequation(nf2,p) rnfequation(nf2,p,1) rnfhnfbasis(bnf2,aa) rnfisfree(bnf2,aa) rnfsteinitz(nf2,aa) \\ setrand(1);quadclassunit(1-10^7,,[1,1]) setrand(1);quadclassunit(10^9-3,,[0.5,0.5]) if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/language0000644000175000017500000000012113213263002015022 0ustar billbillg(v, f) = v; f(n) = g([1], x->0); f(1) foo = vectorsmall(1); for(i=1,1, foo[1]); pari-2.11.2/src/test/in/quadray0000644000175000017500000000147613201017466014733 0ustar billbilldefault(realprecision,38); \\ all quad imaginary whose class group has exponent 2 v=[-15,-35,-51,-91,-115,-123,-187,-195,-235,-267,-403,-427,-435,-483,-555,-595,-627,-715,-795,-1155,-1435,-1995,-3003,-3315,-20,-24,-40,-52,-84,-88,-120,-132,-148,-168,-228,-232,-280,-312,-340,-372,-408,-420,-520,-532,-660,-708,-760,-840,-1012,-1092,-1320,-1380,-1428,-1540,-1848,-5460]; for(i=1, #v, print(v[i]": "quadhilbert(v[i]))) quadhilbert(-4036) quadhilbert(-300003) quadhilbert(-3628843) Q(D,f) = lift(quadray(D,f)); Q(-4,31) Q(-11,2) Q(-15,3) Q(-179,2) Q(-2276,2) Q(-251,2) Q(-35,2) Q(-4,31) Q(-51,3) Q(8-48*3,2) Q(1-48*3,3) Q(1-48*3,4) Q(40-48*3,6) Q(-7,7) K = bnfinit(y^2+5); P5=idealprimedec(K,5)[1]; Q(K,P5) K = bnfinit(y^2+5*12); P2=idealprimedec(K,2)[1]; P5=idealprimedec(K,5)[1]; Q(K,idealmul(K,P2,P5)) \\#1633 quadray(-11,3) pari-2.11.2/src/test/in/sumformal0000644000175000017500000000015512314242552015263 0ustar billbillsumformal(1/n) sumformal(0) sumformal(1) sumformal(n) sumformal(n^2) sumformal(x*y + 1) sumformal(x*y + 1,y) pari-2.11.2/src/test/in/factor0000644000175000017500000000404613457566440014555 0ustar billbilldefault(realprecision,38); factor(x^2+I) factor(x^2-1.) factor(x^2+I+1.) factor(x^2+Mod(1,5)) factor(x^2+Mod(1,3)+I) factor(x^2+Mod(1,5)*I) factor(x^2+(1+O(5))*I) factor(x^2+(1+O(3))+I) factor(x^2+(1+O(5))) factor(x^2+quadgen(-3)) factor(x^2+quadgen(-3)*Mod(1,3)) factor(x^2+quadgen(-3)*Mod(1,5)) factor(x^2+quadgen(-3)*(1+O(5))) factor(x^2+quadgen(-3)*(1+O(3))) factor(x^2+Mod(y,y^2+1)) factor(x^2+Mod(y*Mod(1,3),y^2+1)) factor(x^2+Mod(y*Mod(1,5),y^2+1)) factor(x^2+Mod(y*(1+O(3)),y^2+1)) factor(5/2 + I/3) factor(5^4 + 5^4*I) factor(5 + I) factor(15+3*I) factor(4+4*I) factor((3+4*I)/25) factor(15,3) q=31271192761826143388782348951/31274945109847936339856761591; factor(q,2) factor(q,500100) factor((x-2.)*(x^2+1)) factor((x+1)^2/(x^2-4)) factor((x^2+1)/x) factor(x^2+a^3*x-Mod(6,a^2-2)) p1 = (289*x^4 + 1)^8; p2 = (19*x^2 + 1)^16; factor(p1) factor(p2) factor(x^2-1/y^2) factor(y/x) factor((x^3+y^3)^2*(x^4+y^4)) factor(x^3+y^3) factor((x^7-y^7)*Mod(1,7)) factor((x^7-y)*Mod(1,7)) factor(x^5+y*x^4+y^2*x^3+(y^2-1)*x^2+(y^3-y)*x+(y^4-y^2)) factor((x^2+y^2) * Mod(1,13)) factor(x^3+I*y*x^2+(y^2+I)*x+(I*y^3-y)) factor((x^3+y^3+z^3-3*x*y*z)*Mod(1,7)) centerlift(factor((x^3+y^3+1-3*x*y)*(1+O(7^3)))) factor(x*y*(x+y)) E(n)=ellinit([2,1-n^2,(1-n^2)*(1+n),0,0]); factor(elldivpol(ellinit(E(t)),4)) factor(0.*x^2+x+1) factor(0.*x^2+x+I) factor(x^2+1, I) factor(x^2-1, 1.) factor(x^2+I+1, 1.) factor(x^2+1,Mod(1,5)) factor(x^2+Mod(1,3),I) factor(x^2+1,O(5)) factor(x^2+O(5^2)) factor(x^2+(1+O(3)),I) factor(x^2+x+1,quadgen(-3)) factor(x^2+quadgen(-3),Mod(1,3)) factor(x^2+quadgen(-3),Mod(1,5)) factor(x^2+quadgen(-3),O(5)) factor(x^2+quadgen(-3),O(3)) factor(x^2+y,Mod(1,y^2+1)) factor(x^2+Mod(y,y^2+1),Mod(1,3)) factor(x^2+Mod(y,y^2+1),Mod(1,5)) factor(x^2+Mod(y,y^2+1),O(3)) factor(5/2,I) factor(x^2+a^3*x-6,Mod(1,a^2-2)) factor((x*y+1)*(x*y+2),Mod(1,2)) factor((x*y+1)*x*(y^2+y+1)*(z^3+z+1),Mod(1,2)) factor(1/(x^5+3*y*x^4+3*y^2*x^3+y^3*x^2)) factor(x^3+y^3,quadgen(-3)) factor(x^7-y^7,Mod(1,7)) factor(x^7-y,Mod(1,7)) factor(x^2+y^2,Mod(1,13)) factor(x^3+y^3+z^3-3*x*y*z,Mod(1,7)) pari-2.11.2/src/test/in/history0000644000175000017500000000014613201017466014757 0ustar billbill2 3 4 5 %`````` %```` %3 % %#3;1 %#```;1 %#;1 default(histsize,1) 1; %`` default(histsize,10) %`` %13 pari-2.11.2/src/test/in/genus2red0000644000175000017500000003761413326135265015174 0ustar billbill\\ Input from Namikawa-Ueno's list of curves of genus 2 \\ with expected reduction types. \\ t is to be substituted with a prime number bigger or equal to 7 \\ and can be taken to be 5 most of the time... \\ a, b, c are generic integers (to be changed if unexpected output) do(P, s) = print("Type: ", s); genus2red(subst(P,'t,7),7); P0=x^5+a*x^3+b*x^2+c*x+1; do(substvec(P0, [a,b,c], [1,-2,3]), "[I{0-0-0}], p. 155") P0=x^5+a*t^2*x^3+b*t^3*x^2+c*t^4*x+t^5; do(substvec(P0, [a,b,c], [1,-2,3]), "[I*{0-0-0}], p. 155") P0=x^6+a*t*x^4+b*t^2*x^2+t^3; do(substvec(P0, [a,b], [4,-1]), "[II], p. 155") genus2red(substvec(P0,[a,b,t],[4,-1,3]),3) P0=x^6+a*t*x^3+t^2; do(subst(P0, 'a, 4), "[III], p. 155") P0=t*(x^6+a*t*x^3+t^2); do(subst(P0, 'a, 5), "[IV], p. 155") P0=x^6+t; do(P0, "[V], p. 156") P0=x^6+t^5; do(P0, "[V*], p. 156") P0=x*(x^4+a*t*x^2+t^2); do(subst(P0, 'a, 3), "[VI], p. 156") P0=x*(x^4+t); do(P0, "[VII], p. 156") P0=x*(x^4+t^5); do(P0, "[VII*], p. 156") P0=x^5+t; do(P0, "[VIII-1], p. 156") P0=x^5+t^3; do(P0, "[VIII-2], p. 157") P0=x^5+t^7; do(P0, "[VIII-3], p. 157") P0=x^5+t^9; do(P0, "[VIII-4], p. 157") P0=x^5+t^2; do(P0, "[IX-1], p. 157") P0=x^5+t^4; do(P0, "[IX-2], p. 157") P0=x^5+t^6; do(P0, "[IX-3], p. 157") P0=x^5+t^8; do(P0, "[IX-4], p. 158") \\ Elliptic type, \\ m > 0 FIXME: changed ! m = 10; P0=(x^3+a*x+1)*(x^3+b*t^(4*m)*x+t^(6*m)) ; do(substvec(P0, [a,b], [3,10]), Strprintf("[I{0}-I{0}-%ld], p. 158", m)) \\ misprint in N-U: m+1 must be m. genus2red(substvec(P0,['a,'b,'t],[-1,1,3]),3) \\ m >= 0 m = 10; P0=((x-1)^3+a*t^2*(x-1)+t^3)*(x^3+b*t^(4*m+2)*x+t^(6*m+3)); do(substvec(P0, [a,b], [3,10]), Strprintf("[I{0}*-I{0}*-%ld], p. 158", m)) genus2red(substvec(P0,['a,'b,'t],[-1,1,3]),3) \\ m >= 0 m = 10; P0=(x^3+a*x+1)*(x^3+b*t^(4*m+2)*x+t^(6*m+3)); do(substvec(P0, [a,b], [3,10]), Strprintf("[I{0}-I{0}*-%ld], p. 159", m)) genus2red(substvec(P0,['a,'b,'t],[-1,1,3]),3) \\ m >= 0 m = 10; P0=(x^2-t)^3+a*t^(2*m+4)*(x^2-t)+t^(3*m+6); do(subst(P0, 'a, 3), Strprintf("[2I{0}-%ld], p. 159",m+1)) genus2red(substvec(P0,['a,'t],[-1,3]),3) \\ m >= 0 m = 10; P0=(x^2-t)^3+a*t^(2*m+3)*(x^2-t)+t^(3*m+4)*x; do(subst(P0, 'a, 3), Strprintf("[2I{0}*-%ld], p. 159",m)) \\ m >= 0 m = 10; P0=(x^2-t)^3+a*t^(2*m+3)*(x^2-t)+t^(3*m+4)*x; do(subst(P0, 'a, 3), Strprintf("[2I{0}*-%ld], p. 159",m)) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+1))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}-II-%ld], p. 159",m)) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+5))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}-II*-%ld], p. 160",m)) genus2red(substvec(P0,['a,'t],[3,3]),3) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+2))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}-IV-%ld], p. 160",m)) genus2red(substvec(P0,['a,'t],[3,3]),3) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+4))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}-IV*-%ld], p. 160",m)) genus2red(substvec(P0,['a,'t],[3,3]),3) \\ m >= 0 m = 10; P0=t*(x^3+t^(6*m+4))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}*-II-%ld], p. 160",m)) genus2red(substvec(P0,['a,'t],[3,3]),3) \\ m >= -1 m = 10; P0=t*(x^3+t^(6*m+8))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}*-II*-%ld], p. 160-161",m)) genus2red(substvec(P0,['a,'t],[3,3]),3) \\ m >= 0 m = 10; P0=t*(x^3+t^(6*m+5))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}*-IV-%ld], p. 161",m)) \\ m >= -1 m = 10; P0=t*(x^3+t^(6*m+7))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}*-IV*-%ld], p. 161",m)) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+1))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}-III-%ld], p. 161",m)) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+3))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}-III*-%ld], p. 162",m)) \\ m >= 0 m = 10; P0=t*x*(x^2+t^(4*m+3))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}*-III-%ld], p. 162",m)) \\ m >= -1 m = 10; P0=t*x*(x^2+t^(4*m+5))*(x^2+a*x+1); do(subst(P0, 'a, 3), Strprintf("[I{0}*-III*-%ld], p. 162",m)) \\ m >= 0 m = 10; P0=(x^2-t)^3+t^(3*m+3)*x; do(P0, Strprintf("[2II-%ld], p. 162",m)) genus2red(subst(P0,'t,3),3) \\ m >= 0 m = 10; P0=(x^2-t)^3+t^(3*m+5)*x; do(P0, Strprintf("[2II*-%ld], p. 163",m)) genus2red(subst(P0,'t,3),3) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+1))*((x-1)^3+t); do(P0, Strprintf("[II-II-%ld], p. 163",m)) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+1))*((x-1)^3+t^5); do(P0, Strprintf("[II-II*-%ld], p. 163",m)) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+5))*((x-1)^3+t^5); do(P0, Strprintf("[II*-II*-%ld], p. 163",m)) \\ m = -1 P0=t*(x^3+t^2)*((x-1)^3+t^2); do(P0, "[II*-II*-(-1)], p. 163") \\ m >= 0 m = 10; P0=(x^3+t^(6*m+1))*((x-1)^3+t^2); do(P0, Strprintf("[II-IV-%ld], p. 164",m)) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+1))*((x-1)^3+t^4); do(P0, Strprintf("[II-IV*-%ld], p. 164",m)) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+5))*((x-1)^3+t^2); do(P0, Strprintf("[II*-IV-%ld], p. 164",m)) \\ m = -1 P0=(x^3+t^2)*(x^3+t); do(P0, "[II*-IV-(-1)], p. 164") \\ m bigger or equal -1 m = 10; P0=t*(x^3+t^(6*m+7))*((x-1)^3+t^2); do(P0, Strprintf("[II*-IV*-%ld], p. 164-165",m)) \\ m >= 0 m = 10; P0=(x^2-t)^3+t^(3*m+4); do(P0, Strprintf("[2IV-%ld], p. 165",m)) genus2red(subst(P0,'t,3),3) \\ m >= 0 m = 10; P0=(x^2-t)^3+t^(3*m+5); do(P0, Strprintf("[2IV*-%ld], p. 165",m)) genus2red(subst(P0,'t,3),3) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+2))*((x-1)^3+t^2); do(P0, Strprintf("[IV-IV-%ld], p. 165",m)) \\ m >= 0 m = 10; P0=(x^3+t^(6*m+2))*((x-1)^3+t^4); do(P0, Strprintf("[IV-IV*-%ld], p. 165",m)) \\ m >= -1 m = 10; P0=t*(x^3+t^(6*m+7))*((x-1)^3+t); do(P0, Strprintf("[IV*-IV*-%ld], p. 166",m)) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+1))*((x-1)^3+t); do(P0, Strprintf("[II-III-%ld], p. 166",m)) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+3))*((x-1)^3+t); do(P0, Strprintf("[II-III*-%ld], p. 166",m)) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+1))*((x-1)^3+t^5); do(P0, Strprintf("[II*-III-%ld], p. 166",m)) \\ m = -1 P0=(x^2+t)*(x^3+t^2); do(P0, "[II*-III-(-1)], p. 167") \\ m at least -1 m = 10; P0=t*x*(x^2+t^(4*m+5))*((x-1)^3+t^2); do(P0, Strprintf("[II*-III*-%ld], p. 167",m)) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+1))*((x-1)^3+t^2); do(P0, Strprintf("[IV-III-%ld], p. 167",m)) genus2red(subst(P0,'t,3),3) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+3))*((x-1)^3+t^2); do(P0, Strprintf("[IV-III*-%ld], p. 167",m)) genus2red(subst(P0,'t,3),3) \\ m = -1 P0=x*(x^2+t)*(x^3+t); do(P0, "[IV-III*-(-1)], p. 167") \\ the top horizontal line has mult. 3. \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+1))*((x-1)^3+t^4); do(P0, Strprintf("[IV*-III-%ld], p. 168",m)) \\ m at least -1 m = 10; P0=t*x*(x^2+t^(4*m+5))*((x-1)^3+t); do(P0, Strprintf("[IV*-III*-%ld], p. 168",m)) \\ m >= 0 m = 10; P0=(x^2-t)*((x^2-t)^2+t^(2*m+2)*x); do(P0, Strprintf("[2III-%ld], p. 168",m)) genus2red(subst(P0,'t,3),3) \\ m >= 0 m = 10; P0=(x^2-t)*((x^2-t)^2+t^(2*m+3)*x); do(P0, Strprintf("[2III*-%ld], p. 168",m)) genus2red(subst(P0,'t,3),3) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+1))*(x-1)*((x-1)^2+t); do(P0, Strprintf("[III-III-%ld], p. 169",m)) \\ m >= 0 m = 10; P0=x*(x^2+t^(4*m+1))*(x-1)*((x-1)^2+t^3); do(P0, Strprintf("[III-III*-%ld], p. 169",m)) \\ m >= -1 m = 10; P0=t*x*(x^2+t^(4*m+5))*(x-1)*((x-1)^2+t); do(P0, Strprintf("[III*-III*-{%ld}], p. 169",m)) \\ Parabolic type \\ n > 0 n = 9; P0=(x^3+a*x+1)*(x^2+t^n); do(subst(P0, 'a, 3), Strprintf("[I{%ld-0-0}], p. 170",n)) \\ n, m > 0 n = 9; m = 10; P0=(x^3+a*t^(4*m)*x+t^(6*m))*((x-1)^2+t^n); do(subst(P0, 'a, 3), Strprintf("[I{%ld}-I{0}-%ld], p. 170",n, m)) genus2red(substvec(P0,['a,'t],[-1,3]),3) \\ n, m >= 0 n = 9; m = 10; P0=(x+t)*(x^2+t^(n+2))*((x-1)^3+a*t^(4*m)*(x-1)+t^(6*m)); do(subst(P0, 'a, 3), Strprintf("[I{0}-I*{%ld}-%ld], p. 170",n, m)) genus2red(substvec(P0,['a,'t],[-1,3]),3) \\ n, m >= 0 n = 9; m = 10; P0=(x^3+a*t^(4*m+2)*x+t^(6*m+3))*((x-1)^2+t^n); do(subst(P0, 'a, 3), Strprintf("[I{%ld}-I{0}*-%ld], p. 171",n, m)) \\ n > 0 n = 9; P0=t*(x^3+a*x+1)*(x^2+t^n); do(subst(P0, 'a, 3), Strprintf("[I*{%ld-0-0}], p. 171",n)) \\ n, m >= 0 n = 9; m = 10; P0=(x+t)*(x^2+t^(n+2))*((x-1)^3+a*t^(4*m+2)*(x-1)+t^(6*m+3)); do(subst(P0, 'a, 3), Strprintf("[I*{%ld}-I{0}*-%ld], p. 171",n, m)) \\ n > 0 n = 9; P0=(x^4+a*t*x^2+t^2)*((x-1)^2+t^(n-1)); do(subst(P0, 'a, 3), Strprintf("[II{%ld-0}], p. 171",n)) \\ n > 0 n = 9; P0=t*(x^4+a*t*x^2+t^2)*((x-1)^2+t^(n-1)); do(subst(P0, 'a, 3), Strprintf("[II*{%ld-0}], p. 172",n)) \\ n > 0, m >= 0 n = 9; m = 10; P0=(x^3+t^(6*m+1))*((x-1)^2+t^n); do(P0, Strprintf("[II-I{%ld}-%ld], p. 172",n, m)) \\ n > 0, m >= 0 n = 9; m = 10; P0=(x^3+t^(6*m+5))*((x-1)^2+t^n); do(P0, Strprintf("[II*-I{%ld}-%ld], p. 172",n, m)) \\ n > 0, m >= 0 n = 9; m = 10; P0=(x^3+t^(6*m+2))*((x-1)^2+t^n); do(P0, Strprintf("[IV-I{%ld}-%ld], p. 173",n, m)) \\ n > 0, m >= 0 n = 9; m = 10; P0=(x^3+t^(6*m+4))*((x-1)^2+t^n); do(P0, Strprintf("[IV*-I{%ld}-%ld], p. 173",n, m)) \\ n, m >= 0 n = 9; m = 10; P0=(x-1+t)*((x-1)^2+t^(n+2))*(x^3+t^(6*m+1)); do(P0, Strprintf("[II-I*{%ld}-%ld], p. 173",n, m)) \\ n, m >= 0 n = 9; m = 10; P0=(x-1+t)*((x-1)^2+t^(n+2))*(x^3+t^(6*m+5)); do(P0, Strprintf("[II*-I*{%ld}-%ld], p. 174",n, m)) \\ n >= 0, m = -1 n = 9; P0=t*((x-1)^2+t^n)*(x^3+t^2); do(P0, Strprintf("[II*-I*{%ld}-(-1)], p. 174",n)) \\ n, m >= 0 n = 9; m = 10; P0=(x-1+t)*((x-1)^2+t^(n+2))*(x^3+t^(6*m+2)); do(P0, Strprintf("[IV-I*{%ld}-%ld], p. 174",n, m)) \\ n, m >= 0 n = 9; m = 10; P0=(x-1+t)*((x-1)^2+t^(n+2))*(x^3+t^(6*m+4)); do(P0, Strprintf("[IV*-I*{%ld}-%ld], p. 174",n, m)) \\ n >= 0, m = -1 n = 9; P0=t*((x-1)^2+t^n)*(x^3+t); do(P0, Strprintf("[IV*-I*{%ld}-(-1)], p. 175",n)) genus2red(subst(P0,'t,3),3) \\ n >= 0 n = 9; P0=x*(x^3+t)*((x-1)^2+t^n); do(P0, Strprintf("[IV-II{%ld}], p. 175",n)) genus2red(subst(P0,'t,3),3) \\ n > 0 n = 9; P0=x*(x^3+t^2)*((x-1)^2+t^(n-1)); do(P0, Strprintf("[IV*-II{%ld}], p. 175",n)) genus2red(subst(P0,'t,3),3) \\ n = 0 P0=(x^2+t^3)*(x^3+t^4); do(P0, "[IV*-II{0}], p. 175") genus2red(subst(P0,'t,3),3) \\ n >= 0 n = 9; P0=(x^3+t)*(x^2+t^(n+1)); do(P0, Strprintf("[II-II*{%ld}], p. 176",n)) genus2red(subst(P0,'t,3),3) \\ n >= 0 n = 9; P0=t*x*(x^3+t)*((x-1)^2+t^n); do(P0, Strprintf("[II*-II*{%ld}], p. 176",n)) genus2red(subst(P0,'t,3),3) \\ n > 0, m >= 0 n = 9; m = 10; P0=x*(x^2+t^(4*m+1))*((x-1)^2+t^n); do(P0, Strprintf("[III-I{%ld}-%ld], p. 176",n,m)) genus2red(subst(P0,'t,3),3) \\ n > 0, m >= 0 n = 9; m = 10; P0=x*(x^2+t^(4*m+3))*((x-1)^2+t^n); do(P0, Strprintf("[III*-I{%ld}-%ld], p. 176",n,m)) genus2red(subst(P0,'t,3),3) \\ n, m >= 0 n = 9; m = 10; P0=(x+t)*(x^2+t^(n+2))*(x-1)*((x-1)^2+t^(4*m+1)); do(P0, Strprintf("[III-I*{%ld}-%ld], p. 177",n,m)) genus2red(subst(P0,'t,3),3) \\ n, m >= 0 n = 9; m = 10; P0=(x+t)*(x^2+t^(n+2))*(x-1)*((x-1)^2+t^(4*m+3)); do(P0, Strprintf("[III*-I*{%ld}-%ld], p. 177",n,m)) genus2red(subst(P0,'t,3),3) \\ n >= 0, m = -1 n = 9; P0=t*x*(x^2+t)*((x-1)^2+t^n); do(P0, Strprintf("[III*-I*{%ld}-(-1)], p. 177",n)) \\ attach one more projective line of mult. 1 to the component 2B \\ n >= 0 n = 9; P0=(x^4+t)*((x-1)^2+t^n); do(P0, Strprintf("[III-II{%ld}], p. 177",n)) \\ n > 0 n = 9; P0=(x^4+t^3)*((x-1)^2+t^(n-1)); do(P0, Strprintf("[III*-II{%ld}], p. 178",n)) \\ n = 0 P0=t*(x^2+t)*(x^4+t); do(P0, "[III*-II{0}], p. 178") \\ n >= 0 n = 9; P0=(x^4+t)*(x^2+t^(n+1)); do(P0, Strprintf("[III-II*{%ld}], p. 178",n)) \\ n >= 0 n = 9; P0=(x^4+t^3)*(x^2+t^(n+2)); do(P0, Strprintf("[III*-II*{%ld}], p. 178",n)) \\ Parabolic type continued \\ n, p > 0 n = 9; p = 8; P0=(x^2+t^n)*((x+1)^2+t^p)*(x-1); do(P0, Strprintf("[I{%ld-%ld-0}], p. 179",n,p)) \\ n, p, m > 0 n = 9; p = 8; m = 10; P0=(x+t^(2*m))*(x^2+t^(4*m+n))*((x-1)^2+t^p); do(P0, Strprintf("[I{%ld}-I{%ld}-%ld}], p. 179",n,p,m)) \\ n, p > 0 n = 9; p = 8; P0=t*(x^2+t^n)*((x+1)^2+t^p)*(x-1); do(P0, Strprintf("[I*{%ld-%ld-0}], p. 180",n,p)) genus2red(subst(P0,'t,3),3) \\ n, p > 0, m >= 0 n = 9; p = 8; m = 10; P0=(x+t^(2*m+1))*(x^2+t^(4*m+n+2))*(x-1+t)*((x-1)^2+t^(p+2)); do(P0, Strprintf("[I*{%ld}-I*{%ld}-%ld], p. 180",n,p,m)) \\ n, p > 0, m >= 0 n = 9; p = 8; m = 10; P0=(x+t^(2*m+1))*(x^2+t^(4*m+p+2))*((x-1)^2+t^n); do(P0, Strprintf("[I{%ld}-I*{%ld}-%ld], p. 180",n,p,m)) genus2red(subst(P0,'t,3),3) \\ n > 0 even, m > 0 k = 4; m = 10; n=2*k; P0=((x^2-t)+t^(m+1))*((x^2-t)^2+t^(2*m+k+2)); do(P0, Strprintf("[2I{%ld}-%ld], p. 181",n,m)) genus2red(subst(P0,'t,3),3) \\ n > 0 odd, m > 0 k = 4; m = 10; n=2*k+1; P0=((x^2-t)+t^(m+1))*((x^2-t)^2+t^(2*m+k+2)*x); do(P0, Strprintf("[2I{%ld}-%ld}], p. 181",n,m)) \\ n > 0 even, m=0 k = 4; n=2*k; P0=((x^2-t)+a*t)*((x^2-t)^2+t^(k+2)); do(subst(P0, 'a, 2), Strprintf("[2I{%ld}-0], p. 181",n)) \\ n > 0 odd, m=0 k = 4; n=2*k+1; P0=((x^2-t)+a*t)*((x^2-t)^2+t^(k+2)*x); do(subst(P0, 'a, 2), Strprintf("[2I{%ld}-0], p. 181",n)) \\ n > 0 even, m >= 0 k = 4; m = 10; n=2*k; P0=((x^2-t)+t^(m+1)*x)*((x^2-t)^2+t^(2*m+k+3)); do(P0, Strprintf("[2I*{%ld}-%ld}], p. 181",n,m)) genus2red(subst(P0,'t,3),3) \\ n > 0 odd, m k = 4; m = 10; n=2*k+1; P0=((x^2-t)+t^(m+1)*x)*((x^2-t)^2+t^(2*m+k+3)*x); do(P0, Strprintf("[2I*{%ld}-%ld}], p. 181",n,m)) \\ n, p > 0 n = 9; p = 8; P0=(x^2+t)*(x^2+t^(p+1))*((x-1)^2+t^(n-1)); do(P0, Strprintf("[II{%ld-%ld}], p. 182",n,p)) genus2red(subst(P0,'t,3),3) \\ n > 0 even k = 4; n=2*k; P0=x*((x^2-t^3)^2+t^(k+6)); do(P0, Strprintf("[III{%ld}], p. 182",n)) \\ n > 0 odd k = 4; n=2*k+1; P0=x*((x^2-t^3)^2+t^(k+5)*x); do(P0, Strprintf("[III{%ld}], p. 182",n)) \\ n, p, q > 0 n = 9; p = 8; q = 5; P0=(x^2+t^n)*((x-1)^2+t^p)*((x-2)^2+t^q); do(P0, Strprintf("[I{%ld-%ld-%ld}], pp. 182-183",n,p,q)) \\ n, p, q > 0 n = 9; p = 8; q = 5; P0=t*(x^2+t^n)*((x-1)^2+t^p)*((x-2)^2+t^q); do(P0, Strprintf("[I*{%ld-%ld-%ld}], pp. 183",n,p,q)) \\ n, p > 0, p even n = 9; k = 4; p=2*k; P0=((x^2-t)^2+t^(k+2))*((x-1)^2+t^(n-1)); do(P0, Strprintf("[II{%ld-%ld}], p. 183",n,p)) genus2red(subst(P0,'t,3),3) \\ n, p > 0, p odd n = 9; k = 4; p=2*k+1; P0=((x^2-t)^2+t^(k+2)*x)*((x-1)^2+t^(n-1)); do(P0, Strprintf("[II{%ld-%ld}], p. 183",n,p)) genus2red(subst(P0,'t,3),3) \\ n, p > 0 n = 9; k = 4; l = 0; p=2*k+l; P0=t*((x^2-t)^2+t^(k+2)*x^l)*((x-1)^2+t^(n-1)); do(P0, Strprintf("[II*{%ld-%ld}], p. 184",n,p)) \\ n, p > 0 n = 9; k = 4; l = 1; p=2*k+l; P0=t*((x^2-t)^2+t^(k+2)*x^l)*((x-1)^2+t^(n-1)); do(P0, Strprintf("[II*{%ld-%ld}], p. 184",n,p)) \\ n > 0 k = 4; l = 0; n=3*k+l; P0=(x^3-t)^2+t^(k+2)*x^l; do(P0, Strprintf("[III{%ld}], p. 184",n)) genus2red(subst(P0,'t,3),3) \\ n > 0 k = 4; l = 1; n=3*k+l; P0=(x^3-t)^2+t^(k+2)*x^l; do(P0, Strprintf("[III{%ld}], p. 184",n)) genus2red(subst(P0,'t,3),3) \\ n > 0 k = 4; l = 2; n=3*k+l; P0=(x^3-t)^2+t^(k+2)*x^l; do(P0, Strprintf("[III{%ld}], p. 184",n)) genus2red(subst(P0,'t,3),3) \\ n > 0 k = 2; l = 0; n=3*k+l; P0=t*((x^3-t)^2+t^(k+2)*x^l); do(P0, Strprintf("[III*{%ld}], p. 184",n)) genus2red(subst(P0,'t,3),3) \\ n > 0 k = 2; l = 1; n=3*k+l; P0=t*((x^3-t)^2+t^(k+2)*x^l); do(P0, Strprintf("[III*{%ld}], p. 184",n)) genus2red(subst(P0,'t,3),3) \\ n > 0 k = 2; l = 2; n=3*k+l; P0=(x^3-t)^2+t^(k+2)*x^l; do(P0, Strprintf("[III{%ld}], p. 184",n)) genus2red(subst(P0,'t,3),3) \\ Extras : p = 3 \e \\ Colin Stahlke, bug28 genus2red(-x^6-6*x^2-7,3) genus2red(-9*x^6+6*x^5-8*x^4-5*x^3+5*x^2-10*x+3,3) \\ M. Stoll, bug28 genus2red(3*x^6+3*x^4+3*x^3+x^2-5*x-5,3) \\ Colin Stahlke, bug28 genus2red(-3*x^6+6*x^5-1*x^4+6*x^3-6*x^2-1*x-6,3) \\ J. Mueller, bug28 genus2red((x^3+2*x+1)*(x^3+3^2*x^2+3^8),3) \\ A. Brumer, bug28 P=x^6+4*x^5-24*x^4-16*x^3-52*x^2-48*x; genus2red(P,3) P=x^6+4*x^5+24*x^4+32*x^3+56*x^2+48*x+24; genus2red(P,3) P=24*x^5+56*x^4+76*x^3+33*x^2-4*x-20; genus2red(P,3) P=-3*x^6+6*x^5-25*x^4+36*x^3-69*x^2+38*x-39; genus2red(P,3) \\ M. Stoll, bug28 P=-5*x^5+5*x^4+10*x^3-7; genus2red([P,1],3) P=-5*x^6-3*x^5-10*x^4-10*x^3-7; genus2red([P,1],3) P=3*x^5+5*x^4+5*x-4; genus2red([P,1],3) Q=x^2+x; P=-9*x^6+6*x^5-8*x^4-5*x^3+5*x^2-10*x+3; genus2red([P,Q],3) \\ M. Stoll, bug27 Q=x^3+1; P=-7*x^6+5*x^3+5*x^2-6*x+1; genus2red([P,Q],3) \\ #1596 genus2red(27*x^5 + 97*x^4 + 118*x^3 + 60*x^2 + 13*x + 1,3) \\ #1597 genus2red([-x^6 - 3*x^4 - 10*x^2 - 1,x],3) \\ #1597 genus2red([-60*x^6-203*x^5-291*x^4-244*x^3-129*x^2-41*x-7,x^3+x^2+x+1]) \\ #1597 genus2red(6*x^6+5*x^4+x^2+1,7) \\ #1597 genus2red([1,x^3-1]) genus2red(x^5+1/5, 5) genus2red(273*x^6-38933/5*x^5-4483763/4*x^4+371954149/10*x^3+569046245/4*x^2+12389355*x-42117075,5) \\ #1826 genus2red(177*x^6+126*x^5-63*x^4+72*x+84,3) \\ #2053 genus2red(3*(4*x^6 + 6*x^5 + 3*x^4 + 8*x^3 + 9*x^2 - 3), 3) genus2red(x^6+27,3) pari-2.11.2/src/test/in/nffactor0000644000175000017500000003246113447371554015102 0ustar billbilldefault(parisize,"16M"); do(T, P) = lift(nffactor(nfinit(T),P)[,1]); do(polcyclo(13,y),x^72-291*x^70+168*x^69+40380*x^68-48588*x^67-3528919*x^66+6672120*x^65+215657160*x^64-575538144*x^63-9642387423*x^62+34735086786*x^61+318475831783*x^60-1543992152304*x^59-7526047084203*x^58+51709921323996*x^57+110268119466273*x^56-1306863903654948*x^55-197687339387338*x^54+24340617020480994*x^53-37674206381844006*x^52-309388136734870296*x^51+1097175021601270233*x^50+1965430743178095924*x^49-17057741307681944498*x^48+12695705864721864408*x^47+149941210123858078557*x^46-449449010694960248724*x^45-360137445013361079753*x^44+4743771886303072354536*x^43-7957480107528139931362*x^42-20006312987061736459890*x^41+103127662005251951018025*x^40-57922725775374790826892*x^39-575374977336477060878406*x^38+1141042155363070337681952*x^37+2107623272811930164219492*x^36-8555883275792119671168984*x^35-6622038332271478648217502*x^34+67788499073804904961005264*x^33-62194621346216574281355513*x^32-298503076979390816950994616*x^31+935868776923024509133161567*x^30-602191893688026944562387144*x^29-2378403718028116295265005703*x^28+7144715267789671188060423636*x^27-8264313767410946129053876314*x^26-2988303993119955116599622124*x^25+36320303706133493815706370331*x^24-93405543373036036850518472592*x^23+137892731303549623166716872621*x^22-73374564495372153466268524626*x^21-180690507689854149951443988039*x^20+506199649638427572646328975856*x^19-511453665473658325356669209047*x^18-183193264910244539106552118338*x^17+1423840911419731272911578335897*x^16-2367314022969857609246689985844*x^15+2236677523353346112926136338695*x^14-1548489683091587051973217338168*x^13+2105049137205776145162583648404*x^12-4754348311294629767834593856064*x^11+7567806891220394207855512254933*x^10-7605431066578089163623568649610*x^9+3882625664788999249342771140339*x^8+1356469287400668040516453202076*x^7-3841355512345259545848813224621*x^6+2330504083587501732658867007532*x^5-169172628407290891217225606775*x^4-398965703199322569698936377044*x^3+198978398979453484569202793808*x^2-60597282938946837445378411698*x+12280639561039083425818958713) do(polcyclo(5,y),x^48+12*x^46+948*x^44+7200*x^42+152361*x^40+815832*x^38+9475380*x^36+44654004*x^34+299137536*x^32+1335241260*x^30+5029216452*x^28+15282825984*x^26+37737671337*x^24+79579803672*x^22+143658877428*x^20+222699104460*x^18+303698198961*x^16+348787956312*x^14+312863646960*x^12+212893847424*x^10+111407984496*x^8+43762394880*x^6+11836253952*x^4+1904684544*x^2+136048896) do(polsubcyclo(17,8,y),x^48-104*x^46+4664*x^44-122476*x^42+2137838*x^40-26567700*x^38+245144964*x^36-1725955872*x^34+9441692003*x^32-40611588644*x^30+138356971048*x^28-374714866240*x^26+807289826646*x^24-1380693858220*x^22+1866021172640*x^20-1978766780068*x^18+1630151673857*x^16-1029505301024*x^14+489498952012*x^12-170832297056*x^10+42133382284*x^8-6904507136*x^6+669868016*x^4-28899680*x^2+16) do(polsubcyclo(19,6,y),x^64-6384*x^62+18261761*x^60-31231019568*x^58+35925400902280*x^56-29635423138225800*x^54+18244443900381139917*x^52-8609789775431197305288*x^50+3173715440318358526295493*x^48-926253189958924421506713024*x^46+216130107574547887816493973792*x^44-40600173780591579547211667354912*x^42+6168621134132051706341715912515370*x^40-760139434277348135867991392951415744*x^38+76052955647065900426700689494084391434*x^36-6175311843554416772593815034596603661344*x^34+406137362468726923132369140307868626461744*x^32-21559959594011538596615817038079394912524336*x^30+919122010228667702998458013093798368177514170*x^28-31251399013676293208252728256910183010646331888*x^26+840017792466500823059432352741453680599704357258*x^24-17651171087877975905738341268934550365403253370816*x^22+285940694256111366646633973109729677687028435758880*x^20-3510138236669349338216717168753743720690200440965920*x^18+31970659328447652254136627725804141367170891626180389*x^16-210577501276259853380917767547980363666145460503950096*x^14+972633665701140285445722173171004563157651576027463941*x^12-3038789368329382179884462851269146550248145196800679728*x^10+6158927928896588396670590928896385649075890120481042824*x^8-7695135079270077790657693634058524039308535641860032904*x^6+5510293734552561962521574495431679567021222445632508873*x^4-1998778331104544904932086470347413669495129560426038280*x^2+273892744995340833777347939263771534786080723599733441) do(y^16-748*y^14+183362*y^12-18209312*y^10+854163776*y^8-19811731456*y^6+217053667328*y^4-963359277056*y^2+1401249857536,x^64-50520*x^62+1184742668*x^60-17134912892184*x^58+171302841202784230*x^56-1257730595773642457272*x^54+7035168717087126283039868*x^52-30701149599207543908253060456*x^50+106209876041363261331175274376961*x^48-294437498300554938723628131780900528*x^46+658747632370852789155278036118795891376*x^44-1194508299658559259423544698671941624911936*x^42+1758886106345358997541429698467814358261692768*x^40-2102877763749659939135348751421310839041552295168*x^38+2037272869739882513058383232251947632400144748327680*x^36-1593244672706602785431833797822694649876503949099971584*x^34+1000137401948528280332750479657406431558467421878362177792*x^32-500163144667908835632768747437877749311388525989506418016256*x^30+197386643425666396587295586758946216300889646426384501395505152*x^28-60764991565332609893728829321665731738637757708625749066895851520*x^26+14391680825163014577680716072706067747656540117078764576362349133824*x^24-2579614931575491289251668514169821364409673054271152939186037020688384*x^22+343089307498773969742537952871359998792597096472804803564329469006053376*x^20-33039893809399713739300133477660888984993965585329459081212907387885715456*x^18+2232207983615195492545494908634867604311043135572503317867045868579149840384*x^16-101424324951708207798235121163034156328923938680623314497489525231592962785280*x^14+2924360883858624736764622501847786486366632522081726107231999581887779150233600*x^12-49361130671745243582144295846906126266126621338339076133495563142930969537806336*x^10+439086453618923969602036267436177792533605154882821831371393950663185250364948480*x^8-1791241595903032942764035441499088453133177154876529243608326027299172423825358848*x^6+3156683219740128500900617761806000080676491013147893106666462267204557337199116288*x^4-2047559682560580731342531379502232338263001052780076721919148124626016913223319552*x^2+364046770867177439711105777657339121207381033680019800170419997640962734592884736) do(y^20+1161*y^16+357096*y^12+15694096*y^8+129931776*y^4+26873856,x^20+1219*x^16+25560*x^14+1352565*x^12+15766260*x^10+468310924*x^8-1266123120*x^6+27117441616*x^4+101145350400*x^2+914700960000) do(y^3+y^2+2,x^24+69) do(y^4+7^2,x^28-14*x^24+20321*x^20+166992*x^16+1171296*x^12+1342208*x^8-5005056*x^4+3211264) setrand(1);do(y^16-24*y^14+196*y^12-696*y^10+1118*y^8-840*y^6+292*y^4-40*y^2+1,x^32-208*x^30+12736*x^28-330032*x^26+4326444*x^24-32221712*x^22+147532904*x^20-437660272*x^18+869634612*x^16-1179150112*x^14+1097619208*x^12-696893680*x^10+295476664*x^8-80251024*x^6+12946192*x^4-1075648*x^2+33614) setrand(29);do(y^16+6*y^8+1,x^64+112*x^60+4672*x^56-61472*x^52+1722640*x^48-19382720*x^44+137146112*x^40+89961600*x^36+762162272*x^32-7723483904*x^28+17460562944*x^24+100233636352*x^20+74611011840*x^16-74722169856*x^12+20300812288*x^8+1358714880*x^4+21381376) setrand(6);do(y^16+2,x^64+192*x^62+17568*x^60+1019520*x^58+42131676*x^56+1319651424*x^54+32559096528*x^52+649228312512*x^50+10651553826426*x^48+145639438552224*x^46+1674922821206832*x^44+16307859539653056*x^42+135023677732167696*x^40+953248899971965824*x^38+5745239175305568960*x^36+29556064271185194240*x^34+129595725382952883843*x^32+483002100692576612640*x^30+1523870714370199019760*x^28+4047489983524093705152*x^26+8985812828648862019536*x^24+16525310345394167002752*x^22+24893927149975603242048*x^20+30294355815129821928192*x^18+29274561574319887883226*x^16+21987801771104340121824*x^14+12494344840480632094992*x^12+5187763623118143696192*x^10+1502211081063677383836*x^8+283567347515314680480*x^6+31146155438884525872*x^4+1543354925530003776*x^2+8057044481403681) do(y^32+28*y^24+70*y^16+28*y^8+1, x^16-72*x^12-280*x^8+288*x^4+16) S=x^5-5*x^3+4*x-1; T=y^15-25*y^13+202*y^11-16*y^10-665*y^9+115*y^8+916*y^7-160*y^6-537*y^5+80*y^4+119*y^3-16*y^2-8*y+1; lift(nfroots(T,S)) S=polsubcyclo(97,12); lift(nfroots(subst(S,x,y),S)) S=x^9+9*x^8+36*x^7+69*x^6+36*x^5-99*x^4-303*x^3-450*x^2-342*x-226; T=y^9-15*y^6-87*y^3-125; lift(nffactor(T,S)) lift(nffactor(nfinit(y^2+1),(x-y)^3*(x^2+y)^4*(x^3-y*x+y)^5)) lift(factor(Mod(y,y^2+1)*x^2 + y)) lift(nffactor(nfinit(y^2+1),Mod(y,y^2+1)*x^2 + y)) factor((2*x+1)^2*(x+1)^3) {P=x^9 - 9*x^7 + 27*x^5 - 30*x^3 + 9*x - 2/7; K= a^27-63*a^25+1701*a^23-25914*a^21+246960*a^19-700*a^18-1543941*a^17+21168*a^16+6465060*a^15-254016*a^14-18197865*a^13+1560552*a^12+34034175*a^11-5321988*a^10-40965225*a^9+10224144*a^8+29604330*a^7-10606932*a^6-10927980*a^5+5186160*a^4+1256409*a^3-777924*a^2+21952; #nfroots(K,P)} \\ no factor #930 nf = nfinit(y^16-24*y^12+80*y^10-172*y^8+192*y^6-112*y^4+32*y^2+4); P = x^16-24*x^12+80*x^10-172*x^8+192*x^6-112*x^4+32*x^2+4; do(nf, P) nfroots(nf, P*(x^2+y)*(x^2+2*y)) \\ Bug #959 P=x^36+12*x^35-900*x^34-585*x^33+232905*x^32-1232184*x^31-15039873*x^30+110066100*x^29+430062960*x^28-3889034165*x^27-6885371553*x^26+72277665264*x^25+75990228525*x^24-788853282390*x^23-669954405945*x^22+5321235823803*x^21+4528671343041*x^20-22706777648475*x^19-20887787332600*x^18+62214414690960*x^17+62136364754205*x^16-111213087488775*x^15-118854042392850*x^14+131983619890275*x^13+148593402314775*x^12-105099439356375*x^11-122927027339625*x^10+56029221057500*x^9+67224101142000*x^8-19578944328750*x^7-23826919393125*x^6+4261743915000*x^5+5216451275625*x^4-517952334375*x^3-635253609375*x^2+26484140625*x+32625390625; #nfgaloisconj(nfinit([P,nfbasis([P, factor(poldisc(P), 175069)])]),1) \\ Bug #1006 #do(y^24-12*y^23+72*y^22-286*y^21+849*y^20-2022*y^19+4034*y^18-6894*y^17+10182*y^16-13048*y^15+14532*y^14-13974*y^13+11365*y^12-7578*y^11+4038*y^10-1766*y^9+762*y^8-408*y^7+236*y^6-126*y^5+69*y^4-38*y^3+18*y^2-6*y+1,8*x^9+42*x^6+6*x^3-1) \\ Bug #980 P=x^6 - x^5 - 76*x^4 + 60*x^3 + 1140*x^2 + 1155*x - 695 Q=a^36 - 140*a^34 + 8402*a^32 - 288950*a^30 + 6406703*a^28 - 97539585*a^26 + 1059042259*a^24 - 8396309325*a^22 + 49297808195*a^20 - 215811263825*a^18 + 704643601819*a^16 - 1705347924285*a^14 + 3017070472643*a^12 - 3809285900925*a^10 + 3299709349267*a^8 - 1836758642090*a^6 + 585303753211*a^4 - 85409835875*a^2 + 3969153125 lift(nfroots(Q,P)) \\ Bug #1023 do(a^2+13,polcyclo(13,13*x^2)) \\ Bug #1070 do(y^2-5,x^5-x^4-7*x^3+x^2+7*x-3) \\ Bug #1075 lift(nffactor(polcyclo(21,y), x^2-y^7)) \\ Bug #1132 do(y^4-y^2+1, 3*x^3+(-12*y^3+6*y)*x^2-11*y^2*x+(2*y^3-4*y)) \\ Bug #1141 do(y^2-y+1, (x-(1+y)/3)^2*(x+2*(1+y)/3)) \\ Bug #1142 lift(nffactor(3*y^2+1, 3*x^2+1)) lift(nfroots(3*y^2+1, 3*x^2+1)) \\#1207 lift(nffactor(t^6-6*t^5-3298534883316*t^4+13194139533310*t^3+3626777458830693384585198*t^2-7253554917667983838937052*t-1329227995784915872903826851489644559,x^3-3)) \\#1276 pol=1225*x^6+1750*x^5-21675*x^4-380*x^3+110180*x^2-129720*x+48771;lift(factorback(factornf(pol,subst(pol,x,y)))) \\#1438 factor((x^2-1)*(x^2-2)*(x^2-5)) \\#1446 factor((x^80-1)/(x-1)) \\also exercises Flx_extgcd above half-gcd threshold test(T,p)= { v=polhensellift(T,lift(factormod(T,p)[,1]),p,10); valuation(T-factorback(v),p); } \\also exercises FqX_extgcd above half-gcd threshold test(polcyclo(503),3) test(polcyclo(211),18446744073709551667) do(y^2-22,x^2+926246528884912528275985458927067632*y-4344481316563541186659879867597013188) nfroots(a^2+1,x^2) nfroots(,x+1/2) nfroots(,x^2-1/4) nfroots(,(x+1)*(x^2+1)) \\#1841 K = nfinit (y^4 + 57*y^2 + 661); P = Mod((1/11*y^2 + 56/11)*x^2 + x + 3, K.pol); nfroots (K, P) nfroots (K, P / pollead(P)) nfroots (K, P / (pollead(P)*y)) \\ #1956, #1957 nfroots(a^2-a+3,x^2+Mod(84*a-248/3,a^2-a+3)*x+Mod(-1440*a-73760/9,a^2-a+3)) nfroots(a^2-a+3,a*(x^2-4)) nffactor(y^2+7, (11*x)^4 - 10*(11*x)^2 + 1) \\ #2009 nffactor(y^8-y^6+y^4-y^2+1,x^4-1) \\ #2013 #nffactor(y^16+8, x^128+38963*x^120+443415855*x^112-3190514348*x^104+1973183073491*x^96+12244232235795*x^88+1921165187202898*x^80+36262111346728415*x^72+203445143688320136*x^64+36262111346728415*x^56+1921165187202898*x^48+12244232235795*x^40+1973183073491*x^32-3190514348*x^24+443415855*x^16+38963*x^8+1)[,2] \\ #2083 f=x^20-15*x^19+70989*x^18-1646113*x^17+3890074283*x^16-199035549796*x^15+203804256639644*x^14-10657741285726487*x^13+9779630086245476401*x^12-457685358591718595073*x^11+211985887298317287648516*x^10-13621268697129972225420327*x^9+3065457104886066023133986949*x^8-28110542105571309419720191704*x^7+34539665971867983088754678645580*x^6-1061445386217881235978009629856081*x^5+498395492968339432558541006017143039*x^4-15789239186368833250097534490638459475*x^3+1774782276941552319212370439848636475557*x^2+4469330093535998306027448264353195140536*x+4277406750726325717327241436124994515881; g=y^20-5*y^19-497395*y^18+43617925*y^17+92084825461*y^16-13577322967760*y^15-7694013534722665*y^14+1430561593275815035*y^13+321534254513790999596*y^12-70299145498412320125190*y^11-6894702144208513885815805*y^10+1786517983436254067840917780*y^9+72426826805051978098685836211*y^8-24338190557208310471662504670520*y^7-255231848841911020332784180965840*y^6+172908549561723112381441893500998965*y^5-1042438501414486010172621550211101919*y^4-555813027721813935650430329326884907050*y^3+6754721428610694790490649672796107843280*y^2+470810707124413968773034018937652067163520*y+3896560262532181966922924457358135376686480; apply(poldegree, nffactor(g, f)[,1]) \\ Errors, keep at end of file polhensellift(x^2+x+1,[x+a,x+a+1],2,10) pari-2.11.2/src/test/in/ellpadic0000644000175000017500000000412413326135265015041 0ustar billbilldefault(parisize,"20M") e=ellinit([1,-1,1,-1,-14]); E=ellinit([0,0,0,-e.c4/48,-e.c6/864]); P=[1,-1/4;0,1]; { forprime(p=3,40,if(p==17,next); A=ellpadicfrobenius(e,p,10); B=ellpadicfrobenius(E,p,10); if(P*B!=A*P,error(p))); } Ep=ellinit(E,O(3^5)); [ellintegralmodel(Ep,&v)[1..5],v] elllocalred(Ep) elllocalred(ellchangecurve(Ep,[3,0,0,0])) elllocalred(ellchangecurve(Ep,[1/3,0,0,0])) E=ellinit([1,-1,1,0,0]);P=[0,0]; ellpadicheight(E,2,4, P) ellpadicheight(E,3,4, P) ellpadicheight(E,5,4, P) E=ellinit([0,-1,1,-10,-20]);P=[5,5]; ellpadicheight(E,19,6, P) ellpadicheight(E,19,0, P) Ep=ellinit([0,-1,1,-10,-20], O(11^5)); [ellap(Ep), ellap(Ep,11)] [ellcard(Ep), ellcard(Ep,11)] [ellgroup(Ep), ellgroup(Ep,11)] [ellissupersingular(Ep), ellissupersingular(Ep,11)] ellpadics2(Ep,11,5) E=ellinit([1,0,1,-6,4],O(5^5)); ellissupersingular(E) lift(ellpadicfrobenius(E,5,5)) ellinit([1,1,1,1,1],O(2^2)).group ellinit([0,2],O(2^2)).group ellinit([1,1,2,1,1],O(2^2)).group ellinit([1,3,1,2,2],O(3^2)).group ellinit([1,2,2,2,3],O(3^2)).group ellinit([1,1,3,1,3],O(3^2)).group ellinit([3,4],O(5^2)).group ellinit([0,5],O(5^2)).group ellinit([2,2],O(5^2)).group E=ellinit([0,0,1,-4,2]);P=[-2,1]; ellpadicheight(E,3,5, P) P2 = ellmul(E,P,2); ellpadiclog(E,3,5,P) ellpadiclog(E,3,5,P2) E=ellinit([0,0,1,-7,6]); P=[-2,3]; P2=ellmul(E,P,2); Q=[-1,3]; Q2=ellmul(E,Q,2); R=[0,2]; ellpadicheight(E,2,5, P,Q2) ellpadicheight(E,2,5, P2,Q) M=ellpadicheightmatrix(E,5,5, [P,Q,R]); lift(M) ellpadicheight(E,3,5, P)*[1,2]~ ellpadicheight(E,3,5, P,Q)*[1,2]~ matdet(M[1]) matdet(M[2]) E=ellinit([-577/48,14689/864]); ellpadics2(E,43,6) E=ellinit([1,0,1,-460,-3830]); ellpadics2(E,5,6) E=ellinit([0,0,1,-1,0]); \\ 37a1 ellpadics2(E,5,6) ellpadicbsd(E,7,10) ellpadicbsd(E,37,10) E=ellinit([0,1,1,-7,5]); ellpadicbsd(E,7,5) ellpadicregulator(E,7,5,[[-1,3]]) ellpadicbsd(E,7,5,-4) E=ellinit([1, -1, 1, 0, 0]); ellpadicfrobenius(E,5,7) E=ellinit([0,0,1,-4,2]); ellpadicfrobenius(E,3,5) \\ ERRORS keep at end of file ellap(Ep,2) ellpadics2(Ep,2,5) ellcard(Ep,2) ellgroup(Ep,2) ellissupersingular(Ep,2) elllocalred(Ep,2) ellgroup(ellinit([5^6,5^6]),5,1) pari-2.11.2/src/test/in/variable0000644000175000017500000000063513201017466015046 0ustar billbillv=[1,O(3),x,O(x),Mod(y,y^2+1),1/y,[y,z],Mat(z),List(),List([y,z])]; { for(i=1,#v, print(iferr(variable(v[i]), E,E)) ) } variable() varhigher("y"); tt=varlower("y"); variable() zz=varhigher("y",x); variable() varhigher("y",zz); variable() varlower("y",zz); variable() varlower("y",tt); variable() varlower("tt",y); varhigher("y",y); variable() varhigher("zzz",y);1/0 variable() variables([v,tt,zz]) variables() pari-2.11.2/src/test/in/galoischartable0000644000175000017500000000354113326135265016412 0ustar billbill\\ package: galpol inn(len, c1, c2, f) = simplify(lift(sum(i=1,#len,len[i]*c1[i]*subst(c2[i],y,1/y))*Mod(1,f))); testchar(G, n = poldegree(G.pol))= { my(cl = galoisconjclasses(G)); my(len = apply(length, cl)); my([ct,e] = galoischartable(G)); my(dim = simplify(ct[1,])); my(one = vector(#dim,k,1)); my(f = polcyclo(e,y)); if (#len!=#dim, error("dim1")); if (sum(i=1,#dim,dim[i]^2)!=n,error("dim2")); if (sum(i=1,#len,len[i])!=n,error("dim3")); M=matrix(#len,#dim,i,j,inn(len,ct[,i],ct[,j],f)); if(M!=n*matid(#len),error("columns")); M=matrix(#len,#dim,i,j,inn(one,ct[i,],ct[j,],f)); if(!matisdiagonal(M),error("lines")); for(i=1,#len,if(M[i,i]<0,error("diag"))); } { for(i=1,16, for(j=1,galoisgetpol(i), [pol,den] = galoisgetpol(i,j,1); gal = galoisinit(pol,den); testchar(gal); )); } \\#1931 G=galoisinit(x^24-24*x^22+253*x^20-1540*x^18+5984*x^16-15488*x^14+27026*x^12-31448*x^10+23540*x^8-10528*x^6+2416*x^4-192*x^2+1); setrand(211); testchar(G) dopol(G)= { my([T,o]=galoischartable(G)); for(i=1,#T,printsep(":", T[,i], galoischardet(G,T[,i],o), galoischarpoly(G,T[,i],o))); } G=galoisinit(x^10-2*x^9-20*x^8+2*x^7+69*x^6-x^5-69*x^4+2*x^3+20*x^2-2*x-1); dopol(G) {G = [Vecsmall([1, 2, 3, 4, 5]), Vecsmall([1, 5, 4, 3, 2]), Vecsmall([2, 1, 5, 4, 3]), Vecsmall([2, 3, 4, 5, 1]), Vecsmall([3, 2, 1, 5, 4]), Vecsmall([3, 4, 5, 1, 2]), Vecsmall([4, 3, 2, 1, 5]), Vecsmall([4, 5, 1, 2, 3]), Vecsmall([5, 1, 2, 3, 4]), Vecsmall([5, 4, 3, 2, 1])];} dopol(G) G=[[Vecsmall([28,40,13,30,4,19,22,7,8,32,25,38,33,16,29,18,14,24,21,9,3,1,11,5,36,23,35,10,34,20,2,37,27,6,12,41,31,42,15,17,39,26]),Vecsmall([3,38,1,42,21,8,12,6,11,29,9,7,17,23,30,34,13,35,31,33,5,41,14,36,37,28,32,26,10,15,19,27,20,16,18,24,25,2,40,39,22,4])],Vecsmall([21,2])]; testchar(G, 42); pari-2.11.2/src/test/in/sumdiv0000644000175000017500000000240613457610667014605 0ustar billbilln = 10!; fa = factor(n); sumdiv(n, d, eulerphi(d)) sumdiv(n, d, d^2) sumdiv(fa, d, eulerphi(d)) sumdiv(fa, d, d^2) sumdivmult(n, d, eulerphi(d)) sumdivmult(n, d, d^2) sumdivmult(fa, d, eulerphi(d)) sumdivmult(fa, d, d^2) sigma2(x) = sigma(x,2); sigma3(x) = sigma(x,3); sigma_1(x) = sigma(x,-1); core2(x) = core(x,1); fun = [ispowerful, moebius, core, core2, omega, bigomega, eulerphi, numdiv, sigma, sigma2, sigma3, sigma_1]; for(i=1,#fun, print(fun[i](fa))) v = concat([-50..-1], [1..50]); fav = apply(factor, v); { for (i=1,#fun, my(f = fun[i]); for (j=1,#v, if (f(v[j]) != f(fav[j]), error([f,v[j]])))) } \\ allow 0 fun0 = [ispowerful, core, core2, eulerphi]; { for (i=1,#fun0, my(f = fun0[i]); if (f(0) != f(factor(0)), error([f,0]))) } test(fa)= for(i=1,#fun, print(iferr(fun[i](fa),E,E))); test(0) test(factor(0)) test(-2) test(factor(-2)) fa = factor(1); for(i=1,#fun, print(fun[i](fa))) divisors(fa) fa = factor(0); ispowerful(fa) core(fa) core2(fa) divisors(fa) fa = [5!, factor(5!)]; core2(fa) divisors(fa) n = x^2*(x+1)^3*(x+2)^5; fa = factor(n); sumdiv(n, d, d) sumdiv(fa, d, d) sumdivmult(n, d, d) sumdivmult(fa, d, d) \\#1664 divisors([1,2]) \\#1702 moebius(factor(18)) \\ core would destroy its input R = 762104756900678410271641; core(R); R pari-2.11.2/src/test/in/nf0000644000175000017500000001105313447371554013675 0ustar billbilldefault(realprecision,38); default(parisize,"60M"); setrand(1429412696);bnfinit(x^2+29051222508*x-12).clgp setrand(1); bnfinit(x^8 + 12*x^6 + 30*x^4 + 24*x^2 + 4).reg setrand(1); bnfinit(x^4 - 3*x^2 + 49).reg bnfinit(x-1/2).clgp bnfinit(x^2-1/2).clgp bnfinit(x^2+2).tu \\ #2027 nfinit(factor(polzagier(9,5))[2,1],2).disc nfinit(Pol([1,0,42,112,728,3248,14224,3392,289478,-804944,2966908,-11015200,17342836,-108601584,381107816,-1679988352,6252186465,-14812800240,28868620970,-27997506768,-33428758132,98285772160,-51592356424,-39975211584,55983352320,-24670808064,5337884160,-733917184,87744512])).disc setrand(3);bnfinit(x^2-(1130481^2+4)).clgp setrand(2);bnfinit(x^4 - x^3 + 63*x^2 - 22*x + 1004).clgp setrand(1);bnfinit(x^8 - 8*x^6 + 38*x^4 - 143*x^2 + 121).clgp bnfcertify(bnfinit(x^2-40!)); bnfcertify(bnfinit(x^8-2)); \\#1736 setrand(1);bnfinit(x^3-87156*x^2-6728799*x-456533).cyc nf=nfinit(y^5-4*y^3+2*y+11); v = [4/3, -1, y^2+y+1, Mod(y,nf.pol),Mod(1/2,nf.pol),[1,2,3,4,5]~]; for (i=1, #v, print( nfelttrace(nf,v[i]) )) for (i=1, #v, print( nfeltnorm(nf,v[i]) )) nfeltnorm(nf,[3,3;y,2]) for (i=1, #v, print( nfbasistoalg(nf,v[i]) )) for (i=1, #v, print( nfalgtobasis(nf,v[i]) )) funs = [nfeltadd, nfeltdiv, nfeltdiveuc, nfeltdivrem, nfeltmod, nfeltmul]; try(f) = for (i=1, #v, for (j=1,#v, print( f(nf, v[i],v[j])) )) for (i = 1, #funs, try(funs[i])) nfisincl(nfinit(x-1),y) p=x^2+3;nfbasis([p, factor(poldisc(p))]) \\#1253 k=bnfinit(z^2+19*z+6,1); bnfisunit(k,k.fu[1]^2) \\#1158 nf=nfinit(x^2+x+1); nfinit(nf) \\#1180 setrand(1);quadclassunit(572).no bnf=bnfinit(x^3-2); S=bnfsunit(bnf,idealfactor(bnf,2*3*5*7)[,1]); bnfissunit(bnf,S,x) bnfissunit(bnf,S,x+2) bnfissunit(bnf,S,x+100) bnfisunit(bnf, x+100) \\#1247 setrand(1);bnfinit(x^2+1635847).no \\#1381 K = bnfinit(x^2+23); L = bnrdisclist(K, 10); s = L[2]; bnfdecodemodule(K, s[1][1]) default(realprecision,19); K=bnfinit(x^5-x^4+x^3+100*x+20,1); A=idealpow(K,idealprimedec(K,5)[2],150); bnfisprincipal(K,A); default(realprecision,173); K=nfnewprec(K); bnfisprincipal(K,A) l=ideallist(K,4,0);ideallistarch(K,l,[1]) l=ideallist(K,4,3);L=ideallistarch(K,l,[1]) bnrdisclist(K,l) bnrdisclist(K,L) bnrdisclist(K,4,[1]) K=nfinit([x^5-x^4+x^3+100*x+20,[1,x,x^2-x,1/2*x^4-1/2*x^3+1/2*x^2+40,x^3-x^2+x]]); K.index K=nfinit([x^5+9*x^4+851*x^3+18890*x^2+252376*x+529348, 39820]); nfcertify(K) nf=nfinit( [ x^7 + 2539107, [43] ] ); \\ #1973 g=polcyclo(13); f=x^12-2*x^11+17*x^10-73*x^9+198*x^8-578*x^7+1533*x^6-3404*x^5+5716*x^4-8260*x^3+18652*x^2-25578*x+15601; nfisincl(f,g) \\#1921 K=nfinit('x^2-2);L=nfinit('x^4-2); nfisincl(K,L) nfisincl(K.pol,L) nfisincl(K,L.pol) nfisincl(x^3-21*x-35,x^6-48*x^4-56*x^3+453*x^2+840*x+62) \\#2023 nfisincl(x^3-11*x^2+42*x-49,polcompositum(x^3-x-1,x^7-x-1)[1]) nfisincl(x^3-11*x^2+42*x-49,x^6+12*x^5+60*x^4+80*x^3-1860*x^2-12108*x-18821) \\#2041 nfisincl(y^2 + 1, z^4 + 1) nfisincl(x^5-x^4+x^3-2*x^2+3*x-1,x^20+x^15+x^10+x^5+1) \\#2022 nfisisom(K,x^2-8) nfisisom(x^2-8,K) nfisisom(nfinit(y^2 + 1), z^2 + 1) K = nfinit(x^2 + 1); nfisisom(K, y^2 + 1); K.pol \\#1631 setrand(1);bnfinit(x^16-48*x^14+934*x^12-9632*x^10+57251*x^8-198568*x^6+386172*x^4-377776*x^2+137288).no K = nfinit(y^2-5); L = nfcompositum(K, x^5-y, polcyclo(5)) L = nfcompositum(K, x^5-y, polcyclo(5), 1); [R,a,b,k] = L[1] a^5 - y liftall(b^5) L = nfcompositum(K, x^5-y, x^5-y) L = nfcompositum(K, x^5-y, polcyclo(3),2) L = nfcompositum(K, x^5-y, polcyclo(3),3) nfcompositum(nfinit(y),x,x^2+x+1,3) p=10^62+447; q=10^42+63; nf=nfinit([polcompositum(x^2-p,x^2-q,2), [2,p,q]]); idealprimedec(nf,25339)[1].gen \\ overflow in get_norm \\#1777 nfcompositum(nfinit(y-1),x^3-2,x^3-1) \\#1796 nfcompositum(bnfinit(y),x^3-2,x^3-1) \\ oo loop in 2.9 K=bnfinit(x^2+2323); P=idealprimedec(K,23)[1]; bnfisprincipal(K,P) \\ #2054 D = 1460939943556665662782863549; K = nfinit([x^2-D,[3,7,1586327]]); setrand(426507128); bnfinit(K,,[0.132,0.15]); \\ test old-style nf.zk K=nfinit(x^2+23); K[7] /= 2; nfbasistoalg(K,[0,1]~) nfalgtobasis(K,x) K.zk nfinit(x, 3)[2] nfinit(1/2*x + 3/5, 3)[2] \\ ERRORS: keep at end of file nfinit([y^3+2,[1,x]]) nfinit([y^3+2,[1,x,x^2]]) nfinit([y^3+2,[1,y^5,y]]) nfdisc([y^2+2,matid(3)]) nfdisc([2*y^2+1,matid(3)]) nfdisc([y^2+2,""]) nfnewprec(x) nfnewprec(quadgen(5)) nfnewprec(vector(5)) nfnewprec(vector(6)) nfnewprec(vector(8)) nfnewprec(vector(9)) nfnewprec(vector(16)) nfcompositum(nfinit(x-1),x^3-2,x^3-1) nfcompositum(nfinit(x^2+1),x^3-2,x^3-1) nfcompositum(nfinit(x-1),y^3-2,y^3-1) nfcompositum(bnfinit(x),x^3-2,x^3-1) nfisincl(y^2 + 1, z^4 + z^2 + 1) nfisisom(x,x^0) nf=nfinit('a^2+1); idealhnf(nf,3,('a^2+1)*Mod(1,3)) nfalgtobasis(nf,['a,'a]~) pari-2.11.2/src/test/in/bern0000644000175000017500000000034413326135265014212 0ustar billbillbernfrac(0); bernfrac(1); for(k = 1, 20, print(bernfrac(k))); for(k = 0, 5, print(bernpol(k))); bernfrac(-1) bernreal(-1) bernpol(-1) bernvec(30) default(realprecision,38); bernreal(30) bernreal(202) localprec(57); bernreal(30) pari-2.11.2/src/test/in/qf0000644000175000017500000000263213201017466013666 0ustar billbillqfgaussred([0,7,2,3; 7,0,6,8; 2,6,0,9; 3,8,9,0]) Q=[2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1;-1,2,1,1,1,1,1,1,1,1,1,1,1;-1,1,2,1,1,1,1,1,1,1,1,1,1;-1,1,1,2,1,1,1,1,1,1,1,1,1;-1,1,1,1,2,1,1,1,1,1,1,1,1;-1,1,1,1,1,2,1,1,1,1,1,1,1;-1,1,1,1,1,1,2,1,1,1,1,1,1;-1,1,1,1,1,1,1,2,1,1,1,1,1;-1,1,1,1,1,1,1,1,2,1,1,1,1;-1,1,1,1,1,1,1,1,1,2,1,1,1;-1,1,1,1,1,1,1,1,1,1,2,1,1;-1,1,1,1,1,1,1,1,1,1,1,2,1;-1,1,1,1,1,1,1,1,1,1,1,1,2]; Q[3,7] += 1.25; Q[7,3] += 1.25; qfsign(Q) Q=[8,4,4,4,4,4,4,4,4,4,4,4;4,8,4,4,4,4,4,4,4,4,4,4;4,4,8,0,0,0,3,0,0,0,0,0;4,4,0 ,8,4,4,1,4,4,4,4,4;4,4,0,4,8,4,4,4,4,4,4,4;4,4,0,4,4,8,4,4,4,4,4,4;4,4,3,1,4,4,8 ,4,1,1,1,1;4,4,0,4,4,4,4,8,4,4,4,4;4,4,0,4,4,4,1,4,8,4,4,4;4,4,0,4,4,4,1,4,4,8,4 ,4;4,4,0,4,4,4,1,4,4,4,8,4;4,4,0,4,4,4,1,4,4,4,4,8]; qfminim(Q,,0,2)[1] qfrep(Q,16) qfrep(Q,8,1) qfminim(Q,,,1) qfminim(Q,8,,1) qfminim(Q,4,,1) qfminim([;],4,,1) qfminim([;],4,,2) qfminim(matid(2),0,1,2) qfminim(matid(2),0,1,1) qfminim(matid(2),0,1,0) L=[360815,2283021;-316840,2566404]; qfminim(L~*L,10^16)[2] qfminim(L~*L,10^16,,2)[2] forqfvec(v, [3,2;2,3], 3, print(v)) forqfvec(v, [3,2;2,3],, print(v)) forqfvec(v,[;],3,) x=[1,2,3]~; y=[-1,0,1]~; qfeval(,x) q=[1,2,3;2,2,-1;3,-1,0]; qfeval(q,x) qfeval(,x,y) qfeval(q,x,y) M=[1,2,3;4,5,6;7,8,9]; qfeval(,M) qfeval(q,M) qfeval(,1) qfeval(,1,1) qfeval(Mat(1),x) qfeval(Mat(x~),x) qfeval(,1,1) qfeval(,[1],[1,2]) qfeval(q,[1,2],[1,2]) qfeval(Mat([1,2]),[1,2],[1,2]) qfeval(1,1) pari-2.11.2/src/test/in/prime0000644000175000017500000000121113457566440014402 0ustar billbilltest(N)= { default(primelimit, N); for (b=10, 20, print1(prime(2^b), " ")); for (b=10, 26, print1(primepi(2^b), " ")); } test(10^6); test(10^8); primepi(2^32) precprime(1) primepi(2750160) \\ #1855 primes(50) primes([-5,5]) primes([10,20]) primes([2^32-100,2^32+100]) primes([2^64-100,2^64+100]) #primes([2^50,2^50+200000]) #primes([10^7, 10^7+10^6]) #primes([2^1023+5000, 2^1023+7000]) nextprime(2^32-1) nextprime(2^64-1) nextprime(2.5) precprime(2.5) \\ Errors, keep at end of file \\#1668 primes([1,Pol(2)]); nextprime(x) precprime(x) \\#2113 Cannot test: the test would not finish before end of universe. \\\p520 \\primepi(Pi*10^100) pari-2.11.2/src/test/in/ideal0000644000175000017500000000753513455056357014362 0ustar billbillQi = nfinit(x^2+1); idealintersect(Qi,0,1) Q = nfinit(y); idealaddtoone(Q,1,[;]) idealaddtoone(Q,2,[;]) idealaddtoone(Q,[;],[;]) idealaddtoone(Q,[;],1) idealaddtoone(Q,[1,[;]]) idealaddtoone(Q,[1,[;],Mat(1/2)]) zQ = idealstar(,4); ideallog(Q,2,zQ) z=znstar(6,1); z.clgp ideallog(,0,z) ideallog(,2,z) ideallog(,3,z) ideallog(Q,3,z) ideallog(,3,zQ) p=19;N=19^4;z=znstar(N,1);g=Mod(z.gen[1],N); for(i=1,1000,if (i%p && g^ideallog(,i,z)[1] != i, error(i))) z=znstar(3120,1); Mat(vector(#z,i,znlog(z.gen[i],z))) nfisideal(Qi,matdiagonal([6,12])) P = idealprimedec(Qi,2)[1]; idealprincipalunits(Qi,P,10) idealprincipalunits(Qi,P,1) idealintersect(Qi, 1/2,1/2) ideallog(Q,1/2,idealstar(Q,3,1)) idealdiv(Qi,7*x-1,3*x+1,1) K=nfinit(x^2-236*x+13384);\\ Q(sqrt(60)), in disguise idealhnf(K, qfbprimeform(60,2)) K=nfinit(x^3-2); u=nfalgtobasis(K,x);v=nfalgtobasis(K,x^2); idealhnf(K,Mat([u,v])) idealhnf(K,1/4,1/6) idealhnf(K,4,[6,0,0]~) idealhnf(K,2,1/6) idealhnf(K,1/3,u/2) idealhnf(K,u,v/2) P = idealprimedec(K,5); idealval(K,P[1],P[2]) idealval(K,P[2],P[1]) idealval(K,P[2],P[2]) P[1][2] += 5; idealval(K,P[1],P[1]) idealmul(K,P[1],P[1].gen[2]) idealmul(K,[2,1;0,1],[2,1;0,1]) idealmul(K,matid(4),matid(4)) idealnorm(K,P[1]) idealinv(K,Mod(x,K.pol)) idealinv(K,Mod(x-1,K.pol)) idealinv(K,2) idealinv(K,1) idealpow(K,idealhnf(K,x),-2) v=[1,1/2,x,Mod(x,K.pol),P[1],[;],Mat(1),vector(5),[1,2,3;4,5,6;7,8,9],[1,2,3;0,4,5;0,0,6],I]; for(i=1,#v, if(!nfisideal(K,v[i]),print(i))) idealred(K,2) idealred(K,[2,[;]]) idealred(K,[2,factor(1)]) k=nfinit(polcyclo(5)); idealfactor(k,101,100) idealfactor(k,2*101,100) idealfactor(k,101/103,100) idealfactor(k,101/(2*103),100) idealfactor(k,2^4*[0,1,0,0]~,100) nf=nfinit(x^2+x+1); p = 67452192952521724999; pi = idealprimedec(nf,p)[1]; q = 762234946175168528650011228121; qi = idealprimedec(nf,q)[1]; f=idealfactor(nf, idealdiv(nf,pi,qi)) idealfactor(nf, 787033*(x+1), 100) fa = idealfactor(nf, 471440*x + 612823, 100) idealfactor(nf,fa[2,1],10) idealfactor(nf,fa[2,1],40) idealfactor(nf, 471440*x + 612823, 2000) id=idealfactorback(nf,f) idealnumden(nf,id) idealnumden(nf,pi) idealnumden(nf,1) idealnumden(nf,1/2) idealnumden(nf,x/2) nffactorback(nf, [3, x+1, [1,2]~], [1, 2, 3]) test(nf,F,v)= { my(Y = idealchinese(nf,F,v), P = F[,1], E = F[,2]); for (i=1,#P, if( nfeltval(nf, nfeltadd(nf,v[i],-Y),P[i]) < E[i], error(i))); Y; } v = [x,0,[0,1/7^4]~,Mod(x,nf.pol)]; F = idealfactor(nf, 2*3*7); F[,2] *= 3; test(nf,F,v) F[,2] = [0,1,-2,3]~; test(nf,F,v) F[,2] = [1,1,1,1]~; test(nf,F,[1,0,0,0]) test(nf,F,[0,1/11,0,0]) P = F[2,1]; v = nfeltval(nf, 0, P, &y); [v == valuation(0,2),y] v = nfeltval(nf, 12, P, &y); [v,y] v = nfeltval(nf, (2/5*(1-x))^3, P, &y); [v,y] v = nfeltval(nf, nfeltpow(nf,P.gen[2],4), P, &y); [v,y] K = nfinit(t^2-2); fa = idealfactor(K, 2^2*3); C = idealchinese(K, [fa, [1,1]]); idealchinese(K, C, [1,t]) idealchinese(K, C, [-1,t]) C = idealchinese(K, fa); idealchinese(K, C, [1,t]) C = idealchinese(K, [C,[-1,-1]]); idealchinese(K, C, [1,t]) F = idealfactor(Q,2); idealchinese(Q, [F,[-1]], [0]) idealchinese(Q, [F,[1]], [0]) idealchinese(Q, [F,[0]], [0]) K = nfinit(x^3 - 2); A = [46875, 30966, 9573; 0, 3, 0; 0, 0, 3]; idealispower(K, A, 3, &B) B A = [9375, 2841, 198; 0, 3, 0; 0, 0, 3]; idealispower(K, A, 3) idealispower(K, A, 1) \\ #2019 idealispower(nfinit('y), 4, 2, &A) A K = nfinit(x^3 - 2); idealispower(K,2*5^3,3, &A) A \\ #1643 K=nfinit(x^8-1310*x^6+575380*x^4-93689568*x^2+3644295424); idealprimedec(K,17,1) K=nfinit(2*x^2+1); idealprimedec(K,2) nf=nfinit(x^6+108); a=Mod(x,x^6+108); { for(k=2,5, u=nfalgtobasis(nf,(2*a^2+a+3)*random(2^100*x^6)^k); b=idealredmodpower(nf,u,k); v=nfeltmul(nf,u,nfeltpow(nf,b,k)); print(v)); } idealredmodpower(nf,0,2) idealredmodpower(nf,1,2) idealredmodpower(nf,x^5-3*x^4-3*x^3+18*x^2-18*x-54,2) idealredmodpower(nf,x/2,2) idealredmodpower(nf,x/12,2) \\ Errors, keep at end of file idealred(nf,[2,Mat(1)]) pari-2.11.2/src/test/in/matpermanent0000644000175000017500000000077113326135265015763 0ustar billbilldefault(realprecision,38); matpermanent([;]) matpermanent(Mat(a)) matpermanent(Mat(1)) matpermanent([a,b,c;d,e,f;g,h,j]) m = [1,2,3;4,5,6;7,8,9]; matpermanent(m) matpermanent(m/2) matpermanent(m*1.) m = matrix(20,20,i,j,1); matpermanent(m) m = matrix(20,20,i,j,2^i + j); matpermanent(m) m = matrix(20,20,i,j,16^i + j); matpermanent(m) { for (n = 1, 10, m = matrix(n,n,i,j,i!=j); if (matpermanent(m)!=n!*sum(i=0,n,(-1)^i/i!), error(n))) } \\Errors matpermanent(matrix(64)) matpermanent(matrix(2,3)) pari-2.11.2/src/test/in/trans0000644000175000017500000000162113326135265014412 0ustar billbillHEAP=[184, if(sizebyte(0)==16,4426,6777)]; \\ A tres grande precision \p 2000 \e abs(-0.01) agm(1,2) agm(1+O(7^5),8+O(7^5)) 4*arg(3+3*I) bernreal(12) bernvec(6) eta(q) gammah(10) Pi precision(Pi,38) sqr(1+O(2)) sqrt(13+O(127^12)) teichmuller(7+O(127^12)) \\ A grande precision \p 500 Catalan Euler acos(0.5) acosh(3) 3*asin(sqrt(3)/2) asinh(0.5) 3*atan(sqrt(3)) atanh(0.5) besseljh(1,1) cos(1) cosh(1) exp(1) exp(1.123) incgam(4,1,6) incgamc(2,1) log(2) sin(Pi/6) sinh(1) sqr(tan(Pi/3)) tanh(1) thetanullk(0.5,7) \\ A moyenne precision \p 210 dilog(0.5) eint1(2) lngamma(10^50*I) polylog(5,0.5) polylog(-4,t) polylog(5,0.5,1) polylog(5,0.5,2) polylog(5,0.5,3) psi(1) round(prod(k=1,17,x-exp(2*I*Pi*k/17)), &e) e theta(0.5,3) weber(I) weber(I,1) weber(I,2) zeta(3) \\ A faible precision \p 38 besselk(1+I,1) erfc(2) gamma(10.5) hyperu(1,1,1) incgam(2,1) zeta(0.5+14.1347251*I) \\ if (getheap() != HEAP, getheap()) pari-2.11.2/src/test/in/ser0000644000175000017500000000426313447371554014070 0ustar billbilldefault(realprecision,38); s=x+x^2+O(x^5) f=[atan,asin,acos,cosh,sinh,tanh,cotanh,acosh,asinh,atanh]; { for (i=1,#f, print(f[i](s)); print(f[i](O(x^5))); print(f[i]([Pol(1)])); ) } O(x^-2) O(1/x^2) trace(I*x+1+O(x^2)) norm(I*x+1+O(x^2)) a=Ser(vector(200,i,i)); a^2 == a*(a+1) - a \\ test RgX_mullow, RgX_sqrlow 3+O(1) serreverse(x/2+O(x^2)) serreverse(tan(x)/2) iferr(sqrt(x+1/y),E,E) \\ #2063 ((y^-3+O(y))*x+1)/x s = 1/x + x + 2*x^2 + O(x^3); serchop(s) serchop(s, 2) serchop(s, 100) serchop(Mod(0,3)+x+O(x^2)) serchop(Mod(0,3)+O(x^2)) serchop(Mod(0,3)*x+O(x^2)) Ser(Qfb(1,2,3)) Ser(Qfb(1,2,3),, 5.5) Ser(Qfb(1,2,-5)) Ser(Qfb(1,2,-5),y,2) Ser([1,2,3], y, 5) Ser([1,2,3]~, y, 5) Ser([],,3) Ser(Vecsmall([1,2,3]), y, 5) Ser(x+O(x^2),,3) Ser(O(x^2),,3) Ser(x+x^2+x^3+O(x^4),,2) Ser(x^2+x^3,x,0) Ser(1+x,x,0) Ser(1/(x+1),x,0) Ser(1/x,x,0) Ser(1/y,x,0) Ser(x+y+O(x^2),x) Ser(x+y+O(x^2),y) s = Ser(Mod(0,7)) Ser(Mod(1,7)*(x^4+x^2), x,3) s+O(x^16) s+Mod(1,7) s+Mod(1,7)*x s/x s' deriv(s,y) trace(s) round(s) round(s,&e) lift(s) lift(s,x) liftint(s) O(x^2)*0 deriv(Mod(2,4)*x^2+O(x^3)) x^3*(1+O(y^2)) Mod(1,3)*x^3*(1+O(y^2)) O(x)/2 s = O(3^2)+O(x); s/3 s/2 s*3 (1+O(x))^2 1/(x+0.)+O(x^2) [1==O(x), 1==O(x^0), 1==O(x^-1)] [-1==O(x), -1==O(x^0), -1==O(x^-1)] [2==O(x), 2==O(x^0), 2==O(x^-1)] a=Mod(3,9) + O(x^2); b=Mod(3,9) + O(x^2); a*b a=1./x+O(1);a-a a=1/x+O(1);a-a a=Mod(1,2)/x+O(1);a-a subst(1+O(x),x,y) subst(1+x+O(x^2),x,y^2) O(1)==O(x) O(1)==x O(x)==1 exp(x+O(x^200))*exp(-x+O(x^200)) exp(x+O(x^200))^2==exp(2*x+O(x^200)) subst(1+x^3+O(x^6),x,x+O(x^4)) subst(1+x^2+O(x^6),x,x+O(x^3)) subst(1+x^3+x^4+O(x^6),x,x+x^2+O(x^3)) subst(x^2+O(x^3),x,0*x) subst(x^2+O(x^3),x,Mod(0,3)*x) subst(x^2+O(x^3),x,O(3)*x) subst(1+x+O(x^2),x,0*x) subst(1+x+O(x^2),x,Mod(0,3)*x) subst(1+x+O(x^2),x,O(3)*x) subst(1+x^2+O(x^3),x,z) subst(1+x^2+y^2+O(x^3),x,z) laurentseries(x->sin(x)/x^2, 3) laurentseries(x->sin(x)/x^2, 3, t) laurentseries(x->(cos(x)-1)/x) \\ Errors. Keep at end of file subst(x^-1+O(x),x,Mod(0,3)) subst(O(x^-1),x,Mod(0,3)) subst(x^-1+O(x),x,0*x) subst(O(x^-1),x,0*x) Ser(1/x,y) Ser(x,y) Ser([x],y) Ser(x,, -5) Ser("") O(13^-5)/Mat(Mod(2,26)*y*x+(Mod(1,2)*y^-1+O(y^3))) laurentseries(1) laurentseries((x,y)->1) pari-2.11.2/src/test/in/bessel0000644000175000017500000000137713455114163014545 0ustar billbilldefault(realprecision,38); default(seriesprecision,6); besseljh(1,2^64) besseljh(10,x) NU = [x,0,1,1/2,sqrt(2),10,1+I]; ARG = [x,1,1/2,1+I]; F=[besselh1,besselh2,besseli,besselj,besseljh,besselk,besseln]; test(f)= { print(f); for (i=1,#NU, for (j=1,#ARG, print([i,j],": ", iferr(f(NU[i],ARG[j]), E,E)); ) ); } for(i=1,#F,test(F[i])); for(i=1,#F,print(F[i](1,Mod(x,x^2+1)))); for(i=1,#F,print(F[i](1,[1]))); for(i=1,#F,print(F[i](1,[1]~))); for(i=1,#F,print(F[i](1,Mat(1)))); besseljh(2,0.) besseljh(2,1e-50) besselk(1,1000) besselk(1e-5,20) besselk(I,1000) besselk(1e-20,1e-5) \\ errors for(i=1,#F,print(iferr(F[i](O(2),1),E,E))); for(i=1,#F,print(iferr(F[i]("",1),E,E))); for(i=1,#F,print(iferr(F[i](1,O(2)),E,E))); for(i=1,#F,print(iferr(F[i](1,""),E,E))); pari-2.11.2/src/test/in/polyser0000644000175000017500000000241613326135265014763 0ustar billbillHEAP=[62, if(sizebyte(0)==16,4718,4776)]; default(realprecision,154); Pi; default(realprecision,38); \e apol=y^3+5*y+1 deriv((x+y)^5,y) ((x+y)^5)' dz=vector(30,k,1);dd=vector(30,k,k==1);dm=dirdiv(dd,dz) direuler(s=1,40,1+s*X+s^2*X) dirmul(abs(dm),dz) zz=yy;yy=xx;eval(zz) factorpadic(apol,7,8) intformal(sin(x)) intformal((-x^2-2*a*x+8*a)/(x^4-14*x^3+(2*a+49)*x^2-14*a*x+a^2)) newtonpoly(x^4+3*x^3+27*x^2+9*x+81,3) padicappr(apol,1+O(7^8)) padicappr(x^3+5*x+1,Mod(x*(1+O(7^8)),x^2+x-1)) Pol(sin(x)) Pol([1,2,3,4,5]) Polrev([1,2,3,4,5]) polcoeff(sin(x),7) polcyclo(105) pcy=polcyclo(405) pcy * pcy poldegree(x^3/(x-1)) poldisc(x^3+4*x+12) poldiscreduced(x^3+4*x+12) polinterpolate([0,2,3],[0,4,9],5) polisirreducible(x^5+3*x^3+5*x^2+15) pollegendre(10) zpol=0.3+pollegendre(10) polrecip(3*x^7-5*x^3+6*x-9) polresultant(x^3-1,x^3+1) polresultant(x^3-1.,x^3+1.,,1) polroots(x^5-5*x^2-5*x-5) polroots(x^4-1000000000000000000000) polrootsmod(x^16-1,41) polrootspadic(x^4+1,41,6) polsturm(zpol) polsturm(zpol,0.91,1) polsylvestermatrix(a2*x^2+a1*x+a0,b1*x+b0) polsym(x^17-1,17) poltchebi(10) polzagier(6,3) serconvol(sin(x),x*cos(x)) serlaplace(x*exp(x*y)/(exp(x)-1)) serreverse(tan(x)) subst(sin(x),x,y) subst(sin(x),x,x+x^2) taylor(y/(x-y),y) variable(name^4-other) if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/in/sumnumrat0000644000175000017500000000112113447371554015320 0ustar billbill\p115 sumnumrat(1/x,-oo) sumnumrat(1/x^2,-oo) sumeulerrat(y/x^2,1) F=1/(x^2+1)^2; sumnumrat(F,1) F=1/((x+1)*(x^2+x+1)); sumnumrat(F,0) F=1+1/x^2; prodnumrat(F,1) sumeulerrat(1/(q^2+1),1) sumeulerrat(1/(q+1),2) prodeulerrat(1+1/q^2,1)*zeta(4)/zeta(2) prodeulerrat(1+1/q^4,1/2)*zeta(4)/zeta(2) prodeulerrat(1-2/(q*(q+1)),1) prodeulerrat(1+1/q,3)*zeta(6)/zeta(3) sumnumrat(0,0) prodnumrat(1,1) prodeulerrat(1) sumeulerrat(0) \\ errors sumnumrat(1/x^2,oo) sumnumrat(1.0,1) sumnumrat(1/x,10) prodnumrat(1+1/x,10) prodnumrat(2,1) sumeulerrat(1) sumeulerrat(1/p) prodeulerrat(2) prodeulerrat(1+1/p) pari-2.11.2/src/test/in/debugger0000644000175000017500000000112513201017466015040 0ustar billbill\e default(breakloop,1) my(bound=100,step=20,halt=41); check(B)= { my(bi=[B^2]); for(i=1,bound, my(p=i+step,N=p^2); if(i==halt,error("check:",N))) } check(1000); [bound, step, halt, i, p, N, bi, B] break [bound, step, halt, i, p, N, bi, B] my(p=120);for(i=1,100,1/0) [p,i] dbg_err() break fun(N)=check(N^2+1); fun(20); N dbg_up(4) N break f(N,x)=my(z=x^2+1);breakpoint();gcd(N,z^2+1-z); f(221,3) z z iferrname("e_VAR",vector(10000,i,1/(i-100)),E,Vec(E)) i break f()=1/0 f(); allocatemem(10^7) for(i=1,10,if(i==2,1/0)); i N=5 M=6;1/0 break N M break F1(T) = 1/0; F1(2) dbg_up T break pari-2.11.2/src/test/in/algebras0000644000175000017500000024420613326135265015053 0ustar billbillal = alginit(nfinit(y), [Mat(1)]); \\reported by Bill J = varhigher("J",y); default(realprecision,38); default(parisize,100M); Q=nfinit(y); T=polcyclo(5, 'x); F=rnfinit(Q, T); A = alginit(F, [Mod(x^2,T), 3]); print("contains nfabs: ", algsplittingfield(A)[12][1] != 0); A[1][12][1] = 0; A do(name, test) = { setrand(1); print(name,": ", iferr(test(), E, E)); } gusuite(name, tests) = print("Suite: ", name); tests(); searchin(hf,pr,h) = { my(i,n); for(i=1,#hf[1], if(hf[1][i]==pr, return(hf[2][i]==h)) ); return(h==0); }; samehasse(hf1,hi1,hf2,hi2) = { my(i,n); if(hi1 != hi2, return(0)); n = #hf1[1]; for(i=1,n, if(!searchin(hf2,hf1[1][i],hf1[2][i]), return(0)); ); n = #hf2[1]; for(i=1,n, if(!searchin(hf1,hf2[1][i],hf2[2][i]), return(0)); ); return(1); }; hassetriv(hf,hi) = samehasse(hf,hi,[[],Vecsmall([])],Vecsmall(vector(#hi,i,0))); altriv(al) = hassetriv(alghassef(al),alghassei(al)); alsame(al,hf,hi) = samehasse(alghassef(al),alghassei(al),hf,hi); testcharpol(al,a)= { my (T = algcharpoly(al,a)); print(T); !algpoleval(al,T,a); } get() = gusuite("get", ()->{ my(s='s,i='i,poli,nf,ii,pols,rnf,ss,al); poli = i^2+1; nf = nfinit(poli); ii = Mod(i,poli); pols = s^2+2; rnf = rnfinit(nf, pols); ss = Mod(s,pols); al = alginit(rnf,[-ss,ii]); do("degree", ()->algdegree(al)==2); do("center", ()->algcenter(al)==nf); do("splitting", ()->algsplittingfield(al)==rnf); do("automorphism", ()->algaut(al)==-ss); do("b", ()->algb(al)==ii); do("trivial hasse invariants", ()->altriv(al)); do("charac", ()->algchar(al)==0); do("dim", ()->algdim(al)==4); do("absdim", ()->algdim(al,1)==8); do("basis", ()->#algbasis(al)==8); do("invbasis", ()->#alginvbasis(al)==8); do("basis*invbasis", ()->algbasis(al)*alginvbasis(al)==matid(8)); do("iscyclic", ()->algtype(al)==3); do("radical", ()->algradical(al)==0); \\cyclic => simple }); operations() = gusuite("operations", ()->{ my(s='s,i='i,poli,nf,ii,pols,rnf,ss,al,n,un,u,j); poli = i^2+1; nf = nfinit(poli); ii = Mod(i,poli); pols = s^2+2; rnf = rnfinit(nf, pols); ss = Mod(s,pols); ss = ss*Mod(1,poli); al = alginit(rnf,[-ss,ii]); do("radical", ()->algradical(al)==0); \\cyclic => simple nfii = ii; ii = ii*Mod(1,pols); n = [-ss,ii-1]~; un = [1,0]~; u = [1-ss,ii-1]~; j = [0,1]~; do("addition", ()->algadd(al,n,un)==u); do("negation", ()->algneg(al,u)==[ss-1,1-ii]~); do("soustraction", ()->algsub(al,u,n)==un); do("multiplication", ()->algmul(al,n,un)==n); do("non-commutativity", ()->algmul(al,n,j)==algmul(al,j,n)); do("left division", ()->algdivl(al,u,n)==n); do("right division", ()->algdivr(al,n,u)==n); do("noncommutative left division", ()->algdivl(al,u,j)==[ii+1,1-ss]~); do("noncommutative right division", ()->algdivr(al,j,u)==[ii+1,1+ss]~); do("division by non-invertible", ()->algdivl(al,n,u)); do("nilpotent", ()->algsqr(al,n)==[0,0]~); do("square", ()->algsqr(al,u)==algadd(al,u,n)); do("square j", ()->algsqr(al,j)==[ii,0]~); do("inverse", ()->alginv(al,u)==algsub(al,un,n)); do("powers", ()->algpow(al,u,124)==algadd(al,un,algmul(al,[124,0]~,n))); do("negative powers", ()->algpow(al,j,-56)==un); do("multiplication table j", ()->algtomatrix(al,j)==[0,ii;1,0]); do("multiplication table", ()->algtomatrix(al,u)==[1-ss,-1-ii;ii-1,1+ss]); do("characteristic polynomial", ()->algcharpoly(al,u,'y)==y^2-2*y+1); do("characteristic polynomial j", ()->algcharpoly(al,j,'y)==y^2-nfii); do("trace zero", ()->algtrace(al,n)==0); do("trace commutator", ()->algtrace(al,algsub(al,algmul(al,j,u),algmul(al,u,j)))==0); do("trace", ()->algtrace(al,algmul(al,u,j))==-2-2*nfii); do("norm zero", ()->algnorm(al,n)==0); do("norm one", ()->algnorm(al,u)==1); do("norm j", ()->algnorm(al,j)==-nfii); a = algadd(al,u,j); b = algadd(al, n, [12-4*ii+ss*(4-ii),7+3*ii+ss*(1+7*ii)]~); do("norm is multiplicative a*b", ()->nfalgtobasis(nf,algnorm(al,algmul(al,a,b)))==nfalgtobasis(nf,nfeltmul(nf,algnorm(al,a),algnorm(al,b)))); do("norm is multiplicative b*a", ()->nfalgtobasis(nf,algnorm(al,algmul(al,b,a)))==nfalgtobasis(nf,nfeltmul(nf,algnorm(al,b),algnorm(al,a)))); do("poleval", ()->algbasistoalg(al,algpoleval(al,x^3-2,u)) ==\ algsub(al,algpow(al,u,3),[2,0]~)); do("poleval b", ()->algbasistoalg(al,algpoleval(al,x^3+i*x-3*i,u)) ==\ algsub(al,algadd(al,algpow(al,u,3), algmul(al,[i,0]~,u)), [3*i,0]~)); }); tensor() = gusuite("tensor product of cyclic algebras", ()->{ my(nf,pol,jj,al1,al2,al3,hf12,hf23,p7,p7b,p3,p5); pol = y^2+y+1; nf = nfinit(pol); jj = Mod(y,pol); al1 = alginit(rnfinit(nf,x^2-(1+jj)), [-x, 4*jj+5]); al2 = alginit(rnfinit(nf,x^3-2), [jj*x, 7]); al3 = alginit(rnfinit(nf,x^4+x^3+x^2+x+1), [x^2, 7]); do("radical 1", ()->algradical(al1)==0); \\cyclic => simple do("radical 2", ()->algradical(al2)==0); \\cyclic => simple do("radical 3", ()->algradical(al3)==0); \\cyclic => simple p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; p7 = idealprimedec(nf,7)[1]; p7b = idealprimedec(nf,7)[2]; hf12 = [[p3,p7,p7b],Vecsmall([3,4,5])]; hf23 = [[p5,p7,p7b],Vecsmall([6,11,7])]; do("tensor of degree 2 and 3 no mo", ()->alsame(algtensor(al1,al2,0),hf12,Vecsmall([]))); }); rnfprimedec2(rnf,pp,nf2) = { my(nf = rnf.nf,pp2,pp3); pp2 = rnfidealup(rnf,pp); pp3 = idealadd(nf2,pp2[1],pp2[2]); for(i=3, #pp2, pp3 = idealadd(nf2,pp3,pp2[i])); return(idealfactor(nf2,pp3)); }; rnfprimedec(rnf,pp) = rnfprimedec2(rnf,pp,nfinit(rnf.polabs)); testgwa(nf,Lpr,Ld,pl) = ()->{ my(rnf, d, n, nf2); rnf = rnfinit(nf,nfgrunwaldwang(nf,Lpr,Ld,pl,x)); d = rnf.disc[1]; n = poldegree(rnf.pol); return(1); nf2 = nfinit(rnf.polabs); for(i=1,#Lpr, if(#mattranspose(rnfprimedec2(rnf,Lpr[i],nf2))*Ld[i] != n, return(0))); return(1); }; gw() = gusuite("Grunwald-Wang", ()->{ my(p2,p3,p5,p7,p11,p13,p17,pp,ppp,nf); nf = nfinit(y); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; pp = idealprimedec(nf,nextprime(1234))[1]; ppp = idealprimedec(nf,nextprime(4321))[1]; do("A quadratic over Q, 2 large inert, imaginary", testgwa(nf,[pp,ppp],Vecsmall([2,2]),Vecsmall([-1]))); do("A quartic over Q, 2 large inert, imaginary", testgwa(bnfinit(nf),[pp,ppp],Vecsmall([4,4]),Vecsmall([-1]))); nf = nfinit(y^2+1); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; do("A : degree 4 over Q(i), local degrees [4,1,1]", testgwa(nf,[p2,p3,p5],Vecsmall([4,1,1]),Vecsmall([]))); nf = nfinit(y^2+y+1); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; p7 = idealprimedec(nf,7)[1]; pp = idealprimedec(nf,nextprime(1248))[1]; ppp = idealprimedec(nf,nextprime(7531))[1]; do("A degree 3 over Q(j), local degrees [3,3] larger primes", testgwa(nf,[pp,ppp],[3,3],[])); nf = nfinit(y^2-5); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; p7 = idealprimedec(nf,7)[1]; p11 = idealprimedec(nf,11)[1]; p13 = idealprimedec(nf,13)[1]; p17 = idealprimedec(nf,17)[1]; pp = idealprimedec(nf,nextprime(1248))[1]; ppp = idealprimedec(nf,nextprime(4897))[1]; do("A : degree 3 over Q(sqrt(5)), local degrees [3,3] [0,0], larger primes", testgwa(nf,[pp,ppp],[3,3],[0,0])); /* TODO check what happens with [-1,-1] */ nf = nfinit(y^2-7); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; p7 = idealprimedec(nf,7)[1]; p11 = idealprimedec(nf,11)[1]; p13 = idealprimedec(nf,13)[1]; p17 = idealprimedec(nf,17)[1]; do("A : degree 5 over Q(sqrt(7)), local degrees [5,5,5,5,5,5,5] [0,0]", testgwa(nf,[p2,p3,p5,p7,p11,p13,p17],Vecsmall([5,5,5,5,5,5,5]),Vecsmall([0,0]))); /* TODO check what happens with [-1,-1] */ nf = nfinit(polcyclo(9,y)); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; p7 = idealprimedec(nf,7)[1]; do("A : degree 9 over Q(zeta_9), local degrees [9,9,9,9]", testgwa(nf,[p2,p3,p5,p7],Vecsmall([9,9,9,9]),Vecsmall([]))); nf = nfinit(y^6 -y^5 -7*y^4 +2*y^3 +7*y^2 -2*y -1); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; p5 = idealprimedec(nf,5)[1]; p7 = idealprimedec(nf,7)[1]; p11 = idealprimedec(nf,11)[1]; p13 = idealprimedec(nf,13)[1]; p17 = idealprimedec(nf,17)[1]; pp = idealprimedec(nf,nextprime(1357))[1]; ppp = idealprimedec(nf,nextprime(853))[1]; do("A degree 2 over totally real sextic, local degrees [2,2] [2,2,2,2,2,2], larger primes", testgwa(nf,[pp,ppp],Vecsmall([2,2]),Vecsmall([-1,-1,-1,-1,-1,-1]))); do("A degree 2 over totally real sextic, local degrees [] [2,2,2,2,2,2]", testgwa(nf,[],Vecsmall([]),Vecsmall([-1,-1,-1,-1,-1,-1]))); }); moreoperations() = gusuite("more operations", ()->{ my(x='x, y='y, nf, p1, p2, iinv, finv, al, u, t, b, w, un, pol1, pol2, cp, mul, rnf, aut, ww, tt, ord, invord, Y = varhigher("Y",y)); pol1 = y; nf = nfinit(pol1); p1 = idealprimedec(nf,2)[1]; p2 = idealprimedec(nf,3)[1]; iinv = [0]; finv = [[p1,p2],[-2/3,-1/3]]; al = alginit(nf,[3,finv,iinv],x); do("construct algebra", ()->al); pol2 = algsplittingfield(al).pol; mul = Mod(1,pol1)*Mod(1,pol2); u = [0,1,0]~*mul; t = [x,0,0]~*mul; b = [algb(al),0,0]~*mul; w = [x+x^2-7,1/2+x-3/7*x^2,12*x-1]~*mul; un = [1,0,0]~*mul; do("norm(u)", ()->lift(algnorm(al,u))==lift(algb(al))); do("norm(t)", ()->algnorm(al,t)==rnfeltnorm(algsplittingfield(al),x)); do("trace(u)", ()->algtrace(al,u)==0); do("trace(t)", ()->algtrace(al,t)==rnfelttrace(algsplittingfield(al),x)); do("u+t", ()->algadd(al,u,t)==algadd(al,t,u)); do("u*t", ()->algmul(al,u,t)!=algmul(al,t,u)); do("u^3", ()->algpow(al,u,3)==b); do("w^-1 L", ()->algmul(al,w,alginv(al,w))==un); do("w^-1 R", ()->algmul(al,alginv(al,w),w)==un); do("w^-1*u", ()->algmul(al,w,algdivl(al,w,u))); do("u*w^-1", ()->algmul(al,algdivr(al,u,w),w)); cp = algcharpoly(al,w,Y); do("charpol(w)", ()->cp); do("eval charpol", ()->algadd(al,algadd(al,algpow(al,w,3),algmul(al,[polcoeff(cp,2),0,0]~*mul,algsqr(al,w))),algadd(al,algmul(al,[polcoeff(cp,1),0,0]~*mul,w),[polcoeff(cp,0),0,0]~*mul))==0); do("trace(w)", ()->algtrace(al,w)==-polcoeff(cp,2)); do("norm(w)", ()->algnorm(al,w)==-polcoeff(cp,0)); do("dim", ()->algdim(al)==9); do("absdim", ()->algdim(al,1)==9); do("iscommutative", ()->algiscommutative(al)==0); do("issemisimple", ()->algissemisimple(al)==1); do("issimple", ()->algissimple(al)==1); pol1 = y^2+1; nf = nfinit(pol1); pol2 = x^3 + x^2 - 2*x - 1; rnf = rnfinit(nf,pol2); aut = x^2-2; al = alginit(rnf,[aut,Mod(2,pol1)]); mul = Mod(1,pol1)*Mod(1,pol2); u = [0,1,0]~*mul; t = [x,0,0]~*mul; tt = [y*x,0,0]~*mul; b = [2,0,0]~*mul; un = [1,0,0]~*mul; w = [y*x-1/3*x^2, 2+y/7-x, -12*x-3*y*x^2]~*mul; ww = [-x^2*y, 1/13+y+x+4*x^2, (-2+y)*x^2+(y/3+1/5)*x]~*mul; ord = algbasis(al); invord = alginvbasis(al); do("algleftmultable w+ww", ()->algtomatrix(al,algadd(al,w,ww),1)==(algtomatrix(al,w,1)+algtomatrix(al,ww,1))); do("algleftmultable w*ww", ()->algtomatrix(al,algmul(al,w,ww),1)==(algtomatrix(al,w,1)*algtomatrix(al,ww,1))); do("alg(basis(w))", ()->algbasistoalg(al,algalgtobasis(al,w))==w); do("alg(basis(ww))", ()->algbasistoalg(al,algalgtobasis(al,ww))==ww); do("basis(w)+ww", ()->algadd(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algadd(al,w,ww))); do("basis(w)-ww", ()->algsub(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algsub(al,w,ww))); do("w+basis(ww)", ()->algadd(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algadd(al,w,ww))); do("w-basis(ww)", ()->algsub(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algsub(al,w,ww))); do("basis(w)*ww", ()->algmul(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algmul(al,w,ww))); do("w*basis(ww)", ()->algmul(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algmul(al,w,ww))); do("basis(w)^2", ()->algsqr(al,algalgtobasis(al,w))==algalgtobasis(al,algsqr(al,w))); do("basis(ww)^2", ()->algsqr(al,algalgtobasis(al,ww))==algalgtobasis(al,algsqr(al,ww))); do("basis(w)\\ww", ()->algdivl(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivl(al,w,ww))); do("w\\basis(ww)", ()->algdivl(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivl(al,w,ww))); do("basis(ww)\\w", ()->algdivl(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivl(al,ww,w))); do("ww\basis(w)", ()->algdivl(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivl(al,ww,w))); do("basis(w)^-1", ()->alginv(al,algalgtobasis(al,w))==algalgtobasis(al,alginv(al,w))); do("basis(ww)^-1", ()->alginv(al,algalgtobasis(al,ww))==algalgtobasis(al,alginv(al,ww))); do("basis(w)/ww", ()->algdivr(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivr(al,w,ww))); do("w/basis(ww)", ()->algdivr(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivr(al,w,ww))); do("basis(ww)/w", ()->algdivr(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivr(al,ww,w))); do("ww/basis(w)", ()->algdivr(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivr(al,ww,w))); do("trace(basis(w))", ()->algtrace(al,w)==algtrace(al,algalgtobasis(al,w))); do("trace(basis(ww))", ()->algtrace(al,ww)==algtrace(al,algalgtobasis(al,ww))); w = [0,0,x*y]~*mul; ww = [1+y,1+x,1+x^2]~*mul; do("alg(basis(w)) 2", ()->algbasistoalg(al,algalgtobasis(al,w))==w); do("alg(basis(ww)) 2", ()->algbasistoalg(al,algalgtobasis(al,ww))==ww); do("basis(w)+ww 2", ()->algadd(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algadd(al,w,ww))); do("basis(w)-ww 2", ()->algsub(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algsub(al,w,ww))); do("w+basis(ww) 2", ()->algadd(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algadd(al,w,ww))); do("w-basis(ww) 2", ()->algsub(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algsub(al,w,ww))); do("basis(w)*ww 2", ()->algmul(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algmul(al,w,ww))); do("w*basis(ww) 2", ()->algmul(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algmul(al,w,ww))); do("basis(w)^2 2", ()->algsqr(al,algalgtobasis(al,w))==algalgtobasis(al,algsqr(al,w))); do("basis(ww)^2 2", ()->algsqr(al,algalgtobasis(al,ww))==algalgtobasis(al,algsqr(al,ww))); do("basis(w)\ww 2", ()->algdivl(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivl(al,w,ww))); do("w\basis(ww) 2", ()->algdivl(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivl(al,w,ww))); do("basis(ww)\w 2", ()->algdivl(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivl(al,ww,w))); do("ww\basis(w) 2", ()->algdivl(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivl(al,ww,w))); do("basis(w)^-1 2", ()->alginv(al,algalgtobasis(al,w))==algalgtobasis(al,alginv(al,w))); do("basis(ww)^-1 2", ()->alginv(al,algalgtobasis(al,ww))==algalgtobasis(al,alginv(al,ww))); do("basis(w)/ww 2", ()->algdivr(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivr(al,w,ww))); do("w/basis(ww) 2", ()->algdivr(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivr(al,w,ww))); do("basis(ww)/w 2", ()->algdivr(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivr(al,ww,w))); do("ww/basis(w) 2", ()->algdivr(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivr(al,ww,w))); do("trace(basis(w)) 2", ()->algtrace(al,w)==algtrace(al,algalgtobasis(al,w))); do("trace(basis(ww)) 2", ()->algtrace(al,ww)==algtrace(al,algalgtobasis(al,ww))); w = [1/2,1/3*x,1/5]~*mul; ww = [1+y,1+x,1+x^2]~*mul; do("alg(basis(w)) 3", ()->algbasistoalg(al,algalgtobasis(al,w))==w); do("alg(basis(ww)) 3", ()->algbasistoalg(al,algalgtobasis(al,ww))==ww); do("basis(w)+ww 3", ()->algadd(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algadd(al,w,ww))); do("basis(w)-ww 3", ()->algsub(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algsub(al,w,ww))); do("w+basis(ww) 3", ()->algadd(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algadd(al,w,ww))); do("w-basis(ww) 3", ()->algsub(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algsub(al,w,ww))); do("basis(w)*ww 3", ()->algmul(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algmul(al,w,ww))); do("w*basis(ww) 3", ()->algmul(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algmul(al,w,ww))); do("basis(w)^2 3", ()->algsqr(al,algalgtobasis(al,w))==algalgtobasis(al,algsqr(al,w))); do("basis(ww)^2 3", ()->algsqr(al,algalgtobasis(al,ww))==algalgtobasis(al,algsqr(al,ww))); do("basis(w)\ww 3", ()->algdivl(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivl(al,w,ww))); do("w\basis(ww) 3", ()->algdivl(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivl(al,w,ww))); do("basis(ww)\w 3", ()->algdivl(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivl(al,ww,w))); do("ww\basis(w) 3", ()->algdivl(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivl(al,ww,w))); do("basis(w)^-1 3", ()->alginv(al,algalgtobasis(al,w))==algalgtobasis(al,alginv(al,w))); do("basis(ww)^-1 3", ()->alginv(al,algalgtobasis(al,ww))==algalgtobasis(al,alginv(al,ww))); do("basis(w)/ww 3", ()->algdivr(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivr(al,w,ww))); do("w/basis(ww) 3", ()->algdivr(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivr(al,w,ww))); do("basis(ww)/w 3", ()->algdivr(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivr(al,ww,w))); do("ww/basis(w) 3", ()->algdivr(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivr(al,ww,w))); do("trace(basis(w)) 3", ()->algtrace(al,w)==algtrace(al,algalgtobasis(al,w))); do("trace(basis(ww)) 3", ()->algtrace(al,ww)==algtrace(al,algalgtobasis(al,ww))); do("radical", ()->algradical(al)==0); \\cyclic => simple do("iscommutative cyc 3", ()->algiscommutative(al)==0); do("issemisimple cyc 3", ()->algissemisimple(al)==1); do("issimple cyc 3", ()->algissimple(al)==1); pol1 = y; nf = nfinit(pol1); pol2 = x^2-2; rnf = rnfinit(nf,pol2); aut = -x; al = alginit(rnf,[aut,Mod(5,pol1)]); mul = Mod(1,pol1)*Mod(1,pol2); u = [0,1]~*mul; t = [x,0]~*mul; b = [5,0]~*mul; un = [1,0]~*mul; w = [-1/3*x^2, 2/7-x]~*mul; ww = [-x^2*4, 1/13+x+4*x^2]~*mul; ord = algbasis(al); invord = alginvbasis(al); do("algleftmultable/Q w+ww", ()->algtomatrix(al,algadd(al,w,ww),1)==(algtomatrix(al,w,1)+algtomatrix(al,ww,1))); do("algleftmultable/Q w*ww", ()->algtomatrix(al,algmul(al,w,ww),1)==(algtomatrix(al,w,1)*algtomatrix(al,ww,1))); do("alg(basis(w))/Q", ()->algbasistoalg(al,algalgtobasis(al,w))==w); do("alg(basis(ww))/Q", ()->algbasistoalg(al,algalgtobasis(al,ww))==ww); do("basis(w)+ww/Q", ()->algadd(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algadd(al,w,ww))); do("basis(w)-ww/Q", ()->algsub(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algsub(al,w,ww))); do("w+basis(ww)/Q", ()->algadd(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algadd(al,w,ww))); do("w-basis(ww)/Q", ()->algsub(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algsub(al,w,ww))); do("basis(w)*ww/Q", ()->algmul(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algmul(al,w,ww))); do("w*basis(ww)/Q", ()->algmul(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algmul(al,w,ww))); do("basis(w)^2/Q", ()->algsqr(al,algalgtobasis(al,w))==algalgtobasis(al,algsqr(al,w))); do("basis(ww)^2/Q", ()->algsqr(al,algalgtobasis(al,ww))==algalgtobasis(al,algsqr(al,ww))); do("basis(w)\ww/Q", ()->algdivl(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivl(al,w,ww))); do("w\basis(ww)/Q", ()->algdivl(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivl(al,w,ww))); do("basis(ww)\w/Q", ()->algdivl(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivl(al,ww,w))); do("ww\basis(w)/Q", ()->algdivl(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivl(al,ww,w))); do("basis(w)^-1/Q", ()->alginv(al,algalgtobasis(al,w))==algalgtobasis(al,alginv(al,w))); do("basis(ww)^-1/Q", ()->alginv(al,algalgtobasis(al,ww))==algalgtobasis(al,alginv(al,ww))); do("basis(w)/ww/Q", ()->algdivr(al,algalgtobasis(al,w),ww)==algalgtobasis(al,algdivr(al,w,ww))); do("w/basis(ww)/Q", ()->algdivr(al,w,algalgtobasis(al,ww))==algalgtobasis(al,algdivr(al,w,ww))); do("basis(ww)/w/Q", ()->algdivr(al,algalgtobasis(al,ww),w)==algalgtobasis(al,algdivr(al,ww,w))); do("ww/basis(w)/Q", ()->algdivr(al,ww,algalgtobasis(al,w))==algalgtobasis(al,algdivr(al,ww,w))); do("trace(basis(w))/Q", ()->algtrace(al,w)==algtrace(al,algalgtobasis(al,w))); do("trace(basis(ww))/Q", ()->algtrace(al,ww)==algtrace(al,algalgtobasis(al,ww))); do("radical/Q", ()->algradical(al)==0); \\cyclic => simple do("iscommutative /Q", ()->algiscommutative(al)==0); do("issemisimple /Q", ()->algissemisimple(al)==1); do("issimple /Q", ()->algissimple(al)==1); }); tablealg() = gusuite("table algebra", ()->{ my(x='x, al, mt, p, un, a, b, c, d, e, ss, projm, liftm, pa, sc); mt = [[1,0,0;0,1,0;0,0,1],[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; \\Matrices [*,*;0,*] un = [1,0,0]~; a = [1,0,-1]~; b = [0,-1,1]~; do("algisassociative 0.0", ()->algisassociative(mt)); do("algisassociative 0.1", ()->algisassociative(mt[2..3])); my (mt0 = mt); mt0[3][3,1] = 1; do("algisassociative 0.2", ()->algisassociative(mt0)); do("algisassociative 0.3", ()->algisassociative('x)); al = algtableinit(mt,0); do("construction 0", ()->al); do("iscyclic 0", ()->algtype(al)==1); do("dim 0", ()->algdim(al,1)==3); do("dim 0b", ()->algdim(al)==3); do("char 0", ()->algchar(al)==0); do("a+b 0", ()->algadd(al,a,b)==[1,-1,0]~); do("a-b 0", ()->algsub(al,a,b)==[1,1,-2]~); do("a*b 0", ()->algmul(al,a,b)==[0,-1,0]~); do("b*a 0", ()->algmul(al,b,a)==[0,0,0]~); do("a^2 0", ()->algsqr(al,a)==a); do("b^2 0", ()->algsqr(al,b)==b); e = [1,1,0]~; do("e^691691 0", ()->algpow(al,e,691691)==[1,691691,0]~); d = [1,0,1]~; do("d^101 0", ()->algpow(al,d,101)==[1,0,2^101-1]~); do("multable(a) 0", ()->algtomatrix(al,a,1)==[1,0,0;0,1,0;-1,0,0]); do("multable(b) 0", ()->algtomatrix(al,b,1)==[0,0,0;-1,0,-1;1,0,1]); do("divl(d,a) 0", ()->algdivl(al,d,a)==a); do("divl(d,b) 0", ()->algdivl(al,d,b)==[0,-1,1/2]~); do("d^-1 0", ()->alginv(al,d)==[1,0,-1/2]~); do("divr(a,d) 0", ()->algdivr(al,a,d)==a); do("divr(b,d) 0", ()->algdivr(al,b,d)==[0,-1/2,1/2]~); c = [0,7,0]~; do("rad(al) 0", ()->#algradical(al)==1); \\matrices [0,*;0,0] do("ss(al) 0", ()->#algradical(algquotient(al,algradical(al)))==0); [ss,projm,liftm] = algquotient(al,algradical(al),1); pa = projm*a; do("proj(a) idem 0", ()->algsqr(ss,pa)==pa); do("idemproj 0", ()->algcentralproj(ss,[pa,algsub(ss,projm*un,pa)])); sc = algcentralproj(ss,[pa,algsub(ss,projm*un,pa)]); do("simple components 0", ()->algmultable(sc[1])==[Mat(1)] && algmultable(sc[2])==[Mat(1)]); do("center al 0", ()->#algcenter(al)==1); do("center ss 0", ()->#algcenter(ss)==2); do("primesubalg ss 0", ()->#algprimesubalg(ss)==-1); do("charpol annihil(a) 0", ()->testcharpol(al,a)); do("charpol annihil(b) 0", ()->testcharpol(al,b)); do("charpol annihil(c) 0", ()->testcharpol(al,c)); do("charpol annihil(d) 0", ()->testcharpol(al,d)); do("charpol annihil(e) 0", ()->testcharpol(al,e)); do("random 0", ()->algrandom(al,1)); do("algsimpledec 0", ()->#algsimpledec(ss)[2]==2); do("alg_decomposition 0", ()->dec=algsimpledec(al); #dec[1]==1 && #dec[2]==2); do("iscommutative 0", ()->algiscommutative(al)==0); do("issemisimple 0", ()->algissemisimple(al)==0); do("issimple 0", ()->algissimple(al)==0); do("issimple ss 0", ()->algissimple(ss)==0); do("isdivision 0", ()->algisdivision(al)==0); p = 2; al = algtableinit(mt,p); do("algisassociative 2", ()->algisassociative(mt,p)); do("construction 2", ()->al); do("iscyclic 2", ()->algtype(al)==1); do("dim 2", ()->algdim(al,1)==3); do("char 2", ()->algchar(al)==p); do("a+b 2", ()->algadd(al,a,b)==[1,1,0]~); do("a-b 2", ()->algsub(al,a,b)==algadd(al,a,b)); do("a*b 2", ()->algmul(al,a,b)==[0,p-1,0]~); do("b*a 2", ()->algmul(al,b,a)==[0,0,0]~); do("a^2 2", ()->algsqr(al,a)==a*Mod(1,p)); do("b^2 2", ()->algsqr(al,b)==b*Mod(1,p)); do("multable(a) 2", ()->algtomatrix(al,a,1)==[1,0,0;0,1,0;-1,0,0]*Mod(1,p)); do("multable(b) 2", ()->algtomatrix(al,b,1)==[0,0,0;-1,0,-1;1,0,1]*Mod(1,p)); do("divl(un,a) 2", ()->algdivl(al,un,a)==a*Mod(1,p)); do("divl(un,b) 2", ()->algdivl(al,un,b)==b*Mod(1,p)); do("un^-1 2", ()->alginv(al,un)==un); do("divr(a,un) 2", ()->algdivr(al,a,un)==a*Mod(1,p)); do("divr(b,un) 2", ()->algdivr(al,b,un)==b*Mod(1,p)); do("rad(al) 2", ()->#algradical(al)==1); \\matrices [0,*;0,0] do("ss(al) 2", ()->#algradical(algquotient(al,algradical(al)))==0); [ss,projm,liftm] = algquotient(al,algradical(al),1); pa = projm*a; do("proj(a) idem 2", ()->algsqr(ss,pa)==pa*Mod(1,p)); do("idemproj 2", ()->algcentralproj(ss,[pa,algsub(ss,projm*un,pa)])); sc = algcentralproj(ss,[pa,algsub(ss,projm*un,pa)]); do("simple components 2", ()->algmultable(sc[1])==[Mat(Mod(1,p))] && algmultable(sc[2])==[Mat(Mod(1,p))]); do("center al 2", ()->#algcenter(al)==1); do("center ss 2", ()->#algcenter(ss)==2); do("primesubalg ss 2", ()->#algprimesubalg(ss)==2); do("charpol annihil(a) 2", ()->testcharpol(al,a)); do("charpol annihil(b) 2", ()->testcharpol(al,b)); do("charpol annihil(c) 2", ()->testcharpol(al,c)); do("random 2", ()->algrandom(al,1)); do("algsimpledec 2", ()->#algsimpledec(ss)[2]==2); do("alg_decomposition 2", ()->dec=algsimpledec(al); #dec[1]==1 && #dec[2]==2); do("iscommutative 2", ()->algiscommutative(al)==0); do("issemisimple 2", ()->algissemisimple(al)==0); do("issimple 2", ()->algissimple(al)==0); do("issimple ss 2", ()->algissimple(ss)==0); do("matrix trace 2", ()->algtrace(al,[un,vector(3)~;vector(3)~,un])==0); do("matrix norm 2", ()->algnorm(al,[un,vector(3)~;vector(3)~,un])==1); do("norm 2", ()->algnorm(al,un)==1); p = 3; mt = [[1,0;0,1],[0,0;1,0]];\\F3[x]/(x^2) un = [1,0]~; a = [1,-1]~; b = [0,1]~; al = algtableinit(mt,p); do("construction 3", ()->al); do("iscyclic 3", ()->algtype(al)==1); do("dim 3", ()->algdim(al,1)==2); do("char 3", ()->algchar(al)==p); do("a+b 3", ()->algadd(al,a,b)==un); do("a-b 3", ()->algsub(al,a,b)==[1,1]~); do("a*b 3", ()->algmul(al,a,b)==[0,1]~); do("b*a 3", ()->algmul(al,b,a)==[0,1]~); do("a^2 3", ()->algsqr(al,a)==[1,1]~); do("b^2 3", ()->algsqr(al,b)==[0,0]~); do("a^691691 3", ()->algpow(al,a,691691)==[1,-691691]~*Mod(1,p)); do("multable(a) 3", ()->algtomatrix(al,a,1)==[1,0;-1,1]*Mod(1,p)); do("multable(b) 3", ()->algtomatrix(al,b,1)==[0,0;1,0]); do("algdivl(a,b) 3", ()->algdivl(al,a,b)==b); do("a^-1 3", ()->alginv(al,a)==[1,1]~); do("algdivr(b,a) 3", ()->algdivr(al,b,a)==b); do("rad(al) 3", ()->#algradical(al)==1); \\ideal (x) do("ss(al) 3", ()->#algradical(algquotient(al,algradical(al)))==0); [ss,projm,liftm] = algquotient(al,algradical(al),1); do("center al 3", ()->#algcenter(al)==2); do("center ss 3", ()->#algcenter(ss)==1); do("primesubalg ss 3", ()->#algprimesubalg(ss)==1); do("charpol annihil(a) 3", ()->testcharpol(al,a)); do("charpol annihil(b) 3", ()->testcharpol(al,b)); do("random 3", ()->algrandom(al,1)); do("algsimpledec 3", ()->#algsimpledec(ss)[2]==1); do("alg_decomposition 3", ()->dec=algsimpledec(al); #dec[1]==1 && #dec[2]==1); do("iscommutative 3", ()->algiscommutative(al)==1); do("issemisimple 3", ()->algissemisimple(al)==0); do("issemisimple ss 3", ()->algissemisimple(ss)==1); do("issimple 3", ()->algissimple(al)==0); do("issimple ss 3", ()->algissimple(ss)==1); p = 3; mt = [[1,0,0;0,1,0;0,0,1],[0,0,0;1,0,0;0,1,0],[0,0,0;0,0,0;1,0,0]];\\F3[x]/(x^3) un = [1,0,0]~; a = [1,-1,0]~; b = [0,1,0]~; al = algtableinit(mt,p); do("construction 3c", ()->al); do("iscyclic 3c", ()->algtype(al)==1); do("dim 3c", ()->algdim(al,1)==3); do("char 3c", ()->algchar(al)==p); do("a+b 3c", ()->algadd(al,a,b)==un); do("a-b 3c", ()->algsub(al,a,b)==[1,1,0]~); do("a*b 3c", ()->algmul(al,a,b)==[0,1,p-1]~); do("b*a 3c", ()->algmul(al,b,a)==[0,1,p-1]~); do("a^2 3c", ()->algsqr(al,a)==[1,1,1]~); do("b^2 3c", ()->algsqr(al,b)==[0,0,1]~); do("a^691691 3c", ()->algpow(al,a,691691)==[1,-691691,(691691*691690)\2]~*Mod(1,p)); do("multable(a) 3c", ()->algtomatrix(al,a,1)==[1,0,0;-1,1,0;0,-1,1]*Mod(1,p)); do("multable(b) 3c", ()->algtomatrix(al,b,1)==[0,0,0;1,0,0;0,1,0]); do("algdivl(a,b) 3c", ()->algdivl(al,a,b)==[0,1,1]~); do("a^-1 3c", ()->alginv(al,a)==[1,1,1]~); do("algdivr(b,a) 3c", ()->algdivr(al,b,a)==[0,1,1]~); do("rad(al) 3c", ()->#algradical(al)==2); \\ideal (x), basis (x,x^2) do("ss(al) 3c", ()->#algradical(algquotient(al,algradical(al)))==0); [ss,projm,liftm] = algquotient(al,algradical(al),1); do("center al 3c", ()->#algcenter(al)==3); do("center ss 3c", ()->#algcenter(ss)==1); do("primesubalg ss 3c", ()->#algprimesubalg(ss)==1); do("charpol annihil(a) 3c", ()->testcharpol(al,a)); do("charpol annihil(b) 3c", ()->testcharpol(al,b)); do("random 3c", ()->algrandom(al,1)); do("algsimpledec 3c", ()->#algsimpledec(ss)[2]==1); do("alg_decomposition 3c", ()->dec=algsimpledec(al); #dec[1]==2 && #dec[2]==1); do("iscommutative 3c", ()->algiscommutative(al)==1); do("issemisimple 3c", ()->algissemisimple(al)==0); do("issemisimple ss 3c", ()->algissemisimple(ss)==1); do("issimple 3c", ()->algissimple(al)==0); do("issimple ss 3c", ()->algissimple(ss)==1); p = 2; mt = [[1,0;0,1],[0,1;1,1]]; \\F2[x]/(x^2+x+1) un = [1,0]~; a = [0,1]~; b = [1,1]~; al = algtableinit(mt,p); do("construction 2b", ()->al); do("iscyclic 2b", ()->algtype(al)==1); do("dim 2b", ()->algdim(al,1)==2); do("char 2b", ()->algchar(al)==p); do("a+b 2b", ()->algadd(al,a,b)==un); do("a-b 2b", ()->algsub(al,a,b)==un); do("a*b 2b", ()->algmul(al,a,b)==un); do("b*a 2b", ()->algmul(al,b,a)==un); do("a^2 2b", ()->algsqr(al,a)==b); do("b^2 2b", ()->algsqr(al,b)==a); do("a^691691 2b", ()->algpow(al,a,691691)==b); do("multable(a) 2b", ()->algtomatrix(al,a,1)==[0,1;1,1]); do("multable(b) 2b", ()->algtomatrix(al,b,1)==[1,1;1,0]); do("divl(a,b) 2b", ()->algdivl(al,a,b)==a); do("a^-1 2b", ()->alginv(al,a)==b); do("divr(b,a) 2b", ()->algdivr(al,b,a)==a); do("rad(al) 2b", ()->#algradical(al)==0); \\separable extension of F2 do("center al 2b", ()->#algcenter(al)==2); do("primesubalg al 2b", ()->#algprimesubalg(al)==1); do("charpol annihil(a) 2b", ()->testcharpol(al,a)); do("charpol annihil(b) 2b", ()->testcharpol(al,b)); do("random 2b", ()->algrandom(al,1)); do("algsimpledec 2b", ()->#algsimpledec(al)[2]==1); do("alg_decomposition 2b", ()->dec=algsimpledec(al); dec[1]==0 && #dec[2]==1 && algdim(dec[2][1],1)==2); do("iscommutative 2b", ()->algiscommutative(al)==1); do("issemisimple 2b", ()->algissemisimple(al)==1); do("issimple 2b", ()->algissimple(al)==1); do("issimple,1 2b", ()->algissimple(al,1)==1); p = 3; mt = [matid(4), [0,1,0,0; 1,0,0,0; 0,0,1,0; 0,0,0,-1], [0,0,0,1/2; 0,0,0,1/2; 1,-1,0,0; 0,0,0,0], [0,0,1/2,0; 0,0,-1/2,0; 0,0,0,0; 1,1,0,0]]*Mod(1,p); \\M_2(F3) un = [1,0,0,0]~; a = [0,1,-1,0]~; b = [1,1,0,1]~; al = algtableinit(mt,p); do("construction 3b", ()->al); do("iscyclic 3b", ()->algtype(al)==1); do("dim 3b", ()->algdim(al,1)==4); do("char 3b", ()->algchar(al)==p); do("a+b 3b", ()->algadd(al,a,b)==[1,-1,2,1]~*Mod(1,p)); do("a-b 3b", ()->algsub(al,a,b)==[2,0,2,2]~); do("a*b 3b", ()->algmul(al,a,b)==[2,2,0,2]~); do("b*a 3b", ()->algmul(al,b,a)==[2,0,1,1]~); do("a^2 3b", ()->algsqr(al,a)==un); do("b^2 3b", ()->algsqr(al,b)==-b*Mod(1,p)); do("a^691691 3b", ()->algpow(al,a,691691)==a*Mod(1,p)); do("b^691691 3b", ()->algpow(al,b,691691)==b); do("multable(a) 3b", ()->algtomatrix(al,a,1)==[0,1,0,1;1,0,0,1;2,1,1,0;0,0,0,2]); do("multable(b) 3b", ()->algtomatrix(al,b,1)==[1,1,2,0;1,1,1,0;0,0,2,0;1,1,0,0]); do("divl(a,b) 3b", ()->algdivl(al,a,b)==[2,2,0,2]~); do("a^-1 3b", ()->alginv(al,a)==[0,1,2,0]~); do("divr(b,a) 3b", ()->algdivr(al,b,a)==[2,0,1,1]~); c = [0,0,1,0]~; do("rad(al) 3b", ()->#algradical(al)==0); \\matrix ring is semisimple do("center al 3b", ()->#algcenter(al)==1); do("primesubalg al 3b", ()->#algprimesubalg(al)==1); do("charpol annihil(a) 3b", ()->testcharpol(al,a)); do("charpol annihil(b) 3b", ()->testcharpol(al,b)); do("charpol annihil(c) 3b", ()->testcharpol(al,c)); do("random 3b", ()->algrandom(al,1)); do("algsimpledec 3b", ()->#algsimpledec(al)[2]==1); do("alg_decomposition 3b", ()->dec=algsimpledec(al); dec[1]==0 && #dec[2]==1 && #algcenter(dec[2][1])==1); do("iscommutative 3b", ()->algiscommutative(al)==0); do("issemisimple 3b", ()->algissemisimple(al)==1); do("issimple 3b", ()->algissimple(al)==1); p = 2; mt = [matid(4), [0,0,1,0; 1,0,0,1; 0,0,0,0; 0,0,-1,0], [0,0,0,0; 0,0,0,0; 1,0,0,0; 0,1,0,0], [0,0,0,0; 0,0,0,0; 0,0,1,0; 1,0,0,1]]*Mod(1,p); \\M_2(F2) un = [1,0,0,0]~; a = [0,1,0,0]~; b = [1,0,0,1]~; al = algtableinit(mt,p); do("construction 2c", ()->al); do("iscyclic 2c", ()->algtype(al)==1); do("dim 2c", ()->algdim(al,1)==4); do("char 2c", ()->algchar(al)==p); do("a+b 2c", ()->algadd(al,a,b)==[1,1,0,1]~); do("a-b 2c", ()->algsub(al,a,b)==[1,1,0,1]~); do("a*b 2c", ()->algmul(al,a,b)==[0,0,0,0]~); do("b*a 2c", ()->algmul(al,b,a)==a); do("a^2 2c", ()->algsqr(al,a)==[0,0,0,0]~); do("b^2 2c", ()->algsqr(al,b)==b); c = [1,1,1,1]~; do("a^691691 2c", ()->algpow(al,a,691691)==[0,0,0,0]~); do("b^691691 2c", ()->algpow(al,b,691691)==b); do("c^691691 2c", ()->algpow(al,c,691691)==[0,1,1,1]~); do("multable(a) 2c", ()->algtomatrix(al,a,1)==[0,0,1,0;1,0,0,1;0,0,0,0;0,0,1,0]); do("multable(b) 2c", ()->algtomatrix(al,b,1)==[1,0,0,0;0,1,0,0;0,0,0,0;1,0,0,0]); do("divl(c,a) 2c", ()->algdivl(al,c,a)==[0,0,0,1]~); do("divl(c,b) 2c", ()->algdivl(al,c,b)==[0,0,1,0]~); do("c^-1 2c", ()->alginv(al,c)==[0,1,1,1]~); do("divr(a,c) 2c", ()->algdivr(al,a,c)==[1,1,0,1]~); do("divr(b,c) 2c", ()->algdivr(al,b,c)==[0,1,0,0]~); do("rad(al) 2c", ()->#algradical(al)==0); \\matrix ring is semisimple do("center al 2c", ()->#algcenter(al)==1); do("primesubalg al 2c", ()->#algprimesubalg(al)==1); do("charpol annihil(a) 2c", ()->testcharpol(al,a)); do("charpol annihil(b) 2c", ()->testcharpol(al,b)); do("charpol annihil(c) 2c", ()->testcharpol(al,c)); do("random 2c", ()->algrandom(al,1)); do("algsimpledec 2c", ()->#algsimpledec(al)[2]==1); do("alg_decomposition 2c", ()->dec=algsimpledec(al); dec[1]==0 && #dec[2]==1 && #algcenter(dec[2][1])==1); do("iscommutative 2c", ()->algiscommutative(al)==0); do("issemisimple 2c", ()->algissemisimple(al)==1); do("issimple 2c", ()->algissimple(al)==1); p = 5; mt = [Mat(Mod(1,p))]; un = [1]~; a = [2]~; b = [3]~; al = algtableinit(mt,p); do("construction 5", ()->al); do("iscyclic 5", ()->algtype(al)==1); do("dim 5", ()->algdim(al,1)==1); do("char 5", ()->algchar(al)==p); do("a+b 5", ()->algadd(al,a,b)==[Mod(0,p)]~); do("a-b 5", ()->algsub(al,a,b)==[Mod(4,p)]~); do("a*b 5", ()->algmul(al,a,b)==[Mod(1,p)]~); do("b*a 5", ()->algmul(al,b,a)==[Mod(1,p)]~); do("a^2 5", ()->algsqr(al,a)==[Mod(4,p)]~); do("b^2 5", ()->algsqr(al,b)==[Mod(-1,p)]~); do("a^691691 5", ()->algpow(al,a,691691)==b); do("multable(a) 5", ()->algtomatrix(al,a,1)==Mat(Mod(2,p))); do("multable(b) 5", ()->algtomatrix(al,b,1)==Mat(Mod(3,p))); do("divl(a,b) 5", ()->algdivl(al,a,b)==[Mod(4,p)]~); do("a^-1 5", ()->alginv(al,a)==[Mod(3,p)]~); do("divr(a,b) 5", ()->algdivr(al,a,b)==[Mod(4,p)]~); do("rad(al) 5", ()->#algradical(al)==0); \\F5, dim 1 do("center al 5", ()->#algcenter(al)==1); do("primesubalg al 5", ()->#algprimesubalg(al)==1); do("charpol annihil(a) 5", ()->testcharpol(al,a)); do("charpol annihil(b) 5", ()->testcharpol(al,b)); do("random 5", ()->algrandom(al,1)); do("algsimpledec 5", ()->#algsimpledec(al)[2]==1); do("alg_decomposition 5", ()->dec=algsimpledec(al); dec[1]==0 && #dec[2]==1 && algdim(dec[2][1],1)==1); do("iscommutative 5", ()->algiscommutative(al)==1); do("issemisimple 5", ()->algissemisimple(al)==1); do("issimple 5", ()->algissimple(al)==1); p = 0; \\M_2(Q)+Q mt = [matid(5), [0,0,1,0,0; 1,0,0,1,0; 0,0,0,0,0; 0,0,-1,0,0; 0,1,-1,-1,1], [0,0,0,0,0; 0,0,0,0,0; 1,0,0,0,0; 0,1,0,0,0; 0,0,0,0,0], [0,0,0,0,0; 0,0,0,0,0; 0,0,1,0,0; 1,0,0,1,0; 0,0,0,0,0], [0,0,0,0,0; 0,0,0,0,0; 0,0,0,0,0; 0,0,0,0,0; 1,1,0,0,1] ]; un = [1,0,0,0,0]~; a = [1,0,0,0,-1]~; b = [1,1,0,0,0]~; al = algtableinit(mt,p); do("construction 0b", ()->al); do("iscyclic 0b", ()->algtype(al)==1); do("dim 0b", ()->algdim(al,1)==5); do("char 0b", ()->algchar(al)==p); do("a+b 0b", ()->algadd(al,a,b)==[2,1,0,0,-1]~); do("a-b 0b", ()->algsub(al,a,b)==[0,-1,0,0,-1]~); do("a*b 0b", ()->algmul(al,a,b)==[1,1,0,0,-2]~); do("b*a 0b", ()->algmul(al,b,a)==algmul(al,a,b));\\a central do("a^2 0b", ()->algsqr(al,a)==a); do("b^2 0b", ()->algsqr(al,b)==[1,2,0,0,1]~); do("a^691691 0b", ()->algpow(al,a,691691)==a); do("b^691 0b", ()->algpow(al,b,691)==[1,691,0,0,2^691-1-691]~); do("multable(a) 0b", ()->algtomatrix(al,a,1)== [1,0,0,0,0; 0,1,0,0,0; 0,0,1,0,0; 0,0,0,1,0; -1,-1,0,0,0]); do("multable(b) 0b", ()->algtomatrix(al,b,1)== [1,0,1,0,0; 1,1,0,1,0; 0,0,1,0,0; 0,0,-1,1,0; 0,1,-1,-1,2]); do("divl(b,a) 0b", ()->algdivl(al,b,a)==[1,-1,0,0,0]~); do("b^-1 0b", ()->alginv(al,b)==[1,-1,0,0,1/2]~); do("divr(a,b) 0b", ()->algdivr(al,a,b)==algdivl(al,b,a)); do("rad(al) 0b", ()->#algradical(al)==0); do("idemproj 0b", ()->algcentralproj(al,[a,algsub(al,un,a)])); sc = algcentralproj(al,[a,algsub(al,un,a)]); do("simple components 0b", ()->algdim(sc[1],1)==4 && algdim(sc[2],1)==1); do("mt M2 component 0b", ()->algmultable(sc[1])[1]==matid(4)); do("center al 0b", ()->#algcenter(al)==2); do("primesubalg al 0b", ()->#algprimesubalg(al)==-1); do("charpol annihil(a) 0b", ()->testcharpol(al,a)); do("charpol annihil(b) 0b", ()->testcharpol(al,b)); do("random 0b", ()->algrandom(al,1)); do("algsimpledec 0b", ()->#algsimpledec(al)[2]==2); do("alg_decomposition 0b", ()->dec=algsimpledec(al); dec[1]==0 && #dec[2]==2 && #algcenter(dec[2][1])==1 && #algcenter(dec[2][2])==1 && (algdim(dec[2][1],1)==4 || algdim(dec[2][2],1)==4)); do("subalg M2(Q)", ()->sal=algsubalg(al,[1,0,0,0; 0,1,0,0; 0,0,1,0; 0,0,0,1;\ 0,0,0,0])[1]; algisassociative(sal) && algradical(sal)==0 &&\ #algsimpledec(sal)[2]==1); do("iscommutative 0b", ()->algiscommutative(al)==0); do("issemisimple 0b", ()->algissemisimple(al)==1); do("issimple 0b", ()->algissimple(al)==0); p = 3; al = algtableinit(mt,p); do("construction 3d", ()->al); do("iscyclic 3d", ()->algtype(al)==1); do("dim 3d", ()->algdim(al,1)==5); do("char 3d", ()->algchar(al)==p); do("a+b 3d", ()->algadd(al,a,b)==[2,1,0,0,-1]~*Mod(1,p)); do("a-b 3d", ()->algsub(al,a,b)==[0,-1,0,0,-1]~*Mod(1,p)); do("a*b 3d", ()->algmul(al,a,b)==[1,1,0,0,-2]~*Mod(1,p)); do("b*a 3d", ()->algmul(al,b,a)==algmul(al,a,b));\\a central do("a^2 3d", ()->algsqr(al,a)==a*Mod(1,p)); do("b^2 3d", ()->algsqr(al,b)==[1,2,0,0,1]~); do("a^691691 3d", ()->algpow(al,a,691691)==a*Mod(1,p)); do("b^691 3d", ()->algpow(al,b,691)==[1,691,0,0,2^691-1-691]~*Mod(1,p)); do("multable(a) 3d", ()->algtomatrix(al,a,1)== [1,0,0,0,0; 0,1,0,0,0; 0,0,1,0,0; 0,0,0,1,0; -1,-1,0,0,0]*Mod(1,p)); do("multable(b) 3d", ()->algtomatrix(al,b,1)== [1,0,1,0,0; 1,1,0,1,0; 0,0,1,0,0; 0,0,-1,1,0; 0,1,-1,-1,2]*Mod(1,p)); do("divl(b,a) 3d", ()->algdivl(al,b,a)==[1,-1,0,0,0]~*Mod(1,p)); do("b^-1 3d", ()->alginv(al,b)==[1,-1,0,0,1/2]~*Mod(1,p)); do("divr(a,b) 3d", ()->algdivr(al,a,b)==algdivl(al,b,a)); do("rad(al) 3d", ()->#algradical(al)==0); do("idemproj 3d", ()->algcentralproj(al,[a,algsub(al,un,a)])); sc = algcentralproj(al,[a,algsub(al,un,a)]); do("simple components 3d", ()->algdim(sc[1],1)==4 && algdim(sc[2],1)==1); do("mt M2 component 3d", ()->algmultable(sc[1])[1]==matid(4)); do("center al 3d", ()->#algcenter(al)==2); do("primesubalg al 3d", ()->#algprimesubalg(al)==2); do("charpol annihil(a) 3d", ()->testcharpol(al,a)); do("charpol annihil(b) 3d", ()->testcharpol(al,b)); do("random 3d", ()->algrandom(al,1)); do("algsimpledec 3d", ()->#algsimpledec(al)[2]==2); do("alg_decomposition 3d", ()->dec=algsimpledec(al); dec[1]==0 && #dec[2]==2 && #algcenter(dec[2][1])==1 && #algcenter(dec[2][2])==1 && (algdim(dec[2][1],1)==4 || algdim(dec[2][2],1)==4)); do("subalg M2(F3)", ()->sal=algsubalg(al,[1,0,0,0; 0,1,0,0; 0,0,1,0; 0,0,0,1;\ 0,0,0,0]); algisassociative(sal[1]) && algradical(sal[1])==0 &&\ #algsimpledec(sal[1])[2]==1); do("iscommutative 3d", ()->algiscommutative(al)==0); do("issemisimple 3d", ()->algissemisimple(al)==1); do("issimple 3d", ()->algissimple(al)==0); do("issimple,1 3d", ()->algissimple(al,1)==0); }); all() = gusuite("all", ()->{ get(); operations(); tensor(); gw(); moreoperations(); tablealg(); }); all(); nf = nfinit(y^2-2); al = alginit(nf, [-3,-5], x,1); print("maxorder assoc: ", algisassociative(al[9])); al0 = alginit(nf, [-3,-5], x,0); print("natorder assoc: ", algisassociative(al0[9])); un = [1,0]~; ii = [x,0]~; jj = [0,1]~; kk = algmul(al,ii,jj); print("spl(1): ", algtomatrix(al,un)==matid(2)); print("spl(i): ", algtomatrix(al,ii)==[x,0;0,-x]); print("spl(j): ", algtomatrix(al,jj)==[0,-5;1,0]); print("spl(k): ", algtomatrix(al,kk)==[0,-5*x;-x,0]); print("spl(basis(1)): ", algtomatrix(al,algalgtobasis(al,un))==matid(2)); print("spl(basis(i)): ", algtomatrix(al,algalgtobasis(al,ii))==[x,0;0,-x]); print("spl(basis(j)): ", algtomatrix(al,algalgtobasis(al,jj))==[0,-5;1,0]); print("spl(basis(k)): ", algtomatrix(al,algalgtobasis(al,kk))==[0,-5*x;-x,0]); a = y+1; b = 1/3; c = -y/5+1/2; print("spl(a*1): ", algtomatrix(al,a*un)==a*matid(2)); print("spl(a*i): ", algtomatrix(al,a*ii)==a*[x,0;0,-x]); print("spl(a*j): ", algtomatrix(al,a*jj)==a*[0,-5;1,0]); print("spl(a*k): ", algtomatrix(al,a*kk)==a*[0,-5*x;-x,0]); print("spl(b*1): ", algtomatrix(al,b*un)==b*matid(2)); print("spl(b*i): ", algtomatrix(al,b*ii)==b*[x,0;0,-x]); print("spl(b*j): ", algtomatrix(al,b*jj)==b*[0,-5;1,0]); print("spl(b*k): ", algtomatrix(al,b*kk)==b*[0,-5*x;-x,0]); ord = algbasis(al); invord = alginvbasis(al); setrand(1); x1 = algrandom(al,1); ax1 = algbasistoalg(al,x1); nx1 = algalgtobasis(al0,ax1); print("nattomax 1: ", nx1==ord*x1); setrand(2); x2 = algrandom(al,1); ax2 = algbasistoalg(al,x2); nx2 = algalgtobasis(al0,ax2); print("nattomax 2: ", nx2==ord*x2); print("ord*invord=id: ", ord*invord == matid(8)); print("spl additive: ", algtomatrix(al,x1) + algtomatrix(al,x2) == algtomatrix(al, algadd(al,x1,x2))); print("spl multiplicative: ", algtomatrix(al,x1) * algtomatrix(al,x2) == algtomatrix(al, algmul(al,x1,x2))); print("changebasis bug 1: ", algalgtobasis(al,algbasistoalg(al,algmul(al,x1,x2)))==algmul(al,x1,x2)); print("changebasis bug 2: ", algalgtobasis(al0,algmul(al0,ax1,ax2)) == algmul(al0,nx1,nx2)); print("changebasis bug 3: ", invord*algmul(al0,nx1,nx2) == algmul(al,x1,x2)); print("changebasis bug 4: ", algtomatrix(al,x1,1) == invord*algtomatrix(al0,nx1,1)*ord); print("algtableinit segfault bug: "); alt = algtableinit(al[9]); print(alt != 'alt); print("center of CSA: ", #algcenter(alt)==2); print("radical of CSA: ", algradical(alt)==0); print("decomposition of CSA: ", #algsimpledec(alt)[2]==1); dec = algsimpledec(alt); {print("alg_decomposition of CSA: ", #dec==2 && dec[1]==0 && #dec[2]==1 && #algcenter(dec[2][1])==2 && algdim(dec[2][1],1)==8);} print("alsimple bug"); mt = [matid(3), [0,0,0;1,1,0;0,0,0], [0,0,0;0,0,0;1,0,1]]; A = algtableinit(mt); algissimple(A) print("tests for al_CSA: "); T = y^3-y+1; nf = nfinit(T); m_i = [0,-1,0, 0;\ 1, 0,0, 0;\ 0, 0,0,-1;\ 0, 0,1, 0]; m_j = [0, 0,-1,0;\ 0, 0, 0,1;\ 1, 0, 0,0;\ 0,-1, 0,0]; m_k = [0, 0, 0, -1;\ 0, 0,-1, 0;\ 0, 1, 0, 0;\ 1, 0, 0, 0]; mt = [matid(4), m_i, m_j, m_k]; print(algisassociative(mt)); al = alginit(nf, mt, 'x); print(al != 0); print("algebra:"); print("csa getcenter: ", algcenter(al) == nf); print("csa getsplitting: ", algsplittingfield(al) != 0); print("getrelmultable: ", algrelmultable(al) == mt); print("getsplittingdata:"); print(#algsplittingdata(al) == 3); print(#algsplittingdata(al)[1] == 12); print(#algsplittingdata(al)[2] == 2); print(#algsplittingdata(al)[3][1,] == 12); print(#algsplittingdata(al)[3][,1] == 2); print(al[3][3]*al[3][2][,1] == [1,0]~); print(al[3][3]*al[3][2][,2] == [0,1]~); polabs = al[1][12][1].pol; for(i=1,10,\ print(al[3][3]*algmul(al, al[3][2][,1], algpow(al,al[3][1],i)) == [Mod(x^i,polabs),0]~);\ print(al[3][3]*algmul(al, al[3][2][,2], algpow(al,al[3][1],i)) == [0,Mod(x,polabs)^i]~)\ ); print("hasse invariants:"); do("hassei csa", () -> alghassei(al) == 0); do("hassef cas", () -> alghassef(al) == 0); do("hasse csa", () -> alghasse(al,1) == 0); print("csa splitting pol: ", poldegree(al[1][12][1].pol) == 6); print("csa basis: ", matsize(algbasis(al)) == [12,12]); print("csa invbasis: ", matsize(alginvbasis(al)) == [12,12]); print("csa absdim: ", #algmultable(al) == algdim(al,1)); print("csa char: ", algchar(al) == 0); print("csa deg: ", algdegree(al) == 2); print("csa dim: ", algdim(al) == 4); print("csa absdim: ", algdim(al,1) == 12); print("csa type: ", algtype(al) == 2); \\2==al_CSA print("csa iscommutative: ", algiscommutative(al)==0); print("csa issemisimple: ", algissemisimple(al)==1); print("elements:"); a = [0, Mod(y,T), 0, 0]~; b = [0, -1, Mod(2*y^2,T), 0]~; c = [Mod(1-y+2*y^2,T), 3, 0, Mod(-3*y,T)]~; mynorm(aa) = sum(i=1,4,aa[i]^2); algbasistoalg(al,a) algalgtobasis(al,[1,2,3,4,5,6,7,8,9,10,11,12]~) print("csa add: ", algadd(al,a,b) == a+b); print("csa neg: ", algneg(al,a) == -a); print("csa neg 2: ", algneg(al,b) == -b); print("csa sub: ", algsub(al,a,b) == a-b); print("csa mul: ", algmul(al,a,b) == [Mod(y,T), 0, 0, Mod(2*y-2,T)]~); print("csa mul 2: ", algmul(al,b,a) == [Mod(y,T), 0, 0, Mod(2-2*y,T)]~); print("csa sqr: ", algsqr(al,a) == [Mod(-y^2,T),0,0,0]~); print("csa sqr 2: ", algsqr(al,b) == [Mod(-1-4*y^4,T),0,0,0]~); print("csa mt: ", algrelmultable(al)*b == -m_i + Mod(2*y^2,T)*m_j); print("csa inv: ", alginv(al,a) == -1/y^2*a); print("csa inv 2: ", alginv(al,b) == -1/Mod(1+4*y^4,T)*b); print("csa divl: ", algdivl(al,1+a+b,b) == algmul(al, alginv(al, 1+a+b), b)); print("csa pow: ", algpow(al, a, 5) == Mod(y^4,T)*a); aa = algalgtobasis(al, a); bb = algalgtobasis(al, b); cc = algalgtobasis(al, c); print("csa mul 3: ", algmul(al,aa,b) == algalgtobasis(al,algmul(al,a,b))); print("csa mul 4: ", algmul(al,a,bb) == algalgtobasis(al,algmul(al,a,b))); print("csa pow 2: ", algpow(al,aa,13) == algalgtobasis(al,algpow(al,a,13))); print("csa sub 2: ", algsub(al,aa,b) == algalgtobasis(al,algsub(al,a,b))); print("csa sub 3: ", algsub(al,bb,a) == algalgtobasis(al,algsub(al,b,a))); print("csa inv 3: ", alginv(al,aa) == algalgtobasis(al,alginv(al,a))); print("csa inv 4: ", alginv(al,bb) == algalgtobasis(al,alginv(al,b))); print("csa inv 5: ", alginv(al,algadd(al,a,bb)) == algalgtobasis(al,alginv(al,algadd(al,a,b)))); print("csa trace: ", algtrace(al,cc) == 2*c[1]); print("csa trace 2: ", algtrace(al,c) == 2*c[1]); D = 12; flag = 1; for(i=1, D,\ for(j=i, D,\ ei = matid(D)[,i];\ ej = matid(D)[,j];\ flag = flag && (algtomatrix(al,ei)*algtomatrix(al,ej) == algtomatrix(al, algmul(al, ei, ej)));\ flag = flag && (algtomatrix(al,ei)+algtomatrix(al,ej) == algtomatrix(al, algadd(al, ei, ej)))\ )); print(flag); print("testcharpol"); testcharpol(al,elt) = print(algcharpoly(al,elt)==x^2-algtrace(al,elt)*x+mynorm(elt)); testcharpol(al,a); testcharpol(al,b); testcharpol(al,c); print("testcharpol2"); testcharpol2(al,elt) = print(algcharpoly(al,elt)==x^2-algtrace(al,elt)*x+mynorm(algbasistoalg(al,elt))); testcharpol2(al,aa); testcharpol2(al,bb); testcharpol2(al,cc); print("testnorm"); testnorm(al,elt) = print(algnorm(al,elt) == mynorm(elt)); testnorm(al,a); testnorm(al,b); testnorm(al,c); print("testnorm2"); testnorm2(al,elt) = print(algnorm(al,elt) == mynorm(algbasistoalg(al,elt))); testnorm2(al,aa); testnorm2(al,bb); testnorm2(al,cc); doubleindex(N,i,j) = (i-1)*N+j; matrixringmt(N) = { my(mt = [Mat([Col(0,N^2) | i<-[1..N^2]]) | j<-[1..N^2]], B, Bi, mt2=Vec(0,N^2)); for(i=1,N, for(j=1,N, for(k=1,N, mt[doubleindex(N,i,j)][doubleindex(N,i,k),doubleindex(N,j,k)] = 1 ) ) ); B = matid(N^2); for(i=1, N, B[doubleindex(N,i,i),1]=1); Bi = B^(-1); mt2[1] = matid(N^2); for(i=2,N^2, mt2[i] = Bi*mt[i]*B); mt2; } print("examples from docu"); setrand(1); algtype([]) A = alginit(nfinit(y),[-1,1]); algadd(A,[1,0]~,[1,2]~) algisinv(A,[-1,1]~) algisinv(A,[1,2]~,&ix) ix algisdivl(A,[x+2,-x-2]~,[x,1]~) algisdivl(A,[x+2,-x-2]~,[-x,x]~) algisdivl(A,[x+2,-x-2]~,[-x,x]~,&z) z A = alginit(nfinit(y^2-5),[2,y]); algalgtobasis(A,[y,1]~) algbasistoalg(A,algalgtobasis(A,[y,1]~)) algbasistoalg(A,[0,1,0,0,2,-3,0,0]~) algalgtobasis(A,algbasistoalg(A,[0,1,0,0,2,-3,0,0]~)) mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; A = algtableinit(mt,2); e = [0,1,0]~; one = [1,0,0]~; e2 = algsub(A,one,e); algcentralproj(A,[e,e2]) algprimesubalg(A) algquotient(A,[0;1;0]) algsubalg(A,[1,0; 0,0; 0,1]) algiscommutative(A) algissimple(A) mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; A = algtableinit(mt); algiscommutative(A) algissemisimple(A) algissimple(A) algissimple(A,1) nf = nfinit(y^2-5); A = alginit(nf, [-3,1-y]); alghassef(A) algdegree(A)^algdim(A,1)*nf.disc^algdim(A)*idealnorm(nf,alghassef(A)[1][2])^algdegree(A) algdisc(A) nf = nfinit(y^3-y+1); A = alginit(nf, [-1,-1]); algdim(A,1) algcenter(A).pol algdegree(A) algdim(A) nf = nfinit(y); p = idealprimedec(nf,7)[1]; p2 = idealprimedec(nf,11)[1]; A = alginit(nf,[3,[[p,p2],[1/3,2/3]],[0]]); algaut(A) algb(A) mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; A = algtableinit(mt,13); algchar(A) algtype(A) nf = nfinit(y^2-5); A = alginit(nf, [-1,2*y-1]); alghassef(A) A = alginit(nf, [-1,y]); alghassei(A) alghasse(A, 1) alghasse(A, 2) alghasse(A, idealprimedec(nf,2)[1]) alghasse(A, idealprimedec(nf,5)[1]) algindex(A, 1) algindex(A, 2) algindex(A, idealprimedec(nf,2)[1]) algindex(A, idealprimedec(nf,5)[1]) algindex(A) algisdivision(A, 1) algisdivision(A, 2) algisdivision(A, idealprimedec(nf,2)[1]) algisdivision(A, idealprimedec(nf,5)[1]) algisdivision(A) algissplit(A, 1) algissplit(A, 2) algissplit(A, idealprimedec(nf,2)[1]) algissplit(A, idealprimedec(nf,5)[1]) algissplit(A) algisramified(A, 1) algisramified(A, 2) algisramified(A, idealprimedec(nf,2)[1]) algisramified(A, idealprimedec(nf,5)[1]) algisramified(A) algramifiedplaces(A) nf = nfinit(y^2-5); pr = idealprimedec(nf,13)[1]; pol = nfgrunwaldwang(nf, [pr], [2], [0,-1], 'x) A = alginit(nfinit(y), [-1,-1]); alginvbasis(A) algbasis(A) algmultable(A) alginv(A,[1,1,0,0]~) algmul(A,[1,1,0,0]~,[0,0,2,1]~) algtomatrix(A,[0,1,0,0]~,1) algtomatrix(A,[0,x]~,1) algneg(A,[1,1,0,0]~) algtomatrix(A,[0,0,0,2]~) algpow(A,[1,1,0,0]~,7) algsub(A,[1,1,0,0]~,[1,0,1,0]~) algtrace(A,[5,0,0,1]~) algtype(A) nf = nfinit(y^3-5); a = y; b = y^2; {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} mt = [matid(4), m_i, m_j, m_k]; A = alginit(nf,mt,'x); algrelmultable(A) algsplittingfield(A).pol algsplittingdata(A) algtype(A) mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; A = algtableinit(mt,19); algnorm(A,[0,-2,3]~) A = algtableinit(mt); algnorm(A,[0,-2,3]~) m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; m_k=[0,0,0,-1;0,0,-1,0;0,1,0,0;1,0,0,0]; mt = [matid(4), m_i, m_j, m_k]; A = algtableinit(mt); algissemisimple(A) algissimple(A) algissimple(A,1) \\end examples print("matrices over algebras"); scal8(a) = vector(8,i,if(i==1,a,0))~; setrand(1); nf = nfinit(y^2-5); al = alginit(nf, [-1,-7]); setrand(1); M1 = [algrandom(al,2),algrandom(al,2);algrandom(al,2),algrandom(al,2)] M2 = [algrandom(al,2),algrandom(al,2);algrandom(al,2),algrandom(al,2)] print("mul alM: ", algmul(al,M1,M2)); a = [1,2,3,4,5,6,7,8]~; M = Mat([0,0]); M[1,1] = a; M[1,2] = a; algmul(al, M, [a,a,a;a,a,a]); print("sqr alM: ", algsqr(al,M1) == algmul(al,M1,M1)); print("divl alM: ", algmul(al,M1,algdivl(al,M1,M2)) == M2); print("divr alM: ", algmul(al,algdivr(al,M1,M2),M2) == M1); print("isinv alM: ", algisinv(al, M1)); print("isinv alM 2: ", algisinv(al, M2)); un = [1,0,0,0,0,0,0,0]~; zero = [0,0,0,0,0,0,0,0]~; id = [un,zero;zero,un]; {print("inv alM: ", algmul(al,M1,alginv(al,M1)) == id && algmul(al,alginv(al,M1),M1) == id);} {print("inv alM 2: ", algmul(al,M2,alginv(al,M2)) == id && algmul(al,alginv(al,M2),M2) == id);} print("neg alM: ", algneg(al,M1) == -M1); print("sub alM: ", algsub(al,M1,M2) == M1-M2); print("add alM: ", algadd(al,M1,M2) == M1+M2); print("algtobasis basistoalg alM 1: ", algalgtobasis(al, algbasistoalg(al, M1)) == M1); print("algtobasis basistoalg alM 2: ", algalgtobasis(al, algbasistoalg(al, M2)) == M2); print("algleftmultable add alM: ", algtomatrix(al, M1,1)+algtomatrix(al,M2,1) == algtomatrix(al, algadd(al, M1, M2),1)); print("algleftmultable mul alM: ", algtomatrix(al, M1,1)*algtomatrix(al,M2,1) == algtomatrix(al, algmul(al, M1, M2),1)); {print("algleftmultable sqr alM: ", algtomatrix(al, M1,1)^2 == algtomatrix(al, algsqr(al, M1),1));} print("algsplitm add alM: ", algtomatrix(al, M1)+algtomatrix(al,M2) == algtomatrix(al, algadd(al, M1, M2))); print("algsplitm mul alM: ", algtomatrix(al, M1)*algtomatrix(al,M2) == algtomatrix(al, algmul(al, M1, M2))); print("algsplitm sqr alM: ", algtomatrix(al, M1)^2 == algtomatrix(al, algsqr(al, M1))); print("algsplitm sqr alM 2: ", algtomatrix(al, M2)^2 == algtomatrix(al, algsqr(al, M2))); {print("algtrace alM: ", algtrace(al,M1) == algtrace(al,M1[1,1]) + algtrace(al,M1[2,2]));} {print("algtrace alM 2: ", algtrace(al,M2) == algtrace(al,M2[1,1]) + algtrace(al,M2[2,2]));} {print("algtrace prod alM: ", algtrace(al, algmul(al,M1,M2)) == algtrace(al, algmul(al,M2,M1)));} {print("algnorm alM: ", algnorm(al,algmul(al,M1,M2)) == algnorm(al,M1) * algnorm(al,M2));} {print("algnorm alM 2: ", algnorm(al,algmul(al,M2,M1)) == algnorm(al,M1) * algnorm(al,M2));} {print("algcharpoly alM: ", poldegree(algcharpoly(al,M1))==4 && polcoeff(algcharpoly(al,M1),3) == -algtrace(al,M1) && polcoeff(algcharpoly(al,M1),0) == algnorm(al,M1));} {print("algcharpoly alM 2: ", poldegree(algcharpoly(al,M2))==4 && polcoeff(algcharpoly(al,M2),3) == -algtrace(al,M2) && polcoeff(algcharpoly(al,M2),0) == algnorm(al,M2));} m = 15; n = -8; {print("pow alM: ", algmul(al, algpow(al,M1,m), algpow(al,M1,n)) == algpow(al,M1,m+n));} {print("pow alM 2: ", algmul(al, algpow(al,M2,m), algpow(al,M2,n)) == algpow(al,M2,m+n));} print("pow 0 alM: ", algpow(al,M1,0) == id); algbasistoalg(al,M1) algbasistoalg(al,M2) m1 = [1,2;3,4]; m2 = [5,6;7,8]; M1 = apply(scal8,m1); M2 = apply(scal8,m2); print("mul scalar alM: ", algmul(al,M1,M2) == apply(scal8,m1*m2)); m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; m_k=[0,0,0,-1;0,0,-1,0;0,1,0,0;1,0,0,0]; mt = [matid(4), m_i, m_j, m_k]; al = algtableinit(mt); setrand(10); M1 = [algrandom(al,2),algrandom(al,2);algrandom(al,2),algrandom(al,2)] M2 = [algrandom(al,2),algrandom(al,2);algrandom(al,2),algrandom(al,2)] print("mul alM t: ", algmul(al,M1,M2)); print("sqr alM t: ", algsqr(al,M1) == algmul(al,M1,M1)); print("divl alM t: ", algmul(al,M1,algdivl(al,M1,M2)) == M2); print("divr alM t: ", algmul(al,algdivr(al,M1,M2),M2) == M1); print("isinv alM t: ", algisinv(al, M1)); print("isinv alM t 2: ", algisinv(al, M2)); un = [1,0,0,0]~; zero = [0,0,0,0]~; id = [un,zero;zero,un]; {print("inv alM t: ", algmul(al,M1,alginv(al,M1)) == id && algmul(al,alginv(al,M1),M1) == id);} {print("inv alM t 2: ", algmul(al,M2,alginv(al,M2)) == id && algmul(al,alginv(al,M2),M2) == id);} print("neg alM t: ", algneg(al,M1) == -M1); print("sub alM t: ", algsub(al,M1,M2) == M1-M2); print("add alM t: ", algadd(al,M1,M2) == M1+M2); print("algleftmultable add alM t: ", algtomatrix(al,M1,1) + algtomatrix(al,M2,1) == algtomatrix(al, algadd(al,M1,M2),1)); print("algleftmultable mul alM t: ", algtomatrix(al,M1,1) * algtomatrix(al,M2,1) == algtomatrix(al, algmul(al,M1,M2),1)); print("algleftmultable sqr alM t: ", algtomatrix(al,M1,1)^2 == algtomatrix(al,algsqr(al,M1),1)); {print("algtrace alM t: ", algtrace(al,M1) == 2*(algtrace(al,M1[1,1]) + algtrace(al,M1[2,2])));} {print("algtrace alM t 2: ", algtrace(al,M2) == 2*(algtrace(al,M2[1,1]) + algtrace(al,M2[2,2])));} {print("algtrace prod alM t: ", algtrace(al, algmul(al,M1,M2)) == algtrace(al, algmul(al,M2,M1)));} {print("algnorm alM t: ", algnorm(al,algmul(al,M1,M2)) == algnorm(al,M1) * algnorm(al,M2));} {print("algnorm alM t 2: ", algnorm(al,algmul(al,M2,M1)) == algnorm(al,M1) * algnorm(al,M2));} {print("algcharpoly alM t: ", poldegree(algcharpoly(al,M1))==16 && polcoeff(algcharpoly(al,M1),15) == -algtrace(al,M1) && polcoeff(algcharpoly(al,M1),0) == algnorm(al,M1));} {print("algcharpoly alM t 2: ", poldegree(algcharpoly(al,M2))==16 && polcoeff(algcharpoly(al,M2),15) == -algtrace(al,M2) && polcoeff(algcharpoly(al,M2),0) == algnorm(al,M2));} m = 32; n = -63; {print("pow alM t: ", algmul(al, algpow(al,M1,m), algpow(al,M1,n)) == algpow(al,M1,m+n));} {print("pow alM 2 t: ", algmul(al, algpow(al,M2,m), algpow(al,M2,n)) == algpow(al,M2,m+n));} print("pow 0 alM t: ", algpow(al,M2,0) == id); T = y^3-y+1; nf = nfinit(T); print("csa al2"); setrand(1); al2 = alginit(nf, matrixringmt(2), 'x); print("al2 contains nfabs: ", algsplittingfield(al2)[12][1] != 0); al2b = al2; al2b[1][12][1] = 0; \\ depends on 32/64bit print(al2b); print("csa al3"); al3 = alginit(nf, matrixringmt(3), 'x); print("al3 contains nfabs: ", algsplittingfield(al3)[12][1] != 0); \\limit cases print("trivial algebra over a quadratic field"); al = alginit(rnfinit(nfinit(y^2+1),x),[y,1]) a = [y]~ b = [1-2*y]~ c = [-3,1]~ algadd(al,a,b) algsub(al,c,a) algmul(al,a,b) algdivl(al,b,c) algdivr(al,c,b) alginv(al,a) algalgtobasis(al,b) algtomatrix(al,a) algtomatrix(al,a,1) algcharpoly(al,b) algtrace(al,c) algnorm(al,c) algiscommutative(al) algissemisimple(al) algissimple(al) alghasse(al,1) alghasse(al,idealprimedec(nfinit(y^2+1),2)[1]) algindex(al) algisdivision(al) algissplit(al) algisramified(al) algramifiedplaces(al) print("trivial algebra over Q"); al = alginit(rnfinit(nfinit(y),x),[y,1]) a = [-2]~ b = [1/3]~ c = [4/5]~ algadd(al,a,b) algsub(al,c,a) algmul(al,a,b) algdivl(al,b,c) algdivr(al,c,b) alginv(al,a) algalgtobasis(al,b) algtomatrix(al,a,1) algtomatrix(al,b) algcharpoly(al,b) algtrace(al,c) algnorm(al,c) algiscommutative(al) algissemisimple(al) algissimple(al) alghasse(al,1) alghasse(al,idealprimedec(nfinit(y),2)[1]) algindex(al) algisdivision(al) algissplit(al) algisramified(al) algramifiedplaces(al) print("trivial CSA over Q"); al = alginit(nfinit(y), [Mat(1)]); algsqr(al,[Mod(3,y)]~) algsqr(al,[2]~) print("nontrivial CSA over Q"); {m_i = [0,-1,0, 0; 1, 0,0, 0; 0, 0,0,-1; 0, 0,1, 0]; m_j = [0, 0,-1,0; 0, 0, 0,1; 1, 0, 0,0; 0,-1, 0,0]; m_k = [0, 0, 0, -1; 0, 0,-1, 0; 0, 1, 0, 0; 1, 0, 0, 0]; mt = [matid(4), m_i, m_j, m_k];} al = alginit(nfinit(y), mt); algsqr(al,[Mod(3,y),Mod(2,y),Mod(1,y),Mod(2,y)]~) algsqr(al,[2,3,4,5]~) print("empty matrices"); al = alginit(nfinit(y), [-1,-1]); print("-v: ", algneg(al,[;]) == [;]); print("v^(-1): ", alginv(al,[;]) == [;]); print("v^n: ", algpow(al, [;], 13) == [;]); print("v^0: ", algpow(al, [;], 0) == [;]); print("mt(v)", algtomatrix(al, [;], 1) == [;]); print("spl(v)", algtomatrix(al, [;]) == [;]); print("trace(v): ", algtrace(al, [;]) == 0); print("norm(v): ", algnorm(al, [;]) == 1); print("charpoly(v): ", algcharpoly(al, [;]) == 1 && type(algcharpoly(al,[;])) == "t_POL"); print("v+v: ", algadd(al,[;],[;]) == [;]); print("v-v: ", algsub(al,[;],[;]) == [;]); print("v*v: ", algmul(al,[;],[;]) == [;]); print("v/v: ", algdivr(al,[;],[;]) == [;]); print("v\\v: ", algdivl(al,[;],[;]) == [;]); v1 = matrix(0,1); print("v*nv: ", algmul(al,v1,matid(1))==v1); print("v*v 2: ", algmul(al,[;],matrix(0,1))==matrix(0,1)); print("trace(v) char 2: ", algtrace(algtableinit([matid(1)],2), [;]) == 0); mt0 = [Mat([1])]; almt0 = algtableinit(mt0,0) a = [12]~ b = [-1/7]~ algadd(almt0,a,b) algsub(almt0,a,b) algmul(almt0,a,b) algneg(almt0,a) alginv(almt0,a) algsqr(almt0,b) algdivl(almt0,a,b) algtrace(almt0,a) algnorm(almt0,b) algcharpoly(almt0,a) algtomatrix(almt0,b,1) algpow(almt0,a,0) algiscommutative(almt0) algissemisimple(almt0) algissimple(almt0) algisdivision(almt0) print("trivial tensor product"); al1 = alginit(nfinit(y),1); al2 = alginit(nfinit(y),2); print(algtensor(al1,al2)==al2); print(algtensor(al2,al1)==al2); print("splitting a nasty commutative algebra"); {mt = [matid(8), [0,2,0,0,0,0,0,0; 1,0,0,0,0,0,0,0; 0,0,0,2,0,0,0,0; 0,0,1,0,0,0,0,0; 0,0,0,0,0,2,0,0; 0,0,0,0,1,0,0,0; 0,0,0,0,0,0,0,2; 0,0,0,0,0,0,1,0], [0,0,3,0,0,0,0,0; 0,0,0,3,0,0,0,0; 1,0,0,0,0,0,0,0; 0,1,0,0,0,0,0,0; 0,0,0,0,0,0,3,0; 0,0,0,0,0,0,0,3; 0,0,0,0,1,0,0,0; 0,0,0,0,0,1,0,0], [0,0,0,6,0,0,0,0; 0,0,3,0,0,0,0,0; 0,2,0,0,0,0,0,0; 1,0,0,0,0,0,0,0; 0,0,0,0,0,0,0,6; 0,0,0,0,0,0,3,0; 0,0,0,0,0,2,0,0; 0,0,0,0,1,0,0,0], [0,0,0,0,5,0,0,0; 0,0,0,0,0,5,0,0; 0,0,0,0,0,0,5,0; 0,0,0,0,0,0,0,5; 1,0,0,0,0,0,0,0; 0,1,0,0,0,0,0,0; 0,0,1,0,0,0,0,0; 0,0,0,1,0,0,0,0], [0,0,0,0,0,10,0, 0; 0,0,0,0,5, 0,0, 0; 0,0,0,0,0, 0,0,10; 0,0,0,0,0, 0,5, 0; 0,2,0,0,0, 0,0, 0; 1,0,0,0,0, 0,0, 0; 0,0,0,2,0, 0,0, 0; 0,0,1,0,0, 0,0, 0], [0,0,0,0,0,0,15, 0; 0,0,0,0,0,0, 0,15; 0,0,0,0,5,0, 0, 0; 0,0,0,0,0,5, 0, 0; 0,0,3,0,0,0, 0, 0; 0,0,0,3,0,0, 0, 0; 1,0,0,0,0,0, 0, 0; 0,1,0,0,0,0, 0, 0], [0,0,0,0,0, 0, 0,30; 0,0,0,0,0, 0,15, 0; 0,0,0,0,0,10, 0, 0; 0,0,0,0,5, 0, 0, 0; 0,0,0,6,0, 0, 0, 0; 0,0,3,0,0, 0, 0, 0; 0,2,0,0,0, 0, 0, 0; 1,0,0,0,0, 0, 0, 0] ];} {chg = [1, 0,0,0,0,0, 0, 0; 0, 1,0,0,0,0, 0, 0; 0,-2,1,1,0,0, 0, 0; 0,-1,0,1,0,0, 0, 0; 0, 0,0,0,1,1,-2, 0; 0, 0,0,0,0,1, 0,-1; 0, 0,0,0,0,0, 1, 0; 0, 0,0,0,0,0, 0, 1];} chgi = chg^(-1); mt2 = vector(8,j,chgi*sum(i=1,8,chg[i,j]*mt[i])*chg); algisassociative(mt2) al = algtableinit(mt2); algiscommutative(al) algissemisimple(al) setrand(9991); algissimple(al,1) print("non associative algebra"); mt = [matid(3), [0,2,3;1,4,5;0,6,7], [0,8,9;0,10,11;1,12,13]]; algisassociative(mt) print("csa without maximal order"); alginit(nfinit(y), [matid(1)], 'x, 0); print("simplify bug #1671"); test(str,al)={ my(sal = simplify(al), x, y); setrand(1); print("testing simplify: ", str); print(algtype(al) == algtype(sal)); print(algdim(al) == algdim(sal)); setrand(11); x = algrandom(al,3); y = algrandom(al,10); print(algsqr(al,x) == algsqr(sal,x)); print(algtomatrix(al,x) == algtomatrix(sal,x)); print(algcharpoly(al,x) == algcharpoly(sal,x)); print(algnorm(al,x) == algnorm(sal,x)); print(algtomatrix(al,x,1) == algtomatrix(sal,x,1)); print(algtrace(al,x) == algtrace(sal,x)); print(alginv(al,x) == alginv(sal,x)); print(algpow(al,x,42) == algpow(sal,x,42)); print(algmul(al,x,y) == algmul(sal,x,y)); print(algdivl(al,x,y) == algdivl(sal,x,y)); print(algbasistoalg(al,x) == algbasistoalg(sal,x)); x = algbasistoalg(al,x); print(algbasistoalg(al,y) == algbasistoalg(sal,y)); y = algbasistoalg(al,y); print(algsqr(al,x) == algsqr(sal,x)); print(algtomatrix(al,x) == algtomatrix(sal,x)); print(algcharpoly(al,x) == algcharpoly(sal,x)); print(algnorm(al,x) == algnorm(sal,x)); print(algtomatrix(al,x,1) == algtomatrix(sal,x,1)); print(algtrace(al,x) == algtrace(sal,x)); print(alginv(al,x) == alginv(sal,x)); print(algpow(al,x,42) == algpow(sal,x,42)); print(algmul(al,x,y) == algmul(sal,x,y)); print(algdivl(al,x,y) == algdivl(sal,x,y)); print(algadd(al,x,y) == algadd(al,x,simplify(y))); print(algmul(al,x,y) == algmul(al,x,simplify(y))); print(algmul(al,x,y) == algmul(al,simplify(x),simplify(y))); }; test("degree 1 cyclic over Q", alginit(nfinit(y),1)); test("degree 1 cyclic over Q(i)", alginit(nfinit(y^2+1),1)); test("degree 1 csa over Q", alginit(nfinit(y), [matid(1)])); test("degree 1 csa over Q(i)", alginit(nfinit(y^2+1), [matid(1)])); test("quatalg over Q(s5)", alginit(nfinit(y^2-5), [-2,-3])); {m_i = [0,-1,0, 0; 1, 0,0, 0; 0, 0,0,-1; 0, 0,1, 0]; m_j = [0, 0,-1,0; 0, 0, 0,1; 1, 0, 0,0; 0,-1, 0,0]; m_k = [0, 0, 0, -1; 0, 0,-1, 0; 0, 1, 0, 0; 1, 0, 0, 0]; mt = [matid(4), m_i, m_j, m_k];} test("quatalg csa over Q", alginit(nfinit(y), mt)); m = matcompanion(x^4+1); mt = [m^i | i <- [0..3]]; al = algtableinit(mt); B = [1,0;0,0;0,1/2;0,0] al2 = algsubalg(al,B); \\ bad inputs m_i = [0,-1,0, 0;\ 1, 0,0, 0;\ 0, 0,0,-1;\ 0, 0,1, 0]; m_j = [0, 0,-1,0;\ 0, 0, 0,1;\ 1, 0, 0,0;\ 0,-1, 0,0]; m_k = [0, 0, 0, -1;\ 0, 0,-1, 0;\ 0, 1, 0, 0;\ 1, 0, 0, 0]; mt = [matid(4), m_i, m_j, m_k]; almt = algtableinit(mt,0); algsplittingfield(almt); algdegree(almt); alghassei(almt); alghassef(almt); algrandom(1,1) algrandom(1,I) algtype(1) algdim([1,[1],0,0,0,0,0,0,0,0]) algdim([1,[1],0,0,0,0,0,0,0,0],1) algtensor(al,al2) algtensor(al2,al) algtensor(1,z,1) algisassociative([1],0) algisassociative([[1,0;0,2],[0,0;0,0]]) algmul(almt,a,b) algtomatrix(almt,a,1) alginv(almt,a) algalgtobasis(almt,a) algbasistoalg(almt,[0,0,0,0]~) algpoleval(almt,1,a) zero = [0,0,0,0]~; m = Mat([1,1]); m[1,1]=zero; m[1,2]=zero; algadd(almt, [zero;zero], m) algadd(almt, [zero;zero;zero], [zero;zero]); algsub(almt, [zero;zero], m) algsub(almt, [zero;zero;zero], [zero;zero]); algmul(almt, m, [zero;zero;zero]); algsqr(almt, [zero;zero]); algdivl(almt, m, zero); algdivl(almt, m, [zero,zero;zero,zero]); algdivl(almt, m, m); alginv(almt, m); algtomatrix(almt,m,1); algpow(almt, m, 3); algtrace(almt, m); algcharpoly(almt, m); algcharpoly(alginit(nfinit(y),[-1,-1]), m); algnorm(almt, m); algnorm(alginit(nfinit(y),[-1,-1]), m); alginit(nfinit(y),[2,[[],[]],[x]]) alginit(nfinit(y),[2,[],[1,1]]) alginit(nfinit(y),[2,[[],[]],Vecsmall([1])]) alginit(y,[2,[[],[]],[1]]) alginit(nfinit(y), y) alginit(nfinit(y), [1,2,3,4]) algtableinit(mt,y); alginit(nfinit(y^2+1),-3); alginit(nfinit(x^2+1),3); highvar = varhigher("highvar"); alginit(nfinit(highvar^2+1),3); al = alginit(nfinit(y^2-2),[-1,-1]); algrandom(al,-10) al = alginit(nfinit(y^2-2),[-1,-1]); algrelmultable(al); algsplittingdata(al); alghasse(almt, 1); algindex(almt, 1); algisdivision(almt); algissplit(almt); algisramified(almt); algramifiedplaces(almt); alghasse(al, -1); alghasse(al, 3); alghasse(al, 2^100); alghasse(al, []); alghasse(al, 1/3); algtableinit([matid(2), [0,1/2;1,0]]); Q = nfinit(y); alginit(Q, [matid(2), [0,1/2;1,0]]); alginit(Q, [-1/2, -1]); alginit(Q, [-1, -1/2]); alginit(rnfinit(Q, x^2+1), [-x,-1/2]); algsqr([0,0,0,0,0,0,0,0,0,0,0],[]~); algsqr([0,0,0,0,0,0,0,0,[],0,0],[]~); algsqr([0,0,0,0,0,0,0,0,[0],0,0],[]~); algsqr([0,0,0,0,0,0,0,0,[[;]],0,0],[]~); algsqr([[],0,0,0,0,0,0,0,[[;]],0,0],[]~); algsqr([[],[0],0,0,0,0,0,0,[[;]],0,0],[]~); algdim([[],[0],0,0,0,0,0,0,[[;]],0,0]); algdegree([[],[0],0,0,0,0,0,0,[[;]],0,0]); algdegree([rnfinit(nfinit(y),x),[[]],0,0,0,0,0,0,[[;]],0,0]); algcenter([rnfinit(nfinit(y),x),[[]],0,0,0,0,0,0,[[;]],0,0]); algcentralproj(almt,0); algcentralproj(almt,[zero,zero]); algsubalg(almt,0); algisassociative([]); algisassociative([matid(2),Mat([1,1])]); algisassociative([[1,2;3,4],matid(2)]); algisassociative([matid(1)],[]); algsqr(algtableinit([matid(1)]),[1,2]~); algsqr(al,vector(691)~); algsqr(al,[1,2,3,4,5,6,7,f^2]~); algsqr(al,[f^3,[]]~); algmul(al,[;],[1,2]~); algdivl(al,[;],matid(1)); algdivl(al,matid(1),matrix(1,2)); alginv(al,[0,0]~); al0mt = algtableinit([matid(1)]); algalgtobasis(al0mt,[1]~); algbasistoalg(al0mt,[1]~); nfgrunwaldwang(nfinit(y),0,[],[],'x); nfgrunwaldwang(nfinit(y),[2],'x-'x,[1]); alginit(rnfinit(nfinit(y),x),0); alginit(rnfinit(nfinit(y),x),[1,2,3,4]); alginit(nfinit(y), [matid(2),matid(2)]); alginit(nfinit(y), [matid(2),[0,1;1,0]]); nfgrunwaldwang(nfinit(y), 0, [], [0]); nfgrunwaldwang(nfinit(y), [2], [], [0]); nfgrunwaldwang(nfinit(y), [2], [2], []); nfgrunwaldwang(nfinit(y), [2], [6], [0]); nfgrunwaldwang(nfinit(y), [2,3], [2,3], [0]); nfgrunwaldwang(nfinit(y), [2], [3], [-1]); nfgrunwaldwang(nfinit(y), [[]~], [3], [-1]); nfgrunwaldwang(nfinit(y), [2], [9], [0]); mt=[matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; A=algtableinit(mt,2); algdegree(A) algsub(A,1,1) algadd(A,1,1) algneg(A,1) algmul(A,1,1) algsqr(A,1) algdivl(A,1,1) algdivr(A,1,1) alginv(A,1) a='a; K=nfinit(a);PR=idealprimedec(K,2);A=alginit(K,[3,[PR,[1]],[-1]]); K=nfinit(a);P2=idealprimedec(K,2);P3=idealprimedec(K,3);A=alginit(K,[3,[concat(P2,P3),[1/3,-2/3]],[1/3]]); algtensor(alginit(nfinit(y),2),alginit(nfinit(y^2+1),3)); algtensor(alginit(nfinit(y),2),alginit(nfinit(y),2)); nf = nfinit(y); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1]; \\alginit(nf, [2, [[p2,p3],[1/2,1/2]], [0]]); alginit(nf, [2, [[p2,p2],[1/2,1/2]], [0]]); alginit(nf, [2, [[p2,p3],[1/2,1/2]], [0,0]]); alginit(nf, [2, [[p2,p3],[1/2,1/2],0], [0]]); alginit(nf, [2, [0,[1/2,1/2]], [0]]); alginit(nf, [2, [[p2,p3],0], [0]]); alginit(nf, [2, [[p2,p3],[1/2,1/2,0]], [0]]); alginit(nf, [2, [[p2,p3],[1/2,1/2]], [1/3]]); al = alginit(nfinit(y),[-1,-1]); setrand(23); a = algrandom(al,2); algcharpoly(al,a,'z); al = alginit(nfinit(y^2+7), [-1,-1]); algcharpoly(al,[1,2,3]~); algindex(1, 1) al = alginit(nfinit(y), [Mat(1)]); algsqr(al,[Mod(1,y),Mod(2,y)]~) {m_i = [0,-1,0, 0; 1, 0,0, 0; 0, 0,0,-1; 0, 0,1, 0]; m_j = [0, 0,-1,0; 0, 0, 0,1; 1, 0, 0,0; 0,-1, 0,0]; m_k = [0, 0, 0, -1; 0, 0,-1, 0; 0, 1, 0, 0; 1, 0, 0, 0]; mt = [matid(4), m_i, m_j, m_k];} al = alginit(nfinit(y), mt); algsqr(al,[Mod(1,y),Mod(2,y)]~) alfail = alginit(nf, [0,0], 'x); algb(al); algaut(al); algtableinit([Mat(1)],1) algtableinit([Mat(1)],4) al = alginit(nfinit(y),[-1,-1]); algpoleval(al,x+1,"toto") algpoleval(al,x+1,[1,2,3]) algpoleval(al,x+1,[1,2]) a = [1..4]~; b = [5..8]~; mb = algtomatrix(al,b,1); algpoleval(al,x+1,[a,mb]); algpoleval(al,x+1,[1,mb]); alginit(nfinit(y),["a",[[],[]],[]]); alginit(nfinit(y),[1,[[],[]],[]]); alginit(nfinit(y),[0,[[],[]],[]]); \\end bad inputs print("new algsimpledec"); \\ K^3 mt = [matid(3),[0,0,0;1,1,0;0,0,0],[0,0,0;0,0,0;1,0,1]]; al = algtableinit(mt); algissimple(al) algsimpledec(al,1) al2 = algtableinit(mt,5); algissimple(al2) algsimpledec(al2,1) \\ upper-tri in M2(K) mt = [matid(3),[0,0,0;1,1,0;0,0,1],[0,0,0;0,0,0;1,0,0]]; al = algtableinit(mt); algsimpledec(al,1) al2 = algtableinit(mt,5); algsimpledec(al2,1) print("norm(,1)"); nf = nfinit(y^2-5); B = alginit(nf,[-1,y]); b = [x,1]~; algnorm(B,b,1) n = algnorm(B,b) nfeltnorm(nf,n)^2 algnorm(B,b/3,1) algnorm(B,[3,5,1,6,7,-2,1/7,0]~,1) m = [[1/3,y]~,[0,0]~;[y+1,y-1]~,[1..8]~]; algnorm(B,m,1)==matdet(algtomatrix(B,m,1)) a = algrandom(B,2); algnorm(B,a,1)*algnorm(B,b,1)==algnorm(B,algmul(B,a,b),1) print("trace(,1)"); nf = nfinit(y^2-5); A = alginit(nf,[-1,y]); a = [1+x+y,2*y]~*Mod(1,y^2-5)*Mod(1,x^2+1); t = algtrace(A,a) algtrace(A,a,1) algdegree(A)*nfelttrace(nf,t) b = [1+x/3+y,y-x/7]~*Mod(1,y^2-5)*Mod(1,x^2+1); algdegree(A)*nfelttrace(nf,algtrace(A,b))==algtrace(A,b,1) c = [4/3,2,1,6,8,9,-1,3/2]~; algdegree(A)*nfelttrace(nf,algtrace(A,c))==algtrace(A,c,1) m = [[y,x]~*Mod(1,y^2-5)*Mod(1,x^2+1),[1,0]~;[1..8]~,[1/7,5,6,7,8,1/4,1/3,1/2]~]; 2*algdegree(A)*nfelttrace(nf,algtrace(A,m))==algtrace(A,m,1) algtrace(A,[[1,0]~,[0,0]~;[0,0]~,[1,0]~],1)==4*algdim(A,1) print("charpoly(,1)"); nf = nfinit(y^2-5); al = alginit(nf,[-3-y,y]); pol = nf.pol; polrel = algsplittingfield(al).pol; a = [y,1+x]~*Mod(1,pol)*Mod(1,polrel); P = lift(algcharpoly(al,a)) algcharpoly(al,a,,1) lift(P*subst(P,y,-y)*Mod(1,pol))^2 b = [1+x/3+y/2,3*y-x/7]~*Mod(1,pol)*Mod(1,polrel); P = lift(algcharpoly(al,b)); Q = algcharpoly(al,b,,1); Q == lift(P*subst(P,y,-y)*Mod(1,pol))^2 c = [4/3,2,1/7,6,4,9,-1,3/2]~; P = lift(algcharpoly(al,c)); Q = algcharpoly(al,c,,1); Q == lift(P*subst(P,y,-y)*Mod(1,pol))^2 {m = [[y/3,x+1]~*Mod(1,pol)*Mod(1,polrel),[1,7/11]~; [1..8]~,[1/7,5,6,7/2,8,1/4,1,-1/2]~];} P = lift(algcharpoly(al,m)); Q = algcharpoly(al,m,,1); Q==lift(P*subst(P,y,-y)*Mod(1,pol))^4 print("more al_MAT tests"); setrand(1); nf=nfinit(y^2-5); pol = nf.pol; al=alginit(nf,[y,-1]); polrel = algsplittingfield(al).pol; m1 = matrix(2,2,i,j,algrandom(al,1)/(i+2*j)); {m2 = matrix(2,2,i,j,vector(2,k,random(2)+random(2)*x+random(2)*y+ random(2)*x*y)~*Mod(1,polrel)*Mod(1,pol)/prime(i+2*j));} {m3 = [[1,0]~,[1..8]~;[y+x,y-x]~*Mod(1,polrel)*Mod(1,pol), [1,3,5,0,-1,-2,0,-2]~/3];} print("add"); algadd(al,m1,m2)==algadd(al,m2,m1) algadd(al,m1,m3)==algadd(al,m3,m1) algadd(al,m1,m2)==algadd(al,m2,m1) algadd(al,algadd(al,m1,m2),m3) == algadd(al,m1,algadd(al,m2,m3)) print("alg/basis"); algalgtobasis(al,m1) == m1 algbasistoalg(al,m2) == m2 algalgtobasis(al,algbasistoalg(al,algalgtobasis(al,m1))) == algalgtobasis(al,m1) algalgtobasis(al,algbasistoalg(al,algalgtobasis(al,m2))) == algalgtobasis(al,m2) algalgtobasis(al,algbasistoalg(al,algalgtobasis(al,m3))) == algalgtobasis(al,m3) algbasistoalg(al,algalgtobasis(al,algbasistoalg(al,m1))) == algbasistoalg(al,m1) algbasistoalg(al,algalgtobasis(al,algbasistoalg(al,m2))) == algbasistoalg(al,m2) algbasistoalg(al,algalgtobasis(al,algbasistoalg(al,m3))) == algbasistoalg(al,m3) print("charpoly"); mid = [[1,0]~,[0,0]~;[0,0]~,[1,0]~]; t = 123/7; testcp(m)= { my(P,Q); P = algcharpoly(al,m); print(algnorm(al,m) == polcoeff(P,0)); print(algtrace(al,m) == -polcoeff(P,3)); print(algnorm(al,algsub(al,m,t*mid))==subst(P,x,t)); Q = algcharpoly(al,m,,1); print(algnorm(al,m,1) == polcoeff(Q,0)); print(algtrace(al,m,1) == -polcoeff(Q,31)); print(algnorm(al,algsub(al,m,t*mid),1)==subst(Q,x,t)); } testcp(m1); testcp(m2); testcp(m3); print("inv/div"); algisinv(al,m1,&m1i) m1i == alginv(al,m1) algdivl(al,m1,m2) == algmul(al,m1i,m2) algdivr(al,m2,m1) == algmul(al,m2,m1i) algisdivl(al,m1,m3,&d13) algdivl(al,m1,m3) == d13 algisinv(al,m2,&m2i) m2i == alginv(al,m2) algdivl(al,m2,m1) == algmul(al,m2i,m1) algdivr(al,m1,m2) == algmul(al,m1,m2i) algisdivl(al,m2,m3,&d23) algdivl(al,m2,m3) == d23 algisinv(al,m3,&m3i) m3i == alginv(al,m3) algdivl(al,m3,m1) == algmul(al,m3i,m1) algdivr(al,m1,m3) == algmul(al,m1,m3i) algisdivl(al,m3,m2,&d32) algdivl(al,m3,m2) == d32 midbasis = [[1,0,0,0,0,0,0,0]~,vector(8)~;vector(8)~,[1,0,0,0,0,0,0,0]~]; algmul(al,m1i,m1) == midbasis algmul(al,m1,m1i) == midbasis algmul(al,m2i,m2) == midbasis algmul(al,m2,m2i) == midbasis algmul(al,m3i,m3) == midbasis algmul(al,m3,m3i) == midbasis print("mul"); algmul(al,algmul(al,m1,m2),m3) == algmul(al,m1,algmul(al,m2,m3)) algmul(al,m1,algadd(al,m2,m3)) == algadd(al, algmul(al,m1,m2), algmul(al,m1,m3)) algmul(al,algadd(al,m1,m2),m3) == algadd(al,algmul(al,m1,m3),algmul(al,m2,m3)) print("neg"); algadd(al,m1,algneg(al,m1)) == 0 algadd(al,m2,algneg(al,m2)) == 0 algadd(al,m3,algneg(al,m3)) == 0 print("norm"); algnorm(al,m1)*algnorm(al,m2) == algnorm(al,algmul(al,m1,m2)) algnorm(al,m1)*algnorm(al,m3) == algnorm(al,algmul(al,m1,m3)) algnorm(al,m3)*algnorm(al,m2) == algnorm(al,algmul(al,m3,m2)) print("pow"); algpow(al,m1,5) == algmul(al,algpow(al,m1,2),algpow(al,m1,3)) algalgtobasis(al,algpow(al,m2,3)) == algmul(al,algpow(al,m2,5),algpow(al,m2,-2)) algpow(al,m3,3) == algmul(al,algpow(al,m3,-1),algpow(al,m3,4)) print("sqr"); algsqr(al,m1) == algpow(al,m1,2) algsqr(al,m2) == algpow(al,m2,2) algsqr(al,m3) == algpow(al,m3,2) print("sub"); algsub(al,m2,m3) == algadd(al,m2,algneg(al,m3)) algsub(al,m1,m3) == algadd(al,m1,algneg(al,m3)) algsub(al,m1,m2) == algadd(al,m1,algneg(al,m2)) print("trace"); algtrace(al,m2)+algtrace(al,m3) == algtrace(al,algadd(al,m2,m3)) algtrace(al,m1)+algtrace(al,m3) == algtrace(al,algadd(al,m1,m3)) algtrace(al,m1)+algtrace(al,m2) == algtrace(al,algadd(al,m1,m2)) print("algtomatrix"); sm1 = algtomatrix(al,m1); sm2 = algtomatrix(al,m2); sm3 = algtomatrix(al,m3); #sm1==4 #sm1[,1]==4 sm2+sm3 == algtomatrix(al,algadd(al,m2,m3)) sm2*sm3 == algtomatrix(al,algmul(al,m2,m3)) sm1+sm3 == algtomatrix(al,algadd(al,m1,m3)) sm1*sm3 == algtomatrix(al,algmul(al,m1,m3)) sm1+sm2 == algtomatrix(al,algadd(al,m1,m2)) sm1*sm2 == algtomatrix(al,algmul(al,m1,m2)) print("algleftmultable"); M1 = algtomatrix(al,m1,1); M2 = algtomatrix(al,m2,1); M3 = algtomatrix(al,m3,1); #M1==32 #M1[,1]==32 #M2==32 #M2[,1]==32 #M3==32 #M3[,1]==32 M2+M3 == algtomatrix(al,algadd(al,m2,m3),1) M2*M3 == algtomatrix(al,algmul(al,m2,m3),1) M1+M3 == algtomatrix(al,algadd(al,m1,m3),1) M1*M3 == algtomatrix(al,algmul(al,m1,m3),1) M1+M2 == algtomatrix(al,algadd(al,m1,m2),1) M1*M2 == algtomatrix(al,algmul(al,m1,m2),1) print("more al_CSA tests"); setrand(1); nf = nfinit(y^2-5); mti = [0,-1,0,0;[1,0]~,0,0,0;0,0,0,-1;0,0,1,0]; mtj = [0,0,Mod(y,y^2-5),0;0,0,0,-y;1,0,0,0;0,-1,0,0]; mtk = [0,0,0,y;0,0,[1,2]~,0;0,1,0,0;1,0,0,0]; mt = [matid(4),mti,mtj,mtk]; al = alginit(nf,mt); a1 = [1/2,-3,2,4/3,-1,0,1,2/5]~; a2 = [1+2*y,y/3,5/2,-3*y/7]~*Mod(1,y^2-5); a3 = algrandom(al,2)/13; aid = [1,0,0,0]~; algadd(al,algadd(al,a1,a2),a3) == algadd(al,a1,algadd(al,a2,a3)) algadd(al,a1,a2) == algadd(al,a2,a1) algbasistoalg(al,algalgtobasis(al,algbasistoalg(al,a1))) == algbasistoalg(al,a1) algalgtobasis(al,algbasistoalg(al,algalgtobasis(al,a2))) == algalgtobasis(al,a2) t = 7/3; testcp(a)= { my(P,Q); P = algcharpoly(al,a); print(algnorm(al,a) == polcoeff(P,0)); print(algtrace(al,a) == -polcoeff(P,1)); print(algnorm(al,algsub(al,a,t*aid))==subst(P,x,t)); Q = algcharpoly(al,a,,1); print(algnorm(al,a,1) == polcoeff(Q,0)); print(algtrace(al,a,1) == -polcoeff(Q,7)); print(algnorm(al,algsub(al,a,t*aid),1)==subst(Q,x,t)); } print("charpoly"); testcp(a1); testcp(a2); testcp(a3); print("inv/div"); algisinv(al,a1,&a1i) a1i == alginv(al,a1) algdivl(al,a1,a2) == algmul(al,a1i,a2) algdivr(al,a2,a1) == algmul(al,a2,a1i) algisdivl(al,a1,a3,&d13) algdivl(al,a1,a3) == d13 aidbasis = vector(8,i,i==1)~; algmul(al,a1i,a1) == aidbasis algmul(al,a1,a1i) == aidbasis a2i = alginv(al,a2); print("mul"); algmul(al,a2i,a2) == aid algmul(al,a2,a2i) == aid algmul(al,algmul(al,a1,a2),a3) == algmul(al,a1,algmul(al,a2,a3)) print("neg"); algadd(al,a1,algneg(al,a1)) == 0 algadd(al,a2,algneg(al,a2)) == 0 algadd(al,a3,algneg(al,a3)) == 0 print("norm"); algnorm(al,a1)*algnorm(al,a2) == algnorm(al,algmul(al,a1,a2)) algnorm(al,a1)*algnorm(al,a3) == algnorm(al,algmul(al,a1,a3)) algnorm(al,a3)*algnorm(al,a2) == algnorm(al,algmul(al,a3,a2)) print("pow"); algpow(al,a1,5) == algmul(al,algpow(al,a1,2),algpow(al,a1,3)) algpow(al,a2,3) == algmul(al,algpow(al,a2,5),algpow(al,a2,-2)) algpow(al,a3,3) == algmul(al,algpow(al,a3,-1),algpow(al,a3,4)) print("sqr"); algsqr(al,a1) == algpow(al,a1,2) algsqr(al,a2) == algpow(al,a2,2) algsqr(al,a3) == algpow(al,a3,2) print("sub"); algsub(al,a2,a3) == algadd(al,a2,algneg(al,a3)) algsub(al,a1,a3) == algadd(al,a1,algneg(al,a3)) algsub(al,a1,a2) == algadd(al,a1,algneg(al,a2)) print("trace"); algtrace(al,a2)+algtrace(al,a3) == algtrace(al,algadd(al,a2,a3)) algtrace(al,a1)+algtrace(al,a3) == algtrace(al,algadd(al,a1,a3)) algtrace(al,a1)+algtrace(al,a2) == algtrace(al,algadd(al,a1,a2)) print("algtomatrix"); sa1 = algtomatrix(al,a1); sa2 = algtomatrix(al,a2); sa3 = algtomatrix(al,a3); #sa1==2 #sa1[,1]==2 sa2+sa3 == algtomatrix(al,algadd(al,a2,a3)) sa2*sa3 == algtomatrix(al,algmul(al,a2,a3)) sa1+sa3 == algtomatrix(al,algadd(al,a1,a3)) sa1*sa3 == algtomatrix(al,algmul(al,a1,a3)) sa1+sa2 == algtomatrix(al,algadd(al,a1,a2)) sa1*sa2 == algtomatrix(al,algmul(al,a1,a2)) print("algleftmultable"); ma1 = algtomatrix(al,a1,1); ma2 = algtomatrix(al,a2,1); ma3 = algtomatrix(al,a3,1); #ma1==8 #ma1[,1]==8 #ma2==8 #ma2[,1]==8 ma2+ma3 == algtomatrix(al,algadd(al,a2,a3),1) ma2*ma3 == algtomatrix(al,algmul(al,a2,a3),1) ma1+ma3 == algtomatrix(al,algadd(al,a1,a3),1) ma1*ma3 == algtomatrix(al,algmul(al,a1,a3),1) ma1+ma2 == algtomatrix(al,algadd(al,a1,a2),1) ma1*ma2 == algtomatrix(al,algmul(al,a1,a2),1) print("csa pol/polmod bugs"); setrand(1); nf = nfinit(y^2-5); mti = [0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; mtj = [0,0,y,0;0,0,0,-y;1,0,0,0;0,-1,0,0]; mtk = [0,0,0,y;0,0,y,0;0,1,0,0;1,0,0,0]; mt = [matid(4),mti,mtj,mtk]; al = alginit(nf,mt*Mod(1,nf.pol)); algrelmultable(al) a = [y,y,y,y/3]~; algpow(al,a,4) algpow(al,a,-2) algmul(al,a,a) algnorm(al,a) == algnorm(al,algalgtobasis(al,a)) algnorm(al,a,1) == algnorm(al,algalgtobasis(al,a),1) algtrace(al,a) == algtrace(al,algalgtobasis(al,a)) algtrace(al,a,1) == algtrace(al,algalgtobasis(al,a),1) algcharpoly(al,a) == algcharpoly(al,algalgtobasis(al,a)) algcharpoly(al,a,,1) == algcharpoly(al,algalgtobasis(al,a),,1) algtomatrix(al,a) == algtomatrix(al,algalgtobasis(al,a)) print("csa: denom over Z[y] but not over ZK"); setrand(1); nf = nfinit(y^2-5); mti = [0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; mtj = [0,0,(y-1)/2,0;0,0,0,-(y-1)/2;1,0,0,0;0,-1,0,0]; mtk = [0,0,0,(y-1)/2;0,0,(y-1)/2,0;0,1,0,0;1,0,0,0]; mt = [matid(4),mti,mtj,mtk]; al = alginit(nf,mt*Mod(1,nf.pol)); algrelmultable(al) mti = [0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; mtj = [0,0,(y-1)/3,0;0,0,0,-(y-1)/3;1,0,0,0;0,-1,0,0]; mtk = [0,0,0,(y-1)/3;0,0,(y-1)/3,0;0,1,0,0;1,0,0,0]; mt = [matid(4),mti,mtj,mtk]; al = alginit(nf,mt*Mod(1,nf.pol)); print("al_MAT over al_CSA"); setrand(1); nf = nfinit(y^2-5); mti = [0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; mtj = [0,0,(y-1)/2,0;0,0,0,-(y-1)/2;1,0,0,0;0,-1,0,0]; mtk = [0,0,0,(y-1)/2;0,0,(y-1)/2,0;0,1,0,0;1,0,0,0]; mt = [matid(4),mti,mtj,mtk]; al = alginit(nf,mt*Mod(1,nf.pol)); m1 = [algrandom(al,2)/2,algrandom(al,1)/3;algrandom(al,2)/5,algrandom(al,3)]; m2 = [[y,1/2,2-y,0]~,[3,y/2,-3*y,1]~;[7,0,0,y]~,[1-y,2,-y,0]~]; algnorm(al,algmul(al,m1,m2)) == algnorm(al,m1)*algnorm(al,m2) algnorm(al,algmul(al,m1,m2),1) == algnorm(al,m1,1)*algnorm(al,m2,1) algtrace(al,algadd(al,m1,m2)) == algtrace(al,m1)+algtrace(al,m2) algtrace(al,algadd(al,m1,m2),1) == algtrace(al,m1,1)+algtrace(al,m2,1) mid = [[1,0,0,0]~,vector(4)~;vector(4)~,[1,0,0,0]~]; t = -3/7; testcp(m)= { my(P,Q); P = algcharpoly(al,m); print(algnorm(al,m) == polcoeff(P,0)); print(algtrace(al,m) == -polcoeff(P,3)); print(algnorm(al,algsub(al,m,t*mid))==subst(P,x,t)); Q = algcharpoly(al,m,,1); print(algnorm(al,m,1) == polcoeff(Q,0)); print(algtrace(al,m,1) == -polcoeff(Q,31)); print(algnorm(al,algsub(al,m,t*mid),1)==subst(Q,x,t)); } testcp(m1); testcp(m2); print("algleftmultable"); M1 = algtomatrix(al,m1,1); M2 = algtomatrix(al,m2,1); #M1==32 #M1[,1]==32 #M2==32 #M2[,1]==32 M1+M2 == algtomatrix(al,algadd(al,m1,m2),1) M1*M2 == algtomatrix(al,algmul(al,m1,m2),1) print("nfgrunwaldwang SEGV #1669"); nfgrunwaldwang(nfinit(y),[2,3],[1,2],Vecsmall(1)) nfgrunwaldwang(nfinit(x),[2,3],[1,2],Vecsmall(1)) \\alg_model bug for 1-dim al_CSA al = alginit(nfinit(y),[matid(1)]); algtomatrix(al,[Mod(1,y)]~) algtomatrix(al,[1]~) algtomatrix(al,[1+y-y]~) algtomatrix(al,[1/2]~) algtomatrix(al,[Mod(1/2,y)]~) \\al_MATRIX sqr bug al = algtableinit([matid(2),[0,0;1,0]],2); m = [[1,1]~,[1,0]~;[0,1]~,[0,0]~]; type(algsqr(al,m))=="t_MAT" \\algpoleval type check setrand(1); nf = nfinit(y^2-5); al = alginit(nf,[y,-1]); a = [1..8]~; pol = algcharpoly(al,a); algpoleval(al,pol,a)==0 algpoleval(al,pol,[;]) pol = algcharpoly(al,a,,1); algpoleval(al,pol,a)==0 ma = algtomatrix(al,a,1); algpoleval(al,pol,[a,ma])==0 \\not implemented al = algtableinit([Mat(1)]); al2 = algtensor(al,al); al = algtableinit([Mat(1)],2); al2 = algtensor(al,al); pari-2.11.2/src/test/in/objets0000644000175000017500000000156313201017466014550 0ustar billbilldefault(realprecision,38); \e +3 -5 5+3 5-3 5/3 5\3 5\/3 5%3 5^3 binary(65537) bittest(10^100,100) ceil(-2.5) centerlift(Mod(456,555)) component(1+O(7^4),3) conj(1+I) conjvec(Mod(x^2+x+1,x^3-x-1)) truncate(1.7,&e) e denominator(12345/54321) divrem(345,123) divrem(x^7-1,x^5+1) floor(-1/2) floor(-2.5) frac(-2.7) I^2 imag(2+3*I) lex([1,3],[1,3,5]) max(2,3) min(2,3) Mod(-12,7) norm(1+I) norm(Mod(x+5,x^3+x+1)) numerator((x+1)/(x-1)) 1/(1+x)+O(x^20) numtoperm(7,1035) permtonum([4,7,1,6,3,5,2]) 37. real(5-7*I) shift(1,50) shift([3,4,-11,-12],-2) shiftmul([3,4,-11,-12],-2) sign(-1) sign(0) sign(0.) simplify(((x+I+1)^2-x^2-2*x*(I+1))^2) sizedigit([1.3*10^5,2*I*Pi*exp(4*Pi)]) truncate(-2.7) truncate(sin(x^2)) type(Mod(x,x^2+1)) valuation(6^10000-1,5) \p 57 Pi \p 38 O(x^12) padicno=(5/3)*127+O(127^5) padicprec(padicno,127) length(divisors(1000)) Mod(10873,49649)^-1 (1+I)*(1+1/2*I) pari-2.11.2/src/test/in/ispower0000644000175000017500000000646713457566441015001 0ustar billbilldo(n)= my(k,z); if (k=ispower(n,,&z), print([k,z])); {v = [ 3^101*2^20, 3^101*2^101, 3^101*2^101*5, 2^20*3^15*5^5, 2^3*103^6, 2^5*103^10, 2^7*103^10, 2^15*103^10, 2^21*103^42, 2^35*103^70, 2^105*103^210, 103^100003, 541^121 ]; } for (i=1, #v, do(v[i])) for (i=1, 10^6, do(i)) \\#1259 do(-16) do(-64) do(-8) do(-8 * 103^6) do(-1/64) ispower(2,2^64) ispower(1/2,2^64) for (i=1, #v, if (!ispowerful(v[i]), print(i))) ispowerful(5^3*(10^1000+1)^2) v = [1, 2^10, 2^15, 2^32, 2^64, 2^128]; /* correct = vector(#v); { for (k = 1, #v, my(u = v[k], s,t); for(i=u, u+10^4, if ((a = ispower(i,,&p)) && isprime(p), s += a; t += p); if (isprime(i), s ++; t += i); ); correct[k] = [s,t]; ) } */ { for (k = 1, #v, my(u = v[k], s,t); s = sum(i=u, u+10^4, isprimepower(i)); t = 0;for (i = u, u+10^4, if (isprimepower(i,&p), t += p)); print([s,t]); \\ if ([s,t] != correct[k], error(k)) ) } n=(2^100+277)^10; ispseudoprimepower(n) ispseudoprimepower(n,&p) p isprimepower(541^121) ispowerful(4) p = 10^6+3; q = 10^6+33; r = 10^6+37; v = [Mod(p, p^2*q), Mod(6*p, q*(p*r)^2), Mod(6, p^2*q), Mod(4*p, 8*p^2*q)]; [ispower(a,2) | a<-v] [ispower(a,3) | a<-v] [if(ispower(a,2,&b), b) | a<-v] [if(ispower(a,3,&b), b) | a<-v] [if(issquare(a^2,&b), b) | a<-v] [if(ispower(a^3,3,&b), b) | a<-v] ispower(Mod(2, 7*5^3), 7, &z); z issquare(Mod(1,2)) issquare(Mod(0,2),&s);s issquare(Mod(2,3)) issquare(Mod(13,121)) issquare(Mod(Mod(1,2)*y,y^3+y^2+1)) if (issquare(Mod(Mod(1,2)*y,y^3+y^2+1),&b),b) issquare(Mod(Mod(1,5)*y+2,y^3+y^2+1)) if (issquare(Mod(Mod(1,5)*y,y^3+y^2+1),&b),b) if (issquare(Mod(Mod(4,5),y^3+y^2+1),&b),b) default(realprecision,38); if(issquare(Pol(0),&z),z) issquare(Pol(4)) issquare(x^2+x) issquare(y^2*x^0) issquare(x^0/4) if(issquare(y^2*x^0,&z),z) issquare(2*x^4+x^3+Mod(1,2)) issquare(x^2+Mod(1,2)) if(issquare(x^2+Mod(1,2),&z),z) t=ffgen(2^3,'t); if(issquare((t*x^2+(1+t)*x+1)^2,&z),z) if(issquare((x^4+x^3+3*x^2+2*x+4)*Mod(1,5),&z),z) if(issquare(4/x^2,&z),z) issquare(1.5) if(issquare(1.5,&z),z) issquare(4/9) issquare(4/3) issquare(I) issquare(ffgen(2^3,'t)) if(issquare(ffgen(2^3,'t),&z),z) issquare(O(x)) issquare(x+O(x^2)) issquare(4*x^2+O(x^3)) issquare(4/x^2) if (issquare(x^0/4,&z),z) if (issquare((x+1/2)^2,&z),z) if (issquare(x^0/4,&z),z) issquare(Mod(1,4)*x^2) issquare(Mod(1,4)*(x+1)^2) issquare(Mod(x,Mod(x^2+x+2,3))) ispower(-8,4) if(ispower(-8,3,&z),z) ispower(-8/27,3) if(ispower(-8/27,3,&z),z) ispower(Pol(0),3) ispower(x^2,3) ispower(x^3+x,3) ispower(x^3+4,3) if(ispower(Pol(8),3,&z),z) if(ispower((2+x)^3,3,&z),z) ispower((2+x)^3-1,3) ispower(1009^11) ispower(-1.,3) ispower(I,3) if(ispower(1/(2*x)^3,3,&z), z) if(ispower(1+x+O(x^2),3,&z), z) if(ispower((-2/3)^5,5,&z),z) ispower(3^(11^2)) ispower((2/3)^(11^2)) ispower(30011^(17*11)) issquare(Mod(3,22)) \\#1703 ispower(-167^10) \\#1782 isprimepower(30011^(17*3)) do(f,k) = ispower(f,k,&z) && z^k == f; test(t) = { my(T = 5*t*(x^3+x^2+t)*(x^2+t*x+1)^3); [do(T,3), do(T^6,3), do(T^9,3), do(T^18,3), do(T^18,9), do(T^18,18)]; } test(Mod(1,2)) test(Mod(1,3)) test(Mod(1,17)) test(Mod(1,nextprime(2^100))) test(ffgen(2^3,'t)) test(ffgen(3^3,'t)) test(ffgen([nextprime(2^100),3],'t)) test(Mod(Mod(1,2),y^3+y^2+1)) ispower(Mod(x,x^2+1), 2, &y) ispower(Mod(x,x^2+1), 2) p=2^1500+1465; ispower(p^11) ispower(p^29) ispower(p^101) \\#1915 issquare(Mod(1,67)*x^4+Mod(14,67)*x^2+Mod(49,67)) pari-2.11.2/src/test/in/gamma0000644000175000017500000000144213272130645014343 0ustar billbilldefault(realprecision,38); default(seriesprecision,6); gamma(2+I+x) gamma(1+x) gamma(2+x) gamma(-2+x) lngamma(2+I+x) lngamma(1+x) lngamma(-2+x) lngamma(2+x) lngamma(1) lngamma(1.) psi(2+I+x) psi(1+x) psi(-2+x) gamma(-1/2+x) gamma(1+a*x+O(x^2)) lngamma(1+a*x+O(x^2)) gamma(O(x)) lngamma(O(x)) psi(O(x)) gamma(0.+1/2*x+O(x^2)) psi(x) gamma(x) gamma(1000) psi(2^400) psi(-1.5) psi(x+O(x^2)) real(psi((3/2+0.E-38*I)+x/2+O(x^2))) gamma(x+O(x^2)) gamma(-1-10^-16) gamma(10^-16) lngamma(-1-10^-16) lngamma(10^-16) binomial(2^64+1,2) binomial(1001.,1000) lngamma(2^301) lngamma(2^301 + 2*I) lngamma(2^64 + 2*I) lngamma(-200.5) gammah(400) gammah(400+I) default(realprecision,115); lngamma(2^301 + 2*I) lngamma(2^301 + 200*I) default(realprecision,154); lngamma(2^301 + 2000*I) gamma(1+10^-30) gamma(-1e-6) pari-2.11.2/src/test/in/aurifeuille0000644000175000017500000000057011636712103015565 0ustar billbillalias(factor_Aurifeuille,"_factor_Aurifeuille") do(d, a) = polcyclo(d, a) / factor_Aurifeuille(a, d); do(35, -7*3^2) do(35, 5*3^2*7^2) do(70, 7*3^2) do(70, -5*3^2) do(44, 2*11*9^2) do(44, 2*11) do(12,6) do(4,8) do(100,2) alias(factor_Aurifeuille_prime,"_factor_Aurifeuille_prime") do(d, a) = polcyclo(d, a) / factor_Aurifeuille_prime(a, d); do(12, 2) do(15, 5) do(30, 3) pari-2.11.2/src/test/in/cyclo0000644000175000017500000000154213036414402014365 0ustar billbillallocatemem(8000000); poliscyclo(1) poliscyclo(x^0) poliscyclo(x) for (i=1,100, if (poliscyclo(polcyclo(i)) != i, error(i))) for (i=1,100, if (!poliscycloprod(x^i-1), error(i))) poliscyclo(polcyclo(10^5)) poliscyclo(polcyclo(12345)) { for (i=1,10, f = polcyclo(i); for(j=i+1,10, g = f*polcyclo(j); if (poliscyclo(g), error("is ", [i,j])); if (!poliscycloprod(g), error("prod ", [i,j])); print (polcyclofactors(g)) ) ); } poliscycloprod((x-1)^2) poliscycloprod((x+1)^2*(x-1)) test(n,t)= if (polcyclo(n,t) != subst(polcyclo(n),x,t), error([n,t])); test(5,1);test(5,-1); test(10,1);test(10,-1); test(40,1);test(40,-1); test(2,-1); test(10,-1); test(11,-1); test(5,Mod(-1,3)) \\ roots of 1 test(20, I) test(10, Mod(3,11)) test(10, 2 + O(11)) test(30, -1.0) z15 = Mod(t,polcyclo(15,t)); test(15, z15) test(30, z15) test(105, z15) pari-2.11.2/src/test/in/characteristic0000644000175000017500000000046213326135265016255 0ustar billbillv=[1,1.,Mod(1,6),1/2,I+Mod(1,3), O(2), quadgen(5)*Mod(1,3), Mod(1,x)]; for (i=1,#v, print(characteristic(v[i]))) characteristic(v) characteristic(matid(2)*Mod(1,2)) characteristic([]) characteristic(List()) characteristic(ffgen(2^3)) characteristic([ffgen(2),ffgen(3)]) characteristic([ffgen(2),Mod(1,3)]) pari-2.11.2/src/test/in/polred0000644000175000017500000000675513326135265014565 0ustar billbillrnfpolredbest(nfinit(quadpoly(5,y)),x^7-14*x^5+56*x^3-56*x+22) \\ rnfpolred(nfinit(quadpoly(1996,y)),quadray(1996,1)) \\ rnfpolred(nfinit(quadpoly(904,y)),quadray(904,1)) K=nfinit(quadpoly(29,y)); T=quadray(29,17) rnfpolredabs(K,T) rnfpolredbest(K,T) rnfpolredabs(K,[T,100],16) rnfpolredbest(K,[T,100]) K=nfinit(y^3-y-1); T=x^3-x-1; rnfpolredabs(K,T) rnfpolredabs(K,T,2) [P,a]=rnfpolredbest(K,T,1); subst(K.pol,y,a) [P,a,b]=rnfpolredbest(K,T,3); subst(K.pol,y,a) substvec(T,[x,y],[a,b]) rnfpolred(nfinit(quadpoly(1129,y)),quadray(1129,1)); nfinit(Pol([256,-2560,5120,6400,-60320,6976,116320,72560,-456615,270630,-129362])); polredabs(quadpoly(14586217464)) { p=x^32 - 1680*x^30 + 1026480*x^28 - 289096080*x^26 + 39933334980*x^24 - 2715474610800*x^22 + 88886222283600*x^20 - 1619990314513200*x^18 + 17928141864081750*x^16 - 125620995771054000*x^14 + 565267786831818000*x^12 - 1629524362237758000*x^10 + 2978275448322310500*x^8 - 3393290168363970000*x^6 + 2319247705779270000*x^4 - 866101453967610000*x^2 + 135345425000900625; #polredabs(p,4) } polredabs(x^12+139968*x^10+24814646784*x^8+1854249948463104*x^6+177954917169813848064*x^4-1827912356210202139164672*x^2+68504919608701082757419237376); polredabs(x^4+10^21*x^2+1) polredabs(x^4+146077*x^2+2629386) polredabs(y^4-2*y^3-24*y^2+61*y+2,1) \\#1146 polredabs(x^9-4*x^7-3*x^6+9*x^5+8*x^4-6*x^3-9*x^2-4*x-1) \\#1228 polredabs(x^5-13*x^3+3*x^2+5*x-1) \\#1229 polredabs(x^6+21471450*x^2+71643071500) polredbest(x^6+21471450*x^2+71643071500) polredbest(4*x^4+146077*x^2+2629386) polredabs(2*x+1) polredabs(2*x+1,1) polred([x,[1]]) polred(2*x+1) polred(2*x+1,1) polred(4*x^2+1,2) polredbest(2*x+1) polredbest(2*x+1,1) polredbest(4*x^2+1,1) polredord(2*x+1) polredord(4*x^2+1) \\ #1519, test T->unscale != 1 polredbest(x^8+24*x^6+80*x^5+1040*x^4-4288*x^3-12736*x^2-61952*x+311296,1) \\ #1511 polredabs(x^16-4*x^15-334*x^14+264*x^13+32231*x^12+57392*x^11-1031422*x^10-3628868*x^9+7185297*x^8+42417784*x^7+11283472*x^6-137773504*x^5-127243504*x^4+69059728*x^3+56307944*x^2-6264432*x+6436) \\ #1653 default(parisize, 3<<23); f=x^40+10*x^39+75*x^38+410*x^37+1888*x^36+7364*x^35+25310*x^34+77140*x^33+211669*x^32+524946*x^31+1183823*x^30+2430610*x^29+4548530*x^28+7743916*x^27+11954920*x^26+16627228*x^25+20626386*x^24+22445616*x^23+20835590*x^22+15611648*x^21+8209812*x^20+1290846*x^19-2562740*x^18-2525172*x^17-76374*x^16+2095346*x^15+2320830*x^14+1050748*x^13-71120*x^12-238080*x^11+31952*x^10+106808*x^9+12549*x^8-18470*x^7-485*x^6+3202*x^5-232*x^4-430*x^3+150*x^2-20*x+1; polredbest(f); polredabs(x^5 - 331137220*x^4 + 37922047405356360*x^3 - 1127174691845938128093840*x^2 + 52208293424667465123438066822480*x - 16507431553557006099641796204889368224) f=5*x^12+13*x^4+11*x^3+2*x+1; [g,h] = polredabs(f,1); [g,subst(f,x,h)] \\ #1961 polredabs(x^15-15*x^13-2*x^12+78*x^11-10*x^10-393*x^9+81*x^8+939*x^7-373*x^6-822*x^5+723*x^4-1588*x^3-57*x^2+127*x-13) \\ #1963 f=x^23-4324*x^21-6486*x^20+5382299*x^19-23233933*x^18-2724444300*x^17+29686323629*x^16+512000507352*x^15-10294412120640*x^14+6885232378569*x^13+1102283075184770*x^12-8796561210816172*x^11-7798660667836453*x^10+474243077814357335*x^9-2826995282155771181*x^8+5949260040976823570*x^7+9167317157190582864*x^6-81864894718917833350*x^5+204445625295748936871*x^4-269173314235796280477*x^3+199912058984322799237*x^2-78929282232647458634*x+12862216057817467245; polredabs(f)==f K=nfinit(z^4 + 50*z^2 + 45); u=rnfpolredabs(K,x^4 - 6*x^2 - 5*x - 1) rnfpolredabs(K,u) \\ #2054 K=nfinit(polcyclo(5,t)); rnfpolredabs(K, y^2+(t^3+3*t^2+3*t+1)*y+(-53*t^3-10*t-10), 1) pari-2.11.2/src/test/in/ellsea0000644000175000017500000000517313326135265014536 0ustar billbilldefault(parisize,"16M"); do(i,v)= { E = ellinit([0,0,0,v[2],v[3]]*Mod(1,v[1])); print(i, ": ", ellap(E,v[1])); } { v=[[202600005603433095160409308644759862837,25496852782325453225973142890909600552,129550610797481291887769966647995045232], [173327739907566197112155895875385467119,52716988591102938437323369716512206005,43087597392844950895070462564402654315], [523583591335747530615071369664554118036421993253,25679429559575246581833628827363203226862930934,78220741356817481602535950765825830003112603824], [1319450668936329467137913739322239157303860926441,807652438980115949692649657326438677571309575087,1017125626316888896817395440127041355136940446205], [439581010348913995032270658729785287035964480323270935583,323922016281172901245123590380881598241426088528431020005,54496426275749371996644207660602248980615186517525561222], [2979720374579183569554262247145622188470249961843364603751,428654869348535206084607029945439317783967748844874233571,1182279475380088064870625220629639405548336474256523329003], [6243380271698146227966925307851825694742847655729810693741,4068721281680536125235363885580194460678653324971583338307,2519148351962491328666249705249360758373031631978108875818], [1606938044258990275541962092341162602522202993782792835304761,1,252199199707645577897249048746397012330572101453777389069968], [1267650600228229401496703205953,1,417990942431022911086532367249], [590295810358705651741,1,3], [18446744073709551629,1,42]]; } for(i=1,#v, do(i,v[i])); J= {[Mod(139969198258936384621998533779, 896615193897208487551655423041), Mod(153550450851144056623726364403,1160030981035862964864325445299), Mod(386229222639189135614980939195,529656639561667839197968630433), Mod(543979953519664739130128566041,817701636704151811034504702087), Mod(80210534001353032236065226821, 983440823277044783790077069059), Mod(1293115044598381293398949316, 383857664397975779060725841281)]; } for(i=1,#J, print(i,":",ellcard(ellinit(ellfromj(J[i]))))) g=ffgen(nextprime(2^32)^2);E=ellinit([g,3]);ellap(E) b=ffgen(37^18,'b);E=ellinit(ellfromj(b));ellap(E) p = 1048845330395786101209709; E = ellinit([1,56], p); ellsea(E,1) ellsea(E,2) a=ffgen(ffinit(nextprime(2^30),3),'a); E = ellinit([1,a]); ellsea(E,1) ellsea(E,2) ellsea(ellinit([1,519],523)) p = nextprime(2^100); E = ellinit([1122988618244467583984567614936, 429172847969450664478514342664], p); ellsea(E, -1) E = ellinit([1213812743793711191989251498394, 677975617584150034841507871840], p); ellsea(E, 2) ellsea(E, -2) p=1048845330395786101209839; E = ellinit([1,15], p); F=ellinit([1,-15], p); ellsea(E, 1) ellsea(E, -1) ellsea(F, 1) ellsea(F, -1) ellsea(E, 7) ellsea(E, -7) ellsea(F, 7) ellsea(F, -7) pari-2.11.2/src/test/in/nfpolsturm0000644000175000017500000000103413326135265015472 0ustar billbillnf = nfinit(polsubcyclo(11,5,'y)); t = x^2 - nf.zk[2]; nfpolsturm(nf, t) nfpolsturm(nf, t, 1) nfpolsturm(nf, t, [1..4]) nfpolsturm(nf, -1) nfpolsturm(nf, y) nfpolsturm(nf, Mod(y,nf.pol)) nfpolsturm(nf, x^2-(y+950385237198502187979577282097391163977102921506573742575513/495253880608585631635195731645995689515566957889181807495428)) nf=nfinit(a^2-2); for(n=1,100,if(nfpolsturm(nf,x^2-Mod(a+1,a^2-2)^n)!=[if (n%2,0,2),2],print(n))) \\ Errors nfpolsturm(nf, a, 3) nfpolsturm(nf, a, [-1..1]) nfpolsturm(nf, a, [1..3]) nfpolsturm(nf, 0, 1) pari-2.11.2/src/test/in/polmodular0000644000175000017500000001551513201017466015442 0ustar billbillhash_base = 2^64; init_h = 5381; split_Z(n) = { my (bits = 8, base = 2^bits, sgn = sign(n) % base, res = []); n = abs(n); while (n != 0, res = concat(res, bitand(n, base - 1)); n = shift(n, -bits)); res = concat(res, sgn); } glue(h, a) = bitand((((h << 5) + h) + a), hash_base - 1); hash_Z(n) = { my (v = split_Z(n), h = init_h); for (i = 1, #v, h = glue(h, v[i])); h; } hash_ZX(pol) = { my (v = Vec(pol), h = init_h); for (i = 1, #v, h = glue(h, hash_Z(v[i]))); h; } hash_ZXX(pol) = { my (v = [Vec(c) | c <- Vec(pol)], h = init_h); for (i = 1, #v, h = glue(h, hash_ZX(v[i]))); h; } { lvl_idx = [0, 1, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 0, 0, 7, 0, 8, 0, 0, 0, 9]; modpoly_hashes = [ 953115400354185, 619732354788530567, 7671381920119322245, 1662362517513198972, 11499552816775494464, 10945716853871337038, 1858790070632847848, 16279119036202003022, 9091292905489559584 ]; } check_modpoly(L, hash, inv = 0) = { if (hash_ZXX(polmodular(L, inv)) != hash, error("Bad modpoly")); } default(parisize, "32M"); { MAX_LEVEL = 23; \\ This already gives 89% coverage in 1.2s forprime(L = 2, MAX_LEVEL, check_modpoly(L, modpoly_hashes[lvl_idx[L]])); modfn_in = [[2, 5, 7818678061185], [5, 1, 14017670839540699521], [5, 5, 10135583858468178383], [7, 1, 6937006200180283618], [7, 5, 9634555674574853739], [19, 1, 11245295902670825360], [29, 1, 16325532180637558646], [47, 1, 5045713438637349850], [61, 5, 5614541323969591564], [71, 0, 8840690212199031415], [101, 1, 18403372459340572304], [139, 1, 4966835288214143418], [359, 1, 15999826932501894898], \\ takes 3s, no smaller example though :( [5, 6, 14025475434705720054], [5, 9, 4070138482583618498], [7, 10, 2092081457940371680], [3, 14, 7826463370842897], [2, 15, 7613995049265], [5, 21, 2152391919677952616], [3, 26, 7840368574373379], [2, 35, 8034981587292], [2, 39, 8034981863898], [5, 2, 14025475647798473994], [5, 23, 4078176315075291878], [7, 24, 15539023920884183490], [5, 27, 2153788462654972246], [5, 28, 4579080621787198547], [41, 2, 18150754343002627833], [41, 5, 3465379807262449566], [41, 6, 12863521307608118553], [41, 9, 5674021873271863077], [41, 10, 15269149163413540837], [41, 14, 12129179001644404437], [41, 15, 445355180908304715], [41, 21, 9618478875553953373], [41, 23, 7613336307888355697], [41, 24, 7221767736513486251], [41, 26, 2777849492219862654], [41, 27, 1438586205409091583], [41, 28, 8177252307561913215], [41, 35, 8718342713488965926], [41, 39, 1857869646559265631], [29, 21, 140598897682543022], [101, 21, 1028254489804326757], [53, 15, 11992315117197580073], \\ NB: The hashes for these tests do not come from \\ an independent source [17, 3, 7524902883828545591], [19, 3, 13749860608403259582], [19, 4, 451945996748663121], [19, 8, 13661084005765275348] ]; for (i = 1, #modfn_in, my (in = modfn_in[i]); check_modpoly(in[1], in[3], in[2])); \\ Check that specifying variables works my (phi7 = polmodular(7)); if (phi7 != polmodular(7, , 'x, 'y) || phi7 != polmodular(7, , 'x) || polmodular(7, , 's, 't) != substvec(phi7, ['x, 'y], ['s, 't]), error("Bad variables")); \\ Check argument checking my (got_err); iferr (polmodular(7, , "I am the queen of France", 'x), err, got_err = 1, errname(err) == "e_TYPE"); if ( ! got_err, error("No type error from bad param")); got_err = 0; iferr (polmodular(7, , ffgen(2^3), 'x), err, got_err = 1, errname(err) == "e_DOMAIN"); if ( ! got_err, error("No domain error from non-prime field arg")); got_err = 0; iferr (polmodular(1), err, got_err = 1, errname(err) == "e_DOMAIN"); if ( ! got_err, error("No error from level 1")); got_err = 0; iferr (polmodular(6), err, got_err = 1, errname(err) == "e_IMPL"); if ( ! got_err, error("No error from composite level")); got_err = 0; iferr (polmodular(7, , 'x, 'y, 1), err, got_err = 1, errname(err) == "e_FLAG"); if ( ! got_err, error("No error from inappropriate flag")); got_err = 0; iferr (polmodular(7, , 'x, 'x), err, got_err = 1, errname(err) == "e_PRIORITY"); if ( ! got_err, error("No error from same variables")); got_err = 0; iferr (polmodular(7, , 'y, 'x), err, got_err = 1, errname(err) == "e_PRIORITY"); if ( ! got_err, error("No error from bad variables")); got_err = 0; iferr (polmodular(3, 5); polmodular(2, 1), err, got_err = 1, errname(err) == "e_DOMAIN"); if ( ! got_err, error("No error from incompatible level/invariant pair")); got_err = 0; iferr (polmodular(19, 7), err, got_err = 1, errname(err) == "e_DOMAIN"); if ( ! got_err, error("No error from bad invariant")); } all(v) = { my (r = 1); for (i = 1, #v, r = r && v[i]); r; } poloftype(f, tp) = { type(f) == "t_POL" && all([type(polcoeff(f, d)) == tp | d <- [0 .. poldegree(f)]]); } lift_ffx(f) = { my (v = Vec(f)); if ( ! all([poldegree(c.pol) == 0 | c <- v]), error("Polynomial has coeffs in extension")); Pol([polcoeff(c.pol, 0) | c <- Vec(f)], variable(f)); } check_eval_modpoly(L, j, p, expected) = { my (jm = Mod(j, p), jf = j * ffgen(p)^0, um = polmodular(L, , jm, 'y, 0), uf = polmodular(L, , jf, 'y, 0), vm = polmodular(L, , jm, 'y, 1), vf = polmodular(L, , jf, 'y, 1)); if ( ! poloftype(um, "t_INTMOD") || ! poloftype(uf, "t_FFELT") || type(vm) != "t_VEC" || #vm != 3 || type(vf) != "t_VEC" || #vf != 3, error("Invalid return type")); if ( ! all([poloftype(v, "t_INTMOD") | v <- vm]) || ! all([poloftype(v, "t_FFELT") | v <- vf]), error("Invalid coefficients")); if (um != vm[1] || uf != vf[1] || lift(um) != lift_ffx(uf) || hash_ZX(lift(um)) != expected[1], error("Wrong result for modpoly eval")); if (hash_ZX(lift(vm[2])) != expected[2], error("Wrong derivative")); if (hash_ZX(lift(vm[3])) != expected[3], error("Wrong second derivative")); } { my (p = nextprime(2^40)); check_eval_modpoly( 5, 7, 151, [8033941431460000, 243641761686181, 243612090562303]); check_eval_modpoly(19, 7, 151, [11844895572672018496, 369501438945078285, 13082720985735388448]); \\check_eval_modpoly( 5, 7, factorial(12), XXXX); check_eval_modpoly( 5, 7, p, [3901199766181530739, 4054334766401667256, 16751141247645108349]); \\check_eval_modpoly(23, 7, factorial(12), XXXX); check_eval_modpoly(23, 7, p, [2360118342899681926, 2787294817779511277, 18359991236545579908]); } pari-2.11.2/src/test/in/install0000644000175000017500000000016213326135265014730 0ustar billbillinstall(addii,GG) type(addii) addii(1,2) ?addii kill(addii) ?addii install(addiu,"GD0,U,") addiu(2,3) type(addiu) pari-2.11.2/src/test/in/lfun0000644000175000017500000003112613457566441014243 0ustar billbilldefault("parisize","32M"); default("realprecision",38); zetaan(n)=vector(n,i,1); K=bnfinit('x^3+'x^2-3*'x-1); L148=lfuncreate(K); lfuncost(L148, [20]) lfunthetacost(L148) for(i=1,10,print(i,":",lfun(L148,-i))) L117=lfundiv(nfinit('x^4-'x^3-'x^2+'x+1),1); for(i=1,10,print(i,":",lfun(L117,i))) e121=ellinit([1,1,1,-30,-76]); \\ 121a1 L121=lfuninit(e121,[100],2); lfuncost(L121) lfun(L121,1+100*I) lfun(L121,1+x+O(x^3)) lfun(1,1+x+O(x^4),1) lfun(1,1+x+O(x^4),2) lfun(1,2+x^2+O(x^6),1) lfun(1,2+x^2+O(x^6),2) \p36 lfun(x^4-2,x+O(x^6),1) lfun(x^4-2,x+O(x^6),2) \p38 lfun(polcyclo(12),2) lfun(lfunmul(1,1),1) lfun(lfunmul(x^2+1,x^2+1),1) lfun(lfundiv(x^2+1,-4),1) pol=x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1; real(lfun(lfundiv(pol,[bnrinit(bnfinit(x^2+23),1),[1]]),1)) \\ check for loss in accuracy in lfunthetaspec nf24217=nfinit(x^5-5*x^3-x^2+3*x+1); L2=lfuncreate(nf24217); lfunhardy(L2,5) /* higher precision */ default("realprecision",54) /* Riemann */ lzeta = lfuncreate(1); lfun(lzeta,1) lfun(lzeta,1/2+200*I) lfun(lzeta,.5+200*I) lfun(lzeta,0,1) lfun(lzeta,x) lfunzeros(lzeta,14.14) lfunzeros(lzeta,[14,14.5]) lfunzeros(lzeta,30) lzeta[6]=0; lfun(lzeta,2) lfuntheta(lzeta,1e50) lfuntheta(lzeta,1e50+I) /* odd Dirichlet char */ lfun(Mod(8,13), 1) /* EC */ e = ellinit([0, 0, 1, -7, 6]); lfunzeros(e,20) lfunzeros(e,[0,3]) /* Ramanujan */ ltau=lfunetaquo(Mat([1,24])); lfunmfspec(ltau) /* other functions */ t = 4+I/5; t^2*lfuntheta(L121,t) lfuntheta(L121,1/t) vv=lfunthetainit(L121,1/t); lfuntheta(vv,1/t) lfunthetacost(vv) vv=lfunthetainit(L117,[1,2/5]); lfuntheta(vv,1) my(x = 2*I/5); e=exp(x/2)*lfuntheta(vv, exp(x)); /* should be real */ [real(e),round(imag(e)*10^55)] M=msinit(11,4,1); F=mssplit(M,msnew(M))[1]; L=lfuncreate([n->subst(lift(msqexpansion(M,F,n)),'x,1+sqrt(3)),0,[0,1],[4,3/2],11,1]); default("realprecision",115); lfun(L,2) default("realprecision",54); Z101=znstar(101,1); L=lfuncreate([Z101,[1]]); L=lfuninit(L,[1,1,1]); lfuncheckfeq(L) L=lfuninit(L,[1,1,1]); lfuncheckfeq(L) lfuncheckfeq(L,11/10) lfuncheckfeq(L,9/10) lfun(L,1) lfun(L,2) { my(V=lfunan(L,100)); my(q=exp(2*I*Pi/101),S=sum(i=1,100,V[i]*q^i)/sqrt(-101)); my(z=lfuntheta(L,1),eps=abs(S-z/conj(z))); if(eps>10^-55,error("charinit(101): ",eps)); } lfunzeros(L,20) L=lfuncreate([Z101,[1]]); L=lfuninit(L,[1,0,0]); lfuncheckfeq(L) lfun(L,1) K=bnfinit('x^2+23);B=bnrinit(K,1,1); L=lfuncreate([B,[1]]); lfuncheckfeq(L) algdep(exp(lfun(L,0,1)),3) /* GENUS 2 curve */ print("Curve y^2+(x^3+x^2+1)*y = x^2+x"); L=lfungenus2([x^2+x,x^3+x^2+1]); default("realprecision",19); lfuncheckfeq(L) print("Curve y^2+(x^3+1)*y = x^2+x"); L=lfungenus2([x^2+x,x^3+1]); for(i=1,20,lfunan(L,i)) print("Curve y^2+(x^2+x)*y = x^6+3*x^5+6*x^4+7*x^3+6*x^2+3*x+1"); L=lfungenus2([x^6+3*x^5+6*x^4+7*x^3+6*x^2+3*x+1,x^2+x]); L[5]*=4; lfuncheckfeq(L) print("Curve y^2=",x^5+x); fun(p, d)= \\ if (d == 2), only 1 + trace term is needed { my(p16=p%16, p8=p16%8); if (d == 2 && p8 != 1, return (1)); if (p8 == 5 || p8 == 7, return((1+p*x^2)^-2)); my([u,v] = qfbsolve(Qfb(1,0,2),p)); if (p8 == 3, return (1 / (1 + (-4*u^2 + 2*p)*x^2 + p^2*x^4))); if (u%4 != 1, u=-u); if(p16==1,(1-2*x*u+p*x^2)^-2, (1+2*x*u+p*x^2)^-2); } L=lfuncreate([[(p,d)->fun(p, d),[[2, 1]]], 0, [0,0,1,1], 2, 2^16, -1]); default("realprecision",38) lfuncheckfeq(L) lfunrootres(L) lfun(L,1,1) print("Curve y^2=",x^5+1); B=bnfinit(polcyclo(5)); fun2(p, d)= \\ if (d == 2), only 1 + trace term is needed { my(p10 = p%10); if (p10 != 1, if (d == 2, return (1)); return (if (p10==9, 1 / (1+2*p*x^2+p^2*x^4), 1 / (1 + p^2*x^4))); ); my (u = nfbasistoalg(B, bnfisprincipal(B,idealprimedec(B,p)[1])[2])); my (a = subst(liftpol(u),x,x^2) * u); for (i = 0, 9, my (b = (-x)^i * a); my (t = nfelttrace(B, b), t10 = t % 10); if (t10 == 4, return(if (d == 2, 1 + t*x, 1 / polrecip(minpoly(b))))); ); } L=lfuncreate([[(p,d)->fun2(p,d),[[2,1],[5, 1]]], 0, [0,0,1,1], 2, 5^4*2^4, 1]); lfuncheckfeq(L) lfunrootres(L) lfun(L,1) lfungenus2(x^5+3^5) \\#2047 print("Elliptic curves over number fields"); K=nfinit(a^2+1); E1=ellinit([1+a,0,1,0,0],K); lfuncheckfeq(E1) lfunlambda(E1,1) E2=ellinit([a,0,a,0,0],K); lfuncheckfeq(E2) lfunlambda(E2,1) E3=ellinit([1,a-1,a+1,-a-1,0],K); lfuncheckfeq(E3) lfunlambda(E3,1) E4=ellinit([0,1-a,a,-a,0],K); lfuncheckfeq(E4) lfunlambda(E4,2) K2=nfinit(a^2-a+5); E5=ellinit([a,1-a,1,-1,0],K2); lfuncheckfeq(E5) lfunlambda(E5,1) K=bnfinit(subst(x^3-x^2-3*x+1,x,a)); E=ellinit([a^2-a-2,-a^2+2*a+3,a^2-1,-a^2+a+4,-a^2+2],K); localbitprec(4); lfuncheckfeq(E) localbitprec(32);lfuncheckfeq(E) print("Grossencharacter"); K=bnfinit(polcyclo(5)); id5=idealprimedec(K,5)[1]; B=bnrinit(K,id5,1); F(p,d)= { my(pr=idealprimedec(K, p, d-1)); 1 / simplify(lift(prod(k=1,#pr, 1 - G(pr[k])*X^pr[k].f))); } G(pr)= { if(idealval(K,B.mod,pr),0, my([e,al] = bnrisprincipal(B,pr)); my(al1=nfbasistoalg(K,al)); my(al2=nfbasistoalg(K,nfgaloisapply(K,x^2,al))); my(al3=nfbasistoalg(K,nfgaloisapply(K,x^3,al))); al1^3*al2^2*al3^1); } L=lfuncreate([(p,d)->F(p,d),0,[-1,0,0,1],4,625,0]); lfuncheckfeq(L) lfun(L,2)/(Pi/5^(15/4)*gamma(1/5)^(7/2)*gamma(3/5)^(1/2)/(gamma(4/5)^(7/2)*gamma(2/5)^(1/2))) print("tensor product") E=ellinit([0,-1,1,-10,-20]); F=ellinit([1,0,1,4,-6]); L=lfuncreate([[(p,e)->my(ta=ellap(E,p),tb=ellap(F,p));1/(p^4*x^4-tb*ta*p^2*x^3+(-2*p^2+(ta^2+tb^2)*p)*x^2-tb*ta*x+1),[[2,1/(2*x^2-2*x+1)],[7,1/(7*x^2+2*x+1)],[11,1/(11*x^2+1)]]],1,[-1,0,0,1],3,23716,0]); \pb64 lfuncheckfeq(L) lfun(L,3/2) print("check all formats"); default("realprecision",54) e = ellinit([0, 0, 1, -1, 0]); le2 = lfuncreate([ n->ellan(e,n), 0, [0,1], 2, 37, -1]); le3 = lfuncreate([ ellan(e,1000), 0, [0,1], 2, 37, -1]); le4 = lfuncreate([ (p,d)->1/(1-ellap(e,p)*'x+if(p!=37,p*'x^2)), 0, [0,1], 2, 37, -1]); le41 = lfuncreate([ [(p,d)->1/(1-ellap(e,p)*'x+p*'x^2), [[37,1/(1+'x)]]], 0, [0,1], 2, 37, -1]); lfuncheckfeq(le2) lfuncheckfeq(le3) lfuncheckfeq(le4) lfuncheckfeq(le41) lfunan(le41,10) lfunan(2^63+5,10) lfunan(2^64+5,10) \\ zeta(s)*zeta(s-(k-1)), single pole at k if k even >= 4 f(k) = lfuncreate([n->vector(n,i,sigma(i,k-1)),0,[0,1],k,1,I^k,zeta(k)]); lfun(f(4),5)-zeta(5)*zeta(2) \\ bernfrac(2*k) / (4*k) forstep(k=4,18,2,print(bestappr(-lfun(f(k),0),10000000))) L = lfuninit(x^2+1, [1,2,2]); lfun(L,2)/(Pi^2/6*Catalan) lfunhardy(L,2) lfun(lfunetaquo([1,1;3,1;5,1;15,1]),2) lfun(lfunetaquo(Mat([1,24])),2) lfun(lfunetaquo([5,2;7,2]),2) lfun(ellinit([1,1,1,-10,-10]),2) \\ 15a1 \\ residue 2*Pi/sqrt(23) at 1 L=lfunqf([2,1;1,12]); L=lfuninit(L,[1/2,20],1); newton(L,z,N)=for(i=1,N,z-=lfun(L,z)/lfun(L,z,1));z; z=newton(L,1/2+16*I,10) abs(lfun(L,z))>1e-50 localprec(100); L=lfunmul(1,1); lfun(L,2)/(Pi^4/36) lfuncheckfeq(L) localbitprec(300);L=lfunmul(L,1); lfun(L,3)/(zeta(3)^3) lfuncheckfeq(L) print("zeta(s-a)"); Z(a)=lfuncreate([(p,n)->1/(1-p^a*x),0,[-a],2*a+1,1,1,[[a+1,0]]]); lfuncheckfeq(Z(1)) lfun(Z(1),2) lfun(Z(1),3) lfuncheckfeq(Z(2)) lfun(Z(2),2) lfun(Z(2),3) print("zeta(s)*zeta(s-a)"); L(a)=lfuncreate([(p,n)->1/((1-p^a*x)*(1-x)),0,[-a,0],a+1,1,1,[[a+1,lfun(1,a+1+x+O(x^2))*(1/x+Euler+O(x))],[1,lfun(1,1-a+x+O(x^3))*(1/x+Euler+O(x))]]]); lfuncheckfeq(L(1)) lfun(L(1),2) lfun(L(1),3) lfuncheckfeq(L(2)) lfun(L(2),2) lfun(L(2),3) lf=[1,-7,-3,25,3,21,-9,-63,6,-21,-4,-75,-3,63,-9,169,37,-42,-75,75,27,28,10,189,-76,21,-90,-225,212,63,-6,-623,12,-259,-27,150,-88,525,9,-189,-3,-189,547,-100,18,-70,-147,-507,25,532,-111,-75,-108,630,-12,567,225,-1484,-45,-225,145,42,-54,2233,-9,-84,-632,925,-30,189,-650,-378,859,616,228,-1875,36,-63,-978,507,-234,21,931,675,111,-3829,-636,252,-571,-126,27,250,18,1029,-225,1869,453,-175,-24,-1900,830,777,1246,189,81,756,707,-2250,-378,84,264,-1521,-225,-1575,30,5300,-18,315,-333,567,-1722,-1015,9,-150,-108,378,1607,-6111,-1641,63,-1399,300,675,4424,-270,-2331,-861,210,1938,-675,441,4550,12,1014,636,-6013,-75,-2200,157,-1596,2356,4725,222,-252,-18,225,-414,6846,324,-1869,-90,1638,-11,-75,36,-6517,-1852,-1701,-1460,-777,-450,13675,-2021,4452,684,-676,135,3997,1444,450,442,-189,-435,-630,-264,-126,-148,-3675,810,1575,-366,-6699,-2790,-3171,27,625,-815,168,-2753,4788,1896,-5810,-1908,-2775,-9,-8722,60,-507,300,-567,-3519,-2700,1950,-4949,1641,5670,54,2646,-2577,-300,-111,-1848,100,5607,-456,1575,-2302,5625,-813,-210,-108,-13356,-1136,126,-441,-1125,2934,2331,5251,-1521,5366,12054,2673,3625,75,-63,225,378,-2793,756,4478,-1350,-40,-11249,-333,13257,-1794,11487,792,-225,1272,9793,4270,-756,-324,-4725,1713,-15800,7959,1890,-2409,6253,-81,6027,304,-750,1592,-13566,-36,1701,7566,-3087,-737,-16250,675,-84,27,-3738,-6553,-4452,-1359,21475,-6777,525,-135,5544,360,-1099,-30,5700,-4923,-16492,-2490,-12675,435,-1554,1350,900,-3738,126,4001,-567,2685,2898,-162,-24450,7560,-2268,-848,6699,-2121,630,-2775,-5850,228,77,1134,189,1323,-252,-6732,23275,-528,12964,-1896,4563,-5228,10220,675,2775,24,3150,-2808,-34461,-90,14147,2829,-15900,4999,-4788,270,2492,-18397,-945,-1950,-14275,999,-10108,3871,-1134,-1861,-3094,5166,675,2577,3045,3171,1690,-18,1848,972,450,-6977,1036,324,9261,-636,-5670,8517,-5625,-4821,2562,5665,18333,108,19530,3282,11325,-194,-189,370,-1575,4197,5705,-2934,-600,-1484,19271,-2025,-12844,-2484,-13272,18,20750,-702,13356,352,6993,-12944,63,2583,31150,405,-420,2793,1869,-5814,-2100,-1919,2025,21564,24633,-882,6804,-2812,-13650,-1305,17675,-36,-11487,-1559,-15210,-4556,-378,-1908,-9450,-750,18039,-4476,756,150,777,7725,6600,-1713,-700,-471,-20097,-8444,3192,12,-5625,-7068,16114,81,-14175,-2673,5691,-3330,750,-5217,756,-2666,35828,54,7952,-672,-450,5688,3087,1242,2835,-2188,-20538,5700,-8325,-648,-36757,-1129,5607,264,-37562,270,-43050,1359,-18711,467,-9135,33,-525,-4973,225,7844,-1575,-72,-1014,5850,19551,-3859,-2700,5556,-31346,4091,3402,2490,280,4380,40175,10085,2331,-7731,-31311,6750,12558,3738,-41025,588,-5544,6063,567,-2290,-8904,11663,-34975,-2052,-29890,-222,2028,-13838,2268,-270,16875,9,-11991,2121,39816,-4332,-55713,-100,-6750,16984,16863,-1326,-23051,-1134,567,-6079,-21525,870,-2128,-15900,1890,8802,-11144,792,48450,-28136,252,-1641,-4563,444,-52962,591,11025,-675,5159,2106,40950,-13725,-4725,16866,300,1098,-189,-760,13398,21984,45871,8370,15900,-8379,9513,432,-54117,-54,47439,3770,-1875,450,945,2445,-14872,16344,-2520,-999,3925,8259,210]; L=lfuncreate([lf,0,[-1,0,0,1],4,61,1]); localprec(38);lfunconductor(L,100) K=bnfinit(y^2+47); rel=x^5+2*x^4+2*x^3+x^2-1; T=rnfequation(K.pol, rel); L=lfunabelianrelinit(T,K,rel,[2,0,0]); lfun(L,2) lfuncost(L) L=lfuninit(polcyclo(3), [1/2,0,0]); lfuncheckfeq(L) lfuncost(L) lfunconductor(1,1) /* lfunconductor */ default(realprecision,38); lfunconductor(1) lfunconductor(-4) lfunconductor(857) lfunconductor(120) lfunconductor(2108) lfunrootres(x^3+x^2-3*x-1) default(realprecision,19) lfunconductor(1,[1/2,10]) /* guess small conductor */ e1=ellinit([0, 0, 1, -7, 6]); lfunconductor(e1) lnf725=lfundiv(x^4-x^3-3*x^2+x+1,1); lfunconductor(lnf725,,1) /* bigger one. * remark: should be able to search in a big range * with few coefficients, would be faster */ lnf24217=lfundiv(nf24217,1); lfunconductor(lnf24217,10^5,1) e2=ellinit([3,-27,-18,24,9]); lfunconductor(e2,10^8,1) N=nfinit(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1);G=galoisinit(N); L=lfunartin(N,G,[[-1,1;-1,0],[0,1;1,0]],1); if(lfunan(L,100)!=lfunan(lfundiv(x^3-3*x^2+2*x-1,1),100),error("lfunartin")); N=nfinit(x^12-11*x^10+44*x^8-78*x^6+60*x^4-16*x^2+1); G=galoisinit(N); L=lfunartin(N,G,[1,-y+1,y,-y+1,-1,y,-y,1,y-1,-y,y-1,-1]~,6); if(round(lfunan(L,100)-lfunan([znstar(28,1),[5,1]],100),&e),error("lfunartin")); e K=nfinit(polcyclo(4,a));G=galoisinit(K);[T,o]=galoischartable(G); L=lfunartin(K,G,T[,1]+T[,2],o); localbitprec(50);lfuncheckfeq(L) localbitprec(20); #lfunzeros('x^2-2,6) lfuncost(1, [100], 5) L = lfuninit(polcyclo(5), [1/2,1/2,50]); lfuncost(L) lfun(1,2000) default(realprecision,38) Z=znstar(7,1); La=lfuncreate([Z,[2]]); Lb=lfuncreate([Z,[4]]); L=La;L[2]=Lb[1]; lfun(L,2+I) lfun(La,2+I) { L1=lfuncreate([Z,[1]]); L2=lfuncreate([Z,[3]]); my(t=lfunrootres(L1)[3]); L=lfuncreate([n->lfunan(L1,n)+lfunan(L2,n),n->conj(lfunan(L1,n))*t+lfunan(L2,n),[1],1,7,1]); } f(s)=[round(lfun(L,s)/(lfun(L1,s)+lfun(L2,s)),&e),e]; lfuncheckfeq(L) f(2+I) \\ zeta via lfuncreate + Lambda polar part a=n->vector(n,i,1); z=lfuncreate([a, a, [0], 1, 1, 1, [[0,-1/x+O(1)], [1,1/x+O(1)]]~]); lfun(z,2) { E=ellinit([0,0,1,0,-7]); \\27a1 localbitprec(48); for(i=1,7, L=lfunsympow(E,i); print(i,":",lfuncheckfeq(L))) } L=lfunsympow(E,5); lfun(L,1,1) \\ #2118 Z = lfuncreate([n->[1], 0, [0], 1, 1, 1, 1]); lfun(Z,2) \\ ERRORS: keep them at end of file lfuntheta(1,0) lfunhardy(1,I) lfun(1,2,-1) lfunan(lfuncreate([1,0,[0],1,1,1,1]),10) N=nfinit(x^2+1);G=galoisinit(N);lfunartin(N,G,[1]~,2) N=nfinit(x^2+1);G=galoisinit(N);lfunartin(N,G,[1,1,1]~,2) Lt=lfuncreate([1,0,[-1,0,0,1,-2,-1,0,0],21,61^2,1]); localbitprec(16);lfun(Lt,12); pari-2.11.2/src/test/in/linear0000644000175000017500000000511513326135265014537 0ustar billbillHEAP=[99, if(sizebyte(0)==16,8775,8955)]; default(realprecision,38); \e algdep(2*cos(2*Pi/13),6) algdep(2*cos(2*Pi/13),6,15) charpoly([1,2;3,4],z) charpoly(Mod(x^2+x+1,x^3+5*x+1),z) charpoly([1,2;3,4],z,1) charpoly(Mod(1,8191)*[1,2;3,4],z,2) lindep(Mod(1,7)*[2,-1;1,3]) lindep([(1-3*sqrt(2))/(3-2*sqrt(3)),1,sqrt(2),sqrt(3),sqrt(6)]) lindep([(1-3*sqrt(2))/(3-2*sqrt(3)),1,sqrt(2),sqrt(3),sqrt(6)],14) matadjoint([1,2;3,4]) matcompanion(x^5-12*x^3+0.0005) matdet([1,2,3;1,5,6;9,8,7]) matdet([1,2,3;1,5,6;9,8,7],1) matdetint([1,2,3;4,5,6]) matdiagonal([2,4,6]) mateigen([1,2,3;4,5,6;7,8,9]) mathess(mathilbert(7)) mathilbert(5) amat=1/mathilbert(7) mathnf(amat) mathnf(amat,1) mathnf(amat,4) mathnf(amat,5) mathnfmod(amat,matdetint(amat)) mathnfmodid(amat,123456789*10^100) matid(5) matimage([1,3,5;2,4,6;3,5,7]) matimage([1,3,5;2,4,6;3,5,7],1) matimage(Pi*[1,3,5;2,4,6;3,5,7]) matimagecompl([1,3,5;2,4,6;3,5,7]) matimagecompl(Pi*[1,3,5;2,4,6;3,5,7]) matindexrank([1,1,1;1,1,1;1,1,2]) matintersect([1,2;3,4;5,6],[2,3;7,8;8,9]) matinverseimage([1,1;2,3;5,7],[2,2,6]~) matisdiagonal([1,0,0;0,5,0;0,0,0]) matker(matrix(4,4,x,y,x/y)) matker(matrix(4,4,x,y,sin(x+y))) matker(matrix(4,4,x,y,x+y),1) matkerint(matrix(4,4,x,y,x*y)) matkerint(matrix(4,4,x,y,x*y),1) matkerint(matrix(4,6,x,y,2520/(x+y))) matmuldiagonal(amat,[1,2,3,4,5,6,7]) matmultodiagonal(amat^-1,%) matpascal(8) matrank(matrix(5,5,x,y,x+y)) matrix(5,5,x,y,gcd(x,y)) matrixqz([1,3;3,5;5,7],0) matrixqz([1/3,1/4,1/6;1/2,1/4,-1/4;1/3,1,0],-1) matrixqz([1,3;3,5;5,7],-2) matsize([1,2;3,4;5,6]) matsnf(1/mathilbert(6)) matsnf(x*matid(5)-matrix(5,5,j,k,1),2) matsolve(mathilbert(10),[1,2,3,4,5,6,7,8,9,0]~) matsolvemod([2,3;5,4],[7,11]~,[1,4]~) matsolvemod([2,3;5,4],[7,11]~,[1,4]~,1) matsupplement([1,3;2,4;3,6]) mattranspose(vector(2,x,x)) %*%~ norml2(vector(10,x,x)) qfgaussred(mathilbert(5)) qfjacobi(mathilbert(6)) m=1/mathilbert(7) mp=concat(m,matid(7)) qflll(m) qflllgram(m) qflllgram(m,1) qflllgram(mp~*mp,4) qflll(m,1) qflll(m,2) qflll(mp,4) qfminim([2,1;1,2],4,6) qfperfection([2,0,1;0,2,1;1,1,2]) qfsign(mathilbert(5)-0.11*matid(5)) trace(1+I) trace(Mod(x+5,x^3+x+1)) Vec(sin(x)) vecmax([-3,7,-2,11]) vecmin([-3,7,-2,11]) concat([1,2],[3,4]) concat(Mat(vector(4,x,x)~),vector(4,x,10+x)~) vecextract([1,2,3,4,5,6,7,8,9,10],1000) vecextract(matrix(15,15,x,y,x+y),vector(5,x,3*x),vector(3,y,3*y)) round((1.*mathilbert(7))^(-1) << 77) / 2^77 vecsort([8,7,6,5],,1) vecsort([[1,5],[2,4],[1,5,1],[1,4,2]]) vecsort(vector(17,x,5*x%17)) vecsort([[1,8,5],[2,5,8],[3,6,-6],[4,8,6]],2) vecsort([[1,8,5],[2,5,8],[3,6,-6],[4,8,6]],[2,1]) vector(10,x,1/x) if (getheap()!=HEAP, getheap()) pari-2.11.2/src/test/dotest0000755000175000017500000000734713326135265014175 0ustar billbill#!/bin/sh trap exit 2 bitlen=$1; shift exe_suff=$1; shift testlist=$@ if (tail -n 1 $0 >/dev/null 2>&1); then tail='tail -n' else tail='tail -' fi if (head -n 1 $0 >/dev/null 2>&1); then head='head -n' else head='head -' fi if (printf %-22s foo >/dev/null 2>&1); then printf=OK else printf= fi wrln () { echo "$1"; echo "$1" >&3; } wr () { echo $n "$1$c"; echo $n "$1$c" >&3; } wrtab () { if test -n "$printf"; then printf %$1s "$2" printf %$1s "$2" >&3 else echo $n "$2 $c" echo $n "$2 $c" >&3 fi; } confdir=../config testdir=../src/test execdir=. case `$confdir/arch-osname` in *-cygwin*|*-mingw*|*-msys*) crlf=OK ;; *) crlf= ;; esac if test -f /bin/rm ; then RM=/bin/rm; else RM=rm ; fi (echo "hi there\c" ; echo " ") > echotmp if grep c echotmp >/dev/null 2>&1 ; then n=-n; c=; else n=; c='\c'; fi $RM -f echotmp . $confdir/version exec 3>> Bench-$VersionMajor.$VersionMinor.$patch dotestSUF=${dotestSUF:-"sta dyn"} for arg in $dotestSUF; do if test -s $execdir/gp-$arg$exe_suff; then SUF="$SUF $arg" datadir=`echo 'print(default(datadir))' | $RUNTEST $execdir/gp-$arg -q -f` fi done file_test=gp.out for suf in $SUF; do eval time$suf=0 files$suf=; done for testdata in $testlist; do O=$IFS;IFS=_;set $testdata;IFS=$O;testname=$1;testmul=$2 pkgs=`${head}1 $testdir/in/$testname | grep package: | cut -f2 -d:` skip="" for pkg in $pkgs; do if test ! -x "$datadir/$pkg"; then wrln "! Skipping $testname: optional package $pkg not installed." skip="true"; fi done if test "$skip" = "true"; then untested="$untested $testname" else file_in=$testdir/in/$testname file_out=$testdir/$bitlen/$testname if test ! -r $file_out; then file_out=$testdir/32/$testname; fi if test ! -r $file_out; then touch $file_out; fi if test ! -r $file_in; then wrln "Error! Missing file, can't test $testname" exit 1 fi testmul=${testmul:-1000} wrtab -27 "* Testing $testname " for suf in $SUF; do file_diff=$testname-$suf.dif gp=$execdir/gp-$suf$exe_suff (echo 'gettime();0;'; cat $file_in; \ echo 'print("Total time spent: ",gettime);') \ | $RUNTEST $gp -q --test > $file_test 2>&1 if test -n "$crlf"; then # when building on windows, remove extra cr so diff's will match cat $file_test | tr -d '\r' | diff -c $file_out - > $file_diff else diff -c $file_out $file_test > $file_diff fi pat=`grep "^[-+!] " $file_diff | grep -v "Total time"` time=`${tail}1 $file_test | sed -n 's,.*Total time spent: \(.*\),\1,p'` if test -n "$time"; then eval t='$'time$suf if test -n "$exprbug"; then t=`expr $time \'\*\' $testmul / 1000 + $t` else t=`expr $time '*' $testmul / 1000 + $t` fi eval time$suf=$t fi pre= if test -z "$pat"; then wr "gp-$suf..TIME=" wrtab 8 "$time "; else eval BUG$suf=BUG eval files$suf=\"'$'files$suf $file_diff\" wrtab -21 "gp-$suf..BUG [${time:-0}]" fi done wrln fi done $RM -f $file_test BUG= for suf in $SUF; do B=`eval echo '$'BUG$suf`; BUG="$BUG$B" t=`eval echo '$'time$suf` if test -n "$B"; then B=' [BUG]'; fi wrln "+++$B Total bench for gp-$suf is $t" done if test -n "$untested"; then wrln "The following tests were skipped:$untested" fi if test -z "$BUG"; then exit 0; fi pwd=`pwd` wrln wrln "PROBLEMS WERE NOTED. The following files list them in diff format: " wrln "Directory: $pwd" for suf in $SUF; do B=`eval echo '$'BUG$suf`; BUG="$BUG$B" if test -n "$B"; then flist=`eval echo '$'files$suf` for f in $flist; do wrln " $f" if test "$dump_dif" = 1; then cat $f; fi done fi done exit 1 pari-2.11.2/src/test/kerntest.c0000644000175000017500000000427713201017466014741 0ustar billbill#include "pari.h" GEN gen_0, gen_1, gen_m1, gen_2, gen_m2; THREAD pari_sp avma; THREAD size_t memused = 0; ulong DEBUGLEVEL,DEBUGMEM = 0; const double LOG10_2 = 0.; const long lontyp[] = {0}; THREAD VOLATILE int PARI_SIGINT_block, PARI_SIGINT_pending; struct pari_mainstack * pari_mainstack; long *varpriority; void mt_sigint_block(void) { } void mt_sigint_unblock(void) { } void new_chunk_resize(size_t x) {(void)x;} void specinit() { long size = 100000L; pari_mainstack = malloc(sizeof(*pari_mainstack)); pari_mainstack->size = size; pari_mainstack->bot = (pari_sp)malloc(size); pari_mainstack->top = avma = pari_mainstack->bot + size; gen_0 = cgeti(2); affui(0, gen_0); gen_1 = utoipos(1); gen_m1= utoineg(1); gen_2 = utoipos(2); gen_m2= utoineg(2); } void sorstring(ulong x) { #ifdef LONG_IS_64BIT if (x>>32) printf("%08lx ", x>>32); printf("%08lx ", x & 0xFFFFFFFF); #else printf("%08lx ", x); #endif } void _voiri(GEN x) { long i, lx = lgefint(x); GEN y = int_MSW(x); printf("signe: %ld, ",signe(x)); for (i=2; i < lx; i++, y = int_precW(y)) sorstring(*y); printf("\n"); } void _voirr(GEN x) { long i, lx = lg(x); printf("signe: %ld, expo: %ld, ",signe(x),expo(x)); for (i=2; i < lx; i++) sorstring(x[i]); printf("\n"); } int main() { GEN x,y,r,z, xr,yr; specinit(); x = utoipos(187654321UL); y = utoineg(12345678UL); printf("INT: %ld\n", itos(x)); printf("conv:"); _voiri(x); printf("+:"); _voiri(addii(x,y)); printf("-:"); _voiri(subii(x,y)); printf("*:"); _voiri(mulii(x,y)); printf("/:"); _voiri(dvmdii(x,y, &z)); printf("rem:"); _voiri(z); printf("pow:\n"); z = mulii(x,x); _voiri(z); z = mulii(z,z); _voiri(z); z = mulii(z,z); _voiri(z); z = mulii(z,z); _voiri(z); z = mulii(z,z); _voiri(z); printf("invmod:"); invmod(y,z,&r); _voiri(r); xr = itor(x, DEFAULTPREC); yr = itor(y, DEFAULTPREC); printf("\nREAL: %f\n", rtodbl(xr)); printf("conv1:"); _voirr(xr); printf("conv2:"); _voirr(dbltor(rtodbl(xr))); printf("+:"); _voirr(addrr(xr,yr)); printf("-:"); _voirr(subrr(xr,yr)); printf("*:"); _voirr(mulrr(xr,yr)); printf("/:"); _voirr(divrr(xr,yr)); printf("gcc bug?:"); _voirr(divru(dbltor(3.),2)); return 0; } pari-2.11.2/src/test/dummy.c0000644000175000017500000000075413201017466014231 0ustar billbillvoid nchar2nlong(){} void newblock(){} void remsBIL(){} void bit_accuracy(){} void is_bigint(){} void divsBIL(){} void copy_bin(){} void pari_free(){} void pari_malloc(){} void shiftaddress(){} void shiftaddress_canon(){} void powuu(){} void gerepilemanysp(){} void ceilr(){} void roundr(){} void pari_err(){} void pari_err_BUG(){} void pari_err_INV(){} void pari_err_OVERFLOW(){} void pari_err_PREC(){} void pari_warn(){} void quadratic_prec_mask(){} void prec2nbits(){} void nbits2prec(){} pari-2.11.2/src/test/tune.c0000644000175000017500000006777613326135265014100 0ustar billbill/* Copyright (C) 2001 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file is a quick hack adapted from gmp-4.0 tuning utilities * (T. Granlund et al.) * * (GMU MP Library is Copyright Free Software Foundation, Inc.) */ #define PARI_TUNE #include #include int option_trace = 0; double Step_Factor = .01; /* small steps by default */ ulong DFLT_mod1, DFLT_hmod, DFLT_qmod, DFLT_mod2; GEN LARGE_mod; #ifdef LONG_IS_64BIT # define DFLT_mod DFLT_mod1 # define Fmod_MUL_MULII_LIMIT Flx_MUL_MULII_LIMIT # define Fmod_SQR_SQRI_LIMIT Flx_SQR_SQRI_LIMIT # else # define DFLT_mod DFLT_mod2 # define Fmod_MUL_MULII_LIMIT Flx_MUL_MULII2_LIMIT # define Fmod_SQR_SQRI_LIMIT Flx_SQR_SQRI2_LIMIT #endif typedef struct { ulong reps, type; long *var, *var_disable, *var_enable, var_enable_min, size, enabled; GEN x, y; ulong l; GEN T, p; } speed_param; typedef double (*speed_function_t)(speed_param *s); typedef struct { int kernel; const char *name; long *var; int type; /* t_INT or t_REAL */ long min_size; long max_size; speed_function_t fun; double step_factor; /* how much to step sizes (rounded down) */ double stop_factor; long *var_disable; long *var_enable; } tune_param; /* ========================================================== */ /* To use GMP cycle counting functions, look for GMP in Oxxx/Makefile */ #ifdef GMP_TIMER /* needed to link with gmp-4.0/tune/{time,freq}.o */ int speed_option_verbose = 0; extern double speed_unittime; extern int speed_precision; void speed_starttime(void); double speed_endtime(void); #else static pari_timer __T; static double speed_unittime = 1e-4; static int speed_precision= 1000; static void speed_starttime() { timer_start(&__T); } static double speed_endtime() { return (double)timer_delay(&__T)/1000.; } #endif /* ========================================================== */ /* int, n words, odd */ static GEN rand_INT(long n) { pari_sp av = avma; GEN x, N = int2n(n*BITS_IN_LONG); do x = randomi(N); while (lgefint(x) != n+2); if (!mpodd(x)) x = addis(x,1); /*For Barrett REDC */ return gerepileuptoint(av, x); } /* real, n words */ static GEN rand_REAL(long n) { return gmul2n(itor(rand_INT(n), n+2),-BITS_IN_LONG*n); } static GEN rand_FpX(long n) { GEN x; do x = random_FpX(n+1, 0, LARGE_mod); while (degpol(x) < n); return x; } /* Flx, degree n */ static GEN rand_F2x(long n) { GEN x; do x = random_F2x(BITS_IN_LONG*n, 0); while (lgpol(x) < n); return x; } /* Flx, degree n */ static GEN rand_Flx(long n, ulong l) { GEN x; do x = random_Flx(n+1, 0, l); while (degpol(x) < n); return x; } static GEN rand_F2xqX(long n, GEN T) { GEN x; do x = random_F2xqX(n+1, 0, T); while (degpol(x) < n); return x; } static GEN rand_FlxqX(long n, GEN T, ulong l) { GEN x; do x = random_FlxqX(n+1, 0, T, l); while (degpol(x) < n); return x; } static GEN rand_FpXQX(long n, GEN T) { GEN x; do x = random_FpXQX(n+1, 0, T, LARGE_mod); while (degpol(x) < n); return x; } /* normalized Fpx, degree n */ static GEN rand_NFpX(long n) { pari_sp av = avma; GEN x = gadd(pol_xn(n,0), random_FpX(n, 0, LARGE_mod)); return gerepileupto(av, x); } /* normalized Flx, degree n */ static GEN rand_NFlx(long n, ulong l) { pari_sp av = avma; GEN x = Flx_add(Flx_shift(pol1_Flx(0),n), random_Flx(n, 0, l), l); return gerepileuptoleaf(av, x); } static GEN rand_NF2xqX(long n, GEN T) { pari_sp av = avma; GEN x = F2xX_add(monomial(pol1_F2x(0),n,0), random_F2xqX(n, 0, T)); return gerepileupto(av, x); } static GEN rand_NFlxqX(long n, GEN T, long l) { pari_sp av = avma; GEN x = FlxX_add(monomial(pol1_Flx(0),n,0), random_FlxqX(n, 0, T, l), l); return gerepileupto(av, x); } static GEN rand_NFpXQX(long n, GEN T) { pari_sp av = avma; GEN x = gadd(pol_xn(n,0), random_FpXQX(n, 0, T, LARGE_mod)); return gerepileupto(av, x); } #define t_F2x 100 #define t_Fqx 200 #define t_Fhx 201 #define t_Flx 202 #define t_Fl1x 203 #define t_Fl2x 204 #define t_NFqx 210 #define t_NFhx 211 #define t_NFlx 212 #define t_NFl1x 213 #define t_NFl2x 214 #define t_FpX 300 #define t_NFpX 310 #define t_F2xqX 400 #define t_NF2xqX 410 #define t_FlxqX 500 #define t_NFlxqX 510 #define t_FpXQX 600 #define t_NFpXQX 610 static GEN rand_g(speed_param *s) { long n = s->size; switch (s->type) { case t_INT: return rand_INT(n); case t_REAL: return rand_REAL(n); case t_F2x: return rand_F2x(n); case t_Fqx: return rand_Flx(n,DFLT_qmod); case t_Fhx: return rand_Flx(n,DFLT_hmod); case t_Flx: return rand_Flx(n,DFLT_mod); case t_Fl1x: return rand_Flx(n,DFLT_mod1); case t_Fl2x: return rand_Flx(n,DFLT_mod2); case t_NFqx: return rand_NFlx(n,DFLT_qmod); case t_NFhx: return rand_NFlx(n,DFLT_hmod); case t_NFlx: return rand_NFlx(n,DFLT_mod); case t_NFl1x: return rand_NFlx(n,DFLT_mod1); case t_NFl2x: return rand_NFlx(n,DFLT_mod2); case t_FpX: return rand_FpX(n); case t_NFpX: return rand_NFpX(n); case t_F2xqX: return rand_F2xqX(n, s->T); case t_NF2xqX: return rand_NF2xqX(n, s->T); case t_FlxqX: return rand_FlxqX(n, s->T, s->l); case t_NFlxqX: return rand_NFlxqX(n, s->T, s->l); case t_FpXQX: return rand_FpXQX(n, s->T); case t_NFpXQX: return rand_NFpXQX(n, s->T); } return NULL; } static void dft_Flxq(speed_param *s) { do { s->T = rand_NFlx(10, s->l); } while (!Flx_is_irred(s->T, s->l)); s->T[1] = evalvarn(1); s->T = Flx_get_red(s->T, s->l); } static void dft_FpXQ(speed_param *s) { s->T = rand_NFpX(10); setvarn(s->T, 1); s->T = FpX_get_red(s->T, s->p); } static void dftmod(speed_param *s) { switch (s->type) { case t_Fqx: s->l=DFLT_qmod; return; case t_Fhx: s->l=DFLT_hmod; return; case t_Flx: s->l=DFLT_mod; return; case t_Fl1x: s->l=DFLT_mod1; return; case t_Fl2x: s->l=DFLT_mod2; return; case t_NFqx: s->l=DFLT_qmod; return; case t_NFhx: s->l=DFLT_hmod; return; case t_NFlx: s->l=DFLT_mod; return; case t_NFl1x: s->l=DFLT_mod1; return; case t_NFl2x: s->l=DFLT_mod2; return; case t_FpX: s->p=LARGE_mod; return; case t_NFpX: s->p=LARGE_mod; return; case t_F2xqX: s->l=2; dft_Flxq(s); return; case t_NF2xqX: s->l=2; dft_Flxq(s); return; case t_FlxqX: s->l=DFLT_mod; dft_Flxq(s); return; case t_NFlxqX: s->l=DFLT_mod; dft_Flxq(s); return; case t_FpXQX: s->p=LARGE_mod; dft_FpXQ(s); return; case t_NFpXQX: s->p=LARGE_mod; dft_FpXQ(s); return; } } /* ========================================================== */ #define TIME_FUN(call) {\ { \ pari_sp av = avma; \ int i; \ speed_starttime(); \ i = (s)->reps; \ do { call; avma = av; } while (--i); \ } \ return speed_endtime(); \ } #define m_menable(s,var,min) (*(s->var)=minss(lg(s->x)-2,s->min)) #define m_enable(s,var) (*(s->var)=lg(s->x)-2)/* enable asymptotically fastest */ #define m_disable(s,var) (*(s->var)=lg(s->x)+1)/* disable asymptotically fastest */ static void enable(speed_param *s) { m_enable(s,var); s->enabled = 1; if (s->var_disable) m_disable(s,var_disable); if (s->var_enable) m_menable(s,var_enable,var_enable_min); } static void disable(speed_param *s) { m_disable(s,var); s->enabled = 0; if (s->var_disable) m_disable(s,var_disable); if (s->var_enable) m_menable(s,var_enable,var_enable_min); } static double speed_mulrr(speed_param *s) { TIME_FUN(mulrr(s->x, s->y)); } static double speed_sqrr(speed_param *s) { TIME_FUN(sqrr(s->x)); } static double speed_mulii(speed_param *s) { TIME_FUN(mulii(s->x, s->y)); } static double speed_sqri (speed_param *s) { TIME_FUN(sqri(s->x)); } static double speed_exp(speed_param *s) { TIME_FUN(mpexp(s->x)); } static double speed_inv(speed_param *s) { TIME_FUN(invr(s->x)); } static double speed_log(speed_param *s) { TIME_FUN(mplog(s->x)); } static double speed_logcx(speed_param *s) { GEN z; setexpo(s->x,0); z = mkcomplex(gen_1, s->x); glog(z,s->size); TIME_FUN(glog(z,s->size)); } static double speed_atan(speed_param *s) { setexpo(s->x, 0); gatan(s->x, 0); TIME_FUN(gatan(s->x, 0)); } static double speed_Fp_pow(speed_param *s) { TIME_FUN( Fp_pow(s->x, subis(s->y,1), s->y)); } static double speed_divrr(speed_param *s) { TIME_FUN(divrr(s->x, s->y)); } static double speed_invmod(speed_param *s) { GEN T; TIME_FUN(invmod(s->x, s->y, &T)); } static double speed_F2x_mul(speed_param *s) { TIME_FUN(F2x_mul(s->x, s->y)); } static double speed_Flx_sqr(speed_param *s) { TIME_FUN(Flx_sqr(s->x, s->l)); } static double speed_Flx_inv(speed_param *s) { TIME_FUN(Flx_invBarrett(s->x, s->l)); } static double speed_Flx_mul(speed_param *s) { TIME_FUN(Flx_mul(s->x, s->y, s->l)); } static double speed_Flx_divrem(speed_param *s) { GEN r, x = rand_NFlx((degpol(s->x)-1)*2, s->l); TIME_FUN(Flx_divrem(x, s->x, s->l, &r)); } static double speed_Flx_rem(speed_param *s) { GEN x = rand_NFlx((degpol(s->x)-1)*2, s->l); TIME_FUN(Flx_rem(x, s->x, s->l)); } static double speed_Flxq_red(speed_param *s) { GEN x = rand_NFlx((degpol(s->x)-1)*2, s->l); GEN q = Flx_get_red(s->x, s->l); TIME_FUN(Flx_rem(x, q, s->l)); } static double speed_Flx_halfgcd(speed_param *s) { TIME_FUN(Flx_halfgcd(s->x, s->y, s->l)); } static double speed_Flx_gcd(speed_param *s) { TIME_FUN(Flx_gcd(s->x, s->y, s->l)); } static double speed_Flx_extgcd(speed_param *s) { GEN u,v; TIME_FUN(Flx_extgcd(s->x, s->y, s->l, &u, &v)); } static double speed_FpX_inv(speed_param *s) { TIME_FUN(FpX_invBarrett(s->x, s->p)); } static double speed_FpX_divrem(speed_param *s) { GEN r, x = rand_NFpX((degpol(s->x)-1)*2); TIME_FUN(FpX_divrem(x, s->x, s->p, &r)); } static double speed_FpX_rem(speed_param *s) { GEN x = rand_NFpX((degpol(s->x)-1)*2); TIME_FUN(FpX_rem(x, s->x, s->p)); } static double speed_FpXQ_red(speed_param *s) { GEN x = rand_NFpX((degpol(s->x)-1)*2); GEN q = FpX_get_red(s->x, s->p); TIME_FUN(FpX_rem(x, q, s->p)); } static double speed_FpX_halfgcd(speed_param *s) { TIME_FUN(FpX_halfgcd(s->x, s->y, s->p)); } static double speed_FpX_gcd(speed_param *s) { TIME_FUN(FpX_gcd(s->x, s->y, s->p)); } static double speed_FpX_extgcd(speed_param *s) { GEN u,v; TIME_FUN(FpX_extgcd(s->x, s->y, s->p, &u, &v)); } static double speed_F2xqX_inv(speed_param *s) { TIME_FUN(F2xqX_invBarrett(s->x, s->T)); } static double speed_F2xqX_divrem(speed_param *s) { GEN r, x = rand_NF2xqX((degpol(s->x)-1)*2, s->T); TIME_FUN(F2xqX_divrem(x, s->x, s->T, &r)); } static double speed_F2xqX_rem(speed_param *s) { GEN x = rand_NF2xqX((degpol(s->x)-1)*2, s->T); TIME_FUN(F2xqX_rem(x, s->x, s->T)); } static double speed_F2xqXQ_red(speed_param *s) { GEN x = rand_NF2xqX((degpol(s->x)-1)*2, s->T); GEN q = F2xqX_get_red(s->x, s->T); TIME_FUN(F2xqX_rem(x, q, s->T)); } static double speed_FlxqX_inv(speed_param *s) { TIME_FUN(FlxqX_invBarrett(s->x, s->T, s->l)); } static double speed_FlxqX_divrem(speed_param *s) { GEN r, x = rand_NFlxqX((degpol(s->x)-1)*2, s->T, s->l); TIME_FUN(FlxqX_divrem(x, s->x, s->T, s->l, &r)); } static double speed_FlxqX_rem(speed_param *s) { GEN x = rand_NFlxqX((degpol(s->x)-1)*2, s->T, s->l); TIME_FUN(FlxqX_rem(x, s->x, s->T, s->l)); } static double speed_FlxqXQ_red(speed_param *s) { GEN x = rand_NFlxqX((degpol(s->x)-1)*2, s->T, s->l); GEN q = FlxqX_get_red(s->x, s->T, s->l); TIME_FUN(FlxqX_rem(x, q, s->T, s->l)); } static double speed_FlxqX_halfgcd(speed_param *s) { TIME_FUN(FlxqX_halfgcd(s->x, s->y, s->T, s->l)); } static double speed_FlxqX_extgcd(speed_param *s) { GEN u,v; TIME_FUN(FlxqX_extgcd(s->x, s->y, s->T, s->l, &u, &v)); } static double speed_FlxqX_gcd(speed_param *s) { TIME_FUN(FlxqX_gcd(s->x, s->y, s->T, s->l)); } static double speed_FpXQX_inv(speed_param *s) { TIME_FUN(FpXQX_invBarrett(s->x, s->T, s->p)); } static double speed_FpXQX_divrem(speed_param *s) { GEN r, x = rand_NFpXQX((degpol(s->x)-1)*2, s->T); TIME_FUN(FpXQX_divrem(x, s->x, s->T, s->p, &r)); } static double speed_FpXQX_rem(speed_param *s) { GEN x = rand_NFpXQX((degpol(s->x)-1)*2, s->T); TIME_FUN(FpXQX_rem(x, s->x, s->T, s->p)); } static double speed_FpXQXQ_red(speed_param *s) { GEN x = rand_NFpXQX((degpol(s->x)-1)*2, s->T); GEN q = FpXQX_get_red(s->x, s->T, s->p); TIME_FUN(FpXQX_rem(x, q, s->T, s->p)); } static double speed_FpXQX_halfgcd(speed_param *s) { TIME_FUN(FpXQX_halfgcd(s->x, s->y, s->T, s->p)); } static double speed_FpXQX_extgcd(speed_param *s) { GEN u,v; TIME_FUN(FpXQX_extgcd(s->x, s->y, s->T, s->p, &u, &v)); } static double speed_FpXQX_gcd(speed_param *s) { TIME_FUN(FpXQX_gcd(s->x, s->y, s->T, s->p)); } /* small coeffs: earlier thresholds for more complicated rings */ static double speed_RgX_sqr(speed_param *s) { TIME_FUN(RgX_sqr_i(s->x)); } static double speed_RgX_mul(speed_param *s) { TIME_FUN(RgX_mul_i(s->x, s->y)); } enum { PARI = 1, GMP = 2 }; #ifdef PARI_KERNEL_GMP # define AVOID PARI #else # define AVOID GMP #endif /* Thresholds are set in this order. If f() depends on g(), g() should * occur first */ #define var(a) # a, &a static tune_param param[] = { {PARI,var(MULII_KARATSUBA_LIMIT), t_INT, 4,0, speed_mulii,0,0,&MULII_FFT_LIMIT}, {PARI,var(SQRI_KARATSUBA_LIMIT), t_INT, 4,0, speed_sqri,0,0,&SQRI_FFT_LIMIT}, {PARI,var(MULII_FFT_LIMIT), t_INT, 500,0, speed_mulii,0.02}, {PARI,var(SQRI_FFT_LIMIT), t_INT, 500,0, speed_sqri,0.02}, {0, var(MULRR_MULII_LIMIT), t_REAL,4,0, speed_mulrr}, {0, var(SQRR_SQRI_LIMIT), t_REAL,4,0, speed_sqrr}, {0, var(Fp_POW_REDC_LIMIT), t_INT, 3,100, speed_Fp_pow,0,0,&Fp_POW_BARRETT_LIMIT}, {0, var(Fp_POW_BARRETT_LIMIT), t_INT, 3,0, speed_Fp_pow}, {0, var(INVNEWTON_LIMIT), t_REAL,66,0, speed_inv,0.03}, {GMP, var(DIVRR_GMP_LIMIT), t_REAL,4,0, speed_divrr}, {0, var(EXPNEWTON_LIMIT), t_REAL,66,0, speed_exp}, {0, var(LOGAGM_LIMIT), t_REAL,4,0, speed_log}, {0, var(LOGAGMCX_LIMIT), t_REAL,3,0, speed_logcx,0.05}, {0, var(AGM_ATAN_LIMIT), t_REAL,20,0, speed_atan,0.05}, {GMP, var(INVMOD_GMP_LIMIT), t_INT, 3,0, speed_invmod}, {0, var(F2x_MUL_KARATSUBA_LIMIT),t_F2x,3,0, speed_F2x_mul}, {0, var(Flx_MUL_KARATSUBA_LIMIT),t_Flx,5,0, speed_Flx_mul,0,0,&Fmod_MUL_MULII_LIMIT}, {0, var(Flx_SQR_KARATSUBA_LIMIT),t_Flx,5,0, speed_Flx_sqr,0,0,&Fmod_SQR_SQRI_LIMIT}, {0, var(Flx_MUL_QUARTMULII_LIMIT),t_Fqx,3,0, speed_Flx_mul}, {0, var(Flx_SQR_QUARTSQRI_LIMIT), t_Fqx,3,0, speed_Flx_sqr}, {0, var(Flx_MUL_HALFMULII_LIMIT),t_Fhx,3,0, speed_Flx_mul}, {0, var(Flx_SQR_HALFSQRI_LIMIT), t_Fhx,3,0, speed_Flx_sqr}, {0, var(Flx_MUL_MULII_LIMIT), t_Fl1x,5,0, speed_Flx_mul}, {0, var(Flx_SQR_SQRI_LIMIT), t_Fl1x,5,0, speed_Flx_sqr}, {0, var(Flx_MUL_MULII2_LIMIT), t_Fl2x,5,20000, speed_Flx_mul,0.05}, {0, var(Flx_SQR_SQRI2_LIMIT), t_Fl2x,5,20000, speed_Flx_sqr,0.05}, {0, var(Flx_INVBARRETT_KARATSUBA_LIMIT), t_NFlx,5,20000, speed_Flx_inv,0,0,&Fmod_MUL_MULII_LIMIT,&Flx_MUL_KARATSUBA_LIMIT}, {0, var(Flx_INVBARRETT_QUARTMULII_LIMIT), t_NFqx,5,0, speed_Flx_inv,0,0,NULL,&Flx_MUL_QUARTMULII_LIMIT}, {0, var(Flx_INVBARRETT_HALFMULII_LIMIT), t_NFhx,5,0, speed_Flx_inv,0,0,NULL,&Flx_MUL_HALFMULII_LIMIT}, {0, var(Flx_INVBARRETT_MULII_LIMIT), t_NFl1x,5,0, speed_Flx_inv,0,0,NULL,&Flx_MUL_MULII_LIMIT}, {0, var(Flx_INVBARRETT_MULII2_LIMIT),t_NFl2x,5,0, speed_Flx_inv,0,0,NULL,&Flx_MUL_MULII2_LIMIT}, {0, var(Flx_DIVREM_BARRETT_LIMIT),t_NFlx,10,0, speed_Flx_divrem,0.05}, {0, var(Flx_REM_BARRETT_LIMIT), t_NFlx,10,0, speed_Flx_rem,0.05}, {0, var(Flx_BARRETT_KARATSUBA_LIMIT), t_NFlx,5,0, speed_Flxq_red,0,0,&Fmod_MUL_MULII_LIMIT,&Flx_MUL_KARATSUBA_LIMIT}, {0, var(Flx_BARRETT_QUARTMULII_LIMIT), t_NFqx,5,0, speed_Flxq_red,0,0,NULL,&Flx_MUL_QUARTMULII_LIMIT}, {0, var(Flx_BARRETT_HALFMULII_LIMIT), t_NFhx,5,0, speed_Flxq_red,0,0,NULL,&Flx_MUL_HALFMULII_LIMIT}, {0, var(Flx_BARRETT_MULII_LIMIT), t_NFl1x,5,0, speed_Flxq_red,0,0,NULL,&Flx_MUL_MULII_LIMIT}, {0, var(Flx_BARRETT_MULII2_LIMIT),t_NFl2x,5,0, speed_Flxq_red,0,0,NULL,&Flx_MUL_MULII2_LIMIT}, {0, var(Flx_HALFGCD_KARATSUBA_LIMIT), t_Flx,10,0, speed_Flx_halfgcd,0,0,&Fmod_MUL_MULII_LIMIT,&Flx_MUL_KARATSUBA_LIMIT}, {0, var(Flx_HALFGCD_QUARTMULII_LIMIT), t_Fqx,10,0, speed_Flx_halfgcd,0,0,NULL,&Flx_MUL_QUARTMULII_LIMIT}, {0, var(Flx_HALFGCD_HALFMULII_LIMIT), t_Fhx,10,0, speed_Flx_halfgcd,0,0,NULL,&Flx_MUL_HALFMULII_LIMIT}, {0, var(Flx_HALFGCD_MULII_LIMIT), t_Fl1x,10,0, speed_Flx_halfgcd,0,0,NULL,&Flx_MUL_MULII_LIMIT}, {0, var(Flx_HALFGCD_MULII2_LIMIT),t_Fl2x,10,0, speed_Flx_halfgcd,0,0,NULL,&Flx_MUL_MULII2_LIMIT}, {0, var(Flx_GCD_LIMIT), t_Flx,10,0, speed_Flx_gcd,0.1}, {0, var(Flx_EXTGCD_LIMIT), t_Flx,10,0, speed_Flx_extgcd}, {0, var(F2xqX_INVBARRETT_LIMIT),t_NF2xqX,10,0, speed_F2xqX_inv,0.05}, {0, var(F2xqX_BARRETT_LIMIT), t_NF2xqX,10,0, speed_F2xqXQ_red,0.05}, {0, var(F2xqX_DIVREM_BARRETT_LIMIT), t_NF2xqX,10,0, speed_F2xqX_divrem,0.05}, {0, var(F2xqX_REM_BARRETT_LIMIT), t_NF2xqX,10,0, speed_F2xqX_rem,0.05}, {0, var(FlxqX_INVBARRETT_LIMIT),t_NFlxqX,10,0, speed_FlxqX_inv,0.05}, {0, var(FlxqX_BARRETT_LIMIT), t_NFlxqX,10,0, speed_FlxqXQ_red,0.05}, {0, var(FlxqX_DIVREM_BARRETT_LIMIT), t_NFlxqX,10,0, speed_FlxqX_divrem,0.05}, {0, var(FlxqX_REM_BARRETT_LIMIT), t_NFlxqX,10,0, speed_FlxqX_rem,0.05}, {0, var(FlxqX_HALFGCD_LIMIT), t_FlxqX,10,0, speed_FlxqX_halfgcd,0.05}, {0, var(FlxqX_GCD_LIMIT), t_FlxqX,10,0, speed_FlxqX_gcd,0.05}, {0, var(FlxqX_EXTGCD_LIMIT), t_FlxqX,10,0, speed_FlxqX_extgcd,0.05}, {0, var(FpX_INVBARRETT_LIMIT), t_NFpX,10,0, speed_FpX_inv,0.05}, {0, var(FpX_DIVREM_BARRETT_LIMIT),t_NFpX,10,0, speed_FpX_divrem,0.05}, {0, var(FpX_REM_BARRETT_LIMIT), t_NFpX,10,0, speed_FpX_rem,0.05}, {0, var(FpX_BARRETT_LIMIT), t_NFpX,10,0, speed_FpXQ_red}, {0, var(FpX_HALFGCD_LIMIT), t_FpX,10,0, speed_FpX_halfgcd}, {0, var(FpX_GCD_LIMIT), t_FpX,10,0, speed_FpX_gcd,0.1}, {0, var(FpX_EXTGCD_LIMIT), t_FpX,10,0, speed_FpX_extgcd}, {0, var(FpXQX_INVBARRETT_LIMIT),t_NFpXQX,10,0, speed_FpXQX_inv,0.05}, {0, var(FpXQX_BARRETT_LIMIT), t_NFpXQX,10,0, speed_FpXQXQ_red,0.05}, {0, var(FpXQX_DIVREM_BARRETT_LIMIT), t_NFpXQX,10,0, speed_FpXQX_divrem,0.05}, {0, var(FpXQX_REM_BARRETT_LIMIT), t_NFpXQX,10,0, speed_FpXQX_rem,0.05}, {0, var(FpXQX_HALFGCD_LIMIT), t_FpXQX,10,0, speed_FpXQX_halfgcd,0.05}, {0, var(FpXQX_GCD_LIMIT), t_FpXQX,10,0, speed_FpXQX_gcd,0.05}, {0, var(FpXQX_EXTGCD_LIMIT), t_FpXQX,10,0, speed_FpXQX_extgcd,0.05}, {0, var(RgX_MUL_LIMIT), t_FpX, 4,0, speed_RgX_mul}, {0, var(RgX_SQR_LIMIT), t_FpX, 4,0, speed_RgX_sqr}, }; /* ========================================================== */ int ndat = 0, allocdat = 0; struct dat_t { long size; double d; } *dat = NULL; int double_cmp_ptr(double *x, double *y) { return (int)(*x - *y); } double time_fun(speed_function_t fun, speed_param *s, long enabled) { const double TOLERANCE = 1.005; /* 0.5% */ pari_sp av = avma; double t[30]; ulong i, j, e; s->reps = 1; if (enabled) enable(s); else disable(s); for (i = 0; i < numberof(t); i++) { for (;;) { double reps_d; t[i] = fun(s); if (!t[i]) { s->reps *= 10; continue; } if (t[i] >= speed_unittime * speed_precision) break; /* go to a value of reps to make t[i] >= precision */ reps_d = ceil (1.1 * s->reps * speed_unittime * speed_precision / maxdd(t[i], speed_unittime)); if (reps_d > 2e9 || reps_d < 1.0) pari_err(e_MISC, "Fatal error: new reps bad: %.2f", reps_d); s->reps = (ulong)reps_d; } t[i] /= s->reps; /* require 3 values within TOLERANCE when >= 2 secs, 4 when below */ e = (t[0] >= 2.0)? 3: 4; /* Look for e many t[]'s within TOLERANCE of each other to consider a valid measurement. Return smallest among them. */ if (i >= e) { qsort (t, i+1, sizeof(t[0]), (QSCOMP)double_cmp_ptr); for (j = e-1; j < i; j++) if (t[j] <= t[j-e+1] * TOLERANCE) { avma = av; return t[j-e+1]; } } } pari_err(e_MISC,"couldn't measure time"); return -1.0; /* LCOV_EXCL_LINE */ } int cmpdat(const void *a, const void *b) { struct dat_t *da =(struct dat_t *)a; struct dat_t *db =(struct dat_t *)b; return da->size-db->size; } void add_dat(long size, double d) { if (ndat == allocdat) { allocdat += maxss(allocdat, 100); dat = (struct dat_t*) pari_realloc((void*)dat, allocdat * sizeof(dat[0])); } dat[ndat].size = size; dat[ndat].d = d; ndat++; qsort(dat, ndat, sizeof(*dat), cmpdat); } void diag(const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } void print_define(const char *name, long value) { printf("#define __%-30s %ld\n", name, value); } long analyze_dat(int final) { double x, min_x; int j, min_j; /* If the threshold is set at dat[0].size, any positive values are bad. */ x = 0.0; for (j = 0; j < ndat; j++) if (dat[j].d > 0.0) x += dat[j].d; if (final && option_trace >= 3) { diag("\n"); diag("x is the sum of the badness from setting thresh at given size\n"); diag(" (minimum x is sought)\n"); diag("size=%ld first x=%.4f\n", dat[j].size, x); } min_x = x; min_j = 0; /* When stepping to the next dat[j].size, positive values are no longer bad (so subtracted), negative values become bad (so add the absolute value, meaning subtract). */ for (j = 0; j < ndat; j++) { if (final && option_trace >= 3) diag ("size=%ld x=%.4f\n", dat[j].size, x); if (x < min_x) { min_x = x; min_j = j; } x -= dat[j].d; } return min_j; } void Test(tune_param *param, long linear) { int since_positive, since_change, thresh, new_thresh; speed_param s; long save_var_disable = -1; pari_timer T; pari_sp av=avma; long good = -1, bad = param->min_size; if (param->kernel == AVOID) { print_define(param->name, -1); return; } #define DEFAULT(x,n) if (! (param->x)) param->x = (n); DEFAULT(step_factor, Step_Factor); DEFAULT(stop_factor, 1.2); DEFAULT(max_size, 10000); if (param->var_disable) save_var_disable = *(param->var_disable); if (param->var_enable) s.var_enable_min = *(param->var_enable); s.type = param->type; s.size = param->min_size; s.var = param->var; s.var_disable = param->var_disable; s.var_enable = param->var_enable; dftmod(&s); ndat = since_positive = since_change = thresh = 0; if (option_trace >= 1) { timer_start(&T); diag("\nSetting %s... (default %ld)\n", param->name, *(param->var)); } if (option_trace >= 2) { diag(" algorithm-A algorithm-B ratio possible\n"); diag(" (seconds) (seconds) diff thresh\n"); } for(;;) { pari_sp av=avma; double t1, t2, d; s.x = rand_g(&s); s.y = rand_g(&s); t1 = time_fun(param->fun, &s, 0); t2 = time_fun(param->fun, &s, 1); avma = av; if (t2 >= t1) d = (t2 - t1) / t2; else d = (t2 - t1) / t1; add_dat(s.size, d); new_thresh = analyze_dat(0); if (option_trace >= 2) diag ("size =%4ld %.8f %.8f % .4f %c %ld\n", s.size, t1,t2, d, d < 0? '#': ' ', dat[new_thresh].size); #define SINCE_POSITIVE 20 #define SINCE_CHANGE 50 if (linear) { /* Stop if method B has been consistently faster for a while */ if (d >= 0) since_positive = 0; else if (++since_positive > SINCE_POSITIVE) { if (option_trace >= 1) diag("Stop: since_positive (%d)\n", SINCE_POSITIVE); break; } /* Stop if method A has become slower by a certain factor */ if (t1 >= t2 * param->stop_factor) { if (option_trace >= 1) diag("Stop: t1 >= t2 * factor (%.1f)\n", param->stop_factor); break; } /* Stop if threshold implied hasn't changed for a while */ if (thresh != new_thresh) since_change = 0, thresh = new_thresh; else if (++since_change > SINCE_CHANGE) { if (option_trace >= 1) diag("Stop: since_change (%d)\n", SINCE_CHANGE); break; } s.size += maxss((long)floor(s.size * param->step_factor), 1); } else { if (t2 <= t1) new_thresh = good = s.size; else bad = s.size; if (bad == -1) linear = 1; else if (good == -1) { long new_size = minss(2*s.size,param->max_size-1); if (new_size==s.size) linear = 1; s.size = new_size; } else if (good-bad < 20*param->step_factor*bad) { linear = 1; new_thresh = s.size = bad + 1; } else s.size = (good+bad)/2; err_printf("bad= %ld good = %ld thresh = %ld linear = %ld\n",bad, good, thresh, linear); } if (s.size >= param->max_size) { if (option_trace >= 1) diag("Stop: max_size (%ld). Disable Algorithm B?\n",param->max_size); break; } } thresh = dat[analyze_dat(1)].size; if (option_trace >= 1) diag("Total time: %gs\n", (double)timer_delay(&T)/1000.); print_define(param->name, thresh); *(param->var) = thresh; /* set to optimal value for next tests */ if (param->var_disable) *(param->var_disable) = save_var_disable; if (param->var_enable) *(param->var_enable) = s.var_enable_min; avma = av; } void error(char **argv) { long i; diag("This is the PARI/GP tuning utility. Usage: tune [OPTION] var1 var2...\n"); diag("Options:\n"); diag(" -t: verbose output\n"); diag(" -tt: very verbose output\n"); diag(" -ttt: output everything\n"); diag(" -s xxx: set step factor between successive sizes to xxx (default 0.01)\n"); diag(" -p xxx: set Flx modulus to xxx (default 27449)\n"); diag(" -u xxx: set speed_unittime to xxx (default 1e-4s)\n"); diag("Tunable variables (omitting variable indices tunes everybody):\n"); for (i = 0; i < (long)numberof(param); i++) diag(" %2ld: %-25s (default %4ld)\n", i, param[i].name, *(param[i].var)); exit(1); } int main(int argc, char **argv) { int i, r, n = 0; int linear = 1; GEN v; pari_init(8000000, 2); DFLT_mod = 27449; LARGE_mod=subis(powuu(3,128),62); #ifdef LONG_IS_64BIT DFLT_qmod = 3; DFLT_hmod = 257; DFLT_mod2 = 281474976710677UL; #else DFLT_qmod = 3; DFLT_hmod = 3; DFLT_mod1 = 1031UL; #endif v = new_chunk(argc); for (i = 1; i < argc; i++) { char *s = argv[i]; if (*s == '-') { switch(*++s) { case 't': option_trace++; while (*++s == 't') option_trace++; break; case 'd': linear = 1-linear; break; case 'p': if (!*++s) { if (++i == argc) error(argv); s = argv[i]; } DFLT_mod = itou(gp_read_str(s)); break; case 's': if (!*++s) { if (++i == argc) error(argv); s = argv[i]; } Step_Factor = atof(s); break; case 'u': s++; if (!*++s) { if (++i == argc) error(argv); s = argv[i]; } speed_unittime = atof(s); break; default: error(argv); } } else { if (!isdigit((int)*s)) error(argv); r = atol(s); if (r >= (long)numberof(param) || r < 0) error(argv); v[n++] = r; } } if (n) { for (i = 0; i < n; i++) Test(¶m[ v[i] ], linear); return 0; } n = numberof(param); for (i = 0; i < n; i++) Test(¶m[i], linear); return 0; } pari-2.11.2/src/basemath/0000755000175000017500000000000013461316051013531 5ustar billbillpari-2.11.2/src/basemath/elltors.c0000644000175000017500000004706513454731237015406 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** TORSION OF ELLIPTIC CURVES over NUMBER FIELDS **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" static int smaller_x(GEN p, GEN q) { int s = abscmpii(denom_i(p), denom_i(q)); return (s<0 || (s==0 && abscmpii(numer_i(p),numer_i(q)) < 0)); } /* best generator in cycle of length k */ static GEN best_in_cycle(GEN e, GEN p, long k) { GEN p0 = p,q = p; long i; for (i=2; i+i = E_tors, possibly NULL (= oo), p,q independent unless NULL * order p = k, order q = 2 unless NULL */ static GEN tors(GEN e, long k, GEN p, GEN q, GEN v) { GEN r; if (q) { long n = k>>1; GEN p1, best = q, np = ellmul(e,p,utoipos(n)); if (n % 2 && smaller_x(gel(np,1), gel(best,1))) best = np; p1 = elladd(e,q,np); if (smaller_x(gel(p1,1), gel(best,1))) q = p1; else if (best == np) { p = elladd(e,p,q); q = np; } p = best_in_cycle(e,p,k); if (v) { p = ellchangepointinv(p,v); q = ellchangepointinv(q,v); } r = cgetg(4,t_VEC); gel(r,1) = utoipos(2*k); gel(r,2) = mkvec2(utoipos(k), gen_2); gel(r,3) = mkvec2copy(p, q); } else { if (p) { p = best_in_cycle(e,p,k); if (v) p = ellchangepointinv(p,v); r = cgetg(4,t_VEC); gel(r,1) = utoipos(k); gel(r,2) = mkvec( gel(r,1) ); gel(r,3) = mkvec( gcopy(p) ); } else { r = cgetg(4,t_VEC); gel(r,1) = gen_1; gel(r,2) = cgetg(1,t_VEC); gel(r,3) = cgetg(1,t_VEC); } } return r; } /* Finds a multiplicative upper bound for #E_tor; assume integral model */ static long torsbound(GEN e) { GEN D = ell_get_disc(e); pari_sp av = avma, av2; long m, b, bold, nb; forprime_t S; long CM = ellQ_get_CM(e); nb = expi(D) >> 3; /* nb = number of primes to try ~ 1 prime every 8 bits in D */ b = bold = 5040; /* = 2^4 * 3^2 * 5 * 7 */ m = 0; /* p > 2 has good reduction => E(Q) injects in E(Fp) */ (void)u_forprime_init(&S, 3, ULONG_MAX); av2 = avma; while (m < nb || (b > 12 && b != 16)) { ulong p = u_forprime_next(&S); if (!p) pari_err_BUG("torsbound [ran out of primes]"); if (!umodiu(D, p)) continue; b = ugcd(b, p+1 - ellap_CM_fast(e,p,CM)); avma = av2; if (b == 1) break; if (b == bold) m++; else { bold = b; m = 0; } } avma = av; return b; } /* return a rational point of order pk = p^k on E, or NULL if E(Q)[k] = O. * *fk is either NULL (pk = 4 or prime) or elldivpol(p^(k-1)). * Set *fk to elldivpol(p^k) */ static GEN tpoint(GEN E, long pk, GEN *fk) { GEN f = elldivpol(E,pk,0), g = *fk, v; long i, l; *fk = f; if (g) f = RgX_div(f, g); v = nfrootsQ(f); l = lg(v); for (i = 1; i < l; i++) { GEN x = gel(v,i); GEN y = ellordinate(E,x,0); if (lg(y) != 1) return mkvec2(x,gel(y,1)); } return NULL; } /* return E(Q)[2] */ static GEN t2points(GEN E, GEN *f2) { long i, l; GEN v; *f2 = ec_bmodel(E); v = nfrootsQ(*f2); l = lg(v); for (i = 1; i < l; i++) { GEN x = gel(v,i); GEN y = ellordinate(E,x,0); if (lg(y) != 1) gel(v,i) = mkvec2(x,gel(y,1)); } return v; } static GEN elltors_divpol(GEN E) { GEN T2 = NULL, p, P, Q, v; long v2, r2, B; E = ellintegralmodel_i(E, &v); B = torsbound(E); /* #E_tor | B */ if (B == 1) return tors(E,1,NULL,NULL, v); v2 = vals(B); /* bound for v_2(point order) */ B >>= v2; p = const_vec(9, NULL); r2 = 0; if (v2) { GEN f; T2 = t2points(E, &f); switch(lg(T2)-1) { case 0: v2 = 0; break; case 1: r2 = 1; if (v2 == 4) v2 = 3; break; default: r2 = 2; v2--; break; /* 3 */ } if (v2) gel(p,2) = gel(T2,1); /* f = f_2 */ if (v2 > 1) { gel(p,4) = tpoint(E,4, &f); if (!gel(p,4)) v2 = 1; } /* if (v2>1) now f = f4 */ if (v2 > 2) { gel(p,8) = tpoint(E,8, &f); if (!gel(p,8)) v2 = 2; } } B <<= v2; if (B % 3 == 0) { GEN f3 = NULL; gel(p,3) = tpoint(E,3,&f3); if (!gel(p,3)) B /= (B%9)? 3: 9; if (gel(p,3) && B % 9 == 0) { gel(p,9) = tpoint(E,9,&f3); if (!gel(p,9)) B /= 3; } } if (B % 5 == 0) { GEN junk = NULL; gel(p,5) = tpoint(E,5,&junk); if (!gel(p,5)) B /= 5; } if (B % 7 == 0) { GEN junk = NULL; gel(p,7) = tpoint(E,7,&junk); if (!gel(p,7)) B /= 7; } /* B is the exponent of E_tors(Q), r2 is the rank of its 2-Sylow, * for i > 1, p[i] is a point of order i if one exists and i is a prime power * and NULL otherwise */ if (r2 == 2) /* 2 cyclic factors */ { /* C2 x C2 */ if (B == 2) return tors(E,2, gel(T2,1), gel(T2,2), v); else if (B == 6) { /* C2 x C6 */ P = elladd(E, gel(p,3), gel(T2,1)); Q = gel(T2,2); } else { /* C2 x C4 or C2 x C8 */ P = gel(p, B); Q = gel(T2,2); if (gequal(Q, ellmul(E, P, utoipos(B>>1)))) Q = gel(T2,1); } } else /* cyclic */ { Q = NULL; if (v2) { if (B>>v2 == 1) P = gel(p, B); else P = elladd(E, gel(p, B>>v2), gel(p,1<> 3); if (g > 20) g = 20; /* P | p such that e(P/p) < p-1 => E(K) injects in E(k(P)) [otherwise * we may lose some p-torsion]*/ (void)u_forprime_init(&S, 3, ULONG_MAX); av = avma; while (k < g) /* k = number of good primes already used */ { ulong p = u_forprime_next(&S); GEN P, gp; long j, l; if (!umodiu(ND,p)) continue; gp = utoipos(p); /* primes of degree 1 are easier and give smaller bounds */ if (typ(D) != t_POLMOD) /* E/Q */ { P = primedec_deg1(K, gp); /* single P|p has all the information */ if (!P) continue; P = mkvec(P); } else P = idealprimedec_limit_f(K, utoipos(p), 1); l = lg(P); for (j = 1; j < l; j++,k++) { GEN Q = gel(P,j), EQ, cyc; long n; if ((ulong)pr_get_e(Q) >= p-1) continue; EQ = ellinit(E,zkmodprinit(K,Q),0); cyc = ellgroup(EQ, NULL); n = lg(cyc)-1; if (n == 0) return mkvec2(gen_1,gen_1); B1 = gcdii(B1,gel(cyc,1)); B2 = (n == 1)? gen_1: gcdii(B2,gel(cyc,2)); obj_free(EQ); /* division by 2 is cheap when it fails, no need to have a sharp bound */ if (Z_ispow2(B1)) return mkvec2(B1,B2); } if ((g & 15) == 0) gerepileall(av, 2, &B1, &B2); } if (abscmpiu(B2, 2) > 0) { /* if E(K) has full n-torsion then K contains the n-th roots of 1 */ GEN n = gel(rootsof1(K), 1); B2 = gcdii(B2,n); } return mkvec2(B1,B2); } /* Checks whether the point P is divisible by n in E(K), where xn is * [phi_n, psi_n^2] * If true, returns a point Q such that nQ = P or -P. Else, returns NULL */ static GEN ellnfis_divisible_by(GEN E, GEN K, GEN P, GEN xn) { GEN r, x = gel(P,1); long i, l; if (ell_is_inf(P)) return P; r = nfroots(K, RgX_sub(RgX_Rg_mul(gel(xn,2), x), gel(xn,1))); l = lg(r); for(i=1; i= n2 such that * E(K)[p^oo] = Z/p^n1 x Z/p^n2 * Returns [cyc,gen], where E(K)[p^oo] = sum Z/cyc[i] gen[i] */ static GEN ellnftorsprimary(GEN E, long p, long N1, long N2, long v) { GEN X, P1, P2, Q1, Q2, xp, K = ellnf_get_nf(E); long n1, n2; /* compute E[p] = < P1 > or < P1, P2 > */ P1 = P2 = ellinf(); X = nfroots(K, elldivpol(E,p,v)); if(lg(X) == 1) return ptor0(); if (p==2) { P1 = tor2(E, gel(X,1)); if (lg(X) > 2) P2 = tor2(E, gel(X,2)); /* E[2] = (Z/2Z)^2 */ } else { long j, l = lg(X), nT, a; GEN T = vectrunc_init(l); for(j=1; j < l; j++) { GEN a = gel(X,j), Y = ellordinate(E,a,0); if (lg(Y) != 1) vectrunc_append(T, mkvec2(a,gel(Y,1))); } nT = lg(T)-1; if (!nT) return ptor0(); P1 = gel(T,1); a = (p-1)/2; if (nT != a) { /* E[p] = (Z/pZ)^2 */ GEN Z = cgetg(a+1,t_VEC), Q1 = P1; long k; gel(Z,1) = Q1; for (k=2; k <= a; k++) gel(Z,k) = elladd(E,Q1,P1); gen_sort_inplace(Z, (void*)&cmp_universal, &cmp_nodata, NULL); while (tablesearch(Z, gel(T,k), &cmp_universal)) k++; P2 = gel(T,k); } } xp = ellxn(E, p, v); if (ell_is_inf(P2)) { /* E[p^oo] is cyclic, start from P1 and divide by p while possible */ for (n1 = 1; n1 < N1; n1++) { GEN Q = ellnfis_divisible_by(E,K,P1,xp); if (!Q) break; P1 = Q; } return ptor1(p, n1, P1); } /* E[p] = (Z/pZ)^2, compute n2 and E[p^n2] */ Q1 = NULL; for (n2 = 1; n2 < N2; n2++) { Q1 = ellnfis_divisible_by(E,K,P1,xp); Q2 = ellnfis_divisible_by(E,K,P2,xp); if (!Q1 || !Q2) break; P1 = Q1; P2 = Q2; } /* compute E[p^oo] = < P1, P2 > */ n1 = n2; if (n2 == N2) { if (N1 == N2) return ptor2(p, n2,n2, P1,P2); Q1 = ellnfis_divisible_by(E,K,P1,xp); } if (Q1) { P1 = Q1; n1++; } else { Q2 = ellnfis_divisible_by(E,K,P2,xp); if (Q2) { P2 = P1; P1 = Q2; n1++; } else { long k; for (k = 1; k < p; k++) { P1 = elladd(E,P1,P2); Q1 = ellnfis_divisible_by(E,K,P1,xp); if (Q1) { P1 = Q1; n1++; break; } } if (k == p) return ptor2(p, n2,n2, P1,P2); } } /* P1,P2 of order p^n1,p^n2 with n1=n2+1. * Keep trying to divide P1 + k P2 with 0 <= k < p by p */ while (n1 < N1) { Q1 = ellnfis_divisible_by(E,K,P1,xp); if (Q1) { P1 = Q1; n1++; } else { long k; for (k = 1; k < p; k++) { P1 = elladd(E,P1,P2); Q1 = ellnfis_divisible_by(E,K,P1,xp); if (Q1) { P1 = Q1; n1++; break; } } if (k == p) break; } } return ptor2(p, n1,n2, P1,P2); } /* P affine point */ static GEN nfpt(GEN e, GEN P) { GEN T = nf_get_pol(ellnf_get_nf(e)); GEN x = gel(P,1), y = gel(P,2); long tx = typ(x), ty = typ(y); if (tx == ty) return P; if (tx != t_POLMOD) x = mkpolmod(x,T); else y = mkpolmod(y,T); return mkvec2(x,y); } /* Computes the torsion subgroup of E(K), as [order, cyc, gen] */ static GEN ellnftors(GEN e) { GEN B = nftorsbound(e), B1 = gel(B,1), B2 = gel(B,2), d1,d2, P1,P2; GEN f = Z_factor(B1), P = gel(f,1), E = gel(f,2); long i, l = lg(P), v = fetch_var_higher(); d1 = d2 = gen_1; P1 = P2 = ellinf(); for (i=1; i= n1 */ long N2 = Z_lval(B2,p); /* >= n2 */ GEN T = ellnftorsprimary(e, p, N1, N2, v), cyc = gel(T,1), gen = gel(T,2); if (is_pm1(gel(cyc,1))) continue; /* update generators P1,P2 and their respective orders d1,d2 */ P1 = elladd(e, P1, gel(gen,1)); d1 = mulii(d1, gel(cyc,1)); if (lg(cyc) > 2) { P2 = elladd(e, P2, gel(gen,2)); d2 = mulii(d2, gel(cyc,2)); } } (void)delete_var(); if (is_pm1(d1)) return mkvec3(gen_1,cgetg(1,t_VEC),cgetg(1,t_VEC)); if (is_pm1(d2)) return mkvec3(d1, mkvec(d1), mkvec(nfpt(e,P1))); return mkvec3(mulii(d1,d2), mkvec2(d1,d2), mkvec2(nfpt(e,P1),nfpt(e,P2))); } GEN elltors(GEN e) { pari_sp av = avma; GEN t = NULL; checkell(e); switch(ell_get_type(e)) { case t_ELL_Q: t = elltors_divpol(e); break; case t_ELL_NF: t = ellnftors(e); break; case t_ELL_Fp: case t_ELL_Fq: return ellgroup0(e,NULL,1); default: pari_err_TYPE("elltors",e); } return gerepilecopy(av, t); } GEN elltors0(GEN e, long flag) { (void)flag; return elltors(e); } /********************************************************************/ /** **/ /** ORDER OF POINTS over NUMBER FIELDS **/ /** **/ /********************************************************************/ /* E a t_ELL_Q (use Mazur's theorem) */ long ellorder_Q(GEN E, GEN P) { pari_sp av = avma; GEN dx, dy, d4, d6, D, Pp, Q; forprime_t S; ulong a4, p; long k; if (ell_is_inf(P)) return 1; if (gequal(P, ellneg(E,P))) return 2; dx = Q_denom(gel(P,1)); dy = Q_denom(gel(P,2)); if (ell_is_integral(E)) /* integral model, try Nagell Lutz */ if (abscmpiu(dx, 4) > 0 || abscmpiu(dy, 8) > 0) return 0; d4 = Q_denom(ell_get_c4(E)); d6 = Q_denom(ell_get_c6(E)); D = ell_get_disc (E); /* choose not too small prime p dividing neither a coefficient of the short Weierstrass form nor of P and leading to good reduction */ u_forprime_init(&S, 100003, ULONG_MAX); while ( (p = u_forprime_next(&S)) ) if (umodiu(d4, p) && umodiu(d6, p) && Rg_to_Fl(D, p) && umodiu(dx, p) && umodiu(dy, p)) break; /* transform E into short Weierstrass form Ep modulo p and P to Pp on Ep, * check whether the order of Pp on Ep is <= 12 */ Pp = point_to_a4a6_Fl(E, P, p, &a4); for (Q = Fle_dbl(Pp, a4, p), k = 2; !ell_is_inf(Q) && k <= 12; Q = Fle_add(Q, Pp, a4, p), k++) /* empty */; if (k == 13) k = 0; else { /* check whether [k]P = O over Q. Save potentially costly last elladd */ GEN R; Q = ellmul(E, P, utoipos(k>>1)); R = odd(k)? elladd(E, P,Q): Q; if (!gequal(Q, ellneg(E,R))) k = 0; } avma = av; return k; } /* E a t_ELL_NF */ static GEN ellorder_nf(GEN E, GEN P) { GEN K = ellnf_get_nf(E), B; pari_sp av = avma; GEN dx, dy, d4, d6, D, ND, Ep, Pp, Q, gp, modpr, pr, T, k; forprime_t S; ulong a4, p; if (ell_is_inf(P)) return gen_1; if (gequal(P, ellneg(E,P))) return gen_2; B = gel(nftorsbound(E), 1); dx = Q_denom(gel(P,1)); dy = Q_denom(gel(P,2)); d4 = Q_denom(ell_get_c4(E)); d6 = Q_denom(ell_get_c6(E)); D = ell_get_disc(E); ND = idealnorm(K,D); if (typ(ND) == t_FRAC) ND = gel(ND,1); /* choose not too small prime p of degree 1 dividing neither a coefficient of * the short Weierstrass form nor of P and leading to good reduction */ u_forprime_init(&S, 100003, ULONG_MAX); while ( (p = u_forprime_next(&S)) ) { if (!umodiu(d4, p) || !umodiu(d6, p) || !umodiu(ND, p) || !umodiu(dx, p) || !umodiu(dy, p)) continue; gp = utoipos(p); pr = primedec_deg1(K, gp); if (pr) break; } modpr = nf_to_Fq_init(K, &pr,&T,&gp); Ep = ellinit(E, pr, 0); Pp = nfV_to_FqV(P, K, modpr); /* transform E into short Weierstrass form Ep modulo p and P to Pp on Ep, * check whether the order of Pp on Ep divides B */ Pp = point_to_a4a6_Fl(Ep, Pp, p, &a4); if (!ell_is_inf(Fle_mul(Pp, B, a4, p))) { avma = av; return gen_0; } k = Fle_order(Pp, B, a4, p); { /* check whether [k]P = O over K. Save potentially costly last elladd */ GEN R; Q = ellmul(E, P, shifti(k,-1)); R = mod2(k)? elladd(E, P,Q): Q; if (!gequal(Q, ellneg(E,R))) k = gen_0; } return gerepileuptoint(av, k); } GEN ellorder(GEN E, GEN P, GEN o) { pari_sp av = avma; GEN fg, r, E0 = E; checkell(E); checkellpt(P); if (ell_is_inf(P)) return gen_1; if (ell_get_type(E)==t_ELL_Q) { long tx = typ(gel(P,1)), ty = typ(gel(P,2)); GEN p = NULL; if (is_rational_t(tx) && is_rational_t(ty)) return utoi(ellorder_Q(E, P)); if (tx == t_INTMOD || tx == t_FFELT) p = gel(P,1); if (!p && (ty == t_INTMOD || ty == t_FFELT)) p = gel(P,2); if (p) { E = ellinit(E,p,0); if (lg(E)==1) pari_err_IMPL("ellorder for curve with singular reduction"); } } if (ell_get_type(E)==t_ELL_NF) return ellorder_nf(E, P); checkell_Fq(E); fg = ellff_get_field(E); if (!o) o = ellff_get_o(E); if (typ(fg)==t_FFELT) r = FF_ellorder(E, P, o); else { GEN p = fg, e = ellff_get_a4a6(E); GEN Pp = FpE_changepointinv(RgE_to_FpE(P,p), gel(e,3), p); r = FpE_order(Pp, o, gel(e,1), p); } if (E != E0) obj_free(E); return gerepileuptoint(av, r); } GEN orderell(GEN e, GEN z) { return ellorder(e,z,NULL); } pari-2.11.2/src/basemath/arith1.c0000644000175000017500000043513013457566441015112 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*********************************************************************/ /** **/ /** ARITHMETIC FUNCTIONS **/ /** (first part) **/ /** **/ /*********************************************************************/ #include "pari.h" #include "paripriv.h" /******************************************************************/ /* */ /* GENERATOR of (Z/mZ)* */ /* */ /******************************************************************/ static GEN remove2(GEN q) { long v = vali(q); return v? shifti(q, -v): q; } static ulong u_remove2(ulong q) { return q >> vals(q); } GEN odd_prime_divisors(GEN q) { return gel(Z_factor(remove2(q)), 1); } static GEN u_odd_prime_divisors(ulong q) { return gel(factoru(u_remove2(q)), 1); } /* p odd prime, q=(p-1)/2; L0 list of (some) divisors of q = (p-1)/2 or NULL * (all prime divisors of q); return the q/l, l in L0 */ static GEN is_gener_expo(GEN p, GEN L0) { GEN L, q = shifti(p,-1); long i, l; if (L0) { l = lg(L0); L = cgetg(l, t_VEC); } else { L0 = L = odd_prime_divisors(q); l = lg(L); } for (i=1; i> 1; long i, l; GEN L; if (L0) { l = lg(L0); L = cgetg(l, t_VECSMALL); } else { L0 = L = u_odd_prime_divisors(q); l = lg(L); } for (i=1; i= 0) return 0; for (i=lg(L)-1; i; i--) { ulong t = Fl_powu(x, uel(L,i), p); if (t == p_1 || t == 1) return 0; } return 1; } /* assume p prime */ ulong pgener_Fl_local(ulong p, GEN L0) { const pari_sp av = avma; const ulong p_1 = p-1; long x; GEN L; if (p <= 19) switch(p) { /* quick trivial cases */ case 2: return 1; case 7: case 17: return 3; default: return 2; } L = u_is_gener_expo(p,L0); for (x=2;;x++) { if (is_gener_Fl(x,p,p_1,L)) break; } avma = av; return x; } ulong pgener_Fl(ulong p) { return pgener_Fl_local(p, NULL); } /* L[i] = set of (p-1)/2l, l ODD prime divisor of p-1 (l=2 can be included, * but wasteful) */ int is_gener_Fp(GEN x, GEN p, GEN p_1, GEN L) { long i, t = lgefint(x)==3? kroui(x[2], p): kronecker(x, p); if (t >= 0) return 0; for (i = lg(L)-1; i; i--) { GEN t = Fp_pow(x, gel(L,i), p); if (equalii(t, p_1) || equali1(t)) return 0; } return 1; } /* assume p prime, return a generator of all L[i]-Sylows in F_p^*. */ GEN pgener_Fp_local(GEN p, GEN L0) { pari_sp av0 = avma; GEN x, p_1, L; if (lgefint(p) == 3) { ulong z; if (p[2] == 2) return gen_1; if (L0) L0 = ZV_to_nv(L0); z = pgener_Fl_local(uel(p,2), L0); avma = av0; return utoipos(z); } p_1 = subiu(p,1); L = is_gener_expo(p, L0); x = utoipos(2); for (;; x[2]++) { if (is_gener_Fp(x, p, p_1, L)) break; } avma = av0; return utoipos(uel(x,2)); } GEN pgener_Fp(GEN p) { return pgener_Fp_local(p, NULL); } ulong pgener_Zl(ulong p) { if (p == 2) pari_err_DOMAIN("pgener_Zl","p","=",gen_2,gen_2); /* only p < 2^32 such that znprimroot(p) != znprimroot(p^2) */ if (p == 40487) return 10; #ifndef LONG_IS_64BIT return pgener_Fl(p); #else if (p < (1UL<<32)) return pgener_Fl(p); else { const pari_sp av = avma; const ulong p_1 = p-1; long x ; GEN p2 = sqru(p), L = u_is_gener_expo(p, NULL); for (x=2;;x++) if (is_gener_Fl(x,p,p_1,L) && !is_pm1(Fp_powu(utoipos(x),p_1,p2))) break; avma = av; return x; } #endif } /* p prime. Return a primitive root modulo p^e, e > 1 */ GEN pgener_Zp(GEN p) { if (lgefint(p) == 3) return utoipos(pgener_Zl(p[2])); else { const pari_sp av = avma; GEN p_1 = subiu(p,1), p2 = sqri(p), L = is_gener_expo(p,NULL); GEN x = utoipos(2); for (;; x[2]++) if (is_gener_Fp(x,p,p_1,L) && !equali1(Fp_pow(x,p_1,p2))) break; avma = av; return utoipos(uel(x,2)); } } static GEN gener_Zp(GEN q, GEN F) { GEN p = NULL; long e = 0; if (F) { GEN P = gel(F,1), E = gel(F,2); long i, l = lg(P); for (i = 1; i < l; i++) { p = gel(P,i); if (absequaliu(p, 2)) continue; if (i < l-1) pari_err_DOMAIN("znprimroot", "argument","=",F,F); e = itos(gel(E,i)); } if (!p) pari_err_DOMAIN("znprimroot", "argument","=",F,F); } else e = Z_isanypower(q, &p); return e > 1? pgener_Zp(p): pgener_Fp(q); } GEN znprimroot(GEN N) { pari_sp av = avma; GEN x, n, F; if ((F = check_arith_non0(N,"znprimroot"))) { F = clean_Z_factor(F); N = typ(N) == t_VEC? gel(N,1): factorback(F); } N = absi_shallow(N); if (abscmpiu(N, 4) <= 0) { avma = av; return mkintmodu(N[2]-1,N[2]); } switch(mod4(N)) { case 0: /* N = 0 mod 4 */ pari_err_DOMAIN("znprimroot", "argument","=",N,N); x = NULL; break; case 2: /* N = 2 mod 4 */ n = shifti(N,-1); /* becomes odd */ x = gener_Zp(n,F); if (!mod2(x)) x = addii(x,n); break; default: /* N odd */ x = gener_Zp(N,F); break; } return gerepilecopy(av, mkintmod(x, N)); } /* n | (p-1), returns a primitive n-th root of 1 in F_p^* */ GEN rootsof1_Fp(GEN n, GEN p) { pari_sp av = avma; GEN L = odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */ GEN z = pgener_Fp_local(p, L); z = Fp_pow(z, diviiexact(subiu(p,1), n), p); /* prim. n-th root of 1 */ return gerepileuptoint(av, z); } GEN rootsof1u_Fp(ulong n, GEN p) { pari_sp av = avma; GEN z, L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */ z = pgener_Fp_local(p, Flv_to_ZV(L)); z = Fp_pow(z, diviuexact(subiu(p,1), n), p); /* prim. n-th root of 1 */ return gerepileuptoint(av, z); } ulong rootsof1_Fl(ulong n, ulong p) { pari_sp av = avma; GEN L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fl_local */ ulong z = pgener_Fl_local(p, L); z = Fl_powu(z, (p-1) / n, p); /* prim. n-th root of 1 */ avma = av; return z; } /*********************************************************************/ /** **/ /** INVERSE TOTIENT FUNCTION **/ /** **/ /*********************************************************************/ /* N t_INT, L a ZV containing all prime divisors of N, and possibly other * primes. Return factor(N) */ GEN Z_factor_listP(GEN N, GEN L) { long i, k, l = lg(L); GEN P = cgetg(l, t_COL), E = cgetg(l, t_COL); for (i = k = 1; i < l; i++) { GEN p = gel(L,i); long v = Z_pvalrem(N, p, &N); if (v) { gel(P,k) = p; gel(E,k) = utoipos(v); k++; } } setlg(P, k); setlg(E, k); return mkmat2(P,E); } /* look for x such that phi(x) = n, p | x => p > m (if m = NULL: no condition). * L is a list of primes containing all prime divisors of n. */ static long istotient_i(GEN n, GEN m, GEN L, GEN *px) { pari_sp av = avma, av2; GEN k, D; long i, v; if (m && mod2(n)) { if (!equali1(n)) return 0; if (px) *px = gen_1; return 1; } D = divisors(Z_factor_listP(shifti(n, -1), L)); /* loop through primes p > m, d = p-1 | n */ av2 = avma; if (!m) { /* special case p = 2, d = 1 */ k = n; for (v = 1;; v++) { if (istotient_i(k, gen_2, L, px)) { if (px) *px = shifti(*px, v); return 1; } if (mod2(k)) break; k = shifti(k,-1); } avma = av2; } for (i = 1; i < lg(D); ++i) { GEN p, d = shifti(gel(D, i), 1); /* even divisors of n */ if (m && cmpii(d, m) < 0) continue; p = addiu(d, 1); if (!isprime(p)) continue; k = diviiexact(n, d); for (v = 1;; v++) { GEN r; if (istotient_i(k, p, L, px)) { if (px) *px = mulii(*px, powiu(p, v)); return 1; } k = dvmdii(k, p, &r); if (r != gen_0) break; } avma = av2; } avma = av; return 0; } /* find x such that phi(x) = n */ long istotient(GEN n, GEN *px) { pari_sp av = avma; if (typ(n) != t_INT) pari_err_TYPE("istotient", n); if (signe(n) < 1) return 0; if (mod2(n)) { if (!equali1(n)) return 0; if (px) *px = gen_1; return 1; } if (istotient_i(n, NULL, gel(Z_factor(n), 1), px)) { if (!px) avma = av; else *px = gerepileuptoint(av, *px); return 1; } avma = av; return 0; } /*********************************************************************/ /** **/ /** INTEGRAL LOGARITHM **/ /** **/ /*********************************************************************/ /* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e * e = floor(log_y B). Set *ptq = y^e if non-NULL */ long ulogintall(ulong B, ulong y, ulong *ptq) { ulong r, r2; long e; if (y == 2) { long eB = expu(B); /* 2^eB <= B < 2^(eB + 1) */ if (ptq) *ptq = 1UL << eB; return eB; } r = y, r2 = 1UL; for (e=1;; e++) { /* here, r = y^e, r2 = y^(e-1) */ if (r >= B) { if (r != B) { e--; r = r2; } if (ptq) *ptq = r; return e; } r2 = r; r = umuluu_or_0(y, r); if (!r) { if (ptq) *ptq = r2; return e; } } } /* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e * e = floor(log_y B). Set *ptq = y^e if non-NULL */ long logintall(GEN B, GEN y, GEN *ptq) { pari_sp av; long ey, e, emax, i, eB = expi(B); /* 2^eB <= B < 2^(eB + 1) */ GEN q, pow2; if (lgefint(B) == 3) { ulong q; if (lgefint(y) > 3) { if (ptq) *ptq = gen_1; return 0; } if (!ptq) return ulogintall(B[2], y[2], NULL); e = ulogintall(B[2], y[2], &q); *ptq = utoi(q); return e; } if (equaliu(y,2)) { if (ptq) *ptq = int2n(eB); return eB; } av = avma; ey = expi(y); /* eB/(ey+1) - 1 < e <= eB/ey */ emax = eB/ey; if (emax <= 13) /* e small, be naive */ { GEN r = y, r2 = gen_1; for (e=1;; e++) { /* here, r = y^e, r2 = y^(e-1) */ long fl = cmpii(r, B); if (fl >= 0) { if (fl) { e--; cgiv(r); r = r2; } if (ptq) *ptq = gerepileuptoint(av, r); else avma = av; return e; } r2 = r; r = mulii(r,y); } } /* e >= 13 ey / (ey+1) >= 6.5 */ /* binary splitting: compute bits of e one by one */ /* compute pow2[i] = y^(2^i) [i < crude upper bound for log_2 log_y(B)] */ pow2 = new_chunk((long)log2(eB)+2); gel(pow2,0) = y; for (i=0, q=y;; ) { GEN r = gel(pow2,i); /* r = y^2^i */ long fl = cmpii(r,B); if (!fl) { e = 1L< 0) { i--; break; } q = r; if (1L<<(i+1) > emax) break; gel(pow2,++i) = sqri(q); } for (e = 1L< 0) avma = av2; else { e += (1L<>1))) { avma = av; return 0; } y[1] = evalsigne(1) | evalvarn(varn(x)); goto END; } else { for (i = 2; i < lx; i+=2) if (!issquare(gel(x,i))) { avma = av; return 0; } avma = av; return 1; } } else { long m = 1; x = RgX_Rg_div(x,a); /* a(x^m) = B^2 => B = b(x^m) provided a(0) != 0 */ if (!signe(p)) x = RgX_deflate_max(x,&m); y = ser2rfrac_i(gsqrt(RgX_to_ser(x,lg(x)-1),0)); if (!RgX_equal(RgX_sqr(y), x)) { avma = av; return 0; } if (!pt) { avma = av; return 1; } if (!gequal1(a)) y = gmul(b, y); if (m != 1) y = RgX_inflate(y,m); } END: if (v) y = RgX_shift_shallow(y, v>>1); *pt = gerepilecopy(av, y); return 1; } /* b unit mod p */ static int Up_ispower(GEN b, GEN K, GEN p, long d, GEN *pt) { if (d == 1) { /* mod p: faster */ if (!Fp_ispower(b, K, p)) return 0; if (pt) *pt = Fp_sqrtn(b, K, p, NULL); } else { /* mod p^{2 +} */ if (!ispower(cvtop(b, p, d), K, pt)) return 0; if (pt) *pt = gtrunc(*pt); } return 1; } /* We're studying whether a mod (q*p^e) is a K-th power, (q,p) = 1. * Decide mod p^e, then reduce a mod q unless q = NULL. */ static int handle_pe(GEN *pa, GEN q, GEN L, GEN K, GEN p, long e) { GEN t, A; long v = Z_pvalrem(*pa, p, &A), d = e - v; if (d <= 0) t = gen_0; else { ulong r; v = uabsdivui_rem(v, K, &r); if (r || !Up_ispower(A, K, p, d, L? &t: NULL)) return 0; if (L && v) t = mulii(t, powiu(p, v)); } if (q) *pa = modii(*pa, q); if (L) vectrunc_append(L, mkintmod(t, powiu(p, e))); return 1; } long Zn_ispower(GEN a, GEN q, GEN K, GEN *pt) { GEN L, N; pari_sp av; long e, i, l; ulong pp; forprime_t S; if (!signe(a)) { if (pt) { GEN t = cgetg(3, t_INTMOD); gel(t,1) = icopy(q); gel(t,2) = gen_0; *pt = t; } return 1; } /* a != 0 */ av = avma; if (typ(q) != t_INT) /* integer factorization */ { GEN P = gel(q,1), E = gel(q,2); l = lg(P); L = pt? vectrunc_init(l): NULL; for (i = 1; i < l; i++) { GEN p = gel(P,i); long e = itos(gel(E,i)); if (!handle_pe(&a, NULL, L, K, p, e)) { avma = av; return 0; } } goto END; } if (!mod2(K) && kronecker(a, shifti(q,-vali(q))) == -1) { avma = av; return 0; } L = pt? vectrunc_init(expi(q)+1): NULL; u_forprime_init(&S, 2, tridiv_bound(q)); while ((pp = u_forprime_next(&S))) { int stop; e = Z_lvalrem_stop(&q, pp, &stop); if (!e) continue; if (!handle_pe(&a, q, L, K, utoipos(pp), e)) { avma = av; return 0; } if (stop) { if (!is_pm1(q) && !handle_pe(&a, q, L, K, q, 1)) { avma = av; return 0; } goto END; } } l = lg(primetab); for (i = 1; i < l; i++) { GEN p = gel(primetab,i); e = Z_pvalrem(q, p, &q); if (!e) continue; if (!handle_pe(&a, q, L, K, p, e)) { avma = av; return 0; } if (is_pm1(q)) goto END; } N = gcdii(a,q); if (!is_pm1(N)) { if (ifac_isprime(N)) { e = Z_pvalrem(q, N, &q); if (!handle_pe(&a, q, L, K, N, e)) { avma = av; return 0; } } else { GEN part = ifac_start(N, 0); for(;;) { long e; GEN p; if (!ifac_next(&part, &p, &e)) break; e = Z_pvalrem(q, p, &q); if (!handle_pe(&a, q, L, K, p, e)) { avma = av; return 0; } } } } if (!is_pm1(q)) { if (ifac_isprime(q)) { if (!handle_pe(&a, q, L, K, q, 1)) { avma = av; return 0; } } else { GEN part = ifac_start(q, 0); for(;;) { long e; GEN p; if (!ifac_next(&part, &p, &e)) break; if (!handle_pe(&a, q, L, K, p, e)) { avma = av; return 0; } } } } END: if (pt) *pt = gerepileupto(av, chinese1_coprime_Z(L)); return 1; } static long polmodispower(GEN x, GEN K, GEN *pt) { pari_sp av = avma; GEN p = NULL, T = NULL; if (Rg_is_FpXQ(x, &T,&p) && p) { x = liftall_shallow(x); if (T) T = liftall_shallow(T); if (!Fq_ispower(x, K, T, p)) { avma = av; return 0; } if (!pt) { avma = av; return 1; } x = Fq_sqrtn(x, K, T,p, NULL); if (typ(x) == t_INT) x = Fp_to_mod(x,p); else x = mkpolmod(FpX_to_mod(x,p), FpX_to_mod(T,p)); *pt = gerepilecopy(av, x); return 1; } pari_err_IMPL("ispower for general t_POLMOD"); return 0; } long issquareall(GEN x, GEN *pt) { long tx = typ(x); GEN F; pari_sp av; if (!pt) return issquare(x); switch(tx) { case t_INT: return Z_issquareall(x, pt); case t_FRAC: av = avma; F = cgetg(3, t_FRAC); if ( !Z_issquareall(gel(x,1), &gel(F,1)) || !Z_issquareall(gel(x,2), &gel(F,2))) { avma = av; return 0; } *pt = F; return 1; case t_POLMOD: return polmodispower(x, gen_2, pt); case t_POL: return polissquareall(x,pt); case t_RFRAC: av = avma; F = cgetg(3, t_RFRAC); if ( !issquareall(gel(x,1), &gel(F,1)) || !polissquareall(gel(x,2), &gel(F,2))) { avma = av; return 0; } *pt = F; return 1; case t_REAL: case t_COMPLEX: case t_PADIC: case t_SER: if (!issquare(x)) return 0; *pt = gsqrt(x, DEFAULTPREC); return 1; case t_INTMOD: return Zn_ispower(gel(x,2), gel(x,1), gen_2, pt); case t_FFELT: return FF_issquareall(x, pt); } pari_err_TYPE("issquareall",x); return 0; /* LCOV_EXCL_LINE */ } long issquare(GEN x) { pari_sp av; GEN a, p; long i, v; switch(typ(x)) { case t_INT: return Z_issquare(x); case t_REAL: return (signe(x)>=0); case t_INTMOD: return Zn_ispower(gel(x,2), gel(x,1), gen_2, NULL); case t_FRAC: return Z_issquare(gel(x,1)) && Z_issquare(gel(x,2)); case t_FFELT: return FF_issquareall(x, NULL); case t_COMPLEX: return 1; case t_PADIC: a = gel(x,4); if (!signe(a)) return 1; if (valp(x)&1) return 0; p = gel(x,2); if (!absequaliu(p, 2)) return (kronecker(a,p) != -1); v = precp(x); /* here p=2, a is odd */ if ((v>=3 && mod8(a) != 1 ) || (v==2 && mod4(a) != 1)) return 0; return 1; case t_POLMOD: return polmodispower(x, gen_2, NULL); case t_POL: return polissquareall(x,NULL); case t_SER: if (!signe(x)) return 1; if (valp(x)&1) return 0; return issquare(gel(x,2)); case t_RFRAC: av = avma; i = issquare(gmul(gel(x,1),gel(x,2))); avma = av; return i; } pari_err_TYPE("issquare",x); return 0; /* LCOV_EXCL_LINE */ } GEN gissquare(GEN x) { return issquare(x)? gen_1: gen_0; } GEN gissquareall(GEN x, GEN *pt) { return issquareall(x,pt)? gen_1: gen_0; } long ispolygonal(GEN x, GEN S, GEN *N) { pari_sp av = avma; GEN D, d, n; if (typ(x) != t_INT) pari_err_TYPE("ispolygonal", x); if (typ(S) != t_INT) pari_err_TYPE("ispolygonal", S); if (abscmpiu(S,3) < 0) pari_err_DOMAIN("ispolygonal","s","<", utoipos(3),S); if (signe(x) < 0) return 0; if (signe(x) == 0) { if (N) *N = gen_0; return 1; } if (is_pm1(x)) { if (N) *N = gen_1; return 1; } /* n = (sqrt( (8s - 16) x + (s-4)^2 ) + s - 4) / 2(s - 2) */ if (abscmpiu(S, 1<<16) < 0) /* common case ! */ { ulong s = S[2], r; if (s == 4) return Z_issquareall(x, N); if (s == 3) D = addiu(shifti(x, 3), 1); else D = addiu(mului(8*s - 16, x), (s-4)*(s-4)); if (!Z_issquareall(D, &d)) { avma = av; return 0; } if (s == 3) d = subiu(d, 1); else d = addiu(d, s - 4); n = absdiviu_rem(d, 2*s - 4, &r); if (r) { avma = av; return 0; } } else { GEN r, S_2 = subiu(S,2), S_4 = subiu(S,4); D = addii(mulii(shifti(S_2,3), x), sqri(S_4)); if (!Z_issquareall(D, &d)) { avma = av; return 0; } d = addii(d, S_4); n = dvmdii(shifti(d,-1), S_2, &r); if (r != gen_0) { avma = av; return 0; } } if (N) *N = gerepileuptoint(av, n); else avma = av; return 1; } /*********************************************************************/ /** **/ /** PERFECT POWER **/ /** **/ /*********************************************************************/ static long polispower(GEN x, GEN K, GEN *pt) { pari_sp av; long v, d, k = itos(K); GEN y, a, b; GEN T = NULL, p = NULL; if (!signe(x)) { if (pt) *pt = gcopy(x); return 1; } d = degpol(x); if (d % k) return 0; /* degree not multiple of k */ av = avma; if (RgX_is_FpXQX(x, &T, &p) && p) { /* over Fq */ if (T && typ(T) == t_FFELT) { if (!FFX_ispower(x, k, T, pt)) { avma = av; return 0; } return 1; } x = RgX_to_FqX(x,T,p); if (!FqX_ispower(x, k, T,p, pt)) { avma = av; return 0; } if (pt) *pt = gerepileupto(av, FqX_to_mod(*pt, T, p)); return 1; } v = RgX_valrem(x, &x); if (v % k) return 0; v /= k; a = gel(x,2); b = NULL; if (!ispower(a, K, &b)) { avma = av; return 0; } if (d) { GEN p = characteristic(x); a = leading_coeff(x); if (!ispower(a, K, &b)) { avma = av; return 0; } x = RgX_normalize(x); if (signe(p) && cmpii(p,K) <= 0) pari_err_IMPL("ispower(general t_POL) in small characteristic"); y = gtrunc(gsqrtn(RgX_to_ser(x,lg(x)), K, NULL, 0)); if (!RgX_equal(powgi(y, K), x)) { avma = av; return 0; } } else y = pol_1(varn(x)); if (pt) { if (!gequal1(a)) { if (!b) b = gsqrtn(a, K, NULL, DEFAULTPREC); y = gmul(b,y); } if (v) y = RgX_shift_shallow(y, v); *pt = gerepilecopy(av, y); } else avma = av; return 1; } long Z_ispowerall(GEN x, ulong k, GEN *pt) { long s = signe(x); ulong mask; if (!s) { if (pt) *pt = gen_0; return 1; } if (s > 0) { if (k == 2) return Z_issquareall(x, pt); if (k == 3) { mask = 1; return !!is_357_power(x, pt, &mask); } if (k == 5) { mask = 2; return !!is_357_power(x, pt, &mask); } if (k == 7) { mask = 4; return !!is_357_power(x, pt, &mask); } return is_kth_power(x, k, pt); } if (!odd(k)) return 0; if (Z_ispowerall(absi_shallow(x), k, pt)) { if (pt) *pt = negi(*pt); return 1; }; return 0; } /* is x a K-th power mod p ? Assume p prime. */ int Fp_ispower(GEN x, GEN K, GEN p) { pari_sp av = avma; GEN p_1; long r; x = modii(x, p); if (!signe(x) || equali1(x)) { avma = av; return 1; } /* implies p > 2 */ p_1 = subiu(p,1); K = gcdii(K, p_1); if (absequaliu(K, 2)) { r = kronecker(x,p); avma = av; return (r > 0); } x = Fp_pow(x, diviiexact(p_1,K), p); avma = av; return equali1(x); } /* x unit defined modulo 2^e, e > 0, p prime */ static int U2_issquare(GEN x, long e) { long r = signe(x)>=0?mod8(x):8-mod8(x); if (e==1) return 1; if (e==2) return (r&3L) == 1; return r == 1; } /* x unit defined modulo p^e, e > 0, p prime */ static int Up_issquare(GEN x, GEN p, long e) { return (absequaliu(p,2))? U2_issquare(x, e): kronecker(x,p)==1; } long Zn_issquare(GEN d, GEN fn) { long j, np; if (typ(d) != t_INT) pari_err_TYPE("Zn_issquare",d); if (typ(fn) == t_INT) return Zn_ispower(d, fn, gen_2, NULL); /* integer factorization */ np = nbrows(fn); for (j = 1; j <= np; ++j) { GEN r, p = gcoeff(fn, j, 1); long e = itos(gcoeff(fn, j, 2)); long v = Z_pvalrem(d,p,&r); if (v < e && (odd(v) || !Up_issquare(r, p, e-v))) return 0; } return 1; } static long Qp_ispower(GEN x, GEN K, GEN *pt) { pari_sp av = avma; GEN z = Qp_sqrtn(x, K, NULL); if (!z) { avma = av; return 0; } if (pt) *pt = z; return 1; } long ispower(GEN x, GEN K, GEN *pt) { GEN z; if (!K) return gisanypower(x, pt); if (typ(K) != t_INT) pari_err_TYPE("ispower",K); if (signe(K) <= 0) pari_err_DOMAIN("ispower","exponent","<=",gen_0,K); if (equali1(K)) { if (pt) *pt = gcopy(x); return 1; } switch(typ(x)) { case t_INT: if (lgefint(K) != 3) return 0; return Z_ispowerall(x, itou(K), pt); case t_FRAC: { GEN a = gel(x,1), b = gel(x,2); ulong k; if (lgefint(K) != 3) return 0; k = itou(K); if (pt) { z = cgetg(3, t_FRAC); if (Z_ispowerall(a, k, &a) && Z_ispowerall(b, k, &b)) { *pt = z; gel(z,1) = a; gel(z,2) = b; return 1; } avma = (pari_sp)(z + 3); return 0; } return Z_ispower(a, k) && Z_ispower(b, k); } case t_INTMOD: return Zn_ispower(gel(x,2), gel(x,1), K, pt); case t_FFELT: return FF_ispower(x, K, pt); case t_PADIC: return Qp_ispower(x, K, pt); case t_POLMOD: return polmodispower(x, K, pt); case t_POL: return polispower(x, K, pt); case t_RFRAC: { GEN a = gel(x,1), b = gel(x,2); if (pt) { z = cgetg(3, t_RFRAC); if (ispower(a, K, &a) && polispower(b, K, &b)) { *pt = z; gel(z,1) = a; gel(z,2) = b; return 1; } avma = (pari_sp)(z + 3); return 0; } return (ispower(a, K, NULL) && polispower(b, K, NULL)); } case t_REAL: if (signe(x) < 0 && !mpodd(K)) return 0; case t_COMPLEX: if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC); return 1; case t_SER: if (signe(x) && (!dvdsi(valp(x), K) || !ispower(gel(x,2), K, NULL))) return 0; if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC); return 1; } pari_err_TYPE("ispower",x); return 0; /* LCOV_EXCL_LINE */ } long gisanypower(GEN x, GEN *pty) { long tx = typ(x); ulong k, h; if (tx == t_INT) return Z_isanypower(x, pty); if (tx == t_FRAC) { pari_sp av = avma; GEN fa, P, E, a = gel(x,1), b = gel(x,2); long i, j, p, e; int sw = (abscmpii(a, b) > 0); if (sw) swap(a, b); k = Z_isanypower(a, pty? &a: NULL); if (!k) { /* a = -1,1 or not a pure power */ if (!is_pm1(a)) { avma = av; return 0; } if (signe(a) < 0) b = negi(b); k = Z_isanypower(b, pty? &b: NULL); if (!k || !pty) { avma = av; return k; } *pty = gerepileupto(av, ginv(b)); return k; } fa = factoru(k); P = gel(fa,1); E = gel(fa,2); h = k; for (i = lg(P) - 1; i > 0; i--) { p = P[i]; e = E[i]; for (j = 0; j < e; j++) if (!is_kth_power(b, p, &b)) break; if (j < e) k /= upowuu(p, e - j); } if (k == 1) { avma = av; return 0; } if (!pty) { avma = av; return k; } if (k != h) a = powiu(a, h/k); *pty = gerepilecopy(av, mkfrac(a, b)); return k; } pari_err_TYPE("gisanypower", x); return 0; /* LCOV_EXCL_LINE */ } /* v_p(x) = e != 0 for some p; return ispower(x,,&x), updating x. * No need to optimize for 2,3,5,7 powers (done before) */ static long split_exponent(ulong e, GEN *x) { GEN fa, P, E; long i, j, l, k = 1; if (e == 1) return 1; fa = factoru(e); P = gel(fa,1); E = gel(fa,2); l = lg(P); for (i = 1; i < l; i++) { ulong p = P[i]; for (j = 0; j < E[i]; j++) { GEN y; if (!is_kth_power(*x, p, &y)) break; k *= p; *x = y; } } return k; } static long Z_isanypower_nosmalldiv(GEN *px) { /* any prime divisor of x is > 102 */ const double LOG2_103 = 6.6865; /* lower bound for log_2(103) */ const double LOG103 = 4.6347; /* lower bound for log(103) */ forprime_t T; ulong mask = 7, e2; long k, ex; GEN y, x = *px; k = 1; while (Z_issquareall(x, &y)) { k <<= 1; x = y; } while ( (ex = is_357_power(x, &y, &mask)) ) { k *= ex; x = y; } e2 = (ulong)((expi(x) + 1) / LOG2_103); /* >= log_103 (x) */ if (u_forprime_init(&T, 11, e2)) { GEN logx = NULL; const ulong Q = 30011; /* prime */ ulong p, xmodQ; double dlogx = 0; /* cut off at x^(1/p) ~ 2^30 bits which seems to be about optimum; * for large p the modular checks are no longer competitively fast */ while ( (ex = is_pth_power(x, &y, &T, 30)) ) { k *= ex; x = y; e2 = (ulong)((expi(x) + 1) / LOG2_103); u_forprime_restrict(&T, e2); } if (DEBUGLEVEL>4) err_printf("Z_isanypower: now k=%ld, x=%ld-bit\n", k, expi(x)); xmodQ = umodiu(x, Q); /* test Q | x, just in case */ if (!xmodQ) { *px = x; return k * split_exponent(Z_lval(x,Q), px); } /* x^(1/p) < 2^31 */ p = T.p; if (p <= e2) { logx = logr_abs( itor(x, DEFAULTPREC) ); dlogx = rtodbl(logx); e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */ } while (p && p <= e2) { /* is x a p-th power ? By computing y = round(x^(1/p)). * Check whether y^p = x, first mod Q, then exactly. */ pari_sp av = avma; long e; GEN logy = divru(logx, p), y = grndtoi(mpexp(logy), &e); ulong ymodQ = umodiu(y,Q); if (e >= -10 || Fl_powu(ymodQ, p % (Q-1), Q) != xmodQ || !equalii(powiu(y, p), x)) avma = av; else { k *= p; x = y; xmodQ = ymodQ; logx = logy; dlogx /= p; e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */ u_forprime_restrict(&T, e2); continue; /* if success, retry same p */ } p = u_forprime_next(&T); } } *px = x; return k; } static ulong tinyprimes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199 }; /* disregard the sign of x, caller will take care of x < 0 */ static long Z_isanypower_aux(GEN x, GEN *pty) { long ex, v, i, l, k; GEN y, P, E; ulong mask, e = 0; if (abscmpii(x, gen_2) < 0) return 0; /* -1,0,1 */ if (signe(x) < 0) x = negi(x); k = l = 1; P = cgetg(26 + 1, t_VECSMALL); E = cgetg(26 + 1, t_VECSMALL); /* trial division */ for(i = 0; i < 26; i++) { ulong p = tinyprimes[i]; int stop; v = Z_lvalrem_stop(&x, p, &stop); if (v) { P[l] = p; E[l] = v; l++; e = ugcd(e, v); if (e == 1) goto END; } if (stop) { if (is_pm1(x)) k = e; goto END; } } if (e) { /* Bingo. Result divides e */ long v3, v5, v7; ulong e2 = e; v = u_lvalrem(e2, 2, &e2); if (v) { for (i = 0; i < v; i++) { if (!Z_issquareall(x, &y)) break; k <<= 1; x = y; } } mask = 0; v3 = u_lvalrem(e2, 3, &e2); if (v3) mask = 1; v5 = u_lvalrem(e2, 5, &e2); if (v5) mask |= 2; v7 = u_lvalrem(e2, 7, &e2); if (v7) mask |= 4; while ( (ex = is_357_power(x, &y, &mask)) ) { x = y; switch(ex) { case 3: k *= 3; if (--v3 == 0) mask &= ~1; break; case 5: k *= 5; if (--v5 == 0) mask &= ~2; break; case 7: k *= 7; if (--v7 == 0) mask &= ~4; break; } } k *= split_exponent(e2, &x); } else k = Z_isanypower_nosmalldiv(&x); END: if (pty && k != 1) { if (e) { /* add missing small factors */ y = powuu(P[1], E[1] / k); for (i = 2; i < l; i++) y = mulii(y, powuu(P[i], E[i] / k)); x = equali1(x)? y: mulii(x,y); } *pty = x; } return k == 1? 0: k; } long Z_isanypower(GEN x, GEN *pty) { pari_sp av = avma; long k = Z_isanypower_aux(x, pty); if (!k) { avma = av; return 0; } if (signe(x) < 0) { long v = vals(k); if (v) { GEN y; k >>= v; if (k == 1) { avma = av; return 0; } if (!pty) { avma = av; return k; } y = *pty; y = powiu(y, 1< p >= 103 */ v = Z_isanypower_nosmalldiv(&n); /* expensive */ if (!(flag? isprime(n): BPSW_psp(n))) { avma = av; return 0; } if (pt) *pt = gerepilecopy(av, n); else avma = av; return v; } long isprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,1); } long ispseudoprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,0); } long uisprimepower(ulong n, ulong *pp) { /* We must have CUTOFF^11 >= ULONG_MAX and CUTOFF^3 < ULONG_MAX. * Tests suggest that 200-300 is the best range for 64-bit platforms. */ const ulong CUTOFF = 200UL; const long TINYCUTOFF = 46; /* tinyprimes[45] = 199 */ const ulong CUTOFF3 = CUTOFF*CUTOFF*CUTOFF; #ifdef LONG_IS_64BIT /* primes preceeding the appropriate root of ULONG_MAX. */ const ulong ROOT9 = 137; const ulong ROOT8 = 251; const ulong ROOT7 = 563; const ulong ROOT5 = 7129; const ulong ROOT4 = 65521; #else const ulong ROOT9 = 11; const ulong ROOT8 = 13; const ulong ROOT7 = 23; const ulong ROOT5 = 83; const ulong ROOT4 = 251; #endif ulong mask; long v, i; int e; if (n < 2) return 0; if (!odd(n)) { if (n & (n-1)) return 0; *pp = 2; return vals(n); } if (n < 8) { *pp = n; return 1; } /* 3,5,7 */ for (i = 1/*skip p=2*/; i < TINYCUTOFF; i++) { ulong p = tinyprimes[i]; if (n % p == 0) { v = u_lvalrem(n, p, &n); if (n == 1) { *pp = p; return v; } return 0; } } /* p | n => p >= CUTOFF */ if (n < CUTOFF3) { if (n < CUTOFF*CUTOFF || uisprime_101(n)) { *pp = n; return 1; } if (uissquareall(n, &n)) { *pp = n; return 2; } return 0; } /* Check for squares, fourth powers, and eighth powers as appropriate. */ v = 1; if (uissquareall(n, &n)) { v <<= 1; if (CUTOFF <= ROOT4 && uissquareall(n, &n)) { v <<= 1; if (CUTOFF <= ROOT8 && uissquareall(n, &n)) v <<= 1; } } if (CUTOFF > ROOT5) mask = 1; else { const ulong CUTOFF5 = CUTOFF3*CUTOFF*CUTOFF; if (n < CUTOFF5) mask = 1; else mask = 3; if (CUTOFF <= ROOT7) { const ulong CUTOFF7 = CUTOFF5*CUTOFF*CUTOFF; if (n >= CUTOFF7) mask = 7; } } if (CUTOFF <= ROOT9 && (e = uis_357_power(n, &n, &mask))) { v *= e; mask=1; } if ((e = uis_357_power(n, &n, &mask))) v *= e; if (uisprime_101(n)) { *pp = n; return v; } return 0; } /*********************************************************************/ /** **/ /** KRONECKER SYMBOL **/ /** **/ /*********************************************************************/ /* t = 3,5 mod 8 ? (= 2 not a square mod t) */ static int ome(long t) { switch(t & 7) { case 3: case 5: return 1; default: return 0; } } /* t a t_INT, is t = 3,5 mod 8 ? */ static int gome(GEN t) { return signe(t)? ome( mod2BIL(t) ): 0; } /* assume y odd, return kronecker(x,y) * s */ static long krouu_s(ulong x, ulong y, long s) { ulong x1 = x, y1 = y, z; while (x1) { long r = vals(x1); if (r) { if (odd(r) && ome(y1)) s = -s; x1 >>= r; } if (x1 & y1 & 2) s = -s; z = y1 % x1; y1 = x1; x1 = z; } return (y1 == 1)? s: 0; } long kronecker(GEN x, GEN y) { pari_sp av = avma; long s = 1, r; ulong xu, yu; if (typ(x) != t_INT) pari_err_TYPE("kronecker",x); if (typ(y) != t_INT) pari_err_TYPE("kronecker",y); switch (signe(y)) { case -1: y = negi(y); if (signe(x) < 0) s = -1; break; case 0: return is_pm1(x); } r = vali(y); if (r) { if (!mpodd(x)) { avma = av; return 0; } if (odd(r) && gome(x)) s = -s; y = shifti(y,-r); } x = modii(x,y); while (lgefint(x) > 3) /* x < y */ { GEN z; r = vali(x); if (r) { if (odd(r) && gome(y)) s = -s; x = shifti(x,-r); } /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */ if (mod2BIL(x) & mod2BIL(y) & 2) s = -s; z = remii(y,x); y = x; x = z; if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"kronecker"); gerepileall(av, 2, &x, &y); } } xu = itou(x); if (!xu) return is_pm1(y)? s: 0; r = vals(xu); if (r) { if (odd(r) && gome(y)) s = -s; xu >>= r; } /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */ if (xu & mod2BIL(y) & 2) s = -s; yu = umodiu(y, xu); avma = av; return krouu_s(yu, xu, s); } long krois(GEN x, long y) { ulong yu; long s = 1; if (y <= 0) { if (y == 0) return is_pm1(x); yu = (ulong)-y; if (signe(x) < 0) s = -1; } else yu = (ulong)y; if (!odd(yu)) { long r; if (!mpodd(x)) return 0; r = vals(yu); yu >>= r; if (odd(r) && gome(x)) s = -s; } return krouu_s(umodiu(x, yu), yu, s); } /* assume y != 0 */ long kroiu(GEN x, ulong y) { long r; if (odd(y)) return krouu_s(umodiu(x,y), y, 1); if (!mpodd(x)) return 0; r = vals(y); y >>= r; return krouu_s(umodiu(x,y), y, (odd(r) && gome(x))? -1: 1); } /* assume y > 0, odd, return s * kronecker(x,y) */ static long krouodd(ulong x, GEN y, long s) { long r; if (lgefint(y) == 3) return krouu_s(x, y[2], s); if (!x) return 0; /* y != 1 */ r = vals(x); if (r) { if (odd(r) && gome(y)) s = -s; x >>= r; } /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */ if (x & mod2BIL(y) & 2) s = -s; return krouu_s(umodiu(y,x), x, s); } long krosi(long x, GEN y) { const pari_sp av = avma; long s = 1, r; switch (signe(y)) { case -1: y = negi(y); if (x < 0) s = -1; break; case 0: return (x==1 || x==-1); } r = vali(y); if (r) { if (!odd(x)) { avma = av; return 0; } if (odd(r) && ome(x)) s = -s; y = shifti(y,-r); } if (x < 0) { x = -x; if (mod4(y) == 3) s = -s; } s = krouodd((ulong)x, y, s); avma = av; return s; } long kroui(ulong x, GEN y) { const pari_sp av = avma; long s = 1, r; switch (signe(y)) { case -1: y = negi(y); break; case 0: return x==1UL; } r = vali(y); if (r) { if (!odd(x)) { avma = av; return 0; } if (odd(r) && ome(x)) s = -s; y = shifti(y,-r); } s = krouodd(x, y, s); avma = av; return s; } long kross(long x, long y) { ulong yu; long s = 1; if (y <= 0) { if (y == 0) return (labs(x)==1); yu = (ulong)-y; if (x < 0) s = -1; } else yu = (ulong)y; if (!odd(yu)) { long r; if (!odd(x)) return 0; r = vals(yu); yu >>= r; if (odd(r) && ome(x)) s = -s; } x %= (long)yu; if (x < 0) x += yu; return krouu_s((ulong)x, yu, s); } long krouu(ulong x, ulong y) { long r; if (odd(y)) return krouu_s(x, y, 1); if (!odd(x)) return 0; r = vals(y); y >>= r; return krouu_s(x, y, (odd(r) && ome(x))? -1: 1); } /*********************************************************************/ /** **/ /** HILBERT SYMBOL **/ /** **/ /*********************************************************************/ /* x,y are t_INT or t_REAL */ static long mphilbertoo(GEN x, GEN y) { long sx = signe(x), sy = signe(y); if (!sx || !sy) return 0; return (sx < 0 && sy < 0)? -1: 1; } long hilbertii(GEN x, GEN y, GEN p) { pari_sp av; long oddvx, oddvy, z; if (!p) return mphilbertoo(x,y); if (is_pm1(p) || signe(p) < 0) pari_err_PRIME("hilbertii",p); if (!signe(x) || !signe(y)) return 0; av = avma; oddvx = odd(Z_pvalrem(x,p,&x)); oddvy = odd(Z_pvalrem(y,p,&y)); /* x, y are p-units, compute hilbert(x * p^oddvx, y * p^oddvy, p) */ if (absequaliu(p, 2)) { z = (Mod4(x) == 3 && Mod4(y) == 3)? -1: 1; if (oddvx && gome(y)) z = -z; if (oddvy && gome(x)) z = -z; } else { z = (oddvx && oddvy && mod4(p) == 3)? -1: 1; if (oddvx && kronecker(y,p) < 0) z = -z; if (oddvy && kronecker(x,p) < 0) z = -z; } avma = av; return z; } static void err_prec(void) { pari_err_PREC("hilbert"); } static void err_p(GEN p, GEN q) { pari_err_MODULUS("hilbert", p,q); } static void err_oo(GEN p) { pari_err_MODULUS("hilbert", p, strtoGENstr("oo")); } /* x t_INTMOD, *pp = prime or NULL [ unset, set it to x.mod ]. * Return lift(x) provided it's p-adic accuracy is large enough to decide * hilbert()'s value [ problem at p = 2 ] */ static GEN lift_intmod(GEN x, GEN *pp) { GEN p = *pp, N = gel(x,1); x = gel(x,2); if (!p) { *pp = p = N; switch(itos_or_0(p)) { case 2: case 4: err_prec(); } return x; } if (!signe(p)) err_oo(N); if (absequaliu(p,2)) { if (vali(N) <= 2) err_prec(); } else { if (!dvdii(N,p)) err_p(N,p); } if (!signe(x)) err_prec(); return x; } /* x t_PADIC, *pp = prime or NULL [ unset, set it to x.p ]. * Return lift(x)*p^(v(x) mod 2) provided it's p-adic accuracy is large enough * to decide hilbert()'s value [ problem at p = 2 ]*/ static GEN lift_padic(GEN x, GEN *pp) { GEN p = *pp, q = gel(x,2), y = gel(x,4); if (!p) *pp = p = q; else if (!equalii(p,q)) err_p(p, q); if (absequaliu(p,2) && precp(x) <= 2) err_prec(); if (!signe(y)) err_prec(); return odd(valp(x))? mulii(p,y): y; } long hilbert(GEN x, GEN y, GEN p) { pari_sp av = avma; long tx = typ(x), ty = typ(y), z; if (p && typ(p) != t_INT) pari_err_TYPE("hilbert",p); if (tx == t_REAL) { if (p && signe(p)) err_oo(p); switch (ty) { case t_INT: case t_REAL: return mphilbertoo(x,y); case t_FRAC: return mphilbertoo(x,gel(y,1)); default: pari_err_TYPE2("hilbert",x,y); } } if (ty == t_REAL) { if (p && signe(p)) err_oo(p); switch (tx) { case t_INT: case t_REAL: return mphilbertoo(x,y); case t_FRAC: return mphilbertoo(gel(x,1),y); default: pari_err_TYPE2("hilbert",x,y); } } if (tx == t_INTMOD) { x = lift_intmod(x, &p); tx = t_INT; } if (ty == t_INTMOD) { y = lift_intmod(y, &p); ty = t_INT; } if (tx == t_PADIC) { x = lift_padic(x, &p); tx = t_INT; } if (ty == t_PADIC) { y = lift_padic(y, &p); ty = t_INT; } if (tx == t_FRAC) { tx = t_INT; x = p? mulii(gel(x,1),gel(x,2)): gel(x,1); } if (ty == t_FRAC) { ty = t_INT; y = p? mulii(gel(y,1),gel(y,2)): gel(y,1); } if (tx != t_INT || ty != t_INT) pari_err_TYPE2("hilbert",x,y); if (p && !signe(p)) p = NULL; z = hilbertii(x,y,p); avma = av; return z; } /*******************************************************************/ /* */ /* SQUARE ROOT MODULO p */ /* */ /*******************************************************************/ static ulong Fl_2gener_pre_all(long e, ulong p, ulong pi) { ulong y, m; long k, i; ulong q = (p-1) >> e; /* q = (p-1)/2^oo is odd */ for (k=2; ; k++) { /* loop terminates for k < p (even if p composite) */ i = krouu(k, p); if (i >= 0) { if (i) continue; pari_err_PRIME("Fl_sqrt [modulus]",utoi(p)); } y = m = Fl_powu_pre(k, q, p, pi); for (i=1; i> e; /* q = (p-1)/2^oo is odd */ if (e == 1) y = p1; else if (y==0) y = Fl_2gener_pre_all(e, p, pi); p1 = Fl_powu_pre(a, q >> 1, p, pi); /* a ^ [(q-1)/2] */ if (!p1) return 0; v = Fl_mul_pre(a, p1, p, pi); w = Fl_mul_pre(v, p1, p, pi); while (w != 1) { /* a*w = v^2, y primitive 2^e-th root of 1 a square --> w even power of y, hence w^(2^(e-1)) = 1 */ p1 = Fl_sqr_pre(w,p,pi); for (k=1; p1 != 1 && k < e; k++) p1 = Fl_sqr_pre(p1,p,pi); if (k == e) return ~0UL; /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */ p1 = y; for (i=1; i < e-k; i++) p1 = Fl_sqr_pre(p1, p, pi); y = Fl_sqr_pre(p1, p, pi); e = k; w = Fl_mul_pre(y, w, p, pi); v = Fl_mul_pre(v, p1, p, pi); } p1 = p - v; if (v > p1) v = p1; return v; } ulong Fl_sqrt(ulong a, ulong p) { ulong pi = get_Fl_red(p); return Fl_sqrt_pre_i(a, 0, p, pi); } ulong Fl_sqrt_pre(ulong a, ulong p, ulong pi) { return Fl_sqrt_pre_i(a, 0, p, pi); } static ulong Fl_lgener_pre_all(ulong l, long e, ulong r, ulong p, ulong pi, ulong *pt_m) { ulong x, y, m; ulong le1 = upowuu(l, e-1); for (x = 2; ; x++) { y = Fl_powu_pre(x, r, p, pi); if (y==1) continue; m = Fl_powu_pre(y, le1, p, pi); if (m != 1) break; } *pt_m = m; return y; } /* solve x^l = a , l prime in G of order q. * * q = (l^e)*r, e >= 1, (r,l) = 1 * y generates the l-Sylow of G * m = y^(l^(e-1)) != 1 */ static ulong Fl_sqrtl_raw(ulong a, ulong l, ulong e, ulong r, ulong p, ulong pi, ulong y, ulong m) { ulong p1, v, w, z, dl; ulong u2; if (a==0) return a; u2 = Fl_inv(l%r, r); v = Fl_powu_pre(a, u2, p, pi); w = Fl_powu_pre(v, l, p, pi); w = Fl_mul_pre(w, Fl_inv(a, p), p, pi); if (w==1) return v; if (y==0) y = Fl_lgener_pre_all(l, e, r, p, pi, &m); while (w!=1) { ulong k = 0; p1 = w; do { z = p1; p1 = Fl_powu_pre(p1, l, p, pi); k++; } while (p1!=1); if (k==e) return ULONG_MAX; dl = Fl_log_pre(z, m, l, p, pi); dl = Fl_neg(dl, l); p1 = Fl_powu_pre(y,dl*upowuu(l,e-k-1),p,pi); m = Fl_powu_pre(m, dl, p, pi); e = k; v = Fl_mul_pre(p1,v,p,pi); y = Fl_powu_pre(p1,l,p,pi); w = Fl_mul_pre(y,w,p,pi); } return v; } static ulong Fl_sqrtl_i(ulong a, ulong l, ulong p, ulong pi, ulong y, ulong m) { ulong r, e = u_lvalrem(p-1, l, &r); return Fl_sqrtl_raw(a, l, e, r, p, pi, y, m); } ulong Fl_sqrtl_pre(ulong a, ulong l, ulong p, ulong pi) { return Fl_sqrtl_i(a, l, p, pi, 0, 0); } ulong Fl_sqrtl(ulong a, ulong l, ulong p) { ulong pi = get_Fl_red(p); return Fl_sqrtl_i(a, l, p, pi, 0, 0); } ulong Fl_sqrtn_pre(ulong a, long n, ulong p, ulong pi, ulong *zetan) { ulong m, q = p-1, z; ulong nn = n >= 0 ? (ulong)n: -(ulong)n; if (a==0) { if (n < 0) pari_err_INV("Fl_sqrtn", mkintmod(gen_0,utoi(p))); if (zetan) *zetan = 1UL; return 0; } if (n==1) { if (zetan) *zetan = 1; return n < 0? Fl_inv(a,p): a; } if (n==2) { if (zetan) *zetan = p-1; return Fl_sqrt_pre_i(a, 0, p, pi); } if (a == 1 && !zetan) return a; m = ugcd(nn, q); z = 1; if (m!=1) { GEN F = factoru(m); long i, j, e; ulong r, zeta, y, l; for (i = nbrows(F); i; i--) { l = ucoeff(F,i,1); j = ucoeff(F,i,2); e = u_lvalrem(q,l, &r); y = Fl_lgener_pre_all(l, e, r, p, pi, &zeta); if (zetan) z = Fl_mul_pre(z, Fl_powu_pre(y, upowuu(l,e-j), p, pi), p, pi); if (a!=1) do { a = Fl_sqrtl_raw(a, l, e, r, p, pi, y, zeta); if (a==ULONG_MAX) return ULONG_MAX; } while (--j); } } if (m != nn) { ulong qm = q/m, nm = nn/m; a = Fl_powu_pre(a, Fl_inv(nm%qm, qm), p, pi); } if (n < 0) a = Fl_inv(a, p); if (zetan) *zetan = z; return a; } ulong Fl_sqrtn(ulong a, long n, ulong p, ulong *zetan) { ulong pi = get_Fl_red(p); return Fl_sqrtn_pre(a, n, p, pi, zetan); } /* Cipolla is better than Tonelli-Shanks when e = v_2(p-1) is "too big". * Otherwise, is a constant times worse; for p = 3 (mod 4), is about 3 times worse, * and in average is about 2 or 2.5 times worse. But try both algorithms for * S(n) = (2^n+3)^2-8 with n = 750, 771, 779, 790, 874, 1176, 1728, 2604, etc. * * If X^2 := t^2 - a is not a square in F_p (so X is in F_p^2), then * (t+X)^(p+1) = (t-X)(t+X) = a, hence sqrt(a) = (t+X)^((p+1)/2) in F_p^2. * If (a|p)=1, then sqrt(a) is in F_p. * cf: LNCS 2286, pp 430-434 (2002) [Gonzalo Tornaria] */ /* compute y^2, y = y[1] + y[2] X */ static GEN sqrt_Cipolla_sqr(void *data, GEN y) { GEN u = gel(y,1), v = gel(y,2), p = gel(data,2), n = gel(data,3); GEN u2 = sqri(u), v2 = sqri(v); v = subii(sqri(addii(v,u)), addii(u2,v2)); u = addii(u2, mulii(v2,n)); /* NOT mkvec2: must be gerepileupto-able */ retmkvec2(modii(u,p), modii(v,p)); } /* compute (t+X) y^2 */ static GEN sqrt_Cipolla_msqr(void *data, GEN y) { GEN u = gel(y,1), v = gel(y,2), a = gel(data,1), p = gel(data,2), gt = gel(data,4); ulong t = gt[2]; GEN d = addii(u, mului(t,v)), d2= sqri(d); GEN b = remii(mulii(a,v), p); u = subii(mului(t,d2), mulii(b,addii(u,d))); v = subii(d2, mulii(b,v)); /* NOT mkvec2: must be gerepileupto-able */ retmkvec2(modii(u,p), modii(v,p)); } /* assume a reduced mod p [ otherwise correct but inefficient ] */ static GEN sqrt_Cipolla(GEN a, GEN p) { pari_sp av1; GEN u, v, n, y, pov2; ulong t; if (kronecker(a, p) < 0) return NULL; pov2 = shifti(p,-1); if (cmpii(a,pov2) > 0) a = subii(a,p); /* center: avoid multiplying by huge base*/ av1 = avma; for(t=1; ; t++) { n = subsi((long)(t*t), a); if (kronecker(n, p) < 0) break; avma = av1; } /* compute (t+X)^((p-1)/2) =: u+vX */ u = utoipos(t); y = gen_pow_fold(mkvec2(u, gen_1), pov2, mkvec4(a,p,n,u), sqrt_Cipolla_sqr, sqrt_Cipolla_msqr); /* Now u+vX = (t+X)^((p-1)/2); thus * (u+vX)(t+X) = sqrt(a) + 0 X * Whence, * sqrt(a) = (u+vt)t - v*a * 0 = (u+vt) * Thus a square root is v*a */ v = Fp_mul(gel(y, 2), a, p); if (cmpii(v,pov2) > 0) v = subii(p,v); return v; } /* Return NULL if p is found to be composite */ static GEN Fp_2gener_all(long e, GEN p) { GEN y, m; long k; GEN q = shifti(subiu(p,1), -e); /* q = (p-1)/2^oo is odd */ if (e==0 && !equaliu(p,2)) return NULL; for (k=2; ; k++) { long i = krosi(k, p); if (i >= 0) { if (i) continue; return NULL; } y = m = Fp_pow(utoi(k), q, p); for (i=1; i 0) v = q; else avma = av; return v; } /* Tonelli-Shanks. Assume p is prime and return NULL if (a,p) = -1. */ GEN Fp_sqrt_i(GEN a, GEN y, GEN p) { pari_sp av = avma; long i, k, e; GEN p1, q, v, w; if (typ(a) != t_INT) pari_err_TYPE("Fp_sqrt",a); if (typ(p) != t_INT) pari_err_TYPE("Fp_sqrt",p); if (signe(p) <= 0 || equali1(p)) pari_err_PRIME("Fp_sqrt",p); if (lgefint(p) == 3) { ulong pp = uel(p,2), u = Fl_sqrt(umodiu(a, pp), pp); if (u == ~0UL) return NULL; return utoi(u); } a = modii(a, p); if (!signe(a)) { avma = av; return gen_0; } p1 = subiu(p,1); e = vali(p1); if (e <= 2) { /* direct formulas more efficient */ pari_sp av2; if (e == 0) pari_err_PRIME("Fp_sqrt [modulus]",p); /* p != 2 */ if (e == 1) { q = addiu(shifti(p1,-2),1); /* (p+1) / 4 */ v = Fp_pow(a, q, p); } else { /* Atkin's formula */ GEN i, a2 = shifti(a,1); if (cmpii(a2,p) >= 0) a2 = subii(a2,p); q = shifti(p1, -3); /* (p-5)/8 */ v = Fp_pow(a2, q, p); i = Fp_mul(a2, Fp_sqr(v,p), p); /* i^2 = -1 */ v = Fp_mul(a, Fp_mul(v, subiu(i,1), p), p); } av2 = avma; /* must check equality in case (a/p) = -1 or p not prime */ e = equalii(Fp_sqr(v,p), a); avma = av2; return e? gerepileuptoint(av,choose_sqrt(v,p)): NULL; } /* On average, Cipolla is better than Tonelli/Shanks if and only if * e(e-1) > 8*log2(n)+20, see LNCS 2286 pp 430 [GTL] */ if (e*(e-1) > 20 + 8 * expi(p)) { v = sqrt_Cipolla(a,p); if (!v) { avma = av; return NULL; } return gerepileuptoint(av,v); } if (!y) { y = Fp_2gener_all(e, p); if (!y) pari_err_PRIME("Fp_sqrt [modulus]",p); } q = shifti(p1,-e); /* q = (p-1)/2^oo is odd */ p1 = Fp_pow(a, shifti(q,-1), p); /* a ^ (q-1)/2 */ v = Fp_mul(a, p1, p); w = Fp_mul(v, p1, p); while (!equali1(w)) { /* a*w = v^2, y primitive 2^e-th root of 1 a square --> w even power of y, hence w^(2^(e-1)) = 1 */ p1 = Fp_sqr(w,p); for (k=1; !equali1(p1) && k < e; k++) p1 = Fp_sqr(p1,p); if (k == e) { avma=av; return NULL; } /* p composite or (a/p) != 1 */ /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */ p1 = y; for (i=1; i < e-k; i++) p1 = Fp_sqr(p1,p); y = Fp_sqr(p1, p); e = k; w = Fp_mul(y, w, p); v = Fp_mul(v, p1, p); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"Fp_sqrt"); gerepileall(av,3, &y,&w,&v); } } return gerepileuptoint(av, choose_sqrt(v,p)); } GEN Fp_sqrt(GEN a, GEN p) { return Fp_sqrt_i(a, NULL, p); } /*********************************************************************/ /** **/ /** GCD & BEZOUT **/ /** **/ /*********************************************************************/ GEN lcmii(GEN x, GEN y) { pari_sp av; GEN a, b; if (!signe(x) || !signe(y)) return gen_0; av = avma; a = gcdii(x,y); if (!equali1(a)) y = diviiexact(y,a); b = mulii(x,y); setabssign(b); return gerepileuptoint(av, b); } /* given x in assume 0 < x < N; return u in (Z/NZ)^* such that u x = gcd(x,N) (mod N); * set *pd = gcd(x,N) */ GEN Fp_invgen(GEN x, GEN N, GEN *pd) { GEN d, d0, e, v; if (lgefint(N) == 3) { ulong dd, NN = N[2], xx = umodiu(x,NN); if (!xx) { *pd = N; return gen_0; } xx = Fl_invgen(xx, NN, &dd); *pd = utoi(dd); return utoi(xx); } *pd = d = bezout(x, N, &v, NULL); if (equali1(d)) return v; /* vx = gcd(x,N) (mod N), v coprime to N/d but need not be coprime to N */ e = diviiexact(N,d); d0 = Z_ppo(d, e); /* d = d0 d1, d0 coprime to N/d, rad(d1) | N/d */ if (equali1(d0)) return v; if (!equalii(d,d0)) e = lcmii(e, diviiexact(d,d0)); return Z_chinese_coprime(v, gen_1, e, d0, mulii(e,d0)); } /*********************************************************************/ /** **/ /** CHINESE REMAINDERS **/ /** **/ /*********************************************************************/ /* Chinese Remainder Theorem. x and y must have the same type (integermod, * polymod, or polynomial/vector/matrix recursively constructed with these * as coefficients). Creates (with the same type) a z in the same residue * class as x and the same residue class as y, if it is possible. * * We also allow (during recursion) two identical objects even if they are * not integermod or polymod. For example: * * ? x = [1, Mod(5, 11), Mod(X + Mod(2, 7), X^2 + 1)]; * ? y = [1, Mod(7, 17), Mod(X + Mod(0, 3), X^2 + 1)]; * ? chinese(x, y) * %3 = [1, Mod(16, 187), Mod(X + mod(9, 21), X^2 + 1)] */ static GEN gen_chinese(GEN x, GEN(*f)(GEN,GEN)) { GEN z = gassoc_proto(f,x,NULL); if (z == gen_1) retmkintmod(gen_0,gen_1); return z; } /* x t_INTMOD, y t_POLMOD; promote x to t_POLMOD mod Pol(x.mod) then * call chinese: makes Mod(0,1) a better "neutral" element */ static GEN chinese_intpol(GEN x,GEN y) { pari_sp av = avma; GEN z = mkpolmod(gel(x,2), scalarpol_shallow(gel(x,1), varn(gel(y,1)))); return gerepileupto(av, chinese(z, y)); } GEN chinese1(GEN x) { return gen_chinese(x,chinese); } GEN chinese(GEN x, GEN y) { pari_sp av; long tx = typ(x), ty; GEN z,p1,p2,d,u,v; if (!y) return chinese1(x); if (gidentical(x,y)) return gcopy(x); ty = typ(y); if (tx == ty) switch(tx) { case t_POLMOD: { GEN A = gel(x,1), B = gel(y,1); GEN a = gel(x,2), b = gel(y,2); if (varn(A)!=varn(B)) pari_err_VAR("chinese",A,B); if (RgX_equal(A,B)) retmkpolmod(chinese(a,b), gcopy(A)); /*same modulus*/ av = avma; d = RgX_extgcd(A,B,&u,&v); p2 = gsub(b, a); if (!gequal0(gmod(p2, d))) break; p1 = gdiv(A,d); p2 = gadd(a, gmul(gmul(u,p1), p2)); z = cgetg(3, t_POLMOD); gel(z,1) = gmul(p1,B); gel(z,2) = gmod(p2,gel(z,1)); return gerepileupto(av, z); } case t_INTMOD: { GEN A = gel(x,1), B = gel(y,1); GEN a = gel(x,2), b = gel(y,2), c, d, C, U; z = cgetg(3,t_INTMOD); Z_chinese_pre(A, B, &C, &U, &d); c = Z_chinese_post(a, b, C, U, d); if (!c) pari_err_OP("chinese", x,y); avma = (pari_sp)z; gel(z,1) = icopy(C); gel(z,2) = icopy(c); return z; } case t_POL: { long i, lx = lg(x), ly = lg(y); if (varn(x) != varn(y)) break; if (lx < ly) { swap(x,y); lswap(lx,ly); } z = cgetg(lx, t_POL); z[1] = x[1]; for (i=2; i>1)+1, t_VEC); if (typ(xa)==t_VECSMALL) { for (j=1, k=1; k>1)+1, t_VEC); for (j=1, k=1; k=1; i--) { GEN u = gel(T, i); GEN v = gel(Tp, i+1); long n = lg(u)-1; t = cgetg(n+1, t_VEC); for (j=1, k=1; k2) err_printf("Start parallel Chinese remainder: "); mt_queue_start_lim(&pt, worker, l-1); for (i=1; i2) err_printf("%ld%% ",(++cnt)*100/(l-1)); } } if (DEBUGLEVEL>2) err_printf("\n"); mt_queue_end(&pt); return M; } GEN nxMV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2) { return nxCV_polint_center_tree(vA, P, T, R, m2); } static GEN nxMV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2) { long i, j, l = lg(gel(vA,1)), n = lg(P); GEN A = cgetg(n, t_VEC); GEN V = cgetg(l, t_MAT); for (i=1; i < l; i++) { for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i); gel(V,i) = nxCV_polint_center_tree(A, P, T, R, m2); } return V; } static GEN nxMV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2) { GEN worker = snm_closure(is_entry("_nxMV_polint_worker"), mkvec4(T, R, P, m2)); return polint_chinese(worker, mA, P); } static GEN nmV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2) { long i, j, l = lg(gel(vA,1)), n = lg(P); GEN A = cgetg(n, t_VEC); GEN V = cgetg(l, t_MAT); for (i=1; i < l; i++) { for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i); gel(V,i) = ncV_polint_center_tree(A, P, T, R, m2); } return V; } GEN nmV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2) { return ncV_polint_center_tree(vA, P, T, R, m2); } static GEN nmV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2) { GEN worker = snm_closure(is_entry("_polint_worker"), mkvec4(T, R, P, m2)); return polint_chinese(worker, mA, P); } /* return [A mod P[i], i=1..#P] */ GEN Z_ZV_mod(GEN A, GEN P) { pari_sp av = avma; return gerepilecopy(av, Z_ZV_mod_tree(A, P, ZV_producttree(P))); } /* P a t_VECSMALL */ GEN Z_nv_mod(GEN A, GEN P) { pari_sp av = avma; return gerepileuptoleaf(av, Z_ZV_mod_tree(A, P, ZV_producttree(P))); } /* B a ZX, T = ZV_producttree(P) */ GEN ZX_nv_mod_tree(GEN B, GEN A, GEN T) { pari_sp av; long i, j, l = lg(B), n = lg(A)-1; GEN V = cgetg(n+1, t_VEC); for (j=1; j <= n; j++) { gel(V, j) = cgetg(l, t_VECSMALL); mael(V, j, 1) = B[1]&VARNBITS; } av = avma; for (i=2; i < l; i++) { GEN v = Z_ZV_mod_tree(gel(B, i), A, T); for (j=1; j <= n; j++) mael(V, j, i) = v[j]; avma = av; } for (j=1; j <= n; j++) (void) Flx_renormalize(gel(V, j), l); return V; } static GEN to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; } GEN ZXX_nv_mod_tree(GEN P, GEN xa, GEN T, long w) { pari_sp av = avma; long i, j, l = lg(P), n = lg(xa)-1, vP = varn(P); GEN V = cgetg(n+1, t_VEC); for (j=1; j <= n; j++) { gel(V, j) = cgetg(l, t_POL); mael(V, j, 1) = vP; } for (i=2; i < l; i++) { GEN v = ZX_nv_mod_tree(to_ZX(gel(P, i), w), xa, T); for (j=1; j <= n; j++) gmael(V, j, i) = gel(v,j); } for (j=1; j <= n; j++) (void) FlxX_renormalize(gel(V, j), l); return gerepilecopy(av, V); } GEN ZXC_nv_mod_tree(GEN C, GEN xa, GEN T, long w) { pari_sp av = avma; long i, j, l = lg(C), n = lg(xa)-1; GEN V = cgetg(n+1, t_VEC); for (j = 1; j <= n; j++) gel(V, j) = cgetg(l, t_COL); for (i = 1; i < l; i++) { GEN v = ZX_nv_mod_tree(to_ZX(gel(C, i), w), xa, T); for (j = 1; j <= n; j++) gmael(V, j, i) = gel(v,j); } return gerepilecopy(av, V); } GEN ZXM_nv_mod_tree(GEN M, GEN xa, GEN T, long w) { pari_sp av = avma; long i, j, l = lg(M), n = lg(xa)-1; GEN V = cgetg(n+1, t_VEC); for (j=1; j <= n; j++) gel(V, j) = cgetg(l, t_MAT); for (i=1; i < l; i++) { GEN v = ZXC_nv_mod_tree(gel(M, i), xa, T, w); for (j=1; j <= n; j++) gmael(V, j, i) = gel(v,j); } return gerepilecopy(av, V); } /* B a ZX, T = ZV_producttree(P) */ GEN ZV_nv_mod_tree(GEN B, GEN A, GEN T) { pari_sp av; long i, j, l = lg(B), n = lg(A)-1; GEN V = cgetg(n+1, t_VEC); for (j=1; j <= n; j++) gel(V, j) = cgetg(l, t_VECSMALL); av = avma; for (i=1; i < l; i++) { GEN v = Z_ZV_mod_tree(gel(B, i), A, T); for (j=1; j <= n; j++) mael(V, j, i) = v[j]; avma = av; } return V; } GEN ZM_nv_mod_tree(GEN M, GEN xa, GEN T) { pari_sp av = avma; long i, j, l = lg(M), n = lg(xa)-1; GEN V = cgetg(n+1, t_VEC); for (j=1; j <= n; j++) gel(V, j) = cgetg(l, t_MAT); for (i=1; i < l; i++) { GEN v = ZV_nv_mod_tree(gel(M, i), xa, T); for (j=1; j <= n; j++) gmael(V, j, i) = gel(v,j); } return gerepilecopy(av, V); } static GEN ZV_sqr(GEN z) { long i,l = lg(z); GEN x = cgetg(l, t_VEC); if (typ(z)==t_VECSMALL) for (i=1; i 1 */ static ulong Fl_2powu_pre(ulong n, ulong p, ulong pi) { ulong y = 2; int j = 1+bfffo(n); /* normalize, i.e set highest bit to 1 (we know n != 0) */ n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */ for (; j; n<<=1,j--) { y = Fl_sqr_pre(y,p,pi); if (n & HIGHBIT) y = Fl_double(y, p); } return y; } /* 2^n mod p; assume n > 1 and !(p & HIGHMASK) */ static ulong Fl_2powu(ulong n, ulong p) { ulong y = 2; int j = 1+bfffo(n); /* normalize, i.e set highest bit to 1 (we know n != 0) */ n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */ for (; j; n<<=1,j--) { y = (y*y) % p; if (n & HIGHBIT) y = Fl_double(y, p); } return y; } ulong Fl_powu_pre(ulong x, ulong n0, ulong p, ulong pi) { ulong y, z, n; if (n0 <= 1) { /* frequent special cases */ if (n0 == 1) return x; if (n0 == 0) return 1; } if (x <= 2) { if (x == 2) return Fl_2powu_pre(n0, p, pi); return x; /* 0 or 1 */ } y = 1; z = x; n = n0; for(;;) { if (n&1) y = Fl_mul_pre(y,z,p,pi); n>>=1; if (!n) return y; z = Fl_sqr_pre(z,p,pi); } } ulong Fl_powu(ulong x, ulong n0, ulong p) { ulong y, z, n; if (n0 <= 2) { /* frequent special cases */ if (n0 == 2) return Fl_sqr(x,p); if (n0 == 1) return x; if (n0 == 0) return 1; } if (x <= 1) return x; /* 0 or 1 */ if (p & HIGHMASK) return Fl_powu_pre(x, n0, p, get_Fl_red(p)); if (x == 2) return Fl_2powu(n0, p); y = 1; z = x; n = n0; for(;;) { if (n&1) y = (y*z) % p; n>>=1; if (!n) return y; z = (z*z) % p; } } /* Reduce data dependency to maximize internal parallelism */ GEN Fl_powers_pre(ulong x, long n, ulong p, ulong pi) { long i, k; GEN powers = cgetg(n + 2, t_VECSMALL); powers[1] = 1; if (n == 0) return powers; powers[2] = x; for (i = 3, k=2; i <= n; i+=2, k++) { powers[i] = Fl_sqr_pre(powers[k], p, pi); powers[i+1] = Fl_mul_pre(powers[k], powers[k+1], p, pi); } if (i==n+1) powers[i] = Fl_sqr_pre(powers[k], p, pi); return powers; } GEN Fl_powers(ulong x, long n, ulong p) { return Fl_powers_pre(x, n, p, get_Fl_red(p)); } /********************************************************************** ** ** ** Powering over (Z/NZ)^*, large N ** ** ** **********************************************************************/ static GEN Fp_dblsqr(GEN x, GEN N) { GEN z = shifti(Fp_sqr(x, N), 1); return cmpii(z, N) >= 0? subii(z, N): z; } typedef struct muldata { GEN (*sqr)(void * E, GEN x); GEN (*mul)(void * E, GEN x, GEN y); GEN (*mul2)(void * E, GEN x); } muldata; /* modified Barrett reduction with one fold */ /* See Fast Modular Reduction, W. Hasenplaugh, G. Gaubatz, V. Gopal, ARITH 18 */ static GEN Fp_invmBarrett(GEN p, long s) { GEN R, Q = dvmdii(int2n(3*s),p,&R); return mkvec2(Q,R); } /* a <= (N-1)^2, 2^(2s-2) <= N < 2^(2s). Return 0 <= r < N such that * a = r (mod N) */ static GEN Fp_rem_mBarrett(GEN a, GEN B, long s, GEN N) { pari_sp av = avma; GEN P = gel(B, 1), Q = gel(B, 2); /* 2^(3s) = P N + Q, 0 <= Q < N */ long t = expi(P)+1; /* 2^(t-1) <= P < 2^t */ GEN u = shifti(a, -3*s), v = remi2n(a, 3*s); /* a = 2^(3s)u + v */ GEN A = addii(v, mulii(Q,u)); /* 0 <= A < 2^(3s+1) */ GEN q = shifti(mulii(shifti(A, t-3*s), P), -t); /* A/N - 4 < q <= A/N */ GEN r = subii(A, mulii(q, N)); GEN sr= subii(r,N); /* 0 <= r < 4*N */ if (signe(sr)<0) return gerepileuptoint(av, r); r=sr; sr = subii(r,N); /* 0 <= r < 3*N */ if (signe(sr)<0) return gerepileuptoint(av, r); r=sr; sr = subii(r,N); /* 0 <= r < 2*N */ return gerepileuptoint(av, signe(sr)>=0 ? sr:r); } /* Montgomery reduction */ INLINE ulong init_montdata(GEN N) { return (ulong) -invmod2BIL(mod2BIL(N)); } struct montred { GEN N; ulong inv; }; /* Montgomery reduction */ static GEN _sqr_montred(void * E, GEN x) { struct montred * D = (struct montred *) E; return red_montgomery(sqri(x), D->N, D->inv); } /* Montgomery reduction */ static GEN _mul_montred(void * E, GEN x, GEN y) { struct montred * D = (struct montred *) E; return red_montgomery(mulii(x, y), D->N, D->inv); } static GEN _mul2_montred(void * E, GEN x) { struct montred * D = (struct montred *) E; GEN z = shifti(_sqr_montred(E, x), 1); long l = lgefint(D->N); while (lgefint(z) > l) z = subii(z, D->N); return z; } static GEN _sqr_remii(void* N, GEN x) { return remii(sqri(x), (GEN) N); } static GEN _mul_remii(void* N, GEN x, GEN y) { return remii(mulii(x, y), (GEN) N); } static GEN _mul2_remii(void* N, GEN x) { return Fp_dblsqr(x, (GEN) N); } struct redbarrett { GEN iM, N; long s; }; static GEN _sqr_remiibar(void *E, GEN x) { struct redbarrett * D = (struct redbarrett *) E; return Fp_rem_mBarrett(sqri(x), D->iM, D->s, D->N); } static GEN _mul_remiibar(void *E, GEN x, GEN y) { struct redbarrett * D = (struct redbarrett *) E; return Fp_rem_mBarrett(mulii(x, y), D->iM, D->s, D->N); } static GEN _mul2_remiibar(void *E, GEN x) { struct redbarrett * D = (struct redbarrett *) E; return Fp_dblsqr(x, D->N); } static long Fp_select_red(GEN *y, ulong k, GEN N, long lN, muldata *D, void **pt_E) { if (lN >= Fp_POW_BARRETT_LIMIT && (k==0 || ((double)k)*expi(*y) > 2 + expi(N))) { struct redbarrett * E = (struct redbarrett *) stack_malloc(sizeof(struct redbarrett)); D->sqr = &_sqr_remiibar; D->mul = &_mul_remiibar; D->mul2 = &_mul2_remiibar; E->N = N; E->s = 1+(expi(N)>>1); E->iM = Fp_invmBarrett(N, E->s); *pt_E = (void*) E; return 0; } else if (mod2(N) && lN < Fp_POW_REDC_LIMIT) { struct montred * E = (struct montred *) stack_malloc(sizeof(struct montred)); *y = remii(shifti(*y, bit_accuracy(lN)), N); D->sqr = &_sqr_montred; D->mul = &_mul_montred; D->mul2 = &_mul2_montred; E->N = N; E->inv = init_montdata(N); *pt_E = (void*) E; return 1; } else { D->sqr = &_sqr_remii; D->mul = &_mul_remii; D->mul2 = &_mul2_remii; *pt_E = (void*) N; return 0; } } GEN Fp_powu(GEN A, ulong k, GEN N) { long lN = lgefint(N); int base_is_2, use_montgomery; muldata D; void *E; pari_sp av; if (lN == 3) { ulong n = uel(N,2); return utoi( Fl_powu(umodiu(A, n), k, n) ); } if (k <= 2) { /* frequent special cases */ if (k == 2) return Fp_sqr(A,N); if (k == 1) return A; if (k == 0) return gen_1; } av = avma; A = modii(A,N); base_is_2 = 0; if (lgefint(A) == 3) switch(A[2]) { case 1: avma = av; return gen_1; case 2: base_is_2 = 1; break; } /* TODO: Move this out of here and use for general modular computations */ use_montgomery = Fp_select_red(&A, k, N, lN, &D, &E); if (base_is_2) A = gen_powu_fold_i(A, k, E, D.sqr, D.mul2); else A = gen_powu_i(A, k, E, D.sqr, D.mul); if (use_montgomery) { A = red_montgomery(A, N, ((struct montred *) E)->inv); if (cmpii(A, N) >= 0) A = subii(A,N); } return gerepileuptoint(av, A); } GEN Fp_pows(GEN A, long k, GEN N) { if (lgefint(N) == 3) { ulong n = N[2]; ulong a = umodiu(A, n); if (k < 0) { a = Fl_inv(a, n); k = -k; } return utoi( Fl_powu(a, (ulong)k, n) ); } if (k < 0) { A = Fp_inv(A, N); k = -k; }; return Fp_powu(A, (ulong)k, N); } /* A^K mod N */ GEN Fp_pow(GEN A, GEN K, GEN N) { pari_sp av; long s, lN = lgefint(N), sA; int base_is_2, use_montgomery; GEN y; muldata D; void *E; s = signe(K); if (!s) return dvdii(A,N)? gen_0: gen_1; if (lN == 3 && lgefint(K) == 3) { ulong n = N[2], a = umodiu(A, n); if (s < 0) a = Fl_inv(a, n); if (a <= 1) return utoi(a); /* 0 or 1 */ return utoi(Fl_powu(a, uel(K,2), n)); } av = avma; if (s < 0) y = Fp_inv(A,N); else { y = modii(A,N); if (!signe(y)) { avma = av; return gen_0; } } if (lgefint(K) == 3) return gerepileuptoint(av, Fp_powu(y, K[2], N)); base_is_2 = 0; sA = signe(y)==-1 && mod2(K); if (lgefint(y) == 3) switch(y[2]) { case 1: return sA ? gen_m1 : gen_1; case 2: base_is_2 = 1; break; } /* TODO: Move this out of here and use for general modular computations */ use_montgomery = Fp_select_red(&y, 0UL, N, lN, &D, &E); if (base_is_2) y = gen_pow_fold_i(y, K, E, D.sqr, D.mul2); else y = gen_pow_i(y, K, E, D.sqr, D.mul); if (use_montgomery) { y = red_montgomery(y, N, ((struct montred *) E)->inv); if (cmpii(y,N) >= 0) y = subii(y,N); if (sA) y = subii(N, y); } return gerepileuptoint(av,y); } static GEN _Fp_mul(void *E, GEN x, GEN y) { return Fp_mul(x,y,(GEN)E); } static GEN _Fp_sqr(void *E, GEN x) { return Fp_sqr(x,(GEN)E); } static GEN _Fp_one(void *E) { (void) E; return gen_1; } GEN Fp_pow_init(GEN x, GEN n, long k, GEN p) { return gen_pow_init(x, n, k, (void*)p, &_Fp_sqr, &_Fp_mul); } GEN Fp_pow_table(GEN R, GEN n, GEN p) { return gen_pow_table(R, n, (void*)p, &_Fp_one, &_Fp_mul); } GEN Fp_powers(GEN x, long n, GEN p) { if (lgefint(p) == 3) return Flv_to_ZV(Fl_powers(umodiu(x, uel(p, 2)), n, uel(p, 2))); return gen_powers(x, n, 1, (void*)p, _Fp_sqr, _Fp_mul, _Fp_one); } static GEN _Fp_pow(void *E, GEN x, GEN n) { return Fp_pow(x,n,(GEN)E); } static GEN _Fp_rand(void *E) { return addiu(randomi(subiu((GEN)E,1)),1); } static GEN Fp_easylog(void *E, GEN a, GEN g, GEN ord); static const struct bb_group Fp_star={_Fp_mul,_Fp_pow,_Fp_rand,hash_GEN, equalii,equali1,Fp_easylog}; static GEN _Fp_red(void *E, GEN x) { return Fp_red(x, (GEN)E); } static GEN _Fp_add(void *E, GEN x, GEN y) { (void) E; return addii(x,y); } static GEN _Fp_neg(void *E, GEN x) { (void) E; return negi(x); } static GEN _Fp_rmul(void *E, GEN x, GEN y) { (void) E; return mulii(x,y); } static GEN _Fp_inv(void *E, GEN x) { return Fp_inv(x,(GEN)E); } static int _Fp_equal0(GEN x) { return signe(x)==0; } static GEN _Fp_s(void *E, long x) { (void) E; return stoi(x); } static const struct bb_field Fp_field={_Fp_red,_Fp_add,_Fp_rmul,_Fp_neg, _Fp_inv,_Fp_equal0,_Fp_s}; const struct bb_field *get_Fp_field(void **E, GEN p) { *E = (void*)p; return &Fp_field; } /*********************************************************************/ /** **/ /** ORDER of INTEGERMOD x in (Z/nZ)* **/ /** **/ /*********************************************************************/ ulong Fl_order(ulong a, ulong o, ulong p) { pari_sp av = avma; GEN m, P, E; long i; if (!o) o = p-1; m = factoru(o); P = gel(m,1); E = gel(m,2); for (i = lg(P)-1; i; i--) { ulong j, l = P[i], e = E[i], t = o / upowuu(l,e), y = Fl_powu(a, t, p); if (y == 1) o = t; else for (j = 1; j < e; j++) { y = Fl_powu(y, l, p); if (y == 1) { o = t * upowuu(l, j); break; } } } avma = av; return o; } /*Find the exact order of a assuming a^o==1*/ GEN Fp_order(GEN a, GEN o, GEN p) { if (lgefint(p) == 3 && (!o || typ(o) == t_INT)) { ulong pp = p[2], oo = (o && lgefint(o)==3)? o[2]: pp-1; return utoi( Fl_order(umodiu(a, pp), oo, pp) ); } return gen_order(a, o, (void*)p, &Fp_star); } GEN Fp_factored_order(GEN a, GEN o, GEN p) { return gen_factored_order(a, o, (void*)p, &Fp_star); } /* return order of a mod p^e, e > 0, pe = p^e */ static GEN Zp_order(GEN a, GEN p, long e, GEN pe) { GEN ap, op; if (absequaliu(p, 2)) { if (e == 1) return gen_1; if (e == 2) return mod4(a) == 1? gen_1: gen_2; if (mod4(a) == 1) op = gen_1; else { op = gen_2; a = Fp_sqr(a, pe); } } else { ap = (e == 1)? a: remii(a,p); op = Fp_order(ap, subiu(p,1), p); if (e == 1) return op; a = Fp_pow(a, op, pe); /* 1 mod p */ } if (equali1(a)) return op; return mulii(op, powiu(p, e - Z_pval(subiu(a,1), p))); } GEN znorder(GEN x, GEN o) { pari_sp av = avma; GEN b, a; if (typ(x) != t_INTMOD) pari_err_TYPE("znorder [t_INTMOD expected]",x); b = gel(x,1); a = gel(x,2); if (!equali1(gcdii(a,b))) pari_err_COPRIME("znorder", a,b); if (!o) { GEN fa = Z_factor(b), P = gel(fa,1), E = gel(fa,2); long i, l = lg(P); o = gen_1; for (i = 1; i < l; i++) { GEN p = gel(P,i); long e = itos(gel(E,i)); if (l == 2) o = Zp_order(a, p, e, b); else { GEN pe = powiu(p,e); o = lcmii(o, Zp_order(remii(a,pe), p, e, pe)); } } return gerepileuptoint(av, o); } return Fp_order(a, o, b); } GEN order(GEN x) { return znorder(x, NULL); } /*********************************************************************/ /** **/ /** DISCRETE LOGARITHM in (Z/nZ)* **/ /** **/ /*********************************************************************/ static GEN Fp_log_halfgcd(ulong bnd, GEN C, GEN g, GEN p) { pari_sp av = avma; GEN h1, h2, F, G; if (!Fp_ratlift(g,p,C,shifti(C,-1),&h1,&h2)) return NULL; if ((F = Z_issmooth_fact(h1, bnd)) && (G = Z_issmooth_fact(h2, bnd))) { GEN M = cgetg(3, t_MAT); gel(M,1) = vecsmall_concat(gel(F, 1),gel(G, 1)); gel(M,2) = vecsmall_concat(gel(F, 2),zv_neg_inplace(gel(G, 2))); return gerepileupto(av, M); } avma = av; return NULL; } static GEN Fp_log_find_rel(GEN b, ulong bnd, GEN C, GEN p, GEN *g, long *e) { GEN rel; do { (*e)++; *g = Fp_mul(*g, b, p); rel = Fp_log_halfgcd(bnd, C, *g, p); } while (!rel); return rel; } struct Fp_log_rel { GEN rel; ulong prmax; long nbrel, nbmax, nbgen; }; /* add u^e */ static void addifsmooth1(struct Fp_log_rel *r, GEN z, long u, long e) { pari_sp av = avma; long off = r->prmax+1; GEN F = cgetg(3, t_MAT); gel(F,1) = vecsmall_append(gel(z,1), off+u); gel(F,2) = vecsmall_append(gel(z,2), e); gel(r->rel,++r->nbrel) = gerepileupto(av, F); } /* add u^-1 v^-1 */ static void addifsmooth2(struct Fp_log_rel *r, GEN z, long u, long v) { pari_sp av = avma; long off = r->prmax+1; GEN P = mkvecsmall2(off+u,off+v), E = mkvecsmall2(-1,-1); GEN F = cgetg(3, t_MAT); gel(F,1) = vecsmall_concat(gel(z,1), P); gel(F,2) = vecsmall_concat(gel(z,2), E); gel(r->rel,++r->nbrel) = gerepileupto(av, F); } /* Let p=C^2+c Solve h = (C+x)*(C+a)-p = 0 [mod l] h= -c+x*(C+a)+C*a = 0 [mod l] x = (c-C*a)/(C+a) [mod l] h = -c+C*(x+a)+a*x */ GEN Fp_log_sieve_worker(long a, long prmax, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz) { pari_sp ltop = avma; long th = expi(mulis(C,a)), n = lg(pi)-1; long i, j; GEN sieve = zero_zv(a+2)+1; GEN L = cgetg(1+a+2, t_VEC); pari_sp av = avma; long rel = 1; GEN z, h; h = addis(C,a); if ((z = Z_issmooth_fact(h, prmax))) { gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -1)); av = avma; } for(i=1; i<=n; i++) { ulong li = pi[i], s = sz[i], al = a % li; ulong u, iv = Fl_invsafe(Fl_add(Ci[i],al,li),li); if (!iv) continue; u = Fl_mul(Fl_sub(ci[i],Fl_mul(Ci[i],al,li),li), iv ,li); for(j = u; j<=a; j+=li) sieve[j] += s; } th = th - expu(th)-1; for(j=0; j=th) { GEN h = addiu(subii(muliu(C,a+j),c), a*j); if ((z = Z_issmooth_fact(h, prmax))) { gel(L, rel++) = mkvec2(z, mkvecsmall3(2, a, j)); av = avma; } else avma = av; } /* j = a */ if (sieve[a]>=th) { GEN h = addiu(subii(muliu(C,2*a),c), a*a); if ((z = Z_issmooth_fact(h, prmax))) { gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -2)); av = avma; } } setlg(L, rel); return gerepilecopy(ltop, L); } static long Fp_log_sieve(struct Fp_log_rel *r, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz) { struct pari_mt pt; long i, j, nb = 0; GEN worker = snm_closure(is_entry("_Fp_log_sieve_worker"), mkvecn(7, utoi(r->prmax), C, c, Ci, ci, pi, sz)); long running, pending = 0; GEN W = zerovec(r->nbgen); mt_queue_start_lim(&pt, worker, r->nbgen); for (i = 0; (running = (i < r->nbgen)) || pending; i++) { GEN done; long idx; mt_queue_submit(&pt, i, running ? mkvec(stoi(i)): NULL); done = mt_queue_get(&pt, &idx, &pending); if (!done || lg(done)==1) continue; gel(W, idx+1) = done; nb += lg(done)-1; if (DEBUGLEVEL && (i&127)==0) err_printf("%ld%% ",100*nb/r->nbmax); } mt_queue_end(&pt); for(j = 1; j <= r->nbgen && r->nbrel < r->nbmax; j++) { long ll, m; GEN L = gel(W,j); if (isintzero(L)) continue; ll = lg(L); for (m=1; mnbrel < r->nbmax ; m++) { GEN Lm = gel(L,m), h = gel(Lm, 1), v = gel(Lm, 2); if (v[1] == 1) addifsmooth1(r, h, v[2], v[3]); else addifsmooth2(r, h, v[2], v[3]); } } return j; } static GEN ECP_psi(GEN x, GEN y) { long prec = realprec(x); GEN lx = glog(x, prec), ly = glog(y, prec); GEN u = gdiv(lx, ly); return gpow(u, gneg(u),prec); } struct computeG { GEN C; long bnd, nbi; }; static GEN _computeG(void *E, GEN gen) { struct computeG * d = (struct computeG *) E; GEN ps = ECP_psi(gmul(gen,d->C), stoi(d->bnd)); return gsub(gmul(gsqr(gen),ps),gmul2n(gaddgs(gen,d->nbi),2)); } static long compute_nbgen(GEN C, long bnd, long nbi) { struct computeG d; d.C = shifti(C, 1); d.bnd = bnd; d.nbi = nbi; return itos(ground(zbrent((void*)&d, _computeG, gen_2, stoi(bnd), DEFAULTPREC))); } static GEN _psi(void*E, GEN y) { GEN lx = (GEN) E; long prec = realprec(lx); GEN ly = glog(y, prec); GEN u = gdiv(lx, ly); return gsub(gdiv(y ,ly), gpow(u, u, prec)); } static GEN opt_param(GEN x, long prec) { return zbrent((void*)glog(x,prec), _psi, gen_2, x, prec); } static GEN check_kernel(long nbg, long N, long prmax, GEN C, GEN M, GEN p, GEN m) { pari_sp av = avma; long lM = lg(M)-1, nbcol = lM; long tbs = maxss(1, expu(nbg/expi(m))); for (;;) { GEN K = FpMs_leftkernel_elt_col(M, nbcol, N, m); GEN tab; long i, f=0; long l = lg(K), lm = lgefint(m); GEN idx = diviiexact(subiu(p,1),m), g; pari_timer ti; if (DEBUGLEVEL) timer_start(&ti); for(i=1; i (nbg>>1)) return gerepileupto(av, K); for(i=1; i<=nbcol; i++) { long a = 1+random_Fl(lM); swap(gel(M,a),gel(M,i)); } if (4*nbcol>5*nbg) nbcol = nbcol*9/10; } } static GEN Fp_log_find_ind(GEN a, GEN K, long prmax, GEN C, GEN p, GEN m) { pari_sp av=avma; GEN aa = gen_1; long AV = 0; for(;;) { GEN A = Fp_log_find_rel(a, prmax, C, p, &aa, &AV); GEN F = gel(A,1), E = gel(A,2); GEN Ao = gen_0; long i, l = lg(F); for(i=1; i=0) return NULL; p_1 = subiu(p,1); if (!is_pm1(gcdii(m,diviiexact(p_1,m)))) m = diviiexact(p_1, Z_ppo(p_1, m)); pr = primes_upto_zv(bnd); nbi = lg(pr)-1; C = sqrtremi(p, &c); av2 = avma; for (i = 1; i <= nbi; ++i) { ulong lp = pr[i]; while (lp <= bnd) { nbr++; lp *= pr[i]; } } pi = cgetg(nbr+1,t_VECSMALL); Ci = cgetg(nbr+1,t_VECSMALL); ci = cgetg(nbr+1,t_VECSMALL); sz = cgetg(nbr+1,t_VECSMALL); for (i = 1, j = 1; i <= nbi; ++i) { ulong lp = pr[i], sp = expu(2*lp-1); while (lp <= bnd) { pi[j] = lp; Ci[j] = umodiu(C, lp); ci[j] = umodiu(c, lp); sz[j] = sp; lp *= pr[i]; j++; } } r.nbrel = 0; r.nbgen = compute_nbgen(C, bnd, nbi); r.nbmax = 2*(nbi+r.nbgen); r.rel = cgetg(r.nbmax+1,t_VEC); r.prmax = pr[nbi]; if (DEBUGLEVEL) { err_printf("bnd=%lu Size FB=%ld extra gen=%ld \n", bnd, nbi, r.nbgen); timer_start(&ti); } nbg = Fp_log_sieve(&r, C, c, Ci, ci, pi, sz); nbrow = r.prmax + nbg; if (DEBUGLEVEL) { err_printf("\n"); timer_printf(&ti," %ld relations, %ld generators", r.nbrel, nbi+nbg); } setlg(r.rel,r.nbrel+1); r.rel = gerepilecopy(av2, r.rel); K = check_kernel(nbi+nbrow-r.prmax, nbrow, r.prmax, C, r.rel, p, m); if (DEBUGLEVEL) timer_start(&ti); Ao = Fp_log_find_ind(a, K, r.prmax, C, p, m); if (DEBUGLEVEL) timer_printf(&ti," log element"); Bo = Fp_log_find_ind(b, K, r.prmax, C, p, m); if (DEBUGLEVEL) timer_printf(&ti," log generator"); d = gcdii(Ao,Bo); l = Fp_div(diviiexact(Ao, d) ,diviiexact(Bo, d), m); if (!equalii(a,Fp_pow(b,l,p))) pari_err_BUG("Fp_log_index"); return gerepileuptoint(av, l); } static int Fp_log_use_index(long e, long p) { return (e >= 27 && 20*(p+6)<=e*e); } /* Trivial cases a = 1, -1. Return x s.t. g^x = a or [] if no such x exist */ static GEN Fp_easylog(void *E, GEN a, GEN g, GEN ord) { pari_sp av = avma; GEN p = (GEN)E; /* assume a reduced mod p, p not necessarily prime */ if (equali1(a)) return gen_0; /* p > 2 */ if (equalii(subiu(p,1), a)) /* -1 */ { pari_sp av2; GEN t; ord = get_arith_Z(ord); if (mpodd(ord)) { avma = av; return cgetg(1, t_VEC); } /* no solution */ t = shifti(ord,-1); /* only possible solution */ av2 = avma; if (!equalii(Fp_pow(g, t, p), a)) { avma = av; return cgetg(1, t_VEC); } avma = av2; return gerepileuptoint(av, t); } if (typ(ord)==t_INT && BPSW_psp(p) && Fp_log_use_index(expi(ord),expi(p))) return Fp_log_index(a, g, ord, p); avma = av; return NULL; /* not easy */ } GEN Fp_log(GEN a, GEN g, GEN ord, GEN p) { GEN v = get_arith_ZZM(ord); GEN F = gmael(v,2,1); long lF = lg(F)-1, lmax; if (lF == 0) return equali1(a)? gen_0: cgetg(1, t_VEC); lmax = expi(gel(F,lF)); if (BPSW_psp(p) && Fp_log_use_index(lmax,expi(p))) v = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(27))); return gen_PH_log(a,g,v,(void*)p,&Fp_star); } static ulong Fl_log_naive(ulong a, ulong g, ulong ord, ulong p) { ulong i, h=1; for(i=0; i 1, N = prod_{i <= l} P[i]^E[i], P[i] prime. * PHI[l] = eulerphi(N / P[l]^E[l]). Destroys P/E */ static GEN znlog_rec(GEN h, GEN g, GEN N, GEN P, GEN E, GEN PHI) { long l = lg(P) - 1, e = E[l]; GEN p = gel(P, l), phi = gel(PHI,l), pe = e == 1? p: powiu(p, e); GEN a,b, hp,gp, hpe,gpe, ogpe; /* = order(g mod p^e) | p^(e-1)(p-1) */ if (l == 1) { hpe = h; gpe = g; } else { hpe = modii(h, pe); gpe = modii(g, pe); } if (e == 1) { hp = hpe; gp = gpe; } else { hp = remii(hpe, p); gp = remii(gpe, p); } if (hp == gen_0 || gp == gen_0) return NULL; if (absequaliu(p, 2)) { GEN n = int2n(e); ogpe = Zp_order(gpe, gen_2, e, n); a = Fp_log(hpe, gpe, ogpe, n); if (typ(a) != t_INT) return NULL; } else { /* Avoid black box groups: (Z/p^2)^* / (Z/p)^* ~ (Z/pZ, +), where DL is trivial */ /* [order(gp), factor(order(gp))] */ GEN v = Fp_factored_order(gp, subiu(p,1), p); GEN ogp = gel(v,1); if (!equali1(Fp_pow(hp, ogp, p))) return NULL; a = Fp_log(hp, gp, v, p); if (typ(a) != t_INT) return NULL; if (e == 1) ogpe = ogp; else { /* find a s.t. g^a = h (mod p^e), p odd prime, e > 0, (h,p) = 1 */ /* use p-adic log: O(log p + e) mul*/ long vpogpe, vpohpe; hpe = Fp_mul(hpe, Fp_pow(gpe, negi(a), pe), pe); gpe = Fp_pow(gpe, ogp, pe); /* g,h = 1 mod p; compute b s.t. h = g^b */ /* v_p(order g mod pe) */ vpogpe = equali1(gpe)? 0: e - Z_pval(subiu(gpe,1), p); /* v_p(order h mod pe) */ vpohpe = equali1(hpe)? 0: e - Z_pval(subiu(hpe,1), p); if (vpohpe > vpogpe) return NULL; ogpe = mulii(ogp, powiu(p, vpogpe)); /* order g mod p^e */ if (is_pm1(gpe)) return is_pm1(hpe)? a: NULL; b = gdiv(Qp_log(cvtop(hpe, p, e)), Qp_log(cvtop(gpe, p, e))); a = addii(a, mulii(ogp, padic_to_Q(b))); } } /* gp^a = hp => x = a mod ogpe => generalized Pohlig-Hellman strategy */ if (l == 1) return a; N = diviiexact(N, pe); /* make N coprime to p */ h = Fp_mul(h, Fp_pow(g, modii(negi(a), phi), N), N); g = Fp_pow(g, modii(ogpe, phi), N); setlg(P, l); /* remove last element */ setlg(E, l); b = znlog_rec(h, g, N, P, E, PHI); if (!b) return NULL; return addmulii(a, b, ogpe); } static GEN get_PHI(GEN P, GEN E) { long i, l = lg(P); GEN PHI = cgetg(l, t_VEC); gel(PHI,1) = gen_1; for (i=1; i 1) t = mulii(t, gel(PHI,i)); gel(PHI,i+1) = t; } return PHI; } GEN znlog(GEN h, GEN g, GEN o) { pari_sp av = avma; GEN N, fa, P, E, x; switch (typ(g)) { case t_PADIC: { GEN p = gel(g,2); long v = valp(g); if (v < 0) pari_err_DIM("znlog"); if (v > 0) { long k = gvaluation(h, p); if (k % v) return cgetg(1,t_VEC); k /= v; if (!gequal(h, gpowgs(g,k))) { avma = av; return cgetg(1,t_VEC); } avma = av; return stoi(k); } N = gel(g,3); g = Rg_to_Fp(g, N); break; } case t_INTMOD: N = gel(g,1); g = gel(g,2); break; default: pari_err_TYPE("znlog", g); return NULL; /* LCOV_EXCL_LINE */ } if (equali1(N)) { avma = av; return gen_0; } h = Rg_to_Fp(h, N); if (o) return gerepileupto(av, Fp_log(h, g, o, N)); fa = Z_factor(N); P = gel(fa,1); E = vec_to_vecsmall(gel(fa,2)); x = znlog_rec(h, g, N, P, E, get_PHI(P,E)); if (!x) { avma = av; return cgetg(1,t_VEC); } return gerepileuptoint(av, x); } GEN Fp_sqrtn(GEN a, GEN n, GEN p, GEN *zeta) { if (lgefint(p)==3) { long nn = itos_or_0(n); if (nn) { ulong pp = p[2]; ulong uz; ulong r = Fl_sqrtn(umodiu(a,pp),nn,pp, zeta ? &uz:NULL); if (r==ULONG_MAX) return NULL; if (zeta) *zeta = utoi(uz); return utoi(r); } } a = modii(a,p); if (!signe(a)) { if (zeta) *zeta = gen_1; if (signe(n) < 0) pari_err_INV("Fp_sqrtn", mkintmod(gen_0,p)); return gen_0; } if (absequaliu(n,2)) { if (zeta) *zeta = subiu(p,1); return signe(n) > 0 ? Fp_sqrt(a,p): Fp_sqrt(Fp_inv(a, p),p); } return gen_Shanks_sqrtn(a,n,subiu(p,1),zeta,(void*)p,&Fp_star); } /*********************************************************************/ /** **/ /** FUNDAMENTAL DISCRIMINANTS **/ /** **/ /*********************************************************************/ static int fa_isfundamental(GEN F) { GEN P = gel(F,1), E = gel(F,2); long i, s, l = lg(P); if (l == 1) return 1; s = signe(gel(P,1)); /* = signe(x) */ if (!s) return 0; if (s < 0) { l--; P = vecslice(P,2,l); E = vecslice(E,2,l); } if (l == 1) return 0; if (!absequaliu(gel(P,1), 2)) i = 1; /* need x = 1 mod 4 */ else { i = 2; switch(itou(gel(E,1))) { case 2: s = -s; break; /* need x/4 = 3 mod 4 */ case 3: s = 0; break; /* no condition mod 4 */ default: return 0; } } for(; i < l; i++) { if (!equali1(gel(E,i))) return 0; if (s && Mod4(gel(P,i)) == 3) s = -s; } return s >= 0; } long isfundamental(GEN x) { if (typ(x) != t_INT) { pari_sp av = avma; int v = fa_isfundamental(check_arith_all(x,"isfundamental")); avma = av; return v; } return Z_isfundamental(x); } /* x fundamental ? */ long uposisfundamental(ulong x) { ulong r = x & 15; /* x mod 16 */ if (!r) return 0; switch(r & 3) { /* x mod 4 */ case 0: return (r == 4)? 0: uissquarefree(x >> 2); case 1: return uissquarefree(x); default: return 0; } } /* -x fundamental ? */ long unegisfundamental(ulong x) { ulong r = x & 15; /* x mod 16 */ if (!r) return 0; switch(r & 3) { /* x mod 4 */ case 0: return (r == 12)? 0: uissquarefree(x >> 2); case 3: return uissquarefree(x); default: return 0; } } long sisfundamental(long x) { return x < 0? unegisfundamental((ulong)(-x)): uposisfundamental(x); } long Z_isfundamental(GEN x) { long r; switch(lgefint(x)) { case 2: return 0; case 3: return signe(x) < 0? unegisfundamental(x[2]) : uposisfundamental(x[2]); } r = mod16(x); if (!r) return 0; if ((r & 3) == 0) { pari_sp av; r >>= 2; /* |x|/4 mod 4 */ if (signe(x) < 0) r = 4-r; if (r == 1) return 0; av = avma; r = Z_issquarefree( shifti(x,-2) ); avma = av; return r; } r &= 3; /* |x| mod 4 */ if (signe(x) < 0) r = 4-r; return (r==1) ? Z_issquarefree(x) : 0; } static GEN fa_quaddisc(GEN f) { GEN P = gel(f,1), E = gel(f,2), s = gen_1; long i, l = lg(P); for (i = 1; i < l; i++) /* possibly including -1 */ if (mpodd(gel(E,i))) s = mulii(s, gel(P,i)); if (Mod4(s) > 1) s = shifti(s,2); return s; } GEN quaddisc(GEN x) { const pari_sp av = avma; if (is_rational_t(typ(x))) x = factor(x); else x = check_arith_all(x,"quaddisc"); return gerepileuptoint(av, fa_quaddisc(x)); } /*********************************************************************/ /** **/ /** FACTORIAL **/ /** **/ /*********************************************************************/ /* return a * (a+1) * ... * b. Assume a <= b [ note: factoring out powers of 2 * first is slower ... ] */ GEN mulu_interval(ulong a, ulong b) { pari_sp av = avma; ulong k, l, N, n; long lx; GEN x; if (!a) return gen_0; n = b - a + 1; if (n < 61) { if (n == 1) return utoi(a); x = muluu(a,a+1); if (n == 2) return x; for (k=a+2; k<=b; k++) x = mului(k,x); return gerepileuptoint(av, x); } lx = 1; x = cgetg(2 + n/2, t_VEC); N = b + a; for (k = a;; k++) { l = N - k; if (l <= k) break; gel(x,lx++) = muluu(k,l); } if (l == k) gel(x,lx++) = utoipos(k); setlg(x, lx); return gerepileuptoint(av, ZV_prod(x)); } GEN muls_interval(long a, long b) { pari_sp av = avma; long lx, k, l, N, n = b - a + 1; GEN x; if (a <= 0 && b >= 0) return gen_0; if (n < 61) { x = stoi(a); for (k=a+1; k<=b; k++) x = mulsi(k,x); return gerepileuptoint(av, x); } lx = 1; x = cgetg(2 + n/2, t_VEC); N = b + a; for (k = a;; k++) { l = N - k; if (l <= k) break; gel(x,lx++) = mulss(k,l); } if (l == k) gel(x,lx++) = stoi(k); setlg(x, lx); return gerepileuptoint(av, ZV_prod(x)); } GEN mpfact(long n) { if (n < 2) { if (n < 0) pari_err_DOMAIN("factorial", "argument","<",gen_0,stoi(n)); return gen_1; } return mulu_interval(2UL, (ulong)n); } /*******************************************************************/ /** **/ /** LUCAS & FIBONACCI **/ /** **/ /*******************************************************************/ static void lucas(ulong n, GEN *a, GEN *b) { GEN z, t, zt; if (!n) { *a = gen_2; *b = gen_1; return; } lucas(n >> 1, &z, &t); zt = mulii(z, t); switch(n & 3) { case 0: *a = subiu(sqri(z),2); *b = subiu(zt,1); break; case 1: *a = subiu(zt,1); *b = addiu(sqri(t),2); break; case 2: *a = addiu(sqri(z),2); *b = addiu(zt,1); break; case 3: *a = addiu(zt,1); *b = subiu(sqri(t),2); } } GEN fibo(long n) { pari_sp av = avma; GEN a, b; if (!n) return gen_0; lucas((ulong)(labs(n)-1), &a, &b); a = diviuexact(addii(shifti(a,1),b), 5); if (n < 0 && !odd(n)) setsigne(a, -1); return gerepileuptoint(av, a); } /*******************************************************************/ /* */ /* CONTINUED FRACTIONS */ /* */ /*******************************************************************/ static GEN icopy_lg(GEN x, long l) { long lx = lgefint(x); GEN y; if (lx >= l) return icopy(x); y = cgeti(l); affii(x, y); return y; } /* continued fraction of a/b. If y != NULL, stop when partial quotients * differ from y */ static GEN Qsfcont(GEN a, GEN b, GEN y, ulong k) { GEN z, c; ulong i, l, ly = lgefint(b); /* times 1 / log2( (1+sqrt(5)) / 2 ) */ l = (ulong)(3 + bit_accuracy_mul(ly, 1.44042009041256)); if (k > 0 && k+1 > 0 && l > k+1) l = k+1; /* beware overflow */ if (l > LGBITS) l = LGBITS; z = cgetg(l,t_VEC); l--; if (y) { pari_sp av = avma; if (l >= (ulong)lg(y)) l = lg(y)-1; for (i = 1; i <= l; i++) { GEN q = gel(y,i); gel(z,i) = q; c = b; if (!gequal1(q)) c = mulii(q, b); c = subii(a, c); if (signe(c) < 0) { /* partial quotient too large */ c = addii(c, b); if (signe(c) >= 0) i++; /* by 1 */ break; } if (cmpii(c, b) >= 0) { /* partial quotient too small */ c = subii(c, b); if (cmpii(c, b) < 0) { /* by 1. If next quotient is 1 in y, add 1 */ if (i < l && equali1(gel(y,i+1))) gel(z,i) = addiu(q,1); i++; } break; } if ((i & 0xff) == 0) gerepileall(av, 2, &b, &c); a = b; b = c; } } else { a = icopy_lg(a, ly); b = icopy(b); for (i = 1; i <= l; i++) { gel(z,i) = truedvmdii(a,b,&c); if (c == gen_0) { i++; break; } affii(c, a); cgiv(c); c = a; a = b; b = c; } } i--; if (i > 1 && gequal1(gel(z,i))) { cgiv(gel(z,i)); --i; gel(z,i) = addui(1, gel(z,i)); /* unclean: leave old z[i] on stack */ } setlg(z,i+1); return z; } static GEN sersfcont(GEN a, GEN b, long k) { long i, l = typ(a) == t_POL? lg(a): 3; GEN y, c; if (lg(b) > l) l = lg(b); if (k > 0 && l > k+1) l = k+1; y = cgetg(l,t_VEC); for (i=1; i= lb) pari_err_DIM("contfrac [too few denominators]"); lb = k+1; } y = cgetg(lb,t_VEC); if (lb==1) return y; if (is_scalar_t(tx)) { if (!is_intreal_t(tx) && tx != t_FRAC) pari_err_TYPE("sfcont2",x); } else if (tx == t_SER) x = ser2rfrac_i(x); if (!gequal1(gel(b,1))) x = gmul(gel(b,1),x); for (i = 1;;) { if (tx == t_REAL) { long e = expo(x); if (e > 0 && nbits2prec(e+1) > realprec(x)) break; gel(y,i) = floorr(x); p1 = subri(x, gel(y,i)); } else { gel(y,i) = gfloor(x); p1 = gsub(x, gel(y,i)); } if (++i >= lb) break; if (gequal0(p1)) break; x = gdiv(gel(b,i),p1); } setlg(y,i); return gerepilecopy(av,y); } GEN gcf(GEN x) { return gboundcf(x,0); } GEN gcf2(GEN b, GEN x) { return contfrac0(x,b,0); } GEN contfrac0(GEN x, GEN b, long nmax) { long tb; if (!b) return gboundcf(x,nmax); tb = typ(b); if (tb == t_INT) return gboundcf(x,itos(b)); if (! is_vec_t(tb)) pari_err_TYPE("contfrac0",b); if (nmax < 0) pari_err_DOMAIN("contfrac","nmax","<",gen_0,stoi(nmax)); return sfcont2(b,x,nmax); } GEN contfracpnqn(GEN x, long n) { pari_sp av = avma; long i, lx = lg(x); GEN M,A,B, p0,p1, q0,q1; if (lx == 1) { if (! is_matvec_t(typ(x))) pari_err_TYPE("pnqn",x); if (n >= 0) return cgetg(1,t_MAT); return matid(2); } switch(typ(x)) { case t_VEC: case t_COL: A = x; B = NULL; break; case t_MAT: switch(lgcols(x)) { case 2: A = row(x,1); B = NULL; break; case 3: A = row(x,2); B = row(x,1); break; default: pari_err_DIM("pnqn [ nbrows != 1,2 ]"); return NULL; /*LCOV_EXCL_LINE*/ } break; default: pari_err_TYPE("pnqn",x); return NULL; /*LCOV_EXCL_LINE*/ } p1 = gel(A,1); q1 = B? gel(B,1): gen_1; /* p[0], q[0] */ if (n >= 0) { lx = minss(lx, n+2); if (lx == 2) return gerepilecopy(av, mkmat(mkcol2(p1,q1))); } else if (lx == 2) return gerepilecopy(av, mkmat2(mkcol2(p1,q1), mkcol2(gen_1,gen_0))); /* lx >= 3 */ p0 = gen_1; q0 = gen_0; /* p[-1], q[-1] */ M = cgetg(lx, t_MAT); gel(M,1) = mkcol2(p1,q1); for (i=2; i= 0; * return [[p0, ..., pn], [q0,...,qn]] */ GEN ZV_allpnqn(GEN x) { long i, lx = lg(x); GEN p0, p1, q0, q1, p2, q2, P,Q, v = cgetg(3,t_VEC); gel(v,1) = P = cgetg(lx, t_VEC); gel(v,2) = Q = cgetg(lx, t_VEC); p0 = gen_1; q0 = gen_0; gel(P, 1) = p1 = gel(x,1); gel(Q, 1) = q1 = gen_1; for (i=2; i= 0) A = d-1 - B; else { B = d >> 1; A = odd(d)? B : B-1; } if (varn(N) != varn(x)) x = scalarpol(x, varn(N)); if (!RgXQ_ratlift(x, N, A, B, &a,&b) || degpol(RgX_gcd(a,b)) > 0) return NULL; return gdiv(a,b); } /* k > 0 t_INT, x a t_FRAC, returns the convergent a/b * of the continued fraction of x with b <= k maximal */ static GEN bestappr_frac(GEN x, GEN k) { pari_sp av; GEN p0, p1, p, q0, q1, q, a, y; if (cmpii(gel(x,2),k) <= 0) return gcopy(x); av = avma; y = x; p1 = gen_1; p0 = truedvmdii(gel(x,1), gel(x,2), &a); /* = floor(x) */ q1 = gen_0; q0 = gen_1; x = mkfrac(a, gel(x,2)); /* = frac(x); now 0<= x < 1 */ for(;;) { x = ginv(x); /* > 1 */ a = typ(x)==t_INT? x: divii(gel(x,1), gel(x,2)); if (cmpii(a,k) > 0) { /* next partial quotient will overflow limits */ GEN n, d; a = divii(subii(k, q1), q0); p = addii(mulii(a,p0), p1); p1=p0; p0=p; q = addii(mulii(a,q0), q1); q1=q0; q0=q; /* compare |y-p0/q0|, |y-p1/q1| */ n = gel(y,1); d = gel(y,2); if (abscmpii(mulii(q1, subii(mulii(q0,n), mulii(d,p0))), mulii(q0, subii(mulii(q1,n), mulii(d,p1)))) < 0) { p1 = p0; q1 = q0; } break; } p = addii(mulii(a,p0), p1); p1=p0; p0=p; q = addii(mulii(a,q0), q1); q1=q0; q0=q; if (cmpii(q0,k) > 0) break; x = gsub(x,a); /* 0 <= x < 1 */ if (typ(x) == t_INT) { p1 = p0; q1 = q0; break; } /* x = 0 */ } return gerepileupto(av, gdiv(p1,q1)); } /* k > 0 t_INT, x != 0 a t_REAL, returns the convergent a/b * of the continued fraction of x with b <= k maximal */ static GEN bestappr_real(GEN x, GEN k) { pari_sp av = avma; GEN kr, p0, p1, p, q0, q1, q, a, y = x; p1 = gen_1; a = p0 = floorr(x); q1 = gen_0; q0 = gen_1; x = subri(x,a); /* 0 <= x < 1 */ if (!signe(x)) { cgiv(x); return a; } kr = itor(k, realprec(x)); for(;;) { long d; x = invr(x); /* > 1 */ if (cmprr(x,kr) > 0) { /* next partial quotient will overflow limits */ a = divii(subii(k, q1), q0); p = addii(mulii(a,p0), p1); p1=p0; p0=p; q = addii(mulii(a,q0), q1); q1=q0; q0=q; /* compare |y-p0/q0|, |y-p1/q1| */ if (abscmprr(mulir(q1, subri(mulir(q0,y), p0)), mulir(q0, subri(mulir(q1,y), p1))) < 0) { p1 = p0; q1 = q0; } break; } d = nbits2prec(expo(x) + 1); if (d > lg(x)) { p1 = p0; q1 = q0; break; } /* original x was ~ 0 */ a = truncr(x); /* truncr(x) will NOT raise e_PREC */ p = addii(mulii(a,p0), p1); p1=p0; p0=p; q = addii(mulii(a,q0), q1); q1=q0; q0=q; if (cmpii(q0,k) > 0) break; x = subri(x,a); /* 0 <= x < 1 */ if (!signe(x)) { p1 = p0; q1 = q0; break; } } if (signe(q1) < 0) { togglesign_safe(&p1); togglesign_safe(&q1); } return gerepilecopy(av, equali1(q1)? p1: mkfrac(p1,q1)); } /* k t_INT or NULL */ static GEN bestappr_Q(GEN x, GEN k) { long lx, tx = typ(x), i; GEN a, y; switch(tx) { case t_INT: return icopy(x); case t_FRAC: return k? bestappr_frac(x, k): gcopy(x); case t_REAL: if (!signe(x)) return gen_0; /* i <= e iff nbits2lg(e+1) > lg(x) iff floorr(x) fails */ i = bit_prec(x); if (i <= expo(x)) return NULL; return bestappr_real(x, k? k: int2n(i)); case t_INTMOD: { pari_sp av = avma; a = mod_to_frac(gel(x,2), gel(x,1), k); if (!a) return NULL; return gerepilecopy(av, a); } case t_PADIC: { pari_sp av = avma; long v = valp(x); a = mod_to_frac(gel(x,4), gel(x,3), k); if (!a) return NULL; if (v) a = gmul(a, powis(gel(x,2), v)); return gerepilecopy(av, a); } case t_COMPLEX: { pari_sp av = avma; y = cgetg(3, t_COMPLEX); gel(y,2) = bestappr(gel(x,2), k); gel(y,1) = bestappr(gel(x,1), k); if (gequal0(gel(y,2))) return gerepileupto(av, gel(y,1)); return y; } case t_SER: if (ser_isexactzero(x)) return gcopy(x); /* fall through */ case t_POLMOD: case t_POL: case t_RFRAC: case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; } for (; i 0) { x = RgX_shift_shallow(x, v); dN += v; } else if (v < 0) { if (B >= 0) B = maxss(B+v, 0); } t = mod_to_rfrac(x, pol_xn(dN, varn(x)), B); if (!t) return NULL; if (v < 0) { GEN a, b; long vx; if (typ(t) == t_POL) return RgX_mulXn(t, v); /* t_RFRAC */ vx = varn(x); a = gel(t,1); b = gel(t,2); v -= RgX_valrem(b, &b); if (typ(a) == t_POL && varn(a) == vx) v += RgX_valrem(a, &a); if (v < 0) b = RgX_shift(b, -v); else if (v > 0) { if (typ(a) != t_POL || varn(a) != vx) a = scalarpol_shallow(a, vx); a = RgX_shift(a, v); } t = mkrfraccopy(a, b); } return t; } static GEN bestappr_RgX(GEN x, long B); /* x t_POLMOD, B >= 0 or < 0 [omit condition on B]. * Look for coprime t_POL a,b, deg(b)<=B, such that a/b = x */ static GEN bestappr_RgX(GEN x, long B) { long i, lx, tx = typ(x); GEN y, t; switch(tx) { case t_INT: case t_REAL: case t_INTMOD: case t_FRAC: case t_COMPLEX: case t_PADIC: case t_QUAD: case t_POL: return gcopy(x); case t_RFRAC: { pari_sp av = avma; if (B < 0 || degpol(gel(x,2)) <= B) return gcopy(x); x = rfrac_to_ser(x, 2*B+1); t = bestappr_ser(x, B); if (!t) return NULL; return gerepileupto(av, t); } case t_POLMOD: { pari_sp av = avma; t = mod_to_rfrac(gel(x,2), gel(x,1), B); if (!t) return NULL; return gerepileupto(av, t); } case t_SER: { pari_sp av = avma; t = bestappr_ser(x, B); if (!t) return NULL; return gerepileupto(av, t); } case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; } for (; i1) pari_warn(warnmem,"quadunit"); gerepileall(av2,4, &a,&f,&u,&v); } } if (signe(gel(y,3)) < 0) y = gneg(y); return gerepileupto(av, y); } GEN quadunit0(GEN x, long v) { GEN y = quadunit(x); if (v==-1) v = fetch_user_var("w"); setvarn(gel(y,1), v); return y; } GEN quadregulator(GEN x, long prec) { pari_sp av = avma, av2; GEN R, rsqd, u, v, sqd; long r, Rexpo; check_quaddisc_real(x, &r, "quadregulator"); sqd = sqrti(x); rsqd = gsqrt(x,prec); Rexpo = 0; R = real2n(1, prec); /* = 2 */ av2 = avma; u = stoi(r); v = gen_2; for(;;) { GEN u1 = subii(mulii(divii(addii(u,sqd),v), v), u); GEN v1 = divii(subii(x,sqri(u1)),v); if (equalii(v,v1)) { R = sqrr(R); shiftr_inplace(R, -1); R = mulrr(R, divri(addir(u1,rsqd),v)); break; } if (equalii(u,u1)) { R = sqrr(R); shiftr_inplace(R, -1); break; } R = mulrr(R, divri(addir(u1,rsqd),v)); Rexpo += expo(R); setexpo(R,0); u = u1; v = v1; if (Rexpo & ~EXPOBITS) pari_err_OVERFLOW("quadregulator [exponent]"); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"quadregulator"); gerepileall(av2,3, &R,&u,&v); } } R = logr_abs(divri(R,v)); if (Rexpo) { GEN t = mulsr(Rexpo, mplog2(prec)); shiftr_inplace(t, 1); R = addrr(R,t); } return gerepileuptoleaf(av, R); } /*************************************************************************/ /** **/ /** CLASS NUMBER **/ /** **/ /*************************************************************************/ int qfb_equal1(GEN f) { return equali1(gel(f,1)); } static GEN qfi_pow(void *E, GEN f, GEN n) { return E? nupow(f,n,(GEN)E): powgi(f,n); } static GEN qfi_comp(void *E, GEN f, GEN g) { return E? nucomp(f,g,(GEN)E): qficomp(f,g); } static const struct bb_group qfi_group={ qfi_comp,qfi_pow,NULL,hash_GEN, gidentical,qfb_equal1,NULL}; GEN qfi_order(GEN q, GEN o) { return gen_order(q, o, NULL, &qfi_group); } GEN qfi_log(GEN a, GEN g, GEN o) { return gen_PH_log(a, g, o, NULL, &qfi_group); } GEN qfi_Shanks(GEN a, GEN g, long n) { pari_sp av = avma; GEN T, X; long rt_n, c; a = redimag(a); g = redimag(g); rt_n = sqrt((double)n); c = n / rt_n; c = (c * rt_n < n + 1) ? c + 1 : c; T = gen_Shanks_init(g, rt_n, NULL, &qfi_group); X = gen_Shanks(T, a, c, NULL, &qfi_group); if (!X) { avma = av; return X; } return gerepileuptoint(av, X); } GEN qfbclassno0(GEN x,long flag) { switch(flag) { case 0: return map_proto_G(classno,x); case 1: return map_proto_G(classno2,x); default: pari_err_FLAG("qfbclassno"); } return NULL; /* LCOV_EXCL_LINE */ } /* f^h = 1, return order(f). Set *pfao to its factorization */ static GEN find_order(void *E, GEN f, GEN h, GEN *pfao) { GEN v = gen_factored_order(f, h, E, &qfi_group); *pfao = gel(v,2); return gel(v,1); } static int ok_q(GEN q, GEN h, GEN d2, long r2) { if (d2) { if (r2 <= 2 && !mpodd(q)) return 0; return is_pm1(Z_ppo(q,d2)); } else { if (r2 <= 1 && !mpodd(q)) return 0; return is_pm1(Z_ppo(q,h)); } } /* a,b given by their factorizations. Return factorization of lcm(a,b). * Set A,B such that A*B = lcm(a, b), (A,B)=1, A|a, B|b */ static GEN split_lcm(GEN a, GEN Fa, GEN b, GEN Fb, GEN *pA, GEN *pB) { GEN P = ZC_union_shallow(gel(Fa,1), gel(Fb,1)); GEN A = gen_1, B = gen_1; long i, l = lg(P); GEN E = cgetg(l, t_COL); for (i=1; i= 0 */ static void corediscfact(GEN x, long xmod4, GEN *ptD, GEN *ptP, GEN *ptE) { long s = signe(x), l, i; GEN fa = absZ_factor(x); GEN d, P = gel(fa,1), E = gtovecsmall(gel(fa,2)); l = lg(P); d = gen_1; for (i=1; i>= 1; } if (!xmod4 && mod4(d) != ((s < 0)? 3: 1)) { d = shifti(d,2); E[1]--; } *ptD = (s < 0)? negi(d): d; *ptP = P; *ptE = E; } static GEN conductor_part(GEN x, long xmod4, GEN *ptD, GEN *ptreg) { long l, i, s = signe(x); GEN E, H, D, P, reg; corediscfact(x, xmod4, &D, &P, &E); H = gen_1; l = lg(P); /* f \prod_{p|f} [ 1 - (D/p) p^-1 ] = \prod_{p^e||f} p^(e-1) [ p - (D/p) ] */ for (i=1; i= 2) H = mulii(H, powiu(p,e-1)); } } /* divide by [ O_K^* : O^* ] */ if (s < 0) { reg = NULL; switch(itou_or_0(D)) { case 4: H = shifti(H,-1); break; case 3: H = divis(H,3); break; } } else { reg = quadregulator(D,DEFAULTPREC); if (!equalii(x,D)) H = divii(H, roundr(divrr(quadregulator(x,DEFAULTPREC), reg))); } if (ptreg) *ptreg = reg; *ptD = D; return H; } static long two_rank(GEN x) { GEN p = gel(absZ_factor(x),1); long l = lg(p)-1; #if 0 /* positive disc not needed */ if (signe(x) > 0) { long i; for (i=1; i<=l; i++) if (mod4(gel(p,i)) == 3) { l--; break; } } #endif return l-1; } static GEN sqr_primeform(GEN x, ulong p) { return redimag(qfisqr(primeform_u(x, p))); } /* return a set of forms hopefully generating Cl(K)^2; set L ~ L(chi_D,1) */ static GEN get_forms(GEN D, GEN *pL) { const long MAXFORM = 20; GEN L, sqrtD = gsqrt(absi_shallow(D),DEFAULTPREC); GEN forms = vectrunc_init(MAXFORM+1); long s, nforms = 0; ulong p; forprime_t S; L = mulrr(divrr(sqrtD,mppi(DEFAULTPREC)), dbltor(1.005));/*overshoot by 0.5%*/ s = itos_or_0( truncr(shiftr(sqrtr(sqrtD), 1)) ); if (!s) pari_err_OVERFLOW("classno [discriminant too large]"); if (s < 10) s = 200; else if (s < 20) s = 1000; else if (s < 5000) s = 5000; u_forprime_init(&S, 2, s); while ( (p = u_forprime_next(&S)) ) { long d, k = kroiu(D,p); pari_sp av2; if (!k) continue; if (k > 0) { if (++nforms < MAXFORM) vectrunc_append(forms, sqr_primeform(D,p)); d = p-1; } else d = p+1; av2 = avma; affrr(divru(mulur(p,L),d), L); avma = av2; } *pL = L; return forms; } /* h ~ #G, return o = order of f, set fao = its factorization */ static GEN Shanks_order(void *E, GEN f, GEN h, GEN *pfao) { long s = minss(itos(sqrti(h)), 10000); GEN T = gen_Shanks_init(f, s, E, &qfi_group); GEN v = gen_Shanks(T, ginv(f), ULONG_MAX, E, &qfi_group); return find_order(E, f, addiu(v,1), pfao); } /* if g = 1 in G/ ? */ static int equal1(void *E, GEN T, ulong N, GEN g) { return !!gen_Shanks(T, g, N, E, &qfi_group); } /* Order of 'a' in G/, T = gen_Shanks_init(f,n), order(f) < n*N * FIXME: should be gen_order, but equal1 has the wrong prototype */ static GEN relative_order(void *E, GEN a, GEN o, ulong N, GEN T) { pari_sp av = avma; long i, l; GEN m; m = get_arith_ZZM(o); if (!m) pari_err_TYPE("gen_order [missing order]",a); o = gel(m,1); m = gel(m,2); l = lgcols(m); for (i = l-1; i; i--) { GEN t, y, p = gcoeff(m,i,1); long j, e = itos(gcoeff(m,i,2)); if (l == 2) { t = gen_1; y = a; } else { t = diviiexact(o, powiu(p,e)); y = powgi(a, t); } if (equal1(E, T,N,y)) o = t; else { for (j = 1; j < e; j++) { y = powgi(y, p); if (equal1(E, T,N,y)) break; } if (j < e) { if (j > 1) p = powiu(p, j); o = mulii(t, p); } } } return gerepilecopy(av, o); } /* h(x) for x<0 using Baby Step/Giant Step. * Assumes G is not too far from being cyclic. * * Compute G^2 instead of G so as to kill most of the non-cyclicity */ GEN classno(GEN x) { pari_sp av = avma; long r2, k, s, i, l; GEN forms, hin, Hf, D, g1, d1, d2, q, L, fad1, order_bound; void *E; if (signe(x) >= 0) return classno2(x); check_quaddisc(x, &s, &k, "classno"); if (abscmpiu(x,12) <= 0) return gen_1; Hf = conductor_part(x, k, &D, NULL); if (abscmpiu(D,12) <= 0) return gerepilecopy(av, Hf); forms = get_forms(D, &L); r2 = two_rank(D); hin = roundr(shiftr(L, -r2)); /* rough approximation for #G, G = Cl(K)^2 */ l = lg(forms); order_bound = const_vec(l-1, NULL); E = expi(D) > 60? (void*)sqrtnint(shifti(absi_shallow(D),-2),4): NULL; g1 = gel(forms,1); gel(order_bound,1) = d1 = Shanks_order(E, g1, hin, &fad1); q = diviiround(hin, d1); /* approximate order of G/ */ d2 = NULL; /* not computed yet */ if (is_pm1(q)) goto END; for (i=2; i < l; i++) { GEN o, fao, a, F, fd, f = gel(forms,i); fd = powgi(f, d1); if (is_pm1(gel(fd,1))) continue; F = powgi(fd, q); a = gel(F,1); o = is_pm1(a)? find_order(E, fd, q, &fao): Shanks_order(E, fd, q, &fao); /* f^(d1 q) = 1 */ fao = merge_factor(fad1,fao, (void*)&cmpii, &cmp_nodata); o = find_order(E, f, fao, &fao); gel(order_bound,i) = o; /* o = order of f, fao = factor(o) */ update_g1(&g1,&d1,&fad1, f,o,fao); q = diviiround(hin, d1); if (is_pm1(q)) goto END; } /* very probably d1 = expo(Cl^2(K)), q ~ #Cl^2(K) / d1 */ if (expi(q) > 3) { /* q large: compute d2, 2nd elt divisor */ ulong N, n = 2*itou(sqrti(d1)); GEN D = d1, T = gen_Shanks_init(g1, n, E, &qfi_group); d2 = gen_1; N = itou( gceil(gdivgs(d1,n)) ); /* order(g1) <= n*N */ for (i = 1; i < l; i++) { GEN d, f = gel(forms,i), B = gel(order_bound,i); if (!B) B = find_order(E, f, fad1, /*junk*/&d); f = powgi(f,d2); if (equal1(E, T,N,f)) continue; B = gdiv(B,d2); if (typ(B) == t_FRAC) B = gel(B,1); /* f^B = 1 */ d = relative_order(E, f, B, N,T); d2= mulii(d,d2); D = mulii(d1,d2); q = diviiround(hin,D); if (is_pm1(q)) { d1 = D; goto END; } } /* very probably, d2 is the 2nd elementary divisor */ d1 = D; /* product of first two elt divisors */ } /* impose q | d2^oo (d1^oo if d2 not computed), and compatible with known * 2-rank */ if (!ok_q(q,d1,d2,r2)) { GEN q0 = q; long d; if (cmpii(mulii(q,d1), hin) < 0) { /* try q = q0+1,-1,+2,-2 */ d = 1; do { q = addis(q0,d); d = d>0? -d: 1-d; } while(!ok_q(q,d1,d2,r2)); } else { /* q0-1,+1,-2,+2 */ d = -1; do { q = addis(q0,d); d = d<0? -d: -1-d; } while(!ok_q(q,d1,d2,r2)); } } d1 = mulii(d1,q); END: return gerepileuptoint(av, shifti(mulii(d1,Hf), r2)); } GEN quadclassno(GEN x) { pari_sp av = avma; GEN Hf, D; long s, r; check_quaddisc(x, &s, &r, "quadclassno"); if (s < 0 && abscmpiu(x,12) <= 0) return gen_1; Hf = conductor_part(x, r, &D, NULL); return gerepileuptoint(av, mulii(Hf, gel(quadclassunit0(D,0,NULL,0),1))); } /* use Euler products */ GEN classno2(GEN x) { pari_sp av = avma; const long prec = DEFAULTPREC; long n, i, r, s; GEN p1, p2, S, p4, p5, p7, Hf, Pi, reg, logd, d, dr, D, half; check_quaddisc(x, &s, &r, "classno2"); if (s < 0 && abscmpiu(x,12) <= 0) return gen_1; Hf = conductor_part(x, r, &D, ®); if (s < 0 && abscmpiu(D,12) <= 0) return gerepilecopy(av, Hf); /* |D| < 12*/ Pi = mppi(prec); d = absi_shallow(D); dr = itor(d, prec); logd = logr_abs(dr); p1 = sqrtr(divrr(mulir(d,logd), gmul2n(Pi,1))); if (s > 0) { GEN invlogd = invr(logd); p2 = subsr(1, shiftr(mulrr(logr_abs(reg),invlogd),1)); if (cmprr(sqrr(p2), shiftr(invlogd,1)) >= 0) p1 = mulrr(p2,p1); } n = itos_or_0( mptrunc(p1) ); if (!n) pari_err_OVERFLOW("classno [discriminant too large]"); p4 = divri(Pi,d); p7 = invr(sqrtr_abs(Pi)); half = real2n(-1, prec); if (s > 0) { /* i = 1, shortcut */ p1 = sqrtr_abs(dr); p5 = subsr(1, mulrr(p7,incgamc(half,p4,prec))); S = addrr(mulrr(p1,p5), eint1(p4,prec)); for (i=2; i<=n; i++) { long k = kroiu(D,i); if (!k) continue; p2 = mulir(sqru(i), p4); p5 = subsr(1, mulrr(p7,incgamc(half,p2,prec))); p5 = addrr(divru(mulrr(p1,p5),i), eint1(p2,prec)); S = (k>0)? addrr(S,p5): subrr(S,p5); } S = shiftr(divrr(S,reg),-1); } else { /* i = 1, shortcut */ p1 = gdiv(sqrtr_abs(dr), Pi); p5 = subsr(1, mulrr(p7,incgamc(half,p4,prec))); S = addrr(p5, divrr(p1, mpexp(p4))); for (i=2; i<=n; i++) { long k = kroiu(D,i); if (!k) continue; p2 = mulir(sqru(i), p4); p5 = subsr(1, mulrr(p7,incgamc(half,p2,prec))); p5 = addrr(p5, divrr(p1, mulur(i, mpexp(p2)))); S = (k>0)? addrr(S,p5): subrr(S,p5); } } return gerepileuptoint(av, mulii(Hf, roundr(S))); } /* 1 + q + ... + q^v, v > 0 */ static GEN geomsumu(ulong q, long v) { GEN u = utoipos(1+q); for (; v > 1; v--) u = addui(1, mului(q, u)); return u; } static GEN geomsum(GEN q, long v) { GEN u; if (lgefint(q) == 3) return geomsumu(q[2], v); u = addiu(q,1); for (; v > 1; v--) u = addui(1, mulii(q, u)); return u; } static GEN hclassno6_large(GEN x) { long i, l, s, xmod4; GEN Q, H, D, P, E; x = negi(x); check_quaddisc(x, &s, &xmod4, "hclassno"); corediscfact(x, xmod4, &D, &P, &E); Q = quadclassunit0(D, 0, NULL, 0); H = gel(Q,1); l = lg(P); /* H \prod_{p^e||f} (1 + (p^e-1)/(p-1))[ p - (D/p) ] */ for (i=1; i 0, x = 0,3 (mod 4). Return 6*hclassno(x), an integer */ GEN hclassno6(GEN x) { ulong d = itou_or_0(x); if (!d || d > 500000) return hclassno6_large(x); return utoipos(hclassno6u(d)); } GEN hclassno(GEN x) { long a, s; if (typ(x) != t_INT) pari_err_TYPE("hclassno",x); s = signe(x); if (s < 0) return gen_0; if (!s) return gdivgs(gen_1, -12); a = mod4(x); if (a == 1 || a == 2) return gen_0; return gdivgs(hclassno6(x), 6); } /******************************************************************/ /* */ /* RAMANUJAN's TAU FUNCTION */ /* */ /******************************************************************/ /* 4|N > 0, not fundamental at 2; 6 * Hurwitz class number in level 2, * equal to 6*(H(N)+2H(N/4)), H=qfbhclassno */ static GEN Hspec(GEN N) { long v2 = Z_lvalrem(N, 2, &N), v2f = v2 >> 1; GEN t; if (odd(v2)) { v2f--; N = shifti(N,3); } else if (mod4(N)!=3) { v2f--; N = shifti(N,2); } /* N fundamental at 2, v2f = v2(f) s.t. N = f^2 D, D fundamental */ t = addui(3, muliu(subiu(int2n(v2f+1), 3), 2 - kroiu(N,2))); return mulii(t, hclassno6(N)); } /* Ramanujan tau function for p prime */ static GEN tauprime(GEN p) { pari_sp av = avma, av2; GEN s, p2, p2_7, p_9, T; ulong lim, t, tin; if (absequaliu(p, 2)) return utoineg(24); /* p > 2 */ p2 = sqri(p); p2_7 = mului(7, p2); p_9 = mului(9, p); av2 = avma; lim = itou(sqrtint(p)); tin = mod4(p) == 3? 1: 0; s = gen_0; for (t = 1; t <= lim; ++t) { GEN h, a, t2 = sqru(t), D = shifti(subii(p, t2), 2); /* 4(p-t^2) */ /* t mod 2 != tin <=> D not fundamental at 2 */ h = ((t&1UL) == tin)? hclassno6(D): Hspec(D); a = mulii(powiu(t2,3), addii(p2_7, mulii(t2, subii(shifti(t2,2), p_9)))); s = addii(s, mulii(a,h)); if (!(t & 255)) s = gerepileuptoint(av2, s); } /* 28p^3 - 28p^2 - 90p - 35 */ T = subii(shifti(mulii(p2_7, subiu(p,1)), 2), addiu(mului(90,p), 35)); s = shifti(diviuexact(s, 3), 6); return gerepileuptoint(av, subii(mulii(mulii(p2,p),T), addui(1, s))); } /* Ramanujan tau function, return 0 for <= 0 */ GEN ramanujantau(GEN n) { pari_sp ltop = avma; GEN T, F, P, E; long j, lP; if (!(F = check_arith_all(n,"ramanujantau"))) { if (signe(n) <= 0) return gen_0; F = Z_factor(n); } else { P = gel(F,1); if (lg(P) == 1 || signe(gel(P,1)) <= 0) return gen_0; } P = gel(F,1); E = gel(F,2); lP = lg(P); T = gen_1; for (j = 1; j < lP; j++) { GEN p = gel(P,j), tp = tauprime(p), t1 = tp, t0 = gen_1; long k, e = itou(gel(E,j)); for (k = 1; k < e; k++) { GEN t2 = subii(mulii(tp, t1), mulii(powiu(p, 11), t0)); t0 = t1; t1 = t2; } T = mulii(T, t1); } return gerepileuptoint(ltop, T); } pari-2.11.2/src/basemath/FpXQX_factor.c0000644000175000017500000023737513457566437016246 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /** **/ /** Isomorphisms between finite fields **/ /** **/ /*******************************************************************/ static void err_Flxq(const char *s, GEN P, ulong l) { if (!uisprime(l)) pari_err_PRIME(s, utoi(l)); pari_err_IRREDPOL(s, Flx_to_ZX(get_Flx_mod(P))); } static void err_FpXQ(const char *s, GEN P, GEN l) { if (!BPSW_psp(l)) pari_err_PRIME(s, l); pari_err_IRREDPOL(s, get_FpX_mod(P)); } /* compute the reciprocical isomorphism of S mod T,p, i.e. V such that V(S)=X mod T,p*/ GEN Flxq_ffisom_inv(GEN S,GEN T, ulong p) { pari_sp ltop = avma; long n = get_Flx_degree(T); GEN M = Flxq_matrix_pow(S,n,n,T,p); GEN V = Flm_Flc_invimage(M, vecsmall_ei(n, 2), p); if (!V) err_Flxq("Flxq_ffisom_inv", T, p); return gerepileupto(ltop, Flv_to_Flx(V, get_Flx_var(T))); } GEN FpXQ_ffisom_inv(GEN S,GEN T, GEN p) { pari_sp ltop = avma; long n = get_FpX_degree(T); GEN M = FpXQ_matrix_pow(S,n,n,T,p); GEN V = FpM_FpC_invimage(M, col_ei(n, 2), p); if (!V) err_FpXQ("Flxq_ffisom_inv", T, p); return gerepilecopy(ltop, RgV_to_RgX(V, get_FpX_var(T))); } /* Let M the matrix of the Frobenius automorphism of Fp[X]/(T). Compute M^d * TODO: use left-right binary (tricky!) */ GEN Flm_Frobenius_pow(GEN M, long d, GEN T, ulong p) { pari_sp ltop=avma; long i,l = get_Flx_degree(T); GEN R, W = gel(M,2); for (i = 2; i <= d; ++i) W = Flm_Flc_mul(M,W,p); R=Flxq_matrix_pow(Flv_to_Flx(W,get_Flx_var(T)),l,l,T,p); return gerepileupto(ltop,R); } GEN FpM_Frobenius_pow(GEN M, long d, GEN T, GEN p) { pari_sp ltop=avma; long i,l = get_FpX_degree(T); GEN R, W = gel(M,2); for (i = 2; i <= d; ++i) W = FpM_FpC_mul(M,W,p); R=FpXQ_matrix_pow(RgV_to_RgX(W, get_FpX_var(T)),l,l,T,p); return gerepilecopy(ltop,R); } /* Essentially we want to compute FqM_ker(MA-pol_x(v),U,l) * To avoid use of matrix in Fq we compute FpM_ker(U(MA),l) then recover the * eigenvalue by Galois action */ static GEN Flx_Flm_Flc_eval(GEN U, GEN MA, GEN a, ulong p) { long i, l = lg(U); GEN b = Flv_Fl_mul(a, uel(U, l-1), p); for (i=l-2; i>=2; i--) b = Flv_add(Flm_Flc_mul(MA, b, p), Flv_Fl_mul(a, uel(U, i), p), p); return b; } static GEN Flx_intersect_ker(GEN P, GEN MA, GEN U, ulong p) { pari_sp ltop = avma; long i, vp = get_Flx_var(P), vu = get_Flx_var(U), r = get_Flx_degree(U); GEN V, A, R; ulong ib0; pari_timer T; if (DEBUGLEVEL>=4) timer_start(&T); V = Flx_div(Flx_Fl_add(monomial_Flx(1, get_Flx_degree(P), vu), p-1, p), U, p); do { A = Flx_Flm_Flc_eval(V, MA, random_Flv(lg(MA)-1, p), p); } while (zv_equal0(A)); if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo"); /*The formula is * a_{r-1} = -\phi(a_0)/b_0 * a_{i-1} = \phi(a_i)+b_ia_{r-1} i=r-1 to 1 * Where a_0=A[1] and b_i=U[i+2] */ ib0 = Fl_inv(Fl_neg(U[2], p), p); R = cgetg(r+1,t_MAT); gel(R,1) = A; gel(R,r) = Flm_Flc_mul(MA, Flv_Fl_mul(A,ib0, p), p); for(i=r-1; i>1; i--) { gel(R,i) = Flm_Flc_mul(MA,gel(R,i+1),p); Flv_add_inplace(gel(R,i), Flv_Fl_mul(gel(R,r), U[i+2], p), p); } return gerepileupto(ltop, Flm_to_FlxX(Flm_transpose(R),vp,vu)); } static GEN FpX_FpM_FpC_eval(GEN U, GEN MA, GEN a, GEN p) { long i, l = lg(U); GEN b = FpC_Fp_mul(a, gel(U, l-1), p); for (i=l-2; i>=2; i--) b = FpC_add(FpM_FpC_mul(MA, b, p), FpC_Fp_mul(a, gel(U, i), p), p); return b; } static GEN FpX_intersect_ker(GEN P, GEN MA, GEN U, GEN l) { pari_sp ltop = avma; long i, vp = get_FpX_var(P), vu = get_FpX_var(U), r = get_FpX_degree(U); GEN V, A, R, ib0; pari_timer T; if (DEBUGLEVEL>=4) timer_start(&T); V = FpX_div(FpX_Fp_sub(pol_xn(get_FpX_degree(P), vu), gen_1, l), U, l); do { A = FpX_FpM_FpC_eval(V, MA, random_FpC(lg(MA)-1, l), l); } while (ZV_equal0(A)); if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo"); /*The formula is * a_{r-1} = -\phi(a_0)/b_0 * a_{i-1} = \phi(a_i)+b_ia_{r-1} i=r-1 to 1 * Where a_0=A[1] and b_i=U[i+2] */ ib0 = Fp_inv(negi(gel(U,2)),l); R = cgetg(r+1,t_MAT); gel(R,1) = A; gel(R,r) = FpM_FpC_mul(MA, FpC_Fp_mul(A,ib0,l), l); for(i=r-1;i>1;i--) gel(R,i) = FpC_add(FpM_FpC_mul(MA,gel(R,i+1),l), FpC_Fp_mul(gel(R,r), gel(U,i+2), l),l); return gerepilecopy(ltop,RgM_to_RgXX(shallowtrans(R),vp,vu)); } /* n must divide both the degree of P and Q. Compute SP and SQ such * that the subfield of FF_l[X]/(P) generated by SP and the subfield of * FF_l[X]/(Q) generated by SQ are isomorphic of degree n. P and Q do * not need to be of the same variable; if MA, resp. MB, is not NULL, must be * the matrix of the Frobenius map in FF_l[X]/(P), resp. FF_l[X]/(Q). * Implementation choice: we assume the prime p is large so we handle * Frobenius as matrices. */ void Flx_ffintersect(GEN P, GEN Q, long n, ulong l,GEN *SP, GEN *SQ, GEN MA, GEN MB) { pari_sp ltop = avma; long vp = get_Flx_var(P), vq = get_Flx_var(Q); long np = get_Flx_degree(P), nq = get_Flx_degree(Q), e; ulong pg; GEN A, B, Ap, Bp; if (np<=0) pari_err_IRREDPOL("FpX_ffintersect", P); if (nq<=0) pari_err_IRREDPOL("FpX_ffintersect", Q); if (n<=0 || np%n || nq%n) pari_err_TYPE("FpX_ffintersect [bad degrees]",stoi(n)); e = u_lvalrem(n, l, &pg); if(!MA) MA = Flx_matFrobenius(P,l); if(!MB) MB = Flx_matFrobenius(Q,l); A = Ap = pol0_Flx(vp); B = Bp = pol0_Flx(vq); if (pg > 1) { pari_timer T; GEN ipg = utoipos(pg); if (l%pg == 1) { /* more efficient special case */ ulong L, z, An, Bn; z = Fl_neg(rootsof1_Fl(pg, l), l); if (DEBUGLEVEL>=4) timer_start(&T); A = Flm_ker(Flm_Fl_add(MA, z, l),l); if (lg(A)!=2) err_Flxq("FpX_ffintersect",P,l); A = Flv_to_Flx(gel(A,1),vp); B = Flm_ker(Flm_Fl_add(MB, z, l),l); if (lg(B)!=2) err_Flxq("FpX_ffintersect",Q,l); B = Flv_to_Flx(gel(B,1),vq); if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker"); An = Flxq_powu(A,pg,P,l)[2]; Bn = Flxq_powu(B,pg,Q,l)[2]; if (!Bn) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q)); z = Fl_div(An,Bn,l); L = Fl_sqrtn(z, pg, l, NULL); if (L==ULONG_MAX) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q)); if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn"); B = Flx_Fl_mul(B,L,l); } else { GEN L, An, Bn, z, U; U = gmael(Flx_factor(ZX_to_Flx(polcyclo(pg, fetch_var()),l),l),1,1); A = Flx_intersect_ker(P, MA, U, l); B = Flx_intersect_ker(Q, MB, U, l); if (DEBUGLEVEL>=4) timer_start(&T); An = gel(FlxYqq_pow(A,ipg,P,U,l),2); Bn = gel(FlxYqq_pow(B,ipg,Q,U,l),2); if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]"); z = Flxq_div(An,Bn,U,l); L = Flxq_sqrtn(z,ipg,U,l,NULL); if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q)); if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn"); B = FlxqX_Flxq_mul(B,L,U,l); A = FlxY_evalx(A,0,l); B = FlxY_evalx(B,0,l); (void)delete_var(); } } if (e) { GEN VP, VQ, Ay, By; ulong lmun = l-1; long j; MA = Flm_Fl_add(MA,lmun,l); MB = Flm_Fl_add(MB,lmun,l); Ay = pol1_Flx(vp); By = pol1_Flx(vq); VP = vecsmall_ei(np, 1); VQ = np == nq? VP: vecsmall_ei(nq, 1); /* save memory */ for(j=0;j 1) { GEN ipg = utoipos(pg); pari_timer T; if (umodiu(l,pg) == 1) /* No need to use relative extension, so don't. (Well, now we don't * in the other case either, but this special case is more efficient) */ { GEN L, An, Bn, z; z = negi( rootsof1u_Fp(pg, l) ); if (DEBUGLEVEL>=4) timer_start(&T); A = FpM_ker(RgM_Rg_add_shallow(MA, z),l); if (lg(A)!=2) err_FpXQ("FpX_ffintersect",P,l); A = RgV_to_RgX(gel(A,1),vp); B = FpM_ker(RgM_Rg_add_shallow(MB, z),l); if (lg(B)!=2) err_FpXQ("FpX_ffintersect",Q,l); B = RgV_to_RgX(gel(B,1),vq); if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker"); An = gel(FpXQ_pow(A,ipg,P,l),2); Bn = gel(FpXQ_pow(B,ipg,Q,l),2); if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q)); z = Fp_div(An,Bn,l); L = Fp_sqrtn(z,ipg,l,NULL); if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q)); if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn"); B = FpX_Fp_mul(B,L,l); } else { GEN L, An, Bn, z, U; U = gmael(FpX_factor(polcyclo(pg,fetch_var()),l),1,1); A = FpX_intersect_ker(P, MA, U, l); B = FpX_intersect_ker(Q, MB, U, l); if (DEBUGLEVEL>=4) timer_start(&T); An = gel(FpXYQQ_pow(A,ipg,P,U,l),2); Bn = gel(FpXYQQ_pow(B,ipg,Q,U,l),2); if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]"); if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q)); z = Fq_div(An,Bn,U,l); L = Fq_sqrtn(z,ipg,U,l,NULL); if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q)); if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn"); B = FqX_Fq_mul(B,L,U,l); A = FpXY_evalx(A,gen_0,l); B = FpXY_evalx(B,gen_0,l); (void)delete_var(); } } if (e) { GEN VP, VQ, Ay, By, lmun = subiu(l,1); long j; MA = RgM_Rg_add_shallow(MA,gen_m1); MB = RgM_Rg_add_shallow(MB,gen_m1); Ay = pol_1(vp); By = pol_1(vq); VP = col_ei(np, 1); VQ = np == nq? VP: col_ei(nq, 1); /* save memory */ for(j=0;j>1, S, T, p); GEN V = FlxqXQ_autsum(mkvec3(xp, Xp, ap2), get_Flx_degree(T), S, T, p); return gel(V,3); } GEN FlxqXQ_halfFrobenius(GEN a, GEN S, GEN T, ulong p) { long vT = get_Flx_var(T); GEN xp, Xp; T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); xp = Flx_Frobenius(T, p); Xp = FlxqXQ_powu(polx_FlxX(get_FlxqX_var(S), vT), p, S, T, p); return FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p); } static GEN FpXQXQ_halfFrobenius_i(GEN a, GEN xp, GEN Xp, GEN S, GEN T, GEN p) { GEN ap2 = FpXQXQ_pow(a, shifti(p,-1), S, T, p); GEN V = FpXQXQ_autsum(mkvec3(xp, Xp, ap2), get_FpX_degree(T), S, T, p); return gel(V, 3); } GEN FpXQXQ_halfFrobenius(GEN a, GEN S, GEN T, GEN p) { pari_sp av = avma; GEN z; if (lgefint(p)==3) { ulong pp = p[2]; long v = get_FpX_var(T); GEN Tp = ZXT_to_FlxT(T,pp), Sp = ZXXT_to_FlxXT(S, pp, v); z = FlxX_to_ZXX(FlxqXQ_halfFrobenius(ZXX_to_FlxX(a,pp,v),Sp,Tp,pp)); } else { GEN xp, Xp; T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); xp = FpX_Frobenius(T, p); Xp = FpXQXQ_pow(pol_x(get_FpXQX_var(S)), p, S, T, p); z = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p); } return gerepilecopy(av, z); } static GEN FlxqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, ulong p) { ulong dT = get_Flx_degree(T), df = get_FlxqX_degree(f); GEN q = powuu(p,dT); if (expi(q) >= expu(dT)*(long)usqrt(df)) return gel(FlxqXQ_autpow(mkvec2(xp, Xp), dT, f, T, p), 2); else return FlxqXQ_pow(pol_x(get_FlxqX_var(f)), q, f, T, p); } GEN FlxqX_Frobenius(GEN S, GEN T, ulong p) { pari_sp av = avma; GEN X = polx_FlxX(get_FlxqX_var(S), get_Flx_var(T)); GEN xp = Flx_Frobenius(T, p); GEN Xp = FlxqXQ_powu(X, p, S, T, p); GEN Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p); return gerepilecopy(av, Xq); } static GEN FpXQXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, GEN p) { ulong dT = get_FpX_degree(T), df = get_FpXQX_degree(f); GEN q = powiu(p, dT); if (expi(q) >= expu(dT)*(long)usqrt(df)) return gel(FpXQXQ_autpow(mkvec2(xp, Xp), dT, f, T, p), 2); else return FpXQXQ_pow(pol_x(get_FpXQX_var(f)), q, f, T, p); } GEN FpXQX_Frobenius(GEN S, GEN T, GEN p) { pari_sp av = avma; GEN X = pol_x(get_FpXQX_var(S)); GEN xp = FpX_Frobenius(T, p); GEN Xp = FpXQXQ_pow(X, p, S, T, p); GEN Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p); return gerepilecopy(av, Xq); } static GEN F2xqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T) { ulong dT = get_F2x_degree(T), df = get_F2xqX_degree(f); if (dT >= expu(dT)*usqrt(df)) return gel(F2xqXQ_autpow(mkvec2(xp, Xp), dT, f, T), 2); else { long v = get_F2xqX_var(f), vT = get_F2x_var(T); return F2xqXQ_pow(polx_F2xX(v,vT), int2n(dT), f, T); } } static GEN FlxqX_split_part(GEN f, GEN T, ulong p) { long n = degpol(f); GEN z, Xq, X = polx_FlxX(varn(f),get_Flx_var(T)); if (n <= 1) return f; f = FlxqX_red(f, T, p); Xq = FlxqX_Frobenius(f, T, p); z = FlxX_sub(Xq, X , p); return FlxqX_gcd(z, f, T, p); } GEN FpXQX_split_part(GEN f, GEN T, GEN p) { if(lgefint(p)==3) { ulong pp=p[2]; GEN Tp = ZXT_to_FlxT(T, pp); GEN z = FlxqX_split_part(ZXX_to_FlxX(f, pp, get_Flx_var(T)), Tp, pp); return FlxX_to_ZXX(z); } else { long n = degpol(f); GEN z, X = pol_x(varn(f)); if (n <= 1) return f; f = FpXQX_red(f, T, p); z = FpXQX_Frobenius(f, T, p); z = FpXX_sub(z, X , p); return FpXQX_gcd(z, f, T, p); } } long FpXQX_nbroots(GEN f, GEN T, GEN p) { pari_sp av = avma; GEN z = FpXQX_split_part(f, T, p); avma = av; return degpol(z); } long FqX_nbroots(GEN f, GEN T, GEN p) { return T ? FpXQX_nbroots(f, T, p): FpX_nbroots(f, p); } long FlxqX_nbroots(GEN f, GEN T, ulong p) { pari_sp av = avma; GEN z = FlxqX_split_part(f, T, p); avma = av; return degpol(z); } static GEN FlxqX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, ulong p) { long j, N = get_FlxqX_degree(S); GEN Q = FlxqXQ_matrix_pow(Xq,N,N,S,T,p); for (j=1; j<=N; j++) gcoeff(Q,j,j) = Flx_Fl_add(gcoeff(Q,j,j), p-1, p); return FlxqM_ker(Q,T,p); } static GEN FpXQX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, GEN p) { long j,N = get_FpXQX_degree(S); GEN Q = FpXQXQ_matrix_pow(Xq,N,N,S,T,p); for (j=1; j<=N; j++) gcoeff(Q,j,j) = Fq_sub(gcoeff(Q,j,j), gen_1, T, p); return FqM_ker(Q,T,p); } static long isabsolutepol(GEN f) { long i, l = lg(f); for(i=2; i 0) return 0; } return 1; } #define set_irred(i) { if ((i)>ir) swap(t[i],t[ir]); ir++;} static long FlxqX_split_Berlekamp(GEN *t, GEN xp, GEN T, ulong p) { GEN u = *t, a,b,vker,pol; long vu = varn(u), vT = get_Flx_var(T), dT = get_Flx_degree(T); long d, i, ir, L, la, lb; GEN S, X, Xp, Xq; if (degpol(u)==1) return 1; T = Flx_get_red(T, p); S = FlxqX_get_red(u, T, p); X = polx_FlxX(get_FlxqX_var(S),get_Flx_var(T)); Xp = FlxqXQ_powu(X, p, S, T, p); Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p); vker = FlxqX_Berlekamp_ker_i(Xq, S, T, p); vker = Flm_to_FlxV(vker,u[1]); d = lg(vker)-1; ir = 0; /* t[i] irreducible for i < ir, still to be treated for i < L */ for (L=1; L2 and x monic */ static GEN FlxqX_quad_roots(GEN x, GEN T, ulong p) { GEN s, D, nb, b = gel(x,3), c = gel(x,2); D = Flx_sub(Flxq_sqr(b,T,p), Flx_mulu(c,4,p), p); nb = Flx_neg(b,p); if (lgpol(D)==0) return mkcol(Flx_halve(nb, p)); s = Flxq_sqrt(D,T,p); if (!s) return cgetg(1, t_COL); s = Flx_halve(Flx_add(s,nb,p),p); return mkcol2(s, Flx_sub(nb,s,p)); } static GEN FpXQX_quad_roots(GEN x, GEN T, GEN p) { GEN s, D, nb, b = gel(x,3), c = gel(x,2); if (absequaliu(p, 2)) { GEN f2 = ZXX_to_F2xX(x, get_FpX_var(T)); s = F2xqX_quad_roots(f2, ZX_to_F2x(get_FpX_mod(T))); return F2xC_to_ZXC(s); } D = Fq_sub(Fq_sqr(b,T,p), Fq_Fp_mul(c,utoi(4),T,p), T,p); nb = Fq_neg(b,T,p); if (signe(D)==0) return mkcol(Fq_to_FpXQ(Fq_halve(nb,T, p),T,p)); s = Fq_sqrt(D,T,p); if (!s) return cgetg(1, t_COL); s = Fq_halve(Fq_add(s,nb,T,p),T, p); return mkcol2(Fq_to_FpXQ(s,T,p), Fq_to_FpXQ(Fq_sub(nb,s,T,p),T,p)); } static GEN F2xqX_Frobenius_deflate(GEN S, GEN T) { GEN F = RgX_deflate(S, 2); long i, l = lg(F); for (i=2; i 0) { long j; for(j = 1;;j++) { v = F2xqX_gcd(r, t, T); tv = F2xqX_div(t, v, T); if (degpol(tv) > 0) gel(u, j*q) = F2xqX_normalize(tv, T); if (degpol(v) <= 0) break; r = F2xqX_div(r, v, T); t = v; } if (degpol(r) == 0) break; } f = F2xqX_Frobenius_deflate(r, T); } for (i = n; i; i--) if (degpol(gel(u,i))) break; setlg(u,i+1); return gerepilecopy(av, u); } long F2xqX_ispower(GEN f, long k, GEN T, GEN *pt_r) { pari_sp av = avma; GEN lc, F; long i, l, n = degpol(f), v = varn(f); if (n % k) return 0; lc = F2xq_sqrtn(leading_coeff(f), stoi(k), T, NULL); if (!lc) { av = avma; return 0; } F = F2xqX_factor_squarefree(f, T); l = lg(F)-1; for(i=1; i<=l; i++) if (i%k && degpol(gel(F,i))) { avma = av; return 0; } if (pt_r) { GEN r = scalarpol(lc, v), s = pol1_F2xX(v, T[1]); for(i=l; i>=1; i--) { if (i%k) continue; s = F2xqX_mul(s, gel(F,i), T); r = F2xqX_mul(r, s, T); } *pt_r = gerepileupto(av, r); } else av = avma; return 1; } static void F2xqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN V, long idx) { pari_sp btop; long n = degpol(Sp); GEN S, f, ff; long dT = get_F2x_degree(T); GEN R = F2xqX_easyroots(Sp, T); if (R) { long i, l = lg(R)-1; for (i=0; i 0 && degpol(f) < n) break; avma = btop; } f = gerepileupto(btop, F2xqX_normalize(f, T)); ff = F2xqX_div(Sp, f, T); F2xqX_roots_edf(f, xp, Xp, T, V, idx); F2xqX_roots_edf(ff,xp, Xp, T, V, idx+degpol(f)); } static GEN F2xqX_roots_ddf(GEN f, GEN xp, GEN T) { GEN X, Xp, Xq, g, V; long n; GEN R = F2xqX_easyroots(f, T); if (R) return R; X = pol_x(varn(f)); Xp = F2xqXQ_sqr(X, f, T); Xq = F2xqXQ_Frobenius(xp, Xp, f, T); g = F2xqX_gcd(F2xX_add(Xq, X), f, T); n = degpol(g); if (n==0) return cgetg(1, t_COL); g = F2xqX_normalize(g, T); V = cgetg(n+1,t_COL); F2xqX_roots_edf(g, xp, Xp, T, V, 1); return V; } static GEN F2xqX_roots_i(GEN S, GEN T) { GEN M; S = F2xqX_red(S, T); if (!signe(S)) pari_err_ROOTS0("F2xqX_roots"); if (degpol(S)==0) return cgetg(1, t_COL); S = F2xqX_normalize(S, T); M = F2xqX_easyroots(S, T); if (!M) { GEN xp = F2x_Frobenius(T); GEN F, V = F2xqX_factor_squarefree(S, T); long i, j, l = lg(V); F = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (degpol(gel(V,i))) gel(F, j++) = F2xqX_roots_ddf(gel(V,i), xp, T); setlg(F,j); M = shallowconcat1(F); } gen_sort_inplace(M, (void*) &cmp_Flx, &cmp_nodata, NULL); return M; } static GEN FlxqX_easyroots(GEN f, GEN T, ulong p) { if (FlxY_degreex(f) <= 0) return Flx_rootsff_i(FlxX_to_Flx(f), T, p); if (degpol(f)==1) return mkcol(Flx_neg(constant_coeff(f), p)); if (degpol(f)==2) return FlxqX_quad_roots(f,T,p); return NULL; } static GEN FlxqX_invFrobenius(GEN xp, GEN T, ulong p) { return Flxq_autpow(xp, get_Flx_degree(T)-1, T, p); } static GEN FlxqX_Frobenius_deflate(GEN S, GEN ixp, GEN T, ulong p) { GEN F = RgX_deflate(S, p); long i, l = lg(F); if (typ(ixp)==t_INT) for (i=2; i 0) { long j; for(j = 1;;j++) { v = FlxqX_gcd(r, t, T, p); tv = FlxqX_div(t, v, T, p); if (degpol(tv) > 0) gel(u, j*q) = FlxqX_normalize(tv, T, p); if (degpol(v) <= 0) break; r = FlxqX_div(r, v, T, p); t = v; } if (degpol(r) == 0) break; } if (!xp) xp = Flx_Frobenius(T, p); if (!ixp) ixp = FlxqX_invFrobenius(xp, T, p); f = FlxqX_Frobenius_deflate(r, ixp, T, p); } for (i = n; i; i--) if (degpol(gel(u,i))) break; setlg(u,i+1); return gerepilecopy(av, u); } GEN FlxqX_factor_squarefree(GEN f, GEN T, ulong p) { return FlxqX_factor_squarefree_i(f, NULL, T, p); } long FlxqX_ispower(GEN f, ulong k, GEN T, ulong p, GEN *pt_r) { pari_sp av = avma; GEN lc, F; long i, l, n = degpol(f), v = varn(f); if (n % k) return 0; lc = Flxq_sqrtn(leading_coeff(f), stoi(k), T, p, NULL); if (!lc) { av = avma; return 0; } F = FlxqX_factor_squarefree_i(f, NULL, T, p); l = lg(F)-1; for(i=1; i<=l; i++) if (i%k && degpol(gel(F,i))) { avma = av; return 0; } if (pt_r) { GEN r = scalarpol(lc, v), s = pol1_FlxX(v, T[1]); for(i=l; i>=1; i--) { if (i%k) continue; s = FlxqX_mul(s, gel(F,i), T, p); r = FlxqX_mul(r, s, T, p); } *pt_r = gerepileupto(av, r); } else av = avma; return 1; } static GEN FlxqX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, ulong p) { pari_sp btop = avma; long n = degpol(Sp); GEN f; long vT = get_Flx_var(T), dT = get_Flx_degree(T); pari_timer ti; if (DEBUGLEVEL >= 7) timer_start(&ti); while (1) { GEN a = deg1pol(pol1_Flx(vT), random_Flx(dT, vT, p), varn(Sp)); GEN R = FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p); if (DEBUGLEVEL >= 7) timer_printf(&ti, "FlxqXQ_halfFrobenius"); f = FlxqX_gcd(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p); if (degpol(f) > 0 && degpol(f) < n) break; avma = btop; } return gerepileupto(btop, FlxqX_normalize(f, T, p)); } static void FlxqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, ulong p, GEN V, long idx) { GEN S, f, ff; GEN R = FlxqX_easyroots(Sp, T, p); if (R) { long i, l = lg(R)-1; for (i=0; i 0) gel(u, j) = FpXQX_normalize(tv, T, p); if (degpol(v) <= 0) break; r = FpXQX_div(r, v, T, p); t = v; } setlg(u, j+1); return gerepilecopy(av, u); } GEN FpXQX_factor_squarefree(GEN f, GEN T, GEN p) { if (lgefint(p)==3) { pari_sp av = avma; ulong pp = p[2]; GEN M; long vT = get_FpX_var(T); if (pp==2) { M = F2xqX_factor_squarefree(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T))); return gerepileupto(av, F2xXC_to_ZXXC(M)); } M = FlxqX_factor_squarefree(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp); return gerepileupto(av, FlxXC_to_ZXXC(M)); } return FpXQX_factor_Yun(f, T, p); } long FpXQX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r) { pari_sp av = avma; GEN lc, F; long i, l, n = degpol(f), v = varn(f); if (n % k) return 0; if (lgefint(p)==3) { ulong pp = p[2]; GEN fp = ZXX_to_FlxX(f, pp, varn(T)); if (!FlxqX_ispower(fp, k, ZX_to_Flx(T, pp), pp, pt_r)) { avma = av; return 0; } if (pt_r) *pt_r = gerepileupto(av, FlxX_to_ZXX(*pt_r)); else avma = av; return 1; } lc = FpXQ_sqrtn(leading_coeff(f), stoi(k), T, p, NULL); if (!lc) { av = avma; return 0; } F = FpXQX_factor_Yun(f, T, p); l = lg(F)-1; for(i=1; i <= l; i++) if (i%k && degpol(gel(F,i))) { avma = av; return 0; } if (pt_r) { GEN r = scalarpol(lc, v), s = pol_1(v); for(i=l; i>=1; i--) { if (i%k) continue; s = FpXQX_mul(s, gel(F,i), T, p); r = FpXQX_mul(r, s, T, p); } *pt_r = gerepileupto(av, r); } else av = avma; return 1; } long FqX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r) { return T ? FpXQX_ispower(f, k, T, p, pt_r): FpX_ispower(f, k, p, pt_r); } static GEN FpXQX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, GEN p) { pari_sp btop = avma; long n = degpol(Sp); GEN f; long vT = get_FpX_var(T), dT = get_FpX_degree(T); pari_timer ti; if (DEBUGLEVEL >= 7) timer_start(&ti); while (1) { GEN a = deg1pol(pol_1(vT), random_FpX(dT, vT, p), varn(Sp)); GEN R = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p); if (DEBUGLEVEL >= 7) timer_printf(&ti, "FpXQXQ_halfFrobenius"); f = FpXQX_gcd(FqX_Fq_sub(R, pol_1(vT), T, p), Sp, T, p); if (degpol(f) > 0 && degpol(f) < n) break; avma = btop; } return gerepileupto(btop, FpXQX_normalize(f, T, p)); } static void FpXQX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN p, GEN V, long idx) { GEN S, f, ff; GEN R = FpXQX_easyroots(Sp, T, p); if (R) { long i, l = lg(R)-1; for (i=0; i=7) timer_start(&ti); if (dT <= ro) for (i = 3; i <= l+1; i++) gel(b, i) = F2xqXQ_pow(gel(b, i-1), int2n(dT), S, T); else { xq = F2xqXQ_powers(gel(b, 2), bo, S, T); if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq baby"); for (i = 3; i <= l+1; i++) gel(b, i) = F2xqX_F2xqXQV_eval(gel(b, i-1), xq, S, T); } if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: baby"); xq = F2xqXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T); if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq giant"); g = cgetg(m+1, t_VEC); gel(g, 1) = gel(xq, 2); for(i = 2; i <= m; i++) gel(g, i) = F2xqX_F2xqXQV_eval(gel(g, i-1), xq, S, T); if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: giant"); h = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { pari_sp av = avma; GEN gj = gel(g, j); GEN e = F2xX_add(gj, gel(b, 1)); for (i = 2; i <= l; i++) e = F2xqXQ_mul(e, F2xX_add(gj, gel(b, i)), S, T); gel(h, j) = gerepileupto(av, e); } if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: diff"); Sr = get_F2xqX_mod(S); F = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { GEN u = F2xqX_gcd(Sr, gel(h,j), T); if (degpol(u)) { u = F2xqX_normalize(u, T); Sr = F2xqX_div(Sr, u, T); } gel(F,j) = u; } if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: F"); f = const_vec(n, pol1_F2xX(v, vT)); for (j = 1; j <= m; j++) { GEN e = gel(F, j); for (i=l-1; i >= 0; i--) { GEN u = F2xqX_gcd(e, F2xX_add(gel(g, j), gel(b, i+1)), T); if (degpol(u)) { gel(f, l*j-i) = u = F2xqX_normalize(u, T); e = F2xqX_div(e, u, T); } if (!degpol(e)) break; } } if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: f"); if (degpol(Sr)) gel(f, degpol(Sr)) = Sr; return gerepilecopy(av, f); } static GEN F2xqX_ddf_i(GEN f, GEN T, GEN X, GEN xp) { GEN Xp, Xq; if (!get_F2xqX_degree(f)) return cgetg(1,t_VEC); f = F2xqX_get_red(f, T); Xp = F2xqXQ_sqr(X, f, T); Xq = F2xqXQ_Frobenius(xp, Xp, f, T); return F2xqX_ddf_Shoup(f, Xq, T); } static void F2xqX_ddf_init(GEN *S, GEN *T, GEN *xp, GEN *X) { *T = F2x_get_red(*T); *S = F2xqX_normalize(get_F2xqX_mod(*S), *T); *xp = F2x_Frobenius(*T); *X = polx_F2xX(get_F2xqX_var(*S), get_F2x_var(*T)); } GEN F2xqX_degfact(GEN S, GEN T) { GEN xp, X, V; long i, l; F2xqX_ddf_init(&S,&T,&xp,&X); V = F2xqX_factor_squarefree(S, T); l = lg(V); for (i=1; i < l; i++) gel(V,i) = F2xqX_ddf_i(gel(V,i), T, X, xp); return vddf_to_simplefact(V, degpol(S)); } GEN F2xqX_ddf(GEN S, GEN T) { GEN xp, X; F2xqX_ddf_init(&S,&T,&xp,&X); return ddf_to_ddf2( F2xqX_ddf_i(S, T, X, xp) ); } static void F2xqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Sq, long d, GEN T, GEN V, long idx) { long v = varn(Sp), n = degpol(Sp), r = n/d; GEN S, f, ff; long dT = get_F2x_degree(T); if (r==1) { gel(V, idx) = Sp; return; } S = F2xqX_get_red(Sp, T); Xp = F2xqX_rem(Xp, S, T); Sq = F2xqXQV_red(Sq, S, T); while (1) { pari_sp btop = avma; long l; GEN w0 = random_F2xqX(n, v, T), g = w0; for (l=1; l 0 && degpol(f) < n) break; avma = btop; } f = F2xqX_normalize(f, T); ff = F2xqX_div(Sp, f , T); F2xqX_edf_simple(f, xp, Xp, Sq, d, T, V, idx); F2xqX_edf_simple(ff, xp, Xp, Sq, d, T, V, idx+degpol(f)/d); } static GEN F2xqX_factor_Shoup(GEN S, GEN xp, GEN T) { long i, n, s = 0; GEN X, Xp, Xq, Sq, D, V; long vT = get_F2x_var(T); pari_timer ti; n = get_F2xqX_degree(S); S = F2xqX_get_red(S, T); if (DEBUGLEVEL>=6) timer_start(&ti); X = polx_F2xX(get_F2xqX_var(S), vT); Xp = F2xqXQ_sqr(X, S, T); Xq = F2xqXQ_Frobenius(xp, Xp, S, T); Sq = F2xqXQ_powers(Xq, n-1, S, T); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_Frobenius"); D = F2xqX_ddf_Shoup(S, Xq, T); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_ddf_Shoup"); s = ddf_to_nbfact(D); V = cgetg(s+1, t_COL); for (i = 1, s = 1; i <= n; i++) { GEN Di = gel(D,i); long ni = degpol(Di), ri = ni/i; if (ni == 0) continue; Di = F2xqX_normalize(Di, T); if (ni == i) { gel(V, s++) = Di; continue; } F2xqX_edf_simple(Di, xp, Xp, Sq, i, T, V, s); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_edf(%ld)",i); s += ri; } return V; } static GEN F2xqX_factor_Cantor(GEN f, GEN T) { GEN xp, E, F, V; long i, j, l; T = F2x_get_red(T); f = F2xqX_normalize(f, T); switch(degpol(f)) { case -1: retmkmat2(mkcol(f), mkvecsmall(1)); case 0: return trivial_fact(); case 1: retmkmat2(mkcol(f), mkvecsmall(1)); case 2: return F2xqX_factor_2(f, T); } if (F2xY_degreex(f) <= 0) return F2x_factorff_i(F2xX_to_F2x(f), T); xp = F2x_Frobenius(T); V = F2xqX_factor_squarefree(f, T); l = lg(V); F = cgetg(l, t_VEC); E = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (degpol(gel(V,i))) { GEN Fj = F2xqX_factor_Shoup(gel(V,i), xp, T); gel(F, j) = Fj; gel(E, j) = const_vecsmall(lg(Fj)-1, i); j++; } return sort_factor_pol(FE_concat(F,E,j), cmp_Flx); } static GEN FlxqX_Berlekamp_i(GEN f, GEN T, ulong p) { long lfact, d = degpol(f), j, k, lV; GEN E, t, V, xp; switch(d) { case -1: retmkmat2(mkcolcopy(f), mkvecsmall(1)); case 0: return trivial_fact(); } T = Flx_get_red(T, p); f = FlxqX_normalize(f, T, p); if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p); if (degpol(f)==2) return FlxqX_factor_2(f, T, p); xp = Flx_Frobenius(T, p); V = FlxqX_factor_squarefree_i(f, xp, T, p); lV = lg(V); /* to hold factors and exponents */ t = cgetg(d+1,t_VEC); E = cgetg(d+1, t_VECSMALL); lfact = 1; for (k=1; k=7) timer_start(&ti); b = XP; if (expi(q) > ro) { xq = FlxqXQ_powers(b, brent_kung_optpow(n, l-1, 1), S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq baby"); } else xq = NULL; for (i = 3; i <= l+1; i++) { b = xq ? FlxqX_FlxqXQV_eval(b, xq, S, T, p) : FlxqXQ_pow(b, q, S, T, p); if (gequal(b,X)) { avma = av; return i-1; } hash_insert_long(&h, b, i-1); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: baby"); g = b; xq = FlxqXQ_powers(g, brent_kung_optpow(n, m, 1), S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq giant"); for(i = 2; i <= m+1; i++) { g = FlxqX_FlxqXQV_eval(g, xq, S, T, p); if (hash_haskey_long(&h, g, &j)) { avma=av; return l*i-j; } } avma = av; return n; } static GEN FlxqX_ddf_Shoup(GEN S, GEN Xq, GEN T, ulong p) { pari_sp av = avma; GEN b, g, h, F, f, Sr, xq, q; long i, j, n, v, vT, bo, ro; long B, l, m; pari_timer ti; n = get_FlxqX_degree(S); v = get_FlxqX_var(S); vT = get_Flx_var(T); if (n == 0) return cgetg(1, t_VEC); if (n == 1) return mkvec(get_FlxqX_mod(S)); B = n/2; l = usqrt(B); m = (B+l-1)/l; S = FlxqX_get_red(S, T, p); b = cgetg(l+2, t_VEC); gel(b, 1) = polx_FlxX(v, vT); gel(b, 2) = Xq; bo = brent_kung_optpow(n, l-1, 1); ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo); q = powuu(p, get_Flx_degree(T)); if (DEBUGLEVEL>=7) timer_start(&ti); if (expi(q) <= ro) for (i = 3; i <= l+1; i++) gel(b, i) = FlxqXQ_pow(gel(b, i-1), q, S, T, p); else { xq = FlxqXQ_powers(gel(b, 2), bo, S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq baby"); for (i = 3; i <= l+1; i++) gel(b, i) = FlxqX_FlxqXQV_eval(gel(b, i-1), xq, S, T, p); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: baby"); xq = FlxqXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq giant"); g = cgetg(m+1, t_VEC); gel(g, 1) = gel(xq, 2); for(i = 2; i <= m; i++) gel(g, i) = FlxqX_FlxqXQV_eval(gel(g, i-1), xq, S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: giant"); h = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { pari_sp av = avma; GEN gj = gel(g, j); GEN e = FlxX_sub(gj, gel(b, 1), p); for (i = 2; i <= l; i++) e = FlxqXQ_mul(e, FlxX_sub(gj, gel(b, i), p), S, T, p); gel(h, j) = gerepileupto(av, e); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: diff"); Sr = get_FlxqX_mod(S); F = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { GEN u = FlxqX_gcd(Sr, gel(h, j), T, p); if (degpol(u)) { u = FlxqX_normalize(u, T, p); Sr = FlxqX_div(Sr, u, T, p); } gel(F,j) = u; } if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: F"); f = const_vec(n, pol1_FlxX(v, vT)); for (j = 1; j <= m; j++) { GEN e = gel(F, j); for (i=l-1; i >= 0; i--) { GEN u = FlxqX_gcd(e, FlxX_sub(gel(g, j), gel(b, i+1), p), T, p); if (degpol(u)) { gel(f, l*j-i) = u = FlxqX_normalize(u, T, p); e = FlxqX_div(e, u, T, p); } if (!degpol(e)) break; } } if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: f"); if (degpol(Sr)) gel(f, degpol(Sr)) = Sr; return gerepilecopy(av, f); } static GEN FlxqX_ddf_i(GEN f, GEN T, ulong p) { GEN Xq; if (!get_FlxqX_degree(f)) return cgetg(1, t_VEC); f = FlxqX_get_red(f, T, p); Xq = FlxqX_Frobenius(f, T, p); return FlxqX_ddf_Shoup(f, Xq, T, p); } GEN FlxqX_ddf(GEN S, GEN T, ulong p) { T = Flx_get_red(T, p); S = FlxqX_normalize(get_FlxqX_mod(S), T, p); return ddf_to_ddf2( FlxqX_ddf_i(S, T, p) ); } GEN FlxqX_degfact(GEN S, GEN T, ulong p) { GEN V; long i, l; T = Flx_get_red(T, p); S = FlxqX_normalize(get_FlxqX_mod(S), T, p); V = FlxqX_factor_squarefree(S, T, p); l = lg(V); for (i=1; i < l; i++) gel(V,i) = FlxqX_ddf_i(gel(V,i), T, p); return vddf_to_simplefact(V, degpol(S)); } static void FlxqX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, ulong p, GEN V, long idx) { GEN Sp = get_FlxqX_mod(S); GEN u1, u2, f1, f2; GEN h; h = FlxqX_get_red(hp, T, p); t = FlxqX_rem(t, S, T, p); Xp = FlxqX_rem(Xp, h, T, p); u1 = FlxqX_roots_split(hp, xp, Xp, h, T, p); f1 = FlxqX_gcd(FlxqX_FlxqXQ_eval(u1, t, S, T, p), Sp, T, p); f1 = FlxqX_normalize(f1, T, p); u2 = FlxqX_div(hp, u1, T, p); f2 = FlxqX_div(Sp, f1, T, p); if (degpol(u1)==1) gel(V, idx) = f1; else FlxqX_edf_rec(FlxqX_get_red(f1, T, p), xp, Xp, u1, t, d, T, p, V, idx); idx += degpol(f1)/d; if (degpol(u2)==1) gel(V, idx) = f2; else FlxqX_edf_rec(FlxqX_get_red(f2, T, p), xp, Xp, u2, t, d, T, p, V, idx); } static void FlxqX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p, GEN V, long idx) { long n = degpol(Sp), r = n/d, vS = varn(Sp), vT = get_Flx_var(T); GEN S, h, t; pari_timer ti; if (r==1) { gel(V, idx) = Sp; return; } S = FlxqX_get_red(Sp, T, p); Xp = FlxqX_rem(Xp, S, T, p); Xq = FlxqX_rem(Xq, S, T, p); if (DEBUGLEVEL>=7) timer_start(&ti); do { GEN g = random_FlxqX(n, vS, T, p); t = gel(FlxqXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2); if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_auttrace"); h = FlxqXQ_minpoly(t, S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_minpoly"); } while (degpol(h) != r); Xp = FlxqXQ_powu(polx_FlxX(vS, vT), p, h, T, p); FlxqX_edf_rec(S, xp, Xp, h, t, d, T, p, V, idx); } static void FlxqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p, GEN V, long idx) { long v = varn(Sp), n = degpol(Sp), r = n/d; GEN S, f, ff; long vT = get_Flx_var(T), dT = get_Flx_degree(T); if (r==1) { gel(V, idx) = Sp; return; } S = FlxqX_get_red(Sp, T, p); Xp = FlxqX_rem(Xp, S, T, p); Xq = FlxqX_rem(Xq, S, T, p); while (1) { pari_sp btop = avma; long i; GEN g = random_FlxqX(n, v, T, p); GEN t = gel(FlxqXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2); if (lgpol(t) == 0) continue; for(i=1; i<=10; i++) { pari_sp btop2 = avma; GEN r = random_Flx(dT, vT, p); GEN R = FlxqXQ_halfFrobenius_i(FlxX_Flx_add(t, r, p), xp, Xp, S, T, p); f = FlxqX_gcd(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p); if (degpol(f) > 0 && degpol(f) < n) break; avma = btop2; } if (degpol(f) > 0 && degpol(f) < n) break; avma = btop; } f = FlxqX_normalize(f, T, p); ff = FlxqX_div(Sp, f , T, p); FlxqX_edf_simple(f, xp, Xp, Xq, d, T, p, V, idx); FlxqX_edf_simple(ff, xp, Xp, Xq, d, T, p, V, idx+degpol(f)/d); } static GEN FlxqX_factor_Shoup(GEN S, GEN xp, GEN T, ulong p) { long i, n, s = 0; GEN X, Xp, Xq, D, V; long dT = get_Flx_degree(T), vT = get_Flx_var(T); long e = expi(powuu(p, dT)); pari_timer ti; n = get_FlxqX_degree(S); S = FlxqX_get_red(S, T, p); if (DEBUGLEVEL>=6) timer_start(&ti); X = polx_FlxX(get_FlxqX_var(S), vT); Xp = FlxqXQ_powu(X, p, S, T, p); Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_Frobenius"); D = FlxqX_ddf_Shoup(S, Xq, T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_ddf_Shoup"); s = ddf_to_nbfact(D); V = cgetg(s+1, t_COL); for (i = 1, s = 1; i <= n; i++) { GEN Di = gel(D,i); long ni = degpol(Di), ri = ni/i; if (ni == 0) continue; Di = FlxqX_normalize(Di, T, p); if (ni == i) { gel(V, s++) = Di; continue; } if (ri <= e*expu(e)) FlxqX_edf(Di, xp, Xp, Xq, i, T, p, V, s); else FlxqX_edf_simple(Di, xp, Xp, Xq, i, T, p, V, s); if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_edf(%ld)",i); s += ri; } return V; } static GEN FlxqX_factor_Cantor(GEN f, GEN T, ulong p) { GEN xp, E, F, V; long i, j, l; T = Flx_get_red(T, p); f = FlxqX_normalize(f, T, p); switch(degpol(f)) { case -1: retmkmat2(mkcol(f), mkvecsmall(1)); case 0: return trivial_fact(); case 1: retmkmat2(mkcol(f), mkvecsmall(1)); case 2: return FlxqX_factor_2(f, T, p); } if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p); xp = Flx_Frobenius(T, p); V = FlxqX_factor_squarefree_i(f, xp, get_Flx_mod(T), p); l = lg(V); F = cgetg(l, t_VEC); E = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (degpol(gel(V,i))) { GEN Fj = FlxqX_factor_Shoup(gel(V,i), xp, T, p); gel(F, j) = Fj; gel(E, j) = const_vecsmall(lg(Fj)-1, i); j++; } return sort_factor_pol(FE_concat(F,E,j), cmp_Flx); } long FlxqX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, ulong p) { pari_sp av = avma; GEN u = get_FlxqX_mod(S); long s; if (FlxY_degreex(u) <= 0) s = Flx_nbfactff(FlxX_to_Flx(u), T, p); else s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, Xq, T, p)); avma = av; return s; } long FlxqX_nbfact(GEN S, GEN T, ulong p) { pari_sp av = avma; GEN u = get_FlxqX_mod(S); long s; if (FlxY_degreex(u) <= 0) s = Flx_nbfactff(FlxX_to_Flx(u), T, p); else s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, FlxqX_Frobenius(S, T, p), T, p)); avma = av; return s; } GEN FlxqX_factor(GEN x, GEN T, ulong p) { pari_sp av = avma; return gerepilecopy(av, FlxqX_factor_Cantor(x, T, p)); } GEN F2xqX_factor(GEN x, GEN T) { pari_sp av = avma; return gerepilecopy(av, F2xqX_factor_Cantor(x, T)); } long FpXQX_ddf_degree(GEN S, GEN XP, GEN T, GEN p) { pari_sp av = avma; GEN X, b, g, xq, q; long i, j, n, v, B, l, m, bo, ro; pari_timer ti; hashtable h; n = get_FpXQX_degree(S); v = get_FpXQX_var(S); X = pol_x(v); if (gequal(X,XP)) return 1; B = n/2; l = usqrt(B); m = (B+l-1)/l; T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); hash_init_GEN(&h, l+2, gequal, 1); hash_insert_long(&h, X, 0); hash_insert_long(&h, simplify_shallow(XP), 1); bo = brent_kung_optpow(n, l-1, 1); ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo); q = powiu(p, get_FpX_degree(T)); if (DEBUGLEVEL>=7) timer_start(&ti); b = XP; if (expi(q) > ro) { xq = FpXQXQ_powers(b, brent_kung_optpow(n, l-1, 1), S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq baby"); } else xq = NULL; for (i = 3; i <= l+1; i++) { b = xq ? FpXQX_FpXQXQV_eval(b, xq, S, T, p) : FpXQXQ_pow(b, q, S, T, p); if (gequal(b,X)) { avma = av; return i-1; } hash_insert_long(&h, simplify_shallow(b), i-1); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: baby"); g = b; xq = FpXQXQ_powers(g, brent_kung_optpow(n, m, 1), S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq giant"); for(i = 2; i <= m+1; i++) { g = FpXQX_FpXQXQV_eval(g, xq, S, T, p); if (hash_haskey_long(&h, simplify_shallow(g), &j)) { avma=av; return l*i-j; } } avma = av; return n; } static GEN FpXQX_ddf_Shoup(GEN S, GEN Xq, GEN T, GEN p) { pari_sp av = avma; GEN b, g, h, F, f, Sr, xq, q; long i, j, n, v, bo, ro; long B, l, m; pari_timer ti; n = get_FpXQX_degree(S); v = get_FpXQX_var(S); if (n == 0) return cgetg(1, t_VEC); if (n == 1) return mkvec(get_FpXQX_mod(S)); B = n/2; l = usqrt(B); m = (B+l-1)/l; S = FpXQX_get_red(S, T, p); b = cgetg(l+2, t_VEC); gel(b, 1) = pol_x(v); gel(b, 2) = Xq; bo = brent_kung_optpow(n, l-1, 1); ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo); q = powiu(p, get_FpX_degree(T)); if (DEBUGLEVEL>=7) timer_start(&ti); if (expi(q) <= ro) for (i = 3; i <= l+1; i++) gel(b, i) = FpXQXQ_pow(gel(b, i-1), q, S, T, p); else { xq = FpXQXQ_powers(gel(b, 2), bo, S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq baby"); for (i = 3; i <= l+1; i++) gel(b, i) = FpXQX_FpXQXQV_eval(gel(b, i-1), xq, S, T, p); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: baby"); xq = FpXQXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq giant"); g = cgetg(m+1, t_VEC); gel(g, 1) = gel(xq, 2); for(i = 2; i <= m; i++) gel(g, i) = FpXQX_FpXQXQV_eval(gel(g, i-1), xq, S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: giant"); h = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { pari_sp av = avma; GEN gj = gel(g, j); GEN e = FpXX_sub(gj, gel(b, 1), p); for (i = 2; i <= l; i++) e = FpXQXQ_mul(e, FpXX_sub(gj, gel(b, i), p), S, T, p); gel(h, j) = gerepileupto(av, e); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: diff"); Sr = get_FpXQX_mod(S); F = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { GEN u = FpXQX_gcd(Sr, gel(h,j), T, p); if (degpol(u)) { u = FpXQX_normalize(u, T, p); Sr = FpXQX_div(Sr, u, T, p); } gel(F,j) = u; } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: F"); f = const_vec(n, pol_1(v)); for (j = 1; j <= m; j++) { GEN e = gel(F, j); for (i=l-1; i >= 0; i--) { GEN u = FpXQX_gcd(e, FpXX_sub(gel(g, j), gel(b, i+1), p), T, p); if (degpol(u)) { gel(f, l*j-i) = u = FpXQX_normalize(u, T, p); e = FpXQX_div(e, u, T, p); } if (!degpol(e)) break; } } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: f"); if (degpol(Sr)) gel(f, degpol(Sr)) = Sr; return gerepilecopy(av, f); } static GEN FpXQX_ddf_i(GEN f, GEN T, GEN p) { GEN Xq; if (!get_FpXQX_degree(f)) return cgetg(1,t_VEC); f = FpXQX_get_red(f, T, p); Xq = FpXQX_Frobenius(f, T, p); return FpXQX_ddf_Shoup(f, Xq, T, p); } static GEN FpXQX_ddf_raw(GEN f, GEN T, GEN p) { if (lgefint(p)==3) { ulong pp = p[2]; GEN M; long vT = get_FpX_var(T); if (pp==2) { M = F2xqX_ddf(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T))); return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2)); } M = FlxqX_ddf(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp); return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2)); } T = FpX_get_red(T, p); f = FpXQX_normalize(get_FpXQX_mod(f), T, p); return ddf_to_ddf2( FpXQX_ddf_i(f, T, p) ); } GEN FpXQX_ddf(GEN x, GEN T, GEN p) { pari_sp av = avma; return gerepilecopy(av, FpXQX_ddf_raw(x,T,p)); } static GEN FpXQX_degfact_raw(GEN f, GEN T, GEN p) { GEN V; long i,l; if (lgefint(p)==3) { ulong pp = p[2]; long vT = get_FpX_var(T); if (pp==2) return F2xqX_degfact(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T))); else return FlxqX_degfact(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp); } T = FpX_get_red(T, p); f = FpXQX_normalize(get_FpXQX_mod(f), T, p); V = FpXQX_factor_Yun(f, T, p); l = lg(V); for (i=1; i < l; i++) gel(V,i) = FpXQX_ddf_i(gel(V,i), T, p); return vddf_to_simplefact(V, degpol(f)); } GEN FpXQX_degfact(GEN x, GEN T, GEN p) { pari_sp av = avma; return gerepilecopy(av, FpXQX_degfact_raw(x,T,p)); } static void FpXQX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, GEN p, GEN V, long idx) { GEN Sp = get_FpXQX_mod(S); GEN u1, u2, f1, f2; GEN h; h = FpXQX_get_red(hp, T, p); t = FpXQX_rem(t, S, T, p); Xp = FpXQX_rem(Xp, h, T, p); u1 = FpXQX_roots_split(hp, xp, Xp, h, T, p); f1 = FpXQX_gcd(FpXQX_FpXQXQ_eval(u1, t, S, T, p), Sp, T, p); f1 = FpXQX_normalize(f1, T, p); u2 = FpXQX_div(hp, u1, T, p); f2 = FpXQX_div(Sp, f1, T, p); if (degpol(u1)==1) gel(V, idx) = f1; else FpXQX_edf_rec(FpXQX_get_red(f1, T, p), xp, Xp, u1, t, d, T, p, V, idx); idx += degpol(f1)/d; if (degpol(u2)==1) gel(V, idx) = f2; else FpXQX_edf_rec(FpXQX_get_red(f2, T, p), xp, Xp, u2, t, d, T, p, V, idx); } static void FpXQX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx) { long n = degpol(Sp), r = n/d, vS = varn(Sp); GEN S, h, t; pari_timer ti; if (r==1) { gel(V, idx) = Sp; return; } S = FpXQX_get_red(Sp, T, p); Xp = FpXQX_rem(Xp, S, T, p); Xq = FpXQX_rem(Xq, S, T, p); if (DEBUGLEVEL>=7) timer_start(&ti); do { GEN g = random_FpXQX(n, vS, T, p); t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_auttrace"); h = FpXQXQ_minpoly(t, S, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_minpoly"); } while (degpol(h) != r); Xp = FpXQXQ_pow(pol_x(vS), p, h, T, p); FpXQX_edf_rec(S, xp, Xp, h, t, d, T, p, V, idx); } static void FpXQX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx) { long v = varn(Sp), n = degpol(Sp), r = n/d; GEN S, f, ff; long vT = get_FpX_var(T), dT = get_FpX_degree(T); if (r==1) { gel(V, idx) = Sp; return; } S = FpXQX_get_red(Sp, T, p); Xp = FpXQX_rem(Xp, S, T, p); Xq = FpXQX_rem(Xq, S, T, p); while (1) { pari_sp btop = avma; long i; GEN g = random_FpXQX(n, v, T, p); GEN t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2); if (lgpol(t) == 0) continue; for(i=1; i<=10; i++) { pari_sp btop2 = avma; GEN r = random_FpX(dT, vT, p); GEN R = FpXQXQ_halfFrobenius_i(FqX_Fq_add(t, r, T, p), xp, Xp, S, T, p); f = FpXQX_gcd(FqX_Fq_add(R, gen_m1, T, p), Sp, T, p); if (degpol(f) > 0 && degpol(f) < n) break; avma = btop2; } if (degpol(f) > 0 && degpol(f) < n) break; avma = btop; } f = FpXQX_normalize(f, T, p); ff = FpXQX_div(Sp, f , T, p); FpXQX_edf_simple(f, xp, Xp, Xq, d, T, p, V, idx); FpXQX_edf_simple(ff, xp, Xp, Xq, d, T, p, V, idx+degpol(f)/d); } static GEN FpXQX_factor_Shoup(GEN S, GEN xp, GEN T, GEN p) { long i, n, s = 0, dT = get_FpX_degree(T), e = expi(powiu(p, dT)); GEN X, Xp, Xq, D, V; pari_timer ti; n = get_FpXQX_degree(S); S = FpXQX_get_red(S, T, p); if (DEBUGLEVEL>=6) timer_start(&ti); X = pol_x(get_FpXQX_var(S)); Xp = FpXQXQ_pow(X, p, S, T, p); Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_Frobenius"); D = FpXQX_ddf_Shoup(S, Xq, T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_ddf_Shoup"); s = ddf_to_nbfact(D); V = cgetg(s+1, t_COL); for (i = 1, s = 1; i <= n; i++) { GEN Di = gel(D,i); long ni = degpol(Di), ri = ni/i; if (ni == 0) continue; Di = FpXQX_normalize(Di, T, p); if (ni == i) { gel(V, s++) = Di; continue; } if (ri <= e*expu(e)) FpXQX_edf(Di, xp, Xp, Xq, i, T, p, V, s); else FpXQX_edf_simple(Di, xp, Xp, Xq, i, T, p, V, s); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_edf(%ld)",i); s += ri; } return V; } static GEN FpXQX_factor_Cantor(GEN f, GEN T, GEN p) { GEN xp, E, F, V; long i, j, l; T = FpX_get_red(T, p); f = FpXQX_normalize(f, T, p); switch(degpol(f)) { case -1: retmkmat2(mkcol(f), mkvecsmall(1)); case 0: return trivial_fact(); case 1: retmkmat2(mkcol(f), mkvecsmall(1)); case 2: return FpXQX_factor_2(f, T, p); } if (isabsolutepol(f)) return FpX_factorff_i(simplify_shallow(f), T, p); xp = FpX_Frobenius(T, p); V = FpXQX_factor_Yun(f, T, p); l = lg(V); F = cgetg(l, t_VEC); E = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (degpol(gel(V,i))) { GEN Fj = FpXQX_factor_Shoup(gel(V,i), xp, T, p); gel(E,j) = const_vecsmall(lg(Fj)-1, i); gel(F,j) = Fj; j++; } return sort_factor_pol(FE_concat(F,E,j), cmp_RgX); } long FpXQX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, GEN p) { pari_sp av = avma; GEN u = get_FpXQX_mod(S); long s; if (lgefint(p)==3) { ulong pp = p[2]; long vT = get_FpX_var(T); GEN Sp = ZXXT_to_FlxXT(S,pp,vT), Xqp = ZXX_to_FlxX(Xq,pp,vT); s = FlxqX_nbfact_Frobenius(Sp, Xqp, ZXT_to_FlxT(T,pp), pp); } else if (isabsolutepol(u)) s = FpX_nbfactff(simplify_shallow(u), T, p); else s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, Xq, T, p)); avma = av; return s; } long FpXQX_nbfact(GEN S, GEN T, GEN p) { pari_sp av = avma; GEN u = get_FpXQX_mod(S); long s; if (lgefint(p)==3) { ulong pp = p[2]; long vT = get_FpX_var(T); s = FlxqX_nbfact(ZXXT_to_FlxXT(S,pp,vT), ZXT_to_FlxT(T,pp), pp); } else if (isabsolutepol(u)) s = FpX_nbfactff(simplify_shallow(u), T, p); else s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, FpXQX_Frobenius(S, T, p), T, p)); avma = av; return s; } long FqX_nbfact(GEN u, GEN T, GEN p) { return T ? FpXQX_nbfact(u, T, p): FpX_nbfact(u, p); } static GEN FpXQX_factor_Berlekamp_i(GEN f, GEN T, GEN p) { if (lgefint(p)==3) { ulong pp = p[2]; GEN M; long vT = get_FpX_var(T); if (pp==2) { M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T))); return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2)); } M = FlxqX_Berlekamp_i(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp); return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2)); } return FpXQX_Berlekamp_i(f, T, p); } GEN FpXQX_factor_Berlekamp(GEN x, GEN T, GEN p) { pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_Berlekamp_i(x,T,p)); } static GEN FpXQX_factor_i(GEN f, GEN T, GEN p) { if (lgefint(p)==3) { ulong pp = p[2]; GEN M; long vT = get_FpX_var(T); if (pp==2) { M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T))); return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2)); } M = FlxqX_factor_Cantor(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp); return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2)); } return FpXQX_factor_Cantor(f, T, p); } GEN FpXQX_factor(GEN x, GEN T, GEN p) { pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_i(x,T,p)); } long FlxqX_is_squarefree(GEN P, GEN T, ulong p) { pari_sp av = avma; GEN z = FlxqX_gcd(P, FlxX_deriv(P, p), T, p); avma = av; return degpol(z)==0; } long FqX_is_squarefree(GEN P, GEN T, GEN p) { pari_sp av = avma; GEN z = FqX_gcd(P, FqX_deriv(P, T, p), T, p); avma = av; return degpol(z)==0; } /* as RgX_to_FpXQ(FqX_to_FFX), leaving alone t_FFELT */ static GEN RgX_to_FFX(GEN x, GEN ff) { long i, lx; GEN p = FF_p_i(ff), T = FF_mod(ff), y = cgetg_copy(x,&lx); y[1] = x[1]; if (degpol(T) == 1) T = NULL; for (i = 2; i < lx; i++) { GEN c = gel(x,i); gel(y,i) = typ(c) == t_FFELT? c: Fq_to_FF(Rg_to_Fq(c,T,p), ff); } return y; } #define code(t1,t2) ((t1 << 6) | t2) /* Check types and replace F by a monic normalized FpX having the same roots * Don't bother to make constant polynomials monic */ static GEN factmod_init(GEN f, GEN *pD, GEN *pT, GEN *pp) { const char *s = "factormod"; GEN T = NULL, p = NULL, D = *pD; if (typ(f) != t_POL) pari_err_TYPE(s,f); if (!D) { long pa, t = RgX_type(f, pp, pT, &pa); if (t == t_FFELT) return f; *pD = gen_0; if (t != t_INTMOD && t != code(t_POLMOD,t_INTMOD)) pari_err_TYPE(s,f); return RgX_to_FqX(f, *pT, *pp); } switch(typ(D)) { case t_INT: p = D; break; case t_FFELT: { *pD = NULL; *pT = D; return RgX_to_FFX(f,D); } case t_VEC: if (lg(D) == 3) { p = gel(D,1); T = gel(D,2); if (typ(p) == t_INT) break; if (typ(T) == t_INT) { swap(T,p); break; } } default: pari_err_TYPE(s,D); } if (signe(p) <= 0) pari_err_PRIME(s,p); if (T) { if (typ(T) != t_POL) pari_err_TYPE(s,p); T = RgX_to_FpX(T,p); if (varncmp(varn(T), varn(f)) <= 0) pari_err_PRIORITY(s, T, "<=", varn(f)); } *pT = T; *pp = p; return RgX_to_FqX(f, T, p); } #undef code static GEN to_Fq(GEN x, GEN T, GEN p) { long i, lx, tx = typ(x); GEN y; if (tx == t_INT) y = mkintmod(x,p); else { if (tx != t_POL) pari_err_TYPE("to_Fq",x); y = cgetg_copy(x,&lx); y[1] = x[1]; for (i=2; i 0; j--) for (i = h-1; i > 0; i--) if (typ(gcoeff(x,i,j)) != t_INT) return 0; return 1; } int RgM_is_QM(GEN x) { long i, j, h, l = lg(x); if (l == 1) return 1; h = lgcols(x); if (h == 1) return 1; for (j = l-1; j > 0; j--) for (i = h-1; i > 0; i--) if (!is_rational_t(typ(gcoeff(x,i,j)))) return 0; return 1; } int RgV_is_ZMV(GEN V) { long i, l = lg(V); for (i=1; i 0). */ static GEN RgM_zc_mul_i(GEN x, GEN y, long c, long l) { GEN z = cgetg(l,t_COL); long i; for (i = 1; i < l; i++) gel(z,i) = RgMrow_zc_mul_i(x,y,c,i); return z; } GEN RgM_zc_mul(GEN x, GEN y) { return RgM_zc_mul_i(x,y, lg(x), lgcols(x)); } /* x t_MAT, y a compatible zm (dimension > 0). */ GEN RgM_zm_mul(GEN x, GEN y) { long j, c, l = lg(x), ly = lg(y); GEN z = cgetg(ly, t_MAT); if (l == 1) return z; c = lgcols(x); for (j = 1; j < ly; j++) gel(z,j) = RgM_zc_mul_i(x, gel(y,j), l,c); return z; } static GEN RgV_zc_mul_i(GEN x, GEN y, long l) { long i; GEN z = gen_0; pari_sp av = avma; for (i = 1; i < l; i++) z = gadd(z, gmulgs(gel(x,i), y[i])); return gerepileupto(av, z); } GEN RgV_zc_mul(GEN x, GEN y) { return RgV_zc_mul_i(x, y, lg(x)); } GEN RgV_zm_mul(GEN x, GEN y) { long j, l = lg(x), ly = lg(y); GEN z = cgetg(ly, t_VEC); for (j = 1; j < ly; j++) gel(z,j) = RgV_zc_mul_i(x, gel(y,j), l); return z; } /* scalar product x.x */ GEN RgV_dotsquare(GEN x) { long i, lx = lg(x); pari_sp av = avma; GEN z; if (lx == 1) return gen_0; z = gsqr(gel(x,1)); for (i=2; i1) pari_warn(warnmem,"RgV_dotsquare, i = %ld",i); z = gerepileupto(av, z); } } return gerepileupto(av,z); } /* scalar product x.y, lx = lg(x) = lg(y) */ static GEN RgV_dotproduct_i(GEN x, GEN y, long lx) { pari_sp av = avma; long i; GEN z; if (lx == 1) return gen_0; z = gmul(gel(x,1),gel(y,1)); for (i=2; i1) pari_warn(warnmem,"RgV_dotproduct, i = %ld",i); z = gerepileupto(av, z); } } return gerepileupto(av,z); } GEN RgV_dotproduct(GEN x,GEN y) { if (x == y) return RgV_dotsquare(x); return RgV_dotproduct_i(x, y, lg(x)); } /* v[1] + ... + v[lg(v)-1] */ GEN RgV_sum(GEN v) { GEN p; long i, l = lg(v); if (l == 1) return gen_0; p = gel(v,1); for (i=2; i n. */ GEN RgV_sumpart(GEN v, long n) { GEN p; long i; if (!n) return gen_0; p = gel(v,1); for (i=2; i<=n; i++) p = gadd(p, gel(v,i)); return p; } /* v[m] + ... + v[n]. Assume lg(v) > n, m > 0. */ GEN RgV_sumpart2(GEN v, long m, long n) { GEN p; long i; if (n < m) return gen_0; p = gel(v,m); for (i=m+1; i<=n; i++) p = gadd(p, gel(v,i)); return p; } GEN RgM_sumcol(GEN A) { long i,j,m,l = lg(A); GEN v; if (l == 1) return cgetg(1,t_MAT); if (l == 2) return gcopy(gel(A,1)); m = lgcols(A); v = cgetg(m, t_COL); for (i = 1; i < m; i++) { pari_sp av = avma; GEN s = gcoeff(A,i,1); for (j = 2; j < l; j++) s = gadd(s, gcoeff(A,i,j)); gel(v, i) = gerepileupto(av, s); } return v; } static GEN _gmul(void *data, GEN x, GEN y) { (void)data; return gmul(x,y); } GEN RgV_prod(GEN x) { return gen_product(x, NULL, _gmul); } /* ADDITION SCALAR + MATRIX */ /* x square matrix, y scalar; create the square matrix x + y*Id */ GEN RgM_Rg_add(GEN x, GEN y) { long l = lg(x), i, j; GEN z = cgetg(l,t_MAT); if (l==1) return z; if (l != lgcols(x)) pari_err_OP( "+", x, y); z = cgetg(l,t_MAT); for (i=1; i 1 */ static GEN RgMrow_RgC_mul_i(GEN x, GEN y, long i, long l) { pari_sp av = avma; GEN t = gmul(gcoeff(x,i,1), gel(y,1)); /* l > 1 ! */ long j; for (j=2; j 1, l = lgcols(x) */ static GEN RgM_RgC_mul_i(GEN x, GEN y, long lx, long l) { GEN z = cgetg(l,t_COL); long i; for (i=1; i1 ? lg(gel(x,1))-1:0; return gen_bkeval_powers(Q,degpol(Q),x,(void*)&n,&RgM_algebra,&_RgM_cmul); } GEN RgX_RgM_eval(GEN Q, GEN x) { long n = lg(x)-1; return gen_bkeval(Q,degpol(Q),x,1,(void*)&n,&RgM_algebra,&_RgM_cmul); } GEN RgC_Rg_div(GEN x, GEN y) { pari_APPLY_type(t_COL, gdiv(gel(x,i),y)) } GEN RgC_Rg_mul(GEN x, GEN y) { pari_APPLY_type(t_COL, gmul(gel(x,i),y)) } GEN RgV_Rg_mul(GEN x, GEN y) { pari_APPLY_type(t_VEC, gmul(gel(x,i),y)) } GEN RgM_Rg_div(GEN X, GEN c) { long i, j, h, l = lg(X); GEN A = cgetg(l, t_MAT); if (l == 1) return A; h = lgcols(X); for (j=1; jpp[i] divides n, and lasta = a_{n/p}. * Call fun(E, N, a_N), for all N, n | N, P^+(N) <= p, a_N != 0, * i.e. assumes that fun accumulates a_N * w(N) */ static void gen_BG_add(void *E, bg_fun *fun, struct bg_data *bg, GEN n, long i, GEN a, GEN lasta) { pari_sp av = avma; long j; ulong nn = itou_or_0(n); if (nn && nn <= bg->rootbnd) bg->an[nn] = itos(a); if (signe(a)) { fun(E, n, a); j = 1; } else j = i; for(; j <= i; j++) { ulong p = bg->p[j]; GEN nexta, pn = mului(p, n); if (cmpii(pn, bg->bnd) > 0) return; nexta = mulis(a, bg->an[p]); if (i == j && umodiu(bg->N, p)) nexta = subii(nexta, mului(p, lasta)); gen_BG_add(E, fun, bg, pn, j, nexta, a); avma = av; } } static void gen_BG_init(struct bg_data *bg, GEN E, GEN N, GEN bnd) { bg->E = E; bg->N = N; bg->bnd = bnd; bg->rootbnd = itou(sqrtint(bnd)); bg->p = primes_upto_zv(bg->rootbnd); bg->an = ellanQ_zv(E, bg->rootbnd); } static void gen_BG_rec(void *E, bg_fun *fun, struct bg_data *bg) { long i, j, lp = lg(bg->p)-1; GEN bndov2 = shifti(bg->bnd, -1); pari_sp av = avma, av2; GEN p; forprime_t S; (void)forprime_init(&S, utoipos(bg->p[lp]+1), bg->bnd); av2 = avma; if (DEBUGLEVEL) err_printf("1st stage, using recursion for p <= %ld\n", bg->p[lp]); for (i = 1; i <= lp; i++) { ulong pp = bg->p[i]; long ap = bg->an[pp]; gen_BG_add(E, fun, bg, utoipos(pp), i, stoi(ap), gen_1); avma = av2; } if (DEBUGLEVEL) err_printf("2nd stage, looping for p <= %Ps\n", bndov2); while ( (p = forprime_next(&S)) ) { long jmax; GEN ap = ellap(bg->E, p); pari_sp av3 = avma; if (!signe(ap)) continue; jmax = itou( divii(bg->bnd, p) ); /* 2 <= jmax <= el->rootbound */ fun(E, p, ap); for (j = 2; j <= jmax; j++) { long aj = bg->an[j]; GEN a, n; if (!aj) continue; a = mulis(ap, aj); n = muliu(p, j); fun(E, n, a); avma = av3; } avma = av2; if (abscmpii(p, bndov2) >= 0) break; } if (DEBUGLEVEL) err_printf("3nd stage, looping for p <= %Ps\n", bg->bnd); while ( (p = forprime_next(&S)) ) { GEN ap = ellap(bg->E, p); if (!signe(ap)) continue; fun(E, p, ap); avma = av2; } avma = av; } /****************************************************************** * * L functions of elliptic curves * Pascal Molin (molin.maths@gmail.com) 2014 * ******************************************************************/ struct lcritical { GEN h; /* real */ long cprec; /* computation prec */ long L; /* number of points */ GEN K; /* length of series */ long real; }; static double logboundG0(long e, double aY) { double cla, loggam; cla = 1 + 1/sqrt(aY); if (e) cla = ( cla + 1/(2*aY) ) / (2*sqrt(aY)); loggam = (e) ? M_LN2-aY : -aY + log( log( 1+1/aY) ); return log(cla) + loggam; } static void param_points(GEN N, double Y, double tmax, long bprec, long *cprec, long *L, GEN *K, double *h) { double D, a, aY, X, logM; long d = 2, w = 1; tmax *= d; D = bprec * M_LN2 + M_PI/4*tmax + 2; *cprec = nbits2prec(ceil(D / M_LN2) + 5); a = 2 * M_PI / sqrt(gtodouble(N)); aY = a * cos(M_PI/2*Y); logM = 2*M_LN2 + logboundG0(w+1, aY) + tmax * Y * M_PI/2; *h = ( 2 * M_PI * M_PI / 2 * Y ) / ( D + logM ); X = log( D / a); *L = ceil( X / *h); *K = ceil_safe(dbltor( D / a )); } static GEN vecF2_lk(GEN E, GEN K, GEN rbnd, GEN Q, GEN sleh, long prec) { pari_sp av = avma, av2; long l, L = lg(K)-1; GEN a = ellanQ_zv(E, itos(gel(K,1))); GEN S = cgetg(L+1, t_VEC); for (l = 1; l <= L; l++) gel(S,l) = cgetr(prec); av2 = avma; for (l = 1; l <= L; ++l) { GEN e1, Sl; long aB, b, A, B; GEN z, zB; pari_sp av3; long Kl = itou(gel(K,l)); /* FIXME: could reduce prec here (useful for large prec) */ e1 = gel(Q, l); Sl = real_0(prec);; /* baby-step giant step */ A = rbnd[l]; B = A; z = powersr(e1, B); zB = gel(z, B+1); av3 = avma; for (aB = A*B; aB >= 0; aB -= B) { GEN s = real_0(prec); /* could change also prec here */ for (b = B; b > 0; --b) { long k = aB+b; if (k <= Kl && a[k]) s = addrr(s, mulsr(a[k], gel(z, b+1))); if (gc_needed(av3, 1)) gerepileall(av3, 2, &s, &Sl); } Sl = addrr(mulrr(Sl, zB), s); } affrr(mulrr(Sl, gel(sleh,l)), gel(S, l)); /* to avoid copying all S */ avma = av2; } return gerepilecopy(av, S); } /* Return C, C[i][j] = Q[j]^i, i = 1..nb */ static void baby_init(struct baby_giant *bb, GEN Q, GEN bnd, GEN rbnd, long prec) { long i, j, l = lg(Q); GEN R, C, r0; C = cgetg(l,t_VEC); for (i = 1; i < l; ++i) gel(C, i) = powersr(gel(Q, i), rbnd[i]); R = cgetg(l,t_VEC); r0 = real_0(prec); for (i = 1; i < l; ++i) { gel(R, i) = cgetg(rbnd[i]+1, t_VEC); gmael(R, i, 1) = cgetr(prec); affrr(gmael(C, i, 2),gmael(R, i, 1)); for (j = 2; j <= rbnd[i]; j++) { gmael(R, i, j) = cgetr(prec); affrr(r0, gmael(R, i, j)); } } bb->baby = C; bb->giant = R; bb->bnd = bnd; bb->rbnd = rbnd; } static long baby_size(GEN rbnd, long Ks, long prec) { long i, s, m, l = lg(rbnd); for (s = 0, i = 1; i < l; ++i) s += rbnd[i]; m = 2*s*prec + 3*l + s; if (DEBUGLEVEL) err_printf("ellL1: BG_add: %ld words, ellan: %ld words\n", m, Ks); return m; } static void ellL1_add(void *E, GEN n, GEN a) { pari_sp av = avma; struct baby_giant *bb = (struct baby_giant*) E; long j, l = lg(bb->giant); for (j = 1; j < l; j++) if (cmpii(n, gel(bb->bnd,j)) <= 0) { ulong r, q = uabsdiviu_rem(n, bb->rbnd[j], &r); GEN giant = gel(bb->giant, j), baby = gel(bb->baby, j); affrr(addrr(gel(giant, q+1), mulri(gel(baby, r+1), a)), gel(giant, q+1)); avma = av; } else break; } static GEN vecF2_lk_bsgs(GEN E, GEN bnd, GEN rbnd, GEN Q, GEN sleh, GEN N, long prec) { pari_sp av = avma; struct bg_data bg; struct baby_giant bb; long k, L = lg(bnd)-1; GEN S; baby_init(&bb, Q, bnd, rbnd, prec); gen_BG_init(&bg, E, N, gel(bnd,1)); gen_BG_rec((void*) &bb, ellL1_add, &bg); S = cgetg(L+1, t_VEC); for (k = 1; k <= L; ++k) { pari_sp av2 = avma; long j, g = rbnd[k]; GEN giant = gmael(bb.baby, k, g+1); GEN Sl = real_0(prec); for (j = g; j >=1; j--) Sl = addrr(mulrr(Sl, giant), gmael(bb.giant,k,j)); gel(S, k) = gerepileupto(av2, mulrr(gel(sleh,k), Sl)); } return gerepileupto(av, S); } static GEN vecF(struct lcritical *C, GEN E) { pari_sp av = avma, av2; long prec = C->cprec, Ks = itos_or_0(C->K), l, L = C->L; GEN N = ellQ_get_N(E); GEN PiN = shiftr(divrr(mppi(prec), gsqrt(N, prec)), 1); GEN eh = mpexp(C->h), elh = powersr(eh, L-1), sleh = elh; GEN Q, bnd, rbnd, vec; rbnd = cgetg(L+1, t_VECSMALL); av2 = avma; bnd = cgetg(L+1, t_VEC); Q = cgetg(L+1, t_VEC); for (l = 1; l <= L; ++l) { gel(bnd,l) = l==1 ? C->K: ceil_safe(divir(C->K, gel(elh, l))); rbnd[l] = itou(sqrtint(gel(bnd,l)))+1; gel(Q, l) = mpexp(mulrr(negr(PiN), gel(elh, l))); } gerepileall(av2, 2, &bnd, &Q); if (Ks && baby_size(rbnd, Ks, prec) > (Ks>>1)) vec = vecF2_lk(E, bnd, rbnd, Q, sleh, prec); else vec = vecF2_lk_bsgs(E, bnd, rbnd, Q, sleh, N, prec); return gerepileupto(av, vec); } /* ************************************************************************ * * Compute Lambda function by Fourier inversion * */ static GEN glambda(GEN t, GEN vec, GEN h, long real, long prec) { GEN ehs, elhs; GEN r; long L = lg(vec)-1, l; /* assume vec is a grid */ ehs = gexp(gmul(gen_I(),gmul(h, t)), prec); elhs = (real == 1) ? gen_1 : mkcomplex(gen_0, gen_m1); r = gmul2n(real_i(gmul(real_i(gel(vec, 1)), elhs)), -1); /* FIXME: summing backward may be more stable */ for (l = 2; l <= L; ++l) { elhs = gmul(elhs, ehs); r = gadd(r, real_i(gmul(gel(vec, l), elhs))); } return gmul(mulsr(4, h), r); } static GEN Lpoints(struct lcritical *C, GEN e, GEN tmax, long bprec) { double h = 0, Y = .97; GEN N = ellQ_get_N(e); param_points(N, Y, gtodouble(tmax), bprec, &C->cprec, &C->L, &C->K, &h); C->real = ellrootno_global(e); C->h = rtor(dbltor(h), C->cprec); return vecF(C, e); } static GEN Llambda(GEN vec, struct lcritical *C, GEN t, long prec) { GEN lambda = glambda(gprec_w(t, C->cprec), vec, C->h, C->real, C->cprec); return gprec_w(lambda, prec); } /* 2*(2*Pi)^(-s)*gamma(s)*N^(s/2); */ static GEN ellgammafactor(GEN N, GEN s, long prec) { GEN c = gpow(divrr(gsqrt(N,prec), Pi2n(1,prec)), s, prec); return gmul(gmul2n(c,1), ggamma(s, prec)); } static GEN ellL1_eval(GEN e, GEN vec, struct lcritical *C, GEN t, long prec) { GEN g = ellgammafactor(ellQ_get_N(e), gaddgs(gmul(gen_I(),t), 1), prec); return gdiv(Llambda(vec, C, t, prec), g); } static GEN ellL1_der(GEN e, GEN vec, struct lcritical *C, GEN t, long der, long prec) { GEN r = polcoeff0(ellL1_eval(e, vec, C, t, prec), der, 0); r = gmul(r,powIs(C->real == 1 ? -der: 1-der)); return gmul(real_i(r), mpfact(der)); } GEN ellL1_bitprec(GEN E, long r, long bitprec) { pari_sp av = avma; struct lcritical C; long prec = nbits2prec(bitprec); GEN e, vec, t; if (r < 0) pari_err_DOMAIN("ellL1", "derivative order", "<", gen_0, stoi(r)); e = ellanal_globalred(E, NULL); if (r == 0 && ellrootno_global(e) < 0) { avma = av; return gen_0; } vec = Lpoints(&C, e, gen_0, bitprec); t = r ? scalarser(gen_1, 0, r): zeroser(0, 0); setvalp(t, 1); return gerepileupto(av, ellL1_der(e, vec, &C, t, r, prec)); } GEN ellL1(GEN E, long r, long prec) { return ellL1_bitprec(E, r, prec2nbits(prec)); } GEN ellanalyticrank_bitprec(GEN E, GEN eps, long bitprec) { pari_sp av = avma, av2; long prec = nbits2prec(bitprec); struct lcritical C; pari_timer ti; GEN e, vec; long rk; if (DEBUGLEVEL) timer_start(&ti); if (!eps) eps = real2n(-bitprec/2+1, DEFAULTPREC); else if (typ(eps) != t_REAL) { eps = gtofp(eps, DEFAULTPREC); if (typ(eps) != t_REAL) pari_err_TYPE("ellanalyticrank", eps); } e = ellanal_globalred(E, NULL); vec = Lpoints(&C, e, gen_0, bitprec); if (DEBUGLEVEL) timer_printf(&ti, "init L"); av2 = avma; for (rk = C.real>0 ? 0: 1; ; rk += 2) { GEN Lrk; GEN t = rk ? scalarser(gen_1, 0, rk): zeroser(0, 0); setvalp(t, 1); Lrk = ellL1_der(e, vec, &C, t, rk, prec); if (DEBUGLEVEL) timer_printf(&ti, "L^(%ld)=%Ps", rk, Lrk); if (abscmprr(Lrk, eps) > 0) return gerepilecopy(av, mkvec2(stoi(rk), Lrk)); avma = av2; } } GEN ellanalyticrank(GEN E, GEN eps, long prec) { return ellanalyticrank_bitprec(E, eps, prec2nbits(prec)); } /* Heegner point computation This section is a C version by Bill Allombert of a GP script by Christophe Delaunay which was based on a GP script by John Cremona. Reference: Henri Cohen's book GTM 239. */ static void heegner_L1_bg(void*E, GEN n, GEN a) { struct baby_giant *bb = (struct baby_giant*) E; long j, l = lg(bb->giant); for (j = 1; j < l; j++) if (cmpii(n, gel(bb->bnd,j)) <= 0) { ulong r, q = uabsdiviu_rem(n, bb->rbnd[j], &r); GEN giant = gel(bb->giant, j), baby = gel(bb->baby, j); gaffect(gadd(gel(giant, q+1), gdiv(gmul(gel(baby, r+1), a), n)), gel(giant, q+1)); } } static void heegner_L1(void*E, GEN n, GEN a) { struct baby_giant *bb = (struct baby_giant*) E; long j, l = lg(bb->giant); for (j = 1; j < l; j++) if (cmpii(n, gel(bb->bnd,j)) <= 0) { ulong r, q = uabsdiviu_rem(n, bb->rbnd[j], &r); GEN giant = gel(bb->giant, j), baby = gel(bb->baby, j); GEN ex = mulreal(gel(baby, r+1), gel(giant, q+1)); affrr(addrr(gel(bb->sum, j), divri(mulri(ex, a), n)), gel(bb->sum, j)); } } /* Return C, C[i][j] = Q[j]^i, i = 1..nb */ static void baby_init2(struct baby_giant *bb, GEN Q, GEN bnd, GEN rbnd, long prec) { long i, j, l = lg(Q); GEN R, C, r0; C = cgetg(l,t_VEC); for (i = 1; i < l; ++i) gel(C, i) = gpowers(gel(Q, i), rbnd[i]); R = cgetg(l,t_VEC); r0 = mkcomplex(real_0(prec),real_0(prec)); for (i = 1; i < l; ++i) { gel(R, i) = cgetg(rbnd[i]+1, t_VEC); gmael(R, i, 1) = cgetc(prec); gaffect(gmael(C, i, 2),gmael(R, i, 1)); for (j = 2; j <= rbnd[i]; j++) { gmael(R, i, j) = cgetc(prec); gaffect(r0, gmael(R, i, j)); } } bb->baby = C; bb->giant = R; bb->bnd = bnd; bb->rbnd = rbnd; } /* Return C, C[i][j] = Q[j]^i, i = 1..nb */ static void baby_init3(struct baby_giant *bb, GEN Q, GEN bnd, GEN rbnd, long prec) { long i, l = lg(Q); GEN R, C, S; C = cgetg(l,t_VEC); for (i = 1; i < l; ++i) gel(C, i) = gpowers(gel(Q, i), rbnd[i]); R = cgetg(l,t_VEC); for (i = 1; i < l; ++i) gel(R, i) = gpowers(gmael(C, i, 1+rbnd[i]), rbnd[i]); S = cgetg(l,t_VEC); for (i = 1; i < l; ++i) { gel(S, i) = cgetr(prec); affrr(real_i(gmael(C, i, 2)), gel(S, i)); } bb->baby = C; bb->giant = R; bb->sum = S; bb->bnd = bnd; bb->rbnd = rbnd; } /* ymin a t_REAL */ static GEN heegner_psi(GEN E, GEN N, GEN points, long bitprec) { pari_sp av = avma, av2; struct baby_giant bb; struct bg_data bg; long k, L = lg(points)-1, prec = nbits2prec(bitprec)+EXTRAPRECWORD; GEN Q, pi2 = Pi2n(1, prec), bnd, rbnd; long l; GEN B = divrr(mulur(bitprec,mplog2(DEFAULTPREC)), pi2); GEN bndmax; rbnd = cgetg(L+1, t_VECSMALL); av2 = avma; bnd = cgetg(L+1, t_VEC); Q = cgetg(L+1, t_VEC); for (l = 1; l <= L; ++l) { gel(bnd,l) = ceil_safe(divrr(B,imag_i(gel(points, l)))); rbnd[l] = itou(sqrtint(gel(bnd,l)))+1; gel(Q, l) = expIxy(pi2, gel(points, l), prec); } gerepileall(av2, 2, &bnd, &Q); bndmax = gel(bnd,vecindexmax(bnd)); gen_BG_init(&bg, E, N, bndmax); if (bitprec >= 1900) { GEN S; baby_init2(&bb, Q, bnd, rbnd, prec); gen_BG_rec((void*)&bb, heegner_L1_bg, &bg); S = cgetg(L+1, t_VEC); for (k = 1; k <= L; ++k) { pari_sp av2 = avma; long j, g = rbnd[k]; GEN giant = gmael(bb.baby, k, g+1); GEN Sl = real_0(prec); for (j = g; j >=1; j--) Sl = gadd(gmul(Sl, giant), gmael(bb.giant,k,j)); gel(S, k) = gerepileupto(av2, real_i(Sl)); } return gerepileupto(av, S); } else { baby_init3(&bb, Q, bnd, rbnd, prec); gen_BG_rec((void*)&bb, heegner_L1, &bg); return gerepilecopy(av, bb.sum); } } /*Returns lambda_bad list for one prime p, nv = localred(E, p) */ static GEN lambda1(GEN E, GEN nv, GEN p, long prec) { pari_sp av; GEN res, lp; long kod = itos(gel(nv, 2)); if (kod==2 || kod ==-2) return cgetg(1,t_VEC); av = avma; lp = glog(p, prec); if (kod > 4) { long n = Z_pval(ell_get_disc(E), p); long j, m = kod - 4, nl = 1 + (m >> 1L); res = cgetg(nl, t_VEC); for (j = 1; j < nl; j++) gel(res, j) = gmul(lp, gsubgs(gdivgs(sqru(j), n), j)); /* j^2/n - j */ } else if (kod < -4) res = mkvec2(negr(lp), shiftr(mulrs(lp, kod), -2)); else { const long lam[] = {8,9,0,6,0,0,0,3,4}; long m = -lam[kod+4]; res = mkvec(divru(mulrs(lp, m), 6)); } return gerepilecopy(av, res); } static GEN lambdalist(GEN E, long prec) { pari_sp ltop = avma; GEN glob = ellglobalred(E), plist = gmael(glob,4,1), L = gel(glob,5); GEN res, v, D = ell_get_disc(E); long i, j, k, l, m, n, np = lg(plist), lr = 1; v = cgetg(np, t_VEC); for (j = 1, i = 1 ; j < np; ++j) { GEN p = gel(plist, j); if (dvdii(D, sqri(p))) { GEN la = lambda1(E, gel(L,j), p, prec); gel(v, i++) = la; lr *= lg(la); } } np = i; res = cgetg(lr+1, t_VEC); gel(res, 1) = gen_0; n = 1; m = 1; for (j = 1; j < np; ++j) { GEN w = gel(v, j); long lw = lg(w); for (k = 1; k <= n; k++) { GEN t = gel(res, k); for (l = 1, m = n; l < lw; l++, m+=n) gel(res, k + m) = mpadd(t, gel(w, l)); } n = m; } return gerepilecopy(ltop, res); } /* P a t_INT or t_FRAC, return its logarithmic height */ static GEN heightQ(GEN P, long prec) { long s; if (typ(P) == t_FRAC) { GEN a = gel(P,1), b = gel(P,2); P = abscmpii(a,b) > 0 ? a: b; } s = signe(P); if (!s) return real_0(prec); if (s < 0) P = negi(P); return glog(P, prec); } /* t a t_INT or t_FRAC, returns max(1, log |t|), returns a t_REAL */ static GEN logplusQ(GEN t, long prec) { if (typ(t) == t_INT) { if (!signe(t)) return real_1(prec); if (signe(t) < 0) t = negi(t); } else { GEN a = gel(t,1), b = gel(t,2); if (abscmpii(a, b) < 0) return real_1(prec); if (signe(a) < 0) t = gneg(t); } return glog(t, prec); } /* See GTM239, p532, Th 8.1.18 * Return M such that h_naive <= M */ static GEN hnaive_max(GEN ell, GEN ht) { const long prec = LOWDEFAULTPREC; /* minimal accuracy */ GEN b2 = ell_get_b2(ell), j = ell_get_j(ell); GEN logd = glog(absi_shallow(ell_get_disc(ell)), prec); GEN logj = logplusQ(j, prec); GEN hj = heightQ(j, prec); GEN logb2p = signe(b2)? addrr(logplusQ(gdivgs(b2, 12),prec), mplog2(prec)) : real_1(prec); GEN mu = addrr(divru(addrr(logd, logj),6), logb2p); return addrs(addrr(addrr(ht, divru(hj,12)), mu), 2); } static GEN qfb_root(GEN Q, GEN vDi) { GEN a2 = shifti(gel(Q, 1),1), b = gel(Q, 2); return mkcomplex(gdiv(negi(b),a2),divri(vDi,a2)); } static GEN qimag2(GEN Q) { pari_sp av = avma; GEN z = gdiv(negi(qfb_disc(Q)), shifti(sqri(gel(Q, 1)),2)); return gerepileupto(av, z); } /***************************************************/ /*Routines for increasing the imaginary parts using*/ /*Atkin-Lehner operators */ /***************************************************/ static GEN qfb_mult(GEN Q, GEN M) { GEN A = gel(Q, 1) , B = gel(Q, 2) , C = gel(Q, 3); GEN a = gcoeff(M, 1, 1), b = gcoeff(M, 1, 2); GEN c = gcoeff(M, 2, 1), d = gcoeff(M, 2, 2); GEN W1 = addii(addii(mulii(sqri(a), A), mulii(mulii(c, a), B)), mulii(sqri(c), C)); GEN W2 = addii(addii(mulii(mulii(shifti(b,1), a), A), mulii(addii(mulii(d, a), mulii(c, b)), B)), mulii(mulii(shifti(d,1), c), C)); GEN W3 = addii(addii(mulii(sqri(b), A), mulii(mulii(d, b), B)), mulii(sqri(d), C)); GEN D = gcdii(W1, gcdii(W2, W3)); if (!equali1(D)) { W1 = diviiexact(W1,D); W2 = diviiexact(W2,D); W3 = diviiexact(W3,D); } return qfi(W1, W2, W3); } #ifdef DEBUG static void best_point_old(GEN Q, GEN NQ, GEN f, GEN *u, GEN *v) { long n, k; GEN U, c, d; GEN A = gel(f, 1); GEN B = gel(f, 2); GEN C = gel(f, 3); GEN q = qfi(mulii(NQ, C), negi(B), diviiexact(A, NQ)); redimagsl2(q, &U); *u = c = gcoeff(U, 1, 1); *v = d = gcoeff(U, 2, 1); if (equali1(gcdii(mulii(*u, NQ), mulii(*v, Q)))) return; for (n = 1; ; n++) { for (k = -n; k<=n; k++) { *u = addis(c, k); *v = addiu(d, n); if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q)))) return; *v= subiu(d, n); if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q)))) return; *u = addiu(c, n); *v = addis(d, k); if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q)))) return; *u = subiu(c, n); if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q)))) return; } } } /* q(x,y) = ax^2 + bxy + cy^2 */ static GEN qfb_eval(GEN q, GEN x, GEN y) { GEN a = gel(q,1), b = gel(q,2), c = gel(q,3); GEN x2 = sqri(x), y2 = sqri(y), xy = mulii(x,y); return addii(addii(mulii(a, x2), mulii(b,xy)), mulii(c, y2)); } #endif static long nexti(long i) { return i>0 ? -i : 1-i; } /* q0 + i q1 + i^2 q2 */ static GEN qfmin_eval(GEN q0, GEN q1, GEN q2, long i) { return addii(mulis(addii(mulis(q2, i), q1), i), q0); } /* assume a > 0, return gcd(a,b,c) */ static ulong gcduii(ulong a, GEN b, GEN c) { a = ugcdiu(b, a); return a == 1? 1: ugcdiu(c, a); } static void best_point(GEN Q, GEN NQ, GEN f, GEN *pu, GEN *pv) { GEN a = mulii(NQ, gel(f,3)), b = negi(gel(f,2)), c = diviiexact(gel(f,1), NQ); GEN D = absi_shallow( qfb_disc(f) ); GEN U, qr = redimagsl2(qfi(a,b,c), &U); GEN A = gel(qr,1), B = gel(qr,2), A2 = shifti(A,1), AA4 = sqri(A2); GEN V, best; long y; /* 4A qr(x,y) = (2A x + By)^2 + D y^2 * Write x = x0(y) + i, where x0 is an integer minimum * (the smallest in case of tie) of x-> qr(x,y), for given y. * 4A qr(x,y) = ((2A x0 + By)^2 + Dy^2) + 4A i (2A x0 + By) + 4A^2 i^2 * = q0(y) + q1(y) i + q2 i^2 * Loop through (x,y), y>0 by (roughly) increasing values of qr(x,y) */ /* We must test whether [X,Y]~ := U * [x,y]~ satisfy (X NQ, Y Q) = 1 * This is equivalent to (X,Y) = 1 (note that (X,Y) = (x,y)), and * (X, Q) = (Y, NQ) = 1. * We have U * [x0+i, y]~ = U * [x0,y]~ + i U[,1] =: V0 + i U[,1] */ /* try [1,0]~ = first minimum */ V = gel(U,1); /* U *[1,0]~ */ *pu = gel(V,1); *pv = gel(V,2); if (is_pm1(gcdii(*pu, Q)) && is_pm1(gcdii(*pv, NQ))) return; /* try [0,1]~ = second minimum */ V = gel(U,2); /* U *[0,1]~ */ *pu = gel(V,1); *pv = gel(V,2); if (is_pm1(gcdii(*pu, Q)) && is_pm1(gcdii(*pv, NQ))) return; /* (X,Y) = (1, \pm1) always works. Try to do better now */ best = subii(addii(a, c), absi_shallow(b)); *pu = gen_1; *pv = signe(b) < 0? gen_1: gen_m1; for (y = 1;; y++) { GEN Dy2, r, By, x0, q0, q1, V0; long i; if (y > 1) { if (gcduii(y, gcoeff(U,1,1), Q) != 1) continue; if (gcduii(y, gcoeff(U,2,1), NQ) != 1) continue; } Dy2 = mulii(D, sqru(y)); if (cmpii(Dy2, best) >= 0) break; /* we won't improve. STOP */ By = muliu(B,y), x0 = truedvmdii(negi(By), A2, &r); if (cmpii(r, A) >= 0) { x0 = subiu(x0,1); r = subii(r, A2); } /* (2A x + By)^2 + Dy^2, minimal at x = x0. Assume A2 > 0 */ /* r = 2A x0 + By */ q0 = addii(sqri(r), Dy2); /* minimal value for this y, at x0 */ if (cmpii(q0, best) >= 0) continue; /* we won't improve for this y */ q1 = shifti(mulii(A2, r), 1); V0 = ZM_ZC_mul(U, mkcol2(x0, utoipos(y))); for (i = 0;; i = nexti(i)) { pari_sp av2 = avma; GEN x, N = qfmin_eval(q0, q1, AA4, i); if (cmpii(N , best) >= 0) break; x = addis(x0, i); if (ugcdiu(x, y) == 1) { GEN u, v; V = ZC_add(V0, ZC_z_mul(gel(U,1), i)); /* [X, Y] */ u = gel(V,1); v = gel(V,2); if (is_pm1(gcdii(u, Q)) && is_pm1(gcdii(v, NQ))) { *pu = u; *pv = v; best = N; break; } } avma = av2; } } #ifdef DEBUG { GEN oldu, oldv, F = qfi(a,b,c); best_point_old(Q, NQ, f, &oldu, &oldv); if (!equalii(oldu, *pu) || !equalii(oldv, *pv)) { if (!equali1(gcdii(mulii(*pu, NQ), mulii(*pv, Q)))) pari_err_BUG("best_point (gcd)"); if (cmpii(qfb_eval(F, *pu,*pv), qfb_eval(F, oldu, oldv)) > 0) { pari_warn(warner, "%Ps,%Ps,%Ps, %Ps > %Ps", Q,NQ,f, mkvec2(*pu,*pv), mkvec2(oldu,oldv)); pari_err_BUG("best_point (too large)"); } } } #endif } static GEN best_lift(GEN N, GEN Q, GEN NQ, GEN f) { GEN a,b,c,d,M; best_point(Q, NQ, f, &c, &d); (void)bezout(mulii(d, Q), mulii(NQ, c), &a, &b); M = mkmat2( mkcol2(mulii(d, Q), mulii(negi(N), c)), mkcol2(b, mulii(a, Q))); return qfb_mult(f, M); } static GEN lift_points(GEN N, GEN listQ, GEN f, GEN *pt, GEN *pQ) { pari_sp av = avma; GEN yf = gen_0, tf = NULL, Qf = NULL; long k, l = lg(listQ); for (k = 1; k < l; ++k) { GEN c = gel(listQ, k), Q = gel(c,1), NQ = gel(c,2); GEN t = best_lift(N, Q, NQ, f), y = qimag2(t); if (gcmp(y, yf) > 0) { yf = y; Qf = Q; tf = t; } } gerepileall(av, 3, &tf, &Qf, &yf); *pt = tf; *pQ = Qf; return yf; } /***************************/ /* Twists */ /***************************/ static GEN ltwist1(GEN E, GEN d, long bitprec) { pari_sp av = avma; GEN Ed = ellinit(elltwist(E, d), NULL, DEFAULTPREC); GEN z = ellL1_bitprec(Ed, 0, bitprec); obj_free(Ed); return gerepileuptoleaf(av, z); } /* Return O_re*c(E)/(4*O_vol*|E_t|^2) */ static GEN heegner_indexmult(GEN om, long t, GEN tam, long prec) { pari_sp av = avma; GEN Ovr = gabs(imag_i(gel(om, 2)), prec); /* O_vol/O_re, t_REAL */ return gerepileupto(av, divru(divir(tam, Ovr), 4*t*t)); } /* omega(gcd(D, N)), given faN = factor(N) */ static long omega_N_D(GEN faN, ulong D) { GEN P = gel(faN, 1); long i, l = lg(P), w = 0; for (i = 1; i < l; i++) if (dvdui(D, gel(P,i))) w++; return w; } static GEN heegner_indexmultD(GEN faN, GEN a, long D, GEN sqrtD) { pari_sp av = avma; GEN c; long w; switch(D) { case -3: w = 9; break; case -4: w = 4; break; default: w = 1; } c = shifti(stoi(w), omega_N_D(faN,-D)); /* (w(D)/2)^2 * 2^omega(gcd(D,N)) */ return gerepileupto(av, mulri(mulrr(a, sqrtD), c)); } static GEN heegner_try_point(GEN E, GEN lambdas, GEN ht, GEN z, long prec) { long l = lg(lambdas); long i, eps; GEN P = real_i(pointell(E, z, prec)), x = gel(P,1); GEN rh = subrr(ht, shiftr(ellheightoo(E, P, prec),1)); for (i = 1; i < l; ++i) { GEN logd = shiftr(gsub(rh, gel(lambdas, i)), -1); GEN d, approxd = gexp(logd, prec); if (DEBUGLEVEL > 2) err_printf("Trying lambda number %ld, logd=%Ps, approxd=%Ps\n", i, logd, approxd); d = grndtoi(approxd, &eps); if (signe(d) > 0 && eps<-10) { GEN X, ylist, d2 = sqri(d), approxn = mulir(d2, x); if (DEBUGLEVEL > 2) err_printf("approxn=%Ps eps=%ld\n", approxn,eps); X = gdiv(ground(approxn), d2); ylist = ellordinate(E, X, prec); if (lg(ylist) > 1) { GEN P = mkvec2(X, gel(ylist, 1)); GEN hp = ghell(E,P,prec); if (cmprr(hp, shiftr(ht,1)) < 0 && cmprr(hp, shiftr(ht,-1)) > 0) return P; if (DEBUGLEVEL) err_printf("found non-Heegner point %Ps\n", P); } } } return NULL; } static GEN heegner_find_point(GEN e, GEN om, GEN ht, GEN z1, long k, long prec) { GEN lambdas = lambdalist(e, prec); pari_sp av = avma; long m; GEN Ore = gel(om, 1), Oim = gel(om, 2); if (DEBUGLEVEL) err_printf("%ld*%ld multipliers to test\n",k,lg(lambdas)-1); for (m = 0; m < k; m++) { GEN P, z2 = divru(addrr(z1, mulsr(m, Ore)), k); if (DEBUGLEVEL > 2) err_printf("Trying multiplier %ld\n",m); P = heegner_try_point(e, lambdas, ht, z2, prec); if (P) return P; if (signe(ell_get_disc(e)) > 0) { z2 = gadd(z2, gmul2n(Oim, -1)); P = heegner_try_point(e, lambdas, ht, z2, prec); if (P) return P; } avma = av; } pari_err_BUG("ellheegner, point not found"); return NULL; /* LCOV_EXCL_LINE */ } /* N > 1, fa = factor(N), return factor(4*N) */ static GEN fa_shift2(GEN fa) { GEN P = gel(fa,1), E = gel(fa,2); if (absequaliu(gcoeff(fa,1,1), 2)) { E = shallowcopy(E); gel(E,1) = addiu(gel(E,1), 2); } else { P = shallowconcat(gen_2, P); E = shallowconcat(gen_2, E); } return mkmat2(P, E); } /* P = prime divisors of N(E). Return the product of primes p in P, a_p != -1 * HACK: restrict to small primes since large ones won't divide our C-long * discriminants */ static GEN get_bad(GEN E, GEN P) { long k, l = lg(P), ibad = 1; GEN B = cgetg(l, t_VECSMALL); for (k = 1; k < l; k++) { GEN p = gel(P,k); long pp = itos_or_0(p); if (!pp) break; if (! equalim1(ellap(E,p))) B[ibad++] = pp; } setlg(B, ibad); return ibad == 1? NULL: zv_prod_Z(B); } /* list of pairs [Q,N/Q], where Q | N and gcd(Q,N/Q) = 1 */ static GEN find_div(GEN N, GEN faN) { GEN listQ = divisors(faN); long j, k, l = lg(listQ); gel(listQ, 1) = mkvec2(gen_1, N); for (j = k = 2; k < l; ++k) { GEN Q = gel(listQ, k), NQ = diviiexact(N, Q); if (is_pm1(gcdii(Q,NQ))) gel(listQ, j++) = mkvec2(Q,NQ); } setlg(listQ, j); return listQ; } static long testDisc(GEN bad, long d) { return !bad || ugcdiu(bad, -d) == 1; } /* bad = product of bad primes. Return the NDISC largest fundamental * discriminants D < d such that (D,bad) = 1 and d is a square mod 4N */ static GEN listDisc(GEN fa4N, GEN bad, long d) { const long NDISC = 10; GEN v = cgetg(NDISC+1, t_VECSMALL); pari_sp av = avma; long j = 1; for(;;) { d -= odd(d)? 1: 3; if (testDisc(bad,d) && unegisfundamental(-d) && Zn_issquare(stoi(d), fa4N)) { v[j++] = d; if (j > NDISC) break; } avma = av; } avma = av; return v; } /* L = vector of [q1,q2] or [q1,q2,q2'] * cd = (b^2 - D)/(4N) */ static void listfill(GEN N, GEN b, GEN c, GEN d, GEN L, long *s) { long k, l = lg(L); GEN add, frm2, a = mulii(d, N), V = mkqfi(a,b,c), frm = redimag(V); for (k = 1; k < l; ++k) { /* Lk = [v,frm] or [v,frm,frm2] */ GEN Lk = gel(L,k); long i; for (i = 2; i < lg(Lk); i++) /* 1 or 2 elements */ if (gequal(frm, gel(Lk,i))) { GEN v = gel(Lk, 1); if (cmpii(a, gel(v,1)) < 0) gel(Lk,1) = V; return; } } frm2 = redimag( mkqfi(d, negi(b), mulii(c,N)) ); add = gequal(frm, frm2)? mkvec2(V,frm): mkvec3(V,frm,frm2); vectrunc_append(L, add); *s += lg(add) - 2; } /* faN4 = factor(4*N) */ static GEN listheegner(GEN N, GEN faN4, GEN listQ, GEN D) { pari_sp av = avma; const long kmin = 30; long h = itos(gel(quadclassunit0(D, 0, NULL, DEFAULTPREC), 1)); GEN ymin, b = Zn_sqrt(D, faN4), L = vectrunc_init(h+1); long l, k, s = 0; for (k = 0; k < kmin || s < h; k++) { GEN bk = addii(b, mulsi(2*k, N)); GEN C = diviiexact(shifti(subii(sqri(bk), D), -2), N); GEN div = divisors(C); long i, l = lg(div); for (i = 1; i < l; i++) { GEN d = gel(div, i), c = gel(div, l-i); /* cd = C */ listfill(N, bk, c, d, L, &s); } } l = lg(L); ymin = NULL; for (k = 1; k < l; k++) { GEN t, Q, Lk = gel(L,k), f = gel(Lk,1); GEN y = lift_points(N, listQ, f, &t, &Q); gel(L, k) = mkvec3(t, stoi(lg(Lk) - 2), Q); if (!ymin || gcmp(y, ymin) < 0) ymin = y; } if (DEBUGLEVEL > 1) err_printf("Disc %Ps : N*ymin = %Pg\n", D, gmul(gsqrt(ymin, DEFAULTPREC),N)); return gerepilecopy(av, mkvec3(ymin, L, D)); } /* Q | N, P = prime divisors of N, R[i] = local epsilon-factor at P[i]. * Return \prod_{p | Q} R[i] */ static long rootno(GEN Q, GEN P, GEN R) { long s = 1, i, l = lg(P); for (i = 1; i < l; i++) if (dvdii(Q, gel(P,i))) s *= R[i]; return s; } static void heegner_find_disc(GEN *points, GEN *coefs, long *pind, GEN E, GEN indmult, long prec) { long d = 0; GEN faN4, bad, N, faN, listQ, listR; ellQ_get_Nfa(E, &N, &faN); faN4 = fa_shift2(faN); listQ = find_div(N, faN); bad = get_bad(E, gel(faN, 1)); listR = gel(obj_check(E, Q_ROOTNO), 2); for(;;) { pari_sp av = avma; GEN list, listD = listDisc(faN4, bad, d); long k, l = lg(listD); list = cgetg(l, t_VEC); for (k = 1; k < l; ++k) gel(list, k) = listheegner(N, faN4, listQ, stoi(listD[k])); list = vecsort0(list, gen_1, 0); for (k = l-1; k > 0; --k) { long bprec = 8; GEN Lk = gel(list,k), D = gel(Lk,3); GEN sqrtD = sqrtr_abs(itor(D, prec)); /* sqrt(|D|) */ GEN indmultD = heegner_indexmultD(faN, indmult, itos(D), sqrtD); do { GEN mulf, indr; pari_timer ti; if (DEBUGLEVEL) timer_start(&ti); mulf = ltwist1(E, D, bprec+expo(indmultD)); if (DEBUGLEVEL) timer_printf(&ti,"ellL1twist"); indr = mulrr(indmultD, mulf); if (DEBUGLEVEL) err_printf("Disc = %Ps, Index^2 = %Ps\n", D, indr); if (signe(indr)>0 && expo(indr) >= -1) /* indr >=.5 */ { long e, i, l; GEN pts, cfs, L, indi = grndtoi(sqrtr_abs(indr), &e); if (e > expi(indi)-7) { bprec++; pari_warn(warnprec, "ellL1",bprec); continue; } *pind = itos(indi); L = gel(Lk, 2); l = lg(L); pts = cgetg(l, t_VEC); cfs = cgetg(l, t_VECSMALL); for (i = 1; i < l; ++i) { GEN P = gel(L,i), z = gel(P,2), Q = gel(P,3); /* [1 or 2, Q] */ long c; gel(pts, i) = qfb_root(gel(P,1), sqrtD); c = rootno(Q, gel(faN,1), listR); if (!equali1(z)) c *= 2; cfs[i] = c; } if (DEBUGLEVEL) err_printf("N = %Ps, ymin*N = %Ps\n",N, gmul(gsqrt(gel(Lk, 1), prec),N)); *coefs = cfs; *points = pts; return; } } while(0); } d = listD[l-1]; avma = av; } } GEN ellanal_globalred_all(GEN e, GEN *cb, GEN *N, GEN *tam) { GEN E = ellanal_globalred(e, cb), red = obj_check(E, Q_GLOBALRED); *N = gel(red, 1); *tam = gel(red,2); if (signe(ell_get_disc(E))>0) *tam = shifti(*tam,1); return E; } GEN ellheegner(GEN E) { pari_sp av = avma; GEN z, P, ht, points, coefs, s, om, indmult; long ind, lint, k, l, wtor, etor; long bitprec = 16, prec = nbits2prec(bitprec)+1; pari_timer ti; GEN N, cb, tam, torsion; E = ellanal_globalred_all(E, &cb, &N, &tam); if (ellrootno_global(E) == 1) pari_err_DOMAIN("ellheegner", "(analytic rank)%2","=",gen_0,E); torsion = elltors(E); wtor = itos( gel(torsion,1) ); /* #E(Q)_tor */ etor = wtor > 1? itou(gmael(torsion, 2, 1)): 1; /* exponent of E(Q)_tor */ while (1) { GEN hnaive, l1; long bitneeded; if (DEBUGLEVEL) timer_start(&ti); l1 = ellL1_bitprec(E, 1, bitprec); if (DEBUGLEVEL) timer_printf(&ti,"ellL1"); if (expo(l1) < 1 - bitprec/2) pari_err_DOMAIN("ellheegner", "analytic rank",">",gen_1,E); om = ellR_omega(E,prec); ht = divrr(mulru(l1, wtor * wtor), mulri(gel(om,1), tam)); if (DEBUGLEVEL) err_printf("Expected height=%Ps\n", ht); hnaive = hnaive_max(E, ht); if (DEBUGLEVEL) err_printf("Naive height <= %Ps\n", hnaive); bitneeded = itos(gceil(divrr(hnaive, mplog2(prec)))) + 10; if (DEBUGLEVEL) err_printf("precision = %ld\n", bitneeded); if (bitprec>=bitneeded) break; bitprec = bitneeded; prec = nbits2prec(bitprec)+1; } indmult = heegner_indexmult(om, wtor, tam, prec); heegner_find_disc(&points, &coefs, &ind, E, indmult, prec); if (DEBUGLEVEL) timer_start(&ti); s = heegner_psi(E, N, points, bitprec); if (DEBUGLEVEL) timer_printf(&ti,"heegner_psi"); l = lg(points); z = mulsr(coefs[1], gel(s, 1)); for (k = 2; k < l; ++k) z = addrr(z, mulsr(coefs[k], gel(s, k))); if (DEBUGLEVEL) err_printf("z=%Ps\n", z); z = gsub(z, gmul(gel(om,1), ground(gdiv(z, gel(om,1))))); lint = wtor > 1 ? ugcd(ind, etor): 1; P = heegner_find_point(E, om, ht, gmulsg(2*lint, z), lint*2*ind, prec); if (DEBUGLEVEL) timer_printf(&ti,"heegner_find_point"); if (cb) P = ellchangepointinv(P, cb); return gerepilecopy(av, P); } /* Modular degree */ static GEN ellisobound(GEN e) { GEN M = gel(ellisomat(e,0,1),2); return vecmax(gel(M,1)); } /* 4Pi^2 / E.area */ static GEN getA(GEN E, long prec) { return mpdiv(sqrr(Pi2n(1,prec)), ellR_area(E, prec)); } /* Modular degree of elliptic curve e over Q, assuming Manin constant = 1 * (otherwise multiply by square of Manin constant). */ GEN ellmoddegree(GEN E) { pari_sp av = avma; GEN N, tam, mc2, d; long b; E = ellanal_globalred_all(E, NULL, &N, &tam); mc2 = sqri(ellisobound(E)); b = expi(mulii(N, mc2)) + maxss(0, expo(getA(E, LOWDEFAULTPREC))) + 16; for(;;) { long prec = nbits2prec(b), e, s; GEN deg = mulri(mulrr(lfunellmfpeters(E, b), getA(E, prec)), mc2); d = grndtoi(deg, &e); if (DEBUGLEVEL) err_printf("ellmoddegree: %Ps, bit=%ld, err=%ld\n",deg,b,e); s = expo(deg); if (e <= -8 && s <= b-8) return gerepileupto(av, gdiv(d,mc2)); b = maxss(s, b+e) + 16; } } pari-2.11.2/src/basemath/ecpp.c0000644000175000017500000012436613326135265014646 0ustar billbill/* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #define dbg_mode() if (DEBUGLEVEL >= 2) #define ANSI_RED "\x1b[31m" #define ANSI_GREEN "\x1b[32m" #define ANSI_YELLOW "\x1b[33m" #define ANSI_BLUE "\x1b[34m" #define ANSI_MAGENTA "\x1b[35m" #define ANSI_CYAN "\x1b[36m" #define ANSI_WHITE "\x1b[37m" #define ANSI_BRIGHT_RED "\x1b[31;1m" #define ANSI_BRIGHT_GREEN "\x1b[32;1m" #define ANSI_BRIGHT_YELLOW "\x1b[33;1m" #define ANSI_BRIGHT_BLUE "\x1b[34;1m" #define ANSI_BRIGHT_MAGENTA "\x1b[35;1m" #define ANSI_BRIGHT_CYAN "\x1b[36;1m" #define ANSI_BRIGHT_WHITE "\x1b[37;1m" #define ANSI_RESET "\x1b[0m" /* THINGS THAT DON'T BELONG */ /* Assume that x is a vector such that f(x) = 1 for x <= k f(x) = 0 otherwise. Return k. */ static long zv_binsearch0(void *E, long (*f)(void* E, GEN x), GEN x) { long lo = 1; long hi = lg(x)-1; while (lo < hi) { long mi = lo + (hi - lo)/2 + 1; if (f(E,gel(x,mi))) lo = mi; else hi = mi - 1; } if (f(E,gel(x,lo))) return lo; return 0; } INLINE long timer_record(GEN* X0, const char* Xx, pari_timer* ti) { long t = timer_delay(ti), i = Xx[0]-'A'+1, j = Xx[1]-'1'+1; umael3(*X0, 1, i, j) += t; umael3(*X0, 2, i, j) ++; return t; } INLINE long FpJ_is_inf(GEN P) { return signe(gel(P, 3)) == 0; } /*****************************************************************/ /* D < 0 fundamental: return the number of units in Q(sqrt(D)) */ INLINE long D_get_wD(long D) { if (D == -4) return 4; if (D == -3) return 6; return 2; } /* Dinfo contains information related to the discirminant * D: the discriminant (D < 0) * h: the class number associated to D * bi: the "best invariant" for computing polclass(D, bi) * pd: the degree of polclass; equal to h except when bi is a double * eta-quotient w_p,q with p|D and q|D, where pd = h/2. * Dfac: the prime factorization of D; we have D = q0 q1* q2* ... qn* * where q0 = 1, 4, -4, 8, qi* = 1 mod 4 and |qi| is a prime. * The factorization is a vecsmall listing the indices of the qi* as * they appear in the primelist (q0 = 1 is omitted) */ INLINE long Dinfo_get_D(GEN Dinfo) { return gel(Dinfo, 1)[1]; } INLINE long Dinfo_get_h(GEN Dinfo) { return gel(Dinfo, 1)[2]; } INLINE long Dinfo_get_bi(GEN Dinfo) { return gel(Dinfo, 1)[3]; } INLINE ulong Dinfo_get_pd(GEN Dinfo) { return umael(Dinfo, 1, 4); } INLINE GEN Dinfo_get_Dfac(GEN Dinfo) { return gel(Dinfo, 2); } /* primelist and indexlist * * primelist begins with 8, -4, -8; subsequent elements are the p^* for * successive odd primes <= maxsqrt, by increasing absolute value * * i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | * ---------+----+----+----+----+----+----+----+----+----+-----+-----+ * i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | * Plist[i] | 8 | -4 | -8 | -3 | 5 | -7 |-11 | 13 | 17 | -19 | -23 | * p | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | 21 | 23 | * ---------+----+----+----+----+----+----+----+----+----+-----+-----+*/ /* primelist containing primes whose absolute value is at most maxsqrt */ static GEN ecpp_primelist_init(long maxsqrt) { GEN P = cgetg(maxsqrt, t_VECSMALL); forprime_t T; long p, j = 4; u_forprime_init(&T, 3, maxsqrt); P[1] = 8; P[2] = -4; P[3] = -8; while((p = u_forprime_next(&T))) P[j++] = ((p & 3UL) == 1)? p: -p; setlg(P,j); return P; } static GEN Dfac_to_p(GEN x, GEN P) { pari_APPLY_long(uel(P,x[i])); } static GEN Dfac_to_roots(GEN x, GEN P) { pari_APPLY_type(t_VEC, gel(P,x[i])); } #if 0 INLINE ulong ecpp_param_get_maxsqrt(GEN param) { return umael3(param, 1, 1, 1); } INLINE ulong ecpp_param_get_maxdisc(GEN param) { return umael3(param, 1, 1, 2); } #endif INLINE ulong ecpp_param_get_maxpcdg(GEN param) { return umael3(param, 1, 1, 3); } INLINE GEN ecpp_param_get_primelist(GEN param) { return gmael(param, 1, 2); } INLINE GEN ecpp_param_get_disclist(GEN param) { return gmael(param, 1, 3); } INLINE GEN ecpp_param_get_primorial_vec(GEN param) { return gel(param, 2); } INLINE GEN ecpp_param_get_tune(GEN param) { return gel(param, 3); } /* Input: x, 20 <= x <= 35 * Output: a vector whose ith entry is the product of all primes below 2^x */ static GEN primorial_vec(ulong x) { pari_sp av = avma; long i, y = x-19; GEN v = primes_upto_zv(1UL << x), w = cgetg(y+1, t_VEC); /* ind[i]th prime number is the largest prime <= 2^(20+i) */ long ind[] = { 0, 82025L, 155611L, 295947L, 564163L, 1077871L, 2063689L, 3957809L, 7603553L, 14630843L, 28192750L, 54400028L, 105097565L, 203280221L, 393615806L, 762939111L, 1480206279L}; gel(w,1) = zv_prod_Z(vecslice(v,1,ind[1])); for (i = 2; i <= y; i++) { pari_sp av2 = avma; GEN q = mulii(gel(w,i-1), zv_prod_Z(vecslice(v,ind[i-1]+1,ind[i]))); gel(w,i) = gerepileuptoint(av2, q); } return gerepileupto(av, w); } /* NDmqg contains N, as in the theorem in ??ecpp Dinfo, as discussed in the comment about Dinfo m, as in the theorem in ??ecpp q, as in the theorem in ??ecpp g, a quadratic non-residue modulo N sqrt, a list of squareroots */ INLINE GEN NDmqg_get_N(GEN x) { return gel(x,1); } INLINE GEN NDmqg_get_Dinfo(GEN x) { return gel(x,2); } INLINE GEN NDmqg_get_m(GEN x) { return gel(x,3); } INLINE GEN NDmqg_get_q(GEN x) { return gel(x,4); } INLINE GEN NDmqg_get_g(GEN x) { return gel(x,5); } INLINE GEN NDmqg_get_sqrt(GEN x) { return gel(x,6); } /* COMPARATOR FUNCTIONS */ static int sort_disclist(void *data, GEN x, GEN y) { long d1, h1, g1, o1, pd1, hf1, wD1, d2, h2, g2, o2, pd2, hf2, wD2; (void)data; d1 = Dinfo_get_D(x); wD1 = D_get_wD(d1); d2 = Dinfo_get_D(y); wD2 = D_get_wD(d2); /* higher number of units means more elliptic curves to try */ if (wD1 != wD2) return wD2 > wD1 ? 1 : -1; /* lower polclass degree is better: faster computation of roots modulo N */ pd1 = Dinfo_get_pd(x); /* degree of polclass */ pd2 = Dinfo_get_pd(y); if (pd1 != pd2) return pd1 > pd2 ? 1 : -1; g1 = lg(Dinfo_get_Dfac(x))-1; /* genus number */ h1 = Dinfo_get_h(x); /* class number */ o1 = h1 >> (g1-1); /* odd class number */ g2 = lg(Dinfo_get_Dfac(y))-1; h2 = Dinfo_get_h(y); o2 = h2 >> (g2-1); if (o1 != o2) return g1 > g2 ? 1 : -1; /* lower class number is better: higher probability of succesful cornacchia */ if (h1 != h2) return h1 > h2 ? 1 : -1; /* higher height factor is better: polclass would have lower coefficients */ hf1 = modinv_height_factor(Dinfo_get_bi(x)); /* height factor for best inv. */ hf2 = modinv_height_factor(Dinfo_get_bi(y)); if (hf1 != hf2) return hf2 > hf1 ? 1 : -1; /* "higher" discriminant is better since its absolute value is lower */ if (d1 != d2) return d2 > d1 ? 1 : -1; return 0; } INLINE long NDmqg_get_D(GEN x) { return Dinfo_get_D(NDmqg_get_Dinfo(x)); } static int sort_NDmq_by_D(void *data, GEN x, GEN y) { long d1 = NDmqg_get_D(x); long d2 = NDmqg_get_D(y); (void)data; return d2 > d1 ? 1 : -1; } static int sort_Dmq_by_q(void *data, GEN x, GEN y) { (void)data; return cmpii(gel(x,3), gel(y,3)); } INLINE long Dmq_get_D(GEN Dmq) { return Dinfo_get_D(gel(Dmq,1)); } INLINE long Dmq_get_h(GEN Dmq) { return Dinfo_get_h(gel(Dmq,1)); } static int sort_Dmq_by_cnum(void *data, GEN x, GEN y) { ulong h1 = Dmq_get_h(x); ulong h2 = Dmq_get_h(y); if (h1 != h2) return h1 > h2 ? 1 : -1; return sort_Dmq_by_q(data, x, y); } /* return H s.t if -maxD <= D < 0 is fundamental then H[(-D)>>1] is the * ordinary class number of Q(sqrt(D)); junk at other entries. */ static GEN allh(ulong maxD) { ulong a, A = usqrt(maxD/3), maxD2 = maxD >> 1; GEN H = zero_zv(maxD2); for (a = 1; a <= A; a++) { ulong a2 = a << 1, aa = a*a, aa4 = aa << 2, b, c; { /* b = 0 */ ulong D = aa << 1; for (c = a; D <= maxD2; c++) { H[D]++; D += a2; } } for (b = 1; b < a; b++) { ulong B = b*b, D = (aa4 - B) >> 1; if (D > maxD2) break; H[D]++; D += a2; /* c = a */ for (c = a+1; D <= maxD2; c++) { H[D] += 2; D += a2; } } { /* b = a */ ulong D = (aa4 - aa) >> 1; for (c = a; D <= maxD2; c++) { H[D]++; D += a2; } } } return H; } static GEN mkDinfo(GEN c, long D, long h) { long bi, pd, p1, p2; bi = disc_best_modinv(D); pd = (modinv_degree(&p1,&p2,bi) && (-D)%p1==0 && (-D)%p2==0)? h/2: h; gel(c,1) = mkvecsmall4(D, h, bi, pd); return c; } static GEN ecpp_disclist_init(ulong maxdisc, GEN primelist) { pari_sp av = avma; long t, ip, u, lp, lmerge; GEN merge, ev, od, Harr = allh(maxdisc); /* table of class numbers*/ long lenv = maxdisc/4; /* max length of od/ev */ long N; /* maximum number of positive prime factors */ /* tuning paramaters blatantly copied from vecfactoru */ if (maxdisc < 510510UL) N = 7; else if (maxdisc < 9699690UL) N = 8; #ifdef LONG_IS_64BIT else if (maxdisc < 223092870UL) N = 9; else if (maxdisc < 6469693230UL) N = 10; else if (maxdisc < 200560490130UL) N = 11; else if (maxdisc < 7420738134810UL) N = 12; else if (maxdisc < 304250263527210UL) N = 13; else N = 16; /* don't bother */ #else else N = 9; #endif /* od[t] attached to discriminant 1-4*t, ev[t] attached to -4*t */ od = cgetg(lenv + 1, t_VEC); /* contains 'long' at first: save memory */ ev = cgetg(lenv + 1, t_VEC); /* first pass: squarefree sieve and restrict to maxsqrt-smooth disc */ for (t = 1; t <= lenv; t++) { od[t] = 1; switch(t&7) { case 0: case 4: ev[t] = 0; break; case 2: ev[t] =-8; break; case 6: ev[t] = 8; break; default:ev[t] =-4; break; } } lp = lg(primelist); for (ip = 4; ip < lp; ip++) /* skip 8,-4,-8 */ { /* sieve by squares of primes */ long s, q = primelist[ip], p = labs(q); s = (q == p)? 3: 1; for (t = (s*p+1)>>2; t <= lenv; t += p, s += 4) { long c = od[t]; if (c) { if (s%p == 0) od[t] = 0; else od[t] = c*q; } } s = 1; for (t = p; t <= lenv; t += p, s++) { long c = ev[t]; if (c) { if (s%p == 0) ev[t] = 0; else ev[t] = c*q; } } } for (u = 0, t = 1; t <= lenv; t++) { /* restrict to maxsqrt-smooth disc */ if (od[t] != -4*t+1) od[t] = 0; else u++; if (ev[t] != -4*t) ev[t] = 0; else u++; } /* second pass: sieve by primes and record factorization */ for (t = 1; t <= lenv; t++) { if (od[t]) gel(od,t) = mkvec2(NULL, vecsmalltrunc_init(N)); if (ev[t]) { GEN F = vecsmalltrunc_init(N); long id; switch(t&7) { case 2: id = 3; break; case 6: id = 1; break; default:id = 2; break; } vecsmalltrunc_append(F, id); gel(ev,t) = mkvec2(NULL, F); } } lp = lg(primelist); for (ip = 4; ip < lp; ip++) /* skip 8,-4,-8 */ { long s, q = primelist[ip], p = labs(q); s = (q == p)? 3: 1; for (t = (s*p+1)>>2; t <= lenv; t += p, s += 4) { GEN c = gel(od,t); if (c) vecsmalltrunc_append(gel(c,2), ip); } s = 1; for (t = p; t <= lenv; t += p, s++) { GEN c = gel(ev,t); if (c) vecsmalltrunc_append(gel(c,2), ip); } } /* merging the two arrays */ merge = cgetg(u+1, t_VEC); lmerge = 0; for (t = 1; t <= lenv; t++) { GEN c; c = gel(od,t); if (c) gel(merge, ++lmerge) = mkDinfo(c,1-4*t, Harr[2*t-1]); c = gel(ev,t); if (c) gel(merge, ++lmerge) = mkDinfo(c, -4*t, Harr[2*t]); } setlg(merge, lmerge); gen_sort_inplace(merge, NULL, &sort_disclist, NULL); return gerepilecopy(av, merge); } /* Input: a vector tune whose components are [maxsqrt,maxpcdg,tdivexp,expiN] * Output: vector param of precomputations * let x = be a component of tune then * param[1][1] = [maxsqrt, maxdisc, maxpcdg] * param[1][2] = primelist = Vecsmall of primes * param[1][3] = disclist = vector of Dinfos, sorted by quality * param[2] = primorial_vec * param[3] = tune */ static GEN ecpp_param_set(GEN tune, GEN x) { pari_sp av = avma; ulong maxsqrt = uel(x,1), maxpcdg = uel(x,2), tdivexp = uel(x,3); ulong maxdisc = maxsqrt * maxsqrt; GEN T = mkvecsmall3(maxsqrt, maxdisc, maxpcdg); GEN Plist = ecpp_primelist_init(maxsqrt); GEN Dlist = ecpp_disclist_init(maxdisc, Plist); GEN primorial = primorial_vec(tdivexp); return gerepilecopy(av, mkvec3(mkvec3(T,Plist,Dlist), primorial, tune)); } /* cert contains [N, t, s, a4, [x, y]] as documented in ??ecpp; the following * information can be obtained: * D = squarefreepart(t^2-4N) * m = (N+1-t), q = m/s, a6 = y^3 - x^2 - a4*x, J */ INLINE GEN cert_get_N(GEN x) { return gel(x,1); } INLINE GEN cert_get_t(GEN x) { return gel(x,2); } INLINE GEN cert_get_D(GEN x) { GEN N = cert_get_N(x), t = cert_get_t(x); return coredisc(subii(sqri(t), shifti(N, 2))); } INLINE GEN cert_get_m(GEN x) { GEN N = cert_get_N(x), t = cert_get_t(x); return subii(addiu(N, 1), t); } INLINE GEN cert_get_s(GEN x) { return gel(x,3); } INLINE GEN cert_get_q(GEN x) { return diviiexact(cert_get_m(x), cert_get_s(x)); } INLINE GEN cert_get_a4(GEN x) { return gel(x,4); } INLINE GEN cert_get_P(GEN x) { return gel(x,5); } INLINE GEN cert_get_x(GEN x) { return gel(cert_get_P(x), 1); } INLINE GEN cert_get_a6(GEN z) { GEN N = cert_get_N(z), a = cert_get_a4(z), P = cert_get_P(z); GEN x = gel(P,1), xx = Fp_sqr(x, N); GEN y = gel(P,2), yy = Fp_sqr(y, N); return Fp_sub(yy, Fp_mul(x, Fp_add(xx,a,N), N), N); } INLINE GEN cert_get_E(GEN x) { return mkvec2(cert_get_a4(x), cert_get_a6(x)); } INLINE GEN cert_get_J(GEN x) { GEN a = cert_get_a4(x), b = cert_get_a6(x), N = cert_get_N(x); return Fp_ellj(a, b, N); } /* Given J, N, set A = 3*J*(1728-J) mod N, B = 2*J*(1728-J)^2 mod N */ static void Fp_ellfromj(GEN j, GEN N, GEN *A, GEN *B) { GEN k, jk; j = Fp_red(j, N); if (isintzero(j)) { *A = gen_0; *B = gen_1; return; } if (absequalui(umodui(1728,N), j)) { *A = gen_1; *B = gen_0; return; } k = Fp_sub(utoi(1728), j, N); jk = Fp_mul(j, k, N); *A = Fp_mulu(jk, 3, N); *B = Fp_mulu(Fp_mul(j, Fp_sqr(k,N), N), 2, N); } /* "Twist factor". Does not cover J = 0, 1728 */ static GEN cert_get_lambda(GEN z) { GEN N, J, a, b, A, B; J = cert_get_J(z); N = cert_get_N(z); a = cert_get_a4(z); b = cert_get_a6(z); Fp_ellfromj(J, N, &A, &B); return Fp_div(Fp_mul(a,B,N), Fp_mul(b,A,N), N); } /* Solves for T such that if [A, B] = [3*J*(1728-J), 2*J*(1728-J)^2] and you let L = T^3 + A*T + B, A = A*L^2, B = B*L^3 then x == TL and y == L^2 */ static GEN cert_get_T(GEN z) { GEN N = cert_get_N(z), x = cert_get_x(z); GEN l = cert_get_lambda(z); /* l = 1/L */ return Fp_mul(x, l, N); } /* database for all invariants, stolen from Hamish's code */ static GEN polmodular_db_init_allinv(void) { const long DEFAULT_MODPOL_DB_LEN = 32; GEN a, b = cgetg(39+1, t_VEC); long i; for (i = 1; i < 40; i++) gel(b,i) = zerovec_block(DEFAULT_MODPOL_DB_LEN); a = zerovec_block(DEFAULT_MODPOL_DB_LEN); return mkvec2(a, b); } /* Given D and a database of modular polynomials, return polclass(D, inv) */ static GEN D_polclass(long D, long inv, GEN *db) { GEN HD, t = mkvec2(gel(*db, 1), inv == 0? gen_0: gmael(*db, 2, inv)); HD = polclass0(D, inv, 0, &t); gel(*db, 1) = gel(t,1); if (inv != 0) gmael(*db, 2, inv) = gel(t,2); return HD; } static GEN NqE_check(GEN N, GEN q, GEN a, GEN b, GEN s) { GEN mP, sP, P = random_FpE(a, b, N); GEN PJ = mkvec3(gel(P,1), gel(P,2), gen_1); sP = FpJ_mul(PJ, s, a, N); if (FpJ_is_inf(sP)) return NULL; mP = FpJ_mul(sP, q, a, N); return FpJ_is_inf(mP)? mkvec2(a, P): NULL; } /* Find an elliptic curve E modulo N and a point P on E which corresponds to * the ith element of the certificate; uses N, D, m, q, J from previous steps. * All computations are modulo N unless stated otherwise */ /* g is a quadratic and cubic non-residue modulo N */ static GEN j0_find_g(GEN N) { GEN n = diviuexact(subiu(N, 1), 3); for(;;) { GEN g = randomi(N); if (kronecker(g, N) == -1 && !equali1(Fp_pow(g, n, N))) return g; } } static GEN find_EP(GEN N, long D, GEN q, GEN g, GEN J, GEN s) { GEN A0, B0; Fp_ellfromj(J, N, &A0, &B0); for(;;) { /* expect one iteration: not worth saving the A's and B's */ GEN gg, v, A = A0, B = B0; long i; if ((v = NqE_check(N, q, A, B, s))) return v; switch (D_get_wD(D)) { case 2: gg = Fp_sqr(g, N); A = Fp_mul(A, gg, N); B = Fp_mul(Fp_mul(B, gg, N), g, N); if ((v = NqE_check(N, q, A, B, s))) return v; break; case 4: for (i = 1; i < 4; i++) { A = Fp_mul(A, g, N); if ((v = NqE_check(N, q, A, B, s))) return v; } break; default: /* 6 */ B = Fp_mul(B, g, N); if ((v = NqE_check(N, q, A, B, s))) return v; g = j0_find_g(N); for (i = 1; i < 6; i++) { B = Fp_mul(B, g, N); if (i == 3) continue; if ((v = NqE_check(N, q, A, B, s))) return v; } break; } } } /* Convert the disc. factorisation of a genus field to the * disc. factorisation of its real part. */ static GEN realgenusfield(GEN Dfac, GEN sq, GEN p) { long i, j, l = lg(Dfac), dn, n = 0; GEN sn, s = gen_0, R = cgetg(l-1, t_VECSMALL); for (i = 1; i < l; i++) if (Dfac[i] < 0) { n = i; break; } if (n == 0) pari_err_BUG("realgenusfield"); dn = Dfac[n]; sn = gel(sq, n); for (j = i = 1; i < l; i++) if (i != n) { long d = Dfac[i]; GEN si = gel(sq,i); R[j++] = d > 0 ? d : d * dn; s = Fp_add(s, d > 0? si: Fp_mul(si, sn, p), p); } return mkvec2(R, s); } static GEN FpX_classtower_oneroot(GEN P, GEN Dfac, GEN sq, GEN p) { pari_timer ti; pari_sp av = avma; GEN C; dbg_mode() timer_start(&ti); if (degpol(P) > 1) { GEN N = NULL, V = realgenusfield(Dfac, sq, p), v = gel(V,1), R = gel(V,2); long i, l = lg(v); for (i = 1; i < l; i++) { GEN Q = deg2pol_shallow(gen_1, gen_0, stoi(-v[i]), 1); if (!N) N = Q; else { GEN cm = polcompositum0(N,Q,3); N = gel(cm,1); P = gsubst(P, 1, gel(cm,2)); } P = liftpol_shallow(gmael(nffactor(N,P),1,1)); } if (N) { P = FpXY_evalx(Q_primpart(P), R, p); dbg_mode() err_printf(ANSI_BRIGHT_GREEN " %6ld[%ld]" ANSI_RESET, timer_delay(&ti), l-1); } else dbg_mode() err_printf(" "); } C = FpX_oneroot_split(P, p); dbg_mode() err_printf(" %6ld", timer_delay(&ti)); return gerepileupto(av, C); } /* This uses [N, D, m, q] from step 1 to find the appropriate j-invariants * to be used in step 3. Step 2 is divided into substeps 2a, 2b, 2c */ static GEN ecpp_step2(GEN step1, GEN *X0, GEN primelist) { long j, Dprev = 0; pari_timer ti; GEN perm = gen_indexsort(step1, NULL, &sort_NDmq_by_D); GEN step2 = cgetg(lg(step1), t_VEC); GEN HD = NULL, db = polmodular_db_init_allinv(); for (j = 1; j < lg(step2); j++) { long i = uel(perm, j); GEN J, t, s, EP, rt, S = gel(step1, i); GEN N = NDmqg_get_N(S), Dinfo = NDmqg_get_Dinfo(S); GEN m = NDmqg_get_m(S), q = NDmqg_get_q(S); GEN g = NDmqg_get_g(S), sq = NDmqg_get_sqrt(S); long D = Dinfo_get_D(Dinfo), inv = Dinfo_get_bi(Dinfo); GEN Dfacp = Dfac_to_p(Dinfo_get_Dfac(Dinfo), primelist); /* C1: Find the appropriate class polynomial modulo N */ dbg_mode() timer_start(&ti); if (D != Dprev) HD = D_polclass(D, inv, &db); dbg_mode() { long tt = timer_record(X0, "C1", &ti); err_printf(ANSI_BRIGHT_GREEN "\n[ %3d | %4ld bits]" ANSI_RESET, i, expi(N)); err_printf(ANSI_GREEN " D = %8ld poldeg = %4ld" ANSI_RESET, D, degpol(HD)); if (D == Dprev) err_printf(" %6ld", tt); else err_printf(ANSI_BRIGHT_WHITE " %6ld" ANSI_RESET, tt); } /* C2: Find a root modulo N of polclass(D,inv) */ dbg_mode() timer_start(&ti); rt = FpX_classtower_oneroot(HD, Dfacp, sq, N); dbg_mode() err_printf(" %6ld", timer_record(X0, "C2", &ti)); /* C3: Convert root from previous step into the appropriate j-invariant */ dbg_mode() timer_start(&ti); J = Fp_modinv_to_j(rt, inv, N); /* root of polclass(D) */ dbg_mode() err_printf(" %6ld", timer_record(X0, "C3", &ti)); /* D1: Find an elliptic curve E with a point P satisfying the theorem */ dbg_mode() timer_start(&ti); s = diviiexact(m, q); EP = find_EP(N, D, q, g, J, s); dbg_mode() err_printf(" %6ld", timer_record(X0, "D1", &ti)); /* D2: Compute for t and s */ t = subii(addiu(N, 1), m); /* t = N+1-m */ gel(step2, i) = mkvec5(N, t, s, gel(EP,1), gel(EP,2)); Dprev = D; } gunclone_deep(db); return step2; } /* end of functions for step 2 */ /* start of functions for step 1 */ /* This finds the square root of D modulo N [given by Dfac]: find the square * root modulo N of each prime p dividing D and multiply them out */ static GEN D_find_discsqrt(GEN N, GEN primelist, GEN Dfac, GEN sqrtlist, GEN g) { GEN s = NULL; long i, l = lg(Dfac); for (i = 1; i < l; i++) { long j = Dfac[i]; GEN sj = gel(sqrtlist,j); if (!signe(sj)) { GEN p = stoi(primelist[j]); dbg_mode() err_printf(ANSI_MAGENTA "S" ANSI_RESET); /* A4: Get the square root of a prime factor of D. */ sj = gel(sqrtlist, j) = Fp_sqrt_i(p, g, N); if (!sj) pari_err_BUG("D_find_discsqrt"); ; /* possible if N composite */ } s = s? Fp_mul(s, sj, N): sj; } return s;/* != NULL */ } /* Given a solution U, V to U^2 + |D|V^2 = 4N, this find all the possible cardinalities of the elliptic curves over the finite field F_N whose endomorphism ring is isomorphic to the maximal order in the imaginary quadratic number field K = Q(sqrt(D)). ??? */ static GEN NUV_find_m(GEN Dinfo, GEN N, GEN U, GEN V, long wD) { GEN m, Nplus1 = addiu(N, 1), u = U, mvec = cgetg(wD+1, t_VEC); long i; for (i = 0; i < wD; i++) { if (odd(i)) m = subii(Nplus1, u); else { if (wD == 4 && i==2) u = shifti(V, 1); else if (wD == 6 && i==2) u = shifti(submuliu(U, V, 3), -1); else if (wD == 6 && i==4) u = shifti(addmuliu(U, V, 3), -1); m = addii(Nplus1, u); } gel(mvec, i+1) = mkvec2(Dinfo, m); } return mvec; } /* Populates Dmbatch with Dmvec's -- whose components are of the form [D,m], where m is a cardinalities of an elliptic curve with endomorphism ring isomorphic to the maximal order of imaginary quadratic K = Q(sqrt(D)). It returns 0 if: * Any of the p* dividing D is not a quadratic residue mod N * Cornacchia cannot find a solution U^2 + |D|V^2 = 4N. Otherwise, it returns the number of cardinalities added to Dmbatch. Finally, sqrtlist and g help compute the square root modulo N of D. */ static long D_collectcards(GEN N, GEN param, GEN* X0, GEN Dinfo, GEN sqrtlist, GEN g, GEN Dmbatch, GEN kroP) { long i, l, corn_succ, wD, D = Dinfo_get_D(Dinfo); GEN U, V, sqrtofDmodN, Dfac = Dinfo_get_Dfac(Dinfo); GEN primelist = ecpp_param_get_primelist(param); pari_timer ti; /* A1: Check (p*|N) = 1 for all primes dividing D */ l = lg(Dfac); for (i = 1; i < l; i++) { long j = Dfac[i], s = kroP[j]; if (s > 1) kroP[j] = s = krosi(primelist[j], N); /* update cache */ if (s == 0) return -1; /* N is composite */ if (s < 0) return 0; } /* A3: Get square root of D mod N */ dbg_mode() timer_start(&ti); sqrtofDmodN = D_find_discsqrt(N, primelist, Dfac, sqrtlist, g); dbg_mode() timer_record(X0, "A3", &ti); /* A5: Use square root with Cornacchia to solve U^2 + |D|V^2 = 4N */ dbg_mode() timer_start(&ti); corn_succ = cornacchia2_sqrt( utoi(labs(D)), N, sqrtofDmodN, &U, &V); dbg_mode() timer_record(X0, "A5", &ti); if (!corn_succ) { dbg_mode() err_printf(ANSI_YELLOW "c" ANSI_RESET); return 0; } /* A6: Collect the w(D) cardinalities of E/(F_N) with CM by D */ dbg_mode() err_printf(ANSI_BRIGHT_YELLOW "D" ANSI_RESET); wD = D_get_wD(D); vectrunc_append_batch(Dmbatch, NUV_find_m(Dinfo,N,U,V,wD)); return wD; } /* Compute (S(16N, 2) + S(4096N, 4) + 4)\4 + 1, where S is the nth root * rounded down. This is at most one more than (N^1/4 + 1)^2. */ static GEN ecpp_qlo(GEN N) { GEN a = sqrtnint(shifti(N, 4), 2); GEN b = sqrtnint(shifti(N, 12), 4); return addiu(shifti(addii(a, b), -2), 2); } static long lessthan_qlo(void* E, GEN Dmq) { return (cmpii(gel(Dmq,3), (GEN)E) < 0); } static long gained_bits(void* E, GEN Dmq) { return (expi(gel(Dmq,3)) <= (long)E); } /* Input: Dmqvec * Output: Dmqvec such that q satisfies (N^1/4 + 1)^2 < q < N/2 */ static GEN Dmqvec_slice(GEN N, GEN Dmqvec) { long lo, hi; gen_sort_inplace(Dmqvec, NULL, &sort_Dmq_by_q, NULL); /* sort wrt q */ lo = zv_binsearch0((void*)ecpp_qlo(N), &lessthan_qlo, Dmqvec); lo++; if (lo >= lg(Dmqvec)) return NULL; hi = zv_binsearch0((void*)(expi(N)-1), &gained_bits, Dmqvec); if (hi == 0) return NULL; return vecslice(Dmqvec, lo, hi); } /* Given a Dmvec of [D,m]'s, simultaneously remove all prime factors of each * m less then BOUND_PRIMORIAL. This implements Franke 2004: Proving the * Primality of Very Large Numbers with fastECPP */ static GEN Dmvec_batchfactor(GEN Dmvec, GEN primorial) { long i, l = lg(Dmvec); GEN leaf, v = cgetg(l, t_VEC); for (i = 1; i < l; i++) { /* cheaply remove powers of 2 */ GEN m = gmael(Dmvec, i, 2); long v2 = vali(m); gel(v,i) = v2? shifti(m,-v2): m; } leaf = Z_ZV_mod_tree(primorial, v, ZV_producttree(v)); /* Go through each leaf and remove small factors. */ for (i = 1; i < l; i++) { GEN q = gel(v,i), Dm = gel(Dmvec,i), L = gel(leaf,i); while (!equali1(L)) { L = gcdii(q, L); q = diviiexact(q, L); } gel(v,i) = mkvec3(gel(Dm,1), gel(Dm,2), q); } return v; } /* return good parameters [maxsqrt, maxpcdg, tdivexp] for ecpp(N) */ static GEN tunevec(long expiN, GEN param) { GEN T = ecpp_param_get_tune(param); long i, n = lg(T)-1; for (i = 1; i < n; i++) { GEN x = gel(T,i); if (expiN <= x[4]) return x; } return gel(T,n); } static long tunevec_tdivbd(long expiN, GEN param) { return uel(tunevec(expiN, param), 3); } static long tunevec_batchsize(long expiN, GEN param) { long t, b = 28 - tunevec_tdivbd(expiN, param); if (b < 0) return expiN; t = expiN >> b; return t < 1? 1: t; } static GEN Dmbatch_factor_Dmqvec(GEN N, long expiN, GEN* X0, GEN Dmbatch, GEN param) { pari_sp av = avma; pari_timer ti; GEN Dmqvec, primorial_vec = ecpp_param_get_primorial_vec(param); GEN primorial = gel(primorial_vec, tunevec_tdivbd(expiN, param)-19); /* B1: Factor by batch */ dbg_mode() timer_start(&ti); Dmqvec = Dmvec_batchfactor(Dmbatch, primorial); dbg_mode() timer_record(X0, "B1", &ti); /* B2: For each batch, remove cardinalities lower than (N^(1/4)+1)^2 * and cardinalities in which we didn't win enough bits */ Dmqvec = Dmqvec_slice(N, Dmqvec); if (!Dmqvec) { avma = av; return NULL; } /* nothing is left */ return gerepilecopy(av, Dmqvec); } /* Dmq (where q has no small prime factors): determine if q is pseudoprime */ static long Dmq_isgoodq(GEN Dmq, GEN* X0) { pari_timer ti; long s; /* B3: Check pseudoprimality of each q on the list. */ dbg_mode() timer_start(&ti); s = BPSW_psp_nosmalldiv(gel(Dmq,3)); dbg_mode() timer_record(X0, "B3", &ti); return s; /* did not find for this m */ } static GEN mkNDmqg(GEN z, GEN N, GEN Dmq, GEN g, GEN sqrtlist) { GEN Dinfo = gel(Dmq,1), sq = Dfac_to_roots(Dinfo_get_Dfac(Dinfo),sqrtlist); GEN NDmqg = mkcol6(N, Dinfo, gel(Dmq,2), gel(Dmq,3), g, sq); return mkvec2(NDmqg, z); } /* expi(N) > 64. Return [ NDmqg, N_downrun(q) ]; NDmqg is a vector of the form * [N,D,m,q,g,sqrt]. For successive D, find a square root of D mod N (g is a * quadratic non-residue), solve U^2 + |D|V^2 = 4N, then find candidates for m. * When enough m's, batch-factor them to produce the q's. If one of the q's is * pseudoprime, recursive call with N = q. May return gen_0 at toplevel * => N has a small prime divisor */ static GEN N_downrun(GEN N, GEN param, GEN *X0, long *depth, long persevere) { pari_timer T, ti; long lgdisclist, lprimelist, t, i, j, expiN = expi(N); long persevere_next = 0, FAIL = 0; ulong maxpcdg; GEN primelist, disclist, sqrtlist, g, Dmbatch, kroP; dbg_mode() timer_start(&T); (*depth)++; /* we're going down the tree. */ maxpcdg = ecpp_param_get_maxpcdg(param); primelist = ecpp_param_get_primelist(param); disclist = ecpp_param_get_disclist(param); lgdisclist = lg(disclist); t = tunevec_batchsize(expiN, param); /* Precomputation for taking square roots, g needed for Fp_sqrt_i */ g = Fp_2gener(N); if (!g) return gen_0; /* Composite if this happens. */ /* Initialize sqrtlist for this N. */ lprimelist = lg(primelist); sqrtlist = zerovec(lprimelist-1); /* A2: Check (p*|N) = 1 for all p */ dbg_mode() timer_start(&ti); /* kroP[i] will contain (primelist[i] | N) */ kroP = const_vecsmall(lprimelist-1, 2/*sentinel*/); switch(mod8(N)) { /* primelist[1,2,3] = [8,-4,-8]; N is odd */ case 1: kroP[1] = kroP[2] = kroP[3] = 1; break; case 3: kroP[1] = -1; kroP[2] =-1; kroP[3] = 1; break; case 5: kroP[1] = -1; kroP[2] = 1; kroP[3] =-1; break; case 7: kroP[1] = 1; kroP[2] =-1; kroP[3] =-1; break; } dbg_mode() timer_record(X0, "A2", &ti); /* Print the start of this iteration. */ dbg_mode() { char o = persevere? '<': '['; char c = persevere? '>': ']'; err_printf(ANSI_BRIGHT_CYAN "\n%c %3d | %4ld bits%c " ANSI_RESET, o, *depth, expiN, c); } /* Initialize Dmbatch, populated with candidate cardinalities in Phase I * (until #Dmbatch >= t); its elements will be factored on Phase II */ Dmbatch = vectrunc_init(t+7); /* Number of cardinalities so far; should always be equal to lg(Dmbatch)-1. */ /* i determines which discriminant we are considering. */ i = 1; while (!FAIL) { pari_timer F; long lgDmqlist, last_i = i, numcard = 0; /* #Dmbatch */ GEN Dmqlist; /* Dmbatch begins "empty", but keep the allocated memory. */ setlg(Dmbatch, 1); /* PHASE I: Go through the D's and search for candidate m's. * Fill up Dmbatch until there are at least t elements. */ while (i < lgdisclist ) { GEN Dinfo = gel(disclist, i); long n; if (!persevere && Dinfo_get_pd(Dinfo) > maxpcdg) { FAIL = 1; break; } n = D_collectcards(N,param, X0, Dinfo, sqrtlist, g, Dmbatch, kroP); if (n < 0) return gen_0; last_i = i++; numcard += n; if (numcard >= t) break; } /* We have exhausted disclist and there are no card. to be factored */ if (numcard <= 0 && (FAIL || i >= lgdisclist)) break; /* PHASE II: Find the corresponding q's for the m's found. Use Dmbatch */ /* Find coresponding q of the candidate m's. */ dbg_mode() timer_start(&F); Dmqlist = Dmbatch_factor_Dmqvec(N, expiN, X0, Dmbatch, param); if (Dmqlist == NULL) continue; /* none left => next discriminant. */ /* If we are cheating by adding class numbers, sort by class number */ if (Dinfo_get_pd(gel(disclist, last_i)) > maxpcdg) gen_sort_inplace(Dmqlist, NULL, &sort_Dmq_by_cnum, NULL); /* Check pseudoprimality before going down. */ lgDmqlist = lg(Dmqlist); for (j = 1; j < lgDmqlist; j++) { GEN z, Dmq = gel(Dmqlist,j), q = gel(Dmq,3); dbg_mode() err_printf(ANSI_WHITE "." ANSI_RESET); if (!Dmq_isgoodq(Dmq, X0)) continue; dbg_mode() { err_printf(ANSI_BRIGHT_RED "\n %5ld bits " ANSI_RESET, expi(q)-expiN); err_printf(" D = %ld", Dmq_get_D(Dmq)); err_printf(ANSI_BRIGHT_BLUE " h = %ld" ANSI_RESET, Dmq_get_h(Dmq)); } /* q is pseudoprime */ if (expi(q) < 64) z = gen_1; /* q is prime; sentinel */ else { z = N_downrun(q, param, X0, depth, persevere_next); if (!z) { dbg_mode() { char o = persevere? '<': '[', c = persevere? '>': ']'; err_printf(ANSI_CYAN "\n%c %3d | %4ld bits%c " ANSI_RESET, o, *depth, expiN, c); } continue; /* downrun failed */ } } return mkNDmqg(z, N, Dmq, g, sqrtlist); /* SUCCESS */ } if (i >= lgdisclist) break; /* discriminants exhausted: FAIL */ if (Dinfo_get_pd(gel(disclist, last_i)) > maxpcdg) { dbg_mode() err_printf(ANSI_BRIGHT_RED " !" ANSI_RESET); persevere_next = 1; } } /* FAILED: Out of discriminants. */ umael(*X0, 3, 1)++; /* FAILS++ */ dbg_mode() err_printf(ANSI_BRIGHT_RED " X" ANSI_RESET); (*depth)--; return NULL; } /* x: the output of the (recursive) downrun function; return a vector * whose components are [N, D, m, q, g] */ static GEN ecpp_flattencert(GEN x, long depth) { long i, l = depth+1; GEN ret = cgetg(l, t_VEC); if (typ(x) != t_VEC) return gen_0; for (i = 1; i < l; i++) { gel(ret, i) = gel(x,1); x = gel(x,2); } return ret; } /* Call the first downrun then unravel the skeleton of the certificate. * Assume expi(N) < 64. This returns one of the following: * - a vector of the form [N, D, m, q, y] * - gen_0 (if N is composite) * - NULL (if FAIL) */ static GEN ecpp_step1(GEN N, GEN param, GEN* X0) { pari_sp av = avma; long depth = 0; GEN downrun = N_downrun(N, param, X0, &depth, 1); if (downrun == NULL) { avma = av; return NULL; } return gerepilecopy(av, ecpp_flattencert(downrun, depth)); } /* The input is an integer N. It uses the precomputation step0 done in ecpp_step0. */ static GEN ecpp0(GEN N, GEN param) { GEN step1, answer, Tv, Cv, X0; pari_sp av = avma; long i, j; /* Check if N is pseudoprime to begin with. */ if (!BPSW_psp(N)) return gen_0; /* Check if we should even prove it. */ if (expi(N) < 64) return N; /* Timers and Counters */ Tv = mkvec4(zero_zv(5), zero_zv(3), zero_zv(3), zero_zv(1)); Cv = mkvec4(zero_zv(5), zero_zv(3), zero_zv(3), zero_zv(1)); X0 = mkvec3(Tv, Cv, zero_zv(1)); step1 = ecpp_step1(N, param, &X0); if (step1 == NULL) { avma = av; return NULL; } if (typ(step1) != t_VEC) { avma = av; return gen_0; } answer = ecpp_step2(step1, &X0, ecpp_param_get_primelist(param)); dbg_mode() { for (i = 1; i < lg(Tv); i++) { GEN v = gel(Tv, i); long l = lg(v); for (j = 1; j < l; j++) { long t = umael3(X0,1, i,j), n = umael3(X0,2, i,j); if (!t) continue; err_printf("\n %c%ld: %16ld %16ld %16.3f", 'A'+i-1,j, t,n, (double)t/n); } } err_printf("\n" ANSI_BRIGHT_RED "\nFAILS: %16ld" ANSI_RESET "\n", umael(X0, 3, 1)); } return gerepilecopy(av, answer); } static const long ecpp_tune[][4]= { { 100, 2, 20, 500 }, { 350, 14, 21, 1000 }, { 450, 18, 21, 1500 }, { 750, 22, 22, 2000 }, { 900, 26, 23, 2500 }, { 1000, 32, 23, 3000 }, { 1200, 38, 24, 3500 }, { 1400, 44, 24, 4000 }, { 1600, 50, 24, 4500 }, { 1800, 56, 25, 5000 }, { 2000, 62, 25, 5500 }, { 2200, 68, 26, 6000 }, { 2400, 74, 26, 6500 }, { 2600, 80, 26, 7000 }, { 2800, 86, 26, 7500 }, { 3000, 92, 27, 8000 }, { 3200, 98, 27, 8500 }, { 3400, 104, 28, 9000 }, { 3600, 110, 28, 9500 }, { 3800, 116, 29, 10000 }, { 4000, 122, 29, 0 } }; /* assume N BPSW-pseudoprime */ GEN ecpp(GEN N) { long expiN, i, tunelen; GEN tune; /* Check if we should even prove it. */ expiN = expi(N); if (expiN < 64) return N; tunelen = (expiN+499)/500; tune = cgetg(tunelen+1, t_VEC); for (i = 1; i <= tunelen && ecpp_tune[i-1][3]; i++) gel(tune,i) = mkvecsmall4(ecpp_tune[i-1][0], ecpp_tune[i-1][1], ecpp_tune[i-1][2], ecpp_tune[i-1][3]); for (; i <= tunelen; i++) gel(tune,i) = mkvecsmall4(200*(i-1),6*i-4,30,500*i); for(;;) { GEN C, param, x = gel(tune, tunelen); pari_timer T; dbg_mode() timer_start(&T); param = ecpp_param_set(tune, x); dbg_mode() { err_printf(ANSI_BRIGHT_WHITE "\n%Ps" ANSI_RESET, x); err_printf(ANSI_WHITE " %8ld" ANSI_RESET, timer_delay(&T)); } if ((C = ecpp0(N, param))) return C; x[1] *= 2; x[2] *= 2; x[3] = minss(x[3]+1, 30); } } long isprimeECPP(GEN N) { pari_sp av = avma; GEN res; if (!BPSW_psp(N)) return 0; res = ecpp(N); avma = av; return !isintzero(res); } /* PARI ECPP Certificate -> Human-readable format */ static GEN cert_out(GEN x) { long i, l = lg(x); pari_str str; str_init(&str, 1); if (typ(x) == t_INT) { str_printf(&str, "%Ps is prime.\nIndeed, ispseudoprime(%Ps) = 1 and %Ps < 2^64.\n", x, x, x); return strtoGENstr(str.string); } for (i = 1; i < l; i++) { GEN xi = gel(x, i); str_printf(&str, "[%ld]\n", i); str_printf(&str, " N = %Ps\n", cert_get_N(xi)); str_printf(&str, " t = %Ps\n", cert_get_t(xi)); str_printf(&str, " s = %Ps\n", cert_get_s(xi)); str_printf(&str, "a4 = %Ps\n", cert_get_a4(xi)); str_printf(&str, "D = %Ps\n", cert_get_D(xi)); str_printf(&str, "m = %Ps\n", cert_get_m(xi)); str_printf(&str, "q = %Ps\n", cert_get_q(xi)); str_printf(&str, "E = %Ps\n", cert_get_E(xi)); str_printf(&str, "P = %Ps\n", cert_get_P(xi)); } return strtoGENstr(str.string); } /* PARI ECPP Certificate -> Magma Certificate * [* [* * N, |D|, -1, m, * [* a, b *], * [* x, y, 1 *], * [* [* q, 1 *] *] * *], ... *] */ static GEN magma_out(GEN x) { long i, n = lg(x)-1; pari_str ret; str_init(&ret, 1); if (typ(x) == t_INT) { str_printf(&ret, "Operation not supported."); return strtoGENstr(ret.string); } str_printf(&ret, "[* "); for (i = 1; i<=n; i++) { GEN xi = gel(x,i), E = cert_get_E(xi), P = cert_get_P(xi); str_printf(&ret, "[* %Ps, %Ps, -1, %Ps, ", cert_get_N(xi), negi(cert_get_D(xi)), cert_get_m(xi)); str_printf(&ret, "[* %Ps, %Ps *], ", gel(E,1), gel(E,2)); str_printf(&ret, "[* %Ps, %Ps, 1 *], ", gel(P,1), gel(P,2)); str_printf(&ret, "[* [* %Ps, 1 *] *] *]", cert_get_q(xi)); if (i != n) str_printf(&ret, ", "); } str_printf(&ret, " *]"); return strtoGENstr(ret.string); } /* Prints: label=(sign)hexvalue\n * where sign is + or - * hexvalue is value in hex, of the form: 0xABC123 */ static void primo_printval(pari_str *ret, const char* label, GEN value) { str_printf(ret, label); if (signe(value) >= 0) str_printf(ret, "=0x%P0X\n", value); else str_printf(ret, "=-0x%P0X\n", negi(value)); } /* Input: PARI ECPP Certificate / Output: PRIMO Certificate * * Let Y^2 = X^3 + aX + b be the elliptic curve over N with the point (x,y) * as described in the PARI certificate. * * If J != 0, 1728, PRIMO asks for [J,T], where T = a/A * B/b * x, * A = 3J(1728-J) and B = 2J(1728-J)^2. * * If J=0 or J=1728, PRIMO asks for [A,B,T]; we let A=a and B=b => T = x */ static GEN primo_out(GEN x) { long i, l = (typ(x) == t_INT) ? 1 : lg(x); pari_str ret; str_init(&ret, 1); str_printf(&ret, "[PRIMO - Primality Certificate]\nFormat=4\n"); str_printf(&ret, "TestCount=%ld\n\n[Comments]\n", l-1); str_printf(&ret, "Generated by %s\n",paricfg_version); str_printf(&ret, "https://pari.math.u-bordeaux.fr/\n\n[Candidate]\n"); if (typ(x) == t_INT) { str_printf(&ret, "N=0x%P0X\n", x); return strtoGENstr(ret.string); } str_printf(&ret, "N=0x%P0X\n\n", cert_get_N(gel(x,1))); for (i = 1; i < l; i++) { GEN a4, a6, N, Nover2, xi = gel(x,i); long Ais0, Bis0; str_printf(&ret, "[%ld]\n", i); N = cert_get_N(xi); Nover2 = shifti(N, -1); primo_printval(&ret, "S", cert_get_s(xi)); primo_printval(&ret, "W", cert_get_t(xi)); a4 = cert_get_a4(xi); Ais0 = isintzero(a4); a6 = cert_get_a6(xi); Bis0 = isintzero(a6); if (!Ais0 && !Bis0) { /* J != 0, 1728 */ primo_printval(&ret, "J", Fp_center_i(cert_get_J(xi), N, Nover2)); primo_printval(&ret, "T", cert_get_T(xi)); } else { if (!Ais0) a4 = Fp_center_i(a4, N, Nover2); if (!Bis0) a6 = Fp_center_i(a6, N, Nover2); primo_printval(&ret, "A", a4); primo_printval(&ret, "B", a6); primo_printval(&ret, "T", cert_get_x(xi)); } str_printf(&ret, "\n"); } return strtoGENstr(ret.string); } /* return 1 if q > (N^1/4 + 1)^2, 0 otherwise */ static long Nq_isvalid(GEN N, GEN q) { GEN c = subii(sqri(subiu(q,1)), N); if (signe(c) <= 0) return 0; /* (q-1)^2 > N; check that (N - (q-1)^2)^2 > 16Nq */ return (cmpii(sqri(c), shifti(mulii(N,q), 4)) > 0); } /* return 1 if 'cert' is a valid PARI ECPP certificate */ static long ecppisvalid_i(GEN cert) { const long trustbits = 64;/* a pseudoprime < 2^trustbits is prime */ long i, lgcert = lg(cert); GEN ql, q = gen_0; if (typ(cert) == t_INT) { if (expi(cert) >= trustbits) return 0; /* >= 2^trustbits */ return BPSW_psp(cert); } if (typ(cert) != t_VEC || lgcert <= 1) return 0; ql = gel(cert, lgcert-1); if (lg(ql)-1 != 5) return 0; ql = cert_get_q(ql); if (expi(ql) >= trustbits || !BPSW_psp(ql)) return 0; for (i = 1; i < lgcert; i++) { GEN N, W, mP, sP, r, m, s, a, P, certi = gel(cert, i); if (lg(certi)-1 != 5) return 0; N = cert_get_N(certi); if (typ(N) != t_INT || signe(N) <= 0) return 0; switch(umodiu(N,6)) { case 1: case 5: break; /* Check if N is not divisible by 2 or 3 */ default: return 0; } /* Check if N matches the q from the previous entry. */ if (i > 1 && !equalii(N, q)) return 0; W = cert_get_t(certi); if (typ(W) != t_INT) return 0; /* Check if W^2 < 4N (Hasse interval) */ if (!(cmpii(sqri(W), shifti(N,2)) < 0)) return 0; s = cert_get_s(certi); if (typ(s) != t_INT || signe(s) < 0) return 0; m = cert_get_m(certi); q = dvmdii(m, s, &r); /* Check m%s == 0 */ if (!isintzero(r)) return 0; /* Check q > (N^(1/4) + 1)^2 */ if (!Nq_isvalid(N, q)) return 0; a = cert_get_a4(certi); if (typ(a) != t_INT) return 0; P = cert_get_P(certi); if (typ(P) != t_VEC || lg(P) != 3) return 0; P = FpE_to_FpJ(P); /* Check mP == 0 */ mP = FpJ_mul(P, m, a, N); if (!FpJ_is_inf(mP)) return 0; /* Check sP != 0 and third component is coprime to N */ sP = FpJ_mul(P, s, a, N); if (!isint1(gcdii(gel(sP, 3), N))) return 0; } return 1; } long ecppisvalid(GEN cert) { pari_sp av = avma; long v = ecppisvalid_i(cert); avma = av; return v; } GEN ecppexport(GEN cert, long flag) { switch(flag) { case 0: return cert_out(cert); case 1: return primo_out(cert); case 2: return magma_out(cert); } pari_err_FLAG("primecertexport"); return NULL;/*LCOV_EXCL_LINE*/ } pari-2.11.2/src/basemath/Ser.c0000644000175000017500000001504513447371554014450 0ustar billbill/* Copyright (C) 2000, 2012 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* Conversion --> t_SER */ /* */ /*******************************************************************/ static GEN RgX_to_ser_i(GEN x, long l, long lx, long v, int copy) { GEN y; long i; if (lx == 2) return zeroser(varn(x), l-2); if (l < 2) pari_err_BUG("RgX_to_ser (l < 2)"); y = cgetg(l,t_SER); y[1] = x[1]; /* e.g. Mod(0,3) * x^0 */ if (v == LONG_MAX) { v = 1; lx = 3; } else { x += v; lx = minss(lx-v, l); } setvalp(y, v); if (copy) for (i = 2; i = 0 */ GEN sertoser(GEN x, long prec) { long i, lx = lg(x), l; GEN y; if (lx == 2) return zeroser(varn(x), prec); l = prec+2; lx = minss(lx, l); y = cgetg(l,t_SER); y[1] = x[1]; for (i = 2; i < lx; i++) gel(y,i) = gel(x,i); for ( ; i < l; i++) gel(y,i) = gen_0; return y; } /* R(1/x) + O(x^N) */ GEN rfracrecip_to_ser_absolute(GEN R, long N) { GEN n = gel(R,1), d = gel(R,2); long vx = varn(d), vn, v, dn; if (typ(n) != t_POL || varn(n) != vx) { vn = 0; dn = 0; } else { vn = RgX_valrem(n, &n); n = RgX_recip(n); dn = degpol(n); } v = vn - RgX_valrem(d, &d); d = RgX_recip(d); R = gdiv(n, RgX_to_ser(d, N+2)); setvalp(R, valp(R) + degpol(d)-dn-v); return R; } /* assume prec >= 0 */ GEN scalarser(GEN x, long v, long prec) { long i, l; GEN y; if (gequal0(x)) { if (isrationalzero(x)) return zeroser(v, prec); if (!isexactzero(x)) prec--; y = cgetg(3, t_SER); y[1] = evalsigne(0) | _evalvalp(prec) | evalvarn(v); gel(y,2) = gcopy(x); return y; } l = prec + 2; y = cgetg(l, t_SER); y[1] = evalsigne(1) | _evalvalp(0) | evalvarn(v); gel(y,2) = gcopy(x); for (i=3; i 0) return scalarser(x, v, prec); return RgX_to_ser_i(x, prec+2, lg(x), RgX_val(x), 1); } /* x a t_RFRAC */ static GEN rfractoser(GEN x, long v, long prec) { long s = varncmp(varn(gel(x,2)), v); pari_sp av; if (s < 0) err_ser_priority(x,v); if (s > 0) return scalarser(x, v, prec); av = avma; return gerepileupto(av, rfrac_to_ser(x, prec+2)); } GEN toser_i(GEN x) { switch(typ(x)) { case t_SER: return x; case t_POL: return RgX_to_ser(x, precdl+2); case t_RFRAC: return rfrac_to_ser(x, precdl+2); } return NULL; } /* conversion: prec ignored if t_VEC or t_SER in variable v */ GEN gtoser(GEN x, long v, long prec) { long tx = typ(x); if (v < 0) v = 0; if (prec < 0) pari_err_DOMAIN("Ser", "precision", "<", gen_0, stoi(prec)); if (tx == t_SER) { long s = varncmp(varn(x), v); if (s < 0) return coefstoser(x, v, prec); else if (s > 0) return scalarser(x, v, prec); return gcopy(x); } if (is_scalar_t(tx)) return scalarser(x,v,prec); switch(tx) { case t_POL: return poltoser(x, v, prec); case t_RFRAC: return rfractoser(x, v, prec); case t_QFR: case t_QFI: return RgV_to_ser_i(x, v, 4+1, 1); case t_VECSMALL: x = zv_to_ZV(x);/*fall through*/ case t_VEC: case t_COL: if (varncmp(gvar(x), v) <= 0) pari_err_PRIORITY("Ser", x, "<=", v); return RgV_to_ser_i(x, v, lg(x)+1, 1); } pari_err_TYPE("Ser",x); return NULL; /* LCOV_EXCL_LINE */ } /* impose prec */ GEN gtoser_prec(GEN x, long v, long prec) { pari_sp av = avma; if (v < 0) v = 0; if (prec < 0) pari_err_DOMAIN("Ser", "precision", "<", gen_0, stoi(prec)); switch(typ(x)) { case t_SER: if (varn(x) != v) break; return gerepilecopy(av, sertoser(x, prec)); case t_QFR: case t_QFI: x = RgV_to_ser_i(mkvec3(gel(x,1),gel(x,2),gel(x,3)), v, prec+2, 1); return gerepileupto(av, x); case t_VECSMALL: x = zv_to_ZV(x);/*fall through*/ case t_VEC: case t_COL: if (varncmp(gvar(x), v) <= 0) pari_err_PRIORITY("Ser", x, "<=", v); return RgV_to_ser_i(x, v, prec+2, 1); } return gtoser(x, v, prec); } GEN Ser0(GEN x, long v, GEN d, long prec) { if (!d) return gtoser(x, v, prec); if (typ(d) != t_INT) { d = gceil(d); if (typ(d) != t_INT) pari_err_TYPE("Ser [precision]",d); } return gtoser_prec(x, v, itos(d)); } pari-2.11.2/src/basemath/F2x.c0000644000175000017500000017350613457566440014366 0ustar billbill/* Copyright (C) 2007 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Not so fast arithmetic with polynomials over F_2 */ /***********************************************************************/ /** **/ /** F2x **/ /** **/ /***********************************************************************/ /* F2x objects are defined as follows: An F2x is a t_VECSMALL: x[0] = codeword x[1] = evalvarn(variable number) (signe is not stored). x[2] = a_0...a_31 x[3] = a_32..a_63, etc. on 32bit x[2] = a_0...a_63 x[3] = a_64..a_127, etc. on 64bit where the a_i are bits. signe(x) is not valid. Use lgpol(x)!=0 instead. Note: pol0_F2x=pol0_Flx and pol1_F2x=pol1_Flx */ INLINE long F2x_degree_lg(GEN x, long l) { return (l==2)?-1:bit_accuracy(l)-bfffo(x[l-1])-1; } long F2x_degree(GEN x) { return F2x_degree_lg(x, lg(x)); } GEN monomial_F2x(long d, long vs) { long l=nbits2lg(d+1); GEN z = zero_zv(l-1); z[1] = vs; F2x_set(z,d); return z; } GEN F2x_to_ZX(GEN x) { long l=3+F2x_degree(x); GEN z=cgetg(l,t_POL); long i,j,k; for(i=2,k=2;i=3)|x[1]; return z; } GEN F2x_to_Flx(GEN x) { long l=3+F2x_degree(x); GEN z=cgetg(l,t_VECSMALL); long i,j,k; z[1]=x[1]; for(i=2,k=2;i>j)&1UL; return z; } GEN F2x_to_F2xX(GEN z, long sv) { long i, d = F2x_degree(z); GEN x = cgetg(d+3,t_POL); for (i=0; i<=d; i++) gel(x,i+2) = F2x_coeff(z,i) ? pol1_F2x(sv): pol0_F2x(sv); x[1] = evalsigne(d+1!=0)| z[1]; return x; } GEN Z_to_F2x(GEN x, long v) { long sv = evalvarn(v); return mpodd(x) ? pol1_F2x(sv): pol0_F2x(sv); } GEN ZX_to_F2x(GEN x) { long l=nbits2lg(lgpol(x)); GEN z=cgetg(l,t_VECSMALL); long i,j,k; z[1]=((ulong)x[1])&VARNBITS; for(i=2, k=1,j=BITS_IN_LONG;i> 32; #endif c ^= c >> 16; c ^= c >> 8; c ^= c >> 4; c ^= c >> 2; c ^= c >> 1; return c & 1; } else return F2x_coeff(P,0); } GEN F2x_add(GEN x, GEN y) { long i,lz; GEN z; long lx=lg(x); long ly=lg(y); if (ly>lx) swapspec(x,y, lx,ly); lz = lx; z = cgetg(lz, t_VECSMALL); z[1]=x[1]; for (i=2; ilx) swapspec(x,y, lx,ly); lz = lx+2; z = cgetg(lz, t_VECSMALL) + 2; for (i=0; i>dc; yi = uel(y,i+1); x[i+1] ^= (yi<>dc; yi = uel(y,i+2); x[i+2] ^= (yi<>dc; yi = uel(y,i+3); x[i+3] ^= (yi<>dc; } for( ; i>dc; } if (r) x[i] ^= r; } else { for(i=0; i>BITS_IN_HALFULONG; ulong x2=x&LOWMASK; ulong y1=(y&HIGHMASK)>>BITS_IN_HALFULONG; ulong y2=y&LOWMASK; ulong r1,r2,rr; GEN z; ulong i; rr=r1=r2=0UL; if (x2) for(i=0;i>BITS_IN_HALFULONG; z=cgetg((r1?4:3),t_VECSMALL); z[2]=r2; if (r1) z[3]=r1; return z; } static GEN F2x_mulspec_basecase(GEN x, GEN y, long nx, long ny) { long l, i, j; GEN z; l = nx + ny; z = zero_Flv(l+1); for(i=0; i < ny-1; i++) { GEN zi = z+2+i; ulong yi = uel(y,i); if (yi) for(j=0; j < BITS_IN_LONG; j++) if (yi&(1UL<nx)? ny+2: nx+d+2; (void)new_chunk(lz); xd = x+nx; yd = y+ny; while (xd > x) *--zd = *--xd; x = zd + a; while (zd > x) *--zd = 0; } else { xd = new_chunk(d); yd = y+d; x = F2x_addspec(x,yd,nx,a); lz = (a>nx)? ny+2: lg(x)+d; x += 2; while (xd > x) *--zd = *--xd; } while (yd > y) *--zd = *--yd; *--zd = vs; *--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd; } /* shift polynomial + gerepile */ /* Do not set evalvarn. Cf Flx_shiftip */ static GEN F2x_shiftip(pari_sp av, GEN x, long v) { long i, lx = lg(x), ly; GEN y; if (!v || lx==2) return gerepileuptoleaf(av, x); ly = lx + v; (void)new_chunk(ly); /* check that result fits */ x += lx; y = (GEN)av; for (i = 2; i>1); n0=na-i; na=i; a0=a+n0; n0a=n0; while (n0a && !a[n0a-1]) n0a--; if (nb > n0) { GEN b0,c1,c2; long n0b; nb -= n0; b0 = b+n0; n0b = n0; while (n0b && !b[n0b-1]) n0b--; c = F2x_mulspec(a,b,n0a,n0b); c0 = F2x_mulspec(a0,b0,na,nb); c2 = F2x_addspec(a0,a,na,n0a); c1 = F2x_addspec(b0,b,nb,n0b); c1 = F2x_mul(c1,c2); c2 = F2x_add(c0,c); c2 = F2x_add(c1,c2); c0 = F2x_addshift(c0,c2,n0); } else { c = F2x_mulspec(a,b,n0a,nb); c0 = F2x_mulspec(a0,b,na,nb); } c0 = F2x_addshift(c0,c,n0); return F2x_shiftip(av,c0, v); } GEN F2x_mul(GEN x, GEN y) { GEN z = F2x_mulspec(x+2,y+2, lgpol(x),lgpol(y)); z[1] = x[1]; return z; } GEN F2x_sqr(GEN x) { const ulong sq[]={0,1,4,5,16,17,20,21,64,65,68,69,80,81,84,85}; long i,ii,j,jj; long lx=lg(x), lz=2+((lx-2)<<1); GEN z; z = cgetg(lz, t_VECSMALL); z[1]=x[1]; for (j=2,jj=2;j>BITS_IN_HALFULONG; ulong x2=(ulong)x[j]&LOWMASK; z[jj]=0; if (x2) for(i=0,ii=0;i>i)&15UL]<>i)&15UL]<>1); GEN z; z = cgetg(lz, t_VECSMALL); z[1]=x[1]; for (j=2,jj=2;jj>i)&15UL, rh = (x2>>(i+4))&15UL; z[jj]|=sq[rl|(rh<<1)]<>i)&15UL, rh = (x2>>(i+4))&15UL; z[jj]|=(sq[rl|(rh<<1)]<=2; i--) { x[i] = (((ulong)y[i+dl])>>db)|r; r = ((ulong)y[i+dl])<>dc; } x[i+dl] = r; } else for(i=2; i=dy) { F2x_addshiftip(x,y,dx-dy); while (lx>2 && x[lx-1]==0) lx--; dx = F2x_degree_lg(x,lx); } return F2x_renormalize(x, lx); } GEN F2x_divrem(GEN x, GEN y, GEN *pr) { long dx, dy, dz, lx = lg(x), vs = x[1]; GEN z; dy = F2x_degree(y); if (dy<0) pari_err_INV("F2x_divrem",y); if (pr == ONLY_REM) return F2x_rem(x, y); if (!dy) { z = F2x_copy(x); if (pr && pr != ONLY_DIVIDES) *pr = pol0_F2x(vs); return z; } dx = F2x_degree_lg(x,lx); dz = dx-dy; if (dz < 0) { if (pr == ONLY_DIVIDES) return dx < 0? F2x_copy(x): NULL; z = pol0_F2x(vs); if (pr) *pr = F2x_copy(x); return z; } z = zero_zv(lg(x)-lg(y)+2); z[1] = vs; x = F2x_copy(x); while (dx>=dy) { F2x_set(z,dx-dy); F2x_addshiftip(x,y,dx-dy); while (lx>2 && x[lx-1]==0) lx--; dx = F2x_degree_lg(x,lx); } z = F2x_renormalize(z, lg(z)); if (!pr) { cgiv(x); return z; } x = F2x_renormalize(x, lx); if (pr == ONLY_DIVIDES) { if (lg(x) == 2) { cgiv(x); return z; } avma = (pari_sp)(z + lg(z)); return NULL; } *pr = x; return z; } long F2x_valrem(GEN x, GEN *Z) { long v, v2, i, l=lg(x); GEN y; if (l==2) { *Z = F2x_copy(x); return LONG_MAX; } for (i=2; i> v2; else { const ulong sh = BITS_IN_LONG - v2; ulong r = x[2+v]; for (i=3; i> v2); r = x[i+v]; } y[l-1] = r >> v2; (void)F2x_renormalize(y,l); } *Z = y; return (v << TWOPOTBITS_IN_LONG) + v2; } GEN F2x_deflate(GEN x, long d) { GEN y; long i,id, dy, dx = F2x_degree(x); if (d <= 1) return F2x_copy(x); if (dx < 0) return F2x_copy(x); dy = dx/d; /* dy+1 coefficients + 1 extra word for variable */ y = zero_zv(nbits2lg(dy+1)-1); y[1] = x[1]; for (i=id=0; i<=dy; i++,id+=d) if (F2x_coeff(x,id)) F2x_set(y, i); return y; } /* write p(X) = e(X^2) + Xo(X^2), shallow function */ void F2x_even_odd(GEN p, GEN *pe, GEN *po) { long n = F2x_degree(p), n0, n1, i; GEN p0, p1; if (n <= 0) { *pe = F2x_copy(p); *po = pol0_F2x(p[1]); return; } n0 = (n>>1)+1; n1 = n+1 - n0; /* n1 <= n0 <= n1+1 */ p0 = zero_zv(nbits2lg(n0+1)-1); p0[1] = p[1]; p1 = zero_zv(nbits2lg(n1+1)-1); p1[1] = p[1]; for (i=0; i>1)&mask; return F2x_renormalize(x,l); } GEN F2x_gcd(GEN a, GEN b) { pari_sp av = avma; if (lg(b) > lg(a)) swap(a, b); while (lgpol(b)) { GEN c = F2x_rem(a,b); a = b; b = c; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"F2x_gcd (d = %ld)",F2x_degree(c)); gerepileall(av,2, &a,&b); } } if (gc_needed(av,2)) a = gerepileuptoleaf(av, a); return a; } GEN F2x_extgcd(GEN a, GEN b, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,d,d1,v1; long vx = a[1]; d = a; d1 = b; v = pol0_F2x(vx); v1 = pol1_F2x(vx); while (lgpol(d1)) { GEN r, q = F2x_divrem(d,d1, &r); v = F2x_add(v,F2x_mul(q,v1)); u=v; v=v1; v1=u; u=r; d=d1; d1=u; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"F2x_extgcd (d = %ld)",F2x_degree(d)); gerepileall(av,5, &d,&d1,&u,&v,&v1); } } if (ptu) *ptu = F2x_div(F2x_add(d, F2x_mul(b,v)), a); *ptv = v; if (gc_needed(av,2)) gerepileall(av,ptu?3:2,&d,ptv,ptu); return d; } static GEN F2x_halfgcd_i(GEN a, GEN b) { pari_sp av=avma; GEN u,u1,v,v1; long vx = a[1]; long n = (F2x_degree(a)+1)>>1; u1 = v = pol0_F2x(vx); u = v1 = pol1_F2x(vx); while (F2x_degree(b)>=n) { GEN r, q = F2x_divrem(a,b, &r); a = b; b = r; swap(u,u1); swap(v,v1); u1 = F2x_add(u1, F2x_mul(u, q)); v1 = F2x_add(v1, F2x_mul(v, q)); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"F2x_halfgcd (d = %ld)",F2x_degree(b)); gerepileall(av,6, &a,&b,&u1,&v1,&u,&v); } } return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1))); } GEN F2x_halfgcd(GEN x, GEN y) { pari_sp av; GEN M,q,r; if (F2x_degree(y)= F2x_degree(T); return gen_powers(x, l, use_sqr, (void*)T, &_F2xq_sqr, &_F2xq_mul, &_F2xq_one); } GEN F2xq_matrix_pow(GEN y, long n, long m, GEN P) { return F2xV_to_F2m(F2xq_powers(y,m-1,P),n); } GEN F2x_Frobenius(GEN T) { return F2xq_sqr(polx_F2x(T[1]), T); } GEN F2x_matFrobenius(GEN T) { long n = F2x_degree(T); return F2xq_matrix_pow(F2x_Frobenius(T), n, n, T); } static struct bb_algebra F2xq_algebra = { _F2xq_red, _F2xq_add, _F2xq_add, _F2xq_mul, _F2xq_sqr, _F2xq_one, _F2xq_zero}; GEN F2x_F2xqV_eval(GEN Q, GEN x, GEN T) { long d = F2x_degree(Q); return gen_bkeval_powers(Q,d,x,(void*)T,&F2xq_algebra,_F2xq_cmul); } GEN F2x_F2xq_eval(GEN Q, GEN x, GEN T) { long d = F2x_degree(Q); int use_sqr = 2*F2x_degree(x) >= F2x_degree(T); return gen_bkeval(Q, d, x, use_sqr, (void*)T, &F2xq_algebra, _F2xq_cmul); } static GEN F2xq_autpow_sqr(void * T, GEN x) { return F2x_F2xq_eval(x, x, (GEN) T); } static GEN F2xq_autpow_mul(void * T, GEN x, GEN y) { return F2x_F2xq_eval(x, y, (GEN) T); } GEN F2xq_autpow(GEN x, long n, GEN T) { if (n==0) return F2x_rem(polx_F2x(x[1]), T); if (n==1) return F2x_rem(x, T); return gen_powu(x,n,(void*)T,F2xq_autpow_sqr,F2xq_autpow_mul); } ulong F2xq_trace(GEN x, GEN T) { pari_sp av = avma; ulong t; long n = F2x_degree(T)-1; GEN z = F2x_mul(x, F2x_deriv(T)); z = F2x_rem(z, T); t = F2x_degree(z)>n, d = dT-(h<1) err_printf("Found %lu\n", g[2]); } return gerepileuptoint(av, l); } } avma = av; return NULL; } static GEN F2xq_log_find_rel(GEN b, long r, GEN T, GEN *g, ulong *e) { pari_sp av = avma; while (1) { GEN M; *g = F2xq_mul(*g, b, T); (*e)++; M = F2x_halfgcd(*g,T); if (F2x_is_smooth(gcoeff(M,1,1), r)) { GEN z = F2x_add(F2x_mul(gcoeff(M,1,1),*g), F2x_mul(gcoeff(M,1,2),T)); if (F2x_is_smooth(z, r)) { GEN F = F2x_factorel(z); GEN G = F2x_factorel(gcoeff(M,1,1)); GEN rel = mkmat2(vecsmall_concat(gel(F, 1),gel(G, 1)), vecsmall_concat(gel(F, 2),zv_neg(gel(G, 2)))); gerepileall(av, 2, g, &rel); return rel; } } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"F2xq_log_find_rel"); *g = gerepileuptoleaf(av, *g); } } } static GEN F2xq_log_Coppersmith_rec(GEN W, long r2, GEN a, long r, long n, GEN T, GEN m) { GEN b = polx_F2x(T[1]); ulong AV = 0; GEN g = a, bad = pol0_F2x(T[1]); pari_timer ti; while(1) { long i, l; GEN V, F, E, Ao; timer_start(&ti); V = F2xq_log_find_rel(b, r2, T, &g, &AV); if (DEBUGLEVEL>1) timer_printf(&ti,"%ld-smooth element",r2); F = gel(V,1); E = gel(V,2); l = lg(F); Ao = gen_0; for(i=1; i>n, d = dT-(h< 1) { for (j=1; jnbrel) break; gel(M,rel++) = gel(L,j); if (DEBUGLEVEL && (rel&511UL)==0) err_printf("%ld%%[%ld] ",rel*100/nbrel,i); } } if (rel>nbrel) stop=1; i++; } mt_queue_end(&pt); if (DEBUGLEVEL) err_printf(": %ld tests\n", nbtest); return M; } static GEN smallirred_F2x(ulong n, long sv) { GEN a = zero_zv(nbits2lg(n+1)-1); a[1] = sv; F2x_set(a,n); a[2]++; while (!F2x_is_irred(a)) a[2]+=2; return a; } static GEN check_kernel(long N, GEN M, long nbi, GEN T, GEN m) { pari_sp av = avma; GEN K = FpMs_leftkernel_elt(M, N, m); long i, f=0, tbs; long l = lg(K), lm = lgefint(m); GEN idx = diviiexact(int2um1(F2x_degree(T)),m); GEN g = F2xq_pow(polx_F2x(T[1]), idx, T); GEN tab; pari_timer ti; if (DEBUGLEVEL) timer_start(&ti); K = FpC_Fp_mul(K, Fp_inv(gel(K,2), m), m); tbs = maxss(1, expu(nbi/expi(m))); tab = F2xq_pow_init(g, int2n(F2x_degree(T)), tbs, T); for(i=1; i100); GEN T = smallirred_F2x(n,T0[1]); long d = 2, r2 = 3*r/2, d2 = 2; long N = (1UL<<(r+1))-1UL; long nbi = itos(ffsumnbirred(gen_2, r)), nbrel=nbi*5/4; if (DEBUGLEVEL) { err_printf("F2xq_log: Parameters r=%ld r2=%ld\n", r,r2); err_printf("F2xq_log: Size FB=%ld rel. needed=%ld\n", nbi, nbrel); timer_start(&ti); } S = Flx_to_F2x(Flx_ffisom(F2x_to_Flx(T0),F2x_to_Flx(T),2)); a = F2x_F2xq_eval(a0, S, T); b = F2x_F2xq_eval(b0, S, T); if (DEBUGLEVEL) timer_printf(&ti,"model change"); M = F2xq_log_Coppersmith(nbrel,r,d,T); if(DEBUGLEVEL) timer_printf(&ti,"relations"); W = check_kernel(N, M, nbi, T, m); timer_start(&ti); Ao = F2xq_log_Coppersmith_rec(W, r2, a, r, d2, T, m); if (DEBUGLEVEL) timer_printf(&ti,"smooth element"); Bo = F2xq_log_Coppersmith_rec(W, r2, b, r, d2, T, m); if (DEBUGLEVEL) timer_printf(&ti,"smooth generator"); e = Fp_div(Ao, Bo, m); if (!F2x_equal(F2xq_pow(b0,e,T0),a0)) pari_err_BUG("F2xq_log"); return gerepileupto(av, e); } static GEN F2xq_easylog(void* E, GEN a, GEN g, GEN ord) { if (F2x_equal1(a)) return gen_0; if (F2x_equal(a,g)) return gen_1; if (typ(ord)!=t_INT) return NULL; if (expi(ord)<28) return NULL; return F2xq_log_index(a,g,ord,(GEN)E); } GEN F2xq_log(GEN a, GEN g, GEN ord, GEN T) { GEN z, v = get_arith_ZZM(ord); ord = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(28))); z = gen_PH_log(a,g,ord,(void*)T,&F2xq_star); return z? z: cgetg(1,t_VEC); } GEN F2xq_Artin_Schreier(GEN a, GEN T) { pari_sp ltop=avma; long j,N = F2x_degree(T); GEN Q = F2x_matFrobenius(T); for (j=1; j<=N; j++) F2m_flip(Q,j,j); F2v_add_inplace(gel(Q,1),a); Q = F2m_ker_sp(Q,0); if (lg(Q)!=2) return NULL; Q = gel(Q,1); Q[1] = T[1]; return gerepileuptoleaf(ltop, F2x_renormalize(Q, lg(Q))); } GEN F2xq_sqrt_fast(GEN c, GEN sqx, GEN T) { GEN c0, c1; F2x_even_odd(c, &c0, &c1); return F2x_add(c0, F2xq_mul(c1, sqx, T)); } static int F2x_is_x(GEN a) { return lg(a)==3 && a[2]==2; } GEN F2xq_sqrt(GEN a, GEN T) { pari_sp av = avma; long n = F2x_degree(T); GEN sqx; if (n==1) return F2x_copy(a); if (n==2) return F2xq_sqr(a,T); sqx = F2xq_autpow(mkF2(4, T[1]), n-1, T); return gerepileuptoleaf(av, F2x_is_x(a)? sqx: F2xq_sqrt_fast(a,sqx,T)); } GEN F2xq_sqrtn(GEN a, GEN n, GEN T, GEN *zeta) { if (!lgpol(a)) { if (signe(n) < 0) pari_err_INV("F2xq_sqrtn",a); if (zeta) *zeta=pol1_F2x(T[1]); return pol0_F2x(T[1]); } return gen_Shanks_sqrtn(a,n,subiu(powuu(2,F2x_degree(T)),1),zeta,(void*)T,&F2xq_star); } GEN gener_F2xq(GEN T, GEN *po) { long i, j, vT = T[1], f = F2x_degree(T); pari_sp av0 = avma, av; GEN g, L2, o, q; if (f == 1) { if (po) *po = mkvec2(gen_1, trivial_fact()); return pol1_F2x(vT); } q = int2um1(f); o = factor_pn_1(gen_2,f); L2 = leafcopy( gel(o, 1) ); for (i = j = 1; i < lg(L2); i++) { if (absequaliu(gel(L2,i),2)) continue; gel(L2,j++) = diviiexact(q, gel(L2,i)); } setlg(L2, j); for (av = avma;; avma = av) { g = random_F2x(f, vT); if (F2x_degree(g) < 1) continue; for (i = 1; i < j; i++) { GEN a = F2xq_pow(g, gel(L2,i), T); if (F2x_equal1(a)) break; } if (i == j) break; } if (!po) g = gerepilecopy(av0, g); else { *po = mkvec2(int2um1(f), o); gerepileall(av0, 2, &g, po); } return g; } static GEN _F2xq_neg(void *E, GEN x) { (void) E; return F2x_copy(x); } static GEN _F2xq_rmul(void *E, GEN x, GEN y) { (void) E; return F2x_mul(x,y); } static GEN _F2xq_inv(void *E, GEN x) { return F2xq_inv(x, (GEN) E); } static int _F2xq_equal0(GEN x) { return lgpol(x)==0; } static GEN _F2xq_s(void *E, long x) { GEN T = (GEN) E; long v = get_F2x_var(T); return odd(x)? pol1_F2x(v): pol0_F2x(v); } static const struct bb_field F2xq_field={_F2xq_red,_F2xq_add,_F2xq_rmul,_F2xq_neg, _F2xq_inv,_F2xq_equal0,_F2xq_s}; const struct bb_field *get_F2xq_field(void **E, GEN T) { *E = (void *) T; return &F2xq_field; } /***********************************************************************/ /** **/ /** F2v **/ /** **/ /***********************************************************************/ /* F2v objects are defined as follows: An F2v is a t_VECSMALL: v[0] = codeword v[1] = number of components x[2] = a_0...a_31 x[3] = a_32..a_63, etc. on 32bit x[2] = a_0...a_63 x[3] = a_64..a_127, etc. on 64bit where the a_i are bits. */ GEN F2c_to_ZC(GEN x) { long l=x[1]+1; GEN z = cgetg(l, t_COL); long i,j,k; for (i=2,k=1; i>j)&1UL; return z; } GEN F2m_to_Flm(GEN z) { long i, l = lg(z); GEN x = cgetg(l,t_MAT); for (i=1; ilx) swapspec(x,y, lx,ly); lz = lx+2; z = cgetg(lz, t_POL); for (i=0; ilx) swapspec(x,y, lx,ly); lz = lx; z = cgetg(lz, t_POL); z[1]=x[1]; for (i=2; i>ib; for(i=0; i>ib; } if (db) uel(t,2+i) = (uel(x,3+il+i)< 0) { GEN u = pol0_F2x(T[1]); long i,j; for (i=2,j=2; i=dy; i--) { av=avma; p1=gel(x,i); for (j=i-dy+1; j<=i && j<=dz; j++) p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j))); if (lead) p1 = F2x_mul(p1, lead); tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,F2x_rem(p1,T)); } if (!pr) { if (lead) gunclone(lead); return z-2; } rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3); for (sx=0; ; i--) { p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j))); tetpil=avma; p1 = F2x_rem(p1, T); if (lgpol(p1)) { sx = 1; break; } if (!i) break; avma=av; } if (pr == ONLY_DIVIDES) { if (lead) gunclone(lead); if (sx) { avma=av0; return NULL; } avma = (pari_sp)rem; return z-2; } lr=i+3; rem -= lr; rem[0] = evaltyp(t_POL) | evallg(lr); rem[1] = z[-1]; p1 = gerepile((pari_sp)rem,tetpil,p1); rem += 2; gel(rem,i) = p1; for (i--; i>=0; i--) { av=avma; p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j))); tetpil=avma; gel(rem,i) = gerepile(av,tetpil, F2x_rem(p1, T)); } rem -= 2; if (lead) gunclone(lead); if (!sx) (void)F2xX_renormalize(rem, lr); if (pr == ONLY_REM) return gerepileupto(av0,rem); *pr = rem; return z-2; } static GEN F2xX_recipspec(GEN x, long l, long n, long vs) { long i; GEN z = cgetg(n+2,t_POL); z[1] = 0; z += 2; for(i=0; i=0; i--) if (lgpol(gel(x,i))) break; return i+1; } static GEN F2xqX_invBarrett_Newton(GEN S, GEN T) { pari_sp av = avma; long nold, lx, lz, lq, l = degpol(S), i, lQ; GEN q, y, z, x = cgetg(l+2, t_POL) + 2; long dT = F2x_degree(T); ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */ for (i=0;i1 && F2x_degree(gel(q,1)) >= dT) gel(q,1) = F2x_rem(gel(q,1), T); if (lQ>1 && lgpol(gel(q,1))) { GEN u = gel(q, 1); if (!F2x_equal1(gel(x,0))) u = F2xq_mul(u, F2xq_sqr(gel(x,0), T), T); else u = F2x_copy(u); gel(x,1) = u; lx = 2; } else lx = 1; nold = 1; for (; mask > 1; ) { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */ long i, lnew, nnew = nold << 1; if (mask & 1) nnew--; mask >>= 1; lnew = nnew + 1; lq = F2xX_lgrenormalizespec(q, minss(lQ,lnew)); z = F2xqX_mulspec(x, q, T, lx, lq); /* FIXME: high product */ lz = lgpol(z); if (lz > lnew) lz = lnew; z += 2; /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */ for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break; nold = nnew; if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */ /* z + i represents (x*q - 1) / t^i */ lz = F2xX_lgrenormalizespec (z+i, lz-i); z = F2xqX_mulspec(x, z+i, T, lx, lz); /* FIXME: low product */ lz = lgpol(z); z += 2; if (lz > lnew-i) lz = F2xX_lgrenormalizespec(z, lnew-i); lx = lz+ i; y = x + i; /* x -= z * t^i, in place */ for (i = 0; i < lz; i++) gel(y,i) = gel(z,i); } x -= 2; setlg(x, lx + 2); x[1] = S[1]; return gerepilecopy(av, x); } /* x/polrecip(P)+O(x^n) */ GEN F2xqX_invBarrett(GEN T, GEN Q) { pari_sp ltop=avma; long l=lg(T), v = varn(T); GEN r; GEN c = gel(T,l-1); if (l<5) return pol_0(v); if (l<=F2xqX_INVBARRETT_LIMIT) { if (!F2x_equal1(c)) { GEN ci = F2xq_inv(c,Q); T = F2xqX_F2xq_mul(T, ci, Q); r = F2xqX_invBarrett_basecase(T,Q); r = F2xqX_F2xq_mul(r,ci,Q); } else r = F2xqX_invBarrett_basecase(T,Q); } else r = F2xqX_invBarrett_Newton(T,Q); return gerepileupto(ltop, r); } GEN F2xqX_get_red(GEN S, GEN T) { if (typ(S)==t_POL && lg(S)>F2xqX_BARRETT_LIMIT) retmkvec2(F2xqX_invBarrett(S, T), S); return S; } /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1) * * and mg is the Barrett inverse of S. */ static GEN F2xqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, GEN *pr) { GEN q, r; long lt = degpol(S); /*We discard the leading term*/ long ld, lm, lT, lmg; ld = l-lt; lm = minss(ld, lgpol(mg)); lT = F2xX_lgrenormalizespec(S+2,lt); lmg = F2xX_lgrenormalizespec(mg+2,lm); q = F2xX_recipspec(x+lt,ld,ld,0); /* q = rec(x) lq<=ld*/ q = F2xqX_mulspec(q+2,mg+2,T,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/ q = F2xX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/ if (!pr) return q; r = F2xqX_mulspec(q+2,S+2,T,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/ r = F2xX_addspec(x,r+2,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */ if (pr == ONLY_REM) return r; *pr = r; return q; } static GEN F2xqX_divrem_Barrett_noGC(GEN x, GEN mg, GEN S, GEN T, GEN *pr) { long l = lgpol(x), lt = degpol(S), lm = 2*lt-1; GEN q = NULL, r; long i; if (l <= lt) { if (pr == ONLY_REM) return RgX_copy(x); if (pr == ONLY_DIVIDES) return signe(x)? NULL: pol_0(varn(x)); if (pr) *pr = RgX_copy(x); return pol_0(varn(x)); } if (lt <= 1) return F2xqX_divrem_basecase(x,S,T,pr); if (pr != ONLY_REM && l>lm) { long vT = get_F2x_var(T); q = cgetg(l-lt+2, t_POL); for (i=0;ilm ? shallowcopy(x): x; while (l>lm) { GEN zr, zq = F2xqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,&zr); long lz = lgpol(zr); if (pr != ONLY_REM) { long lq = lgpol(zq); for(i=0; i lt) { GEN zq = F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,&r); if (!q) q = zq; else { long lq = lgpol(zq); for(i=0; i lt) (void) F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,&r); else { setlg(r, l+2); r = RgX_copy(r); } r[1] = x[1]; return F2xX_renormalize(r, lg(r)); } if (pr) { r[1] = x[1]; r = F2xX_renormalize(r, lg(r)); } q[1] = x[1]; q = F2xX_renormalize(q, lg(q)); if (pr == ONLY_DIVIDES) return signe(r)? NULL: q; if (pr) *pr = r; return q; } GEN F2xqX_divrem(GEN x, GEN S, GEN T, GEN *pr) { GEN B, y = get_F2xqX_red(S, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (pr==ONLY_REM) return F2xqX_rem(x, y, T); if (!B && d+3 < F2xqX_DIVREM_BARRETT_LIMIT) return F2xqX_divrem_basecase(x,y,T,pr); else { pari_sp av=avma; GEN mg = B? B: F2xqX_invBarrett(y, T); GEN q = F2xqX_divrem_Barrett_noGC(x,mg,y,T,pr); if (!q) {avma=av; return NULL;} if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q); gerepileall(av,2,&q,pr); return q; } } GEN F2xqX_rem(GEN x, GEN S, GEN T) { GEN B, y = get_F2xqX_red(S, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (d < 0) return F2xqX_red(x, T); if (!B && d+3 < F2xqX_REM_BARRETT_LIMIT) return F2xqX_divrem_basecase(x,y, T, ONLY_REM); else { pari_sp av=avma; GEN mg = B? B: F2xqX_invBarrett(y, T); GEN r = F2xqX_divrem_Barrett_noGC(x, mg, y, T, ONLY_REM); return gerepileupto(av, r); } } GEN F2xqX_gcd(GEN a, GEN b, GEN T) { pari_sp av = avma, av0=avma; while (signe(b)) { GEN c; if (gc_needed(av0,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_gcd (d = %ld)",degpol(b)); gerepileall(av0,2, &a,&b); } av = avma; c = F2xqX_rem(a, b, T); a=b; b=c; } avma = av; return a; } GEN F2xqX_extgcd(GEN a, GEN b, GEN T, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,d,d1,v1; long vx = varn(a); d = a; d1 = b; v = pol_0(vx); v1 = pol1_F2xX(vx, get_F2x_var(T)); while (signe(d1)) { GEN r, q = F2xqX_divrem(d, d1, T, &r); v = F2xX_add(v,F2xqX_mul(q,v1,T)); u=v; v=v1; v1=u; u=r; d=d1; d1=u; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_extgcd (d = %ld)",degpol(d)); gerepileall(av,5, &d,&d1,&u,&v,&v1); } } if (ptu) *ptu = F2xqX_div(F2xX_add(d,F2xqX_mul(b,v, T)), a, T); *ptv = v; return d; } static GEN _F2xqX_mul(void *data,GEN a,GEN b) { return F2xqX_mul(a,b, (GEN) data); } static GEN _F2xqX_sqr(void *data,GEN a) { return F2xqX_sqr(a, (GEN) data); } GEN F2xqX_powu(GEN x, ulong n, GEN T) { return gen_powu(x, n, (void*)T, &_F2xqX_sqr, &_F2xqX_mul); } /***********************************************************************/ /** **/ /** F2xqXQ **/ /** **/ /***********************************************************************/ GEN F2xqXQ_mul(GEN x, GEN y, GEN S, GEN T) { return F2xqX_rem(F2xqX_mul(x,y,T),S,T); } GEN F2xqXQ_sqr(GEN x, GEN S, GEN T) { return F2xqX_rem(F2xqX_sqr(x,T),S,T); } GEN F2xqXQ_invsafe(GEN x, GEN S, GEN T) { GEN V, z = F2xqX_extgcd(get_F2xqX_mod(S), x, T, NULL, &V); if (degpol(z)) return NULL; z = F2xq_invsafe(gel(z,2),T); if (!z) return NULL; return F2xqX_F2xq_mul(V, z, T); } GEN F2xqXQ_inv(GEN x, GEN S, GEN T) { pari_sp av = avma; GEN U = F2xqXQ_invsafe(x, S, T); if (!U) pari_err_INV("F2xqXQ_inv",x); return gerepileupto(av, U); } struct _F2xqXQ { GEN T, S; }; static GEN _F2xqXQ_add(void *data, GEN x, GEN y) { (void) data; return F2xX_add(x,y); } static GEN _F2xqXQ_cmul(void *data, GEN P, long a, GEN x) { (void) data; return F2xX_F2x_mul(x,gel(P,a+2)); } static GEN _F2xqXQ_red(void *data, GEN x) { struct _F2xqXQ *d = (struct _F2xqXQ*) data; return F2xqX_red(x, d->T); } static GEN _F2xqXQ_mul(void *data, GEN x, GEN y) { struct _F2xqXQ *d = (struct _F2xqXQ*) data; return F2xqXQ_mul(x,y, d->S,d->T); } static GEN _F2xqXQ_sqr(void *data, GEN x) { struct _F2xqXQ *d = (struct _F2xqXQ*) data; return F2xqXQ_sqr(x, d->S,d->T); } static GEN _F2xqXQ_zero(void *data) { struct _F2xqXQ *d = (struct _F2xqXQ*) data; return pol_0(get_F2xqX_var(d->S)); } static GEN _F2xqXQ_one(void *data) { struct _F2xqXQ *d = (struct _F2xqXQ*) data; return pol1_F2xX(get_F2xqX_var(d->S),get_F2x_var(d->T)); } static struct bb_algebra F2xqXQ_algebra = { _F2xqXQ_red, _F2xqXQ_add, _F2xqXQ_add, _F2xqXQ_mul,_F2xqXQ_sqr,_F2xqXQ_one,_F2xqXQ_zero }; GEN F2xqXQ_pow(GEN x, GEN n, GEN S, GEN T) { struct _F2xqXQ D; long s = signe(n); if (!s) return pol1_F2xX(get_F2xqX_var(S), get_F2x_var(T)); if (s < 0) x = F2xqXQ_inv(x,S,T); if (is_pm1(n)) return s < 0 ? x : gcopy(x); if (degpol(x) >= get_F2xqX_degree(S)) x = F2xqX_rem(x,S,T); D.S = S; D.T = T; return gen_pow(x, n, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul); } GEN F2xqXQ_powers(GEN x, long l, GEN S, GEN T) { struct _F2xqXQ D; int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S); D.S = S; D.T = T; return gen_powers(x, l, use_sqr, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul,&_F2xqXQ_one); } GEN F2xqX_F2xqXQV_eval(GEN P, GEN V, GEN S, GEN T) { struct _F2xqXQ D; D.S = S; D.T = T; return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &F2xqXQ_algebra, _F2xqXQ_cmul); } GEN F2xqX_F2xqXQ_eval(GEN Q, GEN x, GEN S, GEN T) { struct _F2xqXQ D; int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S); D.S = S; D.T = T; return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &F2xqXQ_algebra, _F2xqXQ_cmul); } static GEN F2xqXQ_autpow_sqr(void * E, GEN x) { struct _F2xqXQ *D = (struct _F2xqXQ *)E; GEN T = D->T; GEN phi = gel(x,1), S = gel(x,2); long n = brent_kung_optpow(F2x_degree(T)-1,lgpol(S)+1,1); GEN V = F2xq_powers(phi, n, T); GEN phi2 = F2x_F2xqV_eval(phi, V, T); GEN Sphi = F2xY_F2xqV_evalx(S, V, T); GEN S2 = F2xqX_F2xqXQ_eval(Sphi, S, D->S, T); return mkvec2(phi2, S2); } static GEN F2xqXQ_autpow_mul(void * E, GEN x, GEN y) { struct _F2xqXQ *D = (struct _F2xqXQ *)E; GEN T = D->T; GEN phi1 = gel(x,1), S1 = gel(x,2); GEN phi2 = gel(y,1), S2 = gel(y,2); long n = brent_kung_optpow(F2x_degree(T)-1,lgpol(S1)+1,1); GEN V = F2xq_powers(phi2, n, T); GEN phi3 = F2x_F2xqV_eval(phi1,V,T); GEN Sphi = F2xY_F2xqV_evalx(S1,V,T); GEN S3 = F2xqX_F2xqXQ_eval(Sphi, S2, D->S, T); return mkvec2(phi3, S3); } GEN F2xqXQ_autpow(GEN aut, long n, GEN S, GEN T) { struct _F2xqXQ D; D.S = S; D.T = T; return gen_powu(aut,n,&D,F2xqXQ_autpow_sqr,F2xqXQ_autpow_mul); } static GEN F2xqXQ_auttrace_mul(void *E, GEN x, GEN y) { struct _F2xqXQ *D = (struct _F2xqXQ *) E; GEN T = D->T; GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3); GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3); long n2 = brent_kung_optpow(F2x_degree(T)-1, lgpol(S1)+lgpol(a1)+1, 1); GEN V2 = F2xq_powers(phi2, n2, T); GEN phi3 = F2x_F2xqV_eval(phi1, V2, T); GEN Sphi = F2xY_F2xqV_evalx(S1, V2, T); GEN aphi = F2xY_F2xqV_evalx(a1, V2, T); long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1); GEN V = F2xqXQ_powers(S2, n, D->S, T); GEN S3 = F2xqX_F2xqXQV_eval(Sphi, V, D->S, T); GEN aS = F2xqX_F2xqXQV_eval(aphi, V, D->S, T); GEN a3 = F2xX_add(aS, a2); return mkvec3(phi3, S3, a3); } static GEN F2xqXQ_auttrace_sqr(void *E, GEN x) { return F2xqXQ_auttrace_mul(E, x, x); } GEN F2xqXQ_auttrace(GEN aut, long n, GEN S, GEN T) { struct _F2xqXQ D; D.S = S; D.T = T; return gen_powu(aut,n,&D,F2xqXQ_auttrace_sqr,F2xqXQ_auttrace_mul); } GEN F2xqXQV_red(GEN x, GEN S, GEN T) { pari_APPLY_type(t_VEC, F2xqX_rem(gel(x,i), S, T)) } pari-2.11.2/src/basemath/polarit2.c0000644000175000017500000027520613457566441015464 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /***********************************************************************/ /** **/ /** ARITHMETIC OPERATIONS ON POLYNOMIALS **/ /** (second part) **/ /** **/ /***********************************************************************/ #include "pari.h" #include "paripriv.h" /* compute Newton sums S_1(P), ... , S_n(P). S_k(P) = sum a_j^k, a_j root of P * If N != NULL, assume p-adic roots and compute mod N [assume integer coeffs] * If T != NULL, compute mod (T,N) [assume integer coeffs if N != NULL] * If y0!= NULL, precomputed i-th powers, i=1..m, m = length(y0). * Not memory clean in the latter case */ GEN polsym_gen(GEN P, GEN y0, long n, GEN T, GEN N) { long dP=degpol(P), i, k, m; pari_sp av1, av2; GEN s,y,P_lead; if (n<0) pari_err_IMPL("polsym of a negative n"); if (typ(P) != t_POL) pari_err_TYPE("polsym",P); if (!signe(P)) pari_err_ROOTS0("polsym"); y = cgetg(n+2,t_COL); if (y0) { if (typ(y0) != t_COL) pari_err_TYPE("polsym_gen",y0); m = lg(y0)-1; for (i=1; i<=m; i++) gel(y,i) = gel(y0,i); /* not memory clean */ } else { m = 1; gel(y,1) = stoi(dP); } P += 2; /* strip codewords */ P_lead = gel(P,dP); if (gequal1(P_lead)) P_lead = NULL; if (P_lead) { if (N) P_lead = Fq_inv(P_lead,T,N); else if (T) P_lead = QXQ_inv(P_lead,T); } for (k=m; k<=n; k++) { av1 = avma; s = (dP>=k)? gmulsg(k,gel(P,dP-k)): gen_0; for (i=1; i 0) y = subii(y, p); break; case -1: if (!po2 || abscmpii(y,po2) > 0) y = addii(y, p); break; } return y; } static long s_centermod(long x, ulong pp, ulong pps2) { long y = x % (long)pp; if (y < 0) y += pp; return Fl_center(y, pp,pps2); } /* for internal use */ GEN centermod_i(GEN x, GEN p, GEN ps2) { long i, lx; pari_sp av; GEN y; if (!ps2) ps2 = shifti(p,-1); switch(typ(x)) { case t_INT: return centermodii(x,p,ps2); case t_POL: lx = lg(x); y = cgetg(lx,t_POL); y[1] = x[1]; for (i=2; i 0) { long j; for(j = 1;;j++) { v = RgX_gcd(r, t); tv = RgX_div(t, v); if (degpol(tv) > 0) gel(u, j*q) = tv; if (degpol(v) <= 0) break; r = RgX_div(r, v); t = v; } if (degpol(r) == 0) break; } if (!p) break; r = RgX_Frobenius_deflate(f, p); if (!r) { gel(u, q) = f; break; } f = r; } for (i = n; i; i--) if (degpol(gel(u,i))) break; setlg(u,i+1); return u; } /* Lmod contains modular factors of *F (NULL codes an empty slot: used factor) * Lfac accumulates irreducible factors as they are found. * p is a product of modular factors in Lmod[1..i-1] (NULL for p = 1), not * a rational factor of *F * Find an irreducible factor of *F divisible by p (by including * exhaustively further factors from Lmod[i..]); return 0 on failure, else 1. * Update Lmod, Lfac and *F */ static int RgX_cmbf(GEN p, long i, GEN BLOC, GEN Lmod, GEN Lfac, GEN *F) { GEN q; if (i == lg(Lmod)) return 0; if (RgX_cmbf(p, i+1, BLOC, Lmod, Lfac, F) && p) return 1; if (!gel(Lmod,i)) return 0; p = p? RgX_mul(p, gel(Lmod,i)): gel(Lmod,i); q = RgV_to_RgX(RgX_digits(p, BLOC), varn(*F)); if (degpol(q)) { GEN R, Q = RgX_divrem(*F, q, &R); if (signe(R)==0) { vectrunc_append(Lfac, q); *F = Q; return 1; } } if (RgX_cmbf(p, i+1, BLOC, Lmod, Lfac, F)) { gel(Lmod,i) = NULL; return 1; } return 0; } static GEN factor_domain(GEN x, GEN flag); static GEN RgXY_factor_squarefree(GEN f, GEN dom) { pari_sp av = avma; ulong i, c = itou_or_0(residual_characteristic(f)); long vy = gvar2(f), val = RgX_valrem(f, &f), n = RgXY_degreex(f); GEN Lmod, F = NULL, BLOC = NULL, Lfac = coltrunc_init(degpol(f)+2); if (val) { GEN x = pol_x(varn(f)); if (dom) { GEN c = Rg_get_1(dom); if (typ(c) != t_INT) x = RgX_Rg_mul(x, c); } vectrunc_append(Lfac, x); if (!degpol(f)) return Lfac; } for(;;) { for (i = 0; !c || i < c; i++) { BLOC = gpowgs(gaddgs(pol_x(vy), i), n+1); F = poleval(f, BLOC); if (issquarefree(c ? gmul(F,mkintmodu(1,c)): F)) break; } if (!c || i < c) break; n++; } if (DEBUGLEVEL >= 2) err_printf("bifactor: bloc:(x+%ld)^%ld, deg f=%ld\n",i,n,RgXY_degreex(f)); Lmod = gel(factor_domain(F,dom),1); if (DEBUGLEVEL >= 2) err_printf("bifactor: %ld local factors\n",lg(Lmod)-1); (void)RgX_cmbf(NULL, 1, BLOC, Lmod, Lfac, &f); if (degpol(f)) vectrunc_append(Lfac, f); return gerepilecopy(av, Lfac); } static GEN FE_matconcat(GEN F, GEN E, long l) { setlg(E,l); E = shallowconcat1(E); setlg(F,l); F = shallowconcat1(F); return mkmat2(F,E); } static int gen_cmp_RgXY(void *data, GEN x, GEN y) { long vx = varn(x), vy = varn(y); return (vx == vy)? gen_cmp_RgX(data, x, y): -varncmp(vx, vy); } static GEN RgXY_factor(GEN f, GEN dom) { pari_sp av = avma; GEN C, F, E, cf, V; long i, j, l; if (dom) { GEN c = Rg_get_1(dom); if (typ(c) != t_INT) f = RgX_Rg_mul(f,c); } cf = content(f); V = RgXY_squff(gdiv(f, cf)); l = lg(V); C = factor_domain(cf, dom); F = cgetg(l+1, t_VEC); gel(F,1) = gel(C,1); E = cgetg(l+1, t_VEC); gel(E,1) = gel(C,2); for (i=1, j=2; i < l; i++) { GEN v = gel(V,i); if (degpol(v)) { gel(F,j) = v = RgXY_factor_squarefree(v, dom); gel(E,j) = const_col(lg(v)-1, utoipos(i)); j++; } } f = FE_matconcat(F,E,j); (void)sort_factor(f,(void*)cmp_universal, &gen_cmp_RgXY); return gerepilecopy(av, f); } /***********************************************************************/ /** **/ /** FACTORIZATION **/ /** **/ /***********************************************************************/ static long RgX_settype(GEN x, long *t, GEN *p, GEN *pol, long *pa, GEN *ff, long *t2, long *var); #define assign_or_fail(x,y) { GEN __x = x;\ if (!*y) *y=__x; else if (!gequal(__x,*y)) return 0;\ } #define update_prec(x,y) { long __x = x; if (__x < *y) *y=__x; } static const long tsh = 6; static long code(long t1, long t2) { return (t1 << tsh) | t2; } void RgX_type_decode(long x, long *t1, long *t2) { *t1 = x >> tsh; *t2 = (x & ((1L<= tsh; } static int settype(GEN c, long *t, GEN *p, GEN *pol, long *pa, GEN *ff, long *t2, long *var) { long j; switch(typ(c)) { case t_INT: break; case t_FRAC: t[1]=1; break; break; case t_REAL: update_prec(precision(c), pa); t[2]=1; break; case t_INTMOD: assign_or_fail(gel(c,1),p); t[3]=1; break; case t_FFELT: if (!*ff) *ff=c; else if (!FF_samefield(c,*ff)) return 0; assign_or_fail(FF_p_i(c),p); t[5]=1; break; case t_COMPLEX: for (j=1; j<=2; j++) { GEN d = gel(c,j); switch(typ(d)) { case t_INT: case t_FRAC: if (!*t2) *t2 = t_COMPLEX; t[1]=1; break; case t_REAL: update_prec(precision(d), pa); if (!*t2) *t2 = t_COMPLEX; t[2]=1; break; case t_INTMOD: assign_or_fail(gel(d,1),p); if (!signe(*p) || mod4(*p) != 3) return 0; if (!*t2) *t2 = t_COMPLEX; t[3]=1; break; case t_PADIC: update_prec(precp(d)+valp(d), pa); assign_or_fail(gel(d,2),p); if (!*t2) *t2 = t_COMPLEX; t[7]=1; break; default: return 0; } } if (!t[2]) assign_or_fail(mkpoln(3, gen_1,gen_0,gen_1), pol); /*x^2+1*/ break; case t_PADIC: update_prec(precp(c)+valp(c), pa); assign_or_fail(gel(c,2),p); t[7]=1; break; case t_QUAD: assign_or_fail(gel(c,1),pol); for (j=2; j<=3; j++) { GEN d = gel(c,j); switch(typ(d)) { case t_INT: case t_FRAC: t[8]=1; break; case t_INTMOD: assign_or_fail(gel(d,1),p); if (*t2 != t_POLMOD) *t2 = t_QUAD; t[3]=1; break; case t_PADIC: update_prec(precp(d)+valp(d), pa); assign_or_fail(gel(d,2),p); if (*t2 != t_POLMOD) *t2 = t_QUAD; t[7]=1; break; default: return 0; } } break; case t_POLMOD: assign_or_fail(gel(c,1),pol); if (typ(gel(c,2))==t_POL && varn(gel(c,2))!=varn(gel(c,1))) return 0; for (j=1; j<=2; j++) { GEN pbis, polbis; long pabis; *t2 = t_POLMOD; switch(Rg_type(gel(c,j),&pbis,&polbis,&pabis)) { case t_INT: break; case t_FRAC: t[1]=1; break; case t_INTMOD: t[3]=1; break; case t_PADIC: t[7]=1; update_prec(pabis,pa); break; default: return 0; } if (pbis) assign_or_fail(pbis,p); if (polbis) assign_or_fail(polbis,pol); } break; case t_RFRAC: t[10] = 1; if (!settype(gel(c,1),t,p,pol,pa,ff,t2,var)) return 0; c = gel(c,2); /* fall through */ case t_POL: t[10] = 1; if (!RgX_settype(c,t,p,pol,pa,ff,t2,var)) return 0; if (*var == NO_VARIABLE) { *var = varn(c); break; } /* if more than one free var, ensure varn() == *var fails. FIXME: should * keep the list of all variables, later t_POLMOD may cancel them */ if (*var != varn(c)) *var = MAXVARN+1; break; default: return 0; } return 1; } /* t[0] unused. Other values, if set, indicate a coefficient of type * t[1] : t_FRAC * t[2] : t_REAL * t[3] : t_INTMOD * t[4] : Unused * t[5] : t_FFELT * t[6] : Unused * t[7] : t_PADIC * t[8] : t_QUAD of rationals (t_INT/t_FRAC) * t[9]: Unused * t[10]: t_POL (recursive factorisation) */ /* if t2 != 0: t_POLMOD/t_QUAD/t_COMPLEX of modular (t_INTMOD/t_PADIC, * given by t) */ static long choosetype(long *t, long t2, GEN ff, GEN *pol, long var) { if (t[10] && (!*pol || var!=varn(*pol))) return t_POL; if (t2) /* polmod/quad/complex of intmod/padic */ { if (t[2] && (t[3]||t[7])) return 0; if (t[3]) return code(t2,t_INTMOD); if (t[7]) return code(t2,t_PADIC); if (t[2]) return t_COMPLEX; if (t[1]) return code(t2,t_FRAC); return code(t2,t_INT); } if (t[5]) /* ffelt */ { if (t[2]||t[8]||t[9]) return 0; *pol=ff; return t_FFELT; } if (t[2]) /* inexact, real */ { if (t[3]||t[7]||t[9]) return 0; return t_REAL; } if (t[10]) return t_POL; if (t[8]) return code(t_QUAD,t_INT); if (t[3]) return t_INTMOD; if (t[7]) return t_PADIC; if (t[1]) return t_FRAC; return t_INT; } static long RgX_settype(GEN x, long *t, GEN *p, GEN *pol, long *pa, GEN *ff, long *t2, long *var) { long i, lx = lg(x); for (i=2; i (impose imag(x) >= 0) */ static GEN gauss_normal(GEN x) { if (typ(x) != t_COMPLEX) return (signe(x) < 0)? absi(x): x; if (signe(gel(x,1)) < 0) x = gneg(x); if (signe(gel(x,2)) < 0) x = mulcxI(x); return x; } static GEN gauss_factor(GEN x) { pari_sp av = avma; GEN a = real_i(x), b = imag_i(x), d = gen_1, n, y, fa, P, E, P2, E2; long t1 = typ(a); long t2 = typ(b), i, j, l, exp = 0; if (t1 == t_FRAC) d = gel(a,2); if (t2 == t_FRAC) d = lcmii(d, gel(b,2)); if (d == gen_1) y = x; else { y = gmul(x, d); a = real_i(y); t1 = typ(a); b = imag_i(y); t2 = typ(b); } if (t1 != t_INT || t2 != t_INT) return NULL; y = gauss_primpart(y, &n); fa = factor(cxnorm(y)); P = gel(fa,1); E = gel(fa,2); l = lg(P); P2 = cgetg(l, t_COL); E2 = cgetg(l, t_COL); for (j = 1, i = l-1; i > 0; i--) /* remove largest factors first */ { /* either p = 2 (ramified) or those factors split in Q(i) */ GEN p = gel(P,i), w, w2, t, we, pe; long v, e = itos(gel(E,i)); int is2 = absequaliu(p, 2); w = is2? mkcomplex(gen_1,gen_1): gauss_factor_p(p); w2 = gauss_normal( conj_i(w) ); /* w * w2 * I^3 = p, w2 = conj(w) * I */ pe = powiu(p, e); we = gpowgs(w, e); t = gauss_primpart_try( gmul(y, conj_i(we)), pe ); if (t) y = t; /* y /= w^e */ else { /* y /= conj(w)^e, should be y /= w2^e */ y = gauss_primpart_try( gmul(y, we), pe ); swap(w, w2); exp -= e; /* += 3*e mod 4 */ } gel(P,i) = w; v = Z_pvalrem(n, p, &n); if (v) { exp -= v; /* += 3*v mod 4 */ if (is2) v <<= 1; /* 2 = w^2 I^3 */ else { gel(P2,j) = w2; gel(E2,j) = utoipos(v); j++; } gel(E,i) = stoi(e + v); } v = Z_pvalrem(d, p, &d); if (v) { exp += v; /* -= 3*v mod 4 */ if (is2) v <<= 1; /* 2 is ramified */ else { gel(P2,j) = w2; gel(E2,j) = utoineg(v); j++; } gel(E,i) = stoi(e - v); } exp &= 3; } if (j > 1) { long k = 1; GEN P1 = cgetg(l, t_COL); GEN E1 = cgetg(l, t_COL); /* remove factors with exponent 0 */ for (i = 1; i < l; i++) if (signe(gel(E,i))) { gel(P1,k) = gel(P,i); gel(E1,k) = gel(E,i); k++; } setlg(P1, k); setlg(E1, k); setlg(P2, j); setlg(E2, j); fa = famat_mul_shallow(mkmat2(P1,E1), mkmat2(P2,E2)); } if (!equali1(n) || !equali1(d)) { GEN Fa = factor(Qdivii(n, d)); P = gel(Fa,1); l = lg(P); E = gel(Fa,2); for (i = 1; i < l; i++) { GEN w, p = gel(P,i); long e; int is2; switch(mod4(p)) { case 3: continue; case 2: is2 = 1; break; default:is2 = 0; break; } e = itos(gel(E,i)); w = is2? mkcomplex(gen_1,gen_1): gauss_factor_p(p); gel(P,i) = w; if (is2) gel(E,i) = stoi(2*e); else { P = shallowconcat(P, gauss_normal( conj_i(w) )); E = shallowconcat(E, gel(E,i)); } exp -= e; /* += 3*e mod 4 */ exp &= 3; } gel(Fa,1) = P; gel(Fa,2) = E; fa = famat_mul_shallow(fa, Fa); } fa = sort_factor(fa, (void*)&gauss_cmp, &cmp_nodata); y = gmul(y, powIs(exp)); if (!gequal1(y)) { gel(fa,1) = shallowconcat(mkcol(y), gel(fa,1)); gel(fa,2) = shallowconcat(gen_1, gel(fa,2)); } return gerepilecopy(av, fa); } GEN Q_factor_limit(GEN x, ulong lim) { pari_sp av = avma; GEN a, b; if (typ(x) == t_INT) return Z_factor_limit(x, lim); a = Z_factor_limit(gel(x,1), lim); b = Z_factor_limit(gel(x,2), lim); gel(b,2) = ZC_neg(gel(b,2)); return gerepilecopy(av, merge_factor(a,b,(void*)&cmpii,cmp_nodata)); } GEN Q_factor(GEN x) { pari_sp av = avma; GEN a, b; if (typ(x) == t_INT) return Z_factor(x); a = Z_factor(gel(x,1)); b = Z_factor(gel(x,2)); gel(b,2) = ZC_neg(gel(b,2)); return gerepilecopy(av, merge_factor(a,b,(void*)&cmpii,cmp_nodata)); } /* replace t_QUAD/t_COMPLEX coeffs by t_POLMOD in T */ static GEN RgX_fix_quad(GEN x, GEN T) { long i, l, v = varn(T); GEN y = cgetg_copy(x,&l); for (i = 2; i < l; i++) { GEN c = gel(x,i); switch(typ(c)) { case t_QUAD: c++;/* fall through */ case t_COMPLEX: c = deg1pol_shallow(gel(c,2),gel(c,1),v); } gel(y,i) = c; } y[1] = x[1]; return y; } static GEN RgX_factor(GEN x, GEN dom) { pari_sp av; long pa, v, lx, r1, i; GEN p, pol, y, p1, p2; long tx = dom ? RgX_Rg_type(x,dom,&p,&pol,&pa): RgX_type(x,&p,&pol,&pa); switch(tx) { case 0: pari_err_IMPL("factor for general polynomials"); case t_POL: return RgXY_factor(x, dom); case t_INT: return ZX_factor(x); case t_FRAC: return QX_factor(x); case t_INTMOD: return factmod(x,p); case t_PADIC: return factorpadic(x,p,pa); case t_FFELT: return FFX_factor(x,pol); case t_COMPLEX: y = cgetg(3,t_MAT); av = avma; p1 = deg1_from_roots(roots(x,pa), varn(x)); gel(y,1) = p1 = gerepileupto(av, p1); gel(y,2) = const_col(lg(p1)-1, gen_1); return y; case t_REAL: y=cgetg(3,t_MAT); v=varn(x); av=avma; p1=cleanroots(x,pa); lx = lg(p1); for (r1 = 1; r1 < lx; r1++) if (typ(gel(p1,r1)) == t_COMPLEX) break; lx=(r1+lx)>>1; p2=cgetg(lx,t_COL); for (i = 1; i < r1; i++) gel(p2,i) = deg1pol_shallow(gen_1, negr(gel(p1,i)), v); for ( ; i < lx; i++) { GEN a = gel(p1,2*i-r1); p = cgetg(5, t_POL); gel(p2,i) = p; p[1] = x[1]; gel(p,2) = gnorm(a); gel(p,3) = gmul2n(gel(a,1),1); togglesign(gel(p,3)); gel(p,4) = gen_1; } gel(y,1) = gerepileupto(av,p2); gel(y,2) = const_col(lx-1, gen_1); return y; default: { GEN w = NULL, T = pol; long t1, t2; av = avma; RgX_type_decode(tx, &t1, &t2); if (t1 == t_COMPLEX) w = gen_I(); else if (t1 == t_QUAD) w = mkquad(pol,gen_0,gen_1); if (w) { /* substitute I or w by t_POLMOD */ T = leafcopy(pol); setvarn(T, fetch_var()); x = RgX_fix_quad(x, T); } switch (t2) { case t_INT: case t_FRAC: p1 = nffactor(T,x); break; case t_INTMOD: T = RgX_to_FpX(T,p); if (FpX_is_irred(T,p)) { p1 = factmod(x,mkvec2(p,T)); break; } /*fall through*/ default: if (w) (void)delete_var(); pari_err_IMPL("factor for general polynomial"); return NULL; /* LCOV_EXCL_LINE */ } if (t1 == t_POLMOD) return gerepileupto(av, p1); /* substitute back I or w */ gel(p1,1) = gsubst(liftpol_shallow(gel(p1,1)), varn(T), w); (void)delete_var(); return gerepilecopy(av, p1); } } } static GEN factor_domain(GEN x, GEN dom) { long tx = typ(x); long tdom = dom ? typ(dom): 0; pari_sp av; if (gequal0(x)) switch(tx) { case t_INT: case t_COMPLEX: case t_POL: case t_RFRAC: return prime_fact(x); default: pari_err_TYPE("factor",x); } av = avma; switch(tx) { case t_POL: return RgX_factor(x, dom); case t_RFRAC: { GEN a = gel(x,1), b = gel(x,2); GEN y = famat_inv_shallow(RgX_factor(b, dom)); if (typ(a)==t_POL) y = famat_mul_shallow(RgX_factor(a, dom), y); return gerepilecopy(av, sort_factor_pol(y, cmp_universal)); } case t_INT: if (tdom==0 || tdom==t_INT) return Z_factor(x); case t_FRAC: if (tdom==0 || tdom==t_INT) return Q_factor(x); case t_COMPLEX: /* fall through */ if (tdom==0 || tdom==t_COMPLEX) { GEN y = gauss_factor(x); if (y) return y; } /* fall through */ } pari_err_TYPE("factor",x); return NULL; /* LCOV_EXCL_LINE */ } GEN factor(GEN x) { return factor_domain(x, NULL); } /*******************************************************************/ /* */ /* ROOTS --> MONIC POLYNOMIAL */ /* */ /*******************************************************************/ static GEN normalized_mul(void *E, GEN x, GEN y) { long a = gel(x,1)[1], b = gel(y,1)[1]; (void) E; return mkvec2(mkvecsmall(a + b), RgX_mul_normalized(gel(x,2),a, gel(y,2),b)); } /* L = [Vecsmall([a]), A], with a > 0, A an RgX, deg(A) < a; return X^a + A */ static GEN normalized_to_RgX(GEN L) { long i, a = gel(L,1)[1]; GEN A = gel(L,2); GEN z = cgetg(a + 3, t_POL); z[1] = evalsigne(1) | evalvarn(varn(A)); for (i = 2; i < lg(A); i++) gel(z,i) = gcopy(gel(A,i)); for ( ; i < a+2; i++) gel(z,i) = gen_0; gel(z,i) = gen_1; return z; } /* compute prod (x - a[i]) */ GEN roots_to_pol(GEN a, long v) { pari_sp av = avma; long i, k, lx = lg(a); GEN L; if (lx == 1) return pol_1(v); L = cgetg(lx, t_VEC); for (k=1,i=1; i 5) return 0; return gsigne(RgX_disc(x)) > 0; } y = factor(x); return (lg(gcoeff(y,1,1))==l); } static int RgX_is_irred(GEN x) { pari_sp av = avma; int r = RgX_is_irred_i(x); avma = av; return r; } long isirreducible(GEN x) { switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: return 0; case t_POL: return RgX_is_irred(x); } pari_err_TYPE("isirreducible",x); return 0; } /*******************************************************************/ /* */ /* GENERIC GCD */ /* */ /*******************************************************************/ /* x is a COMPLEX or a QUAD */ static GEN triv_cont_gcd(GEN x, GEN y) { pari_sp av = avma; GEN c; if (typ(x)==t_COMPLEX) { GEN a = gel(x,1), b = gel(x,2); if (typ(a) == t_REAL || typ(b) == t_REAL) return gen_1; c = ggcd(a,b); } else c = ggcd(gel(x,2),gel(x,3)); return gerepileupto(av, ggcd(c,y)); } /* y is a PADIC, x a rational number or an INTMOD */ static GEN padic_gcd(GEN x, GEN y) { GEN p = gel(y,2); long v = gvaluation(x,p), w = valp(y); if (w < v) v = w; return powis(p, v); } /* x,y in Z[i], at least one of which is t_COMPLEX */ static GEN gauss_gcd(GEN x, GEN y) { pari_sp av = avma; GEN dx, dy; dx = denom_i(x); x = gmul(x, dx); dy = denom_i(y); y = gmul(y, dy); while (!gequal0(y)) { GEN z = gsub(x, gmul(ground(gdiv(x,y)), y)); x = y; y = z; } x = gauss_normal(x); if (typ(x) == t_COMPLEX) { if (gequal0(gel(x,2))) x = gel(x,1); else if (gequal0(gel(x,1))) x = gel(x,2); } return gerepileupto(av, gdiv(x, lcmii(dx, dy))); } static int c_is_rational(GEN x) { return is_rational_t(typ(gel(x,1))) && is_rational_t(typ(gel(x,2))); } static GEN c_zero_gcd(GEN c) { GEN x = gel(c,1), y = gel(c,2); long tx = typ(x), ty = typ(y); if (tx == t_REAL || ty == t_REAL) return gen_1; if (tx == t_PADIC || tx == t_INTMOD || ty == t_PADIC || ty == t_INTMOD) return ggcd(x, y); return gauss_gcd(c, gen_0); } /* gcd(x, 0) */ static GEN zero_gcd(GEN x) { pari_sp av; switch(typ(x)) { case t_INT: return absi(x); case t_FRAC: return absfrac(x); case t_COMPLEX: return c_zero_gcd(x); case t_REAL: return gen_1; case t_PADIC: return powis(gel(x,2), valp(x)); case t_SER: return pol_xnall(valp(x), varn(x)); case t_POLMOD: { GEN d = gel(x,2); if (typ(d) == t_POL && varn(d) == varn(gel(x,1))) return content(d); return isinexact(d)? zero_gcd(d): gcopy(d); } case t_POL: if (!isinexact(x)) break; av = avma; return gerepileupto(av, monomialcopy(content(x), RgX_val(x), varn(x))); case t_RFRAC: if (!isinexact(x)) break; av = avma; return gerepileupto(av, gdiv(zero_gcd(gel(x,1)), gel(x,2))); } return gcopy(x); } /* z is an exact zero, t_INT, t_INTMOD or t_FFELT */ static GEN zero_gcd2(GEN y, GEN z) { pari_sp av; switch(typ(z)) { case t_INT: return zero_gcd(y); case t_INTMOD: av = avma; return gerepileupto(av, gmul(y, mkintmod(gen_1,gel(z,1)))); case t_FFELT: av = avma; return gerepileupto(av, gmul(y, FF_1(z))); default: pari_err_TYPE("zero_gcd", z); } return NULL; } static GEN cont_gcd_pol_i(GEN x, GEN y) { return scalarpol(ggcd(content(x),y), varn(x));} /* tx = t_POL, y considered as constant */ static GEN cont_gcd_pol(GEN x, GEN y) { pari_sp av = avma; return gerepileupto(av, cont_gcd_pol_i(x,y)); } /* tx = t_RFRAC, y considered as constant */ static GEN cont_gcd_rfrac(GEN x, GEN y) { pari_sp av = avma; GEN cx; x = primitive_part(x, &cx); /* e.g. Mod(1,2) / (2*y+1) => primitive_part = Mod(1,2)*y^0 */ if (typ(x) != t_RFRAC) x = cont_gcd_pol_i(x, y); else x = gred_rfrac_simple(ggcd(cx? cx: gen_1, y), gel(x,2)); return gerepileupto(av, x); } /* !is_const_t(tx), tx != t_POL,t_RFRAC, y considered as constant */ static GEN cont_gcd_gen(GEN x, GEN y) { pari_sp av = avma; return gerepileupto(av, ggcd(content(x),y)); } /* !is_const(tx), y considered as constant */ static GEN cont_gcd(GEN x, long tx, GEN y) { switch(tx) { case t_RFRAC: return cont_gcd_rfrac(x,y); case t_POL: return cont_gcd_pol(x,y); default: return cont_gcd_gen(x,y); } } static GEN gcdiq(GEN x, GEN y) { GEN z; if (!signe(x)) return Q_abs(y); z = cgetg(3,t_FRAC); gel(z,1) = gcdii(x,gel(y,1)); gel(z,2) = icopy(gel(y,2)); return z; } static GEN gcdqq(GEN x, GEN y) { GEN z = cgetg(3,t_FRAC); gel(z,1) = gcdii(gel(x,1), gel(y,1)); gel(z,2) = lcmii(gel(x,2), gel(y,2)); return z; } /* assume x,y t_INT or t_FRAC */ GEN Q_gcd(GEN x, GEN y) { long tx = typ(x), ty = typ(y); if (tx == t_INT) { return (ty == t_INT)? gcdii(x,y): gcdiq(x,y); } else { return (ty == t_INT)? gcdiq(y,x): gcdqq(x,y); } } GEN ggcd(GEN x, GEN y) { long vx, vy, tx = typ(x), ty = typ(y); pari_sp av, tetpil; GEN p1,z; if (is_noncalc_t(tx) || is_matvec_t(tx) || is_noncalc_t(ty) || is_matvec_t(ty)) pari_err_TYPE2("gcd",x,y); if (tx>ty) { swap(x,y); lswap(tx,ty); } /* tx <= ty */ z = gisexactzero(x); if (z) return zero_gcd2(y,z); z = gisexactzero(y); if (z) return zero_gcd2(x,z); if (is_const_t(tx)) { if (ty == tx) switch(tx) { case t_INT: return gcdii(x,y); case t_INTMOD: z=cgetg(3,t_INTMOD); if (equalii(gel(x,1),gel(y,1))) gel(z,1) = icopy(gel(x,1)); else gel(z,1) = gcdii(gel(x,1),gel(y,1)); if (gequal1(gel(z,1))) gel(z,2) = gen_0; else { av = avma; p1 = gcdii(gel(z,1),gel(x,2)); if (!equali1(p1)) { p1 = gcdii(p1,gel(y,2)); if (equalii(p1, gel(z,1))) { cgiv(p1); p1 = gen_0; } else p1 = gerepileuptoint(av, p1); } gel(z,2) = p1; } return z; case t_FRAC: return gcdqq(x,y); case t_FFELT: if (!FF_samefield(x,y)) pari_err_OP("gcd",x,y); return FF_equal0(x) && FF_equal0(y)? FF_zero(y): FF_1(y); case t_COMPLEX: if (c_is_rational(x) && c_is_rational(y)) return gauss_gcd(x,y); return triv_cont_gcd(y,x); case t_PADIC: if (!equalii(gel(x,2),gel(y,2))) return gen_1; return powis(gel(y,2), minss(valp(x), valp(y))); case t_QUAD: av=avma; p1=gdiv(x,y); if (gequal0(gel(p1,3))) { p1=gel(p1,2); if (typ(p1)==t_INT) { avma=av; return gcopy(y); } tetpil=avma; return gerepile(av,tetpil, gdiv(y,gel(p1,2))); } if (typ(gel(p1,2))==t_INT && typ(gel(p1,3))==t_INT) {avma=av; return gcopy(y);} p1 = ginv(p1); avma=av; if (typ(gel(p1,2))==t_INT && typ(gel(p1,3))==t_INT) return gcopy(x); return triv_cont_gcd(y,x); default: return gen_1; /* t_REAL */ } if (is_const_t(ty)) switch(tx) { case t_INT: switch(ty) { case t_INTMOD: z = cgetg(3,t_INTMOD); gel(z,1) = icopy(gel(y,1)); av = avma; p1 = gcdii(gel(y,1),gel(y,2)); if (!equali1(p1)) { p1 = gcdii(x,p1); if (equalii(p1, gel(z,1))) { cgiv(p1); p1 = gen_0; } else p1 = gerepileuptoint(av, p1); } gel(z,2) = p1; return z; case t_REAL: return gen_1; case t_FRAC: return gcdiq(x,y); case t_COMPLEX: if (c_is_rational(y)) return gauss_gcd(x,y); return triv_cont_gcd(y,x); case t_FFELT: if (!FF_equal0(y)) return FF_1(y); return dvdii(x, gel(y,4))? FF_zero(y): FF_1(y); case t_PADIC: return padic_gcd(x,y); case t_QUAD: return triv_cont_gcd(y,x); default: pari_err_TYPE2("gcd",x,y); } case t_REAL: switch(ty) { case t_INTMOD: case t_FFELT: case t_PADIC: pari_err_TYPE2("gcd",x,y); default: return gen_1; } case t_INTMOD: switch(ty) { case t_FRAC: av = avma; p1=gcdii(gel(x,1),gel(y,2)); avma = av; if (!equali1(p1)) pari_err_OP("gcd",x,y); return ggcd(gel(y,1), x); case t_FFELT: { GEN p = gel(y,4); if (!dvdii(gel(x,1), p)) pari_err_OP("gcd",x,y); if (!FF_equal0(y)) return FF_1(y); return dvdii(gel(x,2),p)? FF_zero(y): FF_1(y); } case t_COMPLEX: case t_QUAD: return triv_cont_gcd(y,x); case t_PADIC: return padic_gcd(x,y); default: pari_err_TYPE2("gcd",x,y); } case t_FRAC: switch(ty) { case t_COMPLEX: if (c_is_rational(y)) return gauss_gcd(x,y); case t_QUAD: return triv_cont_gcd(y,x); case t_FFELT: { GEN p = gel(y,4); if (dvdii(gel(x,2), p)) pari_err_OP("gcd",x,y); if (!FF_equal0(y)) return FF_1(y); return dvdii(gel(x,1),p)? FF_zero(y): FF_1(y); } case t_PADIC: return padic_gcd(x,y); default: pari_err_TYPE2("gcd",x,y); } case t_FFELT: switch(ty) { case t_PADIC: { GEN p = gel(y,2); long v = valp(y); if (!equalii(p, gel(x,4)) || v < 0) pari_err_OP("gcd",x,y); return (v && FF_equal0(x))? FF_zero(x): FF_1(x); } default: pari_err_TYPE2("gcd",x,y); } case t_COMPLEX: switch(ty) { case t_PADIC: case t_QUAD: return triv_cont_gcd(x,y); default: pari_err_TYPE2("gcd",x,y); } case t_PADIC: switch(ty) { case t_QUAD: return triv_cont_gcd(y,x); default: pari_err_TYPE2("gcd",x,y); } default: return gen_1; /* tx = t_REAL */ } return cont_gcd(y,ty, x); } if (tx == t_POLMOD) { if (ty == t_POLMOD) { GEN T = gel(x,1); z = cgetg(3,t_POLMOD); T = RgX_equal_var(T,gel(y,1))? RgX_copy(T): RgX_gcd(T, gel(y,1)); gel(z,1) = T; if (degpol(T) <= 0) gel(z,2) = gen_0; else { GEN X, Y, d; av = avma; X = gel(x,2); Y = gel(y,2); d = ggcd(content(X), content(Y)); if (!gequal1(d)) { X = gdiv(X,d); Y = gdiv(Y,d); } p1 = ggcd(T, X); gel(z,2) = gerepileupto(av, gmul(d, ggcd(p1, Y))); } return z; } vx = varn(gel(x,1)); switch(ty) { case t_POL: vy = varn(y); if (varncmp(vy,vx) < 0) return cont_gcd_pol(y, x); z = cgetg(3,t_POLMOD); gel(z,1) = RgX_copy(gel(x,1)); av = avma; p1 = ggcd(gel(x,1),gel(x,2)); gel(z,2) = gerepileupto(av, ggcd(p1,y)); return z; case t_RFRAC: vy = varn(gel(y,2)); if (varncmp(vy,vx) < 0) return cont_gcd_rfrac(y, x); av = avma; p1 = ggcd(gel(x,1),gel(y,2)); if (degpol(p1)) pari_err_OP("gcd",x,y); avma = av; return gdiv(ggcd(gel(y,1),x), content(gel(y,2))); } } vx = gvar(x); vy = gvar(y); if (varncmp(vy, vx) < 0) return cont_gcd(y,ty, x); if (varncmp(vy, vx) > 0) return cont_gcd(x,tx, y); /* vx = vy: same main variable */ switch(tx) { case t_POL: switch(ty) { case t_POL: return RgX_gcd(x,y); case t_SER: z = ggcd(content(x), content(y)); return monomialcopy(z, minss(valp(y),gval(x,vx)), vx); case t_RFRAC: return cont_gcd_rfrac(y, x); } break; case t_SER: z = ggcd(content(x), content(y)); switch(ty) { case t_SER: return monomialcopy(z, minss(valp(x),valp(y)), vx); case t_RFRAC: return monomialcopy(z, minss(valp(x),gval(y,vx)), vx); } break; case t_RFRAC: { GEN xd = gel(x,2), yd = gel(y,2); if (ty != t_RFRAC) pari_err_TYPE2("gcd",x,y); z = cgetg(3,t_RFRAC); av = avma; gel(z,2) = gerepileupto(av, RgX_mul(xd, RgX_div(yd, RgX_gcd(xd, yd)))); gel(z,1) = ggcd(gel(x,1), gel(y,1)); return z; } } pari_err_TYPE2("gcd",x,y); return NULL; /* LCOV_EXCL_LINE */ } GEN ggcd0(GEN x, GEN y) { return y? ggcd(x,y): content(x); } static GEN fix_lcm(GEN x) { GEN t; switch(typ(x)) { case t_INT: if (signe(x)<0) x = negi(x); break; case t_POL: if (lg(x) <= 2) break; t = leading_coeff(x); if (typ(t) == t_INT && signe(t) < 0) x = gneg(x); } return x; } GEN glcm0(GEN x, GEN y) { if (!y) return fix_lcm(gassoc_proto(glcm,x,y)); return glcm(x,y); } GEN glcm(GEN x, GEN y) { pari_sp av; GEN z; if (typ(x)==t_INT && typ(y)==t_INT) return lcmii(x,y); av = avma; z = ggcd(x,y); if (!gequal1(z)) { if (gequal0(z)) { avma = av; return gmul(x,y); } y = gdiv(y,z); } return gerepileupto(av, fix_lcm(gmul(x,y))); } /* x + r ~ x ? Assume x,r are t_POL, deg(r) <= deg(x) */ static int pol_approx0(GEN r, GEN x, int exact) { long i, lx,lr; if (exact) return gequal0(r); lx = lg(x); lr = lg(r); if (lr < lx) lx = lr; for (i=2; i1) pari_warn(warnmem,"RgX_gcd_simple"); gerepileall(av,2, &x,&y); } } } GEN RgX_extgcd_simple(GEN a, GEN b, GEN *pu, GEN *pv) { pari_sp av = avma; GEN q, r, d, d1, u, v, v1; int exact = !(isinexactreal(a) || isinexactreal(b)); d = a; d1 = b; v = gen_0; v1 = gen_1; for(;;) { if (pol_approx0(d1, a, exact)) break; q = poldivrem(d,d1, &r); v = gsub(v, gmul(q,v1)); u=v; v=v1; v1=u; u=r; d=d1; d1=u; } u = gsub(d, gmul(b,v)); u = RgX_div(u,a); gerepileall(av, 3, &u,&v,&d); *pu = u; *pv = v; return d; } /*******************************************************************/ /* */ /* CONTENT / PRIMITIVE PART */ /* */ /*******************************************************************/ GEN content(GEN x) { long lx, i, t, tx = typ(x); pari_sp av = avma; GEN c; if (is_scalar_t(tx)) return zero_gcd(x); switch(tx) { case t_RFRAC: { GEN n = gel(x,1), d = gel(x,2); /* -- varncmp(vn, vd) < 0 can't happen * -- if n is POLMOD, its main variable (in the sense of gvar2) * has lower priority than denominator */ if (typ(n) == t_POLMOD || varncmp(gvar(n), varn(d)) > 0) n = isinexact(n)? zero_gcd(n): gcopy(n); else n = content(n); return gerepileupto(av, gdiv(n, content(d))); } case t_VEC: case t_COL: lx = lg(x); if (lx==1) return gen_0; break; case t_MAT: { long hx, j; lx = lg(x); if (lx == 1) return gen_0; hx = lgcols(x); if (hx == 1) return gen_0; if (lx == 2) { x = gel(x,1); lx = lg(x); break; } if (hx == 2) { x = row_i(x, 1, 1, lx-1); break; } c = content(gel(x,1)); for (j=2; j lx) { /* integer coeffs */ while (lx-- > lontyp[tx]) { c = gcdii(c, gel(x,lx)); if (equali1(c)) { avma=av; return gen_1; } } } else { if (isinexact(c)) c = zero_gcd(c); while (lx-- > lontyp[tx]) { GEN d = gel(x,lx); t = typ(d); if (is_matvec_t(t)) d = content(d); c = ggcd(c, d); } if (isinexact(c)) { avma=av; return gen_1; } } switch(typ(c)) { case t_INT: if (signe(c) < 0) c = negi(c); break; case t_VEC: case t_COL: case t_MAT: pari_err_TYPE("content",x); } return av==avma? gcopy(c): gerepileupto(av,c); } GEN primitive_part(GEN x, GEN *ptc) { pari_sp av = avma; GEN c = content(x); if (gequal1(c)) { avma = av; c = NULL; } else if (!gequal0(c)) x = gdiv(x,c); if (ptc) *ptc = c; return x; } GEN primpart(GEN x) { return primitive_part(x, NULL); } static GEN Q_content_v(GEN x, long i, long l) { pari_sp av = avma; GEN d = Q_content_safe(gel(x,i)); if (!d) return NULL; for (i++; i < l; i++) { GEN c = Q_content_safe(gel(x,i)); if (!c) return NULL; d = Q_gcd(d, c); } return gerepileupto(av, d); } /* As content(), but over Q. Treats polynomial as elts of Q[x1,...xn], instead * of Q(x2,...,xn)[x1] */ GEN Q_content_safe(GEN x) { long l; switch(typ(x)) { case t_INT: return absi(x); case t_FRAC: return absfrac(x); case t_COMPLEX: case t_VEC: case t_COL: case t_MAT: l = lg(x); return l==1? gen_1: Q_content_v(x, 1, l); case t_POL: l = lg(x); return l==2? gen_0: Q_content_v(x, 2, l); case t_POLMOD: return Q_content_safe(gel(x,2)); case t_RFRAC: { GEN a, b; a = Q_content(gel(x,1)); if (!a) return NULL; b = Q_content(gel(x,2)); if (!b) return NULL; return gdiv(a, b); } } return NULL; } GEN Q_content(GEN x) { GEN c = Q_content_safe(x); if (!c) pari_err_TYPE("Q_content",x); return c; } GEN ZX_content(GEN x) { long i, l = lg(x); GEN d; pari_sp av; if (l == 2) return gen_0; d = gel(x,2); if (l == 3) return absi(d); av = avma; for (i=3; !is_pm1(d) && i 3); } /* compute U, V s.t Ux + Vy = resultant(x,y) */ static GEN subresext_i(GEN x, GEN y, GEN *U, GEN *V) { pari_sp av, av2; long dx, dy, du, signh, tx = typ(x), ty = typ(y); GEN r, z, g, h, p1, cu, cv, u, v, um1, uze, vze; if (!is_extscalar_t(tx)) pari_err_TYPE("subresext",x); if (!is_extscalar_t(ty)) pari_err_TYPE("subresext",y); if (gequal0(x) || gequal0(y)) { *U = *V = gen_0; return gen_0; } if (tx != t_POL) { if (ty != t_POL) { *U = ginv(x); *V = gen_0; return gen_1; } return scalar_res(y,x,V,U); } if (ty != t_POL) return scalar_res(x,y,U,V); if (varn(x) != varn(y)) return varncmp(varn(x), varn(y)) < 0? scalar_res(x,y,U,V) : scalar_res(y,x,V,U); if (gequal0(leading_coeff(x))) x = RgX_renormalize(x); if (gequal0(leading_coeff(y))) y = RgX_renormalize(y); dx = degpol(x); dy = degpol(y); signh = 1; if (dx < dy) { pswap(U,V); lswap(dx,dy); swap(x,y); if (both_odd(dx, dy)) signh = -signh; } if (dy == 0) { *V = gpowgs(gel(y,2),dx-1); *U = gen_0; return gmul(*V,gel(y,2)); } av = avma; u = x = primitive_part(x, &cu); v = y = primitive_part(y, &cv); g = h = gen_1; av2 = avma; um1 = gen_1; uze = gen_0; for(;;) { if (!subres_step(&u, &v, &g, &h, &uze, &um1, &signh)) break; if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"subresext, dr = %ld", degpol(v)); gerepileall(av2,6, &u,&v,&g,&h,&uze,&um1); } } /* uze an RgX */ if (!u) { *U = *V = gen_0; avma = av; return gen_0; } z = gel(v,2); du = degpol(u); if (du > 1) { /* z = gdivexact(gpowgs(z,du), gpowgs(h,du-1)); */ p1 = gpowgs(gdiv(z,h),du-1); z = gmul(z,p1); uze = RgX_Rg_mul(uze, p1); } if (signh < 0) { z = gneg_i(z); uze = RgX_neg(uze); } vze = RgX_divrem(Rg_RgX_sub(z, RgX_mul(uze,x)), y, &r); if (signe(r)) pari_warn(warner,"inexact computation in subresext"); /* uze ppart(x) + vze ppart(y) = z = resultant(ppart(x), ppart(y)), */ p1 = gen_1; if (cu) p1 = gmul(p1, gpowgs(cu,dy)); if (cv) p1 = gmul(p1, gpowgs(cv,dx)); cu = cu? gdiv(p1,cu): p1; cv = cv? gdiv(p1,cv): p1; z = gmul(z,p1); *U = RgX_Rg_mul(uze,cu); *V = RgX_Rg_mul(vze,cv); return z; } GEN subresext(GEN x, GEN y, GEN *U, GEN *V) { pari_sp av = avma; GEN z = subresext_i(x, y, U, V); gerepileall(av, 3, &z, U, V); return z; } static GEN zero_extgcd(GEN y, GEN *U, GEN *V, long vx) { GEN x=content(y); *U=pol_0(vx); *V = scalarpol(ginv(x), vx); return gmul(y,*V); } static int must_negate(GEN x) { GEN t = leading_coeff(x); switch(typ(t)) { case t_INT: case t_REAL: return (signe(t) < 0); case t_FRAC: return (signe(gel(t,1)) < 0); } return 0; } /* compute U, V s.t Ux + Vy = GCD(x,y) using subresultant */ GEN RgX_extgcd(GEN x, GEN y, GEN *U, GEN *V) { pari_sp av, av2, tetpil; long signh; /* junk */ long dx, dy, vx, tx = typ(x), ty = typ(y); GEN z, g, h, p1, cu, cv, u, v, um1, uze, vze, *gptr[3]; if (tx!=t_POL) pari_err_TYPE("RgX_extgcd",x); if (ty!=t_POL) pari_err_TYPE("RgX_extgcd",y); if ( varncmp(varn(x),varn(y))) pari_err_VAR("RgX_extgcd",x,y); vx=varn(x); if (!signe(x)) { if (signe(y)) return zero_extgcd(y,U,V,vx); *U = pol_0(vx); *V = pol_0(vx); return pol_0(vx); } if (!signe(y)) return zero_extgcd(x,V,U,vx); dx = degpol(x); dy = degpol(y); if (dx < dy) { pswap(U,V); lswap(dx,dy); swap(x,y); } if (dy==0) { *U=pol_0(vx); *V=ginv(y); return pol_1(vx); } av = avma; u = x = primitive_part(x, &cu); v = y = primitive_part(y, &cv); g = h = gen_1; av2 = avma; um1 = gen_1; uze = gen_0; for(;;) { if (!subres_step(&u, &v, &g, &h, &uze, &um1, &signh)) break; if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgX_extgcd, dr = %ld",degpol(v)); gerepileall(av2,6,&u,&v,&g,&h,&uze,&um1); } } if (uze != gen_0) { GEN r; vze = RgX_divrem(RgX_sub(v, RgX_mul(uze,x)), y, &r); if (signe(r)) pari_warn(warner,"inexact computation in RgX_extgcd"); if (cu) uze = RgX_Rg_div(uze,cu); if (cv) vze = RgX_Rg_div(vze,cv); p1 = ginv(content(v)); } else /* y | x */ { vze = cv ? RgX_Rg_div(pol_1(vx),cv): pol_1(vx); uze = pol_0(vx); p1 = gen_1; } if (must_negate(v)) p1 = gneg(p1); tetpil = avma; z = RgX_Rg_mul(v,p1); *U = RgX_Rg_mul(uze,p1); *V = RgX_Rg_mul(vze,p1); gptr[0] = &z; gptr[1] = U; gptr[2] = V; gerepilemanysp(av,tetpil,gptr,3); return z; } int RgXQ_ratlift(GEN x, GEN T, long amax, long bmax, GEN *P, GEN *Q) { pari_sp av = avma, av2, tetpil; long signh; /* junk */ long vx; GEN g, h, p1, cu, cv, u, v, um1, uze, *gptr[2]; if (typ(x)!=t_POL) pari_err_TYPE("RgXQ_ratlift",x); if (typ(T)!=t_POL) pari_err_TYPE("RgXQ_ratlift",T); if ( varncmp(varn(x),varn(T)) ) pari_err_VAR("RgXQ_ratlift",x,T); if (bmax < 0) pari_err_DOMAIN("ratlift", "bmax", "<", gen_0, stoi(bmax)); if (!signe(T)) { if (degpol(x) <= amax) { *P = RgX_copy(x); *Q = pol_1(varn(x)); return 1; } return 0; } if (amax+bmax >= degpol(T)) pari_err_DOMAIN("ratlift", "amax+bmax", ">=", stoi(degpol(T)), mkvec3(stoi(amax), stoi(bmax), T)); vx = varn(T); u = x = primitive_part(x, &cu); v = T = primitive_part(T, &cv); g = h = gen_1; av2 = avma; um1 = gen_1; uze = gen_0; for(;;) { (void) subres_step(&u, &v, &g, &h, &uze, &um1, &signh); if (!u || (typ(uze)==t_POL && degpol(uze)>bmax)) { avma=av; return 0; } if (typ(v)!=t_POL || degpol(v)<=amax) break; if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgXQ_ratlift, dr = %ld", degpol(v)); gerepileall(av2,6,&u,&v,&g,&h,&uze,&um1); } } if (uze == gen_0) { avma = av; *P = pol_0(vx); *Q = pol_1(vx); return 1; } if (cu) uze = RgX_Rg_div(uze,cu); p1 = ginv(content(v)); if (must_negate(v)) p1 = gneg(p1); tetpil = avma; *P = RgX_Rg_mul(v,p1); *Q = RgX_Rg_mul(uze,p1); gptr[0] = P; gptr[1] = Q; gerepilemanysp(av,tetpil,gptr,2); return 1; } /*******************************************************************/ /* */ /* RESULTANT USING DUCOS VARIANT */ /* */ /*******************************************************************/ /* x^n / y^(n-1), assume n > 0 */ static GEN Lazard(GEN x, GEN y, long n) { long a; GEN c; if (n == 1) return x; a = 1 << expu(n); /* a = 2^k <= n < 2^(k+1) */ c=x; n-=a; while (a>1) { a>>=1; c=gdivexact(gsqr(c),y); if (n>=a) { c=gdivexact(gmul(c,x),y); n -= a; } } return c; } /* F (x/y)^(n-1), assume n >= 1 */ static GEN Lazard2(GEN F, GEN x, GEN y, long n) { if (n == 1) return F; return RgX_Rg_divexact(RgX_Rg_mul(F, Lazard(x,y,n-1)), y); } static GEN RgX_neg_i(GEN x, long lx) { long i; GEN y = cgetg(lx, t_POL); y[1] = x[1]; for (i=2; i 1 && gequal0(gel(x,i))) i--; return i+1; } #define addshift(x,y) RgX_addmulXn_shallow((x),(y),1) /* delta = deg(P) - deg(Q) > 0, deg(Q) > 0, P,Q,Z t_POL in the same variable, * s "scalar". Return prem(P, -Q) / s^delta lc(P) */ static GEN nextSousResultant(GEN P, GEN Q, GEN Z, GEN s) { GEN p0, q0, h0, TMP, H, A, z0 = leading_coeff(Z); long p, q, j, lP, lQ; pari_sp av; p = degpol(P); p0 = gel(P,p+2); lP = reductum_lg(P,lg(P)); q = degpol(Q); q0 = gel(Q,q+2); lQ = reductum_lg(Q,lg(Q)); /* p > q. Very often p - 1 = q */ av = avma; /* H = RgX_neg(reductum(Z)) optimized, using Q ~ Z */ H = RgX_neg_i(Z, lQ); /* deg H < q */ A = (q+2 < lP)? RgX_Rg_mul_i(H, gel(P,q+2), lQ): NULL; for (j = q+1; j < p; j++) { if (degpol(H) == q-1) { /* h0 = coeff of degree q-1 = leading coeff */ h0 = gel(H,q+1); (void)normalizepol_lg(H, q+1); H = addshift(H, RgX_Rg_divexact(RgX_Rg_mul_i(Q, gneg(h0), lQ), q0)); } else H = RgX_shift_shallow(H, 1); if (j+2 < lP) { TMP = RgX_Rg_mul(H, gel(P,j+2)); A = A? RgX_add(A, TMP): TMP; } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"nextSousResultant j = %ld/%ld",j,p); gerepileall(av,A?2:1,&H,&A); } } if (q+2 < lP) lP = reductum_lg(P, q+3); TMP = RgX_Rg_mul_i(P, z0, lP); A = A? RgX_add(A, TMP): TMP; A = RgX_Rg_divexact(A, p0); if (degpol(H) == q-1) { h0 = gel(H,q+1); (void)normalizepol_lg(H, q+1); /* destroy old H */ A = RgX_add(RgX_Rg_mul(addshift(H,A),q0), RgX_Rg_mul_i(Q, gneg(h0), lQ)); } else A = RgX_Rg_mul(addshift(H,A), q0); return RgX_Rg_divexact(A, s); } #undef addshift /* Ducos's subresultant */ GEN RgX_resultant_all(GEN P, GEN Q, GEN *sol) { pari_sp av, av2; long dP, dQ, delta, sig = 1; GEN cP, cQ, Z, s; dP = degpol(P); dQ = degpol(Q); delta = dP - dQ; if (delta < 0) { if (both_odd(dP, dQ)) sig = -1; swap(P,Q); lswap(dP, dQ); delta = -delta; } if (sol) *sol = gen_0; av = avma; if (dQ <= 0) { if (dQ < 0) return Rg_get_0(P); s = gpowgs(gel(Q,2), dP); if (sig == -1) s = gerepileupto(av, gneg(s)); return s; } /* primitive_part is also possible here, but possibly very costly, * and hardly ever worth it */ P = Q_primitive_part(P, &cP); Q = Q_primitive_part(Q, &cQ); av2 = avma; s = gpowgs(leading_coeff(Q),delta); if (both_odd(dP, dQ)) sig = -sig; Z = Q; Q = RgX_pseudorem(P, Q); P = Z; while(degpol(Q) > 0) { delta = degpol(P) - degpol(Q); /* > 0 */ Z = Lazard2(Q, leading_coeff(Q), s, delta); if (both_odd(degpol(P), degpol(Q))) sig = -sig; Q = nextSousResultant(P, Q, Z, s); P = Z; if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"resultant_all, degpol Q = %ld",degpol(Q)); gerepileall(av2,2,&P,&Q); } s = leading_coeff(P); } if (!signe(Q)) { avma = av; return Rg_get_0(Q); } s = Lazard(leading_coeff(Q), s, degpol(P)); if (sig == -1) s = gneg(s); if (cP) s = gmul(s, gpowgs(cP,dQ)); if (cQ) s = gmul(s, gpowgs(cQ,dP)); if (sol) { *sol = P; gerepileall(av, 2, &s, sol); return s; } return gerepilecopy(av, s); } /* Return resultant(P,Q). * Uses Sylvester's matrix if P or Q inexact, a modular algorithm if they * are in Q[X], and Ducos/Lazard optimization of the subresultant algorithm * in the "generic" case. */ GEN resultant(GEN P, GEN Q) { long TP, TQ; GEN s, p = NULL; if ((s = init_resultant(P,Q))) return s; if ((TP = RgX_simpletype(P)) == t_REAL || (TQ = RgX_simpletype(Q)) == t_REAL) return resultant2(P,Q); /* inexact */ if (TP && TQ) /* rational */ { if (TP == t_INT && TQ == t_INT) return ZX_resultant(P,Q); return QX_resultant(P,Q); } if (RgX_is_FpX(P, &p) && RgX_is_FpX(Q, &p) && p) { pari_sp av = avma; GEN r = FpX_resultant(RgX_to_FpX(P, p), RgX_to_FpX(Q, p), p); return gerepileupto(av, Fp_to_mod(r, p)); } return RgX_resultant_all(P, Q, NULL); } /*******************************************************************/ /* */ /* RESULTANT USING SYLVESTER MATRIX */ /* */ /*******************************************************************/ static GEN syl_RgC(GEN x, long j, long d, long D, long cp) { GEN c = cgetg(d+1,t_COL); long i; for (i=1; i< j; i++) gel(c,i) = gen_0; for ( ; i<=D; i++) { GEN t = gel(x,D-i+2); gel(c,i) = cp? gcopy(t): t; } for ( ; i<=d; i++) gel(c,i) = gen_0; return c; } static GEN syl_RgM(GEN x, GEN y, long cp) { long j, d, dx = degpol(x), dy = degpol(y); GEN M; if (dx < 0) return dy < 0? cgetg(1,t_MAT): zeromat(dy,dy); if (dy < 0) return zeromat(dx,dx); d = dx+dy; M = cgetg(d+1,t_MAT); for (j=1; j<=dy; j++) gel(M,j) = syl_RgC(x,j,d,j+dx, cp); for (j=1; j<=dx; j++) gel(M,j+dy) = syl_RgC(y,j,d,j+dy, cp); return M; } GEN RgX_sylvestermatrix(GEN x, GEN y) { return syl_RgM(x,y,0); } GEN sylvestermatrix(GEN x, GEN y) { if (typ(x)!=t_POL) pari_err_TYPE("sylvestermatrix",x); if (typ(y)!=t_POL) pari_err_TYPE("sylvestermatrix",y); if (varn(x) != varn(y)) pari_err_VAR("sylvestermatrix",x,y); return syl_RgM(x,y,1); } GEN resultant2(GEN x, GEN y) { pari_sp av = avma; GEN r = init_resultant(x,y); return r? r: gerepileupto(av, det(RgX_sylvestermatrix(x,y))); } /* let vx = main variable of x, v0 a variable of highest priority; * return a t_POL in variable v0: * if vx <= v, return subst(x, v, pol_x(v0)) * if vx > v, return scalarpol(x, v0) */ static GEN fix_pol(GEN x, long v, long v0) { long vx, tx = typ(x); if (tx != t_POL) vx = gvar(x); else { /* shortcut: almost nothing to do */ vx = varn(x); if (v == vx) { if (v0 != v) { x = leafcopy(x); setvarn(x, v0); } return x; } } if (varncmp(v, vx) > 0) { x = gsubst(x, v, pol_x(v0)); if (typ(x) != t_POL) vx = gvar(x); else { vx = varn(x); if (vx == v0) return x; } } if (varncmp(vx, v0) <= 0) pari_err_TYPE("polresultant", x); return scalarpol_shallow(x, v0); } /* resultant of x and y with respect to variable v, or with respect to their * main variable if v < 0. */ GEN polresultant0(GEN x, GEN y, long v, long flag) { long v0 = 0; pari_sp av = avma; if (v >= 0) { v0 = fetch_var_higher(); x = fix_pol(x,v, v0); y = fix_pol(y,v, v0); } switch(flag) { case 2: case 0: x=resultant(x,y); break; case 1: x=resultant2(x,y); break; default: pari_err_FLAG("polresultant"); } if (v >= 0) (void)delete_var(); return gerepileupto(av,x); } GEN polresultantext0(GEN x, GEN y, long v) { GEN R, U, V; long v0 = 0; pari_sp av = avma; if (v >= 0) { v0 = fetch_var_higher(); x = fix_pol(x,v, v0); y = fix_pol(y,v, v0); } R = subresext_i(x,y, &U,&V); if (v >= 0) { (void)delete_var(); if (typ(U) == t_POL && varn(U) != v) U = poleval(U, pol_x(v)); if (typ(V) == t_POL && varn(V) != v) V = poleval(V, pol_x(v)); } return gerepilecopy(av, mkvec3(U,V,R)); } GEN polresultantext(GEN x, GEN y) { return polresultantext0(x,y,-1); } /*******************************************************************/ /* */ /* CHARACTERISTIC POLYNOMIAL USING RESULTANT */ /* */ /*******************************************************************/ /* (v - x)^d */ static GEN caract_const(pari_sp av, GEN x, long v, long d) { return gerepileupto(av, gpowgs(deg1pol_shallow(gen_1, gneg_i(x), v), d)); } /* return caract(Mod(x,T)) in variable v */ GEN RgXQ_charpoly(GEN x, GEN T, long v) { pari_sp av = avma; long d = degpol(T), dx, vx, vp, v0; GEN ch, L; if (typ(x) != t_POL) return caract_const(av, x, v, d); vx = varn(x); vp = varn(T); if (varncmp(vx, vp) > 0) return caract_const(av, x, v, d); if (varncmp(vx, vp) < 0) pari_err_PRIORITY("RgXQ_charpoly", x, "<", vp); dx = degpol(x); if (dx >= degpol(T)) { x = RgX_rem(x, T); dx = degpol(x); } if (dx <= 0) return dx? pol_xn(d, v): caract_const(av, gel(x,2), v, d); v0 = fetch_var_higher(); x = RgX_neg(x); gel(x,2) = gadd(gel(x,2), pol_x(v)); setvarn(x, v0); T = leafcopy(T); setvarn(T, v0); ch = resultant(T, x); (void)delete_var(); /* test for silly input: x mod (deg 0 polynomial) */ if (typ(ch) != t_POL) pari_err_PRIORITY("RgXQ_charpoly", pol_x(v), "<", gvar(ch)); L = leading_coeff(ch); if (!gequal1(L)) ch = RgX_Rg_div(ch, L); return gerepileupto(av, ch); } /* characteristic polynomial (in v) of x over nf, where x is an element of the * algebra nf[t]/(Q(t)) */ GEN rnfcharpoly(GEN nf, GEN Q, GEN x, long v) { const char *f = "rnfcharpoly"; long dQ = degpol(Q); pari_sp av = avma; GEN T; if (v < 0) v = 0; nf = checknf(nf); T = nf_get_pol(nf); Q = RgX_nffix(f, T,Q,0); switch(typ(x)) { case t_INT: case t_FRAC: return caract_const(av, x, v, dQ); case t_POLMOD: x = polmod_nffix2(f,T,Q, x,0); break; case t_POL: x = varn(x) == varn(T)? Rg_nffix(f,T,x,0): RgX_nffix(f, T,x,0); break; default: pari_err_TYPE(f,x); } if (typ(x) != t_POL) return caract_const(av, x, v, dQ); /* x a t_POL in variable vQ */ if (degpol(x) >= dQ) x = RgX_rem(x, Q); if (dQ <= 1) return caract_const(av, constant_coeff(x), v, 1); return gerepilecopy(av, lift_if_rational( RgXQ_charpoly(x, Q, v) )); } /*******************************************************************/ /* */ /* GCD USING SUBRESULTANT */ /* */ /*******************************************************************/ static int inexact(GEN x, int *simple, int *rational); static int isinexactall(GEN x, int *simple, int *rational) { long i, lx = lg(x); for (i=2; i 0) x = RgX_gcd_simple(x,y); else { dx = lg(x); dy = lg(y); if (dx < dy) { swap(x,y); lswap(dx,dy); } if (dy==3) { d = ggcd(gel(y,2), content(x)); return gerepileupto(av, scalarpol(d, varn(x))); } u = primitive_part(x, &p1); if (!p1) p1 = gen_1; v = primitive_part(y, &p2); if (!p2) p2 = gen_1; d = ggcd(p1,p2); av1 = avma; g = h = gen_1; for(;;) { GEN r = RgX_pseudorem(u,v); long degq, du, dv, dr = lg(r); if (!signe(r)) break; if (dr <= 3) { avma = av1; return gerepileupto(av, scalarpol(d, varn(x))); } if (DEBUGLEVEL > 9) err_printf("RgX_gcd: dr = %ld\n", degpol(r)); du = lg(u); dv = lg(v); degq = du-dv; u = v; p1 = g; g = leading_coeff(u); switch(degq) { case 0: break; case 1: p1 = gmul(h,p1); h = g; break; default: p1 = gmul(gpowgs(h,degq), p1); h = gdiv(gpowgs(g,degq), gpowgs(h,degq-1)); } v = RgX_Rg_div(r,p1); if (gc_needed(av1,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgX_gcd"); gerepileall(av1,4, &u,&v,&g,&h); } } x = RgX_Rg_mul(primpart(v), d); } if (must_negate(x)) x = RgX_neg(x); return gerepileupto(av,x); } /* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */ static GEN RgX_disc_aux(GEN P) { long n = degpol(P), TP, dd; GEN N, D, L, y, p; if (!signe(P) || !n) return Rg_get_0(P); if (n == 1) return Rg_get_1(P); if (n == 2) { GEN a = gel(P,4), b = gel(P,3), c = gel(P,2); return gsub(gsqr(b), gmul2n(gmul(a,c),2)); } TP = RgX_simpletype(P); if (TP == t_INT) return ZX_disc(P); if (TP == t_FRAC) return QX_disc(P); p = NULL; if (RgX_is_FpX(P, &p) && p) return Fp_to_mod(FpX_disc(RgX_to_FpX(P,p), p), p); y = RgX_deriv(P); N = characteristic(P); if (signe(N)) y = gmul(y, mkintmod(gen_1,N)); if (!signe(y)) return Rg_get_0(y); dd = degpol(P)-2 - degpol(y); if (TP == t_REAL) D = resultant2(P,y); else { D = RgX_resultant_all(P, y, NULL); if (D == gen_0) return Rg_get_0(y); } L = leading_coeff(P); if (dd && !gequal1(L)) D = (dd == -1)? gdiv(D, L): gmul(D, gpowgs(L, dd)); if (n & 2) D = gneg(D); return D; } GEN RgX_disc(GEN x) { pari_sp av = avma; return gerepileupto(av, RgX_disc_aux(x)); } GEN poldisc0(GEN x, long v) { long v0, tx = typ(x); pari_sp av; GEN D; if (tx == t_POL && (v < 0 || v == varn(x))) return RgX_disc(x); switch(tx) { case t_COMPLEX: return utoineg(4); case t_QUAD: return quad_disc(x); case t_POLMOD: if (v >= 0 && varn(gel(x,1)) != v) break; return RgX_disc(gel(x,1)); case t_QFR: case t_QFI: av = avma; return gerepileuptoint(av, qfb_disc(x)); case t_VEC: case t_COL: case t_MAT: { long i; GEN z = cgetg_copy(x, &i); for (i--; i; i--) gel(z,i) = poldisc0(gel(x,i), v); return z; } } if (v < 0) pari_err_TYPE("poldisc",x); av = avma; v0 = fetch_var_higher(); x = fix_pol(x,v, v0); D = RgX_disc(x); (void)delete_var(); return gerepileupto(av, D); } GEN reduceddiscsmith(GEN x) { long j, n = degpol(x); pari_sp av = avma; GEN xp, M; if (typ(x) != t_POL) pari_err_TYPE("poldiscreduced",x); if (n<=0) pari_err_CONSTPOL("poldiscreduced"); RgX_check_ZX(x,"poldiscreduced"); if (!gequal1(gel(x,n+2))) pari_err_IMPL("non-monic polynomial in poldiscreduced"); M = cgetg(n+1,t_MAT); xp = ZX_deriv(x); for (j=1; j<=n; j++) { gel(M,j) = RgX_to_RgC(xp, n); if (j 0) { d = (vx == NO_VARIABLE)? ginv(x): gred_rfrac_simple(gen_1, x); return scalarpol(d, vy); } if (lg(x)!=3) pari_err_INV("RgXQ_inv",mkpolmod(x,y)); x = gel(x,2); vx = gvar(x); } av = avma; d = subresext_i(x,y,&u,&v/*junk*/); if (gequal0(d)) pari_err_INV("RgXQ_inv",mkpolmod(x,y)); d = gdiv(u,d); if (typ(d) != t_POL || varn(d) != vy) d = scalarpol(d, vy); return gerepileupto(av, d); } /*Assume x is a polynomial and y is not */ static GEN scalar_bezout(GEN x, GEN y, GEN *U, GEN *V) { long vx = varn(x); int xis0 = signe(x)==0, yis0 = gequal0(y); if (xis0 && yis0) { *U = *V = pol_0(vx); return pol_0(vx); } if (yis0) { *U=pol_1(vx); *V = pol_0(vx); return RgX_copy(x);} *U=pol_0(vx); *V= ginv(y); return pol_1(vx); } /* Assume x==0, y!=0 */ static GEN zero_bezout(GEN y, GEN *U, GEN *V) { *U=gen_0; *V = ginv(y); return gen_1; } GEN gbezout(GEN x, GEN y, GEN *u, GEN *v) { long tx=typ(x), ty=typ(y), vx; if (tx == t_INT && ty == t_INT) return bezout(x,y,u,v); if (tx != t_POL) { if (ty == t_POL) return scalar_bezout(y,x,v,u); else { int xis0 = gequal0(x), yis0 = gequal0(y); if (xis0 && yis0) { *u = *v = gen_0; return gen_0; } if (xis0) return zero_bezout(y,u,v); else return zero_bezout(x,v,u); } } else if (ty != t_POL) return scalar_bezout(x,y,u,v); vx = varn(x); if (vx != varn(y)) return varncmp(vx, varn(y)) < 0? scalar_bezout(x,y,u,v) : scalar_bezout(y,x,v,u); return RgX_extgcd(x,y,u,v); } GEN gcdext0(GEN x, GEN y) { GEN z=cgetg(4,t_VEC); gel(z,3) = gbezout(x,y,(GEN*)(z+1),(GEN*)(z+2)); return z; } /*******************************************************************/ /* */ /* GENERIC (modular) INVERSE */ /* */ /*******************************************************************/ GEN ginvmod(GEN x, GEN y) { long tx=typ(x); switch(typ(y)) { case t_POL: if (tx==t_POL) return RgXQ_inv(x,y); if (is_scalar_t(tx)) return ginv(x); break; case t_INT: if (tx==t_INT) return Fp_inv(x,y); if (tx==t_POL) return gen_0; } pari_err_TYPE2("ginvmod",x,y); return NULL; /* LCOV_EXCL_LINE */ } /***********************************************************************/ /** **/ /** NEWTON POLYGON **/ /** **/ /***********************************************************************/ /* assume leading coeff of x is non-zero */ GEN newtonpoly(GEN x, GEN p) { GEN y; long n,ind,a,b,c,u1,u2,r1,r2; long *vval, num[] = {evaltyp(t_INT) | _evallg(3), 0, 0}; if (typ(x)!=t_POL) pari_err_TYPE("newtonpoly",x); n=degpol(x); if (n<=0) return cgetg(1,t_VEC); y = cgetg(n+1,t_VEC); x += 2; /* now x[i] = term of degree i */ vval = (long *) pari_malloc(sizeof(long)*(n+1)); for (a=0; a<=n; a++) vval[a] = gvaluation(gel(x,a),p); for (a=0, ind=1; a n2, is undefined! */ GEN iLP; /* iLP[p] = i such that LV[p] = [LP[i],...] */ GEN id2; /* id2[i] = powers of ideal i */ GEN L_jid; /* indexes of "useful" prime ideals for rnd_rel */ long KC, KCZ, KCZ2; GEN subFB; /* LP o subFB = part of FB used to build random relations */ int sfb_chg; /* need to change subFB ? */ int newpow; /* need to compute powFB */ GEN perm; /* permutation of LP used to represent relations [updated by hnfspec/hnfadd: dense rows come first] */ GEN vecG, G0; GEN idealperm; /* permutation of ideals under field automorphisms */ GEN minidx; /* minidx[i] min ideal in orbit of LP[i] under field autom */ subFB_t *allsubFB; /* all subFB's used */ GEN embperm; /* permutations of the complex embeddings */ GEN invs; /* inverse of automorphism */ } FB_t; enum { sfb_CHANGE = 1, sfb_INCREASE = 2 }; typedef struct REL_t { GEN R; /* relation vector as t_VECSMALL; clone */ long nz; /* index of first non-zero elt in R (hash) */ GEN m; /* pseudo-minimum yielding the relation; clone */ long relorig; /* relation this one is an image of */ long relaut; /* automorphim used to compute this relation from the original */ GEN junk[3]; /*make sure sizeof(struct) is a power of two.*/ } REL_t; typedef struct RELCACHE_t { REL_t *chk; /* last checkpoint */ REL_t *base; /* first rel found */ REL_t *last; /* last rel found so far */ REL_t *end; /* target for last relation. base <= last <= end */ size_t len; /* number of rels pre-allocated in base */ long relsup; /* how many linearly dependent relations we allow */ GEN basis; /* mod p basis (generating family actually) */ ulong missing; /* missing vectors in generating family above */ } RELCACHE_t; typedef struct FP_t { double **q; GEN x; double *y; double *z; double *v; } FP_t; typedef struct RNDREL_t { GEN Nideal; long jid; GEN ex; GEN m1; } RNDREL_t; static void wr_rel(GEN col) { long i, l = lg(col); err_printf("\nrel = "); for (i=1; i 1) { err_printf("\n++++ cglob = %ld", cache->last - cache->base); wr_rel(cache->last->R); } else err_printf("%ld ", cache->last - cache->base); } static void dbg_cancelrel(long jid, long jdir, GEN col) { err_printf("relation cancelled: "); if (DEBUGLEVEL>3) err_printf("(jid=%ld,jdir=%ld)",jid,jdir); wr_rel(col); err_flush(); } static void delete_cache(RELCACHE_t *M) { REL_t *rel; for (rel = M->base+1; rel <= M->last; rel++) { gunclone(rel->R); if (!rel->m) continue; gunclone(rel->m); } pari_free((void*)M->base); M->base = NULL; } static void unclone_subFB(FB_t *F) { subFB_t *sub, *subold; GEN id2 = F->id2; long i; for (sub = F->allsubFB; sub; sub = subold) { GEN subFB = sub->subFB; for (i = 1; i < lg(subFB); i++) { long id = subFB[i]; if (gel(id2, id) == gen_0) continue; gunclone(gel(id2, id)); gel(id2, id) = gen_0; } subold = sub->old; pari_free(sub); } } static void delete_FB(FB_t *F) { unclone_subFB(F); gunclone(F->minidx); gunclone(F->idealperm); } static void reallocate(RELCACHE_t *M, long len) { REL_t *old = M->base; M->len = len; M->base = (REL_t*)pari_realloc((void*)old, (len+1) * sizeof(REL_t)); if (old) { size_t last = M->last - old, chk = M->chk - old, end = M->end - old; M->last = M->base + last; M->chk = M->base + chk; M->end = M->base + end; } } #define pr_get_smallp(pr) gel(pr,1)[2] /* don't take P|p all other Q|p are already there */ static int bad_subFB(FB_t *F, long t) { GEN LP, P = gel(F->LP,t); long p = pr_get_smallp(P); LP = F->LV[p]; return (isclone(LP) && t == F->iLP[p] + lg(LP)-1); } static void assign_subFB(FB_t *F, GEN yes, long iyes) { subFB_t *sub; long i, lv; /* single malloc for struct + GEN */ lv = sizeof(subFB_t) + iyes*sizeof(long); sub = (subFB_t *)pari_malloc(lv); sub->subFB = (GEN)&sub[1]; sub->old = F->allsubFB; F->allsubFB = sub; for (i = 0; i < iyes; i++) sub->subFB[i] = yes[i]; F->subFB = sub->subFB; F->newpow = 1; } /* * Determine the permutation of the ideals made by each field automorphism. */ static void FB_aut_perm(FB_t *F, GEN auts, GEN cyclic) { pari_sp av0 = avma; long i, KC = F->KC, nauts = lg(auts); GEN minidx = zero_Flv(KC), perm = zero_Flm_copy(KC, nauts-1); if (nauts == 1) { for (i = 1; i <= KC; i++) minidx[i] = i; } else { long j, m; for (m = 1; m < lg(cyclic); m++) { GEN thiscyc = gel(cyclic, m); long k0 = thiscyc[1]; GEN aut = gel(auts, k0), permk0 = gel(perm, k0), ppermk; i = 1; while (i <= KC) { pari_sp av2 = avma; GEN seen = zero_Flv(KC), P = gel(F->LP, i); long imin = i, p, f, l; p = pr_get_p(P)[2]; f = pr_get_f(P); do { if (++i > KC) break; P = gel(F->LP, i); } while (p == pr_get_p(P)[2] && f == pr_get_f(P)); for (j = imin; j < i; j++) { GEN img = ZM_ZC_mul(aut, pr_get_gen(gel(F->LP, j))); for (l = imin; l < i; l++) if (!seen[l] && ZC_prdvd(img, gel(F->LP, l))) { seen[l] = 1; permk0[j] = l; break; } } avma = av2; } for (ppermk = permk0, i = 2; i < lg(thiscyc); i++) { GEN permk = gel(perm, thiscyc[i]); for (j = 1; j <= KC; j++) permk[j] = permk0[ppermk[j]]; ppermk = permk; } } for (j = 1; j <= KC; j++) { if (minidx[j]) continue; minidx[j] = j; for (i = 1; i < nauts; i++) minidx[coeff(perm, j, i)] = j; } } F->minidx = gclone(minidx); F->idealperm = gclone(perm); avma = av0; } /* set subFB. * Fill F->perm (if != NULL): primes ideals sorted by increasing norm (except * the ones in subFB come first [dense rows for hnfspec]) */ static int subFBgen(FB_t *F, GEN auts, GEN cyclic, double PROD, long minsFB) { GEN y, perm, yes, no; long i, j, k, iyes, ino, lv = F->KC + 1; double prod; pari_sp av; F->LP = cgetg(lv, t_VEC); F->L_jid = F->perm = cgetg(lv, t_VECSMALL); av = avma; y = cgetg(lv,t_COL); /* Norm P */ for (k=0, i=1; i <= F->KCZ; i++) { GEN LP = F->LV[F->FB[i]]; long l = lg(LP); for (j = 1; j < l; j++) { GEN P = gel(LP,j); k++; gel(y,k) = pr_norm(P); gel(F->LP,k) = P; } } /* perm sorts LP by increasing norm */ perm = indexsort(y); no = cgetg(lv, t_VECSMALL); ino = 1; yes = cgetg(lv, t_VECSMALL); iyes = 1; prod = 1.0; for (i = 1; i < lv; i++) { long t = perm[i]; if (bad_subFB(F, t)) { no[ino++] = t; continue; } yes[iyes++] = t; prod *= (double)itos(gel(y,t)); if (iyes > minsFB && prod > PROD) break; } setlg(yes, iyes); for (j=1; jperm[j] = yes[j]; for (i=1; iperm[j] = no[i]; for ( ; jperm[j] = perm[j]; F->allsubFB = NULL; FB_aut_perm(F, auts, cyclic); if (iyes) assign_subFB(F, yes, iyes); avma = av; return 1; } static int subFB_change(FB_t *F) { long i, iyes, minsFB, lv = F->KC + 1, l = lg(F->subFB)-1; pari_sp av = avma; GEN yes, L_jid = F->L_jid, present = zero_zv(lv-1); switch (F->sfb_chg) { case sfb_INCREASE: minsFB = l + 1; break; default: minsFB = l; break; } yes = cgetg(minsFB+1, t_VECSMALL); iyes = 1; if (L_jid) { for (i = 1; i < lg(L_jid); i++) { long l = L_jid[i]; yes[iyes++] = l; present[l] = 1; if (iyes > minsFB) break; } } else i = 1; if (iyes <= minsFB) { for ( ; i < lv; i++) { long l = F->perm[i]; if (present[l]) continue; yes[iyes++] = l; if (iyes > minsFB) break; } if (i == lv) return 0; } if (zv_equal(F->subFB, yes)) { if (DEBUGLEVEL) err_printf("\n*** NOT Changing sub factor base\n"); } else { if (DEBUGLEVEL) err_printf("\n*** Changing sub factor base\n"); assign_subFB(F, yes, iyes); } F->sfb_chg = 0; avma = av; return 1; } static GEN init_famat(GEN x) { return mkvec2(x, trivial_fact()); } static GEN red(GEN nf, GEN I, GEN G0, GEN *pm) { GEN y = idealred0(nf, init_famat(I), G0), J = gel(y,1); if (is_pm1(gcoeff(J,1,1)) || cmpii(ZM_det_triangular(I), ZM_det_triangular(J)) < 0) { *pm = gen_1; J = I; } else { GEN m = gel(y,2); *pm = lgcols(m)==1? gen_1: Q_primpart(gmael(m,1,1)); } return J; } /* make sure enough room to store n more relations */ static void pre_allocate(RELCACHE_t *cache, size_t n) { size_t len = (cache->last - cache->base) + n; if (len >= cache->len) reallocate(cache, len << 1); } void init_GRHcheck(GRHcheck_t *S, long N, long R1, double LOGD) { const double c1 = M_PI*M_PI/2; const double c2 = 3.663862376709; const double c3 = 3.801387092431; /* Euler + log(8*Pi)*/ S->clone = 0; S->cN = R1*c2 + N*c1; S->cD = LOGD - N*c3 - R1*M_PI/2; S->maxprimes = 16000; /* sufficient for LIMC=176081*/ S->primes = (GRHprime_t*)pari_malloc(S->maxprimes*sizeof(*S->primes)); S->nprimes = 0; S->limp = 0; u_forprime_init(&S->P, 2, ULONG_MAX); } void free_GRHcheck(GRHcheck_t *S) { if (S->clone) { long i = S->nprimes; GRHprime_t *pr; for (pr = S->primes, i = S->nprimes; i > 0; pr++, i--) gunclone(pr->dec); } pari_free(S->primes); } int GRHok(GRHcheck_t *S, double L, double SA, double SB) { return (S->cD + (S->cN + 2*SB) / L - 2*SA < -1e-8); } /* Return factorization pattern of p: [f,n], where n[i] primes of * residue degree f[i] */ static GEN get_fs(GEN nf, GEN P, GEN index, ulong p) { long j, k, f, n, l; GEN fs, ns; if (umodiu(index, p)) { /* easy case: p does not divide index */ GEN F = Flx_degfact(ZX_to_Flx(P,p), p); fs = gel(F,1); l = lg(fs); } else { GEN F = idealprimedec(nf, utoipos(p)); l = lg(F); fs = cgetg(l, t_VECSMALL); for (j = 1; j < l; j++) fs[j] = pr_get_f(gel(F,j)); } ns = cgetg(l, t_VECSMALL); f = fs[1]; n = 1; for (j = 2, k = 1; j < l; j++) if (fs[j] == f) n++; else { ns[k] = n; fs[k] = f; k++; f = fs[j]; n = 1; } ns[k] = n; fs[k] = f; k++; setlg(fs, k); setlg(ns, k); return mkvec2(fs,ns); } /* cache data for all rational primes up to the LIM */ static void cache_prime_dec(GRHcheck_t *S, ulong LIM, GEN nf) { pari_sp av = avma; GRHprime_t *pr; GEN index, P; double nb; if (S->limp >= LIM) return; S->clone = 1; nb = primepi_upper_bound((double)LIM); /* #{p <= LIM} <= nb */ GRH_ensure(S, nb+1); /* room for one extra prime */ P = nf_get_pol(nf); index = nf_get_index(nf); for (pr = S->primes + S->nprimes;;) { ulong p = u_forprime_next(&(S->P)); pr->p = p; pr->logp = log((double)p); pr->dec = gclone(get_fs(nf, P, index, p)); S->nprimes++; pr++; avma = av; /* store up to nextprime(LIM) included */ if (p >= LIM) { S->limp = p; break; } } } static double tailresback(long R1, long R2, double rK, long C, double C2, double C3, double r1K, double r2K, double logC, double logC2, double logC3) { const double rQ = 1.83787706641; const double r1Q = 1.98505372441; const double r2Q = 1.07991541347; return fabs((R1+R2-1)*(12*logC3+4*logC2-9*logC-6)/(2*C*logC3) + (rK-rQ)*(6*logC2 + 5*logC + 2)/(C*logC3) - R2*(6*logC2+11*logC+6)/(C2*logC2) - 2*(r1K-r1Q)*(3*logC2 + 4*logC + 2)/(C2*logC3) + (R1+R2-1)*(12*logC3+40*logC2+45*logC+18)/(6*C3*logC3) + (r2K-r2Q)*(2*logC2 + 3*logC + 2)/(C3*logC3)); } static double tailres(long R1, long R2, double al2K, double rKm, double rKM, double r1Km, double r1KM, double r2Km, double r2KM, double C, long i) { /* C >= 3*2^i, lower bound for eint1(log(C)/2) */ /* for(i=0,30,print(eint1(log(3*2^i)/2))) */ static double tab[] = { 0.50409264803, 0.26205336997, 0.14815491171, 0.08770540561, 0.05347651832, 0.03328934284, 0.02104510690, 0.01346475900, 0.00869778586, 0.00566279855, 0.00371111950, 0.00244567837, 0.00161948049, 0.00107686891, 0.00071868750, 0.00048119961, 0.00032312188, 0.00021753772, 0.00014679818, 9.9272855581E-5, 6.7263969995E-5, 4.5656812967E-5, 3.1041124593E-5, 2.1136011590E-5, 1.4411645381E-5, 9.8393304088E-6, 6.7257395409E-6, 4.6025878272E-6, 3.1529719271E-6, 2.1620490021E-6, 1.4839266071E-6 }; const double logC = log(C), logC2 = logC*logC, logC3 = logC*logC2; const double C2 = C*C, C3 = C*C2; double E1 = i >30? 0: tab[i]; return al2K*((33*logC2+22*logC+8)/(8*logC3*sqrt(C))+15*E1/16) + maxdd(tailresback(rKm,r1KM,r2Km, C,C2,C3,R1,R2,logC,logC2,logC3), tailresback(rKM,r1Km,r2KM, C,C2,C3,R1,R2,logC,logC2,logC3))/2 + ((R1+R2-1)*4*C+R2)*(C2+6*logC)/(4*C2*C2*logC2); } static long primeneeded(long N, long R1, long R2, double LOGD) { const double lim = 0.25; /* should be log(2)/2 == 0.34657... */ const double al2K = 0.3526*LOGD - 0.8212*N + 4.5007; const double rKm = -1.0155*LOGD + 2.1042*N - 8.3419; const double rKM = -0.5 *LOGD + 1.2076*N + 1; const double r1Km = - LOGD + 1.4150*N; const double r1KM = - LOGD + 1.9851*N; const double r2Km = - LOGD + 0.9151*N; const double r2KM = - LOGD + 1.0800*N; long Cmin = 3, Cmax = 3, i = 0; while (tailres(R1, R2, al2K, rKm, rKM, r1Km, r1KM, r2Km, r2KM, Cmax, i) > lim) { Cmin = Cmax; Cmax *= 2; i++; } i--; while (Cmax - Cmin > 1) { long t = (Cmin + Cmax)/2; if (tailres(R1, R2, al2K, rKm, rKM, r1Km, r1KM, r2Km, r2KM, t, i) > lim) Cmin = t; else Cmax = t; } return Cmax; } /* for (; i > 0; pr++, i--) { GEN dec, a = NULL, b = NULL, fs, ns; long j, k, limp = (long)(llimc/pr->logp); ulong p = pr->p; dec = pr->dec; fs = gel(dec, 1); ns = gel(dec, 2); k = lg(fs); for (j = 1; j < k; j++) { long f, nb; GEN nor; f = fs[j]; if (f > limp) continue; nb = ns[j]; nor = powuu(p, f); if (a) { a = mulii(a, powiu(nor, nb)); b = mulii(b, powiu(subii(nor, gen_1), nb)); } else { a = powuu(p, f*nb-1); b = diviuexact(powiu(subii(nor, gen_1), nb), p-1); } } if (a) invres = divri(mulir(b, invres), a); else invres = divru(mulur(p, invres), p-1); } */ static GEN compute_invres(GRHcheck_t *S, long LIMC) { pari_sp av = avma; double loginvres = 0.; GRHprime_t *pr; long i; double logLIMC = log((double)LIMC); double logLIMC2 = logLIMC*logLIMC, denc; double c0, c1, c2; denc = 1/(pow((double)LIMC, 3.) * logLIMC * logLIMC2); c2 = ( logLIMC2 + 3 * logLIMC / 2 + 1) * denc; denc *= LIMC; c1 = (3 * logLIMC2 + 4 * logLIMC + 2) * denc; denc *= LIMC; c0 = (3 * logLIMC2 + 5 * logLIMC / 2 + 1) * denc; for (pr = S->primes, i = S->nprimes; i > 0; pr++, i--) { GEN dec, fs, ns; long addpsi; double addpsi1, addpsi2; double logp = pr->logp, NPk; long j, k, limp = logLIMC/logp; ulong p = pr->p, p2 = p*p; if (limp < 1) break; dec = pr->dec; fs = gel(dec, 1); ns = gel(dec, 2); loginvres += 1./p; /* * note for optimization: limp == 1 nearly always and limp >= 3 for * only very few primes. */ for (k = 2, NPk = p; k <= limp; k++) { NPk *= p; loginvres += 1/(k * NPk); } addpsi = limp; addpsi1 = p *(pow((double)p , (double)limp)-1)/(p -1); addpsi2 = p2*(pow((double)p2, (double)limp)-1)/(p2-1); j = lg(fs); while (--j > 0) { long f, nb, kmax; double NP, NP2, addinvres; f = fs[j]; if (f > limp) continue; nb = ns[j]; NP = pow((double)p, (double)f); addinvres = 1/NP; kmax = limp / f; for (k = 2, NPk = NP; k <= kmax; k++) { NPk *= NP; addinvres += 1/(k*NPk); } NP2 = NP*NP; loginvres -= nb * addinvres; addpsi -= nb * f * kmax; addpsi1 -= nb*(f*NP *(pow(NP ,(double)kmax)-1)/(NP -1)); addpsi2 -= nb*(f*NP2*(pow(NP2,(double)kmax)-1)/(NP2-1)); } loginvres -= (addpsi*c0 - addpsi1*c1 + addpsi2*c2)*logp; } return gerepileuptoleaf(av, mpexp(dbltor(loginvres))); } static long nthideal(GRHcheck_t *S, GEN nf, long n) { pari_sp av = avma; GEN P = nf_get_pol(nf); ulong p = 0, *vecN = (ulong*)const_vecsmall(n, LONG_MAX); long i, res, N = poldegree(P, -1); for (i = 0; ; i++) { GRHprime_t *pr; GEN fs; cache_prime_dec(S, p+1, nf); pr = S->primes + i; fs = gel(pr->dec, 1); p = pr->p; if (fs[1] != N) { GEN ns = gel(pr->dec, 2); long k, l, j = lg(fs); while (--j > 0) { ulong NP = upowuu(p, fs[j]); long nf; if (!NP) continue; for (k = 1; k <= n; k++) if (vecN[k] > NP) break; if (k > n) continue; /* vecN[k] <= NP */ nf = ns[j]; /*#{primes of norme NP} = nf, insert them here*/ for (l = k+nf; l <= n; l++) vecN[l] = vecN[l-nf]; for (l = 0; l < nf && k+l <= n; l++) vecN[k+l] = NP; while (l <= k) vecN[l++] = NP; } } if (p > vecN[n]) break; } res = vecN[n]; avma = av; return res; } /* Compute FB, LV, iLP + KC*. Reset perm * C2: bound for norm of tested prime ideals (includes be_honest()) * C1: bound for p, such that P|p (NP <= C2) used to build relations */ static void FBgen(FB_t *F, GEN nf, long N, ulong C1, ulong C2, GRHcheck_t *S) { GRHprime_t *pr; long i, ip; GEN prim; const double L = log((double)C2 + 0.5); cache_prime_dec(S, C2, nf); pr = S->primes; F->sfb_chg = 0; F->FB = cgetg(C2+1, t_VECSMALL); F->iLP = cgetg(C2+1, t_VECSMALL); F->LV = (GEN*)const_vec(C2, NULL); prim = icopy(gen_1); i = ip = 0; F->KC = F->KCZ = 0; for (;; pr++) /* p <= C2 */ { ulong p = pr->p; long k, l, m; GEN LP, nb, f; if (!F->KC && p > C1) { F->KCZ = i; F->KC = ip; } if (p > C2) break; if (DEBUGLEVEL>1) { err_printf(" %ld",p); err_flush(); } f = gel(pr->dec, 1); nb = gel(pr->dec, 2); if (f[1] == N) { if (p == C2) break; continue; /* p inert */ }/* compute l such that p^f <= C2 <=> f <= l */ l = (long)(L/pr->logp); for (k=0, m=1; m < lg(f) && f[m]<=l; m++) k += nb[m]; if (!k) /* p too inert to appear in FB */ { if (p == C2) break; continue; } prim[2] = p; LP = idealprimedec_limit_f(nf,prim, l); /* keep non-inert ideals with Norm <= C2 */ if (m == lg(f)) setisclone(LP); /* flag it: all prime divisors in FB */ F->FB[++i]= p; F->LV[p] = LP; F->iLP[p] = ip; ip += k; if (p == C2) break; } if (!F->KC) { F->KCZ = i; F->KC = ip; } /* Note F->KC > 0 otherwise GRHchk is false */ setlg(F->FB, F->KCZ+1); F->KCZ2 = i; if (DEBUGLEVEL>1) { err_printf("\n"); if (DEBUGLEVEL>6) { err_printf("########## FACTORBASE ##########\n\n"); err_printf("KC2=%ld, KC=%ld, KCZ=%ld, KCZ2=%ld\n", ip, F->KC, F->KCZ, F->KCZ2); for (i=1; i<=F->KCZ; i++) err_printf("++ LV[%ld] = %Ps",i,F->LV[F->FB[i]]); } } F->perm = NULL; F->L_jid = NULL; } static int GRHchk(GEN nf, GRHcheck_t *S, ulong LIMC) { double logC = log((double)LIMC), SA = 0, SB = 0; GRHprime_t *pr = S->primes; cache_prime_dec(S, LIMC, nf); for (pr = S->primes;; pr++) { ulong p = pr->p; GEN dec, fs, ns; double logCslogp; long j; if (p > LIMC) break; dec = pr->dec; fs = gel(dec, 1); ns = gel(dec,2); logCslogp = logC/pr->logp; for (j = 1; j < lg(fs); j++) { long f = fs[j], M, nb; double logNP, q, A, B; if (f > logCslogp) break; logNP = f * pr->logp; q = 1/sqrt((double)upowuu(p, f)); A = logNP * q; B = logNP * A; M = (long)(logCslogp/f); if (M > 1) { double inv1_q = 1 / (1-q); A *= (1 - pow(q, (double)M)) * inv1_q; B *= (1 - pow(q, (double)M)*(M+1 - M*q)) * inv1_q * inv1_q; } nb = ns[j]; SA += nb * A; SB += nb * B; } if (p == LIMC) break; } return GRHok(S, logC, SA, SB); } /* SMOOTH IDEALS */ static void store(long i, long e, FACT *fact) { ++fact[0].pr; fact[fact[0].pr].pr = i; /* index */ fact[fact[0].pr].ex = e; /* exponent */ } /* divide out x by all P|p, where x as in can_factor(). k = v_p(Nx) */ static int divide_p_elt(GEN LP, long ip, long k, GEN m, FACT *fact) { long j, l = lg(LP); for (j=1; j 0 */ k -= v * pr_get_f(P); if (!k) return 1; } return 0; } static int divide_p_id(GEN LP, long ip, long k, GEN nf, GEN I, FACT *fact) { long j, l = lg(LP); for (j=1; j 0 */ k -= v * pr_get_f(P); if (!k) return 1; } return 0; } static int divide_p_quo(GEN LP, long ip, long k, GEN nf, GEN I, GEN m, FACT *fact) { long j, l = lg(LP); for (j=1; j 0 */ k -= v * pr_get_f(P); if (!k) return 1; } return 0; } /* |*N| != 0 is the norm of a primitive ideal, in particular not divisible by * any inert prime. Is |*N| a smooth rational integer wrt F ? (put the * exponents in *ex) */ static int smooth_norm(FB_t *F, GEN *N, GEN *ex) { GEN FB = F->FB; const long KCZ = F->KCZ; const ulong limp = uel(FB,KCZ); /* last p in FB */ long i; *ex = new_chunk(KCZ+1); for (i=1; ; i++) { int stop; ulong p = uel(FB,i); long v = Z_lvalrem_stop(N, p, &stop); (*ex)[i] = v; if (v) { GEN LP = F->LV[p]; if(!LP) pari_err_BUG("can_factor"); if (lg(LP) == 1) return 0; if (stop) break; } if (i == KCZ) return 0; } (*ex)[0] = i; return (abscmpiu(*N,limp) <= 0); } static int divide_p(FB_t *F, long p, long k, GEN nf, GEN I, GEN m, FACT *fact) { GEN LP = F->LV[p]; long ip = F->iLP[p]; if (!m) return divide_p_id (LP,ip,k,nf,I,fact); if (!I) return divide_p_elt(LP,ip,k,m,fact); return divide_p_quo(LP,ip,k,nf,I,m,fact); } /* Let x = m if I == NULL, * I if m == NULL, * m/I otherwise. * Can we factor the integral primitive ideal x ? |N| = Norm x > 0 */ static long can_factor(FB_t *F, GEN nf, GEN I, GEN m, GEN N, FACT *fact) { GEN ex; long i, res = 0; fact[0].pr = 0; if (is_pm1(N)) return 1; if (!smooth_norm(F, &N, &ex)) goto END; for (i=1; i<=ex[0]; i++) if (ex[i] && !divide_p(F, F->FB[i], ex[i], nf, I, m, fact)) goto END; res = is_pm1(N) || divide_p(F, itou(N), 1, nf, I, m, fact); END: if (!res && DEBUGLEVEL > 1) { err_printf("."); err_flush(); } return res; } /* can we factor m/I ? [m in I from idealpseudomin_nonscalar], NI = norm I */ static long factorgen(FB_t *F, GEN nf, GEN I, GEN NI, GEN m, FACT *fact) { long e, r1 = nf_get_r1(nf); GEN M = nf_get_M(nf); GEN N = divri(embed_norm(RgM_RgC_mul(M,m), r1), NI); /* ~ N(m/I) */ N = grndtoi(N, &e); if (e > -1) { if (DEBUGLEVEL > 1) { err_printf("+"); err_flush(); } return 0; } return can_factor(F, nf, I, m, N, fact); } /* FUNDAMENTAL UNITS */ /* a, m real. Return (Re(x) + a) + I * (Im(x) % m) */ static GEN addRe_modIm(GEN x, GEN a, GEN m) { GEN re, im, z; if (typ(x) == t_COMPLEX) { im = modRr_safe(gel(x,2), m); if (!im) return NULL; re = gadd(gel(x,1), a); z = gequal0(im)? re: mkcomplex(re, im); } else z = gadd(x, a); return z; } /* clean archimedean components */ static GEN cleanarch(GEN x, long N, long prec) { long i, R1, RU, tx = typ(x); GEN s, y, pi2; if (tx == t_MAT) { y = cgetg(lg(x), tx); for (i=1; i < lg(x); i++) { gel(y,i) = cleanarch(gel(x,i), N, prec); if (!gel(y,i)) return NULL; } return y; } if (!is_vec_t(tx)) pari_err_TYPE("cleanarch",x); RU = lg(x)-1; R1 = (RU<<1)-N; s = gdivgs(RgV_sum(real_i(x)), -N); /* -log |norm(x)| / N */ y = cgetg(RU+1,tx); pi2 = Pi2n(1, prec); for (i=1; i<=R1; i++) { gel(y,i) = addRe_modIm(gel(x,i), s, pi2); if (!gel(y,i)) return NULL; } if (i <= RU) { GEN pi4 = Pi2n(2, prec), s2 = gmul2n(s, 1); for ( ; i<=RU; i++) { gel(y,i) = addRe_modIm(gel(x,i), s2, pi4); if (!gel(y,i)) return NULL; } } return y; } static GEN not_given(long reason) { if (DEBUGLEVEL) switch(reason) { case fupb_LARGE: pari_warn(warner,"fundamental units too large, not given"); break; case fupb_PRECI: pari_warn(warner,"insufficient precision for fundamental units, not given"); break; } return NULL; } /* check whether exp(x) will 1) get too big (real(x) large), 2) require * large accuracy for argument reduction (imag(x) large) */ static int exp_OK(GEN x, long *pte) { long i,I,j,J, e = - (long)HIGHEXPOBIT; RgM_dimensions(x, &I,&J); for (j=1; j<=J; j++) for (i=1; i<=I; i++) { GEN c = gcoeff(x,i,j), re; if (typ(c)!=t_COMPLEX) re = c; else { GEN im = gel(c,2); e = maxss(e, expo(im) + 5 - bit_prec(im)); re = gel(c,1); } if (expo(re) > 20) { *pte = LONG_MAX; return 0; } } *pte = -e; return (e < 0); } static GEN log_m1(long r1, long ru, long prec) { GEN v = cgetg(ru+1,t_COL); GEN a = r1? PiI2n(0,prec): NULL; GEN a2 = (r1 != ru)? PiI2n(1,prec): NULL; long i; for (i=1; i<=r1; i++) gel(v,i) = a; for ( ; i<=ru; i++) gel(v,i) = a2; return v; } static GEN getfu(GEN nf, GEN *ptA, long *pte, long prec) { GEN u, y, matep, A, vec, T = nf_get_pol(nf), M = nf_get_M(nf); long e, i, j, R1, RU, N = degpol(T); if (DEBUGLEVEL) err_printf("\n#### Computing fundamental units\n"); R1 = nf_get_r1(nf); RU = (N+R1)>>1; if (RU==1) { *pte=LONG_MAX; return cgetg(1,t_VEC); } *pte = 0; A = *ptA; if (lg(A) < RU) return not_given(fupb_PRECI); matep = cgetg(RU,t_MAT); for (j=1; j= 0) return not_given(fupb_PRECI); for (j=1; j 0 */ vec = log_m1(R1,RU,prec); for (j=1; j pmax) pmax = p; } L = const_vec(pmax, NULL); if (list_pr) { for (i=1; iKCZ = i; F->KC = ip; F->FB = FB; setlg(FB, i+1); F->LV = (GEN*)LV; F->iLP= iLP; return L; } /* add v^e to factorization */ static void add_to_fact(long v, long e, FACT *fact) { long i, l = fact[0].pr; for (i=1; i<=l && fact[i].pr < v; i++)/*empty*/; if (i <= l && fact[i].pr == v) fact[i].ex += e; else store(v, e, fact); } static void inv_fact(FACT *fact) { long i, l = fact[0].pr; for (i=1; i<=l; i++) fact[i].ex = -fact[i].ex; } /* L (small) list of primes above the same p including pr. Return pr index */ static int pr_index(GEN L, GEN pr) { long j, l = lg(L); GEN al = pr_get_gen(pr); for (j=1; jiLP[p] + pr_index(F->LV[p], pr); } /* x, y 2 extended ideals whose first component is an integral HNF and second * a famat */ static GEN idealHNF_mulred(GEN nf, GEN x, GEN y) { GEN A = idealHNF_mul(nf, gel(x,1), gel(y,1)); GEN F = famat_mul_shallow(gel(x,2), gel(y,2)); return idealred(nf, mkvec2(A, F)); } /* red(x * pr^n), n > 0 is small, x extended ideal. Reduction in order to * avoid prec pb: don't let id become too large as lgsub increases */ static GEN idealmulpowprimered(GEN nf, GEN x, GEN pr, ulong n) { GEN A = idealmulpowprime(nf, gel(x,1), pr, utoipos(n)); return idealred(nf, mkvec2(A, gel(x,2))); } /* return famat y (principal ideal) such that y / x is smooth [wrt Vbase] */ static GEN SPLIT(FB_t *F, GEN nf, GEN x, GEN Vbase, FACT *fact) { GEN vecG, ex, y, x0, Nx = ZM_det_triangular(x); long nbtest_lim, nbtest, i, j, ru, lgsub; pari_sp av; /* try without reduction if x is small */ if (gexpo(gcoeff(x,1,1)) < 100 && can_factor(F, nf, x, NULL, Nx, fact)) return NULL; av = avma; y = idealpseudomin_nonscalar(x, nf_get_roundG(nf)); if (factorgen(F, nf, x, Nx, y, fact)) return y; avma = av; /* reduce in various directions */ ru = lg(nf_get_roots(nf)); vecG = cgetg(ru, t_VEC); for (j=1; j2) err_printf("# ideals tried = %ld\n",nbtest); for (i=1; i nbtest_lim) { nbtest = 0; if (++lgsub < minss(7, lg(Vbase)-1)) { nbtest_lim <<= 1; ex = cgetg(lgsub, t_VECSMALL); } else nbtest_lim = LONG_MAX; /* don't increase further */ if (DEBUGLEVEL>2) err_printf("SPLIT: increasing factor base [%ld]\n",lgsub); } } } INLINE GEN bnf_get_W(GEN bnf) { return gel(bnf,1); } INLINE GEN bnf_get_B(GEN bnf) { return gel(bnf,2); } INLINE GEN bnf_get_C(GEN bnf) { return gel(bnf,4); } INLINE GEN bnf_get_vbase(GEN bnf) { return gel(bnf,5); } /* Return y (as an elt of K or a t_MAT representing an elt in Z[K]) * such that x / (y) is smooth and store the exponents of its factorization * on g_W and g_B in Wex / Bex; return NULL for y = 1 */ static GEN split_ideal(GEN bnf, GEN x, GEN *pWex, GEN *pBex) { GEN L, y, Vbase = bnf_get_vbase(bnf); GEN Wex, W = bnf_get_W(bnf); GEN Bex, B = bnf_get_B(bnf); long p, j, i, l, nW, nB; FACT *fact; FB_t F; L = recover_partFB(&F, Vbase, lg(x)-1); fact = (FACT*)stack_malloc((F.KC+1)*sizeof(FACT)); y = SPLIT(&F, bnf_get_nf(bnf), x, Vbase, fact); nW = lg(W)-1; *pWex = Wex = zero_zv(nW); nB = lg(B)-1; *pBex = Bex = zero_zv(nB); l = lg(F.FB); p = j = 0; /* -Wall */ for (i = 1; i <= fact[0].pr; i++) { /* decode index C = ip+j --> (p,j) */ long a, b, t, C = fact[i].pr; for (t = 1; t < l; t++) { long q = F.FB[t], k = C - F.iLP[q]; if (k <= 0) break; p = q; j = k; } a = gel(L, p)[j]; b = a - nW; if (b <= 0) Wex[a] = y? -fact[i].ex: fact[i].ex; else Bex[b] = y? -fact[i].ex: fact[i].ex; } return y; } /**** logarithmic embeddings ****/ static GEN famat_to_arch(GEN nf, GEN fa, long prec); static GEN triv_arch(GEN nf) { return zerovec(lg(nf_get_roots(nf))-1); } /* Get archimedean components: [e_i Log( sigma_i(X) )], where X = primpart(x), * and e_i = 1 (resp 2.) for i <= R1 (resp. > R1) */ static GEN get_arch(GEN nf, GEN x, long prec) { long i, l, R1; GEN v; if (typ(x) == t_MAT) return famat_to_arch(nf,x,prec); x = nf_to_scalar_or_basis(nf,x); if (typ(x) != t_COL) return triv_arch(nf); x = RgM_RgC_mul(nf_get_M(nf), Q_primpart(x)); l = lg(x); for (i=1; i < l; i++) if (gequal0(gabs(gel(x,i),prec))) return NULL; v = cgetg(l,t_VEC); R1 = nf_get_r1(nf); for (i=1; i<=R1; i++) gel(v,i) = glog(gel(x,i),prec); for ( ; i < l; i++) gel(v,i) = gmul2n(glog(gel(x,i),prec),1); return v; } static GEN famat_to_arch(GEN nf, GEN fa, long prec) { GEN g,e, y = NULL; long i,l; if (typ(fa) != t_MAT) pari_err_TYPE("famat_to_arch",fa); if (lg(fa) == 1) return triv_arch(nf); g = gel(fa,1); e = gel(fa,2); l = lg(e); for (i=1; i= l */ a = cgetg(l, t_VEC); for (i=1; i e) e = f; } return e; } /* col = archimedian components of x, Nx = kNx^e its norm (e > 0, usually = 1), * dx a bound for its denominator. Return x or NULL (fail) */ GEN isprincipalarch(GEN bnf, GEN col, GEN kNx, GEN e, GEN dx, long *pe) { GEN nf, x, y, logfu, s, M; long N, R1, RU, i, prec = gprecision(col); bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); M = nf_get_M(nf); if (!prec) prec = prec_arch(bnf); *pe = 128; logfu = bnf_get_logfu(bnf); N = nf_get_degree(nf); R1 = nf_get_r1(nf); RU = (N + R1)>>1; if (!(col = cleanarch(col,N,prec))) return NULL; settyp(col, t_COL); if (RU > 1) { /* reduce mod units */ GEN u, z = init_red_mod_units(bnf,prec); u = red_mod_units(col,z); if (!u && z) return NULL; if (u) { col = RgC_add(col, RgM_RgC_mul(logfu, u)); if (!(col = cleanarch(col,N,prec))) return NULL; } } s = divru(mulir(e, glog(kNx,prec)), N); for (i=1; i<=R1; i++) gel(col,i) = gexp(gadd(s, gel(col,i)),prec); for ( ; i<=RU; i++) gel(col,i) = gexp(gadd(s, gmul2n(gel(col,i),-1)),prec); /* d.alpha such that x = alpha \prod gj^ej */ x = RgM_solve_realimag(M,col); if (!x) return NULL; x = RgC_Rg_mul(x, dx); y = grndtoi(x, pe); if (*pe > -5) { *pe = needed_bitprec(x); return NULL; } return RgC_Rg_div(y, dx); } /* y = C \prod g[i]^e[i] ? */ static int fact_ok(GEN nf, GEN y, GEN C, GEN g, GEN e) { pari_sp av = avma; long i, c = lg(e); GEN z = C? C: gen_1; for (i=1; i 1 */ static int RgV_is1(GEN u) { return isint1(gel(u,1)) && RgV_isscalar(u); } static GEN add_principal_part(GEN nf, GEN u, GEN v, long flag) { if (flag & nf_GENMAT) return (typ(u) == t_COL && RgV_is1(u))? v: famat_mul_shallow(v,u); else return nfmul(nf, v, u); } #if 0 /* compute C prod P[i]^e[i], e[i] >=0 for all i. C may be NULL (omitted) * e destroyed ! */ static GEN expand(GEN nf, GEN C, GEN P, GEN e) { long i, l = lg(e), done = 1; GEN id = C; for (i=1; i 0)? 0: n>>1, n); return v; } if (!isint1(Q_denom(x))) { avma = av; return cgetg(1,t_COL); } } R1 = nf_get_r1(nf); v = cgetg(RU+1,t_COL); for (i=1; i<=R1; i++) gel(v,i) = gen_1; for ( ; i<=RU; i++) gel(v,i) = gen_2; logunit = shallowconcat(logunit, v); /* ex = fundamental units exponents */ rlog = real_i(logunit); prec = nf_get_prec(nf); for (i=1;; i++) { GEN rx = get_arch_real(nf,x,&emb, MEDDEFAULTPREC); if (rx) { GEN logN = RgV_sum(rx); /* log(Nx), should be ~ 0 */ if (gexpo(logN) > -20) { /* precision problem ? */ if (typ(logN) != t_REAL) { avma = av; return cgetg(1,t_COL); } /*no*/ if (i == 1) { GEN N = nfnorm(nf, x); if (!is_pm1(N)) { avma = av; return cgetg(1, t_COL); } } } else { ex = RgM_solve(rlog, rx); if (ex) { ex = grndtoi(ex, &e); if (!signe(gel(ex,RU)) && e < -4) break; } } } if (i == 1) prec = nbits2prec(gexpo(x) + 128); else { if (i > 4) pari_err_PREC("bnfisunit"); prec = precdbl(prec); } if (DEBUGLEVEL) pari_warn(warnprec,"bnfisunit",prec); nf = nfnewprec_shallow(nf, prec); } setlg(ex, RU); /* ZC */ p1 = imag_i( row_i(logunit,1, 1,RU-1) ); p1 = RgV_dotproduct(p1, ex); if (!R1) p1 = gmul2n(p1, -1); p1 = gsub(garg(gel(emb,1),prec), p1); /* p1 = arg(the missing root of 1) */ pi2_sur_w = divru(mppi(prec), n>>1); /* 2pi / n */ e = umodiu(roundr(divrr(p1, pi2_sur_w)), n); if (n > 2) { GEN z = algtobasis(nf, bnf_get_tuU(bnf)); /* primitive root of 1 */ GEN ro = RgV_dotproduct(row(nf_get_M(nf), 1), z); GEN p2 = roundr(divrr(garg(ro, prec), pi2_sur_w)); e *= Fl_inv(umodiu(p2,n), n); e %= n; } gel(ex,RU) = mkintmodu(e, n); setlg(ex, RU+1); return gerepilecopy(av, ex); } GEN nfsign_from_logarch(GEN LA, GEN invpi, GEN archp) { long l = lg(archp), i; GEN y = cgetg(l, t_VECSMALL); pari_sp av = avma; for (i=1; im; long i; if (!z) return zerocol(RU); arch = typ(z) == t_COL? RgM_RgC_mul(M, z): RgC_Rg_mul(gel(M,1), z); C = cgetg(RU+1, t_COL); arch = glog(arch, prec); for (i=1; i<=R1; i++) gel(C,i) = gel(arch,i); for ( ; i<=RU; i++) gel(C,i) = gmul2n(gel(arch,i), 1); return C; } static GEN perm_log_embed(GEN C, GEN perm) { long i, n; GEN Cnew = cgetg_copy(C, &n); for (i = 1; i < n; i++) { long v = perm[i]; if (v > 0) gel(Cnew, i) = gel(C, v); else gel(Cnew, i) = conj_i(gel(C, -v)); } return Cnew; } static GEN set_fact(FB_t *F, FACT *fact, GEN ex, long *pnz) { long i, n = fact[0].pr; long nz; GEN c = zero_Flv(F->KC); if (!n) /* trivial factorization */ *pnz = F->KC+1; else { nz = fact[1].pr; if (fact[n].pr < nz) /* Possible with jid in rnd_rel */ nz = fact[n].pr; for (i=1; i<=n; i++) c[fact[i].pr] = fact[i].ex; if (ex) { for (i=1; isubFB[i]; c[v] += ex[i]; if (v < nz) nz = v; } } *pnz = nz; } return c; } /* Is cols already in the cache ? bs = index of first non zero coeff in cols * General check for colinearity useless since exceedingly rare */ static int already_known(RELCACHE_t *cache, long bs, GEN cols) { REL_t *r; long l = lg(cols); for (r = cache->last; r > cache->base; r--) if (bs == r->nz) { GEN coll = r->R; long b = bs; while (b < l && cols[b] == coll[b]) b++; if (b == l) return 1; } return 0; } /* Add relation R to cache, nz = index of first non zero coeff in R. * If relation is a linear combination of the previous ones, return 0. * Otherwise, update basis and return > 0. Compute mod p (much faster) * so some kernel vector might not be genuine. */ static int add_rel_i(RELCACHE_t *cache, GEN R, long nz, GEN m, long orig, long aut, REL_t **relp, long in_rnd_rel) { long i, k, n = lg(R)-1; if (nz == n+1) { k = 0; goto ADD_REL; } if (already_known(cache, nz, R)) return -1; if (cache->last >= cache->base + cache->len) return 0; if (DEBUGLEVEL>6) { err_printf("adding vector = %Ps\n",R); err_printf("generators =\n%Ps\n", cache->basis); } if (cache->missing) { GEN a = leafcopy(R), basis = cache->basis; k = lg(a); do --k; while (!a[k]); while (k) { GEN c = gel(basis, k); if (c[k]) { long ak = a[k]; for (i=1; i < k; i++) if (c[i]) a[i] = (a[i] + ak*(mod_p-c[i])) % mod_p; a[k] = 0; do --k; while (!a[k]); /* k cannot go below 0: codeword is a sentinel */ } else { ulong invak = Fl_inv(uel(a,k), mod_p); /* Cleanup a */ for (i = k; i-- > 1; ) { long j, ai = a[i]; c = gel(basis, i); if (!ai || !c[i]) continue; ai = mod_p-ai; for (j = 1; j < i; j++) if (c[j]) a[j] = (a[j] + ai*c[j]) % mod_p; a[i] = 0; } /* Insert a/a[k] as k-th column */ c = gel(basis, k); for (i = 1; imissing--; break; } } } else k = (cache->last - cache->base) + 1; if (k || cache->relsup > 0 || (m && in_rnd_rel)) { REL_t *rel; ADD_REL: rel = ++cache->last; if (!k && cache->relsup && nz < n+1) { cache->relsup--; k = (rel - cache->base) + cache->missing; } rel->R = gclone(R); rel->m = m ? gclone(m) : NULL; rel->nz = nz; if (aut) { rel->relorig = (rel - cache->base) - orig; rel->relaut = aut; } else rel->relaut = 0; if (relp) *relp = rel; if (DEBUGLEVEL) dbg_newrel(cache); } return k; } static int add_rel(RELCACHE_t *cache, FB_t *F, GEN R, long nz, GEN m, long in_rnd_rel) { REL_t *rel; long k, l, reln; const long nauts = lg(F->idealperm), KC = F->KC; k = add_rel_i(cache, R, nz, m, 0, 0, &rel, in_rnd_rel); if (k > 0 && m) { GEN Rl = cgetg(KC+1, t_VECSMALL); reln = rel - cache->base; for (l = 1; l < nauts; l++) { GEN perml = gel(F->idealperm, l); long i, nzl = perml[nz]; for (i = 1; i <= KC; i++) Rl[i] = 0; for (i = nz; i <= KC; i++) if (R[i]) { long v = perml[i]; if (v < nzl) nzl = v; Rl[v] = R[i]; } (void)add_rel_i(cache, Rl, nzl, NULL, reln, l, NULL, in_rnd_rel); } } return k; } /* Compute powers of prime ideal (P^0,...,P^a) (a > 1) */ static void powPgen(GEN nf, GEN vp, GEN *ppowP, long a) { GEN id2, J; long j; id2 = cgetg(a+1,t_VEC); J = mkvec2(pr_get_p(vp), zk_scalar_or_multable(nf,pr_get_gen(vp))); gel(id2,1) = J; vp = pr_hnf(nf,vp); for (j=2; j<=a; j++) { if (DEBUGLEVEL>1) err_printf(" %ld", j); J = idealtwoelt(nf, idealHNF_mul(nf, vp, J)); gel(J, 2) = zk_scalar_or_multable(nf, gel(J,2)); gel(id2,j) = J; } setlg(id2, j); *ppowP = id2; if (DEBUGLEVEL>1) err_printf("\n"); } /* Compute powers of prime ideals (P^0,...,P^a) in subFB (a > 1) */ static void powFBgen(RELCACHE_t *cache, FB_t *F, GEN nf, GEN auts) { const long a = 1L<subFB, idealperm = F->idealperm; long i, k, l, id, n = lg(F->subFB), naut = lg(auts); if (DEBUGLEVEL) err_printf("Computing powers for subFB: %Ps\n",subFB); if (cache) pre_allocate(cache, n*naut); for (i=1; iid2, id) == gen_0) { GEN id2 = NULL; for (k = 1; k < naut; k++) { long sigmaid = coeff(idealperm, id, k); GEN sigmaid2 = gel(F->id2, sigmaid); if (sigmaid2 != gen_0) { GEN aut = gel(auts, k), invaut = gel(auts, F->invs[k]); long lid2; id2 = cgetg_copy(sigmaid2, &lid2); if (DEBUGLEVEL>1) err_printf("%ld: automorphism(%ld)\n", id,sigmaid); for (l = 1; l < lid2; l++) { GEN id2l = gel(sigmaid2, l); gel(id2, l) = mkvec2(gel(id2l, 1), ZM_mul(ZM_mul(invaut, gel(id2l, 2)), aut)); } break; } } if (!id2) { if (DEBUGLEVEL>1) err_printf("%ld: 1", id); powPgen(nf, gel(F->LP, id), &id2, a); } gel(F->id2, id) = gclone(id2); avma = av; } } F->sfb_chg = 0; F->newpow = 0; } INLINE void step(GEN x, double *y, GEN inc, long k) { if (!y[k]) x[k]++; /* leading coeff > 0 */ else { long i = inc[k]; x[k] += i; inc[k] = (i > 0)? -1-i: 1-i; } } INLINE long Fincke_Pohst_ideal(RELCACHE_t *cache, FB_t *F, GEN nf, GEN M, GEN G, GEN ideal0, FACT *fact, long nbrelpid, FP_t *fp, RNDREL_t *rr, long prec, long *nbsmallnorm, long *nbfact) { pari_sp av; const long N = nf_get_degree(nf), R1 = nf_get_r1(nf); GEN r, u, gx, inc=const_vecsmall(N, 1), ideal; GEN Nideal = nbrelpid ? NULL : idealnorm(nf, ideal0); double BOUND; long j, k, skipfirst, nbrelideal=0, dependent=0, try_elt=0, try_factor=0; u = ZM_lll(ZM_mul(F->G0, ideal0), 0.99, LLL_IM|LLL_COMPATIBLE); ideal = ZM_mul(ideal0,u); /* approximate T2-LLL reduction */ r = gaussred_from_QR(RgM_mul(G, ideal), prec); /* Cholesky for T2 | ideal */ if (!r) pari_err_BUG("small_norm (precision too low)"); skipfirst = ZV_isscalar(gel(ideal,1))? 1: 0; /* 1 probable */ for (k=1; k<=N; k++) { fp->v[k] = gtodouble(gcoeff(r,k,k)); for (j=1; jq[j][k] = gtodouble(gcoeff(r,j,k)); if (DEBUGLEVEL>3) err_printf("fp->v[%ld]=%.4g ",k,fp->v[k]); } BOUND = mindd(BMULT*fp->v[1], 2*(fp->v[2]+fp->v[1]*fp->q[1][2]*fp->q[1][2])); /* BOUND at most BMULT fp->x smallest known vector */ if (DEBUGLEVEL>1) { if (DEBUGLEVEL>3) err_printf("\n"); err_printf("BOUND = %.4g\n",BOUND); err_flush(); } BOUND *= 1 + 1e-6; k = N; fp->y[N] = fp->z[N] = 0; fp->x[N] = 0; for (av = avma;; avma = av, step(fp->x,fp->y,inc,k)) { GEN R; long nz; do { /* look for primitive element of small norm, cf minim00 */ int fl = 0; double p; if (k > 1) { long l = k-1; fp->z[l] = 0; for (j=k; j<=N; j++) fp->z[l] += fp->q[l][j]*fp->x[j]; p = (double)fp->x[k] + fp->z[k]; fp->y[l] = fp->y[k] + p*p*fp->v[k]; if (l <= skipfirst && !fp->y[1]) fl = 1; fp->x[l] = (long)floor(-fp->z[l] + 0.5); k = l; } for(;; step(fp->x,fp->y,inc,k)) { if (++try_elt > maxtry_ELEMENT) return 0; if (!fl) { p = (double)fp->x[k] + fp->z[k]; if (fp->y[k] + p*p*fp->v[k] <= BOUND) break; step(fp->x,fp->y,inc,k); p = (double)fp->x[k] + fp->z[k]; if (fp->y[k] + p*p*fp->v[k] <= BOUND) break; } fl = 0; inc[k] = 1; if (++k > N) return 0; } } while (k > 1); /* element complete */ if (zv_content(fp->x) !=1) continue; /* not primitive */ gx = ZM_zc_mul(ideal,fp->x); if (ZV_isscalar(gx)) continue; if (++try_factor > maxtry_FACT) return 0; if (!nbrelpid) { if (!factorgen(F,nf,ideal0,Nideal,gx,fact)) continue; return 1; } else if (rr) { if (!factorgen(F,nf,ideal0,rr->Nideal,gx,fact)) continue; add_to_fact(rr->jid, 1, fact); gx = nfmul(nf, rr->m1, gx); } else { GEN Nx, xembed = RgM_RgC_mul(M, gx); long e; if (nbsmallnorm) (*nbsmallnorm)++; Nx = grndtoi(embed_norm(xembed, R1), &e); if (e >= 0) { if (DEBUGLEVEL > 1) { err_printf("+"); err_flush(); } continue; } if (!can_factor(F, nf, NULL, gx, Nx, fact)) continue; } /* smooth element */ R = set_fact(F, fact, rr ? rr->ex : NULL, &nz); /* make sure we get maximal rank first, then allow all relations */ if (add_rel(cache, F, R, nz, gx, rr ? 1 : 0) <= 0) { /* probably Q-dependent from previous ones: forget it */ if (DEBUGLEVEL>1) err_printf("*"); if (++dependent > maxtry_DEP) break; continue; } dependent = 0; if (DEBUGLEVEL && nbfact) (*nbfact)++; if (cache->last >= cache->end) return 1; /* we have enough */ if (++nbrelideal == nbrelpid) break; } return 0; } static void small_norm(RELCACHE_t *cache, FB_t *F, GEN nf, long nbrelpid, GEN M, FACT *fact, GEN p0) { pari_timer T; const long prec = nf_get_prec(nf); FP_t fp; pari_sp av; GEN G = nf_get_G(nf), L_jid = F->L_jid; long nbsmallnorm, nbfact, noideal = lg(L_jid); REL_t *last = cache->last; if (DEBUGLEVEL) { timer_start(&T); err_printf("\n#### Look for %ld relations in %ld ideals (small_norm)\n", cache->end - last, lg(L_jid)-1); } nbsmallnorm = nbfact = 0; minim_alloc(lg(M), &fp.q, &fp.x, &fp.y, &fp.z, &fp.v); for (av = avma; --noideal; avma = av) { GEN ideal = gel(F->LP, L_jid[noideal]); if (DEBUGLEVEL>1) err_printf("\n*** Ideal no %ld: %Ps\n", L_jid[noideal], vecslice(ideal,1,4)); if (p0) ideal = idealmul(nf, p0, ideal); else ideal = pr_hnf(nf, ideal); if (Fincke_Pohst_ideal(cache, F, nf, M, G, ideal, fact, nbrelpid, &fp, NULL, prec, &nbsmallnorm, &nbfact)) break; if (DEBUGLEVEL>1) timer_printf(&T, "for this ideal"); } if (DEBUGLEVEL) { err_printf("\n"); timer_printf(&T, "small norm relations"); if (nbsmallnorm && DEBUGLEVEL > 1) err_printf(" nb. fact./nb. small norm = %ld/%ld = %.3f\n", nbfact,nbsmallnorm,((double)nbfact)/nbsmallnorm); } } /* I integral ideal in HNF form */ static GEN remove_content(GEN I) { long N = lg(I)-1; if (!equali1(gcoeff(I,N,N))) I = Q_primpart(I); return I; } static GEN get_random_ideal(FB_t *F, GEN nf, GEN ex) { long l = lg(ex); for (;;) { GEN ideal = NULL; long i; for (i=1; isubFB[i]; ex[i] = random_bits(RANDOM_BITS); if (ex[i]) { GEN a = gmael(F->id2,id,ex[i]); ideal = ideal? idealHNF_mul(nf,ideal, a): idealhnf_two(nf,a); } } if (ideal) { /* ex != 0 */ ideal = remove_content(ideal); if (!is_pm1(gcoeff(ideal,1,1))) return ideal; /* ideal != Z_K */ } } } static void rnd_rel(RELCACHE_t *cache, FB_t *F, GEN nf, FACT *fact) { pari_timer T; const GEN L_jid = F->L_jid, M = nf_get_M(nf), G = F->G0; GEN baseideal; RNDREL_t rr; FP_t fp; const long nbG = lg(F->vecG)-1, lgsub = lg(F->subFB), l_jid = lg(L_jid); const long prec = nf_get_prec(nf); long jlist; pari_sp av; /* will compute P[ L_jid[i] ] * (random product from subFB) */ if (DEBUGLEVEL) { timer_start(&T); err_printf("\n#### Look for %ld relations in %ld ideals (rnd_rel)\n", cache->end - cache->last, lg(L_jid)-1); } rr.ex = cgetg(lgsub, t_VECSMALL); baseideal = get_random_ideal(F, nf, rr.ex); baseideal = red(nf, baseideal, F->G0, &rr.m1); minim_alloc(lg(M), &fp.q, &fp.x, &fp.y, &fp.z, &fp.v); for (av = avma, jlist = 1; jlist < l_jid; jlist++, avma = av) { long j; GEN ideal; pari_sp av1; REL_t *last = cache->last; rr.jid = L_jid[jlist]; ideal = gel(F->LP,rr.jid); if (DEBUGLEVEL>1) err_printf("\n*** Ideal no %ld: %Ps\n", rr.jid, vecslice(ideal,1,4)); ideal = idealHNF_mul(nf, baseideal, ideal); rr.Nideal = ZM_det_triangular(ideal); if (Fincke_Pohst_ideal(cache, F, nf, M, G, ideal, fact, RND_REL_RELPID, &fp, &rr, prec, NULL, NULL)) break; if (PREVENT_LLL_IN_RND_REL || cache->last != last) continue; for (av1 = avma, j = 1; j <= nbG; j++, avma = av1) { /* reduce along various directions */ GEN m = idealpseudomin_nonscalar(ideal, gel(F->vecG,j)); GEN R; long nz; if (!factorgen(F,nf,ideal,rr.Nideal,m,fact)) continue; /* can factor ideal, record relation */ add_to_fact(rr.jid, 1, fact); R = set_fact(F, fact, rr.ex, &nz); switch (add_rel(cache, F, R, nz, nfmul(nf, m, rr.m1), 1)) { case -1: /* forget it */ if (DEBUGLEVEL>1) dbg_cancelrel(rr.jid,j,R); continue; } if (DEBUGLEVEL) timer_printf(&T, "for this relation"); /* Need more, try next prime ideal */ if (cache->last < cache->end) break; /* We have found enough. Return */ avma = av; return; } } if (DEBUGLEVEL) { err_printf("\n"); timer_printf(&T, "for remaining ideals"); } } static GEN automorphism_perms(GEN M, GEN auts, GEN cyclic, long N) { pari_sp av; const long r1plusr2 = lgcols(M), r1 = 2*r1plusr2-N-2, r2 = r1plusr2-r1-1; long nauts = lg(auts), ncyc = lg(cyclic), i, j, l, m; GEN Mt, perms = cgetg(nauts, t_VEC); for (l = 1; l < nauts; l++) gel(perms, l) = cgetg(r1plusr2, t_VECSMALL); av = avma; Mt = shallowtrans(gprec_w(M, 3)); /* need little accuracy */ Mt = shallowconcat(Mt, conj_i(vecslice(Mt, r1+1, r1+r2))); for (l = 1; l < ncyc; l++) { GEN thiscyc = gel(cyclic, l); long k = thiscyc[1]; GEN Nt = RgM_mul(shallowtrans(gel(auts, k)), Mt); GEN perm = gel(perms, k), permprec; pari_sp av2 = avma; for (i = 1; i < r1plusr2; i++, avma = av2) { GEN vec = gel(Nt, i), minnorm; minnorm = gnorml2(gsub(vec, gel(Mt, 1))); perm[i] = 1; for (j = 2; j <= N; j++) { GEN thisnorm = gnorml2(gsub(vec, gel(Mt, j))); if (gcmp(thisnorm, minnorm) < 0) { minnorm = thisnorm; perm[i] = j >= r1plusr2 ? r2-j : j; } } } for (permprec = perm, m = 2; m < lg(thiscyc); m++) { GEN thisperm = gel(perms, thiscyc[m]); for (i = 1; i < r1plusr2; i++) { long pp = labs(permprec[i]); thisperm[i] = permprec[i] < 0 ? -perm[pp] : perm[pp]; } permprec = thisperm; } } avma = av; return perms; } /* Determine the field automorphisms and its matrix in the integral basis. */ static GEN automorphism_matrices(GEN nf, GEN *invp, GEN *cycp) { pari_sp av = avma; GEN auts = galoisconj(nf, NULL), mats, cyclic, cyclicidx; GEN invs; long nauts = lg(auts)-1, i, j, k, l; cyclic = cgetg(nauts+1, t_VEC); cyclicidx = zero_Flv(nauts); invs = zero_Flv(nauts-1); for (l = 1; l <= nauts; l++) { GEN aut = gel(auts, l); if (gequalX(aut)) { swap(gel(auts, l), gel(auts, nauts)); break; } } /* trivial automorphism is last */ for (l = 1; l <= nauts; l++) gel(auts, l) = algtobasis(nf, gel(auts, l)); /* Compute maximal cyclic subgroups */ for (l = nauts; --l > 0; ) if (!cyclicidx[l]) { GEN elt = gel(auts, l), aut = elt, cyc = cgetg(nauts+1, t_VECSMALL); cyclicidx[l] = l; cyc[1] = l; j = 1; do { elt = galoisapply(nf, elt, aut); for (k = 1; k <= nauts; k++) if (gequal(elt, gel(auts, k))) break; cyclicidx[k] = l; cyc[++j] = k; } while (k != nauts); setlg(cyc, j); gel(cyclic, l) = cyc; /* Store the inverses */ for (i = 1; i <= j/2; i++) { invs[cyc[i]] = cyc[j-i]; invs[cyc[j-i]] = cyc[i]; } } for (i = j = 1; i < nauts; i++) if (cyclicidx[i] == i) cyclic[j++] = cyclic[i]; setlg(cyclic, j); mats = cgetg(nauts, t_VEC); while (--j > 0) { GEN cyc = gel(cyclic, j); long id = cyc[1]; GEN M, Mi, aut = gel(auts, id); gel(mats, id) = Mi = M = nfgaloismatrix(nf, aut); for (i = 2; i < lg(cyc); i++) { Mi = ZM_mul(Mi, M); gel(mats, cyc[i]) = Mi; } } gerepileall(av, 3, &mats, &invs, &cyclic); if (invp) *invp = invs; if (cycp) *cycp = cyclic; return mats; } /* vP a list of maximal ideals above the same p from idealprimedec: f(P/p) is * increasing; 1 <= j <= #vP; orbit a zc of length <= #vP; auts a vector of * automorphisms in ZM form. * Set orbit[i] = 1 for all vP[i], i >= j, in the orbit of pr = vP[j] wrt auts. * N.B.1 orbit need not be initialized to 0: useful to incrementally run * through successive orbits * N.B.2 i >= j, so primes with index < j will be missed; run incrementally * starting from j = 1 ! */ static void pr_orbit_fill(GEN orbit, GEN auts, GEN vP, long j) { GEN pr = gel(vP,j), gen = pr_get_gen(pr); long i, l = lg(auts), J = lg(orbit), f = pr_get_f(pr); orbit[j] = 1; for (i = 1; i < l; i++) { GEN g = ZM_ZC_mul(gel(auts,i), gen); long k; for (k = j+1; k < J; k++) { GEN prk = gel(vP,k); if (pr_get_f(prk) > f) break; /* f(P[k]) increases with k */ /* don't check that e matches: (almost) always 1 ! */ if (!orbit[k] && ZC_prdvd(g, prk)) { orbit[k] = 1; break; } } } } /* remark: F->KCZ changes if be_honest() fails */ static int be_honest(FB_t *F, GEN nf, GEN auts, FACT *fact) { long ex, i, iz, nbtest; long lgsub = lg(F->subFB), KCZ0 = F->KCZ; long N = nf_get_degree(nf), prec = nf_get_prec(nf); GEN M = nf_get_M(nf), G = nf_get_G(nf); FP_t fp; pari_sp av; if (DEBUGLEVEL) { err_printf("Be honest for %ld primes from %ld to %ld\n", F->KCZ2 - F->KCZ, F->FB[ F->KCZ+1 ], F->FB[ F->KCZ2 ]); } minim_alloc(N+1, &fp.q, &fp.x, &fp.y, &fp.z, &fp.v); if (lg(auts) == 1) auts = NULL; av = avma; for (iz=F->KCZ+1; iz<=F->KCZ2; iz++, avma = av) { long p = F->FB[iz]; GEN pr_orbit, P = F->LV[p]; long j, J = lg(P); /* > 1 */ /* the P|p, NP > C2 are assumed in subgroup generated by FB + last P * with NP <= C2 is unramified --> check all but last */ if (pr_get_e(gel(P,J-1)) == 1) J--; if (J == 1) continue; if (DEBUGLEVEL>1) err_printf("%ld ", p); pr_orbit = auts? zero_zv(J-1): NULL; for (j = 1; j < J; j++) { GEN ideal, ideal0; if (pr_orbit) { if (pr_orbit[j]) continue; /* discard all primes in automorphism orbit simultaneously */ pr_orbit_fill(pr_orbit, auts, P, j); } ideal = ideal0 = pr_hnf(nf,gel(P,j)); for (nbtest=0;;) { if (Fincke_Pohst_ideal(NULL, F, nf, M, G, ideal, fact, 0, &fp, NULL, prec, NULL, NULL)) break; if (++nbtest > maxtry_HONEST) { if (DEBUGLEVEL) pari_warn(warner,"be_honest() failure on prime %Ps\n", gel(P,j)); return 0; } /* occurs at most once in the whole function */ if (F->newpow) powFBgen(NULL, F, nf, auts); for (i = 1, ideal = ideal0; i < lgsub; i++) { long id = F->subFB[i]; ex = random_bits(RANDOM_BITS); if (ex) ideal = idealHNF_mul(nf,ideal, gmael(F->id2,id,ex)); } ideal = remove_content(ideal); if (expi(gcoeff(ideal,1,1)) > 100) ideal = idealred(nf, ideal); } } F->KCZ++; /* SUCCESS, "enlarge" factorbase */ } F->KCZ = KCZ0; avma = av; return 1; } /* all primes with N(P) <= BOUND factor on factorbase ? */ void bnftestprimes(GEN bnf, GEN BOUND) { pari_sp av0 = avma, av; ulong count = 0; GEN auts, p, nf = bnf_get_nf(bnf), Vbase = bnf_get_vbase(bnf); GEN fb = gen_sort(Vbase, (void*)&cmp_prime_ideal, cmp_nodata); /*tablesearch*/ ulong pmax = itou( pr_get_p(gel(fb, lg(fb)-1)) ); /*largest p in factorbase*/ forprime_t S; FACT *fact; FB_t F; (void)recover_partFB(&F, Vbase, nf_get_degree(nf)); fact = (FACT*)stack_malloc((F.KC+1)*sizeof(FACT)); forprime_init(&S, gen_2, BOUND); auts = automorphism_matrices(nf, NULL, NULL); if (lg(auts) == 1) auts = NULL; av = avma; while (( p = forprime_next(&S) )) { GEN pr_orbit, vP; long j, J; if (DEBUGLEVEL == 1 && ++count > 1000) { err_printf("passing p = %Ps / %Ps\n", p, BOUND); count = 0; } avma = av; vP = idealprimedec_limit_norm(bnf, p, BOUND); J = lg(vP); /* if last is unramified, all P|p in subgroup generated by FB: skip last */ if (J > 1 && pr_get_e(gel(vP,J-1)) == 1) J--; if (J == 1) continue; if (DEBUGLEVEL>1) err_printf("*** p = %Ps\n",p); pr_orbit = auts? zero_zv(J-1): NULL; for (j = 1; j < J; j++) { GEN P = gel(vP,j); long k; if (pr_orbit) { if (pr_orbit[j]) continue; /* discard all primes in automorphism orbit simultaneously */ pr_orbit_fill(pr_orbit, auts, vP, j); } if (DEBUGLEVEL>1) err_printf(" Testing P = %Ps\n",P); if (abscmpiu(p, pmax) <= 0 && (k = tablesearch(fb, P, &cmp_prime_ideal))) { if (DEBUGLEVEL>1) err_printf(" #%ld in factor base\n",k); } else if (DEBUGLEVEL>1) err_printf(" is %Ps\n", isprincipal(bnf,P)); else /* faster: don't compute result */ (void)SPLIT(&F, nf, pr_hnf(nf,P), Vbase, fact); } } avma = av0; } /* A t_MAT of complex floats, in fact reals. Extract a submatrix B * whose columns are definitely non-0, i.e. gexpo(A[j]) >= -2 * * If possible precision problem (t_REAL 0 with large exponent), set * *precpb to 1 */ static GEN clean_cols(GEN A, int *precpb) { long l = lg(A), h, i, j, k; GEN B; *precpb = 0; if (l == 1) return A; h = lgcols(A);; B = cgetg(l, t_MAT); for (i = k = 1; i < l; i++) { GEN Ai = gel(A,i); int non0 = 0; for (j = 1; j < h; j++) { GEN c = gel(Ai,j); if (gexpo(c) >= -2) { if (gequal0(c)) *precpb = 1; else non0 = 1; } } if (non0) gel(B, k++) = Ai; } setlg(B, k); return B; } static long compute_multiple_of_R_pivot(GEN X, GEN x0/*unused*/, long ix, GEN c) { GEN x = gel(X,ix); long i, k = 0, ex = - (long)HIGHEXPOBIT, lx = lg(x); (void)x0; for (i=1; i ex) { ex = e; k = i; } } return (k && ex > -32)? k: lx; } /* A = complex logarithmic embeddings of units (u_j) found so far, * RU = R1+R2 = unit rank, N = field degree * need = unit rank defect * L = NULL (prec problem) or B^(-1) * A with approximate rational entries * (as t_REAL), B a submatrix of A, with (probably) maximal rank RU */ static GEN compute_multiple_of_R(GEN A, long RU, long N, long *pneed, long *bit, GEN *ptL) { GEN T, d, mdet, Im_mdet, kR, xreal, L; long i, j, r, R1 = 2*RU - N; int precpb; pari_sp av = avma; if (RU == 1) { *ptL = zeromat(0, lg(A)-1); return gen_1; } if (DEBUGLEVEL) err_printf("\n#### Computing regulator multiple\n"); xreal = real_i(A); /* = (log |sigma_i(u_j)|) */ mdet = clean_cols(xreal, &precpb); /* will cause precision to increase on later failure, but we may succeed! */ *ptL = precpb? NULL: gen_1; T = cgetg(RU+1,t_COL); for (i=1; i<=R1; i++) gel(T,i) = gen_1; for ( ; i<=RU; i++) gel(T,i) = gen_2; mdet = shallowconcat(T, mdet); /* det(Span(mdet)) = N * R */ /* could be using indexrank(), but need custom "get_pivot" function */ d = RgM_pivots(mdet, NULL, &r, &compute_multiple_of_R_pivot); /* # of independent columns == unit rank ? */ if (lg(mdet)-1 - r != RU) { if (DEBUGLEVEL) err_printf("Unit group rank = %ld < %ld\n",lg(mdet)-1 - r, RU); *pneed = RU - (lg(mdet)-1-r); avma = av; return NULL; } Im_mdet = cgetg(RU+1, t_MAT); /* extract independent columns */ /* N.B: d[1] = 1, corresponding to T above */ gel(Im_mdet, 1) = T; for (i = j = 2; i <= RU; j++) if (d[j]) gel(Im_mdet, i++) = gel(mdet,j); /* integral multiple of R: the cols we picked form a Q-basis, they have an * index in the full lattice. First column is T */ kR = divru(det2(Im_mdet), N); /* R > 0.2 uniformly */ if (!signe(kR) || expo(kR) < -3) { avma=av; *pneed = 0; return NULL; } setabssign(kR); L = RgM_inv(Im_mdet); if (!L) { *ptL = NULL; return kR; } /* estimate for # of correct bits in result */ *bit = - gexpo(RgM_Rg_sub(RgM_mul(L,Im_mdet), gen_1)); L = rowslice(L, 2, RU); /* remove first line */ L = RgM_mul(L, xreal); /* approximate rational entries */ gerepileall(av,2, &L, &kR); *ptL = L; return kR; } /* leave small integer n as is, convert huge n to t_REAL (for readability) */ static GEN i2print(GEN n) { return lgefint(n) <= DEFAULTPREC? n: itor(n,LOWDEFAULTPREC); } static long bad_check(GEN c) { long ec = gexpo(c); if (DEBUGLEVEL) err_printf("\n ***** check = %.28Pg\n",c); /* safe check for c < 0.75 : avoid underflow in gtodouble() */ if (ec < -1 || (ec == -1 && gtodouble(c) < 0.75)) return fupb_PRECI; /* safe check for c > 1.3 : avoid overflow */ if (ec > 0 || (ec == 0 && gtodouble(c) > 1.3)) return fupb_RELAT; return fupb_NONE; } /* Input: * lambda = approximate rational entries: coords of units found so far on a * sublattice of maximal rank (sublambda) * *ptkR = regulator of sublambda = multiple of regulator of lambda * Compute R = true regulator of lambda. * * If c := Rz ~ 1, by Dirichlet's formula, then lambda is the full group of * units AND the full set of relations for the class group has been computed. * * In fact z is a very rough approximation and we only expect 0.75 < Rz < 1.3 * bit is an estimate for the actual accuracy of lambda * * Output: *ptkR = R, *ptU = basis of fundamental units (in terms lambda) */ static int compute_R(GEN lambda, long RU, GEN z, long bit, GEN *ptL, GEN *ptkR) { pari_sp av = avma; long r, reason; GEN L, H, D, den, R, c; *ptL = NULL; if (DEBUGLEVEL) { err_printf("\n#### Computing check\n"); err_flush(); } if (RU == 1) { *ptkR = gen_1; *ptL = lambda; return bad_check(z); } D = gmul2n(mpmul(*ptkR,z), 1); /* bound for denom(lambda) */ if (expo(D) < 0 && rtodbl(D) < 0.95) return fupb_PRECI; lambda = bestappr(lambda,D); if (lg(lambda) == 1) { if (DEBUGLEVEL) err_printf("truncation error in bestappr\n"); return fupb_PRECI; } den = Q_denom(lambda); if (mpcmp(den,D) > 0) { if (DEBUGLEVEL) err_printf("D = %Ps\nden = %Ps\n",D, i2print(den)); return fupb_PRECI; } L = Q_muli_to_int(lambda, den); if (RU > 5) bit -= 64; else if (RU > 3) bit -= 32; if (gexpo(L) + expi(den) > bit) { if (DEBUGLEVEL) err_printf("dubious bestappr; den = %Ps\n", i2print(den)); return fupb_PRECI; } H = ZM_hnf(L); r = lg(H)-1; if (!r || r != nbrows(H)) R = gen_0; /* wrong rank */ else R = gmul(*ptkR, gdiv(ZM_det_triangular(H), powiu(den, r))); /* R = tentative regulator; regulator > 0.2 uniformly */ if (gexpo(R) < -3) { if (DEBUGLEVEL) err_printf("\n#### Tentative regulator: %.28Pg\n", R); avma = av; return fupb_PRECI; } c = gmul(R,z); /* should be n (= 1 if we are done) */ if (DEBUGLEVEL) err_printf("\n#### Tentative regulator: %.28Pg\n", R); if ((reason = bad_check(c))) { avma = av; return reason; } *ptkR = R; *ptL = L; return fupb_NONE; } /* norm of an extended ideal I, whose 1st component is in integral HNF */ static GEN idnorm(GEN I) { return ZM_det_triangular(gel(I,1)); } /* find the smallest (wrt norm) among I, I^-1 and red(I^-1) */ static GEN inverse_if_smaller(GEN nf, GEN I) { GEN d, dmin, I1; dmin = idnorm(I); I1 = idealinv(nf,I); gel(I1,1) = Q_remove_denom(gel(I1,1), NULL); d = idnorm(I1); if (cmpii(d,dmin) < 0) {I=I1; dmin=d;} /* try reducing (often _increases_ the norm) */ I1 = idealred(nf,I1); d = idnorm(I1); if (cmpii(d,dmin) < 0) I=I1; return I; } /* in place */ static void neg_row(GEN U, long i) { GEN c = U + lg(U)-1; for (; c>U; c--) gcoeff(c,i,0) = negi(gcoeff(c,i,0)); } static void setlg_col(GEN U, long l) { GEN c = U + lg(U)-1; for (; c>U; c--) setlg(*c, l); } /* compute class group (clg1) + data for isprincipal (clg2) */ static void class_group_gen(GEN nf,GEN W,GEN C,GEN Vbase,long prec, GEN nf0, GEN *ptclg1,GEN *ptclg2) { GEN z, G, Ga, ga, GD, cyc, X, Y, D, U, V, Ur, Ui, Uir, I, J, arch; long i, j, lo, lo0; pari_timer T; if (DEBUGLEVEL) timer_start(&T); D = ZM_snfall(W,&U,&V); /* UWV=D, D diagonal, G = g Ui (G=new gens, g=old) */ Ui = ZM_inv(U, NULL); lo0 = lo = lg(D); /* we could set lo = lg(cyc) and truncate all matrices below * setlg_col(D && U && Y, lo) + setlg(D && V && X && Ui, lo) * but it's not worth the complication: * 1) gain is negligible (avoid computing z^0 if lo < lo0) * 2) when computing ga, the products XU and VY use the original matrices */ Ur = ZM_hnfdivrem(U, D, &Y); Uir = ZM_hnfdivrem(Ui,W, &X); /* [x] = logarithmic embedding of x (arch. component) * NB: z = idealred(I) --> I = y z[1], with [y] = - z[2] * P invertible diagonal matrix (\pm 1) which is only implicitly defined * G = g Uir P + [Ga], Uir = Ui + WX * g = G P Ur + [ga], Ur = U + DY */ G = cgetg(lo,t_VEC); Ga= cgetg(lo,t_VEC); z = init_famat(NULL); if (!nf0) nf0 = nf; for (j=1; j0; j--) { pari_sp av = avma; GEN y = get_y(bnf, W, B, C, pFB, j); if (typ(y) == t_INT) { long E = itos(y); if (DEBUGLEVEL>1) err_printf("\n%ld done later at prec %ld\n",j,E); avma = av; vecsmalltrunc_append(retry, j); if (E > prec) prec = E; } else { if (DEBUGLEVEL>1) err_printf("%ld ",j); gel(ma,j) = gerepileupto(av,y); } } if (prec) { long k, l = lg(retry); GEN y, nf = bnf_get_nf(bnf); if (DEBUGLEVEL) pari_warn(warnprec,"makematal",prec); nf = nfnewprec_shallow(nf,prec); bnf = Buchall(nf, nf_FORCE, prec); if (DEBUGLEVEL) err_printf("makematal, adding missing entries:"); for (k=1; k1) err_printf("%ld ",j); gel(ma,j) = gerepileupto(av,y); } } if (DEBUGLEVEL>1) err_printf("\n"); return ma; } enum { MATAL = 1, CYCGEN, UNITS }; GEN bnf_build_cycgen(GEN bnf) { return obj_checkbuild(bnf, CYCGEN, &makecycgen); } GEN bnf_build_matalpha(GEN bnf) { return obj_checkbuild(bnf, MATAL, &makematal); } GEN bnf_build_units(GEN bnf) { return obj_checkbuild(bnf, UNITS, &makeunits); } static GEN get_regulator(GEN mun) { pari_sp av = avma; GEN R; if (lg(mun) == 1) return gen_1; R = det( rowslice(real_i(mun), 1, lgcols(mun)-2) ); setabssign(R); return gerepileuptoleaf(av, R); } /* return corrected archimedian components for elts of x (vector) * (= log(sigma_i(x)) - log(|Nx|) / [K:Q]) */ static GEN get_archclean(GEN nf, GEN x, long prec, int units) { long k,N, la = lg(x); GEN M = cgetg(la,t_MAT); if (la == 1) return M; N = nf_get_degree(nf); for (k=1; k 1) { long e = gexpo(bnf_get_logfu(bnf)) + 1 - TWOPOTBITS_IN_LONG; if (e >= 0) prec += nbits2extraprec(e); } if (DEBUGLEVEL && prec1!=prec) pari_warn(warnprec,"bnfnewprec",prec); matal = bnf_build_matalpha(bnf); for(;;) { pari_sp av = avma; nf = nfnewprec_shallow(nf0,prec); mun = get_archclean(nf, fu, prec, 1); if (mun) { gac = get_archclean(nf, matal, prec, 0); if (gac) break; } avma = av; prec = precdbl(prec); if (DEBUGLEVEL) pari_warn(warnprec,"bnfnewprec(extra)",prec); } y = leafcopy(bnf); gel(y,3) = mun; gel(y,4) = gac; gel(y,7) = nf; my_class_group_gen(y,prec,nf0, &clgp,&clgp2); res = leafcopy(gel(bnf,8)); gel(res,1) = clgp; gel(res,2) = get_regulator(mun); gel(y,8) = res; gel(y,9) = clgp2; return y; } GEN bnfnewprec(GEN bnf, long prec) { pari_sp av = avma; return gerepilecopy(av, bnfnewprec_shallow(checkbnf(bnf), prec)); } GEN bnrnewprec_shallow(GEN bnr, long prec) { GEN y = cgetg(7,t_VEC); long i; gel(y,1) = bnfnewprec_shallow(bnr_get_bnf(bnr), prec); for (i=2; i<7; i++) gel(y,i) = gel(bnr,i); return y; } GEN bnrnewprec(GEN bnr, long prec) { GEN y = cgetg(7,t_VEC); long i; checkbnr(bnr); gel(y,1) = bnfnewprec(bnr_get_bnf(bnr), prec); for (i=2; i<7; i++) gel(y,i) = gcopy(gel(bnr,i)); return y; } static GEN get_clfu(GEN clgp, GEN reg, GEN zu, GEN fu) { if (!fu) fu = cgetg(1,t_MAT); return mkvec5(clgp, reg, gen_1/*DUMMY*/, zu, fu); } static GEN buchall_end(GEN nf,GEN res, GEN clg2, GEN W, GEN B, GEN A, GEN C,GEN Vbase) { GEN z = obj_init(9, 3); gel(z,1) = W; gel(z,2) = B; gel(z,3) = A; gel(z,4) = C; gel(z,5) = Vbase; gel(z,6) = gen_0; gel(z,7) = nf; gel(z,8) = res; gel(z,9) = clg2; return z; } /* FIXME: obsolete function */ GEN bnfcompress(GEN bnf) { pari_sp av = avma; GEN nf, fu, y = cgetg(13,t_VEC); bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); gel(y,1) = nf_get_pol(nf); gel(y,2) = gmael(nf,2,1); gel(y,3) = nf_get_disc(nf); gel(y,4) = nf_get_zk(nf); gel(y,5) = nf_get_roots(nf); gel(y,6) = gen_0; /* FIXME: unused */ gel(y,7) = bnf_get_W(bnf); gel(y,8) = bnf_get_B(bnf); gel(y,9) = codeprimes(bnf_get_vbase(bnf), nf_get_degree(nf)); gel(y,10) = mkvec2(utoipos(bnf_get_tuN(bnf)), nf_to_scalar_or_basis(nf, bnf_get_tuU(bnf))); fu = bnf_build_units(bnf); fu = vecslice(fu,2,lg(fu)-1); gel(y,11) = fu; gel(y,12) = bnf_build_matalpha(bnf); return gerepilecopy(av, y); } /* FIXME: obsolete feature */ static GEN sbnf2bnf(GEN sbnf, long prec) { pari_sp av = avma; GEN ro, nf, A, fu, FU, C, clgp, clgp2, res, y, W, zu, matal, Vbase; long k, l; nfmaxord_t S; if (typ(sbnf) != t_VEC || lg(sbnf) != 13) pari_err_TYPE("bnfmake",sbnf); if (prec < DEFAULTPREC) prec = DEFAULTPREC; S.T0 = S.T = gel(sbnf,1); S.r1 = itos(gel(sbnf,2)); S.dK = gel(sbnf,3); S.basis = gel(sbnf,4); S.index = NULL; S.dT = NULL; S.dKP = NULL; S.basden= NULL; ro = gel(sbnf,5); if (prec > gprecision(ro)) ro = NULL; nf = nfmaxord_to_nf(&S, ro, prec); fu = gel(sbnf,11); A = get_archclean(nf, fu, prec, 1); if (!A) pari_err_PREC("bnfmake"); prec = nf_get_prec(nf); matal = gel(sbnf,12); C = get_archclean(nf,matal,prec,0); if (!C) pari_err_PREC("bnfmake"); Vbase = decode_pr_lists(nf, gel(sbnf,9)); W = gel(sbnf,7); class_group_gen(nf,W,C,Vbase,prec,NULL, &clgp,&clgp2); zu = gel(sbnf,10); zu = mkvec2(gel(zu,1), nf_to_scalar_or_alg(nf, gel(zu,2))); FU = cgetg_copy(fu, &l); for (k=1; k < l; k++) gel(FU,k) = nf_to_scalar_or_alg(nf, gel(fu,k)); res = get_clfu(clgp, get_regulator(A), zu, FU); y = buchall_end(nf,res,clgp2,W,gel(sbnf,8),A,C,Vbase); return gerepilecopy(av,y); } GEN bnfinit0(GEN P, long flag, GEN data, long prec) { double c1 = BNF_C1, c2 = BNF_C2; long fl, relpid = BNF_RELPID; if (typ(P) == t_VEC && lg(P) == 13) return sbnf2bnf(P, prec); /* sbnf */ if (data) { long lx = lg(data); if (typ(data) != t_VEC || lx > 5) pari_err_TYPE("bnfinit",data); switch(lx) { case 4: relpid = itos(gel(data,3)); case 3: c2 = gtodouble(gel(data,2)); case 2: c1 = gtodouble(gel(data,1)); } } switch(flag) { case 2: case 0: fl = 0; break; case 1: fl = nf_FORCE; break; default: pari_err_FLAG("bnfinit"); return NULL; /* LCOV_EXCL_LINE */ } return Buchall_param(P, c1, c2, relpid, fl, prec); } GEN Buchall(GEN P, long flag, long prec) { return Buchall_param(P, BNF_C1, BNF_C2, BNF_RELPID, flag, prec); } static GEN Buchall_deg1(GEN nf) { GEN v = cgetg(1,t_VEC), m = cgetg(1,t_MAT); GEN W, A, B, C, Vbase, res; GEN fu = v, R = gen_1, zu = mkvec2(gen_2, gen_m1); GEN clg1 = mkvec3(gen_1,v,v), clg2 = mkvec3(m,v,v); W = A = B = C = m; Vbase = cgetg(1,t_COL); res = get_clfu(clg1, R, zu, fu); return buchall_end(nf,res,clg2,W,B,A,C,Vbase); } /* return (small set of) indices of columns generating the same lattice as x. * Assume HNF(x) is inexpensive (few rows, many columns). * Dichotomy approach since interesting columns may be at the very end */ GEN extract_full_lattice(GEN x) { long dj, j, k, l = lg(x); GEN h, h2, H, v; if (l < 200) return NULL; /* not worth it */ v = vecsmalltrunc_init(l); H = ZM_hnf(x); h = cgetg(1, t_MAT); dj = 1; for (j = 1; j < l; ) { pari_sp av = avma; long lv = lg(v); for (k = 0; k < dj; k++) v[lv+k] = j+k; setlg(v, lv + dj); h2 = ZM_hnf(vecpermute(x, v)); if (ZM_equal(h, h2)) { /* these dj columns can be eliminated */ avma = av; setlg(v, lv); j += dj; if (j >= l) break; dj <<= 1; if (j + dj >= l) { dj = (l - j) >> 1; if (!dj) dj = 1; } } else if (dj > 1) { /* at least one interesting column, try with first half of this set */ avma = av; setlg(v, lv); dj >>= 1; /* > 0 */ } else { /* this column should be kept */ if (ZM_equal(h2, H)) break; h = h2; j++; } } return v; } static void init_rel(RELCACHE_t *cache, FB_t *F, long add_need) { const long n = F->KC + add_need; /* expected # of needed relations */ long i, j, k, p; GEN c, P; GEN R; if (DEBUGLEVEL) err_printf("KCZ = %ld, KC = %ld, n = %ld\n", F->KCZ,F->KC,n); reallocate(cache, 10*n + 50); /* make room for lots of relations */ cache->chk = cache->base; cache->end = cache->base + n; cache->relsup = add_need; cache->last = cache->base; cache->missing = lg(cache->basis) - 1; for (i = 1; i <= F->KCZ; i++) { /* trivial relations (p) = prod P^e */ p = F->FB[i]; P = F->LV[p]; if (!isclone(P)) continue; /* all prime divisors in FB */ c = zero_Flv(F->KC); k = F->iLP[p]; R = c; c += k; for (j = lg(P)-1; j; j--) c[j] = pr_get_e(gel(P,j)); add_rel(cache, F, R, k+1, /*m*/NULL, 0); } } /* Let z = \zeta_n in nf. List of not-obviously-dependent generators for * cyclotomic units modulo torsion in Q(z) [independent when n a prime power]: * - z^a - 1, n/(a,n) not a prime power, a \nmid n unless a=1, 1 <= a < n/2 * - (Z^a - 1)/(Z - 1), p^k || n, Z = z^{n/p^k}, (p,a) = 1, 1 < a <= (p^k-1)/2 */ GEN nfcyclotomicunits(GEN nf, GEN zu) { long n = itos(gel(zu, 1)), n2, lP, i, a; GEN z, fa, P, E, L, mz, powz; if (n <= 6) return cgetg(1, t_VEC); z = algtobasis(nf,gel(zu, 2)); if ((n & 3) == 2) { n = n >> 1; z = ZC_neg(z); } /* ensure n != 2 (mod 4) */ n2 = n/2; mz = zk_multable(nf, z); /* multiplication by z */ powz = cgetg(n2, t_VEC); gel(powz,1) = z; for (i = 2; i < n2; i++) gel(powz,i) = ZM_ZC_mul(mz, gel(powz,i-1)); /* powz[i] = z^i */ L = vectrunc_init(n); fa = factoru(n); P = gel(fa,1); lP = lg(P); E = gel(fa,2); for (i = 1; i < lP; i++) { /* second kind */ long p = P[i], k = E[i], pk = upowuu(p,k), pk2 = (pk-1) / 2; GEN u = gen_1; for (a = 2; a <= pk2; a++) { u = nfadd(nf, u, gel(powz, (n/pk) * (a-1))); /* = (Z^a-1)/(Z-1) */ if (a % p) vectrunc_append(L, u); } } if (lP > 2) for (a = 1; a < n2; a++) { /* first kind, when n not a prime power */ ulong p; if (a > 1 && (n % a == 0 || uisprimepower(n/ugcd(a,n), &p))) continue; vectrunc_append(L, nfadd(nf, gel(powz, a), gen_m1)); } return L; } static void add_cyclotomic_units(GEN nf, GEN zu, RELCACHE_t *cache, FB_t *F) { pari_sp av = avma; GEN L = nfcyclotomicunits(nf, zu); long i, l = lg(L); if (l > 1) { GEN R = zero_Flv(F->KC); for(i = 1; i < l; i++) add_rel(cache, F, R, F->KC+1, gel(L,i), 0); } avma = av; } static void shift_embed(GEN G, GEN Gtw, long a, long r1) { long j, k, l = lg(G); if (a <= r1) for (j=1; jG0 = G0 = ground(G); F->vecG = mkvec( G0 ); return; } for (e = 32;;) { G = gmul2n(G, e); G0 = ground(G); if (ZM_rank(G0) == r) break; /* maximal rank ? */ } Gtw0 = ground(gmul2n(G, 10)); vecG = cgetg(1 + n*(n+1)/2,t_VEC); for (ind=j=1; j<=n; j++) for (i=1; i<=j; i++) gel(vecG,ind++) = shift_G(G0,Gtw0,i,j,r1); F->G0 = G0; F->vecG = vecG; } static GEN trim_list(FB_t *F) { pari_sp av = avma; GEN L_jid = F->L_jid, present = zero_Flv(F->KC); long i, j, imax = minss(lg(L_jid), F->KC + 1); GEN minidx = F->minidx, idx = cgetg(imax, t_VECSMALL); for (i = j = 1; i < imax; i++) { long id = minidx[L_jid[i]]; if (!present[id]) { idx[j++] = L_jid[i]; present[id] = 1; } } setlg(idx, j); return gerepileuptoleaf(av, idx); } static void try_elt(RELCACHE_t *cache, FB_t *F, GEN nf, GEN x, FACT *fact) { pari_sp av = avma; GEN R, Nx; long nz, tx = typ(x); if (tx == t_INT || tx == t_FRAC) return; if (tx != t_COL) x = algtobasis(nf, x); if (RgV_isscalar(x)) return; x = Q_primpart(x); Nx = nfnorm(nf, x); if (!can_factor(F, nf, NULL, x, Nx, fact)) return; /* smooth element */ R = set_fact(F, fact, NULL, &nz); /* make sure we get maximal rank first, then allow all relations */ (void) add_rel(cache, F, R, nz, x, 0); avma = av; } static long scalar_bit(GEN x) { return bit_accuracy(gprecision(x)) - gexpo(x); } static long RgM_bit(GEN x, long bit) { long i, j, m, b = bit, l = lg(x); if (l == 1) return b; m = lgcols(x); for (j = 1; j < l; j++) for (i = 1; i < m; i++ ) b = minss(b, scalar_bit(gcoeff(x,i,j))); return b; } GEN Buchall_param(GEN P, double cbach, double cbach2, long nbrelpid, long flun, long prec) { pari_timer T; pari_sp av0 = avma, av, av2; long PRECREG, N, R1, R2, RU, low, high, LIMC0, LIMC, LIMC2, LIMCMAX, zc, i; long LIMres, bit; long MAXDEPSIZESFB, MAXDEPSFB; long nreldep, sfb_trials, need, old_need, precdouble = 0, precadd = 0; long done_small, small_fail, fail_limit, squash_index, small_norm_prec; long flag_nfinit = 0; double LOGD, LOGD2, lim; GEN computed = NULL, zu, nf, M_sn, D, A, W, R, h, PERM, fu = NULL /*-Wall*/; GEN small_multiplier; GEN res, L, invhr, B, C, C0, lambda, dep, clg1, clg2, Vbase; GEN auts, cyclic; const char *precpb = NULL; int FIRST = 1, class1 = 0; nfmaxord_t nfT; RELCACHE_t cache; FB_t F; GRHcheck_t GRHcheck; FACT *fact; if (DEBUGLEVEL) timer_start(&T); P = get_nfpol(P, &nf); if (nf) { PRECREG = nf_get_prec(nf); D = nf_get_disc(nf); } else { PRECREG = maxss(prec, MEDDEFAULTPREC); nfinit_basic(&nfT, P); D = nfT.dK; if (!ZX_is_monic(nfT.T0)) { pari_warn(warner,"non-monic polynomial in bnfinit, using polredbest"); flag_nfinit = nf_RED; } } N = degpol(P); if (N <= 1) { if (!nf) nf = nfinit_complete(&nfT, flag_nfinit, PRECREG); return gerepilecopy(av0, Buchall_deg1(nf)); } D = absi_shallow(D); LOGD = dbllog2(D) * M_LN2; LOGD2 = LOGD*LOGD; LIMCMAX = (long)(12.*LOGD2); /* In small_norm, LLL reduction produces v0 in I such that * T2(v0) <= (4/3)^((n-1)/2) NI^(2/n) disc(K)^(1/n) * We consider v with T2(v) <= BMULT * T2(v0) * Hence Nv <= ((4/3)^((n-1)/2) * BMULT / n)^(n/2) NI sqrt(disc(K)). * NI <= LIMCMAX^2 */ small_norm_prec = nbits2prec( BITS_IN_LONG + (N/2. * ((N-1)/2.*log(4./3) + log(BMULT/(double)N)) + 2*log((double) LIMCMAX) + LOGD/2) / M_LN2 ); /* enough to compute norms */ if (small_norm_prec > PRECREG) PRECREG = small_norm_prec; if (!nf) nf = nfinit_complete(&nfT, flag_nfinit, PRECREG); else if (nf_get_prec(nf) < PRECREG) nf = nfnewprec_shallow(nf, PRECREG); M_sn = nf_get_M(nf); if (PRECREG > small_norm_prec) M_sn = gprec_w(M_sn, small_norm_prec); zu = rootsof1(nf); gel(zu,2) = nf_to_scalar_or_alg(nf, gel(zu,2)); auts = automorphism_matrices(nf, &F.invs, &cyclic); F.embperm = automorphism_perms(nf_get_M(nf), auts, cyclic, N); nf_get_sign(nf, &R1, &R2); RU = R1+R2; compute_vecG(nf, &F, minss(RU, 9)); if (DEBUGLEVEL) { timer_printf(&T, "nfinit & rootsof1"); err_printf("R1 = %ld, R2 = %ld\nD = %Ps\n",R1,R2, D); } if (LOGD < 20.) /* tiny disc, Minkowski *may* be smaller than Bach */ { lim = exp(-N + R2 * log(4/M_PI) + LOGD/2) * sqrt(2*M_PI*N); if (lim < 3) lim = 3; } else /* to be ignored */ lim = -1; if (cbach > 12.) { if (cbach2 < cbach) cbach2 = cbach; cbach = 12.; } if (cbach < 0.) pari_err_DOMAIN("Buchall","Bach constant","<",gen_0,dbltor(cbach)); cache.base = NULL; F.subFB = NULL; F.LP = NULL; init_GRHcheck(&GRHcheck, N, R1, LOGD); high = low = LIMC0 = maxss((long)(cbach2*LOGD2), 1); while (!GRHchk(nf, &GRHcheck, high)) { low = high; high *= 2; } while (high - low > 1) { long test = (low+high)/2; if (GRHchk(nf, &GRHcheck, test)) high = test; else low = test; } if (high == LIMC0+1 && GRHchk(nf, &GRHcheck, LIMC0)) LIMC2 = LIMC0; else LIMC2 = high; if (LIMC2 > LIMCMAX) LIMC2 = LIMCMAX; if (DEBUGLEVEL) err_printf("LIMC2 = %ld\n", LIMC2); if (LIMC2 < nthideal(&GRHcheck, nf, 1)) class1 = 1; if (DEBUGLEVEL && class1) err_printf("Class 1\n", LIMC2); LIMC0 = (long)(cbach*LOGD2); LIMC = cbach ? LIMC0 : LIMC2; LIMC = maxss(LIMC, nthideal(&GRHcheck, nf, N)); if (DEBUGLEVEL) timer_printf(&T, "computing Bach constant"); LIMres = primeneeded(N, R1, R2, LOGD); cache_prime_dec(&GRHcheck, LIMres, nf); /* invhr ~ 2^r1 (2pi)^r2 / sqrt(D) w * Res(zeta_K, s=1) = 1 / hR */ invhr = gmul(gdiv(gmul2n(powru(mppi(DEFAULTPREC), R2), RU), mulri(gsqrt(D,DEFAULTPREC),gel(zu,1))), compute_invres(&GRHcheck, LIMres)); if (DEBUGLEVEL) timer_printf(&T, "computing inverse of hR"); av = avma; START: if (DEBUGLEVEL) timer_start(&T); if (!FIRST) LIMC = bnf_increase_LIMC(LIMC,LIMCMAX); if (DEBUGLEVEL && LIMC > LIMC0) err_printf("%s*** Bach constant: %f\n", FIRST?"":"\n", LIMC/LOGD2); if (cache.base) { REL_t *rel; for (i = 1, rel = cache.base + 1; rel < cache.last; rel++) if (rel->m) i++; computed = cgetg(i, t_VEC); for (i = 1, rel = cache.base + 1; rel < cache.last; rel++) if (rel->m) gel(computed, i++) = rel->m; computed = gclone(computed); delete_cache(&cache); } FIRST = 0; avma = av; if (F.LP) delete_FB(&F); if (LIMC2 < LIMC) LIMC2 = LIMC; if (DEBUGLEVEL) { err_printf("LIMC = %ld, LIMC2 = %ld\n",LIMC,LIMC2); } FBgen(&F, nf, N, LIMC, LIMC2, &GRHcheck); if (!F.KC) goto START; av = avma; subFBgen(&F,auts,cyclic,lim < 0? LIMC2: mindd(lim,LIMC2),MINSFB); if (DEBUGLEVEL) { if (lg(F.subFB) > 1) timer_printf(&T, "factorbase (#subFB = %ld) and ideal permutations", lg(F.subFB)-1); else timer_printf(&T, "factorbase (no subFB) and ideal permutations"); } fact = (FACT*)stack_malloc((F.KC+1)*sizeof(FACT)); PERM = leafcopy(F.perm); /* to be restored in case of precision increase */ cache.basis = zero_Flm_copy(F.KC,F.KC); small_multiplier = zero_Flv(F.KC); F.id2 = zerovec(F.KC); MAXDEPSIZESFB = (lg(F.subFB) - 1) * DEPSIZESFBMULT; MAXDEPSFB = MAXDEPSIZESFB / DEPSFBDIV; done_small = 0; small_fail = 0; squash_index = 0; fail_limit = F.KC + 1; R = NULL; A = NULL; av2 = avma; init_rel(&cache, &F, RELSUP + RU-1); /* trivial relations */ old_need = need = cache.end - cache.last; add_cyclotomic_units(nf, zu, &cache, &F); cache.end = cache.last + need; W = NULL; zc = 0; sfb_trials = nreldep = 0; if (computed) { for (i = 1; i < lg(computed); i++) try_elt(&cache, &F, nf, gel(computed, i), fact); if (isclone(computed)) gunclone(computed); if (DEBUGLEVEL && i > 1) { err_printf("\n"); timer_printf(&T, "including already computed relations"); } need = 0; } do { do { pari_sp av4 = avma; if (need > 0) { long oneed = cache.end - cache.last; /* Test below can be true if small_norm did not find enough linearly * dependent relations */ if (need < oneed) need = oneed; pre_allocate(&cache, need+lg(auts)-1+(R ? lg(W)-1 : 0)); cache.end = cache.last + need; F.L_jid = trim_list(&F); } if (need > 0 && nbrelpid > 0 && (done_small <= F.KC+1 || A) && small_fail <= fail_limit && cache.last < cache.base + 2*F.KC+2*RU+RELSUP /* heuristic */) { pari_sp av3 = avma; GEN p0 = NULL; long j, k; REL_t *last = cache.last; if (R && lg(W) > 1 && (done_small % 2)) { /* We have full rank for class group and unit, however those * lattices are too small. The following tries to improve the * prime group lattice: it specifically looks for relations * involving the primes generating the class group. */ long l = lg(W) - 1; /* We need lg(W)-1 relations to squash the class group. */ F.L_jid = vecslice(F.perm, 1, l); cache.end = cache.last + l; /* Lie to the add_rel subsystem: pretend we miss relations involving * the primes generating the class group (and only those). */ cache.missing = l; for ( ; l > 0; l--) mael(cache.basis, F.perm[l], F.perm[l]) = 0; } j = done_small % (F.KC+1); if (j) { long mj = small_multiplier[j]; p0 = gel(F.LP, j); if (!A) { /* Prevent considering both P_iP_j and P_jP_i in small_norm */ /* Since not all elements end up in F.L_jid (because they can * be eliminated by hnfspec/add or by trim_list, keep track * of which ideals are being considered at each run. */ for (i = k = 1; i < lg(F.L_jid); i++) if (F.L_jid[i] > mj) { small_multiplier[F.L_jid[i]] = j; F.L_jid[k++] = F.L_jid[i]; } setlg(F.L_jid, k); } } if (lg(F.L_jid) > 1) small_norm(&cache, &F, nf, nbrelpid, M_sn, fact, p0); avma = av3; if (!A && cache.last != last) small_fail = 0; else small_fail++; if (R && lg(W) > 1 && (done_small % 2)) { long l = lg(W) - 1; for ( ; l > 0; l--) mael(cache.basis, F.perm[l], F.perm[l]) = 1; cache.missing = 0; } F.L_jid = F.perm; need = 0; cache.end = cache.last; done_small++; F.sfb_chg = 0; } if (need > 0) { /* Random relations */ if (lg(F.subFB) == 1) goto START; nreldep++; if (nreldep > MAXDEPSIZESFB) { if (++sfb_trials > SFB_MAX && LIMC < LIMCMAX/6) goto START; F.sfb_chg = sfb_INCREASE; nreldep = 0; } else if (!(nreldep % MAXDEPSFB)) F.sfb_chg = sfb_CHANGE; if (F.newpow) { F.sfb_chg = 0; if (DEBUGLEVEL) err_printf("\n"); } if (F.sfb_chg && !subFB_change(&F)) goto START; if (F.newpow) { powFBgen(&cache, &F, nf, auts); MAXDEPSIZESFB = (lg(F.subFB) - 1) * DEPSIZESFBMULT; MAXDEPSFB = MAXDEPSIZESFB / DEPSFBDIV; if (DEBUGLEVEL) timer_printf(&T, "powFBgen"); } if (!F.sfb_chg) rnd_rel(&cache, &F, nf, fact); F.L_jid = F.perm; } if (DEBUGLEVEL) timer_start(&T); if (precpb) { GEN nf0 = nf; if (precadd) { PRECREG += precadd; precadd = 0; } else PRECREG = precdbl(PRECREG); if (DEBUGLEVEL) { char str[64]; sprintf(str,"Buchall_param (%s)",precpb); pari_warn(warnprec,str,PRECREG); } nf = gclone( nfnewprec_shallow(nf, PRECREG) ); if (precdouble) gunclone(nf0); precdouble++; precpb = NULL; for (i = 1; i < lg(PERM); i++) F.perm[i] = PERM[i]; cache.chk = cache.base; W = NULL; /* recompute arch components+reduce */ } avma = av4; if (cache.chk != cache.last) { /* Reduce relation matrices */ long l = cache.last - cache.chk + 1, j; GEN M = nf_get_M(nf), mat = cgetg(l, t_MAT), emb = cgetg(l, t_MAT); int first = (W == NULL); /* never reduced before */ REL_t *rel; for (j=1,rel = cache.chk + 1; j < l; rel++,j++) { gel(mat,j) = rel->R; if (!rel->relaut) gel(emb,j) = get_log_embed(rel, M, RU, R1, PRECREG); else gel(emb,j) = perm_log_embed(gel(emb, j-rel->relorig), gel(F.embperm, rel->relaut)); } if (DEBUGLEVEL) timer_printf(&T, "floating point embeddings"); if (first) { C = emb; W = hnfspec_i(mat, F.perm, &dep, &B, &C, F.subFB ? lg(F.subFB)-1:0); } else W = hnfadd_i(W, F.perm, &dep, &B, &C, mat, emb); gerepileall(av2, 4, &W,&C,&B,&dep); cache.chk = cache.last; if (DEBUGLEVEL) { if (first) timer_printf(&T, "hnfspec [%ld x %ld]", lg(F.perm)-1, l-1); else timer_printf(&T, "hnfadd (%ld + %ld)", l-1, lg(dep)-1); } } else if (!W) { need = old_need; F.L_jid = vecslice(F.perm, 1, need); continue; } need = F.KC - (lg(W)-1) - (lg(B)-1); /* FIXME: replace by err(e_BUG,"") */ if (!need && cache.missing) { /* The test above will never be true except if 27449|class number, * but the code implicitely assumes that if we have maximal rank * for the ideal lattice, then cache.missing == 0. */ for (i = 1; cache.missing; i++) if (!mael(cache.basis, i, i)) { long j; mael(cache.basis, i, i) = 1; cache.missing--; for (j = i+1; j <= F.KC; j++) mael(cache.basis, j, i) = 0; } } zc = (lg(C)-1) - (lg(B)-1) - (lg(W)-1); if (zc < RU-1) { /* need more columns for units */ need += RU-1 - zc; if (need > F.KC) need = F.KC; } if (need) { /* dependent rows */ F.L_jid = vecslice(F.perm, 1, need); vecsmall_sort(F.L_jid); if (need != old_need) nreldep = 0; old_need = need; } else { /* If the relation lattice is too small, check will be > 1 and we * will do a new run of small_norm/rnd_rel asking for 1 relation. * However they tend to give a relation involving the first element * of L_jid. We thus permute which element is the first of L_jid in * order to increase the probability of finding a good relation, i.e. * one that increases the relation lattice. */ if (lg(W) > 2 && squash_index % (lg(W) - 1)) { long j, l = lg(W) - 1; F.L_jid = leafcopy(F.perm); for (j = 1; j <= l; j++) F.L_jid[j] = F.perm[1 + (j + squash_index - 1) % l]; } else F.L_jid = F.perm; squash_index++; } } while (need); if (!A) { small_fail = 0; fail_limit = maxss(F.KC / FAIL_DIVISOR, MINFAIL); old_need = 0; } A = vecslice(C, 1, zc); /* cols corresponding to units */ bit = bit_accuracy(PRECREG); R = compute_multiple_of_R(A, RU, N, &need, &bit, &lambda); if (need < old_need) small_fail = 0; old_need = need; if (!lambda) { precpb = "bestappr"; continue; } if (!R) { /* not full rank for units */ if (DEBUGLEVEL) err_printf("regulator is zero.\n"); if (!need) precpb = "regulator"; continue; } h = ZM_det_triangular(W); if (DEBUGLEVEL) err_printf("\n#### Tentative class number: %Ps\n", h); switch (compute_R(lambda, RU, mulir(h,invhr), RgM_bit(C, bit), &L, &R)) { case fupb_RELAT: need = 1; /* not enough relations */ continue; case fupb_PRECI: /* prec problem unless we cheat on Bach constant */ if ((precdouble&7) == 7 && LIMC<=LIMCMAX/6) goto START; precpb = "compute_R"; continue; } /* DONE */ if (F.KCZ2 > F.KCZ) { if (F.sfb_chg && !subFB_change(&F)) goto START; if (!be_honest(&F, nf, auts, fact)) goto START; if (DEBUGLEVEL) timer_printf(&T, "to be honest"); } F.KCZ2 = 0; /* be honest only once */ /* fundamental units */ { pari_sp av3 = avma; GEN AU, U, H, v = extract_full_lattice(L); /* L may be very large */ long e; if (v) { A = vecpermute(A, v); L = vecpermute(L, v); } /* arch. components of fund. units */ H = ZM_hnflll(L, &U, 1); U = vecslice(U, lg(U)-(RU-1), lg(U)-1); U = ZM_mul(U, ZM_lll(H, 0.99, LLL_IM|LLL_COMPATIBLE)); AU = RgM_mul(A, U); A = cleanarch(AU, N, PRECREG); if (DEBUGLEVEL) timer_printf(&T, "cleanarch"); if (!A) { precadd = nbits2extraprec( gexpo(AU) + 64 ) - gprecision(AU); if (precadd <= 0) precadd = 1; precpb = "cleanarch"; continue; } fu = getfu(nf, &A, &e, PRECREG); if (DEBUGLEVEL) timer_printf(&T, "getfu"); if (!fu && (flun & nf_FORCE)) { /* units not found but we want them */ if (e > 0) pari_err_OVERFLOW("bnfinit [fundamental units too large]"); if (e < 0) precadd = nbits2extraprec( (-e - (BITS_IN_LONG - 1)) + 64); avma = av3; precpb = "getfu"; continue; } } /* class group generators */ i = lg(C)-zc; C += zc; C[0] = evaltyp(t_MAT)|evallg(i); C0 = C; C = cleanarch(C, N, PRECREG); if (!C) { precadd = nbits2extraprec( gexpo(C0) + 64 ) - gprecision(C0); if (precadd <= 0) precadd = 1; precpb = "cleanarch"; } } while (need || precpb); delete_cache(&cache); delete_FB(&F); free_GRHcheck(&GRHcheck); Vbase = vecpermute(F.LP, F.perm); class_group_gen(nf,W,C,Vbase,PRECREG,NULL, &clg1, &clg2); res = get_clfu(clg1, R, zu, fu); res = buchall_end(nf,res,clg2,W,B,A,C,Vbase); res = gerepilecopy(av0, res); if (precdouble) gunclone(nf); return res; } pari-2.11.2/src/basemath/ellsea.c0000644000175000017500000017274413326135265015167 0ustar billbill/* Copyright (C) 2008 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file is a C version by Bill Allombert of the 'ellsea' GP package * whose copyright statement is as follows: Authors: Christophe Doche Sylvain Duquesne Universite Bordeaux I, Laboratoire A2X For the AREHCC project, see http://www.arehcc.com/ Contributors: Karim Belabas (code cleanup and package release, faster polynomial arithmetic) 'ellsea' is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. */ /* Extension to non prime finite fields by Bill Allombert 2012 */ #include "pari.h" #include "paripriv.h" static GEN global_modular_eqn; static THREAD GEN modular_eqn; void pari_init_seadata(void) { global_modular_eqn = NULL; } void pari_thread_init_seadata(void) { modular_eqn = global_modular_eqn; } void pari_pthread_init_seadata(void) { global_modular_eqn = modular_eqn; } static char * seadata_filename(ulong ell) { return stack_sprintf("%s/seadata/sea%ld", pari_datadir, ell); } static GEN get_seadata(ulong ell) { pari_sp av = avma; GEN eqn; char *s = seadata_filename(ell); pariFILE *F = pari_fopengz(s); if (!F) return NULL; if (ell) /* large single polynomial */ eqn = gp_read_stream(F->file); else { /* table of polynomials of small level */ eqn = gp_readvec_stream(F->file); modular_eqn = eqn = gclone(eqn); avma = av; } pari_fclose(F); return eqn; } /*Builds the modular equation corresponding to the vector list. Shallow */ static GEN list_to_pol(GEN list, long vx, long vy) { long i, l = lg(list); GEN P = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN L = gel(list,i); if (typ(L) == t_VEC) L = RgV_to_RgX_reverse(L, vy); gel(P, i) = L; } return RgV_to_RgX_reverse(P, vx); } struct meqn { char type; GEN eq, eval; long vx,vy; }; static GEN seadata_cache(ulong ell) { long n = uprimepi(ell)-1; GEN C; if (!modular_eqn && !get_seadata(0)) C = NULL; else if (n && n < lg(modular_eqn)) C = gel(modular_eqn, n); else C = get_seadata(ell); return C; } /* C = [prime level, type "A" or "C", pol. coeffs] */ static void seadata_parse(struct meqn *M, GEN C, long vx, long vy) { M->type = *GSTR(gel(C,2)); M->eq = list_to_pol(gel(C,3), vx, vy); } static void get_modular_eqn(struct meqn *M, ulong ell, long vx, long vy) { GEN C = seadata_cache(ell); M->vx = vx; M->vy = vy; M->eval = gen_0; if (C) seadata_parse(M, C, vx, vy); else { M->type = 'J'; /* j^(1/3) for ell != 3, j for 3 */ M->eq = polmodular_ZXX(ell, ell==3? 0: 5, vx, vy); } } GEN ellmodulareqn(long ell, long vx, long vy) { pari_sp av = avma; struct meqn meqn; GEN C; if (vx < 0) vx = 0; if (vy < 0) vy = 1; if (varncmp(vx,vy) >= 0) pari_err_PRIORITY("ellmodulareqn", pol_x(vx), ">=", vy); if (ell < 2 || !uisprime(ell)) pari_err_PRIME("ellmodulareqn (level)", stoi(ell)); C = seadata_cache(ell); if (!C) pari_err_FILE("seadata file", seadata_filename(ell)); seadata_parse(&meqn, C, vx, vy); return gerepilecopy(av, mkvec2(meqn.eq, meqn.type=='A'? gen_1: gen_0)); } /***********************************************************************/ /** **/ /** n-division polynomial **/ /** **/ /***********************************************************************/ static GEN divpol(GEN t, GEN r2, long n, void *E, const struct bb_algebra *ff); static GEN divpol_f2(GEN t, GEN r2, long n, void *E, const struct bb_algebra *ff) { if (n==0) return ff->zero(E); if (n<=2) return ff->one(E); if (gmael(t,2,n)) return gmael(t,2,n); gmael(t,2,n) = gclone(ff->sqr(E,divpol(t,r2,n,E,ff))); return gmael(t,2,n); } static GEN divpol_ff(GEN t, GEN r2, long n, void *E, const struct bb_algebra *ff) { if (n<=2) return ff->zero(E); if (gmael(t,3,n)) return gmael(t,3,n); if (n<=4) return divpol(t,r2,n,E,ff); gmael(t,3,n) = gclone(ff->mul(E,divpol(t,r2,n,E,ff), divpol(t,r2,n-2,E,ff))); return gmael(t,3,n); } static GEN divpol(GEN t, GEN r2, long n, void *E, const struct bb_algebra *ff) { long m = n/2; pari_sp av = avma; GEN res; if (n==0) return ff->zero(E); if (gmael(t,1,n)) return gmael(t,1,n); switch(n) { case 1: case 2: res = ff->one(E); break; default: if (odd(n)) if (odd(m)) res = ff->sub(E, ff->mul(E, divpol_ff(t,r2,m+2,E,ff), divpol_f2(t,r2,m,E,ff)), ff->mul(E, r2, ff->mul(E,divpol_ff(t,r2,m+1,E,ff), divpol_f2(t,r2,m+1,E,ff)))); else res = ff->sub(E, ff->mul(E, r2, ff->mul(E, divpol_ff(t,r2,m+2,E,ff), divpol_f2(t,r2,m,E,ff))), ff->mul(E, divpol_ff(t,r2,m+1,E,ff), divpol_f2(t,r2,m+1,E,ff))); else res = ff->sub(E, ff->mul(E, divpol_ff(t,r2,m+2,E,ff), divpol_f2(t,r2,m-1,E,ff)), ff->mul(E, divpol_ff(t,r2,m,E,ff), divpol_f2(t,r2,m+1,E,ff))); } res = ff->red(E, res); gmael(t,1,n) = gclone(res); avma = av; return gmael(t,1,n); } static void divpol_free(GEN t) { long i, l = lg(gel(t,1)); for (i=1; iff = ff; d->E = E; d->t = mkvec3(const_vec(k, NULL),const_vec(k, NULL),const_vec(k, NULL)); if (k>=3) gmael(d->t,1,3) = gclone(D3); if (k>=4) gmael(d->t,1,4) = gclone(D4); d->r2 = ff->sqr(E, RHS); } static void Fq_elldivpolmod_init(struct divpolmod_red *d, GEN a4, GEN a6, long n, GEN h, GEN T, GEN p) { void *E; const struct bb_algebra *ff; GEN RHS, D3 = NULL, D4 = NULL; long v = h ? get_FpXQX_var(h): 0; D3 = n>=0 ? Fq_elldivpol34(3, a4, a6, h, T, p): NULL; D4 = n>=1 ? Fq_elldivpol34(4, a4, a6, h, T, p): NULL; RHS = rhs(a4, a6, v); RHS = h ? FqX_rem(RHS, h, T, p): RHS; RHS = FqX_mulu(RHS, 4, T, p); ff = h ? T ? get_FpXQXQ_algebra(&E, h, T, p): get_FpXQ_algebra(&E, h, p): T ? get_FpXQX_algebra(&E, T, p, v): get_FpX_algebra(&E, p, v); divpolmod_init(d, D3, D4, RHS, n, E, ff); } static void Flxq_elldivpolmod_init(struct divpolmod_red *d, GEN a4, GEN a6, long n, GEN h, GEN T, ulong p) { void *E; const struct bb_algebra *ff; GEN RHS, D3 = NULL, D4 = NULL; long v = get_FlxqX_var(h), vT = get_Flx_var(T); D3 = n>=0 ? Flxq_elldivpol34(3, a4, a6, h, T, p): NULL; D4 = n>=1 ? Flxq_elldivpol34(4, a4, a6, h, T, p): NULL; RHS = FlxX_Fl_mul(FlxqX_rem(Flxq_rhs(a4, a6, v, vT), h, T, p), 4, p); ff = get_FlxqXQ_algebra(&E, h, T, p); divpolmod_init(d, D3, D4, RHS, n, E, ff); } /*Computes the n-division polynomial modulo the polynomial h \in Fq[x] */ GEN Fq_elldivpolmod(GEN a4, GEN a6, long n, GEN h, GEN T, GEN p) { struct divpolmod_red d; pari_sp ltop = avma; GEN res; Fq_elldivpolmod_init(&d, a4, a6, n, h, T, p); res = gcopy(divpol(d.t,d.r2,n,d.E,d.ff)); divpol_free(d.t); return gerepileupto(ltop, res); } GEN FpXQ_elldivpol(GEN a4, GEN a6, long n, GEN T, GEN p) { return Fq_elldivpolmod(a4,a6,n,NULL,T,p); } GEN Fp_elldivpol(GEN a4, GEN a6, long n, GEN p) { return Fq_elldivpolmod(a4,a6,n,NULL,NULL,p); } static GEN Fq_ellyn(struct divpolmod_red *d, long k) { pari_sp av = avma; void *E = d->E; const struct bb_algebra *ff = d->ff; if (k==1) return mkvec2(ff->one(E), ff->one(E)); else { GEN t = d->t, r2 = d->r2; GEN pn2 = divpol(t,r2,k-2,E,ff); GEN pp2 = divpol(t,r2,k+2,E,ff); GEN pn12 = divpol_f2(t,r2,k-1,E,ff); GEN pp12 = divpol_f2(t,r2,k+1,E,ff); GEN on = ff->red(E,ff->sub(E, ff->mul(E,pp2,pn12), ff->mul(E,pn2,pp12))); GEN f = divpol(t,r2,k,E,ff); GEN f2 = divpol_f2(t,r2,k,E,ff); GEN f3 = ff->mul(E,f,f2); if (!odd(k)) f3 = ff->mul(E,f3,r2); return gerepilecopy(av,mkvec2(on, f3)); } } static void Fq_elldivpolmod_close(struct divpolmod_red *d) { divpol_free(d->t); } static GEN Fq_elldivpol2(GEN a4, GEN a6, GEN T, GEN p) { return mkpoln(4, utoi(4), gen_0, Fq_mulu(a4, 4, T, p), Fq_mulu(a6, 4, T, p)); } static GEN Fq_elldivpol2d(GEN a4, GEN T, GEN p) { return mkpoln(3, utoi(6), gen_0, Fq_mulu(a4, 2, T, p)); } static GEN FqX_numer_isog_abscissa(GEN h, GEN a4, GEN a6, GEN T, GEN p, long vx) { GEN mp1, dh, ddh, t, u, t1, t2, t3, t4, f0; long m = degpol(h); mp1 = gel(h, m + 1); /* negative of first power sum */ dh = FqX_deriv(h, T, p); ddh = FqX_deriv(dh, T, p); t = Fq_elldivpol2(a4, a6, T, p); u = Fq_elldivpol2d(a4, T, p); t1 = FqX_sub(FqX_sqr(dh, T, p), FqX_mul(ddh, h, T, p), T, p); t2 = FqX_mul(u, FqX_mul(h, dh, T, p), T, p); t3 = FqX_mul(FqX_sqr(h, T, p), deg1pol_shallow(stoi(2*m), Fq_mulu(mp1, 2, T, p), vx), T, p); f0 = FqX_add(FqX_sub(FqX_mul(t, t1, T, p), t2, T, p), t3, T, p); t4 = FqX_mul(pol_x(vx), FqX_sqr(h, T, p), T, p); return FqX_add(t4, f0, T, p); } static GEN Zq_inv(GEN b, GEN T, GEN q, GEN p, long e) { return e==1 ? Fq_inv(b, T, p): typ(b)==t_INT ? Fp_inv(b, q): ZpXQ_inv(b, T, p, e); } static GEN Zq_div(GEN a, GEN b, GEN T, GEN q, GEN p, long e) { if (e==1) return Fq_div(a, b, T, q); return Fq_mul(a, Zq_inv(b, T, q, p, e), T, q); } static GEN Zq_sqrt(GEN b, GEN T, GEN q, GEN p, long e) { return e==1 ? Fq_sqrt(b, T, q): typ(b)==t_INT ? Zp_sqrt(b, p, e): ZpXQ_sqrt(b, T, p, e); } static GEN Zq_divexact(GEN a, GEN b) { return typ(a)==t_INT ? diviiexact(a, b): ZX_Z_divexact(a, b); } static long Zq_pval(GEN a, GEN p) { return typ(a)==t_INT ? Z_pval(a, p): ZX_pval(a, p); } static GEN Zq_Z_div_safe(GEN a, GEN b, GEN T, GEN q, GEN p, long e) { long v; if (e==1) return Fq_div(a, b, T, q); v = Z_pvalrem(b, p, &b); if (v>0) { long w = Z_pval(Q_content(a), p); if (v>w) pari_err_INV("Zq_div",b); a = Zq_divexact(a, powiu(p,v)); } return Fq_Fp_mul(a, Fp_inv(b, q), T, q); } /*Gives the first precS terms of the Weierstrass series related to */ /*E: y^2 = x^3 + a4x + a6. Assumes (precS-2)*(2precS+3) < ULONG_MAX, i.e. * precS < 46342 in 32-bit machines */ static GEN find_coeff(GEN a4, GEN a6, GEN T, GEN p, long precS, GEN pp, long e) { GEN res, den; long k, h; if (e > 1) { p = sqri(p); e *= 2; } res = cgetg(precS+1, t_VEC); den = cgetg(precS+1, t_VECSMALL); if (precS == 0) return res; gel(res, 1) = Fq_div(a4, stoi(-5), T, p); den[1] = 0; if (precS == 1) return res; gel(res, 2) = Fq_div(a6, stoi(-7), T, p); den[2] = 0; for (k = 3; k <= precS; ++k) { pari_sp btop = avma; GEN a = gen_0, d; long v=0; if (e > 1) for (h = 1; h <= k-2; h++) v = maxss(v, den[h]+den[k-1-h]); for (h = 1; h <= k-2; h++) { GEN b = Fq_mul(gel(res, h), gel(res, k-1-h), T, p); if (v) b = Fq_Fp_mul(b, powiu(pp, v-(den[h]+den[k-1-h])), T, p); a = Fq_add(a, b, T, p); } v += Z_pvalrem(utoi((k-2) * (2*k + 3)), pp, &d); a = Zq_div(gmulgs(a, 3), d, T, p, pp, e); gel(res, k) = gerepileupto(btop, a); den[k] = v; } return mkvec2(res, den); } /****************************************************************************/ /* SIMPLE ELLIPTIC CURVE OVER Fq */ /****************************************************************************/ static GEN Fq_ellj(GEN a4, GEN a6, GEN T, GEN p) { pari_sp ltop=avma; GEN a43 = Fq_mulu(Fq_powu(a4, 3, T, p), 4, T, p); GEN j = Fq_div(Fq_mulu(a43, 1728, T, p), Fq_add(a43, Fq_mulu(Fq_sqr(a6, T, p), 27, T, p), T, p), T, p); return gerepileupto(ltop, j); } static GEN Zq_ellj(GEN a4, GEN a6, GEN T, GEN p, GEN pp, long e) { pari_sp ltop=avma; GEN a43 = Fq_mulu(Fq_powu(a4, 3, T, p), 4, T, p); GEN j = Zq_div(Fq_mulu(a43, 1728, T, p), Fq_add(a43, Fq_mulu(Fq_sqr(a6, T, p), 27, T, p), T, p), T, p, pp, e); return gerepileupto(ltop, j); } /****************************************************************************/ /* EIGENVALUE */ /****************************************************************************/ static GEN Fq_to_Flx(GEN a4, GEN T, ulong p) { return typ(a4)==t_INT ? Z_to_Flx(a4, p, get_Flx_var(T)): ZX_to_Flx(a4, p); } static GEN Flxq_find_eigen_Frobenius(GEN a4, GEN a6, GEN h, GEN T, ulong p) { long v = get_FlxqX_var(h), vT = get_Flx_var(T); GEN RHS = FlxqX_rem(Flxq_rhs(a4, a6, v, vT), h, T, p); return FlxqXQ_halfFrobenius(RHS, h, T, p); } static GEN Fq_find_eigen_Frobenius(GEN a4, GEN a6, GEN h, GEN T, GEN p) { long v = T ? get_FpXQX_var(h): get_FpX_var(h); GEN RHS = FqX_rem(rhs(a4, a6, v), h, T, p); return T ? FpXQXQ_halfFrobenius(RHS, h, T, p): FpXQ_pow(RHS, shifti(p, -1), h, p); } /*Finds the eigenvalue of the Frobenius given E, ell odd prime, h factor of the *ell-division polynomial, p and tr the possible values for the trace *(useful for primes with one root)*/ static ulong find_eigen_value_oneroot(GEN a4, GEN a6, ulong ell, GEN tr, GEN h, GEN T, GEN p) { pari_sp ltop = avma; ulong t; struct divpolmod_red d; GEN f, Dy, Gy; h = FqX_get_red(h, T, p); Gy = Fq_find_eigen_Frobenius(a4, a6, h, T, p); t = Fl_div(tr[1], 2, ell); if (t < (ell>>1)) t = ell - t; Fq_elldivpolmod_init(&d, a4, a6, t, h, T, p); f = Fq_ellyn(&d, t); Dy = FqXQ_mul(Gy, gel(f,2), h, T, p); if (!gequal(gel(f,1), Dy)) t = ell-t; Fq_elldivpolmod_close(&d); avma = ltop; return t; } static ulong Flxq_find_eigen_value_power(GEN a4, GEN a6, ulong ell, long k, ulong lambda, GEN h, GEN T, ulong p) { pari_sp ltop = avma; ulong t, ellk1 = upowuu(ell, k-1), ellk = ell*ellk1; pari_timer ti; struct divpolmod_red d; GEN Gy; timer_start(&ti); h = FlxqX_get_red(h, T, p); Gy = Flxq_find_eigen_Frobenius(a4, a6, h, T, p); if (DEBUGLEVEL>2) err_printf(" (%ld ms)",timer_delay(&ti)); Flxq_elldivpolmod_init(&d, a4, a6, ellk, h, T, p); for (t = lambda; t < ellk; t += ellk1) { GEN f = Fq_ellyn(&d, t); GEN Dr = FlxqXQ_mul(Gy, gel(f,2), h, T, p); if (varn(gel(f,1))!=varn(Dr)) pari_err_BUG("find_eigen_value_power"); if (gequal(gel(f,1), Dr)) break; if (gequal(gel(f,1), FlxX_neg(Dr,p))) { t = ellk-t; break; } } if (DEBUGLEVEL>2) err_printf(" (%ld ms)",timer_delay(&ti)); Fq_elldivpolmod_close(&d); avma = ltop; return t; } /*Finds the eigenvalue of the Frobenius modulo ell^k given E, ell, k, h factor *of the ell-division polynomial, lambda the previous eigen value and p */ static ulong Fq_find_eigen_value_power(GEN a4, GEN a6, ulong ell, long k, ulong lambda, GEN h, GEN T, GEN p) { pari_sp ltop = avma; ulong t, ellk1 = upowuu(ell, k-1), ellk = ell*ellk1; pari_timer ti; struct divpolmod_red d; GEN Gy; timer_start(&ti); h = FqX_get_red(h, T, p); Gy = Fq_find_eigen_Frobenius(a4, a6, h, T, p); if (DEBUGLEVEL>2) err_printf(" (%ld ms)",timer_delay(&ti)); Fq_elldivpolmod_init(&d, a4, a6, ellk, h, T, p); for (t = lambda; t < ellk; t += ellk1) { GEN f = Fq_ellyn(&d, t); GEN Dr = FqXQ_mul(Gy, gel(f,2), h, T, p); if (varn(gel(f,1))!=varn(Dr)) pari_err_BUG("find_eigen_value_power"); if (gequal(gel(f,1), Dr)) break; if (gequal(gel(f,1), FqX_neg(Dr,T,p))) { t = ellk-t; break; } } if (DEBUGLEVEL>2) err_printf(" (%ld ms)",timer_delay(&ti)); Fq_elldivpolmod_close(&d); avma = ltop; return t; } static ulong find_eigen_value_power(GEN a4, GEN a6, ulong ell, long k, ulong lambda, GEN hq, GEN T, GEN p) { ulong pp = itou_or_0(p); if (pp && T) { GEN a4p = ZX_to_Flx(a4, pp); GEN a6p = ZX_to_Flx(a6, pp); GEN hp = ZXXT_to_FlxXT(hq, pp,varn(a4)); GEN Tp = ZXT_to_FlxT(T, pp); return Flxq_find_eigen_value_power(a4p, a6p, ell, k, lambda, hp, Tp, pp); } return Fq_find_eigen_value_power(a4, a6, ell, k, lambda, hq, T, p); } /*Finds the kernel polynomial h, dividing the ell-division polynomial from the isogenous curve Eb and trace term pp1. Uses CCR algorithm and returns h. Return NULL if E and Eb are *not* isogenous. */ static GEN find_kernel(GEN a4, GEN a6, ulong ell, GEN a4t, GEN a6t, GEN pp1, GEN T, GEN p, GEN pp, long e) { const long ext = 2; pari_sp ltop = avma, btop; GEN P, v, tlist, h; long i, j, k; long deg = (ell - 1)/2, dim = 2 + deg + ext; GEN psi2 = Fq_elldivpol2(a4, a6, T, p); GEN Dpsi2 = Fq_elldivpol2d(a4, T, p); GEN C = find_coeff(a4, a6, T, p, dim, pp, e); GEN Ct = find_coeff(a4t, a6t, T, p, dim, pp, e); GEN V = cgetg(dim+1, t_VEC); for (k = 1; k <= dim; k++) { long v = mael(C,2,k); GEN z = gmul(gsub(gmael(Ct,1,k), gmael(C,1,k)), shifti(mpfact(2*k), -1)); if (signe(z) && Zq_pval(z, pp) < v) return NULL; gel(V, k) = Zq_divexact(z, powiu(pp, v)); } btop = avma; v = zerovec(dim); gel(v, 1) = utoi(deg); gel(v, 2) = pp1; P = pol_x(0); for (k = 3; k <= dim; k++) { GEN s, r = FqX_Fq_mul(Dpsi2, gel(P, 3), T, p); for (j = 4; j < lg(P); j++) { long o = j - 2; GEN D = FqX_add(RgX_shift_shallow(Dpsi2, 1), FqX_mulu(psi2, o-1, T, p), T, p); GEN E = FqX_Fq_mul(D, Fq_mulu(gel(P, j), o, T, p), T, p); r = FqX_add(r, RgX_shift_shallow(E, o-2), T, p); } P = r; s = Fq_mul(gel(P, 2), gel(v, 1), T, p); for (j = 3; j < lg(P)-1; j++) s = Fq_add(s, Fq_mul(gel(P, j), gel(v, j-1), T, p), T, p); gel(v, k) = Zq_Z_div_safe(Fq_sub(gel(V, k-2), s, T, p), gel(P, j), T, p, pp, e); if (gc_needed(btop, 1)) { if(DEBUGMEM>1) pari_warn(warnmem,"find_kernel"); gerepileall(btop, 2, &v, &P); } } tlist = cgetg(dim, t_VEC); gel(tlist, dim-1) = gen_1; for (k = 1; k <= dim-2; k++) { pari_sp btop = avma; GEN s = gel(v, k+1); for (i = 1; i < k; i++) s = Fq_add(s, Fq_mul(gel(tlist, dim-i-1), gel(v, k-i+1), T, p), T, p); gel(tlist, dim-k-1) = gerepileupto(btop, Zq_Z_div_safe(s, stoi(-k), T, p, pp, e)); } for (i = 1; i <= ext; i++) if (signe(Fq_red(gel(tlist, i),T, pp))) { avma = ltop; return NULL; } h = FqX_red(RgV_to_RgX(vecslice(tlist, ext+1, dim-1), 0),T,p); return signe(Fq_elldivpolmod(a4, a6, ell, h, T, pp)) ? NULL: h; } static GEN compute_u(GEN gprime, GEN Dxxg, GEN DxJg, GEN DJJg, GEN j, GEN pJ, GEN px, ulong q, GEN E4, GEN E6, GEN T, GEN p, GEN pp, long e) { pari_sp ltop = avma; GEN dxxgj = FqX_eval(Dxxg, j, T, p); GEN dxJgj = FqX_eval(DxJg, j, T, p); GEN dJJgj = FqX_eval(DJJg, j, T, p); GEN E42 = Fq_sqr(E4, T, p), E6ovE4 = Zq_div(E6, E4, T, p, pp, e); GEN a = Fq_mul(gprime, dxxgj, T, p); GEN b = Fq_mul(Fq_mul(Fq_mulu(j,2*q, T, p), dxJgj, T, p), E6ovE4, T, p); GEN c = Fq_mul(Zq_div(Fq_sqr(E6ovE4, T, p), gprime, T, p, pp, e), j, T, p); GEN d = Fq_mul(Fq_mul(c,sqru(q), T, p), Fq_add(pJ, Fq_mul(j, dJJgj, T, p), T, p), T, p); GEN f = Fq_sub(Fq_div(E6ovE4,utoi(3), T, p), Zq_div(E42, Fq_mulu(E6,2,T, p), T, p, pp, e), T, p); GEN g = Fq_sub(Fq_sub(b,a,T,p), d, T, p); return gerepileupto(ltop, Fq_add(Zq_div(g,px,T,p,pp,e), Fq_mulu(f,q,T,p), T, p)); } /* Finds the isogenous EC, and the sum of the x-coordinates of the points in * the kernel of the isogeny E -> Eb * E: elliptic curve, ell: a prime, meqn: Atkin modular equation * g: root of meqn defining isogenous curve Eb. */ static GEN find_isogenous_from_Atkin(GEN a4, GEN a6, ulong ell, struct meqn *MEQN, GEN g, GEN T, GEN pp, long e) { pari_sp ltop = avma, btop; GEN meqn = MEQN->eq, meqnx, Dmeqnx, Roots, gprime, u1; long k, vJ = MEQN->vy; GEN p = e==1 ? pp: powiu(pp, e); GEN j = Zq_ellj(a4, a6, T, p, pp, e); GEN E4 = Fq_div(a4, stoi(-3), T, p); GEN E6 = Fq_neg(Fq_halve(a6, T, p), T, p); GEN Dx = RgX_deriv(meqn); GEN DJ = deriv(meqn, vJ); GEN Dxg = FpXY_Fq_evaly(Dx, g, T, p, vJ); GEN px = FqX_eval(Dxg, j, T, p), dx = Fq_mul(px, g, T, p); GEN DJg = FpXY_Fq_evaly(DJ, g, T, p, vJ); GEN pJ = FqX_eval(DJg, j, T, p), dJ = Fq_mul(pJ, j, T, p); GEN Dxx = RgX_deriv(Dx); GEN DxJg = FqX_deriv(Dxg, T, p); GEN Dxxg = FpXY_Fq_evaly(Dxx, g, T, p, vJ); GEN DJJg = FqX_deriv(DJg, T, p); GEN a, b; if (!signe(Fq_red(dJ,T,pp)) || !signe(Fq_red(dx,T,pp))) { if (DEBUGLEVEL>0) err_printf("[A: d%c=0]",signe(dJ)? 'x': 'J'); avma = ltop; return NULL; } a = Fq_mul(dJ, Fq_mul(g, E6, T, p), T, p); b = Fq_mul(E4, dx, T, p); gprime = Zq_div(a, b, T, p, pp, e); u1 = compute_u(gprime, Dxxg, DxJg, DJJg, j, pJ, px, 1, E4, E6, T, p, pp, e); meqnx = FpXY_Fq_evaly(meqn, g, T, p, vJ); Dmeqnx = FqX_deriv(meqnx, T, pp); Roots = FqX_roots(meqnx, T, pp); btop = avma; for (k = lg(Roots)-1; k >= 1; k--, avma = btop) { GEN jt = gel(Roots, k); if (signe(FqX_eval(Dmeqnx, jt, T, pp))==0) continue; if (e > 1) jt = ZqX_liftroot(meqnx, gel(Roots, k), T, pp, e); if (signe(Fq_red(jt, T, pp)) == 0 || signe(Fq_sub(jt, utoi(1728), T, pp)) == 0) { if (DEBUGLEVEL>0) err_printf("[A: jt=%ld]",signe(Fq_red(jt,T,p))? 1728: 0); avma = ltop; return NULL; } else { GEN pxstar = FqX_eval(Dxg, jt, T, p); GEN dxstar = Fq_mul(pxstar, g, T, p); GEN pJstar = FqX_eval(DJg, jt, T, p); GEN dJstar = Fq_mul(Fq_mulu(jt, ell, T, p), pJstar, T, p); GEN u = Fq_mul(Fq_mul(dxstar, dJ, T, p), E6, T, p); GEN v = Fq_mul(Fq_mul(dJstar, dx, T, p), E4, T, p); GEN E4t = Zq_div(Fq_mul(Fq_sqr(u, T, p), jt, T, p), Fq_mul(Fq_sqr(v, T, p), Fq_sub(jt, utoi(1728), T, p), T, p), T, p, pp, e); GEN E6t = Zq_div(Fq_mul(u, E4t, T, p), v, T, p, pp, e); GEN u2 = compute_u(gprime, Dxxg, DxJg, DJJg, jt, pJstar, pxstar, ell, E4t, E6t, T, p, pp, e); GEN pp1 = Fq_mulu(Fq_sub(u1, u2, T, p), 3*ell, T, p); GEN a4t = Fq_mul(mulsi(-3, powuu(ell,4)), E4t, T, p); GEN a6t = Fq_mul(mulsi(-2, powuu(ell,6)), E6t, T, p); GEN h = find_kernel(a4, a6, ell, a4t, a6t, pp1, T, p, pp, e); if (h) return gerepilecopy(ltop, mkvec3(a4t, a6t, h)); } } pari_err_BUG("find_isogenous_from_Atkin, kernel not found"); return NULL;/*LCOV_EXCL_LINE*/ } /* Finds E' ell-isogenous to E and the trace term p1 from canonical modular * equation meqn * E: elliptic curve, ell: a prime, meqn: canonical modular equation * g: root of meqn defining isogenous curve Eb. */ static GEN find_isogenous_from_canonical(GEN a4, GEN a6, ulong ell, struct meqn *MEQN, GEN g, GEN T, GEN pp, long e) { pari_sp ltop = avma; GEN meqn = MEQN->eq; long vJ = MEQN->vy; GEN p = e==1 ? pp: powiu(pp, e); GEN h; GEN E4 = Fq_div(a4, stoi(-3), T, p); GEN E6 = Fq_neg(Fq_halve(a6, T, p), T, p); GEN E42 = Fq_sqr(E4, T, p); GEN E43 = Fq_mul(E4, E42, T, p); GEN E62 = Fq_sqr(E6, T, p); GEN delta = Fq_div(Fq_sub(E43, E62, T, p), utoi(1728), T, p); GEN j = Zq_div(E43, delta, T, p, pp, e); GEN Dx = RgX_deriv(meqn); GEN DJ = deriv(meqn, vJ); GEN Dxg = FpXY_Fq_evaly(Dx, g, T, p, vJ); GEN px = FqX_eval(Dxg, j, T, p), dx = Fq_mul(px, g, T, p); GEN DJg = FpXY_Fq_evaly(DJ, g, T, p, vJ); GEN pJ = FqX_eval(DJg, j, T, p), dJ = Fq_mul(j, pJ, T, p); GEN Dxx = RgX_deriv(Dx); GEN DxJg = FqX_deriv(Dxg, T, p); GEN ExJ = FqX_eval(DxJg, j, T, p); ulong tis = ugcd(12, ell-1), is = 12 / tis; GEN itis = Fq_inv(stoi(-tis), T, p); GEN deltal = Fq_div(Fq_mul(delta, Fq_powu(g, tis, T, p), T, p), powuu(ell, 12), T, p); GEN E4l, E6l, a4tilde, a6tilde, p_1; if (signe(Fq_red(dx,T, pp))==0) { if (DEBUGLEVEL>0) err_printf("[C: dx=0]"); avma = ltop; return NULL; } if (signe(Fq_red(dJ, T, pp))==0) { GEN jl; if (DEBUGLEVEL>0) err_printf("[C: dJ=0]"); E4l = Fq_div(E4, sqru(ell), T, p); jl = Zq_div(Fq_powu(E4l, 3, T, p), deltal, T, p, pp, e); E6l = Zq_sqrt(Fq_mul(Fq_sub(jl, utoi(1728), T, p), deltal, T, p), T, p, pp, e); p_1 = gen_0; } else { GEN jl, f, fd, Dgs, Djs, jld; GEN E2s = Zq_div(Fq_mul(Fq_neg(Fq_mulu(E6, 12, T, p), T, p), dJ, T, p), Fq_mul(Fq_mulu(E4, is, T, p), dx, T, p), T, p, pp, e); GEN gd = Fq_mul(Fq_mul(E2s, itis, T, p), g, T, p); GEN jd = Zq_div(Fq_mul(Fq_neg(E42, T, p), E6, T, p), delta, T, p, pp, e); GEN E0b = Zq_div(E6, Fq_mul(E4, E2s, T, p), T, p, pp, e); GEN Dxxgj = FqXY_eval(Dxx, g, j, T, p); GEN Dgd = Fq_add(Fq_mul(gd, px, T, p), Fq_mul(g, Fq_add(Fq_mul(gd, Dxxgj, T, p), Fq_mul(jd, ExJ, T, p), T, p), T, p), T, p); GEN DJgJj = FqX_eval(FqX_deriv(DJg, T, p), j, T, p); GEN Djd = Fq_add(Fq_mul(jd, pJ, T, p), Fq_mul(j, Fq_add(Fq_mul(jd, DJgJj, T, p), Fq_mul(gd, ExJ, T, p), T, p), T, p), T, p); GEN E0bd = Zq_div(Fq_sub(Fq_mul(Dgd, itis, T, p), Fq_mul(E0b, Djd, T, p), T, p), dJ, T, p, pp, e); E4l = Zq_div(Fq_sub(E4, Fq_mul(E2s, Fq_sub(Fq_sub(Fq_add(Zq_div(Fq_mulu(E0bd, 12, T, p), E0b, T, p, pp, e), Zq_div(Fq_mulu(E42, 6, T, p), E6, T, p, pp, e), T, p), Zq_div(Fq_mulu(E6, 4, T, p), E4, T, p, pp, e), T, p), E2s, T, p), T, p), T, p), sqru(ell), T, p, pp, e); jl = Zq_div(Fq_powu(E4l, 3, T, p), deltal, T, p, pp, e); if (signe(Fq_red(jl,T,pp))==0) { if (DEBUGLEVEL>0) err_printf("[C: jl=0]"); avma = ltop; return NULL; } f = Zq_div(powuu(ell, is), g, T, p, pp, e); fd = Fq_neg(Fq_mul(Fq_mul(E2s, f, T, p), itis, T, p), T, p); Dgs = FqXY_eval(Dx, f, jl, T, p); Djs = FqXY_eval(DJ, f, jl, T, p); jld = Zq_div(Fq_mul(Fq_neg(fd, T, p), Dgs, T, p), Fq_mulu(Djs, ell, T, p), T, p, pp, e); E6l = Zq_div(Fq_mul(Fq_neg(E4l, T, p), jld, T, p), jl, T, p, pp, e); p_1 = Fq_neg(Fq_halve(Fq_mulu(E2s, ell, T, p), T, p),T,p); } a4tilde = Fq_mul(Fq_mul(stoi(-3), powuu(ell,4), T, p), E4l, T, p); a6tilde = Fq_mul(Fq_mul(stoi(-2), powuu(ell,6), T, p), E6l, T, p); h = find_kernel(a4, a6, ell, a4tilde, a6tilde, p_1, T, p, pp, e); if (!h) return NULL; return gerepilecopy(ltop, mkvec3(a4tilde, a6tilde, h)); } static GEN corr(GEN c4, GEN c6, GEN T, GEN p, GEN pp, long e) { GEN c46 = Zq_div(Fq_sqr(c4, T, p), c6, T, p, pp, e); GEN c64 = Zq_div(c6, c4, T, p, pp, e); GEN a = Fp_div(gen_2, utoi(3), p); return Fq_add(Fq_halve(c46, T, p), Fq_mul(a, c64, T, p), T, p); } static GEN RgXY_deflatex(GEN H, long n, long d) { long i, l = lg(H); GEN R = cgetg(l, t_POL); R[1] = H[1]; for(i = 2; i < l; i++) { GEN Hi = gel(H, i); gel(R,i) = typ(Hi)==t_POL? RgX_deflate(RgX_shift_shallow(Hi, d), n): Hi; } return RgX_renormalize_lg(R, l); } static GEN Fq_polmodular_eval(GEN meqn, GEN j, long N, GEN T, GEN p, long vJ) { pari_sp av = avma; GEN R, dR, ddR; long t0 = N%3 == 1 ? 2: 0; long t2 = N%3 == 1 ? 0: 2; if (N == 3) { GEN P = FpXX_red(meqn, p); GEN dP = deriv(P, -1), ddP = deriv(dP, -1); R = FpXY_Fq_evaly(P, j, T, p, vJ); dR = FpXY_Fq_evaly(dP, j, T, p, vJ); ddR = FpXY_Fq_evaly(ddP, j, T, p, vJ); return gerepilecopy(av, mkvec3(R,dR,ddR)); } else { GEN P5 = FpXX_red(meqn, p); GEN H = RgX_splitting(P5, 3); GEN H0 = RgXY_deflatex(gel(H,1), 3, -t0); GEN H1 = RgXY_deflatex(gel(H,2), 3, -1); GEN H2 = RgXY_deflatex(gel(H,3), 3, -t2); GEN h0 = FpXY_Fq_evaly(H0, j, T, p, vJ); GEN h1 = FpXY_Fq_evaly(H1, j, T, p, vJ); GEN h2 = FpXY_Fq_evaly(H2, j, T, p, vJ); GEN dH0 = RgX_deriv(H0); GEN dH1 = RgX_deriv(H1); GEN dH2 = RgX_deriv(H2); GEN ddH0 = RgX_deriv(dH0); GEN ddH1 = RgX_deriv(dH1); GEN ddH2 = RgX_deriv(dH2); GEN d0 = FpXY_Fq_evaly(dH0, j, T, p, vJ); GEN d1 = FpXY_Fq_evaly(dH1, j, T, p, vJ); GEN d2 = FpXY_Fq_evaly(dH2, j, T, p, vJ); GEN dd0 = FpXY_Fq_evaly(ddH0, j, T, p, vJ); GEN dd1 = FpXY_Fq_evaly(ddH1, j, T, p, vJ); GEN dd2 = FpXY_Fq_evaly(ddH2, j, T, p, vJ); GEN h02, h12, h22, h03, h13, h23, h012, dh03, dh13, dh23, dh012; GEN ddh03, ddh13, ddh23, ddh012; GEN R1, dR1, ddR1, ddR2; h02 = FqX_sqr(h0, T, p); h12 = FqX_sqr(h1, T, p); h22 = FqX_sqr(h2, T, p); h03 = FqX_mul(h0, h02, T, p); h13 = FqX_mul(h1, h12, T, p); h23 = FqX_mul(h2, h22, T, p); h012 = FqX_mul(FqX_mul(h0, h1, T, p), h2, T, p); dh03 = FqX_mul(FqX_mulu(d0, 3, T, p), h02, T, p); dh13 = FqX_mul(FqX_mulu(d1, 3, T, p), h12, T, p); dh23 = FqX_mul(FqX_mulu(d2, 3, T, p), h22, T, p); dh012 = FqX_add(FqX_add(FqX_mul(FqX_mul(d0, h1, T, p), h2, T, p), FqX_mul(FqX_mul(h0, d1, T, p), h2, T, p), T, p), FqX_mul(FqX_mul(h0, h1, T, p), d2, T, p), T, p); R1 = FqX_sub(h13, FqX_mulu(h012, 3, T, p), T, p); R = FqX_add(FqX_add(FqX_Fq_mul(RgX_shift_shallow(h23, t2), Fq_sqr(j, T, p), T, p), FqX_Fq_mul(RgX_shift_shallow(R1, 1), j, T, p), T, p), RgX_shift_shallow(h03, t0), T, p); dR1 = FqX_sub(dh13, FqX_mulu(dh012, 3, T, p), T, p); dR = FqX_add(FqX_add(RgX_shift_shallow(FqX_add(FqX_Fq_mul(dh23, Fq_sqr(j, T, p), T, p), FqX_Fq_mul(h23, Fq_mulu(j, 2, T, p), T, p), T, p), t2), RgX_shift_shallow(FqX_add(FqX_Fq_mul(dR1, j, T, p), R1, T, p), 1), T, p), RgX_shift_shallow(dh03, t0), T, p); ddh03 = FqX_mulu(FqX_add(FqX_mul(dd0, h02, T, p), FqX_mul(FqX_mulu(FqX_sqr(d0, T, p), 2, T, p), h0, T, p), T, p), 3, T, p); ddh13 = FqX_mulu(FqX_add(FqX_mul(dd1, h12, T, p), FqX_mul(FqX_mulu(FqX_sqr(d1, T, p), 2, T, p), h1, T, p), T, p), 3, T, p); ddh23 = FqX_mulu(FqX_add(FqX_mul(dd2, h22, T, p), FqX_mul(FqX_mulu(FqX_sqr(d2, T, p), 2, T, p), h2, T, p), T, p), 3, T, p); ddh012 = FqX_add(FqX_add(FqX_add(FqX_mul(FqX_mul(dd0, h1, T, p), h2, T, p), FqX_mul(FqX_mul(h0, dd1, T, p), h2, T, p), T, p), FqX_mul(FqX_mul(h0, h1, T, p), dd2, T, p), T, p), FqX_mulu(FqX_add(FqX_add(FqX_mul(FqX_mul(d0, d1, T, p), h2, T, p), FqX_mul(FqX_mul(d0, h1, T, p), d2, T, p), T, p), FqX_mul(FqX_mul(h0, d1, T, p), d2, T, p), T, p), 2, T, p), T, p); ddR1 = FqX_sub(ddh13, FqX_mulu(ddh012, 3, T, p), T, p); ddR2 = FqX_add(FqX_add(FqX_Fq_mul(ddh23, Fq_sqr(j, T, p), T, p), FqX_Fq_mul(dh23, Fq_mulu(j, 4, T, p), T, p), T, p), FqX_mulu(h23, 2, T, p), T, p); ddR = FqX_add(FqX_add(RgX_shift_shallow(ddR2, t2), RgX_shift_shallow(FqX_add(FqX_mulu(dR1, 2, T, p), FqX_Fq_mul(ddR1, j, T, p), T, p), 1), T, p), RgX_shift_shallow(ddh03, t0), T, p); return gerepilecopy(av, mkvec3(R ,dR ,ddR)); } } static GEN meqn_j(struct meqn *MEQN, GEN j, long ell, GEN T, GEN p) { if (MEQN->type=='J') { MEQN->eval = Fq_polmodular_eval(MEQN->eq, j, ell, T, p, MEQN->vy); return gel(MEQN->eval, 1); } else return FqXY_evalx(MEQN->eq, j, T, p); } static GEN find_isogenous_from_J(GEN a4, GEN a6, ulong ell, struct meqn *MEQN, GEN g, GEN T, GEN pp, long e) { pari_sp ltop = avma; GEN meqn = MEQN->eval; GEN p = e==1 ? pp: powiu(pp, e); GEN h; GEN C4, C6, C4t, C6t; GEN j, jp, jtp, jtp2, jtp3; GEN Py, Pxy, Pyy, Pxj, Pyj, Pxxj, Pxyj, Pyyj; GEN s0, s1, s2, s3; GEN den, D, co, cot, c0, p_1, a4tilde, a6tilde; if (signe(g) == 0 || signe(Fq_sub(g, utoi(1728), T, p)) == 0) { if (DEBUGLEVEL>0) err_printf("[J: g=%ld]",signe(g)==0 ?0: 1728); avma = ltop; return NULL; } C4 = Fq_mul(a4, stoi(-48), T, p); C6 = Fq_mul(a6, stoi(-864), T, p); if (signe(C4)==0 || signe(C6)==0) { if (DEBUGLEVEL>0) err_printf("[J: C%ld=0]",signe(C4)==0 ?4: 6); avma = ltop; return NULL; } j = Zq_ellj(a4, a6, T, p, pp, e); jp = Fq_mul(j, Zq_div(C6, C4, T, p, pp, e), T, p); co = corr(C4, C6, T, p, pp, e); Py = RgX_deriv(gel(meqn, 1)); Pxy = RgX_deriv(gel(meqn,2)); Pyy = RgX_deriv(Py); Pxj = FqX_eval(gel(meqn, 2), g, T, p); if (signe(Pxj)==0) { if (DEBUGLEVEL>0) err_printf("[J: Pxj=0]"); avma = ltop; return NULL; } Pyj = FqX_eval(Py, g, T, p); Pxxj = FqX_eval(gel(meqn, 3), g, T, p); Pxyj = FqX_eval(Pxy, g, T, p); Pyyj = FqX_eval(Pyy, g, T, p); jtp = Fq_div(Fq_mul(jp, Zq_div(Pxj, Pyj, T, p, pp, e), T, p), negi(utoi(ell)), T, p); jtp2 = Fq_sqr(jtp,T,p); jtp3 = Fq_mul(jtp,jtp2,T,p); den = Fq_mul(Fq_sqr(g,T,p),Fq_sub(g,utoi(1728),T,p),T, p); D = Zq_inv(den,T,p,pp, e); C4t = Fq_mul(jtp2,Fq_mul(g, D, T, p), T, p); C6t = Fq_mul(jtp3, D, T, p); s0 = Fq_mul(Fq_sqr(jp, T, p), Pxxj, T, p); s1 = Fq_mul(Fq_mulu(Fq_mul(jp,jtp,T,p),2*ell,T,p), Pxyj, T, p); s2 = Fq_mul(Fq_mulu(jtp2,ell*ell,T,p), Pyyj, T, p); s3 = Zq_div(Fq_add(s0, Fq_add(s1, s2, T, p), T, p),Fq_mul(jp, Pxj, T, p),T,p,pp,e); cot = corr(C4t, C6t, T, p, pp, e); c0 = Fq_sub(co,Fq_mulu(cot,ell,T,p),T,p); p_1 = Fq_div(Fq_mulu(Fq_add(s3, c0, T, p),ell,T,p),stoi(-4),T,p); a4tilde = Fq_mul(Fq_div(C4t, stoi(-48), T, p),powuu(ell,4), T, p); a6tilde = Fq_mul(Fq_div(C6t, stoi(-864), T, p),powuu(ell,6), T, p); h = find_kernel(a4, a6, ell, a4tilde, a6tilde, p_1, T, p, pp, e); if (!h) return NULL; return gerepilecopy(ltop, mkvec3(a4tilde, a6tilde, h)); } static GEN find_isogenous(GEN a4,GEN a6, ulong ell, struct meqn *MEQN, GEN g, GEN T,GEN p) { ulong pp = itou_or_0(p); long e = (pp && pp <= 2*ell+3) ? 2+factorial_lval(ell, pp): 1; if (e > 1) { GEN pe = powiu(p, e); GEN meqnj = meqn_j(MEQN, Zq_ellj(a4, a6, T, pe, p, e), ell, T, pe); g = ZqX_liftroot(meqnj, g, T, p, e); } switch(MEQN->type) { case 'C': return find_isogenous_from_canonical(a4,a6,ell, MEQN, g, T,p,e); case 'A': return find_isogenous_from_Atkin(a4,a6,ell, MEQN, g, T,p,e); default: return find_isogenous_from_J(a4,a6,ell, MEQN, g, T,p,e); } } static GEN FqX_homogenous_eval(GEN P, GEN A, GEN B, GEN T, GEN p) { long d = degpol(P), i, v = varn(A); GEN s = scalar_ZX_shallow(gel(P, d+2), v), Bn = pol_1(v); for (i = d-1; i >= 0; i--) { Bn = FqX_mul(Bn, B, T, p); s = FqX_add(FqX_mul(s, A, T, p), FqX_Fq_mul(Bn, gel(P,i+2), T, p), T, p); } return s; } static GEN FqX_homogenous_div(GEN P, GEN Q, GEN A, GEN B, GEN T, GEN p) { GEN z = cgetg(3, t_RFRAC); long d = degpol(Q)-degpol(P); gel(z, 1) = FqX_homogenous_eval(P, A, B, T, p); gel(z, 2) = FqX_homogenous_eval(Q, A, B, T, p); if (d > 0) gel(z, 1) = FqX_mul(gel(z, 1), FqX_powu(B, d, T, p), T, p); else if (d < 0) gel(z, 2) = FqX_mul(gel(z, 2), FqX_powu(B, -d, T, p), T, p); return z; } static GEN find_kernel_power(GEN Eba4, GEN Eba6, GEN Eca4, GEN Eca6, ulong ell, struct meqn *MEQN, GEN kpoly, GEN Ib, GEN T, GEN p) { pari_sp ltop = avma, btop; GEN a4t, a6t, gtmp; GEN num_iso = FqX_numer_isog_abscissa(kpoly, Eba4, Eba6, T, p, 0); GEN mpoly = meqn_j(MEQN, Fq_ellj(Eca4, Eca6, T, p), ell, T, p); GEN mroots = FqX_roots(mpoly, T, p); GEN kpoly2 = FqX_sqr(kpoly, T, p); long i, l1 = lg(mroots); btop = avma; for (i = 1; i < l1; i++) { GEN h; GEN tmp = find_isogenous(Eca4, Eca6, ell, MEQN, gel(mroots, i), T, p); if (!tmp) { avma = ltop; return NULL; } a4t = gel(tmp, 1); a6t = gel(tmp, 2); gtmp = gel(tmp, 3); /*check that the kernel kpoly is the good one */ h = FqX_homogenous_eval(gtmp, num_iso, kpoly2, T, p); if (signe(Fq_elldivpolmod(Eba4, Eba6, ell, h, T, p))) { GEN Ic = FqX_homogenous_div(num_iso,kpoly2, numer_i(Ib),denom_i(Ib), T,p); GEN kpoly_new = FqX_homogenous_eval(gtmp, numer_i(Ic),denom_i(Ic), T,p); return gerepilecopy(ltop, mkvecn(5, a4t, a6t, kpoly_new, gtmp, Ic)); } avma = btop; } avma = ltop; return NULL; } /****************************************************************************/ /* TRACE */ /****************************************************************************/ enum mod_type {MTpathological, MTAtkin, MTElkies, MTone_root, MTroots}; static GEN Flxq_study_eqn(GEN mpoly, GEN T, ulong p, long *pt_dG, long *pt_r) { GEN Xq = FlxqX_Frobenius(mpoly, T, p); GEN G = FlxqX_gcd(FlxX_sub(Xq, pol_x(0), p), mpoly, T, p); *pt_dG = degpol(G); if (!*pt_dG) { *pt_r = FlxqX_ddf_degree(mpoly, Xq, T, p); return NULL; } return gel(FlxqX_roots(G, T, p), 1); } static GEN Fp_study_eqn(GEN mpoly, GEN p, long *pt_dG, long *pt_r) { GEN T = FpX_get_red(mpoly, p); GEN XP = FpX_Frobenius(T, p); GEN G = FpX_gcd(FpX_sub(XP, pol_x(0), p), mpoly, p); *pt_dG = degpol(G); if (!*pt_dG) { *pt_r = FpX_ddf_degree(T, XP, p); return NULL; } return FpX_oneroot(G, p); } static GEN Fq_study_eqn(GEN mpoly, GEN T, GEN p, long *pt_dG, long *pt_r) { GEN G; if (!T) return Fp_study_eqn(mpoly, p, pt_dG, pt_r); if (lgefint(p)==3) { ulong pp = p[2]; GEN Tp = ZXT_to_FlxT(T,pp); GEN mpolyp = ZXX_to_FlxX(mpoly,pp,get_FpX_var(T)); G = Flxq_study_eqn(mpolyp, Tp, pp, pt_dG, pt_r); return G ? Flx_to_ZX(G): NULL; } else { GEN Xq = FpXQX_Frobenius(mpoly, T, p); G = FpXQX_gcd(FpXX_sub(Xq, pol_x(0), p), mpoly, T, p); *pt_dG = degpol(G); if (!*pt_dG) { *pt_r = FpXQX_ddf_degree(mpoly, Xq, T, p); return NULL; } return gel(FpXQX_roots(G, T, p), 1); } } /* Berlekamp variant */ static GEN study_modular_eqn(long ell, GEN mpoly, GEN T, GEN p, enum mod_type *mt, long *ptr_r) { pari_sp ltop = avma; GEN g = gen_0; *ptr_r = 0; /*gcc -Wall*/ if (!FqX_is_squarefree(mpoly, T, p)) *mt = MTpathological; else { long dG; g = Fq_study_eqn(mpoly, T, p, &dG, ptr_r); switch(dG) { case 0: *mt = MTAtkin; break; case 1: *mt = MTone_root; break; case 2: *mt = MTElkies; break; default: *mt = (dG == ell + 1)? MTroots: MTpathological; } } if (DEBUGLEVEL) switch(*mt) { case MTone_root: err_printf("One root\t"); break; case MTElkies: err_printf("Elkies\t"); break; case MTroots: err_printf("l+1 roots\t"); break; case MTAtkin: err_printf("Atkin\t"); break; case MTpathological: err_printf("Pathological\n"); break; } return g ? gerepilecopy(ltop, g): NULL; } /*Returns the trace modulo ell^k when ell is an Elkies prime */ static GEN find_trace_Elkies_power(GEN a4, GEN a6, ulong ell, long *pt_k, struct meqn *MEQN, GEN g, GEN tr, GEN q, GEN T, GEN p, long smallfact, pari_timer *ti) { pari_sp ltop = avma, btop; GEN tmp, Eba4, Eba6, Eca4, Eca6, Ib, kpoly; long k = *pt_k; ulong lambda, ellk = upowuu(ell, k), pellk = umodiu(q, ellk); long cnt; if (DEBUGLEVEL) { err_printf("mod %ld", ell); } Eba4 = a4; Eba6 = a6; tmp = find_isogenous(a4,a6, ell, MEQN, g, T, p); if (!tmp) { avma = ltop; return NULL; } Eca4 = gel(tmp, 1); Eca6 = gel(tmp, 2); kpoly = gel(tmp, 3); Ib = pol_x(0); lambda = tr ? find_eigen_value_oneroot(a4, a6, ell, tr, kpoly, T, p): find_eigen_value_power(a4, a6, ell, 1, 1, kpoly, T, p); if (DEBUGLEVEL>1) err_printf(" [%ld ms]", timer_delay(ti)); if (smallfact && smallfact%(long)ell!=0) { ulong pell = pellk%ell; ulong ap = Fl_add(lambda, Fl_div(pell, lambda, ell), ell); if (Fl_sub(pell, ap, ell)==ell-1) { avma = ltop; return mkvecsmall(ap); } if (smallfact < 0 && Fl_add(pell, ap, ell)==ell-1) { avma = ltop; return mkvecsmall(ap); } } btop = avma; for (cnt = 2; cnt <= k; cnt++) { GEN tmp = find_kernel_power(Eba4, Eba6, Eca4, Eca6, ell, MEQN, kpoly, Ib, T, p); if (!tmp) { k = cnt-1; break; } if (DEBUGLEVEL) err_printf(", %Ps", powuu(ell, cnt)); lambda = find_eigen_value_power(a4, a6, ell, cnt, lambda, gel(tmp,3), T, p); Eba4 = Eca4; Eba6 = Eca6; Eca4 = gel(tmp,1); Eca6 = gel(tmp,2); kpoly = gel(tmp,4); Ib = gel(tmp, 5); if (gc_needed(btop, 1)) { if(DEBUGMEM>1) pari_warn(warnmem,"find_trace_Elkies_power"); gerepileall(btop, 6, &Eba4, &Eba6, &Eca4, &Eca6, &kpoly, &Ib); } if (DEBUGLEVEL>1) err_printf(" [%ld ms]", timer_delay(ti)); } avma = ltop; ellk = upowuu(ell, k); pellk = umodiu(q, ellk); *pt_k = k; return mkvecsmall(Fl_add(lambda, Fl_div(pellk, lambda, ellk), ellk)); } /*Returns the possible values of the trace when ell is an Atkin prime, */ /*given r the splitting degree of the modular equation at J = E.j */ static GEN find_trace_Atkin(ulong ell, long r, GEN q) { pari_sp ltop = avma; long nval = 0; ulong teta, pell = umodiu(q, ell), invp = Fl_inv(pell, ell); GEN val_pos = cgetg(1+ell, t_VECSMALL), P = gel(factoru(r), 1); GEN S = mkvecsmall4(0, pell, 0, 1); GEN U = mkvecsmall3(0, ell-1, 0); pari_sp btop = avma; if (r==2 && krouu(ell-pell, ell) < 0) val_pos[++nval] = 0; for (teta = 1; teta < ell; teta++, avma = btop) { ulong disc = Fl_sub(Fl_sqr(teta,ell), Fl_mul(4UL,pell,ell), ell); GEN a; if (krouu(disc, ell) >= 0) continue; S[3] = Fl_neg(teta, ell); U[3] = Fl_mul(invp, teta, ell); a = Flxq_powu(U, r/P[1], S, ell); if (!Flx_equal1(a) && Flx_equal1(Flxq_powu(a, P[1], S, ell))) { pari_sp av = avma; long i, l=lg(P); for (i = 2; i < l; i++, avma = av) if (Flx_equal1(Flxq_powu(U, r/P[i], S, ell))) break; if (i==l) val_pos[++nval] = teta; } } return gerepileupto(ltop, vecsmall_shorten(val_pos, nval)); } /*Returns the possible traces when there is only one root */ static GEN find_trace_one_root(ulong ell, GEN q) { ulong a = Fl_double(Fl_sqrt(umodiu(q,ell), ell), ell); return mkvecsmall2(a, ell - a); } static GEN find_trace_lp1_roots(long ell, GEN q) { ulong ell2 = ell * ell, pell = umodiu(q, ell2); ulong a = Fl_sqrt(pell%ell, ell); ulong pa = Fl_add(Fl_div(pell, a, ell2), a, ell2); return mkvecsmall2(pa, ell2 - pa); } /*trace modulo ell^k: [], [t] or [t1,...,td] */ static GEN find_trace(GEN a4, GEN a6, GEN j, ulong ell, GEN q, GEN T, GEN p, long *ptr_kt, long smallfact, long vx, long vy) { pari_sp ltop = avma; GEN g, meqnj, tr, tr2; long kt, r; enum mod_type mt; struct meqn MEQN; pari_timer ti; kt = maxss((long)(log(expi(q)*M_LN2)/log((double)ell)), 1); if (DEBUGLEVEL) { err_printf("SEA: Prime %5ld ", ell); timer_start(&ti); } get_modular_eqn(&MEQN, ell, vx, vy); meqnj = meqn_j(&MEQN, j, ell, T, p); g = study_modular_eqn(ell, meqnj, T, p, &mt, &r); /* If l is an Elkies prime, search for a factor of the l-division polynomial. * Then deduce the trace by looking for eigenvalues of the Frobenius by * computing modulo this factor */ switch (mt) { case MTone_root: tr2 = find_trace_one_root(ell, q); tr = find_trace_Elkies_power(a4,a6,ell, &kt, &MEQN, g, tr2, q, T, p, smallfact, &ti); if (!tr) { tr = tr2; kt = 1; } break; case MTElkies: /* Contrary to MTone_root, may look mod higher powers of ell */ if (abscmpiu(p, 2*ell+3) <= 0) kt = 1; /* Not implemented in this case */ tr = find_trace_Elkies_power(a4,a6,ell, &kt, &MEQN, g, NULL, q, T, p, smallfact, &ti); if (!tr) { if (DEBUGLEVEL) err_printf("[fail]\n"); avma = ltop; return NULL; } break; case MTroots: tr = find_trace_lp1_roots(ell, q); kt = 2; break; case MTAtkin: tr = find_trace_Atkin(ell, r, q); if (lg(tr)==1) pari_err_PRIME("ellap",p); kt = 1; break; default: /* case MTpathological: */ avma = ltop; return NULL; } if (DEBUGLEVEL) { long n = lg(tr)-1; if (n > 1 || mt == MTAtkin) { err_printf("%3ld trace(s)",n); if (DEBUGLEVEL>1) err_printf(" [%ld ms]", timer_delay(&ti)); } if (n > 1) err_printf("\n"); } *ptr_kt = kt; return gerepileupto(ltop, tr); } /* A partition of compile_atkin in baby and giant is represented as the binary developpement of an integer; if the i-th bit is 1, the i-th prime in compile-atkin is a baby. The optimum is obtained when the ratio between the number of possibilities for traces modulo giants (p_g) and babies (p_b) is near 3/4. */ static long separation(GEN cnt) { pari_sp btop; long k = lg(cnt)-1, l = (1L<=0) continue; res = mkvec2(utoi(B[i]), b); } return gerepilecopy(ltop, res); } static GEN compute_diff(GEN v) { pari_sp av = avma; long i, l = lg(v) - 1; GEN diff = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(diff, i) = subii(gel(v, i+1), gel(v, i)); return gerepileupto(av, ZV_sort_uniq(diff)); } static int cmp_atkin(void*E, GEN a, GEN b) { long ta=typ(a)==t_INT, tb=typ(b)==t_INT, c; (void) E; if (ta || tb) return ta-tb; c = lg(gel(a,2)) - lg(gel(b,2)); if (c) return c; return cmpii(gel(b,1), gel(a,1)); } static void add_atkin(GEN atkin, GEN trace, long *nb) { long l = lg(atkin)-1; long i, k = gen_search(atkin, trace, 1, NULL, cmp_atkin); if (k==0 || k > l) return; for (i = l; i > k; i--) gel(atkin,i) = gel(atkin,i-1); if (typ(gel(atkin,l))==t_INT) (*nb)++; gel(atkin,k) = trace; } /* V = baby / giant, P = Pb / Pg */ static GEN BSGS_pre(GEN *pdiff, GEN V, GEN P, void *E, const struct bb_group *grp) { GEN diff = compute_diff(V); GEN pre = cgetg(lg(diff), t_VEC); long i, l = lg(diff); gel(pre, 1) = grp->pow(E, P, gel(diff, 1)); /* what we'd _really_ want here is a hashtable diff[i] -> pre[i] */ for (i = 2; i < l; i++) { pari_sp av = avma; GEN d = subii(gel(diff, i), gel(diff, i-1)); GEN Q = grp->mul(E, gel(pre, i-1), grp->pow(E, P, d)); gel(pre, i) = gerepilecopy(av, Q); } *pdiff = diff; return pre; } /* u = trace_elkies, Mu = prod_elkies. Let caller collect garbage */ /* Match & sort: variant from Lercier's thesis, section 11.2.3 */ /* baby/giant/table updated in place: this routines uses * size(baby)+size(giant)+size(table)+size(table_ind) + O(log p) * bits of stack */ static GEN match_and_sort(GEN compile_atkin, GEN Mu, GEN u, GEN q, void *E, const struct bb_group *grp) { pari_sp av1, av2; GEN baby, giant, SgMb, Mb, Mg, den, Sg, dec_inf, div, pp1 = addiu(q,1); GEN P, Pb, Pg, point, diff, pre, table, table_ind; long best_i, i, lbaby, lgiant, k = lg(compile_atkin)-1; GEN bound = sqrti(shifti(q, 2)), card; const long lcard = 100; long lq = lgefint(q), nbcard; pari_timer ti; if (k == 1) { /*only one Atkin prime, check the cardinality with random points */ GEN r = gel(compile_atkin, 1), r1 = gel(r,1), r2 = gel(r,2); long l = lg(r2), j; GEN card = cgetg(l, t_VEC), Cs2, C, U; Z_chinese_pre(Mu, r1, &C,&U, NULL); Cs2 = shifti(C, -1); for (j = 1, i = 1; i < l; i++) { GEN t = Z_chinese_post(u, stoi(r2[i]), C, U, NULL); t = Fp_center_i(t, C, Cs2); if (abscmpii(t, bound) <= 0) gel(card, j++) = subii(pp1, t); } setlg(card, j); return gen_select_order(card, E, grp); } if (DEBUGLEVEL>=2) timer_start(&ti); av1 = avma; best_i = separation( get_lgatkin(compile_atkin, k) ); avma = av1; baby = possible_traces(compile_atkin, utoi(best_i), &Mb, 1); giant = possible_traces(compile_atkin, subiu(int2n(k), best_i+1), &Mg, 0); lbaby = lg(baby); lgiant = lg(giant); den = Fp_inv(Fp_mul(Mu, Mb, Mg), Mg); av2 = avma; for (i = 1; i < lgiant; i++, avma = av2) affii(Fp_mul(gel(giant,i), den, Mg), gel(giant,i)); ZV_sort_inplace(giant); Sg = Fp_mul(negi(u), den, Mg); den = Fp_inv(Fp_mul(Mu, Mg, Mb), Mb); dec_inf = divii(mulii(Mb,addii(Mg,shifti(Sg,1))), shifti(Mg,1)); togglesign(dec_inf); /* now, dec_inf = ceil(- (Mb/2 + Sg Mb/Mg) ) */ div = mulii(truedivii(dec_inf, Mb), Mb); av2 = avma; for (i = 1; i < lbaby; i++, avma = av2) { GEN b = addii(Fp_mul(Fp_sub(gel(baby,i), u, Mb), den, Mb), div); if (cmpii(b, dec_inf) < 0) b = addii(b, Mb); affii(b, gel(baby,i)); } ZV_sort_inplace(baby); SgMb = mulii(Sg, Mb); card = cgetg(lcard+1,t_VEC); for (i = 1; i <= lcard; i++) gel(card,i) = cgetipos(lq+1); av2 = avma; MATCH_RESTART: avma = av2; nbcard = 0; P = grp->rand(E); point = grp->pow(E,P, Mu); Pb = grp->pow(E,point, Mg); Pg = grp->pow(E,point, Mb); /* Precomputation for babies */ pre = BSGS_pre(&diff, baby, Pb, E, grp); /*Now we compute the table of babies, this table contains only the */ /*lifted x-coordinate of the points in order to use less memory */ table = cgetg(lbaby, t_VECSMALL); av1 = avma; /* (p+1 - u - Mu*Mb*Sg) P - (baby[1]) Pb */ point = grp->pow(E,P, subii(subii(pp1, u), mulii(Mu, addii(SgMb, mulii(Mg, gel(baby,1)))))); table[1] = grp->hash(gel(point,1)); for (i = 2; i < lbaby; i++) { GEN d = subii(gel(baby, i), gel(baby, i-1)); point = grp->mul(E, point, grp->pow(E, gel(pre, ZV_search(diff, d)), gen_m1)); table[i] = grp->hash(gel(point,1)); if (gc_needed(av1,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"match_and_sort, baby = %ld", i); point = gerepileupto(av1, point); } } avma = av1; /* Precomputations for giants */ pre = BSGS_pre(&diff, giant, Pg, E, grp); /* Look for a collision among the x-coordinates */ table_ind = vecsmall_indexsort(table); table = perm_mul(table,table_ind); av1 = avma; point = grp->pow(E, Pg, gel(giant, 1)); for (i = 1; ; i++) { GEN d; long h = grp->hash(gel(point, 1)); long s = zv_search(table, h); if (s) { while (table[s] == h && s) s--; for (s++; s < lbaby && table[s] == h; s++) { GEN B = gel(baby,table_ind[s]), G = gel(giant,i); GEN GMb = mulii(G, Mb), BMg = mulii(B, Mg); GEN Be = subii(subii(pp1, u), mulii(Mu, addii(SgMb, BMg))); GEN Bp = grp->pow(E,P, Be); /* p+1 - u - Mu (Sg Mb + GIANT Mb + BABY Mg) */ if (gequal(gel(Bp,1),gel(point,1))) { GEN card1 = subii(Be, mulii(Mu, GMb)); GEN card2 = addii(card1, mulii(mulsi(2,Mu), GMb)); if (abscmpii(subii(pp1, card1), bound) <= 0) affii(card1, gel(card, ++nbcard)); if (nbcard >= lcard) goto MATCH_RESTART; if (abscmpii(subii(pp1, card2), bound) <= 0) affii(card2, gel(card, ++nbcard)); if (nbcard >= lcard) goto MATCH_RESTART; } } } if (i==lgiant-1) break; d = subii(gel(giant, i+1), gel(giant, i)); point = grp->mul(E,point, gel(pre, ZV_search(diff, d))); if (gc_needed(av1,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"match_and_sort, giant = %ld", i); point = gerepileupto(av1, point); } } setlg(card, nbcard+1); if (DEBUGLEVEL>=2) timer_printf(&ti,"match_and_sort"); return gen_select_order(card, E, grp); } static GEN get_bound_bsgs(long lp) { GEN B; if (lp <= 160) B = divru(powru(dbltor(1.048), lp), 9); else if (lp <= 192) B = divrr(powru(dbltor(1.052), lp), dbltor(16.65)); else B = mulrr(powru(dbltor(1.035), minss(lp,307)), dbltor(1.35)); return mulru(B, 1000000); } /*FIXME: the name of the function does not quite match what it does*/ static const struct bb_group * get_FqE_group(void ** pt_E, GEN a4, GEN a6, GEN T, GEN p) { if (!T) return get_FpE_group(pt_E,a4,a6,p); else if (lgefint(p)==3) { ulong pp = uel(p,2); GEN Tp = ZXT_to_FlxT(T,pp); return get_FlxqE_group(pt_E, Fq_to_Flx(a4, Tp, pp), Fq_to_Flx(a6, Tp, pp), Tp, pp); } return get_FpXQE_group(pt_E,a4,a6,T,p); } /* E is an elliptic curve defined over Z or over Fp in ellinit format, defined * by the equation E: y^2 + a1*x*y + a2*y = x^3 + a2*x^2 + a4*x + a6 * p is a prime number * set smallfact to stop whenever a small factor of the order, not dividing smallfact, * is detected. Useful when searching for a good curve for cryptographic * applications */ GEN Fq_ellcard_SEA(GEN a4, GEN a6, GEN q, GEN T, GEN p, long smallfact) { const long MAX_ATKIN = 21; pari_sp ltop = avma, btop; long ell, i, nb_atkin, vx,vy; GEN TR, TR_mod, compile_atkin, bound, bound_bsgs, champ; GEN prod_atkin = gen_1, max_traces = gen_0; GEN j; double bound_gr = 1.; const double growth_factor = 1.26; forprime_t TT; j = Fq_ellj(a4, a6, T, p); if (signe(j) == 0 || signe(Fq_sub(j, utoi(1728), T, p)) == 0) return T ? FpXQ_ellcard(Fq_to_FpXQ(a4, T, p), Fq_to_FpXQ(a6, T, p), T, p) : Fp_ellcard(a4, a6, p); /*First compute the trace modulo 2 */ switch(FqX_nbroots(rhs(a4, a6, 0), T, p)) { case 3: /* bonus time: 4 | #E(Fq) = q+1 - t */ i = mod4(q)+1; if (i > 2) i -= 4; TR_mod = utoipos(4); TR = stoi(i); break; case 1: TR_mod = gen_2; TR = gen_0; break; default : /* 0 */ TR_mod = gen_2; TR = gen_1; break; } if (odd(smallfact) && !mpodd(TR)) { if (DEBUGLEVEL) err_printf("Aborting: #E(Fq) divisible by 2\n"); avma = ltop; return gen_0; } vy = fetch_var(); vx = fetch_var_higher(); /* compile_atkin is a vector containing informations about Atkin primes, * informations about Elkies primes lie in Mod(TR, TR_mod). */ u_forprime_init(&TT, 3, ULONG_MAX); bound = sqrti(shifti(q, 4)); bound_bsgs = get_bound_bsgs(expi(q)); compile_atkin = zerovec(MAX_ATKIN); nb_atkin = 0; btop = avma; while ( (ell = u_forprime_next(&TT)) ) { long ellkt, kt = 1, nbtrace; GEN trace_mod; if (absequalui(ell, p)) continue; trace_mod = find_trace(a4, a6, j, ell, q, T, p, &kt, smallfact, vx,vy); if (!trace_mod) continue; nbtrace = lg(trace_mod) - 1; ellkt = (long)upowuu(ell, kt); if (nbtrace == 1) { long t_mod_ellkt = trace_mod[1]; if (smallfact && smallfact%ell!=0) { /* does ell divide q + 1 - t ? */ long q_mod_ell_plus_one = umodiu(q,ell) + 1; ulong card_mod_ell = umodsu(q_mod_ell_plus_one - t_mod_ellkt, ell); ulong tcard_mod_ell = 1; if (card_mod_ell && smallfact < 0) tcard_mod_ell = umodsu(q_mod_ell_plus_one + t_mod_ellkt, ell); if (!card_mod_ell || !tcard_mod_ell) { if (DEBUGLEVEL) err_printf("\nAborting: #E%s(Fq) divisible by %ld\n", tcard_mod_ell ? "" : "_twist", ell); delete_var(); delete_var(); avma = ltop; return gen_0; } } (void)Z_incremental_CRT(&TR, t_mod_ellkt, &TR_mod, ellkt); if (DEBUGLEVEL) err_printf(", missing %ld bits\n",expi(bound)-expi(TR_mod)); } else { add_atkin(compile_atkin, mkvec2(utoipos(ellkt), trace_mod), &nb_atkin); prod_atkin = value(-1, compile_atkin, nb_atkin); } if (cmpii(mulii(TR_mod, prod_atkin), bound) > 0) { GEN bound_tr; if (!nb_atkin) { delete_var(); delete_var(); return gerepileuptoint(ltop, subii(addiu(q, 1), TR)); } bound_tr = mulrr(bound_bsgs, dbltor(bound_gr)); bound_gr *= growth_factor; if (signe(max_traces)) { max_traces = divis(muliu(max_traces,nbtrace), ellkt); if (DEBUGLEVEL>=3) err_printf("At least %Ps remaining possibilities.\n",max_traces); } if (cmpir(max_traces, bound_tr) < 0) { GEN bound_atkin = truedivii(bound, TR_mod); champ = champion(compile_atkin, nb_atkin, bound_atkin); max_traces = gel(champ,2); if (DEBUGLEVEL>=2) err_printf("%Ps remaining possibilities.\n", max_traces); if (cmpir(max_traces, bound_tr) < 0) { GEN res, cat = shallowextract(compile_atkin, gel(champ,1)); const struct bb_group *grp; void *E; if (DEBUGLEVEL) err_printf("Match and sort for %Ps possibilities.\n", max_traces); delete_var(); delete_var(); grp = get_FqE_group(&E,a4,a6,T,p); res = match_and_sort(cat, TR_mod, TR, q, E, grp); return gerepileuptoint(ltop, res); } } } if (gc_needed(btop, 1)) gerepileall(btop,5, &TR,&TR_mod, &compile_atkin, &max_traces, &prod_atkin); } return NULL;/*LCOV_EXCL_LINE*/ } GEN Fp_ellcard_SEA(GEN a4, GEN a6, GEN p, long smallfact) { return Fq_ellcard_SEA(a4, a6, p, NULL, p, smallfact); } pari-2.11.2/src/basemath/FpE.c0000644000175000017500000015550113326135265014364 0ustar billbill/* Copyright (C) 2009 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Not so fast arithmetic with points over elliptic curves over Fp */ /***********************************************************************/ /** **/ /** FpJ **/ /** **/ /***********************************************************************/ /* Arithmetic is implemented using Jacobian coordinates, representing * a projective point (x : y : z) on E by [z*x , z^2*y , z]. This is * probably not the fastest representation available for the given * problem, but they're easy to implement and up to 60% faster than * the school-book method used in FpE_mulu(). */ /* * Cost: 1M + 8S + 1*a + 10add + 1*8 + 2*2 + 1*3. * Source: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl */ GEN FpJ_dbl(GEN P, GEN a4, GEN p) { GEN X1, Y1, Z1; GEN XX, YY, YYYY, ZZ, S, M, T, Q; if (signe(gel(P,3)) == 0) return gcopy(P); X1 = gel(P,1); Y1 = gel(P,2); Z1 = gel(P,3); XX = Fp_sqr(X1, p); YY = Fp_sqr(Y1, p); YYYY = Fp_sqr(YY, p); ZZ = Fp_sqr(Z1, p); S = Fp_mulu(Fp_sub(Fp_sqr(Fp_add(X1, YY, p), p), Fp_add(XX, YYYY, p), p), 2, p); M = Fp_addmul(Fp_mulu(XX, 3, p), a4, Fp_sqr(ZZ, p), p); T = Fp_sub(Fp_sqr(M, p), Fp_mulu(S, 2, p), p); Q = cgetg(4, t_VEC); gel(Q,1) = T; gel(Q,2) = Fp_sub(Fp_mul(M, Fp_sub(S, T, p), p), Fp_mulu(YYYY, 8, p), p); gel(Q,3) = Fp_sub(Fp_sqr(Fp_add(Y1, Z1, p), p), Fp_add(YY, ZZ, p), p); return Q; } /* * Cost: 11M + 5S + 9add + 4*2. * Source: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl */ GEN FpJ_add(GEN P, GEN Q, GEN a4, GEN p) { GEN X1, Y1, Z1, X2, Y2, Z2; GEN Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V, W, R; if (signe(gel(Q,3)) == 0) return gcopy(P); if (signe(gel(P,3)) == 0) return gcopy(Q); X1 = gel(P,1); Y1 = gel(P,2); Z1 = gel(P,3); X2 = gel(Q,1); Y2 = gel(Q,2); Z2 = gel(Q,3); Z1Z1 = Fp_sqr(Z1, p); Z2Z2 = Fp_sqr(Z2, p); U1 = Fp_mul(X1, Z2Z2, p); U2 = Fp_mul(X2, Z1Z1, p); S1 = mulii(Y1, Fp_mul(Z2, Z2Z2, p)); S2 = mulii(Y2, Fp_mul(Z1, Z1Z1, p)); H = Fp_sub(U2, U1, p); r = Fp_mulu(Fp_sub(S2, S1, p), 2, p); /* If points are equal we must double. */ if (signe(H)== 0) { if (signe(r) == 0) /* Points are equal so double. */ return FpJ_dbl(P, a4, p); else return mkvec3(gen_1, gen_1, gen_0); } I = Fp_sqr(Fp_mulu(H, 2, p), p); J = Fp_mul(H, I, p); V = Fp_mul(U1, I, p); W = Fp_sub(Fp_sqr(r, p), Fp_add(J, Fp_mulu(V, 2, p), p), p); R = cgetg(4, t_VEC); gel(R,1) = W; gel(R,2) = Fp_sub(mulii(r, subii(V, W)), shifti(mulii(S1, J), 1), p); gel(R,3) = Fp_mul(Fp_sub(Fp_sqr(Fp_add(Z1, Z2, p), p), Fp_add(Z1Z1, Z2Z2, p), p), H, p); return R; } GEN FpJ_neg(GEN Q, GEN p) { return mkvec3(icopy(gel(Q,1)), Fp_neg(gel(Q,2), p), icopy(gel(Q,3))); } GEN FpE_to_FpJ(GEN P) { return ell_is_inf(P) ? mkvec3(gen_1, gen_1, gen_0): mkvec3(icopy(gel(P,1)),icopy(gel(P,2)), gen_1); } GEN FpJ_to_FpE(GEN P, GEN p) { if (signe(gel(P,3)) == 0) return ellinf(); else { GEN Z = Fp_inv(gel(P,3), p); GEN Z2 = Fp_sqr(Z, p), Z3 = Fp_mul(Z, Z2, p); retmkvec2(Fp_mul(gel(P,1), Z2, p), Fp_mul(gel(P,2), Z3, p)); } } struct _FpE { GEN a4,a6; GEN p; }; static GEN _FpJ_dbl(void *E, GEN P) { struct _FpE *ell = (struct _FpE *) E; return FpJ_dbl(P, ell->a4, ell->p); } static GEN _FpJ_add(void *E, GEN P, GEN Q) { struct _FpE *ell=(struct _FpE *) E; return FpJ_add(P, Q, ell->a4, ell->p); } static GEN _FpJ_mul(void *E, GEN P, GEN n) { pari_sp av = avma; struct _FpE *e=(struct _FpE *) E; long s = signe(n); if (!s || ell_is_inf(P)) return ellinf(); if (s<0) P = FpJ_neg(P, e->p); if (is_pm1(n)) return s>0? gcopy(P): P; return gerepilecopy(av, gen_pow(P, n, e, &_FpJ_dbl, &_FpJ_add)); } GEN FpJ_mul(GEN P, GEN n, GEN a4, GEN p) { struct _FpE E; E.a4= a4; E.p = p; return _FpJ_mul(&E, P, n); } /***********************************************************************/ /** **/ /** FpE **/ /** **/ /***********************************************************************/ /* These functions deal with point over elliptic curves over Fp defined * by an equation of the form y^2=x^3+a4*x+a6. * Most of the time a6 is omitted since it can be recovered from any point * on the curve. */ GEN RgE_to_FpE(GEN x, GEN p) { if (ell_is_inf(x)) return x; retmkvec2(Rg_to_Fp(gel(x,1),p),Rg_to_Fp(gel(x,2),p)); } GEN FpE_to_mod(GEN x, GEN p) { if (ell_is_inf(x)) return x; retmkvec2(Fp_to_mod(gel(x,1),p),Fp_to_mod(gel(x,2),p)); } GEN FpE_changepoint(GEN x, GEN ch, GEN p) { pari_sp av = avma; GEN p1,z,u,r,s,t,v,v2,v3; if (ell_is_inf(x)) return x; u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); v = Fp_inv(u, p); v2 = Fp_sqr(v,p); v3 = Fp_mul(v,v2,p); p1 = Fp_sub(gel(x,1),r,p); z = cgetg(3,t_VEC); gel(z,1) = Fp_mul(v2, p1, p); gel(z,2) = Fp_mul(v3, Fp_sub(gel(x,2), Fp_add(Fp_mul(s,p1, p),t, p),p),p); return gerepileupto(av, z); } GEN FpE_changepointinv(GEN x, GEN ch, GEN p) { GEN u, r, s, t, X, Y, u2, u3, u2X, z; if (ell_is_inf(x)) return x; X = gel(x,1); Y = gel(x,2); u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); u2 = Fp_sqr(u, p); u3 = Fp_mul(u,u2,p); u2X = Fp_mul(u2,X, p); z = cgetg(3, t_VEC); gel(z,1) = Fp_add(u2X,r,p); gel(z,2) = Fp_add(Fp_mul(u3,Y,p), Fp_add(Fp_mul(s,u2X,p), t, p), p); return z; } static GEN nonsquare_Fp(GEN p) { pari_sp av = avma; GEN a; do { avma = av; a = randomi(p); } while (kronecker(a, p) >= 0); return a; } void Fp_elltwist(GEN a4, GEN a6, GEN p, GEN *pt_a4, GEN *pt_a6) { GEN d = nonsquare_Fp(p), d2 = Fp_sqr(d, p), d3 = Fp_mul(d2, d, p); *pt_a4 = Fp_mul(a4, d2, p); *pt_a6 = Fp_mul(a6, d3, p); } static GEN FpE_dbl_slope(GEN P, GEN a4, GEN p, GEN *slope) { GEN x, y, Q; if (ell_is_inf(P) || !signe(gel(P,2))) return ellinf(); x = gel(P,1); y = gel(P,2); *slope = Fp_div(Fp_add(Fp_mulu(Fp_sqr(x,p), 3, p), a4, p), Fp_mulu(y, 2, p), p); Q = cgetg(3,t_VEC); gel(Q, 1) = Fp_sub(Fp_sqr(*slope, p), Fp_mulu(x, 2, p), p); gel(Q, 2) = Fp_sub(Fp_mul(*slope, Fp_sub(x, gel(Q, 1), p), p), y, p); return Q; } GEN FpE_dbl(GEN P, GEN a4, GEN p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FpE_dbl_slope(P,a4,p,&slope)); } static GEN FpE_add_slope(GEN P, GEN Q, GEN a4, GEN p, GEN *slope) { GEN Px, Py, Qx, Qy, R; if (ell_is_inf(P)) return Q; if (ell_is_inf(Q)) return P; Px = gel(P,1); Py = gel(P,2); Qx = gel(Q,1); Qy = gel(Q,2); if (equalii(Px, Qx)) { if (equalii(Py, Qy)) return FpE_dbl_slope(P, a4, p, slope); else return ellinf(); } *slope = Fp_div(Fp_sub(Py, Qy, p), Fp_sub(Px, Qx, p), p); R = cgetg(3,t_VEC); gel(R, 1) = Fp_sub(Fp_sub(Fp_sqr(*slope, p), Px, p), Qx, p); gel(R, 2) = Fp_sub(Fp_mul(*slope, Fp_sub(Px, gel(R, 1), p), p), Py, p); return R; } GEN FpE_add(GEN P, GEN Q, GEN a4, GEN p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FpE_add_slope(P,Q,a4,p,&slope)); } static GEN FpE_neg_i(GEN P, GEN p) { if (ell_is_inf(P)) return P; return mkvec2(gel(P,1), Fp_neg(gel(P,2), p)); } GEN FpE_neg(GEN P, GEN p) { if (ell_is_inf(P)) return ellinf(); return mkvec2(gcopy(gel(P,1)), Fp_neg(gel(P,2), p)); } GEN FpE_sub(GEN P, GEN Q, GEN a4, GEN p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FpE_add_slope(P, FpE_neg_i(Q, p), a4, p, &slope)); } static GEN _FpE_dbl(void *E, GEN P) { struct _FpE *ell = (struct _FpE *) E; return FpE_dbl(P, ell->a4, ell->p); } static GEN _FpE_add(void *E, GEN P, GEN Q) { struct _FpE *ell=(struct _FpE *) E; return FpE_add(P, Q, ell->a4, ell->p); } static GEN _FpE_mul(void *E, GEN P, GEN n) { pari_sp av = avma; struct _FpE *e=(struct _FpE *) E; long s = signe(n); GEN Q; if (!s || ell_is_inf(P)) return ellinf(); if (s<0) P = FpE_neg(P, e->p); if (is_pm1(n)) return s>0? gcopy(P): P; if (equalis(n,2)) return _FpE_dbl(E, P); Q = gen_pow(FpE_to_FpJ(P), n, e, &_FpJ_dbl, &_FpJ_add); return gerepileupto(av, FpJ_to_FpE(Q, e->p)); } GEN FpE_mul(GEN P, GEN n, GEN a4, GEN p) { struct _FpE E; E.a4 = a4; E.p = p; return _FpE_mul(&E, P, n); } /* Finds a random non-singular point on E */ GEN random_FpE(GEN a4, GEN a6, GEN p) { pari_sp ltop = avma; GEN x, x2, y, rhs; do { avma= ltop; x = randomi(p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */ x2 = Fp_sqr(x, p); rhs = Fp_add(Fp_mul(x, Fp_add(x2, a4, p), p), a6, p); } while ((!signe(rhs) && !signe(Fp_add(Fp_mulu(x2,3,p),a4,p))) || kronecker(rhs, p) < 0); y = Fp_sqrt(rhs, p); if (!y) pari_err_PRIME("random_FpE", p); return gerepilecopy(ltop, mkvec2(x, y)); } static GEN _FpE_rand(void *E) { struct _FpE *e=(struct _FpE *) E; return random_FpE(e->a4, e->a6, e->p); } static const struct bb_group FpE_group={_FpE_add,_FpE_mul,_FpE_rand,hash_GEN,ZV_equal,ell_is_inf,NULL}; const struct bb_group * get_FpE_group(void ** pt_E, GEN a4, GEN a6, GEN p) { struct _FpE *e = (struct _FpE *) stack_malloc(sizeof(struct _FpE)); e->a4 = a4; e->a6 = a6; e->p = p; *pt_E = (void *) e; return &FpE_group; } GEN FpE_order(GEN z, GEN o, GEN a4, GEN p) { pari_sp av = avma; struct _FpE e; GEN r; if (lgefint(p) == 3) { ulong pp = p[2]; r = Fle_order(ZV_to_Flv(z, pp), o, umodiu(a4,pp), pp); } else { e.a4 = a4; e.p = p; r = gen_order(z, o, (void*)&e, &FpE_group); } return gerepileuptoint(av, r); } GEN FpE_log(GEN a, GEN b, GEN o, GEN a4, GEN p) { pari_sp av = avma; struct _FpE e; GEN r; if (lgefint(p) == 3) { ulong pp = p[2]; r = Fle_log(ZV_to_Flv(a,pp), ZV_to_Flv(b,pp), o, umodiu(a4,pp), pp); } else { e.a4 = a4; e.p = p; r = gen_PH_log(a, b, o, (void*)&e, &FpE_group); } return gerepileuptoint(av, r); } /***********************************************************************/ /** **/ /** Pairings **/ /** **/ /***********************************************************************/ /* Derived from APIP from and by Jerome Milan, 2012 */ static GEN FpE_vert(GEN P, GEN Q, GEN a4, GEN p) { if (ell_is_inf(P)) return gen_1; if (!equalii(gel(Q, 1), gel(P, 1))) return Fp_sub(gel(Q, 1), gel(P, 1), p); if (signe(gel(P,2))!=0) return gen_1; return Fp_inv(Fp_add(Fp_mulu(Fp_sqr(gel(P,1),p), 3, p), a4, p), p); } static GEN FpE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN p) { GEN x = gel(Q, 1), y = gel(Q, 2); GEN tmp1 = Fp_sub(x, gel(R, 1), p); GEN tmp2 = Fp_add(Fp_mul(tmp1, slope, p), gel(R,2), p); if (!equalii(y, tmp2)) return Fp_sub(y, tmp2, p); if (signe(y) == 0) return gen_1; else { GEN s1, s2; GEN y2i = Fp_inv(Fp_mulu(y, 2, p), p); s1 = Fp_mul(Fp_add(Fp_mulu(Fp_sqr(x, p), 3, p), a4, p), y2i, p); if (!equalii(s1, slope)) return Fp_sub(s1, slope, p); s2 = Fp_mul(Fp_sub(Fp_mulu(x, 3, p), Fp_sqr(s1, p), p), y2i, p); return signe(s2)!=0 ? s2: y2i; } } /* Computes the equation of the line tangent to R and returns its evaluation at the point Q. Also doubles the point R. */ static GEN FpE_tangent_update(GEN R, GEN Q, GEN a4, GEN p, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = ellinf(); return gen_1; } else if (signe(gel(R,2)) == 0) { *pt_R = ellinf(); return FpE_vert(R, Q, a4, p); } else { GEN slope; *pt_R = FpE_dbl_slope(R, a4, p, &slope); return FpE_Miller_line(R, Q, slope, a4, p); } } /* Computes the equation of the line through R and P, and returns its evaluation at the point Q. Also adds P to the point R. */ static GEN FpE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN p, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = gcopy(P); return FpE_vert(P, Q, a4, p); } else if (ell_is_inf(P)) { *pt_R = gcopy(R); return FpE_vert(R, Q, a4, p); } else if (equalii(gel(P, 1), gel(R, 1))) { if (equalii(gel(P, 2), gel(R, 2))) return FpE_tangent_update(R, Q, a4, p, pt_R); else { *pt_R = ellinf(); return FpE_vert(R, Q, a4, p); } } else { GEN slope; *pt_R = FpE_add_slope(P, R, a4, p, &slope); return FpE_Miller_line(R, Q, slope, a4, p); } } /* Returns the Miller function f_{m, Q} evaluated at the point P using the standard Miller algorithm. */ struct _FpE_miller { GEN p, a4, P; }; static GEN FpE_Miller_dbl(void* E, GEN d) { struct _FpE_miller *m = (struct _FpE_miller *)E; GEN p = m->p, a4 = m->a4, P = m->P; GEN v, line; GEN num = Fp_sqr(gel(d,1), p); GEN denom = Fp_sqr(gel(d,2), p); GEN point = gel(d,3); line = FpE_tangent_update(point, P, a4, p, &point); num = Fp_mul(num, line, p); v = FpE_vert(point, P, a4, p); denom = Fp_mul(denom, v, p); return mkvec3(num, denom, point); } static GEN FpE_Miller_add(void* E, GEN va, GEN vb) { struct _FpE_miller *m = (struct _FpE_miller *)E; GEN p = m->p, a4= m->a4, P = m->P; GEN v, line, point; GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3); GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3); GEN num = Fp_mul(na, nb, p); GEN denom = Fp_mul(da, db, p); line = FpE_chord_update(pa, pb, P, a4, p, &point); num = Fp_mul(num, line, p); v = FpE_vert(point, P, a4, p); denom = Fp_mul(denom, v, p); return mkvec3(num, denom, point); } static GEN FpE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN p) { pari_sp ltop = avma; struct _FpE_miller d; GEN v, num, denom; d.a4 = a4; d.p = p; d.P = P; v = gen_pow(mkvec3(gen_1,gen_1,Q), m, (void*)&d, FpE_Miller_dbl, FpE_Miller_add); num = gel(v,1); denom = gel(v,2); return gerepileupto(ltop, Fp_div(num, denom, p)); } GEN FpE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN p) { pari_sp ltop = avma; GEN num, denom, result; if (ell_is_inf(P) || ell_is_inf(Q) || ZV_equal(P,Q)) return gen_1; num = FpE_Miller(P, Q, m, a4, p); denom = FpE_Miller(Q, P, m, a4, p); result = Fp_div(num, denom, p); if (mpodd(m)) result = Fp_neg(result, p); return gerepileupto(ltop, result); } GEN FpE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN p) { if (ell_is_inf(P) || ell_is_inf(Q)) return gen_1; return FpE_Miller(P, Q, m, a4, p); } /***********************************************************************/ /** **/ /** CM by principal order **/ /** **/ /***********************************************************************/ /* is jn/jd = J (mod p) */ static int is_CMj(long J, GEN jn, GEN jd, GEN p) { return dvdii(subii(mulis(jd,J), jn), p); } #ifndef LONG_IS_64BIT /* is jn/jd = -(2^32 a + b) (mod p) */ static int u2_is_CMj(ulong a, ulong b, GEN jn, GEN jd, GEN p) { GEN mJ = uu32toi(a,b); return dvdii(addii(mulii(jd,mJ), jn), p); } #endif static long Fp_ellj_get_CM(GEN jn, GEN jd, GEN p) { #define CHECK(CM,J) if (is_CMj(J,jn,jd,p)) return CM; CHECK(-3, 0); CHECK(-4, 1728); CHECK(-7, -3375); CHECK(-8, 8000); CHECK(-11, -32768); CHECK(-12, 54000); CHECK(-16, 287496); CHECK(-19, -884736); CHECK(-27, -12288000); CHECK(-28, 16581375); CHECK(-43, -884736000); #ifdef LONG_IS_64BIT CHECK(-67, -147197952000L); CHECK(-163, -262537412640768000L); #else if (u2_is_CMj(0x00000022UL,0x45ae8000UL,jn,jd,p)) return -67; if (u2_is_CMj(0x03a4b862UL,0xc4b40000UL,jn,jd,p)) return -163; #endif #undef CHECK return 0; } /***********************************************************************/ /** **/ /** issupersingular **/ /** **/ /***********************************************************************/ /* assume x reduced mod p, monic. Return one root, or NULL if irreducible */ static GEN FqX_quad_root(GEN x, GEN T, GEN p) { GEN b = gel(x,3), c = gel(x,2); GEN D = Fq_sub(Fq_sqr(b, T, p), Fq_mulu(c,4, T, p), T, p); GEN s = Fq_sqrt(D,T, p); if (!s) return NULL; return Fq_Fp_mul(Fq_sub(s, b, T, p), shifti(addiu(p, 1),-1),T, p); } /* * pol is the modular polynomial of level 2 modulo p. * * (T, p) defines the field FF_{p^2} in which j_prev and j live. */ static long path_extends_to_floor(GEN j_prev, GEN j, GEN T, GEN p, GEN Phi2, ulong max_len) { pari_sp ltop = avma; GEN Phi2_j; ulong mult, d; /* A path made its way to the floor if (i) its length was cut off * before reaching max_path_len, or (ii) it reached max_path_len but * only has one neighbour. */ for (d = 1; d < max_len; ++d) { GEN j_next; Phi2_j = FqX_div_by_X_x(FqXY_evalx(Phi2, j, T, p), j_prev, T, p, NULL); j_next = FqX_quad_root(Phi2_j, T, p); if (!j_next) { /* j is on the floor */ avma = ltop; return 1; } j_prev = j; j = j_next; if (gc_needed(ltop, 2)) gerepileall(ltop, 2, &j, &j_prev); } /* Check that we didn't end up at the floor on the last step (j will * point to the last element in the path. */ Phi2_j = FqX_div_by_X_x(FqXY_evalx(Phi2, j, T, p), j_prev, T, p, NULL); mult = FqX_nbroots(Phi2_j, T, p); avma = ltop; return mult == 0; } static int jissupersingular(GEN j, GEN S, GEN p) { long max_path_len = expi(p)+1; GEN Phi2 = FpXX_red(polmodular_ZXX(2,0,0,1), p); GEN Phi2_j = FqXY_evalx(Phi2, j, S, p); GEN roots = FpXQX_roots(Phi2_j, S, p); long nbroots = lg(roots)-1; int res = 1; /* Every node in a supersingular L-volcano has L + 1 neighbours. */ /* Note: a multiple root only occur when j has CM by sqrt(-15). */ if (nbroots==0 || (nbroots==1 && FqX_is_squarefree(Phi2_j, S, p))) res = 0; else { long i, l = lg(roots); for (i = 1; i < l; ++i) { if (path_extends_to_floor(j, gel(roots, i), S, p, Phi2, max_path_len)) { res = 0; break; } } } /* If none of the paths reached the floor, then the j-invariant is * supersingular. */ return res; } int Fp_elljissupersingular(GEN j, GEN p) { pari_sp ltop = avma; long CM; if (abscmpiu(p, 5) <= 0) return signe(j) == 0; /* valid if p <= 5 */ CM = Fp_ellj_get_CM(j, gen_1, p); if (CM < 0) return krosi(CM, p) < 0; /* valid if p > 3 */ else { GEN S = init_Fq(p, 2, fetch_var()); int res = jissupersingular(j, S, p); (void)delete_var(); avma = ltop; return res; } } /***********************************************************************/ /** **/ /** Cardinal **/ /** **/ /***********************************************************************/ /*assume a4,a6 reduced mod p odd */ static ulong Fl_elltrace_naive(ulong a4, ulong a6, ulong p) { ulong i, j; long a = 0; long d0, d1, d2, d3; GEN k = const_vecsmall(p, -1); k[1] = 0; for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p)) k[j+1] = 1; d0 = 6%p; d1 = d0; d2 = Fl_add(a4, 1, p); d3 = a6; for(i=0;; i++) { a -= k[1+d3]; if (i==p-1) break; d3 = Fl_add(d3, d2, p); d2 = Fl_add(d2, d1, p); d1 = Fl_add(d1, d0, p); } return a; } /* z1 <-- z1 + z2, with precomputed inverse */ static void FpE_add_ip(GEN z1, GEN z2, GEN a4, GEN p, GEN p2inv) { GEN p1,x,x1,x2,y,y1,y2; x1 = gel(z1,1); y1 = gel(z1,2); x2 = gel(z2,1); y2 = gel(z2,2); if (x1 == x2) p1 = Fp_add(a4, mulii(x1,mului(3,x1)), p); else p1 = Fp_sub(y2,y1, p); p1 = Fp_mul(p1, p2inv, p); x = Fp_sub(sqri(p1), addii(x1,x2), p); y = Fp_sub(mulii(p1,subii(x1,x)), y1, p); affii(x, x1); affii(y, y1); } /* make sure *x has lgefint >= k */ static void _fix(GEN x, long k) { GEN y = (GEN)*x; if (lgefint(y) < k) { GEN p1 = cgeti(k); affii(y,p1); *x = (long)p1; } } /* Return the lift of a (mod b), which is closest to c */ static GEN closest_lift(GEN a, GEN b, GEN c) { return addii(a, mulii(b, diviiround(subii(c,a), b))); } static long get_table_size(GEN pordmin, GEN B) { pari_sp av = avma; GEN t = ceilr( sqrtr( divri(itor(pordmin, DEFAULTPREC), B) ) ); if (is_bigint(t)) pari_err_OVERFLOW("ellap [large prime: install the 'seadata' package]"); avma = av; return itos(t) >> 1; } /* Find x such that kronecker(u = x^3+c4x+c6, p) is KRO. * Return point [x*u,u^2] on E (KRO=1) / E^twist (KRO=-1) */ static GEN Fp_ellpoint(long KRO, ulong *px, GEN c4, GEN c6, GEN p) { ulong x = *px; GEN u; for(;;) { x++; /* u = x^3 + c4 x + c6 */ u = modii(addii(c6, mului(x, addii(c4, sqru(x)))), p); if (kronecker(u,p) == KRO) break; } *px = x; return mkvec2(modii(mului(x,u),p), Fp_sqr(u,p)); } static GEN Fl_ellpoint(long KRO, ulong *px, ulong c4, ulong c6, ulong p) { ulong t, u, x = *px; for(;;) { if (++x >= p) pari_err_PRIME("ellap",utoi(p)); t = Fl_add(c4, Fl_sqr(x,p), p); u = Fl_add(c6, Fl_mul(x, t, p), p); if (krouu(u,p) == KRO) break; } *px = x; return mkvecsmall2(Fl_mul(x,u,p), Fl_sqr(u,p)); } static GEN ap_j1728(GEN a4,GEN p); /* compute a_p using Shanks/Mestre + Montgomery's trick. Assume p > 457 */ static GEN Fp_ellcard_Shanks(GEN c4, GEN c6, GEN p) { pari_timer T; long *tx, *ty, *ti, pfinal, i, j, s, KRO, nb; ulong x; pari_sp av = avma, av2; GEN p1, P, mfh, h, F,f, fh,fg, pordmin, u, v, p1p, p2p, A, B, a4, pts; tx = NULL; ty = ti = NULL; /* gcc -Wall */ if (!signe(c6)) { GEN ap = ap_j1728(c4, p); return gerepileuptoint(av, subii(addiu(p,1), ap)); } if (DEBUGLEVEL >= 6) timer_start(&T); /* once #E(Fp) is know mod B >= pordmin, it is completely determined */ pordmin = addiu(sqrti(gmul2n(p,4)), 1); /* ceil( 4sqrt(p) ) */ p1p = addiu(p, 1); p2p = shifti(p1p, 1); x = 0; KRO = 0; /* how many 2-torsion points ? */ switch(FpX_nbroots(mkpoln(4, gen_1, gen_0, c4, c6), p)) { case 3: A = gen_0; B = utoipos(4); break; case 1: A = gen_0; B = gen_2; break; default: A = gen_1; B = gen_2; break; /* 0 */ } for(;;) { h = closest_lift(A, B, p1p); if (!KRO) /* first time, initialize */ { KRO = kronecker(c6,p); f = mkvec2(gen_0, Fp_sqr(c6,p)); } else { KRO = -KRO; f = Fp_ellpoint(KRO, &x, c4,c6,p); } /* [ux, u^2] is on E_u: y^2 = x^3 + c4 u^2 x + c6 u^3 * E_u isomorphic to E (resp. E') iff KRO = 1 (resp. -1) * #E(F_p) = p+1 - a_p, #E'(F_p) = p+1 + a_p * * #E_u(Fp) = A (mod B), h is close to #E_u(Fp) */ a4 = modii(mulii(c4, gel(f,2)), p); /* c4 for E_u */ fh = FpE_mul(f, h, a4, p); if (ell_is_inf(fh)) goto FOUND; s = get_table_size(pordmin, B); /* look for h s.t f^h = 0 */ if (!tx) { /* first time: initialize */ tx = newblock(3*(s+1)); ty = tx + (s+1); ti = ty + (s+1); } F = FpE_mul(f,B,a4,p); *tx = evaltyp(t_VECSMALL) | evallg(s+1); /* F = B.f */ P = gcopy(fh); if (s < 3) { /* we're nearly done: naive search */ GEN q1 = P, mF = FpE_neg(F, p); /* -F */ for (i=1;; i++) { P = FpE_add(P,F,a4,p); /* h.f + i.F */ if (ell_is_inf(P)) { h = addii(h, mului(i,B)); goto FOUND; } q1 = FpE_add(q1,mF,a4,p); /* h.f - i.F */ if (ell_is_inf(q1)) { h = subii(h, mului(i,B)); goto FOUND; } } } /* Baby Step/Giant Step */ nb = minss(128, s >> 1); /* > 0. Will do nb pts at a time: faster inverse */ pts = cgetg(nb+1, t_VEC); j = lgefint(p); for (i=1; i<=nb; i++) { /* baby steps */ gel(pts,i) = P; /* h.f + (i-1).F */ _fix(P+1, j); tx[i] = mod2BIL(gel(P,1)); _fix(P+2, j); ty[i] = mod2BIL(gel(P,2)); P = FpE_add(P,F,a4,p); /* h.f + i.F */ if (ell_is_inf(P)) { h = addii(h, mului(i,B)); goto FOUND; } } mfh = FpE_neg(fh, p); fg = FpE_add(P,mfh,a4,p); /* h.f + nb.F - h.f = nb.F */ if (ell_is_inf(fg)) { h = mului(nb,B); goto FOUND; } u = cgetg(nb+1, t_VEC); av2 = avma; /* more baby steps, nb points at a time */ while (i <= s) { long maxj; for (j=1; j<=nb; j++) /* adding nb.F (part 1) */ { P = gel(pts,j); /* h.f + (i-nb-1+j-1).F */ gel(u,j) = subii(gel(fg,1), gel(P,1)); if (!signe(gel(u,j))) /* sum = 0 or doubling */ { long k = i+j-2; if (equalii(gel(P,2),gel(fg,2))) k -= 2*nb; /* fg == P */ h = addii(h, mulsi(k,B)); goto FOUND; } } v = FpV_inv(u, p); maxj = (i-1 + nb <= s)? nb: s % nb; for (j=1; j<=maxj; j++,i++) /* adding nb.F (part 2) */ { P = gel(pts,j); FpE_add_ip(P,fg, a4,p, gel(v,j)); tx[i] = mod2BIL(gel(P,1)); ty[i] = mod2BIL(gel(P,2)); } avma = av2; } P = FpE_add(gel(pts,j-1),mfh,a4,p); /* = (s-1).F */ if (ell_is_inf(P)) { h = mului(s-1,B); goto FOUND; } if (DEBUGLEVEL >= 6) timer_printf(&T, "[Fp_ellcard_Shanks] baby steps, s = %ld",s); /* giant steps: fg = s.F */ fg = FpE_add(P,F,a4,p); if (ell_is_inf(fg)) { h = mului(s,B); goto FOUND; } pfinal = mod2BIL(p); av2 = avma; /* Goal of the following: sort points by increasing x-coordinate hash. * Done in a complicated way to avoid allocating a large temp vector */ p1 = vecsmall_indexsort(tx); /* = permutation sorting tx */ for (i=1; i<=s; i++) ti[i] = tx[p1[i]]; /* ti = tx sorted */ for (i=1; i<=s; i++) { tx[i] = ti[i]; ti[i] = ty[p1[i]]; } /* tx is sorted. ti = ty sorted */ for (i=1; i<=s; i++) { ty[i] = ti[i]; ti[i] = p1[i]; } /* ty is sorted. ti = permutation sorting tx */ if (DEBUGLEVEL >= 6) timer_printf(&T, "[Fp_ellcard_Shanks] sorting"); avma = av2; gaffect(fg, gel(pts,1)); for (j=2; j<=nb; j++) /* pts[j] = j.fg = (s*j).F */ { P = FpE_add(gel(pts,j-1),fg,a4,p); if (ell_is_inf(P)) { h = mulii(mulss(s,j), B); goto FOUND; } gaffect(P, gel(pts,j)); } /* replace fg by nb.fg since we do nb points at a time */ avma = av2; fg = gcopy(gel(pts,nb)); /* copy: we modify (temporarily) pts[nb] below */ av2 = avma; for (i=1,j=1; ; i++) { GEN ftest = gel(pts,j); long m, l = 1, r = s+1; long k, k2, j2; avma = av2; k = mod2BIL(gel(ftest,1)); while (l < r) { m = (l+r) >> 1; if (tx[m] < k) l = m+1; else r = m; } if (r <= s && tx[r] == k) { while (r && tx[r] == k) r--; k2 = mod2BIL(gel(ftest,2)); for (r++; r <= s && tx[r] == k; r++) if (ty[r] == k2 || ty[r] == pfinal - k2) { /* [h+j2] f == +/- ftest (= [i.s] f)? */ j2 = ti[r] - 1; if (DEBUGLEVEL >=6) timer_printf(&T, "[Fp_ellcard_Shanks] giant steps, i = %ld",i); P = FpE_add(FpE_mul(F,stoi(j2),a4,p),fh,a4,p); if (equalii(gel(P,1), gel(ftest,1))) { if (equalii(gel(P,2), gel(ftest,2))) i = -i; h = addii(h, mulii(addis(mulss(s,i), j2), B)); goto FOUND; } } } if (++j > nb) { /* compute next nb points */ long save = 0; /* gcc -Wall */; for (j=1; j<=nb; j++) { P = gel(pts,j); gel(u,j) = subii(gel(fg,1), gel(P,1)); if (gel(u,j) == gen_0) /* occurs once: i = j = nb, P == fg */ { gel(u,j) = shifti(gel(P,2),1); save = fg[1]; fg[1] = P[1]; } } v = FpV_inv(u, p); for (j=1; j<=nb; j++) FpE_add_ip(gel(pts,j),fg,a4,p, gel(v,j)); if (i == nb) { fg[1] = save; } j = 1; } } FOUND: /* found a point of exponent h on E_u */ h = FpE_order(f, h, a4, p); /* h | #E_u(Fp) = A (mod B) */ A = Z_chinese_all(A, gen_0, B, h, &B); if (cmpii(B, pordmin) >= 0) break; /* not done: update A mod B for the _next_ curve, isomorphic to * the quadratic twist of this one */ A = remii(subii(p2p,A), B); /* #E(Fp)+#E'(Fp) = 2p+2 */ } if (tx) killblock(tx); h = closest_lift(A, B, p1p); return gerepileuptoint(av, KRO==1? h: subii(p2p,h)); } typedef struct { ulong x,y,i; } multiple; static int compare_multiples(multiple *a, multiple *b) { return a->x > b->x? 1:a->xx?-1:0; } /* find x such that h := a + b x is closest to c and return h: * x = round((c-a) / b) = floor( (2(c-a) + b) / 2b ) * Assume 0 <= a < b < c and b + 2c < 2^BIL */ static ulong uclosest_lift(ulong a, ulong b, ulong c) { ulong x = (b + ((c-a) << 1)) / (b << 1); return a + b * x; } static long Fle_dbl_inplace(GEN P, ulong a4, ulong p) { ulong x, y, slope; if (!P[2]) return 1; x = P[1]; y = P[2]; slope = Fl_div(Fl_add(Fl_triple(Fl_sqr(x,p), p), a4, p), Fl_double(y, p), p); P[1] = Fl_sub(Fl_sqr(slope, p), Fl_double(x, p), p); P[2] = Fl_sub(Fl_mul(slope, Fl_sub(x, P[1], p), p), y, p); return 0; } static long Fle_add_inplace(GEN P, GEN Q, ulong a4, ulong p) { ulong Px, Py, Qx, Qy, slope; if (ell_is_inf(Q)) return 0; Px = P[1]; Py = P[2]; Qx = Q[1]; Qy = Q[2]; if (Px==Qx) return Py==Qy ? Fle_dbl_inplace(P, a4, p): 1; slope = Fl_div(Fl_sub(Py, Qy, p), Fl_sub(Px, Qx, p), p); P[1] = Fl_sub(Fl_sub(Fl_sqr(slope, p), Px, p), Qx, p); P[2] = Fl_sub(Fl_mul(slope, Fl_sub(Px, P[1], p), p), Py, p); return 0; } /* assume 99 < p < 2^(BIL-1) - 2^((BIL+1)/2) and e has good reduction at p. * Should use Barett reduction + multi-inverse. See Fp_ellcard_Shanks() */ static long Fl_ellcard_Shanks(ulong c4, ulong c6, ulong p) { GEN f, fh, fg, ftest, F; ulong i, l, r, s, h, x, cp4, p1p, p2p, pordmin,A,B; long KRO; pari_sp av = avma; multiple *table; if (!c6) { GEN ap = ap_j1728(utoi(c4), utoipos(p)); avma = av; return p+1 - itos(ap); } pordmin = (ulong)(1 + 4*sqrt((double)p)); p1p = p+1; p2p = p1p << 1; x = 0; KRO = 0; switch(Flx_nbroots(mkvecsmall5(0L, c6,c4,0L,1L), p)) { case 3: A = 0; B = 4; break; case 1: A = 0; B = 2; break; default: A = 1; B = 2; break; /* 0 */ } for(;;) { /* see comments in Fp_ellcard_Shanks */ h = uclosest_lift(A, B, p1p); if (!KRO) /* first time, initialize */ { KRO = krouu(c6,p); /* != 0 */ f = mkvecsmall2(0, Fl_sqr(c6,p)); } else { KRO = -KRO; f = Fl_ellpoint(KRO, &x, c4,c6,p); } cp4 = Fl_mul(c4, f[2], p); fh = Fle_mulu(f, h, cp4, p); if (ell_is_inf(fh)) goto FOUND; s = (ulong) (sqrt(((double)pordmin)/B) / 2); if (!s) s = 1; table = (multiple *) stack_malloc((s+1) * sizeof(multiple)); F = Fle_mulu(f, B, cp4, p); for (i=0; i < s; i++) { table[i].x = fh[1]; table[i].y = fh[2]; table[i].i = i; if (Fle_add_inplace(fh, F, cp4, p)) { h += B*(i+1); goto FOUND; } } qsort(table,s,sizeof(multiple),(QSCOMP)compare_multiples); fg = Fle_mulu(F, s, cp4, p); ftest = zv_copy(fg); if (ell_is_inf(ftest)) { if (!uisprime(p)) pari_err_PRIME("ellap",utoi(p)); pari_err_BUG("ellap (f^(i*s) = 1)"); } for (i=1; ; i++) { l=0; r=s; while (l> 1; if (table[m].x < uel(ftest,1)) l=m+1; else r=m; } if (r < s && table[r].x == uel(ftest,1)) break; if (Fle_add_inplace(ftest, fg, cp4, p)) pari_err_PRIME("ellap",utoi(p)); } h += table[r].i * B; if (table[r].y == uel(ftest,2)) h -= s * i * B; else h += s * i * B; FOUND: h = itou(Fle_order(f, utoipos(h), cp4, p)); /* h | #E_u(Fp) = A (mod B) */ { GEN C; A = itou( Z_chinese_all(gen_0, utoi(A), utoipos(h), utoipos(B), &C) ); if (abscmpiu(C, pordmin) >= 0) { /* uclosest_lift could overflow */ h = itou( closest_lift(utoi(A), C, utoipos(p1p)) ); break; } B = itou(C); } A = (p2p - A) % B; avma = av; } avma = av; return KRO==1? h: p2p-h; } /** ellap from CM (original code contributed by Mark Watkins) **/ static GEN ap_j0(GEN a6,GEN p) { GEN a, b, e, d; if (umodiu(p,3) != 1) return gen_0; (void)cornacchia2(utoipos(27),p, &a,&b); if (umodiu(a, 3) == 1) a = negi(a); d = mulis(a6,-108); e = diviuexact(shifti(p,-1), 3); /* (p-1) / 6 */ return centermod(mulii(a, Fp_pow(d, e, p)), p); } static GEN ap_j1728(GEN a4,GEN p) { GEN a, b, e; if (mod4(p) != 1) return gen_0; (void)cornacchia2(utoipos(4),p, &a,&b); if (Mod4(a)==0) a = b; if (Mod2(a)==1) a = shifti(a,1); if (Mod8(a)==6) a = negi(a); e = shifti(p,-2); /* (p-1) / 4 */ return centermod(mulii(a, Fp_pow(a4, e, p)), p); } static GEN ap_j8000(GEN a6, GEN p) { GEN a, b; long r = mod8(p), s = 1; if (r != 1 && r != 3) return gen_0; (void)cornacchia2(utoipos(8),p, &a,&b); switch(Mod16(a)) { case 2: case 6: if (Mod4(b)) s = -s; break; case 10: case 14: if (!Mod4(b)) s = -s; break; } if (kronecker(mulis(a6, 42), p) < 0) s = -s; return s > 0? a: negi(a); } static GEN ap_j287496(GEN a6, GEN p) { GEN a, b; long s = 1; if (mod4(p) != 1) return gen_0; (void)cornacchia2(utoipos(4),p, &a,&b); if (Mod4(a)==0) a = b; if (Mod2(a)==1) a = shifti(a,1); if (Mod8(a)==6) s = -s; if (krosi(2,p) < 0) s = -s; if (kronecker(mulis(a6, -14), p) < 0) s = -s; return s > 0? a: negi(a); } static GEN ap_cm(int CM, long A6B, GEN a6, GEN p) { GEN a, b; long s = 1; if (krosi(CM,p) < 0) return gen_0; (void)cornacchia2(utoipos(-CM),p, &a, &b); if ((CM&3) == 0) CM >>= 2; if ((krois(a, -CM) > 0) ^ (CM == -7)) s = -s; if (kronecker(mulis(a6,A6B), p) < 0) s = -s; return s > 0? a: negi(a); } static GEN ec_ap_cm(int CM, GEN a4, GEN a6, GEN p) { switch(CM) { case -3: return ap_j0(a6, p); case -4: return ap_j1728(a4, p); case -8: return ap_j8000(a6, p); case -16: return ap_j287496(a6, p); case -7: return ap_cm(CM, -2, a6, p); case -11: return ap_cm(CM, 21, a6, p); case -12: return ap_cm(CM, 22, a6, p); case -19: return ap_cm(CM, 1, a6, p); case -27: return ap_cm(CM, 253, a6, p); case -28: return ap_cm(-7, -114, a6, p); /* yes, -7 ! */ case -43: return ap_cm(CM, 21, a6, p); case -67: return ap_cm(CM, 217, a6, p); case -163:return ap_cm(CM, 185801, a6, p); default: return NULL; } } static GEN Fp_ellj_nodiv(GEN a4, GEN a6, GEN p) { GEN a43 = Fp_mulu(Fp_powu(a4, 3, p), 4, p); GEN a62 = Fp_mulu(Fp_sqr(a6, p), 27, p); return mkvec2(Fp_mulu(a43, 1728, p), Fp_add(a43, a62, p)); } GEN Fp_ellj(GEN a4, GEN a6, GEN p) { pari_sp av=avma; GEN z = Fp_ellj_nodiv(a4, a6, p); return gerepileuptoint(av,Fp_div(gel(z,1),gel(z,2),p)); } static GEN /* Only compute a mod p, so assume p>=17 */ Fp_ellcard_CM(GEN a4, GEN a6, GEN p) { pari_sp av = avma; GEN a; if (!signe(a4)) a = ap_j0(a6,p); else if (!signe(a6)) a = ap_j1728(a4,p); else { GEN j = Fp_ellj_nodiv(a4, a6, p); long CM = Fp_ellj_get_CM(gel(j,1), gel(j,2), p); if (!CM) { avma = av; return NULL; } a = ec_ap_cm(CM,a4,a6,p); } return gerepileuptoint(av, subii(addiu(p,1),a)); } GEN Fp_ellcard(GEN a4, GEN a6, GEN p) { long lp = expi(p); ulong pp = p[2]; if (lp < 11) return utoi(pp+1 - Fl_elltrace_naive(umodiu(a4,pp), umodiu(a6,pp), pp)); { GEN a = Fp_ellcard_CM(a4,a6,p); if (a) return a; } if (lp >= 56) return Fp_ellcard_SEA(a4, a6, p, 0); if (lp <= BITS_IN_LONG-2) return utoi(Fl_ellcard_Shanks(umodiu(a4,pp), umodiu(a6,pp), pp)); return Fp_ellcard_Shanks(a4, a6, p); } long Fl_elltrace(ulong a4, ulong a6, ulong p) { pari_sp av; long lp; GEN a; if (p < (1<<11)) return Fl_elltrace_naive(a4, a6, p); lp = expu(p); if (lp <= minss(56, BITS_IN_LONG-2)) return p+1-Fl_ellcard_Shanks(a4, a6, p); av = avma; a = subui(p+1, Fp_ellcard(utoi(a4), utoi(a6), utoipos(p))); avma = av; return itos(a); } long Fl_elltrace_CM(long CM, ulong a4, ulong a6, ulong p) { pari_sp av; GEN a; if (!CM) return Fl_elltrace(a4,a6,p); if (p < (1<<11)) return Fl_elltrace_naive(a4, a6, p); av = avma; a = ec_ap_cm(CM, utoi(a4), utoi(a6), utoipos(p)); avma = av; return itos(a); } static GEN _FpE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F) { struct _FpE *e = (struct _FpE *) E; return Fp_order(FpE_weilpairing(P,Q,m,e->a4,e->p), F, e->p); } GEN Fp_ellgroup(GEN a4, GEN a6, GEN N, GEN p, GEN *pt_m) { struct _FpE e; e.a4=a4; e.a6=a6; e.p=p; return gen_ellgroup(N, subiu(p,1), pt_m, (void*)&e, &FpE_group, _FpE_pairorder); } GEN Fp_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN p) { GEN P; pari_sp av = avma; struct _FpE e; e.a4=a4; e.a6=a6; e.p=p; switch(lg(D)-1) { case 1: P = gen_gener(gel(D,1), (void*)&e, &FpE_group); P = mkvec(FpE_changepoint(P, ch, p)); break; default: P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FpE_group, _FpE_pairorder); gel(P,1) = FpE_changepoint(gel(P,1), ch, p); gel(P,2) = FpE_changepoint(gel(P,2), ch, p); break; } return gerepilecopy(av, P); } /* Not so fast arithmetic with points over elliptic curves over FpXQ */ /***********************************************************************/ /** **/ /** FpXQE **/ /** **/ /***********************************************************************/ /* Theses functions deal with point over elliptic curves over FpXQ defined * by an equation of the form y^2=x^3+a4*x+a6. * Most of the time a6 is omitted since it can be recovered from any point * on the curve. */ GEN RgE_to_FpXQE(GEN x, GEN T, GEN p) { if (ell_is_inf(x)) return x; retmkvec2(Rg_to_FpXQ(gel(x,1),T,p),Rg_to_FpXQ(gel(x,2),T,p)); } GEN FpXQE_changepoint(GEN x, GEN ch, GEN T, GEN p) { pari_sp av = avma; GEN p1,z,u,r,s,t,v,v2,v3; if (ell_is_inf(x)) return x; u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); v = FpXQ_inv(u, T, p); v2 = FpXQ_sqr(v, T, p); v3 = FpXQ_mul(v,v2, T, p); p1 = FpX_sub(gel(x,1),r, p); z = cgetg(3,t_VEC); gel(z,1) = FpXQ_mul(v2, p1, T, p); gel(z,2) = FpXQ_mul(v3, FpX_sub(gel(x,2), FpX_add(FpXQ_mul(s,p1, T, p),t, p), p), T, p); return gerepileupto(av, z); } GEN FpXQE_changepointinv(GEN x, GEN ch, GEN T, GEN p) { GEN u, r, s, t, X, Y, u2, u3, u2X, z; if (ell_is_inf(x)) return x; X = gel(x,1); Y = gel(x,2); u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); u2 = FpXQ_sqr(u, T, p); u3 = FpXQ_mul(u,u2, T, p); u2X = FpXQ_mul(u2,X, T, p); z = cgetg(3, t_VEC); gel(z,1) = FpX_add(u2X,r, p); gel(z,2) = FpX_add(FpXQ_mul(u3,Y, T, p), FpX_add(FpXQ_mul(s,u2X, T, p), t, p), p); return z; } static GEN nonsquare_FpXQ(GEN T, GEN p) { pari_sp av = avma; long n = degpol(T), v = varn(T); GEN a; if (odd(n)) { GEN z = cgetg(3, t_POL); z[1] = evalsigne(1) | evalvarn(v); gel(z,2) = nonsquare_Fp(p); return z; } do { avma = av; a = random_FpX(n, v, p); } while (FpXQ_issquare(a, T, p)); return a; } void FpXQ_elltwist(GEN a4, GEN a6, GEN T, GEN p, GEN *pt_a4, GEN *pt_a6) { GEN d = nonsquare_FpXQ(T, p); GEN d2 = FpXQ_sqr(d, T, p), d3 = FpXQ_mul(d2, d, T, p); *pt_a4 = FpXQ_mul(a4, d2, T, p); *pt_a6 = FpXQ_mul(a6, d3, T, p); } static GEN FpXQE_dbl_slope(GEN P, GEN a4, GEN T, GEN p, GEN *slope) { GEN x, y, Q; if (ell_is_inf(P) || !signe(gel(P,2))) return ellinf(); x = gel(P,1); y = gel(P,2); *slope = FpXQ_div(FpX_add(FpX_mulu(FpXQ_sqr(x, T, p), 3, p), a4, p), FpX_mulu(y, 2, p), T, p); Q = cgetg(3,t_VEC); gel(Q, 1) = FpX_sub(FpXQ_sqr(*slope, T, p), FpX_mulu(x, 2, p), p); gel(Q, 2) = FpX_sub(FpXQ_mul(*slope, FpX_sub(x, gel(Q, 1), p), T, p), y, p); return Q; } GEN FpXQE_dbl(GEN P, GEN a4, GEN T, GEN p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FpXQE_dbl_slope(P,a4,T,p,&slope)); } static GEN FpXQE_add_slope(GEN P, GEN Q, GEN a4, GEN T, GEN p, GEN *slope) { GEN Px, Py, Qx, Qy, R; if (ell_is_inf(P)) return Q; if (ell_is_inf(Q)) return P; Px = gel(P,1); Py = gel(P,2); Qx = gel(Q,1); Qy = gel(Q,2); if (ZX_equal(Px, Qx)) { if (ZX_equal(Py, Qy)) return FpXQE_dbl_slope(P, a4, T, p, slope); else return ellinf(); } *slope = FpXQ_div(FpX_sub(Py, Qy, p), FpX_sub(Px, Qx, p), T, p); R = cgetg(3,t_VEC); gel(R, 1) = FpX_sub(FpX_sub(FpXQ_sqr(*slope, T, p), Px, p), Qx, p); gel(R, 2) = FpX_sub(FpXQ_mul(*slope, FpX_sub(Px, gel(R, 1), p), T, p), Py, p); return R; } GEN FpXQE_add(GEN P, GEN Q, GEN a4, GEN T, GEN p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FpXQE_add_slope(P,Q,a4,T,p,&slope)); } static GEN FpXQE_neg_i(GEN P, GEN p) { if (ell_is_inf(P)) return P; return mkvec2(gel(P,1), FpX_neg(gel(P,2), p)); } GEN FpXQE_neg(GEN P, GEN T, GEN p) { (void) T; if (ell_is_inf(P)) return ellinf(); return mkvec2(gcopy(gel(P,1)), FpX_neg(gel(P,2), p)); } GEN FpXQE_sub(GEN P, GEN Q, GEN a4, GEN T, GEN p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FpXQE_add_slope(P, FpXQE_neg_i(Q, p), a4, T, p, &slope)); } struct _FpXQE { GEN a4,a6; GEN T,p; }; static GEN _FpXQE_dbl(void *E, GEN P) { struct _FpXQE *ell = (struct _FpXQE *) E; return FpXQE_dbl(P, ell->a4, ell->T, ell->p); } static GEN _FpXQE_add(void *E, GEN P, GEN Q) { struct _FpXQE *ell=(struct _FpXQE *) E; return FpXQE_add(P, Q, ell->a4, ell->T, ell->p); } static GEN _FpXQE_mul(void *E, GEN P, GEN n) { pari_sp av = avma; struct _FpXQE *e=(struct _FpXQE *) E; long s = signe(n); if (!s || ell_is_inf(P)) return ellinf(); if (s<0) P = FpXQE_neg(P, e->T, e->p); if (is_pm1(n)) return s>0? gcopy(P): P; return gerepileupto(av, gen_pow(P, n, e, &_FpXQE_dbl, &_FpXQE_add)); } GEN FpXQE_mul(GEN P, GEN n, GEN a4, GEN T, GEN p) { struct _FpXQE E; E.a4= a4; E.T = T; E.p = p; return _FpXQE_mul(&E, P, n); } /* Finds a random non-singular point on E */ GEN random_FpXQE(GEN a4, GEN a6, GEN T, GEN p) { pari_sp ltop = avma; GEN x, x2, y, rhs; long v = get_FpX_var(T), d = get_FpX_degree(T); do { avma= ltop; x = random_FpX(d,v,p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */ x2 = FpXQ_sqr(x, T, p); rhs = FpX_add(FpXQ_mul(x, FpX_add(x2, a4, p), T, p), a6, p); } while ((!signe(rhs) && !signe(FpX_add(FpX_mulu(x2,3,p), a4, p))) || !FpXQ_issquare(rhs, T, p)); y = FpXQ_sqrt(rhs, T, p); if (!y) pari_err_PRIME("random_FpE", p); return gerepilecopy(ltop, mkvec2(x, y)); } static GEN _FpXQE_rand(void *E) { struct _FpXQE *e=(struct _FpXQE *) E; return random_FpXQE(e->a4, e->a6, e->T, e->p); } static const struct bb_group FpXQE_group={_FpXQE_add,_FpXQE_mul,_FpXQE_rand,hash_GEN,ZXV_equal,ell_is_inf}; const struct bb_group * get_FpXQE_group(void ** pt_E, GEN a4, GEN a6, GEN T, GEN p) { struct _FpXQE *e = (struct _FpXQE *) stack_malloc(sizeof(struct _FpXQE)); e->a4 = a4; e->a6 = a6; e->T = T; e->p = p; *pt_E = (void *) e; return &FpXQE_group; } GEN FpXQE_order(GEN z, GEN o, GEN a4, GEN T, GEN p) { pari_sp av = avma; struct _FpXQE e; e.a4=a4; e.T=T; e.p=p; return gerepileuptoint(av, gen_order(z, o, (void*)&e, &FpXQE_group)); } GEN FpXQE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, GEN p) { pari_sp av = avma; struct _FpXQE e; e.a4=a4; e.T=T; e.p=p; return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &FpXQE_group)); } /***********************************************************************/ /** **/ /** Pairings **/ /** **/ /***********************************************************************/ /* Derived from APIP from and by Jerome Milan, 2012 */ static GEN FpXQE_vert(GEN P, GEN Q, GEN a4, GEN T, GEN p) { long vT = get_FpX_var(T); if (ell_is_inf(P)) return pol_1(get_FpX_var(T)); if (!ZX_equal(gel(Q, 1), gel(P, 1))) return FpX_sub(gel(Q, 1), gel(P, 1), p); if (signe(gel(P,2))!=0) return pol_1(vT); return FpXQ_inv(FpX_add(FpX_mulu(FpXQ_sqr(gel(P,1), T, p), 3, p), a4, p), T, p); } static GEN FpXQE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN T, GEN p) { long vT = get_FpX_var(T); GEN x = gel(Q, 1), y = gel(Q, 2); GEN tmp1 = FpX_sub(x, gel(R, 1), p); GEN tmp2 = FpX_add(FpXQ_mul(tmp1, slope, T, p), gel(R, 2), p); if (!ZX_equal(y, tmp2)) return FpX_sub(y, tmp2, p); if (signe(y) == 0) return pol_1(vT); else { GEN s1, s2; GEN y2i = FpXQ_inv(FpX_mulu(y, 2, p), T, p); s1 = FpXQ_mul(FpX_add(FpX_mulu(FpXQ_sqr(x, T, p), 3, p), a4, p), y2i, T, p); if (!ZX_equal(s1, slope)) return FpX_sub(s1, slope, p); s2 = FpXQ_mul(FpX_sub(FpX_mulu(x, 3, p), FpXQ_sqr(s1, T, p), p), y2i, T, p); return signe(s2)!=0 ? s2: y2i; } } /* Computes the equation of the line tangent to R and returns its evaluation at the point Q. Also doubles the point R. */ static GEN FpXQE_tangent_update(GEN R, GEN Q, GEN a4, GEN T, GEN p, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = ellinf(); return pol_1(get_FpX_var(T)); } else if (!signe(gel(R,2))) { *pt_R = ellinf(); return FpXQE_vert(R, Q, a4, T, p); } else { GEN slope; *pt_R = FpXQE_dbl_slope(R, a4, T, p, &slope); return FpXQE_Miller_line(R, Q, slope, a4, T, p); } } /* Computes the equation of the line through R and P, and returns its evaluation at the point Q. Also adds P to the point R. */ static GEN FpXQE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN T, GEN p, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = gcopy(P); return FpXQE_vert(P, Q, a4, T, p); } else if (ell_is_inf(P)) { *pt_R = gcopy(R); return FpXQE_vert(R, Q, a4, T, p); } else if (ZX_equal(gel(P, 1), gel(R, 1))) { if (ZX_equal(gel(P, 2), gel(R, 2))) return FpXQE_tangent_update(R, Q, a4, T, p, pt_R); else { *pt_R = ellinf(); return FpXQE_vert(R, Q, a4, T, p); } } else { GEN slope; *pt_R = FpXQE_add_slope(P, R, a4, T, p, &slope); return FpXQE_Miller_line(R, Q, slope, a4, T, p); } } /* Returns the Miller function f_{m, Q} evaluated at the point P using the standard Miller algorithm. */ struct _FpXQE_miller { GEN p; GEN T, a4, P; }; static GEN FpXQE_Miller_dbl(void* E, GEN d) { struct _FpXQE_miller *m = (struct _FpXQE_miller *)E; GEN p = m->p; GEN T = m->T, a4 = m->a4, P = m->P; GEN v, line; GEN num = FpXQ_sqr(gel(d,1), T, p); GEN denom = FpXQ_sqr(gel(d,2), T, p); GEN point = gel(d,3); line = FpXQE_tangent_update(point, P, a4, T, p, &point); num = FpXQ_mul(num, line, T, p); v = FpXQE_vert(point, P, a4, T, p); denom = FpXQ_mul(denom, v, T, p); return mkvec3(num, denom, point); } static GEN FpXQE_Miller_add(void* E, GEN va, GEN vb) { struct _FpXQE_miller *m = (struct _FpXQE_miller *)E; GEN p = m->p; GEN T = m->T, a4 = m->a4, P = m->P; GEN v, line, point; GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3); GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3); GEN num = FpXQ_mul(na, nb, T, p); GEN denom = FpXQ_mul(da, db, T, p); line = FpXQE_chord_update(pa, pb, P, a4, T, p, &point); num = FpXQ_mul(num, line, T, p); v = FpXQE_vert(point, P, a4, T, p); denom = FpXQ_mul(denom, v, T, p); return mkvec3(num, denom, point); } static GEN FpXQE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN T, GEN p) { pari_sp ltop = avma; struct _FpXQE_miller d; GEN v, num, denom, g1; d.a4 = a4; d.T = T; d.p = p; d.P = P; g1 = pol_1(get_FpX_var(T)); v = gen_pow(mkvec3(g1,g1,Q), m, (void*)&d, FpXQE_Miller_dbl, FpXQE_Miller_add); num = gel(v,1); denom = gel(v,2); return gerepileupto(ltop, FpXQ_div(num, denom, T, p)); } GEN FpXQE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, GEN p) { pari_sp ltop = avma; GEN num, denom, result; if (ell_is_inf(P) || ell_is_inf(Q) || ZXV_equal(P,Q)) return pol_1(get_FpX_var(T)); num = FpXQE_Miller(P, Q, m, a4, T, p); denom = FpXQE_Miller(Q, P, m, a4, T, p); result = FpXQ_div(num, denom, T, p); if (mpodd(m)) result = FpX_neg(result, p); return gerepileupto(ltop, result); } GEN FpXQE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, GEN p) { if (ell_is_inf(P) || ell_is_inf(Q)) return pol_1(get_FpX_var(T)); return FpXQE_Miller(P, Q, m, a4, T, p); } /***********************************************************************/ /** **/ /** issupersingular **/ /** **/ /***********************************************************************/ GEN FpXQ_ellj(GEN a4, GEN a6, GEN T, GEN p) { if (absequaliu(p,3)) return pol_0(get_FpX_var(T)); else { pari_sp av=avma; GEN a43 = FpXQ_mul(a4,FpXQ_sqr(a4,T,p),T,p); GEN a62 = FpXQ_sqr(a6,T,p); GEN num = FpX_mulu(a43,6912,p); GEN den = FpX_add(FpX_mulu(a43,4,p),FpX_mulu(a62,27,p),p); return gerepileuptoleaf(av, FpXQ_div(num, den, T, p)); } } int FpXQ_elljissupersingular(GEN j, GEN T, GEN p) { pari_sp ltop = avma; /* All supersingular j-invariants are in FF_{p^2}, so we first check * whether j is in FF_{p^2}. If d is odd, then FF_{p^2} is not a * subfield of FF_{p^d} so the j-invariants are all in FF_p. Hence * the j-invariants are in FF_{p^{2 - e}}. */ ulong d = get_FpX_degree(T); GEN S; int res; if (degpol(j) <= 0) return Fp_elljissupersingular(constant_coeff(j), p); if (abscmpiu(p, 5) <= 0) return 0; /* j != 0*/ /* Set S so that FF_p[T]/(S) is isomorphic to FF_{p^2}: */ if (d == 2) S = T; else { /* d > 2 */ /* We construct FF_{p^2} = FF_p[t]/((T - j)(T - j^p)) which * injects into FF_{p^d} via the map T |--> j. */ GEN j_pow_p = FpXQ_pow(j, p, T, p); GEN j_sum = FpX_add(j, j_pow_p, p), j_prod; long var = varn(T); if (degpol(j_sum) > 0) { avma = ltop; return 0; /* j not in Fp^2 */ } j_prod = FpXQ_mul(j, j_pow_p, T, p); if (degpol(j_prod) > 0 ) { avma = ltop; return 0; /* j not in Fp^2 */ } j_sum = constant_coeff(j_sum); j_prod = constant_coeff(j_prod); S = mkpoln(3, gen_1, Fp_neg(j_sum, p), j_prod); setvarn(S, var); j = pol_x(var); } res = jissupersingular(j, S, p); avma = ltop; return res; } /***********************************************************************/ /** **/ /** Point counting **/ /** **/ /***********************************************************************/ GEN elltrace_extension(GEN t, long n, GEN q) { pari_sp av = avma; GEN v = RgX_to_RgC(RgXQ_powu(pol_x(0), n, mkpoln(3,gen_1,negi(t),q)),2); GEN te = addii(shifti(gel(v,1),1), mulii(t,gel(v,2))); return gerepileuptoint(av, te); } GEN Fp_ffellcard(GEN a4, GEN a6, GEN q, long n, GEN p) { pari_sp av = avma; GEN ap = subii(addiu(p, 1), Fp_ellcard(a4, a6, p)); GEN te = elltrace_extension(ap, n, p); return gerepileuptoint(av, subii(addiu(q, 1), te)); } static GEN FpXQ_ellcardj(GEN a4, GEN a6, GEN j, GEN T, GEN q, GEN p, long n) { GEN q1 = addiu(q,1); if (signe(j)==0) { GEN W, w, t, N; if (umodiu(q,6)!=1) return q1; N = Fp_ffellcard(gen_0,gen_1,q,n,p); t = subii(q1, N); W = FpXQ_pow(a6,diviuexact(shifti(q,-1), 3),T,p); if (degpol(W)>0) /*p=5 mod 6*/ return ZX_equal1(FpXQ_powu(W,3,T,p)) ? addii(q1,shifti(t,-1)): subii(q1,shifti(t,-1)); w = modii(gel(W,2),p); if (equali1(w)) return N; if (equalii(w,subiu(p,1))) return addii(q1,t); else /*p=1 mod 6*/ { GEN u = shifti(t,-1), v = sqrtint(diviuexact(subii(q,sqri(u)),3)); GEN a = addii(u,v), b = shifti(v,1); if (equali1(Fp_powu(w,3,p))) { if (dvdii(addmulii(a, w, b), p)) return subii(q1,subii(shifti(b,1),a)); else return addii(q1,addii(a,b)); } else { if (dvdii(submulii(a, w, b), p)) return subii(q1,subii(a,shifti(b,1))); else return subii(q1,addii(a,b)); } } } else if (equalii(j,modsi(1728,p))) { GEN w, W, N, t; if (mod4(q)==3) return q1; W = FpXQ_pow(a4,shifti(q,-2),T,p); if (degpol(W)>0) return q1; /*p=3 mod 4*/ w = modii(gel(W,2),p); N = Fp_ffellcard(gen_1,gen_0,q,n,p); if (equali1(w)) return N; t = subii(q1, N); if (equalii(w,subiu(p,1))) return addii(q1,t); else /*p=1 mod 4*/ { GEN u = shifti(t,-1), v = sqrtint(subii(q,sqri(u))); if (dvdii(addmulii(u, w, v), p)) return subii(q1,shifti(v,1)); else return addii(q1,shifti(v,1)); } } else { GEN g = Fp_div(j, Fp_sub(utoi(1728), j, p), p); GEN l = FpXQ_div(FpX_mulu(a6,3,p),FpX_mulu(a4,2,p),T,p); GEN N = Fp_ffellcard(Fp_mulu(g,3,p),Fp_mulu(g,2,p),q,n,p); if (FpXQ_issquare(l,T,p)) return N; return subii(shifti(q1,1),N); } } GEN FpXQ_ellcard(GEN a4, GEN a6, GEN T, GEN p) { pari_sp av = avma; long n = get_FpX_degree(T); GEN q = powiu(p, n), r, J; if (degpol(a4)<=0 && degpol(a6)<=0) r = Fp_ffellcard(constant_coeff(a4),constant_coeff(a6),q,n,p); else if (lgefint(p)==3) { ulong pp = p[2]; r = Flxq_ellcard(ZX_to_Flx(a4,pp),ZX_to_Flx(a6,pp),ZX_to_Flx(T,pp),pp); } else if (degpol(J=FpXQ_ellj(a4,a6,T,p))<=0) r = FpXQ_ellcardj(a4,a6,constant_coeff(J),T,q,p,n); else r = Fq_ellcard_SEA(a4, a6, q, T, p, 0); return gerepileuptoint(av, r); } static GEN _FpXQE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F) { struct _FpXQE *e = (struct _FpXQE *) E; return FpXQ_order(FpXQE_weilpairing(P,Q,m,e->a4,e->T,e->p), F, e->T, e->p); } GEN FpXQ_ellgroup(GEN a4, GEN a6, GEN N, GEN T, GEN p, GEN *pt_m) { struct _FpXQE e; GEN q = powiu(p, get_FpX_degree(T)); e.a4=a4; e.a6=a6; e.T=T; e.p=p; return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &FpXQE_group, _FpXQE_pairorder); } GEN FpXQ_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, GEN p) { GEN P; pari_sp av = avma; struct _FpXQE e; e.a4=a4; e.a6=a6; e.T=T; e.p=p; switch(lg(D)-1) { case 1: P = gen_gener(gel(D,1), (void*)&e, &FpXQE_group); P = mkvec(FpXQE_changepoint(P, ch, T, p)); break; default: P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FpXQE_group, _FpXQE_pairorder); gel(P,1) = FpXQE_changepoint(gel(P,1), ch, T, p); gel(P,2) = FpXQE_changepoint(gel(P,2), ch, T, p); break; } return gerepilecopy(av, P); } pari-2.11.2/src/basemath/polmodular.c0000644000175000017500000036445713326135265016104 0ustar billbill/* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #define dbg_printf(lvl) if (DEBUGLEVEL >= (lvl) + 3) err_printf /** * START Code from AVSs "class_inv.h" */ /* actually just returns the square-free part of the level, which is * all we care about */ long modinv_level(long inv) { switch (inv) { case INV_J: return 1; case INV_G2: case INV_W3W3E2:return 3; case INV_F: case INV_F2: case INV_F4: case INV_F8: return 6; case INV_F3: return 2; case INV_W3W3: return 6; case INV_W2W7E2: case INV_W2W7: return 14; case INV_W3W5: return 15; case INV_W2W3E2: case INV_W2W3: return 6; case INV_W2W5E2: case INV_W2W5: return 30; case INV_W2W13: return 26; case INV_W3W7: return 42; case INV_W5W7: return 35; case INV_W3W13: return 39; } pari_err_BUG("modinv_level"); return 0;/*LCOV_EXCL_LINE*/ } /* Where applicable, returns N=p1*p2 (possibly p2=1) s.t. two j's * related to the same f are N-isogenous, and 0 otherwise. This is * often (but not necessarily) equal to the level. */ long modinv_degree(long *P1, long *P2, long inv) { long *p1, *p2, ignored; p1 = P1? P1: &ignored; p2 = P2? P2: &ignored; switch (inv) { case INV_W3W5: return (*p1 = 3) * (*p2 = 5); case INV_W2W3E2: case INV_W2W3: return (*p1 = 2) * (*p2 = 3); case INV_W2W5E2: case INV_W2W5: return (*p1 = 2) * (*p2 = 5); case INV_W2W7E2: case INV_W2W7: return (*p1 = 2) * (*p2 = 7); case INV_W2W13: return (*p1 = 2) * (*p2 = 13); case INV_W3W7: return (*p1 = 3) * (*p2 = 7); case INV_W3W3E2: case INV_W3W3: return (*p1 = 3) * (*p2 = 3); case INV_W5W7: return (*p1 = 5) * (*p2 = 7); case INV_W3W13: return (*p1 = 3) * (*p2 = 13); } *p1 = *p2 = 1; return 0; } /* Certain invariants require that D not have 2 in it's conductor, but * this doesn't apply to every invariant with even level so we handle * it separately */ INLINE int modinv_odd_conductor(long inv) { switch (inv) { case INV_F: case INV_W3W3: case INV_W3W7: return 1; } return 0; } long modinv_height_factor(long inv) { switch (inv) { case INV_J: return 1; case INV_G2: return 3; case INV_F: return 72; case INV_F2: return 36; case INV_F3: return 24; case INV_F4: return 18; case INV_F8: return 9; case INV_W2W3: return 72; case INV_W3W3: return 36; case INV_W2W5: return 54; case INV_W2W7: return 48; case INV_W3W5: return 36; case INV_W2W13: return 42; case INV_W3W7: return 32; case INV_W2W3E2:return 36; case INV_W2W5E2:return 27; case INV_W2W7E2:return 24; case INV_W3W3E2:return 18; case INV_W5W7: return 24; case INV_W3W13: return 28; default: pari_err_BUG("modinv_height_factor"); return 0;/*LCOV_EXCL_LINE*/ } } long disc_best_modinv(long D) { long ret; ret = INV_F; if (modinv_good_disc(ret, D)) return ret; ret = INV_W2W3; if (modinv_good_disc(ret, D)) return ret; ret = INV_W2W5; if (modinv_good_disc(ret, D)) return ret; ret = INV_W2W7; if (modinv_good_disc(ret, D)) return ret; ret = INV_W2W13; if (modinv_good_disc(ret, D)) return ret; ret = INV_W3W3; if (modinv_good_disc(ret, D)) return ret; ret = INV_W2W3E2;if (modinv_good_disc(ret, D)) return ret; ret = INV_W3W5; if (modinv_good_disc(ret, D)) return ret; ret = INV_W3W7; if (modinv_good_disc(ret, D)) return ret; ret = INV_W3W13; if (modinv_good_disc(ret, D)) return ret; ret = INV_W2W5E2;if (modinv_good_disc(ret, D)) return ret; ret = INV_F3; if (modinv_good_disc(ret, D)) return ret; ret = INV_W2W7E2;if (modinv_good_disc(ret, D)) return ret; ret = INV_W5W7; if (modinv_good_disc(ret, D)) return ret; ret = INV_W3W3E2;if (modinv_good_disc(ret, D)) return ret; ret = INV_G2; if (modinv_good_disc(ret, D)) return ret; return INV_J; } INLINE long modinv_sparse_factor(long inv) { switch (inv) { case INV_G2: case INV_F8: case INV_W3W5: case INV_W2W5E2: case INV_W3W3E2: return 3; case INV_F: return 24; case INV_F2: case INV_W2W3: return 12; case INV_F3: return 8; case INV_F4: case INV_W2W3E2: case INV_W2W5: case INV_W3W3: return 6; case INV_W2W7: return 4; case INV_W2W7E2: case INV_W2W13: case INV_W3W7: return 2; } return 1; } #define IQ_FILTER_1MOD3 1 #define IQ_FILTER_2MOD3 2 #define IQ_FILTER_1MOD4 4 #define IQ_FILTER_3MOD4 8 INLINE long modinv_pfilter(long inv) { switch (inv) { case INV_G2: case INV_W3W3: case INV_W3W3E2: case INV_W3W5: case INV_W2W5: case INV_W2W3E2: case INV_W2W5E2: case INV_W5W7: case INV_W3W13: return IQ_FILTER_1MOD3; /* ensure unique cube roots */ case INV_W2W7: case INV_F3: return IQ_FILTER_1MOD4; /* ensure at most two 4th/8th roots */ case INV_F: case INV_F2: case INV_F4: case INV_F8: case INV_W2W3: /* Ensure unique cube roots and at most two 4th/8th roots */ return IQ_FILTER_1MOD3 | IQ_FILTER_1MOD4; } return 0; } int modinv_good_prime(long inv, long p) { switch (inv) { case INV_G2: case INV_W2W3E2: case INV_W3W3: case INV_W3W3E2: case INV_W3W5: case INV_W2W5E2: case INV_W2W5: return (p % 3) == 2; case INV_W2W7: case INV_F3: return (p & 3) != 1; case INV_F2: case INV_F4: case INV_F8: case INV_F: case INV_W2W3: return ((p % 3) == 2) && (p & 3) != 1; } return 1; } /* Returns true if the prime p does not divide the conductor of D */ INLINE int prime_to_conductor(long D, long p) { long b; if (p > 2) return (D % (p * p)); b = D & 0xF; return (b && b != 4); /* 2 divides the conductor of D <=> D=0,4 mod 16 */ } INLINE GEN red_primeform(long D, long p) { pari_sp av = avma; GEN P; if (!prime_to_conductor(D, p)) return NULL; P = primeform_u(stoi(D), p); /* primitive since p \nmid conductor */ return gerepileupto(av, redimag(P)); } /* Computes product of primeforms over primes appearing in the prime * factorization of n (including multiplicity) */ GEN qfb_nform(long D, long n) { pari_sp av = avma; GEN N = NULL, fa = factoru(n), P = gel(fa,1), E = gel(fa,2); long i, l = lg(P); for (i = 1; i < l; ++i) { long j, e; GEN Q = red_primeform(D, P[i]); if (!Q) { avma = av; return NULL; } e = E[i]; if (i == 1) { N = Q; j = 1; } else j = 0; for (; j < e; ++j) N = qficomp(Q, N); } return gerepileupto(av, N); } INLINE int qfb_is_two_torsion(GEN x) { return equali1(gel(x,1)) || !signe(gel(x,2)) || equalii(gel(x,1), gel(x,2)) || equalii(gel(x,1), gel(x,3)); } /* Returns true iff the products p1*p2, p1*p2^-1, p1^-1*p2, and * p1^-1*p2^-1 are all distinct in cl(D) */ INLINE int qfb_distinct_prods(long D, long p1, long p2) { GEN P1, P2; P1 = red_primeform(D, p1); if (!P1) return 0; P1 = qfisqr(P1); P2 = red_primeform(D, p2); if (!P2) return 0; P2 = qfisqr(P2); return !(equalii(gel(P1,1), gel(P2,1)) && absequalii(gel(P1,2), gel(P2,2))); } /* By Corollary 3.1 of Enge-Schertz Constructing elliptic curves over finite * fields using double eta-quotients, we need p1 != p2 to both be non-inert * and prime to the conductor, and if p1=p2=p we want p split and prime to the * conductor. We exclude the case that p1=p2 divides the conductor, even * though this does yield class invariants */ INLINE int modinv_double_eta_good_disc(long D, long inv) { pari_sp av = avma; GEN P; long i1, i2, p1, p2, N; N = modinv_degree(&p1, &p2, inv); if (! N) return 0; i1 = kross(D, p1); if (i1 < 0) return 0; /* Exclude ramified case for w_{p,p} */ if (p1 == p2 && !i1) return 0; i2 = kross(D, p2); if (i2 < 0) return 0; /* this also verifies that p1 is prime to the conductor */ P = red_primeform(D, p1); if (!P || gequal1(gel(P,1)) /* don't allow p1 to be principal */ /* if p1 is unramified, require it to have order > 2 */ || (i1 && qfb_is_two_torsion(P))) { avma = av; return 0; } if (p1 == p2) { /* if p1=p2 we need p1*p1 to be distinct from its inverse */ int ok = ! qfb_is_two_torsion(qfisqr(P)); avma = av; return ok; } /* this also verifies that p2 is prime to the conductor */ P = red_primeform(D, p2); if (!P || gequal1(gel(P,1)) /* don't allow p2 to be principal */ /* if p2 is unramified, require it to have order > 2 */ || (i2 && qfb_is_two_torsion(P))) { avma = av; return 0; } avma = av; /* if p1 and p2 are split, we also require p1*p2, p1*p2^-1, p1^-1*p2, * and p1^-1*p2^-1 to be distinct */ if (i1>0 && i2>0 && !qfb_distinct_prods(D, p1, p2)) { avma = av; return 0; } if (!i1 && !i2) { /* if both p1 and p2 are ramified, make sure their product is not * principal */ P = qfb_nform(D, N); if (equali1(gel(P,1))) { avma = av; return 0; } avma = av; } return 1; } /* Assumes D is a good discriminant for inv, which implies that the * level is prime to the conductor */ long modinv_ramified(long D, long inv) { long p1, p2, N = modinv_degree(&p1, &p2, inv); if (N <= 1) return 0; return !(D % p1) && !(D % p2); } int modinv_good_disc(long inv, long D) { switch (inv) { case INV_J: return 1; case INV_G2: return !!(D % 3); case INV_F3: return (-D & 7) == 7; case INV_F: case INV_F2: case INV_F4: case INV_F8: return ((-D & 7) == 7) && (D % 3); case INV_W3W5: return (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W3W3E2: return (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W3W3: return (D & 1) && (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W2W3E2: return (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W2W3: return ((-D & 7) == 7) && (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W2W5: return ((-D % 80) != 20) && (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W2W5E2: return (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W2W7E2: return ((-D % 112) != 84) && modinv_double_eta_good_disc(D, inv); case INV_W2W7: return ((-D & 7) == 7) && modinv_double_eta_good_disc(D, inv); case INV_W2W13: return ((-D % 208) != 52) && modinv_double_eta_good_disc(D, inv); case INV_W3W7: return (D & 1) && (-D % 21) && modinv_double_eta_good_disc(D, inv); case INV_W5W7: /* NB: This is a guess; avs doesn't have an entry */ return (D % 3) && modinv_double_eta_good_disc(D, inv); case INV_W3W13: /* NB: This is a guess; avs doesn't have an entry */ return (D & 1) && (D % 3) && modinv_double_eta_good_disc(D, inv); } pari_err_BUG("modinv_good_discriminant"); return 0;/*LCOV_EXCL_LINE*/ } int modinv_is_Weber(long inv) { return inv == INV_F || inv == INV_F2 || inv == INV_F3 || inv == INV_F4 || inv == INV_F8; } int modinv_is_double_eta(long inv) { switch (inv) { case INV_W2W3: case INV_W2W3E2: case INV_W2W5: case INV_W2W5E2: case INV_W2W7: case INV_W2W7E2: case INV_W2W13: case INV_W3W3: case INV_W3W3E2: case INV_W3W5: case INV_W3W7: case INV_W5W7: case INV_W3W13: return 1; } return 0; } /* END Code from "class_inv.h" */ INLINE int safe_abs_sqrt(ulong *r, ulong x, ulong p, ulong pi, ulong s2) { if (krouu(x, p) == -1) { if (p%4 == 1) return 0; x = Fl_neg(x, p); } *r = Fl_sqrt_pre_i(x, s2, p, pi); return 1; } INLINE int eighth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2) { ulong s; if (krouu(x, p) == -1) return 0; s = Fl_sqrt_pre_i(x, s2, p, pi); return safe_abs_sqrt(&s, s, p, pi, s2) && safe_abs_sqrt(r, s, p, pi, s2); } INLINE ulong modinv_f_from_j(ulong j, ulong p, ulong pi, ulong s2, long only_residue) { pari_sp av = avma; GEN pol, r; long i; ulong g2, f = ULONG_MAX; /* f^8 must be a root of X^3 - \gamma_2 X - 16 */ g2 = Fl_sqrtl_pre(j, 3, p, pi); pol = mkvecsmall5(0UL, Fl_neg(16 % p, p), Fl_neg(g2, p), 0UL, 1UL); r = Flx_roots(pol, p); for (i = 1; i < lg(r); ++i) if (only_residue) { if (krouu(r[i], p) != -1) { avma = av; return r[i]; } } else if (eighth_root(&f, r[i], p, pi, s2)) { avma = av; return f; } pari_err_BUG("modinv_f_from_j"); return 0;/*LCOV_EXCL_LINE*/ } INLINE ulong modinv_f3_from_j(ulong j, ulong p, ulong pi, ulong s2) { pari_sp av = avma; GEN pol, r; long i; ulong f = ULONG_MAX; pol = mkvecsmall5(0UL, Fl_neg(4096 % p, p), Fl_sub(768 % p, j, p), Fl_neg(48 % p, p), 1UL); r = Flx_roots(pol, p); for (i = 1; i < lg(r); ++i) if (eighth_root(&f, r[i], p, pi, s2)) { avma = av; return f; } pari_err_BUG("modinv_f3_from_j"); return 0;/*LCOV_EXCL_LINE*/ } /* Return the exponent e for the double-eta "invariant" w such that * w^e is a class invariant. For example w2w3^12 is a class * invariant, so double_eta_exponent(INV_W2W3) is 12 and * double_eta_exponent(INV_W2W3E2) is 6. */ INLINE ulong double_eta_exponent(long inv) { switch (inv) { case INV_W2W3: return 12; case INV_W2W3E2: case INV_W2W5: case INV_W3W3: return 6; case INV_W2W7: return 4; case INV_W3W5: case INV_W2W5E2: case INV_W3W3E2: return 3; case INV_W2W7E2: case INV_W2W13: case INV_W3W7: return 2; default: return 1; } } INLINE ulong weber_exponent(long inv) { switch (inv) { case INV_F: return 24; case INV_F2: return 12; case INV_F3: return 8; case INV_F4: return 6; case INV_F8: return 3; default: return 1; } } INLINE ulong double_eta_power(long inv, ulong w, ulong p, ulong pi) { return Fl_powu_pre(w, double_eta_exponent(inv), p, pi); } static GEN double_eta_raw_to_Fp(GEN f, GEN p) { GEN u = FpX_red(RgV_to_RgX(gel(f,1), 0), p); GEN v = FpX_red(RgV_to_RgX(gel(f,2), 0), p); return mkvec3(u, v, gel(f,3)); } /* Given a root x of polclass(D, inv) modulo N, returns a root of polclass(D,0) * modulo N by plugging x to a modular polynomial. For double-eta quotients, * this is done by plugging x into the modular polynomial Phi(INV_WpWq, j) * Enge, Morain 2013: Generalised Weber Functions. */ GEN Fp_modinv_to_j(GEN x, long inv, GEN p) { switch(inv) { case INV_J: return Fp_red(x, p); case INV_G2: return Fp_powu(x, 3, p); case INV_F: case INV_F2: case INV_F3: case INV_F4: case INV_F8: { GEN xe = Fp_powu(x, weber_exponent(inv), p); return Fp_div(Fp_powu(subiu(xe, 16), 3, p), xe, p); } default: if (modinv_is_double_eta(inv)) { GEN xe = Fp_powu(x, double_eta_exponent(inv), p); GEN uvk = double_eta_raw_to_Fp(double_eta_raw(inv), p); GEN J0 = FpX_eval(gel(uvk,1), xe, p); GEN J1 = FpX_eval(gel(uvk,2), xe, p); GEN J2 = Fp_pow(xe, gel(uvk,3), p); GEN phi = mkvec3(J0, J1, J2); return FpX_oneroot(RgX_to_FpX(RgV_to_RgX(phi,1), p),p); } pari_err_BUG("Fp_modinv_to_j"); return NULL;/* LCOV_EXCL_LINE */ } } /* Assuming p = 2 (mod 3) and p = 3 (mod 4): if the two 12th roots of * x (mod p) exist, set *r to one of them and return 1, otherwise * return 0 (without touching *r). */ INLINE int twelth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2) { register ulong t; t = Fl_sqrtl_pre(x, 3, p, pi); if (krouu(t, p) == -1) return 0; t = Fl_sqrt_pre_i(t, s2, p, pi); return safe_abs_sqrt(r, t, p, pi, s2); } INLINE int sixth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2) { register ulong t; t = Fl_sqrtl_pre(x, 3, p, pi); if (krouu(t, p) == -1) return 0; *r = Fl_sqrt_pre_i(t, s2, p, pi); return 1; } INLINE int fourth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2) { register ulong s; if (krouu(x, p) == -1) return 0; s = Fl_sqrt_pre_i(x, s2, p, pi); return safe_abs_sqrt(r, s, p, pi, s2); } INLINE int double_eta_root(long inv, ulong *r, ulong w, ulong p, ulong pi, ulong s2) { switch (double_eta_exponent(inv)) { case 12: return twelth_root(r, w, p, pi, s2); case 6: return sixth_root(r, w, p, pi, s2); case 4: return fourth_root(r, w, p, pi, s2); case 3: *r = Fl_sqrtl_pre(w, 3, p, pi); return 1; case 2: return krouu(w, p) != -1 && !!(*r = Fl_sqrt_pre_i(w, s2, p, pi)); case 1: *r = w; return 1; } pari_err_BUG("double_eta_root"); return 0;/*LCOV_EXCL_LINE*/ } /* F = double_eta_Fl(inv, p) */ static GEN Flx_double_eta_xpoly(GEN F, ulong j, ulong p, ulong pi) { GEN u = gel(F,1), v = gel(F,2), w; long i, k = itos(gel(F,3)), lu = lg(u), lv = lg(v), lw = lu + 1; w = cgetg(lw, t_VECSMALL); /* lu >= max(lv,k) */ w[1] = 0; /* variable number */ for (i = 1; i < lv; i++) uel(w, i + 1) = Fl_add(uel(u, i), Fl_mul_pre(j, uel(v, i), p, pi), p); for ( ; i < lu; i++) uel(w, i + 1) = uel(u, i); uel(w, k + 2) = Fl_add(uel(w, k + 2), Fl_sqr_pre(j, p, pi), p); return Flx_renormalize(w, lw); } /* F = double_eta_Fl(inv, p) */ static GEN Flx_double_eta_jpoly(GEN F, ulong x, ulong p, ulong pi) { pari_sp av = avma; GEN u = gel(F,1), v = gel(F,2), xs; long k = itos(gel(F,3)); ulong a, b, c; /* u is always longest and the length is bigger than k */ xs = Fl_powers_pre(x, lg(u) - 1, p, pi); c = Flv_dotproduct_pre(u, xs, p, pi); b = Flv_dotproduct_pre(v, xs, p, pi); a = uel(xs, k + 1); avma = av; return mkvecsmall4(0, c, b, a); } /* reduce F = double_eta_raw(inv) mod p */ static GEN double_eta_raw_to_Fl(GEN f, ulong p) { GEN u = ZV_to_Flv(gel(f,1), p); GEN v = ZV_to_Flv(gel(f,2), p); return mkvec3(u, v, gel(f,3)); } /* double_eta_raw(inv) mod p */ static GEN double_eta_Fl(long inv, ulong p) { return double_eta_raw_to_Fl(double_eta_raw(inv), p); } /* Go through roots of Psi(X,j) until one has an double_eta_exponent(inv)-th * root, and return that root. F = double_eta_Fl(inv,p) */ INLINE ulong modinv_double_eta_from_j(GEN F, long inv, ulong j, ulong p, ulong pi, ulong s2) { pari_sp av = avma; long i; ulong f = ULONG_MAX; GEN a = Flx_double_eta_xpoly(F, j, p, pi); a = Flx_roots(a, p); for (i = 1; i < lg(a); ++i) if (double_eta_root(inv, &f, uel(a, i), p, pi, s2)) break; if (i == lg(a)) pari_err_BUG("modinv_double_eta_from_j"); avma = av; return f; } /* assume j1 != j2 */ static long modinv_double_eta_from_2j( ulong *r, long inv, ulong j1, ulong j2, ulong p, ulong pi, ulong s2) { pari_sp av = avma; GEN f, g, d, F = double_eta_Fl(inv, p); f = Flx_double_eta_xpoly(F, j1, p, pi); g = Flx_double_eta_xpoly(F, j2, p, pi); d = Flx_gcd(f, g, p); /* NB: Morally the next conditional should be written as follows, but, * because of the case when j1 or j2 may not have the correct endomorphism * ring, we need to use the less strict conditional underneath */ #if 0 if (degpol(d) != 1 || (*r = Flx_oneroot(d, p)) == p || ! double_eta_root(inv, r, *r, p, pi, s2)) pari_err_BUG("modinv_double_eta_from_2j"); #endif if (degpol(d) > 2 || (*r = Flx_oneroot(d, p)) == p || ! double_eta_root(inv, r, *r, p, pi, s2)) return 0; avma = av; return 1; } long modfn_unambiguous_root(ulong *r, long inv, ulong j0, norm_eqn_t ne, GEN jdb) { pari_sp av = avma; long p1, p2, v = ne->v, p1_depth; ulong j1, p = ne->p, pi = ne->pi, s2 = ne->s2; GEN phi; (void) modinv_degree(&p1, &p2, inv); p1_depth = u_lval(v, p1); phi = polmodular_db_getp(jdb, p1, p); if (!next_surface_nbr(&j1, phi, p1, p1_depth, j0, NULL, p, pi)) pari_err_BUG("modfn_unambiguous_root"); if (p2 == p1) { if (!next_surface_nbr(&j1, phi, p1, p1_depth, j1, &j0, p, pi)) pari_err_BUG("modfn_unambiguous_root"); } else { long p2_depth = u_lval(v, p2); phi = polmodular_db_getp(jdb, p2, p); if (!next_surface_nbr(&j1, phi, p2, p2_depth, j1, NULL, p, pi)) pari_err_BUG("modfn_unambiguous_root"); } avma = av; return j1 != j0 && modinv_double_eta_from_2j(r, inv, j0, j1, p, pi, s2); } ulong modfn_root(ulong j, norm_eqn_t ne, long inv) { ulong f, p = ne->p, pi = ne->pi, s2 = ne->s2; switch (inv) { case INV_J: return j; case INV_G2: return Fl_sqrtl_pre(j, 3, p, pi); case INV_F: return modinv_f_from_j(j, p, pi, s2, 0); case INV_F2: f = modinv_f_from_j(j, p, pi, s2, 0); return Fl_sqr_pre(f, p, pi); case INV_F3: return modinv_f3_from_j(j, p, pi, s2); case INV_F4: f = modinv_f_from_j(j, p, pi, s2, 0); return Fl_sqr_pre(Fl_sqr_pre(f, p, pi), p, pi); case INV_F8: return modinv_f_from_j(j, p, pi, s2, 1); } if (modinv_is_double_eta(inv)) { pari_sp av = avma; ulong f = modinv_double_eta_from_j(double_eta_Fl(inv,p), inv, j, p, pi, s2); avma = av; return f; } pari_err_BUG("modfn_root"); return ULONG_MAX;/*LCOV_EXCL_LINE*/ } INLINE ulong modinv_j_from_f(ulong x, ulong n, ulong p, ulong pi) { /* If x satisfies (X^24 - 16)^3 - X^24 * j = 0 * then j = (x^24 - 16)^3 / x^24 */ ulong x24 = Fl_powu_pre(x, 24 / n, p, pi); return Fl_div(Fl_powu_pre(Fl_sub(x24, 16 % p, p), 3, p, pi), x24, p); } /* TODO: Check whether I can use this to refactor something * F = double_eta_raw(inv) */ long modinv_j_from_2double_eta( GEN F, long inv, ulong *j, ulong x0, ulong x1, ulong p, ulong pi) { GEN f, g, d; x0 = double_eta_power(inv, x0, p, pi); x1 = double_eta_power(inv, x1, p, pi); F = double_eta_raw_to_Fl(F, p); f = Flx_double_eta_jpoly(F, x0, p, pi); g = Flx_double_eta_jpoly(F, x1, p, pi); d = Flx_gcd(f, g, p); if (degpol(d) > 1) pari_err_BUG("modinv_j_from_2double_eta"); else if (degpol(d) < 1) return 0; if (j) *j = Flx_deg1_root(d, p); return 1; } INLINE ulong modfn_preimage(ulong x, norm_eqn_t ne, long inv) { ulong p = ne->p, pi = ne->pi; switch (inv) { case INV_J: return x; case INV_G2: return Fl_powu_pre(x, 3, p, pi); /* NB: could replace these with a single call modinv_j_from_f(x,inv,p,pi) * but avoid the dependence on the actual value of inv */ case INV_F: return modinv_j_from_f(x, 1, p, pi); case INV_F2: return modinv_j_from_f(x, 2, p, pi); case INV_F3: return modinv_j_from_f(x, 3, p, pi); case INV_F4: return modinv_j_from_f(x, 4, p, pi); case INV_F8: return modinv_j_from_f(x, 8, p, pi); } /* NB: This function should never be called if modinv_double_eta(inv) is * true */ pari_err_BUG("modfn_preimage"); return ULONG_MAX;/*LCOV_EXCL_LINE*/ } /** * SECTION: class group bb_group. */ INLINE GEN mkqfis(long a, long b, long c) { retmkqfi(stoi(a), stoi(b), stoi(c)); } /** * SECTION: Fixed-length dot-product-like functions on Fl's with * precomputed inverse. */ /* Computes x0y1 + y0x1 (mod p); assumes p < 2^63. */ INLINE ulong Fl_addmul2( ulong x0, ulong x1, ulong y0, ulong y1, ulong p, ulong pi) { return Fl_addmulmul_pre(x0,y1,y0,x1,p,pi); } /* Computes x0y2 + x1y1 + x2y0 (mod p); assumes p < 2^62. */ INLINE ulong Fl_addmul3( ulong x0, ulong x1, ulong x2, ulong y0, ulong y1, ulong y2, ulong p, ulong pi) { ulong l0, l1, h0, h1; LOCAL_OVERFLOW; LOCAL_HIREMAINDER; l0 = mulll(x0, y2); h0 = hiremainder; l1 = mulll(x1, y1); h1 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); l0 = mulll(x2, y0); h0 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); return remll_pre(h1, l1, p, pi); } /* Computes x0y3 + x1y2 + x2y1 + x3y0 (mod p); assumes p < 2^62. */ INLINE ulong Fl_addmul4( ulong x0, ulong x1, ulong x2, ulong x3, ulong y0, ulong y1, ulong y2, ulong y3, ulong p, ulong pi) { ulong l0, l1, h0, h1; LOCAL_OVERFLOW; LOCAL_HIREMAINDER; l0 = mulll(x0, y3); h0 = hiremainder; l1 = mulll(x1, y2); h1 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); l0 = mulll(x2, y1); h0 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); l0 = mulll(x3, y0); h0 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); return remll_pre(h1, l1, p, pi); } /* Computes x0y4 + x1y3 + x2y2 + x3y1 + x4y0 (mod p); assumes p < 2^62. */ INLINE ulong Fl_addmul5( ulong x0, ulong x1, ulong x2, ulong x3, ulong x4, ulong y0, ulong y1, ulong y2, ulong y3, ulong y4, ulong p, ulong pi) { ulong l0, l1, h0, h1; LOCAL_OVERFLOW; LOCAL_HIREMAINDER; l0 = mulll(x0, y4); h0 = hiremainder; l1 = mulll(x1, y3); h1 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); l0 = mulll(x2, y2); h0 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); l0 = mulll(x3, y1); h0 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); l0 = mulll(x4, y0); h0 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); return remll_pre(h1, l1, p, pi); } /* A polmodular database for a given class invariant consists of a t_VEC whose * L-th entry is 0 or a GEN pointing to Phi_L. This function produces a pair * of databases corresponding to the j-invariant and inv */ GEN polmodular_db_init(long inv) { GEN res, jdb, fdb; enum { DEFAULT_MODPOL_DB_LEN = 32 }; res = cgetg_block(2 + 1, t_VEC); jdb = zerovec_block(DEFAULT_MODPOL_DB_LEN); gel(res, 1) = jdb; if (inv != INV_J) { fdb = zerovec_block(DEFAULT_MODPOL_DB_LEN); gel(res, 2) = fdb; } else { gel(res, 2) = gen_0; } return res; } void polmodular_db_add_level(GEN *DB, long L, long inv) { long max_L; GEN db; if (inv == INV_J) { db = gel(*DB, 1); } else { db = gel(*DB, 2); if ( isintzero(db)) pari_err_BUG("polmodular_db_add_level"); } max_L = lg(db) - 1; if (L > max_L) { GEN newdb; long i, newlen = 2 * L; newdb = cgetg_block(newlen + 1, t_VEC); for (i = 1; i <= max_L; ++i) gel(newdb, i) = gel(db, i); for ( ; i <= newlen; ++i) gel(newdb, i) = gen_0; killblock(db); gel(*DB, (inv == INV_J)? 1: 2) = db = newdb; } if (typ(gel(db, L)) == t_INT) { pari_sp av = avma; GEN x = polmodular0_ZM(L, inv, NULL, NULL, 0, DB); /* may set db[L] */ GEN y = gel(db, L); gel(db, L) = gclone(x); if (typ(y) != t_INT) gunclone(y); avma = av; } } void polmodular_db_add_levels(GEN *db, long *levels, long k, long inv) { long i; for (i = 0; i < k; ++i) polmodular_db_add_level(db, levels[i], inv); } GEN polmodular_db_for_inv(GEN db, long inv) { return (inv == INV_J)? gel(db,1): gel(db,2); } /* TODO: Also cache modpoly mod p for most recent p (avoid repeated * reductions in, for example, polclass.c:oneroot_of_classpoly(). */ GEN polmodular_db_getp(GEN db, long L, ulong p) { GEN f = gel(db, L); if (isintzero(f)) pari_err_BUG("polmodular_db_getp"); return ZM_to_Flm(f, p); } /** * SECTION: Table of discriminants to use. */ typedef struct { long GENcode0; /* used when serializing the struct to a t_VECSMALL */ long inv; /* invariant */ long L; /* modpoly level */ long D0; /* fundamental discriminant */ long D1; /* chosen discriminant */ long L0; /* first generator norm */ long L1; /* second generator norm */ long n1; /* order of L0 in cl(D1) */ long n2; /* order of L0 in cl(D2) where D2 = L^2 D1 */ long dl1; /* m such that L0^m = L in cl(D1) */ long dl2_0; /* These two are (m, n) such that L0^m L1^n = form of norm L^2 in D2 */ long dl2_1; /* This n is always 1 or 0. */ /* this part is not serialized */ long nprimes; /* number of primes needed for D1 */ long cost; /* cost to enumerate subgroup of cl(L^2D): subgroup size is n2 if L1=0, 2*n2 o.w. */ long bits; ulong *primes; ulong *traces; } disc_info; #define MODPOLY_MAX_DCNT 64 /* Flag for last parameter of discriminant_with_classno_at_least. * Warning: ignoring the sparse factor makes everything slower by * something like (sparse factor)^3. */ #define USE_SPARSE_FACTOR 0 #define IGNORE_SPARSE_FACTOR 1 static long discriminant_with_classno_at_least(disc_info Ds[MODPOLY_MAX_DCNT], long L, long inv, long ignore_sparse); /** * SECTION: Hard-coded evaluation functions for modular polynomials of * small level. */ /* Based on phi2_eval_ff() in Sutherland's classpoly programme. * Calculates Phi_2(X, j) (mod p) with 6M+7A (4 reductions, not * counting those for Phi_2) */ INLINE GEN Flm_Fl_phi2_evalx(GEN phi2, ulong j, ulong p, ulong pi) { GEN res = cgetg(6, t_VECSMALL); ulong j2, t1; res[1] = 0; /* variable name */ j2 = Fl_sqr_pre(j, p, pi); t1 = Fl_add(j, coeff(phi2, 3, 1), p); t1 = Fl_addmul2(j, j2, t1, coeff(phi2, 2, 1), p, pi); res[2] = Fl_add(t1, coeff(phi2, 1, 1), p); t1 = Fl_addmul2(j, j2, coeff(phi2, 3, 2), coeff(phi2, 2, 2), p, pi); res[3] = Fl_add(t1, coeff(phi2, 2, 1), p); t1 = Fl_mul_pre(j, coeff(phi2, 3, 2), p, pi); t1 = Fl_add(t1, coeff(phi2, 3, 1), p); res[4] = Fl_sub(t1, j2, p); res[5] = 1; return res; } /* Based on phi3_eval_ff() in Sutherland's classpoly programme. * Calculates Phi_3(X, j) (mod p) with 13M+13A (6 reductions, not * counting those for Phi_3) */ INLINE GEN Flm_Fl_phi3_evalx(GEN phi3, ulong j, ulong p, ulong pi) { GEN res = cgetg(7, t_VECSMALL); ulong j2, j3, t1; res[1] = 0; /* variable name */ j2 = Fl_sqr_pre(j, p, pi); j3 = Fl_mul_pre(j, j2, p, pi); t1 = Fl_add(j, coeff(phi3, 4, 1), p); res[2] = Fl_addmul3(j, j2, j3, t1, coeff(phi3, 3, 1), coeff(phi3, 2, 1), p, pi); t1 = Fl_addmul3(j, j2, j3, coeff(phi3, 4, 2), coeff(phi3, 3, 2), coeff(phi3, 2, 2), p, pi); res[3] = Fl_add(t1, coeff(phi3, 2, 1), p); t1 = Fl_addmul3(j, j2, j3, coeff(phi3, 4, 3), coeff(phi3, 3, 3), coeff(phi3, 3, 2), p, pi); res[4] = Fl_add(t1, coeff(phi3, 3, 1), p); t1 = Fl_addmul2(j, j2, coeff(phi3, 4, 3), coeff(phi3, 4, 2), p, pi); t1 = Fl_add(t1, coeff(phi3, 4, 1), p); res[5] = Fl_sub(t1, j3, p); res[6] = 1; return res; } /* Based on phi5_eval_ff() in Sutherland's classpoly programme. * Calculates Phi_5(X, j) (mod p) with 33M+31A (10 reductions, not * counting those for Phi_5) */ INLINE GEN Flm_Fl_phi5_evalx(GEN phi5, ulong j, ulong p, ulong pi) { GEN res = cgetg(9, t_VECSMALL); ulong j2, j3, j4, j5, t1; res[1] = 0; /* variable name */ j2 = Fl_sqr_pre(j, p, pi); j3 = Fl_mul_pre(j, j2, p, pi); j4 = Fl_sqr_pre(j2, p, pi); j5 = Fl_mul_pre(j, j4, p, pi); t1 = Fl_add(j, coeff(phi5, 6, 1), p); t1 = Fl_addmul5(j, j2, j3, j4, j5, t1, coeff(phi5, 5, 1), coeff(phi5, 4, 1), coeff(phi5, 3, 1), coeff(phi5, 2, 1), p, pi); res[2] = Fl_add(t1, coeff(phi5, 1, 1), p); t1 = Fl_addmul5(j, j2, j3, j4, j5, coeff(phi5, 6, 2), coeff(phi5, 5, 2), coeff(phi5, 4, 2), coeff(phi5, 3, 2), coeff(phi5, 2, 2), p, pi); res[3] = Fl_add(t1, coeff(phi5, 2, 1), p); t1 = Fl_addmul5(j, j2, j3, j4, j5, coeff(phi5, 6, 3), coeff(phi5, 5, 3), coeff(phi5, 4, 3), coeff(phi5, 3, 3), coeff(phi5, 3, 2), p, pi); res[4] = Fl_add(t1, coeff(phi5, 3, 1), p); t1 = Fl_addmul5(j, j2, j3, j4, j5, coeff(phi5, 6, 4), coeff(phi5, 5, 4), coeff(phi5, 4, 4), coeff(phi5, 4, 3), coeff(phi5, 4, 2), p, pi); res[5] = Fl_add(t1, coeff(phi5, 4, 1), p); t1 = Fl_addmul5(j, j2, j3, j4, j5, coeff(phi5, 6, 5), coeff(phi5, 5, 5), coeff(phi5, 5, 4), coeff(phi5, 5, 3), coeff(phi5, 5, 2), p, pi); res[6] = Fl_add(t1, coeff(phi5, 5, 1), p); t1 = Fl_addmul4(j, j2, j3, j4, coeff(phi5, 6, 5), coeff(phi5, 6, 4), coeff(phi5, 6, 3), coeff(phi5, 6, 2), p, pi); t1 = Fl_add(t1, coeff(phi5, 6, 1), p); res[7] = Fl_sub(t1, j5, p); res[8] = 1; return res; } GEN Flm_Fl_polmodular_evalx(GEN phi, long L, ulong j, ulong p, ulong pi) { switch (L) { case 2: return Flm_Fl_phi2_evalx(phi, j, p, pi); case 3: return Flm_Fl_phi3_evalx(phi, j, p, pi); case 5: return Flm_Fl_phi5_evalx(phi, j, p, pi); default: { /* not GC clean, but gerepileupto-safe */ GEN j_powers = Fl_powers_pre(j, L + 1, p, pi); return Flm_Flc_mul_pre_Flx(phi, j_powers, p, pi, 0); } } } /** * SECTION: Velu's formula for the codmain curve in the case of small * prime base field. */ INLINE ulong Fl_mul4(ulong x, ulong p) { return Fl_double(Fl_double(x, p), p); } INLINE ulong Fl_mul5(ulong x, ulong p) { return Fl_add(x, Fl_mul4(x, p), p); } INLINE ulong Fl_mul8(ulong x, ulong p) { return Fl_double(Fl_mul4(x, p), p); } INLINE ulong Fl_mul6(ulong x, ulong p) { return Fl_sub(Fl_mul8(x, p), Fl_double(x, p), p); } INLINE ulong Fl_mul7(ulong x, ulong p) { return Fl_sub(Fl_mul8(x, p), x, p); } /* Given an elliptic curve E = [a4, a6] over F_p and a non-zero point * pt on E, return the quotient E' = E/

= [a4_img, a6_img] */ static void Fle_quotient_from_kernel_generator( ulong *a4_img, ulong *a6_img, ulong a4, ulong a6, GEN pt, ulong p, ulong pi) { pari_sp av = avma; ulong t = 0, w = 0; GEN Q; ulong xQ, yQ, tQ, uQ; Q = gcopy(pt); /* Note that, as L is odd, say L = 2n + 1, we necessarily have * [(L - 1)/2]P = [n]P = [n - L]P = -[n + 1]P = -[(L + 1)/2]P. This is * what the condition Q[1] != xQ tests, so the loop will execute n times. */ do { xQ = uel(Q, 1); yQ = uel(Q, 2); /* tQ = 6 xQ^2 + b2 xQ + b4 * = 6 xQ^2 + 2 a4 (since b2 = 0 and b4 = 2 a4) */ tQ = Fl_add(Fl_mul6(Fl_sqr_pre(xQ, p, pi), p), Fl_double(a4, p), p); uQ = Fl_add(Fl_mul4(Fl_sqr_pre(yQ, p, pi), p), Fl_mul_pre(tQ, xQ, p, pi), p); t = Fl_add(t, tQ, p); w = Fl_add(w, uQ, p); Q = gerepileupto(av, Fle_add(pt, Q, a4, p)); } while (uel(Q, 1) != xQ); avma = av; /* a4_img = a4 - 5 * t */ *a4_img = Fl_sub(a4, Fl_mul5(t, p), p); /* a6_img = a6 - b2 * t - 7 * w = a6 - 7 * w (since a1 = a2 = 0 ==> b2 = 0) */ *a6_img = Fl_sub(a6, Fl_mul7(w, p), p); } /** * SECTION: Calculation of modular polynomials. */ /* Given an elliptic curve [a4, a6] over FF_p, try to find a * non-trivial L-torsion point on the curve by considering n times a * random point; val controls the maximum L-valuation expected of n * times a random point */ static GEN find_L_tors_point( ulong *ival, ulong a4, ulong a6, ulong p, ulong pi, ulong n, ulong L, ulong val) { pari_sp av = avma; ulong i; GEN P, Q; do { Q = random_Flj_pre(a4, a6, p, pi); P = Flj_mulu_pre(Q, n, a4, p, pi); } while (P[3] == 0); for (i = 0; i < val; ++i) { Q = Flj_mulu_pre(P, L, a4, p, pi); if (Q[3] == 0) break; P = Q; } if (ival) *ival = i; return gerepilecopy(av, P); } static GEN select_curve_with_L_tors_point( ulong *a4, ulong *a6, ulong L, ulong j, ulong n, ulong card, ulong val, norm_eqn_t ne) { pari_sp av = avma; ulong A4, A4t, A6, A6t; ulong p = ne->p, pi = ne->pi; GEN P; if (card % L != 0) { pari_err_BUG("select_curve_with_L_tors_point: " "Cardinality not divisible by L"); } Fl_ellj_to_a4a6(j, p, &A4, &A6); Fl_elltwist_disc(A4, A6, ne->T, p, &A4t, &A6t); /* Either E = [a4, a6] or its twist has cardinality divisible by L * because of the choice of p and t earlier on. We find out which * by attempting to find a point of order L on each. See bot p16 of * Sutherland 2012. */ while (1) { ulong i; P = find_L_tors_point(&i, A4, A6, p, pi, n, L, val); if (i < val) break; avma = av; lswap(A4, A4t); lswap(A6, A6t); } *a4 = A4; *a6 = A6; return gerepilecopy(av, P); } /* Return 1 if the L-Sylow subgroup of the curve [a4, a6] (mod p) is * cyclic, return 0 if it is not cyclic with "high" probability (I * guess around 1/L^3 chance it is still cyclic when we return 0). * * Based on Sutherland's velu.c:velu_verify_Sylow_cyclic() in classpoly-1.0.1 */ INLINE long verify_L_sylow_is_cyclic(long e, ulong a4, ulong a6, ulong p, ulong pi) { /* Number of times to try to find a point with maximal order in the * L-Sylow subgroup. */ enum { N_RETRIES = 3 }; pari_sp av = avma; long i, res = 0; GEN P; for (i = 0; i < N_RETRIES; ++i) { P = random_Flj_pre(a4, a6, p, pi); P = Flj_mulu_pre(P, e, a4, p, pi); if (P[3] != 0) { res = 1; break; } } avma = av; return res; } static ulong find_noniso_L_isogenous_curve( ulong L, ulong n, norm_eqn_t ne, long e, ulong val, ulong a4, ulong a6, GEN init_pt, long verify) { pari_sp ltop, av; ulong p = ne->p, pi = ne->pi, j_res = 0; GEN pt = init_pt; ltop = av = avma; while (1) { /* c. Use Velu to calculate L-isogenous curve E' = E/

*/ ulong a4_img, a6_img; ulong z2 = Fl_sqr_pre(pt[3], p, pi); pt = mkvecsmall2(Fl_div(pt[1], z2, p), Fl_div(pt[2], Fl_mul_pre(z2, pt[3], p, pi), p)); Fle_quotient_from_kernel_generator(&a4_img, &a6_img, a4, a6, pt, p, pi); /* d. If j(E') = j_res has a different endo ring to j(E), then * return j(E'). Otherwise, go to b. */ if (!verify || verify_L_sylow_is_cyclic(e, a4_img, a6_img, p, pi)) { j_res = Fl_ellj_pre(a4_img, a6_img, p, pi); break; } /* b. Generate random point P on E of order L */ avma = av; pt = find_L_tors_point(NULL, a4, a6, p, pi, n, L, val); } avma = ltop; return j_res; } /* Given a prime L and a j-invariant j (mod p), return the j-invariant * of a curve which has a different endomorphism ring to j and is * L-isogenous to j */ INLINE ulong compute_L_isogenous_curve( ulong L, ulong n, norm_eqn_t ne, ulong j, ulong card, ulong val, long verify) { ulong a4, a6; long e; GEN pt; if (ne->p < 5 || j == 0 || j == 1728 % ne->p) pari_err_BUG("compute_L_isogenous_curve"); pt = select_curve_with_L_tors_point(&a4, &a6, L, j, n, card, val, ne); e = card / L; if (e * L != card) pari_err_BUG("compute_L_isogenous_curve"); return find_noniso_L_isogenous_curve(L, n, ne, e, val, a4, a6, pt, verify); } INLINE GEN get_Lsqr_cycle(const disc_info *dinfo) { long i, n1 = dinfo->n1, L = dinfo->L; GEN cyc = cgetg(L, t_VECSMALL); cyc[1] = 0; for (i = 2; i <= L / 2; ++i) cyc[i] = cyc[i - 1] + n1; if ( ! dinfo->L1) { for ( ; i < L; ++i) cyc[i] = cyc[i - 1] + n1; } else { cyc[L - 1] = 2 * dinfo->n2 - n1 / 2; for (i = L - 2; i > L / 2; --i) cyc[i] = cyc[i + 1] - n1; } return cyc; } INLINE void update_Lsqr_cycle(GEN cyc, const disc_info *dinfo) { long i, L = dinfo->L; for (i = 1; i < L; ++i) ++cyc[i]; if (dinfo->L1 && cyc[L - 1] == 2 * dinfo->n2) { long n1 = dinfo->n1; for (i = L / 2 + 1; i < L; ++i) cyc[i] -= n1; } } static ulong oneroot_of_classpoly( GEN hilb, GEN factu, norm_eqn_t ne, GEN jdb) { pari_sp av = avma; ulong j0, p = ne->p, pi = ne->pi; long i, nfactors = lg(gel(factu, 1)) - 1; GEN hilbp = ZX_to_Flx(hilb, p); /* TODO: Work out how to use hilb with better invariant */ j0 = Flx_oneroot_split(hilbp, p); if (j0 == p) { pari_err_BUG("oneroot_of_classpoly: " "Didn't find a root of the class polynomial"); } for (i = 1; i <= nfactors; ++i) { long L = gel(factu, 1)[i]; long val = gel(factu, 2)[i]; GEN phi = polmodular_db_getp(jdb, L, p); val += z_lval(ne->v, L); j0 = descend_volcano(phi, j0, p, pi, 0, L, val, val); avma = av; } avma = av; return j0; } /* TODO: Precompute the classgp_pcp_t structs and link them to dinfo */ INLINE void make_pcp_surface(const disc_info *dinfo, classgp_pcp_t G) { long k = 1, datalen = 3 * k; memset(G, 0, sizeof *G); G->_data = cgetg(datalen + 1, t_VECSMALL); G->L = G->_data + 1; G->n = G->L + k; G->o = G->L + k; G->k = k; G->h = G->enum_cnt = dinfo->n1; G->L[0] = dinfo->L0; G->n[0] = dinfo->n1; G->o[0] = dinfo->n1; } INLINE void make_pcp_floor(const disc_info *dinfo, classgp_pcp_t G) { long k = dinfo->L1 ? 2 : 1, datalen = 3 * k; memset(G, 0, sizeof *G); G->_data = cgetg(datalen + 1, t_VECSMALL); G->L = G->_data + 1; G->n = G->L + k; G->o = G->L + k; G->k = k; G->h = G->enum_cnt = dinfo->n2 * k; G->L[0] = dinfo->L0; G->n[0] = dinfo->n2; G->o[0] = dinfo->n2; if (dinfo->L1) { G->L[1] = dinfo->L1; G->n[1] = 2; G->o[1] = 2; } } INLINE GEN enum_volcano_surface(const disc_info *dinfo, norm_eqn_t ne, ulong j0, GEN fdb) { pari_sp av = avma; classgp_pcp_t G; make_pcp_surface(dinfo, G); return gerepileupto(av, enum_roots(j0, ne, fdb, G)); } INLINE GEN enum_volcano_floor(long L, norm_eqn_t ne, ulong j0_pr, GEN fdb, const disc_info *dinfo) { pari_sp av = avma; /* L^2 D is the discriminant for the order R = Z + L OO. */ long DR = L * L * ne->D; long R_cond = L * ne->u; /* conductor(DR); */ long w = R_cond * ne->v; /* TODO: Calculate these once and for all in polmodular0_ZM(). */ classgp_pcp_t G; norm_eqn_t eqn; memcpy(eqn, ne, sizeof *ne); eqn->D = DR; eqn->u = R_cond; eqn->v = w; make_pcp_floor(dinfo, G); return gerepileupto(av, enum_roots(j0_pr, eqn, fdb, G)); } INLINE void carray_reverse_inplace(long *arr, long n) { long lim = n>>1, i; --n; for (i = 0; i < lim; i++) lswap(arr[i], arr[n - i]); } INLINE void append_neighbours(GEN rts, GEN surface_js, long njs, long L, long m, long i) { long r_idx = (((i - 1) + m) % njs) + 1; /* (i + m) % njs */ long l_idx = smodss((i - 1) - m, njs) + 1; /* (i - m) % njs */ rts[L] = surface_js[l_idx]; rts[L + 1] = surface_js[r_idx]; } INLINE GEN roots_to_coeffs(GEN rts, ulong p, long L) { long i, k, lrts= lg(rts); GEN M = cgetg(L+2+1, t_MAT); for (i = 1; i <= L+2; ++i) gel(M, i) = cgetg(lrts, t_VECSMALL); for (i = 1; i < lrts; ++i) { pari_sp av = avma; GEN modpol = Flv_roots_to_pol(gel(rts, i), p, 0); for (k = 1; k <= L + 2; ++k) mael(M, k, i) = modpol[k + 1]; avma = av; } return M; } /* NB: Assumes indices are offset at 0, not at 1 like in GENs; * i.e. indices[i] will pick out v[indices[i] + 1] from v. */ INLINE void vecsmall_pick(GEN res, GEN v, GEN indices) { long i; for (i = 1; i < lg(indices); ++i) res[i] = v[indices[i] + 1]; } /* First element of surface_js must lie above the first element of floor_js. * Reverse surface_js if it is not oriented in the same direction as floor_js */ INLINE GEN root_matrix(long L, const disc_info *dinfo, long njinvs, GEN surface_js, GEN floor_js, ulong n, ulong card, ulong val, norm_eqn_t ne) { pari_sp av; long i, m = dinfo->dl1, njs = lg(surface_js) - 1, inv = dinfo->inv, rev; GEN rt_mat = zero_Flm_copy(L + 1, njinvs), rts, cyc; av = avma; i = 1; cyc = get_Lsqr_cycle(dinfo); rts = gel(rt_mat, i); vecsmall_pick(rts, floor_js, cyc); append_neighbours(rts, surface_js, njs, L, m, i); i = 2; update_Lsqr_cycle(cyc, dinfo); rts = gel(rt_mat, i); vecsmall_pick(rts, floor_js, cyc); /* Fix orientation if necessary */ if (modinv_is_double_eta(inv)) { /* TODO: There is potential for refactoring between this, * double_eta_initial_js and modfn_preimage. */ pari_sp av0 = avma; ulong p = ne->p, pi = ne->pi, j; GEN F = double_eta_Fl(inv, p); pari_sp av = avma; ulong r1 = double_eta_power(inv, uel(rts, 1), p, pi); GEN r, f = Flx_double_eta_jpoly(F, r1, p, pi); if ((j = Flx_oneroot(f, p)) == p) pari_err_BUG("root_matrix"); j = compute_L_isogenous_curve(L, n, ne, j, card, val, 0); avma = av; r1 = double_eta_power(inv, uel(surface_js, i), p, pi); f = Flx_double_eta_jpoly(F, r1, p, pi); r = Flx_roots(f, p); if (lg(r) != 3) pari_err_BUG("root_matrix"); rev = (j != uel(r, 1)) && (j != uel(r, 2)); avma = av0; } else { ulong j1pr, j1; j1pr = modfn_preimage(uel(rts, 1), ne, dinfo->inv); j1 = compute_L_isogenous_curve(L, n, ne, j1pr, card, val, 0); rev = j1 != modfn_preimage(uel(surface_js, i), ne, dinfo->inv); } if (rev) carray_reverse_inplace(surface_js + 2, njs - 1); append_neighbours(rts, surface_js, njs, L, m, i); for (i = 3; i <= njinvs; ++i) { update_Lsqr_cycle(cyc, dinfo); rts = gel(rt_mat, i); vecsmall_pick(rts, floor_js, cyc); append_neighbours(rts, surface_js, njs, L, m, i); } avma = av; return rt_mat; } INLINE void interpolate_coeffs(GEN phi_modp, ulong p, GEN j_invs, GEN coeff_mat) { pari_sp av = avma; long i; GEN pols = Flv_Flm_polint(j_invs, coeff_mat, p, 0); for (i = 1; i < lg(pols); ++i) { GEN pol = gel(pols, i); long k, maxk = lg(pol); for (k = 2; k < maxk; ++k) coeff(phi_modp, k - 1, i) = pol[k]; } avma = av; } INLINE long Flv_lastnonzero(GEN v) { long i; for (i = lg(v) - 1; i > 0; --i) if (v[i]) break; return i; } /* Assuming the matrix of coefficients in phi corresponds to polynomials * phi_k^* satisfying Y^c phi_k^*(Y^s) for c in {0, 1, ..., s} satisfying * c + Lk = L + 1 (mod s), change phi so that the coefficients are for the * polynomials Y^c phi_k^*(Y^s) (s is the sparsity factor) */ INLINE void inflate_polys(GEN phi, long L, long s) { long k, deg = L + 1; long maxr; maxr = nbrows(phi); for (k = 0; k <= deg; ) { long i, c = smodss(L * (1 - k) + 1, s); /* TODO: We actually know that the last non-zero element of gel(phi, k) * can't be later than index n+1, where n is about (L + 1)/s. */ ++k; for (i = Flv_lastnonzero(gel(phi, k)); i > 0; --i) { long r = c + (i - 1) * s + 1; if (r > maxr) { coeff(phi, i, k) = 0; continue; } if (r != i) { coeff(phi, r, k) = coeff(phi, i, k); coeff(phi, i, k) = 0; } } } } INLINE void Flv_powu_inplace_pre(GEN v, ulong n, ulong p, ulong pi) { long i; for (i = 1; i < lg(v); ++i) v[i] = Fl_powu_pre(v[i], n, p, pi); } INLINE void normalise_coeffs(GEN coeffs, GEN js, long L, long s, ulong p, ulong pi) { pari_sp av = avma; long k; GEN pows, modinv_js; /* NB: In fact it would be correct to return the coefficients "as is" when * s = 1, but we make that an error anyway since this function should never * be called with s = 1. */ if (s <= 1) pari_err_BUG("normalise_coeffs"); /* pows[i + 1] contains 1 / js[i + 1]^i for i = 0, ..., s - 1. */ pows = cgetg(s + 1, t_VEC); gel(pows, 1) = const_vecsmall(lg(js) - 1, 1); modinv_js = Flv_inv_pre(js, p, pi); gel(pows, 2) = modinv_js; for (k = 3; k <= s; ++k) { gel(pows, k) = gcopy(modinv_js); Flv_powu_inplace_pre(gel(pows, k), k - 1, p, pi); } /* For each column of coefficients coeffs[k] = [a0 .. an], * replace ai by ai / js[i]^c. * Said in another way, normalise each row i of coeffs by * dividing through by js[i - 1]^c (where c depends on i). */ for (k = 1; k < lg(coeffs); ++k) { long i, c = smodss(L * (1 - (k - 1)) + 1, s); GEN col = gel(coeffs, k), C = gel(pows, c + 1); for (i = 1; i < lg(col); ++i) col[i] = Fl_mul_pre(col[i], C[i], p, pi); } avma = av; } INLINE void double_eta_initial_js( ulong *x0, ulong *x0pr, ulong j0, ulong j0pr, norm_eqn_t ne, long inv, ulong L, ulong n, ulong card, ulong val) { pari_sp av0 = avma; ulong p = ne->p, pi = ne->pi, s2 = ne->s2; GEN F = double_eta_Fl(inv, p); pari_sp av = avma; ulong j1pr, j1, r, t; GEN f, g; *x0pr = modinv_double_eta_from_j(F, inv, j0pr, p, pi, s2); t = double_eta_power(inv, *x0pr, p, pi); f = Flx_div_by_X_x(Flx_double_eta_jpoly(F, t, p, pi), j0pr, p, &r); if (r) pari_err_BUG("double_eta_initial_js"); j1pr = Flx_deg1_root(f, p); avma = av; j1 = compute_L_isogenous_curve(L, n, ne, j1pr, card, val, 0); f = Flx_double_eta_xpoly(F, j0, p, pi); g = Flx_double_eta_xpoly(F, j1, p, pi); /* x0 is the unique common root of f and g */ *x0 = Flx_deg1_root(Flx_gcd(f, g, p), p); avma = av0; if ( ! double_eta_root(inv, x0, *x0, p, pi, s2)) pari_err_BUG("double_eta_initial_js"); } /* This is Sutherland 2012, Algorithm 2.1, p16. */ static GEN polmodular_split_p_Flm(ulong L, GEN hilb, GEN factu, norm_eqn_t ne, GEN db, const disc_info *dinfo) { ulong j0, j0_rt, j0pr, j0pr_rt; ulong n, card, val, p = ne->p, pi = ne->pi; long s = modinv_sparse_factor(dinfo->inv); long nj_selected = ceil((L + 1)/(double)s) + 1; GEN surface_js, floor_js, rts; GEN phi_modp; GEN jdb, fdb; long switched_signs = 0; jdb = polmodular_db_for_inv(db, INV_J); fdb = polmodular_db_for_inv(db, dinfo->inv); /* Precomputation */ card = p + 1 - ne->t; val = u_lvalrem(card, L, &n); /* n = card / L^{v_L(card)} */ j0 = oneroot_of_classpoly(hilb, factu, ne, jdb); j0pr = compute_L_isogenous_curve(L, n, ne, j0, card, val, 1); if (modinv_is_double_eta(dinfo->inv)) { double_eta_initial_js(&j0_rt, &j0pr_rt, j0, j0pr, ne, dinfo->inv, L, n, card, val); } else { j0_rt = modfn_root(j0, ne, dinfo->inv); j0pr_rt = modfn_root(j0pr, ne, dinfo->inv); } surface_js = enum_volcano_surface(dinfo, ne, j0_rt, fdb); floor_js = enum_volcano_floor(L, ne, j0pr_rt, fdb, dinfo); rts = root_matrix(L, dinfo, nj_selected, surface_js, floor_js, n, card, val, ne); do { pari_sp btop = avma; long i; GEN coeffs, surf; coeffs = roots_to_coeffs(rts, p, L); surf = vecsmall_shorten(surface_js, nj_selected); if (s > 1) { normalise_coeffs(coeffs, surf, L, s, p, pi); Flv_powu_inplace_pre(surf, s, p, pi); } phi_modp = zero_Flm_copy(L + 2, L + 2); interpolate_coeffs(phi_modp, p, surf, coeffs); if (s > 1) inflate_polys(phi_modp, L, s); /* TODO: Calculate just this coefficient of X^L Y^L, so we can do this * test, then calculate the other coefficients; at the moment we are * sometimes doing all the roots-to-coeffs, normalisation and interpolation * work twice. */ if (ucoeff(phi_modp, L + 1, L + 1) == p - 1) break; if (switched_signs) pari_err_BUG("polmodular_split_p_Flm"); avma = btop; for (i = 1; i < lg(rts); ++i) { surface_js[i] = Fl_neg(surface_js[i], p); coeff(rts, L, i) = Fl_neg(coeff(rts, L, i), p); coeff(rts, L + 1, i) = Fl_neg(coeff(rts, L + 1, i), p); } switched_signs = 1; } while (1); dbg_printf(4)(" Phi_%lu(X, Y) (mod %lu) = %Ps\n", L, p, phi_modp); return phi_modp; } INLINE void norm_eqn_update(norm_eqn_t ne, GEN vne, ulong t, ulong p, long L) { long res; ulong vL_sqr, vL; ne->D = vne[1]; ne->u = vne[2]; ne->t = t; ne->p = p; ne->pi = get_Fl_red(p); ne->s2 = Fl_2gener_pre(p, ne->pi); vL_sqr = (4 * p - t * t) / -ne->D; res = uissquareall(vL_sqr, &vL); if (!res || vL % L) pari_err_BUG("norm_eqn_update"); ne->v = vL; /* select twisting parameter */ do ne->T = random_Fl(p); while (krouu(ne->T, p) != -1); } INLINE void Flv_deriv_pre_inplace(GEN v, long deg, ulong p, ulong pi) { long i, ln = lg(v), d = deg % p; for (i = ln - 1; i > 1; --i, --d) v[i] = Fl_mul_pre(v[i - 1], d, p, pi); v[1] = 0; } INLINE GEN eval_modpoly_modp(GEN Tp, GEN j_powers, norm_eqn_t ne, int compute_derivs) { ulong p = ne->p, pi = ne->pi; long L = lg(j_powers) - 3; GEN j_pows_p = ZV_to_Flv(j_powers, p); GEN tmp = cgetg(2 + 2 * compute_derivs, t_VEC); /* We wrap the result in this t_VEC Tp to trick the * ZM_*_CRT() functions into thinking it's a matrix. */ gel(tmp, 1) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi); if (compute_derivs) { Flv_deriv_pre_inplace(j_pows_p, L + 1, p, pi); gel(tmp, 2) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi); Flv_deriv_pre_inplace(j_pows_p, L + 1, p, pi); gel(tmp, 3) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi); } return tmp; } /* Parallel interface */ GEN polmodular_worker(ulong p, ulong t, ulong L, GEN hilb, GEN factu, GEN vne, GEN vinfo, long derivs, GEN j_powers, GEN fdb) { pari_sp av = avma; norm_eqn_t ne; GEN Tp; norm_eqn_update(ne, vne, t, p, L); Tp = polmodular_split_p_Flm(L, hilb, factu, ne, fdb, (const disc_info*)vinfo); if (!isintzero(j_powers)) Tp = eval_modpoly_modp(Tp, j_powers, ne, derivs); return gerepileupto(av, Tp); } static GEN sympol_to_ZM(GEN phi, long L) { pari_sp av = avma; GEN res = zeromatcopy(L + 2, L + 2); long i, j, c = 1; for (i = 1; i <= L + 1; ++i) for (j = 1; j <= i; ++j, ++c) gcoeff(res, i, j) = gcoeff(res, j, i) = gel(phi, c); gcoeff(res, L + 2, 1) = gcoeff(res, 1, L + 2) = gen_1; return gerepilecopy(av, res); } static GEN polmodular_small_ZM(long L, long inv, GEN *db); INLINE long modinv_max_internal_level(long inv) { switch (inv) { case INV_J: return 5; case INV_G2: return 2; case INV_F: case INV_F2: case INV_F4: case INV_F8: return 5; case INV_W2W5: case INV_W2W5E2: return 7; case INV_W2W3: case INV_W2W3E2: case INV_W3W3: case INV_W3W7: return 5; case INV_W3W3E2:return 2; case INV_F3: case INV_W2W7: case INV_W2W7E2: case INV_W2W13: return 3; case INV_W3W5: case INV_W5W7: case INV_W3W13: return 2; } pari_err_BUG("modinv_max_internal_level"); return LONG_MAX;/*LCOV_EXCL_LINE*/ } GEN polmodular0_ZM(long L, long inv, GEN J, GEN Q, int compute_derivs, GEN *db) { pari_sp ltop = avma; long k, d, Dcnt, nprimes = 0; GEN modpoly, plist; disc_info Ds[MODPOLY_MAX_DCNT]; long lvl = modinv_level(inv); if (ugcd(L, lvl) != 1) pari_err_DOMAIN("polmodular0_ZM", "invariant", "incompatible with", stoi(L), stoi(lvl)); dbg_printf(1)("Calculating modular polynomial of level %lu for invariant %d\n", L, inv); if (L <= modinv_max_internal_level(inv)) return polmodular_small_ZM(L,inv,db); Dcnt = discriminant_with_classno_at_least(Ds, L, inv, USE_SPARSE_FACTOR); for (d = 0; d < Dcnt; d++) nprimes += Ds[d].nprimes; modpoly = cgetg(nprimes+1, t_VEC); plist = cgetg(nprimes+1, t_VECSMALL); for (d = 0, k = 1; d < Dcnt; d++) { disc_info *dinfo = &Ds[d]; struct pari_mt pt; const long D = dinfo->D1, DK = dinfo->D0; const ulong cond = usqrt(D / DK); long i, pending = 0; GEN worker, j_powers, factu, hilb; polmodular_db_add_level(db, dinfo->L0, inv); if (dinfo->L1) polmodular_db_add_level(db, dinfo->L1, inv); factu = factoru(cond); dbg_printf(1)("Selected discriminant D = %ld = %ld^2 * %ld.\n", D,cond,DK); hilb = polclass0(DK, INV_J, 0, db); if (cond > 1) polmodular_db_add_levels(db, zv_to_longptr(gel(factu,1)), lg(gel(factu,1))-1, INV_J); dbg_printf(1)("D = %ld, L0 = %lu, L1 = %lu, ", dinfo->D1, dinfo->L0, dinfo->L1); dbg_printf(1)("n1 = %lu, n2 = %lu, dl1 = %lu, dl2_0 = %lu, dl2_1 = %lu\n", dinfo->n1, dinfo->n2, dinfo->dl1, dinfo->dl2_0, dinfo->dl2_1); dbg_printf(0)("Calculating modular polynomial of level %lu:", L); j_powers = gen_0; if (J) { compute_derivs = !!compute_derivs; j_powers = Fp_powers(J, L+1, Q); } worker = strtoclosure("_polmodular_worker", 8, utoi(L), hilb, factu, mkvecsmall2(D, cond), (GEN)dinfo, stoi(compute_derivs), j_powers, *db); mt_queue_start_lim(&pt, worker, dinfo->nprimes); for (i = 0; i < dinfo->nprimes || pending; i++) { GEN done; long workid; ulong p = dinfo->primes[i], t = dinfo->traces[i]; mt_queue_submit(&pt, p, i < dinfo->nprimes? mkvec2(utoi(p), utoi(t)): NULL); done = mt_queue_get(&pt, &workid, &pending); if (done) { gel(modpoly, k) = done; plist[k] = workid; k++; dbg_printf(0)(" %ld%%", k*100/nprimes); } } dbg_printf(0)("\n"); mt_queue_end(&pt); killblock((GEN)dinfo->primes); } modpoly = nmV_chinese_center(modpoly, plist, NULL); if (J) modpoly = FpM_red(modpoly, Q); return gerepileupto(ltop, modpoly); } GEN polmodular_ZM(long L, long inv) { GEN db, Phi; if (L < 2) pari_err_DOMAIN("polmodular_ZM", "L", "<", gen_2, stoi(L)); /* TODO: Handle non-prime L. This is Algorithm 1.1 and Corollary * 3.4 in Sutherland, "Class polynomials for nonholomorphic modular * functions". */ if ( ! uisprime(L)) pari_err_IMPL("composite level"); db = polmodular_db_init(inv); Phi = polmodular0_ZM(L, inv, NULL, NULL, 0, &db); gunclone_deep(db); return Phi; } GEN polmodular_ZXX(long L, long inv, long vx, long vy) { pari_sp av = avma; GEN phi = polmodular_ZM(L, inv); if (vx < 0) vx = 0; if (vy < 0) vy = 1; if (varncmp(vx, vy) >= 0) pari_err_PRIORITY("polmodular_ZXX", pol_x(vx), "<=", vy); return gerepilecopy(av, RgM_to_RgXX(phi, vx, vy)); } INLINE GEN FpV_deriv(GEN v, long deg, GEN P) { long i, ln = lg(v); GEN dv = cgetg(ln, t_VEC); for (i = ln - 1; i > 1; --i, --deg) gel(dv, i) = Fp_mulu(gel(v, i - 1), deg, P); gel(dv, 1) = gen_0; return dv; } GEN Fp_polmodular_evalx( long L, long inv, GEN J, GEN P, long v, int compute_derivs) { pari_sp av = avma; GEN db, phi; if (L <= modinv_max_internal_level(inv)) { GEN tmp; GEN phi = RgM_to_FpM(polmodular_ZM(L, inv), P); GEN j_powers = Fp_powers(J, L + 1, P); GEN modpol = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v); if (compute_derivs) { tmp = cgetg(4, t_VEC); gel(tmp, 1) = modpol; j_powers = FpV_deriv(j_powers, L + 1, P); gel(tmp, 2) = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v); j_powers = FpV_deriv(j_powers, L + 1, P); gel(tmp, 3) = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v); } else tmp = modpol; return gerepilecopy(av, tmp); } db = polmodular_db_init(inv); phi = polmodular0_ZM(L, inv, J, P, compute_derivs, &db); phi = RgM_to_RgXV(phi, v); gunclone_deep(db); return gerepilecopy(av, compute_derivs ? phi : gel(phi, 1)); } GEN polmodular(long L, long inv, GEN x, long v, long compute_derivs) { pari_sp av = avma; long tx; GEN J = NULL, P = NULL, res = NULL, one = NULL; check_modinv(inv); if ( ! x || gequalX(x)) { long xv = 0; if (x) xv = varn(x); if (compute_derivs) pari_err_FLAG("polmodular"); return polmodular_ZXX(L, inv, xv, v); } tx = typ(x); if (tx == t_INTMOD) { J = gel(x, 2); P = gel(x, 1); one = mkintmod(gen_1, P); } else if (tx == t_FFELT) { J = FF_to_FpXQ_i(x); if (degpol(J) > 0) pari_err_DOMAIN("polmodular", "x", "not in prime subfield ", gen_0, x); J = constant_coeff(J); P = FF_p_i(x); one = p_to_FF(P, 0); } else { pari_err_TYPE("polmodular", x); } if (v < 0) v = 1; res = Fp_polmodular_evalx(L, inv, J, P, v, compute_derivs); res = gmul(res, one); return gerepileupto(av, res); } /** * SECTION: Modular polynomials of level <= MAX_INTERNAL_MODPOLY_LEVEL. */ /* These functions return a vector of unique coefficients of classical * modular polynomials \Phi_L(X, Y) of small level L. The number of * such coefficients is (L + 1)(L + 2)/2 since \Phi is symmetric. * (Note that we omit the common coefficient of X^{L + 1} and Y^{L + 1} since * it is always 1.) See sympol_to_ZM() for how to interpret the coefficients, * and use that function to get the corresponding full (desymmetrised) matrix * of coefficients. */ /* Phi2, the modular polynomial of level 2: * * X^3 * + X^2 * (-Y^2 + 1488*Y - 162000) * + X * (1488*Y^2 + 40773375*Y + 8748000000) * + Y^3 - 162000*Y^2 + 8748000000*Y - 157464000000000 * * [[3, 0, 1], * [2, 2, -1], * [2, 1, 1488], * [2, 0, -162000], * [1, 1, 40773375], * [1, 0, 8748000000], * [0, 0, -157464000000000]], */ static GEN phi2_ZV(void) { GEN phi2 = cgetg(7, t_VEC); gel(phi2, 1) = uu32toi(36662, 1908994048); setsigne(gel(phi2, 1), -1); gel(phi2, 2) = uu32toi(2, 158065408); gel(phi2, 3) = stoi(40773375); gel(phi2, 4) = stoi(-162000); gel(phi2, 5) = stoi(1488); gel(phi2, 6) = gen_m1; return phi2; } /* L = 3 * * [4, 0, 1], * [3, 3, -1], * [3, 2, 2232], * [3, 1, -1069956], * [3, 0, 36864000], * [2, 2, 2587918086], * [2, 1, 8900222976000], * [2, 0, 452984832000000], * [1, 1, -770845966336000000], * [1, 0, 1855425871872000000000] * [0, 0, 0] * * X^4 * + X^3 (-Y^3 + 2232*Y^2 - 1069956*Y + 36864000) * + X^2 (2232*Y^3 + 2587918086*Y^2 + 8900222976000*Y + 452984832000000) * + X (-1069956*Y^3 + 8900222976000*Y^2 - 770845966336000000*Y + 1855425871872000000000) * + Y^4 + 36864000*Y^3 + 452984832000000*Y^2 + 1855425871872000000000*Y * * 1855425871872000000000 == 2^32 * (100 * 2^32 + 2503270400) */ static GEN phi3_ZV(void) { GEN phi3 = cgetg(11, t_VEC); pari_sp av = avma; gel(phi3, 1) = gen_0; gel(phi3, 2) = gerepileupto(av, shifti(uu32toi(100, 2503270400UL), 32)); gel(phi3, 3) = uu32toi(179476562, 2147483648UL); setsigne(gel(phi3, 3), -1); gel(phi3, 4) = uu32toi(105468, 3221225472UL); gel(phi3, 5) = uu32toi(2072, 1050738688); gel(phi3, 6) = utoi(2587918086UL); gel(phi3, 7) = stoi(36864000); gel(phi3, 8) = stoi(-1069956); gel(phi3, 9) = stoi(2232); gel(phi3, 10) = gen_m1; return phi3; } static GEN phi5_ZV(void) { GEN phi5 = cgetg(22, t_VEC); gel(phi5, 1) = mkintn(5, 0x18c2cc9cUL, 0x484382b2UL, 0xdc000000UL, 0x0UL, 0x0UL); gel(phi5, 2) = mkintn(5, 0x2638fUL, 0x2ff02690UL, 0x68026000UL, 0x0UL, 0x0UL); gel(phi5, 3) = mkintn(5, 0x308UL, 0xac9d9a4UL, 0xe0fdab12UL, 0xc0000000UL, 0x0UL); setsigne(gel(phi5, 3), -1); gel(phi5, 4) = mkintn(5, 0x13UL, 0xaae09f9dUL, 0x1b5ef872UL, 0x30000000UL, 0x0UL); gel(phi5, 5) = mkintn(4, 0x1b802fa9UL, 0x77ba0653UL, 0xd2f78000UL, 0x0UL); gel(phi5, 6) = mkintn(4, 0xfbfdUL, 0x278e4756UL, 0xdf08a7c4UL, 0x40000000UL); gel(phi5, 7) = mkintn(4, 0x35f922UL, 0x62ccea6fUL, 0x153d0000UL, 0x0UL); gel(phi5, 8) = mkintn(4, 0x97dUL, 0x29203fafUL, 0xc3036909UL, 0x80000000UL); setsigne(gel(phi5, 8), -1); gel(phi5, 9) = mkintn(3, 0x56e9e892UL, 0xd7781867UL, 0xf2ea0000UL); gel(phi5, 10) = mkintn(3, 0x5d6dUL, 0xe0a58f4eUL, 0x9ee68c14UL); setsigne(gel(phi5, 10), -1); gel(phi5, 11) = mkintn(3, 0x1100dUL, 0x85cea769UL, 0x40000000UL); gel(phi5, 12) = mkintn(3, 0x1b38UL, 0x43cf461fUL, 0x3a900000UL); gel(phi5, 13) = mkintn(3, 0x14UL, 0xc45a616eUL, 0x4801680fUL); gel(phi5, 14) = uu32toi(0x17f4350UL, 0x493ca3e0UL); gel(phi5, 15) = uu32toi(0x183UL, 0xe54ce1f8UL); gel(phi5, 16) = uu32toi(0x1c9UL, 0x18860000UL); gel(phi5, 17) = uu32toi(0x39UL, 0x6f7a2206UL); setsigne(gel(phi5, 17), -1); gel(phi5, 18) = stoi(2028551200); gel(phi5, 19) = stoi(-4550940); gel(phi5, 20) = stoi(3720); gel(phi5, 21) = gen_m1; return phi5; } static GEN phi5_f_ZV(void) { GEN phi = zerovec(21); gel(phi, 3) = stoi(4); gel(phi, 21) = gen_m1; return phi; } static GEN phi3_f3_ZV(void) { GEN phi = zerovec(10); gel(phi, 3) = stoi(8); gel(phi, 10) = gen_m1; return phi; } static GEN phi2_g2_ZV(void) { GEN phi = zerovec(6); gel(phi, 1) = stoi(-54000); gel(phi, 3) = stoi(495); gel(phi, 6) = gen_m1; return phi; } static GEN phi5_w2w3_ZV(void) { GEN phi = zerovec(21); gel(phi, 3) = gen_m1; gel(phi, 10) = stoi(5); gel(phi, 21) = gen_m1; return phi; } static GEN phi7_w2w5_ZV(void) { GEN phi = zerovec(36); gel(phi, 3) = gen_m1; gel(phi, 15) = stoi(56); gel(phi, 19) = stoi(42); gel(phi, 24) = stoi(21); gel(phi, 30) = stoi(7); gel(phi, 36) = gen_m1; return phi; } static GEN phi5_w3w3_ZV(void) { GEN phi = zerovec(21); gel(phi, 3) = stoi(9); gel(phi, 6) = stoi(-15); gel(phi, 15) = stoi(5); gel(phi, 21) = gen_m1; return phi; } static GEN phi3_w2w7_ZV(void) { GEN phi = zerovec(10); gel(phi, 3) = gen_m1; gel(phi, 6) = stoi(3); gel(phi, 10) = gen_m1; return phi; } static GEN phi2_w3w5_ZV(void) { GEN phi = zerovec(6); gel(phi, 3) = gen_1; gel(phi, 6) = gen_m1; return phi; } static GEN phi5_w3w7_ZV(void) { GEN phi = zerovec(21); gel(phi, 3) = gen_m1; gel(phi, 6) = stoi(10); gel(phi, 8) = stoi(5); gel(phi, 10) = stoi(35); gel(phi, 13) = stoi(20); gel(phi, 15) = stoi(10); gel(phi, 17) = stoi(5); gel(phi, 19) = stoi(5); gel(phi, 21) = gen_m1; return phi; } static GEN phi3_w2w13_ZV(void) { GEN phi = zerovec(10); gel(phi, 3) = gen_m1; gel(phi, 6) = stoi(3); gel(phi, 8) = stoi(3); gel(phi, 10) = gen_m1; return phi; } static GEN phi2_w3w3e2_ZV(void) { GEN phi = zerovec(6); gel(phi, 3) = stoi(3); gel(phi, 6) = gen_m1; return phi; } static GEN phi2_w5w7_ZV(void) { GEN phi = zerovec(6); gel(phi, 3) = gen_1; gel(phi, 5) = gen_2; gel(phi, 6) = gen_m1; return phi; } static GEN phi2_w3w13_ZV(void) { GEN phi = zerovec(6); gel(phi, 3) = gen_m1; gel(phi, 5) = gen_2; gel(phi, 6) = gen_m1; return phi; } INLINE long modinv_parent(long inv) { switch (inv) { case INV_F2: case INV_F4: case INV_F8: return INV_F; case INV_W2W3E2: return INV_W2W3; case INV_W2W5E2: return INV_W2W5; case INV_W2W7E2: return INV_W2W7; case INV_W3W3E2: return INV_W3W3; default: pari_err_BUG("modinv_parent"); return -1;/*LCOV_EXCL_LINE*/ } } /* TODO: Think of a better name than "parent power"; sheesh. */ INLINE long modinv_parent_power(long inv) { switch (inv) { case INV_F4: return 4; case INV_F8: return 8; case INV_F2: case INV_W2W3E2: case INV_W2W5E2: case INV_W2W7E2: case INV_W3W3E2: return 2; default: pari_err_BUG("modinv_parent_power"); return -1;/*LCOV_EXCL_LINE*/ } } static GEN polmodular0_powerup_ZM(long L, long inv, GEN *db) { pari_sp ltop = avma, av; long s, D, nprimes, N; GEN mp, pol, P, H; long parent = modinv_parent(inv); long e = modinv_parent_power(inv); disc_info Ds[MODPOLY_MAX_DCNT]; /* FIXME: We throw away the table of fundamental discriminants here. */ long nDs = discriminant_with_classno_at_least(Ds, L, inv, IGNORE_SPARSE_FACTOR); if (nDs != 1) pari_err_BUG("polmodular0_powerup_ZM"); D = Ds[0].D1; nprimes = Ds[0].nprimes + 1; mp = polmodular0_ZM(L, parent, NULL, NULL, 0, db); H = polclass0(D, parent, 0, db); N = L + 2; if (degpol(H) < N) pari_err_BUG("polmodular0_powerup_ZM"); av = avma; pol = ZM_init_CRT(zero_Flm_copy(N, L + 2), 1); P = gen_1; for (s = 1; s < nprimes; ++s) { pari_sp av1, av2; ulong p = Ds[0].primes[s-1], pi = get_Fl_red(p); long i; GEN Hrts, js, Hp, Phip, coeff_mat, phi_modp; phi_modp = zero_Flm_copy(N, L + 2); av1 = avma; Hp = ZX_to_Flx(H, p); Hrts = Flx_roots(Hp, p); if (lg(Hrts)-1 < N) pari_err_BUG("polmodular0_powerup_ZM"); js = cgetg(N + 1, t_VECSMALL); for (i = 1; i <= N; ++i) uel(js, i) = Fl_powu_pre(uel(Hrts, i), e, p, pi); Phip = ZM_to_Flm(mp, p); coeff_mat = zero_Flm_copy(N, L + 2); av2 = avma; for (i = 1; i <= N; ++i) { long k; GEN phi_at_ji, mprts; phi_at_ji = Flm_Fl_polmodular_evalx(Phip, L, uel(Hrts, i), p, pi); mprts = Flx_roots(phi_at_ji, p); if (lg(mprts) != L + 2) pari_err_BUG("polmodular0_powerup_ZM"); Flv_powu_inplace_pre(mprts, e, p, pi); phi_at_ji = Flv_roots_to_pol(mprts, p, 0); for (k = 1; k <= L + 2; ++k) ucoeff(coeff_mat, i, k) = uel(phi_at_ji, k + 1); avma = av2; } interpolate_coeffs(phi_modp, p, js, coeff_mat); avma = av1; (void) ZM_incremental_CRT(&pol, phi_modp, &P, p); if (gc_needed(av, 2)) gerepileall(av, 2, &pol, &P); } killblock((GEN)Ds[0].primes); return gerepileupto(ltop, pol); } /* Returns the modular polynomial with the smallest level for the given * invariant, except if inv is INV_J, in which case return the modular * polynomial of level L in {2,3,5}. NULL is returned if the modular * polynomial can be calculated using polmodular0_powerup_ZM. */ INLINE GEN internal_db(long L, long inv) { switch (inv) { case INV_J: switch (L) { case 2: return phi2_ZV(); case 3: return phi3_ZV(); case 5: return phi5_ZV(); default: break; } case INV_F: return phi5_f_ZV(); case INV_F2: return NULL; case INV_F3: return phi3_f3_ZV(); case INV_F4: return NULL; case INV_G2: return phi2_g2_ZV(); case INV_W2W3: return phi5_w2w3_ZV(); case INV_F8: return NULL; case INV_W3W3: return phi5_w3w3_ZV(); case INV_W2W5: return phi7_w2w5_ZV(); case INV_W2W7: return phi3_w2w7_ZV(); case INV_W3W5: return phi2_w3w5_ZV(); case INV_W3W7: return phi5_w3w7_ZV(); case INV_W2W3E2: return NULL; case INV_W2W5E2: return NULL; case INV_W2W13: return phi3_w2w13_ZV(); case INV_W2W7E2: return NULL; case INV_W3W3E2: return phi2_w3w3e2_ZV(); case INV_W5W7: return phi2_w5w7_ZV(); case INV_W3W13: return phi2_w3w13_ZV(); } pari_err_BUG("internal_db"); return NULL; } /* NB: Should only be called if L <= modinv_max_internal_level(inv) */ static GEN polmodular_small_ZM(long L, long inv, GEN *db) { GEN f = internal_db(L, inv); if (!f) return polmodular0_powerup_ZM(L, inv, db); return sympol_to_ZM(f, L); } /* Each function phi_w?w?_j() returns a vector V containing two * vectors u and v, and a scalar k, which together represent the * bivariate polnomial * * phi(X, Y) = \sum_i u[i] X^i + Y \sum_i v[i] X^i + Y^2 X^k */ static GEN phi_w2w3_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(14, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoineg(0x3cUL); gel(phi0, 3) = utoi(0x702UL); gel(phi0, 4) = utoineg(0x797cUL); gel(phi0, 5) = utoi(0x5046fUL); gel(phi0, 6) = utoineg(0x1be0b8UL); gel(phi0, 7) = utoi(0x28ef9cUL); gel(phi0, 8) = utoi(0x15e2968UL); gel(phi0, 9) = utoi(0x1b8136fUL); gel(phi0, 10) = utoi(0xa67674UL); gel(phi0, 11) = utoi(0x23982UL); gel(phi0, 12) = utoi(0x294UL); gel(phi0, 13) = gen_1; phi1 = cgetg(13, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_m1; gel(phi1, 4) = utoi(0x23UL); gel(phi1, 5) = utoineg(0xaeUL); gel(phi1, 6) = utoineg(0x5b8UL); gel(phi1, 7) = utoi(0x12d7UL); gel(phi1, 8) = utoineg(0x7c86UL); gel(phi1, 9) = utoi(0x37c8UL); gel(phi1, 10) = utoineg(0x69cUL); gel(phi1, 11) = utoi(0x48UL); gel(phi1, 12) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(5); return phi; } static GEN phi_w3w3_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(14, t_VEC); gel(phi0, 1) = utoi(0x2d9UL); gel(phi0, 2) = utoi(0x4fbcUL); gel(phi0, 3) = utoi(0x5828aUL); gel(phi0, 4) = utoi(0x3a7a3cUL); gel(phi0, 5) = utoi(0x1bd8edfUL); gel(phi0, 6) = utoi(0x8348838UL); gel(phi0, 7) = utoi(0x1983f8acUL); gel(phi0, 8) = utoi(0x14e4e098UL); gel(phi0, 9) = utoi(0x69ed1a7UL); gel(phi0, 10) = utoi(0xc3828cUL); gel(phi0, 11) = utoi(0x2696aUL); gel(phi0, 12) = utoi(0x2acUL); gel(phi0, 13) = gen_1; phi1 = cgetg(13, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = utoineg(0x1bUL); gel(phi1, 3) = utoineg(0x5d6UL); gel(phi1, 4) = utoineg(0x1c7bUL); gel(phi1, 5) = utoi(0x7980UL); gel(phi1, 6) = utoi(0x12168UL); gel(phi1, 7) = utoineg(0x3528UL); gel(phi1, 8) = utoineg(0x6174UL); gel(phi1, 9) = utoi(0x2208UL); gel(phi1, 10) = utoineg(0x41dUL); gel(phi1, 11) = utoi(0x36UL); gel(phi1, 12) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = gen_2; return phi; } static GEN phi_w2w5_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(20, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoineg(0x2aUL); gel(phi0, 3) = utoi(0x549UL); gel(phi0, 4) = utoineg(0x6530UL); gel(phi0, 5) = utoi(0x60504UL); gel(phi0, 6) = utoineg(0x3cbbc8UL); gel(phi0, 7) = utoi(0x1d1ee74UL); gel(phi0, 8) = utoineg(0x7ef9ab0UL); gel(phi0, 9) = utoi(0x12b888beUL); gel(phi0, 10) = utoineg(0x15fa174cUL); gel(phi0, 11) = utoi(0x615d9feUL); gel(phi0, 12) = utoi(0xbeca070UL); gel(phi0, 13) = utoineg(0x88de74cUL); gel(phi0, 14) = utoineg(0x2b3a268UL); gel(phi0, 15) = utoi(0x24b3244UL); gel(phi0, 16) = utoi(0xb56270UL); gel(phi0, 17) = utoi(0x25989UL); gel(phi0, 18) = utoi(0x2a6UL); gel(phi0, 19) = gen_1; phi1 = cgetg(19, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_m1; gel(phi1, 4) = utoi(0x1eUL); gel(phi1, 5) = utoineg(0xffUL); gel(phi1, 6) = utoi(0x243UL); gel(phi1, 7) = utoineg(0xf3UL); gel(phi1, 8) = utoineg(0x5c4UL); gel(phi1, 9) = utoi(0x107bUL); gel(phi1, 10) = utoineg(0x11b2fUL); gel(phi1, 11) = utoi(0x48fa8UL); gel(phi1, 12) = utoineg(0x6ff7cUL); gel(phi1, 13) = utoi(0x4bf48UL); gel(phi1, 14) = utoineg(0x187efUL); gel(phi1, 15) = utoi(0x404cUL); gel(phi1, 16) = utoineg(0x582UL); gel(phi1, 17) = utoi(0x3cUL); gel(phi1, 18) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(7); return phi; } static GEN phi_w2w7_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(26, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoineg(0x24UL); gel(phi0, 3) = utoi(0x4ceUL); gel(phi0, 4) = utoineg(0x5d60UL); gel(phi0, 5) = utoi(0x62b05UL); gel(phi0, 6) = utoineg(0x47be78UL); gel(phi0, 7) = utoi(0x2a3880aUL); gel(phi0, 8) = utoineg(0x114bccf4UL); gel(phi0, 9) = utoi(0x4b95e79aUL); gel(phi0, 10) = utoineg(0xe2cfee1cUL); gel(phi0, 11) = uu32toi(0x1UL, 0xe43d1126UL); gel(phi0, 12) = uu32toineg(0x2UL, 0xf04dc6f8UL); gel(phi0, 13) = uu32toi(0x3UL, 0x5384987dUL); gel(phi0, 14) = uu32toineg(0x2UL, 0xa5ccbe18UL); gel(phi0, 15) = uu32toi(0x1UL, 0x4c52c8a6UL); gel(phi0, 16) = utoineg(0x2643fdecUL); gel(phi0, 17) = utoineg(0x49f5ab66UL); gel(phi0, 18) = utoi(0x33074d3cUL); gel(phi0, 19) = utoineg(0x6a3e376UL); gel(phi0, 20) = utoineg(0x675aa58UL); gel(phi0, 21) = utoi(0x2674005UL); gel(phi0, 22) = utoi(0xba5be0UL); gel(phi0, 23) = utoi(0x2644eUL); gel(phi0, 24) = utoi(0x2acUL); gel(phi0, 25) = gen_1; phi1 = cgetg(25, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_m1; gel(phi1, 4) = utoi(0x1cUL); gel(phi1, 5) = utoineg(0x10aUL); gel(phi1, 6) = utoi(0x3f0UL); gel(phi1, 7) = utoineg(0x5d3UL); gel(phi1, 8) = utoi(0x3efUL); gel(phi1, 9) = utoineg(0x102UL); gel(phi1, 10) = utoineg(0x5c8UL); gel(phi1, 11) = utoi(0x102fUL); gel(phi1, 12) = utoineg(0x13f8aUL); gel(phi1, 13) = utoi(0x86538UL); gel(phi1, 14) = utoineg(0x1bbd10UL); gel(phi1, 15) = utoi(0x3614e8UL); gel(phi1, 16) = utoineg(0x42f793UL); gel(phi1, 17) = utoi(0x364698UL); gel(phi1, 18) = utoineg(0x1c7a10UL); gel(phi1, 19) = utoi(0x97cc8UL); gel(phi1, 20) = utoineg(0x1fc8aUL); gel(phi1, 21) = utoi(0x4210UL); gel(phi1, 22) = utoineg(0x524UL); gel(phi1, 23) = utoi(0x38UL); gel(phi1, 24) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(9); return phi; } static GEN phi_w2w13_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(44, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoineg(0x1eUL); gel(phi0, 3) = utoi(0x45fUL); gel(phi0, 4) = utoineg(0x5590UL); gel(phi0, 5) = utoi(0x64407UL); gel(phi0, 6) = utoineg(0x53a792UL); gel(phi0, 7) = utoi(0x3b21af3UL); gel(phi0, 8) = utoineg(0x20d056d0UL); gel(phi0, 9) = utoi(0xe02db4a6UL); gel(phi0, 10) = uu32toineg(0x4UL, 0xb23400b0UL); gel(phi0, 11) = uu32toi(0x14UL, 0x57fbb906UL); gel(phi0, 12) = uu32toineg(0x49UL, 0xcf80c00UL); gel(phi0, 13) = uu32toi(0xdeUL, 0x84ff421UL); gel(phi0, 14) = uu32toineg(0x244UL, 0xc500c156UL); gel(phi0, 15) = uu32toi(0x52cUL, 0x79162979UL); gel(phi0, 16) = uu32toineg(0xa64UL, 0x8edc5650UL); gel(phi0, 17) = uu32toi(0x1289UL, 0x4225bb41UL); gel(phi0, 18) = uu32toineg(0x1d89UL, 0x2a15229aUL); gel(phi0, 19) = uu32toi(0x2a3eUL, 0x4539f1ebUL); gel(phi0, 20) = uu32toineg(0x366aUL, 0xa5ea1130UL); gel(phi0, 21) = uu32toi(0x3f47UL, 0xa19fecb4UL); gel(phi0, 22) = uu32toineg(0x4282UL, 0x91a3c4a0UL); gel(phi0, 23) = uu32toi(0x3f30UL, 0xbaa305b4UL); gel(phi0, 24) = uu32toineg(0x3635UL, 0xd11c2530UL); gel(phi0, 25) = uu32toi(0x29e2UL, 0x89df27ebUL); gel(phi0, 26) = uu32toineg(0x1d03UL, 0x6509d48aUL); gel(phi0, 27) = uu32toi(0x11e2UL, 0x272cc601UL); gel(phi0, 28) = uu32toineg(0x9b0UL, 0xacd58ff0UL); gel(phi0, 29) = uu32toi(0x485UL, 0x608d7db9UL); gel(phi0, 30) = uu32toineg(0x1bfUL, 0xa941546UL); gel(phi0, 31) = uu32toi(0x82UL, 0x56e48b21UL); gel(phi0, 32) = uu32toineg(0x13UL, 0xc36b2340UL); gel(phi0, 33) = uu32toineg(0x5UL, 0x6637257aUL); gel(phi0, 34) = uu32toi(0x5UL, 0x40f70bd0UL); gel(phi0, 35) = uu32toineg(0x1UL, 0xf70842daUL); gel(phi0, 36) = utoi(0x53eea5f0UL); gel(phi0, 37) = utoi(0xda17bf3UL); gel(phi0, 38) = utoineg(0xaf246c2UL); gel(phi0, 39) = utoi(0x278f847UL); gel(phi0, 40) = utoi(0xbf5550UL); gel(phi0, 41) = utoi(0x26f1fUL); gel(phi0, 42) = utoi(0x2b2UL); gel(phi0, 43) = gen_1; phi1 = cgetg(43, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_m1; gel(phi1, 4) = utoi(0x1aUL); gel(phi1, 5) = utoineg(0x111UL); gel(phi1, 6) = utoi(0x5e4UL); gel(phi1, 7) = utoineg(0x1318UL); gel(phi1, 8) = utoi(0x2804UL); gel(phi1, 9) = utoineg(0x3cd6UL); gel(phi1, 10) = utoi(0x467cUL); gel(phi1, 11) = utoineg(0x3cd6UL); gel(phi1, 12) = utoi(0x2804UL); gel(phi1, 13) = utoineg(0x1318UL); gel(phi1, 14) = utoi(0x5e3UL); gel(phi1, 15) = utoineg(0x10dUL); gel(phi1, 16) = utoineg(0x5ccUL); gel(phi1, 17) = utoi(0x100bUL); gel(phi1, 18) = utoineg(0x160e1UL); gel(phi1, 19) = utoi(0xd2cb0UL); gel(phi1, 20) = utoineg(0x4c85fcUL); gel(phi1, 21) = utoi(0x137cb98UL); gel(phi1, 22) = utoineg(0x3c75568UL); gel(phi1, 23) = utoi(0x95c69c8UL); gel(phi1, 24) = utoineg(0x131557bcUL); gel(phi1, 25) = utoi(0x20aacfd0UL); gel(phi1, 26) = utoineg(0x2f9164e6UL); gel(phi1, 27) = utoi(0x3b6a5e40UL); gel(phi1, 28) = utoineg(0x3ff54344UL); gel(phi1, 29) = utoi(0x3b6a9140UL); gel(phi1, 30) = utoineg(0x2f927fa6UL); gel(phi1, 31) = utoi(0x20ae6450UL); gel(phi1, 32) = utoineg(0x131cd87cUL); gel(phi1, 33) = utoi(0x967d1e8UL); gel(phi1, 34) = utoineg(0x3d48ca8UL); gel(phi1, 35) = utoi(0x14333b8UL); gel(phi1, 36) = utoineg(0x5406bcUL); gel(phi1, 37) = utoi(0x10c130UL); gel(phi1, 38) = utoineg(0x27ba1UL); gel(phi1, 39) = utoi(0x433cUL); gel(phi1, 40) = utoineg(0x4c6UL); gel(phi1, 41) = utoi(0x34UL); gel(phi1, 42) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(15); return phi; } static GEN phi_w3w5_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(26, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoi(0x18UL); gel(phi0, 3) = utoi(0xb4UL); gel(phi0, 4) = utoineg(0x178UL); gel(phi0, 5) = utoineg(0x2d7eUL); gel(phi0, 6) = utoineg(0x89b8UL); gel(phi0, 7) = utoi(0x35c24UL); gel(phi0, 8) = utoi(0x128a18UL); gel(phi0, 9) = utoineg(0x12a911UL); gel(phi0, 10) = utoineg(0xcc0190UL); gel(phi0, 11) = utoi(0x94368UL); gel(phi0, 12) = utoi(0x1439d0UL); gel(phi0, 13) = utoi(0x96f931cUL); gel(phi0, 14) = utoineg(0x1f59ff0UL); gel(phi0, 15) = utoi(0x20e7e8UL); gel(phi0, 16) = utoineg(0x25fdf150UL); gel(phi0, 17) = utoineg(0x7091511UL); gel(phi0, 18) = utoi(0x1ef52f8UL); gel(phi0, 19) = utoi(0x341f2de4UL); gel(phi0, 20) = utoi(0x25d72c28UL); gel(phi0, 21) = utoi(0x95d2082UL); gel(phi0, 22) = utoi(0xd2d828UL); gel(phi0, 23) = utoi(0x281f4UL); gel(phi0, 24) = utoi(0x2b8UL); gel(phi0, 25) = gen_1; phi1 = cgetg(25, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_0; gel(phi1, 4) = gen_1; gel(phi1, 5) = utoi(0xfUL); gel(phi1, 6) = utoi(0x2eUL); gel(phi1, 7) = utoineg(0x1fUL); gel(phi1, 8) = utoineg(0x2dUL); gel(phi1, 9) = utoineg(0x5caUL); gel(phi1, 10) = utoineg(0x358UL); gel(phi1, 11) = utoi(0x2f1cUL); gel(phi1, 12) = utoi(0xd8eaUL); gel(phi1, 13) = utoineg(0x38c70UL); gel(phi1, 14) = utoineg(0x1a964UL); gel(phi1, 15) = utoi(0x93512UL); gel(phi1, 16) = utoineg(0x58f2UL); gel(phi1, 17) = utoineg(0x5af1eUL); gel(phi1, 18) = utoi(0x1afb8UL); gel(phi1, 19) = utoi(0xc084UL); gel(phi1, 20) = utoineg(0x7fcbUL); gel(phi1, 21) = utoi(0x1c89UL); gel(phi1, 22) = utoineg(0x32aUL); gel(phi1, 23) = utoi(0x2dUL); gel(phi1, 24) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(8); return phi; } static GEN phi_w3w7_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(34, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoineg(0x14UL); gel(phi0, 3) = utoi(0x82UL); gel(phi0, 4) = utoi(0x1f8UL); gel(phi0, 5) = utoineg(0x2a45UL); gel(phi0, 6) = utoi(0x9300UL); gel(phi0, 7) = utoi(0x32abeUL); gel(phi0, 8) = utoineg(0x19c91cUL); gel(phi0, 9) = utoi(0xc1ba9UL); gel(phi0, 10) = utoi(0x1788f68UL); gel(phi0, 11) = utoineg(0x2b1989cUL); gel(phi0, 12) = utoineg(0x7a92408UL); gel(phi0, 13) = utoi(0x1238d56eUL); gel(phi0, 14) = utoi(0x13dd66a0UL); gel(phi0, 15) = utoineg(0x2dbedca8UL); gel(phi0, 16) = utoineg(0x34282eb8UL); gel(phi0, 17) = utoi(0x2c2a54d2UL); gel(phi0, 18) = utoi(0x98db81a8UL); gel(phi0, 19) = utoineg(0x4088be8UL); gel(phi0, 20) = utoineg(0xe424a220UL); gel(phi0, 21) = utoineg(0x67bbb232UL); gel(phi0, 22) = utoi(0x7dd8bb98UL); gel(phi0, 23) = uu32toi(0x1UL, 0xcaff744UL); gel(phi0, 24) = utoineg(0x1d46a378UL); gel(phi0, 25) = utoineg(0x82fa50f7UL); gel(phi0, 26) = utoineg(0x700ef38cUL); gel(phi0, 27) = utoi(0x20aa202eUL); gel(phi0, 28) = utoi(0x299b3440UL); gel(phi0, 29) = utoi(0xa476c4bUL); gel(phi0, 30) = utoi(0xd80558UL); gel(phi0, 31) = utoi(0x28a32UL); gel(phi0, 32) = utoi(0x2bcUL); gel(phi0, 33) = gen_1; phi1 = cgetg(33, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_0; gel(phi1, 4) = gen_m1; gel(phi1, 5) = utoi(0xeUL); gel(phi1, 6) = utoineg(0x31UL); gel(phi1, 7) = utoineg(0xeUL); gel(phi1, 8) = utoi(0x99UL); gel(phi1, 9) = utoineg(0x8UL); gel(phi1, 10) = utoineg(0x2eUL); gel(phi1, 11) = utoineg(0x5ccUL); gel(phi1, 12) = utoi(0x308UL); gel(phi1, 13) = utoi(0x2904UL); gel(phi1, 14) = utoineg(0x15700UL); gel(phi1, 15) = utoineg(0x2b9ecUL); gel(phi1, 16) = utoi(0xf0966UL); gel(phi1, 17) = utoi(0xb3cc8UL); gel(phi1, 18) = utoineg(0x38241cUL); gel(phi1, 19) = utoineg(0x8604cUL); gel(phi1, 20) = utoi(0x578a64UL); gel(phi1, 21) = utoineg(0x11a798UL); gel(phi1, 22) = utoineg(0x39c85eUL); gel(phi1, 23) = utoi(0x1a5084UL); gel(phi1, 24) = utoi(0xcdeb4UL); gel(phi1, 25) = utoineg(0xb0364UL); gel(phi1, 26) = utoi(0x129d4UL); gel(phi1, 27) = utoi(0x126fcUL); gel(phi1, 28) = utoineg(0x8649UL); gel(phi1, 29) = utoi(0x1aa2UL); gel(phi1, 30) = utoineg(0x2dfUL); gel(phi1, 31) = utoi(0x2aUL); gel(phi1, 32) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(10); return phi; } static GEN phi_w3w13_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(58, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoineg(0x10UL); gel(phi0, 3) = utoi(0x58UL); gel(phi0, 4) = utoi(0x258UL); gel(phi0, 5) = utoineg(0x270cUL); gel(phi0, 6) = utoi(0x9c00UL); gel(phi0, 7) = utoi(0x2b40cUL); gel(phi0, 8) = utoineg(0x20e250UL); gel(phi0, 9) = utoi(0x4f46baUL); gel(phi0, 10) = utoi(0x1869448UL); gel(phi0, 11) = utoineg(0xa49ab68UL); gel(phi0, 12) = utoi(0x96c7630UL); gel(phi0, 13) = utoi(0x4f7e0af6UL); gel(phi0, 14) = utoineg(0xea093590UL); gel(phi0, 15) = utoineg(0x6735bc50UL); gel(phi0, 16) = uu32toi(0x5UL, 0x971a2e08UL); gel(phi0, 17) = uu32toineg(0x6UL, 0x29c9d965UL); gel(phi0, 18) = uu32toineg(0xdUL, 0xeb9aa360UL); gel(phi0, 19) = uu32toi(0x26UL, 0xe9c0584UL); gel(phi0, 20) = uu32toineg(0x1UL, 0xb0cadce8UL); gel(phi0, 21) = uu32toineg(0x62UL, 0x73586014UL); gel(phi0, 22) = uu32toi(0x66UL, 0xaf672e38UL); gel(phi0, 23) = uu32toi(0x6bUL, 0x93c28cdcUL); gel(phi0, 24) = uu32toineg(0x11eUL, 0x4f633080UL); gel(phi0, 25) = uu32toi(0x3cUL, 0xcc42461bUL); gel(phi0, 26) = uu32toi(0x17bUL, 0xdec0a78UL); gel(phi0, 27) = uu32toineg(0x166UL, 0x910d8bd0UL); gel(phi0, 28) = uu32toineg(0xd4UL, 0x47873030UL); gel(phi0, 29) = uu32toi(0x204UL, 0x811828baUL); gel(phi0, 30) = uu32toineg(0x50UL, 0x5d713960UL); gel(phi0, 31) = uu32toineg(0x198UL, 0xa27e42b0UL); gel(phi0, 32) = uu32toi(0xe1UL, 0x25685138UL); gel(phi0, 33) = uu32toi(0xe3UL, 0xaa5774bbUL); gel(phi0, 34) = uu32toineg(0xcfUL, 0x392a9a00UL); gel(phi0, 35) = uu32toineg(0x81UL, 0xfb334d04UL); gel(phi0, 36) = uu32toi(0xabUL, 0x59594a68UL); gel(phi0, 37) = uu32toi(0x42UL, 0x356993acUL); gel(phi0, 38) = uu32toineg(0x86UL, 0x307ba678UL); gel(phi0, 39) = uu32toineg(0xbUL, 0x7a9e59dcUL); gel(phi0, 40) = uu32toi(0x4cUL, 0x27935f20UL); gel(phi0, 41) = uu32toineg(0x2UL, 0xe0ac9045UL); gel(phi0, 42) = uu32toineg(0x24UL, 0x14495758UL); gel(phi0, 43) = utoi(0x20973410UL); gel(phi0, 44) = uu32toi(0x13UL, 0x99ff4e00UL); gel(phi0, 45) = uu32toineg(0x1UL, 0xa710d34aUL); gel(phi0, 46) = uu32toineg(0x7UL, 0xfe5405c0UL); gel(phi0, 47) = uu32toi(0x1UL, 0xcdee0f8UL); gel(phi0, 48) = uu32toi(0x2UL, 0x660c92a8UL); gel(phi0, 49) = utoi(0x3f13a35aUL); gel(phi0, 50) = utoineg(0xe4eb4ba0UL); gel(phi0, 51) = utoineg(0x6420f4UL); gel(phi0, 52) = utoi(0x2c624370UL); gel(phi0, 53) = utoi(0xb31b814UL); gel(phi0, 54) = utoi(0xdd3ad8UL); gel(phi0, 55) = utoi(0x29278UL); gel(phi0, 56) = utoi(0x2c0UL); gel(phi0, 57) = gen_1; phi1 = cgetg(57, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_0; gel(phi1, 4) = gen_m1; gel(phi1, 5) = utoi(0xdUL); gel(phi1, 6) = utoineg(0x34UL); gel(phi1, 7) = utoi(0x1aUL); gel(phi1, 8) = utoi(0xf7UL); gel(phi1, 9) = utoineg(0x16cUL); gel(phi1, 10) = utoineg(0xddUL); gel(phi1, 11) = utoi(0x28aUL); gel(phi1, 12) = utoineg(0xddUL); gel(phi1, 13) = utoineg(0x16cUL); gel(phi1, 14) = utoi(0xf6UL); gel(phi1, 15) = utoi(0x1dUL); gel(phi1, 16) = utoineg(0x31UL); gel(phi1, 17) = utoineg(0x5ceUL); gel(phi1, 18) = utoi(0x2e4UL); gel(phi1, 19) = utoi(0x252cUL); gel(phi1, 20) = utoineg(0x1b34cUL); gel(phi1, 21) = utoi(0xaf80UL); gel(phi1, 22) = utoi(0x1cc5f9UL); gel(phi1, 23) = utoineg(0x3e1aa5UL); gel(phi1, 24) = utoineg(0x86d17aUL); gel(phi1, 25) = utoi(0x2427264UL); gel(phi1, 26) = utoineg(0x691c1fUL); gel(phi1, 27) = utoineg(0x862ad4eUL); gel(phi1, 28) = utoi(0xab21e1fUL); gel(phi1, 29) = utoi(0xbc19ddcUL); gel(phi1, 30) = utoineg(0x24331db8UL); gel(phi1, 31) = utoi(0x972c105UL); gel(phi1, 32) = utoi(0x363d7107UL); gel(phi1, 33) = utoineg(0x39696450UL); gel(phi1, 34) = utoineg(0x1bce7c48UL); gel(phi1, 35) = utoi(0x552ecba0UL); gel(phi1, 36) = utoineg(0x1c7771b8UL); gel(phi1, 37) = utoineg(0x393029b8UL); gel(phi1, 38) = utoi(0x3755be97UL); gel(phi1, 39) = utoi(0x83402a9UL); gel(phi1, 40) = utoineg(0x24d5be62UL); gel(phi1, 41) = utoi(0xdb6d90aUL); gel(phi1, 42) = utoi(0xa0ef177UL); gel(phi1, 43) = utoineg(0x99ff162UL); gel(phi1, 44) = utoi(0xb09e27UL); gel(phi1, 45) = utoi(0x26a7adcUL); gel(phi1, 46) = utoineg(0x116e2fcUL); gel(phi1, 47) = utoineg(0x1383b5UL); gel(phi1, 48) = utoi(0x35a9e7UL); gel(phi1, 49) = utoineg(0x1082a0UL); gel(phi1, 50) = utoineg(0x4696UL); gel(phi1, 51) = utoi(0x19f98UL); gel(phi1, 52) = utoineg(0x8bb3UL); gel(phi1, 53) = utoi(0x18bbUL); gel(phi1, 54) = utoineg(0x297UL); gel(phi1, 55) = utoi(0x27UL); gel(phi1, 56) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(16); return phi; } static GEN phi_w5w7_j(void) { GEN phi, phi0, phi1; phi = cgetg(4, t_VEC); phi0 = cgetg(50, t_VEC); gel(phi0, 1) = gen_1; gel(phi0, 2) = utoi(0xcUL); gel(phi0, 3) = utoi(0x2aUL); gel(phi0, 4) = utoi(0x10UL); gel(phi0, 5) = utoineg(0x69UL); gel(phi0, 6) = utoineg(0x318UL); gel(phi0, 7) = utoineg(0x148aUL); gel(phi0, 8) = utoineg(0x17c4UL); gel(phi0, 9) = utoi(0x1a73UL); gel(phi0, 10) = gen_0; gel(phi0, 11) = utoi(0x338a0UL); gel(phi0, 12) = utoi(0x61698UL); gel(phi0, 13) = utoineg(0x96e8UL); gel(phi0, 14) = utoi(0x140910UL); gel(phi0, 15) = utoineg(0x45f6b4UL); gel(phi0, 16) = utoineg(0x309f50UL); gel(phi0, 17) = utoineg(0xef9f8bUL); gel(phi0, 18) = utoineg(0x283167cUL); gel(phi0, 19) = utoi(0x625e20aUL); gel(phi0, 20) = utoineg(0x16186350UL); gel(phi0, 21) = utoi(0x46861281UL); gel(phi0, 22) = utoineg(0x754b96a0UL); gel(phi0, 23) = uu32toi(0x1UL, 0x421ca02aUL); gel(phi0, 24) = uu32toineg(0x2UL, 0xdb76a5cUL); gel(phi0, 25) = uu32toi(0x4UL, 0xf6afd8eUL); gel(phi0, 26) = uu32toineg(0x6UL, 0xaafd3cb4UL); gel(phi0, 27) = uu32toi(0x8UL, 0xda2539caUL); gel(phi0, 28) = uu32toineg(0xfUL, 0x84343790UL); gel(phi0, 29) = uu32toi(0xfUL, 0x914ff421UL); gel(phi0, 30) = uu32toineg(0x19UL, 0x3c123950UL); gel(phi0, 31) = uu32toi(0x15UL, 0x381f722aUL); gel(phi0, 32) = uu32toineg(0x15UL, 0xe01c0c24UL); gel(phi0, 33) = uu32toi(0x19UL, 0x3360b375UL); gel(phi0, 34) = utoineg(0x59fda9c0UL); gel(phi0, 35) = uu32toi(0x20UL, 0xff55024cUL); gel(phi0, 36) = uu32toi(0x16UL, 0xcc600800UL); gel(phi0, 37) = uu32toi(0x24UL, 0x1879c898UL); gel(phi0, 38) = uu32toi(0x1cUL, 0x37f97498UL); gel(phi0, 39) = uu32toi(0x19UL, 0x39ec4b60UL); gel(phi0, 40) = uu32toi(0x10UL, 0x52c660d0UL); gel(phi0, 41) = uu32toi(0x9UL, 0xcab00333UL); gel(phi0, 42) = uu32toi(0x4UL, 0x7fe69be4UL); gel(phi0, 43) = uu32toi(0x1UL, 0xa0c6f116UL); gel(phi0, 44) = utoi(0x69244638UL); gel(phi0, 45) = utoi(0xed560f7UL); gel(phi0, 46) = utoi(0xe7b660UL); gel(phi0, 47) = utoi(0x29d8aUL); gel(phi0, 48) = utoi(0x2c4UL); gel(phi0, 49) = gen_1; phi1 = cgetg(49, t_VEC); gel(phi1, 1) = gen_0; gel(phi1, 2) = gen_0; gel(phi1, 3) = gen_0; gel(phi1, 4) = gen_0; gel(phi1, 5) = gen_0; gel(phi1, 6) = gen_1; gel(phi1, 7) = utoi(0x7UL); gel(phi1, 8) = utoi(0x8UL); gel(phi1, 9) = utoineg(0x9UL); gel(phi1, 10) = gen_0; gel(phi1, 11) = utoineg(0x13UL); gel(phi1, 12) = utoineg(0x7UL); gel(phi1, 13) = utoineg(0x5ceUL); gel(phi1, 14) = utoineg(0xb0UL); gel(phi1, 15) = utoi(0x460UL); gel(phi1, 16) = utoineg(0x194bUL); gel(phi1, 17) = utoi(0x87c3UL); gel(phi1, 18) = utoi(0x3cdeUL); gel(phi1, 19) = utoineg(0xd683UL); gel(phi1, 20) = utoi(0x6099bUL); gel(phi1, 21) = utoineg(0x111ea8UL); gel(phi1, 22) = utoi(0xfa113UL); gel(phi1, 23) = utoineg(0x1a6561UL); gel(phi1, 24) = utoineg(0x1e997UL); gel(phi1, 25) = utoi(0x214e54UL); gel(phi1, 26) = utoineg(0x29c3f4UL); gel(phi1, 27) = utoi(0x67e102UL); gel(phi1, 28) = utoineg(0x227eaaUL); gel(phi1, 29) = utoi(0x191d10UL); gel(phi1, 30) = utoi(0x1a9cd5UL); gel(phi1, 31) = utoineg(0x58386fUL); gel(phi1, 32) = utoi(0x2e49f6UL); gel(phi1, 33) = utoineg(0x31194bUL); gel(phi1, 34) = utoi(0x9e07aUL); gel(phi1, 35) = utoi(0x260d59UL); gel(phi1, 36) = utoineg(0x189921UL); gel(phi1, 37) = utoi(0xeca4aUL); gel(phi1, 38) = utoineg(0xa3d9cUL); gel(phi1, 39) = utoineg(0x426daUL); gel(phi1, 40) = utoi(0x91875UL); gel(phi1, 41) = utoineg(0x3b55bUL); gel(phi1, 42) = utoineg(0x56f4UL); gel(phi1, 43) = utoi(0xcd1bUL); gel(phi1, 44) = utoineg(0x5159UL); gel(phi1, 45) = utoi(0x10f4UL); gel(phi1, 46) = utoineg(0x20dUL); gel(phi1, 47) = utoi(0x23UL); gel(phi1, 48) = gen_m1; gel(phi, 1) = phi0; gel(phi, 2) = phi1; gel(phi, 3) = utoi(12); return phi; } GEN double_eta_raw(long inv) { switch (inv) { case INV_W2W3: case INV_W2W3E2: return phi_w2w3_j(); case INV_W3W3: case INV_W3W3E2: return phi_w3w3_j(); case INV_W2W5: case INV_W2W5E2: return phi_w2w5_j(); case INV_W2W7: case INV_W2W7E2: return phi_w2w7_j(); case INV_W3W5: return phi_w3w5_j(); case INV_W3W7: return phi_w3w7_j(); case INV_W2W13: return phi_w2w13_j(); case INV_W3W13: return phi_w3w13_j(); case INV_W5W7: return phi_w5w7_j(); default: pari_err_BUG("double_eta_raw"); return NULL;/*LCOV_EXCL_LINE*/ } } /** * SECTION: Select discriminant for given modpoly level. */ /* require an L1, useful for multi-threading */ #define MODPOLY_USE_L1 1 /* no bound on L1 other than the fixed bound MAX_L1 - needed to * handle small L for certain invariants (but not for j) */ #define MODPOLY_NO_MAX_L1 2 /* don't use any auxilliary primes - needed to handle small L for * certain invariants (but not for j) */ #define MODPOLY_NO_AUX_L 4 #define MODPOLY_IGNORE_SPARSE_FACTOR 8 INLINE double modpoly_height_bound(long L, long inv) { double nbits, nbits2; double c; long hf; /* proven bound (in bits), derived from: 6l*log(l)+16*l+13*sqrt(l)*log(l) */ nbits = 6.0*L*log2(L)+16/M_LN2*L+8.0*sqrt((double)L)*log2(L); /* alternative proven bound (in bits), derived from: 6l*log(l)+17*l */ nbits2 = 6.0*L*log2(L)+17/M_LN2*L; if ( nbits2 < nbits ) nbits = nbits2; hf = modinv_height_factor(inv); if (hf > 1) { /* IMPORTANT: when dividing by the height factor, we only want to reduce terms related to the bound on j (the roots of Phi_l(X,y)), not terms arising from binomial coefficients. These arise in lemmas 2 and 3 of the height bound paper, terms of (log 2)*L and 2.085*(L+1) which we convert here to binary logs */ /* Massive overestimate: if you care about speed, determine a good height * bound empirically as done for INV_F below */ nbits2 = nbits - 4.01*L -3.0; nbits = nbits2/hf + 4.01*L + 3.0; } if (inv == INV_F) { if (L < 30) c = 45; else if (L < 100) c = 36; else if (L < 300) c = 32; else if (L < 600) c = 26; else if (L < 1200) c = 24; else if (L < 2400) c = 22; else c = 20; nbits = (6.0*L*log2(L) + c*L)/hf; } return nbits; } /* small enough to write the factorization of a smooth in a BIL bit integer */ #define SMOOTH_PRIMES ((BITS_IN_LONG >> 1) - 1) #define MAX_ATKIN 255 /* Must have primes at least up to MAX_ATKIN */ static const long PRIMES[] = { 0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277 }; #define MAX_L1 255 typedef struct D_entry_struct { ulong m; long D, h; } D_entry; /* Returns a form that generates the classes of norm p^2 in cl(p^2D) * (i.e. one with order p-1), where p is an odd prime that splits in D * and does not divide its conductor (but this is not verified) */ INLINE GEN qform_primeform2(long p, long D) { pari_sp ltop = avma, av; GEN M; register long k; M = factor_pn_1(stoi(p), 1); av = avma; for (k = D & 1; k <= p; k += 2) { GEN Q; long ord, a, b, c = (k * k - D) / 4; if (!(c % p)) continue; a = p * p; b = k * p; Q = redimag(mkqfis(a, b, c)); /* TODO: How do we know that Q has order dividing p - 1? If we don't, then * the call to gen_order should be replaced with a call to something with * fastorder semantics (i.e. return 0 if ord(Q) \ndiv M). */ ord = itos(qfi_order(Q, M)); if (ord == p - 1) { /* TODO: This check that gen_order returned the correct result should be * removed when gen_order is replaced with fastorder semantics. */ GEN tst = gpowgs(Q, p - 1); if (qfb_equal1(tst)) { avma = ltop; return mkqfis(a, b, c); } break; } avma = av; } avma = ltop; return NULL; } /* Let n = #cl(D); return x such that [L0]^x = [L] in cl(D), or -1 if x was * not found */ INLINE long primeform_discrete_log(long L0, long L, long n, long D) { pari_sp av = avma; GEN X, Q, R, DD = stoi(D); Q = primeform_u(DD, L0); R = primeform_u(DD, L); X = qfi_Shanks(R, Q, n); avma = av; return X? itos(X): -1; } /* Return the norm of a class group generator appropriate for a discriminant * that will be used to calculate the modular polynomial of level L and * invariant inv. Don't consider norms less than initial_L0 */ static long select_L0(long L, long inv, long initial_L0) { long L0, modinv_N = modinv_level(inv); if (modinv_N % L == 0) pari_err_BUG("select_L0"); /* TODO: Clean up these anomolous L0 choices */ /* I've no idea why the discriminant-finding code fails with L0=5 * when L=19 and L=29, nor why L0=7 and L0=11 don't work for L=19 * either, nor why this happens for the otherwise unrelated * invariants Weber-f and (2,3) double-eta. */ if (inv == INV_W3W3E2 && L == 5) return 2; if (inv == INV_F || inv == INV_F2 || inv == INV_F4 || inv == INV_F8 || inv == INV_W2W3 || inv == INV_W2W3E2 || inv == INV_W3W3 /* || inv == INV_W3W3E2 */) { if (L == 19) return 13; else if (L == 29 || L == 5) return 7; return 5; } if ((inv == INV_W2W5 || inv == INV_W2W5E2) && (L == 7 || L == 19)) return 13; if ((inv == INV_W2W7 || inv == INV_W2W7E2) && L == 11) return 13; if (inv == INV_W3W5) { if (L == 7) return 13; else if (L == 17) return 7; } if (inv == INV_W3W7) { if (L == 29 || L == 101) return 11; if (L == 11 || L == 19) return 13; } if (inv == INV_W5W7 && L == 17) return 3; /* L0 = smallest small prime different from L that doesn't divide modinv_N */ for (L0 = unextprime(initial_L0 + 1); L0 == L || modinv_N % L0 == 0; L0 = unextprime(L0 + 1)) ; return L0; } /* Return the order of [L]^n in cl(D), where #cl(D) = ord. */ INLINE long primeform_exp_order(long L, long n, long D, long ord) { pari_sp av = avma; GEN Q = gpowgs(primeform_u(stoi(D), L), n); long m = itos(qfi_order(Q, Z_factor(stoi(ord)))); avma = av; return m; } /* If an ideal of norm modinv_deg is equivalent to an ideal of norm L0, we * have an orientation ambiguity that we need to avoid. Note that we need to * check all the possibilities (up to 8), but we can cheaply check inverses * (so at most 2) */ static long orientation_ambiguity(long D1, long L0, long modinv_p1, long modinv_p2, long modinv_N) { pari_sp av = avma; long ambiguity = 0; GEN D = stoi(D1), Q1 = primeform_u(D, modinv_p1), Q2 = NULL; if (modinv_p2 > 1) { if (modinv_p1 == modinv_p2) Q1 = gsqr(Q1); else { GEN P2 = primeform_u(D, modinv_p2); GEN Q = gsqr(P2), R = gsqr(Q1); /* check that p1^2 != p2^{+/-2}, since this leads to * ambiguities when converting j's to f's */ if (equalii(gel(Q,1), gel(R,1)) && absequalii(gel(Q,2), gel(R,2))) { dbg_printf(3)("Bad D=%ld, a^2=b^2 problem between modinv_p1=%ld and modinv_p2=%ld\n", D1, modinv_p1, modinv_p2); ambiguity = 1; } else { /* generate both p1*p2 and p1*p2^{-1} */ Q2 = gmul(Q1, P2); P2 = ginv(P2); Q1 = gmul(Q1, P2); } } } if (!ambiguity) { GEN P = gsqr(primeform_u(D, L0)); if (equalii(gel(P,1), gel(Q1,1)) || (modinv_p2 && modinv_p1 != modinv_p2 && equalii(gel(P,1), gel(Q2,1)))) { dbg_printf(3)("Bad D=%ld, a=b^{+/-2} problem between modinv_N=%ld and L0=%ld\n", D1, modinv_N, L0); ambiguity = 1; } } avma = av; return ambiguity; } static long check_generators( long *n1_, long *m_, long D, long h, long n, long subgrp_sz, long L0, long L1) { long n1, m = primeform_exp_order(L0, n, D, h); if (m_) *m_ = m; n1 = n * m; if (!n1) pari_err_BUG("check_generators"); *n1_ = n1; if (n1 < subgrp_sz/2 || ( ! L1 && n1 < subgrp_sz)) { dbg_printf(3)("Bad D1=%ld with n1=%ld, h1=%ld, L1=%ld: " "L0 and L1 don't span subgroup of size d in cl(D1)\n", D, n, h, L1); return 0; } if (n1 < subgrp_sz && ! (n1 & 1)) { int res; /* check whether L1 is generated by L0, use the fact that it has order 2 */ pari_sp av = avma; GEN D1 = stoi(D); GEN Q = gpowgs(primeform_u(D1, L0), n1 / 2); res = gequal(Q, redimag(primeform_u(D1, L1))); avma = av; if (res) { dbg_printf(3)("Bad D1=%ld, with n1=%ld, h1=%ld, L1=%ld: " "L1 generated by L0 in cl(D1)\n", D, n, h, L1); return 0; } } return 1; } /* Calculate solutions (p, t) to the norm equation * 4 p = t^2 - v^2 L^2 D (*) * corresponding to the descriminant described by Dinfo. * * INPUT: * - max: length of primes and traces * - xprimes: p to exclude from primes (if they arise) * - xcnt: length of xprimes * - minbits: sum of log2(p) must be larger than this * - Dinfo: discriminant, invariant and L for which we seek solutions to (*) * * OUTPUT: * - primes: array of p in (*) * - traces: array of t in (*) * - totbits: sum of log2(p) for p in primes. * * RETURN: * - the number of primes and traces found (these are always the same). * * NOTE: primes and traces are both NULL or both non-NULL. * xprimes can be zero, in which case it is treated as empty. */ static long modpoly_pickD_primes( ulong *primes, ulong *traces, long max, ulong *xprimes, long xcnt, long *totbits, long minbits, disc_info *Dinfo) { double bits; long D, m, n, vcnt, pfilter, one_prime, inv; ulong maxp; register ulong a1, a2, v, t, p, a1_start, a1_delta, L0, L1, L, absD; ulong FF_BITS = BITS_IN_LONG - 2; /* BITS_IN_LONG - NAIL_BITS */ D = Dinfo->D1; absD = -D; L0 = Dinfo->L0; L1 = Dinfo->L1; L = Dinfo->L; inv = Dinfo->inv; /* make sure pfilter and D don't preclude the possibility of p=(t^2-v^2D)/4 being prime */ pfilter = modinv_pfilter(inv); if ((pfilter & IQ_FILTER_1MOD3) && ! (D % 3)) return 0; if ((pfilter & IQ_FILTER_1MOD4) && ! (D & 0xF)) return 0; /* Naively estimate the number of primes satisfying 4p=t^2-L^2D with * t=2 mod L and pfilter. This is roughly * #{t: t^2 < max p and t=2 mod L} / pi(max p) * filter_density, * where filter_density is 1, 2, or 4 depending on pfilter. If this quantity * is already more than twice the number of bits we need, assume that, * barring some obstruction, we should have no problem getting enough primes. * In this case we just verify we can get one prime (which should always be * true, assuming we chose D properly). */ one_prime = 0; *totbits = 0; if (max <= 1 && ! one_prime) { p = ((pfilter & IQ_FILTER_1MOD3) ? 2 : 1) * ((pfilter & IQ_FILTER_1MOD4) ? 2 : 1); one_prime = (1UL << ((FF_BITS+1)/2)) * (log2(L*L*(-D))-1) > p*L*minbits*FF_BITS*M_LN2; if (one_prime) *totbits = minbits+1; /* lie */ } m = n = 0; bits = 0.0; maxp = 0; for (v = 1; v < 100 && bits < minbits; v++) { /* Don't allow v dividing the conductor. */ if (ugcd(absD, v) != 1) continue; /* Avoid v dividing the level. */ if (v > 2 && modinv_is_double_eta(inv) && ugcd(modinv_level(inv), v) != 1) continue; /* can't get odd p with D=1 mod 8 unless v is even */ if ((v & 1) && (D & 7) == 1) continue; /* disallow 4 | v for L0=2 (removing this restriction is costly) */ if (L0 == 2 && !(v & 3)) continue; /* can't get p=3mod4 if v^2D is 0 mod 16 */ if ((pfilter & IQ_FILTER_1MOD4) && !((v*v*D) & 0xF)) continue; if ((pfilter & IQ_FILTER_1MOD3) && !(v%3) ) continue; /* avoid L0-volcanos with non-zero height */ if (L0 != 2 && ! (v % L0)) continue; /* ditto for L1 */ if (L1 && !(v % L1)) continue; vcnt = 0; if ((v*v*absD)/4 > (1L<> 2; if (!(a2 % L)) continue; t = a1*L + 2; p = a2*L*L + t - 1; /* double check calculation just in case of overflow or other weirdness */ if (!odd(p) || t*t + v*v*L*L*absD != 4*p) pari_err_BUG("modpoly_pickD_primes"); if (p > (1UL<= max) goto done; /* TODO: Implement test to filter primes that lead to * L-valuation != 2 */ primes[n] = p; traces[n] = t; } n++; vcnt++; bits += log2(p); if (p > maxp) maxp = p; if (one_prime) goto done; } if (vcnt) dbg_printf(3)("%ld primes with v=%ld, maxp=%ld (%.2f bits)\n", vcnt, v, maxp, log2(maxp)); } done: if (!n) { dbg_printf(3)("check_primes failed completely for D=%ld\n", D); return 0; } dbg_printf(3)("D=%ld: Found %ld primes totalling %0.2f of %ld bits\n", D, n, bits, minbits); if (!*totbits) *totbits = (long)bits; return n; } #define MAX_VOLCANO_FLOOR_SIZE 100000000 static long calc_primes_for_discriminants(disc_info Ds[], long Dcnt, long L, long minbits) { pari_sp av = avma; long i, j, k, m, n, D1, pcnt, totbits; ulong *primes, *Dprimes, *Dtraces; /* D1 is the discriminant with smallest absolute value among those we found */ D1 = Ds[0].D1; for (i = 1; i < Dcnt; i++) if (Ds[i].D1 > D1) D1 = Ds[i].D1; /* n is an upper bound on the number of primes we might get. */ n = ceil(minbits / (log2(L * L * (-D1)) - 2)) + 1; primes = (ulong *) stack_malloc(n * sizeof(*primes)); Dprimes = (ulong *) stack_malloc(n * sizeof(*Dprimes)); Dtraces = (ulong *) stack_malloc(n * sizeof(*Dtraces)); for (i = 0, totbits = 0, pcnt = 0; i < Dcnt && totbits < minbits; i++) { long np = modpoly_pickD_primes(Dprimes, Dtraces, n, primes, pcnt, &Ds[i].bits, minbits - totbits, Ds + i); ulong *T = (ulong *)newblock(2*np); Ds[i].nprimes = np; Ds[i].primes = T; memcpy(T , Dprimes, np * sizeof(*Dprimes)); Ds[i].traces = T+np; memcpy(T+np, Dtraces, np * sizeof(*Dtraces)); totbits += Ds[i].bits; pcnt += np; if (totbits >= minbits || i == Dcnt - 1) { Dcnt = i + 1; break; } /* merge lists */ for (j = pcnt - np - 1, k = np - 1, m = pcnt - 1; m >= 0; m--) { if (k >= 0) { if (j >= 0 && primes[j] > Dprimes[k]) primes[m] = primes[j--]; else primes[m] = Dprimes[k--]; } else { primes[m] = primes[j--]; } } } if (totbits < minbits) { dbg_printf(1)("Only obtained %ld of %ld bits using %ld discriminants\n", totbits, minbits, Dcnt); for (i = 0; i < Dcnt; i++) killblock((GEN)Ds[i].primes); Dcnt = 0; } avma = av; return Dcnt; } /* Select discriminant(s) to use when calculating the modular * polynomial of level L and invariant inv. * * INPUT: * - L: level of modular polynomial (must be odd) * - inv: invariant of modular polynomial * - L0: result of select_L0(L, inv) * - minbits: height of modular polynomial * - flags: see below * - tab: result of scanD0(L0) * - tablen: length of tab * * OUTPUT: * - Ds: the selected discriminant(s) * * RETURN: * - the number of Ds found * * The flags parameter is constructed by ORing zero or more of the * following values: * - MODPOLY_USE_L1: force use of second class group generator * - MODPOLY_NO_AUX_L: don't use auxillary class group elements * - MODPOLY_IGNORE_SPARSE_FACTOR: obtain D for which h(D) > L + 1 * rather than h(D) > (L + 1)/s */ static long modpoly_pickD(disc_info Ds[MODPOLY_MAX_DCNT], long L, long inv, long L0, long max_L1, long minbits, long flags, D_entry *tab, long tablen) { pari_sp ltop = avma, btop; disc_info Dinfo; pari_timer T; long modinv_p1, modinv_p2; /* const after next line */ const long modinv_deg = modinv_degree(&modinv_p1, &modinv_p2, inv); const long pfilter = modinv_pfilter(inv), modinv_N = modinv_level(inv); long i, k, use_L1, Dcnt, D0_i, d, cost, enum_cost, best_cost, totbits; const double L_bits = log2(L); if (!odd(L)) pari_err_BUG("modpoly_pickD"); timer_start(&T); if (flags & MODPOLY_IGNORE_SPARSE_FACTOR) d = L+2; else d = ceildivuu(L+1, modinv_sparse_factor(inv)) + 1; /* Now set level to 0 unless we will need to compute N-isogenies */ dbg_printf(1)("Using L0=%ld for L=%ld, d=%ld, modinv_N=%ld, modinv_deg=%ld\n", L0, L, d, modinv_N, modinv_deg); /* We use L1 if (L0|L) == 1 or if we are forced to by flags. */ use_L1 = (kross(L0,L) > 0 || (flags & MODPOLY_USE_L1)); Dcnt = best_cost = totbits = 0; dbg_printf(3)("use_L1=%ld\n", use_L1); dbg_printf(3)("minbits = %ld\n", minbits); /* Iterate over the fundamental discriminants for L0 */ for (D0_i = 0; D0_i < tablen; D0_i++) { D_entry D0_entry = tab[D0_i]; long m, n0, h0, deg, L1, H_cost, twofactor, D0 = D0_entry.D; double D0_bits; if (! modinv_good_disc(inv, D0)) continue; dbg_printf(3)("D0=%ld\n", D0); /* don't allow either modinv_p1 or modinv_p2 to ramify */ if (kross(D0, L) < 1 || (modinv_p1 > 1 && kross(D0, modinv_p1) < 1) || (modinv_p2 > 1 && kross(D0, modinv_p2) < 1)) { dbg_printf(3)("Bad D0=%ld due to non-split L or ramified level\n", D0); continue; } deg = D0_entry.h; /* class poly degree */ h0 = ((D0_entry.m & 2) ? 2*deg : deg); /* class number */ /* (D0_entry.m & 1) is 1 if ord(L0) < h0 (hence = h0/2), * is 0 if ord(L0) = h0 */ n0 = h0 / ((D0_entry.m & 1) + 1); /* = ord(L0) */ /* Look for L1: for each smooth prime p */ L1 = 0; for (i = 1 ; i <= SMOOTH_PRIMES; i++) { long p = PRIMES[i]; if (p <= L0) continue; /* If 1 + (D0 | p) = 1, i.e. p | D0 */ if (((D0_entry.m >> (2*i)) & 3) == 1) { /* XXX: Why (p | L) = -1? Presumably so (L^2 v^2 D0 | p) = -1? */ if (p <= max_L1 && modinv_N % p && kross(p,L) < 0) { L1 = p; break; } } } if (i > SMOOTH_PRIMES && (n0 < h0 || use_L1)) { /* Didn't find suitable L1 though we need one */ dbg_printf(3)("Bad D0=%ld because there is no good L1\n", D0); continue; } dbg_printf(3)("Good D0=%ld with L1=%ld, n0=%ld, h0=%ld, d=%ld\n", D0, L1, n0, h0, d); /* We're finished if we have sufficiently many discriminants that satisfy * the cost requirement */ if (totbits > minbits && best_cost && h0*(L-1) > 3*best_cost) break; D0_bits = log2(-D0); /* If L^2 D0 is too big to fit in a BIL bit integer, skip D0. */ if (D0_bits + 2 * L_bits > (BITS_IN_LONG - 1)) continue; /* m is the order of L0^n0 in L^2 D0? */ m = primeform_exp_order(L0, n0, L * L * D0, n0 * (L-1)); if (m < (L-1)/2) { dbg_printf(3)("Bad D0=%ld because %ld is less than (L-1)/2=%ld\n", D0, m, (L - 1)/2); continue; } /* Heuristic. Doesn't end up contributing much. */ H_cost = 2 * deg * deg; /* 0xc = 0b1100, so D0_entry.m & 0xc == 1 + (D0 | 2) */ if ((D0 & 7) == 5) /* D0 = 5 (mod 8) */ twofactor = ((D0_entry.m & 0xc) ? 1 : 3); else twofactor = 0; btop = avma; /* For each small prime... */ for (i = 0; i <= SMOOTH_PRIMES; i++) { long h1, h2, D1, D2, n1, n2, dl1, dl20, dl21, p, q, j; double p_bits; avma = btop; /* i = 0 corresponds to 1, which we do not want to skip! (i.e. DK = D) */ if (i) { if (modinv_odd_conductor(inv) && i == 1) continue; p = PRIMES[i]; /* Don't allow large factors in the conductor. */ if (p > max_L1) break; if (p == L0 || p == L1 || p == L || p == modinv_p1 || p == modinv_p2) continue; p_bits = log2(p); /* h1 is the class number of D1 = q^2 D0, where q = p^j (j defined in the loop below) */ h1 = h0 * (p - ((D0_entry.m >> (2*i)) & 0x3) + 1); /* q is the smallest power of p such that h1 >= d ~ "L + 1". */ for (j = 1, q = p; h1 < d; j++, q *= p, h1 *= p) ; D1 = q * q * D0; /* can't have D1 = 0 mod 16 and hope to get any primes congruent to 3 mod 4 */ if ((pfilter & IQ_FILTER_1MOD4) && !(D1 & 0xF)) continue; } else { /* i = 0, corresponds to "p = 1". */ h1 = h0; D1 = D0; p = q = j = 1; p_bits = 0; } /* include a factor of 4 if D1 is 5 mod 8 */ /* XXX: No idea why he does this. */ if (twofactor && (q & 1)) { if (modinv_odd_conductor(inv)) continue; D1 *= 4; h1 *= twofactor; } /* heuristic early abort; we may miss good D1's, but this saves time */ if (totbits > minbits && best_cost && h1*(L-1) > 2.2*best_cost) continue; /* log2(D0 * (p^j)^2 * L^2 * twofactor) > (BIL - 1) -- params too big. */ if (D0_bits + 2*j*p_bits + 2*L_bits + (twofactor && (q & 1) ? 2.0 : 0.0) > (BITS_IN_LONG-1)) continue; if (! check_generators(&n1, NULL, D1, h1, n0, d, L0, L1)) continue; if (n1 >= h1) dl1 = -1; /* fill it in later */ else if ((dl1 = primeform_discrete_log(L0, L, n1, D1)) < 0) continue; dbg_printf(3)("Good D0=%ld, D1=%ld with q=%ld, L1=%ld, n1=%ld, h1=%ld\n", D0, D1, q, L1, n1, h1); if (modinv_deg && orientation_ambiguity(D1, L0, modinv_p1, modinv_p2, modinv_N)) continue; D2 = L * L * D1; h2 = h1 * (L-1); /* m is the order of L0^n1 in cl(D2) */ if (!check_generators(&n2, &m, D2, h2, n1, d*(L-1), L0, L1)) continue; /* This restriction on m is not necessary, but simplifies life later */ if (m < (L-1)/2 || (!L1 && m < L-1)) { dbg_printf(3)("Bad D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, " "order of L0^n1 in cl(D2) is too small\n", D2, D1, D0, n2, h2, L1); continue; } dl20 = n1; dl21 = 0; if (m < L-1) { GEN Q1 = qform_primeform2(L, D1), Q2, X; if (!Q1) pari_err_BUG("modpoly_pickD"); Q2 = primeform_u(stoi(D2), L1); Q2 = gmul(Q1, Q2); /* we know this element has order L-1 */ Q1 = primeform_u(stoi(D2), L0); k = ((n2 & 1) ? 2*n2 : n2)/(L-1); Q1 = gpowgs(Q1, k); X = qfi_Shanks(Q2, Q1, L-1); if (!X) { dbg_printf(3)("Bad D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, " "form of norm L^2 not generated by L0 and L1\n", D2, D1, D0, n2, h2, L1); continue; } dl20 = itos(X) * k; dl21 = 1; } if (! (m < L-1 || n2 < d*(L-1)) && n1 >= d && ! use_L1) L1 = 0; /* we don't need L1 */ if (!L1 && use_L1) { dbg_printf(3)("not using D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, " "because we don't need L1 but must use it\n", D2, D1, D0, n2, h2, L1); continue; } /* don't allow zero dl21 with L1 for the moment, since * modpoly doesn't handle it - we may change this in the future */ if (L1 && ! dl21) continue; dbg_printf(3)("Good D0=%ld, D1=%ld, D2=%ld with s=%ld^%ld, L1=%ld, dl2=%ld, n2=%ld, h2=%ld\n", D0, D1, D2, p, j, L1, dl20, n2, h2); /* This estimate is heuristic and fiddling with the * parameters 5 and 0.25 can change things quite a bit. */ enum_cost = n2 * (5 * L0 * L0 + 0.25 * L1 * L1); cost = enum_cost + H_cost; if (best_cost && cost > 2.2*best_cost) break; if (best_cost && cost >= 0.99*best_cost) continue; Dinfo.GENcode0 = evaltyp(t_VECSMALL)|evallg(13); Dinfo.inv = inv; Dinfo.L = L; Dinfo.D0 = D0; Dinfo.D1 = D1; Dinfo.L0 = L0; Dinfo.L1 = L1; Dinfo.n1 = n1; Dinfo.n2 = n2; Dinfo.dl1 = dl1; Dinfo.dl2_0 = dl20; Dinfo.dl2_1 = dl21; Dinfo.cost = cost; if (!modpoly_pickD_primes(NULL, NULL, 0, NULL, 0, &Dinfo.bits, minbits, &Dinfo)) continue; dbg_printf(2)("Best D2=%ld, D1=%ld, D0=%ld with s=%ld^%ld, L1=%ld, " "n1=%ld, n2=%ld, cost ratio %.2f, bits=%ld\n", D2, D1, D0, p, j, L1, n1, n2, (double)cost/(d*(L-1)), Dinfo.bits); /* Insert Dinfo into the Ds array. Ds is sorted by ascending cost. */ for (j = 0; j < Dcnt; j++) if (Dinfo.cost < Ds[j].cost) break; if (n2 > MAX_VOLCANO_FLOOR_SIZE && n2*(L1 ? 2 : 1) > 1.2* (d*(L-1)) ) { dbg_printf(3)("Not using D1=%ld, D2=%ld for space reasons\n", D1, D2); continue; } if (j == Dcnt && Dcnt == MODPOLY_MAX_DCNT) continue; totbits += Dinfo.bits; if (Dcnt == MODPOLY_MAX_DCNT) totbits -= Ds[Dcnt-1].bits; if (Dcnt < MODPOLY_MAX_DCNT) Dcnt++; if (n2 > MAX_VOLCANO_FLOOR_SIZE) dbg_printf(3)("totbits=%ld, minbits=%ld\n", totbits, minbits); for (k = Dcnt-1; k > j; k--) Ds[k] = Ds[k-1]; Ds[k] = Dinfo; best_cost = (totbits > minbits)? Ds[Dcnt-1].cost: 0; /* if we were able to use D1 with s = 1, there is no point in * using any larger D1 for the same D0 */ if (!i) break; } /* END FOR over small primes */ } /* END WHILE over D0's */ dbg_printf(2)(" checked %ld of %ld fundamental discriminants to find suitable " "discriminant (Dcnt = %ld)\n", D0_i, tablen, Dcnt); if ( ! Dcnt) { dbg_printf(1)("failed completely for L=%ld\n", L); return 0; } Dcnt = calc_primes_for_discriminants(Ds, Dcnt, L, minbits); /* fill in any missing dl1's */ for (i = 0 ; i < Dcnt; i++) if (Ds[i].dl1 < 0 && (Ds[i].dl1 = primeform_discrete_log(L0, L, Ds[i].n1, Ds[i].D1)) < 0) pari_err_BUG("modpoly_pickD"); if (DEBUGLEVEL > 1+3) { err_printf("Selected %ld discriminants using %ld msecs\n", Dcnt, timer_delay(&T)); for (i = 0 ; i < Dcnt ; i++) { GEN H = classno(stoi(Ds[i].D0)); long h0 = itos(H); err_printf (" D0=%ld, h(D0)=%ld, D=%ld, L0=%ld, L1=%ld, " "cost ratio=%.2f, enum ratio=%.2f,", Ds[i].D0, h0, Ds[i].D1, Ds[i].L0, Ds[i].L1, (double)Ds[i].cost/(d*(L-1)), (double)(Ds[i].n2*(Ds[i].L1 ? 2 : 1))/(d*(L-1))); err_printf (" %ld primes, %ld bits\n", Ds[i].nprimes, Ds[i].bits); } } avma = ltop; return Dcnt; } static int _qsort_cmp(const void *a, const void *b) { D_entry *x = (D_entry *)a, *y = (D_entry *)b; long u, v; /* u and v are the class numbers of x and y */ u = x->h * (!!(x->m & 2) + 1); v = y->h * (!!(y->m & 2) + 1); /* Sort by class number */ if (u < v) return -1; if (u > v) return 1; /* Sort by discriminant (which is < 0, hence the sign reversal) */ if (x->D > y->D) return -1; if (x->D < y->D) return 1; return 0; } /* Build a table containing fundamental D, |D| <= maxD whose class groups * - are cyclic generated by an element of norm L0 * - have class number at most maxh * The table is ordered using _qsort_cmp above, which ranks the discriminants * by class number, then by absolute discriminant. * * INPUT: * - maxd: largest allowed discriminant * - maxh: largest allowed class number * - L0: norm of class group generator * * OUTPUT: * - tablelen: length of return value * * RETURN: * - array of {D, h(D), kronecker symbols for small p} */ static D_entry * scanD0(long *tablelen, long *minD, long maxD, long maxh, long L0) { pari_sp av; D_entry *tab; long d, cnt; /* NB: As seen in the loop below, the real class number of D can be */ /* 2*maxh if cl(D) is cyclic. */ if (maxh < 0) pari_err_BUG("scanD0"); /* Not checked, but L0 should be 2, 3, 5 or 7. */ tab = (D_entry *) stack_malloc((maxD/4)*sizeof(*tab)); /* Overestimate */ /* d = 7, 11, 15, 19, 23, ... */ for (av = avma, d = *minD, cnt = 0; d <= maxD; d += 4, avma = av) { GEN DD, H, fact, ordL, frm; long i, j, k, n, h, L1, D = -d; long *q, *e; ulong m; /* Check to see if (D | L0) = 1 */ if (kross(D, L0) < 1) continue; /* [q, e] is the factorisation of d. */ fact = factoru(d); q = zv_to_longptr(gel(fact, 1)); e = zv_to_longptr(gel(fact, 2)); k = lg(gel(fact, 1)) - 1; /* Check if the discriminant is square-free */ for (i = 0; i < k; i++) if (e[i] > 1) break; if (i < k) continue; /* L1 initially the first factor of d if small enough, otherwise ignored */ L1 = (k > 1 && q[0] <= MAX_L1)? q[0]: 0; /* restrict to possibly cyclic class groups */ if (k > 2) continue; /* Check if h(D) is too big */ DD = stoi(D); H = classno(DD); h = itos(H); if (h > 2*maxh || (!L1 && h > maxh)) continue; /* Check if ord(q) is not big enough to generate at least half the * class group (where q is the L0-primeform). */ frm = primeform_u(DD, L0); ordL = qfi_order(redimag(frm), H); n = itos(ordL); if (n < h/2 || (!L1 && n < h)) continue; /* If q is big enough, great! Otherwise, for each potential L1, * do a discrete log to see if it is NOT in the subgroup generated * by L0; stop as soon as such is found. */ for (j = 0; ; j++) { if (n == h || (L1 && !qfi_Shanks(primeform_u(DD, L1), frm, n))) { dbg_printf(2)("D0=%ld good with L1=%ld\n", D, L1); break; } if (!L1) break; L1 = (j < k && k > 1 && q[j] <= MAX_L1 ? q[j] : 0); } /* The first bit of m indicates whether q generates a proper * subgroup of cl(D) (hence implying that we need L1) or if q * generates the whole class group. */ m = (n < h ? 1 : 0); /* bits i and i+1 of m give the 2-bit number 1 + (D|p) where p is * the ith prime. */ for (i = 1 ; i <= SMOOTH_PRIMES; i++) { ulong x = (ulong) (1 + kross(D, PRIMES[i])); m |= x << (2*i); } /* Insert d, h and m into the table */ tab[cnt].D = D; tab[cnt].h = h; tab[cnt].m = m; cnt++; } /* Sort the table */ qsort(tab, cnt, sizeof(*tab), _qsort_cmp); *tablelen = cnt; *minD = d; return tab; } /* Populate Ds with discriminants (and attached data) that can be * used to calculate the modular polynomial of level L and invariant * inv. Return the number of discriminants found. */ static long discriminant_with_classno_at_least(disc_info bestD[MODPOLY_MAX_DCNT], long L, long inv, long ignore_sparse) { enum { SMALL_L_BOUND = 101 }; long max_max_D = 160000 * (inv ? 2 : 1); long minD, maxD, maxh, L0, max_L1, minbits, Dcnt, flags, s, d, h, i, tablen; D_entry *tab; double eps, cost, best_eps = -1.0, best_cost = -1.0; disc_info Ds[MODPOLY_MAX_DCNT]; long best_cnt = 0; pari_timer T; timer_start(&T); s = modinv_sparse_factor(inv); d = ceildivuu(L+1, s) + 1; /* maxD of 10000 allows us to get a satisfactory discriminant in * under 250ms in most cases. */ maxD = 10000; /* Allow the class number to overshoot L by 50%. Must be at least * 1.1*L, and higher values don't seem to provide much benefit, * except when L is small, in which case it's necessary to get any * discriminant at all in some cases. */ maxh = (L / s < SMALL_L_BOUND) ? 10 * L : 1.5 * L; flags = ignore_sparse ? MODPOLY_IGNORE_SPARSE_FACTOR : 0; L0 = select_L0(L, inv, 0); max_L1 = L / 2 + 2; /* for L=11 we need L1=7 for j */ minbits = modpoly_height_bound(L, inv); minD = 7; while ( ! best_cnt) { while (maxD <= max_max_D) { /* TODO: Find a way to re-use tab when we need multiple modpolys */ tab = scanD0(&tablen, &minD, maxD, maxh, L0); dbg_printf(1)("Found %ld potential fundamental discriminants\n", tablen); Dcnt = modpoly_pickD(Ds, L, inv, L0, max_L1, minbits, flags, tab, tablen); eps = 0.0; cost = 0.0; if (Dcnt) { long n1 = 0; for (i = 0; i < Dcnt; i++) { n1 = maxss(n1, Ds[i].n1); cost += Ds[i].cost; } eps = (n1 * s - L) / (double)L; if (best_cost < 0.0 || cost < best_cost) { if (best_cnt) for (i = 0; i < best_cnt; i++) killbloc((GEN)bestD[i].primes); (void) memcpy(bestD, Ds, Dcnt * sizeof(disc_info)); best_cost = cost; best_cnt = Dcnt; best_eps = eps; /* We're satisfied if n1 is within 5% of L. */ if (L / s <= SMALL_L_BOUND || eps < 0.05) break; } else { for (i = 0; i < Dcnt; i++) killbloc((GEN)Ds[i].primes); } } else { if (log2(maxD) > BITS_IN_LONG - 2 * (log2(L) + 2)) { char *err = stack_sprintf("modular polynomial of level %ld and invariant %ld",L,inv); pari_err(e_ARCH, err); } } maxD *= 2; minD += 4; dbg_printf(0)(" Doubling discriminant search space (closest: %.1f%%, cost ratio: %.1f)...\n", eps*100, cost/(double)(d*(L-1))); } max_max_D *= 2; } if (DEBUGLEVEL > 3) { pari_sp av = avma; err_printf("Found discriminant(s):\n"); for (i = 0; i < best_cnt; ++i) { h = itos(classno(stoi(bestD[i].D1))); avma = av; err_printf(" D = %ld, h = %ld, u = %ld, L0 = %ld, L1 = %ld, n1 = %ld, n2 = %ld, cost = %ld\n", bestD[i].D1, h, usqrt(bestD[i].D1 / bestD[i].D0), bestD[i].L0, bestD[i].L1, bestD[i].n1, bestD[i].n2, bestD[i].cost); } err_printf("(off target by %.1f%%, cost ratio: %.1f)\n", best_eps*100, best_cost/(double)(d*(L-1))); } return best_cnt; } pari-2.11.2/src/basemath/map.c0000644000175000017500000002500613326135265014463 0ustar billbill/* Copyright (C) 2015 The PARI group. This file is part of the PARI package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #define tvalue(i) gmael(t,(i),1) #define tleft(i) mael3(t,(i),2,1) #define tright(i) mael3(t,(i),2,2) #define theight(i) mael3(t,(i),2,3) static GEN treesearch(GEN T, GEN x, long mode) { long i = 1; GEN t = list_data(T); if (!t || lg(t)==1) return NULL; while(i) { long c = mode == 0 ? cmp_universal(x, tvalue(i)): cmp_universal(x, gel(tvalue(i),1)); if (c) i = c < 0 ? tleft(i): tright(i); else return tvalue(i); } return NULL; } static long treeparent_r(GEN t, GEN x, long i, long mode, long parent) { long c; if (i==0) return parent; c = mode == 0 ? cmp_universal(x, tvalue(i)): cmp_universal(x, gel(tvalue(i),1)); if (c < 0) return treeparent_r(t,x,tleft(i),mode,i); else if (c > 0) return treeparent_r(t,x,tright(i),mode,i); else return parent; } static long treeparent(GEN T, GEN x, long mode) { GEN t = list_data(T); return t ? treeparent_r(t, x, 1, mode, 0): 0; } static void treekeys_r(GEN t, long i, GEN V, long *n, long mode) { if (i==0) return; treekeys_r(t, tleft(i), V, n, mode); gel(V, ++*n) = gcopy(mode == 0 ? tvalue(i): gel(tvalue(i),1)); treekeys_r(t, tright(i), V, n, mode); } static GEN treekeys(GEN T, long mode) { long n = 0; GEN t = list_data(T); GEN V; if (!t || lg(t)==1) return cgetg(1, t_VEC); V = cgetg(lg(t), t_VEC); treekeys_r(t, 1, V, &n, mode); return V; } static void treekeys_i_r(GEN t, long i, GEN V, long *n, long mode) { if (i==0) return; treekeys_i_r(t, tleft(i), V, n, mode); gel(V, ++*n) = mode == 0 ? tvalue(i): gel(tvalue(i),1); treekeys_r(t, tright(i), V, n, mode); } static GEN treekeys_i(GEN T, long mode) { long n = 0; GEN t = list_data(T); GEN V; if (!t || lg(t)==1) return cgetg(1, t_VEC); V = cgetg(lg(t), t_VEC); treekeys_i_r(t, 1, V, &n, mode); return V; } static void treemat_r(GEN t, long i, GEN V, long *n) { if (i==0) return; treemat_r(t, tleft(i), V, n); ++*n; gmael(V, 1, *n) = gcopy(gel(tvalue(i), 1)); gmael(V, 2, *n) = gcopy(gel(tvalue(i), 2)); treemat_r(t, tright(i), V, n); } static GEN treemat(GEN T) { long n = 0; GEN t = list_data(T); GEN V; if (!t || lg(t)==1) return cgetg(1, t_MAT); V = cgetg(3, t_MAT); gel(V,1) = cgetg(lg(t), t_COL); gel(V,2) = cgetg(lg(t), t_COL); treemat_r(t, 1, V, &n); return V; } static void treemat_i_r(GEN t, long i, GEN V, long *n) { if (i==0) return; treemat_i_r(t, tleft(i), V, n); ++*n; gmael(V, 1, *n) = gel(tvalue(i), 1); gmael(V, 2, *n) = gel(tvalue(i), 2); treemat_r(t, tright(i), V, n); } static GEN treemat_i(GEN T) { long n = 0; GEN t = list_data(T); GEN V; if (!t || lg(t)==1) return cgetg(1, t_MAT); V = cgetg(3, t_MAT); gel(V,1) = cgetg(lg(t), t_COL); gel(V,2) = cgetg(lg(t), t_COL); treemat_i_r(t, 1, V, &n); return V; } static void treemap_i_r(GEN t, long i, long a, long c, GEN p, GEN M) { long b = (a+c)>>1; GEN x = mkvec2(gcopy(gmael(M, 1, p[b])), gcopy(gmael(M, 2, p[b]))); if (a == c) gel(t, i) = mkvec2(x, mkvecsmall3(0, 0, 1)); else if (a+1 == c) { treemap_i_r(t, i+1, a+1, c, p, M); gel(t, i) = mkvec2(x, mkvecsmall3(0, i+1, theight(i+1) + 1)); } else { long l = i+1, r = l + b - a, h; treemap_i_r(t, l, a, b-1, p, M); treemap_i_r(t, r, b+1, c, p, M); h = maxss(theight(l), theight(r))+1; gel(t, i) = mkvec2(x, mkvecsmall3(l, r, h)); } } static void treemap_i(GEN t, GEN p, GEN M) { treemap_i_r(t, 1, 1, lg(p)-1, p, M); } #define value(i) gmael(list_data(T),(i),1) #define left(i) mael3(list_data(T),(i),2,1) #define right(i) mael3(list_data(T),(i),2,2) #define height(i) mael3(list_data(T),(i),2,3) static long treeheight(GEN T, long i) { return i? height(i): 0; } static void change_leaf(GEN T, GEN x, long p) { pari_sp av = avma; listput(T, mkvec2(x, gmael(list_data(T), p, 2)), p); avma = av; } static long new_leaf(GEN T, GEN x) { pari_sp av = avma; listput(T, mkvec2(x, mkvecsmall3(0,0,1)), 0); avma = av; return lg(list_data(T))-1; } static void fix_height(GEN T, long x) { height(x) = maxss(treeheight(T,left(x)), treeheight(T,right(x)))+1; } static long treebalance(GEN T, long i) { return i ? treeheight(T,left(i)) - treeheight(T,right(i)): 0; } static long rotright(GEN T, long y) { long x = left(y); long t = right(x); right(x) = y; left(y) = t; fix_height(T, y); fix_height(T, x); return x; } static long rotleft(GEN T, long x) { long y = right(x); long t = left(y); left(y) = x; right(x) = t; fix_height(T, x); fix_height(T, y); return y; } static long treeinsert_r(GEN T, GEN x, long i, long *d, long mode) { long b, c; if (i==0 || !list_data(T) || lg(list_data(T))==1) return new_leaf(T, x); c = mode == 0 ? cmp_universal(x, value(i)): cmp_universal(gel(x,1), gel(value(i),1)); if (c < 0) { long s = treeinsert_r(T, x, left(i), d, mode); if (s < 0) return s; left(i) = s; } else if (c > 0) { long s = treeinsert_r(T, x, right(i), d, mode); if (s < 0) return s; right(i) = s; } else return -i; fix_height(T, i); b = treebalance(T, i); if (b > 1) { if (*d > 0) left(i) = rotleft(T, left(i)); return rotright(T, i); } if (b < -1) { if (*d < 0) right(i) = rotright(T, right(i)); return rotleft(T, i); } *d = c; return i; } static long treeinsert(GEN T, GEN x, long mode) { GEN d; long c = 0; long r = treeinsert_r(T, x, 1, &c, mode); if (r < 0) return -r; if (r == 1) return 0; d = list_data(T); /* By convention we want the root to be 1 */ swap(gel(d,1), gel(d,r)); if (left(1) == 1) left(1)=r; else if (right(1) == 1) right(1)=r; else pari_err_BUG("treeadd"); return 0; } static long treedelete_r(GEN T, GEN x, long i, long mode, long *dead) { long b, c; if (i==0 || !list_data(T) || lg(list_data(T))==1) return -1; c = mode == 0 ? cmp_universal(x, value(i)): cmp_universal(x, gel(value(i),1)); if (c < 0) { long s = treedelete_r(T, x, left(i), mode, dead); if (s < 0) return s; left(i) = s; } else if (c > 0) { long s = treedelete_r(T, x, right(i), mode, dead); if (s < 0) return s; right(i) = s; } else { *dead = i; if (left(i)==0 && right(i)==0) return 0; else if (left(i)==0) return right(i); else if (right(i)==0) return left(i); else { GEN v; GEN d = list_data(T); long j = right(i); while (left(j)) j = left(j); v = mode == 0 ? value(j): gel(value(j), 1); right(i) = treedelete_r(T, v, right(i), mode, dead); swap(gel(d,i), gel(d,j)); lswap(left(i),left(j)); lswap(right(i),right(j)); lswap(height(i),height(j)); } } fix_height(T, i); b = treebalance(T, i); if (b > 1 && treebalance(T, left(i)) >= 0) return rotright(T, i); if (b > 1 && treebalance(T, left(i)) < 0) { left(i) = rotleft(T, left(i)); return rotright(T, i); } if (b < -1 && treebalance(T, right(i)) <= 0) return rotleft(T,i); if (b < -1 && treebalance(T, right(i)) > 0) { right(i) = rotright(T, right(i)); return rotleft(T, i); } return i; } static long treedelete(GEN T, GEN x, long mode) { GEN d = list_data(T); long dead, l; long r = treedelete_r(T, x, 1, mode, &dead); if (r < 0) return 0; if (r > 1) { /* By convention we want the root to be 1 */ swap(gel(d,1), gel(d,r)); if (left(1) == 1) left(1) = r; else if (right(1) == 1) right(1) = r; else dead = r; } /* We want the dead to be last */ l = lg(d)-1; if (dead != l) { long p = treeparent(T, gel(value(l), 1), mode); if (left(p) == l) left(p) = dead; else if (right(p) == l) right(p) = dead; else pari_err_BUG("treedelete2"); swap(gel(d, dead),gel(d, l)); } listpop(T, 0); return 1; } void mapput(GEN T, GEN a, GEN b) { pari_sp av = avma; long i; GEN p; if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("mapput",T); p = mkvec2(a, b); i = treeinsert(T, p, 1); if (i) change_leaf(T, p, i); avma = av; } void mapdelete(GEN T, GEN a) { pari_sp av = avma; long s; if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("mapdelete",T); s = treedelete(T, a, 1); if (!s) pari_err_COMPONENT("mapdelete", "not in", strtoGENstr("map"), a); avma = av; } GEN mapget(GEN T, GEN a) { GEN x; if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("mapget",T); x = treesearch(T, a, 1); if (!x) pari_err_COMPONENT("mapget", "not in", strtoGENstr("map"), a); return gcopy(gel(x, 2)); } int mapisdefined(GEN T, GEN a, GEN *pt_z) { GEN x; if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("mapisdefined",T); x = treesearch(T, a, 1); if (!x) return 0; if (pt_z) *pt_z = gcopy(gel(x, 2)); return 1; } GEN mapdomain(GEN T) { if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("mapdomain",T); return treekeys(T,1); } GEN mapdomain_shallow(GEN T) { if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("mapdomain_shallow",T); return treekeys_i(T,1); } GEN maptomat(GEN T) { if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("maptomat",T); return treemat(T); } GEN maptomat_shallow(GEN T) { if (typ(T)!=t_LIST || list_typ(T)!=t_LIST_MAP) pari_err_TYPE("maptomap_shallow",T); return treemat_i(T); } GEN gtomap(GEN x) { if (!x) return mkmap(); switch(typ(x)) { case t_MAT: { long n, l = lg(x); GEN M, p; if (l == 1 || lgcols(x)==1) return mkmap(); if (l != 3) pari_err_TYPE("Map",x); p = gen_indexsort_uniq(gel(x,1),(void*)&cmp_universal, cmp_nodata); if (lg(p) != lgcols(x)) pari_err_DOMAIN("Map","x","is not",strtoGENstr("one-to-one"),x); n = lg(p)-1; M = cgetg(3, t_LIST); M[1] = evaltyp(t_LIST_MAP)|evallg(n); list_data(M) = cgetg(n+1, t_VEC); treemap_i(list_data(M), p, x); return M; } default: pari_err_TYPE("Map",x); } return NULL; /* LCOV_EXCL_LINE */ } pari-2.11.2/src/basemath/FpX_factor.c0000644000175000017500000016456313326135265015755 0ustar billbill/* Copyright (C) 2012 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /***********************************************************************/ /** **/ /** Factorisation over finite field **/ /** **/ /***********************************************************************/ /*******************************************************************/ /* */ /* ROOTS MODULO a prime p (no multiplicities) */ /* */ /*******************************************************************/ /* Replace F by a monic normalized FpX having the same factors; * assume p prime and *F a ZX */ static int ZX_factmod_init(GEN *F, GEN p) { if (lgefint(p) == 3) { ulong pp = p[2]; if (pp == 2) { *F = ZX_to_F2x(*F); return 0; } *F = ZX_to_Flx(*F, pp); if (lg(*F) > 3) *F = Flx_normalize(*F, pp); return 1; } *F = FpX_red(*F, p); if (lg(*F) > 3) *F = FpX_normalize(*F, p); return 2; } static void ZX_rootmod_init(GEN *F, GEN p) { if (lgefint(p) == 3) { ulong pp = p[2]; *F = ZX_to_Flx(*F, pp); if (lg(*F) > 3) *F = Flx_normalize(*F, pp); } else { *F = FpX_red(*F, p); if (lg(*F) > 3) *F = FpX_normalize(*F, p); } } /* return 1,...,p-1 [not_0 = 1] or 0,...,p [not_0 = 0] */ static GEN all_roots_mod_p(ulong p, int not_0) { GEN r; ulong i; if (not_0) { r = cgetg(p, t_VECSMALL); for (i = 1; i < p; i++) r[i] = i; } else { r = cgetg(p+1, t_VECSMALL); for (i = 0; i < p; i++) r[i+1] = i; } return r; } /* X^n - 1 */ static GEN Flx_Xnm1(long sv, long n, ulong p) { GEN t = cgetg(n+3, t_VECSMALL); long i; t[1] = sv; t[2] = p - 1; for (i = 3; i <= n+1; i++) t[i] = 0; t[i] = 1; return t; } /* X^n + 1 */ static GEN Flx_Xn1(long sv, long n, ulong p) { GEN t = cgetg(n+3, t_VECSMALL); long i; (void) p; t[1] = sv; t[2] = 1; for (i = 3; i <= n+1; i++) t[i] = 0; t[i] = 1; return t; } static ulong Fl_nonsquare(ulong p) { long k = 2; for (;; k++) { long i = krouu(k, p); if (!i) pari_err_PRIME("Fl_nonsquare",utoipos(p)); if (i < 0) return k; } } static GEN Flx_root_mod_2(GEN f) { int z1, z0 = !(f[2] & 1); long i,n; GEN y; for (i=2, n=1; i < lg(f); i++) n += f[i]; z1 = n & 1; y = cgetg(z0+z1+1, t_VECSMALL); i = 1; if (z0) y[i++] = 0; if (z1) y[i ] = 1; return y; } static ulong Flx_oneroot_mod_2(GEN f) { long i,n; if (!(f[2] & 1)) return 0; for (i=2, n=1; i < lg(f); i++) n += f[i]; if (n & 1) return 1; return 2; } static GEN FpX_roots_i(GEN f, GEN p); static GEN Flx_roots_i(GEN f, ulong p); static int cmpGuGu(GEN a, GEN b) { return (ulong)a < (ulong)b? -1: (a == b? 0: 1); } /* Generic driver to computes the roots of f modulo pp, using 'Roots' when * pp is a small prime. * if (gpwrap), check types thoroughly and return t_INTMODs, otherwise * assume that f is an FpX, pp a prime and return t_INTs */ static GEN rootmod_aux(GEN f, GEN pp) { GEN y; switch(lg(f)) { case 2: pari_err_ROOTS0("rootmod"); case 3: return cgetg(1,t_COL); } if (typ(f) == t_VECSMALL) { ulong p = pp[2]; if (p == 2) y = Flx_root_mod_2(f); else { if (!odd(p)) pari_err_PRIME("rootmod",utoi(p)); y = Flx_roots_i(f, p); } y = Flc_to_ZC(y); } else y = FpX_roots_i(f, pp); return y; } /* assume that f is a ZX and p a prime */ GEN FpX_roots(GEN f, GEN p) { pari_sp av = avma; GEN y; ZX_rootmod_init(&f, p); y = rootmod_aux(f, p); return gerepileupto(av, y); } /* assume x reduced mod p > 2, monic. */ static int FpX_quad_factortype(GEN x, GEN p) { GEN b = gel(x,3), c = gel(x,2); GEN D = subii(sqri(b), shifti(c,2)); return kronecker(D,p); } /* assume x reduced mod p, monic. Return one root, or NULL if irreducible */ static GEN FpX_quad_root(GEN x, GEN p, int unknown) { GEN s, D, b = gel(x,3), c = gel(x,2); if (absequaliu(p, 2)) { if (!signe(b)) return c; return signe(c)? NULL: gen_1; } D = subii(sqri(b), shifti(c,2)); D = remii(D,p); if (unknown && kronecker(D,p) == -1) return NULL; s = Fp_sqrt(D,p); /* p is not prime, go on and give e.g. maxord a chance to recover */ if (!s) return NULL; return Fp_halve(Fp_sub(s,b, p), p); } static GEN FpX_otherroot(GEN x, GEN r, GEN p) { return Fp_neg(Fp_add(gel(x,3), r, p), p); } /* disc(x^2+bx+c) = b^2 - 4c */ static ulong Fl_disc_bc(ulong b, ulong c, ulong p) { return Fl_sub(Fl_sqr(b,p), Fl_double(Fl_double(c,p),p), p); } /* p > 2 */ static ulong Flx_quad_root(GEN x, ulong p, int unknown) { ulong s, b = x[3], c = x[2]; ulong D = Fl_disc_bc(b, c, p); if (unknown && krouu(D,p) == -1) return p; s = Fl_sqrt(D,p); if (s==~0UL) return p; return Fl_halve(Fl_sub(s,b, p), p); } static ulong Flx_otherroot(GEN x, ulong r, ulong p) { return Fl_neg(Fl_add(x[3], r, p), p); } /* 'todo' contains the list of factors to be split. * 'done' the list of finished factors, no longer touched */ struct split_t { GEN todo, done; }; static void split_init(struct split_t *S, long max) { S->todo = vectrunc_init(max); S->done = vectrunc_init(max); } #if 0 /* move todo[i] to done */ static void split_convert(struct split_t *S, long i) { long n = lg(S->todo)-1; vectrunc_append(S->done, gel(S->todo,i)); if (n) gel(S->todo,i) = gel(S->todo, n); setlg(S->todo, n); } #endif /* append t to todo */ static void split_add(struct split_t *S, GEN t) { vectrunc_append(S->todo, t); } /* delete todo[i], add t to done */ static void split_moveto_done(struct split_t *S, long i, GEN t) { long n = lg(S->todo)-1; vectrunc_append(S->done, t); if (n) gel(S->todo,i) = gel(S->todo, n); setlg(S->todo, n); } /* append t to done */ static void split_add_done(struct split_t *S, GEN t) { vectrunc_append(S->done, t); } /* split todo[i] into a and b */ static void split_todo(struct split_t *S, long i, GEN a, GEN b) { gel(S->todo, i) = a; split_add(S, b); } /* split todo[i] into a and b, moved to done */ static void split_done(struct split_t *S, long i, GEN a, GEN b) { split_moveto_done(S, i, a); split_add_done(S, b); } /* by splitting, assume p > 2 prime, deg(f) > 0, and f monic */ static GEN FpX_roots_i(GEN f, GEN p) { GEN pol, pol0, a, q; struct split_t S; split_init(&S, lg(f)-1); settyp(S.done, t_COL); if (ZX_valrem(f, &f)) split_add_done(&S, gen_0); switch(degpol(f)) { case 0: return ZC_copy(S.done); case 1: split_add_done(&S, subii(p, gel(f,2))); return ZC_copy(S.done); case 2: { GEN s, r = FpX_quad_root(f, p, 1); if (r) { split_add_done(&S, r); s = FpX_otherroot(f,r, p); /* f not known to be square free yet */ if (!equalii(r, s)) split_add_done(&S, s); } return sort(S.done); } } a = FpXQ_pow(pol_x(varn(f)), subiu(p,1), f,p); if (lg(a) < 3) pari_err_PRIME("rootmod",p); a = FpX_Fp_sub_shallow(a, gen_1, p); /* a = x^(p-1) - 1 mod f */ a = FpX_gcd(f,a, p); if (!degpol(a)) return ZC_copy(S.done); split_add(&S, FpX_normalize(a,p)); q = shifti(p,-1); pol0 = icopy(gen_1); /* constant term, will vary in place */ pol = deg1pol_shallow(gen_1, pol0, varn(f)); for (pol0[2] = 1;; pol0[2]++) { long j, l = lg(S.todo); if (l == 1) return sort(S.done); if (pol0[2] == 100 && !BPSW_psp(p)) pari_err_PRIME("polrootsmod",p); for (j = 1; j < l; j++) { GEN b, r, s, c = gel(S.todo,j); switch(degpol(c)) { /* convert linear and quadratics to roots, try to split the rest */ case 1: split_moveto_done(&S, j, subii(p, gel(c,2))); j--; l--; break; case 2: r = FpX_quad_root(c, p, 0); if (!r) pari_err_PRIME("polrootsmod",p); s = FpX_otherroot(c,r, p); split_done(&S, j, r, s); j--; l--; break; default: b = FpXQ_pow(pol,q, c,p); if (degpol(b) <= 0) continue; b = FpX_gcd(c,FpX_Fp_sub_shallow(b,gen_1,p), p); if (!degpol(b)) continue; b = FpX_normalize(b, p); c = FpX_div(c,b, p); split_todo(&S, j, b, c); } } } } /* Assume f is normalized */ static ulong Flx_cubic_root(GEN ff, ulong p) { GEN f = Flx_normalize(ff,p); ulong pi = get_Fl_red(p); ulong a = f[4], b=f[3], c=f[2], p3 = p%3==1 ? (2*p+1)/3 :(p+1)/3; ulong t = Fl_mul_pre(a, p3, p, pi), t2 = Fl_sqr_pre(t, p, pi); ulong A = Fl_sub(b, Fl_triple(t2, p), p); ulong B = Fl_addmul_pre(c, t, Fl_sub(Fl_double(t2, p), b, p), p, pi); ulong A3 = Fl_mul_pre(A, p3, p, pi); ulong A32 = Fl_sqr_pre(A3, p, pi), A33 = Fl_mul_pre(A3, A32, p, pi); ulong S = Fl_neg(B,p), P = Fl_neg(A3,p); ulong D = Fl_add(Fl_sqr_pre(S, p, pi), Fl_double(Fl_double(A33, p), p), p); ulong s = Fl_sqrt_pre(D, p, pi), vS1, vS2; if (s!=~0UL) { ulong S1 = S==s ? S: Fl_halve(Fl_sub(S, s, p), p); if (p%3==2) /* 1 solutions */ vS1 = Fl_powu_pre(S1, (2*p-1)/3, p, pi); else { vS1 = Fl_sqrtl_pre(S1, 3, p, pi); if (vS1==~0UL) return p; /*0 solutions*/ /*3 solutions*/ } vS2 = P? Fl_mul_pre(P, Fl_inv(vS1, p), p, pi): 0; return Fl_sub(Fl_add(vS1,vS2, p), t, p); } else { pari_sp av = avma; GEN S1 = mkvecsmall2(Fl_halve(S, p), Fl_halve(1UL, p)); GEN vS1 = Fl2_sqrtn_pre(S1, utoi(3), D, p, pi, NULL); ulong Sa; if (!vS1) return p; /*0 solutions, p%3==2*/ Sa = vS1[1]; if (p%3==1) /*1 solutions*/ { ulong Fa = Fl2_norm_pre(vS1, D, p, pi); if (Fa!=P) Sa = Fl_mul(Sa, Fl_div(Fa, P, p),p); } avma = av; return Fl_sub(Fl_double(Sa,p),t,p); } } /* assume p > 2 prime */ static ulong Flx_oneroot_i(GEN f, ulong p, long fl) { GEN pol, a; ulong q; long da; if (Flx_val(f)) return 0; switch(degpol(f)) { case 1: return Fl_neg(f[2], p); case 2: return Flx_quad_root(f, p, 1); case 3: if (p>3) return Flx_cubic_root(f, p); /*FALL THROUGH*/ } if (!fl) { a = Flxq_powu(polx_Flx(f[1]), p - 1, f,p); if (lg(a) < 3) pari_err_PRIME("rootmod",utoipos(p)); a = Flx_Fl_add(a, p-1, p); /* a = x^(p-1) - 1 mod f */ a = Flx_gcd(f,a, p); } else a = f; da = degpol(a); if (!da) return p; a = Flx_normalize(a,p); q = p >> 1; pol = polx_Flx(f[1]); for(pol[2] = 1;; pol[2]++) { if (pol[2] == 1000 && !uisprime(p)) pari_err_PRIME("Flx_oneroot",utoipos(p)); switch(da) { case 1: return Fl_neg(a[2], p); case 2: return Flx_quad_root(a, p, 0); case 3: if (p>3) return Flx_cubic_root(a, p); /*FALL THROUGH*/ default: { GEN b = Flxq_powu(pol,q, a,p); long db; if (degpol(b) <= 0) continue; b = Flx_gcd(a,Flx_Fl_add(b,p-1,p), p); db = degpol(b); if (!db) continue; b = Flx_normalize(b, p); if (db <= (da >> 1)) { a = b; da = db; } else { a = Flx_div(a,b, p); da -= db; } } } } } /* assume p > 2 prime */ static GEN FpX_oneroot_i(GEN f, GEN p) { GEN pol, pol0, a, q; long da; if (ZX_val(f)) return gen_0; switch(degpol(f)) { case 1: return subii(p, gel(f,2)); case 2: return FpX_quad_root(f, p, 1); } a = FpXQ_pow(pol_x(varn(f)), subiu(p,1), f,p); if (lg(a) < 3) pari_err_PRIME("rootmod",p); a = FpX_Fp_sub_shallow(a, gen_1, p); /* a = x^(p-1) - 1 mod f */ a = FpX_gcd(f,a, p); da = degpol(a); if (!da) return NULL; a = FpX_normalize(a,p); q = shifti(p,-1); pol0 = icopy(gen_1); /* constant term, will vary in place */ pol = deg1pol_shallow(gen_1, pol0, varn(f)); for (pol0[2]=1; ; pol0[2]++) { if (pol0[2] == 1000 && !BPSW_psp(p)) pari_err_PRIME("FpX_oneroot",p); switch(da) { case 1: return subii(p, gel(a,2)); case 2: return FpX_quad_root(a, p, 0); default: { GEN b = FpXQ_pow(pol,q, a,p); long db; if (degpol(b) <= 0) continue; b = FpX_gcd(a,FpX_Fp_sub_shallow(b,gen_1,p), p); db = degpol(b); if (!db) continue; b = FpX_normalize(b, p); if (db <= (da >> 1)) { a = b; da = db; } else { a = FpX_div(a,b, p); da -= db; } } } } } ulong Flx_oneroot(GEN f, ulong p) { pari_sp av = avma; ulong r; switch(lg(f)) { case 2: return 0; case 3: avma = av; return p; } if (p == 2) return Flx_oneroot_mod_2(f); r = Flx_oneroot_i(Flx_normalize(f, p), p, 0); avma = av; return r; } ulong Flx_oneroot_split(GEN f, ulong p) { pari_sp av = avma; ulong r; switch(lg(f)) { case 2: return 0; case 3: avma = av; return p; } if (p == 2) return Flx_oneroot_mod_2(f); r = Flx_oneroot_i(Flx_normalize(f, p), p, 1); avma = av; return r; } /* assume that p is prime */ GEN FpX_oneroot(GEN f, GEN pp) { pari_sp av = avma; ZX_rootmod_init(&f, pp); switch(lg(f)) { case 2: avma = av; return gen_0; case 3: avma = av; return NULL; } if (typ(f) == t_VECSMALL) { ulong r, p = pp[2]; if (p == 2) r = Flx_oneroot_mod_2(f); else r = Flx_oneroot_i(f, p, 0); avma = av; return (r == p)? NULL: utoi(r); } f = FpX_oneroot_i(f, pp); if (!f) { avma = av; return NULL; } return gerepileuptoint(av, f); } /* returns a root of unity in F_p that is suitable for finding a factor */ /* of degree deg_factor of a polynomial of degree deg; the order is */ /* returned in n */ /* A good choice seems to be n close to deg/deg_factor; we choose n */ /* twice as big and decrement until it divides p-1. */ static GEN good_root_of_unity(GEN p, long deg, long deg_factor, long *pt_n) { pari_sp ltop = avma; GEN pm, factn, power, base, zeta; long n; pm = subis (p, 1ul); for (n = deg / 2 / deg_factor + 1; !dvdiu (pm, n); n--); factn = Z_factor(stoi(n)); power = diviuexact (pm, n); base = gen_1; do { base = addis (base, 1l); zeta = Fp_pow (base, power, p); } while (!equaliu (Fp_order (zeta, factn, p), n)); *pt_n = n; return gerepileuptoint (ltop, zeta); } GEN FpX_oneroot_split(GEN fact, GEN p) { pari_sp av = avma; long n, deg_f, i, dmin; GEN prim, expo, minfactor, xplusa, zeta, xpow; fact = FpX_normalize(fact, p); deg_f = degpol(fact); if (deg_f<=2) return FpX_oneroot(fact, p); minfactor = fact; /* factor of minimal degree found so far */ dmin = degpol(minfactor); prim = good_root_of_unity(p, deg_f, 1, &n); expo = diviuexact(subiu(p, 1), n); xplusa = pol_x(varn(fact)); zeta = gen_1; while (dmin != 1) { /* split minfactor by computing its gcd with (X+a)^exp-zeta, where */ /* zeta varies over the roots of unity in F_p */ fact = minfactor; deg_f = dmin; /* update X+a, avoid a=0 */ gel (xplusa, 2) = addis (gel (xplusa, 2), 1); xpow = FpXQ_pow (xplusa, expo, fact, p); for (i = 0; i < n; i++) { GEN tmp = FpX_gcd(FpX_Fp_sub(xpow, zeta, p), fact, p); long dtmp = degpol(tmp); if (dtmp > 0 && dtmp < deg_f) { fact = FpX_div(fact, tmp, p); deg_f = degpol(fact); if (dtmp < dmin) { minfactor = FpX_normalize (tmp, p); dmin = dtmp; if (dmin == 1 || dmin <= deg_f / (n / 2) + 1) /* stop early to avoid too many gcds */ break; } } zeta = Fp_mul (zeta, prim, p); } } return gerepileuptoint(av, Fp_neg(gel(minfactor,2), p)); } /*******************************************************************/ /* */ /* FACTORISATION MODULO p */ /* */ /*******************************************************************/ /* F / E a vector of vectors of factors / exponents of virtual length l * (their real lg may be larger). Set their lg to j, concat and return [F,E] */ static GEN FE_concat(GEN F, GEN E, long l) { setlg(E,l); E = shallowconcat1(E); setlg(F,l); F = shallowconcat1(F); return mkvec2(F,E); } static GEN ddf_to_ddf2_i(GEN V, long fl) { GEN F, D; long i, j, l = lg(V); F = cgetg(l, t_VEC); D = cgetg(l, t_VECSMALL); for (i = j = 1; i < l; i++) { GEN Vi = gel(V,i); if ((fl==2 && F2x_degree(Vi) == 0) ||(fl==0 && degpol(Vi) == 0)) continue; gel(F,j) = Vi; uel(D,j) = i; j++; } setlg(F,j); setlg(D,j); return mkvec2(F,D); } GEN ddf_to_ddf2(GEN V) { return ddf_to_ddf2_i(V, 0); } static GEN F2x_ddf_to_ddf2(GEN V) { return ddf_to_ddf2_i(V, 2); } GEN vddf_to_simplefact(GEN V, long d) { GEN E, F; long i, j, c, l = lg(V); F = cgetg(d+1, t_VECSMALL); E = cgetg(d+1, t_VECSMALL); for (i = c = 1; i < l; i++) { GEN Vi = gel(V,i); long l = lg(Vi); for (j = 1; j < l; j++) { long k, n = degpol(gel(Vi,j)) / j; for (k = 1; k <= n; k++) { uel(F,c) = j; uel(E,c) = i; c++; } } } setlg(F,c); setlg(E,c); return sort_factor(mkvec2(F,E), (void*)&cmpGuGu, cmp_nodata); } /* product of terms of degree 1 in factorization of f */ GEN FpX_split_part(GEN f, GEN p) { long n = degpol(f); GEN z, X = pol_x(varn(f)); if (n <= 1) return f; f = FpX_red(f, p); z = FpX_sub(FpX_Frobenius(f, p), X, p); return FpX_gcd(z,f,p); } /* Compute the number of roots in Fp without counting multiplicity * return -1 for 0 polynomial. lc(f) must be prime to p. */ long FpX_nbroots(GEN f, GEN p) { pari_sp av = avma; GEN z = FpX_split_part(f, p); avma = av; return degpol(z); } int FpX_is_totally_split(GEN f, GEN p) { long n=degpol(f); pari_sp av = avma; if (n <= 1) return 1; if (abscmpui(n, p) > 0) return 0; f = FpX_red(f, p); avma = av; return gequalX(FpX_Frobenius(f, p)); } long Flx_nbroots(GEN f, ulong p) { long n = degpol(f); pari_sp av = avma; GEN z; if (n <= 1) return n; if (n == 2) { ulong D; if (p==2) return (f[2]==0) + (f[2]!=f[3]); D = Fl_sub(Fl_sqr(f[3], p), Fl_mul(Fl_mul(f[4], f[2], p), 4%p, p), p); return 1 + krouu(D,p); } z = Flx_sub(Flx_Frobenius(f, p), polx_Flx(f[1]), p); z = Flx_gcd(z, f, p); avma = av; return degpol(z); } long FpX_ddf_degree(GEN T, GEN XP, GEN p) { pari_sp av = avma; GEN X, b, g, xq; long i, j, n, v, B, l, m; pari_timer ti; hashtable h; n = get_FpX_degree(T); v = get_FpX_var(T); X = pol_x(v); if (ZX_equal(X,XP)) return 1; B = n/2; l = usqrt(B); m = (B+l-1)/l; T = FpX_get_red(T, p); hash_init_GEN(&h, l+2, ZX_equal, 1); hash_insert_long(&h, X, 0); hash_insert_long(&h, XP, 1); if (DEBUGLEVEL>=7) timer_start(&ti); b = XP; xq = FpXQ_powers(b, brent_kung_optpow(n, l-1, 1), T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_degree: xq baby"); for (i = 3; i <= l+1; i++) { b = FpX_FpXQV_eval(b, xq, T, p); if (gequalX(b)) { avma = av; return i-1; } hash_insert_long(&h, b, i-1); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_degree: baby"); g = b; xq = FpXQ_powers(g, brent_kung_optpow(n, m, 1), T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_degree: xq giant"); for(i = 2; i <= m+1; i++) { g = FpX_FpXQV_eval(g, xq, T, p); if (hash_haskey_long(&h, g, &j)) { avma=av; return l*i-j; } } avma = av; return n; } /* See */ static GEN FpX_ddf_Shoup(GEN T, GEN XP, GEN p) { GEN b, g, h, F, f, Tr, xq; long i, j, n, v, B, l, m; pari_timer ti; n = get_FpX_degree(T); v = get_FpX_var(T); if (n == 0) return cgetg(1, t_VEC); if (n == 1) return mkvec(get_FpX_mod(T)); B = n/2; l = usqrt(B); m = (B+l-1)/l; T = FpX_get_red(T, p); b = cgetg(l+2, t_VEC); gel(b, 1) = pol_x(v); gel(b, 2) = XP; if (DEBUGLEVEL>=7) timer_start(&ti); xq = FpXQ_powers(gel(b, 2), brent_kung_optpow(n, l-1, 1), T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: xq baby"); for (i = 3; i <= l+1; i++) gel(b, i) = FpX_FpXQV_eval(gel(b, i-1), xq, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: baby"); xq = FpXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: xq giant"); g = cgetg(m+1, t_VEC); gel(g, 1) = gel(xq, 2); for(i = 2; i <= m; i++) gel(g, i) = FpX_FpXQV_eval(gel(g, i-1), xq, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: giant"); h = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { pari_sp av = avma; GEN gj = gel(g,j), e = FpX_sub(gj, gel(b,1), p); for (i = 2; i <= l; i++) e = FpXQ_mul(e, FpX_sub(gj, gel(b,i), p), T, p); gel(h,j) = gerepileupto(av, e); } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: diff"); Tr = get_FpX_mod(T); F = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { GEN u = FpX_gcd(Tr, gel(h,j), p); if (degpol(u)) { u = FpX_normalize(u, p); Tr = FpX_div(Tr, u, p); } gel(F,j) = u; } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: F"); f = const_vec(n, pol_1(v)); for (j = 1; j <= m; j++) { GEN e = gel(F, j); for (i=l-1; i >= 0; i--) { GEN u = FpX_gcd(e, FpX_sub(gel(g, j), gel(b, i+1), p), p); if (degpol(u)) { u = FpX_normalize(u, p); gel(f, l*j-i) = u; e = FpX_div(e, u, p); } if (!degpol(e)) break; } } if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: f"); if (degpol(Tr)) gel(f, degpol(Tr)) = Tr; return f; } static void FpX_edf_simple(GEN Tp, GEN XP, long d, GEN p, GEN V, long idx) { long n = degpol(Tp), r = n/d, ct = 0; GEN T, f, ff, p2; if (r==1) { gel(V, idx) = Tp; return; } p2 = shifti(p,-1); T = FpX_get_red(Tp, p); XP = FpX_rem(XP, T, p); while (1) { pari_sp btop = avma; long i; GEN g = random_FpX(n, varn(Tp), p); GEN t = gel(FpXQ_auttrace(mkvec2(XP, g), d, T, p), 2); if (signe(t) == 0) continue; for(i=1; i<=10; i++) { pari_sp btop2 = avma; GEN R = FpXQ_pow(FpX_Fp_add(t, randomi(p), p), p2, T, p); f = FpX_gcd(FpX_Fp_sub(R, gen_1, p), Tp, p); if (degpol(f) > 0 && degpol(f) < n) break; avma = btop2; } if (degpol(f) > 0 && degpol(f) < n) break; if (++ct == 10 && !BPSW_psp(p)) pari_err_PRIME("FpX_edf_simple",p); avma = btop; } f = FpX_normalize(f, p); ff = FpX_div(Tp, f ,p); FpX_edf_simple(f, XP, d, p, V, idx); FpX_edf_simple(ff, XP, d, p, V, idx+degpol(f)/d); } static void FpX_edf_rec(GEN T, GEN hp, GEN t, long d, GEN p2, GEN p, GEN V, long idx) { pari_sp av; GEN Tp = get_FpX_mod(T); long n = degpol(hp), vT = varn(Tp), ct = 0; GEN u1, u2, f1, f2, R, h; h = FpX_get_red(hp, p); t = FpX_rem(t, T, p); av = avma; do { avma = av; R = FpXQ_pow(deg1pol(gen_1, randomi(p), vT), p2, h, p); u1 = FpX_gcd(FpX_Fp_sub(R, gen_1, p), hp, p); if (++ct == 10 && !BPSW_psp(p)) pari_err_PRIME("FpX_edf_rec",p); } while (degpol(u1)==0 || degpol(u1)==n); f1 = FpX_gcd(FpX_FpXQ_eval(u1, t, T, p), Tp, p); f1 = FpX_normalize(f1, p); u2 = FpX_div(hp, u1, p); f2 = FpX_div(Tp, f1, p); if (degpol(u1)==1) gel(V, idx) = f1; else FpX_edf_rec(FpX_get_red(f1, p), u1, t, d, p2, p, V, idx); idx += degpol(f1)/d; if (degpol(u2)==1) gel(V, idx) = f2; else FpX_edf_rec(FpX_get_red(f2, p), u2, t, d, p2, p, V, idx); } /* assume Tp a squarefree product of r > 1 irred. factors of degree d */ static void FpX_edf(GEN Tp, GEN XP, long d, GEN p, GEN V, long idx) { long n = degpol(Tp), r = n/d, vT = varn(Tp), ct = 0; GEN T, h, t; pari_timer ti; T = FpX_get_red(Tp, p); XP = FpX_rem(XP, T, p); if (DEBUGLEVEL>=7) timer_start(&ti); do { GEN g = random_FpX(n, vT, p); t = gel(FpXQ_auttrace(mkvec2(XP, g), d, T, p), 2); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_edf: FpXQ_auttrace"); h = FpXQ_minpoly(t, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_edf: FpXQ_minpoly"); if (++ct == 10 && !BPSW_psp(p)) pari_err_PRIME("FpX_edf",p); } while (degpol(h) != r); FpX_edf_rec(T, h, t, d, shifti(p, -1), p, V, idx); } static GEN FpX_factor_Shoup(GEN T, GEN p) { long i, n, s = 0; GEN XP, D, V; long e = expi(p); pari_timer ti; n = get_FpX_degree(T); T = FpX_get_red(T, p); if (DEBUGLEVEL>=6) timer_start(&ti); XP = FpX_Frobenius(T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_Frobenius"); D = FpX_ddf_Shoup(T, XP, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_ddf_Shoup"); s = ddf_to_nbfact(D); V = cgetg(s+1, t_COL); for (i = 1, s = 1; i <= n; i++) { GEN Di = gel(D,i); long ni = degpol(Di), ri = ni/i; if (ni == 0) continue; Di = FpX_normalize(Di, p); if (ni == i) { gel(V, s++) = Di; continue; } if (ri <= e*expu(e)) FpX_edf(Di, XP, i, p, V, s); else FpX_edf_simple(Di, XP, i, p, V, s); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_edf(%ld)",i); s += ri; } return V; } long ddf_to_nbfact(GEN D) { long l = lg(D), i, s = 0; for(i = 1; i < l; i++) s += degpol(gel(D,i))/i; return s; } /* Yun algorithm: Assume p > degpol(T) */ static GEN FpX_factor_Yun(GEN T, GEN p) { long n = degpol(T), i = 1; GEN a, b, c, d = FpX_deriv(T, p); GEN V = cgetg(n+1,t_VEC); a = FpX_gcd(T, d, p); if (degpol(a) == 0) return mkvec(T); b = FpX_div(T, a, p); do { c = FpX_div(d, a, p); d = FpX_sub(c, FpX_deriv(b, p), p); a = FpX_normalize(FpX_gcd(b, d, p), p); gel(V, i++) = a; b = FpX_div(b, a, p); } while (degpol(b)); setlg(V, i); return V; } GEN FpX_factor_squarefree(GEN T, GEN p) { if (lgefint(p)==3) { ulong pp = (ulong)p[2]; GEN u = Flx_factor_squarefree(ZX_to_Flx(T,pp), pp); return FlxV_to_ZXV(u); } return FpX_factor_Yun(T, p); } long FpX_ispower(GEN f, ulong k, GEN p, GEN *pt_r) { pari_sp av = avma; GEN lc, F; long i, l, n = degpol(f), v = varn(f); if (n % k) return 0; if (lgefint(p)==3) { ulong pp = p[2]; GEN fp = ZX_to_Flx(f, pp); if (!Flx_ispower(fp, k, pp, pt_r)) { avma = av; return 0; } if (pt_r) *pt_r = gerepileupto(av, Flx_to_ZX(*pt_r)); else avma = av; return 1; } lc = Fp_sqrtn(leading_coeff(f), stoi(k), p, NULL); if (!lc) { av = avma; return 0; } F = FpX_factor_Yun(f, p); l = lg(F)-1; for(i=1; i <= l; i++) if (i%k && degpol(gel(F,i))) { avma = av; return 0; } if (pt_r) { GEN r = scalarpol(lc, v), s = pol_1(v); for (i=l; i>=1; i--) { if (i%k) continue; s = FpX_mul(s, gel(F,i), p); r = FpX_mul(r, s, p); } *pt_r = gerepileupto(av, r); } else av = avma; return 1; } static GEN FpX_factor_Cantor(GEN T, GEN p) { GEN E, F, V = FpX_factor_Yun(T, p); long i, j, l = lg(V); F = cgetg(l, t_VEC); E = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (degpol(gel(V,i))) { GEN Fj = FpX_factor_Shoup(gel(V,i), p); gel(F, j) = Fj; gel(E, j) = const_vecsmall(lg(Fj)-1, i); j++; } return sort_factor_pol(FE_concat(F,E,j), cmpii); } static GEN FpX_ddf_i(GEN T, GEN p) { GEN XP; T = FpX_get_red(T, p); XP = FpX_Frobenius(T, p); return ddf_to_ddf2(FpX_ddf_Shoup(T, XP, p)); } GEN FpX_ddf(GEN f, GEN p) { pari_sp av = avma; GEN F; switch(ZX_factmod_init(&f, p)) { case 0: F = F2x_ddf(f); F2xV_to_ZXV_inplace(gel(F,1)); break; case 1: F = Flx_ddf(f,p[2]); FlxV_to_ZXV_inplace(gel(F,1)); break; default: F = FpX_ddf_i(f,p); break; } return gerepilecopy(av, F); } static GEN Flx_simplefact_Cantor(GEN T, ulong p); static GEN FpX_simplefact_Cantor(GEN T, GEN p) { GEN V, XP; long i, l; if (lgefint(p) == 3) { ulong pp = p[2]; return Flx_simplefact_Cantor(ZX_to_Flx(T,pp), pp); } T = FpX_get_red(T, p); XP = FpX_Frobenius(T, p); V = FpX_factor_Yun(get_FpX_mod(T), p); l = lg(V); for (i=1; i < l; i++) gel(V,i) = FpX_ddf_Shoup(gel(V,i), XP, p); return vddf_to_simplefact(V, get_FpX_degree(T)); } static int FpX_isirred_Cantor(GEN Tp, GEN p) { pari_sp av = avma; pari_timer ti; long n, d; GEN T = get_FpX_mod(Tp); GEN dT = FpX_deriv(T, p); GEN XP, D; if (degpol(FpX_gcd(T, dT, p)) != 0) { avma = av; return 0; } n = get_FpX_degree(T); T = FpX_get_red(Tp, p); if (DEBUGLEVEL>=6) timer_start(&ti); XP = FpX_Frobenius(T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_Frobenius"); D = FpX_ddf_Shoup(T, XP, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_ddf_Shoup"); d = degpol(gel(D, n)); avma = av; return d==n; } static GEN FpX_factor_deg2(GEN f, GEN p, long d, long flag); /*Assume that p is large and odd*/ static GEN FpX_factor_i(GEN f, GEN pp, long flag) { long d = degpol(f); if (d <= 2) return FpX_factor_deg2(f,pp,d,flag); switch(flag) { default: return FpX_factor_Cantor(f, pp); case 1: return FpX_simplefact_Cantor(f, pp); case 2: return FpX_isirred_Cantor(f, pp)? gen_1: NULL; } } long FpX_nbfact_Frobenius(GEN T, GEN XP, GEN p) { pari_sp av = avma; long s = ddf_to_nbfact(FpX_ddf_Shoup(T, XP, p)); avma = av; return s; } long FpX_nbfact(GEN T, GEN p) { pari_sp av = avma; GEN XP = FpX_Frobenius(T, p); long n = FpX_nbfact_Frobenius(T, XP, p); avma = av; return n; } /* p > 2 */ static GEN FpX_is_irred_2(GEN f, GEN p, long d) { switch(d) { case -1: case 0: return NULL; case 1: return gen_1; } return FpX_quad_factortype(f, p) == -1? gen_1: NULL; } /* p > 2 */ static GEN FpX_degfact_2(GEN f, GEN p, long d) { switch(d) { case -1:retmkvec2(mkvecsmall(-1),mkvecsmall(1)); case 0: return trivial_fact(); case 1: retmkvec2(mkvecsmall(1), mkvecsmall(1)); } switch(FpX_quad_factortype(f, p)) { case 1: retmkvec2(mkvecsmall2(1,1), mkvecsmall2(1,1)); case -1: retmkvec2(mkvecsmall(2), mkvecsmall(1)); default: retmkvec2(mkvecsmall(1), mkvecsmall(2)); } } GEN prime_fact(GEN x) { retmkmat2(mkcolcopy(x), mkcol(gen_1)); } GEN trivial_fact(void) { retmkmat2(cgetg(1,t_COL), cgetg(1,t_COL)); } /* not gerepile safe */ static GEN FpX_factor_2(GEN f, GEN p, long d) { GEN r, s, R, S; long v; int sgn; switch(d) { case -1: retmkvec2(mkcol(pol_0(varn(f))), mkvecsmall(1)); case 0: retmkvec2(cgetg(1,t_COL), cgetg(1,t_VECSMALL)); case 1: retmkvec2(mkcol(f), mkvecsmall(1)); } r = FpX_quad_root(f, p, 1); if (!r) return mkvec2(mkcol(f), mkvecsmall(1)); v = varn(f); s = FpX_otherroot(f, r, p); if (signe(r)) r = subii(p, r); if (signe(s)) s = subii(p, s); sgn = cmpii(s, r); if (sgn < 0) swap(s,r); R = deg1pol_shallow(gen_1, r, v); if (!sgn) return mkvec2(mkcol(R), mkvecsmall(2)); S = deg1pol_shallow(gen_1, s, v); return mkvec2(mkcol2(R,S), mkvecsmall2(1,1)); } static GEN FpX_factor_deg2(GEN f, GEN p, long d, long flag) { switch(flag) { case 2: return FpX_is_irred_2(f, p, d); case 1: return FpX_degfact_2(f, p, d); default: return FpX_factor_2(f, p, d); } } static int F2x_quad_factortype(GEN x) { return x[2] == 7 ? -1: x[2] == 6 ? 1 :0; } static GEN F2x_is_irred_2(GEN f, long d) { return d == 1 || (d==2 && F2x_quad_factortype(f) == -1)? gen_1: NULL; } static GEN F2x_degfact_2(GEN f, long d) { if (!d) return trivial_fact(); if (d == 1) return mkvec2(mkvecsmall(1), mkvecsmall(1)); switch(F2x_quad_factortype(f)) { case 1: return mkvec2(mkvecsmall2(1,1), mkvecsmall2(1,1)); case -1:return mkvec2(mkvecsmall(2), mkvecsmall(1)); default: return mkvec2(mkvecsmall(1), mkvecsmall(2)); } } static GEN F2x_factor_2(GEN f, long d) { long v = f[1]; if (!d) return mkvec2(cgetg(1,t_COL), cgetg(1,t_VECSMALL)); if (labs(d) == 1) return mkvec2(mkcol(f), mkvecsmall(1)); switch(F2x_quad_factortype(f)) { case -1: return mkvec2(mkcol(f), mkvecsmall(1)); case 0: return mkvec2(mkcol(mkvecsmall2(v,2+F2x_coeff(f,0))), mkvecsmall(2)); default: return mkvec2(mkcol2(mkvecsmall2(v,2),mkvecsmall2(v,3)), mkvecsmall2(1,1)); } } static GEN F2x_factor_deg2(GEN f, long d, long flag) { switch(flag) { case 2: return F2x_is_irred_2(f, d); case 1: return F2x_degfact_2(f, d); default: return F2x_factor_2(f, d); } } /* xt = NULL or x^(p-1)/2 mod g */ static void split_squares(struct split_t *S, GEN g, ulong p, GEN xt) { ulong q = p >> 1; GEN a = Flx_mod_Xnm1(g, q, p); /* mod x^(p-1)/2 - 1 */ long d = degpol(a); if (d < 0) { ulong i; split_add_done(S, (GEN)1); for (i = 2; i <= q; i++) split_add_done(S, (GEN)Fl_sqr(i,p)); } else { if (a != g) { (void)Flx_valrem(a, &a); d = degpol(a); } if (d) { if (xt) xt = Flx_Fl_add(xt, p-1, p); else xt = Flx_Xnm1(g[1], q, p); a = Flx_gcd(a, xt, p); if (degpol(a)) split_add(S, Flx_normalize(a, p)); } } } static void split_nonsquares(struct split_t *S, GEN g, ulong p, GEN xt) { ulong q = p >> 1; GEN a = Flx_mod_Xn1(g, q, p); /* mod x^(p-1)/2 + 1 */ long d = degpol(a); if (d < 0) { ulong i, z = Fl_nonsquare(p); split_add_done(S, (GEN)z); for (i = 2; i <= q; i++) split_add_done(S, (GEN)Fl_mul(z, Fl_sqr(i,p), p)); } else { if (a != g) { (void)Flx_valrem(a, &a); d = degpol(a); } if (d) { if (xt) xt = Flx_Fl_add(xt, 1, p); else xt = Flx_Xn1(g[1], q, p); a = Flx_gcd(a, xt, p); if (degpol(a)) split_add(S, Flx_normalize(a, p)); } } } /* p > 2. f monic Flx, f(0) != 0. Add to split_t structs coprime factors * of g = \prod_{f(a) = 0} (X - a). Return 0 when f(x) = 0 for all x in Fp* */ static int split_Flx_cut_out_roots(struct split_t *S, GEN f, ulong p) { GEN a, g = Flx_mod_Xnm1(f, p-1, p); /* f mod x^(p-1) - 1 */ long d = degpol(g); if (d < 0) return 0; if (g != f) { (void)Flx_valrem(g, &g); d = degpol(g); } /*kill powers of x*/ if (!d) return 1; if ((p >> 4) <= (ulong)d) { /* small p; split directly using x^((p-1)/2) +/- 1 */ GEN xt = ((ulong)d < (p>>1))? Flx_rem(monomial_Flx(1, p>>1, g[1]), g, p) : NULL; split_squares(S, g, p, xt); split_nonsquares(S, g, p, xt); } else { /* large p; use x^(p-1) - 1 directly */ a = Flxq_powu(polx_Flx(f[1]), p-1, g,p); if (lg(a) < 3) pari_err_PRIME("rootmod",utoipos(p)); a = Flx_Fl_add(a, p-1, p); /* a = x^(p-1) - 1 mod g */ g = Flx_gcd(g,a, p); if (degpol(g)) split_add(S, Flx_normalize(g,p)); } return 1; } /* by splitting, assume p > 2 prime, deg(f) > 0, and f monic */ static GEN Flx_roots_i(GEN f, ulong p) { GEN pol, g; long v = Flx_valrem(f, &g); ulong q; struct split_t S; /* optimization: test for small degree first */ switch(degpol(g)) { case 1: { ulong r = p - g[2]; return v? mkvecsmall2(0, r): mkvecsmall(r); } case 2: { ulong r = Flx_quad_root(g, p, 1), s; if (r == p) return v? mkvecsmall(0): cgetg(1,t_VECSMALL); s = Flx_otherroot(g,r, p); if (r < s) return v? mkvecsmall3(0, r, s): mkvecsmall2(r, s); else if (r > s) return v? mkvecsmall3(0, s, r): mkvecsmall2(s, r); else return v? mkvecsmall2(0, s): mkvecsmall(s); } } q = p >> 1; split_init(&S, lg(f)-1); settyp(S.done, t_VECSMALL); if (v) split_add_done(&S, (GEN)0); if (! split_Flx_cut_out_roots(&S, g, p)) return all_roots_mod_p(p, lg(S.done) == 1); pol = polx_Flx(f[1]); for (pol[2]=1; ; pol[2]++) { long j, l = lg(S.todo); if (l == 1) { vecsmall_sort(S.done); return S.done; } if (pol[2] == 100 && !uisprime(p)) pari_err_PRIME("polrootsmod",utoipos(p)); for (j = 1; j < l; j++) { GEN b, c = gel(S.todo,j); ulong r, s; switch(degpol(c)) { case 1: split_moveto_done(&S, j, (GEN)(p - c[2])); j--; l--; break; case 2: r = Flx_quad_root(c, p, 0); if (r == p) pari_err_PRIME("polrootsmod",utoipos(p)); s = Flx_otherroot(c,r, p); split_done(&S, j, (GEN)r, (GEN)s); j--; l--; break; default: b = Flxq_powu(pol,q, c,p); /* pol^(p-1)/2 */ if (degpol(b) <= 0) continue; b = Flx_gcd(c,Flx_Fl_add(b,p-1,p), p); if (!degpol(b)) continue; b = Flx_normalize(b, p); c = Flx_div(c,b, p); split_todo(&S, j, b, c); } } } } GEN Flx_roots(GEN f, ulong p) { pari_sp av = avma; switch(lg(f)) { case 2: pari_err_ROOTS0("Flx_roots"); case 3: avma = av; return cgetg(1, t_VECSMALL); } if (p == 2) return Flx_root_mod_2(f); return gerepileuptoleaf(av, Flx_roots_i(Flx_normalize(f, p), p)); } /* assume x reduced mod p, monic. */ static int Flx_quad_factortype(GEN x, ulong p) { ulong b = x[3], c = x[2]; return krouu(Fl_disc_bc(b, c, p), p); } static GEN Flx_is_irred_2(GEN f, ulong p, long d) { if (!d) return NULL; if (d == 1) return gen_1; return Flx_quad_factortype(f, p) == -1? gen_1: NULL; } static GEN Flx_degfact_2(GEN f, ulong p, long d) { if (!d) return trivial_fact(); if (d == 1) return mkvec2(mkvecsmall(1), mkvecsmall(1)); switch(Flx_quad_factortype(f, p)) { case 1: return mkvec2(mkvecsmall2(1,1), mkvecsmall2(1,1)); case -1:return mkvec2(mkvecsmall(2), mkvecsmall(1)); default: return mkvec2(mkvecsmall(1), mkvecsmall(2)); } } /* p > 2 */ static GEN Flx_factor_2(GEN f, ulong p, long d) { ulong r, s; GEN R,S; long v = f[1]; if (!d) return mkvec2(cgetg(1,t_COL), cgetg(1,t_VECSMALL)); if (labs(d) == 1) return mkvec2(mkcol(f), mkvecsmall(1)); r = Flx_quad_root(f, p, 1); if (r==p) return mkvec2(mkcol(f), mkvecsmall(1)); s = Flx_otherroot(f, r, p); r = Fl_neg(r, p); s = Fl_neg(s, p); if (s < r) lswap(s,r); R = mkvecsmall3(v,r,1); if (s == r) return mkvec2(mkcol(R), mkvecsmall(2)); S = mkvecsmall3(v,s,1); return mkvec2(mkcol2(R,S), mkvecsmall2(1,1)); } static GEN Flx_factor_deg2(GEN f, ulong p, long d, long flag) { switch(flag) { case 2: return Flx_is_irred_2(f, p, d); case 1: return Flx_degfact_2(f, p, d); default: return Flx_factor_2(f, p, d); } } void F2xV_to_FlxV_inplace(GEN v) { long i; for(i=1;i=9) timer_printf(&T,"Berlekamp matrix"); Q = F2m_ker_sp(Q,0); if(DEBUGLEVEL>=9) timer_printf(&T,"kernel"); return gerepileupto(ltop,Q); } #define set_irred(i) { if ((i)>ir) swap(t[i],t[ir]); ir++;} static long F2x_split_Berlekamp(GEN *t) { GEN u = *t, a, b, vker; long lb, d, i, ir, L, la, sv = u[1], du = F2x_degree(u); if (du == 1) return 1; if (du == 2) { if (F2x_quad_factortype(u) == 1) /* 0 is a root: shouldn't occur */ { t[0] = mkvecsmall2(sv, 2); t[1] = mkvecsmall2(sv, 3); return 2; } return 1; } vker = F2x_Berlekamp_ker(u); lb = lgcols(vker); d = lg(vker)-1; ir = 0; /* t[i] irreducible for i < ir, still to be treated for i < L */ for (L=1; L 2 */ static GEN F2x_Berlekamp_i(GEN f, long flag) { long lfact, val, d = F2x_degree(f), j, k, lV; GEN y, E, t, V; val = F2x_valrem(f, &f); if (flag == 2 && val) return NULL; V = F2x_factor_squarefree(f); lV = lg(V); if (flag == 2 && lV > 2) return NULL; /* to hold factors and exponents */ t = cgetg(d+1, flag? t_VECSMALL: t_VEC); E = cgetg(d+1,t_VECSMALL); lfact = 1; if (val) { if (flag == 1) t[1] = 1; else gel(t,1) = polx_F2x(f[1]); E[1] = val; lfact++; } for (k=1; k 0) { long j; for(j = 1;;j++) { v = F2x_gcd(r, t); tv = F2x_div(t, v); if (F2x_degree(tv) > 0) gel(u, j*q) = tv; if (F2x_degree(v) <= 0) break; r = F2x_div(r, v); t = v; } if (F2x_degree(r) == 0) break; } f = F2x_sqrt(r); } for (i = n; i; i--) if (F2x_degree(gel(u,i))) break; setlg(u,i+1); return u; } static GEN F2x_ddf_simple(GEN T, GEN XP) { pari_sp av = avma, av2; GEN f, z, Tr, X; long j, n = F2x_degree(T), v = T[1], B = n/2; if (n == 0) return cgetg(1, t_VEC); if (n == 1) return mkvec(T); z = XP; Tr = T; X = polx_F2x(v); f = const_vec(n, pol1_F2x(v)); av2 = avma; for (j = 1; j <= B; j++) { GEN u = F2x_gcd(Tr, F2x_add(z, X)); if (F2x_degree(u)) { gel(f, j) = u; Tr = F2x_div(Tr, u); av2 = avma; } else z = gerepileuptoleaf(av2, z); if (!F2x_degree(Tr)) break; z = F2xq_sqr(z, Tr); } if (F2x_degree(Tr)) gel(f, F2x_degree(Tr)) = Tr; return gerepilecopy(av, f); } GEN F2x_ddf(GEN T) { GEN XP; T = F2x_get_red(T); XP = F2x_Frobenius(T); return F2x_ddf_to_ddf2(F2x_ddf_simple(T, XP)); } static GEN F2xq_frobtrace(GEN a, long d, GEN T) { pari_sp av = avma; long i; GEN x = a; for(i=1; i 0 && df < n) break; avma = btop; } ff = F2x_div(Tp, f); F2x_edf_simple(f, XP, d, V, idx); F2x_edf_simple(ff, XP, d, V, idx+F2x_degree(f)/d); } static GEN F2x_factor_Shoup(GEN T) { long i, n, s = 0; GEN XP, D, V; pari_timer ti; n = F2x_degree(T); if (DEBUGLEVEL>=6) timer_start(&ti); XP = F2x_Frobenius(T); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_Frobenius"); D = F2x_ddf_simple(T, XP); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_ddf_simple"); for (i = 1; i <= n; i++) s += F2x_degree(gel(D,i))/i; V = cgetg(s+1, t_COL); for (i = 1, s = 1; i <= n; i++) { GEN Di = gel(D,i); long ni = F2x_degree(Di), ri = ni/i; if (ni == 0) continue; if (ni == i) { gel(V, s++) = Di; continue; } F2x_edf_simple(Di, XP, i, V, s); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_edf(%ld)",i); s += ri; } return V; } static GEN F2x_factor_Cantor(GEN T) { GEN E, F, V = F2x_factor_squarefree(T); long i, j, l = lg(V); E = cgetg(l, t_VEC); F = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (F2x_degree(gel(V,i))) { GEN Fj = F2x_factor_Shoup(gel(V,i)); gel(F, j) = Fj; gel(E, j) = const_vecsmall(lg(Fj)-1, i); j++; } return sort_factor_pol(FE_concat(F,E,j), cmpGuGu); } #if 0 static GEN F2x_simplefact_Shoup(GEN T) { long i, n, s = 0, j = 1, k; GEN XP, D, V; pari_timer ti; n = F2x_degree(T); if (DEBUGLEVEL>=6) timer_start(&ti); XP = F2x_Frobenius(T); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_Frobenius"); D = F2x_ddf_simple(T, XP); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_ddf_simple"); for (i = 1; i <= n; i++) s += F2x_degree(gel(D,i))/i; V = cgetg(s+1, t_VECSMALL); for (i = 1; i <= n; i++) { long ni = F2x_degree(gel(D,i)), ri = ni/i; if (ni == 0) continue; for (k = 1; k <= ri; k++) V[j++] = i; } return V; } static GEN F2x_simplefact_Cantor(GEN T) { GEN E, F, V = F2x_factor_squarefree(T); long i, j, l = lg(V); F = cgetg(l, t_VEC); E = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (F2x_degree(gel(V,i))) { GEN Fj = F2x_simplefact_Shoup(gel(V,i)); gel(F, j) = Fj; gel(E, j) = const_vecsmall(lg(Fj)-1, i); j++; } return sort_factor(FE_concat(F,E,j), (void*)&cmpGuGu, cmp_nodata); } static int F2x_isirred_Cantor(GEN T) { pari_sp av = avma; pari_timer ti; long n, d; GEN dT = F2x_deriv(T); GEN XP, D; if (F2x_degree(F2x_gcd(T, dT)) != 0) { avma = av; return 0; } n = F2x_degree(T); if (DEBUGLEVEL>=6) timer_start(&ti); XP = F2x_Frobenius(T); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_Frobenius"); D = F2x_ddf_simple(T, XP); if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_ddf_simple"); d = F2x_degree(gel(D, n)); avma = av; return d==n; } #endif /* driver for Cantor factorization, assume deg f > 2; not competitive for * flag != 0, or as deg f increases */ static GEN F2x_Cantor_i(GEN f, long flag) { switch(flag) { default: return F2x_factor_Cantor(f); #if 0 case 1: return F2x_simplefact_Cantor(f); case 2: return F2x_isirred_Cantor(f)? gen_1: NULL; #endif } } static GEN F2x_factor_i(GEN f, long flag) { long d = F2x_degree(f); if (d <= 2) return F2x_factor_deg2(f,d,flag); return (flag == 0 && d <= 20)? F2x_Cantor_i(f, flag) : F2x_Berlekamp_i(f, flag); } GEN F2x_degfact(GEN f) { pari_sp av = avma; GEN z = F2x_factor_i(f, 1); return gerepilecopy(av, z); } int F2x_is_irred(GEN f) { return !!F2x_factor_i(f, 2); } /* Adapted from Shoup NTL */ GEN Flx_factor_squarefree(GEN f, ulong p) { long i, q, n = degpol(f); GEN u = const_vec(n+1, pol1_Flx(f[1])); for(q = 1;;q *= p) { GEN t, v, tv, r = Flx_gcd(f, Flx_deriv(f, p), p); if (degpol(r) == 0) { gel(u, q) = f; break; } t = Flx_div(f, r, p); if (degpol(t) > 0) { long j; for(j = 1;;j++) { v = Flx_gcd(r, t, p); tv = Flx_div(t, v, p); if (degpol(tv) > 0) gel(u, j*q) = Flx_normalize(tv, p); if (degpol(v) <= 0) break; r = Flx_div(r, v, p); t = v; } if (degpol(r) == 0) break; } f = Flx_normalize(Flx_deflate(r, p), p); } for (i = n; i; i--) if (degpol(gel(u,i))) break; setlg(u,i+1); return u; } long Flx_ispower(GEN f, ulong k, ulong p, GEN *pt_r) { pari_sp av = avma; ulong lc; GEN F; long i, n = degpol(f), v = f[1], l; if (n % k) return 0; lc = Fl_sqrtn(Flx_lead(f), k, p, NULL); if (lc == ULONG_MAX) { av = avma; return 0; } F = Flx_factor_squarefree(f, p); l = lg(F)-1; for (i = 1; i <= l; i++) if (i%k && degpol(gel(F,i))) { avma = av; return 0; } if (pt_r) { GEN r = Fl_to_Flx(lc, v), s = pol1_Flx(v); for(i = l; i >= 1; i--) { if (i%k) continue; s = Flx_mul(s, gel(F,i), p); r = Flx_mul(r, s, p); } *pt_r = gerepileuptoleaf(av, r); } else av = avma; return 1; } /* See */ static GEN Flx_ddf_Shoup(GEN T, GEN XP, ulong p) { pari_sp av = avma; GEN b, g, h, F, f, Tr, xq; long i, j, n, v, bo, ro; long B, l, m; pari_timer ti; n = get_Flx_degree(T); v = get_Flx_var(T); if (n == 0) return cgetg(1, t_VEC); if (n == 1) return mkvec(get_Flx_mod(T)); B = n/2; l = usqrt(B); m = (B+l-1)/l; T = Flx_get_red(T, p); b = cgetg(l+2, t_VEC); gel(b, 1) = polx_Flx(v); gel(b, 2) = XP; bo = brent_kung_optpow(n, l-1, 1); ro = l<=1 ? 0:(bo-1)/(l-1) + ((n-1)/bo); if (DEBUGLEVEL>=7) timer_start(&ti); if (expu(p) <= ro) for (i = 3; i <= l+1; i++) gel(b, i) = Flxq_powu(gel(b, i-1), p, T, p); else { xq = Flxq_powers(gel(b, 2), bo, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: xq baby"); for (i = 3; i <= l+1; i++) gel(b, i) = Flx_FlxqV_eval(gel(b, i-1), xq, T, p); } if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: baby"); xq = Flxq_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: xq giant"); g = cgetg(m+1, t_VEC); gel(g, 1) = gel(xq, 2); for(i = 2; i <= m; i++) gel(g, i) = Flx_FlxqV_eval(gel(g, i-1), xq, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: giant"); h = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { pari_sp av = avma; GEN gj = gel(g, j); GEN e = Flx_sub(gj, gel(b, 1), p); for (i = 2; i <= l; i++) e = Flxq_mul(e, Flx_sub(gj, gel(b, i), p), T, p); gel(h, j) = gerepileupto(av, e); } if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: diff"); Tr = get_Flx_mod(T); F = cgetg(m+1, t_VEC); for (j = 1; j <= m; j++) { GEN u = Flx_gcd(Tr, gel(h, j), p); if (degpol(u)) { u = Flx_normalize(u, p); Tr = Flx_div(Tr, u, p); } gel(F, j) = u; } if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: F"); f = const_vec(n, pol1_Flx(v)); for (j = 1; j <= m; j++) { GEN e = gel(F, j); for (i=l-1; i >= 0; i--) { GEN u = Flx_gcd(e, Flx_sub(gel(g, j), gel(b, i+1), p), p); if (degpol(u)) { gel(f, l*j-i) = u; e = Flx_div(e, u, p); } if (!degpol(e)) break; } } if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: f"); if (degpol(Tr)) gel(f, degpol(Tr)) = Tr; return gerepilecopy(av, f); } static void Flx_edf_simple(GEN Tp, GEN XP, long d, ulong p, GEN V, long idx) { long n = degpol(Tp), r = n/d; GEN T, f, ff; ulong p2; if (r==1) { gel(V, idx) = Tp; return; } p2 = p>>1; T = Flx_get_red(Tp, p); XP = Flx_rem(XP, T, p); while (1) { pari_sp btop = avma; long i; GEN g = random_Flx(n, Tp[1], p); GEN t = gel(Flxq_auttrace(mkvec2(XP, g), d, T, p), 2); if (lgpol(t) == 0) continue; for(i=1; i<=10; i++) { pari_sp btop2 = avma; GEN R = Flxq_powu(Flx_Fl_add(t, random_Fl(p), p), p2, T, p); f = Flx_gcd(Flx_Fl_add(R, p-1, p), Tp, p); if (degpol(f) > 0 && degpol(f) < n) break; avma = btop2; } if (degpol(f) > 0 && degpol(f) < n) break; avma = btop; } f = Flx_normalize(f, p); ff = Flx_div(Tp, f ,p); Flx_edf_simple(f, XP, d, p, V, idx); Flx_edf_simple(ff, XP, d, p, V, idx+degpol(f)/d); } static void Flx_edf(GEN Tp, GEN XP, long d, ulong p, GEN V, long idx); static void Flx_edf_rec(GEN T, GEN XP, GEN hp, GEN t, long d, ulong p, GEN V, long idx) { pari_sp av; GEN Tp = get_Flx_mod(T); long n = degpol(hp), vT = Tp[1]; GEN u1, u2, f1, f2; ulong p2 = p>>1; GEN R, h; h = Flx_get_red(hp, p); t = Flx_rem(t, T, p); av = avma; do { avma = av; R = Flxq_powu(mkvecsmall3(vT, random_Fl(p), 1), p2, h, p); u1 = Flx_gcd(Flx_Fl_add(R, p-1, p), hp, p); } while (degpol(u1)==0 || degpol(u1)==n); f1 = Flx_gcd(Flx_Flxq_eval(u1, t, T, p), Tp, p); f1 = Flx_normalize(f1, p); u2 = Flx_div(hp, u1, p); f2 = Flx_div(Tp, f1, p); if (degpol(u1)==1) { if (degpol(f1)==d) gel(V, idx) = f1; else Flx_edf(f1, XP, d, p, V, idx); } else Flx_edf_rec(Flx_get_red(f1, p), XP, u1, t, d, p, V, idx); idx += degpol(f1)/d; if (degpol(u2)==1) { if (degpol(f2)==d) gel(V, idx) = f2; else Flx_edf(f2, XP, d, p, V, idx); } else Flx_edf_rec(Flx_get_red(f2, p), XP, u2, t, d, p, V, idx); } static void Flx_edf(GEN Tp, GEN XP, long d, ulong p, GEN V, long idx) { long n = degpol(Tp), r = n/d, vT = Tp[1]; GEN T, h, t; pari_timer ti; if (r==1) { gel(V, idx) = Tp; return; } T = Flx_get_red(Tp, p); XP = Flx_rem(XP, T, p); if (DEBUGLEVEL>=7) timer_start(&ti); do { GEN g = random_Flx(n, vT, p); t = gel(Flxq_auttrace(mkvec2(XP, g), d, T, p), 2); if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_edf: Flxq_auttrace"); h = Flxq_minpoly(t, T, p); if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_edf: Flxq_minpoly"); } while (degpol(h) <= 1); Flx_edf_rec(T, XP, h, t, d, p, V, idx); } static GEN Flx_factor_Shoup(GEN T, ulong p) { long i, n, s = 0; GEN XP, D, V; long e = expu(p); pari_timer ti; n = get_Flx_degree(T); T = Flx_get_red(T, p); if (DEBUGLEVEL>=6) timer_start(&ti); XP = Flx_Frobenius(T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_Frobenius"); D = Flx_ddf_Shoup(T, XP, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_ddf_Shoup"); s = ddf_to_nbfact(D); V = cgetg(s+1, t_COL); for (i = 1, s = 1; i <= n; i++) { GEN Di = gel(D,i); long ni = degpol(Di), ri = ni/i; if (ni == 0) continue; Di = Flx_normalize(Di, p); if (ni == i) { gel(V, s++) = Di; continue; } if (ri <= e*expu(e)) Flx_edf(Di, XP, i, p, V, s); else Flx_edf_simple(Di, XP, i, p, V, s); if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_edf(%ld)",i); s += ri; } return V; } static GEN Flx_factor_Cantor(GEN T, ulong p) { GEN E, F, V = Flx_factor_squarefree(get_Flx_mod(T), p); long i, j, l = lg(V); F = cgetg(l, t_VEC); E = cgetg(l, t_VEC); for (i=1, j=1; i < l; i++) if (degpol(gel(V,i))) { GEN Fj = Flx_factor_Shoup(gel(V,i), p); gel(F, j) = Fj; gel(E, j) = const_vecsmall(lg(Fj)-1, i); j++; } return sort_factor_pol(FE_concat(F,E,j), cmpGuGu); } GEN Flx_ddf(GEN T, ulong p) { GEN XP; T = Flx_get_red(T, p); XP = Flx_Frobenius(T, p); return ddf_to_ddf2(Flx_ddf_Shoup(T, XP, p)); } static GEN Flx_simplefact_Cantor(GEN T, ulong p) { GEN XP, V; long i, l; T = Flx_get_red(T, p); XP = Flx_Frobenius(T, p); V = Flx_factor_squarefree(get_Flx_mod(T), p); l = lg(V); for (i=1; i < l; i++) gel(V,i) = Flx_ddf_Shoup(gel(V,i), XP, p); return vddf_to_simplefact(V, get_Flx_degree(T)); } static int Flx_isirred_Cantor(GEN Tp, ulong p) { pari_sp av = avma; pari_timer ti; long n, d; GEN T = get_Flx_mod(Tp); GEN dT = Flx_deriv(T, p); GEN XP, D; if (degpol(Flx_gcd(T, dT, p)) != 0) { avma = av; return 0; } n = get_Flx_degree(T); T = Flx_get_red(Tp, p); if (DEBUGLEVEL>=6) timer_start(&ti); XP = Flx_Frobenius(T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_Frobenius"); D = Flx_ddf_Shoup(T, XP, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_ddf_Shoup"); d = degpol(gel(D, n)); avma = av; return d==n; } /* f monic */ static GEN Flx_factor_i(GEN f, ulong pp, long flag) { long d; if (pp==2) { /*We need to handle 2 specially */ GEN F = F2x_factor_i(Flx_to_F2x(f),flag); if (flag==0) F2xV_to_FlxV_inplace(gel(F,1)); return F; } d = degpol(f); if (d <= 2) return Flx_factor_deg2(f,pp,d,flag); switch(flag) { default: return Flx_factor_Cantor(f, pp); case 1: return Flx_simplefact_Cantor(f, pp); case 2: return Flx_isirred_Cantor(f, pp)? gen_1: NULL; } } GEN Flx_degfact(GEN f, ulong p) { pari_sp av = avma; GEN z = Flx_factor_i(Flx_normalize(f,p),p,1); return gerepilecopy(av, z); } /* T must be squarefree mod p*/ GEN Flx_nbfact_by_degree(GEN T, long *nb, ulong p) { GEN XP, D; pari_timer ti; long i, s, n = get_Flx_degree(T); GEN V = const_vecsmall(n, 0); pari_sp av = avma; T = Flx_get_red(T, p); if (DEBUGLEVEL>=6) timer_start(&ti); XP = Flx_Frobenius(T, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_Frobenius"); D = Flx_ddf_Shoup(T, XP, p); if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_ddf_Shoup"); for (i = 1, s = 0; i <= n; i++) { V[i] = degpol(gel(D,i))/i; s += V[i]; } *nb = s; avma = av; return V; } long Flx_nbfact_Frobenius(GEN T, GEN XP, ulong p) { pari_sp av = avma; long s = ddf_to_nbfact(Flx_ddf_Shoup(T, XP, p)); avma = av; return s; } /* T must be squarefree mod p*/ long Flx_nbfact(GEN T, ulong p) { pari_sp av = avma; GEN XP = Flx_Frobenius(T, p); long n = Flx_nbfact_Frobenius(T, XP, p); avma = av; return n; } int Flx_is_irred(GEN f, ulong p) { pari_sp av = avma; int z = !!Flx_factor_i(Flx_normalize(f,p),p,2); avma = av; return z; } /* Use this function when you think f is reducible, and that there are lots of * factors. If you believe f has few factors, use FpX_nbfact(f,p)==1 instead */ int FpX_is_irred(GEN f, GEN p) { pari_sp av = avma; int z; switch(ZX_factmod_init(&f,p)) { case 0: z = !!F2x_factor_i(f,2); break; case 1: z = !!Flx_factor_i(f,p[2],2); break; default: z = !!FpX_factor_i(f,p,2); break; } avma = av; return z; } GEN FpX_degfact(GEN f, GEN p) { pari_sp av = avma; GEN F; switch(ZX_factmod_init(&f,p)) { case 0: F = F2x_factor_i(f,1); break; case 1: F = Flx_factor_i(f,p[2],1); break; default: F = FpX_factor_i(f,p,1); break; } return gerepilecopy(av, F); } #if 0 /* set x <-- x + c*y mod p */ /* x is not required to be normalized.*/ static void Flx_addmul_inplace(GEN gx, GEN gy, ulong c, ulong p) { long i, lx, ly; ulong *x=(ulong *)gx; ulong *y=(ulong *)gy; if (!c) return; lx = lg(gx); ly = lg(gy); if (lx 0; return v_p(Nx) */ static long idealHNF_norm_pval(GEN x, GEN p, long Zval) { long i, v = Zval, l = lg(x); for (i = 2; i < l; i++) v += Z_pval(gcoeff(x,i,i), p); return v; } /* x integral in HNF, f0 = partial factorization of a multiple of * x[1,1] = x\cap Z */ GEN idealHNF_Z_factor_i(GEN x, GEN f0, GEN *pvN, GEN *pvZ) { GEN P, E, vN, vZ, xZ = gcoeff(x,1,1), f = f0? f0: Z_factor(xZ); long i, l; P = gel(f,1); l = lg(P); E = gel(f,2); *pvN = vN = cgetg(l, t_VECSMALL); *pvZ = vZ = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) { GEN p = gel(P,i); vZ[i] = f0? Z_pval(xZ, p): itou(gel(E,i)); vN[i] = idealHNF_norm_pval(x,p, vZ[i]); } return P; } /* return P, primes dividing Nx and xZ = x\cap Z, set v_p(Nx), v_p(xZ); * x integral in HNF */ GEN idealHNF_Z_factor(GEN x, GEN *pvN, GEN *pvZ) { return idealHNF_Z_factor_i(x, NULL, pvN, pvZ); } /* v_P(A)*f(P) <= Nval [e.g. Nval = v_p(Norm A)], Zval = v_p(A \cap Z). * Return v_P(A) */ static long idealHNF_val(GEN A, GEN P, long Nval, long Zval) { long f = pr_get_f(P), vmax, v, e, i, j, k, l; GEN mul, B, a, y, r, p, pk, cx, vals; pari_sp av; if (Nval < f) return 0; p = pr_get_p(P); e = pr_get_e(P); /* v_P(A) <= max [ e * v_p(A \cap Z), floor[v_p(Nix) / f ] */ vmax = minss(Zval * e, Nval / f); mul = pr_get_tau(P); l = lg(mul); B = cgetg(l,t_MAT); /* B[1] not needed: v_pr(A[1]) = v_pr(A \cap Z) is known already */ gel(B,1) = gen_0; /* dummy */ for (j = 2; j < l; j++) { GEN x = gel(A,j); gel(B,j) = y = cgetg(l, t_COL); for (i = 1; i < l; i++) { /* compute a = (x.t0)_i, A in HNF ==> x[j+1..l-1] = 0 */ a = mulii(gel(x,1), gcoeff(mul,i,1)); for (k = 2; k <= j; k++) a = addii(a, mulii(gel(x,k), gcoeff(mul,i,k))); /* p | a ? */ gel(y,i) = dvmdii(a,p,&r); if (signe(r)) return 0; } } vals = cgetg(l, t_VECSMALL); /* vals[1] not needed */ for (j = 2; j < l; j++) { gel(B,j) = Q_primitive_part(gel(B,j), &cx); vals[j] = cx? 1 + e * Q_pval(cx, p): 1; } pk = powiu(p, ceildivuu(vmax, e)); av = avma; y = cgetg(l,t_COL); /* can compute mod p^ceil((vmax-v)/e) */ for (v = 1; v < vmax; v++) { /* we know v_pr(Bj) >= v for all j */ if (e == 1 || (vmax - v) % e == 0) pk = diviiexact(pk, p); for (j = 2; j < l; j++) { GEN x = gel(B,j); if (v < vals[j]) continue; for (i = 1; i < l; i++) { pari_sp av2 = avma; a = mulii(gel(x,1), gcoeff(mul,i,1)); for (k = 2; k < l; k++) a = addii(a, mulii(gel(x,k), gcoeff(mul,i,k))); /* a = (x.t_0)_i; p | a ? */ a = dvmdii(a,p,&r); if (signe(r)) return v; if (lgefint(a) > lgefint(pk)) a = remii(a, pk); gel(y,i) = gerepileuptoint(av2, a); } gel(B,j) = y; y = x; if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"idealval"); gerepileall(av,3, &y,&B,&pk); } } } return v; } /* true nf, x != 0 integral ideal in HNF, cx t_INT or NULL, * FA integer factorization matrix or NULL. Return partial factorization of * cx * x above primes in FA (complete factorization if !FA)*/ static GEN idealHNF_factor_i(GEN nf, GEN x, GEN cx, GEN FA) { const long N = lg(x)-1; long i, j, k, l, v; GEN vN, vZ, vP, vE, vp = idealHNF_Z_factor_i(x, FA, &vN,&vZ); l = lg(vp); i = cx? expi(cx)+1: 1; vP = cgetg((l+i-2)*N+1, t_COL); vE = cgetg((l+i-2)*N+1, t_COL); for (i = k = 1; i < l; i++) { GEN L, p = gel(vp,i); long Nval = vN[i], Zval = vZ[i], vc = cx? Z_pvalrem(cx,p,&cx): 0; if (vc) { L = idealprimedec(nf,p); if (is_pm1(cx)) cx = NULL; } else L = idealprimedec_limit_f(nf,p,Nval); for (j = 1; Nval && j < lg(L); j++) /* !Nval => only cx contributes */ { GEN P = gel(L,j); pari_sp av = avma; v = idealHNF_val(x, P, Nval, Zval); avma = av; Nval -= v*pr_get_f(P); v += vc * pr_get_e(P); if (!v) continue; gel(vP,k) = P; gel(vE,k) = utoipos(v); k++; } if (vc) for (; j 1 && abscmpiu(gel(P,l-1), lim) >= 0) { setlg(P,l-1); setlg(E,l-1); } } x = Q_primitive_part(x, &cx); return idealHNF_factor_i(nf, x, cx, F); } /* c * vector(#L,i,L[i].e), assume results fit in ulong */ static GEN prV_e_muls(GEN L, long c) { long j, l = lg(L); GEN z = cgetg(l, t_COL); for (j = 1; j < l; j++) gel(z,j) = stoi(c * pr_get_e(gel(L,j))); return z; } /* true nf, y in Q */ static GEN Q_nffactor(GEN nf, GEN y, ulong lim) { GEN f, P, E; long l, i; if (typ(y) == t_INT) { if (!signe(y)) pari_err_DOMAIN("idealfactor", "ideal", "=",gen_0,y); if (is_pm1(y)) return trivial_fact(); } y = Q_abs_shallow(y); if (!lim) f = Q_factor(y); else { f = Q_factor_limit(y, lim); P = gel(f,1); l = lg(P); E = gel(f,2); for (i = l-1; i > 0; i--) { if (abscmpiu(gel(P,i), lim) < 0) break; setlg(P,i); setlg(E,i); } } P = gel(f,1); l = lg(P); if (l == 1) return f; E = gel(f,2); for (i = 1; i < l; i++) { gel(P,i) = idealprimedec(nf, gel(P,i)); gel(E,i) = prV_e_muls(gel(P,i), itos(gel(E,i))); } settyp(P,t_VEC); P = shallowconcat1(P); settyp(E,t_VEC); E = shallowconcat1(E); gel(f,1) = P; settyp(P, t_COL); gel(f,2) = E; return f; } GEN idealfactor_limit(GEN nf, GEN x, ulong lim) { pari_sp av = avma; GEN fa, y; long tx = idealtyp(&x,&y); nf = checknf(nf); if (tx == id_PRIME) { if (lim && abscmpiu(pr_get_p(x), lim) >= 0) return trivial_fact(); retmkmat2(mkcolcopy(x), mkcol(gen_1)); } if (tx == id_PRINCIPAL) { y = nf_to_scalar_or_basis(nf, x); if (typ(y) != t_COL) return gerepilecopy(av, Q_nffactor(nf, y, lim)); } y = idealnumden(nf, x); fa = idealHNF_factor(nf, gel(y,1), lim); if (!isint1(gel(y,2))) fa = famat_div_shallow(fa, idealHNF_factor(nf, gel(y,2), lim)); fa = gerepilecopy(av, fa); return sort_factor(fa, (void*)&cmp_prime_ideal, &cmp_nodata); } GEN idealfactor(GEN nf, GEN x) { return idealfactor_limit(nf, x, 0); } GEN gpidealfactor(GEN nf, GEN x, GEN lim) { ulong L = 0; if (lim) { if (typ(lim) != t_INT || signe(lim) < 0) pari_err_FLAG("idealfactor"); L = itou(lim); } return idealfactor_limit(nf, x, L); } static GEN ramified_root(GEN nf, GEN R, GEN A, long n) { GEN v, P = gel(idealfactor(nf, R), 1); long i, l = lg(P); v = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) { long w = idealval(nf, A, gel(P,i)); if (w % n) return NULL; v[i] = w / n; } return idealfactorback(nf, P, v, 0); } static int ramified_root_simple(GEN nf, long n, GEN P, GEN v) { long i, l = lg(v); for (i = 1; i < l; i++) if (v[i]) { GEN vpr = idealprimedec(nf, gel(P,i)); long lpr = lg(vpr), j; for (j = 1; j < lpr; j++) { long e = pr_get_e(gel(vpr,j)); if ((e * v[i]) % n) return 0; } } return 1; } /* true nf; A is assumed to be the n-th power of an integral ideal, * return its n-th root; n > 1 */ static long idealsqrtn_int(GEN nf, GEN A, long n, GEN *pB) { GEN C, root; long i, l; if (typ(A) == t_INT) /* > 0 */ { GEN P = nf_get_ramified_primes(nf), v, q; l = lg(P); v = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) v[i] = Z_pvalrem(A, gel(P,i), &A); C = gen_1; if (!isint1(A) && !Z_ispowerall(A, n, pB? &C: NULL)) return 0; if (!pB) return ramified_root_simple(nf, n, P, v); q = factorback2(P, v); root = ramified_root(nf, q, q, n); if (!root) return 0; if (!equali1(C)) root = isint1(root)? C: ZM_Z_mul(root, C); *pB = root; return 1; } /* compute valuations at ramified primes */ root = ramified_root(nf, idealadd(nf, nf_get_diff(nf), A), A, n); /* remove ramified primes */ if (isint1(root)) root = matid(nf_get_degree(nf)); else A = idealdivexact(nf, A, idealpows(nf,root,n)); A = Q_primitive_part(A, &C); if (C) { if (!Z_ispowerall(C,n,&C)) return 0; if (pB) root = ZM_Z_mul(root, C); } /* compute final n-th root, at most degree(nf)-1 iterations */ for (i = 0;; i++) { GEN J, b, a = gcoeff(A,1,1); /* A \cap Z */ if (is_pm1(a)) break; if (!Z_ispowerall(a,n,&b)) return 0; J = idealadd(nf, b, A); A = idealdivexact(nf, idealpows(nf,J,n), A); if (pB) root = odd(i)? idealdivexact(nf, root, J): idealmul(nf, root, J); } if (pB) *pB = root; return 1; } /* A is assumed to be the n-th power of an ideal in nf returns its n-th root. */ long idealispower(GEN nf, GEN A, long n, GEN *pB) { pari_sp av = avma; GEN v, N, D; nf = checknf(nf); if (n <= 0) pari_err_DOMAIN("idealispower", "n", "<=", gen_0, stoi(n)); if (n == 1) { if (pB) *pB = idealhnf(nf,A); return 1; } v = idealnumden(nf,A); if (gequal0(gel(v,1))) { avma = av; if (pB) *pB = cgetg(1,t_MAT); return 1; } if (!idealsqrtn_int(nf, gel(v,1), n, pB? &N: NULL)) return 0; if (!idealsqrtn_int(nf, gel(v,2), n, pB? &D: NULL)) return 0; if (pB) *pB = gerepileupto(av, idealdiv(nf,N,D)); else avma = av; return 1; } /* x t_INT or integral non-0 ideal in HNF */ static GEN idealredmodpower_i(GEN nf, GEN x, ulong k, ulong B) { GEN cx, y, U, N, F, Q; long nF; if (typ(x) == t_INT) { if (!signe(x) || is_pm1(x)) return gen_1; F = Z_factor_limit(x, B); gel(F,2) = gdiventgs(gel(F,2), k); return ginv(factorback(F)); } N = gcoeff(x,1,1); if (is_pm1(N)) return gen_1; F = Z_factor_limit(N, B); nF=lg(gel(F,1))-1; if (BPSW_psp(gcoeff(F,nF,1))) U = NULL; else { GEN M = powii(gcoeff(F,nF,1), gcoeff(F,nF,2)); y = hnfmodid(x, M); /* coprime part to B! */ if (!idealispower(nf, y, k, &U)) U = NULL; x = hnfmodid(x, diviiexact(N, M)); setlg(gel(F,1), nF); /* remove last entry (unfactored part) */ setlg(gel(F,2), nF); } /* x = B-smooth part of initial x */ x = Q_primitive_part(x, &cx); F = idealHNF_factor_i(nf, x, cx, F); gel(F,2) = gdiventgs(gel(F,2), k); Q = idealfactorback(nf, gel(F,1), gel(F,2), 0); if (U) Q = idealmul(nf,Q,U); if (typ(Q) == t_INT) return Q; y = idealred_elt(nf, idealHNF_inv_Z(nf, Q)); return gdiv(y, gcoeff(Q,1,1)); } GEN idealredmodpower(GEN nf, GEN x, ulong n, ulong B) { pari_sp av = avma; GEN a, b; nf = checknf(nf); if (!n) pari_err_DOMAIN("idealredmodpower","n", "=", gen_0, gen_0); x = idealnumden(nf, x); a = gel(x,1); if (isintzero(a)) { avma = av; return gen_1; } a = idealredmodpower_i(nf, gel(x,1), n, B); b = idealredmodpower_i(nf, gel(x,2), n, B); if (!isint1(b)) a = nf_to_scalar_or_basis(nf, nfdiv(nf, a, b)); return gerepilecopy(av, a); } /* P prime ideal in idealprimedec format. Return valuation(A) at P */ long idealval(GEN nf, GEN A, GEN P) { pari_sp av = avma; GEN a, p, cA; long vcA, v, Zval, tx = idealtyp(&A,&a); if (tx == id_PRINCIPAL) return nfval(nf,A,P); checkprid(P); if (tx == id_PRIME) return pr_equal(P, A)? 1: 0; /* id_MAT */ nf = checknf(nf); A = Q_primitive_part(A, &cA); p = pr_get_p(P); vcA = cA? Q_pval(cA,p): 0; if (pr_is_inert(P)) { avma = av; return vcA; } Zval = Z_pval(gcoeff(A,1,1), p); if (!Zval) v = 0; else { long Nval = idealHNF_norm_pval(A, p, Zval); v = idealHNF_val(A, P, Nval, Zval); } avma = av; return vcA? v + vcA*pr_get_e(P): v; } GEN gpidealval(GEN nf, GEN ix, GEN P) { long v = idealval(nf,ix,P); return v == LONG_MAX? mkoo(): stoi(v); } /* gcd and generalized Bezout */ GEN idealadd(GEN nf, GEN x, GEN y) { pari_sp av = avma; long tx, ty; GEN z, a, dx, dy, dz; tx = idealtyp(&x,&z); ty = idealtyp(&y,&z); nf = checknf(nf); if (tx != id_MAT) x = idealhnf_shallow(nf,x); if (ty != id_MAT) y = idealhnf_shallow(nf,y); if (lg(x) == 1) return gerepilecopy(av,y); if (lg(y) == 1) return gerepilecopy(av,x); /* check for 0 ideal */ dx = Q_denom(x); dy = Q_denom(y); dz = lcmii(dx,dy); if (is_pm1(dz)) dz = NULL; else { x = Q_muli_to_int(x, dz); y = Q_muli_to_int(y, dz); } a = gcdii(gcoeff(x,1,1), gcoeff(y,1,1)); if (is_pm1(a)) { long N = lg(x)-1; if (!dz) { avma = av; return matid(N); } return gerepileupto(av, scalarmat(ginv(dz), N)); } z = ZM_hnfmodid(shallowconcat(x,y), a); if (dz) z = RgM_Rg_div(z,dz); return gerepileupto(av,z); } static GEN trivial_merge(GEN x) { return (lg(x) == 1 || !is_pm1(gcoeff(x,1,1)))? NULL: gen_1; } /* true nf */ static GEN _idealaddtoone(GEN nf, GEN x, GEN y, long red) { GEN a; long tx = idealtyp(&x, &a/*junk*/); long ty = idealtyp(&y, &a/*junk*/); long ea; if (tx != id_MAT) x = idealhnf_shallow(nf, x); if (ty != id_MAT) y = idealhnf_shallow(nf, y); if (lg(x) == 1) a = trivial_merge(y); else if (lg(y) == 1) a = trivial_merge(x); else a = hnfmerge_get_1(x, y); if (!a) pari_err_COPRIME("idealaddtoone",x,y); if (red && (ea = gexpo(a)) > 10) { GEN b = (typ(a) == t_COL)? a: scalarcol_shallow(a, nf_get_degree(nf)); b = ZC_reducemodlll(b, idealHNF_mul(nf,x,y)); if (gexpo(b) < ea) a = b; } return a; } /* true nf */ GEN idealaddtoone_i(GEN nf, GEN x, GEN y) { return _idealaddtoone(nf, x, y, 1); } /* true nf */ GEN idealaddtoone_raw(GEN nf, GEN x, GEN y) { return _idealaddtoone(nf, x, y, 0); } GEN idealaddtoone(GEN nf, GEN x, GEN y) { GEN z = cgetg(3,t_VEC), a; pari_sp av = avma; nf = checknf(nf); a = gerepileupto(av, idealaddtoone_i(nf,x,y)); gel(z,1) = a; gel(z,2) = typ(a) == t_COL? Z_ZC_sub(gen_1,a): subui(1,a); return z; } /* assume elements of list are integral ideals */ GEN idealaddmultoone(GEN nf, GEN list) { pari_sp av = avma; long N, i, l, nz, tx = typ(list); GEN H, U, perm, L; nf = checknf(nf); N = nf_get_degree(nf); if (!is_vec_t(tx)) pari_err_TYPE("idealaddmultoone",list); l = lg(list); L = cgetg(l, t_VEC); if (l == 1) pari_err_DOMAIN("idealaddmultoone", "sum(ideals)", "!=", gen_1, L); nz = 0; /* number of non-zero ideals in L */ for (i=1; i 1) swap(gel(x,1), gel(x,i)); /* help HNF */ gel(x,1) = scalarcol_shallow(gel(x,1), lx-1); break; } x = ZM_hnfmodid(x, D); dx = mul_denom(dx,dA); return dx? gdiv(x,dx): x; } /* nf a true nf, tx <= ty */ static GEN idealmul_aux(GEN nf, GEN x, GEN y, long tx, long ty) { GEN z, cx, cy; switch(tx) { case id_PRINCIPAL: switch(ty) { case id_PRINCIPAL: return idealhnf_principal(nf, nfmul(nf,x,y)); case id_PRIME: { GEN p = pr_get_p(y), pi = pr_get_gen(y), cx; if (pr_is_inert(y)) return RgM_Rg_mul(idealhnf_principal(nf,x),p); x = nf_to_scalar_or_basis(nf, x); switch(typ(x)) { case t_INT: if (!signe(x)) return cgetg(1,t_MAT); return ZM_Z_mul(pr_hnf(nf,y), absi_shallow(x)); case t_FRAC: return RgM_Rg_mul(pr_hnf(nf,y), Q_abs_shallow(x)); } /* t_COL */ x = Q_primitive_part(x, &cx); x = zk_multable(nf, x); z = shallowconcat(ZM_Z_mul(x,p), ZM_ZC_mul(x,pi)); z = ZM_hnfmodid(z, mulii(p, zkmultable_capZ(x))); return cx? ZM_Q_mul(z, cx): z; } default: /* id_MAT */ return idealmulelt(nf, x,y); } case id_PRIME: if (ty==id_PRIME) { y = pr_hnf(nf,y); cy = NULL; } else y = Q_primitive_part(y, &cy); y = idealHNF_mul_two(nf,y,x); return cy? ZM_Q_mul(y,cy): y; default: /* id_MAT */ { long N = nf_get_degree(nf); if (lg(x)-1 != N || lg(y)-1 != N) pari_err_DIM("idealmul"); x = Q_primitive_part(x, &cx); y = Q_primitive_part(y, &cy); cx = mul_content(cx,cy); y = idealHNF_mul(nf,x,y); return cx? ZM_Q_mul(y,cx): y; } } } /* output the ideal product ix.iy */ GEN idealmul(GEN nf, GEN x, GEN y) { pari_sp av; GEN res, ax, ay, z; long tx = idealtyp(&x,&ax); long ty = idealtyp(&y,&ay), f; if (tx>ty) { swap(ax,ay); swap(x,y); lswap(tx,ty); } f = (ax||ay); res = f? cgetg(3,t_VEC): NULL; /*product is an extended ideal*/ av = avma; z = gerepileupto(av, idealmul_aux(checknf(nf), x,y, tx,ty)); if (!f) return z; if (ax && ay) ax = ext_mul(nf, ax, ay); else ax = gcopy(ax? ax: ay); gel(res,1) = z; gel(res,2) = ax; return res; } /* Return x, integral in 2-elt form, such that pr^2 = c * x. cf idealpowprime * nf = true nf */ static GEN idealsqrprime(GEN nf, GEN pr, GEN *pc) { GEN p = pr_get_p(pr), q, gen; long e = pr_get_e(pr), f = pr_get_f(pr); q = (e == 1)? sqri(p): p; if (e <= 2 && e * f == nf_get_degree(nf)) { /* pr^e = (p) */ *pc = q; return mkvec2(gen_1,gen_0); } gen = nfsqr(nf, pr_get_gen(pr)); gen = FpC_red(gen, q); *pc = NULL; return mkvec2(q, gen); } /* cf idealpow_aux */ static GEN idealsqr_aux(GEN nf, GEN x, long tx) { GEN T = nf_get_pol(nf), m, cx, a, alpha; long N = degpol(T); switch(tx) { case id_PRINCIPAL: return idealhnf_principal(nf, nfsqr(nf,x)); case id_PRIME: if (pr_is_inert(x)) return scalarmat(sqri(gel(x,1)), N); x = idealsqrprime(nf, x, &cx); x = idealhnf_two(nf,x); return cx? ZM_Z_mul(x, cx): x; default: x = Q_primitive_part(x, &cx); a = mat_ideal_two_elt(nf,x); alpha = gel(a,2); a = gel(a,1); alpha = nfsqr(nf,alpha); m = zk_scalar_or_multable(nf, alpha); if (typ(m) == t_INT) { x = gcdii(sqri(a), m); if (cx) x = gmul(x, gsqr(cx)); x = scalarmat(x, N); } else { x = ZM_hnfmodid(m, gcdii(sqri(a), zkmultable_capZ(m))); if (cx) cx = gsqr(cx); if (cx) x = ZM_Q_mul(x, cx); } return x; } } GEN idealsqr(GEN nf, GEN x) { pari_sp av; GEN res, ax, z; long tx = idealtyp(&x,&ax); res = ax? cgetg(3,t_VEC): NULL; /*product is an extended ideal*/ av = avma; z = gerepileupto(av, idealsqr_aux(checknf(nf), x, tx)); if (!ax) return z; gel(res,1) = z; gel(res,2) = ext_sqr(nf, ax); return res; } /* norm of an ideal */ GEN idealnorm(GEN nf, GEN x) { pari_sp av; GEN y, T; long tx; switch(idealtyp(&x,&y)) { case id_PRIME: return pr_norm(x); case id_MAT: return RgM_det_triangular(x); } /* id_PRINCIPAL */ nf = checknf(nf); T = nf_get_pol(nf); av = avma; x = nf_to_scalar_or_alg(nf, x); x = (typ(x) == t_POL)? RgXQ_norm(x, T): gpowgs(x, degpol(T)); tx = typ(x); if (tx == t_INT) return gerepileuptoint(av, absi(x)); if (tx != t_FRAC) pari_err_TYPE("idealnorm",x); return gerepileupto(av, Q_abs(x)); } /* I^(-1) = { x \in K, Tr(x D^(-1) I) \in Z }, D different of K/Q * * nf[5][6] = pp( D^(-1) ) = pp( HNF( T^(-1) ) ), T = (Tr(wi wj)) * nf[5][7] = same in 2-elt form. * Assume I integral. Return the integral ideal (I\cap Z) I^(-1) */ GEN idealHNF_inv_Z(GEN nf, GEN I) { GEN J, dual, IZ = gcoeff(I,1,1); /* I \cap Z */ if (isint1(IZ)) return matid(lg(I)-1); J = idealHNF_mul(nf,I, gmael(nf,5,7)); /* I in HNF, hence easily inverted; multiply by IZ to get integer coeffs * missing content cancels while solving the linear equation */ dual = shallowtrans( hnf_divscale(J, gmael(nf,5,6), IZ) ); return ZM_hnfmodid(dual, IZ); } /* I HNF with rational coefficients (denominator d). */ GEN idealHNF_inv(GEN nf, GEN I) { GEN J, IQ = gcoeff(I,1,1); /* I \cap Q; d IQ = dI \cap Z */ J = idealHNF_inv_Z(nf, Q_remove_denom(I, NULL)); /* = (dI)^(-1) * (d IQ) */ return equali1(IQ)? J: RgM_Rg_div(J, IQ); } /* return p * P^(-1) [integral] */ GEN pr_inv_p(GEN pr) { if (pr_is_inert(pr)) return matid(pr_get_f(pr)); return ZM_hnfmodid(pr_get_tau(pr), pr_get_p(pr)); } GEN pr_inv(GEN pr) { GEN p = pr_get_p(pr); if (pr_is_inert(pr)) return scalarmat(ginv(p), pr_get_f(pr)); return RgM_Rg_div(ZM_hnfmodid(pr_get_tau(pr),p), p); } GEN idealinv(GEN nf, GEN x) { GEN res, ax; pari_sp av; long tx = idealtyp(&x,&ax), N; res = ax? cgetg(3,t_VEC): NULL; nf = checknf(nf); av = avma; N = nf_get_degree(nf); switch (tx) { case id_MAT: if (lg(x)-1 != N) pari_err_DIM("idealinv"); x = idealHNF_inv(nf,x); break; case id_PRINCIPAL: x = nf_to_scalar_or_basis(nf, x); if (typ(x) != t_COL) x = idealhnf_principal(nf,ginv(x)); else { /* nfinv + idealhnf where we already know (x) \cap Z */ GEN c, d; x = Q_remove_denom(x, &c); x = zk_inv(nf, x); x = Q_remove_denom(x, &d); /* true inverse is c/d * x */ if (!d) /* x and x^(-1) integral => x a unit */ x = scalarmat_shallow(c? c: gen_1, N); else { c = c? gdiv(c,d): ginv(d); x = zk_multable(nf, x); x = ZM_Q_mul(ZM_hnfmodid(x,d), c); } } break; case id_PRIME: x = pr_inv(x); break; } x = gerepileupto(av,x); if (!ax) return x; gel(res,1) = x; gel(res,2) = ext_inv(nf, ax); return res; } /* write x = A/B, A,B coprime integral ideals */ GEN idealnumden(GEN nf, GEN x) { pari_sp av = avma; GEN x0, ax, c, d, A, B, J; long tx = idealtyp(&x,&ax); nf = checknf(nf); switch (tx) { case id_PRIME: retmkvec2(idealhnf(nf, x), gen_1); case id_PRINCIPAL: { GEN xZ, mx; x = nf_to_scalar_or_basis(nf, x); switch(typ(x)) { case t_INT: return gerepilecopy(av, mkvec2(absi_shallow(x),gen_1)); case t_FRAC:return gerepilecopy(av, mkvec2(absi_shallow(gel(x,1)), gel(x,2))); } /* t_COL */ x = Q_remove_denom(x, &d); if (!d) return gerepilecopy(av, mkvec2(idealhnf(nf, x), gen_1)); mx = zk_multable(nf, x); xZ = zkmultable_capZ(mx); x = ZM_hnfmodid(mx, xZ); /* principal ideal (x) */ x0 = mkvec2(xZ, mx); /* same, for fast multiplication */ break; } default: /* id_MAT */ { long n = lg(x)-1; if (n == 0) return mkvec2(gen_0, gen_1); if (n != nf_get_degree(nf)) pari_err_DIM("idealnumden"); x0 = x = Q_remove_denom(x, &d); if (!d) return gerepilecopy(av, mkvec2(x, gen_1)); break; } } J = hnfmodid(x, d); /* = d/B */ c = gcoeff(J,1,1); /* (d/B) \cap Z, divides d */ B = idealHNF_inv_Z(nf, J); /* (d/B \cap Z) B/d */ if (!equalii(c,d)) B = ZM_Z_mul(B, diviiexact(d,c)); /* = B ! */ A = idealHNF_mul(nf, B, x0); /* d * (original x) * B = d A */ A = ZM_Z_divexact(A, d); /* = A ! */ return gerepilecopy(av, mkvec2(A, B)); } /* Return x, integral in 2-elt form, such that pr^n = c * x. Assume n != 0. * nf = true nf */ static GEN idealpowprime(GEN nf, GEN pr, GEN n, GEN *pc) { GEN p = pr_get_p(pr), q, gen; *pc = NULL; if (is_pm1(n)) /* n = 1 special cased for efficiency */ { q = p; if (typ(pr_get_tau(pr)) == t_INT) /* inert */ { *pc = (signe(n) >= 0)? p: ginv(p); return mkvec2(gen_1,gen_0); } if (signe(n) >= 0) gen = pr_get_gen(pr); else { gen = pr_get_tau(pr); /* possibly t_MAT */ *pc = ginv(p); } } else if (equalis(n,2)) return idealsqrprime(nf, pr, pc); else { long e = pr_get_e(pr), f = pr_get_f(pr); GEN r, m = truedvmdis(n, e, &r); if (e * f == nf_get_degree(nf)) { /* pr^e = (p) */ if (signe(m)) *pc = powii(p,m); if (!signe(r)) return mkvec2(gen_1,gen_0); q = p; gen = nfpow(nf, pr_get_gen(pr), r); } else { m = absi_shallow(m); if (signe(r)) m = addiu(m,1); q = powii(p,m); /* m = ceil(|n|/e) */ if (signe(n) >= 0) gen = nfpow(nf, pr_get_gen(pr), n); else { gen = pr_get_tau(pr); if (typ(gen) == t_MAT) gen = gel(gen,1); n = negi(n); gen = ZC_Z_divexact(nfpow(nf, gen, n), powii(p, subii(n,m))); *pc = ginv(q); } } gen = FpC_red(gen, q); } return mkvec2(q, gen); } /* x * pr^n. Assume x in HNF or scalar (possibly non-integral) */ GEN idealmulpowprime(GEN nf, GEN x, GEN pr, GEN n) { GEN c, cx, y; long N; nf = checknf(nf); N = nf_get_degree(nf); if (!signe(n)) return typ(x) == t_MAT? x: scalarmat_shallow(x, N); /* inert, special cased for efficiency */ if (pr_is_inert(pr)) { GEN q = powii(pr_get_p(pr), n); return typ(x) == t_MAT? RgM_Rg_mul(x,q) : scalarmat_shallow(gmul(Q_abs(x),q), N); } y = idealpowprime(nf, pr, n, &c); if (typ(x) == t_MAT) { x = Q_primitive_part(x, &cx); if (is_pm1(gcoeff(x,1,1))) x = NULL; } else { cx = x; x = NULL; } cx = mul_content(c,cx); if (x) x = idealHNF_mul_two(nf,x,y); else x = idealhnf_two(nf,y); if (cx) x = ZM_Q_mul(x,cx); return x; } GEN idealdivpowprime(GEN nf, GEN x, GEN pr, GEN n) { return idealmulpowprime(nf,x,pr, negi(n)); } /* nf = true nf */ static GEN idealpow_aux(GEN nf, GEN x, long tx, GEN n) { GEN T = nf_get_pol(nf), m, cx, n1, a, alpha; long N = degpol(T), s = signe(n); if (!s) return matid(N); switch(tx) { case id_PRINCIPAL: return idealhnf_principal(nf, nfpow(nf,x,n)); case id_PRIME: if (pr_is_inert(x)) return scalarmat(powii(gel(x,1), n), N); x = idealpowprime(nf, x, n, &cx); x = idealhnf_two(nf,x); return cx? ZM_Q_mul(x, cx): x; default: if (is_pm1(n)) return (s < 0)? idealinv(nf, x): gcopy(x); n1 = (s < 0)? negi(n): n; x = Q_primitive_part(x, &cx); a = mat_ideal_two_elt(nf,x); alpha = gel(a,2); a = gel(a,1); alpha = nfpow(nf,alpha,n1); m = zk_scalar_or_multable(nf, alpha); if (typ(m) == t_INT) { x = gcdii(powii(a,n1), m); if (s<0) x = ginv(x); if (cx) x = gmul(x, powgi(cx,n)); x = scalarmat(x, N); } else { x = ZM_hnfmodid(m, gcdii(powii(a,n1), zkmultable_capZ(m))); if (cx) cx = powgi(cx,n); if (s<0) { GEN xZ = gcoeff(x,1,1); cx = cx ? gdiv(cx, xZ): ginv(xZ); x = idealHNF_inv_Z(nf,x); } if (cx) x = ZM_Q_mul(x, cx); } return x; } } /* raise the ideal x to the power n (in Z) */ GEN idealpow(GEN nf, GEN x, GEN n) { pari_sp av; long tx; GEN res, ax; if (typ(n) != t_INT) pari_err_TYPE("idealpow",n); tx = idealtyp(&x,&ax); res = ax? cgetg(3,t_VEC): NULL; av = avma; x = gerepileupto(av, idealpow_aux(checknf(nf), x, tx, n)); if (!ax) return x; ax = ext_pow(nf, ax, n); gel(res,1) = x; gel(res,2) = ax; return res; } /* Return ideal^e in number field nf. e is a C integer. */ GEN idealpows(GEN nf, GEN ideal, long e) { long court[] = {evaltyp(t_INT) | _evallg(3),0,0}; affsi(e,court); return idealpow(nf,ideal,court); } static GEN _idealmulred(GEN nf, GEN x, GEN y) { return idealred(nf,idealmul(nf,x,y)); } static GEN _idealsqrred(GEN nf, GEN x) { return idealred(nf,idealsqr(nf,x)); } static GEN _mul(void *data, GEN x, GEN y) { return _idealmulred((GEN)data,x,y); } static GEN _sqr(void *data, GEN x) { return _idealsqrred((GEN)data, x); } /* compute x^n (x ideal, n integer), reducing along the way */ GEN idealpowred(GEN nf, GEN x, GEN n) { pari_sp av = avma; long s; GEN y; if (typ(n) != t_INT) pari_err_TYPE("idealpowred",n); s = signe(n); if (s == 0) return idealpow(nf,x,n); y = gen_pow(x, n, (void*)nf, &_sqr, &_mul); if (s < 0) y = idealinv(nf,y); if (s < 0 || is_pm1(n)) y = idealred(nf,y); return gerepileupto(av,y); } GEN idealmulred(GEN nf, GEN x, GEN y) { pari_sp av = avma; return gerepileupto(av, _idealmulred(nf,x,y)); } long isideal(GEN nf,GEN x) { long N, i, j, lx, tx = typ(x); pari_sp av; GEN T, xZ; nf = checknf(nf); T = nf_get_pol(nf); lx = lg(x); if (tx==t_VEC && lx==3) { x = gel(x,1); tx = typ(x); lx = lg(x); } switch(tx) { case t_INT: case t_FRAC: return 1; case t_POL: return varn(x) == varn(T); case t_POLMOD: return RgX_equal_var(T, gel(x,1)); case t_VEC: return get_prid(x)? 1 : 0; case t_MAT: break; default: return 0; } N = degpol(T); if (lx-1 != N) return (lx == 1); if (nbrows(x) != N) return 0; av = avma; x = Q_primpart(x); if (!ZM_ishnf(x)) return 0; xZ = gcoeff(x,1,1); for (j=2; j<=N; j++) if (!dvdii(xZ, gcoeff(x,j,j))) { avma = av; return 0; } for (i=2; i<=N; i++) for (j=2; j<=N; j++) if (! hnf_invimage(x, zk_ei_mul(nf,gel(x,i),j))) { avma = av; return 0; } avma=av; return 1; } GEN idealdiv(GEN nf, GEN x, GEN y) { pari_sp av = avma, tetpil; GEN z = idealinv(nf,y); tetpil = avma; return gerepile(av,tetpil, idealmul(nf,x,z)); } /* This routine computes the quotient x/y of two ideals in the number field nf. * It assumes that the quotient is an integral ideal. The idea is to find an * ideal z dividing y such that gcd(Nx/Nz, Nz) = 1. Then * * x + (Nx/Nz) x * ----------- = --- * y + (Ny/Nz) y * * Proof: we can assume x and y are integral. Let p be any prime ideal * * If p | Nz, then it divides neither Nx/Nz nor Ny/Nz (since Nx/Nz is the * product of the integers N(x/y) and N(y/z)). Both the numerator and the * denominator on the left will be coprime to p. So will x/y, since x/y is * assumed integral and its norm N(x/y) is coprime to p. * * If instead p does not divide Nz, then v_p (Nx/Nz) = v_p (Nx) >= v_p(x). * Hence v_p (x + Nx/Nz) = v_p(x). Likewise for the denominators. QED. * * Peter Montgomery. July, 1994. */ static void err_divexact(GEN x, GEN y) { pari_err_DOMAIN("idealdivexact","denominator(x/y)", "!=", gen_1,mkvec2(x,y)); } GEN idealdivexact(GEN nf, GEN x0, GEN y0) { pari_sp av = avma; GEN x, y, xZ, yZ, Nx, Ny, Nz, cy, q, r; nf = checknf(nf); x = idealhnf_shallow(nf, x0); y = idealhnf_shallow(nf, y0); if (lg(y) == 1) pari_err_INV("idealdivexact", y0); if (lg(x) == 1) { avma = av; return cgetg(1, t_MAT); } /* numerator is zero */ y = Q_primitive_part(y, &cy); if (cy) x = RgM_Rg_div(x,cy); xZ = gcoeff(x,1,1); if (typ(xZ) != t_INT) err_divexact(x,y); yZ = gcoeff(y,1,1); if (isint1(yZ)) return gerepilecopy(av, x); Nx = idealnorm(nf,x); Ny = idealnorm(nf,y); if (typ(Nx) != t_INT) err_divexact(x,y); q = dvmdii(Nx,Ny, &r); if (signe(r)) err_divexact(x,y); if (is_pm1(q)) { avma = av; return matid(nf_get_degree(nf)); } /* Find a norm Nz | Ny such that gcd(Nx/Nz, Nz) = 1 */ for (Nz = Ny;;) /* q = Nx/Nz */ { GEN p1 = gcdii(Nz, q); if (is_pm1(p1)) break; Nz = diviiexact(Nz,p1); q = mulii(q,p1); } xZ = gcoeff(x,1,1); q = gcdii(q, xZ); if (!equalii(xZ,q)) { /* Replace x/y by x+(Nx/Nz) / y+(Ny/Nz) */ x = ZM_hnfmodid(x, q); /* y reduced to unit ideal ? */ if (Nz == Ny) return gerepileupto(av, x); yZ = gcoeff(y,1,1); q = gcdii(diviiexact(Ny,Nz), yZ); y = ZM_hnfmodid(y, q); } yZ = gcoeff(y,1,1); y = idealHNF_mul(nf,x, idealHNF_inv_Z(nf,y)); return gerepileupto(av, ZM_Z_divexact(y, yZ)); } GEN idealintersect(GEN nf, GEN x, GEN y) { pari_sp av = avma; long lz, lx, i; GEN z, dx, dy, xZ, yZ;; nf = checknf(nf); x = idealhnf_shallow(nf,x); y = idealhnf_shallow(nf,y); if (lg(x) == 1 || lg(y) == 1) { avma = av; return cgetg(1,t_MAT); } x = Q_remove_denom(x, &dx); y = Q_remove_denom(y, &dy); if (dx) y = ZM_Z_mul(y, dx); if (dy) x = ZM_Z_mul(x, dy); xZ = gcoeff(x,1,1); yZ = gcoeff(y,1,1); dx = mul_denom(dx,dy); z = ZM_lll(shallowconcat(x,y), 0.99, LLL_KER); lz = lg(z); lx = lg(x); for (i=1; i v(b) * and pple all others */ /* return gcd(a,b),ppg(a,b),pple(a,b) */ GEN Z_ppgle(GEN a, GEN b) { GEN x, y, g, d = gcdii(a,b); if (equalii(a, d)) return mkvec3(a, gen_1, a); x = diviiexact(a,d); y = d; for(;;) { g = gcdii(x,y); if (is_pm1(g)) return mkvec3(d, x, y); x = mulii(x,g); y = diviiexact(y,g); } } static void Z_dcba_rec(GEN L, GEN a, GEN b) { GEN x, r, v, g, h, c, c0; long n; if (is_pm1(b)) { if (!is_pm1(a)) vectrunc_append(L, a); return; } v = Z_ppio(a,b); a = gel(v,2); r = gel(v,3); if (!is_pm1(r)) vectrunc_append(L, r); v = Z_ppgle(a,b); g = gel(v,1); h = gel(v,2); x = c0 = gel(v,3); for (n = 1; !is_pm1(h); n++) { GEN d, y; long i; v = Z_ppgle(h,sqri(g)); g = gel(v,1); h = gel(v,2); c = gel(v,3); if (is_pm1(c)) continue; d = gcdii(c,b); x = mulii(x,d); y = d; for (i=1; i < n; i++) y = sqri(y); Z_dcba_rec(L, diviiexact(c,y), d); } Z_dcba_rec(L,diviiexact(b,x), c0); } static GEN Z_cba_rec(GEN L, GEN a, GEN b) { GEN g; if (lg(L) > 10) { /* a few naive steps before switching to dcba */ Z_dcba_rec(L, a, b); return gel(L, lg(L)-1); } if (is_pm1(a)) return b; g = gcdii(a,b); if (is_pm1(g)) { vectrunc_append(L, a); return b; } a = diviiexact(a,g); b = diviiexact(b,g); return Z_cba_rec(L, Z_cba_rec(L, a, g), b); } GEN Z_cba(GEN a, GEN b) { GEN L = vectrunc_init(expi(a) + expi(b) + 2); GEN t = Z_cba_rec(L, a, b); if (!is_pm1(t)) vectrunc_append(L, t); return L; } /* P = coprime base, extend it by b; TODO: quadratic for now */ GEN ZV_cba_extend(GEN P, GEN b) { long i, l = lg(P); GEN w = cgetg(l+1, t_VEC); for (i = 1; i < l; i++) { GEN v = Z_cba(gel(P,i), b); long nv = lg(v)-1; gel(w,i) = vecslice(v, 1, nv-1); /* those divide P[i] but not b */ b = gel(v,nv); } gel(w,l) = b; return shallowconcat1(w); } GEN ZV_cba(GEN v) { long i, l = lg(v); GEN P; if (l <= 2) return v; P = Z_cba(gel(v,1), gel(v,2)); for (i = 3; i < l; i++) P = ZV_cba_extend(P, gel(v,i)); return P; } /* write x = x1 x2, x2 maximal s.t. (x2,f) = 1, return x2 */ GEN Z_ppo(GEN x, GEN f) { for (;;) { f = gcdii(x, f); if (is_pm1(f)) break; x = diviiexact(x, f); } return x; } /* write x = x1 x2, x2 maximal s.t. (x2,f) = 1, return x2 */ ulong u_ppo(ulong x, ulong f) { for (;;) { f = ugcd(x, f); if (f == 1) break; x /= f; } return x; } /* x t_INT, f ideal. Write x = x1 x2, sqf(x1) | f, (x2,f) = 1. Return x2 */ static GEN nf_coprime_part(GEN nf, GEN x, GEN listpr) { long v, j, lp = lg(listpr), N = nf_get_degree(nf); GEN x1, x2, ex; #if 0 /*1) via many gcds. Expensive ! */ GEN f = idealprodprime(nf, listpr); f = ZM_hnfmodid(f, x); /* first gcd is less expensive since x in Z */ x = scalarmat(x, N); for (;;) { if (gequal1(gcoeff(f,1,1))) break; x = idealdivexact(nf, x, f); f = ZM_hnfmodid(shallowconcat(f,x), gcoeff(x,1,1)); /* gcd(f,x) */ } x2 = x; #else /*2) from prime decomposition */ x1 = NULL; for (j=1; j 0 */ x1 = x1? idealmulpowprime(nf, x1, pr, ex) : idealpow(nf, pr, ex); } x = scalarmat(x, N); x2 = x1? idealdivexact(nf, x, x1): x; #endif return x2; } /* L0 in K^*, assume (L0,f) = 1. Return L integral, L0 = L mod f */ GEN make_integral(GEN nf, GEN L0, GEN f, GEN listpr) { GEN fZ, t, L, D2, d1, d2, d; L = Q_remove_denom(L0, &d); if (!d) return L0; /* L0 = L / d, L integral */ fZ = gcoeff(f,1,1); if (typ(L) == t_INT) return Fp_mul(L, Fp_inv(d, fZ), fZ); /* Kill denom part coprime to fZ */ d2 = Z_ppo(d, fZ); t = Fp_inv(d2, fZ); if (!is_pm1(t)) L = ZC_Z_mul(L,t); if (equalii(d, d2)) return L; d1 = diviiexact(d, d2); /* L0 = (L / d1) mod f. d1 not coprime to f * write (d1) = D1 D2, D2 minimal, (D2,f) = 1. */ D2 = nf_coprime_part(nf, d1, listpr); t = idealaddtoone_i(nf, D2, f); /* in D2, 1 mod f */ L = nfmuli(nf,t,L); /* if (L0, f) = 1, then L in D1 ==> in D1 D2 = (d1) */ return Q_div_to_int(L, d1); /* exact division */ } /* assume L is a list of prime ideals. Return the product */ GEN idealprodprime(GEN nf, GEN L) { long l = lg(L), i; GEN z; if (l == 1) return matid(nf_get_degree(nf)); z = pr_hnf(nf, gel(L,1)); for (i=2; i= 0 for all other pr. * For optimal performance, all [anti-]uniformizers should be precomputed, * but no support for this yet. * * If nored, do not reduce result. * No garbage collecting */ static GEN idealapprfact_i(GEN nf, GEN x, int nored) { GEN z, d, L, e, e2, F; long i, r; int flagden; nf = checknf(nf); L = gel(x,1); e = gel(x,2); F = prV_lcm_capZ(L); flagden = 0; z = NULL; r = lg(e); for (i = 1; i < r; i++) { long s = signe(gel(e,i)); GEN pi, q; if (!s) continue; if (s < 0) flagden = 1; pi = pr_uniformizer(gel(L,i), F); q = nfpow(nf, pi, gel(e,i)); z = z? nfmul(nf, z, q): q; } if (!z) return gen_1; if (nored || typ(z) != t_COL) return z; e2 = cgetg(r, t_VEC); for (i=1; i v)? cvtop(h,gel(h,2),v): h; } /* TATE CURVE */ /* a1, b1 are t_PADICs, a1/b1 = 1 (mod p) if p odd, (mod 2^4) otherwise. * Let (A_n, B_n) be defined by A_1 = a1/p^v, B_1 = b1/p^v, v=v(a1)=v(a2); * A_{n+1} = (A_n + B_n + 2 B_{n+1}) / 4 * B_{n+1} = B_n sqrt(A_n / B_n) = square root of A_n B_n congruent to B_n * R_n = p^v( A_n - B_n ) = r_{n+1} * Return [An,Bn,Rn]. N.B. lim An = M2(a1,b1) = M(sqrt(a1),sqrt(b1))^2 */ GEN Qp_agm2_sequence(GEN a1, GEN b1) { GEN bp, pmod, p = gel(a1,2), q = gel(a1,3), An, Bn, Rn; long pp = precp(a1), v = valp(a1), i; int pis2 = absequaliu(p,2); a1 = gel(a1,4); b1 = gel(b1,4); if (pis2) pmod = utoipos(8); else pmod = p; bp = modii(b1, pmod); An = cgetg(pp+1, t_VEC); /* overestimate: rather log_2(pp) */ Bn = cgetg(pp+1, t_VEC); Rn = cgetg(pp+1, t_VEC); for(i = 1;; i++) { GEN a = a1, b = b1, r; long vr; gel(An, i) = a; gel(Bn, i) = b; r = subii(a,b); if (!signe(r)) break; vr = Z_pvalrem(r,p,&r); if (vr >= pp) break; r = cvtop(r, p, pp - vr); setvalp(r, vr+v); gel(Rn, i) = r; b1 = Zp_sqrt(Fp_mul(a,b,q), p, pp); if (!b1) pari_err_PREC("p-adic AGM"); if (!equalii(modii(b1,pmod), bp)) b1 = Fp_neg(b1, q); /* a1 = (a+b+2sqrt(ab))/4 */ if (pis2) { b1 = remi2n(b1, pp-1); a1 = shifti(addii(addii(a,b), shifti(b1,1)),-2); a1 = remi2n(a1, pp-2); pp -= 2; } else a1 = modii(Fp_halve(addii(Fp_halve(addii(a,b),q), b1), q), q); } setlg(An,i+1); setlg(Bn,i+1); setlg(Rn,i); return mkvec4(An, Bn, Rn, stoi(v)); } void Qp_descending_Landen(GEN AB, GEN *ptx, GEN *pty) { GEN R = gel(AB,3); long i, n = lg(R)-1; GEN x = *ptx; if (isintzero(x)) { i = 2; x = gmul2n(gel(R,1),-2); if (pty) { GEN A = gel(AB,1); if (n == 1) *pty = gmul(x, Qp_sqrt(gadd(x,gel(A,2)))); else *pty = Qp_sqrt(gmul(gmul(x, gadd(x,gel(A,2))), gadd(x,gel(R,2)))); if (!*pty) pari_err_PREC("Qp_descending_Landen"); } } else i = 1; for (; i <= n; i++) { GEN r = gel(R,i), t; if (gequal0(x)) pari_err_PREC("Qp_descending_Landen"); t = Qp_sqrt(gaddsg(1, gdiv(r,x))); /* = 1 (mod p) */ if (!t) pari_err_PREC("Qp_descending_Landen"); if (i == n) { GEN p = gel(r,2); long v, vx = valp(x), vr = valp(r); if (vx >= vr) pari_err_PREC("Qp_descending_Landen"); /* last loop, take into account loss of accuracy from multiplication * by \prod_{j > n} sqrt(1+r_j/x_j); since vx < vr, j = n+1 is enough */ v = 2*vr - vx; /* |r_{n+1}| <= |(r_n)^2 / 8| + 1 bit for sqrt loss */ if (absequaliu(p,2)) v -= 4; /* tail is 1 + O(p^v) */ if (v < precp(x)) x = cvtop(x,p,v); } /* x_{n+1} = x_n ((1 + sqrt(1 + r_n/x_n)) / 2)^2 */ x = gmul(x, gsqr(gmul2n(gaddsg(1,t),-1))); /* y_{n+1} = y_n / (1 - (r_n/4x_{n+1})^2) */ if (pty) *pty = gdiv(*pty, gsubsg(1, gsqr(gdiv(r,gmul2n(x,2))))); } *ptx = x; } void Qp_ascending_Landen(GEN AB, GEN *ptx, GEN *pty) { GEN A = gel(AB,1), R = gel(AB,3), x = *ptx, p, r; long n = lg(R)-1, va = itos(gel(AB,4)), v, i; r = gel(R,n); v = 2*valp(r) + va; if (typ(x) == t_PADIC) v -= 2*valp(x); else v -= valp(gnorm(x)); /* v(x) = v(Nx) / (e*f), here ef = 2 */ p = gel(r,2); if (absequaliu(p,2)) v -= 3; /* |r_{n+1}| <= |(r_n)^2 / 8| */ /* v = v(A[n+1] R[n+1] / x_{n+1}^2) */ if (v <= 0) pari_err_PREC("Qp_ascending_Landen"); /* v > 0 => v = v(x_oo) = ... = v(x_{n+1}) */ x = gsub(x, gmul2n(r,-1)); if (padicprec_relative(x) > v) x = gcvtop(x, p, v); /* x = x_n */ for (i = n; i > 1; i--) { GEN ar = gmul(gel(A,i),gel(R,i)), xp; setvalp(ar, valp(ar)+va); /* A_i = A[i] * p^va */ /* x_{i-1} = x_i + a_i r_i / x_i - r_{i-1}/2 */ xp = gsub(gadd(x, gdiv(ar, x)), gmul2n(gel(R,i-1),-1)); /* y_{i-1} = y_i (1 - a_i r_i / x^2) */ if (pty) *pty = gmul(*pty, gsubsg(1, gdiv(ar,gsqr(x)))); x = xp; } *ptx = x; } /* Let T = 4x^3 + b2 x^2 + 2b4 x + b6, where T has a unique p-adic root 'a'. * Return a lift of a to padic accuracy prec. We have * 216 T = 864 X^3 - 18 c4X - c6, where X = x + b2/12 */ static GEN doellQp_root(GEN E, long prec) { GEN c4=ell_get_c4(E), c6=ell_get_c6(E), j=ell_get_j(E), p=ellQp_get_p(E); GEN c6p, T, a; long alpha; int pis2 = absequaliu(p, 2); if (Q_pval(j, p) >= 0) pari_err_DOMAIN(".root", "v_p(j)", ">=", gen_0, j); /* v(j) < 0 => v(c4^3) = v(c6^2) = 2 alpha */ alpha = Q_pvalrem(ell_get_c4(E), p, &c4) >> 1; if (alpha) (void)Q_pvalrem(ell_get_c6(E), p, &c6); /* Renormalized so that v(c4) = v(c6) = 0; multiply by p^alpha at the end */ if (prec < 4 && pis2) prec = 4; c6p = modii(c6,p); if (pis2) { /* Use 432T(X/4) = 27X^3 - 9c4 X - 2c6 to have integral root; a=0 mod 2 */ T = mkpoln(4, utoipos(27), gen_0, mulis(c4,-9), mulis(c6, -2)); /* v_2(root a) = 1, i.e. will lose one bit of accuracy: prec+1 */ a = ZpX_liftroot(T, gen_0, p, prec+1); alpha -= 2; } else if (absequaliu(p, 3)) { /* Use 216T(X/3) = 32X^3 - 6c4 X - c6 to have integral root; a=-c6 mod 3 */ a = Fp_neg(c6p, p); T = mkpoln(4, utoipos(32), gen_0, mulis(c4, -6), negi(c6)); a = ZX_Zp_root(T, a, p, prec); switch(lg(a)-1) { case 1: /* single root */ a = gel(a,1); break; case 3: /* three roots, e.g. "15a1", choose the right one */ { GEN a1 = gel(a,1), a2 = gel(a,2), a3 = gel(a,3); long v1 = Z_lval(subii(a2, a3), 3); long v2 = Z_lval(subii(a1, a3), 3); long v3 = Z_lval(subii(a1, a2), 3); if (v1 == v2) a = a3; else if (v1 == v3) a = a2; else a = a1; } break; } alpha--; } else { /* p != 2,3: T = 4(x-a)(x-b)^2 = 4x^3 - 3a^2 x - a^3 when b = -a/2 * (so that the trace coefficient vanishes) => a = c6/6c4 (mod p)*/ GEN c4p = modii(c4,p); a = Fp_div(c6p, Fp_mulu(c4p, 6, p), p); T = mkpoln(4, utoipos(864), gen_0, mulis(c4, -18), negi(c6)); a = ZpX_liftroot(T, a, p, prec); } a = cvtop(a, p, prec); if (alpha) setvalp(a, valp(a)+alpha); return gsub(a, gdivgs(ell_get_b2(E), 12)); } GEN ellQp_root(GEN E, long prec) { return obj_checkbuild_padicprec(E, Qp_ROOT, &doellQp_root, prec); } /* compute a,b such that E1: y^2 = x(x-a)(x+a-b) ~ E */ static void doellQp_ab(GEN E, GEN *pta, GEN *ptb, long prec) { GEN b2 = ell_get_b2(E), b4 = ell_get_b4(E), e1 = ellQp_root(E, prec); GEN w, u, t = gadd(gdivgs(b2,4), gmulsg(3,e1)), p = ellQp_get_p(E); w = Qp_sqrt(gmul2n(gadd(b4,gmul(e1,gadd(b2,gmulsg(6,e1)))),1)); u = gadd(t,w); /* Decide between w and -w: we want v(a-b) > v(b) */ if (absequaliu(p,2)) { if (valp(u)-1 <= valp(w)) w = gneg_i(w); } else { if (valp(u) <= valp(w)) w = gneg_i(w); } /* w^2 = 2b4 + 2b2 e1 + 12 e1^2 = 4(e1-e2)(e1-e3) */ *pta = gmul2n(gsub(w,t),-2); *ptb = gmul2n(w,-1); } static GEN doellQp_Tate(GEN E, long prec0) { GEN p = ellQp_get_p(E), j = ell_get_j(E); GEN L, u, u2, q, x1, a, b, d, s, t, AB, A, M2; long v, n, pp, prec = prec0+3; int split = -1; /* unknown */ int pis2 = equaliu(p,2); if (Q_pval(j, p) >= 0) pari_err_DOMAIN(".tate", "v_p(j)", ">=", gen_0, j); START: doellQp_ab(E, &a, &b, prec); d = gsub(a,b); v = prec0 - precp(d); if (v > 0) { prec += v; goto START; } AB = Qp_agm2_sequence(a,b); A = gel(AB,1); n = lg(A)-1; /* AGM iterations */ pp = minss(precp(a),precp(b)); M2 = cvtop(gel(A,n), p, pis2? pp-2*n: pp); setvalp(M2, valp(a)); u2 = ginv(gmul2n(M2, 2)); if (split < 0) split = issquare(u2); x1 = gen_0; Qp_descending_Landen(AB,&x1,NULL); t = gaddsg(1, ginv(gmul2n(gmul(u2,x1),1))); s = Qp_sqrt(gsubgs(gsqr(t), 1)); q = gadd(t,s); if (gequal0(q)) q = gsub(t,s); v = prec0 - precp(q); if (split) { /* we want log q at precision prec0 */ GEN q0 = leafcopy(q); setvalp(q0, 0); v += valp(gsubgs(q0,1)); } if (v > 0) { prec += v; goto START; } if (valp(q) < 0) q = ginv(q); if (split) { u = Qp_sqrt(u2); L = gdivgs(Qp_log(q), valp(q)); } else { GEN T = mkpoln(3, gen_1, gen_0, gneg(u2)); u = mkpolmod(pol_x(0), T); L = gen_1; } return mkvecn(6, u2, u, q, mkvec2(a, b), L, AB); } static long Tate_prec(GEN T) { return padicprec_relative(gel(T,3)); } GEN ellQp_Tate_uniformization(GEN E, long prec) { return obj_checkbuild_prec(E,Qp_TATE,&doellQp_Tate, &Tate_prec,prec); } GEN ellQp_u(GEN E, long prec) { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,2); } GEN ellQp_u2(GEN E, long prec) { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,1); } GEN ellQp_q(GEN E, long prec) { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,3); } GEN ellQp_ab(GEN E, long prec) { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,4); } GEN ellQp_L(GEN E, long prec) { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,5); } GEN ellQp_AGM(GEN E, long prec) { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,6); } /* FORMAL GROUP */ /* t to w := -1/y */ GEN ellformalw(GEN e, long n, long v) { pari_sp av = avma, av2; GEN a1,a2,a3,a4,a6, a63; GEN w = cgetg(3, t_SER), t, U, V, W, U2; ulong mask, nold = 1; if (v < 0) v = 0; if (n <= 0) pari_err_DOMAIN("ellformalw","precision","<=",gen_0,stoi(n)); mask = quadratic_prec_mask(n); t = pol_x(v); checkell(e); a1 = ell_get_a1(e); a2 = ell_get_a2(e); a3 = ell_get_a3(e); a4 = ell_get_a4(e); a6 = ell_get_a6(e); a63 = gmulgs(a6,3); w[1] = evalsigne(1)|evalvarn(v)|evalvalp(3); gel(w,2) = gen_1; /* t^3 + O(t^4) */ /* use Newton iteration, doubling accuracy at each step * * w^3 a6 + w^2(a4 t + a3) + w (a2 t^2 + a1 t - 1) + t^3 * w <- w - ----------------------------------------------------- * w^2 (3a6) + w (2a4 t + 2a3) + (a2 t^2 + a1 t - 1) * * w^3 a6 + w^2 U + w V + W * =: w - ----------------------- * w^2 (3a6) + 2w U + V */ U = gadd(gmul(a4,t), a3); U2 = gmul2n(U,1); V = gsubgs(gadd(gmul(a2,gsqr(t)), gmul(a1,t)), 1); W = gpowgs(t,3); av2 = avma; while (mask > 1) { /* nold correct terms in w */ ulong i, nnew = nold << 1; GEN num, den, wnew, w2, w3; if (mask & 1) nnew--; mask >>= 1; wnew = cgetg(nnew+2, t_SER); wnew[1] = w[1]; for (i = 2; i < nold+2; i++) gel(wnew,i) = gel(w,i); for ( ; i < nnew+2; i++) gel(wnew,i) = gen_0; w = wnew; w2 = gsqr(w); w3 = gmul(w2,w); num = gadd(gmul(a6,w3), gadd(gmul(U,w2), gadd(gmul(V,w), W))); den = gadd(gmul(a63,w2), gadd(gmul(w,U2), V)); w = gerepileupto(av2, gsub(w, gdiv(num, den))); nold = nnew; } return gerepilecopy(av, w); } static GEN ellformalpoint_i(GEN w, GEN wi) { return mkvec2(gmul(pol_x(varn(w)),wi), gneg(wi)); } /* t to [x,y] */ GEN ellformalpoint(GEN e, long n, long v) { pari_sp av = avma; GEN w = ellformalw(e, n, v), wi = ser_inv(w); return gerepilecopy(av, ellformalpoint_i(w, wi)); } static GEN ellformaldifferential_i(GEN e, GEN w, GEN wi, GEN *px) { GEN x, w1; if (gequal0(ell_get_a1(e)) && gequal0(ell_get_a3(e))) { /* dx/2y = dx * -w/2, avoid division */ x = gmul(pol_x(varn(w)), wi); w1 = gmul(derivser(x), gneg(gmul2n(w,-1))); } else { GEN P = ellformalpoint_i(w, wi); x = gel(P,1); w1 = gdiv(derivser(x), ec_dmFdy_evalQ(e, P)); } *px = x; return w1; } /* t to [ dx / (2y + a1 x + a3), x * ... ]*/ GEN ellformaldifferential(GEN e, long n, long v) { pari_sp av = avma; GEN w = ellformalw(e, n, v), wi = ser_inv(w), x; GEN w1 = ellformaldifferential_i(e, w, wi, &x); return gerepilecopy(av, mkvec2(w1,gmul(x,w1))); } /* t to z, dz = w1 dt */ GEN ellformallog(GEN e, long n, long v) { pari_sp av = avma; GEN w = ellformalw(e, n, v), wi = ser_inv(w), x; GEN w1 = ellformaldifferential_i(e, w, wi, &x); return gerepileupto(av, integser(w1)); } /* z to t */ GEN ellformalexp(GEN e, long n, long v) { pari_sp av = avma; return gerepileupto(av, serreverse(ellformallog(e,n,v))); } /* [log_p (sigma(t) / t), log_E t], as power series, d (log_E t) := w1 dt; * As a fonction of z: odd, = e.b2/12 * z + O(z^3). * sigma(z) = ellsigma(e) exp(e.b2/24*z^2) * log_p(sigma(t)/t)=log(subst(sigma(z), x, ellformallog(e))/x) */ static GEN ellformallogsigma_t(GEN e, long n) { pari_sp av = avma; GEN w = ellformalw(e, n, 0), wi = ser_inv(w), t = pol_x(0); GEN x, s = ellformaldifferential_i(e, w, wi, &x); GEN f = gmul(s, gadd(integser(gmul(x,s)), gmul2n(ell_get_a1(e),-1))); return gerepilecopy(av, mkvec2(integser( gsub(ginv(gneg(t)), f) ), integser(s))); } /* P-ADIC HEIGHTS */ /* m >= 0, T = b6^2, g4 = b6^2 - b4 b8, return g_m(xP) mod N, in Mazur-Tate's * notation (Duke 1991)*/ static GEN rellg(hashtable *H, GEN m, GEN T, GEN g4, GEN b8, GEN N) { hashentry *h; GEN n, z, np2, np1, nm2, nm1, fp2, fp1, fm2, fm1, f; ulong m4; if (abscmpiu(m, 4) <= 0) switch(itou(m)) { case 0: return gen_0; case 1: return gen_1; case 2: return subiu(N,1); case 3: return b8; case 4: return g4; } if ((h = hash_search(H, (void*)m))) return (GEN)h->val; m4 = mod4(m); n = shifti(m, -1); f = rellg(H,n,T,g4,b8,N); np2 = addiu(n, 2); fp2 = rellg(H,np2,T,g4,b8,N); np1 = addiu(n, 1); fp1 = rellg(H,np1,T,g4,b8,N); nm2 = subiu(n, 2); fm2 = rellg(H,nm2,T,g4,b8,N); nm1 = subiu(n, 1); fm1 = rellg(H,nm1,T,g4,b8,N); if (odd(m4)) { GEN t1 = Fp_mul(fp2, Fp_powu(f,3,N), N); GEN t2 = Fp_mul(fm1, Fp_powu(fp1,3,N), N); if (mpodd(n)) t2 = Fp_mul(T,t2,N); else t1 = Fp_mul(T,t1,N); z = Fp_sub(t1, t2, N); } else { GEN t1 = Fp_mul(fm2, Fp_sqr(fp1,N), N); GEN t2 = Fp_mul(fp2, Fp_sqr(fm1,N), N); z = Fp_mul(f, Fp_sub(t1, t2, N), N); } hash_insert(H, (void*)m, (void*)z); return z; } static GEN addii3(GEN x, GEN y, GEN z) { return addii(x,addii(y,z)); } static GEN addii4(GEN x, GEN y, GEN z, GEN t) { return addii(x,addii3(y,z,t)); } static GEN addii5(GEN x, GEN y, GEN z, GEN t, GEN u) { return addii(x,addii4(y,z,t,u)); } /* xP = [n,d] (corr. to n/d, coprime), such that the reduction of the point * P = [xP,yP] is non singular at all places. Return x([m] P) mod N as * [num,den] (coprime) */ static GEN xmP(GEN e, GEN xP, GEN m, GEN N) { pari_sp av = avma; ulong k = expi(m); hashtable *H = hash_create((5+k)*k, (ulong(*)(void*))&hash_GEN, (int(*)(void*,void*))&gidentical, 1); GEN b2 = ell_get_b2(e), b4 = ell_get_b4(e), n = gel(xP,1), d = gel(xP,2); GEN b6 = ell_get_b6(e), b8 = ell_get_b8(e); GEN B4, B6, B8, T, g4; GEN d2 = Fp_sqr(d,N), d3 = Fp_mul(d2,d,N), d4 = Fp_sqr(d2,N); GEN n2 = Fp_sqr(n,N), n3 = Fp_mul(n2,n,N), n4 = Fp_sqr(n2,N); GEN nd = Fp_mul(n,d,N), n2d2 = Fp_sqr(nd,N); GEN b2nd = Fp_mul(b2,nd, N), b2n2d = Fp_mul(b2nd,n,N); GEN b6d3 = Fp_mul(b6,d3,N), g,gp1,gm1, C,D; B8 = addii5(muliu(n4,3), mulii(b2n2d,n), mulii(muliu(b4,3), n2d2), mulii(muliu(b6d3,3), n), mulii(b8,d4)); B6 = addii4(muliu(n3,4), mulii(b2nd,n), shifti(mulii(b4,Fp_mul(n,d2,N)), 1), b6d3); B4 = addii3(muliu(n2,6), b2nd, mulii(b4,d2)); B4 = modii(B4,N); B6 = modii(B6,N); B8 = modii(B8,N); g4 = Fp_sub(sqri(B6), mulii(B4,B8), N); T = Fp_sqr(B6,N); g = rellg(H, m, T,g4,B8, N); gp1 = rellg(H, addiu(m,1), T,g4,B8, N); gm1 = rellg(H, subiu(m,1), T,g4,B8, N); C = Fp_sqr(g, N); D = Fp_mul(gp1,gm1, N); if (mpodd(m)) { n = Fp_sub(mulii(C,n), mulii(D,B6), N); d = Fp_mul(C,d, N); } else { n = Fp_sub(Fp_mul(Fp_mul(B6,C,N), n, N), D, N); d = Fp_mul(Fp_mul(C,d,N), B6, N); } return gerepilecopy(av, mkvec2(n,d)); } /* given [n,d2], x = n/d2 (coprime, d2 = d^2), p | den, * return t = -x/y + O(p^v) */ static GEN tfromx(GEN e, GEN x, GEN p, long v, GEN N, GEN *pd) { GEN n = gel(x,1), d2 = gel(x,2), d; GEN a1, a3, b2, b4, b6, B, C, d4, d6, Y; if (!signe(n)) { *pd = gen_1; return zeropadic(p, v); } a1 = ell_get_a1(e); b2 = ell_get_b2(e); a3 = ell_get_a3(e); b4 = ell_get_b4(e); b6 = ell_get_b6(e); d = Qp_sqrt(cvtop(d2, p, v - Z_pval(d2,p))); if (!d) pari_err_BUG("ellpadicheight"); /* Solve Y^2 = 4n^3 + b2 n^2 d2+ 2b4 n d2^2 + b6 d2^3, * Y = 2y + a1 n d + a3 d^3 */ d4 = Fp_sqr(d2, N); d6 = Fp_mul(d4, d2, N); B = gmul(d, Fp_add(mulii(a1,n), mulii(a3,d2), N)); C = mkpoln(4, utoipos(4), Fp_mul(b2, d2, N), Fp_mul(shifti(b4,1), d4, N), Fp_mul(b6,d6,N)); C = FpX_eval(C, n, N); if (!signe(C)) Y = zeropadic(p, v >> 1); else Y = Qp_sqrt(cvtop(C, p, v - Z_pval(C,p))); if (!Y) pari_err_BUG("ellpadicheight"); *pd = d; return gdiv(gmulgs(gmul(n,d), -2), gsub(Y,B)); } /* return minimal i s.t. -v_p(j+1) - log_p(j-1) + (j+1)*t >= v for all j>=i */ static long logsigma_prec(GEN p, long v, long t) { double log2p = dbllog2(p); long j, i = ceil((v - t) / (t - 2*M_LN2/(3*log2p)) + 0.01); if (absequaliu(p,2) && i < 5) i = 5; /* guaranteed to work, now optimize */ for (j = i-1; j >= 2; j--) { if (- u_pval(j+1,p) - log2(j-1)/log2p + (j+1)*t + 0.01 < v) break; i = j; } if (j == 1) { if (- absequaliu(p,2) + 2*t + 0.01 >= v) i = 1; } return i; } /* return minimal i s.t. -v_p(j+1) + (j+1)*t >= v for all j>=i */ static long log_prec(GEN p, long v, long t) { double log2p = dbllog2(p); long j, i = ceil(v / (t - M_LN2/(2*log2p)) + 0.01); /* guaranteed to work, now optimize */ for (j = i-1; j >= 1; j--) { if (- u_pval(j+1,p) + (j+1)*t + 0.01 < v) break; i = j; } return i; } /* P = rational point of exact denominator d. Is Q singular on E(Fp) ? */ static int FpE_issingular(GEN E, GEN P, GEN d, GEN p) { pari_sp av = avma; GEN t, x, y, a1, a2, a3, a4; if (ell_is_inf(E) || dvdii(d,p)) return 0; /* 0_E is smooth */ P = Q_muli_to_int(P,d); x = gel(P,1); y = gel(P,2); a1 = ell_get_a1(E); a3 = ell_get_a3(E); t = addii(shifti(y,1), addii(mulii(a1,x), mulii(a3,d))); if (!dvdii(t,p)) { avma = av; return 0; } a2 = ell_get_a2(E); a4 = ell_get_a4(E); d = Fp_inv(d, p); x = Fp_mul(x,d,p); y = Fp_mul(y,d,p); t = subii(mulii(a1,y), addii(a4, mulii(x, addii(gmul2n(a2,1), muliu(x,3))))); avma = av; return dvdii(t,p); } /* E/Q, P on E(Q). Let g > 0 minimal such that the image of R = [g]P in a * minimal model is everywhere non-singular; return [R,g] */ GEN ellnonsingularmultiple(GEN e, GEN P) { pari_sp av = avma; GEN ch, E = ellanal_globalred(e, &ch), NP, L, S, d, g = gen_1; long i, l; checkellpt(P); if (ell_is_inf(P)) retmkvec2(gcopy(P), gen_1); if (E != e) P = ellchangepoint(P, ch); S = obj_check(E, Q_GLOBALRED); NP = gmael(S,3,1); L = gel(S,4); l = lg(NP); d = Q_denom(P); for (i = 1; i < l; i++) { GEN G = gel(L,i), p = gel(NP,i);/* prime of bad reduction */ long kod; if (!FpE_issingular(E, P, d, p)) continue; kod = itos(gel(G,2)); /* Kodaira type */ if (kod >= 5) /* I_nu */ { long nu = kod - 4; long n = minss(Q_pval(ec_dmFdy_evalQ(E,P), p), nu/2); nu /= ugcd(nu, n); g = muliu(g, nu); P = ellmul(E, P, utoipos(nu)); d = Q_denom(P); } else if (kod <= -5) /* I^*_nu */ { /* either 2 or 4 */ long nu = - kod - 4; P = elladd(E, P,P); d = Q_denom(P); g = shifti(g,1); if (odd(nu) && FpE_issingular(E, P, d, p)) { /* it's 4 */ P = elladd(E, P,P); d = Q_denom(P); g = shifti(g,1); } } else { GEN c = gel(G, 4); /* Tamagawa number at p */ if (absequaliu(c, 4)) c = gen_2; P = ellmul(E, P, c); d = Q_denom(P); g = mulii(g, c); } } if (E != e) P = ellchangepointinv(P, ch); return gerepilecopy(av, mkvec2(P,g)); } GEN ellpadicheight(GEN e, GEN p, long v0, GEN P) { pari_sp av = avma; GEN N, H, h, t, ch, g, E, x, D, ls, lt, S, a,b; long v, vd; int is2; checkellpt(P); if (v0<=0) pari_err_DOMAIN("ellpadicheight","precision","<=",gen_0,stoi(v0)); checkell_Q(e); if (typ(p) != t_INT) pari_err_TYPE("ellpadicheight",p); if (cmpiu(p,2) < 0) pari_err_PRIME("ellpadicheight",p); if (ellorder_Q(e,P)) return mkvec2(gen_0,gen_0); E = ellanal_globalred(e, &ch); if (E != e) P = ellchangepoint(P, ch); S = ellnonsingularmultiple(E, P); P = gel(S,1); g = gel(S,2); v = v0 + 2*Z_pval(g, p); is2 = absequaliu(p,2); if (is2) v += 2; x = Q_remove_denom(gel(P,1), &b); x = mkvec2(x, b? b: gen_1); vd = Z_pval(gel(x,2), p); if (!vd) { /* P not in kernel of reduction mod p */ GEN d, m, X, Pp, Ep = ellinit(E, mkintmod(gen_0,p), 0); long w = v+2; Pp = RgV_to_FpV(P, p); if (lg(Ep) != 1) m = ellorder(Ep, Pp, NULL); else { /* E has bad reduction at p */ m = ellcard(E, p); if (equalii(m, p)) pari_err_TYPE("ellpadicheight: additive reduction", E); } g = mulii(g,m); for(;;) { N = powiu(p, w); X = xmP(E, x, m, N); d = gel(X,2); if (!signe(d)) w <<= 1; else { vd = Z_pval(d, p); if (w >= v+2*vd + is2) break; w = v+2*vd + is2; } } x = X; } /* we will want t mod p^(v+vd) because of t/D in H later, and * we lose p^vd in tfromx because of sqrt(d) (p^(vd+1) if p=2)*/ v += 2*vd + is2; N = powiu(p,v); t = tfromx(E, x, p, v, N, &D); /* D^2=denom(x)=x[2] */ S = ellformallogsigma_t(E, logsigma_prec(p, v-vd, valp(t)) + 1); ls = ser2rfrac_i(gel(S,1)); /* log_p (sigma(T)/T) */ lt = ser2rfrac_i(gel(S,2)); /* log_E (T) */ /* evaluate our formal power series at t */ H = gadd(poleval(ls, t), glog(gdiv(t, D), 0)); h = gsqr(poleval(lt, t)); g = sqri(g); a = gdiv(gmulgs(H,-2), g); b = gdiv(gneg(h), g); if (E != e) { GEN u = gel(ch,1), r = gel(ch,2); a = gdiv(gadd(a, gmul(r,b)), u); b = gmul(u,b); } H = mkvec2(a,b); gel(H,1) = precp_fix(gel(H,1),v0); gel(H,2) = precp_fix(gel(H,2),v0); return gerepilecopy(av, H); } GEN ellpadiclog(GEN E, GEN p, long n, GEN P) { pari_sp av = avma; long vt; GEN t, x, y, L; checkellpt(P); if (ell_is_inf(P)) return gen_0; x = gel(P,1); y = gel(P,2); t = gneg(gdiv(x,y)); vt = gvaluation(t, p); /* can be a t_INT, t_FRAC or t_PADIC */ if (vt <= 0) pari_err_DOMAIN("ellpadiclog","P","not in the kernel of reduction at",p,P); L = ser2rfrac_i(ellformallog(E, log_prec(p, n, vt) + 1, 0)); return gerepileupto(av, poleval(L, cvtop(t, p, n))); } /* E/Qp has multiplicative reduction, Tate curve */ static GEN ellpadics2_tate(GEN Ep, long n) { pari_sp av; GEN u2 = ellQp_u2(Ep, n), q = ellQp_q(Ep, n), pn = gel(q,3); GEN qm, s, b2 = ell_get_b2(Ep), v = vecfactoru_i(1, n); long m; qm = Fp_powers(padic_to_Fp(q, pn), n, pn); s = gel(qm, 2); av = avma; for (m = 2; m <= n; m++) /* sum sigma(m) q^m */ { s = addii(s, mulii(gel(qm,m+1), usumdiv_fact(gel(v,m)))); if ((m & 31) == 0) s = gerepileuptoint(av, s); } s = subui(1, muliu(s,24)); s = gdivgs(gsub(b2, gdiv(s,u2)), 12); return precp_fix(s,n); } GEN ellpadicfrobenius(GEN E, ulong p, long n) { checkell(E); if (p < 2) pari_err_DOMAIN("ellpadicfrobenius","p", "<", gen_2, utoi(p)); switch(ell_get_type(E)) { case t_ELL_Q: break; case t_ELL_Qp: if (equaliu(ellQp_get_p(E), p)) break; default: pari_err_TYPE("ellpadicfrobenius",utoi(p)); } return hyperellpadicfrobenius(ec_bmodel(E), p, n); } /* s2 = (b_2-E_2)/12 */ GEN ellpadics2(GEN E, GEN p, long n) { pari_sp av = avma; GEN l, F, a,b,d, ap; ulong pp; if (typ(p) != t_INT) pari_err_TYPE("ellpadics2",p); if (cmpis(p,2) < 0) pari_err_PRIME("ellpadics2",p); checkell(E); if (Q_pval(ell_get_j(E), p) < 0) { GEN Ep; if (ell_get_type(E) == t_ELL_Qp) Ep = E; else Ep = ellinit(E, zeropadic(p,n), 0); l = ellpadics2_tate(Ep, n); if (Ep != E) obj_free(Ep); return gerepilecopy(av, l); } pp = itou(p); F = ellpadicfrobenius(E, pp, n); a = gcoeff(F,1,1); b = gcoeff(F,1,2); d = gcoeff(F,2,2); ap = gadd(a,d); if (valp(ap) > 0) pari_err_DOMAIN("ellpadics2","E","is supersingular at",p,E); if (pp == 2 || (pp <= 13 && n == 1)) /* 2sqrt(p) > p/2: ambiguity */ ap = ellap(E,p); else { /* either 2sqrt(p) < p/2 or n > 1 and 2sqrt(p) < p^2/2 (since p!=2) */ GEN q = pp <= 13? utoipos(pp * pp): p; ap = padic_to_Fp(ap, q); ap = Fp_center_i(ap, q, shifti(q,-1)); } l = mspadic_unit_eigenvalue(ap, 2, p, n); return gerepileupto(av, gdiv(b, gsub(l, a))); /* slope of eigenvector */ } /* symbol and modular symbol space attached to E to later compute * ellpadicL(E,p,, s,,D) */ static GEN ellpadicL_symbol(GEN E, GEN p, GEN s, GEN D) { GEN s1, s2, ap; long sign; checkell(E); if (ell_get_type(E) != t_ELL_Q) pari_err_TYPE("ellpadicL",E); ap = ellap(E,p); if (D && typ(D) != t_INT) pari_err_TYPE("ellpadicL",D); if (D && !Z_isfundamental(D)) pari_err_DOMAIN("ellpadicL", "isfundamental(D)", "=", gen_0, D); if (!D) D = gen_1; if (Z_pval(ellQ_get_N(E), p) >= 2) pari_err_IMPL("additive reduction in ellpadicL"); mspadic_parse_chi(s, &s1,&s2); sign = signe(D); if (mpodd(s2)) sign = -sign; return shallowconcat(msfromell(E, sign), mkvec4(ap, p, s, D)); } /* W an ellpadicL_symbol, initialize for ellpadicL(E,p,n,s,,D) */ static GEN ellpadicL_init(GEN W, long n) { GEN Wp, den, M = gel(W,1), xpm = gel(W,2), ap = gel(W,3), s = gel(W,5); long p = itos(gel(W,4)), D = itos(gel(W,6)); xpm = Q_remove_denom(xpm,&den); if (!den) den = gen_1; n += Z_lval(den,p); Wp = mspadicinit(M, p, n, Z_lval(ap,p)); return mkvec3(mspadicmoments(Wp,xpm,D), den, s); } /* v from ellpadicL_init, compute ellpadicL(E,p,n,s,r,D) */ static GEN ellpadic_i(GEN v, long r) { GEN oms = gel(v,1), den = gel(v,2), s = gel(v,3); return gdiv(mspadicL(oms,s,r), den); } GEN ellpadicL(GEN E, GEN p, long n, GEN s, long r, GEN D) { pari_sp av = avma; GEN W, v; if (r < 0) pari_err_DOMAIN("ellpadicL","r","<",gen_0,stoi(r)); if (n <= 0) pari_err_DOMAIN("ellpadicL","precision","<=",gen_0,stoi(n)); W = ellpadicL_symbol(E, p, s, D); v = ellpadicL_init(W, n); return gerepileupto(av, ellpadic_i(v, r)); } static long torsion_order(GEN E) { GEN T = elltors(E); return itos(gel(T,1)); } /* E given by a minimal model; D != 0. Compare Euler factor of L(E,(D/.),1) * with L(E^D,1). Return * \prod_{p|D} (p-a_p(E)+eps_{E}(p)) / p, * where eps(p) = 0 if p | N_E and 1 otherwise */ static GEN get_Euler(GEN E, GEN D) { GEN a = gen_1, b = gen_1, P = gel(absZ_factor(D), 1); long i, l = lg(P); for (i = 1; i < l; i++) { GEN p = gel(P,i); a = mulii(a, ellcard(E, p)); b = mulii(b, p); } return Qdivii(a, b); } GEN ellpadicbsd(GEN E, GEN p, long n, GEN D) { const long MAXR = 30; pari_sp av = avma; GEN W, ED, tam, ND, C, apD, U = NULL;/*-Wall*/ long r, vN; checkell(E); if (D && isint1(D)) D = NULL; W = ellpadicL_symbol(E, p, gen_0, D); ED = D? ellinit(elltwist(E,D), gen_1, 0): E; ED = ellanal_globalred_all(ED, NULL, &ND, &tam); vN = Z_pval(ND, p); /* additive reduction ? */ if (vN >= 2) pari_err_DOMAIN("ellpadicbsd","v_p(N(E_D))",">",gen_1,stoi(vN)); if (n < 5) n = 5; for(;; n <<= 1) { GEN v = ellpadicL_init(W, n); for (r = 0; r < MAXR; r++) { U = ellpadic_i(v, r); if (!gequal0(U)) break; } if (r < MAXR) break; } apD = ellap(ED, p); if (typ(U) == t_COL) { /* p | a_p(E_D), frobenius on E_D */ GEN F = mkmat22(gen_0, negi(p), gen_1, apD); U = RgM_RgC_mul(gpowgs(gsubsg(1, gdiv(F,p)), -2), U); settyp(U, t_VEC); } else if (dvdii(ND,p)) { if (equalim1(apD)) /* divide by 1-1/a_p */ U = gdivgs(U, 2); else { /* ap = 1 */ GEN EDp = ellinit(ED, zeropadic(p,n), 0); U = gdiv(U, ellQp_L(EDp,n)); obj_free(EDp); } } else { GEN a = mspadic_unit_eigenvalue(apD, 2, p, n); U = gmul(U, gpowgs(gsubsg(1, ginv(a)), -2)); } C = mulii(tam, mpfact(r)); if (D) C = gmul(C, get_Euler(ED, D)); C = gdiv(sqru(torsion_order(ED)), C); if (D) obj_free(ED); return gerepilecopy(av, mkvec2(utoi(r), gmul(U, C))); } GEN ellpadicregulator(GEN E, GEN p, long n, GEN S) { pari_sp av = avma; GEN FG = ellpadicheightmatrix(E,p,n,S); /* forbids additive reduction */ /* [F,G]: height in basis [omega, eta] */ GEN R, F = gel(FG,1), G = gel(FG,2), ap = ellap(E,p); if (dvdii(ap, p)) { /* supersingular */ GEN f = ellpadicfrobenius(E, itou(p), n); GEN x = gcoeff(f,1,1), y = gcoeff(f,2,1); /* [A,B]: regulator height in basis [omega, eta] */ GEN A = det(F), B = det(gadd(F,G)), C; C = gdiv(gsub(B,A), y); /* R: regulator height in basis [omega, F.omega] */ R = mkvec2(gsub(A, gmul(x,C)), C); } else { GEN s2; if (equali1(ap) && dvdii(ell_get_disc(E),p)) { /* split multiplicative reduction */ GEN Ep = ellinit(E, zeropadic(p,n), 0); GEN q = ellQp_q(Ep,n), u2 = ellQp_u2(Ep,n); s2 = ellpadics2_tate(Ep, n); s2 = gsub(s2, ginv(gmul(Qp_log(q), u2))); /*extended MW group contrib*/ obj_free(Ep); } else s2 = ellpadics2(E,p,n); R = det( RgM_sub(F, RgM_Rg_mul(G,s2)) ); } return gerepilecopy(av, R); } pari-2.11.2/src/basemath/RgX.c0000644000175000017500000022132513447371554014417 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* GENERIC */ /* */ /*******************************************************************/ /* Return optimal parameter l for the evaluation of n/m polynomials of degree d Fractional values can be used if the evaluations are done with different accuracies, and thus have different weights. */ long brent_kung_optpow(long d, long n, long m) { long p, r; long pold=1, rold=n*(d-1); for(p=2; p<=d; p++) { r = m*(p-1) + n*((d-1)/p); if (rone(E)); if (!z) z = gen_0; for (i=1; i<=n; i++) { GEN t = cmul(E,P,a+i,gel(V,i+1)); if (t) { z = ff->add(E, z, t); if (gc_needed(av,2)) z = gerepileupto(av, z); } } return ff->red(E,z); } /* Brent & Kung * (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978) * * V as output by FpXQ_powers(x,l,T,p). For optimal performance, l is as given * by brent_kung_optpow */ GEN gen_bkeval_powers(GEN P, long d, GEN V, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)) { pari_sp av = avma; long l = lg(V)-1; GEN z, u; if (d < 0) return ff->zero(E); if (d < l) return gerepileupto(av, gen_RgXQ_eval_powers(P,V,0,d,E,ff,cmul)); if (l<2) pari_err_DOMAIN("gen_RgX_bkeval_powers", "#powers", "<",gen_2,V); if (DEBUGLEVEL>=8) { long cnt = 1 + (d - l) / (l-1); err_printf("RgX_RgXQV_eval(%ld/%ld): %ld RgXQ_mul\n", d, l-1, cnt); } d -= l; z = gen_RgXQ_eval_powers(P,V,d+1,l-1,E,ff,cmul); while (d >= l-1) { d -= l-1; u = gen_RgXQ_eval_powers(P,V,d+1,l-2,E,ff,cmul); z = ff->add(E,u, ff->mul(E,z,gel(V,l))); if (gc_needed(av,2)) z = gerepileupto(av, z); } u = gen_RgXQ_eval_powers(P,V,0,d,E,ff,cmul); z = ff->add(E,u, ff->mul(E,z,gel(V,d+2))); return gerepileupto(av, ff->red(E,z)); } GEN gen_bkeval(GEN Q, long d, GEN x, int use_sqr, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)) { pari_sp av = avma; GEN z, V; long rtd; if (d < 0) return ff->zero(E); rtd = (long) sqrt((double)d); V = gen_powers(x,rtd,use_sqr,E,ff->sqr,ff->mul,ff->one); z = gen_bkeval_powers(Q, d, V, E, ff, cmul); return gerepileupto(av, z); } static GEN _gen_nored(void *E, GEN x) { (void)E; return x; } static GEN _gen_add(void *E, GEN x, GEN y) { (void)E; return gadd(x, y); } static GEN _gen_sub(void *E, GEN x, GEN y) { (void)E; return gsub(x, y); } static GEN _gen_mul(void *E, GEN x, GEN y) { (void)E; return gmul(x, y); } static GEN _gen_sqr(void *E, GEN x) { (void)E; return gsqr(x); } static GEN _gen_one(void *E) { (void)E; return gen_1; } static GEN _gen_zero(void *E) { (void)E; return gen_0; } static struct bb_algebra Rg_algebra = { _gen_nored, _gen_add, _gen_sub, _gen_mul, _gen_sqr,_gen_one,_gen_zero }; static GEN _gen_cmul(void *E, GEN P, long a, GEN x) {(void)E; return gmul(gel(P,a+2), x);} GEN RgX_RgV_eval(GEN Q, GEN x) { return gen_bkeval_powers(Q, degpol(Q), x, NULL, &Rg_algebra, _gen_cmul); } GEN RgX_Rg_eval_bk(GEN Q, GEN x) { return gen_bkeval(Q, degpol(Q), x, 1, NULL, &Rg_algebra, _gen_cmul); } GEN RgXV_RgV_eval(GEN Q, GEN x) { long i, l = lg(Q), vQ = gvar(Q); GEN v = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN Qi = gel(Q, i); gel(v, i) = typ(Qi)==t_POL && varn(Qi)==vQ? RgX_RgV_eval(Qi, x): gcopy(Qi); } return v; } const struct bb_algebra * get_Rg_algebra(void) { return &Rg_algebra; } static struct bb_ring Rg_ring = { _gen_add, _gen_mul, _gen_sqr }; static GEN _RgX_divrem(void *E, GEN x, GEN y, GEN *r) { (void) E; return RgX_divrem(x, y, r); } GEN RgX_digits(GEN x, GEN T) { pari_sp av = avma; long d = degpol(T), n = (lgpol(x)+d-1)/d; GEN z = gen_digits(x,T,n,NULL, &Rg_ring, _RgX_divrem); return gerepileupto(av, z); } /*******************************************************************/ /* */ /* RgX */ /* */ /*******************************************************************/ long RgX_equal(GEN x, GEN y) { long i = lg(x); if (i != lg(y)) return 0; for (i--; i > 1; i--) if (!gequal(gel(x,i),gel(y,i))) return 0; return 1; } /* Returns 1 in the base ring over which x is defined */ /* HACK: this also works for t_SER */ GEN Rg_get_1(GEN x) { GEN p, T; long i, lx, tx = Rg_type(x, &p, &T, &lx); if (RgX_type_is_composite(tx)) RgX_type_decode(tx, &i /*junk*/, &tx); switch(tx) { case t_INTMOD: retmkintmod(is_pm1(p)? gen_0: gen_1, icopy(p)); case t_PADIC: return cvtop(gen_1, p, lx); case t_FFELT: return FF_1(T); default: return gen_1; } } /* Returns 0 in the base ring over which x is defined */ /* HACK: this also works for t_SER */ GEN Rg_get_0(GEN x) { GEN p, T; long i, lx, tx = Rg_type(x, &p, &T, &lx); if (RgX_type_is_composite(tx)) RgX_type_decode(tx, &i /*junk*/, &tx); switch(tx) { case t_INTMOD: retmkintmod(gen_0, icopy(p)); case t_PADIC: return cvtop(gen_0, p, lx); case t_FFELT: return FF_zero(T); default: return gen_0; } } GEN QX_ZXQV_eval(GEN P, GEN V, GEN dV) { long i, n = degpol(P); GEN z, dz, dP; if (n < 0) return gen_0; P = Q_remove_denom(P, &dP); z = gel(P,2); if (n == 0) return icopy(z); if (dV) z = mulii(dV, z); /* V[1] = dV */ z = ZX_Z_add_shallow(ZX_Z_mul(gel(V,2),gel(P,3)), z); for (i=2; i<=n; i++) z = ZX_add(ZX_Z_mul(gel(V,i+1),gel(P,2+i)), z); dz = mul_denom(dP, dV); return dz? RgX_Rg_div(z, dz): z; } /* Return P(h * x), not memory clean */ GEN RgX_unscale(GEN P, GEN h) { long i, l = lg(P); GEN hi = gen_1, Q = cgetg(l, t_POL); Q[1] = P[1]; if (l == 2) return Q; gel(Q,2) = gcopy(gel(P,2)); for (i=3; i=2; i--) { gel(Q,i) = gmul(gel(P,i), hi); if (i == 2) break; hi = gmul(hi,h); } Q[1] = P[1]; return Q; } /* A(X^d) --> A(X) */ GEN RgX_deflate(GEN x0, long d) { GEN z, y, x; long i,id, dy, dx = degpol(x0); if (d == 1 || dx <= 0) return leafcopy(x0); dy = dx/d; y = cgetg(dy+3, t_POL); y[1] = x0[1]; z = y + 2; x = x0+ 2; for (i=id=0; i<=dy; i++,id+=d) gel(z,i) = gel(x,id); return y; } /* return x0(X^d) */ GEN RgX_inflate(GEN x0, long d) { long i, id, dy, dx = degpol(x0); GEN x = x0 + 2, z, y; if (dx <= 0) return leafcopy(x0); dy = dx*d; y = cgetg(dy+3, t_POL); y[1] = x0[1]; z = y + 2; for (i=0; i<=dy; i++) gel(z,i) = gen_0; for (i=id=0; i<=dx; i++,id+=d) gel(z,id) = gel(x,i); return y; } /* return P(X + c) using destructive Horner, optimize for c = 1,-1 */ GEN RgX_translate(GEN P, GEN c) { pari_sp av = avma; GEN Q, *R; long i, k, n; if (!signe(P) || gequal0(c)) return RgX_copy(P); Q = leafcopy(P); R = (GEN*)(Q+2); n = degpol(P); if (equali1(c)) { for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"TR_POL(1), i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } } else if (equalim1(c)) { for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"TR_POL(-1), i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } } else { for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"TR_POL, i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } } return gerepilecopy(av, Q); } /* return P(X + c) using destructive Horner, optimize for c = 1,-1 */ GEN ZX_translate(GEN P, GEN c) { pari_sp av = avma; GEN Q, *R; long i, k, n; if (!signe(P) || !signe(c)) return ZX_copy(P); Q = leafcopy(P); R = (GEN*)(Q+2); n = degpol(P); if (equali1(c)) { for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"ZX_translate(1), i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } } else if (equalim1(c)) { for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"ZX_translate(-1), i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } } else { for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"ZX_translate, i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } } return gerepilecopy(av, Q); } /* return lift( P(X + c) ) using Horner, c in R[y]/(T) */ GEN RgXQX_translate(GEN P, GEN c, GEN T) { pari_sp av = avma; GEN Q, *R; long i, k, n; if (!signe(P) || gequal0(c)) return RgX_copy(P); Q = leafcopy(P); R = (GEN*)(Q+2); n = degpol(P); for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"RgXQX_translate, i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } return gerepilecopy(av, Q); } /********************************************************************/ /** **/ /** CONVERSIONS **/ /** (not memory clean) **/ /** **/ /********************************************************************/ /* to INT / FRAC / (POLMOD mod T), not memory clean because T not copied, * but everything else is */ static GEN QXQ_to_mod_copy(GEN x, GEN T) { long d; switch(typ(x)) { case t_INT: return icopy(x); case t_FRAC: return gcopy(x); case t_POL: d = degpol(x); if (d < 0) return gen_0; if (d == 0) return gcopy(gel(x,2)); return mkpolmod(RgX_copy(x), T); default: pari_err_TYPE("QXQ_to_mod",x); return NULL;/* LCOV_EXCL_LINE */ } } /* pure shallow version */ static GEN QXQ_to_mod(GEN x, GEN T) { long d; switch(typ(x)) { case t_INT: case t_FRAC: return x; case t_POL: d = degpol(x); if (d < 0) return gen_0; if (d == 0) return gel(x,2); return mkpolmod(x, T); default: pari_err_TYPE("QXQ_to_mod",x); return NULL;/* LCOV_EXCL_LINE */ } } /* T a ZX, z lifted from (Q[Y]/(T(Y)))[X], apply QXQ_to_mod_copy to all coeffs. * Not memory clean because T not copied, but everything else is */ static GEN QXQX_to_mod(GEN z, GEN T) { long i,l = lg(z); GEN x = cgetg(l,t_POL); for (i=2; i1; i--) if (! gequal0(gel(x,i))) break; /* _not_ isexactzero */ stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1)); setlg(x, i+1); setsigne(x, i != 1); return x; } GEN RgV_to_RgX(GEN x, long v) { long i, k = lg(x); GEN p; while (--k && gequal0(gel(x,k))); if (!k) return pol_0(v); i = k+2; p = cgetg(i,t_POL); p[1] = evalsigne(1) | evalvarn(v); x--; for (k=2; k N+1) l = N+1; /* truncate higher degree terms */ z = cgetg(N+1,t_COL); for (i=1; i P(Y,X), n is an upper bound for deg_Y(P) */ GEN RgXY_swapspec(GEN x, long n, long w, long nx) { long j, ly = n+3; GEN y = cgetg(ly, t_POL); y[1] = evalsigne(1); for (j=2; j P(Y,X), n is an upper bound for deg_Y(P) */ GEN RgXY_swap(GEN x, long n, long w) { GEN z = RgXY_swapspec(x+2, n, w, lgpol(x)); setvarn(z, varn(x)); return z; } long RgXY_degreex(GEN b) { long deg = -1, i; if (!signe(b)) return -1; for (i = 2; i < lg(b); ++i) { GEN bi = gel(b, i); if (typ(bi) == t_POL) deg = maxss(deg, degpol(bi)); } return deg; } /* return (x % X^n). Shallow */ GEN RgXn_red_shallow(GEN a, long n) { long i, L = n+2, l = lg(a); GEN b; if (L >= l) return a; /* deg(x) < n */ b = cgetg(L, t_POL); b[1] = a[1]; for (i=2; i= 0) return RgX_shift(x, d); d = -d; v = RgX_val(x); if (v >= d) return RgX_shift(x, -d); av = avma; z = gred_rfrac_simple(RgX_shift_shallow(x, -v), pol_xn(d - v, varn(x))); return gerepileupto(av, z); } long RgX_val(GEN x) { long i, lx = lg(x); if (lx == 2) return LONG_MAX; for (i = 2; i < lx; i++) if (!isexactzero(gel(x,i))) break; if (i == lx) return LONG_MAX;/* possible with non-rational zeros */ return i - 2; } long RgX_valrem(GEN x, GEN *Z) { long v, i, lx = lg(x); if (lx == 2) { *Z = pol_0(varn(x)); return LONG_MAX; } for (i = 2; i < lx; i++) if (!isexactzero(gel(x,i))) break; /* possible with non-rational zeros */ if (i == lx) { *Z = pol_0(varn(x)); return LONG_MAX; } v = i - 2; *Z = RgX_shift_shallow(x, -v); return v; } long RgX_valrem_inexact(GEN x, GEN *Z) { long v; if (!signe(x)) { if (Z) *Z = pol_0(varn(x)); return LONG_MAX; } for (v = 0;; v++) if (!gequal0(gel(x,2+v))) break; if (Z) *Z = RgX_shift_shallow(x, -v); return v; } GEN RgXQC_red(GEN x, GEN T) { pari_APPLY_type(t_COL, grem(gel(x,i), T)) } GEN RgXQV_red(GEN x, GEN T) { pari_APPLY_type(t_VEC, grem(gel(x,i), T)) } GEN RgXQM_red(GEN x, GEN T) { pari_APPLY_same(RgXQC_red(gel(x,i), T)) } GEN RgXQM_mul(GEN P, GEN Q, GEN T) { return RgXQM_red(RgM_mul(P, Q), T); } GEN RgXQX_red(GEN P, GEN T) { long i, l = lg(P); GEN Q = cgetg(l, t_POL); Q[1] = P[1]; for (i=2; i= ny > 0, return x * y * t^v */ static GEN RgX_mulspec_basecase(GEN x, GEN y, long nx, long ny, long v) { long i, lz, nz; GEN z; x = RgXspec_kill0(x,nx); y = RgXspec_kill0(y,ny); lz = nx + ny + 1; nz = lz-2; lz += v; z = cgetg(lz, t_POL) + 2; /* x:y:z [i] = term of degree i */ for (i=0; i 0 */ GEN RgX_addmulXn_shallow(GEN x0, GEN y0, long d) { GEN x, y, xd, yd, zd; long a, lz, nx, ny; if (!signe(x0)) return y0; ny = lgpol(y0); nx = lgpol(x0); zd = (GEN)avma; x = x0 + 2; y = y0 + 2; a = ny-d; if (a <= 0) { lz = nx+d+2; (void)new_chunk(lz); xd = x+nx; yd = y+ny; while (xd > x) gel(--zd,0) = gel(--xd,0); x = zd + a; while (zd > x) gel(--zd,0) = gen_0; } else { xd = new_chunk(d); yd = y+d; x = RgX_addspec_shallow(x,yd, nx,a); lz = (a>nx)? ny+2: lg(x)+d; x += 2; while (xd > x) *--zd = *--xd; } while (yd > y) *--zd = *--yd; *--zd = x0[1]; *--zd = evaltyp(t_POL) | evallg(lz); return zd; } GEN RgX_addmulXn(GEN x0, GEN y0, long d) { GEN x, y, xd, yd, zd; long a, lz, nx, ny; if (!signe(x0)) return RgX_copy(y0); nx = lgpol(x0); ny = lgpol(y0); zd = (GEN)avma; x = x0 + 2; y = y0 + 2; a = ny-d; if (a <= 0) { lz = nx+d+2; (void)new_chunk(lz); xd = x+nx; yd = y+ny; while (xd > x) gel(--zd,0) = gcopy(gel(--xd,0)); x = zd + a; while (zd > x) gel(--zd,0) = gen_0; } else { xd = new_chunk(d); yd = y+d; x = RgX_addspec(x,yd, nx,a); lz = (a>nx)? ny+2: lg(x)+d; x += 2; while (xd > x) *--zd = *--xd; } while (yd > y) gel(--zd,0) = gcopy(gel(--yd,0)); *--zd = x0[1]; *--zd = evaltyp(t_POL) | evallg(lz); return zd; } /* return x * y mod t^n */ static GEN RgXn_mul_basecase(GEN x, GEN y, long n) { long i, lz = n+2, lx = lgpol(x), ly = lgpol(y); GEN z; if (lx < 0) return pol_0(varn(x)); if (ly < 0) return pol_0(varn(x)); z = cgetg(lz, t_POL) + 2; x+=2; if (lx > n) lx = n; y+=2; if (ly > n) ly = n; z[-1] = x[-1]; if (ly > lx) { swap(x,y); lswap(lx,ly); } x = RgXspec_kill0(x, lx); y = RgXspec_kill0(y, ly); /* x:y:z [i] = term of degree i */ for (i=0;i>1; n1 = n-n0; RgX_even_odd(f, &fe, &fo); RgX_even_odd(g, &ge, &go); l = RgXn_mul(fe,ge,n1); h = RgXn_mul(fo,go,n0); m = RgX_sub(RgXn_mul(RgX_add(fe,fo),RgX_add(ge,go),n0), RgX_add(l,h)); /* n1-1 <= n0 <= n1, deg l,m <= n1-1, deg h <= n0-1 * result is t^2 h(t^2) + t m(t^2) + l(t^2) */ l = RgX_inflate(l,2); /* deg l <= 2n1 - 2 <= n-1 */ /* deg(t m(t^2)) <= 2n1 - 1 <= n, truncate to < n */ if (2*degpol(m)+1 == n) m = normalizepol_lg(m, lg(m)-1); m = RgX_inflate(m,2); /* deg(t^2 h(t^2)) <= 2n0 <= n, truncate to < n */ if (2*degpol(h)+2 == n) h = normalizepol_lg(h, lg(h)-1); h = RgX_inflate(h,2); h = RgX_addmulXn(RgX_addmulXn_shallow(h,m,1), l,1); return gerepileupto(av, h); } /* (f*g) \/ x^n */ static GEN RgX_mulhigh_i2(GEN f, GEN g, long n) { long d = degpol(f)+degpol(g) + 1 - n; GEN h; if (d <= 2) return RgX_shift_shallow(RgX_mul(f,g), -n); h = RgX_recip_shallow(RgXn_mul(RgX_recip_shallow(f), RgX_recip_shallow(g), d)); return RgX_shift_shallow(h, d-1-degpol(h)); /* possibly (fg)(0) = 0 */ } /* (f*g) \/ x^n */ static GEN RgX_sqrhigh_i2(GEN f, long n) { long d = 2*degpol(f)+ 1 - n; GEN h; if (d <= 2) return RgX_shift_shallow(RgX_sqr(f), -n); h = RgX_recip_shallow(RgXn_sqr(RgX_recip_shallow(f), d)); return RgX_shift_shallow(h, d-1-degpol(h)); /* possibly (fg)(0) = 0 */ } /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2, * b+2 were sent instead. na, nb = number of terms of a, b. * Only c, c0, c1, c2 are genuine GEN. */ GEN RgX_mulspec(GEN a, GEN b, long na, long nb) { GEN a0, c, c0; long n0, n0a, i, v = 0; pari_sp av; while (na && isrationalzero(gel(a,0))) { a++; na--; v++; } while (nb && isrationalzero(gel(b,0))) { b++; nb--; v++; } if (na < nb) swapspec(a,b, na,nb); if (!nb) return pol_0(0); if (nb < RgX_MUL_LIMIT) return RgX_mulspec_basecase(a,b,na,nb, v); RgX_shift_inplace_init(v); i = (na>>1); n0 = na-i; na = i; av = avma; a0 = a+n0; n0a = n0; while (n0a && isrationalzero(gel(a,n0a-1))) n0a--; if (nb > n0) { GEN b0,c1,c2; long n0b; nb -= n0; b0 = b+n0; n0b = n0; while (n0b && isrationalzero(gel(b,n0b-1))) n0b--; c = RgX_mulspec(a,b,n0a,n0b); c0 = RgX_mulspec(a0,b0, na,nb); c2 = RgX_addspec_shallow(a0,a, na,n0a); c1 = RgX_addspec_shallow(b0,b, nb,n0b); c1 = RgX_mulspec(c1+2,c2+2, lgpol(c1),lgpol(c2)); c2 = RgX_sub(c1, RgX_add(c0,c)); c0 = RgX_addmulXn_shallow(c0, c2, n0); } else { c = RgX_mulspec(a,b,n0a,nb); c0 = RgX_mulspec(a0,b,na,nb); } c0 = RgX_addmulXn(c0,c,n0); return RgX_shift_inplace(gerepileupto(av,c0), v); } INLINE GEN RgX_sqrspec_basecase_limb(GEN x, long a, long i) { pari_sp av = avma; GEN s = NULL; long j, l = (i+1)>>1; for (j=a; j>1); if (t) { t = gsqr(t); s = s? gadd(s, t): t; } } return s? gerepileupto(av,s): gen_0; } static GEN RgX_sqrspec_basecase(GEN x, long nx, long v) { long i, lz, nz; GEN z; if (!nx) return pol_0(0); x = RgXspec_kill0(x,nx); lz = (nx << 1) + 1, nz = lz-2; lz += v; z = cgetg(lz,t_POL) + 2; for (i=0; i n) lx = n; x = RgXspec_kill0(x,lx); z+=2;/* x:z [i] = term of degree i */ for (i=0;i>1; n1 = n-n0; RgX_even_odd(f, &fe, &fo); l = RgXn_sqr(fe,n1); h = RgXn_sqr(fo,n0); m = RgX_sub(RgXn_sqr(RgX_add(fe,fo),n0), RgX_add(l,h)); /* n1-1 <= n0 <= n1, deg l,m <= n1-1, deg h <= n0-1 * result is t^2 h(t^2) + t m(t^2) + l(t^2) */ l = RgX_inflate(l,2); /* deg l <= 2n1 - 2 <= n-1 */ /* deg(t m(t^2)) <= 2n1 - 1 <= n, truncate to < n */ if (2*degpol(m)+1 == n) m = normalizepol_lg(m, lg(m)-1); m = RgX_inflate(m,2); /* deg(t^2 h(t^2)) <= 2n0 <= n, truncate to < n */ if (2*degpol(h)+2 == n) h = normalizepol_lg(h, lg(h)-1); h = RgX_inflate(h,2); h = RgX_addmulXn(RgX_addmulXn_shallow(h,m,1), l,1); return gerepileupto(av, h); } GEN RgX_sqrspec(GEN a, long na) { GEN a0, c, c0, c1; long n0, n0a, i, v = 0; pari_sp av; while (na && isrationalzero(gel(a,0))) { a++; na--; v += 2; } if (na>1); n0 = na-i; na = i; av = avma; a0 = a+n0; n0a = n0; while (n0a && isrationalzero(gel(a,n0a-1))) n0a--; c = RgX_sqrspec(a,n0a); c0 = RgX_sqrspec(a0,na); c1 = gmul2n(RgX_mulspec(a0,a, na,n0a), 1); c0 = RgX_addmulXn_shallow(c0,c1, n0); c0 = RgX_addmulXn(c0,c,n0); return RgX_shift_inplace(gerepileupto(av,c0), v); } /* (X^a + A)(X^b + B) - X^(a+b), where deg A < a, deg B < b */ GEN RgX_mul_normalized(GEN A, long a, GEN B, long b) { GEN z = RgX_mul(A, B); if (a < b) z = RgX_addmulXn_shallow(RgX_addmulXn_shallow(A, B, b-a), z, a); else if (a > b) z = RgX_addmulXn_shallow(RgX_addmulXn_shallow(B, A, a-b), z, b); else z = RgX_addmulXn_shallow(RgX_add(A, B), z, a); return z; } GEN RgX_mul_i(GEN x, GEN y) { GEN z = RgX_mulspec(x+2, y+2, lgpol(x), lgpol(y)); setvarn(z, varn(x)); return z; } GEN RgX_sqr_i(GEN x) { GEN z = RgX_sqrspec(x+2, lgpol(x)); setvarn(z,varn(x)); return z; } /*******************************************************************/ /* */ /* DIVISION */ /* */ /*******************************************************************/ GEN RgX_Rg_divexact(GEN x, GEN y) { long i, lx; GEN z; if (typ(y) == t_INT && is_pm1(y)) return signe(y) < 0 ? RgX_neg(x): RgX_copy(x); z = cgetg_copy(x, &lx); z[1] = x[1]; for (i=2; i 1; i--) { d = gel(x,i); if (!gequal0(d)) break; } if (i == 1) return pol_0(varn(x)); if (i == n && isint1(d)) return x; n = i; z = cgetg(n+1, t_POL); z[1] = x[1]; for (i=2; i1; i--) /* z[i] = a[i+1] + x*z[i+1] */ { GEN t = gadd(gel(a0--,0), gmul(x, gel(z0--,0))); gel(z0,0) = t; } if (r) *r = gadd(gel(a0,0), gmul(x, gel(z0,0))); return z; } /* Polynomial division x / y: * if pr = ONLY_REM return remainder, otherwise return quotient * if pr = ONLY_DIVIDES return quotient if division is exact, else NULL * if pr != NULL set *pr to remainder, as the last object on stack */ /* assume, typ(x) = typ(y) = t_POL, same variable */ static GEN RgX_divrem_i(GEN x, GEN y, GEN *pr) { pari_sp avy, av, av1; long dx,dy,dz,i,j,sx,lr; GEN z,p1,p2,rem,y_lead,mod,p; GEN (*f)(GEN,GEN); if (!signe(y)) pari_err_INV("RgX_divrem",y); dy = degpol(y); y_lead = gel(y,dy+2); if (gequal0(y_lead)) /* normalize denominator if leading term is 0 */ { pari_warn(warner,"normalizing a polynomial with 0 leading term"); for (dy--; dy>=0; dy--) { y_lead = gel(y,dy+2); if (!gequal0(y_lead)) break; } } if (!dy) /* y is constant */ { if (pr == ONLY_REM) return pol_0(varn(x)); z = RgX_Rg_div(x, y_lead); if (pr == ONLY_DIVIDES) return z; if (pr) *pr = pol_0(varn(x)); return z; } dx = degpol(x); if (dx < dy) { if (pr == ONLY_REM) return RgX_copy(x); if (pr == ONLY_DIVIDES) return signe(x)? NULL: pol_0(varn(x)); z = pol_0(varn(x)); if (pr) *pr = RgX_copy(x); return z; } /* x,y in R[X], y non constant */ av = avma; p = NULL; if (RgX_is_FpX(x, &p) && RgX_is_FpX(y, &p) && p) { z = FpX_divrem(RgX_to_FpX(x, p), RgX_to_FpX(y, p), p, pr); if (!z) { avma = av; return NULL; } z = FpX_to_mod(z, p); if (!pr || pr == ONLY_REM || pr == ONLY_DIVIDES) return gerepileupto(av, z); *pr = FpX_to_mod(*pr, p); gerepileall(av, 2, pr, &z); return z; } switch(typ(y_lead)) { case t_REAL: y_lead = ginv(y_lead); f = gmul; mod = NULL; break; case t_INTMOD: case t_POLMOD: y_lead = ginv(y_lead); f = gmul; mod = gmodulo(gen_1, gel(y_lead,1)); break; default: if (gequal1(y_lead)) y_lead = NULL; f = gdiv; mod = NULL; } if (y_lead == NULL) p2 = gel(x,dx+2); else { for(;;) { p2 = f(gel(x,dx+2),y_lead); p2 = simplify_shallow(p2); if (!isexactzero(p2) || (--dx < 0)) break; } if (dx < dy) /* leading coeff of x was in fact zero */ { if (pr == ONLY_DIVIDES) { avma = av; return (dx < 0)? pol_0(varn(x)) : NULL; } if (pr == ONLY_REM) { if (dx < 0) return gerepilecopy(av, scalarpol(p2, varn(x))); else { GEN t; avma = av; t = cgetg(dx + 3, t_POL); t[1] = x[1]; for (i = 2; i < dx + 3; i++) gel(t,i) = gcopy(gel(x,i)); return t; } } if (pr) /* cf ONLY_REM above */ { if (dx < 0) { p2 = gclone(p2); avma = av; z = pol_0(varn(x)); x = scalarpol(p2, varn(x)); gunclone(p2); } else { GEN t; avma = av; z = pol_0(varn(x)); t = cgetg(dx + 3, t_POL); t[1] = x[1]; for (i = 2; i < dx + 3; i++) gel(t,i) = gcopy(gel(x,i)); x = t; } *pr = x; } else { avma = av; z = pol_0(varn(x)); } return z; } } /* dx >= dy */ avy = avma; dz = dx-dy; z = cgetg(dz+3,t_POL); z[1] = x[1]; x += 2; z += 2; y += 2; gel(z,dz) = gcopy(p2); for (i=dx-1; i>=dy; i--) { av1=avma; p1=gel(x,i); for (j=i-dy+1; j<=i && j<=dz; j++) p1 = gsub(p1, gmul(gel(z,j),gel(y,i-j))); if (y_lead) p1 = simplify(f(p1,y_lead)); if (isrationalzero(p1)) { avma=av1; p1 = gen_0; } else p1 = avma==av1? gcopy(p1): gerepileupto(av1,p1); gel(z,i-dy) = p1; } if (!pr) return gerepileupto(av,z-2); rem = (GEN)avma; av1 = (pari_sp)new_chunk(dx+3); for (sx=0; ; i--) { p1 = gel(x,i); /* we always enter this loop at least once */ for (j=0; j<=i && j<=dz; j++) p1 = gsub(p1, gmul(gel(z,j),gel(y,i-j))); if (mod && avma==av1) p1 = gmul(p1,mod); if (!gequal0(p1)) { sx = 1; break; } /* remainder is non-zero */ if (!isexactzero(p1)) break; if (!i) break; avma=av1; } if (pr == ONLY_DIVIDES) { if (sx) { avma=av; return NULL; } avma = (pari_sp)rem; return gerepileupto(av,z-2); } lr=i+3; rem -= lr; if (avma==av1) { avma = (pari_sp)rem; p1 = gcopy(p1); } else p1 = gerepileupto((pari_sp)rem,p1); rem[0] = evaltyp(t_POL) | evallg(lr); rem[1] = z[-1]; rem += 2; gel(rem,i) = p1; for (i--; i>=0; i--) { av1=avma; p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = gsub(p1, gmul(gel(z,j),gel(y,i-j))); if (mod && avma==av1) p1 = gmul(p1,mod); gel(rem,i) = avma==av1? gcopy(p1):gerepileupto(av1,p1); } rem -= 2; if (!sx) (void)normalizepol_lg(rem, lr); if (pr == ONLY_REM) return gerepileupto(av,rem); z -= 2; { GEN *gptr[2]; gptr[0]=&z; gptr[1]=&rem; gerepilemanysp(av,avy,gptr,2); *pr = rem; return z; } } GEN RgX_divrem(GEN x, GEN y, GEN *pr) { if (pr == ONLY_REM) return RgX_rem(x, y); return RgX_divrem_i(x, y, pr); } /* x and y in (R[Y]/T)[X] (lifted), T in R[Y]. y preferably monic */ GEN RgXQX_divrem(GEN x, GEN y, GEN T, GEN *pr) { long vx, dx, dy, dz, i, j, sx, lr; pari_sp av0, av, tetpil; GEN z,p1,rem,lead; if (!signe(y)) pari_err_INV("RgXQX_divrem",y); vx = varn(x); dx = degpol(x); dy = degpol(y); if (dx < dy) { if (pr) { av0 = avma; x = RgXQX_red(x, T); if (pr == ONLY_DIVIDES) { avma=av0; return signe(x)? NULL: gen_0; } if (pr == ONLY_REM) return x; *pr = x; } return pol_0(vx); } lead = leading_coeff(y); if (!dy) /* y is constant */ { if (pr && pr != ONLY_DIVIDES) { if (pr == ONLY_REM) return pol_0(vx); *pr = pol_0(vx); } if (gequal1(lead)) return RgX_copy(x); av0 = avma; x = gmul(x, ginvmod(lead,T)); tetpil = avma; return gerepile(av0,tetpil,RgXQX_red(x,T)); } av0 = avma; dz = dx-dy; lead = gequal1(lead)? NULL: gclone(ginvmod(lead,T)); avma = av0; z = cgetg(dz+3,t_POL); z[1] = x[1]; x += 2; y += 2; z += 2; p1 = gel(x,dx); av = avma; gel(z,dz) = lead? gerepileupto(av, grem(gmul(p1,lead), T)): gcopy(p1); for (i=dx-1; i>=dy; i--) { av=avma; p1=gel(x,i); for (j=i-dy+1; j<=i && j<=dz; j++) p1 = gsub(p1, gmul(gel(z,j),gel(y,i-j))); if (lead) p1 = gmul(grem(p1, T), lead); tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil, grem(p1, T)); } if (!pr) { if (lead) gunclone(lead); return z-2; } rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3); for (sx=0; ; i--) { p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = gsub(p1, gmul(gel(z,j),gel(y,i-j))); tetpil=avma; p1 = grem(p1, T); if (!gequal0(p1)) { sx = 1; break; } if (!i) break; avma=av; } if (pr == ONLY_DIVIDES) { if (lead) gunclone(lead); if (sx) { avma=av0; return NULL; } avma = (pari_sp)rem; return z-2; } lr=i+3; rem -= lr; rem[0] = evaltyp(t_POL) | evallg(lr); rem[1] = z[-1]; p1 = gerepile((pari_sp)rem,tetpil,p1); rem += 2; gel(rem,i) = p1; for (i--; i>=0; i--) { av=avma; p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = gsub(p1, gmul(gel(z,j),gel(y,i-j))); tetpil=avma; gel(rem,i) = gerepile(av,tetpil, grem(p1, T)); } rem -= 2; if (lead) gunclone(lead); if (!sx) (void)normalizepol_lg(rem, lr); if (pr == ONLY_REM) return gerepileupto(av0,rem); *pr = rem; return z-2; } /*******************************************************************/ /* */ /* PSEUDO-DIVISION */ /* */ /*******************************************************************/ INLINE GEN rem(GEN c, GEN T) { if (T && typ(c) == t_POL && varn(c) == varn(T)) c = RgX_rem(c, T); return c; } /* x, y, are ZYX, lc(y) is an integer, T is a ZY */ int ZXQX_dvd(GEN x, GEN y, GEN T) { long dx, dy, dz, i, p, T_ismonic; pari_sp av = avma, av2; GEN y_lead; if (!signe(y)) pari_err_INV("ZXQX_dvd",y); dy = degpol(y); y_lead = gel(y,dy+2); if (typ(y_lead) == t_POL) y_lead = gel(y_lead, 2); /* t_INT */ /* if monic, no point in using pseudo-division */ if (gequal1(y_lead)) return signe(RgXQX_rem(x, y, T)) == 0; T_ismonic = gequal1(leading_coeff(T)); dx = degpol(x); if (dx < dy) return !signe(x); (void)new_chunk(2); x = RgX_recip_shallow(x)+2; y = RgX_recip_shallow(y)+2; /* pay attention to sparse divisors */ for (i = 1; i <= dy; i++) if (!signe(gel(y,i))) gel(y,i) = NULL; dz = dx-dy; p = dz+1; av2 = avma; for (;;) { GEN m, x0 = gel(x,0), y0 = y_lead, cx = content(x0); x0 = gneg(x0); p--; m = gcdii(cx, y0); if (!equali1(m)) { x0 = gdiv(x0, m); y0 = diviiexact(y0, m); if (equali1(y0)) y0 = NULL; } for (i=1; i<=dy; i++) { GEN c = gel(x,i); if (y0) c = gmul(y0, c); if (gel(y,i)) c = gadd(c, gmul(x0,gel(y,i))); if (typ(c) == t_POL) c = T_ismonic ? ZX_rem(c, T): RgX_rem(c, T); gel(x,i) = c; } for ( ; i<=dx; i++) { GEN c = gel(x,i); if (y0) c = gmul(y0, c); if (typ(c) == t_POL) c = T_ismonic ? ZX_rem(c, T): RgX_rem(c, T); gel(x,i) = c; } do { x++; dx--; } while (dx >= 0 && !signe(gel(x,0))); if (dx < dy) break; if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZXQX_dvd dx = %ld >= %ld",dx,dy); gerepilecoeffs(av2,x,dx+1); } } avma = av; return (dx < 0); } /* T either NULL or a t_POL. */ GEN RgXQX_pseudorem(GEN x, GEN y, GEN T) { long vx = varn(x), dx, dy, dz, i, lx, p; pari_sp av = avma, av2; GEN y_lead; if (!signe(y)) pari_err_INV("RgXQX_pseudorem",y); dy = degpol(y); y_lead = gel(y,dy+2); /* if monic, no point in using pseudo-division */ if (gequal1(y_lead)) return T? RgXQX_rem(x, y, T): RgX_rem(x, y); dx = degpol(x); if (dx < dy) return RgX_copy(x); (void)new_chunk(2); x = RgX_recip_shallow(x)+2; y = RgX_recip_shallow(y)+2; /* pay attention to sparse divisors */ for (i = 1; i <= dy; i++) if (isexactzero(gel(y,i))) gel(y,i) = NULL; dz = dx-dy; p = dz+1; av2 = avma; for (;;) { gel(x,0) = gneg(gel(x,0)); p--; for (i=1; i<=dy; i++) { GEN c = gmul(y_lead, gel(x,i)); if (gel(y,i)) c = gadd(c, gmul(gel(x,0),gel(y,i))); gel(x,i) = rem(c, T); } for ( ; i<=dx; i++) { GEN c = gmul(y_lead, gel(x,i)); gel(x,i) = rem(c, T); } do { x++; dx--; } while (dx >= 0 && gequal0(gel(x,0))); if (dx < dy) break; if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgX_pseudorem dx = %ld >= %ld",dx,dy); gerepilecoeffs(av2,x,dx+1); } } if (dx < 0) return pol_0(vx); lx = dx+3; x -= 2; x[0] = evaltyp(t_POL) | evallg(lx); x[1] = evalsigne(1) | evalvarn(vx); x = RgX_recip_shallow(x); if (p) { /* multiply by y[0]^p [beware dummy vars from FpX_FpXY_resultant] */ GEN t = y_lead; if (T && typ(t) == t_POL && varn(t) == varn(T)) t = RgXQ_powu(t, p, T); else t = gpowgs(t, p); for (i=2; i= dy && gequal0(gel(x,0))) { x++; dx--; iz++; } if (dx < dy) break; if (gc_needed(av2,1)) { GEN X = x-2; if(DEBUGMEM>1) pari_warn(warnmem,"RgX_pseudodivrem dx=%ld >= %ld",dx,dy); X[0] = evaltyp(t_POL)|evallg(dx+3); X[1] = z[1]; /* hack */ gerepileall(av2,2, &X, &z); x = X+2; } } while (dx >= 0 && gequal0(gel(x,0))) { x++; dx--; } if (dx < 0) x = pol_0(vx); else { lx = dx+3; x -= 2; x[0] = evaltyp(t_POL) | evallg(lx); x[1] = evalsigne(1) | evalvarn(vx); x = RgX_recip_shallow(x); } z = RgX_recip_shallow(z); r = x; if (p) { GEN c = gel(ypow,p); r = RgX_Rg_mul(r, c); if (T && typ(c) == t_POL && varn(c) == varn(T)) r = RgXQX_red(r, T); } gerepileall(av, 2, &z, &r); *ptr = r; return z; } GEN RgX_pseudodivrem(GEN x, GEN y, GEN *ptr) { return RgXQX_pseudodivrem(x,y,NULL,ptr); } GEN RgXQX_mul(GEN x, GEN y, GEN T) { return RgXQX_red(RgX_mul(x,y), T); } GEN RgX_Rg_mul(GEN y, GEN x) { long i, ly; GEN z = cgetg_copy(y, &ly); z[1] = y[1]; if (ly == 2) return z; for (i = 2; i < ly; i++) gel(z,i) = gmul(x,gel(y,i)); return normalizepol_lg(z,ly); } GEN RgX_muls(GEN y, long x) { long i, ly; GEN z = cgetg_copy(y, &ly); z[1] = y[1]; if (ly == 2) return z; for (i = 2; i < ly; i++) gel(z,i) = gmulsg(x,gel(y,i)); return normalizepol_lg(z,ly); } GEN RgXQX_RgXQ_mul(GEN x, GEN y, GEN T) { return RgXQX_red(RgX_Rg_mul(x,y), T); } GEN RgXQV_RgXQ_mul(GEN v, GEN x, GEN T) { return RgXQV_red(RgV_Rg_mul(v,x), T); } GEN RgXQX_sqr(GEN x, GEN T) { return RgXQX_red(RgX_sqr(x), T); } GEN RgXQX_powers(GEN P, long n, GEN T) { GEN v = cgetg(n+2, t_VEC); long i; gel(v, 1) = pol_1(varn(T)); if (n==0) return v; gel(v, 2) = gcopy(P); for (i = 2; i <= n; i++) gel(v,i+1) = RgXQX_mul(P, gel(v,i), T); return v; } static GEN _add(void *data, GEN x, GEN y) { (void)data; return RgX_add(x, y); } static GEN _sub(void *data, GEN x, GEN y) { (void)data; return RgX_sub(x, y); } static GEN _sqr(void *data, GEN x) { return RgXQ_sqr(x, (GEN)data); } static GEN _mul(void *data, GEN x, GEN y) { return RgXQ_mul(x,y, (GEN)data); } static GEN _cmul(void *data, GEN P, long a, GEN x) { (void)data; return RgX_Rg_mul(x,gel(P,a+2)); } static GEN _one(void *data) { return pol_1(varn((GEN)data)); } static GEN _zero(void *data) { return pol_0(varn((GEN)data)); } static GEN _red(void *data, GEN x) { (void)data; return gcopy(x); } static struct bb_algebra RgXQ_algebra = { _red, _add, _sub, _mul, _sqr, _one, _zero }; GEN RgX_RgXQV_eval(GEN Q, GEN x, GEN T) { return gen_bkeval_powers(Q,degpol(Q),x,(void*)T,&RgXQ_algebra,_cmul); } GEN RgX_RgXQ_eval(GEN Q, GEN x, GEN T) { int use_sqr = 2*degpol(x) >= degpol(T); return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)T,&RgXQ_algebra,_cmul); } /* mod X^n */ struct modXn { long v; /* varn(X) */ long n; } ; static GEN _sqrXn(void *data, GEN x) { struct modXn *S = (struct modXn*)data; return RgXn_sqr(x, S->n); } static GEN _mulXn(void *data, GEN x, GEN y) { struct modXn *S = (struct modXn*)data; return RgXn_mul(x,y, S->n); } static GEN _oneXn(void *data) { struct modXn *S = (struct modXn*)data; return pol_1(S->v); } static GEN _zeroXn(void *data) { struct modXn *S = (struct modXn*)data; return pol_0(S->v); } static struct bb_algebra RgXn_algebra = { _red, _add, _sub, _mulXn, _sqrXn, _oneXn, _zeroXn }; GEN RgXn_powers(GEN x, long m, long n) { long d = degpol(x); int use_sqr = (d<<1) >= n; struct modXn S; S.v = varn(x); S.n = n; return gen_powers(x,m,use_sqr,(void*)&S,_sqrXn,_mulXn,_oneXn); } GEN RgXn_powu_i(GEN x, ulong m, long n) { struct modXn S; S.v = varn(x); S.n = n; return gen_powu_i(x, m, (void*)&S,_sqrXn,_mulXn); } GEN RgXn_powu(GEN x, ulong m, long n) { struct modXn S; S.v = varn(x); S.n = n; return gen_powu(x, m, (void*)&S,_sqrXn,_mulXn); } GEN RgX_RgXnV_eval(GEN Q, GEN x, long n) { struct modXn S; S.v = varn(gel(x,2)); S.n = n; return gen_bkeval_powers(Q,degpol(Q),x,(void*)&S,&RgXn_algebra,_cmul); } GEN RgX_RgXn_eval(GEN Q, GEN x, long n) { int use_sqr = 2*degpol(x) >= n; struct modXn S; S.v = varn(x); S.n = n; return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)&S,&RgXn_algebra,_cmul); } /* Q(x) mod t^n, x in R[t], n >= 1 */ GEN RgXn_eval(GEN Q, GEN x, long n) { long d = degpol(x); int use_sqr; struct modXn S; if (d == 1 && isrationalzero(gel(x,2))) { GEN y = RgX_unscale(Q, gel(x,3)); setvarn(y, varn(x)); return y; } S.v = varn(x); S.n = n; use_sqr = (d<<1) >= n; return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)&S,&RgXn_algebra,_cmul); } /* (f*g mod t^n) \ t^n2, assuming 2*n2 >= n */ static GEN RgXn_mulhigh(GEN f, GEN g, long n2, long n) { GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2); return RgX_add(RgX_mulhigh_i(fl, g, n2), RgXn_mul(fh, g, n - n2)); } /* (f^2 mod t^n) \ t^n2, assuming 2*n2 >= n */ static GEN RgXn_sqrhigh(GEN f, long n2, long n) { GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2); return RgX_add(RgX_mulhigh_i(fl, f, n2), RgXn_mul(fh, f, n - n2)); } GEN RgXn_inv_i(GEN f, long e) { pari_sp av; ulong mask; GEN W, a; long v = varn(f), n = 1; if (!signe(f)) pari_err_INV("RgXn_inv",f); a = ginv(gel(f,2)); if (e == 1) return scalarpol(a, v); else if (e == 2) { GEN b; if (degpol(f) <= 0 || gequal0(b = gel(f,3))) return scalarpol(a, v); av = avma; b = gneg(b); if (!gequal1(a)) b = gmul(b, gsqr(a)); W = deg1pol_shallow(b, a, v); return gcopy(W); } W = scalarpol_shallow(a,v); mask = quadratic_prec_mask(e); av = avma; for (;mask>1;) { GEN u, fr; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; fr = RgXn_red_shallow(f, n); u = RgXn_mul(W, RgXn_mulhigh(fr, W, n2, n), n-n2); W = RgX_sub(W, RgX_shift_shallow(u, n2)); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgXn_inv, e = %ld", n); W = gerepileupto(av, W); } } return W; } static GEN RgXn_inv_FpX(GEN x, long e, GEN p) { pari_sp av = avma; GEN r; if (lgefint(p) == 3) { ulong pp = uel(p, 2); r = Flx_to_ZX_inplace(Flxn_inv(RgX_to_Flx(x, pp), e, pp)); } else r = FpXn_inv(RgX_to_FpX(x, p), e, p); return gerepileupto(av, FpX_to_mod(r, p)); } static GEN RgXn_inv_FpXQX(GEN x, long n, GEN pol, GEN p) { pari_sp av = avma; GEN r, T = RgX_to_FpX(pol, p); if (signe(T) == 0) pari_err_OP("/", gen_1, x); r = FpXQXn_inv(RgX_to_FpXQX(x, T, p), n, T, p); return gerepileupto(av, FpXQX_to_mod(r, pol, p)); } #define code(t1,t2) ((t1 << 6) | t2) static GEN RgXn_inv_fast(GEN x, long e) { GEN p, pol; long pa; long t = RgX_type(x,&p,&pol,&pa); switch(t) { case t_INTMOD: return RgXn_inv_FpX(x, e, p); case code(t_POLMOD, t_INTMOD): return RgXn_inv_FpXQX(x, e, pol, p); default: return NULL; } } #undef code GEN RgXn_inv(GEN f, long e) { GEN h = RgXn_inv_fast(f, e); if (h) return h; return RgXn_inv_i(f, e); } GEN RgXn_exp(GEN h, long e) { pari_sp av = avma, av2; long v = varn(h), n=1; GEN f = pol_1(v), g = pol_1(v); ulong mask = quadratic_prec_mask(e); av2 = avma; if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2))) pari_err_DOMAIN("RgXn_exp","valuation", "<", gen_1, h); for (;mask>1;) { GEN q, w; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; g = RgX_sub(RgX_muls(g,2),RgXn_mul(f,RgXn_sqr(g,n2),n2)); q = RgX_deriv(RgXn_red_shallow(h,n2)); w = RgX_add(q, RgXn_mul(g, RgX_sub(RgX_deriv(f), RgXn_mul(f,q,n-1)),n-1)); f = RgX_add(f, RgXn_mul(f, RgX_sub(RgXn_red_shallow(h, n), RgX_integ(w)), n)); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgXn_exp, e = %ld", n); gerepileall(av2, 2, &f, &g); } } return gerepileupto(av, f); } GEN RgXn_reverse(GEN f, long e) { pari_sp av = avma, av2; ulong mask; GEN fi, a, df, W, an; long v = varn(f), n=1; if (degpol(f)<1 || !gequal0(gel(f,2))) pari_err_INV("serreverse",f); fi = ginv(gel(f,3)); a = deg1pol_shallow(fi,gen_0,v); if (e <= 2) return gerepilecopy(av, a); W = scalarpol(fi,v); df = RgX_deriv(f); mask = quadratic_prec_mask(e); av2 = avma; for (;mask>1;) { GEN u, fa, fr; long n2 = n, rt; n<<=1; if (mask & 1) n--; mask >>= 1; fr = RgXn_red_shallow(f, n); rt = brent_kung_optpow(degpol(fr), 4, 3); an = RgXn_powers(a, rt, n); if (n>1) { long n4 = (n2+1)>>1; GEN dfr = RgXn_red_shallow(df, n2); dfr = RgX_RgXnV_eval(dfr, RgXnV_red_shallow(an, n2), n2); u = RgX_shift(RgX_Rg_sub(RgXn_mul(W, dfr, n2), gen_1), -n4); W = RgX_sub(W, RgX_shift(RgXn_mul(u, W, n2-n4), n4)); } fa = RgX_sub(RgX_RgXnV_eval(fr, an, n), pol_x(v)); fa = RgX_shift(fa, -n2); a = RgX_sub(a, RgX_shift(RgXn_mul(W, fa, n-n2), n2)); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgXn_reverse, e = %ld", n); gerepileall(av2, 2, &a, &W); } } return gerepileupto(av, a); } GEN RgXn_sqrt(GEN h, long e) { pari_sp av = avma, av2; long v = varn(h), n = 1; GEN f = scalarpol(gen_1, v), df = f; ulong mask = quadratic_prec_mask(e); if (degpol(h)<0 || !gequal1(gel(h,2))) pari_err_SQRTN("RgXn_sqrt",h); av2 = avma; while(1) { long n2 = n, m; GEN g; n<<=1; if (mask & 1) n--; mask >>= 1; m = n-n2; g = RgX_sub(RgXn_sqrhigh(f, n2, n), RgX_shift_shallow(RgXn_red_shallow(h, n),-n2)); f = RgX_sub(f, RgX_shift_shallow(RgXn_mul(gmul2n(df, -1), g, m), n2)); if (mask==1) return gerepileupto(av, f); g = RgXn_mul(df, RgXn_mulhigh(df, f, n2, n), m); df = RgX_sub(df, RgX_shift_shallow(g, n2)); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgXn_sqrt, e = %ld", n); gerepileall(av2, 2, &f, &df); } } } /* x,T in Rg[X], n in N, compute lift(x^n mod T)) */ GEN RgXQ_powu(GEN x, ulong n, GEN T) { pari_sp av; GEN y; if (!n) return pol_1(varn(x)); if (n == 1) return RgX_copy(x); av = avma; y = gen_powu(x, n, (void*)T, &_sqr, &_mul); return gerepileupto(av, y); } /* x,T in Rg[X], n in N, compute lift(x^n mod T)) */ GEN RgXQ_pow(GEN x, GEN n, GEN T) { pari_sp av; long s = signe(n); GEN y; if (!s) return pol_1(varn(x)); if (is_pm1(n) == 1) return (s < 0)? RgXQ_inv(x, T): RgX_copy(x); av = avma; if (s < 0) x = RgXQ_inv(x, T); y = gen_pow(x, n, (void*)T, &_sqr, &_mul); return gerepileupto(av, y); } /* generates the list of powers of x of degree 0,1,2,...,l*/ GEN RgXQ_powers(GEN x, long l, GEN T) { int use_sqr = 2*degpol(x) >= degpol(T); return gen_powers(x, l, use_sqr, (void *)T,_sqr,_mul,_one); } /* a in K = Q[X]/(T), returns [a^0, ..., a^n] */ GEN QXQ_powers(GEN a, long n, GEN T) { GEN den, v = RgXQ_powers(Q_remove_denom(a, &den), n, T); /* den*a integral; v[i+1] = (den*a)^i in K */ if (den) { /* restore denominators */ GEN d = den; long i; gel(v,2) = a; for (i=3; i<=n+1; i++) { d = mulii(d,den); gel(v,i) = RgX_Rg_div(gel(v,i), d); } } return v; } static GEN do_QXQ_eval(GEN v, long imin, GEN a, GEN T) { long l, i, m = 0; GEN dz, z; GEN V = cgetg_copy(v, &l); for (i = imin; i < l; i++) { GEN c = gel(v, i); if (typ(c) == t_POL) m = maxss(m, degpol(c)); } z = Q_remove_denom(QXQ_powers(a, m, T), &dz); for (i = 1; i < imin; i++) V[i] = v[i]; for (i = imin; i < l; i++) { GEN c = gel(v,i); if (typ(c) == t_POL) c = QX_ZXQV_eval(c, z, dz); gel(V,i) = c; } return V; } /* [ s(a mod T) | s <- lift(v) ], a,T are QX, v a QXV */ GEN QXV_QXQ_eval(GEN v, GEN a, GEN T) { return do_QXQ_eval(v, 1, a, T); } GEN QXX_QXQ_eval(GEN v, GEN a, GEN T) { return normalizepol(do_QXQ_eval(v, 2, a, T)); } GEN RgXQ_matrix_pow(GEN y, long n, long m, GEN P) { return RgXV_to_RgM(RgXQ_powers(y,m-1,P),n); } GEN RgXQ_norm(GEN x, GEN T) { pari_sp av; long dx = degpol(x); GEN L, y; av = avma; y = resultant(T, x); L = leading_coeff(T); if (gequal1(L) || !signe(x)) return y; return gerepileupto(av, gdiv(y, gpowgs(L, dx))); } GEN RgX_blocks(GEN P, long n, long m) { GEN z = cgetg(m+1,t_VEC); long i,j, k=2, l = lg(P); for(i=1; i<=m; i++) { GEN zi = cgetg(n+2,t_POL); zi[1] = P[1]; gel(z,i) = zi; for(j=2; j>1)+1; n1 = n+1 - n0; /* n1 <= n0 <= n1+1 */ p0 = cgetg(n0+2, t_POL); p0[1] = evalvarn(v)|evalsigne(1); p1 = cgetg(n1+2, t_POL); p1[1] = evalvarn(v)|evalsigne(1); for (i=0; i gvar2(p). Fix this. */ static GEN fix_pol(pari_sp av, GEN p) { long w = gvar2(p), v = varn(p); if (w == v) pari_err_PRIORITY("charpoly", p, "=", w); if (varncmp(w,v) < 0) p = gerepileupto(av, poleval(p, pol_x(v))); return p; } GEN caract(GEN x, long v) { pari_sp av = avma; GEN T, C, x_k, Q; long k, n; if ((T = easychar(x,v))) return T; n = lg(x)-1; if (n == 1) return fix_pol(av, deg1pol(gen_1, gneg(gcoeff(x,1,1)), v)); x_k = pol_x(v); /* to be modified in place */ T = scalarpol(det(x), v); C = utoineg(n); Q = pol_x(v); for (k=1; k<=n; k++) { GEN mk = utoineg(k), d; gel(x_k,2) = mk; d = det(RgM_Rg_add_shallow(x, mk)); T = RgX_add(RgX_mul(T, x_k), RgX_Rg_mul(Q, gmul(C, d))); if (k == n) break; Q = RgX_mul(Q, x_k); C = diviuexact(mulsi(k-n,C), k+1); /* (-1)^k binomial(n,k) */ } return fix_pol(av, RgX_Rg_div(T, mpfact(n))); } /* C = charpoly(x, v) */ static GEN RgM_adj_from_char(GEN x, long v, GEN C) { if (varn(C) != v) /* problem with variable priorities */ { C = gdiv(gsub(C, gsubst(C, v, gen_0)), pol_x(v)); if (odd(lg(x))) C = RgX_neg(C); /* even dimension */ return gsubst(C, v, x); } else { C = RgX_shift_shallow(C, -1); if (odd(lg(x))) C = RgX_neg(C); /* even dimension */ return RgX_RgM_eval(C, x); } } /* assume x square matrice */ static GEN mattrace(GEN x) { long i, lx = lg(x); GEN t; if (lx < 3) return lx == 1? gen_0: gcopy(gcoeff(x,1,1)); t = gcoeff(x,1,1); for (i = 2; i < lx; i++) t = gadd(t, gcoeff(x,i,i)); return t; } static int bad_char(GEN q, long n) { forprime_t S; ulong p; if (!signe(q)) return 0; (void)u_forprime_init(&S, 2, n); while ((p = u_forprime_next(&S))) if (!umodiu(q, p)) return 1; return 0; } /* Using traces: return the characteristic polynomial of x (in variable v). * If py != NULL, the adjoint matrix is put there. */ GEN caradj(GEN x, long v, GEN *py) { pari_sp av, av0; long i, k, n; GEN T, y, t; if ((T = easychar(x, v))) { if (py) { if (typ(x) != t_MAT) pari_err_TYPE("matadjoint",x); *py = cgetg(1,t_MAT); } return T; } n = lg(x)-1; av0 = avma; T = cgetg(n+3,t_POL); T[1] = evalsigne(1) | evalvarn(v); gel(T,n+2) = gen_1; if (!n) { if (py) *py = cgetg(1,t_MAT); return T; } av = avma; t = gerepileupto(av, gneg(mattrace(x))); gel(T,n+1) = t; if (n == 1) { T = fix_pol(av0, T); if (py) *py = matid(1); return T; } if (n == 2) { GEN a = gcoeff(x,1,1), b = gcoeff(x,1,2); GEN c = gcoeff(x,2,1), d = gcoeff(x,2,2); av = avma; gel(T,2) = gerepileupto(av, gsub(gmul(a,d), gmul(b,c))); T = fix_pol(av0, T); if (py) { y = cgetg(3, t_MAT); gel(y,1) = mkcol2(gcopy(d), gneg(c)); gel(y,2) = mkcol2(gneg(b), gcopy(a)); *py = y; } return T; } /* l > 3 */ if (bad_char(residual_characteristic(x), n)) { /* n! not invertible in base ring */ T = charpoly(x, v); if (!py) return gerepileupto(av, T); *py = RgM_adj_from_char(x, v, T); gerepileall(av, 2, &T,py); return T; } av = avma; y = RgM_shallowcopy(x); for (i = 1; i <= n; i++) gcoeff(y,i,i) = gadd(gcoeff(y,i,i), t); for (k = 2; k < n; k++) { GEN y0 = y; y = RgM_mul(y, x); t = gdivgs(mattrace(y), -k); for (i = 1; i <= n; i++) gcoeff(y,i,i) = gadd(gcoeff(y,i,i), t); y = gclone(y); gel(T,n-k+2) = gerepilecopy(av, t); av = avma; if (k > 2) gunclone(y0); } t = gmul(gcoeff(x,1,1),gcoeff(y,1,1)); for (i=2; i<=n; i++) t = gadd(t, gmul(gcoeff(x,1,i),gcoeff(y,i,1))); gel(T,2) = gerepileupto(av, gneg(t)); T = fix_pol(av0, T); if (py) *py = odd(n)? gcopy(y): RgM_neg(y); gunclone(y); return T; } GEN adj(GEN x) { GEN y; (void)caradj(x, fetch_var(), &y); (void)delete_var(); return y; } GEN adjsafe(GEN x) { const long v = fetch_var(); pari_sp av = avma; GEN C, A; if (typ(x) != t_MAT) pari_err_TYPE("matadjoint",x); if (lg(x) < 3) return gcopy(x); C = charpoly(x,v); A = RgM_adj_from_char(x, v, C); (void)delete_var(); return gerepileupto(av, A); } GEN matadjoint0(GEN x, long flag) { switch(flag) { case 0: return adj(x); case 1: return adjsafe(x); } pari_err_FLAG("matadjoint"); return NULL; /* LCOV_EXCL_LINE */ } /*******************************************************************/ /* */ /* Frobenius form */ /* */ /*******************************************************************/ /* The following section implement a mix of Ozello and Storjohann algorithms P. Ozello, doctoral thesis (in French): Calcul exact des formes de Jordan et de Frobenius d'une matrice, Chapitre 2 http://tel.archives-ouvertes.fr/tel-00323705 A. Storjohann, Diss. ETH No. 13922 Algorithms for Matrix Canonical Forms, Chapter 9 https://cs.uwaterloo.ca/~astorjoh/diss2up.pdf We use Storjohann Lemma 9.14 (step1, step2, step3) Ozello theorem 4, and Storjohann Lemma 9.18 */ /* Elementary transforms */ /* M <- U^(-1) M U, U = E_{i,j}(k) => U^(-1) = E{i,j}(-k) * P = U * P */ static void transL(GEN M, GEN P, GEN k, long i, long j) { long l, n = lg(M)-1; for(l=1; l<=n; l++) /* M[,j]-=k*M[,i] */ gcoeff(M,l,j) = gsub(gcoeff(M,l,j), gmul(gcoeff(M,l,i), k)); for(l=1; l<=n; l++) /* M[i,]+=k*M[j,] */ gcoeff(M,i,l) = gadd(gcoeff(M,i,l), gmul(gcoeff(M,j,l), k)); if (P) for(l=1; l<=n; l++) gcoeff(P,i,l) = gadd(gcoeff(P,i,l), gmul(gcoeff(P,j,l), k)); } /* j = a or b */ static void transD(GEN M, GEN P, long a, long b, long j) { long l, n; GEN k = gcoeff(M,a,b), ki; if (gequal1(k)) return; ki = ginv(k); n = lg(M)-1; for(l=1; l<=n; l++) if (l!=j) { gcoeff(M,l,j) = gmul(gcoeff(M,l,j), k); gcoeff(M,j,l) = (j==a && l==b)? gen_1: gmul(gcoeff(M,j,l), ki); } if (P) for(l=1; l<=n; l++) gcoeff(P,j,l) = gmul(gcoeff(P,j,l), ki); } static void transS(GEN M, GEN P, long i, long j) { long l, n = lg(M)-1; swap(gel(M,i), gel(M,j)); for (l=1; l<=n; l++) swap(gcoeff(M,i,l), gcoeff(M,j,l)); if (P) for (l=1; l<=n; l++) swap(gcoeff(P,i,l), gcoeff(P,j,l)); } /* Convert companion matrix to polynomial*/ static GEN minpoly_polslice(GEN M, long i, long j, long v) { long k, d = j+1-i; GEN P = cgetg(d+3,t_POL); P[1] = evalsigne(1)|evalvarn(v); for (k=0; k n) return j; transS(M, P, k, j+1); } transD(M, P, j+1, j, j+1); /* Now M[j+1,j] = 1 */ for (k = 1; k <= n; ++k) if (k != j+1 && !gequal0(gcoeff(M,k,j))) /* zero M[k,j] */ { transL(M, P, gneg(gcoeff(M,k,j)), k, j+1); gcoeff(M,k,j) = gen_0; /* avoid approximate 0 */ } if (gc_needed(av,1)) { if (DEBUGMEM > 1) pari_warn(warnmem,"RgM_minpoly stage 1: j0=%ld, j=%ld", j0, j); gerepilemat2_inplace(av, M, P); } } return n; } static void weakfrobenius_step2(GEN M, GEN P, long j) { pari_sp av = avma; long i, k, n = lg(M)-1; for(i=j; i>=2; i--) { for(k=j+1; k<=n; k++) if (!gequal0(gcoeff(M,i,k))) transL(M, P, gcoeff(M,i,k), i-1, k); if (gc_needed(av,1)) { if (DEBUGMEM > 1) pari_warn(warnmem,"RgM_minpoly stage 2: j=%ld, i=%ld", j, i); gerepilemat2_inplace(av, M, P); } } } static long weakfrobenius_step3(GEN M, GEN P, long j0, long j) { long i, k, n = lg(M)-1; if (j == n) return 0; if (gequal0(gcoeff(M, j0, j+1))) { for (k=j+2; k<=n; k++) if (!gequal0(gcoeff(M, j0, k))) break; if (k > n) return 0; transS(M, P, k, j+1); } transD(M, P, j0, j+1, j+1); for (i=j+2; i<=n; i++) if (!gequal0(gcoeff(M, j0, i))) transL(M, P, gcoeff(M, j0, i),j+1, i); return 1; } /* flag: 0 -> full Frobenius from , 1 -> weak Frobenius form */ static GEN RgM_Frobenius(GEN M, long flag, GEN *pt_P, GEN *pt_v) { pari_sp av = avma, av2, ltop; long n = lg(M)-1, eps, j0 = 1, nb = 0; GEN v, P; v = cgetg(n+1, t_VECSMALL); ltop = avma; P = pt_P ? matid(n): NULL; M = RgM_shallowcopy(M); av2 = avma; while (j0 <= n) { long j = weakfrobenius_step1(M, P, j0); weakfrobenius_step2(M, P, j); eps = weakfrobenius_step3(M, P, j0, j); if (eps == 0) { v[++nb] = j0; if (flag == 0 && nb > 1 && !minpoly_dvdslice(M, v[nb-1], j0, j)) { j = j0; j0 = v[nb-1]; nb -= 2; transL(M, P, gen_1, j, j0); /*lemma 9.18*/ } else j0 = j+1; } else transS(M, P, j0, j+1); /*theorem 4*/ if (gc_needed(av,1)) { if (DEBUGMEM > 1) pari_warn(warnmem,"weakfrobenius j0=%ld",j0); gerepilemat2_inplace(av2, M, P); } } fixlg(v, nb+1); if (pt_v) *pt_v = v; gerepileall(pt_v ? ltop: av, P? 2: 1, &M, &P); if (pt_P) *pt_P = P; return M; } static GEN RgM_minpoly(GEN M, long v) { pari_sp av = avma; GEN V, W; if (lg(M) == 1) return pol_1(v); M = RgM_Frobenius(M, 1, NULL, &V); W = minpoly_listpolslice(M, V, v); if (varncmp(v,gvar2(W)) >= 0) pari_err_PRIORITY("matfrobenius", M, "<=", v); return gerepileupto(av, RgX_normalize(glcm0(W, NULL))); } GEN Frobeniusform(GEN V, long n) { long i, j, k; GEN M = zeromatcopy(n,n); for (k=1,i=1;i n) pari_err_PREC("matfrobenius"); for (j=0; j 2) pari_err_FLAG("matfrobenius"); switch (flag) { case 0: return RgM_Frobenius(M, 0, NULL, NULL); case 1: { pari_sp av = avma; GEN V, W, F; F = RgM_Frobenius(M, 0, NULL, &V); W = minpoly_listpolslice(F, V, v); if (varncmp(v, gvar2(W)) >= 0) pari_err_PRIORITY("matfrobenius", M, "<=", v); return gerepileupto(av, W); } case 2: { GEN P, F, R = cgetg(3, t_VEC); F = RgM_Frobenius(M, 0, &P, NULL); gel(R,1) = F; gel(R,2) = P; return R; } default: pari_err_FLAG("matfrobenius"); } return NULL; /*LCOV_EXCL_LINE*/ } /*******************************************************************/ /* */ /* MINIMAL POLYNOMIAL */ /* */ /*******************************************************************/ static GEN RgXQ_minpoly_naive(GEN y, GEN P) { long n = lgpol(P); GEN M = ker(RgXQ_matrix_pow(y,n,n,P)); return content(RgM_to_RgXV(M,varn(P))); } static GEN easymin(GEN x, long v) { GEN G, R, dR; long tx = typ(x); if (tx == t_FFELT) { R = FpX_to_mod(FF_minpoly(x), FF_p_i(x)); setvarn(R,v); return R; } if (tx == t_POLMOD) { GEN a = gel(x,2), b = gel(x,1); if (typ(a) != t_POL || varn(a) != varn(b)) { if (varncmp(gvar(a), v) <= 0) pari_err_PRIORITY("minpoly", x, "<", v); return deg1pol(gen_1, gneg_i(a), v); } if (!issquarefree(b)) { R = RgXQ_minpoly_naive(a, b); setvarn(R,v); return R; } } R = easychar(x, v); if (!R) return NULL; dR = RgX_deriv(R); if (!lgpol(dR)) return NULL; G = RgX_normalize(RgX_gcd(R,dR)); return RgX_div(R,G); } GEN minpoly(GEN x, long v) { pari_sp av = avma; GEN P; if (v < 0) v = 0; P = easymin(x,v); if (P) return gerepileupto(av,P); avma = av; if (typ(x) == t_POLMOD) { P = RgXQ_minpoly_naive(gel(x,2), gel(x,1)); setvarn(P,v); return gerepileupto(av,P); } if (typ(x) != t_MAT) pari_err_TYPE("minpoly",x); if (lg(x) == 1) return pol_1(v); return RgM_minpoly(x,v); } /*******************************************************************/ /* */ /* HESSENBERG FORM */ /* */ /*******************************************************************/ static int relative0(GEN a, GEN a0, long bit) { return gequal0(a) || (bit && gexpo(a)-gexpo(a0) < bit); } /* assume x a non-empty square t_MAT */ static GEN RgM_hess(GEN x0, long prec) { pari_sp av; long lx = lg(x0), bit = prec? 8 - bit_accuracy(prec): 0, m, i, j; GEN x; if (bit) x0 = RgM_shallowcopy(x0); av = avma; x = RgM_shallowcopy(x0); for (m=2; m1) pari_warn(warnmem,"hess, m = %ld", m); gerepileall(av,2, &x, &t); } } } return x; } GEN hess(GEN x) { pari_sp av = avma; GEN p = NULL, T = NULL; long prec, lx = lg(x); if (typ(x) != t_MAT) pari_err_TYPE("hess",x); if (lx == 1) return cgetg(1,t_MAT); if (lgcols(x) != lx) pari_err_DIM("hess"); switch(RgM_type(x, &p, &T, &prec)) { case t_REAL: case t_COMPLEX: break; default: prec = 0; } return gerepilecopy(av, RgM_hess(x,prec)); } GEN Flm_hess(GEN x, ulong p) { long lx = lg(x), m, i, j; if (lx == 1) return cgetg(1,t_MAT); if (lgcols(x) != lx) pari_err_DIM("hess"); x = Flm_copy(x); for (m=2; m1) pari_warn(warnmem,"hess, m = %ld", m); gerepileall(av,2, &x, &t); } } } return gerepilecopy(av,x); } /* H in Hessenberg form */ static GEN RgM_hess_charpoly(GEN H, long v) { long n = lg(H), r, i; GEN y = cgetg(n+1, t_VEC); gel(y,1) = pol_1(v); for (r = 1; r < n; r++) { pari_sp av2 = avma; GEN z, a = gen_1, b = pol_0(v); for (i = r-1; i; i--) { a = gmul(a, gcoeff(H,i+1,i)); if (gequal0(a)) break; b = RgX_add(b, RgX_Rg_mul(gel(y,i), gmul(a,gcoeff(H,i,r)))); } z = RgX_sub(RgX_shift_shallow(gel(y,r), 1), RgX_Rg_mul(gel(y,r), gcoeff(H,r,r))); gel(y,r+1) = gerepileupto(av2, RgX_sub(z, b)); /* (X - H[r,r])y[r] - b */ } return gel(y,n); } GEN carhess(GEN x, long v) { pari_sp av; GEN y; if ((y = easychar(x,v))) return y; av = avma; y = RgM_hess_charpoly(hess(x), v); return fix_pol(av, y); } /* Bound for sup norm of charpoly(M/dM), M integral: let B = |M|oo / |dM|, * s = max_k binomial(n,k) (kB^2)^(k/2), * return ceil(log2(s)) */ static double charpoly_bound(GEN M, GEN dM) { pari_sp av = avma; GEN B = itor(ZM_supnorm(M), LOWDEFAULTPREC); GEN s = real_0(LOWDEFAULTPREC), bin, B2; long n = lg(M)-1, k; double d; bin = gen_1; if (dM) B = divri(B, dM); B2 = sqrr(B); for (k = n; k >= (n+1)>>1; k--) { GEN t = mulri(powruhalf(mulur(k, B2), k), bin); if (abscmprr(t, s) > 0) s = t; bin = diviuexact(muliu(bin, k), n-k+1); } d = dbllog2(s); avma = av; return ceil(d); } /* Return char_{M/d}(X) = d^(-n) char_M(dX) modulo p. Assume dp = d mod p. */ static GEN QM_charpoly_Flx(GEN M, ulong dp, ulong p) { pari_sp av = avma; GEN H = Flm_charpoly_i(ZM_to_Flm(M,p), p); if (dp) H = Flx_rescale(H, Fl_inv(dp,p), p); return gerepileuptoleaf(av, H); } static int ZX_CRT(GEN *H, GEN Hp, GEN *q, ulong p, long bit) { if (!*H) { *H = ZX_init_CRT(Hp, p, 0); if (DEBUGLEVEL>5) err_printf("charpoly mod %lu, bound = 2^%ld\n", p, expu(p)); if (expu(p) > bit) return 1; *q = utoipos(p); } else { int stable = ZX_incremental_CRT(H, Hp, q,p); if (DEBUGLEVEL>5) err_printf("charpoly mod %lu (stable=%ld), bound = 2^%ld\n", p, stable, expi(*q)); if (stable && expi(*q) > bit) return 1; } return 0; } /* Assume M a square ZM, dM integer. Return charpoly(M / dM) in Z[X] */ static GEN QM_charpoly_ZX_i(GEN M, GEN dM, long bit) { long n = lg(M)-1; GEN q = NULL, H = NULL; forprime_t S; ulong p; if (!n) return pol_1(0); if (bit < 0) bit = (long)charpoly_bound(M, dM) + 1; if (DEBUGLEVEL>5) err_printf("ZM_charpoly: bit-bound 2^%ld\n", bit); init_modular_big(&S); while ((p = u_forprime_next(&S))) { ulong dMp = 0; GEN Hp; if (dM && !(dMp = umodiu(dM, p))) continue; Hp = QM_charpoly_Flx(M, dMp, p); if (ZX_CRT(&H, Hp, &q,p, bit)) break; } if (!p) pari_err_OVERFLOW("charpoly [ran out of primes]"); return H; } GEN QM_charpoly_ZX_bound(GEN M, long bit) { pari_sp av = avma; GEN dM; M = Q_remove_denom(M, &dM); return gerepilecopy(av, QM_charpoly_ZX_i(M, dM, bit)); } GEN QM_charpoly_ZX(GEN M) { pari_sp av = avma; GEN dM; M = Q_remove_denom(M, &dM); return gerepilecopy(av, QM_charpoly_ZX_i(M, dM, -1)); } GEN ZM_charpoly(GEN M) { pari_sp av = avma; return gerepilecopy(av, QM_charpoly_ZX_i(M, NULL, -1)); } /*******************************************************************/ /* */ /* CHARACTERISTIC POLYNOMIAL (BERKOWITZ'S ALGORITHM) */ /* */ /*******************************************************************/ GEN carberkowitz(GEN x, long v) { long lx, i, j, k, r; GEN V, S, C, Q; pari_sp av0, av; if ((V = easychar(x,v))) return V; lx = lg(x); av0 = avma; V = cgetg(lx+1, t_VEC); S = cgetg(lx+1, t_VEC); C = cgetg(lx+1, t_VEC); Q = cgetg(lx+1, t_VEC); av = avma; gel(C,1) = gen_m1; gel(V,1) = gen_m1; for (i=2;i<=lx; i++) gel(C,i) = gel(Q,i) = gel(S,i) = gel(V,i) = gen_0; gel(V,2) = gcoeff(x,1,1); for (r = 2; r < lx; r++) { pari_sp av2; GEN t; for (i = 1; i < r; i++) gel(S,i) = gcoeff(x,i,r); gel(C,2) = gcoeff(x,r,r); for (i = 1; i < r-1; i++) { av2 = avma; t = gmul(gcoeff(x,r,1), gel(S,1)); for (j = 2; j < r; j++) t = gadd(t, gmul(gcoeff(x,r,j), gel(S,j))); gel(C,i+2) = gerepileupto(av2, t); for (j = 1; j < r; j++) { av2 = avma; t = gmul(gcoeff(x,j,1), gel(S,1)); for (k = 2; k < r; k++) t = gadd(t, gmul(gcoeff(x,j,k), gel(S,k))); gel(Q,j) = gerepileupto(av2, t); } for (j = 1; j < r; j++) gel(S,j) = gel(Q,j); } av2 = avma; t = gmul(gcoeff(x,r,1), gel(S,1)); for (j = 2; j < r; j++) t = gadd(t, gmul(gcoeff(x,r,j), gel(S,j))); gel(C,r+1) = gerepileupto(av2, t); if (gc_needed(av0,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"carberkowitz"); gerepileall(av, 2, &C, &V); } for (i = 1; i <= r+1; i++) { av2 = avma; t = gmul(gel(C,i), gel(V,1)); for (j = 2; j <= minss(r,i); j++) t = gadd(t, gmul(gel(C,i+1-j), gel(V,j))); gel(Q,i) = gerepileupto(av2, t); } for (i = 1; i <= r+1; i++) gel(V,i) = gel(Q,i); } V = RgV_to_RgX(vecreverse(V), v); /* not gtopoly: fail if v > gvar(V) */ V = odd(lx)? gcopy(V): RgX_neg(V); return fix_pol(av0, V); } /*******************************************************************/ /* */ /* NORMS */ /* */ /*******************************************************************/ GEN gnorm(GEN x) { pari_sp av; long lx, i; GEN y; switch(typ(x)) { case t_INT: return sqri(x); case t_REAL: return sqrr(x); case t_FRAC: return sqrfrac(x); case t_COMPLEX: av = avma; return gerepileupto(av, cxnorm(x)); case t_QUAD: av = avma; return gerepileupto(av, quadnorm(x)); case t_POL: case t_SER: case t_RFRAC: av = avma; return gerepileupto(av, greal(gmul(conj_i(x),x))); case t_FFELT: y = cgetg(3, t_INTMOD); gel(y,1) = FF_p(x); gel(y,2) = FF_norm(x); return y; case t_POLMOD: { GEN T = gel(x,1), a = gel(x,2); if (typ(a) != t_POL || varn(a) != varn(T)) return gpowgs(a, degpol(T)); return RgXQ_norm(a, T); } case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); for (i=1; i 0) return quadnorm(q); /* imaginary */ if (!prec) pari_err_TYPE("gnorml2", q); return sqrr(quadtofp(q, prec)); } static GEN gnorml2_i(GEN x, long prec) { pari_sp av; long i, lx; GEN s; switch(typ(x)) { case t_INT: return sqri(x); case t_REAL: return sqrr(x); case t_FRAC: return sqrfrac(x); case t_COMPLEX: av = avma; return gerepileupto(av, cxnorm(x)); case t_QUAD: av = avma; return gerepileupto(av, cxquadnorm(x,prec)); case t_POL: lx = lg(x)-1; x++; break; case t_VEC: case t_COL: case t_MAT: lx = lg(x); break; default: pari_err_TYPE("gnorml2",x); return NULL; /* LCOV_EXCL_LINE */ } if (lx == 1) return gen_0; av = avma; s = gnorml2(gel(x,1)); for (i=2; i1) pari_warn(warnmem,"gnorml2"); s = gerepileupto(av, s); } } return gerepileupto(av,s); } GEN gnorml2(GEN x) { return gnorml2_i(x, 0); } static GEN pnormlp(GEN,GEN,long); static GEN pnormlpvec(long i0, GEN x, GEN p, long prec) { pari_sp av = avma; long i, lx = lg(x); GEN s = gen_0; for (i=i0; i1) pari_warn(warnmem,"gnormlp, i = %ld", i); s = gerepileupto(av, s); } } return s; } /* (||x||_p)^p */ static GEN pnormlp(GEN x, GEN p, long prec) { switch(typ(x)) { case t_INT: case t_REAL: x = mpabs(x); break; case t_FRAC: x = absfrac(x); break; case t_COMPLEX: case t_QUAD: x = gabs(x,prec); break; case t_POL: return pnormlpvec(2, x, p, prec); case t_VEC: case t_COL: case t_MAT: return pnormlpvec(1, x, p, prec); default: pari_err_TYPE("gnormlp",x); } return gpow(x, p, prec); } GEN gnormlp(GEN x, GEN p, long prec) { pari_sp av = avma; if (!p || (typ(p) == t_INFINITY && inf_get_sign(p) > 0)) return gsupnorm(x, prec); if (gsigne(p) <= 0) pari_err_DOMAIN("normlp", "p", "<=", gen_0, p); if (is_scalar_t(typ(x))) return gabs(x, prec); if (typ(p) == t_INT) { ulong pp = itou_or_0(p); switch(pp) { case 1: return gnorml1(x, prec); case 2: x = gnorml2_i(x, prec); break; default: x = pnormlp(x, p, prec); break; } if (pp && typ(x) == t_INT && Z_ispowerall(x, pp, &x)) return gerepileuptoleaf(av, x); if (pp == 2) return gerepileupto(av, gsqrt(x, prec)); } else x = pnormlp(x, p, prec); x = gpow(x, ginv(p), prec); return gerepileupto(av, x); } GEN gnorml1(GEN x,long prec) { pari_sp av = avma; long lx,i; GEN s; switch(typ(x)) { case t_INT: case t_REAL: return mpabs(x); case t_FRAC: return absfrac(x); case t_COMPLEX: case t_QUAD: return gabs(x,prec); case t_POL: lx = lg(x); s = gen_0; for (i=2; i 0) *m = z; } /* compare |x| to *m or |x|^2 to *msq, whichever is easiest, and update * the pointed value if x is larger */ void gsupnorm_aux(GEN x, GEN *m, GEN *msq, long prec) { long i, lx; GEN z; switch(typ(x)) { case t_COMPLEX: z = cxnorm(x); store(z, msq); return; case t_QUAD: z = cxquadnorm(x,prec); store(z, msq); return; case t_INT: case t_REAL: z = mpabs(x); store(z,m); return; case t_FRAC: z = absfrac(x); store(z,m); return; case t_POL: lx = lg(x)-1; x++; break; case t_VEC: case t_COL: case t_MAT: lx = lg(x); break; default: pari_err_TYPE("gsupnorm",x); return; /* LCOV_EXCL_LINE */ } for (i=1; i1) pari_warn(warnmem,"qfgaussred_positive"); b=gerepilecopy(av,b); } } return gerepilecopy(av,b); } /* Maximal pivot strategy: x is a suitable pivot if it is non zero and either * - an exact type, or * - it is maximal among remaining non-zero (t_REAL) pivots */ static int suitable(GEN x, long k, GEN *pp, long *pi) { long t = typ(x); switch(t) { case t_INT: return signe(x) != 0; case t_FRAC: return 1; case t_REAL: { GEN p = *pp; if (signe(x) && (!p || abscmprr(p, x) < 0)) { *pp = x; *pi = k; } return 0; } default: return !gequal0(x); } } /* Gauss reduction (arbitrary symetric matrix, only the part above the * diagonal is considered). If signature is non-zero, return only the * signature, in which case gsigne() should be defined for elements of a. */ static GEN gaussred(GEN a, long signature) { GEN r, ak, al; pari_sp av, av1; long n = lg(a), i, j, k, l, sp, sn, t; if (typ(a) != t_MAT) pari_err_TYPE("gaussred",a); if (n == 1) return signature? mkvec2(gen_0, gen_0): cgetg(1, t_MAT); if (lgcols(a) != n) pari_err_DIM("gaussred"); n--; av = avma; r = const_vecsmall(n, 1); av1= avma; a = RgM_shallowcopy(a); t = n; sp = sn = 0; while (t) { long pind = 0; GEN invp, p = NULL; k=1; while (k<=n && (!r[k] || !suitable(gcoeff(a,k,k), k, &p, &pind))) k++; if (k > n && p) k = pind; if (k <= n) { p = gcoeff(a,k,k); invp = ginv(p); /* != 0 */ if (signature) { /* skip if (!signature): gsigne may fail ! */ if (gsigne(p) > 0) sp++; else sn++; } r[k] = 0; t--; ak = row(a, k); for (i=1; i<=n; i++) gcoeff(a,k,i) = r[i]? gmul(gcoeff(a,k,i), invp): gen_0; for (i=1; i<=n; i++) if (r[i]) { GEN c = gel(ak,i); /* - p * a[k,i] */ if (gequal0(c)) continue; for (j=1; j<=n; j++) if (r[j]) gcoeff(a,i,j) = gsub(gcoeff(a,i,j), gmul(c,gcoeff(a,k,j))); } gcoeff(a,k,k) = p; if (gc_needed(av1,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gaussred (t = %ld)", t); a = gerepilecopy(av1, a); } } else { /* all remaining diagonal coeffs are currently 0 */ for (k=1; k<=n; k++) if (r[k]) { l=k+1; while (l<=n && (!r[l] || !suitable(gcoeff(a,k,l), l, &p, &pind))) l++; if (l > n && p) l = pind; if (l > n) continue; p = gcoeff(a,k,l); invp = ginv(p); sp++; sn++; r[k] = r[l] = 0; t -= 2; ak = row(a, k); al = row(a, l); for (i=1; i<=n; i++) if (r[i]) { gcoeff(a,k,i) = gmul(gcoeff(a,k,i), invp); gcoeff(a,l,i) = gmul(gcoeff(a,l,i), invp); } else { gcoeff(a,k,i) = gen_0; gcoeff(a,l,i) = gen_0; } for (i=1; i<=n; i++) if (r[i]) { /* c = a[k,i] * p, d = a[l,i] * p; */ GEN c = gel(ak,i), d = gel(al,i); for (j=1; j<=n; j++) if (r[j]) gcoeff(a,i,j) = gsub(gcoeff(a,i,j), gadd(gmul(gcoeff(a,l,j), c), gmul(gcoeff(a,k,j), d))); } for (i=1; i<=n; i++) if (r[i]) { GEN c = gcoeff(a,k,i), d = gcoeff(a,l,i); gcoeff(a,k,i) = gadd(c, d); gcoeff(a,l,i) = gsub(c, d); } gcoeff(a,k,l) = gen_1; gcoeff(a,l,k) = gen_m1; gcoeff(a,k,k) = gmul2n(p,-1); gcoeff(a,l,l) = gneg(gcoeff(a,k,k)); if (gc_needed(av1,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gaussred"); a = gerepilecopy(av1, a); } break; } if (k > n) break; } } if (!signature) return gerepilecopy(av, a); avma = av; return mkvec2s(sp, sn); } GEN qfgaussred(GEN a) { return gaussred(a,0); } GEN qfsign(GEN a) { return gaussred(a,1); } /* x -= s(y+u*x) */ /* y += s(x-u*y), simultaneously */ static void rot(GEN x, GEN y, GEN s, GEN u) { GEN x1 = subrr(x, mulrr(s,addrr(y,mulrr(u,x)))); GEN y1 = addrr(y, mulrr(s,subrr(x,mulrr(u,y)))); affrr(x1,x); affrr(y1,y); } /* Diagonalization of a REAL symetric matrix. Return a vector [L, r]: * L = vector of eigenvalues * r = matrix of eigenvectors */ GEN jacobi(GEN a, long prec) { pari_sp av1; long de, e, e1, e2, i, j, p, q, l = lg(a); GEN c, ja, L, r, L2, r2, unr; if (typ(a) != t_MAT) pari_err_TYPE("jacobi",a); ja = cgetg(3,t_VEC); L = cgetg(l,t_COL); gel(ja,1) = L; r = cgetg(l,t_MAT); gel(ja,2) = r; if (l == 1) return ja; if (lgcols(a) != l) pari_err_DIM("jacobi"); e1 = HIGHEXPOBIT-1; for (j=1; j e2) { e2 = e; p = i; q = j; } } } a = c; unr = real_1(prec); de = prec2nbits(prec); /* e1 = min expo(a[i,i]) * e2 = max expo(a[i,j]), i != j */ while (e1-e2 < de) { pari_sp av2 = avma; GEN x, y, t, c, s, u; /* compute attached rotation in the plane formed by basis vectors number * p and q */ x = subrr(gel(L,q),gel(L,p)); if (signe(x)) { x = divrr(x, shiftr(gcoeff(a,p,q),1)); y = sqrtr(addrr(unr, sqrr(x))); t = invr((signe(x)>0)? addrr(x,y): subrr(x,y)); } else y = t = unr; c = sqrtr(addrr(unr,sqrr(t))); s = divrr(t,c); u = divrr(t,addrr(unr,c)); /* compute successive transforms of a and the matrix of accumulated * rotations (r) */ for (i=1; i e2) { e2=e; p=i; q=j; } } for (i=j+1; i e2) { e2=e; p=j; q=i; } } } avma = av2; } /* sort eigenvalues from smallest to largest */ c = indexsort(L); r2 = vecpermute(r, c); for (i=1; i Z-modules **/ /** **/ /*************************************************************************/ GEN matrixqz0(GEN x,GEN p) { if (typ(x) != t_MAT) pari_err_TYPE("matrixqz",x); if (!p) return QM_minors_coprime(x,NULL); if (typ(p) != t_INT) pari_err_TYPE("matrixqz",p); if (signe(p)>=0) return QM_minors_coprime(x,p); if (!RgM_is_QM(x)) pari_err_TYPE("matrixqz", x); if (absequaliu(p,1)) return QM_ImZ_hnf(x); /* p = -1 */ if (absequaliu(p,2)) return QM_ImQ_hnf(x); /* p = -2 */ pari_err_FLAG("QM_minors_coprime"); return NULL; /* LCOV_EXCL_LINE */ } GEN QM_minors_coprime(GEN x, GEN D) { pari_sp av = avma, av1; long i, j, m, n, lP; GEN P, y; n = lg(x)-1; if (!n) return gcopy(x); m = nbrows(x); if (n > m) pari_err_DOMAIN("QM_minors_coprime","n",">",strtoGENstr("m"),x); y = x; x = cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { gel(x,j) = Q_primpart(gel(y,j)); RgV_check_ZV(gel(x,j), "QM_minors_coprime"); } /* x now a ZM */ if (n==m) { if (gequal0(ZM_det(x))) pari_err_DOMAIN("QM_minors_coprime", "rank(A)", "<",stoi(n),x); avma = av; return matid(n); } /* m > n */ if (!D || gequal0(D)) { pari_sp av2 = avma; D = ZM_detmult(shallowtrans(x)); if (is_pm1(D)) { avma = av2; return ZM_copy(x); } } P = gel(Z_factor(D), 1); lP = lg(P); av1 = avma; for (i=1; i < lP; i++) { GEN p = gel(P,i), pov2 = shifti(p, -1); for(;;) { GEN N, M = FpM_ker(x, p); long lM = lg(M); if (lM==1) break; FpM_center_inplace(M, p, pov2); N = ZM_Z_divexact(ZM_mul(x,M), p); for (j=1; j1) pari_warn(warnmem,"QM_minors_coprime, p = %Ps", p); x = gerepilecopy(av1, x); pov2 = shifti(p, -1); } } } return gerepilecopy(av, x); } static GEN QM_ImZ_hnfall_i(GEN A, GEN *U, long remove) { GEN V = NULL, D; A = Q_remove_denom(A,&D); if (D) { long l, lA; V = matkermod(A,D,NULL); l = lg(V); lA = lg(A); if (l == 1) V = scalarmat_shallow(D, lA-1); else { if (l < lA) V = hnfmodid(V,D); A = ZM_Z_divexact(ZM_mul(A, V), D); } } A = ZM_hnflll(A, U, remove); if (U && V) *U = ZM_mul(V,*U); return A; } GEN QM_ImZ_hnfall(GEN x, GEN *U, long remove) { pari_sp av = avma; x = QM_ImZ_hnfall_i(x, U, remove); if (U) gerepileall(av, 2, &x, &U); else x = gerepileupto(av, x); return x; } GEN QM_ImZ_hnf(GEN x) { return QM_ImZ_hnfall(x, NULL, 1); } GEN QM_ImQ_hnfall(GEN x, GEN *U, long remove) { pari_sp av = avma, av1; long k, r, m, n = lg(x); GEN c, V; if (U) *U = matid(n-1); if (n==1) return gcopy(x); m = lgcols(x); x = RgM_shallowcopy(x); c = zero_zv(n-1); r = 1; av1 = avma; for (k = 1; k < m; k++) { long j = 1, a; GEN p; while (j1) pari_warn(warnmem,"QM_ImQ_hnf"); gerepileall(av1, U? 2: 1, &x, U); } } x = QM_ImZ_hnfall_i(x, U? &V: NULL, remove); if (U) { *U = RgM_mul(*U,V); gerepileall(av,2,&x,U); } else x = gerepileupto(av,x); return x; } GEN QM_ImQ_hnf(GEN x) { return QM_ImQ_hnfall(x, NULL, 1); } GEN intersect(GEN x, GEN y) { long j, lx = lg(x); pari_sp av; GEN z; if (typ(x)!=t_MAT) pari_err_TYPE("intersect",x); if (typ(y)!=t_MAT) pari_err_TYPE("intersect",y); if (lx==1 || lg(y)==1) return cgetg(1,t_MAT); av = avma; z = ker(shallowconcat(x,y)); for (j=lg(z)-1; j; j--) setlg(z[j], lx); return gerepileupto(av, image(RgM_mul(x,z))); } pari-2.11.2/src/basemath/base1.c0000644000175000017500000021714513447371554014717 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /**************************************************************/ /* */ /* NUMBER FIELDS */ /* */ /**************************************************************/ #include "pari.h" #include "paripriv.h" int new_galois_format = 0; int checkrnf_i(GEN rnf) { return (typ(rnf)==t_VEC && lg(rnf)==13); } void checkrnf(GEN rnf) { if (!checkrnf_i(rnf)) pari_err_TYPE("checkrnf",rnf); } GEN checkbnf_i(GEN X) { if (typ(X) == t_VEC) switch (lg(X)) { case 11: if (typ(gel(X,6)) != t_INT) return NULL; /* pre-2.2.4 format */ if (lg(gel(X,10)) != 4) return NULL; /* pre-2.8.1 format */ return X; case 7: return checkbnf_i(bnr_get_bnf(X)); } return NULL; } GEN checknf_i(GEN X) { if (typ(X)==t_VEC) switch(lg(X)) { case 10: return X; case 11: return checknf_i(bnf_get_nf(X)); case 7: return checknf_i(bnr_get_bnf(X)); case 3: if (typ(gel(X,2)) == t_POLMOD) return checknf_i(gel(X,1)); } return NULL; } GEN checkbnf(GEN x) { GEN bnf = checkbnf_i(x); if (!bnf) pari_err_TYPE("checkbnf [please apply bnfinit()]",x); return bnf; } GEN checknf(GEN x) { GEN nf = checknf_i(x); if (!nf) pari_err_TYPE("checknf [please apply nfinit()]",x); return nf; } void checkbnr(GEN bnr) { if (typ(bnr)!=t_VEC || lg(bnr)!=7) pari_err_TYPE("checkbnr [please apply bnrinit()]",bnr); (void)checkbnf(bnr_get_bnf(bnr)); } void checkbnrgen(GEN bnr) { checkbnr(bnr); if (lg(bnr_get_clgp(bnr))<=3) pari_err_TYPE("checkbnrgen [apply bnrinit(,,1), not bnrinit()]",bnr); } void checksqmat(GEN x, long N) { if (typ(x)!=t_MAT) pari_err_TYPE("checksqmat",x); if (lg(x) == 1 || lgcols(x) != N+1) pari_err_DIM("checksqmat"); } GEN checkbid_i(GEN bid) { GEN f; if (typ(bid)!=t_VEC || lg(bid)!=6 || typ(bid_get_U(bid)) != t_VEC) return NULL; f = bid_get_mod(bid); if (typ(f)!=t_VEC || lg(f)!=3) return NULL; return bid; } void checkbid(GEN bid) { if (!checkbid_i(bid)) pari_err_TYPE("checkbid",bid); } void checkabgrp(GEN v) { if (typ(v) == t_VEC) switch(lg(v)) { case 4: if (typ(gel(v,3)) != t_VEC) break; case 3: if (typ(gel(v,2)) != t_VEC) break; if (typ(gel(v,1)) != t_INT) break; return;/*OK*/ default: break; } pari_err_TYPE("checkabgrp",v); } GEN checknfelt_mod(GEN nf, GEN x, const char *s) { GEN T = gel(x,1), a = gel(x,2), Tnf = nf_get_pol(nf); if (!RgX_equal_var(T, Tnf)) pari_err_MODULUS(s, T, Tnf); return a; } void check_ZKmodule(GEN x, const char *s) { if (typ(x) != t_VEC || lg(x) < 3) pari_err_TYPE(s,x); if (typ(gel(x,1)) != t_MAT) pari_err_TYPE(s,gel(x,1)); if (typ(gel(x,2)) != t_VEC) pari_err_TYPE(s,gel(x,2)); if (lg(gel(x,2)) != lgcols(x)) pari_err_DIM(s); } static long typv6(GEN x) { if (typ(gel(x,1)) == t_VEC && lg(gel(x,3)) == 3) { GEN t = gel(x,3); if (typ(t) != t_VEC) return typ_NULL; t = gel(x,5); switch(typ(gel(x,5))) { case t_VEC: return typ_BID; case t_MAT: return typ_BIDZ; default: return typ_NULL; } } if (typ(gel(x,2)) == t_COL && typ(gel(x,3)) == t_INT) return typ_PRID; return typ_NULL; } GEN get_bnf(GEN x, long *t) { switch(typ(x)) { case t_POL: *t = typ_POL; return NULL; case t_QUAD: *t = typ_Q ; return NULL; case t_VEC: switch(lg(x)) { case 5: if (typ(gel(x,1)) != t_INT) break; *t = typ_QUA; return NULL; case 6: *t = typv6(x); return NULL; case 7: *t = typ_BNR; x = bnr_get_bnf(x); if (typ(x)!=t_VEC || lg(x)!=11) break; return x; case 9: x = gel(x,2); if (typ(x) == t_VEC && lg(x) == 4) *t = typ_GAL; return NULL; case 10: *t = typ_NF; return NULL; case 11: *t = typ_BNF; return x; case 13: *t = typ_RNF; return NULL; case 17: *t = typ_ELL; return NULL; } break; case t_COL: if (get_prid(x)) { *t = typ_MODPR; return NULL; } break; } *t = typ_NULL; return NULL; } GEN get_nf(GEN x, long *t) { switch(typ(x)) { case t_POL : *t = typ_POL; return NULL; case t_QUAD: *t = typ_Q ; return NULL; case t_VEC: switch(lg(x)) { case 3: if (typ(gel(x,2)) != t_POLMOD) break; return get_nf(gel(x,1),t); case 5: if (typ(gel(x,1)) != t_INT) break; *t = typ_QUA; return NULL; case 6: *t = typv6(x); return NULL; case 7: *t = typ_BNR; x = bnr_get_bnf(x); if (typ(x)!=t_VEC || lg(x)!=11) break; x = bnf_get_nf(x); if (typ(x)!=t_VEC || lg(x)!=10) break; return x; case 9: x = gel(x,2); if (typ(x) == t_VEC && lg(x) == 4) *t = typ_GAL; return NULL; case 10: *t = typ_NF; return x; case 11: *t = typ_BNF; x = bnf_get_nf(x); if (typ(x)!=t_VEC || lg(x)!=10) break; return x; case 13: *t = typ_RNF; return NULL; case 17: *t = typ_ELL; return NULL; } break; case t_COL: if (get_prid(x)) { *t = typ_MODPR; return NULL; } break; } *t = typ_NULL; return NULL; } long nftyp(GEN x) { switch(typ(x)) { case t_POL : return typ_POL; case t_QUAD: return typ_Q; case t_VEC: switch(lg(x)) { case 13: return typ_RNF; case 10: if (typ(gel(x,1))!=t_POL) break; return typ_NF; case 11: x = bnf_get_nf(x); if (typ(x)!=t_VEC || lg(x)!=10) break; return typ_BNF; case 7: x = bnr_get_bnf(x); if (typ(x)!=t_VEC || lg(x)!=11) break; x = bnf_get_nf(x); if (typ(x)!=t_VEC || lg(x)!=10) break; return typ_BNR; case 6: return typv6(x); case 9: x = gel(x,2); if (typ(x) == t_VEC && lg(x) == 4) return typ_GAL; case 17: return typ_ELL; } } return typ_NULL; } /*************************************************************************/ /** **/ /** GALOIS GROUP **/ /** **/ /*************************************************************************/ GEN tschirnhaus(GEN x) { pari_sp av = avma, av2; long a, v = varn(x); GEN u, y = cgetg(5,t_POL); if (typ(x)!=t_POL) pari_err_TYPE("tschirnhaus",x); if (lg(x) < 4) pari_err_CONSTPOL("tschirnhaus"); if (v) { u = leafcopy(x); setvarn(u,0); x=u; } y[1] = evalsigne(1)|evalvarn(0); do { a = random_bits(2); if (a==0) a = 1; gel(y,4) = stoi(a); a = random_bits(3); if (a>=4) a -= 8; gel(y,3) = stoi(a); a = random_bits(3); if (a>=4) a -= 8; gel(y,2) = stoi(a); u = RgXQ_charpoly(y,x,v); av2 = avma; } while (degpol(RgX_gcd(u,RgX_deriv(u)))); /* while u not separable */ if (DEBUGLEVEL>1) err_printf("Tschirnhaus transform. New pol: %Ps",u); avma=av2; return gerepileupto(av,u); } /* Assume pol in Z[X], monic of degree n. Find L in Z such that * POL = L^(-n) pol(L x) is monic in Z[X]. Return POL and set *ptk = L. * No GC. */ GEN ZX_Z_normalize(GEN pol, GEN *ptk) { long i,j, sk, n = degpol(pol); /* > 0 */ GEN k, fa, P, E, a, POL; if (ptk) *ptk = gen_1; if (!n) return pol; a = pol + 2; k = gel(a,n-1); /* a[i] = coeff of degree i */ for (i = n-2; i >= 0; i--) { k = gcdii(k, gel(a,i)); if (is_pm1(k)) return pol; } sk = signe(k); if (!sk) return pol; /* monomial! */ fa = absZ_factor_limit(k, 0); k = gen_1; P = gel(fa,1); E = gel(fa,2); POL = leafcopy(pol); a = POL+2; for (i = lg(P)-1; i > 0; i--) { GEN p = gel(P,i), pv, pvj; long vmin = itos(gel(E,i)); /* find v_p(k) = min floor( v_p(a[i]) / (n-i)) */ for (j=n-1; j>=0; j--) { long v; if (!signe(gel(a,j))) continue; v = Z_pval(gel(a,j), p) / (n - j); if (v < vmin) vmin = v; } if (!vmin) continue; pvj = pv = powiu(p,vmin); k = mulii(k, pv); /* a[j] /= p^(v*(n-j)) */ for (j=n-1; j>=0; j--) { if (j < n-1) pvj = mulii(pvj, pv); gel(a,j) = diviiexact(gel(a,j), pvj); } } if (ptk) *ptk = k; return POL; } /* Assume pol != 0 in Z[X]. Find C in Q, L in Z such that POL = C pol(x/L) monic * in Z[X]. Return POL and set *pL = L. Wasteful (but correct) if pol is not * primitive: better if caller used Q_primpart already. No GC. */ GEN ZX_primitive_to_monic(GEN pol, GEN *pL) { long i,j, n = degpol(pol); GEN lc = leading_coeff(pol), L, fa, P, E, a, POL; if (is_pm1(lc)) { if (pL) *pL = gen_1; return signe(lc) < 0? ZX_neg(pol): pol; } if (signe(lc) < 0) POL = ZX_neg(pol); else POL = leafcopy(pol); a = POL+2; lc = gel(a,n); fa = Z_factor_limit(lc,0); L = gen_1; P = gel(fa,1); E = gel(fa,2); for (i = lg(P)-1; i > 0; i--) { GEN p = gel(P,i), pk, pku; long v, j0, e = itos(gel(E,i)), k = e/n, d = k*n - e; if (d < 0) { k++; d += n; } /* k = ceil(e[i] / n); find d, k such that p^d pol(x / p^k) monic */ for (j=n-1; j>0; j--) { if (!signe(gel(a,j))) continue; v = Z_pval(gel(a,j), p); while (v + d < k * j) { k++; d += n; } } pk = powiu(p,k); j0 = d/k; L = mulii(L, pk); pku = powiu(p,d - k*j0); /* a[j] *= p^(d - kj) */ for (j=j0; j>=0; j--) { if (j < j0) pku = mulii(pku, pk); gel(a,j) = mulii(gel(a,j), pku); } j0++; pku = powiu(p,k*j0 - d); /* a[j] /= p^(kj - d) */ for (j=j0; j<=n; j++) { if (j > j0) pku = mulii(pku, pk); gel(a,j) = diviiexact(gel(a,j), pku); } } if (pL) *pL = L; return POL; } /* Assume pol != 0 in Z[X]. Find C,L in Q such that POL = C pol(x/L) * monic in Z[X]. Return POL and set *pL = L. * Wasteful (but correct) if pol is not primitive: better if caller used * Q_primpart already. No GC. */ GEN ZX_Q_normalize(GEN pol, GEN *pL) { GEN lc, POL = ZX_primitive_to_monic(pol, &lc); POL = ZX_Z_normalize(POL, pL); if (pL) *pL = gdiv(lc, *pL); return POL; } GEN ZX_Q_mul(GEN A, GEN z) { pari_sp av = avma; long i, l = lg(A); GEN d, n, Ad, B, u; if (typ(z)==t_INT) return ZX_Z_mul(A,z); n = gel(z, 1); d = gel(z, 2); Ad = RgX_to_RgC(FpX_red(A, d), l-2); u = gcdii(d, FpV_factorback(Ad, NULL, d)); B = cgetg(l, t_POL); B[1] = A[1]; if (equali1(u)) { for(i=2; i 0? pol: ZX_neg(pol); } return ZX_primitive_to_monic(Q_primpart(pol), L); } /* Evaluate pol in s using nfelt arithmetic and Horner rule */ GEN nfpoleval(GEN nf, GEN pol, GEN s) { pari_sp av=avma; long i=lg(pol)-1; GEN res; if (i==1) return gen_0; res = nf_to_scalar_or_basis(nf, gel(pol,i)); for (i-- ; i>=2; i--) res = nfadd(nf, nfmul(nf, s, res), gel(pol,i)); return gerepileupto(av, res); } static GEN QX_table_nfpoleval(GEN nf, GEN pol, GEN m) { pari_sp av = avma; long i = lg(pol)-1; GEN res, den; if (i==1) return gen_0; pol = Q_remove_denom(pol, &den); res = scalarcol_shallow(gel(pol,i), nf_get_degree(nf)); for (i-- ; i>=2; i--) res = ZC_Z_add(ZM_ZC_mul(m, res), gel(pol,i)); if (den) res = RgC_Rg_div(res, den); return gerepileupto(av, res); } GEN FpX_FpC_nfpoleval(GEN nf, GEN pol, GEN a, GEN p) { pari_sp av=avma; long i=lg(pol)-1, n=nf_get_degree(nf); GEN res, Ma; if (i==1) return zerocol(n); Ma = FpM_red(zk_multable(nf, a), p); res = scalarcol(gel(pol,i),n); for (i-- ; i>=2; i--) { res = FpM_FpC_mul(Ma, res, p); gel(res,1) = Fp_add(gel(res,1), gel(pol,i), p); } return gerepileupto(av, res); } /* compute s(x), not stack clean */ static GEN ZC_galoisapply(GEN nf, GEN s, GEN x) { x = nf_to_scalar_or_alg(nf, x); if (typ(x) != t_POL) return scalarcol(x, nf_get_degree(nf)); return QX_table_nfpoleval(nf, x, zk_multable(nf, s)); } /* true nf; S = automorphism in basis form, return an FpC = S(z) mod p */ GEN zk_galoisapplymod(GEN nf, GEN z, GEN S, GEN p) { GEN den, pe, pe1, denpe, R; z = nf_to_scalar_or_alg(nf, z); if (typ(z) != t_POL) return z; if (gequalX(z)) return FpC_red(S, p); /* common, e.g. modpr_genFq */ z = Q_remove_denom(z,&den); denpe = pe = NULL; pe1 = p; if (den) { ulong e = Z_pvalrem(den, p, &den); if (e) { pe = powiu(p, e); pe1 = mulii(pe, p); } denpe = Fp_inv(den, pe1); } R = FpX_FpC_nfpoleval(nf, FpX_red(z, pe1), FpC_red(S, pe1), pe1); if (denpe) R = FpC_Fp_mul(R, denpe, pe1); if (pe) R = gdivexact(R, pe); return R; } /* true nf */ static GEN pr_galoisapply(GEN nf, GEN pr, GEN aut) { GEN p, t, u; if (typ(pr_get_tau(pr)) == t_INT) return pr; /* inert */ p = pr_get_p(pr); u = zk_galoisapplymod(nf, pr_get_gen(pr), aut, p); t = FpM_deplin(zk_multable(nf, u), p); t = zk_scalar_or_multable(nf, t); return mkvec5(p, u, gel(pr,3), gel(pr,4), t); } static GEN vecgaloisapply(GEN nf, GEN aut, GEN v) { long i, l; GEN V = cgetg_copy(v, &l); for (i = 1; i < l; i++) gel(V,i) = galoisapply(nf, aut, gel(v,i)); return V; } /* x: famat or standard algebraic number, aut automorphism in ZC form * simplified from general galoisapply */ static GEN elt_galoisapply(GEN nf, GEN aut, GEN x) { pari_sp av = avma; switch(typ(x)) { case t_INT: return icopy(x); case t_FRAC: return gcopy(x); case t_POLMOD: x = gel(x,2); /* fall through */ case t_POL: { GEN y = basistoalg(nf, ZC_galoisapply(nf, aut, x)); return gerepileupto(av,y); } case t_COL: return gerepileupto(av, ZC_galoisapply(nf, aut, x)); case t_MAT: switch(lg(x)) { case 1: return cgetg(1, t_MAT); case 3: retmkmat2(vecgaloisapply(nf,aut,gel(x,1)), ZC_copy(gel(x,2))); } } pari_err_TYPE("galoisapply",x); return NULL; /* LCOV_EXCL_LINE */ } GEN galoisapply(GEN nf, GEN aut, GEN x) { pari_sp av = avma; long lx; GEN y; nf = checknf(nf); switch(typ(x)) { case t_INT: return icopy(x); case t_FRAC: return gcopy(x); case t_POLMOD: x = gel(x,2); /* fall through */ case t_POL: aut = algtobasis(nf, aut); y = basistoalg(nf, ZC_galoisapply(nf, aut, x)); return gerepileupto(av,y); case t_VEC: aut = algtobasis(nf, aut); switch(lg(x)) { case 6: return gerepilecopy(av, pr_galoisapply(nf, x, aut)); case 3: y = cgetg(3,t_VEC); gel(y,1) = galoisapply(nf, aut, gel(x,1)); gel(y,2) = elt_galoisapply(nf, aut, gel(x,2)); return gerepileupto(av, y); } break; case t_COL: aut = algtobasis(nf, aut); return gerepileupto(av, ZC_galoisapply(nf, aut, x)); case t_MAT: /* ideal */ lx = lg(x); if (lx==1) return cgetg(1,t_MAT); if (nbrows(x) != nf_get_degree(nf)) break; y = RgM_mul(nfgaloismatrix(nf,aut), x); return gerepileupto(av, idealhnf_shallow(nf,y)); } pari_err_TYPE("galoisapply",x); return NULL; /* LCOV_EXCL_LINE */ } /* compute action of automorphism s on nf.zk */ GEN nfgaloismatrix(GEN nf, GEN s) { pari_sp av2, av = avma; GEN zk, D, M, H, m; long k, n; nf = checknf(nf); zk = nf_get_zkprimpart(nf); n = lg(zk)-1; M = cgetg(n+1, t_MAT); gel(M,1) = col_ei(n, 1); /* s(1) = 1 */ if (n == 1) return M; av2 = avma; if (typ(s) != t_COL) s = algtobasis(nf, s); D = nf_get_zkden(nf); H = RgV_to_RgM(zk, n); if (n == 2) { GEN t = gel(H,2); /* D * s(w_2) */ t = ZC_Z_add(ZC_Z_mul(s, gel(t,2)), gel(t,1)); gel(M,2) = gerepileupto(av2, gdiv(t, D)); return M; } m = zk_multable(nf, s); gel(M,2) = s; /* M[,k] = s(x^(k-1)) */ for (k = 3; k <= n; k++) gel(M,k) = ZM_ZC_mul(m, gel(M,k-1)); M = ZM_mul(M, H); if (!equali1(D)) M = ZM_Z_divexact(M, D); return gerepileupto(av, M); } static GEN get_aut(GEN nf, GEN gal, GEN aut, GEN g) { return aut ? gel(aut, g[1]): poltobasis(nf, galoispermtopol(gal, g)); } static GEN idealquasifrob(GEN nf, GEN gal, GEN grp, GEN pr, GEN subg, GEN *S, GEN aut) { pari_sp av = avma; long i, n = nf_get_degree(nf), f = pr_get_f(pr); GEN pi = pr_get_gen(pr); for (i=1; i<=n; i++) { GEN g = gel(grp,i); if ((!subg && perm_order(g)==f) || (subg && perm_relorder(g, subg)==f)) { *S = get_aut(nf, gal, aut, g); if (ZC_prdvd(ZC_galoisapply(nf, *S, pi), pr)) return g; avma = av; } } pari_err_BUG("idealquasifrob [Frobenius not found]"); return NULL; /*LCOV_EXCL_LINE*/ } GEN nfgaloispermtobasis(GEN nf, GEN gal) { GEN grp = gal_get_group(gal); long i, n = lg(grp)-1; GEN aut = cgetg(n+1, t_VEC); for(i=1; i<=n; i++) { pari_sp av = avma; GEN g = gel(grp, i); GEN vec = poltobasis(nf, galoispermtopol(gal, g)); gel(aut, g[1]) = gerepileupto(av, vec); } return aut; } static void gal_check_pol(const char *f, GEN x, GEN y) { if (!RgX_equal_var(x,y)) pari_err_MODULUS(f,x,y); } /* true nf */ GEN idealfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN aut) { pari_sp av = avma; GEN S=NULL, g=NULL; /*-Wall*/ GEN T, p, a, b, modpr; long f, n, s; f = pr_get_f(pr); n = nf_get_degree(nf); if (f==1) { avma = av; return identity_perm(n); } g = idealquasifrob(nf, gal, gal_get_group(gal), pr, NULL, &S, aut); if (f==2) return gerepileuptoleaf(av, g); modpr = zk_to_Fq_init(nf,&pr,&T,&p); a = pol_x(nf_get_varn(nf)); b = nf_to_Fq(nf, zk_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr); for (s = 1; s < f-1; s++) { a = Fq_pow(a, p, T, p); if (ZX_equal(a, b)) break; } g = perm_pow(g, Fl_inv(s, f)); return gerepileupto(av, g); } GEN idealfrobenius(GEN nf, GEN gal, GEN pr) { nf = checknf(nf); checkgal(gal); checkprid(pr); gal_check_pol("idealfrobenius",nf_get_pol(nf),gal_get_pol(gal)); if (pr_get_e(pr)>1) pari_err_DOMAIN("idealfrobenius","pr.e", ">", gen_1,pr); return idealfrobenius_aut(nf, gal, pr, NULL); } /* true nf */ GEN idealramfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN ram, GEN aut) { pari_sp av = avma; GEN S=NULL, g=NULL; /*-Wall*/ GEN T, p, a, b, modpr; GEN isog, deco; long f, n, s; f = pr_get_f(pr); n = nf_get_degree(nf); if (f==1) { avma = av; return identity_perm(n); } modpr = zk_to_Fq_init(nf,&pr,&T,&p); deco = group_elts(gel(ram,1), nf_get_degree(nf)); isog = group_set(gel(ram,2), nf_get_degree(nf)); g = idealquasifrob(nf, gal, deco, pr, isog, &S, aut); a = pol_x(nf_get_varn(nf)); b = nf_to_Fq(nf, zk_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr); for (s=0; !ZX_equal(a, b); s++) a = Fq_pow(a, p, T, p); g = perm_pow(g, Fl_inv(s, f)); return gerepileupto(av, g); } GEN idealramfrobenius(GEN nf, GEN gal, GEN pr, GEN ram) { return idealramfrobenius_aut(nf, gal, pr, ram, NULL); } static GEN idealinertiagroup(GEN nf, GEN gal, GEN aut, GEN pr) { long i, n = nf_get_degree(nf); GEN p, T, modpr = zk_to_Fq_init(nf,&pr,&T,&p); GEN b = modpr_genFq(modpr); long e = pr_get_e(pr), coprime = ugcd(e, pr_get_f(pr)) == 1; GEN grp = gal_get_group(gal), pi = pr_get_gen(pr); pari_sp ltop = avma; for (i=1; i<=n; i++) { GEN iso = gel(grp,i); if (perm_order(iso) == e) { GEN S = get_aut(nf, gal, aut, iso); if (ZC_prdvd(ZC_galoisapply(nf, S, pi), pr) && (coprime || gequalX(nf_to_Fq(nf, galoisapply(nf,S,b), modpr)))) return iso; avma = ltop; } } pari_err_BUG("idealinertiagroup [no isotropic element]"); return NULL; } static GEN idealramgroupstame(GEN nf, GEN gal, GEN aut, GEN pr) { pari_sp av = avma; GEN iso, frob, giso, isog, S, res; long e = pr_get_e(pr), f = pr_get_f(pr); GEN grp = gal_get_group(gal); if (e == 1) { if (f==1) return cgetg(1,t_VEC); frob = idealquasifrob(nf, gal, grp, pr, NULL, &S, aut); avma = av; res = cgetg(2, t_VEC); gel(res, 1) = cyclicgroup(frob, f); return res; } res = cgetg(3, t_VEC); av = avma; iso = idealinertiagroup(nf, gal, aut, pr); avma = av; giso = cyclicgroup(iso, e); gel(res, 2) = giso; if (f==1) { gel(res, 1) = giso; return res; } av = avma; isog = group_set(giso, nf_get_degree(nf)); frob = idealquasifrob(nf, gal, grp, pr, isog, &S, aut); avma = av; gel(res, 1) = dicyclicgroup(iso,frob,e,f); return res; } /* true nf, p | e */ static GEN idealramgroupswild(GEN nf, GEN gal, GEN aut, GEN pr) { pari_sp av2, av = avma; GEN p, T, idx, g, gbas, pi, pibas, Dpi, modpr = zk_to_Fq_init(nf,&pr,&T,&p); long bound, i, vDpi, vDg, n = nf_get_degree(nf); long e = pr_get_e(pr); long f = pr_get_f(pr); ulong nt,rorder; GEN pg, ppi, grp = gal_get_group(gal); /* G_i = {s: v(s(pi) - pi) > i} trivial for i > bound; * v_pr(Diff) = sum_{i = 0}^{bound} (#G_i - 1) >= e-1 + bound*(p-1)*/ bound = (idealval(nf, nf_get_diff(nf), pr) - (e-1)) / (itou(p)-1); (void) u_pvalrem(n,p,&nt); rorder = e*f*(n/nt); idx = const_vecsmall(n,-1); pg = NULL; vDg = 0; if (f == 1) g = gbas = NULL; else { GEN Dg; g = nf_to_scalar_or_alg(nf, modpr_genFq(modpr)); if (!gcmpX(g)) /* p | nf.index */ { g = Q_remove_denom(g, &Dg); vDg = Z_pval(Dg,p); pg = powiu(p, vDg + 1); g = FpX_red(g, pg); } gbas = nf_to_scalar_or_basis(nf, g); } pi = nf_to_scalar_or_alg(nf, pr_get_gen(pr)); pi = Q_remove_denom(pi, &Dpi); vDpi = Dpi ? Z_pval(Dpi, p): 0; ppi = powiu(p, vDpi + (bound + e)/e); pi = FpX_red(pi, ppi); pibas = nf_to_scalar_or_basis(nf, pi); av2 = avma; for (i = 2; i <= n; i++) { GEN S, Spi, piso, iso = gel(grp, i); long j, o, ix = iso[1]; if (idx[ix] >= 0 || rorder % (o = perm_order(iso))) continue; piso = iso; S = get_aut(nf, gal, aut, iso); Spi = FpX_FpC_nfpoleval(nf, pi, FpC_red(S, ppi), ppi); /* Computation made knowing that the valuation is <= bound + 1. Correct * to maximal value if reduction mod ppi altered this */ idx[ix] = minss(bound+1, idealval(nf, gsub(Spi,pibas), pr) - e*vDpi); if (idx[ix] == 0) idx[ix] = -1; else if (g) { GEN Sg = pg? FpX_FpC_nfpoleval(nf, g, FpC_red(S, pg), pg): S; if (vDg) { if (nfval(nf, gsub(Sg, gbas), pr) - e*vDg <= 0) idx[ix] = 0; } else /* same, more efficient */ { if (!ZC_prdvd(gsub(Sg, gbas), pr)) idx[ix] = 0; } } for (j = 2; j < o; j++) { piso = perm_mul(piso,iso); if (ugcd(j,o)==1) idx[ piso[1] ] = idx[ix]; } avma = av2; } return gerepileuptoleaf(av, idx); } GEN idealramgroups_aut(GEN nf, GEN gal, GEN pr, GEN aut) { pari_sp av = avma; GEN tbl, idx, res, set, sub; long i, j, e, n, maxm, p; ulong et; nf = checknf(nf); checkgal(gal); checkprid(pr); gal_check_pol("idealramgroups",nf_get_pol(nf),gal_get_pol(gal)); e = pr_get_e(pr); n = nf_get_degree(nf); p = itos(pr_get_p(pr)); if (e%p) return idealramgroupstame(nf, gal, aut, pr); (void) u_lvalrem(e,p,&et); idx = idealramgroupswild(nf, gal, aut, pr); sub = group_subgroups(galois_group(gal)); tbl = subgroups_tableset(sub, n); maxm = vecsmall_max(idx)+1; res = cgetg(maxm+1,t_VEC); set = zero_F2v(n); F2v_set(set,1); for(i=maxm; i>0; i--) { long ix; for(j=1;j<=n;j++) if (idx[j]==i-1) F2v_set(set,j); ix = tableset_find_index(tbl, set); if (ix==0) pari_err_BUG("idealramgroups"); gel(res,i) = gel(sub, ix); } return gerepilecopy(av, res); } GEN idealramgroups(GEN nf, GEN gal, GEN pr) { return idealramgroups_aut(nf, gal, pr, NULL); } /* x = relative polynomial nf = absolute nf, bnf = absolute bnf */ GEN get_bnfpol(GEN x, GEN *bnf, GEN *nf) { *bnf = checkbnf_i(x); *nf = checknf_i(x); if (*nf) x = nf_get_pol(*nf); if (typ(x) != t_POL) pari_err_TYPE("get_bnfpol",x); return x; } GEN get_nfpol(GEN x, GEN *nf) { if (typ(x) == t_POL) { *nf = NULL; return x; } *nf = checknf(x); return nf_get_pol(*nf); } static GEN incl_disc(GEN nfa, GEN a, int nolocal) { GEN d; if (nfa) return nf_get_disc(nfa); if (nolocal) return NULL; d = ZX_disc(a); if (!signe(d)) pari_err_IRREDPOL("nfisincl",a); return d; } /* is isomorphism / inclusion (a \subset b) compatible with what we know about * basic invariants ? (degree, signature, discriminant); test for isomorphism * if fliso is set and for inclusion otherwise */ static int tests_OK(GEN a, GEN nfa, GEN b, GEN nfb, long fliso) { GEN da2, da, db, fa, P, E, U; long i, l, nP, q, m = degpol(a), n = degpol(b); if (m <= 0) pari_err_IRREDPOL("nfisincl",a); if (n <= 0) pari_err_IRREDPOL("nfisincl",b); q = n / m; /* relative degree */ if (fliso) { if (n != m) return 0; } else { if (n % m) return 0; } if (m == 1) return 1; /*local test expensive if n^2 >> m^4 <=> q = n/m >> m */ db = incl_disc(nfb, b, q > m); da = db? incl_disc(nfa, a, 0): NULL; if (nfa && nfb) /* both nf structures available */ { long r1a = nf_get_r1(nfa), r1b = nf_get_r1(nfb); return fliso ? (r1a == r1b && equalii(da, db)) : (r1b <= r1a * q && dvdii(db, powiu(da, q))); } if (!db) return 1; if (fliso) return issquare(gdiv(da,db)); if (nfa) { P = nf_get_ramified_primes(nfa); l = lg(P); for (i = 1; i < l; i++) if (Z_pval(db, gel(P,i)) < q * Z_pval(da, gel(P,i))) return 0; return 1; } else if (nfb) { P = nf_get_ramified_primes(nfb); l = lg(P); for (i = 1; i < l; i++) { long va = Z_pval(da, gel(P,i)); if (va && Z_pval(db, gel(P,i)) < q * va) return 0; } return 1; } /* da = dK A^2, db = dL B^2, dL = dK^q * N(D) * da = da1 * da2, da2 maximal s.t. (da2, db) = 1: let p a prime divisor of * da2 then p \nmid da1 * dK and p | A => v_p(da) = v_p(da2) is even */ da2 = Z_ppo(da, db); if (!is_pm1(da2)) { /* replace da by da1 all of whose prime divisors divide db */ da2 = absi_shallow(da2); if (!Z_issquare(da2)) return 0; da = diviiexact(da, da2); } if (is_pm1(da)) return 1; fa = absZ_factor_limit(da, 0); P = gel(fa,1); E = gel(fa,2); nP = lg(P) - 1; for (i=1; i 0) { fa = Z_factor(U); P = gel(fa,1); E = gel(fa,2); } else { P = mkvec(U); E = mkvec(gen_1); } nP = lg(P) - 1; for (i=1; i<=nP; i++) if (mod2(gel(E,i)) && !dvdii(db, powiu(gel(P,i),q))) return 0; } return 1; } GEN nfisisom(GEN a, GEN b) { pari_sp av = avma; long i, va, vb, lx; GEN nfa, nfb, y, la, lb; int newvar, sw = 0; a = get_nfpol(a, &nfa); b = get_nfpol(b, &nfb); if (!nfa) { a = Q_primpart(a); RgX_check_ZX(a, "nfisisom"); } if (!nfb) { b = Q_primpart(b); RgX_check_ZX(b, "nfisisom"); } if (nfa && !nfb) { swap(a,b); nfb = nfa; nfa = NULL; sw = 1; } if (!tests_OK(a, nfa, b, nfb, 1)) { avma = av; return gen_0; } if (nfb) lb = gen_1; else nfb = b = ZX_Q_normalize(b,&lb); if (nfa) la = gen_1; else nfa = a = ZX_Q_normalize(a,&la); va = varn(a); vb = varn(b); newvar = (varncmp(vb,va) <= 0); if (newvar) { a = leafcopy(a); setvarn(a, fetch_var_higher()); } y = lift_shallow(nfroots(nfb,a)); if (newvar) (void)delete_var(); lx = lg(y); if (lx==1) { avma=av; return gen_0; } if (sw) { vb = va; b = leafcopy(b); setvarn(b, vb); } for (i=1; i 2) gel(M1i, j-1) = gel(Wj, 2); for (k=3, u=j-1; k> 1; } else { long n = degpol(x); z = (r1 == n)? realroots(x, NULL, prec): QX_complex_roots(x,prec); ru = (n+r1)>>1; } for (i=r1+1; i<=ru; i++) gel(z,i) = gel(z, (i<<1)-r1); z[0]=evaltyp(t_VEC)|evallg(ru+1); return z; } GEN nf_get_allroots(GEN nf) { return embed_roots(nf_get_roots(nf), nf_get_r1(nf)); } /* For internal use. compute trace(x mod pol), sym=polsym(pol,deg(pol)-1) */ GEN quicktrace(GEN x, GEN sym) { GEN p1 = gen_0; long i; if (typ(x) != t_POL) return gmul(x, gel(sym,1)); if (signe(x)) { sym--; for (i=lg(x)-1; i>1; i--) p1 = gadd(p1, gmul(gel(x,i),gel(sym,i))); } return p1; } static GEN get_Tr(GEN mul, GEN x, GEN basden) { GEN t, bas = gel(basden,1), den = gel(basden,2); long i, j, n = lg(bas)-1; GEN T = cgetg(n+1,t_MAT), TW = cgetg(n+1,t_COL), sym = polsym(x, n-1); gel(TW,1) = utoipos(n); for (i=2; i<=n; i++) { t = quicktrace(gel(bas,i), sym); if (den && gel(den,i)) t = diviiexact(t,gel(den,i)); gel(TW,i) = t; /* tr(w[i]) */ } gel(T,1) = TW; for (i=2; i<=n; i++) { gel(T,i) = cgetg(n+1,t_COL); gcoeff(T,1,i) = gel(TW,i); for (j=2; j<=i; j++) /* Tr(W[i]W[j]) */ gcoeff(T,i,j) = gcoeff(T,j,i) = ZV_dotproduct(gel(mul,j+(i-1)*n), TW); } return T; } /* return [bas[i]*denom(bas[i]), denom(bas[i])], denom 1 is given as NULL */ static GEN get_bas_den(GEN bas) { GEN b,d,den, dbas = leafcopy(bas); long i, l = lg(bas); int power = 1; den = cgetg(l,t_VEC); for (i=1; ibasis */ static GEN nf_multable(nfmaxord_t *S, GEN invbas) { GEN T = S->T, w = gel(S->basden,1), den = gel(S->basden,2); long i,j, n = degpol(T); GEN mul = cgetg(n*n+1,t_MAT); /* i = 1 split for efficiency, assume w[1] = 1 */ for (j=1; j<=n; j++) gel(mul,j) = gel(mul,1+(j-1)*n) = col_ei(n, j); for (i=2; i<=n; i++) for (j=i; j<=n; j++) { pari_sp av = avma; GEN z = (i == j)? ZXQ_sqr(gel(w,i), T): ZXQ_mul(gel(w,i),gel(w,j), T); z = ZM_ZX_mul(invbas, z); /* integral column */ if (den) { GEN d = mul_denom(gel(den,i), gel(den,j)); if (d) z = ZC_Z_divexact(z, d); } gel(mul,j+(i-1)*n) = gel(mul,i+(j-1)*n) = gerepileupto(av,z); } return mul; } /* as get_Tr, mul_table not precomputed */ static GEN make_Tr(nfmaxord_t *S) { GEN T = S->T, w = gel(S->basden,1), den = gel(S->basden,2); long i,j, n = degpol(T); GEN c, t, d, M = cgetg(n+1,t_MAT), sym = polsym(T, n-1); /* W[i] = w[i]/den[i]; assume W[1] = 1, case i = 1 split for efficiency */ c = cgetg(n+1,t_COL); gel(M,1) = c; gel(c, 1) = utoipos(n); for (j=2; j<=n; j++) { pari_sp av = avma; t = quicktrace(gel(w,j), sym); if (den) { d = gel(den,j); if (d) t = diviiexact(t, d); } gel(c,j) = gerepileuptoint(av, t); } for (i=2; i<=n; i++) { c = cgetg(n+1,t_COL); gel(M,i) = c; for (j=1; jbasden,1), den = gel(F->basden,2), ro = F->ro; GEN m, d, M; long i, j, l = lg(ro), n = lg(bas); M = cgetg(n,t_MAT); gel(M,1) = const_col(l-1, gen_1); /* bas[1] = 1 */ for (j=2; j 1)? ginv(r): NULL; for (j=2; j F->prec) { M = gprec_w(M, F->prec); F->ro = gprec_w(ro,F->prec); } F->M = M; } /* return G real such that G~ * G = T_2 */ static void make_G(nffp_t *F) { GEN G, M = F->M; long i, j, k, r1 = F->r1, l = lg(M); if (r1 == l-1) { F->G = M; return; } G = cgetg(l, t_MAT); for (j = 1; j < l; j++) { GEN g, m = gel(M,j); gel(G,j) = g = cgetg(l, t_COL); for (k = i = 1; i <= r1; i++) gel(g,k++) = gel(m,i); for ( ; k < l; i++) { GEN r = gel(m,i); if (typ(r) == t_COMPLEX) { GEN a = gel(r,1), b = gel(r,2); gel(g,k++) = mpadd(a, b); gel(g,k++) = mpsub(a, b); } else { gel(g,k++) = r; gel(g,k++) = r; } } } F->G = G; } static void make_M_G(nffp_t *F, int trunc) { long n, eBD, prec; if (F->extraprec < 0) { /* not initialized yet; compute roots so that absolute accuracy * of M & G >= prec */ double er; n = degpol(F->T); eBD = 1 + gexpo(gel(F->basden,1)); er = F->ro? (1+gexpo(F->ro)): fujiwara_bound(F->T); if (er < 0) er = 0; F->extraprec = nbits2extraprec(n*er + eBD + log2(n)); } prec = F->prec + F->extraprec; #ifndef LONG_IS_64BIT /* make sure that default accuracy is the same on 32/64bit */ if (odd(prec)) prec += EXTRAPRECWORD; #endif if (!F->ro || gprecision(gel(F->ro,1)) < prec) F->ro = get_roots(F->T, F->r1, prec); make_M(F, trunc); make_G(F); } static void nffp_init(nffp_t *F, nfmaxord_t *S, long prec) { F->T = S->T; F->r1 = S->r1; F->basden = S->basden; F->ro = NULL; F->extraprec = -1; F->prec = prec; } /* let bas a t_VEC of QX giving a Z-basis of O_K. Return the index of the * basis. Assume bas[1] = 1 and that the leading coefficient of elements * of bas are of the form 1/b for a t_INT b */ static GEN get_nfindex(GEN bas) { pari_sp av = avma; long n = lg(bas)-1, i; GEN D, d, mat; /* assume bas[1] = 1 */ D = gel(bas,1); if (! is_pm1(simplify_shallow(D))) pari_err_TYPE("get_nfindex", D); D = gen_1; for (i = 2; i <= n; i++) { /* after nfbasis, basis is upper triangular! */ GEN B = gel(bas,i), lc; if (degpol(B) != i-1) break; lc = gel(B, i+1); switch (typ(lc)) { case t_INT: continue; case t_FRAC: if (is_pm1(gel(lc,1)) ) {D = mulii(D, gel(lc,2)); continue;} default: pari_err_TYPE("get_nfindex", B); } } if (i <= n) { /* not triangular after all */ bas = vecslice(bas,i,n); bas = Q_remove_denom(bas, &d); if (!d) return D; mat = RgV_to_RgM(bas, n); mat = rowslice(mat, i,n); D = mulii(D, diviiexact(powiu(d, n-i+1), absi_shallow(ZM_det(mat)))); } return gerepileuptoint(av, D); } /* make sure all components of S are initialized */ static void nfmaxord_complete(nfmaxord_t *S) { if (!S->dT) S->dT = ZX_disc(S->T); if (!S->index) { if (S->dK) /* fast */ S->index = sqrti( diviiexact(S->dT, S->dK) ); else S->index = get_nfindex(S->basis); } if (!S->dK) S->dK = diviiexact(S->dT, sqri(S->index)); if (S->r1 < 0) S->r1 = ZX_sturm(S->T); if (!S->basden) S->basden = get_bas_den(S->basis); } GEN nfmaxord_to_nf(nfmaxord_t *S, GEN ro, long prec) { GEN nf = cgetg(10,t_VEC); GEN T = S->T, Tr, D, w, A, dA, MDI, mat = cgetg(9,t_VEC); long n = degpol(T); nffp_t F; nfmaxord_complete(S); nffp_init(&F,S,prec); F.ro = ro; make_M_G(&F, 0); gel(nf,1) = S->T; gel(nf,2) = mkvec2s(S->r1, (n - S->r1)>>1); gel(nf,3) = S->dK; gel(nf,4) = S->index; gel(nf,5) = mat; gel(nf,6) = F.ro; w = S->basis; if (!is_pm1(S->index)) w = Q_remove_denom(w, NULL); gel(nf,7) = w; gel(nf,8) = ZM_inv(RgV_to_RgM(w,n), NULL); gel(nf,9) = nf_multable(S, nf_get_invzk(nf)); gel(mat,1) = F.M; gel(mat,2) = F.G; Tr = get_Tr(gel(nf,9), T, S->basden); gel(mat,6) = A = ZM_inv(Tr, &dA); /* dA T^-1, primitive */ A = ZM_hnfmodid(A, dA); /* CAVEAT: nf is not complete yet, but the fields needed for * idealtwoelt, zk_scalar_or_multable and idealinv are present ! */ MDI = idealtwoelt(nf, A); gel(MDI,2) = zk_scalar_or_multable(nf, gel(MDI,2)); gel(mat,7) = MDI; if (is_pm1(S->index)) { /* principal ideal (T'), whose norm is |dK| */ D = zk_scalar_or_multable(nf, ZX_deriv(T)); if (typ(D) == t_MAT) D = ZM_hnfmod(D, absi_shallow(S->dK)); } else { GEN c = diviiexact(dA, gcoeff(A,1,1)); D = idealHNF_inv_Z(nf, A); /* (A\cap Z) / A */ if (!is_pm1(c)) D = ZM_Z_mul(D, c); } gel(mat,3) = RM_round_maxrank(F.G); gel(mat,4) = Tr; gel(mat,5) = D; gel(mat,8) = S->dKP? shallowtrans(S->dKP): cgetg(1,t_VEC); return nf; } static GEN primes_certify(GEN dK, GEN dKP) { long i, l = lg(dKP); GEN v, w, D = dK; v = vectrunc_init(l); w = vectrunc_init(l); for (i = 1; i < l; i++) { GEN p = gel(dKP,i); vectrunc_append(isprime(p)? w: v, p); (void)Z_pvalrem(D, p, &D); } if (!is_pm1(D)) { if (signe(D) < 0) D = negi(D); vectrunc_append(isprime(D)? w: v, D); } return mkvec2(v,w); } GEN nfcertify(GEN nf) { pari_sp av = avma; GEN vw; nf = checknf(nf); vw = primes_certify(nf_get_disc(nf), nf_get_ramified_primes(nf)); return gerepilecopy(av, gel(vw,1)); } /* set *pro to roots of S->T */ static GEN get_red_G(nfmaxord_t *S, GEN *pro) { GEN G, u, u0 = NULL; pari_sp av; long i, prec, n = degpol(S->T); nffp_t F; prec = nbits2prec(n+32); nffp_init(&F, S, prec); av = avma; for (i=1; ; i++) { F.prec = prec; make_M_G(&F, 0); G = F.G; if (u0) G = RgM_mul(G, u0); if (DEBUGLEVEL) err_printf("get_red_G: starting LLL, prec = %ld (%ld + %ld)\n", prec + F.extraprec, prec, F.extraprec); if ((u = lllfp(G, 0.99, LLL_KEEP_FIRST|LLL_COMPATIBLE))) { if (lg(u)-1 == n) break; /* singular ==> loss of accuracy */ if (u0) u0 = gerepileupto(av, RgM_mul(u0,u)); else u0 = gerepilecopy(av, u); } prec = precdbl(prec) + nbits2extraprec(gexpo(u0)); F.ro = NULL; if (DEBUGLEVEL) pari_warn(warnprec,"get_red_G", prec); } if (u0) u = RgM_mul(u0,u); *pro = F.ro; return u; } /* Compute an LLL-reduced basis for the integer basis of nf(T). * set *pro = roots of x if computed [NULL if not computed] */ static void set_LLL_basis(nfmaxord_t *S, GEN *pro, double DELTA) { GEN B = S->basis; if (S->r1 < 0) S->r1 = ZX_sturm(S->T); if (!S->basden) S->basden = get_bas_den(B); if (S->r1 == degpol(S->T)) { pari_sp av = avma; GEN u = ZM_lll(make_Tr(S), DELTA, LLL_GRAM|LLL_KEEP_FIRST|LLL_IM|LLL_COMPATIBLE); B = gerepileupto(av, RgV_RgM_mul(B, u)); *pro = NULL; } else B = RgV_RgM_mul(B, get_red_G(S, pro)); S->basis = B; S->basden = get_bas_den(B); } /* = 1 iff |a| > |b| or equality and a > 0 */ static int cmpii_polred(GEN a, GEN b) { int fl = abscmpii(a, b); long sa, sb; if (fl) return fl; sa = signe(a); sb = signe(b); if (sa == sb) return 0; return sa == 1? 1: -1; } static int ZX_cmp(GEN x, GEN y) { return gen_cmp_RgX((void*)cmpii_polred, x, y); } /* current best: ZX x of discriminant *dx, is ZX y better than x ? * (if so update *dx); both x and y are monic */ static int ZX_is_better(GEN y, GEN x, GEN *dx) { GEN d = ZX_disc(y); int cmp; if (!*dx) *dx = ZX_disc(x); cmp = abscmpii(d, *dx); if (cmp < 0) { *dx = d; return 1; } return cmp? 0: (ZX_cmp(y, x) < 0); } static void polredbest_aux(nfmaxord_t *S, GEN *pro, GEN *px, GEN *pdx, GEN *pa); /* Seek a simpler, polynomial pol defining the same number field as * x (assumed to be monic at this point) */ static GEN nfpolred(nfmaxord_t *S, GEN *pro) { GEN x = S->T, dx, b, rev; long n = degpol(x), v = varn(x); if (n == 1) { S->T = pol_x(v); *pro = NULL; return scalarpol_shallow(negi(gel(x,2)), v); } polredbest_aux(S, pro, &x, &dx, &b); if (x == S->T) return NULL; /* no improvement */ if (DEBUGLEVEL>1) err_printf("xbest = %Ps\n",x); /* update T */ rev = QXQ_reverse(b, S->T); S->basis = QXV_QXQ_eval(S->basis, rev, x); S->index = sqrti( diviiexact(dx,S->dK) ); S->basden = get_bas_den(S->basis); S->dT = dx; S->T = x; *pro = NULL; /* reset */ return rev; } /* Either nf type or ZX or [monic ZX, data], where data is either an integral * basis (deprecated), or listP data (nfbasis input format) to specify * a set of primes at with the basis order must be maximal. * 1) nf type (or unrecognized): return t_VEC * 2) ZX or [ZX, listP]: return t_POL * 3) [ZX, order basis]: return 0 (deprecated) * incorrect: return -1 */ static long nf_input_type(GEN x) { GEN T, V; long i, d, v; switch(typ(x)) { case t_POL: return t_POL; case t_VEC: if (lg(x) != 3) return t_VEC; /* nf or incorrect */ T = gel(x,1); V = gel(x,2); if (typ(T) != t_POL) return -1; switch(typ(V)) { case t_INT: case t_MAT: return t_POL; case t_VEC: case t_COL: if (RgV_is_ZV(V)) return t_POL; break; default: return -1; } d = degpol(T); v = varn(T); if (d<1 || !RgX_is_ZX(T) || !isint1(gel(T,d+2)) || lg(V)-1!=d) return -1; for (i = 1; i <= d; i++) { /* check integer basis */ GEN c = gel(V,i); switch(typ(c)) { case t_INT: break; case t_POL: if (varn(c) == v && RgX_is_QX(c) && degpol(c) < d) break; /* fall through */ default: return -1; } } return 0; } return t_VEC; /* nf or incorrect */ } /* cater for obsolete nf_PARTIALFACT flag */ static void nfinit_basic_partial(nfmaxord_t *S, GEN T) { if (typ(T) == t_POL) { nfmaxord(S, mkvec2(T,utoipos(500000)), 0); } else nfinit_basic(S, T); } /* true nf */ static GEN nf_basden(GEN nf) { GEN zkD = nf_get_zkprimpart(nf), D = nf_get_zkden(nf); D = equali1(D)? NULL: const_vec(lg(zkD)-1, D); return mkvec2(zkD, D); } void nfinit_basic(nfmaxord_t *S, GEN T) { long t = nf_input_type(T); if (t == t_POL) { nfmaxord(S, T, 0); return; } S->dTP = S->dTE = S->dKE = S->basden = NULL; switch (t) { case t_VEC: { /* nf, bnf, bnr */ GEN nf = checknf(T); S->T = S->T0 = nf_get_pol(nf); S->basis = nf_get_zk(nf); /* probably useless */ S->basden = nf_basden(nf); S->index = nf_get_index(nf); S->dK = nf_get_disc(nf); S->dKP = nf_get_ramified_primes(nf); S->dT = mulii(S->dK, sqri(S->index)); S->r1 = nf_get_r1(nf); break; } case 0: /* monic integral polynomial + integer basis */ S->T = S->T0 = gel(T,1); S->basis = gel(T,2); S->index = NULL; S->dK = NULL; S->dKP = NULL; S->dT = NULL; S->r1 = -1; break; default: /* -1 */ pari_err_TYPE("nfbasic_init", T); return; } S->unscale = gen_1; } GEN nfinit_complete(nfmaxord_t *S, long flag, long prec) { GEN nf, unscale; if (!ZX_is_irred(S->T)) pari_err_IRREDPOL("nfinit",S->T); if (!(flag & nf_RED) && !ZX_is_monic(S->T0)) { pari_warn(warner,"non-monic polynomial. Result of the form [nf,c]"); flag |= nf_RED | nf_ORIG; } unscale = S->unscale; if (!(flag & nf_RED) && !isint1(unscale)) { /* implies lc(x0) = 1 and L := 1/unscale is integral */ long d = degpol(S->T0); GEN L = ginv(unscale); /* x = L^(-deg(x)) x0(L X) */ GEN f= powiu(L, (d*(d-1)) >> 1); S->T = S->T0; /* restore original user-supplied x0, unscale data */ S->unscale = gen_1; S->dT = gmul(S->dT, sqri(f)); S->basis = RgXV_unscale(S->basis, unscale); S->index = gmul(S->index, f); } nfmaxord_complete(S); /* more expensive after set_LLL_basis */ if (flag & nf_RED) { GEN ro, rev; /* lie to polred: more efficient to update *after* modreverse, than to * unscale in the polred subsystem */ S->unscale = gen_1; rev = nfpolred(S, &ro); nf = nfmaxord_to_nf(S, ro, prec); if (flag & nf_ORIG) { if (!rev) rev = pol_x(varn(S->T)); /* no improvement */ if (!isint1(unscale)) rev = RgX_Rg_div(rev, unscale); nf = mkvec2(nf, mkpolmod(rev, S->T)); } S->unscale = unscale; /* restore */ } else { GEN ro; set_LLL_basis(S, &ro, 0.99); nf = nfmaxord_to_nf(S, ro, prec); } return nf; } /* Initialize the number field defined by the polynomial x (in variable v) * flag & nf_RED: try a polred first. * flag & nf_ORIG * do a polred and return [nfinit(x), Mod(a,red)], where * Mod(a,red) = Mod(v,x) (i.e return the base change). */ GEN nfinitall(GEN x, long flag, long prec) { const pari_sp av = avma; nfmaxord_t S; GEN nf; if (checkrnf_i(x)) return rnf_build_nfabs(x, prec); nfinit_basic(&S, x); nf = nfinit_complete(&S, flag, prec); return gerepilecopy(av, nf); } GEN nfinitred(GEN x, long prec) { return nfinitall(x, nf_RED, prec); } GEN nfinitred2(GEN x, long prec) { return nfinitall(x, nf_RED|nf_ORIG, prec); } GEN nfinit(GEN x, long prec) { return nfinitall(x, 0, prec); } GEN nfinit0(GEN x, long flag,long prec) { switch(flag) { case 0: case 1: return nfinitall(x,0,prec); case 2: case 4: return nfinitall(x,nf_RED,prec); case 3: case 5: return nfinitall(x,nf_RED|nf_ORIG,prec); default: pari_err_FLAG("nfinit"); } return NULL; /* LCOV_EXCL_LINE */ } /* assume x a bnr/bnf/nf */ long nf_get_prec(GEN x) { GEN nf = checknf(x), ro = nf_get_roots(nf); return (typ(ro)==t_VEC)? precision(gel(ro,1)): DEFAULTPREC; } /* true nf */ GEN nfnewprec_shallow(GEN nf, long prec) { GEN m, NF = leafcopy(nf); nffp_t F; F.T = nf_get_pol(nf); F.ro = NULL; F.r1 = nf_get_r1(nf); F.basden = nf_basden(nf); F.extraprec = -1; F.prec = prec; make_M_G(&F, 1); gel(NF,5) = m = leafcopy(gel(NF,5)); gel(m,1) = F.M; gel(m,2) = F.G; gel(NF,6) = F.ro; return NF; } GEN nfnewprec(GEN nf, long prec) { GEN z; switch(nftyp(nf)) { default: pari_err_TYPE("nfnewprec", nf); case typ_BNF: z = bnfnewprec(nf,prec); break; case typ_BNR: z = bnrnewprec(nf,prec); break; case typ_NF: { pari_sp av = avma; z = gerepilecopy(av, nfnewprec_shallow(checknf(nf), prec)); break; } } return z; } /********************************************************************/ /** **/ /** POLRED **/ /** **/ /********************************************************************/ GEN embednorm_T2(GEN x, long r1) { pari_sp av = avma; GEN p = RgV_sumpart(x, r1); GEN q = RgV_sumpart2(x,r1+1, lg(x)-1); if (q != gen_0) p = gadd(p, gmul2n(q,1)); return avma == av? gcopy(p): gerepileupto(av, p); } /* simplified version of gnorm for scalar, non-complex inputs, without GC */ static GEN real_norm(GEN x) { switch(typ(x)) { case t_INT: return sqri(x); case t_REAL: return sqrr(x); case t_FRAC: return sqrfrac(x); } pari_err_TYPE("real_norm", x); return NULL; } /* simplified version of gnorm, without GC */ static GEN complex_norm(GEN x) { return typ(x) == t_COMPLEX? cxnorm(x): real_norm(x); } /* return T2(x), argument r1 needed in case x has components whose type * is unexpected, e.g. all of them t_INT for embed(gen_1) */ GEN embed_T2(GEN x, long r1) { pari_sp av = avma; long i, l = lg(x); GEN c, s = NULL, t = NULL; if (typ(gel(x,1)) == t_INT) return muliu(gel(x,1), 2*(l-1)-r1); for (i = 1; i <= r1; i++) { c = real_norm(gel(x,i)); s = s? gadd(s, c): c; } for (; i < l; i++) { c = complex_norm(gel(x,i)); t = t? gadd(t, c): c; } if (t) { t = gmul2n(t,1); s = s? gadd(s,t): t; } return gerepileupto(av, s); } /* return N(x) */ GEN embed_norm(GEN x, long r1) { pari_sp av = avma; long i, l = lg(x); GEN c, s = NULL, t = NULL; if (typ(gel(x,1)) == t_INT) return powiu(gel(x,1), 2*(l-1)-r1); for (i = 1; i <= r1; i++) { c = gel(x,i); s = s? gmul(s, c): c; } for (; i < l; i++) { c = complex_norm(gel(x,i)); t = t? gmul(t, c): c; } if (t) s = s? gmul(s,t): t; return gerepileupto(av, s); } typedef struct { long r1, v, prec; GEN ZKembed; /* embeddings of fincke-pohst-reduced Zk basis */ GEN u; /* matrix giving fincke-pohst-reduced Zk basis */ GEN M; /* embeddings of initial (LLL-reduced) Zk basis */ GEN bound; /* T2 norm of the polynomial defining nf */ long expo_best_disc; /* expo(disc(x)), best generator so far */ } CG_data; /* characteristic pol of x (given by embeddings) */ static GEN get_pol(CG_data *d, GEN x) { long e; GEN g = grndtoi(roots_to_pol_r1(x, d->v, d->r1), &e); return (e > -5)? NULL: g; } /* characteristic pol of x (given as vector on (w_i)) */ static GEN get_polchar(CG_data *d, GEN x) { return get_pol(d, RgM_RgC_mul(d->ZKembed,x)); } /* Choose a canonical polynomial in the pair { Pmin_a, Pmin_{-a} }, i.e. * { z(X), (-1)^(deg z) z(-Z) } and keeping the smallest wrt cmpii_polred * Either leave z alone (return 1) or set z <- (-1)^n z(-X). In place. */ static int ZX_canon_neg(GEN z) { long i, s; for (i = lg(z)-2; i >= 2; i -= 2) { /* examine the odd (resp. even) part of z if deg(z) even (resp. odd). */ s = signe(gel(z,i)); if (!s) continue; /* non trivial */ if (s < 0) break; /* z(X) < (-1)^n z(-X) */ for (; i>=2; i-=2) gel(z,i) = negi(gel(z,i)); return 1; } return 0; } /* return a defining polynomial for Q(alpha), v = embeddings of alpha. * Return NULL on failure: discriminant too large or non primitive */ static GEN try_polmin(CG_data *d, nfmaxord_t *S, GEN v, long flag, GEN *ai) { const long best = flag & nf_ABSOLUTE; long ed; pari_sp av = avma; GEN g; if (best) { ed = expo(embed_disc(v, d->r1, LOWDEFAULTPREC)); avma = av; if (d->expo_best_disc < ed) return NULL; } else ed = 0; g = get_pol(d, v); /* accuracy too low, compute algebraically */ if (!g) { avma = av; g = ZXQ_charpoly(*ai, S->T, varn(S->T)); } g = ZX_radical(g); if (best && degpol(g) != degpol(S->T)) { avma = av; return NULL; } g = gerepilecopy(av, g); d->expo_best_disc = ed; if (flag & nf_ORIG) { if (ZX_canon_neg(g)) *ai = RgX_neg(*ai); if (!isint1(S->unscale)) *ai = RgX_unscale(*ai, S->unscale); } else (void)ZX_canon_neg(g); if (DEBUGLEVEL>3) err_printf("polred: generator %Ps\n", g); return g; } /* does x generate the correct field ? */ static GEN chk_gen(void *data, GEN x) { pari_sp av = avma, av1; GEN h, g = get_polchar((CG_data*)data,x); if (!g) pari_err_PREC("chk_gen"); av1 = avma; h = ZX_gcd(g, ZX_deriv(g)); if (degpol(h)) { avma = av; return NULL; } if (DEBUGLEVEL>3) err_printf(" generator: %Ps\n",g); avma = av1; return gerepileupto(av, g); } static long chk_gen_prec(long N, long bit) { return nbits2prec(10 + (long)log2((double)N) + bit); } /* v = [P,A] two vectors (of ZX and ZV resp.) of same length; remove duplicate * polynomials in P, updating A, in place. Among elements having the same * characteristic pol, choose the smallest according to ZV_abscmp */ static void remove_duplicates(GEN v) { GEN x, a, P = gel(v,1), A = gel(v,2); long k, i, l = lg(P); pari_sp av = avma; if (l < 2) return; (void)sort_factor_pol(mkvec2(P, A), cmpii); x = gel(P,1); a = gel(A,1); for (k=1,i=2; iT); double log2rho; GEN ro; set_LLL_basis(S, &ro, 0.9999); /* || polchar ||_oo < 2^e ~ 2 (n * rho)^n, rho = max modulus of root */ log2rho = ro ? (double)gexpo(ro): fujiwara_bound(S->T); e = n * (long)(log2rho + log2((double)n)) + 1; if (e < 0) e = 0; /* can occur if n = 1 */ prec = chk_gen_prec(n, e); nffp_init(F,S,prec); F->ro = ro; make_M_G(F, 1); d->v = varn(S->T); d->expo_best_disc = -1; d->ZKembed = NULL; d->M = NULL; d->u = NULL; d->r1= S->r1; } static GEN findmindisc(GEN y) { GEN x = gel(y,1), dx = NULL; long i, l = lg(y); for (i = 2; i < l; i++) { GEN yi = gel(y,i); if (ZX_is_better(yi,x,&dx)) x = yi; } return x; } /* filter [y,b] from polred_aux: keep a single polynomial of degree n in y * [ the best wrt discriminant ordering ], but keep all non-primitive * polynomials */ static void filter(GEN y, GEN b, long n) { GEN x, a, dx; long i, k = 1, l = lg(y); a = x = dx = NULL; for (i = 1; i < l; i++) { GEN yi = gel(y,i), ai = gel(b,i); if (degpol(yi) == n) { pari_sp av = avma; if (!dx) dx = ZX_disc(yi); else if (!ZX_is_better(yi,x,&dx)) { avma = av; continue; } x = yi; a = ai; continue; } gel(y,k) = yi; gel(b,k) = ai; k++; } if (dx) { gel(y,k) = x; gel(b,k) = a; k++; } setlg(y, k); setlg(b, k); } static GEN polred_aux(nfmaxord_t *S, GEN *pro, long flag) { /* only keep polynomials of max degree and best discriminant */ const long best = flag & nf_ABSOLUTE; const long orig = flag & nf_ORIG; GEN M, b, y, x = S->T; long maxi, i, j, k, v = varn(x), n = lg(S->basis)-1; nffp_t F; CG_data d; if (n == 1) { if (!best) { GEN X = pol_x(v); return orig? mkmat2(mkcol(X),mkcol(gen_1)): mkvec(X); } else return orig? trivial_fact(): cgetg(1,t_VEC); } polred_init(S, &F, &d); if (pro) *pro = F.ro; M = F.M; if (best) { if (!S->dT) S->dT = ZX_disc(S->T); d.expo_best_disc = expi(S->dT); } /* n + 2 sum_{1 <= i <= n} n-i = n + n(n-1) = n*n */ y = cgetg(n*n + 1, t_VEC); b = cgetg(n*n + 1, t_COL); k = 1; if (!best) { gel(y,1) = pol_x(v); gel(b,1) = gen_0; k++; } for (i = 2; i <= n; i++) { GEN ch, ai; ai = gel(S->basis,i); ch = try_polmin(&d, S, gel(M,i), flag, &ai); if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; } } maxi = minss(n, 3); for (i = 1; i <= maxi; i++) for (j = i+1; j <= n; j++) { GEN ch, ai, v; ai = gadd(gel(S->basis,i), gel(S->basis,j)); v = RgV_add(gel(M,i), gel(M,j)); /* defining polynomial for Q(w_i+w_j) */ ch = try_polmin(&d, S, v, flag, &ai); if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; } ai = gsub(gel(S->basis,i), gel(S->basis,j)); v = RgV_sub(gel(M,i), gel(M,j)); /* defining polynomial for Q(w_i-w_j) */ ch = try_polmin(&d, S, v, flag, &ai); if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; } } setlg(y, k); setlg(b, k); filter(y, b, n); if (!orig) return gen_sort_uniq(y, (void*)cmpii, &gen_cmp_RgX); settyp(y, t_COL); (void)sort_factor_pol(mkmat2(y, b), cmpii); return mkmat2(b, y); } /* FIXME: obsolete */ static GEN Polred(GEN x, long flag, GEN fa) { pari_sp av = avma; nfmaxord_t S; if (fa) nfinit_basic(&S, mkvec2(x,fa)); else if (flag & nf_PARTIALFACT) nfinit_basic_partial(&S, x); else nfinit_basic(&S, x); return gerepilecopy(av, polred_aux(&S, NULL, flag)); } /* finds "best" polynomial in polred_aux list, defaulting to S->T if none of * them is primitive. *px is the ZX, characteristic polynomial of Mod(*pb,S->T), * *pdx its discriminant if pdx != NULL. Set *pro = polroots(S->T) */ static void polredbest_aux(nfmaxord_t *S, GEN *pro, GEN *px, GEN *pdx, GEN *pb) { GEN y, dx, x = S->T; /* default value */ long i, l; y = polred_aux(S, pro, pb? nf_ORIG|nf_ABSOLUTE: nf_ABSOLUTE); dx = S->dT; if (pb) { GEN a, b = deg1pol_shallow(S->unscale, gen_0, varn(x)); a = gel(y,1); l = lg(a); y = gel(y,2); for (i=1; i 1) pari_err_FLAG("polredbest"); return gerepilecopy(av, polredbest_i(T, flag)); } /* DEPRECATED: backward compatibility */ GEN polred0(GEN x, long flag, GEN fa) { long fl = 0; if (flag & 1) fl |= nf_PARTIALFACT; if (flag & 2) fl |= nf_ORIG; return Polred(x, fl, fa); } GEN polredord(GEN x) { pari_sp av = avma; GEN v, lt; long i, n, vx; if (typ(x) != t_POL) pari_err_TYPE("polredord",x); x = Q_primpart(x); RgX_check_ZX(x,"polredord"); n = degpol(x); if (n <= 0) pari_err_CONSTPOL("polredord"); if (n == 1) return gerepilecopy(av, mkvec(x)); lt = leading_coeff(x); vx = varn(x); if (is_pm1(lt)) { if (signe(lt) < 0) x = ZX_neg(x); v = pol_x_powers(n, vx); } else { GEN L; /* basis for Dedekind order */ v = cgetg(n+1, t_VEC); gel(v,1) = scalarpol_shallow(lt, vx); for (i = 2; i <= n; i++) gel(v,i) = RgX_Rg_add(RgX_mulXn(gel(v,i-1), 1), gel(x,n+3-i)); gel(v,1) = pol_1(vx); x = ZX_Q_normalize(x, &L); v = gsubst(v, vx, monomial(ginv(L),1,vx)); for (i=2; i <= n; i++) if (Q_denom(gel(v,i)) == gen_1) gel(v,i) = pol_xn(i-1, vx); } return gerepileupto(av, polred(mkvec2(x, v))); } GEN polred(GEN x) { return Polred(x, 0, NULL); } GEN smallpolred(GEN x) { return Polred(x, nf_PARTIALFACT, NULL); } GEN factoredpolred(GEN x, GEN fa) { return Polred(x, 0, fa); } GEN polred2(GEN x) { return Polred(x, nf_ORIG, NULL); } GEN smallpolred2(GEN x) { return Polred(x, nf_PARTIALFACT|nf_ORIG, NULL); } GEN factoredpolred2(GEN x, GEN fa) { return Polred(x, nf_PARTIALFACT, fa); } /********************************************************************/ /** **/ /** POLREDABS **/ /** **/ /********************************************************************/ /* set V[k] := matrix of multiplication by nk.zk[k] */ static GEN set_mulid(GEN V, GEN M, GEN Mi, long r1, long r2, long N, long k) { GEN v, Mk = cgetg(N+1, t_MAT); long i, e; for (i = 1; i < k; i++) gel(Mk,i) = gmael(V, i, k); for ( ; i <=N; i++) { v = vecmul(gel(M,k), gel(M,i)); v = RgM_RgC_mul(Mi, split_realimag(v, r1, r2)); gel(Mk,i) = grndtoi(v, &e); if (e > -5) return NULL; } gel(V,k) = Mk; return Mk; } static GEN ZM_image_shallow(GEN M, long *pr) { long j, k, r; GEN y, d = ZM_pivots(M, &k); r = lg(M)-1 - k; y = cgetg(r+1,t_MAT); for (j=k=1; j<=r; k++) if (d[k]) gel(y,j++) = gel(M,k); *pr = r; return y; } /* U = base change matrix, R = Cholesky form of the quadratic form [matrix * Q from algo 2.7.6] */ static GEN chk_gen_init(FP_chk_fun *chk, GEN R, GEN U) { CG_data *d = (CG_data*)chk->data; GEN P, V, D, inv, bound, S, M; long N = lg(U)-1, r1 = d->r1, r2 = (N-r1)>>1; long i, j, prec, firstprim = 0, skipfirst = 0; pari_sp av; d->u = U; d->ZKembed = M = RgM_mul(d->M, U); av = avma; bound = d->bound; D = cgetg(N+1, t_VECSMALL); for (i = 1; i <= N; i++) { pari_sp av2 = avma; P = get_pol(d, gel(M,i)); if (!P) pari_err_PREC("chk_gen_init"); P = gerepilecopy(av2, ZX_radical(P)); D[i] = degpol(P); if (D[i] == N) { /* primitive element */ GEN B = embed_T2(gel(M,i), r1); if (!firstprim) firstprim = i; /* index of first primitive element */ if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P); if (gcmp(B,bound) < 0) bound = gerepileuptoleaf(av2, B); } else { if (DEBUGLEVEL>2) err_printf("chk_gen_init: subfield %Ps\n",P); if (firstprim) { /* cycle basis vectors so that primitive elements come last */ GEN u = d->u, e = M; GEN te = gel(e,i), tu = gel(u,i), tR = gel(R,i); long tS = D[i]; for (j = i; j > firstprim; j--) { u[j] = u[j-1]; e[j] = e[j-1]; R[j] = R[j-1]; D[j] = D[j-1]; } gel(u,firstprim) = tu; gel(e,firstprim) = te; gel(R,firstprim) = tR; D[firstprim] = tS; firstprim++; } } } if (!firstprim) { /* try (a little) to find primitive elements to improve bound */ GEN x = cgetg(N+1, t_VECSMALL); if (DEBUGLEVEL>1) err_printf("chk_gen_init: difficult field, trying random elements\n"); for (i = 0; i < 10; i++) { GEN e, B; for (j = 1; j <= N; j++) x[j] = (long)random_Fl(7) - 3; e = RgM_zc_mul(M, x); B = embed_T2(e, r1); if (gcmp(B,bound) >= 0) continue; P = get_pol(d, e); if (!P) pari_err_PREC( "chk_gen_init"); if (!ZX_is_squarefree(P)) continue; if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P); bound = B ; } } if (firstprim != 1) { inv = ginv( split_realimag(M, r1, r2) ); /*TODO: use QR?*/ V = gel(inv,1); for (i = 2; i <= r1+r2; i++) V = gadd(V, gel(inv,i)); /* V corresponds to 1_Z */ V = grndtoi(V, &j); if (j > -5) pari_err_BUG("precision too low in chk_gen_init"); S = mkmat(V); /* 1 */ V = cgetg(N+1, t_VEC); for (i = 1; i <= N; i++,skipfirst++) { /* S = Q-basis of subfield generated by nf.zk[1..i-1] */ GEN Mx, M2; long j, k, h, rkM, dP = D[i]; if (dP == N) break; /* primitive */ Mx = set_mulid(V, M, inv, r1, r2, N, i); if (!Mx) break; /* prec. problem. Stop */ if (dP == 1) continue; rkM = lg(S)-1; M2 = cgetg(N+1, t_MAT); /* we will add to S the elts of M2 */ gel(M2,1) = col_ei(N, i); /* nf.zk[i] */ k = 2; for (h = 1; h < dP; h++) { long r; /* add to M2 the elts of S * nf.zk[i] */ for (j = 1; j <= rkM; j++) gel(M2,k++) = ZM_ZC_mul(Mx, gel(S,j)); setlg(M2, k); k = 1; S = ZM_image_shallow(shallowconcat(S,M2), &r); if (r == rkM) break; if (r > rkM) { rkM = r; if (rkM == N) break; } } if (rkM == N) break; /* Q(w[1],...,w[i-1]) is a strict subfield of nf */ } } /* x_1,...,x_skipfirst generate a strict subfield [unless N=skipfirst=1] */ chk->skipfirst = skipfirst; if (DEBUGLEVEL>2) err_printf("chk_gen_init: skipfirst = %ld\n",skipfirst); /* should be DEF + gexpo( max_k C^n_k (bound/k)^(k/2) ) */ bound = gerepileuptoleaf(av, bound); prec = chk_gen_prec(N, (gexpo(bound)*N)/2); if (DEBUGLEVEL) err_printf("chk_gen_init: new prec = %ld (initially %ld)\n", prec, d->prec); if (prec > d->prec) pari_err_BUG("polredabs (precision problem)"); if (prec < d->prec) d->ZKembed = gprec_w(M, prec); return bound; } static GEN polredabs_i(GEN x, nfmaxord_t *S, GEN *u, long flag) { FP_chk_fun chk = { &chk_gen, &chk_gen_init, NULL, NULL, 0 }; nffp_t F; CG_data d; GEN v, y, a; long i, l; nfinit_basic_partial(S, x); x = S->T0; if (degpol(x) == 1) { long vx = varn(x); *u = NULL; return mkvec2(mkvec( pol_x(vx) ), mkvec( deg1pol_shallow(gen_1, negi(gel(S->T,2)), vx) )); } if (!(flag & nf_PARTIALFACT) && S->dKP) { GEN vw = primes_certify(S->dK, S->dKP); v = gel(vw,1); l = lg(v); if (l != 1) { /* fix integral basis */ GEN w = gel(vw,2); for (i = 1; i < l; i++) w = ZV_union_shallow(w, gel(Z_factor(gel(v,i)),1)); nfinit_basic(S, mkvec2(S->T0,w)); } } chk.data = (void*)&d; polred_init(S, &F, &d); d.bound = embed_T2(F.ro, d.r1); if (realprec(d.bound) > F.prec) d.bound = rtor(d.bound, F.prec); for (;;) { GEN R = R_from_QR(F.G, F.prec); if (R) { d.prec = F.prec; d.M = F.M; v = fincke_pohst(mkvec(R),NULL,-1, 0, &chk); if (v) break; } F.prec = precdbl(F.prec); F.ro = NULL; make_M_G(&F, 1); if (DEBUGLEVEL) pari_warn(warnprec,"polredabs0",F.prec); } y = gel(v,1); a = gel(v,2); l = lg(a); for (i = 1; i < l; i++) /* normalize wrt z -> -z */ if (ZX_canon_neg(gel(y,i)) && (flag & (nf_ORIG|nf_RAW))) gel(a,i) = ZC_neg(gel(a,i)); *u = d.u; return v; } GEN polredabs0(GEN x, long flag) { pari_sp av = avma; GEN Y, A, u, v; nfmaxord_t S; long i, l; v = polredabs_i(x, &S, &u, flag); remove_duplicates(v); Y = gel(v,1); A = gel(v,2); l = lg(A); if (l == 1) pari_err_BUG("polredabs (missing vector)"); if (DEBUGLEVEL) err_printf("Found %ld minimal polynomials.\n",l-1); if (!(flag & nf_ALL)) { GEN y = findmindisc(Y); for (i = 1; i < l; i++) if (ZX_equal(gel(Y,i), y)) break; Y = mkvec(gel(Y,i)); A = mkvec(gel(A,i)); l = 2; } if (flag & (nf_RAW|nf_ORIG)) for (i = 1; i < l; i++) { GEN y = gel(Y,i), a = gel(A,i); if (u) a = RgV_RgC_mul(S.basis, ZM_ZC_mul(u, a)); if (flag & nf_ORIG) { a = QXQ_reverse(a, S.T); if (!isint1(S.unscale)) a = gdiv(a, S.unscale); /* not RgX_Rg_div */ a = mkpolmod(a,y); } gel(Y,i) = mkvec2(y, a); } return gerepilecopy(av, (flag & nf_ALL)? Y: gel(Y,1)); } GEN polredabsall(GEN x, long flun) { return polredabs0(x, flun | nf_ALL); } GEN polredabs(GEN x) { return polredabs0(x,0); } GEN polredabs2(GEN x) { return polredabs0(x,nf_ORIG); } /* true nf, partial nf_rnfeq */ GEN nf_rnfeq_partial(GEN nf, GEN R) { long sa; GEN T = nf_get_pol(nf), pol = rnfequationall(nf, R, &sa, NULL); return mkvec5(pol,gen_0,stoi(sa),T,liftpol_shallow(R)); } /* relative polredabs/best. Returns relative polynomial by default (flag = 0) * flag & nf_ORIG: + element (base change) * flag & nf_ABSOLUTE: absolute polynomial */ static GEN rnfpolred_i(GEN nf, GEN R, long flag, long best) { const char *f = best? "rnfpolredbest": "rnfpolredabs"; const long abs = ((flag & nf_ORIG) && (flag & nf_ABSOLUTE)); GEN listP = NULL, red, pol, A, P, T, rnfeq; pari_sp av = avma; if (typ(R) == t_VEC) { if (lg(R) != 3) pari_err_TYPE(f,R); listP = gel(R,2); R = gel(R,1); } if (typ(R) != t_POL) pari_err_TYPE(f,R); nf = checknf(nf); T = nf_get_pol(nf); R = RgX_nffix(f, T, R, 0); if (best || (flag & nf_PARTIALFACT)) { rnfeq = abs? nf_rnfeq(nf, R): nf_rnfeq_partial(nf, R); pol = gel(rnfeq,1); if (listP) pol = mkvec2(pol, listP); red = best? polredbest_i(pol, abs? 1: 2) : polredabs0(pol, (abs? nf_ORIG: nf_RAW)|nf_PARTIALFACT); P = gel(red,1); A = gel(red,2); } else { nfmaxord_t S; GEN rnf, u, v, y, a; long i, j, l; pari_timer ti; if (DEBUGLEVEL>1) timer_start(&ti); rnf = rnfinit(nf, R); rnfeq = rnf_get_map(rnf); pol = rnf_zkabs(rnf); if (DEBUGLEVEL>1) timer_printf(&ti, "absolute basis"); v = polredabs_i(pol, &S, &u, nf_ORIG); pol = gel(pol,1); y = gel(v,1); P = findmindisc(y); a = gel(v,2); l = lg(y); A = cgetg(l, t_VEC); for (i = j = 1; i < l; i++) if (ZX_equal(gel(y,i),P)) { GEN t = gel(a,i); if (u) t = RgV_RgC_mul(S.basis, ZM_ZC_mul(u,t)); gel(A,j++) = t; } setlg(A,j); /* mod(A[i], pol) are all roots of P in Q[X]/(pol) */ } if (DEBUGLEVEL>1) err_printf("reduced absolute generator: %Ps\n",P); if (flag & nf_ABSOLUTE) { if (flag & nf_ORIG) { GEN a = gel(rnfeq,2); /* Mod(a,pol) root of T */ GEN k = gel(rnfeq,3); /* Mod(variable(R),R) + k*a root of pol */ if (typ(A) == t_VEC) A = gel(A,1); /* any root will do */ a = RgX_RgXQ_eval(a, lift_shallow(A), P); /* Mod(a, P) root of T */ P = mkvec3(P, mkpolmod(a,P), gsub(A, gmul(k,a))); } return gerepilecopy(av, P); } if (typ(A) != t_VEC) { A = eltabstorel_lift(rnfeq, A); P = lift_if_rational( RgXQ_charpoly(A, R, varn(R)) ); } else { /* canonical factor */ long i, l = lg(A), v = varn(R); GEN besta = NULL; for (i = 1; i < l; i++) { GEN a = eltabstorel_lift(rnfeq, gel(A,i)); GEN p = lift_if_rational( RgXQ_charpoly(a, R, v) ); p = lift_if_rational(p); if (i == 1 || cmp_universal(p, P) < 0) { P = p; besta = a; } } A = besta; } if (flag & nf_ORIG) P = mkvec2(P, mkpolmod(RgXQ_reverse(A,R),P)); return gerepilecopy(av, P); } GEN rnfpolredabs(GEN nf, GEN relpol, long flag) { return rnfpolred_i(nf,relpol,flag, 0); } GEN rnfpolredbest(GEN nf, GEN relpol, long flag) { if (flag < 0 || flag > 3) pari_err_FLAG("rnfpolredbest"); return rnfpolred_i(nf,relpol,flag, 1); } pari-2.11.2/src/basemath/bibli1.c0000644000175000017500000015300513326135265015051 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** LLL Algorithm and close friends **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /********************************************************************/ /** QR Factorization via Householder matrices **/ /********************************************************************/ static int no_prec_pb(GEN x) { return (typ(x) != t_REAL || realprec(x) > LOWDEFAULTPREC || expo(x) < BITS_IN_LONG/2); } /* Find a Householder transformation which, applied to x[k..#x], zeroes * x[k+1..#x]; fill L = (mu_{i,j}). Return 0 if precision problem [obtained * a 0 vector], 1 otherwise */ static int FindApplyQ(GEN x, GEN L, GEN B, long k, GEN Q, long prec) { long i, lx = lg(x)-1; GEN x2, x1, xd = x + (k-1); x1 = gel(xd,1); x2 = mpsqr(x1); if (k < lx) { long lv = lx - (k-1) + 1; GEN beta, Nx, v = cgetg(lv, t_VEC); for (i=2; i 1) r = ApplyAllQ(Q, r, j); if (!FindApplyQ(r, L, B, j, Q, prec)) return 0; } *pB = B; *pQ = Q; *pL = L; return 1; } /* x a square t_MAT with t_INT / t_REAL entries and maximal rank. Return * qfgaussred(x~*x) */ GEN gaussred_from_QR(GEN x, long prec) { long j, k = lg(x)-1; GEN B, Q, L; if (!QR_init(x, &B,&Q,&L, prec)) return NULL; for (j=1; j 0; j--) { GEN c = gdiv( RgV_dotproduct(b, gel(G,j)), gel(N,j) ); long e; c = grndtoi(c,&e); if (e >= 0) return NULL; if (signe(c)) b = RgC_sub(b, RgC_Rg_mul(gel(G,j), c)); gel(C,j) = c; } return C; } /********************************************************************/ /** **/ /** LLL ALGORITHM **/ /** **/ /********************************************************************/ /* Def: a matrix M is said to be -partially reduced- if | m1 +- m2 | >= |m1| * for any two columns m1 != m2, in M. * * Input: an integer matrix mat whose columns are linearly independent. Find * another matrix T such that mat * T is partially reduced. * * Output: mat * T if flag = 0; T if flag != 0, * * This routine is designed to quickly reduce lattices in which one row * is huge compared to the other rows. For example, when searching for a * polynomial of degree 3 with root a mod N, the four input vectors might * be the coefficients of * X^3 - (a^3 mod N), X^2 - (a^2 mod N), X - (a mod N), N. * All four constant coefficients are O(p) and the rest are O(1). By the * pigeon-hole principle, the coefficients of the smallest vector in the * lattice are O(p^(1/4)), hence significant reduction of vector lengths * can be anticipated. * * An improved algorithm would look only at the leading digits of dot*. It * would use single-precision calculations as much as possible. * * Original code: Peter Montgomery (1994) */ static GEN lllintpartialall(GEN m, long flag) { const long ncol = lg(m)-1; const pari_sp av = avma; GEN tm1, tm2, mid; if (ncol <= 1) return flag? matid(ncol): gcopy(m); tm1 = flag? matid(ncol): NULL; { const pari_sp av2 = avma; GEN dot11 = ZV_dotsquare(gel(m,1)); GEN dot22 = ZV_dotsquare(gel(m,2)); GEN dot12 = ZV_dotproduct(gel(m,1), gel(m,2)); GEN tm = matid(2); /* For first two columns only */ int progress = 0; long npass2 = 0; /* Row reduce the first two columns of m. Our best result so far is * (first two columns of m)*tm. * * Initially tm = 2 x 2 identity matrix. * Inner products of the reduced matrix are in dot11, dot12, dot22. */ while (npass2 < 2 || progress) { GEN dot12new, q = diviiround(dot12, dot22); npass2++; progress = signe(q); if (progress) {/* Conceptually replace (v1, v2) by (v1 - q*v2, v2), where v1 and v2 * represent the reduced basis for the first two columns of the matrix. * We do this by updating tm and the inner products. */ togglesign(q); dot12new = addii(dot12, mulii(q, dot22)); dot11 = addii(dot11, mulii(q, addii(dot12, dot12new))); dot12 = dot12new; ZC_lincomb1_inplace(gel(tm,1), gel(tm,2), q); } /* Interchange the output vectors v1 and v2. */ swap(dot11,dot22); swap(gel(tm,1), gel(tm,2)); /* Occasionally (including final pass) do garbage collection. */ if ((npass2 & 0xff) == 0 || !progress) gerepileall(av2, 4, &dot11,&dot12,&dot22,&tm); } /* while npass2 < 2 || progress */ { long i; GEN det12 = subii(mulii(dot11, dot22), sqri(dot12)); mid = cgetg(ncol+1, t_MAT); for (i = 1; i <= 2; i++) { GEN tmi = gel(tm,i); if (tm1) { GEN tm1i = gel(tm1,i); gel(tm1i,1) = gel(tmi,1); gel(tm1i,2) = gel(tmi,2); } gel(mid,i) = ZC_lincomb(gel(tmi,1),gel(tmi,2), gel(m,1),gel(m,2)); } for (i = 3; i <= ncol; i++) { GEN c = gel(m,i); GEN dot1i = ZV_dotproduct(gel(mid,1), c); GEN dot2i = ZV_dotproduct(gel(mid,2), c); /* ( dot11 dot12 ) (q1) ( dot1i ) * ( dot12 dot22 ) (q2) = ( dot2i ) * * Round -q1 and -q2 to nearest integer. Then compute * c - q1*mid[1] - q2*mid[2]. * This will be approximately orthogonal to the first two vectors in * the new basis. */ GEN q1neg = subii(mulii(dot12, dot2i), mulii(dot22, dot1i)); GEN q2neg = subii(mulii(dot12, dot1i), mulii(dot11, dot2i)); q1neg = diviiround(q1neg, det12); q2neg = diviiround(q2neg, det12); if (tm1) { gcoeff(tm1,1,i) = addii(mulii(q1neg, gcoeff(tm,1,1)), mulii(q2neg, gcoeff(tm,1,2))); gcoeff(tm1,2,i) = addii(mulii(q1neg, gcoeff(tm,2,1)), mulii(q2neg, gcoeff(tm,2,2))); } gel(mid,i) = ZC_add(c, ZC_lincomb(q1neg,q2neg, gel(mid,1),gel(mid,2))); } /* for i */ } /* local block */ } if (DEBUGLEVEL>6) { if (tm1) err_printf("tm1 = %Ps",tm1); err_printf("mid = %Ps",mid); /* = m * tm1 */ } gerepileall(av, tm1? 2: 1, &mid, &tm1); { /* For each pair of column vectors v and w in mid * tm2, * try to replace (v, w) by (v, v - q*w) for some q. * We compute all inner products and check them repeatedly. */ const pari_sp av3 = avma; long i, j, npass = 0, e = LONG_MAX; GEN dot = cgetg(ncol+1, t_MAT); /* scalar products */ tm2 = matid(ncol); for (i=1; i <= ncol; i++) { gel(dot,i) = cgetg(ncol+1,t_COL); for (j=1; j <= i; j++) gcoeff(dot,j,i) = gcoeff(dot,i,j) = ZV_dotproduct(gel(mid,i),gel(mid,j)); } for(;;) { long reductions = 0, olde = e; for (i=1; i <= ncol; i++) { long ijdif; for (ijdif=1; ijdif < ncol; ijdif++) { long d, k1, k2; GEN codi, q; j = i + ijdif; if (j > ncol) j -= ncol; /* let k1, resp. k2, index of larger, resp. smaller, column */ if (cmpii(gcoeff(dot,i,i), gcoeff(dot,j,j)) > 0) { k1 = i; k2 = j; } else { k1 = j; k2 = i; } codi = gcoeff(dot,k2,k2); q = signe(codi)? diviiround(gcoeff(dot,k1,k2), codi): gen_0; if (!signe(q)) continue; /* Try to subtract a multiple of column k2 from column k1. */ reductions++; togglesign_safe(&q); ZC_lincomb1_inplace(gel(tm2,k1), gel(tm2,k2), q); ZC_lincomb1_inplace(gel(dot,k1), gel(dot,k2), q); gcoeff(dot,k1,k1) = addii(gcoeff(dot,k1,k1), mulii(q, gcoeff(dot,k2,k1))); for (d = 1; d <= ncol; d++) gcoeff(dot,k1,d) = gcoeff(dot,d,k1); } /* for ijdif */ if (gc_needed(av3,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"lllintpartialall"); gerepileall(av3, 2, &dot,&tm2); } } /* for i */ if (!reductions) break; e = 0; for (i = 1; i <= ncol; i++) e += expi( gcoeff(dot,i,i) ); if (e == olde) break; if (DEBUGLEVEL>6) { npass++; err_printf("npass = %ld, red. last time = %ld, log_2(det) ~ %ld\n\n", npass, reductions, e); } } /* for(;;)*/ /* Sort columns so smallest comes first in m * tm1 * tm2. * Use insertion sort. */ for (i = 1; i < ncol; i++) { long j, s = i; for (j = i+1; j <= ncol; j++) if (cmpii(gcoeff(dot,s,s),gcoeff(dot,j,j)) > 0) s = j; if (i != s) { /* Exchange with proper column; only the diagonal of dot is updated */ swap(gel(tm2,i), gel(tm2,s)); swap(gcoeff(dot,i,i), gcoeff(dot,s,s)); } } } /* local block */ return gerepileupto(av, ZM_mul(tm1? tm1: mid, tm2)); } GEN lllintpartial(GEN mat) { return lllintpartialall(mat,1); } GEN lllintpartial_inplace(GEN mat) { return lllintpartialall(mat,0); } /********************************************************************/ /** **/ /** COPPERSMITH ALGORITHM **/ /** Finding small roots of univariate equations. **/ /** **/ /********************************************************************/ static int check_condition(double beta, double tau, double rho, long d, long delta, long t) { long dim = d*delta + t; double cond = d*delta*(delta+1)/2 - beta*delta*dim + rho*delta*(delta - 1) / 2 + rho * t * delta + tau*dim*(dim - 1)/2; if (DEBUGLEVEL >= 4) err_printf("delta = %d, t = %d, cond = %.1lf\n", delta, t, cond); return (cond <= 0); } static void choose_params(GEN P, GEN N, GEN X, GEN B, long *pdelta, long *pt) { long d = degpol(P); GEN P0 = leading_coeff(P); double logN = gtodouble(glog(N, DEFAULTPREC)); double tau, beta, rho; long delta, t; tau = gtodouble(glog(X, DEFAULTPREC)) / logN; beta = B? gtodouble(glog(B, DEFAULTPREC)) / logN: 1.; if (tau >= beta * beta / d) pari_err_OVERFLOW("zncoppersmith [bound too large]"); /* TODO : remove P0 completely ! */ rho = gtodouble(glog(P0, DEFAULTPREC)) / logN; /* Enumerate (delta,t) by increasing dimension of resulting lattice. * Not subtle, but o(1) for computing time */ t = d; delta = 0; for(;;) { t += d * delta + 1; delta = 0; while (t >= 0) { if (check_condition(beta, tau, rho, d, delta, t)) { *pdelta = delta; *pt = t; return; } delta++; t -= d; } } } static int sol_OK(GEN x, GEN N, GEN B) { return B? (cmpii(gcdii(x,N),B) >= 0): dvdii(x,N); } /* deg(P) > 0, x >= 0. Find all j such that gcd(P(j), N) >= B, |j| <= x */ static GEN do_exhaustive(GEN P, GEN N, long x, GEN B) { GEN Pe, Po, sol = vecsmalltrunc_init(2*x + 2); pari_sp av; long j; RgX_even_odd(P, &Pe,&Po); av = avma; if (sol_OK(gel(P,2), N,B)) vecsmalltrunc_append(sol, 0); for (j = 1; j <= x; j++, avma = av) { GEN j2 = sqru(j), E = FpX_eval(Pe,j2,N), O = FpX_eval(Po,j2,N); if (sol_OK(addmuliu(E,O,j), N,B)) vecsmalltrunc_append(sol, j); if (sol_OK(submuliu(E,O,j), N,B)) vecsmalltrunc_append(sol,-j); } vecsmall_sort(sol); return zv_to_ZV(sol); } /* General Coppersmith, look for a root x0 <= p, p >= B, p | N, |x0| <= X. * B = N coded as NULL */ GEN zncoppersmith(GEN P0, GEN N, GEN X, GEN B) { GEN Q, R, N0, M, sh, short_pol, *Xpowers, sol, nsp, P, Z; long delta, i, j, row, d, l, dim, t, bnd = 10; const ulong X_SMALL = 1000; pari_sp av = avma; if (typ(P0) != t_POL) pari_err_TYPE("zncoppersmith",P0); if (typ(N) != t_INT) pari_err_TYPE("zncoppersmith",N); if (typ(X) != t_INT) { X = gfloor(X); if (typ(X) != t_INT) pari_err_TYPE("zncoppersmith",X); } if (signe(X) < 0) pari_err_DOMAIN("zncoppersmith", "X", "<", gen_0, X); d = degpol(P0); if (d == 0) { avma = av; return cgetg(1, t_VEC); } if (d < 0) pari_err_ROOTS0("zncoppersmith"); if (B && typ(B) != t_INT) B = gceil(B); if (abscmpiu(X, X_SMALL) <= 0) return gerepileupto(av, do_exhaustive(P0, N, itos(X), B)); if (B && equalii(B,N)) B = NULL; if (B) bnd = 1; /* bnd-hack is only for the case B = N */ P = leafcopy(P0); if (!gequal1(gel(P,d+2))) { GEN r, z; gel(P,d+2) = bezout(gel(P,d+2), N, &z, &r); for (j = 0; j < d; j++) gel(P,j+2) = modii(mulii(gel(P,j+2), z), N); } if (DEBUGLEVEL >= 2) err_printf("Modified P: %Ps\n", P); choose_params(P, N, X, B, &delta, &t); if (DEBUGLEVEL >= 2) err_printf("Init: trying delta = %d, t = %d\n", delta, t); for(;;) { dim = d * delta + t; /* TODO: In case of failure do not recompute the full vector */ Xpowers = (GEN*)new_chunk(dim + 1); Xpowers[0] = gen_1; for (j = 1; j <= dim; j++) Xpowers[j] = mulii(Xpowers[j-1], X); /* TODO: in case of failure, use the part of the matrix already computed */ M = zeromatcopy(dim,dim); /* Rows of M correspond to the polynomials * N^delta, N^delta Xi, ... N^delta (Xi)^d-1, * N^(delta-1)P(Xi), N^(delta-1)XiP(Xi), ... N^(delta-1)P(Xi)(Xi)^d-1, * ... * P(Xi)^delta, XiP(Xi)^delta, ..., P(Xi)^delta(Xi)^t-1 */ for (j = 1; j <= d; j++) gcoeff(M, j, j) = gel(Xpowers,j-1); /* P-part */ if (delta) row = d + 1; else row = 0; Q = P; for (i = 1; i < delta; i++) { for (j = 0; j < d; j++,row++) for (l = j + 1; l <= row; l++) gcoeff(M, l, row) = mulii(Xpowers[l-1], gel(Q,l-j+1)); Q = ZX_mul(Q, P); } for (j = 0; j < t; row++, j++) for (l = j + 1; l <= row; l++) gcoeff(M, l, row) = mulii(Xpowers[l-1], gel(Q,l-j+1)); /* N-part */ row = dim - t; N0 = N; while (row >= 1) { for (j = 0; j < d; j++,row--) for (l = 1; l <= row; l++) gcoeff(M, l, row) = mulii(gmael(M, row, l), N0); if (row >= 1) N0 = mulii(N0, N); } /* Z is the upper bound for the L^1 norm of the polynomial, ie. N^delta if B = N, B^delta otherwise */ if (B) Z = powiu(B, delta); else Z = N0; if (DEBUGLEVEL >= 2) { if (DEBUGLEVEL >= 6) err_printf("Matrix to be reduced:\n%Ps\n", M); err_printf("Entering LLL\nbitsize bound: %ld\n", expi(Z)); err_printf("expected shvector bitsize: %ld\n", expi(ZM_det_triangular(M))/dim); } sh = ZM_lll(M, 0.75, LLL_INPLACE); /* Take the first vector if it is non constant */ short_pol = gel(sh,1); if (ZV_isscalar(short_pol)) short_pol = gel(sh, 2); nsp = gen_0; for (j = 1; j <= dim; j++) nsp = addii(nsp, absi_shallow(gel(short_pol,j))); if (DEBUGLEVEL >= 2) { err_printf("Candidate: %Ps\n", short_pol); err_printf("bitsize Norm: %ld\n", expi(nsp)); err_printf("bitsize bound: %ld\n", expi(mului(bnd, Z))); } if (cmpii(nsp, mului(bnd, Z)) < 0) break; /* SUCCESS */ /* Failed with the precomputed or supplied value */ t++; if (t == d) { delta++; t = 1; } if (DEBUGLEVEL >= 2) err_printf("Increasing dim, delta = %d t = %d\n", delta, t); } bnd = itos(divii(nsp, Z)) + 1; while (!signe(gel(short_pol,dim))) dim--; R = cgetg(dim + 2, t_POL); R[1] = P[1]; for (j = 1; j <= dim; j++) gel(R,j+1) = diviiexact(gel(short_pol,j), Xpowers[j-1]); gel(R,2) = subii(gel(R,2), mului(bnd - 1, N0)); sol = cgetg(1, t_VEC); for (i = -bnd + 1; i < bnd; i++) { GEN r = nfrootsQ(R); if (DEBUGLEVEL >= 2) err_printf("Roots: %Ps\n", r); for (j = 1; j < lg(r); j++) { GEN z = gel(r,j); if (typ(z) == t_INT && sol_OK(FpX_eval(P,z,N), N,B)) sol = shallowconcat(sol, z); } if (i < bnd) gel(R,2) = addii(gel(R,2), Z); } return gerepileupto(av, ZV_sort_uniq(sol)); } /********************************************************************/ /** **/ /** LINEAR & ALGEBRAIC DEPENDENCE **/ /** **/ /********************************************************************/ static int real_indep(GEN re, GEN im, long bit) { GEN d = gsub(gmul(gel(re,1),gel(im,2)), gmul(gel(re,2),gel(im,1))); return (!gequal0(d) && gexpo(d) > - bit); } GEN lindepfull_bit(GEN x, long bit) { long lx = lg(x), ly, i, j; GEN re, im, M; if (! is_vec_t(typ(x))) pari_err_TYPE("lindep2",x); if (lx <= 2) { if (lx == 2 && gequal0(x)) return matid(1); return NULL; } re = real_i(x); im = imag_i(x); /* independent over R ? */ if (lx == 3 && real_indep(re,im,bit)) return NULL; if (gequal0(im)) im = NULL; ly = im? lx+2: lx+1; M = cgetg(lx,t_MAT); for (i=1; i 0) x = gdiv(x, pol_xn(v, vx)); else x = gmul(x, pol_xn(-v, vx)); /* all t_SER have valuation >= 0 */ for (i=1; i 1 */ long t = typ(gel(x,1)), h = lg(gel(x,1)); GEN m = cgetg(l, t_MAT); for (i = 1; i < l; i++) { GEN y = gel(x,i); if (lg(y) != h || typ(y) != t) pari_err_TYPE("lindep",x); if (t != t_COL) y = shallowtrans(y); /* Sigh */ gel(m,i) = y; } return gerepileupto(av, deplin(m)); } GEN lindep(GEN x) { return lindep2(x, 0); } GEN lindep0(GEN x,long bit) { long i, tx = typ(x); if (tx == t_MAT) return deplin(x); if (! is_vec_t(tx)) pari_err_TYPE("lindep",x); for (i = 1; i < lg(x); i++) switch(typ(gel(x,i))) { case t_PADIC: return lindep_padic(x); case t_POL: case t_RFRAC: case t_SER: return lindep_Xadic(x); case t_VEC: case t_COL: return vec_lindep(x); } return lindep2(x, bit); } GEN algdep0(GEN x, long n, long bit) { long tx = typ(x), i; pari_sp av; GEN y; if (! is_scalar_t(tx)) pari_err_TYPE("algdep0",x); if (tx==t_POLMOD) { y = RgX_copy(gel(x,1)); setvarn(y,0); return y; } if (gequal0(x)) return pol_x(0); if (n <= 0) { if (!n) return gen_1; pari_err_DOMAIN("algdep", "degree", "<", gen_0, stoi(n)); } av = avma; y = cgetg(n+2,t_COL); gel(y,1) = gen_1; gel(y,2) = x; /* n >= 1 */ for (i=3; i<=n+1; i++) gel(y,i) = gmul(gel(y,i-1),x); if (typ(x) == t_PADIC) y = lindep_padic(y); else y = lindep2(y, bit); if (lg(y) == 1) pari_err(e_DOMAIN,"algdep", "degree(x)",">", stoi(n), x); y = RgV_to_RgX(y, 0); if (signe(leading_coeff(y)) > 0) return gerepilecopy(av, y); return gerepileupto(av, ZX_neg(y)); } GEN algdep(GEN x, long n) { return algdep0(x,n,0); } GEN seralgdep(GEN s, long p, long r) { pari_sp av = avma; long vy, i, m, n, prec; GEN S, v, D; if (typ(s) != t_SER) pari_err_TYPE("seralgdep",s); if (p <= 0) pari_err_DOMAIN("seralgdep", "p", "<=", gen_0, stoi(p)); if (r < 0) pari_err_DOMAIN("seralgdep", "r", "<", gen_0, stoi(r)); if (is_bigint(addiu(muluu(p, r), 1))) pari_err_OVERFLOW("seralgdep"); vy = varn(s); if (!vy) pari_err_PRIORITY("seralgdep", s, ">", 0); r++; p++; prec = valp(s) + lg(s)-2; if (r > prec) r = prec; S = cgetg(p+1, t_VEC); gel(S, 1) = s; for (i = 2; i <= p; i++) gel(S,i) = gmul(gel(S,i-1), s); v = cgetg(r*p+1, t_VEC); /* v[r*n+m+1] = s^n * y^m */ /* n = 0 */ for (m = 0; m < r; m++) gel(v, m+1) = pol_xn(m, vy); for(n=1; n < p; n++) for (m = 0; m < r; m++) { GEN c = gel(S,n); if (m) { c = shallowcopy(c); setvalp(c, valp(c) + m); } gel(v, r*n + m + 1) = c; } D = lindep_Xadic(v); if (lg(D) == 1) { avma = av; return gen_0; } v = cgetg(p+1, t_VEC); for (n = 0; n < p; n++) gel(v, n+1) = RgV_to_RgX(vecslice(D, r*n+1, r*n+r), vy); return gerepilecopy(av, RgV_to_RgX(v, 0)); } /* FIXME: could precompute ZM_lll attached to V[2..] */ static GEN lindepcx(GEN V, long bit) { GEN Vr = real_i(V), Vi = imag_i(V); if (gexpo(Vr) < -bit) V = Vi; else if (gexpo(Vi) < -bit) V = Vr; return lindepfull_bit(V, bit); } /* c floating point t_REAL or t_COMPLEX, T ZX, recognize in Q[x]/(T). * V helper vector (containing complex roots of T), MODIFIED */ static GEN cx_bestapprnf(GEN c, GEN T, GEN V, long bit) { GEN M, a, v = NULL; long i, l; gel(V,1) = gneg(c); M = lindepcx(V, bit); if (!M) pari_err(e_MISC, "cannot rationalize coeff in bestapprnf"); l = lg(M); a = NULL; for (i = 1; i < l; i ++) { v = gel(M,i); a = gel(v,1); if (signe(a)) break; } v = RgC_Rg_div(vecslice(v, 2, lg(M)-1), a); if (!T) return gel(v,1); v = RgV_to_RgX(v, varn(T)); l = lg(v); if (l == 2) return gen_0; if (l == 3) return gel(v,2); return mkpolmod(v, T); } static GEN bestapprnf_i(GEN x, GEN T, GEN V, long bit) { long i, l, tx = typ(x); GEN z; switch (tx) { case t_INT: case t_FRAC: return x; case t_REAL: case t_COMPLEX: return cx_bestapprnf(x, T, V, bit); case t_POLMOD: if (RgX_equal(gel(x,1),T)) return x; break; case t_POL: case t_SER: case t_VEC: case t_COL: case t_MAT: l = lg(x); z = cgetg(l, tx); for (i = 1; i < lontyp[tx]; i++) z[i] = x[i]; for (; i < l; i++) gel(z,i) = bestapprnf_i(gel(x,i), T, V, bit); return z; } pari_err_TYPE("mfcxtoQ", x); return NULL;/*LCOV_EXCL_LINE*/ } GEN bestapprnf(GEN x, GEN T, GEN roT, long prec) { pari_sp av = avma; long tx = typ(x), dT = 1, bit; GEN V; if (T) { if (typ(T) != t_POL) T = nf_get_pol(checknf(T)); else if (!RgX_is_ZX(T)) pari_err_TYPE("bestapprnf", T); dT = degpol(T); } if (is_rational_t(tx)) return gcopy(x); if (tx == t_POLMOD) { if (!T || !RgX_equal(T, gel(x,1))) pari_err_TYPE("bestapprnf",x); return gcopy(x); } if (roT) { long l = gprecision(roT); switch(typ(roT)) { case t_INT: case t_FRAC: case t_REAL: case t_COMPLEX: break; default: pari_err_TYPE("bestapprnf", roT); } if (prec < l) prec = l; } else if (!T) roT = gen_1; else { long n = poliscyclo(T); /* cyclotomic is an important special case */ roT = n? rootsof1u_cx(n,prec): gel(QX_complex_roots(T,prec), 1); } V = vec_prepend(gpowers(roT, dT-1), NULL); bit = prec2nbits_mul(prec, 0.8); return gerepilecopy(av, bestapprnf_i(x, T, V, bit)); } /********************************************************************/ /** **/ /** MINIM **/ /** **/ /********************************************************************/ void minim_alloc(long n, double ***q, GEN *x, double **y, double **z, double **v) { long i, s; *x = cgetg(n, t_VECSMALL); *q = (double**) new_chunk(n); s = n * sizeof(double); *y = (double*) stack_malloc_align(s, sizeof(double)); *z = (double*) stack_malloc_align(s, sizeof(double)); *v = (double*) stack_malloc_align(s, sizeof(double)); for (i=1; ia = RgM_gtofp(a, DEFAULTPREC); r = qfgaussred_positive(qv->a); if (!r) { r = qfgaussred_positive(a); /* exact computation */ if (!r) err_minim(a); r = RgM_gtofp(r, DEFAULTPREC); } qv->r = r; qv->u = u; } static void forqfvec_init(struct qfvec *qv, GEN a) { forqfvec_init_dolll(qv, a, 1); } static void forqfvec_i(void *E, long (*fun)(void *, GEN, GEN, double), struct qfvec *qv, GEN BORNE) { GEN x, a = qv->a, r = qv->r, u = qv->u; long n = lg(a), i, j, k; double p,BOUND,*v,*y,*z,**q; const double eps = 0.0001; if (!BORNE) BORNE = gen_0; else { BORNE = gfloor(BORNE); if (typ(BORNE) != t_INT) pari_err_TYPE("minim0",BORNE); } if (n == 1) return; minim_alloc(n, &q, &x, &y, &z, &v); n--; for (j=1; j<=n; j++) { v[j] = rtodbl(gcoeff(r,j,j)); for (i=1; i1) { long l = k-1; z[l] = 0; for (j=k; j<=n; j++) z[l] += q[l][j]*x[j]; p = (double)x[k] + z[k]; y[l] = y[k] + p*p*v[k]; x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]); k = l; } for(;;) { p = (double)x[k] + z[k]; if (y[k] + p*p*v[k] <= BOUND) break; k++; x[k]--; } } while (k > 1); if (! x[1] && y[1]<=eps) break; p = (double)x[1] + z[1]; p = y[1] + p*p*v[1]; /* norm(x) */ if (fun(E, u, x, p)) break; } } void forqfvec(void *E, long (*fun)(void *, GEN, GEN, double), GEN a, GEN BORNE) { pari_sp av = avma; struct qfvec qv; forqfvec_init(&qv, a); forqfvec_i(E, fun, &qv, BORNE); avma = av; } static long _gp_forqf(void *E, GEN u, GEN x, double p/*unused*/) { pari_sp av = avma; (void)p; set_lex(-1, ZM_zc_mul_canon(u, x)); closure_evalvoid((GEN)E); avma = av; return loop_break(); } void forqfvec0(GEN a, GEN BORNE, GEN code) { pari_sp av = avma; struct qfvec qv; forqfvec_init(&qv, a); push_lex(gen_0, code); forqfvec_i((void*) code, &_gp_forqf, &qv, BORNE); pop_lex(1); avma = av; } enum { min_ALL = 0, min_FIRST, min_VECSMALL, min_VECSMALL2 }; /* Minimal vectors for the integral definite quadratic form: a. * Result u: * u[1]= Number of vectors of square norm <= BORNE * u[2]= maximum norm found * u[3]= list of vectors found (at most STOCKMAX, unless NULL) * * If BORNE = NULL: Minimal non-zero vectors. * flag = min_ALL, as above * flag = min_FIRST, exits when first suitable vector is found. * flag = min_VECSMALL, return a t_VECSMALL of (half) the number of vectors * for each norm * flag = min_VECSMALL2, same but count only vectors with even norm, and shift * the answer */ static GEN minim0_dolll(GEN a, GEN BORNE, GEN STOCKMAX, long flag, long dolll) { GEN x, u, r, L, gnorme; long n = lg(a), i, j, k, s, maxrank, sBORNE; pari_sp av = avma, av1; double p,maxnorm,BOUND,*v,*y,*z,**q; const double eps = 1e-10; int stockall = 0; struct qfvec qv; if (!BORNE) sBORNE = 0; else { BORNE = gfloor(BORNE); if (typ(BORNE) != t_INT) pari_err_TYPE("minim0",BORNE); if (is_bigint(BORNE)) pari_err_PREC( "qfminim"); sBORNE = itos(BORNE); avma = av; } if (!STOCKMAX) { stockall = 1; maxrank = 200; } else { STOCKMAX = gfloor(STOCKMAX); if (typ(STOCKMAX) != t_INT) pari_err_TYPE("minim0",STOCKMAX); maxrank = itos(STOCKMAX); if (maxrank < 0) pari_err_TYPE("minim0 [negative number of vectors]",STOCKMAX); } switch(flag) { case min_VECSMALL: case min_VECSMALL2: if (sBORNE <= 0) return cgetg(1, t_VECSMALL); L = zero_zv(sBORNE); if (flag == min_VECSMALL2) sBORNE <<= 1; if (n == 1) return L; break; case min_FIRST: if (n == 1 || (!sBORNE && BORNE)) return cgetg(1,t_VEC); L = NULL; /* gcc -Wall */ break; case min_ALL: if (n == 1 || (!sBORNE && BORNE)) retmkvec3(gen_0, gen_0, cgetg(1, t_MAT)); L = new_chunk(1+maxrank); break; default: return NULL; } minim_alloc(n, &q, &x, &y, &z, &v); forqfvec_init_dolll(&qv, a, dolll); av1 = avma; r = qv.r; u = qv.u; n--; for (j=1; j<=n; j++) { v[j] = rtodbl(gcoeff(r,j,j)); for (i=1; i1) { long l = k-1; z[l] = 0; for (j=k; j<=n; j++) z[l] += q[l][j]*x[j]; p = (double)x[k] + z[k]; y[l] = y[k] + p*p*v[k]; x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]); k = l; } for(;;) { p = (double)x[k] + z[k]; if (y[k] + p*p*v[k] <= BOUND) break; k++; x[k]--; } } while (k > 1); if (! x[1] && y[1]<=eps) break; p = (double)x[1] + z[1]; p = y[1] + p*p*v[1]; /* norm(x) */ if (maxnorm >= 0) { if (p > maxnorm) maxnorm = p; } else { /* maxnorm < 0 : only look for minimal vectors */ pari_sp av2 = avma; gnorme = roundr(dbltor(p)); if (cmpis(gnorme, sBORNE) >= 0) avma = av2; else { sBORNE = itos(gnorme); avma = av1; BOUND = sBORNE * (1+eps); L = new_chunk(maxrank+1); s = 0; } } s++; switch(flag) { case min_FIRST: if (dolll) x = ZM_zc_mul_canon(u,x); return gerepilecopy(av, mkvec2(roundr(dbltor(p)), x)); case min_ALL: if (s > maxrank && stockall) /* overflow */ { long maxranknew = maxrank << 1; GEN Lnew = new_chunk(1 + maxranknew); for (i=1; i<=maxrank; i++) Lnew[i] = L[i]; L = Lnew; maxrank = maxranknew; } if (s<=maxrank) gel(L,s) = leafcopy(x); break; case min_VECSMALL: { ulong norm = (ulong)(p + 0.5); L[norm]++; } break; case min_VECSMALL2: { ulong norm = (ulong)(p + 0.5); if (!odd(norm)) L[norm>>1]++; } break; } } switch(flag) { case min_FIRST: avma = av; return cgetg(1,t_VEC); case min_VECSMALL: case min_VECSMALL2: avma = (pari_sp)L; return L; } r = (maxnorm >= 0) ? roundr(dbltor(maxnorm)): stoi(sBORNE); k = minss(s,maxrank); L[0] = evaltyp(t_MAT) | evallg(k + 1); if (dolll) for (j=1; j<=k; j++) gel(L,j) = ZM_zc_mul_canon(u, gel(L,j)); return gerepilecopy(av, mkvec3(stoi(s<<1), r, L)); } static GEN minim0(GEN a, GEN BORNE, GEN STOCKMAX, long flag) { GEN v = minim0_dolll(a, BORNE, STOCKMAX, flag, 1); if (!v) pari_err_PREC("qfminim"); return v; } GEN qfrep0(GEN a, GEN borne, long flag) { return minim0(a, borne, gen_0, (flag & 1)? min_VECSMALL2: min_VECSMALL); } GEN qfminim0(GEN a, GEN borne, GEN stockmax, long flag, long prec) { switch(flag) { case 0: return minim0(a,borne,stockmax,min_ALL); case 1: return minim0(a,borne,gen_0 ,min_FIRST); case 2: { long maxnum = -1; if (typ(a) != t_MAT) pari_err_TYPE("qfminim",a); if (stockmax) { if (typ(stockmax) != t_INT) pari_err_TYPE("qfminim",stockmax); maxnum = itos(stockmax); } a = fincke_pohst(a,borne,maxnum,prec,NULL); if (!a) pari_err_PREC("qfminim"); return a; } default: pari_err_FLAG("qfminim"); } return NULL; /* LCOV_EXCL_LINE */ } GEN minim(GEN a, GEN borne, GEN stockmax) { return minim0(a,borne,stockmax,min_ALL); } GEN minim_raw(GEN a, GEN BORNE, GEN STOCKMAX) { return minim0_dolll(a, BORNE, STOCKMAX, min_ALL, 0); } GEN minim2(GEN a, GEN borne, GEN stockmax) { return minim0(a,borne,stockmax,min_FIRST); } /* If V depends linearly from the columns of the matrix, return 0. * Otherwise, update INVP and L and return 1. No GC. */ static int addcolumntomatrix(GEN V, GEN invp, GEN L) { long i,j,k, n = lg(invp); GEN a = cgetg(n, t_COL), ak = NULL, mak; for (k = 1; k < n; k++) if (!L[k]) { ak = RgMrow_zc_mul(invp, V, k); if (!gequal0(ak)) break; } if (k == n) return 0; L[k] = 1; mak = gneg_i(ak); for (i=k+1; i> 1; if (L) { GEN D, V, invp; L = gel(L, 3); l = lg(L); if (l == 2) { avma = av; return gen_1; } D = zero_zv(r); V = cgetg(r+1, t_VECSMALL); invp = matid(r); s = 0; for (k = 1; k < l; k++) { pari_sp av2 = avma; GEN x = gel(L,k); long i, j, I; for (i = I = 1; i<=n; i++) for (j=i; j<=n; j++,I++) V[I] = x[i]*x[j]; if (!addcolumntomatrix(V,invp,D)) avma = av2; else if (++s == r) break; } } else { GEN M; L = fincke_pohst(a,NULL,-1, DEFAULTPREC, NULL); if (!L) pari_err_PREC("qfminim"); L = gel(L, 3); l = lg(L); if (l == 2) { avma = av; return gen_1; } M = cgetg(l, t_MAT); for (k = 1; k < l; k++) { GEN x = gel(L,k), c = cgetg(r+1, t_COL); long i, I, j; for (i = I = 1; i<=n; i++) for (j=i; j<=n; j++,I++) gel(c,I) = mulii(gel(x,i), gel(x,j)); gel(M,k) = c; } s = ZM_rank(M); } avma = av; return utoipos(s); } static GEN clonefill(GEN S, long s, long t) { /* initialize to dummy values */ GEN T = S, dummy = cgetg(1, t_STR); long i; for (i = s+1; i <= t; i++) gel(S,i) = dummy; S = gclone(S); if (isclone(T)) gunclone(T); return S; } /* increment ZV x, by incrementing cell of index k. Initial value x0[k] was * chosen to minimize qf(x) for given x0[1..k-1] and x0[k+1,..] = 0 * The last non-zero entry must be positive and goes through x0[k]+1,2,3,... * Others entries go through: x0[k]+1,-1,2,-2,...*/ INLINE void step(GEN x, GEN y, GEN inc, long k) { if (!signe(gel(y,k))) /* x[k+1..] = 0 */ gel(x,k) = addiu(gel(x,k), 1); /* leading coeff > 0 */ else { long i = inc[k]; gel(x,k) = addis(gel(x,k), i), inc[k] = (i > 0)? -1-i: 1-i; } } /* 1 if we are "sure" that x < y, up to few rounding errors, i.e. * x < y - epsilon. More precisely : * - sign(x - y) < 0 * - lgprec(x-y) > 3 || expo(x - y) - expo(x) > -24 */ static int mplessthan(GEN x, GEN y) { pari_sp av = avma; GEN z = mpsub(x, y); avma = av; if (typ(z) == t_INT) return (signe(z) < 0); if (signe(z) >= 0) return 0; if (realprec(z) > LOWDEFAULTPREC) return 1; return ( expo(z) - mpexpo(x) > -24 ); } /* 1 if we are "sure" that x > y, up to few rounding errors, i.e. * x > y + epsilon */ static int mpgreaterthan(GEN x, GEN y) { pari_sp av = avma; GEN z = mpsub(x, y); avma = av; if (typ(z) == t_INT) return (signe(z) > 0); if (signe(z) <= 0) return 0; if (realprec(z) > LOWDEFAULTPREC) return 1; return ( expo(z) - mpexpo(x) > -24 ); } /* x a t_INT, y t_INT or t_REAL */ INLINE GEN mulimp(GEN x, GEN y) { if (typ(y) == t_INT) return mulii(x,y); return signe(x) ? mulir(x,y): gen_0; } /* x + y*z, x,z two mp's, y a t_INT */ INLINE GEN addmulimp(GEN x, GEN y, GEN z) { if (!signe(y)) return x; if (typ(z) == t_INT) return mpadd(x, mulii(y, z)); return mpadd(x, mulir(y, z)); } /* yk + vk * (xk + zk)^2 */ static GEN norm_aux(GEN xk, GEN yk, GEN zk, GEN vk) { GEN t = mpadd(xk, zk); if (typ(t) == t_INT) { /* probably gen_0, avoid loss of accuracy */ yk = addmulimp(yk, sqri(t), vk); } else { yk = mpadd(yk, mpmul(sqrr(t), vk)); } return yk; } /* yk + vk * (xk + zk)^2 < B + epsilon */ static int check_bound(GEN B, GEN xk, GEN yk, GEN zk, GEN vk) { pari_sp av = avma; int f = mpgreaterthan(norm_aux(xk,yk,zk,vk), B); avma = av; return !f; } /* q(k-th canonical basis vector), where q is given in Cholesky form * q(x) = sum_{i = 1}^n q[i,i] (x[i] + sum_{j > i} q[i,j] x[j])^2. * Namely q(e_k) = q[k,k] + sum_{i < k} q[i,i] q[i,k]^2 * Assume 1 <= k <= n. */ static GEN cholesky_norm_ek(GEN q, long k) { GEN t = gcoeff(q,k,k); long i; for (i = 1; i < k; i++) t = norm_aux(gen_0, t, gcoeff(q,i,k), gcoeff(q,i,i)); return t; } /* q is the Cholesky decomposition of a quadratic form * Enumerate vectors whose norm is less than BORNE (Algo 2.5.7), * minimal vectors if BORNE = NULL (implies check = NULL). * If (check != NULL) consider only vectors passing the check, and assumes * we only want the smallest possible vectors */ static GEN smallvectors(GEN q, GEN BORNE, long maxnum, FP_chk_fun *CHECK) { long N = lg(q), n = N-1, i, j, k, s, stockmax, checkcnt = 1; pari_sp av, av1; GEN inc, S, x, y, z, v, p1, alpha, norms; GEN norme1, normax1, borne1, borne2; GEN (*check)(void *,GEN) = CHECK? CHECK->f: NULL; void *data = CHECK? CHECK->data: NULL; const long skipfirst = CHECK? CHECK->skipfirst: 0; const int stockall = (maxnum == -1); alpha = dbltor(0.95); normax1 = gen_0; v = cgetg(N,t_VEC); inc = const_vecsmall(n, 1); av = avma; stockmax = stockall? 2000: maxnum; norms = cgetg(check?(stockmax+1): 1,t_VEC); /* unused if (!check) */ S = cgetg(stockmax+1,t_VEC); x = cgetg(N,t_COL); y = cgetg(N,t_COL); z = cgetg(N,t_COL); for (i=1; i2) err_printf("smallvectors looking for norm < %P.4G\n",borne1); s = 0; k = n; for(;; step(x,y,inc,k)) /* main */ { /* x (supposedly) small vector, ZV. * For all t >= k, we have * z[t] = sum_{j > t} q[t,j] * x[j] * y[t] = sum_{i > t} q[i,i] * (x[i] + z[i])^2 * = 0 <=> x[i]=0 for all i>t */ do { int skip = 0; if (k > 1) { long l = k-1; av1 = avma; p1 = mulimp(gel(x,k), gcoeff(q,l,k)); for (j=k+1; j n) goto END; } if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"smallvectors"); if (stockmax) S = clonefill(S, s, stockmax); if (check) { GEN dummy = cgetg(1, t_STR); for (i=s+1; i<=stockmax; i++) gel(norms,i) = dummy; } gerepileall(av,7,&x,&y,&z,&normax1,&borne1,&borne2,&norms); } } while (k > 1); if (!signe(gel(x,1)) && !signe(gel(y,1))) continue; /* exclude 0 */ av1 = avma; norme1 = norm_aux(gel(x,1),gel(y,1),gel(z,1),gel(v,1)); if (mpgreaterthan(norme1,borne1)) { avma = av1; continue; /* main */ } norme1 = gerepileuptoleaf(av1,norme1); if (check) { if (checkcnt < 5 && mpcmp(norme1, borne2) < 0) { if (!check(data,x)) { checkcnt++ ; continue; /* main */} if (DEBUGLEVEL>4) err_printf("New bound: %Ps", norme1); borne1 = norme1; borne2 = mulrr(borne1, alpha); s = 0; checkcnt = 0; } } else { if (!BORNE) /* find minimal vectors */ { if (mplessthan(norme1, borne1)) { /* strictly smaller vector than previously known */ borne1 = norme1; /* + epsilon */ s = 0; } } else if (mpcmp(norme1,normax1) > 0) normax1 = norme1; } if (++s > stockmax) continue; /* too many vectors: no longer remember */ if (check) gel(norms,s) = norme1; gel(S,s) = leafcopy(x); if (s != stockmax) continue; /* still room, get next vector */ if (check) { /* overflow, eliminate vectors failing "check" */ pari_sp av2 = avma; long imin, imax; GEN per = indexsort(norms), S2 = cgetg(stockmax+1, t_VEC); if (DEBUGLEVEL>2) err_printf("sorting... [%ld elts]\n",s); /* let N be the minimal norm so far for x satisfying 'check'. Keep * all elements of norm N */ for (i = 1; i <= s; i++) { long k = per[i]; if (check(data,gel(S,k))) { borne1 = gel(norms,k); break; } } imin = i; for (; i <= s; i++) if (mpgreaterthan(gel(norms,per[i]), borne1)) break; imax = i; for (i=imin, s=0; i < imax; i++) gel(S2,++s) = gel(S,per[i]); for (i = 1; i <= s; i++) gel(S,i) = gel(S2,i); avma = av2; if (s) { borne2 = mulrr(borne1, alpha); checkcnt = 0; } if (!stockall) continue; if (s > stockmax/2) stockmax <<= 1; norms = cgetg(stockmax+1, t_VEC); for (i = 1; i <= s; i++) gel(norms,i) = borne1; } else { if (!stockall && BORNE) goto END; if (!stockall) continue; stockmax <<= 1; } { GEN Snew = clonefill(vec_lengthen(S,stockmax), s, stockmax); if (isclone(S)) gunclone(S); S = Snew; } } END: if (s < stockmax) stockmax = s; if (check) { GEN per, alph, pols, p; if (DEBUGLEVEL>2) err_printf("final sort & check...\n"); setlg(norms,stockmax+1); per = indexsort(norms); alph = cgetg(stockmax+1,t_VEC); pols = cgetg(stockmax+1,t_VEC); for (j=0,i=1; i<=stockmax; i++) { long t = per[i]; GEN N = gel(norms,t); if (j && mpgreaterthan(N, borne1)) break; if ((p = check(data,gel(S,t)))) { if (!j) borne1 = N; j++; gel(pols,j) = p; gel(alph,j) = gel(S,t); } } setlg(pols,j+1); setlg(alph,j+1); if (stockmax && isclone(S)) { alph = gcopy(alph); gunclone(S); } return mkvec2(pols, alph); } if (stockmax) { setlg(S,stockmax+1); settyp(S,t_MAT); if (isclone(S)) { p1 = S; S = gcopy(S); gunclone(p1); } } else S = cgetg(1,t_MAT); return mkvec3(utoi(s<<1), borne1, S); } /* solve q(x) = x~.a.x <= bound, a > 0. * If check is non-NULL keep x only if check(x). * If a is a vector, assume a[1] is the LLL-reduced Cholesky form of q */ GEN fincke_pohst(GEN a, GEN B0, long stockmax, long PREC, FP_chk_fun *CHECK) { pari_sp av = avma; VOLATILE long i,j,l; VOLATILE GEN r,rinv,rinvtrans,u,v,res,z,vnorm,rperm,perm,uperm, bound = B0; if (typ(a) == t_VEC) { r = gel(a,1); u = NULL; } else { long prec = PREC; l = lg(a); if (l == 1) { if (CHECK) pari_err_TYPE("fincke_pohst [dimension 0]", a); retmkvec3(gen_0, gen_0, cgetg(1,t_MAT)); } u = lllfp(a, 0.75, LLL_GRAM); if (lg(u) != lg(a)) return NULL; r = qf_apply_RgM(a,u); i = gprecision(r); if (i) prec = i; else { prec = DEFAULTPREC + nbits2extraprec(gexpo(r)); if (prec < PREC) prec = PREC; } if (DEBUGLEVEL>2) err_printf("first LLL: prec = %ld\n", prec); r = qfgaussred_positive(r); if (!r) return NULL; for (i=1; i2) err_printf("Fincke-Pohst, final LLL: prec = %ld\n", gprecision(rinvtrans)); v = lll(rinvtrans); if (lg(v) != lg(rinvtrans)) return NULL; rinvtrans = RgM_mul(rinvtrans, v); v = ZM_inv(shallowtrans(v),NULL); r = RgM_mul(r,v); u = u? ZM_mul(u,v): v; l = lg(r); vnorm = cgetg(l,t_VEC); for (j=1; jf_init) bound = CHECK->f_init(CHECK, r, u); q = gaussred_from_QR(r, gprecision(vnorm)); if (!q) pari_err_PREC("fincke_pohst"); res = smallvectors(q, bound, stockmax, CHECK); } pari_ENDCATCH; if (CHECK) { if (CHECK->f_post) res = CHECK->f_post(CHECK, res, u); return res; } if (!res) pari_err_PREC("fincke_pohst"); z = cgetg(4,t_VEC); gel(z,1) = gcopy(gel(res,1)); gel(z,2) = gcopy(gel(res,2)); gel(z,3) = ZM_mul(u, gel(res,3)); return gerepileupto(av,z); } pari-2.11.2/src/basemath/Flx.c0000644000175000017500000040561513455137376014457 0ustar billbill/* Copyright (C) 2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Not so fast arithmetic with polynomials with small coefficients. */ static GEN get_Flx_red(GEN T, GEN *B) { if (typ(T)!=t_VEC) { *B=NULL; return T; } *B = gel(T,1); return gel(T,2); } /***********************************************************************/ /** **/ /** Flx **/ /** **/ /***********************************************************************/ /* Flx objects are defined as follows: Let l an ulong. An Flx is a t_VECSMALL: x[0] = codeword x[1] = evalvarn(variable number) (signe is not stored). x[2] = a_0 x[3] = a_1, etc. With 0 <= a_i < l signe(x) is not valid. Use degpol(x)>=0 instead. */ /***********************************************************************/ /** **/ /** Conversion from Flx **/ /** **/ /***********************************************************************/ GEN Flx_to_ZX(GEN z) { long i, l = lg(z); GEN x = cgetg(l,t_POL); for (i=2; i1; i--) if (x[i]) break; stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1)); setlg(x, i+1); return x; } GEN Flx_red(GEN z, ulong p) { long i, l = lg(z); GEN x = cgetg(l, t_VECSMALL); x[1] = z[1]; for (i=2; ilx) swapspec(x,y, lx,ly); lz = lx+2; z = cgetg(lz, t_VECSMALL) + 2; for (i=0; ilx) swapspec(x,y, lx,ly); lz = lx; z = cgetg(lz, t_VECSMALL); z[1]=x[1]; for (i=2; i=0 and a\x^(-n) if n<0 */ GEN Flx_shift(GEN a, long n) { long i, l = lg(a); GEN b; if (l==2 || !n) return Flx_copy(a); if (l+n<=2) return pol0_Flx(a[1]); b = cgetg(l+n, t_VECSMALL); b[1] = a[1]; if (n < 0) for (i=2-n; i 0, x > 0 and y >= 0 */ static GEN Flx_addshift(GEN x, GEN y, ulong p, long d) { GEN xd,yd,zd = (GEN)avma; long a,lz,ny = lgpol(y), nx = lgpol(x); long vs = x[1]; x += 2; y += 2; a = ny-d; if (a <= 0) { lz = (a>nx)? ny+2: nx+d+2; (void)new_chunk(lz); xd = x+nx; yd = y+ny; while (xd > x) *--zd = *--xd; x = zd + a; while (zd > x) *--zd = 0; } else { xd = new_chunk(d); yd = y+d; x = Flx_addspec(x,yd,p, nx,a); lz = (a>nx)? ny+2: lg(x)+d; x += 2; while (xd > x) *--zd = *--xd; } while (yd > y) *--zd = *--yd; *--zd = vs; *--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd; } /* shift polynomial + gerepile */ /* Do not set evalvarn*/ static GEN Flx_shiftip(pari_sp av, GEN x, long v) { long i, lx = lg(x), ly; GEN y; if (!v || lx==2) return gerepileuptoleaf(av, x); ly = lx + v; /* result length */ (void)new_chunk(ly); /* check that result fits */ x += lx; y = (GEN)av; for (i = 2; i> 1) #define QUARTMASK ((1UL<> BITS_IN_QUARTULONG) & QUARTMASK) #define LHQUARTWORD(x) (((x) >> (2*BITS_IN_QUARTULONG)) & QUARTMASK) #define HHQUARTWORD(x) (((x) >> (3*BITS_IN_QUARTULONG)) & QUARTMASK) INLINE long maxlengthcoeffpol(ulong p, long n) { pari_sp ltop = avma; GEN z = muliu(sqru(p-1), n); long l = lgefint(z); avma = ltop; if (l==3 && HIGHWORD(z[2])==0) { if (HLQUARTWORD(z[2]) == 0) return -1; else return 0; } return l-2; } INLINE ulong Flx_mullimb_ok(GEN x, GEN y, ulong p, long a, long b) { /* Assume OK_ULONG*/ ulong p1 = 0; long i; for (i=a; i= ny > 0 */ static GEN Flx_mulspec_basecase(GEN x, GEN y, ulong p, long nx, long ny) { long i,lz,nz; GEN z; lz = nx+ny+1; nz = lz-2; z = cgetg(lz, t_VECSMALL) + 2; /* x:y:z [i] = term of degree i */ if (SMALL_ULONG(p)) { for (i=0; i>1UL; GEN V = cgetipos(2+n); GEN w; for (w = int_LSW(V), j=0; j+1>2UL; GEN V = cgetipos(2+n); GEN w; for (w = int_LSW(V), j=0; j+3=Flx_MUL_QUARTMULII_LIMIT) return Flx_shiftip(av,Flx_mulspec_quartmulii(a,b,p,na,nb), v); break; case 0: if (na>=Flx_MUL_HALFMULII_LIMIT) return Flx_shiftip(av,Flx_mulspec_halfmulii(a,b,p,na,nb), v); break; case 1: if (na>=Flx_MUL_MULII_LIMIT) return Flx_shiftip(av,Flx_mulspec_mulii(a,b,p,na,nb), v); break; case 2: if (na>=Flx_MUL_MULII2_LIMIT) return Flx_shiftip(av,Flx_mulspec_mulii_inflate(a,b,2,p,na,nb), v); break; case 3: if (na>70) return Flx_shiftip(av,Flx_mulspec_mulii_inflate(a,b,3,p,na,nb), v); break; } if (nb < Flx_MUL_KARATSUBA_LIMIT) return Flx_shiftip(av,Flx_mulspec_basecase(a,b,p,na,nb), v); i=(na>>1); n0=na-i; na=i; a0=a+n0; n0a=n0; while (n0a && !a[n0a-1]) n0a--; if (nb > n0) { GEN b0,c1,c2; long n0b; nb -= n0; b0 = b+n0; n0b = n0; while (n0b && !b[n0b-1]) n0b--; c = Flx_mulspec(a,b,p,n0a,n0b); c0 = Flx_mulspec(a0,b0,p,na,nb); c2 = Flx_addspec(a0,a,p,na,n0a); c1 = Flx_addspec(b0,b,p,nb,n0b); c1 = Flx_mul(c1,c2,p); c2 = Flx_add(c0,c,p); c2 = Flx_neg_inplace(c2,p); c2 = Flx_add(c1,c2,p); c0 = Flx_addshift(c0,c2 ,p, n0); } else { c = Flx_mulspec(a,b,p,n0a,nb); c0 = Flx_mulspec(a0,b,p,na,nb); } c0 = Flx_addshift(c0,c,p,n0); return Flx_shiftip(av,c0, v); } GEN Flx_mul(GEN x, GEN y, ulong p) { GEN z = Flx_mulspec(x+2,y+2,p, lgpol(x),lgpol(y)); z[1] = x[1]; return z; } static GEN Flx_sqrspec_basecase(GEN x, ulong p, long nx) { long i, lz, nz; ulong p1; GEN z; if (!nx) return pol0_Flx(0); lz = (nx << 1) + 1, nz = lz-2; z = cgetg(lz, t_VECSMALL) + 2; if (SMALL_ULONG(p)) { z[0] = x[0]*x[0]%p; for (i=1; i>1); p1 <<= 1; if ((i&1) == 0) p1 += x[i>>1] * x[i>>1]; z[i] = p1 % p; } for ( ; i>1); p1 <<= 1; if ((i&1) == 0) p1 += x[i>>1] * x[i>>1]; z[i] = p1 % p; } } else { ulong pi = get_Fl_red(p); z[0] = Fl_sqr_pre(x[0], p, pi); for (i=1; i>1); p1 = Fl_add(p1, p1, p); if ((i&1) == 0) p1 = Fl_add(p1, Fl_sqr_pre(x[i>>1], p, pi), p); z[i] = p1; } for ( ; i>1); p1 = Fl_add(p1, p1, p); if ((i&1) == 0) p1 = Fl_add(p1, Fl_sqr_pre(x[i>>1], p, pi), p); z[i] = p1; } } z -= 2; return Flx_renormalize(z, lz); } static GEN Flx_sqrspec_sqri(GEN a, ulong p, long na) { GEN z=sqrispec(a,na); return int_to_Flx(z,p); } static GEN Flx_sqrspec_halfsqri(GEN a, ulong p, long na) { GEN z = sqri(Flx_to_int_halfspec(a,na)); return int_to_Flx_half(z,p); } static GEN Flx_sqrspec_quartsqri(GEN a, ulong p, long na) { GEN z = sqri(Flx_to_int_quartspec(a,na)); return int_to_Flx_quart(z,p); } static GEN Flx_sqrspec_sqri_inflate(GEN x, long N, ulong p, long nx) { pari_sp av = avma; GEN z = sqri(Flx_eval2BILspec(x,N,nx)); return gerepileupto(av, Z_mod2BIL_Flx(z, N, (nx-1)*2, p)); } static GEN Flx_sqrspec(GEN a, ulong p, long na) { GEN a0, c, c0; long n0, n0a, i, v = 0; pari_sp av; while (na && !a[0]) { a++; na--; v += 2; } if (!na) return pol0_Flx(0); av = avma; switch(maxlengthcoeffpol(p,na)) { case -1: if (na>=Flx_SQR_QUARTSQRI_LIMIT) return Flx_shiftip(av, Flx_sqrspec_quartsqri(a,p,na), v); break; case 0: if (na>=Flx_SQR_HALFSQRI_LIMIT) return Flx_shiftip(av, Flx_sqrspec_halfsqri(a,p,na), v); break; case 1: if (na>=Flx_SQR_SQRI_LIMIT) return Flx_shiftip(av, Flx_sqrspec_sqri(a,p,na), v); break; case 2: if (na>=Flx_SQR_SQRI2_LIMIT) return Flx_shiftip(av, Flx_sqrspec_sqri_inflate(a,2,p,na), v); break; case 3: if (na>70) return Flx_shiftip(av, Flx_sqrspec_sqri_inflate(a,3,p,na), v); break; } if (na < Flx_SQR_KARATSUBA_LIMIT) return Flx_shiftip(av, Flx_sqrspec_basecase(a,p,na), v); i=(na>>1); n0=na-i; na=i; a0=a+n0; n0a=n0; while (n0a && !a[n0a-1]) n0a--; c = Flx_sqrspec(a,p,n0a); c0= Flx_sqrspec(a0,p,na); if (p == 2) n0 *= 2; else { GEN c1, t = Flx_addspec(a0,a,p,na,n0a); t = Flx_sqr(t,p); c1= Flx_add(c0,c, p); c1= Flx_sub(t, c1, p); c0 = Flx_addshift(c0,c1,p,n0); } c0 = Flx_addshift(c0,c,p,n0); return Flx_shiftip(av,c0,v); } GEN Flx_sqr(GEN x, ulong p) { GEN z = Flx_sqrspec(x+2,p, lgpol(x)); z[1] = x[1]; return z; } GEN Flx_powu(GEN x, ulong n, ulong p) { GEN y = pol1_Flx(x[1]), z; ulong m; if (n == 0) return y; m = n; z = x; for (;;) { if (m&1UL) y = Flx_mul(y,z, p); m >>= 1; if (!m) return y; z = Flx_sqr(z, p); } } GEN Flx_halve(GEN y, ulong p) { GEN z; long i, l; z = cgetg_copy(y, &l); z[1] = y[1]; for(i=2; i=2; i--) { Q[i] = Fl_mul(P[i], hi, p); if (i == 2) break; hi = Fl_mul(hi,h, p); } Q[1] = P[1]; return Q; } static long Flx_multhreshold(GEN T, ulong p, long quart, long half, long mul, long mul2, long kara) { long na = lgpol(T); switch (maxlengthcoeffpol(p,na)) { case -1: if (na>=Flx_MUL_QUARTMULII_LIMIT) return na>=quart; break; case 0: if (na>=Flx_MUL_HALFMULII_LIMIT) return na>=half; break; case 1: if (na>=Flx_MUL_MULII_LIMIT) return na>=mul; break; case 2: if (na>=Flx_MUL_MULII2_LIMIT) return na>=mul2; break; case 3: if (na>=70) return na>=70; break; } return na>=kara; } /* * x/polrecip(P)+O(x^n) */ static GEN Flx_invBarrett_basecase(GEN T, ulong p) { long i, l=lg(T)-1, lr=l-1, k; GEN r=cgetg(lr,t_VECSMALL); r[1] = T[1]; r[2] = 1; if (SMALL_ULONG(p)) for (i=3;i=0; i--) if (x[i]) break; return i+1; } static GEN Flx_invBarrett_Newton(GEN T, ulong p) { long nold, lx, lz, lq, l = degpol(T), lQ; GEN q, y, z, x = zero_zv(l+1) + 2; ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */ pari_sp av; y = T+2; q = Flx_recipspec(y,l+1,l+1); lQ = lgpol(q); q+=2; av = avma; /* We work on _spec_ Flx's, all the l[xzq12] below are lgpol's */ /* initialize */ x[0] = Fl_inv(q[0], p); if (lQ>1 && q[1]) { ulong u = q[1]; if (x[0] != 1) u = Fl_mul(u, Fl_sqr(x[0],p), p); x[1] = p - u; lx = 2; } else lx = 1; nold = 1; for (; mask > 1; avma = av) { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */ long i, lnew, nnew = nold << 1; if (mask & 1) nnew--; mask >>= 1; lnew = nnew + 1; lq = Flx_lgrenormalizespec(q, minss(lQ, lnew)); z = Flx_mulspec(x, q, p, lx, lq); /* FIXME: high product */ lz = lgpol(z); if (lz > lnew) lz = lnew; z += 2; /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */ for (i = nold; i < lz; i++) if (z[i]) break; nold = nnew; if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */ /* z + i represents (x*q - 1) / t^i */ lz = Flx_lgrenormalizespec (z+i, lz-i); z = Flx_mulspec(x, z+i, p, lx, lz); /* FIXME: low product */ lz = lgpol(z); z += 2; if (lz > lnew-i) lz = Flx_lgrenormalizespec(z, lnew-i); lx = lz+ i; y = x + i; /* x -= z * t^i, in place */ for (i = 0; i < lz; i++) y[i] = Fl_neg(z[i], p); } x -= 2; setlg(x, lx + 2); x[1] = T[1]; return x; } /* x/polrecip(T)+O(x^deg(T)) */ GEN Flx_invBarrett(GEN T, ulong p) { pari_sp ltop=avma; long l=lg(T); GEN r; if (l<5) return pol0_Flx(T[1]); if (!Flx_multhreshold(T,p, Flx_INVBARRETT_QUARTMULII_LIMIT, Flx_INVBARRETT_HALFMULII_LIMIT, Flx_INVBARRETT_MULII_LIMIT, Flx_INVBARRETT_MULII2_LIMIT, Flx_INVBARRETT_KARATSUBA_LIMIT)) { ulong c = T[l-1]; if (c!=1) { ulong ci = Fl_inv(c,p); T=Flx_Fl_mul(T, ci, p); r=Flx_invBarrett_basecase(T,p); r=Flx_Fl_mul(r,ci,p); } else r=Flx_invBarrett_basecase(T,p); } else r = Flx_invBarrett_Newton(T,p); return gerepileuptoleaf(ltop, r); } GEN Flx_get_red(GEN T, ulong p) { if (typ(T)!=t_VECSMALL || !Flx_multhreshold(T,p, Flx_BARRETT_QUARTMULII_LIMIT, Flx_BARRETT_HALFMULII_LIMIT, Flx_BARRETT_MULII_LIMIT, Flx_BARRETT_MULII2_LIMIT, Flx_BARRETT_KARATSUBA_LIMIT)) return T; retmkvec2(Flx_invBarrett(T,p),T); } /* separate from Flx_divrem for maximal speed. */ static GEN Flx_rem_basecase(GEN x, GEN y, ulong p) { pari_sp av; GEN z, c; long dx,dy,dy1,dz,i,j; ulong p1,inv; long vs=x[1]; dy = degpol(y); if (!dy) return pol0_Flx(x[1]); dx = degpol(x); dz = dx-dy; if (dz < 0) return Flx_copy(x); x += 2; y += 2; inv = y[dy]; if (inv != 1UL) inv = Fl_inv(inv,p); for (dy1=dy-1; dy1>=0 && !y[dy1]; dy1--); c = cgetg(dy+3, t_VECSMALL); c[1]=vs; c += 2; av=avma; z = cgetg(dz+3, t_VECSMALL); z[1]=vs; z += 2; if (SMALL_ULONG(p)) { z[dz] = (inv*x[dx]) % p; for (i=dx-1; i>=dy; --i) { p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */ for (j=i-dy1; j<=i && j<=dz; j++) { p1 += z[j]*y[i-j]; if (p1 & HIGHBIT) p1 %= p; } p1 %= p; z[i-dy] = p1? ((p - p1)*inv) % p: 0; } for (i=0; i=dy; --i) { p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */ for (j=i-dy1; j<=i && j<=dz; j++) p1 = Fl_addmul_pre(p1, z[j], y[i - j], p, pi); z[i-dy] = p1? Fl_mul_pre(p - p1, inv, p, pi): 0; } for (i=0; i=0 && !c[i]) i--; avma=av; return Flx_renormalize(c-2, i+3); } /* as FpX_divrem but working only on ulong types. * if relevant, *pr is the last object on stack */ static GEN Flx_divrem_basecase(GEN x, GEN y, ulong p, GEN *pr) { GEN z,q,c; long dx,dy,dy1,dz,i,j; ulong p1,inv; long sv=x[1]; dy = degpol(y); if (dy<0) pari_err_INV("Flx_divrem",y); if (pr == ONLY_REM) return Flx_rem_basecase(x, y, p); if (!dy) { if (pr && pr != ONLY_DIVIDES) *pr = pol0_Flx(sv); if (y[2] == 1UL) return Flx_copy(x); return Flx_Fl_mul(x, Fl_inv(y[2], p), p); } dx = degpol(x); dz = dx-dy; if (dz < 0) { q = pol0_Flx(sv); if (pr && pr != ONLY_DIVIDES) *pr = Flx_copy(x); return q; } x += 2; y += 2; z = cgetg(dz + 3, t_VECSMALL); z[1] = sv; z += 2; inv = uel(y, dy); if (inv != 1UL) inv = Fl_inv(inv,p); for (dy1=dy-1; dy1>=0 && !y[dy1]; dy1--); if (SMALL_ULONG(p)) { z[dz] = (inv*x[dx]) % p; for (i=dx-1; i>=dy; --i) { p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */ for (j=i-dy1; j<=i && j<=dz; j++) { p1 += z[j]*y[i-j]; if (p1 & HIGHBIT) p1 %= p; } p1 %= p; z[i-dy] = p1? (long) ((p - p1)*inv) % p: 0; } } else { z[dz] = Fl_mul(inv, x[dx], p); for (i=dx-1; i>=dy; --i) { /* compute -p1 instead of p1 (pb with ulongs otherwise) */ p1 = p - uel(x,i); for (j=i-dy1; j<=i && j<=dz; j++) p1 = Fl_add(p1, Fl_mul(z[j],y[i-j],p), p); z[i-dy] = p1? Fl_mul(p - p1, inv, p): 0; } } q = Flx_renormalize(z-2, dz+3); if (!pr) return q; c = cgetg(dy + 3, t_VECSMALL); c[1] = sv; c += 2; if (SMALL_ULONG(p)) { for (i=0; i=0 && !c[i]) i--; c = Flx_renormalize(c-2, i+3); if (pr == ONLY_DIVIDES) { if (lg(c) != 2) return NULL; } else *pr = c; return q; } /* Compute x mod T where 2 <= degpol(T) <= l+1 <= 2*(degpol(T)-1) * and mg is the Barrett inverse of T. */ static GEN Flx_divrem_Barrettspec(GEN x, long l, GEN mg, GEN T, ulong p, GEN *pr) { GEN q, r; long lt = degpol(T); /*We discard the leading term*/ long ld, lm, lT, lmg; ld = l-lt; lm = minss(ld, lgpol(mg)); lT = Flx_lgrenormalizespec(T+2,lt); lmg = Flx_lgrenormalizespec(mg+2,lm); q = Flx_recipspec(x+lt,ld,ld); /* q = rec(x) lz<=ld*/ q = Flx_mulspec(q+2,mg+2,p,lgpol(q),lmg); /* q = rec(x) * mg lz<=ld+lm*/ q = Flx_recipspec(q+2,minss(ld,lgpol(q)),ld);/* q = rec (rec(x) * mg) lz<=ld*/ if (!pr) return q; r = Flx_mulspec(q+2,T+2,p,lgpol(q),lT); /* r = q*pol lz<=ld+lt*/ r = Flx_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - q*pol lz<=lt */ if (pr == ONLY_REM) return r; *pr = r; return q; } static GEN Flx_divrem_Barrett_noGC(GEN x, GEN mg, GEN T, ulong p, GEN *pr) { long l = lgpol(x), lt = degpol(T), lm = 2*lt-1; GEN q = NULL, r; long i; if (l <= lt) { if (pr == ONLY_REM) return Flx_copy(x); if (pr == ONLY_DIVIDES) return lgpol(x)? NULL: pol0_Flx(x[1]); if (pr) *pr = Flx_copy(x); return pol0_Flx(x[1]); } if (lt <= 1) return Flx_divrem_basecase(x,T,p,pr); if (pr != ONLY_REM && l>lm) q = zero_zv(l-lt+1); r = Flx_copy(x); while (l>lm) { GEN zr, zq = Flx_divrem_Barrettspec(r+2+l-lm,lm,mg,T,p,&zr); long lz = lgpol(zr); if (pr != ONLY_REM) { long lq = lgpol(zq); for(i=0; i lt) { GEN zq = Flx_divrem_Barrettspec(r+2,l,mg,T,p,&r); if (!q) q = zq; else { long lq = lgpol(zq); for(i=0; i lt) r = Flx_divrem_Barrettspec(r+2,l,mg,T,p,ONLY_REM); else r = Flx_renormalize(r, l+2); r[1] = x[1]; return Flx_renormalize(r, lg(r)); } if (pr) { r[1] = x[1]; r = Flx_renormalize(r, lg(r)); } q[1] = x[1]; q = Flx_renormalize(q, lg(q)); if (pr == ONLY_DIVIDES) return lgpol(r)? NULL: q; if (pr) *pr = r; return q; } GEN Flx_divrem(GEN x, GEN T, ulong p, GEN *pr) { GEN B, y = get_Flx_red(T, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (pr==ONLY_REM) return Flx_rem(x, y, p); if (!B && d+3 < Flx_DIVREM_BARRETT_LIMIT) return Flx_divrem_basecase(x,y,p,pr); else { pari_sp av=avma; GEN mg = B? B: Flx_invBarrett(y, p); GEN q1 = Flx_divrem_Barrett_noGC(x,mg,y,p,pr); if (!q1) {avma=av; return NULL;} if (!pr || pr==ONLY_DIVIDES) return gerepileuptoleaf(av, q1); gerepileall(av,2,&q1,pr); return q1; } } GEN Flx_rem(GEN x, GEN T, ulong p) { GEN B, y = get_Flx_red(T, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (d < 0) return Flx_copy(x); if (!B && d+3 < Flx_REM_BARRETT_LIMIT) return Flx_rem_basecase(x,y,p); else { pari_sp av=avma; GEN mg = B ? B: Flx_invBarrett(y, p); GEN r = Flx_divrem_Barrett_noGC(x, mg, y, p, ONLY_REM); return gerepileuptoleaf(av, r); } } /* reduce T mod (X^n - 1, p). Shallow function */ GEN Flx_mod_Xnm1(GEN T, ulong n, ulong p) { long i, j, L = lg(T), l = n+2; GEN S; if (L <= l || n & ~LGBITS) return T; S = cgetg(l, t_VECSMALL); S[1] = T[1]; for (i = 2; i < l; i++) S[i] = T[i]; for (j = 2; i < L; i++) { S[j] = Fl_add(S[j], T[i], p); if (++j == l) j = 2; } return Flx_renormalize(S, l); } /* reduce T mod (X^n + 1, p). Shallow function */ GEN Flx_mod_Xn1(GEN T, ulong n, ulong p) { long i, j, L = lg(T), l = n+2; GEN S; if (L <= l || n & ~LGBITS) return T; S = cgetg(l, t_VECSMALL); S[1] = T[1]; for (i = 2; i < l; i++) S[i] = T[i]; for (j = 2; i < L; i++) { S[j] = Fl_sub(S[j], T[i], p); if (++j == l) j = 2; } return Flx_renormalize(S, l); } struct _Flxq { GEN aut; GEN T; ulong p; }; static GEN _Flx_divrem(void * E, GEN x, GEN y, GEN *r) { struct _Flxq *D = (struct _Flxq*) E; return Flx_divrem(x, y, D->p, r); } static GEN _Flx_add(void * E, GEN x, GEN y) { struct _Flxq *D = (struct _Flxq*) E; return Flx_add(x, y, D->p); } static GEN _Flx_mul(void *E, GEN x, GEN y) { struct _Flxq *D = (struct _Flxq*) E; return Flx_mul(x, y, D->p); } static GEN _Flx_sqr(void *E, GEN x) { struct _Flxq *D = (struct _Flxq*) E; return Flx_sqr(x, D->p); } static struct bb_ring Flx_ring = { _Flx_add,_Flx_mul,_Flx_sqr }; GEN Flx_digits(GEN x, GEN T, ulong p) { pari_sp av = avma; struct _Flxq D; long d = degpol(T), n = (lgpol(x)+d-1)/d; GEN z; D.p = p; z = gen_digits(x,T,n,(void *)&D, &Flx_ring, _Flx_divrem); return gerepileupto(av, z); } GEN FlxV_Flx_fromdigits(GEN x, GEN T, ulong p) { pari_sp av = avma; struct _Flxq D; GEN z; D.p = p; z = gen_fromdigits(x,T,(void *)&D, &Flx_ring); return gerepileupto(av, z); } long Flx_val(GEN x) { long i, l=lg(x); if (l==2) return LONG_MAX; for (i=2; i>1; u1 = v = pol0_Flx(vx); u = v1 = pol1_Flx(vx); while (lgpol(b)>n) { GEN r, q = Flx_divrem(a,b,p, &r); a = b; b = r; swap(u,u1); swap(v,v1); u1 = Flx_sub(u1, Flx_mul(u, q, p), p); v1 = Flx_sub(v1, Flx_mul(v, q ,p), p); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"Flx_halfgcd (d = %ld)",degpol(b)); gerepileall(av,6, &a,&b,&u1,&v1,&u,&v); } } return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1))); } /* ux + vy */ static GEN Flx_addmulmul(GEN u, GEN v, GEN x, GEN y, ulong p) { return Flx_add(Flx_mul(u,x, p), Flx_mul(v,y, p), p); } static GEN FlxM_Flx_mul2(GEN M, GEN x, GEN y, ulong p) { GEN res = cgetg(3, t_COL); gel(res, 1) = Flx_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, p); gel(res, 2) = Flx_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, p); return res; } #if 0 static GEN FlxM_mul2_old(GEN M, GEN N, ulong p) { GEN res = cgetg(3, t_MAT); gel(res, 1) = FlxM_Flx_mul2(M,gcoeff(N,1,1),gcoeff(N,2,1),p); gel(res, 2) = FlxM_Flx_mul2(M,gcoeff(N,1,2),gcoeff(N,2,2),p); return res; } #endif /* A,B are 2x2 matrices, Flx entries. Return A x B using Strassen 7M formula */ static GEN FlxM_mul2(GEN A, GEN B, ulong p) { GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2); GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2); GEN M1 = Flx_mul(Flx_add(A11,A22, p), Flx_add(B11,B22, p), p); GEN M2 = Flx_mul(Flx_add(A21,A22, p), B11, p); GEN M3 = Flx_mul(A11, Flx_sub(B12,B22, p), p); GEN M4 = Flx_mul(A22, Flx_sub(B21,B11, p), p); GEN M5 = Flx_mul(Flx_add(A11,A12, p), B22, p); GEN M6 = Flx_mul(Flx_sub(A21,A11, p), Flx_add(B11,B12, p), p); GEN M7 = Flx_mul(Flx_sub(A12,A22, p), Flx_add(B21,B22, p), p); GEN T1 = Flx_add(M1,M4, p), T2 = Flx_sub(M7,M5, p); GEN T3 = Flx_sub(M1,M2, p), T4 = Flx_add(M3,M6, p); retmkmat2(mkcol2(Flx_add(T1,T2, p), Flx_add(M2,M4, p)), mkcol2(Flx_add(M3,M5, p), Flx_add(T3,T4, p))); } /* Return [0,1;1,-q]*M */ static GEN Flx_FlxM_qmul(GEN q, GEN M, ulong p) { GEN u, v, res = cgetg(3, t_MAT); u = Flx_sub(gcoeff(M,1,1), Flx_mul(gcoeff(M,2,1), q, p), p); gel(res,1) = mkcol2(gcoeff(M,2,1), u); v = Flx_sub(gcoeff(M,1,2), Flx_mul(gcoeff(M,2,2), q, p), p); gel(res,2) = mkcol2(gcoeff(M,2,2), v); return res; } static GEN matid2_FlxM(long v) { return mkmat2(mkcol2(pol1_Flx(v),pol0_Flx(v)), mkcol2(pol0_Flx(v),pol1_Flx(v))); } static GEN Flx_halfgcd_split(GEN x, GEN y, ulong p) { pari_sp av=avma; GEN R, S, V; GEN y1, r, q; long l = lgpol(x), n = l>>1, k; if (lgpol(y)<=n) return matid2_FlxM(x[1]); R = Flx_halfgcd(Flx_shift(x,-n),Flx_shift(y,-n),p); V = FlxM_Flx_mul2(R,x,y,p); y1 = gel(V,2); if (lgpol(y1)<=n) return gerepilecopy(av, R); q = Flx_divrem(gel(V,1), y1, p, &r); k = 2*n-degpol(y1); S = Flx_halfgcd(Flx_shift(y1,-k), Flx_shift(r,-k),p); return gerepileupto(av, FlxM_mul2(S,Flx_FlxM_qmul(q,R,p),p)); } /* Return M in GL_2(Fl[X]) such that: if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b') */ static GEN Flx_halfgcd_i(GEN x, GEN y, ulong p) { if (!Flx_multhreshold(x,p, Flx_HALFGCD_QUARTMULII_LIMIT, Flx_HALFGCD_HALFMULII_LIMIT, Flx_HALFGCD_MULII_LIMIT, Flx_HALFGCD_MULII2_LIMIT, Flx_HALFGCD_KARATSUBA_LIMIT)) return Flx_halfgcd_basecase(x,y,p); return Flx_halfgcd_split(x,y,p); } GEN Flx_halfgcd(GEN x, GEN y, ulong p) { pari_sp av; GEN M,q,r; long lx=lgpol(x), ly=lgpol(y); if (!lx) { long v = x[1]; retmkmat2(mkcol2(pol0_Flx(v),pol1_Flx(v)), mkcol2(pol1_Flx(v),pol0_Flx(v))); } if (ly < lx) return Flx_halfgcd_i(x,y,p); av = avma; q = Flx_divrem(y,x,p,&r); M = Flx_halfgcd_i(x,r,p); gcoeff(M,1,1) = Flx_sub(gcoeff(M,1,1), Flx_mul(q, gcoeff(M,1,2), p), p); gcoeff(M,2,1) = Flx_sub(gcoeff(M,2,1), Flx_mul(q, gcoeff(M,2,2), p), p); return gerepilecopy(av, M); } /*Do not garbage collect*/ static GEN Flx_gcd_basecase(GEN a, GEN b, ulong p) { pari_sp av = avma; ulong iter = 0; if (lg(b) > lg(a)) swap(a, b); while (lgpol(b)) { GEN c = Flx_rem(a,b,p); iter++; a = b; b = c; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"Flx_gcd (d = %ld)",degpol(c)); gerepileall(av,2, &a,&b); } } return iter < 2 ? Flx_copy(a) : a; } GEN Flx_gcd(GEN x, GEN y, ulong p) { pari_sp av = avma; if (!lgpol(x)) return Flx_copy(y); while (lg(y)>Flx_GCD_LIMIT) { GEN c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r = Flx_rem(x, y, p); x = y; y = r; } c = FlxM_Flx_mul2(Flx_halfgcd(x,y, p), x, y, p); x = gel(c,1); y = gel(c,2); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"Flx_gcd (y = %ld)",degpol(y)); gerepileall(av,2,&x,&y); } } return gerepileuptoleaf(av, Flx_gcd_basecase(x,y,p)); } int Flx_is_squarefree(GEN z, ulong p) { pari_sp av = avma; GEN d = Flx_gcd(z, Flx_deriv(z,p) , p); long res= (degpol(d) == 0); avma = av; return res; } static long Flx_is_smooth_squarefree(GEN f, long r, ulong p) { pari_sp av = avma; long i; GEN sx = polx_Flx(f[1]), a = sx; for(i=1;;i++) { if (degpol(f)<=r) {avma = av; return 1;} a = Flxq_powu(Flx_rem(a,f,p), p, f, p); if (Flx_equal(a, sx)) {avma = av; return 1;} if (i==r) {avma = av; return 0;} f = Flx_div(f, Flx_gcd(Flx_sub(a,sx,p),f,p),p); } } static long Flx_is_l_pow(GEN x, ulong p) { ulong i, lx = lgpol(x); for (i=1; i1) pari_warn(warnmem,"Flx_extgcd (d = %ld)",degpol(d)); gerepileall(av,5, &d,&d1,&u,&v,&v1); } } if (ptu) *ptu = Flx_div(Flx_sub(d, Flx_mul(b,v,p), p), a, p); *ptv = v; return d; } static GEN Flx_extgcd_halfgcd(GEN x, GEN y, ulong p, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,R = matid2_FlxM(x[1]); while (lg(y)>Flx_EXTGCD_LIMIT) { GEN M, c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r, q = Flx_divrem(x, y, p, &r); x = y; y = r; R = Flx_FlxM_qmul(q, R, p); } M = Flx_halfgcd(x,y, p); c = FlxM_Flx_mul2(M, x,y, p); R = FlxM_mul2(M, R, p); x = gel(c,1); y = gel(c,2); gerepileall(av,3,&x,&y,&R); } y = Flx_extgcd_basecase(x,y,p,&u,&v); if (ptu) *ptu = Flx_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1),p); *ptv = Flx_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2),p); return y; } /* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st * ux + vy = gcd (mod p) */ GEN Flx_extgcd(GEN x, GEN y, ulong p, GEN *ptu, GEN *ptv) { GEN d; pari_sp ltop=avma; if (lg(y)>Flx_EXTGCD_LIMIT) d = Flx_extgcd_halfgcd(x, y, p, ptu, ptv); else d = Flx_extgcd_basecase(x, y, p, ptu, ptv); gerepileall(ltop,ptu?3:2,&d,ptv,ptu); return d; } ulong Flx_resultant(GEN a, GEN b, ulong p) { long da,db,dc,cnt; ulong lb, res = 1UL; pari_sp av; GEN c; if (lgpol(a)==0 || lgpol(b)==0) return 0; da = degpol(a); db = degpol(b); if (db > da) { swapspec(a,b, da,db); if (both_odd(da,db)) res = p-res; } else if (!da) return 1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */ cnt = 0; av = avma; while (db) { lb = b[db+2]; c = Flx_rem(a,b, p); a = b; b = c; dc = degpol(c); if (dc < 0) { avma = av; return 0; } if (both_odd(da,db)) res = p - res; if (lb != 1) res = Fl_mul(res, Fl_powu(lb, da - dc, p), p); if (++cnt == 100) { cnt = 0; gerepileall(av, 2, &a, &b); } da = db; /* = degpol(a) */ db = dc; /* = degpol(b) */ } avma = av; return Fl_mul(res, Fl_powu(b[2], da, p), p); } /* If resultant is 0, *ptU and *ptU are not set */ ulong Flx_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV) { GEN z,q,u,v, x = a, y = b; ulong lb, res = 1UL; pari_sp av = avma; long dx, dy, dz; long vs=a[1]; dx = degpol(x); dy = degpol(y); if (dy > dx) { swap(x,y); lswap(dx,dy); pswap(ptU, ptV); a = x; b = y; if (both_odd(dx,dy)) res = p-res; } /* dx <= dy */ if (dx < 0) return 0; u = pol0_Flx(vs); v = pol1_Flx(vs); /* v = 1 */ while (dy) { /* b u = x (a), b v = y (a) */ lb = y[dy+2]; q = Flx_divrem(x,y, p, &z); x = y; y = z; /* (x,y) = (y, x - q y) */ dz = degpol(z); if (dz < 0) { avma = av; return 0; } z = Flx_sub(u, Flx_mul(q,v, p), p); u = v; v = z; /* (u,v) = (v, u - q v) */ if (both_odd(dx,dy)) res = p - res; if (lb != 1) res = Fl_mul(res, Fl_powu(lb, dx-dz, p), p); dx = dy; /* = degpol(x) */ dy = dz; /* = degpol(y) */ } res = Fl_mul(res, Fl_powu(y[2], dx, p), p); lb = Fl_mul(res, Fl_inv(y[2],p), p); v = gerepileuptoleaf(av, Flx_Fl_mul(v, lb, p)); av = avma; u = Flx_sub(Fl_to_Flx(res,vs), Flx_mul(b,v,p), p); u = gerepileuptoleaf(av, Flx_div(u,a,p)); /* = (res - b v) / a */ *ptU = u; *ptV = v; return res; } ulong Flx_eval_powers_pre(GEN x, GEN y, ulong p, ulong pi) { ulong l0, l1, h0, h1, v1, i = 1, lx = lg(x)-1; LOCAL_OVERFLOW; LOCAL_HIREMAINDER; x++; if (lx == 1) return 0; l1 = mulll(uel(x,i), uel(y,i)); h1 = hiremainder; v1 = 0; while (++i < lx) { l0 = mulll(uel(x,i), uel(y,i)); h0 = hiremainder; l1 = addll(l0, l1); h1 = addllx(h0, h1); v1 += overflow; } if (v1 == 0) return remll_pre(h1, l1, p, pi); else return remlll_pre(v1, h1, l1, p, pi); } INLINE ulong Flx_eval_pre_i(GEN x, ulong y, ulong p, ulong pi) { ulong p1; long i=lg(x)-1; if (i<=2) return (i==2)? x[2]: 0; p1 = x[i]; for (i--; i>=2; i--) p1 = Fl_addmul_pre(uel(x, i), p1, y, p, pi); return p1; } ulong Flx_eval_pre(GEN x, ulong y, ulong p, ulong pi) { if (degpol(x) > 15) { pari_sp av = avma; GEN v = Fl_powers_pre(y, degpol(x), p, pi); ulong r = Flx_eval_powers_pre(x, v, p, pi); avma = av; return r; } else return Flx_eval_pre_i(x, y, p, pi); } ulong Flx_eval(GEN x, ulong y, ulong p) { return Flx_eval_pre(x, y, p, get_Fl_red(p)); } ulong Flv_prod_pre(GEN x, ulong p, ulong pi) { pari_sp ltop = avma; GEN v; long i,k,lx = lg(x); ulong r; if (lx == 1) return 1UL; if (lx == 2) return uel(x,1); v = cgetg(1+(lx << 1), t_VECSMALL); k = 1; for (i=1; i 2) { lx = k; k = 1; for (i=1; i 1; --i) { ulong t = Fl_mul_pre(u, c[i - 1], p, pi); u = Fl_mul_pre(u, w[i], p, pi); v[i] = t; } v[1] = u; avma = av; } void Flv_inv_pre_inplace(GEN v, ulong p, ulong pi) { Flv_inv_pre_indir(v, v, p, pi); } GEN Flv_inv_pre(GEN w, ulong p, ulong pi) { GEN v = cgetg(lg(w), t_VECSMALL); Flv_inv_pre_indir(w, v, p, pi); return v; } INLINE void Flv_inv_indir(GEN w, GEN v, ulong p) { pari_sp av = avma; GEN c; register ulong u; register long n = lg(w), i; if (n == 1) return; c = cgetg(n, t_VECSMALL); c[1] = w[1]; for (i = 2; i < n; ++i) c[i] = Fl_mul(w[i], c[i - 1], p); i = n - 1; u = Fl_inv(c[i], p); for ( ; i > 1; --i) { ulong t = Fl_mul(u, c[i - 1], p); u = Fl_mul(u, w[i], p); v[i] = t; } v[1] = u; avma = av; } void Flv_inv_inplace(GEN v, ulong p) { if (SMALL_ULONG(p)) Flv_inv_indir(v, v, p); else Flv_inv_pre_indir(v, v, p, get_Fl_red(p)); } GEN Flv_inv(GEN w, ulong p) { GEN v = cgetg(lg(w), t_VECSMALL); if (SMALL_ULONG(p)) Flv_inv_indir(w, v, p); else Flv_inv_pre_indir(w, v, p, get_Fl_red(p)); return v; } GEN Flx_div_by_X_x(GEN a, ulong x, ulong p, ulong *rem) { long l = lg(a), i; GEN a0, z0; GEN z = cgetg(l-1,t_VECSMALL); z[1] = a[1]; a0 = a + l-1; z0 = z + l-2; *z0 = *a0--; if (SMALL_ULONG(p)) { for (i=l-3; i>1; i--) /* z[i] = (a[i+1] + x*z[i+1]) % p */ { ulong t = (*a0-- + x * *z0--) % p; *z0 = (long)t; } if (rem) *rem = (*a0 + x * *z0) % p; } else { for (i=l-3; i>1; i--) { ulong t = Fl_add((ulong)*a0--, Fl_mul(x, *z0--, p), p); *z0 = (long)t; } if (rem) *rem = Fl_add((ulong)*a0, Fl_mul(x, *z0, p), p); } return z; } /* xa, ya = t_VECSMALL */ static GEN Flv_producttree(GEN xa, GEN s, ulong p, long vs) { long n = lg(xa)-1; long m = n==1 ? 1: expu(n-1)+1; long i, j, k, ls = lg(s); GEN T = cgetg(m+1, t_VEC); GEN t = cgetg(ls, t_VEC); for (j=1, k=1; j>1)+1, t_VEC); for (j=1, k=1; k=1; i--) { GEN u = gel(T, i); GEN v = gel(Tp, i+1); long n = lg(u)-1; t = cgetg(n+1, t_VEC); for (j=1, k=1; kT, s->p); } static GEN _Flx_sub(void *E, GEN x, GEN y) { struct _Flxq *s = (struct _Flxq *)E; return Flx_sub(x,y,s->p); } static GEN _Flxq_sqr(void *data, GEN x) { struct _Flxq *D = (struct _Flxq*)data; return Flxq_sqr(x, D->T, D->p); } static GEN _Flxq_mul(void *data, GEN x, GEN y) { struct _Flxq *D = (struct _Flxq*)data; return Flxq_mul(x,y, D->T, D->p); } static GEN _Flxq_one(void *data) { struct _Flxq *D = (struct _Flxq*)data; return pol1_Flx(get_Flx_var(D->T)); } static GEN _Flxq_zero(void *data) { struct _Flxq *D = (struct _Flxq*)data; return pol0_Flx(get_Flx_var(D->T)); } static GEN _Flxq_cmul(void *data, GEN P, long a, GEN x) { struct _Flxq *D = (struct _Flxq*)data; return Flx_Fl_mul(x, P[a+2], D->p); } /* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */ GEN Flxq_powu(GEN x, ulong n, GEN T, ulong p) { pari_sp av = avma; struct _Flxq D; GEN y; switch(n) { case 0: return pol1_Flx(T[1]); case 1: return Flx_copy(x); case 2: return Flxq_sqr(x, T, p); } D.T = Flx_get_red(T, p); D.p = p; y = gen_powu_i(x, n, (void*)&D, &_Flxq_sqr, &_Flxq_mul); return gerepileuptoleaf(av, y); } /* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */ GEN Flxq_pow(GEN x, GEN n, GEN T, ulong p) { pari_sp av = avma; struct _Flxq D; GEN y; long s = signe(n); if (!s) return pol1_Flx(get_Flx_var(T)); if (s < 0) x = Flxq_inv(x,T,p); if (is_pm1(n)) return s < 0 ? x : Flx_copy(x); D.T = Flx_get_red(T, p); D.p = p; y = gen_pow_i(x, n, (void*)&D, &_Flxq_sqr, &_Flxq_mul); return gerepileuptoleaf(av, y); } GEN Flxq_pow_init(GEN x, GEN n, long k, GEN T, ulong p) { struct _Flxq D; D.T = Flx_get_red(T, p); D.p = p; return gen_pow_init(x, n, k, (void*)&D, &_Flxq_sqr, &_Flxq_mul); } GEN Flxq_pow_table(GEN R, GEN n, GEN T, ulong p) { struct _Flxq D; D.T = Flx_get_red(T, p); D.p = p; return gen_pow_table(R, n, (void*)&D, &_Flxq_one, &_Flxq_mul); } /* Inverse of x in Z/lZ[X]/(T) or NULL if inverse doesn't exist * not stack clean. */ GEN Flxq_invsafe(GEN x, GEN T, ulong p) { GEN V, z = Flx_extgcd(get_Flx_mod(T), x, p, NULL, &V); ulong iz; if (degpol(z)) return NULL; iz = Fl_inv (uel(z,2), p); return Flx_Fl_mul(V, iz, p); } GEN Flxq_inv(GEN x,GEN T,ulong p) { pari_sp av=avma; GEN U = Flxq_invsafe(x, T, p); if (!U) pari_err_INV("Flxq_inv",Flx_to_ZX(x)); return gerepileuptoleaf(av, U); } GEN Flxq_div(GEN x,GEN y,GEN T,ulong p) { pari_sp av = avma; return gerepileuptoleaf(av, Flxq_mul(x,Flxq_inv(y,T,p),T,p)); } GEN Flxq_powers(GEN x, long l, GEN T, ulong p) { struct _Flxq D; int use_sqr = 2*degpol(x) >= get_Flx_degree(T); D.T = Flx_get_red(T, p); D.p = p; return gen_powers(x, l, use_sqr, (void*)&D, &_Flxq_sqr, &_Flxq_mul, &_Flxq_one); } GEN Flxq_matrix_pow(GEN y, long n, long m, GEN P, ulong l) { return FlxV_to_Flm(Flxq_powers(y,m-1,P,l),n); } GEN Flx_Frobenius(GEN T, ulong p) { return Flxq_powu(polx_Flx(get_Flx_var(T)), p, T, p); } GEN Flx_matFrobenius(GEN T, ulong p) { long n = get_Flx_degree(T); return Flxq_matrix_pow(Flx_Frobenius(T, p), n, n, T, p); } static struct bb_algebra Flxq_algebra = { _Flxq_red, _Flx_add, _Flx_sub, _Flxq_mul, _Flxq_sqr, _Flxq_one, _Flxq_zero}; GEN Flx_FlxqV_eval(GEN Q, GEN x, GEN T, ulong p) { struct _Flxq D; D.T = Flx_get_red(T, p); D.p=p; return gen_bkeval_powers(Q,degpol(Q),x,(void*)&D,&Flxq_algebra,_Flxq_cmul); } GEN Flx_Flxq_eval(GEN Q, GEN x, GEN T, ulong p) { int use_sqr = 2*degpol(x) >= get_Flx_degree(T); struct _Flxq D; D.T = Flx_get_red(T, p); D.p=p; return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)&D,&Flxq_algebra,_Flxq_cmul); } static GEN Flxq_autpow_sqr(void *E, GEN x) { struct _Flxq *D = (struct _Flxq*)E; return Flx_Flxq_eval(x, x, D->T, D->p); } static GEN Flxq_autpow_mul(void *E, GEN x, GEN y) { struct _Flxq *D = (struct _Flxq*)E; return Flx_Flxq_eval(x, y, D->T, D->p); } GEN Flxq_autpow(GEN x, ulong n, GEN T, ulong p) { struct _Flxq D; if (n==0) return Flx_rem(polx_Flx(x[1]), T, p); if (n==1) return Flx_rem(x, T, p); D.T = Flx_get_red(T, p); D.p = p; return gen_powu(x,n,(void*)&D,Flxq_autpow_sqr,Flxq_autpow_mul); } static GEN Flxq_autsum_mul(void *E, GEN x, GEN y) { struct _Flxq *D = (struct _Flxq*)E; GEN T = D->T; ulong p = D->p; GEN phi1 = gel(x,1), a1 = gel(x,2); GEN phi2 = gel(y,1), a2 = gel(y,2); ulong d = brent_kung_optpow(maxss(degpol(phi1),degpol(a1)),2,1); GEN V2 = Flxq_powers(phi2, d, T, p); GEN phi3 = Flx_FlxqV_eval(phi1, V2, T, p); GEN aphi = Flx_FlxqV_eval(a1, V2, T, p); GEN a3 = Flxq_mul(aphi, a2, T, p); return mkvec2(phi3, a3); } static GEN Flxq_autsum_sqr(void *E, GEN x) { return Flxq_autsum_mul(E, x, x); } GEN Flxq_autsum(GEN x, ulong n, GEN T, ulong p) { struct _Flxq D; D.T = Flx_get_red(T, p); D.p = p; return gen_powu(x,n,(void*)&D,Flxq_autsum_sqr,Flxq_autsum_mul); } static GEN Flxq_auttrace_mul(void *E, GEN x, GEN y) { struct _Flxq *D = (struct _Flxq*)E; GEN T = D->T; ulong p = D->p; GEN phi1 = gel(x,1), a1 = gel(x,2); GEN phi2 = gel(y,1), a2 = gel(y,2); ulong d = brent_kung_optpow(maxss(degpol(phi1),degpol(a1)),2,1); GEN V1 = Flxq_powers(phi1, d, T, p); GEN phi3 = Flx_FlxqV_eval(phi2, V1, T, p); GEN aphi = Flx_FlxqV_eval(a2, V1, T, p); GEN a3 = Flx_add(a1, aphi, p); return mkvec2(phi3, a3); } static GEN Flxq_auttrace_sqr(void *E, GEN x) { return Flxq_auttrace_mul(E, x, x); } GEN Flxq_auttrace(GEN x, ulong n, GEN T, ulong p) { struct _Flxq D; D.T = Flx_get_red(T, p); D.p = p; return gen_powu(x,n,(void*)&D,Flxq_auttrace_sqr,Flxq_auttrace_mul); } static long bounded_order(ulong p, GEN b, long k) { long i; GEN a=modii(utoi(p),b); for(i=1;i 1) z = gel(Flxq_autsum(mkvec2(autk, z), m, T, p), 2); if (!is_pm1(u)) z = Flxq_pow(z, u, T, p); if (signe(v)) z = Flxq_mul(z, Flxq_pow(x, v, T, p), T, p); } return gerepileupto(av,signe(n)>0 ? z : Flxq_inv(z,T,p)); } static GEN _Flxq_pow(void *data, GEN x, GEN n) { struct _Flxq *D = (struct _Flxq*)data; return Flxq_pow_Frobenius(x, n, D->aut, D->T, D->p); } static GEN _Flxq_rand(void *data) { pari_sp av=avma; struct _Flxq *D = (struct _Flxq*)data; GEN z; do { avma = av; z = random_Flx(get_Flx_degree(D->T),get_Flx_var(D->T),D->p); } while (lgpol(z)==0); return z; } /* discrete log in FpXQ for a in Fp^*, g in FpXQ^* of order ord */ static GEN Fl_Flxq_log(ulong a, GEN g, GEN o, GEN T, ulong p) { pari_sp av = avma; GEN q,n_q,ord,ordp, op; if (a == 1UL) return gen_0; /* p > 2 */ ordp = utoi(p - 1); ord = get_arith_Z(o); if (!ord) ord = T? subiu(powuu(p, get_FpX_degree(T)), 1): ordp; if (a == p - 1) /* -1 */ return gerepileuptoint(av, shifti(ord,-1)); ordp = gcdii(ordp, ord); op = typ(o)==t_MAT ? famat_Z_gcd(o, ordp) : ordp; q = NULL; if (T) { /* we want < g > = Fp^* */ if (!equalii(ord,ordp)) { q = diviiexact(ord,ordp); g = Flxq_pow(g,q,T,p); } } n_q = Fp_log(utoi(a), utoi(uel(g,2)), op, utoi(p)); if (lg(n_q)==1) return gerepileuptoleaf(av, n_q); if (q) n_q = mulii(q, n_q); return gerepileuptoint(av, n_q); } static GEN Flxq_easylog(void* E, GEN a, GEN g, GEN ord) { struct _Flxq *f = (struct _Flxq *)E; GEN T = f->T; ulong p = f->p; long d = get_Flx_degree(T); if (Flx_equal1(a)) return gen_0; if (Flx_equal(a,g)) return gen_1; if (!degpol(a)) return Fl_Flxq_log(uel(a,2), g, ord, T, p); if (typ(ord)!=t_INT || d <= 4 || d == 6 || abscmpiu(ord,1UL<<27)<0) return NULL; return Flxq_log_index(a, g, ord, T, p); } int Flx_equal(GEN V, GEN W) { long l = lg(V); if (lg(W) != l) return 0; while (--l > 1) /* do not compare variables, V[1] */ if (V[l] != W[l]) return 0; return 1; } static const struct bb_group Flxq_star={_Flxq_mul,_Flxq_pow,_Flxq_rand,hash_GEN,Flx_equal,Flx_equal1,Flxq_easylog}; const struct bb_group * get_Flxq_star(void **E, GEN T, ulong p) { struct _Flxq *e = (struct _Flxq *) stack_malloc(sizeof(struct _Flxq)); e->T = T; e->p = p; e->aut = Flx_Frobenius(T, p); *E = (void*)e; return &Flxq_star; } GEN Flxq_order(GEN a, GEN ord, GEN T, ulong p) { void *E; const struct bb_group *S = get_Flxq_star(&E,T,p); return gen_order(a,ord,E,S); } GEN Flxq_log(GEN a, GEN g, GEN ord, GEN T, ulong p) { void *E; pari_sp av = avma; const struct bb_group *S = get_Flxq_star(&E,T,p); GEN v = get_arith_ZZM(ord), F = gmael(v,2,1); if (Flxq_log_use_index(gel(F,lg(F)-1), T, p)) v = mkvec2(gel(v, 1), ZM_famat_limit(gel(v, 2), int2n(27))); return gerepileuptoleaf(av, gen_PH_log(a, g, v, E, S)); } GEN Flxq_sqrtn(GEN a, GEN n, GEN T, ulong p, GEN *zeta) { if (!lgpol(a)) { if (signe(n) < 0) pari_err_INV("Flxq_sqrtn",a); if (zeta) *zeta=pol1_Flx(get_Flx_var(T)); return pol0_Flx(get_Flx_var(T)); } else { void *E; pari_sp av = avma; const struct bb_group *S = get_Flxq_star(&E,T,p); GEN o = subiu(powuu(p,get_Flx_degree(T)), 1); GEN s = gen_Shanks_sqrtn(a,n,o,zeta,E,S); if (s) gerepileall(av, zeta?2:1, &s, zeta); return s; } } GEN Flxq_sqrt(GEN a, GEN T, ulong p) { return Flxq_sqrtn(a, gen_2, T, p, NULL); } /* assume T irreducible mod p */ int Flxq_issquare(GEN x, GEN T, ulong p) { if (lgpol(x) == 0 || p == 2) return 1; return krouu(Flxq_norm(x,T,p), p) == 1; } /* assume T irreducible mod p */ int Flxq_is2npower(GEN x, long n, GEN T, ulong p) { pari_sp av; GEN m; int z; if (n==1) return Flxq_issquare(x, T, p); if (lgpol(x) == 0 || p == 2) return 1; av = avma; m = shifti(subiu(powuu(p, get_Flx_degree(T)), 1), -n); z = Flx_equal1(Flxq_pow(x, m, T, p)); avma = av; return z; } GEN Flxq_lroot_fast(GEN a, GEN sqx, GEN T, long p) { pari_sp av=avma; GEN A = Flx_splitting(a,p); return gerepileuptoleaf(av, FlxqV_dotproduct(A,sqx,T,p)); } GEN Flxq_lroot(GEN a, GEN T, long p) { pari_sp av=avma; long n = get_Flx_degree(T), d = degpol(a); GEN sqx, V; if (n==1) return leafcopy(a); if (n==2) return Flxq_powu(a, p, T, p); sqx = Flxq_autpow(Flx_Frobenius(T, p), n-1, T, p); if (d==1 && a[2]==0 && a[3]==1) return gerepileuptoleaf(av, sqx); if (d>=p) { V = Flxq_powers(sqx,p-1,T,p); return gerepileuptoleaf(av, Flxq_lroot_fast(a,V,T,p)); } else return gerepileuptoleaf(av, Flx_Flxq_eval(a,sqx,T,p)); } ulong Flxq_norm(GEN x, GEN TB, ulong p) { GEN T = get_Flx_mod(TB); ulong y = Flx_resultant(T, x, p); ulong L = Flx_lead(T); if ( L==1 || lgpol(x)==0) return y; return Fl_div(y, Fl_powu(L, (ulong)degpol(x), p), p); } ulong Flxq_trace(GEN x, GEN TB, ulong p) { pari_sp av = avma; ulong t; GEN T = get_Flx_mod(TB); long n = degpol(T)-1; GEN z = Flxq_mul(x, Flx_deriv(T, p), TB, p); t = degpol(z)v(tau*z) that is, v*(M_tau) */ static GEN Flxq_transmul_init(GEN tau, GEN T, ulong p) { GEN bht; GEN h, Tp = get_Flx_red(T, &h); long n = degpol(Tp), vT = Tp[1]; GEN ft = Flx_recipspec(Tp+2, n+1, n+1); GEN bt = Flx_recipspec(tau+2, lgpol(tau), n); ft[1] = vT; bt[1] = vT; if (h) bht = Flxn_mul(bt, h, n-1, p); else { GEN bh = Flx_div(Flx_shift(tau, n-1), T, p); bht = Flx_recipspec(bh+2, lgpol(bh), n-1); bht[1] = vT; } return mkvec3(bt, bht, ft); } static GEN Flxq_transmul(GEN tau, GEN a, long n, ulong p) { pari_sp ltop = avma; GEN t1, t2, t3, vec; GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3); if (lgpol(a)==0) return pol0_Flx(a[1]); t2 = Flx_shift(Flx_mul(bt, a, p),1-n); if (lgpol(bht)==0) return gerepileuptoleaf(ltop, t2); t1 = Flx_shift(Flx_mul(ft, a, p),-n); t3 = Flxn_mul(t1, bht, n-1, p); vec = Flx_sub(t2, Flx_shift(t3, 1), p); return gerepileuptoleaf(ltop, vec); } GEN Flxq_minpoly(GEN x, GEN T, ulong p) { pari_sp ltop = avma; long vT = get_Flx_var(T), n = get_Flx_degree(T); GEN v_x; GEN g = pol1_Flx(vT), tau = pol1_Flx(vT); T = Flx_get_red(T, p); v_x = Flxq_powers(x, usqrt(2*n), T, p); while (lgpol(tau) != 0) { long i, j, m, k1; GEN M, v, tr; GEN g_prime, c; if (degpol(g) == n) { tau = pol1_Flx(vT); g = pol1_Flx(vT); } v = random_Flx(n, vT, p); tr = Flxq_transmul_init(tau, T, p); v = Flxq_transmul(tr, v, n, p); m = 2*(n-degpol(g)); k1 = usqrt(m); tr = Flxq_transmul_init(gel(v_x,k1+1), T, p); c = cgetg(m+2,t_VECSMALL); c[1] = T[1]; for (i=0; i , i = 0..m-1 */ M = Flx_halfgcd(monomial_Flx(1, m, vT), c, p); g_prime = gmael(M, 2, 2); if (degpol(g_prime) < 1) continue; g = Flx_mul(g, g_prime, p); tau = Flxq_mul(tau, Flx_FlxqV_eval(g_prime, v_x, T, p), T, p); } g = Flx_normalize(g,p); return gerepileuptoleaf(ltop,g); } /* return (x % X^n). Shallow */ static GEN Flxn_red_shallow(GEN a, long n) { long i, L, l = lg(a); GEN b; if (l == 2 || !n) return zero_Flx(a[1]); L = n+2; if (L > l) L = l; b = cgetg(L, t_VECSMALL); b[1] = a[1]; for (i=2; i1;) { GEN u, fr; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; fr = Flxn_red_shallow(f, n); u = Flx_shift(Flxn_mul(W, fr, n, p), -n2); W = Flx_sub(W, Flx_shift(Flxn_mul(u, W, n-n2, p), n2), p); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgXn_inv, e = %ld", n); W = gerepileupto(av2, W); } } return gerepileupto(av, W); } GEN Flxq_conjvec(GEN x, GEN T, ulong p) { long i, l = 1+get_Flx_degree(T); GEN z = cgetg(l,t_COL); T = Flx_get_red(T,p); gel(z,1) = Flx_copy(x); for (i=2; i 3) { ulong t; (void)u_lvalrem(p_1, 2, &t); L = gel(factoru(t),1); for (i=lg(L)-1; i; i--) L[i] = p_1 / L[i]; } o = factor_pn_1(utoipos(p),f); L2 = leafcopy( gel(o, 1) ); for (i = j = 1; i < lg(L2); i++) { if (umodui(p_1, gel(L2,i)) == 0) continue; gel(L2,j++) = diviiexact(q, gel(L2,i)); } setlg(L2, j); F = Flx_Frobenius(T, p); for (av = avma;; avma = av) { GEN tt; g = random_Flx(f, vT, p); if (degpol(g) < 1) continue; if (p == 2) tt = g; else { ulong t = Flxq_norm(g, T, p); if (t == 1 || !is_gener_Fl(t, p, p_1, L)) continue; tt = Flxq_powu(g, p_1>>1, T, p); } for (i = 1; i < j; i++) { GEN a = Flxq_pow_Frobenius(tt, gel(L2,i), F, T, p); if (!degpol(a) && uel(a,2) == p_1) break; } if (i == j) break; } if (!po) { avma = (pari_sp)g; g = gerepileuptoleaf(av0, g); } else { *po = mkvec2(subiu(powuu(p,f), 1), o); gerepileall(av0, 2, &g, po); } return g; } static GEN _Flxq_neg(void *E, GEN x) { struct _Flxq *s = (struct _Flxq *)E; return Flx_neg(x,s->p); } static GEN _Flxq_rmul(void *E, GEN x, GEN y) { struct _Flxq *s = (struct _Flxq *)E; return Flx_mul(x,y,s->p); } static GEN _Flxq_inv(void *E, GEN x) { struct _Flxq *s = (struct _Flxq *)E; return Flxq_inv(x,s->T,s->p); } static int _Flxq_equal0(GEN x) { return lgpol(x)==0; } static GEN _Flxq_s(void *E, long x) { struct _Flxq *s = (struct _Flxq *)E; ulong u = x<0 ? s->p+x: (ulong)x; return Fl_to_Flx(u, get_Flx_var(s->T)); } static const struct bb_field Flxq_field={_Flxq_red,_Flx_add,_Flxq_rmul,_Flxq_neg, _Flxq_inv,_Flxq_equal0,_Flxq_s}; const struct bb_field *get_Flxq_field(void **E, GEN T, ulong p) { GEN z = new_chunk(sizeof(struct _Flxq)); struct _Flxq *e = (struct _Flxq *) z; e->T = Flx_get_red(T, p); e->p = p; *E = (void*)e; return &Flxq_field; } /***********************************************************************/ /** **/ /** Fl2 **/ /** **/ /***********************************************************************/ /* Fl2 objects are Flv of length 2 [a,b] representing a+bsqrt(D) for a non-square D. */ INLINE GEN mkF2(ulong a, ulong b) { return mkvecsmall2(a,b); } GEN Fl2_mul_pre(GEN x, GEN y, ulong D, ulong p, ulong pi) { ulong xaya, xbyb, Db2, mid; ulong z1, z2; ulong x1 = x[1], x2 = x[2], y1 = y[1], y2 = y[2]; xaya = Fl_mul_pre(x1,y1,p,pi); if (x2==0 && y2==0) return mkF2(xaya,0); if (x2==0) return mkF2(xaya,Fl_mul_pre(x1,y2,p,pi)); if (y2==0) return mkF2(xaya,Fl_mul_pre(x2,y1,p,pi)); xbyb = Fl_mul_pre(x2,y2,p,pi); mid = Fl_mul_pre(Fl_add(x1,x2,p), Fl_add(y1,y2,p),p,pi); Db2 = Fl_mul_pre(D, xbyb, p,pi); z1 = Fl_add(xaya,Db2,p); z2 = Fl_sub(mid,Fl_add(xaya,xbyb,p),p); return mkF2(z1,z2); } GEN Fl2_sqr_pre(GEN x, ulong D, ulong p, ulong pi) { ulong a = x[1], b = x[2]; ulong a2, Db2, ab; a2 = Fl_sqr_pre(a,p,pi); if (b==0) return mkF2(a2,0); Db2= Fl_mul_pre(D, Fl_sqr_pre(b,p,pi), p,pi); ab = Fl_mul_pre(a,b,p,pi); return mkF2(Fl_add(a2,Db2,p), Fl_double(ab,p)); } ulong Fl2_norm_pre(GEN x, ulong D, ulong p, ulong pi) { ulong a2 = Fl_sqr_pre(x[1],p,pi); return x[2]? Fl_sub(a2, Fl_mul_pre(D, Fl_sqr_pre(x[2], p,pi), p,pi), p): a2; } GEN Fl2_inv_pre(GEN x, ulong D, ulong p, ulong pi) { ulong n, ni; if (x[2] == 0) return mkF2(Fl_inv(x[1],p),0); n = Fl_sub(Fl_sqr_pre(x[1], p,pi), Fl_mul_pre(D, Fl_sqr_pre(x[2], p,pi), p,pi), p); ni = Fl_inv(n,p); return mkF2(Fl_mul_pre(x[1], ni, p,pi), Fl_neg(Fl_mul_pre(x[2], ni, p,pi), p)); } int Fl2_equal1(GEN x) { return x[1]==1 && x[2]==0; } struct _Fl2 { ulong p, pi, D; }; static GEN _Fl2_sqr(void *data, GEN x) { struct _Fl2 *D = (struct _Fl2*)data; return Fl2_sqr_pre(x, D->D, D->p, D->pi); } static GEN _Fl2_mul(void *data, GEN x, GEN y) { struct _Fl2 *D = (struct _Fl2*)data; return Fl2_mul_pre(x,y, D->D, D->p, D->pi); } /* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */ GEN Fl2_pow_pre(GEN x, GEN n, ulong D, ulong p, ulong pi) { pari_sp av = avma; struct _Fl2 d; GEN y; long s = signe(n); if (!s) return mkF2(1,0); if (s < 0) x = Fl2_inv_pre(x,D,p,pi); if (is_pm1(n)) return s < 0 ? x : zv_copy(x); d.p = p; d.pi = pi; d.D=D; y = gen_pow_i(x, n, (void*)&d, &_Fl2_sqr, &_Fl2_mul); return gerepileuptoleaf(av, y); } static GEN _Fl2_pow(void *data, GEN x, GEN n) { struct _Fl2 *D = (struct _Fl2*)data; return Fl2_pow_pre(x, n, D->D, D->p, D->pi); } static GEN _Fl2_rand(void *data) { struct _Fl2 *D = (struct _Fl2*)data; ulong a = random_Fl(D->p), b=random_Fl(D->p-1)+1; return mkF2(a,b); } static const struct bb_group Fl2_star={_Fl2_mul, _Fl2_pow, _Fl2_rand, hash_GEN, zv_equal, Fl2_equal1, NULL}; GEN Fl2_sqrtn_pre(GEN a, GEN n, ulong D, ulong p, ulong pi, GEN *zeta) { struct _Fl2 E; GEN o; if (a[1]==0 && a[2]==0) { if (signe(n) < 0) pari_err_INV("Flxq_sqrtn",a); if (zeta) *zeta=mkF2(1,0); return zv_copy(a); } E.p=p; E.pi = pi; E.D = D; o = subiu(powuu(p,2), 1); return gen_Shanks_sqrtn(a,n,o,zeta,(void*)&E,&Fl2_star); } GEN Flx_Fl2_eval_pre(GEN x, GEN y, ulong D, ulong p, ulong pi) { GEN p1; long i = lg(x)-1; if (i <= 2) return mkF2(i == 2? x[2]: 0, 0); p1 = mkF2(x[i], 0); for (i--; i>=2; i--) { p1 = Fl2_mul_pre(p1, y, D, p, pi); uel(p1,1) = Fl_add(uel(p1,1), uel(x,i), p); } return p1; } /***********************************************************************/ /** **/ /** FlxV **/ /** **/ /***********************************************************************/ /* FlxV are t_VEC with Flx coefficients. */ GEN FlxV_Flc_mul(GEN V, GEN W, ulong p) { pari_sp ltop=avma; long i; GEN z = Flx_Fl_mul(gel(V,1),W[1],p); for(i=2;i1; i--) if (lgpol(gel(x,i))) break; stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1)); setlg(x, i+1); setsigne(x, i!=1); return x; } GEN pol1_FlxX(long v, long sv) { GEN z = cgetg(3, t_POL); z[1] = evalsigne(1) | evalvarn(v); gel(z,2) = pol1_Flx(sv); return z; } GEN polx_FlxX(long v, long sv) { GEN z = cgetg(4, t_POL); z[1] = evalsigne(1) | evalvarn(v); gel(z,2) = pol0_Flx(sv); gel(z,3) = pol1_Flx(sv); return z; } long FlxY_degreex(GEN b) { long deg = -1, i; if (!signe(b)) return -1; for (i = 2; i < lg(b); ++i) deg = maxss(deg, degpol(gel(b, i))); return deg; } /*Lift coefficient of B to constant Flx, to give a FlxY*/ GEN Fly_to_FlxY(GEN B, long sv) { long lb=lg(B); long i; GEN b=cgetg(lb,t_POL); b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS); for (i=2; i N+1) l = N+1; /* truncate higher degree terms */ z = cgetg(N+1,t_COL); for (i=1; i P(Y,X), n-1 is the degree in Y */ GEN FlxX_swap(GEN x, long n, long ws) { long j, lx = lg(x), ly = n+3; GEN y = cgetg(ly, t_POL); y[1] = x[1]; for (j=2; j= n) pari_err_BUG("zxX_to_Kronecker, P is not reduced mod Q"); for (j=2; j < l; j++) y[k++] = c[j]; if (i == lp-1) break; for ( ; j < N; j++) y[k++] = 0; } y -= 2; y[1] = P[1]; setlg(y, k+2); return y; } GEN zxX_to_Kronecker(GEN P, GEN Q) { GEN z = zxX_to_Kronecker_spec(P+2, lg(P)-2, degpol(Q)); z[1] = P[1]; return z; } GEN FlxX_add(GEN x, GEN y, ulong p) { long i,lz; GEN z; long lx=lg(x); long ly=lg(y); if (ly>lx) swapspec(x,y, lx,ly); lz = lx; z = cgetg(lz, t_POL); z[1]=x[1]; for (i=2; i= ly) { z[1] = x[1]; for (i=2; i1) pari_warn(warnmem,"FlxY_Flx_translate, i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); } } return gerepilecopy(av, Q); } GEN FlxY_evalx_powers_pre(GEN pol, GEN ypowers, ulong p, ulong pi) { long i, len = lg(pol); GEN res = cgetg(len, t_VECSMALL); res[1] = pol[1] & VARNBITS; for (i = 2; i < len; ++i) res[i] = Flx_eval_powers_pre(gel(pol, i), ypowers, p, pi); return Flx_renormalize(res, len); } ulong FlxY_eval_powers_pre(GEN pol, GEN ypowers, GEN xpowers, ulong p, ulong pi) { pari_sp av = avma; GEN t = FlxY_evalx_powers_pre(pol, ypowers, p, pi); ulong out = Flx_eval_powers_pre(t, xpowers, p, pi); avma = av; return out; } GEN FlxY_FlxqV_evalx(GEN P, GEN x, GEN T, ulong p) { long i, lP = lg(P); GEN res = cgetg(lP,t_POL); res[1] = P[1]; for(i=2; i=dy; i--) { av=avma; p1=gel(x,i); for (j=i-dy+1; j<=i && j<=dz; j++) p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p); if (lead) p1 = Flx_mul(p1, lead,p); tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,Flx_rem(p1,T,p)); } if (!pr) { if (lead) gunclone(lead); return z-2; } rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3); for (sx=0; ; i--) { p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p); tetpil=avma; p1 = Flx_rem(p1, T, p); if (lgpol(p1)) { sx = 1; break; } if (!i) break; avma=av; } if (pr == ONLY_DIVIDES) { if (lead) gunclone(lead); if (sx) { avma=av0; return NULL; } avma = (pari_sp)rem; return z-2; } lr=i+3; rem -= lr; rem[0] = evaltyp(t_POL) | evallg(lr); rem[1] = z[-1]; p1 = gerepile((pari_sp)rem,tetpil,p1); rem += 2; gel(rem,i) = p1; for (i--; i>=0; i--) { av=avma; p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p), p); tetpil=avma; gel(rem,i) = gerepile(av,tetpil, Flx_rem(p1, T, p)); } rem -= 2; if (lead) gunclone(lead); if (!sx) (void)FlxX_renormalize(rem, lr); if (pr == ONLY_REM) return gerepileupto(av0,rem); *pr = rem; return z-2; } static GEN FlxqX_invBarrett_basecase(GEN T, GEN Q, ulong p) { long i, l=lg(T)-1, lr = l-1, k; long sv=Q[1]; GEN r=cgetg(lr,t_POL); r[1]=T[1]; gel(r,2) = pol1_Flx(sv); for (i=3;i=0; i--) if (lgpol(gel(x,i))) break; return i+1; } static GEN FlxqX_invBarrett_Newton(GEN S, GEN T, ulong p) { pari_sp av = avma; long nold, lx, lz, lq, l = degpol(S), i, lQ; GEN q, y, z, x = cgetg(l+2, t_POL) + 2; long dT = get_Flx_degree(T); ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */ for (i=0;i1 && degpol(gel(q,1)) >= dT) gel(q,1) = Flx_rem(gel(q,1), T, p); if (lQ>1 && lgpol(gel(q,1))) { GEN u = gel(q, 1); if (!Flx_equal1(gel(x,0))) u = Flxq_mul(u, Flxq_sqr(gel(x,0), T,p), T,p); gel(x,1) = Flx_neg(u, p); lx = 2; } else lx = 1; nold = 1; for (; mask > 1; ) { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */ long i, lnew, nnew = nold << 1; if (mask & 1) nnew--; mask >>= 1; lnew = nnew + 1; lq = FlxX_lgrenormalizespec(q, minss(lQ,lnew)); z = FlxqX_mulspec(x, q, T, p, lx, lq); /* FIXME: high product */ lz = lgpol(z); if (lz > lnew) lz = lnew; z += 2; /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */ for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break; nold = nnew; if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */ /* z + i represents (x*q - 1) / t^i */ lz = FlxX_lgrenormalizespec (z+i, lz-i); z = FlxqX_mulspec(x, z+i, T,p, lx, lz); /* FIXME: low product */ lz = lgpol(z); z += 2; if (lz > lnew-i) lz = FlxX_lgrenormalizespec(z, lnew-i); lx = lz+ i; y = x + i; /* x -= z * t^i, in place */ for (i = 0; i < lz; i++) gel(y,i) = Flx_neg(gel(z,i), p); } x -= 2; setlg(x, lx + 2); x[1] = S[1]; return gerepilecopy(av, x); } /* x/polrecip(P)+O(x^n) */ GEN FlxqX_invBarrett(GEN T, GEN Q, ulong p) { pari_sp ltop=avma; long l=lg(T), v = varn(T); GEN r; GEN c = gel(T,l-1); if (l<5) return pol_0(v); if (l<=FlxqX_INVBARRETT_LIMIT) { if (!Flx_equal1(c)) { GEN ci = Flxq_inv(c,Q,p); T = FlxqX_Flxq_mul(T, ci, Q, p); r = FlxqX_invBarrett_basecase(T,Q,p); r = FlxqX_Flxq_mul(r,ci,Q,p); } else r = FlxqX_invBarrett_basecase(T,Q,p); } else r = FlxqX_invBarrett_Newton(T,Q,p); return gerepileupto(ltop, r); } GEN FlxqX_get_red(GEN S, GEN T, ulong p) { if (typ(S)==t_POL && lg(S)>FlxqX_BARRETT_LIMIT) retmkvec2(FlxqX_invBarrett(S, T, p), S); return S; } /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1) * * and mg is the Barrett inverse of S. */ static GEN FlxqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, ulong p, GEN *pr) { GEN q, r; long lt = degpol(S); /*We discard the leading term*/ long ld, lm, lT, lmg; ld = l-lt; lm = minss(ld, lgpol(mg)); lT = FlxX_lgrenormalizespec(S+2,lt); lmg = FlxX_lgrenormalizespec(mg+2,lm); q = FlxX_recipspec(x+lt,ld,ld,0); /* q = rec(x) lq<=ld*/ q = FlxqX_mulspec(q+2,mg+2,T,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/ q = FlxX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/ if (!pr) return q; r = FlxqX_mulspec(q+2,S+2,T,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/ r = FlxX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */ if (pr == ONLY_REM) return r; *pr = r; return q; } static GEN FlxqX_divrem_Barrett_noGC(GEN x, GEN mg, GEN S, GEN T, ulong p, GEN *pr) { long l = lgpol(x), lt = degpol(S), lm = 2*lt-1; GEN q = NULL, r; long i; if (l <= lt) { if (pr == ONLY_REM) return RgX_copy(x); if (pr == ONLY_DIVIDES) return signe(x)? NULL: pol_0(varn(x)); if (pr) *pr = RgX_copy(x); return pol_0(varn(x)); } if (lt <= 1) return FlxqX_divrem_basecase(x,S,T,p,pr); if (pr != ONLY_REM && l>lm) { long vT = get_Flx_var(T); q = cgetg(l-lt+2, t_POL); for (i=0;ilm ? shallowcopy(x): x; while (l>lm) { GEN zr, zq = FlxqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,&zr); long lz = lgpol(zr); if (pr != ONLY_REM) { long lq = lgpol(zq); for(i=0; i lt) { GEN zq = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,&r); if (!q) q = zq; else { long lq = lgpol(zq); for(i=0; i lt) (void) FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,&r); else { setlg(r, l+2); r = RgX_copy(r); } r[1] = x[1]; return FlxX_renormalize(r, lg(r)); } if (pr) { r[1] = x[1]; r = FlxX_renormalize(r, lg(r)); } q[1] = x[1]; q = FlxX_renormalize(q, lg(q)); if (pr == ONLY_DIVIDES) return signe(r)? NULL: q; if (pr) *pr = r; return q; } GEN FlxqX_divrem(GEN x, GEN S, GEN T, ulong p, GEN *pr) { GEN B, y = get_FlxqX_red(S, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (pr==ONLY_REM) return FlxqX_rem(x, y, T, p); if (!B && d+3 < FlxqX_DIVREM_BARRETT_LIMIT) return FlxqX_divrem_basecase(x,y,T,p,pr); else { pari_sp av=avma; GEN mg = B? B: FlxqX_invBarrett(y, T, p); GEN q = FlxqX_divrem_Barrett_noGC(x,mg,y,T,p,pr); if (!q) {avma=av; return NULL;} if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q); gerepileall(av,2,&q,pr); return q; } } GEN FlxqX_rem(GEN x, GEN S, GEN T, ulong p) { GEN B, y = get_FlxqX_red(S, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (d < 0) return FlxqX_red(x, T, p); if (!B && d+3 < FlxqX_REM_BARRETT_LIMIT) return FlxqX_divrem_basecase(x,y, T, p, ONLY_REM); else { pari_sp av=avma; GEN mg = B? B: FlxqX_invBarrett(y, T, p); GEN r = FlxqX_divrem_Barrett_noGC(x, mg, y, T, p, ONLY_REM); return gerepileupto(av, r); } } static GEN FlxqX_halfgcd_basecase(GEN a, GEN b, GEN T, ulong p) { pari_sp av=avma; GEN u,u1,v,v1; long vx = varn(a); long n = lgpol(a)>>1; u1 = v = pol_0(vx); u = v1 = pol1_FlxX(vx, get_Flx_var(T)); while (lgpol(b)>n) { GEN r, q = FlxqX_divrem(a,b, T, p, &r); a = b; b = r; swap(u,u1); swap(v,v1); u1 = FlxX_sub(u1, FlxqX_mul(u, q, T, p), p); v1 = FlxX_sub(v1, FlxqX_mul(v, q ,T, p), p); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_halfgcd (d = %ld)",degpol(b)); gerepileall(av,6, &a,&b,&u1,&v1,&u,&v); } } return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1))); } static GEN FlxqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, ulong p) { return FlxX_add(FlxqX_mul(u, x, T, p),FlxqX_mul(v, y, T, p), p); } static GEN FlxqXM_FlxqX_mul2(GEN M, GEN x, GEN y, GEN T, ulong p) { GEN res = cgetg(3, t_COL); gel(res, 1) = FlxqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p); gel(res, 2) = FlxqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p); return res; } static GEN FlxqXM_mul2(GEN A, GEN B, GEN T, ulong p) { GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2); GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2); GEN M1 = FlxqX_mul(FlxX_add(A11,A22, p), FlxX_add(B11,B22, p), T, p); GEN M2 = FlxqX_mul(FlxX_add(A21,A22, p), B11, T, p); GEN M3 = FlxqX_mul(A11, FlxX_sub(B12,B22, p), T, p); GEN M4 = FlxqX_mul(A22, FlxX_sub(B21,B11, p), T, p); GEN M5 = FlxqX_mul(FlxX_add(A11,A12, p), B22, T, p); GEN M6 = FlxqX_mul(FlxX_sub(A21,A11, p), FlxX_add(B11,B12, p), T, p); GEN M7 = FlxqX_mul(FlxX_sub(A12,A22, p), FlxX_add(B21,B22, p), T, p); GEN T1 = FlxX_add(M1,M4, p), T2 = FlxX_sub(M7,M5, p); GEN T3 = FlxX_sub(M1,M2, p), T4 = FlxX_add(M3,M6, p); retmkmat2(mkcol2(FlxX_add(T1,T2, p), FlxX_add(M2,M4, p)), mkcol2(FlxX_add(M3,M5, p), FlxX_add(T3,T4, p))); } /* Return [0,1;1,-q]*M */ static GEN FlxqX_FlxqXM_qmul(GEN q, GEN M, GEN T, ulong p) { GEN u, v, res = cgetg(3, t_MAT); u = FlxX_sub(gcoeff(M,1,1), FlxqX_mul(gcoeff(M,2,1), q, T, p), p); gel(res,1) = mkcol2(gcoeff(M,2,1), u); v = FlxX_sub(gcoeff(M,1,2), FlxqX_mul(gcoeff(M,2,2), q, T, p), p); gel(res,2) = mkcol2(gcoeff(M,2,2), v); return res; } static GEN matid2_FlxXM(long v, long sv) { retmkmat2(mkcol2(pol1_FlxX(v, sv),pol_0(v)), mkcol2(pol_0(v),pol1_FlxX(v, sv))); } static GEN FlxqX_halfgcd_split(GEN x, GEN y, GEN T, ulong p) { pari_sp av=avma; GEN R, S, V; GEN y1, r, q; long l = lgpol(x), n = l>>1, k; if (lgpol(y)<=n) return matid2_FlxXM(varn(x),T[1]); R = FlxqX_halfgcd(RgX_shift_shallow(x,-n),RgX_shift_shallow(y,-n), T, p); V = FlxqXM_FlxqX_mul2(R,x,y, T, p); y1 = gel(V,2); if (lgpol(y1)<=n) return gerepilecopy(av, R); q = FlxqX_divrem(gel(V,1), y1, T, p, &r); k = 2*n-degpol(y1); S = FlxqX_halfgcd(RgX_shift_shallow(y1,-k), RgX_shift_shallow(r,-k), T, p); return gerepileupto(av, FlxqXM_mul2(S,FlxqX_FlxqXM_qmul(q,R, T, p), T, p)); } /* Return M in GL_2(Fp[X]) such that: if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b') */ static GEN FlxqX_halfgcd_i(GEN x, GEN y, GEN T, ulong p) { if (lg(x)<=FlxqX_HALFGCD_LIMIT) return FlxqX_halfgcd_basecase(x, y, T, p); return FlxqX_halfgcd_split(x, y, T, p); } GEN FlxqX_halfgcd(GEN x, GEN y, GEN T, ulong p) { pari_sp av = avma; GEN M,q,r; if (!signe(x)) { long v = varn(x), vT = get_Flx_var(T); retmkmat2(mkcol2(pol_0(v),pol1_FlxX(v,vT)), mkcol2(pol1_FlxX(v,vT),pol_0(v))); } if (degpol(y)1) pari_warn(warnmem,"FlxqX_gcd (d = %ld)",degpol(b)); gerepileall(av0,2, &a,&b); } av = avma; c = FlxqX_rem(a, b, T, p); a=b; b=c; } avma = av; return a; } GEN FlxqX_gcd(GEN x, GEN y, GEN T, ulong p) { pari_sp av = avma; x = FlxqX_red(x, T, p); y = FlxqX_red(y, T, p); if (!signe(x)) return gerepileupto(av, y); while (lg(y)>FlxqX_GCD_LIMIT) { GEN c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r = FlxqX_rem(x, y, T, p); x = y; y = r; } c = FlxqXM_FlxqX_mul2(FlxqX_halfgcd(x,y, T, p), x, y, T, p); x = gel(c,1); y = gel(c,2); gerepileall(av,2,&x,&y); } return gerepileupto(av, FlxqX_gcd_basecase(x, y, T, p)); } static GEN FlxqX_extgcd_basecase(GEN a, GEN b, GEN T, ulong p, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,d,d1,v1; long vx = varn(a); d = a; d1 = b; v = pol_0(vx); v1 = pol1_FlxX(vx, get_Flx_var(T)); while (signe(d1)) { GEN r, q = FlxqX_divrem(d, d1, T, p, &r); v = FlxX_sub(v,FlxqX_mul(q,v1,T, p),p); u=v; v=v1; v1=u; u=r; d=d1; d1=u; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_extgcd (d = %ld)",degpol(d)); gerepileall(av,5, &d,&d1,&u,&v,&v1); } } if (ptu) *ptu = FlxqX_div(FlxX_sub(d,FlxqX_mul(b,v, T, p), p), a, T, p); *ptv = v; return d; } static GEN FlxqX_extgcd_halfgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,R = matid2_FlxXM(varn(x), get_Flx_var(T)); while (lg(y)>FlxqX_EXTGCD_LIMIT) { GEN M, c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r, q = FlxqX_divrem(x, y, T, p, &r); x = y; y = r; R = FlxqX_FlxqXM_qmul(q, R, T, p); } M = FlxqX_halfgcd(x,y, T, p); c = FlxqXM_FlxqX_mul2(M, x,y, T, p); R = FlxqXM_mul2(M, R, T, p); x = gel(c,1); y = gel(c,2); gerepileall(av,3,&x,&y,&R); } y = FlxqX_extgcd_basecase(x,y, T, p, &u,&v); if (ptu) *ptu = FlxqX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T, p); *ptv = FlxqX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T, p); return y; } /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st * ux + vy = gcd (mod T,p) */ GEN FlxqX_extgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv) { GEN d; pari_sp ltop=avma; x = FlxqX_red(x, T, p); y = FlxqX_red(y, T, p); if (lg(y)>FlxqX_EXTGCD_LIMIT) d = FlxqX_extgcd_halfgcd(x, y, T, p, ptu, ptv); else d = FlxqX_extgcd_basecase(x, y, T, p, ptu, ptv); gerepileall(ltop,ptu?3:2,&d,ptv,ptu); return d; } GEN FlxqX_safegcd(GEN P, GEN Q, GEN T, ulong p) { pari_sp av = avma; GEN U; if (!signe(P)) return gcopy(Q); if (!signe(Q)) return gcopy(P); for(;;) { U = Flxq_invsafe(leading_coeff(Q), T, p); if (!U) { avma = av; return NULL; } Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p); P = FlxqX_rem(P,Q,T,p); if (!signe(P)) break; if (gc_needed(av, 1)) { if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_safegcd"); gerepileall(av, 2, &P,&Q); } swap(P, Q); } U = Flxq_invsafe(leading_coeff(Q), T, p); if (!U) { avma = av; return NULL; } Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p); return gerepileupto(av, Q); } struct _FlxqX {ulong p; GEN T;}; static GEN _FlxqX_mul(void *data,GEN a,GEN b) { struct _FlxqX *d=(struct _FlxqX*)data; return FlxqX_mul(a,b,d->T,d->p); } static GEN _FlxqX_sqr(void *data,GEN a) { struct _FlxqX *d=(struct _FlxqX*)data; return FlxqX_sqr(a,d->T,d->p); } GEN FlxqX_powu(GEN V, ulong n, GEN T, ulong p) { struct _FlxqX d; d.p=p; d.T=T; return gen_powu(V, n, (void*)&d, &_FlxqX_sqr, &_FlxqX_mul); } GEN FlxqXV_prod(GEN V, GEN T, ulong p) { struct _FlxqX d; d.p=p; d.T=T; return gen_product(V, (void*)&d, &_FlxqX_mul); } static GEN FlxqV_roots_to_deg1(GEN x, GEN T, ulong p, long v) { long sv = get_Flx_var(T); pari_APPLY_same(deg1pol_shallow(pol1_Flx(sv),Flx_neg(gel(x,i),p),v)) } GEN FlxqV_roots_to_pol(GEN V, GEN T, ulong p, long v) { pari_sp ltop = avma; GEN W = FlxqV_roots_to_deg1(V, T, p, v); return gerepileupto(ltop, FlxqXV_prod(W, T, p)); } /*** FlxqM ***/ GEN FlxqC_Flxq_mul(GEN x, GEN y, GEN T, ulong p) { pari_APPLY_type(t_COL, Flxq_mul(gel(x, i), y, T, p)) } GEN FlxqM_Flxq_mul(GEN x, GEN y, GEN T, ulong p) { pari_APPLY_same(FlxqC_Flxq_mul(gel(x, i), y, T, p)) } static GEN kron_pack_Flx_spec_half(GEN x, long l) { if (l == 0) return gen_0; return Flx_to_int_halfspec(x, l); } static GEN kron_pack_Flx_spec(GEN x, long l) { long i; GEN w, y; if (l == 0) return gen_0; y = cgetipos(l + 2); for (i = 0, w = int_LSW(y); i < l; i++, w = int_nextW(w)) *w = x[i]; return y; } static GEN kron_pack_Flx_spec_2(GEN x, long l) { return Flx_eval2BILspec(x, 2, l); } static GEN kron_pack_Flx_spec_3(GEN x, long l) { return Flx_eval2BILspec(x, 3, l); } static GEN kron_pack_Flx_spec_bits(GEN x, long b, long l) { GEN y; long i; if (l == 0) return gen_0; y = cgetg(l + 1, t_VECSMALL); for(i = 1; i <= l; i++) y[i] = x[l - i]; return nv_fromdigits_2k(y, b); } static GEN kron_unpack_Flx(GEN z, ulong p) { long i, l = lgefint(z); GEN x = cgetg(l, t_VECSMALL), w; for (w = int_LSW(z), i = 2; i < l; w = int_nextW(w), i++) x[i] = ((ulong) *w) % p; return Flx_renormalize(x, l); } static GEN kron_unpack_Flx_2(GEN x, ulong p) { long d = (lgefint(x)-1)/2 - 1; return Z_mod2BIL_Flx_2(x, d, p); } static GEN kron_unpack_Flx_3(GEN x, ulong p) { long d = lgefint(x)/3 - 1; return Z_mod2BIL_Flx_3(x, d, p); } /* assume b < BITS_IN_LONG */ static GEN kron_unpack_Flx_bits_narrow(GEN z, long b, ulong p) { GEN v = binary_2k_nv(z, b), x; long i, l = lg(v) + 1; x = cgetg(l, t_VECSMALL); for (i = 2; i < l; i++) x[i] = v[l - i] % p; return Flx_renormalize(x, l); } static GEN kron_unpack_Flx_bits_wide(GEN z, long b, ulong p, ulong pi) { GEN v = binary_2k(z, b), x, y; long i, l = lg(v) + 1, ly; x = cgetg(l, t_VECSMALL); for (i = 2; i < l; i++) { y = gel(v, l - i); ly = lgefint(y); switch (ly) { case 2: x[i] = 0; break; case 3: x[i] = *int_W_lg(y, 0, ly) % p; break; case 4: x[i] = remll_pre(*int_W_lg(y, 1, ly), *int_W_lg(y, 0, ly), p, pi); break; case 5: x[i] = remlll_pre(*int_W_lg(y, 2, ly), *int_W_lg(y, 1, ly), *int_W_lg(y, 0, ly), p, pi); break; default: x[i] = umodiu(gel(v, l - i), p); } } return Flx_renormalize(x, l); } static GEN FlxM_pack_ZM(GEN M, GEN (*pack)(GEN, long)) { long i, j, l, lc; GEN N = cgetg_copy(M, &l), x; if (l == 1) return N; lc = lgcols(M); for (j = 1; j < l; j++) { gel(N, j) = cgetg(lc, t_COL); for (i = 1; i < lc; i++) { x = gcoeff(M, i, j); gcoeff(N, i, j) = pack(x + 2, lgpol(x)); } } return N; } static GEN FlxM_pack_ZM_bits(GEN M, long b) { long i, j, l, lc; GEN N = cgetg_copy(M, &l), x; if (l == 1) return N; lc = lgcols(M); for (j = 1; j < l; j++) { gel(N, j) = cgetg(lc, t_COL); for (i = 1; i < lc; i++) { x = gcoeff(M, i, j); gcoeff(N, i, j) = kron_pack_Flx_spec_bits(x + 2, b, lgpol(x)); } } return N; } static GEN ZM_unpack_FlxqM(GEN M, GEN T, ulong p, GEN (*unpack)(GEN, ulong)) { long i, j, l, lc, sv = get_Flx_var(T); GEN N = cgetg_copy(M, &l), x; if (l == 1) return N; lc = lgcols(M); for (j = 1; j < l; j++) { gel(N, j) = cgetg(lc, t_COL); for (i = 1; i < lc; i++) { x = unpack(gcoeff(M, i, j), p); x[1] = sv; gcoeff(N, i, j) = Flx_rem(x, T, p); } } return N; } static GEN ZM_unpack_FlxqM_bits(GEN M, long b, GEN T, ulong p) { long i, j, l, lc, sv = get_Flx_var(T); GEN N = cgetg_copy(M, &l), x; if (l == 1) return N; lc = lgcols(M); if (b < BITS_IN_LONG) { for (j = 1; j < l; j++) { gel(N, j) = cgetg(lc, t_COL); for (i = 1; i < lc; i++) { x = kron_unpack_Flx_bits_narrow(gcoeff(M, i, j), b, p); x[1] = sv; gcoeff(N, i, j) = Flx_rem(x, T, p); } } } else { ulong pi = get_Fl_red(p); for (j = 1; j < l; j++) { gel(N, j) = cgetg(lc, t_COL); for (i = 1; i < lc; i++) { x = kron_unpack_Flx_bits_wide(gcoeff(M, i, j), b, p, pi); x[1] = sv; gcoeff(N, i, j) = Flx_rem(x, T, p); } } } return N; } GEN FlxqM_mul_Kronecker(GEN A, GEN B, GEN T, ulong p) { pari_sp av = avma; long b, d = degpol(T), n = lg(A) - 1; GEN C, D, z; GEN (*pack)(GEN, long), (*unpack)(GEN, ulong); int is_sqr = A==B; z = muliu(muliu(sqru(p - 1), d), n); b = expi(z) + 1; /* only do expensive bit-packing if it saves at least 1 limb */ if (b <= BITS_IN_HALFULONG) { if (nbits2lg(d*b) - 2 == (d + 1)/2) b = BITS_IN_HALFULONG; } else { long l = lgefint(z) - 2; if (nbits2lg(d*b) - 2 == d*l) b = l*BITS_IN_LONG; } avma = av; switch (b) { case BITS_IN_HALFULONG: pack = kron_pack_Flx_spec_half; unpack = int_to_Flx_half; break; case BITS_IN_LONG: pack = kron_pack_Flx_spec; unpack = kron_unpack_Flx; break; case 2*BITS_IN_LONG: pack = kron_pack_Flx_spec_2; unpack = kron_unpack_Flx_2; break; case 3*BITS_IN_LONG: pack = kron_pack_Flx_spec_3; unpack = kron_unpack_Flx_3; break; default: A = FlxM_pack_ZM_bits(A, b); B = is_sqr? A: FlxM_pack_ZM_bits(B, b); C = ZM_mul(A, B); D = ZM_unpack_FlxqM_bits(C, b, T, p); return gerepilecopy(av, D); } A = FlxM_pack_ZM(A, pack); B = is_sqr? A: FlxM_pack_ZM(B, pack); C = ZM_mul(A, B); D = ZM_unpack_FlxqM(C, T, p, unpack); return gerepilecopy(av, D); } /*******************************************************************/ /* */ /* (Fl[X]/T(X))[Y] / S(Y) */ /* */ /*******************************************************************/ GEN FlxqXQ_mul(GEN x, GEN y, GEN S, GEN T, ulong p) { return FlxqX_rem(FlxqX_mul(x,y,T,p),S,T,p); } GEN FlxqXQ_sqr(GEN x, GEN S, GEN T, ulong p) { return FlxqX_rem(FlxqX_sqr(x,T,p),S,T,p); } GEN FlxqXQ_invsafe(GEN x, GEN S, GEN T, ulong p) { GEN V, z = FlxqX_extgcd(get_FlxqX_mod(S), x, T, p, NULL, &V); if (degpol(z)) return NULL; z = Flxq_invsafe(gel(z,2),T,p); if (!z) return NULL; return FlxqX_Flxq_mul(V, z, T, p); } GEN FlxqXQ_inv(GEN x, GEN S, GEN T,ulong p) { pari_sp av = avma; GEN U = FlxqXQ_invsafe(x, S, T, p); if (!U) pari_err_INV("FlxqXQ_inv",x); return gerepileupto(av, U); } GEN FlxqXQ_div(GEN x, GEN y, GEN S, GEN T, ulong p) { return FlxqXQ_mul(x, FlxqXQ_inv(y,S,T,p),S,T,p); } struct _FlxqXQ { GEN T, S; ulong p; }; static GEN _FlxqXQ_add(void *data, GEN x, GEN y) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return FlxX_add(x,y, d->p); } static GEN _FlxqXQ_sub(void *data, GEN x, GEN y) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return FlxX_sub(x,y, d->p); } static GEN _FlxqXQ_cmul(void *data, GEN P, long a, GEN x) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return FlxX_Flx_mul(x,gel(P,a+2), d->p); } static GEN _FlxqXQ_red(void *data, GEN x) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return FlxqX_red(x, d->T, d->p); } static GEN _FlxqXQ_mul(void *data, GEN x, GEN y) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return FlxqXQ_mul(x,y, d->S,d->T, d->p); } static GEN _FlxqXQ_sqr(void *data, GEN x) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return FlxqXQ_sqr(x, d->S,d->T, d->p); } static GEN _FlxqXQ_one(void *data) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return pol1_FlxX(get_FlxqX_var(d->S),get_Flx_var(d->T)); } static GEN _FlxqXQ_zero(void *data) { struct _FlxqXQ *d = (struct _FlxqXQ*) data; return pol_0(get_FlxqX_var(d->S)); } static struct bb_algebra FlxqXQ_algebra = { _FlxqXQ_red, _FlxqXQ_add, _FlxqXQ_sub, _FlxqXQ_mul, _FlxqXQ_sqr, _FlxqXQ_one, _FlxqXQ_zero }; const struct bb_algebra * get_FlxqXQ_algebra(void **E, GEN S, GEN T, ulong p) { GEN z = new_chunk(sizeof(struct _FlxqXQ)); struct _FlxqXQ *e = (struct _FlxqXQ *) z; e->T = Flx_get_red(T, p); e->S = FlxqX_get_red(S, e->T, p); e->p = p; *E = (void*)e; return &FlxqXQ_algebra; } /* x over Fq, return lift(x^n) mod S */ GEN FlxqXQ_pow(GEN x, GEN n, GEN S, GEN T, ulong p) { struct _FlxqXQ D; long s = signe(n); if (!s) return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T)); if (s < 0) x = FlxqXQ_inv(x,S,T,p); if (is_pm1(n)) return s < 0 ? x : gcopy(x); if (degpol(x) >= get_FlxqX_degree(S)) x = FlxqX_rem(x,S,T,p); T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S = S; D.T = T; D.p = p; return gen_pow(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul); } /* x over Fq, return lift(x^n) mod S */ GEN FlxqXQ_powu(GEN x, ulong n, GEN S, GEN T, ulong p) { struct _FlxqXQ D; switch(n) { case 0: return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T)); case 1: return gcopy(x); case 2: return FlxqXQ_sqr(x, S, T, p); } T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S = S; D.T = T; D.p = p; return gen_powu(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul); } GEN FlxqXQ_powers(GEN x, long l, GEN S, GEN T, ulong p) { struct _FlxqXQ D; int use_sqr = 2*degpol(x) >= get_FlxqX_degree(S); T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S = S; D.T = T; D.p = p; return gen_powers(x, l, use_sqr, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul,&_FlxqXQ_one); } static GEN FlxqXn_mul(GEN a, GEN b, long n, GEN T, ulong p) { return RgXn_red_shallow(FlxqX_mul(a, b, T, p), n); } /* Let v a linear form, return the linear form z->v(tau*z) that is, v*(M_tau) */ static GEN FlxqXQ_transmul_init(GEN tau, GEN S, GEN T, ulong p) { GEN bht; GEN h, Sp = get_FlxqX_red(S, &h); long n = degpol(Sp), vS = varn(Sp), vT = get_Flx_var(T); GEN ft = FlxX_recipspec(Sp+2, n+1, n+1, vT); GEN bt = FlxX_recipspec(tau+2, lgpol(tau), n, vT); setvarn(ft, vS); setvarn(bt, vS); if (h) bht = FlxqXn_mul(bt, h, n-1, T, p); else { GEN bh = FlxqX_div(RgX_shift_shallow(tau, n-1), S, T, p); bht = FlxX_recipspec(bh+2, lgpol(bh), n-1, vT); setvarn(bht, vS); } return mkvec3(bt, bht, ft); } static GEN FlxqXQ_transmul(GEN tau, GEN a, long n, GEN T, ulong p) { pari_sp ltop = avma; GEN t1, t2, t3, vec; GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3); if (signe(a)==0) return pol_0(varn(a)); t2 = RgX_shift_shallow(FlxqX_mul(bt, a, T, p),1-n); if (signe(bht)==0) return gerepilecopy(ltop, t2); t1 = RgX_shift_shallow(FlxqX_mul(ft, a, T, p),-n); t3 = FlxqXn_mul(t1, bht, n-1, T, p); vec = FlxX_sub(t2, RgX_shift_shallow(t3, 1), p); return gerepileupto(ltop, vec); } static GEN polxn_FlxX(long n, long v, long vT) { long i, a = n+2; GEN p = cgetg(a+1, t_POL); p[1] = evalsigne(1)|evalvarn(v); for (i = 2; i < a; i++) gel(p,i) = pol0_Flx(vT); gel(p,a) = pol1_Flx(vT); return p; } GEN FlxqXQ_minpoly(GEN x, GEN S, GEN T, ulong p) { pari_sp ltop = avma; long vS, vT, n; GEN v_x, g, tau; vS = get_FlxqX_var(S); vT = get_Flx_var(T); n = get_FlxqX_degree(S); g = pol1_FlxX(vS,vT); tau = pol1_FlxX(vS,vT); S = FlxqX_get_red(S, T, p); v_x = FlxqXQ_powers(x, usqrt(2*n), S, T, p); while(signe(tau) != 0) { long i, j, m, k1; GEN M, v, tr; GEN g_prime, c; if (degpol(g) == n) { tau = pol1_FlxX(vS, vT); g = pol1_FlxX(vS, vT); } v = random_FlxqX(n, vS, T, p); tr = FlxqXQ_transmul_init(tau, S, T, p); v = FlxqXQ_transmul(tr, v, n, T, p); m = 2*(n-degpol(g)); k1 = usqrt(m); tr = FlxqXQ_transmul_init(gel(v_x,k1+1), S, T, p); c = cgetg(m+2,t_POL); c[1] = evalsigne(1)|evalvarn(vS); for (i=0; i , i = 0..m-1 */ M = FlxqX_halfgcd(polxn_FlxX(m, vS, vT), c, T, p); g_prime = gmael(M, 2, 2); if (degpol(g_prime) < 1) continue; g = FlxqX_mul(g, g_prime, T, p); tau = FlxqXQ_mul(tau, FlxqX_FlxqXQV_eval(g_prime, v_x, S, T, p), S, T, p); } g = FlxqX_normalize(g,T, p); return gerepilecopy(ltop,g); } GEN FlxqXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, ulong p) { return FlxXV_to_FlxM(FlxqXQ_powers(y,m-1,S,T,p), n, T[1]); } GEN FlxqX_FlxqXQV_eval(GEN P, GEN V, GEN S, GEN T, ulong p) { struct _FlxqXQ D; T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &FlxqXQ_algebra, _FlxqXQ_cmul); } GEN FlxqX_FlxqXQ_eval(GEN Q, GEN x, GEN S, GEN T, ulong p) { struct _FlxqXQ D; int use_sqr = 2*degpol(x) >= get_FlxqX_degree(S); T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &FlxqXQ_algebra, _FlxqXQ_cmul); } static GEN FlxqXQ_autpow_sqr(void * E, GEN x) { struct _FlxqXQ *D = (struct _FlxqXQ *)E; GEN S = D->S, T = D->T; ulong p = D->p; GEN phi = gel(x,1), S1 = gel(x,2); long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1); GEN V = Flxq_powers(phi, n, T, p); GEN phi2 = Flx_FlxqV_eval(phi, V, T, p); GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p); GEN S2 = FlxqX_FlxqXQ_eval(Sphi, S1, S, T, p); return mkvec2(phi2, S2); } static GEN FlxqXQ_autpow_mul(void * E, GEN x, GEN y) { struct _FlxqXQ *D = (struct _FlxqXQ *)E; GEN S = D->S, T = D->T; ulong p = D->p; GEN phi1 = gel(x,1), S1 = gel(x,2); GEN phi2 = gel(y,1), S2 = gel(y,2); long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1); GEN V = Flxq_powers(phi2, n, T, p); GEN phi3 = Flx_FlxqV_eval(phi1, V, T, p); GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p); GEN S3 = FlxqX_FlxqXQ_eval(Sphi, S2, S, T, p); return mkvec2(phi3, S3); } GEN FlxqXQ_autpow(GEN aut, long n, GEN S, GEN T, ulong p) { struct _FlxqXQ D; T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_powu(aut,n,&D,FlxqXQ_autpow_sqr,FlxqXQ_autpow_mul); } static GEN FlxqXQ_autsum_mul(void *E, GEN x, GEN y) { struct _FlxqXQ *D = (struct _FlxqXQ *)E; GEN S = D->S, T = D->T; ulong p = D->p; GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3); GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3); long n2 = brent_kung_optpow(get_Flx_degree(T)-1, lgpol(S1)+lgpol(a1)+1,1); GEN V2 = Flxq_powers(phi2, n2, T, p); GEN phi3 = Flx_FlxqV_eval(phi1, V2, T, p); GEN Sphi = FlxY_FlxqV_evalx(S1, V2, T, p); GEN aphi = FlxY_FlxqV_evalx(a1, V2, T, p); long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1); GEN V = FlxqXQ_powers(S2, n, S, T, p); GEN S3 = FlxqX_FlxqXQV_eval(Sphi, V, S, T, p); GEN aS = FlxqX_FlxqXQV_eval(aphi, V, S, T, p); GEN a3 = FlxqXQ_mul(aS, a2, S, T, p); return mkvec3(phi3, S3, a3); } static GEN FlxqXQ_autsum_sqr(void * T, GEN x) { return FlxqXQ_autsum_mul(T, x, x); } GEN FlxqXQ_autsum(GEN aut, long n, GEN S, GEN T, ulong p) { struct _FlxqXQ D; T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_powu(aut,n,&D,FlxqXQ_autsum_sqr,FlxqXQ_autsum_mul); } static GEN FlxqXQ_auttrace_mul(void *E, GEN x, GEN y) { struct _FlxqXQ *D = (struct _FlxqXQ *)E; GEN S = D->S, T = D->T; ulong p = D->p; GEN S1 = gel(x,1), a1 = gel(x,2); GEN S2 = gel(y,1), a2 = gel(y,2); long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1); GEN V = FlxqXQ_powers(S2, n, S, T, p); GEN S3 = FlxqX_FlxqXQV_eval(S1, V, S, T, p); GEN aS = FlxqX_FlxqXQV_eval(a1, V, S, T, p); GEN a3 = FlxX_add(aS, a2, p); return mkvec2(S3, a3); } static GEN FlxqXQ_auttrace_sqr(void *E, GEN x) { return FlxqXQ_auttrace_mul(E, x, x); } GEN FlxqXQ_auttrace(GEN x, ulong n, GEN S, GEN T, ulong p) { struct _FlxqXQ D; T = Flx_get_red(T, p); S = FlxqX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_powu(x,n,(void*)&D,FlxqXQ_auttrace_sqr,FlxqXQ_auttrace_mul); } /*******************************************************************/ /* */ /* FlxYqQ */ /* */ /*******************************************************************/ /*Preliminary implementation to speed up FpX_ffisom*/ typedef struct { GEN S, T; ulong p; } FlxYqq_muldata; /* reduce x in Fl[X, Y] in the algebra Fl[X, Y]/ (P(X),Q(Y)) */ static GEN FlxYqq_redswap(GEN x, GEN S, GEN T, ulong p) { pari_sp ltop=avma; long n = get_Flx_degree(S); long m = get_Flx_degree(T); long w = get_Flx_var(T); GEN V = FlxX_swap(x,m,w); V = FlxqX_red(V,S,p); V = FlxX_swap(V,n,w); return gerepilecopy(ltop,V); } static GEN FlxYqq_sqr(void *data, GEN x) { FlxYqq_muldata *D = (FlxYqq_muldata*)data; return FlxYqq_redswap(FlxqX_sqr(x, D->T, D->p),D->S,D->T,D->p); } static GEN FlxYqq_mul(void *data, GEN x, GEN y) { FlxYqq_muldata *D = (FlxYqq_muldata*)data; return FlxYqq_redswap(FlxqX_mul(x,y, D->T, D->p),D->S,D->T,D->p); } /* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */ GEN FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p) { pari_sp av = avma; FlxYqq_muldata D; GEN y; D.S = S; D.T = T; D.p = p; y = gen_pow(x, n, (void*)&D, &FlxYqq_sqr, &FlxYqq_mul); return gerepileupto(av, y); } pari-2.11.2/src/basemath/polarit1.c0000644000175000017500000004111013457600745015440 0ustar billbill/* Copyright (C) 2000-2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /***********************************************************************/ /** **/ /** ARITHMETIC OPERATIONS ON POLYNOMIALS **/ /** (first part) **/ /** **/ /***********************************************************************/ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* POLYNOMIAL EUCLIDEAN DIVISION */ /* */ /*******************************************************************/ /* x t_POLMOD, y t_POL in the same variable as x[1], return x % y */ static GEN polmod_mod(GEN x, GEN y) { GEN z, a, T = gel(x,1); if (RgX_equal(T, y)) return gcopy(x); z = cgetg(3,t_POLMOD); T = RgX_gcd(T,y); a = gel(x,2); gel(z,1) = T; gel(z,2) = (typ(a)==t_POL && varn(a)==varn(T))? RgX_rem(a, T): gcopy(a); return z; } /* x,y two "scalars", return 0 with type info */ static GEN rem_scal_scal(GEN x, GEN y) { pari_sp av = avma; GEN z = gadd(gmul(gen_0,x), gmul(gen_0,y)); if (gequal0(y)) pari_err_INV("grem",y); return gerepileupto(av, simplify(z)); } /* x pol, y "scalar", return 0 with type info */ static GEN rem_pol_scal(GEN x, GEN y) { pari_sp av = avma; if (gequal0(y)) pari_err_INV("grem",y); return gerepileupto(av, simplify(gmul(Rg_get_0(x),y))); } /* x "scalar", y pol, return x % y with type info */ static GEN rem_scal_pol(GEN x, GEN y) { if (degpol(y)) { if (!signe(y)) pari_err_INV("grem",y); return gmul(x, Rg_get_1(y)); } y = gel(y,2); return rem_scal_scal(x,y); } GEN poldivrem(GEN x, GEN y, GEN *pr) { const char *f = "euclidean division"; long tx = typ(x), ty = typ(y), vx = gvar(x), vy = gvar(y); GEN z; if (!is_extscalar_t(tx) || !is_extscalar_t(ty)) pari_err_TYPE2(f,x,y); if (vx == vy && ((tx==t_POLMOD) ^ (ty==t_POLMOD))) pari_err_TYPE2(f,x,y); if (ty != t_POL || varncmp(vx, vy) < 0) /* y "scalar" */ { if (!pr || pr == ONLY_DIVIDES) return gdiv(x,y); if (tx != t_POL || varncmp(vy, vx) < 0) /* x "scalar" */ z = rem_scal_scal(x,y); else z = rem_pol_scal(x,y); if (pr == ONLY_REM) return z; *pr = z; return gdiv(x,y); } if (tx != t_POL || varncmp(vx, vy) > 0) /* x "scalar" */ { if (!degpol(y)) /* constant t_POL, treat as scalar */ { y = gel(y,2); if (!pr || pr == ONLY_DIVIDES) gdiv(x,y); z = rem_scal_scal(x,y); if (pr == ONLY_REM) return z; *pr = z; return gdiv(x,y); } if (!signe(y)) pari_err_INV("poldivrem",y); if (!pr || pr == ONLY_DIVIDES) return gequal0(x)? Rg_get_0(y): NULL; z = gmul(x, Rg_get_1(y)); if (pr == ONLY_REM) return z; *pr = z; return Rg_get_0(y); } return RgX_divrem(x,y,pr); } GEN gdeuc(GEN x, GEN y) { const char *f = "euclidean division"; long tx = typ(x), ty = typ(y), vx = gvar(x), vy = gvar(y); if (!is_extscalar_t(tx) || !is_extscalar_t(ty)) pari_err_TYPE2(f,x,y); if (vx == vy && ((tx==t_POLMOD) ^ (ty==t_POLMOD))) pari_err_TYPE2(f,x,y); if (ty != t_POL || varncmp(vx, vy) < 0) return gdiv(x,y); /* y "scalar" */ if (tx != t_POL || varncmp(vx, vy) > 0) { /* x "scalar" */ if (!signe(y)) pari_err_INV("gdeuc",y); if (!degpol(y)) return gdiv(x, gel(y,2)); /* constant */ return Rg_get_0(y); } return RgX_div(x,y); } GEN grem(GEN x, GEN y) { const char *f = "euclidean division"; long tx = typ(x), ty = typ(y), vx = gvar(x), vy = gvar(y); if (ty == t_POL) { if (varncmp(vx,vy) >= 0) { pari_sp av; GEN z; if (!signe(y)) pari_err_INV("grem",y); if (vx != vy) return rem_scal_pol(x,y); switch(tx) { case t_POLMOD: return polmod_mod(x,y); case t_POL: return RgX_rem(x,y); case t_RFRAC: av = avma; z = RgXQ_inv(RgX_rem(gel(x,2), y), y); return gerepileupto(av, grem(gmul(gel(x,1), z), y)); case t_SER: if (RgX_is_monomial(y)) { if (lg(x)-2 + valp(x) < degpol(y)) pari_err_OP("%",x,y); av = avma; return gerepileupto(av, gmod(ser2rfrac_i(x), y)); } default: pari_err_TYPE2("%",x,y); } } else switch(tx) { case t_POL: case t_RFRAC: return rem_pol_scal(x,y); default: pari_err_TYPE2("%",x,y); } } if (!is_extscalar_t(tx) || !is_extscalar_t(ty)) pari_err_TYPE2(f,x,y); if (vx == vy && ty==t_POLMOD) pari_err_TYPE2(f,x,y); if (tx != t_POL || varncmp(vx,vy) > 0) { /* x a "scalar" */ if (ty != t_POL || varncmp(vx, vy) < 0) return rem_scal_scal(x,y); return rem_scal_pol(x,y); } if (ty != t_POL || varncmp(vx, vy) < 0) /* y a "scalar" */ return rem_pol_scal(x,y); return RgX_rem(x,y); } /*******************************************************************/ /* */ /* CONVERSIONS RELATED TO p-ADICS */ /* */ /*******************************************************************/ /* x t_PADIC, p a prime or NULL (unset). Consistency check */ static void check_padic_p(GEN x, GEN p) { GEN q = gel(x,2); if (p && !equalii(p, q)) pari_err_MODULUS("Zp_to_Z", p,q); } /* shallow */ static GEN Zp_to_Z(GEN x, GEN p) { switch(typ(x)) { case t_INT: break; case t_PADIC: check_padic_p(x, p); x = gtrunc(x); break; default: pari_err_TYPE("Zp_to_Z",x); } return x; } /* shallow */ static GEN ZpX_to_ZX(GEN f, GEN p) { long i, l = lg(f); GEN F = cgetg_copy(f, &l); F[1] = f[1]; for (i=2; i= prec */ GEN ZX_Zp_root(GEN f, GEN a, GEN p, long prec) { GEN z, R, a0 = modii(a, p); long i, j, k; if (signe(FpX_eval(FpX_deriv(f, p), a0, p))) { /* simple zero mod p, go all the way to p^prec */ if (prec > 1) a0 = ZpX_liftroot(f, a0, p, prec); return mkcol(a0); } f = ZX_unscale_div(RgX_translate(f,a), p); /* f(pX + a) / p */ (void)ZX_pvalrem(f,p,&f); z = cgetg(degpol(f)+1,t_COL); R = FpX_roots(f, p); for (j=i=1; i 0) f = RgX_div(f,z); T = gel(a,1); a = gel(a,2); p = NULL; prec = LONG_MAX; getprec(a, &prec, &p); getprec(T, &prec, &p); if (!p) pari_err_TYPE("padicappr",T); f = QpXQX_to_ZXY(f, p); if (typ(a) != t_POL) a = scalarpol_shallow(a, varn(T)); a = ZpX_to_ZX(a,p); T = QpX_to_ZX(T,p); /* if f was rounded above, it may now be non-separable */ (void)nfgcd_all(f, RgX_deriv(f), T, NULL, &f); if (!gequal0(FqX_eval(FqX_red(f,T,p), a, T,p))) /* check f(a) = 0 (mod p,T) */ { avma = av; return cgetg(1,t_COL); } z = ZXY_ZpQ_root(f, a, T, p, prec); return gerepilecopy(av, ZXV_to_ZpXQV(z, T, p, prec)); } /*******************************************************************/ /* */ /* FACTORIZATION in Zp[X], using ROUND4 */ /* */ /*******************************************************************/ int cmp_padic(GEN x, GEN y) { long vx, vy; if (x == gen_0) return -1; if (y == gen_0) return 1; vx = valp(x); vy = valp(y); if (vx < vy) return 1; if (vx > vy) return -1; return cmpii(gel(x,4), gel(y,4)); } /* replace p^e by p*...*p [ factors are not known to be equal, only close at * input accuracy ] */ static GEN famat_flatten(GEN fa) { GEN y, P = gel(fa,1), E = gel(fa,2); long i, l = lg(E); y = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN p = gel(P,i); long e = itou(gel(E,i)); gel(y,i) = const_vec(e, p); } y = shallowconcat1(y); settyp(y, t_COL); return mkmat2(y, const_col(lg(y)-1, gen_1)); } GEN factorpadic(GEN f, GEN p, long r) { pari_sp av = avma; GEN y, ppow; long v, n; int reverse = 0, exact; if (typ(f)!=t_POL) pari_err_TYPE("factorpadic",f); if (typ(p)!=t_INT) pari_err_TYPE("factorpadic",p); if (r <= 0) pari_err_DOMAIN("factorpadic", "precision", "<=",gen_0,stoi(r)); if (!signe(f)) return prime_fact(f); if (!degpol(f)) return trivial_fact(); exact = RgX_is_QX(f); /* before RgX_valrem which may lose type information */ v = RgX_valrem_inexact(f, &f); ppow = powiu(p,r); n = degpol(f); if (!n) y = trivial_fact(); else { GEN P, lead, lt; long i, l, pr; f = QpX_to_ZX(f, p); (void)Z_pvalrem(leading_coeff(f), p, <); f = pnormalize(f, p, r, n-1, &lead, &pr, &reverse); y = ZpX_monic_factor(f, p, pr); P = gel(y,1); l = lg(P); if (lead != gen_1) for (i=1; i 0 */ GEN X = ZX_to_ZpX(pol_x(varn(f)), p, ppow, r); y = famat_mulpow_shallow(y, X, utoipos(v)); } if (!exact) y = famat_flatten(y); return gerepilecopy(av, sort_factor_pol(y, cmp_padic)); } pari-2.11.2/src/basemath/bb_hnf.c0000644000175000017500000010036713457566437015146 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #define dbg_printf(lvl) if (DEBUGLEVEL >= (lvl) + 3) err_printf /********************************************************************/ /** **/ /** BLACK BOX HERMITE RINGS AND HOWELL NORMAL FORM **/ /** contributed by Aurel Page (2017) **/ /** **/ /********************************************************************/ /* bb_hermite R: - add(a,b): a+b - neg(a): -a - mul(a,b): a*b - extgcd(a,b,&small): [d,U] with d in R and U in GL_2(R) such that [0;d] = [a;b]*U. set small==1 to assert that U is a 'small' operation (no red needed). - rann(a): b in R such that b*R = {x in R | a*x==0} - lquo(a,b,&r): q in R such that r=a-b*q is a canonical representative of the image of a in R/b*R. The canonical lift of 0 must be 0. - unit(a): u unit in R^* such that a*u is a canonical generator of the ideal a*R - equal0(a): a==0? - equal1(a): a==1? - s(n): image of the small integer n in R - red(a): unique representative of a as an element of R op encoding of elementary operations: - t_VECSMALL: the corresponding permutation (vecpermute) - [Vecsmall([i,j])]: the transposition Ci <-> Cj - [Vecsmall([i]),u], u in R^*: Ci <- Ci*u - [Vecsmall([i,j]),a], a in R: Ci <- Ci + Cj*a - [Vecsmall([i,j,0]),U], U in GL_2(R): (Ci|Cj) <- (Ci|Cj)*U */ struct bb_hermite { GEN (*add)(void*, GEN, GEN); GEN (*neg)(void*, GEN); GEN (*mul)(void*, GEN, GEN); GEN (*extgcd)(void*, GEN, GEN, int*); GEN (*rann)(void*, GEN); GEN (*lquo)(void*, GEN, GEN, GEN*); GEN (*unit)(void*, GEN); int (*equal0)(GEN); int (*equal1)(GEN); GEN (*s)(void*, long); GEN (*red)(void*, GEN); }; static GEN _Fp_add(void *data, GEN x, GEN y) { (void) data; return addii(x,y); } static GEN _Fp_neg(void *data, GEN x) { (void) data; return negi(x); } static GEN _Fp_mul(void *data, GEN x, GEN y) { (void) data; return mulii(x,y); } static GEN _Fp_rann(void *data, GEN x) { GEN d, N = (GEN)data; if (!signe(x)) return gen_1; d = gcdii(x,N); return modii(diviiexact(N,d),N); } static GEN _Fp_lquo(void *data, GEN x, GEN y, GEN* r) { (void) data; return truedvmdii(x,y,r); } /* D=MN, p|M => !p|a, p|N => p|a, return M */ static GEN Z_split(GEN D, GEN a) { long i, n; GEN N; n = expi(D); n = n<2 ? 1 : expu(n)+1; for (i=1;i<=n;i++) a = Fp_sqr(a,D); N = gcdii(a,D); return diviiexact(D,N); } /* c s.t. gcd(a+cb,N) = gcd(a,b,N) without factoring */ static GEN Z_stab(GEN a, GEN b, GEN N) { GEN g, a2, N2; g = gcdii(a,b); g = gcdii(g,N); N2 = diviiexact(N,g); a2 = diviiexact(a,g); return Z_split(N2,a2); } static GEN _Fp_unit(void *data, GEN x) { GEN g,s,v,d,N=(GEN)data,N2; long i; if (!signe(x)) return NULL; g = bezout(x,N,&s,&v); if (equali1(g) || equali1(gcdii(s,N))) return mkvec2(g,s); N2 = diviiexact(N,g); for (i=0; i<5; i++) { s = addii(s,N2); if (equali1(gcdii(s,N))) return mkvec2(g,s); } d = Z_stab(s,N2,N); d = mulii(d,N2); v = Fp_add(s,d,N); if (equali1(v)) return NULL; return mkvec2(g,v); } static GEN _Fp_extgcd(void *data, GEN x, GEN y, int* smallop) { GEN d,u,v,m; if (equali1(y)) { *smallop = 1; return mkvec2(y,mkmat2( mkcol2(gen_1,Fp_neg(x,(GEN)data)), mkcol2(gen_0,gen_1))); } *smallop = 0; d = bezout(x,y,&u,&v); if (!signe(d)) return mkvec2(d,matid(2)); m = cgetg(3,t_MAT); m = mkmat2( mkcol2(diviiexact(y,d),negi(diviiexact(x,d))), mkcol2(u,v)); return mkvec2(d,m); } static int _Fp_equal0(GEN x) { return !signe(x); } static int _Fp_equal1(GEN x) { return equali1(x); } static GEN _Fp_s(void *data, long x) { if (!x) return gen_0; if (x==1) return gen_1; return modsi(x,(GEN)data); } static GEN _Fp_red(void *data, GEN x) { return Fp_red(x, (GEN)data); } /* p not necessarily prime */ static const struct bb_hermite Fp_hermite= {_Fp_add,_Fp_neg,_Fp_mul,_Fp_extgcd,_Fp_rann,_Fp_lquo,_Fp_unit,_Fp_equal0,_Fp_equal1,_Fp_s,_Fp_red}; static const struct bb_hermite* get_Fp_hermite(void **data, GEN p) { *data = (void*)p; return &Fp_hermite; } static void gen_redcol(GEN C, long lim, void* data, const struct bb_hermite *R) { long i; for (i=1; i<=lim; i++) if (!R->equal0(gel(C,i))) gel(C,i) = R->red(data, gel(C,i)); } static GEN /* return NULL if a==0 */ /* assume C*a is zero after lim */ gen_rightmulcol(GEN C, GEN a, long lim, int fillzeros, void* data, const struct bb_hermite *R) { GEN Ca,zero; long i; if (R->equal1(a)) return C; if (R->equal0(a)) return NULL; Ca = cgetg(lg(C),t_COL); for (i=1; i<=lim; i++) gel(Ca,i) = R->mul(data, gel(C,i), a); if (fillzeros && lim+1 < lg(C)) { zero = R->s(data,0); for (i=lim+1; ilim */ gen_addcol(GEN C1, GEN C2, long lim, void* data, const struct bb_hermite *R) { long i; for (i=1; i<=lim; i++) gel(C1,i) = R->add(data, gel(C1,i), gel(C2,i)); } static void /* H[,i] <- H[,i] + C*a */ /* assume C is zero after lim */ gen_addrightmul(GEN H, GEN C, GEN a, long i, long lim, void* data, const struct bb_hermite *R) { GEN Ca; if (R->equal0(a)) return; Ca = gen_rightmulcol(C, a, lim, 0, data, R); gen_addcol(gel(H,i), Ca, lim, data, R); } static GEN gen_zerocol(long n, void* data, const struct bb_hermite *R) { GEN C = cgetg(n+1,t_COL), zero = R->s(data, 0); long i; for (i=1; i<=n; i++) gel(C,i) = zero; return C; } static GEN gen_zeromat(long m, long n, void* data, const struct bb_hermite *R) { GEN M = cgetg(n+1,t_MAT); long i; for (i=1; i<=n; i++) gel(M,i) = gen_zerocol(m, data, R); return M; } static GEN gen_colei(long n, long i, void* data, const struct bb_hermite *R) { GEN C = cgetg(n+1,t_COL), zero = R->s(data, 0); long j; for (j=1; j<=n; j++) if (i!=j) gel(C,j) = zero; else gel(C,j) = R->s(data,1); return C; } static GEN gen_matid_hermite(long n, void* data, const struct bb_hermite *R) { GEN M = cgetg(n+1,t_MAT); long i; for (i=1; i<=n; i++) gel(M,i) = gen_colei(n, i, data, R); return M; } static GEN gen_matmul_hermite(GEN A, GEN B, void* data, const struct bb_hermite *R) { GEN M,sum,prod,zero = R->s(data,0); long a,b,c,c2,i,j,k; RgM_dimensions(A,&a,&c); RgM_dimensions(B,&c2,&b); if (c!=c2) pari_err_DIM("gen_matmul_hermite"); M = cgetg(b+1,t_MAT); for (j=1; j<=b; j++) { gel(M,j) = cgetg(a+1,t_COL); for (i=1; i<=a; i++) { sum = zero; for (k=1; k<=c; k++) { prod = R->mul(data, gcoeff(A,i,k), gcoeff(B,k,j)); sum = R->add(data, sum, prod); } gcoeff(M,i,j) = sum; } gen_redcol(gel(M,j), a, data, R); } return M; } static void /* U = [u1,u2]~, C <- A*u1 + B*u2 */ /* assume both A, B and C are zero after lim */ gen_rightlincomb(GEN A, GEN B, GEN U, GEN *C, long lim, void* data, const struct bb_hermite *R) { GEN Au1, Bu2; Au1 = gen_rightmulcol(A, gel(U,1), lim, 1, data, R); Bu2 = gen_rightmulcol(B, gel(U,2), lim, 1, data, R); if (!Au1 && !Bu2) { *C = gen_zerocol(lg(A)-1, data, R); return; } if (!Au1) { *C = Bu2; return; } if (!Bu2) { *C = Au1; return; } gen_addcol(Au1, Bu2, lim, data, R); *C = Au1; } static void /* (H[,i] | H[,j]) <- (H[,i] | H[,j]) * U */ /* assume both columns are zero after lim */ gen_elem(GEN H, GEN U, long i, long j, long lim, void* data, const struct bb_hermite *R) { GEN Hi, Hj; Hi = shallowcopy(gel(H,i)); Hj = shallowcopy(gel(H,j)); gen_rightlincomb(Hi, Hj, gel(U,1), &gel(H,i), lim, data, R); gen_rightlincomb(Hi, Hj, gel(U,2), &gel(H,j), lim, data, R); } static int /* assume C is zero after lim */ gen_is_zerocol(GEN C, long lim, void* data, const struct bb_hermite *R) { long i; (void) data; for (i=1; i<=lim; i++) if (!R->equal0(gel(C,i))) return 0; return 1; } /* The mkop* functions return NULL if the corresponding operation is the identity */ static GEN /* Ci <- Ci + Cj*a */ mkoptransv(long i, long j, GEN a, void* data, const struct bb_hermite *R) { a = R->red(data,a); if (R->equal0(a)) return NULL; return mkvec2(mkvecsmall2(i,j),a); } static GEN /* (Ci|Cj) <- (Ci|Cj)*U */ mkopU(long i, long j, GEN U, void* data, const struct bb_hermite *R) { if (R->equal1(gcoeff(U,1,1)) && R->equal0(gcoeff(U,1,2)) && R->equal1(gcoeff(U,2,2))) return mkoptransv(i,j,gcoeff(U,2,1),data,R); return mkvec2(mkvecsmall3(i,j,0),U); } static GEN /* Ci <- Ci*u */ mkopmul(long i, GEN u, const struct bb_hermite *R) { if (R->equal1(u)) return NULL; return mkvec2(mkvecsmall(i),u); } static GEN /* Ci <-> Cj */ mkopswap(long i, long j) { return mkvec(mkvecsmall2(i,j)); } /* M: t_MAT. Apply the operation op to M by right multiplication. */ static void gen_rightapply(GEN M, GEN op, void* data, const struct bb_hermite *R) { GEN M2, ind, X; long i, j, m = lg(gel(M,1))-1; switch (typ(op)) { case t_VECSMALL: M2 = vecpermute(M,op); for (i=1; imul(data, X, gel(C,i)); gel(C,i) = R->red(data, gel(C,i)); return; case 3: j = ind[2]; if (R->equal0(gel(C,i))) return; gel(C,j) = R->add(data, gel(C,j), R->mul(data, X, gel(C,i))); return; case 4: j = ind[2]; C2 = gen_matmul_hermite(X, mkmat(mkcol2(gel(C,i),gel(C,j))), data, R); gel(C,i) = gcoeff(C2,1,1); gel(C,j) = gcoeff(C2,2,1); return; } } } } /* \prod_i det ops[i]. Only makes sense if R is commutative. */ static GEN gen_detops(GEN ops, void* data, const struct bb_hermite *R) { GEN d = R->s(data,1); long i, l = lg(ops); for (i = 1; i < l; i++) { GEN X, op = gel(ops,i); switch (typ(op)) { case t_VECSMALL: if (perm_sign(op) < 0) d = R->neg(data,d); break; case t_VEC: switch (lg(op)) { case 2: d = R->neg(data,d); break; case 3: X = gel(op,2); switch (lg(gel(op,1))) { case 2: d = R->mul(data, d, X); d = R->red(data, d); break; case 4: { GEN A = gcoeff(X,1,1), B = gcoeff(X,1,2); GEN C = gcoeff(X,2,1), D = gcoeff(X,2,2); GEN AD = R->mul(data,A,D); GEN BC = R->mul(data,B,C); d = R->mul(data, d, R->add(data, AD, R->neg(data,BC))); d = R->red(data, d); break; } } break; } break; } } return d; } static int gen_is_inv(GEN x, void* data, const struct bb_hermite *R) { GEN u = R->unit(data, x); if (!u) return R->equal1(x); return R->equal1(gel(u,1)); } static long gen_last_inv_diago(GEN A, void* data, const struct bb_hermite *R) { long i,m,n,j; RgM_dimensions(A,&m,&n); for (i=1,j=n-m+1; i<=m; i++,j++) if (!gen_is_inv(gcoeff(A,i,j),data,R)) return i-1; return m; } static GEN /* remove_zerocols: 0 none, 1 until square, 2 all */ /* early abort: if not right-invertible, abort, return NULL, and set ops to the * non-invertible pivot */ gen_howell_i(GEN A, long remove_zerocols, long permute_zerocols, long early_abort, long only_triangular, GEN* ops, void *data, const struct bb_hermite *R) { pari_sp av = avma, av1; GEN H,U,piv=gen_0,u,q,a,perm,iszero,C,zero=R->s(data,0),d,g,r,op,one=R->s(data,1); long m,n,i,j,s,si,i2,si2,nbz,lim,extra,maxop=0,nbop=0,lastinv=0; int smallop; av1 = avma; RgM_dimensions(A,&m,&n); if (early_abort && n0 && si>extra; i--,si--) /* si = s+i */ { if (R->red) gcoeff(H,i,si) = R->red(data, gcoeff(H,i,si)); /* bottom-right diagonal */ for (j = extra+1; j < si; j++) { if (R->red) gcoeff(H,i,j) = R->red(data, gcoeff(H,i,j)); if (R->equal0(gcoeff(H,i,j))) continue; U = R->extgcd(data, gcoeff(H,i,j), gcoeff(H,i,si), &smallop); d = gel(U,1); U = gel(U,2); if (n>10) { /* normalize diagonal coefficient -> faster reductions on this row */ u = R->unit(data, d); if (u) { g = gel(u,1); u = gel(u,2); gcoeff(U,1,2) = R->mul(data, gcoeff(U,1,2), u); gcoeff(U,2,2) = R->mul(data, gcoeff(U,2,2), u); d = g; } } gen_elem(H, U, j, si, i-1, data, R); if (ops) { op = mkopU(j,si,U,data,R); if (op) { nbop++; gel(*ops, nbop) = op; } } gcoeff(H,i,j) = zero; gcoeff(H,i,si) = d; if (R->red && !smallop) { gen_redcol(gel(H,si), i-1, data, R); gen_redcol(gel(H,j), i-1, data, R); } } if (early_abort) { d = gcoeff(H,i,si); u = R->unit(data, d); if (u) d = gel(u,1); if (!R->equal1(d)) { if (ops) *ops = d; return NULL; } } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"gen_howell[1]. i=%ld",i); gerepileall(av1,ops?2:1,&H,ops); } } if (!ops) lastinv = gen_last_inv_diago(H, data, R); /* put in reduced Howell form */ if (!only_triangular) { for (i=m,si=s+m; i>0; i--,si--) /* si = s+i */ { /* normalize diagonal coefficient */ if (i<=lastinv) /* lastinv>0 => !ops */ gcoeff(H,i,si) = one; else { u = R->unit(data,gcoeff(H,i,si)); if (u) { g = gel(u,1); u = gel(u,2); gel(H,si) = gen_rightmulcol(gel(H,si), u, i-1, 1, data, R); gcoeff(H,i,si) = g; if (R->red) gen_redcol(gel(H,si), i-1, data, R); if (ops) { op = mkopmul(si,u,R); if (op) { nbop++; gel(*ops,nbop) = op; } } } else if (R->red) gcoeff(H,i,si) = R->red(data, gcoeff(H,i,si)); } piv = gcoeff(H,i,si); /* reduce above diagonal */ if (!R->equal0(piv)) { C = gel(H,si); for (j=si+1; j<=n; j++) { if (i<=lastinv) /* lastinv>0 => !ops */ gcoeff(H,i,j) = zero; else { gcoeff(H,i,j) = R->red(data, gcoeff(H,i,j)); if (R->equal1(piv)) { q = gcoeff(H,i,j); r = zero; } else q = R->lquo(data, gcoeff(H,i,j), piv, &r); q = R->neg(data,q); gen_addrightmul(H, C, q, j, i-1, data, R); if (ops) { op = mkoptransv(j,si,q,data,R); if (op) { nbop++; gel(*ops,nbop) = op; } } gcoeff(H,i,j) = r; } } } /* ensure Howell property */ if (i>1) { a = R->rann(data, piv); if (!R->equal0(a)) { gel(H,1) = gen_rightmulcol(gel(H,si), a, i-1, 1, data, R); if (gel(H,1) == gel(H,si)) gel(H,1) = shallowcopy(gel(H,1)); /* in case rightmulcol cheated */ if (ops) { op = mkoptransv(1,si,a,data,R); if (op) { nbop++; gel(*ops,nbop) = op; } } for (i2=i-1,si2=s+i2; i2>0; i2--,si2--) { if (R->red) gcoeff(H,i2,1) = R->red(data, gcoeff(H,i2,1)); if (R->equal0(gcoeff(H,i2,1))) continue; if (R->red) gcoeff(H,i2,si2) = R->red(data, gcoeff(H,i2,si2)); if (R->equal0(gcoeff(H,i2,si2))) { swap(gel(H,1), gel(H,si2)); if (ops) { nbop++; gel(*ops,nbop) = mkopswap(1,si2); } continue; } U = R->extgcd(data, gcoeff(H,i2,1), gcoeff(H,i2,si2), &smallop); d = gel(U,1); U = gel(U,2); gen_elem(H, U, 1, si2, i2-1, data, R); if (ops) { op = mkopU(1,si2,U,data,R); if (op) { nbop++; gel(*ops,nbop) = op; } } gcoeff(H,i2,1) = zero; gcoeff(H,i2,si2) = d; if (R->red && !smallop) { gen_redcol(gel(H,si2), i2, data, R); gen_redcol(gel(H,1), i2-1, data, R); } } } } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"gen_howell[2]. i=%ld",i); gerepileall(av1,ops?3:2,&H,&piv,ops); } } } if (R->red) for (j=1; j<=n; j++) { lim = maxss(0,m-n+j); gen_redcol(gel(H,j), lim, data, R); for (i=lim+1; i<=m; i++) gcoeff(H,i,j) = zero; } /* put zero columns first */ iszero = cgetg(n+1,t_VECSMALL); nbz = 0; for (i=1; i<=n; i++) { iszero[i] = gen_is_zerocol(gel(H,i), maxss(0,m-n+i), data, R); if (iszero[i]) nbz++; } j = 1; if (permute_zerocols) { perm = cgetg(n+1, t_VECSMALL); for (i=1; i<=n; i++) if (iszero[i]) { perm[j] = i; j++; } } else perm = cgetg(n-nbz+1, t_VECSMALL); for (i=1; i<=n; i++) if (!iszero[i]) { perm[j] = i; j++; } if (permute_zerocols || remove_zerocols==2) H = vecpermute(H, perm); if (permute_zerocols && remove_zerocols==2) H = vecslice(H, nbz+1, n); if (remove_zerocols==1) H = vecslice(H, s+1, n); if (permute_zerocols && ops) { nbop++; gel(*ops,nbop) = perm; } if (ops) { setlg(*ops, nbop+1); } /* should have nbop <= maxop */ return H; } static GEN gen_howell(GEN A, long remove_zerocols, long permute_zerocols, long early_abort, long only_triangular, GEN* ops, void *data, const struct bb_hermite *R) { pari_sp av = avma; GEN H = gen_howell_i(A, remove_zerocols, permute_zerocols, early_abort, only_triangular, ops, data, R); gerepileall(av, ops?2:1, &H, ops); return H; } static GEN gen_matimage(GEN A, GEN* U, void *data, const struct bb_hermite *R) { GEN ops, H; if (U) { pari_sp av = avma; long m, n, i, r, n2; RgM_dimensions(A,&m,&n); H = gen_howell_i(A, 2, 1, 0, 0, &ops, data, R); r = lg(H)-1; *U = shallowmatconcat(mkvec2(gen_zeromat(n, maxss(0,m-n+1), data, R), gen_matid_hermite(n, data, R))); n2 = lg(*U)-1; for (i=1; i0; j--) { while (R->equal0(gcoeff(H,i,j))) i--; piv = gcoeff(H,i,j); if (R->equal0(piv)) continue; gcoeff(K,j,j) = R->rann(data, piv); if (jneg(data, R->lquo(data, gcoeff(FK,1,j2-j), piv, NULL)); /* remainder has to be zero */ } } return K; } static GEN /* (H,ops) Howell form of A, n = number of columns of A, return a kernel of A */ gen_kernel_from_howell(GEN H, GEN ops, long n, void *data, const struct bb_hermite *R) { pari_sp av; GEN K, KH, zC; long m, r, n2, nbz, i, o, extra, j; RgM_dimensions(H,&m,&r); if (!r) return gen_matid_hermite(n, data, R); /* zerology: what if 0==1 in R? */ n2 = maxss(n,m+1); extra = n2-n; nbz = n2-r; /* compute kernel of augmented matrix */ KH = gen_kernel_howell(H, data, R); zC = gen_zerocol(nbz, data, R); K = cgetg(nbz+r+1, t_MAT); for (i=1; i<=nbz; i++) gel(K,i) = gen_colei(nbz+r, i, data, R); for (i=1; i<=r; i++) gel(K,nbz+i) = shallowconcat(zC, gel(KH,i)); for (i=1; i0; o--) gen_leftapply(gel(K,i), gel(ops,o), data, R); gen_redcol(gel(K,i), nbz+r, data, R); gerepileall(av, 1, &gel(K,i)); } /* deduce kernel of original matrix */ K = rowpermute(K, cyclic_perm(n2,extra)); K = gen_howell_i(K, 2, 0, 0, 0, NULL, data, R); for (j=lg(K)-1, i=n2; j>0; j--) { while (R->equal0(gcoeff(K,i,j))) i--; if (i<=n) return matslice(K, 1, n, 1, j); } return cgetg(1,t_MAT); } /* not GC-clean */ static GEN gen_kernel(GEN A, GEN* im, void *data, const struct bb_hermite *R) { pari_sp av = avma; long n = lg(A)-1; GEN H, ops, K; H = gen_howell_i(A, 2, 1, 0, 0, &ops, data, R); gerepileall(av,2,&H,&ops); K = gen_kernel_from_howell(H, ops, n, data, R); if (im) *im = H; return K; } /* right inverse, not GC-clean */ static GEN gen_inv(GEN A, void* data, const struct bb_hermite *R) { pari_sp av; GEN ops, H, U, un=R->s(data,1); long m,n,j,o,n2; RgM_dimensions(A,&m,&n); av = avma; H = gen_howell_i(A, 0, 0, 1, 0, &ops, data, R); if (!H) pari_err_INV("gen_inv", ops); n2 = lg(H)-1; ops = gerepilecopy(av,ops); /* get rid of H */ U = gen_zeromat(n2, m, data, R); for (j=1; j<=m; j++) gcoeff(U,j+n2-m,j) = un; for (j=1; j<=m; j++) { av = avma; for (o=lg(ops)-1; o>0; o--) gen_leftapply(gel(U,j), gel(ops,o), data, R); gen_redcol(gel(U,j), n2, data, R); gerepileall(av, 1, &gel(U,j)); } if (n2>n) U = rowslice(U, n2-n+1, n2); return U; } /* H true Howell form (no zero columns). Compute Z = Y - HX canonical representative of R^m mod H(R^n) */ static GEN gen_reduce_mod_howell(GEN H, GEN Y, GEN *X, void* data, const struct bb_hermite *R) { pari_sp av = avma; long m,n,i,j; GEN Z, q, r, C; RgM_dimensions(H,&m,&n); if (X) *X = gen_zerocol(n,data,R); Z = shallowcopy(Y); i = m; for (j=n; j>0; j--) { while (R->equal0(gcoeff(H,i,j))) i--; q = R->lquo(data, gel(Z,i), gcoeff(H,i,j), &r); gel(Z,i) = r; C = gen_rightmulcol(gel(H,j), R->neg(data,q), i, 0, data, R); if (C) gen_addcol(Z, C, i-1, data, R); if (X) gel(*X,j) = q; } gen_redcol(Z, lg(Z)-1, data, R); if (X) { gerepileall(av, 2, &Z, X); return Z; } return gerepilecopy(av, Z); } /* H: Howell form of A */ /* (m,n): dimensions of original matrix A */ /* return NULL if no solution */ static GEN gen_solve_from_howell(GEN H, GEN ops, long m, long n, GEN Y, void* data, const struct bb_hermite *R) { pari_sp av = avma; GEN Z, X; long n2, mH, nH, i; RgM_dimensions(H,&mH,&nH); n2 = maxss(n,m+1); Z = gen_reduce_mod_howell(H, Y, &X, data, R); if (!gen_is_zerocol(Z,m,data,R)) { avma=av; return NULL; } X = shallowconcat(zerocol(n2-nH),X); for (i=lg(ops)-1; i>0; i--) gen_leftapply(X, gel(ops,i), data, R); X = vecslice(X, n2-n+1, n2); gen_redcol(X, n, data, R); return gerepilecopy(av, X); } /* return NULL if no solution, not GC-clean */ static GEN gen_solve(GEN A, GEN Y, GEN* K, void* data, const struct bb_hermite *R) { GEN H, ops, X; long m,n; RgM_dimensions(A,&m,&n); if (!n) m = lg(Y)-1; H = gen_howell_i(A, 2, 1, 0, 0, &ops, data, R); X = gen_solve_from_howell(H, ops, m, n, Y, data, R); if (!X) return NULL; if (K) *K = gen_kernel_from_howell(H, ops, n, data, R); return X; } GEN matimagemod(GEN A, GEN d, GEN* U) { void *data; const struct bb_hermite* R; if (typ(A)!=t_MAT || !RgM_is_ZM(A)) pari_err_TYPE("matimagemod", A); if (typ(d)!=t_INT) pari_err_TYPE("matimagemod", d); if (signe(d)<=0) pari_err_DOMAIN("matimagemod", "d", "<=", gen_0, d); if (equali1(d)) return cgetg(1,t_MAT); R = get_Fp_hermite(&data, d); return gen_matimage(A, U, data, R); } /* for testing purpose */ /* GEN ZM_hnfmodid2(GEN A, GEN d) { pari_sp av = avma; void *data; long i; const struct bb_hermite* R = get_Fp_hermite(&data, d); GEN H; if (typ(A)!=t_MAT || !RgM_is_ZM(A)) pari_err_TYPE("ZM_hnfmodid2", A); if (typ(d)!=t_INT) pari_err_TYPE("ZM_hnfmodid2", d); H = gen_howell_i(A, 1, 0, 0, 0, NULL, data, R); for (i=1; i0, not GC-clean */ static GEN matsolvemod_finite(GEN M, GEN D, GEN Y, long flag) { void *data; const struct bb_hermite* R; GEN X, K, d; long m, n; RgM_dimensions(M,&m,&n); if (typ(D)==t_COL) { /* create extra variables for the D[i] */ GEN MD; long i, i2, extra = 0; d = gen_1; for (i=1; i1) r=FpXQ_autpow(r,n,T,p); break; case t_FF_F2xq: r=F2xq_sqr(gel(x,2),T); if (n>1) r=F2xq_autpow(r,n,T); break; default: r=Flxq_powu(gel(x,2),pp,T,pp); if (n>1) r=Flxq_autpow(r,n,T,pp); } return _mkFF(x,z,r); } GEN FFX_preimage(GEN x, GEN F, GEN y) { GEN r, T, p, z; ulong pp; if (FF_equal0(x)) return FF_zero(y); z=_initFF(y,&T,&p,&pp); F = FFX_to_raw(F, y); switch(y[1]) { case t_FF_FpXQ: r = FpXQX_rem(gel(x,2), F, T, p); break; case t_FF_F2xq: r = F2xqX_rem(F2x_to_F2xX(gel(x,2),T[1]), F, T); break; default: r = FlxqX_rem(Flx_to_FlxX(gel(x,2),T[1]), F, T, pp); } if (degpol(r) > 0) return NULL; r = (y[1] == t_FF_FpXQ)? Fq_to_FpXQ(gel(r,2),T, p): gel(r,2); return _mkFF(y,z,r); } GEN FF_mul(GEN x, GEN y) { ulong pp; GEN r, T, p, z=_initFF(x,&T,&p,&pp); pari_sp av=avma; _checkFF(x,y,"*"); switch(x[1]) { case t_FF_FpXQ: r=FpXQ_mul(gel(x,2),gel(y,2),T,p); break; case t_FF_F2xq: r=F2xq_mul(gel(x,2),gel(y,2),T); break; default: r=Flxq_mul(gel(x,2),gel(y,2),T,pp); } return _mkFF(x,z,gerepileupto(av, r)); } GEN FF_Z_mul(GEN x, GEN y) { ulong pp; GEN r, T, p, A = gel(x,2), z=_initFF(x,&T,&p,&pp); switch(x[1]) { case t_FF_FpXQ: /* modii(y,p) left on stack for efficiency */ r = FpX_Fp_mul(A, modii(y,p),p); break; case t_FF_F2xq: r = mpodd(y)? vecsmall_copy(A): zero_Flx(A[1]); break; default: r = Flx_Fl_mul(A, umodiu(y,pp), pp); } return _mkFF(x,z,r); } GEN FF_Z_Z_muldiv(GEN x, GEN a, GEN b) { ulong pp; GEN r, T, p, A = gel(x,2), z=_initFF(x,&T,&p,&pp); switch(x[1]) { case t_FF_FpXQ: /* Fp_div(a,b,p) left on stack for efficiency */ r = FpX_Fp_mul(A, Fp_div(a,b,p), p); break; case t_FF_F2xq: if (!mpodd(b)) pari_err_INV("FF_Z_Z_muldiv", b); r = mpodd(a)? vecsmall_copy(A): zero_Flx(A[1]); break; default: r = Flx_Fl_mul(A, Fl_div(umodiu(a,pp),umodiu(b,pp),pp),pp); } return _mkFF(x,z,r); } GEN FF_sqr(GEN x) { ulong pp; GEN r, T, p, z=_initFF(x,&T,&p,&pp); switch(x[1]) { case t_FF_FpXQ: { pari_sp av=avma; r=gerepileupto(av,FpXQ_sqr(gel(x,2),T,p)); break; } case t_FF_F2xq: r=F2xq_sqr(gel(x,2),T); break; default: r=Flxq_sqr(gel(x,2),T,pp); } return _mkFF(x,z,r); } GEN FF_mul2n(GEN x, long n) { ulong pp; GEN r, T, p, A = gel(x,2), z=_initFF(x,&T,&p,&pp); switch(x[1]) { case t_FF_FpXQ: { GEN p1; /* left on stack for efficiency */ if (n>0) p1=remii(int2n(n),p); else p1=Fp_inv(remii(int2n(-n),p),p); r = FpX_Fp_mul(A, p1, p); } break; case t_FF_F2xq: if (n<0) pari_err_INV("FF_mul2n", gen_2); r = n==0? vecsmall_copy(A): zero_Flx(A[1]); break; default: { ulong l1; if (n>0) l1 = umodiu(int2n(n),pp); else l1 = Fl_inv(umodiu(int2n(-n),pp),pp); r = Flx_Fl_mul(A,l1,pp); } } return _mkFF(x,z,r); } GEN FF_inv(GEN x) { ulong pp; GEN r, T, p, z=_initFF(x,&T,&p,&pp); pari_sp av=avma; switch(x[1]) { case t_FF_FpXQ: r=gerepileupto(av,FpXQ_inv(gel(x,2),T,p)); break; case t_FF_F2xq: r=F2xq_inv(gel(x,2),T); break; default: r=Flxq_inv(gel(x,2),T,pp); } return _mkFF(x,z,r); } GEN FF_div(GEN x, GEN y) { ulong pp; GEN r, T, p, z=_initFF(x,&T,&p,&pp); pari_sp av=avma; _checkFF(x,y,"/"); switch(x[1]) { case t_FF_FpXQ: r=gerepileupto(av,FpXQ_div(gel(x,2),gel(y,2),T,p)); break; case t_FF_F2xq: r=gerepileupto(av,F2xq_div(gel(x,2),gel(y,2),T)); break; default: r=gerepileupto(av,Flxq_div(gel(x,2),gel(y,2),T,pp)); } return _mkFF(x,z,r); } GEN Z_FF_div(GEN n, GEN x) { ulong pp; GEN r, T, p, A = gel(x,2), z=_initFF(x,&T,&p,&pp); pari_sp av=avma; switch(x[1]) { case t_FF_FpXQ: r = gerepileupto(av,FpX_Fp_mul(FpXQ_inv(A,T,p),modii(n,p),p)); break; case t_FF_F2xq: r = F2xq_inv(A,T); /*Check for division by 0*/ if(!mpodd(n)) { avma = av; r = zero_Flx(A[1]); } break; default: r = gerepileupto(av, Flx_Fl_mul(Flxq_inv(A,T,pp),umodiu(n,pp),pp)); } return _mkFF(x,z,r); } GEN FF_sqrtn(GEN x, GEN n, GEN *zetan) { ulong pp; GEN r, T, p, y=_initFF(x,&T,&p,&pp); switch (x[1]) { case t_FF_FpXQ: r=FpXQ_sqrtn(gel(x,2),n,T,p,zetan); break; case t_FF_F2xq: r=F2xq_sqrtn(gel(x,2),n,T,zetan); break; default: r=Flxq_sqrtn(gel(x,2),n,T,pp,zetan); } if (!r) pari_err_SQRTN("FF_sqrtn",x); (void)_mkFF(x, y, r); if (zetan) { GEN z = cgetg(lg(y),t_FFELT); *zetan=_mkFF(x, z, *zetan); } return y; } GEN FF_sqrt(GEN x) { ulong pp; GEN r, T, p, y=_initFF(x,&T,&p,&pp); switch (x[1]) { case t_FF_FpXQ: r = FpXQ_sqrt(gel(x,2),T,p); break; case t_FF_F2xq: r = F2xq_sqrt(gel(x,2),T); break; default: r = Flxq_sqrt(gel(x,2),T,pp); } if (!r) pari_err_SQRTN("FF_sqrt",x); return _mkFF(x, y, r); } long FF_issquare(GEN x) { GEN T, p; ulong pp; _getFF(x, &T, &p, &pp); switch(x[1]) { case t_FF_FpXQ: return FpXQ_issquare(gel(x,2), T, p); case t_FF_F2xq: return 1; default: /* case t_FF_Flxq: */ return Flxq_issquare(gel(x,2), T, pp); } } long FF_issquareall(GEN x, GEN *pt) { if (!pt) return FF_issquare(x); return FF_ispower(x, gen_2, pt); } long FF_ispower(GEN x, GEN K, GEN *pt) { ulong pp; GEN r, T, p; pari_sp av = avma; if (FF_equal0(x)) { if (pt) *pt = gcopy(x); return 1; } _getFF(x, &T, &p, &pp); if (pt) *pt = cgetg(5,t_FFELT); switch(x[1]) { case t_FF_FpXQ: r = FpXQ_sqrtn(gel(x,2),K,T,p,NULL); break; case t_FF_F2xq: r = F2xq_sqrtn(gel(x,2),K,T,NULL); break; default: /* case t_FF_Flxq: */ r = Flxq_sqrtn(gel(x,2),K,T,pp,NULL); break; } if (!r) { avma = av; return 0; } if (pt) { (void)_mkFF(x,*pt,r); } return 1; } GEN FF_pow(GEN x, GEN n) { ulong pp; GEN r, T, p, z=_initFF(x,&T,&p,&pp); switch(x[1]) { case t_FF_FpXQ: r = FpXQ_pow(gel(x,2), n, T, p); break; case t_FF_F2xq: r = F2xq_pow(gel(x,2), n, T); break; default: r = Flxq_pow(gel(x,2), n, T, pp); } return _mkFF(x,z,r); } GEN FF_norm(GEN x) { ulong pp; GEN T,p; _getFF(x,&T,&p,&pp); switch (x[1]) { case t_FF_FpXQ: return FpXQ_norm(gel(x,2),T,p); case t_FF_F2xq: return lgpol(gel(x,2))?gen_1:gen_0; default: return utoi(Flxq_norm(gel(x,2),T,pp)); } } GEN FF_trace(GEN x) { ulong pp; GEN T,p; _getFF(x,&T,&p,&pp); switch(x[1]) { case t_FF_FpXQ: return FpXQ_trace(gel(x,2),T,p); case t_FF_F2xq: return F2xq_trace(gel(x,2),T)?gen_1:gen_0; default: return utoi(Flxq_trace(gel(x,2),T,pp)); } } GEN FF_conjvec(GEN x) { ulong pp; GEN r,T,p,v; long i,l; pari_sp av; _getFF(x,&T,&p,&pp); av = avma; switch(x[1]) { case t_FF_FpXQ: v = FpXQ_conjvec(gel(x,2), T, p); break; case t_FF_F2xq: v = F2xq_conjvec(gel(x,2), T); break; default: v = Flxq_conjvec(gel(x,2), T, pp); } l = lg(v); r = cgetg(l, t_COL); for(i=1; i0; i--) if (!Rg_is_FF(gel(x,i), ff)) return 0; return (*ff != NULL); } int RgM_is_FFM(GEN x, GEN *ff) { long j, lx = lg(x); for (j=lx-1; j>0; j--) if (!RgC_is_FFC(gel(x,j), ff)) return 0; return (*ff != NULL); } static GEN FqC_to_FpXQC(GEN x, GEN T, GEN p) { long i, lx; GEN y = cgetg_copy(x,&lx); for(i=1; i t_MAT */ static GEN FFM_wrap(GEN M, GEN ff, GEN (*Fq)(GEN,GEN,GEN), GEN (*Flxq)(GEN,GEN,ulong), GEN (*F2xq)(GEN,GEN)) { pari_sp av = avma; ulong pp; GEN T, p; _getFF(ff,&T,&p,&pp); M = FFM_to_raw(M, ff); switch(ff[1]) { case t_FF_FpXQ: M = Fq(M,T,p); if (M) M = FqM_to_FpXQM(M,T,p); break; case t_FF_F2xq: M = F2xq(M,T); break; default: M = Flxq(M,T,pp); break; } if (!M) { avma = av; return NULL; } return gerepilecopy(av, raw_to_FFM(M, ff)); } /* for functions (t_MAT, t_MAT) -> t_MAT */ static GEN FFM_FFM_wrap(GEN M, GEN N, GEN ff, GEN (*Fq)(GEN, GEN, GEN, GEN), GEN (*Flxq)(GEN, GEN, GEN, ulong), GEN (*F2xq)(GEN, GEN, GEN)) { pari_sp av = avma; ulong pp; GEN T, p; int is_sqr = M==N; _getFF(ff, &T, &p, &pp); M = FFM_to_raw(M, ff); N = is_sqr? M: FFM_to_raw(N, ff); switch(ff[1]) { case t_FF_FpXQ: M = Fq(M, N, T, p); if (M) M = FqM_to_FpXQM(M, T, p); break; case t_FF_F2xq: M = F2xq(M, N, T); break; default: M = Flxq(M, N, T, pp); break; } if (!M) { avma = av; return NULL; } return gerepilecopy(av, raw_to_FFM(M, ff)); } /* for functions (t_MAT, t_COL) -> t_COL */ static GEN FFM_FFC_wrap(GEN M, GEN C, GEN ff, GEN (*Fq)(GEN, GEN, GEN, GEN), GEN (*Flxq)(GEN, GEN, GEN, ulong), GEN (*F2xq)(GEN, GEN, GEN)) { pari_sp av = avma; ulong pp; GEN T, p; _getFF(ff, &T, &p, &pp); M = FFM_to_raw(M, ff); C = FFC_to_raw(C, ff); switch(ff[1]) { case t_FF_FpXQ: C = Fq(M, C, T, p); if (C) C = FqC_to_FpXQC(C, T, p); break; case t_FF_F2xq: C = F2xq(M, C, T); break; default: C = Flxq(M, C, T, pp); break; } if (!C) { avma = av; return NULL; } return gerepilecopy(av, raw_to_FFC(C, ff)); } GEN FFM_ker(GEN M, GEN ff) { return FFM_wrap(M,ff, &FqM_ker,&FlxqM_ker,&F2xqM_ker); } GEN FFM_image(GEN M, GEN ff) { return FFM_wrap(M,ff, &FqM_image,&FlxqM_image,&F2xqM_image); } GEN FFM_inv(GEN M, GEN ff) { return FFM_wrap(M,ff, &FqM_inv,&FlxqM_inv,&F2xqM_inv); } GEN FFM_suppl(GEN M, GEN ff) { return FFM_wrap(M,ff, &FqM_suppl,&FlxqM_suppl,&F2xqM_suppl); } GEN FFM_deplin(GEN M, GEN ff) { pari_sp av = avma; ulong pp; GEN C, T, p; _getFF(ff, &T, &p, &pp); M = FFM_to_raw(M, ff); switch(ff[1]) { case t_FF_FpXQ: C = FqM_deplin(M, T, p); if (C) C = FqC_to_FpXQC(C, T, p); break; case t_FF_F2xq: C = F2xqM_deplin(M, T); break; default: C = FlxqM_deplin(M, T, pp); break; } if (!C) { avma = av; return NULL; } return gerepilecopy(av, raw_to_FFC(C, ff)); } GEN FFM_indexrank(GEN M, GEN ff) { pari_sp av = avma; ulong pp; GEN R, T, p; _getFF(ff,&T,&p,&pp); M = FFM_to_raw(M, ff); switch(ff[1]) { case t_FF_FpXQ: R = FqM_indexrank(M,T,p); break; case t_FF_F2xq: R = F2xqM_indexrank(M,T); break; default: R = FlxqM_indexrank(M,T,pp); break; } return gerepileupto(av, R); } long FFM_rank(GEN M, GEN ff) { pari_sp av = avma; long r; ulong pp; GEN T, p; _getFF(ff,&T,&p,&pp); M = FFM_to_raw(M, ff); switch(ff[1]) { case t_FF_FpXQ: r = FqM_rank(M,T,p); break; case t_FF_F2xq: r = F2xqM_rank(M,T); break; default: r = FlxqM_rank(M,T,pp); break; } avma = av; return r; } GEN FFM_det(GEN M, GEN ff) { pari_sp av = avma; ulong pp; GEN d, T, p; _getFF(ff,&T,&p,&pp); M = FFM_to_raw(M, ff); switch(ff[1]) { case t_FF_FpXQ: d = FqM_det(M,T,p); break; case t_FF_F2xq: d = F2xqM_det(M,T); break; default: d = FlxqM_det(M,T,pp); break; } return gerepilecopy(av, mkFF_i(ff, d)); } GEN FFM_FFC_gauss(GEN M, GEN C, GEN ff) { return FFM_FFC_wrap(M, C, ff, FqM_FqC_gauss, FlxqM_FlxqC_gauss, F2xqM_F2xqC_gauss); } GEN FFM_gauss(GEN M, GEN N, GEN ff) { return FFM_FFM_wrap(M, N, ff, FqM_gauss, FlxqM_gauss, F2xqM_gauss); } GEN FFM_FFC_invimage(GEN M, GEN C, GEN ff) { return FFM_FFC_wrap(M, C, ff, FqM_FqC_invimage, FlxqM_FlxqC_invimage, F2xqM_F2xqC_invimage); } GEN FFM_invimage(GEN M, GEN N, GEN ff) { return FFM_FFM_wrap(M, N, ff, FqM_invimage, FlxqM_invimage, F2xqM_invimage); } GEN FFM_FFC_mul(GEN M, GEN C, GEN ff) { return FFM_FFC_wrap(M, C, ff, FqM_FqC_mul, FlxqM_FlxqC_mul, F2xqM_F2xqC_mul); } GEN FFM_mul(GEN M, GEN N, GEN ff) { return FFM_FFM_wrap(M, N, ff, FqM_mul, FlxqM_mul, F2xqM_mul); } pari-2.11.2/src/basemath/bb_group.c0000644000175000017500000007022313326135265015506 0ustar billbill/* Copyright (C) 2000-2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /***********************************************************************/ /** **/ /** GENERIC ALGORITHMS ON BLACKBOX GROUP **/ /** **/ /***********************************************************************/ #include "pari.h" #include "paripriv.h" #undef pow /* AIX: pow(a,b) is a macro, wrongly expanded on grp->pow(a,b,c) */ /***********************************************************************/ /** **/ /** POWERING **/ /** **/ /***********************************************************************/ /* return (n>>(i+1-l)) & ((1<=l) return (w>>(r-l))&((1UL<>= (BITS_IN_LONG-lr); return (w<=0) { if (e > l+1) e = l+1; w = (n>>(l+1-e)) & ((1UL<>(v+1))); if (z) { for (i=1; i<=e-v; i++) z = sqr(E, z); z = mul(E, z, tw); } else z = tw; for (i=1; i<=v; i++) z = sqr(E, z); while (l>=0) { if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"sliding_window_powu (%ld)", l); z = gerepilecopy(av, z); } if (n&(1UL<=0) { if (e > l+1) e = l+1; w = int_block(n,l,e); v = vals(w); l-=e; tw = gel(tab, 1+(w>>(v+1))); if (z) { for (i=1; i<=e-v; i++) z = sqr(E, z); z = mul(E, z, tw); } else z = tw; for (i=1; i<=v; i++) z = sqr(E, z); while (l>=0) { if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"sliding_window_pow (%ld)", l); z = gerepilecopy(av, z); } if (int_bit(n,l)) break; z = sqr(E, z); l--; } } return z; } /* assume n != 0, t_INT. Compute x^|n| using leftright binary powering */ static GEN leftright_binary_powu(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)) { pari_sp av = avma; GEN y; int j; if (n == 1) return x; y = x; j = 1+bfffo(n); /* normalize, i.e set highest bit to 1 (we know n != 0) */ n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */ for (; j; n<<=1,j--) { y = sqr(E,y); if (n & HIGHBIT) y = mul(E,y,x); /* first bit set: multiply by base */ if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"leftright_powu (%d)", j); y = gerepilecopy(av, y); } } return y; } GEN gen_powu_i(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)) { long l; if (n == 1) return x; l = expu(n); if (l<=8) return leftright_binary_powu(x, n, E, sqr, mul); else return sliding_window_powu(x, n, l<=24? 2: 3, E, sqr, mul); } GEN gen_powu(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)) { pari_sp av = avma; if (n == 1) return gcopy(x); return gerepilecopy(av, gen_powu_i(x,n,E,sqr,mul)); } GEN gen_pow_i(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)) { long l, e; if (lgefint(n)==3) return gen_powu_i(x, uel(n,2), E, sqr, mul); l = expi(n); if (l<=64) e = 3; else if (l<=160) e = 4; else if (l<=384) e = 5; else if (l<=896) e = 6; else e = 7; return sliding_window_pow(x, n, e, E, sqr, mul); } GEN gen_pow(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)) { pari_sp av = avma; return gerepilecopy(av, gen_pow_i(x,n,E,sqr,mul)); } /* assume n > 0. Compute x^n using left-right binary powering */ GEN gen_powu_fold_i(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)) { pari_sp av = avma; GEN y; int j; if (n == 1) return x; y = x; j = 1+bfffo(n); /* normalize, i.e set highest bit to 1 (we know n != 0) */ n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */ for (; j; n<<=1,j--) { if (n & HIGHBIT) y = msqr(E,y); /* first bit set: multiply by base */ else y = sqr(E,y); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"gen_powu_fold (%d)", j); y = gerepilecopy(av, y); } } return y; } GEN gen_powu_fold(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)) { pari_sp av = avma; if (n == 1) return gcopy(x); return gerepilecopy(av, gen_powu_fold_i(x,n,E,sqr,msqr)); } /* assume N != 0, t_INT. Compute x^|N| using left-right binary powering */ GEN gen_pow_fold_i(GEN x, GEN N, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)) { long ln = lgefint(N); if (ln == 3) return gen_powu_fold_i(x, N[2], E, sqr, msqr); else { GEN nd = int_MSW(N), y = x; ulong n = *nd; long i; int j; pari_sp av = avma; if (n == 1) j = 0; else { j = 1+bfffo(n); /* < BIL */ /* normalize, i.e set highest bit to 1 (we know n != 0) */ n <<= j; j = BITS_IN_LONG - j; } /* first bit is now implicit */ for (i=ln-2;;) { for (; j; n<<=1,j--) { if (n & HIGHBIT) y = msqr(E,y); /* first bit set: multiply by base */ else y = sqr(E,y); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"gen_pow_fold (%d)", j); y = gerepilecopy(av, y); } } if (--i == 0) return y; nd = int_precW(nd); n = *nd; j = BITS_IN_LONG; } } } GEN gen_pow_fold(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN), GEN (*msqr)(void*,GEN)) { pari_sp av = avma; return gerepilecopy(av, gen_pow_fold_i(x,n,E,sqr,msqr)); } GEN gen_pow_init(GEN x, GEN n, long k, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN)) { long i, j, l = expi(n); long m = 1UL<<(k-1); GEN x2 = sqr(E, x), y = gcopy(x); GEN R = cgetg(m+1, t_VEC); for(i = 1; i <= m; i++) { GEN C = cgetg(l+1, t_VEC); gel(C,1) = y; for(j = 2; j <= l; j++) gel(C,j) = sqr(E, gel(C,j-1)); gel(R,i) = C; y = mul(E, y, x2); } return R; } GEN gen_pow_table(GEN R, GEN n, void *E, GEN (*one)(void*), GEN (*mul)(void*,GEN,GEN)) { long e = expu(lg(R)-1) + 1; long l = expi(n); long i, w; GEN z = one(E), tw; for(i=0; i<=l; ) { if (int_bit(n, i)==0) { i++; continue; } if (i+e-1>l) e = l+1-i; w = int_block(n,i+e-1,e); tw = gmael(R, 1+(w>>1), i+1); z = mul(E, z, tw); i += e; } return z; } GEN gen_powers(GEN x, long l, int use_sqr, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN), GEN (*one)(void*)) { long i; GEN V = cgetg(l+2,t_VEC); gel(V,1) = one(E); if (l==0) return V; gel(V,2) = gcopy(x); if (l==1) return V; gel(V,3) = sqr(E,x); if (use_sqr) for(i = 4; i < l+2; i++) gel(V,i) = (i&1)? sqr(E,gel(V, (i+1)>>1)) : mul(E,gel(V, i-1),x); else for(i = 4; i < l+2; i++) gel(V,i) = mul(E,gel(V,i-1),x); return V; } GEN producttree_scheme(long n) { GEN v, w; long i, j, k, u, l; if (n<=2) return mkvecsmall(n); u = expu(n-1); v = cgetg(n+1,t_VECSMALL); w = cgetg(n+1,t_VECSMALL); v[1] = n; l = 1; for (i=1; i<=u; i++) { for(j=1, k=1; j<=l; j++, k+=2) { long vj = v[j], v2 = vj>>1; w[k] = vj-v2; w[k+1] = v2; } swap(v,w); l<<=1; } fixlg(v, l+1); avma = (pari_sp) v; return v; } GEN gen_product(GEN x, void *data, GEN (*mul)(void *,GEN,GEN)) { pari_sp ltop; long i,k,lx = lg(x),lv; pari_timer ti; GEN v; if (DEBUGLEVEL>7) timer_start(&ti); if (lx == 1) return gen_1; if (lx == 2) return gcopy(gel(x,1)); x = leafcopy(x); k = lx; v = producttree_scheme(lx-1); lv = lg(v); ltop = avma; for (k=1, i=1; k 2) { if (DEBUGLEVEL>7) timer_printf(&ti,"gen_product: remaining objects %ld",k-1); lx = k; k = 1; for (i=1; ihash(a))%3UL) { case 0: return mkvec3(grp->pow(E,a,gen_2),Fp_mulu(gel(A,2),2,q), Fp_mulu(gel(A,3),2,q)); case 1: return mkvec3(grp->mul(E,a,x),addis(gel(A,2),1),gel(A,3)); case 2: return mkvec3(grp->mul(E,a,g),gel(A,2),addiu(gel(A,3),1)); } return NULL; } /*Generic Pollard rho discrete log algorithm*/ static GEN gen_Pollard_log(GEN x, GEN g, GEN q, void *E, const struct bb_group *grp) { pari_sp av=avma; GEN A, B, l, sqrt4q = sqrti(shifti(q,4)); ulong i, h = 0, imax = itou_or_0(sqrt4q); if (!imax) imax = ULONG_MAX; do { rho_restart: A = B = mkvec3(x,gen_1,gen_0); i=0; do { if (i>imax) { h++; if (DEBUGLEVEL) pari_warn(warner,"changing Pollard rho hash seed to %ld",h); goto rho_restart; } A = iter_rho(x, g, q, A, h, E, grp); B = iter_rho(x, g, q, B, h, E, grp); B = iter_rho(x, g, q, B, h, E, grp); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_Pollard_log"); gerepileall(av, 2, &A, &B); } i++; } while (!grp->equal(gel(A,1), gel(B,1))); gel(A,2) = modii(gel(A,2), q); gel(B,2) = modii(gel(B,2), q); h++; } while (equalii(gel(A,2), gel(B,2))); l = Fp_div(Fp_sub(gel(B,3), gel(A,3),q),Fp_sub(gel(A,2), gel(B,2), q), q); return gerepileuptoint(av, l); } /* compute a hash of g^(i-1), 1<=i<=n. Return [sorted hash, perm, g^-n] */ GEN gen_Shanks_init(GEN g, long n, void *E, const struct bb_group *grp) { GEN p1 = g, G, perm, table = cgetg(n+1,t_VECSMALL); pari_sp av=avma; long i; table[1] = grp->hash(grp->pow(E,g,gen_0)); for (i=2; i<=n; i++) { table[i] = grp->hash(p1); p1 = grp->mul(E,p1,g); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, baby = %ld", i); p1 = gerepileupto(av, p1); } } G = gerepileupto(av, grp->pow(E,p1,gen_m1)); /* g^-n */ perm = vecsmall_indexsort(table); table = vecsmallpermute(table,perm); return mkvec4(table,perm,g,G); } /* T from gen_Shanks_init(g,n). Return v < n*N such that x = g^v or NULL */ GEN gen_Shanks(GEN T, GEN x, ulong N, void *E, const struct bb_group *grp) { pari_sp av=avma; GEN table = gel(T,1), perm = gel(T,2), g = gel(T,3), G = gel(T,4); GEN p1 = x; long n = lg(table)-1; ulong k; for (k=0; khash(p1), i = zv_search(table, h); if (i) { do i--; while (i && table[i] == h); for (i++; i <= n && table[i] == h; i++) { GEN v = addiu(muluu(n,k), perm[i]-1); if (grp->equal(grp->pow(E,g,v),x)) return gerepileuptoint(av,v); if (DEBUGLEVEL) err_printf("gen_Shanks_log: false positive %lu, %lu\n", k,h); } } p1 = grp->mul(E,p1,G); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, k = %lu", k); p1 = gerepileupto(av, p1); } } return NULL; } /* Generic Shanks baby-step/giant-step algorithm. Return log_g(x), ord g = q. * One-shot: use gen_Shanks_init/log if many logs are desired; early abort * if log < sqrt(q) */ static GEN gen_Shanks_log(GEN x, GEN g, GEN q, void *E, const struct bb_group *grp) { pari_sp av=avma, av1; long lbaby, i, k; GEN p1, table, giant, perm, ginv; p1 = sqrti(q); if (abscmpiu(p1,LGBITS) >= 0) pari_err_OVERFLOW("gen_Shanks_log [order too large]"); lbaby = itos(p1)+1; table = cgetg(lbaby+1,t_VECSMALL); ginv = grp->pow(E,g,gen_m1); av1 = avma; for (p1=x, i=1;;i++) { if (grp->equal1(p1)) { avma = av; return stoi(i-1); } table[i] = grp->hash(p1); if (i==lbaby) break; p1 = grp->mul(E,p1,ginv); if (gc_needed(av1,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, baby = %ld", i); p1 = gerepileupto(av1, p1); } } p1 = giant = gerepileupto(av1, grp->mul(E,x,grp->pow(E, p1, gen_m1))); perm = vecsmall_indexsort(table); table = vecsmallpermute(table,perm); av1 = avma; for (k=1; k<= lbaby; k++) { long h = grp->hash(p1), i = zv_search(table, h); if (i) { while (table[i] == h && i) i--; for (i++; i <= lbaby && table[i] == h; i++) { GEN v = addiu(mulss(lbaby-1,k),perm[i]-1); if (grp->equal(grp->pow(E,g,v),x)) return gerepileuptoint(av,v); if (DEBUGLEVEL) err_printf("gen_Shanks_log: false positive %ld, %lu\n", k,h); } } p1 = grp->mul(E,p1,giant); if (gc_needed(av1,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, k = %ld", k); p1 = gerepileupto(av1, p1); } } avma = av; return cgetg(1, t_VEC); /* no solution */ } /*Generic discrete logarithme in a group of prime order p*/ GEN gen_plog(GEN x, GEN g, GEN p, void *E, const struct bb_group *grp) { if (grp->easylog) { GEN e = grp->easylog(E, x, g, p); if (e) return e; } if (grp->equal1(x)) return gen_0; if (grp->equal(x,g)) return gen_1; if (expi(p)<32) return gen_Shanks_log(x,g,p,E,grp); return gen_Pollard_log(x, g, p, E, grp); } GEN get_arith_ZZM(GEN o) { if (!o) return NULL; switch(typ(o)) { case t_INT: if (signe(o) > 0) return mkvec2(o, Z_factor(o)); break; case t_MAT: if (is_Z_factorpos(o)) return mkvec2(factorback(o), o); break; case t_VEC: if (lg(o) == 3 && signe(gel(o,1)) > 0 && is_Z_factorpos(gel(o,2))) return o; break; } pari_err_TYPE("generic discrete logarithm (order factorization)",o); return NULL; /* LCOV_EXCL_LINE */ } GEN get_arith_Z(GEN o) { if (!o) return NULL; switch(typ(o)) { case t_INT: if (signe(o) > 0) return o; break; case t_MAT: o = factorback(o); if (typ(o) == t_INT && signe(o) > 0) return o; break; case t_VEC: if (lg(o) != 3) break; o = gel(o,1); if (typ(o) == t_INT && signe(o) > 0) return o; break; } pari_err_TYPE("generic discrete logarithm (order factorization)",o); return NULL; /* LCOV_EXCL_LINE */ } /* grp->easylog() is an optional trapdoor function that catch easy logarithms*/ /* Generic Pohlig-Hellman discrete logarithm*/ /* smallest integer n such that g^n=a. Assume g has order ord */ GEN gen_PH_log(GEN a, GEN g, GEN ord, void *E, const struct bb_group *grp) { pari_sp av = avma; GEN v,t0,a0,b,q,g_q,n_q,ginv0,qj,ginv; GEN fa, ex; long e,i,j,l; if (grp->equal(g, a)) /* frequent special case */ return grp->equal1(g)? gen_0: gen_1; if (grp->easylog) { GEN e = grp->easylog(E, a, g, ord); if (e) return e; } v = get_arith_ZZM(ord); ord= gel(v,1); fa = gel(v,2); ex = gel(fa,2); fa = gel(fa,1); l = lg(fa); ginv = grp->pow(E,g,gen_m1); v = cgetg(l, t_VEC); for (i=1; i5) err_printf("Pohlig-Hellman: DL mod %Ps^%ld\n",q,e); qj = new_chunk(e+1); gel(qj,0) = gen_1; gel(qj,1) = q; for (j=2; j<=e; j++) gel(qj,j) = mulii(gel(qj,j-1), q); t0 = diviiexact(ord, gel(qj,e)); a0 = grp->pow(E, a, t0); ginv0 = grp->pow(E, ginv, t0); /* order q^e */ if (grp->equal1(ginv0)) { gel(v,i) = mkintmod(gen_0, gen_1); continue; } do { g_q = grp->pow(E,g, mulii(t0, gel(qj,--e))); /* order q */ } while (grp->equal1(g_q)); n_q = gen_0; for (j=0;; j++) { /* n_q = sum_{ipow(E,a0, gel(qj,e-j)); /* early abort: cheap and very effective */ if (j == 0 && !grp->equal1(grp->pow(E,b,q))) { avma = av; return cgetg(1, t_VEC); } b = gen_plog(b, g_q, q, E, grp); if (typ(b) != t_INT) { avma = av; return cgetg(1, t_VEC); } n_q = addii(n_q, mulii(b, gel(qj,j))); if (j == e) break; a0 = grp->mul(E,a0, grp->pow(E,ginv0, b)); ginv0 = grp->pow(E,ginv0, q); } gel(v,i) = mkintmod(n_q, gel(qj,e+1)); } return gerepileuptoint(av, lift(chinese1_coprime_Z(v))); } /***********************************************************************/ /** **/ /** ORDER OF AN ELEMENT **/ /** **/ /***********************************************************************/ /*Find the exact order of a assuming a^o==1*/ GEN gen_order(GEN a, GEN o, void *E, const struct bb_group *grp) { pari_sp av = avma; long i, l; GEN m; m = get_arith_ZZM(o); if (!m) pari_err_TYPE("gen_order [missing order]",a); o = gel(m,1); m = gel(m,2); l = lgcols(m); for (i = l-1; i; i--) { GEN t, y, p = gcoeff(m,i,1); long j, e = itos(gcoeff(m,i,2)); if (l == 2) { t = gen_1; y = a; } else { t = diviiexact(o, powiu(p,e)); y = grp->pow(E, a, t); } if (grp->equal1(y)) o = t; else { for (j = 1; j < e; j++) { y = grp->pow(E, y, p); if (grp->equal1(y)) break; } if (j < e) { if (j > 1) p = powiu(p, j); o = mulii(t, p); } } } return gerepilecopy(av, o); } /*Find the exact order of a assuming a^o==1, return [order,factor(order)] */ GEN gen_factored_order(GEN a, GEN o, void *E, const struct bb_group *grp) { pari_sp av = avma; long i, l, ind; GEN m, F, P; m = get_arith_ZZM(o); if (!m) pari_err_TYPE("gen_factored_order [missing order]",a); o = gel(m,1); m = gel(m,2); l = lgcols(m); P = cgetg(l, t_COL); ind = 1; F = cgetg(l, t_COL); for (i = l-1; i; i--) { GEN t, y, p = gcoeff(m,i,1); long j, e = itos(gcoeff(m,i,2)); if (l == 2) { t = gen_1; y = a; } else { t = diviiexact(o, powiu(p,e)); y = grp->pow(E, a, t); } if (grp->equal1(y)) o = t; else { for (j = 1; j < e; j++) { y = grp->pow(E, y, p); if (grp->equal1(y)) break; } gel(P,ind) = p; gel(F,ind) = utoipos(j); if (j < e) { if (j > 1) p = powiu(p, j); o = mulii(t, p); } ind++; } } setlg(P, ind); P = vecreverse(P); setlg(F, ind); F = vecreverse(F); return gerepilecopy(av, mkvec2(o, mkmat2(P,F))); } /* E has order o[1], ..., or o[#o], draw random points until all solutions * but one are eliminated */ GEN gen_select_order(GEN o, void *E, const struct bb_group *grp) { pari_sp ltop = avma, btop; GEN lastgood, so, vo; long lo = lg(o), nbo=lo-1; if (nbo == 1) return icopy(gel(o,1)); so = ZV_indexsort(o); /* minimize max( o[i+1] - o[i] ) */ vo = zero_zv(lo); lastgood = gel(o, so[nbo]); btop = avma; for(;;) { GEN lasto = gen_0; GEN P = grp->rand(E), t = mkvec(gen_0); long i; for (i = 1; i < lo; i++) { GEN newo = gel(o, so[i]); if (vo[i]) continue; t = grp->mul(E,t, grp->pow(E, P, subii(newo,lasto)));/*P^o[i]*/ lasto = newo; if (!grp->equal1(t)) { if (--nbo == 1) { avma=ltop; return icopy(lastgood); } vo[i] = 1; } else lastgood = lasto; } avma = btop; } } /*******************************************************************/ /* */ /* n-th ROOT */ /* */ /*******************************************************************/ /* Assume l is prime. Return a generator of the l-th Sylow and set *zeta to an element * of order l. * * q = l^e*r, e>=1, (r,l)=1 * UNCLEAN */ static GEN gen_lgener(GEN l, long e, GEN r,GEN *zeta, void *E, const struct bb_group *grp) { const pari_sp av1 = avma; GEN m, m1; long i; for (;; avma = av1) { m1 = m = grp->pow(E, grp->rand(E), r); if (grp->equal1(m)) continue; for (i=1; ipow(E,m,l); if (grp->equal1(m)) break; } if (i==e) break; } *zeta = m; return m1; } /* Let G be a cyclic group of order o>1. Returns a (random) generator */ GEN gen_gener(GEN o, void *E, const struct bb_group *grp) { pari_sp ltop = avma, av; long i, lpr; GEN F, N, pr, z=NULL; F = get_arith_ZZM(o); N = gel(F,1); pr = gel(F,2); lpr = lgcols(pr); av = avma; for (i = 1; i < lpr; i++) { GEN l = gcoeff(pr,i,1); long e = itos(gcoeff(pr,i,2)); GEN r = diviiexact(N,powis(l,e)); GEN zetan, zl = gen_lgener(l,e,r,&zetan,E,grp); z = i==1 ? zl: grp->mul(E,z,zl); if (gc_needed(av,2)) { /* n can have lots of prime factors*/ if(DEBUGMEM>1) pari_warn(warnmem,"gen_gener"); z = gerepileupto(av, z); } } return gerepileupto(ltop, z); } /* solve x^l = a , l prime in G of order q. * * q = (l^e)*r, e >= 1, (r,l) = 1 * y is not an l-th power, hence generates the l-Sylow of G * m = y^(q/l) != 1 */ static GEN gen_Shanks_sqrtl(GEN a, GEN l, long e, GEN r, GEN y, GEN m,void *E, const struct bb_group *grp) { pari_sp av = avma; long k; GEN p1, u1, u2, v, w, z, dl; (void)bezout(r,l,&u1,&u2); v = grp->pow(E,a,u2); w = grp->pow(E,v,l); w = grp->mul(E,w,grp->pow(E,a,gen_m1)); while (!grp->equal1(w)) { k = 0; p1 = w; do { z = p1; p1 = grp->pow(E,p1,l); k++; } while(!grp->equal1(p1)); if (k==e) { avma = av; return NULL; } dl = gen_plog(z,m,l,E,grp); if (typ(dl) != t_INT) { avma = av; return NULL; } dl = negi(dl); p1 = grp->pow(E, grp->pow(E,y, dl), powiu(l,e-k-1)); m = grp->pow(E,m,dl); e = k; v = grp->mul(E,p1,v); y = grp->pow(E,p1,l); w = grp->mul(E,y,w); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_sqrtl"); gerepileall(av,4, &y,&v,&w,&m); } } return gerepilecopy(av, v); } /* Return one solution of x^n = a in a cyclic group of order q * * 1) If there is no solution, return NULL. * * 2) If there is a solution, there are exactly m of them [m = gcd(q-1,n)]. * If zetan!=NULL, *zetan is set to a primitive m-th root of unity so that * the set of solutions is { x*zetan^k; k=0..m-1 } */ GEN gen_Shanks_sqrtn(GEN a, GEN n, GEN q, GEN *zetan, void *E, const struct bb_group *grp) { pari_sp ltop = avma; GEN m, u1, u2, z; int is_1; if (is_pm1(n)) { if (zetan) *zetan = grp->pow(E,a,gen_0); return signe(n) < 0? grp->pow(E,a,gen_m1): gcopy(a); } is_1 = grp->equal1(a); if (is_1 && !zetan) return gcopy(a); m = bezout(n,q,&u1,&u2); z = grp->pow(E,a,gen_0); if (!is_pm1(m)) { GEN F = Z_factor(m); long i, j, e; GEN r, zeta, y, l; pari_sp av1 = avma; for (i = nbrows(F); i; i--) { l = gcoeff(F,i,1); j = itos(gcoeff(F,i,2)); e = Z_pvalrem(q,l,&r); y = gen_lgener(l,e,r,&zeta,E,grp); if (zetan) z = grp->mul(E,z, grp->pow(E,y,powiu(l,e-j))); if (!is_1) { do { a = gen_Shanks_sqrtl(a,l,e,r,y,zeta,E,grp); if (!a) { avma = ltop; return NULL;} } while (--j); } if (gc_needed(ltop,1)) { /* n can have lots of prime factors*/ if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_sqrtn"); gerepileall(av1, zetan? 2: 1, &a, &z); } } } if (!equalii(m, n)) a = grp->pow(E,a,modii(u1,q)); if (zetan) { *zetan = z; gerepileall(ltop,2,&a,zetan); } else /* is_1 is 0: a was modified above -> gerepileupto valid */ a = gerepileupto(ltop, a); return a; } /*******************************************************************/ /* */ /* structure of groups with pairing */ /* */ /*******************************************************************/ static GEN ellgroup_d2(GEN N, GEN d) { GEN r = gcdii(N, d); GEN F1 = gel(Z_factor(r), 1); long i, j, l1 = lg(F1); GEN F = cgetg(3, t_MAT); gel(F,1) = cgetg(l1, t_COL); gel(F,2) = cgetg(l1, t_COL); for (i = 1, j = 1; i < l1; ++i) { long v = Z_pval(N, gel(F1, i)); if (v<=1) continue; gcoeff(F, j , 1) = gel(F1, i); gcoeff(F, j++, 2) = stoi(v); } setlg(F[1],j); setlg(F[2],j); return j==1 ? NULL : mkvec2(factorback(F), F); } GEN gen_ellgroup(GEN N, GEN d, GEN *pt_m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)) { pari_sp av = avma; GEN N0, N1, F; if (pt_m) *pt_m = gen_1; if (is_pm1(N)) return cgetg(1,t_VEC); F = ellgroup_d2(N, d); if (!F) {avma = av; return mkveccopy(N);} N0 = gel(F,1); N1 = diviiexact(N, N0); while(1) { pari_sp av2 = avma; GEN P, Q, d, s, t, m; P = grp->pow(E,grp->rand(E), N1); s = gen_order(P, F, E, grp); if (equalii(s, N0)) {avma = av; return mkveccopy(N);} Q = grp->pow(E,grp->rand(E), N1); t = gen_order(Q, F, E, grp); if (equalii(t, N0)) {avma = av; return mkveccopy(N);} m = lcmii(s, t); d = pairorder(E, P, Q, m, F); /* structure is [N/d, d] iff m d == N0. Note that N/d = N1 m */ if (is_pm1(d) && equalii(m, N0)) {avma = av; return mkveccopy(N);} if (equalii(mulii(m, d), N0)) { GEN g = mkvec2(mulii(N1,m), d); if (pt_m) *pt_m = m; gerepileall(av,pt_m?2:1,&g,pt_m); return g; } avma = av2; } } GEN gen_ellgens(GEN D1, GEN d2, GEN m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)) { pari_sp ltop = avma, av; GEN F, d1, dm; GEN P, Q, d, s; F = get_arith_ZZM(D1); d1 = gel(F, 1), dm = diviiexact(d1,m); av = avma; do { avma = av; P = grp->rand(E); s = gen_order(P, F, E, grp); } while (!equalii(s, d1)); av = avma; do { avma = av; Q = grp->rand(E); d = pairorder(E, grp->pow(E, P, dm), grp->pow(E, Q, dm), m, F); } while (!equalii(d, d2)); return gerepilecopy(ltop, mkvec2(P,Q)); } pari-2.11.2/src/basemath/buch3.c0000644000175000017500000022607113326135265014717 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* RAY CLASS FIELDS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" static GEN bnr_get_El(GEN bnr) { return gel(bnr,3); } static GEN bnr_get_U(GEN bnr) { return gel(bnr,4); } static GEN bnr_get_Ui(GEN bnr) { return gmael(bnr,4,3); } /* faster than Buchray */ GEN bnfnarrow(GEN bnf) { GEN nf, cyc, gen, Cyc, Gen, A, GD, v, w, H, invpi, logs, R, u, U0, Uoo, archp, sarch; long r1, j, l, t, RU; pari_sp av; bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); r1 = nf_get_r1(nf); if (!r1) return gcopy( bnf_get_clgp(bnf) ); /* simplified version of nfsign_units; r1 > 0 so bnf.tu = -1 */ av = avma; archp = identity_perm(r1); A = bnf_get_logfu(bnf); RU = lg(A)+1; invpi = invr( mppi(nf_get_prec(nf)) ); v = cgetg(RU,t_MAT); gel(v, 1) = const_vecsmall(r1, 1); /* nfsign(-1) */ for (j=2; j 1 */ GEN basecl = cgetg(l,t_VEC), G; G = mkvec2(NULL, trivial_fact()); for (j = 1; j < l; j++) { GEN z = NULL; for (i = 1; i < h; i++) { GEN g, e = gcoeff(U,i,j); if (!signe(e)) continue; g = gel(gen,i); if (typ(g) != t_MAT) { if (z) gel(z,2) = famat_mulpow_shallow(gel(z,2), g, e); else z = mkvec2(NULL, to_famat_shallow(g, e)); continue; } gel(G,1) = g; g = idealpowred(nf,G,e); z = z? idealmulred(nf,z,g): g; } gel(z,2) = famat_reduce(gel(z,2)); gel(basecl,j) = z; } return basecl; } static int too_big(GEN nf, GEN bet) { GEN x = nfnorm(nf,bet); switch (typ(x)) { case t_INT: return abscmpii(x, gen_1); case t_FRAC: return abscmpii(gel(x,1), gel(x,2)); } pari_err_BUG("wrong type in too_big"); return 0; /* LCOV_EXCL_LINE */ } /* true nf; GTM 193: Algo 4.3.4. Reduce x mod divisor */ static GEN idealmoddivisor_aux(GEN nf, GEN x, GEN f, GEN sarch) { pari_sp av = avma; GEN a, A; if ( is_pm1(gcoeff(f,1,1)) ) /* f = 1 */ { A = idealred(nf, mkvec2(x, gen_1)); A = nfinv(nf, gel(A,2)); } else {/* given coprime integral ideals x and f (f HNF), compute "small" * G in x, such that G = 1 mod (f). GTM 193: Algo 4.3.3 */ GEN G = idealaddtoone_raw(nf, x, f); GEN D = idealaddtoone_i(nf, idealdiv(nf,G,x), f); A = nfdiv(nf,D,G); } if (too_big(nf,A) > 0) { avma = av; return x; } a = set_sign_mod_divisor(nf, NULL, A, sarch); if (a != A && too_big(nf,A) > 0) { avma = av; return x; } return idealmul(nf, a, x); } GEN idealmoddivisor(GEN bnr, GEN x) { GEN nf = bnr_get_nf(bnr), bid = bnr_get_bid(bnr); return idealmoddivisor_aux(nf, x, bid_get_ideal(bid), bid_get_sarch(bid)); } /* v_pr(L0 * cx) */ static long fast_val(GEN L0, GEN cx, GEN pr) { pari_sp av = avma; long v = typ(L0) == t_INT? 0: ZC_nfval(L0,pr); if (cx) { long w = Q_pval(cx, pr_get_p(pr)); if (w) v += w * pr_get_e(pr); } avma = av; return v; } /* x coprime to fZ, return y = x mod fZ, y integral */ static GEN make_integral_Z(GEN x, GEN fZ) { GEN d, y = Q_remove_denom(x, &d); if (d) y = FpC_Fp_mul(y, Fp_inv(d, fZ), fZ); return y; } /* p pi^(-1) mod f */ static GEN get_pinvpi(GEN nf, GEN fZ, GEN p, GEN pi, GEN *v) { if (!*v) { GEN invpi = nfinv(nf, pi); *v = make_integral_Z(RgC_Rg_mul(invpi, p), mulii(p, fZ)); } return *v; } /* uniformizer pi for pr, coprime to F/p */ static GEN get_pi(GEN F, GEN pr, GEN *v) { if (!*v) *v = pr_uniformizer(pr, F); return *v; } /* true nf */ static GEN bnr_grp(GEN nf, GEN U, GEN gen, GEN cyc, GEN bid) { GEN h = ZV_prod(cyc); GEN f, fZ, basecl, fa, pr, t, EX, sarch, F, P, vecpi, vecpinvpi; long i,j,l,lp; if (!U) return mkvec2(h, cyc); if (lg(U) == 1) return mkvec3(h, cyc, cgetg(1, t_VEC)); /* basecl = generators in factored form */ basecl = compute_fact(nf, U, gen); EX = gel(bid_get_cyc(bid),1); /* exponent of (O/f)^* */ f = bid_get_ideal(bid); fZ = gcoeff(f,1,1); fa = bid_get_fact(bid); sarch = bid_get_sarch(bid); P = gel(fa,1); F = prV_lcm_capZ(P); lp = lg(P); vecpinvpi = cgetg(lp, t_VEC); vecpi = cgetg(lp, t_VEC); for (i=1; i 0) { pinvpi = get_pinvpi(nf, fZ, p, pi, &gel(vecpinvpi,j)); t = nfpow_u(nf,pinvpi, (ulong)v); LL = nfmul(nf, LL, t); LL = gdiv(LL, powiu(p, v)); } else { t = nfpow_u(nf,pi,(ulong)(-v)); LL = nfmul(nf, LL, t); } } LL = make_integral(nf,LL,f,P); gel(newL,k) = typ(LL) == t_INT? LL: FpC_red(LL, fZ); } av = avma; /* G in nf, = L^e mod f */ G = famat_to_nf_modideal_coprime(nf, newL, e, f, EX); if (mulI) { G = nfmuli(nf, G, mulI); G = typ(G) == t_COL? ZC_hnfrem(G, ZM_Z_mul(f, dmulI)) : modii(G, mulii(fZ,dmulI)); G = RgC_Rg_div(G, dmulI); } G = set_sign_mod_divisor(nf,A,G,sarch); I = idealmul(nf,I,G); /* more or less useless, but cheap at this point */ I = idealmoddivisor_aux(nf,I,f,sarch); gel(basecl,i) = gerepilecopy(av, I); } return mkvec3(h, cyc, basecl); } /********************************************************************/ /** **/ /** INIT RAY CLASS GROUP **/ /** **/ /********************************************************************/ static GEN check_subgroup(GEN bnr, GEN H, GEN *clhray) { GEN cyc = bnr_get_cyc(bnr); *clhray = bnr_get_no(bnr); if (H && isintzero(H)) H = NULL; if (H) switch(typ(H)) { case t_MAT: RgM_check_ZM(H, "check_subgroup"); H = ZM_hnfmodid(H, cyc); break; case t_VEC: if (char_check(cyc, H)) { H = charker(cyc, H); break; } default: pari_err_TYPE("check_subgroup", H); } if (H) { GEN h = ZM_det_triangular(H); if (equalii(h, *clhray)) H = NULL; else *clhray = h; } return H; } static GEN get_dataunit(GEN bnf, GEN bid) { GEN D = nfsign_units(bnf, bid_get_archp(bid), 1); return ideallog_sgn(bnf_get_nf(bnf), bnf_build_units(bnf), D, bid); } /* c a rational content (NULL or t_INT or t_FRAC), return u*c as a ZM/d */ static GEN ZM_content_mul(GEN u, GEN c, GEN *pd) { *pd = gen_1; if (c) { if (typ(c) == t_FRAC) { *pd = gel(c,2); c = gel(c,1); } if (!is_pm1(c)) u = ZM_Z_mul(u, c); } return u; } static GEN Buchray_i(GEN bnf, GEN module, long flag) { GEN nf, cyc, gen, Cyc, Gen, clg, h, logU, U, Ui, vu; GEN bid, cycbid, genbid, H, El; long RU, Ri, j, ngen; const long add_gen = flag & nf_GEN; const long do_init = flag & nf_INIT; bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); RU = lg(nf_get_roots(nf))-1; /* #K.futu */ El = Gen = NULL; /* gcc -Wall */ cyc = bnf_get_cyc(bnf); gen = bnf_get_gen(bnf); ngen = lg(cyc)-1; bid = checkbid_i(module); if (!bid) bid = Idealstar(nf,module,nf_GEN|nf_INIT); cycbid = bid_get_cyc(bid); genbid = bid_get_gen(bid); Ri = lg(cycbid)-1; if (Ri || add_gen || do_init) { GEN fx = bid_get_fact(bid); El = cgetg(ngen+1,t_VEC); for (j=1; j<=ngen; j++) { GEN c = idealcoprimefact(nf, gel(gen,j), fx); gel(El,j) = nf_to_scalar_or_basis(nf,c); } } if (add_gen) { Gen = cgetg(ngen+1,t_VEC); for (j=1; j<=ngen; j++) gel(Gen,j) = idealmul(nf, gel(El,j), gel(gen,j)); Gen = shallowconcat(Gen, genbid); } if (!Ri) { clg = mkvecn(add_gen? 3: 2, bnf_get_no(bnf), cyc, Gen); if (!do_init) return clg; U = matid(ngen); U = mkvec3(U, cgetg(1,t_MAT), U); vu = mkvec3(cgetg(1,t_MAT), matid(RU), gen_1); return mkvecn(6, bnf, bid, El, U, clg, vu); } logU = get_dataunit(bnf, bid); if (do_init) { /* (log(Units)|D) * u = (0 | H) */ GEN c1,c2, u,u1,u2, Hi, D = shallowconcat(logU, diagonal_shallow(cycbid)); H = ZM_hnfall_i(D, &u, 1); u1 = matslice(u, 1,RU, 1,RU); u2 = matslice(u, 1,RU, RU+1,lg(u)-1); /* log(Units) (u1|u2) = (0|H) (mod D), H HNF */ u1 = ZM_lll(u1, 0.99, LLL_INPLACE); Hi = Q_primitive_part(RgM_inv_upper(H), &c1); u2 = ZM_mul(ZM_reducemodmatrix(u2,u1), Hi); u2 = Q_primitive_part(u2, &c2); u2 = ZM_content_mul(u2, mul_content(c1,c2), &c2); vu = mkvec3(u2,u1,c2); /* u2/c2 = H^(-1) (mod Im u1) */ } else { H = ZM_hnfmodid(logU, cycbid); vu = NULL; /* -Wall */ } if (!ngen) h = H; else { GEN logs = cgetg(ngen+1, t_MAT); GEN cycgen = bnf_build_cycgen(bnf); for (j=1; j<=ngen; j++) { GEN c = gel(cycgen,j); if (typ(gel(El,j)) != t_INT) /* <==> != 1 */ c = famat_mulpow_shallow(c, gel(El,j),gel(cyc,j)); gel(logs,j) = ideallog(nf, c, bid); /* = log(Gen[j]^cyc[j]) */ } /* [ cyc 0 ] * [-logs H ] = relation matrix for generators Gen of Cl_f */ h = shallowconcat(vconcat(diagonal_shallow(cyc), gneg_i(logs)), vconcat(zeromat(ngen, Ri), H)); h = ZM_hnf(h); } Cyc = ZM_snf_group(h, &U, &Ui); /* Gen = clg.gen*U, clg.gen = Gen*Ui */ clg = bnr_grp(nf, add_gen? Ui: NULL, Gen, Cyc, bid); if (!do_init) return clg; U = mkvec3(vecslice(U, 1,ngen), vecslice(U,ngen+1,lg(U)-1), Ui); return mkvecn(6, bnf, bid, El, U, clg, vu); } GEN Buchray(GEN bnf, GEN f, long flag) { pari_sp av = avma; return gerepilecopy(av, Buchray_i(bnf, f, flag)); } GEN bnrinit0(GEN bnf, GEN ideal, long flag) { switch(flag) { case 0: flag = nf_INIT; break; case 1: flag = nf_INIT | nf_GEN; break; default: pari_err_FLAG("bnrinit"); } return Buchray(bnf,ideal,flag); } GEN bnrclassno(GEN bnf,GEN ideal) { GEN h, D, bid, cycbid; pari_sp av = avma; bnf = checkbnf(bnf); h = bnf_get_no(bnf); bid = checkbid_i(ideal); if (!bid) bid = Idealstar(bnf, ideal, nf_INIT); cycbid = bid_get_cyc(bid); if (lg(cycbid) == 1) { avma = av; return icopy(h); } D = get_dataunit(bnf, bid); /* (Z_K/f)^* / units ~ Z^n / D */ D = ZM_hnfmodid(D,cycbid); return gerepileuptoint(av, mulii(h, ZM_det_triangular(D))); } GEN bnrclassno0(GEN A, GEN B, GEN C) { pari_sp av = avma; GEN h, H = NULL; /* adapted from ABC_to_bnr, avoid costly bnrinit if possible */ if (typ(A) == t_VEC) switch(lg(A)) { case 7: /* bnr */ checkbnr(A); H = B; break; case 11: /* bnf */ if (!B) pari_err_TYPE("bnrclassno [bnf+missing conductor]",A); if (!C) return bnrclassno(A, B); A = Buchray(A, B, nf_INIT); H = C; break; default: checkbnf(A);/*error*/ } else checkbnf(A);/*error*/ H = check_subgroup(A, H, &h); if (!H) { avma = av; return icopy(h); } return gerepileuptoint(av, h); } /* ZMV_ZCV_mul for two matrices U = [Ux,Uy], it may have more components * (ignored) and vectors x,y */ static GEN ZM2_ZC2_mul(GEN U, GEN x, GEN y) { GEN Ux = gel(U,1), Uy = gel(U,2); if (lg(Ux) == 1) return ZM_ZC_mul(Uy,y); if (lg(Uy) == 1) return ZM_ZC_mul(Ux,x); return ZC_add(ZM_ZC_mul(Ux,x), ZM_ZC_mul(Uy,y)); } GEN bnrisprincipal(GEN bnr, GEN x, long flag) { pari_sp av = avma; GEN bnf, nf, bid, L, ex, cycray, alpha; checkbnr(bnr); cycray = bnr_get_cyc(bnr); if (lg(cycray) == 1 && !(flag & nf_GEN)) return cgetg(1,t_COL); bnf = bnr_get_bnf(bnr); nf = bnf_get_nf(bnf); bid = bnr_get_bid(bnr); if (lg(bid_get_cyc(bid)) == 1) bid = NULL; /* trivial bid */ if (!bid) ex = isprincipal(bnf, x); else { GEN El = bnr_get_El(bnr); GEN idep = bnfisprincipal0(bnf, x, nf_FORCE|nf_GENMAT); GEN ep = gel(idep,1), beta = gel(idep,2); long i, j = lg(ep); for (i = 1; i < j; i++) /* modify beta as if bnf.gen were El*bnr.gen */ if (typ(gel(El,i)) != t_INT && signe(gel(ep,i))) /* <==> != 1 */ beta = famat_mulpow_shallow(beta, gel(El,i), negi(gel(ep,i))); ex = ZM2_ZC2_mul(bnr_get_U(bnr), ep, ideallog(nf,beta,bid)); ex = vecmodii(ex, cycray); } if (!(flag & nf_GEN)) return gerepileupto(av, ex); /* compute generator */ L = isprincipalfact(bnf, x, bnr_get_gen(bnr), ZC_neg(ex), nf_GENMAT|nf_GEN_IF_PRINCIPAL|nf_FORCE); if (L == gen_0) pari_err_BUG("isprincipalray"); alpha = nffactorback(nf, L, NULL); if (bid) { GEN v = gel(bnr,6), u2 = gel(v,1), u1 = gel(v,2), du2 = gel(v,3); GEN y = ZM_ZC_mul(u2, ideallog(nf, L, bid)); if (!is_pm1(du2)) y = ZC_Z_divexact(y,du2); y = ZC_reducemodmatrix(y, u1); if (!ZV_equal0(y)) { GEN U = bnf_build_units(bnf); alpha = nfdiv(nf, alpha, nffactorback(nf, U, y)); } } return gerepilecopy(av, mkvec2(ex,alpha)); } GEN isprincipalray(GEN bnr, GEN x) { return bnrisprincipal(bnr,x,0); } GEN isprincipalraygen(GEN bnr, GEN x) { return bnrisprincipal(bnr,x,nf_GEN); } /* N! / N^N * (4/pi)^r2 * sqrt(|D|) */ GEN minkowski_bound(GEN D, long N, long r2, long prec) { pari_sp av = avma; GEN c = divri(mpfactr(N,prec), powuu(N,N)); if (r2) c = mulrr(c, powru(divur(4,mppi(prec)), r2)); c = mulrr(c, gsqrt(absi_shallow(D),prec)); return gerepileuptoleaf(av, c); } /* N = [K:Q] > 1, D = disc(K) */ static GEN zimmertbound(GEN D, long N, long R2) { pari_sp av = avma; GEN w; if (N > 20) w = minkowski_bound(D, N, R2, DEFAULTPREC); else { const double c[19][11] = { {/*2*/ 0.6931, 0.45158}, {/*3*/ 1.71733859, 1.37420604}, {/*4*/ 2.91799837, 2.50091538, 2.11943331}, {/*5*/ 4.22701425, 3.75471588, 3.31196660}, {/*6*/ 5.61209925, 5.09730381, 4.60693851, 4.14303665}, {/*7*/ 7.05406203, 6.50550021, 5.97735406, 5.47145968}, {/*8*/ 8.54052636, 7.96438858, 7.40555445, 6.86558259, 6.34608077}, {/*9*/ 10.0630022, 9.46382812, 8.87952524, 8.31139202, 7.76081149}, {/*10*/11.6153797, 10.9966020, 10.3907654, 9.79895170, 9.22232770, 8.66213267}, {/*11*/13.1930961, 12.5573772, 11.9330458, 11.3210061, 10.7222412, 10.1378082}, {/*12*/14.7926394, 14.1420915, 13.5016616, 12.8721114, 12.2542699, 11.6490374, 11.0573775}, {/*13*/16.4112395, 15.7475710, 15.0929680, 14.4480777, 13.8136054, 13.1903162, 12.5790381}, {/*14*/18.0466672, 17.3712806, 16.7040780, 16.0456127, 15.3964878, 14.7573587, 14.1289364, 13.5119848}, {/*15*/19.6970961, 19.0111606, 18.3326615, 17.6620757, 16.9999233, 16.3467686, 15.7032228, 15.0699480}, {/*16*/21.3610081, 20.6655103, 19.9768082, 19.2953176, 18.6214885, 17.9558093, 17.2988108, 16.6510652, 16.0131906}, {/*17*/23.0371259, 22.3329066, 21.6349299, 20.9435607, 20.2591899, 19.5822454, 18.9131878, 18.2525157, 17.6007672}, {/*18*/24.7243611, 24.0121449, 23.3056902, 22.6053167, 21.9113705, 21.2242247, 20.5442836, 19.8719830, 19.2077941, 18.5522234}, {/*19*/26.4217792, 25.7021950, 24.9879497, 24.2793271, 23.5766321, 22.8801952, 22.1903709, 21.5075437, 20.8321263, 20.1645647}, {/*20*/28.1285704, 27.4021674, 26.6807314, 25.9645140, 25.2537867, 24.5488420, 23.8499943, 23.1575823, 22.4719720, 21.7935548, 21.1227537} }; w = mulrr(dbltor(exp(-c[N-2][R2])), gsqrt(absi_shallow(D),DEFAULTPREC)); } return gerepileuptoint(av, ceil_safe(w)); } /* return \gamma_n^n if known, an upper bound otherwise */ static GEN hermiteconstant(long n) { GEN h,h1; pari_sp av; switch(n) { case 1: return gen_1; case 2: return mkfrac(utoipos(4), utoipos(3)); case 3: return gen_2; case 4: return utoipos(4); case 5: return utoipos(8); case 6: return mkfrac(utoipos(64), utoipos(3)); case 7: return utoipos(64); case 8: return utoipos(256); } av = avma; h = powru(divur(2,mppi(DEFAULTPREC)), n); h1 = sqrr(ggamma(gdivgs(utoipos(n+4),2),DEFAULTPREC)); return gerepileuptoleaf(av, mulrr(h,h1)); } /* 1 if L (= nf != Q) primitive for sure, 0 if MAYBE imprimitive (may have a * subfield K) */ static long isprimitive(GEN nf) { long p, i, l, ep, N = nf_get_degree(nf); GEN D, fa; p = ucoeff(factoru(N), 1,1); /* smallest prime | N */ if (p == N) return 1; /* prime degree */ /* N = [L:Q] = product of primes >= p, same is true for [L:K] * d_L = t d_K^[L:K] --> check that some q^p divides d_L */ D = nf_get_disc(nf); fa = gel(absZ_factor_limit(D,0),2); /* list of v_q(d_L). Don't check large primes */ if (mod2(D)) i = 1; else { /* q = 2 */ ep = itos(gel(fa,1)); if ((ep>>1) >= p) return 0; /* 2 | d_K ==> 4 | d_K */ i = 2; } l = lg(fa); for ( ; i < l; i++) { ep = itos(gel(fa,i)); if (ep >= p) return 0; } return 1; } static GEN dft_bound(void) { if (DEBUGLEVEL>1) err_printf("Default bound for regulator: 0.2\n"); return dbltor(0.2); } static GEN regulatorbound(GEN bnf) { long N, R1, R2, R; GEN nf, dK, p1, c1; nf = bnf_get_nf(bnf); N = nf_get_degree(nf); if (!isprimitive(nf)) return dft_bound(); dK = absi_shallow(nf_get_disc(nf)); nf_get_sign(nf, &R1, &R2); R = R1+R2-1; c1 = (!R2 && N<12)? int2n(N & (~1UL)): powuu(N,N); if (cmpii(dK,c1) <= 0) return dft_bound(); p1 = sqrr(glog(gdiv(dK,c1),DEFAULTPREC)); p1 = divru(gmul2n(powru(divru(mulru(p1,3),N*(N*N-1)-6*R2),R),R2), N); p1 = sqrtr(gdiv(p1, hermiteconstant(R))); if (DEBUGLEVEL>1) err_printf("Mahler bound for regulator: %Ps\n",p1); return gmax_shallow(p1, dbltor(0.2)); } static int is_unit(GEN M, long r1, GEN x) { pari_sp av = avma; GEN Nx = ground( embed_norm(RgM_zc_mul(M,x), r1) ); int ok = is_pm1(Nx); avma = av; return ok; } /* FIXME: should use smallvectors */ static double minimforunits(GEN nf, long BORNE, ulong w) { const long prec = MEDDEFAULTPREC; long n, r1, i, j, k, *x, cnt = 0; pari_sp av = avma; GEN r, M; double p, norme, normin; double **q,*v,*y,*z; double eps=0.000001, BOUND = BORNE * 1.00001; if (DEBUGLEVEL>=2) { err_printf("Searching minimum of T2-form on units:\n"); if (DEBUGLEVEL>2) err_printf(" BOUND = %ld\n",BORNE); err_flush(); } n = nf_get_degree(nf); r1 = nf_get_r1(nf); minim_alloc(n+1, &q, &x, &y, &z, &v); M = gprec_w(nf_get_M(nf), prec); r = gaussred_from_QR(nf_get_G(nf), prec); for (j=1; j<=n; j++) { v[j] = gtodouble(gcoeff(r,j,j)); for (i=1; i1) { long l = k-1; z[l] = 0; for (j=k; j<=n; j++) z[l] += q[l][j]*x[j]; p = (double)x[k] + z[k]; y[l] = y[k] + p*p*v[k]; x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]); k = l; } for(;;) { p = (double)x[k] + z[k]; if (y[k] + p*p*v[k] <= BOUND) break; k++; x[k]--; } } while (k>1); if (!x[1] && y[1]<=eps) break; if (DEBUGLEVEL>8){ err_printf("."); err_flush(); } if (++cnt == 5000) return -1.; /* too expensive */ p = (double)x[1] + z[1]; norme = y[1] + p*p*v[1]; if (is_unit(M, r1, x) && norme < normin) { /* exclude roots of unity */ if (norme < 2*n) { GEN t = nfpow_u(nf, zc_to_ZC(x), w); if (typ(t) != t_COL || ZV_isscalar(t)) continue; } normin = norme*(1-eps); if (DEBUGLEVEL>=2) { err_printf("*"); err_flush(); } } } if (DEBUGLEVEL>=2){ err_printf("\n"); err_flush(); } avma = av; return normin; } #undef NBMAX static int is_zero(GEN x, long bitprec) { return (gexpo(x) < -bitprec); } static int is_complex(GEN x, long bitprec) { return !is_zero(imag_i(x), bitprec); } /* assume M_star t_REAL * FIXME: what does this do ? To be rewritten */ static GEN compute_M0(GEN M_star,long N) { long m1,m2,n1,n2,n3,lr,lr1,lr2,i,j,l,vx,vy,vz,vM; GEN pol,p1,p2,p3,p4,p5,p6,p7,p8,p9,u,v,w,r,r1,r2,M0,M0_pro,S,P,M; GEN f1,f2,f3,g1,g2,g3,pg1,pg2,pg3,pf1,pf2,pf3,X,Y,Z; long bitprec = 24; if (N == 2) return gmul2n(sqrr(gacosh(gmul2n(M_star,-1),0)), -1); vx = fetch_var(); X = pol_x(vx); vy = fetch_var(); Y = pol_x(vy); vz = fetch_var(); Z = pol_x(vz); vM = fetch_var(); M = pol_x(vM); M0 = NULL; m1 = N/3; for (n1=1; n1<=m1; n1++) /* 1 <= n1 <= n2 <= n3 < N */ { m2 = (N-n1)>>1; for (n2=n1; n2<=m2; n2++) { pari_sp av = avma; n3=N-n1-n2; if (n1==n2 && n1==n3) /* n1 = n2 = n3 = m1 = N/3 */ { p1 = divru(M_star, m1); p4 = sqrtr_abs( mulrr(addsr(1,p1),subrs(p1,3)) ); p5 = subrs(p1,1); u = gen_1; v = gmul2n(addrr(p5,p4),-1); w = gmul2n(subrr(p5,p4),-1); M0_pro=gmul2n(mulur(m1,addrr(sqrr(logr_abs(v)),sqrr(logr_abs(w)))), -2); if (DEBUGLEVEL>2) { err_printf("[ %ld, %ld, %ld ]: %.28Pg\n",n1,n2,n3,M0_pro); err_flush(); } if (!M0 || gcmp(M0_pro,M0) < 0) M0 = M0_pro; } else if (n1==n2 || n2==n3) { /* n3 > N/3 >= n1 */ long k = N - 2*n2; p2 = deg1pol_shallow(stoi(-n2), M_star, vx); /* M* - n2 X */ p3 = gmul(powuu(k,k), gpowgs(gsubgs(RgX_Rg_mul(p2, M_star), k*k), n2)); pol = gsub(p3, RgX_mul(monomial(powuu(n2,n2), n2, vx), gpowgs(p2, N-n2))); r = roots(pol, DEFAULTPREC); lr = lg(r); for (i=1; i2) { err_printf("[ %ld, %ld, %ld ]: %.28Pg\n",n1,n2,n3,M0_pro); err_flush(); } if (!M0 || gcmp(M0_pro,M0) < 0) M0 = M0_pro; } } else { f1 = gsub(gadd(gmulsg(n1,X),gadd(gmulsg(n2,Y),gmulsg(n3,Z))), M); f2 = gmulsg(n1,gmul(Y,Z)); f2 = gadd(f2,gmulsg(n2,gmul(X,Z))); f2 = gadd(f2,gmulsg(n3,gmul(X,Y))); f2 = gsub(f2,gmul(M,gmul(X,gmul(Y,Z)))); f3 = gsub(gmul(gpowgs(X,n1),gmul(gpowgs(Y,n2),gpowgs(Z,n3))), gen_1); /* f1 = n1 X + n2 Y + n3 Z - M */ /* f2 = n1 YZ + n2 XZ + n3 XY */ /* f3 = X^n1 Y^n2 Z^n3 - 1*/ g1=resultant(f1,f2); g1=primpart(g1); g2=resultant(f1,f3); g2=primpart(g2); g3=resultant(g1,g2); g3=primpart(g3); pf1=gsubst(f1,vM,M_star); pg1=gsubst(g1,vM,M_star); pf2=gsubst(f2,vM,M_star); pg2=gsubst(g2,vM,M_star); pf3=gsubst(f3,vM,M_star); pg3=gsubst(g3,vM,M_star); /* g3 = Res_Y,Z(f1,f2,f3) */ r = roots(pg3,DEFAULTPREC); lr = lg(r); for (i=1; i2) { err_printf("[ %ld, %ld, %ld ]: %.28Pg\n",n1,n2,n3,M0_pro); err_flush(); } if (!M0 || gcmp(M0_pro,M0) < 0) M0 = M0_pro; } } } } if (!M0) avma = av; else M0 = gerepilecopy(av, M0); } } for (i=1;i<=4;i++) (void)delete_var(); return M0? M0: gen_0; } static GEN lowerboundforregulator(GEN bnf, GEN units) { long i, N, R2, RU = lg(units)-1; GEN nf, M0, M, G, minunit; double bound; if (!RU) return gen_1; nf = bnf_get_nf(bnf); N = nf_get_degree(nf); R2 = nf_get_r2(nf); G = nf_get_G(nf); minunit = gnorml2(RgM_RgC_mul(G, gel(units,1))); /* T2(units[1]) */ for (i=2; i<=RU; i++) { GEN t = gnorml2(RgM_RgC_mul(G, gel(units,i))); if (gcmp(t,minunit) < 0) minunit = t; } if (gexpo(minunit) > 30) return NULL; bound = minimforunits(nf, itos(gceil(minunit)), bnf_get_tuN(bnf)); if (bound < 0) return NULL; if (DEBUGLEVEL>1) err_printf("M* = %Ps\n", dbltor(bound)); M0 = compute_M0(dbltor(bound), N); if (DEBUGLEVEL>1) { err_printf("M0 = %.28Pg\n",M0); err_flush(); } M = gmul2n(divru(gdiv(powrs(M0,RU),hermiteconstant(RU)),N),R2); if (cmprr(M, dbltor(0.04)) < 0) return NULL; M = sqrtr(M); if (DEBUGLEVEL>1) err_printf("(lower bound for regulator) M = %.28Pg\n",M); return M; } /* upper bound for the index of bnf.fu in the full unit group */ static GEN bound_unit_index(GEN bnf, GEN units) { pari_sp av = avma; GEN x = lowerboundforregulator(bnf, units); if (!x) { avma = av; x = regulatorbound(bnf); } return gerepileuptoint(av, ground(gdiv(bnf_get_reg(bnf), x))); } /* Compute a square matrix of rank #beta attached to a family * (P_i), 1<=i<=#beta, of primes s.t. N(P_i) = 1 mod p, and * (P_i,beta[j]) = 1 for all i,j. nf = true nf */ static void primecertify(GEN nf, GEN beta, ulong p, GEN bad) { long lb = lg(beta), rmax = lb - 1; GEN M, vQ, L; ulong q; forprime_t T; if (p == 2) L = cgetg(1,t_VECSMALL); else L = mkvecsmall(p); (void)u_forprime_arith_init(&T, 1, ULONG_MAX, 1, p); M = cgetg(lb,t_MAT); setlg(M,1); while ((q = u_forprime_next(&T))) { GEN qq, gg, og; long lQ, i, j; ulong g, m; if (!umodiu(bad,q)) continue; qq = utoipos(q); vQ = idealprimedec_limit_f(nf,qq,1); lQ = lg(vQ); if (lQ == 1) continue; /* cf rootsof1_Fl */ g = pgener_Fl_local(q, L); (void)u_lvalrem((q-1) / p, p, &m); gg = utoipos( Fl_powu(g, m, q) ); /* order p in (Z/q)^* */ og = mkmat2(mkcol(utoi(p)), mkcol(gen_1)); /* order of g */ if (DEBUGLEVEL>3) err_printf(" generator of (Zk/Q)^*: %lu\n", g); for (i = 1; i < lQ; i++) { GEN C = cgetg(lb, t_VECSMALL); GEN Q = gel(vQ,i); /* degree 1 */ GEN modpr = zkmodprinit(nf, Q); long r; for (j = 1; j < lb; j++) { GEN t = nf_to_Fp_coprime(nf, gel(beta,j), modpr); t = utoipos( Fl_powu(t[2], m, q) ); /* FIXME: implement Fl_log_Shanks */ C[j] = itou( Fp_log(t, gg, og, qq) ) % p; } r = lg(M); gel(M,r) = C; setlg(M, r+1); if (Flm_rank(M, p) != r) { setlg(M,r); continue; } if (DEBUGLEVEL>2) { if (DEBUGLEVEL>3) { err_printf(" prime ideal Q: %Ps\n",Q); err_printf(" matrix log(b_j mod Q_i): %Ps\n", M); } err_printf(" new rank: %ld\n",r); } if (r == rmax) return; } } pari_err_BUG("primecertify"); } struct check_pr { long w; /* #mu(K) */ GEN mu; /* generator of mu(K) */ GEN fu; GEN cyc; GEN cycgen; GEN bad; /* p | bad <--> p | some element occurring in cycgen */ }; static void check_prime(ulong p, GEN nf, struct check_pr *S) { pari_sp av = avma; long i,b, lc = lg(S->cyc), lf = lg(S->fu); GEN beta = cgetg(lf+lc, t_VEC); if (DEBUGLEVEL>1) err_printf(" *** testing p = %lu\n",p); for (b=1; bcyc,b), p)) break; /* p \nmid cyc[b] */ if (b==1 && DEBUGLEVEL>2) err_printf(" p divides h(K)\n"); gel(beta,b) = gel(S->cycgen,b); } if (S->w % p == 0) { if (DEBUGLEVEL>2) err_printf(" p divides w(K)\n"); gel(beta,b++) = S->mu; } for (i=1; ifu,i); setlg(beta, b); /* beta = [cycgen[i] if p|cyc[i], tu if p|w, fu] */ if (DEBUGLEVEL>3) {err_printf(" Beta list = %Ps\n",beta); err_flush();} primecertify(nf, beta, p, S->bad); avma = av; } static void init_bad(struct check_pr *S, GEN nf, GEN gen) { long i, l = lg(gen); GEN bad = gen_1; for (i=1; i < l; i++) bad = lcmii(bad, gcoeff(gel(gen,i),1,1)); for (i = 1; i < l; i++) { GEN c = gel(S->cycgen,i); long j; if (typ(c) == t_MAT) { GEN g = gel(c,1); for (j = 1; j < lg(g); j++) { GEN h = idealhnf_shallow(nf, gel(g,j)); bad = lcmii(bad, gcoeff(h,1,1)); } } } S->bad = bad; } long bnfcertify0(GEN bnf, long flag) { pari_sp av = avma; long N; GEN nf, cyc, B, U; ulong bound, p; struct check_pr S; forprime_t T; bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); N = nf_get_degree(nf); if (N==1) return 1; B = zimmertbound(nf_get_disc(nf), N, nf_get_r2(nf)); if (is_bigint(B)) pari_warn(warner,"Zimmert's bound is large (%Ps), certification will take a long time", B); if (!is_pm1(nf_get_index(nf))) { GEN D = nf_get_diff(nf), L; if (DEBUGLEVEL>1) err_printf("**** Testing Different = %Ps\n",D); L = bnfisprincipal0(bnf, D, nf_FORCE); if (DEBUGLEVEL>1) err_printf(" is %Ps\n", L); } if (DEBUGLEVEL) { err_printf("PHASE 1 [CLASS GROUP]: are all primes good ?\n"); err_printf(" Testing primes <= %Ps\n", B); err_flush(); } bnftestprimes(bnf, B); if (flag) return 1; U = bnf_build_units(bnf); cyc = bnf_get_cyc(bnf); S.w = bnf_get_tuN(bnf); S.mu = gel(U,1); S.fu = vecslice(U,2,lg(U)-1); S.cyc = cyc; S.cycgen = bnf_build_cycgen(bnf); init_bad(&S, nf, bnf_get_gen(bnf)); B = bound_unit_index(bnf, S.fu); if (DEBUGLEVEL) { err_printf("PHASE 2 [UNITS/RELATIONS]: are all primes good ?\n"); err_printf(" Testing primes <= %Ps\n", B); err_flush(); } bound = itou_or_0(B); if (!bound) pari_err_OVERFLOW("bnfcertify [too many primes to check]"); if (u_forprime_init(&T, 2, bound)) while ( (p = u_forprime_next(&T)) ) check_prime(p, nf, &S); if (lg(cyc) > 1) { GEN f = Z_factor(gel(cyc,1)), P = gel(f,1); long i; if (DEBUGLEVEL>1) { err_printf(" Primes dividing h(K)\n\n"); err_flush(); } for (i = lg(P)-1; i; i--) { p = itou(gel(P,i)); if (p <= bound) break; check_prime(p, nf, &S); } } avma = av; return 1; } long bnfcertify(GEN bnf) { return bnfcertify0(bnf, 0); } /*******************************************************************/ /* */ /* RAY CLASS FIELDS: CONDUCTORS AND DISCRIMINANTS */ /* */ /*******************************************************************/ /* \chi(gen[i]) = zeta_D^chic[i]) * denormalize: express chi(gen[i]) in terms of zeta_{cyc[i]} */ GEN char_denormalize(GEN cyc, GEN D, GEN chic) { long i, l = lg(chic); GEN chi = cgetg(l, t_VEC); /* \chi(gen[i]) = e(chic[i] / D) = e(chi[i] / cyc[i]) * hence chi[i] = chic[i]cyc[i]/ D mod cyc[i] */ for (i = 1; i < l; ++i) { GEN di = gel(cyc, i), t = diviiexact(mulii(di, gel(chic,i)), D); gel(chi, i) = modii(t, di); } return chi; } static GEN bnrchar_i(GEN bnr, GEN g, GEN v) { long i, h, l = lg(g); GEN CH, D, U, U2, H, cyc, cycD, dv, dchi; checkbnr(bnr); switch(typ(g)) { GEN G; case t_VEC: G = cgetg(l, t_MAT); for (i = 1; i < l; i++) gel(G,i) = isprincipalray(bnr, gel(g,i)); g = G; break; case t_MAT: if (RgM_is_ZM(g)) break; default: pari_err_TYPE("bnrchar",g); } cyc = bnr_get_cyc(bnr); H = ZM_hnfall_i(shallowconcat(g,diagonal_shallow(cyc)), v? &U: NULL, 1); dv = NULL; if (v) { GEN w = Q_remove_denom(v, &dv); if (typ(v)!=t_VEC || lg(v)!=l || !RgV_is_ZV(w)) pari_err_TYPE("bnrchar",v); if (!dv) v = NULL; else { U = rowslice(U, 1, l-1); w = FpV_red(ZV_ZM_mul(w, U), dv); for (i = 1; i < l; i++) if (signe(gel(w,i))) pari_err_TYPE("bnrchar [inconsistent values]",v); v = vecslice(w,l,lg(w)-1); } } /* chi defined on subgroup H, chi(H[i]) = e(v[i] / dv) * unless v = NULL: chi|H = 1*/ h = itos( ZM_det_triangular(H) ); /* #(clgp/H) = number of chars */ if (h == 1) /* unique character, H = Id */ { if (v) v = char_denormalize(cyc,dv,v); else v = zerovec(lg(cyc)-1); /* trivial char */ return mkvec(v); } /* chi defined on a subgroup of index h > 1; U H V = D diagonal, * Z^#H / (H) = Z^#H / (D) ~ \oplus (Z/diZ) */ D = ZM_snfall_i(H, &U, NULL, 1); cycD = cyc_normalize(D); gel(cycD,1) = gen_1; /* cycD[i] = d1/di */ dchi = gel(D,1); U2 = ZM_diag_mul(cycD, U); if (v) { GEN Ui = ZM_inv(U, NULL); GEN Z = hnf_solve(H, ZM_mul_diag(Ui, D)); v = ZV_ZM_mul(ZV_ZM_mul(v, Z), U2); dchi = mulii(dchi, dv); U2 = ZM_Z_mul(U2, dv); } CH = cyc2elts(D); for (i = 1; i <= h; i++) { GEN c = zv_ZM_mul(gel(CH,i), U2); if (v) c = ZC_add(c, v); gel(CH,i) = char_denormalize(cyc, dchi, c); } return CH; } GEN bnrchar(GEN bnr, GEN g, GEN v) { pari_sp av = avma; return gerepilecopy(av, bnrchar_i(bnr,g,v)); } /* Let bnr1, bnr2 be such that mod(bnr2) | mod(bnr1), compute the matrix of the * surjective map p: Cl(bnr1) ->> Cl(bnr2). Write (bnr gens) for the * concatenation of the bnf [corrected by El] and bid generators; and * bnr.gen for the SNF generators. Then * bnr.gen = (bnf.gen*bnr.El | bid.gen) bnr.Ui * (bnf.gen*bnr.El | bid.gen) = bnr.gen * bnr.U */ GEN bnrsurjection(GEN bnr1, GEN bnr2) { GEN bnf = bnr_get_bnf(bnr2), nf = bnf_get_nf(bnf); GEN M, U = bnr_get_U(bnr2), bid2 = bnr_get_bid(bnr2); GEN gen1 = bid_get_gen(bnr_get_bid(bnr1)); long i, l = lg(bnf_get_cyc(bnf)), lb = lg(gen1); /* p(bnr1.gen) = p(bnr1 gens) * bnr1.Ui * = (bnr2 gens) * P * bnr1.Ui * = bnr2.gen * (bnr2.U * P * bnr1.Ui) */ /* p(bid1.gen) on bid2.gen */ M = cgetg(lb, t_MAT); for (i = 1; i < lb; i++) gel(M,i) = ideallog(nf, gel(gen1,i), bid2); /* [U[1], U[2]] * [Id, 0; N, M] = [U[1] + U[2]*N, U[2]*M] */ M = ZM_mul(gel(U,2), M); if (l > 1) { /* non trivial class group */ /* p(bnf.gen * bnr1.El) in terms of bnf.gen * bnr2.El and bid2.gen */ GEN El2 = bnr_get_El(bnr2), El1 = bnr_get_El(bnr1); GEN N = cgetg(l, t_MAT); long ngen2 = lg(bid_get_gen(bid2))-1; if (!ngen2) M = gel(U,1); else { for (i = 1; i < l; i++) { /* bnf gen in bnr1 is bnf.gen * El1 = bnf gen in bnr 2 * El1/El2 */ GEN z; if (typ(gel(El1,i)) == t_INT) z = zerocol(ngen2); else { z = nfdiv(nf,gel(El1,i),gel(El2,i)); z = ideallog(nf, z, bid2); } gel(N,i) = z; } M = shallowconcat(ZM_add(gel(U,1), ZM_mul(gel(U,2),N)), M); } } return ZM_mul(M, bnr_get_Ui(bnr1)); } /* Given normalized chi on bnr.clgp of conductor bnrc.mod, * compute primitive character chic on bnrc.clgp equivalent to chi, * still normalized wrt. bnr: * chic(genc[i]) = zeta_C^chic[i]), C = cyc_normalize(bnr.cyc)[1] */ GEN bnrchar_primitive(GEN bnr, GEN nchi, GEN bnrc) { GEN Mc, U, M = bnrsurjection(bnr, bnrc); long l = lg(M); Mc = diagonal_shallow(bnr_get_cyc(bnrc)); (void)ZM_hnfall_i(shallowconcat(M, Mc), &U, 1); /* identity */ U = matslice(U,1,l-1, l,lg(U)-1); return char_simplify(gel(nchi,1), ZV_ZM_mul(gel(nchi,2), U)); } /* s: = Cl_f --> Cl_f2 --> 0, H subgroup of Cl_f (generators given as * HNF on [gen]). Return subgroup s(H) in Cl_f2 */ static GEN imageofgroup(GEN bnr, GEN bnr2, GEN H) { GEN H2, cyc2 = bnr_get_cyc(bnr2); if (!H) return diagonal_shallow(cyc2); H2 = ZM_mul(bnrsurjection(bnr, bnr2), H); return ZM_hnfmodid(H2, cyc2); /* s(H) in Cl_n */ } static GEN imageofchar(GEN bnr, GEN bnrc, GEN chi) { GEN nchi = char_normalize(chi, cyc_normalize(bnr_get_cyc(bnr))); GEN DC = bnrchar_primitive(bnr, nchi, bnrc); return char_denormalize(bnr_get_cyc(bnrc), gel(DC,1), gel(DC,2)); } /* convert A,B,C to [bnr, H] */ GEN ABC_to_bnr(GEN A, GEN B, GEN C, GEN *H, int gen) { if (typ(A) == t_VEC) switch(lg(A)) { case 7: /* bnr */ *H = B; return A; case 11: /* bnf */ if (!B) pari_err_TYPE("ABC_to_bnr [bnf+missing conductor]",A); *H = C; return Buchray(A,B, gen? nf_INIT | nf_GEN: nf_INIT); } pari_err_TYPE("ABC_to_bnr",A); *H = NULL; return NULL; /* LCOV_EXCL_LINE */ } GEN bnrconductor0(GEN A, GEN B, GEN C, long flag) { pari_sp av = avma; GEN H, bnr = ABC_to_bnr(A,B,C,&H, 0); return gerepilecopy(av, bnrconductor_i(bnr, H, flag)); } long bnrisconductor0(GEN A,GEN B,GEN C) { GEN H, bnr = ABC_to_bnr(A,B,C,&H, 0); return bnrisconductor(bnr, H); } static GEN ideallog_to_bnr_i(GEN Ubid, GEN cyc, GEN z) { return (lg(Ubid)==1)? zerocol(lg(cyc)-1): vecmodii(ZM_ZC_mul(Ubid,z), cyc); } /* return bnrisprincipal(bnr, (x)), assuming z = ideallog(x); allow a * t_MAT for z, understood as a collection of ideallog(x_i) */ static GEN ideallog_to_bnr(GEN bnr, GEN z) { GEN U = gel(bnr_get_U(bnr), 2); /* bid part */ GEN y, cyc = bnr_get_cyc(bnr); long i, l; if (typ(z) == t_COL) return ideallog_to_bnr_i(U, cyc, z); y = cgetg_copy(z, &l); for (i = 1; i < l; i++) gel(y,i) = ideallog_to_bnr_i(U, cyc, gel(z,i)); return y; } static GEN bnr_log_gen_pr(GEN bnr, zlog_S *S, GEN nf, long e, long index) { return ideallog_to_bnr(bnr, log_gen_pr(S, index, nf, e)); } static GEN bnr_log_gen_arch(GEN bnr, zlog_S *S, long index) { return ideallog_to_bnr(bnr, log_gen_arch(S, index)); } /* A \subset H ? Allow H = NULL = trivial subgroup */ static int contains(GEN H, GEN A) { return H? (hnf_solve(H, A) != NULL): gequal0(A); } /* (see bnrdisc_i). Given a bnr, and a subgroup * H0 (possibly given as a character chi, in which case H0 = ker chi) of the * ray class group, compute the conductor of H if flag=0. If flag > 0, compute * also the corresponding H' and output * if flag = 1: [[ideal,arch],[hm,cyc,gen],H'] * if flag = 2: [[ideal,arch],newbnr,H'] */ GEN bnrconductor_i(GEN bnr, GEN H0, long flag) { long j, k, l; GEN nf, bid, ideal, archp, clhray, bnrc, e2, e, cond, H; int iscond0, iscondinf = 1, ischi; zlog_S S; checkbnr(bnr); bid = bnr_get_bid(bnr); init_zlog(&S, bid); iscond0 = S.no2; nf = bnr_get_nf(bnr); H = check_subgroup(bnr, H0, &clhray); archp = leafcopy(S.archp); e = S.k; l = lg(e); e2 = cgetg(l, t_COL); for (k = 1; k < l; k++) { for (j = itos(gel(e,k)); j > 0; j--) { if (!contains(H, bnr_log_gen_pr(bnr, &S, nf, j, k))) break; iscond0 = 0; } gel(e2,k) = stoi(j); } l = lg(archp); for (k = 1; k < l; k++) { if (!contains(H, bnr_log_gen_arch(bnr, &S, k))) continue; archp[k] = 0; iscondinf = 0; } if (!iscondinf) { for (j = k = 1; k < l; k++) if (archp[k]) archp[j++] = archp[k]; setlg(archp, j); } ideal = iscond0? bid_get_ideal(bid): factorbackprime(nf, S.P, e2); cond = mkvec2(ideal, indices_to_vec01(archp, nf_get_r1(nf))); if (!flag) return cond; /* character or subgroup ? */ ischi = H0 && typ(H0) == t_VEC; if (iscond0 && iscondinf) { bnrc = bnr; if (ischi) H = H0; else if (!H) H = diagonal_shallow(bnr_get_cyc(bnr)); } else { long flag = lg(bnr_get_clgp(bnr)) == 4? nf_INIT | nf_GEN: nf_INIT; bnrc = Buchray_i(bnr, cond, flag); if (ischi) H = imageofchar(bnr, bnrc, H0); else H = imageofgroup(bnr, bnrc, H); } if (flag == 1) bnrc = bnr_get_clgp(bnrc); return mkvec3(cond, bnrc, H); } GEN bnrconductor(GEN bnr, GEN H0, long flag) { pari_sp av = avma; return gerepilecopy(av, bnrconductor_i(bnr,H0,flag)); } long bnrisconductor(GEN bnr, GEN H0) { pari_sp av = avma; long j, k, l; GEN bnf, nf, archp, clhray, e, H; zlog_S S; checkbnr(bnr); bnf = bnr_get_bnf(bnr); init_zlog(&S, bnr_get_bid(bnr)); if (!S.no2) return 0; nf = bnf_get_nf(bnf); H = check_subgroup(bnr, H0, &clhray); archp = S.archp; e = S.k; l = lg(e); for (k = 1; k < l; k++) { j = itos(gel(e,k)); if (contains(H, bnr_log_gen_pr(bnr, &S, nf, j, k))) { avma = av; return 0; } } l = lg(archp); for (k = 1; k < l; k++) if (contains(H, bnr_log_gen_arch(bnr, &S, k))) { avma = av; return 0; } avma = av; return 1; } /* return the norm group corresponding to the relative extension given by * polrel over bnr.bnf, assuming it is abelian and the modulus of bnr is a * multiple of the conductor */ static GEN rnfnormgroup_i(GEN bnr, GEN polrel) { long i, j, degrel, degnf, k; GEN bnf, index, discnf, nf, G, detG, fa, gdegrel; GEN fac, col, cnd; forprime_t S; ulong p; checkbnr(bnr); bnf = bnr_get_bnf(bnr); nf = bnf_get_nf(bnf); cnd = gel(bnr_get_mod(bnr), 1); polrel = RgX_nffix("rnfnormgroup", nf_get_pol(nf),polrel,1); if (!gequal1(leading_coeff(polrel))) pari_err_IMPL("rnfnormgroup for non-monic polynomials"); degrel = degpol(polrel); if (umodiu(bnr_get_no(bnr), degrel)) return NULL; /* degrel-th powers are in norm group */ gdegrel = utoipos(degrel); G = FpC_red(bnr_get_cyc(bnr), gdegrel); for (i=1; i 1) col = ZC_z_mul(col, f); G = ZM_hnf(shallowconcat(G, col)); detG = ZM_det_triangular(G); k = abscmpiu(detG,degrel); if (k < 0) return NULL; if (!k) { cgiv(detG); return G; } } } return NULL; } GEN rnfnormgroup(GEN bnr, GEN polrel) { pari_sp av = avma; GEN G = rnfnormgroup_i(bnr, polrel); if (!G) { avma = av; return cgetg(1,t_MAT); } return gerepileupto(av, G); } GEN nf_deg1_prime(GEN nf) { GEN z, T = nf_get_pol(nf), D = nf_get_disc(nf), f = nf_get_index(nf); long degnf = degpol(T); forprime_t S; pari_sp av; ulong p; u_forprime_init(&S, degnf, ULONG_MAX); av = avma; while ( (p = u_forprime_next(&S)) ) { ulong r; if (!umodiu(D, p) || !umodiu(f, p)) continue; r = Flx_oneroot(ZX_to_Flx(T,p), p); if (r != p) { z = utoi(Fl_neg(r, p)); z = deg1pol_shallow(gen_1, z, varn(T)); return idealprimedec_kummer(nf, z, 1, utoipos(p)); } avma = av; } return NULL; } static long rnfisabelian_i(GEN nf, GEN pol) { GEN modpr, pr, T, Tnf, pp, ro, nfL, C, a, sig, eq; long i, j, l, v; ulong p, k, ka; if (typ(nf) == t_POL) Tnf = nf; else { nf = checknf(nf); Tnf = nf_get_pol(nf); } v = varn(Tnf); if (degpol(Tnf) != 1 && typ(pol) == t_POL && RgX_is_QX(pol) && rnfisabelian_i(pol_x(v), pol)) return 1; pol = RgX_nffix("rnfisabelian",Tnf,pol,1); eq = nf_rnfeq(nf,pol); /* init L := K[x]/(pol), nf attached to K */ C = gel(eq,1); setvarn(C, v); /* L = Q[t]/(C) */ a = gel(eq,2); setvarn(a, v); /* root of K.pol in L */ nfL = C; ro = nfroots_if_split(&nfL, QXX_QXQ_eval(pol, a, C)); if (!ro) return 0; l = lg(ro)-1; /* small groups are abelian, as are groups of prime order */ if (l < 6 || uisprime(l)) return 1; pr = nf_deg1_prime(nfL); modpr = nf_to_Fq_init(nfL, &pr, &T, &pp); p = itou(pp); k = umodiu(gel(eq,3), p); ka = (k * itou(nf_to_Fq(nfL, a, modpr))) % p; sig= cgetg(l+1, t_VECSMALL); /* image of c = ro[1] + k a [distinguished root of C] by the l automorphisms * sig[i]: ro[1] -> ro[i] */ for (i = 1; i <= l; i++) sig[i] = Fl_add(ka, itou(nf_to_Fq(nfL, gel(ro,i), modpr)), p); ro = Q_primpart(ro); for (i=2; i<=l; i++) { /* start at 2, since sig[1] = identity */ gel(ro,i) = ZX_to_Flx(gel(ro,i), p); for (j=2; j 1 && vecsmall_max(Ez) > 1) { /* cheaply update tame primes */ for (i = 1; i < l; i++) { /* v_pr(f) = 1 + \sum_{0 < i < l} g_i/g_0 <= 1 + max_{i>0} g_i/(g_i-1) \sum_{0 < i < l} g_i -1 <= 1 + (p/(p-1)) * v_P(e(L/K, pr)), P | pr | p */ GEN pr = gel(P,i), p = pr_get_p(pr), e = gen_1; long q, v = z_pvalrem(degT, p, &q); if (v) { /* e = e_tame * e_wild, e_wild | p^v */ long ee, pp = itou(p); long t = ugcd(umodiu(subiu(pr_norm(pr),1), q), q); /* e_tame | t */ /* upper bound for 1 + p/(p-1) * v * e(L/Q,p) */ ee = 1 + (pp * v * pr_get_e(pr) * upowuu(pp,v) * t) / (pp-1); e = utoi(minss(ee, Ez[i])); } gel(E,i) = e; } } } module = mkvec2(D, identity_perm(nf_get_r1(nf))); bnr = Buchray_i(bnf,module,nf_INIT|nf_GEN); H = rnfnormgroup_i(bnr,T); if (!H) { avma = av; return gen_0; } return gerepilecopy(av, bnrconductor_i(bnr,H,2)); } static GEN prV_norms(GEN v) { long i, l; GEN w = cgetg_copy(v, &l); for (i = 1; i < l; i++) gel(w,i) = pr_norm(gel(v,i)); return w; } /* Given a number field bnf=bnr[1], a ray class group structure bnr, and a * subgroup H (HNF form) of the ray class group, compute [n, r1, dk] * attached to H. If flag & rnf_COND, abort (return NULL) if module is not the * conductor. If flag & rnf_REL, return relative data, else absolute */ static GEN bnrdisc_i(GEN bnr, GEN H, long flag) { const long flcond = flag & rnf_COND; GEN nf, clhray, E, ED, dk; long k, d, l, n, r1; zlog_S S; checkbnr(bnr); init_zlog(&S, bnr_get_bid(bnr)); nf = bnr_get_nf(bnr); H = check_subgroup(bnr, H, &clhray); d = itos(clhray); if (!H) H = diagonal_shallow(bnr_get_cyc(bnr)); E = S.k; ED = cgetg_copy(E, &l); for (k = 1; k < l; k++) { long j, e = itos(gel(E,k)), eD = e*d; GEN H2 = H; for (j = e; j > 0; j--) { GEN z = bnr_log_gen_pr(bnr, &S, nf, j, k); long d2; H2 = ZM_hnf(shallowconcat(H2, z)); d2 = itos( ZM_det_triangular(H2) ); if (flcond && j==e && d2 == d) return NULL; if (d2 == 1) { eD -= j; break; } eD -= d2; } gel(ED,k) = utoi(eD); /* v_{P[k]}(relative discriminant) */ } l = lg(S.archp); r1 = nf_get_r1(nf); for (k = 1; k < l; k++) { if (!contains(H, bnr_log_gen_arch(bnr, &S, k))) { r1--; continue; } if (flcond) return NULL; } /* d = relative degree * r1 = number of unramified real places; * [P,ED] = factorization of relative discriminant */ if (flag & rnf_REL) { n = d; dk = factorbackprime(nf, S.P, ED); } else { n = d * nf_get_degree(nf); r1= d * r1; dk = factorback2(prV_norms(S.P), ED); if (((n-r1)&3) == 2) dk = negi(dk); /* (2r2) mod 4 = 2: r2(relext) is odd */ dk = mulii(dk, powiu(absi_shallow(nf_get_disc(nf)), d)); } return mkvec3(utoipos(n), utoi(r1), dk); } GEN bnrdisc(GEN bnr, GEN H, long flag) { pari_sp av = avma; GEN D = bnrdisc_i(bnr, H, flag); if (!D) { avma = av; return gen_0; } return gerepilecopy(av, D); } GEN bnrdisc0(GEN A, GEN B, GEN C, long flag) { GEN H, bnr = ABC_to_bnr(A,B,C,&H, 0); return bnrdisc(bnr,H,flag); } /* Given a number field bnf=bnr[1], a ray class group structure bnr and a * vector chi representing a character on the generators bnr[2][3], compute * the conductor of chi. */ GEN bnrconductorofchar(GEN bnr, GEN chi) { pari_sp av = avma; GEN cyc, K; checkbnr(bnr); cyc = bnr_get_cyc(bnr); if (!char_check(cyc,chi)) pari_err_TYPE("bnrconductorofchar",chi); K = charker(cyc,chi); if (lg(K) == 1) K = NULL; return gerepilecopy(av, bnrconductor_i(bnr, K, 0)); } /* \sum U[i]*y[i], U[i],y[i] ZM, we allow lg(y) > lg(U). */ static GEN ZMV_mul(GEN U, GEN y) { long i, l = lg(U); GEN z = NULL; if (l == 1) return cgetg(1,t_MAT); for (i = 1; i < l; i++) { GEN u = ZM_mul(gel(U,i), gel(y,i)); z = z? ZM_add(z, u): u; } return z; } /* t = [bid,U], h = #Cl(K) */ static GEN get_classno(GEN t, GEN h) { GEN bid = gel(t,1), m = gel(t,2), cyc = bid_get_cyc(bid), U = bid_get_U(bid); return mulii(h, ZM_det_triangular(ZM_hnfmodid(ZMV_mul(U,m), cyc))); } static void chk_listBU(GEN L, const char *s) { if (typ(L) != t_VEC) pari_err_TYPE(s,L); if (lg(L) > 1) { GEN z = gel(L,1); if (typ(z) != t_VEC) pari_err_TYPE(s,z); if (lg(z) == 1) return; z = gel(z,1); /* [bid,U] */ if (typ(z) != t_VEC || lg(z) != 3) pari_err_TYPE(s,z); checkbid(gel(z,1)); } } /* Given lists of [bid, unit ideallogs], return lists of ray class numbers */ GEN bnrclassnolist(GEN bnf,GEN L) { pari_sp av = avma; long i, l = lg(L); GEN V, h; chk_listBU(L, "bnrclassnolist"); if (l == 1) return cgetg(1, t_VEC); bnf = checkbnf(bnf); h = bnf_get_no(bnf); V = cgetg(l,t_VEC); for (i = 1; i < l; i++) { GEN v, z = gel(L,i); long j, lz = lg(z); gel(V,i) = v = cgetg(lz,t_VEC); for (j=1; j 0) { gel(P,c) = gel(P1,i); gel(E,c) = p1; c++; } } } setlg(P, c); setlg(E, c); return mkmat2(P, E); } /* remove index k */ static GEN factorsplice(GEN fa, long k) { GEN p = gel(fa,1), e = gel(fa,2), P, E; long i, l = lg(p) - 1; P = cgetg(l, typ(p)); E = cgetg(l, typ(e)); for (i=1; iidealrelinit; GEN mod = gel(z,3), Fa = gel(z,1); GEN P = gel(Fa,1), E = gel(Fa,2); long k, nz, clhray = z[2], lP = lg(P); for (k=1; kbnf, gel(mod,1), gel(mod,2), clhray); return get_NR1D(N, clhray, D->degk, nz, D->fadk, idealrel); } /* Given a list of bids and attached unit log matrices, return the * list of discrayabs. Only keep moduli which are conductors. */ GEN discrayabslist(GEN bnf, GEN L) { pari_sp av = avma; long i, l = lg(L); GEN nf, V, D, h; disc_data ID; chk_listBU(L, "discrayabslist"); if (l == 1) return cgetg(1, t_VEC); ID.bnf = bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); h = bnf_get_no(bnf); ID.degk = nf_get_degree(nf); ID.fadk = absZ_factor(nf_get_disc(nf)); ID.idealrelinit = trivial_fact(); V = cgetg(l, t_VEC); D = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN z = gel(L,i), v, d; long j, lz = lg(z); gel(V,i) = v = cgetg(lz,t_VEC); gel(D,i) = d = cgetg(lz,t_VEC); for (j=1; j>=1) if (kk&1) rowsel[nba++] = nc + jj; setlg(rowsel, nba); rowselect_p(m, mm, rowsel, nc+1); H[k+1] = hdet(h, mm); } H = gerepileuptoleaf(av, H); gel(L,j) = mkvec2(gel(b,1), H); } return L; } static int is_module(GEN v) { if (lg(v) != 3 || (typ(v) != t_MAT && typ(v) != t_VEC)) return 0; return typ(gel(v,1)) == t_VECSMALL && typ(gel(v,2)) == t_VECSMALL; } GEN decodemodule(GEN nf, GEN fa) { long n, nn, k; pari_sp av = avma; GEN G, E, id, pr; nf = checknf(nf); if (!is_module(fa)) pari_err_TYPE("decodemodule [not a factorization]", fa); n = nf_get_degree(nf); nn = n*n; id = NULL; G = gel(fa,1); E = gel(fa,2); for (k=1; k15) pari_err_IMPL("r1>15 in discrayabslistarch"); arch = const_vec(r1, gen_1); } else if (lg(arch)-1 != r1) pari_err_TYPE("Idealstar [incorrect archimedean component]",arch); U = bnf_build_units(bnf); archp = vec01_to_indices(arch); nba = lg(archp)-1; sgnU = zm_to_ZM( nfsign_units(bnf, archp, 1) ); if (!allarch) sgnU = mkvec2(const_vec(nba,gen_2), sgnU); empty = cgetg(1,t_VEC); /* what follows was rewritten from Ideallist */ BOUND = utoipos(bound); p = cgetipos(3); u_forprime_init(&S, 2, bound); av = avma; sqbou = (long)sqrt((double)bound) + 1; Z = const_vec(bound, empty); gel(Z,1) = mkvec(zsimp()); if (DEBUGLEVEL>1) err_printf("Starting zidealstarunits computations\n"); /* The goal is to compute Ray (lists of bnrclassno). Z contains "zsimps", * simplified bid, from which bnrclassno is easy to compute. * Once p > sqbou, delete Z[i] for i > sqbou and compute directly Ray */ Ray = Z; while ((p[2] = u_forprime_next(&S))) { if (!flbou && p[2] > sqbou) { flbou = 1; if (DEBUGLEVEL>1) err_printf("\nStarting bnrclassno computations\n"); Z = gerepilecopy(av,Z); Ray = cgetg(bound+1, t_VEC); for (i=1; i<=bound; i++) gel(Ray,i) = bnrclassno_all(gel(Z,i),h,sgnU); Z = vecslice(Z, 1, sqbou); } fa = idealprimedec_limit_norm(nf,p,BOUND); for (j=1; j 1 && v[lv-1] == prcode) break; gel(p2,++c) = zsimpjoin(z,sprk,U_pr,prcode,l); } setlg(p2, c+1); pz = gel(Ray,iQ); if (flbou) p2 = bnrclassno_all(p2,h,sgnU); if (lg(pz) > 1) p2 = shallowconcat(pz,p2); gel(Ray,iQ) = p2; } Q = itou_or_0( muluu(Q, q) ); if (!Q || Q > bound) break; } } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"[1]: discrayabslistarch"); gerepileall(av, flbou? 2: 1, &Z, &Ray); } } if (!flbou) /* occurs iff bound = 1,2,4 */ { if (DEBUGLEVEL>1) err_printf("\nStarting bnrclassno computations\n"); Ray = cgetg(bound+1, t_VEC); for (i=1; i<=bound; i++) gel(Ray,i) = bnrclassno_all(gel(Z,i),h,sgnU); } Ray = gerepilecopy(av, Ray); if (DEBUGLEVEL>1) err_printf("Starting discrayabs computations\n"); if (allarch) nbarch = 1L<>=1) if (ka & 1) nba++; for (k2=1,k=1; k<=r1; k++,k2<<=1) if (karch&k2 && clhrayall[karch-k2+1] == clhray) { res = EMPTY; goto STORE; } } idealrel = idealrelinit; for (k=1; k1) pari_warn(warnmem,"[2]: discrayabslistarch"); for (jj=j+1; jj=3) break; return (ly==1)? x: shallowconcat(x,gel(y,1)); case t_MAT: z=cgetg(ly,t_MAT); if (lx != ly) break; for (i=1; i=3) break; return (ly==1)? x: shallowconcat(x, gel(y,1)); case t_MAT: if (lx != lgcols(y)) break; z=cgetg(ly+1,t_MAT); gel(z,1) = x; for (i=2; i<=ly; i++) gel(z,i) = gel(y,i-1); return z; } break; case t_MAT: switch(ty) { case t_VEC: z=cgetg(lx, t_MAT); if (ly != lx) break; for (i=1; i= y1; y--) { GEN c = gel(y,0); long nc = lg(c)-1; if (nc == 0) continue; if (h != lgcols(c)) { if (h) err_cat(gel(y2,0), c); h = lgcols(c); } L += nc; z = new_chunk(nc) - 1; for (i=1; i<=nc; i++) gel(z,i) = gel(c,i); } z = new_chunk(1); *z = evaltyp(t_MAT) | evallg(L); return z; } static GEN catmanySTR(GEN y1, GEN y2) { long L = 1; /* final \0 */ GEN z, y; char *s; for (y = y1; y <= y2; y++) { char *c = GSTR( gel(y,0) ); L += strlen(c); } z = cgetg(nchar2nlong(L)+1, t_STR); s = GSTR(z); for (y = y1; y <= y2; y++) { char *c = GSTR( gel(y,0) ); long nc = strlen(c); if (nc) { (void)memcpy(s, c, nc); s += nc; } } *s = 0; return z; } /* all entries in y have the same type t = t_VEC, COL, MAT or VECSMALL * concatenate y[k1..k2], with yi = y + ki, k1 <= k2 */ static GEN catmany(GEN y1, GEN y2, long t) { long i, L; GEN z, y; if (y1 == y2) return gel(y1,0); if (t == t_MAT) return catmanyMAT(y1, y2); if (t == t_STR) return catmanySTR(y1, y2); L = 1; for (y = y2; y >= y1; y--) { GEN c = gel(y,0); long nc = lg(c)-1; if (nc == 0) continue; L += nc; z = new_chunk(nc) - 1; for (i=1; i<=nc; i++) gel(z,i) = gel(c,i); } z = new_chunk(1); *z = evaltyp(t) | evallg(L); return z; } GEN shallowconcat1(GEN x) { pari_sp av = avma; long lx, t, i; GEN z; switch(typ(x)) { case t_VEC: lx = lg(x); if (lx==1) pari_err_DOMAIN("concat","vector","=",x,x); break; case t_LIST: if (list_typ(x)!=t_LIST_RAW) pari_err_TYPE("concat",x); if (!list_data(x)) pari_err_DOMAIN("concat","vector","=",x,x); x = list_data(x); lx = lg(x); break; default: pari_err_TYPE("concat",x); return NULL; /* LCOV_EXCL_LINE */ } if (lx==2) return gel(x,1); z = gel(x,1); t = typ(z); i = 2; if (is_matvec_t(t) || t == t_VECSMALL || t == t_STR) { /* detect a "homogeneous" object: catmany is faster */ for (; i1) pari_warn(warnmem,"concat: i = %ld", i); z = gerepilecopy(av, z); } } return z; } GEN gconcat1(GEN x) { pari_sp av = avma; return gerepilecopy(av, shallowconcat1(x)); } /* fill M[xoff+i, yoff+j] with the contents of c ( c * Id_n if scalar ) */ static void matfill(GEN M, GEN c, long xoff, long yoff, long n) { long i, j, h, l; l = lg(c); if (l == 1) return; switch(typ(c)) { case t_VEC: for (i = 1; i < l; i++) gcoeff(M,xoff+1,yoff+i) = gel(c,i); break; case t_COL: for (i = 1; i < l; i++) gcoeff(M,xoff+i,yoff+1) = gel(c,i); break; case t_MAT: h = lgcols(c); for (j = 1; j < l; j++) for (i = 1; i < h; i++) gcoeff(M,xoff+i,yoff+j) = gcoeff(c,i,j); break; default: for (i = 1; i <= n; i++) gcoeff(M, xoff+i, yoff+i) = c; break; } } static GEN _matsize(GEN x) { long t = typ(x), L = lg(x) - 1; switch(t) { /* matsize */ case t_VEC: return mkvecsmall2(1, L); case t_COL: return mkvecsmall2(L, 1); case t_MAT: return mkvecsmall2(L? nbrows(x): 0, L); default: if (is_noncalc_t(t)) pari_err_TYPE("_matsize", x); return mkvecsmall2(1, 1); } } GEN shallowmatconcat(GEN v) { long i, j, h, l = lg(v), L = 0, H = 0; GEN M, maxh, maxl; if (l == 1) return cgetg(1,t_MAT); switch(typ(v)) { case t_VEC: for (i = 1; i < l; i++) { GEN c = gel(v,i); GEN s = _matsize(c); H = maxss(H, s[1]); L += s[2]; } M = zeromatcopy(H, L); L = 0; for (i = 1; i < l; i++) { GEN c = gel(v,i); GEN s = _matsize(c); matfill(M, c, 0, L, 1); L += s[2]; } return M; case t_COL: for (i = 1; i < l; i++) { GEN c = gel(v,i); GEN s = _matsize(c); H += s[1]; L = maxss(L, s[2]); } M = zeromatcopy(H, L); H = 0; for (i = 1; i < l; i++) { GEN c = gel(v,i); GEN s = _matsize(c); matfill(M, c, H, 0, 1); H += s[1]; } return M; case t_MAT: h = lgcols(v); maxh = zero_zv(h-1); maxl = zero_zv(l-1); for (j = 1; j < l; j++) for (i = 1; i < h; i++) { GEN c = gcoeff(v,i,j); GEN s = _matsize(c); if (s[1] > maxh[i]) maxh[i] = s[1]; if (s[2] > maxl[j]) maxl[j] = s[2]; } for (i = 1, H = 0; i < h; i++) H += maxh[i]; for (j = 1, L = 0; j < l; j++) L += maxl[j]; M = zeromatcopy(H, L); for (j = 1, L = 0; j < l; j++) { for (i = 1, H = 0; i < h; i++) { GEN c = gcoeff(v,i,j); matfill(M, c, H, L, minss(maxh[i], maxl[j])); H += maxh[i]; } L += maxl[j]; } return M; default: pari_err_TYPE("shallowmatconcat", v); return NULL; } } GEN matconcat(GEN v) { pari_sp av = avma; return gerepilecopy(av, shallowmatconcat(v)); } GEN gconcat(GEN x, GEN y) { long tx, lx,ty,ly,i; GEN z,p1; if (!y) return gconcat1(x); tx = typ(x); ty = typ(y); if (tx==t_STR || ty==t_STR) { pari_sp av = avma; return gerepileuptoleaf(av, strconcat(x,y)); } if (tx==t_LIST || ty==t_LIST) return listconcat(x,y); lx=lg(x); ly=lg(y); if (tx==t_MAT && lx==1) { if (ty!=t_VEC) return gtomat(y); if (ly==1) return cgetg(1, t_MAT); err_cat(x,y); } if (ty==t_MAT && ly==1) { if (tx!=t_VEC) return gtomat(x); if (lx==1) return cgetg(1, t_MAT); err_cat(x,y); } if (tx == ty) { if (tx == t_MAT && lgcols(x) != lgcols(y)) err_cat(x,y); if (!is_matvec_t(tx)) { if (tx != t_VECSMALL) return mkvec2copy(x, y); z = cgetg(lx+ly-1,t_VECSMALL); for (i=1; i=3) break; return (ly==1)? gcopy(x): gconcat(x,gel(y,1)); case t_MAT: z=cgetg(ly,t_MAT); if (lx != ly) break; for (i=1; i=3) break; return (ly==1)? gcopy(x): gconcat(x,gel(y,1)); case t_MAT: if (lx != lgcols(y)) break; z=cgetg(ly+1,t_MAT); gel(z,1) = gcopy(x); for (i=2; i<=ly; i++) gel(z,i) = gcopy(gel(y,i-1)); return z; } break; case t_MAT: switch(ty) { case t_VEC: z=cgetg(lx,t_MAT); if (ly != lx) break; for (i=1; i>1 */ INLINE void Fp_center_inplace(GEN u, GEN p, GEN ps2) { if (abscmpii(u,ps2) > 0) subiiz(u,p,u); } void FpC_center_inplace(GEN z, GEN p, GEN ps2) { long i,l = lg(z); for (i=1; i 1 and 0 < i < lgcols(x) */ static GEN ZMrow_ZC_mul_i(GEN x, GEN y, long lx, long i) { GEN c = mulii(gcoeff(x,i,1), gel(y,1)); long k; for (k = 2; k < lx; k++) { GEN t = mulii(gcoeff(x,i,k), gel(y,k)); if (signe(t)) c = addii(c, t); } return c; } static long zmrow_zc_mul(GEN x, GEN y, long lx, long i) { long k; long c = coeff(x,i,1) * y[1]; for (k = 2; k < lx; k++) c += coeff(x,i,k) * y[k]; return c; } GEN zm_zc_mul(GEN x, GEN y) { long lx = lg(x), l, i; GEN z; if (lx == 1) return cgetg(1, t_VECSMALL); l = lg(gel(x,1)); z = cgetg(l,t_VECSMALL); for (i=1; i= ZM_sw_bound */ static GEN Flm_mul_i(GEN x, GEN y, long l, long lx, long ly, ulong p, ulong pi) { ulong e = expu(p); #ifdef LONG_IS_64BIT long ZM_sw_bound = e <= 29 ? 140: e <=62 ? 40: 70; #else long ZM_sw_bound = e <= 12 ? 230: e <=14 ? 170 : e <=17 ? 110: 120; #endif if (l <= ZM_sw_bound || lx <= ZM_sw_bound || ly <= ZM_sw_bound) return Flm_mul_classical(x, y, l, lx, ly, p, pi); else return Flm_mul_sw(x, y, l - 1, lx - 1, ly - 1, p, pi); } GEN Flm_mul(GEN x, GEN y, ulong p) { long lx=lg(x), ly=lg(y); if (ly==1) return cgetg(1,t_MAT); if (lx==1) return zero_Flm(0, ly-1); return Flm_mul_i(x, y, lgcols(x), lx, ly, p, get_Fl_red(p)); } GEN F2m_mul(GEN x, GEN y) { long i,j,l,lx=lg(x), ly=lg(y); GEN z; if (ly==1) return cgetg(1,t_MAT); z = cgetg(ly,t_MAT); if (lx==1) { for (i=1; ip); } static GEN _Flm_sqr(void *E, GEN x) { return Flm_mul(x,x,((struct _Flm*)E)->p); } static GEN _Flm_one(void *E) { return matid_Flm(((struct _Flm*)E)->n); } GEN Flm_powu(GEN x, ulong n, ulong p) { pari_sp av = avma; struct _Flm d; if (!n) return matid(lg(x)-1); d.p = p; return gerepileupto(av, gen_powu(x, n, (void*)&d, &_Flm_sqr, &_Flm_mul)); } GEN Flm_powers(GEN x, ulong n, ulong p) { pari_sp av = avma; struct _Flm d; d.p = p; d.n = lg(x)-1; return gerepileupto(av, gen_powers(x, n, 1, (void*)&d, &_Flm_sqr, &_Flm_mul, &_Flm_one)); } static GEN _F2m_mul(void *data, GEN x, GEN y) { (void) data; return F2m_mul(x,y); } static GEN _F2m_sqr(void *data, GEN x) { (void) data; return F2m_mul(x,x); } GEN F2m_powu(GEN x, ulong n) { pari_sp av = avma; if (!n) return matid(lg(x)-1); return gerepileupto(av, gen_powu(x, n,NULL, &_F2m_sqr, &_F2m_mul)); } static GEN _FpM_mul(void *p , GEN x, GEN y) { return FpM_mul(x,y,(GEN)p); } static GEN _FpM_sqr(void *p, GEN x) { return FpM_mul(x,x,(GEN)p); } GEN FpM_powu(GEN x, ulong n, GEN p) { pari_sp av = avma; if (!n) return matid(lg(x)-1); if (lgefint(p) == 3) { pari_sp av = avma; ulong pp = uel(p,2); GEN z; if (pp == 2) z = F2m_to_ZM(F2m_powu(ZM_to_F2m(x),n)); else z = Flm_to_ZM(Flm_powu(ZM_to_Flm(x, pp), n, pp)); return gerepileupto(av, z); } return gerepileupto(av, gen_powu(x, n, (void*)p, &_FpM_sqr, &_FpM_mul)); } /*Multiple a column vector by a line vector to make a matrix*/ GEN Flc_Flv_mul(GEN x, GEN y, ulong p) { long i,j, lx=lg(x), ly=lg(y); GEN z; if (ly==1) return cgetg(1,t_MAT); z = cgetg(ly, t_MAT); for (j=1; j < ly; j++) { GEN zj = cgetg(lx,t_VECSMALL); for (i=1; i> 32; #endif c ^= c >> 16; c ^= c >> 8; c ^= c >> 4; c ^= c >> 2; c ^= c >> 1; return c & 1; } GEN FpM_FpC_mul(GEN x, GEN y, GEN p) { long lx = lg(x); return lx==1? cgetg(1,t_COL): FpM_FpC_mul_i(x, y, lx, lgcols(x), p); } GEN Flm_Flc_mul(GEN x, GEN y, ulong p) { long l, lx = lg(x); if (lx==1) return cgetg(1,t_VECSMALL); l = lgcols(x); if (p==2) return Flm_Flc_mul_i_2(x, y, lx, l); else if (SMALL_ULONG(p)) return Flm_Flc_mul_i_SMALL(x, y, lx, l, p); else return Flm_Flc_mul_i(x, y, lx, l, p, get_Fl_red(p)); } GEN Flm_Flc_mul_pre(GEN x, GEN y, ulong p, ulong pi) { long l, lx = lg(x); GEN z; if (lx==1) return cgetg(1,t_VECSMALL); l = lgcols(x); z = cgetg(l, t_VECSMALL); if (SMALL_ULONG(p)) __Flm_Flc_mul_i_SMALL(z, x, y, lx, l, p); else __Flm_Flc_mul_i(z, x, y, lx, l, p, pi); return z; } GEN Flm_Flc_mul_pre_Flx(GEN x, GEN y, ulong p, ulong pi, long sv) { long l, lx = lg(x); GEN z; if (lx==1) return pol0_Flx(sv); l = lgcols(x); z = cgetg(l + 1, t_VECSMALL); z[1] = sv; if (SMALL_ULONG(p)) __Flm_Flc_mul_i_SMALL(z + 1, x, y, lx, l, p); else __Flm_Flc_mul_i(z + 1, x, y, lx, l, p, pi); return Flx_renormalize(z, l + 1); } GEN F2m_F2c_mul(GEN x, GEN y) { long l, lx = lg(x); if (lx==1) return cgetg(1,t_VECSMALL); l = coeff(x,1,1); return F2m_F2c_mul_i(x, y, lx, l); } /* RgV_to_RgX(FpM_FpC_mul(x,y,p), v), p != NULL, memory clean */ GEN FpM_FpC_mul_FpX(GEN x, GEN y, GEN p, long v) { long i, l, lx = lg(x); GEN z; if (lx==1) return pol_0(v); l = lgcols(x); z = new_chunk(l+1); for (i=l-1; i; i--) { pari_sp av = avma; GEN p1 = ZMrow_ZC_mul_i(x,y,lx,i); p1 = modii(p1, p); if (signe(p1)) { if (i != l-1) stackdummy((pari_sp)(z + l+1), (pari_sp)(z + i+2)); gel(z,i+1) = gerepileuptoint(av, p1); break; } avma = av; } if (!i) { avma = (pari_sp)(z + l+1); return pol_0(v); } z[0] = evaltyp(t_POL) | evallg(i+2); z[1] = evalsigne(1) | evalvarn(v); for (; i; i--) { pari_sp av = avma; GEN p1 = ZMrow_ZC_mul_i(x,y,lx,i); gel(z,i+1) = gerepileuptoint(av, modii(p1,p)); } return z; } /********************************************************************/ /** **/ /** TRANSPOSITION **/ /** **/ /********************************************************************/ /* == zm_transpose */ GEN Flm_transpose(GEN x) { long i, dx, lx = lg(x); GEN y; if (lx == 1) return cgetg(1,t_MAT); dx = lgcols(x); y = cgetg(dx,t_MAT); for (i=1; is(E,0); _1 = S->s(E,1); for (i=1; i<=n; i++) { GEN z = const_col(n, _0); gel(z,i) = _1; gel(y, i) = z; } return y; } GEN matid_F2m(long n) { GEN y = cgetg(n+1,t_MAT); long i; if (n < 0) pari_err_DOMAIN("matid_F2m", "dimension","<",gen_0,stoi(n)); for (i=1; i<=n; i++) { gel(y,i) = zero_F2v(n); F2v_set(gel(y,i),i); } return y; } GEN matid_F2xqM(long n, GEN T) { void *E; const struct bb_field *S = get_F2xq_field(&E, T); return gen_matid(n, E, S); } GEN matid_FlxqM(long n, GEN T, ulong p) { void *E; const struct bb_field *S = get_Flxq_field(&E, T, p); return gen_matid(n, E, S); } GEN matid_Flm(long n) { GEN y = cgetg(n+1,t_MAT); long i; if (n < 0) pari_err_DOMAIN("matid_Flm", "dimension","<",gen_0,stoi(n)); for (i=1; i<=n; i++) { gel(y,i) = zero_zv(n); ucoeff(y, i,i) = 1; } return y; } GEN scalar_Flm(long s, long n) { long i; GEN y = cgetg(n+1,t_MAT); for (i=1; i<=n; i++) { gel(y,i) = zero_Flv(n); coeff(y, i,i) = s; } return y; } /********************************************************************/ /** **/ /** CONVERSIONS **/ /** **/ /********************************************************************/ GEN ZV_to_Flv(GEN x, ulong p) { pari_APPLY_ulong(umodiu(gel(x,i), p)) } GEN ZM_to_Flm(GEN x, ulong p) { pari_APPLY_same(ZV_to_Flv(gel(x,i), p)) } GEN ZMV_to_FlmV(GEN x, ulong m) { pari_APPLY_type(t_VEC,ZM_to_Flm(gel(x,i), m)) } /* TO INTMOD */ static GEN to_intmod(GEN x, GEN p) { retmkintmod(modii(x, p), p); } static GEN Fl_to_intmod(ulong x, GEN p) { retmkintmod(utoi(x), p); } GEN Fp_to_mod(GEN z, GEN p) { retmkintmod(modii(z, p), icopy(p)); } /* z in Z[X], return z * Mod(1,p), normalized*/ GEN FpX_to_mod(GEN z, GEN p) { long i,l = lg(z); GEN x; if (l == 2) { x = cgetg(3,t_POL); x[1] = z[1]; gel(x,2) = mkintmod(gen_0,icopy(p)); return x; } x = cgetg(l,t_POL); if (l >2) p = icopy(p); for (i=2; i1) pari_warn(warnmem,"Wiedemann: first loop, %ld",i); W = gerepileupto(av, W); } } b = FpX_renormalize(b, m+2); if (lgpol(b)==0) {avma = btop; continue; } M = FpX_halfgcd(b, pol_xn(m, 0), p); Q = FpX_neg(FpX_normalize(gcoeff(M, 2, 1),p),p); W = B; lQ =lg(Q); if (DEBUGLEVEL) err_printf("Wiedemann: deg. minpoly: %ld\n",lQ-3); V = FpC_Fp_mul(W, gel(Q, lQ-2), p); av = avma; for (i = lQ-3; i > 1; i--) { W = f(E, W); V = ZC_lincomb(gen_1, gel(Q,i), V, W); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"Wiedemann: second loop, %ld",i); gerepileall(av, 2, &V, &W); } } V = FpC_red(V, p); W = FpC_sub(f(E,V), B, p); if (ZV_equal0(W)) return gerepilecopy(ltop, V); av = avma; for (i = 1; i <= n; ++i) { V = W; W = f(E, V); if (ZV_equal0(W)) return gerepilecopy(ltop, shallowtrans(V)); gerepileall(av, 2, &V, &W); } avma = btop; } return NULL; } GEN zMs_ZC_mul(GEN M, GEN B) { long i, j; long n = lg(B)-1; GEN V = zerocol(n); for (i = 1; i <= n; ++i) if (signe(gel(B, i))) { GEN R = gel(M, i), C = gel(R, 1), E = gel(R, 2); long l = lg(C); for (j = 1; j < l; ++j) { long k = C[j]; switch(E[j]) { case 1: gel(V, k) = gel(V,k)==gen_0 ? gel(B,i) : addii(gel(V, k), gel(B,i)); break; case -1: gel(V, k) = gel(V,k)==gen_0 ? negi(gel(B,i)) : subii(gel(V, k), gel(B,i)); break; default: gel(V, k) = gel(V,k)==gen_0 ? mulis(gel(B, i), E[j]) : addii(gel(V, k), mulis(gel(B, i), E[j])); break; } } } return V; } GEN FpMs_FpC_mul(GEN M, GEN B, GEN p) { return FpC_red(zMs_ZC_mul(M, B), p); } GEN ZV_zMs_mul(GEN B, GEN M) { long i, j; long m = lg(M)-1; GEN V = cgetg(m+1,t_VEC); for (i = 1; i <= m; ++i) { GEN R = gel(M, i), C = gel(R, 1), E = gel(R, 2); long l = lg(C); GEN z = mulis(gel(B, C[1]), E[1]); for (j = 2; j < l; ++j) { long k = C[j]; switch(E[j]) { case 1: z = addii(z, gel(B,k)); break; case -1: z = subii(z, gel(B,k)); break; default: z = addii(z, mulis(gel(B,k), E[j])); break; } } gel(V,i) = z; } return V; } GEN FpV_FpMs_mul(GEN B, GEN M, GEN p) { return FpV_red(ZV_zMs_mul(B, M), p); } GEN ZlM_gauss(GEN a, GEN b, ulong p, long e, GEN C) { pari_sp av = avma, av2; GEN xi, xb, pi = gen_1, P; long i; if (!C) { C = Flm_inv(ZM_to_Flm(a, p), p); if (!C) pari_err_INV("ZlM_gauss", a); } P = utoipos(p); av2 = avma; xi = Flm_mul(C, ZM_to_Flm(b, p), p); xb = Flm_to_ZM(xi); for (i = 2; i <= e; i++) { pi = muliu(pi, p); /* = p^(i-1) */ b = ZM_Z_divexact(ZM_sub(b, ZM_nm_mul(a, xi)), P); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZlM_gauss. i=%ld/%ld",i,e); gerepileall(av2,3, &pi,&b,&xb); } xi = Flm_mul(C, ZM_to_Flm(b, p), p); xb = ZM_add(xb, nm_Z_mul(xi, pi)); } return gerepileupto(av, xb); } struct wrapper_modp_s { GEN (*f)(void*, GEN); void *E; GEN p; }; /* compute f(x) mod p */ static GEN wrap_relcomb_modp(void *E, GEN x) { struct wrapper_modp_s *W = (struct wrapper_modp_s*)E; return FpC_red(W->f(W->E, x), W->p); } static GEN wrap_relcomb(void*E, GEN x) { return zMs_ZC_mul((GEN)E, x); } static GEN wrap_relker(void*E, GEN x) { return ZV_zMs_mul(x, (GEN)E); } /* Solve f(X) = B (mod p^e); blackbox version of ZlM_gauss */ GEN gen_ZpM_Dixon(void *E, GEN (*f)(void*, GEN), GEN B, GEN p, long e) { struct wrapper_modp_s W; pari_sp av = avma; GEN xb, xi, pi = gen_1; long i; W.E = E; W.f = f; W.p = p; xi = gen_FpM_Wiedemann((void*)&W, wrap_relcomb_modp, FpC_red(B, p), p); /* f^(-1) B */ if (!xi || e == 1 || typ(xi) == t_VEC) return xi; xb = xi; for (i = 2; i <= e; i++) { pi = mulii(pi, p); /* = p^(i-1) */ B = ZC_Z_divexact(ZC_sub(B, f(E, xi)), p); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_ZpM_Dixon. i=%ld",i); gerepileall(av,3, &pi,&B,&xb); } xi = gen_FpM_Wiedemann((void*)&W, wrap_relcomb_modp, FpC_red(B, p), p); if (!xi) return NULL; if (typ(xi) == t_VEC) return gerepileupto(av, xi); xb = ZC_add(xb, ZC_Z_mul(xi, pi)); } return gerepileupto(av, xb); } static GEN vecprow(GEN A, GEN prow) { return mkvec2(vecsmallpermute(prow,gel(A,1)), gel(A,2)); } /* Solve the equation MX = A. Return either a solution as a t_COL, * or the index of a column which is linearly dependent from the others as a * t_VECSMALL with a single component. */ GEN ZpMs_ZpCs_solve(GEN M, GEN A, long nbrow, GEN p, long e) { pari_sp av = avma; GEN pcol, prow; long nbi=lg(M)-1, lR; long i, n; GEN Mp, Ap, Rp; pari_timer ti; if (DEBUGLEVEL) timer_start(&ti); RgMs_structelim(M, nbrow, gel(A, 1), &pcol, &prow); if (!pcol) { avma = av; return NULL; } if (DEBUGLEVEL) timer_printf(&ti,"structured elimination (%ld -> %ld)",nbi,lg(pcol)-1); n = lg(pcol)-1; Mp = cgetg(n+1, t_MAT); for(i=1; i<=n; i++) gel(Mp, i) = vecprow(gel(M,pcol[i]), prow); Ap = zCs_to_ZC(vecprow(A, prow), n); if (DEBUGLEVEL) timer_start(&ti); Rp = gen_ZpM_Dixon((void*)Mp,wrap_relcomb, Ap, p, e); if (DEBUGLEVEL) timer_printf(&ti,"linear algebra"); if (!Rp) { avma = av; return NULL; } lR = lg(Rp)-1; if (typ(Rp) == t_COL) { GEN R = zerocol(nbi+1); for (i=1; i<=lR; i++) gel(R,pcol[i]) = gel(Rp,i); return gerepilecopy(av, R); } for (i = 1; i <= lR; ++i) if (signe(gel(Rp, i))) return gerepileuptoleaf(av, mkvecsmall(pcol[i])); return NULL; /* LCOV_EXCL_LINE */ } GEN FpMs_FpCs_solve(GEN M, GEN A, long nbrow, GEN p) { return ZpMs_ZpCs_solve(M, A, nbrow, p, 1); } GEN FpMs_FpCs_solve_safe(GEN M, GEN A, long nbrow, GEN p) { GEN res; pari_CATCH(e_INV) { GEN E = pari_err_last(); GEN x = err_get_compo(E,2); if (typ(x) != t_INTMOD) pari_err(0,E); if (DEBUGLEVEL) pari_warn(warner,"FpMs_FpCs_solve_safe, impossible inverse %Ps", x); res = NULL; } pari_TRY { res = ZpMs_ZpCs_solve(M, A, nbrow, p, 1); } pari_ENDCATCH return res; } static GEN FpMs_structelim_back(GEN M, GEN V, GEN prow, GEN p) { long i, j, oldf = 0, f = 0; long lrow = lg(prow), lM = lg(M); GEN W = const_vecsmall(lM-1,1); GEN R = cgetg(lrow, t_VEC); for (i=1; i=2) continue; if (c==1) { pari_sp av = avma; GEN s = gen_0; for(j=1; j %ld)",nbcol,lg(pcol)-1); n = lg(pcol)-1; Mp = cgetg(n+1, t_MAT); for(i=1; i<=n; i++) gel(Mp, i) = vecprow(gel(M,pcol[i]), prow); W.E = (void*) Mp; W.f = wrap_relker; W.p = p; av2 = avma; for(;;) { avma = av2; B = random_FpV(n, p); MB = FpV_FpMs_mul(B, Mp, p); if (DEBUGLEVEL) timer_start(&ti); pari_CATCH(e_INV) { GEN E = pari_err_last(); GEN x = err_get_compo(E,2); if (typ(x) != t_INTMOD) pari_err(0,E); if (DEBUGLEVEL) pari_warn(warner,"FpMs_leftkernel_elt, impossible inverse %Ps", x); Rp = NULL; } pari_TRY { Rp = gen_FpM_Wiedemann((void*)&W, wrap_relcomb_modp, MB, p); } pari_ENDCATCH if (!Rp) continue; if (typ(Rp)==t_COL) { Rp = FpC_sub(Rp,B,p); if (ZV_equal0(Rp)) continue; } R = FpMs_structelim_back(M, Rp, prow, p); if (DEBUGLEVEL) timer_printf(&ti,"Wiedemann left kernel"); return gerepilecopy(av, R); } } GEN FpMs_leftkernel_elt(GEN M, long nbrow, GEN p) { return FpMs_leftkernel_elt_col(M, lg(M)-1, nbrow, p); } pari-2.11.2/src/basemath/ellisog.c0000644000175000017500000013625313447371554015362 0ustar billbill/* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Return 1 if the point Q is a Weierstrass (2-torsion) point of the * curve E, return 0 otherwise */ static long ellisweierstrasspoint(GEN E, GEN Q) { return ell_is_inf(Q) || gequal0(ec_dmFdy_evalQ(E, Q)); } /* Given an elliptic curve E = [a1, a2, a3, a4, a6] and t,w in the ring of * definition of E, return the curve * E' = [a1, a2, a3, a4 - 5t, a6 - (E.b2 t + 7w)] */ static GEN make_velu_curve(GEN E, GEN t, GEN w) { GEN A4, A6, a1 = ell_get_a1(E), a2 = ell_get_a2(E), a3 = ell_get_a3(E); A4 = gsub(ell_get_a4(E), gmulsg(5L, t)); A6 = gsub(ell_get_a6(E), gadd(gmul(ell_get_b2(E), t), gmulsg(7L, w))); return mkvec5(a1,a2,a3,A4,A6); } /* If phi = (f(x)/h(x)^2, g(x,y)/h(x)^3) is an isogeny, return the * variables x and y in a vecsmall */ INLINE void get_isog_vars(GEN phi, long *vx, long *vy) { *vx = varn(gel(phi, 1)); *vy = varn(gel(phi, 2)); if (*vy == *vx) *vy = gvar2(gel(phi,2)); } static GEN RgX_homogenous_evalpow(GEN P, GEN A, GEN B) { pari_sp av = avma; long d, i, v; GEN s; if (typ(P)!=t_POL) return mkvec2(P, gen_1); d = degpol(P); v = varn(A); s = scalarpol_shallow(gel(P, d+2), v); for (i = d-1; i >= 0; i--) { s = gadd(gmul(s, A), gmul(gel(B,d+1-i), gel(P,i+2))); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgX_homogenous_eval(%ld)",i); s = gerepileupto(av, s); } } s = gerepileupto(av, s); return mkvec2(s, gel(B,d+1)); } static GEN RgXQX_homogenous_evalpow(GEN P, GEN A, GEN B, GEN T) { pari_sp av = avma; long i, d = degpol(P), v = varn(A); GEN s; if (signe(P)==0) return mkvec2(pol_0(v), pol_1(v)); s = scalarpol_shallow(gel(P, d+2), v); for (i = d-1; i >= 0; i--) { s = RgX_add(RgXQX_mul(s, A, T), RgXQX_RgXQ_mul(gel(B,d+1-i), gel(P,i+2), T)); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"RgX_homogenous_eval(%ld)",i); s = gerepileupto(av, s); } } s = gerepileupto(av, s); return mkvec2(s, gel(B,d+1)); } /* x must be nonzero */ INLINE long _degree(GEN x) { return typ(x)==t_POL ? degpol(x): 0; } /* Given isogenies F:E' -> E and G:E'' -> E', return the composite * isogeny F o G:E'' -> E */ static GEN ellcompisog(GEN F, GEN G) { pari_sp av = avma; GEN Fv, Gh, Gh2, Gh3, f, g, h, h2, h3, den, num; GEN K, K2, K3, F0, F1, g0, g1, Gp; long v, vx, vy, d; checkellisog(F); checkellisog(G); get_isog_vars(F, &vx, &vy); v = fetch_var_higher(); Fv = shallowcopy(gel(F,3)); setvarn(Fv, v); Gh = gel(G,3); Gh2 = gsqr(Gh); Gh3 = gmul(Gh, Gh2); K = gmul(polresultant0(Fv, deg1pol(gneg(Gh2),gel(G,1), v), v, 0), Gh); delete_var(); K = RgX_normalize(RgX_div(K, RgX_gcd(K,deriv(K,0)))); K2 = gsqr(K); K3 = gmul(K, K2); F0 = polcoeff0(gel(F,2), 0, vy); F1 = polcoeff0(gel(F,2), 1, vy); d = maxss(maxss(degpol(gel(F,1)),_degree(gel(F,3))), maxss(_degree(F0),_degree(F1))); Gp = gpowers(Gh2, d); f = RgX_homogenous_evalpow(gel(F,1), gel(G,1), Gp); g0 = RgX_homogenous_evalpow(F0, gel(G,1), Gp); g1 = RgX_homogenous_evalpow(F1, gel(G,1), Gp); h = RgX_homogenous_evalpow(gel(F,3), gel(G,1), Gp); h2 = mkvec2(gsqr(gel(h,1)), gsqr(gel(h,2))); h3 = mkvec2(gmul(gel(h,1),gel(h2,1)), gmul(gel(h,2),gel(h2,2))); f = gdiv(gmul(gmul(K2, gel(f,1)),gel(h2,2)), gmul(gel(f,2), gel(h2,1))); den = gmul(Gh3, gel(g1,2)); num = gadd(gmul(gel(g0,1),den), gmul(gmul(gel(G,2),gel(g1,1)),gel(g0,2))); g = gdiv(gmul(gmul(K3,num),gel(h3,2)),gmul(gmul(gel(g0,2),den), gel(h3,1))); return gerepilecopy(av, mkvec3(f,g,K)); } static GEN to_RgX(GEN P, long vx) { return typ(P) == t_POL ? lift(P): scalarpol_shallow(lift(P), vx); } static GEN divy(GEN P0, GEN P1, GEN Q, GEN T, long vy) { GEN DP0, P0r = Q_remove_denom(P0, &DP0), P0D; GEN DP1, P1r = Q_remove_denom(P1, &DP1), P1D; GEN DQ, Qr = Q_remove_denom(Q, &DQ), P2; P0D = RgXQX_div(P0r, Qr, T); if (DP0) P0D = gdiv(P0D, DP0); P1D = RgXQX_div(P1r, Qr, T); if (DP1) P1D = gdiv(P1D, DP1); P2 = gadd(gmul(P1D, pol_x(vy)), P0D); if (DQ) P2 = gmul(P2, DQ); return P2; } static GEN ellnfcompisog(GEN nf, GEN F, GEN G) { pari_sp av = avma; GEN Fv, Gh, Gh2, Gh3, f, g, gd, h, h21, h22, h31, h32, den; GEN K, K2, K3, F0, F1, G0, G1, g0, g1, Gp; GEN num0, num1, gn0, gn1; GEN g0d, g01, k3h32; GEN T, res; pari_timer ti; long v, vx, vy, d; if (!nf) return ellcompisog(F, G); T = nf_get_pol(nf); timer_start(&ti); checkellisog(F); checkellisog(G); get_isog_vars(F, &vx, &vy); v = fetch_var_higher(); Fv = shallowcopy(gel(F,3)); setvarn(Fv, v); Gh = lift(gel(G,3)); Gh2 = RgXQX_sqr(Gh, T); Gh3 = RgXQX_mul(Gh, Gh2, T); res = to_RgX(polresultant0(Fv, deg1pol(gmul(gneg(Gh2),gmodulo(gen_1,T)),gel(G,1), v), v, 0),vx); delete_var(); K = Q_remove_denom(RgXQX_mul(res, Gh, T), NULL); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: resultant"); K = RgXQX_div(K, nfgcd(K, deriv(K,0), T, NULL), T); K = RgX_normalize(K); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: nfgcd"); K2 = RgXQX_sqr(K, T); K3 = RgXQX_mul(K, K2, T); F0 = to_RgX(polcoeff0(gel(F,2), 0, vy), vx); F1 = to_RgX(polcoeff0(gel(F,2), 1, vy), vx); G0 = to_RgX(polcoeff0(gel(G,2), 0, vy), vx); G1 = to_RgX(polcoeff0(gel(G,2), 1, vy), vx); d = maxss(maxss(degpol(gel(F,1)),degpol(gel(F,3))),maxss(degpol(F0),degpol(F1))); Gp = RgXQX_powers(Gh2, d, T); f = RgXQX_homogenous_evalpow(to_RgX(gel(F,1),vx), gel(G,1), Gp, T); g0 = RgXQX_homogenous_evalpow(F0, to_RgX(gel(G,1),vx), Gp, T); g1 = RgXQX_homogenous_evalpow(F1, to_RgX(gel(G,1),vx), Gp, T); h = RgXQX_homogenous_evalpow(to_RgX(gel(F,3),vx), gel(G,1), Gp, T); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: evalpow"); h21 = RgXQX_sqr(gel(h,1),T); h22 = RgXQX_sqr(gel(h,2),T); h31 = RgXQX_mul(gel(h,1), h21,T); h32 = RgXQX_mul(gel(h,2), h22,T); if (DEBUGLEVEL) timer_printf(&ti,"h"); f = RgXQX_div(RgXQX_mul(RgXQX_mul(K2, gel(f,1), T), h22, T), RgXQX_mul(gel(f,2), h21, T), T); if (DEBUGLEVEL) timer_printf(&ti,"f"); den = RgXQX_mul(Gh3, gel(g1,2), T); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: den"); g0d = RgXQX_mul(gel(g0,1),den, T); g01 = RgXQX_mul(gel(g1,1),gel(g0,2),T); num0 = RgX_add(g0d, RgXQX_mul(G0,g01, T)); num1 = RgXQX_mul(G1,g01, T); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: num"); k3h32 = RgXQX_mul(K3,h32,T); gn0 = RgXQX_mul(num0, k3h32, T); gn1 = RgXQX_mul(num1, k3h32, T); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: gn"); gd = RgXQX_mul(RgXQX_mul(gel(g0,2), den, T), h31, T); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: gd"); g = divy(gn0, gn1, gd, T, vy); if (DEBUGLEVEL) timer_printf(&ti,"ellnfcompisog: divy"); return gerepilecopy(av, gmul(mkvec3(f,g,K),gmodulo(gen_1,T))); } /* Given an isogeny phi from ellisogeny() and a point P in the domain of phi, * return phi(P) */ GEN ellisogenyapply(GEN phi, GEN P) { pari_sp ltop = avma; GEN f, g, h, img_f, img_g, img_h, img_h2, img_h3, img, tmp; long vx, vy; if (lg(P) == 4) return ellcompisog(phi,P); checkellisog(phi); checkellpt(P); if (ell_is_inf(P)) return ellinf(); f = gel(phi, 1); g = gel(phi, 2); h = gel(phi, 3); get_isog_vars(phi, &vx, &vy); img_h = poleval(h, gel(P, 1)); if (gequal0(img_h)) { avma = ltop; return ellinf(); } img_h2 = gsqr(img_h); img_h3 = gmul(img_h, img_h2); img_f = poleval(f, gel(P, 1)); /* FIXME: This calculation of g is perhaps not as efficient as it could be */ tmp = gsubst(g, vx, gel(P, 1)); img_g = gsubst(tmp, vy, gel(P, 2)); img = cgetg(3, t_VEC); gel(img, 1) = gdiv(img_f, img_h2); gel(img, 2) = gdiv(img_g, img_h3); return gerepileupto(ltop, img); } /* isog = [f, g, h] = [x, y, 1] = identity */ static GEN isog_identity(long vx, long vy) { return mkvec3(pol_x(vx), pol_x(vy), pol_1(vx)); } /* Returns an updated value for isog based (primarily) on tQ and uQ. Used to * iteratively compute the isogeny corresponding to a subgroup generated by a * given point. Ref: Equation 8 in Velu's paper. * isog = NULL codes the identity */ static GEN update_isogeny_polys(GEN isog, GEN E, GEN Q, GEN tQ, GEN uQ, long vx, long vy) { pari_sp ltop = avma, av; GEN xQ = gel(Q, 1), yQ = gel(Q, 2); GEN rt = deg1pol_shallow(gen_1, gneg(xQ), vx); GEN a1 = ell_get_a1(E), a3 = ell_get_a3(E); GEN gQx = ec_dFdx_evalQ(E, Q); GEN gQy = ec_dFdy_evalQ(E, Q); GEN tmp1, tmp2, tmp3, tmp4, f, g, h, rt_sqr, res; /* g -= uQ * (2 * y + E.a1 * x + E.a3) * + tQ * rt * (E.a1 * rt + y - yQ) * + rt * (E.a1 * uQ - gQx * gQy) */ av = avma; tmp1 = gmul(uQ, gadd(deg1pol_shallow(gen_2, gen_0, vy), deg1pol_shallow(a1, a3, vx))); tmp1 = gerepileupto(av, tmp1); av = avma; tmp2 = gmul(tQ, gadd(gmul(a1, rt), deg1pol_shallow(gen_1, gneg(yQ), vy))); tmp2 = gerepileupto(av, tmp2); av = avma; tmp3 = gsub(gmul(a1, uQ), gmul(gQx, gQy)); tmp3 = gerepileupto(av, tmp3); if (!isog) isog = isog_identity(vx,vy); f = gel(isog, 1); g = gel(isog, 2); h = gel(isog, 3); rt_sqr = gsqr(rt); res = cgetg(4, t_VEC); av = avma; tmp4 = gdiv(gadd(gmul(tQ, rt), uQ), rt_sqr); gel(res, 1) = gerepileupto(av, gadd(f, tmp4)); av = avma; tmp4 = gadd(tmp1, gmul(rt, gadd(tmp2, tmp3))); gel(res, 2) = gerepileupto(av, gsub(g, gdiv(tmp4, gmul(rt, rt_sqr)))); av = avma; gel(res, 3) = gerepileupto(av, gmul(h, rt)); return gerepileupto(ltop, res); } /* Given a point P on E, return the curve E/

and, if only_image is zero, * the isogeny pi: E -> E/

. The variables vx and vy are used to describe * the isogeny (ignored if only_image is zero) */ static GEN isogeny_from_kernel_point(GEN E, GEN P, int only_image, long vx, long vy) { pari_sp av = avma; GEN isog, EE, f, g, h, h2, h3; GEN Q = P, t = gen_0, w = gen_0; long c; if (!oncurve(E,P)) pari_err_DOMAIN("isogeny_from_kernel_point", "point", "not on", E, P); if (ell_is_inf(P)) { if (only_image) return E; return mkvec2(E, isog_identity(vx,vy)); } isog = NULL; c = 1; for (;;) { GEN tQ, xQ = gel(Q,1), uQ = ec_2divpol_evalx(E, xQ); int stop = 0; if (ellisweierstrasspoint(E,Q)) { /* ord(P)=2c; take Q=[c]P into consideration and stop */ tQ = ec_dFdx_evalQ(E, Q); stop = 1; } else tQ = ec_half_deriv_2divpol_evalx(E, xQ); t = gadd(t, tQ); w = gadd(w, gadd(uQ, gmul(tQ, xQ))); if (!only_image) isog = update_isogeny_polys(isog, E, Q,tQ,uQ, vx,vy); if (stop) break; Q = elladd(E, P, Q); ++c; /* IF x([c]P) = x([c-1]P) THEN [c]P = -[c-1]P and [2c-1]P = 0 */ if (gequal(gel(Q,1), xQ)) break; if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"isogeny_from_kernel_point"); gerepileall(av, isog? 4: 3, &Q, &t, &w, &isog); } } EE = make_velu_curve(E, t, w); if (only_image) return EE; if (!isog) isog = isog_identity(vx,vy); f = gel(isog, 1); g = gel(isog, 2); if ( ! (typ(f) == t_RFRAC && typ(g) == t_RFRAC)) pari_err_BUG("isogeny_from_kernel_point (f or g has wrong type)"); /* Clean up the isogeny polynomials f, g and h so that the isogeny * is given by (x,y) -> (f(x)/h(x)^2, g(x,y)/h(x)^3) */ h = gel(isog, 3); h2 = gsqr(h); h3 = gmul(h, h2); f = gmul(f, h2); g = gmul(g, h3); if (typ(f) != t_POL || typ(g) != t_POL) pari_err_BUG("isogeny_from_kernel_point (wrong denominator)"); return mkvec2(EE, mkvec3(f,g, gel(isog,3))); } /* Given a t_POL x^n - s1 x^{n-1} + s2 x^{n-2} - s3 x^{n-3} + ... * return the first three power sums (Newton's identities): * p1 = s1 * p2 = s1^2 - 2 s2 * p3 = (s1^2 - 3 s2) s1 + 3 s3 */ static void first_three_power_sums(GEN pol, GEN *p1, GEN *p2, GEN *p3) { long d = degpol(pol); GEN s1, s2, ms3; *p1 = s1 = gneg(RgX_coeff(pol, d-1)); s2 = RgX_coeff(pol, d-2); *p2 = gsub(gsqr(s1), gmulsg(2L, s2)); ms3 = RgX_coeff(pol, d-3); *p3 = gadd(gmul(s1, gsub(*p2, s2)), gmulsg(-3L, ms3)); } /* Let E and a t_POL h of degree 1 or 3 whose roots are 2-torsion points on E. * - if only_image != 0, return [t, w] used to compute the equation of the * quotient by the given 2-torsion points * - else return [t,w, f,g,h], along with the contributions f, g and * h to the isogeny giving the quotient by h. Variables vx and vy are used * to create f, g and h, or ignored if only_image is zero */ /* deg h = 1; 2-torsion contribution from Weierstrass point */ static GEN contrib_weierstrass_pt(GEN E, GEN h, long only_image, long vx, long vy) { GEN p = ellbasechar(E); GEN a1 = ell_get_a1(E); GEN a3 = ell_get_a3(E); GEN x0 = gneg(constant_coeff(h)); /* h = x - x0 */ GEN b = gadd(gmul(a1,x0), a3); GEN y0, Q, t, w, t1, t2, f, g; if (!equalis(p, 2L)) /* char(k) != 2 ==> y0 = -b/2 */ y0 = gmul2n(gneg(b), -1); else { /* char(k) = 2 ==> y0 = sqrt(f(x0)) where E is y^2 + h(x) = f(x). */ if (!gequal0(b)) pari_err_BUG("two_torsion_contrib (a1*x0+a3 != 0)"); y0 = gsqrt(ec_f_evalx(E, x0), 0); } Q = mkvec2(x0, y0); t = ec_dFdx_evalQ(E, Q); w = gmul(x0, t); if (only_image) return mkvec2(t,w); /* Compute isogeny, f = (x - x0) * t */ f = deg1pol_shallow(t, gmul(t, gneg(x0)), vx); /* g = (x - x0) * t * (a1 * (x - x0) + (y - y0)) */ t1 = deg1pol_shallow(a1, gmul(a1, gneg(x0)), vx); t2 = deg1pol_shallow(gen_1, gneg(y0), vy); g = gmul(f, gadd(t1, t2)); return mkvec5(t, w, f, g, h); } /* deg h =3; full 2-torsion contribution. NB: assume h is monic; base field * characteristic is odd or zero (cannot happen in char 2).*/ static GEN contrib_full_tors(GEN E, GEN h, long only_image, long vx, long vy) { GEN p1, p2, p3, half_b2, half_b4, t, w, f, g; first_three_power_sums(h, &p1,&p2,&p3); half_b2 = gmul2n(ell_get_b2(E), -1); half_b4 = gmul2n(ell_get_b4(E), -1); /* t = 3*(p2 + b4/2) + p1 * b2/2 */ t = gadd(gmulsg(3L, gadd(p2, half_b4)), gmul(p1, half_b2)); /* w = 3 * p3 + p2 * b2/2 + p1 * b4/2 */ w = gadd(gmulsg(3L, p3), gadd(gmul(p2, half_b2), gmul(p1, half_b4))); if (only_image) return mkvec2(t,w); /* Compute isogeny */ { GEN a1 = ell_get_a1(E), a3 = ell_get_a3(E), t1, t2; GEN s1 = gneg(RgX_coeff(h, 2)); GEN dh = RgX_deriv(h); GEN psi2xy = gadd(deg1pol_shallow(a1, a3, vx), deg1pol_shallow(gen_2, gen_0, vy)); /* f = -3 (3 x + b2/2 + s1) h + (3 x^2 + (b2/2) x + (b4/2)) h'*/ t1 = RgX_mul(h, gmulsg(-3, deg1pol(stoi(3), gadd(half_b2, s1), vx))); t2 = mkpoln(3, stoi(3), half_b2, half_b4); setvarn(t2, vx); t2 = RgX_mul(dh, t2); f = RgX_add(t1, t2); /* 2g = psi2xy * (f'*h - f*h') - (a1*f + a3*h) * h; */ t1 = RgX_sub(RgX_mul(RgX_deriv(f), h), RgX_mul(f, dh)); t2 = RgX_mul(h, RgX_add(RgX_Rg_mul(f, a1), RgX_Rg_mul(h, a3))); g = RgX_divs(gsub(gmul(psi2xy, t1), t2), 2L); f = RgX_mul(f, h); g = RgX_mul(g, h); } return mkvec5(t, w, f, g, h); } /* Given E and a t_POL T whose roots define a subgroup G of E, return the factor * of T that corresponds to the 2-torsion points E[2] \cap G in G */ INLINE GEN two_torsion_part(GEN E, GEN T) { return RgX_gcd(T, elldivpol(E, 2, varn(T))); } /* Return the jth Hasse derivative of the polynomial f = \sum_{i=0}^n a_i x^i, * i.e. \sum_{i=j}^n a_i \binom{i}{j} x^{i-j}. It is a derivation even when the * coefficient ring has positive characteristic */ static GEN derivhasse(GEN f, ulong j) { ulong i, d = degpol(f); GEN df; if (gequal0(f) || d == 0) return pol_0(varn(f)); if (j == 0) return gcopy(f); df = cgetg(2 + (d-j+1), t_POL); df[1] = f[1]; for (i = j; i <= d; ++i) gel(df, i-j+2) = gmul(binomialuu(i,j), gel(f, i+2)); return normalizepol(df); } static GEN non_two_torsion_abscissa(GEN E, GEN h0, GEN x) { GEN mp1, dh0, ddh0, t, u, t1, t2, t3; long m = degpol(h0); mp1 = gel(h0, m + 1); /* negative of first power sum */ dh0 = RgX_deriv(h0); ddh0 = RgX_deriv(dh0); t = ec_2divpol_evalx(E, x); u = ec_half_deriv_2divpol_evalx(E, x); t1 = RgX_sub(RgX_sqr(dh0), RgX_mul(ddh0, h0)); t2 = RgX_mul(u, RgX_mul(h0, dh0)); t3 = RgX_mul(RgX_sqr(h0), deg1pol_shallow(stoi(2*m), gmulsg(2L, mp1), varn(x))); /* t * (dh0^2 - ddh0*h0) - u*dh0*h0 + (2*m*x - 2*s1) * h0^2); */ return RgX_add(RgX_sub(RgX_mul(t, t1), t2), t3); } static GEN isog_abscissa(GEN E, GEN kerp, GEN h0, GEN x, GEN two_tors) { GEN f0, f2, h2, t1, t2, t3; f0 = (degpol(h0) > 0)? non_two_torsion_abscissa(E, h0, x): pol_0(varn(x)); f2 = gel(two_tors, 3); h2 = gel(two_tors, 5); /* Combine f0 and f2 into the final abscissa of the isogeny. */ t1 = RgX_mul(x, RgX_sqr(kerp)); t2 = RgX_mul(f2, RgX_sqr(h0)); t3 = RgX_mul(f0, RgX_sqr(h2)); /* x * kerp^2 + f2 * h0^2 + f0 * h2^2 */ return RgX_add(t1, RgX_add(t2, t3)); } static GEN non_two_torsion_ordinate_char_not2(GEN E, GEN f, GEN h, GEN psi2) { GEN a1 = ell_get_a1(E), a3 = ell_get_a3(E); GEN df = RgX_deriv(f), dh = RgX_deriv(h); /* g = df * h * psi2/2 - f * dh * psi2 * - (E.a1 * f + E.a3 * h^2) * h/2 */ GEN t1 = RgX_mul(df, RgX_mul(h, RgX_divs(psi2, 2L))); GEN t2 = RgX_mul(f, RgX_mul(dh, psi2)); GEN t3 = RgX_mul(RgX_divs(h, 2L), RgX_add(RgX_Rg_mul(f, a1), RgX_Rg_mul(RgX_sqr(h), a3))); return RgX_sub(RgX_sub(t1, t2), t3); } /* h = kerq */ static GEN non_two_torsion_ordinate_char2(GEN E, GEN h, GEN x, GEN y) { GEN a1 = ell_get_a1(E), a3 = ell_get_a3(E), a4 = ell_get_a4(E); GEN b2 = ell_get_b2(E), b4 = ell_get_b4(E), b6 = ell_get_b6(E); GEN h2, dh, dh2, ddh, D2h, D2dh, H, psi2, u, t, alpha; GEN p1, t1, t2, t3, t4; long m, vx = varn(x); h2 = RgX_sqr(h); dh = RgX_deriv(h); dh2 = RgX_sqr(dh); ddh = RgX_deriv(dh); H = RgX_sub(dh2, RgX_mul(h, ddh)); D2h = derivhasse(h, 2); D2dh = derivhasse(dh, 2); psi2 = deg1pol_shallow(a1, a3, vx); u = mkpoln(3, b2, gen_0, b6); setvarn(u, vx); t = deg1pol_shallow(b2, b4, vx); alpha = mkpoln(4, a1, a3, gmul(a1, a4), gmul(a3, a4)); setvarn(alpha, vx); m = degpol(h); p1 = RgX_coeff(h, m-1); /* first power sum */ t1 = gmul(gadd(gmul(a1, p1), gmulgs(a3, m)), RgX_mul(h,h2)); t2 = gmul(a1, gadd(gmul(a1, gadd(y, psi2)), RgX_add(RgX_Rg_add(RgX_sqr(x), a4), t))); t2 = gmul(t2, gmul(dh, h2)); t3 = gadd(gmul(y, t), RgX_add(alpha, RgX_Rg_mul(u, a1))); t3 = gmul(t3, RgX_mul(h, H)); t4 = gmul(u, psi2); t4 = gmul(t4, RgX_sub(RgX_sub(RgX_mul(h2, D2dh), RgX_mul(dh, H)), RgX_mul(h, RgX_mul(dh, D2h)))); return gadd(t1, gadd(t2, gadd(t3, t4))); } static GEN isog_ordinate(GEN E, GEN kerp, GEN kerq, GEN x, GEN y, GEN two_tors, GEN f) { GEN g; if (! equalis(ellbasechar(E), 2L)) { /* FIXME: We don't use (hence don't need to calculate) * g2 = gel(two_tors, 4) when char(k) != 2. */ GEN psi2 = ec_dmFdy_evalQ(E, mkvec2(x, y)); g = non_two_torsion_ordinate_char_not2(E, f, kerp, psi2); } else { GEN h2 = gel(two_tors, 5); GEN g2 = gmul(gel(two_tors, 4), RgX_mul(kerq, RgX_sqr(kerq))); GEN g0 = non_two_torsion_ordinate_char2(E, kerq, x, y); g0 = gmul(g0, RgX_mul(h2, RgX_sqr(h2))); g = gsub(gmul(y, RgX_mul(kerp, RgX_sqr(kerp))), gadd(g2, g0)); } return g; } /* Given an elliptic curve E and a polynomial kerp whose roots give the * x-coordinates of a subgroup G of E, return the curve E/G and, * if only_image is zero, the isogeny pi:E -> E/G. Variables vx and vy are * used to describe the isogeny (and are ignored if only_image is zero). */ static GEN isogeny_from_kernel_poly(GEN E, GEN kerp, long only_image, long vx, long vy) { long m; GEN b2 = ell_get_b2(E), b4 = ell_get_b4(E), b6 = ell_get_b6(E); GEN p1, p2, p3, x, y, f, g, two_tors, EE, t, w; GEN kerh = two_torsion_part(E, kerp); GEN kerq = RgX_divrem(kerp, kerh, ONLY_DIVIDES); if (!kerq) pari_err_BUG("isogeny_from_kernel_poly"); /* isogeny degree: 2*degpol(kerp)+1-degpol(kerh) */ m = degpol(kerq); kerp = RgX_normalize(kerp); kerq = RgX_normalize(kerq); kerh = RgX_normalize(kerh); switch(degpol(kerh)) { case 0: two_tors = only_image? mkvec2(gen_0, gen_0): mkvec5(gen_0, gen_0, pol_0(vx), pol_0(vx), pol_1(vx)); break; case 1: two_tors = contrib_weierstrass_pt(E, kerh, only_image,vx,vy); break; case 3: two_tors = contrib_full_tors(E, kerh, only_image,vx,vy); break; default: two_tors = NULL; pari_err_DOMAIN("isogeny_from_kernel_poly", "kernel polynomial", "does not define a subgroup of", E, kerp); } first_three_power_sums(kerq,&p1,&p2,&p3); x = pol_x(vx); y = pol_x(vy); /* t = 6 * p2 + b2 * p1 + m * b4, */ t = gadd(gmulsg(6L, p2), gadd(gmul(b2, p1), gmulsg(m, b4))); /* w = 10 * p3 + 2 * b2 * p2 + 3 * b4 * p1 + m * b6, */ w = gadd(gmulsg(10L, p3), gadd(gmul(gmulsg(2L, b2), p2), gadd(gmul(gmulsg(3L, b4), p1), gmulsg(m, b6)))); EE = make_velu_curve(E, gadd(t, gel(two_tors, 1)), gadd(w, gel(two_tors, 2))); if (only_image) return EE; f = isog_abscissa(E, kerp, kerq, x, two_tors); g = isog_ordinate(E, kerp, kerq, x, y, two_tors, f); return mkvec2(EE, mkvec3(f,g,kerp)); } /* Given an elliptic curve E and a subgroup G of E, return the curve * E/G and, if only_image is zero, the isogeny corresponding * to the canonical surjection pi:E -> E/G. The variables vx and * vy are used to describe the isogeny (and are ignored if * only_image is zero). The subgroup G may be given either as * a generating point P on E or as a polynomial kerp whose roots are * the x-coordinates of the points in G */ GEN ellisogeny(GEN E, GEN G, long only_image, long vx, long vy) { pari_sp av = avma; GEN j, z; checkell(E);j = ell_get_j(E); if (vx < 0) vx = 0; if (vy < 0) vy = 1; if (varncmp(vx, vy) >= 0) pari_err_PRIORITY("ellisogeny", pol_x(vx), "<=", vy); if (!only_image && varncmp(vy, gvar(j)) >= 0) pari_err_PRIORITY("ellisogeny", j, ">=", vy); switch(typ(G)) { case t_VEC: checkellpt(G); if (!ell_is_inf(G)) { GEN x = gel(G,1), y = gel(G,2); if (!only_image) { if (varncmp(vy, gvar(x)) >= 0) pari_err_PRIORITY("ellisogeny", x, ">=", vy); if (varncmp(vy, gvar(y)) >= 0) pari_err_PRIORITY("ellisogeny", y, ">=", vy); } } z = isogeny_from_kernel_point(E, G, only_image, vx, vy); break; case t_POL: if (!only_image && varncmp(vy, gvar(constant_coeff(G))) >= 0) pari_err_PRIORITY("ellisogeny", constant_coeff(G), ">=", vy); z = isogeny_from_kernel_poly(E, G, only_image, vx, vy); break; default: z = NULL; pari_err_TYPE("ellisogeny", G); } return gerepilecopy(av, z); } static GEN trivial_isogeny(void) { return mkvec3(pol_x(0), scalarpol(pol_x(1), 0), pol_1(0)); } static GEN isogeny_a4a6(GEN E) { GEN a1 = ell_get_a1(E), a3 = ell_get_a3(E), b2 = ell_get_b2(E); retmkvec3(deg1pol(gen_1, gdivgs(b2, 12), 0), deg1pol(gdivgs(a1,2), deg1pol(gen_1, gdivgs(a3,2), 1), 0), pol_1(0)); } static GEN invisogeny_a4a6(GEN E) { GEN a1 = ell_get_a1(E), a3 = ell_get_a3(E), b2 = ell_get_b2(E); retmkvec3(deg1pol(gen_1, gdivgs(b2, -12), 0), deg1pol(gdivgs(a1,-2), deg1pol(gen_1, gadd(gdivgs(a3,-2), gdivgs(gmul(b2,a1), 24)), 1), 0), pol_1(0)); } static GEN RgXY_eval(GEN P, GEN x, GEN y) { return poleval(poleval(P,x), y); } static GEN twistisogeny(GEN iso, GEN d) { GEN d2 = gsqr(d), d3 = gmul(d, d2); return mkvec3(gdiv(gel(iso,1), d2), gdiv(gel(iso,2), d3), gel(iso, 3)); } static GEN ellisog_by_Kohel(GEN a4, GEN a6, long n, GEN ker, GEN kert, long flag) { GEN E = ellinit(mkvec2(a4, a6), NULL, DEFAULTPREC); GEN F = isogeny_from_kernel_poly(E, ker, flag, 0, 1); GEN Et = ellinit(flag ? F: gel(F, 1), NULL, DEFAULTPREC); GEN c4t = ell_get_c4(Et), c6t = ell_get_c6(Et), jt = ell_get_j(Et); if (!flag) { GEN Ft = isogeny_from_kernel_poly(Et, kert, flag, 0, 1); GEN isot = twistisogeny(gel(Ft, 2), stoi(n)); return mkvec5(c4t, c6t, jt, gel(F, 2), isot); } else return mkvec3(c4t, c6t, jt); } static GEN ellisog_by_roots(GEN a4, GEN a6, long n, GEN z, long flag) { GEN k = deg1pol_shallow(gen_1, gneg(z), 0); GEN kt= deg1pol_shallow(gen_1, gmulsg(n,z), 0); return ellisog_by_Kohel(a4, a6, n, k, kt, flag); } /* n = 2 or 3 */ static GEN a4a6_divpol(GEN a4, GEN a6, long n) { if (n == 2) return mkpoln(4, gen_1, gen_0, a4, a6); return mkpoln(5, utoi(3), gen_0, gmulgs(a4,6) , gmulgs(a6,12), gneg(gsqr(a4))); } static GEN ellisograph_Kohel_iso(GEN nf, GEN e, long n, GEN z, GEN *pR, long flag) { long i, r; GEN R, V, c4 = gel(e,1), c6 = gel(e,2); GEN a4 = gdivgs(c4, -48), a6 = gdivgs(c6, -864); GEN P = a4a6_divpol(a4, a6, n); R = nfroots(nf, z ? RgX_div_by_X_x(P, z, NULL): P); if (pR) *pR = R; r = lg(R); V = cgetg(r, t_VEC); for (i=1; i < r; i++) gel(V,i) = ellisog_by_roots(a4, a6, n, gel(R,i), flag); return V; } static GEN ellisograph_Kohel_r(GEN nf, GEN e, long n, GEN z, long flag) { GEN R, iso = ellisograph_Kohel_iso(nf, e, n, z, &R, flag); long i, r = lg(iso); GEN V = cgetg(r, t_VEC); for (i=1; i < r; i++) gel(V,i) = ellisograph_Kohel_r(nf, gel(iso,i), n, gmulgs(gel(R,i), -n), flag); return mkvec2(e, V); } static GEN corr(GEN c4, GEN c6) { GEN c62 = gmul2n(c6, 1); return gadd(gdiv(gsqr(c4), c62), gdiv(c62, gmulgs(c4,3))); } static GEN elkies98(GEN a4, GEN a6, long l, GEN s, GEN a4t, GEN a6t) { GEN C, P, S; long i, n, d; d = l == 2 ? 1 : l>>1; C = cgetg(d+1, t_VEC); gel(C, 1) = gdivgs(gsub(a4, a4t), 5); if (d >= 2) gel(C, 2) = gdivgs(gsub(a6, a6t), 7); if (d >= 3) gel(C, 3) = gdivgs(gsub(gsqr(gel(C, 1)), gmul(a4, gel(C, 1))), 3); for (n = 3; n < d; ++n) { GEN s = gen_0; for (i = 1; i < n; i++) s = gadd(s, gmul(gel(C, i), gel(C, n-i))); gel(C, n+1) = gdivgs(gsub(gsub(gmulsg(3, s), gmul(gmulsg((2*n-1)*(n-1), a4), gel(C, n-1))), gmul(gmulsg((2*n-2)*(n-2), a6), gel(C, n-2))), (n-1)*(2*n+5)); } P = cgetg(d+2, t_VEC); gel(P, 1 + 0) = stoi(d); gel(P, 1 + 1) = s; if (d >= 2) gel(P, 1 + 2) = gdivgs(gsub(gel(C, 1), gmulgs(gmulsg(2, a4), d)), 6); for (n = 2; n < d; ++n) gel(P, 1 + n+1) = gdivgs(gsub(gsub(gel(C, n), gmul(gmulsg(4*n-2, a4), gel(P, 1+n-1))), gmul(gmulsg(4*n-4, a6), gel(P, 1+n-2))), 4*n+2); S = cgetg(d+3, t_POL); S[1] = evalsigne(1) | evalvarn(0); gel(S, 2 + d - 0) = gen_1; gel(S, 2 + d - 1) = gneg(s); for (n = 2; n <= d; ++n) { GEN s = gen_0; for (i = 1; i <= n; ++i) { GEN p = gmul(gel(P, 1+i), gel(S, 2 + d - (n-i))); s = gadd(s, p); } gel(S, 2 + d - n) = gdivgs(s, -n); } return S; } static GEN ellisog_by_jt(GEN c4, GEN c6, GEN jt, GEN jtp, GEN s0, long n, long flag) { GEN jtp2 = gsqr(jtp), den = gmul(jt, gsubgs(jt, 1728)); GEN c4t = gdiv(jtp2, den); GEN c6t = gdiv(gmul(jtp, c4t), jt); if (flag) return mkvec3(c4t, c6t, jt); else { GEN co = corr(c4, c6); GEN cot = corr(c4t, c6t); GEN s = gmul2n(gmulgs(gadd(gadd(s0, co), gmulgs(cot,-n)), -n), -2); GEN a4 = gdivgs(c4, -48), a6 = gdivgs(c6, -864); GEN a4t = gmul(gdivgs(c4t, -48), powuu(n,4)), a6t = gmul(gdivgs(c6t, -864), powuu(n,6)); GEN ker = elkies98(a4, a6, n, s, a4t, a6t); GEN st = gmulgs(s, -n); GEN a4tt = gmul(a4,powuu(n,4)), a6tt = gmul(a6,powuu(n,6)); GEN kert = elkies98(a4t, a6t, n, st, a4tt, a6tt); return ellisog_by_Kohel(a4, a6, n, ker, kert, flag); } } /* Based on RENE SCHOOF Counting points on elliptic curves over finite fields Journal de Theorie des Nombres de Bordeaux, tome 7, no 1 (1995), p. 219-254. */ static GEN ellisog_by_j(GEN e, GEN jt, long n, GEN P, long flag) { pari_sp av = avma; GEN c4 = gel(e,1), c6 = gel(e, 2), j = gel(e, 3); GEN Px = deriv(P, 0), Py = deriv(P, 1); GEN Pxj = RgXY_eval(Px, j, jt), Pyj = RgXY_eval(Py, j, jt); GEN Pxx = deriv(Px, 0), Pxy = deriv(Py, 0), Pyy = deriv(Py, 1); GEN Pxxj = RgXY_eval(Pxx,j,jt); GEN Pxyj = RgXY_eval(Pxy,j,jt); GEN Pyyj = RgXY_eval(Pyy,j,jt); GEN c6c4 = gdiv(c6, c4); GEN jp = gmul(j, c6c4); GEN jtp = gdivgs(gmul(jp, gdiv(Pxj, Pyj)), -n); GEN jtpn = gmulgs(jtp, n); GEN s0 = gdiv(gadd(gadd(gmul(gsqr(jp),Pxxj),gmul(gmul(jp,jtpn),gmul2n(Pxyj,1))), gmul(gsqr(jtpn),Pyyj)),gmul(jp,Pxj)); GEN et = ellisog_by_jt(c4, c6, jt, jtp, s0, n, flag); return gerepilecopy(av, et); } static GEN ellisograph_iso(GEN nf, GEN e, ulong p, GEN P, GEN oj, long flag) { long i, r; GEN Pj, R, V; if (!P) return ellisograph_Kohel_iso(nf, e, p, oj, NULL, flag); Pj = poleval(P, gel(e,3)); R = nfroots(nf,oj ? RgX_div_by_X_x(Pj, oj, NULL):Pj); r = lg(R); V = cgetg(r, t_VEC); for (i=1; i < r; i++) gel(V, i) = ellisog_by_j(e, gel(R, i), p, P, flag); return V; } static GEN ellisograph_r(GEN nf, GEN e, ulong p, GEN P, GEN oj, long flag) { GEN j = gel(e,3), iso = ellisograph_iso(nf, e, p, P, oj, flag); long i, r = lg(iso); GEN V = cgetg(r, t_VEC); for (i=1; i < r; i++) gel(V,i) = ellisograph_r(nf, gel(iso,i), p, P, j, flag); return mkvec2(e, V); } static GEN ellisograph_a4a6(GEN E, long flag) { GEN c4 = ell_get_c4(E), c6 = ell_get_c6(E), j = ell_get_j(E); return flag ? mkvec3(c4, c6, j): mkvec5(c4, c6, j, isogeny_a4a6(E), invisogeny_a4a6(E)); } static GEN ellisograph_dummy(GEN E, long n, GEN jt, GEN jtt, GEN s0, long flag) { GEN c4 = ell_get_c4(E), c6 = ell_get_c6(E), c6c4 = gdiv(c6, c4); GEN jtp = gmul(c6c4, gdivgs(gmul(jt, jtt), -n)); GEN iso = ellisog_by_jt(c4, c6, jt, jtp, gmul(s0, c6c4), n, flag); GEN v = mkvec2(iso, cgetg(1, t_VEC)); return mkvec2(ellisograph_a4a6(E, flag), mkvec(v)); } static GEN isograph_p(GEN nf, GEN e, ulong p, GEN P, long flag) { pari_sp av = avma; GEN iso; if (P) iso = ellisograph_r(nf, e, p, P, NULL, flag); else iso = ellisograph_Kohel_r(nf, e, p, NULL, flag); return gerepilecopy(av, iso); } static GEN get_polmodular(ulong p) { return p > 3 ? polmodular_ZXX(p,0,0,1): NULL; } static GEN ellisograph_p(GEN nf, GEN E, ulong p, long flag) { GEN e = ellisograph_a4a6(E, flag); GEN P = get_polmodular(p); return isograph_p(nf, e, p, P, flag); } static long etree_nbnodes(GEN T) { GEN F = gel(T,2); long n = 1, i, l = lg(F); for (i = 1; i < l; i++) n += etree_nbnodes(gel(F, i)); return n; } static long etree_listr(GEN nf, GEN T, GEN V, long n, GEN u, GEN ut) { GEN E = gel(T, 1), F = gel(T,2); long i, l = lg(F); GEN iso, isot = NULL; if (lg(E) == 6) { iso = ellnfcompisog(nf,gel(E,4), u); isot = ellnfcompisog(nf,ut, gel(E,5)); gel(V, n) = mkvec5(gel(E,1), gel(E,2), gel(E,3), iso, isot); } else { gel(V, n) = mkvec3(gel(E,1), gel(E,2), gel(E,3)); iso = u; } for (i = 1; i < l; i++) n = etree_listr(nf, gel(F, i), V, n + 1, iso, isot); return n; } static GEN etree_list(GEN nf, GEN T) { long n = etree_nbnodes(T); GEN V = cgetg(n+1, t_VEC); (void) etree_listr(nf, T, V, 1, trivial_isogeny(), trivial_isogeny()); return V; } static long etree_distmatr(GEN T, GEN M, long n) { GEN F = gel(T,2); long i, j, lF = lg(F), m = n + 1; GEN V = cgetg(lF, t_VECSMALL); mael(M, n, n) = 0; for(i = 1; i < lF; i++) V[i] = m = etree_distmatr(gel(F,i), M, m); for(i = 1; i < lF; i++) { long mi = i==1 ? n+1: V[i-1]; for(j = mi; j < V[i]; j++) { mael(M,n,j) = 1 + mael(M, mi, j); mael(M,j,n) = 1 + mael(M, j, mi); } for(j = 1; j < lF; j++) if (i != j) { long i1, j1, mj = j==1 ? n+1: V[j-1]; for (i1 = mi; i1 < V[i]; i1++) for(j1 = mj; j1 < V[j]; j1++) mael(M,i1,j1) = 2 + mael(M,mj,j1) + mael(M,i1,mi); } } return m; } static GEN etree_distmat(GEN T) { long i, n = etree_nbnodes(T); GEN M = cgetg(n+1, t_MAT); for(i = 1; i <= n; i++) gel(M,i) = cgetg(n+1, t_VECSMALL); (void)etree_distmatr(T, M, 1); return M; } static GEN distmat_pow(GEN E, ulong p) { long i, j, l = lg(E); GEN M = cgetg(l, t_MAT); for(i = 1; i < l; i++) { gel(M,i) = cgetg(l, t_COL); for(j = 1; j < l; j++) gmael(M,i,j) = powuu(p,mael(E,i,j)); } return M; } /* Assume there is a single p-isogeny */ static GEN isomatdbl(GEN nf, GEN L, GEN M, ulong p, GEN T2, long flag) { long i, j, n = lg(L) -1; GEN P = get_polmodular(p), V = cgetg(2*n+1, t_VEC), N = cgetg(2*n+1, t_MAT); for (i=1; i <= n; i++) { GEN F, E, e = gel(L,i); if (i == 1) F = gmael(T2, 2, 1); else { F = ellisograph_iso(nf, e, p, P, NULL, flag); if (lg(F) != 2) pari_err_BUG("isomatdbl"); } E = gel(F, 1); if (flag) E = mkvec3(gel(E,1), gel(E,2), gel(E,3)); else { GEN iso = ellnfcompisog(nf, gel(E,4), gel(e, 4)); GEN isot = ellnfcompisog(nf, gel(e,5), gel(E, 5)); E = mkvec5(gel(E,1), gel(E,2), gel(E,3), iso, isot); } gel(V, i) = e; gel(V, i+n) = E; } for (i=1; i <= 2*n; i++) gel(N, i) = cgetg(2*n+1, t_COL); for (i=1; i <= n; i++) for (j=1; j <= n; j++) { gcoeff(N,i,j) = gcoeff(N,i+n,j+n) = gcoeff(M,i,j); gcoeff(N,i,j+n) = gcoeff(N,i+n,j) = muliu(gcoeff(M,i,j), p); } return mkvec2(V, N); } static ulong ellQ_exceptional_iso(GEN j, GEN *jt, GEN *jtp, GEN *s0) { *jt = j; *jtp = gen_1; if (typ(j)==t_INT) { long js = itos_or_0(j); GEN j37; if (js==-32768) { *s0 = mkfracss(-1156,539); return 11; } if (js==-121) { *jt = stoi(-24729001) ; *jtp = mkfracss(4973,5633); *s0 = mkfracss(-1961682050,1204555087); return 11;} if (js==-24729001) { *jt = stoi(-121); *jtp = mkfracss(5633,4973); *s0 = mkfracss(-1961682050,1063421347); return 11;} if (js==-884736) { *s0 = mkfracss(-1100,513); return 19; } j37 = negi(uu32toi(37876312,1780746325)); if (js==-9317) { *jt = j37; *jtp = mkfracss(1984136099,496260169); *s0 = mkfrac(negi(uu32toi(457100760,4180820796UL)), uu32toi(89049913, 4077411069UL)); return 37; } if (equalii(j, j37)) { *jt = stoi(-9317); *jtp = mkfrac(utoi(496260169),utoi(1984136099UL)); *s0 = mkfrac(negi(uu32toi(41554614,2722784052UL)), uu32toi(32367030,2614994557UL)); return 37; } if (js==-884736000) { *s0 = mkfracss(-1073708,512001); return 43; } if (equalii(j, negi(powuu(5280,3)))) { *s0 = mkfracss(-176993228,85184001); return 67; } if (equalii(j, negi(powuu(640320,3)))) { *s0 = mkfrac(negi(uu32toi(72512,1969695276)), uu32toi(35374,1199927297)); return 163; } } else { GEN j1 = mkfracss(-297756989,2); GEN j2 = mkfracss(-882216989,131072); if (gequal(j, j1)) { *jt = j2; *jtp = mkfracss(1503991,2878441); *s0 = mkfrac(negi(uu32toi(121934,548114672)),uu32toi(77014,117338383)); return 17; } if (gequal(j, j2)) { *jt = j1; *jtp = mkfracss(2878441,1503991); *s0 = mkfrac(negi(uu32toi(121934,548114672)),uu32toi(40239,4202639633UL)); return 17; } } return 0; } static GEN nfmkisomat(GEN nf, ulong p, GEN T) { return mkvec2(etree_list(nf,T), distmat_pow(etree_distmat(T),p)); } static GEN mkisomat(ulong p, GEN T) { return nfmkisomat(NULL, p, T); } static GEN mkisomatdbl(ulong p, GEN T, ulong p2, GEN T2, long flag) { GEN v = mkisomat(p,T); return isomatdbl(NULL, gel(v,1), gel(v,2), p2, T2, flag); } /* See M.A Kenku On the number of Q-isomorphism classes of elliptic curves in each Q-isogeny class Journal of Number Theory Volume 15, Issue 2, October 1982, Pages 199-202 http://www.sciencedirect.com/science/article/pii/0022314X82900257 */ enum { _2 = 1, _3 = 2, _5 = 4, _7 = 8, _13 = 16 }; static ulong ellQ_goodl(GEN E) { forprime_t T; long i, CM = ellQ_get_CM(E); ulong mask = 31; GEN disc = ell_get_disc(E); pari_sp av = avma; u_forprime_init(&T, 17UL,ULONG_MAX); for(i=1; mask && i<=20; i++) { ulong p = u_forprime_next(&T); if (umodiu(disc,p)==0) i--; else { long t = ellap_CM_fast(E, p, CM), D = t*t-4*p; if (t%2) mask &= ~_2; if ((mask & _3) && kross(D,3)==-1) mask &= ~_3; if ((mask & _5) && kross(D,5)==-1) mask &= ~_5; if ((mask & _7) && kross(D,7)==-1) mask &= ~_7; if ((mask &_13) && kross(D,13)==-1) mask &= ~_13; } } avma = av; return mask; } static long ellQ_goodl_l(GEN E, long l) { forprime_t T; long i; GEN disc = ell_get_disc(E); pari_sp av = avma; u_forprime_init(&T, 17UL,ULONG_MAX); for(i=1; i<=20; i++) { ulong p = u_forprime_next(&T); if (umodiu(disc,p)==0) { i--; continue; } else { long t = itos(ellap(E, utoi(p))); if (l==2) { if (t%2==1) return 0; } else { long D = t*t-4*p; if (kross(D,l)==-1) return 0; } avma = av; } } return 1; } static ulong ellnf_goodl_l(GEN E, GEN v) { forprime_t T; long i; GEN nf = ellnf_get_nf(E); GEN disc = ell_get_disc(E); long lv = lg(v); ulong w = 0UL; pari_sp av = avma; u_forprime_init(&T, 17UL,ULONG_MAX); for(i=1; i<=20; i++) { ulong p = u_forprime_next(&T); GEN pr = idealprimedec(nf, utoi(p)); long j, k, lv = lg(v), g = lg(pr)-1; for (j=1; j<=g; j++) { GEN prj = gel(pr, j); if (idealval(nf,disc,prj) > 0) {i--; continue;} else { long t = itos(ellap(E, prj)); for(k = 1; k < lv; k++) { long l = v[k]; if (l==2) { if (t%2==1) w |= 1<<(k-1); } else { GEN D = subii(sqrs(t),shifti(pr_norm(prj),2)); if (krois(D,l)==-1) w |= 1<<(k-1); } } } } avma = av; } return w^((1UL<<(lv-1))-1); } static GEN ellnf_charpoly(GEN E, GEN pr) { return deg2pol_shallow(gen_1, negi(ellap(E,pr)), pr_norm(pr), 0); } static GEN RgX_homogenize(GEN P, long v) { GEN Q = leafcopy(P); long i, l = lg(P), d = degpol(P); for (i = 2; i < l; i++) gel(Q,i) = monomial(gel(Q,i), d--, v); return Q; } static GEN starlaw(GEN p, GEN q) { GEN Q = RgX_homogenize(RgX_recip(q), 1); return ZX_ZXY_resultant(p, Q); } static GEN startor(GEN p, long r) { GEN xr = pol_xn(r, 0); GEN psir = gsub(xr, gen_1); return gsubstpol(starlaw(p, psir),xr,pol_x(0)); } static GEN ellnf_get_degree(GEN E, GEN p) { GEN nf = ellnf_get_nf(E); long d = nf_get_degree(nf); GEN dec = idealprimedec(nf, p); long i, l = lg(dec), k; GEN R, starl = deg1pol_shallow(gen_1, gen_m1, 0); for(i=1; i < l; i++) { GEN pr = gel(dec,i); GEN q = ellnf_charpoly(E, pr); starl = starlaw(starl, startor(q, 12*pr_get_e(pr))); } R = p; for(k=0; 2*k<=d; k++) R = mulii(R, poleval(starl,powiu(p,12*k))); return R; } /* Based on a GP script by Nicolas Billerey itself based on Th\'eor\`emes 2.4 and 2.8 of the following article: N. Billerey, Crit\`eres d'irr\'eductibilit\'e pour les repr\'esentations des courbes elliptiques, Int. J. Number Theory 7 (2011), no. 4, 1001-1032. */ static GEN ellnf_prime_degree(GEN E) { forprime_t T; long i; GEN nf = ellnf_get_nf(E); GEN disc = ell_get_disc(E); GEN P, B = gen_0, rB; GEN bad = mulii(nfnorm(nf, disc),nf_get_disc(nf)); u_forprime_init(&T, 5UL,ULONG_MAX); for(i=1; i<=20; i++) { ulong p = u_forprime_next(&T); if (dvdiu(bad, p)) {i--; continue;} B = gcdii(B, ellnf_get_degree(E, utoi(p))); if (Z_issquareall(B,&rB)) B=rB; } if (signe(B)==0) pari_err_IMPL("ellisomat, CM case"); P = vec_to_vecsmall(gel(Z_factor(B),1)); return shallowextract(P, utoi(ellnf_goodl_l(E, P))); } static GEN ellQ_isomat(GEN E, long flag) { GEN K = NULL, T2 = NULL, T3 = NULL, T5, T7, T13; ulong good; long n2, n3, n5, n7, n13; GEN jt, jtp, s0, j = ell_get_j(E); long l = ellQ_exceptional_iso(j, &jt, &jtp, &s0); if (l) { #if 1 return mkisomat(l, ellisograph_dummy(E, l, jt, jtp, s0, flag)); #else return mkisomat(l, ellisograph_p(K, E, l), flag); #endif } good = ellQ_goodl(ellintegralmodel(E,NULL)); if (good & _2) { T2 = ellisograph_p(K, E, 2, flag); n2 = etree_nbnodes(T2); if (n2>4 || gequalgs(j, 1728) || gequalgs(j, 287496)) return mkisomat(2, T2); } else n2 = 1; if (good & _3) { T3 = ellisograph_p(K, E, 3, flag); n3 = etree_nbnodes(T3); if (n3>1 && n2==2) return mkisomatdbl(3,T3,2,T2, flag); if (n3==2 && n2>1) return mkisomatdbl(2,T2,3,T3, flag); if (n3>2 || gequal0(j)) return mkisomat(3, T3); } else n3 = 1; if (good & _5) { T5 = ellisograph_p(K, E, 5, flag); n5 = etree_nbnodes(T5); if (n5>1 && n2>1) return mkisomatdbl(2,T2,5,T5, flag); if (n5>1 && n3>1) return mkisomatdbl(3,T3,5,T5, flag); if (n5>1) return mkisomat(5, T5); } else n5 = 1; if (good & _7) { T7 = ellisograph_p(K, E, 7, flag); n7 = etree_nbnodes(T7); if (n7>1 && n2>1) return mkisomatdbl(2,T2,7,T7, flag); if (n7>1 && n3>1) return mkisomatdbl(3,T3,7,T7, flag); if (n7>1) return mkisomat(7,T7); } else n7 = 1; if (n2>1) return mkisomat(2,T2); if (n3>1) return mkisomat(3,T3); if (good & _13) { T13 = ellisograph_p(K, E, 13, flag); n13 = etree_nbnodes(T13); if (n13>1) return mkisomat(13,T13); } else n13 = 1; return mkvec2(mkvec(ellisograph_a4a6(E,flag)), matid(1)); } static long fill_LM(GEN LM, GEN L, GEN M, GEN z, long k) { GEN Li = gel(LM,1), Mi1 = gmael(LM,2,1); long j, m = lg(Li); for (j = 2; j < m; j++) { GEN d = gel(Mi1,j); gel(L, k) = gel(Li,j); gel(M, k) = z? mulii(d,z): d; k++; } return k; } static GEN ellnf_isocrv(GEN nf, GEN E, GEN v, GEN PE, long flag) { long i, l, lv, n, k; GEN L, M, LE = cgetg_copy(v,&lv), e = ellisograph_a4a6(E, flag); for (i = n = 1; i < lv; i++) { ulong p = uel(v,i); GEN T = isograph_p(nf, e, p, gel(PE,i), flag); GEN LM = nfmkisomat(nf, p, T); gel(LE,i) = LM; n *= lg(gel(LM,1)) - 1; } L = cgetg(n+1,t_VEC); gel(L,1) = e; M = cgetg(n+1,t_COL); gel(M,1) = gen_1; for (i = 1, k = 2; i < lv; i++) { ulong p = uel(v,i); GEN P = gel(PE,i); long kk = k; k = fill_LM(gel(LE,i), L, M, NULL, k); for (l = 2; l < kk; l++) { GEN T = isograph_p(nf, gel(L,l), p, P, flag); GEN LMe = nfmkisomat(nf, p, T); k = fill_LM(LMe, L, M, gel(M,l), k); } } return mkvec2(L, M); } static long nfispower(GEN nf, long d, GEN a, GEN b) { GEN N; if (gequal(a,b)) return 1; N = nfroots(nf, gsub(monomial(b, d, 0), monomial(a,0,0))); return lg(N) > 1; } static long isomat_eq(GEN nf, GEN e1, GEN e2) { if (gequal(e1,e2)) return 1; if (!gequal(gel(e1,3), gel(e2,3))) return 0; if (gequal0(gel(e1,3))) return nfispower(nf,6,gel(e1,2),gel(e2,2)); if (gequalgs(gel(e1,3),1728)) return nfispower(nf,4,gel(e1,1),gel(e2,1)); return nfispower(nf,2,gmul(gel(e1,1),gel(e2,2)),gmul(gel(e1,2),gel(e2,1))); } static long isomat_find(GEN nf, GEN e, GEN L) { long i, l = lg(L); for (i=1; i 1) pari_err_FLAG("ellisomat"); if (p < 0) pari_err_PRIME("ellisomat", utoi(p)); if (p == 1) { flag = 1; p = 0; } /* for backward compatibility */ checkell(E); switch(ell_get_type(E)) { case t_ELL_Q: if (p) good = ellQ_goodl_l(E, p); break; case t_ELL_NF: if (p) good = ellnf_goodl_l(E, mkvecsmall(p)); nf = ellnf_get_nf(E); break; default: pari_err_TYPE("ellisomat",E); } if (!good) r = mkvec2(mkvec(ellisograph_a4a6(E, flag)),matid(1)); else { if (p) r = nfmkisomat(nf, p, ellisograph_p(nf, E, p, flag)); else r = nf? ellnf_isomat(E, flag): ellQ_isomat(E, flag); gel(r,1) = list_to_crv(gel(r,1)); } return gerepilecopy(av, r); } static GEN get_isomat(GEN v) { GEN M, vE, wE; long i, l; if (typ(v) != t_VEC) return NULL; if (checkell_i(v)) { if (ell_get_type(v) != t_ELL_Q) return NULL; v = ellisomat(v,0,1); wE = gel(v,1); l = lg(wE); M = gel(v,2); } else { if (lg(v) != 3) return NULL; vE = gel(v,1); l = lg(vE); M = gel(v,2); if (typ(M) != t_MAT || !RgM_is_ZM(M)) return NULL; if (typ(vE) != t_VEC || l == 1) return NULL; if (lg(gel(vE,1)) == 3) wE = shallowcopy(vE); else { /* [[a4,a6],f,g] */ wE = cgetg_copy(vE,&l); for (i = 1; i < l; i++) gel(wE,i) = gel(gel(vE,i),1); } } /* wE a vector of [a4,a6] */ for (i = 1; i < l; i++) { GEN e = ellinit(gel(wE,i), gen_1, 0), E = ellminimalmodel(e, NULL); obj_free(e); gel(wE,i) = E; } return mkvec2(wE, M); } GEN ellweilcurve(GEN E, GEN *ms) { pari_sp av = avma; GEN vE = get_isomat(E), vL, Wx, W, XPM, Lf, Cf; long i, l; if (!vE) pari_err_TYPE("ellweilcurve",E); vE = gel(vE,1); l = lg(vE); Wx = msfromell(vE, 0); W = gel(Wx,1); XPM = gel(Wx,2); /* lattice attached to the Weil curve in the isogeny class */ Lf = mslattice(W, gmael(XPM,1,3)); Cf = ginv(Lf); /* left-inverse */ vL = cgetg(l, t_VEC); for (i=1; i < l; i++) { GEN c, Ce, Le = gmael(XPM,i,3); Ce = Q_primitive_part(RgM_mul(Cf, Le), &c); Ce = ZM_snf(Ce); if (c) { Ce = ZC_Q_mul(Ce,c); settyp(Ce,t_VEC); } gel(vL,i) = Ce; } for (i = 1; i < l; i++) obj_free(gel(vE,i)); vE = mkvec2(vE, vL); if (!ms) return gerepilecopy(av, vE); *ms = Wx; gerepileall(av, 2, &vE, ms); return vE; } GEN ellisotree(GEN E) { pari_sp av = avma; GEN L = get_isomat(E), vE, adj, M; long i, j, n; if (!L) pari_err_TYPE("ellisotree",E); vE = gel(L,1); adj = gel(L,2); n = lg(vE)-1; L = cgetg(n+1, t_VEC); for (i = 1; i <= n; i++) gel(L,i) = ellR_area(gel(vE,i), LOWDEFAULTPREC); M = zeromatcopy(n,n); for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) { GEN p = gcoeff(adj,i,j); if (!isprime(p)) continue; /* L[i] / L[j] = p or 1/p; p iff E[i].lattice \subset E[j].lattice */ if (gcmp(gel(L,i), gel(L,j)) > 0) gcoeff(M,i,j) = p; else gcoeff(M,j,i) = p; } for (i = 1; i <= n; i++) obj_free(gel(vE,i)); return gerepilecopy(av, mkvec2(vE,M)); } pari-2.11.2/src/basemath/random.c0000644000175000017500000002163013326135265015165 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /* */ /* PSEUDO-RANDOM INTEGERS */ /* */ /********************************************************************/ #include "pari.h" #include "paripriv.h" /********************************************************************/ /* XORGEN (Richard P. Brent) */ /* http://wwwmaths.anu.edu.au/~brent/random.html */ /* (initial adaptation to PARI/GP by Randall Rathbun) */ /********************************************************************/ /* Adapted from xorgens.c version 3.04, Richard P. Brent, 20060628 (GPL). * 32-bit or 64-bit integer random number generator with period at * least 2**4096-1. It is assumed that "ulong" is a 32-bit or 64-bit integer */ #ifdef LONG_IS_64BIT typedef ulong u64; #else typedef unsigned long long u64; static u64 _32to64(ulong a, ulong b) { u64 v = a; return (v<<32)|b; } static void _64to32(u64 v, ulong *a, ulong *b) { *a = v>>32; *b = v&0xFFFFFFFF; } #endif static THREAD u64 state[64]; static THREAD u64 xorgen_w; static THREAD int xorgen_i; /* weyl = odd approximation to 2^64*(sqrt(5)-1)/2. */ static const u64 weyl = (((u64)0x61c88646U)<<32)|((u64)0x80b583ebU); static u64 block(void) { const int r = 64; const int a = 33, b = 26, c = 27, d = 29, s = 53; u64 t, v, w; xorgen_i = (xorgen_i+1)&(r-1); t = state[xorgen_i]; v = state[(xorgen_i+(r-s))&(r-1)]; /* index is (i-s) mod r */ t ^= t<>b; /* (I + L^a)(I + R^b) */ v ^= v<>d; /* (I + L^c)(I + R^d) */ w = t^v; return state[xorgen_i] = w; /* update circular array */ } /* v > 0 */ static void init_xor4096i(u64 v) { const int r = 64; int k; for (k = r; k > 0; k--) {/* avoid correlations for close seeds */ v ^= v<<10; v ^= v>>15; /* recurrence has period 2**64-1 */ v ^= v<<4; v ^= v>>13; } for (xorgen_w = v, k = 0; k < r; k++) { /* initialise circular array */ v ^= v<<10; v ^= v>>15; v ^= v<<4; v ^= v>>13; state[k] = v + (xorgen_w+=weyl); } /* discard first 4*r results */ for (xorgen_i = r-1, k = 4*r; k > 0; k--) (void)block(); } void pari_init_rand(void) { init_xor4096i(1UL); } static u64 rand64(void) { u64 v = block(); xorgen_w += weyl; /* update Weyl generator */ return v + (xorgen_w ^ (xorgen_w>>27)); } /* One random number uniformly distributed in [0..2**BIL) is returned, where * BIL = 8*sizeof(ulong) = 32 or 64. */ ulong pari_rand(void) { return rand64(); } void setrand(GEN x) { const int r2 = numberof(state); long i, lx; u64 v; GEN xp; if (typ(x)!=t_INT) pari_err_TYPE("setrand",x); if (signe(x) <= 0) pari_err_DOMAIN("setrand","n", "<=", gen_0, x); lx = lgefint(x); if (lx == 3) { v = x[2]; init_xor4096i(v); return; } #ifndef LONG_IS_64BIT if (lx == 4) { v = _32to64(*int_W(x,1),*int_W(x,0)); init_xor4096i(v); return; } #endif xp = int_LSW(x); #ifdef LONG_IS_64BIT if (lx != 2 + r2+2) pari_err_DOMAIN("setrand", "n", "!=", strtoGENstr("getrand()"), x); for (i = 0; i < r2; i++, xp = int_nextW(xp)) state[i] = *xp; xorgen_w = *xp; xp = int_nextW(xp); #else if (lx != 2 + 2*r2+3) pari_err_DOMAIN("setrand", "n", "!=", strtoGENstr("getrand()"), x); for (i = 0; i < r2; i++, xp = int_nextW(int_nextW(xp))) state[i] = _32to64(*int_nextW(xp), *xp); xorgen_w = _32to64(*int_nextW(xp), *xp); xp = int_nextW(int_nextW(xp)); #endif xorgen_i = (*xp) & 63; } GEN getrand(void) { const int r2 = numberof(state); GEN x; ulong *xp; long i; if (xorgen_i < 0) init_xor4096i(1UL); #ifdef LONG_IS_64BIT x = cgetipos(2+r2+2); xp = (ulong *) int_LSW(x); for (i = 0; i < r2; i++, xp = int_nextW(xp)) *xp = state[i]; *xp = xorgen_w; xp = int_nextW(xp); #else x = cgetipos(2+2*r2+3); xp = (ulong *) int_LSW(x); for (i = 0; i < r2; i++, xp = int_nextW(int_nextW(xp))) _64to32(state[i], int_nextW(xp), xp); _64to32(xorgen_w, int_nextW(xp), xp); xp = int_nextW(int_nextW(xp)); #endif *xp = xorgen_i? xorgen_i: 64; return x; } /* assume 0 <= k <= BITS_IN_LONG. Return uniform random 0 <= x < (1<> (64-k); } /********************************************************************/ /* */ /* GENERIC ROUTINES */ /* */ /********************************************************************/ /* assume n > 0 */ ulong random_Fl(ulong n) { ulong d; int shift; #ifdef LONG_IS_64BIT int SHIFT = 0; #else int SHIFT = 32; #endif if (n == 1) return 0; shift = bfffo(n); /* 2^(BIL-shift) > n >= 2^(BIL-shift-1)*/ /* if N a power of 2, increment shift. No reject */ if ((n << shift) == HIGHBIT) return rand64() >> (SHIFT+shift+1); for (;;) { d = rand64() >> (SHIFT+shift); /* d < 2^(64-shift) uniformly distributed */ /* reject strategy: proba success = n 2^(shift-64), in [1/2, 1[ */ if (d < n) return d; } } /* assume N > 0, see random_Fl() for algorithm. Make sure that 32-bit and * 64-bit architectures produce the same integers (consuming random bits * by packets of 64) */ GEN randomi(GEN N) { long lx = lgefint(N); GEN x, d; int shift; if (lx == 3) return utoi( random_Fl(N[2]) ); shift = bfffo(*int_MSW(N)); /* if N a power of 2, increment shift */ if (Z_ispow2(N) && ++shift == BITS_IN_LONG) { shift = 0; lx--; } x = cgetipos(lx); for (;;) { GEN y, MSW = int_MSW(x), STOP = MSW; #ifdef LONG_IS_64BIT for (d = int_LSW(x); d != STOP; d = int_nextW(d)) *d = rand64(); *d = rand64() >> shift; #else if (!odd(lx)) STOP = int_precW(STOP); /* STOP points to where MSW would in 64-bit */ for (d = int_LSW(x); d != STOP; d = int_nextW(d)) { ulong a, b; _64to32(rand64(), &a,&b); *d = b; d = int_nextW(d); *d = a; } { ulong a, b; _64to32(rand64() >> shift, &a,&b); if (d == MSW) /* 32 bits needed */ *d = a; else { /* 64 bits needed */ *d = b; d = int_nextW(d); *d = a; } } #endif y = int_normalize(x, 0); if (abscmpii(y, N) < 0) return y; } } GEN random_F2x(long d, long vs) { ulong db, dl = dvmduBIL(d,&db); long i, l = 2 + dl + !!db; GEN y = cgetg(l,t_VECSMALL); y[1] = vs; #ifdef LONG_IS_64BIT for (i=2; i>32); } if (i b)", N); return gerepileuptoint(av, addii(a, randomi(addiu(d,1)))); } return ellrandom(N); default: pari_err_TYPE("genrand",N); return NULL;/*LCOV_EXCL_LINE*/ } } pari-2.11.2/src/basemath/nffactor.c0000644000175000017500000020412513460341157015507 0ustar billbill/* Copyright (C) 2000-2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* POLYNOMIAL FACTORIZATION IN A NUMBER FIELD */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" static GEN nfsqff(GEN nf,GEN pol,long fl,GEN den); static int nfsqff_use_Trager(long n, long dpol); enum { FACTORS = 0, ROOTS, ROOTS_SPLIT }; /* for nf_bestlift: reconstruction of algebraic integers known mod P^k, * P maximal ideal above p */ typedef struct { long k; /* input known mod P^k */ GEN p, pk; /* p^k = denom(prk^-1) [ assume pr unramified ]*/ GEN prk; /* |.|^2 LLL-reduced basis (b_i) of P^k (NOT T2-reduced) */ GEN iprk; /* den * prk^-1 */ GEN GSmin; /* min |b_i^*|^2 */ GEN Tp; /* Tpk mod p */ GEN Tpk; GEN ZqProj;/* projector to Zp / P^k = Z/p^k[X] / Tpk */ GEN tozk; GEN topow; GEN topowden; /* topow x / topowden = basistoalg(x) */ GEN dn; /* NULL (we trust nf.zk) or a t_INT > 1 (an alg. integer has denominator dividing dn, when expressed on nf.zk */ } nflift_t; typedef struct { nflift_t *L; GEN nf; GEN pol, polbase; /* leading coeff is a t_INT */ GEN fact; GEN Br, bound, ZC, BS_2; } nfcmbf_t; /*******************************************************************/ /* RATIONAL RECONSTRUCTION (use ratlift) */ /*******************************************************************/ /* NOT stack clean. a, b stay on the stack */ static GEN lift_to_frac_tdenom(GEN t, GEN mod, GEN amax, GEN bmax, GEN denom, GEN tdenom) { GEN a, b; if (signe(t) < 0) t = addii(t, mod); /* in case t is a centerlift */ if (tdenom) { pari_sp av = avma; a = Fp_center_i(Fp_mul(t, tdenom, mod), mod, shifti(mod,-1)); if (abscmpii(a, amax) < 0) { GEN d = gcdii(a, tdenom); a = diviiexact(a, d); b = diviiexact(tdenom, d); if (is_pm1(b)) { return gerepileuptoint(av, a); } return gerepilecopy(av, mkfrac(a, b)); } avma = av; } if (!Fp_ratlift(t, mod, amax,bmax, &a,&b) || (denom && !dvdii(denom,b)) || !is_pm1(gcdii(a,b))) return NULL; if (is_pm1(b)) { cgiv(b); return a; } return mkfrac(a, b); } static GEN lift_to_frac(GEN t, GEN mod, GEN amax, GEN bmax, GEN denom) { return lift_to_frac_tdenom(t, mod, amax, bmax, denom, NULL); } /* Compute rational lifting for all the components of M modulo mod. * Assume all Fp_ratlift preconditions are met; we allow centerlifts but in * that case are no longer stack clean. If one component fails, return NULL. * If denom != NULL, check that the denominators divide denom. * * We suppose gcd(mod, denom) = 1, then a and b are coprime; so we can use * mkfrac rather than gdiv */ GEN FpC_ratlift(GEN P, GEN mod, GEN amax, GEN bmax, GEN denom) { pari_sp ltop = avma; long j, l; GEN a, d, tdenom = NULL, Q = cgetg_copy(P, &l); if (l==1) return Q; for (j = 1; j < l; ++j) { a = lift_to_frac_tdenom(gel(P,j), mod, amax, bmax, denom, tdenom); if (!a) { avma = ltop; return NULL; } d = Q_denom(a); tdenom = tdenom ? cmpii(tdenom, d)<0? d: tdenom : d; gel(Q,j) = a; } return Q; } GEN FpM_ratlift(GEN M, GEN mod, GEN amax, GEN bmax, GEN denom) { pari_sp av = avma; long j, l = lg(M); GEN N = cgetg_copy(M, &l); if (l == 1) return N; for (j = 1; j < l; ++j) { GEN a = FpC_ratlift(gel(M, j), mod, amax, bmax, denom); if (!a) { avma = av; return NULL; } gel(N,j) = a; } return N; } GEN FpX_ratlift(GEN P, GEN mod, GEN amax, GEN bmax, GEN denom) { pari_sp ltop = avma; long j, l; GEN a, Q = cgetg_copy(P, &l); Q[1] = P[1]; for (j = 2; j < l; ++j) { a = lift_to_frac(gel(P,j), mod, amax,bmax,denom); if (!a) { avma = ltop; return NULL; } gel(Q,j) = a; } return Q; } /*******************************************************************/ /* GCD in K[X], K NUMBER FIELD */ /*******************************************************************/ /* P a non-zero ZXQX */ static GEN lead_simplify(GEN P) { GEN x = gel(P, lg(P)-1); /* x a non-zero ZX or t_INT */ if (typ(x) == t_POL && !degpol(x)) x = gel(x,2); return is_pm1(x)? NULL: x; } /* P,Q in Z[X,Y], T in Z[Y] irreducible. compute GCD in Q[Y]/(T)[X]. * * M. Encarnacion "On a modular Algorithm for computing GCDs of polynomials * over number fields" (ISSAC'94). * * We procede as follows * 1:compute the gcd modulo primes discarding bad primes as they are detected. * 2:reconstruct the result via FpM_ratlift, stoping as soon as we get weird * denominators. * 3:if FpM_ratlift succeeds, try the full division. * Suppose accuracy is insufficient to get the result right: FpM_ratlift will * rarely succeed, and even if it does the polynomial we get has sensible * coefficients, so the full division will not be too costly. * * If not NULL, den must be a multiple of the denominator of the gcd, * for example the discriminant of T. * * NOTE: if T is not irreducible, nfgcd may loop forever, esp. if gcd | T */ GEN nfgcd_all(GEN P, GEN Q, GEN T, GEN den, GEN *Pnew) { pari_sp btop, ltop = avma; GEN lP, lQ, M, dsol, R, bo, sol, mod = NULL, lden = NULL; long vP = varn(P), vT = varn(T), dT = degpol(T), dM = 0, dR; forprime_t S; if (!signe(P)) { if (Pnew) *Pnew = pol_0(vT); return gcopy(Q); } if (!signe(Q)) { if (Pnew) *Pnew = pol_1(vT); return gcopy(P); } /* Compute denominators */ if ((lP = lead_simplify(P)) && (lQ = lead_simplify(Q))) { if (typ(lP) == t_INT && typ(lQ) == t_INT) lden = powiu(gcdii(lP, lQ), dT); else if (typ(lP) == t_INT) lden = gcdii(powiu(lP, dT), ZX_resultant(lQ, T)); else if (typ(lQ) == t_INT) lden = gcdii(powiu(lQ, dT), ZX_resultant(lP, T)); else lden = gcdii(ZX_resultant(lP, T), ZX_resultant(lQ, T)); if (is_pm1(lden)) lden = NULL; den = mul_denom(den, lden); } init_modular_small(&S); btop = avma; for(;;) { ulong p = u_forprime_next(&S); GEN Tp; if (!p) pari_err_OVERFLOW("nfgcd [ran out of primes]"); /*Discard primes dividing disc(T) or lc(PQ) */ if (lden && !umodiu(lden, p)) continue; Tp = ZX_to_Flx(T,p); if (!Flx_is_squarefree(Tp, p)) continue; /*Discard primes when modular gcd does not exist*/ if ((R = FlxqX_safegcd(ZXX_to_FlxX(P,p,vT), ZXX_to_FlxX(Q,p,vT), Tp, p)) == NULL) continue; dR = degpol(R); if (dR == 0) { avma = ltop; if (Pnew) *Pnew = P; return pol_1(vP); } if (mod && dR > dM) continue; /* p divides Res(P/gcd, Q/gcd). Discard. */ R = FlxX_to_Flm(R, dT); /* previous primes divided Res(P/gcd, Q/gcd)? Discard them. */ if (!mod || dR < dM) { M = ZM_init_CRT(R, p); mod = utoipos(p); dM = dR; continue; } (void)ZM_incremental_CRT(&M,R, &mod,p); if (gc_needed(btop, 1)) { if (DEBUGMEM>1) pari_warn(warnmem,"nfgcd"); gerepileall(btop, 2, &M, &mod); } /* I suspect it must be better to take amax > bmax*/ bo = sqrti(shifti(mod, -1)); if ((sol = FpM_ratlift(M, mod, bo, bo, den)) == NULL) continue; sol = RgM_to_RgXX(sol,vP,vT); dsol = Q_primpart(sol); if (!ZXQX_dvd(Q, dsol, T)) continue; if (Pnew) { *Pnew = RgXQX_pseudodivrem(P, dsol, T, &R); if (signe(R)) continue; } else { if (!ZXQX_dvd(P, dsol, T)) continue; } gerepileall(ltop, Pnew? 2: 1, &dsol, Pnew); return dsol; /* both remainders are 0 */ } } GEN nfgcd(GEN P, GEN Q, GEN T, GEN den) { return nfgcd_all(P,Q,T,den,NULL); } int nfissquarefree(GEN nf, GEN x) { pari_sp av = avma; GEN g, y = RgX_deriv(x); if (RgX_is_rational(x)) g = QX_gcd(x, y); else { GEN T = get_nfpol(nf,&nf); x = Q_primpart( liftpol_shallow(x) ); y = Q_primpart( liftpol_shallow(y) ); g = nfgcd(x, y, T, nf? nf_get_index(nf): NULL); } avma = av; return (degpol(g) == 0); } /*******************************************************************/ /* FACTOR OVER (Z_K/pr)[X] --> FqX_factor */ /*******************************************************************/ GEN nffactormod(GEN nf, GEN x, GEN pr) { long j, l, vx = varn(x), vn; pari_sp av = avma; GEN F, E, rep, xrd, modpr, T, p; nf = checknf(nf); vn = nf_get_varn(nf); if (typ(x)!=t_POL) pari_err_TYPE("nffactormod",x); if (varncmp(vx,vn) >= 0) pari_err_PRIORITY("nffactormod", x, ">=", vn); modpr = nf_to_Fq_init(nf, &pr, &T, &p); xrd = nfX_to_FqX(x, nf, modpr); rep = FqX_factor(xrd,T,p); settyp(rep, t_MAT); F = gel(rep,1); l = lg(F); E = gel(rep,2); settyp(E, t_COL); for (j = 1; j < l; j++) { gel(F,j) = FqX_to_nfX(gel(F,j), modpr); gel(E,j) = stoi(E[j]); } return gerepilecopy(av, rep); } /*******************************************************************/ /* MAIN ROUTINES nfroots / nffactor */ /*******************************************************************/ static GEN QXQX_normalize(GEN P, GEN T) { GEN P0 = leading_coeff(P); long t = typ(P0); if (t == t_POL) { if (degpol(P0)) return RgXQX_RgXQ_mul(P, QXQ_inv(P0,T), T); P0 = gel(P0,2); t = typ(P0); } /* t = t_INT/t_FRAC */ if (t == t_INT && is_pm1(P0) && signe(P0) > 0) return P; /* monic */ return RgX_Rg_div(P, P0); } /* assume leading term of P is an integer */ static GEN RgX_int_normalize(GEN P) { GEN P0 = leading_coeff(P); /* cater for t_POL */ if (typ(P0) == t_POL) { P0 = gel(P0,2); /* non-0 constant */ P = shallowcopy(P); gel(P,lg(P)-1) = P0; /* now leading term is a t_INT */ } if (typ(P0) != t_INT) pari_err_BUG("RgX_int_normalize"); if (is_pm1(P0)) return signe(P0) > 0? P: RgX_neg(P); return RgX_Rg_div(P, P0); } /* discard change of variable if nf is of the form [nf,c] as return by nfinit * for non-monic polynomials */ static GEN proper_nf(GEN nf) { return (lg(nf) == 3)? gel(nf,1): nf; } /* if *pnf = NULL replace if by a "quick" K = nfinit(T), ensuring maximality * by small primes only. Return a multiplicative bound for the denominator of * algebraic integers in Z_K in terms of K.zk */ static GEN fix_nf(GEN *pnf, GEN *pT, GEN *pA) { GEN nf, NF, fa, P, Q, q, D, T = *pT; nfmaxord_t S; long i, l; if (*pnf) return gen_1; nfmaxord(&S, T, nf_PARTIALFACT); NF = nfinit_complete(&S, 0, DEFAULTPREC); *pnf = nf = proper_nf(NF); if (nf != NF) { /* t_POL defining base field changed (not monic) */ GEN A = *pA, a = cgetg_copy(A, &l); GEN rev = gel(NF,2), pow, dpow; *pT = T = nf_get_pol(nf); /* need to update T */ pow = QXQ_powers(lift_shallow(rev), degpol(T)-1, T); pow = Q_remove_denom(pow, &dpow); a[1] = A[1]; for (i=2; iprk), t = typ(elt); if (t != t_INT) { if (t == t_POL) elt = ZM_ZX_mul(L->tozk, elt); u = ZM_ZC_mul(L->iprk,elt); for (i=1; ipk); } else { u = ZC_Z_mul(gel(L->iprk,1), elt); for (i=1; ipk); elt = scalarcol(elt, l-1); } u = ZC_sub(elt, ZM_ZC_mul(L->prk, u)); if (bound && gcmp(_norml2(u), bound) > 0) u = NULL; return u; } /* Warning: return L->topowden * (best lift). */ static GEN nf_bestlift_to_pol(GEN elt, GEN bound, nflift_t *L) { pari_sp av = avma; GEN u,v = nf_bestlift(elt,bound,L); if (!v) return NULL; if (ZV_isscalar(v)) { if (L->topowden) u = mulii(L->topowden, gel(v,1)); else u = icopy(gel(v,1)); u = gerepileuptoint(av, u); } else { v = gclone(v); avma = av; u = RgV_dotproduct(L->topow, v); gunclone(v); } return u; } /* return the T->powden * (lift of pol with coefficients of T2-norm <= C) * if it exists. */ static GEN nf_pol_lift(GEN pol, GEN bound, nflift_t *L) { long i, l = lg(pol); GEN x = cgetg(l,t_POL); x[1] = pol[1]; gel(x,l-1) = mul_content(gel(pol,l-1), L->topowden); for (i=l-2; i>1; i--) { GEN t = nf_bestlift_to_pol(gel(pol,i), bound, L); if (!t) return NULL; gel(x,i) = t; } return x; } static GEN zerofact(long v) { GEN z = cgetg(3, t_MAT); gel(z,1) = mkcol(pol_0(v)); gel(z,2) = mkcol(gen_1); return z; } /* Return the factorization of A in Q[X]/(T) in rep [pre-allocated with * cgetg(3,t_MAT)], reclaiming all memory between avma and rep. * y is the vector of irreducible factors of B = Q_primpart( A/gcd(A,A') ). * Bad primes divide 'bad' */ static void fact_from_sqff(GEN rep, GEN A, GEN B, GEN y, GEN T, GEN bad) { pari_sp av = (pari_sp)rep; long n = lg(y)-1; GEN ex; if (A != B) { /* not squarefree */ if (n == 1) { /* perfect power, simple ! */ long e = degpol(A) / degpol(gel(y,1)); y = gerepileupto(av, QXQXV_to_mod(y, T)); ex = mkcol(utoipos(e)); } else { /* compute valuations mod a prime of degree 1 (avoid coeff explosion) */ GEN quo, p, r, Bp, lb = leading_coeff(B), E = cgetalloc(t_VECSMALL,n+1); pari_sp av1 = avma; ulong pp; long j; forprime_t S; u_forprime_init(&S, degpol(T), ULONG_MAX); for (; ; avma = av1) { pp = u_forprime_next(&S); if (! umodiu(bad,pp) || !umodiu(lb, pp)) continue; p = utoipos(pp); r = FpX_oneroot(T, p); if (!r) continue; Bp = FpXY_evalx(B, r, p); if (FpX_is_squarefree(Bp, p)) break; } quo = FpXY_evalx(Q_primpart(A), r, p); for (j=n; j>=2; j--) { GEN junk, fact = Q_remove_denom(gel(y,j), &junk); long e = 0; fact = FpXY_evalx(fact, r, p); for(;; e++) { GEN q = FpX_divrem(quo,fact,p,ONLY_DIVIDES); if (!q) break; quo = q; } E[j] = e; } E[1] = degpol(quo) / degpol(gel(y,1)); y = gerepileupto(av, QXQXV_to_mod(y, T)); ex = zc_to_ZC(E); pari_free((void*)E); } } else { y = gerepileupto(av, QXQXV_to_mod(y, T)); ex = const_col(n, gen_1); } gel(rep,1) = y; settyp(y, t_COL); gel(rep,2) = ex; } /* return the factorization of x in nf */ GEN nffactor(GEN nf,GEN pol) { GEN bad, A, B, y, T, den, rep = cgetg(3, t_MAT); pari_sp av = avma; long dA; pari_timer ti; if (DEBUGLEVEL>2) { timer_start(&ti); err_printf("\nEntering nffactor:\n"); } T = get_nfpol(nf, &nf); RgX_check_ZX(T,"nffactor"); A = RgX_nffix("nffactor",T,pol,1); dA = degpol(A); if (dA <= 0) { avma = (pari_sp)(rep + 3); return (dA == 0)? trivial_fact(): zerofact(varn(pol)); } if (dA == 1) { GEN c; A = Q_primpart( QXQX_normalize(A, T) ); A = gerepilecopy(av, A); c = gel(A,2); if (typ(c) == t_POL && degpol(c) > 0) gel(A,2) = mkpolmod(c, ZX_copy(T)); gel(rep,1) = mkcol(A); gel(rep,2) = mkcol(gen_1); return rep; } if (degpol(T) == 1) return gerepileupto(av, QX_factor(simplify_shallow(A))); den = get_nfsqff_data(&nf, &T, &A, &B, &bad); if (DEBUGLEVEL>2) timer_printf(&ti, "squarefree test"); if (RgX_is_ZX(B)) { GEN v = gel(ZX_factor(B), 1); long i, l = lg(v); y = cgetg(1, t_VEC); for (i = 1; i < l; i++) { GEN b = gel(v,i); /* irreducible / Q */ y = shallowconcat(y, nfsqff(nf, b, 0, den)); } } else y = nfsqff(nf,B, 0, den); if (DEBUGLEVEL>3) err_printf("number of factor(s) found: %ld\n", lg(y)-1); fact_from_sqff(rep, A, B, y, T, bad); return sort_factor_pol(rep, cmp_RgX); } /* assume x scalar or t_COL, G t_MAT */ static GEN arch_for_T2(GEN G, GEN x) { return (typ(x) == t_COL)? RgM_RgC_mul(G,x) : RgC_Rg_mul(gel(G,1),x); } /* polbase a zkX with t_INT leading coeff; return a bound for T_2(P), * P | polbase in C[X]. NB: Mignotte bound: A | S ==> * |a_i| <= binom(d-1, i-1) || S ||_2 + binom(d-1, i) lc(S) * * Apply to sigma(S) for all embeddings sigma, then take the L_2 norm over * sigma, then take the sup over i */ static GEN nf_Mignotte_bound(GEN nf, GEN polbase) { GEN lS = leading_coeff(polbase); /* t_INT */ GEN p1, C, N2, binlS, bin; long prec = nf_get_prec(nf), n = nf_get_degree(nf), r1 = nf_get_r1(nf); long i, j, d = degpol(polbase); binlS = bin = vecbinomial(d-1); if (!isint1(lS)) binlS = ZC_Z_mul(bin,lS); N2 = cgetg(n+1, t_VEC); for (;;) { GEN G = nf_get_G(nf), matGS = cgetg(d+2, t_MAT); for (j=0; j<=d; j++) gel(matGS,j+1) = arch_for_T2(G, gel(polbase,j+2)); matGS = shallowtrans(matGS); for (j=1; j <= r1; j++) /* N2[j] = || sigma_j(S) ||_2 */ { GEN c = sqrtr( _norml2(gel(matGS,j)) ); gel(N2,j) = c; if (!signe(c)) goto PRECPB; } for ( ; j <= n; j+=2) { GEN q1 = _norml2(gel(matGS, j)); GEN q2 = _norml2(gel(matGS, j+1)); GEN c = sqrtr( gmul2n(addrr(q1, q2), -1) ); gel(N2,j) = gel(N2,j+1) = c; if (!signe(c)) goto PRECPB; } break; /* done */ PRECPB: prec = precdbl(prec); nf = nfnewprec_shallow(nf, prec); if (DEBUGLEVEL>1) pari_warn(warnprec, "nf_factor_bound", prec); } /* Take sup over 0 <= i <= d of * sum_j | binom(d-1, i-1) ||sigma_j(S)||_2 + binom(d-1,i) lc(S) |^2 */ /* i = 0: n lc(S)^2 */ C = mului(n, sqri(lS)); /* i = d: sum_sigma ||sigma(S)||_2^2 */ p1 = gnorml2(N2); if (gcmp(C, p1) < 0) C = p1; for (i = 1; i < d; i++) { GEN B = gel(bin,i), L = gel(binlS,i+1); GEN s = sqrr(addri(mulir(B, gel(N2,1)), L)); /* j=1 */ for (j = 2; j <= n; j++) s = addrr(s, sqrr(addri(mulir(B, gel(N2,j)), L))); if (mpcmp(C, s) < 0) C = s; } return C; } /* return a bound for T_2(P), P | polbase * max |b_i|^2 <= 3^{3/2 + d} / (4 \pi d) [P]_2, * where [P]_2 is Bombieri's 2-norm * Sum over conjugates */ static GEN nf_Beauzamy_bound(GEN nf, GEN polbase) { GEN lt, C, s, POL, bin; long d = degpol(polbase), n = nf_get_degree(nf), prec = nf_get_prec(nf); bin = vecbinomial(d); POL = polbase + 2; /* compute [POL]_2 */ for (;;) { GEN G = nf_get_G(nf); long i; s = real_0(prec); for (i=0; i<=d; i++) { GEN c = gel(POL,i); if (gequal0(c)) continue; c = _norml2(arch_for_T2(G,c)); if (!signe(c)) goto PRECPB; /* s += T2(POL[i]) / binomial(d,i) */ s = addrr(s, divri(c, gel(bin,i+1))); } break; PRECPB: prec = precdbl(prec); nf = nfnewprec_shallow(nf, prec); if (DEBUGLEVEL>1) pari_warn(warnprec, "nf_factor_bound", prec); } lt = leading_coeff(polbase); s = mulri(s, muliu(sqri(lt), n)); C = powruhalf(stor(3,DEFAULTPREC), 3 + 2*d); /* 3^{3/2 + d} */ return divrr(mulrr(C, s), mulur(d, mppi(DEFAULTPREC))); } static GEN nf_factor_bound(GEN nf, GEN polbase) { pari_sp av = avma; GEN a = nf_Mignotte_bound(nf, polbase); GEN b = nf_Beauzamy_bound(nf, polbase); if (DEBUGLEVEL>2) { err_printf("Mignotte bound: %Ps\n",a); err_printf("Beauzamy bound: %Ps\n",b); } return gerepileupto(av, gmin(a, b)); } /* True nf; return Bs: if r a root of sigma_i(P), |r| < Bs[i] */ static GEN nf_root_bounds(GEN nf, GEN P) { long lR, i, j, l, prec, r1; GEN Ps, R, V; if (RgX_is_rational(P)) return polrootsbound(P, NULL); r1 = nf_get_r1(nf); P = Q_primpart(P); prec = ZXX_max_lg(P) + 1; l = lg(P); if (nf_get_prec(nf) >= prec) R = nf_get_roots(nf); else R = QX_complex_roots(nf_get_pol(nf), prec); lR = lg(R); V = cgetg(lR, t_VEC); Ps = cgetg(l, t_POL); /* sigma (P) */ Ps[1] = P[1]; for (j=1; j sqrt(Btra). * d = dimension of low part (= [nf:Q]) * n0 = bound for |vS|^2 * */ static double get_Bhigh(long n0, long d) { double sqrtd = sqrt((double)d); double z = n0*sqrtd + sqrtd/2 * (d * (n0+1)); z = 1. + 0.5 * z; return z * z; } typedef struct { GEN d; GEN dPinvS; /* d P^(-1) S [ integral ] */ double **PinvSdbl; /* P^(-1) S as double */ GEN S1, P1; /* S = S0 + S1 q, idem P */ } trace_data; /* S1 * u - P1 * round(P^-1 S u). K non-zero coords in u given by ind */ static GEN get_trace(GEN ind, trace_data *T) { long i, j, l, K = lg(ind)-1; GEN z, s, v; s = gel(T->S1, ind[1]); if (K == 1) return s; /* compute s = S1 u */ for (j=2; j<=K; j++) s = ZC_add(s, gel(T->S1, ind[j])); /* compute v := - round(P^1 S u) */ l = lg(s); v = cgetg(l, t_VECSMALL); for (i=1; iPinvSdbl[ ind[j] ][i]; r = floor(t + 0.5); if (fabs(t + 0.5 - r) < 0.0001) { /* dubious, compute exactly */ z = gen_0; for (j=1; j<=K; j++) z = addii(z, ((GEN**)T->dPinvS)[ ind[j] ][i]); v[i] = - itos( diviiround(z, T->d) ); } else v[i] = - (long)r; } return ZC_add(s, ZM_zc_mul(T->P1, v)); } static trace_data * init_trace(trace_data *T, GEN S, nflift_t *L, GEN q) { long e = gexpo(S), i,j, l,h; GEN qgood, S1, invd; if (e < 0) return NULL; /* S = 0 */ qgood = int2n(e - 32); /* single precision check */ if (cmpii(qgood, q) > 0) q = qgood; S1 = gdivround(S, q); if (gequal0(S1)) return NULL; invd = invr(itor(L->pk, DEFAULTPREC)); T->dPinvS = ZM_mul(L->iprk, S); l = lg(S); h = lgcols(T->dPinvS); T->PinvSdbl = (double**)cgetg(l, t_MAT); for (j = 1; j < l; j++) { double *t = (double *) stack_malloc_align(h * sizeof(double), sizeof(double)); GEN c = gel(T->dPinvS,j); pari_sp av = avma; T->PinvSdbl[j] = t; for (i=1; i < h; i++) t[i] = rtodbl(mulri(invd, gel(c,i))); avma = av; } T->d = L->pk; T->P1 = gdivround(L->prk, q); T->S1 = S1; return T; } static void update_trace(trace_data *T, long k, long i) { if (!T) return; gel(T->S1,k) = gel(T->S1,i); gel(T->dPinvS,k) = gel(T->dPinvS,i); T->PinvSdbl[k] = T->PinvSdbl[i]; } /* reduce coeffs mod (T,pk), then center mod pk */ static GEN FqX_centermod(GEN z, GEN T, GEN pk, GEN pks2) { long i, l; GEN y; if (!T) return centermod_i(z, pk, pks2); y = FpXQX_red(z, T, pk); l = lg(y); for (i = 2; i < l; i++) { GEN c = gel(y,i); if (typ(c) == t_INT) c = Fp_center_i(c, pk, pks2); else c = FpX_center_i(c, pk, pks2); gel(y,i) = c; } return y; } typedef struct { GEN lt, C, Clt, C2lt, C2ltpol; } div_data; static void init_div_data(div_data *D, GEN pol, nflift_t *L) { GEN C2lt, Clt, C = mul_content(L->topowden, L->dn); GEN lc = leading_coeff(pol), lt = is_pm1(lc)? NULL: absi_shallow(lc); if (C) { GEN C2 = sqri(C); if (lt) { C2lt = mulii(C2, lt); Clt = mulii(C,lt); } else { C2lt = C2; Clt = C; } } else C2lt = Clt = lt; D->lt = lt; D->C = C; D->Clt = Clt; D->C2lt = C2lt; D->C2ltpol = C2lt? RgX_Rg_mul(pol, C2lt): pol; } static void update_target(div_data *D, GEN pol) { D->C2ltpol = D->Clt? RgX_Rg_mul(pol, D->Clt): pol; } /* nb = number of modular factors; return a "good" K such that naive * recombination of up to maxK modular factors is not too costly */ long cmbf_maxK(long nb) { if (nb > 10) return 3; return nb-1; } /* Naive recombination of modular factors: combine up to maxK modular * factors, degree <= klim * * target = polynomial we want to factor * famod = array of modular factors. Product should be congruent to * target/lc(target) modulo p^a * For true factors: S1,S2 <= p^b, with b <= a and p^(b-a) < 2^31 */ /* set *done = 1 if factorisation is known to be complete */ static GEN nfcmbf(nfcmbf_t *T, long klim, long *pmaxK, int *done) { GEN nf = T->nf, famod = T->fact, bound = T->bound; GEN ltdn, nfpol = nf_get_pol(nf); long K = 1, cnt = 1, i,j,k, curdeg, lfamod = lg(famod)-1, dnf = degpol(nfpol); pari_sp av0 = avma; GEN Tpk = T->L->Tpk, pk = T->L->pk, pks2 = shifti(pk,-1); GEN ind = cgetg(lfamod+1, t_VECSMALL); GEN deg = cgetg(lfamod+1, t_VECSMALL); GEN degsofar = cgetg(lfamod+1, t_VECSMALL); GEN fa = cgetg(lfamod+1, t_VEC); const double Bhigh = get_Bhigh(lfamod, dnf); trace_data _T1, _T2, *T1, *T2; div_data D; pari_timer ti; timer_start(&ti); *pmaxK = cmbf_maxK(lfamod); init_div_data(&D, T->pol, T->L); ltdn = mul_content(D.lt, T->L->dn); { GEN q = ceil_safe(sqrtr(T->BS_2)); GEN t1,t2, lt2dn = mul_content(ltdn, D.lt); GEN trace1 = cgetg(lfamod+1, t_MAT); GEN trace2 = cgetg(lfamod+1, t_MAT); for (i=1; i <= lfamod; i++) { pari_sp av = avma; GEN P = gel(famod,i); long d = degpol(P); deg[i] = d; P += 2; t1 = gel(P,d-1);/* = - S_1 */ t2 = Fq_sqr(t1, Tpk, pk); if (d > 1) t2 = Fq_sub(t2, gmul2n(gel(P,d-2), 1), Tpk, pk); /* t2 = S_2 Newton sum */ if (ltdn) { t1 = Fq_Fp_mul(t1, ltdn, Tpk, pk); t2 = Fq_Fp_mul(t2, lt2dn, Tpk, pk); } gel(trace1,i) = gclone( nf_bestlift(t1, NULL, T->L) ); gel(trace2,i) = gclone( nf_bestlift(t2, NULL, T->L) ); avma = av; } T1 = init_trace(&_T1, trace1, T->L, q); T2 = init_trace(&_T2, trace2, T->L, q); for (i=1; i <= lfamod; i++) { gunclone(gel(trace1,i)); gunclone(gel(trace2,i)); } } degsofar[0] = 0; /* sentinel */ /* ind runs through strictly increasing sequences of length K, * 1 <= ind[i] <= lfamod */ nextK: if (K > *pmaxK || 2*K > lfamod) goto END; if (DEBUGLEVEL > 3) err_printf("\n### K = %d, %Ps combinations\n", K,binomial(utoipos(lfamod), K)); setlg(ind, K+1); ind[1] = 1; i = 1; curdeg = deg[ind[1]]; for(;;) { /* try all combinations of K factors */ for (j = i; j < K; j++) { degsofar[j] = curdeg; ind[j+1] = ind[j]+1; curdeg += deg[ind[j+1]]; } if (curdeg <= klim) /* trial divide */ { GEN t, y, q; pari_sp av; av = avma; if (T1) { /* d-1 test */ t = get_trace(ind, T1); if (rtodbl(_norml2(t)) > Bhigh) { if (DEBUGLEVEL>6) err_printf("."); avma = av; goto NEXT; } } if (T2) { /* d-2 test */ t = get_trace(ind, T2); if (rtodbl(_norml2(t)) > Bhigh) { if (DEBUGLEVEL>3) err_printf("|"); avma = av; goto NEXT; } } avma = av; y = ltdn; /* full computation */ for (i=1; i<=K; i++) { GEN q = gel(famod, ind[i]); if (y) q = gmul(y, q); y = FqX_centermod(q, Tpk, pk, pks2); } y = nf_pol_lift(y, bound, T->L); if (!y) { if (DEBUGLEVEL>3) err_printf("@"); avma = av; goto NEXT; } /* y = topowden*dn*lt*\prod_{i in ind} famod[i] is apparently in O_K[X], * in fact in (Z[Y]/nf.pol)[X] due to multiplication by C = topowden*dn. * Try out this candidate factor */ q = RgXQX_divrem(D.C2ltpol, y, nfpol, ONLY_DIVIDES); if (!q) { if (DEBUGLEVEL>3) err_printf("*"); avma = av; goto NEXT; } /* Original T->pol in O_K[X] with leading coeff lt in Z, * y = C*lt \prod famod[i] is in O_K[X] with leading coeff in Z * q = C^2*lt*pol / y = C * (lt*pol) / (lt*\prod famod[i]) is a * K-rational factor, in fact in Z[Y]/nf.pol)[X] as above, with * leading term C*lt. */ update_target(&D, q); gel(fa,cnt++) = D.C2lt? RgX_int_normalize(y): y; /* make monic */ for (i=j=k=1; i <= lfamod; i++) { /* remove used factors */ if (j <= K && i == ind[j]) j++; else { gel(famod,k) = gel(famod,i); update_trace(T1, k, i); update_trace(T2, k, i); deg[k] = deg[i]; k++; } } lfamod -= K; *pmaxK = cmbf_maxK(lfamod); if (lfamod < 2*K) goto END; i = 1; curdeg = deg[ind[1]]; if (DEBUGLEVEL > 2) { err_printf("\n"); timer_printf(&ti, "to find factor %Ps",gel(fa,cnt-1)); err_printf("remaining modular factor(s): %ld\n", lfamod); } continue; } NEXT: for (i = K+1;;) { if (--i == 0) { K++; goto nextK; } if (++ind[i] <= lfamod - K + i) { curdeg = degsofar[i-1] + deg[ind[i]]; if (curdeg <= klim) break; } } } END: *done = 1; if (degpol(D.C2ltpol) > 0) { /* leftover factor */ GEN q = D.C2ltpol; if (D.C2lt) q = RgX_int_normalize(q); if (lfamod >= 2*K) { /* restore leading coefficient [#930] */ if (D.lt) q = RgX_Rg_mul(q, D.lt); *done = 0; /* ... may still be reducible */ } setlg(famod, lfamod+1); gel(fa,cnt++) = q; } if (DEBUGLEVEL>6) err_printf("\n"); setlg(fa, cnt); return gerepilecopy(av0, fa); } static GEN nf_chk_factors(nfcmbf_t *T, GEN P, GEN M_L, GEN famod, GEN pk) { GEN nf = T->nf, bound = T->bound; GEN nfT = nf_get_pol(nf); long i, r; GEN pol = P, list, piv, y; GEN Tpk = T->L->Tpk; div_data D; piv = ZM_hnf_knapsack(M_L); if (!piv) return NULL; if (DEBUGLEVEL>3) err_printf("ZM_hnf_knapsack output:\n%Ps\n",piv); r = lg(piv)-1; list = cgetg(r+1, t_VEC); init_div_data(&D, pol, T->L); for (i = 1;;) { pari_sp av = avma; if (DEBUGLEVEL) err_printf("nf_LLL_cmbf: checking factor %ld\n", i); y = chk_factors_get(D.lt, famod, gel(piv,i), Tpk, pk); if (! (y = nf_pol_lift(y, bound, T->L)) ) return NULL; y = gerepilecopy(av, y); /* y is the candidate factor */ pol = RgXQX_divrem(D.C2ltpol, y, nfT, ONLY_DIVIDES); if (!pol) return NULL; if (D.C2lt) y = RgX_int_normalize(y); gel(list,i) = y; if (++i >= r) break; update_target(&D, pol); } gel(list,i) = RgX_int_normalize(pol); return list; } static GEN nf_to_Zq(GEN x, GEN T, GEN pk, GEN pks2, GEN proj) { GEN y; if (typ(x) != t_COL) return centermodii(x, pk, pks2); if (!T) { y = ZV_dotproduct(proj, x); return centermodii(y, pk, pks2); } y = ZM_ZC_mul(proj, x); y = RgV_to_RgX(y, varn(T)); return FpX_center_i(FpX_rem(y, T, pk), pk, pks2); } /* Assume P in nfX form, lc(P) != 0 mod p. Reduce P to Zp[X]/(T) mod p^a */ static GEN ZqX(GEN P, GEN pk, GEN T, GEN proj) { long i, l = lg(P); GEN z, pks2 = shifti(pk,-1); z = cgetg(l,t_POL); z[1] = P[1]; for (i=2; ipk)): P; return ZqX(R, L->pk, L->Tpk, L->ZqProj); } /* k allowing to reconstruct x, |x|^2 < C, from x mod pr^k */ /* return log [ 2sqrt(C/d) * ( (3/2)sqrt(gamma) )^(d-1) ] ^d / log N(pr) * cf. Belabas relative van Hoeij algorithm, lemma 3.12 */ static double bestlift_bound(GEN C, long d, double alpha, GEN p, long f) { const double g = 1 / (alpha - 0.25); /* = 2 if alpha = 3/4 */ GEN C4 = shiftr(gtofp(C,DEFAULTPREC), 2); double t, logp = log(gtodouble(p)); if (f == d) { /* p inert, no LLL fudge factor: p^(2k) / 4 > C */ t = 0.5 * rtodbl(mplog(C4)); return ceil(t / logp); } /* (1/2)log (4C/d) + (d-1)(log 3/2 sqrt(gamma)) */ t = 0.5 * rtodbl(mplog(divru(C4,d))) + (d-1) * log(1.5 * sqrt(g)); return ceil((t * d) / (logp * f)); } static GEN get_R(GEN M) { GEN R; long i, l, prec = nbits2prec( gexpo(M) + 64 ); for(;;) { R = gaussred_from_QR(M, prec); if (R) break; prec = precdbl(prec); } l = lg(R); for (i=1; iTp)>1) { GEN coTp = FpX_div(FpX_red(nfT, L->p), L->Tp, L->p); /* Tp's cofactor */ GEN z, proj; z = ZpX_liftfact(nfT, mkvec2(L->Tp, coTp), L->pk, L->p, L->k); L->Tpk = gel(z,1); proj = QXQV_to_FpM(L->topow, L->Tpk, L->pk); if (L->topowden) proj = FpM_red(ZM_Z_mul(proj, Fp_inv(L->topowden, L->pk)), L->pk); L->ZqProj = proj; } else { L->Tpk = NULL; L->ZqProj = dim1proj(prkHNF); } } /* Square of the radius of largest ball inscript in PRK's fundamental domain, * whose orthogonalized vector's norms are the Bi * Rmax ^2 = min 1/4T_i where T_i = sum_j ( s_ij^2 / B_j) * For p inert, S = Id, T_i = 1 / p^{2k} and Rmax = p^k / 2 */ static GEN max_radius(GEN PRK, GEN B) { GEN S, smax = gen_0; pari_sp av = avma; long i, j, d = lg(PRK)-1; S = RgM_inv( get_R(PRK) ); if (!S) pari_err_PREC("max_radius"); for (i=1; i<=d; i++) { GEN s = gen_0; for (j=1; j<=d; j++) s = mpadd(s, mpdiv( mpsqr(gcoeff(S,i,j)), gel(B,j))); if (mpcmp(s, smax) > 0) smax = s; } return gerepileupto(av, ginv(gmul2n(smax, 2))); } static void bestlift_init(long a, GEN nf, GEN C, nflift_t *L) { const double alpha = 0.99; /* LLL parameter */ const long d = nf_get_degree(nf); pari_sp av = avma, av2; GEN prk, PRK, iPRK, GSmin, T = L->Tp, p = L->p; long f = degpol(T); pari_timer ti; if (f == d) { /* inert p, much simpler */ long a0 = bestlift_bound(C, d, alpha, p, f); GEN q; if (a < a0) a = a0; /* guarantees GSmin >= C */ if (DEBUGLEVEL>2) err_printf("exponent %ld\n",a); q = powiu(p,a); PRK = prk = scalarmat_shallow(q, d); GSmin = shiftr(itor(q, DEFAULTPREC), -1); iPRK = matid(d); goto END; } timer_start(&ti); if (!a) a = (long)bestlift_bound(C, d, alpha, p, f); for (;; avma = av, a += (a==1)? 1: (a>>1)) /* roughly a *= 1.5 */ { GEN B, q = powiu(p,a), Tq = FpXQ_powu(T, a, FpX_red(nf_get_pol(nf), q), q); if (DEBUGLEVEL>2) err_printf("exponent %ld\n",a); prk = idealhnf_two(nf, mkvec2(q, Tq)); av2 = avma; PRK = ZM_lll_norms(prk, alpha, LLL_INPLACE, &B); GSmin = max_radius(PRK, B); if (gcmp(GSmin, C) >= 0) break; } gerepileall(av2, 2, &PRK, &GSmin); iPRK = ZM_inv(PRK, NULL); if (DEBUGLEVEL>2) err_printf("for this exponent, GSmin = %Ps\nTime reduction: %ld\n", GSmin, timer_delay(&ti)); END: L->k = a; L->pk = gcoeff(prk,1,1); L->prk = PRK; L->iprk = iPRK; L->GSmin= GSmin; init_proj(L, prk, nf_get_pol(nf)); } /* Let X = Tra * M_L, Y = bestlift(X) return V s.t Y = X - PRK V * and set *eT2 = gexpo(Y) [cf nf_bestlift, but memory efficient] */ static GEN get_V(GEN Tra, GEN M_L, GEN PRK, GEN PRKinv, GEN pk, long *eT2) { long i, e = 0, l = lg(M_L); GEN V = cgetg(l, t_MAT); *eT2 = 0; for (i = 1; i < l; i++) { /* cf nf_bestlift(Tra * c) */ pari_sp av = avma, av2; GEN v, T2 = ZM_ZC_mul(Tra, gel(M_L,i)); v = gdivround(ZM_ZC_mul(PRKinv, T2), pk); /* small */ av2 = avma; T2 = ZC_sub(T2, ZM_ZC_mul(PRK, v)); e = gexpo(T2); if (e > *eT2) *eT2 = e; avma = av2; gel(V,i) = gerepileupto(av, v); /* small */ } return V; } static GEN nf_LLL_cmbf(nfcmbf_t *T, long rec) { const double BitPerFactor = 0.4; /* nb bits / modular factor */ nflift_t *L = T->L; GEN famod = T->fact, ZC = T->ZC, Br = T->Br, P = T->pol, dn = T->L->dn; long dnf = nf_get_degree(T->nf), dP = degpol(P); long i, C, tmax, n0; GEN lP, Bnorm, Tra, T2, TT, CM_L, m, list, ZERO, Btra; double Bhigh; pari_sp av, av2; long ti_LLL = 0, ti_CF = 0; pari_timer ti2, TI; lP = absi_shallow(leading_coeff(P)); if (is_pm1(lP)) lP = NULL; n0 = lg(famod) - 1; /* Lattice: (S PRK), small vector (vS vP). To find k bound for the image, * write S = S1 q + S0, P = P1 q + P0 * |S1 vS + P1 vP|^2 <= Bhigh for all (vS,vP) assoc. to true factors */ Btra = mulrr(ZC, mulur(dP*dP, normTp(Br, 2, dnf))); Bhigh = get_Bhigh(n0, dnf); C = (long)ceil(sqrt(Bhigh/n0)) + 1; /* C^2 n0 ~ Bhigh */ Bnorm = dbltor( n0 * C * C + Bhigh ); ZERO = zeromat(n0, dnf); av = avma; TT = const_vec(n0, NULL); Tra = cgetg(n0+1, t_MAT); CM_L = scalarmat_s(C, n0); /* tmax = current number of traces used (and computed so far) */ for(tmax = 0;; tmax++) { long a, b, bmin, bgood, delta, tnew = tmax + 1, r = lg(CM_L)-1; GEN M_L, q, CM_Lp, oldCM_L, S1, P1, VV; int first = 1; /* bound for f . S_k(genuine factor) = ZC * bound for T_2(S_tnew) */ Btra = mulrr(ZC, mulur(dP*dP, normTp(Br, 2*tnew, dnf))); bmin = logint(ceil_safe(sqrtr(Btra)), gen_2) + 1; if (DEBUGLEVEL>2) err_printf("\nLLL_cmbf: %ld potential factors (tmax = %ld, bmin = %ld)\n", r, tmax, bmin); /* compute Newton sums (possibly relifting first) */ if (gcmp(L->GSmin, Btra) < 0) { GEN polred; bestlift_init((L->k)<<1, T->nf, Btra, L); polred = ZqX_normalize(T->polbase, lP, L); famod = ZqX_liftfact(polred, famod, L->Tpk, L->pk, L->p, L->k); for (i=1; i<=n0; i++) gel(TT,i) = NULL; } for (i=1; i<=n0; i++) { GEN h, lPpow = lP? powiu(lP, tnew): NULL; GEN z = polsym_gen(gel(famod,i), gel(TT,i), tnew, L->Tpk, L->pk); gel(TT,i) = z; h = gel(z,tnew+1); /* make Newton sums integral */ lPpow = mul_content(lPpow, dn); if (lPpow) h = (typ(h) == t_INT)? Fp_mul(h, lPpow, L->pk): FpX_Fp_mul(h, lPpow, L->pk); gel(Tra,i) = nf_bestlift(h, NULL, L); /* S_tnew(famod) */ } /* compute truncation parameter */ if (DEBUGLEVEL>2) { timer_start(&ti2); timer_start(&TI); } oldCM_L = CM_L; av2 = avma; b = delta = 0; /* -Wall */ AGAIN: M_L = Q_div_to_int(CM_L, utoipos(C)); VV = get_V(Tra, M_L, L->prk, L->iprk, L->pk, &a); if (first) { /* initialize lattice, using few p-adic digits for traces */ bgood = (long)(a - maxss(32, (long)(BitPerFactor * r))); b = maxss(bmin, bgood); delta = a - b; } else { /* add more p-adic digits and continue reduction */ if (a < b) b = a; b = maxss(b-delta, bmin); if (b - delta/2 < bmin) b = bmin; /* near there. Go all the way */ } /* restart with truncated entries */ q = int2n(b); P1 = gdivround(L->prk, q); S1 = gdivround(Tra, q); T2 = ZM_sub(ZM_mul(S1, M_L), ZM_mul(P1, VV)); m = vconcat( CM_L, T2 ); if (first) { first = 0; m = shallowconcat( m, vconcat(ZERO, P1) ); /* [ C M_L 0 ] * m = [ ] square matrix * [ T2' PRK ] T2' = Tra * M_L truncated */ } CM_L = LLL_check_progress(Bnorm, n0, m, b == bmin, /*dbg:*/ &ti_LLL); if (DEBUGLEVEL>2) err_printf("LLL_cmbf: (a,b) =%4ld,%4ld; r =%3ld -->%3ld, time = %ld\n", a,b, lg(m)-1, CM_L? lg(CM_L)-1: 1, timer_delay(&TI)); if (!CM_L) { list = mkcol(RgX_int_normalize(P)); break; } if (b > bmin) { CM_L = gerepilecopy(av2, CM_L); goto AGAIN; } if (DEBUGLEVEL>2) timer_printf(&ti2, "for this trace"); i = lg(CM_L) - 1; if (i == r && ZM_equal(CM_L, oldCM_L)) { CM_L = oldCM_L; avma = av2; continue; } CM_Lp = FpM_image(CM_L, utoipos(27449)); /* inexpensive test */ if (lg(CM_Lp) != lg(CM_L)) { if (DEBUGLEVEL>2) err_printf("LLL_cmbf: rank decrease\n"); CM_L = ZM_hnf(CM_L); } if (i <= r && i*rec < n0) { pari_timer ti; if (DEBUGLEVEL>2) timer_start(&ti); list = nf_chk_factors(T, P, Q_div_to_int(CM_L,utoipos(C)), famod, L->pk); if (DEBUGLEVEL>2) ti_CF += timer_delay(&ti); if (list) break; } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"nf_LLL_cmbf"); gerepileall(av, L->Tpk? 9: 8, &CM_L,&TT,&Tra,&famod,&L->GSmin,&L->pk,&L->prk,&L->iprk, &L->Tpk); } else CM_L = gerepilecopy(av2, CM_L); } if (DEBUGLEVEL>2) err_printf("* Time LLL: %ld\n* Time Check Factor: %ld\n",ti_LLL,ti_CF); return list; } static GEN nf_combine_factors(nfcmbf_t *T, GEN polred, long klim) { nflift_t *L = T->L; GEN res; long maxK; int done; pari_timer ti; if (DEBUGLEVEL>2) timer_start(&ti); T->fact = ZqX_liftfact(polred, T->fact, L->Tpk, L->pk, L->p, L->k); if (DEBUGLEVEL>2) timer_printf(&ti, "Hensel lift"); res = nfcmbf(T, klim, &maxK, &done); if (DEBUGLEVEL>2) timer_printf(&ti, "Naive recombination"); if (!done) { long l = lg(res)-1; GEN v; if (l > 1) { GEN den; T->pol = gel(res,l); T->polbase = Q_remove_denom(RgX_to_nfX(T->nf, T->pol), &den); if (den) { T->Br = gmul(T->Br, den); T->pol = RgX_Rg_mul(T->pol, den); } } v = nf_LLL_cmbf(T, maxK); /* remove last elt, possibly unfactored. Add all new ones. */ setlg(res, l); res = shallowconcat(res, v); } return res; } static GEN nf_DDF_roots(GEN pol, GEN polred, GEN nfpol, long fl, nflift_t *L) { GEN z, Cltx_r, ltdn; long i, m, lz; div_data D; init_div_data(&D, pol, L); ltdn = mul_content(D.lt, L->dn); z = ZqX_roots(polred, L->Tpk, L->p, L->k); Cltx_r = deg1pol_shallow(D.Clt? D.Clt: gen_1, NULL, varn(pol)); lz = lg(z); if (DEBUGLEVEL > 3) err_printf("Checking %ld roots:",lz-1); for (m=1,i=1; i 3) err_printf(" %ld",i); /* lt*dn*topowden * r = Clt * r */ r = nf_bestlift_to_pol(ltdn? gmul(ltdn,r): r, NULL, L); av = avma; gel(Cltx_r,2) = gneg(r); /* check P(r) == 0 */ dvd = ZXQX_dvd(D.C2ltpol, Cltx_r, nfpol); /* integral */ avma = av; /* don't go on with q, usually much larger that C2ltpol */ if (dvd) { if (D.Clt) r = gdiv(r, D.Clt); gel(z,m++) = r; } else if (fl == ROOTS_SPLIT) return cgetg(1, t_VEC); } if (DEBUGLEVEL > 3) err_printf(" done\n"); z[0] = evaltyp(t_VEC) | evallg(m); return z; } /* returns a few factors of T in Fp of degree <= maxf, NULL if none exist */ static GEN get_good_factor(GEN T, ulong p, long maxf) { pari_sp av = avma; GEN r, R = gel(Flx_factor(ZX_to_Flx(T,p),p), 1); if (maxf == 1) { /* degree 1 factors are best */ r = gel(R,1); if (degpol(r) == 1) return mkvec(r); } else { /* otherwise, pick factor of largish degree */ long i, j, dr, d = 0, l = lg(R); GEN v; if (l == 2) return mkvec(gel(R,1)); /* inert is fine */ v = cgetg(l, t_VEC); for (i = j = 1; i < l; i++) { r = gel(R,i); dr = degpol(r); if (dr > maxf) break; if (dr != d) { gel(v,j++) = r; d = dr; } } setlg(v,j); if (j > 1) return v; } avma = av; return NULL; /* failure */ } /* n = number of modular factors, f = residue degree; nold/fold current best * return 1 if new values are "better" than old ones */ static int record(long nold, long n, long fold, long f) { if (!nold) return 1; /* uninitialized */ if (fold == f) return n < nold; /* if f increases, allow increasing n a little */ if (fold < f) return n <= 20 || n < 1.1*nold; /* f decreases, only allow if decreasing n a lot */ return n < 0.7*nold; } /* Optimization problem: factorization of polynomials over large Fq is slow, * BUT bestlift correspondingly faster. * Return maximal residue degree to be considered when picking a prime ideal */ static long get_maxf(long nfdeg) { long maxf = 1; if (nfdeg >= 45) maxf =32; else if (nfdeg >= 30) maxf =16; else if (nfdeg >= 15) maxf = 8; return maxf; } /* number of maximal ideals to test before settling on best prime and number * of factors; B = [K:Q]*deg(P) */ static long get_nbprimes(long B) { if (B <= 128) return 5; if (B <= 1024) return 20; if (B <= 2048) return 65; return 100; } /* Select a prime ideal pr over which to factor pol. * Return the number of factors (or roots, according to flag fl) mod pr. * Set: * lt: leading term of polbase (t_INT or NULL [ for 1 ]) * pr: a suitable maximal ideal * Fa: factors found mod pr * Tp: polynomial defining Fq/Fp */ static long nf_pick_prime(GEN nf, GEN pol, long fl, GEN *lt, GEN *Tp, ulong *pp) { GEN nfpol = nf_get_pol(nf), bad = mulii(nf_get_disc(nf), nf_get_index(nf)); long nfdeg = degpol(nfpol), dpol = degpol(pol), nold = 0, fold = 1; long maxf = get_maxf(nfdeg), ct = get_nbprimes(nfdeg * dpol); ulong p; forprime_t S; pari_timer ti_pr; if (DEBUGLEVEL>3) timer_start(&ti_pr); *lt = leading_coeff(pol); /* t_INT */ if (gequal1(*lt)) *lt = NULL; *pp = 0; *Tp = NULL; (void)u_forprime_init(&S, 2, ULONG_MAX); /* select pr such that pol has the smallest number of factors, ct attempts */ while ((p = u_forprime_next(&S))) { GEN vT; long n, i, l, ok = 0; ulong ltp = 0; if (! umodiu(bad,p)) continue; if (*lt) { ltp = umodiu(*lt, p); if (!ltp) continue; } vT = get_good_factor(nfpol, p, maxf); if (!vT) continue; l = lg(vT); for (i = 1; i < l; i++) { pari_sp av2 = avma; GEN T = gel(vT,i), red = RgX_to_FlxqX(pol, T, p); long f = degpol(T); if (f == 1) { /* degree 1 */ red = FlxX_to_Flx(red); if (ltp) red = Flx_normalize(red, p); if (!Flx_is_squarefree(red, p)) { avma = av2; continue; } ok = 1; n = (fl == FACTORS)? Flx_nbfact(red,p): Flx_nbroots(red,p); } else { if (ltp) red = FlxqX_normalize(red, T, p); if (!FlxqX_is_squarefree(red, T, p)) { avma = av2; continue; } ok = 1; n = (fl == FACTORS)? FlxqX_nbfact(red,T,p): FlxqX_nbroots(red,T,p); } if (fl == ROOTS_SPLIT && n < dpol) return n; /* not split */ if (n <= 1) { if (fl == FACTORS) return n; /* irreducible */ if (!n) return 0; /* no root */ } if (DEBUGLEVEL>3) err_printf("%3ld %s at prime (%ld,x^%ld+...)\n Time: %ld\n", n, (fl == FACTORS)? "factors": "roots", p,f, timer_delay(&ti_pr)); if (fl == ROOTS && f==nfdeg) { *Tp = T; *pp = p; return n; } if (record(nold, n, fold, f)) { nold = n; fold = f; *Tp = T; *pp = p; } else avma = av2; } if (ok && --ct <= 0) break; } if (!nold) pari_err_OVERFLOW("nf_pick_prime [ran out of primes]"); return nold; } /* Assume lt(T) is a t_INT and T square free. Return t_VEC of irred. factors */ static GEN nfsqff_trager(GEN u, GEN T, GEN dent) { long k = 0, i, lx; GEN U, P, x0, mx0, fa, n = ZX_ZXY_rnfequation(T, u, &k); int tmonic; if (DEBUGLEVEL>4) err_printf("nfsqff_trager: choosing k = %ld\n",k); /* n guaranteed to be squarefree */ fa = ZX_DDF(Q_primpart(n)); lx = lg(fa); if (lx == 2) return mkvec(u); tmonic = is_pm1(leading_coeff(T)); P = cgetg(lx,t_VEC); x0 = deg1pol_shallow(stoi(-k), gen_0, varn(T)); mx0 = deg1pol_shallow(stoi(k), gen_0, varn(T)); U = RgXQX_translate(u, mx0, T); if (!tmonic) U = Q_primpart(U); for (i=lx-1; i>0; i--) { GEN f = gel(fa,i), F = nfgcd(U, f, T, dent); F = RgXQX_translate(F, x0, T); /* F = gcd(f, u(t - x0)) [t + x0] = gcd(f(t + x0), u), more efficient */ if (typ(F) != t_POL || degpol(F) == 0) pari_err_IRREDPOL("factornf [modulus]",T); gel(P,i) = QXQX_normalize(F, T); } gen_sort_inplace(P, (void*)&cmp_RgX, &gen_cmp_RgX, NULL); return P; } /* Factor polynomial a on the number field defined by polynomial T, using * Trager's trick */ GEN polfnf(GEN a, GEN T) { GEN rep = cgetg(3, t_MAT), A, B, y, dent, bad; long dA; int tmonic; if (typ(a)!=t_POL) pari_err_TYPE("polfnf",a); if (typ(T)!=t_POL) pari_err_TYPE("polfnf",T); T = Q_primpart(T); tmonic = is_pm1(leading_coeff(T)); RgX_check_ZX(T,"polfnf"); A = Q_primpart( QXQX_normalize(RgX_nffix("polfnf",T,a,1), T) ); dA = degpol(A); if (dA <= 0) { avma = (pari_sp)(rep + 3); return (dA == 0)? trivial_fact(): zerofact(varn(A)); } bad = dent = ZX_disc(T); if (tmonic) dent = indexpartial(T, dent); (void)nfgcd_all(A,RgX_deriv(A), T, dent, &B); if (degpol(B) != dA) B = Q_primpart( QXQX_normalize(B, T) ); ensure_lt_INT(B); y = nfsqff_trager(B, T, dent); fact_from_sqff(rep, A, B, y, T, bad); return sort_factor_pol(rep, cmp_RgX); } static int nfsqff_use_Trager(long n, long dpol) { return dpol*3 0, deg(nfpol) > 1 fl is either FACTORS (return factors), or ROOTS / ROOTS_SPLIT (return roots): - ROOTS, return only the roots of x in nf - ROOTS_SPLIT, as ROOTS if pol splits, [] otherwise den is usually 1, otherwise nf.zk is doubtful, and den bounds the denominator of an arbitrary element of Z_nf on nf.zk */ static GEN nfsqff(GEN nf, GEN pol, long fl, GEN den) { long n, nbf, dpol = degpol(pol); GEN C0, polbase; GEN N2, res, polred, lt, nfpol = typ(nf)==t_POL?nf:nf_get_pol(nf); ulong pp; nfcmbf_t T; nflift_t L; pari_timer ti, ti_tot; if (DEBUGLEVEL>2) { timer_start(&ti); timer_start(&ti_tot); } n = degpol(nfpol); /* deg = 1 => irreducible */ if (dpol == 1) { if (fl == FACTORS) return mkvec(QXQX_normalize(pol, nfpol)); return mkvec(gneg(gdiv(gel(pol,2),gel(pol,3)))); } if (typ(nf)==t_POL || nfsqff_use_Trager(n,dpol)) { GEN z; if (DEBUGLEVEL>2) err_printf("Using Trager's method\n"); if (typ(nf) != t_POL) den = mulii(den, nf_get_index(nf)); z = nfsqff_trager(Q_primpart(pol), nfpol, den); if (fl != FACTORS) { long i, l = lg(z); for (i = 1; i < l; i++) { GEN LT, t = gel(z,i); if (degpol(t) > 1) break; LT = gel(t,3); if (typ(LT) == t_POL) LT = gel(LT,2); /* constant */ gel(z,i) = gdiv(gel(t,2), negi(LT)); } setlg(z, i); if (fl == ROOTS_SPLIT && i != l) return cgetg(1,t_VEC); } return z; } polbase = RgX_to_nfX(nf, pol); nbf = nf_pick_prime(nf, pol, fl, <, &L.Tp, &pp); if (L.Tp) { L.Tp = Flx_to_ZX(L.Tp); L.p = utoi(pp); } if (fl == ROOTS_SPLIT && nbf < dpol) return cgetg(1,t_VEC); if (nbf <= 1) { if (fl == FACTORS) return mkvec(QXQX_normalize(pol, nfpol)); /* irred. */ if (!nbf) return cgetg(1,t_VEC); /* no root */ } if (DEBUGLEVEL>2) { timer_printf(&ti, "choice of a prime ideal"); err_printf("Prime ideal chosen: (%lu,x^%ld+...)\n", pp, degpol(L.Tp)); } L.tozk = nf_get_invzk(nf); L.topow= nf_get_zkprimpart(nf); L.topowden = nf_get_zkden(nf); if (is_pm1(den)) den = NULL; L.dn = den; T.ZC = L2_bound(nf, den); T.Br = nf_root_bounds(nf, pol); if (lt) T.Br = gmul(T.Br, lt); /* C0 = bound for T_2(Q_i), Q | P */ if (fl != FACTORS) C0 = normTp(T.Br, 2, n); else C0 = nf_factor_bound(nf, polbase); T.bound = mulrr(T.ZC, C0); /* bound for |Q_i|^2 in Z^n on chosen Z-basis */ N2 = mulur(dpol*dpol, normTp(T.Br, 4, n)); /* bound for T_2(lt * S_2) */ T.BS_2 = mulrr(T.ZC, N2); /* bound for |S_2|^2 on chosen Z-basis */ if (DEBUGLEVEL>2) { timer_printf(&ti, "bound computation"); err_printf(" 1) T_2 bound for %s: %Ps\n", fl == FACTORS?"factor": "root", C0); err_printf(" 2) Conversion from T_2 --> | |^2 bound : %Ps\n", T.ZC); err_printf(" 3) Final bound: %Ps\n", T.bound); } bestlift_init(0, nf, T.bound, &L); if (DEBUGLEVEL>2) timer_start(&ti); polred = ZqX_normalize(polbase, lt, &L); /* monic */ if (fl != FACTORS) { GEN z = nf_DDF_roots(pol, polred, nfpol, fl, &L); if (lg(z) == 1) return cgetg(1, t_VEC); return z; } T.fact = gel(FqX_factor(polred, L.Tp, L.p), 1); if (DEBUGLEVEL>2) timer_printf(&ti, "splitting mod %Ps^%ld", L.p, degpol(L.Tp)); T.L = &L; T.polbase = polbase; T.pol = pol; T.nf = nf; res = nf_combine_factors(&T, polred, dpol-1); if (DEBUGLEVEL>2) err_printf("Total Time: %ld\n===========\n", timer_delay(&ti_tot)); return res; } /* assume pol monic in nf.zk[X] */ GEN nfroots_if_split(GEN *pnf, GEN pol) { GEN T = get_nfpol(*pnf,pnf), den = fix_nf(pnf, &T, &pol); pari_sp av = avma; GEN z = nfsqff(*pnf, pol, ROOTS_SPLIT, den); if (lg(z) == 1) { avma = av; return NULL; } return gerepilecopy(av, z); } /*******************************************************************/ /* */ /* Roots of unity in a number field */ /* (alternative to nfrootsof1 using factorization in K[X]) */ /* */ /*******************************************************************/ /* Code adapted from nffactor. Structure of the algorithm; only step 1 is * specific to roots of unity. * * [Step 1]: guess roots via ramification. If trivial output this. * [Step 2]: select prime [p] unramified and ideal [pr] above * [Step 3]: evaluate the maximal exponent [k] such that the fondamental domain * of a LLL-reduction of [prk] = pr^k contains a ball of radius larger * than the norm of any root of unity. * [Step 3]: select a heuristic exponent, * LLL reduce prk=pr^k and verify the exponent is sufficient, * otherwise try a larger one. * [Step 4]: factor the cyclotomic polynomial mod [pr], * Hensel lift to pr^k and find the representative in the ball * If there is it is a primitive root */ /* Choose prime ideal unramified with "large" inertia degree */ static void nf_pick_prime_for_units(GEN nf, nflift_t *L) { GEN nfpol = nf_get_pol(nf), bad = mulii(nf_get_disc(nf), nf_get_index(nf)); GEN ap = NULL, r = NULL; long nfdeg = degpol(nfpol), maxf = get_maxf(nfdeg); ulong pp; forprime_t S; (void)u_forprime_init(&S, 2, ULONG_MAX); while ( (pp = u_forprime_next(&S)) ) { if (! umodiu(bad,pp)) continue; r = get_good_factor(nfpol, pp, maxf); if (r) break; } if (!r) pari_err_OVERFLOW("nf_pick_prime [ran out of primes]"); r = gel(r,lg(r)-1); /* largest inertia degree */ ap = utoipos(pp); L->p = ap; L->Tp = Flx_to_ZX(r); L->tozk = nf_get_invzk(nf); L->topow = nf_get_zkprimpart(nf); L->topowden = nf_get_zkden(nf); } /* *Heuristic* exponent k such that the fundamental domain of pr^k * should contain the ball of radius C */ static double mybestlift_bound(GEN C) { C = gtofp(C,DEFAULTPREC); return ceil(log(gtodouble(C)) / 0.2) + 3; } /* simplified nf_DDF_roots: polcyclo(n) monic in ZX either splits or has no * root in nf. * Return a root or NULL (no root) */ static GEN nfcyclo_root(long n, GEN nfpol, nflift_t *L) { GEN q, r, Cltx_r, pol = polcyclo(n,0), gn = utoipos(n); div_data D; init_div_data(&D, pol, L); (void)Fq_sqrtn(gen_1, gn, L->Tp, L->p, &r); /* r primitive n-th root of 1 in Fq */ r = Zq_sqrtnlift(gen_1, gn, r, L->Tpk, L->p, L->k); /* lt*dn*topowden * r = Clt * r */ r = nf_bestlift_to_pol(r, NULL, L); Cltx_r = deg1pol_shallow(D.Clt? D.Clt: gen_1, gneg(r), varn(pol)); /* check P(r) == 0 */ q = RgXQX_divrem(D.C2ltpol, Cltx_r, nfpol, ONLY_DIVIDES); /* integral */ if (!q) return NULL; if (D.Clt) r = gdiv(r, D.Clt); return r; } /* Guesses the number of roots of unity in number field [nf]. * Computes gcd of N(P)-1 for some primes. The value returned is a proven * multiple of the correct value. */ static long guess_roots(GEN nf) { long c = 0, nfdegree = nf_get_degree(nf), B = nfdegree + 20, l; ulong p = 2; GEN T = nf_get_pol(nf), D = nf_get_disc(nf), index = nf_get_index(nf); GEN nbroots = NULL; forprime_t S; pari_sp av; (void)u_forprime_init(&S, 3, ULONG_MAX); av = avma; /* result must be stationary (counter c) for at least B loops */ for (l=1; (p = u_forprime_next(&S)); l++) { GEN old, F, pf_1, Tp; long i, nb, gcdf = 0; if (!umodiu(D,p) || !umodiu(index,p)) continue; Tp = ZX_to_Flx(T,p); /* squarefree */ F = Flx_nbfact_by_degree(Tp, &nb, p); /* the gcd of the p^f - 1 is p^(gcd of the f's) - 1 */ for (i = 1; i <= nfdegree; i++) if (F[i]) { gcdf = gcdf? ugcd(gcdf, i): i; if (gcdf == 1) break; } pf_1 = subiu(powuu(p, gcdf), 1); old = nbroots; nbroots = nbroots? gcdii(pf_1, nbroots): pf_1; if (DEBUGLEVEL>5) err_printf("p=%lu; gcf(f(P/p))=%ld; nbroots | %Ps",p, gcdf, nbroots); /* if same result go on else reset the stop counter [c] */ if (old && equalii(nbroots,old)) { if (!is_bigint(nbroots) && ++c > B) break; } else c = 0; } if (!nbroots) pari_err_OVERFLOW("guess_roots [ran out of primes]"); if (DEBUGLEVEL>5) err_printf("%ld loops\n",l); avma = av; return itos(nbroots); } /* T(x) an irreducible ZX. Is it of the form Phi_n(c \pm x) ? * Return NULL if not, and a root of 1 of maximal order in Z[x]/(T) otherwise * * N.B. Set n_squarefree = 1 if n is squarefree, and 0 otherwise. * This last parameter is inconvenient, but it allows a cheap * stringent test. (n guessed from guess_roots())*/ static GEN ZXirred_is_cyclo_translate(GEN T, long n_squarefree) { long r, m, d = degpol(T); GEN T1, c = divis_rem(gel(T, d+1), d, &r); /* d-1 th coeff divisible by d ? */ /* The trace coefficient of polcyclo(n) is \pm1 if n is square free, and 0 * otherwise. */ if (!n_squarefree) { if (r) return NULL; } else { if (r < -1) { r += d; c = subiu(c, 1); } else if (r == d-1) { r = -1; c = addiu(c, 1); } if (r != 1 && r != -1) return NULL; } if (signe(c)) /* presumably Phi_guess(c \pm x) */ T = RgX_translate(T, negi(c)); if (!n_squarefree) T = RgX_deflate_max(T, &m); /* presumably Phi_core(guess)(\pm x), cyclotomic iff original T was */ T1 = ZX_graeffe(T); if (ZX_equal(T, T1)) /* T = Phi_n, n odd */ return deg1pol_shallow(gen_m1, negi(c), varn(T)); else if (ZX_equal(T1, ZX_z_unscale(T, -1))) /* T = Phi_{2n}, nodd */ return deg1pol_shallow(gen_1, c, varn(T)); return NULL; } static GEN trivroots(void) { return mkvec2(gen_2, gen_m1); } /* Number of roots of unity in number field [nf]. */ GEN rootsof1(GEN nf) { nflift_t L; GEN T, q, fa, LP, LE, C0, z, disc; pari_timer ti; long i, l, nbguessed, nbroots, nfdegree; pari_sp av; nf = checknf(nf); if (nf_get_r1(nf)) return trivroots(); /* Step 1 : guess number of roots and discard trivial case 2 */ if (DEBUGLEVEL>2) timer_start(&ti); nbguessed = guess_roots(nf); if (DEBUGLEVEL>2) timer_printf(&ti, "guessing roots of 1 [guess = %ld]", nbguessed); if (nbguessed == 2) return trivroots(); nfdegree = nf_get_degree(nf); fa = factoru(nbguessed); LP = gel(fa,1); l = lg(LP); LE = gel(fa,2); disc = nf_get_disc(nf); for (i = 1; i < l; i++) { long p = LP[i]; /* Degree and ramification test: find largest k such that Q(zeta_{p^k}) * may be a subfield of K. Q(zeta_p^k) has degree (p-1)p^(k-1) * and v_p(discriminant) = ((p-1)k-1)p^(k-1); so we must have * v_p(disc_K) >= ((p-1)k-1) * n / (p-1) = kn - q, where q = n/(p-1) */ if (p == 2) { /* the test simplifies a little in that case */ long v, vnf, k; if (LE[i] == 1) continue; vnf = vals(nfdegree); v = vali(disc); for (k = minss(LE[i], vnf+1); k >= 1; k--) if (v >= nfdegree*(k-1)) { nbguessed >>= LE[i]-k; LE[i] = k; break; } /* N.B the test above always works for k = 1: LE[i] >= 1 */ } else { long v, vnf, k; ulong r, q = udivuu_rem(nfdegree, p-1, &r); if (r) { nbguessed /= upowuu(p, LE[i]); LE[i] = 0; continue; } /* q = n/(p-1) */ vnf = u_lval(q, p); v = Z_lval(disc, p); for (k = minss(LE[i], vnf+1); k >= 0; k--) if (v >= nfdegree*k-(long)q) { nbguessed /= upowuu(p, LE[i]-k); LE[i] = k; break; } /* N.B the test above always works for k = 0: LE[i] >= 0 */ } } if (DEBUGLEVEL>2) timer_printf(&ti, "after ramification conditions [guess = %ld]", nbguessed); if (nbguessed == 2) return trivroots(); av = avma; /* Step 1.5 : test if nf.pol == subst(polcyclo(nbguessed), x, \pm x+c) */ T = nf_get_pol(nf); if (eulerphiu_fact(fa) == (ulong)nfdegree) { z = ZXirred_is_cyclo_translate(T, uissquarefree_fact(fa)); if (DEBUGLEVEL>2) timer_printf(&ti, "checking for cyclotomic polynomial"); if (z) { z = nf_to_scalar_or_basis(nf,z); return gerepilecopy(av, mkvec2(utoipos(nbguessed), z)); } avma = av; } /* Step 2 : choose a prime ideal for local lifting */ nf_pick_prime_for_units(nf, &L); if (DEBUGLEVEL>2) timer_printf(&ti, "choosing prime %Ps, degree %ld", L.p, L.Tp? degpol(L.Tp): 1); /* Step 3 : compute a reduced pr^k allowing lifting of local solutions */ /* evaluate maximum L2 norm of a root of unity in nf */ C0 = gmulsg(nfdegree, L2_bound(nf, gen_1)); /* lift and reduce pr^k */ if (DEBUGLEVEL>2) err_printf("Lift pr^k; GSmin wanted: %Ps\n",C0); bestlift_init((long)mybestlift_bound(C0), nf, C0, &L); L.dn = NULL; if (DEBUGLEVEL>2) timer_start(&ti); /* Step 4 : actual computation of roots */ nbroots = 2; z = gen_m1; q = powiu(L.p,degpol(L.Tp)); for (i = 1; i < l; i++) { /* for all prime power factors of nbguessed, find a p^k-th root of unity */ long k, p = LP[i]; for (k = minss(LE[i], Z_lval(subiu(q,1UL),p)); k > 0; k--) { /* find p^k-th roots */ pari_sp av = avma; long pk = upowuu(p,k); GEN r; if (pk==2) continue; /* no need to test second roots ! */ r = nfcyclo_root(pk, T, &L); if (DEBUGLEVEL>2) timer_printf(&ti, "for factoring Phi_%ld^%ld", p,k); if (r) { if (DEBUGLEVEL>2) err_printf(" %s root of unity found\n",uordinal(pk)); if (p==2) { nbroots = pk; z = r; } else { nbroots *= pk; z = nfmul(nf, z,r); } break; } avma = av; if (DEBUGLEVEL) pari_warn(warner,"rootsof1: wrong guess"); } } return gerepilecopy(av, mkvec2(utoi(nbroots), z)); } static long zk_equal1(GEN y) { if (typ(y) == t_INT) return equali1(y); return equali1(gel(y,1)) && ZV_isscalar(y); } /* x^w = 1 */ static GEN is_primitive_root(GEN nf, GEN fa, GEN x, long w) { GEN P = gel(fa,1); long i, l = lg(P); for (i = 1; i < l; i++) { long p = itos(gel(P,i)); GEN y = nfpow_u(nf,x, w/p); if (zk_equal1(y) > 0) /* y = 1 */ { if (p != 2 || !equali1(gcoeff(fa,i,2))) return NULL; x = gneg_i(x); } } return x; } GEN rootsof1_kannan(GEN nf) { pari_sp av = avma; long N, k, i, ws, prec; GEN z, y, d, list, w; nf = checknf(nf); if ( nf_get_r1(nf) ) return trivroots(); N = nf_get_degree(nf); prec = nf_get_prec(nf); for (;;) { GEN R = R_from_QR(nf_get_G(nf), prec); if (R) { y = fincke_pohst(mkvec(R), utoipos(N), N * N, 0, NULL); if (y) break; } prec = precdbl(prec); if (DEBUGLEVEL) pari_warn(warnprec,"rootsof1",prec); nf = nfnewprec_shallow(nf,prec); } if (itos(ground(gel(y,2))) != N) pari_err_BUG("rootsof1 (bug1)"); w = gel(y,1); ws = itos(w); if (ws == 2) { avma = av; return trivroots(); } d = Z_factor(w); list = gel(y,3); k = lg(list); for (i=1; i 1; chi character on G ~ cyc. * Return [d,c] such that: chi( g_i ) = e(chi[i] / cyc[i]) = e(c[i]/ d) */ GEN char_normalize(GEN chi, GEN ncyc) { long i, l = lg(chi); GEN c = cgetg(l, t_VEC); if (l > 1) { gel(c,1) = gel(chi,1); for (i = 2; i < l; i++) gel(c,i) = mulii(gel(chi,i), gel(ncyc,i)); } return char_simplify(gel(ncyc,1), c); } /* Called by function 's'. x is a group object affording ".cyc" method, and * chi an abelian character. Return NULL if the group is (Z/nZ)^* [special * case more character types allowed] and x.cyc otherwise */ static GEN get_cyc(GEN x, GEN chi, const char *s) { if (nftyp(x) == typ_BIDZ) { if (!zncharcheck(x, chi)) pari_err_TYPE(s, chi); return NULL; } else { if (typ(x) != t_VEC || !RgV_is_ZV(x)) x = member_cyc(x); if (!char_check(x, chi)) pari_err_TYPE(s, chi); return x; } } /* conjugate character [ZV/ZC] */ GEN charconj(GEN cyc, GEN chi) { long i, l; GEN z = cgetg_copy(chi, &l); for (i = 1; i < l; i++) { GEN c = gel(chi,i); gel(z,i) = signe(c)? subii(gel(cyc,i), c): gen_0; } return z; } GEN charconj0(GEN x, GEN chi) { GEN cyc = get_cyc(x, chi, "charconj"); return cyc? charconj(cyc, chi): zncharconj(x, chi); } GEN charorder(GEN cyc, GEN x) { pari_sp av = avma; long i, l = lg(cyc); GEN f = gen_1; for (i = 1; i < l; i++) if (signe(gel(x,i))) { GEN c, o = gel(cyc,i); c = gcdii(o, gel(x,i)); if (!is_pm1(c)) o = diviiexact(o,c); f = lcmii(f, o); } return gerepileuptoint(av, f); } GEN charorder0(GEN x, GEN chi) { GEN cyc = get_cyc(x, chi, "charorder"); return cyc? charorder(cyc, chi): zncharorder(x, chi); } /* chi character of abelian G: chi[i] = chi(z_i), where G = \oplus Z/cyc[i] z_i. * Return Ker chi */ GEN charker(GEN cyc, GEN chi) { long i, l = lg(cyc); GEN nchi, ncyc, m, U; if (l == 1) return cgetg(1,t_MAT); /* trivial subgroup */ ncyc = cyc_normalize(cyc); nchi = char_normalize(chi, ncyc); m = shallowconcat(gel(nchi,2), gel(nchi,1)); U = gel(ZV_extgcd(m), 2); setlg(U,l); for (i = 1; i < l; i++) setlg(U[i], l); return hnfmodid(U, gel(ncyc,1)); } GEN charker0(GEN x, GEN chi) { GEN cyc = get_cyc(x, chi, "charker"); return cyc? charker(cyc, chi): zncharker(x, chi); } GEN charpow(GEN cyc, GEN a, GEN N) { long i, l; GEN v = cgetg_copy(a, &l); for (i = 1; i < l; i++) gel(v,i) = Fp_mul(gel(a,i), N, gel(cyc,i)); return v; } GEN charmul(GEN cyc, GEN a, GEN b) { long i, l; GEN v = cgetg_copy(a, &l); for (i = 1; i < l; i++) gel(v,i) = Fp_add(gel(a,i), gel(b,i), gel(cyc,i)); return v; } GEN chardiv(GEN cyc, GEN a, GEN b) { long i, l; GEN v = cgetg_copy(a, &l); for (i = 1; i < l; i++) gel(v,i) = Fp_sub(gel(a,i), gel(b,i), gel(cyc,i)); return v; } GEN charpow0(GEN x, GEN a, GEN N) { GEN cyc = get_cyc(x, a, "charpow"); return cyc? charpow(cyc, a, N): zncharpow(x, a, N); } GEN charmul0(GEN x, GEN a, GEN b) { const char *s = "charmul"; GEN cyc = get_cyc(x, a, s); if (!cyc) { if (!zncharcheck(x, b)) pari_err_TYPE(s, b); return zncharmul(x, a, b); } else { if (!char_check(cyc, b)) pari_err_TYPE(s, b); return charmul(cyc, a, b); } } GEN chardiv0(GEN x, GEN a, GEN b) { const char *s = "chardiv"; GEN cyc = get_cyc(x, a, s); if (!cyc) { if (!zncharcheck(x, b)) pari_err_TYPE(s, b); return znchardiv(x, a, b); } else { if (!char_check(cyc, b)) pari_err_TYPE(s, b); return chardiv(cyc, a, b); } } static GEN chareval_i(GEN nchi, GEN dlog, GEN z) { GEN o, q, r, b = gel(nchi,1); GEN a = FpV_dotproduct(gel(nchi,2), dlog, b); /* image is a/b in Q/Z */ if (!z) return gdiv(a,b); if (typ(z) == t_INT) { q = dvmdii(z, b, &r); if (signe(r)) pari_err_TYPE("chareval", z); return mulii(a, q); } /* return z^(a*o/b), assuming z^o = 1 and b | o */ if (typ(z) != t_VEC || lg(z) != 3) pari_err_TYPE("chareval", z); o = gel(z,2); if (typ(o) != t_INT) pari_err_TYPE("chareval", z); q = dvmdii(o, b, &r); if (signe(r)) pari_err_TYPE("chareval", z); q = mulii(a, q); /* in [0, o[ since a is reduced mod b */ z = gel(z,1); if (typ(z) == t_VEC) { if (itos_or_0(o) != lg(z)-1) pari_err_TYPE("chareval", z); return gcopy(gel(z, itos(q)+1)); } else return gpow(z, q, DEFAULTPREC); } static GEN not_coprime(GEN z) { return (!z || typ(z) == t_INT)? gen_m1: gen_0; } static GEN get_chi(GEN cyc, GEN chi) { if (!char_check(cyc,chi)) pari_err_TYPE("chareval", chi); return char_normalize(chi, cyc_normalize(cyc)); } /* G a bnr. FIXME: horribly inefficient to check that (x,N)=1, what to do ? */ static int bnr_coprime(GEN G, GEN x) { GEN t, N = gel(bnr_get_mod(G), 1); if (typ(x) == t_INT) /* shortcut */ { t = gcdii(gcoeff(N,1,1), x); if (equali1(t)) return 1; t = idealadd(G, N, x); return equali1(gcoeff(t,1,1)); } x = idealnumden(G, x); t = idealadd(G, N, gel(x,1)); if (!equali1(gcoeff(t,1,1))) return 0; t = idealadd(G, N, gel(x,2)); return equali1(gcoeff(t,1,1)); } GEN chareval(GEN G, GEN chi, GEN x, GEN z) { pari_sp av = avma; GEN nchi, L; switch(nftyp(G)) { case typ_BNR: if (!bnr_coprime(G, x)) return not_coprime(z); L = isprincipalray(G, x); nchi = get_chi(bnr_get_cyc(G), chi); break; case typ_BNF: L = isprincipal(G, x); nchi = get_chi(bnf_get_cyc(G), chi); break; case typ_BIDZ: if (checkznstar_i(G)) return gerepileupto(av, znchareval(G, chi, x, z)); /* don't implement chars on general bid: need an nf... */ default: pari_err_TYPE("chareval", G); return NULL;/* LCOV_EXCL_LINE */ } return gerepileupto(av, chareval_i(nchi, L, z)); } /* nchi = [ord,D] a quasi-normalized character (ord may be a multiple of * the character order); return v such that v[n] = -1 if (n,N) > 1 else * chi(n) = e(v[n]/ord), 1 <= n <= N */ GEN ncharvecexpo(GEN G, GEN nchi) { long N = itou(znstar_get_N(G)), ord = itou(gel(nchi,1)), i, j, l; GEN cyc, gen, d, t, t1, t2, t3, e, u, u1, u2, u3; GEN D = gel(nchi,2), v = const_vecsmall(N,-1); pari_sp av = avma; if (typ(D) == t_COL) { cyc = znstar_get_conreycyc(G); gen = znstar_get_conreygen(G); } else { cyc = znstar_get_cyc(G); gen = znstar_get_gen(G); } l = lg(cyc); e = u = cgetg(N+1,t_VECSMALL); d = t = cgetg(N+1,t_VECSMALL); *++d = 1; *++e = 0; v[*d] = *e; for (i = 1; i < l; i++) { ulong g = itou(gel(gen,i)), c = itou(gel(cyc,i)), x = itou(gel(D,i)); for (t1=t,u1=u,j=c-1; j; j--,t1=t2,u1=u2) for (t2=d,u2=e, t3=t1,u3=u1; t3 0 */ GEN coprimes_zv(ulong N) { GEN v = const_vecsmall(N,1); pari_sp av = avma; GEN P = gel(factoru(N),1); long i, l = lg(P); for (i = 1; i < l; i++) { ulong p = P[i], j; for (j = p; j <= N; j += p) v[j] = 0; } avma = av; return v; } /* cf zv_cyc_minimal: return k such that g*k is minimal (wrt lex) */ long zv_cyc_minimize(GEN cyc, GEN g, GEN coprime) { pari_sp av = avma; long d, k, e, i, maxi, k0, bestk, l = lg(g), o = lg(coprime)-1; GEN best, gk, gd; ulong t; if (o == 1) return 1; for (i = 1; i < l; i++) if (g[i]) break; if (g[i] == 1) return 1; k0 = Fl_invgen(g[i], cyc[i], &t); d = cyc[i] / (long)t; if (k0 > 1) g = vecmoduu(Flv_Fl_mul(g, k0, cyc[i]), cyc); for (i++; i < l; i++) if (g[i]) break; if (i == l) return k0; cyc = vecslice(cyc,i,l-1); g = vecslice(g, i,l-1); e = cyc[1]; gd = Flv_Fl_mul(g, d, e); bestk = 1; best = g; maxi = e/ugcd(d,e); for (gk = g, k = d+1, i = 1; i < maxi; k += d, i++) { long ko = k % o; gk = Flv_add(gk, gd, e); if (!ko || !coprime[ko]) continue; gk = vecmoduu(gk, cyc); if (vecsmall_lexcmp(gk, best) < 0) { best = gk; bestk = k; } } avma = av; return bestk == 1? k0: Fl_mul(k0, bestk, o); } /* g of order o in abelian group G attached to cyc. Is g a minimal generator * [wrt lex order] of the cyclic subgroup it generates; * coprime = coprimes_zv(o) */ long zv_cyc_minimal(GEN cyc, GEN g, GEN coprime) { pari_sp av = avma; long i, maxi, d, k, e, l = lg(g), o = lg(coprime)-1; /* elt order */ GEN gd, gk; if (o == 1) return 1; for (k = 1; k < l; k++) if (g[k]) break; if (g[k] == 1) return 1; if (cyc[k] % g[k]) return 0; d = cyc[k] / g[k]; /* > 1 */ for (k++; k < l; k++) /* skip following 0s */ if (g[k]) break; if (k == l) return 1; cyc = vecslice(cyc,k,l-1); g = vecslice(g, k,l-1); e = cyc[1]; /* find k in (Z/e)^* such that g*k mod cyc is lexicographically minimal, * k = 1 mod d to fix the first non-zero entry */ gd = Flv_Fl_mul(g, d, e); maxi = e/ugcd(d,e); for (gk = g, k = d+1, i = 1; i < maxi; i++, k += d) { long ko = k % o; gk = Flv_add(gk, gd, e); if (!coprime[ko]) continue; gk = vecmoduu(gk, cyc); if (vecsmall_lexcmp(gk, g) < 0) { avma = av; return 0; } } avma = av; return 1; } static GEN coprime_tables(long N) { GEN D = divisorsu(N), v = const_vec(N, NULL); long i, l = lg(D); for (i = 1; i < l; i++) gel(v, D[i]) = coprimes_zv(D[i]); return v; } /* enumerate all group elements, modulo (Z/cyc[1])^* */ static GEN cyc2elts_normal(GEN cyc, long maxord, GEN ORD) { long i, n, o, N, j = 1; GEN z, vcoprime; if (typ(cyc) != t_VECSMALL) cyc = gtovecsmall(cyc); n = lg(cyc)-1; if (n == 0) return cgetg(1, t_VEC); N = zv_prod(cyc); z = cgetg(N+1, t_VEC); if (1 <= maxord && (!ORD|| zv_search(ORD,1))) gel(z,j++) = zero_zv(n); vcoprime = coprime_tables(cyc[1]); for (i = n; i > 0; i--) { GEN cyc0 = vecslice(cyc,i+1,n), pre = zero_zv(i); GEN D = divisorsu(cyc[i]), C = cyc2elts(cyc0); long s, t, lD = lg(D), nC = lg(C)-1; /* remove last element */ for (s = 1; s < lD-1; s++) { long o0 = D[lD-s]; /* cyc[i] / D[s] */ if (o0 > maxord) continue; pre[i] = D[s]; if (!ORD || zv_search(ORD,o0)) { GEN c = vecsmall_concat(pre, zero_zv(n-i)); gel(z,j++) = c; } for (t = 1; t < nC; t++) { GEN chi0 = gel(C,t); o = lcmuu(o0, zv_charorder(cyc0,chi0)); if (o <= maxord && (!ORD || zv_search(ORD,o))) { GEN c = vecsmall_concat(pre, chi0); if (zv_cyc_minimal(cyc, c, gel(vcoprime,o))) gel(z,j++) = c; } } } } setlg(z,j); return z; } GEN chargalois(GEN G, GEN ORD) { pari_sp av = avma; long maxord, i, l; GEN v, cyc = (typ(G) == t_VEC && RgV_is_ZVpos(G))? G: member_cyc(G); if (lg(cyc) == 1) retmkvec(cgetg(1,t_VEC)); maxord = itou(gel(cyc,1)); if (ORD && gequal0(ORD)) ORD = NULL; if (ORD) switch(typ(ORD)) { long l; case t_VEC: ORD = ZV_to_zv(ORD); case t_VECSMALL: ORD = leafcopy(ORD); vecsmall_sort(ORD); l = lg(ORD); if (l == 1) return cgetg(1, t_VECSMALL); maxord = minss(maxord, ORD[l-1]); break; case t_INT: maxord = minss(maxord, itos(ORD)); ORD = NULL; break; default: pari_err_TYPE("chargalois", ORD); } v = cyc2elts_normal(cyc, maxord, ORD); l = lg(v); for(i = 1; i < l; i++) gel(v,i) = zv_to_ZV(gel(v,i)); return gerepileupto(av, v); } /*********************************************************************/ /** **/ /** (Z/NZ)^* AND DIRICHLET CHARACTERS **/ /** **/ /*********************************************************************/ GEN znstar0(GEN N, long flag) { GEN F = NULL, P, E, cyc, gen, mod, G; long i, i0, l, nbprimes; pari_sp av = avma; if (flag && flag != 1) pari_err_FLAG("znstar"); if ((F = check_arith_all(N,"znstar"))) { F = clean_Z_factor(F); N = typ(N) == t_VEC? gel(N,1): factorback(F); } if (!signe(N)) { if (flag) pari_err_IMPL("znstar(0,1)"); avma = av; retmkvec3(gen_2, mkvec(gen_2), mkvec(gen_m1)); } N = absi_shallow(N); if (abscmpiu(N,2) <= 0) { G = mkvec3(gen_1, cgetg(1,t_VEC), cgetg(1,t_VEC)); if (flag) { GEN v = const_vec(6,cgetg(1,t_VEC)); gel(v,3) = cgetg(1,t_MAT); F = equali1(N)? mkvec2(cgetg(1,t_COL),cgetg(1,t_VECSMALL)) : mkvec2(mkcol(gen_2), mkvecsmall(1)); G = mkvec5(mkvec2(N,mkvec(gen_0)), G, F, v, cgetg(1,t_MAT)); } return gerepilecopy(av,G); } if (!F) F = Z_factor(N); P = gel(F,1); nbprimes = lg(P)-1; E = ZV_to_nv( gel(F,2) ); switch(mod8(N)) { case 0: P = shallowconcat(gen_2,P); E = vecsmall_prepend(E, E[1]); /* add a copy of p=2 row */ i = 2; /* 2 generators at 2 */ break; case 4: i = 1; /* 1 generator at 2 */ break; case 2: case 6: P = vecsplice(P,1); E = vecsplice(E,1); /* remove 2 */ i = 0; /* no generator at 2 */ break; default: i = 0; /* no generator at 2 */ break; } l = lg(P); cyc = cgetg(l,t_VEC); gen = cgetg(l,t_VEC); mod = cgetg(l,t_VEC); /* treat p=2 first */ if (i == 2) { long v2 = E[1]; GEN q = int2n(v2); gel(cyc,1) = gen_2; gel(gen,1) = subiu(q,1); /* -1 */ gel(mod,1) = q; gel(cyc,2) = int2n(v2-2); gel(gen,2) = utoipos(5); /* Conrey normalization */ gel(mod,2) = q; i0 = 3; } else if (i == 1) { gel(cyc,1) = gen_2; gel(gen,1) = utoipos(3); gel(mod,1) = utoipos(4); i0 = 2; } else i0 = 1; /* odd primes, fill remaining entries */ for (i = i0; i < l; i++) { long e = E[i]; GEN p = gel(P,i), q = powiu(p, e-1), Q = mulii(p, q); gel(cyc,i) = subii(Q, q); /* phi(p^e) */ gel(gen,i) = pgener_Zp(p);/* Conrey normalization, for e = 1 also */ gel(mod,i) = Q; } /* gen[i] has order cyc[i] and generates (Z/mod[i]Z)^* */ if (nbprimes > 1) /* lift generators to (Z/NZ)^*, = 1 mod N/mod[i] */ for (i=1; i 1 and remain so in the loop, gen[i] = 1 mod (N/mod[i]) */ if (!flag) { /* update generators in place; about twice faster */ G = gen; for (i=l-1; i>=2; i--) { GEN ci = gel(cyc,i), gi = gel(G,i); long j; for (j=i-1; j>=1; j--) /* we want cyc[i] | cyc[j] */ { GEN cj = gel(cyc,j), gj, qj, v, d; d = bezout(ci,cj,NULL,&v); /* > 1 */ if (absequalii(ci, d)) continue; /* ci | cj */ if (absequalii(cj, d)) { /* cj | ci */ swap(gel(G,j),gel(G,i)); gi = gel(G,i); swap(gel(cyc,j),gel(cyc,i)); ci = gel(cyc,i); continue; } qj = diviiexact(cj,d); gel(cyc,j) = mulii(ci,qj); gel(cyc,i) = d; /* [1,v*cj/d; 0,1]*[1,0;-1,1]*diag(cj,ci)*[ci/d,-v; cj/d,u] * = diag(lcm,gcd), with u ci + v cj = d */ gj = gel(G,j); /* (gj, gi) *= [1,0; -1,1]^-1 */ gj = Fp_mul(gj, gi, N); /* order ci*qj = lcm(ci,cj) */ /* (gj,gi) *= [1,v*qj; 0,1]^-1 */ togglesign_safe(&v); if (signe(v) < 0) v = modii(v,ci); /* >= 0 to avoid inversions */ gel(G,i) = gi = Fp_mul(gi, Fp_pow(gj, mulii(qj, v), N), N); gel(G,j) = gj; ci = d; if (absequaliu(ci, 2)) break; } } G = mkvec3(ZV_prod(cyc), cyc, FpV_to_mod(G,N)); } else { /* keep matrices between generators, return an 'init' structure */ GEN D, U, Ui, fao = cgetg(l, t_VEC), lo = cgetg(l, t_VEC); F = mkvec2(P, E); D = ZV_snf_group(cyc,&U,&Ui); for (i = 1; i < l; i++) { GEN t = gen_0, p = gel(P,i), p_1 = subiu(p,1); long e = E[i]; gel(fao,i) = get_arith_ZZM(p_1); if (e >= 2 && !absequaliu(p,2)) { GEN q = gel(mod,i), g = Fp_pow(gel(gen,i),p_1,q); if (e == 2) t = Fp_inv(diviiexact(subiu(g,1), p), p); else t = ginv(Qp_log(cvtop(g,p,e))); } gel(lo,i) = t; } G = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(G,i) = FpV_factorback(gen, gel(Ui,i), N); G = mkvec3(ZV_prod(D), D, G); G = mkvec5(mkvec2(N,mkvec(gen_0)), G, F, mkvecn(6,mod,fao,Ui,gen,cyc,lo), U); } return gerepilecopy(av, G); } GEN znstar(GEN N) { return znstar0(N, 0); } /* g has order 2^(e-2), g,h = 1 (mod 4); return x s.t. g^x = h (mod 2^e) */ static GEN Zideallog_2k(GEN h, GEN g, long e, GEN pe) { GEN a = Fp_log(h, g, int2n(e-2), pe); if (typ(a) != t_INT) return NULL; return a; } /* ord = get_arith_ZZM(p-1), simplified form of znlog_rec: g is known * to be a primitive root mod p^e; lo = 1/log_p(g^(p-1)) */ static GEN Zideallog_pk(GEN h, GEN g, GEN p, long e, GEN pe, GEN ord, GEN lo) { GEN gp = (e == 1)? g: modii(g, p); GEN hp = (e == 1)? h: modii(h, p); GEN a = Fp_log(hp, gp, ord, p); if (typ(a) != t_INT) return NULL; if (e > 1) { /* find a s.t. g^a = h (mod p^e), p odd prime, e > 0, (h,p) = 1 */ /* use p-adic log: O(log p + e) mul*/ GEN b, p_1 = gel(ord,1); h = Fp_mul(h, Fp_pow(g, negi(a), pe), pe); /* g,h = 1 mod p; compute b s.t. h = g^b */ if (e == 2) /* simpler */ b = Fp_mul(diviiexact(subiu(h,1), p), lo, p); else b = padic_to_Q(gmul(Qp_log(cvtop(h, p, e)), lo)); a = addii(a, mulii(p_1, b)); } return a; } int znconrey_check(GEN cyc, GEN chi) { return typ(chi) == t_COL && lg(chi) == lg(cyc) && RgV_is_ZV(chi); } int zncharcheck(GEN G, GEN chi) { switch(typ(chi)) { case t_INT: return 1; case t_COL: return znconrey_check(znstar_get_conreycyc(G), chi); case t_VEC: return char_check(znstar_get_cyc(G), chi); } return 0; } GEN znconreyfromchar_normalized(GEN bid, GEN chi) { GEN nchi, U = znstar_get_U(bid); long l = lg(chi); if (l == 1) retmkvec2(gen_1,cgetg(1,t_VEC)); if (!RgV_is_ZV(chi) || lgcols(U) != l) pari_err_TYPE("lfunchiZ", chi); nchi = char_normalize(chi, cyc_normalize(znstar_get_cyc(bid))); gel(nchi,2) = ZV_ZM_mul(gel(nchi,2),U); return nchi; } GEN znconreyfromchar(GEN bid, GEN chi) { GEN nchi = znconreyfromchar_normalized(bid, chi); GEN v = char_denormalize(znstar_get_conreycyc(bid), gel(nchi,1), gel(nchi,2)); settyp(v, t_COL); return v; } /* discrete log on canonical "primitive root" generators * Allow log(x) instead of x [usual discrete log on bid's generators */ GEN znconreylog(GEN bid, GEN x) { pari_sp av = avma; GEN N, L, F, P,E, y, pe, fao, gen, lo, cycg; long i, l; if (!checkznstar_i(bid)) pari_err_TYPE("znconreylog", bid); N = znstar_get_N(bid); if (typ(N) != t_INT) pari_err_TYPE("znconreylog", N); if (abscmpiu(N, 2) <= 0) return cgetg(1, t_COL); cycg = znstar_get_conreycyc(bid); switch(typ(x)) { GEN Ui; case t_INT: if (!signe(x)) pari_err_COPRIME("znconreylog", x, N); break; case t_COL: /* log_bid(x) */ Ui = znstar_get_Ui(bid); if (!RgV_is_ZV(x) || lg(x) != lg(Ui)) pari_err_TYPE("znconreylog", x); return gerepileupto(av, vecmodii(ZM_ZC_mul(Ui,x), cycg)); case t_VEC: return gerepilecopy(av, znconreyfromchar(bid, x)); default: pari_err_TYPE("znconreylog", x); } F = znstar_get_faN(bid); /* factor(N) */ P = gel(F, 1); /* prime divisors of N */ E = gel(F, 2); /* exponents */ L = gel(bid,4); pe = znstar_get_pe(bid); fao = gel(L,2); gen = znstar_get_conreygen(bid); /* local generators of (Z/p^k)^* */ lo = gel(L,6); /* 1/log_p((g_i)^(p_i-1)) */ l = lg(gen); i = 1; y = cgetg(l, t_COL); if (!mod2(N) && !mod2(x)) pari_err_COPRIME("znconreylog", x, N); if (absequaliu(gel(P,1), 2) && E[1] >= 2) { if (E[1] == 2) gel(y,i++) = mod4(x) == 1? gen_0: gen_1; else { GEN a, x2, q2 = gel(pe,1); x2 = modii(x, q2); if (mod4(x) == 1) /* 1 or 5 mod 8*/ gel(y,i++) = gen_0; else /* 3 or 7 */ { gel(y,i++) = gen_1; x2 = subii(q2, x2); } /* x2 = 5^x mod q */ a = Zideallog_2k(x2, gel(gen,i), E[1], q2); if (!a) pari_err_COPRIME("znconreylog", x, N); gel(y, i++) = a; } } while (i < l) { GEN p = gel(P,i), q = gel(pe,i), xpe = modii(x, q); GEN a = Zideallog_pk(xpe, gel(gen,i), p, E[i], q, gel(fao,i), gel(lo,i)); if (!a) pari_err_COPRIME("znconreylog", x, N); gel(y, i++) = a; } return gerepilecopy(av, y); } GEN Zideallog(GEN bid, GEN x) { pari_sp av = avma; GEN y = znconreylog(bid, x), U = znstar_get_U(bid); return gerepileupto(av, ZM_ZC_mul(U, y)); } GEN znlog0(GEN h, GEN g, GEN o) { if (typ(g) == t_VEC) { GEN N; if (o) pari_err_TYPE("znlog [with znstar]", o); if (!checkznstar_i(g)) pari_err_TYPE("znlog", h); N = znstar_get_N(g); h = Rg_to_Fp(h,N); return Zideallog(g, h); } return znlog(h, g, o); } GEN znconreyexp(GEN bid, GEN x) { pari_sp av = avma; long i, l; GEN N, pe, gen, cycg, v, vmod; int e2; if (!checkznstar_i(bid)) pari_err_TYPE("znconreyexp", bid); cycg = znstar_get_conreycyc(bid); switch(typ(x)) { case t_VEC: x = znconreylog(bid, x); break; case t_COL: if (RgV_is_ZV(x) && lg(x) == lg(cycg)) break; default: pari_err_TYPE("znconreyexp",x); } pe = znstar_get_pe(bid); gen = znstar_get_conreygen(bid); /* local generators of (Z/p^k)^* */ cycg = znstar_get_conreycyc(bid); l = lg(x); v = cgetg(l, t_VEC); N = znstar_get_N(bid); e2 = !mod8(N); /* 2 generators at p = 2 */ for (i = 1; i < l; i++) { GEN q, g, m; if (i == 1 && e2) { gel(v,1) = NULL; continue; } q = gel(pe,i); g = gel(gen,i); m = modii(gel(x,i), gel(cycg,i)); m = Fp_pow(g, m, q); if (i == 2 && e2 && signe(gel(x,1))) m = Fp_neg(m, q); gel(v,i) = mkintmod(m, q); } if (e2) v = vecsplice(v, 1); v = chinese1_coprime_Z(v); vmod = gel(v,1); v = gel(v,2); if (mpodd(v) || mpodd(N)) return gerepilecopy(av, v); /* handle N = 2 mod 4 */ return gerepileuptoint(av, addii(v, vmod)); } /* Return Dirichlet character \chi_q(m,.), where bid = znstar(q); * m is either a t_INT, or a t_COL [Conrey logarithm] */ GEN znconreychar(GEN bid, GEN m) { pari_sp av = avma; GEN c, d, nchi; if (!checkznstar_i(bid)) pari_err_TYPE("znconreychar", bid); switch(typ(m)) { case t_COL: case t_INT: nchi = znconrey_normalized(bid,m); /* images of primroot gens */ break; default: pari_err_TYPE("znconreychar",m); return NULL;/*LCOV_EXCL_LINE*/ } d = gel(nchi,1); c = ZV_ZM_mul(gel(nchi,2), znstar_get_Ui(bid)); /* images of bid gens */ return gerepilecopy(av, char_denormalize(znstar_get_cyc(bid),d,c)); } /* chi a t_INT or Conrey log describing a character. Return conductor, as an * integer if primitive; as a t_VEC [N,factor(N)] if not. Set *pm=m to the * attached primitive character: chi(g_i) = m[i]/ord(g_i) * Caller should use znconreylog_normalize(BID, m), once BID(conductor) is * computed (wasteful to do it here since BID is shared by many characters) */ GEN znconreyconductor(GEN bid, GEN chi, GEN *pm) { pari_sp av = avma; GEN q, m, F, P, E; long i, j, l; int e2, primitive = 1; if (!checkznstar_i(bid)) pari_err_TYPE("znconreyconductor", bid); if (typ(chi) == t_COL) { if (!znconrey_check(znstar_get_conreycyc(bid), chi)) pari_err_TYPE("znconreyconductor",chi); } else chi = znconreylog(bid, chi); l = lg(chi); F = znstar_get_faN(bid); P = gel(F,1); E = gel(F,2); if (l == 1) { avma = av; if (pm) *pm = cgetg(1,t_COL); if (lg(P) == 1) return gen_1; retmkvec2(gen_1, trivial_fact()); } P = leafcopy(P); E = leafcopy(E); m = cgetg(l, t_COL); e2 = (E[1] >= 3 && absequaliu(gel(P,1),2)); i = j = 1; if (e2) { /* two generators at p=2 */ GEN a1 = gel(chi,1), a = gel(chi,2); i = 3; if (!signe(a)) { e2 = primitive = 0; if (signe(a1)) { /* lose one generator */ E[1] = 2; gel(m,1) = a1; j = 2; } /* else lose both */ } else { long v = Z_pvalrem(a, gen_2, &a); if (v) { E[1] -= v; E[2] = E[1]; primitive = 0; } gel(m,1) = a1; gel(m,2) = a; j = 3; } } l = lg(P); for (; i < l; i++) { GEN p = gel(P,i), a = gel(chi,i); /* image of g_i in Q/Z is a/cycg[i], cycg[i] = order(g_i) */ if (!signe(a)) primitive = 0; else { long v = Z_pvalrem(a, p, &a); E[j] = E[i]; if (v) { E[j] -= v; primitive = 0; } gel(P,j) = gel(P,i); gel(m,j) = a; j++; } } setlg(m,j); setlg(P,j); setlg(E,j); if (pm) *pm = m; /* attached primitive character */ if (primitive) { q = znstar_get_N(bid); if (mod4(q) == 2) primitive = 0; } if (!primitive) { if (e2) { /* remove duplicate p=2 row from factorization */ P = vecsplice(P,1); E = vecsplice(E,1); } E = zc_to_ZC(E); q = mkvec2(factorback2(P,E), mkmat2(P,E)); } gerepileall(av, pm? 2: 1, &q, pm); return q; } GEN zncharinduce(GEN G, GEN chi, GEN N) { pari_sp av = avma; GEN q, faq, P, E, Pq, Eq, CHI; long i, j, l; int e2; if (!checkznstar_i(G)) pari_err_TYPE("zncharinduce", G); if (!zncharcheck(G, chi)) pari_err_TYPE("zncharinduce", chi); q = znstar_get_N(G); if (typ(chi) != t_COL) chi = znconreylog(G, chi); if (checkznstar_i(N)) { GEN faN = znstar_get_faN(N); P = gel(faN,1); l = lg(P); E = gel(faN,2); N = znstar_get_N(N); if (l > 2 && equalii(gel(P,1),gel(P,2))) { /* remove duplicate 2 */ l--; P = vecsplice(P,1); E = vecsplice(E,1); } } else { GEN faN = check_arith_pos(N, "zncharinduce"); if (!faN) faN = Z_factor(N); else N = (typ(N) == t_VEC)? gel(N,1): factorback(faN); P = gel(faN,1); E = gel(faN,2); } if (!dvdii(N,q)) pari_err_DOMAIN("zncharinduce", "N % q", "!=", gen_0, N); if (mod4(N) == 2) { /* remove 2 */ if (lg(P) > 1 && absequaliu(gel(P,1), 2)) { P = vecsplice(P,1); E = vecsplice(E,1); } N = shifti(N,-1); } l = lg(P); /* q = N or q = 2N, N odd */ if (cmpii(N,q) <= 0) return gerepilecopy(av, chi); /* N > 1 => l > 1*/ if (typ(E) != t_VECSMALL) E = ZV_to_zv(E); e2 = (E[1] >= 3 && absequaliu(gel(P,1),2)); /* 2 generators at 2 mod N */ if (ZV_equal0(chi)) { avma = av; return equali1(N)? cgetg(1, t_COL): zerocol(l+e2 - 1); } faq = znstar_get_faN(G); Pq = gel(faq,1); Eq = gel(faq,2); CHI = cgetg(l+e2, t_COL); i = j = 1; if (e2) { i = 2; j = 3; if (absequaliu(gel(Pq,1), 2)) { if (Eq[1] >= 3) { /* 2 generators at 2 mod q */ gel(CHI,1) = gel(chi,1); gel(CHI,2) = shifti(gel(chi,2), E[1]-Eq[1]); } else if (Eq[1] == 2) { /* 1 generator at 2 mod q */ gel(CHI,1) = gel(chi,1); gel(CHI,2) = gen_0; } else gel(CHI,1) = gel(CHI,2) = gen_0; } else gel(CHI,1) = gel(CHI,2) = gen_0; } for (; i < l; i++,j++) { GEN p = gel(P,i); long k = ZV_search(Pq, p); gel(CHI,j) = k? mulii(gel(chi,k), powiu(p, E[i]-Eq[k])): gen_0; } return gerepilecopy(av, CHI); } /* m a Conrey log [on the canonical primitive roots], cycg the primitive * roots orders */ GEN znconreylog_normalize(GEN G, GEN m) { GEN cycg = znstar_get_conreycyc(G); long i, l; GEN d, M = cgetg_copy(m, &l); if (typ(cycg) != t_VEC || lg(cycg) != l) pari_err_TYPE("znconreylog_normalize",mkvec2(m,cycg)); for (i = 1; i < l; i++) gel(M,i) = gdiv(gel(m,i), gel(cycg,i)); /* m[i]: image of primroot generators g_i in Q/Z */ M = Q_remove_denom(M, &d); return mkvec2(d? d: gen_1, M); } /* return normalized character on Conrey generators attached to chi: Conrey * label (t_INT), char on (SNF) G.gen* (t_VEC), or Conrey log (t_COL) */ GEN znconrey_normalized(GEN G, GEN chi) { switch(typ(chi)) { case t_INT: /* Conrey label */ return znconreylog_normalize(G, znconreylog(G, chi)); case t_COL: /* Conrey log */ if (!RgV_is_ZV(chi)) break; return znconreylog_normalize(G, chi); case t_VEC: /* char on G.gen */ if (!RgV_is_ZV(chi)) break; return znconreyfromchar_normalized(G, chi); } pari_err_TYPE("znchareval",chi); return NULL;/* LCOV_EXCL_LINE */ } /* return 1 iff chi(-1) = -1, and 0 otherwise */ long zncharisodd(GEN G, GEN chi) { long i, l, s; GEN N; if (!checkznstar_i(G)) pari_err_TYPE("zncharisodd", G); if (!zncharcheck(G, chi)) pari_err_TYPE("zncharisodd", chi); if (typ(chi) != t_COL) chi = znconreylog(G, chi); N = znstar_get_N(G); l = lg(chi); s = 0; if (!mod8(N)) { s = mpodd(gel(chi,1)); i = 3; } else i = 1; for (; i < l; i++) s += mpodd(gel(chi,i)); return odd(s); } GEN znchartokronecker(GEN G, GEN chi, long flag) { pari_sp av = avma; long s; GEN F, o; if (flag && flag != 1) pari_err_FLAG("znchartokronecker"); s = zncharisodd(G, chi)? -1: 1; if (typ(chi) != t_COL) chi = znconreylog(G, chi); o = zncharorder(G, chi); if (abscmpiu(o,2) > 0) { avma = av; return gen_0; } F = znconreyconductor(G, chi, NULL); if (typ(F) == t_INT) { if (s < 0) F = negi(F); return gerepileuptoint(av, F); } F = gel(F,1); F = (s < 0)? negi(F): icopy(F); if (!flag) { GEN MF = znstar_get_faN(G), P = gel(MF,1); long i, l = lg(P); for (i = 1; i < l; i++) { GEN p = gel(P,i); if (!dvdii(F,p)) F = mulii(F,sqri(p)); } } return gerepileuptoint(av, F); } /* (D/.) as a character mod N; assume |D| divides N and D = 0,1 mod 4*/ GEN znchar_quad(GEN G, GEN D) { GEN cyc = znstar_get_conreycyc(G); GEN gen = znstar_get_conreygen(G); long i, l = lg(cyc); GEN chi = cgetg(l, t_COL); for (i = 1; i < l; i++) { long k = kronecker(D, gel(gen,i)); gel(chi,i) = (k==1)? gen_0: shifti(gel(cyc,i), -1); } return chi; } GEN znchar(GEN D) { pari_sp av = avma; GEN G, chi; switch(typ(D)) { case t_INT: if (!signe(D) || Mod4(D) > 1) pari_err_TYPE("znchar", D); G = znstar0(D,1); chi = mkvec2(G, znchar_quad(G,D)); break; case t_INTMOD: G = znstar0(gel(D,1), 1); chi = mkvec2(G, znconreylog(G, gel(D,2))); break; case t_VEC: if (checkMF_i(D)) { chi = vecslice(MF_get_CHI(D),1,2); break; } else if (checkmf_i(D)) { chi = vecslice(mf_get_CHI(D),1,2); break; } if (lg(D) != 3) pari_err_TYPE("znchar", D); G = gel(D,1); if (!checkznstar_i(G)) pari_err_TYPE("znchar", D); chi = gel(D,2); if (typ(chi) == t_VEC && lg(chi) == 3 && is_vec_t(typ(gel(chi,2)))) { /* normalized character */ GEN n = gel(chi,1), chic = gel(chi,2); GEN cyc = typ(chic)==t_VEC? znstar_get_cyc(G): znstar_get_conreycyc(G); if (!char_check(cyc, chic)) pari_err_TYPE("znchar",D); chi = char_denormalize(cyc, n, chic); } if (!zncharcheck(G, chi)) pari_err_TYPE("znchar", D); chi = mkvec2(G,chi); break; default: pari_err_TYPE("znchar", D); return NULL; /*LCOV_EXCL_LINE*/ } return gerepilecopy(av, chi); } /* G a znstar, not stack clean */ GEN znchareval(GEN G, GEN chi, GEN n, GEN z) { GEN nchi, N = znstar_get_N(G); /* avoid division by 0 */ if (typ(n) == t_FRAC && !equali1(gcdii(gel(n,2), N))) return not_coprime(z); n = Rg_to_Fp(n, N); if (!equali1(gcdii(n, N))) return not_coprime(z); /* nchi: normalized character on Conrey generators */ nchi = znconrey_normalized(G, chi); return chareval_i(nchi, znconreylog(G,n), z); } /* G is a znstar, chi a Dirichlet character */ GEN zncharconj(GEN G, GEN chi) { switch(typ(chi)) { case t_INT: chi = znconreylog(G, chi); /* fall through */ case t_COL: return charconj(znstar_get_conreycyc(G), chi); case t_VEC: return charconj(znstar_get_cyc(G), chi); } pari_err_TYPE("zncharconj",chi); return NULL; /*LCOV_EXCL_LINE*/ } /* G is a znstar, chi a Dirichlet character */ GEN zncharorder(GEN G, GEN chi) { switch(typ(chi)) { case t_INT: chi = znconreylog(G, chi); /*fall through*/ case t_COL: return charorder(znstar_get_conreycyc(G), chi); case t_VEC: return charorder(znstar_get_cyc(G), chi); default: pari_err_TYPE("zncharorder",chi); return NULL; /* LCOV_EXCL_LINE */ } } /* G is a znstar, chi a Dirichlet character */ GEN zncharker(GEN G, GEN chi) { if (typ(chi) != t_VEC) chi = znconreychar(G, chi); return charker(znstar_get_cyc(G), chi); } /* G is a znstar, 'a' is a Dirichlet character */ GEN zncharpow(GEN G, GEN a, GEN n) { switch(typ(a)) { case t_INT: return Fp_pow(a, n, znstar_get_N(G)); case t_VEC: return charpow(znstar_get_cyc(G), a, n); case t_COL: return charpow(znstar_get_conreycyc(G), a, n); default: pari_err_TYPE("znchapow",a); return NULL; /* LCOV_EXCL_LINE */ } } /* G is a znstar, 'a' and 'b' are Dirichlet character */ GEN zncharmul(GEN G, GEN a, GEN b) { long ta = typ(a), tb = typ(b); if (ta == tb) switch(ta) { case t_INT: return Fp_mul(a, b, znstar_get_N(G)); case t_VEC: return charmul(znstar_get_cyc(G), a, b); case t_COL: return charmul(znstar_get_conreycyc(G), a, b); default: pari_err_TYPE("zncharmul",a); return NULL; /* LCOV_EXCL_LINE */ } if (ta != t_COL) a = znconreylog(G, a); if (tb != t_COL) b = znconreylog(G, b); return charmul(znstar_get_conreycyc(G), a, b); } /* G is a znstar, 'a' and 'b' are Dirichlet character */ GEN znchardiv(GEN G, GEN a, GEN b) { long ta = typ(a), tb = typ(b); if (ta == tb) switch(ta) { case t_INT: return Fp_div(a, b, znstar_get_N(G)); case t_VEC: return chardiv(znstar_get_cyc(G), a, b); case t_COL: return chardiv(znstar_get_conreycyc(G), a, b); default: pari_err_TYPE("znchardiv",a); return NULL; /* LCOV_EXCL_LINE */ } if (ta != t_COL) a = znconreylog(G, a); if (tb != t_COL) b = znconreylog(G, b); return chardiv(znstar_get_conreycyc(G), a, b); } /* CHI mod N = \prod_p p^e; let CHI = \prod CHI_p, CHI_p mod p^e * return \prod_{p | (Q,N)} CHI_p. E.g if Q = p, return chi_p */ GEN znchardecompose(GEN G, GEN chi, GEN Q) { GEN c, P, E, F; long l, lP, i; if (!checkznstar_i(G)) pari_err_TYPE("znchardecompose", G); if (typ(Q) != t_INT) pari_err_TYPE("znchardecompose", Q); if (typ(chi) == t_COL) { if (!zncharcheck(G, chi)) pari_err_TYPE("znchardecompose", chi); } else chi = znconreylog(G, chi); l = lg(chi); F = znstar_get_faN(G); c = zerocol(l-1); P = gel(F,1); /* prime divisors of N */ lP = lg(P); E = gel(F,2); /* exponents */ for (i = 1; i < lP; i++) { GEN p = gel(P,i); if (i == 1 && equaliu(p,2) && E[1] >= 3) { if (!mpodd(Q)) { gel(c,1) = icopy(gel(chi,1)); gel(c,2) = icopy(gel(chi,2)); } i = 2; /* skip P[2] = P[1] = 2 */ } else if (dvdii(Q, p)) gel(c,i) = icopy(gel(chi,i)); } return c; } GEN zncharconductor(GEN G, GEN chi) { pari_sp av = avma; GEN F = znconreyconductor(G, chi, NULL); if (typ(F) == t_INT) return F; return gerepilecopy(av, gel(F,1)); } GEN znchartoprimitive(GEN G, GEN chi) { pari_sp av = avma; GEN chi0, F = znconreyconductor(G, chi, &chi0); if (typ(F) == t_INT) chi = mkvec2(G,chi); else chi = mkvec2(znstar0(F,1), chi0); return gerepilecopy(av, chi); } pari-2.11.2/src/basemath/F2xqE.c0000644000175000017500000005715113326135265014641 0ustar billbill/* Copyright (C) 2012 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Not so fast arithmetic with points over elliptic curves over F_2^n */ /***********************************************************************/ /** **/ /** F2xqE **/ /** **/ /***********************************************************************/ /* Theses functions deal with point over elliptic curves over F_2^n defined * by an equation of the form: ** y^2+x*y=x^3+a_2*x^2+a_6 if the curve is ordinary. ** y^2+a_3*y=x^3+a_4*x+a_6 if the curve is supersingular. * Most of the time a6 is omitted since it can be recovered from any point * on the curve. * For supersingular curves, the parameter a2 is replaced by [a3,a4,a3^-1]. */ GEN RgE_to_F2xqE(GEN x, GEN T) { if (ell_is_inf(x)) return x; retmkvec2(Rg_to_F2xq(gel(x,1),T),Rg_to_F2xq(gel(x,2),T)); } GEN F2xqE_changepoint(GEN x, GEN ch, GEN T) { pari_sp av = avma; GEN p1,z,u,r,s,t,v,v2,v3; if (ell_is_inf(x)) return x; u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); v = F2xq_inv(u, T); v2 = F2xq_sqr(v, T); v3 = F2xq_mul(v,v2, T); p1 = F2x_add(gel(x,1),r); z = cgetg(3,t_VEC); gel(z,1) = F2xq_mul(v2, p1, T); gel(z,2) = F2xq_mul(v3, F2x_add(gel(x,2), F2x_add(F2xq_mul(s, p1, T),t)), T); return gerepileupto(av, z); } GEN F2xqE_changepointinv(GEN x, GEN ch, GEN T) { GEN u, r, s, t, X, Y, u2, u3, u2X, z; if (ell_is_inf(x)) return x; X = gel(x,1); Y = gel(x,2); u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); u2 = F2xq_sqr(u, T); u3 = F2xq_mul(u,u2, T); u2X = F2xq_mul(u2,X, T); z = cgetg(3, t_VEC); gel(z,1) = F2x_add(u2X,r); gel(z,2) = F2x_add(F2xq_mul(u3,Y, T), F2x_add(F2xq_mul(s,u2X, T), t)); return z; } static GEN nonzerotrace_F2xq(GEN T) { pari_sp av = avma; long n = F2x_degree(T), vs = T[1]; GEN a; if (odd(n)) return pol1_F2x(vs); do { avma = av; a = random_F2x(n, vs); } while (F2xq_trace(a, T)==0); return a; } void F2xq_elltwist(GEN a, GEN a6, GEN T, GEN *pt_a, GEN *pt_a6) { pari_sp av = avma; GEN n = nonzerotrace_F2xq(T); if (typ(a)==t_VECSMALL) { *pt_a = gerepileuptoleaf(av, F2x_add(n, a)); *pt_a6 = vecsmall_copy(a6); } else { GEN a6t = F2x_add(a6, F2xq_mul(n, F2xq_sqr(gel(a,1), T), T)); *pt_a6 = gerepileuptoleaf(av, a6t); *pt_a = vecsmall_copy(a); } } static GEN F2xqE_dbl_slope(GEN P, GEN a, GEN T, GEN *slope) { GEN x, y, Q; if (ell_is_inf(P)) return ellinf(); x = gel(P,1); y = gel(P,2); if (typ(a)==t_VECSMALL) { GEN a2 = a; if (!lgpol(gel(P,1))) return ellinf(); *slope = F2x_add(x, F2xq_div(y, x, T)); Q = cgetg(3,t_VEC); gel(Q, 1) = F2x_add(F2xq_sqr(*slope, T), F2x_add(*slope, a2)); gel(Q, 2) = F2x_add(F2xq_mul(*slope, F2x_add(x, gel(Q, 1)), T), F2x_add(y, gel(Q, 1))); } else { GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3); *slope = F2xq_mul(F2x_add(a4, F2xq_sqr(x, T)), a3i, T); Q = cgetg(3,t_VEC); gel(Q, 1) = F2xq_sqr(*slope, T); gel(Q, 2) = F2x_add(F2xq_mul(*slope, F2x_add(x, gel(Q, 1)), T), F2x_add(y, a3)); } return Q; } GEN F2xqE_dbl(GEN P, GEN a, GEN T) { pari_sp av = avma; GEN slope; return gerepileupto(av, F2xqE_dbl_slope(P, a, T,&slope)); } static GEN F2xqE_add_slope(GEN P, GEN Q, GEN a, GEN T, GEN *slope) { GEN Px, Py, Qx, Qy, R; if (ell_is_inf(P)) return Q; if (ell_is_inf(Q)) return P; Px = gel(P,1); Py = gel(P,2); Qx = gel(Q,1); Qy = gel(Q,2); if (F2x_equal(Px, Qx)) { if (F2x_equal(Py, Qy)) return F2xqE_dbl_slope(P, a, T, slope); else return ellinf(); } *slope = F2xq_div(F2x_add(Py, Qy), F2x_add(Px, Qx), T); R = cgetg(3,t_VEC); if (typ(a)==t_VECSMALL) { GEN a2 = a; gel(R, 1) = F2x_add(F2x_add(F2x_add(F2x_add(F2xq_sqr(*slope, T), *slope), Px), Qx), a2); gel(R, 2) = F2x_add(F2xq_mul(*slope, F2x_add(Px, gel(R, 1)), T), F2x_add(Py, gel(R, 1))); } else { GEN a3 = gel(a,1); gel(R, 1) = F2x_add(F2x_add(F2xq_sqr(*slope, T), Px), Qx); gel(R, 2) = F2x_add(F2xq_mul(*slope, F2x_add(Px, gel(R, 1)), T), F2x_add(Py, a3)); } return R; } GEN F2xqE_add(GEN P, GEN Q, GEN a, GEN T) { pari_sp av = avma; GEN slope; return gerepileupto(av, F2xqE_add_slope(P, Q, a, T, &slope)); } static GEN F2xqE_neg_i(GEN P, GEN a) { GEN LHS; if (ell_is_inf(P)) return P; LHS = typ(a)==t_VECSMALL ? gel(P,1): gel(a,1); return mkvec2(gel(P,1), F2x_add(LHS, gel(P,2))); } GEN F2xqE_neg(GEN P, GEN a, GEN T) { GEN LHS; (void) T; if (ell_is_inf(P)) return ellinf(); LHS = typ(a)==t_VECSMALL ? gel(P,1): gel(a,1); return mkvec2(gcopy(gel(P,1)), F2x_add(LHS, gel(P,2))); } GEN F2xqE_sub(GEN P, GEN Q, GEN a2, GEN T) { pari_sp av = avma; GEN slope; return gerepileupto(av, F2xqE_add_slope(P, F2xqE_neg_i(Q, a2), a2, T, &slope)); } struct _F2xqE { GEN a2, a6; GEN T; }; static GEN _F2xqE_dbl(void *E, GEN P) { struct _F2xqE *ell = (struct _F2xqE *) E; return F2xqE_dbl(P, ell->a2, ell->T); } static GEN _F2xqE_add(void *E, GEN P, GEN Q) { struct _F2xqE *ell=(struct _F2xqE *) E; return F2xqE_add(P, Q, ell->a2, ell->T); } static GEN _F2xqE_mul(void *E, GEN P, GEN n) { pari_sp av = avma; struct _F2xqE *e=(struct _F2xqE *) E; long s = signe(n); if (!s || ell_is_inf(P)) return ellinf(); if (s<0) P = F2xqE_neg(P, e->a2, e->T); if (is_pm1(n)) return s>0? gcopy(P): P; return gerepileupto(av, gen_pow(P, n, e, &_F2xqE_dbl, &_F2xqE_add)); } GEN F2xqE_mul(GEN P, GEN n, GEN a2, GEN T) { struct _F2xqE E; E.a2 = a2; E.T = T; return _F2xqE_mul(&E, P, n); } /* Finds a random non-singular point on E */ GEN random_F2xqE(GEN a, GEN a6, GEN T) { pari_sp ltop = avma; GEN x, y, rhs, u; do { avma= ltop; x = random_F2x(F2x_degree(T),T[1]); if (typ(a) == t_VECSMALL) { GEN a2 = a, x2; if (!lgpol(x)) { avma=ltop; retmkvec2(pol0_Flx(T[1]), F2xq_sqrt(a6,T)); } u = x; x2 = F2xq_sqr(x, T); rhs = F2x_add(F2xq_mul(x2,F2x_add(x,a2),T),a6); rhs = F2xq_div(rhs,x2,T); } else { GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3), u2i; u = a3; u2i = F2xq_sqr(a3i,T); rhs = F2x_add(F2xq_mul(x,F2x_add(F2xq_sqr(x,T),a4),T),a6); rhs = F2xq_mul(rhs,u2i,T); } } while (F2xq_trace(rhs,T)); y = F2xq_mul(F2xq_Artin_Schreier(rhs, T), u, T); return gerepilecopy(ltop, mkvec2(x, y)); } static GEN _F2xqE_rand(void *E) { struct _F2xqE *ell=(struct _F2xqE *) E; return random_F2xqE(ell->a2, ell->a6, ell->T); } static const struct bb_group F2xqE_group={_F2xqE_add,_F2xqE_mul,_F2xqE_rand,hash_GEN,zvV_equal,ell_is_inf, NULL}; const struct bb_group * get_F2xqE_group(void ** pt_E, GEN a2, GEN a6, GEN T) { struct _F2xqE *e = (struct _F2xqE *) stack_malloc(sizeof(struct _F2xqE)); e->a2 = a2; e->a6 = a6; e->T = T; *pt_E = (void *) e; return &F2xqE_group; } GEN F2xqE_order(GEN z, GEN o, GEN a2, GEN T) { pari_sp av = avma; struct _F2xqE e; e.a2=a2; e.T=T; return gerepileuptoint(av, gen_order(z, o, (void*)&e, &F2xqE_group)); } GEN F2xqE_log(GEN a, GEN b, GEN o, GEN a2, GEN T) { pari_sp av = avma; struct _F2xqE e; e.a2=a2; e.T=T; return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &F2xqE_group)); } /***********************************************************************/ /** **/ /** Pairings **/ /** **/ /***********************************************************************/ /* Derived from APIP from and by Jerome Milan, 2012 */ static long is_2_torsion(GEN Q, GEN a) { return (typ(a)==t_VEC || lgpol(gel(Q, 1))) ? 0: 1; } static GEN F2xqE_vert(GEN P, GEN Q, GEN a, GEN T) { long vT = T[1]; if (ell_is_inf(P)) return pol1_F2x(T[1]); if (!F2x_equal(gel(Q, 1), gel(P, 1))) return F2x_add(gel(Q, 1), gel(P, 1)); if (is_2_torsion(Q, a)) return F2xq_inv(gel(Q,2), T); return pol1_F2x(vT); } static GEN F2xqE_Miller_line(GEN R, GEN Q, GEN slope, GEN a, GEN T) { long vT = T[1]; GEN x = gel(Q, 1), y = gel(Q, 2); GEN tmp1 = F2x_add(x, gel(R, 1)); GEN tmp2 = F2x_add(F2xq_mul(tmp1, slope, T), gel(R, 2)); GEN s1, s2, ix; if (!F2x_equal(y, tmp2)) return F2x_add(y, tmp2); if (is_2_torsion(Q, a)) return pol1_F2x(vT); if (typ(a)==t_VEC) { GEN a4 = gel(a,2), a3i = gel(a,3); s1 = F2xq_mul(F2x_add(a4, F2xq_sqr(x, T)), a3i, T); if (!F2x_equal(s1, slope)) return F2x_add(s1, slope); s2 = F2xq_mul(F2x_add(x, F2xq_sqr(s1, T)), a3i, T); if (lgpol(s2)) return s2; return zv_copy(a3i); } else { GEN a2 = a ; ix = F2xq_inv(x, T); s1 = F2x_add(x, F2xq_mul(y, ix, T)); if (!F2x_equal(s1, slope)) return F2x_add(s1, slope); s2 =F2x_add(a2, F2x_add(F2xq_sqr(s1,T), s1)); if (!F2x_equal(s2, x)) return F2x_add(pol1_F2x(vT), F2xq_mul(s2, ix, T)); return ix; } } /* Computes the equation of the line tangent to R and returns its evaluation at the point Q. Also doubles the point R. */ static GEN F2xqE_tangent_update(GEN R, GEN Q, GEN a2, GEN T, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = ellinf(); return pol1_F2x(T[1]); } else if (is_2_torsion(R, a2)) { *pt_R = ellinf(); return F2xqE_vert(R, Q, a2, T); } else { GEN slope; *pt_R = F2xqE_dbl_slope(R, a2, T, &slope); return F2xqE_Miller_line(R, Q, slope, a2, T); } } /* Computes the equation of the line through R and P, and returns its evaluation at the point Q. Also adds P to the point R. */ static GEN F2xqE_chord_update(GEN R, GEN P, GEN Q, GEN a2, GEN T, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = gcopy(P); return F2xqE_vert(P, Q, a2, T); } else if (ell_is_inf(P)) { *pt_R = gcopy(R); return F2xqE_vert(R, Q, a2, T); } else if (F2x_equal(gel(P, 1), gel(R, 1))) { if (F2x_equal(gel(P, 2), gel(R, 2))) return F2xqE_tangent_update(R, Q, a2, T, pt_R); else { *pt_R = ellinf(); return F2xqE_vert(R, Q, a2, T); } } else { GEN slope; *pt_R = F2xqE_add_slope(P, R, a2, T, &slope); return F2xqE_Miller_line(R, Q, slope, a2, T); } } /* Returns the Miller function f_{m, Q} evaluated at the point P using the standard Miller algorithm. */ struct _F2xqE_miller { GEN T, a2, P; }; static GEN F2xqE_Miller_dbl(void* E, GEN d) { struct _F2xqE_miller *m = (struct _F2xqE_miller *)E; GEN T = m->T, a2 = m->a2, P = m->P; GEN v, line; GEN num = F2xq_sqr(gel(d,1), T); GEN denom = F2xq_sqr(gel(d,2), T); GEN point = gel(d,3); line = F2xqE_tangent_update(point, P, a2, T, &point); num = F2xq_mul(num, line, T); v = F2xqE_vert(point, P, a2, T); denom = F2xq_mul(denom, v, T); return mkvec3(num, denom, point); } static GEN F2xqE_Miller_add(void* E, GEN va, GEN vb) { struct _F2xqE_miller *m = (struct _F2xqE_miller *)E; GEN T = m->T, a2 = m->a2, P = m->P; GEN v, line, point; GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3); GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3); GEN num = F2xq_mul(na, nb, T); GEN denom = F2xq_mul(da, db, T); line = F2xqE_chord_update(pa, pb, P, a2, T, &point); num = F2xq_mul(num, line, T); v = F2xqE_vert(point, P, a2, T); denom = F2xq_mul(denom, v, T); return mkvec3(num, denom, point); } static GEN F2xqE_Miller(GEN Q, GEN P, GEN m, GEN a2, GEN T) { pari_sp ltop = avma; struct _F2xqE_miller d; GEN v, num, denom, g1; d.a2 = a2; d.T = T; d.P = P; g1 = pol1_F2x(T[1]); v = gen_pow(mkvec3(g1,g1,Q), m, (void*)&d, F2xqE_Miller_dbl, F2xqE_Miller_add); num = gel(v,1); denom = gel(v,2); return gerepileupto(ltop, F2xq_div(num, denom, T)); } GEN F2xqE_weilpairing(GEN P, GEN Q, GEN m, GEN a2, GEN T) { pari_sp ltop = avma; GEN num, denom, result; if (ell_is_inf(P) || ell_is_inf(Q) || F2x_equal(P,Q)) return pol1_F2x(T[1]); num = F2xqE_Miller(P, Q, m, a2, T); denom = F2xqE_Miller(Q, P, m, a2, T); result = F2xq_div(num, denom, T); return gerepileupto(ltop, result); } GEN F2xqE_tatepairing(GEN P, GEN Q, GEN m, GEN a2, GEN T) { if (ell_is_inf(P) || ell_is_inf(Q)) return pol1_F2x(T[1]); return F2xqE_Miller(P, Q, m, a2, T); } /***********************************************************************/ /** **/ /** Point counting **/ /** **/ /***********************************************************************/ static GEN Z2x_rshift(GEN y, long x) { GEN z; long i, l; if (!x) return pol0_Flx(y[1]); z = cgetg_copy(y, &l); z[1] = y[1]; for(i=2; i>x; return Flx_renormalize(z, l); } /* Solve the linear equation approximation in the Newton algorithm */ static GEN gen_Z2x_Dixon(GEN F, GEN V, long N, void *E, GEN lin(void *E, GEN F, GEN d, long N), GEN invl(void *E, GEN d)) { pari_sp av = avma; long N2, M; GEN VN2, V2, VM, bil; ulong q = 1UL<>1; M = N - N2; F = FlxT_red(F, q); VN2 = gen_Z2x_Dixon(F, V, N2, E, lin, invl); bil = lin(E, F, VN2, N); V2 = Z2x_rshift(Flx_sub(V, bil, q), N2); VM = gen_Z2x_Dixon(F, V2, M, E, lin, invl); return gerepileupto(av, Flx_add(VN2, Flx_Fl_mul(VM, 1UL<>1; m = N - n; F = ZXT_remi2n(F, N); Xn = gen_Z2X_Dixon(F, V, n, E, lin, lins, invls); FXn = lin(E, F, Xn, N); Vm = ZX_shifti(ZX_sub(V, FXn), -n); Xm = gen_Z2X_Dixon(F, Vm, m, E, lin, lins, invls); return gerepileupto(av, ZX_remi2n(ZX_add(Xn, ZX_shifti(Xm, n)), N)); } /* H -> H mod 2*/ static GEN _can_invls(void *E, GEN V) {(void) E; return V; } /* H -> H-(f0*H0-f1*H1) */ static GEN _can_lin(void *E, GEN F, GEN V, long N) { pari_sp av=avma; GEN d0, d1, z; (void) E; RgX_even_odd(V, &d0, &d1); z = ZX_sub(V, ZX_sub(ZX_mul(gel(F,1), d0), ZX_mul(gel(F,2), d1))); return gerepileupto(av, ZX_remi2n(z, N)); } static GEN _can_lins(void *E, GEN F, GEN V, long N) { GEN D=Flx_splitting(V, 2), z; ulong q = 1UL< P-(P0^2-X*P1^2) */ static GEN _can_iter(void *E, GEN f2, GEN q) { GEN f0, f1, z; (void) E; RgX_even_odd(f2, &f0, &f1); z = ZX_add(ZX_sub(f2, FpX_sqr(f0, q)), RgX_shift_shallow(FpX_sqr(f1, q), 1)); return mkvec3(z,f0,f1); } /* H -> H-(2*P0*H0-2*X*P1*H1) */ static GEN _can_invd(void *E, GEN V, GEN v, GEN q, long M) { GEN F; (void)E; (void)q; F = mkvec2(ZX_shifti(gel(v,2),1), ZX_shifti(RgX_shift_shallow(gel(v,3),1),1)); return gen_Z2X_Dixon(F, V, M, NULL, _can_lin, _can_lins, _can_invls); } /* Lift P to Q such that Q(x^2)=Q(x)*Q(-x) mod 2^n if Q = Q0(X^2)+X*Q1(X^2), solve Q(x^2) = Q0^2-X*Q1^2 */ static GEN F2x_canonlift(GEN P, long n) { return gen_ZpX_Newton(F2x_to_ZX(P),gen_2, n, NULL, _can_iter, _can_invd); } static GEN Z2XQ_frob(GEN x, GEN T, GEN q) { return FpX_rem(RgX_inflate(x, 2), T, q); } static GEN Z2xq_frob(GEN x, GEN T, ulong q) { return Flx_rem(Flx_inflate(x, 2), T, q); } struct _frob_lift { GEN T, sqx; }; /* H -> S^-1(H) mod 2 */ static GEN _frob_invls(void *E, GEN V) { struct _frob_lift *F = (struct _frob_lift*) E; GEN sqx = F->sqx; return F2x_to_Flx(F2xq_sqrt_fast(Flx_to_F2x(V), gel(sqx,1), gel(sqx,2))); } /* H -> f1*S(H) + f2*H */ static GEN _frob_lin(void *E, GEN F, GEN x2, long N) { GEN T = gel(F,3); GEN q = int2n(N); GEN y2 = Z2XQ_frob(x2, T, q); GEN lin = ZX_add(ZX_mul(gel(F,1), y2), ZX_mul(gel(F,2), x2)); (void) E; return FpX_rem(ZX_remi2n(lin, N), T, q); } static GEN _frob_lins(void *E, GEN F, GEN x2, long N) { GEN T = gel(F,3); ulong q = 1UL< P(X,S(X)) */ static GEN _lift_iter(void *E, GEN x2, GEN q) { struct _frob_lift *F = (struct _frob_lift*) E; long N = expi(q); GEN TN = ZXT_remi2n(F->T, N); GEN y2 = Z2XQ_frob(x2, TN, q); GEN x2y2 = FpX_rem(ZX_remi2n(ZX_mul(x2, y2), N), TN, q); GEN s = ZX_add(ZX_add(x2, ZX_shifti(y2, 1)), ZX_shifti(x2y2, 3)); GEN V = ZX_add(ZX_add(ZX_sqr(s), y2), ZX_shifti(x2y2, 2)); return mkvec4(FpX_rem(ZX_remi2n(V, N), TN, q),x2,y2,s); } /* H -> Dx*H+Dy*S(H) */ static GEN _lift_invd(void *E, GEN V, GEN v, GEN qM, long M) { struct _frob_lift *F = (struct _frob_lift*) E; GEN TM = ZXT_remi2n(F->T, M); GEN x2 = gel(v,2), y2 = gel(v,3), s = gel(v,4), r; GEN Dx = ZX_add(ZX_mul(ZX_Z_add(ZX_shifti(y2, 4), gen_2), s), ZX_shifti(y2, 2)); GEN Dy = ZX_add(ZX_Z_add(ZX_mul(ZX_Z_add(ZX_shifti(x2, 4), utoi(4)), s), gen_1), ZX_shifti(x2, 2)); Dx = FpX_rem(ZX_remi2n(Dx, M), TM, qM); Dy = FpX_rem(ZX_remi2n(Dy, M), TM, qM); r = mkvec3(Dy, Dx, TM); return gen_Z2X_Dixon(r, V, M, E, _frob_lin, _frob_lins, _frob_invls); } /* Let P(X,Y)=(X+2*Y+8*X*Y)^2+Y+4*X*Y Solve P(x,S(x))=0 [mod 2^n,T] assuming x = x0 [mod 2,T] we set s = X+2*Y+8*X*Y, P = s^2+Y+4*X*Y Dx = dP/dx = (16*s+4)*x+(4*s+1) Dy = dP/dy = (16*y+2)*s+4*y */ static GEN solve_AGM_eqn(GEN x0, long n, GEN T, GEN sqx) { struct _frob_lift F; F.T=T; F.sqx=sqx; return gen_ZpX_Newton(x0, gen_2, n, &F, _lift_iter, _lift_invd); } static GEN Z2XQ_invnorm_pcyc(GEN a, GEN T, long e) { GEN q = int2n(e); GEN z = ZpXQ_norm_pcyc(a, T, q, gen_2); return Fp_inv(z, q); } /* Assume a = 1 [4] */ static GEN Z2XQ_invnorm(GEN a, GEN T, long e) { pari_timer ti; GEN pe = int2n(e), s; if (degpol(a)==0) return Fp_inv(Fp_powu(gel(a,2), get_FpX_degree(T), pe), pe); if (DEBUGLEVEL>=3) timer_start(&ti); s = ZpXQ_log(a, T, gen_2, e); if (DEBUGLEVEL>=3) timer_printf(&ti,"Z2XQ_log"); s = Fp_neg(FpXQ_trace(s, T, pe), pe); if (DEBUGLEVEL>=3) timer_printf(&ti,"FpXQ_trace"); s = modii(gel(Qp_exp(cvtop(s, gen_2, e-2)),4),pe); if (DEBUGLEVEL>=3) timer_printf(&ti,"Qp_exp"); return s; } /* Assume a2==0, so 4|E(F_p): if t^4 = a6 then (t,t^2) is of order 4 8|E(F_p) <=> trace(a6)==0 */ static GEN F2xq_elltrace_Harley(GEN a6, GEN T2) { pari_sp ltop = avma; pari_timer ti; GEN T, sqx; GEN x, x2, t; long n = F2x_degree(T2), N = ((n + 1)>>1) + 2; long ispcyc; if (n==1) return gen_m1; if (n==2) return F2x_degree(a6) ? gen_1 : stoi(-3); if (n==3) return F2x_degree(a6) ? (F2xq_trace(a6,T2) ? stoi(-3): gen_1) : stoi(5); timer_start(&ti); sqx = mkvec2(F2xq_sqrt(polx_F2x(T2[1]),T2), T2); if (DEBUGLEVEL>1) timer_printf(&ti,"Sqrtx"); ispcyc = zx_is_pcyc(F2x_to_Flx(T2)); T = ispcyc? F2x_to_ZX(T2): F2x_canonlift(T2, N-2); if (DEBUGLEVEL>1) timer_printf(&ti,"Teich"); T = FpX_get_red(T, int2n(N)); if (DEBUGLEVEL>1) timer_printf(&ti,"Barrett"); x = solve_AGM_eqn(F2x_to_ZX(a6), N-2, T, sqx); if (DEBUGLEVEL>1) timer_printf(&ti,"Lift"); x2 = ZX_Z_add_shallow(ZX_shifti(x,2), gen_1); t = (ispcyc? Z2XQ_invnorm_pcyc: Z2XQ_invnorm)(x2, T, N); if (DEBUGLEVEL>1) timer_printf(&ti,"Norm"); if (cmpii(sqri(t), int2n(n + 2)) > 0) t = subii(t, int2n(N)); return gerepileuptoint(ltop, t); } static GEN get_v(GEN u, GEN a, GEN T) { GEN a4 = gel(a,2), a3i = gel(a,3); GEN ui2 = F2xq_mul(u, a3i, T), ui4 = F2xq_sqr(ui2, T); return F2xq_mul(a4, ui4, T); } static GEN get_r(GEN w, GEN u, GEN T) { return F2xq_sqr(F2xq_mul(F2xq_Artin_Schreier(w, T), u, T), T); } static GEN F2xq_elltracej(GEN a, GEN a6, GEN T, GEN q, long n) { GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3); GEN r, pi, rhs; long t, s, m = n >> 1; if (odd(n)) { GEN u, v, w; u = F2xq_pow(a3,diviuexact(subiu(shifti(q,1), 1), 3),T); v = get_v(u, a, T); if (F2xq_trace(v, T)==0) return gen_0; w = F2xq_Artin_Schreier(F2x_1_add(v), T); if (F2xq_trace(w, T)) w = F2x_1_add(w); r = get_r(w, u, T); pi = int2n(m+1); s = (((m+3)&3L) <= 1) ? -1: 1; } else { if (F2x_degree(F2xq_pow(a3,diviuexact(subiu(q, 1), 3),T))==0) { GEN u, v, w; u = F2xq_sqrtn(a3, utoi(3), T, NULL); v = get_v(u, a, T); if (F2xq_trace(v, T)==1) return gen_0; w = F2xq_Artin_Schreier(v, T); if (F2xq_trace(w, T)==1) return gen_0; r = get_r(w, u, T); pi = int2n(m+1); s = odd(m+1) ? -1: 1; } else { long sv = T[1]; GEN P = mkpoln(5, pol1_F2x(sv), pol0_F2x(sv), pol0_F2x(sv), a3, a4); r = F2xq_sqr(gel(F2xqX_roots(P,T), 1), T); pi = int2n(m); s = odd(m) ? -1: 1; } } rhs = F2x_add(F2xq_mul(F2x_add(F2xq_sqr(r, T), a4), r, T), a6); t = F2xq_trace(F2xq_mul(rhs, F2xq_sqr(a3i, T), T), T); return (t==0)^(s==1)? pi: negi(pi); } GEN F2xq_ellcard(GEN a, GEN a6, GEN T) { pari_sp av = avma; long n = F2x_degree(T); GEN c; if (typ(a)==t_VECSMALL) { GEN t = F2xq_elltrace_Harley(a6, T); c = addii(int2u(n), F2xq_trace(a,T) ? addui(1,t): subui(1,t)); } else if (n==1) { long a4i = lgpol(gel(a,2)), a6i = lgpol(a6); return utoi(a4i? (a6i? 1: 5): 3); } else { GEN q = int2u(n); c = subii(addiu(q,1), F2xq_elltracej(a, a6, T, q, n)); } return gerepileuptoint(av, c); } /***********************************************************************/ /** **/ /** Group structure **/ /** **/ /***********************************************************************/ static GEN _F2xqE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F) { struct _F2xqE *e = (struct _F2xqE *) E; return F2xq_order(F2xqE_weilpairing(P,Q,m,e->a2,e->T), F, e->T); } GEN F2xq_ellgroup(GEN a2, GEN a6, GEN N, GEN T, GEN *pt_m) { struct _F2xqE e; GEN q = int2u(F2x_degree(T)); e.a2=a2; e.a6=a6; e.T=T; return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &F2xqE_group, _F2xqE_pairorder); } GEN F2xq_ellgens(GEN a2, GEN a6, GEN ch, GEN D, GEN m, GEN T) { GEN P; pari_sp av = avma; struct _F2xqE e; e.a2=a2; e.a6=a6; e.T=T; switch(lg(D)-1) { case 0: return cgetg(1,t_VEC); case 1: P = gen_gener(gel(D,1), (void*)&e, &F2xqE_group); P = mkvec(F2xqE_changepoint(P, ch, T)); break; default: P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &F2xqE_group, _F2xqE_pairorder); gel(P,1) = F2xqE_changepoint(gel(P,1), ch, T); gel(P,2) = F2xqE_changepoint(gel(P,2), ch, T); break; } return gerepilecopy(av, P); } pari-2.11.2/src/basemath/subcyclo.c0000644000175000017500000006665613326135265015551 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*************************************************************************/ /** **/ /** Routines for handling subgroups of (Z/nZ)^* **/ /** without requiring discrete logarithms. **/ /** **/ /*************************************************************************/ /* Subgroups are [gen,ord,bits] where * gen is a vecsmall of generators * ord is theirs relative orders * bits is a bit vector of the elements, of length(n). */ /*The algorithm is similar to testpermutation*/ static void znstar_partial_coset_func(long n, GEN H, void (*func)(void *data,long c) , void *data, long d, long c) { GEN gen, ord, cache; long i, j, card; if (!d) { (*func)(data,c); return; } cache = const_vecsmall(d,c); (*func)(data,c); /* AFTER cache: may contain gerepileupto statement */ gen = gel(H,1); ord = gel(H,2); card = ord[1]; for (i = 2; i <= d; i++) card *= ord[i]; for(i=1; i 0; i--) { long p = P[i], e = E[i], cnd = cnd0; for ( ; e >= 2; e--) { long q = cnd / p; if (!F2v_coeff(bits, 1 + q)) break; cnd = q; } if (e == 1) { if (p == 2) e = 0; else { long h, g = pgener_Fl(p), q = cnd / p; h = Fl_mul(g-1, Fl_inv(q % p, p), p); /* 1+h*q = g (mod p) */ if (F2v_coeff(bits, 1 + h*q)) e = 0; } } if (e) f *= upowuu(p, e); } avma = av; return f; } long znstar_conductor(GEN H) { return znstar_conductor_bits(gel(H,3)); } /* Compute the orbits of a subgroups of Z/nZ given by a generator * or a set of generators given as a vector. */ GEN znstar_cosets(long n, long phi_n, GEN H) { long k; long c = 0; long card = znstar_order(H); long index = phi_n/card; GEN cosets = cgetg(index+1,t_VECSMALL); pari_sp ltop = avma; GEN bits = zero_F2v(n); for (k = 1; k <= index; k++) { for (c++ ; F2v_coeff(bits,c) || ugcd(c,n)!=1; c++); cosets[k]=c; znstar_coset_bits_inplace(n, H, bits, c); } avma=ltop; return cosets; } /*************************************************************************/ /** **/ /** znstar/HNF interface **/ /** **/ /*************************************************************************/ static long mod_to_small(GEN x) { return itos(typ(x) == t_INTMOD ? gel(x,2): x); } static GEN vecmod_to_vecsmall(GEN x) { pari_APPLY_long(mod_to_small(gel(x,i))) } /* Convert a true znstar output by znstar to a `small znstar' */ GEN znstar_small(GEN zn) { GEN Z = cgetg(4,t_VEC); gel(Z,1) = icopy(gmael3(zn,3,1,1)); gel(Z,2) = vec_to_vecsmall(gel(zn,2)); gel(Z,3) = vecmod_to_vecsmall(gel(zn,3)); return Z; } /* Compute generators for the subgroup of (Z/nZ)* given in HNF. */ GEN znstar_hnf_generators(GEN Z, GEN M) { long j, h, l = lg(M); GEN gen = cgetg(l, t_VECSMALL); pari_sp ltop = avma; GEN zgen = gel(Z,3); ulong n = itou(gel(Z,1)); for (j = 1; j < l; j++) { GEN Mj = gel(M,j); gen[j] = 1; for (h = 1; h < l; h++) { ulong u = itou(gel(Mj,h)); if (!u) continue; gen[j] = Fl_mul(uel(gen,j), Fl_powu(uel(zgen,h), u, n), n); } } avma = ltop; return gen; } GEN znstar_hnf(GEN Z, GEN M) { return znstar_generate(itos(gel(Z,1)),znstar_hnf_generators(Z,M)); } GEN znstar_hnf_elts(GEN Z, GEN H) { pari_sp ltop = avma; GEN G = znstar_hnf(Z,H); long n = itos(gel(Z,1)); return gerepileupto(ltop, znstar_elts(n,G)); } /*************************************************************************/ /** **/ /** polsubcyclo **/ /** **/ /*************************************************************************/ static GEN gscycloconductor(GEN g, long n, long flag) { if (flag==2) retmkvec2(gcopy(g), stoi(n)); return g; } static long lift_check_modulus(GEN H, long n) { long h; switch(typ(H)) { case t_INTMOD: if (!equalsi(n, gel(H,1))) pari_err_MODULUS("galoissubcyclo", stoi(n), gel(H,1)); H = gel(H,2); case t_INT: h = smodis(H,n); if (ugcd(h,n) != 1) pari_err_COPRIME("galoissubcyclo", H,stoi(n)); return h; } pari_err_TYPE("galoissubcyclo [subgroup]", H); return 0;/*LCOV_EXCL_LINE*/ } /* Compute z^ex using the baby-step/giant-step table powz * with only one multiply. * In the modular case, the result is not reduced. */ static GEN polsubcyclo_powz(GEN powz, long ex) { long m = lg(gel(powz,1))-1, q = ex/m, r = ex%m; /*ex=m*q+r*/ GEN g = gmael(powz,1,r+1), G = gmael(powz,2,q+1); return (lg(powz)==4)? mulreal(g,G): gmul(g,G); } static GEN polsubcyclo_complex_bound(pari_sp av, GEN V, long prec) { GEN pol = real_i(roots_to_pol(V,0)); return gerepileuptoint(av, ceil_safe(gsupnorm(pol,prec))); } /* Newton sums mod le. if le==NULL, works with complex instead */ static GEN polsubcyclo_cyclic(long n, long d, long m ,long z, long g, GEN powz, GEN le) { GEN V = cgetg(d+1,t_VEC); ulong base = 1; long i,k; pari_timer ti; if (DEBUGLEVEL >= 6) timer_start(&ti); for (i=1; i<=d; i++, base = Fl_mul(base,z,n)) { pari_sp av = avma; long ex = base; GEN s = gen_0; for (k=0; k= 6) timer_printf(&ti, "polsubcyclo_cyclic"); return V; } struct _subcyclo_orbits_s { GEN powz; GEN *s; ulong count; pari_sp ltop; }; static void _subcyclo_orbits(struct _subcyclo_orbits_s *data, long k) { GEN powz = data->powz; GEN *s = data->s; if (!data->count) data->ltop = avma; *s = gadd(*s, polsubcyclo_powz(powz,k)); data->count++; if ((data->count & 0xffUL) == 0) *s = gerepileupto(data->ltop, *s); } /* Newton sums mod le. if le==NULL, works with complex instead */ static GEN polsubcyclo_orbits(long n, GEN H, GEN O, GEN powz, GEN le) { long i, d = lg(O); GEN V = cgetg(d,t_VEC); struct _subcyclo_orbits_s data; long lle = le?lg(le)*2+1: 2*lg(gmael(powz,1,2))+3;/*dvmdii uses lx+ly space*/ data.powz = powz; for(i=1; i= 4) err_printf("Subcyclo: prime l=%ld\n",l); gl = utoipos(l); av = avma; if (!borne) { /* Use vecmax(Vec((x+o)^d)) = max{binomial(d,i)*o^i ;1<=i<=d} */ i = d-(1+d)/(1+o); borne = mulii(binomial(utoipos(d),i),powuu(o,i)); } if (DEBUGLEVEL >= 4) err_printf("Subcyclo: bound=2^%ld\n",expi(borne)); val = logint(shifti(borne,2), gl) + 1; avma = av; if (DEBUGLEVEL >= 4) err_printf("Subcyclo: val=%ld\n",val); le = powiu(gl,val); z = utoipos( Fl_powu(pgener_Fl(l), e, l) ); z = Zp_sqrtnlift(gen_1,utoipos(n),z,gl,val); *ptr_val = val; *ptr_l = l; return gmodulo(z,le); } /*Fill in the powz table: * powz[1]: baby-step * powz[2]: giant-step * powz[3] exists only if the field is real (value is ignored). */ static GEN polsubcyclo_complex_roots(long n, long real, long prec) { long i, m = (long)(1+sqrt((double) n)); GEN bab, gig, powz = cgetg(real?4:3, t_VEC); bab = cgetg(m+1,t_VEC); gel(bab,1) = gen_1; gel(bab,2) = rootsof1u_cx(n, prec); /* = e_n(1) */ for (i=3; i<=m; i++) gel(bab,i) = gmul(gel(bab,2),gel(bab,i-1)); gig = cgetg(m+1,t_VEC); gel(gig,1) = gen_1; gel(gig,2) = gmul(gel(bab,2),gel(bab,m));; for (i=3; i<=m; i++) gel(gig,i) = gmul(gel(gig,2),gel(gig,i-1)); gel(powz,1) = bab; gel(powz,2) = gig; if (real) gel(powz,3) = gen_0; return powz; } static GEN muliimod_sz(GEN x, GEN y, GEN l, long siz) { pari_sp av = avma; GEN p1; (void)new_chunk(siz); /* HACK */ p1 = mulii(x,y); avma = av; return modii(p1,l); } static GEN polsubcyclo_roots(long n, GEN zl) { GEN le = gel(zl,1), z = gel(zl,2); long i, lle = lg(le)*3; /*Assume dvmdii use lx+ly space*/ long m = (long)(1+sqrt((double) n)); GEN bab, gig, powz = cgetg(3,t_VEC); pari_timer ti; if (DEBUGLEVEL >= 6) timer_start(&ti); bab = cgetg(m+1,t_VEC); gel(bab,1) = gen_1; gel(bab,2) = icopy(z); for (i=3; i<=m; i++) gel(bab,i) = muliimod_sz(z,gel(bab,i-1),le,lle); gig = cgetg(m+1,t_VEC); gel(gig,1) = gen_1; gel(gig,2) = muliimod_sz(z,gel(bab,m),le,lle);; for (i=3; i<=m; i++) gel(gig,i) = muliimod_sz(gel(gig,2),gel(gig,i-1),le,lle); if (DEBUGLEVEL >= 6) timer_printf(&ti, "polsubcyclo_roots"); gel(powz,1) = bab; gel(powz,2) = gig; return powz; } GEN galoiscyclo(long n, long v) { ulong av = avma; GEN grp, G, z, le, L, elts; long val, l, i, j, k; GEN zn = znstar(stoi(n)); long card = itos(gel(zn,1)); GEN gen = vec_to_vecsmall(lift_shallow(gel(zn,3))); GEN ord = gtovecsmall(gel(zn,2)); GEN T = polcyclo(n,v); long d = degpol(T); GEN borneabs = powuu(2,d); z = polsubcyclo_start(n,card/2,2,2*usqrt(d),borneabs,&val,&l); le = gel(z,1); z = gel(z,2); L = cgetg(1+card,t_VEC); gel(L,1) = z; for (j = 1, i = 1; j < lg(gen); j++) { long c = i * (ord[j]-1); for (k = 1; k <= c; k++) gel(L,++i) = Fp_powu(gel(L,k), gen[j], le); } G = abelian_group(ord); elts = group_elts(G, card); /*not stack clean*/ grp = cgetg(9, t_VEC); gel(grp,1) = T; gel(grp,2) = mkvec3(stoi(l), stoi(val), icopy(le)); gel(grp,3) = L; gel(grp,4) = FpV_invVandermonde(L, NULL, le); gel(grp,5) = gen_1; gel(grp,6) = elts; gel(grp,7) = gel(G,1); gel(grp,8) = gel(G,2); return gerepilecopy(av, grp); } /* Convert a bnrinit(Q,n) to a znstar(n) * complex is set to 0 if the bnr is real and to 1 if it is complex. * Not stack clean */ GEN bnr_to_znstar(GEN bnr, long *complex) { GEN gen, F, v, bid; long l, i; checkbnr(bnr); bid = bnr_get_bid(bnr); gen = bid_get_gen(bid); F = bid_get_ideal(bid); if (lg(F) != 2) pari_err_DOMAIN("bnr_to_znstar", "bnr", "!=", strtoGENstr("Q"), bnr); /* F is the finite part of the conductor, complex is the infinite part*/ F = gcoeff(F, 1, 1); *complex = signe(gel(bid_get_arch(bid), 1)); l = lg(gen); v = cgetg(l, t_VEC); for (i = 1; i < l; ++i) { GEN x = gel(gen,i); if (typ(x) == t_COL) x = gel(x,1); gel(v,i) = gmodulo(absi_shallow(x), F); } return mkvec3(bnr_get_no(bnr), bnr_get_cyc(bnr), v); } GEN galoissubcyclo(GEN N, GEN sg, long flag, long v) { pari_sp ltop= avma, av; GEN H, V, B, zl, L, T, le, powz, O, Z = NULL; long i, card, phi_n, val,l, n, cnd, complex=1; pari_timer ti; if (flag<0 || flag>2) pari_err_FLAG("galoissubcyclo"); if (v < 0) v = 0; if (!sg) sg = gen_1; switch(typ(N)) { case t_INT: n = itos(N); if (n < 1) pari_err_DOMAIN("galoissubcyclo", "degree", "<=", gen_0, stoi(n)); break; case t_VEC: if (lg(N)==7) N = bnr_to_znstar(N,&complex); else if (checkznstar_i(N)) N = mkvec3(znstar_get_no(N), znstar_get_cyc(N), gmodulo(znstar_get_gen(N), znstar_get_N(N))); if (lg(N)==4) { /* znstar */ GEN gen = abgrp_get_gen(N); Z = N; if (typ(gen)!=t_VEC) pari_err_TYPE("galoissubcyclo",gen); if (lg(gen) == 1) n = 1; else if (typ(gel(gen,1)) == t_INTMOD) { GEN z = gel(gen,1); n = itos(gel(z,1)); } else { pari_err_TYPE("galoissubcyclo",N); return NULL;/*LCOV_EXCL_LINE*/ } break; } default: /*fall through*/ pari_err_TYPE("galoissubcyclo",N); return NULL;/*LCOV_EXCL_LINE*/ } if (n==1) { avma = ltop; if (flag == 1) return gen_1; return gscycloconductor(deg1pol_shallow(gen_1, gen_m1, v), 1, flag); } switch(typ(sg)) { case t_INTMOD: case t_INT: V = mkvecsmall( lift_check_modulus(sg,n) ); break; case t_VECSMALL: V = gcopy(sg); for (i=1; i= 6) { err_printf("Subcyclo: elements:"); for (i=1;i conj(z) = z^-1 = z^(n-1) is in H */ complex = !F2v_coeff(gel(H,3),n-1); if (DEBUGLEVEL >= 6) err_printf("Subcyclo: complex=%ld\n",complex); if (DEBUGLEVEL >= 1) timer_start(&ti); cnd = znstar_conductor(H); if (DEBUGLEVEL >= 1) timer_printf(&ti, "znstar_conductor"); if (flag == 1) { avma=ltop; return stoi(cnd); } if (cnd == 1) { avma = ltop; return gscycloconductor(deg1pol_shallow(gen_1,gen_m1,v),1,flag); } if (n != cnd) { H = znstar_reduce_modulus(H, cnd); n = cnd; } card = znstar_order(H); phi_n = eulerphiu(n); if (card == phi_n) { avma = ltop; return gscycloconductor(polcyclo(n,v),n,flag); } O = znstar_cosets(n, phi_n, H); if (DEBUGLEVEL >= 1) timer_printf(&ti, "znstar_cosets"); if (DEBUGLEVEL >= 6) err_printf("Subcyclo: orbits=%Ps\n",O); if (DEBUGLEVEL >= 4) err_printf("Subcyclo: %ld orbits with %ld elements each\n",phi_n/card,card); av = avma; powz = polsubcyclo_complex_roots(n,!complex,LOWDEFAULTPREC); L = polsubcyclo_orbits(n,H,O,powz,NULL); B = polsubcyclo_complex_bound(av,L,LOWDEFAULTPREC); zl = polsubcyclo_start(n,phi_n/card,card,1,B,&val,&l); powz = polsubcyclo_roots(n,zl); le = gel(zl,1); L = polsubcyclo_orbits(n,H,O,powz,le); if (DEBUGLEVEL >= 6) timer_start(&ti); T = FpV_roots_to_pol(L,le,v); if (DEBUGLEVEL >= 6) timer_printf(&ti, "roots_to_pol"); T = FpX_center(T,le,shifti(le,-1)); return gerepileupto(ltop, gscycloconductor(T,n,flag)); } /* Z = znstar(n) cyclic. n = 1,2,4,p^a or 2p^a, * and d | phi(n) = 1,1,2,(p-1)p^(a-1) */ static GEN polsubcyclo_g(long n, long d, GEN Z, long v) { pari_sp ltop = avma; long o, p, r, g, gd, l , val; GEN zl, L, T, le, B, powz; pari_timer ti; if (d==1) return deg1pol_shallow(gen_1,gen_m1,v); /* get rid of n=1,2 */ if ((n & 3) == 2) n >>= 1; /* n = 4 or p^a, p odd */ o = itos(gel(Z,1)); g = itos(gmael3(Z,3,1,2)); p = n / ugcd(n,o); /* p^a / gcd(p^a,phi(p^a)) = p*/ r = ugcd(d,n); /* = p^(v_p(d)) < n */ n = r*p; /* n is now the conductor */ o = n-r; /* = phi(n) */ if (o == d) return polcyclo(n,v); o /= d; gd = Fl_powu(g%n, d, n); /*FIXME: If degree is small, the computation of B is a waste of time*/ powz = polsubcyclo_complex_roots(n,(o&1)==0,LOWDEFAULTPREC); L = polsubcyclo_cyclic(n,d,o,g,gd,powz,NULL); B = polsubcyclo_complex_bound(ltop,L,LOWDEFAULTPREC); zl = polsubcyclo_start(n,d,o,1,B,&val,&l); le = gel(zl,1); powz = polsubcyclo_roots(n,zl); L = polsubcyclo_cyclic(n,d,o,g,gd,powz,le); if (DEBUGLEVEL >= 6) timer_start(&ti); T = FpV_roots_to_pol(L,le,v); if (DEBUGLEVEL >= 6) timer_printf(&ti, "roots_to_pol"); return gerepileupto(ltop, FpX_center(T,le,shifti(le,-1))); } GEN polsubcyclo(long n, long d, long v) { pari_sp ltop = avma; GEN L, Z; if (v<0) v = 0; if (d<=0) pari_err_DOMAIN("polsubcyclo","d","<=",gen_0,stoi(d)); if (n<=0) pari_err_DOMAIN("polsubcyclo","n","<=",gen_0,stoi(n)); Z = znstar(stoi(n)); if (!dvdis(gel(Z,1), d)) { avma = ltop; return cgetg(1, t_VEC); } if (lg(gel(Z,2)) == 2) { /* faster but Z must be cyclic */ avma = ltop; return polsubcyclo_g(n, d, Z, v); } L = subgrouplist(gel(Z,2), mkvec(stoi(d))); if (lg(L) == 2) return gerepileupto(ltop, galoissubcyclo(Z, gel(L,1), 0, v)); else { GEN V = cgetg(lg(L),t_VEC); long i; for (i=1; i< lg(V); i++) gel(V,i) = galoissubcyclo(Z, gel(L,i), 0, v); return gerepileupto(ltop, V); } } struct aurifeuille_t { GEN z, le; ulong l; long e; }; /* Let z a primitive n-th root of 1, n > 1, A an integer such that * Aurifeuillian factorization of Phi_n(A) exists ( z.A is a square in Q(z) ). * Let G(p) the Gauss sum mod p prime: * sum_x (x|p) z^(xn/p) for p odd, i - 1 for p = 2 [ i := z^(n/4) ] * We have N(-1) = Nz = 1 (n != 1,2), and * G^2 = (-1|p) p for p odd, G^2 = -2i for p = 2 * In particular, for odd A, (-1|A) A = g^2 is a square. If A = prod p^{e_p}, * sigma_j(g) = \prod_p (sigma_j G(p)))^e_p = \prod_p (j|p)^e_p g = (j|A) g * n odd : z^2 is a primitive root, A = g^2 * Phi_n(A) = N(A - z^2) = N(g - z) N(g + z) * * n = 2 (4) : -z^2 is a primitive root, -A = g^2 * Phi_n(A) = N(A - (-z^2)) = N(g^2 - z^2) [ N(-1) = 1 ] * = N(g - z) N(g + z) * * n = 4 (8) : i z^2 primitive root, -Ai = g^2 * Phi_n(A) = N(A - i z^2) = N(-Ai - z^2) = N(g - z) N(g + z) * sigma_j(g) / g = (j|A) if j = 1 (4) * (-j|A)i if j = 3 (4) * */ /* factor Phi_n(A), Astar: A* = squarefree kernel of A, P = odd prime divisors * of n */ static GEN factor_Aurifeuille_aux(GEN A, long Astar, long n, GEN P, struct aurifeuille_t *S) { pari_sp av; GEN f, a, b, s, powers, z = S->z, le = S->le; long j, k, maxjump, lastj, e = S->e; ulong l = S->l; char *invertible; if ((n & 7) == 4) { /* A^* even */ GEN i = Fp_powu(z, n>>2, le), z2 = Fp_sqr(z, le); invertible = stack_malloc(n); /* even indices unused */ for (j = 1; j < n; j+=2) invertible[j] = 1; for (k = 1; k < lg(P); k++) { long p = P[k]; for (j = p; j < n; j += 2*p) invertible[j] = 0; } lastj = 1; maxjump = 2; for (j= 3; j < n; j+=2) if (invertible[j]) { long jump = j - lastj; if (jump > maxjump) maxjump = jump; lastj = j; } powers = cgetg(maxjump+1, t_VEC); /* powers[k] = z^k, odd indices unused */ gel(powers,2) = z2; for (k = 4; k <= maxjump; k+=2) gel(powers,k) = odd(k>>1)? Fp_mul(gel(powers, k-2), z2, le) : Fp_sqr(gel(powers, k>>1), le); if (Astar == 2) { /* important special case (includes A=2), split for efficiency */ if (!equalis(A, 2)) { GEN f = sqrti(shifti(A,-1)), mf = Fp_neg(f,le), fi = Fp_mul(f,i,le); a = Fp_add(mf, fi, le); b = Fp_sub(mf, fi, le); } else { a = subiu(i,1); b = subsi(-1,i); } av = avma; s = z; f = subii(a, s); lastj = 1; for (j = 3, k = 0; j < n; j+=2) if (invertible[j]) { s = Fp_mul(gel(powers, j-lastj), s, le); /* z^j */ lastj = j; f = Fp_mul(f, subii((j & 3) == 1? a: b, s), le); if (++k == 0x1ff) { gerepileall(av, 2, &s, &f); k = 0; } } } else { GEN ma, mb, B = Fp_mul(A, i, le), gl = utoipos(l); long t; Astar >>= 1; t = Astar & 3; if (Astar < 0) t = 4-t; /* t = 1 or 3 */ if (t == 1) B = Fp_neg(B, le); a = Zp_sqrtlift(B, Fp_sqrt(B, gl), gl, e); b = Fp_mul(a, i, le); ma = Fp_neg(a, le); mb = Fp_neg(b, le); av = avma; s = z; f = subii(a, s); lastj = 1; for (j = 3, k = 0; j>= 1; } /* A^* = 1 (mod 4) */ g = Fl_sqrt(umodiu(A,l), l); a = Zp_sqrtlift(A, utoipos(g), utoipos(l), e); b = negi(a); invertible = stack_malloc(n); for (j = 1; j < n; j++) invertible[j] = 1; for (k = 1; k < lg(P); k++) { long p = P[k]; for (j = p; j < n; j += p) invertible[j] = 0; } lastj = 2; maxjump = 1; for (j= 3; j < n; j++) if (invertible[j]) { long jump = j - lastj; if (jump > maxjump) maxjump = jump; lastj = j; } powers = cgetg(maxjump+1, t_VEC); /* powers[k] = z^k */ gel(powers,1) = z; for (k = 2; k <= maxjump; k++) gel(powers,k) = odd(k)? Fp_mul(gel(powers, k-1), z, le) : Fp_sqr(gel(powers, k>>1), le); av = avma; s = z; f = subii(a, s); lastj = 1; for(j = 2, k = 0; j < n; j++) if (invertible[j]) { s = Fp_mul(gel(powers, j-lastj), s, le); lastj = j; f = Fp_mul(f, subii(kross(j,Astar)==1? a: b, s), le); if (++k == 0x1ff) { gerepileall(av, 2, &s, &f); k = 0; } } } return f; } /* fd = factoru(odd part of d = d or d/4). Return eulerphi(d) */ static ulong phi(long d, GEN fd) { GEN P = gel(fd,1), E = gel(fd,2); long i, l = lg(P); ulong phi = 1; for (i = 1; i < l; i++) { ulong p = P[i], e = E[i]; phi *= upowuu(p, e-1)*(p-1); } if (!odd(d)) phi <<= 1; return phi; } static void Aurifeuille_init(GEN a, long d, GEN fd, struct aurifeuille_t *S) { GEN sqrta = sqrtr_abs(itor(a, LOWDEFAULTPREC)); GEN bound = ceil_safe(powru(addrs(sqrta,1), phi(d, fd))); GEN zl = polsubcyclo_start(d, 0, 0, 1, bound, &(S->e), (long*)&(S->l)); S->le = gel(zl,1); S->z = gel(zl,2); } GEN factor_Aurifeuille_prime(GEN p, long d) { pari_sp av = avma; struct aurifeuille_t S; GEN fd; long pp; if ((d & 3) == 2) { d >>= 1; p = negi(p); } fd = factoru(odd(d)? d: d>>2); pp = itos(p); Aurifeuille_init(p, d, fd, &S); return gerepileuptoint(av, factor_Aurifeuille_aux(p, pp, d, gel(fd,1), &S)); } /* an algebraic factor of Phi_d(a), a != 0 */ GEN factor_Aurifeuille(GEN a, long d) { pari_sp av = avma; GEN fd, P, A; long i, lP, va = vali(a), sa, astar, D; struct aurifeuille_t S; if (d <= 0) pari_err_DOMAIN("factor_Aurifeuille", "degre", "<=",gen_0,stoi(d)); if ((d & 3) == 2) { d >>= 1; a = negi(a); } if ((va & 1) == (d & 1)) { avma = av; return gen_1; } sa = signe(a); if (odd(d)) { long a4; if (d == 1) { if (!Z_issquareall(a, &A)) return gen_1; return gerepileuptoint(av, addiu(A,1)); } A = va? shifti(a, -va): a; a4 = mod4(A); if (sa < 0) a4 = 4 - a4; if (a4 != 1) { avma = av; return gen_1; } } else if ((d & 7) == 4) A = shifti(a, -va); else { avma = av; return gen_1; } /* v_2(d) = 0 or 2. Kill 2 from factorization (minor efficiency gain) */ fd = factoru(odd(d)? d: d>>2); P = gel(fd,1); lP = lg(P); astar = sa; if (odd(va)) astar <<= 1; for (i = 1; i < lP; i++) if (odd( (Z_lvalrem(A, P[i], &A)) ) ) astar *= P[i]; if (sa < 0) { /* negate in place if possible */ if (A == a) A = icopy(A); setabssign(A); } if (!Z_issquare(A)) { avma = av; return gen_1; } D = odd(d)? 1: 4; for (i = 1; i < lP; i++) D *= P[i]; if (D != d) { a = powiu(a, d/D); d = D; } Aurifeuille_init(a, d, fd, &S); return gerepileuptoint(av, factor_Aurifeuille_aux(a, astar, d, P, &S)); } pari-2.11.2/src/basemath/FpXX.c0000644000175000017500000013170013326135265014532 0ustar billbill/* Copyright (C) 2012 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Not so fast arithmetic with polynomials over FpX */ /*******************************************************************/ /* */ /* FpXX */ /* */ /*******************************************************************/ /*Polynomials whose coefficients are either polynomials or integers*/ static ulong to_FlxqX(GEN P, GEN Q, GEN T, GEN p, GEN *pt_P, GEN *pt_Q, GEN *pt_T) { ulong pp = uel(p,2); long v = get_FpX_var(T); *pt_P = ZXX_to_FlxX(P, pp, v); if (pt_Q) *pt_Q = ZXX_to_FlxX(Q, pp, v); *pt_T = ZXT_to_FlxT(T, pp); return pp; } static GEN ZXX_copy(GEN a) { return gcopy(a); } GEN FpXX_red(GEN z, GEN p) { GEN res; long i, l = lg(z); res = cgetg(l,t_POL); res[1] = z[1]; for (i=2; ilx) swapspec(x,y, lx,ly); lz = lx; z = cgetg(lz, t_POL); z[1]=x[1]; for (i=2; i=0 && !signe(gel(y, dy1)); dy1--); p1 = gel(x,dx); av = avma; gel(z,dz) = lead? gerepileupto(av, Fq_mul(p1,lead, T, p)): gcopy(p1); for (i=dx-1; i>=dy; i--) { av=avma; p1=gel(x,i); for (j=i-dy1; j<=i && j<=dz; j++) p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j),NULL,p),NULL,p); if (lead) p1 = Fq_mul(p1, lead, NULL,p); tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,Fq_red(p1,T,p)); } if (!pr) { if (lead) gunclone(lead); return z-2; } rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3); for (sx=0; ; i--) { p1 = gel(x,i); for (j=maxss(0,i-dy1); j<=i && j<=dz; j++) p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j),NULL,p),NULL,p); tetpil=avma; p1 = Fq_red(p1, T, p); if (signe(p1)) { sx = 1; break; } if (!i) break; avma=av; } if (pr == ONLY_DIVIDES) { if (lead) gunclone(lead); if (sx) { avma=av0; return NULL; } avma = (pari_sp)rem; return z-2; } lr=i+3; rem -= lr; rem[0] = evaltyp(t_POL) | evallg(lr); rem[1] = z[-1]; p1 = gerepile((pari_sp)rem,tetpil,p1); rem += 2; gel(rem,i) = p1; for (i--; i>=0; i--) { av=avma; p1 = gel(x,i); for (j=maxss(0,i-dy1); j<=i && j<=dz; j++) p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j), NULL,p), NULL,p); tetpil=avma; gel(rem,i) = gerepile(av,tetpil, Fq_red(p1, T, p)); } rem -= 2; if (lead) gunclone(lead); if (!sx) (void)FpXQX_renormalize(rem, lr); if (pr == ONLY_REM) return gerepileupto(av0,rem); *pr = rem; return z-2; } static GEN FpXQX_halfgcd_basecase(GEN a, GEN b, GEN T, GEN p) { pari_sp av=avma; GEN u,u1,v,v1; long vx = varn(a); long n = lgpol(a)>>1; u1 = v = pol_0(vx); u = v1 = pol_1(vx); while (lgpol(b)>n) { GEN r, q = FpXQX_divrem(a,b, T, p, &r); a = b; b = r; swap(u,u1); swap(v,v1); u1 = FpXX_sub(u1, FpXQX_mul(u, q, T, p), p); v1 = FpXX_sub(v1, FpXQX_mul(v, q ,T, p), p); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_halfgcd (d = %ld)",degpol(b)); gerepileall(av,6, &a,&b,&u1,&v1,&u,&v); } } return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1))); } static GEN FpXQX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, GEN p) { return FpXX_add(FpXQX_mul(u, x, T, p),FpXQX_mul(v, y, T, p), p); } static GEN FpXQXM_FpXQX_mul2(GEN M, GEN x, GEN y, GEN T, GEN p) { GEN res = cgetg(3, t_COL); gel(res, 1) = FpXQX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p); gel(res, 2) = FpXQX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p); return res; } static GEN FpXQXM_mul2(GEN A, GEN B, GEN T, GEN p) { GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2); GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2); GEN M1 = FpXQX_mul(FpXX_add(A11,A22, p), FpXX_add(B11,B22, p), T, p); GEN M2 = FpXQX_mul(FpXX_add(A21,A22, p), B11, T, p); GEN M3 = FpXQX_mul(A11, FpXX_sub(B12,B22, p), T, p); GEN M4 = FpXQX_mul(A22, FpXX_sub(B21,B11, p), T, p); GEN M5 = FpXQX_mul(FpXX_add(A11,A12, p), B22, T, p); GEN M6 = FpXQX_mul(FpXX_sub(A21,A11, p), FpXX_add(B11,B12, p), T, p); GEN M7 = FpXQX_mul(FpXX_sub(A12,A22, p), FpXX_add(B21,B22, p), T, p); GEN T1 = FpXX_add(M1,M4, p), T2 = FpXX_sub(M7,M5, p); GEN T3 = FpXX_sub(M1,M2, p), T4 = FpXX_add(M3,M6, p); retmkmat2(mkcol2(FpXX_add(T1,T2, p), FpXX_add(M2,M4, p)), mkcol2(FpXX_add(M3,M5, p), FpXX_add(T3,T4, p))); } /* Return [0,1;1,-q]*M */ static GEN FpXQX_FpXQXM_qmul(GEN q, GEN M, GEN T, GEN p) { GEN u, v, res = cgetg(3, t_MAT); u = FpXX_sub(gcoeff(M,1,1), FpXQX_mul(gcoeff(M,2,1), q, T, p), p); gel(res,1) = mkcol2(gcoeff(M,2,1), u); v = FpXX_sub(gcoeff(M,1,2), FpXQX_mul(gcoeff(M,2,2), q, T, p), p); gel(res,2) = mkcol2(gcoeff(M,2,2), v); return res; } static GEN matid2_FpXQXM(long v) { retmkmat2(mkcol2(pol_1(v),pol_0(v)), mkcol2(pol_0(v),pol_1(v))); } static GEN FpXQX_halfgcd_split(GEN x, GEN y, GEN T, GEN p) { pari_sp av=avma; GEN R, S, V; GEN y1, r, q; long l = lgpol(x), n = l>>1, k; if (lgpol(y)<=n) return matid2_FpXQXM(varn(x)); R = FpXQX_halfgcd(RgX_shift_shallow(x,-n),RgX_shift_shallow(y,-n), T, p); V = FpXQXM_FpXQX_mul2(R,x,y, T, p); y1 = gel(V,2); if (lgpol(y1)<=n) return gerepilecopy(av, R); q = FpXQX_divrem(gel(V,1), y1, T, p, &r); k = 2*n-degpol(y1); S = FpXQX_halfgcd(RgX_shift_shallow(y1,-k), RgX_shift_shallow(r,-k), T, p); return gerepileupto(av, FpXQXM_mul2(S,FpXQX_FpXQXM_qmul(q,R, T, p), T, p)); } /* Return M in GL_2(Fp[X]) such that: if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b') */ static GEN FpXQX_halfgcd_i(GEN x, GEN y, GEN T, GEN p) { if (lg(x)<=FpXQX_HALFGCD_LIMIT) return FpXQX_halfgcd_basecase(x, y, T, p); return FpXQX_halfgcd_split(x, y, T, p); } GEN FpXQX_halfgcd(GEN x, GEN y, GEN T, GEN p) { pari_sp av = avma; GEN M,q,r; if (lgefint(p)==3) { ulong pp = to_FlxqX(x, y, T, p, &x, &y, &T); M = FlxXM_to_ZXXM(FlxqX_halfgcd(x, y, T, pp)); } else { if (!signe(x)) { long v = varn(x); retmkmat2(mkcol2(pol_0(v),pol_1(v)), mkcol2(pol_1(v),pol_0(v))); } if (degpol(y)1) pari_warn(warnmem,"FpXQX_gcd (d = %ld)",degpol(b)); gerepileall(av0,2, &a,&b); } av = avma; c = FpXQX_rem(a, b, T, p); a=b; b=c; } avma = av; return a; } GEN FpXQX_gcd(GEN x, GEN y, GEN T, GEN p) { pari_sp av = avma; if (lgefint(p) == 3) { GEN Pl, Ql, Tl, U; ulong pp = to_FlxqX(x, y, T, p, &Pl, &Ql, &Tl); U = FlxqX_gcd(Pl, Ql, Tl, pp); return gerepileupto(av, FlxX_to_ZXX(U)); } x = FpXQX_red(x, T, p); y = FpXQX_red(y, T, p); if (!signe(x)) return gerepileupto(av, y); while (lg(y)>FpXQX_GCD_LIMIT) { GEN c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r = FpXQX_rem(x, y, T, p); x = y; y = r; } c = FpXQXM_FpXQX_mul2(FpXQX_halfgcd(x,y, T, p), x, y, T, p); x = gel(c,1); y = gel(c,2); gerepileall(av,2,&x,&y); } return gerepileupto(av, FpXQX_gcd_basecase(x, y, T, p)); } static GEN FpXQX_extgcd_basecase(GEN a, GEN b, GEN T, GEN p, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,d,d1,v1; long vx = varn(a); d = a; d1 = b; v = pol_0(vx); v1 = pol_1(vx); while (signe(d1)) { GEN r, q = FpXQX_divrem(d, d1, T, p, &r); v = FpXX_sub(v,FpXQX_mul(q,v1,T, p),p); u=v; v=v1; v1=u; u=r; d=d1; d1=u; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_extgcd (d = %ld)",degpol(d)); gerepileall(av,5, &d,&d1,&u,&v,&v1); } } if (ptu) *ptu = FpXQX_div(FpXX_sub(d,FpXQX_mul(b,v, T, p), p), a, T, p); *ptv = v; return d; } static GEN FpXQX_extgcd_halfgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,R = matid2_FpXQXM(varn(x)); while (lg(y)>FpXQX_EXTGCD_LIMIT) { GEN M, c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r, q = FpXQX_divrem(x, y, T, p, &r); x = y; y = r; R = FpXQX_FpXQXM_qmul(q, R, T, p); } M = FpXQX_halfgcd(x,y, T, p); c = FpXQXM_FpXQX_mul2(M, x,y, T, p); R = FpXQXM_mul2(M, R, T, p); x = gel(c,1); y = gel(c,2); gerepileall(av,3,&x,&y,&R); } y = FpXQX_extgcd_basecase(x,y, T, p, &u,&v); if (ptu) *ptu = FpXQX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T, p); *ptv = FpXQX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T, p); return y; } /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st * ux + vy = gcd (mod T,p) */ GEN FpXQX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv) { GEN d; pari_sp ltop=avma; if (lgefint(p) == 3) { GEN Pl, Ql, Tl, Dl; ulong pp = to_FlxqX(x, y, T, p, &Pl, &Ql, &Tl); Dl = FlxqX_extgcd(Pl, Ql, Tl, pp, ptu, ptv); if (ptu) *ptu = FlxX_to_ZXX(*ptu); *ptv = FlxX_to_ZXX(*ptv); d = FlxX_to_ZXX(Dl); } else { x = FpXQX_red(x, T, p); y = FpXQX_red(y, T, p); if (lg(y)>FpXQX_EXTGCD_LIMIT) d = FpXQX_extgcd_halfgcd(x, y, T, p, ptu, ptv); else d = FpXQX_extgcd_basecase(x, y, T, p, ptu, ptv); } gerepileall(ltop,ptu?3:2,&d,ptv,ptu); return d; } GEN FpXQX_dotproduct(GEN x, GEN y, GEN T, GEN p) { long i, l = minss(lg(x), lg(y)); pari_sp av; GEN c; if (l == 2) return gen_0; av = avma; c = gmul(gel(x,2),gel(y,2)); for (i=3; i=0; i--) if (signe(gel(x,i))) break; return i+1; } static GEN FpXQX_invBarrett_basecase(GEN S, GEN T, GEN p) { long i, l=lg(S)-1, lr = l-1, k; GEN r=cgetg(lr, t_POL); r[1]=S[1]; gel(r,2) = gen_1; for (i=3; i 2 */ for (i=0;i1) gel(q,1) = Fq_red(gel(q,1), T, p); if (lQ>1 && signe(gel(q,1))) { GEN u = gel(q, 1); if (!gequal1(gel(x,0))) u = Fq_mul(u, Fq_sqr(gel(x,0), T, p), T, p); gel(x,1) = Fq_neg(u, T, p); lx = 2; } else lx = 1; nold = 1; for (; mask > 1; ) { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */ long i, lnew, nnew = nold << 1; if (mask & 1) nnew--; mask >>= 1; lnew = nnew + 1; lq = ZXX_lgrenormalizespec(q, minss(lQ,lnew)); z = FpXQX_mulspec(x, q, T, p, lx, lq); /* FIXME: high product */ lz = lgpol(z); if (lz > lnew) lz = lnew; z += 2; /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */ for (i = nold; i < lz; i++) if (signe(gel(z,i))) break; nold = nnew; if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */ /* z + i represents (x*q - 1) / t^i */ lz = ZXX_lgrenormalizespec (z+i, lz-i); z = FpXQX_mulspec(x, z+i, T, p, lx, lz); /* FIXME: low product */ lz = lgpol(z); z += 2; if (lz > lnew-i) lz = ZXX_lgrenormalizespec(z, lnew-i); lx = lz+ i; y = x + i; /* x -= z * t^i, in place */ for (i = 0; i < lz; i++) gel(y,i) = Fq_neg(gel(z,i), T, p); } x -= 2; setlg(x, lx + 2); x[1] = S[1]; return gerepilecopy(av, x); } /* 1/polrecip(S)+O(x^(deg(S)-1)) */ GEN FpXQX_invBarrett(GEN S, GEN T, GEN p) { pari_sp ltop = avma; long l = lg(S); GEN r; if (l<5) return pol_0(varn(S)); if (l<=FpXQX_INVBARRETT_LIMIT) { GEN c = gel(S,l-1), ci=gen_1; if (!gequal1(c)) { ci = Fq_inv(c, T, p); S = FqX_Fq_mul(S, ci, T, p); r = FpXQX_invBarrett_basecase(S, T, p); r = FqX_Fq_mul(r, ci, T, p); } else r = FpXQX_invBarrett_basecase(S, T, p); } else r = FpXQX_invBarrett_Newton(S, T, p); return gerepileupto(ltop, r); } GEN FpXQX_get_red(GEN S, GEN T, GEN p) { if (typ(S)==t_POL && lg(S)>FpXQX_BARRETT_LIMIT) retmkvec2(FpXQX_invBarrett(S,T,p),S); return S; } /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1) * and mg is the Barrett inverse of S. */ static GEN FpXQX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, GEN p, GEN *pr) { GEN q, r; long lt = degpol(S); /*We discard the leading term*/ long ld, lm, lT, lmg; ld = l-lt; lm = minss(ld, lgpol(mg)); lT = ZXX_lgrenormalizespec(S+2,lt); lmg = ZXX_lgrenormalizespec(mg+2,lm); q = FpXX_recipspec(x+lt,ld,ld); /* q = rec(x) lq<=ld*/ q = FpXQX_mulspec(q+2,mg+2,T,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/ q = FpXX_recipspec(q+2,minss(ld,lgpol(q)),ld); /* q = rec (rec(x) * mg) lq<=ld*/ if (!pr) return q; r = FpXQX_mulspec(q+2,S+2,T,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/ r = FpXX_subspec(x,r+2,p,lt,minss(lt,lgpol(r))); /* r = x - r lr<=lt */ if (pr == ONLY_REM) return r; *pr = r; return q; } static GEN FpXQX_divrem_Barrett_noGC(GEN x, GEN mg, GEN S, GEN T, GEN p, GEN *pr) { long l = lgpol(x), lt = degpol(S), lm = 2*lt-1; GEN q = NULL, r; long i; if (l <= lt) { if (pr == ONLY_REM) return ZXX_copy(x); if (pr == ONLY_DIVIDES) return signe(x)? NULL: pol_0(varn(x)); if (pr) *pr = ZXX_copy(x); return pol_0(varn(x)); } if (lt <= 1) return FpXQX_divrem_basecase(x,S,T,p,pr); if (pr != ONLY_REM && l>lm) { q = cgetg(l-lt+2, t_POL); for (i=0;ilm ? shallowcopy(x): x; while (l>lm) { GEN zr, zq = FpXQX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,&zr); long lz = lgpol(zr); if (pr != ONLY_REM) { long lq = lgpol(zq); for(i=0; i lt) { GEN zq = FpXQX_divrem_Barrettspec(r+2,l,mg,S,T,p,&r); if (!q) q = zq; else { long lq = lgpol(zq); for(i=0; i lt) (void) FpXQX_divrem_Barrettspec(r+2,l,mg,S,T,p,&r); else { setlg(r, l+2); r = ZXX_copy(r); } r[1] = x[1]; return FpXQX_renormalize(r, lg(r)); } if (pr) { r[1] = x[1]; r = FpXQX_renormalize(r, lg(r)); } q[1] = x[1]; q = FpXQX_renormalize(q, lg(q)); if (pr == ONLY_DIVIDES) return signe(r)? NULL: q; if (pr) *pr = r; return q; } GEN FpXQX_divrem(GEN x, GEN S, GEN T, GEN p, GEN *pr) { GEN B, y = get_FpXQX_red(S, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (pr==ONLY_REM) return FpXQX_rem(x, y, T, p); if (lgefint(p) == 3) { GEN a, b, t, z; pari_sp tetpil, av = avma; ulong pp = to_FlxqX(x, y, T, p, &a, &b, &t); z = FlxqX_divrem(a, b, t, pp, pr); if (pr == ONLY_DIVIDES && !z) { avma = av; return NULL; } tetpil=avma; z = FlxX_to_ZXX(z); if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM) *pr = FlxX_to_ZXX(*pr); else return gerepile(av, tetpil, z); gerepileallsp(av,tetpil,2, pr, &z); return z; } if (!B && d+3 < FpXQX_DIVREM_BARRETT_LIMIT) return FpXQX_divrem_basecase(x,y,T,p,pr); else { pari_sp av=avma; GEN mg = B? B: FpXQX_invBarrett(y, T, p); GEN q = FpXQX_divrem_Barrett_noGC(x,mg,y,T,p,pr); if (!q) {avma=av; return NULL;} if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q); gerepileall(av,2,&q,pr); return q; } } GEN FpXQX_rem(GEN x, GEN S, GEN T, GEN p) { GEN B, y = get_FpXQX_red(S, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (d < 0) return FpXQX_red(x, T, p); if (lgefint(p) == 3) { pari_sp av = avma; GEN a, b, t, z; ulong pp = to_FlxqX(x, y, T, p, &a, &b, &t); z = FlxqX_rem(a, b, t, pp); z = FlxX_to_ZXX(z); return gerepileupto(av, z); } if (!B && d+3 < FpXQX_REM_BARRETT_LIMIT) return FpXQX_divrem_basecase(x,y, T, p, ONLY_REM); else { pari_sp av=avma; GEN mg = B? B: FpXQX_invBarrett(y, T, p); GEN r = FpXQX_divrem_Barrett_noGC(x, mg, y, T, p, ONLY_REM); return gerepileupto(av, r); } } /* x + y*z mod p */ INLINE GEN Fq_addmul(GEN x, GEN y, GEN z, GEN T, GEN p) { pari_sp av; if (!signe(y) || !signe(z)) return Fq_red(x, T, p); if (!signe(x)) return Fq_mul(z,y, T, p); av = avma; return gerepileupto(av, Fq_add(x, Fq_mul(y, z, T, p), T, p)); } GEN FpXQX_div_by_X_x(GEN a, GEN x, GEN T, GEN p, GEN *r) { long l = lg(a)-1, i; GEN z = cgetg(l, t_POL); z[1] = evalsigne(1) | evalvarn(0); gel(z, l-1) = gel(a,l); for (i=l-2; i>1; i--) /* z[i] = a[i+1] + x*z[i+1] */ gel(z, i) = Fq_addmul(gel(a,i+1), x, gel(z,i+1), T, p); if (r) *r = Fq_addmul(gel(a,2), x, gel(z,2), T, p); return z; } struct _FpXQXQ { GEN T, S; GEN p; }; static GEN _FpXQX_mul(void *data, GEN a,GEN b) { struct _FpXQXQ *d=(struct _FpXQXQ*)data; return FpXQX_mul(a,b,d->T,d->p); } static GEN _FpXQX_sqr(void *data, GEN a) { struct _FpXQXQ *d=(struct _FpXQXQ*)data; return FpXQX_sqr(a, d->T, d->p); } GEN FpXQX_powu(GEN x, ulong n, GEN T, GEN p) { struct _FpXQXQ D; if (n==0) return pol_1(varn(x)); D.T = T; D.p = p; return gen_powu(x, n, (void *)&D, _FpXQX_sqr, _FpXQX_mul); } GEN FpXQXV_prod(GEN V, GEN T, GEN p) { if (lgefint(p) == 3) { pari_sp av = avma; ulong pp = p[2]; GEN Tl = ZXT_to_FlxT(T, pp); GEN Vl = ZXXV_to_FlxXV(V, pp, get_FpX_var(T)); Tl = FlxqXV_prod(Vl, Tl, pp); return gerepileupto(av, FlxX_to_ZXX(Tl)); } else { struct _FpXQXQ d; d.T=T; d.p=p; return gen_product(V, (void*)&d, &_FpXQX_mul); } } static GEN _FpXQX_divrem(void * E, GEN x, GEN y, GEN *r) { struct _FpXQXQ *d = (struct _FpXQXQ *) E; return FpXQX_divrem(x, y, d->T, d->p, r); } static GEN _FpXQX_add(void * E, GEN x, GEN y) { struct _FpXQXQ *d = (struct _FpXQXQ *) E; return FpXX_add(x, y, d->p); } static GEN _FpXQX_sub(void * E, GEN x, GEN y) { struct _FpXQXQ *d = (struct _FpXQXQ*) E; return FpXX_sub(x,y, d->p); } static struct bb_ring FpXQX_ring = { _FpXQX_add, _FpXQX_mul, _FpXQX_sqr }; GEN FpXQX_digits(GEN x, GEN B, GEN T, GEN p) { pari_sp av = avma; long d = degpol(B), n = (lgpol(x)+d-1)/d; GEN z; struct _FpXQXQ D; D.T = T; D.p = p; z = gen_digits(x, B, n, (void *)&D, &FpXQX_ring, _FpXQX_divrem); return gerepileupto(av, z); } GEN FpXQXV_FpXQX_fromdigits(GEN x, GEN B, GEN T, GEN p) { pari_sp av = avma; struct _FpXQXQ D; GEN z; D.T = T; D.p = p; z = gen_fromdigits(x,B,(void *)&D, &FpXQX_ring); return gerepileupto(av, z); } /* Q an FpXY (t_POL with FpX coeffs), evaluate at X = x */ GEN FpXY_evalx(GEN Q, GEN x, GEN p) { long i, lb = lg(Q); GEN z; z = cgetg(lb, t_POL); z[1] = Q[1]; for (i=2; i=2; i--) z = Fq_add(gel(Q,i), FpX_Fp_mul(z, y, p), NULL, p); return gerepileupto(av, z); } /* Q an FpXY, evaluate at (X,Y) = (x,y) */ GEN FpXY_eval(GEN Q, GEN y, GEN x, GEN p) { pari_sp av = avma; return gerepileuptoint(av, FpX_eval(FpXY_evalx(Q, x, p), y, p)); } GEN FpXY_FpXQV_evalx(GEN P, GEN x, GEN T, GEN p) { long i, lP = lg(P); GEN res = cgetg(lP,t_POL); res[1] = P[1]; for(i=2; iT, D->p),D->S,D->T,D->p); } static GEN FpXYQQ_mul(void *data, GEN x, GEN y) { FpXYQQ_muldata *D = (FpXYQQ_muldata*)data; return FpXYQQ_redswap(FpXQX_mul(x,y, D->T, D->p),D->S,D->T,D->p); } /* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */ GEN FpXYQQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p) { pari_sp av = avma; FpXYQQ_muldata D; GEN y; if (lgefint(p) == 3) { ulong pp = to_FlxqX(x, NULL, T, p, &x, NULL, &T); S = ZX_to_Flx(S, pp); y = FlxX_to_ZXX( FlxYqq_pow(x, n, S, T, pp) ); } else { D.S = S; D.T = T; D.p = p; y = gen_pow(x, n, (void*)&D, &FpXYQQ_sqr, &FpXYQQ_mul); } return gerepileupto(av, y); } GEN FpXQXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p) { return FpXQX_rem(FpXQX_mul(x, y, T, p), S, T, p); } GEN FpXQXQ_sqr(GEN x, GEN S, GEN T, GEN p) { return FpXQX_rem(FpXQX_sqr(x, T, p), S, T, p); } /* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist * return lift(1 / (x mod (p,pol))) */ GEN FpXQXQ_invsafe(GEN x, GEN S, GEN T, GEN p) { GEN V, z = FpXQX_extgcd(get_FpXQX_mod(S), x, T, p, NULL, &V); if (degpol(z)) return NULL; z = gel(z,2); z = typ(z)==t_INT ? Fp_invsafe(z,p) : FpXQ_invsafe(z,T,p); if (!z) return NULL; return typ(z)==t_INT ? FpXX_Fp_mul(V, z, p): FpXQX_FpXQ_mul(V, z, T, p); } GEN FpXQXQ_inv(GEN x, GEN S, GEN T,GEN p) { pari_sp av = avma; GEN U = FpXQXQ_invsafe(x, S, T, p); if (!U) pari_err_INV("FpXQXQ_inv",x); return gerepileupto(av, U); } GEN FpXQXQ_div(GEN x,GEN y,GEN S, GEN T,GEN p) { pari_sp av = avma; return gerepileupto(av, FpXQXQ_mul(x, FpXQXQ_inv(y,S,T,p),S,T,p)); } static GEN _FpXQXQ_cmul(void *data, GEN P, long a, GEN x) { struct _FpXQXQ *d = (struct _FpXQXQ*) data; GEN y = gel(P,a+2); return typ(y)==t_INT ? FpXX_Fp_mul(x,y, d->p): FpXX_FpX_mul(x,y,d->p); } static GEN _FpXQXQ_red(void *data, GEN x) { struct _FpXQXQ *d = (struct _FpXQXQ*) data; return FpXQX_red(x, d->T, d->p); } static GEN _FpXQXQ_mul(void *data, GEN x, GEN y) { struct _FpXQXQ *d = (struct _FpXQXQ*) data; return FpXQXQ_mul(x,y, d->S,d->T, d->p); } static GEN _FpXQXQ_sqr(void *data, GEN x) { struct _FpXQXQ *d = (struct _FpXQXQ*) data; return FpXQXQ_sqr(x, d->S,d->T, d->p); } static GEN _FpXQXQ_one(void *data) { struct _FpXQXQ *d = (struct _FpXQXQ*) data; return pol_1(get_FpXQX_var(d->S)); } static GEN _FpXQXQ_zero(void *data) { struct _FpXQXQ *d = (struct _FpXQXQ*) data; return pol_0(get_FpXQX_var(d->S)); } static struct bb_algebra FpXQXQ_algebra = { _FpXQXQ_red, _FpXQX_add, _FpXQX_sub, _FpXQXQ_mul, _FpXQXQ_sqr, _FpXQXQ_one, _FpXQXQ_zero }; const struct bb_algebra * get_FpXQXQ_algebra(void **E, GEN S, GEN T, GEN p) { GEN z = new_chunk(sizeof(struct _FpXQXQ)); struct _FpXQXQ *e = (struct _FpXQXQ *) z; e->T = FpX_get_red(T, p); e->S = FpXQX_get_red(S, e->T, p); e->p = p; *E = (void*)e; return &FpXQXQ_algebra; } static struct bb_algebra FpXQX_algebra = { _FpXQXQ_red, _FpXQX_add, _FpXQX_sub, _FpXQX_mul, _FpXQX_sqr, _FpXQXQ_one, _FpXQXQ_zero }; const struct bb_algebra * get_FpXQX_algebra(void **E, GEN T, GEN p, long v) { GEN z = new_chunk(sizeof(struct _FpXQXQ)); struct _FpXQXQ *e = (struct _FpXQXQ *) z; e->T = FpX_get_red(T, p); e->S = pol_x(v); e->p = p; *E = (void*)e; return &FpXQX_algebra; } /* x over Fq, return lift(x^n) mod S */ GEN FpXQXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p) { pari_sp ltop = avma; GEN y; struct _FpXQXQ D; long s = signe(n); if (!s) return pol_1(varn(x)); if (is_pm1(n)) /* +/- 1 */ return (s < 0)? FpXQXQ_inv(x,S,T,p): ZXX_copy(x); if (lgefint(p) == 3) { ulong pp = to_FlxqX(x, S, T, p, &x, &S, &T); GEN z = FlxqXQ_pow(x, n, S, T, pp); y = FlxX_to_ZXX(z); } else { T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); D.S = S; D.T = T; D.p = p; if (s < 0) x = FpXQXQ_inv(x,S,T,p); y = gen_pow(x, n, (void*)&D,&_FpXQXQ_sqr,&_FpXQXQ_mul); } return gerepileupto(ltop, y); } /* generates the list of powers of x of degree 0,1,2,...,l*/ GEN FpXQXQ_powers(GEN x, long l, GEN S, GEN T, GEN p) { struct _FpXQXQ D; int use_sqr = 2*degpol(x) >= get_FpXQX_degree(S); T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); D.S = S; D.T = T; D.p = p; return gen_powers(x, l, use_sqr, (void*)&D, &_FpXQXQ_sqr, &_FpXQXQ_mul,&_FpXQXQ_one); } /* Let v a linear form, return the linear form z->v(tau*z) that is, v*(M_tau) */ INLINE GEN FpXQX_recipspec(GEN x, long l, long n) { return RgX_recipspec_shallow(x, l, n); } static GEN FpXQXQ_transmul_init(GEN tau, GEN S, GEN T, GEN p) { GEN bht; GEN h, Sp = get_FpXQX_red(S, &h); long n = degpol(Sp), vT = varn(Sp); GEN ft = FpXQX_recipspec(Sp+2, n+1, n+1); GEN bt = FpXQX_recipspec(tau+2, lgpol(tau), n); setvarn(ft, vT); setvarn(bt, vT); if (h) bht = FpXQXn_mul(bt, h, n-1, T, p); else { GEN bh = FpXQX_div(RgX_shift_shallow(tau, n-1), S, T, p); bht = FpXQX_recipspec(bh+2, lgpol(bh), n-1); setvarn(bht, vT); } return mkvec3(bt, bht, ft); } static GEN FpXQXQ_transmul(GEN tau, GEN a, long n, GEN T, GEN p) { pari_sp ltop = avma; GEN t1, t2, t3, vec; GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3); if (signe(a)==0) return pol_0(varn(a)); t2 = RgX_shift_shallow(FpXQX_mul(bt, a, T, p),1-n); if (signe(bht)==0) return gerepilecopy(ltop, t2); t1 = RgX_shift_shallow(FpXQX_mul(ft, a, T, p),-n); t3 = FpXQXn_mul(t1, bht, n-1, T, p); vec = FpXX_sub(t2, RgX_shift_shallow(t3, 1), p); return gerepileupto(ltop, vec); } static GEN polxn_FpXX(long n, long v, long vT) { long i, a = n+2; GEN p = cgetg(a+1, t_POL); p[1] = evalsigne(1)|evalvarn(v); for (i = 2; i < a; i++) gel(p,i) = pol_0(vT); gel(p,a) = pol_1(vT); return p; } GEN FpXQXQ_minpoly(GEN x, GEN S, GEN T, GEN p) { pari_sp ltop = avma; long vS, vT, n; GEN v_x, g, tau; vS = get_FpXQX_var(S); vT = get_FpX_var(T); n = get_FpXQX_degree(S); g = pol_1(vS); tau = pol_1(vS); S = FpXQX_get_red(S, T, p); v_x = FpXQXQ_powers(x, usqrt(2*n), S, T, p); while(signe(tau) != 0) { long i, j, m, k1; GEN M, v, tr; GEN g_prime, c; if (degpol(g) == n) { tau = pol_1(vS); g = pol_1(vS); } v = random_FpXQX(n, vS, T, p); tr = FpXQXQ_transmul_init(tau, S, T, p); v = FpXQXQ_transmul(tr, v, n, T, p); m = 2*(n-degpol(g)); k1 = usqrt(m); tr = FpXQXQ_transmul_init(gel(v_x,k1+1), S, T, p); c = cgetg(m+2,t_POL); c[1] = evalsigne(1)|evalvarn(vS); for (i=0; i , i = 0..m-1 */ M = FpXQX_halfgcd(polxn_FpXX(m, vS, vT), c, T, p); g_prime = gmael(M, 2, 2); if (degpol(g_prime) < 1) continue; g = FpXQX_mul(g, g_prime, T, p); tau = FpXQXQ_mul(tau, FpXQX_FpXQXQV_eval(g_prime, v_x, S, T, p), S, T, p); } g = FpXQX_normalize(g,T, p); return gerepilecopy(ltop,g); } GEN FpXQXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, GEN p) { return RgXV_to_RgM(FpXQXQ_powers(y,m-1,S,T,p),n); } GEN FpXQX_FpXQXQV_eval(GEN P, GEN V, GEN S, GEN T, GEN p) { struct _FpXQXQ D; T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &FpXQXQ_algebra, _FpXQXQ_cmul); } GEN FpXQX_FpXQXQ_eval(GEN Q, GEN x, GEN S, GEN T, GEN p) { struct _FpXQXQ D; int use_sqr = 2*degpol(x) >= get_FpXQX_degree(S); T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &FpXQXQ_algebra, _FpXQXQ_cmul); } static GEN FpXQXQ_autpow_sqr(void * E, GEN x) { struct _FpXQXQ *D = (struct _FpXQXQ *)E; GEN S = D->S, T = D->T, p = D->p; GEN phi = gel(x,1), S1 = gel(x,2); long n = brent_kung_optpow(get_FpX_degree(T)-1,lgpol(S1)+1,1); GEN V = FpXQ_powers(phi, n, T, p); GEN phi2 = FpX_FpXQV_eval(phi, V, T, p); GEN Sphi = FpXY_FpXQV_evalx(S1, V, T, p); GEN S2 = FpXQX_FpXQXQ_eval(Sphi, S1, S, T, p); return mkvec2(phi2, S2); } static GEN FpXQXQ_autpow_mul(void * E, GEN x, GEN y) { struct _FpXQXQ *D = (struct _FpXQXQ *)E; GEN S = D->S, T = D->T, p = D->p; GEN phi1 = gel(x,1), S1 = gel(x,2); GEN phi2 = gel(y,1), S2 = gel(y,2); long n = brent_kung_optpow(get_FpX_degree(T)-1, lgpol(S1)+1, 1); GEN V = FpXQ_powers(phi2, n, T, p); GEN phi3 = FpX_FpXQV_eval(phi1, V, T, p); GEN Sphi = FpXY_FpXQV_evalx(S1, V, T, p); GEN S3 = FpXQX_FpXQXQ_eval(Sphi, S2, S, T, p); return mkvec2(phi3, S3); } GEN FpXQXQ_autpow(GEN aut, long n, GEN S, GEN T, GEN p) { struct _FpXQXQ D; T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_powu(aut,n,&D,FpXQXQ_autpow_sqr,FpXQXQ_autpow_mul); } static GEN FpXQXQ_auttrace_mul(void *E, GEN x, GEN y) { struct _FpXQXQ *D = (struct _FpXQXQ *)E; GEN S = D->S, T = D->T; GEN p = D->p; GEN S1 = gel(x,1), a1 = gel(x,2); GEN S2 = gel(y,1), a2 = gel(y,2); long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1); GEN V = FpXQXQ_powers(S2, n, S, T, p); GEN S3 = FpXQX_FpXQXQV_eval(S1, V, S, T, p); GEN aS = FpXQX_FpXQXQV_eval(a1, V, S, T, p); GEN a3 = FpXX_add(aS, a2, p); return mkvec2(S3, a3); } static GEN FpXQXQ_auttrace_sqr(void *E, GEN x) { return FpXQXQ_auttrace_mul(E, x, x); } GEN FpXQXQ_auttrace(GEN aut, long n, GEN S, GEN T, GEN p) { struct _FpXQXQ D; T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_powu(aut,n,&D,FpXQXQ_auttrace_sqr,FpXQXQ_auttrace_mul); } static GEN FpXQXQ_autsum_mul(void *E, GEN x, GEN y) { struct _FpXQXQ *D = (struct _FpXQXQ *) E; GEN S = D->S, T = D->T, p = D->p; GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3); GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3); long n2 = brent_kung_optpow(get_FpX_degree(T)-1, lgpol(S1)+lgpol(a1)+1, 1); GEN V2 = FpXQ_powers(phi2, n2, T, p); GEN phi3 = FpX_FpXQV_eval(phi1, V2, T, p); GEN Sphi = FpXY_FpXQV_evalx(S1, V2, T, p); GEN aphi = FpXY_FpXQV_evalx(a1, V2, T, p); long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1); GEN V = FpXQXQ_powers(S2, n, S, T, p); GEN S3 = FpXQX_FpXQXQV_eval(Sphi, V, S, T, p); GEN aS = FpXQX_FpXQXQV_eval(aphi, V, S, T, p); GEN a3 = FpXQXQ_mul(aS, a2, S, T, p); return mkvec3(phi3, S3, a3); } static GEN FpXQXQ_autsum_sqr(void * T, GEN x) { return FpXQXQ_autsum_mul(T,x,x); } GEN FpXQXQ_autsum(GEN aut, long n, GEN S, GEN T, GEN p) { struct _FpXQXQ D; T = FpX_get_red(T, p); S = FpXQX_get_red(S, T, p); D.S=S; D.T=T; D.p=p; return gen_powu(aut,n,&D,FpXQXQ_autsum_sqr,FpXQXQ_autsum_mul); } GEN FpXQXn_mul(GEN x, GEN y, long n, GEN T, GEN p) { pari_sp av = avma; GEN z, kx, ky; long d; if (ZXX_is_ZX(y) && ZXX_is_ZX(x)) return FpXn_mul(x,y,n,p); d = get_FpX_degree(T); kx = ZXX_to_Kronecker(x, d); ky = ZXX_to_Kronecker(y, d); z = Kronecker_to_FpXQX(ZXn_mul(ky,kx,(2*d-1)*n), T, p); return gerepileupto(av, z); } GEN FpXQXn_sqr(GEN x, long n, GEN T, GEN p) { pari_sp av = avma; GEN z, kx; long d; if (ZXX_is_ZX(x)) return ZXn_sqr(x, n); d = get_FpX_degree(T); kx= ZXX_to_Kronecker(x, d); z = Kronecker_to_FpXQX(ZXn_sqr(kx, (2*d-1)*n), T, p); return gerepileupto(av, z); } INLINE GEN FpXXn_red(GEN a, long n) { return RgXn_red_shallow(a, n); } GEN FpXQXn_exp(GEN h, long e, GEN T, GEN p) { pari_sp av = avma, av2; long v = varn(h), n=1; GEN f = pol_1(v), g = pol_1(v); ulong mask = quadratic_prec_mask(e); av2 = avma; if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2))) pari_err_DOMAIN("FpXQXn_exp","valuation", "<", gen_1, h); for (;mask>1;) { GEN q, w; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; g = FpXX_sub(FpXX_mulu(g,2,p), FpXQXn_mul(f, FpXQXn_sqr(g, n2, T, p), n2, T, p), p); q = FpXX_deriv(FpXXn_red(h,n2), p); w = FpXX_add(q, FpXQXn_mul(g, FpXX_sub(FpXX_deriv(f, p), FpXQXn_mul(f,q,n-1, T, p), p),n-1, T, p), p); f = FpXX_add(f, FpXQXn_mul(f, FpXX_sub(FpXXn_red(h, n), FpXX_integ(w, p), p), n, T, p), p); if (gc_needed(av2,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpXQXn_exp, e = %ld", n); gerepileall(av2, 2, &f, &g); } } return gerepileupto(av, f); } /* (f*g) \/ x^n */ static GEN FpXQX_mulhigh_i(GEN f, GEN g, long n, GEN T, GEN p) { return RgX_shift_shallow(FpXQX_mul(f,g,T, p),-n); } static GEN FpXQXn_mulhigh(GEN f, GEN g, long n2, long n, GEN T, GEN p) { GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2); return FpXX_add(FpXQX_mulhigh_i(fl, g, n2, T, p), FpXQXn_mul(fh, g, n - n2, T, p), p); } GEN FpXQXn_inv(GEN f, long e, GEN T, GEN p) { pari_sp av = avma, av2; ulong mask; GEN W, a; long v = varn(f), n = 1; if (!signe(f)) pari_err_INV("FpXXn_inv",f); a = Fq_inv(gel(f,2), T, p); if (e == 1) return scalarpol(a, v); else if (e == 2) { GEN b; if (degpol(f) <= 0) return scalarpol(a, v); b = Fq_neg(gel(f,3),T,p); if (signe(b)==0) return scalarpol(a, v); if (!is_pm1(a)) b = Fq_mul(b, Fq_sqr(a, T, p), T, p); W = deg1pol_shallow(b, a, v); return gerepilecopy(av, W); } W = scalarpol_shallow(Fq_inv(gel(f,2), T, p),v); mask = quadratic_prec_mask(e); av2 = avma; for (;mask>1;) { GEN u, fr; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; fr = FpXXn_red(f, n); u = FpXQXn_mul(W, FpXQXn_mulhigh(fr, W, n2, n, T, p), n-n2, T, p); W = FpXX_sub(W, RgX_shift_shallow(u, n2), p); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"FpXQXn_inv, e = %ld", n); W = gerepileupto(av2, W); } } return gerepileupto(av, W); } pari-2.11.2/src/basemath/alglin3.c0000644000175000017500000005502513326135265015243 0ustar billbill/* Copyright (C) 2012 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** LINEAR ALGEBRA **/ /** (third part) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* SUM */ /* */ /*******************************************************************/ GEN vecsum(GEN v) { pari_sp av = avma; long i, l; GEN p; if (!is_vec_t(typ(v))) pari_err_TYPE("vecsum", v); l = lg(v); if (l == 1) return gen_0; p = gel(v,1); if (l == 2) return gcopy(p); for (i=2; i1) pari_warn(warnmem,"sum"); p = gerepileupto(av, p); } } return gerepileupto(av, p); } /*******************************************************************/ /* */ /* TRANSPOSE */ /* */ /*******************************************************************/ /* A[x0,]~ */ static GEN row_transpose(GEN A, long x0) { long i, lB = lg(A); GEN B = cgetg(lB, t_COL); for (i=1; imax) return 0; } if (*s == '.') { s++; if (*s != '.') return 0; do s++; while (isspace((int)*s)); if (*s) { *b = str_to_long(s, &s); if (*b < 0) *b += lx; if (*b<1 || *b>max || *s) return 0; } return 1; } if (*s) return 0; *b = *a; return 1; } static int extract_selector_ok(long lx, GEN L) { long i, l; switch (typ(L)) { case t_INT: { long maxj; if (!signe(L)) return 1; l = lgefint(L)-1; maxj = BITS_IN_LONG - bfffo(*int_MSW(L)); return ((l-2) * BITS_IN_LONG + maxj < lx); } case t_STR: { long first, last, cmpl; return get_range(GSTR(L), &first, &last, &cmpl, lx); } case t_VEC: case t_COL: l = lg(L); for (i=1; i=lx || j<=0) return 0; } return 1; case t_VECSMALL: l = lg(L); for (i=1; i=lx || j<=0) return 0; } return 1; } return 0; } GEN shallowmatextract(GEN x, GEN l1, GEN l2) { long i, j, n1 = lg(l1), n2 = lg(l2); GEN M = cgetg(n2, t_MAT); for(i=1; i < n2; i++) { long ii = l2[i]; GEN C = cgetg(n1, t_COL); for (j=1; j < n1; j++) { long jj = l1[j]; gel(C, j) = gmael(x, ii, jj); } gel(M, i) = C; } return M; } GEN shallowextract(GEN x, GEN L) { long i,j, tl = typ(L), tx = typ(x), lx = lg(x); GEN y; switch(tx) { case t_VEC: case t_COL: case t_MAT: case t_VECSMALL: break; default: pari_err_TYPE("extract",x); } if (tl==t_INT) { /* extract components of x as per the bits of mask L */ long k, l, ix, iy, maxj; GEN Ld; if (!signe(L)) return cgetg(1,tx); y = new_chunk(lx); l = lgefint(L)-1; ix = iy = 1; maxj = BITS_IN_LONG - bfffo(*int_MSW(L)); if ((l-2) * BITS_IN_LONG + maxj >= lx) pari_err_TYPE("vecextract [mask too large]", L); for (k = 2, Ld = int_LSW(L); k < l; k++, Ld = int_nextW(Ld)) { ulong B = *Ld; for (j = 0; j < BITS_IN_LONG; j++, B >>= 1, ix++) if (B & 1) y[iy++] = x[ix]; } { /* k = l */ ulong B = *Ld; for (j = 0; j < maxj; j++, B >>= 1, ix++) if (B & 1) y[iy++] = x[ix]; } y[0] = evaltyp(tx) | evallg(iy); return y; } if (tl==t_STR) { char *s = GSTR(L); long first, last, cmpl, d; if (! get_range(s, &first, &last, &cmpl, lx)) pari_err_TYPE("vecextract [incorrect range]", L); if (lx == 1) return cgetg(1,tx); d = last - first; if (cmpl) { if (d >= 0) { y = cgetg(lx - (1+d),tx); for (j=1; jfirst; i--,j++) gel(y,j) = gel(x,i); for (i=last-1; i>0; i--,j++) gel(y,j) = gel(x,i); } } else { if (d >= 0) { y = cgetg(d+2,tx); for (i=first,j=1; i<=last; i++,j++) gel(y,j) = gel(x,i); } else { y = cgetg(2-d,tx); for (i=first,j=1; i>=last; i--,j++) gel(y,j) = gel(x,i); } } return y; } if (is_vec_t(tl)) { long ll=lg(L); y=cgetg(ll,tx); for (i=1; i=",stoi(lx),stoi(j)); gel(y,i) = gel(x,j); } return y; } if (tl == t_VECSMALL) { long ll=lg(L); y=cgetg(ll,tx); for (i=1; i=",stoi(lx),stoi(j)); gel(y,i) = gel(x,j); } return y; } pari_err_TYPE("vecextract [mask]", L); return NULL; /* LCOV_EXCL_LINE */ } /* does the component selector l select 0 component ? */ static int select_0(GEN l) { switch(typ(l)) { case t_INT: return (!signe(l)); case t_VEC: case t_COL: case t_VECSMALL: return (lg(l) == 1); } return 0; } GEN extract0(GEN x, GEN l1, GEN l2) { pari_sp av = avma, av2; GEN y; if (! l2) { y = shallowextract(x, l1); if (lg(y) == 1 || typ(y) == t_VECSMALL) return y; av2 = avma; y = gcopy(y); } else { if (typ(x) != t_MAT) pari_err_TYPE("extract",x); y = shallowextract(x,l2); if (select_0(l1)) { avma = av; return zeromat(0, lg(y)-1); } if (lg(y) == 1 && lg(x) > 1) { if (!extract_selector_ok(lgcols(x), l1)) pari_err_TYPE("vecextract [incorrect mask]", l1); avma = av; return cgetg(1, t_MAT); } y = shallowextract(shallowtrans(y), l1); av2 = avma; y = gtrans(y); } stackdummy(av, av2); return y; } static long vecslice_parse_arg(long lA, long *y1, long *y2, long *skip) { *skip=0; if (*y1==LONG_MAX) { if (*y2!=LONG_MAX) { if (*y2<0) *y2 += lA; if (*y2<0 || *y2==LONG_MAX || *y2>=lA) pari_err_DIM("_[..]"); *skip=*y2; } *y1 = 1; *y2 = lA-1; } else if (*y2==LONG_MAX) *y2 = *y1; if (*y1<=0) *y1 += lA; if (*y2<0) *y2 += lA; if (*y1<=0 || *y1>*y2+1 || *y2>=lA) pari_err_DIM("_[..]"); return *y2 - *y1 + 2 - !!*skip; } static GEN vecslice_i(GEN A, long t, long lB, long y1, long skip) { GEN B = cgetg(lB, t); long i; for (i=1; i0) return cgetg(1,t_VEC); l = itos(subii(b,a))+1; a = setloop(a); y = cgetg(l+1, t_VEC); for (i=1; i<=l; a = incloop(a), i++) gel(y,i) = icopy(a); return y; } GEN vecrangess(long a, long b) { GEN y; long i, l; if (a>b) return cgetg(1,t_VEC); l = b-a+1; y = cgetg(l+1, t_VEC); for (i=1; i<=l; a++, i++) gel(y,i) = stoi(a); return y; } GEN genindexselect(void *E, long (*f)(void* E, GEN x), GEN A) { long l, i, lv; GEN v, z; pari_sp av; clone_lock(A); switch(typ(A)) { case t_LIST: z = list_data(A); l = z? lg(z): 1; break; case t_VEC: case t_COL: case t_MAT: l = lg(A); z = A; break; default: pari_err_TYPE("select",A); return NULL;/*LCOV_EXCL_LINE*/ } v = cgetg(l, t_VECSMALL); av = avma; for (i = lv = 1; i < l; i++) { if (f(E, gel(z,i))) v[lv++] = i; avma = av; } clone_unlock_deep(A); fixlg(v, lv); return v; } static GEN extract_copy(GEN A, GEN v) { long i, l = lg(v); GEN B = cgetg(l, typ(A)); for (i = 1; i < l; i++) gel(B,i) = gcopy(gel(A,v[i])); return B; } /* as genselect, but treat A [ t_VEC,t_COL, or t_MAT] as a t_VEC */ GEN vecselect(void *E, long (*f)(void* E, GEN x), GEN A) { GEN v; clone_lock(A); v = genindexselect(E, f, A); A = extract_copy(A, v); settyp(A, t_VEC); clone_unlock_deep(A); return A; } GEN genselect(void *E, long (*f)(void* E, GEN x), GEN A) { GEN y, z, v;/* v left on stack for efficiency */ clone_lock(A); switch(typ(A)) { case t_LIST: z = list_data(A); if (!z) y = mklist(); else { GEN B; y = cgetg(3, t_LIST); v = genindexselect(E, f, z); B = extract_copy(z, v); y[1] = lg(B)-1; list_data(y) = B; } break; case t_VEC: case t_COL: case t_MAT: v = genindexselect(E, f, A); y = extract_copy(A, v); break; default: pari_err_TYPE("select",A); return NULL;/*LCOV_EXCL_LINE*/ } clone_unlock_deep(A); return y; } static void check_callgen1(GEN f, const char *s) { if (typ(f) != t_CLOSURE || closure_is_variadic(f) || closure_arity(f) < 1) pari_err_TYPE(s, f); } GEN select0(GEN f, GEN x, long flag) { check_callgen1(f, "select"); switch(flag) { case 0: return genselect((void *) f, gp_callbool, x); case 1: return genindexselect((void *) f, gp_callbool, x); default: pari_err_FLAG("select"); return NULL;/*LCOV_EXCL_LINE*/ } } GEN parselect_worker(GEN d, GEN C) { return gequal0(closure_callgen1(C, d))? gen_0: gen_1; } GEN parselect(GEN C, GEN D, long flag) { pari_sp av; long lv, l = lg(D), i; GEN V, W, worker; check_callgen1(C, "parselect"); if (!is_vec_t(typ(D))) pari_err_TYPE("parselect",D); W = cgetg(l, t_VECSMALL); av = avma; worker = strtoclosure("_parselect_worker", 1, C); V = gen_parapply(worker, D); for (lv=1, i=1; i1) pari_warn(warnmem,"fold"); z = gerepilecopy(av, z); } } clone_unlock_deep(x); return gerepilecopy(av, z); } GEN fold0(GEN f, GEN x) { if (typ(f) != t_CLOSURE || closure_arity(f) < 2) pari_err_TYPE("apply",f); return genfold((void *) f, gp_call2, x); } /*******************************************************************/ /* */ /* SCALAR-MATRIX OPERATIONS */ /* */ /*******************************************************************/ GEN gtomat(GEN x) { long lx, i; GEN y; if (!x) return cgetg(1, t_MAT); switch(typ(x)) { case t_LIST: if (list_typ(x)==t_LIST_MAP) return maptomat(x); x = list_data(x); if (!x) return cgetg(1, t_MAT); /* fall through */ case t_VEC: { lx=lg(x); y=cgetg(lx,t_MAT); if (lx == 1) break; if (typ(gel(x,1)) == t_COL) { long h = lgcols(x); for (i=2; in = n = absi_shallow(n); S->t = subiu(n,1); S->r1 = vali(S->t); S->t1 = shifti(S->t, -S->r1); S->sqrt1 = cgeti(lg(n)); S->sqrt1[1] = evalsigne(0)|evallgefint(2); S->sqrt2 = cgeti(lg(n)); S->sqrt2[1] = evalsigne(0)|evallgefint(2); } static void Fl_init_MR_Jaeschke(Fl_MR_Jaeschke_t *S, ulong n) { S->n = n; S->t = n-1; S->r1 = vals(S->t); S->t1 = S->t >> S->r1; S->sqrt1 = 0; S->sqrt2 = 0; } /* c = sqrt(-1) seen in bad_for_base. End-matching: compare or remember * If ends do mismatch, then we have factored n, and this information * should somehow be made available to the factoring machinery. But so * exceedingly rare... besides we use BSPW now. */ static int MR_Jaeschke_ok(MR_Jaeschke_t *S, GEN c) { if (signe(S->sqrt1)) { /* saw one earlier: compare */ if (!equalii(c, S->sqrt1) && !equalii(c, S->sqrt2)) { /* too many sqrt(-1)s mod n */ if (DEBUGLEVEL) { GEN z = gcdii(addii(c, S->sqrt1), S->n); pari_warn(warner,"found factor\n\t%Ps\ncurrently lost to the factoring machinery", z); } return 1; } } else { /* remember */ affii(c, S->sqrt1); affii(subii(S->n, c), S->sqrt2); } return 0; } static int Fl_MR_Jaeschke_ok(Fl_MR_Jaeschke_t *S, ulong c) { if (S->sqrt1) { /* saw one earlier: compare */ if (c != S->sqrt1 && c != S->sqrt2) return 1; } else { /* remember */ S->sqrt1 = c; S->sqrt2 = S->n - c; } return 0; } /* is n strong pseudo-prime for base a ? 'End matching' (check for square * roots of -1) added by GN */ static int bad_for_base(MR_Jaeschke_t *S, GEN a) { pari_sp av = avma; long r; GEN c2, c = Fp_pow(a, S->t1, S->n); if (is_pm1(c) || equalii(S->t, c)) return 0; /* go fishing for -1, not for 1 (saves one squaring) */ for (r = S->r1 - 1; r; r--) /* r1 - 1 squarings */ { c2 = c; c = remii(sqri(c), S->n); if (equalii(S->t, c)) return MR_Jaeschke_ok(S, c2); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"Rabin-Miller"); c = gerepileuptoint(av, c); } } return 1; } static int Fl_bad_for_base(Fl_MR_Jaeschke_t *S, ulong a) { long r; ulong c2, c = Fl_powu(a, S->t1, S->n); if (c == 1 || c == S->t) return 0; /* go fishing for -1, not for 1 (saves one squaring) */ for (r = S->r1 - 1; r; r--) /* r1 - 1 squarings */ { c2 = c; c = Fl_sqr(c, S->n); if (c == S->t) return Fl_MR_Jaeschke_ok(S, c2); } return 1; } /* Miller-Rabin test for k random bases */ long millerrabin(GEN n, long k) { pari_sp av2, av = avma; ulong r; long i; MR_Jaeschke_t S; if (typ(n) != t_INT) pari_err_TYPE("millerrabin",n); if (signe(n)<=0) return 0; /* If |n| <= 3, check if n = +- 1 */ if (lgefint(n)==3 && uel(n,2)<=3) return uel(n,2) != 1; if (!mod2(n)) return 0; init_MR_Jaeschke(&S, n); av2 = avma; for (i=1; i<=k; i++) { do r = umodui(pari_rand(), n); while (!r); if (DEBUGLEVEL > 4) err_printf("Miller-Rabin: testing base %ld\n", r); if (bad_for_base(&S, utoipos(r))) { avma = av; return 0; } avma = av2; } avma = av; return 1; } GEN gispseudoprime(GEN x, long flag) { return flag? map_proto_lGL(millerrabin, x, flag): map_proto_lG(BPSW_psp,x); } long ispseudoprime(GEN x, long flag) { return flag? millerrabin(x, flag): BPSW_psp(x); } /* As above for k bases taken in pr (i.e not random). We must have |n|>2 and * 1<=k<=11 (not checked) or k in {16,17} to select some special sets of bases. * * From Jaeschke, 'On strong pseudoprimes to several bases', Math.Comp. 61 * (1993), 915--926 (see also http://www.utm.edu/research/primes/prove2.html), * we have: * * k == 4 (bases 2,3,5,7) detects all composites * n < 118 670 087 467 == 172243 * 688969 with the single exception of * n == 3 215 031 751 == 151 * 751 * 28351, * * k == 5 (bases 2,3,5,7,11) detects all composites * n < 2 152 302 898 747 == 6763 * 10627 * 29947, * * k == 6 (bases 2,3,...,13) detects all composites * n < 3 474 749 660 383 == 1303 * 16927 * 157543, * * k == 7 (bases 2,3,...,17) detects all composites * n < 341 550 071 728 321 == 10670053 * 32010157, * Even this limiting value is caught by an end mismatch between bases 5 and 17 * * Moreover, the four bases chosen at * * k == 16 (2,13,23,1662803) detects all composites up * to at least 10^12, and the combination at * * k == 17 (31,73) detects most odd composites without prime factors > 100 * in the range n < 2^36 (with less than 250 exceptions, indeed with fewer * than 1400 exceptions up to 2^42). --GN */ int Fl_MR_Jaeschke(ulong n, long k) { const ulong pr[] = { 0, 2,3,5,7,11,13,17,19,23,29, 31,73, 2,13,23,1662803UL, }; const ulong *p; ulong r; long i; Fl_MR_Jaeschke_t S; if (!(n & 1)) return 0; if (k == 16) { /* use smaller (faster) bases if possible */ p = (n < 3215031751UL)? pr: pr+13; k = 4; } else if (k == 17) { p = (n < 1373653UL)? pr: pr+11; k = 2; } else p = pr; /* 2,3,5,... */ Fl_init_MR_Jaeschke(&S, n); for (i=1; i<=k; i++) { r = p[i] % n; if (!r) break; if (Fl_bad_for_base(&S, r)) return 0; } return 1; } int MR_Jaeschke(GEN n) { pari_sp av = avma; MR_Jaeschke_t S; if (lgefint(n) == 3) return Fl_MR_Jaeschke(uel(n,2), 17); if (!mod2(n)) return 0; av = avma; init_MR_Jaeschke(&S, n); if (bad_for_base(&S, utoipos(31))) { avma = av; return 0; } if (bad_for_base(&S, utoipos(73))) { avma = av; return 0; } avma = av; return 1; } /*********************************************************************/ /** **/ /** PSEUDO PRIMALITY (LUCAS) **/ /** **/ /*********************************************************************/ /* compute n-th term of Lucas sequence modulo N. * v_{k+2} = P v_{k+1} - v_k, v_0 = 2, v_1 = P. * Assume n > 0 */ static GEN LucasMod(GEN n, ulong P, GEN N) { pari_sp av = avma; GEN nd = int_MSW(n); ulong m = *nd; long i, j; GEN v = utoipos(P), v1 = utoipos(P*P - 2); if (m == 1) j = 0; else { j = 1+bfffo(m); /* < BIL */ m <<= j; j = BITS_IN_LONG - j; } for (i=lgefint(n)-2;;) /* cf. leftright_pow */ { for (; j; m<<=1,j--) { /* v = v_k, v1 = v_{k+1} */ if (m&HIGHBIT) { /* set v = v_{2k+1}, v1 = v_{2k+2} */ v = subiu(mulii(v,v1), P); v1= subiu(sqri(v1), 2); } else {/* set v = v_{2k}, v1 = v_{2k+1} */ v1= subiu(mulii(v,v1), P); v = subiu(sqri(v), 2); } v = modii(v, N); v1= modii(v1,N); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"LucasMod"); gerepileall(av, 2, &v,&v1); } } if (--i == 0) return v; j = BITS_IN_LONG; nd=int_precW(nd); m = *nd; } } /* compute n-th term of Lucas sequence modulo N. * v_{k+2} = P v_{k+1} - v_k, v_0 = 2, v_1 = P. * Assume n > 0 */ static ulong u_LucasMod_pre(ulong n, ulong P, ulong N, ulong NI) { ulong v, v1, m; long j; if (n == 1) return P; j = 1 + bfffo(n); /* < BIL */ v = P; v1 = P*P - 2; m = n<>= v; if (n & HIGHMASK) { ulong ni = get_Fl_red(n); z = u_LucasMod_pre(m, b, n, ni); if (z == 2 || z == n-2) return 1; for (i=1; i 3. Caller should check that N is not a square first (taken care of here, * but inefficient) */ static int IsLucasPsP(GEN N) { pari_sp av = avma; GEN m, z; long i, v; ulong b; for (b=3;; b+=2) { ulong c = b*b - 4; /* = 1 mod 4 */ if (b == 129 && Z_issquare(N)) return 0; /* avoid oo loop if N = m^2 */ if (krouu(umodiu(N,c), c) < 0) break; } m = addiu(N,1); v = vali(m); m = shifti(m,-v); z = LucasMod(m, b, N); if (absequaliu(z, 2)) return 1; if (equalii(z, subiu(N,2))) return 1; for (i=1; i1) pari_warn(warnmem,"IsLucasPsP"); z = gerepileupto(av, z); } } return 0; } /* assume u odd, u > 1 */ static int iu_coprime(GEN N, ulong u) { const ulong n = umodiu(N, u); return (n == 1 || ugcd(n, u) == 1); } /* assume u odd, u > 1 */ static int uu_coprime(ulong n, ulong u) { return ugcd(n, u) == 1; } /* composite strong 2-pseudoprime < 1016801 whose prime divisors are > 101 */ static int is_2_prp_101(ulong n) { switch(n) { case 42799: case 49141: case 88357: case 90751: case 104653: case 130561: case 196093: case 220729: case 253241: case 256999: case 271951: case 280601: case 357761: case 390937: case 458989: case 486737: case 489997: case 514447: case 580337: case 741751: case 838861: case 873181: case 877099: case 916327: case 976873: case 983401: return 1; } return 0; } static int u_2_prp(ulong n) { Fl_MR_Jaeschke_t S; Fl_init_MR_Jaeschke(&S, n); return Fl_bad_for_base(&S, 2) == 0; } static int uBPSW_psp(ulong n) { return (u_2_prp(n) && uislucaspsp(n)); } int uisprime(ulong n) { if (n < 103) switch(n) { case 2: case 3: case 5: case 7: case 11: case 13: case 17: case 19: case 23: case 29: case 31: case 37: case 41: case 43: case 47: case 53: case 59: case 61: case 67: case 71: case 73: case 79: case 83: case 89: case 97: case 101: return 1; default: return 0; } if (!odd(n)) return 0; #ifdef LONG_IS_64BIT /* 16294579238595022365 = 3*5*7*11*13*17*19*23*29*31*37*41*43*47*53 * 7145393598349078859 = 59*61*67*71*73*79*83*89*97*101 */ if (!uu_coprime(n, 16294579238595022365UL) || !uu_coprime(n, 7145393598349078859UL)) return 0; #else /* 4127218095 = 3*5*7*11*13*17*19*23*37 * 3948078067 = 29*31*41*43*47*53 * 4269855901 = 59*83*89*97*101 * 1673450759 = 61*67*71*73*79 */ if (!uu_coprime(n, 4127218095UL) || !uu_coprime(n, 3948078067UL) || !uu_coprime(n, 1673450759UL) || !uu_coprime(n, 4269855901UL)) return 0; #endif return uisprime_101(n); } /* assume no prime divisor <= 101 */ int uisprime_101(ulong n) { if (n < 10427) return 1; if (n < 1016801) return u_2_prp(n) && !is_2_prp_101(n); return uBPSW_psp(n); } /* assume no prime divisor <= 661 */ int uisprime_661(ulong n) { return uBPSW_psp(n); } long BPSW_psp(GEN N) { pari_sp av; MR_Jaeschke_t S; int k; if (typ(N) != t_INT) pari_err_TYPE("BPSW_psp",N); if (signe(N) <= 0) return 0; if (lgefint(N) == 3) return uisprime(uel(N,2)); if (!mod2(N)) return 0; #ifdef LONG_IS_64BIT /* 16294579238595022365 = 3*5*7*11*13*17*19*23*29*31*37*41*43*47*53 * 7145393598349078859 = 59*61*67*71*73*79*83*89*97*101 */ if (!iu_coprime(N, 16294579238595022365UL) || !iu_coprime(N, 7145393598349078859UL)) return 0; #else /* 4127218095 = 3*5*7*11*13*17*19*23*37 * 3948078067 = 29*31*41*43*47*53 * 4269855901 = 59*83*89*97*101 * 1673450759 = 61*67*71*73*79 */ if (!iu_coprime(N, 4127218095UL) || !iu_coprime(N, 3948078067UL) || !iu_coprime(N, 1673450759UL) || !iu_coprime(N, 4269855901UL)) return 0; #endif /* no prime divisor < 103 */ av = avma; init_MR_Jaeschke(&S, N); k = (!bad_for_base(&S, gen_2) && IsLucasPsP(N)); avma = av; return k; } /* can we write n = x^k ? Assume N has no prime divisor <= 2^14. * Not memory clean */ long isanypower_nosmalldiv(GEN N, GEN *px) { GEN x = N, y; ulong mask = 7; long ex, k = 1; forprime_t T; while (Z_issquareall(x, &y)) { k <<= 1; x = y; } while ( (ex = is_357_power(x, &y, &mask)) ) { k *= ex; x = y; } (void)u_forprime_init(&T, 11, ULONG_MAX); /* stop when x^(1/k) < 2^14 */ while ( (ex = is_pth_power(x, &y, &T, 15)) ) { k *= ex; x = y; } *px = x; return k; } /* no prime divisor <= 2^14 (> 661) */ long BPSW_psp_nosmalldiv(GEN N) { pari_sp av; MR_Jaeschke_t S; long l = lgefint(N); int k; if (l == 3) return uisprime_661(uel(N,2)); av = avma; /* N large: test for pure power, rarely succeeds, but requires < 1% of * compositeness test times */ if (bit_accuracy(l) > 512 && isanypower_nosmalldiv(N, &N) != 1) { avma = av; return 0; } init_MR_Jaeschke(&S, N); k = (!bad_for_base(&S, gen_2) && IsLucasPsP(N)); avma = av; return k; } /***********************************************************************/ /** **/ /** Pocklington-Lehmer **/ /** P-1 primality test **/ /** **/ /***********************************************************************/ /* Assume x BPSW pseudoprime. Check whether it's small enough to be certified * prime (< 2^64). Reference for strong 2-pseudoprimes: * http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html */ static int BPSW_isprime_small(GEN x) { long l = lgefint(x); #ifdef LONG_IS_64BIT return (l == 3); #else return (l <= 4); #endif } /* Assume N > 1, p^e || N-1, p prime. Find a witness a(p) such that * a^(N-1) = 1 (mod N) * a^(N-1)/p - 1 invertible mod N. * Proves that any divisor of N is 1 mod p^e. Return 0 if N is composite */ static ulong pl831(GEN N, GEN p) { GEN b, c, g, Nmunp = diviiexact(subiu(N,1), p); pari_sp av = avma; ulong a; for(a = 2;; a++, avma = av) { b = Fp_pow(utoipos(a), Nmunp, N); if (!equali1(b)) break; } c = Fp_pow(b,p,N); g = gcdii(subiu(b,1), N); /* 0 < g < N */ return (equali1(c) && equali1(g))? a: 0; } /* Brillhart, Lehmer, Selfridge test (Crandall & Pomerance, Th 4.1.5) * N^(1/3) <= f fully factored, f | N-1. If pl831(p) is true for * any prime divisor p of f, then any divisor of N is 1 mod f. * In that case return 1 iff N is prime */ static int BLS_test(GEN N, GEN f) { GEN c1, c2, r, q; q = dvmdii(N, f, &r); if (!is_pm1(r)) return 0; c2 = dvmdii(q, f, &c1); /* N = 1 + f c1 + f^2 c2, 0 <= c_i < f; check whether it is of the form * (1 + fa)(1 + fb) */ return ! Z_issquare(subii(sqri(c1), shifti(c2,2))); } /* BPSW_psp(N) && !BPSW_isprime_small(N). Decide between Pocklington-Lehmer * and APRCL/ECPP. Return a vector of (small) primes such that PL-witnesses * guarantee the primality of N. Return NULL if PL is likely too expensive. * Return gen_0 if BLS test finds N to be composite */ static GEN BPSW_try_PL(GEN N) { ulong B = minuu(1UL<<19, maxprime()); GEN E, p, U, F, N_1 = subiu(N,1); GEN fa = Z_factor_limit(N_1, B), P = gel(fa,1); long n = lg(P)-1; p = gel(P,n); /* if p prime, then N-1 is fully factored */ if (cmpii(p,sqru(B)) <= 0 || (BPSW_psp_nosmalldiv(p) && BPSW_isprime(p))) return P; E = gel(fa,2); U = powii(p, gel(E,n)); /* unfactored part of N-1 */ /* factored part of N-1; n >= 2 since 2p | N-1 */ F = (n == 2)? powii(gel(P,1), gel(E,1)): diviiexact(N_1, U); setlg(P, n); /* remove last (composite) entry */ /* N-1 = F U, F factored, U possibly composite, (U,F) = 1 */ if (cmpii(F, U) > 0) return P; /* 1/2-smooth */ if (cmpii(sqri(F), U) > 0) return BLS_test(N,F)? P: gen_0; /* 1/3-smooth */ return NULL; /* not smooth enough */ } static GEN isprimePL(GEN N); /* F is a vector whose entries are primes. For each of them, find a PL * witness. Return 0 if caller lied and F contains a composite */ static long PL_certify(GEN N, GEN F) { long i, l = lg(F); for(i = 1; i < l; i++) if (! pl831(N, gel(F,i))) return 0; return 1; } /* F is a vector whose entries are *believed* to be primes (BPSW_psp). * For each of them, recording a witness and recursive primality certificate */ static GEN PL_certificate(GEN N, GEN F) { long i, l = lg(F); GEN C; if (BPSW_isprime_small(N)) return N; C = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN p = gel(F,i), C0; ulong w; if (BPSW_isprime_small(p)) { gel(C,i) = p; continue; } w = pl831(N,p); if (!w) return gen_0; C0 = isprimePL(p); if (isintzero(C0)) { /* composite in prime factorisation ! */ err_printf("Not a prime: %Ps", p); pari_err_BUG("PL_certificate [false prime number]"); } gel(C,i) = mkvec3(p,utoipos(w), C0); } return mkvec2(N, C); } /* M a t_MAT */ static int PL_isvalid(GEN v) { GEN C, F, F2, N, N1, U; long i, l; switch(typ(v)) { case t_INT: return BPSW_isprime_small(v) && BPSW_psp(v); case t_VEC: if (lg(v) == 3) break;/*fall through */ default: return 0; } N = gel(v,1); C = gel(v,2); if (typ(N) != t_INT || signe(N) <= 0 || typ(C) != t_VEC) return 0; U = N1 = subiu(N,1); l = lg(C); for (i = 1; i < l; i++) { GEN p = gel(C,i), a = NULL, C0 = NULL, ap; long vp; if (typ(p) != t_INT) { if (lg(p) != 4) return 0; a = gel(p,2); C0 = gel(p,3); p = gel(p,1); if (typ(p) != t_INT || typ(a) != t_INT || !PL_isvalid(C0)) return 0; } vp = Z_pvalrem(U, p, &U); if (!vp) return 0; if (!a) { if (!BPSW_isprime_small(p)) return 0; continue; } if (!equalii(gel(C0,1), p)) return 0; ap = Fp_pow(a, diviiexact(N1,p), N); if (!equali1(gcdii(subiu(ap,1), N)) || !equali1(Fp_pow(ap, p, N))) return 0; } F = diviiexact(N1, U); /* factored part of N-1 */ F2= sqri(F); if (cmpii(F2, N) > 0) return 1; if (cmpii(mulii(F2,F), N) <= 0) return 0; return BLS_test(N,F); } /* Assume N is a strong BPSW pseudoprime, Pocklington-Lehmer primality proof. * Return gen_0 (non-prime), N (small prime), matrix (large prime) * * The matrix has 3 columns, [a,b,c] with * a[i] prime factor of N-1, * b[i] witness for a[i] as in pl831 * c[i] check_prime(a[i]) */ static GEN isprimePL(GEN N) { GEN cbrtN, N_1, F, f; if (BPSW_isprime_small(N)) return N; cbrtN = sqrtnint(N,3); N_1 = subiu(N,1); F = Z_factor_until(N_1, sqri(cbrtN)); f = factorback(F); /* factored part of N-1, f^3 > N */ if (DEBUGLEVEL>3) { GEN r = divri(itor(f,LOWDEFAULTPREC), N); err_printf("Pocklington-Lehmer: proving primality of N = %Ps\n", N); err_printf("Pocklington-Lehmer: N-1 factored up to %Ps! (%.3Ps%%)\n", f, r); } /* if N-1 is only N^(1/3)-smooth, BLS test */ if (!equalii(f,N_1) && cmpii(sqri(f),N) <= 0 && !BLS_test(N,f)) return gen_0; /* Failed, N is composite */ F = gel(F,1); settyp(F, t_VEC); return PL_certificate(N, F); } /* assume N a BPSW pseudoprime, in particular, it is odd > 2. Prove N prime */ long BPSW_isprime(GEN N) { pari_sp av; long t; GEN P; if (BPSW_isprime_small(N)) return 1; av = avma; P = BPSW_try_PL(N); if (!P) /* not smooth enough */ t = expi(N) < 768? isprimeAPRCL(N): isprimeECPP(N); else t = (typ(P) == t_INT)? 0: PL_certify(N,P); avma = av; return t; } static long _isprimePL(GEN x) { pari_sp av = avma; if (!BPSW_psp(x)) return 0; x = isprimePL(x); avma = av; return !isintzero(x); } GEN gisprime(GEN x, long flag) { switch (flag) { case 0: return map_proto_lG(isprime,x); case 1: return map_proto_lG(_isprimePL,x); case 2: return map_proto_lG(isprimeAPRCL,x); case 3: return map_proto_lG(isprimeECPP,x); } pari_err_FLAG("gisprime"); return NULL; } long isprime(GEN x) { return BPSW_psp(x) && BPSW_isprime(x); } GEN primecert(GEN x, long flag) { if (!BPSW_psp(x)) return gen_0; switch(flag) { case 0: return ecpp(x); case 1: { pari_sp av = avma; return gerepilecopy(av, isprimePL(x)); } } pari_err_FLAG("primecert"); return NULL;/*LCOV_EXCL_LINE*/ } enum { c_VOID = 0, c_ECPP, c_N1 }; static long cert_type(GEN c) { switch(typ(c)) { case t_INT: return c_ECPP; case t_VEC: if (lg(c) == 3 && typ(gel(c,1)) == t_INT) return c_N1; return c_ECPP; } return c_VOID; } long primecertisvalid(GEN c) { switch(typ(c)) { case t_INT: return BPSW_isprime_small(c) && BPSW_psp(c); case t_VEC: return cert_type(c) == c_ECPP? ecppisvalid(c): PL_isvalid(c); } return 0; } static long check_eccpcertentry(GEN c) { GEN v; long i,l = lg(c); if (typ(c)!=t_VEC || l!=6) return 0; for(i=1; i<=4; i++) if (typ(gel(c,i))!=t_INT) return 0; v = gel(c,5); if(typ(v)!=t_VEC) return 0; for(i=1; i<=2; i++) if (typ(gel(v,i))!=t_INT) return 0; return 1; } static long check_eccpcert(GEN c) { long i, l; switch(typ(c)) { case t_INT: return signe(c) >= 0; case t_VEC: break; default: return 0; } l = lg(c); if (l == 1) return 0; for (i = 1; i < l; i++) if (check_eccpcertentry(gel(c,i))==0) return 0; return 1; } GEN primecertexport(GEN c, long flag) { if (cert_type(c) != c_ECPP) pari_err_IMPL("N-1 certificate"); if (!check_eccpcert(c)) pari_err_TYPE("primecertexport - invalid certificate", c); return ecppexport(c, flag); } /***********************************************************************/ /** **/ /** PRIME NUMBERS **/ /** **/ /***********************************************************************/ static struct { ulong p; long n; } prime_table[] = { { 0, 0}, { 7919, 1000}, { 17389, 2000}, { 27449, 3000}, { 37813, 4000}, { 48611, 5000}, { 59359, 6000}, { 70657, 7000}, { 81799, 8000}, { 93179, 9000}, { 104729, 10000}, { 224737, 20000}, { 350377, 30000}, { 479909, 40000}, { 611953, 50000}, { 746773, 60000}, { 882377, 70000}, { 1020379, 80000}, { 1159523, 90000}, { 1299709, 100000}, { 2750159, 200000}, { 7368787, 500000}, { 15485863, 1000000}, { 32452843, 2000000}, { 86028121, 5000000}, { 179424673, 10000000}, { 373587883, 20000000}, { 982451653, 50000000}, { 2038074743, 100000000}, { 4000000483UL,189961831}, { 4222234741UL,200000000}, #if BITS_IN_LONG == 64 { 5336500537UL, 250000000L}, { 6461335109UL, 300000000L}, { 7594955549UL, 350000000L}, { 8736028057UL, 400000000L}, { 9883692017UL, 450000000L}, { 11037271757UL, 500000000L}, { 13359555403UL, 600000000L}, { 15699342107UL, 700000000L}, { 18054236957UL, 800000000L}, { 20422213579UL, 900000000L}, { 22801763489UL, 1000000000L}, { 47055833459UL, 2000000000L}, { 71856445751UL, 3000000000L}, { 97011687217UL, 4000000000L}, {122430513841UL, 5000000000L}, {148059109201UL, 6000000000L}, {173862636221UL, 7000000000L}, {200000000507UL, 8007105083L}, {225898512559UL, 9000000000L}, {252097800623UL,10000000000L}, {384489816343UL,15000000000L}, {518649879439UL,20000000000L}, {654124187867UL,25000000000L}, {790645490053UL,30000000000L}, {928037044463UL,35000000000L}, {1066173339601UL,40000000000L}, {1344326694119UL,50000000000L}, {1624571841097UL,60000000000L}, {1906555030411UL,70000000000L}, {2190026988349UL,80000000000L}, {2474799787573UL,90000000000L}, {2760727302517UL,100000000000L} #endif }; static const int prime_table_len = numberof(prime_table); /* find prime closest to n in prime_table. */ static long prime_table_closest_p(ulong n) { long i; for (i = 1; i < prime_table_len; i++) { ulong p = prime_table[i].p; if (p > n) { ulong u = n - prime_table[i-1].p; if (p - n > u) i--; break; } } if (i == prime_table_len) i = prime_table_len - 1; return i; } /* return the n-th successor of prime p > 2 */ static GEN prime_successor(ulong p, ulong n) { forprime_t S; ulong i; forprime_init(&S, utoipos(p+1), NULL); for (i = 1; i < n; i++) (void)forprime_next(&S); return forprime_next(&S); } /* find the N-th prime */ static GEN prime_table_find_n(ulong N) { byteptr d; ulong n, p, maxp = maxprime(); long i; for (i = 1; i < prime_table_len; i++) { n = prime_table[i].n; if (n > N) { ulong u = N - prime_table[i-1].n; if (n - N > u) i--; break; } } if (i == prime_table_len) i = prime_table_len - 1; p = prime_table[i].p; n = prime_table[i].n; if (n > N && p > maxp) { i--; p = prime_table[i].p; n = prime_table[i].n; } /* if beyond prime table, then n <= N */ d = diffptr + n; if (n > N) { n -= N; do { n--; PREC_PRIME_VIADIFF(p,d); } while (n) ; } else if (n < N) { n = N-n; if (p > maxp) return prime_successor(p, n); do { if (!*d) return prime_successor(p, n); n--; NEXT_PRIME_VIADIFF(p,d); } while (n) ; } return utoipos(p); } ulong uprime(long N) { pari_sp av = avma; GEN p; if (N <= 0) pari_err_DOMAIN("prime", "n", "<=",gen_0, stoi(N)); p = prime_table_find_n(N); if (lgefint(p) != 3) pari_err_OVERFLOW("uprime"); avma = av; return p[2]; } GEN prime(long N) { pari_sp av = avma; GEN p; if (N <= 0) pari_err_DOMAIN("prime", "n", "<=",gen_0, stoi(N)); new_chunk(4); /*HACK*/ p = prime_table_find_n(N); avma = av; return icopy(p); } /* random b-bit prime */ GEN randomprime(GEN N) { pari_sp av = avma, av2; GEN a, b, d; if (!N) for(;;) { ulong p = random_bits(31); if (uisprime(p)) return utoipos(p); } switch(typ(N)) { case t_INT: a = gen_2; b = subiu(N,1); /* between 2 and N-1 */ d = subiu(N,2); if (signe(d) <= 0) pari_err_DOMAIN("randomprime","N", "<=", gen_2, N); break; case t_VEC: if (lg(N) != 3) pari_err_TYPE("randomprime",N); a = gel(N,1); b = gel(N,2); if (gcmp(b, a) < 0) pari_err_DOMAIN("randomprime","b-a", "<", gen_0, mkvec2(a,b)); if (typ(a) != t_INT) { a = gceil(a); if (typ(a) != t_INT) pari_err_TYPE("randomprime",a); } if (typ(b) != t_INT) { b = gfloor(b); if (typ(b) != t_INT) pari_err_TYPE("randomprime",b); } if (cmpis(a, 2) < 0) { a = gen_2; d = subiu(b,1); } else d = addiu(subii(b,a), 1); if (signe(d) <= 0) pari_err_DOMAIN("randomprime","floor(b) - max(ceil(a),2)", "<", gen_0, mkvec2(a,b)); break; default: pari_err_TYPE("randomprime", N); return NULL; /*LCOV_EXCL_LINE*/ } av2 = avma; for (;;) { GEN p = addii(a, randomi(d)); if (BPSW_psp(p)) return gerepileuptoint(av, p); avma = av2; } } /* set *pp = nextprime(a) = p * *pd so that NEXT_PRIME_VIADIFF(d, p) = nextprime(p+1) * *pn so that p = the n-th prime * error if nextprime(a) is out of primetable bounds */ void prime_table_next_p(ulong a, byteptr *pd, ulong *pp, ulong *pn) { byteptr d; ulong p, n, maxp = maxprime(); long i = prime_table_closest_p(a); p = prime_table[i].p; if (p > a && p > maxp) { i--; p = prime_table[i].p; } /* if beyond prime table, then p <= a */ n = prime_table[i].n; d = diffptr + n; if (p < a) { if (a > maxp) pari_err_MAXPRIME(a); do { n++; NEXT_PRIME_VIADIFF(p,d); } while (p < a); } else if (p != a) { do { n--; PREC_PRIME_VIADIFF(p,d); } while (p > a) ; if (p < a) { NEXT_PRIME_VIADIFF(p,d); n++; } } *pn = n; *pp = p; *pd = d; } ulong uprimepi(ulong a) { ulong p, n, maxp = maxprime(); if (a <= maxp) { byteptr d; prime_table_next_p(a, &d, &p, &n); return p == a? n: n-1; } else { long i = prime_table_closest_p(a); forprime_t S; p = prime_table[i].p; if (p > a) { i--; p = prime_table[i].p; } /* p = largest prime in table <= a */ n = prime_table[i].n; (void)u_forprime_init(&S, p+1, a); for (; p; n++) p = u_forprime_next(&S); return n-1; } } GEN primepi(GEN x) { pari_sp av = avma; GEN pp, nn, N = typ(x) == t_INT? x: gfloor(x); forprime_t S; ulong n, p; long i; if (typ(N) != t_INT) pari_err_TYPE("primepi",N); if (signe(N) <= 0) return gen_0; if (lgefint(N) == 3) { n = N[2]; avma = av; return utoi(uprimepi(n)); } i = prime_table_len-1; p = prime_table[i].p; n = prime_table[i].n; (void)forprime_init(&S, utoipos(p+1), N); nn = setloop(utoipos(n)); pp = gen_0; for (; pp; incloop(nn)) pp = forprime_next(&S); return gerepileuptoint(av, subiu(nn,1)); } /* pi(x) < x/log x * (1 + 1/log x + 2.51/log^2 x)), x>=355991 [ Dusart ] * pi(x) < x/(log x - 1.1), x >= 60184 [ Dusart ] * ? \p9 * ? M = 0; for(x = 4, 60184, M = max(M, log(x) - x/primepi(x))); M * %1 = 1.11196252 */ double primepi_upper_bound(double x) { if (x >= 355991) { double L = 1/log(x); return x * L * (1 + L + 2.51*L*L); } if (x >= 60184) return x / (log(x) - 1.1); if (x < 5) return 2; /* don't bother */ return x / (log(x) - 1.111963); } /* pi(x) > x/log x (1 + 1/log x), x >= 599 [ Dusart ] * pi(x) > x / (log x + 2), x >= 55 [ Rosser ] */ double primepi_lower_bound(double x) { if (x >= 599) { double L = 1/log(x); return x * L * (1 + L); } if (x < 55) return 0; /* don't bother */ return x / (log(x) + 2.); } GEN gprimepi_upper_bound(GEN x) { pari_sp av = avma; double L; if (typ(x) != t_INT) x = gfloor(x); if (expi(x) <= 1022) { avma = av; return dbltor(primepi_upper_bound(gtodouble(x))); } x = itor(x, LOWDEFAULTPREC); L = 1 / rtodbl(logr_abs(x)); x = mulrr(x, dbltor(L * (1 + L + 2.51*L*L))); return gerepileuptoleaf(av, x); } GEN gprimepi_lower_bound(GEN x) { pari_sp av = avma; double L; if (typ(x) != t_INT) x = gfloor(x); if (abscmpiu(x, 55) <= 0) return gen_0; if (expi(x) <= 1022) { avma = av; return dbltor(primepi_lower_bound(gtodouble(x))); } x = itor(x, LOWDEFAULTPREC); L = 1 / rtodbl(logr_abs(x)); x = mulrr(x, dbltor(L * (1 + L))); return gerepileuptoleaf(av, x); } GEN primes(long n) { forprime_t S; long i; GEN y; if (n <= 0) return cgetg(1, t_VEC); y = cgetg(n+1, t_VEC); (void)new_chunk(3*n); /*HACK*/ u_forprime_init(&S, 2, ULONG_MAX); avma = (pari_sp)y; for (i = 1; i <= n; i++) gel(y, i) = utoipos( u_forprime_next(&S) ); return y; } GEN primes_zv(long n) { forprime_t S; long i; GEN y; if (n <= 0) return cgetg(1, t_VECSMALL); y = cgetg(n+1,t_VECSMALL); u_forprime_init(&S, 2, ULONG_MAX); for (i = 1; i <= n; i++) y[i] = u_forprime_next(&S); avma = (pari_sp)y; return y; } GEN primes0(GEN N) { switch(typ(N)) { case t_INT: return primes(itos(N)); case t_VEC: if (lg(N) == 3) return primes_interval(gel(N,1),gel(N,2)); } pari_err_TYPE("primes", N); return NULL; } GEN primes_interval(GEN a, GEN b) { pari_sp av = avma; forprime_t S; long i, n; GEN y, d, p; if (typ(a) != t_INT) { a = gceil(a); if (typ(a) != t_INT) pari_err_TYPE("primes_interval",a); } if (typ(b) != t_INT) { b = gfloor(b); if (typ(b) != t_INT) pari_err_TYPE("primes_interval",b); } if (signe(a) < 0) a = gen_2; d = subii(b, a); if (signe(d) < 0 || signe(b) <= 0) { avma = av; return cgetg(1, t_VEC); } if (lgefint(b) == 3) { avma = av; y = primes_interval_zv(itou(a), itou(b)); n = lg(y); settyp(y, t_VEC); for (i = 1; i < n; i++) gel(y,i) = utoipos(y[i]); return y; } /* at most d+1 primes in [a,b]. If d large, try better bound to lower * memory use */ if (abscmpiu(d,100000) > 0) { GEN D = gsub(gprimepi_upper_bound(b), gprimepi_lower_bound(a)); D = ceil_safe(D); if (cmpii(D, d) < 0) d = D; } n = itos(d)+1; forprime_init(&S, a, b); y = cgetg(n+1, t_VEC); i = 1; while ((p = forprime_next(&S))) gel(y, i++) = icopy(p); setlg(y, i); return gerepileupto(av, y); } /* a <= b, at most d primes in [a,b]. Return them */ static GEN primes_interval_i(ulong a, ulong b, ulong d) { ulong p, i = 1, n = d + 1; forprime_t S; GEN y = cgetg(n+1, t_VECSMALL); pari_sp av = avma; u_forprime_init(&S, a, b); while ((p = u_forprime_next(&S))) y[i++] = p; avma = av; setlg(y, i); stackdummy((pari_sp)(y + i), (pari_sp)(y + n+1)); return y; } GEN primes_interval_zv(ulong a, ulong b) { ulong d; if (!a) return primes_upto_zv(b); if (b < a) return cgetg(1, t_VECSMALL); d = b - a; if (d > 100000UL) { ulong D = (ulong)ceil(primepi_upper_bound(b)-primepi_lower_bound(a)); if (D < d) d = D; } return primes_interval_i(a, b, d); } GEN primes_upto_zv(ulong b) { ulong d; if (b < 2) return cgetg(1, t_VECSMALL); d = (b > 100000UL)? (ulong)primepi_upper_bound(b): b; return primes_interval_i(2, b, d); } /***********************************************************************/ /** **/ /** PRIVATE PRIME TABLE **/ /** **/ /***********************************************************************/ static GEN global_primetab; void pari_init_primetab(void) { global_primetab = NULL; } void pari_pthread_init_primetab(void) { global_primetab = primetab; } void pari_thread_init_primetab(void) { if (global_primetab) { long i, l = lg(global_primetab); primetab = cgetg_block(l, t_VEC); for (i = 1; i < l; i++) gel(primetab,i) = gclone(gel(global_primetab,i)); } else primetab = cgetg_block(1, t_VEC); } /* delete dummy NULL entries */ static void cleanprimetab(GEN T) { long i,j, l = lg(T); for (i = j = 1; i < l; i++) if (T[i]) T[j++] = T[i]; setlg(T,j); } /* remove p from T */ static void rmprime(GEN T, GEN p) { long i; if (typ(p) != t_INT) pari_err_TYPE("removeprimes",p); i = ZV_search(T, p); if (!i) pari_err_DOMAIN("removeprimes","prime","not in", strtoGENstr("primetable"), p); gunclone(gel(T,i)); gel(T,i) = NULL; cleanprimetab(T); } /*stolen from ZV_union_shallow() : clone entries from y */ static GEN addp_union(GEN x, GEN y) { long i, j, k, lx = lg(x), ly = lg(y); GEN z = cgetg(lx + ly - 1, t_VEC); i = j = k = 1; while (i 0) gel(z,k++) = gclone(gel(y,j++)); else { gel(z,k++) = gel(x,i++); j++; } } while (i 0) { /* sort 3 real roots in decreasing order */ R = real_i(R); gen_sort_inplace(R, NULL, &invcmp, NULL); e1 = gel(R,1); e2 = gel(R,2); e3 = gel(R,3); d3 = subrr(e1,e2); d1 = subrr(e2,e3); d2 = subrr(e1,e3); if (realprec(d3) < prec0 || realprec(d1) < prec0) return NULL; } else { e1 = gel(R,1); e2 = gel(R,2); e3 = gel(R,3); if (s < 0) { /* make sure e1 is real, imag(e2) > 0 and imag(e3) < 0 */ e1 = real_i(e1); if (signe(gel(e2,2)) < 0) swap(e2, e3); } d3 = gsub(e1,e2); d1 = gsub(e2,e3); d2 = gsub(e1,e3); if (precision(d1) < prec0 || precision(d2) < prec0 || precision(d3) < prec0) return NULL; } return mkcol6(e1,e2,e3,d1,d2,d3); } static GEN doellR_roots(GEN e, long prec0) { long p; for (p = prec0;; p = precdbl(p)) { GEN v = doellR_roots_i(e, p, prec0); if (v) return v; if (DEBUGLEVEL) pari_warn(warnprec,"doellR_roots", p); } } static GEN ellR_root(GEN e, long prec) { return gel(ellR_roots(e,prec),1); } /* Given E and the x-coordinate of a point Q = [xQ, yQ], return * f(xQ) = xQ^3 + E.a2 * xQ^2 + E.a4 * xQ + E.a6 * where E is given by y^2 + h(x)y = f(x). */ GEN ec_f_evalx(GEN E, GEN x) { pari_sp av = avma; GEN z; z = gadd(ell_get_a2(E),x); z = gadd(ell_get_a4(E), gmul(x,z)); z = gadd(ell_get_a6(E), gmul(x,z)); return gerepileupto(av, z); /* ((x + E.a2) * x + E.a4) * x + E.a6 */ } /* a1 x + a3 */ GEN ec_h_evalx(GEN e, GEN x) { GEN a1 = ell_get_a1(e); GEN a3 = ell_get_a3(e); return gadd(a3, gmul(x,a1)); } static GEN Zec_h_evalx(GEN e, GEN x) { GEN a1 = ell_get_a1(e); GEN a3 = ell_get_a3(e); return signe(a1)? addii(a3, mulii(x, a1)): a3; } /* y^2 + a1 xy + a3 y = y^2 + h(x)y */ static GEN ec_LHS_evalQ(GEN e, GEN Q) { GEN x = gel(Q,1), y = gel(Q,2); return gmul(y, gadd(y, ec_h_evalx(e,x))); } /* Given E and a point Q = [xQ, yQ], return * 3 * xQ^2 + 2 * E.a2 * xQ + E.a4 - E.a1 * yQ. * which is the derivative of the curve equation * f(x) - (y^2 + h(x)y) = 0 * wrt x evaluated at Q */ GEN ec_dFdx_evalQ(GEN E, GEN Q) { pari_sp av = avma; GEN x = gel(Q,1), y = gel(Q,2); GEN a1 = ell_get_a1(E); GEN a2 = ell_get_a2(E); GEN a4 = ell_get_a4(E); GEN tmp = gmul(gadd(gmulsg(3L,x), gmul2n(a2,1)), x); return gerepileupto(av, gadd(tmp, gsub(a4, gmul(a1, y)))); } /* 2y + a1 x + a3 = -ec_dFdy_evalQ */ GEN ec_dmFdy_evalQ(GEN e, GEN Q) { GEN x = gel(Q,1), y = gel(Q,2); return gadd(ec_h_evalx(e,x), gmul2n(y,1)); } /* Given E and a point Q = [xQ, yQ], return * -(2 * yQ + E.a1 * xQ + E.a3) * which is the derivative of the curve equation * f(x) - (y^2 + h(x)y) = 0 * wrt y evaluated at Q */ GEN ec_dFdy_evalQ(GEN E, GEN Q) { pari_sp av = avma; return gerepileupto(av, gneg(ec_dmFdy_evalQ(E,Q))); } /* Given E and a point Q = [xQ, yQ], return * 4 xQ^3 + E.b2 xQ^2 + 2 E.b4 xQ + E.b6 * which is the 2-division polynomial of E evaluated at Q */ GEN ec_2divpol_evalx(GEN E, GEN x) { pari_sp av = avma; GEN b2 = ell_get_b2(E), x4 = gmul2n(x,2), t1, t2; GEN b42 = gmul2n(ell_get_b4(E), 1); GEN b6 = ell_get_b6(E); if (ell_get_type(E) == t_ELL_NF) { GEN nf = ellnf_get_nf(E); t1 = nfmul(nf, nfadd(nf, x4, b2), x); t2 = nfadd(nf, t1, b42); t2 = nfadd(nf, nfmul(nf, t2, x), b6); t2 = nftoalg(nf, t2); } else { t1 = gmul(gadd(x4, b2), x); t2 = gadd(t1, b42); t2 = gadd(gmul(t2, x), b6); } return gerepileupto(av, t2); } /* Given E and a point Q = [xQ, yQ], return * 3 xQ^4 + E.b2 xQ^3 + 3 E.b4 xQ^2 + 3*E.b6 xQ + E.b8 * which is the 3-division polynomial of E evaluated at Q */ GEN ec_3divpol_evalx(GEN E, GEN x) { pari_sp av = avma; GEN b2 = ell_get_b2(E); GEN b4 = ell_get_b4(E); GEN b6 = ell_get_b6(E); GEN b8 = ell_get_b8(E); GEN x2 = gsqr(x); GEN t1 = gadd(gadd(gmulsg(3L, x2), gmul(b2, x)), gmulsg(3L, b4)); GEN t2 = gadd(gmul(gmulsg(3L, b6), x), b8); return gerepileupto(av, gadd(gmul(t1, x2), t2)); } /* Given E and a point Q = [xQ, yQ], return * 6 xQ^2 + E.b2 xQ + E.b4 * which, if f is the curve equation, is 2 dfdx - E.a1 dfdy evaluated at Q */ GEN ec_half_deriv_2divpol_evalx(GEN E, GEN x) { pari_sp av = avma; GEN b2 = ell_get_b2(E); GEN b4 = ell_get_b4(E); GEN res = gadd(gmul(gadd(gmulsg(6L, x), b2), x), b4); return gerepileupto(av, res); } /* Return the characteristic of the ring over which E is defined. */ GEN ellbasechar(GEN E) { pari_sp av = avma; GEN D = ell_get_disc(E); return gerepileuptoint(av, characteristic(D)); } /* Initialize basic elliptic struct y[1..12] for initsmall * (do not include j to allow for singular Weistrass model) * Also allocate room for n dynamic members. */ static GEN initsmall_i(GEN x, long n) { GEN a1,a2,a3,a4,a6, b2,b4,b6,b8, c4,c6, D; GEN y = obj_init(15, n); switch(lg(x)) { case 1: case 2: case 4: case 5: pari_err_TYPE("ellxxx [not an elliptic curve (ell5)]",x); return NULL; /* LCOV_EXCL_LINE */ case 3: a1 = a2 = a3 = gen_0; a4 = gel(x,1); a6 = gel(x,2); b2 = gen_0; b4 = gmul2n(a4,1); b6 = gmul2n(a6,2); b8 = gneg(gsqr(a4)); c4 = gmulgs(a4,-48); c6 = gmulgs(a6,-864); D = gadd(gmul(gmulgs(a4,-64), gsqr(a4)), gmulsg(-432,gsqr(a6))); break; default: /* l > 5 */ { GEN a11, a13, a33, b22; a1 = gel(x,1); a2 = gel(x,2); a3 = gel(x,3); a4 = gel(x,4); a6 = gel(x,5); a11= gsqr(a1); b2 = gadd(a11, gmul2n(a2,2)); a13= gmul(a1, a3); b4 = gadd(a13, gmul2n(a4,1)); a33= gsqr(a3); b6 = gadd(a33, gmul2n(a6,2)); b8 = gsub(gadd(gmul(a11,a6), gmul(b6, a2)), gmul(a4, gadd(a4,a13))); b22= gsqr(b2); c4 = gadd(b22, gmulsg(-24,b4)); c6 = gadd(gmul(b2,gsub(gmulsg(36,b4),b22)), gmulsg(-216,b6)); D = gsub(gmul(b4, gadd(gmulsg(9,gmul(b2,b6)),gmulsg(-8,gsqr(b4)))), gadd(gmul(b22,b8),gmulsg(27,gsqr(b6)))); break; } } gel(y,1) = a1; gel(y,2) = a2; gel(y,3) = a3; gel(y,4) = a4; gel(y,5) = a6; gel(y,6) = b2; /* a1^2 + 4a2 */ gel(y,7) = b4; /* a1 a3 + 2a4 */ gel(y,8) = b6; /* a3^2 + 4 a6 */ gel(y,9) = b8; /* a1^2 a6 + 4a6 a2 + a2 a3^2 - a4(a4 + a1 a3) */ gel(y,10)= c4; /* b2^2 - 24 b4 */ gel(y,11)= c6; /* 36 b2 b4 - b2^3 - 216 b6 */ gel(y,12)= D; gel(y,16) = zerovec(n); return y; } /* return basic elliptic struct y[1..13], y[14] (domain type) and y[15] * (domain-specific data) are left uninitialized, from x[1], ..., x[5]. * Also allocate room for n dynamic members (actually stored in the last * component y[16])*/ static GEN initsmall(GEN x, long n) { GEN j, y = initsmall_i(x, n), c4 = ell_get_c4(y), D = ell_get_disc(y); if (gequal0(D)) { gel(y, 13) = gen_0; return NULL; } if (typ(D) == t_POL && typ(c4) == t_POL && varn(D) == varn(c4)) { /* c4^3 / D, simplifying incrementally */ GEN g = RgX_gcd(D, c4); if (degpol(g) == 0) j = gred_rfrac_simple(gmul(gsqr(c4),c4), D); else { GEN d, c = RgX_div(c4, g); D = RgX_div(D, g); g = RgX_gcd(D,c4); if (degpol(g) == 0) j = gred_rfrac_simple(gmul(gsqr(c4),c), D); else { D = RgX_div(D, g); d = RgX_div(c4, g); g = RgX_gcd(D,c4); if (degpol(g)) { D = RgX_div(D, g); c4 = RgX_div(c4, g); } j = gred_rfrac_simple(gmul(gmul(c4, d),c), D); } } } else j = gdiv(gmul(gsqr(c4),c4), D); gel(y,13) = j; return y; } void ellprint(GEN e) { pari_sp av = avma; long vx, vy; GEN z; checkell5(e); vx = fetch_var(); name_var(vx, "X"); vy = fetch_var(); name_var(vy, "Y"); z = mkvec2(pol_x(vx), pol_x(vy)); err_printf("%Ps - (%Ps)\n", ec_LHS_evalQ(e, z), ec_f_evalx(e, pol_x(vx))); (void)delete_var(); (void)delete_var(); avma = av; } /* compute a,b such that E1: y^2 = x(x-a)(x-b) ~ E */ static GEN doellR_ab(GEN E, long prec) { GEN b2 = ell_get_b2(E), R = ellR_roots(E, prec); GEN e1 = gel(R,1), d2 = gel(R,5), d3 = gel(R,6), a, b, t; t = gmul2n(gadd(mulur(12,e1), b2), -4); /* = (12 e1 + b2) / 16 */ if (ellR_get_sign(E) > 0) b = mulrr(d3,d2); else b = cxnorm(d3); b = sqrtr(b); /* = sqrt( (e1 - e2)(e1 - e3) ) */ if (gsigne(t) > 0) togglesign(b); a = gsub(gmul2n(b,-1),t); return mkvec2(a, b); } GEN ellR_ab(GEN E, long prec) { return obj_checkbuild_realprec(E, R_AB, &doellR_ab, prec); } /* q a t_REAL*/ static long real_prec(GEN q) { return signe(q)? realprec(q): LONG_MAX; } /* q a t_PADIC */ static long padic_prec(GEN q) { return signe(gel(q,4))? precp(q)+valp(q): valp(q); } /* check whether moduli are consistent */ static void chk_p(GEN p, GEN p2) { if (!equalii(p, p2)) pari_err_MODULUS("ellinit", p,p2); } static int fix_nftype(GEN *pp) { switch(nftyp(*pp)) { case typ_NF: case typ_BNF: break; case typ_BNR:*pp = bnr_get_bnf(*pp); break; default: return 0; } return 1; } static long base_ring(GEN x, GEN *pp, long *prec) { long i, e = *prec, ep = LONG_MAX, imax = minss(lg(x), 6); GEN p = NULL; long t = t_FRAC; if (*pp) switch(t = typ(*pp)) { case t_INT: if (cmpis(*pp,2) < 0) { t = t_FRAC; p = NULL; break; } p = *pp; t = t_INTMOD; break; case t_INTMOD: p = gel(*pp, 1); break; case t_REAL: e = real_prec(*pp); p = NULL; break; case t_PADIC: ep = padic_prec(*pp); p = gel(*pp, 2); break; case t_FFELT: p = *pp; break; case t_VEC: t = t_VEC; p = *pp; if (fix_nftype(&p)) break; default: pari_err_TYPE("elliptic curve base_ring", *pp); return 0; } /* Possible cases: * t = t_VEC (p an nf or bnf) * t = t_FFELT (p t_FFELT) * t = t_INTMOD (p a prime) * t = t_PADIC (p a prime, ep = padic prec) * t = t_REAL (p = NULL, e = real prec) * t = t_FRAC (p = NULL) */ for (i = 1; i < imax; i++) { GEN p2, q = gel(x,i); switch(typ(q)) { case t_PADIC: p2 = gel(q,2); switch(t) { case t_FRAC: t = t_PADIC; p = p2; break; case t_PADIC: chk_p(p,p2); break; default: pari_err_TYPE("elliptic curve base_ring", x); } ep = minss(ep, padic_prec(q)); break; case t_INTMOD: p2 = gel(q,1); switch(t) { case t_FRAC: t = t_INTMOD; p = p2; break; case t_FFELT: chk_p(FF_p_i(p),p2); break; case t_INTMOD:chk_p(p,p2); break; default: pari_err_TYPE("elliptic curve base_ring", x); } break; case t_FFELT: switch(t) { case t_INTMOD: chk_p(p, FF_p_i(q)); /* fall through */ case t_FRAC: t = t_FFELT; p = q; break; case t_FFELT: if (!FF_samefield(p,q) && FF_f(q)>1) pari_err_MODULUS("ellinit", p,q); break; default: pari_err_TYPE("elliptic curve base_ring", x); } break; case t_INT: case t_FRAC: break; case t_REAL: switch(t) { case t_REAL: e = minss(e, real_prec(q)); break; case t_FRAC: e = real_prec(q); t = t_REAL; break; default: pari_err_TYPE("elliptic curve base_ring", x); } break; case t_COL: case t_POL: case t_POLMOD: if (t == t_VEC) break; default: /* base ring too general */ return t_COMPLEX; } } *pp = p; *prec = (t == t_PADIC)? ep: e; return t; } /* s = 0 complex, else real; * if (s = 2) set s = sign(D), else accept s as is */ static GEN ellinit_Rg(GEN x, long s, long prec) { GEN y; if (lg(x) > 6) switch(ell_get_type(x)) { case t_ELL_Rg: case t_ELL_Q: break; default: pari_err_TYPE("elliptic curve base_ring", x); } if (!(y = initsmall(x, 4))) return NULL; if (s == 2) s = gsigne(ell_get_disc(y)); gel(y,14) = mkvecsmall(t_ELL_Rg); gel(y,15) = mkvec(mkvecsmall2(prec2nbits(prec), s)); return y; } static GEN ellinit_Qp(GEN x, GEN p, long prec) { GEN y; if (lg(x) > 6) { switch(ell_get_type(x)) { /* sanity checks */ case t_ELL_Q: break; case t_ELL_Qp: chk_p(ellQp_get_p(x), p); break; default: pari_err_TYPE("elliptic curve base_ring", x); } x = vecslice(x,1,5); } x = QpV_to_QV(x); /* make entries rational */ if (!(y = initsmall(x, 2))) return NULL; gel(y,14) = mkvecsmall(t_ELL_Qp); gel(y,15) = mkvec(zeropadic(p, prec)); return y; } static GEN ellinit_Q(GEN x, long prec) { GEN y; long s; if (!(y = initsmall(x, 8))) return NULL; s = gsigne( ell_get_disc(y) ); gel(y,14) = mkvecsmall(t_ELL_Q); gel(y,15) = mkvec(mkvecsmall2(prec2nbits(prec), s)); return y; } static GEN nfVtoalg(GEN nf, GEN x) { long i, l; GEN y = cgetg_copy(x,&l); for (i=1; i 6) x = vecslice(x,1,5); nf = checknf(p); x = nfVtoalg(nf, x); if (!(y = initsmall(x, 5))) return NULL; gel(y,14) = mkvecsmall(t_ELL_NF); gel(y,15) = mkvec(p); return y; } /* FF_ellinit allows singular cubic, return NULL in that case */ static GEN FF_ellinit_ns(GEN x, GEN fg) { x = FF_ellinit(x,fg); return FF_equal0(ell_get_disc(x))? NULL: x; } static GEN ellinit_Fp(GEN x, GEN p) { long i; GEN y, disc; if (lg(x) > 6) switch(ell_get_type(x)) { case t_ELL_Q: break; case t_ELL_Fp: chk_p(ellff_get_p(x),p); break; case t_ELL_Qp: chk_p(ellQp_get_p(x),p); break; default: pari_err_TYPE("elliptic curve base_ring", x); } if (!(y = initsmall(x, 4))) return NULL; /* ell_to_a4a6_bc does not handle p<=3 */ if (abscmpiu(p,3)<=0) return FF_ellinit_ns(y,p_to_FF(p,0)); disc = Rg_to_Fp(ell_get_disc(y),p); if (!signe(disc)) return NULL; for(i=1;i<=13;i++) gel(y,i) = Fp_to_mod(Rg_to_Fp(gel(y,i),p),p); gel(y,14) = mkvecsmall(t_ELL_Fp); gel(y,15) = mkvec2(p, ell_to_a4a6_bc(y, p)); return y; } static GEN ellinit_Fq(GEN x, GEN fg) { GEN y; if (!(y = initsmall(x, 4))) return NULL; return FF_ellinit_ns(y,fg); } static GEN ellnf_to_Fq(GEN nf, GEN x, GEN P, GEN *pp, GEN *pT) { GEN e = vecslice(x,1,5); GEN p, modP; if (get_modpr(P)) { /* modpr accept */ modP = P; p = modpr_get_p(modP); } else { /* pr, initialize modpr */ GEN d = Q_denom(e); p = pr_get_p(P); modP = dvdii(d,p)? nfmodprinit(nf,P): zkmodprinit(nf,P); } *pp = p; *pT = modpr_get_T(modP); return nfV_to_FqV(e, nf, modP); } static GEN ellinit_nf_to_Fq(GEN nf, GEN E, GEN P) { GEN T,p; E = ellnf_to_Fq(nf, E, P, &p, &T); return T? ellinit_Fq(E,Tp_to_FF(T,p)): ellinit_Fp(E,p); } GEN ellinit(GEN x, GEN D, long prec) { pari_sp av = avma; GEN y; switch(typ(x)) { case t_STR: x = gel(ellsearchcurve(x),2); break; case t_VEC: if (lg(x) > 6) checkell(x); break; default: pari_err_TYPE("ellxxx [not an elliptic curve (ell5)]",x); } if (D && get_prid(D)) { if (lg(x) == 6 || ell_get_type(x) != t_ELL_NF) pari_err_TYPE("ellinit",x); y = ellinit_nf_to_Fq(ellnf_get_nf(x), x, D); goto END; } switch (base_ring(x, &D, &prec)) { case t_PADIC: y = ellinit_Qp(x, D, prec); break; case t_INTMOD: y = ellinit_Fp(x, D); break; case t_FFELT: y = ellinit_Fq(x, D); break; case t_FRAC: y = ellinit_Q(x, prec); break; case t_REAL: y = ellinit_Rg(x, 2, prec); break; case t_VEC: y = ellinit_nf(x, D); break; default: y = ellinit_Rg(x, 0, prec); } END: if (!y) { avma = av; return cgetg(1,t_VEC); } return gerepilecopy(av,y); } /********************************************************************/ /** **/ /** COORDINATE CHANGE **/ /** Apply [u,r,s,t]. All coordch_* functions update E[1..14] only **/ /** and copy E[15] (type-specific data), E[16] (dynamic data) **/ /** verbatim **/ /** **/ /********************************************************************/ /* [1,0,0,0] */ static GEN init_ch(void) { return mkvec4(gen_1,gen_0,gen_0,gen_0); } static int is_trivial_change(GEN v) { GEN u, r, s, t; if (typ(v) == t_INT) return 1; u = gel(v,1); r = gel(v,2); s = gel(v,3); t = gel(v,4); return isint1(u) && isintzero(r) && isintzero(s) && isintzero(t); } /* Accumulate the effects of variable changes w o v, where * w = [u,r,s,t], *vtotal = v = [U,R,S,T]. No assumption on types */ static void gcomposev(GEN *vtotal, GEN w) { GEN v = *vtotal; GEN U2, U, R, S, T, u, r, s, t; if (!v || typ(v) == t_INT) { *vtotal = w; return; } U = gel(v,1); R = gel(v,2); S = gel(v,3); T = gel(v,4); u = gel(w,1); r = gel(w,2); s = gel(w,3); t = gel(w,4); U2 = gsqr(U); gel(v,1) = gmul(U, u); gel(v,2) = gadd(R, gmul(U2, r)); gel(v,3) = gadd(S, gmul(U, s)); gel(v,4) = gadd(T, gmul(U2, gadd(gmul(U, t), gmul(S, r)))); } /* [u,r,s,t]^-1 = [ 1/u,-r/u^2,-s/u, (rs-t)/u^3 ] */ GEN ellchangeinvert(GEN w) { GEN u,r,s,t, u2,u3, U,R,S,T; if (typ(w) == t_INT) return w; u = gel(w,1); r = gel(w,2); s = gel(w,3); t = gel(w,4); u2 = gsqr(u); u3 = gmul(u2,u); U = ginv(u); R = gdiv(gneg(r), u2); S = gdiv(gneg(s), u); T = gdiv(gsub(gmul(r,s), t), u3); return mkvec4(U,R,S,T); } static GEN ell_to_nfell10(GEN e) { long i; GEN nf = ellnf_get_nf(e); GEN y = cgetg(11,t_VEC); for(i=1; i<=10; i++) gel(y, i) = nf_to_scalar_or_basis(nf, gel(e, i)); return y; } /* apply [u^(-1),0,0,0] */ static GEN nf_coordch_uinv(GEN nf, GEN e, GEN u) { GEN y, u2, u3, u4, u6, u8; long lx; if (gequal1(u)) return e; y = cgetg_copy(e, &lx); u2 = nfsqr(nf,u); u3 = nfmul(nf,u,u2); u4 = nfsqr(nf,u2); u6 = nfsqr(nf,u3); u8 = nfsqr(nf,u4); gel(y,1) = nfmul(nf,ell_get_a1(e), u); gel(y,2) = nfmul(nf,ell_get_a2(e), u2); gel(y,3) = nfmul(nf,ell_get_a3(e), u3); gel(y,4) = nfmul(nf,ell_get_a4(e), u4); gel(y,5) = nfmul(nf,ell_get_a6(e), u6); if (lx == 6) return y; gel(y,6) = nfmul(nf,ell_get_b2(e), u2); gel(y,7) = nfmul(nf,ell_get_b4(e), u4); gel(y,8) = nfmul(nf,ell_get_b6(e), u6); gel(y,9) = nfmul(nf,ell_get_b8(e), u8); return y; } /* apply [1,r,0,0] */ static GEN nf_coordch_r(GEN nf, GEN e, GEN r) { GEN a2, a4, b4, b6, y, p1, r2, b2r, rx3; long lx; if (gequal0(r)) return e; y = cgetg_copy(e, &lx); a2 = ell_get_a2(e); a4 = ell_get_a4(e); rx3 = gmulsg(3,r); gel(y,1) = ell_get_a1(e); /* A2 = a2 + 3r */ gel(y,2) = nfadd(nf,a2,rx3); /* A3 = a1 r + a3 */ gel(y,3) = nfadd(nf,ell_get_a3(e), nfmul(nf,ell_get_a1(e),r)); /* A4 = 3r^2 + 2a2 r + a4 */ gel(y,4) = nfadd(nf,a4, nfmul(nf,r,nfadd(nf,gmul2n(a2,1),rx3))); /* A6 = r^3 + a2 r^2 + a4 r + a6 */ gel(y,5) = nfadd(nf,ell_get_a6(e),nfmul(nf,r,nfadd(nf, a4, nfmul(nf,r,nfadd(nf,a2, r))))); if (lx == 6) return y; b4 = ell_get_b4(e); b6 = ell_get_b6(e); /* B2 = 12r + b2 */ gel(y,6) = nfadd(nf,ell_get_b2(e),gmul2n(rx3,2)); b2r = nfmul(nf,r, ell_get_b2(e)); r2 = nfsqr(nf,r); /* B4 = 6r^2 + b2 r + b4 */ gel(y,7) = nfadd(nf,b4,nfadd(nf,b2r, gmulsg(6,r2))); /* B6 = 4r^3 + 2b2 r^2 + 2b4 r + b6 */ gel(y,8) = nfadd(nf,b6,nfmul(nf,r,nfadd(nf,gmul2n(b4,1), nfadd(nf,b2r,gmul2n(r2,2))))); /* B8 = 3r^4 + b2 r^3 + 3b4 r^2 + 3b6 r + b8 */ p1 = nfadd(nf,gmulsg(3,b4),nfadd(nf,b2r, gmulsg(3,r2))); gel(y,9) = nfadd(nf,ell_get_b8(e), nfmul(nf,r,nfadd(nf,gmulsg(3,b6), nfmul(nf,r,p1)))); return y; } static GEN nf_coordch_s(GEN nf, GEN e, GEN s) { GEN a1, y; if (gequal0(s)) return e; a1 = ell_get_a1(e); y = leafcopy(e); /* A1 = a1 + 2s */ gel(y,1) = nfadd(nf,a1,gmul2n(s,1)); /* A2 = a2 - (a1 s + s^2) */ gel(y,2) = nfsub(nf,ell_get_a2(e),nfmul(nf,s,nfadd(nf,a1,s))); /* A4 = a4 - s a3 */ gel(y,4) = nfsub(nf,ell_get_a4(e),nfmul(nf,s,ell_get_a3(e))); return y; } /* apply [1,0,0,t] */ static GEN nf_coordch_t(GEN nf, GEN e, GEN t) { GEN a1, a3, y; if (gequal0(t)) return e; a1 = ell_get_a1(e); a3 = ell_get_a3(e); y = leafcopy(e); /* A3 = 2t + a3 */ gel(y,3) = nfadd(nf,a3, gmul2n(t,1)); /* A4 = a4 - a1 t */ gel(y,4) = nfsub(nf,ell_get_a4(e), nfmul(nf,t,a1)); /* A6 = a6 - t(t + a3) */ gel(y,5) = nfsub(nf,ell_get_a6(e), nfmul(nf,t,nfadd(nf,t, a3))); return y; } /* apply [1,0,s,t] */ static GEN nf_coordch_st(GEN nf, GEN e, GEN s, GEN t) { GEN y, a1, a3; if (gequal0(s)) return nf_coordch_t(nf, e, t); if (gequal0(t)) return nf_coordch_s(nf, e, s); a1 = ell_get_a1(e); a3 = ell_get_a3(e); y = leafcopy(e); /* A1 = a1 + 2s */ gel(y,1) = nfadd(nf,a1,gmul2n(s,1)); /* A2 = a2 - (a1 s + s^2) */ gel(y,2) = nfsub(nf,ell_get_a2(e),nfmul(nf,s,nfadd(nf,a1,s))); /* A3 = 2t + a3 */ gel(y,3) = nfadd(nf,a3,gmul2n(t,1)); /* A4 = a4 - (a1 t + s (2t + a3)) */ gel(y,4) = nfsub(nf,ell_get_a4(e),nfadd(nf,nfmul(nf,t,a1),nfmul(nf,s,gel(y,3)))); /* A6 = a6 - t(t + a3) */ gel(y,5) = nfsub(nf,ell_get_a6(e), nfmul(nf,t,nfadd(nf,t, a3))); return y; } static GEN nf_coordch_rt(GEN nf, GEN e, GEN r, GEN t) { e = nf_coordch_r(nf, e, r); return nf_coordch_t(nf, e, t); } /* apply [1,r,s,t] */ static GEN nf_coordch_rst(GEN nf, GEN e, GEN r, GEN s, GEN t) { e = nf_coordch_r(nf, e, r); return nf_coordch_st(nf, e, s, t); } /* apply w = [u,r,s,t] */ static GEN nf_coordch(GEN nf, GEN e, GEN w) { if (typ(w) == t_INT) return e; e = nf_coordch_rst(nf, e, gel(w,2), gel(w,3), gel(w,4)); return nf_coordch_uinv(nf, e, nfinv(nf, gel(w,1))); } /* apply [u^(-1),0,0,0] */ static GEN coordch_uinv(GEN e, GEN u) { GEN y, u2, u3, u4, u6, u12, D, c4, c6; long lx; if (gequal1(u)) return e; y = cgetg_copy(e, &lx); u2 = gsqr(u); u3 = gmul(u,u2); u4 = gsqr(u2); u6 = gsqr(u3); gel(y,1) = gmul(ell_get_a1(e), u); gel(y,2) = gmul(ell_get_a2(e), u2); gel(y,3) = gmul(ell_get_a3(e), u3); gel(y,4) = gmul(ell_get_a4(e), u4); gel(y,5) = gmul(ell_get_a6(e), u6); if (lx == 6) return y; gel(y,6) = gmul(ell_get_b2(e), u2); gel(y,7) = gmul(ell_get_b4(e), u4); gel(y,8) = gmul(ell_get_b6(e), u6); gel(y,9) = gmul(ell_get_b8(e), gsqr(u4)); u12 = gsqr(u6); D = ell_get_disc(e); c4 = ell_get_c4(e); c6 = ell_get_c6(e); c4 = gmul(c4, u4); c6 = gmul(c6, u6); D = gmul(D, u12); gel(y,10)= c4; gel(y,11)= c6; gel(y,12)= D; gel(y,13)= ell_get_j(e); gel(y,14)= gel(e,14); gel(y,15)= gel(e,15); gel(y,16)= gel(e,16); return y; } /* apply [1,r,0,0] */ static GEN coordch_r(GEN e, GEN r) { GEN a2, b4, b6, y, p1, r2, b2r, rx3; if (gequal0(r)) return e; y = leafcopy(e); a2 = ell_get_a2(e); rx3 = gmulsg(3,r); /* A2 = a2 + 3r */ gel(y,2) = gadd(a2,rx3); /* A3 = a1 r + a3 */ gel(y,3) = ec_h_evalx(e,r); /* A4 = 3r^2 + 2a2 r + a4 */ gel(y,4) = gadd(ell_get_a4(e), gmul(r,gadd(gmul2n(a2,1),rx3))); /* A6 = r^3 + a2 r^2 + a4 r + a6 */ gel(y,5) = ec_f_evalx(e,r); if (lg(y) == 6) return y; b4 = ell_get_b4(e); b6 = ell_get_b6(e); /* B2 = 12r + b2 */ gel(y,6) = gadd(ell_get_b2(e),gmul2n(rx3,2)); b2r = gmul(r, ell_get_b2(e)); r2 = gsqr(r); /* B4 = 6r^2 + b2 r + b4 */ gel(y,7) = gadd(b4,gadd(b2r, gmulsg(6,r2))); /* B6 = 4r^3 + 2b2 r^2 + 2b4 r + b6 */ gel(y,8) = gadd(b6,gmul(r,gadd(gmul2n(b4,1), gadd(b2r,gmul2n(r2,2))))); /* B8 = 3r^4 + b2 r^3 + 3b4 r^2 + 3b6 r + b8 */ p1 = gadd(gmulsg(3,b4),gadd(b2r, gmulsg(3,r2))); gel(y,9) = gadd(ell_get_b8(e), gmul(r,gadd(gmulsg(3,b6), gmul(r,p1)))); return y; } /* apply [1,0,s,0] */ static GEN coordch_s(GEN e, GEN s) { GEN a1, y; if (gequal0(s)) return e; a1 = ell_get_a1(e); y = leafcopy(e); /* A1 = a1 + 2s */ gel(y,1) = gadd(a1,gmul2n(s,1)); /* A2 = a2 - (a1 s + s^2) */ gel(y,2) = gsub(ell_get_a2(e),gmul(s,gadd(a1,s))); /* A4 = a4 - s a3 */ gel(y,4) = gsub(ell_get_a4(e),gmul(s,ell_get_a3(e))); return y; } /* apply [1,0,0,t] */ static GEN coordch_t(GEN e, GEN t) { GEN a1, a3, y; if (gequal0(t)) return e; a1 = ell_get_a1(e); a3 = ell_get_a3(e); y = leafcopy(e); /* A3 = 2t + a3 */ gel(y,3) = gadd(a3, gmul2n(t,1)); /* A4 = a4 - a1 t */ gel(y,4) = gsub(ell_get_a4(e), gmul(t,a1)); /* A6 = a6 - t(t + a3) */ gel(y,5) = gsub(ell_get_a6(e), gmul(t,gadd(t, a3))); return y; } /* apply [1,0,s,t] */ static GEN coordch_st(GEN e, GEN s, GEN t) { GEN y, a1, a3; if (gequal0(s)) return coordch_t(e, t); if (gequal0(t)) return coordch_s(e, s); a1 = ell_get_a1(e); a3 = ell_get_a3(e); y = leafcopy(e); /* A1 = a1 + 2s */ gel(y,1) = gadd(a1,gmul2n(s,1)); /* A2 = a2 - (a1 s + s^2) */ gel(y,2) = gsub(ell_get_a2(e),gmul(s,gadd(a1,s))); /* A3 = 2t + a3 */ gel(y,3) = gadd(a3,gmul2n(t,1)); /* A4 = a4 - (a1 t + s (2t + a3)) */ gel(y,4) = gsub(ell_get_a4(e),gadd(gmul(t,a1),gmul(s,gel(y,3)))); /* A6 = a6 - t(t + a3) */ gel(y,5) = gsub(ell_get_a6(e), gmul(t,gadd(t, a3))); return y; } /* apply [1,r,s,t] */ static GEN coordch_rst(GEN e, GEN r, GEN s, GEN t) { e = coordch_r(e, r); return coordch_st(e, s, t); } /* apply w = [u,r,s,t] */ static GEN coordch(GEN e, GEN w) { if (typ(w) == t_INT) return e; e = coordch_rst(e, gel(w,2), gel(w,3), gel(w,4)); return coordch_uinv(e, ginv(gel(w,1))); } /* the ch_* routines update E[14] (type), E[15] (type specific data), E[16] * (dynamic data) */ static GEN ch_Qp(GEN E, GEN e, GEN w) { GEN S, p = ellQp_get_zero(E), u2 = NULL, u = gel(w,1), r = gel(w,2); long prec = valp(p); if (base_ring(E, &p, &prec) != t_PADIC) return ellinit(E, p, prec); if ((S = obj_check(e, Qp_ROOT))) { if (!u2) u2 = gsqr(u); obj_insert_shallow(E, Qp_ROOT, gdiv(gsub(S, r), u2)); } if ((S = obj_check(e, Qp_TATE))) { GEN U2 = gel(S,1), U = gel(S,2), Q = gel(S,3), AB = gel(S,4), L = gel(S,5); if (!u2) u2 = gsqr(u); U2 = gmul(U2, u2); U = gmul(U, u); AB = gdiv(AB, u2); obj_insert_shallow(E, Qp_TATE, mkvec5(U2,U,Q,AB,L)); } return E; } /* common to Q and Rg */ static GEN ch_R(GEN E, GEN e, GEN w) { GEN S, u = gel(w,1), r = gel(w,2); if ((S = obj_check(e, R_PERIODS))) obj_insert_shallow(E, R_PERIODS, gmul(S, u)); if ((S = obj_check(e, R_ETA))) obj_insert_shallow(E, R_ETA, gmul(S, u)); if ((S = obj_check(e, R_ROOTS))) { GEN ro = cgetg(4, t_VEC), u2 = gsqr(u); long i; for (i = 1; i <= 3; i++) gel(ro,i) = gdiv(gsub(gel(S,i), r), u2); obj_insert_shallow(E, R_ROOTS, ro); } return E; } static GEN ch_Rg(GEN E, GEN e, GEN w) { GEN p = NULL; long prec = ellR_get_prec(E); if (base_ring(E, &p, &prec) != t_REAL) return ellinit(E, p, prec); ch_R(E, e, w); return E; } static GEN ch_Q(GEN E, GEN e, GEN w) { long prec = ellR_get_prec(E); GEN S, v = NULL, p = NULL; if (base_ring(E, &p, &prec) != t_FRAC) return ellinit(E, p, prec); ch_R(E, e, w); if ((S = obj_check(e, Q_GROUPGEN))) S = obj_insert_shallow(E, Q_GROUPGEN, ellchangepoint(S, w)); if ((S = obj_check(e, Q_MINIMALMODEL))) { if (lg(S) == 2) { /* model was minimal */ if (!is_trivial_change(w)) /* no longer minimal */ S = mkvec3(gel(S,1), ellchangeinvert(w), e); (void)obj_insert_shallow(E, Q_MINIMALMODEL, S); } else { v = gel(S,2); if (gequal(v, w) || (is_trivial_change(v) && is_trivial_change(w))) S = mkvec(gel(S,1)); /* now minimal */ else { w = ellchangeinvert(w); gcomposev(&w, v); v = w; S = leafcopy(S); /* don't modify S in place: would corrupt e */ gel(S,2) = v; } (void)obj_insert_shallow(E, Q_MINIMALMODEL, S); } } if ((S = obj_check(e, Q_GLOBALRED))) S = obj_insert_shallow(E, Q_GLOBALRED, S); if ((S = obj_check(e, Q_ROOTNO))) S = obj_insert_shallow(E, Q_ROOTNO, S); return E; } static void ch_FF(GEN E, GEN e, GEN w) { GEN S; if ((S = obj_check(e, FF_CARD))) S = obj_insert_shallow(E, FF_CARD, S); if ((S = obj_check(e, FF_GROUP))) S = obj_insert_shallow(E, FF_GROUP, S); if ((S = obj_check(e, FF_GROUPGEN))) S = obj_insert_shallow(E, FF_GROUPGEN, ellchangepoint(S, w)); if ((S = obj_check(e, FF_O))) S = obj_insert_shallow(E, FF_O, S); } /* FF_CARD, FF_GROUP, FF_O are invariant */ static GEN ch_Fp(GEN E, GEN e, GEN w) { long prec = 0; GEN p = ellff_get_field(E); if (base_ring(E, &p, &prec) != t_INTMOD) return ellinit(E, p, prec); gel(E,15) = mkvec2(p, ell_to_a4a6_bc(E, p)); ch_FF(E, e, w); return E; } static GEN ch_Fq(GEN E, GEN e, GEN w) { long prec = 0; GEN p = ellff_get_field(E); if (base_ring(E, &p, &prec) != t_FFELT) return ellinit(E, p, prec); gel(E,15) = FF_elldata(E, p); ch_FF(E, e, w); return E; } static void ell_reset(GEN E) { gel(E,16) = zerovec(lg(gel(E,16))-1); } GEN ellchangecurve(GEN e, GEN w) { pari_sp av = avma; GEN E; checkell5(e); if (equali1(w)) return gcopy(e); checkcoordch(w); E = coordch(leafcopy(e), w); if (lg(E) != 6) { ell_reset(E); switch(ell_get_type(E)) { case t_ELL_Qp: E = ch_Qp(E,e,w); break; case t_ELL_Fp: E = ch_Fp(E,e,w); break; case t_ELL_Fq: E = ch_Fq(E,e,w); break; case t_ELL_Q: E = ch_Q(E,e,w); break; case t_ELL_Rg: E = ch_Rg(E,e,w); break; } } return gerepilecopy(av, E); } /* v o= [1,r,0,0] */ static void nf_compose_r(GEN nf, GEN *vtotal, GEN *e, GEN r) { GEN v = *vtotal; GEN U2, R, S, T; if (gequal0(r)) return; *e = nf_coordch_r(nf, *e,r); U2 = nfsqr(nf,gel(v,1)); R = gel(v,2); S = gel(v, 3); T = gel(v, 4); gel(v,2) = nfadd(nf,R, nfmul(nf,U2, r)); gel(v,4) = nfadd(nf,T, nfmul(nf,U2, nfmul(nf,S, r))); } /* v o= [1,0,s,0]; never used for s = 0 */ static void nf_compose_s(GEN nf, GEN *vtotal, GEN *e, GEN s) { GEN v = *vtotal; GEN U, S; *e = nf_coordch_s(nf,*e,s); U = gel(v,1); S = gel(v,3); gel(v,3) = nfadd(nf, S, nfmul(nf, U, s)); } /* v o= [1,0,0,t] */ static void nf_compose_t(GEN nf ,GEN *vtotal, GEN *e, GEN t) { GEN v = *vtotal; GEN U3, U, T; if (gequal0(t)) return; *e = nf_coordch_t(nf,*e,t); U = gel(v,1); U3 = nfmul(nf,U, nfsqr(nf,U)); T = gel(v,4); gel(v,4) = nfadd(nf,T, nfmul(nf,U3, t)); } /* v o= [1,r,0,t] */ static void nf_compose_rt(GEN nf, GEN *vtotal, GEN *e, GEN r, GEN t) { GEN v = *vtotal; GEN U2, U, R, S, T; if (gequal0(t)) { nf_compose_r(nf, vtotal, e, r); return; } *e = nf_coordch_rt(nf,*e,r,t); U = gel(v,1); R = gel(v,2); S = gel(v,3); T = gel(v,4); U2 = nfsqr(nf,U); gel(v,2) = nfadd(nf,R, nfmul(nf,U2, r)); gel(v,4) = nfadd(nf,T, nfmul(nf,U2, nfadd(nf,nfmul(nf,U, t), nfmul(nf,S, r)))); } /* v o= [1,0,s,t] */ static void nf_compose_st(GEN nf, GEN *vtotal, GEN *e, GEN s, GEN t) { GEN v = *vtotal; GEN U3, U, S, T; if (gequal0(s)) { nf_compose_t(nf, vtotal, e, t); return; } if (gequal0(t)) { nf_compose_s(nf, vtotal, e, s); return; } *e = nf_coordch_st(nf, *e,s,t); U = gel(v,1); U3 = nfmul(nf,U,nfsqr(nf,U)); S = gel(v,3); T = gel(v,4); gel(v,3) = nfadd(nf, S, nfmul(nf,U, s)); gel(v,4) = nfadd(nf, T, nfmul(nf,U3, t)); } /* v o= [u,0,0,0] */ static void nf_compose_u(GEN nf, GEN *vtotal, GEN *e, GEN u, GEN uinv) { GEN v = *vtotal; *e = nf_coordch_uinv(nf, *e,uinv); gel(v,1) = nfmul(nf,gel(v,1), u); } /* X = (x-r)/u^2 * Y = (y - s(x-r) - t) / u^3 */ static GEN ellchangepoint0(GEN P, GEN v2, GEN v3, GEN r, GEN s, GEN t) { GEN a, x, y; if (ell_is_inf(P)) return P; x = gel(P,1); y = gel(P,2); a = gsub(x,r); retmkvec2(gmul(v2, a), gmul(v3, gsub(y, gadd(gmul(s,a),t)))); } GEN ellchangepoint(GEN x, GEN ch) { GEN y, v, v2, v3, r, s, t, u; long tx, i, lx = lg(x); pari_sp av = avma; if (typ(x) != t_VEC) pari_err_TYPE("ellchangepoint",x); if (equali1(ch)) return gcopy(x); checkcoordch(ch); if (lx == 1) return cgetg(1, t_VEC); u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); v = ginv(u); v2 = gsqr(v); v3 = gmul(v,v2); tx = typ(gel(x,1)); if (is_matvec_t(tx)) { y = cgetg(lx,tx); for (i=1; i t = 3 iff * v4 = 6, v6 = 9 and vD >= 18. Total net effect is * v4 += 2v(d2) - 4t, v6 += 3v(d2) - 6t, vD += 6 v(d2) - 12t * After rescaling in get_u (c4 >>= 4t, c6 >>= 6t) we need * c6 % 4 = 3 OR (v4 >= 4 AND (v6 >= 5 or c6 % 32 = 8)) */ static long twist2(GEN c4, GEN c6, GEN disc, long vg) { /* v4 >= 4, v6 >= 3 (and c6 = 0,8 mod 32). After twist + minimization, * either same condition OR v(C4) = 0, C6 = 0,3 mod 4 */ long v4, v6, vD; if (vg == 18) /* v4=6, v6=9, vD>=18; only case with t = 3 */ return (umodi2n(c6, 11)>>9) == 1 ? -8: 8; /* need C6 % 4 = 3 */ /* 100 = oo, any number >= 8 would do */ v4 = signe(c4)? vali(c4): 100; if (v4 == 5) return 1; /* 100 = oo, any number > 9 would do */ v6 = signe(c6)? vali(c6): 100; if (v6 == 7) return 1; /* handle case v(DISC) = 0 or v(C4) = 0 after twist, only case with d2 = -4 */ if (vg == 12 && ((v4==4 && v6==6) || (v4>=8 && v6==9))) return -4; /* Now, d2 = 1 OR v(d2) = 3, t = 2 => v4 -= 2, v6 -= 3, vD -= 6 */ if (v4 < 6 || v6 < 6) return 1; /* v(C4) >= 4, v(C6) >= 3 */ vD = vali(disc); if (v6==6 && vD==6 && (umodi2n(c6,8)>>6) == 1) return 8; /* C6 % 32 = 8 */ return -8; } /* Return D such that E_D has minimal discriminant. It also has minimal conductor in Z[1/2] */ GEN ellminimaltwist(GEN e) { pari_sp av = avma; GEN c4, c6, disc, g, N, M, F, E, D = gen_1; long i, lF; checkell_Q(e); E = ellminimalmodel(e, NULL); c4 = ell_get_c4(E); c6 = ell_get_c6(E); disc = ell_get_disc(E); g = gcdii(disc, sqri(c6)); ellQ_get_Nfa(E, &N, &M); F = gel(M, 1); lF = lg(F); /* on twist by d, (c4,c6,D,g) -> (d^2 c4, d^3 c6, d^6 D, d^6 g), * then apply get_u(). Since model is minimal, v(g) < 12 unless p=3 and * v(g) < 14 or p = 2 and v(g) <= 18 */ for(i = 1; i < lF; i++) { GEN p = gel(F, i); long vg = Z_pval(g,p), d2; if (vg < 6) continue; /* twist by fund. discriminant d2; in get_u, we have v(g) = vg + 6*v(d2) */ switch(itou_or_0(p)) { default: /* p > 3, 6 <= v(g) < 12 => v(D) -= 6 */ D = mulii(D, (mod4(p)==1)? p: negi(p)); break; case 3: /* bad case: v(final_c6) = 2 => no reduction; else v(D) -= 6 */ if (safe_Z_lval(c6,3) != 5) D = mulis(D, -3); break; case 2: d2 = twist2(c4,c6,disc,vg); if (d2 != 1) D = mulis(D,d2); break; } } obj_free(E); return gerepileuptoleaf(av, D); } /* Reference: William A. Stein and Mark Watkins A Database of Elliptic Curves-First Report ANTS 5 */ static GEN localred_23(GEN e, long p); GEN ellminimaltwistcond(GEN e) { pari_sp av = avma; GEN D = ellminimaltwist(e); GEN eD = ellinit(elltwist(e, D), NULL, DEFAULTPREC); GEN R = localred_23(ellintegralmodel_i(eD,NULL), 2); long f = itos(gel(R,1)), v = vali(D); if (f==4) D = negi(v==3 ? D: shifti(D, v==0? 2: -2)); else if (f==6) { long s, t; if (v < 3) s = v==0? 3: 1; else { t = (v==3 && mod32(D) == 8)? 1: -1; s = signe(D)==t ? -3: -1; } D = shifti(D, s); } return gerepileuptoleaf(av, D); } GEN ellminimaltwist0(GEN e, long flag) { switch(flag) { case 0: return ellminimaltwist(e); case 1: return ellminimaltwistcond(e); } pari_err_FLAG("ellminimaltwist"); return NULL; /* LCOV_EXCL_LINE */ } static long ellexpo(GEN E) { long i, f, e = -(long)HIGHEXPOBIT; for (i=1; i<=5; i++) { f = gexpo(gel(E,i)); if (f > e) e = f; } return e; } /* Exactness of lhs and rhs in the following depends in non-obvious ways * on the coeffs of the curve as well as on the components of the point z. * Thus if e is exact, with a1==0, and z has exact y coordinate only, the * lhs will be exact but the rhs won't. */ int oncurve(GEN e, GEN z) { GEN LHS, RHS, x; long pl, pr, ex, expx; pari_sp av; checkellpt(z); if (ell_is_inf(z)) return 1; /* oo */ if (ell_get_type(e) == t_ELL_NF) z = nfVtoalg(ellnf_get_nf(e), z); av = avma; LHS = ec_LHS_evalQ(e,z); RHS = ec_f_evalx(e,gel(z,1)); x = gsub(LHS,RHS); if (gequal0(x)) { avma = av; return 1; } pl = precision(LHS); pr = precision(RHS); if (!pl && !pr) { avma = av; return 0; } /* both of LHS, RHS are exact */ /* at least one of LHS,RHS is inexact */ ex = pr? gexpo(RHS): gexpo(LHS); /* don't take exponent of exact 0 */ if (!pr || (pl && pl < pr)) pr = pl; /* min among nonzero elts of {pl,pr} */ expx = gexpo(x); pr = (expx < ex - prec2nbits(pr) + 15 || expx < ellexpo(e) - prec2nbits(pr) + 5); avma = av; return pr; } GEN ellisoncurve(GEN e, GEN x) { long i, tx = typ(x), lx; checkell(e); if (!is_vec_t(tx)) pari_err_TYPE("ellisoncurve [point]", x); lx = lg(x); if (lx==1) return cgetg(1,tx); tx = typ(gel(x,1)); if (is_vec_t(tx)) { GEN z = cgetg(lx,tx); for (i=1; i= gexpo(y1)); else eq = gequal(y1,y2); if (!eq) return NULL; } dx = ec_dmFdy_evalQ(e,mkvec2(x,y1)); if (gequal0(dx)) return NULL; dy = gadd(gsub(ell_get_a4(e),gmul(ell_get_a1(e),y1)), gmul(x,gadd(gmul2n(ell_get_a2(e),1),gmulsg(3,x)))); return gdiv(dy,dx); } GEN elladd(GEN e, GEN z1, GEN z2) { GEN s, z, x, y, x1, x2, y1, y2; pari_sp av = avma; checkell(e); checkellpt(z1); checkellpt(z2); if (ell_is_inf(z1)) return gcopy(z2); if (ell_is_inf(z2)) return gcopy(z1); x1 = gel(z1,1); y1 = gel(z1,2); x2 = gel(z2,1); y2 = gel(z2,2); if (ell_get_type(e) == t_ELL_NF) { GEN nf = ellnf_get_nf(e); x1 = nftoalg(nf, x1); x2 = nftoalg(nf, x2); y1 = nftoalg(nf, y1); y2 = nftoalg(nf, y2); } if (cx_approx_equal(x1,x2)) { s = slope_samex(e, x1, y1, y2); if (!s) { avma = av; return ellinf(); } } else s = gdiv(gsub(y2,y1), gsub(x2,x1)); x = gsub(gmul(s,gadd(s,ell_get_a1(e))), gadd(gadd(x1,x2),ell_get_a2(e))); y = gadd(gadd(y1, ec_h_evalx(e,x)), gmul(s,gsub(x,x1))); z = cgetg(3,t_VEC); gel(z,1) = gcopy(x); gel(z,2) = gneg(y); return gerepileupto(av, z); } static GEN ellneg_i(GEN e, GEN z) { GEN t, x, y; if (ell_is_inf(z)) return z; x = gel(z,1); y = gel(z,2); if (ell_get_type(e) == t_ELL_NF) { GEN nf = ellnf_get_nf(e); x = nftoalg(nf,x); y = nftoalg(nf,y); } t = cgetg(3,t_VEC); gel(t,1) = x; gel(t,2) = gneg_i(gadd(y, ec_h_evalx(e,x))); return t; } GEN ellneg(GEN e, GEN z) { pari_sp av; GEN t, y; checkell(e); checkellpt(z); if (ell_is_inf(z)) return z; t = cgetg(3,t_VEC); gel(t,1) = gcopy(gel(z,1)); av = avma; y = gneg(gadd(gel(z,2), ec_h_evalx(e,gel(z,1)))); gel(t,2) = gerepileupto(av, y); return t; } GEN ellsub(GEN e, GEN z1, GEN z2) { pari_sp av = avma; checkell(e); checkellpt(z2); return gerepileupto(av, elladd(e, z1, ellneg_i(e,z2))); } /* E an ell, x a scalar */ static GEN ellordinate_i(GEN E, GEN x, long prec) { pari_sp av = avma; GEN a, b, D, d, y, p, nf = NULL; if (ell_get_type(E) == t_ELL_NF) { nf = ellnf_get_nf(E); x = nftoalg(nf,x); } a = ec_f_evalx(E,x); b = ec_h_evalx(E,x); D = gadd(gsqr(b), gmul2n(a,2)); /* solve y*(y+b) = a */ if (gequal0(D)) { if (ell_get_type(E) == t_ELL_Fq && absequaliu(ellff_get_p(E),2)) retmkvec( FF_sqrt(a) ); b = gneg_i(b); y = cgetg(2,t_VEC); gel(y,1) = gmul2n(b,-1); return gerepileupto(av,y); } /* D != 0 */ switch(ell_get_type(E)) { case t_ELL_Fp: /* imply p!=2 */ p = ellff_get_p(E); D = gel(D,2); if (kronecker(D, p) < 0) { avma = av; return cgetg(1,t_VEC); } d = Fp_sqrt(D, p); break; case t_ELL_Fq: if (absequaliu(ellff_get_p(E),2)) { GEN F = FFX_roots(mkpoln(3, gen_1, b, a), D); if (lg(F) == 1) { avma = av; return cgetg(1,t_VEC); } return gerepileupto(av, F); } if (!FF_issquareall(D,&d)) { avma = av; return cgetg(1,t_VEC); } break; case t_ELL_Q: if (typ(x) == t_COMPLEX) { d = gsqrt(D, prec); break; } if (!issquareall(D,&d)) { avma = av; return cgetg(1,t_VEC); } break; case t_ELL_NF: { GEN T = mkpoln(3, gen_1, gen_0, gneg(D)); setvarn(T, fetch_var_higher()); d = nfroots(nf, T); delete_var(); if (lg(d) == 1) { avma = av; return cgetg(1, t_VEC); } d = gel(d,1); break; } case t_ELL_Qp: p = ellQp_get_p(E); D = cvtop(D, p, ellQp_get_prec(E)); if (!issquare(D)) { avma = av; return cgetg(1,t_VEC); } d = Qp_sqrt(D); break; default: d = gsqrt(D,prec); } a = gsub(d,b); y = cgetg(3,t_VEC); gel(y,1) = gmul2n(a, -1); gel(y,2) = gsub(gel(y,1),d); return gerepileupto(av,y); } GEN ellordinate(GEN e, GEN x, long prec) { checkell(e); if (is_matvec_t(typ(x))) { long i, lx; GEN v = cgetg_copy(x, &lx); for (i=1; i>1)-4)>>2; z1 = ellwpseries(e, 0, ln); z2 = ser_unscale(z1, n); p0 = gen_0; p1 = gen_1; q0 = gen_1; q1 = gen_0; do { GEN p2,q2, ss = gen_0; do { long ep = (-valp(z2)) >> 1; ss = gadd(ss, gmul(gel(z2,2), pol_xnall(ep, 0))); z2 = gsub(z2, gmul(gel(z2,2), gpowgs(z1, ep))); } while (valp(z2) <= 0); p2 = gadd(p0, gmul(ss,p1)); p0 = p1; p1 = p2; q2 = gadd(q0, gmul(ss,q1)); q0 = q1; q1 = q2; if (!signe(z2)) break; z2 = ginv(z2); } while (degpol(p1) < vn); if (degpol(p1) > vn || signe(z2)) pari_err_TYPE("ellmul [not a complex multiplication]", n); q1p = RgX_deriv(q1); b2ov12 = gdivgs(ell_get_b2(e), 12); grdx = gadd(gel(P,1), b2ov12); /* x(P) + b2/12 */ q1 = poleval(q1, grdx); if (gequal0(q1)) return ellinf(); p1p = RgX_deriv(p1); p1 = poleval(p1, grdx); p1p = poleval(p1p, grdx); q1p = poleval(q1p, grdx); x = gdiv(p1,q1); y = gdiv(gsub(gmul(p1p,q1), gmul(p1,q1p)), gmul(n,gsqr(q1))); x = gsub(x, b2ov12); y = gsub( gmul(ec_dmFdy_evalQ(e,P), y), ec_h_evalx(e,x)); return mkvec2(x, gmul2n(y,-1)); } static GEN _sqr(void *e, GEN x) { return elladd((GEN)e, x, x); } static GEN _mul(void *e, GEN x, GEN y) { return elladd((GEN)e, x, y); } static GEN ellffmul(GEN E, GEN P, GEN n) { GEN fg = ellff_get_field(E); if (typ(fg)==t_FFELT) return FF_ellmul(E, P, n); else { pari_sp av = avma; GEN p = fg, e = ellff_get_a4a6(E), Q; GEN Pp = FpE_changepointinv(RgE_to_FpE(P, p), gel(e,3), p); GEN Qp = FpE_mul(Pp, n, gel(e,1), p); Q = FpE_to_mod(FpE_changepoint(Qp, gel(e,3), p), p); return gerepileupto(av, Q); } } /* [n] z, n integral */ static GEN ellmul_Z(GEN e, GEN z, GEN n) { long s; if (ell_is_inf(z)) return ellinf(); if (ell_over_Fq(e)) return ellffmul(e,z,n); s = signe(n); if (!s) return ellinf(); if (s < 0) z = ellneg_i(e,z); if (is_pm1(n)) return z; return gen_pow(z, n, (void*)e, &_sqr, &_mul); } /* x a t_REAL, try to round it to an integer */ enum { OK, LOW_PREC, NO }; static long myroundr(GEN *px) { GEN x = *px; long e; if (bit_prec(x) - expo(x) < 5) return LOW_PREC; *px = grndtoi(x, &e); if (e >= -5) return NO; return OK; } /* E has CM by Q, t_COMPLEX or t_QUAD. Return q such that E has CM by Q/q * or gen_1 (couldn't find q > 1) * or NULL (doesn't have CM by Q) */ static GEN CM_factor(GEN E, GEN Q) { GEN w, tau, D, v, x, y, F, dF, q, r, fk, fkb, fkc; long prec; if (ell_get_type(E) != t_ELL_Q) return gen_1; switch(typ(Q)) { case t_COMPLEX: D = utoineg(4); v = gel(Q,2); break; case t_QUAD: D = quad_disc(Q); v = gel(Q,3); break; default: return NULL; /*-Wall*/ } /* disc Q = v^2 D, D < 0 fundamental */ w = ellR_omega(E, DEFAULTPREC + nbits2nlong(expi(D))); tau = gdiv(gel(w,2), gel(w,1)); prec = precision(tau); /* disc tau = -4 k^2 (Im tau)^2 for some integral k * Assuming that E has CM by Q, then disc Q / disc tau = f^2 is a square. * Compute f*k */ x = gel(tau,1); y = gel(tau,2); /* tau = x + Iy */ fk = gmul(gdiv(v, gmul2n(y, 1)), sqrtr_abs(itor(D, prec))); switch(myroundr(&fk)) { case NO: return NULL; case LOW_PREC: return gen_1; } fk = absi_shallow(fk); fkb = gmul(fk, gmul2n(x,1)); switch(myroundr(&fkb)) { case NO: return NULL; case LOW_PREC: return gen_1; } fkc = gmul(fk, cxnorm(tau)); switch(myroundr(&fkc)) { case NO: return NULL; case LOW_PREC: return gen_1; } /* tau is a root of fk (X^2 - b X + c) \in Z[X], */ F = Q_primpart(mkvec3(fk, fkb, fkc)); dF = qfb_disc(F); /* = disc tau, E has CM by orders of disc dF q^2, all q */ q = dvmdii(dF, D, &r); if (r != gen_0 || !Z_issquareall(q, &q)) return NULL; /* disc(Q) = disc(tau) (v / q)^2 */ v = dvmdii(absi_shallow(v), q, &r); if (r != gen_0) return NULL; return is_pm1(v)? gen_1: v; /* E has CM by Q/q: [Q] = [q] o [Q/q] */ } /* [a + w] z, a integral, w pure imaginary */ static GEN ellmul_CM_aux(GEN e, GEN z, GEN a, GEN w) { GEN A, B, q; if (typ(a) != t_INT) pari_err_TYPE("ellmul_Z",a); q = CM_factor(e, w); if (!q) pari_err_TYPE("ellmul [not a complex multiplication]",w); if (q != gen_1) w = gdiv(w, q); /* compute [a + q w] z, z has CM by w */ if (typ(w) == t_QUAD && is_pm1(gel(gel(w,1), 3))) { /* replace w by w - u, u in Z, so that N(w-u) is minimal * N(w - u) = N w - Tr w u + u^2, minimal for u = Tr w / 2 */ GEN u = gtrace(w); if (typ(u) != t_INT) pari_err_TYPE("ellmul_CM",w); u = shifti(u, -1); if (signe(u)) { w = gsub(w, u); a = addii(a, mulii(q,u)); } /* [a + w]z = [(a + qu)] z + [q] [(w - u)] z */ } A = ellmul_Z(e,z,a); B = ellmul_CM(e,z,w); if (q != gen_1) B = ellmul_Z(e, B, q); return elladd(e, A, B); } GEN ellmul(GEN e, GEN z, GEN n) { pari_sp av = avma; checkell(e); checkellpt(z); if (ell_is_inf(z)) return ellinf(); switch(typ(n)) { case t_INT: return gerepilecopy(av, ellmul_Z(e,z,n)); case t_QUAD: { GEN pol = gel(n,1), a = gel(n,2), b = gel(n,3); if (signe(gel(pol,2)) < 0) pari_err_TYPE("ellmul_CM",n); /* disc > 0 ? */ return gerepileupto(av, ellmul_CM_aux(e,z,a,mkquad(pol, gen_0,b))); } case t_COMPLEX: { GEN a = gel(n,1), b = gel(n,2); return gerepileupto(av, ellmul_CM_aux(e,z,a,mkcomplex(gen_0,b))); } } pari_err_TYPE("ellmul (non integral, non CM exponent)",n); return NULL; /* LCOV_EXCL_LINE */ } /********************************************************************/ /** **/ /** Periods **/ /** **/ /********************************************************************/ /* References: The complex AGM, periods of elliptic curves over C and complex elliptic logarithms John E. Cremona, Thotsaphon Thongjunthug, arXiv:1011.0914 */ static GEN ellomega_agm(GEN a, GEN b, GEN c, long prec) { GEN pi = mppi(prec), mIpi = mkcomplex(gen_0, negr(pi)); GEN Mac = agm(a,c,prec), Mbc = agm(b,c,prec); retmkvec2(gdiv(pi, Mac), gdiv(mIpi, Mbc)); } static GEN ellomega_cx(GEN E, long prec) { pari_sp av = avma; GEN roots = ellR_roots(E,prec); GEN d1=gel(roots,4), d2=gel(roots,5), d3=gel(roots,6); GEN a = gsqrt(d3,prec), b = gsqrt(d1,prec), c = gsqrt(d2,prec); return gerepileupto(av, ellomega_agm(a,b,c,prec)); } /* return [w1,w2] for E / R; w1 > 0 is real. * If e.disc > 0, w2 = -I r; else w2 = w1/2 - I r, for some real r > 0. * => tau = w1/w2 is in upper half plane */ static GEN doellR_omega(GEN E, long prec) { pari_sp av = avma; GEN roots, d2, z, a, b, c; if (ellR_get_sign(E) >= 0) return ellomega_cx(E,prec); roots = ellR_roots(E,prec); d2 = gel(roots,5); z = gsqrt(d2,prec); /* imag(e1-e3) > 0, so that b > 0*/ a = gel(z,1); /* >= 0 */ b = gel(z,2); c = gabs(z, prec); z = ellomega_agm(a,b,c,prec); return gerepilecopy(av, mkvec2(gel(z,1),gmul2n(gadd(gel(z,1),gel(z,2)),-1))); } static GEN doellR_eta(GEN E, long prec) { GEN w = ellR_omega(E, prec); return elleta(w, prec); } GEN ellR_omega(GEN E, long prec) { return obj_checkbuild_realprec(E, R_PERIODS, &doellR_omega, prec); } GEN ellR_eta(GEN E, long prec) { return obj_checkbuild_realprec(E, R_ETA, &doellR_eta, prec); } GEN ellR_roots(GEN E, long prec) { return obj_checkbuild_realprec(E, R_ROOTS, &doellR_roots, prec); } GEN ellR_area(GEN E, long prec) { pari_sp av = avma; GEN w, w1, w2, a,b,c,d; w = ellR_omega(E, prec); w1 = gel(w,1); a = real_i(w1); b = imag_i(w1); w2 = gel(w,2); c = real_i(w2); d = imag_i(w2); return gerepileupto(av, gabs(gsub(gmul(a,d),gmul(b,c)), prec)); } /********************************************************************/ /** **/ /** ELLIPTIC FUNCTIONS **/ /** **/ /********************************************************************/ /* P = [x,0] is 2-torsion on y^2 = g(x). Return w1/2, (w1+w2)/2, or w2/2 * depending on whether x is closest to e1,e2, or e3, the 3 complex root of g */ static GEN zell_closest_0(GEN om, GEN x, GEN ro) { GEN e1 = gel(ro,1), e2 = gel(ro,2), e3 = gel(ro,3); GEN d1 = gnorm(gsub(x,e1)); GEN d2 = gnorm(gsub(x,e2)); GEN d3 = gnorm(gsub(x,e3)); GEN z = gel(om,2); if (gcmp(d1, d2) <= 0) { if (gcmp(d1, d3) <= 0) z = gel(om,1); } else { if (gcmp(d2, d3)<=0) z = gadd(gel(om,1),gel(om,2)); } return gmul2n(z, -1); } static GEN zellcx(GEN E, GEN P, long prec) { GEN R = ellR_roots(E, prec+EXTRAPRECWORD); GEN x0 = gel(P,1), y0 = ec_dmFdy_evalQ(E,P); if (gequal0(y0)) return zell_closest_0(ellomega_cx(E,prec),x0,R); else { GEN e2 = gel(R,2), e3 = gel(R,3), d2 = gel(R,5), d3 = gel(R,6); GEN a = gsqrt(d2,prec), b = gsqrt(d3,prec); GEN r = gsqrt(gdiv(gsub(x0,e3), gsub(x0,e2)),prec); GEN t = gdiv(gneg(y0), gmul2n(gmul(r,gsub(x0,e2)),1)); GEN ar = real_i(a), br = real_i(b), ai = imag_i(a), bi = imag_i(b); /* |a+b| < |a-b| */ if (gcmp(gmul(ar,br), gneg(gmul(ai,bi))) < 0) b = gneg(b); return zellagmcx(a,b,r,t,prec); } } /* Assume E/R, disc E < 0, and P \in E(R) ==> z \in R */ static GEN zellrealneg(GEN E, GEN P, long prec) { GEN x0 = gel(P,1), y0 = ec_dmFdy_evalQ(E,P); if (gequal0(y0)) return gmul2n(gel(ellR_omega(E,prec),1),-1); else { GEN R = ellR_roots(E, prec+EXTRAPRECWORD); GEN d2 = gel(R,5), e3 = gel(R,3); GEN a = gsqrt(d2,prec); GEN z = gsqrt(gsub(x0,e3), prec); GEN ar = real_i(a), zr = real_i(z), ai = imag_i(a), zi = imag_i(z); GEN t = gdiv(gneg(y0), gmul2n(gnorm(z),1)); GEN r2 = ginv(gsqrt(gaddsg(1,gdiv(gmul(ai,zi),gmul(ar,zr))),prec)); return zellagmcx(ar,gabs(a,prec),r2,gmul(t,r2),prec); } } /* Assume E/R, disc E > 0, and P \in E(R) */ static GEN zellrealpos(GEN E, GEN P, long prec) { GEN R = ellR_roots(E, prec+EXTRAPRECWORD); GEN d2,d3,e1,e2,e3, a,b, x0 = gel(P,1), y0 = ec_dmFdy_evalQ(E,P); if (gequal0(y0)) return zell_closest_0(ellR_omega(E,prec), x0,R); e1 = gel(R,1); e2 = gel(R,2); e3 = gel(R,3); d2 = gel(R,5); d3 = gel(R,6); a = gsqrt(d2,prec); b = gsqrt(d3,prec); if (gcmp(x0,e1)>0) { GEN r = gsqrt(gdiv(gsub(x0,e3), gsub(x0,e2)),prec); GEN t = gdiv(gneg(y0), gmul2n(gmul(r,gsub(x0,e2)),1)); return zellagmcx(a,b,r,t,prec); } else { GEN om = ellR_omega(E,prec); GEN r = gdiv(a,gsqrt(gsub(e1,x0),prec)); GEN t = gdiv(gmul(r,y0),gmul2n(gsub(x0,e3),1)); return gsub(zellagmcx(a,b,r,t,prec),gmul2n(gel(om,2),-1)); } } static void ellQp_P2t_err(GEN E, GEN z) { if (typ(ellQp_u(E,1)) == t_POLMOD) pari_err_IMPL("ellpointtoz when u not in Qp"); pari_err_DOMAIN("ellpointtoz", "point", "not on", strtoGENstr("E"),z); } static GEN get_r0(GEN E, long prec) { GEN b2 = ell_get_b2(E), e1 = ellQp_root(E, prec); return gadd(e1,gmul2n(b2,-2)); } static GEN ellQp_P2t(GEN E, GEN P, long prec) { pari_sp av = avma; GEN a, b, ab, c0, r0, ar, r, x, delta, x1, y1, t, u, q; long vq, vt, Q, R; if (ell_is_inf(P)) return gen_1; ab = ellQp_ab(E, prec); a = gel(ab,1); b = gel(ab,2); u = ellQp_u(E, prec); q = ellQp_q(E, prec); x = gel(P,1); r0 = get_r0(E, prec); c0 = gadd(x, gmul2n(r0,-1)); if (typ(c0) != t_PADIC) pari_err_TYPE("ellpointtoz",P); r = gsub(a,b); ar = gmul(a, r); if (gequal0(c0)) { x1 = Qp_sqrt(gneg(ar)); if (!x1) ellQp_P2t_err(E,P); } else { delta = gdiv(ar, gsqr(c0)); t = Qp_sqrt(gsubsg(1,gmul2n(delta,2))); if (!t) ellQp_P2t_err(E,P); x1 = gmul(gmul2n(c0,-1), gaddsg(1,t)); } y1 = gdiv(gmul2n(ec_dmFdy_evalQ(E,P), -1), gsubsg(1, gdiv(ar, gsqr(x1)))); Qp_descending_Landen(ellQp_AGM(E,prec), &x1,&y1); t = gmul(u, gmul2n(y1,1)); /* 2u y_oo */ t = gdiv(gsub(t, x1), gadd(t, x1)); /* Reduce mod q^Z: we want 0 <= v(t) < v(q) */ if (typ(t) == t_PADIC) vt = valp(t); else vt = valp(gnorm(t)) / 2; /* v(t) = v(Nt) / (e*f) */ vq = valp(q); /* > 0 */ Q = vt / vq; R = vt % vq; if (R < 0) Q--; if (Q) t = gdiv(t, gpowgs(q,Q)); if (padicprec_relative(t) > prec) t = gprec(t, prec); return gerepileupto(av, t); } static GEN ellQp_t2P(GEN E, GEN t, long prec) { pari_sp av = avma; GEN AB, A, R, x0,x1, y0,y1, u, u2, r0, s0, ar; long v; if (gequal1(t)) return ellinf(); AB = ellQp_AGM(E,prec); A = gel(AB,1); R = gel(AB,3); v = itos(gel(AB,4)); u = ellQp_u(E,prec); u2= ellQp_u2(E,prec); x1 = gdiv(t, gmul(u2, gsqr(gsubsg(1,t)))); y1 = gdiv(gmul(x1,gaddsg(1,t)), gmul(gmul2n(u,1),gsubsg(1,t))); Qp_ascending_Landen(AB, &x1,&y1); r0 = get_r0(E, prec); ar = gmul(gel(A,1), gel(R,1)); setvalp(ar, valp(ar)+v); x0 = gsub(gadd(x1, gdiv(ar, x1)), gmul2n(r0,-1)); s0 = gmul2n(ec_h_evalx(E, x0), -1); y0 = gsub(gmul(y1, gsubsg(1, gdiv(ar,gsqr(x1)))), s0); return gerepilecopy(av, mkvec2(x0,y0)); } static GEN zell_i(GEN e, GEN z, long prec) { GEN t; long s; (void)ellR_omega(e, prec); /* type checking */ if (ell_is_inf(z)) return gen_0; s = ellR_get_sign(e); if (s && typ(gel(z,1))!=t_COMPLEX && typ(gel(z,2))!=t_COMPLEX) t = (s < 0)? zellrealneg(e,z,prec): zellrealpos(e,z,prec); else t = zellcx(e,z,prec); return t; } static GEN ellnfembed(GEN E, long prec); static GEN ellpointnfembed(GEN E, GEN P, long prec); static void ellnfembed_free(GEN L); GEN zell(GEN E, GEN P, long prec) { pari_sp av = avma; checkell(E); checkellpt(P); switch(ell_get_type(E)) { case t_ELL_Qp: prec = minss(ellQp_get_prec(E), padicprec_relative(P)); return ellQp_P2t(E, P, prec); case t_ELL_NF: { GEN Ee = ellnfembed(E, prec), Pe = ellpointnfembed(E, P, prec); long i, l = lg(Pe); for (i = 1; i < l; i++) gel(Pe,i) = zell_i(gel(Ee,i), gel(Pe,i), prec); ellnfembed_free(Ee); return gerepilecopy(av, Pe); } case t_ELL_Q: break; case t_ELL_Rg: break; default: pari_err_TYPE("ellpointtoz", E); } return gerepileupto(av, zell_i(E, P, prec)); } enum period_type { t_PER_W, t_PER_WETA, t_PER_ELL }; /* normalization / argument reduction for ellptic functions */ typedef struct { enum period_type type; GEN in; /* original input */ GEN w1,w2,tau; /* original basis for L = = w2 <1,tau> */ GEN W1,W2,Tau; /* new basis for L = = W2 <1,tau> */ GEN a,b,c,d; /* t_INT; tau in F = h/Sl2, tau = g.t, g=[a,b;c,d] in SL(2,Z) */ GEN z,Z; /* z/w2 defined mod <1,tau>, Z = z/w2 + x*tau+y reduced mod <1,tau>*/ GEN x,y; /* t_INT */ int swap; /* 1 if we swapped w1 and w2 */ int some_q_is_real; /* exp(2iPi g.tau) for some g \in SL(2,Z) */ int some_z_is_real; /* z + xw1 + yw2 is real for some x,y \in Z */ int some_z_is_pure_imag; /* z + xw1 + yw2 in i*R */ int q_is_real; /* exp(2iPi tau) \in R */ int abs_u_is_1; /* |exp(2iPi Z)| = 1 */ long prec; /* precision(Z) */ } ellred_t; /* compute g in SL_2(Z), g.t is in the usual fundamental domain. Internal function no check, no garbage. */ static void set_gamma(GEN *pt, GEN *pa, GEN *pb, GEN *pc, GEN *pd) { GEN a, b, c, d, t, t0e, t0 = *pt, run = dbltor(1. - 1e-8); long e = gexpo(gel(t0,2)); t = t0e = (e >= 0)? t0: gprec_wensure(t0, precision(t0)+nbits2extraprec(-e)); a = d = gen_1; b = c = gen_0; for(;;) { GEN m, n = ground(gel(t,1)); if (signe(n)) { /* apply T^n */ t = gsub(t,n); a = subii(a, mulii(n,c)); b = subii(b, mulii(n,d)); } m = cxnorm(t); if (gcmp(m,run) > 0) break; t = gneg_i(gdiv(conj_i(t), m)); /* apply S */ togglesign_safe(&c); swap(a,c); togglesign_safe(&d); swap(b,d); } if (e < 0 && (signe(b) || signe(c))) *pt = t0e; *pa = a; *pb = b; *pc = c; *pd = d; } /* Im z > 0. Return U.z in PSl2(Z)'s standard fundamental domain. * Set *pU to U. */ GEN cxredsl2_i(GEN z, GEN *pU, GEN *czd) { GEN a,b,c,d; set_gamma(&z, &a, &b, &c, &d); *pU = mkmat2(mkcol2(a,c), mkcol2(b,d)); *czd = gadd(gmul(c,z), d); return gdiv(gadd(gmul(a,z), b), *czd); } GEN cxredsl2(GEN t, GEN *pU) { pari_sp av = avma; GEN czd; t = cxredsl2_i(t, pU, &czd); gerepileall(av, 2, &t, pU); return t; } /* swap w1, w2 so that Im(t := w1/w2) > 0. Set tau = representative of t in * the standard fundamental domain, and g in Sl_2, such that tau = g.t */ static void red_modSL2(ellred_t *T, long prec) { long s, p; T->tau = gdiv(T->w1,T->w2); if (isintzero(real_i(T->tau))) T->some_q_is_real = 1; s = gsigne(imag_i(T->tau)); if (!s) pari_err_DOMAIN("elliptic function", "det(w1,w2)", "=", gen_0, mkvec2(T->w1,T->w2)); T->swap = (s < 0); if (T->swap) { swap(T->w1, T->w2); T->tau = ginv(T->tau); } set_gamma(&T->tau, &T->a, &T->b, &T->c, &T->d); /* update lattice */ p = precision(T->tau); if (p) { T->w1 = gprec_wensure(T->w1, p); T->w2 = gprec_wensure(T->w2, p); } T->W1 = gadd(gmul(T->a,T->w1), gmul(T->b,T->w2)); T->W2 = gadd(gmul(T->c,T->w1), gmul(T->d,T->w2)); T->Tau = gdiv(T->W1, T->W2); if (isintzero(real_i(T->Tau))) T->some_q_is_real = T->q_is_real = 1; p = precision(T->Tau); if (!p) p = prec; T->prec = p; } /* is z real or pure imaginary ? */ static void check_complex(GEN z, int *real, int *imag) { if (typ(z) != t_COMPLEX) { *real = 1; *imag = 0; } else if (isintzero(gel(z,1))) { *real = 0; *imag = 1; } else *real = *imag = 0; } static void reduce_z(GEN z, ellred_t *T) { long p; GEN Z; switch(typ(z)) { case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: break; case t_QUAD: z = isexactzero(gel(z,2))? gel(z,1): quadtofp(z, T->prec); break; default: pari_err_TYPE("reduction mod 2-dim lattice (reduce_z)", z); } Z = gdiv(z, T->W2); T->z = z; T->x = ground(gdiv(imag_i(Z), imag_i(T->Tau))); if (signe(T->x)) Z = gsub(Z, gmul(T->x,T->Tau)); T->y = ground(real_i(Z)); if (signe(T->y)) Z = gsub(Z, T->y); T->abs_u_is_1 = (typ(Z) != t_COMPLEX); /* Z = - y - x tau + z/W2, x,y integers */ check_complex(z, &(T->some_z_is_real), &(T->some_z_is_pure_imag)); if (!T->some_z_is_real && !T->some_z_is_pure_imag) { int W2real, W2imag; check_complex(T->W2,&W2real,&W2imag); if (W2real) check_complex(Z, &(T->some_z_is_real), &(T->some_z_is_pure_imag)); else if (W2imag) check_complex(Z, &(T->some_z_is_pure_imag), &(T->some_z_is_real)); } p = precision(Z); if (gequal0(Z) || (p && gexpo(Z) < 5 - prec2nbits(p))) Z = NULL; /*z in L*/ if (p && p < T->prec) T->prec = p; T->Z = Z; } /* return x.eta1 + y.eta2 */ static GEN eta_correction(ellred_t *T, GEN eta) { GEN y1 = NULL, y2 = NULL; if (signe(T->x)) y1 = gmul(T->x, gel(eta,1)); if (signe(T->y)) y2 = gmul(T->y, gel(eta,2)); if (!y1) return y2? y2: gen_0; return y2? gadd(y1, y2): y1; } /* e is either * - [w1,w2] * - [[w1,w2],[eta1,eta2]] * - an ellinit structure */ static void compute_periods(ellred_t *T, GEN z, long prec) { GEN w, e; T->q_is_real = 0; T->some_q_is_real = 0; switch(T->type) { case t_PER_ELL: { long pr, p = prec; if (z && (pr = precision(z))) p = pr; e = T->in; w = ellR_omega(e, p); T->some_q_is_real = T->q_is_real = 1; break; } case t_PER_W: w = T->in; break; default: /*t_PER_WETA*/ w = gel(T->in,1); break; } T->w1 = gel(w,1); T->w2 = gel(w,2); red_modSL2(T, prec); if (z) reduce_z(z, T); } static int check_periods(GEN e, ellred_t *T) { GEN w1; if (typ(e) != t_VEC) return 0; T->in = e; switch(lg(e)) { case 17: T->type = t_PER_ELL; break; case 3: w1 = gel(e,1); if (typ(w1) != t_VEC) T->type = t_PER_W; else { if (lg(w1) != 3) return 0; T->type = t_PER_WETA; } break; default: return 0; } return 1; } static int get_periods(GEN e, GEN z, ellred_t *T, long prec) { if (!check_periods(e, T)) return 0; compute_periods(T, z, prec); return 1; } /* 2iPi/x, more efficient when x pure imaginary */ static GEN PiI2div(GEN x, long prec) { return gdiv(Pi2n(1, prec), mulcxmI(x)); } /* exp(I x y), more efficient for x in R, y pure imaginary */ GEN expIxy(GEN x, GEN y, long prec) { return gexp(gmul(x, mulcxI(y)), prec); } /* (2iPi/W2)^k E_k(W1/W2) */ static GEN _elleisnum(ellred_t *T, long k) { GEN y = cxEk(T->Tau, k, T->prec); y = gmul(y, gpowgs(mulcxI(gdiv(Pi2n(1,T->prec), T->W2)),k)); return cxtoreal(y); } /* Return (2iPi)^k E_k(L) = (2iPi/w2)^k E_k(tau), with L = , k > 0 even * E_k(tau) = 1 + 2/zeta(1-k) * sum(n>=1, n^(k-1) q^n/(1-q^n)) * If flag is != 0 and k=4 or 6, compute g2 = E4/12 or g3 = -E6/216 resp. */ GEN elleisnum(GEN om, long k, long flag, long prec) { pari_sp av = avma; GEN y; ellred_t T; if (k<=0) pari_err_DOMAIN("elleisnum", "k", "<=", gen_0, stoi(k)); if (k&1) pari_err_DOMAIN("elleisnum", "k % 2", "!=", gen_0, stoi(k)); if (!get_periods(om, NULL, &T, prec)) pari_err_TYPE("elleisnum",om); y = _elleisnum(&T, k); if (k==2 && signe(T.c)) { GEN a = gmul(Pi2n(1,T.prec), mului(12, T.c)); y = gsub(y, mulcxI(gdiv(a, gmul(T.w2, T.W2)))); } else if (k==4 && flag) y = gdivgs(y, 12); else if (k==6 && flag) y = gdivgs(y,-216); return gerepileupto(av,y); } /* return quasi-periods attached to [T->W1,T->W2] */ static GEN _elleta(ellred_t *T) { GEN y1, y2, e2 = gdivgs(_elleisnum(T,2), -12); y2 = gmul(T->W2, e2); y1 = gsub(gmul(T->W1,e2), PiI2div(T->W2, T->prec)); retmkvec2(y1, y2); } /* compute eta1, eta2 */ GEN elleta(GEN om, long prec) { pari_sp av = avma; GEN y1, y2, E2, pi; ellred_t T; if (!check_periods(om, &T)) pari_err_TYPE("elleta",om); if (T.type == t_PER_ELL) return ellR_eta(om, prec); compute_periods(&T, NULL, prec); prec = T.prec; pi = mppi(prec); E2 = cxEk(T.Tau, 2, prec); /* E_2(Tau) */ if (signe(T.c)) { GEN u = gdiv(T.w2, T.W2); /* E2 := u^2 E2 + 6iuc/pi = E_2(tau) */ E2 = gadd(gmul(gsqr(u), E2), mulcxI(gdiv(gmul(mului(6,T.c), u), pi))); } y2 = gdiv(gmul(E2, sqrr(pi)), gmulsg(3, T.w2)); if (T.swap) { y1 = y2; y2 = gadd(gmul(T.tau,y1), PiI2div(T.w2, prec)); } else y1 = gsub(gmul(T.tau,y2), PiI2div(T.w2, prec)); switch(typ(T.w1)) { case t_INT: case t_FRAC: case t_REAL: y1 = real_i(y1); } return gerepilecopy(av, mkvec2(y1,y2)); } GEN ellperiods(GEN w, long flag, long prec) { pari_sp av = avma; ellred_t T; if (!get_periods(w, NULL, &T, prec)) pari_err_TYPE("ellperiods",w); switch(flag) { case 0: return gerepilecopy(av, mkvec2(T.W1, T.W2)); case 1: return gerepilecopy(av, mkvec2(mkvec2(T.W1, T.W2), _elleta(&T))); default: pari_err_FLAG("ellperiods"); return NULL;/*LCOV_EXCL_LINE*/ } } /* 2Pi Im(z)/log(2) */ static double get_toadd(GEN z) { return (2*M_PI/M_LN2)*gtodouble(imag_i(z)); } /* computes the numerical value of wp(z | L), L = om1 Z + om2 Z * return NULL if z in L. If flall=1, compute also wp' */ static GEN ellwpnum_all(GEN e, GEN z, long flall, long prec) { long toadd; pari_sp av = avma, av1; GEN pi2, q, u, y, yp, u1, u2, qn; ellred_t T; int simple_case; if (!get_periods(e, z, &T, prec)) pari_err_TYPE("ellwp",e); if (!T.Z) return NULL; prec = T.prec; /* Now L,Z normalized to <1,tau>. Z in fund. domain of <1, tau> */ pi2 = Pi2n(1, prec); q = expIxy(pi2, T.Tau, prec); u = expIxy(pi2, T.Z, prec); u1 = gsubsg(1,u); u2 = gsqr(u1); /* (1-u)^2 = -4u sin^2(Pi Z) */ if (gequal0(gnorm(u2))) return NULL; /* possible if loss of accuracy */ y = gdiv(u,u2); /* -1/4(sin^2(Pi Z)) */ if (T.abs_u_is_1) y = real_i(y); simple_case = T.abs_u_is_1 && T.q_is_real; y = gadd(mkfrac(gen_1, utoipos(12)), y); yp = flall? gen_0: NULL; toadd = (long)ceil(get_toadd(T.Z)); av1 = avma; qn = q; for(;;) { /* y += u q^n [ 1/(1-q^n u)^2 + 1/(q^n-u)^2 ] - 2q^n /(1-q^n)^2 */ /* analogous formula for yp */ GEN yadd, ypadd = NULL; GEN qnu = gmul(qn,u); /* q^n u */ GEN a = gsubsg(1,qnu);/* 1 - q^n u */ GEN a2 = gsqr(a); /* (1 - q^n u)^2 */ if (yp) ypadd = gdiv(gaddsg(1,qnu),gmul(a,a2)); if (simple_case) /* conj(u) = 1/u: formula simplifies */ yadd = gmul2n(real_i(gdiv(u,a2)), 1); else { GEN b = gsub(qn,u);/* q^n - u */ GEN b2 = gsqr(b); /* (q^n - u)^2 */ yadd = gmul(u, gadd(ginv(a2),ginv(b2))); if (yp) ypadd = gadd(ypadd, gdiv(gadd(qn,u),gmul(b,b2))); } yadd = gsub(yadd, gmul2n(ginv(gsqr(gsubsg(1,qn))), 1)); y = gadd(y, gmul(qn,yadd)); if (yp) yp = gadd(yp, gmul(qn,ypadd)); qn = gmul(q,qn); if (gexpo(qn) <= - prec2nbits(prec) - 5 - toadd) break; if (gc_needed(av1,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ellwp"); gerepileall(av1, flall? 3: 2, &y, &qn, &yp); } } if (yp) { if (simple_case) yp = gsub(yp, conj_i(gmul(yp,gsqr(u)))); yp = gadd(yp, gdiv(gaddsg(1,u), gmul(u1,u2))); } u1 = gdiv(pi2, mulcxmI(T.W2)); u2 = gsqr(u1); y = gmul(u2,y); /* y *= (2i pi / w2)^2 */ if (T.some_q_is_real && (T.some_z_is_real || T.some_z_is_pure_imag)) y = real_i(y); if (yp) { yp = gmul(u, gmul(gmul(u1,u2),yp));/* yp *= u (2i pi / w2)^3 */ if (T.some_q_is_real) { if (T.some_z_is_real) yp = real_i(yp); else if (T.some_z_is_pure_imag) yp = mkcomplex(gen_0, imag_i(yp)); } y = mkvec2(y, yp); } return gerepilecopy(av, y); } static GEN ellwpseries_aux(GEN c4, GEN c6, long v, long PRECDL) { long i, k, l; pari_sp av; GEN _1, t, res = cgetg(PRECDL+2,t_SER), *P = (GEN*)(res + 2); res[1] = evalsigne(1) | _evalvalp(-2) | evalvarn(v); if (!PRECDL) { setsigne(res,0); return res; } for (i=1; i 1) pari_err_FLAG("ellsigma"); if (!z) z = pol_x(0); y = toser_i(z); if (y) { long vy = varn(y), v = valp(y); GEN P, Q, c4,c6; if (!get_c4c6(w,&c4,&c6,prec0)) pari_err_TYPE("ellsigma",w); if (v <= 0) pari_err_IMPL("ellsigma(t_SER) away from 0"); if (flag) pari_err_TYPE("log(ellsigma)",y); if (gequal0(y)) { avma = av; return zeroser(vy, -v); } P = ellwpseries_aux(c4,c6, vy, lg(y)-2); P = integser(gneg(P)); /* \zeta' = - \wp*/ /* (log \sigma)' = \zeta; remove log-singularity first */ P = integser(serchop0(P)); P = gexp(P, prec0); setvalp(P, valp(P)+1); Q = gsubst(P, varn(P), y); return gerepileupto(av, Q); } if (!get_periods(w, z, &T, prec0)) pari_err_TYPE("ellsigma",w); if (!T.Z) { if (!flag) return gen_0; pari_err_DOMAIN("log(ellsigma)", "argument","=",gen_0,z); } prec = T.prec; pi2 = Pi2n(1,prec); pi = mppi(prec); urninv = uinv = NULL; if (typ(T.Z) == t_FRAC && equaliu(gel(T.Z,2), 2) && equalim1(gel(T.Z,1))) { toadd = 0; urn = mkcomplex(gen_0, gen_m1); /* Z = -1/2 => urn = -I */ u = gen_1; } else { toadd = (long)ceil(fabs( get_toadd(T.Z) )); urn = expIxy(pi, T.Z, prec); /* exp(i Pi Z) */ u = gneg_i(gsqr(urn)); if (!T.abs_u_is_1) { urninv = ginv(urn); uinv = gneg_i(gsqr(urninv)); } } q8 = expIxy(gmul2n(pi2,-3), T.Tau, prec); q = gpowgs(q8,8); av1 = avma; y = gen_0; qn = q; qn2 = gen_1; for(n=0;;n++) { /* qn = q^(n+1), qn2 = q^(n(n+1)/2), urn = u^((n+1)/2) * if |u| = 1, will multiply by 2*I at the end ! */ y = gadd(y, gmul(qn2, uinv? gsub(urn,urninv): imag_i(urn))); qn2 = gmul(qn,qn2); if (gexpo(qn2) + n*toadd <= - prec2nbits(prec) - 5) break; qn = gmul(q,qn); urn = gmul(urn,u); if (uinv) urninv = gmul(urninv,uinv); if (gc_needed(av1,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ellsigma"); gerepileall(av1,urninv? 5: 4, &y,&qn,&qn2,&urn,&urninv); } } y = gmul(y, gdiv(q8, gmul(pi2,gpowgs(trueeta(T.Tau,prec),3)))); y = gmul(y, T.abs_u_is_1? gmul2n(T.W2,1): mulcxmI(T.W2)); et = _elleta(&T); z0 = gmul(T.Z,T.W2); y1 = gadd(z0, gmul2n(gadd(gmul(T.x,T.W1), gmul(T.y,T.W2)),-1)); etnew = gmul(eta_correction(&T, et), y1); y1 = gadd(etnew, gmul2n(gmul(gmul(T.Z,z0),gel(et,2)),-1)); if (flag) { y = gadd(y1, glog(y,prec)); if (mpodd(T.x) || mpodd(T.y)) y = gadd(y, mulcxI(pi)); /* log(real number): im(y) = 0 or Pi */ if (T.some_q_is_real && isintzero(imag_i(z)) && gexpo(imag_i(y)) < 1) y = real_i(y); } else { y = gmul(y, gexp(y1,prec)); if (mpodd(T.x) || mpodd(T.y)) y = gneg_i(y); if (T.some_q_is_real) { int re, cx; check_complex(z,&re,&cx); if (re) y = real_i(y); else if (cx && typ(y) == t_COMPLEX) gel(y,1) = gen_0; } } return gerepilecopy(av, y); } GEN pointell(GEN e, GEN z, long prec) { pari_sp av = avma; GEN v; checkell(e); if (ell_get_type(e) == t_ELL_Qp) { prec = minss(ellQp_get_prec(e), padicprec_relative(z)); return ellQp_t2P(e, z, prec); } v = ellwpnum_all(e,z,1,prec); if (!v) { avma = av; return ellinf(); } gel(v,1) = gsub(gel(v,1), gdivgs(ell_get_b2(e),12)); gel(v,2) = gmul2n(gsub(gel(v,2), ec_h_evalx(e,gel(v,1))),-1); return gerepilecopy(av, v); } /********************************************************************/ /** **/ /** Tate's algorithm e (cf Anvers IV) **/ /** Kodaira types, global minimal model **/ /** **/ /********************************************************************/ /* structure to hold incremental computation of standard minimal model/Q */ typedef struct { long a1; /*{0,1}*/ long a2; /*{-1,0,1}*/ long a3; /*{0,1}*/ long b2; /* centermod(-c6, 12), in [-5,6] */ GEN u, u2, u3, u4, u6; GEN a4, a6, b4, b6, b8, c4, c6, D; } ellmin_t; /* u from [u,r,s,t] */ static void min_set_u(ellmin_t *M, GEN u) { M->u = u; if (is_pm1(u)) M->u2 = M->u3 = M->u4 = M->u6 = gen_1; else { M->u2 = sqri(u); M->u3 = mulii(M->u2, u); M->u4 = sqri(M->u2); M->u6 = sqri(M->u3); } } /* E = original curve */ static void min_set_c(ellmin_t *M, GEN E) { GEN c4 = ell_get_c4(E), c6 = ell_get_c6(E); if (!is_pm1(M->u4)) { c4 = diviiexact(c4, M->u4); c6 = diviiexact(c6, M->u6); } M->c4 = c4; M->c6 = c6; } static void min_set_D(ellmin_t *M, GEN E) { GEN D = ell_get_disc(E); if (!is_pm1(M->u6)) D = diviiexact(D, sqri(M->u6)); M->D = D; } static void min_set_b(ellmin_t *M) { long b22, b2; M->b2 = b2 = Fl_center(12 - umodiu(M->c6,12), 12, 6); b22 = b2 * b2; /* in [0,36] */ M->b4 = diviuexact(subui(b22, M->c4), 24); M->b6 = diviuexact(subii(mulsi(b2, subiu(mului(36,M->b4),b22)), M->c6), 216); } static void min_set_a(ellmin_t *M) { long a1, a2, a3, a13, b2 = M->b2; GEN b4 = M->b4, b6 = M->b6; if (odd(b2)) { a1 = 1; a2 = (b2 - 1) >> 2; } else { a1 = 0; a2 = b2 >> 2; } M->a1 = a1; M->a2 = a2; M->a3 = a3 = Mod2(b6)? 1: 0; a13 = a1 & a3; /* a1 * a3 */ M->a4 = shifti(subiu(b4, a13), -1); M->a6 = shifti(subiu(b6, a3), -2); } static void min_set_all(ellmin_t *M, GEN E, GEN u) { min_set_u(M, u); min_set_c(M, E); min_set_D(M, E); min_set_b(M); min_set_a(M); } static GEN min_to_ell(ellmin_t *M, GEN E) { GEN b8, y = obj_init(15, 8); long a11, a13; gel(y,1) = M->a1? gen_1: gen_0; gel(y,2) = stoi(M->a2); gel(y,3) = M->a3? gen_1: gen_0; gel(y,4) = M->a4; gel(y,5) = M->a6; gel(y,6) = stoi(M->b2); gel(y,7) = M->b4; gel(y,8) = M->b6; a11 = M->a1; a13 = M->a1 & M->a3; b8 = subii(addii(mului(a11,M->a6), mulis(M->b6, M->a2)), mulii(M->a4, addiu(M->a4,a13))); gel(y,9) = b8; /* a1^2 a6 + 4a6 a2 + a2 a3^2 - a4(a4 + a1 a3) */ gel(y,10)= M->c4; gel(y,11)= M->c6; gel(y,12)= M->D; gel(y,13)= gel(E,13); gel(y,14)= gel(E,14); gel(y,15)= gel(E,15); return y; } static GEN min_get_v(ellmin_t *M, GEN E) { GEN r, s, t; r = diviuexact(subii(mulis(M->u2,M->b2), ell_get_b2(E)), 12); s = shifti(subii(M->a1? M->u: gen_0, ell_get_a1(E)), -1); t = shifti(subii(M->a3? M->u3: gen_0, Zec_h_evalx(E,r)), -1); return mkvec4(M->u,r,s,t); } /* return v_p(u), where [u,r,s,t] is the variable change to minimal model */ static long get_vp_u_small(GEN E, ulong p, long *pv6, long *pvD) { GEN c6 = ell_get_c6(E); long d, v6, vD = Z_lval(ell_get_disc(E), p); if (!signe(c6)) { d = vD / 12; if (d) { if (p == 2) { GEN c4 = ell_get_c4(E); long a = Mod16( shifti(c4, -4*d) ); if (a) d--; } if (d) vD -= 12*d; /* non minimal model */ } v6 = 12; /* +oo */ } else { v6 = Z_lval(c6,p); d = minss(2*v6, vD) / 12; if (d) { if (p == 2) { GEN c4 = ell_get_c4(E); long a = Mod16( shifti(c4, -4*d) ); long b = Mod32( shifti(c6, -6*d) ); if ((b & 3) != 3 && (a || (b && b!=8))) d--; } else if (p == 3) { if (v6 == 6*d+2) d--; } if (d) { v6 -= 6*d; vD -= 12*d; } /* non minimal model */ } } *pv6 = v6; *pvD = vD; return d; } static long get_vp_u(GEN E, GEN p, long *pv6, long *pvD) { GEN c6; long d, v6, vD; if (lgefint(p) == 3) return get_vp_u_small(E, p[2], pv6, pvD); c6 = ell_get_c6(E); vD = Z_pval(ell_get_disc(E), p); if (!signe(c6)) { d = vD / 12; if (d) vD -= 12*d; /* non minimal model */ v6 = 12; /* +oo */ } else { v6 = Z_pval(c6,p); d = minss(2*v6, vD) / 12; if (d) { v6 -= 6*d; vD -= 12*d; } /* non minimal model */ } *pv6 = v6; *pvD = vD; return d; } /* Given an integral elliptic curve in ellinit form, and a prime p, returns the type of the fiber at p of the Neron model, as well as the change of variables in the form [f, kod, v, c]. * The integer f is the conductor's exponent. * The integer kod is the Kodaira type using the following notation: II , III , IV --> 2, 3, 4 I0 --> 1 Inu --> 4+nu for nu > 0 A '*' negates the code (e.g I* --> -2) * v is a quadruple [u, r, s, t] yielding a minimal model * c is the Tamagawa number. Uses Tate's algorithm (Anvers IV). Given the remarks at the bottom of page 46, the "long" algorithm is used for p = 2,3 only. */ static GEN localred_result(long f, long kod, long c, GEN v) { GEN z = cgetg(5, t_VEC); gel(z,1) = stoi(f); gel(z,2) = stoi(kod); gel(z,3) = gcopy(v); gel(z,4) = stoi(c); return z; } static GEN localredbug(GEN p, const char *s) { if (BPSW_psp(p)) pari_err_BUG(s); pari_err_PRIME("localred",p); return NULL; /* LCOV_EXCL_LINE */ } /* v_p( denom(j(E)) ) >= 0 */ static long j_pval(GEN E, GEN p) { return Z_pval(Q_denom(ell_get_j(E)), p); } /* p > 3, e integral */ static GEN localred_p(GEN e, GEN p) { long k, f, kod, c, nuj, nuD, nu6; GEN p2, v, tri, c4, c6, D = ell_get_disc(e); c4 = ell_get_c4(e); c6 = ell_get_c6(e); nuj = j_pval(e, p); nuD = Z_pval(D, p); k = get_vp_u(e, p, &nu6, &nuD); if (!k) v = init_ch(); else { /* model not minimal */ ellmin_t M; min_set_all(&M, e, powiu(p,k)); v = min_get_v(&M, e); c4 = M.c4; c6 = M.c6; D = M.D; } if (nuj > 0) switch(nuD - nuj) { case 0: f = 1; kod = 4+nuj; /* Inu */ switch(kronecker(negi(c6),p)) { case 1: c = nuD; break; case -1: c = odd(nuD)? 1: 2; break; default: return localredbug(p,"localred (p | c6)"); } break; case 6: { GEN d = Fp_red(diviiexact(D, powiu(p, 6+nuj)), p); if (nuj & 1) d = Fp_mul(d, diviiexact(c6, powiu(p,3)), p); f = 2; kod = -4-nuj; c = 3 + kronecker(d, p); /* Inu* */ break; } default: return localredbug(p,"localred (nu_D - nu_j != 0,6)"); } else switch(nuD) { case 0: f = 0; kod = 1; c = 1; break; /* I0, regular */ case 2: f = 2; kod = 2; c = 1; break; /* II */ case 3: f = 2; kod = 3; c = 2; break; /* III */ case 4: f = 2; kod = 4; /* IV */ c = 2 + krosi(-6,p) * kronecker(diviiexact(c6,sqri(p)), p); break; case 6: f = 2; kod = -1; /* I0* */ p2 = sqri(p); /* x^3 - 3c4/p^2 x - 2c6/p^3 */ tri = mkpoln(4, gen_1, gen_0, negi(mului(3, diviiexact(c4, p2))), negi(shifti(diviiexact(c6, mulii(p2,p)), 1))); c = 1 + FpX_nbroots(tri, p); break; case 8: f = 2; kod = -4; /* IV* */ c = 2 + krosi(-6,p) * kronecker(diviiexact(c6, sqri(sqri(p))), p); break; case 9: f = 2; kod = -3; c = 2; break; /* III* */ case 10: f = 2; kod = -2; c = 1; break; /* II* */ default: return localredbug(p,"localred"); } return localred_result(f, kod, c, v); } /* return a_{ k,l } in Tate's notation, pl = p^l */ static ulong aux(GEN ak, ulong q, ulong pl) { return umodiu(ak, q) / pl; } static ulong aux2(GEN ak, ulong p, GEN pl) { pari_sp av = avma; ulong res = umodiu(diviiexact(ak, pl), p); avma = av; return res; } /* number of distinct roots of X^3 + aX^2 + bX + c modulo p = 2 or 3 * assume a,b,c in {0, 1} [ p = 2 ] or {0, 1, 2} [ p = 3 ] * if there's a multiple root, put it in *mult */ static long numroots3(long a, long b, long c, long p, long *mult) { if (p == 2) { if ((c + a * b) & 1) return 3; *mult = b; return (a + b) & 1 ? 2 : 1; } /* p = 3 */ if (!a) { *mult = -c; return b ? 3 : 1; } *mult = a * b; if (b == 2) return (a + c) == 3 ? 2 : 3; else return c ? 3 : 2; } /* same for aX^2 +bX + c */ static long numroots2(long a, long b, long c, long p, long *mult) { if (p == 2) { *mult = c; return b & 1 ? 2 : 1; } /* p = 3 */ *mult = a * b; return (b * b - a * c) % 3 ? 2 : 1; } /* p = 2 or 3 */ static GEN localred_23(GEN e, long p) { long c, nu, nu6, nuD, r, s, t; long k, theroot, p2, p3, p4, p5, a21, a42, a63, a32, a64; GEN v; k = get_vp_u_small(e, p, &nu6, &nuD); if (!k) v = init_ch(); else { ellmin_t M; min_set_all(&M, e, powuu(p, k)); v = min_get_v(&M, e); e = min_to_ell(&M, e); } /* model is minimal */ nuD = Z_lval(ell_get_disc(e), (ulong)p); if (p == 2) { p2 = 4; p3 = 8; p4 = 16; p5 = 32; } else { p2 = 9; p3 = 27; p4 = 81; p5 =243; } if (!nuD) return localred_result(0, 1, 1, v); /* I0 */ if (umodiu(ell_get_b2(e), p)) /* p \nmid b2 */ { if (umodiu(negi(ell_get_c6(e)), p == 2 ? 8 : 3) == 1) c = nuD; else c = 2 - (nuD & 1); return localred_result(1, 4 + nuD, c, v); /* Inu */ } if (p == 2) { r = umodiu(ell_get_a4(e), 2); s = umodiu(ell_get_a2(e), 2); t = umodiu(ell_get_a6(e), 2); if (r) { t = (s + t) & 1; s = (s + 1) & 1; } } else /* p == 3 */ { r = - umodiu(ell_get_b6(e), 3); s = umodiu(ell_get_a1(e), 3); t = umodiu(ell_get_a3(e), 3); if (s) { t = (t + r*s) % 3; if (t < 0) t += 3; } } /* p | (a1, a2, a3, a4, a6) */ if (r || s || t) e = coordch_rst(e, stoi(r), stoi(s), stoi(t)); if (umodiu(ell_get_a6(e), p2)) return localred_result(nuD, 2, 1, v); /* II */ if (umodiu(ell_get_b8(e), p3)) return localred_result(nuD - 1, 3, 2, v); /* III */ if (umodiu(ell_get_b6(e), p3)) { if (umodiu(ell_get_b6(e), (p==2)? 32: 27) == (ulong)p2) c = 3; else c = 1; return localred_result(nuD - 2, 4, c, v); /* IV */ } if (umodiu(ell_get_a6(e), p3)) e = coordch_t(e, p == 2? gen_2: modis(ell_get_a3(e), 9)); /* p | a1, a2; p^2 | a3, a4; p^3 | a6 */ a21 = aux(ell_get_a2(e), p2, p); a42 = aux(ell_get_a4(e), p3, p2); a63 = aux(ell_get_a6(e), p4, p3); switch (numroots3(a21, a42, a63, p, &theroot)) { case 3: c = a63 ? 1: 2; if (p == 2) c += ((a21 + a42 + a63) & 1); else { if (((1 + a21 + a42 + a63) % 3) == 0) c++; if (((1 - a21 + a42 - a63) % 3) == 0) c++; } return localred_result(nuD - 4, -1, c, v); /* I0* */ case 2: { /* compute nu */ GEN pk, pk1, p2k; long al, be, ga; if (theroot) e = coordch_r(e, stoi(theroot * p)); /* p | a1; p^2 | a2, a3; p^3 | a4; p^4 | a6 */ nu = 1; pk = utoipos(p2); p2k = utoipos(p4); for(;;) { be = aux2(ell_get_a3(e), p, pk); ga = -aux2(ell_get_a6(e), p, p2k); al = 1; if (numroots2(al, be, ga, p, &theroot) == 2) break; if (theroot) e = coordch_t(e, mulsi(theroot,pk)); pk1 = pk; pk = mului(p, pk); p2k = mului(p, p2k); nu++; al = a21; be = aux2(ell_get_a4(e), p, pk); ga = aux2(ell_get_a6(e), p, p2k); if (numroots2(al, be, ga, p, &theroot) == 2) break; if (theroot) e = coordch_r(e, mulsi(theroot, pk1)); p2k = mului(p, p2k); nu++; } if (p == 2) c = 4 - 2 * (ga & 1); else c = 3 + kross(be * be - al * ga, 3); return localred_result(nuD - 4 - nu, -4 - nu, c, v); /* Inu* */ } case 1: if (theroot) e = coordch_r(e, stoi(theroot*p)); /* p | a1; p^2 | a2, a3; p^3 | a4; p^4 | a6 */ a32 = aux(ell_get_a3(e), p3, p2); a64 = aux(ell_get_a6(e), p5, p4); if (numroots2(1, a32, -a64, p, &theroot) == 2) { if (p == 2) c = 3 - 2 * a64; else c = 2 + kross(a32 * a32 + a64, 3); return localred_result(nuD - 6, -4, c, v); /* IV* */ } if (theroot) e = coordch_t(e, stoi(theroot*p2)); /* p | a1; p^2 | a2; p^3 | a3, a4; p^5 | a6 */ if (umodiu(ell_get_a4(e), p4)) return localred_result(nuD - 7, -3, 2, v); /* III* */ /* p^6 \nmid a6, otherwise wouldn't be minimal */ return localred_result(nuD - 8, -2, 1, v); /* II* */ } return NULL; /* LCOV_EXCL_LINE */ } /* e is integral */ static GEN localred(GEN e, GEN p) { if (abscmpiu(p, 3) > 0) /* p != 2,3 */ return localred_p(e,p); else { long l = itos(p); if (l < 2) pari_err_PRIME("localred",p); return localred_23(e, l); } } /* Given J an ideal in HNF coprime to 2 and z algebraic integer, * return b algebraic integer such that z + 2b in J */ static GEN approx_mod2(GEN J, GEN z) { GEN b = z; long i; if (typ(b) == t_INT) { if (mpodd(b)) b = addii(b, gcoeff(J,1,1)); return shifti(negi(b),-1); } for (i = lg(J)-1; i >= 1; i--) { if (mpodd(gel(b,i))) b = ZC_add(b, gel(J,i)); } return gshift(ZC_neg(b), -1); } /* Given J an ideal in HNF coprime to 3 and z algebraic integer, * return b algebraic integer such that z + 3b in J */ static GEN approx_mod3(GEN J, GEN z) { GEN b = z; long i; if (typ(b) == t_INT) { long s = smodis(b,3); if (s) { GEN Jz = gcoeff(J,1,1); if (smodis(Jz, 3) == s) b = subii(b, Jz); else b = addii(b, Jz); } return diviiexact(b, stoi(-3)); } for (i = lg(J)-1; i >= 1; i--) { long s = smodis(gel(b,i), 3); if (!s) continue; if (smodis(gcoeff(J,i,i), 3) == s) b = ZC_sub(b, gel(J,i)); else b = ZC_add(b, gel(J,i)); } return ZC_Z_divexact(b, stoi(-3)); } /* return a such that v_P(a) = -1, integral elsewhere */ static GEN get_piinv(GEN P) { GEN z = pr_get_tau(P); if (typ(z) == t_MAT) z = gel(z,1); return gdiv(z, pr_get_p(P)); } /* pi = local uniformizer, pv = 1/pi */ static void get_uniformizers(GEN nf, GEN P, GEN *pi, GEN *pv) { if (pr_is_inert(P)) { *pi = pr_get_p(P); *pv = mkfrac(gen_1, *pi); } else { *pv = get_piinv(P); *pi = nfinv(nf, *pv); } } /* x^2+E.a1*x-E.a2 */ static GEN pola1a2(GEN e, GEN nf, GEN modP) { GEN a1 = nf_to_Fq(nf, ell_get_a1(e), modP); GEN a2 = nf_to_Fq(nf, ell_get_a2(e), modP); return mkpoln(3, gen_1, a1, gneg(a2)); } /* x^2+E.a3*pv3*x-E.a6*pv6 */ static GEN pola3a6(GEN e, GEN nf, GEN modP, GEN pv3, GEN pv6) { GEN a3 = nf_to_Fq(nf, nfmul(nf, ell_get_a3(e), pv3), modP); GEN a6 = nf_to_Fq(nf, nfmul(nf, ell_get_a6(e), pv6), modP); return mkpoln(3, gen_1, a3, gneg(a6)); } /* E.a2*pv2*x^2 + E.a4*pv4*x + E.a6*pv6 */ static GEN pola2a4a6(GEN e, GEN nf, GEN modP, GEN pv2, GEN pv4, GEN pv6) { GEN a2 = nf_to_Fq(nf, nfmul(nf, ell_get_a2(e), pv2), modP); GEN a4 = nf_to_Fq(nf, nfmul(nf, ell_get_a4(e), pv4), modP); GEN a6 = nf_to_Fq(nf, nfmul(nf, ell_get_a6(e), pv6), modP); return mkpoln(3, a2, a4, a6); } static GEN pol2sqrt_23(GEN modP, GEN Q) { GEN p = modpr_get_p(modP), T = modpr_get_T(modP); GEN r = absequaliu(p,2) ? gel(Q,2): gel(Q,3); if (!gequal1(gel(Q,4))) r = Fq_div(r, gel(Q,4), T, p); if (absequaliu(p,2)) r = Fq_sqrt(r,T,p); return Fq_to_nf(r, modP); } static GEN nflocalred_section7(GEN e, GEN nf, GEN modP, GEN pi, GEN pv, long vD, GEN ch) { GEN p = modpr_get_p(modP), T = modpr_get_T(modP); GEN pi3 = nfsqr(nf,pi); GEN pv3 = nfsqr(nf,pv), pv4 = nfmul(nf,pv,pv3), pv6 = nfsqr(nf,pv3); long n = 1; while(1) { GEN Q = pola3a6(e, nf, modP, pv3, pv6); GEN gama; if (FqX_is_squarefree(Q, T, p)) { long nr = FqX_nbroots(Q,T,p); return localred_result(vD-n-4,-4-n,nr+2,ch); } gama = pol2sqrt_23(modP, Q); nf_compose_t(nf, &ch, &e, nfmul(nf, gama,pi3)); pv6 = nfmul(nf,pv,pv6); n++; Q = pola2a4a6(e, nf, modP, pv, pv4, pv6); if (FqX_is_squarefree(Q, T, p)) { long nr = FqX_nbroots(Q,T,p); return localred_result(vD-n-4,-4-n,nr+2,ch); } gama = pol2sqrt_23(modP, Q); nf_compose_r(nf, &ch, &e, nfmul(nf, gama, pi3)); pi3 = nfmul(nf,pi, pi3); pv3 = pv4; pv4 = nfmul(nf,pv,pv4); pv6 = nfmul(nf,pv,pv6); n++; } } /* Tate algorithm, following J.H. Silverman GTM 151, chapt. IV, algo 9.4 */ /* Dedicated to John Tate for his kind words */ static GEN nflocalred_23(GEN nf, GEN e, GEN D, GEN P, long *ap) { GEN T, p, modP; long vD; GEN ch, pv, pv2, pv4, pi, pol; modP = nf_to_Fq_init(nf,&P,&T,&p); get_uniformizers(nf,P, &pi, &pv); ch = init_ch(); vD = nfval(nf,D,P); *ap = 0; while(1) { if (vD==0) return localred_result(0,1,1,ch); else { GEN a1 = nf_to_Fq(nf, ell_get_a1(e), modP); GEN a2 = nf_to_Fq(nf, ell_get_a2(e), modP); GEN a3 = nf_to_Fq(nf, ell_get_a3(e), modP); GEN a4 = nf_to_Fq(nf, ell_get_a4(e), modP); GEN a6 = nf_to_Fq(nf, ell_get_a6(e), modP); GEN x0, y0; if (absequaliu(p,2)) { GEN x02, y02; if (signe(a1)) { x0 = Fq_div(a3, a1, T, p); x02 = Fq_sqr(x0,T,p); y02 = Fq_add(Fq_mul(x02,Fq_add(x0,a2,T,p),T,p),Fq_add(Fq_mul(a4,x0,T,p),a6,T,p),T,p); } else { x0 = Fq_sqrt(a4, T, p); y02 = Fq_add(Fq_mul(a4,a2,T,p),a6,T,p); } y0 = Fq_sqrt(y02,T,p); } else { GEN a12 = Fq_add(Fq_sqr(a1,T,p),a2,T,p); if (signe(a12)) x0 = Fq_div(Fq_sub(a4,Fq_mul(a3,a1,T,p),T,p),a12,T,p); else x0 = Fq_sqrtn(Fq_neg(Fq_add(Fq_sqr(a3,T,p),a6,T,p),T,p),p,T,p,NULL); y0 = Fq_add(Fq_mul(a1, x0, T, p), a3, T, p); } x0 = Fq_to_nf(x0, modP); y0 = Fq_to_nf(y0, modP); nf_compose_rt(nf, &ch, &e, x0, y0); } /* 2 */ { GEN b2 = nf_to_Fq(nf, ell_get_b2(e), modP); if (signe(b2) != 0) { GEN Q = pola1a2(e, nf, modP); long nr = FqX_nbroots(Q, T, p); if (nr==2) { *ap = 1; return localred_result(1,vD+4,vD,ch); /* Inu */ } else { *ap = -1; return localred_result(1,vD+4,odd(vD)?1:2,ch); } } } /* 3 */ { long va6 = nfval(nf,ell_get_a6(e),P); if (va6 <= 1) return localred_result(vD,2,1,ch); /* II */ } /* 4 */ { long vb8 = nfval(nf,ell_get_b8(e),P); if (vb8 <= 2) return localred_result(vD-1,3,2,ch);/* III */ } /* 5 */ pv2 = nfsqr(nf,pv); { long vb6 = nfval(nf,ell_get_b6(e),P); if (vb6<=2) { GEN Q = pola3a6(e, nf, modP, pv, pv2); long nr = FqX_nbroots(Q,T,p); return localred_result(vD-2,4,1+nr,ch);/* IV */ } } /* 6 */ { GEN pv3 = nfmul(nf,pv, pv2); GEN alpha = pol2sqrt_23(modP, pola1a2(e, nf, modP)); GEN beta = pol2sqrt_23(modP, pola3a6(e, nf, modP, pv, pv2)); GEN po2, E, F, mr; long i, lE; nf_compose_st(nf, &ch, &e, alpha, nfmul(nf, beta, pi)); po2 = pola2a4a6(e, nf, modP, pv, pv2, pv3); if (signe(po2)) /* po2 = 0 is frequent when non-minimal */ { pol = RgX_add(pol_xn(3,0), po2); F = FqX_factor(pol, T, p); E = gel(F,2); lE = lg(E); if (E[1] == 1 && (lE == 2 || E[2] == 1)) { /* T squarefree, degree pattern is (3), (12) or (111) */ long c; /* 1 + number of roots */ switch(lE) { case 2: c = 1; break; case 3: c = 2; break; default: c = 4; break; } return localred_result(vD-4,-1,c,ch);/* I0* */ } /* 7 */ i = (lE == 2 || E[1] == 2)? 1: 2; /* index of multiple root */ mr = constant_coeff(gmael(F,1,i)); /* - multiple root */ if (!gequal0(mr)) { /* not so frequent */ GEN gama = Fq_to_nf(Fq_neg(mr, T, p), modP); nf_compose_r(nf, &ch, &e, nfmul(nf, gama,pi)); } if (lE == 3) return nflocalred_section7(e, nf, modP, pi, pv, vD, ch); /* Inu* */ } } pv4 = nfsqr(nf,pv2); pol = pola3a6(e, nf, modP, pv2, pv4); /* 8 */ if (FqX_is_squarefree(pol,T,p)) { long nr = FqX_nbroots(pol, T, p); return localred_result(vD-6,-4,1+nr,ch); /* IV* */ } /* 9 */ { GEN alpha = pol2sqrt_23(modP, pol); nf_compose_t(nf, &ch, &e, nfmul(nf, alpha, nfsqr(nf,pi))); if (nfval(nf, ell_get_a4(e), P) == 3) return localred_result(vD-7,-3,2,ch); /* III* */ } /* 10 */ if (nfval(nf, ell_get_a6(e), P) == 5) return localred_result(vD-8,-2,1,ch); /* II* */ /* 11 */ nf_compose_u(nf, &ch, &e, pi, pv); vD -= 12; } } /* Local reduction, residual characteristic >= 5. E/nf, P prid * Output: f, kod, [u,r,s,t], c */ static GEN nflocalred_p(GEN e, GEN P) { GEN nf = ellnf_get_nf(e), T,p, modP = nf_to_Fq_init(nf,&P,&T,&p); long c, f, vD, nuj, kod, m; GEN ch, c4, c6, D, z, pi, piinv; c4 = ell_get_c4(e); c6 = ell_get_c6(e); D = ell_get_disc(e); vD = nfval(nf,D,P); nuj = nfval(nf,ell_get_j(e),P); nuj = nuj >= 0? 0: -nuj; /* v_P(denom(j)) */ m = (vD - nuj)/12; get_uniformizers(nf,P, &pi, &piinv); if(m <= 0) ch = init_ch(); else { /* model not minimal */ GEN r,s,t, a1,a2,a3, u,ui,ui2,ui4,ui6,ui12; u = nfpow_u(nf,pi,m); ui = nfpow_u(nf,piinv,m); ui2 = nfsqr(nf,ui); ui4 = nfsqr(nf,ui2); ui6 = nfmul(nf,ui2,ui4); ui12 = nfsqr(nf,ui6); c4 = nfmul(nf,c4,ui4); c6 = nfmul(nf,c6,ui6); D = nfmul(nf,D,ui12); vD -= 12*m; a1 = nf_to_scalar_or_basis(nf, ell_get_a1(e)); a2 = nf_to_scalar_or_basis(nf, ell_get_a2(e)); a3 = nf_to_scalar_or_basis(nf, ell_get_a3(e)); s = approx_mod2(idealpow(nf,P,stoi(m)), a1); r = gsub(a2, nfmul(nf,s,gadd(a1,s))); r = approx_mod3(idealpow(nf,P,stoi(2*m)), r); t = gadd(a3, nfmul(nf,r,a1)); t = approx_mod2(idealpow(nf,P,stoi(3*m)), t); ch = mkvec4(u,r,s,t); } kod = 0; c = 1; /* minimal at P */ if (nuj > 0) { /* v(j) < 0 */ if (vD == nuj) { /* v(c4) = v(c6) = 0, multiplicative reduction */ f = 1; kod = 4+vD; z = Fq_neg(nf_to_Fq(nf,c6,modP), T,p); if (Fq_issquare(z,T,p)) c = vD;/* split */ else c = odd(vD)?1 : 2; /* non-split */ } else { /* v(c4) = 2, v(c6) = 3, potentially multiplicative */ GEN Du; f = 2; kod = 2-vD; (void)nfvalrem(nf, D, P, &Du); z = nf_to_Fq(nf, Du, modP); if(odd(vD)) { GEN c6u; (void)nfvalrem(nf, c6, P, &c6u); c6u = nf_to_Fq(nf, c6u, modP); z = Fq_mul(z, c6u, T,p); } c = Fq_issquare(z,T,p)? 4: 2; } } else { /* v(j) >= 0 */ f = vD? 2: 0; switch(vD) { GEN piinv2, piinv3, piinv4, w; case 0: kod = 0; c = 1; break; case 2: kod = 2; c = 1; break; case 3: kod = 3; c = 2; break; case 4: kod = 4; z = nfmul(nf,c6,nfsqr(nf,piinv)); z = nf_to_Fq(nf, z, modP); z = Fq_Fp_mul(z,stoi(-6),T,p); c = Fq_issquare(z,T,p)? 3: 1; break; case 6: kod = -1; piinv2 = nfsqr(nf,piinv); piinv3 = nfmul(nf,piinv,piinv2); z = nfmul(nf,c4,piinv2); z = nf_to_Fq(nf, z, modP); z = Fq_Fp_mul(z,stoi(-3), T,p); w = nfmul(nf,c6,piinv3); w = nf_to_Fq(nf, w, modP); w = Fq_Fp_mul(w,gen_m2, T,p); c = 1 + FqX_nbroots(mkpoln(4, gen_1,gen_0,z,w), T,p); break; case 8: kod = -4; piinv4 = nfpow_u(nf,piinv,4); z = nfmul(nf,c6,piinv4); z = nf_to_Fq(nf, z, modP); z = Fq_Fp_mul(z,stoi(-6),T,p); c = Fq_issquare(z,T,p)? 3: 1; break; case 9: kod = -3; c = 2; break; case 10: kod = -2; c = 1; break; } } return localred_result(f,kod,c,ch); } /* E is integral */ static GEN nflocalred(GEN E, GEN pr) { GEN p = pr_get_p(pr); if (abscmpiu(p, 3) <= 0) { long i, ap, vu; GEN nf = ellnf_get_nf(E), e = ell_to_nfell10(E), D = ell_get_disc(E); GEN q = nflocalred_23(nf,e,D,pr,&ap), v = gel(q,3), u = gel(v,1); gel(q,3) = v; /* do nothing if already minimal or equation was not pr-integral */ vu = nfval(nf, u, pr); if (vu > 0) { /* remove denominators in r,s,t on nf.zk */ GEN D, r = gel(v,2), s = gel(v,3), t = gel(v,4); D = Q_denom(mkvec3(r, s, t)); if (!equali1(D)) { /* Beware: D may not be coprime to pr */ GEN a; (void)nfvalrem(nf, D, pr, &D); /* a in D/p^oo, = 1 mod (u^6) locally */ a = idealaddtoone_i(nf, D, idealpows(nf, pr, 6*vu)); gel(v,2) = nfmul(nf, r, a); gel(v,3) = nfmul(nf, s, a); gel(v,4) = nfmul(nf, t, a); } } for(i=1; i <= 4; i++) gel(v,i) = nftoalg(nf, gel(v,i)); return q; } return nflocalred_p(E,pr); } static GEN checkellp(GEN *pE, GEN p, GEN *pv, const char *s) { GEN q, E = *pE; long tE; checkell(E); tE = ell_get_type(E); if (pv) *pv = NULL; if (p) switch(typ(p)) { case t_INT: if (cmpis(p, 2) < 0) pari_err_DOMAIN(s,"p", "<", gen_2, p); break; case t_VEC: q = get_prid(p); if (q && tE == t_ELL_NF) { *pE = ellintegralmodel_i(E, pv); return q; } default: pari_err_TYPE(s,p); } switch(tE) { case t_ELL_Fp: case t_ELL_Fq: q = ellff_get_p(E); break; case t_ELL_Qp: q = ellQp_get_p(E); break; case t_ELL_Q: if (p) { q = p; p = NULL; break; } default: pari_err_TYPE(stack_strcat(s," [can't determine p]"), E); return NULL;/*LCOV_EXCL_LINE*/ } if (p && !equalii(p, q)) pari_err_MODULUS(s, p,q); if (tE == t_ELL_Q || tE == t_ELL_Qp || tE == t_ELL_NF) *pE = ellintegralmodel_i(E, pv); return q; } GEN elllocalred(GEN E, GEN p) { pari_sp av = avma; GEN v, q; checkell(E); p = checkellp(&E, p, &v, "elllocalred"); switch(ell_get_type(E)) { case t_ELL_Qp: case t_ELL_Q: q = localred(E, p); break; case t_ELL_NF: q = nflocalred(E, p); break; default: pari_err_TYPE("elllocalred", E); return NULL;/*LCOV_EXCL_LINE*/ } if (v) { /* compose local change of variables with v */ GEN u = gel(v,1), w = gel(q,3); if (is_trivial_change(w)) gel(q,3) = mkvec4(u,gen_0,gen_0,gen_0); else gel(w,1) = gmul(u, gel(w,1)); } return gerepilecopy(av, q); } /* typ(c) = t_INT or t_FRAC */ static GEN handle_Q(GEN c, GEN *pd) { *pd = (typ(c) == t_INT)? NULL: gel(c,2); return c; } static GEN handle_coeff(GEN nf, GEN c, GEN *pd) { *pd = NULL; switch(typ(c)) { case t_INT: *pd = NULL; return c; case t_FRAC: *pd = gel(c,2); return c; case t_POL: case t_POLMOD: case t_COL: if (nf) { c = nf_to_scalar_or_basis(nf,c); return handle_Q(Q_content(c), pd); } default: pari_err_TYPE("ellintegralmodel",c); return NULL; } } /* Return an integral model for e / nf, Q. Set v = NULL (already integral) * or the variable change [u,0,0,0], u = 1/t, t > 1 integer making e integral */ GEN ellintegralmodel_i(GEN e, GEN *pv) { GEN a, t, u, L, nf; long i, l, k; if (pv) *pv = NULL; /* t_ELL_Qp is also possible */ nf = (ell_get_type(e) == t_ELL_NF)?ellnf_get_nf(e): NULL; L = cgetg(1, t_VEC); a = cgetg(6, t_VEC); for (i = 1; i < 6; i++) { GEN d; gel(a,i) = handle_coeff(nf, gel(e,i), &d); if (d) /* partial factorization of denominator */ L = shallowconcat(L, gel(Z_factor_limit(d, 0),1)); } /* a = [a1, a2, a3, a4, a6] */ l = lg(L); if (l == 1) return e; L = ZV_sort_uniq(L); l = lg(L); t = gen_1; for (k = 1; k < l; k++) { GEN p = gel(L,k); long n = 0, m; for (i = 1; i < 6; i++) if (!gequal0(gel(a,i))) { long r = (i == 5)? 6: i; /* a5 is missing */ m = r * n + Q_pval(gel(a,i), p); while (m < 0) { n++; m += r; } } t = mulii(t, powiu(p, n)); } u = ginv(t); if (pv) *pv = mkvec4(u,gen_0,gen_0,gen_0); return coordch_uinv(e, t); } GEN ellintegralmodel(GEN e, GEN *pv) { pari_sp av = avma; checkell(e); switch(ell_get_type(e)) { case t_ELL_Q: case t_ELL_Qp: case t_ELL_NF: break; default: pari_err_TYPE("ellintegralmodel",e); } e = ellintegralmodel_i(e, pv); if (!pv || !*pv) { e = gerepilecopy(av, e); if (pv) *pv = init_ch(); } else gerepileall(av, 2, &e, pv); return e; } static long F2_card(ulong a1, ulong a2, ulong a3, ulong a4, ulong a6) { long N = 1; /* oo */ if (!a3) N ++; /* x = 0, y=0 or 1 */ else if (!a6) N += 2; /* x = 0, y arbitrary */ if ((a3 ^ a1) == 0) N++; /* x = 1, y = 0 or 1 */ else if (a2 ^ a4 ^ a6) N += 2; /* x = 1, y arbitrary */ return N; } static long F3_card(ulong b2, ulong b4, ulong b6) { ulong Po = 1+2*b4, Pe = b2+b6; /* kro(x,3)+1 = (x+1)%3, N = 4 + sum(kro) = 1+ sum(1+kro) */ return 1+(b6+1)%3+(Po+Pe+1)%3+(2*Po+Pe+1)%3; } static long cardmod2(GEN e) { /* solve y(1 + a1x + a3) = x (1 + a2 + a4) + a6 */ ulong a1 = Rg_to_F2(ell_get_a1(e)); ulong a2 = Rg_to_F2(ell_get_a2(e)); ulong a3 = Rg_to_F2(ell_get_a3(e)); ulong a4 = Rg_to_F2(ell_get_a4(e)); ulong a6 = Rg_to_F2(ell_get_a6(e)); return F2_card(a1,a2,a3,a4,a6); } static long cardmod3(GEN e) { ulong b2 = Rg_to_Fl(ell_get_b2(e), 3); ulong b4 = Rg_to_Fl(ell_get_b4(e), 3); ulong b6 = Rg_to_Fl(ell_get_b6(e), 3); return F3_card(b2,b4,b6); } static ulong ZtoF2(GEN x) { return (ulong)mpodd(x); } /* complete local reduction at 2, u = 2^d */ static void min_set_2(ellmin_t *M, GEN E, long d) { min_set_u(M, int2n(d)); min_set_c(M, E); min_set_b(M); min_set_a(M); } /* local reduction at 3, u = 3^d, don't compute the a_i */ static void min_set_3(ellmin_t *M, GEN E, long d) { min_set_u(M, powuu(3, d)); min_set_c(M, E); min_set_b(M); } static long ellQap_u(GEN E, ulong p, int *good_red) { long vc6, vD, d = get_vp_u_small(E, p, &vc6, &vD); if (vD) /* bad reduction */ { GEN c6; long s; *good_red = 0; if (vc6) return 0; c6 = ell_get_c6(E); if (d) c6 = diviiexact(c6, powuu(p, 6*d)); s = kroiu(c6,p); if ((p & 3) == 3) s = -s; return s; } *good_red = 1; if (p == 2) { ellmin_t M; if (!d) return 3 - cardmod2(E); min_set_2(&M, E, d); return 3 - F2_card(M.a1, M.a2 & 1, M.a3, ZtoF2(M.a4), ZtoF2(M.a6)); } else if (p == 3) { ellmin_t M; if (!d) return 4 - cardmod3(E); min_set_3(&M, E, d); return 4 - F3_card(M.b2, umodiu(M.b4,3), umodiu(M.b6,3)); } else { ellmin_t M; GEN a4, a6, pp = utoipos(p); min_set_u(&M, powuu(p,d)); min_set_c(&M, E); c4c6_to_a4a6(M.c4, M.c6, pp, &a4,&a6); return itos( subui(p+1, Fp_ellcard(a4, a6, pp)) ); } } static GEN ellQap(GEN E, GEN p, int *good_red) { GEN a4,a6, c4, c6, D; long vc6, vD, d; if (lgefint(p) == 3) return stoi( ellQap_u(E, p[2], good_red) ); c6 = ell_get_c6(E); D = ell_get_disc(E); vc6 = Z_pval(c6,p); vD = Z_pval(D,p); d = minss(2*vc6, vD) / 12; if (d) { vc6 -= 6*d; vD -= 12*d; } /* non minimal model */ if (vD) /* bad reduction */ { long s; *good_red = 0; if (vc6) return gen_0; if (d) c6 = diviiexact(c6, powiu(p, 6*d)); s = kronecker(c6,p); if (mod4(p) == 3) s = -s; return s < 0? gen_m1: gen_1; } *good_red = 1; c4 = ell_get_c4(E); if (d) { GEN u2 = powiu(p, 2*d), u4 = sqri(u2), u6 = mulii(u2,u4); c4 = diviiexact(c4, u4); c6 = diviiexact(c6, u6); } c4c6_to_a4a6(c4, c6, p, &a4,&a6); return subii(addiu(p,1), Fp_ellcard(a4, a6, p)); } static GEN doellcard(GEN E) { GEN fg = ellff_get_field(E); if (typ(fg)==t_FFELT) return FF_ellcard(E); else { GEN e = ellff_get_a4a6(E); return Fp_ellcard(gel(e,1),gel(e,2),fg); } } static GEN ellnfap(GEN E, GEN P, int *good_red) { GEN a4,a6, card, nf = ellnf_get_nf(E); GEN T,p, modP = nf_to_Fq_init(nf,&P,&T,&p); if (abscmpiu(p, 3) <= 0) { long ap; GEN nf = ellnf_get_nf(E), e = ell_to_nfell10(E), D = ell_get_disc(E); GEN L = nflocalred_23(nf, e,D,P,&ap), kod = gel(L,2); if (!equali1(kod)) { *good_red = 0; return stoi(ap); } *good_red = 1; E = nf_coordch(nf, vecslice(e,1,5), gel(L,3)); E = ellinit_nf_to_Fq(nf, E, modP); card = FF_ellcard(E); } else { GEN c6 = ell_get_c6(E), c4 = ell_get_c4(E); long vD = nfval(nf, ell_get_disc(E), P); if (vD) { GEN c6new; long d, vc6 = nfvalrem(nf,c6,P, &c6new); d = ((vc6 == LONG_MAX)? vD: minss(vD,2*vc6)) / 12; if (vD > 12*d) { /* bad reduction */ *good_red = 0; if (vc6 != 6*d) return gen_0; c6 = nf_to_Fq(nf, c6new, modP); return Fq_issquare(gneg(c6),T,p)? gen_1: gen_m1; } if (d) { /* model not minimal at P */ GEN piinv = get_piinv(P); GEN ui2 = nfpow(nf, piinv, stoi(2*d)); GEN ui4 = nfsqr(nf, ui2); GEN ui6 = nfmul(nf, ui2, ui4); c4 = nfmul(nf, c4, ui4); c6 = nfmul(nf, c6, ui6); } } *good_red = 1; c4 = nf_to_Fq(nf, c4, modP); c6 = nf_to_Fq(nf, c6, modP); Fq_c4c6_to_a4a6(c4, c6, T,p, &a4,&a6); card = T? FpXQ_ellcard(Fq_to_FpXQ(a4,T,p),Fq_to_FpXQ(a6,T,p),T,p) : Fp_ellcard(a4,a6,p); } return subii(addiu(pr_norm(P),1), card); } /* a, b not both 0; sorted list of primes dividing gcd(a,b), using coprime * basis */ static GEN Z_gcd_primes(GEN a, GEN b) { GEN P; if (!signe(a)) P = gel(absZ_factor(b), 1); else if (!signe(b)) P = gel(absZ_factor(a), 1); else { GEN A, B, v = Z_ppio(a,b), d = gel(v,1); /* = gcd(a,b) */ long k, l; if (is_pm1(d)) return cgetg(1, t_COL); A = gel(v,2); /* gcd(a, b^oo) */ B = diviiexact(b, Z_ppo(b, d)); /* gcd(b, a^oo) */ /* d = gcd(A,B) */ P = Z_cba(A, B); /* use coprime basis to help as much as possible */ l = lg(P); for (k = 1; k < l; k++) gel(P,k) = gel(Z_factor(gel(P,k)), 1); P = shallowconcat1(P); P = ZV_sort(P); } settyp(P, t_VEC); return P; } /* E/Q, integral model, Laska-Kraus-Connell algorithm. Set *pDP to a list * of known prime divisors of minimal discriminant */ static GEN get_u(GEN E, GEN *pDP) { pari_sp av; GEN D = ell_get_disc(E); GEN c4 = ell_get_c4(E); GEN c6 = ell_get_c6(E), g, u, P, DP; long l, k; P = Z_gcd_primes(c4, c6); l = lg(P); if (l == 1) { *pDP = P; return gen_1; } DP = vectrunc_init(l); settyp(DP,t_COL); av = avma; g = gcdii(sqri(c6), D); u = gen_1; for (k = 1; k < l; k++) { GEN p = gel(P, k); long vg = Z_pval(g, p), d = vg / 12, r = vg % 12; if (d) switch(itou_or_0(p)) { case 2: { long a, b; a = Mod16( shifti(c4, -4*d) ); b = Mod32( shifti(c6, -6*d) ); if ((b & 3) != 3 && (a || (b && b!=8))) { d--; r += 12; } break; } case 3: if (safe_Z_lval(c6,3) == 6*d+2) { d--; r += 12; } break; } if (r) vectrunc_append(DP, p); if (d) u = mulii(u, powiu(p, d)); } *pDP = DP; return gerepileuptoint(av, u); } /* Ensure a1 and a3 are 2-restricted and a2 is 3-restricted */ static GEN nfrestrict23(GEN nf, GEN E) { GEN a1 = nf_to_scalar_or_basis(nf, ell_get_a1(E)), A1, A2, A3, r, s, t; GEN a2 = nf_to_scalar_or_basis(nf, ell_get_a2(E)); GEN a3 = nf_to_scalar_or_basis(nf, ell_get_a3(E)); A1 = gmodgs(a1,2); s = gshift(gsub(A1,a1), -1); s = lift_if_rational(basistoalg(nf, s)); A2 = nfsub(nf, a2, nfmul(nf,s, nfadd(nf,a1,s))); r = gdivgs(gsub(gmodgs(A2,3), A2), 3); r = lift_if_rational(basistoalg(nf, r)); A3 = nfadd(nf, a3, nfmul(nf,r,A1)); t = nfadd(nf, nfmul(nf, r,s), gshift(gsub(gmodgs(A3,2), A3), -1)); t = lift_if_rational(basistoalg(nf, t)); return mkvec4(gen_1, r, s, t); } static GEN zk_capZ(GEN nf, GEN x) { GEN mx = zk_scalar_or_multable(nf, x); return (typ(mx) == t_INT)? mx: zkmultable_capZ(mx); } static GEN ellnf_c4c6_primes(GEN E) { GEN nf = ellnf_get_nf(E); GEN c4Z = zk_capZ(nf, ell_get_c4(E)); GEN c6Z = zk_capZ(nf, ell_get_c6(E)); return Z_gcd_primes(c4Z, c6Z); /* primes dividing (c4,c6) \cap Z */ } static GEN ellnf_D_primes(GEN E) { GEN nf = ellnf_get_nf(E); GEN P = ellnf_c4c6_primes(E); GEN DZ = zk_capZ(nf, ell_get_disc(E)); long k, l = lg(P); for (k = 1; k < l; k++) (void)Z_pvalrem(DZ, gel(P,k), &DZ); if (!is_pm1(DZ)) { GEN Q = gel(absZ_factor(DZ),1); settyp(Q, t_VEC); P = ZV_sort(shallowconcat(P, Q)); } return P; } /* convert vector of localreds to NF_MINIMALPRIMES */ static GEN Q_to_minimalprimes(GEN nf, GEN P, GEN Q) { GEN L, Lr, Ls, Lt, U; long k, l = lg(P); Lr = vectrunc_init(l); Ls = vectrunc_init(l); Lt = vectrunc_init(l); L = vectrunc_init(l); settyp(L,t_COL); U = vectrunc_init(l); settyp(U,t_COL); for (k = 1; k < l; k++) { GEN pr = gel(P, k), q = gel(Q, k), v, u; long vu; v = gel(q,3); u = gel(v,1); vu = nfval(nf, u, pr); if (!vu) continue; vectrunc_append(Lr, gel(v,2)); vectrunc_append(Ls, gel(v,3)); vectrunc_append(Lt, gel(v,4)); vectrunc_append(L, pr); vectrunc_append(U, stoi(vu)); } return mkvec5(L, U, Lr, Ls, Lt); } /* E integral */ static GEN ellminimalprimes(GEN E) { GEN S, nf, c4, c6, P, Q; long j, k, l; if ((S = obj_check(E, NF_MINIMALPRIMES))) return S; nf = ellnf_get_nf(E); c4 = nf_to_scalar_or_basis(nf, ell_get_c4(E)); c6 = nf_to_scalar_or_basis(nf, ell_get_c6(E)); if (typ(c4) == t_INT) c4 = NULL; if (typ(c6) == t_INT) c6 = NULL; P = nf_pV_to_prV(nf, ellnf_c4c6_primes(E)); Q = cgetg_copy(P, &l); for (k = j = 1; k < l; k++) { GEN pr = gel(P, k); if (c4 && !ZC_prdvd(c4,pr)) continue; if (c6 && !ZC_prdvd(c6,pr)) continue; gel(Q,j) = nflocalred(E, pr); /* pr | (c4,c6) */ gel(P,j++) = pr; } setlg(P,j); setlg(Q,j); return obj_insert(E, NF_MINIMALPRIMES, Q_to_minimalprimes(nf,P,Q)); } static GEN ellminimalnormu(GEN E0) { GEN E, S, L, U, P, v, Nu = NULL, nf = ellnf_get_nf(E0); long i, l; E = ellintegralmodel_i(E0, &v); S = ellminimalprimes(E); L = gel(S,1); U = gel(S,2); if (v) Nu = idealnorm(nf, gel(v,1)); P = cgetg_copy(L, &l); for (i = 1; i < l; i++) gel(P,i) = pr_norm(gel(L,i)); P = factorback2(P, U); if (Nu) P = gmul(Nu, P); return P; } /* E integral model; return change of variable to miminal model (t_VEC) * or (non-trivial) Weierstrass class (t_COL) */ static GEN bnf_get_v(GEN E) { GEN bnf = ellnf_get_bnf(E); GEN nf, L, Lr, Ls, Lt, F, C, U, R, S, T; if (!bnf) pari_err_TYPE("ellminimalmodel (need a bnf)", ellnf_get_nf(E)); S = ellminimalprimes(E); L = gel(S,1); U = gel(S,2); Lr = gel(S,3); Ls = gel(S,4); Lt = gel(S,5); F = isprincipalfact(bnf, NULL, L, U, nf_GEN); if (!gequal0(gel(F,1))) return gel(F,1); nf = bnf_get_nf(bnf); C = idealchinese(nf, mkmat2(L, ZC_z_mul(U,6)), NULL); U = basistoalg(nf, gel(F,2)); R = basistoalg(nf, idealchinese(nf, C, Lr)); S = basistoalg(nf, idealchinese(nf, C, Ls)); T = basistoalg(nf, idealchinese(nf, C, Lt)); return lift_if_rational(mkvec4(U,R,S,T)); } GEN ellminimaldisc(GEN E) { pari_sp av = avma; checkell(E); switch(ell_get_type(E)) { case t_ELL_Q: E = ellminimalmodel(E,NULL); return gerepileuptoint(av, absi_shallow(ell_get_disc(E))); case t_ELL_NF: { GEN nf = ellnf_get_nf(E), S, L, U, D; E = ellintegralmodel_i(E,NULL); S = ellminimalprimes(E); L = gel(S,1); U = ZC_z_mul(gel(S,2), 12); D = idealfactorback(nf, L, U, 0); return gerepileupto(av, idealdiv(nf, ell_get_disc(E), D)); } default: pari_err_TYPE("ellminimaldisc (E / number field)", E); return NULL; /*LCOV_EXCL_LINE*/ } } /* update Q_MINIMALMODEL entry in E, but don't update type-specific data on * ellminimalmodel(E) */ static GEN ellminimalmodel_i(GEN E, GEN *ptv) { GEN S, y, e, v, v0, u, DP; ellmin_t M; if ((S = obj_check(E, Q_MINIMALMODEL))) { if (lg(S) != 2) { E = gel(S,3); v = gel(S,2); } else v = init_ch(); if (ptv) *ptv = v; return gcopy(E); } e = ellintegralmodel_i(E, &v0); u = get_u(e, &DP); min_set_all(&M, e, u); v = min_get_v(&M, e); y = min_to_ell(&M, e); if (v0) { gcomposev(&v0, v); v = v0; } if (is_trivial_change(v)) { v = init_ch(); S = mkvec(DP); } else S = mkvec3(DP, v, y); obj_insert(E, Q_MINIMALMODEL, S); if (ptv) *ptv = v; return y; } static GEN ellQminimalmodel(GEN E, GEN *ptv) { pari_sp av = avma; GEN S, DP, v, y = ellminimalmodel_i(E, &v); if (!is_trivial_change(v)) ch_Q(y, E, v); S = obj_check(E, Q_MINIMALMODEL); DP = gel(S,1); obj_insert_shallow(y, Q_MINIMALMODEL, mkvec(DP)); if (!ptv) y = gerepilecopy(av, y); else { *ptv = v; gerepileall(av, 2, &y, ptv); } return y; } static GEN ellnfminimalmodel_i(GEN E, GEN *ptv) { GEN S, y, v, v2; if ((S = obj_check(E, NF_MINIMALMODEL))) { switch(lg(S)) { case 1: v = init_ch(); break; case 2: v = NULL; E = gel(S,1); break; default: E = gel(S,2); v = gel(S,1); break; } *ptv = v; return gcopy(E); } *ptv = NULL; y = ellintegralmodel_i(E, &v); v2 = bnf_get_v(y); if (typ(v2) == t_COL) { obj_insert(E, NF_MINIMALMODEL, mkvec(v2)); return v2; /* non-trivial Weierstrass class */ } y = coordch(y, v2); gcomposev(&v, v2); v2 = nfrestrict23(ellnf_get_nf(E), y); y = coordch(y, v2); /* copy to avoid inserting twice in y = E */ y = obj_reinit(y); gcomposev(&v, v2); if (is_trivial_change(v)) { v = init_ch(); S = cgetg(1,t_VEC); } else { v = lift_if_rational(v); S = mkvec2(v, y); } obj_insert(E, NF_MINIMALMODEL, S); *ptv = v; return y; } static GEN ellnfminimalmodel(GEN E, GEN *ptv) { pari_sp av = avma; GEN v, y = ellnfminimalmodel_i(E, &v); if (v) obj_insert_shallow(y, NF_MINIMALMODEL, cgetg(1,t_VEC)); if (!v || !ptv) y = gerepilecopy(av, y); else { *ptv = v; gerepileall(av, 2, &y, ptv); } return y; } GEN ellminimalmodel(GEN E, GEN *ptv) { checkell(E); switch(ell_get_type(E)) { case t_ELL_Q: return ellQminimalmodel(E, ptv); case t_ELL_NF: return ellnfminimalmodel(E, ptv); default: pari_err_TYPE("ellminimalmodel (E / number field)", E); return NULL; /*LCOV_EXCL_LINE*/ } } /* Reduction of a rational curve E to its standard minimal model, don't * update type-dependant components. * Set v = [u, r, s, t] = change of variable E -> minimal model, with u > 0 * Set gr = [N, [u,r,s,t], c, fa, L], where * N = arithmetic conductor of E * c = product of the local Tamagawa numbers cp * fa = factorization of N * L = list of localred(E,p) for p | N. */ static GEN ellQ_globalred(GEN e) { long k, l, iN; GEN S, c, E, L, P, NP, NE, D; E = ellminimalmodel_i(e, NULL); S = obj_check(e, Q_MINIMALMODEL); P = gel(S,1); l = lg(P); /* some known prime divisors of D */ D = ell_get_disc(E); for (k = 1; k < l; k++) (void)Z_pvalrem(D, gel(P,k), &D); if (!is_pm1(D)) P = ZV_sort( shallowconcat(P, gel(absZ_factor(D),1)) ); l = lg(P); c = gen_1; iN = 1; NP = cgetg(l, t_COL); NE = cgetg(l, t_COL); L = cgetg(l, t_VEC); for (k = 1; k < l; k++) { GEN p = gel(P,k), q = localred(E, p), ex = gel(q,1); if (!signe(ex)) continue; gel(NP, iN) = p; gel(NE, iN) = ex; gel(L, iN) = q; iN++; gel(q,3) = gen_0; /*delete variable change*/ c = mulii(c, gel(q,4)); } setlg(L, iN); setlg(NP, iN); setlg(NE, iN); return mkvec4(factorback2(NP,NE), c, mkmat2(NP,NE), L); } static GEN ellglobalred_i(GEN E) { return obj_checkbuild(E, Q_GLOBALRED, &ellQ_globalred); } static GEN Q_to_globalred(GEN nf, GEN P, GEN Q, GEN v) { GEN c, L, NP, NE; long j, k, l = lg(P); c = gen_1; NP = cgetg(l, t_COL); NE = cgetg(l, t_COL); L = cgetg(l, t_VEC); for (k = j = 1; k < l; k++) { GEN p = gel(P,k), q = gel(Q,k), ex; ex = gel(q,1); if (!signe(ex)) continue; gel(NP, j) = p; gel(NE, j) = ex; gel(L, j) = q; j++; c = mulii(c, gel(q,4)); } setlg(L, j); setlg(NP, j); setlg(NE, j); return mkvec5(idealfactorback(nf,NP,NE,0), v, c, mkmat2(NP,NE), L); } static GEN ellnfglobalred(GEN E0) { GEN E, P, Q, D, nf, v; long j, k, l; E = ellintegralmodel_i(E0, &v); if (!v) v = init_ch(); nf = ellnf_get_nf(E); P = nf_pV_to_prV(nf, ellnf_D_primes(E)); D = nf_to_scalar_or_basis(nf, ell_get_disc(E)); if (typ(D) == t_INT) D = NULL; Q = cgetg_copy(P, &l); for (k = j = 1; k < l; k++) { GEN p = gel(P,k); if (D && !ZC_prdvd(D, p)) continue; gel(Q,j) = nflocalred(E, p); gel(P,j++) = p; } setlg(P,j); setlg(Q,j); if (!obj_check(E0, NF_MINIMALPRIMES)) (void)obj_insert(E0, NF_MINIMALPRIMES, Q_to_minimalprimes(nf,P,Q)); return Q_to_globalred(nf,P,Q,v); } GEN ellglobalred(GEN E) { pari_sp av = avma; GEN S, gr, v; checkell(E); switch(ell_get_type(E)) { default: pari_err_TYPE("ellglobalred",E); case t_ELL_Q: gr = ellglobalred_i(E); S = obj_check(E, Q_MINIMALMODEL); v = (lg(S) == 2)? init_ch(): gel(S,2); v = mkvec5(gel(gr,1), v, gel(gr,2),gel(gr,3),gel(gr,4)); break; case t_ELL_NF: v = obj_checkbuild(E, NF_GLOBALRED, &ellnfglobalred); break; } return gerepilecopy(av, v); } static GEN doellrootno(GEN e); /* Return E = ellminimalmodel(e), but only update E[1..14]. * insert MINIMALMODEL, GLOBALRED, ROOTNO in both e (regular insertion) * and E (shallow insert) */ GEN ellanal_globalred(GEN e, GEN *ch) { GEN E, S, v = NULL; checkell_Q(e); if (!(S = obj_check(e, Q_MINIMALMODEL))) { E = ellminimalmodel_i(e, &v); S = obj_check(e, Q_MINIMALMODEL); obj_insert_shallow(E, Q_MINIMALMODEL, mkvec(gel(S,1))); } else if (lg(S) == 2) /* trivial change */ E = e; else { v = gel(S,2); E = gcopy(gel(S,3)); obj_insert_shallow(E, Q_MINIMALMODEL, mkvec(gel(S,1))); } if (ch) *ch = v; S = ellglobalred_i(e); if (E != e) obj_insert_shallow(E, Q_GLOBALRED, S); S = obj_check(e, Q_ROOTNO); if (!S) { S = doellrootno(E); obj_insert(e, Q_ROOTNO, S); /* insert in e */ } if (E != e) obj_insert_shallow(E, Q_ROOTNO, S); /* ... and in E */ return E; } static GEN ellQ_tamagawa(GEN e) { GEN red = ellglobalred(e), tam = gel(red,3); return (signe(ell_get_disc(e)) > 0)? shifti(tam,1): icopy(tam); } static GEN ellnf_tamagawa(GEN e) { GEN red = ellglobalred(e), tam = gel(red,3); GEN nf = ellnf_get_nf(e), s = nfsign(nf, ell_get_disc(e)); long r1, r2; nf_get_sign(nf, &r1, &r2); return shifti(tam, r2 + r1 - hammingweight(s)); } GEN elltamagawa(GEN E) { pari_sp av = avma; GEN v; checkell(E); switch(ell_get_type(E)) { default: pari_err_TYPE("elltamagawa",E); case t_ELL_Q: v = ellQ_tamagawa(E); break; case t_ELL_NF: v = ellnf_tamagawa(E); break; } return gerepileuptoint(av, v); } static GEN ellnf_get_nf_prec(GEN E, long prec) { GEN S, nf = ellnf_get_nf(E); if (nf_get_prec(nf) >= prec) return nf; if ((S = obj_check(E, NF_NF)) && nf_get_prec(S) >= prec) return S; return obj_insert(E, NF_NF, nfnewprec_shallow(nf, prec)); } /* true nf, use nf prec */ static GEN nfembedall(GEN nf, GEN x) { long r1, r2; GEN cx; nf_get_sign(nf,&r1,&r2); x = nf_to_scalar_or_basis(nf,x); if (typ(x) != t_COL) return const_vec(r1+r2, x); x = Q_primitive_part(x, &cx); x = RgM_RgC_mul(nf_get_M(nf), x); if (cx) x = RgC_Rg_mul(x,cx); return x; } static long nfembed_extraprec(GEN x) { long e = gexpo(x); return e < 8? 0: nbits2extraprec(e); } static GEN ellnfembed(GEN E, long prec) { GEN E0, nf = ellnf_get_nf(E), Eb = cgetg(6,t_VEC), e = cgetg(6,t_VEC), L, sD; long prec0 = prec, r1, r2, n, i; nf_get_sign(nf, &r1, &r2); n = r1+r2; E0 = RgC_to_nfC(nf, vecslice(E,1,5)); prec += nfembed_extraprec(E0); /* need accuracy 3b for bmodel to ensure roots are correct to b bits */ prec0 = prec; prec += (prec-2)*3 + nfembed_extraprec(E0); L = cgetg(n+1, t_VEC); sD = nfeltsign(nf, ell_get_disc(E), identity_perm(r1)); for(;;) { nf = ellnf_get_nf_prec(E, prec); for (i=1; i<=5; i++) gel(Eb,i) = nfembedall(nf,gel(E0,i)); for (i=1; i<=n; i++) { GEN Ei, r; long j; for (j=1; j<=5; j++) gel(e,j) = gmael(Eb,j,i); gel(L,i) = Ei = ellinit_Rg(e, i<=r1? signe(gel(sD,i)): 0, prec); if (!Ei) break; r = doellR_roots_i(Ei, prec, prec0); if (!r) break; } if (i > n) return L; prec = precdbl(prec); if (DEBUGLEVEL>1) pari_warn(warnprec,"ellnfembed", prec); } } static GEN ellpointnfembed(GEN E, GEN P, long prec) { GEN nf = ellnf_get_nf(E), Px, Py, L; long i, l; P = RgC_to_nfC(nf, P); prec += nfembed_extraprec(P); nf = ellnf_get_nf_prec(E, prec); Px = nfembedall(nf, gel(P,1)); Py = nfembedall(nf, gel(P,2)); l = lg(Px); L = cgetg(l, t_VEC); for(i = 1; i < l; i++) gel(L,i) = mkvec2(gel(Px,i), gel(Py,i)); return L; } static void ellnfembed_free(GEN L) { long i, l = lg(L); for(i = 1; i < l; i++) obj_free(gel(L,i)); } static GEN ellnf_vec_wrap(GEN (*fun)(GEN, long), GEN E, long prec) { pari_sp av = avma; GEN V = ellnfembed(E, prec); long i, l = lg(V); GEN P = cgetg(l, t_VEC); for(i=1; i 4) return 1; switch(kod) { case 1: return (v6>0) ? 2 : 1; case 2: if (vD==4) return 1; else { if (vD==7) return 3; else return v4==4 ? 2 : 4; } case 3: switch(vD) { case 6: return 3; case 8: return 4; case 9: return 5; default: return v4==5 ? 2 : 1; } case 4: return v4>4 ? 2 : 1; case -1: switch(vD) { case 9: return 2; case 10: return 4; default: return v4>4 ? 3 : 1; } case -2: switch(vD) { case 12: return 2; case 14: return 3; default: return 1; } case -3: switch(vD) { case 12: return 2; case 14: return 3; case 15: return 4; default: return 1; } case -4: return v6==7 ? 2 : 1; case -5: return (v6==7 || v4==6) ? 2 : 1; case -6: switch(vD) { case 12: return 2; case 13: return 3; default: return v4==6 ? 2 : 1; } case -7: return (vD==12 || v4==6) ? 2 : 1; default: return v4==6 ? 2 : 1; } } /* p = 3; v(c4), v(c6), v(D) for minimal model, +oo is coded by 12 */ static long neron_3(long v4, long v6, long vD, long kod) { if (labs(kod) > 4) return 1; switch(kod) { case -1: case 1: return v4&1 ? 2 : 1; case -3: case 3: return (2*v6>vD+3) ? 2 : 1; case -4: case 2: switch (vD%6) { case 4: return 3; case 5: return 4; default: return v6%3==1 ? 2 : 1; } default: /* kod = -2 et 4 */ switch (vD%6) { case 0: return 2; case 1: return 3; default: return 1; } } } static long ellrootno_2(GEN e) { long n2, kod, u, v, x1, y1, D1, vD, v4, v6; long d = get_vp_u_small(e, 2, &v6, &vD); if (!vD) return 1; if (d) { /* not minimal */ ellmin_t M; min_set_2(&M, e, d); min_set_D(&M, e); e = min_to_ell(&M, e); } val_init(e, 2,64,&v4,&u, &v6,&v, &vD,&D1); kod = kod_23(e,2); n2 = neron_2(v4,v6,vD, kod); if (kod>=5) { long a2, a3; a2 = ZtoF2(ell_get_a2(e)); a3 = ZtoF2(ell_get_a3(e)); return odd(a2 + a3) ? 1 : -1; } if (kod<-9) return (n2==2) ? -kross(-1,v) : -1; x1 = u+v+v; switch(kod) { case 1: return 1; case 2: switch(n2) { case 1: switch(v4) { case 4: return kross(-1,u); case 5: return 1; default: return -1; } case 2: return (v6==7) ? 1 : -1; case 3: return (v%8==5 || (u*v)%8==5) ? 1 : -1; case 4: if (v4>5) return kross(-1,v); return (v4==5) ? -kross(-1,u) : -1; } case 3: switch(n2) { case 1: return -kross(2,u*v); case 2: return -kross(2,v); case 3: y1 = (u - (v << (v6-5))) & 15; return (y1==7 || y1==11) ? 1 : -1; case 4: return (v%8==3 || (2*u+v)%8==7) ? 1 : -1; case 5: return v6==8 ? kross(2,x1) : kross(-2,u); } case -1: switch(n2) { case 1: return -kross(2,x1); case 2: return (v%8==7) || (x1%32==11) ? 1 : -1; case 3: return v4==6 ? 1 : -1; case 4: if (v4>6) return kross(-1,v); return v4==6 ? -kross(-1,u*v) : -1; } case -2: return n2==1 ? kross(-2,v) : kross(-1,v); case -3: switch(n2) { case 1: y1=(u-2*v)%64; if (y1<0) y1+=64; return (y1==3) || (y1==19) ? 1 : -1; case 2: return kross(2*kross(-1,u),v); case 3: return -kross(-1,u)*kross(-2*kross(-1,u),u*v); case 4: return v6==11 ? kross(-2,x1) : -kross(-2,u); } case -5: if (n2==1) return x1%32==23 ? 1 : -1; else return -kross(2,2*u+v); case -6: switch(n2) { case 1: return 1; case 2: return v6==10 ? 1 : -1; case 3: return (u%16==11) || ((u+4*v)%16==3) ? 1 : -1; } case -7: if (n2==1) return 1; else { y1 = (u + (v << (v6-8))) & 15; if (v6==10) return (y1==9 || y1==13) ? 1 : -1; else return (y1==9 || y1==5) ? 1 : -1; } case -8: return n2==2 ? kross(-1,v*D1) : -1; case -9: return n2==2 ? -kross(-1,D1) : -1; default: return -1; } } static long ellrootno_3(GEN e) { long n2, kod, u, v, D1, r6, K4, K6, vD, v4, v6; long d = get_vp_u_small(e, 3, &v6, &vD); if (!vD) return 1; if (d) { /* not minimal */ ellmin_t M; min_set_3(&M, e, d); min_set_a(&M); min_set_D(&M, e); e = min_to_ell(&M, e); } val_init(e, 3,81, &v4,&u, &v6,&v, &vD,&D1); kod = kod_23(e,3); K6 = kross(v,3); if (kod>4) return K6; n2 = neron_3(v4,v6,vD,kod); r6 = v%9; K4 = kross(u,3); switch(kod) { case 1: case 3: case -3: return 1; case 2: switch(n2) { case 1: return (r6==4 || r6>6) ? 1 : -1; case 2: return -K4*K6; case 3: return 1; case 4: return -K6; } case 4: switch(n2) { case 1: return K6*kross(D1,3); case 2: return -K4; case 3: return -K6; } case -2: return n2==2 ? 1 : K6; case -4: switch(n2) { case 1: if (v4==4) return (r6==4 || r6==8) ? 1 : -1; else return (r6==1 || r6==2) ? 1 : -1; case 2: return -K6; case 3: return (r6==2 || r6==7) ? 1 : -1; case 4: return K6; } default: return -1; } } /* p > 3. Don't assume that e is minimal or even integral at p */ static long ellrootno_p(GEN e, GEN p) { long nuj, nuD, nu; GEN D = ell_get_disc(e); long ep, z; nuD = Q_pval(D, p); if (!nuD) return 1; nuj = j_pval(e, p); nu = (nuD - nuj) % 12; if (nu == 0) { GEN c6; long d, vg; if (!nuj) return 1; /* good reduction */ /* p || N */ c6 = ell_get_c6(e); /* != 0 */ vg = minss(2*Q_pval(c6, p), nuD); d = vg / 12; if (d) { GEN q = powiu(p,6*d); c6 = (typ(c6) == t_INT)? diviiexact(c6, q): gdiv(c6, q); } if (typ(c6) != t_INT) c6 = Rg_to_Fp(c6,p); /* c6 in minimal model */ return -kronecker(negi(c6), p); } if (nuj) return krosi(-1,p); ep = 12 / ugcd(12, nu); if (ep==4) z = 2; else z = (ep&1) ? 3 : 1; return krosi(-z, p); } static GEN doellrootno(GEN e) { GEN V, P, S = ellglobalred_i(e); long i, l, s = -1; V = obj_check(e, Q_MINIMALMODEL); if (lg(V) != 2) e = gel(V,3); P = gmael(S,3,1); l = lg(P); V = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) { GEN p = gel(P,i); long t; switch(itou_or_0(p)) { case 2: t = ellrootno_2(e); break; case 3: t = ellrootno_3(e); break; default:t = ellrootno_p(e, p); } V[i] = t; if (t < 0) s = -s; } return mkvec2(stoi(s), V); } /* local epsilon factor at p (over Q), including p=0 for the infinite place. * Global if p==1 or NULL. */ static long ellQ_rootno(GEN e, GEN p) { pari_sp av = avma; GEN S; long s; if (!p || isint1(p)) return ellrootno_global(e); if (!signe(p)) return -1; /* local factor at infinity */ if ( (S = obj_check(e, Q_ROOTNO)) ) { GEN T = obj_check(e, Q_GLOBALRED), NP = gmael(T,3,1); long i = ZV_search(NP, p); if (i) { GEN V = gel(S,2); return V[i]; } return 1; } switch(itou_or_0(p)) { case 2: e = ellintegralmodel_i(e, NULL); s = ellrootno_2(e); break; case 3: e = ellintegralmodel_i(e, NULL); s = ellrootno_3(e); break; default: s = ellrootno_p(e,p); break; } avma = av; return s; } /* global root number over number field * Root numbers and parity of ranks of elliptic curves, Tim and Vladimir Dokchitser * https://arxiv.org/abs/0906.1815 */ static GEN ellrnfup(GEN rnf, GEN E, long prec) { long i; GEN Eb = cgetg(6, t_VEC); for(i=1; i<=5; i++) gel(Eb, i) = rnfeltup(rnf,gel(E, i)); return ellinit_nf(Eb, rnf_build_nfabs(rnf, prec)); } static GEN ellnf2isog(GEN E, GEN z) { long v = fetch_var_higher(); GEN S = deg1pol(gen_1, gneg(z), v); GEN E2 = ellisogeny(E, S, 1, -1, -1); delete_var(); return ellinit_nf(E2, ellnf_get_nf(E)); } static GEN ellnf_reladelicvolume(GEN E, GEN P, GEN z, long prec) { pari_sp av = avma; GEN nf = ellnf_get_nf(E); GEN rnf = rnfinit0(nf, P, 1); GEN Et = ellrnfup(rnf, E, prec); GEN E2 = ellnf2isog(Et, rnfeltreltoabs(rnf, z)); GEN c1 = ellnf_adelicvolume(Et, prec), c2 = ellnf_adelicvolume(E2, prec); obj_free(rnf); obj_free(Et); obj_free(E2); return gerepilecopy(av, mkvec2(c1,c2)); } static long rootnovalp(GEN z, ulong p, long prec) { return mpodd(ground(gdiv(glog(z, prec), glog(utoi(p),prec)))); } static GEN ec_bmodel_var(GEN E, long v) { GEN P = ec_bmodel(E); setvarn(P,v); return P; } static long ellnf_rootno_global(GEN E) { pari_sp av = avma; GEN nf = ellnf_get_nf(E); long prec = nf_get_prec(nf); long v, var = fetch_var_higher(); GEN F; E = ellintegralmodel_i(E, NULL); F = nfroots(nf, ec_bmodel_var(E, var)); if (lg(F)>1) { GEN Et = ellnf2isog(E, gel(F,1)); GEN cK = ellnf_adelicvolume(E, prec), cKt = ellnf_adelicvolume(Et, prec); obj_free(Et); v = rootnovalp(divrr(cK,cKt), 2, prec); } else { GEN D = deg2pol_shallow(gen_1, gen_0, gneg(ell_get_disc(E)), var); GEN P = RgX_divs(RgX_rescale(ec_bmodel_var(E, var), utoi(4)), 4); GEN c = ellnf_reladelicvolume(E, P, gmul2n(pol_x(var),-2), prec); GEN cL = gel(c,1), cLt = gel(c,2); GEN F = nfroots(nf, D); if (lg(F)>1) v = rootnovalp(divrr(cL,cLt), 2, prec); else { GEN cK = ellnf_adelicvolume(E, prec); GEN cp = nfcompositum(nf, P, D, 3); GEN cc = ellnf_reladelicvolume(E, gel(cp,1), gmul2n(gel(cp,2),-2), prec); GEN cF = gel(cc,1), cFt = gel(cc,2); GEN rnf = rnfinit0(nf,D,1); GEN Et = ellrnfup(rnf, E, prec); GEN cKv = ellnf_adelicvolume(Et, prec); long v2 = rootnovalp(divrr(gmul(cL,cF),gmul(cLt,cFt)), 2, prec); long v3 = rootnovalp(divrr(gmul(cF,gsqr(cK)),gmul(cKv,gsqr(cL))), 3, prec); obj_free(rnf); obj_free(Et); v = odd(v2+v3); } } delete_var(); avma = av; return v ? -1: 1; } static GEN doellnfrootno(GEN e) { return stoi(ellnf_rootno_global(e)); } long ellrootno_global(GEN e) { pari_sp av = avma; GEN S; switch(ell_get_type(e)) { case t_ELL_Q: S = gel(obj_checkbuild(e, Q_ROOTNO, &doellrootno),1); break; case t_ELL_NF: S = obj_checkbuild(e, NF_ROOTNO, &doellnfrootno); break; default: pari_err_TYPE("ellrootno", e); return 0; /*LCOV_EXCL_LINE*/ } avma = av; return itos(S); } long ellrootno(GEN e, GEN p) { checkell(e); if (p && typ(p) != t_INT) pari_err_TYPE("ellrootno", p); if (p && signe(p) < 0) pari_err_PRIME("ellrootno",p); switch(ell_get_type(e)) { case t_ELL_Q: return ellQ_rootno(e, p); default: pari_err_TYPE("ellrootno", e); case t_ELL_NF: if (p) pari_err_IMPL("local root number for number fields"); return ellrootno_global(e); } } /********************************************************************/ /** **/ /** TRACE OF FROBENIUS **/ /** **/ /********************************************************************/ /* assume p does not divide disc E */ long ellap_CM_fast(GEN E, ulong p, long CM) { ulong a4, a6; if (p == 2) return 3 - cardmod2(E); if (p == 3) return 4 - cardmod3(E); Fl_ell_to_a4a6(E, p, &a4, &a6); return Fl_elltrace_CM(CM, a4, a6, p); } static void checkell_int(GEN e) { checkell_Q(e); if (typ(ell_get_a1(e)) != t_INT || typ(ell_get_a2(e)) != t_INT || typ(ell_get_a3(e)) != t_INT || typ(ell_get_a4(e)) != t_INT || typ(ell_get_a6(e)) != t_INT) pari_err_TYPE("ellanQ [not an integral model]",e); } long ellQ_get_CM(GEN e) { GEN j = ell_get_j(e); long CM = 0; if (typ(j) == t_INT) switch(itos_or_0(j)) { case 0: if (!signe(j)) CM = -3; break; case 1728: CM = -4; break; case -3375: CM = -7; break; case 8000: CM = -8; break; case 54000: CM = -12; break; case -32768: CM = -11; break; case 287496: CM = -16; break; case -884736: CM = -19; break; case -12288000: CM = -27; break; case 16581375: CM = -28; break; case -884736000: CM = -43; break; #ifdef LONG_IS_64BIT case -147197952000L: CM = -67; break; case -262537412640768000L: CM = -163; break; #endif } return CM; } /* bad reduction at p */ static void sievep_bad(ulong p, GEN an, ulong n) { ulong m, N; switch (an[p]) /* (-c6/p) */ { case -1: /* non-split */ N = n/p; for (m=2; m<=N; m++) if (an[m] != LONG_MAX) an[m*p] = -an[m]; break; case 0: /* additive */ for (m=2*p; m<=n; m+=p) an[m] = 0; break; case 1: /* split */ N = n/p; for (m=2; m<=N; m++) if (an[m] != LONG_MAX) an[m*p] = an[m]; break; } } /* good reduction at p */ static void sievep_good(ulong p, GEN an, ulong n, ulong SQRTn) { const long ap = an[p]; ulong m; if (p <= SQRTn) { ulong pk, oldpk = 1; for (pk=p; pk <= n; oldpk=pk, pk *= p) { if (pk != p) an[pk] = ap * an[oldpk] - p * an[oldpk/p]; for (m = n/pk; m > 1; m--) if (an[m] != LONG_MAX && m%p) an[m*pk] = an[m] * an[pk]; } } else { for (m = n/p; m > 1; m--) if (an[m] != LONG_MAX) an[m*p] = ap * an[m]; } } static void sievep(ulong p, GEN an, ulong n, ulong SQRTn, int good_red) { if (good_red) sievep_good(p, an, n, SQRTn); else sievep_bad(p, an, n); } static long ellan_get_ap(ulong p, int *good_red, int CM, GEN e) { if (!umodiu(ell_get_disc(e),p)) /* p|D, bad reduction or non-minimal model */ return ellQap_u(e, p, good_red); else /* good reduction */ { *good_red = 1; return ellap_CM_fast(e, p, CM); } } GEN ellanQ_zv(GEN e, long n0) { pari_sp av; ulong p, SQRTn, n = (ulong)n0; GEN an; int CM; if (n0 <= 0) return cgetg(1,t_VEC); if (n >= LGBITS) pari_err_IMPL( stack_sprintf("ellan for n >= %lu", LGBITS) ); e = ellintegralmodel_i(e,NULL); SQRTn = usqrt(n); CM = ellQ_get_CM(e); an = const_vecsmall(n, LONG_MAX); an[1] = 1; av = avma; for (p=2; p<=n; p++) { int good_red; if (an[p] != LONG_MAX) continue; /* p not prime */ an[p] = ellan_get_ap(p, &good_red, CM, e); sievep(p, an, n, SQRTn, good_red); } avma = av; return an; } static GEN ellanQ(GEN e, long N) { return vecsmall_to_vec_inplace(ellanQ_zv(e,N)); } static GEN ellnflocal(void *S, GEN p, long n) { pari_sp av = avma; GEN E = (GEN)S; GEN LP = idealprimedec_limit_f(ellnf_get_nf(E), p, n-1), T = NULL; long l = lg(LP), i; for (i = 1; i < l; i++) { int goodred; GEN P = gel(LP,i), T2; GEN ap = ellnfap(E, P, &goodred); long f = pr_get_f(P); if (goodred) T2 = mkpoln(3, pr_norm(P), negi(ap), gen_1); else { if (!signe(ap)) continue; T2 = deg1pol_shallow(negi(ap), gen_1, 0); } if (f > 1) T2 = RgX_inflate(T2, f); T = T? ZX_mul(T, T2): T2; } if (!T) { avma = av; return pol_1(0); } return gerepileupto(av, RgXn_inv_i(T, n)); } static GEN ellnfan(GEN E, long N) { return direuler_bad((void*)E, &ellnflocal, gen_2, stoi(N), NULL, NULL); } GEN ellan(GEN E, long N) { checkell(E); switch(ell_get_type(E)) { case t_ELL_Q: return ellanQ(E, N); case t_ELL_NF: return ellnfan(E, N); default: pari_err_TYPE("ellan",E); return NULL; /*LCOV_EXCL_LINE*/ } } static GEN apk_good(GEN ap, GEN p, long e) { GEN u, v, w; long j; if (e == 1) return ap; u = ap; w = subii(sqri(ap), p); for (j=3; j<=e; j++) { v = u; u = w; w = subii(mulii(ap,u), mulii(p,v)); } return w; } GEN akell(GEN e, GEN n) { long i, j, s; pari_sp av = avma; GEN fa, P, E, D, u, y; checkell_int(e); if (typ(n) != t_INT) pari_err_TYPE("akell",n); if (signe(n)<= 0) return gen_0; if (gequal1(n)) return gen_1; D = ell_get_disc(e); u = Z_ppo(n, D); y = gen_1; s = 1; if (!equalii(u, n)) { /* bad reduction at primes dividing n/u */ fa = Z_factor(diviiexact(n, u)); P = gel(fa,1); E = gel(fa,2); for (i=1; i 0) { GEN a0=a; x = gsub(x, b); a = gneg(b); b = gsub(a0, b); } a = gsqrt(gneg(a), prec); b = gsqrt(gneg(b), prec); /* compute height on isogenous curve E1 ~ E0 */ for(n=0;; n++) { GEN p1, p2, ab, a0 = a; a = gmul2n(gadd(a0,b), -1); r = gsub(a, a0); if (gequal0(r) || gexpo(r) < ex) break; ab = gmul(a0, b); b = gsqrt(ab, prec); p1 = gmul2n(gsub(x, ab), -1); p2 = gsqr(a); x = gadd(p1, gsqrt(gadd(gsqr(p1), gmul(x, p2)), prec)); V = shallowconcat(V, gadd(x, p2)); } if (n) { x = gel(V,n); while (--n > 0) x = gdiv(gsqr(x), gel(V,n)); } else x = gadd(x, gsqr(a)); /* height on E1 is log(x)/2. Go back to E0 */ return flag? gsqr(gdiv(gsqr(x), x_a)): gdiv(x, sqrtr(mpabs_shallow(x_a))); } /* is P \in E(R)^0, the neutral component ? */ static int ellR_on_neutral(GEN E, GEN P, long prec) { GEN x = gel(P,1), e1 = ellR_root(E, prec); return gcmp(x, e1) >= 0; } /* hoo + 1/2 log(den(x)) */ static GEN hoo_aux(GEN E, GEN z, GEN d, long prec) { pari_sp av = avma; GEN h; if (!ellR_on_neutral(E, z, prec)) { GEN eh = exphellagm(E, elladd(E, z,z), 0, prec); /* h_oo(2P) = 4h_oo(P) - log |2y + a1x + a3| */ h = gmul(eh, gabs(ec_dmFdy_evalQ(E, z), prec)); } else h = exphellagm(E, z, 1, prec); if (!is_pm1(d)) h = gmul(h, sqri(d)); return gerepileuptoleaf(av, gmul2n(mplog(h), -2)); } GEN ellheightoo(GEN E, GEN z, long prec) { return hoo_aux(E, z, gen_1, prec); } /* Formula from Silverman GTM 151 Theorem 3.2 page 466 */ static GEN ellheight_C(GEN E, GEN P, long prec) { pari_sp av = avma; GEN z = zell(E, P, prec); GEN per = ellperiods(E, 1, prec); GEN w = gel(per,1), w1 = gel(w,1), w2 = gel(w, 2), w1c = conj_i(w1); GEN e = gel(per,2), e1 = gel(e,1), e2 = gel(e, 2); GEN D = gsub(gmul(w1, conj_i(w2)),gmul(w1c, w2)); GEN b = gdiv(gsub(gmul(w1, conj_i(z)),gmul(w1c, z)), D); GEN a = gdiv(gsub(z, gmul(b, w2)), w1); GEN eta = gadd(gmul(a, e1), gmul(b, e2)); GEN r = gmul2n(real_i(gmul(z, eta)), -1); GEN l = real_i(ellsigma(per, z, 1, prec)); return gerepileupto(av, gsub(r, l)); } static GEN _hell(GEN E, GEN p, long n, GEN P) { return p? ellpadicheight(E,p,n, P): ellheight(E,P,n); } static GEN ellheightpairing(GEN E, GEN p, long n, GEN P, GEN Q) { pari_sp av = avma; GEN a = _hell(E,p,n, elladd(E,P,Q)); GEN b = _hell(E,p,n, ellsub(E,P,Q)); return gerepileupto(av, gmul2n(gsub(a,b), -2)); } GEN ellheight0(GEN e, GEN a, GEN b, long n) { return b? ellheightpairing(e,NULL,n, a,b): ellheight(e,a,n); } GEN ellpadicheight0(GEN e, GEN p, long n, GEN P, GEN Q) { return Q? ellheightpairing(e,p,n, P,Q): ellpadicheight(e,p,n, P); } static GEN ellnf_localheight(GEN e, GEN P, GEN pr) { long v1, v2, vD, vu; GEN nf = ellnf_get_nf(e); GEN lr = nflocalred(e,pr); GEN k = gel(lr, 2), urst = gel(lr, 3), u = gel(urst, 1); GEN E = ellchangecurve(e, urst); GEN Q = ellchangepoint(P, urst); GEN v; vu = nfval(nf, u, pr); v1 = nfval(nf, ec_dFdx_evalQ(E, Q), pr); v2 = nfval(nf, ec_dmFdy_evalQ(E, Q), pr); vD = nfval(nf, ell_get_disc(E), pr); if (v1<0) vu = 0; if (v1<=0 || v2<=0) v = gen_0; else if (cmpis(k,5) >= 0) { GEN a = gdivsg(minss(2*v2,vD),mulss(2,vD)); v = gmul(gsub(gsqr(a),a),gdivgs(stoi(vD),2)); } else { long v3 = nfval(nf, ec_3divpol_evalx(E, gel(Q,1)), pr); v = (v2=3*v2) ? gdivgs(stoi(v2),-3): gdivgs(stoi(v3),-8); } return gsubgs(v,vu); } static GEN ellnf_height(GEN E, GEN P, long prec) { pari_sp av = avma; GEN x, nf, disc, d, F, Ee, Pe, s; long i, n, l, r1; if (signe(ellorder(E, P, NULL))) return gen_0; x = gel(P,1); if (gequal0(ec_2divpol_evalx(E, x))) { avma = av; return gen_0; } nf = ellnf_get_nf(E); r1 = nf_get_r1(nf); disc = ell_get_disc(E); d = idealnorm(nf, gel(idealnumden(nf, x), 2)); F = gel(idealfactor(nf, disc), 1); Ee = ellnfembed(E, prec); Pe = ellpointnfembed(E, P, prec); n = lg(Ee); l = lg(F); s = gmul2n(glog(d, prec), -1); for (i=1; i<=r1; i++) s = gadd(s, ellheightoo(gel(Ee, i), gel(Pe, i), prec)); for ( ; i N) n = N; u = n * ((N<<1) - n); v = N << 3; } else { n2 = Z_pval(psi2, p); n = Z_pval(psi3, p); if (n >= 3*n2) { u = n2; v = 3; } else { u = n; v = 8; } } /* z -= u log(p) / v */ z = gsub(z, divru(mulur(u, logr_abs(itor(p,prec))), v)); } return gerepileupto(av, gmul2n(z, 1)); } GEN ellheight(GEN e, GEN a, long prec) { checkell(e); checkellpt(a); switch(ell_get_type(e)) { case t_ELL_Q: return ellQ_height(e, a, prec); default: pari_err_TYPE("ellheight", e); case t_ELL_NF: return ellnf_height(e, a, prec); } } GEN ellpadicheightmatrix(GEN e, GEN p, long n, GEN x) { GEN D, A, B; long lx = lg(x), i, j; pari_sp av = avma; if (!is_vec_t(typ(x))) pari_err_TYPE("ellheightmatrix",x); D = cgetg(lx,t_VEC); A = cgetg(lx,t_MAT); B = cgetg(lx,t_MAT); for (i=1; i minq, then the list of potential orders in ellsea will not contain * an ambiguity => oo-loop. E.g. ellsea(ellinit([1,519],523)) */ GEN ellsea(GEN E, long smallfact) { const ulong minq = 523; checkell_Fq(E); switch(ell_get_type(E)) { case t_ELL_Fp: { GEN p = ellff_get_field(E), e = ellff_get_a4a6(E); if (abscmpiu(p, minq) <= 0) return Fp_ellcard(gel(e,1), gel(e,2), p); return Fp_ellcard_SEA(gel(e,1), gel(e,2), p, smallfact); } case t_ELL_Fq: { GEN fg = ellff_get_field(E); if (abscmpiu(FF_p_i(fg), 7) <= 0 || abscmpiu(FF_q(fg), minq) <= 0) return FF_ellcard(E); return FF_ellcard_SEA(E, smallfact); } } return NULL; /*LCOV_EXCL_LINE*/ } GEN ellff_get_card(GEN E) { return obj_checkbuild(E, FF_CARD, &doellcard); } GEN ellcard(GEN E, GEN p) { p = checkellp(&E, p, NULL, "ellcard"); switch(ell_get_type(E)) { case t_ELL_Fp: case t_ELL_Fq: return icopy(ellff_get_card(E)); case t_ELL_Qp: case t_ELL_Q: { pari_sp av = avma; int goodred; GEN N = ellcard_ram(E, p, &goodred); if (!goodred) N = subiu(N, 1); /* remove singular point */ return gerepileuptoint(av, N); } case t_ELL_NF: { pari_sp av = avma; int goodred; GEN N = subii(pr_norm(p), ellnfap(E, p, &goodred)); if (goodred) N = addiu(N, 1); return gerepileuptoint(av, N); } default: pari_err_TYPE("ellcard",E); return NULL; /*LCOV_EXCL_LINE*/ } } /* assume model is p-minimal */ static GEN ellgroup_m(GEN E, GEN p, GEN *pm) { GEN a4, a6, N = ellcard(E, p); /* #E^ns(Fp) */ *pm = gen_1; if (equali1(N)) return cgetg(1,t_VEC); if (absequaliu(p, 2)) return mkvec(N); if (absequaliu(p, 3)) { /* The only possible non-cyclic group is [2,2] which happens 9 times */ ulong b2, b4, b6; if (!absequaliu(N, 4)) return mkvec(N); /* If the group is not cyclic, T = 4x^3 + b2 x^2 + 2b4 x + b6 * must have 3 roots else 1 root. Test T(0) = T(1) = 0 mod 3 */ b6 = Rg_to_Fl(ell_get_b6(E), 3); if (b6) return mkvec(N); /* b6 = T(0) = 0 mod 3. Test T(1) */ b2 = Rg_to_Fl(ell_get_b2(E), 3); b4 = Rg_to_Fl(ell_get_b4(E), 3); if ((1 + b2 + (b4<<1)) % 3) return mkvec(N); return mkvec2s(2, 2); } /* Now assume p > 3 */ ell_to_a4a6(E, p, &a4,&a6); return Fp_ellgroup(a4,a6,N,p, pm); } static GEN doellGm(GEN E) { GEN fg = ellff_get_field(E); GEN m, G = (typ(fg) == t_FFELT)? FF_ellgroup(E, &m): ellgroup_m(E, fg, &m); return mkvec2(G, m); } static GEN ellff_Gm(GEN E) { return obj_checkbuild(E, FF_GROUP, &doellGm); } GEN ellff_get_group(GEN E) { return gel(ellff_Gm(E), 1); } GEN ellff_get_m(GEN E) { return gel(ellff_Gm(E), 2); } GEN ellff_get_D(GEN E) { GEN G = ellff_get_group(E), o = ellff_get_o(E); switch(lg(G)) { case 1: return G; case 2: return mkvec(o); default: return mkvec2(o, gel(G,2)); } } /* E / Fp */ static GEN doellgens(GEN E) { GEN fg = ellff_get_field(E); if (typ(fg)==t_FFELT) return FF_ellgens(E); else { GEN F, p = fg, e = ellff_get_a4a6(E); F = Fp_ellgens(gel(e,1),gel(e,2),gel(e,3), ellff_get_D(E),ellff_get_m(E),p); return FpVV_to_mod(F,p); } } GEN ellff_get_gens(GEN E) { return obj_checkbuild(E, FF_GROUPGEN, &doellgens); } GEN ellgroup(GEN E, GEN p) { pari_sp av = avma; GEN m, G; p = checkellp(&E,p, NULL, "ellgroup"); switch(ell_get_type(E)) { case t_ELL_Fp: case t_ELL_Fq: G = ellff_get_group(E); break; case t_ELL_Qp: case t_ELL_Q: if (Z_pval(Q_numer(ell_get_disc(E)), p)) { GEN Q = localred(E,p), kod = gel(Q,2); E = ellchangecurve(E, gel(Q,3)); if (!equali1(kod)) { G = mkvec(ellcard(E,p)); break; } } G = ellgroup_m(E,p,&m); break; case t_ELL_NF: if (nfval(ellnf_get_nf(E), ell_get_disc(E), p)) { GEN Q = nflocalred(E,p), kod = gel(Q,2); E = ellchangecurve(E, gel(Q,3)); if (!equali1(kod)) { G = mkvec(ellcard(E,p)); break; } } E = ellinit(E, p, 0); G = ellff_get_group(E); G = gcopy(G); obj_free(E); break; default: pari_err_TYPE("ellgroup", E); return NULL;/*LCOV_EXCL_LINE*/ } return gerepilecopy(av, G); } GEN ellgroup0(GEN E, GEN p, long flag) { pari_sp av = avma; long tE, freeE = 0; GEN G; if (flag==0) return ellgroup(E, p); if (flag!=1) pari_err_FLAG("ellgroup"); checkell(E); tE = ell_get_type(E); if (tE != t_ELL_Fp && tE != t_ELL_Fq) { GEN Q = elllocalred(E, p), v = gel(Q,3), u = gel(v,1), kod = gel(Q,2); long vu; switch(tE) { case t_ELL_Qp: p = ellQp_get_p(E);/*fall through*/ case t_ELL_Q: vu = Q_pval(u, p); break; case t_ELL_NF: vu = nfval(ellnf_get_nf(E), u, p); break; default: pari_err_TYPE("ellgroup", E); vu = 0; } if (vu) pari_err_TYPE("ellgroup [not a p-minimal curve]",E); if (!equali1(kod)) /* bad reduction */ { GEN Ep = obj_init(15, 4), T = NULL, q = p, ap = ellap(E,p); if (typ(p) == t_INT) { long i; for (i = 1; i <= 12; i++) gel(Ep,i) = gel(E,i); } else { q = pr_norm(p); Ep = initsmall_i(ellnf_to_Fq(ellnf_get_nf(E), E, p, &p, &T), 4); } E = FF_ellinit(Ep, Tp_to_FF(T, p)); /* singular curve */ obj_insert(E, FF_CARD, subii(q, ap)); } else E = ellinit(E, p, 0); freeE = 1; } G = mkvec3(ellff_get_card(E), ellff_get_group(E), ellff_get_gens(E)); if (!freeE) return gerepilecopy(av, G); G = gcopy(G); obj_free(E); return gerepileupto(av, G); } GEN ellgenerators(GEN E) { checkell(E); switch(ell_get_type(E)) { case t_ELL_Q: return obj_checkbuild(E, Q_GROUPGEN, &elldatagenerators); case t_ELL_Fp: case t_ELL_Fq: return gcopy(ellff_get_gens(E)); default: pari_err_TYPE("ellgenerators",E); return NULL;/*LCOV_EXCL_LINE*/ } } /* char != 2,3, j != 0, 1728 */ static GEN ellfromj_simple(GEN j) { pari_sp av = avma; GEN k = gsubsg(1728,j), kj = gmul(k, j), k2j = gmul(kj, k); GEN E = zerovec(5); gel(E,4) = gmulsg(3,kj); gel(E,5) = gmulsg(2,k2j); return gerepileupto(av, E); } GEN ellfromj(GEN j) { GEN T = NULL, p = typ(j)==t_FFELT? FF_p_i(j): NULL; /* trick: use j^0 to get 1 in the proper base field */ if ((p || (Rg_is_FpXQ(j,&T,&p) && p)) && lgefint(p) == 3) switch(p[2]) { case 2: if (gequal0(j)) retmkvec5(gen_0,gen_0, gpowgs(j,0), gen_0,gen_0); else retmkvec5(gpowgs(j,0),gen_0,gen_0, gen_0,ginv(j)); case 3: if (gequal0(j)) retmkvec5(gen_0,gen_0,gen_0, gpowgs(j,0), gen_0); else { GEN E = zerovec(5); pari_sp av = avma; gel(E,5) = gerepileupto(av, gneg(gsqr(j))); gel(E,2) = gcopy(j); return E; } } if (gequal0(j)) retmkvec5(gen_0,gen_0,gen_0,gen_0, gpowgs(j,0)); if (gequalgs(j,1728)) retmkvec5(gen_0,gen_0,gen_0, gpowgs(j,0), gen_0); return ellfromj_simple(j); } /********************************************************************/ /** **/ /** IS SUPERSINGULAR **/ /** **/ /********************************************************************/ int elljissupersingular(GEN x) { pari_sp av = avma; int res; if (typ(x) == t_INTMOD) { GEN p = gel(x, 1); GEN j = gel(x, 2); res = Fp_elljissupersingular(j, p); } else if (typ(x) == t_FFELT) { GEN j = FF_to_FpXQ_i(x); GEN p = FF_p_i(x); GEN T = FF_mod(x); res = FpXQ_elljissupersingular(j, T, p); } else { pari_err_TYPE("elljissupersingular", x); return 0; /*LCOV_EXCL_LINE*/ } avma = av; return res; } int ellissupersingular(GEN E, GEN p) { pari_sp av; GEN j; int res; if (typ(E)!=t_VEC && !p) return elljissupersingular(E); p = checkellp(&E, p, NULL, "ellissupersingular"); j = ell_get_j(E); switch(ell_get_type(E)) { case t_ELL_Fp: case t_ELL_Fq: return elljissupersingular(j); case t_ELL_Qp: case t_ELL_Q: if (typ(j)==t_FRAC && dvdii(gel(j,2), p)) return 0; av = avma; res = Fp_elljissupersingular(Rg_to_Fp(j, p), p); avma = av; return res; case t_ELL_NF: { GEN modP, T, nf = ellnf_get_nf(E), pr = p; av = avma; j = nf_to_scalar_or_basis(nf, j); if (dvdii(Q_denom(j), pr_get_p(pr))) { if (typ(j) == t_FRAC || nfval(nf, j, pr) < 0) return 0; modP = nf_to_Fq_init(nf,&pr,&T,&p); } else modP = zk_to_Fq_init(nf,&pr,&T,&p); j = nf_to_Fq(nf, j, modP); if (typ(j) == t_INT) res = Fp_elljissupersingular(j, p); else res = FpXQ_elljissupersingular(j, T, p); avma = av; return res; } default: pari_err_TYPE("ellissupersingular",E); } return 0; /*LCOV_EXCL_LINE*/ } /* n <= 4, N is the characteristic of the base ring or NULL (char 0) */ static GEN elldivpol4(GEN e, GEN N, long n, long v) { GEN b2,b4,b6,b8, res; if (n==0) return pol_0(v); if (n<=2) return N? scalarpol_shallow(mkintmod(gen_1,N),v): pol_1(v); b2 = ell_get_b2(e); b4 = ell_get_b4(e); b6 = ell_get_b6(e); b8 = ell_get_b8(e); if (n==3) res = mkpoln(5, N? modsi(3,N): utoi(3),b2,gmulsg(3,b4),gmulsg(3,b6),b8); else { GEN b10 = gsub(gmul(b2, b8), gmul(b4, b6)); GEN b12 = gsub(gmul(b8, b4), gsqr(b6)); res = mkpoln(7, N? modsi(2,N): gen_2,b2,gmulsg(5,b4),gmulsg(10,b6),gmulsg(10,b8),b10,b12); } setvarn(res, v); return res; } /* T = (2y + a1x + a3)^4 modulo the curve equation. Store elldivpol(e,n,v) * in t[n]. N is the caracteristic of the base ring or NULL (char 0) */ static GEN elldivpol0(GEN e, GEN t, GEN N, GEN T, long n, long v) { GEN ret; long m = n/2; if (gel(t,n)) return gel(t,n); if (n<=4) ret = elldivpol4(e, N, n, v); else if (odd(n)) { GEN t1 = RgX_mul(elldivpol0(e,t,N,T,m+2,v), gpowgs(elldivpol0(e,t,N,T,m,v),3)); GEN t2 = RgX_mul(elldivpol0(e,t,N,T,m-1,v), gpowgs(elldivpol0(e,t,N,T,m+1,v),3)); if (odd(m))/*f_{4l+3} = f_{2l+3}f_{2l+1}^3 - T f_{2l}f_{2l+2}^3, m=2l+1*/ ret = RgX_sub(t1, RgX_mul(T,t2)); else /*f_{4l+1} = T f_{2l+2}f_{2l}^3 - f_{2l-1}f_{2l+1}^3, m=2l*/ ret = RgX_sub(RgX_mul(T,t1), t2); } else { /* f_2m = f_m(f_{m+2}f_{m-1}^2 - f_{m-2}f_{m+1}^2) */ GEN t1 = RgX_mul(elldivpol0(e,t,N,T,m+2,v), RgX_sqr(elldivpol0(e,t,N,T,m-1,v))); GEN t2 = RgX_mul(elldivpol0(e,t,N,T,m-2,v), RgX_sqr(elldivpol0(e,t,N,T,m+1,v))); ret = RgX_mul(elldivpol0(e,t,N,T,m,v), RgX_sub(t1,t2)); } gel(t,n) = ret; return ret; } GEN elldivpol(GEN e, long n, long v) { pari_sp av = avma; GEN f, D, N; checkell(e); D = ell_get_disc(e); if (v==-1) v = 0; if (varncmp(gvar(D), v) <= 0) pari_err_PRIORITY("elldivpol", e, "<=", v); N = characteristic(D); if (!signe(N)) N = NULL; if (n<0) n = -n; if (n==1 || n==3) f = elldivpol4(e, N, n, v); else { GEN d2 = ec_bmodel(e); /* (2y + a1x + 3)^2 mod E */ setvarn(d2,v); if (N && !mod2(N)) { gel(d2,5) = modsi(4,N); d2 = normalizepol(d2); } if (n <= 4) f = elldivpol4(e, N, n, v); else f = elldivpol0(e, const_vec(n,NULL), N,RgX_sqr(d2), n, v); if (n%2==0) f = RgX_mul(f, d2); } return gerepilecopy(av, f); } /* return [phi_n, (psi_n)^2] such that x[nP] = phi_n / (psi_n)^2 */ GEN ellxn(GEN e, long n, long v) { pari_sp av = avma; GEN d2, D, N, A, B; checkell(e); D = ell_get_disc(e); if (v==-1) v = 0; if (varncmp(gvar(D), v) <= 0) pari_err_PRIORITY("elldivpol", e, "<=", v); N = characteristic(D); if (!signe(N)) N = NULL; if (n < 0) n = -n; d2 = ec_bmodel(e); /* (2y + a1x + 3)^2 mod E */ setvarn(d2,v); if (N && !mod2(N)) { gel(d2,5) = modsi(4,N); d2 = normalizepol(d2); } if (n == 0) { A = pol_0(v); B = pol_0(v); } else if (n == 1) { A = pol_1(v); B = pol_x(v); } else if (n == 2) { GEN b4 = ell_get_b4(e); GEN b6 = ell_get_b6(e); GEN b8 = ell_get_b8(e); A = d2; /* phi_2 = x^4 - b4*x^2 - 2b6*x - b8 */ B = mkpoln(5, gen_1, gen_0, gneg(b4), gmul2n(gneg(b6),1), gneg(b8)); setvarn(B,v); } else { GEN t = const_vec(n+1,NULL), T = RgX_sqr(d2); GEN f = elldivpol0(e, t, N, T, n, v); /* f_n / d2^(n odd)*/ GEN g = elldivpol0(e, t, N, T, n-1, v); /* f_{n-1} / d2^(n even) */ GEN h = elldivpol0(e, t, N, T, n+1, v); /* f_{n+1} / d2^(n even) */ GEN f2 = RgX_sqr(f), u = RgX_mul(g,h); if (!odd(n)) A = RgX_mul(f2, d2); else { A = f2; u = RgX_mul(u,d2); } /* A = psi_n^2, u = psi_{n-1} psi_{n+1} */ B = RgX_sub(RgX_shift(A,1), u); } return gerepilecopy(av, mkvec2(B,A)); } pari-2.11.2/src/basemath/gen2.c0000644000175000017500000021304313326135265014541 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** GENERIC OPERATIONS **/ /** (second part) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /*********************************************************************/ /** **/ /** MAP FUNCTIONS WITH GIVEN PROTOTYPES **/ /** **/ /*********************************************************************/ GEN map_proto_G(GEN (*f)(GEN), GEN x) { if (is_matvec_t(typ(x))) { long lx, i; GEN y = cgetg_copy(x, &lx); for (i=1; i long */ /* */ /*******************************************************************/ long gtolong(GEN x) { switch(typ(x)) { case t_INT: return itos(x); case t_REAL: return (long)(rtodbl(x) + 0.5); case t_FRAC: { pari_sp av = avma; long y = itos(ground(x)); avma = av; return y; } case t_COMPLEX: if (gequal0(gel(x,2))) return gtolong(gel(x,1)); break; case t_QUAD: if (gequal0(gel(x,3))) return gtolong(gel(x,2)); break; } pari_err_TYPE("gtolong",x); return 0; /* LCOV_EXCL_LINE */ } /*******************************************************************/ /* */ /* COMPARISONS */ /* */ /*******************************************************************/ int isexactzero(GEN g) { long i, lx; switch (typ(g)) { case t_INT: return !signe(g); case t_INTMOD: return !signe(gel(g,2)); case t_COMPLEX: return isexactzero(gel(g,1)) && isexactzero(gel(g,2)); case t_FFELT: return FF_equal0(g); case t_QUAD: return isexactzero(gel(g,2)) && isexactzero(gel(g,3)); case t_POLMOD: return isexactzero(gel(g,2)); case t_POL: lx = lg(g); /* cater for Mod(0,2)*x^0 */ return lx == 2 || (lx == 3 && isexactzero(gel(g,2))); case t_RFRAC: return isexactzero(gel(g,1)); /* may occur: Mod(0,2)/x */ case t_VEC: case t_COL: case t_MAT: for (i=lg(g)-1; i; i--) if (!isexactzero(gel(g,i))) return 0; return 1; } return 0; } GEN gisexactzero(GEN g) { long i, lx; GEN a, b; switch (typ(g)) { case t_INT: return !signe(g)? g: NULL; case t_INTMOD: return !signe(gel(g,2))? g: NULL; case t_COMPLEX: a = gisexactzero(gel(g,1)); if (!a) return NULL; b = gisexactzero(gel(g,2)); if (!b) return NULL; return ggcd(a,b); case t_FFELT: return FF_equal0(g)? g: NULL; case t_QUAD: a = gisexactzero(gel(g,2)); if (!a) return NULL; b = gisexactzero(gel(g,3)); if (!b) return NULL; return ggcd(a,b); case t_POLMOD: return gisexactzero(gel(g,2)); case t_POL: lx = lg(g); /* cater for Mod(0,2)*x^0 */ if (lx == 2) return gen_0; if (lx == 3) return gisexactzero(gel(g,2)); return NULL; case t_RFRAC: return gisexactzero(gel(g,1)); /* may occur: Mod(0,2)/x */ case t_VEC: case t_COL: case t_MAT: a = gen_0; for (i=lg(g)-1; i; i--) { b = gisexactzero(gel(g,i)); if (!b) return NULL; a = ggcd(a, b); } return a; } return NULL; } int isrationalzero(GEN g) { long i; switch (typ(g)) { case t_INT: return !signe(g); case t_COMPLEX: return isintzero(gel(g,1)) && isintzero(gel(g,2)); case t_QUAD: return isintzero(gel(g,2)) && isintzero(gel(g,3)); case t_POLMOD: return isrationalzero(gel(g,2)); case t_POL: return lg(g) == 2; case t_VEC: case t_COL: case t_MAT: for (i=lg(g)-1; i; i--) if (!isrationalzero(gel(g,i))) return 0; return 1; } return 0; } int gequal0(GEN x) { switch(typ(x)) { case t_INT: case t_REAL: case t_POL: case t_SER: return !signe(x); case t_INTMOD: return !signe(gel(x,2)); case t_FFELT: return FF_equal0(x); case t_COMPLEX: /* is 0 iff norm(x) would be 0 (can happen with Re(x) and Im(x) != 0 * only if Re(x) and Im(x) are of type t_REAL). See mp.c:addrr(). */ if (gequal0(gel(x,1))) { if (gequal0(gel(x,2))) return 1; if (typ(gel(x,1))!=t_REAL || typ(gel(x,2))!=t_REAL) return 0; return (expo(gel(x,1))>=expo(gel(x,2))); } if (gequal0(gel(x,2))) { if (typ(gel(x,1))!=t_REAL || typ(gel(x,2))!=t_REAL) return 0; return (expo(gel(x,2))>=expo(gel(x,1))); } return 0; case t_PADIC: return !signe(gel(x,4)); case t_QUAD: return gequal0(gel(x,2)) && gequal0(gel(x,3)); case t_POLMOD: return gequal0(gel(x,2)); case t_RFRAC: return gequal0(gel(x,1)); case t_VEC: case t_COL: case t_MAT: { long i; for (i=lg(x)-1; i; i--) if (!gequal0(gel(x,i))) return 0; return 1; } } return 0; } /* x a t_POL or t_SER, considered as having valuation v; let X(t) = t^(-v) x(t) * return 1 (true) if coeff(X,i) = 0 for all i != 0 and test(coeff(X, 0)) * is true. Return 0 (false) otherwise, or if x == 0 */ static int is_monomial_test(GEN x, long v, int(*test)(GEN)) { long d, i, l; if (!signe(x)) return (typ(x) == t_SER && v <= 0); if (v > 0) return 0; l = lg(x); d = 2-v; if (l <= d) return 0; /* 2 <= d < l */ if (!test(gel(x,d))) return 0; for (i = 2; i < d; i++) if (!gequal0(gel(x,i))) return 0; for (i = d+1; i < l; i++) if (!gequal0(gel(x,i))) return 0; return 1; } static int col_test(GEN x, int(*test)(GEN)) { long i, l = lg(x); if (l == 1 || !test(gel(x,1))) return 0; for (i = 2; i < l; i++) if (!gequal0(gel(x,i))) return 0; return 1; } static int mat_test(GEN x, int(*test)(GEN)) { long i, j, l = lg(x); if (l == 1) return 1; if (l != lgcols(x)) return 0; for (i = 1; i < l; i++) for (j = 1; j < l; j++) if (i == j) { if (!test(gcoeff(x,i,i))) return 0; } else { if (!gequal0(gcoeff(x,i,j))) return 0; } return 1; } /* returns 1 whenever x = 1, and 0 otherwise */ int gequal1(GEN x) { switch(typ(x)) { case t_INT: return equali1(x); case t_REAL: { long s = signe(x); if (!s) return expo(x) >= 0; return s > 0 ? absrnz_equal1(x): 0; } case t_INTMOD: return is_pm1(gel(x,2)) || is_pm1(gel(x,1)); case t_POLMOD: return gequal1(gel(x,2)) || gequal1(gel(x,1)); case t_FFELT: return FF_equal1(x); case t_FRAC: return 0; case t_COMPLEX: return gequal1(gel(x,1)) && gequal0(gel(x,2)); case t_PADIC: return !valp(x) && gequal1(gel(x,4)); case t_QUAD: return gequal1(gel(x,2)) && gequal0(gel(x,3)); case t_POL: return is_monomial_test(x, 0, &gequal1); case t_SER: return is_monomial_test(x, valp(x), &gequal1); case t_RFRAC: return gequal(gel(x,1), gel(x,2)); case t_COL: return col_test(x, &gequal1); case t_MAT: return mat_test(x, &gequal1); } return 0; } /* returns 1 whenever the x = -1, 0 otherwise */ int gequalm1(GEN x) { pari_sp av; long y; GEN p1; switch(typ(x)) { case t_INT: return equalim1(x); case t_REAL: { long s = signe(x); if (!s) return expo(x) >= 0; return s < 0 ? absrnz_equal1(x): 0; } case t_INTMOD: av=avma; y=equalii(addui(1,gel(x,2)), gel(x,1)); avma=av; return y; case t_FRAC: return 0; case t_FFELT: return FF_equalm1(x); case t_COMPLEX: return gequalm1(gel(x,1)) && gequal0(gel(x,2)); case t_QUAD: return gequalm1(gel(x,2)) && gequal0(gel(x,3)); case t_PADIC: av=avma; y=equalii(addui(1,gel(x,4)), gel(x,3)); avma=av; return y; case t_POLMOD: av=avma; p1 = gaddgs(gel(x,2), 1); y = gequal0(p1) || gequal(p1,gel(x,1)); avma=av; return y; case t_POL: return is_monomial_test(x, 0, &gequalm1); case t_SER: return is_monomial_test(x, valp(x), &gequalm1); case t_RFRAC: av=avma; y=gequal(gel(x,1), gneg_i(gel(x,2))); avma=av; return y; case t_COL: return col_test(x, &gequalm1); case t_MAT: return mat_test(x, &gequalm1); } return 0; } int gequalX(GEN x) { return typ(x) == t_POL && lg(x) == 4 && isintzero(gel(x,2)) && isint1(gel(x,3)); } static int cmp_str(const char *x, const char *y) { int f = strcmp(x, y); return f > 0? 1 : f? -1: 0; } static int cmp_universal_rec(GEN x, GEN y, long i0) { long i, lx = lg(x), ly = lg(y); if (lx < ly) return -1; if (lx > ly) return 1; for (i = i0; i < lx; i++) { int f = cmp_universal(gel(x,i), gel(y,i)); if (f) return f; } return 0; } /* Universal "meaningless" comparison function. Transitive, returns 0 iff * gidentical(x,y) */ int cmp_universal(GEN x, GEN y) { long lx, ly, i, tx = typ(x), ty = typ(y); if (tx < ty) return -1; if (ty < tx) return 1; switch(tx) { case t_INT: return cmpii(x,y); case t_STR: return cmp_str(GSTR(x),GSTR(y)); case t_REAL: case t_VECSMALL: lx = lg(x); ly = lg(y); if (lx < ly) return -1; if (lx > ly) return 1; for (i = 1; i < lx; i++) { if (x[i] < y[i]) return -1; if (x[i] > y[i]) return 1; } return 0; case t_POL: case t_SER: case t_FFELT: case t_CLOSURE: if (x[1] < y[1]) return -1; if (x[1] > y[1]) return 1; return cmp_universal_rec(x, y, 2); case t_LIST: { long tx = list_typ(x), ty = list_typ(y); GEN vx, vy; if (tx < ty) return -1; if (tx > ty) return 1; vx = list_data(x); vy = list_data(y); if (!vx) return vy? -1: 0; if (!vy) return 1; switch (tx) { case t_LIST_MAP: { pari_sp av = avma; int ret = cmp_universal_rec(maptomat_shallow(x), maptomat_shallow(y),1); avma = av; return ret; } default: return cmp_universal_rec(vx, vy, 1); } } default: return cmp_universal_rec(x, y, lontyp[tx]); } } static int cmpfrac(GEN x, GEN y) { pari_sp av = avma; GEN a = gel(x,1), b = gel(x,2); GEN c = gel(y,1), d = gel(y,2); int r = cmpii(mulii(a, d), mulii(b, c)); avma = av; return r; } static int cmpifrac(GEN a, GEN y) { pari_sp av = avma; GEN c = gel(y,1), d = gel(y,2); int r = cmpii(mulii(a, d), c); avma = av; return r; } static int cmprfrac(GEN a, GEN y) { pari_sp av = avma; GEN c = gel(y,1), d = gel(y,2); int r = cmpri(mulri(a, d), c); avma = av; return r; } static int cmpgen(GEN x, GEN y) { pari_sp av = avma; int s = gsigne(gsub(x,y)); avma = av; return s; } /* returns the sign of x - y when it makes sense. 0 otherwise */ int gcmp(GEN x, GEN y) { long tx = typ(x), ty = typ(y); if (tx == ty) /* generic case */ switch(tx) { case t_INT: return cmpii(x, y); case t_REAL: return cmprr(x, y); case t_FRAC: return cmpfrac(x, y); case t_QUAD: return cmpgen(x, y); case t_STR: return cmp_str(GSTR(x), GSTR(y)); case t_INFINITY: { long sx = inf_get_sign(x), sy = inf_get_sign(y); if (sx < sy) return -1; if (sx > sy) return 1; return 0; } } if (ty == t_INFINITY) return -inf_get_sign(y); switch(tx) { case t_INT: switch(ty) { case t_REAL: return cmpir(x, y); case t_FRAC: return cmpifrac(x, y); case t_QUAD: return cmpgen(x, y); } break; case t_REAL: switch(ty) { case t_INT: return cmpri(x, y); case t_FRAC: return cmprfrac(x, y); case t_QUAD: return cmpgen(x, y); } break; case t_FRAC: switch(ty) { case t_INT: return -cmpifrac(y, x); case t_REAL: return -cmprfrac(y, x); case t_QUAD: return cmpgen(x, y); } break; case t_QUAD: return cmpgen(x, y); case t_INFINITY: return inf_get_sign(x); } pari_err_TYPE2("comparison",x,y); return 0;/*LCOV_EXCL_LINE*/ } int gcmpsg(long s, GEN y) { switch(typ(y)) { case t_INT: return cmpsi(s,y); case t_REAL: return cmpsr(s,y); case t_FRAC: { pari_sp av = avma; GEN n = gel(y,1), d = gel(y,2); int f = cmpii(mulsi(s,d), n); avma = av; return f; } case t_QUAD: { pari_sp av = avma; int f = gsigne(gsubsg(s, y)); avma = av; return f; } case t_INFINITY: return -inf_get_sign(y); } pari_err_TYPE2("comparison",stoi(s),y); return 0; /* LCOV_EXCL_LINE */ } static long roughtype(GEN x) { switch(typ(x)) { case t_MAT: return t_MAT; case t_VEC: case t_COL: return t_VEC; case t_VECSMALL: return t_VECSMALL; default: return t_INT; } } static int lexcmpsg(long x, GEN y); static int lexcmpgs(GEN x, long y) { return -lexcmpsg(y,x); } /* lexcmp(stoi(x),y), y t_VEC/t_COL/t_MAT */ static int lexcmp_s_matvec(long x, GEN y) { int fl; if (lg(y)==1) return 1; fl = lexcmpsg(x,gel(y,1)); if (fl) return fl; return -1; } /* x a scalar, y a t_VEC/t_COL/t_MAT */ static int lexcmp_scal_matvec(GEN x, GEN y) { int fl; if (lg(y)==1) return 1; fl = lexcmp(x,gel(y,1)); if (fl) return fl; return -1; } /* x a scalar, y a t_VECSMALL */ static int lexcmp_scal_vecsmall(GEN x, GEN y) { int fl; if (lg(y)==1) return 1; fl = lexcmpgs(x, y[1]); if (fl) return fl; return -1; } /* tx = ty = t_MAT, or x and y are both vect_t */ static int lexcmp_similar(GEN x, GEN y) { long i, lx = lg(x), ly = lg(y), l = minss(lx,ly); for (i=1; i y[1])? 1: -1; default: return gcmpsg(x,y); } } /* as gcmp for vector/matrices, using lexicographic ordering on components */ int lexcmp(GEN x, GEN y) { const long tx = roughtype(x), ty = roughtype(y); if (tx == ty) switch(tx) { case t_MAT: case t_VEC: return lexcmp_similar(x,y); case t_VECSMALL: return vecsmall_lexcmp(x,y); default: return gcmp(x,y); } if (tx == t_VECSMALL) return lexcmp_vecsmall_other(x,y,ty); if (ty == t_VECSMALL) return -lexcmp_vecsmall_other(y,x,tx); if (tx == t_INT) return lexcmp_scal_matvec(x,y); /*scalar*/ if (ty == t_INT) return -lexcmp_scal_matvec(y,x); if (ty==t_MAT) return lexcmp_vec_mat(x,y); /*tx==t_MAT*/ return -lexcmp_vec_mat(y,x); } /*****************************************************************/ /* */ /* EQUALITY */ /* returns 1 if x == y, 0 otherwise */ /* */ /*****************************************************************/ /* x,y t_POL */ static int polidentical(GEN x, GEN y) { long lx; if (x[1] != y[1]) return 0; lx = lg(x); if (lg(y) != lg(x)) return 0; for (lx--; lx >= 2; lx--) if (!gidentical(gel(x,lx), gel(y,lx))) return 0; return 1; } /* x,y t_SER */ static int seridentical(GEN x, GEN y) { return polidentical(x,y); } /* typ(x) = typ(y) = t_VEC/COL/MAT */ static int vecidentical(GEN x, GEN y) { long i; if ((x[0] ^ y[0]) & (TYPBITS|LGBITS)) return 0; for (i = lg(x)-1; i; i--) if (! gidentical(gel(x,i),gel(y,i)) ) return 0; return 1; } static int identicalrr(GEN x, GEN y) { long i, lx = lg(x); if (lg(y) != lx) return 0; if (x[1] != y[1]) return 0; i=2; while (i ly) if (!gequal0(gel(x,--lx))) return 0; while (ly > lx) if (!gequal0(gel(y,--ly))) return 0; for (lx--; lx >= 2; lx--) if (!gequal(gel(x,lx), gel(y,lx))) return 0; return 1; } /* x,y t_POL */ static int serequal(GEN x, GEN y) { long lx; if (varn(x) != varn(y)) return 0; if (!signe(x)) { if (!signe(y)) return 1; return valp(y) >= valp(x); } if (!signe(y)) return valp(x) >= valp(y); if ((x[1] ^ y[1]) & VALPBITS) return 0; lx = minss(lg(x), lg(y)); for (lx--; lx >= 2; lx--) if (!gequal(gel(x,lx), gel(y,lx))) return 0; return 1; } /* typ(x) = typ(y) = t_VEC/COL/MAT */ static int vecequal(GEN x, GEN y) { long i; if ((x[0] ^ y[0]) & (TYPBITS|LGBITS)) return 0; for (i = lg(x)-1; i; i--) if (! gequal(gel(x,i),gel(y,i)) ) return 0; return 1; } static int gequal_try(GEN x, GEN y) { int i; pari_CATCH(CATCH_ALL) { GEN E = pari_err_last(); switch(err_get_num(E)) { case e_STACK: case e_MEM: case e_ALARM: pari_err(0, E); /* rethrow */ } return 0; } pari_TRY { i = gequal0(gadd(x, gneg_i(y))); } pari_ENDCATCH; return i; } int gequal(GEN x, GEN y) { pari_sp av; long tx, ty; long i; if (x == y) return 1; tx = typ(x); ty = typ(y); if (tx == ty) switch(tx) { case t_INT: return equalii(x,y); case t_REAL: return equalrr(x,y); case t_FRAC: case t_INTMOD: return equalii(gel(x,2), gel(y,2)) && equalii(gel(x,1), gel(y,1)); case t_COMPLEX: return gequal(gel(x,2),gel(y,2)) && gequal(gel(x,1),gel(y,1)); case t_PADIC: if (!equalii(gel(x,2),gel(y,2))) return 0; av = avma; i = gequal0(gsub(x,y)); avma = av; return i; case t_POLMOD: if (varn(gel(x,1)) != varn(gel(y,1))) break; return gequal(gel(x,2),gel(y,2)) && RgX_equal_var(gel(x,1),gel(y,1)); case t_POL: return polequal(x,y); case t_SER: return serequal(x,y); case t_FFELT: return FF_equal(x,y); case t_QFR: case t_QFI: return equalii(gel(x,1),gel(y,1)) && equalii(gel(x,2),gel(y,2)) && equalii(gel(x,3),gel(y,3)); case t_QUAD: return ZX_equal(gel(x,1),gel(y,1)) && gequal(gel(x,2),gel(y,2)) && gequal(gel(x,3),gel(y,3)); case t_RFRAC: { GEN a = gel(x,1), b = gel(x,2), c = gel(y,1), d = gel(y,2); if (gequal(b,d)) return gequal(a,c); /* simple case */ av = avma; i = gequal(simplify_shallow(gmul(a,d)), simplify_shallow(gmul(b,c))); avma = av; return i; } case t_STR: return !strcmp(GSTR(x),GSTR(y)); case t_VEC: case t_COL: case t_MAT: return vecequal(x,y); case t_VECSMALL: return zv_equal(x,y); case t_LIST: return list_cmp(x, y, gequal); case t_CLOSURE: return closure_identical(x,y); case t_INFINITY: return gequal(gel(x,1),gel(y,1)); } (void)&av; /* emulate volatile */ av = avma; i = gequal_try(x, y); avma = av; return i; } int gequalsg(long s, GEN x) { pari_sp av = avma; int f = gequal(stoi(s), x); avma = av; return f; } /* a and b are t_INT, t_FRAC, t_REAL or t_COMPLEX of those. Check whether * a-b is invertible */ int cx_approx_equal(GEN a, GEN b) { pari_sp av = avma; GEN d; int r; if (a == b) return 1; d = gsub(a,b); r = (gequal0(d) || (typ(d) == t_COMPLEX && gequal0(cxnorm(d)))); avma = av; return r; } /*******************************************************************/ /* */ /* VALUATION */ /* p is either a t_INT or a t_POL. */ /* returns the largest exponent of p dividing x when this makes */ /* sense : error for types real, integermod and polymod if p does */ /* not divide the modulus, q-adic if q!=p. */ /* */ /*******************************************************************/ static long minval(GEN x, GEN p) { long i,k, val = LONG_MAX, lx = lg(x); for (i=lontyp[typ(x)]; i 0) return 0; } return minval(x,p); } case t_SER: { if (tp == t_POL) { long vp = varn(p), vx = varn(x); if (vp == vx) { long val = RgX_val(p); if (!val) pari_err_DOMAIN("gvaluation", "p", "=", p, p); return (long)(valp(x) / val); } if (varncmp(vx, vp) > 0) return 0; } return minval(x,p); } case t_RFRAC: return gvaluation(gel(x,1),p) - gvaluation(gel(x,2),p); case t_COMPLEX: case t_QUAD: case t_VEC: case t_COL: case t_MAT: return minval(x,p); } pari_err_OP("valuation", x,p); return 0; /* LCOV_EXCL_LINE */ } GEN gpvaluation(GEN x, GEN p) { long v = gvaluation(x,p); return v == LONG_MAX? mkoo(): stoi(v); } /* x is non-zero */ long u_lvalrem(ulong x, ulong p, ulong *py) { ulong vx; if (p == 2) { vx = vals(x); *py = x >> vx; return vx; } for(vx = 0;;) { if (x % p) { *py = x; return vx; } x /= p; /* gcc is smart enough to make a single div */ vx++; } } long u_lval(ulong x, ulong p) { ulong vx; if (p == 2) return vals(x); for(vx = 0;;) { if (x % p) return vx; x /= p; /* gcc is smart enough to make a single div */ vx++; } } long z_lval(long s, ulong p) { return u_lval(labs(s), p); } long z_lvalrem(long s, ulong p, long *py) { long v; if (s < 0) { ulong u = (ulong)-s; v = u_lvalrem(u, p, &u); *py = -(long)u; } else { ulong u = (ulong)s; v = u_lvalrem(u, p, &u); *py = (long)u; } return v; } /* assume |p| > 1 */ long z_pval(long s, GEN p) { if (lgefint(p) > 3) return 0; return z_lval(s, uel(p,2)); } /* assume |p| > 1 */ long z_pvalrem(long s, GEN p, long *py) { if (lgefint(p) > 3) { *py = s; return 0; } return z_lvalrem(s, uel(p,2), py); } /* return v_q(x) and set *py = x / q^v_q(x), using divide & conquer */ static long Z_pvalrem_DC(GEN x, GEN q, GEN *py) { GEN r, z = dvmdii(x, q, &r); long v; if (r != gen_0) { *py = x; return 0; } if (2 * lgefint(q) <= lgefint(z)+3) /* avoid squaring if pointless */ v = Z_pvalrem_DC(z, sqri(q), py) << 1; else { v = 0; *py = z; } z = dvmdii(*py, q, &r); if (r != gen_0) return v + 1; *py = z; return v + 2; } static const long VAL_DC_THRESHOLD = 16; long Z_lval(GEN x, ulong p) { long vx; pari_sp av; if (p == 2) return vali(x); if (lgefint(x) == 3) return u_lval(uel(x,2), p); av = avma; for(vx = 0;;) { ulong r; GEN q = absdiviu_rem(x, p, &r); if (r) break; vx++; x = q; if (vx == VAL_DC_THRESHOLD) { if (p == 1) pari_err_DOMAIN("Z_lval", "p", "=", gen_1, gen_1); vx += Z_pvalrem_DC(x, sqru(p), &x) << 1; q = absdiviu_rem(x, p, &r); if (!r) vx++; break; } } avma = av; return vx; } long Z_lvalrem(GEN x, ulong p, GEN *py) { long vx, sx; pari_sp av; if (p == 2) { vx = vali(x); *py = shifti(x, -vx); return vx; } if (lgefint(x) == 3) { ulong u; vx = u_lvalrem(uel(x,2), p, &u); *py = signe(x) < 0? utoineg(u): utoipos(u); return vx; } av = avma; (void)new_chunk(lgefint(x)); sx = signe(x); for(vx = 0;;) { ulong r; GEN q = absdiviu_rem(x, p, &r); if (r) break; vx++; x = q; if (vx == VAL_DC_THRESHOLD) { if (p == 1) pari_err_DOMAIN("Z_lvalrem", "p", "=", gen_1, gen_1); vx += Z_pvalrem_DC(x, sqru(p), &x) << 1; q = absdiviu_rem(x, p, &r); if (!r) { vx++; x = q; } break; } } avma = av; *py = icopy(x); setsigne(*py, sx); return vx; } /* Is |q| <= p ? */ static int isless_iu(GEN q, ulong p) { long l = lgefint(q); return l==2 || (l == 3 && uel(q,2) <= p); } long u_lvalrem_stop(ulong *n, ulong p, int *stop) { ulong N = *n, q = N / p, r = N % p; /* gcc makes a single div */ long v = 0; if (!r) { do { v++; N = q; q = N / p; r = N % p; } while (!r); *n = N; } *stop = q <= p; return v; } /* Assume n > 0. Return v_p(n), set *n := n/p^v_p(n). Set 'stop' if now * n < p^2 [implies n prime if no prime < p divides n] */ long Z_lvalrem_stop(GEN *n, ulong p, int *stop) { pari_sp av; long v; ulong r; GEN N, q; if (lgefint(*n) == 3) { r = (*n)[2]; v = u_lvalrem_stop(&r, p, stop); if (v) *n = utoipos(r); return v; } av = avma; v = 0; q = absdiviu_rem(*n, p, &r); if (r) avma = av; else { do { v++; N = q; if (v == VAL_DC_THRESHOLD) { v += Z_pvalrem_DC(N,sqru(p),&N) << 1; q = absdiviu_rem(N, p, &r); if (!r) { v++; N = q; } break; } q = absdiviu_rem(N, p, &r); } while (!r); *n = N; } *stop = isless_iu(q,p); return v; } /* x is a non-zero integer, |p| > 1 */ long Z_pvalrem(GEN x, GEN p, GEN *py) { long vx; pari_sp av; if (lgefint(p) == 3) return Z_lvalrem(x, uel(p,2), py); if (lgefint(x) == 3) { *py = icopy(x); return 0; } av = avma; vx = 0; (void)new_chunk(lgefint(x)); for(;;) { GEN r, q = dvmdii(x,p,&r); if (r != gen_0) { avma = av; *py = icopy(x); return vx; } vx++; x = q; } } long u_pvalrem(ulong x, GEN p, ulong *py) { if (lgefint(p) == 3) return u_lvalrem(x, uel(p,2), py); *py = x; return 0; } long u_pval(ulong x, GEN p) { if (lgefint(p) == 3) return u_lval(x, uel(p,2)); return 0; } long Z_pval(GEN x, GEN p) { long vx; pari_sp av; if (lgefint(p) == 3) return Z_lval(x, uel(p,2)); if (lgefint(x) == 3) return 0; av = avma; vx = 0; for(;;) { GEN r, q = dvmdii(x,p,&r); if (r != gen_0) { avma = av; return vx; } vx++; x = q; } } /* return v_p(n!) = [n/p] + [n/p^2] + ... */ long factorial_lval(ulong n, ulong p) { ulong q = p, v = 0; do { v += n/q; q *= p; } while (n >= q); return (long)v; } /********** Same for "containers" ZX / ZV / ZC **********/ /* If the t_INT q divides the ZX/ZV x, return the quotient. Otherwise NULL. * Stack clean; assumes lg(x) > 1 */ static GEN gen_Z_divides(GEN x, GEN q, long imin) { long i, l; GEN y = cgetg_copy(x, &l); y[1] = x[1]; /* Needed for ZX; no-op if ZV, overwritten in first iteration */ for (i = imin; i < l; i++) { GEN r, xi = gel(x,i); if (!signe(xi)) { gel(y,i) = xi; continue; } gel(y,i) = dvmdii(xi, q, &r); if (r != gen_0) { avma = (pari_sp)(y+l); return NULL; } } return y; } /* If q divides the ZX/ZV x, return the quotient. Otherwise NULL. * Stack clean; assumes lg(x) > 1 */ static GEN gen_z_divides(GEN x, ulong q, long imin) { long i, l; GEN y = cgetg_copy(x, &l); y[1] = x[1]; /* Needed for ZX; no-op if ZV, overwritten in first iteration */ for (i = imin; i < l; i++) { ulong r; GEN xi = gel(x,i); if (!signe(xi)) { gel(y,i) = xi; continue; } gel(y,i) = absdiviu_rem(xi, q, &r); if (r) { avma = (pari_sp)(y+l); return NULL; } affectsign_safe(xi, &gel(y,i)); } return y; } /* return v_q(x) and set *py = x / q^v_q(x), using divide & conquer */ static long gen_pvalrem_DC(GEN x, GEN q, GEN *py, long imin) { pari_sp av = avma; long v, i, l, lz = LONG_MAX; GEN y = cgetg_copy(x, &l); y[1] = x[1]; for (i = imin; i < l; i++) { GEN r, xi = gel(x,i); if (!signe(xi)) { gel(y,i) = xi; continue; } gel(y,i) = dvmdii(xi, q, &r); if (r != gen_0) { avma = av; *py = x; return 0; } lz = minss(lz, lgefint(gel(y,i))); } if (2 * lgefint(q) <= lz+3) /* avoid squaring if pointless */ v = gen_pvalrem_DC(y, sqri(q), py, imin) << 1; else { v = 0; *py = y; } y = gen_Z_divides(*py, q, imin); if (!y) return v+1; *py = y; return v+2; } static long gen_2val(GEN x, long imin) { long i, lx = lg(x), v = LONG_MAX; for (i = imin; i < lx; i++) { GEN c = gel(x,i); long w; if (!signe(c)) continue; w = vali(c); if (w < v) { v = w; if (!v) break; } } return v; } static long gen_lval(GEN x, ulong p, long imin) { long i, lx, v; pari_sp av; GEN y; if (p == 2) return gen_2val(x, imin); av = avma; lx = lg(x); y = leafcopy(x); for(v = 0;; v++) for (i = imin; i < lx; i++) { ulong r; gel(y,i) = absdiviu_rem(gel(y,i), p, &r); if (r) { avma = av; return v; } } } long ZX_lval(GEN x, ulong p) { return gen_lval(x, p, 2); } long ZV_lval(GEN x, ulong p) { return gen_lval(x, p, 1); } static long gen_pval(GEN x, GEN p, long imin) { long i, lx, v; pari_sp av; GEN y; if (lgefint(p) == 3) return gen_lval(x, p[2], imin); av = avma; lx = lg(x); y = leafcopy(x); for(v = 0;; v++) { if (v == VAL_DC_THRESHOLD) { if (is_pm1(p)) pari_err_DOMAIN("gen_pval", "p", "=", p, p); v += gen_pvalrem_DC(y, p, &y, imin); avma = av; return v; } for (i = imin; i < lx; i++) { GEN r; gel(y,i) = dvmdii(gel(y,i), p, &r); if (r != gen_0) { avma = av; return v; } } } } long ZX_pval(GEN x, GEN p) { return gen_pval(x, p, 2); } long ZV_pval(GEN x, GEN p) { return gen_pval(x, p, 1); } /* v = 0 (mod p) */ int ZV_Z_dvd(GEN v, GEN p) { pari_sp av = avma; long i, l = lg(v); for (i=1; i=0)? stoi(s): gcopy(x); } GEN gmin(GEN x, GEN y) { return gcopy(gmin_shallow(x,y)); } GEN gmings(GEN x, long s) { return (gcmpsg(s,x)>0)? gcopy(x): stoi(s); } long vecindexmax(GEN x) { long lx = lg(x), i0, i; GEN s; if (lx==1) pari_err_DOMAIN("vecindexmax", "empty argument", "=", x,x); switch(typ(x)) { case t_VEC: case t_COL: s = gel(x,i0=1); for (i=2; i 0) s = gel(x,i0=i); return i0; case t_VECSMALL: return vecsmall_indexmax(x); default: pari_err_TYPE("vecindexmax",x); } /* LCOV_EXCL_LINE */ return 0; } long vecindexmin(GEN x) { long lx = lg(x), i0, i; GEN s; if (lx==1) pari_err_DOMAIN("vecindexmin", "empty argument", "=", x,x); switch(typ(x)) { case t_VEC: case t_COL: s = gel(x,i0=1); for (i=2; i= vy) { avma = av; return gen_0; } z = gel(x,4); if (!signe(z) || vy > vx + precp(x)) pari_err_OP("",x, mkintmod(gen_1,Y)); if (vx) z = mulii(z, powiu(p,vx)); return gerepileuptoint(av, remii(z, Y)); } ulong padic_to_Fl(GEN x, ulong Y) { GEN p = gel(x,2); ulong u, z; long vy, vx = valp(x); vy = u_pvalrem(Y,p, &u); if (vx < 0 || u != 1) pari_err_OP("",x, mkintmodu(1,Y)); /* Y = p^vy */ if (vx >= vy) return 0; z = umodiu(gel(x,4), Y); if (!z || vy > vx + precp(x)) pari_err_OP("",x, mkintmodu(1,Y)); if (vx) { ulong pp = p[2]; z = Fl_mul(z, upowuu(pp,vx), Y); /* p^vx < p^vy = Y */ } return z; } static void croak(const char *s) { char *t; t = stack_sprintf("gaffect [overwriting universal object: %s]",s); pari_err_BUG(t); } void gaffect(GEN x, GEN y) { long vx, i, lx, ly, tx = typ(x), ty = typ(y); pari_sp av; GEN p1, num, den; if (tx == ty) switch(tx) { case t_INT: if (!is_universal_constant(y)) { affii(x,y); return; } /* y = gen_0, gnil, gen_1 or gen_2 */ if (y==gen_0) croak("gen_0"); if (y==gen_1) croak("gen_1"); if (y==gen_m1) croak("gen_m1"); if (y==gen_m2) croak("gen_m2"); if (y==gen_2) croak("gen_2"); croak("gnil)"); case t_REAL: affrr(x,y); return; case t_INTMOD: if (!dvdii(gel(x,1),gel(y,1))) pari_err_OP("",x,y); modiiz(gel(x,2),gel(y,1),gel(y,2)); return; case t_FRAC: affii(gel(x,1),gel(y,1)); affii(gel(x,2),gel(y,2)); return; case t_COMPLEX: gaffect(gel(x,1),gel(y,1)); gaffect(gel(x,2),gel(y,2)); return; case t_PADIC: if (!equalii(gel(x,2),gel(y,2))) pari_err_OP("",x,y); modiiz(gel(x,4),gel(y,3),gel(y,4)); setvalp(y,valp(x)); return; case t_QUAD: if (! ZX_equal(gel(x,1),gel(y,1))) pari_err_OP("",x,y); affii(gel(x,2),gel(y,2)); affii(gel(x,3),gel(y,3)); return; case t_VEC: case t_COL: case t_MAT: lx = lg(x); if (lx != lg(y)) pari_err_DIM("gaffect"); for (i=1; i REAL, COMPLEX OR P-ADIC */ /* */ /*******************************************************************/ GEN quadtofp(GEN x, long prec) { GEN z, Q, u = gel(x,2), v = gel(x,3); pari_sp av; if (prec < LOWDEFAULTPREC) prec = LOWDEFAULTPREC; if (isintzero(v)) return cxcompotor(u, prec); av = avma; Q = gel(x,1); z = itor(quad_disc(x), prec); if (signe(gel(Q,2)) < 0) /* Q[2] = -D/4 or (1-D)/4 */ { z = subri(sqrtr(z), gel(Q,3)); shiftr_inplace(z, -1); } else { z = sqrtr_abs(z); shiftr_inplace(z, -1); z = mkcomplex(gmul2n(negi(gel(Q,3)),-1), z); }/* z = (-b + sqrt(D)) / 2 */ return gerepileupto(av, gadd(u, gmul(v,z))); } static GEN qtop(GEN x, GEN p, long d) { GEN z, D, P, b, u = gel(x,2), v = gel(x,3); pari_sp av; if (gequal0(v)) return cvtop(u, p, d); P = gel(x,1); b = gel(P,3); av = avma; D = quad_disc(x); if (absequaliu(p,2)) d += 2; z = Qp_sqrt(cvtop(D,p,d)); if (!z) pari_err_SQRTN("Qp_sqrt",D); z = gmul2n(gsub(z, b), -1); z = gadd(u, gmul(v, z)); if (typ(z) != t_PADIC) /* t_INTMOD for t_QUAD of t_INTMODs... */ z = cvtop(z, p, d); return gerepileupto(av, z); } static GEN ctop(GEN x, GEN p, long d) { pari_sp av = avma; GEN z, u = gel(x,1), v = gel(x,2); if (isrationalzero(v)) return cvtop(u, p, d); z = Qp_sqrt(cvtop(gen_m1, p, d - gvaluation(v, p))); /* = I */ if (!z) pari_err_SQRTN("Qp_sqrt",gen_m1); z = gadd(u, gmul(v, z)); if (typ(z) != t_PADIC) /* t_INTMOD for t_COMPLEX of t_INTMODs... */ z = cvtop(z, p, d); return gerepileupto(av, z); } /* cvtop2(stoi(s), y) */ GEN cvstop2(long s, GEN y) { GEN z, p = gel(y,2); long v, d = signe(gel(y,4))? precp(y): 0; if (!s) return zeropadic(p, d); v = z_pvalrem(s, p, &s); if (d <= 0) return zeropadic(p, v); z = cgetg(5, t_PADIC); z[1] = evalprecp(d) | evalvalp(v); gel(z,2) = p; gel(z,3) = gel(y,3); gel(z,4) = modsi(s, gel(y,3)); return z; } /* cvtop(x, gel(y,2), precp(y)), shallow */ GEN cvtop2(GEN x, GEN y) { GEN z, p = gel(y,2); long v, d = signe(gel(y,4))? precp(y): 0; switch(typ(x)) { case t_INT: if (!signe(x)) return zeropadic(p, d); if (d <= 0) return zeropadic(p, Z_pval(x,p)); v = Z_pvalrem(x, p, &x); z = cgetg(5, t_PADIC); z[1] = evalprecp(d) | evalvalp(v); gel(z,2) = p; gel(z,3) = gel(y,3); gel(z,4) = modii(x, gel(y,3)); return z; case t_INTMOD: v = Z_pval(gel(x,1),p); if (v > d) v = d; return cvtop(gel(x,2), p, v); case t_FRAC: { GEN num, den; if (d <= 0) return zeropadic(p, Q_pval(x,p)); num = gel(x,1); v = Z_pvalrem(num, p, &num); den = gel(x,2); if (!v) v = -Z_pvalrem(den, p, &den); z = cgetg(5, t_PADIC); z[1] = evalprecp(d) | evalvalp(v); gel(z,2) = p; gel(z,3) = gel(y,3); if (!is_pm1(den)) num = mulii(num, Fp_inv(den, gel(y,3))); gel(z,4) = modii(num, gel(y,3)); return z; } case t_COMPLEX: return ctop(x, p, d); case t_QUAD: return qtop(x, p, d); } pari_err_TYPE("cvtop2",x); return NULL; /* LCOV_EXCL_LINE */ } /* assume is_const_t(tx) */ GEN cvtop(GEN x, GEN p, long d) { GEN z; long v; if (typ(p) != t_INT) pari_err_TYPE("cvtop",p); switch(typ(x)) { case t_INT: if (!signe(x)) return zeropadic(p, d); if (d <= 0) return zeropadic(p, Z_pval(x,p)); v = Z_pvalrem(x, p, &x); z = cgetg(5, t_PADIC); z[1] = evalprecp(d) | evalvalp(v); gel(z,2) = icopy(p); gel(z,3) = powiu(p, d); gel(z,4) = modii(x, gel(z,3)); return z; /* not memory-clean */ case t_INTMOD: v = Z_pval(gel(x,1),p); if (v > d) v = d; return cvtop(gel(x,2), p, v); case t_FRAC: { GEN num, den; if (d <= 0) return zeropadic(p, Q_pval(x,p)); num = gel(x,1); v = Z_pvalrem(num, p, &num); den = gel(x,2); if (!v) v = -Z_pvalrem(den, p, &den); z = cgetg(5, t_PADIC); z[1] = evalprecp(d) | evalvalp(v); gel(z,2) = icopy(p); gel(z,3) = powiu(p, d); if (!is_pm1(den)) num = mulii(num, Fp_inv(den, gel(z,3))); gel(z,4) = modii(num, gel(z,3)); return z; /* not memory-clean */ } case t_COMPLEX: return ctop(x, p, d); case t_PADIC: p = gel(x,2); /* override */ if (!signe(gel(x,4))) return zeropadic(p, d); z = cgetg(5,t_PADIC); z[1] = x[1]; setprecp(z,d); gel(z,2) = icopy(p); gel(z,3) = powiu(p, d); gel(z,4) = modii(gel(x,4), gel(z,3)); return z; case t_QUAD: return qtop(x, p, d); } pari_err_TYPE("cvtop",x); return NULL; /* LCOV_EXCL_LINE */ } GEN gcvtop(GEN x, GEN p, long r) { long i, lx; GEN y; switch(typ(x)) { case t_POL: case t_SER: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; if) f=e; } return f; case t_VEC: case t_COL: case t_MAT: lx = lg(x); f = -(long)HIGHEXPOBIT; for (i=1; if) f=e; } return f; } return -1-(long)HIGHEXPOBIT; } long gexpo(GEN x) { long e = gexpo_safe(x); if (e < -(long)HIGHEXPOBIT) pari_err_TYPE("gexpo",x); return e; } GEN gpexponent(GEN x) { long e = gexpo(x); return e == -(long)HIGHEXPOBIT? mkmoo(): stoi(e); } long sizedigit(GEN x) { return gequal0(x)? 0: (long) ((gexpo(x)+1) * LOG10_2) + 1; } /* normalize series. avma is not updated */ GEN normalize(GEN x) { long i, lx = lg(x), vx=varn(x), vp=valp(x); GEN y, z; if (typ(x) != t_SER) pari_err_TYPE("normalize",x); if (lx == 2) { setsigne(x,0); return x; } if (lx == 3) { z = gel(x,2); if (!gequal0(z)) { setsigne(x,1); return x; } if (isrationalzero(z)) return zeroser(vx,vp+1); if (isexactzero(z)) { /* dangerous case: already normalized ? */ if (!signe(x)) return x; setvalp(x,vp+1); /* no: normalize */ } setsigne(x,0); return x; } for (i=2; i1; i--) if (! gequal0(gel(x,i))) break; stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1)); setlg(x, i+1); setsigne(x, i!=1); return x; } GEN normalizepol_lg(GEN x, long lx) { long i, LX = 0; GEN KEEP = NULL; for (i = lx-1; i>1; i--) { GEN z = gel(x,i); if (! gequal0(z) ) { if (!LX) LX = i+1; stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + LX)); x[0] = evaltyp(t_POL) | evallg(LX); setsigne(x,1); return x; } else if (!isexactzero(z)) { if (!LX) LX = i+1; /* to be kept as leading coeff */ } else if (!isrationalzero(z)) KEEP = z; /* to be kept iff all other coeffs are exact 0s */ } if (!LX) { if (KEEP) { /* e.g. Pol(Mod(0,2)) */ gel(x,2) = KEEP; LX = 3; } else LX = 2; /* Pol(0) */ } stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + LX)); x[0] = evaltyp(t_POL) | evallg(LX); setsigne(x,0); return x; } /* normalize polynomial x in place */ GEN normalizepol(GEN x) { return normalizepol_lg(x, lg(x)); } int gsigne(GEN x) { switch(typ(x)) { case t_INT: case t_REAL: return signe(x); case t_FRAC: return signe(gel(x,1)); case t_QUAD: { pari_sp av = avma; GEN T = gel(x,1), a = gel(x,2), b = gel(x,3); long sa, sb; if (signe(gel(T,2)) > 0) break; a = gmul2n(a,1); if (signe(gel(T,3))) a = gadd(a,b); /* a + b sqrt(D) > 0 ? */ sa = gsigne(a); sb = gsigne(b); if (sa == sb) { avma = av; return sa; } if (sa == 0) { avma = av; return sb; } if (sb == 0) { avma = av; return sa; } /* different signs, take conjugate expression */ sb = gsigne(gsub(gsqr(a), gmul(quad_disc(x), gsqr(b)))); avma = av; return sb * sa; } case t_INFINITY: return inf_get_sign(x); } pari_err_TYPE("gsigne",x); return 0; /* LCOV_EXCL_LINE */ } /*******************************************************************/ /* */ /* LISTS */ /* */ /*******************************************************************/ /* make sure L can hold l elements, at least doubling the previous max number * of components. */ static void ensure_nb(GEN L, long l) { long nmax = list_nmax(L), i, lw; GEN v, w; if (l <= nmax) return; if (nmax) { nmax <<= 1; if (l > nmax) nmax = l; w = list_data(L); lw = lg(w); v = newblock(nmax+1); v[0] = w[0]; for (i=1; i < lw; i++) gel(v,i) = gel(w, i); killblock(w); } else /* unallocated */ { nmax = 32; if (list_data(L)) pari_err(e_MISC, "store list in variable before appending elements"); v = newblock(nmax+1); v[0] = evaltyp(t_VEC) | _evallg(1); } list_data(L) = v; L[1] = evaltyp(list_typ(L))|evallg(nmax); } void listkill(GEN L) { if (typ(L) != t_LIST) pari_err_TYPE("listkill",L); if (list_nmax(L)) { GEN v = list_data(L); long i, l = lg(v); for (i=1; i= l) { ensure_nb(L, l); z = list_data(L); /* it may change ! */ index = l; l++; } else gunclone_deep( gel(z, index) ); gel(z,index) = x; z[0] = evaltyp(t_VEC) | evallg(l); /*must be after gel(z,index) is set*/ return gel(z,index); } GEN listput0(GEN L, GEN x, long index) { if (typ(L) != t_LIST || list_typ(L) != t_LIST_RAW) pari_err_TYPE("listput",L); return listput(L, x, index); } GEN listinsert(GEN L, GEN x, long index) { long l, i; GEN z; if (typ(L) != t_LIST || list_typ(L) != t_LIST_RAW) pari_err_TYPE("listinsert",L); z = list_data(L); l = z? lg(z): 1; if (index <= 0) pari_err_COMPONENT("listinsert", "<=", gen_0, stoi(index)); if (index > l) pari_err_COMPONENT("listinsert", ">", stoi(l), stoi(index)); ensure_nb(L, l); BLOCK_SIGINT_START z = list_data(L); for (i=l; i > index; i--) gel(z,i) = gel(z,i-1); z[0] = evaltyp(t_VEC) | evallg(l+1); gel(z,index) = gclone(x); BLOCK_SIGINT_END return gel(z,index); } void listpop(GEN L, long index) { long l, i; GEN z; if (typ(L) != t_LIST) pari_err_TYPE("listinsert",L); if (index < 0) pari_err_COMPONENT("listpop", "<", gen_0, stoi(index)); z = list_data(L); if (!z || (l = lg(z)-1) == 0) return; if (!index || index > l) index = l; BLOCK_SIGINT_START gunclone_deep( gel(z, index) ); z[0] = evaltyp(t_VEC) | evallg(l); for (i=index; i < l; i++) z[i] = z[i+1]; BLOCK_SIGINT_END } void listpop0(GEN L, long index) { if (typ(L) != t_LIST || list_typ(L) != t_LIST_RAW) pari_err_TYPE("listpop",L); listpop(L, index); } /* return a copy fully allocated on stack. gclone from changevalue is * supposed to malloc() it */ GEN gtolist(GEN x) { GEN y; if (!x) return mklist(); switch(typ(x)) { case t_VEC: case t_COL: y = mklist(); if (lg(x) == 1) return y; list_data(y) = gcopy(x); settyp(list_data(y), t_VEC); return y; case t_LIST: y = mklist(); list_data(y) = list_data(x)? gcopy(list_data(x)): NULL; return y; default: return mklistcopy(x); } } void listsort(GEN L, long flag) { long i, l; pari_sp av = avma; GEN perm, v, vnew; if (typ(L) != t_LIST) pari_err_TYPE("listsort",L); v = list_data(L); l = v? lg(v): 1; if (l < 3) return; if (flag) { long lnew; perm = gen_indexsort_uniq(L, (void*)&cmp_universal, cmp_nodata); lnew = lg(perm); /* may have changed since 'uniq' */ vnew = cgetg(lnew,t_VEC); for (i=1; i= ny) { lz = nx+2; z = cgetg(lz,t_POL); z[1] = 0; z += 2; for (i=0; ip); } static GEN _FpX_mul(void *data, GEN x, GEN y) { struct _FpXQ *D = (struct _FpXQ*)data; return FpX_mul(x,y, D->p); } GEN FpX_powu(GEN x, ulong n, GEN p) { struct _FpXQ D; if (n==0) return pol_1(varn(x)); D.p = p; return gen_powu(x, n, (void *)&D, _FpX_sqr, _FpX_mul); } GEN FpX_halve(GEN y, GEN p) { GEN z; long i, l; z = cgetg_copy(y, &l); z[1] = y[1]; for(i=2; i=0 && !signe(gel(y, dy1)); dy1--); p1 = gel(x,dx); av = avma; gel(z,dz) = lead? gerepileuptoint(av, Fp_mul(p1,lead, p)): icopy(p1); for (i=dx-1; i>=dy; i--) { av=avma; p1=gel(x,i); for (j=i-dy1; j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); if (lead) p1 = mulii(p1,lead); gel(z,i-dy) = gerepileuptoint(av,modii(p1, p)); } if (!pr) { if (lead) gunclone(lead); return z-2; } rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3); for (sx=0; ; i--) { p1 = gel(x,i); for (j=maxss(0,i-dy1); j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); p1 = modii(p1,p); if (signe(p1)) { sx = 1; break; } if (!i) break; avma=av; } if (pr == ONLY_DIVIDES) { if (lead) gunclone(lead); if (sx) { avma=av0; return NULL; } avma = (pari_sp)rem; return z-2; } lr=i+3; rem -= lr; rem[0] = evaltyp(t_POL) | evallg(lr); rem[1] = z[-1]; p1 = gerepileuptoint((pari_sp)rem, p1); rem += 2; gel(rem,i) = p1; for (i--; i>=0; i--) { av=avma; p1 = gel(x,i); for (j=maxss(0,i-dy1); j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); gel(rem,i) = gerepileuptoint(av, modii(p1,p)); } rem -= 2; if (lead) gunclone(lead); if (!sx) (void)FpX_renormalize(rem, lr); if (pr == ONLY_REM) return gerepileupto(av0,rem); *pr = rem; return z-2; } GEN FpX_div_by_X_x(GEN a, GEN x, GEN p, GEN *r) { long l = lg(a)-1, i; GEN z = cgetg(l, t_POL); z[1] = evalsigne(1) | evalvarn(0); gel(z, l-1) = gel(a,l); for (i=l-2; i>1; i--) /* z[i] = a[i+1] + x*z[i+1] */ gel(z, i) = Fp_addmul(gel(a,i+1), x, gel(z,i+1), p); if (r) *r = Fp_addmul(gel(a,2), x, gel(z,2), p); return z; } static GEN _FpX_divrem(void * E, GEN x, GEN y, GEN *r) { struct _FpXQ *D = (struct _FpXQ*) E; return FpX_divrem(x, y, D->p, r); } static GEN _FpX_add(void * E, GEN x, GEN y) { struct _FpXQ *D = (struct _FpXQ*) E; return FpX_add(x, y, D->p); } static struct bb_ring FpX_ring = { _FpX_add,_FpX_mul,_FpX_sqr }; GEN FpX_digits(GEN x, GEN T, GEN p) { pari_sp av = avma; struct _FpXQ D; long d = degpol(T), n = (lgpol(x)+d-1)/d; GEN z; D.p = p; z = gen_digits(x,T,n,(void *)&D, &FpX_ring, _FpX_divrem); return gerepileupto(av, z); } GEN FpXV_FpX_fromdigits(GEN x, GEN T, GEN p) { pari_sp av = avma; struct _FpXQ D; GEN z; D.p = p; z = gen_fromdigits(x,T,(void *)&D, &FpX_ring); return gerepileupto(av, z); } long FpX_valrem(GEN x, GEN t, GEN p, GEN *py) { pari_sp av=avma; long k; GEN r, y; for (k=0; ; k++) { y = FpX_divrem(x, t, p, &r); if (signe(r)) break; x = y; } *py = gerepilecopy(av,x); return k; } static GEN FpX_halfgcd_basecase(GEN a, GEN b, GEN p) { pari_sp av=avma; GEN u,u1,v,v1; long vx = varn(a); long n = lgpol(a)>>1; u1 = v = pol_0(vx); u = v1 = pol_1(vx); while (lgpol(b)>n) { GEN r, q = FpX_divrem(a,b,p, &r); a = b; b = r; swap(u,u1); swap(v,v1); u1 = FpX_sub(u1, FpX_mul(u, q, p), p); v1 = FpX_sub(v1, FpX_mul(v, q ,p), p); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpX_halfgcd (d = %ld)",degpol(b)); gerepileall(av,6, &a,&b,&u1,&v1,&u,&v); } } return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1))); } static GEN FpX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN p) { return FpX_add(FpX_mul(u, x, p),FpX_mul(v, y, p), p); } static GEN FpXM_FpX_mul2(GEN M, GEN x, GEN y, GEN p) { GEN res = cgetg(3, t_COL); gel(res, 1) = FpX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, p); gel(res, 2) = FpX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, p); return res; } static GEN FpXM_mul2(GEN A, GEN B, GEN p) { GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2); GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2); GEN M1 = FpX_mul(FpX_add(A11,A22, p), FpX_add(B11,B22, p), p); GEN M2 = FpX_mul(FpX_add(A21,A22, p), B11, p); GEN M3 = FpX_mul(A11, FpX_sub(B12,B22, p), p); GEN M4 = FpX_mul(A22, FpX_sub(B21,B11, p), p); GEN M5 = FpX_mul(FpX_add(A11,A12, p), B22, p); GEN M6 = FpX_mul(FpX_sub(A21,A11, p), FpX_add(B11,B12, p), p); GEN M7 = FpX_mul(FpX_sub(A12,A22, p), FpX_add(B21,B22, p), p); GEN T1 = FpX_add(M1,M4, p), T2 = FpX_sub(M7,M5, p); GEN T3 = FpX_sub(M1,M2, p), T4 = FpX_add(M3,M6, p); retmkmat2(mkcol2(FpX_add(T1,T2, p), FpX_add(M2,M4, p)), mkcol2(FpX_add(M3,M5, p), FpX_add(T3,T4, p))); } /* Return [0,1;1,-q]*M */ static GEN FpX_FpXM_qmul(GEN q, GEN M, GEN p) { GEN u, v, res = cgetg(3, t_MAT); u = FpX_sub(gcoeff(M,1,1), FpX_mul(gcoeff(M,2,1), q, p), p); gel(res,1) = mkcol2(gcoeff(M,2,1), u); v = FpX_sub(gcoeff(M,1,2), FpX_mul(gcoeff(M,2,2), q, p), p); gel(res,2) = mkcol2(gcoeff(M,2,2), v); return res; } static GEN matid2_FpXM(long v) { retmkmat2(mkcol2(pol_1(v),pol_0(v)), mkcol2(pol_0(v),pol_1(v))); } static GEN FpX_halfgcd_split(GEN x, GEN y, GEN p) { pari_sp av=avma; GEN R, S, V; GEN y1, r, q; long l = lgpol(x), n = l>>1, k; if (lgpol(y)<=n) return matid2_FpXM(varn(x)); R = FpX_halfgcd(RgX_shift_shallow(x,-n),RgX_shift_shallow(y,-n),p); V = FpXM_FpX_mul2(R,x,y,p); y1 = gel(V,2); if (lgpol(y1)<=n) return gerepilecopy(av, R); q = FpX_divrem(gel(V,1), y1, p, &r); k = 2*n-degpol(y1); S = FpX_halfgcd(RgX_shift_shallow(y1,-k), RgX_shift_shallow(r,-k),p); return gerepileupto(av, FpXM_mul2(S,FpX_FpXM_qmul(q,R,p),p)); } /* Return M in GL_2(Fp[X]) such that: if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b') */ static GEN FpX_halfgcd_i(GEN x, GEN y, GEN p) { if (lg(x)<=FpX_HALFGCD_LIMIT) return FpX_halfgcd_basecase(x,y,p); return FpX_halfgcd_split(x,y,p); } GEN FpX_halfgcd(GEN x, GEN y, GEN p) { pari_sp av = avma; GEN M,q,r; if (lgefint(p)==3) { ulong pp = to_Flx(&x, &y, p); M = FlxM_to_ZXM(Flx_halfgcd(x, y, pp)); } else { if (!signe(x)) { long v = varn(x); retmkmat2(mkcol2(pol_0(v),pol_1(v)), mkcol2(pol_1(v),pol_0(v))); } if (degpol(y)1) pari_warn(warnmem,"FpX_gcd (d = %ld)",degpol(b)); gerepileall(av0,2, &a,&b); } av = avma; c = FpX_rem(a,b,p); a=b; b=c; } avma = av; return a; } GEN FpX_gcd(GEN x, GEN y, GEN p) { pari_sp av = avma; if (lgefint(p)==3) { ulong pp; (void)new_chunk((lg(x) + lg(y)) << 2); /* scratch space */ pp = to_Flx(&x, &y, p); x = Flx_gcd(x, y, pp); avma = av; return Flx_to_ZX(x); } x = FpX_red(x, p); y = FpX_red(y, p); if (!signe(x)) return gerepileupto(av, y); while (lg(y)>FpX_GCD_LIMIT) { GEN c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r = FpX_rem(x, y, p); x = y; y = r; } c = FpXM_FpX_mul2(FpX_halfgcd(x,y, p), x, y, p); x = gel(c,1); y = gel(c,2); gerepileall(av,2,&x,&y); } return gerepileupto(av, FpX_gcd_basecase(x,y,p)); } /* Return NULL if gcd can be computed else return a factor of p */ GEN FpX_gcd_check(GEN x, GEN y, GEN p) { pari_sp av = avma; GEN a,b,c; a = FpX_red(x, p); b = FpX_red(y, p); while (signe(b)) { GEN g = gcdii(p, leading_coeff(b)); if (!equali1(g)) return gerepileuptoint(av,g); c = FpX_rem(a,b,p); a = b; b = c; if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd_check (d = %ld)",degpol(b)); gerepileall(av,2,&a,&b); } } avma = av; return NULL; } static GEN FpX_extgcd_basecase(GEN a, GEN b, GEN p, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,d,d1,v1; long vx = varn(a); d = a; d1 = b; v = pol_0(vx); v1 = pol_1(vx); while (signe(d1)) { GEN r, q = FpX_divrem(d,d1,p, &r); v = FpX_sub(v,FpX_mul(q,v1,p),p); u=v; v=v1; v1=u; u=r; d=d1; d1=u; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpX_extgcd (d = %ld)",degpol(d)); gerepileall(av,5, &d,&d1,&u,&v,&v1); } } if (ptu) *ptu = FpX_div(FpX_sub(d,FpX_mul(b,v,p),p),a,p); *ptv = v; return d; } static GEN FpX_extgcd_halfgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv) { pari_sp av=avma; GEN u,v,R = matid2_FpXM(varn(x)); while (lg(y)>FpX_EXTGCD_LIMIT) { GEN M, c; if (lgpol(y)<=(lgpol(x)>>1)) { GEN r, q = FpX_divrem(x, y, p, &r); x = y; y = r; R = FpX_FpXM_qmul(q, R, p); } M = FpX_halfgcd(x,y, p); c = FpXM_FpX_mul2(M, x,y, p); R = FpXM_mul2(M, R, p); x = gel(c,1); y = gel(c,2); gerepileall(av,3,&x,&y,&R); } y = FpX_extgcd_basecase(x,y,p,&u,&v); if (ptu) *ptu = FpX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1),p); *ptv = FpX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2),p); return y; } /* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st * ux + vy = gcd (mod p) */ GEN FpX_extgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv) { GEN d; pari_sp ltop=avma; if (lgefint(p)==3) { ulong pp = to_Flx(&x, &y, p); d = Flx_extgcd(x,y, pp, ptu,ptv); d = Flx_to_ZX(d); if (ptu) *ptu=Flx_to_ZX(*ptu); *ptv=Flx_to_ZX(*ptv); } else { x = FpX_red(x, p); y = FpX_red(y, p); if (lg(y)>FpX_EXTGCD_LIMIT) d = FpX_extgcd_halfgcd(x, y, p, ptu, ptv); else d = FpX_extgcd_basecase(x, y, p, ptu, ptv); } gerepileall(ltop,ptu?3:2,&d,ptv,ptu); return d; } GEN FpX_rescale(GEN P, GEN h, GEN p) { long i, l = lg(P); GEN Q = cgetg(l,t_POL), hi = h; Q[l-1] = P[l-1]; for (i=l-2; i>=2; i--) { gel(Q,i) = Fp_mul(gel(P,i), hi, p); if (i == 2) break; hi = Fp_mul(hi,h, p); } Q[1] = P[1]; return Q; } GEN FpX_deriv(GEN x, GEN p) { return FpX_red(ZX_deriv(x), p); } GEN FpX_integ(GEN x, GEN p) { long i, lx = lg(x); GEN y; if (lx == 2) return ZX_copy(x); y = cgetg(lx+1, t_POL); y[1] = x[1]; gel(y,2) = gen_0; for (i=3; i<=lx; i++) gel(y,i) = Fp_div(gel(x,i-1), utoipos(i-2), p); return ZX_renormalize(y, lx+1);; } INLINE GEN FpXn_recip(GEN P, long n) { return RgXn_recip_shallow(P, n); } GEN FpX_Newton(GEN P, long n, GEN p) { pari_sp av = avma; GEN dP = FpX_deriv(P, p); GEN Q = FpXn_recip(FpX_div(RgX_shift(dP,n), P, p), n); return gerepilecopy(av, Q); } GEN FpX_fromNewton(GEN P, GEN p) { pari_sp av = avma; long n = itos(modii(constant_coeff(P), p))+1; GEN z = FpX_neg(FpX_integ(RgX_shift(P,-1),p),p); GEN Q = FpXn_recip(FpXn_exp(z, n, p), n); return gerepilecopy(av, Q); } GEN FpX_invLaplace(GEN x, GEN p) { pari_sp av = avma; long i, e = 0, l = lg(x); GEN t = gen_1, y = cgetg(l,t_POL); y[1] = x[1]; for (i=2; i=2; i=j-1) { for (j=i; !signe(gel(x,j)); j--) if (j==2) { if (i!=j) y = Fp_powu(y,i-j+1,p); p1=mulii(p1,y); goto fppoleval;/*sorry break(2) no implemented*/ } r = (i==j)? y: Fp_powu(y,i-j+1,p); p1 = Fp_addmul(gel(x,j), p1, r, p); if ((i & 7) == 0) { affii(p1, res); p1 = res; avma = av; } } fppoleval: modiiz(p1,p,res); avma = av; return res; } /* Tz=Tx*Ty where Tx and Ty coprime * return lift(chinese(Mod(x*Mod(1,p),Tx*Mod(1,p)),Mod(y*Mod(1,p),Ty*Mod(1,p)))) * if Tz is NULL it is computed * As we do not return it, and the caller will frequently need it, * it must compute it and pass it. */ GEN FpX_chinese_coprime(GEN x,GEN y,GEN Tx,GEN Ty,GEN Tz,GEN p) { pari_sp av = avma; GEN ax,p1; ax = FpX_mul(FpXQ_inv(Tx,Ty,p), Tx,p); p1 = FpX_mul(ax, FpX_sub(y,x,p),p); p1 = FpX_add(x,p1,p); if (!Tz) Tz=FpX_mul(Tx,Ty,p); p1 = FpX_rem(p1,Tz,p); return gerepileupto(av,p1); } /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/ GEN FpX_resultant(GEN a, GEN b, GEN p) { long da,db,dc; pari_sp av; GEN c,lb, res = gen_1; if (!signe(a) || !signe(b)) return gen_0; if (lgefint(p) == 3) { pari_sp av = avma; ulong pp = to_Flx(&a, &b, p); long r = Flx_resultant(a, b, pp); avma = av; return utoi(r); } da = degpol(a); db = degpol(b); if (db > da) { swapspec(a,b, da,db); if (both_odd(da,db)) res = subii(p, res); } if (!da) return gen_1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */ av = avma; while (db) { lb = gel(b,db+2); c = FpX_rem(a,b, p); a = b; b = c; dc = degpol(c); if (dc < 0) { avma = av; return gen_0; } if (both_odd(da,db)) res = subii(p, res); if (!equali1(lb)) res = Fp_mul(res, Fp_powu(lb, da - dc, p), p); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpX_resultant (da = %ld)",da); gerepileall(av,3, &a,&b,&res); } da = db; /* = degpol(a) */ db = dc; /* = degpol(b) */ } res = Fp_mul(res, Fp_powu(gel(b,2), da, p), p); return gerepileuptoint(av, res); } /* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */ GEN FpX_disc(GEN P, GEN p) { pari_sp av = avma; GEN L, dP = FpX_deriv(P,p), D = FpX_resultant(P, dP, p); long dd; if (!signe(D)) return gen_0; dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */ L = leading_coeff(P); if (dd && !equali1(L)) D = (dd == -1)? Fp_div(D,L,p): Fp_mul(D, Fp_powu(L, dd, p), p); if (degpol(P) & 2) D = Fp_neg(D ,p); return gerepileuptoint(av, D); } GEN FpXV_prod(GEN V, GEN p) { struct _FpXQ D; D.p = p; return gen_product(V, (void *)&D, &_FpX_mul); } GEN FpV_roots_to_pol(GEN V, GEN p, long v) { pari_sp ltop=avma; long i; GEN g=cgetg(lg(V),t_VEC); for(i=1;i 1; i--) { gel(y,i) = Fp_mul(u, gel(y,i-1), p); u = Fp_mul(u, gel(x,i), p); /* u = 1 / (x[1] ... x[i-1]) */ } gel(y,1) = u; return y; } GEN FqV_inv(GEN x, GEN T, GEN p) { long i, lx = lg(x); GEN u, y = cgetg(lx, t_VEC); gel(y,1) = gel(x,1); for (i=2; i 1; i--) { gel(y,i) = Fq_mul(u, gel(y,i-1), T,p); u = Fq_mul(u, gel(x,i), T,p); /* u = 1 / (x[1] ... x[i-1]) */ } gel(y,1) = u; return y; } /***********************************************************************/ /** **/ /** Barrett reduction **/ /** **/ /***********************************************************************/ static GEN FpX_invBarrett_basecase(GEN T, GEN p) { long i, l=lg(T)-1, lr = l-1, k; GEN r=cgetg(lr, t_POL); r[1]=T[1]; gel(r,2) = gen_1; for (i=3; i=0; i--) if (signe(gel(x,i))) break; return i+1; } INLINE GEN FpX_recipspec(GEN x, long l, long n) { return RgX_recipspec_shallow(x, l, n); } static GEN FpX_invBarrett_Newton(GEN T, GEN p) { pari_sp av = avma; long nold, lx, lz, lq, l = degpol(T), i, lQ; GEN q, y, z, x = cgetg(l+2, t_POL) + 2; ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */ for (i=0;i1) gel(q,1) = Fp_red(gel(q,1), p); if (lQ>1 && signe(gel(q,1))) { GEN u = gel(q, 1); if (!equali1(gel(x,0))) u = Fp_mul(u, Fp_sqr(gel(x,0), p), p); gel(x,1) = Fp_neg(u, p); lx = 2; } else lx = 1; nold = 1; for (; mask > 1; ) { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */ long i, lnew, nnew = nold << 1; if (mask & 1) nnew--; mask >>= 1; lnew = nnew + 1; lq = ZX_lgrenormalizespec(q, minss(lQ,lnew)); z = FpX_mulspec(x, q, p, lx, lq); /* FIXME: high product */ lz = lgpol(z); if (lz > lnew) lz = lnew; z += 2; /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */ for (i = nold; i < lz; i++) if (signe(gel(z,i))) break; nold = nnew; if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */ /* z + i represents (x*q - 1) / t^i */ lz = ZX_lgrenormalizespec (z+i, lz-i); z = FpX_mulspec(x, z+i, p, lx, lz); /* FIXME: low product */ lz = lgpol(z); z += 2; if (lz > lnew-i) lz = ZX_lgrenormalizespec(z, lnew-i); lx = lz+ i; y = x + i; /* x -= z * t^i, in place */ for (i = 0; i < lz; i++) gel(y,i) = Fp_neg(gel(z,i), p); } x -= 2; setlg(x, lx + 2); x[1] = T[1]; return gerepilecopy(av, x); } /* 1/polrecip(T)+O(x^(deg(T)-1)) */ GEN FpX_invBarrett(GEN T, GEN p) { pari_sp ltop = avma; long l = lg(T); GEN r; if (l<5) return pol_0(varn(T)); if (l<=FpX_INVBARRETT_LIMIT) { GEN c = gel(T,l-1), ci=gen_1; if (!equali1(c)) { ci = Fp_inv(c, p); T = FpX_Fp_mul(T, ci, p); r = FpX_invBarrett_basecase(T, p); r = FpX_Fp_mul(r, ci, p); } else r = FpX_invBarrett_basecase(T, p); } else r = FpX_invBarrett_Newton(T, p); return gerepileupto(ltop, r); } GEN FpX_get_red(GEN T, GEN p) { if (typ(T)==t_POL && lg(T)>FpX_BARRETT_LIMIT) retmkvec2(FpX_invBarrett(T,p),T); return T; } /* Compute x mod T where 2 <= degpol(T) <= l+1 <= 2*(degpol(T)-1) * and mg is the Barrett inverse of T. */ static GEN FpX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN T, GEN p, GEN *pr) { GEN q, r; long lt = degpol(T); /*We discard the leading term*/ long ld, lm, lT, lmg; ld = l-lt; lm = minss(ld, lgpol(mg)); lT = ZX_lgrenormalizespec(T+2,lt); lmg = ZX_lgrenormalizespec(mg+2,lm); q = FpX_recipspec(x+lt,ld,ld); /* q = rec(x) lq<=ld*/ q = FpX_mulspec(q+2,mg+2,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/ q = FpX_recipspec(q+2,minss(ld,lgpol(q)),ld);/* q = rec (rec(x) * mg) lq<=ld*/ if (!pr) return q; r = FpX_mulspec(q+2,T+2,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/ r = FpX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */ if (pr == ONLY_REM) return r; *pr = r; return q; } static GEN FpX_divrem_Barrett_noGC(GEN x, GEN mg, GEN T, GEN p, GEN *pr) { GEN q = NULL, r = FpX_red(x, p); long l = lgpol(r), lt = degpol(T), lm = 2*lt-1; long i; if (l <= lt) { if (pr == ONLY_REM) return r; if (pr == ONLY_DIVIDES) return signe(x)? NULL: pol_0(varn(x)); if (pr) *pr = r; return pol_0(varn(T)); } if (lt <= 1) return FpX_divrem_basecase(r,T,p,pr); if (pr != ONLY_REM && l>lm) { q = cgetg(l-lt+2, t_POL); for (i=0;ilm) { GEN zr, zq = FpX_divrem_Barrettspec(r+2+l-lm,lm,mg,T,p,&zr); long lz = lgpol(zr); if (pr != ONLY_REM) { long lq = lgpol(zq); for(i=0; i lt) { GEN zq = FpX_divrem_Barrettspec(r+2,l,mg,T,p,&r); if (!q) q = zq; else { long lq = lgpol(zq); for(i=0; i lt) r = FpX_divrem_Barrettspec(r+2, l, mg, T, p, ONLY_REM); else r = FpX_renormalize(r, l+2); r[1] = x[1]; return FpX_renormalize(r, lg(r)); } if (pr) { r[1] = x[1]; r = FpX_renormalize(r, lg(r)); } q[1] = x[1]; q = FpX_renormalize(q, lg(q)); if (pr == ONLY_DIVIDES) return signe(r)? NULL: q; if (pr) *pr = r; return q; } GEN FpX_divrem(GEN x, GEN T, GEN p, GEN *pr) { GEN B, y = get_FpX_red(T, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (pr==ONLY_REM) return FpX_rem(x, y, p); if (!B && d+3 < FpX_DIVREM_BARRETT_LIMIT) return FpX_divrem_basecase(x,y,p,pr); else if (lgefint(p)==3) { pari_sp av = avma; ulong pp = to_Flxq(&x, &T, p); GEN z = Flx_divrem(x, T, pp, pr); if (!z) return NULL; if (!pr || pr == ONLY_DIVIDES) return Flx_to_ZX_inplace(gerepileuptoleaf(av, z)); z = Flx_to_ZX(z); *pr = Flx_to_ZX(*pr); gerepileall(av, 2, &z, pr); return z; } else { pari_sp av=avma; GEN mg = B? B: FpX_invBarrett(y, p); GEN q1 = FpX_divrem_Barrett_noGC(x,mg,y,p,pr); if (!q1) {avma=av; return NULL;} if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q1); gerepileall(av,2,&q1,pr); return q1; } } GEN FpX_rem(GEN x, GEN T, GEN p) { GEN B, y = get_FpX_red(T, &B); long dy = degpol(y), dx = degpol(x), d = dx-dy; if (d < 0) return FpX_red(x,p); if (!B && d+3 < FpX_REM_BARRETT_LIMIT) return FpX_divrem_basecase(x,y,p,ONLY_REM); else if (lgefint(p)==3) { pari_sp av = avma; ulong pp = to_Flxq(&x, &T, p); return Flx_to_ZX_inplace(gerepileuptoleaf(av, Flx_rem(x, T, pp))); } else { pari_sp av = avma; GEN mg = B? B: FpX_invBarrett(y, p); return gerepileupto(av, FpX_divrem_Barrett_noGC(x, mg, y, p, ONLY_REM)); } } static GEN FpV_producttree(GEN xa, GEN s, GEN p, long vs) { long n = lg(xa)-1; long m = n==1 ? 1: expu(n-1)+1; long i, j, k, ls = lg(s); GEN T = cgetg(m+1, t_VEC); GEN t = cgetg(ls, t_VEC); for (j=1, k=1; j>1)+1, t_VEC); for (j=1, k=1; k=1; i--) { GEN u = gel(T, i); GEN v = gel(Tp, i+1); long n = lg(u)-1; t = cgetg(n+1, t_VEC); for (j=1, k=1; kT, D->p); } static GEN _FpXQ_mul(void *data, GEN x, GEN y) { struct _FpXQ *D = (struct _FpXQ*)data; return FpXQ_mul(x,y, D->T, D->p); } static GEN _FpXQ_zero(void *data) { struct _FpXQ *D = (struct _FpXQ*)data; return pol_0(get_FpX_var(D->T)); } static GEN _FpXQ_one(void *data) { struct _FpXQ *D = (struct _FpXQ*)data; return pol_1(get_FpX_var(D->T)); } static GEN _FpXQ_red(void *data, GEN x) { struct _FpXQ *D = (struct _FpXQ*)data; return FpX_red(x,D->p); } static struct bb_algebra FpXQ_algebra = { _FpXQ_red, _FpXQ_add, _FpXQ_sub, _FpXQ_mul, _FpXQ_sqr, _FpXQ_one, _FpXQ_zero }; const struct bb_algebra * get_FpXQ_algebra(void **E, GEN T, GEN p) { GEN z = new_chunk(sizeof(struct _FpXQ)); struct _FpXQ *e = (struct _FpXQ *) z; e->T = FpX_get_red(T, p); e->p = p; *E = (void*)e; return &FpXQ_algebra; } static struct bb_algebra FpX_algebra = { _FpXQ_red, _FpXQ_add, _FpXQ_sub, _FpX_mul, _FpX_sqr, _FpXQ_one, _FpXQ_zero }; const struct bb_algebra * get_FpX_algebra(void **E, GEN p, long v) { GEN z = new_chunk(sizeof(struct _FpXQ)); struct _FpXQ *e = (struct _FpXQ *) z; e->T = pol_x(v); e->p = p; *E = (void*)e; return &FpX_algebra; } /* x,pol in Z[X], p in Z, n in Z, compute lift(x^n mod (p, pol)) */ GEN FpXQ_pow(GEN x, GEN n, GEN T, GEN p) { struct _FpXQ D; pari_sp av; long s = signe(n); GEN y; if (!s) return pol_1(varn(x)); if (is_pm1(n)) /* +/- 1 */ return (s < 0)? FpXQ_inv(x,T,p): FpXQ_red(x,T,p); av = avma; if (!is_bigint(p)) { ulong pp = to_Flxq(&x, &T, p); y = Flxq_pow(x, n, T, pp); return Flx_to_ZX_inplace(gerepileuptoleaf(av, y)); } if (s < 0) x = FpXQ_inv(x,T,p); D.p = p; D.T = FpX_get_red(T,p); y = gen_pow(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul); return gerepileupto(av, y); } GEN /*Assume n is very small*/ FpXQ_powu(GEN x, ulong n, GEN T, GEN p) { struct _FpXQ D; pari_sp av; GEN y; if (!n) return pol_1(varn(x)); if (n==1) return FpXQ_red(x,T,p); av = avma; if (!is_bigint(p)) { ulong pp = to_Flxq(&x, &T, p); y = Flxq_powu(x, n, T, pp); return Flx_to_ZX_inplace(gerepileuptoleaf(av, y)); } D.T = FpX_get_red(T, p); D.p = p; y = gen_powu(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul); return gerepileupto(av, y); } /* generates the list of powers of x of degree 0,1,2,...,l*/ GEN FpXQ_powers(GEN x, long l, GEN T, GEN p) { struct _FpXQ D; int use_sqr; if (l>2 && lgefint(p) == 3) { pari_sp av = avma; ulong pp = to_Flxq(&x, &T, p); GEN z = FlxV_to_ZXV(Flxq_powers(x, l, T, pp)); return gerepileupto(av, z); } use_sqr = 2*degpol(x)>=get_FpX_degree(T); D.T = FpX_get_red(T,p); D.p = p; return gen_powers(x, l, use_sqr, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul,&_FpXQ_one); } GEN FpXQ_matrix_pow(GEN y, long n, long m, GEN P, GEN l) { return RgXV_to_RgM(FpXQ_powers(y,m-1,P,l),n); } GEN FpX_Frobenius(GEN T, GEN p) { return FpXQ_pow(pol_x(get_FpX_var(T)), p, T, p); } GEN FpX_matFrobenius(GEN T, GEN p) { long n = get_FpX_degree(T); return FpXQ_matrix_pow(FpX_Frobenius(T, p), n, n, T, p); } GEN FpX_FpXQV_eval(GEN Q, GEN x, GEN T, GEN p) { struct _FpXQ D; D.T = FpX_get_red(T,p); D.p = p; return gen_bkeval_powers(Q,degpol(Q),x,(void*)&D,&FpXQ_algebra,_FpXQ_cmul); } GEN FpX_FpXQ_eval(GEN Q, GEN x, GEN T, GEN p) { struct _FpXQ D; int use_sqr; if (lgefint(p) == 3) { pari_sp av = avma; ulong pp = to_Flxq(&x, &T, p); GEN z = Flx_Flxq_eval(ZX_to_Flx(Q, pp), x, T, pp); return Flx_to_ZX_inplace(gerepileuptoleaf(av, z)); } use_sqr = 2*degpol(x) >= get_FpX_degree(T); D.T = FpX_get_red(T,p); D.p = p; return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)&D,&FpXQ_algebra,_FpXQ_cmul); } GEN FpXC_FpXQV_eval(GEN P, GEN x, GEN T, GEN p) { long i, l = lg(P); GEN res = cgetg(l, t_COL); for (i=1; iT, D->p); } static GEN FpXQ_autpow_mul(void *E, GEN x, GEN y) { struct _FpXQ *D = (struct _FpXQ*)E; return FpX_FpXQ_eval(x, y, D->T, D->p); } GEN FpXQ_autpow(GEN x, ulong n, GEN T, GEN p) { struct _FpXQ D; if (n==0) return FpX_rem(pol_x(varn(x)), T, p); if (n==1) return FpX_rem(x, T, p); D.T = FpX_get_red(T, p); D.p = p; return gen_powu(x,n,(void*)&D,FpXQ_autpow_sqr,FpXQ_autpow_mul); } static GEN FpXQ_auttrace_mul(void *E, GEN x, GEN y) { struct _FpXQ *D = (struct _FpXQ*)E; GEN T = D->T, p = D->p; GEN phi1 = gel(x,1), a1 = gel(x,2); GEN phi2 = gel(y,1), a2 = gel(y,2); ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1); GEN V1 = FpXQ_powers(phi1, d, T, p); GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p); GEN aphi = FpX_FpXQV_eval(a2, V1, T, p); GEN a3 = FpX_add(a1, aphi, p); return mkvec2(phi3, a3); } static GEN FpXQ_auttrace_sqr(void *E, GEN x) { return FpXQ_auttrace_mul(E, x, x); } GEN FpXQ_auttrace(GEN x, ulong n, GEN T, GEN p) { struct _FpXQ D; D.T = FpX_get_red(T, p); D.p = p; return gen_powu(x,n,(void*)&D,FpXQ_auttrace_sqr,FpXQ_auttrace_mul); } static GEN FpXQ_autsum_mul(void *E, GEN x, GEN y) { struct _FpXQ *D = (struct _FpXQ*)E; GEN T = D->T, p = D->p; GEN phi1 = gel(x,1), a1 = gel(x,2); GEN phi2 = gel(y,1), a2 = gel(y,2); ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1); GEN V1 = FpXQ_powers(phi1, d, T, p); GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p); GEN aphi = FpX_FpXQV_eval(a2, V1, T, p); GEN a3 = FpXQ_mul(a1, aphi, T, p); return mkvec2(phi3, a3); } static GEN FpXQ_autsum_sqr(void *E, GEN x) { return FpXQ_autsum_mul(E, x, x); } GEN FpXQ_autsum(GEN x, ulong n, GEN T, GEN p) { struct _FpXQ D; D.T = FpX_get_red(T, p); D.p = p; return gen_powu(x,n,(void*)&D,FpXQ_autsum_sqr,FpXQ_autsum_mul); } static GEN FpXQM_autsum_mul(void *E, GEN x, GEN y) { struct _FpXQ *D = (struct _FpXQ*)E; GEN T = D->T, p = D->p; GEN phi1 = gel(x,1), a1 = gel(x,2); GEN phi2 = gel(y,1), a2 = gel(y,2); long g = lg(a2)-1, dT = get_FpX_degree(T); ulong d = brent_kung_optpow(dT-1, g*g+1, 1); GEN V1 = FpXQ_powers(phi1, d, T, p); GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p); GEN aphi = FpXM_FpXQV_eval(a2, V1, T, p); GEN a3 = FqM_mul(a1, aphi, T, p); return mkvec2(phi3, a3); } static GEN FpXQM_autsum_sqr(void *E, GEN x) { return FpXQM_autsum_mul(E, x, x); } GEN FpXQM_autsum(GEN x, ulong n, GEN T, GEN p) { struct _FpXQ D; D.T = FpX_get_red(T, p); D.p = p; return gen_powu(x, n, (void*)&D, FpXQM_autsum_sqr, FpXQM_autsum_mul); } static long bounded_order(GEN p, GEN b, long k) { long i; GEN a=modii(p,b); for(i=1;i 1) z = gel(FpXQ_autsum(mkvec2(autk, z), m, T, p), 2); if (!is_pm1(u)) z = FpXQ_pow(z, u, T, p); if (signe(v)) z = FpXQ_mul(z, FpXQ_pow(x, v, T, p), T, p); } return gerepileupto(av,signe(n)>0 ? z : FpXQ_inv(z,T,p)); } /* assume T irreducible mod p */ int FpXQ_issquare(GEN x, GEN T, GEN p) { pari_sp av; long res; if (lg(x) == 2 || absequalui(2, p)) return 1; if (lg(x) == 3) return Fq_issquare(gel(x,2), T, p); /* Ng = g^((q-1)/(p-1)) */ av = avma; res = kronecker(FpXQ_norm(x,T,p), p) == 1; avma = av; return res; } int Fp_issquare(GEN x, GEN p) { if (absequalui(2, p)) return 1; return kronecker(x, p) == 1; } /* assume T irreducible mod p */ int Fq_issquare(GEN x, GEN T, GEN p) { if (typ(x) != t_INT) return FpXQ_issquare(x, T, p); return (T && ! odd(get_FpX_degree(T))) || Fp_issquare(x, p); } long Fq_ispower(GEN x, GEN K, GEN T, GEN p) { pari_sp av = avma; long d; GEN Q; if (equaliu(K,2)) return Fq_issquare(x, T, p); if (!T) return Fp_ispower(x, K, p); d = get_FpX_degree(T); if (typ(x) == t_INT && !umodui(d, K)) return 1; Q = subiu(powiu(p,d), 1); Q = diviiexact(Q, gcdii(Q, K)); d = gequal1(Fq_pow(x, Q, T,p)); avma = av; return d; } /* discrete log in FpXQ for a in Fp^*, g in FpXQ^* of order ord */ GEN Fp_FpXQ_log(GEN a, GEN g, GEN o, GEN T, GEN p) { pari_sp av = avma; GEN q,n_q,ord,ordp, op; if (equali1(a)) return gen_0; /* p > 2 */ ordp = subiu(p, 1); /* even */ ord = get_arith_Z(o); if (!ord) ord = T? subiu(powiu(p, get_FpX_degree(T)), 1): ordp; if (equalii(a, ordp)) /* -1 */ return gerepileuptoint(av, shifti(ord,-1)); ordp = gcdii(ordp,ord); op = typ(o)==t_MAT ? famat_Z_gcd(o,ordp) : ordp; q = NULL; if (T) { /* we want < g > = Fp^* */ if (!equalii(ord,ordp)) { q = diviiexact(ord,ordp); g = FpXQ_pow(g,q,T,p); } g = constant_coeff(g); } n_q = Fp_log(a,g,op,p); if (lg(n_q)==1) return gerepileuptoleaf(av, n_q); if (q) n_q = mulii(q, n_q); return gerepileuptoint(av, n_q); } static GEN _FpXQ_pow(void *data, GEN x, GEN n) { struct _FpXQ *D = (struct _FpXQ*)data; return FpXQ_pow_Frobenius(x,n, D->aut, D->T, D->p); } static GEN _FpXQ_rand(void *data) { pari_sp av=avma; struct _FpXQ *D = (struct _FpXQ*)data; GEN z; do { avma=av; z=random_FpX(get_FpX_degree(D->T),get_FpX_var(D->T),D->p); } while (!signe(z)); return z; } static GEN _FpXQ_easylog(void *E, GEN a, GEN g, GEN ord) { struct _FpXQ *s=(struct _FpXQ*) E; if (degpol(a)) return NULL; return Fp_FpXQ_log(constant_coeff(a),g,ord,s->T,s->p); } static const struct bb_group FpXQ_star={_FpXQ_mul,_FpXQ_pow,_FpXQ_rand,hash_GEN,ZX_equal,ZX_equal1,_FpXQ_easylog}; const struct bb_group * get_FpXQ_star(void **E, GEN T, GEN p) { struct _FpXQ *e = (struct _FpXQ *) stack_malloc(sizeof(struct _FpXQ)); e->T = T; e->p = p; e->aut = FpX_Frobenius(T, p); *E = (void*)e; return &FpXQ_star; } GEN FpXQ_order(GEN a, GEN ord, GEN T, GEN p) { if (lgefint(p)==3) { pari_sp av=avma; ulong pp = to_Flxq(&a, &T, p); GEN z = Flxq_order(a, ord, T, pp); return gerepileuptoint(av,z); } else { void *E; const struct bb_group *S = get_FpXQ_star(&E,T,p); return gen_order(a,ord,E,S); } } GEN FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p) { pari_sp av=avma; if (lgefint(p)==3) { if (uel(p,2) == 2) { GEN z = F2xq_log(ZX_to_F2x(a), ZX_to_F2x(g), ord, ZX_to_F2x(get_FpX_mod(T))); return gerepileuptoleaf(av, z); } else { ulong pp = to_Flxq(&a, &T, p); GEN z = Flxq_log(a, ZX_to_Flx(g, pp), ord, T, pp); return gerepileuptoleaf(av, z); } } else { void *E; const struct bb_group *S = get_FpXQ_star(&E,T,p); GEN z = gen_PH_log(a,g,ord,E,S); return gerepileuptoleaf(av, z); } } GEN Fq_log(GEN a, GEN g, GEN ord, GEN T, GEN p) { if (!T) return Fp_log(a,g,ord,p); if (typ(g) == t_INT) { if (typ(a) == t_POL) { if (degpol(a)) return cgetg(1,t_VEC); a = gel(a,2); } return Fp_log(a,g,ord,p); } return typ(a) == t_INT? Fp_FpXQ_log(a,g,ord,T,p): FpXQ_log(a,g,ord,T,p); } GEN FpXQ_sqrtn(GEN a, GEN n, GEN T, GEN p, GEN *zeta) { pari_sp av = avma; GEN z; if (!signe(a)) { long v=varn(a); if (signe(n) < 0) pari_err_INV("FpXQ_sqrtn",a); if (zeta) *zeta=pol_1(v); return pol_0(v); } if (lgefint(p)==3) { if (uel(p,2) == 2) { z = F2xq_sqrtn(ZX_to_F2x(a), n, ZX_to_F2x(get_FpX_mod(T)), zeta); if (!z) return NULL; z = F2x_to_ZX(z); if (!zeta) return gerepileuptoleaf(av, z); *zeta=F2x_to_ZX(*zeta); } else { ulong pp = to_Flxq(&a, &T, p); z = Flxq_sqrtn(a, n, T, pp, zeta); if (!z) return NULL; if (!zeta) return Flx_to_ZX_inplace(gerepileuptoleaf(av, z)); z = Flx_to_ZX(z); *zeta=Flx_to_ZX(*zeta); } } else { void *E; const struct bb_group *S = get_FpXQ_star(&E,T,p); GEN o = subiu(powiu(p,get_FpX_degree(T)),1); z = gen_Shanks_sqrtn(a,n,o,zeta,E,S); if (!z) return NULL; if (!zeta) return gerepileupto(av, z); } gerepileall(av, 2, &z,zeta); return z; } GEN FpXQ_sqrt(GEN a, GEN T, GEN p) { return FpXQ_sqrtn(a, gen_2, T, p, NULL); } GEN FpXQ_norm(GEN x, GEN TB, GEN p) { pari_sp av = avma; GEN T = get_FpX_mod(TB); GEN y = FpX_resultant(T, x, p); GEN L = leading_coeff(T); if (gequal1(L) || signe(x)==0) return y; return gerepileupto(av, Fp_div(y, Fp_pows(L, degpol(x), p), p)); } GEN FpXQ_trace(GEN x, GEN TB, GEN p) { pari_sp av = avma; GEN T = get_FpX_mod(TB); GEN dT = FpX_deriv(T,p); long n = degpol(dT); GEN z = FpXQ_mul(x, dT, TB, p); if (degpol(z)v(tau*z) that is, v*(M_tau) */ static GEN FpXQ_transmul_init(GEN tau, GEN T, GEN p) { GEN bht; GEN h, Tp = get_FpX_red(T, &h); long n = degpol(Tp), vT = varn(Tp); GEN ft = FpX_recipspec(Tp+2, n+1, n+1); GEN bt = FpX_recipspec(tau+2, lgpol(tau), n); setvarn(ft, vT); setvarn(bt, vT); if (h) bht = FpXn_mul(bt, h, n-1, p); else { GEN bh = FpX_div(RgX_shift_shallow(tau, n-1), T, p); bht = FpX_recipspec(bh+2, lgpol(bh), n-1); setvarn(bht, vT); } return mkvec3(bt, bht, ft); } static GEN FpXQ_transmul(GEN tau, GEN a, long n, GEN p) { pari_sp ltop = avma; GEN t1, t2, t3, vec; GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3); if (signe(a)==0) return pol_0(varn(a)); t2 = RgX_shift_shallow(FpX_mul(bt, a, p),1-n); if (signe(bht)==0) return gerepilecopy(ltop, t2); t1 = RgX_shift_shallow(FpX_mul(ft, a, p),-n); t3 = FpXn_mul(t1, bht, n-1, p); vec = FpX_sub(t2, RgX_shift_shallow(t3, 1), p); return gerepileupto(ltop, vec); } GEN FpXQ_minpoly(GEN x, GEN T, GEN p) { pari_sp ltop = avma; long vT, n; GEN v_x, g, tau; if (lgefint(p)==3) { ulong pp = to_Flxq(&x, &T, p); GEN g = Flxq_minpoly(x, T, pp); return gerepileupto(ltop, Flx_to_ZX(g)); } vT = get_FpX_var(T); n = get_FpX_degree(T); g = pol_1(vT); tau = pol_1(vT); T = FpX_get_red(T, p); x = FpXQ_red(x, T, p); v_x = FpXQ_powers(x, usqrt(2*n), T, p); while(signe(tau) != 0) { long i, j, m, k1; GEN M, v, tr; GEN g_prime, c; if (degpol(g) == n) { tau = pol_1(vT); g = pol_1(vT); } v = random_FpX(n, vT, p); tr = FpXQ_transmul_init(tau, T, p); v = FpXQ_transmul(tr, v, n, p); m = 2*(n-degpol(g)); k1 = usqrt(m); tr = FpXQ_transmul_init(gel(v_x,k1+1), T, p); c = cgetg(m+2,t_POL); c[1] = evalsigne(1)|evalvarn(vT); for (i=0; i , i = 0..m-1 */ M = FpX_halfgcd(pol_xn(m, vT), c, p); g_prime = gmael(M, 2, 2); if (degpol(g_prime) < 1) continue; g = FpX_mul(g, g_prime, p); tau = FpXQ_mul(tau, FpX_FpXQV_eval(g_prime, v_x, T, p), T, p); } g = FpX_normalize(g,p); return gerepilecopy(ltop,g); } GEN FpXQ_conjvec(GEN x, GEN T, GEN p) { pari_sp av=avma; long i; long n = get_FpX_degree(T), v = varn(x); GEN M = FpX_matFrobenius(T, p); GEN z = cgetg(n+1,t_COL); gel(z,1) = RgX_to_RgC(x,n); for (i=2; i<=n; i++) gel(z,i) = FpM_FpC_mul(M,gel(z,i-1),p); gel(z,1) = x; for (i=2; i<=n; i++) gel(z,i) = RgV_to_RgX(gel(z,i),v); return gerepilecopy(av,z); } /* p prime, p_1 = p-1, q = p^deg T, Lp = cofactors of some prime divisors * l_p of p-1, Lq = cofactors of some prime divisors l_q of q-1, return a * g in Fq such that * - Ng generates all l_p-Sylows of Fp^* * - g generates all l_q-Sylows of Fq^* */ static GEN gener_FpXQ_i(GEN T, GEN p, GEN p_1, GEN Lp, GEN Lq) { pari_sp av; long vT = varn(T), f = degpol(T), l = lg(Lq); GEN F = FpX_Frobenius(T, p); int p_is_2 = is_pm1(p_1); for (av = avma;; avma = av) { GEN t, g = random_FpX(f, vT, p); long i; if (degpol(g) < 1) continue; if (p_is_2) t = g; else { t = FpX_resultant(T, g, p); /* Ng = g^((q-1)/(p-1)), assuming T monic */ if (kronecker(t, p) == 1) continue; if (lg(Lp) > 1 && !is_gener_Fp(t, p, p_1, Lp)) continue; t = FpXQ_pow(g, shifti(p_1,-1), T, p); } for (i = 1; i < l; i++) { GEN a = FpXQ_pow_Frobenius(t, gel(Lq,i), F, T, p); if (!degpol(a) && equalii(gel(a,2), p_1)) break; } if (i == l) return g; } } GEN gener_FpXQ(GEN T, GEN p, GEN *po) { long i, j, f = get_FpX_degree(T); GEN g, Lp, Lq, p_1, q_1, N, o; pari_sp av = avma; p_1 = subiu(p,1); if (f == 1) { GEN Lp, fa; o = p_1; fa = Z_factor(o); Lp = gel(fa,1); Lp = vecslice(Lp, 2, lg(Lp)-1); /* remove 2 for efficiency */ g = cgetg(3, t_POL); g[1] = evalsigne(1) | evalvarn(get_FpX_var(T)); gel(g,2) = pgener_Fp_local(p, Lp); if (po) *po = mkvec2(o, fa); return g; } if (lgefint(p) == 3) { ulong pp = to_Flxq(NULL, &T, p); g = gener_Flxq(T, pp, po); if (!po) return Flx_to_ZX_inplace(gerepileuptoleaf(av, g)); g = Flx_to_ZX(g); gerepileall(av, 2, &g, po); return g; } /* p now odd */ q_1 = subiu(powiu(p,f), 1); N = diviiexact(q_1, p_1); Lp = odd_prime_divisors(p_1); for (i=lg(Lp)-1; i; i--) gel(Lp,i) = diviiexact(p_1, gel(Lp,i)); o = factor_pn_1(p,f); Lq = leafcopy( gel(o, 1) ); for (i = j = 1; i < lg(Lq); i++) { if (dvdii(p_1, gel(Lq,i))) continue; gel(Lq,j++) = diviiexact(N, gel(Lq,i)); } setlg(Lq, j); g = gener_FpXQ_i(get_FpX_mod(T), p, p_1, Lp, Lq); if (!po) g = gerepilecopy(av, g); else { *po = mkvec2(q_1, o); gerepileall(av, 2, &g, po); } return g; } GEN gener_FpXQ_local(GEN T, GEN p, GEN L) { GEN Lp, Lq, p_1 = subiu(p,1), q_1, N, Q; long f, i, ip, iq, l = lg(L); T = get_FpX_mod(T); f = degpol(T); q_1 = subiu(powiu(p,f), 1); N = diviiexact(q_1, p_1); Q = is_pm1(p_1)? gen_1: shifti(p_1,-1); Lp = cgetg(l, t_VEC); ip = 1; Lq = cgetg(l, t_VEC); iq = 1; for (i=1; i < l; i++) { GEN a, b, ell = gel(L,i); if (absequaliu(ell,2)) continue; a = dvmdii(Q, ell, &b); if (b == gen_0) gel(Lp,ip++) = a; else gel(Lq,iq++) = diviiexact(N,ell); } setlg(Lp, ip); setlg(Lq, iq); return gener_FpXQ_i(T, p, p_1, Lp, Lq); } /***********************************************************************/ /** **/ /** FpXn **/ /** **/ /***********************************************************************/ INLINE GEN FpXn_red(GEN a, long n) { return RgXn_red_shallow(a, n); } GEN FpXn_mul(GEN a, GEN b, long n, GEN p) { return FpX_red(ZXn_mul(a, b, n), p); } GEN FpXn_sqr(GEN a, long n, GEN p) { return FpX_red(ZXn_sqr(a, n), p); } GEN FpXn_exp(GEN h, long e, GEN p) { pari_sp av = avma, av2; long v = varn(h), n=1; GEN f = pol_1(v), g = pol_1(v); ulong mask = quadratic_prec_mask(e); av2 = avma; if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2))) pari_err_DOMAIN("FpXn_exp","valuation", "<", gen_1, h); for (;mask>1;) { GEN q, w; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; g = FpX_sub(FpX_mulu(g,2,p), FpXn_mul(f, FpXn_sqr(g, n2, p), n2, p), p); q = FpX_deriv(FpXn_red(h,n2), p); w = FpX_add(q, FpXn_mul(g, FpX_sub(FpX_deriv(f, p), FpXn_mul(f,q,n-1, p), p),n-1, p), p); f = FpX_add(f, FpXn_mul(f, FpX_sub(FpXn_red(h, n), FpX_integ(w,p), p), n, p), p); if (gc_needed(av2,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpXn_exp, e = %ld", n); gerepileall(av2, 2, &f, &g); } } return gerepileupto(av, f); } /* (f*g) \/ x^n */ static GEN FpX_mulhigh_i(GEN f, GEN g, long n, GEN p) { return RgX_shift_shallow(FpX_mul(f,g, p),-n); } static GEN FpXn_mulhigh(GEN f, GEN g, long n2, long n, GEN p) { GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2); return FpX_add(FpX_mulhigh_i(fl, g, n2, p), FpXn_mul(fh, g, n - n2, p), p); } GEN FpXn_inv(GEN f, long e, GEN p) { pari_sp av = avma, av2; ulong mask; GEN W, a; long v = varn(f), n = 1; if (!signe(f)) pari_err_INV("FpXn_inv",f); a = Fp_inv(gel(f,2), p); if (e == 1) return scalarpol(a, v); else if (e == 2) { GEN b; if (degpol(f) <= 0) return scalarpol(a, v); b = Fp_neg(gel(f,3),p); if (signe(b)==0) return scalarpol(a, v); if (!is_pm1(a)) b = Fp_mul(b, Fp_sqr(a, p), p); W = deg1pol_shallow(b, a, v); return gerepilecopy(av, W); } W = scalarpol_shallow(Fp_inv(gel(f,2), p),v); mask = quadratic_prec_mask(e); av2 = avma; for (;mask>1;) { GEN u, fr; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; fr = FpXn_red(f, n); u = FpXn_mul(W, FpXn_mulhigh(fr, W, n2, n, p), n-n2, p); W = FpX_sub(W, RgX_shift_shallow(u, n2), p); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"FpXn_inv, e = %ld", n); W = gerepileupto(av2, W); } } return gerepileupto(av, W); } pari-2.11.2/src/basemath/matperm.c0000644000175000017500000001004013326135265015343 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** MATRIX PERMANENT, via RYSER'S FORMULA **/ /** (initial implementation: C. Greathouse) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /* Ryser's formula */ GEN matpermanent(GEN M) { pari_sp av; long n = lg(M)-1, i, x, upper; GEN p, in; if (typ(M) != t_MAT) pari_err_TYPE("matpermanent", M); if (!n) return gen_1; if (n != nbrows(M)) pari_err_DIM("matpermanent"); #ifdef LONG_IS_64BIT /* because of vals(long x) => x <= LONG_MAX */ if (n > 63) pari_err_IMPL("large matrix permanent"); #else if (n > 31) pari_err_IMPL("large matrix permanent"); #endif if (n == 1) return gcopy(gcoeff(M,1,1)); av = avma; if (RgM_is_QM(M)) { GEN cM; M = Q_primitive_part(M, &cM); p = ZM_permanent(M); if (cM) p = gerepileupto(av, gmul(p, gpowgs(cM,n))); return p; } p = gen_0; in = zerovec(n); upper = 1L << n; for (x = 1; x < upper; x++) { long gray = x ^ (x>>1), k = vals(x); GEN col = gel(M,k+1); if (gray & (1L<>1), k = vals(x); GEN c, col = gel(M, k+1); if (gray & (1L<>1); long i, k = vals(x); GEN c, col = gel(M, k+1); if (gray & (1UL<a = (GEN*)new_chunk(n+1); A->b = (GEN*)new_chunk(n+1); A->p = (GEN*)new_chunk(n+1); A->q = (GEN*)new_chunk(n+1); } static GEN mulii3(GEN a, GEN b, GEN c) { return mulii(mulii(a,b),c); } static GEN mulii4(GEN a, GEN b, GEN c, GEN d) { return mulii(mulii(a,b),mulii(c,d)); } /* T_{n1,n1+1}, given P = p[n1]p[n1+1] */ static GEN T2(struct abpq *A, long n1, GEN P) { GEN u1 = mulii4(A->a[n1], A->p[n1], A->b[n1+1], A->q[n1+1]); GEN u2 = mulii3(A->b[n1],A->a[n1+1], P); return addii(u1, u2); } /* assume n2 > n1. Compute sum_{n1 <= n < n2} a/b(n) p/q(n1)... p/q(n) */ void abpq_sum(struct abpq_res *r, long n1, long n2, struct abpq *A) { struct abpq_res L, R; GEN u1, u2; pari_sp av; long n; switch(n2 - n1) { GEN b, p, q; case 1: r->P = A->p[n1]; r->Q = A->q[n1]; r->B = A->b[n1]; r->T = mulii(A->a[n1], A->p[n1]); return; case 2: r->P = mulii(A->p[n1], A->p[n1+1]); r->Q = mulii(A->q[n1], A->q[n1+1]); r->B = mulii(A->b[n1], A->b[n1+1]); av = avma; r->T = gerepileuptoint(av, T2(A, n1, r->P)); return; case 3: p = mulii(A->p[n1+1], A->p[n1+2]); q = mulii(A->q[n1+1], A->q[n1+2]); b = mulii(A->b[n1+1], A->b[n1+2]); r->P = mulii(A->p[n1], p); r->Q = mulii(A->q[n1], q); r->B = mulii(A->b[n1], b); av = avma; u1 = mulii3(b, q, A->a[n1]); u2 = mulii(A->b[n1], T2(A, n1+1, p)); r->T = gerepileuptoint(av, mulii(A->p[n1], addii(u1, u2))); return; } av = avma; n = (n1 + n2) >> 1; abpq_sum(&L, n1, n, A); abpq_sum(&R, n, n2, A); r->P = mulii(L.P, R.P); r->Q = mulii(L.Q, R.Q); r->B = mulii(L.B, R.B); u1 = mulii3(R.B,R.Q,L.T); u2 = mulii3(L.B,L.P,R.T); r->T = addii(u1,u2); avma = av; r->P = icopy(r->P); r->Q = icopy(r->Q); r->B = icopy(r->B); r->T = icopy(r->T); } /********************************************************************/ /** **/ /** PI **/ /** **/ /********************************************************************/ /* replace *old clone by c. Protect against SIGINT */ static void swap_clone(GEN *old, GEN c) { GEN tmp = *old; *old = c; if (tmp) gunclone(tmp); } /* ---- * 53360 (640320)^(1/2) \ (6n)! (545140134 n + 13591409) * -------------------- = / ------------------------------ * Pi ---- (n!)^3 (3n)! (-640320)^(3n) * n>=0 * * Ramanujan's formula + binary splitting */ static GEN pi_ramanujan(long prec) { const ulong B = 545140134, A = 13591409, C = 640320; const double alpha2 = 47.11041314; /* 3log(C/12) / log(2) */ long n, nmax, prec2; struct abpq_res R; struct abpq S; GEN D, u; nmax = (long)(1 + prec2nbits(prec)/alpha2); #ifdef LONG_IS_64BIT D = utoipos(10939058860032000UL); /* C^3/24 */ #else D = uutoi(2546948UL,495419392UL); #endif abpq_init(&S, nmax); S.a[0] = utoipos(A); S.b[0] = S.p[0] = S.q[0] = gen_1; for (n = 1; n <= nmax; n++) { S.a[n] = addiu(muluu(B, n), A); S.b[n] = gen_1; S.p[n] = mulis(muluu(6*n-5, 2*n-1), 1-6*n); S.q[n] = mulii(sqru(n), muliu(D,n)); } abpq_sum(&R, 0, nmax, &S); prec2 = prec+EXTRAPRECWORD; u = itor(muliu(R.Q,C/12), prec2); return rtor(mulrr(divri(u, R.T), sqrtr_abs(utor(C,prec2))), prec); } #if 0 /* Much slower than binary splitting at least up to prec = 10^8 */ /* Gauss - Brent-Salamin AGM iteration */ static GEN pi_brent_salamin(long prec) { GEN A, B, C; pari_sp av2; long i, G; G = - prec2nbits(prec); incrprec(prec); A = real2n(-1, prec); B = sqrtr_abs(A); /* = 1/sqrt(2) */ setexpo(A, 0); C = real2n(-2, prec); av2 = avma; for (i = 0;; i++) { GEN y, a, b, B_A = subrr(B, A); pari_sp av3 = avma; if (expo(B_A) < G) break; a = addrr(A,B); shiftr_inplace(a, -1); b = mulrr(A,B); affrr(a, A); affrr(sqrtr_abs(b), B); avma = av3; y = sqrr(B_A); shiftr_inplace(y, i - 2); affrr(subrr(C, y), C); avma = av2; } shiftr_inplace(C, 2); return divrr(sqrr(addrr(A,B)), C); } GEN constpi(long prec) { pari_sp av; GEN tmp; if (gpi && realprec(gpi) >= prec) return gpi; tmp = cgetr_block(prec); av = avma; affrr(pi_brent_salamin(prec), tmp); swap_clone(&gpi, tmp); avma = av; return gpi; } #endif GEN constpi(long prec) { pari_sp av; GEN tmp; if (gpi && realprec(gpi) >= prec) return gpi; av = avma; tmp = gclone(pi_ramanujan(prec)); swap_clone(&gpi,tmp); avma = av; return gpi; } GEN mppi(long prec) { return rtor(constpi(prec), prec); } /* Pi * 2^n */ GEN Pi2n(long n, long prec) { GEN x = mppi(prec); shiftr_inplace(x, n); return x; } /* I * Pi * 2^n */ GEN PiI2n(long n, long prec) { retmkcomplex(gen_0, Pi2n(n, prec)); } /* 2I * Pi */ GEN PiI2(long prec) { return PiI2n(1, prec); } /********************************************************************/ /** **/ /** EULER CONSTANT **/ /** **/ /********************************************************************/ GEN consteuler(long prec) { GEN u,v,a,b,tmpeuler; long l, n1, n, k, x; pari_sp av1, av2; if (geuler && realprec(geuler) >= prec) return geuler; av1 = avma; tmpeuler = cgetr_block(prec); incrprec(prec); l = prec+EXTRAPRECWORD; x = (long) (1 + prec2nbits_mul(l, M_LN2/4)); a = utor(x,l); u=logr_abs(a); setsigne(u,-1); affrr(u,a); b = real_1(l); v = real_1(l); n = (long)(1+3.591*x); /* z=3.591: z*[ ln(z)-1 ]=1 */ n1 = minss(n, SQRTVERYBIGINT); if (x < SQRTVERYBIGINT) { ulong xx = x*x; av2 = avma; for (k=1; k=0} 1/(binomial(2n,n)(2n+1)^2) + Pi log(2+sqrt(3)) */ static GEN catalan(long prec) { long i, nmax = prec2nbits(prec) >> 1; struct abpq_res R; struct abpq A; GEN u, v; abpq_init(&A, nmax); A.a[0] = A.b[0] = A.p[0] = A.q[0] = gen_1; for (i = 1; i <= nmax; i++) { A.a[i] = gen_1; A.b[i] = utoipos((i<<1)+1); A.p[i] = utoipos(i); A.q[i] = utoipos((i<<2)+2); } abpq_sum(&R, 0, nmax, &A); u = mulur(3, rdivii(R.T, mulii(R.B,R.Q),prec)); v = mulrr(mppi(prec), logr_abs(addrs(sqrtr_abs(utor(3,prec)), 2))); u = addrr(u, v); shiftr_inplace(u, -3); return u; } GEN constcatalan(long prec) { pari_sp av = avma; GEN tmp; if (gcatalan && realprec(gcatalan) >= prec) return gcatalan; tmp = gclone(catalan(prec)); swap_clone(&gcatalan,tmp); avma = av; return gcatalan; } GEN mpcatalan(long prec) { return rtor(constcatalan(prec), prec); } /********************************************************************/ /** **/ /** TYPE CONVERSION FOR TRANSCENDENTAL FUNCTIONS **/ /** **/ /********************************************************************/ static GEN transvec(GEN (*f)(GEN,long), GEN x, long prec) { long i, l; GEN y = cgetg_copy(x, &l); for (i=1; i= 0? real_0_bit(e): real_1_bit(-e); } static GEN powr0(GEN x) { return signe(x)? real_1(realprec(x)): mpexp0(x); } /* x t_POL or t_SER, return scalarpol(Rg_get_1(x)) */ static GEN scalarpol_get_1(GEN x) { GEN y = cgetg(3,t_POL); y[1] = evalvarn(varn(x)) | evalsigne(1); gel(y,2) = Rg_get_1(x); return y; } /* to be called by the generic function gpowgs(x,s) when s = 0 */ static GEN gpowg0(GEN x) { long lx, i; GEN y; switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: case t_PADIC: return gen_1; case t_QUAD: x++; /*fall through*/ case t_COMPLEX: { pari_sp av = avma; GEN a = gpowg0(gel(x,1)); GEN b = gpowg0(gel(x,2)); if (a == gen_1) return b; if (b == gen_1) return a; return gerepileupto(av, gmul(a,b)); } case t_INTMOD: y = cgetg(3,t_INTMOD); gel(y,1) = icopy(gel(x,1)); gel(y,2) = is_pm1(gel(x,1))? gen_0: gen_1; return y; case t_FFELT: return FF_1(x); case t_POLMOD: retmkpolmod(scalarpol_get_1(gel(x,1)), gcopy(gel(x,1))); case t_RFRAC: return scalarpol_get_1(gel(x,2)); case t_POL: case t_SER: return scalarpol_get_1(x); case t_MAT: lx=lg(x); if (lx==1) return cgetg(1,t_MAT); if (lx != lgcols(x)) pari_err_DIM("gpow"); y = matid(lx-1); for (i=1; i 0) * * Use left shift binary algorithm (RS is wasteful: multiplies big numbers, * with LS one of them is the base, hence small). Sign of result is set * to s (= 1,-1). Makes life easier for caller, which otherwise might do a * setsigne(gen_1 / gen_m1) */ static GEN powiu_sign(GEN a, ulong N, long s) { pari_sp av; GEN y; if (lgefint(a) == 3) { /* easy if |a| < 3 */ ulong q = a[2]; if (q == 1) return (s>0)? gen_1: gen_m1; if (q == 2) { a = int2u(N); setsigne(a,s); return a; } q = upowuu(q, N); if (q) return s>0? utoipos(q): utoineg(q); } if (N <= 2) { if (N == 2) return sqri(a); a = icopy(a); setsigne(a,s); return a; } av = avma; y = gen_powu_i(a, N, NULL, &_sqri, &_muli); setsigne(y,s); return gerepileuptoint(av, y); } /* a^n */ GEN powiu(GEN a, ulong n) { long s; if (!n) return gen_1; s = signe(a); if (!s) return gen_0; return powiu_sign(a, n, (s < 0 && odd(n))? -1: 1); } GEN powis(GEN a, long n) { long s; GEN t, y; if (n >= 0) return powiu(a, n); s = signe(a); if (!s) pari_err_INV("powis",gen_0); t = (s < 0 && odd(n))? gen_m1: gen_1; if (is_pm1(a)) return t; /* n < 0, |a| > 1 */ y = cgetg(3,t_FRAC); gel(y,1) = t; gel(y,2) = powiu_sign(a, -n, 1); /* force denominator > 0 */ return y; } GEN powuu(ulong p, ulong N) { pari_sp av = avma; long P[] = {evaltyp(t_INT)|_evallg(3), evalsigne(1)|evallgefint(3),0}; ulong pN; GEN y; if (N <= 2) { if (N == 2) return sqru(p); if (N == 1) return utoi(p); return gen_1; } if (!p) return gen_0; pN = upowuu(p, N); if (pN) return utoipos(pN); if (p == 2) return int2u(N); P[2] = p; av = avma; y = gen_powu_i(P, N, NULL, &_sqri, &_muli); return gerepileuptoint(av, y); } /* return 0 if overflow */ static ulong usqru(ulong p) { return p & HIGHMASK? 0: p*p; } ulong upowuu(ulong p, ulong k) { #ifdef LONG_IS_64BIT const ulong CUTOFF3 = 2642245; const ulong CUTOFF4 = 65535; const ulong CUTOFF5 = 7131; const ulong CUTOFF6 = 1625; const ulong CUTOFF7 = 565; const ulong CUTOFF8 = 255; const ulong CUTOFF9 = 138; const ulong CUTOFF10 = 84; const ulong CUTOFF11 = 56; const ulong CUTOFF12 = 40; const ulong CUTOFF13 = 30; const ulong CUTOFF14 = 23; const ulong CUTOFF15 = 19; const ulong CUTOFF16 = 15; const ulong CUTOFF17 = 13; const ulong CUTOFF18 = 11; const ulong CUTOFF19 = 10; const ulong CUTOFF20 = 9; #else const ulong CUTOFF3 = 1625; const ulong CUTOFF4 = 255; const ulong CUTOFF5 = 84; const ulong CUTOFF6 = 40; const ulong CUTOFF7 = 23; const ulong CUTOFF8 = 15; const ulong CUTOFF9 = 11; const ulong CUTOFF10 = 9; const ulong CUTOFF11 = 7; const ulong CUTOFF12 = 6; const ulong CUTOFF13 = 5; const ulong CUTOFF14 = 4; const ulong CUTOFF15 = 4; const ulong CUTOFF16 = 3; const ulong CUTOFF17 = 3; const ulong CUTOFF18 = 3; const ulong CUTOFF19 = 3; const ulong CUTOFF20 = 3; #endif if (p <= 2) { if (p < 2) return p; return k < BITS_IN_LONG? 1UL< CUTOFF3) return 0; return p*p*p; case 4: if (p > CUTOFF4) return 0; p2=p*p; return p2*p2; case 5: if (p > CUTOFF5) return 0; p2=p*p; return p2*p2*p; case 6: if (p > CUTOFF6) return 0; p2=p*p; return p2*p2*p2; case 7: if (p > CUTOFF7) return 0; p2=p*p; return p2*p2*p2*p; case 8: if (p > CUTOFF8) return 0; p2=p*p; p4=p2*p2; return p4*p4; case 9: if (p > CUTOFF9) return 0; p2=p*p; p4=p2*p2; return p4*p4*p; case 10: if (p > CUTOFF10)return 0; p2=p*p; p4=p2*p2; return p4*p4*p2; case 11: if (p > CUTOFF11)return 0; p2=p*p; p4=p2*p2; return p4*p4*p2*p; case 12: if (p > CUTOFF12)return 0; p2=p*p; p4=p2*p2; return p4*p4*p4; case 13: if (p > CUTOFF13)return 0; p2=p*p; p4=p2*p2; return p4*p4*p4*p; case 14: if (p > CUTOFF14)return 0; p2=p*p; p4=p2*p2; return p4*p4*p4*p2; case 15: if (p > CUTOFF15)return 0; p2=p*p; p3=p2*p; p5=p3*p2; return p5*p5*p5; case 16: if (p > CUTOFF16)return 0; p2=p*p; p4=p2*p2; p8=p4*p4; return p8*p8; case 17: if (p > CUTOFF17)return 0; p2=p*p; p4=p2*p2; p8=p4*p4; return p*p8*p8; case 18: if (p > CUTOFF18)return 0; p2=p*p; p4=p2*p2; p8=p4*p4; return p2*p8*p8; case 19: if (p > CUTOFF19)return 0; p2=p*p; p4=p2*p2; p8=p4*p4; return p*p2*p8*p8; case 20: if (p > CUTOFF20)return 0; p2=p*p; p4=p2*p2; p8=p4*p4; return p4*p8*p8; } #ifdef LONG_IS_64BIT switch(p) { case 3: if (k > 40) return 0; break; case 4: if (k > 31) return 0; return 1UL<<(2*k); case 5: if (k > 27) return 0; break; case 6: if (k > 24) return 0; break; case 7: if (k > 22) return 0; break; default: return 0; } /* no overflow */ { ulong q = upowuu(p, k >> 1); q *= q ; return odd(k)? q*p: q; } #else return 0; #endif } typedef struct { long prec, a; GEN (*sqr)(GEN); GEN (*mulug)(ulong,GEN); } sr_muldata; static GEN _rpowuu_sqr(void *data, GEN x) { sr_muldata *D = (sr_muldata *)data; if (typ(x) == t_INT && lgefint(x) >= D->prec) { /* switch to t_REAL */ D->sqr = &sqrr; D->mulug = &mulur; x = itor(x, D->prec); } return D->sqr(x); } static GEN _rpowuu_msqr(void *data, GEN x) { GEN x2 = _rpowuu_sqr(data, x); sr_muldata *D = (sr_muldata *)data; return D->mulug(D->a, x2); } /* return a^n as a t_REAL of precision prec. Assume a > 0, n > 0 */ GEN rpowuu(ulong a, ulong n, long prec) { pari_sp av; GEN y, z; sr_muldata D; if (a == 1) return real_1(prec); if (a == 2) return real2n(n, prec); if (n == 1) return utor(a, prec); z = cgetr(prec); av = avma; D.sqr = &sqri; D.mulug = &mului; D.prec = prec; D.a = (long)a; y = gen_powu_fold_i(utoipos(a), n, (void*)&D, &_rpowuu_sqr, &_rpowuu_msqr); mpaff(y, z); avma = av; return z; } GEN powrs(GEN x, long n) { pari_sp av = avma; GEN y; if (!n) return powr0(x); y = gen_powu_i(x, (ulong)labs(n), NULL, &_sqrr, &_mulr); if (n < 0) y = invr(y); return gerepileuptoleaf(av,y); } GEN powru(GEN x, ulong n) { pari_sp av = avma; GEN y; if (!n) return powr0(x); y = gen_powu_i(x, n, NULL, &_sqrr, &_mulr); return gerepileuptoleaf(av,y); } GEN powersr(GEN x, long n) { long prec = realprec(x); return gen_powers(x, n, 1, &prec, &_sqrr, &_mulr, &_oner); } /* x^(s/2), assume x t_REAL */ GEN powrshalf(GEN x, long s) { if (s & 1) return sqrtr(powrs(x, s)); return powrs(x, s>>1); } /* x^(s/2), assume x t_REAL */ GEN powruhalf(GEN x, ulong s) { if (s & 1) return sqrtr(powru(x, s)); return powru(x, s>>1); } /* x^(n/d), assume x t_REAL, return t_REAL */ GEN powrfrac(GEN x, long n, long d) { long z; if (!n) return powr0(x); z = cgcd(n, d); if (z > 1) { n /= z; d /= z; } if (d == 1) return powrs(x, n); x = powrs(x, n); if (d == 2) return sqrtr(x); return sqrtnr(x, d); } /* assume x != 0 */ static GEN pow_monome(GEN x, long n) { long i, d, dx = degpol(x); GEN A, b, y; if (n < 0) { n = -n; y = cgetg(3, t_RFRAC); } else y = NULL; if (HIGHWORD(dx) || HIGHWORD(n)) { LOCAL_HIREMAINDER; d = (long)mulll((ulong)dx, (ulong)n); if (hiremainder || (d &~ LGBITS)) d = LGBITS; /* overflow */ d += 2; } else d = dx*n + 2; if ((d + 1) & ~LGBITS) pari_err(e_OVERFLOW,"pow_monome [degree]"); A = cgetg(d+1, t_POL); A[1] = x[1]; for (i=2; i < d; i++) gel(A,i) = gen_0; b = gpowgs(gel(x,dx+2), n); /* not memory clean if (n < 0) */ if (!y) y = A; else { GEN c = denom_i(b); gel(y,1) = c; if (c != gen_1) b = gmul(b,c); gel(y,2) = A; } gel(A,d) = b; return y; } /* x t_PADIC */ static GEN powps(GEN x, long n) { long e = n*valp(x), v; GEN t, y, mod, p = gel(x,2); pari_sp av; if (!signe(gel(x,4))) { if (n < 0) pari_err_INV("powps",x); return zeropadic(p, e); } v = z_pval(n, p); y = cgetg(5,t_PADIC); mod = gel(x,3); if (v == 0) mod = icopy(mod); else { if (precp(x) == 1 && absequaliu(p, 2)) v++; mod = mulii(mod, powiu(p,v)); mod = gerepileuptoint((pari_sp)y, mod); } y[1] = evalprecp(precp(x) + v) | evalvalp(e); gel(y,2) = icopy(p); gel(y,3) = mod; av = avma; t = gel(x,4); if (n < 0) { t = Fp_inv(t, mod); n = -n; } t = Fp_powu(t, n, mod); gel(y,4) = gerepileuptoint(av, t); return y; } /* x t_PADIC */ static GEN powp(GEN x, GEN n) { long v; GEN y, mod, p = gel(x,2); if (valp(x)) pari_err_OVERFLOW("valp()"); if (!signe(gel(x,4))) { if (signe(n) < 0) pari_err_INV("powp",x); return zeropadic(p, 0); } v = Z_pval(n, p); y = cgetg(5,t_PADIC); mod = gel(x,3); if (v == 0) mod = icopy(mod); else { mod = mulii(mod, powiu(p,v)); mod = gerepileuptoint((pari_sp)y, mod); } y[1] = evalprecp(precp(x) + v) | _evalvalp(0); gel(y,2) = icopy(p); gel(y,3) = mod; gel(y,4) = Fp_pow(gel(x,4), n, mod); return y; } static GEN pow_polmod(GEN x, GEN n) { GEN z = cgetg(3, t_POLMOD), a = gel(x,2), T = gel(x,1); gel(z,1) = gcopy(T); if (typ(a) != t_POL || varn(a) != varn(T) || lg(a) <= 3) a = powgi(a, n); else { pari_sp av = avma; GEN p = NULL; if (RgX_is_FpX(T, &p) && RgX_is_FpX(a, &p) && p) { T = RgX_to_FpX(T, p); a = RgX_to_FpX(a, p); if (lgefint(p) == 3) { ulong pp = p[2]; a = Flxq_pow(ZX_to_Flx(a, pp), n, ZX_to_Flx(T, pp), pp); a = Flx_to_ZX(a); } else a = FpXQ_pow(a, n, T, p); a = FpX_to_mod(a, p); a = gerepileupto(av, a); } else { avma = av; a = RgXQ_pow(a, n, gel(z,1)); } } gel(z,2) = a; return z; } GEN gpowgs(GEN x, long n) { long m; pari_sp av; GEN y; if (n == 0) return gpowg0(x); if (n == 1) switch (typ(x)) { case t_QFI: return redimag(x); case t_QFR: return redreal(x); default: return gcopy(x); } if (n ==-1) return ginv(x); switch(typ(x)) { case t_INT: return powis(x,n); case t_REAL: return powrs(x,n); case t_INTMOD: y = cgetg(3,t_INTMOD); gel(y,1) = icopy(gel(x,1)); gel(y,2) = Fp_pows(gel(x,2), n, gel(x,1)); return y; case t_FRAC: { GEN a = gel(x,1), b = gel(x,2); long s = (signe(a) < 0 && odd(n))? -1: 1; if (n < 0) { n = -n; if (is_pm1(a)) return powiu_sign(b, n, s); /* +-1/x[2] inverts to t_INT */ swap(a, b); } y = cgetg(3, t_FRAC); gel(y,1) = powiu_sign(a, n, s); gel(y,2) = powiu_sign(b, n, 1); return y; } case t_PADIC: return powps(x, n); case t_RFRAC: { av = avma; y = cgetg(3, t_RFRAC); m = labs(n); gel(y,1) = gpowgs(gel(x,1),m); gel(y,2) = gpowgs(gel(x,2),m); if (n < 0) y = ginv(y); return gerepileupto(av,y); } case t_POLMOD: { long N[] = {evaltyp(t_INT) | _evallg(3),0,0}; affsi(n,N); return pow_polmod(x, N); } case t_POL: if (RgX_is_monomial(x)) return pow_monome(x, n); default: { pari_sp av = avma; y = gen_powu_i(x, (ulong)labs(n), NULL, &_sqr, &_mul); if (n < 0) y = ginv(y); return gerepileupto(av,y); } } } /* n a t_INT */ GEN powgi(GEN x, GEN n) { GEN y; if (!is_bigint(n)) return gpowgs(x, itos(n)); /* probable overflow for non-modular types (typical exception: (X^0)^N) */ switch(typ(x)) { case t_INTMOD: y = cgetg(3,t_INTMOD); gel(y,1) = icopy(gel(x,1)); gel(y,2) = Fp_pow(gel(x,2), n, gel(x,1)); return y; case t_FFELT: return FF_pow(x,n); case t_PADIC: return powp(x, n); case t_INT: if (is_pm1(x)) return (signe(x) < 0 && mpodd(n))? gen_m1: gen_1; if (signe(x)) pari_err_OVERFLOW("lg()"); if (signe(n) < 0) pari_err_INV("powgi",gen_0); return gen_0; case t_FRAC: pari_err_OVERFLOW("lg()"); case t_QFR: return qfrpow(x, n); case t_POLMOD: return pow_polmod(x, n); default: { pari_sp av = avma; y = gen_pow(x, n, NULL, &_sqr, &_mul); if (signe(n) < 0) y = ginv(y); return gerepileupto(av,y); } } } /* Assume x = 1 + O(t), n a scalar. Return x^n */ static GEN ser_pow_1(GEN x, GEN n) { long lx, mi, i, j, d; GEN y = cgetg_copy(x, &lx), X = x+2, Y = y + 2; y[1] = evalsigne(1) | _evalvalp(0) | evalvarn(varn(x)); d = mi = lx-3; while (mi>=1 && isrationalzero(gel(X,mi))) mi--; gel(Y,0) = gen_1; for (i=1; i<=d; i++) { pari_sp av = avma; GEN s = gen_0; for (j=1; j<=minss(i,mi); j++) { GEN t = gsubgs(gmulgs(n,j),i-j); s = gadd(s, gmul(gmul(t, gel(X,j)), gel(Y,i-j))); } gel(Y,i) = gerepileupto(av, gdivgs(s,i)); } return y; } /* we suppose n != 0, valp(x) = 0 and leading-term(x) != 0. Not stack clean */ static GEN ser_pow(GEN x, GEN n, long prec) { GEN y, c, lead; if (varncmp(gvar(n), varn(x)) <= 0) return gexp(gmul(n, glog(x,prec)), prec); lead = gel(x,2); if (gequal1(lead)) return ser_pow_1(x, n); x = ser_normalize(x); if (typ(n) == t_FRAC && !isinexact(lead) && ispower(lead, gel(n,2), &c)) c = powgi(c, gel(n,1)); else c = gpow(lead,n, prec); y = gmul(c, ser_pow_1(x, n)); /* gpow(t_POLMOD,n) can be a t_COL [conjvec] */ if (typ(y) != t_SER) pari_err_TYPE("gpow", y); return y; } static long val_from_i(GEN E) { if (is_bigint(E)) pari_err_OVERFLOW("sqrtn [valuation]"); return itos(E); } /* return x^q, assume typ(x) = t_SER, typ(q) = t_INT/t_FRAC and q != 0 */ static GEN ser_powfrac(GEN x, GEN q, long prec) { GEN y, E = gmulsg(valp(x), q); long e; if (!signe(x)) { if (gsigne(q) < 0) pari_err_INV("gpow", x); return zeroser(varn(x), val_from_i(gfloor(E))); } if (typ(E) != t_INT) pari_err_DOMAIN("sqrtn", "valuation", "!=", mkintmod(gen_0, gel(q,2)), x); e = val_from_i(E); y = leafcopy(x); setvalp(y, 0); y = ser_pow(y, q, prec); setvalp(y, e); return y; } static GEN gpow0(GEN x, GEN n, long prec) { pari_sp av = avma; long i, lx; GEN y; switch(typ(n)) { case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: case t_QUAD: break; case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(n, &lx); for (i=1; i 0) { prec += nbits2extraprec(expi(a)); if (tx != t_REAL) x = gtofp(x, prec); z = sqrtnr(x, D); if (!equali1(a)) z = powgi(z, a); return gerepileuptoleaf(av, z); } } } i = precision(n); if (i) prec = i; prec0 = prec; if (!gprecision(x)) { long e = gexpo_safe(n); /* avoided if n = 0 or gexpo not defined */ if (e > 2) prec += nbits2extraprec(e); } y = gmul(n, glog(x,prec)); y = gexp(y,prec); if (prec0 == prec) return gerepileupto(av, y); return gerepilecopy(av, gprec_wtrunc(y,prec0)); } GEN gpowers0(GEN x, long n, GEN x0) { long i, l; GEN V; if (!x0) return gpowers(x,n); if (n < 0) return cgetg(1,t_VEC); l = n+2; V = cgetg(l, t_VEC); gel(V,1) = gcopy(x0); for (i = 2; i < l; i++) gel(V,i) = gmul(gel(V,i-1),x); return V; } GEN gpowers(GEN x, long n) { if (n < 0) return cgetg(1,t_VEC); return gen_powers(x, n, 1, (void*)x, &_sqr, &_mul, &_one); } /* return [q^1,q^4,...,q^{n^2}] */ GEN gsqrpowers(GEN q, long n) { pari_sp av = avma; GEN L = gpowers0(gsqr(q), n, q); /* L[i] = q^(2i - 1), i <= n+1 */ GEN v = cgetg(n+1, t_VEC); long i; gel(v, 1) = gcopy(q); for (i = 2; i <= n ; ++i) gel(v, i) = q = gmul(q, gel(L,i)); /* q^(i^2) */ return gerepileupto(av, v); } /* 4 | N. returns a vector RU which contains exp(2*i*k*Pi/N), k=0..N-1 */ static GEN grootsof1_4(long N, long prec) { GEN z, RU = cgetg(N+1,t_VEC), *v = ((GEN*)RU) + 1; long i, N2 = (N>>1), N4 = (N>>2), N8 = (N>>3); /* z^N2 = -1, z^N4 = I; if z^k = a+I*b, then z^(N4-k) = I*conj(z) = b+a*I */ v[0] = gen_1; v[1] = z = rootsof1u_cx(N, prec); if (odd(N4)) N8++; for (i=1; i>1; RU = cgetg(N+1,t_VEC); v = ((GEN*)RU) + 1; v[0] = gen_1; v[1] = z = rootsof1u_cx(N, prec); if (odd(N)) for (i=2; i=0?mod16(x):16-mod16(x); GEN z; long ez; pari_sp av; switch(e) { case 1: return gen_1; case 2: return (r & 3UL) == 1? gen_1: NULL; case 3: return (r & 7UL) == 1? gen_1: NULL; case 4: if (r == 1) return gen_1; else return (r == 9)? utoipos(3): NULL; default: if ((r&7UL) != 1) return NULL; } av = avma; z = (r==1)? gen_1: utoipos(3); ez = 3; /* number of correct bits in z (compared to sqrt(x)) */ for(;;) { GEN mod; ez = (ez<<1) - 1; if (ez > e) ez = e; mod = int2n(ez); z = addii(z, remi2n(mulii(x, Fp_inv(z,mod)), ez)); z = shifti(z, -1); /* (z + x/z) / 2 */ if (e == ez) return gerepileuptoint(av, z); if (ez < e) ez--; if (gc_needed(av,2)) { if (DEBUGMEM > 1) pari_warn(warnmem,"Qp_sqrt"); z = gerepileuptoint(av,z); } } } /* x unit defined modulo p^e, e > 0 */ GEN Qp_sqrt(GEN x) { long pp, e = valp(x); GEN z,y,mod, p = gel(x,2); if (gequal0(x)) return zeropadic(p, (e+1) >> 1); if (e & 1) return NULL; y = cgetg(5,t_PADIC); pp = precp(x); mod = gel(x,3); z = gel(x,4); /* lift to t_INT */ e >>= 1; z = Zp_sqrt(z, p, pp); if (!z) return NULL; if (absequaliu(p,2)) { pp = (pp <= 3) ? 1 : pp-1; mod = int2n(pp); } else mod = icopy(mod); y[1] = evalprecp(pp) | evalvalp(e); gel(y,2) = icopy(p); gel(y,3) = mod; gel(y,4) = z; return y; } GEN Zn_sqrt(GEN d, GEN fn) { pari_sp ltop = avma, btop; GEN b = gen_0, m = gen_1; long j, np; if (typ(d) != t_INT) pari_err_TYPE("Zn_sqrt",d); if (typ(fn) == t_INT) fn = absZ_factor(fn); else if (!is_Z_factorpos(fn)) pari_err_TYPE("Zn_sqrt",fn); np = nbrows(fn); btop = avma; for (j = 1; j <= np; ++j) { GEN bp, mp, pr, r; GEN p = gcoeff(fn, j, 1); long e = itos(gcoeff(fn, j, 2)); long v = Z_pvalrem(d,p,&r); if (v >= e) bp =gen_0; else { if (odd(v)) return NULL; bp = Zp_sqrt(r, p, e-v); if (!bp) return NULL; if (v) bp = mulii(bp, powiu(p, v>>1L)); } mp = powiu(p, e); pr = mulii(m, mp); b = Z_chinese_coprime(b, bp, m, mp, pr); m = pr; if (gc_needed(btop, 1)) gerepileall(btop, 2, &b, &m); } return gerepileupto(ltop, b); } static GEN sqrt_ser(GEN b, long prec) { long e = valp(b), vx = varn(b), lx, lold, j; ulong mask; GEN a, x, lta, ltx; if (!signe(b)) return zeroser(vx, e>>1); a = leafcopy(b); x = cgetg_copy(b, &lx); if (e & 1) pari_err_DOMAIN("sqrtn", "valuation", "!=", mkintmod(gen_0, gen_2), b); a[1] = x[1] = evalsigne(1) | evalvarn(0) | _evalvalp(0); lta = gel(a,2); if (gequal1(lta)) ltx = lta; else if (!issquareall(lta,<x)) ltx = gsqrt(lta,prec); gel(x,2) = ltx; for (j = 3; j < lx; j++) gel(x,j) = gen_0; setlg(x,3); mask = quadratic_prec_mask(lx - 2); lold = 1; while (mask > 1) { GEN y, x2 = gmul2n(x,1); long l = lold << 1, lx; if (mask & 1) l--; mask >>= 1; setlg(a, l + 2); setlg(x, l + 2); y = sqr_ser_part(x, lold, l-1) - lold; for (j = lold+2; j < l+2; j++) gel(y,j) = gsub(gel(y,j), gel(a,j)); y += lold; setvalp(y, lold); y = normalize(y); y = gsub(x, gdiv(y, x2)); /* = gmul2n(gsub(x, gdiv(a,x)), -1); */ lx = minss(l+2, lg(y)); for (j = lold+2; j < lx; j++) gel(x,j) = gel(y,j); lold = l; } x[1] = evalsigne(1) | evalvarn(vx) | _evalvalp(e >> 1); return x; } GEN gsqrt(GEN x, long prec) { pari_sp av; GEN y; switch(typ(x)) { case t_INT: if (!signe(x)) return real_0(prec); /* no loss of accuracy */ x = itor(x,prec); /* fall through */ case t_REAL: return sqrtr(x); case t_INTMOD: { GEN p = gel(x,1), a; y = cgetg(3,t_INTMOD); gel(y,1) = icopy(p); a = Fp_sqrt(gel(x,2),p); if (!a) { if (!BPSW_psp(p)) pari_err_PRIME("sqrt [modulus]",p); pari_err_SQRTN("gsqrt",x); } gel(y,2) = a; return y; } case t_COMPLEX: { /* (u+iv)^2 = a+ib <=> u^2+v^2 = sqrt(a^2+b^2), u^2-v^2=a, 2uv=b */ GEN a = gel(x,1), b = gel(x,2), r, u, v; if (isrationalzero(b)) return gsqrt(a, prec); y = cgetg(3,t_COMPLEX); av = avma; r = cxnorm(x); if (typ(r) == t_INTMOD || typ(r) == t_PADIC) pari_err_IMPL("sqrt(complex of t_INTMODs)"); r = gsqrt(r, prec); /* t_REAL, |a+Ib| */ if (!signe(r)) u = v = gerepileuptoleaf(av, sqrtr(r)); else if (gsigne(a) < 0) { /* v > 0 since r > 0, a < 0, rounding errors can't make the sum of two * positive numbers = 0 */ v = sqrtr( gmul2n(gsub(r,a), -1) ); if (gsigne(b) < 0) togglesign(v); v = gerepileuptoleaf(av, v); av = avma; /* v = 0 is impossible */ u = gerepileuptoleaf(av, gdiv(b, shiftr(v,1))); } else { u = sqrtr( gmul2n(gadd(r,a), -1) ); u = gerepileuptoleaf(av, u); av = avma; if (!signe(u)) /* possible if a = 0.0, e.g. sqrt(0.e-10+1e-10*I) */ v = u; else v = gerepileuptoleaf(av, gdiv(b, shiftr(u,1))); } gel(y,1) = u; gel(y,2) = v; return y; } case t_PADIC: y = Qp_sqrt(x); if (!y) pari_err_SQRTN("Qp_sqrt",x); return y; case t_FFELT: return FF_sqrt(x); default: av = avma; if (!(y = toser_i(x))) break; return gerepilecopy(av, sqrt_ser(y, prec)); } return trans_eval("sqrt",gsqrt,x,prec); } /********************************************************************/ /** **/ /** N-th ROOT **/ /** **/ /********************************************************************/ static void bug_logp(GEN p) { if (!BPSW_psp(p)) pari_err_PRIME("p-adic log",p); pari_err_BUG("log_p"); } /* Let x = 1 mod p and y := (x-1)/(x+1) = 0 (p). Then * log(x) = log(1+y) - log(1-y) = 2 \sum_{k odd} y^k / k. * palogaux(x) returns the last sum (not multiplied by 2) */ static GEN palogaux(GEN x) { long i, k, e, pp, t; GEN y,s,y2, p = gel(x,2); int is2 = absequaliu(p,2); y = subiu(gel(x,4), 1); if (!signe(y)) { long v = valp(x)+precp(x); if (is2) v--; return zeropadic(p, v); } /* optimize t: log(x) = log(x^(p^t)) / p^t */ e = Z_pval(y, p); /* valp(y) = e >= 1; precp(y) = precp(x)-e */ if (!e) bug_logp(p); if (is2) t = sqrt( (double)(precp(x)-e) / e ); /* instead of (2*e) */ else t = sqrt( (double)(precp(x)-e) / (e * (expi(p) + hammingweight(p))) ); for (i = 0; i < t; i++) x = gpow(x, p, 0); y = gdiv(gaddgs(x,-1), gaddgs(x,1)); e = valp(y); /* > 0 */ if (e <= 0) bug_logp(p); pp = precp(y) + e; if (is2) pp--; else { GEN p1; for (p1=utoipos(e); abscmpui(pp,p1) > 0; pp++) p1 = mulii(p1, p); pp -= 2; } k = pp/e; if (!odd(k)) k--; if (DEBUGLEVEL>5) err_printf("logp: [pp,k,e,t] = [%ld,%ld,%ld,%ld]\n",pp,k,e,t); if (k > 1) { y2 = gsqr(y); s = gdivgs(gen_1,k); while (k > 2) { k -= 2; s = gadd(gmul(y2,s), gdivgs(gen_1,k)); } y = gmul(s,y); } if (t) setvalp(y, valp(y) - t); return y; } GEN Qp_log(GEN x) { pari_sp av = avma; GEN y, p = gel(x,2), a = gel(x,4); if (!signe(a)) pari_err_DOMAIN("Qp_log", "argument", "=", gen_0, x); y = leafcopy(x); setvalp(y,0); if (absequaliu(p,2)) y = palogaux(gsqr(y)); else if (gequal1(modii(a, p))) y = gmul2n(palogaux(y), 1); else { /* compute log(x^(p-1)) / (p-1) */ GEN mod = gel(y,3), p1 = subiu(p,1); gel(y,4) = Fp_pow(a, p1, mod); p1 = diviiexact(subsi(1,mod), p1); /* 1/(p-1) */ y = gmul(palogaux(y), shifti(p1,1)); } return gerepileupto(av,y); } static GEN Qp_exp_safe(GEN x); /*compute the p^e th root of x p-adic, assume x != 0 */ static GEN Qp_sqrtn_ram(GEN x, long e) { pari_sp ltop=avma; GEN a, p = gel(x,2), n = powiu(p,e); long v = valp(x), va; if (v) { long z; v = sdivsi_rem(v, n, &z); if (z) return NULL; x = leafcopy(x); setvalp(x,0); } /*If p = 2, -1 is a root of 1 in U1: need extra check*/ if (absequaliu(p, 2) && mod8(gel(x,4)) != 1) return NULL; a = Qp_log(x); va = valp(a) - e; if (va <= 0) { if (signe(gel(a,4))) return NULL; /* all accuracy lost */ a = cvtop(remii(gel(x,4),p), p, 1); } else { setvalp(a, va); /* divide by p^e */ a = Qp_exp_safe(a); if (!a) return NULL; /* n=p^e and a^n=z*x where z is a (p-1)th-root of 1. * Since z^n=z, we have (a/z)^n = x. */ a = gdiv(x, powgi(a,subiu(n,1))); /* = a/z = x/a^(n-1)*/ if (v) setvalp(a,v); } return gerepileupto(ltop,a); } /*compute the nth root of x p-adic p prime with n*/ static GEN Qp_sqrtn_unram(GEN x, GEN n, GEN *zetan) { pari_sp av; GEN Z, a, r, p = gel(x,2); long v = valp(x); if (v) { long z; v = sdivsi_rem(v,n,&z); if (z) return NULL; } r = cgetp(x); setvalp(r,v); Z = NULL; /* -Wall */ if (zetan) Z = cgetp(x); av = avma; a = Fp_sqrtn(gel(x,4), n, p, zetan); if (!a) return NULL; affii(Zp_sqrtnlift(gel(x,4), n, a, p, precp(x)), gel(r,4)); if (zetan) { affii(Zp_sqrtnlift(gen_1, n, *zetan, p, precp(x)), gel(Z,4)); *zetan = Z; } avma = av; return r; } GEN Qp_sqrtn(GEN x, GEN n, GEN *zetan) { pari_sp av, tetpil; GEN q, p; long e; if (absequaliu(n, 2)) { if (zetan) *zetan = gen_m1; if (signe(n) < 0) x = ginv(x); return Qp_sqrt(x); } av = avma; p = gel(x,2); if (!signe(gel(x,4))) { if (signe(n) < 0) pari_err_INV("Qp_sqrtn", x); q = divii(addis(n, valp(x)-1), n); if (zetan) *zetan = gen_1; avma = av; return zeropadic(p, itos(q)); } /* treat the ramified part using logarithms */ e = Z_pvalrem(n, p, &q); if (e) { x = Qp_sqrtn_ram(x,e); if (!x) return NULL; } if (is_pm1(q)) { /* finished */ if (signe(q) < 0) x = ginv(x); x = gerepileupto(av, x); if (zetan) *zetan = (e && absequaliu(p, 2))? gen_m1 /*-1 in Q_2*/ : gen_1; return x; } tetpil = avma; /* use hensel lift for unramified case */ x = Qp_sqrtn_unram(x, q, zetan); if (!x) return NULL; if (zetan) { GEN *gptr[2]; if (e && absequaliu(p, 2))/*-1 in Q_2*/ { tetpil = avma; x = gcopy(x); *zetan = gneg(*zetan); } gptr[0] = &x; gptr[1] = zetan; gerepilemanysp(av,tetpil,gptr,2); return x; } return gerepile(av,tetpil,x); } GEN sqrtnint(GEN a, long n) { pari_sp ltop = avma; GEN x, b, q; long s, k, e; const ulong nm1 = n - 1; if (typ(a) != t_INT) pari_err_TYPE("sqrtnint",a); if (n <= 0) pari_err_DOMAIN("sqrtnint", "n", "<=", gen_0, stoi(n)); if (n == 1) return icopy(a); s = signe(a); if (s < 0) pari_err_DOMAIN("sqrtnint", "x", "<", gen_0, a); if (!s) return gen_0; if (lgefint(a) == 3) return utoi(usqrtn(itou(a), n)); e = expi(a); k = e/(2*n); if (k == 0) { long flag; if (n > e) {avma = ltop; return gen_1;} flag = cmpii(a, powuu(3, n)); avma = ltop; return (flag < 0) ? gen_2: stoi(3); } if (e < n*BITS_IN_LONG - 1) { ulong xs, qs; b = itor(a, (2*e < n*BITS_IN_LONG)? DEFAULTPREC: MEDDEFAULTPREC); x = mpexp(divru(logr_abs(b), n)); xs = itou(floorr(x)) + 1; /* >= a^(1/n) */ for(;;) { q = divii(a, powuu(xs, nm1)); if (lgefint(q) > 3) break; qs = itou(q); if (qs >= xs) break; xs -= (xs - qs + nm1)/n; } return utoi(xs); } b = addui(1, shifti(a, -n*k)); x = shifti(addui(1, sqrtnint(b, n)), k); q = divii(a, powiu(x, nm1)); while (cmpii(q, x) < 0) /* a priori one iteration, no GC necessary */ { x = subii(x, divis(addui(nm1, subii(x, q)), n)); q = divii(a, powiu(x, nm1)); } return gerepileuptoleaf(ltop, x); } ulong usqrtn(ulong a, ulong n) { ulong x, s, q; const ulong nm1 = n - 1; if (!n) pari_err_DOMAIN("sqrtnint", "n", "=", gen_0, utoi(n)); if (n == 1 || a == 0) return a; s = 1 + expu(a)/n; x = 1UL << s; q = (nm1*s >= BITS_IN_LONG)? 0: a >> (nm1*s); while (q < x) { ulong X; x -= (x - q + nm1)/n; X = upowuu(x, nm1); q = X? a/X: 0; } return x; } static ulong cubic_prec_mask(long n) { long a = n, i; ulong mask = 0; for(i = 1;; i++, mask *= 3) { long c = a%3; if (c) mask += 3 - c; a = (a+2)/3; if (a==1) return mask + upowuu(3, i); } } /* cubic Newton iteration, |a|^(1/n), assuming a != 0 */ GEN sqrtnr_abs(GEN a, long n) { pari_sp av; GEN x, b; long eextra, eold, n1, n2, prec, B, v; ulong mask; if (n == 1) return mpabs(a); if (n == 2) return sqrtr_abs(a); prec = realprec(a); B = prec2nbits(prec); eextra = expu(n)-1; n1 = n+1; n2 = 2*n; av = avma; v = expo(a) / n; if (v) a = shiftr(a, -n*v); b = rtor(a, DEFAULTPREC); x = mpexp(divru(logr_abs(b), n)); if (prec == DEFAULTPREC) { if (v) shiftr_inplace(x, v); return gerepileuptoleaf(av, x); } mask = cubic_prec_mask(B + 63); eold = 1; for(;;) { /* reach 64 */ long enew = eold * 3; enew -= mask % 3; if (enew > 64) break; /* back up one step */ mask /= 3; eold = enew; } for(;;) { long pr, enew = eold * 3; GEN y, z; enew -= mask % 3; mask /= 3; pr = nbits2prec(enew + eextra); b = rtor(a, pr); setsigne(b,1); x = rtor(x, pr); y = subrr(powru(x, n), b); z = divrr(y, addrr(mulur(n1, y), mulur(n2, b))); shiftr_inplace(z,1); x = mulrr(x, subsr(1,z)); if (mask == 1) { if (v) shiftr_inplace(x, v); return gerepileuptoleaf(av, gprec_wtrunc(x,prec)); } eold = enew; } } static void shiftc_inplace(GEN z, long d) { shiftr_inplace(gel(z,1), d); shiftr_inplace(gel(z,2), d); } /* exp(2*Pi*I/n), same iteration as sqrtnr_abs, different initial point */ static GEN sqrtnof1(ulong n, long prec) { pari_sp av; GEN x; long eold, n1, n2, B; ulong mask; B = prec2nbits(prec); n1 = n+1; n2 = 2*n; av = avma; x = expIr(divru(Pi2n(1, LOWDEFAULTPREC), n)); if (prec == LOWDEFAULTPREC) return gerepileupto(av, x); mask = cubic_prec_mask(B + BITS_IN_LONG-1); eold = 1; for(;;) { /* reach BITS_IN_LONG */ long enew = eold * 3; enew -= mask % 3; if (enew > BITS_IN_LONG) break; /* back up one step */ mask /= 3; eold = enew; } for(;;) { long pr, enew = eold * 3; GEN y, z; enew -= mask % 3; mask /= 3; pr = nbits2prec(enew); x = cxtofp(x, pr); y = gsub(gpowgs(x, n), gen_1); z = gdiv(y, gaddgs(gmulsg(n1, y), n2)); shiftc_inplace(z,1); x = gmul(x, gsubsg(1, z)); if (mask == 1) return gerepilecopy(av, gprec_w(x,prec)); eold = enew; } } /* exp(2iPi/d) */ GEN rootsof1u_cx(ulong n, long prec) { switch(n) { case 1: return gen_1; case 2: return gen_m1; case 4: return gen_I(); case 3: case 6: case 12: { pari_sp av = avma; GEN a = (n == 3)? mkfrac(gen_m1,gen_2): ghalf; GEN sq3 = sqrtr_abs(utor(3, prec)); shiftr_inplace(sq3, -1); a = (n == 12)? mkcomplex(sq3, a): mkcomplex(a, sq3); return gerepilecopy(av, a); } case 8: { pari_sp av = avma; GEN sq2 = sqrtr_abs(utor(2, prec)); shiftr_inplace(sq2,-1); return gerepilecopy(av, mkcomplex(sq2, sq2)); } } return sqrtnof1(n, prec); } /* e(a/b) */ GEN rootsof1q_cx(long a, long b, long prec) { long g = cgcd(a,b); GEN z; if (g != 1) { a /= g; b /= g; } if (b < 0) { b = -b; a = -a; } z = rootsof1u_cx(b, prec); if (a < 0) { z = conj_i(z); a = -a; } return gpowgs(z, a); } /* initializes powers of e(a/b) */ GEN rootsof1powinit(long a, long b, long prec) { long g = cgcd(a,b); if (g != 1) { a /= g; b /= g; } if (b < 0) { b = -b; a = -a; } a %= b; if (a < 0) a += b; return mkvec2(grootsof1(b,prec), mkvecsmall2(a,b)); } /* T = rootsof1powinit(a,b); return e(a/b)^c */ GEN rootsof1pow(GEN T, long c) { GEN vz = gel(T,1), ab = gel(T,2); long a = ab[1], b = ab[2]; /* a >= 0, b > 0 */ c %= b; if (c < 0) c += b; a = Fl_mul(a, c, b); return gel(vz, a + 1); } /* exp(2iPi/d), assume d a t_INT */ GEN rootsof1_cx(GEN d, long prec) { if (lgefint(d) == 3) return rootsof1u_cx((ulong)d[2], prec); return expIr(divri(Pi2n(1,prec), d)); } GEN gsqrtn(GEN x, GEN n, GEN *zetan, long prec) { long i, lx, tx; pari_sp av; GEN y, z; if (typ(n)!=t_INT) pari_err_TYPE("sqrtn",n); if (!signe(n)) pari_err_DOMAIN("sqrtn", "n", "=", gen_0, n); if (is_pm1(n)) { if (zetan) *zetan = gen_1; return (signe(n) > 0)? gcopy(x): ginv(x); } if (zetan) *zetan = gen_0; tx = typ(x); if (is_matvec_t(tx)) { y = cgetg_copy(x, &lx); for (i=1; i 0 && tx == t_REAL && signe(x) > 0) y = sqrtnr(x, nn); else y = gexp(gdiv(glog(x,prec), n), prec); y = gerepileupto(av, y); } if (zetan) *zetan = rootsof1_cx(n, prec); return y; case t_QUAD: return gsqrtn(quadtofp(x, prec), n, zetan, prec); default: av = avma; if (!(y = toser_i(x))) break; return gerepileupto(av, ser_powfrac(y, ginv(n), prec)); } pari_err_TYPE("sqrtn",x); return NULL;/* LCOV_EXCL_LINE */ } /********************************************************************/ /** **/ /** EXP(X) - 1 **/ /** **/ /********************************************************************/ /* exp(|x|) - 1, assume x != 0. * For efficiency, x should be reduced mod log(2): if so, we have a < 0 */ GEN exp1r_abs(GEN x) { long l = realprec(x), a = expo(x), b = prec2nbits(l), L, i, n, m, B; GEN y, p2, X; pari_sp av; double d; if (b + a <= 0) return mpabs(x); y = cgetr(l); av = avma; B = b/3 + BITS_IN_LONG + (BITS_IN_LONG*BITS_IN_LONG)/ b; d = a/2.; m = (long)(d + sqrt(d*d + B)); /* >= 0 */ if (m < (-a) * 0.1) m = 0; /* not worth it */ L = l + nbits2extraprec(m); /* Multiplication is quadratic in this range (l is small, otherwise we * use logAGM + Newton). Set Y = 2^(-e-a) x, compute truncated series * sum x^k/k!: this costs roughly * m b^2 + sum_{k <= n} (k e + BITS_IN_LONG)^2 * bit operations with |x| < 2^(1+a), |Y| < 2^(1-e) , m = e+a and b bits of * accuracy needed, so * B := (b / 3 + BITS_IN_LONG + BITS_IN_LONG^2 / b) ~ m(m-a) * we want b ~ 3 m (m-a) or m~b+a hence * m = min( a/2 + sqrt(a^2/4 + B), b + a ) * NB: e ~ (b/3)^(1/2) as b -> oo * * Truncate the sum at k = n (>= 1), the remainder is * sum_{k >= n+1} Y^k / k! < Y^(n+1) / (n+1)! (1-Y) < Y^(n+1) / n! * We want Y^(n+1) / n! <= Y 2^-b, hence -n log_2 |Y| + log_2 n! >= b * log n! ~ (n + 1/2) log(n+1) - (n+1) + log(2Pi)/2, * error bounded by 1/6(n+1) <= 1/12. Finally, we want * n (-1/log(2) -log_2 |Y| + log_2(n+1)) >= b */ b += m; d = m-dbllog2(x)-1/M_LN2; /* ~ -log_2 Y - 1/log(2) */ n = (long)(b / d); if (n > 1) n = (long)(b / (d + log2((double)n+1))); /* log~constant in small ranges */ while (n*(d+log2((double)n+1)) < b) n++; /* expect few corrections */ X = rtor(x,L); shiftr_inplace(X, -m); setsigne(X, 1); if (n == 1) p2 = X; else { long s = 0, l1 = nbits2prec((long)(d + n + 16)); GEN unr = real_1(L); pari_sp av2; p2 = cgetr(L); av2 = avma; for (i=n; i>=2; i--, avma = av2) { /* compute X^(n-1)/n! + ... + X/2 + 1 */ GEN p1, p3; setprec(X,l1); p3 = divru(X,i); l1 += dvmdsBIL(s - expo(p3), &s); if (l1>L) l1=L; setprec(unr,l1); p1 = addrr_sign(unr,1, i == n? p3: mulrr(p3,p2),1); setprec(p2,l1); affrr(p1,p2); /* p2 <- 1 + (X/i)*p2 */ } setprec(X,L); p2 = mulrr(X,p2); } for (i=1; i<=m; i++) { if (realprec(p2) > L) setprec(p2,L); p2 = mulrr(p2, addsr(2,p2)); } affrr_fixlg(p2,y); avma = av; return y; } GEN mpexpm1(GEN x) { const long s = 6; long l, sx = signe(x); GEN y, z; pari_sp av; if (!sx) return real_0_bit(expo(x)); l = realprec(x); if (l > maxss(EXPNEWTON_LIMIT, (1L< 0) return exp1r_abs(x); /* compute exp(x) * (1 - exp(-x)) */ av = avma; y = exp1r_abs(x); z = addsr(1, y); setsigne(z, -1); return gerepileupto(av, divrr(y, z)); } static GEN serexp(GEN x, long prec); GEN gexpm1(GEN x, long prec) { switch(typ(x)) { case t_REAL: return mpexpm1(x); case t_COMPLEX: return cxexpm1(x,prec); case t_PADIC: return gsubgs(Qp_exp(x), 1); default: { pari_sp av = avma; long ey; GEN y; if (!(y = toser_i(x))) break; ey = valp(y); if (ey < 0) pari_err_DOMAIN("expm1","valuation", "<", gen_0, x); if (gequal0(y)) return gcopy(y); if (ey) return gerepileupto(av, gsubgs(serexp(y,prec), 1)); else { GEN e1 = gexpm1(gel(y,2), prec), e = gaddgs(e1,1); y = gmul(e, serexp(serchop0(y),prec)); gel(y,2) = e1; return gerepilecopy(av, y); } } } return trans_eval("expm1",gexpm1,x,prec); } /********************************************************************/ /** **/ /** EXP(X) **/ /** **/ /********************************************************************/ /* centermod(x, log(2)), set *sh to the quotient */ static GEN modlog2(GEN x, long *sh) { double d = rtodbl(x), da = fabs(d); long q = (long) ((da + (M_LN2/2))/M_LN2); if (da > M_LN2 * LONG_MAX) pari_err_OVERFLOW("expo()"); /* avoid overflow in q */ if (d < 0) q = -q; *sh = q; if (q) { long l = realprec(x) + 1; x = subrr(rtor(x,l), mulsr(q, mplog2(l))); if (!signe(x)) return NULL; } return x; } static GEN mpexp_basecase(GEN x) { pari_sp av = avma; long sh, l = realprec(x); GEN y, z; y = modlog2(x, &sh); if (!y) { avma = av; return real2n(sh, l); } z = addsr(1, exp1r_abs(y)); if (signe(y) < 0) z = invr(z); if (sh) { shiftr_inplace(z, sh); if (realprec(z) > l) z = rtor(z, l); /* spurious precision increase */ } #ifdef DEBUG { GEN t = mplog(z), u = divrr(subrr(x, t),x); if (signe(u) && expo(u) > 5-prec2nbits(minss(l,realprec(t)))) pari_err_BUG("exp"); } #endif return gerepileuptoleaf(av, z); /* NOT affrr, precision often increases */ } GEN mpexp(GEN x) { const long s = 6; /*Initial steps using basecase*/ long i, p, l = realprec(x), sh; GEN a, t, z; ulong mask; if (l <= maxss(EXPNEWTON_LIMIT, (1L<>= 1; } a = mpexp_basecase(rtor(x, nbits2prec(p))); x = addrs(x,1); if (realprec(x) < l+EXTRAPRECWORD) x = rtor(x, l+EXTRAPRECWORD); a = rtor(a, l+EXTRAPRECWORD); /*append 0s */ t = NULL; for(;;) { p <<= 1; if (mask & 1) p--; mask >>= 1; setprec(x, nbits2prec(p)); setprec(a, nbits2prec(p)); t = mulrr(a, subrr(x, logr_abs(a))); /* a (x - log(a)) */ if (mask == 1) break; affrr(t, a); avma = (pari_sp)a; } affrr(t,z); if (sh) shiftr_inplace(z, sh); avma = (pari_sp)z; return z; } static long Qp_exp_prec(GEN x) { long k, e = valp(x), n = e + precp(x); GEN p = gel(x,2); int is2 = absequaliu(p,2); if (e < 1 || (e == 1 && is2)) return -1; if (is2) { n--; e--; k = n/e; if (n%e == 0) k--; } else { /* e > 0, n > 0 */ GEN r, t = subiu(p, 1); k = itos(dvmdii(subiu(muliu(t,n), 1), subiu(muliu(t,e), 1), &r)); if (!signe(r)) k--; } return k; } static GEN Qp_exp_safe(GEN x) { long k; pari_sp av; GEN y; if (gequal0(x)) return gaddgs(x,1); k = Qp_exp_prec(x); if (k < 0) return NULL; av = avma; for (y=gen_1; k; k--) y = gaddsg(1, gdivgs(gmul(y,x), k)); return gerepileupto(av, y); } GEN Qp_exp(GEN x) { GEN y = Qp_exp_safe(x); if (!y) pari_err_DOMAIN("gexp(t_PADIC)","argument","",gen_0,x); return y; } static GEN cos_p(GEN x) { long k; pari_sp av; GEN x2, y; if (gequal0(x)) return gaddgs(x,1); k = Qp_exp_prec(x); if (k < 0) return NULL; av = avma; x2 = gsqr(x); if (k & 1) k--; for (y=gen_1; k; k-=2) { GEN t = gdiv(gmul(y,x2), muluu(k, k-1)); y = gsubsg(1, t); } return gerepileupto(av, y); } static GEN sin_p(GEN x) { long k; pari_sp av; GEN x2, y; if (gequal0(x)) return gcopy(x); k = Qp_exp_prec(x); if (k < 0) return NULL; av = avma; x2 = gsqr(x); if (k & 1) k--; for (y=gen_1; k; k-=2) { GEN t = gdiv(gmul(y,x2), muluu(k, k+1)); y = gsubsg(1, t); } return gerepileupto(av, gmul(y, x)); } static GEN cxexp(GEN x, long prec) { GEN r, p1, p2, y = cgetg(3,t_COMPLEX); pari_sp av = avma, tetpil; long l; l = precision(x); if (l > prec) prec = l; r = gexp(gel(x,1),prec); if (gequal0(r)) { gel(y,1) = r; gel(y,2) = r; return y; } gsincos(gel(x,2),&p2,&p1,prec); tetpil = avma; gel(y,1) = gmul(r,p1); gel(y,2) = gmul(r,p2); gerepilecoeffssp(av,tetpil,y+1,2); return y; } /* given a t_SER x^v s(x), with s(0) != 0, return x^v(s - s(0)), shallow */ GEN serchop0(GEN s) { long i, l = lg(s); GEN y; if (l == 2) return s; if (l == 3 && isexactzero(gel(s,2))) return s; y = cgetg(l, t_SER); y[1] = s[1]; gel(y,2) = gen_0; for (i=3; i =3 && isrationalzero(gel(x,mi))) mi--; mi += ex-2; y[1] = evalsigne(1) | _evalvalp(0) | evalvarn(varn(x)); /* zd[i] = coefficient of X^i in z */ xd = x+2-ex; yd = y+2; ly -= 2; gel(yd,0) = gen_1; for (i=1; i= L); } /* assume x > 0 */ static GEN agm1r_abs(GEN x) { long l = realprec(x), L = 5-prec2nbits(l); GEN a1, b1, y = cgetr(l); pari_sp av = avma; a1 = addrr(real_1(l), x); shiftr_inplace(a1, -1); b1 = sqrtr_abs(x); while (agmr_gap(a1,b1,L)) { GEN a = a1; a1 = addrr(a,b1); shiftr_inplace(a1, -1); b1 = sqrtr_abs(mulrr(a,b1)); } affrr_fixlg(a1,y); avma = av; return y; } struct agmcx_gap_t { long L, ex, cnt; }; static void agmcx_init(GEN x, long *prec, struct agmcx_gap_t *S) { long l = precision(x); if (l) *prec = l; S->L = 1-prec2nbits(*prec); S->cnt = 0; S->ex = LONG_MAX; } static long agmcx_a_b(GEN x, GEN *a1, GEN *b1, long prec) { long rotate = 0; if (gsigne(real_i(x))<0) { /* Rotate by +/-Pi/2, so that the choice of the principal square * root gives the optimal AGM. So a1 = +/-I*a1, b1=sqrt(-x). */ if (gsigne(imag_i(x))<0) { *a1=mulcxI(*a1); rotate=-1; } else { *a1=mulcxmI(*a1); rotate=1; } x = gneg(x); } *b1 = gsqrt(x, prec); return rotate; } /* return 0 if we must stop the AGM loop (a=b or a ~ b), 1 otherwise */ static int agmcx_gap(GEN a, GEN b, struct agmcx_gap_t *S) { GEN d = gsub(b, a); long ex = S->ex; S->ex = gexpo(d); if (gequal0(d) || S->ex - gexpo(b) < S->L) return 0; /* if (S->ex >= ex) we're no longer making progress; twice in a row */ if (S->ex < ex) S->cnt = 0; else if (S->cnt++) return 0; return 1; } static GEN agm1cx(GEN x, long prec) { struct agmcx_gap_t S; GEN a1, b1; pari_sp av = avma; long rotate; agmcx_init(x, &prec, &S); a1 = gtofp(gmul2n(gadd(real_1(prec), x), -1), prec); rotate = agmcx_a_b(x, &a1, &b1, prec); while (agmcx_gap(a1,b1,&S)) { GEN a = a1; a1 = gmul2n(gadd(a,b1),-1); b1 = gsqrt(gmul(a,b1), prec); } if (rotate) a1 = rotate>0 ? mulcxI(a1):mulcxmI(a1); return gerepilecopy(av,a1); } GEN zellagmcx(GEN a0, GEN b0, GEN r, GEN t, long prec) { struct agmcx_gap_t S; pari_sp av = avma; GEN x = gdiv(a0, b0), a1, b1; long rotate; agmcx_init(x, &prec, &S); a1 = gtofp(gmul2n(gadd(real_1(prec), x), -1), prec); r = gsqrt(gdiv(gmul(a1,gaddgs(r, 1)),gadd(r, x)), prec); t = gmul(r, t); rotate = agmcx_a_b(x, &a1, &b1, prec); while (agmcx_gap(a1,b1,&S)) { GEN a = a1, b = b1; a1 = gmul2n(gadd(a,b),-1); b1 = gsqrt(gmul(a,b), prec); r = gsqrt(gdiv(gmul(a1,gaddgs(r, 1)),gadd(gmul(b, r), a )), prec); t = gmul(r, t); } if (rotate) a1 = rotate>0 ? mulcxI(a1):mulcxmI(a1); a1 = gmul(a1, b0); t = gatan(gdiv(a1,t), prec); /* send t to the fundamental domain if necessary */ if (gsigne(real_i(t))<0) t = gadd(t, mppi(prec)); return gerepileupto(av,gdiv(t,a1)); } static long ser_cmp_expo(GEN A, GEN B) { long e = -(long)HIGHEXPOBIT, d = valp(B) - valp(A); long i, la = lg(A), v = varn(B); for (i = 2; i < la; i++) { GEN a = gel(A,i), b; long ei; if (isexactzero(a)) continue; b = polcoef_i(B, i-2 + d, v); ei = gexpo(a); if (!isexactzero(b)) ei -= gexpo(b); e = maxss(e, ei); } return e; } static GEN ser_agm1(GEN y, long prec) { GEN a1 = y, b1 = gen_1; long l = lg(y)-2, l2 = 6-prec2nbits(prec), eold = LONG_MAX; for(;;) { GEN a = a1, p1; a1 = gmul2n(gadd(a,b1),-1); b1 = gsqrt(gmul(a,b1), prec); p1 = gsub(b1,a1); if (isinexactreal(p1)) { long e = ser_cmp_expo(p1, b1); if (e < l2 || e >= eold) break; eold = e; } else { long ep = valp(p1)-valp(b1); if (ep >= l && gequal0(p1)) break; } } return a1; } /* agm(1,x) */ static GEN agm1(GEN x, long prec) { GEN y; pari_sp av; if (gequal0(x)) return gcopy(x); switch(typ(x)) { case t_INT: if (!is_pm1(x)) break; return (signe(x) > 0)? real_1(prec): real_0(prec); case t_REAL: return signe(x) > 0? agm1r_abs(x): agm1cx(x, prec); case t_COMPLEX: if (gequal0(gel(x,2))) return agm1(gel(x,1), prec); return agm1cx(x, prec); case t_PADIC: { GEN a1 = x, b1 = gen_1; long l = precp(x); av = avma; for(;;) { GEN a = a1, p1; long ep; a1 = gmul2n(gadd(a,b1),-1); a = gmul(a,b1); b1 = Qp_sqrt(a); if (!b1) pari_err_SQRTN("Qp_sqrt",a); p1 = gsub(b1,a1); ep = valp(p1)-valp(b1); if (ep<=0) { b1 = gneg_i(b1); p1 = gsub(b1,a1); ep=valp(p1)-valp(b1); } if (ep >= l || gequal0(p1)) return gerepilecopy(av,a1); } } default: av = avma; if (!(y = toser_i(x))) break; return gerepilecopy(av, ser_agm1(y, prec)); } return trans_eval("agm",agm1,x,prec); } GEN agm(GEN x, GEN y, long prec) { pari_sp av; if (is_matvec_t(typ(y))) { if (is_matvec_t(typ(x))) pari_err_TYPE2("agm",x,y); swap(x, y); } if (gequal0(y)) return gcopy(y); av = avma; return gerepileupto(av, gmul(y, agm1(gdiv(x,y), prec))); } /********************************************************************/ /** **/ /** LOG(X) **/ /** **/ /********************************************************************/ /* atanh(u/v) using binary splitting */ static GEN atanhQ_split(ulong u, ulong v, long prec) { long i, nmax; GEN u2 = sqru(u), v2 = sqru(v); double d = ((double)v) / u; struct abpq_res R; struct abpq A; /* satisfies (2n+1) (v/u)^2n > 2^bitprec */ nmax = (long)(prec2nbits(prec) / (2*log2(d))); abpq_init(&A, nmax); A.a[0] = A.b[0] = gen_1; A.p[0] = utoipos(u); A.q[0] = utoipos(v); for (i = 1; i <= nmax; i++) { A.a[i] = gen_1; A.b[i] = utoipos((i<<1)+1); A.p[i] = u2; A.q[i] = v2; } abpq_sum(&R, 0, nmax, &A); return rdivii(R.T, mulii(R.B,R.Q),prec); } /* log(2) = 10*atanh(1/17)+4*atanh(13/499); faster than logagmr_abs() * and Pi/2M(1,4/2^n) ~ n log(2) */ static GEN log2_split(long prec) { GEN u = atanhQ_split(1, 17, prec); GEN v = atanhQ_split(13, 499, prec); shiftr_inplace(v, 2); return addrr(mulur(10, u), v); } GEN constlog2(long prec) { pari_sp av; GEN tmp; if (glog2 && realprec(glog2) >= prec) return glog2; tmp = cgetr_block(prec); av = avma; affrr(log2_split(prec+EXTRAPRECWORD), tmp); swap_clone(&glog2,tmp); avma = av; return glog2; } GEN mplog2(long prec) { return rtor(constlog2(prec), prec); } /* dont check that q != 2^expo(q), done in logr_abs */ static GEN logagmr_abs(GEN q) { long prec = realprec(q), e = expo(q), lim; GEN z = cgetr(prec), y, Q, _4ovQ; pari_sp av = avma; incrprec(prec); lim = prec2nbits(prec) >> 1; Q = rtor(q,prec); shiftr_inplace(Q,lim-e); setsigne(Q,1); _4ovQ = invr(Q); shiftr_inplace(_4ovQ, 2); /* 4/Q */ /* Pi / 2agm(1, 4/Q) ~ log(Q), q = Q * 2^(e-lim) */ y = divrr(Pi2n(-1, prec), agm1r_abs(_4ovQ)); y = addrr(y, mulsr(e - lim, mplog2(prec))); affrr_fixlg(y, z); avma = av; return z; } /* sum_{k >= 0} y^(2k+1) / (2k+1), y close to 0 */ static GEN logr_aux(GEN y) { long k, L = realprec(y); /* should be ~ l+1 - (k-2) */ /* log(x) = log(1+y) - log(1-y) = 2 sum_{k odd} y^k / k * Truncate the sum at k = 2n+1, the remainder is * 2 sum_{k >= 2n+3} y^k / k < 2y^(2n+3) / (2n+3)(1-y) < y^(2n+3) * We want y^(2n+3) < y 2^(-prec2nbits(L)), hence * n+1 > -prec2nbits(L) /-log_2(y^2) */ double d = -2*dbllog2r(y); /* ~ -log_2(y^2) */ k = (long)(2*(prec2nbits(L) / d)); k |= 1; if (k >= 3) { GEN T, S = cgetr(L), y2 = sqrr(y), unr = real_1(L); pari_sp av = avma; long s = 0, incs = (long)d, l1 = nbits2prec((long)d); setprec(S, l1); setprec(unr,l1); affrr(divru(unr,k), S); for (k -= 2;; k -= 2) /* k = 2n+1, ..., 1 */ { /* S = y^(2n+1-k)/(2n+1) + ... + 1 / k */ setprec(y2, l1); T = mulrr(S,y2); if (k == 1) break; l1 += dvmdsBIL(s + incs, &s); if (l1>L) l1=L; setprec(S, l1); setprec(unr,l1); affrr(addrr(divru(unr, k), T), S); avma = av; } /* k = 1 special-cased for eficiency */ y = mulrr(y, addsr(1,T)); /* = log(X)/2 */ } return y; } /*return log(|x|), assuming x != 0 */ GEN logr_abs(GEN X) { long EX, L, m, k, a, b, l = realprec(X); GEN z, x, y; ulong u; double d; /* Assuming 1 < x < 2, we want delta = x-1, 1-x/2, 1-1/x, or 2/x-1 small. * We have 2/x-1 > 1-x/2, 1-1/x < x-1. So one should be choosing between * 1-1/x and 1-x/2 ( crossover sqrt(2), worse ~ 0.29 ). To avoid an inverse, * we choose between x-1 and 1-x/2 ( crossover 4/3, worse ~ 0.33 ) */ EX = expo(X); u = uel(X,2); k = 2; if (u > (~0UL / 3) * 2) { /* choose 1-x/2 */ EX++; u = ~u; while (!u && ++k < l) { u = uel(X,k); u = ~u; } } else { /* choose x - 1 */ u &= ~HIGHBIT; /* u - HIGHBIT, assuming HIGHBIT set */ while (!u && ++k < l) u = uel(X,k); } if (k == l) return EX? mulsr(EX, mplog2(l)): real_0(l); a = prec2nbits(k) + bfffo(u); /* ~ -log2 |1-x| */ L = l+1; b = prec2nbits(L - (k-2)); /* take loss of accuracy into account */ if (b > 24*a*log2(L) && prec2nbits(l) > prec2nbits(LOGAGM_LIMIT)) return logagmr_abs(X); z = cgetr(EX? l: l - (k-2)); /* Multiplication is quadratic in this range (l is small, otherwise we * use AGM). Set Y = x^(1/2^m), y = (Y - 1) / (Y + 1) and compute truncated * series sum y^(2k+1)/(2k+1): the costs is less than * m b^2 + sum_{k <= n} ((2k+1) e + BITS_IN_LONG)^2 * bit operations with |x-1| < 2^(1-a), |Y| < 2^(1-e) , m = e-a and b bits of * accuracy needed (+ BITS_IN_LONG since bit accuracies increase by * increments of BITS_IN_LONG), so * 4n^3/3 e^2 + n^2 2e BITS_IN_LONG+ n BITS_IN_LONG ~ m b^2, with n ~ b/2e * or b/6e + BITS_IN_LONG/2e + BITS_IN_LONG/2be ~ m * B := (b / 6 + BITS_IN_LONG/2 + BITS_IN_LONG^2 / 2b) ~ m(m+a) * m = min( -a/2 + sqrt(a^2/4 + B), b - a ) * NB: e ~ (b/6)^(1/2) as b -> oo * Instead of the above pessimistic estimate for the cost of the sum, use * optimistic estimate (BITS_IN_LONG -> 0) */ d = -a/2.; m = (long)(d + sqrt(d*d + b/6)); /* >= 0 */ if (m > b-a) m = b-a; if (m < 0.2*a) m = 0; else L += nbits2extraprec(m); x = rtor(X,L); setsigne(x,1); shiftr_inplace(x,-EX); /* 2/3 < x < 4/3 */ for (k=1; k<=m; k++) x = sqrtr_abs(x); y = divrr(subrs(x,1), addrs(x,1)); /* = (x-1) / (x+1), close to 0 */ y = logr_aux(y); /* log(1+y) - log(1-y) = log(x) */ shiftr_inplace(y, m + 1); if (EX) y = addrr(y, mulsr(EX, mplog2(l+1))); affrr_fixlg(y, z); avma = (pari_sp)z; return z; } /* assume Im(q) != 0 and precision(q) >= prec. Compute log(q) with accuracy * prec [disregard input accuracy] */ GEN logagmcx(GEN q, long prec) { GEN z = cgetc(prec), y, Q, a, b; long lim, e, ea, eb; pari_sp av = avma; int neg = 0; incrprec(prec); if (gsigne(gel(q,1)) < 0) { q = gneg(q); neg = 1; } lim = prec2nbits(prec) >> 1; Q = gtofp(q, prec); a = gel(Q,1); b = gel(Q,2); if (gequal0(a)) { affrr_fixlg(logr_abs(b), gel(z,1)); y = Pi2n(-1, prec); if (signe(b) < 0) setsigne(y, -1); affrr_fixlg(y, gel(z,2)); avma = av; return z; } ea = expo(a); eb = expo(b); e = ea <= eb ? lim - eb : lim - ea; shiftr_inplace(a, e); shiftr_inplace(b, e); /* Pi / 2agm(1, 4/Q) ~ log(Q), q = Q * 2^e */ y = gdiv(Pi2n(-1, prec), agm1cx( gdivsg(4, Q), prec )); a = gel(y,1); b = gel(y,2); a = addrr(a, mulsr(-e, mplog2(prec))); if (realprec(a) <= LOWDEFAULTPREC) a = real_0_bit(expo(a)); if (neg) b = gsigne(b) <= 0? gadd(b, mppi(prec)) : gsub(b, mppi(prec)); affrr_fixlg(a, gel(z,1)); affrr_fixlg(b, gel(z,2)); avma = av; return z; } GEN mplog(GEN x) { if (signe(x)<=0) pari_err_DOMAIN("mplog", "argument", "<=", gen_0, x); return logr_abs(x); } /* pe = p^e, p prime, 0 < x < pe a t_INT coprime to p. Return the (p-1)-th * root of 1 in (Z/pe)^* congruent to x mod p, resp x mod 4 if p = 2. * Simplified form of Zp_sqrtnlift: 1/(p-1) is trivial to compute */ GEN Zp_teichmuller(GEN x, GEN p, long e, GEN pe) { GEN q, z, p1; pari_sp av; ulong mask; if (absequaliu(p,2)) return (mod4(x) & 2)? subiu(pe,1): gen_1; if (e == 1) return icopy(x); av = avma; p1 = subiu(p, 1); mask = quadratic_prec_mask(e); q = p; z = remii(x, p); while (mask > 1) { /* Newton iteration solving z^{1 - p} = 1, z = x (mod p) */ GEN w, t, qold = q; if (mask <= 3) /* last iteration */ q = pe; else { q = sqri(q); if (mask & 1) q = diviiexact(q, p); } mask >>= 1; /* q <= qold^2 */ if (lgefint(q) == 3) { ulong Z = uel(z,2), Q = uel(q,2), P1 = uel(p1,2); ulong W = (Q-1) / P1; /* -1/(p-1) + O(qold) */ ulong T = Fl_mul(W, Fl_powu(Z,P1,Q) - 1, Q); Z = Fl_mul(Z, 1 + T, Q); z = utoi(Z); } else { w = diviiexact(subiu(qold,1),p1); /* -1/(p-1) + O(qold) */ t = Fp_mul(w, subiu(Fp_pow(z,p1,q), 1), q); z = Fp_mul(z, addui(1,t), q); } } return gerepileuptoint(av, z); } GEN teichmullerinit(long p, long n) { GEN t, pn, g, v; ulong gp, tp; long a, m; if (p == 2) return mkvec(gen_1); if (!uisprime(p)) pari_err_PRIME("teichmullerinit",utoipos(p)); m = p >> 1; /* (p-1)/2 */ tp= gp= pgener_Fl(p); /* order (p-1), gp^m = -1 */ pn = powuu(p, n); v = cgetg(p, t_VEC); t = g = Zp_teichmuller(utoipos(gp), utoipos(p), n, pn); gel(v, 1) = gen_1; gel(v, p-1) = subiu(pn,1); for (a = 1; a < m; a++) { gel(v, tp) = t; gel(v, p - tp) = Fp_neg(t, pn); /* g^(m+a) = -g^a */ if (a < m-1) { t = Fp_mul(t, g, pn); /* g^(a+1) */ tp = Fl_mul(tp, gp, p); /* t mod p */ } } return v; } /* tab from teichmullerinit or NULL */ GEN teichmuller(GEN x, GEN tab) { GEN p, q, y, z; long n, tx = typ(x); if (!tab) { if (tx == t_VEC && lg(x) == 3) { p = gel(x,1); q = gel(x,2); if (typ(p) == t_INT && typ(q) == t_INT) return teichmullerinit(itos(p), itos(q)); } } else if (typ(tab) != t_VEC) pari_err_TYPE("teichmuller",tab); if (tx!=t_PADIC) pari_err_TYPE("teichmuller",x); z = gel(x,4); if (!signe(z)) return gcopy(x); p = gel(x,2); q = gel(x,3); n = precp(x); y = cgetg(5,t_PADIC); y[1] = evalprecp(n) | _evalvalp(0); gel(y,2) = icopy(p); gel(y,3) = icopy(q); if (tab) { ulong pp = itou_or_0(p); if (lg(tab) != (long)pp) pari_err_TYPE("teichmuller",tab); z = gel(tab, umodiu(z, pp)); if (typ(z) != t_INT) pari_err_TYPE("teichmuller",tab); z = remii(z, q); } else z = Zp_teichmuller(z, p, n, q); gel(y,4) = z; return y; } GEN teich(GEN x) { return teichmuller(x, NULL); } GEN glog(GEN x, long prec) { pari_sp av, tetpil; GEN y, p1; long l; switch(typ(x)) { case t_REAL: if (signe(x) >= 0) { if (!signe(x)) pari_err_DOMAIN("log", "argument", "=", gen_0, x); return logr_abs(x); } retmkcomplex(logr_abs(x), mppi(realprec(x))); case t_FRAC: { GEN a, b; long e1, e2; av = avma; a = gel(x,1); b = gel(x,2); e1 = expi(subii(a,b)); e2 = expi(b); if (e2 > e1) prec += nbits2nlong(e2 - e1); x = fractor(x, prec); return gerepileupto(av, glog(x, prec)); } case t_COMPLEX: if (ismpzero(gel(x,2))) return glog(gel(x,1), prec); l = precision(x); if (l > prec) prec = l; if (ismpzero(gel(x,1))) { GEN a = gel(x,2), b; av = avma; b = Pi2n(-1,prec); if (gsigne(a) < 0) { setsigne(b, -1); a = gabs(a,prec); } a = isint1(a) ? gen_0: glog(a,prec); return gerepilecopy(av, mkcomplex(a, b)); } if (prec >= LOGAGMCX_LIMIT) return logagmcx(x, prec); y = cgetg(3,t_COMPLEX); gel(y,2) = garg(x,prec); av = avma; p1 = glog(cxnorm(x),prec); tetpil = avma; gel(y,1) = gerepile(av,tetpil,gmul2n(p1,-1)); return y; case t_PADIC: return Qp_log(x); default: av = avma; if (!(y = toser_i(x))) break; if (!signe(y)) pari_err_DOMAIN("log", "argument", "=", gen_0, x); if (valp(y)) pari_err_DOMAIN("log", "series valuation", "!=", gen_0, x); p1 = integser(gdiv(derivser(y), y)); /* log(y)' = y'/y */ if (!gequal1(gel(y,2))) p1 = gadd(p1, glog(gel(y,2),prec)); return gerepileupto(av, p1); } return trans_eval("log",glog,x,prec); } static GEN mplog1p(GEN x) { long ex, a, b, l, L; if (!signe(x)) return rcopy(x); ex = expo(x); if (ex >= 0) return glog(addrs(x,1), 0); a = -ex; b = realprec(x); L = b+1; if (b > a*log2(L) && prec2nbits(b) > prec2nbits(LOGAGM_LIMIT)) { x = addrs(x,1); l = b + nbits2extraprec(a); if (realprec(x) < l) x = rtor(x,l); return logagmr_abs(x); } x = rtor(x, L); x = logr_aux(divrr(x, addrs(x,2))); if (realprec(x) > b) fixlg(x, b); shiftr_inplace(x,1); return x; } static GEN log1p_i(GEN x, long prec); static GEN cxlog1p(GEN x, long prec) { pari_sp av; GEN z, a, b = gel(x,2); long l; if (ismpzero(b)) return log1p_i(gel(x,1), prec); l = precision(x); if (l > prec) prec = l; if (prec >= LOGAGMCX_LIMIT) return logagmcx(gaddgs(x,1), prec); a = gel(x,1); z = cgetg(3,t_COMPLEX); av = avma; a = gadd(gadd(gmul2n(a,1), gsqr(a)), gsqr(b)); a = log1p_i(a, prec); shiftr_inplace(a,-1); gel(z,1) = gerepileupto(av, a); gel(z,2) = garg(gaddgs(x,1),prec); return z; } static GEN log1p_i(GEN x, long prec) { switch(typ(x)) { case t_REAL: return mplog1p(x); case t_COMPLEX: return cxlog1p(x, prec); case t_PADIC: return Qp_log(gaddgs(x,1)); default: { long ey; GEN y; if (!(y = toser_i(x))) break; ey = valp(y); if (ey < 0) pari_err_DOMAIN("log1p","valuation", "<", gen_0, x); if (gequal0(y)) return gcopy(y); if (ey) return glog(gaddgs(y,1),prec); else { GEN a = gel(y,2), a1 = gaddgs(a,1); y = gdiv(y, a1); gel(y,2) = gen_1; return gadd(glog1p(a,prec), glog(y, prec)); } } } return trans_eval("log1p",glog1p,x,prec); } GEN glog1p(GEN x, long prec) { pari_sp av = avma; return gerepileupto(av, log1p_i(x, prec)); } /********************************************************************/ /** **/ /** SINE, COSINE **/ /** **/ /********************************************************************/ /* Reduce x0 mod Pi/2 to x in [-Pi/4, Pi/4]. Return cos(x)-1 */ static GEN mpcosm1(GEN x, long *ptmod8) { long a = expo(x), l = realprec(x), b, L, i, n, m, B; GEN y, p2, x2; double d; n = 0; if (a >= 0) { long p; GEN q; if (a > 30) { GEN z, pitemp = Pi2n(-2, nbits2prec(a + 32)); z = addrr(x,pitemp); /* = x + Pi/4 */ if (expo(z) >= bit_prec(z) + 3) pari_err_PREC("mpcosm1"); shiftr_inplace(pitemp, 1); q = floorr( divrr(z,pitemp) ); /* round ( x / (Pi/2) ) */ p = l+EXTRAPRECWORD; x = rtor(x,p); } else { q = stoi((long)floor(rtodbl(x) / (M_PI/2) + 0.5)); p = l; } if (signe(q)) { x = subrr(x, mulir(q, Pi2n(-1,p))); /* x mod Pi/2 */ a = expo(x); if (!signe(x) && a >= 0) pari_err_PREC("mpcosm1"); n = mod4(q); if (n && signe(q) < 0) n = 4 - n; } } /* a < 0 */ b = signe(x); *ptmod8 = (b < 0)? 4 + n: n; if (!b) return real_0_bit(expo(x)*2 - 1); b = prec2nbits(l); if (b + 2*a <= 0) { y = sqrr(x); shiftr_inplace(y, -1); setsigne(y, -1); return y; } y = cgetr(l); B = b/6 + BITS_IN_LONG + (BITS_IN_LONG*BITS_IN_LONG/2)/ b; d = a/2.; m = (long)(d + sqrt(d*d + B)); /* >= 0 ,*/ if (m < (-a) * 0.1) m = 0; /* not worth it */ L = l + nbits2extraprec(m); b += m; d = 2.0 * (m-dbllog2r(x)-1/M_LN2); /* ~ 2( - log_2 Y - 1/log(2) ) */ n = (long)(b / d); if (n > 1) n = (long)(b / (d + log2((double)n+1))); /* log~constant in small ranges */ while (n*(d+log2((double)n+1)) < b) n++; /* expect few corrections */ /* Multiplication is quadratic in this range (l is small, otherwise we * use logAGM + Newton). Set Y = 2^(-e-a) x, compute truncated series * sum Y^2k/(2k)!: this costs roughly * m b^2 + sum_{k <= n} (2k e + BITS_IN_LONG)^2 * ~ floor(b/2e) b^2 / 3 + m b^2 * bit operations with |x| < 2^(1+a), |Y| < 2^(1-e) , m = e+a and b bits of * accuracy needed, so * B := ( b / 6 + BITS_IN_LONG + BITS_IN_LONG^2 / 2b) ~ m(m-a) * we want b ~ 6 m (m-a) or m~b+a hence * m = min( a/2 + sqrt(a^2/4 + b/6), b/2 + a ) * NB1: e ~ (b/6)^(1/2) or b/2. * NB2: We use b/4 instead of b/6 in the formula above: hand-optimized... * * Truncate the sum at k = n (>= 1), the remainder is * < sum_{k >= n+1} Y^2k / 2k! < Y^(2n+2) / (2n+2)!(1-Y^2) < Y^(2n+2)/(2n+1)! * We want ... <= Y^2 2^-b, hence -2n log_2 |Y| + log_2 (2n+1)! >= b * log n! ~ (n + 1/2) log(n+1) - (n+1) + log(2Pi)/2, * error bounded by 1/6(n+1) <= 1/12. Finally, we want * 2n (-1/log(2) - log_2 |Y| + log_2(2n+2)) >= b */ x = rtor(x, L); shiftr_inplace(x, -m); setsigne(x, 1); x2 = sqrr(x); if (n == 1) { p2 = x2; shiftr_inplace(p2, -1); setsigne(p2, -1); } /*-Y^2/2*/ else { GEN unr = real_1(L); pari_sp av; long s = 0, l1 = nbits2prec((long)(d + n + 16)); p2 = cgetr(L); av = avma; for (i=n; i>=2; i--) { GEN p1; setprec(x2,l1); p1 = divrunu(x2, 2*i-1); l1 += dvmdsBIL(s - expo(p1), &s); if (l1>L) l1=L; if (i != n) p1 = mulrr(p1,p2); setprec(unr,l1); p1 = addrr_sign(unr,1, p1,-signe(p1)); setprec(p2,l1); affrr(p1,p2); avma = av; } shiftr_inplace(p2, -1); togglesign(p2); /* p2 := -p2/2 */ setprec(x2,L); p2 = mulrr(x2,p2); } /* Now p2 = sum {1<= i <=n} (-1)^i x^(2i) / (2i)! ~ cos(x) - 1 */ for (i=1; i<=m; i++) { /* p2 = cos(x)-1 --> cos(2x)-1 */ p2 = mulrr(p2, addsr(2,p2)); shiftr_inplace(p2, 1); if ((i & 31) == 0) p2 = gerepileuptoleaf((pari_sp)y, p2); } affrr_fixlg(p2,y); return y; } /* sqrt (|1 - (1+x)^2|) = sqrt(|x*(x+2)|). Sends cos(x)-1 to |sin(x)| */ static GEN mpaut(GEN x) { pari_sp av = avma; GEN t = mulrr(x, addsr(2,x)); /* != 0 */ if (!signe(t)) return real_0_bit(expo(t) >> 1); return gerepileuptoleaf(av, sqrtr_abs(t)); } /********************************************************************/ /** COSINE **/ /********************************************************************/ GEN mpcos(GEN x) { long mod8; pari_sp av; GEN y,p1; if (!signe(x)) { long l = nbits2prec(-expo(x)); if (l < LOWDEFAULTPREC) l = LOWDEFAULTPREC; return real_1(l); } av = avma; p1 = mpcosm1(x,&mod8); switch(mod8) { case 0: case 4: y = addsr(1,p1); break; case 1: case 7: y = mpaut(p1); togglesign(y); break; case 2: case 6: y = subsr(-1,p1); break; default: y = mpaut(p1); break; /* case 3: case 5: */ } return gerepileuptoleaf(av, y); } /* convert INT or FRAC to REAL, which is later reduced mod 2Pi : avoid * cancellation */ static GEN tofp_safe(GEN x, long prec) { return (typ(x) == t_INT || gexpo(x) > 0)? gadd(x, real_0(prec)) : fractor(x, prec); } GEN gcos(GEN x, long prec) { pari_sp av; GEN r, u, v, y, u1, v1; long i; switch(typ(x)) { case t_REAL: return mpcos(x); case t_COMPLEX: if (isintzero(gel(x,1))) return gcosh(gel(x,2), prec); i = precision(x); if (i) prec = i; y = cgetc(prec); av = avma; r = gexp(gel(x,2),prec); v1 = gmul2n(addrr(invr(r),r), -1); /* = cos(I*Im(x)) */ u1 = subrr(v1, r); /* = - I*sin(I*Im(x)) */ gsincos(gel(x,1),&u,&v,prec); affrr_fixlg(gmul(v1,v), gel(y,1)); affrr_fixlg(gmul(u1,u), gel(y,2)); avma = av; return y; case t_INT: case t_FRAC: y = cgetr(prec); av = avma; affrr_fixlg(mpcos(tofp_safe(x,prec)), y); avma = av; return y; case t_PADIC: y = cos_p(x); if (!y) pari_err_DOMAIN("gcos(t_PADIC)","argument","",gen_0,x); return y; default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) return gerepileupto(av, gaddsg(1,y)); if (valp(y) < 0) pari_err_DOMAIN("cos","valuation", "<", gen_0, x); gsincos(y,&u,&v,prec); return gerepilecopy(av,v); } return trans_eval("cos",gcos,x,prec); } /********************************************************************/ /** SINE **/ /********************************************************************/ GEN mpsin(GEN x) { long mod8; pari_sp av; GEN y,p1; if (!signe(x)) return real_0_bit(expo(x)); av = avma; p1 = mpcosm1(x,&mod8); switch(mod8) { case 0: case 6: y=mpaut(p1); break; case 1: case 5: y=addsr(1,p1); break; case 2: case 4: y=mpaut(p1); togglesign(y); break; default: y=subsr(-1,p1); break; /* case 3: case 7: */ } return gerepileuptoleaf(av, y); } GEN gsin(GEN x, long prec) { pari_sp av; GEN r, u, v, y, v1, u1; long i; switch(typ(x)) { case t_REAL: return mpsin(x); case t_COMPLEX: if (isintzero(gel(x,1))) retmkcomplex(gen_0,gsinh(gel(x,2),prec)); i = precision(x); if (i) prec = i; y = cgetc(prec); av = avma; r = gexp(gel(x,2),prec); v1 = gmul2n(addrr(invr(r),r), -1); /* = cos(I*Im(x)) */ u1 = subrr(r, v1); /* = I*sin(I*Im(x)) */ gsincos(gel(x,1),&u,&v,prec); affrr_fixlg(gmul(v1,u), gel(y,1)); affrr_fixlg(gmul(u1,v), gel(y,2)); avma = av; return y; case t_INT: case t_FRAC: y = cgetr(prec); av = avma; affrr_fixlg(mpsin(tofp_safe(x,prec)), y); avma = av; return y; case t_PADIC: y = sin_p(x); if (!y) pari_err_DOMAIN("gsin(t_PADIC)","argument","",gen_0,x); return y; default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) return gerepilecopy(av, y); if (valp(y) < 0) pari_err_DOMAIN("sin","valuation", "<", gen_0, x); gsincos(y,&u,&v,prec); return gerepilecopy(av,u); } return trans_eval("sin",gsin,x,prec); } /********************************************************************/ /** SINE, COSINE together **/ /********************************************************************/ void mpsincos(GEN x, GEN *s, GEN *c) { long mod8; pari_sp av, tetpil; GEN p1, *gptr[2]; if (!signe(x)) { long e = expo(x); *s = real_0_bit(e); *c = e >= 0? real_0_bit(e): real_1_bit(-e); return; } av=avma; p1=mpcosm1(x,&mod8); tetpil=avma; switch(mod8) { case 0: *c=addsr( 1,p1); *s=mpaut(p1); break; case 1: *s=addsr( 1,p1); *c=mpaut(p1); togglesign(*c); break; case 2: *c=subsr(-1,p1); *s=mpaut(p1); togglesign(*s); break; case 3: *s=subsr(-1,p1); *c=mpaut(p1); break; case 4: *c=addsr( 1,p1); *s=mpaut(p1); togglesign(*s); break; case 5: *s=addsr( 1,p1); *c=mpaut(p1); break; case 6: *c=subsr(-1,p1); *s=mpaut(p1); break; case 7: *s=subsr(-1,p1); *c=mpaut(p1); togglesign(*c); break; } gptr[0]=s; gptr[1]=c; gerepilemanysp(av,tetpil,gptr,2); } /* SINE and COSINE - 1 */ void mpsincosm1(GEN x, GEN *s, GEN *c) { long mod8; pari_sp av, tetpil; GEN p1, *gptr[2]; if (!signe(x)) { long e = expo(x); *s = real_0_bit(e); *c = real_0_bit(2*e-1); return; } av=avma; p1=mpcosm1(x,&mod8); tetpil=avma; switch(mod8) { case 0: *c=rcopy(p1); *s=mpaut(p1); break; case 1: *s=addsr(1,p1); *c=addrs(mpaut(p1),1); togglesign(*c); break; case 2: *c=subsr(-2,p1); *s=mpaut(p1); togglesign(*s); break; case 3: *s=subsr(-1,p1); *c=subrs(mpaut(p1),1); break; case 4: *c=rcopy(p1); *s=mpaut(p1); togglesign(*s); break; case 5: *s=addsr( 1,p1); *c=subrs(mpaut(p1),1); break; case 6: *c=subsr(-2,p1); *s=mpaut(p1); break; case 7: *s=subsr(-1,p1); *c=subsr(-1,mpaut(p1)); break; } gptr[0]=s; gptr[1]=c; gerepilemanysp(av,tetpil,gptr,2); } /* return exp(ix), x a t_REAL */ GEN expIr(GEN x) { pari_sp av = avma; GEN v = cgetg(3,t_COMPLEX); mpsincos(x, (GEN*)(v+2), (GEN*)(v+1)); if (!signe(gel(v,2))) return gerepilecopy(av, gel(v,1)); return v; } /* return exp(ix)-1, x a t_REAL */ static GEN expm1_Ir(GEN x) { pari_sp av = avma; GEN v = cgetg(3,t_COMPLEX); mpsincosm1(x, (GEN*)(v+2), (GEN*)(v+1)); if (!signe(gel(v,2))) return gerepilecopy(av, gel(v,1)); return v; } /* return exp(z)-1, z complex */ GEN cxexpm1(GEN z, long prec) { pari_sp av = avma; GEN X, Y, x = real_i(z), y = imag_i(z); long l = precision(z); if (l) prec = l; if (typ(x) != t_REAL) x = gtofp(x, prec); if (typ(y) != t_REAL) y = gtofp(y, prec); if (gequal0(y)) return mpexpm1(x); if (gequal0(x)) return expm1_Ir(y); X = mpexpm1(x); /* t_REAL */ Y = expm1_Ir(y); /* exp(x+iy) - 1 = (exp(x)-1)(exp(iy)-1) + exp(x)-1 + exp(iy)-1 */ return gerepileupto(av, gadd(gadd(X,Y), gmul(X,Y))); } void gsincos(GEN x, GEN *s, GEN *c, long prec) { long i, j, ex, ex2, lx, ly, mi; pari_sp av, tetpil; GEN y, r, u, v, u1, v1, p1, p2, p3, p4, ps, pc; GEN *gptr[4]; switch(typ(x)) { case t_INT: case t_FRAC: *s = cgetr(prec); *c = cgetr(prec); av = avma; mpsincos(tofp_safe(x, prec), &ps, &pc); affrr_fixlg(ps,*s); affrr_fixlg(pc,*c); avma = av; return; case t_REAL: mpsincos(x,s,c); return; case t_COMPLEX: i = precision(x); if (i) prec = i; ps = cgetc(prec); *s = ps; pc = cgetc(prec); *c = pc; av = avma; r = gexp(gel(x,2),prec); v1 = gmul2n(addrr(invr(r),r), -1); /* = cos(I*Im(x)) */ u1 = subrr(r, v1); /* = I*sin(I*Im(x)) */ gsincos(gel(x,1), &u,&v, prec); affrr_fixlg(mulrr(v1,u), gel(ps,1)); affrr_fixlg(mulrr(u1,v), gel(ps,2)); affrr_fixlg(mulrr(v1,v), gel(pc,1)); affrr_fixlg(mulrr(u1,u), gel(pc,2)); togglesign(gel(pc,2)); avma = av; return; case t_QUAD: av = avma; gsincos(quadtofp(x, prec), s, c, prec); gerepileall(av, 2, s, c); return; default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) { *s = gerepilecopy(av,y); *c = gaddsg(1,*s); return; } ex = valp(y); lx = lg(y); ex2 = 2*ex+2; if (ex < 0) pari_err_DOMAIN("gsincos","valuation", "<", gen_0, x); if (ex2 > lx) { *s = x == y? gcopy(y): gerepilecopy(av, y); av = avma; *c = gerepileupto(av, gsubsg(1, gdivgs(gsqr(y),2))); return; } if (!ex) { gsincos(serchop0(y),&u,&v,prec); gsincos(gel(y,2),&u1,&v1,prec); p1 = gmul(v1,v); p2 = gmul(u1,u); p3 = gmul(v1,u); p4 = gmul(u1,v); tetpil = avma; *c = gsub(p1,p2); *s = gadd(p3,p4); gptr[0]=s; gptr[1]=c; gerepilemanysp(av,tetpil,gptr,2); return; } ly = lx+2*ex; mi = lx-1; while (mi>=3 && isrationalzero(gel(y,mi))) mi--; mi += ex-2; pc = cgetg(ly,t_SER); *c = pc; ps = cgetg(lx,t_SER); *s = ps; pc[1] = evalsigne(1) | _evalvalp(0) | evalvarn(varn(y)); gel(pc,2) = gen_1; ps[1] = y[1]; for (i=2; i 2) gel(y,2) = gen_1; return y; } else { GEN z0, y0 = gel(y,2), y1 = serchop0(y), y10 = y1; if (!gequal1(y0)) y10 = gdiv(y10, y0); gsincos(y1,&u,&v,prec); z0 = gdiv(gcos(y0,prec), y0); y = gaddsg(1, y10); u = gadd(gmul(gsinc(y0, prec),v), gmul(z0, u)); return gerepileupto(av,gdiv(u,y)); } } } return trans_eval("sinc",gsinc,x,prec); } /********************************************************************/ /** **/ /** TANGENT and COTANGENT **/ /** **/ /********************************************************************/ static GEN mptan(GEN x) { pari_sp av = avma; GEN s, c; mpsincos(x,&s,&c); if (!signe(c)) pari_err_DOMAIN("tan", "argument", "=", strtoGENstr("Pi/2 + kPi"),x); return gerepileuptoleaf(av, divrr(s,c)); } GEN gtan(GEN x, long prec) { pari_sp av; GEN y, s, c; switch(typ(x)) { case t_REAL: return mptan(x); case t_COMPLEX: { if (isintzero(gel(x,1))) retmkcomplex(gen_0,gtanh(gel(x,2),prec)); av = avma; y = mulcxmI(gtanh(mulcxI(x), prec)); /* tan x = -I th(I x) */ gel(y,1) = gcopy(gel(y,1)); return gerepileupto(av, y); } case t_INT: case t_FRAC: y = cgetr(prec); av = avma; affrr_fixlg(mptan(tofp_safe(x,prec)), y); avma = av; return y; case t_PADIC: av = avma; return gerepileupto(av, gdiv(gsin(x,prec), gcos(x,prec))); default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) return gerepilecopy(av, y); if (valp(y) < 0) pari_err_DOMAIN("tan","valuation", "<", gen_0, x); gsincos(y,&s,&c,prec); return gerepileupto(av, gdiv(s,c)); } return trans_eval("tan",gtan,x,prec); } static GEN mpcotan(GEN x) { pari_sp av=avma, tetpil; GEN s,c; mpsincos(x,&s,&c); tetpil=avma; return gerepile(av,tetpil,divrr(c,s)); } GEN gcotan(GEN x, long prec) { pari_sp av; GEN y, s, c; switch(typ(x)) { case t_REAL: return mpcotan(x); case t_COMPLEX: if (isintzero(gel(x,1))) { GEN z = cgetg(3, t_COMPLEX); gel(z,1) = gen_0; av = avma; gel(z,2) = gerepileupto(av, gneg(ginv(gtanh(gel(x,2),prec)))); return z; } av = avma; gsincos(x,&s,&c,prec); return gerepileupto(av, gdiv(c,s)); case t_INT: case t_FRAC: y = cgetr(prec); av = avma; affrr_fixlg(mpcotan(tofp_safe(x,prec)), y); avma = av; return y; case t_PADIC: av = avma; return gerepileupto(av, gdiv(gcos(x,prec), gsin(x,prec))); default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) pari_err_DOMAIN("cotan", "argument", "=", gen_0, y); if (valp(y) < 0) pari_err_DOMAIN("cotan","valuation", "<", gen_0, x); gsincos(y,&s,&c,prec); return gerepileupto(av, gdiv(c,s)); } return trans_eval("cotan",gcotan,x,prec); } pari-2.11.2/src/basemath/buch4.c0000644000175000017500000005716213326135265014723 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* S-CLASS GROUP AND NORM SYMBOLS */ /* (Denis Simon, desimon@math.u-bordeaux.fr) */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" /* p > 2, T ZX, p prime, x t_INT */ static long lemma6(GEN T, GEN p, long nu, GEN x) { long la, mu; pari_sp av = avma; GEN gpx, gx = poleval(T, x); if (Zp_issquare(gx, p)) { avma = av; return 1; } la = Z_pval(gx, p); gpx = poleval(ZX_deriv(T), x); mu = signe(gpx)? Z_pval(gpx,p) : la+nu+1; /* mu = +oo */ avma = av; if (la > mu<<1) return 1; if (la >= nu<<1 && mu >= nu) return 0; return -1; } /* p = 2, T ZX, x t_INT: return 1 = yes, -1 = no, 0 = inconclusive */ static long lemma7(GEN T, long nu, GEN x) { long odd4, la, mu; pari_sp av = avma; GEN gpx, oddgx, gx = poleval(T, x); if (Zp_issquare(gx,gen_2)) return 1; gpx = poleval(ZX_deriv(T), x); la = Z_lvalrem(gx, 2, &oddgx); odd4 = umodiu(oddgx,4); avma = av; mu = vali(gpx); if (mu < 0) mu = la+nu+1; /* mu = +oo */ if (la > mu<<1) return 1; if (nu > mu) { long mnl = mu+nu-la; if (odd(la)) return -1; if (mnl==1) return 1; if (mnl==2 && odd4==1) return 1; } else { long nu2 = nu << 1; if (la >= nu2) return 0; if (la == nu2 - 2 && odd4==1) return 0; } return -1; } /* T a ZX, p a prime, pnu = p^nu, x0 t_INT */ static long zpsol(GEN T, GEN p, long nu, GEN pnu, GEN x0) { long i, res; pari_sp av = avma, btop; GEN x, pnup; res = absequaliu(p,2)? lemma7(T,nu,x0): lemma6(T,p,nu,x0); if (res== 1) return 1; if (res==-1) return 0; x = x0; pnup = mulii(pnu,p); btop = avma; for (i=0; i < itos(p); i++) { x = addii(x,pnu); if (zpsol(T,p,nu+1,pnup,x)) { avma = av; return 1; } if (gc_needed(btop, 2)) { x = gerepileupto(btop, x); if (DEBUGMEM > 1) pari_warn(warnmem, "zpsol: %ld/%Ps",i,p); } } avma = av; return 0; } /* return 1 if equation y^2=T(x) has a rational p-adic solution (possibly * infinite), 0 otherwise. */ long hyperell_locally_soluble(GEN T,GEN p) { pari_sp av = avma; long res; if (typ(T)!=t_POL) pari_err_TYPE("zpsoluble",T); if (typ(p)!=t_INT) pari_err_TYPE("zpsoluble",p); RgX_check_ZX(T, "zpsoluble"); res = zpsol(T,p,0,gen_1,gen_0) || zpsol(RgX_recip_shallow(T), p, 1, p, gen_0); avma = av; return res; } /* is t a square in (O_K/pr) ? Assume v_pr(t) = 0 */ static long quad_char(GEN nf, GEN t, GEN pr) { GEN ord, ordp, T, p, modpr = zk_to_Fq_init(nf, &pr,&T,&p); t = nf_to_Fq(nf,t,modpr); if (T) { ord = subiu( pr_norm(pr), 1 ); /* |(O_K / pr)^*| */ ordp= subiu( p, 1); /* |F_p^*| */ t = Fq_pow(t, diviiexact(ord, ordp), T,p); /* in F_p^* */ if (typ(t) == t_POL) { if (degpol(t)) pari_err_BUG("nfhilbertp"); t = gel(t,2); } } return kronecker(t, p); } /* quad_char(x), x in Z, non-zero mod p */ static long Z_quad_char(GEN x, GEN pr) { long f = pr_get_f(pr); if (!odd(f)) return 1; return kronecker(x, pr_get_p(pr)); } /* (pr,2) = 1. return 1 if x in Z_K is a square in Z_{K_pr}, 0 otherwise. * modpr = zkmodprinit(nf,pr) */ static long psquarenf(GEN nf,GEN x,GEN pr,GEN modpr) { pari_sp av = avma; GEN p = pr_get_p(pr); long v; x = nf_to_scalar_or_basis(nf, x); if (typ(x) == t_INT) { if (!signe(x)) return 1; v = Z_pvalrem(x, p, &x) * pr_get_e(pr); if (v&1) return 0; v = (Z_quad_char(x, pr) == 1); } else { v = ZC_nfvalrem(x, pr, &x); if (v&1) return 0; v = (quad_char(nf, x, modpr) == 1); } avma = av; return v; } /* Is x a square in (ZK / pr^(1+2e))^* ? pr | 2 */ static long check2(GEN nf, GEN x, GEN sprk) { GEN zlog = zlog_pr(nf, x, sprk); long i, l = lg(zlog); for (i=1; i 1) */ if (mpodd(gel(zlog,i))) return 0; return 1; } /* pr | 2. Return 1 if x in Z_K is square in Z_{K_pr}, 0 otherwise */ static int psquare2nf_i(GEN nf,GEN x,GEN pr,GEN sprk) { long v = nfvalrem(nf, x, pr, &x); /* now (x,pr) = 1 */ return v == LONG_MAX || (!odd(v) && check2(nf,x,sprk)); } static int psquare2nf(GEN nf,GEN x,GEN pr,GEN sprk) { pari_sp av = avma; long v = psquare2nf_i(nf,x,pr,sprk); avma = av; return v; } /* pr above an odd prime */ static long lemma6nf(GEN nf, GEN T, GEN pr, long nu, GEN x, GEN modpr) { pari_sp av = avma; long la, mu; GEN gpx, gx = nfpoleval(nf, T, x); if (psquarenf(nf,gx,pr,modpr)) return 1; la = nfval(nf,gx,pr); gpx = nfpoleval(nf, RgX_deriv(T), x); mu = gequal0(gpx)? la+nu+1: nfval(nf,gpx,pr); avma = av; if (la > (mu<<1)) return 1; if (la >= (nu<<1) && mu >= nu) return 0; return -1; } /* pr above 2 */ static long lemma7nf(GEN nf, GEN T, GEN pr, long nu, GEN x, GEN sprk) { long res, la, mu, q; GEN gpx, gx = nfpoleval(nf, T, x); if (psquare2nf(nf,gx,pr,sprk)) return 1; gpx = nfpoleval(nf, RgX_deriv(T), x); /* gx /= pi^la, pi a pr-uniformizer */ la = nfvalrem(nf, gx, pr, &gx); mu = gequal0(gpx)? la+nu+1: nfval(nf,gpx,pr); if (la > (mu<<1)) return 1; if (nu > mu) { if (la&1) return -1; q = mu+nu-la; res = 1; } else { long nu2 = nu<<1; if (la >= nu2) return 0; if (odd(la)) return -1; q = nu2-la; res = 0; } if (q > pr_get_e(pr)<<1) return -1; if (q == 1) return res; /* is gx a square mod pi^q ? FIXME : highly inefficient */ sprk = zlog_pr_init(nf, pr, q); if (!check2(nf, gx, sprk)) res = -1; return res; } /* zinit either a sprk (pr | 2) or a modpr structure (pr | p odd). pnu = pi^nu, pi a uniformizer */ static long zpsolnf(GEN nf,GEN T,GEN pr,long nu,GEN pnu,GEN x0,GEN repr,GEN zinit) { long i, res; pari_sp av = avma; GEN pnup; res = typ(zinit) == t_VEC? lemma7nf(nf,T,pr,nu,x0,zinit) : lemma6nf(nf,T,pr,nu,x0,zinit); avma = av; if (res== 1) return 1; if (res==-1) return 0; pnup = nfmul(nf, pnu, pr_get_gen(pr)); nu++; for (i=1; i3) err_printf("nfhilbert not soluble at real place %ld\n",i); avma = av; return -1; } /* local solutions in finite completions ? (pr | 2ab) * primes above 2 are toughest. Try the others first */ Sa = idealfactor(nf, a); Sb = idealfactor(nf, b); S2 = idealfactor(nf, gen_2); S = merge_factor(Sa, Sb, (void*)&cmp_prime_ideal, &cmp_nodata); S = merge_factor(S, S2, (void*)&cmp_prime_ideal, &cmp_nodata); S = gel(S,1); /* product of all hilbertp is 1 ==> remove one prime (above 2!) */ for (i=lg(S)-1; i>1; i--) if (nfhilbertp(nf,a,b,gel(S,i)) < 0) { if (DEBUGLEVEL>3) err_printf("nfhilbert not soluble at finite place %Ps\n",S[i]); avma = av; return -1; } avma = av; return 1; } long nfhilbert0(GEN nf,GEN a,GEN b,GEN p) { nf = checknf(nf); if (p) { checkprid(p); if (gequal0(a)) pari_err_DOMAIN("nfhilbert", "a", "=", gen_0, a); if (gequal0(b)) pari_err_DOMAIN("nfhilbert", "b", "=", gen_0, b); return nfhilbertp(nf,a,b,p); } return nfhilbert(nf,a,b); } /* S a list of prime ideal in idealprimedec format. Return res: * res[1] = generators of (S-units / units), as polynomials * res[2] = [perm, HB, den], for bnfissunit * res[3] = [] (was: log. embeddings of res[1]) * res[4] = S-regulator ( = R * det(res[2]) * \prod log(Norm(S[i]))) * res[5] = S class group * res[6] = S */ GEN bnfsunit0(GEN bnf, GEN S, long flag, long prec) { pari_sp av = avma; long i,j,ls; GEN p1,nf,gen,M,U,H; GEN sunit,card,sreg,res,pow; if (!is_vec_t(typ(S))) pari_err_TYPE("bnfsunit",S); bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); gen = bnf_get_gen(bnf); sreg = bnf_get_reg(bnf); res=cgetg(7,t_VEC); gel(res,1) = gel(res,2) = gel(res,3) = cgetg(1,t_VEC); gel(res,4) = sreg; gel(res,5) = bnf_get_clgp(bnf); gel(res,6) = S; ls=lg(S); /* M = relation matrix for the S class group (in terms of the class group * generators given by gen) * 1) ideals in S */ M = cgetg(ls,t_MAT); for (i=1; i 1) { /* non trivial (rare!) */ GEN A, u, D = ZM_snfall_i(H, &u, NULL, 1); long l; ZV_snf_trunc(D); l = lg(D); card = ZV_prod(D); A = cgetg(l, t_VEC); pow = ZM_inv(u, NULL); for(i = 1; i < l; i++) gel(A,i) = idealfactorback(nf, gen, gel(pow,i), 1); gel(res,5) = mkvec3(card, D, A); } /* S-units */ if (ls>1) { GEN den, Sperm, perm, dep, B, A, U1 = U; long lH, lB, FLAG = flag|nf_FORCE; /* U1 = upper left corner of U, invertible. S * U1 = principal ideals * whose generators generate the S-units */ setlg(U1,ls); p1 = cgetg(ls, t_MAT); /* p1 is junk for mathnfspec */ for (i=1; i 1 && lgcols(dep) > 1) pari_err_BUG("bnfsunit"); /* [ H B ] [ H^-1 - H^-1 B ] * perm o HNF(U1) = [ 0 Id ], inverse = [ 0 Id ] * (permute the rows) * S * HNF(U1) = _integral_ generators for S-units = sunit */ Sperm = cgetg(ls, t_VEC); sunit = cgetg(ls, t_VEC); for (i=1; ihash(p); hashentry *e = hash_search2(H, (void*)p, h); if (!e) { hash_insert2(H, (void*)p, NULL, h); if (H2) hash_insert2(H2, (void*)p, NULL, h); } } /* N a t_INT */ static void Zfa_append(GEN N, hashtable *H, hashtable *H2) { if (!is_pm1(N)) { GEN v = gel(absZ_factor(N),1); long i, l = lg(v); for (i=1; i 2) pari_err_FLAG("rnfisnorminit"); T = get_bnfpol(T, &bnf, &nf); if (!bnf) bnf = Buchall(nf? nf: T, nf_FORCE, DEFAULTPREC); if (!nf) nf = bnf_get_nf(bnf); relpol = get_bnfpol(relpol, &bnfabs, &nfabs); if (!gequal1(leading_coeff(relpol))) pari_err_IMPL("non monic relative equation"); drel = degpol(relpol); if (drel <= 2) galois = 1; relpol = RgX_nffix("rnfisnorminit", T, relpol, 1); if (nf_get_degree(nf) == 1) /* over Q */ rnfeq = mkvec5(relpol,gen_0,gen_0,T,relpol); else if (galois == 2) /* needs eltup+abstorel */ rnfeq = nf_rnfeq(nf, relpol); else /* needs abstorel */ rnfeq = nf_rnfeqsimple(nf, relpol); polabs = gel(rnfeq,1); k = gel(rnfeq,3); if (!bnfabs || !gequal0(k)) bnfabs = Buchall(polabs, nf_FORCE, nf_get_prec(nf)); if (!nfabs) nfabs = bnf_get_nf(bnfabs); if (galois == 2) { GEN P = polabs==relpol? leafcopy(relpol): nfX_eltup(nf, rnfeq, relpol); setvarn(P, fetch_var_higher()); galois = !!nfroots_if_split(&nfabs, P); (void)delete_var(); } cyc = bnf_get_cyc(bnfabs); gen = bnf_get_gen(bnfabs); l = lg(cyc); for(i=1; i answer is unconditional) * if flag>0 add to S all primes dividing p <= flag * if flag<0 add to S all primes dividing abs(flag) * answer is a vector v = [a,b] such that * x = N(a)*b and x is a norm iff b = 1 [assuming S large enough] */ GEN rnfisnorm(GEN T, GEN x, long flag) { pari_sp av = avma; GEN bnf, rel, relpol, rnfeq, nfpol; GEN nf, aux, H, U, Y, M, A, bnfS, sunitrel, futu, S, S1, S2, Sx; long L, i, drel, itu; hashtable *H0, *H2; if (typ(T) != t_VEC || lg(T) != 9) pari_err_TYPE("rnfisnorm [please apply rnfisnorminit()]", T); bnf = gel(T,1); rel = gel(T,2); bnf = checkbnf(bnf); rel = checkbnf(rel); nf = bnf_get_nf(bnf); x = nf_to_scalar_or_alg(nf,x); if (gequal0(x)) { avma = av; return mkvec2(gen_0, gen_1); } if (gequal1(x)) { avma = av; return mkvec2(gen_1, gen_1); } relpol = gel(T,3); rnfeq = gel(T,4); drel = degpol(relpol); if (gequalm1(x) && odd(drel)) { avma = av; return mkvec2(gen_m1, gen_1); } /* build set T of ideals involved in the solutions */ nfpol = nf_get_pol(nf); S = gel(T,5); H0 = hash_create_INT(100UL); H2 = hash_create_INT(100UL); L = lg(S); for (i = 1; i < L; i++) p_append(gel(S,i),H0,NULL); S1 = gel(T,6); S2 = gel(T,7); if (flag && !gequal0(gel(T,8))) pari_warn(warner,"useless flag in rnfisnorm: the extension is Galois"); if (flag > 0) { forprime_t T; ulong p; u_forprime_init(&T, 2, flag); while ((p = u_forprime_next(&T))) p_append(utoipos(p), H0,H2); } else if (flag < 0) Zfa_append(utoipos(-flag),H0,H2); /* overkill: prime ideals dividing x would be enough */ A = idealnumden(nf, x); fa_append(gel(A,1), H0,H2); fa_append(gel(A,2), H0,H2); Sx = hash_keys(H2); L = lg(Sx); if (L > 1) { /* new primes */ settyp(Sx, t_VEC); S1 = shallowconcat(S1, nf_pV_to_prV(nf, Sx)); S2 = shallowconcat(S2, nf_pV_to_prV(rel, Sx)); } /* computation on T-units */ futu = shallowconcat(bnf_get_fu(rel), bnf_get_tuU(rel)); bnfS = bnfsunit(bnf,S1,LOWDEFAULTPREC); sunitrel = shallowconcat(futu, gel(bnfsunit(rel,S2,LOWDEFAULTPREC), 1)); A = lift_shallow(bnfissunit(bnf,bnfS,x)); L = lg(sunitrel); itu = lg(nf_get_roots(nf))-1; /* index of torsion unit in bnfsunit(nf) output */ M = cgetg(L+1,t_MAT); for (i=1; in = a; pbits = nbits = 0; for (i = 0; a; a >>= 1, ++i) { a0 = a & 1; c1 = (c0 + a0 + ((a & 2) >> 1)) >> 1; t = c0 + a0 - (c1 << 1); if (t < 0) nbits |= (1UL << i); else if (t > 0) pbits |= (1UL << i); c0 = c1; } c1 = c0 >> 1; t = c0 - (c1 << 1); /* Note that we don't need to check whether t < 0, since a >= 0 implies * that this most significant signed bit must be non-negative. */ if (t > 0 && i != BITS_IN_LONG) pbits |= (1UL << i); x->pbits = pbits; x->nbits = nbits; /* Note that expu returns the least nonzero bit in the argument, * like the bit-scan-rev instruction on Intel architectures. */ /* Using pbits here is justified by the fact that a >= 0, so the * most significant bit must be positive. */ x->lnzb = t? i-2: i-3; } /* Standard left-to-right signed double-and-add to compute [n]P. */ static GEN Flj_mulu_pre_naf(GEN P, ulong n, ulong a4, ulong p, ulong pi, const naf_t *x) { GEN R, Pinv; ulong pbits, nbits, lnzb; ulong m; if (n == 0) return mkvecsmall3(1, 1, 0); if (n == 1) return Flv_copy(P); R = Flj_dbl_pre(P, a4, p, pi); if (n == 2) return R; pbits = x->pbits; nbits = x->nbits; lnzb = x->lnzb; Pinv = Flj_neg(P, p); m = (1UL << lnzb); for ( ; m; m >>= 1) { Flj_dbl_pre_inplace(R, a4, p, pi); if (m & pbits) Flj_add_pre_inplace(R, P, a4, p, pi); else if (m & nbits) Flj_add_pre_inplace(R, Pinv, a4, p, pi); } avma = (pari_sp)R; return R; } GEN Flj_mulu_pre(GEN P, ulong n, ulong a4, ulong p, ulong pi) { naf_t x; naf_repr(&x, n); return Flj_mulu_pre_naf(P, n, a4, p, pi, &x); } ulong Flj_order_ufact(GEN P, ulong n, GEN F, ulong a4, ulong p, ulong pi) { pari_sp av = avma; ulong res = 1; long i, nfactors; GEN primes, exps; primes = gel(F, 1); nfactors = lg(primes); exps = gel(F, 2); for (i = 1; i < nfactors; ++i) { ulong q, pp = primes[i]; long j, k, ei = exps[i]; naf_t x; GEN b; for (q = pp, j = 1; j < ei; ++j) q *= pp; b = Flj_mulu_pre(P, n / q, a4, p, pi); naf_repr(&x, pp); for (j = 0; j < ei && b[3] != 0; ++j) b = Flj_mulu_pre_naf(b, pp, a4, p, pi, &x); if (b[3] != 0) return 0; for (k = 0; k < j; ++k) res *= pp; avma = av; } return res; } GEN Fle_to_Flj(GEN P) { return ell_is_inf(P) ? mkvecsmall3(1UL, 1UL, 0UL): mkvecsmall3(P[1], P[2], 1UL); } GEN Flj_to_Fle_pre(GEN P, ulong p, ulong pi) { if (P[3] == 0) return ellinf(); else { ulong Z = Fl_inv(P[3], p); ulong Z2 = Fl_sqr_pre(Z, p, pi); ulong X3 = Fl_mul_pre(P[1], Z2, p, pi); ulong Y3 = Fl_mul_pre(P[2], Fl_mul_pre(Z, Z2, p, pi), p, pi); return mkvecsmall2(X3, Y3); } } INLINE void random_Fle_pre_indir(ulong a4, ulong a6, ulong p, ulong pi, ulong *pt_x, ulong *pt_y) { ulong x, x2, y, rhs; do { x = random_Fl(p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */ x2 = Fl_sqr_pre(x, p, pi); rhs = Fl_addmul_pre(a6, x, Fl_add(x2, a4, p), p, pi); } while ((!rhs && !Fl_add(Fl_triple(x2,p),a4,p)) || krouu(rhs, p) < 0); y = Fl_sqrt_pre(rhs, p, pi); *pt_x = x; *pt_y = y; } GEN random_Flj_pre(ulong a4, ulong a6, ulong p, ulong pi) { ulong x, y; random_Fle_pre_indir(a4, a6, p, pi, &x, &y); return mkvecsmall3(x, y, 1); } /***********************************************************************/ /** **/ /** Fle **/ /** **/ /***********************************************************************/ GEN Fle_changepoint(GEN x, GEN ch, ulong p) { ulong p1,u,r,s,t,v,v2,v3; GEN z; if (ell_is_inf(x)) return x; u = ch[1]; r = ch[2]; s = ch[3]; t = ch[4]; v = Fl_inv(u, p); v2 = Fl_sqr(v,p); v3 = Fl_mul(v,v2,p); p1 = Fl_sub(x[1],r,p); z = cgetg(3,t_VECSMALL); z[1] = Fl_mul(v2, p1, p); z[2] = Fl_mul(v3, Fl_sub(x[2], Fl_add(Fl_mul(s,p1, p),t, p),p),p); return z; } GEN Fle_changepointinv(GEN x, GEN ch, ulong p) { ulong u, r, s, t, X, Y, u2, u3, u2X; GEN z; if (ell_is_inf(x)) return x; X = x[1]; Y = x[2]; u = ch[1]; r = ch[2]; s = ch[3]; t = ch[4]; u2 = Fl_sqr(u, p); u3 = Fl_mul(u,u2,p); u2X = Fl_mul(u2,X, p); z = cgetg(3, t_VECSMALL); z[1] = Fl_add(u2X,r,p); z[2] = Fl_add(Fl_mul(u3,Y,p), Fl_add(Fl_mul(s,u2X,p), t, p), p); return z; } static GEN Fle_dbl_slope(GEN P, ulong a4, ulong p, ulong *slope) { ulong x, y, Qx, Qy; if (ell_is_inf(P) || !P[2]) return ellinf(); x = P[1]; y = P[2]; *slope = Fl_div(Fl_add(Fl_triple(Fl_sqr(x,p), p), a4, p), Fl_double(y, p), p); Qx = Fl_sub(Fl_sqr(*slope, p), Fl_double(x, p), p); Qy = Fl_sub(Fl_mul(*slope, Fl_sub(x, Qx, p), p), y, p); return mkvecsmall2(Qx, Qy); } GEN Fle_dbl(GEN P, ulong a4, ulong p) { ulong slope; return Fle_dbl_slope(P,a4,p,&slope); } static GEN Fle_add_slope(GEN P, GEN Q, ulong a4, ulong p, ulong *slope) { ulong Px, Py, Qx, Qy, Rx, Ry; if (ell_is_inf(P)) return Q; if (ell_is_inf(Q)) return P; Px = P[1]; Py = P[2]; Qx = Q[1]; Qy = Q[2]; if (Px==Qx) return Py==Qy ? Fle_dbl_slope(P, a4, p, slope): ellinf(); *slope = Fl_div(Fl_sub(Py, Qy, p), Fl_sub(Px, Qx, p), p); Rx = Fl_sub(Fl_sub(Fl_sqr(*slope, p), Px, p), Qx, p); Ry = Fl_sub(Fl_mul(*slope, Fl_sub(Px, Rx, p), p), Py, p); return mkvecsmall2(Rx, Ry); } GEN Fle_add(GEN P, GEN Q, ulong a4, ulong p) { ulong slope; return Fle_add_slope(P,Q,a4,p,&slope); } static GEN Fle_neg(GEN P, ulong p) { if (ell_is_inf(P)) return P; return mkvecsmall2(P[1], Fl_neg(P[2], p)); } GEN Fle_sub(GEN P, GEN Q, ulong a4, ulong p) { pari_sp av = avma; ulong slope; return gerepileupto(av, Fle_add_slope(P, Fle_neg(Q, p), a4, p, &slope)); } struct _Fle { ulong a4, a6, p; }; static GEN _Fle_dbl(void *E, GEN P) { struct _Fle *ell = (struct _Fle *) E; return Fle_dbl(P, ell->a4, ell->p); } static GEN _Fle_add(void *E, GEN P, GEN Q) { struct _Fle *ell=(struct _Fle *) E; return Fle_add(P, Q, ell->a4, ell->p); } GEN Fle_mulu(GEN P, ulong n, ulong a4, ulong p) { ulong pi; if (!n || ell_is_inf(P)) return ellinf(); if (n==1) return zv_copy(P); if (n==2) return Fle_dbl(P, a4, p); pi = get_Fl_red(p); return Flj_to_Fle_pre(Flj_mulu_pre(Fle_to_Flj(P), n, a4, p, pi), p, pi); } static GEN _Fle_mul(void *E, GEN P, GEN n) { pari_sp av = avma; struct _Fle *e=(struct _Fle *) E; long s = signe(n); GEN Q; if (!s || ell_is_inf(P)) return ellinf(); if (s < 0) P = Fle_neg(P, e->p); if (is_pm1(n)) return s > 0? zv_copy(P): P; Q = (lgefint(n)==3) ? Fle_mulu(P, uel(n,2), e->a4, e->p): gen_pow(P, n, (void*)e, &_Fle_dbl, &_Fle_add); return s > 0? Q: gerepileuptoleaf(av, Q); } GEN Fle_mul(GEN P, GEN n, ulong a4, ulong p) { struct _Fle E; E.a4 = a4; E.p = p; return _Fle_mul(&E, P, n); } /* Finds a random non-singular point on E */ GEN random_Fle_pre(ulong a4, ulong a6, ulong p, ulong pi) { ulong x, y; random_Fle_pre_indir(a4, a6, p, pi, &x, &y); return mkvecsmall2(x, y); } GEN random_Fle(ulong a4, ulong a6, ulong p) { return random_Fle_pre(a4, a6, p, get_Fl_red(p)); } static GEN _Fle_rand(void *E) { struct _Fle *e=(struct _Fle *) E; return random_Fle(e->a4, e->a6, e->p); } static const struct bb_group Fle_group={_Fle_add,_Fle_mul,_Fle_rand,hash_GEN,zv_equal,ell_is_inf,NULL}; GEN Fle_order(GEN z, GEN o, ulong a4, ulong p) { pari_sp av = avma; struct _Fle e; e.a4=a4; e.p=p; return gerepileuptoint(av, gen_order(z, o, (void*)&e, &Fle_group)); } GEN Fle_log(GEN a, GEN b, GEN o, ulong a4, ulong p) { pari_sp av = avma; struct _Fle e; e.a4=a4; e.p=p; return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &Fle_group)); } ulong Fl_ellj(ulong a4, ulong a6, ulong p) { if (SMALL_ULONG(p)) { /* a43 = 4 a4^3 */ ulong a43 = Fl_double(Fl_double(Fl_mul(a4, Fl_sqr(a4, p), p), p), p); /* a62 = 27 a6^2 */ ulong a62 = Fl_mul(Fl_sqr(a6, p), 27 % p, p); ulong z1 = Fl_mul(a43, 1728 % p, p); ulong z2 = Fl_add(a43, a62, p); return Fl_div(z1, z2, p); } return Fl_ellj_pre(a4, a6, p, get_Fl_red(p)); } void Fl_ellj_to_a4a6(ulong j, ulong p, ulong *pt_a4, ulong *pt_a6) { ulong zagier = 1728 % p; if (j == 0) { *pt_a4 = 0; *pt_a6 =1; } else if (j == zagier) { *pt_a4 = 1; *pt_a6 =0; } else { ulong k = Fl_sub(zagier, j, p); ulong kj = Fl_mul(k, j, p); ulong k2j = Fl_mul(kj, k, p); *pt_a4 = Fl_triple(kj, p); *pt_a6 = Fl_double(k2j, p); } } ulong Fl_elldisc_pre(ulong a4, ulong a6, ulong p, ulong pi) { /* D = -(4A^3 + 27B^2) */ ulong t1, t2; t1 = Fl_mul_pre(a4, Fl_sqr_pre(a4, p, pi), p, pi); t1 = Fl_double(Fl_double(t1, p), p); t2 = Fl_mul_pre(27 % p, Fl_sqr_pre(a6, p, pi), p, pi); return Fl_neg(Fl_add(t1, t2, p), p); } ulong Fl_elldisc(ulong a4, ulong a6, ulong p) { if (SMALL_ULONG(p)) { /* D = -(4A^3 + 27B^2) */ ulong t1, t2; t1 = Fl_mul(a4, Fl_sqr(a4, p), p); t1 = Fl_double(Fl_double(t1, p), p); t2 = Fl_mul(27 % p, Fl_sqr(a6, p), p); return Fl_neg(Fl_add(t1, t2, p), p); } return Fl_elldisc_pre(a4, a6, p, get_Fl_red(p)); } static ulong nonsquare_Fl(ulong p) { ulong a; do a = random_Fl(p); while (krouu(a, p) >= 0); return a; } void Fl_elltwist_disc(ulong a4, ulong a6, ulong D, ulong p, ulong *pa4, ulong *pa6) { ulong D2 = Fl_sqr(D, p); *pa4 = Fl_mul(a4, D2, p); *pa6 = Fl_mul(a6, Fl_mul(D, D2, p), p); } void Fl_elltwist(ulong a4, ulong a6, ulong p, ulong *pt_a4, ulong *pt_a6) { Fl_elltwist_disc(a4, a6, nonsquare_Fl(p), p, pt_a4, pt_a6); } static void Fle_dbl_sinv_pre_inplace(GEN P, ulong a4, ulong sinv, ulong p, ulong pi) { ulong x, y, slope; if (uel(P,1)==p) return; if (!P[2]) { P[1] = p; return; } x = P[1]; y = P[2]; slope = Fl_mul_pre(Fl_add(Fl_triple(Fl_sqr_pre(x, p, pi), p), a4, p), sinv, p, pi); P[1] = Fl_sub(Fl_sqr_pre(slope, p, pi), Fl_double(x, p), p); P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(x, P[1], p), p, pi), y, p); } static void Fle_add_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi) { ulong Px, Py, Qx, Qy, slope; if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Q[2]; } if (ell_is_inf(Q)) return; Px = P[1]; Py = P[2]; Qx = Q[1]; Qy = Q[2]; if (Px==Qx) { if (Py==Qy) Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi); else P[1] = p; return; } slope = Fl_mul_pre(Fl_sub(Py, Qy, p), sinv, p, pi); P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p); P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p); } static void Fle_sub_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi) { ulong Px, Py, Qx, Qy, slope; if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Fl_neg(Q[2], p); } if (ell_is_inf(Q)) return; Px = P[1]; Py = P[2]; Qx = Q[1]; Qy = Q[2]; if (Px==Qx) { if (Py==Qy) P[1] = p; else Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi); return; } slope = Fl_mul_pre(Fl_add(Py, Qy, p), sinv, p, pi); P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p); P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p); } static long skipzero(long n) { return n ? n:1; } void FleV_add_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi) { long i, l=lg(a4); GEN sinv = cgetg(l, t_VECSMALL); for(i=1; ipbits; nbits = x->nbits; lnzb = x->lnzb; m = (1UL << lnzb); for ( ; m; m >>= 1) { FleV_dbl_pre_inplace(R, a4, p, pi); if (m & pbits) FleV_add_pre_inplace(R, P, a4, p, pi); else if (m & nbits) FleV_sub_pre_inplace(R, P, a4, p, pi); } avma = av; } void FleV_mulu_pre_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi) { naf_t x; naf_repr(&x, n); FleV_mulu_pre_naf_inplace(P, n, a4, p, pi, &x); } pari-2.11.2/src/basemath/buch1.c0000644000175000017500000007435113326135265014717 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* CLASS GROUP AND REGULATOR (McCURLEY, BUCHMANN) */ /* QUADRATIC FIELDS */ /* */ /*******************************************************************/ /* For largeprime() hashtable. Note that hashed pseudoprimes are odd (unless * 2 | index), hence the low order bit is not useful. So we hash * HASHBITS bits starting at bit 1, not bit 0 */ #define HASHBITS 10 static const long HASHT = 1L << HASHBITS; static long hash(long q) { return (q & ((1L << (HASHBITS+1)) - 1)) >> 1; } #undef HASHBITS /* See buch2.c: * B->subFB contains split p such that \prod p > sqrt(B->Disc) * B->powsubFB contains powers of forms in B->subFB */ #define RANDOM_BITS 4 static const long CBUCH = (1L< Cl (a > 0) */ static GEN qfr3_canon(GEN x, struct qfr_data *S) { GEN a = gel(x,1), c = gel(x,3); if (signe(a) < 0) { if (absequalii(a,c)) return qfr3_rho(x, S); setsigne(a, 1); setsigne(c,-1); } return x; } static GEN qfr3_canon_safe(GEN x, struct qfr_data *S) { GEN a = gel(x,1), c = gel(x,3); if (signe(a) < 0) { if (absequalii(a,c)) return qfr3_rho(x, S); gel(x,1) = negi(a); gel(x,3) = negi(c); } return x; } static GEN qfr5_canon(GEN x, struct qfr_data *S) { GEN a = gel(x,1), c = gel(x,3); if (signe(a) < 0) { if (absequalii(a,c)) return qfr5_rho(x, S); setsigne(a, 1); setsigne(c,-1); } return x; } static GEN QFR5_comp(GEN x,GEN y, struct qfr_data *S) { return qfr5_canon(qfr5_comp(x,y,S), S); } static GEN QFR3_comp(GEN x, GEN y, struct qfr_data *S) { return qfr3_canon(qfr3_comp(x,y,S), S); } /* compute rho^n(x) */ static GEN qfr5_rho_pow(GEN x, long n, struct qfr_data *S) { long i; pari_sp av = avma; for (i=1; i<=n; i++) { x = qfr5_rho(x,S); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"qfr5_rho_pow"); x = gerepilecopy(av, x); } } return gerepilecopy(av, x); } static GEN qfr5_pf(struct qfr_data *S, long p, long prec) { GEN y = primeform_u(S->D,p); return qfr5_canon(qfr5_red(qfr_to_qfr5(y,prec), S), S); } static GEN qfr3_pf(struct qfr_data *S, long p) { GEN y = primeform_u(S->D,p); return qfr3_canon(qfr3_red(y, S), S); } #define qfi_pf primeform_u /* Warning: ex[0] not set in general */ static GEN init_form(struct buch_quad *B, GEN ex, GEN (*comp)(GEN,GEN,struct qfr_data *S)) { long i, l = lg(B->powsubFB); GEN F = NULL; for (i=1; ipowsubFB,i,ex[i]); F = F? comp(F, t, B->QFR): t; } return F; } static GEN qfr5_factorback(struct buch_quad *B, GEN ex) { return init_form(B, ex, &QFR5_comp); } static GEN QFI_comp(GEN x, GEN y, struct qfr_data *S) { (void)S; return qficomp(x,y); } static GEN qfi_factorback(struct buch_quad *B, GEN ex) { return init_form(B, ex, &QFI_comp); } static GEN random_form(struct buch_quad *B, GEN ex, GEN (*comp)(GEN,GEN, struct qfr_data *S)) { long i, l = lg(ex); pari_sp av = avma; GEN F; for(;;) { for (i=1; i= LIMCMAX) pari_err_BUG("Buchmann's algorithm"); if (LIMC <= LIMCMAX/40) /* cbach <= 0.3 */ LIMC *= 2; else if (LIMCMAX < 60) /* \Delta_K <= 9 */ LIMC++; else LIMC += LIMCMAX / 60; /* cbach += 0.2 */ if (LIMC > LIMCMAX) LIMC = LIMCMAX; return LIMC; } /* Is |q| <= p ? */ static int isless_iu(GEN q, ulong p) { long l = lgefint(q); return l==2 || (l == 3 && uel(q,2) <= p); } static long factorquad(struct buch_quad *B, GEN f, long nFB, ulong limp) { ulong X; long i, lo = 0; GEN x = gel(f,1), FB = B->FB, P = B->primfact, E = B->exprimfact; for (i=1; lgefint(x) > 3; i++) { ulong p = uel(FB,i), r; GEN q = absdiviu_rem(x, p, &r); if (!r) { long k = 0; do { k++; x = q; q = absdiviu_rem(x, p, &r); } while (!r); lo++; P[lo] = p; E[lo] = k; } if (isless_iu(q,p)) { if (lgefint(x) == 3) { X = uel(x,2); goto END; } return 0; } if (i == nFB) return 0; } X = uel(x,2); if (X == 1) { P[0] = 0; return 1; } for (;; i++) { /* single precision affair, split for efficiency */ ulong p = uel(FB,i); ulong q = X / p, r = X % p; /* gcc makes a single div */ if (!r) { long k = 0; do { k++; X = q; q = X / p; r = X % p; } while (!r); lo++; P[lo] = p; E[lo] = k; } if (q <= p) break; if (i == nFB) return 0; } END: if (X > B->limhash) return 0; if (X != 1 && X <= limp) { if (B->badprim && ugcdui(X, B->badprim) > 1) return 0; lo++; P[lo] = X; E[lo] = 1; X = 1; } P[0] = lo; return X; } /* Check for a "large prime relation" involving q; q may not be prime */ static long * largeprime(struct buch_quad *B, long q, GEN ex, long np, long nrho) { const long hashv = hash(q); long *pt, i, l = lg(B->subFB); for (pt = B->hashtab[hashv]; ; pt = (long*) pt[0]) { if (!pt) { pt = (long*) pari_malloc((l+3) * sizeof(long)); *pt++ = nrho; /* nrho = pt[-3] */ *pt++ = np; /* np = pt[-2] */ *pt++ = q; /* q = pt[-1] */ pt[0] = (long)B->hashtab[hashv]; for (i=1; ihashtab[hashv]=pt; return NULL; } if (pt[-1] == q) break; } for(i=1; iprimes + S->nprimes-1)->p; } /* ensure that S->primes can hold at least nb primes */ void GRH_ensure(GRHcheck_t *S, long nb) { if (S->maxprimes <= nb) { do S->maxprimes *= 2; while (S->maxprimes <= nb); S->primes = (GRHprime_t*)pari_realloc((void*)S->primes, S->maxprimes*sizeof(*S->primes)); } } /* cache data for all primes up to the LIM */ static void cache_prime_quad(GRHcheck_t *S, ulong LIM, GEN D) { GRHprime_t *pr; long nb; if (S->limp >= LIM) return; nb = (long)primepi_upper_bound((double)LIM); /* #{p <= LIM} <= nb */ GRH_ensure(S, nb+1); /* room for one extra prime */ for (pr = S->primes + S->nprimes;;) { ulong p = u_forprime_next(&(S->P)); pr->p = p; pr->logp = log((double)p); pr->dec = (GEN)kroiu(D,p); S->nprimes++; pr++; /* store up to nextprime(LIM) included */ if (p >= LIM) { S->limp = p; break; } } } static GEN compute_invresquad(GRHcheck_t *S) { pari_sp av = avma; GEN invres = real_1(DEFAULTPREC); GRHprime_t *pr = S->primes; long i = S->nprimes, LIMC = GRH_last_prime(S)+diffptr[i]-1; /* nextprime(p+1)-1*/ double limp = log((double)LIMC) / 2; for (; i > 0; pr++, i--) { long s = (long)pr->dec; if (s) { ulong p = pr->p; if (s>0 || pr->logp <= limp) /* Both p and P contribute */ invres = mulur(p - s, divru(invres, p)); else if (s<0) /* Only p contributes */ invres = mulur(p, divru(invres, p - 1)); } } return gerepileuptoleaf(av, invres); } /* p | conductor of order of disc D ? */ static int is_bad(GEN D, ulong p) { pari_sp av = avma; int r; if (p == 2) { r = mod16(D) >> 1; if (r && signe(D) < 0) r = 8-r; return (r < 4); } r = dvdii(D, sqru(p)); /* p^2 | D ? */ avma = av; return r; } /* returns the n-th suitable ideal for the factorbase */ static long nthidealquad(GEN D, long n) { pari_sp av = avma; forprime_t S; ulong p; (void)u_forprime_init(&S, 2, ULONG_MAX); while ((p = u_forprime_next(&S)) && n > 0) if (!is_bad(D, p) && kroiu(D, p) >= 0) n--; avma = av; return p; } static int quadGRHchk(GEN D, GRHcheck_t *S, ulong LIMC) { double logC = log((double)LIMC), SA = 0, SB = 0; long i; cache_prime_quad(S, LIMC, D); for (i = 0;; i++) { GRHprime_t *pr = S->primes+i; ulong p = pr->p; long M; double logNP, q, A, B; if (p > LIMC) break; if ((long)pr->dec < 0) { logNP = 2 * pr->logp; q = 1/(double)p; } else { logNP = pr->logp; q = 1/sqrt((double)p); } A = logNP * q; B = logNP * A; M = (long)(logC/logNP); if (M > 1) { double inv1_q = 1 / (1-q); A *= (1 - pow(q, (double) M)) * inv1_q; B *= (1 - pow(q, (double) M)*(M+1 - M*q)) * inv1_q * inv1_q; } if ((long)pr->dec>0) { SA += 2*A;SB += 2*B; } else { SA += A; SB += B; } if (p == LIMC) break; } return GRHok(S, logC, SA, SB); } /* C2 >= C1; create B->FB, B->numFB; set B->badprim. Return L(kro_D, 1) */ static void FBquad(struct buch_quad *B, ulong C2, ulong C1, GRHcheck_t *S) { GEN D = B->QFR->D; long i; pari_sp av; GRHprime_t *pr; cache_prime_quad(S, C2, D); pr = S->primes; B->numFB = cgetg(C2+1, t_VECSMALL); B->FB = cgetg(C2+1, t_VECSMALL); av = avma; B->KC = 0; i = 0; B->badprim = gen_1; for (;; pr++) /* p <= C2 */ { ulong p = pr->p; if (!B->KC && p > C1) B->KC = i; if (p > C2) break; switch ((long)pr->dec) { case -1: break; /* inert */ case 0: /* ramified */ if (is_bad(D, p)) { B->badprim = muliu(B->badprim, p); break; } /* fall through */ default: /* split */ i++; B->numFB[p] = i; B->FB[i] = p; break; } if (p == C2) { if (!B->KC) B->KC = i; break; } } B->KC2 = i; setlg(B->FB, B->KC2+1); if (B->badprim != gen_1) B->badprim = gerepileuptoint(av, B->badprim); else { B->badprim = NULL; avma = av; } } /* create B->vperm, return B->subFB */ static GEN subFBquad(struct buch_quad *B, GEN D, double PROD, long minSFB) { long i, j, lgsub = 1, ino = 1, lv = B->KC+1; double prod = 1.; pari_sp av; GEN no; B->vperm = cgetg(lv, t_VECSMALL); av = avma; no = cgetg(lv, t_VECSMALL); for (j = 1; j < lv; j++) { ulong p = uel(B->FB,j); if (!umodiu(D, p)) no[ino++] = j; /* ramified */ else { B->vperm[lgsub++] = j; prod *= p; if (lgsub > minSFB && prod > PROD) break; } } /* lgsub >= 1 otherwise quadGRHchk is false */ i = lgsub; for (j = 1; j < ino;i++,j++) B->vperm[i] = no[j]; for ( ; i < lv; i++) B->vperm[i] = i; no = gclone(vecslice(B->vperm, 1, lgsub-1)); avma = av; return no; } /* assume n >= 1, x[i][j] = B->subFB[i]^j, for j = 1..n */ static GEN powsubFBquad(struct buch_quad *B, long n) { pari_sp av = avma; long i,j, l = lg(B->subFB); GEN F, y, x = cgetg(l, t_VEC), D = B->QFR->D; if (B->PRECREG) /* real */ { for (i=1; iQFR, B->FB[B->subFB[i]], B->PRECREG); y = cgetg(n+1, t_VEC); gel(x,i) = y; gel(y,1) = F; for (j=2; j<=n; j++) gel(y,j) = QFR5_comp(gel(y,j-1), F, B->QFR); } } else /* imaginary */ { for (i=1; iFB[B->subFB[i]]); y = cgetg(n+1, t_VEC); gel(x,i) = y; gel(y,1) = F; for (j=2; j<=n; j++) gel(y,j) = qficomp(gel(y,j-1), F); } } x = gclone(x); avma = av; return x; } static void sub_fact(struct buch_quad *B, GEN col, GEN F) { GEN b = gel(F,2); long i; for (i=1; i<=B->primfact[0]; i++) { ulong p = B->primfact[i], k = B->numFB[p]; long e = B->exprimfact[i]; if (umodiu(b, p<<1) > p) e = -e; col[k] -= e; } } static void add_fact(struct buch_quad *B, GEN col, GEN F) { GEN b = gel(F,2); long i; for (i=1; i<=B->primfact[0]; i++) { ulong p = B->primfact[i], k = B->numFB[p]; long e = B->exprimfact[i]; if (umodiu(b, p<<1) > p) e = -e; col[k] += e; } } static GEN get_clgp(struct buch_quad *B, GEN W, GEN *ptD, long prec) { GEN res, init, u1, D = ZM_snf_group(W,NULL,&u1), Z = prec? real_0(prec): NULL; long i, j, l = lg(W), c = lg(D); res=cgetg(c,t_VEC); init = cgetg(l,t_VEC); for (i=1; iQFR->D, B->FB[B->vperm[i]]); for (j=1; jQFR); g = g? qfr3_comp(g, t, B->QFR): t; } g = qfr3_to_qfr(qfr3_canon_safe(qfr3_red(g, B->QFR), B->QFR), Z); } else { for (i=1; iQFR->D; for (i = 1; i <= B->KC; i++) { /* ramified prime ==> trivial relation */ if (umodiu(D, B->FB[i])) continue; col = zero_zv(B->KC); col[i] = 2; j++; gel(mat,j) = col; gel(C,j) = gen_0; } return j; } static void dbg_all(pari_timer *T, const char *phase, long s, long n) { err_printf("\n"); timer_printf(T, "%s rel [#rel/#test = %ld/%ld]", phase,s,n); } /* Imaginary Quadratic fields */ static void imag_relations(struct buch_quad *B, long need, long *pc, ulong LIMC, GEN mat) { pari_timer T; long lgsub = lg(B->subFB), current = *pc, nbtest = 0, s = 0; long i, fpc; pari_sp av; GEN col, form, ex = cgetg(lgsub, t_VECSMALL); if (!current) current = 1; if (DEBUGLEVEL>2) timer_start(&T); av = avma; for(;;) { if (s >= need) break; avma = av; form = qfi_random(B,ex); form = qficomp(form, qfi_pf(B->QFR->D, B->FB[current])); nbtest++; fpc = factorquad(B,form,B->KC,LIMC); if (!fpc) { if (DEBUGLEVEL>3) err_printf("."); if ((nbtest & 0xff) == 0 && ++current > B->KC) current = 1; continue; } if (fpc > 1) { long *fpd = largeprime(B,fpc,ex,current,0); ulong b1, b2, p; GEN form2; if (!fpd) { if (DEBUGLEVEL>3) err_printf("."); continue; } form2 = qficomp(qfi_factorback(B,fpd), qfi_pf(B->QFR->D, B->FB[fpd[-2]])); p = fpc << 1; b1 = umodiu(gel(form2,2), p); b2 = umodiu(gel(form,2), p); if (b1 != b2 && b1+b2 != p) continue; col = gel(mat,++s); add_fact(B,col, form); (void)factorquad(B,form2,B->KC,LIMC); if (b1==b2) { for (i=1; isubFB[i]] += fpd[i]-ex[i]; sub_fact(B, col, form2); col[fpd[-2]]++; } else { for (i=1; isubFB[i]] += -fpd[i]-ex[i]; add_fact(B, col, form2); col[fpd[-2]]--; } if (DEBUGLEVEL>2) err_printf(" %ldP",s); } else { col = gel(mat,++s); for (i=1; isubFB[i]] = -ex[i]; add_fact(B, col, form); if (DEBUGLEVEL>2) err_printf(" %ld",s); } col[current]--; if (++current > B->KC) current = 1; } if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest); *pc = current; } static int imag_be_honest(struct buch_quad *B) { long p, fpc, s = B->KC, nbtest = 0; GEN F, ex = cgetg(lg(B->subFB), t_VECSMALL); pari_sp av = avma; while (sKC2) { p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p); F = qficomp(qfi_pf(B->QFR->D, p), qfi_random(B, ex)); fpc = factorquad(B,F,s,p-1); if (fpc == 1) { nbtest=0; s++; } else if (++nbtest > 40) return 0; avma = av; } return 1; } /* Real Quadratic fields */ static void real_relations(struct buch_quad *B, long need, long *pc, long lim, ulong LIMC, GEN mat, GEN C) { pari_timer T; long lgsub = lg(B->subFB), prec = B->PRECREG, current = *pc, nbtest=0, s=0; long i, fpc, endcycle, rhoacc, rho; /* in a 2nd phase, don't include FB[current] but run along the cyle * ==> get more units */ int first = (current == 0); pari_sp av, av1; GEN d, col, form, form0, form1, ex = cgetg(lgsub, t_VECSMALL); if (DEBUGLEVEL>2) timer_start(&T); if (!current) current = 1; if (lim > need) lim = need; av = avma; for(;;) { if (s >= need) break; if (first && s >= lim) { first = 0; if (DEBUGLEVEL>2) dbg_all(&T, "initial", s, nbtest); } avma = av; form = qfr3_random(B, ex); if (!first) form = QFR3_comp(form, qfr3_pf(B->QFR, B->FB[current]), B->QFR); av1 = avma; form0 = form; form1 = NULL; endcycle = rhoacc = 0; rho = -1; CYCLE: if (endcycle || rho > 5000) { if (++current > B->KC) current = 1; continue; } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"real_relations"); gerepileall(av1, form1? 2: 1, &form, &form1); } if (rho < 0) rho = 0; /* first time in */ else { form = qfr3_rho(form, B->QFR); rho++; rhoacc++; if (first) endcycle = (absequalii(gel(form,1),gel(form0,1)) && equalii(gel(form,2),gel(form0,2))); else { if (absequalii(gel(form,1), gel(form,3))) /* a = -c */ { if (absequalii(gel(form,1),gel(form0,1)) && equalii(gel(form,2),gel(form0,2))) continue; form = qfr3_rho(form, B->QFR); rho++; rhoacc++; } else { setsigne(form[1],1); setsigne(form[3],-1); } if (equalii(gel(form,1),gel(form0,1)) && equalii(gel(form,2),gel(form0,2))) continue; } } nbtest++; fpc = factorquad(B,form,B->KC,LIMC); if (!fpc) { if (DEBUGLEVEL>3) err_printf("."); goto CYCLE; } if (fpc > 1) { /* look for Large Prime relation */ long *fpd = largeprime(B,fpc,ex,first? 0: current,rhoacc); ulong b1, b2, p; GEN form2; if (!fpd) { if (DEBUGLEVEL>3) err_printf("."); goto CYCLE; } if (!form1) { form1 = qfr5_factorback(B,ex); if (!first) form1 = QFR5_comp(form1, qfr5_pf(B->QFR, B->FB[current], prec), B->QFR); } form1 = qfr5_rho_pow(form1, rho, B->QFR); rho = 0; form2 = qfr5_factorback(B,fpd); if (fpd[-2]) form2 = QFR5_comp(form2, qfr5_pf(B->QFR, B->FB[fpd[-2]], prec), B->QFR); form2 = qfr5_rho_pow(form2, fpd[-3], B->QFR); if (!absequalii(gel(form2,1),gel(form2,3))) { setsigne(form2[1], 1); setsigne(form2[3],-1); } p = fpc << 1; b1 = umodiu(gel(form2,2), p); b2 = umodiu(gel(form1,2), p); if (b1 != b2 && b1+b2 != p) goto CYCLE; col = gel(mat,++s); add_fact(B, col, form1); (void)factorquad(B,form2,B->KC,LIMC); if (b1==b2) { for (i=1; isubFB[i]] += fpd[i]-ex[i]; sub_fact(B,col, form2); if (fpd[-2]) col[fpd[-2]]++; d = qfr5_dist(subii(gel(form1,4),gel(form2,4)), divrr(gel(form1,5),gel(form2,5)), prec); } else { for (i=1; isubFB[i]] += -fpd[i]-ex[i]; add_fact(B, col, form2); if (fpd[-2]) col[fpd[-2]]--; d = qfr5_dist(addii(gel(form1,4),gel(form2,4)), mulrr(gel(form1,5),gel(form2,5)), prec); } if (DEBUGLEVEL>2) err_printf(" %ldP",s); } else { /* standard relation */ if (!form1) { form1 = qfr5_factorback(B, ex); if (!first) form1 = QFR5_comp(form1, qfr5_pf(B->QFR, B->FB[current], prec), B->QFR); } form1 = qfr5_rho_pow(form1, rho, B->QFR); rho = 0; col = gel(mat,++s); for (i=1; isubFB[i]] = -ex[i]; add_fact(B, col, form1); d = qfr5_dist(gel(form1,4), gel(form1,5), prec); if (DEBUGLEVEL>2) err_printf(" %ld",s); } affrr(d, gel(C,s)); if (first) { if (s >= lim) continue; goto CYCLE; } else { col[current]--; if (++current > B->KC) current = 1; } } if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest); *pc = current; } static int real_be_honest(struct buch_quad *B) { long p, fpc, s = B->KC, nbtest = 0; GEN F,F0, ex = cgetg(lg(B->subFB), t_VECSMALL); pari_sp av = avma; while (sKC2) { p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p); F = QFR3_comp(qfr3_random(B, ex), qfr3_pf(B->QFR, p), B->QFR); for (F0 = F;;) { fpc = factorquad(B,F,s,p-1); if (fpc == 1) { nbtest=0; s++; break; } if (++nbtest > 40) return 0; F = qfr3_canon(qfr3_rho(F, B->QFR), B->QFR); if (equalii(gel(F,1),gel(F0,1)) && equalii(gel(F,2),gel(F0,2))) break; } avma = av; } return 1; } static GEN gcdreal(GEN a,GEN b) { if (!signe(a)) return mpabs_shallow(b); if (!signe(b)) return mpabs_shallow(a); if (typ(a)==t_INT) { if (typ(b)==t_INT) return gcdii(a,b); a = itor(a, lg(b)); } else if (typ(b)==t_INT) b = itor(b, lg(a)); if (expo(a)<-5) return absr(b); if (expo(b)<-5) return absr(a); a = absr(a); b = absr(b); while (expo(b) >= -5 && signe(b)) { long e; GEN r, q = gcvtoi(divrr(a,b),&e); if (e > 0) return NULL; r = subrr(a, mulir(q,b)); a = b; b = r; } return mpabs_shallow(a); } static int get_R(struct buch_quad *B, GEN C, long sreg, GEN z, GEN *ptR) { GEN R = gen_1; double c; long i; if (B->PRECREG) { R = mpabs_shallow(gel(C,1)); for (i=2; i<=sreg; i++) { R = gcdreal(gel(C,i), R); if (!R) return fupb_PRECI; } if (gexpo(R) <= -3) { if (DEBUGLEVEL>2) err_printf("regulator is zero.\n"); return fupb_RELAT; } if (DEBUGLEVEL>2) err_printf("#### Tentative regulator: %Ps\n",R); } c = gtodouble(gmul(z, R)); if (c < 0.8 || c > 1.3) return fupb_RELAT; *ptR = R; return fupb_NONE; } static int quad_be_honest(struct buch_quad *B) { int r; if (B->KC2 <= B->KC) return 1; if (DEBUGLEVEL>2) err_printf("be honest for primes from %ld to %ld\n", B->FB[B->KC+1],B->FB[B->KC2]); r = B->PRECREG? real_be_honest(B): imag_be_honest(B); if (DEBUGLEVEL>2) err_printf("\n"); return r; } GEN Buchquad(GEN D, double cbach, double cbach2, long prec) { const long MAXRELSUP = 7, SFB_MAX = 3; pari_timer T; pari_sp av0 = avma, av, av2; const long RELSUP = 5; long i, s, current, triv, sfb_trials, nrelsup, nreldep, need, nsubFB, minSFB; ulong low, high, LIMC0, LIMC, LIMC2, LIMCMAX, cp; GEN W, cyc, res, gen, dep, mat, C, extraC, B, R, invhr, h = NULL; /*-Wall*/ double drc, sdrc, lim, LOGD, LOGD2; GRHcheck_t GRHcheck; struct qfr_data QFR; struct buch_quad BQ; int FIRST = 1; check_quaddisc(D, &s, /*junk*/&i, "Buchquad"); R = NULL; /* -Wall */ BQ.QFR = &QFR; QFR.D = D; if (s < 0) { if (abscmpiu(QFR.D,4) <= 0) { GEN z = cgetg(5,t_VEC); gel(z,1) = gel(z,4) = gen_1; gel(z,2) = gel(z,3) = cgetg(1,t_VEC); return z; } prec = BQ.PRECREG = 0; } else { BQ.PRECREG = maxss(prec+EXTRAPRECWORD, nbits2prec(2*expi(QFR.D) + 128)); } if (DEBUGLEVEL>2) timer_start(&T); BQ.primfact = new_chunk(100); BQ.exprimfact = new_chunk(100); BQ.hashtab = (long**) new_chunk(HASHT); for (i=0; i 6.) { if (cbach2 < cbach) cbach2 = cbach; cbach = 6.; } if (cbach < 0.) pari_err_DOMAIN("Buchquad","Bach constant","<",gen_0,dbltor(cbach)); av = avma; BQ.powsubFB = BQ.subFB = NULL; minSFB = (expi(D) > 15)? 3: 2; init_GRHcheck(&GRHcheck, 2, BQ.PRECREG? 2: 0, LOGD); high = low = LIMC0 = maxss((long)(cbach2*LOGD2), 1); LIMCMAX = (long)(6.*LOGD2); /* 97/1223 below to ensure a good enough approximation of residue */ cache_prime_quad(&GRHcheck, expi(D) < 16 ? 97: 1223, D); while (!quadGRHchk(D, &GRHcheck, high)) { low = high; high *= 2; } while (high - low > 1) { long test = (low+high)/2; if (quadGRHchk(D, &GRHcheck, test)) high = test; else low = test; } if (high == LIMC0+1 && quadGRHchk(D, &GRHcheck, LIMC0)) LIMC2 = LIMC0; else LIMC2 = high; if (LIMC2 > LIMCMAX) LIMC2 = LIMCMAX; LIMC0 = (long)(cbach*LOGD2); LIMC = cbach ? LIMC0 : LIMC2; LIMC = maxss(LIMC, nthidealquad(D, 2)); /* LIMC = Max(cbach*(log D)^2, exp(sqrt(log D loglog D) / 8)) */ START: do { if (!FIRST) LIMC = bnf_increase_LIMC(LIMC,LIMCMAX); if (DEBUGLEVEL>2 && LIMC > LIMC0) err_printf("%s*** Bach constant: %f\n", FIRST?"":"\n", LIMC/LOGD2); FIRST = 0; avma = av; if (BQ.subFB) gunclone(BQ.subFB); if (BQ.powsubFB) gunclone(BQ.powsubFB); clearhash(BQ.hashtab); if (LIMC < cp) LIMC = cp; if (LIMC2 < LIMC) LIMC2 = LIMC; if (BQ.PRECREG) qfr_data_init(QFR.D, BQ.PRECREG, &QFR); FBquad(&BQ, LIMC2, LIMC, &GRHcheck); if (DEBUGLEVEL>2) timer_printf(&T, "factor base"); BQ.subFB = subFBquad(&BQ, QFR.D, lim + 0.5, minSFB); if (DEBUGLEVEL>2) timer_printf(&T, "subFBquad = %Ps", vecpermute(BQ.FB, BQ.subFB)); nsubFB = lg(BQ.subFB) - 1; } while (nsubFB < (expi(D) > 15 ? 3 : 2)); /* invhr = 2^r1 (2pi)^r2 / sqrt(D) w ~ L(chi,1) / hR */ invhr = gmul(dbltor((BQ.PRECREG?2.:M_PI)/sdrc), compute_invresquad(&GRHcheck)); BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1); if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad"); BQ.limhash = (LIMC & HIGHMASK)? (HIGHBIT>>1): LIMC*LIMC; need = BQ.KC + RELSUP - 2; current = 0; W = NULL; sfb_trials = nreldep = nrelsup = 0; s = nsubFB + RELSUP; av2 = avma; do { if ((nreldep & 3) == 1 || (nrelsup & 7) == 1) { if (DEBUGLEVEL>2) err_printf("*** Changing sub factor base\n"); gunclone(BQ.subFB); gunclone(BQ.powsubFB); BQ.subFB = gclone(vecslice(BQ.vperm, 1, nsubFB)); BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1); if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad"); clearhash(BQ.hashtab); } need += 2; mat = cgetg(need+1, t_MAT); extraC = cgetg(need+1, t_VEC); if (!W) { /* first time */ C = extraC; triv = trivial_relations(&BQ, mat, C); if (DEBUGLEVEL>2) err_printf("KC = %ld, need %ld relations\n", BQ.KC, need); } else { triv = 0; if (DEBUGLEVEL>2) err_printf("...need %ld more relations\n", need); } if (BQ.PRECREG) { for (i = triv+1; i<=need; i++) { gel(mat,i) = zero_zv(BQ.KC); gel(extraC,i) = cgetr(BQ.PRECREG); } real_relations(&BQ, need - triv, ¤t, s,LIMC,mat + triv,extraC + triv); } else { for (i = triv+1; i<=need; i++) { gel(mat,i) = zero_zv(BQ.KC); gel(extraC,i) = gen_0; } imag_relations(&BQ, need - triv, ¤t, LIMC,mat + triv); } if (!W) W = hnfspec_i(mat,BQ.vperm,&dep,&B,&C,nsubFB); else W = hnfadd_i(W,BQ.vperm,&dep,&B,&C, mat,extraC); gerepileall(av2, 4, &W,&C,&B,&dep); need = BQ.KC - (lg(W)-1) - (lg(B)-1); if (need) { if (++nreldep > 15 && cbach < 1) goto START; continue; } h = ZM_det_triangular(W); if (DEBUGLEVEL>2) err_printf("\n#### Tentative class number: %Ps\n", h); switch(get_R(&BQ, C, (lg(C)-1) - (lg(B)-1) - (lg(W)-1), mulir(h,invhr), &R)) { case fupb_PRECI: BQ.PRECREG = precdbl(BQ.PRECREG); FIRST = 1; goto START; case fupb_RELAT: if (++nrelsup > MAXRELSUP) { if (++sfb_trials > SFB_MAX && cbach <= 1) goto START; if (nsubFB < minss(10,BQ.KC)) nsubFB++; } need = minss(BQ.KC, nrelsup); } } while (need); /* DONE */ if (!quad_be_honest(&BQ)) goto START; if (DEBUGLEVEL>2) timer_printf(&T, "be honest"); clearhash(BQ.hashtab); free_GRHcheck(&GRHcheck); gen = get_clgp(&BQ,W,&cyc,prec); gunclone(BQ.subFB); gunclone(BQ.powsubFB); res = cgetg(5,t_VEC); gel(res,1) = h; gel(res,2) = cyc; gel(res,3) = gen; gel(res,4) = R; return gerepilecopy(av0,res); } GEN buchimag(GEN D, GEN c, GEN c2, GEN REL) { (void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),0); } GEN buchreal(GEN D, GEN flag, GEN c, GEN c2, GEN REL, long prec) { if (signe(flag)) pari_err_IMPL("narrow class group"); (void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),prec); } GEN quadclassunit0(GEN x, long flag, GEN data, long prec) { long lx; double c1 = 0.0, c2 = 0.0; if (!data) lx=1; else { lx = lg(data); if (typ(data)!=t_VEC) pari_err_TYPE("quadclassunit", data); if (lx > 7) pari_err_DIM("quadclassunit [tech vector]"); if (lx > 3) lx = 3; } switch(lx) { case 3: c2 = gtodouble(gel(data,2)); case 2: c1 = gtodouble(gel(data,1)); } if (flag) pari_err_IMPL("narrow class group"); return Buchquad(x,c1,c2,prec); } pari-2.11.2/src/basemath/crvwtors.c0000644000175000017500000050646413326135265015613 0ustar billbill/* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* In the database, the curve X1(N) is given by the bivariate * polynomial X. The degree of X in its main variable is at least * the degree of its secondary variable, except for N = 6, 7, 8, 9, * 10, 12. Note that X1(N) is genus 0 for N <= 10 and N = 12, and * genus 1 for N = 11, 14, and 15. */ INLINE ulong Fl_div4(ulong x, ulong p) { return Fl_halve(Fl_halve(x, p), p); } INLINE ulong Fl_div8(ulong x, ulong p) { return Fl_halve(Fl_div4(x, p), p); } /* These tags describe which map to use to convert from (r,s) to (b,c) * coeffs. */ typedef enum { RS_MAP, T_MAP, QT_MAP, TQ_MAP } map_type; typedef struct { GEN crv; GEN r_num, r_den; long rplus1; GEN s_num, s_den; long splus1; map_type map; } X1_info; #define FIRST_X1_LEVEL 13 #define LAST_X1_LEVEL 39 /* The table is defined at the end of the file. */ INLINE const X1_info *get_X1_info(ulong N); /* Compute the image of * (x,y) |--> (r_n(x,y)/r_d(x,y), s_n(x,y), s_d(x,y)) */ static void map_X1_points( GEN r, GEN s, const X1_info *X1, long ncurves, ulong p, ulong pi) { pari_sp ltop = avma, av; GEN X1_c, rn_pol, rd_pol, sn_pol, sd_pol, rn, sn, rd, sd; long xdeg, ydeg, i; X1_c = zxX_to_FlxX(X1->crv, p); xdeg = degpol(X1_c); ydeg = FlxY_degreex(X1_c); rn_pol = zxX_to_FlxX(X1->r_num, p); rd_pol = zxX_to_FlxX(X1->r_den, p); sn_pol = zxX_to_FlxX(X1->s_num, p); sd_pol = zxX_to_FlxX(X1->s_den, p); xdeg = maxss(xdeg, degpol(rn_pol)); xdeg = maxss(xdeg, degpol(rd_pol)); xdeg = maxss(xdeg, degpol(sn_pol)); xdeg = maxss(xdeg, degpol(sd_pol)); ydeg = maxss(ydeg, FlxY_degreex(rn_pol)); ydeg = maxss(ydeg, FlxY_degreex(rd_pol)); ydeg = maxss(ydeg, FlxY_degreex(sn_pol)); ydeg = maxss(ydeg, FlxY_degreex(sd_pol)); rn = cgetg(ncurves + 1, t_VECSMALL); rd = cgetg(ncurves + 1, t_VECSMALL); sn = cgetg(ncurves + 1, t_VECSMALL); sd = cgetg(ncurves + 1, t_VECSMALL); av = avma; for (i = 1; i <= ncurves; ) { GEN pol, ypowers, xpowers; ulong y, x; y = random_Fl(p); ypowers = Fl_powers_pre(y, ydeg, p, pi); pol = FlxY_evalx_powers_pre(X1_c, ypowers, p, pi); x = Flx_oneroot(pol, p); if (x != p) { xpowers = Fl_powers_pre(x, xdeg, p, pi); rd[i] = FlxY_eval_powers_pre(rd_pol, ypowers, xpowers, p, pi); sd[i] = FlxY_eval_powers_pre(sd_pol, ypowers, xpowers, p, pi); if (rd[i] != 0 && sd[i] != 0) { rn[i] = FlxY_eval_powers_pre(rn_pol, ypowers, xpowers, p, pi); sn[i] = FlxY_eval_powers_pre(sn_pol, ypowers, xpowers, p, pi); ++i; } } avma = av; } Flv_inv_pre_inplace(rd, p, pi); Flv_inv_pre_inplace(sd, p, pi); for (i = 1; i <= ncurves; ++i) { r[i] = Fl_addmul_pre(X1->rplus1, rn[i], rd[i], p, pi); s[i] = Fl_addmul_pre(X1->splus1, sn[i], sd[i], p, pi); } avma = ltop; } /* * A curve y^2 = x^3 + a2 x^2 + a4 x is isomorphic to the curve * * y^2 = x^3 + (a4 - 1/3*a2^2) x + (2/27*a2^3 - 1/3*a4*a2) * = x^3 + (a4 - a2 c) x + (2 c^3 - a4 c) * * (where c = a2/3) which is in short form. */ INLINE void a2a4_to_a4a6(ulong *a4, ulong *a6, ulong A2, ulong A4, ulong inv3, ulong p, ulong pi) { ulong c = Fl_mul_pre(A2, inv3, p, pi); *a4 = Fl_sub(A4, Fl_mul_pre(A2, c, p, pi), p); *a6 = Fl_sub(Fl_double(Fl_mul_pre(c, Fl_sqr_pre(c, p, pi), p, pi), p), Fl_mul_pre(A4, c, p, pi), p); } /* * A curve y^2 + a1 xy + a3 y = x^3 is isomorphic to the curve * * y^2 = x^3 + (1/2*a3*a1 -1/48*a1^4) x + (1/864*a1^6 - 1/24*a3*a1^3 + 1/4*a3^2 * = x^3 + c (a3 - 1/3 * c^3) x + 1/3 * c^3(1/9 c^2 a1 - a3) + 1/4 a3^2 * * (where c = a1/2) which is in short form. */ INLINE void a1a3_to_a4a6( ulong *a4, ulong *a6, ulong a1, ulong a3, ulong inv3, ulong inv4, ulong inv9, ulong p, ulong pi) { ulong c = Fl_halve(a1, p); ulong c2 = Fl_sqr_pre(c, p, pi); ulong c3_on_3 = Fl_mul_pre(Fl_mul_pre(c, c2, p, pi), inv3, p, pi); /* t1 = c^2 * a1 / 9 */ ulong t1 = Fl_mul_pre(c2, Fl_mul_pre(a1, inv9, p, pi), p, pi); /* t1 = c^3/3 (c^2 * a1 / 9 - a3) */ t1 = Fl_mul_pre(c3_on_3, Fl_sub(t1, a3, p), p, pi); *a4 = Fl_mul_pre(c, Fl_sub(a3, c3_on_3, p), p, pi); *a6 = Fl_addmul_pre(t1, inv4, Fl_sqr_pre(a3, p, pi), p, pi); } /* Assumes m > 3, p > 5 */ /* FIXME: Where do we assume that p > 5? Some testing suggests that * this works for p == 5 also. */ /* Sutherland has a version of this function in tecurve.c * around line 306. */ /* FIXME: Could precompute some of the constants. */ INLINE void bc_to_a4a6( ulong *a4, ulong *a6, ulong b, ulong c, ulong p, ulong pi) { /* E: y^2 + (1 - c)xy - by = x^3 - bx^2, so a1 = 1 - c * and a2 = a3 = -b. */ ulong t0, t2, b2, b4, b6, c4, c6; b6 = Fl_sub(c, 1, p); t0 = Fl_sqr_pre(b6, p, pi); b4 = Fl_double(Fl_double(b, p), p); b2 = Fl_sub(t0, b4, p); b4 = Fl_mul_pre(b6, b, p, pi); b6 = Fl_sqr_pre(b, p, pi); t2 = Fl_sqr_pre(b2, p, pi); c4 = Fl_mul_pre(24 % p, b4, p, pi); c4 = Fl_sub(c4, t2, p); t0 = Fl_mul_pre(36 % p, b4, p, pi); t2 = Fl_sub(t2, t0, p); c6 = Fl_mul_pre(b2, t2, p, pi); t0 = Fl_mul_pre(216 % p, b6, p, pi); c6 = Fl_add(c6, t0, p); *a4 = Fl_mul_pre(27 % p, c4, p, pi); *a6 = Fl_mul_pre(54 % p, c6, p, pi); } INLINE void bc_to_a4a6_and_tors( ulong *a4, ulong *a6, ulong *tx, ulong *ty, ulong b, ulong c, ulong p, ulong pi) { bc_to_a4a6(a4, a6, b, c, p, pi); /* tx = 3((c - 1)^2 - 4b) */ *tx = Fl_triple(Fl_sub(Fl_sqr(Fl_sub(c, 1, p), p), Fl_double(Fl_double(b, p), p), p), p); /* ty = -108 b */ *ty = Fl_neg(Fl_mul_pre(108 % p, b, p, pi), p); } INLINE void tq_to_a4a6_and_tors( ulong *a4, ulong *a6, ulong *tx, ulong *ty, ulong q, ulong t, ulong p, ulong pi, ulong inv3) { ulong A2, A4; ulong t2 = Fl_sqr_pre(t, p, pi); ulong qtp1 = Fl_addmul_pre(1L, q, t, p, pi); /* a2 = t^2-2*(q*t+1), a4 = (1-t^2)*(q*t+1)^2 */ A2 = Fl_sub(t2, Fl_double(qtp1, p), p); A4 = Fl_mul_pre(Fl_sub(1L, t2, p), Fl_sqr_pre(qtp1, p, pi), p, pi); a2a4_to_a4a6(a4, a6, A2, A4, inv3, p, pi); /* [tx, ty] = [(t+1)*(q*t+1),t*(q*t+1)*(t+1)] */ *tx = Fl_mul_pre(Fl_add(t, 1L, p), qtp1, p, pi); *ty = Fl_mul_pre(t, *tx, p, pi); /* Map to isomorphic curve */ *tx = Fl_addmul_pre(*tx, A2, inv3, p, pi); } INLINE void qt_to_a4a6_and_tors( ulong *a4, ulong *a6, ulong *tx, ulong *ty, ulong q, ulong t, ulong p, ulong pi, ulong c_12, ulong c_108) { /* z = (q+1)*(t^2-1)/8 */ ulong z = Fl_div8(Fl_mul_pre(Fl_add(q, 1L, p), Fl_sub(Fl_sqr_pre(t, p, pi), 1L, p), p, pi), p); ulong bb = Fl_mul_pre(Fl_sub(q, 1L, p), z, p, pi); ulong b = Fl_halve(bb, p); /* E=[1,(q^2-1)*(t^2-1)/16,(q^2-1)*(t^2-1)/16,0,0]; * = [1, (q-1)*(q+1)*(t^2-1)/16, idem] * = [1, b, b, 0, 0] */ bc_to_a4a6(a4, a6, Fl_neg(b, p), 0L, p, pi); /* [tx,ty]= [(q+1)*(t^2-1)/8,(q+1)^2*(t^2-1)*(t-1)/32]; * = [z, (q+1)*(t-1)*z*1/4] */ *tx = z; *ty = Fl_mul_pre(Fl_add(q, 1L, p), Fl_mul_pre(Fl_div4(z, p), Fl_sub(t, 1L, p), p, pi), p, pi); /* Map to isomorphic curve: * (x, y) |--> (3(12x + 4b + 1), 108(2y + x + b)) */ *ty = Fl_mul_pre(c_108, Fl_add(Fl_double(*ty, p), Fl_add(b, *tx, p), p), p, pi); *tx = Fl_triple(Fl_addmul_pre(Fl_add(Fl_double(bb, p), 1L, p), c_12, *tx, p, pi), p); } INLINE void t_to_a4a6_and_tors( ulong *a4, ulong *a6, ulong *tx, ulong *ty, ulong q, ulong t, ulong p, ulong pi, ulong inv3, ulong inv4, ulong inv9) { ulong a1, a3, qt = Fl_mul_pre(q, t, p, pi), t1; /* a1 = q*t+t+(2-q), a3 = (q*t)*(t-1)+t */ a1 = Fl_add(Fl_add(qt, t, p), Fl_sub(2L, q, p), p); a3 = Fl_addmul_pre(t, qt, Fl_sub(t, 1L, p), p, pi); a1a3_to_a4a6(a4, a6, a1, a3, inv3, inv4, inv9, p, pi); *tx = Fl_neg(t, p); *ty = Fl_sqr_pre(t, p, pi); /* Map to isomorphic curve: * (x, y) |--> (x + 1/12*a1^2, 1/2*a1*x + (y + 1/2*a3)) */ t1 = Fl_halve(a1, p); *ty = Fl_addmul_pre(Fl_add(*ty, Fl_halve(a3, p), p), *tx, t1, p, pi); *tx = Fl_addmul_pre(*tx, inv3, Fl_sqr_pre(t1, p, pi), p, pi); } INLINE void rs_to_a4a6_and_tors( ulong *a4, ulong *a6, ulong *tx, ulong *ty, ulong r, ulong s, ulong p, ulong pi) { /* c = s (r - 1) */ ulong c = Fl_mul_pre(s, Fl_sub(r, 1, p), p, pi); /* b = rc */ ulong b = Fl_mul_pre(r, c, p, pi); bc_to_a4a6_and_tors(a4, a6, tx, ty, b, c, p, pi); } INLINE void random_curves_with_general_X1( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, long m, ulong p, ulong pi) { pari_sp av = avma; const X1_info *X1 = get_X1_info(m); GEN r, r_, s, s_; r_ = cgetg(ncurves + 1, t_VECSMALL); r = r_ + 1; s_ = cgetg(ncurves + 1, t_VECSMALL); s = s_ + 1; map_X1_points(r_, s_, X1, ncurves, p, pi); switch (X1->map) { case RS_MAP: while (ncurves--) rs_to_a4a6_and_tors(a4++, a6++, tx++, ty++, *r++, *s++, p, pi); break; case T_MAP: { ulong inv3 = Fl_inv(3L, p), inv4 = Fl_div4(1L, p); ulong inv9 = Fl_sqr_pre(inv3, p, pi); while (ncurves--) { t_to_a4a6_and_tors(a4++, a6++, tx++, ty++, *r++, *s++, p, pi, inv3, inv4, inv9); } break; } case TQ_MAP: { ulong inv3 = Fl_inv(3L, p); while (ncurves--) { tq_to_a4a6_and_tors(a4++, a6++, tx++, ty++, *r++, *s++, p, pi, inv3); } break; } case QT_MAP: { ulong c_12 = 12 % p, c_108 = 108 % p; while (ncurves--) { qt_to_a4a6_and_tors(a4++, a6++, tx++, ty++, *r++, *s++, p, pi, c_12, c_108); } break; } } avma = av; } INLINE void random_curves_with_11_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { pari_sp ltop = avma, av; const ulong A4 = Fl_neg(432 % p, p), A6 = 8208 % p; const ulong c_6 = 6 % p, c_72 = 72 % p, c_108 = 108 % p; const ulong inv216 = Fl_inv(216 % p, p); av = avma; while (ncurves) { GEN Q; ulong r, s, den; /* FIXME: Curve arithmetic in Pari is slow enough that it's faster * to generate random points on the curve than it is to compute * random multiples of a point. I don't know if this is to be * expected or not. Should check if this is still true when using * the fast jac_{add,mul} routines in 'classpoly.c'. Anyway, * disabled for now. */ #if 0 /* Must guard against the possibility that [n]Q = 0 */ do { /* FIXME: should perhaps use p + 1 + 2\sqrt{p} instead of p - 1 */ n = random_Fl(m1) + 1; /* m1 = p - 1; */ Q = Fle_mulu(P, n, A4, p); } while (ell_is_inf(Q)); #endif /* FIXME: Thing is, if I'm going to do it this way *anyway*, I * might as well use the non-elliptic version of X1(11), since the * formulae are much nicer. */ Q = random_Fle_pre(A4, A6, p, pi); /* den = 6x + 72 */ den = Fl_addmul_pre(c_72, c_6, Q[1], p, pi); if (den == 0) continue; /* r = (y + 108)/216, s = 1 + (y - 108)/(6x + 72) */ r = Fl_mul_pre(Fl_add(Q[2], c_108, p), inv216, p, pi); s = Fl_add(1, Fl_div(Fl_sub(Q[2], c_108, p), den, p), p); rs_to_a4a6_and_tors(a4++, a6++, tx++, ty++, r, s, p, pi); avma = av; --ncurves; } avma = ltop; } INLINE void random_curves_with_elliptic_X1( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, long m, ulong p, ulong pi) { switch (m) { case 11: random_curves_with_11_torsion(a4, a6, tx, ty, ncurves, p, pi); break; /* cases 12 and 13 are not missing, it is handled by * random_curves_with_rational_X1() and * random_curves_with_general_X1() respectively. */ case 14: /*random_curves_with_14_torsion(a4, a6, tx, ty, ncurves, p, pi); break;*/ case 15: /*random_curves_with_14_torsion(a4, a6, tx, ty, ncurves, p, pi); break;*/ /* FIXME: random_curves_with_elliptic_X1() currently uses the * alternative (but nevertheless very efficient) non-elliptic * implementation for levels 14 and 15. */ random_curves_with_general_X1(a4, a6, tx, ty, ncurves, m, p, pi); break; default: pari_err_BUG("random_curves_with_elliptic_X1"); } } INLINE void random_curves_with_2_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { const ulong m1 = p - 1, inv3 = Fl_inv(3L, p); while (ncurves--) { ulong A2 = random_Fl(m1) + 1; /* non-zero */ ulong A4 = random_Fl(m1) + 1; /* non-zero */ a2a4_to_a4a6(a4++, a6++, A2, A4, inv3, p, pi); /* [0,0] is a 2-torsion point on y^2 = x(x^2 + a2x + a4) which * is mapped to [(1/3)a2, 0] on y^2 = x^3 + A4x + A6. */ *tx++ = Fl_mul_pre(inv3, A2, p, pi); *ty++ = 0L; }; } INLINE void random_curves_with_3_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { const ulong m1 = p - 1; const ulong inv3 = Fl_inv(3, p), inv4 = Fl_inv(4, p); const ulong inv9 = Fl_sqr_pre(inv3, p, pi); while (ncurves--) { ulong a1 = random_Fl(m1) + 1; /* non-zero */ ulong a3 = random_Fl(m1) + 1; /* non-zero */ a1a3_to_a4a6(a4++, a6++, a1, a3, inv3, inv4, inv9, p, pi); /* [0,0] is a 3-torsion point on y^2 + a1xy + a3y = x^3 which * is mapped to [a1^2/12, a3/2] on y^2 = x^3 + a4x + a6. */ *tx++ = Fl_mul_pre(Fl_sqr_pre(Fl_halve(a1, p), p, pi), inv3, p, pi); *ty++ = Fl_halve(a3, p); } } INLINE void random_curves_with_4_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { const ulong m1 = p - 1; while (ncurves--) { ulong b = random_Fl(m1) + 1; /* non-zero */ bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, 0L, p, pi); } } INLINE void random_curves_with_5_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { const ulong m1 = p - 1; while (ncurves--) { ulong b = random_Fl(m1) + 1; /* non-zero */ bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, b, p, pi); } } INLINE void random_curves_with_6_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { const ulong m2 = p - 2; while (ncurves--) { ulong c = random_Fl(m2) + 1; /* in [1, p - 2] */ ulong b = Fl_add(c, Fl_sqr_pre(c, p, pi), p); /* b = c + c^2 */ bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, c, p, pi); } } INLINE void random_curves_with_7_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { const ulong m2 = p - 2; while (ncurves--) { ulong d = random_Fl(m2) + 2; /* in [2, p - 2] */ ulong c = Fl_sub(Fl_sqr_pre(d, p, pi), d, p); /* c = d^2 - d */ ulong b = Fl_mul_pre(c, d, p, pi); /* b = d^3 - d^2 */ bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, c, p, pi); } } INLINE void random_curves_with_8_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { const ulong m1 = p - 1; while (ncurves--) { ulong d = random_Fl(m1) + 1; /* non-zero */ /* b = (2d - 1)(d - 1) */ ulong b = Fl_mul_pre(Fl_sub(Fl_double(d, p), 1, p), Fl_sub(d, 1, p), p, pi); /* c = (2d - 1)(d - 1)/d */ ulong c = Fl_div(b, d, p); bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, c, p, pi); } } INLINE void random_curves_with_9_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { while (ncurves--) { ulong f = random_Fl(p); /* d = f(f - 1) + 1 = f^2 - f + 1 = f^2 - (f - 1) */ ulong d = Fl_sub(Fl_sqr_pre(f, p, pi), Fl_sub(f, 1, p), p); /* c = fd - f */ ulong c = Fl_mul_pre(f, Fl_sub(d, 1, p), p, pi); /* b = cd */ ulong b = Fl_mul_pre(c, d, p, pi); bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, c, p, pi); } } INLINE void random_curves_with_10_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { while (ncurves) { ulong f, f2, d, c, b, t; f = random_Fl(p); /* t = f - (f - 1)^2 = (3f - 1) - f^2 */ f2 = Fl_sqr_pre(f, p, pi); t = Fl_sub(Fl_sub(Fl_triple(f, p), 1, p), f2, p); if (t == 0) continue; /* d = f^2 / (f - (f - 1)^2) */ d = Fl_div(f2, t, p); /* c = fd - f */ c = Fl_mul_pre(f, Fl_sub(d, 1, p), p, pi); /* b = cd */ b = Fl_mul_pre(c, d, p, pi); bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, c, p, pi); --ncurves; } } INLINE void random_curves_with_12_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, ulong p, ulong pi) { while (ncurves--) { ulong tau, t1, t2, M, f, d, c, b; tau = random_Fl(p); /* tau mustn't be = 1. If it is, just set tau = 2. */ tau += tau == 1; /* t1 = tau - 1 */ t1 = Fl_sub(tau, 1, p); /* M = (3 tau - 3 tau^2 - 1)/(tau - 1) = -(3 tau + 1/(tau - 1)) */ t2 = Fl_inv(t1, p); M = Fl_neg(Fl_add(Fl_triple(tau, p), t2, p), p); /* f = M/(1 - tau) = -M / (tau - 1) */ f = Fl_neg(Fl_mul_pre(M, t2, p, pi), p); /* d = M + tau */ d = Fl_add(M, tau, p); /* c = fd - f */ c = Fl_mul_pre(f, Fl_sub(d, 1, p), p, pi); /* b = cd */ b = Fl_mul_pre(c, d, p, pi); bc_to_a4a6_and_tors(a4++, a6++, tx++, ty++, b, c, p, pi); } } INLINE void random_curves_with_rational_X1( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, long m, ulong p, ulong pi) { switch (m) { case 2: random_curves_with_2_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 3: random_curves_with_3_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 4: random_curves_with_4_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 5: random_curves_with_5_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 6: random_curves_with_6_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 7: random_curves_with_7_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 8: random_curves_with_8_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 9: random_curves_with_9_torsion(a4, a6, tx, ty, ncurves, p, pi); break; case 10: random_curves_with_10_torsion(a4, a6, tx, ty, ncurves, p, pi); break; /* case 11 is not missing, it is handled by random_curves_with_elliptic_X1() */ case 12: random_curves_with_12_torsion(a4, a6, tx, ty, ncurves, p, pi); break; default: pari_err_BUG("random_curves_with_rational_X1"); } } static void random_curves_with_any_torsion( ulong *a4, ulong *a6, ulong *px, ulong *py, long ncurves, ulong p, ulong pi) { pari_sp av = avma; ulong c_1728 = 1728 % p; long i; for (i = 0; i < ncurves; ++i) { GEN P; ulong j; do j = random_Fl(p); while (j == 0 || j == c_1728); Fl_ellj_to_a4a6(j, p, &a4[i], &a6[i]); P = random_Fle_pre(a4[i], a6[i], p, pi); px[i] = P[1]; py[i] = P[2]; avma = av; } } /* Assumes p < 2^62 or thereabouts. */ INLINE long torsion_compatible_with_characteristic(long m, ulong p) { ulong two_sqrt_p = usqrt(4*p); ulong lo = p + 1 - two_sqrt_p; ulong hi = p + 1 + two_sqrt_p; /* If ceil(lo/m) <= floor(hi/m) then there is a positive * integer n such that lo <= mn <= hi. */ /* NB: Ceil(a/b) = (a + b - 1)/b, Floor(a/b) = a/b (using integer * truncation). */ return (lo + m - 1)/m <= hi/m; } /* * Input: pointers a4, a6, t{x,y} where t{x,y} is allowed to be * zero, each (non-zero one) pointing to space for at least ncurves * elements; an integer m <= 50; a prime p > 3; a flag in {0, 1}. * * The flag indicates that we should generate curves faster at the * expense of not guaranteeing uniform randomness. This only makes a * difference when m = 11, 14 and 15. * * Output: Put the coefficients of ncurves elliptic curves with * m-torsion into a4 and a6. The actual number of *unique* curves * generated is *not* guaranteed to be ncurves, but will be close * whenever p is big relative to ncurves. When non-zero, (torx[i], * tory[i]) will contain the m-torsion point on [a4[i], a6[i]]. */ void random_curves_with_m_torsion( ulong *a4, ulong *a6, ulong *tx, ulong *ty, long ncurves, long m, ulong p) { ulong pi = get_Fl_red(p); if (ncurves == 0) return; if (m < 1 || m > LAST_X1_LEVEL || ! torsion_compatible_with_characteristic(m, p)) pari_err_BUG("random_curves_with_m_torsion"); else if (m == 1) random_curves_with_any_torsion(a4, a6, tx, ty, ncurves, p, pi); else if (m <= 10 || m == 12) random_curves_with_rational_X1(a4, a6, tx, ty, ncurves, m, p, pi); else if (m == 11 || m == 14 || m == 15) random_curves_with_elliptic_X1(a4, a6, tx, ty, ncurves, m, p, pi); else random_curves_with_general_X1(a4, a6, tx, ty, ncurves, m, p, pi); /* The likelihood of getting *any* zero discriminants is small * enough that we can check using this slightly roundabout and * expensive manner. */ while (ncurves--) { ulong d = Fl_elldisc_pre(*a4, *a6, p, pi); if (d == 0) /* should almost never be true */ random_curves_with_m_torsion(a4, a6, tx, ty, 1L, m, p); ++a4; ++a6; ++tx; ++ty; } } #define vZ evalvarn(1) /* variable number for secondary variable */ static const long FLX_0[3] = { evaltyp(t_VECSMALL) | _evallg(2), vZ }; static const long FLX_1[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, 1 }; static const long FLX_m1[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, -1 }; static const long FLX_Z[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 1 }; static const long FLX_mZ[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, -1 }; /* * X1 Curves database follows! */ /* x^2 + (z^3 + z^2 + 1)*x + (-z^2 - z) */ static const long X1_13_crv_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, -1, -1 }; /* -z^2 - z */ static const long X1_13_crv_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, 0, 1, 1 }; /* z^3 + z^2 + 1 */ static const long *X1_13_crv[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_13_crv_0, X1_13_crv_1, FLX_1 }; /* -z*x + 1 */ static const long *X1_13_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1, FLX_mZ }; /* 1 */ static const long *X1_13_r_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1 }; /* -z*x */ static const long *X1_13_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, FLX_mZ }; /* x + 1 */ static const long *X1_13_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1, FLX_1 }; /* x^2 + (z^2 + z)*x + z */ static const long X1_14_crv_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 1, 1 }; /* z^2 + z */ static const long *X1_14_crv[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), FLX_Z, X1_14_crv_1, FLX_1 }; /* -x - z */ static const long *X1_14_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_mZ, FLX_m1 }; /* x^2 + (z + 2)*x + (z + 1) */ static const long X1_14_r_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long X1_14_r_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 2, 1 }; /* z + 2 */ static const long *X1_14_r_d[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_14_r_d_0, X1_14_r_d_1, FLX_1 }; /* (-z + 1) */ static const long X1_14_s_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, -1 }; /* -z + 1 */ static const long *X1_14_s_n[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_14_s_n_0 }; /* x + 1 */ static const long *X1_14_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1, FLX_1 }; /* x^2 + (z^2 + z + 1)*x + z^2 */ static const long X1_15_crv_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, 1 }; /* z^2 */ static const long X1_15_crv_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, 1, 1 }; /* z^2 + z + 1 */ static const long *X1_15_crv[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_15_crv_0, X1_15_crv_1, FLX_1 }; /* x^2 + z*x */ static const long *X1_15_r_n[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, FLX_Z, FLX_1 }; /* z^2*x + (z^3 + z^2) */ static const long X1_15_r_d_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 1, 1 }; /* z^3 + z^2 */ static const long X1_15_r_d_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, 1 }; /* z^2 */ static const long *X1_15_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_15_r_d_0, X1_15_r_d_1 }; /* x */ static const long *X1_15_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, FLX_1 }; /* (z^2 + z) */ static const long X1_15_s_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 1, 1 }; /* z^2 + z */ static const long *X1_15_s_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_15_s_d_0 }; /* x^2 + (z^3 + z^2 - z + 1)*x + z^2 */ static const long X1_16_crv_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, 1 }; /* z^2 */ static const long X1_16_crv_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, -1, 1, 1 }; /* z^3 + z^2 - z + 1 */ static const long *X1_16_crv[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_16_crv_0, X1_16_crv_1, FLX_1 }; /* x^2 + (-z + 1)*x + z^2 */ static const long X1_16_r_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, 1 }; /* z^2 */ static const long X1_16_r_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, -1 }; /* -z + 1 */ static const long *X1_16_r_n[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_16_r_n_0, X1_16_r_n_1, FLX_1 }; /* -x + (z^2 + z - 1) */ static const long X1_16_r_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -1, 1, 1 }; /* z^2 + z - 1 */ static const long *X1_16_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_16_r_d_0, FLX_m1 }; /* -x + z */ static const long *X1_16_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_Z, FLX_m1 }; /* (z + 1) */ static const long X1_16_s_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_16_s_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_16_s_d_0 }; /* x^4 + (z^3 + z^2 - z + 2)*x^3 + (z^3 - 3*z + 1)*x^2 + (-z^4 - 2*z)*x + (z^3 + z^2) */ static const long X1_17_crv_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 1, 1 }; /* z^3 + z^2 */ static const long X1_17_crv_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, -2, 0, 0, -1 }; /* -z^4 - 2*z */ static const long X1_17_crv_2[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, -3, 0, 1 }; /* z^3 - 3*z + 1 */ static const long X1_17_crv_3[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 2, -1, 1, 1 }; /* z^3 + z^2 - z + 2 */ static const long *X1_17_crv[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_17_crv_0, X1_17_crv_1, X1_17_crv_2, X1_17_crv_3, FLX_1 }; /* -x + (z^2 + z) */ static const long X1_17_r_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 1, 1 }; /* z^2 + z */ static const long *X1_17_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_17_r_n_0, FLX_m1 }; /* -x^2 + (z - 1)*x + (z^2 + z) */ static const long X1_17_r_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 1, 1 }; /* z^2 + z */ static const long X1_17_r_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, 1 }; /* z - 1 */ static const long *X1_17_r_d[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_17_r_d_0, X1_17_r_d_1, FLX_m1 }; /* (z + 1) */ static const long X1_17_s_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_17_s_n[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_17_s_n_0 }; /* x + (z + 1) */ static const long X1_17_s_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_17_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_17_s_d_0, FLX_1 }; /* x^2 + (z^3 - 2*z^2 + 3*z + 1)*x + 2*z */ static const long X1_18_crv_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 2 }; /* 2*z */ static const long X1_18_crv_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, 3, -2, 1 }; /* z^3 - 2*z^2 + 3*z + 1 */ static const long *X1_18_crv[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_18_crv_0, X1_18_crv_1, FLX_1 }; /* -z*x + (z^2 - 3*z + 1) */ static const long X1_18_r_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, -3, 1 }; /* z^2 - 3*z + 1 */ static const long *X1_18_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_18_r_n_0, FLX_mZ }; /* (z^3 - 2*z^2 + z)*x + (z^2 - 2*z + 1) */ static const long X1_18_r_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, -2, 1 }; /* z^2 - 2*z + 1 */ static const long X1_18_r_d_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 1, -2, 1 }; /* z^3 - 2*z^2 + z */ static const long *X1_18_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_18_r_d_0, X1_18_r_d_1 }; /* -x + (z^2 - 2*z) */ static const long X1_18_s_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, -2, 1 }; /* z^2 - 2*z */ static const long *X1_18_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_18_s_n_0, FLX_m1 }; /* -x^2 + (-z - 2)*x + (z^2 - 3*z) */ static const long X1_18_s_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, -3, 1 }; /* z^2 - 3*z */ static const long X1_18_s_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -2, -1 }; /* -z - 2 */ static const long *X1_18_s_d[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_18_s_d_0, X1_18_s_d_1, FLX_m1 }; /* x^5 + (-z^2 - 2)*x^4 + (-2*z^3 - 2*z^2 - 2*z + 1)*x^3 + (z^5 + 3*z^4 + 7*z^3 + 6*z^2 + 2*z)*x^2 + (-z^5 - 2*z^4 - 4*z^3 - 3*z^2)*x + (z^3 + z^2) */ static const long X1_19_crv_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 1, 1 }; /* z^3 + z^2 */ static const long X1_19_crv_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, -3, -4, -2, -1 }; /* -z^5 - 2*z^4 - 4*z^3 - 3*z^2 */ static const long X1_19_crv_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 2, 6, 7, 3, 1 }; /* z^5 + 3*z^4 + 7*z^3 + 6*z^2 + 2*z */ static const long X1_19_crv_3[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, -2, -2, -2 }; /* -2*z^3 - 2*z^2 - 2*z + 1 */ static const long X1_19_crv_4[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -2, 0, -1 }; /* -z^2 - 2 */ static const long *X1_19_crv[8] = { (long *)(evaltyp(t_POL) | _evallg(8)), (long *)(evalvarn(0) | evalsigne(1)), X1_19_crv_0, X1_19_crv_1, X1_19_crv_2, X1_19_crv_3, X1_19_crv_4, FLX_1 }; /* z*x^2 + (z^2 - z)*x - z^2 */ static const long X1_19_r_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, -1 }; /* -z^2 */ static const long X1_19_r_n_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, -1, 1 }; /* z^2 - z */ static const long *X1_19_r_n[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_19_r_n_0, X1_19_r_n_1, FLX_Z }; /* (-z - 1)*x^2 + (-z^2 + 1)*x + (z^3 + 3*z^2 + 2*z) */ static const long X1_19_r_d_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 2, 3, 1 }; /* z^3 + 3*z^2 + 2*z */ static const long X1_19_r_d_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, 0, -1 }; /* -z^2 + 1 */ static const long X1_19_r_d_2[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, -1 }; /* -z - 1 */ static const long *X1_19_r_d[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_19_r_d_0, X1_19_r_d_1, X1_19_r_d_2 }; /* z*x - z */ static const long *X1_19_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_mZ, FLX_Z }; /* (-z - 1)*x + (z^2 + 2*z + 1) */ static const long X1_19_s_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, 2, 1 }; /* z^2 + 2*z + 1 */ static const long X1_19_s_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, -1 }; /* -z - 1 */ static const long *X1_19_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_19_s_d_0, X1_19_s_d_1 }; /* x^3 - z^3*x^2 - z^2*x + z */ static const long X1_20_crv_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, -1 }; /* -z^2 */ static const long X1_20_crv_2[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 0, -1 }; /* -z^3 */ static const long *X1_20_crv[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), FLX_Z, X1_20_crv_1, X1_20_crv_2, FLX_1 }; /* -x + z */ static const long *X1_20_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_Z, FLX_m1 }; /* z*x - 1 */ static const long *X1_20_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_m1, FLX_Z }; /* 4*z^3*x^3 + (-4*z^4 - 8*z^2)*x^2 + (8*z^3 + 4*z)*x - 4*z^2 */ static const long X1_20_s_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, -4 }; /* -4*z^2 */ static const long X1_20_s_n_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 4, 0, 8 }; /* 8*z^3 + 4*z */ static const long X1_20_s_n_2[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, -8, 0, -4 }; /* -4*z^4 - 8*z^2 */ static const long X1_20_s_n_3[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 0, 4 }; /* 4*z^3 */ static const long *X1_20_s_n[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), X1_20_s_n_0, X1_20_s_n_1, X1_20_s_n_2, X1_20_s_n_3 }; /* (z^4 + 4*z^2 - 1)*x^3 + (-10*z^3 - 2*z)*x^2 + (3*z^4 + 8*z^2 + 1)*x + (-2*z^3 - 2*z) */ static const long X1_20_s_d_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -2, 0, -2 }; /* -2*z^3 - 2*z */ static const long X1_20_s_d_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, 0, 8, 0, 3 }; /* 3*z^4 + 8*z^2 + 1 */ static const long X1_20_s_d_2[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -2, 0, -10 }; /* -10*z^3 - 2*z */ static const long X1_20_s_d_3[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, -1, 0, 4, 0, 1 }; /* z^4 + 4*z^2 - 1 */ static const long *X1_20_s_d[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), X1_20_s_d_0, X1_20_s_d_1, X1_20_s_d_2, X1_20_s_d_3 }; /* x^4 + (3*z^2 + 1)*x^3 + (z^5 + z^4 + 2*z^2 + 2*z)*x^2 + (2*z^4 + z^3 + z)*x + z^3 */ static const long X1_21_crv_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 0, 1 }; /* z^3 */ static const long X1_21_crv_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 1, 0, 1, 2 }; /* 2*z^4 + z^3 + z */ static const long X1_21_crv_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 2, 2, 0, 1, 1 }; /* z^5 + z^4 + 2*z^2 + 2*z */ static const long X1_21_crv_3[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, 0, 3 }; /* 3*z^2 + 1 */ static const long *X1_21_crv[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_21_crv_0, X1_21_crv_1, X1_21_crv_2, X1_21_crv_3, FLX_1 }; /* (z + 1)*x^3 + (z + 2)*x^2 + x */ static const long X1_21_r_n_2[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 2, 1 }; /* z + 2 */ static const long X1_21_r_n_3[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_21_r_n[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, FLX_1, X1_21_r_n_2, X1_21_r_n_3 }; /* -z*x^3 + (z^2 - 1)*x^2 + 2*z*x + 1 */ static const long X1_21_r_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 2 }; /* 2*z */ static const long X1_21_r_d_2[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -1, 0, 1 }; /* z^2 - 1 */ static const long *X1_21_r_d[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1, X1_21_r_d_1, X1_21_r_d_2, FLX_mZ }; /* x^2 + x */ static const long *X1_21_s_n[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, FLX_1, FLX_1 }; /* z*x + 1 */ static const long *X1_21_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1, FLX_Z }; /* x^4 + (z^3 + 2*z^2 + z + 2)*x^3 + (z^5 + z^4 + 2*z^3 + 2*z^2 + 1)*x^2 + (z^5 - z^4 - 2*z^3 - z^2 - z)*x + (-z^4 - z^3) */ static const long X1_22_crv_0[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, 0, -1, -1 }; /* -z^4 - z^3 */ static const long X1_22_crv_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, -1, -1, -2, -1, 1 }; /* z^5 - z^4 - 2*z^3 - z^2 - z */ static const long X1_22_crv_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 1, 0, 2, 2, 1, 1 }; /* z^5 + z^4 + 2*z^3 + 2*z^2 + 1 */ static const long X1_22_crv_3[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 2, 1, 2, 1 }; /* z^3 + 2*z^2 + z + 2 */ static const long *X1_22_crv[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_22_crv_0, X1_22_crv_1, X1_22_crv_2, X1_22_crv_3, FLX_1 }; /* (z^2 + z + 1)*x + z^2 */ static const long X1_22_r_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, 1 }; /* z^2 */ static const long X1_22_r_n_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, 1, 1 }; /* z^2 + z + 1 */ static const long *X1_22_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_22_r_n_0, X1_22_r_n_1 }; /* x + (z^3 + 2*z^2) */ static const long X1_22_r_d_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 2, 1 }; /* z^3 + 2*z^2 */ static const long *X1_22_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_22_r_d_0, FLX_1 }; /* (z + 1)*x */ static const long X1_22_s_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_22_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, X1_22_s_n_1 }; /* x + z^2 */ static const long X1_22_s_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, 1 }; /* z^2 */ static const long *X1_22_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_22_s_d_0, FLX_1 }; /* x^7 + (z^5 - z^4 + z^3 + 4*z^2 + 3)*x^6 + (z^7 + 3*z^5 + z^4 + 5*z^3 + 7*z^2 - 4*z + 3)*x^5 + (2*z^7 + 3*z^5 - z^4 - 2*z^3 - z^2 - 8*z + 1)*x^4 + (z^7 - 4*z^6 - 5*z^5 - 6*z^4 - 6*z^3 - 2*z^2 - 3*z)*x^3 + (-3*z^6 + 5*z^4 + 3*z^3 + 3*z^2 + 2*z)*x^2 + (3*z^5 + 4*z^4 + z)*x + (-z^4 - 2*z^3 - z^2) */ static const long X1_23_crv_0[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, -1, -2, -1 }; /* -z^4 - 2*z^3 - z^2 */ static const long X1_23_crv_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 1, 0, 0, 4, 3 }; /* 3*z^5 + 4*z^4 + z */ static const long X1_23_crv_2[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 2, 3, 3, 5, 0, -3 }; /* -3*z^6 + 5*z^4 + 3*z^3 + 3*z^2 + 2*z */ static const long X1_23_crv_3[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, -3, -2, -6, -6, -5, -4, 1 }; /* z^7 - 4*z^6 - 5*z^5 - 6*z^4 - 6*z^3 - 2*z^2 - 3*z */ static const long X1_23_crv_4[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 1, -8, -1, -2, -1, 3, 0, 2 }; /* 2*z^7 + 3*z^5 - z^4 - 2*z^3 - z^2 - 8*z + 1 */ static const long X1_23_crv_5[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 3, -4, 7, 5, 1, 3, 0, 1 }; /* z^7 + 3*z^5 + z^4 + 5*z^3 + 7*z^2 - 4*z + 3 */ static const long X1_23_crv_6[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 3, 0, 4, 1, -1, 1 }; /* z^5 - z^4 + z^3 + 4*z^2 + 3 */ static const long *X1_23_crv[10] = { (long *)(evaltyp(t_POL) | _evallg(10)), (long *)(evalvarn(0) | evalsigne(1)), X1_23_crv_0, X1_23_crv_1, X1_23_crv_2, X1_23_crv_3, X1_23_crv_4, X1_23_crv_5, X1_23_crv_6, FLX_1 }; /* x + (z^2 + z + 1) */ static const long X1_23_r_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, 1, 1 }; /* z^2 + z + 1 */ static const long *X1_23_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_23_r_n_0, FLX_1 }; /* -z*x + z^2 */ static const long X1_23_r_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, 1 }; /* z^2 */ static const long *X1_23_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_23_r_d_0, FLX_mZ }; /* x + (z + 1) */ static const long X1_23_s_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_23_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_23_s_n_0, FLX_1 }; /* z */ static const long *X1_23_s_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_Z }; /* (z^2 - 3)*x^4 + (z^5 + 2*z^4 + 2*z^3 + 2*z^2 - 3*z)*x^2 + (-z^4 - z^2) */ static const long X1_24_crv_0[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, -1, 0, -1 }; /* -z^4 - z^2 */ static const long X1_24_crv_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, -3, 2, 2, 2, 1 }; /* z^5 + 2*z^4 + 2*z^3 + 2*z^2 - 3*z */ static const long X1_24_crv_4[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -3, 0, 1 }; /* z^2 - 3 */ static const long *X1_24_crv[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_24_crv_0, FLX_0, X1_24_crv_2, FLX_0, X1_24_crv_4 }; /* x */ static const long *X1_24_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, FLX_1 }; /* 1 */ static const long *X1_24_r_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1 }; /* 4*x^3 + 4*z*x */ static const long X1_24_s_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 4 }; /* 4*z */ static const long X1_24_s_n_3[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, 4 }; /* 4 */ static const long *X1_24_s_n[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, X1_24_s_n_1, FLX_0, X1_24_s_n_3 }; /* (z - 2)*x^4 + (-4*z - 2)*x^2 - z */ static const long X1_24_s_d_2[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -2, -4 }; /* -4*z - 2 */ static const long X1_24_s_d_4[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -2, 1 }; /* z - 2 */ static const long *X1_24_s_d[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), FLX_mZ, FLX_0, X1_24_s_d_2, FLX_0, X1_24_s_d_4 }; /* z*u^5 + (z^4 - 2*z^3 - z^2 + 2*z + 1)*u^4 + (-2*z^6 + 2*z^4 - 4*z^3 - 2*z^2 + 2)*u^3 + (z^8 + z^7 - 2*z^6 + z^5 - z^4 - z^3 - 2*z^2 - z + 1)*u^2 + (z^8 + z^7 + 2*z^6 + z^5 - 2*z^4 + z^3 - z^2)*u + z^6 */ static const long X1_25_crv_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 0, 0, 0, 1 }; /* z^6 */ static const long X1_25_crv_1[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, -1, 1, -2, 1, 2, 1, 1 }; /* z^8 + z^7 + 2*z^6 + z^5 - 2*z^4 + z^3 - z^2 */ static const long X1_25_crv_2[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 1, -1, -2, -1, -1, 1, -2, 1, 1 }; /* z^8 + z^7 - 2*z^6 + z^5 - z^4 - z^3 - 2*z^2 - z + 1 */ static const long X1_25_crv_3[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 2, 0, -2, -4, 2, 0, -2 }; /* -2*z^6 + 2*z^4 - 4*z^3 - 2*z^2 + 2 */ static const long X1_25_crv_4[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, 2, -1, -2, 1 }; /* z^4 - 2*z^3 - z^2 + 2*z + 1 */ static const long *X1_25_crv[8] = { (long *)(evaltyp(t_POL) | _evallg(8)), (long *)(evalvarn(0) | evalsigne(1)), X1_25_crv_0, X1_25_crv_1, X1_25_crv_2, X1_25_crv_3, X1_25_crv_4, FLX_Z }; /* -z^2*u^6 + (2*z^4 - 2*z^2 - 2*z)*u^5 + (-z^6 + 2*z^5 + 5*z^4 + z^3 - 4*z - 1)*u^4 + (-2*z^7 - 3*z^6 + 4*z^5 + 4*z^4 + 5*z^3 - z - 2)*u^3 + (-z^8 - 4*z^7 - 2*z^6 - z^5 + 3*z^4 + 5*z^3 - z^2 + z - 1)*u^2 + (-z^8 - z^7 - 2*z^6 - 3*z^5 + 2*z^4 + z^3)*u - z^6 */ static const long X1_25_r_n_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 0, 0, 0, -1 }; /* -z^6 */ static const long X1_25_r_n_1[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 1, 2, -3, -2, -1, -1 }; /* -z^8 - z^7 - 2*z^6 - 3*z^5 + 2*z^4 + z^3 */ static const long X1_25_r_n_2[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 1, -1, 5, 3, -1, -2, -4, -1 }; /* -z^8 - 4*z^7 - 2*z^6 - z^5 + 3*z^4 + 5*z^3 - z^2 + z - 1 */ static const long X1_25_r_n_3[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -2, -1, 0, 5, 4, 4, -3, -2 }; /* -2*z^7 - 3*z^6 + 4*z^5 + 4*z^4 + 5*z^3 - z - 2 */ static const long X1_25_r_n_4[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, -4, 0, 1, 5, 2, -1 }; /* -z^6 + 2*z^5 + 5*z^4 + z^3 - 4*z - 1 */ static const long X1_25_r_n_5[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, -2, -2, 0, 2 }; /* 2*z^4 - 2*z^2 - 2*z */ static const long X1_25_r_n_6[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, -1 }; /* -z^2 */ static const long *X1_25_r_n[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_25_r_n_0, X1_25_r_n_1, X1_25_r_n_2, X1_25_r_n_3, X1_25_r_n_4, X1_25_r_n_5, X1_25_r_n_6 }; /* -z^2*u^6 + (2*z^4 + z^3 - 2*z^2 - 2*z)*u^5 + (-z^6 + 7*z^4 + 3*z^3 + z^2 - 4*z - 1)*u^4 + (-z^7 - 8*z^6 + z^5 + 7*z^4 + 7*z^3 + 2*z^2 - z - 2)*u^3 + (2*z^8 - 6*z^7 - 11*z^6 - 2*z^5 + 3*z^4 + 7*z^3 + z - 1)*u^2 + (3*z^9 + 3*z^8 - 6*z^7 - 6*z^6 - 3*z^5 + z^4 + 2*z^3)*u + (z^10 + 3*z^9 + z^8 - 2*z^7 - z^6) */ static const long X1_25_r_d_0[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 0, 0, 0, -1, -2, 1, 3, 1 }; /* z^10 + 3*z^9 + z^8 - 2*z^7 - z^6 */ static const long X1_25_r_d_1[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 2, 1, -3, -6, -6, 3, 3 }; /* 3*z^9 + 3*z^8 - 6*z^7 - 6*z^6 - 3*z^5 + z^4 + 2*z^3 */ static const long X1_25_r_d_2[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 1, 0, 7, 3, -2, -11, -6, 2 }; /* 2*z^8 - 6*z^7 - 11*z^6 - 2*z^5 + 3*z^4 + 7*z^3 + z - 1 */ static const long X1_25_r_d_3[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -2, -1, 2, 7, 7, 1, -8, -1 }; /* -z^7 - 8*z^6 + z^5 + 7*z^4 + 7*z^3 + 2*z^2 - z - 2 */ static const long X1_25_r_d_4[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, -4, 1, 3, 7, 0, -1 }; /* -z^6 + 7*z^4 + 3*z^3 + z^2 - 4*z - 1 */ static const long X1_25_r_d_5[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, -2, -2, 1, 2 }; /* 2*z^4 + z^3 - 2*z^2 - 2*z */ static const long X1_25_r_d_6[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, -1 }; /* -z^2 */ static const long *X1_25_r_d[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_25_r_d_0, X1_25_r_d_1, X1_25_r_d_2, X1_25_r_d_3, X1_25_r_d_4, X1_25_r_d_5, X1_25_r_d_6 }; /* -z*u^3 + (z^3 - z - 1)*u^2 + (z^4 + z^3 - z^2 + z - 1)*u + z^4 */ static const long X1_25_s_n_0[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, 0, 0, 1 }; /* z^4 */ static const long X1_25_s_n_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, -1, 1, -1, 1, 1 }; /* z^4 + z^3 - z^2 + z - 1 */ static const long X1_25_s_n_2[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -1, -1, 0, 1 }; /* z^3 - z - 1 */ static const long *X1_25_s_n[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), X1_25_s_n_0, X1_25_s_n_1, X1_25_s_n_2, FLX_mZ }; /* -z*u^3 + (z^3 + z^2 - z - 1)*u^2 + (2*z^3 + z - 1)*u + (-z^5 + z^3) */ static const long X1_25_s_d_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 0, 1, 0, -1 }; /* -z^5 + z^3 */ static const long X1_25_s_d_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -1, 1, 0, 2 }; /* 2*z^3 + z - 1 */ static const long X1_25_s_d_2[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -1, -1, 1, 1 }; /* z^3 + z^2 - z - 1 */ static const long *X1_25_s_d[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), X1_25_s_d_0, X1_25_s_d_1, X1_25_s_d_2, FLX_mZ }; /* x^6 + (3*z^2 + 4*z - 2)*x^5 + (3*z^4 + 10*z^3 - 9*z + 1)*x^4 + (z^6 + 7*z^5 + 8*z^4 - 14*z^3 - 11*z^2 + 6*z)*x^3 + (z^7 + 4*z^6 - z^5 - 13*z^4 + 2*z^3 + 10*z^2 - z)*x^2 + (-z^6 + 7*z^4 + 4*z^3 - 2*z^2)*x + (-z^4 - z^3) */ static const long X1_26_crv_0[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, 0, -1, -1 }; /* -z^4 - z^3 */ static const long X1_26_crv_1[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, -2, 4, 7, 0, -1 }; /* -z^6 + 7*z^4 + 4*z^3 - 2*z^2 */ static const long X1_26_crv_2[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, -1, 10, 2, -13, -1, 4, 1 }; /* z^7 + 4*z^6 - z^5 - 13*z^4 + 2*z^3 + 10*z^2 - z */ static const long X1_26_crv_3[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 6, -11, -14, 8, 7, 1 }; /* z^6 + 7*z^5 + 8*z^4 - 14*z^3 - 11*z^2 + 6*z */ static const long X1_26_crv_4[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, -9, 0, 10, 3 }; /* 3*z^4 + 10*z^3 - 9*z + 1 */ static const long X1_26_crv_5[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -2, 4, 3 }; /* 3*z^2 + 4*z - 2 */ static const long *X1_26_crv[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_26_crv_0, X1_26_crv_1, X1_26_crv_2, X1_26_crv_3, X1_26_crv_4, X1_26_crv_5, FLX_1 }; /* z*x^2 + (z^3 + 3*z^2)*x - z^2 */ static const long X1_26_r_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, -1 }; /* -z^2 */ static const long X1_26_r_n_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 3, 1 }; /* z^3 + 3*z^2 */ static const long *X1_26_r_n[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_26_r_n_0, X1_26_r_n_1, FLX_Z }; /* (z + 1)*x^2 + (z^3 + 4*z^2 + 3*z)*x + (z^3 + z^2) */ static const long X1_26_r_d_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 1, 1 }; /* z^3 + z^2 */ static const long X1_26_r_d_1[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 3, 4, 1 }; /* z^3 + 4*z^2 + 3*z */ static const long X1_26_r_d_2[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_26_r_d[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_26_r_d_0, X1_26_r_d_1, X1_26_r_d_2 }; /* z*x - z */ static const long *X1_26_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_mZ, FLX_Z }; /* (z + 1)*x */ static const long X1_26_s_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_26_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_0, X1_26_s_d_1 }; /* (z^2 - 2*z + 1)*u^6 + (z^5 - 2*z^4 + z^3 + 2*z^2 - 4*z + 2)*u^5 + (-z^7 + 5*z^5 - 5*z^4 + 2*z^3 - 2*z^2 + 1)*u^4 + (z^8 - 4*z^7 - z^6 + 5*z^5 + 2*z^3 - 5*z^2 + 2*z)*u^3 + (3*z^8 - 4*z^7 - 2*z^6 - 2*z^5 + 3*z^4 + 2*z^3 - z^2 + z)*u^2 + (3*z^8 - 3*z^5)*u + (z^8 + z^7 + z^6) */ static const long X1_27_crv_0[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, 0, 0, 1, 1, 1 }; /* z^8 + z^7 + z^6 */ static const long X1_27_crv_1[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, 0, -3, 0, 0, 3 }; /* 3*z^8 - 3*z^5 */ static const long X1_27_crv_2[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 1, -1, 2, 3, -2, -2, -4, 3 }; /* 3*z^8 - 4*z^7 - 2*z^6 - 2*z^5 + 3*z^4 + 2*z^3 - z^2 + z */ static const long X1_27_crv_3[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 2, -5, 2, 0, 5, -1, -4, 1 }; /* z^8 - 4*z^7 - z^6 + 5*z^5 + 2*z^3 - 5*z^2 + 2*z */ static const long X1_27_crv_4[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 1, 0, -2, 2, -5, 5, 0, -1 }; /* -z^7 + 5*z^5 - 5*z^4 + 2*z^3 - 2*z^2 + 1 */ static const long X1_27_crv_5[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 2, -4, 2, 1, -2, 1 }; /* z^5 - 2*z^4 + z^3 + 2*z^2 - 4*z + 2 */ static const long X1_27_crv_6[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, -2, 1 }; /* z^2 - 2*z + 1 */ static const long *X1_27_crv[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_27_crv_0, X1_27_crv_1, X1_27_crv_2, X1_27_crv_3, X1_27_crv_4, X1_27_crv_5, X1_27_crv_6 }; /* (-z^4 + 2*z^2 - 2*z + 1)*u^4 + (z^5 - 4*z^4 - z^3 + 6*z^2 - 4*z + 2)*u^3 + (3*z^5 - 5*z^4 - 2*z^3 + 5*z^2 - z + 1)*u^2 + (3*z^5 - 2*z^4 - z^3 + z^2)*u + z^5 */ static const long X1_27_r_n_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 0, 0, 0, 1 }; /* z^5 */ static const long X1_27_r_n_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 1, -1, -2, 3 }; /* 3*z^5 - 2*z^4 - z^3 + z^2 */ static const long X1_27_r_n_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 1, -1, 5, -2, -5, 3 }; /* 3*z^5 - 5*z^4 - 2*z^3 + 5*z^2 - z + 1 */ static const long X1_27_r_n_3[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 2, -4, 6, -1, -4, 1 }; /* z^5 - 4*z^4 - z^3 + 6*z^2 - 4*z + 2 */ static const long X1_27_r_n_4[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, -2, 2, 0, -1 }; /* -z^4 + 2*z^2 - 2*z + 1 */ static const long *X1_27_r_n[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_27_r_n_0, X1_27_r_n_1, X1_27_r_n_2, X1_27_r_n_3, X1_27_r_n_4 }; /* (-z^3 + z^2 - z + 1)*u^4 + (z^5 - z^4 - 2*z^3 + z^2 - z + 2)*u^3 + (3*z^5 - 2*z^4 - z^3 - 2*z^2 + 2*z + 1)*u^2 + (3*z^5 - z^4 - 3*z^2 + z)*u + (z^5 - z^2) */ static const long X1_27_r_d_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, -1, 0, 0, 1 }; /* z^5 - z^2 */ static const long X1_27_r_d_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 1, -3, 0, -1, 3 }; /* 3*z^5 - z^4 - 3*z^2 + z */ static const long X1_27_r_d_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 1, 2, -2, -1, -2, 3 }; /* 3*z^5 - 2*z^4 - z^3 - 2*z^2 + 2*z + 1 */ static const long X1_27_r_d_3[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 2, -1, 1, -2, -1, 1 }; /* z^5 - z^4 - 2*z^3 + z^2 - z + 2 */ static const long X1_27_r_d_4[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, -1, 1, -1 }; /* -z^3 + z^2 - z + 1 */ static const long *X1_27_r_d[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_27_r_d_0, X1_27_r_d_1, X1_27_r_d_2, X1_27_r_d_3, X1_27_r_d_4 }; /* (z^3 - 2*z + 1)*u^3 + (-z^4 + 2*z^3 + z^2 - 4*z + 2)*u^2 + (-2*z^4 + z^3 + z^2 - z + 1)*u - z^4 */ static const long X1_27_s_n_0[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, 0, 0, -1 }; /* -z^4 */ static const long X1_27_s_n_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, -1, 1, 1, -2 }; /* -2*z^4 + z^3 + z^2 - z + 1 */ static const long X1_27_s_n_2[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 2, -4, 1, 2, -1 }; /* -z^4 + 2*z^3 + z^2 - 4*z + 2 */ static const long X1_27_s_n_3[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, -2, 0, 1 }; /* z^3 - 2*z + 1 */ static const long *X1_27_s_n[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), X1_27_s_n_0, X1_27_s_n_1, X1_27_s_n_2, X1_27_s_n_3 }; /* (-z + 1)*u^3 + (-z^4 - z + 2)*u^2 + (-2*z^4 + 2*z + 1)*u + (-z^4 + z) */ static const long X1_27_s_d_0[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 1, 0, 0, -1 }; /* -z^4 + z */ static const long X1_27_s_d_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, 2, 0, 0, -2 }; /* -2*z^4 + 2*z + 1 */ static const long X1_27_s_d_2[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 2, -1, 0, 0, -1 }; /* -z^4 - z + 2 */ static const long X1_27_s_d_3[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, -1 }; /* -z + 1 */ static const long *X1_27_s_d[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), X1_27_s_d_0, X1_27_s_d_1, X1_27_s_d_2, X1_27_s_d_3 }; /* (z^5 + 3*z^4 + 3*z^3 + z^2)*x^6 + (z^8 + 2*z^7 + z^6 + 11*z^4 + 22*z^3 + 11*z^2)*x^5 + (9*z^7 + 9*z^6 - 6*z^5 - 6*z^4 + 45*z^3 + 45*z^2)*x^4 + (-5*z^8 + 28*z^6 - 42*z^4 + 84*z^2 - 1)*x^3 + (-25*z^7 + 25*z^6 + 23*z^5 - 23*z^4 - 67*z^3 + 67*z^2 + 5*z - 5)*x^2 + (6*z^8 - 12*z^7 - 12*z^6 + 36*z^5 - 36*z^3 + 12*z^2 + 12*z - 6)*x + (-z^9 + 3*z^8 - 8*z^6 + 6*z^5 + 6*z^4 - 8*z^3 + 3*z - 1) */ static const long X1_28_crv_0[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, -1, 3, 0, -8, 6, 6, -8, 0, 3, -1 }; /* -z^9 + 3*z^8 - 8*z^6 + 6*z^5 + 6*z^4 - 8*z^3 + 3*z - 1 */ static const long X1_28_crv_1[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -6, 12, 12, -36, 0, 36, -12, -12, 6 }; /* 6*z^8 - 12*z^7 - 12*z^6 + 36*z^5 - 36*z^3 + 12*z^2 + 12*z - 6 */ static const long X1_28_crv_2[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -5, 5, 67, -67, -23, 23, 25, -25 }; /* -25*z^7 + 25*z^6 + 23*z^5 - 23*z^4 - 67*z^3 + 67*z^2 + 5*z - 5 */ static const long X1_28_crv_3[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 0, 84, 0, -42, 0, 28, 0, -5 }; /* -5*z^8 + 28*z^6 - 42*z^4 + 84*z^2 - 1 */ static const long X1_28_crv_4[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, 0, 45, 45, -6, -6, 9, 9 }; /* 9*z^7 + 9*z^6 - 6*z^5 - 6*z^4 + 45*z^3 + 45*z^2 */ static const long X1_28_crv_5[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 11, 22, 11, 0, 1, 2, 1 }; /* z^8 + 2*z^7 + z^6 + 11*z^4 + 22*z^3 + 11*z^2 */ static const long X1_28_crv_6[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 1, 3, 3, 1 }; /* z^5 + 3*z^4 + 3*z^3 + z^2 */ static const long *X1_28_crv[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_28_crv_0, X1_28_crv_1, X1_28_crv_2, X1_28_crv_3, X1_28_crv_4, X1_28_crv_5, X1_28_crv_6 }; /* (z + 1)*x + 2 */ static const long X1_28_r_n_0[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, 2 }; /* 2 */ static const long X1_28_r_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_28_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_28_r_n_0, X1_28_r_n_1 }; /* 2*z */ static const long X1_28_r_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 2 }; /* 2*z */ static const long *X1_28_r_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_28_r_d_0 }; /* (-z - 1)*x - 2 */ static const long X1_28_s_n_0[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, -2 }; /* -2 */ static const long X1_28_s_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, -1 }; /* -z - 1 */ static const long *X1_28_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_28_s_n_0, X1_28_s_n_1 }; /* 2 */ static const long X1_28_s_d_0[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, 2 }; /* 2 */ static const long *X1_28_s_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_28_s_d_0 }; /* x^11 + (2*z^3 + 5*z^2 + 5*z - 3)*x^10 + (z^6 + 8*z^5 + 18*z^4 + 11*z^3 - 5*z^2 - 12*z + 3)*x^9 + (3*z^8 + 15*z^7 + 29*z^6 + 6*z^5 - 39*z^4 - 19*z^3 + 5*z^2 + 5*z - 1)*x^8 + (3*z^10 + 14*z^9 + 18*z^8 - 26*z^7 - 99*z^6 - 45*z^5 + 95*z^4 + 25*z^3 - 37*z^2 + 7*z)*x^7 + (z^12 + 5*z^11 - 44*z^9 - 106*z^8 - 40*z^7 + 197*z^6 + 190*z^5 - 140*z^4 - 93*z^3 + 59*z^2 - 6*z)*x^6 + (-2*z^12 - 16*z^11 - 37*z^10 + 9*z^9 + 184*z^8 + 256*z^7 - 99*z^6 - 346*z^5 + 20*z^4 + 130*z^3 - 32*z^2 + z)*x^5 + (z^12 + 15*z^11 + 65*z^10 + 99*z^9 - 55*z^8 - 320*z^7 - 165*z^6 + 223*z^5 + 100*z^4 - 66*z^3 + 5*z^2)*x^4 + (-4*z^11 - 36*z^10 - 108*z^9 - 98*z^8 + 110*z^7 + 191*z^6 - 15*z^5 - 64*z^4 + 10*z^3)*x^3 + (6*z^10 + 38*z^9 + 76*z^8 + 25*z^7 - 55*z^6 - 26*z^5 + 10*z^4)*x^2 + (-4*z^9 - 17*z^8 - 18*z^7 + 5*z^5)*x + (z^8 + 2*z^7 + z^6) */ static const long X1_29_crv_0[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, 0, 0, 1, 2, 1 }; /* z^8 + 2*z^7 + z^6 */ static const long X1_29_crv_1[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 5, 0, -18, -17, -4 }; /* -4*z^9 - 17*z^8 - 18*z^7 + 5*z^5 */ static const long X1_29_crv_2[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 0, 10, -26, -55, 25, 76, 38, 6 }; /* 6*z^10 + 38*z^9 + 76*z^8 + 25*z^7 - 55*z^6 - 26*z^5 + 10*z^4 */ static const long X1_29_crv_3[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 10, -64, -15, 191, 110, -98, -108, -36, -4 }; /* -4*z^11 - 36*z^10 - 108*z^9 - 98*z^8 + 110*z^7 + 191*z^6 - 15*z^5 - 64*z^4 + 10*z^3 */ static const long X1_29_crv_4[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 5, -66, 100, 223, -165, -320, -55, 99, 65, 15, 1 }; /* z^12 + 15*z^11 + 65*z^10 + 99*z^9 - 55*z^8 - 320*z^7 - 165*z^6 + 223*z^5 + 100*z^4 - 66*z^3 + 5*z^2 */ static const long X1_29_crv_5[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 1, -32, 130, 20, -346, -99, 256, 184, 9, -37, -16, -2 }; /* -2*z^12 - 16*z^11 - 37*z^10 + 9*z^9 + 184*z^8 + 256*z^7 - 99*z^6 - 346*z^5 + 20*z^4 + 130*z^3 - 32*z^2 + z */ static const long X1_29_crv_6[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, -6, 59, -93, -140, 190, 197, -40, -106, -44, 0, 5, 1 }; /* z^12 + 5*z^11 - 44*z^9 - 106*z^8 - 40*z^7 + 197*z^6 + 190*z^5 - 140*z^4 - 93*z^3 + 59*z^2 - 6*z */ static const long X1_29_crv_7[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 7, -37, 25, 95, -45, -99, -26, 18, 14, 3 }; /* 3*z^10 + 14*z^9 + 18*z^8 - 26*z^7 - 99*z^6 - 45*z^5 + 95*z^4 + 25*z^3 - 37*z^2 + 7*z */ static const long X1_29_crv_8[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 5, 5, -19, -39, 6, 29, 15, 3 }; /* 3*z^8 + 15*z^7 + 29*z^6 + 6*z^5 - 39*z^4 - 19*z^3 + 5*z^2 + 5*z - 1 */ static const long X1_29_crv_9[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 3, -12, -5, 11, 18, 8, 1 }; /* z^6 + 8*z^5 + 18*z^4 + 11*z^3 - 5*z^2 - 12*z + 3 */ static const long X1_29_crv_10[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -3, 5, 5, 2 }; /* 2*z^3 + 5*z^2 + 5*z - 3 */ static const long *X1_29_crv[14] = { (long *)(evaltyp(t_POL) | _evallg(14)), (long *)(evalvarn(0) | evalsigne(1)), X1_29_crv_0, X1_29_crv_1, X1_29_crv_2, X1_29_crv_3, X1_29_crv_4, X1_29_crv_5, X1_29_crv_6, X1_29_crv_7, X1_29_crv_8, X1_29_crv_9, X1_29_crv_10, FLX_1 }; /* -x + (-z^3 - z^2 - z) */ static const long X1_29_r_n_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -1, -1, -1 }; /* -z^3 - z^2 - z */ static const long *X1_29_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_29_r_n_0, FLX_m1 }; /* (z^2 + z - 1)*x - z */ static const long X1_29_r_d_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -1, 1, 1 }; /* z^2 + z - 1 */ static const long *X1_29_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_mZ, X1_29_r_d_1 }; /* -z*x - z^2 */ static const long X1_29_s_n_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 0, 0, -1 }; /* -z^2 */ static const long *X1_29_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_29_s_n_0, FLX_mZ }; /* (z - 1)*x - z */ static const long X1_29_s_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, 1 }; /* z - 1 */ static const long *X1_29_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_mZ, X1_29_s_d_1 }; /* x^6 + (z^6 - 5*z^5 + 6*z^4 + 3*z^3 - 6*z^2 + 7*z + 3)*x^5 + (z^7 - 3*z^6 - 13*z^5 + 44*z^4 - 18*z^3 + z^2 + 18*z + 3)*x^4 + (z^8 - 3*z^7 - 13*z^6 + 27*z^5 + 46*z^4 - 32*z^3 + 21*z^2 + 15*z + 1)*x^3 + (2*z^8 - 16*z^7 + 18*z^6 + 40*z^5 + 12*z^4 - 12*z^3 + 18*z^2 + 4*z)*x^2 + (-8*z^7 + 28*z^6 + 12*z^5 + 4*z^2)*x + 8*z^6 */ static const long X1_30_crv_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 0, 0, 0, 8 }; /* 8*z^6 */ static const long X1_30_crv_1[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, 0, 4, 0, 0, 12, 28, -8 }; /* -8*z^7 + 28*z^6 + 12*z^5 + 4*z^2 */ static const long X1_30_crv_2[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 4, 18, -12, 12, 40, 18, -16, 2 }; /* 2*z^8 - 16*z^7 + 18*z^6 + 40*z^5 + 12*z^4 - 12*z^3 + 18*z^2 + 4*z */ static const long X1_30_crv_3[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 1, 15, 21, -32, 46, 27, -13, -3, 1 }; /* z^8 - 3*z^7 - 13*z^6 + 27*z^5 + 46*z^4 - 32*z^3 + 21*z^2 + 15*z + 1 */ static const long X1_30_crv_4[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 3, 18, 1, -18, 44, -13, -3, 1 }; /* z^7 - 3*z^6 - 13*z^5 + 44*z^4 - 18*z^3 + z^2 + 18*z + 3 */ static const long X1_30_crv_5[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 3, 7, -6, 3, 6, -5, 1 }; /* z^6 - 5*z^5 + 6*z^4 + 3*z^3 - 6*z^2 + 7*z + 3 */ static const long *X1_30_crv[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_30_crv_0, X1_30_crv_1, X1_30_crv_2, X1_30_crv_3, X1_30_crv_4, X1_30_crv_5, FLX_1 }; /* x + 1 */ static const long *X1_30_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1, FLX_1 }; /* 1 */ static const long *X1_30_r_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1 }; /* 4*x^2 + (4*z + 4)*x + 4*z */ static const long X1_30_s_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 4 }; /* 4*z */ static const long X1_30_s_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 4, 4 }; /* 4*z + 4 */ static const long X1_30_s_n_2[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, 4 }; /* 4 */ static const long *X1_30_s_n[5] = { (long *)(evaltyp(t_POL) | _evallg(5)), (long *)(evalvarn(0) | evalsigne(1)), X1_30_s_n_0, X1_30_s_n_1, X1_30_s_n_2 }; /* (z - 3)*x^3 - 6*x^2 + (-4*z - 4)*x - 4*z */ static const long X1_30_s_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, -4 }; /* -4*z */ static const long X1_30_s_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -4, -4 }; /* -4*z - 4 */ static const long X1_30_s_d_2[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, -6 }; /* -6 */ static const long X1_30_s_d_3[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -3, 1 }; /* z - 3 */ static const long *X1_30_s_d[6] = { (long *)(evaltyp(t_POL) | _evallg(6)), (long *)(evalvarn(0) | evalsigne(1)), X1_30_s_d_0, X1_30_s_d_1, X1_30_s_d_2, X1_30_s_d_3 }; /* u^12 + (z^10 - z^9 - 8*z^8 + 6*z^7 + 23*z^6 - 12*z^5 - 26*z^4 + 8*z^3 + 10*z^2 + 7*z - 3)*u^11 + (z^11 - 8*z^10 - 11*z^9 + 61*z^8 + 45*z^7 - 152*z^6 - 70*z^5 + 129*z^4 + 37*z^3 - 24*z + 3)*u^10 + (-8*z^11 + 17*z^10 + 105*z^9 - 93*z^8 - 387*z^7 + 145*z^6 + 453*z^5 - 57*z^4 - 91*z^3 - 73*z^2 + 31*z - 1)*u^9 + (-z^12 + 25*z^11 + 27*z^10 - 273*z^9 - 260*z^8 + 745*z^7 + 569*z^6 - 572*z^5 - 266*z^4 - 36*z^3 + 131*z^2 - 19*z)*u^8 + (5*z^12 - 32*z^11 - 162*z^10 + 193*z^9 + 911*z^8 - 147*z^7 - 1254*z^6 - 78*z^5 + 301*z^4 + 222*z^3 - 99*z^2 + 6*z)*u^7 + (-10*z^12 + 240*z^10 + 268*z^9 - 864*z^8 - 967*z^7 + 713*z^6 + 598*z^5 + 28*z^4 - 216*z^3 + 37*z^2 - z)*u^6 + (10*z^12 + 44*z^11 - 115*z^10 - 537*z^9 + 19*z^8 + 1033*z^7 + 242*z^6 - 351*z^5 - 200*z^4 + 91*z^3 - 6*z^2)*u^5 + (-5*z^12 - 47*z^11 - 52*z^10 + 293*z^9 + 448*z^8 - 266*z^7 - 390*z^6 - 17*z^5 + 112*z^4 - 15*z^3)*u^4 + (z^12 + 20*z^11 + 76*z^10 - z^9 - 247*z^8 - 119*z^7 + 103*z^6 + 68*z^5 - 20*z^4)*u^3 + (-3*z^11 - 27*z^10 - 49*z^9 + 25*z^8 + 67*z^7 + 13*z^6 - 15*z^5)*u^2 + (3*z^10 + 14*z^9 + 11*z^8 - 5*z^7 - 6*z^6)*u + (-z^9 - 2*z^8 - z^7) */ static const long X1_31_crv_0[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 0, 0, -1, -2, -1 }; /* -z^9 - 2*z^8 - z^7 */ static const long X1_31_crv_1[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 0, 0, 0, -6, -5, 11, 14, 3 }; /* 3*z^10 + 14*z^9 + 11*z^8 - 5*z^7 - 6*z^6 */ static const long X1_31_crv_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 0, 0, -15, 13, 67, 25, -49, -27, -3 }; /* -3*z^11 - 27*z^10 - 49*z^9 + 25*z^8 + 67*z^7 + 13*z^6 - 15*z^5 */ static const long X1_31_crv_3[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 0, 0, -20, 68, 103, -119, -247, -1, 76, 20, 1 }; /* z^12 + 20*z^11 + 76*z^10 - z^9 - 247*z^8 - 119*z^7 + 103*z^6 + 68*z^5 - 20*z^4 */ static const long X1_31_crv_4[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 0, -15, 112, -17, -390, -266, 448, 293, -52, -47, -5 }; /* -5*z^12 - 47*z^11 - 52*z^10 + 293*z^9 + 448*z^8 - 266*z^7 - 390*z^6 - 17*z^5 + 112*z^4 - 15*z^3 */ static const long X1_31_crv_5[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, -6, 91, -200, -351, 242, 1033, 19, -537, -115, 44, 10 }; /* 10*z^12 + 44*z^11 - 115*z^10 - 537*z^9 + 19*z^8 + 1033*z^7 + 242*z^6 - 351*z^5 - 200*z^4 + 91*z^3 - 6*z^2 */ static const long X1_31_crv_6[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, -1, 37, -216, 28, 598, 713, -967, -864, 268, 240, 0, -10 }; /* -10*z^12 + 240*z^10 + 268*z^9 - 864*z^8 - 967*z^7 + 713*z^6 + 598*z^5 + 28*z^4 - 216*z^3 + 37*z^2 - z */ static const long X1_31_crv_7[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 6, -99, 222, 301, -78, -1254, -147, 911, 193, -162, -32, 5 }; /* 5*z^12 - 32*z^11 - 162*z^10 + 193*z^9 + 911*z^8 - 147*z^7 - 1254*z^6 - 78*z^5 + 301*z^4 + 222*z^3 - 99*z^2 + 6*z */ static const long X1_31_crv_8[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, -19, 131, -36, -266, -572, 569, 745, -260, -273, 27, 25, -1 }; /* -z^12 + 25*z^11 + 27*z^10 - 273*z^9 - 260*z^8 + 745*z^7 + 569*z^6 - 572*z^5 - 266*z^4 - 36*z^3 + 131*z^2 - 19*z */ static const long X1_31_crv_9[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, -1, 31, -73, -91, -57, 453, 145, -387, -93, 105, 17, -8 }; /* -8*z^11 + 17*z^10 + 105*z^9 - 93*z^8 - 387*z^7 + 145*z^6 + 453*z^5 - 57*z^4 - 91*z^3 - 73*z^2 + 31*z - 1 */ static const long X1_31_crv_10[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 3, -24, 0, 37, 129, -70, -152, 45, 61, -11, -8, 1 }; /* z^11 - 8*z^10 - 11*z^9 + 61*z^8 + 45*z^7 - 152*z^6 - 70*z^5 + 129*z^4 + 37*z^3 - 24*z + 3 */ static const long X1_31_crv_11[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, -3, 7, 10, 8, -26, -12, 23, 6, -8, -1, 1 }; /* z^10 - z^9 - 8*z^8 + 6*z^7 + 23*z^6 - 12*z^5 - 26*z^4 + 8*z^3 + 10*z^2 + 7*z - 3 */ static const long *X1_31_crv[15] = { (long *)(evaltyp(t_POL) | _evallg(15)), (long *)(evalvarn(0) | evalsigne(1)), X1_31_crv_0, X1_31_crv_1, X1_31_crv_2, X1_31_crv_3, X1_31_crv_4, X1_31_crv_5, X1_31_crv_6, X1_31_crv_7, X1_31_crv_8, X1_31_crv_9, X1_31_crv_10, X1_31_crv_11, FLX_1 }; /* (-z^4 + 3*z^3 - 2*z^2 - z + 1)*u^7 + (-z^5 + 7*z^4 - 11*z^3 + 2*z^2 + 3*z)*u^6 + (5*z^5 - 18*z^4 + 12*z^3 + 3*z^2 - 1)*u^5 + (z^6 - 11*z^5 + 22*z^4 + z^3 - 6*z^2 - 4*z + 1)*u^4 + (-2*z^6 + 15*z^5 - 9*z^4 - 15*z^3 - 3*z^2 + 4*z)*u^3 + (3*z^6 - 11*z^5 - 10*z^4 + 4*z^3 + 6*z^2)*u^2 + (-3*z^6 + 6*z^4 + 4*z^3)*u + (z^6 + 2*z^5 + z^4) */ static const long X1_31_r_n_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 0, 1, 2, 1 }; /* z^6 + 2*z^5 + z^4 */ static const long X1_31_r_n_1[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 4, 6, 0, -3 }; /* -3*z^6 + 6*z^4 + 4*z^3 */ static const long X1_31_r_n_2[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 6, 4, -10, -11, 3 }; /* 3*z^6 - 11*z^5 - 10*z^4 + 4*z^3 + 6*z^2 */ static const long X1_31_r_n_3[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 4, -3, -15, -9, 15, -2 }; /* -2*z^6 + 15*z^5 - 9*z^4 - 15*z^3 - 3*z^2 + 4*z */ static const long X1_31_r_n_4[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 1, -4, -6, 1, 22, -11, 1 }; /* z^6 - 11*z^5 + 22*z^4 + z^3 - 6*z^2 - 4*z + 1 */ static const long X1_31_r_n_5[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, 0, 3, 12, -18, 5 }; /* 5*z^5 - 18*z^4 + 12*z^3 + 3*z^2 - 1 */ static const long X1_31_r_n_6[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 3, 2, -11, 7, -1 }; /* -z^5 + 7*z^4 - 11*z^3 + 2*z^2 + 3*z */ static const long X1_31_r_n_7[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, -1, -2, 3, -1 }; /* -z^4 + 3*z^3 - 2*z^2 - z + 1 */ static const long *X1_31_r_n[10] = { (long *)(evaltyp(t_POL) | _evallg(10)), (long *)(evalvarn(0) | evalsigne(1)), X1_31_r_n_0, X1_31_r_n_1, X1_31_r_n_2, X1_31_r_n_3, X1_31_r_n_4, X1_31_r_n_5, X1_31_r_n_6, X1_31_r_n_7 }; /* (-z + 1)*u^6 + (-4*z^2 + 5*z - 1)*u^5 + (-z^6 - z^5 + 5*z^4 - z^3 + 6*z^2 - 7*z + 1)*u^4 + (3*z^6 + 10*z^5 - 6*z^4 - 8*z^3 - 10*z^2 + 5*z)*u^3 + (-z^6 - 14*z^5 - 10*z^4 + z^3 + 8*z^2)*u^2 + (-2*z^6 + 2*z^5 + 7*z^4 + 5*z^3)*u + (z^6 + 2*z^5 + z^4) */ static const long X1_31_r_d_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 0, 1, 2, 1 }; /* z^6 + 2*z^5 + z^4 */ static const long X1_31_r_d_1[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 5, 7, 2, -2 }; /* -2*z^6 + 2*z^5 + 7*z^4 + 5*z^3 */ static const long X1_31_r_d_2[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 8, 1, -10, -14, -1 }; /* -z^6 - 14*z^5 - 10*z^4 + z^3 + 8*z^2 */ static const long X1_31_r_d_3[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 5, -10, -8, -6, 10, 3 }; /* 3*z^6 + 10*z^5 - 6*z^4 - 8*z^3 - 10*z^2 + 5*z */ static const long X1_31_r_d_4[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 1, -7, 6, -1, 5, -1, -1 }; /* -z^6 - z^5 + 5*z^4 - z^3 + 6*z^2 - 7*z + 1 */ static const long X1_31_r_d_5[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -1, 5, -4 }; /* -4*z^2 + 5*z - 1 */ static const long X1_31_r_d_6[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, -1 }; /* -z + 1 */ static const long *X1_31_r_d[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_31_r_d_0, X1_31_r_d_1, X1_31_r_d_2, X1_31_r_d_3, X1_31_r_d_4, X1_31_r_d_5, X1_31_r_d_6 }; /* (-z^3 + 3*z^2 - z - 2)*u^6 + (-z^4 + 7*z^3 - 8*z^2 - 3*z + 1)*u^5 + (5*z^4 - 15*z^3 + 2*z^2 + 5*z + 1)*u^4 + (z^5 - 11*z^4 + 9*z^3 + 9*z^2 - z - 1)*u^3 + (-3*z^5 + 8*z^4 + 6*z^3 - 4*z^2 - 2*z)*u^2 + (3*z^5 + z^4 - 4*z^3 - 2*z^2)*u + (-z^5 - 2*z^4 - z^3) */ static const long X1_31_s_n_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 0, -1, -2, -1 }; /* -z^5 - 2*z^4 - z^3 */ static const long X1_31_s_n_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, -2, -4, 1, 3 }; /* 3*z^5 + z^4 - 4*z^3 - 2*z^2 */ static const long X1_31_s_n_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, -2, -4, 6, 8, -3 }; /* -3*z^5 + 8*z^4 + 6*z^3 - 4*z^2 - 2*z */ static const long X1_31_s_n_3[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, -1, 9, 9, -11, 1 }; /* z^5 - 11*z^4 + 9*z^3 + 9*z^2 - z - 1 */ static const long X1_31_s_n_4[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, 5, 2, -15, 5 }; /* 5*z^4 - 15*z^3 + 2*z^2 + 5*z + 1 */ static const long X1_31_s_n_5[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, -3, -8, 7, -1 }; /* -z^4 + 7*z^3 - 8*z^2 - 3*z + 1 */ static const long X1_31_s_n_6[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -2, -1, 3, -1 }; /* -z^3 + 3*z^2 - z - 2 */ static const long *X1_31_s_n[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_31_s_n_0, X1_31_s_n_1, X1_31_s_n_2, X1_31_s_n_3, X1_31_s_n_4, X1_31_s_n_5, X1_31_s_n_6 }; /* (z^2 - z - 1)*u^6 + (2*z^3 - 4*z^2 - z)*u^5 + (z^4 - 6*z^3 + 3*z^2 + z + 1)*u^4 + (-z^5 - 7*z^4 + 5*z^3 + 4*z^2 + 2*z - 1)*u^3 + (10*z^4 + 7*z^3 - z^2 - 3*z)*u^2 + (2*z^5 - z^4 - 5*z^3 - 3*z^2)*u + (-z^5 - 2*z^4 - z^3) */ static const long X1_31_s_d_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 0, -1, -2, -1 }; /* -z^5 - 2*z^4 - z^3 */ static const long X1_31_s_d_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, -3, -5, -1, 2 }; /* 2*z^5 - z^4 - 5*z^3 - 3*z^2 */ static const long X1_31_s_d_2[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, -3, -1, 7, 10 }; /* 10*z^4 + 7*z^3 - z^2 - 3*z */ static const long X1_31_s_d_3[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, 2, 4, 5, -7, -1 }; /* -z^5 - 7*z^4 + 5*z^3 + 4*z^2 + 2*z - 1 */ static const long X1_31_s_d_4[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, 1, 3, -6, 1 }; /* z^4 - 6*z^3 + 3*z^2 + z + 1 */ static const long X1_31_s_d_5[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -1, -4, 2 }; /* 2*z^3 - 4*z^2 - z */ static const long X1_31_s_d_6[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -1, -1, 1 }; /* z^2 - z - 1 */ static const long *X1_31_s_d[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_31_s_d_0, X1_31_s_d_1, X1_31_s_d_2, X1_31_s_d_3, X1_31_s_d_4, X1_31_s_d_5, X1_31_s_d_6 }; /* (z^8 - 4*z^7 + 6*z^6 - 4*z^5 + z^4)*x^8 + (16*z^8 - 48*z^7 + 48*z^6 - 16*z^5)*x^7 + (z^11 - 2*z^10 + z^9 + 104*z^8 - 208*z^7 + 96*z^6 + 16*z^5 - 8*z^4 - z^3 + 2*z^2 - z)*x^6 + (12*z^11 - 12*z^10 + 352*z^8 - 352*z^7 - 96*z^6 + 96*z^5 - 12*z^3 + 12*z^2)*x^5 + (54*z^11 - 6*z^9 + 664*z^8 - 432*z^6 + 24*z^4 - 54*z^3 + 6*z)*x^4 + (112*z^11 + 112*z^10 + 64*z^9 + 768*z^8 + 768*z^7 - 128*z^6 - 128*z^5 + 64*z^4 - 48*z^3 - 48*z^2)*x^3 + (106*z^11 + 212*z^10 + 198*z^9 + 600*z^8 + 1020*z^7 + 576*z^6 + 132*z^5 + 168*z^4 + 90*z^3 - 20*z^2 - 10*z)*x^2 + (40*z^11 + 120*z^10 + 144*z^9 + 240*z^8 + 480*z^7 + 480*z^6 + 240*z^5 + 144*z^4 + 120*z^3 + 40*z^2)*x + (-z^12 + 6*z^10 - 15*z^8 + 20*z^6 - 15*z^4 + 6*z^2 - 1) */ static const long X1_32_crv_0[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, -1, 0, 6, 0, -15, 0, 20, 0, -15, 0, 6, 0, -1 }; /* -z^12 + 6*z^10 - 15*z^8 + 20*z^6 - 15*z^4 + 6*z^2 - 1 */ static const long X1_32_crv_1[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 40, 120, 144, 240, 480, 480, 240, 144, 120, 40 }; /* 40*z^11 + 120*z^10 + 144*z^9 + 240*z^8 + 480*z^7 + 480*z^6 + 240*z^5 + 144*z^4 + 120*z^3 + 40*z^2 */ static const long X1_32_crv_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, -10, -20, 90, 168, 132, 576, 1020, 600, 198, 212, 106 }; /* 106*z^11 + 212*z^10 + 198*z^9 + 600*z^8 + 1020*z^7 + 576*z^6 + 132*z^5 + 168*z^4 + 90*z^3 - 20*z^2 - 10*z */ static const long X1_32_crv_3[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, -48, -48, 64, -128, -128, 768, 768, 64, 112, 112 }; /* 112*z^11 + 112*z^10 + 64*z^9 + 768*z^8 + 768*z^7 - 128*z^6 - 128*z^5 + 64*z^4 - 48*z^3 - 48*z^2 */ static const long X1_32_crv_4[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 6, 0, -54, 24, 0, -432, 0, 664, -6, 0, 54 }; /* 54*z^11 - 6*z^9 + 664*z^8 - 432*z^6 + 24*z^4 - 54*z^3 + 6*z */ static const long X1_32_crv_5[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 12, -12, 0, 96, -96, -352, 352, 0, -12, 12 }; /* 12*z^11 - 12*z^10 + 352*z^8 - 352*z^7 - 96*z^6 + 96*z^5 - 12*z^3 + 12*z^2 */ static const long X1_32_crv_6[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, -1, 2, -1, -8, 16, 96, -208, 104, 1, -2, 1 }; /* z^11 - 2*z^10 + z^9 + 104*z^8 - 208*z^7 + 96*z^6 + 16*z^5 - 8*z^4 - z^3 + 2*z^2 - z */ static const long X1_32_crv_7[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, 0, -16, 48, -48, 16 }; /* 16*z^8 - 48*z^7 + 48*z^6 - 16*z^5 */ static const long X1_32_crv_8[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, 1, -4, 6, -4, 1 }; /* z^8 - 4*z^7 + 6*z^6 - 4*z^5 + z^4 */ static const long *X1_32_crv[11] = { (long *)(evaltyp(t_POL) | _evallg(11)), (long *)(evalvarn(0) | evalsigne(1)), X1_32_crv_0, X1_32_crv_1, X1_32_crv_2, X1_32_crv_3, X1_32_crv_4, X1_32_crv_5, X1_32_crv_6, X1_32_crv_7, X1_32_crv_8 }; /* (z - 1)*x + 2*z */ static const long X1_32_r_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 2 }; /* 2*z */ static const long X1_32_r_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, 1 }; /* z - 1 */ static const long *X1_32_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_32_r_n_0, X1_32_r_n_1 }; /* 2 */ static const long X1_32_r_d_0[3] = { evaltyp(t_VECSMALL) | _evallg(3), vZ, 2 }; /* 2 */ static const long *X1_32_r_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_32_r_d_0 }; /* (-z + 1)*x - 2*z */ static const long X1_32_s_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, -2 }; /* -2*z */ static const long X1_32_s_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, -1 }; /* -z + 1 */ static const long *X1_32_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_32_s_n_0, X1_32_s_n_1 }; /* 2*z */ static const long X1_32_s_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 0, 2 }; /* 2*z */ static const long *X1_32_s_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_32_s_d_0 }; /* z^8*x^10 + (-z^17 - 2*z^16 - 4*z^15 - 6*z^14 - 9*z^13 - 12*z^12 - 16*z^11 - 20*z^10 - 25*z^9 - 18*z^8)*x^9 + (-3*z^17 - 15*z^16 - 24*z^15 - 28*z^14 - 16*z^13 + 6*z^12 + 32*z^11 + 32*z^10 - 33*z^9 - 155*z^8 - 188*z^7 - 108*z^6 - 58*z^5 - 28*z^4 - 12*z^3 - 4*z^2 - z)*x^8 + (-6*z^17 - 48*z^16 - 144*z^15 - 226*z^14 - 225*z^13 - 39*z^12 + 402*z^11 + 1116*z^10 + 1854*z^9 + 2071*z^8 + 1536*z^7 + 852*z^6 + 476*z^5 + 249*z^4 + 114*z^3 + 40*z^2 + 9*z)*x^7 + (-10*z^17 - 110*z^16 - 520*z^15 - 1464*z^14 - 3006*z^13 - 5160*z^12 - 7660*z^11 - 9656*z^10 - 9778*z^9 - 7536*z^8 - 4500*z^7 - 2580*z^6 - 1696*z^5 - 1028*z^4 - 508*z^3 - 180*z^2 - 36*z)*x^6 + (z^20 + 10*z^19 + 60*z^18 + 255*z^17 + 795*z^16 + 1872*z^15 + 3576*z^14 + 6042*z^13 + 9198*z^12 + 11872*z^11 + 12028*z^10 + 8886*z^9 + 4847*z^8 + 3188*z^7 + 3762*z^6 + 3917*z^5 + 2801*z^4 + 1422*z^3 + 480*z^2 + 84*z)*x^5 + (10*z^17 + 60*z^16 + 120*z^15 - 64*z^14 - 690*z^13 - 1026*z^12 + 392*z^11 + 3456*z^10 + 4980*z^9 + 1576*z^8 - 5292*z^7 - 10032*z^6 - 9630*z^5 - 6174*z^4 - 2808*z^3 - 840*z^2 - 126*z)*x^4 + (6*z^17 + 54*z^16 + 192*z^15 + 254*z^14 - 419*z^13 - 2392*z^12 - 4432*z^11 - 3020*z^10 + 4499*z^9 + 15607*z^8 + 23336*z^7 + 22966*z^6 + 16391*z^5 + 8779*z^4 + 3458*z^3 + 896*z^2 + 112*z - 1)*x^3 + (3*z^17 + 36*z^16 + 192*z^15 + 572*z^14 + 884*z^13 - 150*z^12 - 4536*z^11 - 13080*z^10 - 23253*z^9 - 29900*z^8 - 29288*z^7 - 22380*z^6 - 13480*z^5 - 6328*z^4 - 2184*z^3 - 476*z^2 - 41*z + 3)*x^2 + (z^17 + 15*z^16 + 108*z^15 + 494*z^14 + 1605*z^13 + 3927*z^12 + 7490*z^11 + 11376*z^10 + 13938*z^9 + 13882*z^8 + 11292*z^7 + 7506*z^6 + 4025*z^5 + 1659*z^4 + 462*z^3 + 56*z^2 - 9*z - 3)*x + (z^8 + 8*z^7 + 28*z^6 + 56*z^5 + 70*z^4 + 56*z^3 + 28*z^2 + 8*z + 1) */ static const long X1_33_crv_0[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 1, 8, 28, 56, 70, 56, 28, 8, 1 }; /* z^8 + 8*z^7 + 28*z^6 + 56*z^5 + 70*z^4 + 56*z^3 + 28*z^2 + 8*z + 1 */ static const long X1_33_crv_1[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, -3, -9, 56, 462, 1659, 4025, 7506, 11292, 13882, 13938, 11376, 7490, 3927, 1605, 494, 108, 15, 1 }; /* z^17 + 15*z^16 + 108*z^15 + 494*z^14 + 1605*z^13 + 3927*z^12 + 7490*z^11 + 11376*z^10 + 13938*z^9 + 13882*z^8 + 11292*z^7 + 7506*z^6 + 4025*z^5 + 1659*z^4 + 462*z^3 + 56*z^2 - 9*z - 3 */ static const long X1_33_crv_2[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 3, -41, -476, -2184, -6328, -13480, -22380, -29288, -29900, -23253, -13080, -4536, -150, 884, 572, 192, 36, 3 }; /* 3*z^17 + 36*z^16 + 192*z^15 + 572*z^14 + 884*z^13 - 150*z^12 - 4536*z^11 - 13080*z^10 - 23253*z^9 - 29900*z^8 - 29288*z^7 - 22380*z^6 - 13480*z^5 - 6328*z^4 - 2184*z^3 - 476*z^2 - 41*z + 3 */ static const long X1_33_crv_3[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, -1, 112, 896, 3458, 8779, 16391, 22966, 23336, 15607, 4499, -3020, -4432, -2392, -419, 254, 192, 54, 6 }; /* 6*z^17 + 54*z^16 + 192*z^15 + 254*z^14 - 419*z^13 - 2392*z^12 - 4432*z^11 - 3020*z^10 + 4499*z^9 + 15607*z^8 + 23336*z^7 + 22966*z^6 + 16391*z^5 + 8779*z^4 + 3458*z^3 + 896*z^2 + 112*z - 1 */ static const long X1_33_crv_4[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, -126, -840, -2808, -6174, -9630, -10032, -5292, 1576, 4980, 3456, 392, -1026, -690, -64, 120, 60, 10 }; /* 10*z^17 + 60*z^16 + 120*z^15 - 64*z^14 - 690*z^13 - 1026*z^12 + 392*z^11 + 3456*z^10 + 4980*z^9 + 1576*z^8 - 5292*z^7 - 10032*z^6 - 9630*z^5 - 6174*z^4 - 2808*z^3 - 840*z^2 - 126*z */ static const long X1_33_crv_5[23] = { evaltyp(t_VECSMALL) | _evallg(23), vZ, 0, 84, 480, 1422, 2801, 3917, 3762, 3188, 4847, 8886, 12028, 11872, 9198, 6042, 3576, 1872, 795, 255, 60, 10, 1 }; /* z^20 + 10*z^19 + 60*z^18 + 255*z^17 + 795*z^16 + 1872*z^15 + 3576*z^14 + 6042*z^13 + 9198*z^12 + 11872*z^11 + 12028*z^10 + 8886*z^9 + 4847*z^8 + 3188*z^7 + 3762*z^6 + 3917*z^5 + 2801*z^4 + 1422*z^3 + 480*z^2 + 84*z */ static const long X1_33_crv_6[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, -36, -180, -508, -1028, -1696, -2580, -4500, -7536, -9778, -9656, -7660, -5160, -3006, -1464, -520, -110, -10 }; /* -10*z^17 - 110*z^16 - 520*z^15 - 1464*z^14 - 3006*z^13 - 5160*z^12 - 7660*z^11 - 9656*z^10 - 9778*z^9 - 7536*z^8 - 4500*z^7 - 2580*z^6 - 1696*z^5 - 1028*z^4 - 508*z^3 - 180*z^2 - 36*z */ static const long X1_33_crv_7[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, 9, 40, 114, 249, 476, 852, 1536, 2071, 1854, 1116, 402, -39, -225, -226, -144, -48, -6 }; /* -6*z^17 - 48*z^16 - 144*z^15 - 226*z^14 - 225*z^13 - 39*z^12 + 402*z^11 + 1116*z^10 + 1854*z^9 + 2071*z^8 + 1536*z^7 + 852*z^6 + 476*z^5 + 249*z^4 + 114*z^3 + 40*z^2 + 9*z */ static const long X1_33_crv_8[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, -1, -4, -12, -28, -58, -108, -188, -155, -33, 32, 32, 6, -16, -28, -24, -15, -3 }; /* -3*z^17 - 15*z^16 - 24*z^15 - 28*z^14 - 16*z^13 + 6*z^12 + 32*z^11 + 32*z^10 - 33*z^9 - 155*z^8 - 188*z^7 - 108*z^6 - 58*z^5 - 28*z^4 - 12*z^3 - 4*z^2 - z */ static const long X1_33_crv_9[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, 0, 0, 0, 0, 0, 0, 0, -18, -25, -20, -16, -12, -9, -6, -4, -2, -1 }; /* -z^17 - 2*z^16 - 4*z^15 - 6*z^14 - 9*z^13 - 12*z^12 - 16*z^11 - 20*z^10 - 25*z^9 - 18*z^8 */ static const long X1_33_crv_10[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; /* z^8 */ static const long *X1_33_crv[13] = { (long *)(evaltyp(t_POL) | _evallg(13)), (long *)(evalvarn(0) | evalsigne(1)), X1_33_crv_0, X1_33_crv_1, X1_33_crv_2, X1_33_crv_3, X1_33_crv_4, X1_33_crv_5, X1_33_crv_6, X1_33_crv_7, X1_33_crv_8, X1_33_crv_9, X1_33_crv_10 }; /* (z + 1) */ static const long X1_33_r_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_33_r_n[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), X1_33_r_n_0 }; /* z */ static const long *X1_33_r_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_Z }; /* 1 */ static const long *X1_33_s_n[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1 }; /* (-z - 1)*x + (z + 1) */ static const long X1_33_s_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long X1_33_s_d_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, -1 }; /* -z - 1 */ static const long *X1_33_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_33_s_d_0, X1_33_s_d_1 }; /* u^10 + (z^5 - z^2 - 4*z + 4)*u^9 + (8*z^5 - z^4 - 5*z^3 + z^2 - 12*z + 6)*u^8 + (5*z^7 - 2*z^6 + 16*z^5 - z^4 - 20*z^3 + 9*z^2 - 11*z + 4)*u^7 + (-z^8 + 24*z^7 + 2*z^6 + 7*z^5 - 36*z^3 + 8*z^2 + 1)*u^6 + (z^10 + z^9 - 7*z^8 + 40*z^7 + 26*z^6 + 2*z^5 + 8*z^4 - 29*z^3 - 3*z^2 + 5*z)*u^5 + (2*z^10 + 4*z^9 - 5*z^8 + 35*z^7 + 37*z^6 + 5*z^5 + 12*z^4 - 6*z^3 - 5*z^2 + 2*z)*u^4 + (z^10 + 4*z^9 + 7*z^8 + 28*z^7 + 29*z^6 + 7*z^5 + 5*z^4 + 3*z^3)*u^3 + (2*z^9 + 10*z^8 + 16*z^7 + 10*z^6 + 2*z^5 - z^4 + z^2)*u^2 + (z^9 + 5*z^8 + 5*z^7 - z^5 - z^4 - z^3)*u + (-z^7 - 2*z^6 - z^5) */ static const long X1_34_crv_0[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, 0, 0, 0, 0, -1, -2, -1 }; /* -z^7 - 2*z^6 - z^5 */ static const long X1_34_crv_1[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, -1, -1, -1, 0, 5, 5, 1 }; /* z^9 + 5*z^8 + 5*z^7 - z^5 - z^4 - z^3 */ static const long X1_34_crv_2[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 1, 0, -1, 2, 10, 16, 10, 2 }; /* 2*z^9 + 10*z^8 + 16*z^7 + 10*z^6 + 2*z^5 - z^4 + z^2 */ static const long X1_34_crv_3[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 3, 5, 7, 29, 28, 7, 4, 1 }; /* z^10 + 4*z^9 + 7*z^8 + 28*z^7 + 29*z^6 + 7*z^5 + 5*z^4 + 3*z^3 */ static const long X1_34_crv_4[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 2, -5, -6, 12, 5, 37, 35, -5, 4, 2 }; /* 2*z^10 + 4*z^9 - 5*z^8 + 35*z^7 + 37*z^6 + 5*z^5 + 12*z^4 - 6*z^3 - 5*z^2 + 2*z */ static const long X1_34_crv_5[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 5, -3, -29, 8, 2, 26, 40, -7, 1, 1 }; /* z^10 + z^9 - 7*z^8 + 40*z^7 + 26*z^6 + 2*z^5 + 8*z^4 - 29*z^3 - 3*z^2 + 5*z */ static const long X1_34_crv_6[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 1, 0, 8, -36, 0, 7, 2, 24, -1 }; /* -z^8 + 24*z^7 + 2*z^6 + 7*z^5 - 36*z^3 + 8*z^2 + 1 */ static const long X1_34_crv_7[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 4, -11, 9, -20, -1, 16, -2, 5 }; /* 5*z^7 - 2*z^6 + 16*z^5 - z^4 - 20*z^3 + 9*z^2 - 11*z + 4 */ static const long X1_34_crv_8[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 6, -12, 1, -5, -1, 8 }; /* 8*z^5 - z^4 - 5*z^3 + z^2 - 12*z + 6 */ static const long X1_34_crv_9[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 4, -4, -1, 0, 0, 1 }; /* z^5 - z^2 - 4*z + 4 */ static const long *X1_34_crv[13] = { (long *)(evaltyp(t_POL) | _evallg(13)), (long *)(evalvarn(0) | evalsigne(1)), X1_34_crv_0, X1_34_crv_1, X1_34_crv_2, X1_34_crv_3, X1_34_crv_4, X1_34_crv_5, X1_34_crv_6, X1_34_crv_7, X1_34_crv_8, X1_34_crv_9, FLX_1 }; /* u^8 + (-z^2 - 3*z + 3)*u^7 + (-z^3 + 3*z^2 - 5*z + 3)*u^6 + (-3*z^4 - 11*z^3 + 7*z^2 - 2*z + 1)*u^5 + (2*z^5 + 2*z^4 - 15*z^3 + z^2 - z)*u^4 + (-2*z^6 + 5*z^4 - 7*z^3 - 3*z^2 - 2*z)*u^3 + (z^7 + 2*z^4 - z)*u^2 + (z^5 + z^4 + z^3 + z^2)*u + (z^6 + 2*z^5 + z^4) */ static const long X1_34_r_n_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 0, 1, 2, 1 }; /* z^6 + 2*z^5 + z^4 */ static const long X1_34_r_n_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 1, 1, 1, 1 }; /* z^5 + z^4 + z^3 + z^2 */ static const long X1_34_r_n_2[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, -1, 0, 0, 2, 0, 0, 1 }; /* z^7 + 2*z^4 - z */ static const long X1_34_r_n_3[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, -2, -3, -7, 5, 0, -2 }; /* -2*z^6 + 5*z^4 - 7*z^3 - 3*z^2 - 2*z */ static const long X1_34_r_n_4[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, -1, 1, -15, 2, 2 }; /* 2*z^5 + 2*z^4 - 15*z^3 + z^2 - z */ static const long X1_34_r_n_5[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, -2, 7, -11, -3 }; /* -3*z^4 - 11*z^3 + 7*z^2 - 2*z + 1 */ static const long X1_34_r_n_6[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 3, -5, 3, -1 }; /* -z^3 + 3*z^2 - 5*z + 3 */ static const long X1_34_r_n_7[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 3, -3, -1 }; /* -z^2 - 3*z + 3 */ static const long *X1_34_r_n[11] = { (long *)(evaltyp(t_POL) | _evallg(11)), (long *)(evalvarn(0) | evalsigne(1)), X1_34_r_n_0, X1_34_r_n_1, X1_34_r_n_2, X1_34_r_n_3, X1_34_r_n_4, X1_34_r_n_5, X1_34_r_n_6, X1_34_r_n_7, FLX_1 }; /* (-z^3 + 1)*u^6 + (-z^4 - 4*z^3 + 2*z^2 + 3)*u^5 + (-2*z^5 - 2*z^4 - 4*z^3 + 2*z^2 - 3*z + 3)*u^4 + (-z^6 - 2*z^5 - 2*z^4 - 5*z^3 - 3*z^2 - 6*z + 1)*u^3 + (z^7 - z^5 - 2*z^4 - 2*z^3 - z^2 - 3*z)*u^2 + (2*z^5 + 3*z^4 + 3*z^3 + 2*z^2)*u + (z^6 + 2*z^5 + z^4) */ static const long X1_34_r_d_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 0, 1, 2, 1 }; /* z^6 + 2*z^5 + z^4 */ static const long X1_34_r_d_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 2, 3, 3, 2 }; /* 2*z^5 + 3*z^4 + 3*z^3 + 2*z^2 */ static const long X1_34_r_d_2[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, -3, -1, -2, -2, -1, 0, 1 }; /* z^7 - z^5 - 2*z^4 - 2*z^3 - z^2 - 3*z */ static const long X1_34_r_d_3[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 1, -6, -3, -5, -2, -2, -1 }; /* -z^6 - 2*z^5 - 2*z^4 - 5*z^3 - 3*z^2 - 6*z + 1 */ static const long X1_34_r_d_4[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 3, -3, 2, -4, -2, -2 }; /* -2*z^5 - 2*z^4 - 4*z^3 + 2*z^2 - 3*z + 3 */ static const long X1_34_r_d_5[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 3, 0, 2, -4, -1 }; /* -z^4 - 4*z^3 + 2*z^2 + 3 */ static const long X1_34_r_d_6[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 1, 0, 0, -1 }; /* -z^3 + 1 */ static const long *X1_34_r_d[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_34_r_d_0, X1_34_r_d_1, X1_34_r_d_2, X1_34_r_d_3, X1_34_r_d_4, X1_34_r_d_5, X1_34_r_d_6 }; /* -u^7 + (z^2 + 3*z - 3)*u^6 + (z^3 - 2*z^2 + 5*z - 3)*u^5 + (3*z^4 + 10*z^3 - 4*z^2 + z - 1)*u^4 + (-2*z^5 + 2*z^4 + 14*z^3 - 2*z)*u^3 + (z^6 + z^4 + 6*z^3 + z^2 - z)*u^2 + (z^4 + z^3)*u + (z^5 + 2*z^4 + z^3) */ static const long X1_34_s_n_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 0, 1, 2, 1 }; /* z^5 + 2*z^4 + z^3 */ static const long X1_34_s_n_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, 0, 1, 1 }; /* z^4 + z^3 */ static const long X1_34_s_n_2[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, -1, 1, 6, 1, 0, 1 }; /* z^6 + z^4 + 6*z^3 + z^2 - z */ static const long X1_34_s_n_3[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, -2, 0, 14, 2, -2 }; /* -2*z^5 + 2*z^4 + 14*z^3 - 2*z */ static const long X1_34_s_n_4[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, -1, 1, -4, 10, 3 }; /* 3*z^4 + 10*z^3 - 4*z^2 + z - 1 */ static const long X1_34_s_n_5[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -3, 5, -2, 1 }; /* z^3 - 2*z^2 + 5*z - 3 */ static const long X1_34_s_n_6[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -3, 3, 1 }; /* z^2 + 3*z - 3 */ static const long *X1_34_s_n[10] = { (long *)(evaltyp(t_POL) | _evallg(10)), (long *)(evalvarn(0) | evalsigne(1)), X1_34_s_n_0, X1_34_s_n_1, X1_34_s_n_2, X1_34_s_n_3, X1_34_s_n_4, X1_34_s_n_5, X1_34_s_n_6, FLX_m1 }; /* z*u^6 + (-z^2 + 3*z - 1)*u^5 + (4*z^3 - z^2 + z - 3)*u^4 + (-z^5 + 6*z^3 - z^2 - 2*z - 3)*u^3 + (z^6 + 3*z^3 + z^2 - 1)*u^2 + (2*z^4 + 3*z^3 + 2*z^2 + z)*u + (z^5 + 2*z^4 + z^3) */ static const long X1_34_s_d_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 0, 1, 2, 1 }; /* z^5 + 2*z^4 + z^3 */ static const long X1_34_s_d_1[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 1, 2, 3, 2 }; /* 2*z^4 + 3*z^3 + 2*z^2 + z */ static const long X1_34_s_d_2[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, 0, 1, 3, 0, 0, 1 }; /* z^6 + 3*z^3 + z^2 - 1 */ static const long X1_34_s_d_3[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -3, -2, -1, 6, 0, -1 }; /* -z^5 + 6*z^3 - z^2 - 2*z - 3 */ static const long X1_34_s_d_4[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -3, 1, -1, 4 }; /* 4*z^3 - z^2 + z - 3 */ static const long X1_34_s_d_5[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -1, 3, -1 }; /* -z^2 + 3*z - 1 */ static const long *X1_34_s_d[9] = { (long *)(evaltyp(t_POL) | _evallg(9)), (long *)(evalvarn(0) | evalsigne(1)), X1_34_s_d_0, X1_34_s_d_1, X1_34_s_d_2, X1_34_s_d_3, X1_34_s_d_4, X1_34_s_d_5, FLX_Z }; /* z^3*u^12 + (-z^7 - 8*z^4 - 6*z^3 - z)*u^11 + (7*z^8 + 5*z^7 + 25*z^5 + 44*z^4 + 12*z^3 + 7*z^2 + 5*z)*u^10 + (-18*z^9 - 32*z^8 - 7*z^7 - 34*z^6 - 122*z^5 - 80*z^4 - 27*z^3 - 32*z^2 - 8*z + 1)*u^9 + (-z^11 + 19*z^10 + 72*z^9 + 41*z^8 + 3*z^7 + 141*z^6 + 193*z^5 + 71*z^4 + 75*z^3 + 47*z^2 - 2*z - 3)*u^8 + (4*z^12 + 4*z^11 - 59*z^10 - 79*z^9 + 44*z^8 + 5*z^7 - 178*z^6 - 100*z^5 - 72*z^4 - 99*z^3 - 9*z^2 + 17*z + 3)*u^7 + (-6*z^13 - 32*z^12 - 24*z^11 + 45*z^10 - 43*z^9 - 174*z^8 - 37*z^7 + 35*z^6 - z^5 + 90*z^4 + 34*z^3 - 35*z^2 - 15*z - 1)*u^6 + (4*z^14 + 33*z^13 + 80*z^12 + 42*z^11 + 9*z^10 + 145*z^9 + 183*z^8 + 73*z^7 + 60*z^6 - 27*z^5 - 52*z^4 + 32*z^3 + 27*z^2 + 3*z)*u^5 + (-z^15 - 14*z^14 - 57*z^13 - 72*z^12 - 6*z^10 - 100*z^9 - 84*z^8 - 47*z^7 - 3*z^6 + 50*z^5 - 6*z^4 - 27*z^3 + 2*z)*u^4 + (2*z^15 + 16*z^14 + 36*z^13 + 6*z^12 - 45*z^11 - 13*z^10 + 25*z^9 + 11*z^8 - 7*z^7 - 36*z^6 - 15*z^5 + 19*z^4 - 8*z^2 - z)*u^3 + (-z^15 - 6*z^14 - 3*z^13 + 21*z^12 + 26*z^11 + z^10 - 3*z^9 + 9*z^8 + 20*z^7 + 16*z^6 - 8*z^5 - 7*z^4 + 7*z^3 + 4*z^2)*u^2 + (-3*z^13 - 6*z^12 + z^11 + 7*z^10 + z^9 - 6*z^8 - 7*z^7 + z^6 + 7*z^5 + z^4 - 3*z^3 - z^2)*u + (-z^12 - 3*z^11 - 3*z^10 - z^9 - z^7 - 3*z^6 - 3*z^5 - z^4) */ static const long X1_35_crv_0[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 0, 0, -1, -3, -3, -1, 0, -1, -3, -3, -1 }; /* -z^12 - 3*z^11 - 3*z^10 - z^9 - z^7 - 3*z^6 - 3*z^5 - z^4 */ static const long X1_35_crv_1[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, 0, 0, -1, -3, 1, 7, 1, -7, -6, 1, 7, 1, -6, -3 }; /* -3*z^13 - 6*z^12 + z^11 + 7*z^10 + z^9 - 6*z^8 - 7*z^7 + z^6 + 7*z^5 + z^4 - 3*z^3 - z^2 */ static const long X1_35_crv_2[18] = { evaltyp(t_VECSMALL) | _evallg(18), vZ, 0, 0, 4, 7, -7, -8, 16, 20, 9, -3, 1, 26, 21, -3, -6, -1 }; /* -z^15 - 6*z^14 - 3*z^13 + 21*z^12 + 26*z^11 + z^10 - 3*z^9 + 9*z^8 + 20*z^7 + 16*z^6 - 8*z^5 - 7*z^4 + 7*z^3 + 4*z^2 */ static const long X1_35_crv_3[18] = { evaltyp(t_VECSMALL) | _evallg(18), vZ, 0, -1, -8, 0, 19, -15, -36, -7, 11, 25, -13, -45, 6, 36, 16, 2 }; /* 2*z^15 + 16*z^14 + 36*z^13 + 6*z^12 - 45*z^11 - 13*z^10 + 25*z^9 + 11*z^8 - 7*z^7 - 36*z^6 - 15*z^5 + 19*z^4 - 8*z^2 - z */ static const long X1_35_crv_4[18] = { evaltyp(t_VECSMALL) | _evallg(18), vZ, 0, 2, 0, -27, -6, 50, -3, -47, -84, -100, -6, 0, -72, -57, -14, -1 }; /* -z^15 - 14*z^14 - 57*z^13 - 72*z^12 - 6*z^10 - 100*z^9 - 84*z^8 - 47*z^7 - 3*z^6 + 50*z^5 - 6*z^4 - 27*z^3 + 2*z */ static const long X1_35_crv_5[17] = { evaltyp(t_VECSMALL) | _evallg(17), vZ, 0, 3, 27, 32, -52, -27, 60, 73, 183, 145, 9, 42, 80, 33, 4 }; /* 4*z^14 + 33*z^13 + 80*z^12 + 42*z^11 + 9*z^10 + 145*z^9 + 183*z^8 + 73*z^7 + 60*z^6 - 27*z^5 - 52*z^4 + 32*z^3 + 27*z^2 + 3*z */ static const long X1_35_crv_6[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, -1, -15, -35, 34, 90, -1, 35, -37, -174, -43, 45, -24, -32, -6 }; /* -6*z^13 - 32*z^12 - 24*z^11 + 45*z^10 - 43*z^9 - 174*z^8 - 37*z^7 + 35*z^6 - z^5 + 90*z^4 + 34*z^3 - 35*z^2 - 15*z - 1 */ static const long X1_35_crv_7[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 3, 17, -9, -99, -72, -100, -178, 5, 44, -79, -59, 4, 4 }; /* 4*z^12 + 4*z^11 - 59*z^10 - 79*z^9 + 44*z^8 + 5*z^7 - 178*z^6 - 100*z^5 - 72*z^4 - 99*z^3 - 9*z^2 + 17*z + 3 */ static const long X1_35_crv_8[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, -3, -2, 47, 75, 71, 193, 141, 3, 41, 72, 19, -1 }; /* -z^11 + 19*z^10 + 72*z^9 + 41*z^8 + 3*z^7 + 141*z^6 + 193*z^5 + 71*z^4 + 75*z^3 + 47*z^2 - 2*z - 3 */ static const long X1_35_crv_9[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 1, -8, -32, -27, -80, -122, -34, -7, -32, -18 }; /* -18*z^9 - 32*z^8 - 7*z^7 - 34*z^6 - 122*z^5 - 80*z^4 - 27*z^3 - 32*z^2 - 8*z + 1 */ static const long X1_35_crv_10[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 5, 7, 12, 44, 25, 0, 5, 7 }; /* 7*z^8 + 5*z^7 + 25*z^5 + 44*z^4 + 12*z^3 + 7*z^2 + 5*z */ static const long X1_35_crv_11[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, -1, 0, -6, -8, 0, 0, -1 }; /* -z^7 - 8*z^4 - 6*z^3 - z */ static const long X1_35_crv_12[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 0, 1 }; /* z^3 */ static const long *X1_35_crv[15] = { (long *)(evaltyp(t_POL) | _evallg(15)), (long *)(evalvarn(0) | evalsigne(1)), X1_35_crv_0, X1_35_crv_1, X1_35_crv_2, X1_35_crv_3, X1_35_crv_4, X1_35_crv_5, X1_35_crv_6, X1_35_crv_7, X1_35_crv_8, X1_35_crv_9, X1_35_crv_10, X1_35_crv_11, X1_35_crv_12 }; /* -z^8*u^19 + (11*z^9 + 8*z^8 + 2*z^6)*u^18 + (-51*z^10 - 83*z^9 - 24*z^8 - 20*z^7 - 13*z^6 - z^4)*u^17 + (125*z^11 + 359*z^10 + 234*z^9 + 118*z^8 + 124*z^7 + 30*z^6 + 7*z^5 + 4*z^4)*u^16 + (-156*z^12 - 804*z^11 - 940*z^10 - 498*z^9 - 527*z^8 - 273*z^7 - 46*z^6 - 25*z^5 - 4*z^4 + 2*z^3 + z^2)*u^15 + (35*z^13 + 861*z^12 + 1909*z^11 + 1379*z^10 + 1322*z^9 + 1091*z^8 + 261*z^7 + 70*z^6 + 19*z^5 - 16*z^4 - 15*z^3 - 2*z^2)*u^14 + (174*z^14 + 19*z^13 - 1703*z^12 - 2223*z^11 - 2147*z^10 - 2523*z^9 - 972*z^8 - 162*z^7 - 62*z^6 + 61*z^5 + 79*z^4 + 21*z^3 - 2*z^2 - z - 1)*u^13 + (-232*z^15 - 1155*z^14 - 552*z^13 + 1490*z^12 + 2193*z^11 + 3700*z^10 + 2378*z^9 + 472*z^8 + 272*z^7 - 65*z^6 - 225*z^5 - 88*z^4 + 21*z^3 + 11*z^2 + 11*z + 2)*u^12 + (72*z^16 + 1175*z^15 + 2713*z^14 + 1080*z^13 - 944*z^12 - 3365*z^11 - 3864*z^10 - 1239*z^9 - 855*z^8 - 294*z^7 + 373*z^6 + 253*z^5 - 90*z^4 - 57*z^3 - 46*z^2 - 21*z - 1)*u^11 + (85*z^17 - 152*z^16 - 2096*z^15 - 2809*z^14 - 902*z^13 + 1269*z^12 + 3806*z^11 + 2152*z^10 + 1495*z^9 + 1142*z^8 - 339*z^7 - 614*z^6 + 111*z^5 + 181*z^4 + 84*z^3 + 81*z^2 + 11*z)*u^10 + (-85*z^18 - 520*z^17 - 149*z^16 + 1678*z^15 + 1797*z^14 + 1203*z^13 - 1299*z^12 - 2155*z^11 - 1471*z^10 - 1685*z^9 + 163*z^8 + 1172*z^7 + 249*z^6 - 319*z^5 - 62*z^4 - 132*z^3 - 43*z^2)*u^9 + (19*z^19 + 357*z^18 + 1085*z^17 + 381*z^16 - 1194*z^15 - 2243*z^14 - 1704*z^13 + 870*z^12 + 1000*z^11 + 1263*z^10 - 131*z^9 - 1589*z^8 - 952*z^7 + 278*z^6 + 36*z^5 + 65*z^4 + 75*z^3 - z^2 + 2*z)*u^8 + (7*z^20 - 40*z^19 - 522*z^18 - 898*z^17 + 184*z^16 + 1590*z^15 + 2413*z^14 + 396*z^13 - 950*z^12 - 708*z^11 + 188*z^10 + 1491*z^9 + 1264*z^8 - 100*z^7 - 187*z^6 + 53*z^5 - 73*z^4 + 12*z^3 - 9*z^2 - 2*z)*u^7 + (-3*z^21 - 34*z^20 - 2*z^19 + 314*z^18 + 201*z^17 - 523*z^16 - 1148*z^15 - 515*z^14 + 1090*z^13 + 767*z^12 - 67*z^11 - 980*z^10 - 905*z^9 + 43*z^8 + 463*z^7 - 23*z^6 + 39*z^5 - 27*z^4 + 2*z^3 + 11*z^2)*u^6 + (9*z^21 + 56*z^20 + 40*z^19 - 101*z^18 - 10*z^17 + 100*z^16 + 74*z^15 - 730*z^14 - 802*z^13 - 104*z^12 + 449*z^11 + 429*z^10 - 71*z^9 - 525*z^8 - 125*z^7 + 20*z^6 + 34*z^5 + 32*z^4 - 13*z^3)*u^5 + (-9*z^21 - 37*z^20 + 79*z^18 + 103*z^17 + 86*z^16 + 178*z^15 + 385*z^14 + 109*z^13 - 137*z^12 - 168*z^11 + 29*z^10 + 289*z^9 + 172*z^8 - 57*z^7 - 42*z^6 - 50*z^5 + 4*z^4 - z^3)*u^4 + (3*z^21 + 7*z^20 - 26*z^19 - 43*z^18 - 24*z^17 + 43*z^16 - 13*z^15 - 29*z^14 + 28*z^13 + 49*z^12 + 24*z^11 - 54*z^10 - 82*z^9 + 35*z^8 + 40*z^7 + 31*z^6 - 2*z^5 - 4*z^4 + z^3 - z^2)*u^3 + (z^20 + 9*z^19 - 4*z^18 - 30*z^17 - 44*z^16 - 5*z^15 - 6*z^13 - 25*z^12 - 17*z^11 + 9*z^10 - 5*z^9 - 19*z^8 - 11*z^7 + z^6 + 8*z^5 - z^4)*u^2 + (5*z^18 + 7*z^17 - 8*z^15 - 4*z^14 + 4*z^13 + 6*z^12 - 5*z^11 - 10*z^10 - 4*z^9 - z^8 - z^7 - 5*z^6 - 2*z^5)*u + (z^17 + 2*z^16 + z^15 - z^14 - 2*z^13 + 2*z^11 + z^10 - z^9 - 2*z^8 - z^7) */ static const long X1_35_r_n_0[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, 0, 0, 0, 0, 0, 0, -1, -2, -1, 1, 2, 0, -2, -1, 1, 2, 1 }; /* z^17 + 2*z^16 + z^15 - z^14 - 2*z^13 + 2*z^11 + z^10 - z^9 - 2*z^8 - z^7 */ static const long X1_35_r_n_1[21] = { evaltyp(t_VECSMALL) | _evallg(21), vZ, 0, 0, 0, 0, 0, -2, -5, -1, -1, -4, -10, -5, 6, 4, -4, -8, 0, 7, 5 }; /* 5*z^18 + 7*z^17 - 8*z^15 - 4*z^14 + 4*z^13 + 6*z^12 - 5*z^11 - 10*z^10 - 4*z^9 - z^8 - z^7 - 5*z^6 - 2*z^5 */ static const long X1_35_r_n_2[23] = { evaltyp(t_VECSMALL) | _evallg(23), vZ, 0, 0, 0, 0, -1, 8, 1, -11, -19, -5, 9, -17, -25, -6, 0, -5, -44, -30, -4, 9, 1 }; /* z^20 + 9*z^19 - 4*z^18 - 30*z^17 - 44*z^16 - 5*z^15 - 6*z^13 - 25*z^12 - 17*z^11 + 9*z^10 - 5*z^9 - 19*z^8 - 11*z^7 + z^6 + 8*z^5 - z^4 */ static const long X1_35_r_n_3[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, -1, 1, -4, -2, 31, 40, 35, -82, -54, 24, 49, 28, -29, -13, 43, -24, -43, -26, 7, 3 }; /* 3*z^21 + 7*z^20 - 26*z^19 - 43*z^18 - 24*z^17 + 43*z^16 - 13*z^15 - 29*z^14 + 28*z^13 + 49*z^12 + 24*z^11 - 54*z^10 - 82*z^9 + 35*z^8 + 40*z^7 + 31*z^6 - 2*z^5 - 4*z^4 + z^3 - z^2 */ static const long X1_35_r_n_4[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, 0, -1, 4, -50, -42, -57, 172, 289, 29, -168, -137, 109, 385, 178, 86, 103, 79, 0, -37, -9 }; /* -9*z^21 - 37*z^20 + 79*z^18 + 103*z^17 + 86*z^16 + 178*z^15 + 385*z^14 + 109*z^13 - 137*z^12 - 168*z^11 + 29*z^10 + 289*z^9 + 172*z^8 - 57*z^7 - 42*z^6 - 50*z^5 + 4*z^4 - z^3 */ static const long X1_35_r_n_5[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, 0, -13, 32, 34, 20, -125, -525, -71, 429, 449, -104, -802, -730, 74, 100, -10, -101, 40, 56, 9 }; /* 9*z^21 + 56*z^20 + 40*z^19 - 101*z^18 - 10*z^17 + 100*z^16 + 74*z^15 - 730*z^14 - 802*z^13 - 104*z^12 + 449*z^11 + 429*z^10 - 71*z^9 - 525*z^8 - 125*z^7 + 20*z^6 + 34*z^5 + 32*z^4 - 13*z^3 */ static const long X1_35_r_n_6[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, 11, 2, -27, 39, -23, 463, 43, -905, -980, -67, 767, 1090, -515, -1148, -523, 201, 314, -2, -34, -3 }; /* -3*z^21 - 34*z^20 - 2*z^19 + 314*z^18 + 201*z^17 - 523*z^16 - 1148*z^15 - 515*z^14 + 1090*z^13 + 767*z^12 - 67*z^11 - 980*z^10 - 905*z^9 + 43*z^8 + 463*z^7 - 23*z^6 + 39*z^5 - 27*z^4 + 2*z^3 + 11*z^2 */ static const long X1_35_r_n_7[23] = { evaltyp(t_VECSMALL) | _evallg(23), vZ, 0, -2, -9, 12, -73, 53, -187, -100, 1264, 1491, 188, -708, -950, 396, 2413, 1590, 184, -898, -522, -40, 7 }; /* 7*z^20 - 40*z^19 - 522*z^18 - 898*z^17 + 184*z^16 + 1590*z^15 + 2413*z^14 + 396*z^13 - 950*z^12 - 708*z^11 + 188*z^10 + 1491*z^9 + 1264*z^8 - 100*z^7 - 187*z^6 + 53*z^5 - 73*z^4 + 12*z^3 - 9*z^2 - 2*z */ static const long X1_35_r_n_8[22] = { evaltyp(t_VECSMALL) | _evallg(22), vZ, 0, 2, -1, 75, 65, 36, 278, -952, -1589, -131, 1263, 1000, 870, -1704, -2243, -1194, 381, 1085, 357, 19 }; /* 19*z^19 + 357*z^18 + 1085*z^17 + 381*z^16 - 1194*z^15 - 2243*z^14 - 1704*z^13 + 870*z^12 + 1000*z^11 + 1263*z^10 - 131*z^9 - 1589*z^8 - 952*z^7 + 278*z^6 + 36*z^5 + 65*z^4 + 75*z^3 - z^2 + 2*z */ static const long X1_35_r_n_9[21] = { evaltyp(t_VECSMALL) | _evallg(21), vZ, 0, 0, -43, -132, -62, -319, 249, 1172, 163, -1685, -1471, -2155, -1299, 1203, 1797, 1678, -149, -520, -85 }; /* -85*z^18 - 520*z^17 - 149*z^16 + 1678*z^15 + 1797*z^14 + 1203*z^13 - 1299*z^12 - 2155*z^11 - 1471*z^10 - 1685*z^9 + 163*z^8 + 1172*z^7 + 249*z^6 - 319*z^5 - 62*z^4 - 132*z^3 - 43*z^2 */ static const long X1_35_r_n_10[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, 11, 81, 84, 181, 111, -614, -339, 1142, 1495, 2152, 3806, 1269, -902, -2809, -2096, -152, 85 }; /* 85*z^17 - 152*z^16 - 2096*z^15 - 2809*z^14 - 902*z^13 + 1269*z^12 + 3806*z^11 + 2152*z^10 + 1495*z^9 + 1142*z^8 - 339*z^7 - 614*z^6 + 111*z^5 + 181*z^4 + 84*z^3 + 81*z^2 + 11*z */ static const long X1_35_r_n_11[19] = { evaltyp(t_VECSMALL) | _evallg(19), vZ, -1, -21, -46, -57, -90, 253, 373, -294, -855, -1239, -3864, -3365, -944, 1080, 2713, 1175, 72 }; /* 72*z^16 + 1175*z^15 + 2713*z^14 + 1080*z^13 - 944*z^12 - 3365*z^11 - 3864*z^10 - 1239*z^9 - 855*z^8 - 294*z^7 + 373*z^6 + 253*z^5 - 90*z^4 - 57*z^3 - 46*z^2 - 21*z - 1 */ static const long X1_35_r_n_12[18] = { evaltyp(t_VECSMALL) | _evallg(18), vZ, 2, 11, 11, 21, -88, -225, -65, 272, 472, 2378, 3700, 2193, 1490, -552, -1155, -232 }; /* -232*z^15 - 1155*z^14 - 552*z^13 + 1490*z^12 + 2193*z^11 + 3700*z^10 + 2378*z^9 + 472*z^8 + 272*z^7 - 65*z^6 - 225*z^5 - 88*z^4 + 21*z^3 + 11*z^2 + 11*z + 2 */ static const long X1_35_r_n_13[17] = { evaltyp(t_VECSMALL) | _evallg(17), vZ, -1, -1, -2, 21, 79, 61, -62, -162, -972, -2523, -2147, -2223, -1703, 19, 174 }; /* 174*z^14 + 19*z^13 - 1703*z^12 - 2223*z^11 - 2147*z^10 - 2523*z^9 - 972*z^8 - 162*z^7 - 62*z^6 + 61*z^5 + 79*z^4 + 21*z^3 - 2*z^2 - z - 1 */ static const long X1_35_r_n_14[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, 0, 0, -2, -15, -16, 19, 70, 261, 1091, 1322, 1379, 1909, 861, 35 }; /* 35*z^13 + 861*z^12 + 1909*z^11 + 1379*z^10 + 1322*z^9 + 1091*z^8 + 261*z^7 + 70*z^6 + 19*z^5 - 16*z^4 - 15*z^3 - 2*z^2 */ static const long X1_35_r_n_15[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 1, 2, -4, -25, -46, -273, -527, -498, -940, -804, -156 }; /* -156*z^12 - 804*z^11 - 940*z^10 - 498*z^9 - 527*z^8 - 273*z^7 - 46*z^6 - 25*z^5 - 4*z^4 + 2*z^3 + z^2 */ static const long X1_35_r_n_16[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 0, 4, 7, 30, 124, 118, 234, 359, 125 }; /* 125*z^11 + 359*z^10 + 234*z^9 + 118*z^8 + 124*z^7 + 30*z^6 + 7*z^5 + 4*z^4 */ static const long X1_35_r_n_17[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 0, -1, 0, -13, -20, -24, -83, -51 }; /* -51*z^10 - 83*z^9 - 24*z^8 - 20*z^7 - 13*z^6 - z^4 */ static const long X1_35_r_n_18[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 0, 2, 0, 8, 11 }; /* 11*z^9 + 8*z^8 + 2*z^6 */ static const long X1_35_r_n_19[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, 0, 0, 0, 0, -1 }; /* -z^8 */ static const long *X1_35_r_n[22] = { (long *)(evaltyp(t_POL) | _evallg(22)), (long *)(evalvarn(0) | evalsigne(1)), X1_35_r_n_0, X1_35_r_n_1, X1_35_r_n_2, X1_35_r_n_3, X1_35_r_n_4, X1_35_r_n_5, X1_35_r_n_6, X1_35_r_n_7, X1_35_r_n_8, X1_35_r_n_9, X1_35_r_n_10, X1_35_r_n_11, X1_35_r_n_12, X1_35_r_n_13, X1_35_r_n_14, X1_35_r_n_15, X1_35_r_n_16, X1_35_r_n_17, X1_35_r_n_18, X1_35_r_n_19 }; /* (-z^10 + z^7)*u^16 + (10*z^11 + 5*z^10 - 9*z^8 - 4*z^7 - 2*z^5 - z^4)*u^15 + (-40*z^12 - 47*z^11 - 8*z^10 + 32*z^9 + 35*z^8 + 4*z^7 + 19*z^6 + 17*z^5 + 4*z^4 + z^3 + 2*z^2)*u^14 + (-z^14 + 77*z^13 + 175*z^12 + 71*z^11 - 48*z^10 - 122*z^9 - 33*z^8 - 75*z^7 - 107*z^6 - 48*z^5 - 12*z^4 - 22*z^3 - 6*z^2 - 1)*u^13 + (7*z^15 - 50*z^14 - 307*z^13 - 248*z^12 - 21*z^11 + 193*z^10 + 109*z^9 + 149*z^8 + 348*z^7 + 235*z^6 + 71*z^5 + 95*z^4 + 63*z^3 + 3*z^2 + 9*z + 2)*u^12 + (-19*z^16 - 79*z^15 + 169*z^14 + 406*z^13 + 219*z^12 - 27*z^11 - 153*z^10 - 117*z^9 - 627*z^8 - 612*z^7 - 237*z^6 - 201*z^5 - 257*z^4 - 38*z^3 - 28*z^2 - 20*z - 1)*u^11 + (23*z^17 + 192*z^16 + 271*z^15 - 206*z^14 - 400*z^13 - 436*z^12 - 70*z^11 - 106*z^10 + 512*z^9 + 884*z^8 + 427*z^7 + 180*z^6 + 492*z^5 + 171*z^4 + 21*z^3 + 73*z^2 + 11*z)*u^10 + (-7*z^18 - 142*z^17 - 520*z^16 - 311*z^15 + 307*z^14 + 779*z^13 + 598*z^12 + 382*z^11 + 204*z^10 - 520*z^9 - 317*z^8 + 106*z^7 - 343*z^6 - 348*z^5 + 75*z^4 - 108*z^3 - 45*z^2)*u^9 + (-11*z^19 - 6*z^18 + 271*z^17 + 539*z^16 + 53*z^15 - 548*z^14 - 883*z^13 - 517*z^12 - 885*z^11 - 445*z^10 - 196*z^9 - 456*z^8 - 282*z^7 + 295*z^6 - 201*z^5 + 2*z^4 + 91*z^3 + 2*z)*u^8 + (11*z^20 + 75*z^19 + 84*z^18 - 240*z^17 - 307*z^16 - 33*z^15 + 466*z^14 + 459*z^13 + 840*z^12 + 1094*z^11 + 575*z^10 + 413*z^9 + 589*z^8 + 9*z^7 + 163*z^6 + 191*z^5 - 109*z^4 - z^3 - 10*z^2 - 2*z)*u^7 + (-3*z^21 - 45*z^20 - 158*z^19 - 94*z^18 + 231*z^17 + 363*z^16 + 171*z^15 - 237*z^14 - 385*z^13 - 810*z^12 - 341*z^11 + 132*z^10 - 60*z^9 - 109*z^8 + 43*z^7 - 218*z^6 + 86*z^5 + 11*z^4 + 11*z^3 + 12*z^2)*u^6 + (9*z^21 + 66*z^20 + 128*z^19 - 49*z^18 - 304*z^17 - 367*z^16 - 4*z^15 + 143*z^14 + 189*z^13 - 122*z^12 - 610*z^11 - 532*z^10 - 58*z^9 - 108*z^8 + 91*z^7 - 19*z^6 - 22*z^5 + 19*z^4 - 19*z^3)*u^5 + (-9*z^21 - 40*z^20 - 16*z^19 + 130*z^18 + 208*z^17 + 70*z^16 - 130*z^15 + 7*z^14 + 219*z^13 + 509*z^12 + 451*z^11 + 43*z^10 - 81*z^9 - 62*z^8 - 56*z^7 + 12*z^6 - 48*z^5 + 4*z^4)*u^4 + (3*z^21 + 7*z^20 - 27*z^19 - 58*z^18 - 16*z^17 + 104*z^16 + 68*z^15 - 67*z^14 - 162*z^13 - 115*z^12 + 88*z^11 + 186*z^10 + 80*z^9 + 36*z^8 - 18*z^7 + 18*z^6 + 6*z^5 - 3*z^4 - z^2)*u^3 + (z^20 + 9*z^19 - 4*z^18 - 36*z^17 - 51*z^16 + 2*z^15 + 26*z^14 + 8*z^13 - 60*z^12 - 85*z^11 - 24*z^10 + 28*z^9 + 38*z^8 + 19*z^7 + 4*z^5 - z^4 + z^3)*u^2 + (5*z^18 + 7*z^17 - z^16 - 10*z^15 - 4*z^14 + 9*z^13 + 14*z^12 - 3*z^11 - 19*z^10 - 17*z^9 - 7*z^8 + 3*z^7 + 2*z^6 + 2*z^5 + z^4)*u + (z^17 + 2*z^16 + z^15 - z^14 - 2*z^13 + 2*z^11 + z^10 - z^9 - 2*z^8 - z^7) */ static const long X1_35_r_d_0[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, 0, 0, 0, 0, 0, 0, -1, -2, -1, 1, 2, 0, -2, -1, 1, 2, 1 }; /* z^17 + 2*z^16 + z^15 - z^14 - 2*z^13 + 2*z^11 + z^10 - z^9 - 2*z^8 - z^7 */ static const long X1_35_r_d_1[21] = { evaltyp(t_VECSMALL) | _evallg(21), vZ, 0, 0, 0, 0, 1, 2, 2, 3, -7, -17, -19, -3, 14, 9, -4, -10, -1, 7, 5 }; /* 5*z^18 + 7*z^17 - z^16 - 10*z^15 - 4*z^14 + 9*z^13 + 14*z^12 - 3*z^11 - 19*z^10 - 17*z^9 - 7*z^8 + 3*z^7 + 2*z^6 + 2*z^5 + z^4 */ static const long X1_35_r_d_2[23] = { evaltyp(t_VECSMALL) | _evallg(23), vZ, 0, 0, 0, 1, -1, 4, 0, 19, 38, 28, -24, -85, -60, 8, 26, 2, -51, -36, -4, 9, 1 }; /* z^20 + 9*z^19 - 4*z^18 - 36*z^17 - 51*z^16 + 2*z^15 + 26*z^14 + 8*z^13 - 60*z^12 - 85*z^11 - 24*z^10 + 28*z^9 + 38*z^8 + 19*z^7 + 4*z^5 - z^4 + z^3 */ static const long X1_35_r_d_3[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, -1, 0, -3, 6, 18, -18, 36, 80, 186, 88, -115, -162, -67, 68, 104, -16, -58, -27, 7, 3 }; /* 3*z^21 + 7*z^20 - 27*z^19 - 58*z^18 - 16*z^17 + 104*z^16 + 68*z^15 - 67*z^14 - 162*z^13 - 115*z^12 + 88*z^11 + 186*z^10 + 80*z^9 + 36*z^8 - 18*z^7 + 18*z^6 + 6*z^5 - 3*z^4 - z^2 */ static const long X1_35_r_d_4[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, 0, 0, 4, -48, 12, -56, -62, -81, 43, 451, 509, 219, 7, -130, 70, 208, 130, -16, -40, -9 }; /* -9*z^21 - 40*z^20 - 16*z^19 + 130*z^18 + 208*z^17 + 70*z^16 - 130*z^15 + 7*z^14 + 219*z^13 + 509*z^12 + 451*z^11 + 43*z^10 - 81*z^9 - 62*z^8 - 56*z^7 + 12*z^6 - 48*z^5 + 4*z^4 */ static const long X1_35_r_d_5[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, 0, -19, 19, -22, -19, 91, -108, -58, -532, -610, -122, 189, 143, -4, -367, -304, -49, 128, 66, 9 }; /* 9*z^21 + 66*z^20 + 128*z^19 - 49*z^18 - 304*z^17 - 367*z^16 - 4*z^15 + 143*z^14 + 189*z^13 - 122*z^12 - 610*z^11 - 532*z^10 - 58*z^9 - 108*z^8 + 91*z^7 - 19*z^6 - 22*z^5 + 19*z^4 - 19*z^3 */ static const long X1_35_r_d_6[24] = { evaltyp(t_VECSMALL) | _evallg(24), vZ, 0, 0, 12, 11, 11, 86, -218, 43, -109, -60, 132, -341, -810, -385, -237, 171, 363, 231, -94, -158, -45, -3 }; /* -3*z^21 - 45*z^20 - 158*z^19 - 94*z^18 + 231*z^17 + 363*z^16 + 171*z^15 - 237*z^14 - 385*z^13 - 810*z^12 - 341*z^11 + 132*z^10 - 60*z^9 - 109*z^8 + 43*z^7 - 218*z^6 + 86*z^5 + 11*z^4 + 11*z^3 + 12*z^2 */ static const long X1_35_r_d_7[23] = { evaltyp(t_VECSMALL) | _evallg(23), vZ, 0, -2, -10, -1, -109, 191, 163, 9, 589, 413, 575, 1094, 840, 459, 466, -33, -307, -240, 84, 75, 11 }; /* 11*z^20 + 75*z^19 + 84*z^18 - 240*z^17 - 307*z^16 - 33*z^15 + 466*z^14 + 459*z^13 + 840*z^12 + 1094*z^11 + 575*z^10 + 413*z^9 + 589*z^8 + 9*z^7 + 163*z^6 + 191*z^5 - 109*z^4 - z^3 - 10*z^2 - 2*z */ static const long X1_35_r_d_8[22] = { evaltyp(t_VECSMALL) | _evallg(22), vZ, 0, 2, 0, 91, 2, -201, 295, -282, -456, -196, -445, -885, -517, -883, -548, 53, 539, 271, -6, -11 }; /* -11*z^19 - 6*z^18 + 271*z^17 + 539*z^16 + 53*z^15 - 548*z^14 - 883*z^13 - 517*z^12 - 885*z^11 - 445*z^10 - 196*z^9 - 456*z^8 - 282*z^7 + 295*z^6 - 201*z^5 + 2*z^4 + 91*z^3 + 2*z */ static const long X1_35_r_d_9[21] = { evaltyp(t_VECSMALL) | _evallg(21), vZ, 0, 0, -45, -108, 75, -348, -343, 106, -317, -520, 204, 382, 598, 779, 307, -311, -520, -142, -7 }; /* -7*z^18 - 142*z^17 - 520*z^16 - 311*z^15 + 307*z^14 + 779*z^13 + 598*z^12 + 382*z^11 + 204*z^10 - 520*z^9 - 317*z^8 + 106*z^7 - 343*z^6 - 348*z^5 + 75*z^4 - 108*z^3 - 45*z^2 */ static const long X1_35_r_d_10[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, 11, 73, 21, 171, 492, 180, 427, 884, 512, -106, -70, -436, -400, -206, 271, 192, 23 }; /* 23*z^17 + 192*z^16 + 271*z^15 - 206*z^14 - 400*z^13 - 436*z^12 - 70*z^11 - 106*z^10 + 512*z^9 + 884*z^8 + 427*z^7 + 180*z^6 + 492*z^5 + 171*z^4 + 21*z^3 + 73*z^2 + 11*z */ static const long X1_35_r_d_11[19] = { evaltyp(t_VECSMALL) | _evallg(19), vZ, -1, -20, -28, -38, -257, -201, -237, -612, -627, -117, -153, -27, 219, 406, 169, -79, -19 }; /* -19*z^16 - 79*z^15 + 169*z^14 + 406*z^13 + 219*z^12 - 27*z^11 - 153*z^10 - 117*z^9 - 627*z^8 - 612*z^7 - 237*z^6 - 201*z^5 - 257*z^4 - 38*z^3 - 28*z^2 - 20*z - 1 */ static const long X1_35_r_d_12[18] = { evaltyp(t_VECSMALL) | _evallg(18), vZ, 2, 9, 3, 63, 95, 71, 235, 348, 149, 109, 193, -21, -248, -307, -50, 7 }; /* 7*z^15 - 50*z^14 - 307*z^13 - 248*z^12 - 21*z^11 + 193*z^10 + 109*z^9 + 149*z^8 + 348*z^7 + 235*z^6 + 71*z^5 + 95*z^4 + 63*z^3 + 3*z^2 + 9*z + 2 */ static const long X1_35_r_d_13[17] = { evaltyp(t_VECSMALL) | _evallg(17), vZ, -1, 0, -6, -22, -12, -48, -107, -75, -33, -122, -48, 71, 175, 77, -1 }; /* -z^14 + 77*z^13 + 175*z^12 + 71*z^11 - 48*z^10 - 122*z^9 - 33*z^8 - 75*z^7 - 107*z^6 - 48*z^5 - 12*z^4 - 22*z^3 - 6*z^2 - 1 */ static const long X1_35_r_d_14[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 2, 1, 4, 17, 19, 4, 35, 32, -8, -47, -40 }; /* -40*z^12 - 47*z^11 - 8*z^10 + 32*z^9 + 35*z^8 + 4*z^7 + 19*z^6 + 17*z^5 + 4*z^4 + z^3 + 2*z^2 */ static const long X1_35_r_d_15[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 0, -1, -2, 0, -4, -9, 0, 5, 10 }; /* 10*z^11 + 5*z^10 - 9*z^8 - 4*z^7 - 2*z^5 - z^4 */ static const long X1_35_r_d_16[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1 }; /* -z^10 + z^7 */ static const long *X1_35_r_d[19] = { (long *)(evaltyp(t_POL) | _evallg(19)), (long *)(evalvarn(0) | evalsigne(1)), X1_35_r_d_0, X1_35_r_d_1, X1_35_r_d_2, X1_35_r_d_3, X1_35_r_d_4, X1_35_r_d_5, X1_35_r_d_6, X1_35_r_d_7, X1_35_r_d_8, X1_35_r_d_9, X1_35_r_d_10, X1_35_r_d_11, X1_35_r_d_12, X1_35_r_d_13, X1_35_r_d_14, X1_35_r_d_15, X1_35_r_d_16 }; /* z^4*u^10 + (-5*z^5 - 4*z^4 - z^2)*u^9 + (7*z^6 + 18*z^5 + 4*z^4 + 4*z^3 + 2*z^2)*u^8 + (3*z^7 - 22*z^6 - 16*z^5 - 5*z^4 - 6*z^3 + z + 1)*u^7 + (-14*z^8 - 10*z^7 + 17*z^6 + z^5 + 5*z^4 - 3*z^3 - 3*z^2 - 6*z - 1)*u^6 + (7*z^9 + 36*z^8 + 8*z^7 + 2*z^6 - z^5 + 5*z^4 + 3*z^3 + 10*z^2 + 6*z)*u^5 + (4*z^10 - 15*z^9 - 23*z^8 + 2*z^6 + 3*z^5 + z^4 - 3*z^3 - 9*z^2)*u^4 + (-3*z^11 - 9*z^10 + 8*z^9 - 2*z^8 - 4*z^7 - 9*z^6 - 5*z^5 - 6*z^4 + 6*z^3 - z^2)*u^3 + (6*z^11 + 5*z^10 + 3*z^8 + 4*z^7 + 3*z^6 + 5*z^5 - 3*z^4 + z^2 - z)*u^2 + (-3*z^11 + z^10 - z^8 - z^7 - 2*z^6 + z^4 - 2*z^3)*u + (-z^10 - z^5) */ static const long X1_35_s_n_0[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1 }; /* -z^10 - z^5 */ static const long X1_35_s_n_1[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, -2, 1, 0, -2, -1, -1, 0, 1, -3 }; /* -3*z^11 + z^10 - z^8 - z^7 - 2*z^6 + z^4 - 2*z^3 */ static const long X1_35_s_n_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, -1, 1, 0, -3, 5, 3, 4, 3, 0, 5, 6 }; /* 6*z^11 + 5*z^10 + 3*z^8 + 4*z^7 + 3*z^6 + 5*z^5 - 3*z^4 + z^2 - z */ static const long X1_35_s_n_3[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, -1, 6, -6, -5, -9, -4, -2, 8, -9, -3 }; /* -3*z^11 - 9*z^10 + 8*z^9 - 2*z^8 - 4*z^7 - 9*z^6 - 5*z^5 - 6*z^4 + 6*z^3 - z^2 */ static const long X1_35_s_n_4[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, -9, -3, 1, 3, 2, 0, -23, -15, 4 }; /* 4*z^10 - 15*z^9 - 23*z^8 + 2*z^6 + 3*z^5 + z^4 - 3*z^3 - 9*z^2 */ static const long X1_35_s_n_5[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 6, 10, 3, 5, -1, 2, 8, 36, 7 }; /* 7*z^9 + 36*z^8 + 8*z^7 + 2*z^6 - z^5 + 5*z^4 + 3*z^3 + 10*z^2 + 6*z */ static const long X1_35_s_n_6[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, -6, -3, -3, 5, 1, 17, -10, -14 }; /* -14*z^8 - 10*z^7 + 17*z^6 + z^5 + 5*z^4 - 3*z^3 - 3*z^2 - 6*z - 1 */ static const long X1_35_s_n_7[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 1, 1, 0, -6, -5, -16, -22, 3 }; /* 3*z^7 - 22*z^6 - 16*z^5 - 5*z^4 - 6*z^3 + z + 1 */ static const long X1_35_s_n_8[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 2, 4, 4, 18, 7 }; /* 7*z^6 + 18*z^5 + 4*z^4 + 4*z^3 + 2*z^2 */ static const long X1_35_s_n_9[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, -1, 0, -4, -5 }; /* -5*z^5 - 4*z^4 - z^2 */ static const long X1_35_s_n_10[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, 0, 0, 1 }; /* z^4 */ static const long *X1_35_s_n[13] = { (long *)(evaltyp(t_POL) | _evallg(13)), (long *)(evalvarn(0) | evalsigne(1)), X1_35_s_n_0, X1_35_s_n_1, X1_35_s_n_2, X1_35_s_n_3, X1_35_s_n_4, X1_35_s_n_5, X1_35_s_n_6, X1_35_s_n_7, X1_35_s_n_8, X1_35_s_n_9, X1_35_s_n_10 }; /* z^5*u^9 + (-6*z^6 - 3*z^5 - z^3 - z^2)*u^8 + (13*z^7 + 16*z^6 + 2*z^5 + 5*z^4 + 8*z^3 + 2*z^2 + 1)*u^7 + (-10*z^8 - 31*z^7 - 9*z^6 - 10*z^5 - 22*z^4 - 13*z^3 + z^2 - 5*z - 1)*u^6 + (-3*z^9 + 21*z^8 + 16*z^7 + 10*z^6 + 30*z^5 + 28*z^4 - 3*z^3 + 6*z^2 + 6*z)*u^5 + (8*z^10 + 7*z^9 - 11*z^8 - 5*z^7 - 22*z^6 - 25*z^5 + 5*z^4 + 6*z^3 - 10*z^2)*u^4 + (-3*z^11 - 16*z^10 - 3*z^9 + z^8 + 7*z^7 + 6*z^6 - 8*z^5 - 20*z^4 + 5*z^3)*u^3 + (6*z^11 + 8*z^10 - z^9 + 3*z^7 + 7*z^6 + 16*z^5 + z^4 - 2*z^3 - z)*u^2 + (-3*z^11 + z^10 + z^9 - z^8 - 2*z^7 - 4*z^6 - z^5 + 3*z^4 + z^2)*u + (-z^10 - z^5) */ static const long X1_35_s_d_0[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1 }; /* -z^10 - z^5 */ static const long X1_35_s_d_1[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 1, 0, 3, -1, -4, -2, -1, 1, 1, -3 }; /* -3*z^11 + z^10 + z^9 - z^8 - 2*z^7 - 4*z^6 - z^5 + 3*z^4 + z^2 */ static const long X1_35_s_d_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, -1, 0, -2, 1, 16, 7, 3, 0, -1, 8, 6 }; /* 6*z^11 + 8*z^10 - z^9 + 3*z^7 + 7*z^6 + 16*z^5 + z^4 - 2*z^3 - z */ static const long X1_35_s_d_3[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 5, -20, -8, 6, 7, 1, -3, -16, -3 }; /* -3*z^11 - 16*z^10 - 3*z^9 + z^8 + 7*z^7 + 6*z^6 - 8*z^5 - 20*z^4 + 5*z^3 */ static const long X1_35_s_d_4[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, -10, 6, 5, -25, -22, -5, -11, 7, 8 }; /* 8*z^10 + 7*z^9 - 11*z^8 - 5*z^7 - 22*z^6 - 25*z^5 + 5*z^4 + 6*z^3 - 10*z^2 */ static const long X1_35_s_d_5[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 6, 6, -3, 28, 30, 10, 16, 21, -3 }; /* -3*z^9 + 21*z^8 + 16*z^7 + 10*z^6 + 30*z^5 + 28*z^4 - 3*z^3 + 6*z^2 + 6*z */ static const long X1_35_s_d_6[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, -5, 1, -13, -22, -10, -9, -31, -10 }; /* -10*z^8 - 31*z^7 - 9*z^6 - 10*z^5 - 22*z^4 - 13*z^3 + z^2 - 5*z - 1 */ static const long X1_35_s_d_7[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 1, 0, 2, 8, 5, 2, 16, 13 }; /* 13*z^7 + 16*z^6 + 2*z^5 + 5*z^4 + 8*z^3 + 2*z^2 + 1 */ static const long X1_35_s_d_8[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, -1, -1, 0, -3, -6 }; /* -6*z^6 - 3*z^5 - z^3 - z^2 */ static const long X1_35_s_d_9[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 0, 0, 0, 0, 1 }; /* z^5 */ static const long *X1_35_s_d[12] = { (long *)(evaltyp(t_POL) | _evallg(12)), (long *)(evalvarn(0) | evalsigne(1)), X1_35_s_d_0, X1_35_s_d_1, X1_35_s_d_2, X1_35_s_d_3, X1_35_s_d_4, X1_35_s_d_5, X1_35_s_d_6, X1_35_s_d_7, X1_35_s_d_8, X1_35_s_d_9 }; /* (z^7 - 2*z^6 + 2*z^5 - z^4)*u^8 + (4*z^8 - 4*z^7 + 4*z^5 - 4*z^4)*u^7 + (6*z^9 + 2*z^8 - 10*z^7 + 10*z^6 + z^5 - 13*z^4 + 4*z^3 - z^2)*u^6 + (4*z^10 + 10*z^9 - 10*z^8 + 24*z^6 - 36*z^5 + 2*z^4 + 2*z^3 - 2*z^2)*u^5 + (z^11 + 8*z^10 + z^9 - 9*z^8 + 27*z^7 - 9*z^6 - 55*z^5 + 34*z^4 - 13*z^3)*u^4 + (2*z^11 + 4*z^10 - 4*z^9 + 8*z^8 + 26*z^7 - 54*z^6 - 24*z^5 + 50*z^4 - 38*z^3 + 12*z^2 - 2*z)*u^3 + (z^11 + 15*z^8 - 3*z^7 - 43*z^6 + 9*z^5 + 29*z^4 - 39*z^3 + 22*z^2 - 7*z + 1)*u^2 + (2*z^9 + 6*z^8 - 10*z^7 - 14*z^6 + 18*z^5 - 10*z^4 + 2*z^3)*u + (z^9 - 3*z^7 + z^6) */ static const long X1_36_crv_0[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 0, 1, -3, 0, 1 }; /* z^9 - 3*z^7 + z^6 */ static const long X1_36_crv_1[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 2, -10, 18, -14, -10, 6, 2 }; /* 2*z^9 + 6*z^8 - 10*z^7 - 14*z^6 + 18*z^5 - 10*z^4 + 2*z^3 */ static const long X1_36_crv_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 1, -7, 22, -39, 29, 9, -43, -3, 15, 0, 0, 1 }; /* z^11 + 15*z^8 - 3*z^7 - 43*z^6 + 9*z^5 + 29*z^4 - 39*z^3 + 22*z^2 - 7*z + 1 */ static const long X1_36_crv_3[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, -2, 12, -38, 50, -24, -54, 26, 8, -4, 4, 2 }; /* 2*z^11 + 4*z^10 - 4*z^9 + 8*z^8 + 26*z^7 - 54*z^6 - 24*z^5 + 50*z^4 - 38*z^3 + 12*z^2 - 2*z */ static const long X1_36_crv_4[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, -13, 34, -55, -9, 27, -9, 1, 8, 1 }; /* z^11 + 8*z^10 + z^9 - 9*z^8 + 27*z^7 - 9*z^6 - 55*z^5 + 34*z^4 - 13*z^3 */ static const long X1_36_crv_5[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 0, -2, 2, 2, -36, 24, 0, -10, 10, 4 }; /* 4*z^10 + 10*z^9 - 10*z^8 + 24*z^6 - 36*z^5 + 2*z^4 + 2*z^3 - 2*z^2 */ static const long X1_36_crv_6[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, -1, 4, -13, 1, 10, -10, 2, 6 }; /* 6*z^9 + 2*z^8 - 10*z^7 + 10*z^6 + z^5 - 13*z^4 + 4*z^3 - z^2 */ static const long X1_36_crv_7[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 0, 0, 0, 0, -4, 4, 0, -4, 4 }; /* 4*z^8 - 4*z^7 + 4*z^5 - 4*z^4 */ static const long X1_36_crv_8[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, 0, 0, 0, -1, 2, -2, 1 }; /* z^7 - 2*z^6 + 2*z^5 - z^4 */ static const long *X1_36_crv[11] = { (long *)(evaltyp(t_POL) | _evallg(11)), (long *)(evalvarn(0) | evalsigne(1)), X1_36_crv_0, X1_36_crv_1, X1_36_crv_2, X1_36_crv_3, X1_36_crv_4, X1_36_crv_5, X1_36_crv_6, X1_36_crv_7, X1_36_crv_8 }; /* (z^3 - z)*u^4 + (4*z^4 - 4*z^2)*u^3 + (5*z^5 + z^4 - 6*z^3 - z^2 - 1)*u^2 + (2*z^6 + 2*z^5 - 4*z^4 - 2*z^3 - 2*z)*u + (z^6 - z^5 - 2*z^4 + 3*z^3 - 5*z^2 + 3*z - 1) */ static const long X1_36_r_n_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, 3, -5, 3, -2, -1, 1 }; /* z^6 - z^5 - 2*z^4 + 3*z^3 - 5*z^2 + 3*z - 1 */ static const long X1_36_r_n_1[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, -2, 0, -2, -4, 2, 2 }; /* 2*z^6 + 2*z^5 - 4*z^4 - 2*z^3 - 2*z */ static const long X1_36_r_n_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, 0, -1, -6, 1, 5 }; /* 5*z^5 + z^4 - 6*z^3 - z^2 - 1 */ static const long X1_36_r_n_3[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, -4, 0, 4 }; /* 4*z^4 - 4*z^2 */ static const long X1_36_r_n_4[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -1, 0, 1 }; /* z^3 - z */ static const long *X1_36_r_n[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_36_r_n_0, X1_36_r_n_1, X1_36_r_n_2, X1_36_r_n_3, X1_36_r_n_4 }; /* (z^3 - z)*u^4 + (6*z^4 - 2*z^3 - 4*z^2 + z)*u^3 + (7*z^5 + 3*z^4 - 12*z^3 + 3*z^2 + z - 1)*u^2 + (2*z^6 + 5*z^5 - 5*z^4 - 8*z^3 + 9*z^2 - 5*z + 1)*u + (z^6 - 3*z^4 + z^3) */ static const long X1_36_r_d_0[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 0, 0, 1, -3, 0, 1 }; /* z^6 - 3*z^4 + z^3 */ static const long X1_36_r_d_1[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 1, -5, 9, -8, -5, 5, 2 }; /* 2*z^6 + 5*z^5 - 5*z^4 - 8*z^3 + 9*z^2 - 5*z + 1 */ static const long X1_36_r_d_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, 1, 3, -12, 3, 7 }; /* 7*z^5 + 3*z^4 - 12*z^3 + 3*z^2 + z - 1 */ static const long X1_36_r_d_3[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 1, -4, -2, 6 }; /* 6*z^4 - 2*z^3 - 4*z^2 + z */ static const long X1_36_r_d_4[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -1, 0, 1 }; /* z^3 - z */ static const long *X1_36_r_d[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_36_r_d_0, X1_36_r_d_1, X1_36_r_d_2, X1_36_r_d_3, X1_36_r_d_4 }; /* (z^3 - z)*u^4 + (2*z^4 + 2*z^3 - 4*z^2 - z)*u^3 + (z^5 + 3*z^4 - 2*z^3 - 6*z^2 - 1)*u^2 + (z^5 + z^4 - 4*z^3 - 5*z^2 + z - 1)*u + (-2*z^3 - 2*z^2 + 2*z - 1) */ static const long X1_36_s_n_0[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, -1, 2, -2, -2 }; /* -2*z^3 - 2*z^2 + 2*z - 1 */ static const long X1_36_s_n_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, 1, -5, -4, 1, 1 }; /* z^5 + z^4 - 4*z^3 - 5*z^2 + z - 1 */ static const long X1_36_s_n_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, 0, -6, -2, 3, 1 }; /* z^5 + 3*z^4 - 2*z^3 - 6*z^2 - 1 */ static const long X1_36_s_n_3[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, -1, -4, 2, 2 }; /* 2*z^4 + 2*z^3 - 4*z^2 - z */ static const long X1_36_s_n_4[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -1, 0, 1 }; /* z^3 - z */ static const long *X1_36_s_n[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_36_s_n_0, X1_36_s_n_1, X1_36_s_n_2, X1_36_s_n_3, X1_36_s_n_4 }; /* (z^3 - z)*u^4 + (4*z^4 - 4*z^2)*u^3 + (3*z^5 + 5*z^4 - 8*z^3 - 2*z^2 + z - 1)*u^2 + (4*z^5 - 10*z^3 + 4*z^2 - 2*z)*u + (z^5 - z^4 - 4*z^3 + 3*z^2 - z) */ static const long X1_36_s_d_0[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, -1, 3, -4, -1, 1 }; /* z^5 - z^4 - 4*z^3 + 3*z^2 - z */ static const long X1_36_s_d_1[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, -2, 4, -10, 0, 4 }; /* 4*z^5 - 10*z^3 + 4*z^2 - 2*z */ static const long X1_36_s_d_2[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, -1, 1, -2, -8, 5, 3 }; /* 3*z^5 + 5*z^4 - 8*z^3 - 2*z^2 + z - 1 */ static const long X1_36_s_d_3[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 0, 0, -4, 0, 4 }; /* 4*z^4 - 4*z^2 */ static const long X1_36_s_d_4[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, -1, 0, 1 }; /* z^3 - z */ static const long *X1_36_s_d[7] = { (long *)(evaltyp(t_POL) | _evallg(7)), (long *)(evalvarn(0) | evalsigne(1)), X1_36_s_d_0, X1_36_s_d_1, X1_36_s_d_2, X1_36_s_d_3, X1_36_s_d_4 }; /* (z^4 + 4*z^3 + 6*z^2 + 4*z + 1)*x^18 + (4*z^6 + 27*z^5 + 61*z^4 + 53*z^3 + 3*z^2 - 20*z - 8)*x^17 + (6*z^8 + 64*z^7 + 227*z^6 + 318*z^5 + 86*z^4 - 186*z^3 - 123*z^2 + 28*z + 28)*x^16 + (4*z^10 + 70*z^9 + 390*z^8 + 899*z^7 + 697*z^6 - 460*z^5 - 878*z^4 - 71*z^3 + 299*z^2 + 18*z - 56)*x^15 + (z^12 + 36*z^11 + 334*z^10 + 1256*z^9 + 1944*z^8 + 227*z^7 - 2560*z^6 - 1975*z^5 + 530*z^4 + 635*z^3 - 205*z^2 - 65*z + 70)*x^14 + (7*z^13 + 137*z^12 + 885*z^11 + 2414*z^10 + 2085*z^9 - 2931*z^8 - 6951*z^7 - 2982*z^6 + 2372*z^5 + 2034*z^4 + 306*z^3 + 38*z^2 - 50*z - 56)*x^13 + (21*z^14 + 294*z^13 + 1420*z^12 + 2579*z^11 - 870*z^10 - 9749*z^9 - 11481*z^8 + 664*z^7 + 10483*z^6 + 6962*z^5 - 527*z^4 - 2730*z^3 - 733*z^2 + 322*z + 28)*x^12 + (35*z^15 + 363*z^14 + 1210*z^13 + 414*z^12 - 6515*z^11 - 14529*z^10 - 6010*z^9 + 16913*z^8 + 23552*z^7 + 4413*z^6 - 13117*z^5 - 8675*z^4 + 2488*z^3 + 2270*z^2 - 494*z - 8)*x^11 + (26*z^16 + 184*z^15 + 129*z^14 - 2320*z^13 - 8129*z^12 - 7355*z^11 + 12096*z^10 + 31592*z^9 + 16424*z^8 - 20987*z^7 - 29776*z^6 - 1252*z^5 + 14573*z^4 + 1991*z^3 - 3145*z^2 + 412*z + 1)*x^10 + (-z^18 - 5*z^17 - 52*z^16 - 501*z^15 - 2023*z^14 - 2681*z^13 + 4715*z^12 + 19581*z^11 + 18001*z^10 - 14660*z^9 - 40593*z^8 - 16842*z^7 + 25005*z^6 + 20440*z^5 - 8210*z^4 - 5975*z^3 + 2525*z^2 - 210*z)*x^9 + (-z^19 - 10*z^18 - 52*z^17 - 172*z^16 - 162*z^15 + 1311*z^14 + 5622*z^13 + 7317*z^12 - 5435*z^11 - 25859*z^10 - 20839*z^9 + 16281*z^8 + 34475*z^7 + 2999*z^6 - 20366*z^5 - 2065*z^4 + 5725*z^3 - 1264*z^2 + 66*z)*x^8 + (3*z^18 + 32*z^17 + 180*z^16 + 595*z^15 + 789*z^14 - 1585*z^13 - 7639*z^12 - 9008*z^11 + 5183*z^10 + 22272*z^9 + 12561*z^8 - 16256*z^7 - 16253*z^6 + 7183*z^5 + 5741*z^4 - 3053*z^3 + 395*z^2 - 12*z)*x^7 + (-3*z^17 - 39*z^16 - 243*z^15 - 807*z^14 - 1079*z^13 + 1278*z^12 + 6267*z^11 + 6155*z^10 - 4834*z^9 - 13100*z^8 - 1905*z^7 + 9941*z^6 + 1372*z^5 - 3726*z^4 + 978*z^3 - 72*z^2 + z)*x^6 + (z^16 + 22*z^15 + 166*z^14 + 564*z^13 + 678*z^12 - 891*z^11 - 3469*z^10 - 2293*z^9 + 3656*z^8 + 4495*z^7 - 2053*z^6 - 2249*z^5 + 1275*z^4 - 180*z^3 + 6*z^2)*x^5 + (-5*z^14 - 60*z^13 - 210*z^12 - 180*z^11 + 555*z^10 + 1350*z^9 + 185*z^8 - 1655*z^7 - 400*z^6 + 910*z^5 - 240*z^4 + 15*z^3)*x^4 + (10*z^12 + 35*z^11 - 15*z^10 - 265*z^9 - 325*z^8 + 201*z^7 + 321*z^6 - 180*z^5 + 20*z^4)*x^3 + (26*z^9 + 77*z^8 + 30*z^7 - 72*z^6 + 15*z^5)*x^2 + (-z^9 - 7*z^8 - 12*z^7 + 6*z^6)*x + z^7 */ static const long X1_37_crv_0[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, 0, 0, 0, 0, 0, 0, 1 }; /* z^7 */ static const long X1_37_crv_1[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 0, 6, -12, -7, -1 }; /* -z^9 - 7*z^8 - 12*z^7 + 6*z^6 */ static const long X1_37_crv_2[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 15, -72, 30, 77, 26 }; /* 26*z^9 + 77*z^8 + 30*z^7 - 72*z^6 + 15*z^5 */ static const long X1_37_crv_3[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 0, 0, 20, -180, 321, 201, -325, -265, -15, 35, 10 }; /* 10*z^12 + 35*z^11 - 15*z^10 - 265*z^9 - 325*z^8 + 201*z^7 + 321*z^6 - 180*z^5 + 20*z^4 */ static const long X1_37_crv_4[17] = { evaltyp(t_VECSMALL) | _evallg(17), vZ, 0, 0, 0, 15, -240, 910, -400, -1655, 185, 1350, 555, -180, -210, -60, -5 }; /* -5*z^14 - 60*z^13 - 210*z^12 - 180*z^11 + 555*z^10 + 1350*z^9 + 185*z^8 - 1655*z^7 - 400*z^6 + 910*z^5 - 240*z^4 + 15*z^3 */ static const long X1_37_crv_5[19] = { evaltyp(t_VECSMALL) | _evallg(19), vZ, 0, 0, 6, -180, 1275, -2249, -2053, 4495, 3656, -2293, -3469, -891, 678, 564, 166, 22, 1 }; /* z^16 + 22*z^15 + 166*z^14 + 564*z^13 + 678*z^12 - 891*z^11 - 3469*z^10 - 2293*z^9 + 3656*z^8 + 4495*z^7 - 2053*z^6 - 2249*z^5 + 1275*z^4 - 180*z^3 + 6*z^2 */ static const long X1_37_crv_6[20] = { evaltyp(t_VECSMALL) | _evallg(20), vZ, 0, 1, -72, 978, -3726, 1372, 9941, -1905, -13100, -4834, 6155, 6267, 1278, -1079, -807, -243, -39, -3 }; /* -3*z^17 - 39*z^16 - 243*z^15 - 807*z^14 - 1079*z^13 + 1278*z^12 + 6267*z^11 + 6155*z^10 - 4834*z^9 - 13100*z^8 - 1905*z^7 + 9941*z^6 + 1372*z^5 - 3726*z^4 + 978*z^3 - 72*z^2 + z */ static const long X1_37_crv_7[21] = { evaltyp(t_VECSMALL) | _evallg(21), vZ, 0, -12, 395, -3053, 5741, 7183, -16253, -16256, 12561, 22272, 5183, -9008, -7639, -1585, 789, 595, 180, 32, 3 }; /* 3*z^18 + 32*z^17 + 180*z^16 + 595*z^15 + 789*z^14 - 1585*z^13 - 7639*z^12 - 9008*z^11 + 5183*z^10 + 22272*z^9 + 12561*z^8 - 16256*z^7 - 16253*z^6 + 7183*z^5 + 5741*z^4 - 3053*z^3 + 395*z^2 - 12*z */ static const long X1_37_crv_8[22] = { evaltyp(t_VECSMALL) | _evallg(22), vZ, 0, 66, -1264, 5725, -2065, -20366, 2999, 34475, 16281, -20839, -25859, -5435, 7317, 5622, 1311, -162, -172, -52, -10, -1 }; /* -z^19 - 10*z^18 - 52*z^17 - 172*z^16 - 162*z^15 + 1311*z^14 + 5622*z^13 + 7317*z^12 - 5435*z^11 - 25859*z^10 - 20839*z^9 + 16281*z^8 + 34475*z^7 + 2999*z^6 - 20366*z^5 - 2065*z^4 + 5725*z^3 - 1264*z^2 + 66*z */ static const long X1_37_crv_9[21] = { evaltyp(t_VECSMALL) | _evallg(21), vZ, 0, -210, 2525, -5975, -8210, 20440, 25005, -16842, -40593, -14660, 18001, 19581, 4715, -2681, -2023, -501, -52, -5, -1 }; /* -z^18 - 5*z^17 - 52*z^16 - 501*z^15 - 2023*z^14 - 2681*z^13 + 4715*z^12 + 19581*z^11 + 18001*z^10 - 14660*z^9 - 40593*z^8 - 16842*z^7 + 25005*z^6 + 20440*z^5 - 8210*z^4 - 5975*z^3 + 2525*z^2 - 210*z */ static const long X1_37_crv_10[19] = { evaltyp(t_VECSMALL) | _evallg(19), vZ, 1, 412, -3145, 1991, 14573, -1252, -29776, -20987, 16424, 31592, 12096, -7355, -8129, -2320, 129, 184, 26 }; /* 26*z^16 + 184*z^15 + 129*z^14 - 2320*z^13 - 8129*z^12 - 7355*z^11 + 12096*z^10 + 31592*z^9 + 16424*z^8 - 20987*z^7 - 29776*z^6 - 1252*z^5 + 14573*z^4 + 1991*z^3 - 3145*z^2 + 412*z + 1 */ static const long X1_37_crv_11[18] = { evaltyp(t_VECSMALL) | _evallg(18), vZ, -8, -494, 2270, 2488, -8675, -13117, 4413, 23552, 16913, -6010, -14529, -6515, 414, 1210, 363, 35 }; /* 35*z^15 + 363*z^14 + 1210*z^13 + 414*z^12 - 6515*z^11 - 14529*z^10 - 6010*z^9 + 16913*z^8 + 23552*z^7 + 4413*z^6 - 13117*z^5 - 8675*z^4 + 2488*z^3 + 2270*z^2 - 494*z - 8 */ static const long X1_37_crv_12[17] = { evaltyp(t_VECSMALL) | _evallg(17), vZ, 28, 322, -733, -2730, -527, 6962, 10483, 664, -11481, -9749, -870, 2579, 1420, 294, 21 }; /* 21*z^14 + 294*z^13 + 1420*z^12 + 2579*z^11 - 870*z^10 - 9749*z^9 - 11481*z^8 + 664*z^7 + 10483*z^6 + 6962*z^5 - 527*z^4 - 2730*z^3 - 733*z^2 + 322*z + 28 */ static const long X1_37_crv_13[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, -56, -50, 38, 306, 2034, 2372, -2982, -6951, -2931, 2085, 2414, 885, 137, 7 }; /* 7*z^13 + 137*z^12 + 885*z^11 + 2414*z^10 + 2085*z^9 - 2931*z^8 - 6951*z^7 - 2982*z^6 + 2372*z^5 + 2034*z^4 + 306*z^3 + 38*z^2 - 50*z - 56 */ static const long X1_37_crv_14[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 70, -65, -205, 635, 530, -1975, -2560, 227, 1944, 1256, 334, 36, 1 }; /* z^12 + 36*z^11 + 334*z^10 + 1256*z^9 + 1944*z^8 + 227*z^7 - 2560*z^6 - 1975*z^5 + 530*z^4 + 635*z^3 - 205*z^2 - 65*z + 70 */ static const long X1_37_crv_15[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, -56, 18, 299, -71, -878, -460, 697, 899, 390, 70, 4 }; /* 4*z^10 + 70*z^9 + 390*z^8 + 899*z^7 + 697*z^6 - 460*z^5 - 878*z^4 - 71*z^3 + 299*z^2 + 18*z - 56 */ static const long X1_37_crv_16[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, 28, 28, -123, -186, 86, 318, 227, 64, 6 }; /* 6*z^8 + 64*z^7 + 227*z^6 + 318*z^5 + 86*z^4 - 186*z^3 - 123*z^2 + 28*z + 28 */ static const long X1_37_crv_17[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -8, -20, 3, 53, 61, 27, 4 }; /* 4*z^6 + 27*z^5 + 61*z^4 + 53*z^3 + 3*z^2 - 20*z - 8 */ static const long X1_37_crv_18[7] = { evaltyp(t_VECSMALL) | _evallg(7), vZ, 1, 4, 6, 4, 1 }; /* z^4 + 4*z^3 + 6*z^2 + 4*z + 1 */ static const long *X1_37_crv[21] = { (long *)(evaltyp(t_POL) | _evallg(21)), (long *)(evalvarn(0) | evalsigne(1)), X1_37_crv_0, X1_37_crv_1, X1_37_crv_2, X1_37_crv_3, X1_37_crv_4, X1_37_crv_5, X1_37_crv_6, X1_37_crv_7, X1_37_crv_8, X1_37_crv_9, X1_37_crv_10, X1_37_crv_11, X1_37_crv_12, X1_37_crv_13, X1_37_crv_14, X1_37_crv_15, X1_37_crv_16, X1_37_crv_17, X1_37_crv_18 }; /* (z^2 + z + 1)*x - 1 */ static const long X1_37_r_n_1[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, 1, 1, 1 }; /* z^2 + z + 1 */ static const long *X1_37_r_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_m1, X1_37_r_n_1 }; /* x + (z^2 + z - 1) */ static const long X1_37_r_d_0[5] = { evaltyp(t_VECSMALL) | _evallg(5), vZ, -1, 1, 1 }; /* z^2 + z - 1 */ static const long *X1_37_r_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_37_r_d_0, FLX_1 }; /* (z + 1)*x - 1 */ static const long X1_37_s_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_37_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), FLX_m1, X1_37_s_n_1 }; /* x + (z - 1) */ static const long X1_37_s_d_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, -1, 1 }; /* z - 1 */ static const long *X1_37_s_d[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_37_s_d_0, FLX_1 }; /* z^3*u^12 + (z^6 + 4*z^4 + 10*z^3 - z^2 + z)*u^11 + (4*z^7 + 10*z^6 + 2*z^5 + 39*z^4 + 41*z^3 - 5*z^2 + 7*z - 1)*u^10 + (z^9 + 4*z^8 + 38*z^7 + 32*z^6 + 26*z^5 + 167*z^4 + 88*z^3 - 10*z^2 + 17*z - 6)*u^9 + (4*z^10 + 3*z^9 + 39*z^8 + 141*z^7 + 28*z^6 + 144*z^5 + 396*z^4 + 94*z^3 - 18*z^2 + 12*z - 15)*u^8 + (6*z^11 + 14*z^10 + 173*z^8 + 234*z^7 - 44*z^6 + 421*z^5 + 545*z^4 - 4*z^3 - 50*z^2 - 17*z - 20)*u^7 + (4*z^12 + 25*z^11 - z^10 + 41*z^9 + 368*z^8 + 91*z^7 - 39*z^6 + 691*z^5 + 383*z^4 - 168*z^3 - 91*z^2 - 38*z - 15)*u^6 + (z^13 + 17*z^12 + 30*z^11 - 33*z^10 + 171*z^9 + 326*z^8 - 163*z^7 + 166*z^6 + 594*z^5 + 24*z^4 - 236*z^3 - 82*z^2 - 28*z - 6)*u^5 + (4*z^13 + 26*z^12 + 4*z^11 - 7*z^10 + 202*z^9 + 61*z^8 - 135*z^7 + 249*z^6 + 210*z^5 - 153*z^4 - 146*z^3 - 34*z^2 - 9*z - 1)*u^4 + (6*z^13 + 17*z^12 - 10*z^11 + 27*z^10 + 78*z^9 - 34*z^8 - 10*z^7 + 107*z^6 - 17*z^5 - 90*z^4 - 39*z^3 - 5*z^2 - z)*u^3 + (4*z^13 + 4*z^12 - 3*z^11 + 12*z^10 + 10*z^9 - 9*z^8 + 6*z^7 + 6*z^6 - 25*z^5 - 15*z^4 - 3*z^3)*u^2 + (z^13 + z^10 + z^9 - 3*z^7 - 3*z^6 - 3*z^5)*u - z^7 */ static const long X1_38_crv_0[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, 0, 0, 0, 0, 0, 0, 0, -1 }; /* -z^7 */ static const long X1_38_crv_1[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, 0, 0, 0, 0, 0, -3, -3, -3, 0, 1, 1, 0, 0, 1 }; /* z^13 + z^10 + z^9 - 3*z^7 - 3*z^6 - 3*z^5 */ static const long X1_38_crv_2[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, 0, 0, 0, -3, -15, -25, 6, 6, -9, 10, 12, -3, 4, 4 }; /* 4*z^13 + 4*z^12 - 3*z^11 + 12*z^10 + 10*z^9 - 9*z^8 + 6*z^7 + 6*z^6 - 25*z^5 - 15*z^4 - 3*z^3 */ static const long X1_38_crv_3[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, 0, -1, -5, -39, -90, -17, 107, -10, -34, 78, 27, -10, 17, 6 }; /* 6*z^13 + 17*z^12 - 10*z^11 + 27*z^10 + 78*z^9 - 34*z^8 - 10*z^7 + 107*z^6 - 17*z^5 - 90*z^4 - 39*z^3 - 5*z^2 - z */ static const long X1_38_crv_4[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, -1, -9, -34, -146, -153, 210, 249, -135, 61, 202, -7, 4, 26, 4 }; /* 4*z^13 + 26*z^12 + 4*z^11 - 7*z^10 + 202*z^9 + 61*z^8 - 135*z^7 + 249*z^6 + 210*z^5 - 153*z^4 - 146*z^3 - 34*z^2 - 9*z - 1 */ static const long X1_38_crv_5[16] = { evaltyp(t_VECSMALL) | _evallg(16), vZ, -6, -28, -82, -236, 24, 594, 166, -163, 326, 171, -33, 30, 17, 1 }; /* z^13 + 17*z^12 + 30*z^11 - 33*z^10 + 171*z^9 + 326*z^8 - 163*z^7 + 166*z^6 + 594*z^5 + 24*z^4 - 236*z^3 - 82*z^2 - 28*z - 6 */ static const long X1_38_crv_6[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, -15, -38, -91, -168, 383, 691, -39, 91, 368, 41, -1, 25, 4 }; /* 4*z^12 + 25*z^11 - z^10 + 41*z^9 + 368*z^8 + 91*z^7 - 39*z^6 + 691*z^5 + 383*z^4 - 168*z^3 - 91*z^2 - 38*z - 15 */ static const long X1_38_crv_7[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, -20, -17, -50, -4, 545, 421, -44, 234, 173, 0, 14, 6 }; /* 6*z^11 + 14*z^10 + 173*z^8 + 234*z^7 - 44*z^6 + 421*z^5 + 545*z^4 - 4*z^3 - 50*z^2 - 17*z - 20 */ static const long X1_38_crv_8[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, -15, 12, -18, 94, 396, 144, 28, 141, 39, 3, 4 }; /* 4*z^10 + 3*z^9 + 39*z^8 + 141*z^7 + 28*z^6 + 144*z^5 + 396*z^4 + 94*z^3 - 18*z^2 + 12*z - 15 */ static const long X1_38_crv_9[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, -6, 17, -10, 88, 167, 26, 32, 38, 4, 1 }; /* z^9 + 4*z^8 + 38*z^7 + 32*z^6 + 26*z^5 + 167*z^4 + 88*z^3 - 10*z^2 + 17*z - 6 */ static const long X1_38_crv_10[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -1, 7, -5, 41, 39, 2, 10, 4 }; /* 4*z^7 + 10*z^6 + 2*z^5 + 39*z^4 + 41*z^3 - 5*z^2 + 7*z - 1 */ static const long X1_38_crv_11[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, 0, 1, -1, 10, 4, 0, 1 }; /* z^6 + 4*z^4 + 10*z^3 - z^2 + z */ static const long X1_38_crv_12[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, 0, 1 }; /* z^3 */ static const long *X1_38_crv[15] = { (long *)(evaltyp(t_POL) | _evallg(15)), (long *)(evalvarn(0) | evalsigne(1)), X1_38_crv_0, X1_38_crv_1, X1_38_crv_2, X1_38_crv_3, X1_38_crv_4, X1_38_crv_5, X1_38_crv_6, X1_38_crv_7, X1_38_crv_8, X1_38_crv_9, X1_38_crv_10, X1_38_crv_11, X1_38_crv_12 }; /* (z^3 - z^2)*u^10 + (z^5 + 4*z^4 + 2*z^3 - 8*z^2 + 2*z)*u^9 + (6*z^6 + 10*z^5 + 14*z^4 - 13*z^3 - 17*z^2 + 9*z - 1)*u^8 + (15*z^7 + 25*z^6 + 22*z^5 + 10*z^4 - 45*z^3 - 11*z^2 + 13*z - 2)*u^7 + (21*z^8 + 46*z^7 + 21*z^6 + 33*z^5 - 20*z^4 - 63*z^3 + 5*z^2 + 12*z - 1)*u^6 + (17*z^9 + 58*z^8 + 14*z^7 + 25*z^6 + 39*z^5 - 67*z^4 - 42*z^3 + 21*z^2 + 10*z)*u^5 + (7*z^10 + 45*z^9 + 24*z^8 - 27*z^7 + 75*z^6 - 9*z^5 - 71*z^4 + 23*z^2 + 4*z)*u^4 + (z^11 + 17*z^10 + 30*z^9 - 32*z^8 + 9*z^7 + 68*z^6 - 49*z^5 - 32*z^4 + 17*z^3 + 8*z^2)*u^3 + (2*z^11 + 12*z^10 - 2*z^9 - 24*z^8 + 33*z^7 + 16*z^6 - 38*z^5 - z^4 + 6*z^3)*u^2 + (z^11 + 2*z^10 - 6*z^9 - z^8 + 13*z^7 - 6*z^6 - 9*z^5 + 2*z^4)*u + (-z^9 + z^8 + z^7 - 2*z^6) */ static const long X1_38_r_n_0[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 0, -2, 1, 1, -1 }; /* -z^9 + z^8 + z^7 - 2*z^6 */ static const long X1_38_r_n_1[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 0, 2, -9, -6, 13, -1, -6, 2, 1 }; /* z^11 + 2*z^10 - 6*z^9 - z^8 + 13*z^7 - 6*z^6 - 9*z^5 + 2*z^4 */ static const long X1_38_r_n_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 6, -1, -38, 16, 33, -24, -2, 12, 2 }; /* 2*z^11 + 12*z^10 - 2*z^9 - 24*z^8 + 33*z^7 + 16*z^6 - 38*z^5 - z^4 + 6*z^3 */ static const long X1_38_r_n_3[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 8, 17, -32, -49, 68, 9, -32, 30, 17, 1 }; /* z^11 + 17*z^10 + 30*z^9 - 32*z^8 + 9*z^7 + 68*z^6 - 49*z^5 - 32*z^4 + 17*z^3 + 8*z^2 */ static const long X1_38_r_n_4[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 4, 23, 0, -71, -9, 75, -27, 24, 45, 7 }; /* 7*z^10 + 45*z^9 + 24*z^8 - 27*z^7 + 75*z^6 - 9*z^5 - 71*z^4 + 23*z^2 + 4*z */ static const long X1_38_r_n_5[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 10, 21, -42, -67, 39, 25, 14, 58, 17 }; /* 17*z^9 + 58*z^8 + 14*z^7 + 25*z^6 + 39*z^5 - 67*z^4 - 42*z^3 + 21*z^2 + 10*z */ static const long X1_38_r_n_6[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 12, 5, -63, -20, 33, 21, 46, 21 }; /* 21*z^8 + 46*z^7 + 21*z^6 + 33*z^5 - 20*z^4 - 63*z^3 + 5*z^2 + 12*z - 1 */ static const long X1_38_r_n_7[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -2, 13, -11, -45, 10, 22, 25, 15 }; /* 15*z^7 + 25*z^6 + 22*z^5 + 10*z^4 - 45*z^3 - 11*z^2 + 13*z - 2 */ static const long X1_38_r_n_8[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, 9, -17, -13, 14, 10, 6 }; /* 6*z^6 + 10*z^5 + 14*z^4 - 13*z^3 - 17*z^2 + 9*z - 1 */ static const long X1_38_r_n_9[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 2, -8, 2, 4, 1 }; /* z^5 + 4*z^4 + 2*z^3 - 8*z^2 + 2*z */ static const long X1_38_r_n_10[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, -1, 1 }; /* z^3 - z^2 */ static const long *X1_38_r_n[13] = { (long *)(evaltyp(t_POL) | _evallg(13)), (long *)(evalvarn(0) | evalsigne(1)), X1_38_r_n_0, X1_38_r_n_1, X1_38_r_n_2, X1_38_r_n_3, X1_38_r_n_4, X1_38_r_n_5, X1_38_r_n_6, X1_38_r_n_7, X1_38_r_n_8, X1_38_r_n_9, X1_38_r_n_10 }; /* (z^3 - z^2)*u^10 + (z^5 + 5*z^4 + z^3 - 8*z^2 + 2*z)*u^9 + (7*z^6 + 12*z^5 + 17*z^4 - 20*z^3 - 15*z^2 + 9*z - 1)*u^8 + (19*z^7 + 28*z^6 + 30*z^5 + 10*z^4 - 61*z^3 - 3*z^2 + 13*z - 2)*u^7 + (26*z^8 + 58*z^7 + 19*z^6 + 54*z^5 - 32*z^4 - 82*z^3 + 20*z^2 + 12*z - 1)*u^6 + (19*z^9 + 74*z^8 + 21*z^7 + 16*z^6 + 75*z^5 - 93*z^4 - 53*z^3 + 36*z^2 + 10*z)*u^5 + (7*z^10 + 51*z^9 + 43*z^8 - 41*z^7 + 72*z^6 + 35*z^5 - 106*z^4 - 2*z^3 + 31*z^2 + 4*z)*u^4 + (z^11 + 17*z^10 + 37*z^9 - 26*z^8 - 14*z^7 + 90*z^6 - 33*z^5 - 59*z^4 + 19*z^3 + 10*z^2)*u^3 + (2*z^11 + 12*z^10 + z^9 - 29*z^8 + 31*z^7 + 27*z^6 - 41*z^5 - 10*z^4 + 8*z^3)*u^2 + (z^11 + 2*z^10 - 6*z^9 - 2*z^8 + 14*z^7 - 5*z^6 - 11*z^5 + 2*z^4)*u + (-z^9 + z^8 + z^7 - 2*z^6) */ static const long X1_38_r_d_0[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 0, 0, 0, 0, 0, -2, 1, 1, -1 }; /* -z^9 + z^8 + z^7 - 2*z^6 */ static const long X1_38_r_d_1[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 0, 2, -11, -5, 14, -2, -6, 2, 1 }; /* z^11 + 2*z^10 - 6*z^9 - 2*z^8 + 14*z^7 - 5*z^6 - 11*z^5 + 2*z^4 */ static const long X1_38_r_d_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 8, -10, -41, 27, 31, -29, 1, 12, 2 }; /* 2*z^11 + 12*z^10 + z^9 - 29*z^8 + 31*z^7 + 27*z^6 - 41*z^5 - 10*z^4 + 8*z^3 */ static const long X1_38_r_d_3[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 10, 19, -59, -33, 90, -14, -26, 37, 17, 1 }; /* z^11 + 17*z^10 + 37*z^9 - 26*z^8 - 14*z^7 + 90*z^6 - 33*z^5 - 59*z^4 + 19*z^3 + 10*z^2 */ static const long X1_38_r_d_4[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 4, 31, -2, -106, 35, 72, -41, 43, 51, 7 }; /* 7*z^10 + 51*z^9 + 43*z^8 - 41*z^7 + 72*z^6 + 35*z^5 - 106*z^4 - 2*z^3 + 31*z^2 + 4*z */ static const long X1_38_r_d_5[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 10, 36, -53, -93, 75, 16, 21, 74, 19 }; /* 19*z^9 + 74*z^8 + 21*z^7 + 16*z^6 + 75*z^5 - 93*z^4 - 53*z^3 + 36*z^2 + 10*z */ static const long X1_38_r_d_6[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 12, 20, -82, -32, 54, 19, 58, 26 }; /* 26*z^8 + 58*z^7 + 19*z^6 + 54*z^5 - 32*z^4 - 82*z^3 + 20*z^2 + 12*z - 1 */ static const long X1_38_r_d_7[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -2, 13, -3, -61, 10, 30, 28, 19 }; /* 19*z^7 + 28*z^6 + 30*z^5 + 10*z^4 - 61*z^3 - 3*z^2 + 13*z - 2 */ static const long X1_38_r_d_8[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, 9, -15, -20, 17, 12, 7 }; /* 7*z^6 + 12*z^5 + 17*z^4 - 20*z^3 - 15*z^2 + 9*z - 1 */ static const long X1_38_r_d_9[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 2, -8, 1, 5, 1 }; /* z^5 + 5*z^4 + z^3 - 8*z^2 + 2*z */ static const long X1_38_r_d_10[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, -1, 1 }; /* z^3 - z^2 */ static const long *X1_38_r_d[13] = { (long *)(evaltyp(t_POL) | _evallg(13)), (long *)(evalvarn(0) | evalsigne(1)), X1_38_r_d_0, X1_38_r_d_1, X1_38_r_d_2, X1_38_r_d_3, X1_38_r_d_4, X1_38_r_d_5, X1_38_r_d_6, X1_38_r_d_7, X1_38_r_d_8, X1_38_r_d_9, X1_38_r_d_10 }; /* (z^3 - z^2)*u^9 + (z^5 + 3*z^4 + 3*z^3 - 8*z^2 + 2*z)*u^8 + (5*z^6 + 7*z^5 + 12*z^4 - 6*z^3 - 19*z^2 + 9*z - 1)*u^7 + (10*z^7 + 20*z^6 + 11*z^5 + 17*z^4 - 31*z^3 - 19*z^2 + 13*z - 2)*u^6 + (12*z^8 + 31*z^7 + 15*z^6 + 12*z^5 + 8*z^4 - 52*z^3 - 10*z^2 + 12*z - 1)*u^5 + (10*z^9 + 30*z^8 + 9*z^7 + 13*z^6 + 15*z^5 - 22*z^4 - 46*z^3 + 6*z^2 + 10*z)*u^4 + (5*z^10 + 23*z^9 - 2*z^8 - 4*z^7 + 42*z^6 - 27*z^5 - 25*z^4 - 13*z^3 + 15*z^2 + 4*z)*u^3 + (z^11 + 11*z^10 + 4*z^9 - 24*z^8 + 35*z^7 + 2*z^6 - 30*z^5 - 3*z^4 + 7*z^3 + 6*z^2)*u^2 + (2*z^11 + 5*z^10 - 11*z^9 + 4*z^8 + 13*z^7 - 11*z^6 - 8*z^5 + 6*z^4 + 2*z^3)*u + (z^11 - z^10 - z^9 + 2*z^8 + z^7 - 4*z^6 + 2*z^5) */ static const long X1_38_s_n_0[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 0, 0, 2, -4, 1, 2, -1, -1, 1 }; /* z^11 - z^10 - z^9 + 2*z^8 + z^7 - 4*z^6 + 2*z^5 */ static const long X1_38_s_n_1[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 2, 6, -8, -11, 13, 4, -11, 5, 2 }; /* 2*z^11 + 5*z^10 - 11*z^9 + 4*z^8 + 13*z^7 - 11*z^6 - 8*z^5 + 6*z^4 + 2*z^3 */ static const long X1_38_s_n_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 6, 7, -3, -30, 2, 35, -24, 4, 11, 1 }; /* z^11 + 11*z^10 + 4*z^9 - 24*z^8 + 35*z^7 + 2*z^6 - 30*z^5 - 3*z^4 + 7*z^3 + 6*z^2 */ static const long X1_38_s_n_3[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 4, 15, -13, -25, -27, 42, -4, -2, 23, 5 }; /* 5*z^10 + 23*z^9 - 2*z^8 - 4*z^7 + 42*z^6 - 27*z^5 - 25*z^4 - 13*z^3 + 15*z^2 + 4*z */ static const long X1_38_s_n_4[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 10, 6, -46, -22, 15, 13, 9, 30, 10 }; /* 10*z^9 + 30*z^8 + 9*z^7 + 13*z^6 + 15*z^5 - 22*z^4 - 46*z^3 + 6*z^2 + 10*z */ static const long X1_38_s_n_5[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 12, -10, -52, 8, 12, 15, 31, 12 }; /* 12*z^8 + 31*z^7 + 15*z^6 + 12*z^5 + 8*z^4 - 52*z^3 - 10*z^2 + 12*z - 1 */ static const long X1_38_s_n_6[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -2, 13, -19, -31, 17, 11, 20, 10 }; /* 10*z^7 + 20*z^6 + 11*z^5 + 17*z^4 - 31*z^3 - 19*z^2 + 13*z - 2 */ static const long X1_38_s_n_7[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, 9, -19, -6, 12, 7, 5 }; /* 5*z^6 + 7*z^5 + 12*z^4 - 6*z^3 - 19*z^2 + 9*z - 1 */ static const long X1_38_s_n_8[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 2, -8, 3, 3, 1 }; /* z^5 + 3*z^4 + 3*z^3 - 8*z^2 + 2*z */ static const long X1_38_s_n_9[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, -1, 1 }; /* z^3 - z^2 */ static const long *X1_38_s_n[12] = { (long *)(evaltyp(t_POL) | _evallg(12)), (long *)(evalvarn(0) | evalsigne(1)), X1_38_s_n_0, X1_38_s_n_1, X1_38_s_n_2, X1_38_s_n_3, X1_38_s_n_4, X1_38_s_n_5, X1_38_s_n_6, X1_38_s_n_7, X1_38_s_n_8, X1_38_s_n_9 }; /* (z^3 - z^2)*u^9 + (z^5 + 4*z^4 + 2*z^3 - 8*z^2 + 2*z)*u^8 + (6*z^6 + 9*z^5 + 15*z^4 - 13*z^3 - 17*z^2 + 9*z - 1)*u^7 + (14*z^7 + 23*z^6 + 19*z^5 + 17*z^4 - 47*z^3 - 11*z^2 + 13*z - 2)*u^6 + (17*z^8 + 43*z^7 + 13*z^6 + 33*z^5 - 4*z^4 - 71*z^3 + 5*z^2 + 12*z - 1)*u^5 + (12*z^9 + 46*z^8 + 16*z^7 + 4*z^6 + 51*z^5 - 48*z^4 - 57*z^3 + 21*z^2 + 10*z)*u^4 + (5*z^10 + 29*z^9 + 17*z^8 - 18*z^7 + 39*z^6 + 17*z^5 - 60*z^4 - 15*z^3 + 23*z^2 + 4*z)*u^3 + (z^11 + 11*z^10 + 11*z^9 - 18*z^8 + 12*z^7 + 24*z^6 - 14*z^5 - 30*z^4 + 9*z^3 + 8*z^2)*u^2 + (2*z^11 + 5*z^10 - 8*z^9 - z^8 + 11*z^7 - 11*z^5 - 3*z^4 + 4*z^3)*u + (z^11 - z^10 - z^9 + z^8 + 2*z^7 - 3*z^6) */ static const long X1_38_s_d_0[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 0, 0, 0, -3, 2, 1, -1, -1, 1 }; /* z^11 - z^10 - z^9 + z^8 + 2*z^7 - 3*z^6 */ static const long X1_38_s_d_1[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 0, 4, -3, -11, 0, 11, -1, -8, 5, 2 }; /* 2*z^11 + 5*z^10 - 8*z^9 - z^8 + 11*z^7 - 11*z^5 - 3*z^4 + 4*z^3 */ static const long X1_38_s_d_2[14] = { evaltyp(t_VECSMALL) | _evallg(14), vZ, 0, 0, 8, 9, -30, -14, 24, 12, -18, 11, 11, 1 }; /* z^11 + 11*z^10 + 11*z^9 - 18*z^8 + 12*z^7 + 24*z^6 - 14*z^5 - 30*z^4 + 9*z^3 + 8*z^2 */ static const long X1_38_s_d_3[13] = { evaltyp(t_VECSMALL) | _evallg(13), vZ, 0, 4, 23, -15, -60, 17, 39, -18, 17, 29, 5 }; /* 5*z^10 + 29*z^9 + 17*z^8 - 18*z^7 + 39*z^6 + 17*z^5 - 60*z^4 - 15*z^3 + 23*z^2 + 4*z */ static const long X1_38_s_d_4[12] = { evaltyp(t_VECSMALL) | _evallg(12), vZ, 0, 10, 21, -57, -48, 51, 4, 16, 46, 12 }; /* 12*z^9 + 46*z^8 + 16*z^7 + 4*z^6 + 51*z^5 - 48*z^4 - 57*z^3 + 21*z^2 + 10*z */ static const long X1_38_s_d_5[11] = { evaltyp(t_VECSMALL) | _evallg(11), vZ, -1, 12, 5, -71, -4, 33, 13, 43, 17 }; /* 17*z^8 + 43*z^7 + 13*z^6 + 33*z^5 - 4*z^4 - 71*z^3 + 5*z^2 + 12*z - 1 */ static const long X1_38_s_d_6[10] = { evaltyp(t_VECSMALL) | _evallg(10), vZ, -2, 13, -11, -47, 17, 19, 23, 14 }; /* 14*z^7 + 23*z^6 + 19*z^5 + 17*z^4 - 47*z^3 - 11*z^2 + 13*z - 2 */ static const long X1_38_s_d_7[9] = { evaltyp(t_VECSMALL) | _evallg(9), vZ, -1, 9, -17, -13, 15, 9, 6 }; /* 6*z^6 + 9*z^5 + 15*z^4 - 13*z^3 - 17*z^2 + 9*z - 1 */ static const long X1_38_s_d_8[8] = { evaltyp(t_VECSMALL) | _evallg(8), vZ, 0, 2, -8, 2, 4, 1 }; /* z^5 + 4*z^4 + 2*z^3 - 8*z^2 + 2*z */ static const long X1_38_s_d_9[6] = { evaltyp(t_VECSMALL) | _evallg(6), vZ, 0, 0, -1, 1 }; /* z^3 - z^2 */ static const long *X1_38_s_d[12] = { (long *)(evaltyp(t_POL) | _evallg(12)), (long *)(evalvarn(0) | evalsigne(1)), X1_38_s_d_0, X1_38_s_d_1, X1_38_s_d_2, X1_38_s_d_3, X1_38_s_d_4, X1_38_s_d_5, X1_38_s_d_6, X1_38_s_d_7, X1_38_s_d_8, X1_38_s_d_9 }; /* z^12*x^14 + (-z^23 - 2*z^22 - 4*z^21 - 6*z^20 - 9*z^19 - 12*z^18 - 16*z^17 - 20*z^16 - 25*z^15 - 30*z^14 - 36*z^13 - 12*z^12)*x^13 + (-18*z^23 - 52*z^22 - 100*z^21 - 147*z^20 - 187*z^19 - 208*z^18 - 216*z^17 - 218*z^16 - 248*z^15 - 348*z^14 - 596*z^13 - 650*z^12 - 483*z^11 - 308*z^10 - 188*z^9 - 108*z^8 - 58*z^7 - 28*z^6 - 12*z^5 - 4*z^4 - z^3)*x^12 + (-153*z^23 - 594*z^22 - 1300*z^21 - 2055*z^20 - 2574*z^19 - 2556*z^18 - 1806*z^17 - 261*z^16 + 1845*z^15 + 3786*z^14 + 3780*z^13 + 2178*z^12 + 849*z^11 + 360*z^10 + 266*z^9 + 243*z^8 + 192*z^7 + 124*z^6 + 60*z^5 + 21*z^4 + 3*z^3)*x^11 + (-816*z^23 - 4080*z^22 - 10860*z^21 - 20535*z^20 - 31080*z^19 - 39972*z^18 - 44924*z^17 - 43894*z^16 - 34940*z^15 - 17560*z^14 + 268*z^13 + 8717*z^12 + 7806*z^11 + 3780*z^10 + 720*z^9 - 616*z^8 - 818*z^7 - 544*z^6 - 240*z^5 - 60*z^4 - 6*z^3)*x^10 + (z^28 + 10*z^27 + 60*z^26 + 270*z^25 + 1005*z^24 + 192*z^23 - 9736*z^22 - 38140*z^21 - 87840*z^20 - 151485*z^19 - 216012*z^18 - 269898*z^17 - 306131*z^16 - 316700*z^15 - 284760*z^14 - 207128*z^13 - 114251*z^12 - 43146*z^11 - 5820*z^10 + 6900*z^9 + 7806*z^8 + 5035*z^7 + 2314*z^6 + 720*z^5 + 130*z^4 + 10*z^3)*x^9 + (9*z^28 + 91*z^27 + 540*z^26 + 2400*z^25 + 8890*z^24 + 20526*z^23 + 21288*z^22 - 23112*z^21 - 140013*z^20 - 320022*z^19 - 516680*z^18 - 678672*z^17 - 787386*z^16 - 859748*z^15 - 893172*z^14 - 842244*z^13 - 686088*z^12 - 474318*z^11 - 280656*z^10 - 144524*z^9 - 65124*z^8 - 25122*z^7 - 7784*z^6 - 1740*z^5 - 240*z^4 - 15*z^3)*x^8 + (36*z^28 + 369*z^27 + 2164*z^26 + 9452*z^25 + 34678*z^24 + 96449*z^23 + 188602*z^22 + 245336*z^21 + 166136*z^20 - 94892*z^19 - 461620*z^18 - 768278*z^17 - 883369*z^16 - 829121*z^15 - 743626*z^14 - 706388*z^13 - 669214*z^12 - 565402*z^11 - 404852*z^10 - 245998*z^9 - 129905*z^8 - 61105*z^7 - 25634*z^6 - 9268*z^5 - 2744*z^4 - 637*z^3 - 112*z^2 - 14*z - 1)*x^7 + (84*z^28 + 876*z^27 + 5076*z^26 + 21640*z^25 + 77944*z^24 + 230394*z^23 + 528492*z^22 + 922068*z^21 + 1213200*z^20 + 1162575*z^19 + 693252*z^18 + 6228*z^17 - 521846*z^16 - 626120*z^15 - 375720*z^14 - 68172*z^13 + 79677*z^12 + 72513*z^11 + 20760*z^10 - 6456*z^9 - 7416*z^8 - 1916*z^7 + 496*z^6 + 480*z^5 + 135*z^4 + 15*z^3)*x^6 + (126*z^28 + 1344*z^27 + 7704*z^26 + 31770*z^25 + 110495*z^24 + 332211*z^23 + 826386*z^22 + 1650292*z^21 + 2628990*z^20 + 3341835*z^19 + 3353964*z^18 + 2539962*z^17 + 1236231*z^16 + 55910*z^15 - 540060*z^14 - 540912*z^13 - 271552*z^12 - 44343*z^11 + 39780*z^10 + 34350*z^9 + 11565*z^8 + 333*z^7 - 1366*z^6 - 600*z^5 - 120*z^4 - 10*z^3)*x^5 + (126*z^28 + 1386*z^27 + 7896*z^26 + 31200*z^25 + 101730*z^24 + 297098*z^23 + 765412*z^22 + 1667408*z^21 + 3004995*z^20 + 4469310*z^19 + 5505000*z^18 + 5608136*z^17 + 4657354*z^16 + 3031220*z^15 + 1391660*z^14 + 270580*z^13 - 204565*z^12 - 244602*z^11 - 134160*z^10 - 41460*z^9 - 2842*z^8 + 4030*z^7 + 2216*z^6 + 600*z^5 + 90*z^4 + 6*z^3)*x^4 + (84*z^28 + 966*z^27 + 5544*z^26 + 21000*z^25 + 61860*z^24 + 161856*z^23 + 398596*z^22 + 897424*z^21 + 1758603*z^20 + 2925262*z^19 + 4115740*z^18 + 4919796*z^17 + 5012510*z^16 + 4342211*z^15 + 3166854*z^14 + 1907052*z^13 + 913956*z^12 + 320100*z^11 + 58652*z^10 - 14782*z^9 - 17649*z^8 - 8090*z^7 - 2360*z^6 - 456*z^5 - 54*z^4 - 3*z^3)*x^3 + (36*z^28 + 443*z^27 + 2640*z^26 + 9912*z^25 + 26488*z^24 + 56208*z^23 + 108084*z^22 + 209364*z^21 + 405039*z^20 + 723204*z^19 + 1128252*z^18 + 1513356*z^17 + 1749258*z^16 + 1752384*z^15 + 1525872*z^14 + 1153404*z^13 + 753402*z^12 + 422268*z^11 + 201168*z^10 + 80432*z^9 + 26520*z^8 + 7032*z^7 + 1444*z^6 + 216*z^5 + 21*z^4 + z^3)*x^2 + (9*z^28 + 123*z^27 + 800*z^26 + 3220*z^25 + 8834*z^24 + 17206*z^23 + 23900*z^22 + 22600*z^21 + 11580*z^20 - 2916*z^19 - 12024*z^18 - 12470*z^17 - 7885*z^16 - 3335*z^15 - 930*z^14 - 156*z^13 - 12*z^12)*x + (z^28 + 16*z^27 + 120*z^26 + 560*z^25 + 1820*z^24 + 4368*z^23 + 8008*z^22 + 11440*z^21 + 12870*z^20 + 11440*z^19 + 8008*z^18 + 4368*z^17 + 1820*z^16 + 560*z^15 + 120*z^14 + 16*z^13 + z^12) */ static const long X1_39_crv_0[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 120, 560, 1820, 4368, 8008, 11440, 12870, 11440, 8008, 4368, 1820, 560, 120, 16, 1 }; /* z^28 + 16*z^27 + 120*z^26 + 560*z^25 + 1820*z^24 + 4368*z^23 + 8008*z^22 + 11440*z^21 + 12870*z^20 + 11440*z^19 + 8008*z^18 + 4368*z^17 + 1820*z^16 + 560*z^15 + 120*z^14 + 16*z^13 + z^12 */ static const long X1_39_crv_1[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -12, -156, -930, -3335, -7885, -12470, -12024, -2916, 11580, 22600, 23900, 17206, 8834, 3220, 800, 123, 9 }; /* 9*z^28 + 123*z^27 + 800*z^26 + 3220*z^25 + 8834*z^24 + 17206*z^23 + 23900*z^22 + 22600*z^21 + 11580*z^20 - 2916*z^19 - 12024*z^18 - 12470*z^17 - 7885*z^16 - 3335*z^15 - 930*z^14 - 156*z^13 - 12*z^12 */ static const long X1_39_crv_2[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, 1, 21, 216, 1444, 7032, 26520, 80432, 201168, 422268, 753402, 1153404, 1525872, 1752384, 1749258, 1513356, 1128252, 723204, 405039, 209364, 108084, 56208, 26488, 9912, 2640, 443, 36 }; /* 36*z^28 + 443*z^27 + 2640*z^26 + 9912*z^25 + 26488*z^24 + 56208*z^23 + 108084*z^22 + 209364*z^21 + 405039*z^20 + 723204*z^19 + 1128252*z^18 + 1513356*z^17 + 1749258*z^16 + 1752384*z^15 + 1525872*z^14 + 1153404*z^13 + 753402*z^12 + 422268*z^11 + 201168*z^10 + 80432*z^9 + 26520*z^8 + 7032*z^7 + 1444*z^6 + 216*z^5 + 21*z^4 + z^3 */ static const long X1_39_crv_3[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, -3, -54, -456, -2360, -8090, -17649, -14782, 58652, 320100, 913956, 1907052, 3166854, 4342211, 5012510, 4919796, 4115740, 2925262, 1758603, 897424, 398596, 161856, 61860, 21000, 5544, 966, 84 }; /* 84*z^28 + 966*z^27 + 5544*z^26 + 21000*z^25 + 61860*z^24 + 161856*z^23 + 398596*z^22 + 897424*z^21 + 1758603*z^20 + 2925262*z^19 + 4115740*z^18 + 4919796*z^17 + 5012510*z^16 + 4342211*z^15 + 3166854*z^14 + 1907052*z^13 + 913956*z^12 + 320100*z^11 + 58652*z^10 - 14782*z^9 - 17649*z^8 - 8090*z^7 - 2360*z^6 - 456*z^5 - 54*z^4 - 3*z^3 */ static const long X1_39_crv_4[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, 6, 90, 600, 2216, 4030, -2842, -41460, -134160, -244602, -204565, 270580, 1391660, 3031220, 4657354, 5608136, 5505000, 4469310, 3004995, 1667408, 765412, 297098, 101730, 31200, 7896, 1386, 126 }; /* 126*z^28 + 1386*z^27 + 7896*z^26 + 31200*z^25 + 101730*z^24 + 297098*z^23 + 765412*z^22 + 1667408*z^21 + 3004995*z^20 + 4469310*z^19 + 5505000*z^18 + 5608136*z^17 + 4657354*z^16 + 3031220*z^15 + 1391660*z^14 + 270580*z^13 - 204565*z^12 - 244602*z^11 - 134160*z^10 - 41460*z^9 - 2842*z^8 + 4030*z^7 + 2216*z^6 + 600*z^5 + 90*z^4 + 6*z^3 */ static const long X1_39_crv_5[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, -10, -120, -600, -1366, 333, 11565, 34350, 39780, -44343, -271552, -540912, -540060, 55910, 1236231, 2539962, 3353964, 3341835, 2628990, 1650292, 826386, 332211, 110495, 31770, 7704, 1344, 126 }; /* 126*z^28 + 1344*z^27 + 7704*z^26 + 31770*z^25 + 110495*z^24 + 332211*z^23 + 826386*z^22 + 1650292*z^21 + 2628990*z^20 + 3341835*z^19 + 3353964*z^18 + 2539962*z^17 + 1236231*z^16 + 55910*z^15 - 540060*z^14 - 540912*z^13 - 271552*z^12 - 44343*z^11 + 39780*z^10 + 34350*z^9 + 11565*z^8 + 333*z^7 - 1366*z^6 - 600*z^5 - 120*z^4 - 10*z^3 */ static const long X1_39_crv_6[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, 15, 135, 480, 496, -1916, -7416, -6456, 20760, 72513, 79677, -68172, -375720, -626120, -521846, 6228, 693252, 1162575, 1213200, 922068, 528492, 230394, 77944, 21640, 5076, 876, 84 }; /* 84*z^28 + 876*z^27 + 5076*z^26 + 21640*z^25 + 77944*z^24 + 230394*z^23 + 528492*z^22 + 922068*z^21 + 1213200*z^20 + 1162575*z^19 + 693252*z^18 + 6228*z^17 - 521846*z^16 - 626120*z^15 - 375720*z^14 - 68172*z^13 + 79677*z^12 + 72513*z^11 + 20760*z^10 - 6456*z^9 - 7416*z^8 - 1916*z^7 + 496*z^6 + 480*z^5 + 135*z^4 + 15*z^3 */ static const long X1_39_crv_7[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, -1, -14, -112, -637, -2744, -9268, -25634, -61105, -129905, -245998, -404852, -565402, -669214, -706388, -743626, -829121, -883369, -768278, -461620, -94892, 166136, 245336, 188602, 96449, 34678, 9452, 2164, 369, 36 }; /* 36*z^28 + 369*z^27 + 2164*z^26 + 9452*z^25 + 34678*z^24 + 96449*z^23 + 188602*z^22 + 245336*z^21 + 166136*z^20 - 94892*z^19 - 461620*z^18 - 768278*z^17 - 883369*z^16 - 829121*z^15 - 743626*z^14 - 706388*z^13 - 669214*z^12 - 565402*z^11 - 404852*z^10 - 245998*z^9 - 129905*z^8 - 61105*z^7 - 25634*z^6 - 9268*z^5 - 2744*z^4 - 637*z^3 - 112*z^2 - 14*z - 1 */ static const long X1_39_crv_8[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, -15, -240, -1740, -7784, -25122, -65124, -144524, -280656, -474318, -686088, -842244, -893172, -859748, -787386, -678672, -516680, -320022, -140013, -23112, 21288, 20526, 8890, 2400, 540, 91, 9 }; /* 9*z^28 + 91*z^27 + 540*z^26 + 2400*z^25 + 8890*z^24 + 20526*z^23 + 21288*z^22 - 23112*z^21 - 140013*z^20 - 320022*z^19 - 516680*z^18 - 678672*z^17 - 787386*z^16 - 859748*z^15 - 893172*z^14 - 842244*z^13 - 686088*z^12 - 474318*z^11 - 280656*z^10 - 144524*z^9 - 65124*z^8 - 25122*z^7 - 7784*z^6 - 1740*z^5 - 240*z^4 - 15*z^3 */ static const long X1_39_crv_9[31] = { evaltyp(t_VECSMALL) | _evallg(31), vZ, 0, 0, 0, 10, 130, 720, 2314, 5035, 7806, 6900, -5820, -43146, -114251, -207128, -284760, -316700, -306131, -269898, -216012, -151485, -87840, -38140, -9736, 192, 1005, 270, 60, 10, 1 }; /* z^28 + 10*z^27 + 60*z^26 + 270*z^25 + 1005*z^24 + 192*z^23 - 9736*z^22 - 38140*z^21 - 87840*z^20 - 151485*z^19 - 216012*z^18 - 269898*z^17 - 306131*z^16 - 316700*z^15 - 284760*z^14 - 207128*z^13 - 114251*z^12 - 43146*z^11 - 5820*z^10 + 6900*z^9 + 7806*z^8 + 5035*z^7 + 2314*z^6 + 720*z^5 + 130*z^4 + 10*z^3 */ static const long X1_39_crv_10[26] = { evaltyp(t_VECSMALL) | _evallg(26), vZ, 0, 0, 0, -6, -60, -240, -544, -818, -616, 720, 3780, 7806, 8717, 268, -17560, -34940, -43894, -44924, -39972, -31080, -20535, -10860, -4080, -816 }; /* -816*z^23 - 4080*z^22 - 10860*z^21 - 20535*z^20 - 31080*z^19 - 39972*z^18 - 44924*z^17 - 43894*z^16 - 34940*z^15 - 17560*z^14 + 268*z^13 + 8717*z^12 + 7806*z^11 + 3780*z^10 + 720*z^9 - 616*z^8 - 818*z^7 - 544*z^6 - 240*z^5 - 60*z^4 - 6*z^3 */ static const long X1_39_crv_11[26] = { evaltyp(t_VECSMALL) | _evallg(26), vZ, 0, 0, 0, 3, 21, 60, 124, 192, 243, 266, 360, 849, 2178, 3780, 3786, 1845, -261, -1806, -2556, -2574, -2055, -1300, -594, -153 }; /* -153*z^23 - 594*z^22 - 1300*z^21 - 2055*z^20 - 2574*z^19 - 2556*z^18 - 1806*z^17 - 261*z^16 + 1845*z^15 + 3786*z^14 + 3780*z^13 + 2178*z^12 + 849*z^11 + 360*z^10 + 266*z^9 + 243*z^8 + 192*z^7 + 124*z^6 + 60*z^5 + 21*z^4 + 3*z^3 */ static const long X1_39_crv_12[26] = { evaltyp(t_VECSMALL) | _evallg(26), vZ, 0, 0, 0, -1, -4, -12, -28, -58, -108, -188, -308, -483, -650, -596, -348, -248, -218, -216, -208, -187, -147, -100, -52, -18 }; /* -18*z^23 - 52*z^22 - 100*z^21 - 147*z^20 - 187*z^19 - 208*z^18 - 216*z^17 - 218*z^16 - 248*z^15 - 348*z^14 - 596*z^13 - 650*z^12 - 483*z^11 - 308*z^10 - 188*z^9 - 108*z^8 - 58*z^7 - 28*z^6 - 12*z^5 - 4*z^4 - z^3 */ static const long X1_39_crv_13[26] = { evaltyp(t_VECSMALL) | _evallg(26), vZ, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -12, -36, -30, -25, -20, -16, -12, -9, -6, -4, -2, -1 }; /* -z^23 - 2*z^22 - 4*z^21 - 6*z^20 - 9*z^19 - 12*z^18 - 16*z^17 - 20*z^16 - 25*z^15 - 30*z^14 - 36*z^13 - 12*z^12 */ static const long X1_39_crv_14[15] = { evaltyp(t_VECSMALL) | _evallg(15), vZ, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; /* z^12 */ static const long *X1_39_crv[17] = { (long *)(evaltyp(t_POL) | _evallg(17)), (long *)(evalvarn(0) | evalsigne(1)), X1_39_crv_0, X1_39_crv_1, X1_39_crv_2, X1_39_crv_3, X1_39_crv_4, X1_39_crv_5, X1_39_crv_6, X1_39_crv_7, X1_39_crv_8, X1_39_crv_9, X1_39_crv_10, X1_39_crv_11, X1_39_crv_12, X1_39_crv_13, X1_39_crv_14 }; /* -z */ static const long *X1_39_r_n[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_mZ }; /* 1 */ static const long *X1_39_r_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_1 }; /* (z + 1)*x + (z + 1) */ static const long X1_39_s_n_0[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long X1_39_s_n_1[4] = { evaltyp(t_VECSMALL) | _evallg(4), vZ, 1, 1 }; /* z + 1 */ static const long *X1_39_s_n[4] = { (long *)(evaltyp(t_POL) | _evallg(4)), (long *)(evalvarn(0) | evalsigne(1)), X1_39_s_n_0, X1_39_s_n_1 }; /* z */ static const long *X1_39_s_d[3] = { (long *)(evaltyp(t_POL) | _evallg(3)), (long *)(evalvarn(0) | evalsigne(1)), FLX_Z }; static const X1_info X1_table[LAST_X1_LEVEL - FIRST_X1_LEVEL + 1] = { { (GEN)X1_13_crv, (GEN)X1_13_r_n, (GEN)X1_13_r_d, 0, (GEN)X1_13_s_n, (GEN)X1_13_s_d, 1, RS_MAP }, { (GEN)X1_14_crv, (GEN)X1_14_r_n, (GEN)X1_14_r_d, 1, (GEN)X1_14_s_n, (GEN)X1_14_s_d, 0, RS_MAP }, { (GEN)X1_15_crv, (GEN)X1_15_r_n, (GEN)X1_15_r_d, 1, (GEN)X1_15_s_n, (GEN)X1_15_s_d, 1, RS_MAP }, { (GEN)X1_16_crv, (GEN)X1_16_r_n, (GEN)X1_16_r_d, 0, (GEN)X1_16_s_n, (GEN)X1_16_s_d, 0, RS_MAP }, { (GEN)X1_17_crv, (GEN)X1_17_r_n, (GEN)X1_17_r_d, 0, (GEN)X1_17_s_n, (GEN)X1_17_s_d, 0, RS_MAP }, { (GEN)X1_18_crv, (GEN)X1_18_r_n, (GEN)X1_18_r_d, 0, (GEN)X1_18_s_n, (GEN)X1_18_s_d, 0, RS_MAP }, { (GEN)X1_19_crv, (GEN)X1_19_r_n, (GEN)X1_19_r_d, 1, (GEN)X1_19_s_n, (GEN)X1_19_s_d, 1, RS_MAP }, { (GEN)X1_20_crv, (GEN)X1_20_r_n, (GEN)X1_20_r_d, 0, (GEN)X1_20_s_n, (GEN)X1_20_s_d, 0, TQ_MAP }, { (GEN)X1_21_crv, (GEN)X1_21_r_n, (GEN)X1_21_r_d, 1, (GEN)X1_21_s_n, (GEN)X1_21_s_d, 1, RS_MAP }, { (GEN)X1_22_crv, (GEN)X1_22_r_n, (GEN)X1_22_r_d, 0, (GEN)X1_22_s_n, (GEN)X1_22_s_d, 0, RS_MAP }, { (GEN)X1_23_crv, (GEN)X1_23_r_n, (GEN)X1_23_r_d, 0, (GEN)X1_23_s_n, (GEN)X1_23_s_d, 0, RS_MAP }, { (GEN)X1_24_crv, (GEN)X1_24_r_n, (GEN)X1_24_r_d, 0, (GEN)X1_24_s_n, (GEN)X1_24_s_d, 0, TQ_MAP }, { (GEN)X1_25_crv, (GEN)X1_25_r_n, (GEN)X1_25_r_d, 0, (GEN)X1_25_s_n, (GEN)X1_25_s_d, 0, RS_MAP }, { (GEN)X1_26_crv, (GEN)X1_26_r_n, (GEN)X1_26_r_d, 0, (GEN)X1_26_s_n, (GEN)X1_26_s_d, 0, RS_MAP }, { (GEN)X1_27_crv, (GEN)X1_27_r_n, (GEN)X1_27_r_d, 0, (GEN)X1_27_s_n, (GEN)X1_27_s_d, 0, RS_MAP }, { (GEN)X1_28_crv, (GEN)X1_28_r_n, (GEN)X1_28_r_d, 0, (GEN)X1_28_s_n, (GEN)X1_28_s_d, 0, QT_MAP }, { (GEN)X1_29_crv, (GEN)X1_29_r_n, (GEN)X1_29_r_d, 0, (GEN)X1_29_s_n, (GEN)X1_29_s_d, 1, RS_MAP }, { (GEN)X1_30_crv, (GEN)X1_30_r_n, (GEN)X1_30_r_d, 0, (GEN)X1_30_s_n, (GEN)X1_30_s_d, 0, TQ_MAP }, { (GEN)X1_31_crv, (GEN)X1_31_r_n, (GEN)X1_31_r_d, 0, (GEN)X1_31_s_n, (GEN)X1_31_s_d, 0, RS_MAP }, { (GEN)X1_32_crv, (GEN)X1_32_r_n, (GEN)X1_32_r_d, 0, (GEN)X1_32_s_n, (GEN)X1_32_s_d, 0, QT_MAP }, { (GEN)X1_33_crv, (GEN)X1_33_r_n, (GEN)X1_33_r_d, 0, (GEN)X1_33_s_n, (GEN)X1_33_s_d, 0, T_MAP}, { (GEN)X1_34_crv, (GEN)X1_34_r_n, (GEN)X1_34_r_d, 0, (GEN)X1_34_s_n, (GEN)X1_34_s_d, 0, RS_MAP }, { (GEN)X1_35_crv, (GEN)X1_35_r_n, (GEN)X1_35_r_d, 0, (GEN)X1_35_s_n, (GEN)X1_35_s_d, 0, RS_MAP }, { (GEN)X1_36_crv, (GEN)X1_36_r_n, (GEN)X1_36_r_d, 0, (GEN)X1_36_s_n, (GEN)X1_36_s_d, 0, RS_MAP }, { (GEN)X1_37_crv, (GEN)X1_37_r_n, (GEN)X1_37_r_d, 0, (GEN)X1_37_s_n, (GEN)X1_37_s_d, 0, RS_MAP }, { (GEN)X1_38_crv, (GEN)X1_38_r_n, (GEN)X1_38_r_d, 0, (GEN)X1_38_s_n, (GEN)X1_38_s_d, 0, RS_MAP }, { (GEN)X1_39_crv, (GEN)X1_39_r_n, (GEN)X1_39_r_d, 0, (GEN)X1_39_s_n, (GEN)X1_39_s_d, 0, T_MAP } }; INLINE const X1_info * get_X1_info(ulong N) { return &X1_table[N - FIRST_X1_LEVEL]; } pari-2.11.2/src/basemath/polclass.c0000644000175000017500000017204413366427320015533 0ustar billbill/* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" #define dbg_printf(lvl) if (DEBUGLEVEL >= (lvl) + 3) err_printf /* * SECTION: Functions dedicated to finding a j-invariant with a given * trace. */ /* TODO: This code is shared with * torsion_compatible_with_characteristic() in 'torsion.c'. */ static void hasse_bounds(long *low, long *high, long p) { long two_sqrt_p = usqrt(4*p); *low = p + 1 - two_sqrt_p; *high = p + 1 + two_sqrt_p; } /* a / b : a and b are from factoru and b must divide a exactly */ INLINE GEN famatsmall_divexact(GEN a, GEN b) { GEN a1 = gel(a,1), a2 = gel(a,2), c1, c2; GEN b1 = gel(b,1), b2 = gel(b,2); long i, j, k, la = lg(a1); c1 = cgetg(la, t_VECSMALL); c2 = cgetg(la, t_VECSMALL); for (i = j = k = 1; j < la; j++) { c1[k] = a1[j]; c2[k] = a2[j]; if (a1[j] == b1[i]) { c2[k] -= b2[i++]; if (!c2[k]) continue; } k++; } setlg(c1, k); setlg(c2, k); return mkvec2(c1,c2); } /* This is Sutherland, 2009, TestCurveOrder. * * [a4, a6] and p specify an elliptic curve over FF_p. N0,N1 are the two * possible curve orders, and n0,n1 their factoru */ static long test_curve_order(norm_eqn_t ne, ulong a4, ulong a6, long N0, long N1, GEN n0, GEN n1, const long hasse[2]) { pari_sp ltop = avma, av; ulong a4t, a6t, p = ne->p, pi = ne->pi, T = ne->T, swapped = 0; long m0, m1, hasse_low, hasse_high; if (p <= 11) { long card = (long)p + 1 - Fl_elltrace(a4, a6, p); return card == N0 || card == N1; } /* [a4, a6] is the given curve and [a4t, a6t] is its quadratic twist */ Fl_elltwist_disc(a4, a6, T, p, &a4t, &a6t); m0 = m1 = 1; if (N0 + N1 != 2 * (long)p + 2) pari_err_BUG("test_curve_order"); hasse_low = hasse[0]; hasse_high = hasse[1]; for (av = avma;;) { GEN pt, Q, fa0; long a1, x, n_s; pt = random_Flj_pre(a4, a6, p, pi); Q = Flj_mulu_pre(pt, m0, a4, p, pi); fa0 = m0 == 1? n0: famatsmall_divexact(n0, factoru(m0)); n_s = Flj_order_ufact(Q, N0 / m0, fa0, a4, p, pi); if (n_s == 0) { /* If m0 divides N1 and m1 divides N0 and N0 < N1, then swap */ if (!swapped && N1 % m0 == 0 && N0 % m1 == 0) { swapspec(n0, n1, N0, N1); swapped = 1; continue; } avma = ltop; return 0; } m0 *= n_s; a1 = (2 * p + 2) % m1; x = (hasse_low + m0 - 1) / m0; /* using ceil(n/d) = (n + d - 1)/d */ x *= m0; for ( ; x <= hasse_high; x += m0) if ((x % m1) == a1 && x != N0 && x != N1) break; /* every x in N was either N0 or N1, so we return true */ if (x > hasse_high) { avma = ltop; return 1; } lswap(a4, a4t); lswap(a6, a6t); lswap(m0, m1); avma = av; } } static GEN random_FleV(GEN x, GEN a6, ulong p, ulong pi) { pari_APPLY_type(t_VEC, random_Fle_pre(uel(x,i), uel(a6,i), p, pi)) } /** * START Code from AVSs "torcosts.h" */ struct torctab_rec { int m; int fix2, fix3; int N; int s2_flag; int t3_flag; double rating; }; /* These costs assume p=2 mod 3, 3 mod 4 and not 1 mod N */ static struct torctab_rec torctab1[] = { { 11, 1, 1, 11, 1, 1, 0.047250 }, { 33, 1, 0, 11, 1, 2, 0.047250 }, { 22, 1, 1, 11, 3, 1, 0.055125 }, { 66, 1, 0, 11, 3, 2, 0.055125 }, { 11, 1, 0, 11, 1, 0, 0.058000 }, { 13, 1, 1, 13, 1, 1, 0.058542 }, { 39, 1, 0, 13, 1, 2, 0.058542 }, { 22, 0, 1, 11, 2, 1, 0.061333 }, { 66, 0, 0, 11, 2, 2, 0.061333 }, { 22, 1, 0, 11, 3, 0, 0.061750 }, { 14, 1, 1, 14, 3, 1, 0.062500 }, { 42, 1, 0, 14, 3, 2, 0.062500 }, { 26, 1, 1, 13, 3, 1, 0.064583 }, { 78, 1, 0, 13, 3, 2, 0.064583 }, { 28, 0, 1, 14, 4, 1, 0.065625 }, { 84, 0, 0, 14, 4, 2, 0.065625 }, { 7, 1, 1, 7, 1, 1, 0.068750 }, { 13, 1, 0, 13, 1, 0, 0.068750 }, { 21, 1, 0, 7, 1, 2, 0.068750 }, { 26, 1, 0, 13, 3, 0, 0.069583 }, { 17, 1, 1, 17, 1, 1, 0.069687 }, { 51, 1, 0, 17, 1, 2, 0.069687 }, { 11, 0, 1, 11, 0, 1, 0.072500 }, { 33, 0, 0, 11, 0, 2, 0.072500 }, { 44, 1, 0, 11, 130, 0, 0.072667 }, { 52, 0, 1, 13, 4, 1, 0.073958 }, { 156, 0, 0, 13, 4, 2, 0.073958 }, { 34, 1, 1, 17, 3, 1, 0.075313 }, { 102, 1, 0, 17, 3, 2, 0.075313 }, { 15, 1, 0, 15, 1, 0, 0.075625 }, { 13, 0, 1, 13, 0, 1, 0.076667 }, { 39, 0, 0, 13, 0, 2, 0.076667 }, { 44, 0, 0, 11, 4, 0, 0.076667 }, { 30, 1, 0, 15, 3, 0, 0.077188 }, { 22, 0, 0, 11, 2, 0, 0.077333 }, { 34, 1, 0, 17, 3, 0, 0.077969 }, { 17, 1, 0, 17, 1, 0, 0.078750 }, { 14, 0, 1, 14, 0, 1, 0.080556 }, { 28, 0, 0, 14, 4, 0, 0.080556 }, { 42, 0, 0, 14, 0, 2, 0.080556 }, { 7, 1, 0, 7, 1, 0, 0.080833 }, { 9, 1, 0, 9, 1, 0, 0.080833 }, { 68, 0, 1, 17, 4, 1, 0.081380 }, { 204, 0, 0, 17, 4, 2, 0.081380 }, { 52, 0, 0, 13, 4, 0, 0.082292 }, { 10, 1, 1, 10, 3, 1, 0.084687 }, { 17, 0, 1, 17, 0, 1, 0.084687 }, { 51, 0, 0, 17, 0, 2, 0.084687 }, { 20, 0, 1, 10, 4, 1, 0.085938 }, { 60, 0, 0, 10, 4, 2, 0.085938 }, { 19, 1, 1, 19, 1, 1, 0.086111 }, { 57, 1, 0, 19, 1, 2, 0.086111 }, { 68, 0, 0, 17, 4, 0, 0.088281 }, { 38, 1, 1, 19, 3, 1, 0.089514 }, { 114, 1, 0, 19, 3, 2, 0.089514 }, { 20, 0, 0, 10, 4, 0, 0.090625 }, { 36, 0, 0, 18, 4, 0, 0.090972 }, { 26, 0, 0, 13, 2, 0, 0.091667 }, { 11, 0, 0, 11, 0, 0, 0.092000 }, { 19, 1, 0, 19, 1, 0, 0.092778 }, { 38, 1, 0, 19, 3, 0, 0.092778 }, { 14, 1, 0, 7, 3, 0, 0.092917 }, { 18, 1, 0, 9, 3, 0, 0.092917 }, { 76, 0, 1, 19, 4, 1, 0.095255 }, { 228, 0, 0, 19, 4, 2, 0.095255 }, { 10, 0, 1, 10, 0, 1, 0.096667 }, { 13, 0, 0, 13, 0, 0, 0.096667 }, { 30, 0, 0, 10, 0, 2, 0.096667 }, { 19, 0, 1, 19, 0, 1, 0.098333 }, { 57, 0, 0, 19, 0, 2, 0.098333 }, { 17, 0, 0, 17, 0, 0, 0.100000 }, { 23, 1, 1, 23, 1, 1, 0.100227 }, { 69, 1, 0, 23, 1, 2, 0.100227 }, { 7, 0, 1, 7, 0, 1, 0.100833 }, { 21, 0, 0, 7, 0, 2, 0.100833 }, { 76, 0, 0, 19, 4, 0, 0.102083 }, { 14, 0, 0, 14, 0, 0, 0.102222 }, { 18, 0, 0, 9, 2, 0, 0.102222 }, { 5, 1, 1, 5, 1, 1, 0.103125 }, { 46, 1, 1, 23, 3, 1, 0.104318 }, { 138, 1, 0, 23, 3, 2, 0.104318 }, { 23, 1, 0, 23, 1, 0, 0.105682 }, { 46, 1, 0, 23, 3, 0, 0.106705 }, { 92, 0, 1, 23, 4, 1, 0.109091 }, { 276, 0, 0, 23, 4, 2, 0.109091 }, { 19, 0, 0, 19, 0, 0, 0.110000 }, { 23, 0, 1, 23, 0, 1, 0.112273 }, { 69, 0, 0, 23, 0, 2, 0.112273 }, { 7, 0, 0, 7, 0, 0, 0.113333 }, { 9, 0, 0, 9, 0, 0, 0.113333 }, { 92, 0, 0, 23, 4, 0, 0.113826 }, { 16, 0, 1, 16, 0, 1, 0.118125 }, { 48, 0, 0, 16, 0, 2, 0.118125 }, { 5, 1, 0, 5, 1, 0, 0.121250 }, { 15, 0, 0, 15, 0, 0, 0.121250 }, { 10, 0, 0, 10, 0, 0, 0.121667 }, { 23, 0, 0, 23, 0, 0, 0.123182 }, { 12, 0, 0, 12, 0, 0, 0.141667 }, { 5, 0, 1, 5, 0, 1, 0.145000 }, { 16, 0, 0, 16, 0, 0, 0.145000 }, { 8, 0, 1, 8, 0, 1, 0.151250 }, { 29, 1, 1, 29, 1, 1, 0.153036 }, { 87, 1, 0, 29, 1, 2, 0.153036 }, { 25, 0, 0, 25, 0, 0, 0.155000 }, { 58, 1, 1, 29, 3, 1, 0.156116 }, { 174, 1, 0, 29, 3, 2, 0.156116 }, { 29, 1, 0, 29, 1, 0, 0.157500 }, { 58, 1, 0, 29, 3, 0, 0.157500 }, { 116, 0, 1, 29, 4, 1, 0.161086 }, { 29, 0, 1, 29, 0, 1, 0.163393 }, { 87, 0, 0, 29, 0, 2, 0.163393 }, { 116, 0, 0, 29, 4, 0, 0.163690 }, { 5, 0, 0, 5, 0, 0, 0.170000 }, { 8, 0, 0, 8, 0, 0, 0.170000 }, { 29, 0, 0, 29, 0, 0, 0.171071 }, { 31, 1, 1, 31, 1, 1, 0.186583 }, { 93, 1, 0, 31, 1, 2, 0.186583 }, { 62, 1, 1, 31, 3, 1, 0.189750 }, { 186, 1, 0, 31, 3, 2, 0.189750 }, { 31, 1, 0, 31, 1, 0, 0.191333 }, { 62, 1, 0, 31, 3, 0, 0.192167 }, { 124, 0, 1, 31, 4, 1, 0.193056 }, { 31, 0, 1, 31, 0, 1, 0.195333 }, { 93, 0, 0, 31, 0, 2, 0.195333 }, { 124, 0, 0, 31, 4, 0, 0.197917 }, { 2, 1, 1, 2, 3, 1, 0.200000 }, { 6, 1, 0, 2, 3, 2, 0.200000 }, { 31, 0, 0, 31, 0, 0, 0.206667 }, { 4, 1, 1, 4, 130, 1, 0.214167 }, { 6, 0, 0, 6, 0, 0, 0.226667 }, { 3, 1, 0, 3, 1, 0, 0.230000 }, { 4, 0, 1, 4, 0, 1, 0.241667 }, { 4, 1, 0, 2, 130, 0, 0.266667 }, { 4, 0, 0, 4, 0, 0, 0.283333 }, { 3, 0, 0, 3, 0, 0, 0.340000 }, { 1, 1, 1, 1, 1, 1, 0.362500 }, { 2, 0, 1, 2, 0, 1, 0.386667 }, { 1, 1, 0, 1, 1, 0, 0.410000 }, { 2, 0, 0, 2, 0, 0, 0.453333 }, }; static struct torctab_rec torctab2[] = { { 11, 1, 1, 11, 1, 1, 0.047250 }, { 33, 1, 0, 11, 1, 2, 0.047250 }, { 22, 1, 1, 11, 3, 1, 0.055125 }, { 66, 1, 0, 11, 3, 2, 0.055125 }, { 13, 1, 1, 13, 1, 1, 0.057500 }, { 39, 1, 0, 13, 1, 2, 0.057500 }, { 11, 1, 0, 11, 1, 0, 0.058000 }, { 22, 0, 1, 11, 2, 1, 0.061333 }, { 66, 0, 0, 11, 2, 2, 0.061333 }, { 14, 1, 1, 14, 3, 1, 0.061458 }, { 42, 1, 0, 14, 3, 2, 0.061458 }, { 22, 1, 0, 11, 3, 0, 0.061750 }, { 26, 1, 1, 13, 3, 1, 0.064062 }, { 78, 1, 0, 13, 3, 2, 0.064062 }, { 28, 0, 1, 14, 4, 1, 0.065625 }, { 84, 0, 0, 14, 4, 2, 0.065625 }, { 13, 1, 0, 13, 1, 0, 0.066667 }, { 26, 1, 0, 13, 3, 0, 0.069583 }, { 17, 1, 1, 17, 1, 1, 0.069687 }, { 51, 1, 0, 17, 1, 2, 0.069687 }, { 11, 0, 1, 11, 0, 1, 0.070000 }, { 33, 0, 0, 11, 0, 2, 0.070000 }, { 7, 1, 1, 7, 1, 1, 0.070417 }, { 21, 1, 0, 7, 1, 2, 0.070417 }, { 15, 1, 0, 15, 1, 0, 0.072500 }, { 52, 0, 1, 13, 4, 1, 0.073090 }, { 156, 0, 0, 13, 4, 2, 0.073090 }, { 34, 1, 1, 17, 3, 1, 0.074219 }, { 102, 1, 0, 17, 3, 2, 0.074219 }, { 7, 1, 0, 7, 1, 0, 0.076667 }, { 13, 0, 1, 13, 0, 1, 0.076667 }, { 39, 0, 0, 13, 0, 2, 0.076667 }, { 44, 0, 0, 11, 4, 0, 0.076667 }, { 17, 1, 0, 17, 1, 0, 0.077188 }, { 22, 0, 0, 11, 2, 0, 0.077333 }, { 34, 1, 0, 17, 3, 0, 0.077969 }, { 30, 1, 0, 15, 3, 0, 0.080312 }, { 14, 0, 1, 14, 0, 1, 0.080556 }, { 28, 0, 0, 14, 4, 0, 0.080556 }, { 42, 0, 0, 14, 0, 2, 0.080556 }, { 9, 1, 0, 9, 1, 0, 0.080833 }, { 68, 0, 1, 17, 4, 1, 0.081380 }, { 204, 0, 0, 17, 4, 2, 0.081380 }, { 52, 0, 0, 13, 4, 0, 0.082292 }, { 10, 1, 1, 10, 3, 1, 0.083125 }, { 20, 0, 1, 10, 4, 1, 0.083333 }, { 60, 0, 0, 10, 4, 2, 0.083333 }, { 17, 0, 1, 17, 0, 1, 0.084687 }, { 51, 0, 0, 17, 0, 2, 0.084687 }, { 19, 1, 1, 19, 1, 1, 0.084722 }, { 57, 1, 0, 19, 1, 2, 0.084722 }, { 11, 0, 0, 11, 0, 0, 0.087000 }, { 68, 0, 0, 17, 4, 0, 0.088281 }, { 38, 1, 1, 19, 3, 1, 0.090139 }, { 114, 1, 0, 19, 3, 2, 0.090139 }, { 36, 0, 0, 18, 4, 0, 0.090972 }, { 19, 1, 0, 19, 1, 0, 0.091389 }, { 26, 0, 0, 13, 2, 0, 0.091667 }, { 13, 0, 0, 13, 0, 0, 0.092500 }, { 38, 1, 0, 19, 3, 0, 0.092778 }, { 14, 1, 0, 7, 3, 0, 0.092917 }, { 18, 1, 0, 9, 3, 0, 0.092917 }, { 20, 0, 0, 10, 4, 0, 0.095833 }, { 76, 0, 1, 19, 4, 1, 0.096412 }, { 228, 0, 0, 19, 4, 2, 0.096412 }, { 17, 0, 0, 17, 0, 0, 0.096875 }, { 19, 0, 1, 19, 0, 1, 0.098056 }, { 57, 0, 0, 19, 0, 2, 0.098056 }, { 23, 1, 1, 23, 1, 1, 0.100682 }, { 69, 1, 0, 23, 1, 2, 0.100682 }, { 7, 0, 1, 7, 0, 1, 0.100833 }, { 21, 0, 0, 7, 0, 2, 0.100833 }, { 30, 0, 0, 15, 2, 0, 0.100833 }, { 76, 0, 0, 19, 4, 0, 0.102083 }, { 14, 0, 0, 14, 0, 0, 0.102222 }, { 5, 1, 1, 5, 1, 1, 0.103125 }, { 46, 1, 1, 23, 3, 1, 0.104034 }, { 138, 1, 0, 23, 3, 2, 0.104034 }, { 23, 1, 0, 23, 1, 0, 0.104545 }, { 7, 0, 0, 7, 0, 0, 0.105000 }, { 10, 0, 1, 10, 0, 1, 0.105000 }, { 16, 0, 1, 16, 0, 1, 0.105417 }, { 48, 0, 0, 16, 0, 2, 0.105417 }, { 46, 1, 0, 23, 3, 0, 0.106705 }, { 18, 0, 0, 9, 2, 0, 0.107778 }, { 92, 0, 1, 23, 4, 1, 0.108239 }, { 276, 0, 0, 23, 4, 2, 0.108239 }, { 19, 0, 0, 19, 0, 0, 0.110000 }, { 23, 0, 1, 23, 0, 1, 0.111136 }, { 69, 0, 0, 23, 0, 2, 0.111136 }, { 9, 0, 0, 9, 0, 0, 0.113333 }, { 10, 0, 0, 10, 0, 0, 0.113333 }, { 92, 0, 0, 23, 4, 0, 0.113826 }, { 5, 1, 0, 5, 1, 0, 0.115000 }, { 15, 0, 0, 15, 0, 0, 0.115000 }, { 23, 0, 0, 23, 0, 0, 0.120909 }, { 8, 0, 1, 8, 0, 1, 0.126042 }, { 24, 0, 0, 8, 0, 2, 0.126042 }, { 16, 0, 0, 16, 0, 0, 0.127188 }, { 8, 0, 0, 8, 0, 0, 0.141667 }, { 25, 0, 1, 25, 0, 1, 0.144000 }, { 5, 0, 1, 5, 0, 1, 0.151250 }, { 12, 0, 0, 12, 0, 0, 0.152083 }, { 29, 1, 1, 29, 1, 1, 0.153929 }, { 87, 1, 0, 29, 1, 2, 0.153929 }, { 25, 0, 0, 25, 0, 0, 0.155000 }, { 58, 1, 1, 29, 3, 1, 0.155045 }, { 174, 1, 0, 29, 3, 2, 0.155045 }, { 29, 1, 0, 29, 1, 0, 0.156429 }, { 58, 1, 0, 29, 3, 0, 0.157857 }, { 116, 0, 1, 29, 4, 1, 0.158631 }, { 116, 0, 0, 29, 4, 0, 0.163542 }, { 29, 0, 1, 29, 0, 1, 0.164286 }, { 87, 0, 0, 29, 0, 2, 0.164286 }, { 29, 0, 0, 29, 0, 0, 0.169286 }, { 5, 0, 0, 5, 0, 0, 0.170000 }, { 31, 1, 1, 31, 1, 1, 0.187000 }, { 93, 1, 0, 31, 1, 2, 0.187000 }, { 62, 1, 1, 31, 3, 1, 0.188500 }, { 186, 1, 0, 31, 3, 2, 0.188500 }, { 31, 1, 0, 31, 1, 0, 0.191333 }, { 62, 1, 0, 31, 3, 0, 0.192083 }, { 124, 0, 1, 31, 4, 1, 0.193472 }, { 31, 0, 1, 31, 0, 1, 0.196167 }, { 93, 0, 0, 31, 0, 2, 0.196167 }, { 124, 0, 0, 31, 4, 0, 0.197083 }, { 2, 1, 1, 2, 3, 1, 0.200000 }, { 6, 1, 0, 2, 3, 2, 0.200000 }, { 31, 0, 0, 31, 0, 0, 0.205000 }, { 6, 0, 0, 6, 0, 0, 0.226667 }, { 3, 1, 0, 3, 1, 0, 0.230000 }, { 4, 0, 1, 4, 0, 1, 0.241667 }, { 4, 0, 0, 4, 0, 0, 0.283333 }, { 3, 0, 0, 3, 0, 0, 0.340000 }, { 1, 1, 1, 1, 1, 1, 0.362500 }, { 2, 0, 1, 2, 0, 1, 0.370000 }, { 1, 1, 0, 1, 1, 0, 0.385000 }, { 2, 0, 0, 2, 0, 0, 0.453333 }, }; static struct torctab_rec torctab3[] = { { 66, 1, 0, 11, 3, 2, 0.040406 }, { 33, 1, 0, 11, 1, 2, 0.043688 }, { 78, 1, 0, 13, 3, 2, 0.045391 }, { 132, 1, 0, 11, 130, 2, 0.046938 }, { 39, 1, 0, 13, 1, 2, 0.047656 }, { 102, 1, 0, 17, 3, 2, 0.049922 }, { 42, 1, 0, 14, 3, 2, 0.050000 }, { 51, 1, 0, 17, 1, 2, 0.051680 }, { 132, 0, 0, 11, 4, 2, 0.052188 }, { 156, 1, 0, 13, 130, 2, 0.053958 }, { 156, 0, 0, 13, 4, 2, 0.054818 }, { 84, 1, 0, 14, 130, 2, 0.055000 }, { 15, 1, 0, 15, 1, 0, 0.056719 }, { 204, 0, 0, 17, 4, 2, 0.057227 }, { 114, 1, 0, 19, 3, 2, 0.057500 }, { 11, 1, 0, 11, 1, 0, 0.058000 }, { 66, 0, 0, 11, 2, 2, 0.058000 }, { 57, 1, 0, 19, 1, 2, 0.059062 }, { 30, 1, 0, 15, 3, 0, 0.059063 }, { 84, 0, 0, 14, 4, 2, 0.060677 }, { 22, 1, 0, 11, 3, 0, 0.061750 }, { 78, 0, 0, 13, 2, 2, 0.063542 }, { 228, 0, 0, 19, 4, 2, 0.063889 }, { 21, 1, 0, 7, 1, 2, 0.065000 }, { 138, 1, 0, 23, 3, 2, 0.065028 }, { 69, 1, 0, 23, 1, 2, 0.066903 }, { 13, 1, 0, 13, 1, 0, 0.068750 }, { 102, 0, 0, 17, 2, 2, 0.068906 }, { 26, 1, 0, 13, 3, 0, 0.069583 }, { 51, 0, 0, 17, 0, 2, 0.070312 }, { 60, 1, 0, 15, 130, 0, 0.071094 }, { 276, 0, 0, 23, 4, 2, 0.071236 }, { 39, 0, 0, 13, 0, 2, 0.071250 }, { 33, 0, 0, 11, 0, 2, 0.072750 }, { 44, 1, 0, 11, 130, 0, 0.073500 }, { 60, 0, 0, 15, 4, 0, 0.073828 }, { 9, 1, 0, 9, 1, 0, 0.074097 }, { 30, 0, 0, 15, 2, 0, 0.075625 }, { 57, 0, 0, 19, 0, 2, 0.075625 }, { 7, 1, 0, 7, 1, 0, 0.076667 }, { 44, 0, 0, 11, 4, 0, 0.076667 }, { 22, 0, 0, 11, 2, 0, 0.077333 }, { 17, 1, 0, 17, 1, 0, 0.078750 }, { 34, 1, 0, 17, 3, 0, 0.078750 }, { 69, 0, 0, 23, 0, 2, 0.079943 }, { 28, 0, 0, 14, 4, 0, 0.080556 }, { 42, 0, 0, 14, 0, 2, 0.080833 }, { 52, 0, 0, 13, 4, 0, 0.082292 }, { 14, 1, 1, 14, 3, 1, 0.083333 }, { 36, 0, 0, 18, 4, 0, 0.083391 }, { 18, 1, 0, 9, 3, 0, 0.085174 }, { 68, 0, 0, 17, 4, 0, 0.089583 }, { 15, 0, 0, 15, 0, 0, 0.090938 }, { 19, 1, 0, 19, 1, 0, 0.091389 }, { 26, 0, 0, 13, 2, 0, 0.091667 }, { 11, 0, 0, 11, 0, 0, 0.092000 }, { 13, 0, 0, 13, 0, 0, 0.092500 }, { 38, 1, 0, 19, 3, 0, 0.092778 }, { 14, 1, 0, 7, 3, 0, 0.092917 }, { 18, 0, 0, 9, 2, 0, 0.093704 }, { 174, 1, 0, 29, 3, 2, 0.095826 }, { 20, 0, 0, 10, 4, 0, 0.095833 }, { 96, 1, 0, 16, 133, 2, 0.096562 }, { 21, 0, 0, 21, 0, 0, 0.096875 }, { 87, 1, 0, 29, 1, 2, 0.096964 }, { 17, 0, 0, 17, 0, 0, 0.100000 }, { 348, 0, 0, 29, 4, 2, 0.100558 }, { 76, 0, 0, 19, 4, 0, 0.100926 }, { 14, 0, 0, 14, 0, 0, 0.102222 }, { 9, 0, 0, 9, 0, 0, 0.103889 }, { 46, 1, 0, 23, 3, 0, 0.105114 }, { 23, 1, 0, 23, 1, 0, 0.105682 }, { 48, 0, 0, 16, 0, 2, 0.106406 }, { 87, 0, 0, 29, 0, 2, 0.107545 }, { 19, 0, 0, 19, 0, 0, 0.107778 }, { 7, 0, 0, 7, 0, 0, 0.113333 }, { 10, 0, 0, 10, 0, 0, 0.113333 }, { 92, 0, 0, 23, 4, 0, 0.113636 }, { 12, 0, 0, 12, 0, 0, 0.114062 }, { 5, 1, 0, 5, 1, 0, 0.115000 }, { 186, 1, 0, 31, 3, 2, 0.115344 }, { 93, 1, 0, 31, 1, 2, 0.118125 }, { 23, 0, 0, 23, 0, 0, 0.120909 }, { 93, 0, 0, 31, 0, 2, 0.128250 }, { 16, 0, 0, 16, 0, 0, 0.138750 }, { 25, 0, 0, 25, 0, 0, 0.155000 }, { 58, 1, 0, 29, 3, 0, 0.155714 }, { 29, 1, 0, 29, 1, 0, 0.158214 }, { 3, 1, 0, 3, 1, 0, 0.163125 }, { 116, 0, 0, 29, 4, 0, 0.163690 }, { 5, 0, 0, 5, 0, 0, 0.170000 }, { 6, 0, 0, 6, 0, 0, 0.170000 }, { 8, 0, 0, 8, 0, 0, 0.170000 }, { 29, 0, 0, 29, 0, 0, 0.172857 }, { 31, 1, 0, 31, 1, 0, 0.191333 }, { 62, 1, 0, 31, 3, 0, 0.191750 }, { 124, 0, 0, 31, 4, 0, 0.197917 }, { 31, 0, 0, 31, 0, 0, 0.201667 }, { 3, 0, 0, 3, 0, 0, 0.236250 }, { 4, 0, 0, 4, 0, 0, 0.262500 }, { 2, 1, 1, 2, 3, 1, 0.317187 }, { 1, 1, 0, 1, 1, 0, 0.410000 }, { 2, 0, 0, 2, 0, 0, 0.453333 }, }; static struct torctab_rec torctab4[] = { { 66, 1, 0, 11, 3, 2, 0.041344 }, { 33, 1, 0, 11, 1, 2, 0.042750 }, { 78, 1, 0, 13, 3, 2, 0.045781 }, { 39, 1, 0, 13, 1, 2, 0.046875 }, { 264, 1, 0, 11, 131, 2, 0.049043 }, { 42, 1, 0, 14, 3, 2, 0.050000 }, { 102, 1, 0, 17, 3, 2, 0.050508 }, { 51, 1, 0, 17, 1, 2, 0.051094 }, { 528, 1, 0, 11, 132, 2, 0.052891 }, { 132, 0, 0, 11, 4, 2, 0.052969 }, { 168, 1, 0, 14, 131, 2, 0.053965 }, { 156, 0, 0, 13, 4, 2, 0.054948 }, { 336, 1, 0, 14, 132, 2, 0.056120 }, { 15, 1, 0, 15, 1, 0, 0.056719 }, { 66, 0, 0, 11, 2, 2, 0.057000 }, { 114, 1, 0, 19, 3, 2, 0.057812 }, { 11, 1, 0, 11, 1, 0, 0.058000 }, { 204, 0, 0, 17, 4, 2, 0.058203 }, { 57, 1, 0, 19, 1, 2, 0.058542 }, { 84, 0, 0, 14, 4, 2, 0.059375 }, { 30, 1, 0, 15, 3, 0, 0.061406 }, { 22, 1, 0, 11, 3, 0, 0.063000 }, { 78, 0, 0, 13, 2, 2, 0.063542 }, { 138, 1, 0, 23, 3, 2, 0.064815 }, { 21, 1, 0, 7, 1, 2, 0.065000 }, { 228, 0, 0, 19, 4, 2, 0.065104 }, { 69, 1, 0, 23, 1, 2, 0.066477 }, { 13, 1, 0, 13, 1, 0, 0.068750 }, { 102, 0, 0, 17, 2, 2, 0.068906 }, { 51, 0, 0, 17, 0, 2, 0.069141 }, { 26, 1, 0, 13, 3, 0, 0.070625 }, { 276, 0, 0, 23, 4, 2, 0.071236 }, { 39, 0, 0, 13, 0, 2, 0.071250 }, { 33, 0, 0, 11, 0, 2, 0.072750 }, { 60, 0, 0, 15, 4, 0, 0.073828 }, { 9, 1, 0, 9, 1, 0, 0.074097 }, { 57, 0, 0, 19, 0, 2, 0.074583 }, { 30, 0, 0, 15, 2, 0, 0.075625 }, { 44, 0, 0, 11, 4, 0, 0.076667 }, { 17, 1, 0, 17, 1, 0, 0.077188 }, { 22, 0, 0, 11, 2, 0, 0.077333 }, { 69, 0, 0, 23, 0, 2, 0.080114 }, { 36, 0, 0, 18, 4, 0, 0.080208 }, { 34, 1, 0, 17, 3, 0, 0.080312 }, { 28, 0, 0, 14, 4, 0, 0.080556 }, { 7, 1, 0, 7, 1, 0, 0.080833 }, { 52, 0, 0, 13, 4, 0, 0.082292 }, { 42, 0, 0, 14, 0, 2, 0.082500 }, { 14, 1, 1, 14, 3, 1, 0.083333 }, { 15, 0, 0, 15, 0, 0, 0.086250 }, { 18, 1, 0, 9, 3, 0, 0.087083 }, { 26, 0, 0, 13, 2, 0, 0.088889 }, { 68, 0, 0, 17, 4, 0, 0.089583 }, { 48, 1, 0, 16, 132, 2, 0.089844 }, { 19, 1, 0, 19, 1, 0, 0.091389 }, { 11, 0, 0, 11, 0, 0, 0.092000 }, { 38, 1, 0, 19, 3, 0, 0.092917 }, { 18, 0, 0, 9, 2, 0, 0.093704 }, { 14, 1, 0, 7, 3, 0, 0.095000 }, { 96, 1, 0, 16, 133, 2, 0.095391 }, { 20, 0, 0, 10, 4, 0, 0.095833 }, { 174, 1, 0, 29, 3, 2, 0.095893 }, { 13, 0, 0, 13, 0, 0, 0.096667 }, { 17, 0, 0, 17, 0, 0, 0.096875 }, { 21, 0, 0, 21, 0, 0, 0.096875 }, { 87, 1, 0, 29, 1, 2, 0.097366 }, { 48, 0, 0, 16, 0, 2, 0.097969 }, { 24, 1, 0, 12, 131, 0, 0.098789 }, { 76, 0, 0, 19, 4, 0, 0.100926 }, { 348, 0, 0, 29, 4, 2, 0.101116 }, { 14, 0, 0, 14, 0, 0, 0.102222 }, { 9, 0, 0, 9, 0, 0, 0.103889 }, { 23, 1, 0, 23, 1, 0, 0.104545 }, { 46, 1, 0, 23, 3, 0, 0.105682 }, { 12, 0, 0, 12, 0, 0, 0.106250 }, { 87, 0, 0, 29, 0, 2, 0.108348 }, { 19, 0, 0, 19, 0, 0, 0.110000 }, { 7, 0, 0, 7, 0, 0, 0.113333 }, { 10, 0, 0, 10, 0, 0, 0.113333 }, { 92, 0, 0, 23, 4, 0, 0.113826 }, { 186, 1, 0, 31, 3, 2, 0.116094 }, { 93, 1, 0, 31, 1, 2, 0.116813 }, { 23, 0, 0, 23, 0, 0, 0.120909 }, { 5, 1, 0, 5, 1, 0, 0.121250 }, { 93, 0, 0, 31, 0, 2, 0.127625 }, { 16, 0, 0, 16, 0, 0, 0.132917 }, { 8, 0, 0, 8, 0, 0, 0.141667 }, { 25, 0, 0, 25, 0, 0, 0.152500 }, { 58, 1, 0, 29, 3, 0, 0.157946 }, { 29, 1, 0, 29, 1, 0, 0.158393 }, { 116, 0, 0, 29, 4, 0, 0.162946 }, { 3, 1, 0, 3, 1, 0, 0.163125 }, { 29, 0, 0, 29, 0, 0, 0.169286 }, { 5, 0, 0, 5, 0, 0, 0.170000 }, { 6, 0, 0, 6, 0, 0, 0.170000 }, { 31, 1, 0, 31, 1, 0, 0.191333 }, { 62, 1, 0, 31, 3, 0, 0.192083 }, { 124, 0, 0, 31, 4, 0, 0.196389 }, { 31, 0, 0, 31, 0, 0, 0.205000 }, { 3, 0, 0, 3, 0, 0, 0.255000 }, { 4, 0, 0, 4, 0, 0, 0.262500 }, { 2, 1, 1, 2, 3, 1, 0.325000 }, { 1, 1, 0, 1, 1, 0, 0.385000 }, { 2, 0, 0, 2, 0, 0, 0.420000 }, }; #define TWIST_DOUBLE_RATIO (9.0/16.0) static long torsion_constraint(struct torctab_rec *torctab, long ltorc, double tormod[], long n, long m) { long i, b = -1; double rb = -1.; for (i = 0 ; i < ltorc ; i++) { struct torctab_rec *ti = torctab + i; if ( ! (n%ti->m) && ( !ti->fix2 || (n%(2*ti->m)) ) && ( ! ti->fix3 || (n%(3*ti->m)) ) ) if ( n == m || ( ! (m%ti->m) && ( !ti->fix2 || (m%(2*ti->m)) ) && ( ! ti->fix3 || (m%(3*ti->m)) ) ) ) { double ri = ti->rating*tormod[ti->N]; if ( b < 0 || ri < rb ) { b = i; rb = ri; } } } if (b < 0) pari_err_BUG("find_rating"); return b; } static void best_torsion_constraint(ulong p, long t, int *ptwist, ulong *ptor, int *ps2, int *pt3) { struct torctab_rec *torctab; double tormod[32]; long ltorc; long n1, n2; long b, b1, b2, b12; long i; if ( (p%3)==2 ) { if ( (p&3)==3 ) { torctab = torctab1; ltorc = sizeof(torctab1)/sizeof(*torctab1); } else { torctab = torctab2; ltorc = sizeof(torctab2)/sizeof(*torctab2); } } else { if ( (p&3)==3 ) { torctab = torctab3; ltorc = sizeof(torctab3)/sizeof(*torctab3); } else { torctab = torctab4; ltorc = sizeof(torctab4)/sizeof(*torctab4); } } for ( i = 0 ; i < 32 ; i++ ) tormod[i] = 1.0; if ( (p%5)==1 ) tormod[5] = tormod[10] = tormod[15] = 6.0/5.0; if ( (p%7)==1 ) tormod[7] = tormod[14] = 8.0/7.0; if ( (p%11)== 1 ) tormod[11] = 12.0/11.0; if ( (p%13)==1 ) tormod[13] = 14.0/13.0; if ( (p%17)==1 ) tormod[17] = 18.0/17.0; if ( (p%19)==1 ) tormod[19] = 20.0/19.0; if ( (p%23)==1 ) tormod[23] = 24.0/23.0; if ( (p%29)==1 ) tormod[29] = 30.0/29.0; if ( (p%31)==1 ) tormod[31] = 32.0/31.0; n1 = p+1-t; n2 = p+1+t; b12 = -1; b1 = torsion_constraint(torctab, ltorc, tormod, n1, n1); b2 = torsion_constraint(torctab, ltorc, tormod, n2, n2); b12 = torsion_constraint(torctab, ltorc, tormod, n1, n2); if ( b1 > b2 ) { if ( torctab[b2].rating / TWIST_DOUBLE_RATIO > torctab[b12].rating ) *ptwist = 3; else *ptwist = 2; } else if ( torctab[b1].rating / TWIST_DOUBLE_RATIO > torctab[b12].rating ) *ptwist = 3; else *ptwist = 1; b = *ptwist ==1 ? b1: *ptwist ==2 ? b2: b12; *ptor = torctab[b].N; *ps2 = torctab[b].s2_flag; *pt3 = torctab[b].t3_flag; } /* This is Sutherland 2009 Algorithm 1.1 */ static long find_j_inv_with_given_trace( ulong *j_t, norm_eqn_t ne, long rho_inv, long max_curves) { pari_sp ltop = avma, av; long curves_tested = 0, batch_size; long N0, N1, hasse[2]; GEN n0, n1; long i, found = 0; ulong p = ne->p, pi = ne->pi; long t = ne->t; ulong p1 = p + 1, a4, a6, m, N; GEN A4, A6, tx, ty; int s2_flag, t3_flag, twist; if (p == 2 || p == 3) { if (t == 0) pari_err_BUG("find_j_inv_with_given_trace"); *j_t = t; return 1; } N0 = (long)p1 - t; n0 = factoru(N0); N1 = (long)p1 + t; n1 = factoru(N1); best_torsion_constraint(p, t, &twist, &m, &s2_flag, &t3_flag); N = p1 - (twist<3 ? (twist==1 ? t: -t): 0); /* Select batch size so that we have roughly a 50% chance of finding * a good curve in a batch. */ batch_size = 1.0 + rho_inv / (2.0 * m); A4 = cgetg(batch_size + 1, t_VECSMALL); A6 = cgetg(batch_size + 1, t_VECSMALL); tx = cgetg(batch_size + 1, t_VECSMALL); ty = cgetg(batch_size + 1, t_VECSMALL); dbg_printf(2)(" Selected torsion constraint m = %lu and batch " "size = %ld\n", m, batch_size); hasse_bounds(&hasse[0], &hasse[1], p); av = avma; while (!found && (max_curves <= 0 || curves_tested < max_curves)) { GEN Pp1, Pt; random_curves_with_m_torsion((ulong *)(A4 + 1), (ulong *)(A6 + 1), (ulong *)(tx + 1), (ulong *)(ty + 1), batch_size, m, p); Pp1 = random_FleV(A4, A6, p, pi); Pt = gcopy(Pp1); FleV_mulu_pre_inplace(Pp1, N, A4, p, pi); if (twist >= 3) FleV_mulu_pre_inplace(Pt, t, A4, p, pi); for (i = 1; i <= batch_size; ++i) { ++curves_tested; a4 = A4[i]; a6 = A6[i]; if (a4 == 0 || a6 == 0) continue; if (( (twist >= 3 && mael(Pp1,i,1) == mael(Pt,i,1)) || (twist < 3 && umael(Pp1,i,1) == p)) && test_curve_order(ne, a4, a6, N0, N1, n0, n1, hasse)) { *j_t = Fl_ellj_pre(a4, a6, p, pi); found = 1; break; } } avma = av; } avma = ltop; return curves_tested; } /* * SECTION: Functions for dealing with polycyclic presentations. */ static GEN next_generator(GEN DD, long D, ulong u, long filter, GEN *genred, long *P) { pari_sp av = avma; ulong p = (ulong)*P; while (1) { p = unextprime(p + 1); if (p > LONG_MAX) pari_err_BUG("next_generator"); if (kross(D, (long)p) != -1 && u % p != 0 && filter % p != 0) { GEN gen = primeform_u(DD, p); /* If gen is in the principal class, skip it */ *genred = redimag(gen); if (!equali1(gel(*genred,1))) { *P = (long)p; return gen; } avma = av; } } } INLINE long * evec_ri_mutate(long r[], long i) { return r + (i * (i - 1) >> 1); } INLINE const long * evec_ri(const long r[], long i) { return r + (i * (i - 1) >> 1); } /* Reduces evec e so that e[i] < n[i] (assume e[i] >= 0) using pcp(n,r,k). * No check for overflow, this could be an issue for large groups */ INLINE void evec_reduce(long e[], const long n[], const long r[], long k) { long i, j, q; const long *ri; if (!k) return; for (i = k - 1; i > 0; i--) { if (e[i] >= n[i]) { q = e[i] / n[i]; ri = evec_ri(r, i); for (j = 0; j < i; j++) e[j] += q * ri[j]; e[i] -= q * n[i]; } } e[0] %= n[0]; } /* Computes e3 = log(a^e1*a^e2) in terms of the given polycyclic * presentation (here a denotes the implicit vector of generators) */ INLINE void evec_compose(long e3[], const long e1[], const long e2[], const long n[],const long r[], long k) { long i; for (i = 0; i < k; i++) e3[i] = e1[i] + e2[i]; evec_reduce(e3, n, r, k); } /* Converts an evec to an integer index corresponding to the * multi-radix representation of the evec with moduli corresponding to * the subgroup orders m[i] */ INLINE long evec_to_index(const long e[], const long m[], long k) { long i, index = e[0]; for (i = 1; i < k; i++) index += e[i] * m[i - 1]; return index; } INLINE void evec_copy(long f[], const long e[], long k) { long i; for (i = 0; i < k; ++i) f[i] = e[i]; } INLINE void evec_clear(long e[], long k) { long i; for (i = 0; i < k; ++i) e[i] = 0; } /* e1 and e2 may overlap */ /* Note that this function is not very efficient because it does not know the * orders of the elements in the presentation, only the relative orders */ INLINE void evec_inverse(long e2[], const long e1[], const long n[], const long r[], long k) { pari_sp av = avma; long i, *e3, *e4; e3 = new_chunk(k); e4 = new_chunk(k); evec_clear(e4, k); evec_copy(e3, e1, k); /* We have e1 + e4 = e3 which we maintain throughout while making e1 * the zero vector */ for (i = k - 1; i >= 0; i--) if (e3[i]) { e4[i] += n[i] - e3[i]; evec_reduce(e4, n, r, k); e3[i] = n[i]; evec_reduce(e3, n, r, k); } evec_copy(e2, e4, k); avma = av; } /* e1 and e2 may overlap */ /* This is a faster way to compute inverses, if the presentation * element orders are known (these are specified in the array o, the * array n holds the relative orders) */ INLINE void evec_inverse_o( long e2[], const long e1[], const long n[], const long o[], const long r[], long k) { long j; for (j = 0; j < k; j++) e2[j] = (e1[j] ? o[j] - e1[j] : 0); evec_reduce(e2, n, r, k); } /* Computes the order of the group element a^e using the pcp (n,r,k) */ INLINE long evec_order(const long e[], const long n[], const long r[], long k) { pari_sp av = avma; long *f = new_chunk(k); long i, j, o, m; evec_copy(f, e, k); for (o = 1, i = k - 1; i >= 0; i--) if (f[i]) { m = n[i] / ugcd(f[i], n[i]); for (j = 0; j < k; j++) f[j] *= m; evec_reduce(f, n, r, k); o *= m; } avma = av; return o; } /* Computes orders o[] for each generator using relative orders n[] * and power relations r[] */ INLINE void evec_orders(long o[], const long n[], const long r[], long k) { pari_sp av = avma; long i, *e = new_chunk(k); evec_clear(e, k); for (i = 0; i < k; i++) { e[i] = 1; if (i) e[i - 1] = 0; o[i] = evec_order(e, n, r, k); } avma = av; } INLINE int evec_equal(const long e1[], const long e2[], long k) { long j; for (j = 0; j < k; ++j) if (e1[j] != e2[j]) break; return j == k; } INLINE void index_to_evec(long e[], long index, const long m[], long k) { long i; for (i = k - 1; i > 0; --i) { e[i] = index / m[i - 1]; index -= e[i] * m[i - 1]; } e[0] = index; } INLINE void evec_n_to_m(long m[], const long n[], long k) { long i; m[0] = n[0]; for (i = 1; i < k; ++i) m[i] = m[i - 1] * n[i]; } /* Based on logfac() in Sutherland's classpoly package. * Ramanujan approximation to log(n!), accurate to O(1/n^3) */ INLINE double logfac(long n) { const double HALFLOGPI = 0.57236494292470008707171367567653; return n * log((double) n) - (double) n + log((double) n * (1.0 + 4.0 * n * (1.0 + 2.0 * n))) / 6.0 + HALFLOGPI; } /* This is based on Sutherland 2009, Lemma 8 (p31). */ static double upper_bound_on_classpoly_coeffs(long D, long h, GEN qfinorms) { const double LOG2E = 1.44269504088896340735992468100189; pari_sp ltop = avma; GEN C = dbltor(2114.567); double Mk, m, logbinom; GEN tmp = mulrr(mppi(LOWDEFAULTPREC), sqrtr(stor(-D, LOWDEFAULTPREC))); /* We treat this case separately since the table is not initialised when * h = 1. This is the same as in the for loop below but with ak = 1. */ double log2Mk = dbllog2r(mpadd(mpexp(tmp), C)); double res = log2Mk; ulong maxak = 1; double log2Mh = log2Mk; pari_sp btop = avma; long k; for (k = 2; k <= h; ++k) { ulong ak = uel(qfinorms, k); /* exp(tmp/a[k]) can overflow for even moderate discriminants, so we need * to use t_REALs instead of doubles. Sutherland has a (more complicated) * implementation in the classpoly package which should be consulted if * this ever turns out to be a bottleneck. * * One idea to avoid t_REALs is the following: we have * log(e^x + C) - x <= log(2) ~ 0.69 for x >= log(C) ~ 0.44 and * the difference is basically zero for x slightly bigger than log(C). * Hence for large discriminants, we have x = \pi\sqrt{-D}/ak >> log(C) * and so we could approximate log(e^x + C) by x. */ log2Mk = dbllog2r(mpadd(mpexp(divru(tmp, ak)), C)); res += log2Mk; if (ak > maxak) { maxak = ak; log2Mh = log2Mk; } avma = btop; } Mk = pow(2.0, log2Mh); m = floor((h + 1)/(Mk + 1.0)); /* This line computes "log2(itos(binomialuu(h, m)))". The smallest * fundamental discriminant for which logbinom is not zero is * -1579751. */ logbinom = (m > 0 && m < h) ? LOG2E * (logfac(h) - logfac(m) - logfac(h - m)) : 0; avma = ltop; return res + logbinom - m * log2Mh + 2.0; } INLINE long distinct_inverses(const long f[], const long ef[], const long ei[], const long n[], const long o[], const long r[], long k, long L0, long i) { pari_sp av = avma; long j, *e2, *e3; if ( ! ef[i] || (L0 && ef[0])) return 0; for (j = i + 1; j < k; ++j) if (ef[j]) break; if (j < k) return 0; e2 = new_chunk(k); evec_copy(e2, ef, i); e2[i] = o[i] - ef[i]; for (j = i + 1; j < k; ++j) e2[j] = 0; evec_reduce(e2, n, r, k); if (evec_equal(ef, e2, k)) { avma = av; return 0; } e3 = new_chunk(k); evec_inverse_o(e3, ef, n, o, r, k); if (evec_equal(e2, e3, k)) { avma = av; return 0; } if (f) { evec_compose(e3, f, ei, n, r, k); if (evec_equal(e2, e3, k)) { avma = av; return 0; } evec_inverse_o(e3, e3, n, o, r, k); if (evec_equal(e2, e3, k)) { avma = av; return 0; } } avma = av; return 1; } INLINE long next_prime_evec(long *qq, long f[], const long m[], long k, hashtable *tbl, long D, GEN DD, long u, long lvl, long ubound) { pari_sp av = avma; hashentry *he; GEN P; long idx, q = *qq; do q = unextprime(q + 1); while (!(u % q) || kross(D, q) == -1 || !(lvl % q) || !(D % (q * q))); if (q > ubound) return 0; *qq = q; /* Get evec f corresponding to q */ P = redimag(primeform_u(DD, q)); he = hash_search(tbl, P); if (!he) pari_err_BUG("next_prime_evec"); idx = itos((GEN) he->val); index_to_evec(f, idx, m, k); avma = av; return 1; } /* Return 1 on success, 0 on failure. */ static int orient_pcp(classgp_pcp_t G, long *ni, long D, long u, hashtable *tbl) { pari_sp av = avma; /* 199 seems to suffice, but can be increased if necessary */ enum { MAX_ORIENT_P = 199 }; const long *L = G->L, *n = G->n, *r = G->r, *m = G->m, *o = G->o; long i, *ps = G->orient_p, *qs = G->orient_q, *reps = G->orient_reps; long *ef, *e, *ei, *f, k = G->k, lvl = modinv_level(G->inv); GEN DD = stoi(D); memset(ps, 0, k * sizeof(long)); memset(qs, 0, k * sizeof(long)); memset(reps, 0, k * k * sizeof(long)); for (i = 0; i < k; ++i) { ps[i] = -1; if (o[i] > 2) break; } for (++i; i < k; ++i) ps[i] = (o[i] > 2) ? 0 : -1; /* ps[i] = -!(o[i] > 2); */ e = new_chunk(k); ei = new_chunk(k); f = new_chunk(k); for (i = 0; i < k; ++i) { long p; if (ps[i]) continue; p = L[i]; ef = &reps[i * k]; while (!ps[i]) { if (!next_prime_evec(&p, ef, m, k, tbl, D, DD, u, lvl, MAX_ORIENT_P)) break; evec_inverse_o(ei, ef, n, o, r, k); if (!distinct_inverses(NULL, ef, ei, n, o, r, k, G->L0, i)) continue; ps[i] = p; qs[i] = 1; } if (ps[i]) continue; p = unextprime(L[i] + 1); while (!ps[i]) { long q; if (!next_prime_evec(&p, e, m, k, tbl, D, DD, u, lvl, MAX_ORIENT_P)) break; evec_inverse_o(ei, e, n, o, r, k); q = L[i]; while (!qs[i]) { if (!next_prime_evec(&q, f, m, k, tbl, D, DD, u, lvl, p - 1)) break; evec_compose(ef, e, f, n, r, k); if (!distinct_inverses(f, ef, ei, n, o, r, k, G->L0, i)) continue; ps[i] = p; qs[i] = q; } } if (!ps[i]) return 0; } if (ni) { GEN N = qfb_nform(D, *ni); hashentry *he = hash_search(tbl, N); if (!he) pari_err_BUG("orient_pcp"); *ni = itos((GEN) he->val); } avma = av; return 1; } /* We must avoid situations where L_i^{+/-2} = L_j^2 (or = L_0*L_j^2 * if ell0 flag is set), with |L_i| = |L_j| = 4 (or have 4th powers in * but not 2nd powers in ) and j < i */ /* These cases cause problems when enumerating roots via gcds */ /* returns the index of the first bad generator, or -1 if no bad * generators are found */ static long classgp_pcp_check_generators(const long *n, long *r, long k, long L0) { pari_sp av = avma; long *e1, i, i0, j, s; const long *ei; s = !!L0; e1 = new_chunk(k); for (i = s + 1; i < k; i++) { if (n[i] != 2) continue; ei = evec_ri(r, i); for (j = s; j < i; j++) if (ei[j]) break; if (j == i) continue; for (i0 = s; i0 < i; i0++) { if ((4 % n[i0])) continue; evec_clear(e1, k); e1[i0] = 4; evec_reduce(e1, n, r, k); for (j = s; j < i; j++) if (e1[j]) break; if (j < i) continue; /* L_i0^4 is not trivial or in */ evec_clear(e1, k); e1[i0] = 2; evec_reduce(e1, n, r, k); /* compute L_i0^2 */ for (j = s; j < i; j++) if (e1[j] != ei[j]) break; if (j == i) return i; evec_inverse(e1, e1, n, r, k); /* compute L_i0^{-2} */ for (j = s; j < i; j++) if (e1[j] != ei[j]) break; if (j == i) return i; } } avma = av; return -1; } static void pcp_alloc_and_set( classgp_pcp_t G, const long *L, const long *n, const long *r, long k) { /* classgp_pcp contains 6 arrays of length k (L, m, n, o, orient_p, orient_q), * one of length binom(k, 2) (r) and one of length k^2 (orient_reps) */ long rlen = k * (k - 1) / 2, datalen = 6 * k + rlen + k * k; G->_data = newblock(datalen); G->L = G->_data; G->m = G->L + k; G->n = G->m + k; G->o = G->n + k; G->r = G->o + k; G->orient_p = G->r + rlen; G->orient_q = G->orient_p + k; G->orient_reps = G->orient_q + k; G->k = k; evec_copy(G->L, L, k); evec_copy(G->n, n, k); evec_copy(G->r, r, rlen); evec_orders(G->o, n, r, k); evec_n_to_m(G->m, n, k); } static void classgp_pcp_clear(classgp_pcp_t G) { if (G->_data) killblock(G->_data); } /* This is Sutherland 2009, Algorithm 2.2 (p16). */ static void classgp_make_pcp( classgp_pcp_t G, double *height, long *ni, long h, long D, ulong u, long inv, long Lfilter, long orient) { enum { MAX_GENS = 16, MAX_RLEN = MAX_GENS * (MAX_GENS - 1) / 2 }; pari_sp av = avma, bv; long curr_p, h2, nelts, lvl = modinv_level(inv); GEN DD, ident, T, v; hashtable *tbl; long i, L1, L2; long k, L[MAX_GENS], n[MAX_GENS], r[MAX_RLEN]; memset(G, 0, sizeof *G); G->D = D; G->h = h; G->inv = inv; G->L0 = (modinv_is_double_eta(inv) && modinv_ramified(D, inv)) ? modinv_degree(NULL, NULL, inv) : 0; G->enum_cnt = h / (1 + !!G->L0); G->Lfilter = ulcm(Lfilter, lvl); if (h == 1) { if (G->L0) pari_err_BUG("classgp_pcp"); G->k = 0; G->_data = NULL; v = const_vecsmall(1, 1); *height = upper_bound_on_classpoly_coeffs(D, h, v); /* NB: No need to set *ni when h = 1 */ avma = av; return; } DD = stoi(D); bv = avma; while (1) { k = 0; /* Hash table has a QFI as a key and the (boxed) index of that QFI * in T as its value */ tbl = hash_create(h, (ulong(*)(void*)) hash_GEN, (int(*)(void*,void*))&gequal, 1); ident = redimag(primeform_u(DD, 1)); hash_insert(tbl, ident, gen_0); T = vectrunc_init(h + 1); vectrunc_append(T, ident); nelts = 1; curr_p = 1; while (nelts < h) { GEN gamma_i, beta; hashentry *e; long N = glength(T), Tlen = N, ri = 1; if (k == MAX_GENS) pari_err_IMPL("classgp_pcp"); if (nelts == 1 && G->L0) { curr_p = G->L0; gamma_i = qfb_nform(D, curr_p); beta = redimag(gamma_i); if (equali1(gel(beta, 1))) { curr_p = 1; gamma_i = next_generator(DD, D, u, G->Lfilter, &beta, &curr_p); } } else gamma_i = next_generator(DD, D, u, G->Lfilter, &beta, &curr_p); while ((e = hash_search(tbl, beta)) == NULL) { long j; for (j = 1; j <= N; ++j) { GEN t = qficomp(beta, gel(T, j)); vectrunc_append(T, t); hash_insert(tbl, t, stoi(Tlen++)); } beta = qficomp(beta, gamma_i); ++ri; } if (ri > 1) { long j, si; L[k] = curr_p; n[k] = ri; nelts *= ri; /* This is to reset the curr_p counter when we have G->L0 != 0 * in the first position of L. */ if (curr_p == G->L0) curr_p = 1; N = 1; si = itos((GEN) e->val); for (j = 0; j < k; ++j) { evec_ri_mutate(r, k)[j] = (si / N) % n[j]; N *= n[j]; } ++k; } } if ((i = classgp_pcp_check_generators(n, r, k, G->L0)) < 0) { pcp_alloc_and_set(G, L, n, r, k); if (!orient || orient_pcp(G, ni, D, u, tbl)) break; G->Lfilter *= G->L[0]; classgp_pcp_clear(G); } else if (log2(G->Lfilter) + log2(L[i]) >= BITS_IN_LONG) pari_err_IMPL("classgp_pcp"); else G->Lfilter *= L[i]; avma = bv; } v = cgetg(h + 1, t_VECSMALL); v[1] = 1; for (i = 2; i <= h; ++i) uel(v,i) = itou(gmael(T,i,1)); h2 = G->L0 ? h / 2 : h; *height = upper_bound_on_classpoly_coeffs(D, h2, v); /* The norms of the last one or two generators. */ L1 = L[k - 1]; L2 = k > 1 ? L[k - 2] : 1; /* 4 * L1^2 * L2^2 must fit in a ulong */ if (2 * (1 + log2(L1) + log2(L2)) >= BITS_IN_LONG) pari_err_IMPL("classgp_pcp"); if (G->L0 && (G->L[0] != G->L0 || G->o[0] != 2)) pari_err_BUG("classgp_pcp"); avma = av; return; } INLINE ulong classno_wrapper(long D) { pari_sp av = avma; GEN clsgp = quadclassunit0(stoi(D), 0, NULL, DEFAULTPREC); ulong h = itou(gel(clsgp, 1)); avma = av; return h; } /* * SECTION: Functions for calculating class polynomials. */ /* NB: Sutherland defines V_MAX to be 1200 with saying why. */ #define V_MAX 1200 #define NSMALL_PRIMES 11 static const long SMALL_PRIMES[11] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 }; static long is_smooth_enough(ulong *factors, long v) { long i; *factors = 0; for (i = 0; i < NSMALL_PRIMES; ++i) { long p = SMALL_PRIMES[i]; if (v % p == 0) *factors |= 1UL << i; while (v % p == 0) v /= p; if (v == 1) break; } return v == 1; } /* Hurwitz class number of |D| assuming hclassno() and attached * conversion to double costs much more than unegisfundamental(). */ INLINE double hclassno_wrapper(long D, long h) { /* TODO: Can probably calculate hurwitz faster using -D, factor(u) * and classno(D). */ pari_sp av = avma; ulong abs_D = D < 0 ? -D : D; double hurwitz; if (h && unegisfundamental(abs_D)) hurwitz = (double) h; else hurwitz = rtodbl(gtofp(hclassno(utoi(abs_D)), DEFAULTPREC)); avma = av; return hurwitz; } /* This is Sutherland 2009, Algorithm 2.1 (p8). * NB: This function is not gerepileupto-safe. */ static GEN select_classpoly_prime_pool( double min_prime_bits, double delta, classgp_pcp_t G) { pari_sp av; double prime_bits = 0.0, hurwitz, z; ulong i; /* t_min[v] will hold the lower bound of the t we need to look at * for a given v. */ ulong t_min[V_MAX], t_size_lim; GEN res; long D = G->D, inv = G->inv; if (delta <= 0) pari_err_BUG("select_suitable_primes"); hurwitz = hclassno_wrapper(D, G->h); res = cgetg(1, t_VEC); /* Initialise t_min to be all 2's. This avoids trace 0 and trace 1 curves */ for (i = 0; i < V_MAX; ++i) t_min[i] = 2; /* maximum possible trace = sqrt(2^BIL - D) */ t_size_lim = 2.0 * sqrt((double)((1UL << (BITS_IN_LONG - 2)) - (((ulong)-D) >> 2))); av = avma; for (z = -D / (2.0 * hurwitz); ; z *= delta + 1.0) { /* v_bound_aux = -4 z H(-D). */ double v_bound_aux = -4.0 * z * hurwitz; ulong v; dbg_printf(1)("z = %.2f\n", z); for (v = 1; ; ++v) { ulong pcount = 0, t, t_max, vfactors; ulong m_vsqr_D = v * v * (ulong)(-D); /* hurwitz_ratio_bound = 11 * log(log(v + 4))^2 */ double hurwitz_ratio_bound = log(log(v + 4.0)), max_p, H; hurwitz_ratio_bound *= 11.0 * hurwitz_ratio_bound; if (v >= v_bound_aux * hurwitz_ratio_bound / D || v >= V_MAX) break; if ( ! is_smooth_enough(&vfactors, v)) continue; H = hclassno_wrapper(m_vsqr_D, 0); /* t <= 2 sqrt(p) and p <= z H(-v^2 D) and * * H(-v^2 D) < vH(-D) (11 log(log(v + 4))^2) * * This last term is v * hurwitz * hurwitz_ratio_bound. */ max_p = z * v * hurwitz * hurwitz_ratio_bound; t_max = 2.0 * mindd(sqrt((double)((1UL << (BITS_IN_LONG - 2)) - (m_vsqr_D >> 2))), sqrt(max_p)); for (t = t_min[v]; t <= t_max; ++t) { ulong possible_4p = t * t + m_vsqr_D; if (possible_4p % 4 == 0) { ulong possible_p = possible_4p / 4; if (uisprime(possible_p) && modinv_good_prime(inv, possible_p)) { long p = possible_p; double rho_inv = p / H; GEN hit; hit = mkvecsmall5(p, t, v, (long)rho_inv, vfactors); /* FIXME: Avoid doing GC for every prime as here. */ res = gerepileupto(av, gconcat(res, hit)); prime_bits += log2(p); ++pcount; } } } t_min[v] = t_max + 1; if (pcount) { dbg_printf(2)(" Found %lu primes for v = %lu.\n", pcount, v); if (gc_needed(av, 2)) res = gerepilecopy(av, res); } if (prime_bits > min_prime_bits) { dbg_printf(1)("Found %ld primes; total size %.2f bits.\n", glength(res), prime_bits); return gerepilecopy(av, res); } } /* Have we exhausted all possible solutions that fit in machine words? */ if (t_min[1] >= t_size_lim) { char *err = stack_sprintf("class polynomial of discriminant %ld", D); pari_err(e_ARCH, err); } } } INLINE int cmp_small(long a, long b) { return a>b? 1: (aD, inv = G->inv; ulong biggest_p; double prime_bits, min_prime_bits, b; GEN prime_pool; if (k < 2) pari_err_BUG("select_suitable_primes"); s = modinv_height_factor(inv); b = height / s + height_margin(inv, D); dbg_printf(1)("adjusted height = %.2f\n", b); min_prime_bits = k * b; prime_pool = select_classpoly_prime_pool(min_prime_bits, delta, G); /* FIXME: Apply torsion constraints */ /* FIXME: Rank elts of res according to cost/benefit ratio */ gen_sort_inplace(prime_pool, NULL, primecmp, NULL); prime_bits = 0.0; biggest_p = gel(prime_pool, 1)[1]; *biggest_v = gel(prime_pool, 1)[3]; *vfactors = 0; for (i = 1; i < lg(prime_pool); ++i) { ulong p = gel(prime_pool, i)[1]; ulong v = gel(prime_pool, i)[3]; prime_bits += log2(p); *vfactors |= gel(prime_pool, i)[5]; if (p > biggest_p) biggest_p = p; if (v > *biggest_v) *biggest_v = v; if (prime_bits > b) break; } dbg_printf(1)("Selected %ld primes; largest is %lu ~ 2^%.2f\n", i, biggest_p, log2(biggest_p)); return gerepilecopy(av, vecslice0(prime_pool, 1, i)); } /* This is Sutherland 2009 Algorithm 1.2. */ static long oneroot_of_classpoly( ulong *j_endo, int *endo_cert, ulong j, norm_eqn_t ne, GEN jdb) { pari_sp av = avma; long nfactors, L_bound, i; ulong p = ne->p, pi = ne->pi; GEN factw, factors, u_levels, vdepths; if (j == 0 || j == 1728 % p) pari_err_BUG("oneroot_of_classpoly"); *endo_cert = 1; if (ne->u * ne->v == 1) { *j_endo = j; return 1; } /* TODO: Precalculate all this data further up */ factw = factoru(ne->u * ne->v); factors = gel(factw, 1); nfactors = lg(factors) - 1; u_levels = cgetg(nfactors + 1, t_VECSMALL); for (i = 1; i <= nfactors; ++i) u_levels[i] = z_lval(ne->u, gel(factw, 1)[i]); vdepths = gel(factw, 2); /* FIXME: This should be bigger */ L_bound = maxdd(log((double) -ne->D), (double)ne->v); /* Iterate over the primes L dividing w */ for (i = 1; i <= nfactors; ++i) { pari_sp bv = avma; GEN phi; long jlvl, lvl_diff, depth = vdepths[i]; long L = factors[i]; if (L > L_bound) { *endo_cert = 0; break; } phi = polmodular_db_getp(jdb, L, p); /* TODO: See if I can reuse paths created in j_level_in_volcano() * later in {ascend,descend}_volcano(), perhaps by combining the * functions into one "adjust_level" function. */ jlvl = j_level_in_volcano(phi, j, p, pi, L, depth); lvl_diff = u_levels[i] - jlvl; if (lvl_diff < 0) /* j's level is less than v(u) so we must ascend */ j = ascend_volcano(phi, j, p, pi, jlvl, L, depth, -lvl_diff); else if (lvl_diff > 0) /* otherwise j's level is greater than v(u) so we descend */ j = descend_volcano(phi, j, p, pi, jlvl, L, depth, lvl_diff); avma = bv; } avma = av; /* At this point the probability that j has the wrong endomorphism * ring is about \sum_{p|u_compl} 1/p (and u_compl must be bigger * than L_bound, so pretty big), so just return it and rely on * detection code in enum_j_with_endo_ring(). Detection is that we * hit a previously found j-invariant earlier than expected. OR, we * evaluate class polynomials of the suborders at j and if any are * zero then j must be chosen again. */ *j_endo = j; return j != 0 && j != 1728 % p; } INLINE long vecsmall_isin_skip(GEN v, long x, long k) { long i, l = lg(v); for (i = k; i < l; ++i) if (v[i] == x) return i; return 0; } INLINE ulong select_twisting_param(ulong p) { ulong T; do T = random_Fl(p); while (krouu(T, p) != -1); return T; } INLINE void setup_norm_eqn(norm_eqn_t ne, long D, long u, GEN norm_eqn) { ne->D = D; ne->u = u; ne->t = norm_eqn[2]; ne->v = norm_eqn[3]; ne->p = (ulong) norm_eqn[1]; ne->pi = get_Fl_red(ne->p); ne->s2 = Fl_2gener_pre(ne->p, ne->pi); ne->T = select_twisting_param(ne->p); } INLINE ulong Flv_powsum_pre(GEN v, ulong n, ulong p, ulong pi) { long i, l = lg(v); ulong psum = 0; for (i = 1; i < l; ++i) psum = Fl_add(psum, Fl_powu_pre(uel(v,i), n, p, pi), p); return psum; } INLINE int modinv_has_sign_ambiguity(long inv) { switch (inv) { case INV_F: case INV_F3: case INV_W2W3E2: case INV_W2W7E2: case INV_W2W3: case INV_W2W5: case INV_W2W7: case INV_W3W3: case INV_W2W13: case INV_W3W7: return 1; } return 0; } INLINE int modinv_units(int inv) { return modinv_is_double_eta(inv) || modinv_is_Weber(inv); } INLINE int adjust_signs(GEN js, ulong p, ulong pi, long inv, GEN T, long e) { long negate = 0; long h = lg(js) - 1; if ((h & 1) && modinv_units(inv)) { ulong prod = Flv_prod_pre(js, p, pi); if (prod != p - 1) { if (prod != 1) pari_err_BUG("adjust_signs: constant term is not +/-1"); negate = 1; } } else { ulong tp, t; tp = umodiu(T, p); t = Flv_powsum_pre(js, e, p, pi); if (t == 0) return 0; if (t != tp) { if (Fl_neg(t, p) != tp) pari_err_BUG("adjust_signs: incorrect trace"); negate = 1; } } if (negate) Flv_neg_inplace(js, p); return 1; } static ulong find_jinv( long *trace_tries, long *endo_tries, int *cert, norm_eqn_t ne, long inv, long rho_inv, GEN jdb) { long found, ok = 1; ulong j, r; do { do { long tries; ulong j_t = 0; /* TODO: Set batch size according to expected number of tries and * experimental cost/benefit analysis. */ tries = find_j_inv_with_given_trace(&j_t, ne, rho_inv, 0); if (j_t == 0) pari_err_BUG("polclass0: Couldn't find j-invariant with given trace."); dbg_printf(2)(" j-invariant %ld has trace +/-%ld (%ld tries, 1/rho = %ld)\n", j_t, ne->t, tries, rho_inv); *trace_tries += tries; found = oneroot_of_classpoly(&j, cert, j_t, ne, jdb); ++*endo_tries; } while (!found); if (modinv_is_double_eta(inv)) ok = modfn_unambiguous_root(&r, inv, j, ne, jdb); else r = modfn_root(j, ne, inv); } while (!ok); return r; } static GEN polclass_roots_modp( long *n_trace_curves, norm_eqn_t ne, long rho_inv, classgp_pcp_t G, GEN db) { pari_sp av = avma; ulong j = 0; long inv = G->inv, endo_tries = 0; int endo_cert; GEN res, jdb, fdb; jdb = polmodular_db_for_inv(db, INV_J); fdb = polmodular_db_for_inv(db, inv); dbg_printf(2)("p = %ld, t = %ld, v = %ld\n", ne->p, ne->t, ne->v); do { j = find_jinv(n_trace_curves, &endo_tries, &endo_cert, ne, inv, rho_inv, jdb); res = enum_roots(j, ne, fdb, G); if ( ! res && endo_cert) pari_err_BUG("polclass_roots_modp"); if (res && ! endo_cert && vecsmall_isin_skip(res, res[1], 2)) { avma = av; res = NULL; } } while (!res); dbg_printf(2)(" j-invariant %ld has correct endomorphism ring " "(%ld tries)\n", j, endo_tries); dbg_printf(4)(" all such j-invariants: %Ps\n", res); return gerepileupto(av, res); } INLINE int modinv_inverted_involution(long inv) { return modinv_is_double_eta(inv); } INLINE int modinv_negated_involution(long inv) { /* determined by trial and error */ return inv == INV_F || inv == INV_W3W5 || inv == INV_W3W7 || inv == INV_W3W3 || inv == INV_W5W7; } /* Return true iff Phi_L(j0, j1) = 0. */ INLINE long verify_edge(ulong j0, ulong j1, ulong p, ulong pi, long L, GEN fdb) { pari_sp av = avma; GEN phi = polmodular_db_getp(fdb, L, p); GEN f = Flm_Fl_polmodular_evalx(phi, L, j1, p, pi); ulong r = Flx_eval_pre(f, j0, p, pi); avma = av; return !r; } INLINE long verify_2path( ulong j1, ulong j2, ulong p, ulong pi, long L1, long L2, GEN fdb) { pari_sp av = avma; GEN phi1 = polmodular_db_getp(fdb, L1, p); GEN phi2 = polmodular_db_getp(fdb, L2, p); GEN f = Flm_Fl_polmodular_evalx(phi1, L1, j1, p, pi); GEN g = Flm_Fl_polmodular_evalx(phi2, L2, j2, p, pi); GEN d = Flx_gcd(f, g, p); long n = degpol(d); if (n >= 2) n = Flx_nbroots(d, p); avma = av; return n; } static long oriented_n_action( const long *ni, classgp_pcp_t G, GEN v, ulong p, ulong pi, GEN fdb) { pari_sp av = avma; long i, j, k = G->k; long nr = k * (k - 1) / 2; const long *n = G->n, *m = G->m, *o = G->o, *r = G->r, *ps = G->orient_p, *qs = G->orient_q, *reps = G->orient_reps; long *signs = new_chunk(k); long *e = new_chunk(k); long *rels = new_chunk(nr); evec_copy(rels, r, nr); for (i = 0; i < k; ++i) { /* If generator doesn't require orientation, continue; power rels already * copied to *rels in initialisation */ if (ps[i] <= 0) { signs[i] = 1; continue; } /* Get rep of orientation element and express it in terms of the * (partially) oriented presentation */ for (j = 0; j < i; ++j) { long t = reps[i * k + j]; e[j] = (signs[j] < 0 ? o[j] - t : t); } e[j] = reps[i * k + j]; for (++j; j < k; ++j) e[j] = 0; evec_reduce(e, n, rels, k); j = evec_to_index(e, m, k); /* FIXME: These calls to verify_edge recalculate powers of v[0] * and v[j] over and over again, they also reduce Phi_{ps[i]} modulo p over * and over again. Need to cache these things! */ if (qs[i] > 1) signs[i] = (verify_2path(uel(v,1), uel(v,j+1), p, pi, ps[i], qs[i], fdb) ? 1 : -1); else /* Verify ps[i]-edge to orient ith generator */ signs[i] = (verify_edge(uel(v,1), uel(v,j+1), p, pi, ps[i], fdb) ? 1 : -1); /* Update power relation */ for (j = 0; j < i; ++j) { long t = evec_ri(r, i)[j]; e[j] = (signs[i] * signs[j] < 0 ? o[j] - t : t); } while (j < k) e[j++] = 0; evec_reduce(e, n, rels, k); for (j = 0; j < i; ++j) evec_ri_mutate(rels, i)[j] = e[j]; /* TODO: This is a sanity check, can be removed if everything is working */ for (j = 0; j <= i; ++j) { long t = reps[i * k + j]; e[j] = (signs[j] < 0 ? o[j] - t : t); } while (j < k) e[j++] = 0; evec_reduce(e, n, rels, k); j = evec_to_index(e, m, k); if (qs[i] > 1) { if (!verify_2path(uel(v,1), uel(v, j+1), p, pi, ps[i], qs[i], fdb)) pari_err_BUG("oriented_n_action"); } else { if (!verify_edge(uel(v,1), uel(v, j+1), p, pi, ps[i], fdb)) pari_err_BUG("oriented_n_action"); } } /* Orient representation of [N] relative to the torsor */ for (i = 0; i < k; ++i) e[i] = (signs[i] < 0 ? o[i] - ni[i] : ni[i]); evec_reduce(e, n, rels, k); avma = av; return evec_to_index(e, m, k); } /* F = double_eta_raw(inv) */ INLINE void adjust_orientation(GEN F, long inv, GEN v, long e, ulong p, ulong pi) { ulong j0 = uel(v, 1), je = uel(v, e); if (!modinv_j_from_2double_eta(F, inv, NULL, j0, je, p, pi)) { if (modinv_inverted_involution(inv)) Flv_inv_pre_inplace(v, p, pi); if (modinv_negated_involution(inv)) Flv_neg_inplace(v, p); } } static void polclass_psum( GEN *psum, long *d, GEN roots, GEN primes, GEN pilist, ulong h, long inv) { /* Number of consecutive CRT stabilisations before we assume we have * the correct answer. */ enum { MIN_STAB_CNT = 3 }; pari_sp av = avma, btop; GEN ps, psum_sqr, P; long i, e, stabcnt, nprimes = lg(primes) - 1; if ((h & 1) && modinv_units(inv)) { *psum = gen_1; *d = 0; return; } e = -1; ps = cgetg(nprimes+1, t_VECSMALL); do { e += 2; for (i = 1; i <= nprimes; ++i) { GEN roots_modp = gel(roots, i); ulong p = uel(primes, i), pi = uel(pilist, i); uel(ps, i) = Flv_powsum_pre(roots_modp, e, p, pi); } btop = avma; psum_sqr = Z_init_CRT(0, 1); P = gen_1; for (i = 1, stabcnt = 0; stabcnt < MIN_STAB_CNT && i <= nprimes; ++i) { ulong p = uel(primes, i), pi = uel(pilist, i); ulong ps2 = Fl_sqr_pre(uel(ps, i), p, pi); ulong stab = Z_incremental_CRT(&psum_sqr, ps2, &P, p); /* stabcnt = stab * (stabcnt + 1) */ if (stab) ++stabcnt; else stabcnt = 0; if (gc_needed(av, 2)) gerepileall(btop, 2, &psum_sqr, &P); } if (stabcnt == 0 && nprimes >= MIN_STAB_CNT) pari_err_BUG("polclass_psum"); } while (!signe(psum_sqr)); if ( ! Z_issquareall(psum_sqr, psum)) pari_err_BUG("polclass_psum"); dbg_printf(1)("Classpoly power sum (e = %ld) is %Ps; found with %.2f%% of the primes\n", e, *psum, 100 * (i - 1) / (double) nprimes); *psum = gerepileupto(av, *psum); *d = e; } static GEN polclass_small_disc(long D, long inv, long xvar) { if (D == -3) return pol_x(xvar); if (D == -4) { switch (inv) { case INV_J: return deg1pol(gen_1, stoi(-1728), xvar); case INV_G2:return deg1pol(gen_1, stoi(-12), xvar); default: /* no other invariants for which we can calculate H_{-4}(X) */ pari_err_BUG("polclass_small_disc"); } } return NULL; } GEN polclass0(long D, long inv, long xvar, GEN *db) { pari_sp av = avma; GEN primes; long n_curves_tested = 0; long nprimes, s, i, j, del, ni, orient; GEN P, H, plist, pilist; ulong u, L, maxL, vfactors, biggest_v; long h, p1, p2, filter = 1; classgp_pcp_t G; double height; static const long k = 2; static const double delta = 0.5; if (D >= -4) return polclass_small_disc(D, inv, xvar); (void) corediscs(D, &u); h = classno_wrapper(D); dbg_printf(1)("D = %ld, conductor = %ld, inv = %ld\n", D, u, inv); ni = modinv_degree(&p1, &p2, inv); orient = modinv_is_double_eta(inv) && kross(D, p1) && kross(D, p2); classgp_make_pcp(G, &height, &ni, h, D, u, inv, filter, orient); primes = select_classpoly_primes(&vfactors, &biggest_v, k, delta, G, height); /* Prepopulate *db with all the modpolys we might need */ /* TODO: Clean this up; in particular, note that u is factored later on. */ /* This comes from L_bound in oneroot_of_classpoly() above */ maxL = maxdd(log((double) -D), (double)biggest_v); if (u > 1) { for (L = 2; L <= maxL; L = unextprime(L + 1)) if (!(u % L)) polmodular_db_add_level(db, L, INV_J); } for (i = 0; vfactors; ++i) { if (vfactors & 1UL) polmodular_db_add_level(db, SMALL_PRIMES[i], INV_J); vfactors >>= 1; } if (p1 > 1) polmodular_db_add_level(db, p1, INV_J); if (p2 > 1) polmodular_db_add_level(db, p2, INV_J); s = !!G->L0; polmodular_db_add_levels(db, G->L + s, G->k - s, inv); if (orient) { for (i = 0; i < G->k; ++i) { if (G->orient_p[i] > 1) polmodular_db_add_level(db, G->orient_p[i], inv); if (G->orient_q[i] > 1) polmodular_db_add_level(db, G->orient_q[i], inv); } } nprimes = lg(primes) - 1; H = cgetg(nprimes + 1, t_VEC); plist = cgetg(nprimes + 1, t_VECSMALL); pilist = cgetg(nprimes + 1, t_VECSMALL); for (i = 1; i <= nprimes; ++i) { long rho_inv = gel(primes, i)[4]; norm_eqn_t ne; setup_norm_eqn(ne, D, u, gel(primes, i)); gel(H, i) = polclass_roots_modp(&n_curves_tested, ne, rho_inv, G, *db); uel(plist, i) = ne->p; uel(pilist, i) = ne->pi; if (DEBUGLEVEL>2 && (i & 3L)==0) err_printf(" %ld%%", i*100/nprimes); } dbg_printf(0)("\n"); if (orient) { GEN nvec = new_chunk(G->k); GEN fdb = polmodular_db_for_inv(*db, inv); GEN F = double_eta_raw(inv); index_to_evec((long *)nvec, ni, G->m, G->k); for (i = 1; i <= nprimes; ++i) { GEN v = gel(H, i); ulong p = uel(plist, i), pi = uel(pilist, i); long oni = oriented_n_action(nvec, G, v, p, pi, fdb); adjust_orientation(F, inv, v, oni + 1, p, pi); } } if (modinv_has_sign_ambiguity(inv)) { GEN psum; long e; polclass_psum(&psum, &e, H, plist, pilist, h, inv); for (i = 1; i <= nprimes; ++i) { GEN v = gel(H, i); ulong p = uel(plist, i), pi = uel(pilist, i); if (!adjust_signs(v, p, pi, inv, psum, e)) uel(plist, i) = 0; } } for (i = 1, j = 1, del = 0; i <= nprimes; ++i) { GEN v = gel(H, i), pol; ulong p = uel(plist, i); if (!p) { del++; continue; } pol = Flv_roots_to_pol(v, p, xvar); uel(plist, j) = p; gel(H, j++) = Flx_to_Flv(pol, lg(pol) - 2); } setlg(H,nprimes+1-del); setlg(plist,nprimes+1-del); classgp_pcp_clear(G); dbg_printf(1)("Total number of curves tested: %ld\n", n_curves_tested); H = ncV_chinese_center(H, plist, &P); dbg_printf(1)("Result height: %.2f\n", dbllog2r(itor(gsupnorm(H, DEFAULTPREC), DEFAULTPREC))); return gerepilecopy(av, RgV_to_RgX(H, xvar)); } void check_modinv(long inv) { switch (inv) { case INV_J: case INV_F: case INV_F2: case INV_F3: case INV_F4: case INV_G2: case INV_W2W3: case INV_F8: case INV_W3W3: case INV_W2W5: case INV_W2W7: case INV_W3W5: case INV_W3W7: case INV_W2W3E2: case INV_W2W5E2: case INV_W2W13: case INV_W2W7E2: case INV_W3W3E2: case INV_W5W7: case INV_W3W13: break; default: pari_err_DOMAIN("polmodular", "inv", "invalid invariant", stoi(inv), gen_0); } } GEN polclass(GEN DD, long inv, long xvar) { GEN db, H; long dummy, D; if (xvar < 0) xvar = 0; check_quaddisc_imag(DD, &dummy, "polclass"); check_modinv(inv); D = itos(DD); if (!modinv_good_disc(inv, D)) pari_err_DOMAIN("polclass", "D", "incompatible with given invariant", stoi(inv), DD); db = polmodular_db_init(inv); H = polclass0(D, inv, xvar, &db); gunclone_deep(db); return H; } pari-2.11.2/src/basemath/base3.c0000644000175000017500000023571213447371554014721 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* BASIC NF OPERATIONS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* OPERATIONS OVER NUMBER FIELD ELEMENTS. */ /* represented as column vectors over the integral basis */ /* */ /*******************************************************************/ static GEN get_tab(GEN nf, long *N) { GEN tab = (typ(nf) == t_MAT)? nf: gel(nf,9); *N = nbrows(tab); return tab; } /* x != 0, y t_INT. Return x * y (not memory clean if x = 1) */ static GEN _mulii(GEN x, GEN y) { return is_pm1(x)? (signe(x) < 0)? negi(y): y : mulii(x, y); } GEN tablemul_ei_ej(GEN M, long i, long j) { long N; GEN tab = get_tab(M, &N); tab += (i-1)*N; return gel(tab,j); } /* Outputs x.ei, where ei is the i-th elt of the algebra basis. * x an RgV of correct length and arbitrary content (polynomials, scalars...). * M is the multiplication table ei ej = sum_k M_k^(i,j) ek */ GEN tablemul_ei(GEN M, GEN x, long i) { long j, k, N; GEN v, tab; if (i==1) return gcopy(x); tab = get_tab(M, &N); if (typ(x) != t_COL) { v = zerocol(N); gel(v,i) = gcopy(x); return v; } tab += (i-1)*N; v = cgetg(N+1,t_COL); /* wi . x = [ sum_j tab[k,j] x[j] ]_k */ for (k=1; k<=N; k++) { pari_sp av = avma; GEN s = gen_0; for (j=1; j<=N; j++) { GEN c = gcoeff(tab,k,j); if (!gequal0(c)) s = gadd(s, gmul(c, gel(x,j))); } gel(v,k) = gerepileupto(av,s); } return v; } /* as tablemul_ei, assume x a ZV of correct length */ GEN zk_ei_mul(GEN nf, GEN x, long i) { long j, k, N; GEN v, tab; if (i==1) return ZC_copy(x); tab = get_tab(nf, &N); tab += (i-1)*N; v = cgetg(N+1,t_COL); for (k=1; k<=N; k++) { pari_sp av = avma; GEN s = gen_0; for (j=1; j<=N; j++) { GEN c = gcoeff(tab,k,j); if (signe(c)) s = addii(s, _mulii(c, gel(x,j))); } gel(v,k) = gerepileuptoint(av, s); } return v; } /* table of multiplication by wi in R[w1,..., wN] */ GEN ei_multable(GEN TAB, long i) { long k,N; GEN m, tab = get_tab(TAB, &N); tab += (i-1)*N; m = cgetg(N+1,t_MAT); for (k=1; k<=N; k++) gel(m,k) = gel(tab,k); return m; } GEN zk_multable(GEN nf, GEN x) { long i, l = lg(x); GEN mul = cgetg(l,t_MAT); gel(mul,1) = x; /* assume w_1 = 1 */ for (i=2; i 0? leafcopy(v): RgC_neg(v); } l = lg(v); y = cgetg(l, t_COL); for (i=1; i < l; i++) { GEN c = gel(v,i); if (typ(c) != t_COL) c = gmul(c, x); else c = RgC_Rg_mul(c, x); gel(y,i) = c; } return y; } else { GEN dx; x = zk_multable(nf, Q_remove_denom(x,&dx)); y = nfC_multable_mul(v, x); return dx? RgC_Rg_div(y, dx): y; } } static GEN mulbytab(GEN M, GEN c) { return typ(c) == t_COL? RgM_RgC_mul(M,c): RgC_Rg_mul(gel(M,1), c); } GEN tablemulvec(GEN M, GEN x, GEN v) { long l, i; GEN y; if (typ(x) == t_COL && RgV_isscalar(x)) { x = gel(x,1); return typ(v) == t_POL? RgX_Rg_mul(v,x): RgV_Rg_mul(v,x); } x = multable(M, x); /* multiplication table by x */ y = cgetg_copy(v, &l); if (typ(v) == t_POL) { y[1] = v[1]; for (i=2; i < l; i++) gel(y,i) = mulbytab(x, gel(v,i)); y = normalizepol(y); } else { for (i=1; i < l; i++) gel(y,i) = mulbytab(x, gel(v,i)); } return y; } GEN zkmultable_capZ(GEN mx) { return Q_denom(zkmultable_inv(mx)); } GEN zkmultable_inv(GEN mx) { return ZM_gauss(mx, col_ei(lg(mx)-1,1)); } /* nf a true nf, x a ZC */ GEN zk_inv(GEN nf, GEN x) { return zkmultable_inv(zk_multable(nf,x)); } /* inverse of x in nf */ GEN nfinv(GEN nf, GEN x) { pari_sp av = avma; GEN z; nf = checknf(nf); x = nf_to_scalar_or_basis(nf, x); if (typ(x) == t_COL) { GEN d; x = Q_remove_denom(x, &d); z = zk_inv(nf, x); if (d) z = RgC_Rg_mul(z, d); } else z = ginv(x); return gerepileupto(av, z); } /* quotient of x and y in nf */ GEN nfdiv(GEN nf, GEN x, GEN y) { pari_sp av = avma; GEN z; nf = checknf(nf); y = nf_to_scalar_or_basis(nf, y); if (typ(y) != t_COL) { x = nf_to_scalar_or_basis(nf, x); z = (typ(x) == t_COL)? RgC_Rg_div(x, y): gdiv(x,y); } else { GEN d; y = Q_remove_denom(y, &d); z = nfmul(nf, x, zk_inv(nf,y)); if (d) z = RgC_Rg_mul(z, d); } return gerepileupto(av, z); } /* product of INTEGERS (t_INT or ZC) x and y in nf * compute xy as ( sum_i x_i sum_j y_j m^{i,j}_k )_k */ GEN nfmuli(GEN nf, GEN x, GEN y) { long i, j, k, N; GEN s, v, TAB = get_tab(nf, &N); if (typ(x) == t_INT) return (typ(y) == t_COL)? ZC_Z_mul(y, x): mulii(x,y); if (typ(y) == t_INT) return ZC_Z_mul(x, y); /* both x and y are ZV */ v = cgetg(N+1,t_COL); for (k=1; k<=N; k++) { pari_sp av = avma; GEN TABi = TAB; if (k == 1) s = mulii(gel(x,1),gel(y,1)); else s = addii(mulii(gel(x,1),gel(y,k)), mulii(gel(x,k),gel(y,1))); for (i=2; i<=N; i++) { GEN t, xi = gel(x,i); TABi += N; if (!signe(xi)) continue; t = NULL; for (j=2; j<=N; j++) { GEN p1, c = gcoeff(TABi, k, j); /* m^{i,j}_k */ if (!signe(c)) continue; p1 = _mulii(c, gel(y,j)); t = t? addii(t, p1): p1; } if (t) s = addii(s, mulii(xi, t)); } gel(v,k) = gerepileuptoint(av,s); } return v; } /* square of INTEGER (t_INT or ZC) x in nf */ GEN nfsqri(GEN nf, GEN x) { long i, j, k, N; GEN s, v, TAB = get_tab(nf, &N); if (typ(x) == t_INT) return sqri(x); v = cgetg(N+1,t_COL); for (k=1; k<=N; k++) { pari_sp av = avma; GEN TABi = TAB; if (k == 1) s = sqri(gel(x,1)); else s = shifti(mulii(gel(x,1),gel(x,k)), 1); for (i=2; i<=N; i++) { GEN p1, c, t, xi = gel(x,i); TABi += N; if (!signe(xi)) continue; c = gcoeff(TABi, k, i); t = signe(c)? _mulii(c,xi): NULL; for (j=i+1; j<=N; j++) { c = gcoeff(TABi, k, j); if (!signe(c)) continue; p1 = _mulii(c, shifti(gel(x,j),1)); t = t? addii(t, p1): p1; } if (t) s = addii(s, mulii(xi, t)); } gel(v,k) = gerepileuptoint(av,s); } return v; } /* both x and y are RgV */ GEN tablemul(GEN TAB, GEN x, GEN y) { long i, j, k, N; GEN s, v; if (typ(x) != t_COL) return gmul(x, y); if (typ(y) != t_COL) return gmul(y, x); N = lg(x)-1; v = cgetg(N+1,t_COL); for (k=1; k<=N; k++) { pari_sp av = avma; GEN TABi = TAB; if (k == 1) s = gmul(gel(x,1),gel(y,1)); else s = gadd(gmul(gel(x,1),gel(y,k)), gmul(gel(x,k),gel(y,1))); for (i=2; i<=N; i++) { GEN t, xi = gel(x,i); TABi += N; if (gequal0(xi)) continue; t = NULL; for (j=2; j<=N; j++) { GEN p1, c = gcoeff(TABi, k, j); /* m^{i,j}_k */ if (gequal0(c)) continue; p1 = gmul(c, gel(y,j)); t = t? gadd(t, p1): p1; } if (t) s = gadd(s, gmul(xi, t)); } gel(v,k) = gerepileupto(av,s); } return v; } GEN tablesqr(GEN TAB, GEN x) { long i, j, k, N; GEN s, v; if (typ(x) != t_COL) return gsqr(x); N = lg(x)-1; v = cgetg(N+1,t_COL); for (k=1; k<=N; k++) { pari_sp av = avma; GEN TABi = TAB; if (k == 1) s = gsqr(gel(x,1)); else s = gmul2n(gmul(gel(x,1),gel(x,k)), 1); for (i=2; i<=N; i++) { GEN p1, c, t, xi = gel(x,i); TABi += N; if (gequal0(xi)) continue; c = gcoeff(TABi, k, i); t = !gequal0(c)? gmul(c,xi): NULL; for (j=i+1; j<=N; j++) { c = gcoeff(TABi, k, j); if (gequal0(c)) continue; p1 = gmul(gmul2n(c,1), gel(x,j)); t = t? gadd(t, p1): p1; } if (t) s = gadd(s, gmul(xi, t)); } gel(v,k) = gerepileupto(av,s); } return v; } static GEN _mul(void *data, GEN x, GEN y) { return nfmuli((GEN)data,x,y); } static GEN _sqr(void *data, GEN x) { return nfsqri((GEN)data,x); } /* Compute z^n in nf, left-shift binary powering */ GEN nfpow(GEN nf, GEN z, GEN n) { pari_sp av = avma; long s; GEN x, cx; if (typ(n)!=t_INT) pari_err_TYPE("nfpow",n); nf = checknf(nf); s = signe(n); if (!s) return gen_1; x = nf_to_scalar_or_basis(nf, z); if (typ(x) != t_COL) return powgi(x,n); if (s < 0) { /* simplified nfinv */ GEN d; x = Q_remove_denom(x, &d); x = zk_inv(nf, x); x = primitive_part(x, &cx); cx = mul_content(cx, d); n = negi(n); } else x = primitive_part(x, &cx); x = gen_pow(x, n, (void*)nf, _sqr, _mul); if (cx) x = gmul(x, powgi(cx, n)); return av==avma? gcopy(x): gerepileupto(av,x); } /* Compute z^n in nf, left-shift binary powering */ GEN nfpow_u(GEN nf, GEN z, ulong n) { pari_sp av = avma; GEN x, cx; nf = checknf(nf); if (!n) return gen_1; x = nf_to_scalar_or_basis(nf, z); if (typ(x) != t_COL) return gpowgs(x,n); x = primitive_part(x, &cx); x = gen_powu(x, n, (void*)nf, _sqr, _mul); if (cx) x = gmul(x, powgi(cx, utoipos(n))); return av==avma? gcopy(x): gerepileupto(av,x); } static GEN _nf_red(void *E, GEN x) { (void)E; return x; } static GEN _nf_add(void *E, GEN x, GEN y) { return nfadd((GEN)E,x,y); } static GEN _nf_neg(void *E, GEN x) { (void)E; return gneg(x); } static GEN _nf_mul(void *E, GEN x, GEN y) { return nfmul((GEN)E,x,y); } static GEN _nf_inv(void *E, GEN x) { return nfinv((GEN)E,x); } static GEN _nf_s(void *E, long x) { (void)E; return stoi(x); } static const struct bb_field nf_field={_nf_red,_nf_add,_nf_mul,_nf_neg, _nf_inv,&gequal0,_nf_s }; const struct bb_field *get_nf_field(void **E, GEN nf) { *E = (void*)nf; return &nf_field; } GEN nfM_det(GEN nf, GEN M) { void *E; const struct bb_field *S = get_nf_field(&E, nf); return gen_det(M, E, S); } GEN nfM_inv(GEN nf, GEN M) { void *E; const struct bb_field *S = get_nf_field(&E, nf); return gen_Gauss(M, matid(lg(M)-1), E, S); } GEN nfM_mul(GEN nf, GEN A, GEN B) { void *E; const struct bb_field *S = get_nf_field(&E, nf); return gen_matmul(A, B, E, S); } GEN nfM_nfC_mul(GEN nf, GEN A, GEN B) { void *E; const struct bb_field *S = get_nf_field(&E, nf); return gen_matcolmul(A, B, E, S); } /* valuation of integral x (ZV), with resp. to prime ideal pr */ long ZC_nfvalrem(GEN x, GEN pr, GEN *newx) { long i, v, l; GEN r, y, p = pr_get_p(pr), mul = pr_get_tau(pr); /* p inert */ if (typ(mul) == t_INT) return newx? ZV_pvalrem(x, p, newx):ZV_pval(x, p); y = cgetg_copy(x, &l); /* will hold the new x */ x = leafcopy(x); for(v=0;; v++) { for (i=1; i n) return 1; /* room for only one such pr */ return ZV_equal(pr_get_gen(P), gQ) || ZC_prdvd(gQ, P); } long nfval(GEN nf, GEN x, GEN pr) { pari_sp av = avma; long w, e; GEN cx, p; if (gequal0(x)) return LONG_MAX; nf = checknf(nf); checkprid(pr); p = pr_get_p(pr); e = pr_get_e(pr); x = nf_to_scalar_or_basis(nf, x); if (typ(x) != t_COL) return e*Q_pval(x,p); x = Q_primitive_part(x, &cx); w = ZC_nfval(x,pr); if (cx) w += e*Q_pval(cx,p); avma = av; return w; } /* want to write p^v = uniformizer^(e*v) * z^v, z coprime to pr */ /* z := tau^e / p^(e-1), algebraic integer coprime to pr; return z^v */ static GEN powp(GEN nf, GEN pr, long v) { GEN b, z; long e; if (!v) return gen_1; b = pr_get_tau(pr); if (typ(b) == t_INT) return gen_1; e = pr_get_e(pr); z = gel(b,1); if (e != 1) z = gdiv(nfpow_u(nf, z, e), powiu(pr_get_p(pr),e-1)); if (v < 0) { v = -v; z = nfinv(nf, z); } if (v != 1) z = nfpow_u(nf, z, v); return z; } long nfvalrem(GEN nf, GEN x, GEN pr, GEN *py) { pari_sp av = avma; long w, e; GEN cx, p, t; if (!py) return nfval(nf,x,pr); if (gequal0(x)) { *py = gcopy(x); return LONG_MAX; } nf = checknf(nf); checkprid(pr); p = pr_get_p(pr); e = pr_get_e(pr); x = nf_to_scalar_or_basis(nf, x); if (typ(x) != t_COL) { w = Q_pvalrem(x,p, py); if (!w) { *py = gerepilecopy(av, x); return 0; } *py = gerepileupto(av, gmul(powp(nf, pr, w), *py)); return e*w; } x = Q_primitive_part(x, &cx); w = ZC_nfvalrem(x,pr, py); if (cx) { long v = Q_pvalrem(cx,p, &t); *py = nfmul(nf, *py, gmul(powp(nf,pr,v), t)); *py = gerepileupto(av, *py); w += e*v; } else *py = gerepilecopy(av, *py); return w; } GEN gpnfvalrem(GEN nf, GEN x, GEN pr, GEN *py) { long v = nfvalrem(nf,x,pr,py); return v == LONG_MAX? mkoo(): stoi(v); } /* true nf */ GEN coltoalg(GEN nf, GEN x) { return mkpolmod( nf_to_scalar_or_alg(nf, x), nf_get_pol(nf) ); } GEN basistoalg(GEN nf, GEN x) { GEN T; nf = checknf(nf); switch(typ(x)) { case t_COL: { pari_sp av = avma; return gerepilecopy(av, coltoalg(nf, x)); } case t_POLMOD: T = nf_get_pol(nf); if (!RgX_equal_var(T,gel(x,1))) pari_err_MODULUS("basistoalg", T,gel(x,1)); return gcopy(x); case t_POL: T = nf_get_pol(nf); if (varn(T) != varn(x)) pari_err_VAR("basistoalg",x,T); retmkpolmod(RgX_rem(x, T), ZX_copy(T)); case t_INT: case t_FRAC: T = nf_get_pol(nf); retmkpolmod(gcopy(x), ZX_copy(T)); default: pari_err_TYPE("basistoalg",x); return NULL; /* LCOV_EXCL_LINE */ } } /* true nf, x a t_POL */ static GEN pol_to_scalar_or_basis(GEN nf, GEN x) { GEN T = nf_get_pol(nf); long l = lg(x); if (varn(x) != varn(T)) pari_err_VAR("nf_to_scalar_or_basis", x,T); if (l >= lg(T)) { x = RgX_rem(x, T); l = lg(x); } if (l == 2) return gen_0; if (l == 3) { x = gel(x,2); if (!is_rational_t(typ(x))) pari_err_TYPE("nf_to_scalar_or_basis",x); return x; } return poltobasis(nf,x); } /* Assume nf is a genuine nf. */ GEN nf_to_scalar_or_basis(GEN nf, GEN x) { switch(typ(x)) { case t_INT: case t_FRAC: return x; case t_POLMOD: x = checknfelt_mod(nf,x,"nf_to_scalar_or_basis"); switch(typ(x)) { case t_INT: case t_FRAC: return x; case t_POL: return pol_to_scalar_or_basis(nf,x); } break; case t_POL: return pol_to_scalar_or_basis(nf,x); case t_COL: if (lg(x)-1 != nf_get_degree(nf)) break; return QV_isscalar(x)? gel(x,1): x; } pari_err_TYPE("nf_to_scalar_or_basis",x); return NULL; /* LCOV_EXCL_LINE */ } /* Let x be a polynomial with coefficients in Q or nf. Return the same * polynomial with coefficients expressed as vectors (on the integral basis). * No consistency checks, not memory-clean. */ GEN RgX_to_nfX(GEN nf, GEN x) { long i, l; GEN y = cgetg_copy(x, &l); y[1] = x[1]; for (i=2; i= lg(T)) { x = RgX_rem(x, T); l = lg(x); } if (l == 2) return gen_0; if (l == 3) return gel(x,2); return x; } case t_COL: { GEN dx; if (lg(x)-1 != nf_get_degree(nf)) break; if (QV_isscalar(x)) return gel(x,1); x = Q_remove_denom(x, &dx); x = RgV_RgC_mul(nf_get_zkprimpart(nf), x); dx = mul_denom(dx, nf_get_zkden(nf)); return gdiv(x,dx); } } pari_err_TYPE("nf_to_scalar_or_alg",x); return NULL; /* LCOV_EXCL_LINE */ } /* gmul(A, RgX_to_RgC(x)), A t_MAT of compatible dimensions */ GEN RgM_RgX_mul(GEN A, GEN x) { long i, l = lg(x)-1; GEN z; if (l == 1) return zerocol(nbrows(A)); z = gmul(gel(x,2), gel(A,1)); for (i = 2; i < l; i++) if (!gequal0(gel(x,i+1))) z = gadd(z, gmul(gel(x,i+1), gel(A,i))); return z; } GEN ZM_ZX_mul(GEN A, GEN x) { long i, l = lg(x)-1; GEN z; if (l == 1) return zerocol(nbrows(A)); z = ZC_Z_mul(gel(A,1), gel(x,2)); for (i = 2; i < l ; i++) if (signe(gel(x,i+1))) z = ZC_add(z, ZC_Z_mul(gel(A,i), gel(x,i+1))); return z; } /* x a t_POL, nf a genuine nf. No garbage collecting. No check. */ GEN poltobasis(GEN nf, GEN x) { GEN d, T = nf_get_pol(nf); if (varn(x) != varn(T)) pari_err_VAR( "poltobasis", x,T); if (degpol(x) >= degpol(T)) x = RgX_rem(x,T); x = Q_remove_denom(x, &d); if (!RgX_is_ZX(x)) pari_err_TYPE("poltobasis",x); x = ZM_ZX_mul(nf_get_invzk(nf), x); if (d) x = RgC_Rg_div(x, d); return x; } GEN algtobasis(GEN nf, GEN x) { pari_sp av; nf = checknf(nf); switch(typ(x)) { case t_POLMOD: if (!RgX_equal_var(nf_get_pol(nf),gel(x,1))) pari_err_MODULUS("algtobasis", nf_get_pol(nf),gel(x,1)); x = gel(x,2); switch(typ(x)) { case t_INT: case t_FRAC: return scalarcol(x, nf_get_degree(nf)); case t_POL: av = avma; return gerepileupto(av,poltobasis(nf,x)); } break; case t_POL: av = avma; return gerepileupto(av,poltobasis(nf,x)); case t_COL: if (!RgV_is_QV(x)) pari_err_TYPE("nfalgtobasis",x); if (lg(x)-1 != nf_get_degree(nf)) pari_err_DIM("nfalgtobasis"); return gcopy(x); case t_INT: case t_FRAC: return scalarcol(x, nf_get_degree(nf)); } pari_err_TYPE("algtobasis",x); return NULL; /* LCOV_EXCL_LINE */ } GEN rnfbasistoalg(GEN rnf,GEN x) { const char *f = "rnfbasistoalg"; long lx, i; pari_sp av = avma; GEN z, nf, relpol, T; checkrnf(rnf); nf = rnf_get_nf(rnf); T = nf_get_pol(nf); relpol = QXQX_to_mod_shallow(rnf_get_pol(rnf), T); switch(typ(x)) { case t_COL: z = cgetg_copy(x, &lx); for (i=1; i= degpol(T)) x = RgX_rem(x,T); x = mkpolmod(x,T); break; } x = RgX_nffix(f, T, x, 0); if (degpol(x) >= degpol(relpol)) x = RgX_rem(x,relpol); return gerepileupto(av, RgM_RgX_mul(rnf_get_invzk(rnf), x)); } return gerepileupto(av, scalarcol(x, rnf_get_degree(rnf))); } /* Given a and b in nf, gives an algebraic integer y in nf such that a-b.y * is "small" */ GEN nfdiveuc(GEN nf, GEN a, GEN b) { pari_sp av = avma; a = nfdiv(nf,a,b); return gerepileupto(av, ground(a)); } /* Given a and b in nf, gives a "small" algebraic integer r in nf * of the form a-b.y */ GEN nfmod(GEN nf, GEN a, GEN b) { pari_sp av = avma; GEN p1 = gneg_i(nfmul(nf,b,ground(nfdiv(nf,a,b)))); return gerepileupto(av, nfadd(nf,a,p1)); } /* Given a and b in nf, gives a two-component vector [y,r] in nf such * that r=a-b.y is "small". */ GEN nfdivrem(GEN nf, GEN a, GEN b) { pari_sp av = avma; GEN p1,z, y = ground(nfdiv(nf,a,b)); p1 = gneg_i(nfmul(nf,b,y)); z = cgetg(3,t_VEC); gel(z,1) = gcopy(y); gel(z,2) = nfadd(nf,a,p1); return gerepileupto(av, z); } /*************************************************************************/ /** **/ /** REAL EMBEDDINGS **/ /** **/ /*************************************************************************/ static GEN sarch_get_cyc(GEN sarch) { return gel(sarch,1); } static GEN sarch_get_archp(GEN sarch) { return gel(sarch,2); } static GEN sarch_get_MI(GEN sarch) { return gel(sarch,3); } static GEN sarch_get_lambda(GEN sarch) { return gel(sarch,4); } static GEN sarch_get_F(GEN sarch) { return gel(sarch,5); } /* true nf, return number of positive roots of char_x */ static long num_positive(GEN nf, GEN x) { GEN T = nf_get_pol(nf); GEN charx = ZXQ_charpoly(nf_to_scalar_or_alg(nf,x), T, 0); long np; charx = ZX_radical(charx); np = ZX_sturmpart(charx, mkvec2(gen_0,mkoo())); return np * (degpol(T) / degpol(charx)); } /* x a QC: return sigma_k(x) where 1 <= k <= r1+r2; correct but inefficient * if x in Q. M = nf_get_M(nf) */ static GEN nfembed_i(GEN M, GEN x, long k) { long i, l = lg(M); GEN z = gel(x,1); for (i = 2; i < l; i++) z = gadd(z, gmul(gcoeff(M,k,i), gel(x,i))); return z; } GEN nfembed(GEN nf, GEN x, long k) { pari_sp av = avma; nf = checknf(nf); x = nf_to_scalar_or_basis(nf,x); if (typ(x) != t_COL) return gerepilecopy(av, x); return gerepileupto(av, nfembed_i(nf_get_M(nf),x,k)); } /* x a ZC */ static GEN zk_embed(GEN M, GEN x, long k) { long i, l = lg(x); GEN z = gel(x,1); /* times M[k,1], which is 1 */ for (i = 2; i < l; i++) z = mpadd(z, mpmul(gcoeff(M,k,i), gel(x,i))); return z; } /* Given floating point approximation z of sigma_k(x), decide its sign * [0/+, 1/- and -1 for FAIL] */ static long eval_sign_embed(GEN z) { /* dubious, fail */ if (typ(z) == t_REAL && realprec(z) <= LOWDEFAULTPREC) return -1; return (signe(z) < 1)? 1: 0; } /* return v such that (-1)^v = sign(sigma_k(x)), x primitive ZC */ static long eval_sign(GEN M, GEN x, long k) { return eval_sign_embed( zk_embed(M, x, k) ); } /* check that signs[i..#signs] == s; signs = NULL encodes "totally positive" */ static int oksigns(long l, GEN signs, long i, long s) { if (!signs) return s == 0; for (; i < l; i++) if (signs[i] != s) return 0; return 1; } /* check that signs[i] = s and signs[i+1..#signs] = 1-s */ static int oksigns2(long l, GEN signs, long i, long s) { if (!signs) return s == 0 && i == l-1; return signs[i] == s && oksigns(l, signs, i+1, 1-s); } /* true nf, x a ZC (primitive for efficiency), embx its embeddings or NULL */ static int nfchecksigns_i(GEN nf, GEN x, GEN embx, GEN signs, GEN archp) { long l = lg(archp), i; GEN M = nf_get_M(nf), sarch = NULL; long np = -1; for (i = 1; i < l; i++) { long s; if (embx) s = eval_sign_embed(gel(embx,i)); else s = eval_sign(M, x, archp[i]); /* 0 / + or 1 / -; -1 for FAIL */ if (s < 0) /* failure */ { long ni, r1 = nf_get_r1(nf); GEN xi; if (np < 0) { np = num_positive(nf, x); if (np == 0) return oksigns(l, signs, i, 1); if (np == r1) return oksigns(l, signs, i, 0); sarch = nfarchstar(nf, NULL, identity_perm(r1)); } xi = set_sign_mod_divisor(nf, vecsmall_ei(r1, archp[i]), gen_1, sarch); xi = Q_primpart(xi); ni = num_positive(nf, nfmuli(nf,x,xi)); if (ni == 0) return oksigns2(l, signs, i, 0); if (ni == r1) return oksigns2(l, signs, i, 1); s = ni < np? 0: 1; } if (s != (signs? signs[i]: 0)) return 0; } return 1; } static void pl_convert(GEN pl, GEN *psigns, GEN *parchp) { long i, j, l = lg(pl); GEN signs = cgetg(l, t_VECSMALL); GEN archp = cgetg(l, t_VECSMALL); for (i = j = 1; i < l; i++) { if (!pl[i]) continue; archp[j] = i; signs[j] = (pl[i] < 0)? 1: 0; j++; } setlg(archp, j); *parchp = archp; setlg(signs, j); *psigns = signs; } /* pl : requested signs for real embeddings, 0 = no sign constraint */ int nfchecksigns(GEN nf, GEN x, GEN pl) { pari_sp av = avma; GEN signs, archp; int res; nf = checknf(nf); x = nf_to_scalar_or_basis(nf,x); if (typ(x) != t_COL) { long i, l = lg(pl), s = gsigne(x); for (i = 1; i < l; i++) if (pl[i] && pl[i] != s) { avma = av; return 0; } avma = av; return 1; } pl_convert(pl, &signs, &archp); res = nfchecksigns_i(nf, x, NULL, signs, archp); avma = av; return res; } /* signs = NULL: totally positive, else sign[i] = 0 (+) or 1 (-) */ static GEN get_C(GEN lambda, long l, GEN signs) { long i; GEN C, mlambda; if (!signs) return const_vec(l-1, lambda); C = cgetg(l, t_COL); mlambda = gneg(lambda); for (i = 1; i < l; i++) gel(C,i) = signs[i]? mlambda: lambda; return C; } /* signs = NULL: totally positive at archp */ static GEN nfsetsigns(GEN nf, GEN signs, GEN x, GEN sarch) { long i, l = lg(sarch_get_archp(sarch)); GEN ex; /* Is signature already correct ? */ if (typ(x) != t_COL) { long s = gsigne(x); if (!s) i = 1; else if (!signs) i = (s < 0)? 1: l; else { s = s < 0? 1: 0; for (i = 1; i < l; i++) if (signs[i] != s) break; } ex = (i < l)? const_col(l-1, x): NULL; } else { pari_sp av = avma; GEN cex, M = nf_get_M(nf), archp = sarch_get_archp(sarch); GEN xp = Q_primitive_part(x,&cex); ex = cgetg(l,t_COL); for (i = 1; i < l; i++) gel(ex,i) = zk_embed(M,xp,archp[i]); if (nfchecksigns_i(nf, xp, ex, signs, archp)) { ex = NULL; avma = av; } else if (cex) ex = RgC_Rg_mul(ex, cex); /* put back content */ } if (ex) { /* If no, fix it */ GEN MI = sarch_get_MI(sarch), F = sarch_get_F(sarch); GEN lambda = sarch_get_lambda(sarch); GEN t = RgC_sub(get_C(lambda, l, signs), ex); long e; t = grndtoi(RgM_RgC_mul(MI,t), &e); if (lg(F) != 1) t = ZM_ZC_mul(F, t); x = typ(x) == t_COL? RgC_add(t, x): RgC_Rg_add(t, x); } return x; } /* - sarch = nfarchstar(nf, F); * - x encodes a vector of signs at arch.archp: either a t_VECSMALL * (vector of signs as {0,1}-vector), NULL (totally positive at archp), * or a non-zero number field element (replaced by its signature at archp); * - y is a non-zero number field element * Return z = y (mod F) with signs(y, archp) = signs(x) (a {0,1}-vector) */ GEN set_sign_mod_divisor(GEN nf, GEN x, GEN y, GEN sarch) { GEN archp = sarch_get_archp(sarch); if (lg(archp) == 1) return y; nf = checknf(nf); if (x && typ(x) != t_VECSMALL) x = nfsign_arch(nf, x, archp); y = nf_to_scalar_or_basis(nf,y); return nfsetsigns(nf, x, y, sarch); } static GEN setsigns_init(GEN nf, GEN archp, GEN F, GEN DATA) { GEN lambda, Mr = rowpermute(nf_get_M(nf), archp), MI = F? RgM_mul(Mr,F): Mr; lambda = gmul2n(matrixnorm(MI,DEFAULTPREC), -1); if (typ(lambda) != t_REAL) lambda = gmul(lambda, sstoQ(1001,1000)); if (lg(archp) < lg(MI)) { GEN perm = gel(indexrank(MI), 2); if (!F) F = matid(nf_get_degree(nf)); MI = vecpermute(MI, perm); F = vecpermute(F, perm); } if (!F) F = cgetg(1,t_MAT); MI = RgM_inv(MI); return mkvec5(DATA, archp, MI, lambda, F); } /* F non-0 integral ideal in HNF (or NULL: Z_K), compute elements in 1+F * whose sign matrix at archp is identity; archp in 'indices' format */ GEN nfarchstar(GEN nf, GEN F, GEN archp) { long nba = lg(archp) - 1; if (!nba) return mkvec2(cgetg(1,t_VEC), archp); if (F && equali1(gcoeff(F,1,1))) F = NULL; if (F) F = idealpseudored(F, nf_get_roundG(nf)); return setsigns_init(nf, archp, F, const_vec(nba, gen_2)); } /*************************************************************************/ /** **/ /** IDEALCHINESE **/ /** **/ /*************************************************************************/ static int isprfact(GEN x) { long i, l; GEN L, E; if (typ(x) != t_MAT || lg(x) != 3) return 0; L = gel(x,1); l = lg(L); E = gel(x,2); for(i=1; i= 0) gel(E,i) = addiu(gel(E,i), v); else if (v + e <= 0) F = idealmulpowprime(nf, F, pr, stoi(-v)); /* coprime to pr */ else { F = idealmulpowprime(nf, F, pr, stoi(e)); gel(E,i) = stoi(v + e); } } } U = cgetg(r, t_VEC); for (i = 1; i < r; i++) { GEN u; if (w && gequal0(gel(w,i))) u = gen_0; /* unused */ else { GEN pr = gel(L,i), e = gel(E,i), t; t = idealdivpowprime(nf,F, pr, e); u = hnfmerge_get_1(t, idealpow(nf, pr, e)); if (!u) pari_err_COPRIME("idealchinese", t,pr); } gel(U,i) = u; } F = idealpseudored(F, nf_get_roundG(nf)); return mkvec2(F, U); } static GEN pl_normalize(GEN nf, GEN pl) { const char *fun = "idealchinese"; if (lg(pl)-1 != nf_get_r1(nf)) pari_err_TYPE(fun,pl); switch(typ(pl)) { case t_VEC: RgV_check_ZV(pl,fun); pl = ZV_to_zv(pl); /* fall through */ case t_VECSMALL: break; default: pari_err_TYPE(fun,pl); } return pl; } static int is_chineseinit(GEN x) { GEN fa, pl; long l; if (typ(x) != t_VEC || lg(x)!=3) return 0; fa = gel(x,1); pl = gel(x,2); if (typ(fa) != t_VEC || typ(pl) != t_VEC) return 0; l = lg(fa); if (l != 1) { if (l != 3 || typ(gel(fa,1)) != t_MAT || typ(gel(fa,2)) != t_VEC) return 0; } l = lg(pl); if (l != 1) { if (l != 6 || typ(gel(pl,3)) != t_MAT || typ(gel(pl,1)) != t_VECSMALL || typ(gel(pl,2)) != t_VECSMALL) return 0; } return 1; } /* nf a true 'nf' */ static GEN chineseinit_i(GEN nf, GEN fa, GEN w, GEN dw) { const char *fun = "idealchineseinit"; GEN archp = NULL, pl = NULL; switch(typ(fa)) { case t_VEC: if (is_chineseinit(fa)) { if (dw) pari_err_DOMAIN(fun, "denom(y)", "!=", gen_1, w); return fa; } if (lg(fa) != 3) pari_err_TYPE(fun, fa); /* of the form [x,s] */ pl = pl_normalize(nf, gel(fa,2)); fa = gel(fa,1); archp = vecsmall01_to_indices(pl); /* keep pr_init, reset pl */ if (is_chineseinit(fa)) { fa = gel(fa,1); break; } /* fall through */ case t_MAT: /* factorization? */ if (isprfact(fa)) { fa = pr_init(nf, fa, w, dw); break; } default: pari_err_TYPE(fun,fa); } if (!pl) pl = cgetg(1,t_VEC); else { long r = lg(archp); if (r == 1) pl = cgetg(1, t_VEC); else { GEN F = (lg(fa) == 1)? NULL: gel(fa,1), signs = cgetg(r, t_VECSMALL); long i; for (i = 1; i < r; i++) signs[i] = (pl[archp[i]] < 0)? 1: 0; pl = setsigns_init(nf, archp, F, signs); } } return mkvec2(fa, pl); } /* Given a prime ideal factorization x, possibly with 0 or negative exponents, * and a vector w of elements of nf, gives b such that * v_p(b-w_p)>=v_p(x) for all prime ideals p in the ideal factorization * and v_p(b)>=0 for all other p, using the standard proof given in GTM 138. */ GEN idealchinese(GEN nf, GEN x, GEN w) { const char *fun = "idealchinese"; pari_sp av = avma; GEN x1, x2, s, dw, F; nf = checknf(nf); if (!w) return gerepilecopy(av, chineseinit_i(nf,x,NULL,NULL)); if (typ(w) != t_VEC) pari_err_TYPE(fun,w); w = Q_remove_denom(matalgtobasis(nf,w), &dw); if (!is_chineseinit(x)) x = chineseinit_i(nf,x,w,dw); /* x is a 'chineseinit' */ x1 = gel(x,1); s = NULL; x2 = gel(x,2); if (lg(x1) == 1) F = NULL; else { GEN U = gel(x1,2); long i, r = lg(w); F = gel(x1,1); for (i=1; i", utoi(r1), utoi(i)); } static GEN parse_embed(GEN ind, long r, const char *f) { long l, i; if (!ind) return identity_perm(r); switch(typ(ind)) { case t_INT: case t_VEC: case t_COL: ind = gtovecsmall(ind); break; case t_VECSMALL: break; default: pari_err_TYPE(f, ind); } l = lg(ind); for (i = 1; i < l; i++) chk_ind(f, ind[i], r); return ind; } GEN nfeltsign(GEN nf, GEN x, GEN ind0) { pari_sp av = avma; long i, l, r1; GEN v, ind; nf = checknf(nf); r1 = nf_get_r1(nf); x = nf_to_scalar_or_basis(nf, x); ind = parse_embed(ind0, r1, "nfeltsign"); l = lg(ind); if (typ(x) != t_COL) { GEN s; switch(gsigne(x)) { case -1:s = gen_m1; break; case 1: s = gen_1; break; default: s = gen_0; break; } avma = av; return (ind0 && typ(ind0) == t_INT)? s: const_vec(l-1, s); } v = nfsign_arch(nf, x, ind); if (ind0 && typ(ind0) == t_INT) { avma = av; return v[1]? gen_m1: gen_1; } settyp(v, t_VEC); for (i = 1; i < l; i++) gel(v,i) = v[i]? gen_m1: gen_1; return gerepileupto(av, v); } GEN nfeltembed(GEN nf, GEN x, GEN ind0, long prec0) { pari_sp av = avma; long i, e, l, r1, r2, prec, prec1; GEN v, ind, cx; nf = checknf(nf); nf_get_sign(nf,&r1,&r2); x = nf_to_scalar_or_basis(nf, x); ind = parse_embed(ind0, r1+r2, "nfeltembed"); l = lg(ind); if (typ(x) != t_COL) { if (!(ind0 && typ(ind0) == t_INT)) x = const_vec(l-1, x); return gerepilecopy(av, x); } x = Q_primitive_part(x, &cx); prec1 = prec0; e = gexpo(x); if (e > 8) prec1 += nbits2extraprec(e); prec = prec1; if (nf_get_prec(nf) < prec) nf = nfnewprec_shallow(nf, prec); v = cgetg(l, t_VEC); for(;;) { GEN M = nf_get_M(nf); for (i = 1; i < l; i++) { GEN t = nfembed_i(M, x, ind[i]); long e = gexpo(t); if (gequal0(t) || precision(t) < prec0 || (e < 0 && prec < prec1 + nbits2extraprec(-e)) ) break; if (cx) t = gmul(t, cx); gel(v,i) = t; } if (i == l) break; prec = precdbl(prec); if (DEBUGLEVEL>1) pari_warn(warnprec,"eltnfembed", prec); nf = nfnewprec_shallow(nf, prec); } if (ind0 && typ(ind0) == t_INT) v = gel(v,1); return gerepilecopy(av, v); } /* number of distinct roots of sigma(f) */ GEN nfpolsturm(GEN nf, GEN f, GEN ind0) { pari_sp av = avma; long d, l, r1, single; GEN ind, u, v, vr1, T, s, t; nf = checknf(nf); T = nf_get_pol(nf); r1 = nf_get_r1(nf); ind = parse_embed(ind0, r1, "nfpolsturm"); single = ind0 && typ(ind0) == t_INT; l = lg(ind); if (gequal0(f)) pari_err_ROOTS0("nfpolsturm"); if (typ(f) == t_POL && varn(f) != varn(T)) { f = RgX_nffix("nfsturn", T, f,1); if (lg(f) == 3) f = NULL; } else { (void)Rg_nffix("nfpolsturm", T, f, 0); f = NULL; } if (!f) { avma = av; return single? gen_0: zerovec(l-1); } d = degpol(f); if (d == 1) { avma = av; return single? gen_1: const_vec(l-1,gen_1); } vr1 = const_vecsmall(l-1, 1); u = Q_primpart(f); s = ZV_to_zv(nfeltsign(nf, gel(u,d+2), ind)); v = RgX_deriv(u); t = odd(d)? leafcopy(s): zv_neg(s); for(;;) { GEN r = RgX_neg( Q_primpart(RgX_pseudorem(u, v)) ), sr; long i, dr = degpol(r); if (dr < 0) break; sr = ZV_to_zv(nfeltsign(nf, gel(r,dr+2), ind)); for (i = 1; i < l; i++) if (sr[i] != s[i]) { s[i] = sr[i], vr1[i]--; } if (odd(dr)) sr = zv_neg(sr); for (i = 1; i < l; i++) if (sr[i] != t[i]) { t[i] = sr[i], vr1[i]++; } if (!dr) break; u = v; v = r; } if (single) { avma = av; return stoi(vr1[1]); } return gerepileupto(av, zv_to_ZV(vr1)); } /* return the vector of signs of x; the matrix of such if x is a vector * of nf elements */ GEN nfsign(GEN nf, GEN x) { long i, l; GEN archp, S; nf = checknf(nf); archp = identity_perm( nf_get_r1(nf) ); if (typ(x) != t_VEC) return nfsign_arch(nf, x, archp); l = lg(x); S = cgetg(l, t_MAT); for (i=1; i 10)? shifti(EX,-1): NULL; for (i = 1; i < lx; i++) { GEN h, n = centermodii(gel(e,i), EX, EXo2); long sn = signe(n); if (!sn) continue; h = nf_to_scalar_or_basis(nf, gel(g,i)); switch(typ(h)) { case t_INT: break; case t_FRAC: h = Fp_div(gel(h,1), gel(h,2), idZ); break; default: { GEN dh; h = Q_remove_denom(h, &dh); if (dh) h = FpC_Fp_mul(h, Fp_inv(dh,idZ), idZ); } } if (sn > 0) plus = nfmulpowmodideal(nf, plus, h, n, id); else /* sn < 0 */ minus = nfmulpowmodideal(nf, minus, h, negi(n), id); } if (minus) plus = nfmulmodideal(nf, plus, nfinvmodideal(nf,minus,id), id); return plus? plus: gen_1; } /* given 2 integral ideals x, y in HNF s.t x | y | x^2, compute (1+x)/(1+y) in * the form [[cyc],[gen], U], where U := ux^-1 as a pair [ZM, denom(U)] */ static GEN zidealij(GEN x, GEN y) { GEN U, G, cyc, xp = gcoeff(x,1,1), xi = hnf_invscale(x, xp); long j, N; /* x^(-1) y = relations between the 1 + x_i (HNF) */ cyc = ZM_snf_group(ZM_Z_divexact(ZM_mul(xi, y), xp), &U, &G); N = lg(cyc); G = ZM_mul(x,G); settyp(G, t_VEC); /* new generators */ for (j=1; j 1, x + 1; shallow */ static GEN ZC_add1(GEN x) { long i, l = lg(x); GEN y = cgetg(l, t_COL); for (i = 2; i < l; i++) gel(y,i) = gel(x,i); gel(y,1) = addiu(gel(x,1), 1); return y; } /* lg(x) > 1, x - 1; shallow */ static GEN ZC_sub1(GEN x) { long i, l = lg(x); GEN y = cgetg(l, t_COL); for (i = 2; i < l; i++) gel(y,i) = gel(x,i); gel(y,1) = subiu(gel(x,1), 1); return y; } /* x,y are t_INT or ZC */ static GEN zkadd(GEN x, GEN y) { long tx = typ(x); if (tx == typ(y)) return tx == t_INT? addii(x,y): ZC_add(x,y); else return tx == t_INT? ZC_Z_add(y,x): ZC_Z_add(x,y); } /* x a t_INT or ZC, x+1; shallow */ static GEN zkadd1(GEN x) { long tx = typ(x); return tx == t_INT? addiu(x,1): ZC_add1(x); } /* x a t_INT or ZC, x-1; shallow */ static GEN zksub1(GEN x) { long tx = typ(x); return tx == t_INT? subiu(x,1): ZC_sub1(x); } /* x,y are t_INT or ZC; x - y */ static GEN zksub(GEN x, GEN y) { long tx = typ(x), ty = typ(y); if (tx == ty) return tx == t_INT? subii(x,y): ZC_sub(x,y); else return tx == t_INT? Z_ZC_sub(x,y): ZC_Z_sub(x,y); } /* x is t_INT or ZM (mult. map), y is t_INT or ZC; x * y */ static GEN zkmul(GEN x, GEN y) { long tx = typ(x), ty = typ(y); if (ty == t_INT) return tx == t_INT? mulii(x,y): ZC_Z_mul(gel(x,1),y); else return tx == t_INT? ZC_Z_mul(y,x): ZM_ZC_mul(x,y); } /* (U,V) = 1 coprime ideals. Want z = x mod U, = y mod V; namely * z =vx + uy = v(x-y) + y, where u + v = 1, u in U, v in V. * zkc = [v, UV], v a t_INT or ZM (mult. by v map), UV a ZM (ideal in HNF); * shallow */ GEN zkchinese(GEN zkc, GEN x, GEN y) { GEN v = gel(zkc,1), UV = gel(zkc,2), z = zkadd(zkmul(v, zksub(x,y)), y); return zk_modHNF(z, UV); } /* special case z = x mod U, = 1 mod V; shallow */ GEN zkchinese1(GEN zkc, GEN x) { GEN v = gel(zkc,1), UV = gel(zkc,2), z = zkadd1(zkmul(v, zksub1(x))); return (typ(z) == t_INT)? z: ZC_hnfrem(z, UV); } static GEN zkVchinese1(GEN zkc, GEN v) { long i, ly; GEN y = cgetg_copy(v, &ly); for (i=1; i 5) { GEN b = (typ(v) == t_COL)? v: scalarcol_shallow(v, nf_get_degree(nf)); b= ZC_reducemodlll(b, AB); if (gexpo(b) < e) v = b; } return mkvec2(zk_scalar_or_multable(nf,v), AB); } /* prepare to solve z = x (mod A), z = 1 mod (B) * and then z = 1 (mod A), z = y mod (B) [zkchinese1 twice] */ static GEN zkchinese1init2(GEN nf, GEN A, GEN B, GEN AB) { GEN zkc = zkchineseinit(nf, A, B, AB); GEN mv = gel(zkc,1), mu; if (typ(mv) == t_INT) return mkvec2(zkc, mkvec2(subui(1,mv),AB)); mu = RgM_Rg_add_shallow(ZM_neg(mv), gen_1); return mkvec2(mkvec2(mv,AB), mkvec2(mu,AB)); } static GEN apply_U(GEN L, GEN a) { GEN e, U = gel(L,3), dU = gel(L,4); if (typ(a) == t_INT) e = ZC_Z_mul(gel(U,1), subiu(a, 1)); else { /* t_COL */ GEN t = gel(a,1); gel(a,1) = subiu(gel(a,1), 1); /* a -= 1 */ e = ZM_ZC_mul(U, a); gel(a,1) = t; /* restore */ } return gdiv(e, dU); } /* true nf; vectors of [[cyc],[g],U.X^-1]. Assume k > 1. */ static GEN principal_units(GEN nf, GEN pr, long k, GEN prk) { GEN list, prb; ulong mask = quadratic_prec_mask(k); long a = 1; if (DEBUGLEVEL>3) err_printf("treating pr^%ld, pr = %Ps\n",k,pr); prb = pr_hnf(nf,pr); list = vectrunc_init(k); while (mask > 1) { GEN pra = prb; long b = a << 1; if (mask & 1) b--; mask >>= 1; /* compute 1 + pr^a / 1 + pr^b, 2a <= b */ if(DEBUGLEVEL>3) err_printf(" treating a = %ld, b = %ld\n",a,b); prb = (b >= k)? prk: idealpows(nf,pr,b); vectrunc_append(list, zidealij(pra, prb)); a = b; } return list; } /* a = 1 mod (pr) return log(a) on local-gens of 1+pr/1+pr^k */ static GEN log_prk1(GEN nf, GEN a, long nh, GEN L2, GEN prk) { GEN y = cgetg(nh+1, t_COL); long j, iy, c = lg(L2)-1; for (j = iy = 1; j <= c; j++) { GEN L = gel(L2,j), cyc = gel(L,1), gen = gel(L,2), E = apply_U(L,a); long i, nc = lg(cyc)-1; int last = (j == c); for (i = 1; i <= nc; i++, iy++) { GEN t, e = gel(E,i); if (typ(e) != t_INT) pari_err_COPRIME("zlog_prk1", a, prk); t = Fp_neg(e, gel(cyc,i)); gel(y,iy) = negi(t); if (!last && signe(t)) a = nfmulpowmodideal(nf, a, gel(gen,i), t, prk); } } return y; } /* true nf */ static GEN principal_units_relations(GEN nf, GEN L2, GEN prk, long nh) { GEN h = cgetg(nh+1,t_MAT); long ih, j, c = lg(L2)-1; for (j = ih = 1; j <= c; j++) { GEN L = gel(L2,j), F = gel(L,1), G = gel(L,2); long k, lG = lg(G); for (k = 1; k < lG; k++,ih++) { /* log(g^f) mod pr^e */ GEN a = nfpowmodideal(nf,gel(G,k),gel(F,k),prk); gel(h,ih) = ZC_neg(log_prk1(nf, a, nh, L2, prk)); gcoeff(h,ih,ih) = gel(F,k); } } return h; } /* true nf; e > 1; multiplicative group (1 + pr) / (1 + pr^k), * prk = pr^k or NULL */ static GEN idealprincipalunits_i(GEN nf, GEN pr, long k, GEN *pU) { GEN cyc, gen, L2, prk = idealpows(nf, pr, k); L2 = principal_units(nf, pr, k, prk); if (k == 2) { GEN L = gel(L2,1); cyc = gel(L,1); gen = gel(L,2); if (pU) *pU = matid(lg(gen)-1); } else { long c = lg(L2), j; GEN EX, h, Ui, vg = cgetg(c, t_VEC); for (j = 1; j < c; j++) gel(vg, j) = gmael(L2,j,2); vg = shallowconcat1(vg); h = principal_units_relations(nf, L2, prk, lg(vg)-1); h = ZM_hnfall_i(h, NULL, 0); cyc = ZM_snf_group(h, pU, &Ui); c = lg(Ui); gen = cgetg(c, t_VEC); EX = gel(cyc,1); for (j = 1; j < c; j++) gel(gen,j) = famat_to_nf_modideal_coprime(nf, vg, gel(Ui,j), prk, EX); } return mkvec4(cyc, gen, prk, L2); } GEN idealprincipalunits(GEN nf, GEN pr, long k) { pari_sp av; GEN v; nf = checknf(nf); if (k == 1) { checkprid(pr); retmkvec3(gen_1,cgetg(1,t_VEC),cgetg(1,t_VEC)); } av = avma; v = idealprincipalunits_i(nf, pr, k, NULL); return gerepilecopy(av, mkvec3(powiu(pr_norm(pr), k-1), gel(v,1), gel(v,2))); } /* true nf; given an ideal pr^k dividing an integral ideal x (in HNF form) * compute an 'sprk', the structure of G = (Z_K/pr^k)^* [ x = NULL for x=pr^k ] * Return a vector with at least 4 components [cyc],[gen],[HNF pr^k,pr,k],ff, * where * cyc : type of G as abelian group (SNF) * gen : generators of G, coprime to x * pr^k: in HNF * ff : data for log_g in (Z_K/pr)^* * Two extra components are present iff k > 1: L2, U * L2 : list of data structures to compute local DL in (Z_K/pr)^*, * and 1 + pr^a/ 1 + pr^b for various a < b <= min(2a, k) * U : base change matrices to convert a vector of local DL to DL wrt gen */ static GEN sprkinit(GEN nf, GEN pr, GEN gk, GEN x) { GEN T, p, modpr, cyc, gen, g, g0, ord0, A, prk, U, L2; long k = itos(gk), f = pr_get_f(pr); if(DEBUGLEVEL>3) err_printf("treating pr^%ld, pr = %Ps\n",k,pr); modpr = nf_to_Fq_init(nf, &pr,&T,&p); /* (Z_K / pr)^* */ if (f == 1) { g0 = g = pgener_Fp(p); ord0 = get_arith_ZZM(subiu(p,1)); } else { g0 = g = gener_FpXQ(T,p, &ord0); g = Fq_to_nf(g, modpr); if (typ(g) == t_POL) g = poltobasis(nf, g); } A = gel(ord0, 1); /* Norm(pr)-1 */ if (k == 1) { cyc = mkvec(A); gen = mkvec(g); prk = pr_hnf(nf,pr); L2 = U = NULL; } else { /* local-gens of (1 + pr)/(1 + pr^k) = SNF-gens * U */ GEN AB, B, u, v, w; long j, l; w = idealprincipalunits_i(nf, pr, k, &U); /* incorporate (Z_K/pr)^*, order A coprime to B = expo(1+pr/1+pr^k)*/ cyc = leafcopy(gel(w,1)); B = gel(cyc,1); AB = mulii(A,B); gen = leafcopy(gel(w,2)); prk = gel(w,3); g = nfpowmodideal(nf, g, B, prk); g0 = Fq_pow(g0, modii(B,A), T, p); /* update primitive root */ L2 = mkvec3(A, g, gel(w,4)); gel(cyc,1) = AB; gel(gen,1) = nfmulmodideal(nf, gel(gen,1), g, prk); u = mulii(Fp_inv(A,B), A); v = subui(1, u); l = lg(U); for (j = 1; j < l; j++) gcoeff(U,1,j) = Fp_mul(u, gcoeff(U,1,j), AB); U = mkvec2(Rg_col_ei(v, lg(gen)-1, 1), U); } /* local-gens of (Z_K/pr^k)^* = SNF-gens * U */ if (x) { GEN uv = zkchineseinit(nf, idealdivpowprime(nf,x,pr,gk), prk, x); gen = zkVchinese1(uv, gen); } return mkvecn(U? 6: 4, cyc, gen, prk, mkvec3(modpr,g0,ord0), L2, U); } static GEN sprk_get_cyc(GEN s) { return gel(s,1); } static GEN sprk_get_expo(GEN s) { GEN cyc = sprk_get_cyc(s); return lg(cyc) == 1? gen_1: gel(cyc, 1); } static GEN sprk_get_gen(GEN s) { return gel(s,2); } static GEN sprk_get_prk(GEN s) { return gel(s,3); } static GEN sprk_get_ff(GEN s) { return gel(s,4); } static GEN sprk_get_pr(GEN s) { GEN ff = gel(s,4); return modpr_get_pr(gel(ff,1)); } /* A = Npr-1, = (Z_K/pr)^*, L2 to 1 + pr / 1 + pr^k */ static void sprk_get_L2(GEN s, GEN *A, GEN *g, GEN *L2) { GEN v = gel(s,5); *A = gel(v,1); *g = gel(v,2); *L2 = gel(v,3); } static void sprk_get_U2(GEN s, GEN *U1, GEN *U2) { GEN v = gel(s,6); *U1 = gel(v,1); *U2 = gel(v,2); } static int sprk_is_prime(GEN s) { return lg(s) == 5; } static GEN famat_zlog_pr(GEN nf, GEN g, GEN e, GEN sprk) { GEN pr = sprk_get_pr(sprk); GEN prk = sprk_get_prk(sprk); GEN x = famat_makecoprime(nf, g, e, pr, prk, sprk_get_expo(sprk)); return zlog_pr(nf, x, sprk); } /* log_g(a) in (Z_K/pr)^* */ static GEN nf_log(GEN nf, GEN a, GEN ff) { GEN pr = gel(ff,1), g = gel(ff,2), ord = gel(ff,3); GEN T,p, modpr = nf_to_Fq_init(nf, &pr, &T, &p); return Fq_log(nf_to_Fq(nf,a,modpr), g, ord, T, p); } /* a in Z_K (t_COL or t_INT), pr prime ideal, sprk = sprkinit(nf,pr,k,x). * return log(a) on SNF-generators of (Z_K/pr^k)^**/ GEN zlog_pr(GEN nf, GEN a, GEN sprk) { GEN e, prk, A, g, L2, U1, U2, y; if (typ(a) == t_MAT) return famat_zlog_pr(nf, gel(a,1), gel(a,2), sprk); e = nf_log(nf, a, sprk_get_ff(sprk)); if (sprk_is_prime(sprk)) return mkcol(e); /* k = 1 */ prk = sprk_get_prk(sprk); sprk_get_L2(sprk, &A,&g,&L2); if (signe(e)) { e = Fp_neg(e, A); a = nfmulpowmodideal(nf, a, g, e, prk); } sprk_get_U2(sprk, &U1,&U2); y = ZM_ZC_mul(U2, log_prk1(nf, a, lg(U2)-1, L2, prk)); if (signe(e)) y = ZC_sub(y, ZC_Z_mul(U1,e)); return vecmodii(y, sprk_get_cyc(sprk)); } GEN zlog_pr_init(GEN nf, GEN pr, long k) { return sprkinit(checknf(nf),pr,utoipos(k),NULL);} GEN vzlog_pr(GEN nf, GEN v, GEN sprk) { long l = lg(v), i; GEN w = cgetg(l, t_MAT); for (i = 1; i < l; i++) gel(w,i) = zlog_pr(nf, gel(v,i), sprk); return w; } static GEN famat_zlog(GEN nf, GEN fa, GEN sgn, zlog_S *S) { long i, n0, n = lg(S->U)-1; GEN g, e, y; if (lg(fa) == 1) return zerocol(n); g = gel(fa,1); e = gel(fa,2); y = cgetg(n+1, t_COL); n0 = lg(S->sprk)-1; /* n0 = n (trivial arch. part), or n-1 */ for (i=1; i <= n0; i++) gel(y,i) = famat_zlog_pr(nf, g, e, gel(S->sprk,i)); if (n0 != n) { if (!sgn) sgn = nfsign_arch(nf, fa, S->archp); gel(y,n) = Flc_to_ZC(sgn); } return y; } /* assume that cyclic factors are normalized, in particular != [1] */ static GEN split_U(GEN U, GEN Sprk) { long t = 0, k, n, l = lg(Sprk); GEN vU = cgetg(l+1, t_VEC); for (k = 1; k < l; k++) { n = lg(sprk_get_cyc(gel(Sprk,k))) - 1; /* > 0 */ gel(vU,k) = vecslice(U, t+1, t+n); t += n; } /* t+1 .. lg(U)-1 */ n = lg(U) - t - 1; /* can be 0 */ if (!n) setlg(vU,l); else gel(vU,l) = vecslice(U, t+1, t+n); return vU; } void init_zlog(zlog_S *S, GEN bid) { GEN fa2 = bid_get_fact2(bid); S->U = bid_get_U(bid); S->hU = lg(bid_get_cyc(bid))-1; S->archp = bid_get_archp(bid); S->sprk = bid_get_sprk(bid); S->bid = bid; S->P = gel(fa2,1); S->k = gel(fa2,2); S->no2 = lg(S->P) == lg(gel(bid_get_fact(bid),1)); } /* a a t_FRAC/t_INT, reduce mod bid */ static GEN Q_mod_bid(GEN bid, GEN a) { GEN xZ = gcoeff(bid_get_ideal(bid),1,1); GEN b = Rg_to_Fp(a, xZ); if (gsigne(a) < 0) b = subii(b, xZ); return signe(b)? b: xZ; } /* Return decomposition of a on the CRT generators blocks attached to the * S->sprk and sarch; sgn = sign(a, S->arch), NULL if unknown */ static GEN zlog(GEN nf, GEN a, GEN sgn, zlog_S *S) { long k, l; GEN y; a = nf_to_scalar_or_basis(nf, a); switch(typ(a)) { case t_INT: break; case t_FRAC: a = Q_mod_bid(S->bid, a); break; default: /* case t_COL: */ { GEN den; check_nfelt(a, &den); if (den) { a = Q_muli_to_int(a, den); a = mkmat2(mkcol2(a, den), mkcol2(gen_1, gen_m1)); return famat_zlog(nf, a, sgn, S); } } } if (sgn) sgn = (lg(sgn) == 1)? NULL: leafcopy(sgn); else sgn = (lg(S->archp) == 1)? NULL: nfsign_arch(nf, a, S->archp); l = lg(S->sprk); y = cgetg(sgn? l+1: l, t_COL); for (k = 1; k < l; k++) { GEN sprk = gel(S->sprk,k); gel(y,k) = zlog_pr(nf, a, sprk); } if (sgn) gel(y,l) = Flc_to_ZC(sgn); return y; } /* true nf */ GEN pr_basis_perm(GEN nf, GEN pr) { long f = pr_get_f(pr); GEN perm; if (f == nf_get_degree(nf)) return identity_perm(f); perm = cgetg(f+1, t_VECSMALL); perm[1] = 1; if (f > 1) { GEN H = pr_hnf(nf,pr); long i, k; for (i = k = 2; k <= f; i++) if (!equali1(gcoeff(H,i,i))) perm[k++] = i; } return perm; } /* \sum U[i]*y[i], U[i] ZM, y[i] ZC. We allow lg(y) > lg(U). */ static GEN ZMV_ZCV_mul(GEN U, GEN y) { long i, l = lg(U); GEN z = NULL; if (l == 1) return cgetg(1,t_COL); for (i = 1; i < l; i++) { GEN u = ZM_ZC_mul(gel(U,i), gel(y,i)); z = z? ZC_add(z, u): u; } return z; } /* A * (U[1], ..., U[d] */ static GEN ZM_ZMV_mul(GEN A, GEN U) { long i, l; GEN V = cgetg_copy(U,&l); for (i = 1; i < l; i++) gel(V,i) = ZM_mul(A,gel(U,i)); return V; } /* Log on bid.gen of generators of P_{1,I pr^{e-1}} / P_{1,I pr^e} (I,pr) = 1, * defined implicitly via CRT. 'ind' is the index of pr in modulus * factorization */ GEN log_gen_pr(zlog_S *S, long ind, GEN nf, long e) { GEN A, sprk = gel(S->sprk,ind), Uind = gel(S->U, ind); if (e == 1) retmkmat( gel(Uind,1) ); else { GEN G, pr = sprk_get_pr(sprk); long i, l; if (e == 2) { GEN A, g, L, L2; sprk_get_L2(sprk,&A,&g,&L2); L = gel(L2,1); G = gel(L,2); l = lg(G); } else { GEN perm = pr_basis_perm(nf,pr), PI = nfpow_u(nf, pr_get_gen(pr), e-1); l = lg(perm); G = cgetg(l, t_VEC); if (typ(PI) == t_INT) { /* zk_ei_mul doesn't allow t_INT */ long N = nf_get_degree(nf); gel(G,1) = addiu(PI,1); for (i = 2; i < l; i++) { GEN z = col_ei(N, 1); gel(G,i) = z; gel(z, perm[i]) = PI; } } else { gel(G,1) = nfadd(nf, gen_1, PI); for (i = 2; i < l; i++) gel(G,i) = nfadd(nf, gen_1, zk_ei_mul(nf, PI, perm[i])); } } A = cgetg(l, t_MAT); for (i = 1; i < l; i++) gel(A,i) = ZM_ZC_mul(Uind, zlog_pr(nf, gel(G,i), sprk)); return A; } } /* Log on bid.gen of generator of P_{1,f} / P_{1,f v[index]} * v = vector of r1 real places */ GEN log_gen_arch(zlog_S *S, long index) { GEN U = gel(S->U, lg(S->U)-1); return gel(U, index); } /* compute bid.clgp: [h,cyc] or [h,cyc,gen] */ static GEN bid_grp(GEN nf, GEN U, GEN cyc, GEN g, GEN F, GEN sarch) { GEN G, h = ZV_prod(cyc); long c; if (!U) return mkvec2(h,cyc); c = lg(U); G = cgetg(c,t_VEC); if (c > 1) { GEN U0, Uoo, EX = gel(cyc,1); /* exponent of bid */ long i, hU = nbrows(U), nba = lg(sarch_get_cyc(sarch))-1; /* #f_oo */ if (!nba) { U0 = U; Uoo = NULL; } else if (nba == hU) { U0 = NULL; Uoo = U; } else { U0 = rowslice(U, 1, hU-nba); Uoo = rowslice(U, hU-nba+1, hU); } for (i = 1; i < c; i++) { GEN t = gen_1; if (U0) t = famat_to_nf_modideal_coprime(nf, g, gel(U0,i), F, EX); if (Uoo) t = set_sign_mod_divisor(nf, ZV_to_Flv(gel(Uoo,i),2), t, sarch); gel(G,i) = t; } } return mkvec3(h, cyc, G); } /* remove prime ideals of norm 2 with exponent 1 from factorization */ static GEN famat_strip2(GEN fa) { GEN P = gel(fa,1), E = gel(fa,2), Q, F; long l = lg(P), i, j; Q = cgetg(l, t_COL); F = cgetg(l, t_COL); for (i = j = 1; i < l; i++) { GEN pr = gel(P,i), e = gel(E,i); if (!absequaliu(pr_get_p(pr), 2) || itou(e) != 1 || pr_get_f(pr) != 1) { gel(Q,j) = pr; gel(F,j) = e; j++; } } setlg(Q,j); setlg(F,j); return mkmat2(Q,F); } /* Compute [[ideal,arch], [h,[cyc],[gen]], idealfact, [liste], U] flag may include nf_GEN | nf_INIT */ static GEN Idealstar_i(GEN nf, GEN ideal, long flag) { long i, k, nbp, R1; GEN y, cyc, U, u1 = NULL, fa, fa2, sprk, x, arch, archp, E, P, sarch, gen; nf = checknf(nf); R1 = nf_get_r1(nf); if (typ(ideal) == t_VEC && lg(ideal) == 3) { arch = gel(ideal,2); ideal= gel(ideal,1); switch(typ(arch)) { case t_VEC: if (lg(arch) != R1+1) pari_err_TYPE("Idealstar [incorrect archimedean component]",arch); archp = vec01_to_indices(arch); break; case t_VECSMALL: archp = arch; k = lg(archp)-1; if (k && archp[k] > R1) pari_err_TYPE("Idealstar [incorrect archimedean component]",arch); arch = indices_to_vec01(archp, R1); break; default: pari_err_TYPE("Idealstar [incorrect archimedean component]",arch); return NULL; } } else { arch = zerovec(R1); archp = cgetg(1, t_VECSMALL); } if (is_nf_factor(ideal)) { fa = ideal; x = idealfactorback(nf, gel(fa,1), gel(fa,2), 0); } else { fa = idealfactor(nf, ideal); x = ideal; } if (typ(x) != t_MAT) x = idealhnf_shallow(nf, x); if (lg(x) == 1) pari_err_DOMAIN("Idealstar", "ideal","=",gen_0,x); if (typ(gcoeff(x,1,1)) != t_INT) pari_err_DOMAIN("Idealstar","denominator(ideal)", "!=",gen_1,x); sarch = nfarchstar(nf, x, archp); fa2 = famat_strip2(fa); P = gel(fa2,1); E = gel(fa2,2); nbp = lg(P)-1; sprk = cgetg(nbp+1,t_VEC); if (nbp) { GEN t = (lg(gel(fa,1))==2)? NULL: x; /* beware fa != fa2 */ cyc = cgetg(nbp+2,t_VEC); gen = cgetg(nbp+1,t_VEC); for (i = 1; i <= nbp; i++) { GEN L = sprkinit(nf, gel(P,i), gel(E,i), t); gel(sprk,i) = L; gel(cyc,i) = sprk_get_cyc(L); /* true gens are congruent to those mod x AND positive at archp */ gel(gen,i) = sprk_get_gen(L); } gel(cyc,i) = sarch_get_cyc(sarch); cyc = shallowconcat1(cyc); gen = shallowconcat1(gen); cyc = ZV_snf_group(cyc, &U, (flag & nf_GEN)? &u1: NULL); } else { cyc = sarch_get_cyc(sarch); gen = cgetg(1,t_VEC); U = matid(lg(cyc)-1); if (flag & nf_GEN) u1 = U; } y = bid_grp(nf, u1, cyc, gen, x, sarch); if (!(flag & nf_INIT)) return y; U = split_U(U, sprk); return mkvec5(mkvec2(x, arch), y, mkvec2(fa,fa2), mkvec2(sprk, sarch), U); } GEN Idealstar(GEN nf, GEN ideal, long flag) { pari_sp av = avma; if (!nf) nf = nfinit(pol_x(0), DEFAULTPREC); return gerepilecopy(av, Idealstar_i(nf, ideal, flag)); } GEN Idealstarprk(GEN nf, GEN pr, long k, long flag) { pari_sp av = avma; GEN z = Idealstar_i(nf, mkmat2(mkcol(pr),mkcols(k)), flag); return gerepilecopy(av, z); } /* FIXME: obsolete */ GEN zidealstarinitgen(GEN nf, GEN ideal) { return Idealstar(nf,ideal, nf_INIT|nf_GEN); } GEN zidealstarinit(GEN nf, GEN ideal) { return Idealstar(nf,ideal, nf_INIT); } GEN zidealstar(GEN nf, GEN ideal) { return Idealstar(nf,ideal, nf_GEN); } GEN idealstar0(GEN nf, GEN ideal,long flag) { switch(flag) { case 0: return Idealstar(nf,ideal, nf_GEN); case 1: return Idealstar(nf,ideal, nf_INIT); case 2: return Idealstar(nf,ideal, nf_INIT|nf_GEN); default: pari_err_FLAG("idealstar"); } return NULL; /* LCOV_EXCL_LINE */ } void check_nfelt(GEN x, GEN *den) { long l = lg(x), i; GEN t, d = NULL; if (typ(x) != t_COL) pari_err_TYPE("check_nfelt", x); for (i=1; ihU) return cgetg(1, t_COL); cyc = bid_get_cyc(S->bid); if (typ(x) == t_MAT) { if (lg(x) == 1) return zerocol(lg(cyc)-1); y = famat_zlog(nf, x, sgn, S); } else y = zlog(nf, x, sgn, S); y = ZMV_ZCV_mul(S->U, y); return gerepileupto(av, vecmodii(y, cyc)); } /* Given x (not necessarily integral), and bid as output by zidealstarinit, * compute the vector of components on the generators bid[2]. * Assume (x,bid) = 1 and sgn is either NULL or nfsign_arch(x, bid) */ GEN ideallog_sgn(GEN nf, GEN x, GEN sgn, GEN bid) { zlog_S S; nf = checknf(nf); checkbid(bid); init_zlog(&S, bid); if (sgn && typ(x) == t_VEC) /* vector of elements and signatures */ { long i, l = lg(x); GEN y = cgetg(l, t_MAT); for (i = 1; i < l; i++) gel(y,i) = ideallog_i(nf, gel(x,i), gel(sgn,i), &S); return y; } return ideallog_i(nf, x, sgn, &S); } GEN ideallog(GEN nf, GEN x, GEN bid) { if (!nf) return Zideallog(bid, x); return ideallog_sgn(nf, x, NULL, bid); } /*************************************************************************/ /** **/ /** JOIN BID STRUCTURES, IDEAL LISTS **/ /** **/ /*************************************************************************/ /* bid1, bid2: for coprime modules m1 and m2 (without arch. part). * Output: bid for m1 m2 */ static GEN join_bid(GEN nf, GEN bid1, GEN bid2) { pari_sp av = avma; long nbgen, l1,l2; GEN I1,I2, G1,G2, sprk1,sprk2, cyc1,cyc2, sarch; GEN sprk, fa,fa2, U, cyc, y, u1 = NULL, x, gen; I1 = bid_get_ideal(bid1); I2 = bid_get_ideal(bid2); if (gequal1(gcoeff(I1,1,1))) return bid2; /* frequent trivial case */ G1 = bid_get_grp(bid1); G2 = bid_get_grp(bid2); x = idealmul(nf, I1,I2); fa = famat_mul_shallow(bid_get_fact(bid1), bid_get_fact(bid2)); fa2= famat_mul_shallow(bid_get_fact2(bid1), bid_get_fact2(bid2)); sprk1 = bid_get_sprk(bid1); sprk2 = bid_get_sprk(bid2); sprk = shallowconcat(sprk1, sprk2); cyc1 = abgrp_get_cyc(G1); l1 = lg(cyc1); cyc2 = abgrp_get_cyc(G2); l2 = lg(cyc2); gen = (lg(G1)>3 && lg(G2)>3)? gen_1: NULL; nbgen = l1+l2-2; cyc = ZV_snf_group(shallowconcat(cyc1,cyc2), &U, gen? &u1: NULL); if (nbgen) { GEN U1 = bid_get_U(bid1), U2 = bid_get_U(bid2); U1 = l1==1? const_vec(lg(sprk1), cgetg(1,t_MAT)) : ZM_ZMV_mul(vecslice(U, 1, l1-1), U1); U2 = l2==1? const_vec(lg(sprk2), cgetg(1,t_MAT)) : ZM_ZMV_mul(vecslice(U, l1, nbgen), U2); U = shallowconcat(U1, U2); } else U = const_vec(lg(sprk), cgetg(1,t_MAT)); if (gen) { GEN uv = zkchinese1init2(nf, I2, I1, x); gen = shallowconcat(zkVchinese1(gel(uv,1), abgrp_get_gen(G1)), zkVchinese1(gel(uv,2), abgrp_get_gen(G2))); } sarch = bid_get_sarch(bid1); /* trivial */ y = bid_grp(nf, u1, cyc, gen, x, sarch); x = mkvec2(x, bid_get_arch(bid1)); y = mkvec5(x, y, mkvec2(fa, fa2), mkvec2(sprk, sarch), U); return gerepilecopy(av,y); } typedef struct _ideal_data { GEN nf, emb, L, pr, prL, sgnU, archp; } ideal_data; /* z <- ( z | f(v[i])_{i=1..#v} ) */ static void concat_join(GEN *pz, GEN v, GEN (*f)(ideal_data*,GEN), ideal_data *data) { long i, nz, lv = lg(v); GEN z, Z; if (lv == 1) return; z = *pz; nz = lg(z)-1; *pz = Z = cgetg(lv + nz, typ(z)); for (i = 1; i <=nz; i++) gel(Z,i) = gel(z,i); Z += nz; for (i = 1; i < lv; i++) gel(Z,i) = f(data, gel(v,i)); } static GEN join_idealinit(ideal_data *D, GEN x) { return join_bid(D->nf, x, D->prL); } static GEN join_ideal(ideal_data *D, GEN x) { return idealmulpowprime(D->nf, x, D->pr, D->L); } static GEN join_unit(ideal_data *D, GEN x) { GEN bid = join_idealinit(D, gel(x,1)), u = gel(x,2), v = mkvec(D->emb); if (lg(u) != 1) v = shallowconcat(u, v); return mkvec2(bid, v); } /* flag & nf_GEN : generators, otherwise no * flag &2 : units, otherwise no * flag &4 : ideals in HNF, otherwise bid * flag &8 : omit ideals which cannot be conductors (pr^1 with Npr=2) */ static GEN Ideallist(GEN bnf, ulong bound, long flag) { const long cond = flag & 8; const long do_units = flag & 2, big_id = !(flag & 4); const long istar_flag = (flag & nf_GEN) | nf_INIT; pari_sp av, av0 = avma; long i, j; GEN nf, z, p, fa, id, BOUND, U, empty = cgetg(1,t_VEC); forprime_t S; ideal_data ID; GEN (*join_z)(ideal_data*, GEN) = do_units? &join_unit : (big_id? &join_idealinit: &join_ideal); nf = checknf(bnf); if ((long)bound <= 0) return empty; id = matid(nf_get_degree(nf)); if (big_id) id = Idealstar(nf,id, istar_flag); /* z[i] will contain all "objects" of norm i. Depending on flag, this means * an ideal, a bid, or a couple [bid, log(units)]. Such objects are stored * in vectors, computed one primary component at a time; join_z * reconstructs the global object */ BOUND = utoipos(bound); z = cgetg(bound+1,t_VEC); if (do_units) { U = bnf_build_units(bnf); gel(z,1) = mkvec( mkvec2(id, cgetg(1,t_VEC)) ); } else { U = NULL; /* -Wall */ gel(z,1) = mkvec(id); } for (i=2; i<=(long)bound; i++) gel(z,i) = empty; ID.nf = nf; p = cgetipos(3); u_forprime_init(&S, 2, bound); av = avma; while ((p[2] = u_forprime_next(&S))) { if (DEBUGLEVEL>1) { err_printf("%ld ",p[2]); err_flush(); } fa = idealprimedec_limit_norm(nf, p, BOUND); for (j=1; j1) pari_warn(warnmem,"Ideallist"); z = gerepilecopy(av, z); } } return gerepilecopy(av0, z); } GEN ideallist0(GEN bnf,long bound, long flag) { if (flag<0 || flag>15) pari_err_FLAG("ideallist"); return Ideallist(bnf,bound,flag); } GEN ideallist(GEN bnf,long bound) { return Ideallist(bnf,bound,4); } /* bid = for module m (without arch. part), arch = archimedean part. * Output: bid for [m,arch] */ static GEN join_bid_arch(GEN nf, GEN bid, GEN archp) { pari_sp av = avma; GEN G, U; GEN sprk, cyc, y, u1 = NULL, x, sarch, gen; checkbid(bid); G = bid_get_grp(bid); x = bid_get_ideal(bid); sarch = nfarchstar(nf, bid_get_ideal(bid), archp); sprk = bid_get_sprk(bid); gen = (lg(G)>3)? gel(G,3): NULL; cyc = diagonal_shallow(shallowconcat(gel(G,2), sarch_get_cyc(sarch))); cyc = ZM_snf_group(cyc, &U, gen? &u1: NULL); y = bid_grp(nf, u1, cyc, gen, x, sarch); U = split_U(U, sprk); y = mkvec5(mkvec2(x, archp), y, gel(bid,3), mkvec2(sprk, sarch), U); return gerepilecopy(av,y); } static GEN join_arch(ideal_data *D, GEN x) { return join_bid_arch(D->nf, x, D->archp); } static GEN join_archunit(ideal_data *D, GEN x) { GEN bid = join_arch(D, gel(x,1)), u = gel(x,2), v = mkvec(D->emb); if (lg(u) != 1) v = shallowconcat(u, v); return mkvec2(bid, v); } /* L from ideallist, add archimedean part */ GEN ideallistarch(GEN bnf, GEN L, GEN arch) { pari_sp av; long i, j, l = lg(L), lz; GEN v, z, V; ideal_data ID; GEN (*join_z)(ideal_data*, GEN); if (typ(L) != t_VEC) pari_err_TYPE("ideallistarch",L); if (l == 1) return cgetg(1,t_VEC); z = gel(L,1); if (typ(z) != t_VEC) pari_err_TYPE("ideallistarch",z); z = gel(z,1); /* either a bid or [bid,U] */ ID.nf = checknf(bnf); ID.archp = vec01_to_indices(arch); if (lg(z) == 3) { /* the latter: do units */ if (typ(z) != t_VEC) pari_err_TYPE("ideallistarch",z); ID.emb = zm_to_ZM( rowpermute(nfsign_units(bnf,NULL,1), ID.archp) ); join_z = &join_archunit; } else join_z = &join_arch; av = avma; V = cgetg(l, t_VEC); for (i = 1; i < l; i++) { z = gel(L,i); lz = lg(z); gel(V,i) = v = cgetg(lz,t_VEC); for (j=1; j1; k++,l-=2) { av = avma; a = diviuuexact(muluui(l, l-1, a), 4*k, n-k); togglesign(a); a = gerepileuptoint(av, a); gel(r--,0) = a; gel(r--,0) = gen_0; } q[1] = evalsigne(1) | evalvarn(v); return q; } static void polchebyshev1_eval_aux(long n, GEN x, GEN *pt1, GEN *pt2) { GEN t1, t2, b; if (n == 1) { *pt1 = gen_1; *pt2 = x; return; } if (n == 0) { *pt1 = x; *pt2 = gen_1; return; } polchebyshev1_eval_aux((n+1) >> 1, x, &t1, &t2); b = gsub(gmul(gmul2n(t1,1), t2), x); if (odd(n)) { *pt1 = gadd(gmul2n(gsqr(t1), 1), gen_m1); *pt2 = b; } else { *pt1 = b; *pt2 = gadd(gmul2n(gsqr(t2), 1), gen_m1); } } static GEN polchebyshev1_eval(long n, GEN x) { GEN t1, t2; long i, v; pari_sp av; if (n < 0) n = -n; if (n==0) return gen_1; if (n==1) return gcopy(x); av = avma; v = u_lvalrem(n, 2, (ulong*)&n); polchebyshev1_eval_aux((n+1)>>1, x, &t1, &t2); if (n != 1) t2 = gsub(gmul(gmul2n(t1,1), t2), x); for (i = 1; i <= v; i++) t2 = gadd(gmul2n(gsqr(t2), 1), gen_m1); return gerepileupto(av, t2); } /* Chebychev polynomial of the second kind U(n,x): the coefficient in front of * x^(n-2*m) is (-1)^m * 2^(n-2m)*(n-m)!/m!/(n-2m)! for m=0,1,...,n/2 */ GEN polchebyshev2(long n, long v) { pari_sp av; GEN q, a, r; long m; int neg = 0; if (v<0) v = 0; /* polchebyshev(-n,2) = -polchebyshev(n-2,2) */ if (n < 0) { if (n == -1) return zeropol(v); neg = 1; n = -n-2; } if (n==0) return neg ? scalar_ZX_shallow(gen_m1, v): pol_1(v); q = cgetg(n+3, t_POL); r = q + n+2; a = int2n(n); if (neg) togglesign(a); gel(r--,0) = a; gel(r--,0) = gen_0; for (m=1; 2*m<= n; m++) { av = avma; a = diviuuexact(muluui(n-2*m+2, n-2*m+1, a), 4*m, n-m+1); togglesign(a); a = gerepileuptoint(av, a); gel(r--,0) = a; gel(r--,0) = gen_0; } q[1] = evalsigne(1) | evalvarn(v); return q; } static void polchebyshev2_eval_aux(long n, GEN x, GEN *pu1, GEN *pu2) { GEN u1, u2, u, mu1; if (n == 1) { *pu1 = gen_1; *pu2 = gmul2n(x,1); return; } if (n == 0) { *pu1 = gen_0; *pu2 = gen_1; return; } polchebyshev2_eval_aux(n >> 1, x, &u1, &u2); mu1 = gneg(u1); u = gmul(gadd(u2,u1), gadd(u2,mu1)); if (odd(n)) { *pu1 = u; *pu2 = gmul(gmul2n(u2,1), gadd(gmul(x,u2), mu1)); } else { *pu2 = u; *pu1 = gmul(gmul2n(u1,1), gadd(u2, gmul(x,mu1))); } } static GEN polchebyshev2_eval(long n, GEN x) { GEN u1, u2, mu1; long neg = 0; pari_sp av; if (n < 0) { if (n == -1) return gen_0; neg = 1; n = -n-2; } if (n==0) return neg ? gen_m1: gen_1; av = avma; polchebyshev2_eval_aux(n>>1, x, &u1, &u2); mu1 = gneg(u1); if (odd(n)) u2 = gmul(gmul2n(u2,1), gadd(gmul(x,u2), mu1)); else u2 = gmul(gadd(u2,u1), gadd(u2,mu1)); if (neg) u2 = gneg(u2); return gerepileupto(av, u2); } GEN polchebyshev(long n, long kind, long v) { switch (kind) { case 1: return polchebyshev1(n, v); case 2: return polchebyshev2(n, v); default: pari_err_FLAG("polchebyshev"); } return NULL; /* LCOV_EXCL_LINE */ } GEN polchebyshev_eval(long n, long kind, GEN x) { if (!x) return polchebyshev(n, kind, 0); if (gequalX(x)) return polchebyshev(n, kind, varn(x)); switch (kind) { case 1: return polchebyshev1_eval(n, x); case 2: return polchebyshev2_eval(n, x); default: pari_err_FLAG("polchebyshev"); } return NULL; /* LCOV_EXCL_LINE */ } /* Hermite polynomial H(n,x): H(n+1) = 2x H(n) - 2n H(n-1) * The coefficient in front of x^(n-2*m) is * (-1)^m * n! * 2^(n-2m)/m!/(n-2m)! for m=0,1,...,n/2.. */ GEN polhermite(long n, long v) { long m; pari_sp av; GEN q,a,r; if (v<0) v = 0; if (n < 0) pari_err_DOMAIN("polhermite", "degree", "<", gen_0, stoi(n)); if (n==0) return pol_1(v); q = cgetg(n+3, t_POL); r = q + n+2; a = int2n(n); gel(r--,0) = a; gel(r--,0) = gen_0; for (m=1; 2*m<= n; m++) { av = avma; a = diviuexact(muluui(n-2*m+2, n-2*m+1, a), 4*m); togglesign(a); gel(r--,0) = a = gerepileuptoint(av, a); gel(r--,0) = gen_0; } q[1] = evalsigne(1) | evalvarn(v); return q; } GEN polhermite_eval(long n, GEN x) { long i; pari_sp av, av2; GEN x2, u, v; if (!x) return polhermite(n, 0); if (gequalX(x)) return polhermite(n, varn(x)); if (n==0) return gen_1; if (n==1) return gmul2n(x,1); av = avma; x2 = gmul2n(x,1); v = gen_1; u = x2; av2= avma; for (i=1; i1; k++,l-=2) { /* l = n-2*k+2 */ av = avma; a = diviuuexact(muluui(l, l-1, a), 2*k, n+l-1); togglesign(a); a = gerepileuptoint(av, a); gel(r--,0) = a; gel(r--,0) = gen_0; } q[1] = evalsigne(1) | evalvarn(v); return gerepileupto(av, gmul2n(q,-n)); } GEN pollegendre_eval(long n, GEN x) { long i; pari_sp av; GEN u, v; if (!x) return pollegendre(n, 0); if (gequalX(x)) return pollegendre(n, varn(x)); /* pollegendre(-n) = pollegendre(n-1) */ if (n < 0) n = -n-1; if (n==0) return gen_1; if (n==1) return gcopy(x); av = avma; v = gen_1; u = x; for (i=1; i 1) { qpow = new_chunk(I+1); gel(qpow,2)=q; } for (j=3; j<=I; j++) gel(qpow,j) = gmul(q, gel(qpow,j-1)); } for (i=1; i<=n; i++) { I = (i+1)/2; gcoeff(m,i,1)= gen_1; if (q) { for (j=2; j<=I; j++) gcoeff(m,i,j) = gadd(gmul(gel(qpow,j),gcoeff(m,i-1,j)), gcoeff(m,i-1,j-1)); } else { for (j=2; j<=I; j++) gcoeff(m,i,j) = addii(gcoeff(m,i-1,j), gcoeff(m,i-1,j-1)); } for ( ; j<=i; j++) gcoeff(m,i,j) = gcoeff(m,i,i+1-j); for ( ; j<=n; j++) gcoeff(m,i,j) = gen_0; } return gerepilecopy(av, m); } /******************************************************************/ /** **/ /** PRECISION CHANGES **/ /** **/ /******************************************************************/ GEN gprec(GEN x, long d) { pari_sp av = avma; if (d <= 0) pari_err_DOMAIN("gprec", "precision", "<=", gen_0, stoi(d)); return gerepilecopy(av, gprec_w(x, ndec2prec(d))); } /* not GC-safe; precision given in word length (including codewords) */ GEN gprec_w(GEN x, long pr) { long lx, i; GEN y; switch(typ(x)) { case t_REAL: if (signe(x)) return realprec(x) != pr? rtor(x,pr): x; i = -prec2nbits(pr); if (i < expo(x)) return real_0_bit(i); y = cgetr(2); y[1] = x[1]; return y; case t_COMPLEX: y = cgetg(3, t_COMPLEX); gel(y,1) = gprec_w(gel(x,1),pr); gel(y,2) = gprec_w(gel(x,2),pr); break; case t_POL: case t_SER: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i pr)? rtor(x,pr): x; case t_COMPLEX: y = cgetg(3, t_COMPLEX); gel(y,1) = gprec_wtrunc(gel(x,1),pr); gel(y,2) = gprec_wtrunc(gel(x,2),pr); break; case t_POL: case t_SER: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i1) pari_warn(warnmem,"dirmul, %ld/%ld",j,nx); z = gerepilecopy(av2,z); } } return gerepilecopy(av,z); } GEN dirdiv(GEN x, GEN y) { pari_sp av = avma, av2; long nx,ny,nz, dx,dy, i,j,k; GEN p1; if (typ(x)!=t_VEC) pari_err_TYPE("dirdiv",x); if (typ(y)!=t_VEC) pari_err_TYPE("dirdiv",y); dx = dirval(x); nx = lg(x)-1; dy = dirval(y); ny = lg(y)-1; if (dy != 1 || !ny) pari_err_INV("dirdiv",y); nz = minss(nx,ny*dx); p1 = gel(y,1); if (gequal1(p1)) p1 = NULL; else y = gdiv(y,p1); y = RgV_kill0(y); av2 = avma; x = p1 ? gdiv(x,p1): leafcopy(x); for (j=1; j1) pari_warn(warnmem,"dirdiv, %ld/%ld",j,nz); x = gerepilecopy(av2,x); } } return gerepilecopy(av,x); } /*******************************************************************/ /** **/ /** COMBINATORICS **/ /** **/ /*******************************************************************/ /** BINOMIAL COEFFICIENTS **/ /*******************************************************************/ GEN binomialuu(ulong n, ulong k) { pari_sp ltop = avma; GEN z; if (k > n) return gen_0; k = minuu(k,n-k); if (!k) return gen_1; if (k == 1) return utoipos(n); z = diviiexact(mulu_interval(n-k+1, n), mulu_interval(2UL, k)); return gerepileuptoint(ltop,z); } GEN binomial(GEN n, long k) { long i, prec; pari_sp av; GEN y; if (k <= 1) { if (is_noncalc_t(typ(n))) pari_err_TYPE("binomial",n); if (k < 0) return gen_0; if (k == 0) return gen_1; return gcopy(n); } av = avma; if (typ(n) == t_INT) { if (signe(n) > 0) { GEN z = subiu(n,k); if (cmpis(z,k) < 0) { k = itos(z); avma = av; if (k <= 1) { if (k < 0) return gen_0; if (k == 0) return gen_1; return icopy(n); } } } /* k > 1 */ if (lgefint(n) == 3 && signe(n) > 0) { y = binomialuu(itou(n),(ulong)k); return gerepileupto(av, y); } else { y = cgetg(k+1,t_VEC); for (i=1; i<=k; i++) gel(y,i) = subiu(n,i-1); y = ZV_prod(y); } y = diviiexact(y, mpfact(k)); return gerepileuptoint(av, y); } prec = precision(n); if (prec && k > 200 + 0.8*prec2nbits(prec)) { GEN A = mpfactr(k, prec), B = ggamma(gsubgs(n,k-1), prec); return gerepileupto(av, gdiv(ggamma(gaddgs(n,1), prec), gmul(A,B))); } y = cgetg(k+1,t_VEC); for (i=1; i<=k; i++) gel(y,i) = gsubgs(n,i-1); return gerepileupto(av, gdiv(RgV_prod(y), mpfact(k))); } GEN binomial0(GEN x, GEN k) { if (!k) { if (typ(x) != t_INT || signe(x) < 0) pari_err_TYPE("binomial", x); return vecbinomial(itos(x)); } if (typ(k) != t_INT) pari_err_TYPE("binomial", k); return binomial(x, itos(k)); } /* Assume n >= 0, return bin, bin[k+1] = binomial(n, k) */ GEN vecbinomial(long n) { long d, k; GEN C; if (!n) return mkvec(gen_1); C = cgetg(n+2, t_VEC) + 1; /* C[k] = binomial(n, k) */ gel(C,0) = gen_1; gel(C,1) = utoipos(n); d = (n + 1) >> 1; for (k=2; k <= d; k++) { pari_sp av = avma; gel(C,k) = gerepileuptoint(av, diviuexact(mului(n-k+1, gel(C,k-1)), k)); } for ( ; k <= n; k++) gel(C,k) = gel(C,n-k); return C - 1; } /********************************************************************/ /** STIRLING NUMBERS **/ /********************************************************************/ /* Stirling number of the 2nd kind. The number of ways of partitioning a set of n elements into m non-empty subsets. */ GEN stirling2(ulong n, ulong m) { pari_sp av = avma; GEN s, bmk; ulong k; if (n==0) return (m == 0)? gen_1: gen_0; if (m > n || m == 0) return gen_0; if (m==n) return gen_1; /* k = 0 */ bmk = gen_1; s = powuu(m, n); for (k = 1; k <= ((m-1)>>1); ++k) { /* bmk = binomial(m, k) */ GEN c, kn, mkn; bmk = diviuexact(mului(m-k+1, bmk), k); kn = powuu(k, n); mkn = powuu(m-k, n); c = odd(m)? subii(mkn,kn): addii(mkn,kn); c = mulii(bmk, c); s = odd(k)? subii(s, c): addii(s, c); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"stirling2"); gerepileall(av, 2, &s, &bmk); } } /* k = m/2 */ if (!odd(m)) { GEN c; bmk = diviuexact(mului(k+1, bmk), k); c = mulii(bmk, powuu(k,n)); s = odd(k)? subii(s, c): addii(s, c); } return gerepileuptoint(av, diviiexact(s, mpfact(m))); } /* Stirling number of the first kind. Up to the sign, the number of permutations of n symbols which have exactly m cycles. */ GEN stirling1(ulong n, ulong m) { pari_sp ltop=avma; ulong k; GEN s, t; if (n < m) return gen_0; else if (n==m) return gen_1; /* t = binomial(n-1+k, m-1) * binomial(2n-m, n-m-k) */ /* k = n-m > 0 */ t = binomialuu(2*n-m-1, m-1); s = mulii(t, stirling2(2*(n-m), n-m)); if (odd(n-m)) togglesign(s); for (k = n-m-1; k > 0; --k) { GEN c; t = diviuuexact(muluui(n-m+k+1, n+k+1, t), n+k, n-m-k); c = mulii(t, stirling2(n-m+k, k)); s = odd(k)? subii(s, c): addii(s, c); if ((k & 0x1f) == 0) { t = gerepileuptoint(ltop, t); s = gerepileuptoint(avma, s); } } return gerepileuptoint(ltop, s); } GEN stirling(long n, long m, long flag) { if (n < 0) pari_err_DOMAIN("stirling", "n", "<", gen_0, stoi(n)); if (m < 0) pari_err_DOMAIN("stirling", "m", "<", gen_0, stoi(m)); switch (flag) { case 1: return stirling1((ulong)n,(ulong)m); case 2: return stirling2((ulong)n,(ulong)m); default: pari_err_FLAG("stirling"); } return NULL; /*LCOV_EXCL_LINE*/ } /*******************************************************************/ /** **/ /** RECIPROCAL POLYNOMIAL **/ /** **/ /*******************************************************************/ /* return coefficients s.t x = x_0 X^n + ... + x_n */ GEN polrecip(GEN x) { long tx = typ(x); if (is_scalar_t(tx)) return gcopy(x); if (tx != t_POL) pari_err_TYPE("polrecip",x); return RgX_recip(x); } /********************************************************************/ /** **/ /** POLYNOMIAL INTERPOLATION **/ /** **/ /********************************************************************/ /* allow X = NULL for [1,...,n] */ GEN RgV_polint(GEN X, GEN Y, long v) { pari_sp av0 = avma, av; GEN Q, P = NULL; long i, l = lg(Y); if (!X) { X = cgetg(l, t_VEC); for (i=1; i1) pari_warn(warnmem,"FpV_polint"); P = gerepileupto(av, P); } } if (!P) { avma = av; return zeropol(v); } return gerepileupto(av0, P); } /* X,Y are "spec" GEN vectors with n > 0 components ( at X[0], ... X[n-1] ) */ GEN polint_i(GEN X, GEN Y, GEN x, long n, GEN *ptdy) { long i, m, ns = 0; pari_sp av = avma; GEN y, c, d, dy = NULL; /* gcc -Wall */ if (n == 1) { if (ptdy) *ptdy = gen_0; return gmul(gel(Y,0), Rg_get_1(x)); } if (!X) { X = cgetg(n+1, t_VEC); for (i=1; i<=n; i++) gel(X,i) = utoipos(i); X++; } switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: case t_QUAD: { GEN D = NULL; for (i=0; i 0 && (!t || gequalX(t))) return RgV_polint(X, Y, vt); av = avma; /* first interpolate in high priority variable, then substitute t */ v0 = fetch_var_higher(); P = RgV_polint(X, Y, v0); P = gsubst(P, v0, t? t: pol_x(0)); (void)delete_var(); return gerepileupto(av, P); } /* numerical interpolation */ if (lx == 1) return Rg_get_0(t); return polint_i(X? X+1: NULL,Y+1,t,lx-1,ptdy); } /********************************************************************/ /** **/ /** MODREVERSE **/ /** **/ /********************************************************************/ static void err_reverse(GEN x, GEN T) { pari_err_DOMAIN("modreverse","deg(minpoly(z))", "<", stoi(degpol(T)), mkpolmod(x,T)); } /* return y such that Mod(y, charpoly(Mod(a,T)) = Mod(a,T) */ GEN RgXQ_reverse(GEN a, GEN T) { pari_sp av = avma; long n = degpol(T); GEN y; if (n <= 1) { if (n <= 0) return gcopy(a); return gerepileupto(av, gneg(gdiv(gel(T,2), gel(T,3)))); } if (typ(a) != t_POL || !signe(a)) err_reverse(a,T); y = RgXV_to_RgM(RgXQ_powers(a,n-1,T), n); y = RgM_solve(y, col_ei(n, 2)); if (!y) err_reverse(a,T); return gerepilecopy(av, RgV_to_RgX(y, varn(T))); } GEN QXQ_reverse(GEN a, GEN T) { pari_sp av = avma; long n = degpol(T); GEN y; if (n <= 1) { if (n <= 0) return gcopy(a); return gerepileupto(av, gneg(gdiv(gel(T,2), gel(T,3)))); } if (typ(a) != t_POL || !signe(a)) err_reverse(a,T); if (gequalX(a)) return gcopy(a); y = RgXV_to_RgM(QXQ_powers(a,n-1,T), n); y = QM_gauss(y, col_ei(n, 2)); if (!y) err_reverse(a,T); return gerepilecopy(av, RgV_to_RgX(y, varn(T))); } GEN modreverse(GEN x) { long v, n; GEN T, a; if (typ(x)!=t_POLMOD) pari_err_TYPE("modreverse",x); T = gel(x,1); n = degpol(T); if (n <= 0) return gcopy(x); a = gel(x,2); v = varn(T); retmkpolmod(RgXQ_reverse(a, T), (n==1)? gsub(pol_x(v), a): RgXQ_charpoly(a, T, v)); } /********************************************************************/ /** **/ /** MERGESORT **/ /** **/ /********************************************************************/ static int cmp_small(GEN x, GEN y) { long a = (long)x, b = (long)y; return a>b? 1: (a= lx) pari_err_TYPE("lexicographic vecsort, index too large", stoi(c)); s = lexcmp(gel(x,c), gel(y,c)); if (s) return s; } return 0; } /* return permutation sorting v[1..n], removing duplicates. Assume n > 0 */ static GEN gen_sortspec_uniq(GEN v, long n, void *E, int (*cmp)(void*,GEN,GEN)) { pari_sp av; long NX, nx, ny, m, ix, iy, i; GEN x, y, w, W; int s; switch(n) { case 1: return mkvecsmall(1); case 2: s = cmp(E,gel(v,1),gel(v,2)); if (s < 0) return mkvecsmall2(1,2); else if (s > 0) return mkvecsmall2(2,1); return mkvecsmall(1); case 3: s = cmp(E,gel(v,1),gel(v,2)); if (s < 0) { s = cmp(E,gel(v,2),gel(v,3)); if (s < 0) return mkvecsmall3(1,2,3); else if (s == 0) return mkvecsmall2(1,2); s = cmp(E,gel(v,1),gel(v,3)); if (s < 0) return mkvecsmall3(1,3,2); else if (s > 0) return mkvecsmall3(3,1,2); return mkvecsmall2(1,2); } else if (s > 0) { s = cmp(E,gel(v,1),gel(v,3)); if (s < 0) return mkvecsmall3(2,1,3); else if (s == 0) return mkvecsmall2(2,1); s = cmp(E,gel(v,2),gel(v,3)); if (s < 0) return mkvecsmall3(2,3,1); else if (s > 0) return mkvecsmall3(3,2,1); return mkvecsmall2(2,1); } else { s = cmp(E,gel(v,1),gel(v,3)); if (s < 0) return mkvecsmall2(1,3); else if (s == 0) return mkvecsmall(1); return mkvecsmall2(3,1); } } NX = nx = n>>1; ny = n-nx; av = avma; x = gen_sortspec_uniq(v, nx,E,cmp); nx = lg(x)-1; y = gen_sortspec_uniq(v+NX,ny,E,cmp); ny = lg(y)-1; w = cgetg(n+1, t_VECSMALL); m = ix = iy = 1; while (ix<=nx && iy<=ny) { s = cmp(E, gel(v,x[ix]), gel(v,y[iy]+NX)); if (s < 0) w[m++] = x[ix++]; else if (s > 0) w[m++] = y[iy++]+NX; else { w[m++] = x[ix++]; iy++; } } while (ix<=nx) w[m++] = x[ix++]; while (iy<=ny) w[m++] = y[iy++]+NX; avma = av; W = cgetg(m, t_VECSMALL); for (i = 1; i < m; i++) W[i] = w[i]; return W; } /* return permutation sorting v[1..n]. Assume n > 0 */ static GEN gen_sortspec(GEN v, long n, void *E, int (*cmp)(void*,GEN,GEN)) { long nx, ny, m, ix, iy; GEN x, y, w; switch(n) { case 1: (void)cmp(E,gel(v,1),gel(v,1)); /* check for type error */ return mkvecsmall(1); case 2: return cmp(E,gel(v,1),gel(v,2)) <= 0? mkvecsmall2(1,2) : mkvecsmall2(2,1); case 3: if (cmp(E,gel(v,1),gel(v,2)) <= 0) { if (cmp(E,gel(v,2),gel(v,3)) <= 0) return mkvecsmall3(1,2,3); return (cmp(E,gel(v,1),gel(v,3)) <= 0)? mkvecsmall3(1,3,2) : mkvecsmall3(3,1,2); } else { if (cmp(E,gel(v,1),gel(v,3)) <= 0) return mkvecsmall3(2,1,3); return (cmp(E,gel(v,2),gel(v,3)) <= 0)? mkvecsmall3(2,3,1) : mkvecsmall3(3,2,1); } } nx = n>>1; ny = n-nx; w = cgetg(n+1,t_VECSMALL); x = gen_sortspec(v, nx,E,cmp); y = gen_sortspec(v+nx,ny,E,cmp); m = ix = iy = 1; while (ix<=nx && iy<=ny) if (cmp(E, gel(v,x[ix]), gel(v,y[iy]+nx))<=0) w[m++] = x[ix++]; else w[m++] = y[iy++]+nx; while (ix<=nx) w[m++] = x[ix++]; while (iy<=ny) w[m++] = y[iy++]+nx; avma = (pari_sp)w; return w; } static void init_sort(GEN *x, long *tx, long *lx) { *tx = typ(*x); if (*tx == t_LIST) { if (list_typ(*x)!=t_LIST_RAW) pari_err_TYPE("sort",*x); *x = list_data(*x); *lx = *x? lg(*x): 1; } else { if (!is_matvec_t(*tx) && *tx != t_VECSMALL) pari_err_TYPE("gen_sort",*x); *lx = lg(*x); } } /* (x o y)[1..lx-1], destroy y */ INLINE GEN sort_extract(GEN x, GEN y, long tx, long lx) { long i; switch(tx) { case t_VECSMALL: for (i=1; i (cmp_REV|cmp_LEX|cmp_IND|cmp_UNIQ)) pari_err_FLAG("vecsort"); if (!CMP) { /* wrt key: precompute all values, O(n) calls instead of O(n log n) */ pari_sp av = avma; GEN v, y; long i, tx, lx; init_sort(&x, &tx, &lx); if (lx == 1) return flag&cmp_IND? cgetg(1,t_VECSMALL): triv_sort(tx); v = cgetg(lx, t_VEC); for (i = 1; i < lx; i++) gel(v,i) = closure_callgen1(k, gel(x,i)); y = vecsort0(v, NULL, flag | cmp_IND); y = flag&cmp_IND? y: sort_extract(x, y, tx, lg(y)); return gerepileupto(av, y); } if (flag&cmp_UNIQ) x = flag&cmp_IND? gen_indexsort_uniq(x, E, CMP): gen_sort_uniq(x, E, CMP); else x = flag&cmp_IND? gen_indexsort(x, E, CMP): gen_sort(x, E, CMP); if (flag & cmp_REV) { /* reverse order */ GEN y = x; if (typ(x)==t_LIST) { y = list_data(x); if (!y) return x; } vecreverse_inplace(y); } return x; } GEN indexsort(GEN x) { return gen_indexsort(x, (void*)&gcmp, cmp_nodata); } GEN indexlexsort(GEN x) { return gen_indexsort(x, (void*)&lexcmp, cmp_nodata); } GEN indexvecsort(GEN x, GEN k) { if (typ(k) != t_VECSMALL) pari_err_TYPE("vecsort",k); return gen_indexsort(x, (void*)k, &veccmp); } GEN sort(GEN x) { return gen_sort(x, (void*)gcmp, cmp_nodata); } GEN lexsort(GEN x) { return gen_sort(x, (void*)lexcmp, cmp_nodata); } GEN vecsort(GEN x, GEN k) { if (typ(k) != t_VECSMALL) pari_err_TYPE("vecsort",k); return gen_sort(x, (void*)k, &veccmp); } /* adapted from gen_search; don't export: keys of T[i] should be precomputed */ static long key_search(GEN T, GEN x, GEN code) { long u = lg(T)-1, i, l, s; if (!u) return 0; l = 1; x = closure_callgen1(code, x); do { i = (l+u)>>1; s = lexcmp(x, closure_callgen1(code, gel(T,i))); if (!s) return i; if (s<0) u=i-1; else l=i+1; } while (u>=l); return 0; } long vecsearch(GEN v, GEN x, GEN k) { pari_sp av = avma; void *E; int (*CMP)(void*,GEN,GEN) = sort_function(&E, v, k); long r, tv = typ(v); if (tv == t_VECSMALL) x = (GEN)itos(x); else if (!is_matvec_t(tv)) pari_err_TYPE("vecsearch", v); r = CMP? gen_search(v, x, 0, E, CMP): key_search(v, x, k); avma = av; return r; } GEN ZV_indexsort(GEN L) { return gen_indexsort(L, (void*)&cmpii, &cmp_nodata); } GEN ZV_sort(GEN L) { return gen_sort(L, (void*)&cmpii, &cmp_nodata); } GEN ZV_sort_uniq(GEN L) { return gen_sort_uniq(L, (void*)&cmpii, &cmp_nodata); } void ZV_sort_inplace(GEN L) { gen_sort_inplace(L, (void*)&cmpii, &cmp_nodata,NULL); } /********************************************************************/ /** SEARCH IN SORTED VECTOR **/ /********************************************************************/ /* index of x in table T, 0 otherwise */ long tablesearch(GEN T, GEN x, int (*cmp)(GEN,GEN)) { long l = 1, u = lg(T)-1, i, s; while (u>=l) { i = (l+u)>>1; s = cmp(x, gel(T,i)); if (!s) return i; if (s<0) u=i-1; else l=i+1; } return 0; } /* looks if x belongs to the set T and returns the index if yes, 0 if no */ long gen_search(GEN T, GEN x, long flag, void *data, int (*cmp)(void*,GEN,GEN)) { long u = lg(T)-1, i, l, s; if (!u) return flag? 1: 0; l = 1; do { i = (l+u)>>1; s = cmp(data, x, gel(T,i)); if (!s) return flag? 0: i; if (s<0) u=i-1; else l=i+1; } while (u>=l); if (!flag) return 0; return (s<0)? i: i+1; } long ZV_search(GEN x, GEN y) { return tablesearch(x, y, cmpii); } long zv_search(GEN x, long y) { return tablesearch(x, (GEN)y, cmp_small); } /********************************************************************/ /** COMPARISON FUNCTIONS **/ /********************************************************************/ int cmp_nodata(void *data, GEN x, GEN y) { int (*cmp)(GEN,GEN)=(int (*)(GEN,GEN)) data; return cmp(x,y); } /* assume x and y come from the same idealprimedec call (uniformizer unique) */ int cmp_prime_over_p(GEN x, GEN y) { long k = pr_get_f(x) - pr_get_f(y); /* diff. between residue degree */ return k? ((k > 0)? 1: -1) : ZV_cmp(pr_get_gen(x), pr_get_gen(y)); } int cmp_prime_ideal(GEN x, GEN y) { int k = cmpii(pr_get_p(x), pr_get_p(y)); return k? k: cmp_prime_over_p(x,y); } /* assume x and y are t_POL in the same variable whose coeffs can be * compared (used to sort polynomial factorizations) */ int gen_cmp_RgX(void *data, GEN x, GEN y) { int (*coeff_cmp)(GEN,GEN)=(int(*)(GEN,GEN))data; long i, lx = lg(x), ly = lg(y); int fl; if (lx > ly) return 1; if (lx < ly) return -1; for (i=lx-1; i>1; i--) if ((fl = coeff_cmp(gel(x,i), gel(y,i)))) return fl; return 0; } static int cmp_RgX_Rg(GEN x, GEN y) { long lx = lgpol(x), ly; if (lx > 1) return 1; ly = gequal0(y) ? 0:1; if (lx > ly) return 1; if (lx < ly) return -1; if (lx==0) return 0; return gcmp(gel(x,2), y); } int cmp_RgX(GEN x, GEN y) { if (typ(x) == t_POLMOD) x = gel(x,2); if (typ(y) == t_POLMOD) y = gel(y,2); if (typ(x) == t_POL) { if (typ(y) != t_POL) return cmp_RgX_Rg(x, y); } else { if (typ(y) != t_POL) return gcmp(x,y); return - cmp_RgX_Rg(y,x); } return gen_cmp_RgX((void*)&gcmp,x,y); } int cmp_Flx(GEN x, GEN y) { long i, lx = lg(x), ly = lg(y); if (lx > ly) return 1; if (lx < ly) return -1; for (i=lx-1; i>1; i--) if (uel(x,i) != uel(y,i)) return uel(x,i) 0) z[k++] = y[j++]; else { z[k++] = x[i++]; j++; } } while (i 0) z[k++] = y[j++]; else { z[k++] = x[i++]; j++; } } while (i 0) iy++; else { gel(z, iz++) = gel(x,ix); ix++; iy++; } } setlg(z,iz); return gerepilecopy(av,z); } GEN gen_setminus(GEN A, GEN B, int (*cmp)(GEN,GEN)) { pari_sp ltop = avma; long i = 1, j = 1, k = 1, lx = lg(A), ly = lg(B); GEN diff = cgetg(lx,t_VEC); while (i < lx && j < ly) switch ( cmp(gel(A,i),gel(B,j)) ) { case -1: gel(diff,k++) = gel(A,i++); break; case 1: j++; break; case 0: i++; break; } while (i < lx) gel(diff,k++) = gel(A,i++); setlg(diff,k); return gerepilecopy(ltop,diff); } GEN setminus(GEN x, GEN y) { if (typ(x) != t_VEC) pari_err_TYPE("setminus",x); if (typ(y) != t_VEC) pari_err_TYPE("setminus",y); return gen_setminus(x,y,cmp_universal); } GEN setbinop(GEN f, GEN x, GEN y) { pari_sp av = avma; long i, j, lx, ly, k = 1; GEN z; if (typ(f) != t_CLOSURE || closure_arity(f) != 2 || closure_is_variadic(f)) pari_err_TYPE("setbinop [function needs exactly 2 arguments]",f); lx = lg(x); if (typ(x) != t_VEC) pari_err_TYPE("setbinop", x); if (y == NULL) { /* assume x = y and f symmetric */ z = cgetg((((lx-1)*lx) >> 1) + 1, t_VEC); for (i = 1; i < lx; i++) for (j = i; j < lx; j++) gel(z, k++) = closure_callgen2(f, gel(x,i),gel(x,j)); } else { ly = lg(y); if (typ(y) != t_VEC) pari_err_TYPE("setbinop", y); z = cgetg((lx-1)*(ly-1) + 1, t_VEC); for (i = 1; i < lx; i++) for (j = 1; j < ly; j++) gel(z, k++) = closure_callgen2(f, gel(x,i),gel(y,j)); } return gerepileupto(av, gtoset(z)); } pari-2.11.2/src/basemath/polarit3.c0000644000175000017500000021156513447371554015461 0ustar billbill/* Copyright (C) 2000-2005 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /***********************************************************************/ /** **/ /** ARITHMETIC OPERATIONS ON POLYNOMIALS **/ /** (third part) **/ /** **/ /***********************************************************************/ #include "pari.h" #include "paripriv.h" /************************************************************************ ** ** ** Ring membership ** ** ** ************************************************************************/ struct charact { GEN q; int isprime; }; static void char_update_prime(struct charact *S, GEN p) { if (!S->isprime) { S->isprime = 1; S->q = p; } if (!equalii(p, S->q)) pari_err_MODULUS("characteristic", S->q, p); } static void char_update_int(struct charact *S, GEN n) { if (S->isprime) { if (dvdii(n, S->q)) return; pari_err_MODULUS("characteristic", S->q, n); } S->q = gcdii(S->q, n); } static void charact(struct charact *S, GEN x) { const long tx = typ(x); long i, l; switch(tx) { case t_INTMOD:char_update_int(S, gel(x,1)); break; case t_FFELT: char_update_prime(S, gel(x,4)); break; case t_COMPLEX: case t_QUAD: case t_POLMOD: case t_POL: case t_SER: case t_RFRAC: case t_VEC: case t_COL: case t_MAT: l = lg(x); for (i=lontyp[tx]; i < l; i++) charact(S,gel(x,i)); break; case t_LIST: x = list_data(x); if (x) charact(S, x); break; } } static void charact_res(struct charact *S, GEN x) { const long tx = typ(x); long i, l; switch(tx) { case t_INTMOD:char_update_int(S, gel(x,1)); break; case t_FFELT: char_update_prime(S, gel(x,4)); break; case t_PADIC: char_update_prime(S, gel(x,2)); break; case t_COMPLEX: case t_QUAD: case t_POLMOD: case t_POL: case t_SER: case t_RFRAC: case t_VEC: case t_COL: case t_MAT: l = lg(x); for (i=lontyp[tx]; i < l; i++) charact_res(S,gel(x,i)); break; case t_LIST: x = list_data(x); if (x) charact_res(S, x); break; } } GEN characteristic(GEN x) { struct charact S; S.q = gen_0; S.isprime = 0; charact(&S, x); return S.q; } GEN residual_characteristic(GEN x) { struct charact S; S.q = gen_0; S.isprime = 0; charact_res(&S, x); return S.q; } int Rg_is_Fp(GEN x, GEN *pp) { GEN mod; switch(typ(x)) { case t_INTMOD: mod = gel(x,1); if (!*pp) *pp = mod; else if (mod != *pp && !equalii(mod, *pp)) { if (DEBUGLEVEL) pari_warn(warner,"different moduli in Rg_is_Fp"); return 0; } return 1; case t_INT: return 1; default: return 0; } } int RgX_is_FpX(GEN x, GEN *pp) { long i, lx = lg(x); for (i=2; i 0 a t_INT, return lift(x * Mod(1,p)). * If x is an INTMOD, assume modulus is a multiple of p. */ GEN Rg_to_Fp(GEN x, GEN p) { if (lgefint(p) == 3) return utoi(Rg_to_Fl(x, uel(p,2))); switch(typ(x)) { case t_INT: return modii(x, p); case t_FRAC: { pari_sp av = avma; GEN z = modii(gel(x,1), p); if (z == gen_0) return gen_0; return gerepileuptoint(av, remii(mulii(z, Fp_inv(gel(x,2), p)), p)); } case t_PADIC: return padic_to_Fp(x, p); case t_INTMOD: { GEN q = gel(x,1), a = gel(x,2); if (equalii(q, p)) return icopy(a); if (!dvdii(q,p)) pari_err_MODULUS("Rg_to_Fp", q, p); return remii(a, p); } default: pari_err_TYPE("Rg_to_Fp",x); return NULL; /* LCOV_EXCL_LINE */ } } /* If x is a POLMOD, assume modulus is a multiple of T. */ GEN Rg_to_FpXQ(GEN x, GEN T, GEN p) { long ta, tx = typ(x), v = get_FpX_var(T); GEN a, b; if (is_const_t(tx)) { if (tx == t_FFELT) { GEN z = FF_to_FpXQ(x); setvarn(z, v); return z; } return scalar_ZX(degpol(T)? Rg_to_Fp(x, p): gen_0, v); } switch(tx) { case t_POLMOD: b = gel(x,1); a = gel(x,2); ta = typ(a); if (is_const_t(ta)) return scalar_ZX(degpol(T)? Rg_to_Fp(a, p): gen_0, v); b = RgX_to_FpX(b, p); if (varn(b) != v) break; a = RgX_to_FpX(a, p); if (ZX_equal(b,get_FpX_mod(T)) || signe(FpX_rem(b,T,p))==0) return FpX_rem(a, T, p); break; case t_POL: if (varn(x) != v) break; return FpX_rem(RgX_to_FpX(x,p), T, p); case t_RFRAC: a = Rg_to_FpXQ(gel(x,1), T,p); b = Rg_to_FpXQ(gel(x,2), T,p); return FpXQ_div(a,b, T,p); } pari_err_TYPE("Rg_to_FpXQ",x); return NULL; /* LCOV_EXCL_LINE */ } GEN RgX_to_FpX(GEN x, GEN p) { long i, l; GEN z = cgetg_copy(x, &l); z[1] = x[1]; for (i = 2; i < l; i++) gel(z,i) = Rg_to_Fp(gel(x,i), p); return FpX_renormalize(z, l); } GEN RgV_to_FpV(GEN x, GEN p) { pari_APPLY_type(t_VEC, Rg_to_Fp(gel(x,i), p)) } GEN RgC_to_FpC(GEN x, GEN p) { pari_APPLY_type(t_COL, Rg_to_Fp(gel(x,i), p)) } GEN RgM_to_FpM(GEN x, GEN p) { pari_APPLY_same(RgC_to_FpC(gel(x,i), p)) } GEN RgV_to_Flv(GEN x, ulong p) { pari_APPLY_ulong(Rg_to_Fl(gel(x,i), p)) } GEN RgM_to_Flm(GEN x, ulong p) { pari_APPLY_same(RgV_to_Flv(gel(x,i), p)) } GEN RgX_to_FpXQX(GEN x, GEN T, GEN p) { long i, l = lg(x); GEN z = cgetg(l, t_POL); z[1] = x[1]; for (i = 2; i < l; i++) gel(z,i) = Rg_to_FpXQ(gel(x,i), T,p); return FpXQX_renormalize(z, l); } GEN RgX_to_FqX(GEN x, GEN T, GEN p) { long i, l = lg(x); GEN z = cgetg(l, t_POL); z[1] = x[1]; if (T) for (i = 2; i < l; i++) gel(z,i) = Rg_to_FpXQ(gel(x,i), T, p); else for (i = 2; i < l; i++) gel(z,i) = Rg_to_Fp(gel(x,i), p); return FpXQX_renormalize(z, l); } GEN RgC_to_FqC(GEN x, GEN T, GEN p) { long i, l = lg(x); GEN z = cgetg(l, t_COL); if (T) for (i = 1; i < l; i++) gel(z,i) = Rg_to_FpXQ(gel(x,i), T, p); else for (i = 1; i < l; i++) gel(z,i) = Rg_to_Fp(gel(x,i), p); return z; } GEN RgM_to_FqM(GEN x, GEN T, GEN p) { pari_APPLY_same(RgC_to_FqC(gel(x, i), T, p)) } /* lg(V) > 1 */ GEN FpXV_FpC_mul(GEN V, GEN W, GEN p) { pari_sp av = avma; long i, l = lg(V); GEN z = ZX_Z_mul(gel(V,1),gel(W,1)); for(i=2; i 3) /* non-constant */ return FqX_Fq_mul_to_monic(z, Fq_inv(lc,T,p), T,p); /* constant */ lc = gel(lc,2); z = shallowcopy(z); gel(z, lg(z)-1) = lc; } /* lc a t_INT */ if (equali1(lc)) return z; return FqX_Fq_mul_to_monic(z, Fp_inv(lc,p), T,p); } GEN FqX_eval(GEN x, GEN y, GEN T, GEN p) { pari_sp av; GEN p1, r; long j, i=lg(x)-1; if (i<=2) return (i==2)? Fq_red(gel(x,2), T, p): gen_0; av=avma; p1=gel(x,i); /* specific attention to sparse polynomials (see poleval)*/ /*You've guessed it! It's a copy-paste(tm)*/ for (i--; i>=2; i=j-1) { for (j=i; !signe(gel(x,j)); j--) if (j==2) { if (i!=j) y = Fq_pow(y,utoipos(i-j+1), T, p); return gerepileupto(av, Fq_mul(p1,y, T, p)); } r = (i==j)? y: Fq_pow(y, utoipos(i-j+1), T, p); p1 = Fq_add(Fq_mul(p1,r,T,p), gel(x,j), T, p); } return gerepileupto(av, p1); } GEN FqXY_evalx(GEN Q, GEN x, GEN T, GEN p) { long i, lb = lg(Q); GEN z; if (!T) return FpXY_evalx(Q, x, p); z = cgetg(lb, t_POL); z[1] = Q[1]; for (i=2; iT, s->p); } static GEN _Fq_add(void *E, GEN x, GEN y) { (void) E; switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1)) { case 0: return addii(x,y); case 1: return ZX_Z_add(x,y); case 2: return ZX_Z_add(y,x); default: return ZX_add(x,y); } } static GEN _Fq_neg(void *E, GEN x) { (void) E; return typ(x)==t_POL?ZX_neg(x):negi(x); } static GEN _Fq_mul(void *E, GEN x, GEN y) { (void) E; switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1)) { case 0: return mulii(x,y); case 1: return ZX_Z_mul(x,y); case 2: return ZX_Z_mul(y,x); default: return ZX_mul(x,y); } } static GEN _Fq_inv(void *E, GEN x) { struct _Fq_field *s = (struct _Fq_field *)E; return Fq_inv(x,s->T,s->p); } static int _Fq_equal0(GEN x) { return signe(x)==0; } static GEN _Fq_s(void *E, long x) { (void) E; return stoi(x); } static const struct bb_field Fq_field={_Fq_red,_Fq_add,_Fq_mul,_Fq_neg, _Fq_inv,_Fq_equal0,_Fq_s}; const struct bb_field *get_Fq_field(void **E, GEN T, GEN p) { GEN z = new_chunk(sizeof(struct _Fq_field)); struct _Fq_field *e = (struct _Fq_field *) z; e->T = T; e->p = p; *E = (void*)e; return &Fq_field; } /*******************************************************************/ /* */ /* Fq[X] */ /* */ /*******************************************************************/ /* P(X + c) */ GEN FpX_translate(GEN P, GEN c, GEN p) { pari_sp av = avma; GEN Q, *R; long i, k, n; if (!signe(P) || !signe(c)) return ZX_copy(P); Q = leafcopy(P); R = (GEN*)(Q+2); n = degpol(P); for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"FpX_translate, i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } return gerepilecopy(av, FpX_renormalize(Q, lg(Q))); } /* P(X + c), c an Fq */ GEN FqX_translate(GEN P, GEN c, GEN T, GEN p) { pari_sp av = avma; GEN Q, *R; long i, k, n; /* signe works for t_(INT|POL) */ if (!signe(P) || !signe(c)) return RgX_copy(P); Q = leafcopy(P); R = (GEN*)(Q+2); n = degpol(P); for (i=1; i<=n; i++) { for (k=n-i; k1) pari_warn(warnmem,"FqX_translate, i = %ld/%ld", i,n); Q = gerepilecopy(av, Q); R = (GEN*)Q+2; } } return gerepilecopy(av, FpXQX_renormalize(Q, lg(Q))); } GEN FqV_roots_to_pol(GEN V, GEN T, GEN p, long v) { pari_sp ltop = avma; long k; GEN W; if (lgefint(p) == 3) { ulong pp = p[2]; GEN Tl = ZX_to_Flx(T, pp); GEN Vl = FqV_to_FlxV(V, T, p); Tl = FlxqV_roots_to_pol(Vl, Tl, pp, v); return gerepileupto(ltop, FlxX_to_ZXX(Tl)); } W = cgetg(lg(V),t_VEC); for(k=1; k < lg(V); k++) gel(W,k) = deg1pol_shallow(gen_1,Fq_neg(gel(V,k),T,p),v); return gerepileupto(ltop, FpXQXV_prod(W, T, p)); } GEN FqV_red(GEN x, GEN T, GEN p) { pari_APPLY_same(Fq_red(gel(x,i), T, p)) } GEN FqC_add(GEN x, GEN y, GEN T, GEN p) { if (!T) return FpC_add(x, y, p); pari_APPLY_type(t_COL, Fq_add(gel(x,i), gel(y,i), T, p)) } GEN FqC_sub(GEN x, GEN y, GEN T, GEN p) { if (!T) return FpC_sub(x, y, p); pari_APPLY_type(t_COL, Fq_sub(gel(x,i), gel(y,i), T, p)) } GEN FqC_Fq_mul(GEN x, GEN y, GEN T, GEN p) { if (!T) return FpC_Fp_mul(x, y, p); pari_APPLY_type(t_COL, Fq_mul(gel(x,i),y,T,p)) } GEN FqV_to_FlxV(GEN x, GEN T, GEN pp) { long vT = evalvarn(get_FpX_var(T)); ulong p = pp[2]; pari_APPLY_type(t_VEC, typ(gel(x,i))==t_INT? Z_to_Flx(gel(x,i), p, vT) : ZX_to_Flx(gel(x,i), p)) } GEN FqC_to_FlxC(GEN x, GEN T, GEN pp) { long vT = evalvarn(get_FpX_var(T)); ulong p = pp[2]; pari_APPLY_type(t_COL, typ(gel(x,i))==t_INT? Z_to_Flx(gel(x,i), p, vT) : ZX_to_Flx(gel(x,i), p)) } GEN FqM_to_FlxM(GEN x, GEN T, GEN p) { pari_APPLY_same(FqC_to_FlxC(gel(x,i), T, p)) } GEN FpXC_center(GEN x, GEN p, GEN pov2) { pari_APPLY_type(t_COL, FpX_center(gel(x,i), p, pov2)) } GEN FpXM_center(GEN x, GEN p, GEN pov2) { pari_APPLY_same(FpXC_center(gel(x,i), p, pov2)) } /*******************************************************************/ /* */ /* GENERIC CRT */ /* */ /*******************************************************************/ static long get_nbprimes(ulong bound, ulong *pt_start) { #ifdef LONG_IS_64BIT ulong pstart = 4611686018427388039UL; #else ulong pstart = 1073741827UL; #endif if (pt_start) *pt_start = pstart; return (bound/expu(pstart))+1; } static GEN primelist_disc(ulong *p, long n, GEN dB) { ulong u = 0; GEN P = cgetg(n+1, t_VECSMALL); long i; if (dB && typ(dB)==t_VECSMALL) { u = uel(dB,1); dB = NULL; } for (i=1; i <= n; i++, *p = unextprime(*p+1)) { if (dB && umodiu(dB, *p)==0) { i--; continue; } if (u && *p%u!=1) { i--; continue; } P[i] = *p; } return P; } void gen_inccrt(const char *str, GEN worker, GEN dB, long n, long mmin, ulong *p, GEN *pt_H, GEN *pt_mod, GEN crt(GEN, GEN, GEN*), GEN center(GEN, GEN, GEN)) { pari_sp av = avma; long m; GEN H, P, mod; pari_timer ti; if (!*p) (void) get_nbprimes(1, p); m = minss(mmin, n); if (DEBUGLEVEL > 4) { timer_start(&ti); err_printf("%s: nb primes: %ld\n",str, n); } if (m == 1) { GEN P = primelist_disc(p, n, dB); GEN done = closure_callgen1(worker, P); H = gel(done,1); mod = gel(done,2); if (!*pt_H && center) H = center(H, mod, shifti(mod,-1)); if (DEBUGLEVEL>4) timer_printf(&ti,"%s: modular", str); } else { long i, s = (n+m-1)/m, r = m - (m*s-n), di = 0; struct pari_mt pt; long pending = 0; H = cgetg(m+1, t_VEC); P = cgetg(m+1, t_VEC); mt_queue_start_lim(&pt, worker, m); for (i=1; i<=m || pending; i++) { GEN done; GEN pr = i <= m ? mkvec(primelist_disc(p, i<=r ? s: s-1, dB)): NULL; mt_queue_submit(&pt, i, pr); done = mt_queue_get(&pt, NULL, &pending); if (done) { di++; gel(H, di) = gel(done,1); gel(P, di) = gel(done,2); if (DEBUGLEVEL>5) err_printf("%ld%% ",100*di/m); } } mt_queue_end(&pt); if (DEBUGLEVEL>5) err_printf("\n"); if (DEBUGLEVEL>4) timer_printf(&ti,"%s: modular", str); H = crt(H, P, &mod); if (DEBUGLEVEL>4) timer_printf(&ti,"%s: chinese", str); } if (*pt_H) H = crt(mkvec2(*pt_H, H), mkvec2(*pt_mod, mod), &mod); *pt_H = H; *pt_mod = mod; gerepileall(av, 2, pt_H, pt_mod); } GEN gen_crt(const char *str, GEN worker, GEN dB, ulong bound, long mmin, GEN *pt_mod, GEN crt(GEN, GEN, GEN*), GEN center(GEN, GEN, GEN)) { ulong p = 0; GEN mod = gen_1, H = NULL; bound++; while ((ulong)expi(mod) < bound) { long n = get_nbprimes(bound-expi(mod), NULL); gen_inccrt(str, worker, dB, n, mmin, &p, &H, &mod, crt, center); } if (pt_mod) *pt_mod = mod; return H; } /*******************************************************************/ /* */ /* MODULAR GCD */ /* */ /*******************************************************************/ /* return z = a mod q, b mod p (p,q) = 1; qinv = 1/q mod p; a in ]-q,q] */ static GEN Fl_chinese_coprime(GEN a, ulong b, GEN q, ulong p, ulong qinv, GEN pq, GEN pq2) { ulong d, amod = umodiu(a, p); pari_sp av = avma; GEN ax; if (b == amod) return NULL; d = Fl_mul(Fl_sub(b, amod, p), qinv, p); /* != 0 */ if (d >= 1 + (p>>1)) ax = subii(a, mului(p-d, q)); else { ax = addii(a, mului(d, q)); /* in ]0, pq[ assuming a in ]-q,q[ */ if (cmpii(ax,pq2) > 0) ax = subii(ax,pq); } return gerepileuptoint(av, ax); } GEN Z_init_CRT(ulong Hp, ulong p) { return stoi(Fl_center(Hp, p, p>>1)); } GEN ZX_init_CRT(GEN Hp, ulong p, long v) { long i, l = lg(Hp), lim = (long)(p>>1); GEN H = cgetg(l, t_POL); H[1] = evalsigne(1) | evalvarn(v); for (i=2; i>1); GEN c, cp, H = cgetg(l, t_MAT); if (l==1) return H; m = lgcols(Hp); for (j=1; j lp) { /* degree decreases */ GEN x = cgetg(l, t_VECSMALL); for (i=1; i>1), n; H = cgetg(l, t_MAT); if (l==1) return H; m = lgcols(Hp); n = deg + 3; for (j=1; j da) { swapspec(a,b, da,db); } else if (!da) return; ind = 0; while (db) { GEN c = Flx_rem(a,b, p); a = b; b = c; dc = degpol(c); if (dc < 0) break; ind++; if (dc > dglist[ind]) dglist[ind] = dc; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"Flx_resultant_all"); gerepileall(av, 2, &a,&b); } db = dc; /* = degpol(b) */ } if (ind+1 > lg(dglist)) setlg(dglist,ind+1); avma = av; return; } /* assuming the PRS finishes on a degree 1 polynomial C0 + C1X, with * "generic" degree sequence as given by dglist, set *Ci and return * resultant(a,b). Modular version of Collins's subresultant */ static ulong Flx_resultant_all(GEN a, GEN b, long *C0, long *C1, GEN dglist, ulong p) { long da,db,dc, ind; ulong lb, res, g = 1UL, h = 1UL, ca = 1UL, cb = 1UL; int s = 1; pari_sp av = avma; *C0 = 1; *C1 = 0; if (lgpol(a)==0 || lgpol(b)==0) return 0; da = degpol(a); db = degpol(b); if (db > da) { swapspec(a,b, da,db); if (both_odd(da,db)) s = -s; } else if (!da) return 1; /* = a[2] ^ db, since 0 <= db <= da = 0 */ ind = 0; while (db) { /* sub-resultant algo., applied to ca * a and cb * b, ca,cb scalars, * da = deg a, db = deg b */ GEN c = Flx_rem(a,b, p); long delta = da - db; if (both_odd(da,db)) s = -s; lb = Fl_mul(b[db+2], cb, p); a = b; b = c; dc = degpol(c); ind++; if (dc != dglist[ind]) { avma = av; return 0; } /* degenerates */ if (g == h) { /* frequent */ ulong cc = Fl_mul(ca, Fl_powu(Fl_div(lb,g,p), delta+1, p), p); ca = cb; cb = cc; } else { ulong cc = Fl_mul(ca, Fl_powu(lb, delta+1, p), p); ulong ghdelta = Fl_mul(g, Fl_powu(h, delta, p), p); ca = cb; cb = Fl_div(cc, ghdelta, p); } da = db; /* = degpol(a) */ db = dc; /* = degpol(b) */ g = lb; if (delta == 1) h = g; /* frequent */ else h = Fl_mul(h, Fl_powu(Fl_div(g,h,p), delta, p), p); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"Flx_resultant_all"); gerepileall(av, 2, &a,&b); } } if (da > 1) return 0; /* Failure */ /* last non-constant polynomial has degree 1 */ *C0 = Fl_mul(ca, a[2], p); *C1 = Fl_mul(ca, a[3], p); res = Fl_mul(cb, b[2], p); if (s == -1) res = p - res; avma = av; return res; } /* Q a vector of polynomials representing B in Fp[X][Y], evaluate at X = x, * Return 0 in case of degree drop. */ static GEN FlxY_evalx_drop(GEN Q, ulong x, ulong p) { GEN z; long i, lb = lg(Q); ulong leadz = Flx_eval(leading_coeff(Q), x, p); long vs=mael(Q,2,1); if (!leadz) return zero_Flx(vs); z = cgetg(lb, t_VECSMALL); z[1] = vs; for (i=2; i=2; i--) { GEN c = gel(Q,i); z = FqX_Fq_mul(z, y, T, p); z = typ(c) == t_INT? FqX_Fq_add(z,c,T,p): FqX_add(z,c,T,p); } return gerepileupto(av, z); } static GEN ZX_norml1(GEN x) { long i, l = lg(x); GEN s; if (l == 2) return gen_0; s = gel(x, l-1); /* != 0 */ for (i = l-2; i > 1; i--) { GEN xi = gel(x,i); if (!signe(x)) continue; s = addii_sign(s,1, xi,1); } return s; } /* Interpolate at roots of 1 and use Hadamard bound for univariate resultant: * bound = N_2(A)^degpol B N_2(B)^degpol(A), where * N_2(A) = sqrt(sum (N_1(Ai))^2) * Return e such that Res(A, B) < 2^e */ ulong ZX_ZXY_ResBound(GEN A, GEN B, GEN dB) { pari_sp av = avma, av2; GEN a = gen_0, b = gen_0; long i , lA = lg(A), lB = lg(B); double loga, logb; for (i=2; i1) pari_warn(warnmem,"ZX_ZXY_ResBound i = %ld",i); a = gerepileupto(av, a); } } a = gerepileuptoint(av, a); av2 = avma; for (i=2; i1) pari_warn(warnmem,"ZX_ZXY_ResBound i = %ld",i); b = gerepileupto(av2, b); } } loga = dbllog2(a); logb = dbllog2(b); if (dB) logb -= 2 * dbllog2(dB); i = (long)((degpol(B) * loga + degpol(A) * logb) / 2); avma = av; return (i <= 0)? 1: 1 + (ulong)i; } /* return Res(a(Y), b(n,Y)) over Fp. la = leading_coeff(a) [for efficiency] */ static ulong Flx_FlxY_eval_resultant(GEN a, GEN b, ulong n, ulong p, ulong la) { GEN ev = FlxY_evalx(b, n, p); long drop = lg(b) - lg(ev); ulong r = Flx_resultant(a, ev, p); if (drop && la != 1) r = Fl_mul(r, Fl_powu(la, drop,p),p); return r; } static GEN FpX_FpXY_eval_resultant(GEN a, GEN b, GEN n, GEN p, GEN la, long db, long vX) { GEN ev = FpXY_evaly(b, n, p, vX); long drop = db-degpol(ev); GEN r = FpX_resultant(a, ev, p); if (drop && !gequal1(la)) r = Fp_mul(r, Fp_powu(la, drop,p),p); return r; } /* assume dres := deg(Res_X(a,b), Y) <= deg(a,X) * deg(b,Y) < p */ /* Return a Fly */ static GEN Flx_FlxY_resultant_polint(GEN a, GEN b, ulong p, long dres, long sx) { long i; ulong n, la = Flx_lead(a); GEN x = cgetg(dres+2, t_VECSMALL); GEN y = cgetg(dres+2, t_VECSMALL); /* Evaluate at dres+ 1 points: 0 (if dres even) and +/- n, so that P_n(X) = * P_{-n}(-X), where P_i is Lagrange polynomial: P_i(j) = delta_{i,j} */ for (i=0,n = 1; i < dres; n++) { x[++i] = n; y[i] = Flx_FlxY_eval_resultant(a,b, x[i], p,la); x[++i] = p-n; y[i] = Flx_FlxY_eval_resultant(a,b, x[i], p,la); } if (i == dres) { x[++i] = 0; y[i] = Flx_FlxY_eval_resultant(a,b, x[i], p,la); } return Flv_polint(x,y, p, sx); } static GEN FlxX_pseudorem(GEN x, GEN y, ulong p) { long vx = varn(x), dx, dy, dz, i, lx, dp; pari_sp av = avma, av2; if (!signe(y)) pari_err_INV("FlxX_pseudorem",y); (void)new_chunk(2); dx=degpol(x); x = RgX_recip_shallow(x)+2; dy=degpol(y); y = RgX_recip_shallow(y)+2; dz=dx-dy; dp = dz+1; av2 = avma; for (;;) { gel(x,0) = Flx_neg(gel(x,0), p); dp--; for (i=1; i<=dy; i++) gel(x,i) = Flx_add( Flx_mul(gel(y,0), gel(x,i), p), Flx_mul(gel(x,0), gel(y,i), p), p ); for ( ; i<=dx; i++) gel(x,i) = Flx_mul(gel(y,0), gel(x,i), p); do { x++; dx--; } while (dx >= 0 && lg(gel(x,0))==2); if (dx < dy) break; if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"FlxX_pseudorem dx = %ld >= %ld",dx,dy); gerepilecoeffs(av2,x,dx+1); } } if (dx < 0) return zero_Flx(0); lx = dx+3; x -= 2; x[0]=evaltyp(t_POL) | evallg(lx); x[1]=evalsigne(1) | evalvarn(vx); x = RgX_recip_shallow(x); if (dp) { /* multiply by y[0]^dp [beware dummy vars from FpX_FpXY_resultant] */ GEN t = Flx_powu(gel(y,0), dp, p); for (i=2; i1) pari_warn(warnmem,"FlxX_resultant, dr = %ld",dr); gerepileall(av2,4, &u, &v, &g, &h); } } z = gel(v,2); if (dv > 1) z = Flx_div(Flx_powu(z,dv,p), Flx_powu(h,dv-1,p), p); if (signh < 0) z = Flx_neg(z,p); return gerepileupto(av, z); } /* Warning: * This function switches between valid and invalid variable ordering*/ static GEN FlxY_to_FlyX(GEN b, long sv) { long i, n=-1; long sw = b[1]&VARNBITS; for(i=2;i= pp) z = FlxX_resultant(Fly_to_FlxY(a, sy), b, pp, sx); else z = Flx_FlxY_resultant_polint(a, b, pp, (ulong)dres, sy); return gerepileupto(ltop,z); } /* return a t_POL (in variable v >= 0) whose coeffs are the coeffs of b, * in variable v. This is an incorrect PARI object if initially varn(b) << v. * We could return a vector of coeffs, but it is convenient to have degpol() * and friends available. Even in that case, it will behave nicely with all * functions treating a polynomial as a vector of coeffs (eg poleval). * FOR INTERNAL USE! */ GEN swap_vars(GEN b0, long v) { long i, n = RgX_degree(b0, v); GEN b, x; if (n < 0) return pol_0(v); b = cgetg(n+3, t_POL); x = b + 2; b[1] = evalsigne(1) | evalvarn(v); for (i=0; i<=n; i++) gel(x,i) = polcoef_i(b0, i, v); return b; } /* assume varn(b) << varn(a) */ /* return a FpY*/ GEN FpX_FpXY_resultant(GEN a, GEN b, GEN p) { long i,n,dres, db, vY = varn(b), vX = varn(a); GEN la,x,y; if (lgefint(p) == 3) { ulong pp = uel(p,2); b = ZXX_to_FlxX(b, pp, vX); a = ZX_to_Flx(a, pp); x = Flx_FlxY_resultant(a, b, pp); return Flx_to_ZX(x); } db = RgXY_degreex(b); dres = degpol(a)*degpol(b); la = leading_coeff(a); x = cgetg(dres+2, t_VEC); y = cgetg(dres+2, t_VEC); /* Evaluate at dres+ 1 points: 0 (if dres even) and +/- n, so that P_n(X) = * P_{-n}(-X), where P_i is Lagrange polynomial: P_i(j) = delta_{i,j} */ for (i=0,n = 1; i < dres; n++) { gel(x,++i) = utoipos(n); gel(y,i) = FpX_FpXY_eval_resultant(a,b,gel(x,i),p,la,db,vY); gel(x,++i) = subiu(p,n); gel(y,i) = FpX_FpXY_eval_resultant(a,b,gel(x,i),p,la,db,vY); } if (i == dres) { gel(x,++i) = gen_0; gel(y,i) = FpX_FpXY_eval_resultant(a,b, gel(x,i), p,la,db,vY); } return FpV_polint(x,y, p, vY); } static GEN FpX_diamondsum(GEN P, GEN Q, GEN p) { long n = 1+ degpol(P)*degpol(Q); GEN Pl = FpX_invLaplace(FpX_Newton(P,n,p), p); GEN Ql = FpX_invLaplace(FpX_Newton(Q,n,p), p); GEN L = FpX_Laplace(FpXn_mul(Pl, Ql, n, p), p); return FpX_fromNewton(L, p); } #if 0 GEN FpX_diamondprod(GEN P, GEN Q, GEN p) { long n = 1+ degpol(P)*degpol(Q); GEN L=FpX_convol(FpX_Newton(P,n,p), FpX_Newton(Q,n,p), p); return FpX_fromNewton(L, p); } #endif GEN FpX_direct_compositum(GEN a, GEN b, GEN p) { long da = degpol(a), db = degpol(b); if (cmpis(p, da*db) > 0) return FpX_diamondsum(a, b, p); else { long v = varn(a), w = fetch_var_higher(); GEN mx = deg1pol_shallow(gen_m1, gen_0, v); GEN r, ymx = deg1pol_shallow(gen_1, mx, w); /* Y-X */ if (degpol(a) < degpol(b)) swap(a,b); r = FpX_FpXY_resultant(a, poleval(b,ymx),p); setvarn(r, v); (void)delete_var(); return r; } } static GEN _FpX_direct_compositum(void *E, GEN a, GEN b) { return FpX_direct_compositum(a,b, (GEN)E); } GEN FpXV_direct_compositum(GEN V, GEN p) { return gen_product(V, (void *)p, &_FpX_direct_compositum); } /* 0, 1, -1, 2, -2, ... */ #define next_lambda(a) (a>0 ? -a : 1-a) GEN FpX_compositum(GEN a, GEN b, GEN p) { long k, v = fetch_var_higher(); for (k = 1;; k = next_lambda(k)) { GEN x = deg1pol_shallow(gen_1, gmulsg(k, pol_x(v)), 0); /* x + k y */ GEN C = FpX_FpXY_resultant(a, poleval(b,x),p); if (FpX_is_squarefree(C, p)) { (void)delete_var(); return C; } } } /* Assume A in Z[Y], B in Q[Y][X], B squarefree in (Q[Y]/(A))[X] and * Res_Y(A, B) in Z[X]. Find a small lambda (start from *lambda, use * next_lambda successively) such that C(X) = Res_Y(A(Y), B(X + lambda Y)) * is squarefree, reset *lambda to the chosen value and return C. Set LERS to * the Last non-constant polynomial in the Euclidean Remainder Sequence */ static GEN ZX_ZXY_resultant_LERS(GEN A, GEN B0, long *plambda, GEN *LERS) { ulong bound, dp; pari_sp av = avma, av2 = 0; long lambda = *plambda, degA = degpol(A), dres = degA*degpol(B0); long stable, checksqfree, i,n, cnt, degB; long v, vX = varn(B0), vY = varn(A); /* vY < vX */ GEN x, y, dglist, B, q, a, b, ev, H, H0, H1, Hp, H0p, H1p, C0, C1; forprime_t S; if (degA == 1) { GEN a1 = gel(A,3), a0 = gel(A,2); B = lambda? RgX_translate(B0, monomial(stoi(lambda), 1, vY)): B0; H = gsubst(B, vY, gdiv(gneg(a0),a1)); if (!equali1(a1)) H = RgX_Rg_mul(H, powiu(a1, poldegree(B,vY))); *LERS = mkvec2(scalarpol_shallow(a0,vX), scalarpol_shallow(a1,vX)); gerepileall(av, 2, &H, LERS); return H; } dglist = Hp = H0p = H1p = C0 = C1 = NULL; /* gcc -Wall */ C0 = cgetg(dres+2, t_VECSMALL); C1 = cgetg(dres+2, t_VECSMALL); dglist = cgetg(dres+1, t_VECSMALL); x = cgetg(dres+2, t_VECSMALL); y = cgetg(dres+2, t_VECSMALL); B0 = leafcopy(B0); A = leafcopy(A); B = B0; v = fetch_var_higher(); setvarn(A,v); /* make sure p large enough */ INIT: /* always except the first time */ if (av2) { avma = av2; lambda = next_lambda(lambda); } if (lambda) B = RgX_translate(B0, monomial(stoi(lambda), 1, vY)); B = swap_vars(B, vY); setvarn(B,v); /* B0(lambda v + x, v) */ if (DEBUGLEVEL>4) err_printf("Trying lambda = %ld\n", lambda); av2 = avma; if (degA <= 3) { /* sub-resultant faster for small degrees */ H = RgX_resultant_all(A,B,&q); if (typ(q) != t_POL || degpol(q)!=1) goto INIT; H0 = gel(q,2); if (typ(H0) == t_POL) setvarn(H0,vX); else H0 = scalarpol(H0,vX); H1 = gel(q,3); if (typ(H1) == t_POL) setvarn(H1,vX); else H1 = scalarpol(H1,vX); if (!ZX_is_squarefree(H)) goto INIT; goto END; } H = H0 = H1 = NULL; degB = degpol(B); bound = ZX_ZXY_ResBound(A, B, NULL); if (DEBUGLEVEL>4) err_printf("bound for resultant coeffs: 2^%ld\n",bound); dp = 1; init_modular_big(&S); for(cnt = 0, checksqfree = 1;;) { ulong p = u_forprime_next(&S); GEN Hi; a = ZX_to_Flx(A, p); b = ZXX_to_FlxX(B, p, varn(A)); if (degpol(a) < degA || degpol(b) < degB) continue; /* p | lc(A)lc(B) */ if (checksqfree) { /* find degree list for generic Euclidean Remainder Sequence */ long goal = minss(degpol(a), degpol(b)); /* longest possible */ for (n=1; n <= goal; n++) dglist[n] = 0; setlg(dglist, 1); for (n=0; n <= dres; n++) { ev = FlxY_evalx_drop(b, n, p); Flx_resultant_set_dglist(a, ev, dglist, p); if (lg(dglist)-1 == goal) break; } /* last pol in ERS has degree > 1 ? */ goal = lg(dglist)-1; if (degpol(B) == 1) { if (!goal) goto INIT; } else { if (goal <= 1) goto INIT; if (dglist[goal] != 0 || dglist[goal-1] != 1) goto INIT; } if (DEBUGLEVEL>4) err_printf("Degree list for ERS (trials: %ld) = %Ps\n",n+1,dglist); } for (i=0,n = 0; i <= dres; n++) { ev = FlxY_evalx_drop(b, n, p); x[++i] = n; y[i] = Flx_resultant_all(a, ev, C0+i, C1+i, dglist, p); if (!C1[i]) i--; /* C1(i) = 0. No way to recover C0(i) */ } Hi = Flv_Flm_polint(x, mkvec3(y,C0,C1), p, 0); Hp = gel(Hi,1); H0p = gel(Hi,2); H1p = gel(Hi,3); if (!H && degpol(Hp) != dres) continue; if (dp != 1) Hp = Flx_Fl_mul(Hp, Fl_powu(Fl_inv(dp,p), degA, p), p); if (checksqfree) { if (!Flx_is_squarefree(Hp, p)) goto INIT; if (DEBUGLEVEL>4) err_printf("Final lambda = %ld\n", lambda); checksqfree = 0; } if (!H) { /* initialize */ q = utoipos(p); stable = 0; H = ZX_init_CRT(Hp, p,vX); H0= ZX_init_CRT(H0p, p,vX); H1= ZX_init_CRT(H1p, p,vX); } else { GEN qp = muliu(q,p); stable = ZX_incremental_CRT_raw(&H, Hp, q,qp, p) & ZX_incremental_CRT_raw(&H0,H0p, q,qp, p) & ZX_incremental_CRT_raw(&H1,H1p, q,qp, p); q = qp; } /* could make it probabilistic for H ? [e.g if stable twice, etc] * Probabilistic anyway for H0, H1 */ if (DEBUGLEVEL>5 && (stable || ++cnt==100)) { cnt=0; err_printf("%ld%%%s ",100*expi(q)/bound,stable?"s":""); } if (stable && (ulong)expi(q) >= bound) break; /* DONE */ if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZX_ZXY_rnfequation"); gerepileall(av2, 4, &H, &q, &H0, &H1); } } END: if (DEBUGLEVEL>5) err_printf(" done\n"); setvarn(H, vX); (void)delete_var(); *LERS = mkvec2(H0,H1); gerepileall(av, 2, &H, LERS); *plambda = lambda; return H; } GEN ZX_ZXY_resultant_all(GEN A, GEN B, long *plambda, GEN *LERS) { if (LERS) { if (!plambda) pari_err_BUG("ZX_ZXY_resultant_all [LERS != NULL needs lambda]"); return ZX_ZXY_resultant_LERS(A, B, plambda, LERS); } return ZX_ZXY_rnfequation(A, B, plambda); } /* If lambda = NULL, return caract(Mod(A, T)), T,A in Z[X]. * Otherwise find a small lambda such that caract (Mod(A + lambda X, T)) is * squarefree */ GEN ZXQ_charpoly_sqf(GEN A, GEN T, long *lambda, long v) { pari_sp av = avma; GEN R, a; long dA; int delvar; if (v < 0) v = 0; switch (typ(A)) { case t_POL: dA = degpol(A); if (dA > 0) break; A = constant_coeff(A); default: if (lambda) { A = scalar_ZX_shallow(A,varn(T)); dA = 0; break;} return gerepileupto(av, gpowgs(gsub(pol_x(v), A), degpol(T))); } delvar = 0; if (varn(T) == 0) { long v0 = fetch_var(); delvar = 1; T = leafcopy(T); setvarn(T,v0); A = leafcopy(A); setvarn(A,v0); } R = ZX_ZXY_rnfequation(T, deg1pol_shallow(gen_1, gneg_i(A), 0), lambda); if (delvar) (void)delete_var(); setvarn(R, v); a = leading_coeff(T); if (!gequal1(a)) R = gdiv(R, powiu(a, dA)); return gerepileupto(av, R); } /* charpoly(Mod(A,T)), A may be in Q[X], but assume T and result are integral */ GEN ZXQ_charpoly(GEN A, GEN T, long v) { return (degpol(T) < 16) ? RgXQ_charpoly(A,T,v): ZXQ_charpoly_sqf(A,T, NULL, v); } GEN QXQ_charpoly(GEN A, GEN T, long v) { pari_sp av = avma; GEN den, B = Q_remove_denom(A, &den); GEN P = ZXQ_charpoly(B, T, v); return gerepilecopy(av, den ? RgX_rescale(P, ginv(den)): P); } static GEN trivial_case(GEN A, GEN B) { long d; if (typ(A) == t_INT) return powiu(A, degpol(B)); d = degpol(A); if (d == 0) return trivial_case(gel(A,2),B); if (d < 0) return gen_0; return NULL; } static ulong ZX_resultant_prime(GEN a, GEN b, GEN dB, long degA, long degB, ulong p) { pari_sp av = avma; ulong H; long dropa, dropb; ulong dp = dB ? umodiu(dB, p): 1; if (!b) b = Flx_deriv(a, p); dropa = degA - degpol(a); dropb = degB - degpol(b); if (dropa && dropb) /* p | lc(A), p | lc(B) */ { avma = av; return 0; } H = Flx_resultant(a, b, p); if (dropa) { /* multiply by ((-1)^deg B lc(B))^(deg A - deg a) */ ulong c = b[degB+2]; /* lc(B) */ if (odd(degB)) c = p - c; c = Fl_powu(c, dropa, p); if (c != 1) H = Fl_mul(H, c, p); } else if (dropb) { /* multiply by lc(A)^(deg B - deg b) */ ulong c = a[degA+2]; /* lc(A) */ c = Fl_powu(c, dropb, p); if (c != 1) H = Fl_mul(H, c, p); } if (dp != 1) H = Fl_mul(H, Fl_powu(Fl_inv(dp,p), degA, p), p); avma = av; return H; } /* If B=NULL, assume B=A' */ static GEN ZX_resultant_slice(GEN A, GEN B, GEN dB, GEN P, GEN *mod) { pari_sp av = avma; long degA, degB, i, n = lg(P)-1; GEN H, T; degA = degpol(A); degB = B ? degpol(B): degA - 1; if (n == 1) { ulong Hp, p = uel(P,1); GEN a, b; a = ZX_to_Flx(A, p), b = B ? ZX_to_Flx(B, p): NULL; Hp = ZX_resultant_prime(a, b, dB, degA, degB, p); avma = av; *mod = utoi(p); return utoi(Hp); } T = ZV_producttree(P); A = ZX_nv_mod_tree(A, P, T); if (B) B = ZX_nv_mod_tree(B, P, T); H = cgetg(n+1, t_VECSMALL); for(i=1; i <= n; i++) { ulong p = P[i]; GEN a = gel(A,i), b = B? gel(B,i): NULL; H[i] = ZX_resultant_prime(a, b, dB, degA, degB, p); } H = ZV_chinese_tree(H, P, T, ZV_chinesetree(P,T)); *mod = gmael(T, lg(T)-1, 1); gerepileall(av, 2, &H, mod); return H; } GEN ZX_resultant_worker(GEN P, GEN A, GEN B, GEN dB) { GEN V = cgetg(3, t_VEC); if (isintzero(B)) B = NULL; if (isintzero(dB)) dB = NULL; gel(V,1) = ZX_resultant_slice(A,B,dB,P,&gel(V,2)); return V; } /* Res(A, B/dB), assuming the A,B in Z[X] and result is integer */ /* if B=NULL, take B = A' */ GEN ZX_resultant_all(GEN A, GEN B, GEN dB, ulong bound) { pari_sp av = avma; long m; GEN H, worker; int is_disc = !B; if (is_disc) B = ZX_deriv(A); if ((H = trivial_case(A,B)) || (H = trivial_case(B,A))) return H; if (!bound) bound = ZX_ZXY_ResBound(A, B, dB); if (is_disc) B = NULL; worker = strtoclosure("_ZX_resultant_worker", 3, A, B?B:gen_0, dB?dB:gen_0); m = degpol(A)+(B ? degpol(B): 0); H = gen_crt("ZX_resultant_all", worker, dB, bound, m, NULL, ZV_chinese_center, Fp_center); return gerepileuptoint(av, H); } /* A0 and B0 in Q[X] */ GEN QX_resultant(GEN A0, GEN B0) { GEN s, a, b, A, B; pari_sp av = avma; A = Q_primitive_part(A0, &a); B = Q_primitive_part(B0, &b); s = ZX_resultant(A, B); if (!signe(s)) { avma = av; return gen_0; } if (a) s = gmul(s, gpowgs(a,degpol(B))); if (b) s = gmul(s, gpowgs(b,degpol(A))); return gerepileupto(av, s); } GEN ZX_resultant(GEN A, GEN B) { return ZX_resultant_all(A,B,NULL,0); } GEN QXQ_intnorm(GEN A, GEN B) { GEN c, n, R, lB; long dA = degpol(A), dB = degpol(B); pari_sp av = avma; if (dA < 0) return gen_0; A = Q_primitive_part(A, &c); if (!c || typ(c) == t_INT) { n = c; R = ZX_resultant(B, A); } else { n = gel(c,1); R = ZX_resultant_all(B, A, gel(c,2), 0); } if (n && !equali1(n)) R = mulii(R, powiu(n, dB)); lB = leading_coeff(B); if (!equali1(lB)) R = diviiexact(R, powiu(lB, dA)); return gerepileuptoint(av, R); } GEN QXQ_norm(GEN A, GEN B) { GEN c, R, lB; long dA = degpol(A), dB = degpol(B); pari_sp av = avma; if (dA < 0) return gen_0; A = Q_primitive_part(A, &c); R = ZX_resultant(B, A); if (c) R = gmul(R, gpowgs(c, dB)); lB = leading_coeff(B); if (!equali1(lB)) R = gdiv(R, gpowgs(lB, dA)); return gerepileupto(av, R); } /* assume x has integral coefficients */ GEN ZX_disc_all(GEN x, ulong bound) { pari_sp av = avma; GEN l, R; long s, d = degpol(x); if (d <= 1) return d ? gen_1: gen_0; s = (d & 2) ? -1: 1; l = leading_coeff(x); R = ZX_resultant_all(x, NULL, NULL, bound); if (is_pm1(l)) { if (signe(l) < 0) s = -s; } else R = diviiexact(R,l); if (s == -1) togglesign_safe(&R); return gerepileuptoint(av,R); } GEN ZX_disc(GEN x) { return ZX_disc_all(x,0); } GEN QX_disc(GEN x) { pari_sp av = avma; GEN c, d = ZX_disc( Q_primitive_part(x, &c) ); if (c) d = gmul(d, gpowgs(c, 2*degpol(x) - 2)); return gerepileupto(av, d); } GEN QXQ_mul(GEN x, GEN y, GEN T) { GEN dx, nx = Q_primitive_part(x, &dx); GEN dy, ny = Q_primitive_part(y, &dy); GEN z = ZXQ_mul(nx, ny, T); if (dx || dy) { GEN d = dx ? dy ? gmul(dx, dy): dx : dy; if (!gequal1(d)) z = ZX_Q_mul(z, d); } return z; } GEN QXQ_sqr(GEN x, GEN T) { GEN dx, nx = Q_primitive_part(x, &dx); GEN z = ZXQ_sqr(nx, T); if (dx) z = ZX_Q_mul(z, gsqr(dx)); return z; } /* lift(1 / Mod(A,B)). B a ZX, A a scalar or a QX */ GEN QXQ_inv(GEN A, GEN B) { GEN D, cU, q, U, V; ulong p; pari_sp av2, av = avma; forprime_t S; pari_timer ti; if (is_scalar_t(typ(A))) return scalarpol(ginv(A), varn(B)); /* A a QX, B a ZX */ A = Q_primitive_part(A, &D); /* A, B in Z[X] */ init_modular_small(&S); if (DEBUGLEVEL>5) timer_start(&ti); av2 = avma; U = NULL; while ((p = u_forprime_next(&S))) { GEN a, b, qp, Up, Vp; int stable; a = ZX_to_Flx(A, p); b = ZX_to_Flx(B, p); /* if p | Res(A/G, B/G), discard */ if (!Flx_extresultant(b,a,p, &Vp,&Up)) continue; if (!U) { /* First time */ U = ZX_init_CRT(Up,p,varn(A)); V = ZX_init_CRT(Vp,p,varn(A)); q = utoipos(p); continue; } if (DEBUGLEVEL>5) timer_printf(&ti,"QXQ_inv: mod %ld (bound 2^%ld)", p,expi(q)); qp = muliu(q,p); stable = ZX_incremental_CRT_raw(&U, Up, q,qp, p) & ZX_incremental_CRT_raw(&V, Vp, q,qp, p); if (stable) { /* all stable: check divisibility */ GEN res = ZX_add(ZX_mul(A,U), ZX_mul(B,V)); if (degpol(res) == 0) { res = gel(res,2); D = D? gmul(D, res): res; break; } /* DONE */ if (DEBUGLEVEL) err_printf("QXQ_inv: char 0 check failed"); } q = qp; if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"QXQ_inv"); gerepileall(av2, 3, &q,&U,&V); } } if (!p) pari_err_OVERFLOW("QXQ_inv [ran out of primes]"); cU = ZX_content(U); if (!is_pm1(cU)) { U = Q_div_to_int(U, cU); D = gdiv(D, cU); } return gerepileupto(av, RgX_Rg_div(U, D)); } /* lift(C / Mod(A,B)). B monic ZX, A and C scalar or QX. Use when result is * small */ GEN QXQ_div_ratlift(GEN C, GEN A, GEN B) { GEN dA, dC, q, U; ulong p, ct, delay; pari_sp av2, av = avma; forprime_t S; pari_timer ti; if (is_scalar_t(typ(A))) { A = gdiv(C,A); if (typ(A) != t_POL) A = scalarpol(A, varn(B)); return A; } /* A a QX, B a ZX */ A = Q_remove_denom(A, &dA); C = Q_remove_denom(C, &dC); if (typ(C) != t_POL) C = scalarpol_shallow(C, varn(B)); if (dA) C = ZX_Z_mul(C,dA); /* A, B, C in Z[X] */ init_modular_small(&S); if (DEBUGLEVEL>5) timer_start(&ti); av2 = avma; U = NULL; ct = 0; delay = 1; while ((p = u_forprime_next(&S))) { GEN a, b, Up, Ur; a = ZX_to_Flx(A, p); b = ZX_to_Flx(B, p); /* if p | Res(A/G, B/G), discard */ Up = Flxq_invsafe(a,b,p); if (!Up) continue; Up = Flxq_mul(Up, ZX_to_Flx(C,p), b, p); if (!U) { /* First time */ U = ZX_init_CRT(Up,p,varn(A)); q = utoipos(p); } else { GEN qp = muliu(q,p); (void)ZX_incremental_CRT_raw(&U, Up, q,qp, p); q = qp; } if (DEBUGLEVEL>5) timer_printf(&ti,"QXQ_div: mod %ld (bound 2^%ld)", p,expi(q)); b = sqrti(shifti(q,-1)); Ur = FpX_ratlift(U,q,b,b,NULL); if (Ur && ++ct == delay) { /* check divisibility */ GEN d, V = Q_remove_denom(Ur,&d), W = d? ZX_Z_mul(C,d): C; if (!signe(ZX_rem(ZX_sub(ZX_mul(A,V), W), B))) { U = Ur; break; } delay <<= 1; if (DEBUGLEVEL) err_printf("QXQ_div: check failed, delay = %ld",delay); } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"QXQ_div"); gerepileall(av2, 2, &q,&U); } } if (!p) pari_err_OVERFLOW("QXQ_div [ran out of primes]"); if (!dC) return gerepilecopy(av, U); return gerepileupto(av, RgX_Rg_div(U, dC)); } /************************************************************************ * * * ZX_ZXY_resultant * * * ************************************************************************/ static GEN ZX_ZXY_resultant_prime(GEN a, GEN b, ulong dp, ulong p, long degA, long degB, long dres, long sX) { long dropa = degA - degpol(a), dropb = degB - degpol(b); GEN Hp = Flx_FlxY_resultant_polint(a, b, p, dres, sX); if (dropa && dropb) Hp = zero_Flx(sX); else { if (dropa) { /* multiply by ((-1)^deg B lc(B))^(deg A - deg a) */ GEN c = gel(b,degB+2); /* lc(B) */ if (odd(degB)) c = Flx_neg(c, p); if (!Flx_equal1(c)) { c = Flx_powu(c, dropa, p); if (!Flx_equal1(c)) Hp = Flx_mul(Hp, c, p); } } else if (dropb) { /* multiply by lc(A)^(deg B - deg b) */ ulong c = uel(a, degA+2); /* lc(A) */ c = Fl_powu(c, dropb, p); if (c != 1) Hp = Flx_Fl_mul(Hp, c, p); } } if (dp != 1) Hp = Flx_Fl_mul(Hp, Fl_powu(Fl_inv(dp,p), degA, p), p); return Hp; } static GEN ZX_ZXY_resultant_slice(GEN A, GEN B, GEN dB, long degA, long degB, long dres, GEN P, GEN *mod, long sX, long vY) { pari_sp av = avma; long i, n = lg(P)-1; GEN H, T, D; if (n == 1) { ulong p = uel(P,1); ulong dp = dB ? umodiu(dB, p): 1; GEN a = ZX_to_Flx(A, p), b = ZXX_to_FlxX(B, p, vY); GEN Hp = ZX_ZXY_resultant_prime(a, b, dp, p, degA, degB, dres, sX); H = Flx_to_ZX(Hp); *mod = utoi(p); gerepileall(av, 2, &H, mod); return H; } T = ZV_producttree(P); A = ZX_nv_mod_tree(A, P, T); B = ZXX_nv_mod_tree(B, P, T, vY); D = dB ? Z_ZV_mod_tree(dB, P, T): NULL; H = cgetg(n+1, t_VEC); for(i=1; i <= n; i++) { ulong p = P[i]; GEN a = gel(A,i), b = gel(B,i); ulong dp = D ? uel(D, i): 1; gel(H,i) = ZX_ZXY_resultant_prime(a, b, dp, p, degA, degB, dres, sX); } H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T)); *mod = gmael(T, lg(T)-1, 1); gerepileall(av, 2, &H, mod); return H; } GEN ZX_ZXY_resultant_worker(GEN P, GEN A, GEN B, GEN dB, GEN v) { GEN V = cgetg(3, t_VEC); if (isintzero(dB)) dB = NULL; gel(V,1) = ZX_ZXY_resultant_slice(A, B, dB, v[1], v[2], v[3], P, &gel(V,2), v[4], v[5]); return V; } GEN ZX_ZXY_resultant(GEN A, GEN B) { pari_sp av = avma; ulong bound; long v = fetch_var_higher(); long degA = degpol(A), degB, dres = degA * degpol(B); long vX = varn(B), vY = varn(A); /* assume vY has lower priority */ long sX = evalvarn(vX); GEN worker, H, dB; B = Q_remove_denom(B, &dB); if (!dB) B = leafcopy(B); A = leafcopy(A); setvarn(A,v); B = swap_vars(B, vY); setvarn(B,v); degB = degpol(B); bound = ZX_ZXY_ResBound(A, B, dB); if (DEBUGLEVEL>4) err_printf("bound for resultant coeffs: 2^%ld\n",bound); worker = strtoclosure("_ZX_ZXY_resultant_worker", 4, A, B, dB?dB:gen_0, mkvecsmall5(degA, degB,dres, vY, sX)); H = gen_crt("ZX_ZXY_resultant_all", worker, dB, bound, degpol(A)+degpol(B), NULL, nxV_chinese_center, FpX_center_i); setvarn(H, vX); (void)delete_var(); return gerepilecopy(av, H); } static long ZX_ZXY_rnfequation_lambda(GEN A, GEN B0, long lambda) { pari_sp av = avma; long degA = degpol(A), degB, dres = degA*degpol(B0); long v = fetch_var_higher(); long vX = varn(B0), vY = varn(A); /* assume vY has lower priority */ long sX = evalvarn(vX); GEN dB, B, a, b, Hp; forprime_t S; B0 = Q_remove_denom(B0, &dB); if (!dB) B0 = leafcopy(B0); A = leafcopy(A); B = B0; setvarn(A,v); INIT: if (lambda) B = RgX_translate(B0, monomial(stoi(lambda), 1, vY)); B = swap_vars(B, vY); setvarn(B,v); /* B0(lambda v + x, v) */ if (DEBUGLEVEL>4) err_printf("Trying lambda = %ld\n", lambda); degB = degpol(B); init_modular_big(&S); while (1) { ulong p = u_forprime_next(&S); ulong dp = dB ? umodiu(dB, p): 1; if (!dp) continue; a = ZX_to_Flx(A, p); b = ZXX_to_FlxX(B, p, v); Hp = ZX_ZXY_resultant_prime(a, b, dp, p, degA, degB, dres, sX); if (degpol(Hp) != dres) continue; if (dp != 1) Hp = Flx_Fl_mul(Hp, Fl_powu(Fl_inv(dp,p), degA, p), p); if (!Flx_is_squarefree(Hp, p)) { lambda = next_lambda(lambda); goto INIT; } if (DEBUGLEVEL>4) err_printf("Final lambda = %ld\n", lambda); avma = av; (void)delete_var(); return lambda; } } GEN ZX_ZXY_rnfequation(GEN A, GEN B, long *lambda) { if (lambda) { *lambda = ZX_ZXY_rnfequation_lambda(A, B, *lambda); B = RgX_translate(B, monomial(stoi(*lambda), 1, varn(A))); } return ZX_ZXY_resultant(A,B); } /************************************************************************ * * * IRREDUCIBLE POLYNOMIAL / Fp * * * ************************************************************************/ /* irreducible (unitary) polynomial of degree n over Fp */ GEN ffinit_rand(GEN p,long n) { for(;;) { pari_sp av = avma; GEN pol = ZX_add(pol_xn(n, 0), random_FpX(n-1,0, p)); if (FpX_is_irred(pol, p)) return pol; avma = av; } } /* return an extension of degree 2^l of F_2, assume l > 0 * Not stack clean. */ static GEN f2init(long l) { GEN Q, T, S; long i, v; if (l == 1) return polcyclo(3, 0); v = fetch_var_higher(); S = mkpoln(4, gen_1,gen_1,gen_0,gen_0); /* y(y^2 + y) */ Q = mkpoln(3, gen_1,gen_1, S); /* x^2 + x + y(y^2+y) */ setvarn(Q, v); /* x^4+x+1, irred over F_2, minimal polynomial of a root of Q */ T = mkpoln(5, gen_1,gen_0,gen_0,gen_1,gen_1); setvarn(T, v); /* Q = x^2 + x + a(y) irred. over K = F2[y] / (T(y)) * ==> x^2 + x + a(y) b irred. over K for any root b of Q * ==> x^2 + x + (b^2+b)b */ for (i=2; i 0 * Not stack clean. */ GEN ffinit_Artin_Shreier(GEN ip, long l) { long i, v, p = itos(ip); GEN T, Q, xp = pol_xn(p,0); /* x^p */ T = ZX_sub(xp, deg1pol_shallow(gen_1,gen_1,0)); /* x^p - x - 1 */ if (l == 1) return T; v = fetch_var_higher(); setvarn(xp, v); Q = ZX_sub(pol_xn(2*p-1,0), pol_xn(p,0)); Q = gsub(xp, deg1pol_shallow(gen_1, Q, v)); /* x^p - x - (y^(2p-1)-y^p) */ for (i = 2; i <= l; ++i) T = FpX_FpXY_resultant(T, Q, ip); (void)delete_var(); setvarn(T,0); return T; } /* check if polsubcyclo(n,l,0) is irreducible modulo p */ static long fpinit_check(GEN p, long n, long l) { ulong q; if (!uisprime(n)) return 0; q = umodiu(p,n); if (!q) return 0; return ugcd((n-1)/Fl_order(q, n-1, n), l) == 1; } /* let k=2 if p%4==1, and k=4 else and assume k*p does not divide l. * Return an irreducible polynomial of degree l over F_p. * Variant of Adleman and Lenstra "Finding irreducible polynomials over * finite fields", ACM, 1986 (5) 350--355. * Not stack clean */ static GEN fpinit(GEN p, long l) { ulong n = 1+l; while (!fpinit_check(p,n,l)) n += l; if (DEBUGLEVEL>=4) err_printf("FFInit: using polsubcyclo(%ld, %ld)\n",n,l); return FpX_red(polsubcyclo(n,l,0),p); } static GEN ffinit_fact(GEN p, long n) { GEN P, F = gel(factoru_pow(n),3); long i, l = lg(F); P= cgetg(l, t_VEC); if (!odd(n) && absequaliu(p, 2)) gel(P,1) = f2init(vals(n)); /* if n is even, F[1] = 2^vals(n)*/ else gel(P,1) = fpinit(p, F[1]); for (i = 2; i < l; ++i) gel(P,i) = fpinit(p, F[i]); return FpXV_direct_compositum(P, p); } static GEN init_Fq_i(GEN p, long n, long v) { GEN P; if (n <= 0) pari_err_DOMAIN("ffinit", "degree", "<=", gen_0, stoi(n)); if (typ(p) != t_INT) pari_err_TYPE("ffinit",p); if (signe(p) <= 0) pari_err_PRIME("ffinit",p); if (v < 0) v = 0; if (n == 1) return pol_x(v); if (fpinit_check(p, n+1, n)) return polcyclo(n+1, v); P = ffinit_fact(p,n); setvarn(P, v); return P; } GEN init_Fq(GEN p, long n, long v) { pari_sp av = avma; return gerepileupto(av, init_Fq_i(p, n, v)); } GEN ffinit(GEN p, long n, long v) { pari_sp av = avma; return gerepileupto(av, FpX_to_mod(init_Fq_i(p, n, v), p)); } GEN ffnbirred(GEN p, long n) { pari_sp av = avma; long j, l; GEN s = gen_0, dk, pd; dk = divisorsu(n); l = lg(dk); for (j = 1; j < l; j++) { long d = dk[j], m = moebiusu(d); if (!m) continue; pd = powiu(p, dk[l-j]); /* p^{n/d} */ s = m>0? addii(s, pd): subii(s,pd); } return gerepileuptoint(av, divis(s, n)); } GEN ffsumnbirred(GEN p, long n) { pari_sp av = avma; long i, j; GEN v, q, t = gen_0; v = cgetg(n+1,t_VECSMALL); v[1] = 1; q = cgetg(n+1,t_VEC); gel(q,1) = p; for (i=2; i<=n; i++) { v[i] = moebiusu(i); gel(q,i) = mulii(gel(q,i-1), p); } for (i=1; i<=n; i++) { GEN s = gen_0, dk = divisorsu(i); long l = lg(dk); for (j = 1; j < l; j++) { long d = dk[j], m = v[d]; GEN pd; if (!m) continue; pd = gel(q, dk[l-j]); /* p^{n/d} */ s = m>0? addii(s, pd): subii(s, pd); } t = addii(t, divis(s, i)); } return gerepileuptoint(av, t); } GEN ffnbirred0(GEN p, long n, long flag) { if (typ(p) != t_INT) pari_err_TYPE("ffnbirred", p); if (n <= 0) pari_err_DOMAIN("ffnbirred", "degree", "<=", gen_0, stoi(n)); switch(flag) { case 0: return ffnbirred(p, n); case 1: return ffsumnbirred(p, n); } pari_err_FLAG("ffnbirred"); return NULL; /* LCOV_EXCL_LINE */ } static void checkmap(GEN m, const char *s) { if (typ(m)!=t_VEC || lg(m)!=3 || typ(gel(m,1))!=t_FFELT) pari_err_TYPE(s,m); } GEN ffembed(GEN a, GEN b) { pari_sp av = avma; GEN p, Ta, Tb, g, r = NULL; if (typ(a)!=t_FFELT) pari_err_TYPE("ffembed",a); if (typ(b)!=t_FFELT) pari_err_TYPE("ffembed",b); p = FF_p_i(a); g = FF_gen(a); if (!equalii(p, FF_p_i(b))) pari_err_MODULUS("ffembed",a,b); Ta = FF_mod(a); Tb = FF_mod(b); if (degpol(Tb)%degpol(Ta)!=0) pari_err_DOMAIN("ffembed",GENtostr_raw(a),"is not a subfield of",b,a); r = gel(FFX_roots(Ta, b), 1); return gerepilecopy(av, mkvec2(g,r)); } GEN ffextend(GEN a, GEN P, long v) { pari_sp av = avma; long n; GEN p, T, R, g, m; if (typ(a)!=t_FFELT) pari_err_TYPE("ffextend",a); T = a; p = FF_p_i(a); if (typ(P)!=t_POL || !RgX_is_FpXQX(P,&T,&p)) pari_err_TYPE("ffextend", P); if (!FF_samefield(a, T)) pari_err_MODULUS("ffextend",a,T); if (v < 0) v = varn(P); n = FF_f(T) * degpol(P); R = ffinit(p, n, v); g = ffgen(R, v); m = ffembed(a, g); R = FFX_roots(ffmap(m, P),g); return gerepilecopy(av, mkvec2(gel(R,1), m)); } GEN fffrobenius(GEN a, long n) { GEN g; if (typ(a)!=t_FFELT) pari_err_TYPE("fffrobenius",a); retmkvec2(g=FF_gen(a), FF_Frobenius(g, n)); } GEN ffinvmap(GEN m) { pari_sp av = avma; long i, l; GEN T, F, a, g, r, f = NULL; checkmap(m, "ffinvmap"); a = gel(m,1); r = gel(m,2); if (typ(r) != t_FFELT) pari_err_TYPE("ffinvmap", m); g = FF_gen(a); T = FF_mod(r); F = gel(FFX_factor(T, a), 1); l = lg(F); for(i=1; i= 1 && RgX_is_FpXQX(r,&a,&p) && a && typ(a)==t_FFELT) return a; pari_err_TYPE(s, r); return NULL; /* LCOV_EXCL_LINE */ } static GEN ffeltmap_i(GEN m, GEN x) { GEN r = gel(m,2); if (!FF_samefield(x, gel(m,1))) pari_err_DOMAIN("ffmap","m","domain does not contain", x, r); if (typ(r)==t_FFELT) return FF_map(r, x); else return FFX_preimage(x, r, ffpartmapimage("ffmap", r)); } static GEN ffmap_i(GEN m, GEN x) { GEN y; long i, lx, tx = typ(x); switch(tx) { case t_FFELT: return ffeltmap_i(m, x); case t_POL: case t_RFRAC: case t_SER: case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); for (i=1; ibot; long u, i; size_t dec; (void)gerepile(av,tetpil,NULL); dec = av-tetpil; for (u=t+1; u<=m; u++) { A = (pari_sp)coeff(x,u,k); if (A < av && A >= bot) coeff(x,u,k) += dec; } for (i=k+1; i<=n; i++) for (u=1; u<=m; u++) { A = (pari_sp)coeff(x,u,i); if (A < av && A >= bot) coeff(x,u,i) += dec; } } static void gen_gerepile_gauss_ker(GEN x, long k, long t, pari_sp av, void *E, GEN (*copy)(void*, GEN)) { pari_sp tetpil = avma; long u,i, n = lg(x)-1, m = n? nbrows(x): 0; if (DEBUGMEM > 1) pari_warn(warnmem,"gauss_pivot_ker. k=%ld, n=%ld",k,n); for (u=t+1; u<=m; u++) gcoeff(x,u,k) = copy(E,gcoeff(x,u,k)); for (i=k+1; i<=n; i++) for (u=1; u<=m; u++) gcoeff(x,u,i) = copy(E,gcoeff(x,u,i)); gerepile_mat(av,tetpil,x,k,m,n,t); } /* special gerepile for huge matrices */ #define COPY(x) {\ GEN _t = (x); if (!is_universal_constant(_t)) x = gcopy(_t); \ } INLINE GEN _copy(void *E, GEN x) { (void) E; COPY(x); return x; } static void gerepile_gauss_ker(GEN x, long k, long t, pari_sp av) { gen_gerepile_gauss_ker(x, k, t, av, NULL, &_copy); } static void gerepile_gauss(GEN x,long k,long t,pari_sp av, long j, GEN c) { pari_sp tetpil = avma, A, bot; long u,i, n = lg(x)-1, m = n? nbrows(x): 0; size_t dec; if (DEBUGMEM > 1) pari_warn(warnmem,"gauss_pivot. k=%ld, n=%ld",k,n); for (u=t+1; u<=m; u++) if (u==j || !c[u]) COPY(gcoeff(x,u,k)); for (u=1; u<=m; u++) if (u==j || !c[u]) for (i=k+1; i<=n; i++) COPY(gcoeff(x,u,i)); (void)gerepile(av,tetpil,NULL); dec = av-tetpil; bot = pari_mainstack->bot; for (u=t+1; u<=m; u++) if (u==j || !c[u]) { A=(pari_sp)coeff(x,u,k); if (A=bot) coeff(x,u,k)+=dec; } for (u=1; u<=m; u++) if (u==j || !c[u]) for (i=k+1; i<=n; i++) { A=(pari_sp)coeff(x,u,i); if (A=bot) coeff(x,u,i)+=dec; } } /*******************************************************************/ /* */ /* GENERIC */ /* */ /*******************************************************************/ GEN gen_ker(GEN x, long deplin, void *E, const struct bb_field *ff) { pari_sp av0 = avma, av, tetpil; GEN y, c, d; long i, j, k, r, t, n, m; n=lg(x)-1; if (!n) return cgetg(1,t_MAT); m=nbrows(x); r=0; x = RgM_shallowcopy(x); c = zero_zv(m); d=new_chunk(n+1); av=avma; for (k=1; k<=n; k++) { for (j=1; j<=m; j++) if (!c[j]) { gcoeff(x,j,k) = ff->red(E, gcoeff(x,j,k)); if (!ff->equal0(gcoeff(x,j,k))) break; } if (j>m) { if (deplin) { GEN c = cgetg(n+1, t_COL), g0 = ff->s(E,0), g1=ff->s(E,1); for (i=1; ired(E, gcoeff(x,d[i],k)); gel(c,k) = g1; for (i=k+1; i<=n; i++) gel(c,i) = g0; return gerepileupto(av0, c); } r++; d[k]=0; for(j=1; jneg(E,ff->inv(E,gcoeff(x,j,k))); c[j] = k; d[k] = j; gcoeff(x,j,k) = ff->s(E,-1); for (i=k+1; i<=n; i++) gcoeff(x,j,i) = ff->red(E,ff->mul(E,piv,gcoeff(x,j,i))); for (t=1; t<=m; t++) { if (t==j) continue; piv = ff->red(E,gcoeff(x,t,k)); if (ff->equal0(piv)) continue; gcoeff(x,t,k) = ff->s(E,0); for (i=k+1; i<=n; i++) gcoeff(x,t,i) = ff->red(E, ff->add(E, gcoeff(x,t,i), ff->mul(E,piv,gcoeff(x,j,i)))); if (gc_needed(av,1)) gen_gerepile_gauss_ker(x,k,t,av,E,ff->red); } } } if (deplin) { avma = av0; return NULL; } tetpil=avma; y=cgetg(r+1,t_MAT); for (j=k=1; j<=r; j++,k++) { GEN C = cgetg(n+1,t_COL); GEN g0 = ff->s(E,0), g1 = ff->s(E,1); gel(y,j) = C; while (d[k]) k++; for (i=1; ired(E,p1); gunclone(p1); } else gel(C,i) = g0; gel(C,k) = g1; for (i=k+1; i<=n; i++) gel(C,i) = g0; } return gerepile(av0,tetpil,y); } GEN gen_Gauss_pivot(GEN x, long *rr, void *E, const struct bb_field *ff) { pari_sp av; GEN c, d; long i, j, k, r, t, m, n = lg(x)-1; if (!n) { *rr = 0; return NULL; } m=nbrows(x); r=0; d = cgetg(n+1, t_VECSMALL); x = RgM_shallowcopy(x); c = zero_zv(m); av=avma; for (k=1; k<=n; k++) { for (j=1; j<=m; j++) if (!c[j]) { gcoeff(x,j,k) = ff->red(E,gcoeff(x,j,k)); if (!ff->equal0(gcoeff(x,j,k))) break; } if (j>m) { r++; d[k]=0; } else { GEN piv = ff->neg(E,ff->inv(E,gcoeff(x,j,k))); GEN g0 = ff->s(E,0); c[j] = k; d[k] = j; for (i=k+1; i<=n; i++) gcoeff(x,j,i) = ff->red(E,ff->mul(E,piv,gcoeff(x,j,i))); for (t=1; t<=m; t++) { if (c[t]) continue; /* already a pivot on that line */ piv = ff->red(E,gcoeff(x,t,k)); if (ff->equal0(piv)) continue; gcoeff(x,t,k) = g0; for (i=k+1; i<=n; i++) gcoeff(x,t,i) = ff->red(E, ff->add(E,gcoeff(x,t,i), ff->mul(E,piv,gcoeff(x,j,i)))); if (gc_needed(av,1)) gerepile_gauss(x,k,t,av,j,c); } for (i=k; i<=n; i++) gcoeff(x,j,i) = g0; /* dummy */ } } *rr = r; avma = (pari_sp)d; return d; } GEN gen_det(GEN a, void *E, const struct bb_field *ff) { pari_sp av = avma; long i,j,k, s = 1, nbco = lg(a)-1; GEN q, x = ff->s(E,1); if (!nbco) return x; a = RgM_shallowcopy(a); for (i=1; ired(E,gcoeff(a,k,i)); if (!ff->equal0(gcoeff(a,k,i))) break; } if (k > nbco) return gerepileupto(av, gcoeff(a,i,i)); if (k != i) { /* exchange the lines s.t. k = i */ for (j=i; j<=nbco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j)); s = -s; } q = gcoeff(a,i,i); x = ff->red(E,ff->mul(E,x,q)); q = ff->inv(E,q); for (k=i+1; k<=nbco; k++) { GEN m = ff->red(E,gcoeff(a,i,k)); if (ff->equal0(m)) continue; m = ff->neg(E, ff->red(E,ff->mul(E,m, q))); for (j=i+1; j<=nbco; j++) gcoeff(a,j,k) = ff->red(E,ff->add(E, gcoeff(a,j,k), ff->mul(E,m,gcoeff(a,j,i)))); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i); gerepileall(av,4, &a,&x,&q,&m); } } } if (s < 0) x = ff->neg(E,x); return gerepileupto(av, ff->red(E,ff->mul(E, x, gcoeff(a,nbco,nbco)))); } INLINE void _gen_addmul(GEN b, long k, long i, GEN m, void *E, const struct bb_field *ff) { gel(b,i) = ff->red(E,gel(b,i)); gel(b,k) = ff->add(E,gel(b,k), ff->mul(E,m, gel(b,i))); } static GEN _gen_get_col(GEN a, GEN b, long li, void *E, const struct bb_field *ff) { GEN u = cgetg(li+1,t_COL); pari_sp av = avma; long i, j; gel(u,li) = gerepileupto(av, ff->red(E,ff->mul(E,gel(b,li), gcoeff(a,li,li)))); for (i=li-1; i>0; i--) { pari_sp av = avma; GEN m = gel(b,i); for (j=i+1; j<=li; j++) m = ff->add(E,m, ff->neg(E,ff->mul(E,gcoeff(a,i,j), gel(u,j)))); m = ff->red(E, m); gel(u,i) = gerepileupto(av, ff->red(E,ff->mul(E,m, gcoeff(a,i,i)))); } return u; } GEN gen_Gauss(GEN a, GEN b, void *E, const struct bb_field *ff) { long i, j, k, li, bco, aco; GEN u, g0 = ff->s(E,0); pari_sp av = avma; a = RgM_shallowcopy(a); b = RgM_shallowcopy(b); aco = lg(a)-1; bco = lg(b)-1; li = nbrows(a); for (i=1; i<=aco; i++) { GEN invpiv; for (k = i; k <= li; k++) { GEN piv = ff->red(E,gcoeff(a,k,i)); if (!ff->equal0(piv)) { gcoeff(a,k,i) = ff->inv(E,piv); break; } gcoeff(a,k,i) = g0; } /* found a pivot on line k */ if (k > li) return NULL; if (k != i) { /* swap lines so that k = i */ for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j)); for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j)); } if (i == aco) break; invpiv = gcoeff(a,i,i); /* 1/piv mod p */ for (k=i+1; k<=li; k++) { GEN m = ff->red(E,gcoeff(a,k,i)); gcoeff(a,k,i) = g0; if (ff->equal0(m)) continue; m = ff->red(E,ff->neg(E,ff->mul(E,m, invpiv))); for (j=i+1; j<=aco; j++) _gen_addmul(gel(a,j),k,i,m,E,ff); for (j=1 ; j<=bco; j++) _gen_addmul(gel(b,j),k,i,m,E,ff); } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_Gauss. i=%ld",i); gerepileall(av,2, &a,&b); } } if(DEBUGLEVEL>4) err_printf("Solving the triangular system\n"); u = cgetg(bco+1,t_MAT); for (j=1; j<=bco; j++) gel(u,j) = _gen_get_col(a, gel(b,j), aco, E, ff); return u; } /* compatible t_MAT * t_COL, lgA = lg(A) = lg(B) > 1, l = lgcols(A) */ static GEN gen_matcolmul_i(GEN A, GEN B, ulong lgA, ulong l, void *E, const struct bb_field *ff) { GEN C = cgetg(l, t_COL); ulong i; for (i = 1; i < l; i++) { pari_sp av = avma; GEN e = ff->mul(E, gcoeff(A, i, 1), gel(B, 1)); ulong k; for(k = 2; k < lgA; k++) e = ff->add(E, e, ff->mul(E, gcoeff(A, i, k), gel(B, k))); gel(C, i) = gerepileupto(av, ff->red(E, e)); } return C; } GEN gen_matcolmul(GEN A, GEN B, void *E, const struct bb_field *ff) { ulong lgA = lg(A); if (lgA != (ulong)lg(B)) pari_err_OP("operation 'gen_matcolmul'", A, B); if (lgA == 1) return cgetg(1, t_COL); return gen_matcolmul_i(A, B, lgA, lgcols(A), E, ff); } GEN gen_matmul(GEN A, GEN B, void *E, const struct bb_field *ff) { ulong j, l, lgA, lgB = lg(B); GEN C; if (lgB == 1) return cgetg(1, t_MAT); lgA = lg(A); if (lgA != (ulong)lgcols(B)) pari_err_OP("operation 'gen_matmul'", A, B); if (lgA == 1) return zeromat(0, lgB - 1); l = lgcols(A); C = cgetg(lgB, t_MAT); for(j = 1; j < lgB; j++) gel(C, j) = gen_matcolmul_i(A, gel(B, j), lgA, l, E, ff); return C; } static GEN gen_colneg(GEN A, void *E, const struct bb_field *ff) { long i, l; GEN B = cgetg_copy(A, &l); for (i = 1; i < l; i++) gel(B, i) = ff->neg(E, gel(A, i)); return B; } static GEN gen_matneg(GEN A, void *E, const struct bb_field *ff) { long i, l; GEN B = cgetg_copy(A, &l); for (i = 1; i < l; i++) gel(B, i) = gen_colneg(gel(A, i), E, ff); return B; } /* assume dim A >= 1, A invertible + upper triangular */ static GEN gen_matinv_upper_ind(GEN A, long index, void *E, const struct bb_field *ff) { long n = lg(A) - 1, i, j; GEN u = cgetg(n + 1, t_COL); for (i = n; i > index; i--) gel(u, i) = ff->s(E, 0); gel(u, i) = ff->inv(E, gcoeff(A, i, i)); for (i--; i > 0; i--) { pari_sp av = avma; GEN m = ff->neg(E, ff->mul(E, gcoeff(A, i, i + 1), gel(u, i + 1))); for (j = i + 2; j <= n; j++) m = ff->add(E, m, ff->neg(E, ff->mul(E, gcoeff(A, i, j), gel(u, j)))); gel(u, i) = gerepileupto(av, ff->red(E, ff->mul(E, m, ff->inv(E, gcoeff(A, i, i))))); } return u; } static GEN gen_matinv_upper(GEN A, void *E, const struct bb_field *ff) { long i, l; GEN B = cgetg_copy(A, &l); for (i = 1; i < l; i++) gel(B,i) = gen_matinv_upper_ind(A, i, E, ff); return B; } /* find z such that A z = y. Return NULL if no solution */ GEN gen_matcolinvimage(GEN A, GEN y, void *E, const struct bb_field *ff) { pari_sp av = avma; long i, l = lg(A); GEN M, x, t; M = gen_ker(shallowconcat(A, y), 0, E, ff); i = lg(M) - 1; if (!i) { avma = av; return NULL; } x = gel(M, i); t = gel(x, l); if (ff->equal0(t)) { avma = av; return NULL; } t = ff->neg(E, ff->inv(E, t)); setlg(x, l); for (i = 1; i < l; i++) gel(x, i) = ff->red(E, ff->mul(E, t, gel(x, i))); return gerepilecopy(av, x); } /* find Z such that A Z = B. Return NULL if no solution */ GEN gen_matinvimage(GEN A, GEN B, void *E, const struct bb_field *ff) { pari_sp av = avma; GEN d, x, X, Y; long i, j, nY, nA, nB; x = gen_ker(shallowconcat(gen_matneg(A, E, ff), B), 0, E, ff); /* AX = BY, Y in strict upper echelon form with pivots = 1. * We must find T such that Y T = Id_nB then X T = Z. This exists * iff Y has at least nB columns and full rank. */ nY = lg(x) - 1; nB = lg(B) - 1; if (nY < nB) { avma = av; return NULL; } nA = lg(A) - 1; Y = rowslice(x, nA + 1, nA + nB); /* nB rows */ d = cgetg(nB + 1, t_VECSMALL); for (i = nB, j = nY; i >= 1; i--, j--) { for (; j >= 1; j--) if (!ff->equal0(gcoeff(Y, i, j))) { d[i] = j; break; } if (!j) { avma = av; return NULL; } } /* reduce to the case Y square, upper triangular with 1s on diagonal */ Y = vecpermute(Y, d); x = vecpermute(x, d); X = rowslice(x, 1, nA); return gerepileupto(av, gen_matmul(X, gen_matinv_upper(Y, E, ff), E, ff)); } static GEN image_from_pivot(GEN x, GEN d, long r) { GEN y; long j, k; if (!d) return gcopy(x); /* d left on stack for efficiency */ r = lg(x)-1 - r; /* = dim Im(x) */ y = cgetg(r+1,t_MAT); for (j=k=1; j<=r; k++) if (d[k]) gel(y,j++) = gcopy(gel(x,k)); return y; } /*******************************************************************/ /* */ /* Echelon form and CUP decomposition */ /* */ /*******************************************************************/ /* By Peter Bruin, based on C.-P. Jeannerod, C. Pernet and A. Storjohann, Rank-profile revealing Gaussian elimination and the CUP matrix decomposition. J. Symbolic Comput. 56 (2013), 46-68. Decompose an m x n-matrix A of rank r as C*U*P, with - C: m x r-matrix in column echelon form (not necessarily reduced) with all pivots equal to 1 - U: upper-triangular r x n-matrix - P: permutation matrix The pivots of C and the known zeroes in C and U are not necessarily filled in; instead, we also return the vector R of pivot rows. Instead of the matrix P, we return the permutation p of [1..n] (t_VECSMALL) such that P[i,j] = 1 if and only if j = p[i]. */ /* complement of a strictly increasing subsequence of (1, 2, ..., n) */ static GEN indexcompl(GEN v, long n) { long i, j, k, m = lg(v) - 1; GEN w = cgetg(n - m + 1, t_VECSMALL); for (i = j = k = 1; i <= n; i++) if (j <= m && v[j] == i) j++; else w[k++] = i; return w; } static GEN Flm_rsolve_upper_1(GEN U, GEN B, ulong p) { return Flm_Fl_mul(B, Fl_inv(ucoeff(U, 1, 1), p), p); } static GEN Flm_rsolve_upper_2(GEN U, GEN B, ulong p) { ulong a = ucoeff(U, 1, 1), b = ucoeff(U, 1, 2), d = ucoeff(U, 2, 2); ulong D = Fl_mul(a, d, p), Dinv = Fl_inv(D, p); ulong ainv = Fl_mul(d, Dinv, p), dinv = Fl_mul(a, Dinv, p); GEN B1 = rowslice(B, 1, 1); GEN B2 = rowslice(B, 2, 2); GEN X2 = Flm_Fl_mul(B2, dinv, p); GEN X1 = Flm_Fl_mul(Flm_sub(B1, Flm_Fl_mul(X2, b, p), p), ainv, p); return vconcat(X1, X2); } /* solve U*X = B, U upper triangular and invertible */ static GEN Flm_rsolve_upper(GEN U, GEN B, ulong p) { long n = lg(U) - 1, n1; GEN U2, U11, U12, U22, B1, B2, X1, X2, X; pari_sp av = avma; if (n == 0) return B; if (n == 1) return Flm_rsolve_upper_1(U, B, p); if (n == 2) return Flm_rsolve_upper_2(U, B, p); n1 = (n + 1)/2; U2 = vecslice(U, n1 + 1, n); U22 = rowslice(U2, n1 + 1, n); B2 = rowslice(B, n1 + 1, n); X2 = Flm_rsolve_upper(U22, B2, p); U12 = rowslice(U2, 1, n1); B1 = rowslice(B, 1, n1); B1 = Flm_sub(B1, Flm_mul(U12, X2, p), p); if (gc_needed(av, 1)) gerepileall(av, 2, &B1, &X2); U11 = matslice(U, 1,n1, 1,n1); X1 = Flm_rsolve_upper(U11, B1, p); X = vconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } static GEN Flm_lsolve_upper_1(GEN U, GEN B, ulong p) { return Flm_Fl_mul(B, Fl_inv(ucoeff(U, 1, 1), p), p); } static GEN Flm_lsolve_upper_2(GEN U, GEN B, ulong p) { ulong a = ucoeff(U, 1, 1), b = ucoeff(U, 1, 2), d = ucoeff(U, 2, 2); ulong D = Fl_mul(a, d, p), Dinv = Fl_inv(D, p); ulong ainv = Fl_mul(d, Dinv, p), dinv = Fl_mul(a, Dinv, p); GEN B1 = vecslice(B, 1, 1); GEN B2 = vecslice(B, 2, 2); GEN X1 = Flm_Fl_mul(B1, ainv, p); GEN X2 = Flm_Fl_mul(Flm_sub(B2, Flm_Fl_mul(X1, b, p), p), dinv, p); return shallowconcat(X1, X2); } /* solve X*U = B, U upper triangular and invertible */ static GEN Flm_lsolve_upper(GEN U, GEN B, ulong p) { long n = lg(U) - 1, n1; GEN U2, U11, U12, U22, B1, B2, X1, X2, X; pari_sp av = avma; if (n == 0) return B; if (n == 1) return Flm_lsolve_upper_1(U, B, p); if (n == 2) return Flm_lsolve_upper_2(U, B, p); n1 = (n + 1)/2; U2 = vecslice(U, n1 + 1, n); U11 = matslice(U, 1,n1, 1,n1); U12 = rowslice(U2, 1, n1); U22 = rowslice(U2, n1 + 1, n); B1 = vecslice(B, 1, n1); B2 = vecslice(B, n1 + 1, n); X1 = Flm_lsolve_upper(U11, B1, p); B2 = Flm_sub(B2, Flm_mul(X1, U12, p), p); if (gc_needed(av, 1)) gerepileall(av, 3, &B2, &U22, &X1); X2 = Flm_lsolve_upper(U22, B2, p); X = shallowconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } static GEN Flm_rsolve_lower_unit_2(GEN L, GEN A, ulong p) { GEN X1 = rowslice(A, 1, 1); GEN X2 = Flm_sub(rowslice(A, 2, 2), Flm_Fl_mul(X1, ucoeff(L, 2, 1), p), p); return vconcat(X1, X2); } /* solve L*X = A, L lower triangular with ones on the diagonal * (at least as many rows as columns) */ static GEN Flm_rsolve_lower_unit(GEN L, GEN A, ulong p) { long m = lg(L) - 1, m1, n; GEN L1, L11, L21, L22, A1, A2, X1, X2, X; pari_sp av = avma; if (m == 0) return zero_Flm(0, lg(A) - 1); if (m == 1) return rowslice(A, 1, 1); if (m == 2) return Flm_rsolve_lower_unit_2(L, A, p); m1 = (m + 1)/2; n = nbrows(L); L1 = vecslice(L, 1, m1); L11 = rowslice(L1, 1, m1); L21 = rowslice(L1, m1 + 1, n); A1 = rowslice(A, 1, m1); X1 = Flm_rsolve_lower_unit(L11, A1, p); A2 = rowslice(A, m1 + 1, n); A2 = Flm_sub(A2, Flm_mul(L21, X1, p), p); if (gc_needed(av, 1)) gerepileall(av, 2, &A2, &X1); L22 = matslice(L, m1+1,n, m1+1,m); X2 = Flm_rsolve_lower_unit(L22, A2, p); X = vconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } static GEN Flm_lsolve_lower_unit_2(GEN L, GEN A, ulong p) { GEN X2 = vecslice(A, 2, 2); GEN X1 = Flm_sub(vecslice(A, 1, 1), Flm_Fl_mul(X2, ucoeff(L, 2, 1), p), p); return shallowconcat(X1, X2); } /* solve L*X = A, L square lower triangular with ones on the diagonal */ static GEN Flm_lsolve_lower_unit(GEN L, GEN A, ulong p) { long m = lg(L) - 1, m1; GEN L1, L2, L11, L21, L22, A1, A2, X1, X2, X; pari_sp av = avma; if (m <= 1) return A; if (m == 2) return Flm_lsolve_lower_unit_2(L, A, p); m1 = (m + 1)/2; L2 = vecslice(L, m1 + 1, m); L22 = rowslice(L2, m1 + 1, m); A2 = vecslice(A, m1 + 1, m); X2 = Flm_lsolve_lower_unit(L22, A2, p); if (gc_needed(av, 1)) X2 = gerepilecopy(av, X2); L1 = vecslice(L, 1, m1); L21 = rowslice(L1, m1 + 1, m); A1 = vecslice(A, 1, m1); A1 = Flm_sub(A1, Flm_mul(X2, L21, p), p); L11 = rowslice(L1, 1, m1); if (gc_needed(av, 1)) gerepileall(av, 3, &A1, &L11, &X2); X1 = Flm_lsolve_lower_unit(L11, A1, p); X = shallowconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } /* destroy A */ static long Flm_CUP_gauss(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, ulong p) { long i, j, k, m = nbrows(A), n = lg(A) - 1, pr, pc, u, v; if (P) *P = identity_perm(n); *R = cgetg(m + 1, t_VECSMALL); for (j = 1, pr = 0; j <= n; j++) { for (pr++, pc = 0; pr <= m; pr++) { for (k = j; k <= n; k++) { v = ucoeff(A, pr, k); if (!pc && v) pc = k; } if (pc) break; } if (!pc) break; (*R)[j] = pr; if (pc != j) { swap(gel(A, j), gel(A, pc)); if (P) lswap((*P)[j], (*P)[pc]); } u = Fl_inv(ucoeff(A, pr, j), p); for (i = pr + 1; i <= m; i++) { v = Fl_mul(ucoeff(A, i, j), u, p); ucoeff(A, i, j) = v; for (k = j + 1; k <= n; k++) ucoeff(A, i, k) = Fl_sub(ucoeff(A, i, k), Fl_mul(ucoeff(A, pr, k), v, p), p); } } setlg(*R, j); *C = vecslice(A, 1, j - 1); if (U) *U = rowpermute(A, *R); return j - 1; } static const long Flm_CUP_LIMIT = 8; static ulong Flm_CUP(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, ulong p) { long m = nbrows(A), m1, n = lg(A) - 1, i, r1, r2, r; GEN R1, C1, U1, P1, R2, C2, U2, P2; GEN A1, A2, B2, C21, U11, U12, T21, T22; pari_sp av = avma; if (m < Flm_CUP_LIMIT || n < Flm_CUP_LIMIT) /* destroy A; not called at the outermost recursion level */ return Flm_CUP_gauss(A, R, C, U, P, p); m1 = (minss(m, n) + 1)/2; A1 = rowslice(A, 1, m1); A2 = rowslice(A, m1 + 1, m); r1 = Flm_CUP(A1, &R1, &C1, &U1, &P1, p); if (r1 == 0) { r2 = Flm_CUP(A2, &R2, &C2, &U2, &P2, p); *R = cgetg(r2 + 1, t_VECSMALL); for (i = 1; i <= r2; i++) (*R)[i] = R2[i] + m1; *C = vconcat(zero_Flm(m1, r2), C2); *U = U2; *P = P2; r = r2; } else { U11 = vecslice(U1, 1, r1); U12 = vecslice(U1, r1 + 1, n); T21 = vecslicepermute(A2, P1, 1, r1); T22 = vecslicepermute(A2, P1, r1 + 1, n); C21 = Flm_lsolve_upper(U11, T21, p); if (gc_needed(av, 1)) gerepileall(av, 7, &R1, &C1, &P1, &U11, &U12, &T22, &C21); B2 = Flm_sub(T22, Flm_mul(C21, U12, p), p); r2 = Flm_CUP(B2, &R2, &C2, &U2, &P2, p); r = r1 + r2; *R = cgetg(r + 1, t_VECSMALL); for (i = 1; i <= r1; i++) (*R)[i] = R1[i]; for (; i <= r; i++) (*R)[i] = R2[i - r1] + m1; *C = shallowconcat(vconcat(C1, C21), vconcat(zero_Flm(m1, r2), C2)); *U = shallowconcat(vconcat(U11, zero_Flm(r2, r1)), vconcat(vecpermute(U12, P2), U2)); *P = cgetg(n + 1, t_VECSMALL); for (i = 1; i <= r1; i++) (*P)[i] = P1[i]; for (; i <= n; i++) (*P)[i] = P1[P2[i - r1] + r1]; } if (gc_needed(av, 1)) gerepileall(av, 4, R, C, U, P); return r; } static ulong Flm_echelon_gauss(GEN A, GEN *R, GEN *C, ulong p) { return Flm_CUP_gauss(A, R, C, NULL, NULL, p); } /* column echelon form */ static ulong Flm_echelon(GEN A, GEN *R, GEN *C, ulong p) { long j, j1, j2, m = nbrows(A), n = lg(A) - 1, n1, r, r1, r2; GEN A1, A2, R1, R1c, C1, R2, C2; GEN A12, A22, B2, C11, C21, M12; pari_sp av = avma; if (m < Flm_CUP_LIMIT || n < Flm_CUP_LIMIT) return Flm_echelon_gauss(Flm_copy(A), R, C, p); n1 = (n + 1)/2; A1 = vecslice(A, 1, n1); A2 = vecslice(A, n1 + 1, n); r1 = Flm_echelon(A1, &R1, &C1, p); if (!r1) return Flm_echelon(A2, R, C, p); if (r1 == m) { *R = R1; *C = C1; return r1; } R1c = indexcompl(R1, m); C11 = rowpermute(C1, R1); C21 = rowpermute(C1, R1c); A12 = rowpermute(A2, R1); A22 = rowpermute(A2, R1c); M12 = Flm_rsolve_lower_unit(C11, A12, p); B2 = Flm_sub(A22, Flm_mul(C21, M12, p), p); r2 = Flm_echelon(B2, &R2, &C2, p); if (!r2) { *R = R1; *C = C1; r = r1; } else { R2 = perm_mul(R1c, R2); C2 = rowpermute(vconcat(zero_Flm(r1, r2), C2), perm_inv(vecsmall_concat(R1, R1c))); r = r1 + r2; *R = cgetg(r + 1, t_VECSMALL); *C = cgetg(r + 1, t_MAT); for (j = j1 = j2 = 1; j <= r; j++) if (j2 > r2 || (j1 <= r1 && R1[j1] < R2[j2])) { gel(*C, j) = gel(C1, j1); (*R)[j] = R1[j1++]; } else { gel(*C, j) = gel(C2, j2); (*R)[j] = R2[j2++]; } } if (gc_needed(av, 1)) gerepileall(av, 2, R, C); return r; } static GEN FlxqM_rsolve_upper_1(GEN U, GEN B, GEN T, ulong p) { return FlxqM_Flxq_mul(B, Flxq_inv(gcoeff(U, 1, 1), T, p), T, p); } static GEN FlxqM_rsolve_upper_2(GEN U, GEN B, GEN T, ulong p) { GEN a = gcoeff(U, 1, 1), b = gcoeff(U, 1, 2), d = gcoeff(U, 2, 2); GEN D = Flxq_mul(a, d, T, p), Dinv = Flxq_inv(D, T, p); GEN ainv = Flxq_mul(d, Dinv, T, p), dinv = Flxq_mul(a, Dinv, T, p); GEN B1 = rowslice(B, 1, 1); GEN B2 = rowslice(B, 2, 2); GEN X2 = FlxqM_Flxq_mul(B2, dinv, T, p); GEN X1 = FlxqM_Flxq_mul(FlxM_sub(B1, FlxqM_Flxq_mul(X2, b, T, p), p), ainv, T, p); return vconcat(X1, X2); } /* solve U*X = B, U upper triangular and invertible */ static GEN FlxqM_rsolve_upper(GEN U, GEN B, GEN T, ulong p) { long n = lg(U) - 1, n1; GEN U2, U11, U12, U22, B1, B2, X1, X2, X; pari_sp av = avma; if (n == 0) return B; if (n == 1) return FlxqM_rsolve_upper_1(U, B, T, p); if (n == 2) return FlxqM_rsolve_upper_2(U, B, T, p); n1 = (n + 1)/2; U2 = vecslice(U, n1 + 1, n); U11 = matslice(U, 1,n1, 1,n1); U12 = rowslice(U2, 1, n1); U22 = rowslice(U2, n1 + 1, n); B1 = rowslice(B, 1, n1); B2 = rowslice(B, n1 + 1, n); X2 = FlxqM_rsolve_upper(U22, B2, T, p); B1 = FlxM_sub(B1, FlxqM_mul(U12, X2, T, p), p); if (gc_needed(av, 1)) gerepileall(av, 3, &B1, &U11, &X2); X1 = FlxqM_rsolve_upper(U11, B1, T, p); X = vconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } static GEN FlxqM_lsolve_upper_1(GEN U, GEN B, GEN T, ulong p) { return FlxqM_Flxq_mul(B, Flxq_inv(gcoeff(U, 1, 1), T, p), T, p); } static GEN FlxqM_lsolve_upper_2(GEN U, GEN B, GEN T, ulong p) { GEN a = gcoeff(U, 1, 1), b = gcoeff(U, 1, 2), d = gcoeff(U, 2, 2); GEN D = Flxq_mul(a, d, T, p), Dinv = Flxq_inv(D, T, p); GEN ainv = Flxq_mul(d, Dinv, T, p), dinv = Flxq_mul(a, Dinv, T, p); GEN B1 = vecslice(B, 1, 1); GEN B2 = vecslice(B, 2, 2); GEN X1 = FlxqM_Flxq_mul(B1, ainv, T, p); GEN X2 = FlxqM_Flxq_mul(FlxM_sub(B2, FlxqM_Flxq_mul(X1, b, T, p), p), dinv, T, p); return shallowconcat(X1, X2); } /* solve X*U = B, U upper triangular and invertible */ static GEN FlxqM_lsolve_upper(GEN U, GEN B, GEN T, ulong p) { long n = lg(U) - 1, n1; GEN U2, U11, U12, U22, B1, B2, X1, X2, X; pari_sp av = avma; if (n == 0) return B; if (n == 1) return FlxqM_lsolve_upper_1(U, B, T, p); if (n == 2) return FlxqM_lsolve_upper_2(U, B, T, p); n1 = (n + 1)/2; U2 = vecslice(U, n1 + 1, n); U11 = matslice(U, 1,n1, 1,n1); U12 = rowslice(U2, 1, n1); U22 = rowslice(U2, n1 + 1, n); B1 = vecslice(B, 1, n1); B2 = vecslice(B, n1 + 1, n); X1 = FlxqM_lsolve_upper(U11, B1, T, p); B2 = FlxM_sub(B2, FlxqM_mul(X1, U12, T, p), p); if (gc_needed(av, 1)) gerepileall(av, 3, &B2, &U22, &X1); X2 = FlxqM_lsolve_upper(U22, B2, T, p); X = shallowconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } static GEN FlxqM_rsolve_lower_unit_2(GEN L, GEN A, GEN T, ulong p) { GEN X1 = rowslice(A, 1, 1); GEN X2 = FlxM_sub(rowslice(A, 2, 2), FlxqM_Flxq_mul(X1, gcoeff(L, 2, 1), T, p), p); return vconcat(X1, X2); } /* solve L*X = A, L lower triangular with ones on the diagonal * (at least as many rows as columns) */ static GEN FlxqM_rsolve_lower_unit(GEN L, GEN A, GEN T, ulong p) { long m = lg(L) - 1, m1, n; GEN L1, L11, L21, L22, A1, A2, X1, X2, X; pari_sp av = avma; if (m == 0) return zeromat(0, lg(A) - 1); if (m == 1) return rowslice(A, 1, 1); if (m == 2) return FlxqM_rsolve_lower_unit_2(L, A, T, p); m1 = (m + 1)/2; n = nbrows(L); L1 = vecslice(L, 1, m1); L11 = rowslice(L1, 1, m1); L21 = rowslice(L1, m1 + 1, n); A1 = rowslice(A, 1, m1); A2 = rowslice(A, m1 + 1, n); X1 = FlxqM_rsolve_lower_unit(L11, A1, T, p); A2 = FlxM_sub(A2, FlxqM_mul(L21, X1, T, p), p); if (gc_needed(av, 1)) gerepileall(av, 2, &A2, &X1); L22 = matslice(L, m1+1,n, m1+1,m); X2 = FlxqM_rsolve_lower_unit(L22, A2, T, p); X = vconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } static GEN FlxqM_lsolve_lower_unit_2(GEN L, GEN A, GEN T, ulong p) { GEN X2 = vecslice(A, 2, 2); GEN X1 = FlxM_sub(vecslice(A, 1, 1), FlxqM_Flxq_mul(X2, gcoeff(L, 2, 1), T, p), p); return shallowconcat(X1, X2); } /* solve L*X = A, L square lower triangular with ones on the diagonal */ static GEN FlxqM_lsolve_lower_unit(GEN L, GEN A, GEN T, ulong p) { long m = lg(L) - 1, m1; GEN L1, L2, L11, L21, L22, A1, A2, X1, X2, X; pari_sp av = avma; if (m <= 1) return A; if (m == 2) return FlxqM_lsolve_lower_unit_2(L, A, T, p); m1 = (m + 1)/2; L1 = vecslice(L, 1, m1); L2 = vecslice(L, m1 + 1, m); L11 = rowslice(L1, 1, m1); L21 = rowslice(L1, m1 + 1, m); L22 = rowslice(L2, m1 + 1, m); A1 = vecslice(A, 1, m1); A2 = vecslice(A, m1 + 1, m); X2 = FlxqM_lsolve_lower_unit(L22, A2, T, p); A1 = FlxM_sub(A1, FlxqM_mul(X2, L21, T, p), p); if (gc_needed(av, 1)) gerepileall(av, 3, &A1, &L11, &X2); X1 = FlxqM_lsolve_lower_unit(L11, A1, T, p); X = shallowconcat(X1, X2); if (gc_needed(av, 1)) X = gerepilecopy(av, X); return X; } /* destroy A */ static long FlxqM_CUP_gauss(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, GEN T, ulong p) { long i, j, k, m = nbrows(A), n = lg(A) - 1, pr, pc; pari_sp av; GEN u, v; if (P) *P = identity_perm(n); *R = cgetg(m + 1, t_VECSMALL); av = avma; for (j = 1, pr = 0; j <= n; j++) { for (pr++, pc = 0; pr <= m; pr++) { for (k = j; k <= n; k++) { v = Flx_rem(gcoeff(A, pr, k), T, p); gcoeff(A, pr, k) = v; if (!pc && lgpol(v) > 0) pc = k; } if (pc) break; } if (!pc) break; (*R)[j] = pr; if (pc != j) { swap(gel(A, j), gel(A, pc)); if (P) lswap((*P)[j], (*P)[pc]); } u = Flxq_inv(gcoeff(A, pr, j), T, p); for (i = pr + 1; i <= m; i++) { v = Flxq_mul(gcoeff(A, i, j), u, T, p); gcoeff(A, i, j) = v; for (k = j + 1; k <= n; k++) gcoeff(A, i, k) = Flx_sub(gcoeff(A, i, k), Flx_mul(gcoeff(A, pr, k), v, p), p); } if (gc_needed(av, 2)) A = gerepilecopy(av, A); } setlg(*R, j); *C = vecslice(A, 1, j - 1); if (U) *U = rowpermute(A, *R); return j - 1; } static const long FlxqM_CUP_LIMIT = 5; static ulong FlxqM_CUP(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, GEN T, ulong p) { long m = nbrows(A), m1, n = lg(A) - 1, i, r1, r2, r, sv; GEN R1, C1, U1, P1, R2, C2, U2, P2; GEN A1, A2, B2, C21, U11, U12, T21, T22; pari_sp av = avma; if (m < FlxqM_CUP_LIMIT || n < FlxqM_CUP_LIMIT) /* destroy A; not called at the outermost recursion level */ return FlxqM_CUP_gauss(A, R, C, U, P, T, p); sv = get_Flx_var(T); m1 = (minss(m, n) + 1)/2; A1 = rowslice(A, 1, m1); A2 = rowslice(A, m1 + 1, m); r1 = FlxqM_CUP(A1, &R1, &C1, &U1, &P1, T, p); if (r1 == 0) { r2 = FlxqM_CUP(A2, &R2, &C2, &U2, &P2, T, p); *R = cgetg(r2 + 1, t_VECSMALL); for (i = 1; i <= r2; i++) (*R)[i] = R2[i] + m1; *C = vconcat(zero_FlxM(m1, r2, sv), C2); *U = U2; *P = P2; r = r2; } else { U11 = vecslice(U1, 1, r1); U12 = vecslice(U1, r1 + 1, n); T21 = vecslicepermute(A2, P1, 1, r1); T22 = vecslicepermute(A2, P1, r1 + 1, n); C21 = FlxqM_lsolve_upper(U11, T21, T, p); if (gc_needed(av, 1)) gerepileall(av, 7, &R1, &C1, &P1, &U11, &U12, &T22, &C21); B2 = FlxM_sub(T22, FlxqM_mul(C21, U12, T, p), p); r2 = FlxqM_CUP(B2, &R2, &C2, &U2, &P2, T, p); r = r1 + r2; *R = cgetg(r + 1, t_VECSMALL); for (i = 1; i <= r1; i++) (*R)[i] = R1[i]; for ( ; i <= r; i++) (*R)[i] = R2[i - r1] + m1; *C = shallowmatconcat(mkmat2(mkcol2(C1, C21), mkcol2(zero_FlxM(m1, r2, sv), C2))); *U = shallowmatconcat(mkmat2(mkcol2(U11, zero_FlxM(r2, r1, sv)), mkcol2(vecpermute(U12, P2), U2))); *P = cgetg(n + 1, t_VECSMALL); for (i = 1; i <= r1; i++) (*P)[i] = P1[i]; for ( ; i <= n; i++) (*P)[i] = P1[P2[i - r1] + r1]; } if (gc_needed(av, 1)) gerepileall(av, 4, R, C, U, P); return r; } static ulong FlxqM_echelon_gauss(GEN A, GEN *R, GEN *C, GEN T, ulong p) { return FlxqM_CUP_gauss(A, R, C, NULL, NULL, T, p); } /* column echelon form */ static ulong FlxqM_echelon(GEN A, GEN *R, GEN *C, GEN T, ulong p) { long j, j1, j2, m = nbrows(A), n = lg(A) - 1, n1, r, r1, r2; GEN A1, A2, R1, R1c, C1, R2, C2; GEN A12, A22, B2, C11, C21, M12; pari_sp av = avma; if (m < FlxqM_CUP_LIMIT || n < FlxqM_CUP_LIMIT) return FlxqM_echelon_gauss(shallowcopy(A), R, C, T, p); n1 = (n + 1)/2; A1 = vecslice(A, 1, n1); A2 = vecslice(A, n1 + 1, n); r1 = FlxqM_echelon(A1, &R1, &C1, T, p); if (!r1) return FlxqM_echelon(A2, R, C, T, p); if (r1 == m) { *R = R1; *C = C1; return r1; } R1c = indexcompl(R1, m); C11 = rowpermute(C1, R1); C21 = rowpermute(C1, R1c); A12 = rowpermute(A2, R1); A22 = rowpermute(A2, R1c); M12 = FlxqM_rsolve_lower_unit(C11, A12, T, p); B2 = FlxM_sub(A22, FlxqM_mul(C21, M12, T, p), p); r2 = FlxqM_echelon(B2, &R2, &C2, T, p); if (!r2) { *R = R1; *C = C1; r = r1; } else { R2 = perm_mul(R1c, R2); C2 = rowpermute(vconcat(zero_FlxM(r1, r2, get_Flx_var(T)), C2), perm_inv(vecsmall_concat(R1, R1c))); r = r1 + r2; *R = cgetg(r + 1, t_VECSMALL); *C = cgetg(r + 1, t_MAT); for (j = j1 = j2 = 1; j <= r; j++) { if (j2 > r2 || (j1 <= r1 && R1[j1] < R2[j2])) { gel(*C, j) = gel(C1, j1); (*R)[j] = R1[j1++]; } else { gel(*C, j) = gel(C2, j2); (*R)[j] = R2[j2++]; } } } if (gc_needed(av, 1)) gerepileall(av, 2, R, C); return r; } /*******************************************************************/ /* */ /* LINEAR ALGEBRA MODULO P */ /* */ /*******************************************************************/ static long F2v_find_nonzero(GEN x0, GEN mask0, long m) { ulong *x = (ulong *)x0+2, *mask = (ulong *)mask0+2, e; long i, l = lg(x0)-2; for (i = 0; i < l; i++) { e = *x++ & *mask++; if (e) return i*BITS_IN_LONG+vals(e)+1; } return m+1; } /* in place, destroy x */ GEN F2m_ker_sp(GEN x, long deplin) { GEN y, c, d; long i, j, k, r, m, n; n = lg(x)-1; m = mael(x,1,1); r=0; d = cgetg(n+1, t_VECSMALL); c = const_F2v(m); for (k=1; k<=n; k++) { GEN xk = gel(x,k); j = F2v_find_nonzero(xk, c, m); if (j>m) { if (deplin) { GEN c = zero_F2v(n); for (i=1; i m) { if (deplin==1) { c = cgetg(n+1, t_VECSMALL); for (i=1; i m) { if (deplin==1) { c = cgetg(n+1, t_VECSMALL); for (i=1; i= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT) switch(deplin) { case 0: return Flm_ker_echelon(x, p, 0); case 1: return Flm_deplin_echelon(x, p); case 2: return Flm_ker_echelon(x, p, 1); } return Flm_ker_gauss(inplace? x: Flm_copy(x), p, deplin); } GEN Flm_ker_sp(GEN x, ulong p, long deplin) { return Flm_ker_i(x, p, deplin, 1); } GEN Flm_ker(GEN x, ulong p) { return Flm_ker_i(x, p, 0, 0); } GEN Flm_deplin(GEN x, ulong p) { return Flm_ker_i(x, p, 1, 0); } ulong F2m_det_sp(GEN x) { return !F2m_ker_sp(x, 1); } ulong F2m_det(GEN x) { pari_sp av = avma; ulong d = F2m_det_sp(F2m_copy(x)); avma = av; return d; } /* in place, destroy a, SMALL_ULONG(p) is TRUE */ static ulong Flm_det_gauss_OK(GEN a, long nbco, ulong p) { long i,j,k, s = 1; ulong q, x = 1; for (i=1; i nbco) return ucoeff(a,i,i); if (k != i) { /* exchange the lines s.t. k = i */ for (j=i; j<=nbco; j++) lswap(ucoeff(a,i,j), ucoeff(a,k,j)); s = -s; } q = ucoeff(a,i,i); if (x & HIGHMASK) x %= p; x *= q; q = Fl_inv(q,p); for (k=i+1; k<=nbco; k++) { ulong m = ucoeff(a,i,k) % p; if (!m) continue; m = p - ((m*q)%p); for (j=i+1; j<=nbco; j++) { ulong c = ucoeff(a,j,k); if (c & HIGHMASK) c %= p; ucoeff(a,j,k) = c + m*ucoeff(a,j,i); } } } if (x & HIGHMASK) x %= p; q = ucoeff(a,nbco,nbco); if (q & HIGHMASK) q %= p; x = (x*q) % p; if (s < 0 && x) x = p - x; return x; } /* in place, destroy a */ static ulong Flm_det_gauss(GEN a, ulong p) { long i,j,k, s = 1, nbco = lg(a)-1; ulong pi, q, x = 1; if (SMALL_ULONG(p)) return Flm_det_gauss_OK(a, nbco, p); pi = get_Fl_red(p); for (i=1; i nbco) return ucoeff(a,i,i); if (k != i) { /* exchange the lines s.t. k = i */ for (j=i; j<=nbco; j++) lswap(ucoeff(a,i,j), ucoeff(a,k,j)); s = -s; } q = ucoeff(a,i,i); x = Fl_mul_pre(x, q, p, pi); q = Fl_inv(q,p); for (k=i+1; k<=nbco; k++) { ulong m = ucoeff(a,i,k); if (!m) continue; m = Fl_mul_pre(m, q, p, pi); for (j=i+1; j<=nbco; j++) ucoeff(a,j,k) = Fl_sub(ucoeff(a,j,k), Fl_mul_pre(m,ucoeff(a,j,i), p, pi), p); } } if (s < 0) x = Fl_neg(x, p); return Fl_mul(x, ucoeff(a,nbco,nbco), p); } static ulong Flm_det_CUP(GEN a, ulong p) { GEN R, C, U, P; long d, i, n = lg(a) - 1, r; r = Flm_CUP(a, &R, &C, &U, &P, p); if (r < n) d = 0; else { d = perm_sign(P) == 1? 1: p-1; for (i = 1; i <= n; i++) d = Fl_mul(d, ucoeff(U, i, i), p); } return d; } static ulong Flm_det_i(GEN x, ulong p, long inplace) { pari_sp av = avma; ulong d; if (lg(x) - 1 >= Flm_CUP_LIMIT) d = Flm_det_CUP(x, p); else d = Flm_det_gauss(inplace? x: Flm_copy(x), p); avma = av; return d; } ulong Flm_det_sp(GEN x, ulong p) { return Flm_det_i(x, p, 1); } ulong Flm_det(GEN x, ulong p) { return Flm_det_i(x, p, 0); } static GEN FpM_init(GEN a, GEN p, ulong *pp) { if (lgefint(p) == 3) { *pp = uel(p,2); return (*pp==2)? ZM_to_F2m(a): ZM_to_Flm(a, *pp); } *pp = 0; return a; } GEN RgM_Fp_init(GEN a, GEN p, ulong *pp) { if (lgefint(p) == 3) { *pp = uel(p,2); return (*pp==2)? RgM_to_F2m(a): RgM_to_Flm(a, *pp); } *pp = 0; return RgM_to_FpM(a,p); } static GEN FpM_det_gen(GEN a, GEN p) { void *E; const struct bb_field *S = get_Fp_field(&E,p); return gen_det(a, E, S); } GEN FpM_det(GEN a, GEN p) { pari_sp av = avma; ulong pp, d; a = FpM_init(a, p, &pp); switch(pp) { case 0: return FpM_det_gen(a, p); case 2: d = F2m_det_sp(a); break; default:d = Flm_det_sp(a,pp); break; } avma = av; return utoi(d); } /* Destroy x */ static GEN F2m_gauss_pivot(GEN x, long *rr) { GEN c, d; long i, j, k, r, m, n; n = lg(x)-1; if (!n) { *rr=0; return NULL; } m = mael(x,1,1); r=0; d = cgetg(n+1, t_VECSMALL); c = const_F2v(m); for (k=1; k<=n; k++) { GEN xk = gel(x,k); j = F2v_find_nonzero(xk, c, m); if (j>m) { r++; d[k] = 0; } else { F2v_clear(c,j); d[k] = j; for (i=k+1; i<=n; i++) { GEN xi = gel(x,i); if (F2v_coeff(xi,j)) F2v_add_inplace(xi, xk); } } } *rr = r; avma = (pari_sp)d; return d; } /* Destroy x */ static GEN Flm_gauss_pivot(GEN x, ulong p, long *rr) { GEN c,d; long i,j,k,r,t,n,m; n=lg(x)-1; if (!n) { *rr=0; return NULL; } m=nbrows(x); r=0; d=cgetg(n+1,t_VECSMALL); c = zero_zv(m); for (k=1; k<=n; k++) { for (j=1; j<=m; j++) if (!c[j]) { ucoeff(x,j,k) %= p; if (ucoeff(x,j,k)) break; } if (j>m) { r++; d[k]=0; } else { ulong piv = p - Fl_inv(ucoeff(x,j,k), p); c[j]=k; d[k]=j; for (i=k+1; i<=n; i++) ucoeff(x,j,i) = Fl_mul(piv, ucoeff(x,j,i), p); for (t=1; t<=m; t++) if (!c[t]) /* no pivot on that line yet */ { piv = ucoeff(x,t,k); if (piv) { ucoeff(x,t,k) = 0; for (i=k+1; i<=n; i++) ucoeff(x,t,i) = Fl_add(ucoeff(x,t,i), Fl_mul(piv,ucoeff(x,j,i),p),p); } } for (i=k; i<=n; i++) ucoeff(x,j,i) = 0; /* dummy */ } } *rr = r; avma = (pari_sp)d; return d; } static GEN Flm_pivots_CUP(GEN x, ulong p, long *rr) { pari_sp av; long i, n = lg(x) - 1, r; GEN R, C, U, P, d = zero_zv(n); av = avma; r = Flm_CUP(x, &R, &C, &U, &P, p); for(i = 1; i <= r; i++) d[P[i]] = R[i]; avma = av; *rr = n - r; return d; } static GEN Flm_pivots(GEN x, ulong p, long *rr, long inplace) { if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT) return Flm_pivots_CUP(x, p, rr); return Flm_gauss_pivot(inplace? x: Flm_copy(x), p, rr); } static GEN FpM_gauss_pivot_gen(GEN x, GEN p, long *rr) { void *E; const struct bb_field *S = get_Fp_field(&E,p); return gen_Gauss_pivot(x, rr, E, S); } static GEN FpM_gauss_pivot(GEN x, GEN p, long *rr) { ulong pp; if (lg(x)==1) { *rr = 0; return NULL; } x = FpM_init(x, p, &pp); switch(pp) { case 0: return FpM_gauss_pivot_gen(x, p, rr); case 2: return F2m_gauss_pivot(x, rr); default:return Flm_pivots(x, pp, rr, 1); } } GEN FpM_image(GEN x, GEN p) { long r; GEN d = FpM_gauss_pivot(x,p,&r); /* d left on stack for efficiency */ return image_from_pivot(x,d,r); } GEN Flm_image(GEN x, ulong p) { long r; GEN d = Flm_pivots(x, p, &r, 0); /* d left on stack for efficiency */ return image_from_pivot(x,d,r); } GEN F2m_image(GEN x) { long r; GEN d = F2m_gauss_pivot(F2m_copy(x),&r); /* d left on stack for efficiency */ return image_from_pivot(x,d,r); } long FpM_rank(GEN x, GEN p) { pari_sp av = avma; long r; (void)FpM_gauss_pivot(x,p,&r); avma = av; return lg(x)-1 - r; } long Flm_rank(GEN x, ulong p) { pari_sp av = avma; long r; if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT) { GEN R, C; r = Flm_echelon(x, &R, &C, p); avma = av; return r; } (void) Flm_pivots(x, p, &r, 0); avma = av; return lg(x)-1 - r; } long F2m_rank(GEN x) { pari_sp av = avma; long r; (void)F2m_gauss_pivot(F2m_copy(x),&r); avma = av; return lg(x)-1 - r; } static GEN FlxqM_gauss_pivot(GEN x, GEN T, ulong p, long *rr) { void *E; const struct bb_field *S = get_Flxq_field(&E, T, p); return gen_Gauss_pivot(x, rr, E, S); } static GEN FlxqM_pivots_CUP(GEN x, GEN T, ulong p, long *rr) { pari_sp av; long i, n = lg(x) - 1, r; GEN R, C, U, P, d = zero_zv(n); av = avma; r = FlxqM_CUP(x, &R, &C, &U, &P, T, p); for(i = 1; i <= r; i++) d[P[i]] = R[i]; avma = av; *rr = n - r; return d; } static GEN FlxqM_pivots(GEN x, GEN T, ulong p, long *rr) { if (lg(x) - 1 >= FlxqM_CUP_LIMIT && nbrows(x) >= FlxqM_CUP_LIMIT) return FlxqM_pivots_CUP(x, T, p, rr); return FlxqM_gauss_pivot(x, T, p, rr); } GEN FlxqM_image(GEN x, GEN T, ulong p) { long r; GEN d = FlxqM_pivots(x, T, p, &r); /* d left on stack for efficiency */ return image_from_pivot(x,d,r); } long FlxqM_rank(GEN x, GEN T, ulong p) { pari_sp av = avma; long r; if (lg(x) - 1 >= FlxqM_CUP_LIMIT && nbrows(x) >= FlxqM_CUP_LIMIT) { GEN R, C; r = FlxqM_echelon(x, &R, &C, T, p); avma = av; return r; } (void) FlxqM_pivots(x, T, p, &r); avma = av; return lg(x)-1 - r; } static GEN FlxqM_det_gen(GEN a, GEN T, ulong p) { void *E; const struct bb_field *S = get_Flxq_field(&E, T, p); return gen_det(a, E, S); } static GEN FlxqM_det_CUP(GEN a, GEN T, ulong p) { pari_sp av = avma; GEN R, C, U, P, d; long i, n = lg(a) - 1, r, sv = get_Flx_var(T); r = FlxqM_CUP(a, &R, &C, &U, &P, T, p); if (r < n) d = pol0_Flx(sv); else { d = mkvecsmall2(sv, perm_sign(P) == 1? 1: p - 1); for (i = 1; i <= n; i++) d = Flxq_mul(d, gcoeff(U, i, i), T, p); } return gerepileuptoleaf(av, d); } GEN FlxqM_det(GEN a, GEN T, ulong p) { if (lg(a) - 1 >= FlxqM_CUP_LIMIT) return FlxqM_det_CUP(a, T, p); else return FlxqM_det_gen(a, T, p); } GEN FlxqM_FlxqC_invimage(GEN A, GEN B, GEN T, ulong p) { void *E; const struct bb_field *ff = get_Flxq_field(&E, T, p); return gen_matcolinvimage(A, B, E, ff); } GEN FlxqM_FlxqC_mul(GEN A, GEN B, GEN T, ulong p) { void *E; const struct bb_field *ff = get_Flxq_field(&E, T, p); return gen_matcolmul(A, B, E, ff); } GEN FlxqM_mul(GEN A, GEN B, GEN T, ulong p) { void *E; const struct bb_field *ff; long n = lg(A) - 1; if (n == 0) return cgetg(1, t_MAT); if (n > 1) return FlxqM_mul_Kronecker(A, B, T, p); ff = get_Flxq_field(&E, T, p); return gen_matmul(A, B, E, ff); } static GEN FlxqM_invimage_gen(GEN A, GEN B, GEN T, ulong p) { void *E; const struct bb_field *ff = get_Flxq_field(&E, T, p); return gen_matinvimage(A, B, E, ff); } static GEN FlxqM_invimage_CUP(GEN A, GEN B, GEN T, ulong p) { pari_sp av = avma; GEN R, Rc, C, U, P, B1, B2, C1, C2, X, Y, Z; long r, sv = get_Flx_var(T); r = FlxqM_CUP(A, &R, &C, &U, &P, T, p); Rc = indexcompl(R, nbrows(B)); C1 = rowpermute(C, R); C2 = rowpermute(C, Rc); B1 = rowpermute(B, R); B2 = rowpermute(B, Rc); Z = FlxqM_rsolve_lower_unit(C1, B1, T, p); if (!gequal(FlxqM_mul(C2, Z, T, p), B2)) return NULL; Y = vconcat(FlxqM_rsolve_upper(vecslice(U, 1, r), Z, T, p), zero_FlxM(lg(A) - 1 - r, lg(B) - 1, sv)); X = rowpermute(Y, perm_inv(P)); return gerepilecopy(av, X); } GEN FlxqM_invimage(GEN A, GEN B, GEN T, ulong p) { long nA = lg(A)-1, nB = lg(B)-1; if (!nB) return cgetg(1, t_MAT); if (nA + nB >= FlxqM_CUP_LIMIT && nbrows(B) >= FlxqM_CUP_LIMIT) return FlxqM_invimage_CUP(A, B, T, p); return FlxqM_invimage_gen(A, B, T, p); } GEN F2xqM_det(GEN a, GEN T) { void *E; const struct bb_field *S = get_F2xq_field(&E, T); return gen_det(a, E, S); } static GEN F2xqM_gauss_gen(GEN a, GEN b, GEN T) { void *E; const struct bb_field *S = get_F2xq_field(&E, T); return gen_Gauss(a, b, E, S); } GEN F2xqM_gauss(GEN a, GEN b, GEN T) { pari_sp av = avma; long n = lg(a)-1; GEN u; if (!n || lg(b)==1) { avma = av; return cgetg(1, t_MAT); } u = F2xqM_gauss_gen(a, b, T); if (!u) { avma = av; return NULL; } return gerepilecopy(av, u); } GEN F2xqM_inv(GEN a, GEN T) { pari_sp av = avma; GEN u; if (lg(a) == 1) { avma = av; return cgetg(1, t_MAT); } u = F2xqM_gauss_gen(a, matid_F2xqM(nbrows(a),T), T); if (!u) { avma = av; return NULL; } return gerepilecopy(av, u); } GEN F2xqM_F2xqC_gauss(GEN a, GEN b, GEN T) { pari_sp av = avma; GEN u; if (lg(a) == 1) return cgetg(1, t_COL); u = F2xqM_gauss_gen(a, mkmat(b), T); if (!u) { avma = av; return NULL; } return gerepilecopy(av, gel(u,1)); } GEN F2xqM_F2xqC_invimage(GEN A, GEN B, GEN T) { void *E; const struct bb_field *ff = get_F2xq_field(&E, T); return gen_matcolinvimage(A, B, E, ff); } GEN F2xqM_F2xqC_mul(GEN A, GEN B, GEN T) { void *E; const struct bb_field *ff = get_F2xq_field(&E, T); return gen_matcolmul(A, B, E, ff); } GEN F2xqM_mul(GEN A, GEN B, GEN T) { void *E; const struct bb_field *ff = get_F2xq_field(&E, T); return gen_matmul(A, B, E, ff); } GEN F2xqM_invimage(GEN A, GEN B, GEN T) { void *E; const struct bb_field *ff = get_F2xq_field(&E, T); return gen_matinvimage(A, B, E, ff); } static GEN FqM_gauss_pivot_gen(GEN x, GEN T, GEN p, long *rr) { void *E; const struct bb_field *S = get_Fq_field(&E,T,p); return gen_Gauss_pivot(x, rr, E, S); } static GEN FqM_gauss_pivot(GEN x, GEN T, GEN p, long *rr) { if (lg(x)==1) { *rr = 0; return NULL; } if (!T) return FpM_gauss_pivot(x, p, rr); if (lgefint(p) == 3) { pari_sp av = avma; ulong pp = uel(p,2); GEN Tp = ZXT_to_FlxT(T, pp); GEN d = FlxqM_gauss_pivot(FqM_to_FlxM(x, T, p), Tp, pp, rr); return d ? gerepileuptoleaf(av, d): d; } return FqM_gauss_pivot_gen(x, T, p, rr); } GEN FqM_image(GEN x, GEN T, GEN p) { long r; GEN d = FqM_gauss_pivot(x,T,p,&r); /* d left on stack for efficiency */ return image_from_pivot(x,d,r); } long FqM_rank(GEN x, GEN T, GEN p) { pari_sp av = avma; long r; (void)FqM_gauss_pivot(x,T,p,&r); avma = av; return lg(x)-1 - r; } GEN FqM_det(GEN x, GEN T, GEN p) { void *E; const struct bb_field *S = get_Fq_field(&E,T,p); return gen_det(x, E, S); } GEN FqM_FqC_invimage(GEN A, GEN B, GEN T, GEN p) { void *E; const struct bb_field *ff = get_Fq_field(&E, T, p); return gen_matcolinvimage(A, B, E, ff); } GEN FqM_FqC_mul(GEN A, GEN B, GEN T, GEN p) { void *E; const struct bb_field *ff = get_Fq_field(&E, T, p); return gen_matcolmul(A, B, E, ff); } GEN FqM_mul(GEN A, GEN B, GEN T, GEN p) { void *E; long n = lg(A) - 1; const struct bb_field *ff; if (n == 0) return cgetg(1, t_MAT); if (n > 1) return FqM_mul_Kronecker(A, B, T, p); ff = get_Fq_field(&E, T, p); return gen_matmul(A, B, E, ff); } GEN FqM_invimage(GEN A, GEN B, GEN T, GEN p) { void *E; const struct bb_field *ff = get_Fq_field(&E, T, p); return gen_matinvimage(A, B, E, ff); } static GEN FpM_ker_gen(GEN x, GEN p, long deplin) { void *E; const struct bb_field *S = get_Fp_field(&E,p); return gen_ker(x, deplin, E, S); } static GEN FpM_ker_i(GEN x, GEN p, long deplin) { pari_sp av = avma; ulong pp; GEN y; if (lg(x)==1) return cgetg(1,t_MAT); x = FpM_init(x, p, &pp); switch(pp) { case 0: return FpM_ker_gen(x,p,deplin); case 2: y = F2m_ker_sp(x, deplin); if (!y) return y; y = deplin? F2c_to_ZC(y): F2m_to_ZM(y); return gerepileupto(av, y); default: y = Flm_ker_sp(x, pp, deplin); if (!y) return y; y = deplin? Flc_to_ZC(y): Flm_to_ZM(y); return gerepileupto(av, y); } } GEN FpM_ker(GEN x, GEN p) { return FpM_ker_i(x,p,0); } GEN FpM_deplin(GEN x, GEN p) { return FpM_ker_i(x,p,1); } static GEN FqM_ker_gen(GEN x, GEN T, GEN p, long deplin) { void *E; const struct bb_field *S = get_Fq_field(&E,T,p); return gen_ker(x,deplin,E,S); } static GEN FqM_ker_i(GEN x, GEN T, GEN p, long deplin) { if (!T) return FpM_ker_i(x,p,deplin); if (lg(x)==1) return cgetg(1,t_MAT); if (lgefint(p)==3) { pari_sp ltop=avma; ulong l= p[2]; GEN Ml = FqM_to_FlxM(x, T, p); GEN Tl = ZXT_to_FlxT(T,l); GEN p1 = FlxM_to_ZXM(FlxqM_ker(Ml,Tl,l)); return gerepileupto(ltop,p1); } return FqM_ker_gen(x, T, p, deplin); } GEN FqM_ker(GEN x, GEN T, GEN p) { return FqM_ker_i(x,T,p,0); } GEN FqM_deplin(GEN x, GEN T, GEN p) { return FqM_ker_i(x,T,p,1); } static GEN FlxqM_ker_gen(GEN x, GEN T, ulong p, long deplin) { const struct bb_field *ff; void *E; if (lg(x)==1) return cgetg(1,t_MAT); ff=get_Flxq_field(&E,T,p); return gen_ker(x,deplin, E, ff); } static GEN FlxqM_ker_echelon(GEN x, GEN T, ulong p) { pari_sp av = avma; GEN R, Rc, C, C1, C2, S, K; long n = lg(x) - 1, r; r = FlxqM_echelon(shallowtrans(x), &R, &C, T, p); Rc = indexcompl(R, n); C1 = rowpermute(C, R); C2 = rowpermute(C, Rc); S = FlxqM_lsolve_lower_unit(C1, C2, T, p); K = vecpermute(shallowconcat(FlxM_neg(S, p), matid_FlxqM(n - r, T, p)), perm_inv(vecsmall_concat(R, Rc))); K = shallowtrans(K); return gerepilecopy(av, K); } static GEN col_ei_FlxC(long n, long i, long sv) { GEN v = zero_FlxC(n, sv); gel(v, i) = pol1_Flx(sv); return v; } static GEN FlxqM_deplin_echelon(GEN x, GEN T, ulong p) { pari_sp av = avma; GEN R, Rc, C, C1, C2, s, v; long i, n = lg(x) - 1, r, sv = get_Flx_var(T); r = FlxqM_echelon(shallowtrans(x), &R, &C, T, p); if (r == n) { avma = av; return NULL; } Rc = indexcompl(R, n); i = Rc[1]; C1 = rowpermute(C, R); C2 = rowslice(C, i, i); s = row(FlxqM_lsolve_lower_unit(C1, C2, T, p), 1); settyp(s, t_COL); v = vecpermute(shallowconcat(FlxC_neg(s, p), col_ei_FlxC(n - r, 1, sv)), perm_inv(vecsmall_concat(R, Rc))); return gerepilecopy(av, v); } static GEN FlxqM_ker_i(GEN x, GEN T, ulong p, long deplin) { if (lg(x) - 1 >= FlxqM_CUP_LIMIT && nbrows(x) >= FlxqM_CUP_LIMIT) return deplin? FlxqM_deplin_echelon(x, T, p): FlxqM_ker_echelon(x, T, p); return FlxqM_ker_gen(x, T, p, deplin); } GEN FlxqM_ker(GEN x, GEN T, ulong p) { return FlxqM_ker_i(x, T, p, 0); } GEN FlxqM_deplin(GEN x, GEN T, ulong p) { return FlxqM_ker_i(x, T, p, 1); } static GEN F2xqM_ker_i(GEN x, GEN T, long deplin) { const struct bb_field *ff; void *E; if (lg(x)==1) return cgetg(1,t_MAT); ff = get_F2xq_field(&E,T); return gen_ker(x,deplin, E, ff); } GEN F2xqM_ker(GEN x, GEN T) { return F2xqM_ker_i(x, T, 0); } GEN F2xqM_deplin(GEN x, GEN T) { return F2xqM_ker_i(x, T, 1); } static GEN F2xqM_gauss_pivot(GEN x, GEN T, long *rr) { void *E; const struct bb_field *S = get_F2xq_field(&E,T); return gen_Gauss_pivot(x, rr, E, S); } GEN F2xqM_image(GEN x, GEN T) { long r; GEN d = F2xqM_gauss_pivot(x,T,&r); /* d left on stack for efficiency */ return image_from_pivot(x,d,r); } long F2xqM_rank(GEN x, GEN T) { pari_sp av = avma; long r; (void)F2xqM_gauss_pivot(x,T,&r); avma = av; return lg(x)-1 - r; } /*******************************************************************/ /* */ /* Solve A*X=B (Gauss pivot) */ /* */ /*******************************************************************/ /* x ~ 0 compared to reference y */ int approx_0(GEN x, GEN y) { long tx = typ(x); if (tx == t_COMPLEX) return approx_0(gel(x,1), y) && approx_0(gel(x,2), y); return gequal0(x) || (tx == t_REAL && gexpo(y) - gexpo(x) > bit_prec(x)); } /* x a column, x0 same column in the original input matrix (for reference), * c list of pivots so far */ static long gauss_get_pivot_max(GEN X, GEN X0, long ix, GEN c) { GEN p, r, x = gel(X,ix), x0 = gel(X0,ix); long i, k = 0, ex = - (long)HIGHEXPOBIT, lx = lg(x); if (c) { for (i=1; i ex) { ex = e; k = i; } } } else { for (i=ix; i ex) { ex = e; k = i; } } } if (!k) return lx; p = gel(x,k); r = gel(x0,k); if (isrationalzero(r)) r = x0; return approx_0(p, r)? lx: k; } static long gauss_get_pivot_padic(GEN X, GEN p, long ix, GEN c) { GEN x = gel(X, ix); long i, k = 0, ex = (long)HIGHVALPBIT, lx = lg(x); if (c) { for (i=1; i0; i--) { pari_sp av = avma; GEN m = gel(b,i); for (j=i+1; j<=li; j++) m = gsub(m, gmul(gcoeff(a,i,j), gel(u,j))); gel(u,i) = gerepileupto(av, gdiv(m, gcoeff(a,i,i))); } return u; } /* assume 0 <= a[i,j] < p */ static GEN Fl_get_col_OK(GEN a, GEN b, long li, ulong p) { GEN u = cgetg(li+1,t_VECSMALL); ulong m = uel(b,li) % p; long i,j; uel(u,li) = (m * ucoeff(a,li,li)) % p; for (i = li-1; i > 0; i--) { m = p - uel(b,i)%p; for (j = i+1; j <= li; j++) { if (m & HIGHBIT) m %= p; m += ucoeff(a,i,j) * uel(u,j); /* 0 <= u[j] < p */ } m %= p; if (m) m = ((p-m) * ucoeff(a,i,i)) % p; uel(u,i) = m; } return u; } static GEN Fl_get_col(GEN a, GEN b, long li, ulong p) { GEN u = cgetg(li+1,t_VECSMALL); ulong m = uel(b,li) % p; long i,j; uel(u,li) = Fl_mul(m, ucoeff(a,li,li), p); for (i=li-1; i>0; i--) { m = b[i]%p; for (j = i+1; j <= li; j++) m = Fl_sub(m, Fl_mul(ucoeff(a,i,j), uel(u,j), p), p); if (m) m = Fl_mul(m, ucoeff(a,i,i), p); uel(u,i) = m; } return u; } /* bk -= m * bi */ static void _submul(GEN b, long k, long i, GEN m) { gel(b,k) = gsub(gel(b,k), gmul(m, gel(b,i))); } static int init_gauss(GEN a, GEN *b, long *aco, long *li, int *iscol) { *iscol = *b ? (typ(*b) == t_COL): 0; *aco = lg(a) - 1; if (!*aco) /* a empty */ { if (*b && lg(*b) != 1) pari_err_DIM("gauss"); *li = 0; return 0; } *li = nbrows(a); if (*li < *aco) pari_err_INV("gauss [no left inverse]", a); if (*b) { switch(typ(*b)) { case t_MAT: if (lg(*b) == 1) return 0; *b = RgM_shallowcopy(*b); break; case t_COL: *b = mkmat( leafcopy(*b) ); break; default: pari_err_TYPE("gauss",*b); } if (nbrows(*b) != *li) pari_err_DIM("gauss"); } else *b = matid(*li); return 1; } static GEN Flm_inv_sp(GEN a, ulong *detp, ulong p); static GEN RgM_inv_QM(GEN M) { pari_sp av = avma; GEN den, cM, pM = Q_primitive_part(M, &cM); GEN b = ZM_inv(pM, &den); if (!b) { avma = av; return NULL; } if (cM) den = gmul(den, cM); if (!gequal1(den)) b = ZM_Q_mul(b, ginv(den)); return gerepileupto(av, b); } static GEN RgM_inv_FpM(GEN a, GEN p) { ulong pp; a = RgM_Fp_init(a, p, &pp); switch(pp) { case 0: a = FpM_inv(a,p); if (a) a = FpM_to_mod(a, p); break; case 2: a = F2m_inv(a); if (a) a = F2m_to_mod(a); break; default: a = Flm_inv_sp(a, NULL, pp); if (a) a = Flm_to_mod(a, pp); } return a; } static GEN RgM_inv_FqM(GEN x, GEN pol, GEN p) { pari_sp av = avma; GEN b, T = RgX_to_FpX(pol, p); if (signe(T) == 0) pari_err_OP("^",x,gen_m1); b = FqM_inv(RgM_to_FqM(x, T, p), T, p); if (!b) { avma = av; return NULL; } return gerepileupto(av, FqM_to_mod(b, T, p)); } #define code(t1,t2) ((t1 << 6) | t2) static GEN RgM_inv_fast(GEN x) { GEN p, pol; long pa; long t = RgM_type(x, &p,&pol,&pa); switch(t) { case t_INT: /* Fall back */ case t_FRAC: return RgM_inv_QM(x); case t_FFELT: return FFM_inv(x, pol); case t_INTMOD: return RgM_inv_FpM(x, p); case code(t_POLMOD, t_INTMOD): return RgM_inv_FqM(x, pol, p); default: return gen_0; } } #undef code static GEN RgM_RgC_solve_FpC(GEN a, GEN b, GEN p) { pari_sp av = avma; ulong pp; a = RgM_Fp_init(a, p, &pp); switch(pp) { case 0: b = RgC_to_FpC(b, p); a = FpM_FpC_gauss(a,b,p); return a ? gerepileupto(av, FpC_to_mod(a, p)): NULL; case 2: b = RgV_to_F2v(b); a = F2m_F2c_gauss(a,b); return a ? gerepileupto(av, F2c_to_mod(a)): NULL; default: b = RgV_to_Flv(b, pp); a = Flm_Flc_gauss(a, b, pp); return a ? gerepileupto(av, Flc_to_mod(a, pp)): NULL; } } static GEN RgM_solve_FpM(GEN a, GEN b, GEN p) { pari_sp av = avma; ulong pp; a = RgM_Fp_init(a, p, &pp); switch(pp) { case 0: b = RgM_to_FpM(b, p); a = FpM_gauss(a,b,p); return a ? gerepileupto(av, FpM_to_mod(a, p)): NULL; case 2: b = RgM_to_F2m(b); a = F2m_gauss(a,b); return a ? gerepileupto(av, F2m_to_mod(a)): NULL; default: b = RgM_to_Flm(b, pp); a = Flm_gauss(a,b,pp); return a ? gerepileupto(av, Flm_to_mod(a, pp)): NULL; } } /* Gaussan Elimination. If a is square, return a^(-1)*b; * if a has more rows than columns and b is NULL, return c such that c a = Id. * a is a (not necessarily square) matrix * b is a matrix or column vector, NULL meaning: take the identity matrix, * effectively returning the inverse of a * If a and b are empty, the result is the empty matrix. * * li: number of rows of a and b * aco: number of columns of a * bco: number of columns of b (if matrix) */ static GEN RgM_solve_basecase(GEN a, GEN b) { pari_sp av = avma; long i, j, k, li, bco, aco; int iscol; pivot_fun pivot; GEN p, u, data; avma = av; if (lg(a)-1 == 2 && nbrows(a) == 2) { /* 2x2 matrix, start by inverting a */ GEN u = gcoeff(a,1,1), v = gcoeff(a,1,2); GEN w = gcoeff(a,2,1), x = gcoeff(a,2,2); GEN D = gsub(gmul(u,x), gmul(v,w)), ainv; if (gequal0(D)) return NULL; ainv = mkmat2(mkcol2(x, gneg(w)), mkcol2(gneg(v), u)); ainv = gmul(ainv, ginv(D)); if (b) ainv = gmul(ainv, b); return gerepileupto(av, ainv); } if (!init_gauss(a, &b, &aco, &li, &iscol)) return cgetg(1, iscol?t_COL:t_MAT); pivot = get_pivot_fun(a, a, &data); a = RgM_shallowcopy(a); bco = lg(b)-1; if(DEBUGLEVEL>4) err_printf("Entering gauss\n"); p = NULL; /* gcc -Wall */ for (i=1; i<=aco; i++) { /* k is the line where we find the pivot */ k = pivot(a, data, i, NULL); if (k > li) return NULL; if (k != i) { /* exchange the lines s.t. k = i */ for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j)); for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j)); } p = gcoeff(a,i,i); if (i == aco) break; for (k=i+1; k<=li; k++) { GEN m = gcoeff(a,k,i); if (!gequal0(m)) { m = gdiv(m,p); for (j=i+1; j<=aco; j++) _submul(gel(a,j),k,i,m); for (j=1; j<=bco; j++) _submul(gel(b,j),k,i,m); } } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gauss. i=%ld",i); gerepileall(av,2, &a,&b); } } if(DEBUGLEVEL>4) err_printf("Solving the triangular system\n"); u = cgetg(bco+1,t_MAT); for (j=1; j<=bco; j++) gel(u,j) = get_col(a,gel(b,j),p,aco); return gerepilecopy(av, iscol? gel(u,1): u); } static GEN RgM_RgC_solve_fast(GEN x, GEN y) { GEN p, pol; long pa; long t = RgM_RgC_type(x, y, &p,&pol,&pa); switch(t) { case t_INT: return ZM_gauss(x, y); case t_FRAC: return QM_gauss(x, y); case t_INTMOD: return RgM_RgC_solve_FpC(x, y, p); case t_FFELT: return FFM_FFC_gauss(x, y, pol); default: return gen_0; } } static GEN RgM_solve_fast(GEN x, GEN y) { GEN p, pol; long pa; long t = RgM_type2(x, y, &p,&pol,&pa); switch(t) { case t_INT: return ZM_gauss(x, y); case t_FRAC: return QM_gauss(x, y); case t_INTMOD: return RgM_solve_FpM(x, y, p); case t_FFELT: return FFM_gauss(x, y, pol); default: return gen_0; } } GEN RgM_solve(GEN a, GEN b) { pari_sp av = avma; GEN u; if (!b) return RgM_inv(a); u = typ(b)==t_MAT ? RgM_solve_fast(a, b): RgM_RgC_solve_fast(a, b); if (!u) { avma = av; return u; } if (u != gen_0) return u; return RgM_solve_basecase(a, b); } GEN RgM_inv(GEN a) { GEN b = RgM_inv_fast(a); return b==gen_0? RgM_solve_basecase(a, NULL): b; } /* assume dim A >= 1, A invertible + upper triangular */ static GEN RgM_inv_upper_ind(GEN A, long index) { long n = lg(A)-1, i = index, j; GEN u = zerocol(n); gel(u,i) = ginv(gcoeff(A,i,i)); for (i--; i>0; i--) { pari_sp av = avma; GEN m = gneg(gmul(gcoeff(A,i,i+1),gel(u,i+1))); /* j = i+1 */ for (j=i+2; j<=n; j++) m = gsub(m, gmul(gcoeff(A,i,j),gel(u,j))); gel(u,i) = gerepileupto(av, gdiv(m, gcoeff(A,i,i))); } return u; } GEN RgM_inv_upper(GEN A) { long i, l; GEN B = cgetg_copy(A, &l); for (i = 1; i < l; i++) gel(B,i) = RgM_inv_upper_ind(A, i); return B; } /* assume dim A >= 1, A invertible + upper triangular, 1s on diagonal */ static GEN FpM_inv_upper_1_ind(GEN A, long index, GEN p) { long n = lg(A)-1, i = index, j; GEN u = zerocol(n); gel(u,i) = gen_1; for (i--; i>0; i--) { pari_sp av = avma; GEN m = negi(mulii(gcoeff(A,i,i+1),gel(u,i+1))); /* j = i+1 */ for (j=i+2; j<=n; j++) m = subii(m, mulii(gcoeff(A,i,j),gel(u,j))); gel(u,i) = gerepileuptoint(av, modii(m,p)); } return u; } static GEN FpM_inv_upper_1(GEN A, GEN p) { long i, l; GEN B = cgetg_copy(A, &l); for (i = 1; i < l; i++) gel(B,i) = FpM_inv_upper_1_ind(A, i, p); return B; } /* assume dim A >= 1, A invertible + upper triangular, 1s on diagonal, * reduced mod p */ static GEN Flm_inv_upper_1_ind(GEN A, long index, ulong p) { long n = lg(A)-1, i = index, j; GEN u = const_vecsmall(n, 0); u[i] = 1; if (SMALL_ULONG(p)) for (i--; i>0; i--) { ulong m = ucoeff(A,i,i+1) * uel(u,i+1); /* j = i+1 */ for (j=i+2; j<=n; j++) { if (m & HIGHMASK) m %= p; m += ucoeff(A,i,j) * uel(u,j); } u[i] = Fl_neg(m % p, p); } else for (i--; i>0; i--) { ulong m = Fl_mul(ucoeff(A,i,i+1),uel(u,i+1), p); /* j = i+1 */ for (j=i+2; j<=n; j++) m = Fl_add(m, Fl_mul(ucoeff(A,i,j),uel(u,j),p), p); u[i] = Fl_neg(m, p); } return u; } static GEN F2m_inv_upper_1_ind(GEN A, long index) { pari_sp av = avma; long n = lg(A)-1, i = index, j; GEN u = const_vecsmall(n, 0); u[i] = 1; for (i--; i>0; i--) { ulong m = F2m_coeff(A,i,i+1) & uel(u,i+1); /* j = i+1 */ for (j=i+2; j<=n; j++) m ^= F2m_coeff(A,i,j) & uel(u,j); u[i] = m & 1; } return gerepileuptoleaf(av, Flv_to_F2v(u)); } static GEN Flm_inv_upper_1(GEN A, ulong p) { long i, l; GEN B = cgetg_copy(A, &l); for (i = 1; i < l; i++) gel(B,i) = Flm_inv_upper_1_ind(A, i, p); return B; } static GEN F2m_inv_upper_1(GEN A) { long i, l; GEN B = cgetg_copy(A, &l); for (i = 1; i < l; i++) gel(B,i) = F2m_inv_upper_1_ind(A, i); return B; } static GEN split_realimag_col(GEN z, long r1, long r2) { long i, ru = r1+r2; GEN x = cgetg(ru+r2+1,t_COL), y = x + r2; for (i=1; i<=r1; i++) { GEN a = gel(z,i); if (typ(a) == t_COMPLEX) a = gel(a,1); /* paranoia: a should be real */ gel(x,i) = a; } for ( ; i<=ru; i++) { GEN b, a = gel(z,i); if (typ(a) == t_COMPLEX) { b = gel(a,2); a = gel(a,1); } else b = gen_0; gel(x,i) = a; gel(y,i) = b; } return x; } GEN split_realimag(GEN x, long r1, long r2) { long i,l; GEN y; if (typ(x) == t_COL) return split_realimag_col(x,r1,r2); y = cgetg_copy(x, &l); for (i=1; i aco */ { if (F2v_coeff(b, i)) F2v_set(u, d[i]); else F2v_clear(u, d[i]); } return u; } /* destroy a, b */ static GEN F2m_gauss_sp(GEN a, GEN b) { long i, j, k, l, li, bco, aco = lg(a)-1; GEN u, d; if (!aco) return cgetg(1,t_MAT); li = gel(a,1)[1]; d = zero_Flv(li); bco = lg(b)-1; for (i=1; i<=aco; i++) { GEN ai = vecsmall_copy(gel(a,i)); if (!d[i] && F2v_coeff(ai, i)) k = i; else for (k = 1; k <= li; k++) if (!d[k] && F2v_coeff(ai,k)) break; /* found a pivot on row k */ if (k > li) return NULL; d[k] = i; /* Clear k-th row but column-wise instead of line-wise */ /* a_ij -= a_i1*a1j/a_11 line-wise grouping: L_j -= a_1j/a_11*L_1 column-wise: C_i -= a_i1/a_11*C_1 */ F2v_clear(ai,k); for (l=1; l<=aco; l++) { GEN al = gel(a,l); if (F2v_coeff(al,k)) F2v_add_inplace(al,ai); } for (l=1; l<=bco; l++) { GEN bl = gel(b,l); if (F2v_coeff(bl,k)) F2v_add_inplace(bl,ai); } } u = cgetg(bco+1,t_MAT); for (j = 1; j <= bco; j++) gel(u,j) = F2_get_col(gel(b,j), d, li, aco); return u; } GEN F2m_gauss(GEN a, GEN b) { pari_sp av = avma; if (lg(a) == 1) return cgetg(1,t_MAT); return gerepileupto(av, F2m_gauss_sp(F2m_copy(a), F2m_copy(b))); } GEN F2m_F2c_gauss(GEN a, GEN b) { pari_sp av = avma; GEN z = F2m_gauss(a, mkmat(b)); if (!z) { avma = av; return NULL; } if (lg(z) == 1) { avma = av; return cgetg(1,t_VECSMALL); } return gerepileuptoleaf(av, gel(z,1)); } GEN F2m_inv(GEN a) { pari_sp av = avma; if (lg(a) == 1) return cgetg(1,t_MAT); return gerepileupto(av, F2m_gauss_sp(F2m_copy(a), matid_F2m(gel(a,1)[1]))); } /* destroy a, b */ static GEN Flm_gauss_sp_OK(GEN a, GEN b, ulong *detp, ulong p) { long i, j, k, li, bco, aco = lg(a)-1, s = 1; ulong det = 1; GEN u; li = nbrows(a); bco = lg(b)-1; for (i=1; i<=aco; i++) { ulong invpiv; /* Fl_get_col wants 0 <= a[i,j] < p for all i,j */ for (k = 1; k < i; k++) ucoeff(a,k,i) %= p; for (k = i; k <= li; k++) { ulong piv = ( ucoeff(a,k,i) %= p ); if (piv) { ucoeff(a,k,i) = Fl_inv(piv, p); if (detp) { if (det & HIGHMASK) det %= p; det *= piv; } break; } } /* found a pivot on line k */ if (k > li) return NULL; if (k != i) { /* swap lines so that k = i */ s = -s; for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j)); for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j)); } if (i == aco) break; invpiv = p - ucoeff(a,i,i); /* -1/piv mod p */ for (k=i+1; k<=li; k++) { ulong m = ( ucoeff(a,k,i) %= p ); if (!m) continue; m = Fl_mul(m, invpiv, p); if (m == 1) { for (j=i+1; j<=aco; j++) _Fl_add_OK(gel(a,j),k,i, p); for (j=1; j<=bco; j++) _Fl_add_OK(gel(b,j),k,i, p); } else { for (j=i+1; j<=aco; j++) _Fl_addmul_OK(gel(a,j),k,i,m, p); for (j=1; j<=bco; j++) _Fl_addmul_OK(gel(b,j),k,i,m, p); } } } if (detp) { det %= p; if (s < 0 && det) det = p - det; *detp = det; } u = cgetg(bco+1,t_MAT); for (j=1; j<=bco; j++) gel(u,j) = Fl_get_col_OK(a,gel(b,j), aco,p); return u; } /* destroy a, b */ static GEN Flm_gauss_sp(GEN a, GEN b, ulong *detp, ulong p) { long i, j, k, li, bco, aco = lg(a)-1, s = 1; ulong det = 1; GEN u; ulong pi; if (!aco) { if (detp) *detp = 1; return cgetg(1,t_MAT); } if (SMALL_ULONG(p)) return Flm_gauss_sp_OK(a, b, detp, p); pi = get_Fl_red(p); li = nbrows(a); bco = lg(b)-1; for (i=1; i<=aco; i++) { ulong invpiv; /* Fl_get_col wants 0 <= a[i,j] < p for all i,j */ for (k = i; k <= li; k++) { ulong piv = ucoeff(a,k,i); if (piv) { ucoeff(a,k,i) = Fl_inv(piv, p); if (detp) det = Fl_mul_pre(det, piv, p, pi); break; } } /* found a pivot on line k */ if (k > li) return NULL; if (k != i) { /* swap lines so that k = i */ s = -s; for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j)); for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j)); } if (i == aco) break; invpiv = p - ucoeff(a,i,i); /* -1/piv mod p */ for (k=i+1; k<=li; k++) { ulong m = ucoeff(a,k,i); if (!m) continue; m = Fl_mul_pre(m, invpiv, p, pi); if (m == 1) { for (j=i+1; j<=aco; j++) _Fl_add(gel(a,j),k,i, p); for (j=1; j<=bco; j++) _Fl_add(gel(b,j),k,i, p); } else { for (j=i+1; j<=aco; j++) _Fl_addmul(gel(a,j),k,i,m, p, pi); for (j=1; j<=bco; j++) _Fl_addmul(gel(b,j),k,i,m, p, pi); } } } if (detp) { if (s < 0 && det) det = p - det; *detp = det; } u = cgetg(bco+1,t_MAT); for (j=1; j<=bco; j++) gel(u,j) = Fl_get_col(a,gel(b,j), aco,p); return u; } static GEN Flm_gauss_from_CUP(GEN b, GEN R, GEN C, GEN U, GEN P, ulong p, ulong *detp) { GEN Y = Flm_rsolve_lower_unit(rowpermute(C, R), rowpermute(b, R), p); GEN X = rowpermute(Flm_rsolve_upper(U, Y, p), perm_inv(P)); if (detp) { ulong d = perm_sign(P) == 1? 1: p-1; long i, r = lg(R); for (i = 1; i < r; i++) d = Fl_mul(d, ucoeff(U, i, i), p); *detp = d; } return X; } static GEN Flm_gauss_CUP(GEN a, GEN b, ulong *detp, ulong p) { GEN R, C, U, P; long n = lg(a) - 1, r; if (nbrows(a) < n || (r = Flm_CUP(a, &R, &C, &U, &P, p)) < n) return NULL; return Flm_gauss_from_CUP(b, R, C, U, P, p, detp); } GEN Flm_gauss(GEN a, GEN b, ulong p) { pari_sp av = avma; GEN x; if (lg(a) - 1 >= Flm_CUP_LIMIT) x = Flm_gauss_CUP(a, b, NULL, p); else { a = RgM_shallowcopy(a); b = RgM_shallowcopy(b); x = Flm_gauss_sp(a, b, NULL, p); } if (!x) { avma = av; return NULL; } return gerepileupto(av, x); } static GEN Flm_inv_i(GEN a, ulong *detp, ulong p, long inplace) { pari_sp av = avma; long n = lg(a) - 1; GEN b, x; if (n == 0) return cgetg(1, t_MAT); b = matid_Flm(nbrows(a)); if (n >= Flm_CUP_LIMIT) x = Flm_gauss_CUP(a, b, detp, p); else { if (!inplace) a = RgM_shallowcopy(a); x = Flm_gauss_sp(a, b, detp, p); } if (!x) { avma = av; return NULL; } return gerepileupto(av, x); } static GEN Flm_inv_sp(GEN a, ulong *detp, ulong p) { return Flm_inv_i(a, detp, p, 1); } GEN Flm_inv(GEN a, ulong p) { return Flm_inv_i(a, NULL, p, 0); } GEN Flm_Flc_gauss(GEN a, GEN b, ulong p) { pari_sp av = avma; GEN z = Flm_gauss(a, mkmat(b), p); if (!z) { avma = av; return NULL; } if (lg(z) == 1) { avma = av; return cgetg(1,t_VECSMALL); } return gerepileuptoleaf(av, gel(z,1)); } GEN Flm_adjoint(GEN A, ulong p) { pari_sp av = avma; GEN R, C, U, P, C1, U1, v, c, d; long r, i, q, n = lg(A)-1, m; ulong D; if (n == 0) return cgetg(1, t_MAT); r = Flm_CUP(A, &R, &C, &U, &P, p); m = nbrows(A); if (r == n) { GEN X = Flm_gauss_from_CUP(matid_Flm(m), R, C, U, P, p, &D); return gerepileupto(av, Flm_Fl_mul(X, D, p)); } if (r < n-1) return zero_Flm(n, m); for (q = n, i = 1; i < n; i++) if (R[i] != i) { q = i; break; } C1 = matslice(C, 1, q-1, 1, q-1); c = vecslice(Flm_row(C, q), 1, q-1); c = Flm_lsolve_lower_unit(C1, Flm_transpose(mkmat(c)), p); d = cgetg(m+1, t_VECSMALL); for (i=1; i1; b an FpM or NULL (replace by identity) */ static GEN FpM_gauss_i(GEN a, GEN b, GEN p, ulong *pp) { long n = nbrows(a); a = FpM_init(a,p,pp); switch(*pp) { case 0: if (!b) b = matid(n); return FpM_gauss_gen(a,b,p); case 2: if (b) b = ZM_to_F2m(b); else b = matid_F2m(n); return F2m_gauss_sp(a,b); default: if (b) b = ZM_to_Flm(b, *pp); else b = matid_Flm(n); return Flm_gauss_sp(a,b, NULL, *pp); } } GEN FpM_gauss(GEN a, GEN b, GEN p) { pari_sp av = avma; ulong pp; GEN u; if (lg(a) == 1 || lg(b)==1) return cgetg(1, t_MAT); u = FpM_gauss_i(a, b, p, &pp); if (!u) { avma = av; return NULL; } switch(pp) { case 0: return gerepilecopy(av, u); case 2: u = F2m_to_ZM(u); break; default: u = Flm_to_ZM(u); break; } return gerepileupto(av, u); } GEN FpM_inv(GEN a, GEN p) { pari_sp av = avma; ulong pp; GEN u; if (lg(a) == 1) return cgetg(1, t_MAT); u = FpM_gauss_i(a, NULL, p, &pp); if (!u) { avma = av; return NULL; } switch(pp) { case 0: return gerepilecopy(av, u); case 2: u = F2m_to_ZM(u); break; default: u = Flm_to_ZM(u); break; } return gerepileupto(av, u); } GEN FpM_FpC_gauss(GEN a, GEN b, GEN p) { pari_sp av = avma; ulong pp; GEN u; if (lg(a) == 1) return cgetg(1, t_COL); u = FpM_gauss_i(a, mkmat(b), p, &pp); if (!u) { avma = av; return NULL; } switch(pp) { case 0: return gerepilecopy(av, gel(u,1)); case 2: u = F2c_to_ZC(gel(u,1)); break; default: u = Flc_to_ZC(gel(u,1)); break; } return gerepileupto(av, u); } static GEN FlxqM_gauss_gen(GEN a, GEN b, GEN T, ulong p) { void *E; const struct bb_field *S = get_Flxq_field(&E, T, p); return gen_Gauss(a, b, E, S); } static GEN FlxqM_gauss_CUP(GEN a, GEN b, GEN T, ulong p) { GEN R, C, U, P, Y; long n = lg(a) - 1, r; if (nbrows(a) < n || (r = FlxqM_CUP(a, &R, &C, &U, &P, T, p)) < n) return NULL; Y = FlxqM_rsolve_lower_unit(rowpermute(C, R), rowpermute(b, R), T, p); return rowpermute(FlxqM_rsolve_upper(U, Y, T, p), perm_inv(P)); } static GEN FlxqM_gauss_i(GEN a, GEN b, GEN T, ulong p) { if (lg(a) - 1 >= FlxqM_CUP_LIMIT) return FlxqM_gauss_CUP(a, b, T, p); return FlxqM_gauss_gen(a, b, T, p); } GEN FlxqM_gauss(GEN a, GEN b, GEN T, ulong p) { pari_sp av = avma; long n = lg(a)-1; GEN u; if (!n || lg(b)==1) { avma = av; return cgetg(1, t_MAT); } u = FlxqM_gauss_i(a, b, T, p); if (!u) { avma = av; return NULL; } return gerepilecopy(av, u); } GEN FlxqM_inv(GEN a, GEN T, ulong p) { pari_sp av = avma; GEN u; if (lg(a) == 1) { avma = av; return cgetg(1, t_MAT); } u = FlxqM_gauss_i(a, matid_FlxqM(nbrows(a),T,p), T,p); if (!u) { avma = av; return NULL; } return gerepilecopy(av, u); } GEN FlxqM_FlxqC_gauss(GEN a, GEN b, GEN T, ulong p) { pari_sp av = avma; GEN u; if (lg(a) == 1) return cgetg(1, t_COL); u = FlxqM_gauss_i(a, mkmat(b), T, p); if (!u) { avma = av; return NULL; } return gerepilecopy(av, gel(u,1)); } static GEN FqM_gauss_gen(GEN a, GEN b, GEN T, GEN p) { void *E; const struct bb_field *S = get_Fq_field(&E,T,p); return gen_Gauss(a,b,E,S); } GEN FqM_gauss(GEN a, GEN b, GEN T, GEN p) { pari_sp av = avma; GEN u; long n; if (!T) return FpM_gauss(a,b,p); n = lg(a)-1; if (!n || lg(b)==1) return cgetg(1, t_MAT); u = FqM_gauss_gen(a,b,T,p); if (!u) { avma = av; return NULL; } return gerepilecopy(av, u); } GEN FqM_inv(GEN a, GEN T, GEN p) { pari_sp av = avma; GEN u; if (!T) return FpM_inv(a,p); if (lg(a) == 1) return cgetg(1, t_MAT); u = FqM_gauss_gen(a,matid(nbrows(a)),T,p); if (!u) { avma = av; return NULL; } return gerepilecopy(av, u); } GEN FqM_FqC_gauss(GEN a, GEN b, GEN T, GEN p) { pari_sp av = avma; GEN u; if (!T) return FpM_FpC_gauss(a,b,p); if (lg(a) == 1) return cgetg(1, t_COL); u = FqM_gauss_gen(a,mkmat(b),T,p); if (!u) { avma = av; return NULL; } return gerepilecopy(av, gel(u,1)); } static GEN ZlM_gauss_ratlift(GEN a, GEN b, ulong p, long e, GEN C) { pari_sp av = avma, av2; GEN bb, xi, xb, pi, P, B, r; long i, k = 2; if (!C) { C = Flm_inv(ZM_to_Flm(a, p), p); if (!C) pari_err_INV("ZlM_gauss", a); } pi = P = utoipos(p); av2 = avma; xi = Flm_mul(C, ZM_to_Flm(b, p), p); xb = Flm_to_ZM(xi); bb = b; for (i = 2; i <= e; i++) { bb = ZM_Z_divexact(ZM_sub(bb, ZM_nm_mul(a, xi)), P); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZlM_gauss. i=%ld/%ld",i,e); gerepileall(av2,3, &pi,&bb,&xb); } xi = Flm_mul(C, ZM_to_Flm(bb, p), p); xb = ZM_add(xb, nm_Z_mul(xi, pi)); pi = muliu(pi, p); /* = p^(i-1) */ if (i==k && i < e) { k *= 2; B = sqrti(shifti(pi,-1)); r = FpM_ratlift(xb, pi, B, B, NULL); if (r) { GEN dr, nr = Q_remove_denom(r,&dr); if (ZM_equal(ZM_mul(a,nr), dr? ZM_Z_mul(b,dr): b)) { if (DEBUGLEVEL>=4) err_printf("ZlM_gauss: early solution: %ld/%ld\n",i,e); return gerepilecopy(av, r); } } } } B = sqrti(shifti(pi,-1)); return gerepileupto(av, FpM_ratlift(xb, pi, B, B, NULL)); } /* Dixon p-adic lifting algorithm. * Numer. Math. 40, 137-141 (1982), DOI: 10.1007/BF01459082 */ GEN ZM_gauss(GEN a, GEN b0) { pari_sp av = avma, av2; int iscol; long n, ncol, i, m, elim; ulong p; GEN C, delta, nb, nmin, res, b = b0; forprime_t S; if (!init_gauss(a, &b, &n, &ncol, &iscol)) return cgetg(1, iscol?t_COL:t_MAT); nb = gen_0; ncol = lg(b); for (i = 1; i < ncol; i++) { GEN ni = gnorml2(gel(b, i)); if (cmpii(nb, ni) < 0) nb = ni; } if (!signe(nb)) { avma = av; return gcopy(b0); } delta = gen_1; nmin = nb; for (i = 1; i <= n; i++) { GEN ni = gnorml2(gel(a, i)); if (cmpii(ni, nmin) < 0) { delta = mulii(delta, nmin); nmin = ni; } else delta = mulii(delta, ni); } if (!signe(nmin)) return NULL; elim = expi(delta)+1; av2 = avma; init_modular_big(&S); for(;;) { p = u_forprime_next(&S); C = Flm_inv_sp(ZM_to_Flm(a, p), NULL, p); if (C) break; elim -= expu(p); if (elim < 0) return NULL; avma = av2; } /* N.B. Our delta/lambda are SQUARES of those in the paper * log(delta lambda) / log p, where lambda is 3+sqrt(5) / 2, * whose log is < 1, hence + 1 (to cater for rounding errors) */ m = (long)ceil((rtodbl(logr_abs(itor(delta,LOWDEFAULTPREC))) + 1) / log((double)p)); res = ZlM_gauss_ratlift(a, b, p, m, C); if (iscol) return gerepilecopy(av, gel(res, 1)); return gerepileupto(av, res); } /* same as above, M rational */ GEN QM_gauss(GEN M, GEN B) { pari_sp av = avma; GEN K, MB; MB = Q_primitive_part(mkvec2(M,B), NULL); K = ZM_gauss(gel(MB,1), gel(MB,2)); return gerepileupto(av, K); } static GEN ZM_inv_slice(GEN A, GEN P, GEN *mod) { pari_sp av = avma; long i, n = lg(P)-1; GEN H, T; if (n == 1) { ulong p = uel(P,1); GEN Hp, a = ZM_to_Flm(A, p); Hp = Flm_adjoint(a, p); Hp = gerepileupto(av, Flm_to_ZM(Hp)); *mod = utoi(p); return Hp; } T = ZV_producttree(P); A = ZM_nv_mod_tree(A, P, T); H = cgetg(n+1, t_VEC); for(i=1; i <= n; i++) gel(H,i) = Flm_adjoint(gel(A, i), uel(P,i)); H = nmV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P,T)); *mod = gmael(T, lg(T)-1, 1); gerepileall(av, 2, &H, mod); return H; } static GEN RgM_true_Hadamard(GEN a) { pari_sp av = avma; long n = lg(a)-1, i; GEN B; if (n == 0) return gen_1; a = RgM_gtofp(a, LOWDEFAULTPREC); B = gnorml2(gel(a,1)); for (i = 2; i <= n; i++) B = gmul(B, gnorml2(gel(a,i))); return gerepileuptoint(av, ceil_safe(sqrtr(B))); } GEN ZM_inv_worker(GEN P, GEN A) { GEN V = cgetg(3, t_VEC); gel(V,1) = ZM_inv_slice(A, P, &gel(V,2)); return V; } static GEN ZM_inv0(GEN A, GEN *pden) { if (pden) *pden = gen_1; (void)A; return cgetg(1, t_MAT); } static GEN ZM_inv1(GEN A, GEN *pden) { GEN a = gcoeff(A,1,1); long s = signe(a); if (!s) return NULL; if (pden) *pden = absi(a); retmkmat(mkcol(s == 1? gen_1: gen_m1)); } static GEN ZM_inv2(GEN A, GEN *pden) { GEN a, b, c, d, D, cA; long s; A = Q_primitive_part(A, &cA); a = gcoeff(A,1,1); b = gcoeff(A,1,2); c = gcoeff(A,2,1); d = gcoeff(A,2,2); D = subii(mulii(a,d), mulii(b,c)); /* left on stack */ s = signe(D); if (!s) return NULL; if (s < 0) D = negi(D); if (pden) *pden = mul_denom(D, cA); if (s > 0) retmkmat2(mkcol2(icopy(d), negi(c)), mkcol2(negi(b), icopy(a))); else retmkmat2(mkcol2(negi(d), icopy(c)), mkcol2(icopy(b), negi(a))); } /* to be used when denom(M^(-1)) << det(M) and a sharp multiple is * not available. Return H primitive such that M*H = den*Id */ GEN ZM_inv_ratlift(GEN M, GEN *pden) { pari_sp av2, av = avma; GEN Hp, q, H; ulong p; long m = lg(M)-1; forprime_t S; pari_timer ti; if (m == 0) return ZM_inv0(M,pden); if (m == 1 && nbrows(M)==1) return ZM_inv1(M,pden); if (m == 2 && nbrows(M)==2) return ZM_inv2(M,pden); if (DEBUGLEVEL>5) timer_start(&ti); init_modular_big(&S); av2 = avma; H = NULL; while ((p = u_forprime_next(&S))) { GEN Mp, B, Hr; Mp = ZM_to_Flm(M,p); Hp = Flm_inv_sp(Mp, NULL, p); if (!Hp) continue; if (!H) { H = ZM_init_CRT(Hp, p); q = utoipos(p); } else ZM_incremental_CRT(&H, Hp, &q, p); B = sqrti(shifti(q,-1)); Hr = FpM_ratlift(H,q,B,B,NULL); if (DEBUGLEVEL>5) timer_printf(&ti,"ZM_inv mod %lu (ratlift=%ld)", p,!!Hr); if (Hr) {/* DONE ? */ GEN Hl = Q_remove_denom(Hr, pden); if (ZM_isscalar(ZM_mul(Hl, M), *pden)) { H = Hl; break; } } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_inv_ratlift"); gerepileall(av2, 2, &H, &q); } } if (!*pden) *pden = gen_1; gerepileall(av, 2, &H, pden); return H; } static GEN ZM_adj_ratlift(GEN A, GEN H, GEN mod) { GEN B; GEN D = ZMrow_ZC_mul(H, gel(A,1), 1); GEN g = gcdii(D, mod); if (!equali1(g)) { mod = diviiexact(mod, g); H = FpM_red(H, mod); } D = Fp_inv(Fp_red(D, mod), mod); H = FpM_Fp_mul(H, D, mod); B = sqrti(shifti(mod,-1)); return FpM_ratlift(H, mod, B, B, NULL); } GEN ZM_inv(GEN A, GEN *pden) { pari_sp av = avma; long m = lg(A)-1, n, k1 = 1, k2; GEN H = NULL, D, H1 = NULL, mod1 = NULL, worker; ulong bnd, mask, p = 0; pari_timer ti; if (m == 0) return ZM_inv0(A,pden); if (pden) *pden = gen_1; if (nbrows(A) < m) return NULL; if (m == 1 && nbrows(A)==1) return ZM_inv1(A,pden); if (m == 2 && nbrows(A)==2) return ZM_inv2(A,pden); if (DEBUGLEVEL>=5) timer_start(&ti); bnd = expi(RgM_true_Hadamard(A)); worker = strtoclosure("_ZM_inv_worker", 1, A); gen_inccrt("ZM_inv_r", worker, NULL, k1, m, &p, &H1, &mod1, nmV_chinese_center, FpM_center); n = (bnd+1)/expu(p)+1; if (DEBUGLEVEL>=5) timer_printf(&ti,"inv (%ld/%ld primes)", k1, n); mask = quadratic_prec_mask(n); for (k2 = 0;;) { GEN Hr; if (k2 > 0) { gen_inccrt("ZM_inv_r", worker, NULL, k2, m, &p, &H1, &mod1,nmV_chinese_center,FpM_center); k1 += k2; if (DEBUGLEVEL>=5) timer_printf(&ti,"CRT (%ld/%ld primes)", k1, n); } if (mask == 1) break; k2 = (mask&1UL) ? k1-1: k1; mask >>= 1; Hr = ZM_adj_ratlift(A, H1, mod1); if (DEBUGLEVEL>=5) timer_printf(&ti,"ratlift (%ld/%ld primes)", k1, n); if (Hr) {/* DONE ? */ GEN den; GEN Hl = Q_remove_denom(Hr, &den); GEN R = ZM_mul(Hl, A); if (DEBUGLEVEL>=5) timer_printf(&ti,"mult (%ld/%ld primes)", k1, n); den = den ? den: gen_1; if (den) { if (ZM_isscalar(R, den)) { H = Hl; if (pden) *pden = den; break; } } else if (ZM_isidentity(R)) { H=Hl; break; } } } if (!H) { GEN d; H = H1; D = ZMrow_ZC_mul(H, gel(A,1), 1); if (signe(D)==0) pari_err_INV("ZM_inv", A); d = gcdii(Q_content_safe(H), D); if (signe(D) < 0) d = negi(d); if (!equali1(d)) { H = ZM_Z_divexact(H, d); D = diviiexact(D, d); } if (pden) *pden = D; } gerepileall(av, pden? 2: 1, &H, pden); return H; } /* same as above, M rational */ GEN QM_inv(GEN M) { pari_sp av = avma; GEN den, cM, K; M = Q_primitive_part(M, &cM); K = ZM_inv(M, &den); if (!K) { avma = av; return NULL; } cM = inv_content(mul_content(cM, den)); if (cM) K = RgM_Rg_div(K, cM); return gerepileupto(av, K); } static GEN ZM_ker_i(GEN M, long fl) { pari_sp av2, av = avma; GEN q, H, D; forprime_t S; av2 = avma; H = NULL; D = NULL; if (lg(M)==1) return cgetg(1, t_MAT); init_modular_big(&S); for(;;) { GEN Kp, Hp, Dp, Mp, Hr, B; ulong p = u_forprime_next(&S); Mp = ZM_to_Flm(M, p); Kp = Flm_ker_sp(Mp, p, 2); Hp = gel(Kp,1); Dp = gel(Kp,2); if (H && (lg(Hp)>lg(H) || (lg(Hp)==lg(H) && vecsmall_lexcmp(Dp,D)>0))) continue; if (!H || (lg(Hp)5) err_printf("ZM_ker mod %lu (ratlift=%ld)\n", p,!!Hr); if (Hr) {/* DONE ? */ GEN MH = QM_mul(M, Hr); if (gequal0(MH)) { H = fl ? vec_Q_primpart(Hr): Hr; break; } } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_ker"); gerepileall(av2, 3, &H, &D, &q); } } return gerepilecopy(av, H); } GEN ZM_ker(GEN M) { return ZM_ker_i(M, 1); } GEN QM_ker(GEN M) { pari_sp av = avma; long l = lg(M)-1; if (l==0) return cgetg(1, t_MAT); if (lgcols(M)==1) return matid(l); M = shallowtrans(vec_Q_primpart(shallowtrans(M))); return gerepileupto(av, ZM_ker_i(M, 0)); } /* x a ZM. Return a multiple of the determinant of the lattice generated by * the columns of x. From Algorithm 2.2.6 in GTM138 */ GEN detint(GEN A) { if (typ(A) != t_MAT) pari_err_TYPE("detint",A); RgM_check_ZM(A, "detint"); return ZM_detmult(A); } GEN ZM_detmult(GEN A) { pari_sp av1, av = avma; GEN B, c, v, piv; long rg, i, j, k, m, n = lg(A) - 1; if (!n) return gen_1; m = nbrows(A); if (n < m) return gen_0; c = zero_zv(m); av1 = avma; B = zeromatcopy(m,m); v = cgetg(m+1, t_COL); piv = gen_1; rg = 0; for (k=1; k<=n; k++) { GEN pivprec = piv; long t = 0; for (i=1; i<=m; i++) { pari_sp av2 = avma; GEN vi; if (c[i]) continue; vi = mulii(piv, gcoeff(A,i,k)); for (j=1; j<=m; j++) if (c[j]) vi = addii(vi, mulii(gcoeff(B,j,i),gcoeff(A,j,k))); if (!t && signe(vi)) t = i; gel(v,i) = gerepileuptoint(av2, vi); } if (!t) continue; /* at this point c[t] = 0 */ if (++rg >= m) { /* full rank; mostly done */ GEN det = gel(v,t); /* last on stack */ if (++k > n) det = absi(det); else { /* improve further; at this point c[i] is set for all i != t */ gcoeff(B,t,t) = piv; v = centermod(gel(B,t), det); for ( ; k<=n; k++) det = gcdii(det, ZV_dotproduct(v, gel(A,k))); } return gerepileuptoint(av, det); } piv = gel(v,t); for (i=1; i<=m; i++) { GEN mvi; if (c[i] || i == t) continue; gcoeff(B,t,i) = mvi = negi(gel(v,i)); for (j=1; j<=m; j++) if (c[j]) /* implies j != t */ { pari_sp av2 = avma; GEN z = addii(mulii(gcoeff(B,j,i), piv), mulii(gcoeff(B,j,t), mvi)); if (rg > 1) z = diviiexact(z, pivprec); gcoeff(B,j,i) = gerepileuptoint(av2, z); } } c[t] = k; if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"detint. k=%ld",k); gerepileall(av1, 2, &piv,&B); v = zerovec(m); } } avma = av; return gen_0; } /* Reduce x modulo (invertible) y */ GEN closemodinvertible(GEN x, GEN y) { return gmul(y, ground(RgM_solve(y,x))); } GEN reducemodinvertible(GEN x, GEN y) { return gsub(x, closemodinvertible(x,y)); } GEN reducemodlll(GEN x,GEN y) { return reducemodinvertible(x, ZM_lll(y, 0.75, LLL_INPLACE)); } /*******************************************************************/ /* */ /* KERNEL of an m x n matrix */ /* return n - rk(x) linearly independent vectors */ /* */ /*******************************************************************/ static GEN RgM_deplin_i(GEN x0) { pari_sp av = avma, av2; long i, j, k, nl, nc = lg(x0)-1; GEN D, x, y, c, l, d, ck; if (!nc) { avma=av; return NULL; } nl = nbrows(x0); c = zero_zv(nl); l = cgetg(nc+1, t_VECSMALL); /* not initialized */ av2 = avma; x = RgM_shallowcopy(x0); d = const_vec(nl, gen_1); /* pivot list */ ck = NULL; /* gcc -Wall */ for (k=1; k<=nc; k++) { ck = gel(x,k); for (j=1; j nl) break; if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"deplin k = %ld/%ld",k,nc); gerepileall(av2, 2, &x, &d); ck = gel(x,k); } gel(d,k) = gel(ck,i); c[i] = k; l[k] = i; /* pivot d[k] in x[i,k] */ } if (k > nc) { avma = av; return NULL; } if (k == 1) { avma = av; return scalarcol_shallow(gen_1,nc); } y = cgetg(nc+1,t_COL); gel(y,1) = gcopy(gel(ck, l[1])); for (D=gel(d,1),j=2; j>1); x = zc_to_ZC(x); break; } return gerepileupto(av, x); } /* FIXME: implement direct modular ZM_deplin ? */ static GEN QM_deplin(GEN M) { pari_sp av = avma; long l = lg(M)-1; GEN k; if (l==0) return NULL; if (lgcols(M)==1) return col_ei(l, 1); M = shallowtrans(vec_Q_primpart(shallowtrans(M))); k = ZM_ker_i(M, 1); if (lg(k)== 1) { avma = av; return NULL; } return gerepilecopy(av, gel(k,1)); } static GEN RgM_deplin_FqM(GEN x, GEN pol, GEN p) { pari_sp av = avma; GEN b, T = RgX_to_FpX(pol, p); if (signe(T) == 0) pari_err_OP("deplin",x,pol); b = FqM_deplin(RgM_to_FqM(x, T, p), T, p); return gerepileupto(av, b); } #define code(t1,t2) ((t1 << 6) | t2) static GEN RgM_deplin_fast(GEN x) { GEN p, pol; long pa; long t = RgM_type(x, &p,&pol,&pa); switch(t) { case t_INT: /* fall through */ case t_FRAC: return QM_deplin(x); case t_FFELT: return FFM_deplin(x, pol); case t_INTMOD: return RgM_deplin_FpM(x, p); case code(t_POLMOD, t_INTMOD): return RgM_deplin_FqM(x, pol, p); default: return gen_0; } } #undef code static GEN RgM_deplin(GEN x) { GEN z = RgM_deplin_fast(x); if (z!= gen_0) return z; return RgM_deplin_i(x); } GEN deplin(GEN x) { switch(typ(x)) { case t_MAT: { GEN z = RgM_deplin(x); if (z) return z; return cgetg(1, t_COL); } case t_VEC: return RgV_deplin(x); default: pari_err_TYPE("deplin",x); } return NULL;/*LCOV_EXCL_LINE*/ } /*******************************************************************/ /* */ /* GAUSS REDUCTION OF MATRICES (m lines x n cols) */ /* (kernel, image, complementary image, rank) */ /* */ /*******************************************************************/ /* return the transform of x under a standard Gauss pivot. * x0 is a reference point when guessing whether x[i,j] ~ 0 * (iff x[i,j] << x0[i,j]) * Set r = dim ker(x). d[k] contains the index of the first non-zero pivot * in column k */ static GEN gauss_pivot_ker(GEN x, GEN x0, GEN *dd, long *rr) { GEN c, d, p, data; pari_sp av; long i, j, k, r, t, n, m; pivot_fun pivot; n=lg(x)-1; if (!n) { *dd=NULL; *rr=0; return cgetg(1,t_MAT); } m=nbrows(x); r=0; pivot = get_pivot_fun(x, x0, &data); x = RgM_shallowcopy(x); c = zero_zv(m); d = cgetg(n+1,t_VECSMALL); av=avma; for (k=1; k<=n; k++) { j = pivot(x, data, k, c); if (j > m) { r++; d[k]=0; for(j=1; j m) { r++; d[k] = 0; } else { c[j] = k; d[k] = j; p = gdiv(gen_m1, gcoeff(x,j,k)); for (i=k+1; i<=n; i++) gcoeff(x,j,i) = gmul(p,gcoeff(x,j,i)); for (t=1; t<=m; t++) if (!c[t]) /* no pivot on that line yet */ { p = gcoeff(x,t,k); gcoeff(x,t,k) = gen_0; for (i=k+1; i<=n; i++) gcoeff(x,t,i) = gadd(gcoeff(x,t,i), gmul(p, gcoeff(x,j,i))); if (gc_needed(av,1)) gerepile_gauss(x,k,t,av,j,c); } for (i=k; i<=n; i++) gcoeff(x,j,i) = gen_0; /* dummy */ } } *rr = r; avma = (pari_sp)d; return d; } static long ZM_count_0_cols(GEN M) { long i, l = lg(M), n = 0; for (i = 1; i < l; i++) if (ZV_equal0(gel(M,i))) n++; return n; } static void indexrank_all(long m, long n, long r, GEN d, GEN *prow, GEN *pcol); /* As RgM_pivots, integer entries. Set *rr = dim Ker M0 */ GEN ZM_pivots(GEN M0, long *rr) { GEN d, dbest = NULL; long m, n, i, imax, rmin, rbest, zc; int beenthere = 0; pari_sp av, av0 = avma; forprime_t S; rbest = n = lg(M0)-1; if (n == 0) { *rr = 0; return NULL; } zc = ZM_count_0_cols(M0); if (n == zc) { *rr = zc; return zero_zv(n); } m = nbrows(M0); rmin = maxss(zc, n-m); init_modular_small(&S); imax = (n < (1<<4))? 1: (n>>3); /* heuristic */ for(;;) { GEN row, col, M, KM, IM, RHS, X, cX; long rk; for (av = avma, i = 0;; avma = av, i++) { ulong p = u_forprime_next(&S); long rp; if (!p) pari_err_OVERFLOW("ZM_pivots [ran out of primes]"); d = Flm_pivots(ZM_to_Flm(M0, p), p, &rp, 1); if (rp == rmin) { rbest = rp; goto END; } /* maximal rank, return */ if (rp < rbest) { /* save best r so far */ rbest = rp; if (dbest) gunclone(dbest); dbest = gclone(d); if (beenthere) break; } if (!beenthere && i >= imax) break; } beenthere = 1; /* Dubious case: there is (probably) a non trivial kernel */ indexrank_all(m,n, rbest, dbest, &row, &col); M = rowpermute(vecpermute(M0, col), row); rk = n - rbest; /* (probable) dimension of image */ IM = vecslice(M,1,rk); KM = vecslice(M,rk+1, n); M = rowslice(IM, 1,rk); /* square maximal rank */ X = ZM_gauss(M, rowslice(KM, 1,rk)); X = Q_remove_denom(X, &cX); RHS = rowslice(KM,rk+1,m); if (cX) RHS = ZM_Z_mul(RHS, cX); if (ZM_equal(ZM_mul(rowslice(IM,rk+1,m), X), RHS)) { d = vecsmall_copy(dbest); goto END; } avma = av; } END: *rr = rbest; if (dbest) gunclone(dbest); return gerepileuptoleaf(av0, d); } /* set *pr = dim Ker x */ static GEN gauss_pivot(GEN x, long *pr) { GEN data; pivot_fun pivot = get_pivot_fun(x, x, &data); return RgM_pivots(x, data, pr, pivot); } /* compute ker(x), x0 is a reference point when guessing whether x[i,j] ~ 0 * (iff x[i,j] << x0[i,j]) */ static GEN ker_aux(GEN x, GEN x0) { pari_sp av = avma; GEN d,y; long i,j,k,r,n; x = gauss_pivot_ker(x,x0,&d,&r); if (!r) { avma=av; return cgetg(1,t_MAT); } n = lg(x)-1; y=cgetg(r+1,t_MAT); for (j=k=1; j<=r; j++,k++) { GEN p = cgetg(n+1,t_COL); gel(y,j) = p; while (d[k]) k++; for (i=1; i= Flm_CUP_LIMIT && nbrows(B) >= Flm_CUP_LIMIT) return Flm_invimage_CUP(A, B, p); x = Flm_ker_sp(shallowconcat(Flm_neg(A,p), B), p, 0); /* AX = BY, Y in strict upper echelon form with pivots = 1. * We must find T such that Y T = Id_nB then X T = Z. This exists iff * Y has at least nB columns and full rank */ nY = lg(x)-1; if (nY < nB) return NULL; Y = rowslice(x, nA+1, nA+nB); /* nB rows */ d = cgetg(nB+1, t_VECSMALL); for (i = nB, j = nY; i >= 1; i--, j--) { for (; j>=1; j--) if (coeff(Y,i,j)) { d[i] = j; break; } if (!j) return NULL; } /* reduce to the case Y square, upper triangular with 1s on diagonal */ Y = vecpermute(Y, d); x = vecpermute(x, d); X = rowslice(x, 1, nA); return Flm_mul(X, Flm_inv_upper_1(Y,p), p); } static GEN F2m_invimage_i(GEN A, GEN B) { GEN d, x, X, Y; long i, j, nY, nA = lg(A)-1, nB = lg(B)-1; x = F2m_ker_sp(shallowconcat(A, B), 0); /* AX = BY, Y in strict upper echelon form with pivots = 1. * We must find T such that Y T = Id_nB then X T = Z. This exists iff * Y has at least nB columns and full rank */ nY = lg(x)-1; if (nY < nB) return NULL; /* implicitly: Y = rowslice(x, nA+1, nA+nB), nB rows */ d = cgetg(nB+1, t_VECSMALL); for (i = nB, j = nY; i >= 1; i--, j--) { for (; j>=1; j--) if (F2m_coeff(x,nA+i,j)) { d[i] = j; break; } /* Y[i,j] */ if (!j) return NULL; } x = vecpermute(x, d); X = F2m_rowslice(x, 1, nA); Y = F2m_rowslice(x, nA+1, nA+nB); return F2m_mul(X, F2m_inv_upper_1(Y)); } GEN Flm_invimage(GEN A, GEN B, ulong p) { pari_sp av = avma; GEN X = Flm_invimage_i(A,B,p); if (!X) { avma = av; return NULL; } return gerepileupto(av, X); } GEN F2m_invimage(GEN A, GEN B) { pari_sp av = avma; GEN X = F2m_invimage_i(A,B); if (!X) { avma = av; return NULL; } return gerepileupto(av, X); } static GEN FpM_invimage_i(GEN A, GEN B, GEN p) { GEN d, x, X, Y; long i, j, nY, nA = lg(A)-1, nB = lg(B)-1; if (lgefint(p) == 3) { ulong pp = p[2]; A = ZM_to_Flm(A, pp); B = ZM_to_Flm(B, pp); x = Flm_invimage_i(A, B, pp); return x? Flm_to_ZM(x): NULL; } x = FpM_ker(shallowconcat(ZM_neg(A), B), p); /* AX = BY, Y in strict upper echelon form with pivots = 1. * We must find T such that Y T = Id_nB then X T = Z. This exists iff * Y has at least nB columns and full rank */ nY = lg(x)-1; if (nY < nB) return NULL; Y = rowslice(x, nA+1, nA+nB); /* nB rows */ d = cgetg(nB+1, t_VECSMALL); for (i = nB, j = nY; i >= 1; i--, j--) { for (; j>=1; j--) if (signe(gcoeff(Y,i,j))) { d[i] = j; break; } if (!j) return NULL; } /* reduce to the case Y square, upper triangular with 1s on diagonal */ Y = vecpermute(Y, d); x = vecpermute(x, d); X = rowslice(x, 1, nA); return FpM_mul(X, FpM_inv_upper_1(Y,p), p); } GEN FpM_invimage(GEN A, GEN B, GEN p) { pari_sp av = avma; GEN X = FpM_invimage_i(A,B,p); if (!X) { avma = av; return NULL; } return gerepileupto(av, X); } static GEN RgM_invimage_FpM(GEN A, GEN B, GEN p) { pari_sp av = avma; ulong pp; GEN x; A = RgM_Fp_init(A,p,&pp); switch(pp) { case 0: B = RgM_to_FpM(B,p); x = FpM_invimage_i(A, B, p); return x ? gerepileupto(av, FpM_to_mod(x, p)): x; case 2: B = RgM_to_F2m(B); x = F2m_invimage_i(A, B); return x ? gerepileupto(av, F2m_to_mod(x)): x; default: B = RgM_to_Flm(B,pp); x = Flm_invimage_i(A, B, pp); return x ? gerepileupto(av, Flm_to_mod(x, pp)): x; } } static GEN RgM_invimage_fast(GEN x, GEN y) { GEN p, pol; long pa; long t = RgM_type2(x, y, &p,&pol,&pa); switch(t) { case t_INTMOD: return RgM_invimage_FpM(x, y, p); case t_FFELT: return FFM_invimage(x, y, pol); default: return gen_0; } } /* find Z such that A Z = B. Return NULL if no solution */ GEN RgM_invimage(GEN A, GEN B) { pari_sp av = avma; GEN d, x, X, Y; long i, j, nY, nA = lg(A)-1, nB = lg(B)-1; X = RgM_invimage_fast(A, B); if (!X) {avma = av; return NULL; } if (X != gen_0) return X; x = ker(shallowconcat(RgM_neg(A), B)); /* AX = BY, Y in strict upper echelon form with pivots = 1. * We must find T such that Y T = Id_nB then X T = Z. This exists iff * Y has at least nB columns and full rank */ nY = lg(x)-1; if (nY < nB) { avma = av; return NULL; } Y = rowslice(x, nA+1, nA+nB); /* nB rows */ d = cgetg(nB+1, t_VECSMALL); for (i = nB, j = nY; i >= 1; i--, j--) { for (; j>=1; j--) if (!gequal0(gcoeff(Y,i,j))) { d[i] = j; break; } if (!j) { avma = av; return NULL; } } /* reduce to the case Y square, upper triangular with 1s on diagonal */ Y = vecpermute(Y, d); x = vecpermute(x, d); X = rowslice(x, 1, nA); return gerepileupto(av, RgM_mul(X, RgM_inv_upper(Y))); } /* r = dim Ker x, n = nbrows(x) */ static GEN get_suppl(GEN x, GEN d, long n, long r, GEN(*ei)(long,long)) { pari_sp av; GEN y, c; long j, k, rx = lg(x)-1; /* != 0 due to init_suppl() */ if (rx == n && r == 0) return gcopy(x); y = cgetg(n+1, t_MAT); av = avma; c = zero_zv(n); /* c = lines containing pivots (could get it from gauss_pivot, but cheap) * In theory r = 0 and d[j] > 0 for all j, but why take chances? */ for (k = j = 1; j<=rx; j++) if (d[j]) { c[ d[j] ] = 1; gel(y,k++) = gel(x,j); } for (j=1; j<=n; j++) if (!c[j]) gel(y,k++) = (GEN)j; /* HACK */ avma = av; rx -= r; for (j=1; j<=rx; j++) gel(y,j) = gcopy(gel(y,j)); for ( ; j<=n; j++) gel(y,j) = ei(n, y[j]); return y; } static void init_suppl(GEN x) { if (lg(x) == 1) pari_err_IMPL("suppl [empty matrix]"); /* HACK: avoid overwriting d from gauss_pivot() after avma=av */ (void)new_chunk(lgcols(x) * 2); } GEN FpM_suppl(GEN x, GEN p) { GEN d; long r; init_suppl(x); d = FpM_gauss_pivot(x,p, &r); return get_suppl(x,d,nbrows(x),r,&col_ei); } GEN Flm_suppl(GEN x, ulong p) { GEN d; long r; init_suppl(x); d = Flm_pivots(x, p, &r, 0); return get_suppl(x,d,nbrows(x),r,&vecsmall_ei); } GEN F2m_suppl(GEN x) { GEN d; long r; init_suppl(x); d = F2m_gauss_pivot(F2m_copy(x), &r); return get_suppl(x,d,mael(x,1,1),r,&F2v_ei); } static GEN RgM_suppl_FpM(GEN x, GEN p) { pari_sp av = avma; ulong pp; x = RgM_Fp_init(x, p, &pp); switch(pp) { case 0: x = FpM_to_mod(FpM_suppl(x,p), p); break; case 2: x = F2m_to_mod(F2m_suppl(x)); break; default:x = Flm_to_mod(Flm_suppl(x,pp), pp); break; } return gerepileupto(av, x); } static GEN RgM_suppl_fast(GEN x) { GEN p, pol; long pa; long t = RgM_type(x,&p,&pol,&pa); switch(t) { case t_INTMOD: return RgM_suppl_FpM(x, p); case t_FFELT: return FFM_suppl(x, pol); default: return NULL; } } /* x is an n x k matrix, rank(x) = k <= n. Return an invertible n x n matrix * whose first k columns are given by x. If rank(x) < k, undefined result. */ GEN suppl(GEN x) { pari_sp av = avma; GEN d, M; long r; if (typ(x)!=t_MAT) pari_err_TYPE("suppl",x); M = RgM_suppl_fast(x); if (M) return M; init_suppl(x); d = gauss_pivot(x,&r); avma = av; return get_suppl(x,d,nbrows(x),r,&col_ei); } /* variable number to be filled in later */ static GEN _FlxC_ei(long n, long i) { GEN x = cgetg(n + 1, t_COL); long j; for (j = 1; j <= n; j++) gel(x, j) = (j == i)? pol1_Flx(0): pol0_Flx(0); return x; } GEN F2xqM_suppl(GEN x, GEN T) { pari_sp av = avma; GEN d, y; long n = nbrows(x), r, sv = get_Flx_var(T); init_suppl(x); d = F2xqM_gauss_pivot(x, T, &r); avma = av; y = get_suppl(x, d, n, r, &_FlxC_ei); if (sv) { long i, j; for (j = r + 1; j <= n; j++) { for (i = 1; i <= n; i++) gcoeff(y, i, j)[1] = sv; } } return y; } GEN FlxqM_suppl(GEN x, GEN T, ulong p) { pari_sp av = avma; GEN d, y; long n = nbrows(x), r, sv = get_Flx_var(T); init_suppl(x); d = FlxqM_gauss_pivot(x, T, p, &r); avma = av; y = get_suppl(x, d, n, r, &_FlxC_ei); if (sv) { long i, j; for (j = r + 1; j <= n; j++) { for (i = 1; i <= n; i++) gcoeff(y, i, j)[1] = sv; } } return y; } GEN FqM_suppl(GEN x, GEN T, GEN p) { pari_sp av = avma; GEN d; long r; if (!T) return FpM_suppl(x,p); init_suppl(x); d = FqM_gauss_pivot(x,T,p,&r); avma = av; return get_suppl(x,d,nbrows(x),r,&col_ei); } GEN image2(GEN x) { pari_sp av = avma; long k, n, i; GEN A, B; if (typ(x)!=t_MAT) pari_err_TYPE("image2",x); if (lg(x) == 1) return cgetg(1,t_MAT); A = ker(x); k = lg(A)-1; if (!k) { avma = av; return gcopy(x); } A = suppl(A); n = lg(A)-1; B = cgetg(n-k+1, t_MAT); for (i = k+1; i <= n; i++) gel(B,i-k) = RgM_RgC_mul(x, gel(A,i)); return gerepileupto(av, B); } GEN matimage0(GEN x,long flag) { switch(flag) { case 0: return image(x); case 1: return image2(x); default: pari_err_FLAG("matimage"); } return NULL; /* LCOV_EXCL_LINE */ } static long RgM_rank_FpM(GEN x, GEN p) { pari_sp av = avma; ulong pp; long r; x = RgM_Fp_init(x,p,&pp); switch(pp) { case 0: r = FpM_rank(x,p); break; case 2: r = F2m_rank(x); break; default:r = Flm_rank(x,pp); break; } avma = av; return r; } static long RgM_rank_FqM(GEN x, GEN pol, GEN p) { pari_sp av = avma; long r; GEN T = RgX_to_FpX(pol, p); if (signe(T) == 0) pari_err_OP("rank",x,pol); r = FqM_rank(RgM_to_FqM(x, T, p), T, p); avma = av; return r; } #define code(t1,t2) ((t1 << 6) | t2) static long RgM_rank_fast(GEN x) { GEN p, pol; long pa; long t = RgM_type(x,&p,&pol,&pa); switch(t) { case t_INT: return ZM_rank(x); case t_FRAC: return QM_rank(x); case t_INTMOD: return RgM_rank_FpM(x, p); case t_FFELT: return FFM_rank(x, pol); case code(t_POLMOD, t_INTMOD): return RgM_rank_FqM(x, pol, p); default: return -1; } } #undef code long rank(GEN x) { pari_sp av = avma; long r; if (typ(x)!=t_MAT) pari_err_TYPE("rank",x); r = RgM_rank_fast(x); if (r >= 0) return r; (void)gauss_pivot(x, &r); avma = av; return lg(x)-1 - r; } /* d a t_VECSMALL of integers in 1..n. Return the vector of the d[i] * followed by the missing indices */ static GEN perm_complete(GEN d, long n) { GEN y = cgetg(n+1, t_VECSMALL); long i, j = 1, k = n, l = lg(d); pari_sp av = avma; char *T = stack_calloc(n+1); for (i = 1; i < l; i++) T[d[i]] = 1; for (i = 1; i <= n; i++) if (T[i]) y[j++] = i; else y[k--] = i; avma = av; return y; } /* n = dim x, r = dim Ker(x), d from gauss_pivot */ static GEN indexrank0(long n, long r, GEN d) { GEN p1, p2, res = cgetg(3,t_VEC); long i, j; r = n - r; /* now r = dim Im(x) */ p1 = cgetg(r+1,t_VECSMALL); gel(res,1) = p1; p2 = cgetg(r+1,t_VECSMALL); gel(res,2) = p2; if (d) { for (i=0,j=1; j<=n; j++) if (d[j]) { i++; p1[i] = d[j]; p2[i] = j; } vecsmall_sort(p1); } return res; } /* n = dim x, r = dim Ker(x), d from gauss_pivot */ static GEN indeximage0(long n, long r, GEN d) { long i, j; GEN v; r = n - r; /* now r = dim Im(x) */ v = cgetg(r+1,t_VECSMALL); if (d) for (i=j=1; j<=n; j++) if (d[j]) v[i++] = j; return v; } /* x an m x n t_MAT, n > 0, r = dim Ker(x), d from gauss_pivot */ static void indexrank_all(long m, long n, long r, GEN d, GEN *prow, GEN *pcol) { GEN IR = indexrank0(n, r, d); *prow = perm_complete(gel(IR,1), m); *pcol = perm_complete(gel(IR,2), n); } static void init_indexrank(GEN x) { (void)new_chunk(3 + 2*lg(x)); /* HACK */ } static GEN RgM_indexrank_FpM(GEN x, GEN p) { pari_sp av = avma; ulong pp; GEN r; x = RgM_Fp_init(x,p,&pp); switch(pp) { case 0: r = FpM_indexrank(x,p); break; case 2: r = F2m_indexrank(x); break; default: r = Flm_indexrank(x,pp); break; } return gerepileupto(av, r); } static GEN RgM_indexrank_FqM(GEN x, GEN pol, GEN p) { pari_sp av = avma; GEN r, T = RgX_to_FpX(pol, p); if (signe(T) == 0) pari_err_OP("indexrank",x,pol); r = FqM_indexrank(RgM_to_FqM(x, T, p), T, p); return gerepileupto(av, r); } #define code(t1,t2) ((t1 << 6) | t2) static GEN RgM_indexrank_fast(GEN x) { GEN p, pol; long pa; long t = RgM_type(x,&p,&pol,&pa); switch(t) { case t_INT: return ZM_indexrank(x); case t_FRAC: return QM_indexrank(x); case t_INTMOD: return RgM_indexrank_FpM(x, p); case t_FFELT: return FFM_indexrank(x, pol); case code(t_POLMOD, t_INTMOD): return RgM_indexrank_FqM(x, pol, p); default: return NULL; } } #undef code GEN indexrank(GEN x) { pari_sp av; long r; GEN d; if (typ(x)!=t_MAT) pari_err_TYPE("indexrank",x); d = RgM_indexrank_fast(x); if (d) return d; av = avma; init_indexrank(x); d = gauss_pivot(x, &r); avma = av; return indexrank0(lg(x)-1, r, d); } GEN FpM_indexrank(GEN x, GEN p) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = FpM_gauss_pivot(x,p,&r); avma = av; return indexrank0(lg(x)-1, r, d); } GEN Flm_indexrank(GEN x, ulong p) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = Flm_pivots(x, p, &r, 0); avma = av; return indexrank0(lg(x)-1, r, d); } GEN F2m_indexrank(GEN x) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = F2m_gauss_pivot(F2m_copy(x),&r); avma = av; return indexrank0(lg(x)-1, r, d); } GEN F2xqM_indexrank(GEN x, GEN T) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = F2xqM_gauss_pivot(x, T, &r); avma = av; return indexrank0(lg(x) - 1, r, d); } GEN FlxqM_indexrank(GEN x, GEN T, ulong p) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = FlxqM_gauss_pivot(x, T, p, &r); avma = av; return indexrank0(lg(x) - 1, r, d); } GEN FqM_indexrank(GEN x, GEN T, GEN p) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = FqM_gauss_pivot(x, T, p, &r); avma = av; return indexrank0(lg(x) - 1, r, d); } GEN ZM_indeximage(GEN x) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = ZM_pivots(x,&r); avma = av; return indeximage0(lg(x)-1, r, d); } long ZM_rank(GEN x) { pari_sp av = avma; long r; (void)ZM_pivots(x,&r); avma = av; return lg(x)-1-r; } GEN ZM_indexrank(GEN x) { pari_sp av = avma; long r; GEN d; init_indexrank(x); d = ZM_pivots(x,&r); avma = av; return indexrank0(lg(x)-1, r, d); } long QM_rank(GEN x) { pari_sp av = avma; long r = ZM_rank(Q_primpart(x)); avma = av; return r; } GEN QM_indexrank(GEN x) { pari_sp av = avma; GEN r = ZM_indexrank(Q_primpart(x)); return gerepileupto(av, r); } /*******************************************************************/ /* */ /* ZabM */ /* */ /*******************************************************************/ static GEN FpXM_ratlift(GEN a, GEN q) { GEN B, y; long i, j, l = lg(a), n; B = sqrti(shifti(q,-1)); y = cgetg(l, t_MAT); if (l==1) return y; n = lgcols(a); for (i=1; i>1; ulong p= 1 + m - (m % n); long lM = lg(M); if (lM == 1) { *pden = gen_1; return cgetg(1,t_MAT); } av2 = avma; H = NULL; for(;;) { GEN Hp, Pp, Mp, Hr; do p += n; while(!uisprime(p)); Pp = ZX_to_Flx(P, p); Mp = FqM_to_FlxM(M, P, utoi(p)); Hp = FlkM_inv(Mp, Pp, p); if (!Hp) continue; if (!H) { H = ZXM_init_CRT(Hp, degpol(P)-1, p); q = utoipos(p); } else ZXM_incremental_CRT(&H, Hp, &q, p); Hr = FpXM_ratlift(H, q); if (DEBUGLEVEL>5) err_printf("ZabM_inv mod %ld (ratlift=%ld)\n", p,!!Hr); if (Hr) {/* DONE ? */ GEN Hl = Q_remove_denom(Hr, pden); GEN MH = ZXQM_mul(Hl, M, P); if (*pden) { if (RgM_isscalar(MH, *pden)) { H = Hl; break; }} else { if (RgM_isidentity(MH)) { H = Hl; *pden = gen_1; break; } } } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZabM_inv"); gerepileall(av2, 2, &H, &q); } } gerepileall(av, 2, &H, pden); return H; } static GEN FlkM_ker(GEN M, GEN P, ulong p) { ulong pi = get_Fl_red(p); GEN R = Flx_roots(P, p); long l = lg(R), i, dP = degpol(P), r; GEN M1, K, D; GEN W = Flv_invVandermonde(R, 1UL, p); GEN V = cgetg(l, t_VEC); M1 = FlxM_eval_powers_pre(M, Fl_powers_pre(uel(R,1), dP, p, pi), p, pi); K = Flm_ker_sp(M1, p, 2); r = lg(gel(K,1)); D = gel(K,2); gel(V, 1) = gel(K,1); for(i=2; i>1; ulong p= 1 + m - (m % n); av2 = avma; H = NULL; D = NULL; for(;;) { GEN Kp, Hp, Dp, Pp, Mp, Hr; do p += n; while(!uisprime(p)); Pp = ZX_to_Flx(P, p); Mp = FqM_to_FlxM(M, P, utoi(p)); Kp = FlkM_ker(Mp, Pp, p); if (!Kp) continue; Hp = gel(Kp,1); Dp = gel(Kp,2); if (H && (lg(Hp)>lg(H) || (lg(Hp)==lg(H) && vecsmall_lexcmp(Dp,D)>0))) continue; if (!H || (lg(Hp)5) err_printf("ZabM_ker mod %ld (ratlift=%ld)\n", p,!!Hr); if (Hr) {/* DONE ? */ GEN Hl = vec_Q_primpart(Hr); GEN MH = ZXQM_mul(M, Hl,P); if (gequal0(MH)) { H = Hl; break; } } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZabM_ker"); gerepileall(av2, 3, &H, &D, &q); } } return gerepilecopy(av, H); } GEN ZabM_indexrank(GEN M, GEN P, long n) { pari_sp av = avma; ulong m = LONG_MAX>>1; ulong p = 1+m-(m%n), D = degpol(P); long lM = lg(M), lmax = 0, c = 0; GEN v; for(;;) { GEN R, Mp, K; ulong pi; long l; do p += n; while (!uisprime(p)); pi = get_Fl_red(p); R = Flx_roots(ZX_to_Flx(P, p), p); Mp = FqM_to_FlxM(M, P, utoipos(p)); K = FlxM_eval_powers_pre(Mp, Fl_powers_pre(uel(R,1), D,p,pi), p,pi); v = Flm_indexrank(K, p); l = lg(gel(v,2)); if (l == lM) break; if (lmax >= 0 && l > lmax) { lmax = l; c = 0; } else c++; if (c > 2) { /* probably not maximal rank, expensive check */ lM -= lg(ZabM_ker(M, P, n))-1; /* actual rank (+1) */ if (lmax == lM) break; lmax = -1; /* disable check */ } } return gerepileupto(av, v); } #if 0 GEN ZabM_gauss(GEN M, GEN P, long n, GEN *den) { pari_sp av = avma; GEN v, S, W; v = ZabM_indexrank(M, P, n); S = shallowmatextract(M,gel(v,1),gel(v,2)); W = ZabM_inv(S, P, n, den); gerepileall(av,2,&W,den); return W; } #endif GEN ZabM_pseudoinv(GEN M, GEN P, long n, GEN *pv, GEN *den) { GEN v = ZabM_indexrank(M, P, n); if (pv) *pv = v; M = shallowmatextract(M,gel(v,1),gel(v,2)); return ZabM_inv(M, P, n, den); } GEN ZM_pseudoinv(GEN M, GEN *pv, GEN *den) { GEN v = ZM_indexrank(M); if (pv) *pv = v; M = shallowmatextract(M,gel(v,1),gel(v,2)); return ZM_inv(M, den); } /*******************************************************************/ /* */ /* Structured Elimination */ /* */ /*******************************************************************/ static void rem_col(GEN c, long i, GEN iscol, GEN Wrow, long *rcol, long *rrow) { long lc = lg(c), k; iscol[i] = 0; (*rcol)--; for (k = 1; k < lc; ++k) { Wrow[c[k]]--; if (Wrow[c[k]]==0) (*rrow)--; } } static void rem_singleton(GEN M, GEN iscol, GEN Wrow, long *rcol, long *rrow) { long i, j; long nbcol = lg(iscol)-1, last; do { last = 0; for (i = 1; i <= nbcol; ++i) if (iscol[i]) { GEN c = gmael(M, i, 1); long lc = lg(c); for (j = 1; j < lc; ++j) if (Wrow[c[j]] == 1) { rem_col(c, i, iscol, Wrow, rcol, rrow); last=1; break; } } } while (last); } static GEN fill_wcol(GEN M, GEN iscol, GEN Wrow, long *w, GEN wcol) { long nbcol = lg(iscol)-1; long i, j, m, last; GEN per; for (m = 2, last=0; !last ; m++) { for (i = 1; i <= nbcol; ++i) { wcol[i] = 0; if (iscol[i]) { GEN c = gmael(M, i, 1); long lc = lg(c); for (j = 1; j < lc; ++j) if (Wrow[c[j]] == m) { wcol[i]++; last = 1; } } } } per = vecsmall_indexsort(wcol); *w = wcol[per[nbcol]]; return per; } /* M is a RgMs with nbrow rows, A a list of row indices. Eliminate rows of M with a single entry that do not belong to A, and the corresponding columns. Also eliminate columns until #colums=#rows. Return pcol and prow: pcol is a map from the new columns indices to the old one. prow is a map from the old rows indices to the new one (0 if removed). */ void RgMs_structelim_col(GEN M, long nbcol, long nbrow, GEN A, GEN *p_col, GEN *p_row) { long i,j,k; long lA = lg(A); GEN prow = cgetg(nbrow+1, t_VECSMALL); GEN pcol = zero_zv(nbcol); pari_sp av = avma; long rcol = nbcol, rrow = 0, imin = nbcol - usqrt(nbcol); GEN iscol = const_vecsmall(nbcol, 1); GEN Wrow = zero_zv(nbrow); GEN wcol = cgetg(nbcol+1, t_VECSMALL); pari_sp av2=avma; for (i = 1; i <= nbcol; ++i) { GEN F = gmael(M, i, 1); long l = lg(F)-1; for (j = 1; j <= l; ++j) Wrow[F[j]]++; } for (j = 1; j < lA; ++j) { if (Wrow[A[j]] == 0) { *p_col=NULL; return; } Wrow[A[j]] = -1; } for (i = 1; i <= nbrow; ++i) if (Wrow[i]) rrow++; rem_singleton(M, iscol, Wrow, &rcol, &rrow); if (rcolrrow;) { long w; GEN per = fill_wcol(M, iscol, Wrow, &w, wcol); for (i = nbcol; i>=imin && wcol[per[i]]>=w && rcol>rrow; i--) rem_col(gmael(M, per[i], 1), per[i], iscol, Wrow, &rcol, &rrow); rem_singleton(M, iscol, Wrow, &rcol, &rrow); avma = av2; } for (j = 1, i = 1; i <= nbcol; ++i) if (iscol[i]) pcol[j++] = i; setlg(pcol,j); for (k = 1, i = 1; i <= nbrow; ++i) prow[i] = Wrow[i] ? k++: 0; avma = av; *p_col = pcol; *p_row = prow; } void RgMs_structelim(GEN M, long nbrow, GEN A, GEN *p_col, GEN *p_row) { RgMs_structelim_col(M, lg(M)-1, nbrow, A, p_col, p_row); } /*******************************************************************/ /* */ /* EIGENVECTORS */ /* (independent eigenvectors, sorted by increasing eigenvalue) */ /* */ /*******************************************************************/ /* assume x is square of dimension > 0 */ static int RgM_is_symmetric_cx(GEN x, long bit) { pari_sp av = avma; long i, j, l = lg(x); for (i = 1; i < l; i++) for (j = 1; j < i; j++) { GEN a = gcoeff(x,i,j), b = gcoeff(x,j,i), c = gsub(a,b); if (!gequal0(c) && gexpo(c) - gexpo(a) > -bit) { avma = av; return 0; } } avma = av; return 1; } static GEN eigen_err(int exact, GEN x, long flag, long prec) { pari_sp av = avma; if (RgM_is_symmetric_cx(x, prec2nbits(prec) - 10)) { /* approximately symmetric: recover */ x = jacobi(x, prec); if (flag) return x; return gerepilecopy(av, gel(x,1)); } if (exact) { GEN y = mateigen(x, flag, precdbl(prec)); return gerepilecopy(av, gprec_wtrunc(y, prec)); } pari_err_PREC("mateigen"); return NULL; /* LCOV_EXCL_LINE */ } GEN mateigen(GEN x, long flag, long prec) { GEN y, R, T; long k, l, ex, n = lg(x); int exact; pari_sp av = avma; if (typ(x)!=t_MAT) pari_err_TYPE("eigen",x); if (n != 1 && n != lgcols(x)) pari_err_DIM("eigen"); if (flag < 0 || flag > 1) pari_err_FLAG("mateigen"); if (n == 1) { if (flag) retmkvec2(cgetg(1,t_VEC), cgetg(1,t_MAT)); return cgetg(1,t_VEC); } if (n == 2) { if (flag) retmkvec2(mkveccopy(gcoeff(x,1,1)), matid(1)); return matid(1); } ex = 16 - prec2nbits(prec); T = charpoly(x,0); exact = RgX_is_QX(T); if (exact) { T = ZX_radical( Q_primpart(T) ); R = nfrootsQ(T); if (lg(R)-1 < degpol(T)) { /* add missing complex roots */ GEN r = cleanroots(RgX_div(T, roots_to_pol(R, 0)), prec); settyp(r, t_VEC); R = shallowconcat(R, r); } } else { GEN r1, v = vectrunc_init(lg(T)); long e; R = cleanroots(T,prec); r1 = NULL; for (k = 1; k < lg(R); k++) { GEN r2 = gel(R,k), r = grndtoi(r2, &e); if (e < ex) r2 = r; if (r1) { r = gsub(r1,r2); if (gequal0(r) || gexpo(r) < ex) continue; } vectrunc_append(v, r2); r1 = r2; } R = v; } /* R = distinct complex roots of charpoly(x) */ l = lg(R); y = cgetg(l, t_VEC); for (k = 1; k < l; k++) { GEN F = ker_aux(RgM_Rg_sub_shallow(x, gel(R,k)), x); long d = lg(F)-1; if (!d) { avma = av; return eigen_err(exact, x, flag, prec); } gel(y,k) = F; if (flag) gel(R,k) = const_vec(d, gel(R,k)); } y = shallowconcat1(y); if (lg(y) > n) { avma = av; return eigen_err(exact, x, flag, prec); } /* lg(y) < n if x is not diagonalizable */ if (flag) y = mkvec2(shallowconcat1(R), y); return gerepilecopy(av,y); } GEN eigen(GEN x, long prec) { return mateigen(x, 0, prec); } /*******************************************************************/ /* */ /* DETERMINANT */ /* */ /*******************************************************************/ GEN det0(GEN a,long flag) { switch(flag) { case 0: return det(a); case 1: return det2(a); default: pari_err_FLAG("matdet"); } return NULL; /* LCOV_EXCL_LINE */ } /* M a 2x2 matrix, returns det(M) */ static GEN RgM_det2(GEN M) { pari_sp av = avma; GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2); GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2); return gerepileupto(av, gsub(gmul(a,d), gmul(b,c))); } /* M a 2x2 ZM, returns det(M) */ static GEN ZM_det2(GEN M) { pari_sp av = avma; GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2); GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2); return gerepileuptoint(av, subii(mulii(a,d), mulii(b, c))); } /* M a 3x3 ZM, return det(M) */ static GEN ZM_det3(GEN M) { pari_sp av = avma; GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2), c = gcoeff(M,1,3); GEN d = gcoeff(M,2,1), e = gcoeff(M,2,2), f = gcoeff(M,2,3); GEN g = gcoeff(M,3,1), h = gcoeff(M,3,2), i = gcoeff(M,3,3); GEN t, D = signe(i)? mulii(subii(mulii(a,e), mulii(b,d)), i): gen_0; if (signe(g)) { t = mulii(subii(mulii(b,f), mulii(c,e)), g); D = addii(D, t); } if (signe(h)) { t = mulii(subii(mulii(c,d), mulii(a,f)), h); D = addii(D, t); } return gerepileuptoint(av, D); } static GEN det_simple_gauss(GEN a, GEN data, pivot_fun pivot) { pari_sp av = avma; long i,j,k, s = 1, nbco = lg(a)-1; GEN p, x = gen_1; a = RgM_shallowcopy(a); for (i=1; i nbco) return gerepilecopy(av, gcoeff(a,i,i)); if (k != i) { /* exchange the lines s.t. k = i */ for (j=i; j<=nbco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j)); s = -s; } p = gcoeff(a,i,i); x = gmul(x,p); for (k=i+1; k<=nbco; k++) { GEN m = gcoeff(a,i,k); if (gequal0(m)) continue; m = gdiv(m,p); for (j=i+1; j<=nbco; j++) gcoeff(a,j,k) = gsub(gcoeff(a,j,k), gmul(m,gcoeff(a,j,i))); } if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i); gerepileall(av,2, &a,&x); } } if (s < 0) x = gneg_i(x); return gerepileupto(av, gmul(x, gcoeff(a,nbco,nbco))); } GEN det2(GEN a) { GEN data; pivot_fun pivot; long n = lg(a)-1; if (typ(a)!=t_MAT) pari_err_TYPE("det2",a); if (!n) return gen_1; if (n != nbrows(a)) pari_err_DIM("det2"); if (n == 1) return gcopy(gcoeff(a,1,1)); if (n == 2) return RgM_det2(a); pivot = get_pivot_fun(a, a, &data); return det_simple_gauss(a, data, pivot); } /* Assumes a a square t_MAT of dimension n > 0. Returns det(a) using * Gauss-Bareiss. */ static GEN det_bareiss(GEN a) { pari_sp av = avma; long nbco = lg(a)-1,i,j,k,s = 1; GEN p, pprec; a = RgM_shallowcopy(a); for (pprec=gen_1,i=1; inbco) return gerepilecopy(av, p); swap(gel(a,k), gel(a,i)); s = -s; p = gcoeff(a,i,i); } ci = gel(a,i); for (k=i+1; k<=nbco; k++) { GEN ck = gel(a,k), m = gel(ck,i); if (gequal0(m)) { if (gequal1(p)) { if (diveuc) gel(a,k) = gdiv(gel(a,k), pprec); } else for (j=i+1; j<=nbco; j++) { GEN p1 = gmul(p, gel(ck,j)); if (diveuc) p1 = gdiv(p1,pprec); gel(ck,j) = p1; } } else for (j=i+1; j<=nbco; j++) { pari_sp av2 = avma; GEN p1 = gsub(gmul(p,gel(ck,j)), gmul(m,gel(ci,j))); if (diveuc) p1 = gdiv(p1,pprec); gel(ck,j) = gerepileupto(av2, p1); } if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i); gerepileall(av,2, &a,&pprec); ci = gel(a,i); p = gcoeff(a,i,i); } } } p = gcoeff(a,nbco,nbco); p = (s < 0)? gneg(p): gcopy(p); return gerepileupto(av, p); } /* count non-zero entries in col j, at most 'max' of them. * Return their indices */ static GEN col_count_non_zero(GEN a, long j, long max) { GEN v = cgetg(max+1, t_VECSMALL); GEN c = gel(a,j); long i, l = lg(a), k = 1; for (i = 1; i < l; i++) if (!gequal0(gel(c,i))) { if (k > max) return NULL; /* fail */ v[k++] = i; } setlg(v, k); return v; } /* count non-zero entries in row i, at most 'max' of them. * Return their indices */ static GEN row_count_non_zero(GEN a, long i, long max) { GEN v = cgetg(max+1, t_VECSMALL); long j, l = lg(a), k = 1; for (j = 1; j < l; j++) if (!gequal0(gcoeff(a,i,j))) { if (k > max) return NULL; /* fail */ v[k++] = j; } setlg(v, k); return v; } static GEN det_develop(GEN a, long max, double bound); /* (-1)^(i+j) a[i,j] * det RgM_minor(a,i,j) */ static GEN coeff_det(GEN a, long i, long j, long max, double bound) { GEN c = gcoeff(a, i, j); c = gmul(c, det_develop(RgM_minor(a, i,j), max, bound)); if (odd(i+j)) c = gneg(c); return c; } /* a square t_MAT, 'bound' a rough upper bound for the number of * multiplications we are willing to pay while developing rows/columns before * switching to Gaussian elimination */ static GEN det_develop(GEN M, long max, double bound) { pari_sp av = avma; long i,j, n = lg(M)-1, lbest = max+2, best_col = 0, best_row = 0; GEN best = NULL; if (bound < 1.) return det_bareiss(M); /* too costly now */ switch(n) { case 0: return gen_1; case 1: return gcopy(gcoeff(M,1,1)); case 2: return RgM_det2(M); } if (max > ((n+2)>>1)) max = (n+2)>>1; for (j = 1; j <= n; j++) { pari_sp av2 = avma; GEN v = col_count_non_zero(M, j, max); long lv; if (!v || (lv = lg(v)) >= lbest) { avma = av2; continue; } if (lv == 1) { avma = av; return gen_0; } if (lv == 2) { avma = av; return gerepileupto(av, coeff_det(M,v[1],j,max,bound)); } best = v; lbest = lv; best_col = j; } for (i = 1; i <= n; i++) { pari_sp av2 = avma; GEN v = row_count_non_zero(M, i, max); long lv; if (!v || (lv = lg(v)) >= lbest) { avma = av2; continue; } if (lv == 1) { avma = av; return gen_0; } if (lv == 2) { avma = av; return gerepileupto(av, coeff_det(M,i,v[1],max,bound)); } best = v; lbest = lv; best_row = i; } if (best_row) { double d = lbest-1; GEN s = NULL; long k; bound /= d*d*d; for (k = 1; k < lbest; k++) { GEN c = coeff_det(M, best_row, best[k], max, bound); s = s? gadd(s, c): c; } return gerepileupto(av, s); } if (best_col) { double d = lbest-1; GEN s = NULL; long k; bound /= d*d*d; for (k = 1; k < lbest; k++) { GEN c = coeff_det(M, best[k], best_col, max, bound); s = s? gadd(s, c): c; } return gerepileupto(av, s); } return det_bareiss(M); } /* area of parallelogram bounded by (v1,v2) */ static GEN parallelogramarea(GEN v1, GEN v2) { return gsub(gmul(gnorml2(v1), gnorml2(v2)), gsqr(RgV_dotproduct(v1, v2))); } /* Square of Hadamard bound for det(a), a square matrix. * Slightly improvement: instead of using the column norms, use the area of * the parallelogram formed by pairs of consecutive vectors */ GEN RgM_Hadamard(GEN a) { pari_sp av = avma; long n = lg(a)-1, i; GEN B; if (n == 0) return gen_1; if (n == 1) return gsqr(gcoeff(a,1,1)); a = RgM_gtofp(a, LOWDEFAULTPREC); B = gen_1; for (i = 1; i <= n/2; i++) B = gmul(B, parallelogramarea(gel(a,2*i-1), gel(a,2*i))); if (odd(n)) B = gmul(B, gnorml2(gel(a, n))); return gerepileuptoint(av, ceil_safe(B)); } /* If B=NULL, assume B=A' */ static GEN ZM_det_slice(GEN A, GEN P, GEN *mod) { pari_sp av = avma; long i, n = lg(P)-1; GEN H, T; if (n == 1) { ulong Hp, p = uel(P,1); GEN a = ZM_to_Flm(A, p); Hp = Flm_det_sp(a, p); avma = av; *mod = utoi(p); return utoi(Hp); } T = ZV_producttree(P); A = ZM_nv_mod_tree(A, P, T); H = cgetg(n+1, t_VECSMALL); for(i=1; i <= n; i++) { ulong p = P[i]; GEN a = gel(A,i); H[i] = Flm_det_sp(a, p); } H = ZV_chinese_tree(H, P, T, ZV_chinesetree(P,T)); *mod = gmael(T, lg(T)-1, 1); gerepileall(av, 2, &H, mod); return H; } GEN ZM_det_worker(GEN P, GEN A) { GEN V = cgetg(3, t_VEC); gel(V,1) = ZM_det_slice(A, P, &gel(V,2)); return V; } /* assume dim(a) = n > 0 */ static GEN ZM_det_i(GEN M, long n) { const long DIXON_THRESHOLD = 40; pari_sp av = avma, av2; long i; ulong p, Dp = 1; forprime_t S; pari_timer ti; GEN H, D, mod, h, q, v, worker; if (n == 1) return icopy(gcoeff(M,1,1)); if (n == 2) return ZM_det2(M); if (n == 3) return ZM_det3(M); if (DEBUGLEVEL >=4) timer_start(&ti); h = RgM_Hadamard(M); if (!signe(h)) { avma = av; return gen_0; } h = sqrti(h); q = gen_1; init_modular_big(&S); p = 0; /* -Wall */ while( cmpii(q, h) <= 0 && (p = u_forprime_next(&S)) ) { av2 = avma; Dp = Flm_det_sp(ZM_to_Flm(M, p), p); avma = av2; if (Dp) break; q = muliu(q, p); } if (!p) pari_err_OVERFLOW("ZM_det [ran out of primes]"); if (!Dp) { avma = av; return gen_0; } if (n <= DIXON_THRESHOLD) D = q; else { av2 = avma; v = cgetg(n+1, t_COL); gel(v, 1) = gen_1; /* ensure content(v) = 1 */ for (i = 2; i <= n; i++) gel(v, i) = stoi(random_Fl(15) - 7); D = Q_denom(ZM_gauss(M, v)); if (expi(D) < expi(h) >> 1) { /* First try unlucky, try once more */ for (i = 2; i <= n; i++) gel(v, i) = stoi(random_Fl(15) - 7); D = lcmii(D, Q_denom(ZM_gauss(M, v))); } D = gerepileuptoint(av2, D); if (q != gen_1) D = lcmii(D, q); } /* determinant is a multiple of D */ if (DEBUGLEVEL >=4) timer_printf(&ti,"ZM_det: Dixon %ld/%ld bits",expi(D),expi(h)); h = divii(h, D); worker = strtoclosure("_ZM_det_worker", 1, M); H = gen_crt("ZM_det", worker, D, expi(h)+1, lg(M)-1, &mod, ZV_chinese, NULL); if (D) H = Fp_div(H, D, mod); H = Fp_center(H, mod, shifti(mod,-1)); if (D) H = mulii(H, D); return gerepileuptoint(av, H); } static GEN RgM_det_FpM(GEN a, GEN p) { pari_sp av = avma; ulong pp, d; a = RgM_Fp_init(a,p,&pp); switch(pp) { case 0: return gerepileupto(av, Fp_to_mod(FpM_det(a,p),p)); break; case 2: d = F2m_det(a); break; default:d = Flm_det_sp(a, pp); break; } avma = av; return mkintmodu(d, pp); } static GEN RgM_det_FqM(GEN x, GEN pol, GEN p) { pari_sp av = avma; GEN b, T = RgX_to_FpX(pol, p); if (signe(T) == 0) pari_err_OP("%",x,pol); b = FqM_det(RgM_to_FqM(x, T, p), T, p); if (!b) { avma = av; return NULL; } return gerepilecopy(av, mkpolmod(FpX_to_mod(b, p), FpX_to_mod(T, p))); } #define code(t1,t2) ((t1 << 6) | t2) static GEN RgM_det_fast(GEN x) { GEN p, pol; long pa; long t = RgM_type(x, &p,&pol,&pa); switch(t) { case t_INT: return ZM_det(x); case t_FRAC: return QM_det(x); case t_FFELT: return FFM_det(x, pol); case t_INTMOD: return RgM_det_FpM(x, p); case code(t_POLMOD, t_INTMOD): return RgM_det_FqM(x, pol, p); default: return NULL; } } #undef code static long det_init_max(long n) { if (n > 100) return 0; if (n > 50) return 1; if (n > 30) return 4; return 7; } GEN det(GEN a) { long n = lg(a)-1; double B; GEN data, b; pivot_fun pivot; if (typ(a)!=t_MAT) pari_err_TYPE("det",a); if (!n) return gen_1; if (n != nbrows(a)) pari_err_DIM("det"); if (n == 1) return gcopy(gcoeff(a,1,1)); if (n == 2) return RgM_det2(a); b = RgM_det_fast(a); if (b) return b; pivot = get_pivot_fun(a, a, &data); if (pivot != gauss_get_pivot_NZ) return det_simple_gauss(a, data, pivot); B = (double)n; return det_develop(a, det_init_max(n), B*B*B); } GEN ZM_det(GEN a) { long n = lg(a)-1; if (!n) return gen_1; return ZM_det_i(a, n); } GEN QM_det(GEN M) { pari_sp av = avma; GEN cM, pM = Q_primitive_part(M, &cM); GEN b = ZM_det(pM); if (cM) b = gmul(b, gpowgs(cM, lg(M)-1)); return gerepileupto(av, b); } pari-2.11.2/src/basemath/lll.c0000644000175000017500000006062313457566437014513 0ustar billbill/* Copyright (C) 2008 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* default quality ratio for LLL */ static const double LLLDFT = 0.99; /* assume flag & (LLL_KER|LLL_IM|LLL_ALL). LLL_INPLACE implies LLL_IM */ static GEN lll_trivial(GEN x, long flag) { GEN y; if (lg(x) == 1) { /* dim x = 0 */ if (! (flag & LLL_ALL)) return cgetg(1,t_MAT); y=cgetg(3,t_VEC); gel(y,1) = cgetg(1,t_MAT); gel(y,2) = cgetg(1,t_MAT); return y; } /* dim x = 1 */ if (gequal0(gel(x,1))) { if (flag & LLL_KER) return matid(1); if (flag & (LLL_IM|LLL_INPLACE)) return cgetg(1,t_MAT); y = cgetg(3,t_VEC); gel(y,1) = matid(1); gel(y,2) = cgetg(1,t_MAT); return y; } if (flag & LLL_INPLACE) return gcopy(x); if (flag & LLL_KER) return cgetg(1,t_MAT); if (flag & LLL_IM) return matid(1); y=cgetg(3,t_VEC); gel(y,1) = cgetg(1,t_MAT); gel(y,2) = (flag & LLL_GRAM)? gcopy(x): matid(1); return y; } /* vecslice(h,#h-k,#h) in place. Works for t_MAT, t_VEC/t_COL */ static GEN lll_get_im(GEN h, long k) { ulong mask = h[0] & ~LGBITS; long l = lg(h) - k; h += k; h[0] = mask | evallg(l); return h; } /* k = dim Kernel */ static GEN lll_finish(GEN h, long k, long flag) { GEN g; if (flag & LLL_KER) { setlg(h,k+1); return h; } if (flag & LLL_IM) return lll_get_im(h, k); g = vecslice(h,1,k); return mkvec2(g, lll_get_im(h, k)); } INLINE GEN mulshift(GEN y, GEN z, long e) { long ly = lgefint(y), lz; pari_sp av; GEN t; if (ly == 2) return gen_0; lz = lgefint(z); av = avma; (void)new_chunk(ly+lz+nbits2lg(e)); /* HACK */ t = mulii(z, y); avma = av; return shifti(t, e); } INLINE GEN submulshift(GEN x, GEN y, GEN z, long e) { long lx = lgefint(x), ly, lz; pari_sp av; GEN t; if (!e) return submulii(x, y, z); if (lx == 2) { t = mulshift(y, z, e); togglesign(t); return t; } ly = lgefint(y); if (ly == 2) return icopy(x); lz = lgefint(z); av = avma; (void)new_chunk(lx+ly+lz+nbits2lg(e)); /* HACK */ t = shifti(mulii(z, y), e); avma = av; return subii(x, t); } /********************************************************************/ /** **/ /** FPLLL (adapted from D. Stehle's code) **/ /** **/ /********************************************************************/ /* Babai() and fplll() are a conversion to libpari API and data types of the file proved.c in fplll-1.3 by Damien Stehle'. Copyright 2005, 2006 Damien Stehle'. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program implements ideas from the paper "Floating-point LLL Revisited", by Phong Nguyen and Damien Stehle', in the Proceedings of Eurocrypt'2005, Springer-Verlag; and was partly inspired by Shoup's NTL library: http://www.shoup.net/ntl/ */ /***********************************************/ /* Babai's Nearest Plane algorithm (iterative) */ /***********************************************/ /* Size-reduces b_kappa using mu_{i,j} and r_{i,j} for j<=i zeros)? a : zeros+1; GEN maxmu = gen_0, max2mu = gen_0; /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */ const long d = U ? lg(U)-1: 0; if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"Babai[0], a=%ld", aa); gerepileall(av,U?3:2,&B,&G,&U); } for (;;) { int go_on = 0; GEN max3mu; long i, j; if (gc_needed(av0,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa); gerepileall(av,U?5:4,&B,&G,&maxmu,&max2mu,&U); } /* Step2: compute the GSO for stage kappa */ max3mu = max2mu; max2mu = maxmu; maxmu = real_0(prec); for (j=aa; j k) { tmp = mulrr(gmael(mu,j,k), gmael(r,kappa,k)); rtmp = subir(gmael(G,kappa,j), tmp); for (k++; k5) err_printf("prec too low\n"); return kappa; } /* Step3--5: compute the X_j's */ for (j=kappa-1; j>zeros; j--) { tmp = gmael(mu,kappa,j); if (abscmprr(tmp, eta) <= 0) continue; /* (essentially) size-reduced */ if (gc_needed(av0,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j); gerepileall(av,U?5:4,&B,&G,&maxmu,&max2mu,&U); } go_on = 1; /* we consider separately the case |X| = 1 */ if (abscmprr(tmp, halfplus1) <= 0) { if (signe(tmp) > 0) { /* in this case, X = 1 */ pari_sp btop = avma; for (k=zeros+1; k= 2 */ ztmp = roundr_safe(tmp); if (lgefint(ztmp) == 3) { pari_sp btop = avma; ulong xx = ztmp[2]; /* X fits in an ulong */ if (signe(ztmp) > 0) /* = xx */ { for (k=zeros+1; kkappa; i--) for (j=1;j<=d;j++) gmael(mu,i,j) = gmael(mu,i-1,j); for (j=1;j<=d;j++) gmael(mu,kappa,j) = gel(mutmp,j); avma = av; } /* ****************** */ /* The LLL Algorithm */ /* ****************** */ /* LLL-reduces the integer matrix(ces) (G,B,U)? "in place" */ static GEN fplll(GEN *ptrB, GEN *ptrU, GEN *ptrr, double DELTA, double ETA, long flag, long prec) { const long gram = flag & LLL_GRAM; /*Gram matrix*/ const long keepfirst = flag & LLL_KEEP_FIRST; /*never swap with first vector*/ pari_sp av, av2; long kappa, kappa2, d, n, i, j, zeros, kappamax, maxG, bab; GEN G, mu, r, s, tmp, SPtmp, alpha; GEN delta = dbltor(DELTA), eta = dbltor(ETA), halfplus1 = dbltor(1.5); const long triangular = 0; pari_timer T; GEN B = *ptrB, U; long cnt = 0; d = lg(B)-1; if (gram) { G = B; n = d; B = cgetg(1, t_VECSMALL); /* dummy */ } else { G = zeromatcopy(d,d); n = nbrows(B); } U = *ptrU; /* NULL if inplace */ if(DEBUGLEVEL>=4) { timer_start(&T); err_printf("Entering L^2: LLL-parameters (%P.3f,%.3Pf), working precision %d words\n",delta,eta, prec); } mu = cgetg(d+1, t_MAT); r = cgetg(d+1, t_MAT); s = cgetg(d+1, t_VEC); for (j = 1; j <= d; j++) { GEN M = cgetg(d+1, t_COL), R = cgetg(d+1, t_COL); gel(mu,j)= M; gel(r,j) = R; gel(s,j) = cgetr(prec); for (i = 1; i <= d; i++) { gel(R,i) = cgetr(prec); gel(M,i) = cgetr(prec); } } SPtmp = zerovec(d+1); alpha = cgetg(d+1, t_VECSMALL); av = avma; /* Step2: Initializing the main loop */ kappamax = 1; i = 1; maxG = d; /* later updated to kappamax if (!gram) */ do { if (!gram) gmael(G,i,i) = ZV_dotsquare(gel(B,i)); affir(gmael(G,i,i), gmael(r,i,i)); } while (signe(gmael(G,i,i)) == 0 && (++i <=d)); zeros = i-1; /* all vectors B[i] with i <= zeros are zero vectors */ kappa = i; if (zeros < d) affir(gmael(G,zeros+1,zeros+1), gmael(r,zeros+1,zeros+1)); for (i=zeros+1; i<=d; i++) alpha[i]=1; while (++kappa <= d) { if (kappa>kappamax) { if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa); kappamax = kappa; if (!gram) { for (i=zeros+1; i<=kappa; i++) gmael(G,kappa,i) = ZV_dotproduct(gel(B,kappa), gel(B,i)); maxG = kappamax; } } /* Step3: Call to the Babai algorithm, mu,r,s updated in place */ bab = Babai(av, kappa, &G,&B,&U, mu,r,s, alpha[kappa], zeros, maxG, gram? 0 : ((triangular && kappamax <= n) ? kappamax: n), eta, halfplus1, prec); if (bab) {*ptrB=(gram?G:B); *ptrU=U; return NULL; } av2 = avma; if ((keepfirst && kappa == 2) || cmprr(mulrr(gmael(r,kappa-1,kappa-1), delta), gel(s,kappa-1)) <= 0) { /* Step4: Success of Lovasz's condition */ alpha[kappa] = kappa; tmp = mulrr(gmael(mu,kappa,kappa-1), gmael(r,kappa,kappa-1)); affrr(subrr(gel(s,kappa-1), tmp), gmael(r,kappa,kappa)); avma = av2; } else { /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */ if (DEBUGLEVEL>=4 && kappa==kappamax && signe(gel(s,kappa-1))) if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", expo(gel(s,1))); } kappa2 = kappa; do { kappa--; if (kappakappa; i--) alpha[i] = alpha[i-1]; for (i=kappa2+1; i<=kappamax; i++) if (kappa < alpha[i]) alpha[i] = kappa; alpha[kappa] = kappa; /* Step6: Update the mu's and r's */ rotate(mu,kappa2,kappa,d); rotate(r,kappa2,kappa,d); affrr(gel(s,kappa), gmael(r,kappa,kappa)); /* Step7: Update B, G, U */ if (!gram) rotate(B,kappa2,kappa,n); if (U) rotate(U,kappa2,kappa,d); for (i=1; i<=kappa2; i++) gel(SPtmp,i) = gmael(G,kappa2,i); for (i=kappa2+1; i<=maxG; i++) gel(SPtmp,i) = gmael(G,i,kappa2); for (i=kappa2; i>kappa; i--) { for (j=1; j=4) timer_printf(&T,"LLL"); if (ptrr) *ptrr = RgM_diagonal_shallow(r); if (!U) { if (zeros) { if (gram) { G = lll_get_im(G, zeros); d -= zeros; for (i = 1; i <= d; i++) gel(G,i) = lll_get_im(gel(G,i), zeros); } else B = lll_get_im(B, zeros); } } else if (flag & (LLL_IM|LLL_KER|LLL_ALL)) U = lll_finish(U, zeros, flag); if (gram) { if (U) return U; for (i = 1; i <= d; i++) for (j = i+1; j <= d; j++) gmael(G,i,j) = gmael(G,j,i); return G; } return U? U: B; } /* Assume x a ZM, if ptB != NULL, set it to Gram-Schmidt (squared) norms */ GEN ZM_lll_norms(GEN x, double DELTA, long flag, GEN *B) { pari_sp ltop = avma; const long compat = flag & LLL_COMPATIBLE; const double ETA = 0.51; long p, n = lg(x)-1; GEN U; if (n <= 1) return lll_trivial(x, flag); x = RgM_shallowcopy(x); U = (flag & LLL_INPLACE)? NULL: matid(n); for (p = compat? DEFAULTPREC: LOWDEFAULTPREC;;) { GEN m = fplll(&x, &U, B, DELTA, ETA, flag, p); if (m) return m; if (compat) p += DEFAULTPREC-2; else incrprec(p); gerepileall(ltop, U? 2: 1, &x, &U); } } /********************************************************************/ /** **/ /** LLL OVER K[X] **/ /** **/ /********************************************************************/ static int pslg(GEN x) { long tx; if (gequal0(x)) return 2; tx = typ(x); return is_scalar_t(tx)? 3: lg(x); } static int REDgen(long k, long l, GEN h, GEN L, GEN B) { GEN q, u = gcoeff(L,k,l); long i; if (pslg(u) < pslg(B)) return 0; q = gneg(gdeuc(u,B)); gel(h,k) = gadd(gel(h,k), gmul(q,gel(h,l))); for (i=1; i 2) k--; } else { for (l=k-2; l>=1; l--) if (REDgen(k, l, h, L, gel(B,l+1))) flc = 1; if (++k > n) break; } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"lllgramallgen"); gerepileall(av,3,&B,&L,&h); } } k=1; while (k 0) pari_err_COPRIME("BuildTree", gel(V,j), gel(V,j+1)); d = gel(d,2); if (!gequal1(d)) { if (typ(d)==t_POL) { d = FpXQ_inv(d, T, p); u = FqX_Fq_mul(u, d, T, p); v = FqX_Fq_mul(v, d, T, p); } else { d = Fp_inv(d, p); u = FqX_Fp_mul(u, d, T,p); v = FqX_Fp_mul(v, d, T,p); } } gel(W,j) = u; gel(W,j+1) = v; } } /* au + bv = 1 (p0), ab = f (p0). Lift mod p1 = p0 pd (<= p0^2). * If noinv is set, don't lift the inverses u and v */ static void ZpX_HenselLift(GEN V, GEN W, long j, GEN f, GEN pd, GEN p0, GEN p1, int noinv) { pari_sp av = avma; long space = lg(f) * lgefint(p1); GEN a2, b2, g, z, s, t; GEN a = gel(V,j), b = gel(V,j+1); GEN u = gel(W,j), v = gel(W,j+1); (void)new_chunk(space); /* HACK */ g = ZX_sub(f, ZX_mul(a,b)); g = ZX_Z_divexact(g, p0); g = FpX_red(g, pd); z = FpX_mul(v,g, pd); t = FpX_divrem(z,a, pd, &s); t = ZX_add(ZX_mul(u,g), ZX_mul(t,b)); t = FpX_red(t, pd); t = ZX_Z_mul(t,p0); s = ZX_Z_mul(s,p0); avma = av; a2 = ZX_add(a,s); b2 = ZX_add(b,t); /* already reduced mod p1 = pd p0 */ gel(V,j) = a2; gel(V,j+1) = b2; if (noinv) return; av = avma; (void)new_chunk(space); /* HACK */ g = ZX_add(ZX_mul(u,a2), ZX_mul(v,b2)); g = Z_ZX_sub(gen_1, g); g = ZX_Z_divexact(g, p0); g = FpX_red(g, pd); z = FpX_mul(v,g, pd); t = FpX_divrem(z,a, pd, &s); t = ZX_add(ZX_mul(u,g), ZX_mul(t,b)); t = FpX_red(t, pd); t = ZX_Z_mul(t,p0); s = ZX_Z_mul(s,p0); avma = av; gel(W,j) = ZX_add(u,t); gel(W,j+1) = ZX_add(v,s); } static void ZpXQ_HenselLift(GEN V, GEN W, long j, GEN f, GEN Td, GEN T1, GEN pd, GEN p0, GEN p1, int noinv) { pari_sp av = avma; const long n = degpol(T1), vT = varn(T1); long space = lg(f) * lgefint(p1) * lg(T1); GEN a2, b2, g, z, s, t; GEN a = gel(V,j), b = gel(V,j+1); GEN u = gel(W,j), v = gel(W,j+1); (void)new_chunk(space); /* HACK */ g = RgX_sub(f, Kronecker_to_ZXX(ZXX_mul_Kronecker(a,b,n), n, vT)); g = FpXQX_red(g, T1, p1); g = RgX_Rg_divexact(g, p0); z = FpXQX_mul(v,g, Td,pd); t = FpXQX_divrem(z,a, Td,pd, &s); t = ZX_add(ZXX_mul_Kronecker(u,g,n), ZXX_mul_Kronecker(t,b,n)); t = Kronecker_to_ZXX(t, n, vT); t = FpXQX_red(t, Td, pd); t = RgX_Rg_mul(t,p0); s = RgX_Rg_mul(s,p0); avma = av; a2 = RgX_add(a,s); b2 = RgX_add(b,t); /* already reduced mod p1 = pd p0 */ gel(V,j) = a2; gel(V,j+1) = b2; if (noinv) return; av = avma; (void)new_chunk(space); /* HACK */ g = ZX_add(ZXX_mul_Kronecker(u,a2,n), ZXX_mul_Kronecker(v,b2,n)); g = Kronecker_to_ZXX(g, n, vT); g = Rg_RgX_sub(gen_1, g); g = FpXQX_red(g, T1, p1); g = RgX_Rg_divexact(g, p0); z = FpXQX_mul(v,g, Td,pd); t = FpXQX_divrem(z,a, Td,pd, &s); t = ZX_add(ZXX_mul_Kronecker(u,g,n), ZXX_mul_Kronecker(t,b,n)); t = Kronecker_to_ZXX(t, n, vT); t = FpXQX_red(t, Td, pd); t = RgX_Rg_mul(t,p0); s = RgX_Rg_mul(s,p0); avma = av; gel(W,j) = RgX_add(u,t); gel(W,j+1) = RgX_add(v,s); } /* v list of factors, w list of inverses. f = v[j] v[j+1] * Lift v[j] and v[j+1] mod p0 pd (possibly mod T), then all their divisors */ static void ZpX_RecTreeLift(GEN link, GEN v, GEN w, GEN pd, GEN p0, GEN p1, GEN f, long j, int noinv) { if (j < 0) return; ZpX_HenselLift(v, w, j, f, pd, p0,p1, noinv); ZpX_RecTreeLift(link, v, w, pd, p0,p1, gel(v,j) , link[j ], noinv); ZpX_RecTreeLift(link, v, w, pd, p0,p1, gel(v,j+1), link[j+1], noinv); } static void ZpXQ_RecTreeLift(GEN link, GEN v, GEN w, GEN Td, GEN T1, GEN pd, GEN p0, GEN p1, GEN f, long j, int noinv) { if (j < 0) return; ZpXQ_HenselLift(v, w, j, f, Td,T1, pd, p0,p1, noinv); ZpXQ_RecTreeLift(link, v, w, Td,T1, pd, p0,p1, gel(v,j) , link[j ], noinv); ZpXQ_RecTreeLift(link, v, w, Td,T1, pd, p0,p1, gel(v,j+1), link[j+1], noinv); } /* Assume n > 0. We want to go to accuracy n, starting from accuracy 1, using * a quadratically convergent algorithm. Goal: 9 -> 1,2,3,5,9 instead of * 1,2,4,8,9 (sequence of accuracies). * * Let a0 = 1, a1 = 2, a2, ... ak = n, the sequence of accuracies. To obtain * it, work backwards: * a(k) = n, a(i-1) = (a(i) + 1) \ 2, * but we do not want to store a(i) explicitly, even as a t_VECSMALL, since * this would leave an object on the stack. We store a(i) implicitly in a * MASK: let a(0) = 1, if the i-bit of MASK is set, set a(i+1) = 2 a(i) - 1, * and 2a(i) otherwise. * * In fact, we do something a little more complicated to simplify the * function interface and avoid returning k and MASK separately: we return * MASK + 2^(k+1), so the highest bit of the mask indicates the length of the * sequence, and the following ones are as above. */ ulong quadratic_prec_mask(long n) { long a = n, i; ulong mask = 0; for(i = 1;; i++, mask <<= 1) { mask |= (a&1); a = (a+1)>>1; if (a==1) return mask | (1UL << i); } } /* Lift to precision p^e0. * a = modular factors of f mod (p,T) [possibly T=NULL] * OR a TreeLift structure [e, link, v, w]: go on lifting * flag = 0: standard. * flag = 1: return TreeLift structure */ static GEN MultiLift(GEN f, GEN a, GEN T, GEN p, long e0, long flag) { long i, eold, e, k = lg(a) - 1; GEN E, v, w, link, penew, Tnew; ulong mask; pari_timer Ti; if (k < 2) pari_err_DOMAIN("MultiLift", "#(modular factors)", "<", gen_2,a); if (e0 < 1) pari_err_DOMAIN("MultiLift", "precision", "<", gen_1,stoi(e0)); if (e0 == 1) return a; if (DEBUGLEVEL > 3) timer_start(&Ti); if (typ(gel(a,1)) == t_INT) { /* a = TreeLift structure */ e = itos(gel(a,1)); link = gel(a,2); v = gel(a,3); w = gel(a,4); } else { e = 1; v = cgetg(2*k-2 + 1, t_VEC); w = cgetg(2*k-2 + 1, t_VEC); link=cgetg(2*k-2 + 1, t_VECSMALL); BuildTree(link, v, w, a, T? FpX_red(T,p): NULL, p); if (DEBUGLEVEL > 3) timer_printf(&Ti, "building tree"); } mask = quadratic_prec_mask(e0); eold = 1; penew = NULL; Tnew = NULL; if (DEBUGLEVEL > 3) err_printf("lifting to prec %ld\n", e0); while (mask > 1) { long enew = eold << 1; if (mask & 1) enew--; mask >>= 1; if (enew >= e) { /* mask == 1: last iteration */ GEN peold = penew? penew: powiu(p, eold); GEN Td = NULL, pd; long d = enew - eold; /* = eold or eold-1 */ /* lift from p^eold to p^enew */ pd = (d == eold)? peold: diviiexact(peold, p); /* p^d */ penew = mulii(peold,pd); if (T) { if (Tnew) Td = (d == eold)? Tnew: FpX_red(Tnew,pd); else Td = FpX_red(T, peold); Tnew = FpX_red(T, penew); ZpXQ_RecTreeLift(link, v, w, Td, Tnew, pd, peold, penew, f, lg(v)-2, (flag == 0 && mask == 1)); } else ZpX_RecTreeLift(link, v, w, pd, peold, penew, f, lg(v)-2, (flag == 0 && mask == 1)); if (DEBUGLEVEL > 3) timer_printf(&Ti, "reaching prec %ld", enew); } eold = enew; } if (flag) E = mkvec4(utoipos(e0), link, v, w); else { E = cgetg(k+1, t_VEC); for (i = 1; i <= 2*k-2; i++) { long t = link[i]; if (t < 0) gel(E,-t) = gel(v,i); } } return E; } /* Q list of (coprime, monic) factors of pol mod (T,p). Lift mod p^e = pe. * T may be NULL */ GEN ZpX_liftfact(GEN pol, GEN Q, GEN pe, GEN p, long e) { pari_sp av = avma; pol = FpX_normalize(pol, pe); if (lg(Q) == 2) return mkvec(pol); return gerepilecopy(av, MultiLift(pol, Q, NULL, p, e, 0)); } GEN ZpXQX_liftfact(GEN pol, GEN Q, GEN T, GEN pe, GEN p, long e) { pari_sp av = avma; pol = FpXQX_normalize(pol, T, pe); if (lg(Q) == 2) return mkvec(pol); return gerepilecopy(av, MultiLift(pol, Q, T, p, e, 0)); } GEN ZqX_liftfact(GEN f, GEN a, GEN T, GEN pe, GEN p, long e) { return T ? ZpXQX_liftfact(f, a, T, pe, p, e): ZpX_liftfact(f, a, pe, p, e); } GEN ZqX_liftroot(GEN f, GEN a, GEN T, GEN p, long e) { return T ? ZpXQX_liftroot(f, a,T , p, e): ZpX_liftroot(f, a, p, e); } /* U = NULL treated as 1 */ static void BezoutPropagate(GEN link, GEN v, GEN w, GEN pe, GEN U, GEN f, long j) { GEN Q, R; if (j < 0) return; Q = FpX_mul(gel(v,j), gel(w,j), pe); if (U) { Q = FpXQ_mul(Q, U, f, pe); R = FpX_sub(U, Q, pe); } else R = Fp_FpX_sub(gen_1, Q, pe); gel(w,j+1) = Q; /* 0 mod U v[j], 1 mod (1-U) v[j+1] */ gel(w,j) = R; /* 1 mod U v[j], 0 mod (1-U) v[j+1] */ BezoutPropagate(link, v, w, pe, R, f, link[j ]); BezoutPropagate(link, v, w, pe, Q, f, link[j+1]); } /* as above, but return the Bezout coefficients for the lifted modular factors * U[i] = 1 mod Qlift[i] * 0 mod Qlift[j], j != i */ GEN bezout_lift_fact(GEN pol, GEN Q, GEN p, long e) { pari_sp av = avma; GEN E, link, v, w, pe; long i, k = lg(Q)-1; if (k == 1) retmkvec(pol_1(varn(pol))); pe = powiu(p, e); pol = FpX_normalize(pol, pe); E = MultiLift(pol, Q, NULL, p, e, 1); link = gel(E,2); v = gel(E,3); w = gel(E,4); BezoutPropagate(link, v, w, pe, NULL, pol, lg(v)-2); E = cgetg(k+1, t_VEC); for (i = 1; i <= 2*k-2; i++) { long t = link[i]; if (t < 0) E[-t] = w[i]; } return gerepilecopy(av, E); } /* Front-end for ZpX_liftfact: lift the factorization of pol mod p given by L to p^N (if possible) */ GEN polhensellift(GEN pol, GEN L, GEN p, long N) { GEN T = NULL; long i, l, t; pari_sp av = avma; void (*chk)(GEN, const char*); if (typ(pol) != t_POL) pari_err_TYPE("polhensellift",pol); RgX_check_ZXX(pol, "polhensellift"); if (!is_vec_t(typ(L)) || lg(L) < 3) pari_err_TYPE("polhensellift",L); t = typ(p); if (t == t_VEC) /* [p, T] */ { T = gel(p,2); if (typ(T) != t_POL) pari_err_TYPE("polhensellift",pol); RgX_check_ZX(T, "polhensellift"); p = gel(p,1); t = typ(p); } chk = T? RgX_check_ZXX: RgX_check_ZX; if (t != t_INT) pari_err_TYPE("polhensellift",p); if (N < 1) pari_err_DOMAIN("polhensellift", "precision", "<", gen_1,stoi(N)); l = lg(L); L = leafcopy(L); for (i = 1; i < l; i++) { GEN q = gel(L,i); if (typ(q) != t_POL) gel(L,i) = scalar_ZX_shallow(q, varn(pol)); else chk(q, "polhensellift"); } return gerepilecopy(av, ZqX_liftfact(pol, L, T, powiu(p,N), p, N)); } static GEN FqV_roots_from_deg1(GEN x, GEN T, GEN p) { long i,l = lg(x); GEN r = cgetg(l,t_VEC); for (i=1; i 1, e >= 1 * f is a ZX with leading term prime to p. * a is a simple root mod l for all l|p. * Return roots of f mod p^e, as integers (implicitly mod p^e) * STANDARD USE: p is a prime power */ GEN ZpX_liftroot(GEN f, GEN a, GEN p, long e) { pari_sp av = avma; GEN q = p, fr, W; ulong mask; a = modii(a,q); if (e == 1) return a; mask = quadratic_prec_mask(e); fr = FpX_red(f,q); W = Fp_inv(FpX_eval(ZX_deriv(fr), a, q), q); /* 1/f'(a) mod p */ for(;;) { q = sqri(q); if (mask & 1) q = diviiexact(q, p); mask >>= 1; fr = FpX_red(f,q); a = Fp_sub(a, Fp_mul(W, FpX_eval(fr, a,q), q), q); if (mask == 1) return gerepileuptoint(av, a); W = Fp_sub(shifti(W,1), Fp_mul(Fp_sqr(W,q), FpX_eval(ZX_deriv(fr),a,q), q), q); } } GEN ZpX_liftroots(GEN f, GEN S, GEN p, long e) { long i, n = lg(S)-1, d = degpol(f); GEN r; if (n == d) return ZpX_liftroots_full(f, S, powiu(p, e), p, e); r = cgetg(n+1, typ(S)); for (i=1; i <= n; i++) gel(r,i) = ZpX_liftroot(f, gel(S,i), p, e); return r; } GEN ZpXQX_liftroot_vald(GEN f, GEN a, long v, GEN T, GEN p, long e) { pari_sp av = avma, av2; GEN pv = p, q, W, df, Tq, fr, dfr; ulong mask; a = Fq_red(a, T, p); if (e <= v+1) return a; df = RgX_deriv(f); if (v) { pv = powiu(p,v); df = ZXX_Z_divexact(df, pv); } mask = quadratic_prec_mask(e-v); Tq = FpXT_red(T, p); dfr = FpXQX_red(df, Tq, p); W = Fq_inv(FqX_eval(dfr, a, Tq, p), Tq, p); /* 1/f'(a) mod (T,p) */ q = p; av2 = avma; for (;;) { GEN u, fa, qv, q2v, q2, Tq2; q2 = q; q = sqri(q); if (mask & 1) q = diviiexact(q,p); mask >>= 1; if (v) { qv = mulii(q, pv); q2v = mulii(q2, pv); } else { qv = q; q2v = q2; } Tq2 = FpXT_red(T, q2v); Tq = FpXT_red(T, qv); fr = FpXQX_red(f, Tq, qv); fa = FqX_eval(fr, a, Tq, qv); fa = typ(fa)==t_INT? diviiexact(fa,q2v): ZX_Z_divexact(fa, q2v); a = Fq_sub(a, Fq_mul(Fq_mul(W,fa,Tq2,q2v),q2, Tq,qv), Tq, qv); if (mask == 1) return gerepileupto(av, a); dfr = FpXQX_red(df, Tq, q); u = Fq_sub(Fq_mul(W,FqX_eval(dfr,a,Tq,q),Tq,q),gen_1,Tq,q); u = typ(u)==t_INT? diviiexact(u,q2): ZX_Z_divexact(u,q2); W = Fq_sub(W, Fq_mul(Fq_mul(u,W,Tq2,q2),q2, Tq,q),Tq,q); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQX_liftroot, e = %ld", e); gerepileall(av2, 3, &a, &W, &q); } } } GEN ZpXQX_liftroot(GEN f, GEN a, GEN T, GEN p, long e) { return ZpXQX_liftroot_vald(f,a,0,T,p,e); } /* Same as ZpX_liftroot for the polynomial X^n-b*/ GEN Zp_sqrtnlift(GEN b, GEN n, GEN a, GEN p, long e) { pari_sp ltop=avma; GEN q, w, n_1; ulong mask; long pis2 = equalii(n, gen_2)? 1: 0; if (e == 1) return icopy(a); n_1 = subiu(n,1); mask = quadratic_prec_mask(e); w = Fp_inv(pis2 ? shifti(a,1): Fp_mul(n,Fp_pow(a,n_1,p), p), p); q = p; for(;;) { q = sqri(q); if (mask & 1) q = diviiexact(q, p); mask >>= 1; if (lgefint(q) == 3 && lgefint(n) == 3) { ulong Q = uel(q,2), N = uel(n,2); ulong A = umodiu(a, Q); ulong B = umodiu(b, Q); ulong W = umodiu(w, Q); A = Fl_sub(A, Fl_mul(W, Fl_sub(Fl_powu(A,N,Q), B, Q), Q), Q); a = utoi(A); if (mask == 1) break; W = Fl_sub(Fl_add(W,W,Q), Fl_mul(Fl_sqr(W,Q), Fl_mul(N,Fl_powu(A, N-1, Q), Q), Q), Q); w = utoi(W); } else { /* a -= w (a^n - b) */ a = modii(subii(a, mulii(w, subii(Fp_pow(a,n,q),b))), q); if (mask == 1) break; /* w += w - w^2 n a^(n-1)*/ w = subii(shifti(w,1), Fp_mul(Fp_sqr(w,q), pis2? shifti(a,1): mulii(n,Fp_pow(a,n_1,q)), q)); } } return gerepileuptoint(ltop,a); } /* Same as ZpX_liftroot for the polynomial X^2-b */ GEN Zp_sqrtlift(GEN b, GEN a, GEN p, long e) { return Zp_sqrtnlift(b, gen_2, a, p, e); } GEN Zp_sqrt(GEN x, GEN p, long e) { pari_sp av; GEN z; if (absequaliu(p,2)) return Z2_sqrt(x,e); av = avma; z = Fp_sqrt(Fp_red(x, p), p); if (!z) return NULL; if (e > 1) z = Zp_sqrtlift(x, z, p, e); return gerepileuptoint(av, z); } /* Compute (x-1)/(x+1)/p^k */ static GEN ZpXQ_log_to_ath(GEN x, long k, GEN T, GEN p, long e, GEN pe) { pari_sp av = avma; long vT = get_FpX_var(T); GEN bn, bdi; GEN bd = ZX_Z_add(x, gen_1); if (absequaliu(p,2)) /*For p=2, we need to simplify by 2*/ { bn = ZX_shifti(x,-(k+1)); bdi= ZpXQ_invlift(ZX_shifti(bd ,-1), pol_1(vT), T, p, e); } else { bn = ZX_Z_divexact(ZX_Z_sub(x, gen_1),powiu(p,k)); bdi= ZpXQ_invlift(bd, scalarpol(Fp_inv(gen_2,p),vT), T, p, e); } return gerepileupto(av, FpXQ_mul(bn, bdi, T, pe)); } /* Assume p odd, a = 1 [p], return log(a) */ GEN ZpXQ_log(GEN a, GEN T, GEN p, long N) { pari_sp av = avma; pari_timer ti; long is2 = absequaliu(p,2); ulong pp = is2 ? 0: itou_or_0(p); double lp = is2 ? 1: pp ? log2(pp): expi(p); long k = maxss(1 , (long) .5+pow((double)(N>>1)/(lp*lp), 1./3)); GEN ak, s, b, pol; long e = is2 ? N-1: N; long i, l = (e-2)/(2*(k+is2)); GEN pe = powiu(p,e); GEN TNk, pNk = powiu(p,N+k); if( DEBUGLEVEL>=3) timer_start(&ti); TNk = FpX_get_red(get_FpX_mod(T), pNk); ak = FpXQ_pow(a, powiu(p,k), TNk, pNk); if( DEBUGLEVEL>=3) timer_printf(&ti,"FpXQ_pow(%ld)",k); b = ZpXQ_log_to_ath(ak, k, T, p, e, pe); if( DEBUGLEVEL>=3) timer_printf(&ti,"ZpXQ_log_to_ath"); pol= cgetg(l+3,t_POL); pol[1] = evalsigne(1)|evalvarn(0); for(i=0; i<=l; i++) { GEN g; ulong z = 2*i+1; if (pp) { long w = u_lvalrem(z, pp, &z); g = powuu(pp,2*i*k-w); } else g = powiu(p,2*i*k); gel(pol,i+2) = Fp_div(g, utoi(z),pe); } if( DEBUGLEVEL>=3) timer_printf(&ti,"pol(%ld)",l); s = FpX_FpXQ_eval(pol, FpXQ_sqr(b, T, pe), T, pe); if( DEBUGLEVEL>=3) timer_printf(&ti,"FpX_FpXQ_eval"); s = ZX_shifti(FpXQ_mul(b, s, T, pe), 1); return gerepileupto(av, is2? s: FpX_red(s, pe)); } /***********************************************************************/ /** **/ /** Generic quadratic hensel lift over Zp[X] **/ /** **/ /***********************************************************************/ /* q = p^N */ GEN gen_ZpX_Dixon(GEN F, GEN V, GEN q, GEN p, long N, void *E, GEN lin(void *E, GEN F, GEN d, GEN q), GEN invl(void *E, GEN d)) { pari_sp av = avma; long N2, M; GEN VN2, V2, VM, bil; GEN q2, qM; V = FpX_red(V, q); if (N == 1) return invl(E, V); N2 = (N + 1)>>1; M = N - N2; F = FpXT_red(F, q); qM = powiu(p, M); q2 = M == N2? qM: mulii(qM, p); /* q2 = p^N2, qM = p^M, q = q2 * qM */ VN2 = gen_ZpX_Dixon(F, V, q2, p, N2, E, lin, invl); bil = lin(E, F, VN2, q); V2 = ZX_Z_divexact(ZX_sub(V, bil), q2); VM = gen_ZpX_Dixon(F, V2, qM, p, M, E, lin, invl); return gerepileupto(av, FpX_red(ZX_add(VN2, ZX_Z_mul(VM, q2)), q)); } GEN gen_ZpX_Newton(GEN x, GEN p, long n, void *E, GEN eval(void *E, GEN f, GEN q), GEN invd(void *E, GEN V, GEN v, GEN q, long M)) { pari_sp ltop = avma, av; long N = 1, N2, M; long mask; GEN q = p; if (n == 1) return gcopy(x); mask = quadratic_prec_mask(n); av = avma; while (mask > 1) { GEN qM, q2, v, V; N2 = N; N <<= 1; q2 = q; if (mask&1UL) { /* can never happen when q2 = p */ N--; M = N2-1; qM = diviiexact(q2,p); /* > 1 */ q = mulii(qM,q2); } else { M = N2; qM = q2; q = sqri(q2); } /* q2 = p^N2, qM = p^M, q = p^N = q2 * qM */ mask >>= 1; v = eval(E, x, q); V = ZX_Z_divexact(gel(v,1), q2); x = FpX_sub(x, ZX_Z_mul(invd(E, V, v, qM, M), q2), q); if (gc_needed(av, 1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gen_ZpX_Newton"); gerepileall(av, 2, &x, &q); } } return gerepileupto(ltop, x); } struct _ZpXQ_inv { GEN T, a, p ,n; }; static GEN _inv_invd(void *E, GEN V, GEN v, GEN q, long M/*unused*/) { struct _ZpXQ_inv *d = (struct _ZpXQ_inv *) E; GEN Tq = FpXT_red(d->T, q); (void)M; return FpXQ_mul(V, gel(v,2), Tq, q); } static GEN _inv_eval(void *E, GEN x, GEN q) { struct _ZpXQ_inv *d = (struct _ZpXQ_inv *) E; GEN Tq = FpXT_red(d->T, q); GEN f = FpX_Fp_sub(FpXQ_mul(x, FpX_red(d->a, q), Tq, q), gen_1, q); return mkvec2(f, x); } GEN ZpXQ_invlift(GEN a, GEN x, GEN T, GEN p, long e) { struct _ZpXQ_inv d; d.a = a; d.T = T; d.p = p; return gen_ZpX_Newton(x, p, e, &d, _inv_eval, _inv_invd); } GEN ZpXQ_inv(GEN a, GEN T, GEN p, long e) { pari_sp av=avma; GEN ai; if (lgefint(p)==3) { ulong pp = p[2]; ai = Flx_to_ZX(Flxq_inv(ZX_to_Flx(a,pp), ZXT_to_FlxT(T, pp), pp)); } else ai = FpXQ_inv(FpX_red(a,p), FpXT_red(T,p),p); return gerepileupto(av, ZpXQ_invlift(a, ai, T, p, e)); } GEN ZpXQ_div(GEN a, GEN b, GEN T, GEN q, GEN p, long e) { return FpXQ_mul(a, ZpXQ_inv(b, T, p, e), T, q); } GEN ZpXQX_divrem(GEN x, GEN Sp, GEN T, GEN q, GEN p, long e, GEN *pr) { pari_sp av = avma; GEN S = get_FpXQX_mod(Sp); GEN b = leading_coeff(S), bi; GEN S2, Q; if (typ(b)==t_INT) return FpXQX_divrem(x, Sp, T, q, pr); bi = ZpXQ_inv(b, T, p, e); S2 = FqX_Fq_mul_to_monic(S, bi, T, q); Q = FpXQX_divrem(x, S2, T, q, pr); if (pr==ONLY_DIVIDES && !Q) { avma = av; return NULL; } if (pr==ONLY_REM || pr==ONLY_DIVIDES) return gerepileupto(av, Q); Q = FpXQX_FpXQ_mul(Q, bi, T, q); gerepileall(av, 2, &Q, pr); return Q; } GEN ZpXQX_digits(GEN x, GEN B, GEN T, GEN q, GEN p, long e) { pari_sp av = avma; GEN b = leading_coeff(B), bi; GEN B2, P, V, W; long i, lV; if (typ(b)==t_INT) return FpXQX_digits(x, B, T, q); bi = ZpXQ_inv(b, T, p, e); B2 = FqX_Fq_mul_to_monic(B, bi, T, q); V = FpXQX_digits(x, B2, T, q); lV = lg(V)-1; P = FpXQ_powers(bi, lV-1, T, q); W = cgetg(lV+1, t_VEC); for(i=1; i<=lV; i++) gel(W, i) = FpXQX_FpXQ_mul(gel(V,i), gel(P, i), T, q); return gerepileupto(av, W); } struct _ZpXQ_sqrtn { GEN T, a, n, ai; }; static GEN _sqrtn_invd(void *E, GEN V, GEN v, GEN q, long M) { struct _ZpXQ_sqrtn *d = (struct _ZpXQ_sqrtn *) E; GEN Tq = FpX_red(d->T, q), aiq = FpX_red(d->ai, q); (void)M; return FpXQ_mul(FpXQ_mul(V, gel(v,2), Tq, q), aiq, Tq, q); } static GEN _sqrtn_eval(void *E, GEN x, GEN q) { struct _ZpXQ_sqrtn *d = (struct _ZpXQ_sqrtn *) E; GEN Tq = FpX_red(d->T, q); GEN f = FpX_sub(FpXQ_pow(x, d->n, Tq, q), d->a, q); return mkvec2(f, x); } GEN ZpXQ_sqrtnlift(GEN a, GEN n, GEN x, GEN T, GEN p, long e) { struct _ZpXQ_sqrtn d; d.a = a; d.T = T; d.n = n; d.ai = ZpXQ_inv(ZX_Z_mul(a, n),T,p,(e+1)>>1); return gen_ZpX_Newton(x, p, e, &d, _sqrtn_eval, _sqrtn_invd); } static GEN to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; } GEN Zq_sqrtnlift(GEN a, GEN n, GEN x, GEN T, GEN p, long e) { return T? ZpXQ_sqrtnlift(to_ZX(a,varn(T)), n, to_ZX(x,varn(T)), T, p, e) : Zp_sqrtnlift(a, n, x, p, e); } GEN ZpXQ_sqrt(GEN a, GEN T, GEN p, long e) { pari_sp av = avma; GEN z = FpXQ_sqrt(FpX_red(a, p), T, p); if (!z) return NULL; if (e <= 1) return gerepileupto(av, z); return gerepileupto(av, ZpXQ_sqrtnlift(a, gen_2, z, T, p, e)); } GEN ZpX_ZpXQ_liftroot_ea(GEN P, GEN S, GEN T, GEN p, long n, void *E, int early(void *E, GEN x, GEN q)) { pari_sp ltop = avma, av; long N, r; long mask; GEN q2, q, W, Q, Tq2, Tq, Pq; pari_timer ti; T = FpX_get_red(T, powiu(p, n)); if (n == 1) return gcopy(S); mask = quadratic_prec_mask(n); av = avma; q2 = p; q = sqri(p); mask >>= 1; N = 2; if (DEBUGLEVEL > 3) timer_start(&ti); Tq = FpXT_red(T,q); Tq2 = FpXT_red(Tq,q2); Pq = FpX_red(P,q); W = FpXQ_inv(FpX_FpXQ_eval(FpX_deriv(P,q2), S, Tq2, q2), Tq2, q2); Q = ZX_Z_divexact(FpX_FpXQ_eval(Pq, S, Tq, q), q2); r = brent_kung_optpow(degpol(P), 4, 3); if (DEBUGLEVEL > 3) err_printf("ZpX_ZpXQ_liftroot: lifting to prec %ld\n",n); for (;;) { GEN H, Sq, Wq, Spow, dP, qq, Pqq, Tqq; H = FpXQ_mul(W, Q, Tq2, q2); Sq = FpX_sub(S, ZX_Z_mul(H, q2), q); if (DEBUGLEVEL > 3) timer_printf(&ti,"ZpX_ZpXQ_liftroot: reaching prec %ld",N); if (mask==1 || (early && early(E, Sq, q))) return gerepileupto(ltop, Sq); qq = sqri(q); N <<= 1; if (mask&1UL) { qq = diviiexact(qq, p); N--; } mask >>= 1; Pqq = FpX_red(P, qq); Tqq = FpXT_red(T, qq); Spow = FpXQ_powers(Sq, r, Tqq, qq); Q = ZX_Z_divexact(FpX_FpXQV_eval(Pqq, Spow, Tqq, qq), q); dP = FpX_FpXQV_eval(FpX_deriv(Pq, q), FpXV_red(Spow, q), Tq, q); Wq = ZX_Z_divexact(FpX_Fp_sub(FpXQ_mul(W, dP, Tq, q), gen_1, q), q2); Wq = ZX_Z_mul(FpXQ_mul(W, Wq, Tq2, q2), q2); Wq = FpX_sub(W, Wq, q); S = Sq; W = Wq; q2 = q; q = qq; Tq2 = Tq; Tq = Tqq; Pq = Pqq; if (gc_needed(av, 1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpX_ZpXQ_Newton"); gerepileall(av, 8, &S, &W, &Q, &Tq2, &Tq, &Pq, &q, &q2); } } } GEN ZpX_ZpXQ_liftroot(GEN P, GEN S, GEN T, GEN p, long n) { return ZpX_ZpXQ_liftroot_ea(P, S, T, p, n, NULL, NULL); } GEN ZpX_Frobenius(GEN T, GEN p, long e) { return ZpX_ZpXQ_liftroot(get_FpX_mod(T), FpX_Frobenius(T, p), T, p, e); } GEN ZpXQM_prodFrobenius(GEN M, GEN T, GEN p, long e) { pari_sp av = avma; GEN xp = ZpX_Frobenius(T, p, e); GEN z = FpXQM_autsum(mkvec2(xp, M), get_FpX_degree(T), T, powiu(p,e)); return gerepilecopy(av, gel(z,2)); } pari-2.11.2/src/basemath/lfunutils.c0000644000175000017500000020601413457576465015753 0ustar billbill/* Copyright (C) 2015 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** L-functions: Applications **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" static GEN tag(GEN x, long t) { return mkvec2(mkvecsmall(t), x); } /* v a t_VEC of length > 1 */ static int is_tagged(GEN v) { GEN T = gel(v,1); return (typ(T)==t_VEC && lg(T)==3 && typ(gel(T,1))==t_VECSMALL); } static void checkldata(GEN ldata) { GEN vga, w, N; #if 0 /* assumed already checked and true */ long l = lg(ldata); if (typ(ldata)!=t_VEC || l < 7 || l > 8 || !is_tagged(ldata)) pari_err_TYPE("checkldata", ldata); #endif vga = ldata_get_gammavec(ldata); if (typ(vga) != t_VEC) pari_err_TYPE("checkldata [gammavec]",vga); w = gel(ldata, 4); /* FIXME */ switch(typ(w)) { case t_INT: break; case t_VEC: if (lg(w) == 3 && typ(gel(w,1)) == t_INT) break; default: pari_err_TYPE("checkldata [weight]",w); } N = ldata_get_conductor(ldata); if (typ(N) != t_INT) pari_err_TYPE("checkldata [conductor]",N); } /* data may be either an object (polynomial, elliptic curve, etc...) * or a description vector [an,sd,Vga,k,conductor,rootno,{poles}]. */ GEN lfuncreate(GEN data) { long lx = lg(data); if (typ(data)==t_VEC && (lx == 7 || lx == 8)) { GEN ldata; if (is_tagged(data)) ldata = gcopy(data); else { /* tag first component as t_LFUN_GENERIC */ ldata = gcopy(data); gel(ldata, 1) = tag(gel(ldata,1), t_LFUN_GENERIC); if (typ(gel(ldata, 2))!=t_INT) gel(ldata, 2) = tag(gel(ldata,2), t_LFUN_GENERIC); } checkldata(ldata); return ldata; } return lfunmisc_to_ldata(data); } /********************************************************************/ /** Simple constructors **/ /********************************************************************/ static GEN vecan_conj(GEN an, long n, long prec) { GEN p1 = ldata_vecan(gel(an,1), n, prec); return typ(p1) == t_VEC? conj_i(p1): p1; } static GEN vecan_mul(GEN an, long n, long prec) { GEN p1 = ldata_vecan(gel(an,1), n, prec); GEN p2 = ldata_vecan(gel(an,2), n, prec); if (typ(p1) == t_VECSMALL) p1 = vecsmall_to_vec(p1); if (typ(p2) == t_VECSMALL) p2 = vecsmall_to_vec(p2); return dirmul(p1, p2); } static GEN lfunconvol(GEN a1, GEN a2) { return tag(mkvec2(a1, a2), t_LFUN_MUL); } static GEN vecan_div(GEN an, long n, long prec) { GEN p1 = ldata_vecan(gel(an,1), n, prec); GEN p2 = ldata_vecan(gel(an,2), n, prec); if (typ(p1) == t_VECSMALL) p1 = vecsmall_to_vec(p1); if (typ(p2) == t_VECSMALL) p2 = vecsmall_to_vec(p2); return dirdiv(p1, p2); } static GEN lfunconvolinv(GEN a1, GEN a2) { return tag(mkvec2(a1,a2), t_LFUN_DIV); } static GEN lfunconj(GEN a1) { return tag(mkvec(a1), t_LFUN_CONJ); } static GEN lfuncombdual(GEN fun(GEN, GEN), GEN ldata1, GEN ldata2) { GEN a1 = ldata_get_an(ldata1), a2 = ldata_get_an(ldata2); GEN b1 = ldata_get_dual(ldata1), b2 = ldata_get_dual(ldata2); if (typ(b1)==t_INT && typ(b2)==t_INT) return utoi(signe(b1) && signe(b2)); else { if (typ(b1)==t_INT) b1 = signe(b1) ? lfunconj(a1): a1; if (typ(b2)==t_INT) b2 = signe(b2) ? lfunconj(a2): a2; return fun(b1, b2); } } static GEN vecan_twist(GEN an, long n, long prec) { GEN p1 = ldata_vecan(gel(an,1), n, prec); GEN p2 = ldata_vecan(gel(an,2), n, prec); long i; GEN V; if (typ(p1) == t_VECSMALL) p1 = vecsmall_to_vec(p1); if (typ(p2) == t_VECSMALL) p2 = vecsmall_to_vec(p2); V = cgetg(n+1, t_VEC); for(i = 1; i <= n ; i++) gel(V, i) = gmul(gel(p1, i), gel(p2, i)); return V; } static GEN lfunmulpoles(GEN ldata1, GEN ldata2, long bitprec) { long k = ldata_get_k(ldata1), l, j; GEN r1 = ldata_get_residue(ldata1); GEN r2 = ldata_get_residue(ldata2), r; if (r1 && typ(r1) != t_VEC) r1 = mkvec(mkvec2(stoi(k), r1)); if (r2 && typ(r2) != t_VEC) r2 = mkvec(mkvec2(stoi(k), r2)); if (!r1) { if (!r2) return NULL; r1 = lfunrtopoles(r2); } else { r1 = lfunrtopoles(r1); if (r2) r1 = setunion(r1, lfunrtopoles(r2)); } l = lg(r1); r = cgetg(l, t_VEC); for (j = 1; j < l; j++) { GEN be = gel(r1,j); GEN z1 = lfun(ldata1,be,bitprec), z2 = lfun(ldata2,be,bitprec); if (typ(z1) == t_SER && typ(z2) == t_SER) { /* pole of both, recompute to needed seriesprecision */ long e = valp(z1) + valp(z2); GEN b = RgX_to_ser(deg1pol_shallow(gen_1, be, 0), 3-e); z1 = lfun(ldata1,b,bitprec); z2 = lfun(ldata2,b,bitprec); } gel(r,j) = mkvec2(be, gmul(z1, z2)); } return r; } GEN lfunmul(GEN ldata1, GEN ldata2, long bitprec) { pari_sp ltop = avma; GEN r, N, Vga, eno, a1a2, b1b2, LD; long k; ldata1 = lfunmisc_to_ldata_shallow(ldata1); ldata2 = lfunmisc_to_ldata_shallow(ldata2); k = ldata_get_k(ldata1); if (ldata_get_k(ldata2) != k) pari_err_OP("lfunmul [weight]",ldata1, ldata2); r = lfunmulpoles(ldata1, ldata2, bitprec); N = gmul(ldata_get_conductor(ldata1), ldata_get_conductor(ldata2)); Vga = shallowconcat(ldata_get_gammavec(ldata1), ldata_get_gammavec(ldata2)); Vga = sort(Vga); eno = gmul(ldata_get_rootno(ldata1), ldata_get_rootno(ldata2)); a1a2 = lfunconvol(ldata_get_an(ldata1), ldata_get_an(ldata2)); b1b2 = lfuncombdual(lfunconvol, ldata1, ldata2); LD = mkvecn(7, a1a2, b1b2, Vga, stoi(k), N, eno, r); if (!r) setlg(LD,7); return gerepilecopy(ltop, LD); } static GEN lfundivpoles(GEN ldata1, GEN ldata2, long bitprec) { long k = ldata_get_k(ldata1), i, j, l; GEN r1 = ldata_get_residue(ldata1); GEN r2 = ldata_get_residue(ldata2), r; if (r1 && typ(r1) != t_VEC) r1 = mkvec(mkvec2(stoi(k), r1)); if (r2 && typ(r2) != t_VEC) r2 = mkvec(mkvec2(stoi(k), r2)); if (!r1) return NULL; r1 = lfunrtopoles(r1); l = lg(r1); r = cgetg(l, t_VEC); for (i = j = 1; j < l; j++) { GEN be = gel(r1,j); GEN z = gdiv(lfun(ldata1,be,bitprec), lfun(ldata2,be,bitprec)); if (valp(z) < 0) gel(r,i++) = mkvec2(be, z); } if (i == 1) return NULL; setlg(r, i); return r; } GEN lfundiv(GEN ldata1, GEN ldata2, long bitprec) { pari_sp ltop = avma; GEN r, N, v, v1, v2, eno, a1a2, b1b2, LD, eno2; long k, j, j1, j2, l1, l2; ldata1 = lfunmisc_to_ldata_shallow(ldata1); ldata2 = lfunmisc_to_ldata_shallow(ldata2); k = ldata_get_k(ldata1); if (ldata_get_k(ldata2) != k) pari_err_OP("lfundiv [weight]",ldata1, ldata2); r = lfundivpoles(ldata1, ldata2, bitprec); N = gdiv(ldata_get_conductor(ldata1), ldata_get_conductor(ldata2)); if (typ(N) != t_INT) pari_err_OP("lfundiv [conductor]",ldata1, ldata2); a1a2 = lfunconvolinv(ldata_get_an(ldata1), ldata_get_an(ldata2)); b1b2 = lfuncombdual(lfunconvolinv, ldata1, ldata2); eno2 = ldata_get_rootno(ldata2); eno = isintzero(eno2)? gen_0: gdiv(ldata_get_rootno(ldata1), eno2); v1 = shallowcopy(ldata_get_gammavec(ldata1)); v2 = ldata_get_gammavec(ldata2); l1 = lg(v1); l2 = lg(v2); for (j2 = 1; j2 < l2; j2++) { for (j1 = 1; j1 < l1; j1++) if (gel(v1,j1) && gequal(gel(v1,j1), gel(v2,j2))) { gel(v1,j1) = NULL; break; } if (j1 == l1) pari_err_OP("lfundiv [Vga]",ldata1, ldata2); } v = cgetg(l1-l2+1, t_VEC); for (j1 = j = 1; j1 < l1; j1++) if (gel(v1, j1)) gel(v,j++) = gel(v1,j1); LD = mkvecn(7, a1a2, b1b2, v, stoi(k), N, eno, r); if (!r) setlg(LD,7); return gerepilecopy(ltop, LD); } static GEN gamma_imagchi(GEN gam, long w) { long i, j, k=1, l; GEN g = cgetg_copy(gam, &l); gam = shallowcopy(gam); for (i = l-1; i>=1; i--) { GEN al = gel(gam, i); if (al) { GEN N = gaddsg(w,gmul2n(real_i(al),1)); if (gcmpgs(N,2) > 0) { GEN bl = gsubgs(al, 1); for (j=1; j < i; j++) if (gel(gam,j) && gequal(gel(gam,j), bl)) { gel(gam,j) = NULL; break; } if (j==i) return NULL; gel(g, k++) = al; gel(g, k++) = bl; } else if (gequal0(N)) gel(g, k++) = gaddgs(al, 1); else if (gequal1(N)) gel(g, k++) = gsubgs(al, 1); else return NULL; } } return sort(g); } GEN lfuntwist(GEN ldata1, GEN chi) { pari_sp ltop = avma; GEN L, N, N1, N2, a, a1, a2, b, b1, b2, gam, gam1, gam2; GEN ldata2; long d1, k, t; ldata1 = lfunmisc_to_ldata_shallow(ldata1); ldata2 = lfunmisc_to_ldata_shallow(chi); t = ldata_get_type(ldata2); if (t == t_LFUN_ZETA) return gerepilecopy(ltop, ldata1); if (t != t_LFUN_CHIZ && t != t_LFUN_KRONECKER) pari_err_TYPE("lfuntwist", chi); N1 = ldata_get_conductor(ldata1); N2 = ldata_get_conductor(ldata2); if (!gequal1(gcdii(N1, N2))) pari_err_IMPL("lfuntwist (conductors not coprime)"); k = ldata_get_k(ldata1); d1 = ldata_get_degree(ldata1); N = gmul(N1, gpowgs(N2, d1)); gam1 = ldata_get_gammavec(ldata1); gam2 = ldata_get_gammavec(ldata2); if (gequal0(gel(gam2, 1))) gam = gam1; else gam = gamma_imagchi(ldata_get_gammavec(ldata1), k-1); if (!gam) pari_err_IMPL("lfuntwist (gammafactors)"); a1 = ldata_get_an(ldata1); a2 = ldata_get_an(ldata2); b1 = ldata_get_dual(ldata1); b2 = ldata_get_dual(ldata2); a = tag(mkvec2(a1, a2), t_LFUN_TWIST); if (typ(b1)==t_INT) b = signe(b1) && signe(b2) ? gen_0: gen_1; else b = tag(mkvec2(b1,lfunconj(a2)), t_LFUN_TWIST); L = mkvecn(6, a, b, gam, stoi(k), N, gen_0); return gerepilecopy(ltop, L); } /*****************************************************************/ /* L-series from closure */ /*****************************************************************/ static GEN localfactor(void *E, GEN p, long n) { GEN s = closure_callgen2((GEN)E, p, utoi(n)); return direuler_factor(s, n); } static GEN vecan_closure(GEN a, long L, long prec) { long ta = typ(a); GEN gL, Sbad = NULL; if (!L) return cgetg(1,t_VEC); if (ta == t_VEC) { long l = lg(a); if (l == 1) pari_err_TYPE("vecan_closure", a); ta = typ(gel(a,1)); /* regular vector, return it */ if (ta != t_CLOSURE) return vecslice(a, 1, minss(L,l-1)); if (l != 3) pari_err_TYPE("vecan_closure", a); Sbad = gel(a,2); if (typ(Sbad) != t_VEC) pari_err_TYPE("vecan_closure", a); a = gel(a,1); } else if (ta != t_CLOSURE) pari_err_TYPE("vecan_closure", a); push_localprec(prec); gL = stoi(L); switch(closure_arity(a)) { case 2: a = direuler_bad((void*)a, localfactor, gen_2, gL,gL, Sbad); break; case 1: a = closure_callgen1(a, gL); if (typ(a) != t_VEC) pari_err_TYPE("vecan_closure", a); break; default: pari_err_TYPE("vecan_closure [wrong arity]", a); a = NULL; /*LCOV_EXCL_LINE*/ } pop_localprec(); return a; } /*****************************************************************/ /* L-series of Dirichlet characters. */ /*****************************************************************/ static GEN lfunzeta(void) { GEN zet = mkvecn(7, NULL, gen_0, NULL, gen_1, gen_1, gen_1, gen_1); gel(zet,1) = tag(gen_1, t_LFUN_ZETA); gel(zet,3) = mkvec(gen_0); return zet; } static GEN lfunzetainit(GEN dom, long der, long bitprec) { return lfuninit(lfunzeta(), dom, der, bitprec); } static GEN vecan_Kronecker(GEN D, long n) { GEN v = cgetg(n+1, t_VECSMALL); ulong Du = itou_or_0(D); long i, id, d = Du ? minuu(Du, n): n; for (i = 1; i <= d; i++) v[i] = krois(D,i); for (id = i; i <= n; i++,id++) /* periodic mod d */ { if (id > d) id = 1; gel(v, i) = gel(v, id); } return v; } static GEN lfunchiquad(GEN D) { GEN r; if (equali1(D)) return lfunzeta(); if (!isfundamental(D)) pari_err_TYPE("lfunchiquad [not primitive]", D); r = mkvecn(6, NULL, gen_0, NULL, gen_1, NULL, gen_1); gel(r,1) = tag(icopy(D), t_LFUN_KRONECKER); gel(r,3) = mkvec(signe(D) < 0? gen_1: gen_0); gel(r,5) = mpabs(D); return r; } /* Begin Hecke characters. Here a character is assumed to be given by a vector on the generators of the ray class group clgp of CL_m(K). If clgp = [h,[d1,...,dk],[g1,...,gk]] with dk|...|d2|d1, a character chi is given by [a1,a2,...,ak] such that chi(gi)=\zeta_di^ai. */ /* Value of CHI on x, coprime to bnr.mod */ static GEN chigeneval(GEN logx, GEN nchi, GEN z, long prec) { pari_sp av = avma; GEN d = gel(nchi,1); GEN e = FpV_dotproduct(gel(nchi,2), logx, d); if (typ(z) != t_VEC) return gerepileupto(av, gpow(z, e, prec)); else { ulong i = itou(e); avma = av; return gel(z, i+1); } } /* return x + yz; y != 0; z = 0,1 "often"; x = 0 "often" */ static GEN gaddmul(GEN x, GEN y, GEN z) { pari_sp av; if (typ(z) == t_INT) { if (!signe(z)) return x; if (equali1(z)) return gadd(x,y); } if (isintzero(x)) return gmul(y,z); av = avma; return gerepileupto(av, gadd(x, gmul(y,z))); } static GEN vecan_chiZ(GEN an, long n, long prec) { forprime_t iter; GEN G = gel(an,1); GEN nchi = gel(an,2), gord = gel(nchi,1), z; GEN gp = cgetipos(3), v = vec_ei(n, 1); GEN N = znstar_get_N(G); long ord = itos_or_0(gord); ulong Nu = itou_or_0(N); long i, id, d = Nu ? minuu(Nu, n): n; ulong p; if (ord && n > (ord>>4)) { GEN w = ncharvecexpo(G, nchi); z = grootsof1(ord, prec); for (i = 1; i <= d; i++) if (w[i] >= 0) gel(v, i) = gel(z, w[i]+1); } else { z = rootsof1_cx(gord, prec); u_forprime_init(&iter, 2, d); while ((p = u_forprime_next(&iter))) { GEN ch; ulong k; if (!umodiu(N,p)) continue; gp[2] = p; ch = chigeneval(znconreylog(G, gp), nchi, z, prec); gel(v, p) = ch; for (k = 2*p; k <= (ulong)d; k += p) gel(v, k) = gaddmul(gel(v, k), ch, gel(v, k/p)); } } for (id = i = d+1; i <= n; i++,id++) /* periodic mod d */ { if (id > d) id = 1; gel(v, i) = gel(v, id); } return v; } static GEN vecan_chigen(GEN an, long n, long prec) { forprime_t iter; GEN bnr = gel(an,1), nf = bnr_get_nf(bnr); GEN nchi = gel(an,2), gord = gel(nchi,1), z; GEN gp = cgetipos(3), v = vec_ei(n, 1); GEN N = gel(bnr_get_mod(bnr), 1), NZ = gcoeff(N,1,1); long ord = itos_or_0(gord); ulong p; if (ord && n > (ord>>4)) z = grootsof1(ord, prec); else z = rootsof1_cx(gord, prec); if (nf_get_degree(nf) == 1) { ulong Nu = itou_or_0(NZ); long i, id, d = Nu ? minuu(Nu, n): n; u_forprime_init(&iter, 2, d); while ((p = u_forprime_next(&iter))) { GEN ch; ulong k; if (!umodiu(NZ,p)) continue; gp[2] = p; ch = chigeneval(isprincipalray(bnr,gp), nchi, z, prec); gel(v, p) = ch; for (k = 2*p; k <= (ulong)d; k += p) gel(v, k) = gaddmul(gel(v, k), ch, gel(v, k/p)); } for (id = i = d+1; i <= n; i++,id++) /* periodic mod d */ { if (id > d) id = 1; gel(v, i) = gel(v, id); } } else { GEN BOUND = stoi(n); u_forprime_init(&iter, 2, n); while ((p = u_forprime_next(&iter))) { GEN L; long j; int check = !umodiu(NZ,p); gp[2] = p; L = idealprimedec_limit_norm(nf, gp, BOUND); for (j = 1; j < lg(L); j++) { GEN pr = gel(L, j), ch; ulong k, q; if (check && idealval(nf, N, pr)) continue; ch = chigeneval(isprincipalray(bnr,pr), nchi, z, prec); q = upr_norm(pr); gel(v, q) = gadd(gel(v, q), ch); for (k = 2*q; k <= (ulong)n; k += q) gel(v, k) = gaddmul(gel(v, k), ch, gel(v, k/q)); } } } return v; } static GEN lfunzetak_i(GEN T); static GEN vec01(long r1, long r2) { long d = r1+r2, i; GEN v = cgetg(d+1,t_VEC); for (i = 1; i <= r1; i++) gel(v,i) = gen_0; for ( ; i <= d; i++) gel(v,i) = gen_1; return v; } /* G is a bid of nftyp typ_BIDZ */ static GEN lfunchiZ(GEN G, GEN chi) { pari_sp av = avma; GEN sig = NULL; GEN N = bid_get_ideal(G), nchi, r; int real; if (typ(N) != t_INT) pari_err_TYPE("lfunchiZ", G); if (equali1(N)) return lfunzeta(); if (typ(chi) != t_COL) chi = znconreylog(G,chi); N = znconreyconductor(G, chi, &chi); if (typ(N) != t_INT) { if (equali1(gel(N,1))) { avma = av; return lfunzeta(); } G = znstar0(N, 1); N = gel(N,1); } /* chi now primitive on G */ switch(itou_or_0(zncharorder(G, chi))) { case 1: avma = av; return lfunzeta(); case 2: if (zncharisodd(G,chi)) N = negi(N); return gerepileupto(av, lfunchiquad(N)); } sig = mkvec( zncharisodd(G, chi)? gen_1: gen_0 ); nchi = znconreylog_normalize(G, chi); real = abscmpiu(gel(nchi,1), 2) <= 0; r = mkvecn(6, tag(mkvec2(G,nchi), t_LFUN_CHIZ), real? gen_0: gen_1, sig, gen_1, N, gen_0); return gerepilecopy(av, r); } static GEN lfunchigen(GEN bnr, GEN CHI) { pari_sp av = avma; GEN v; GEN N, sig, Ldchi, nf, nchi, NN; long r1, r2, n1; int real; if (nftyp(bnr) == typ_BIDZ) return lfunchiZ(bnr, CHI); v = bnrconductor_i(bnr, CHI, 2); bnr = gel(v,2); CHI = gel(v,3); /* now CHI is primitive wrt bnr */ nf = bnr_get_nf(bnr); N = bnr_get_mod(bnr); n1 = lg(vec01_to_indices(gel(N,2))) - 1; /* vecsum(N[2]) */ N = gel(N,1); NN = mulii(idealnorm(nf, N), absi_shallow(nf_get_disc(nf))); if (equali1(NN)) return gerepileupto(av, lfunzeta()); if (ZV_equal0(CHI)) return gerepilecopy(av, lfunzetak_i(bnr)); nf_get_sign(nf, &r1, &r2); sig = vec01(r1+r2-n1, r2+n1); nchi = char_normalize(CHI, cyc_normalize(bnr_get_cyc(bnr))); real = abscmpiu(gel(nchi,1), 2) <= 0; Ldchi = mkvecn(6, tag(mkvec2(bnr, nchi), t_LFUN_CHIGEN), real? gen_0: gen_1, sig, gen_1, NN, gen_0); return gerepilecopy(av, Ldchi); } /* Find all characters of clgp whose kernel contain group given by HNF H. * Set *pcnj[i] if chi[i] is not real */ static GEN chigenkerfind(GEN bnr, GEN H, GEN *pcnj) { GEN res, cnj, L = bnrchar(bnr, H, NULL), cyc = bnr_get_cyc(bnr); long i, k, l = lg(L); res = cgetg(l, t_VEC); *pcnj = cnj = cgetg(l, t_VECSMALL); for (i = k = 1; i < l; i++) { GEN chi = gel(L,i), c = charconj(cyc, chi); long fl = ZV_cmp(c, chi); if (fl < 0) continue; /* keep one char in pair of conjugates */ gel(res, k) = chi; cnj[k] = fl; k++; } setlg(cnj, k); setlg(res, k); return res; } static GEN lfunzetak_i(GEN T) { GEN Vga, N, nf, bnf = checkbnf_i(T), r = gen_0/*unknown*/; long r1, r2; if (bnf) nf = bnf_get_nf(bnf); else { nf = checknf_i(T); if (!nf) nf = T = nfinit(T, DEFAULTPREC); } nf_get_sign(nf,&r1,&r2); N = absi_shallow(nf_get_disc(nf)); if (bnf) { GEN h = bnf_get_no(bnf); GEN R = bnf_get_reg(bnf); long prec = nf_get_prec(nf); r = gdiv(gmul(mulir(shifti(h, r1+r2), powru(mppi(prec), r2)), R), mulur(bnf_get_tuN(bnf), gsqrt(N, prec))); } Vga = vec01(r1+r2,r2); return mkvecn(7, tag(T,t_LFUN_NF), gen_0, Vga, gen_1, N, gen_1, r); } static GEN lfunzetak(GEN T) { pari_sp ltop = avma; return gerepilecopy(ltop, lfunzetak_i(T)); } /* bnf = NULL: base field = Q */ GEN lfunabelianrelinit(GEN nfabs, GEN bnf, GEN polrel, GEN dom, long der, long bitprec) { pari_sp ltop = avma; GEN cond, chi, cnj, res, bnr, M, domain; long l, i; long v = -1; if (bnf) bnf = checkbnf(bnf); else { v = fetch_var(); bnf = Buchall(pol_x(v), 0, nbits2prec(bitprec)); } if (typ(polrel) != t_POL) pari_err_TYPE("lfunabelianrelinit", polrel); cond = rnfconductor(bnf, polrel); chi = chigenkerfind(gel(cond,2), gel(cond,3), &cnj); bnr = Buchray(bnf, gel(cond,1), nf_INIT); l = lg(chi); res = cgetg(l, t_VEC); for (i = 1; i < l; ++i) { GEN L = lfunchigen(bnr, gel(chi,i)); gel(res, i) = lfuninit(L, dom, der, bitprec); } if (v >= 0) delete_var(); M = mkvec3(res, const_vecsmall(l-1, 1), cnj); domain = mkvec2(dom, mkvecsmall2(der, bitprec)); return gerepilecopy(ltop, lfuninit_make(t_LDESC_PRODUCT, lfunzetak_i(nfabs), M, domain)); } /*****************************************************************/ /* Dedekind zeta functions */ /*****************************************************************/ static GEN dirzetak0(GEN nf, ulong N) { GEN vect, c, c2, T = nf_get_pol(nf), index = nf_get_index(nf); pari_sp av = avma, av2; const ulong SQRTN = usqrt(N); ulong i, p, lx; long court[] = {evaltyp(t_INT)|_evallg(3), evalsigne(1)|evallgefint(3),0}; forprime_t S; c = cgetalloc(t_VECSMALL, N+1); c2 = cgetalloc(t_VECSMALL, N+1); c2[1] = c[1] = 1; for (i=2; i<=N; i++) c[i] = 0; u_forprime_init(&S, 2, N); av2 = avma; while ( (p = u_forprime_next(&S)) ) { avma = av2; if (umodiu(index, p)) /* p does not divide index */ vect = gel(Flx_degfact(ZX_to_Flx(T,p), p),1); else { court[2] = p; vect = idealprimedec_degrees(nf,court); } lx = lg(vect); if (p <= SQRTN) for (i=1; i N) break; memcpy(c2 + 2, c + 2, (N-1)*sizeof(long)); /* c2[i] <- c[i] + sum_{k = 1}^{v_q(i)} c[i/q^k] for all i <= N */ for (qn = q; qn <= N; qn *= q) { ulong k0 = N/qn, k, k2; /* k2 = k*qn */ for (k = k0, k2 = k*qn; k > 0; k--, k2 -=qn) c2[k2] += c[k]; if (q > k0) break; /* <=> q*qn > N */ } swap(c, c2); } else /* p > sqrt(N): simpler */ for (i=1; i 1) break; /* c2[i] <- c[i] + sum_{k = 1}^{v_q(i)} c[i/q^k] for all i <= N */ for (k = N/p, k2 = k*p; k > 0; k--, k2 -= p) c[k2] += c[k]; } } avma = av; pari_free(c2); return c; } GEN dirzetak(GEN nf, GEN b) { GEN z, c; long n; if (typ(b) != t_INT) pari_err_TYPE("dirzetak",b); if (signe(b) <= 0) return cgetg(1,t_VEC); nf = checknf(nf); n = itou_or_0(b); if (!n) pari_err_OVERFLOW("dirzetak"); c = dirzetak0(nf, n); z = vecsmall_to_vec(c); pari_free(c); return z; } static GEN linit_get_mat(GEN linit) { if (linit_get_type(linit)==t_LDESC_PRODUCT) return lfunprod_get_fact(linit_get_tech(linit)); else return mkvec3(mkvec(linit), mkvecsmall(1), mkvecsmall(0)); } static GEN lfunproduct(GEN ldata, GEN linit1, GEN linit2, GEN domain) { GEN M1 = linit_get_mat(linit1); GEN M2 = linit_get_mat(linit2); GEN M3 = mkvec3(shallowconcat(gel(M1, 1), gel(M2, 1)), vecsmall_concat(gel(M1, 2), gel(M2, 2)), vecsmall_concat(gel(M1, 3), gel(M2, 3))); return lfuninit_make(t_LDESC_PRODUCT, ldata, M3, domain); } static GEN lfunzetakinit_raw(GEN T, GEN dom, long der, long bitprec) { pari_sp ltop = avma; GEN ldata = lfunzetak_i(T); return gerepileupto(ltop, lfuninit(ldata, dom, der, bitprec)); } static GEN lfunzetakinit_quotient(GEN nf, GEN polk, GEN dom, long der, long bitprec) { pari_sp av = avma; GEN ak, an, nfk, Vga, ldata, N, Lk, LKk, domain; long r1k, r2k, r1, r2; nf_get_sign(nf,&r1,&r2); nfk = nfinit(polk, nbits2prec(bitprec)); Lk = lfunzetakinit(nfk, dom, der, 0, bitprec); /* zeta_k */ nf_get_sign(nfk,&r1k,&r2k); Vga = vec01((r1+r2) - (r1k+r2k), r2-r2k); N = absi_shallow(diviiexact(nf_get_disc(nf), nf_get_disc(nfk))); ak = nf_get_degree(nf)==1 ? tag(gen_1, t_LFUN_ZETA): tag(nfk, t_LFUN_NF); an = tag(mkvec2(tag(nf,t_LFUN_NF), ak), t_LFUN_DIV); ldata = mkvecn(6, an, gen_0, Vga, gen_1, N, gen_1); LKk = lfuninit(ldata, dom, der, bitprec); /* zeta_K/zeta_k */ domain = mkvec2(dom, mkvecsmall2(der, bitprec)); return gerepilecopy(av, lfunproduct(lfunzetak_i(nf), Lk, LKk, domain)); } static GEN lfunzetakinit_artin(GEN nf, GEN gal, GEN dom, long der, long bitprec); static GEN lfunzetakinit_Galois(GEN nf, GEN gal, GEN dom, long der, long bitprec) { GEN grp = galois_group(gal); if (group_isabelian(grp)) return lfunabelianrelinit(nf, NULL, gal_get_pol(gal), dom, der, bitprec); else return lfunzetakinit_artin(nf, gal, dom, der, bitprec); } GEN lfunzetakinit(GEN NF, GEN dom, long der, long flag, long bitprec) { GEN nf = checknf(NF); GEN G, nfs, sbg; long lf, d = nf_get_degree(nf); if (d == 1) return lfunzetainit(dom, der, bitprec); G = galoisinit(nf, NULL); if (!isintzero(G)) return lfunzetakinit_Galois(nf, G, dom, der, bitprec); nfs = nfsubfields(nf, 0); lf = lg(nfs)-1; sbg = gmael(nfs,lf-1,1); if (flag && d > 4*degpol(sbg)) return lfunzetakinit_raw(nf, dom, der, bitprec); return lfunzetakinit_quotient(nf, sbg, dom, der, bitprec); } /***************************************************************/ /* Elliptic Curves and Modular Forms */ /***************************************************************/ static GEN lfunellnf(GEN e) { pari_sp av = avma; GEN ldata = cgetg(7, t_VEC), nf = ellnf_get_nf(e); GEN N = gel(ellglobalred(e), 1); long n = nf_get_degree(nf); gel(ldata, 1) = tag(e, t_LFUN_ELL); gel(ldata, 2) = gen_0; gel(ldata, 3) = vec01(n, n); gel(ldata, 4) = gen_2; gel(ldata, 5) = mulii(idealnorm(nf,N), sqri(nf_get_disc(nf))); gel(ldata, 6) = stoi(ellrootno_global(e)); return gerepilecopy(av, ldata); } static GEN lfunellQ(GEN e) { pari_sp av = avma; GEN ldata = cgetg(7, t_VEC); gel(ldata, 1) = tag(ellanal_globalred(e, NULL), t_LFUN_ELL); gel(ldata, 2) = gen_0; gel(ldata, 3) = mkvec2(gen_0, gen_1); gel(ldata, 4) = gen_2; gel(ldata, 5) = ellQ_get_N(e); gel(ldata, 6) = stoi(ellrootno_global(e)); return gerepilecopy(av, ldata); /* ellanal_globalred not gerepile-safe */ } static GEN lfunell(GEN e) { long t = ell_get_type(e); switch(t) { case t_ELL_Q: return lfunellQ(e); case t_ELL_NF:return lfunellnf(e); } pari_err_TYPE("lfun",e); return NULL; /*LCOV_EXCL_LINE*/ } static GEN ellsympow_gamma(long m) { GEN V = cgetg(m+2, t_VEC); long i = 1, j; if (!odd(m)) gel(V, i++) = stoi(-2*(m>>2)); for (j = (m+1)>>1; j > 0; i+=2, j--) { gel(V,i) = stoi(1-j); gel(V,i+1) = stoi(1-j+1); } return V; } static GEN ellsympow_trace(GEN p, GEN t, long m) { long k, n = m >> 1; GEN tp = gpowers0(sqri(t), n, odd(m)? t: NULL); GEN pp = gen_1, b = gen_1, r = gel(tp,n+1); for(k=1; k<=n; k++) { GEN s; pp = mulii(pp, p); b = diviuexact(muliu(b, (m-(2*k-1))*(m-(2*k-2))), k*(m-(k-1))); s = mulii(mulii(b, gel(tp,1+n-k)), pp); r = odd(k) ? subii(r, s): addii(r, s); } return r; } static GEN ellsympow_abelian(GEN p, GEN ap, long m, long o) { pari_sp av = avma; long i, M, n = (m+1)>>1; GEN pk, tv, pn, pm, F, v; if (!odd(o)) { if (odd(m)) return pol_1(0); M = m >> 1; o >>= 1; } else M = m * ((o+1) >> 1); pk = gpowers(p,n); pn = gel(pk,n+1); tv = cgetg(m+2,t_VEC); gel(tv, 1) = gen_2; gel(tv, 2) = ap; for (i = 3; i <= m+1; i++) gel(tv,i) = subii(mulii(ap,gel(tv,i-1)), mulii(p,gel(tv,i-2))); pm = odd(m)? mulii(gel(pk,n), pn): sqri(pn); /* cheap p^m */ F = deg2pol_shallow(pm, gen_0, gen_1, 0); v = odd(m) ? pol_1(0): deg1pol_shallow(negi(pn), gen_1, 0); for (i = M % o; i < n; i += o) /* o | m-2*i */ { gel(F,3) = negi(mulii(gel(tv,m-2*i+1), gel(pk,i+1))); v = ZX_mul(v, F); } return gerepilecopy(av, v); } static GEN ellsympow(void *E, GEN p, long n) { pari_sp av = avma; GEN v =(GEN) E, ap = ellap(gel(v,1), p); ulong m = itou(gel(v,2)); if (n <= 2) { GEN t = ellsympow_trace(p, ap, m); return deg1pol_shallow(t, gen_1, 0); } else return gerepileupto(av, RgXn_inv_i(ellsympow_abelian(p, ap, m, 1), n)); } static GEN vecan_ellsympow(GEN an, long n) { GEN nn = utoi(n), crvm = gel(an,1), bad = gel(an,2); return direuler_bad((void*)crvm, &ellsympow, gen_2, nn, nn, bad); } static long ellsympow_betam(long o, long m) { const long c3[]={3, -1, 1}; const long c12[]={6, -2, 2, 0, 4, -4}; const long c24[]={12, -2, -4, 6, 4, -10}; if (!odd(o) && odd(m)) return 0; switch(o) { case 1: return m+1; case 2: return m+1; case 3: case 6: return (m+c3[m%3])/3; case 4: return m%4 == 0 ? (m+2)/2: m/2; case 8: return m%4 == 0 ? (m+4)/4: (m-2)/4; case 12: return (m+c12[(m%12)/2])/6; case 24: return (m+c24[(m%12)/2])/12; } return 0; } static long ellsympow_epsm(long o, long m) { return m+1-ellsympow_betam(o, m); } static GEN ellsympow_multred(GEN E, GEN p, long m, long vN, long *cnd, long *w) { if (vN==1) /* mult red*/ { *cnd = m; *w = odd(m) ? ellrootno(E, p): 1; if (odd(m) && signe(ellap(E,p))==-1) return deg1pol_shallow(gen_1, gen_1, 0); else return deg1pol_shallow(gen_m1, gen_1, 0); } else { *cnd = odd(m)? m+1: m; *w = odd(m) && odd((m+1)>>1) ? ellrootno(E, p): 1; if (odd(m) && equaliu(p,2)) *cnd += ((m+1)>>1)*(vN-2); return odd(m)? pol_1(0): deg1pol_shallow(gen_m1, gen_1, 0); } } static GEN ellsympow_nonabelian(GEN p, long m, long bet) { GEN pm = powiu(p, m), F; if (odd(m)) return gpowgs(deg2pol_shallow(pm, gen_0, gen_1, 0), bet>>1); F = gpowgs(deg2pol_shallow(negi(pm), gen_0, gen_1, 0), bet>>1); if (!odd(bet)) return F; if (m%4==2) return gmul(F, deg1pol_shallow(powiu(p, m>>1), gen_1, 0)); else return gmul(F, deg1pol_shallow(negi(powiu(p, m>>1)), gen_1, 0)); } static long safe_Z_pvalrem(GEN n, GEN p, GEN *pr) { return signe(n)==0? -1: Z_pvalrem(n, p, pr); } static GEN c4c6_ap(GEN c4, GEN c6, GEN p) { GEN N = Fp_ellcard(Fp_muls(c4,-27,p), Fp_muls(c6, -54, p), p); return subii(addis(p, 1), N); } static GEN ellsympow_abelian_twist(GEN E, GEN p, long m, long o) { GEN ap; GEN c4 = ell_get_c4(E), c6 = ell_get_c6(E); GEN c4t, c6t; long v4 = safe_Z_pvalrem(c4, p, &c4t); long v6 = safe_Z_pvalrem(c6, p, &c6t); if (v6>=0 && (v4==-1 || 3*v4>=2*v6)) c6 = c6t; if (v4>=0 && (v6==-1 || 3*v4<=2*v6)) c4 = c4t; ap = c4c6_ap(c4, c6, p); return ellsympow_abelian(p, ap, m, o); } static GEN ellsympow_goodred(GEN E, GEN p, long m, long *cnd, long *w) { long o = 12/cgcd(12, Z_pval(ell_get_disc(E), p)); long bet = ellsympow_betam(o, m); long eps = m + 1 - bet; *w = odd(m) && odd(eps>>1) ? ellrootno(E,p): 1; *cnd = eps; if (umodiu(p, o) == 1) return ellsympow_abelian_twist(E, p, m, o); else return ellsympow_nonabelian(p, m, bet); } static long ellsympow_inertia3(GEN E, long vN) { long vD = Z_lval(ell_get_disc(E), 3); if (vN==2) return vD%2==0 ? 2: 4; if (vN==4) return vD%4==0 ? 3: 6; if (vN==3 || vN==5) return 12; return 0; } static long ellsympow_deltam3(long o, long m, long vN) { if (o==3 || o==6) return ellsympow_epsm(3, m); if (o==12 && vN ==3) return (ellsympow_epsm(3, m))/2; if (o==12 && vN ==5) return (ellsympow_epsm(3, m))*3/2; return 0; } static long ellsympow_isabelian3(GEN E) { ulong c4 = umodiu(ell_get_c4(E),81), c6 = umodiu(ell_get_c6(E), 243); return (c4 == 27 || (c4%27==9 && (c6==108 || c6==135))); } static long ellsympow_rootno3(GEN E, GEN p, long o, long m) { const long w6p[]={1,-1,-1,-1,1,1}; const long w6n[]={-1,1,-1,1,-1,1}; const long w12p[]={1,1,-1,1,1,1}; const long w12n[]={-1,-1,-1,-1,-1,1}; long w = ellrootno(E, p), mm = (m%12)>>1; switch(o) { case 2: return m%4== 1 ? -1: 1; case 6: return w == 1 ? w6p[mm]: w6n[mm]; case 12: return w == 1 ? w12p[mm]: w12n[mm]; default: return 1; } } static GEN ellsympow_goodred3(GEN E, GEN F, GEN p, long m, long vN, long *cnd, long *w) { long o = ellsympow_inertia3(E, vN); long bet = ellsympow_betam(o, m); *cnd = m + 1 - bet + ellsympow_deltam3(o, m, vN); *w = odd(m)? ellsympow_rootno3(E, p, o, m): 1; if (o==1 || o==2) return ellsympow_abelian(p, ellap(F, p), m, o); if ((o==3 || o==6) && ellsympow_isabelian3(F)) return ellsympow_abelian(p, p, m, o); else return ellsympow_nonabelian(p, m, bet); } static long ellsympow_inertia2(GEN F, long vN) { long vM = itos(gel(elllocalred(F, gen_2),1)); GEN c6 = ell_get_c6(F); long v6 = signe(c6) ? vali(c6): 24; if (vM==0) return vN==0 ? 1: 2; if (vM==2) return vN==2 ? 3: 6; if (vM==5) return 8; if (vM==8) return v6>=9? 8: 4; if (vM==3 || vN==7) return 24; return 0; } static long ellsympow_deltam2(long o, long m, long vN) { if ((o==2 || o==6) && vN==4) return ellsympow_epsm(2, m); if ((o==2 || o==6) && vN==6) return 2*ellsympow_epsm(2, m); if (o==4) return 2*ellsympow_epsm(4, m)+ellsympow_epsm(2, m); if (o==8 && vN==5) return ellsympow_epsm(8, m)+ellsympow_epsm(2, m)/2; if (o==8 && vN==6) return ellsympow_epsm(8, m)+ellsympow_epsm(2, m); if (o==8 && vN==8) return ellsympow_epsm(8, m)+ellsympow_epsm(4, m)+ellsympow_epsm(2, m); if (o==24 && vN==3) return (2*ellsympow_epsm(8, m)+ellsympow_epsm(2, m))/6; if (o==24 && vN==4) return (ellsympow_epsm(8, m)+ellsympow_epsm(2, m)*2)/3; if (o==24 && vN==6) return (ellsympow_epsm(8, m)+ellsympow_epsm(2, m)*5)/3; if (o==24 && vN==7) return (ellsympow_epsm(8, m)*10+ellsympow_epsm(2, m)*5)/6; return 0; } static long ellsympow_isabelian2(GEN F) { return umodi2n(ell_get_c4(F),7) == 96; } static long ellsympow_rootno2(GEN E, long vN, long m, long bet) { long eps2 = (m + 1 - bet)>>1; long eta = odd(vN) && m%8==3 ? -1 : 1; long w2 = odd(eps2) ? ellrootno(E, gen_2): 1; return eta == w2 ? 1 : -1; } static GEN ellsympow_goodred2(GEN E, GEN F, GEN p, long m, long vN, long *cnd, long *w) { long o = ellsympow_inertia2(F, vN); long bet = ellsympow_betam(o, m); *cnd = m + 1 - bet + ellsympow_deltam2(o, m, vN); *w = odd(m) ? ellsympow_rootno2(E, vN, m, bet): 1; if (o==1 || o==2) return ellsympow_abelian(p, ellap(F, p), m, o); if (o==4 && ellsympow_isabelian2(F)) return ellsympow_abelian(p, p, m, o); else return ellsympow_nonabelian(p, m, bet); } static GEN ellminimaldotwist(GEN E, GEN *pD, long prec) { GEN D = ellminimaltwistcond(E), Et = elltwist(E, D), Etmin; if (pD) *pD = D; Et = ellinit(Et, NULL, prec); Etmin = ellminimalmodel(Et, NULL); obj_free(Et); return Etmin; } /* Based on Symmetric powers of elliptic curve L-functions, Phil Martin and Mark Watkins, ANTS VII with thanks to Mark Watkins. BA20180402 */ static GEN lfunellsympow(GEN e, ulong m) { pari_sp av = avma; GEN B, N, Nfa, pr, ex, ld, bad, ejd, et, pole; long i, l, mero, w = (m&7)==1 || (m&7)==3 ? -1: 1; checkell_Q(e); e = ellminimalmodel(e, NULL); ejd = Q_denom(ell_get_j(e)); mero = m==0 || (m%4==0 && ellQ_get_CM(e)<0); ellQ_get_Nfa(e, &N, &Nfa); pr = gel(Nfa,1); ex = gel(Nfa,2); l = lg(pr); if (ugcd(umodiu(N,6), 6) == 1) et = NULL; else et = ellminimaldotwist(e, NULL, DEFAULTPREC); B = gen_1; bad = cgetg(l, t_VEC); for (i=1; i>1)),gen_0)): NULL; ld = mkvecn(mero? 7: 6, tag(mkvec2(mkvec2(e,utoi(m)),bad), t_LFUN_SYMPOW_ELL), gen_0, ellsympow_gamma(m), stoi(m+1), B, stoi(w), pole); if (et) obj_free(et); return gerepilecopy(av, ld); } GEN lfunsympow(GEN ldata, ulong m) { ldata = lfunmisc_to_ldata_shallow(ldata); if (ldata_get_type(ldata) != t_LFUN_ELL) pari_err_IMPL("lfunsympow"); return lfunellsympow(gel(ldata_get_an(ldata), 2), m); } GEN lfunmfspec(GEN lmisc, long bitprec) { pari_sp ltop = avma; GEN Vga, linit, ldataf, veven, vodd, om, op, eps, dom; long k, k2, j; ldataf = lfunmisc_to_ldata_shallow(lmisc); k = ldata_get_k(ldataf); dom = mkvec3(dbltor(k/2.), dbltor((k-2)/2.), gen_0); if (is_linit(lmisc) && linit_get_type(lmisc) == t_LDESC_INIT && sdomain_isincl(k, dom, lfun_get_dom(linit_get_tech(lmisc)))) linit = lmisc; else linit = lfuninit(ldataf, dom, 0, bitprec); Vga = ldata_get_gammavec(ldataf); if (!gequal(Vga, mkvec2(gen_0,gen_1))) pari_err_TYPE("lfunmfspec", lmisc); if (odd(k)) pari_err_IMPL("odd weight in lfunmfspec"); k2 = k/2; vodd = cgetg(k2+1, t_VEC); veven = cgetg(k2, t_VEC); for (j=1; j <= k2; ++j) gel(vodd,j) = lfunlambda(linit, stoi(2*j-1), bitprec); for (j=1; j < k2; ++j) gel(veven,j) = lfunlambda(linit, stoi(2*j), bitprec); if (k > 2) { om = gel(veven,1); veven = gdiv(veven, om); op = gel(vodd,2); } else { /* veven empty */ om = gen_1; op = gel(vodd,1); } if (maxss(gexpo(imag_i(om)), gexpo(imag_i(op))) > -bitprec/2) pari_err_TYPE("lfunmfspec", lmisc); vodd = gdiv(vodd, op); eps = int2n(bitprec/4); veven= bestappr(veven, eps); vodd = bestappr(vodd, eps); return gerepilecopy(ltop, mkvec4(veven, vodd, om, op)); } static long ellsymsq_bad2(GEN c4, GEN c6, long e) { switch (e) { case 2: return 1; case 3: return 0; case 5: return 0; case 7: return 0; case 8: if (dvdiu(c6,512)) return 0; return umodiu(c4,128)==32 ? 1 : -1; default: return 0; } } static long ellsymsq_bad3(GEN c4, GEN c6, long e) { long c6_243, c4_81; switch (e) { case 2: return 1; case 3: return 0; case 5: return 0; case 4: c4_81 = umodiu(c4,81); if (c4_81 == 27) return -1; if (c4_81%27 != 9) return 1; c6_243 = umodiu(c6,243); return (c6_243==108 || c6_243==135)? -1: 1; default: return 0; } } static int c4c6_testp(GEN c4, GEN c6, GEN p) { GEN p2 = sqri(p); return (dvdii(c6,p2) && !dvdii(c4,p2)); } /* assume e = v_p(N) >= 2 */ static long ellsymsq_badp(GEN c4, GEN c6, GEN p, long e) { if (absequaliu(p, 2)) return ellsymsq_bad2(c4, c6, e); if (absequaliu(p, 3)) return ellsymsq_bad3(c4, c6, e); switch(umodiu(p, 12UL)) { case 1: return -1; case 5: return c4c6_testp(c4,c6,p)? -1: 1; case 7: return c4c6_testp(c4,c6,p)? 1:-1; default:return 1; /* p%12 = 11 */ } } static GEN lfunellsymsqmintwist(GEN e) { pari_sp av = avma; GEN N, Nfa, P, E, V, c4, c6, ld; long i, l, k; checkell_Q(e); e = ellminimalmodel(e, NULL); ellQ_get_Nfa(e, &N, &Nfa); c4 = ell_get_c4(e); c6 = ell_get_c6(e); P = gel(Nfa,1); l = lg(P); E = gel(Nfa,2); V = cgetg(l, t_VEC); for (i=k=1; i vt */ if (absequaliu(p, 2)) { if (vt == 0 && v >= 4) r = shifti(subsi(9, sqri(ellap(Et, p))), v-3); /* 9=(2+1)^2 */ else if (vt == 1) r = gmul2n(utoipos(3), v-3); /* not in Z if v=2 */ else if (vt >= 2) r = int2n(v-vt); else r = gen_1; /* vt = 0, 1 <= v <= 3 */ } else if (vt >= 1) r = gdiv(subiu(sqri(p), 1), p); else r = gdiv(mulii(subiu(p, 1), subii(sqri(addiu(p, 1)), sqri(ellap(Et, p)))), p); f = gmul(f, r); } return f; } GEN lfunellmfpeters(GEN E, long bitprec) { pari_sp ltop = avma; GEN D, Et = ellminimaldotwist(E, &D, nbits2prec(bitprec)); GEN nor = lfunellmfpetersmintwist(Et, bitprec); GEN nor2 = gmul(nor, elldiscfix(E, Et, D)); obj_free(Et); return gerepileupto(ltop, nor2); } /*************************************************************/ /* Genus 2 curves */ /*************************************************************/ static void Flv_diffnext(GEN d, ulong p) { long j, n = lg(d)-1; for(j = n; j>=2; j--) uel(d,j) = Fl_add(uel(d,j), uel(d,j-1), p); } static GEN Flx_difftable(GEN P, ulong p) { long i, n = degpol(P); GEN V = cgetg(n+2, t_VECSMALL); uel(V, n+1) = Flx_constant(P); for(i = n; i >= 1; i--) { P = Flx_diff1(P, p); uel(V, i) = Flx_constant(P); } return V; } static long Flx_genus2trace_naive(GEN H, ulong p) { pari_sp av = avma; ulong i, j; long a, n = degpol(H); GEN k = const_vecsmall(p, -1), d; k[1] = 0; for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p)) k[j+1] = 1; a = n == 5 ? 0: k[1+Flx_lead(H)]; d = Flx_difftable(H, p); for (i=0; i < p; i++) { a += k[1+uel(d,n+1)]; Flv_diffnext(d, p); } avma = av; return a; } static GEN dirgenus2(void *E, GEN p, long n) { pari_sp av = avma; GEN Q = (GEN) E; GEN f; if (n > 2) f = RgX_recip(hyperellcharpoly(gmul(Q,gmodulo(gen_1, p)))); else { ulong pp = itou(p); GEN Qp = ZX_to_Flx(Q, pp); long t = Flx_genus2trace_naive(Qp, pp); f = deg1pol_shallow(stoi(t), gen_1, 0); } return gerepileupto(av, RgXn_inv_i(f, n)); } static GEN vecan_genus2(GEN an, long L) { GEN Q = gel(an,1), bad = gel(an, 2); return direuler_bad((void*)Q, dirgenus2, gen_2, stoi(L), NULL, bad); } static GEN genus2_redmodel(GEN P, GEN p) { GEN M = FpX_factor(P, p); GEN F = gel(M,1), E = gel(M,2); long i, k, r = lg(F); GEN U = scalarpol(leading_coeff(P), varn(P)); GEN G = cgetg(r, t_COL); for (i=1, k=0; i1) gel(G,++k) = gel(F,i); if (odd(E[i])) U = FpX_mul(U, gel(F,i), p); } setlg(G,++k); return mkvec2(G,U); } static GEN oneminusxd(long d) { return gsub(gen_1, pol_xn(d, 0)); } static GEN ellfromeqncharpoly(GEN P, GEN Q, GEN p) { long v; GEN E, F, t, y; v = fetch_var(); y = pol_x(v); F = gsub(gadd(ZX_sqr(y), gmul(y, Q)), P); E = ellinit(ellfromeqn(F), p, DEFAULTPREC); delete_var(); t = ellap(E, p); obj_free(E); return mkpoln(3, gen_1, negi(t), p); } static GEN genus2_eulerfact(GEN P, GEN p) { GEN Pp = FpX_red(P, p); GEN GU = genus2_redmodel(Pp, p); long d = 6-degpol(Pp), v = d/2, w = odd(d); GEN abe, tor; GEN ki, kp = pol_1(0), kq = pol_1(0); GEN F = gel(GU,1), Q = gel(GU,2); long dQ = degpol(Q), lF = lg(F)-1; abe = dQ >= 5 ? RgX_recip(hyperellcharpoly(gmul(Q,gmodulo(gen_1,p)))) : dQ >= 3 ? RgX_recip(ellfromeqncharpoly(Q,gen_0,p)) : pol_1(0); ki = dQ != 0 ? oneminusxd(1) : Fp_issquare(gel(Q,2),p) ? ZX_sqr(oneminusxd(1)) : oneminusxd(2); if (lF) { long i; for(i=1; i <= lF; i++) { GEN Fi = gel(F, i); long d = degpol(Fi); GEN e = FpX_rem(Q, Fi, p); GEN kqf = lgpol(e)==0 ? oneminusxd(d): FpXQ_issquare(e, Fi, p) ? ZX_sqr(oneminusxd(d)) : oneminusxd(2*d); kp = gmul(kp, oneminusxd(d)); kq = gmul(kq, kqf); } } if (v) { GEN kqoo = w==1 ? oneminusxd(1): Fp_issquare(leading_coeff(Q), p)? ZX_sqr(oneminusxd(1)) : oneminusxd(2); kp = gmul(kp, oneminusxd(1)); kq = gmul(kq, kqoo); } tor = RgX_div(ZX_mul(oneminusxd(1), kq), ZX_mul(ki, kp)); return ginv( ZX_mul(abe, tor) ); } static GEN F2x_genus2_find_trans(GEN P, GEN Q, GEN F) { pari_sp av = avma; long i, d = F2x_degree(F), v = P[1]; GEN M, C, V; M = cgetg(d+1, t_MAT); for (i=1; i<=d; i++) { GEN Mi = F2x_rem(F2x_add(F2x_shift(Q,i-1), monomial_F2x(2*i-2,v)), F); gel(M,i) = F2x_to_F2v(Mi, d); } C = F2x_to_F2v(F2x_rem(P, F), d); V = F2m_F2c_invimage(M, C); return gerepileuptoleaf(av, F2v_to_F2x(V, v)); } static GEN F2x_genus2_trans(GEN P, GEN Q, GEN H) { return F2x_add(P,F2x_add(F2x_mul(H,Q), F2x_sqr(H))); } static GEN F2x_genus_redoo(GEN P, GEN Q, long k) { if (F2x_degree(P)==2*k) { long c = F2x_coeff(P,2*k-1), dQ = F2x_degree(Q); if ((dQ==k-1 && c==1) || (dQ0) { GEN M = gel(F2x_factor(F),1); long i, l = lg(M); for(i=1; i 0) { GEN d = F2xq_div(c, F2xq_sqr(b, T), T); return F2xq_trace(d, T)? 0: 2; } else return 1; } static GEN genus2_redmodel2(GEN P) { GEN Q = pol_0(varn(P)); GEN P2 = ZX_to_F2x(P); while (F2x_issquare(P2)) { GEN H = F2x_to_ZX(F2x_sqrt(P2)); GEN P1 = ZX_sub(P, ZX_sqr(H)); GEN Q1 = ZX_add(Q, ZX_mulu(H, 2)); if ((signe(P1)==0 || ZX_lval(P1,2)>=2) && (signe(Q1)==0 || ZX_lval(Q1,2)>=1)) { P = ZX_shifti(P1, -2); Q = ZX_shifti(Q1, -1); P2= ZX_to_F2x(P); } else break; } return mkvec2(P,Q); } static GEN genus2_eulerfact2(GEN PQ) { GEN V = F2x_genus_red(ZX_to_F2x(gel(PQ, 1)), ZX_to_F2x(gel(PQ, 2))); GEN P = gel(V, 1), Q = gel(V, 2); GEN F = gel(V, 3), v = gel(V, 4); GEN abe, tor; GEN ki, kp = pol_1(0), kq = pol_1(0); long dP = F2x_degree(P), dQ = F2x_degree(Q), d = maxss(dP, 2*dQ); if (!lgpol(F)) return pol_1(0); ki = dQ!=0 || dP>0 ? oneminusxd(1): dP==-1 ? ZX_sqr(oneminusxd(1)): oneminusxd(2); abe = d>=5? RgX_recip(hyperellcharpoly(gmul(PQ,gmodulss(1,2)))): d>=3? RgX_recip(ellfromeqncharpoly(F2x_to_ZX(P), F2x_to_ZX(Q), gen_2)): pol_1(0); if (lgpol(F)) { GEN M = gel(F2x_factor(F), 1); long i, lF = lg(M)-1; for(i=1; i <= lF; i++) { GEN Fi = gel(M, i); long d = F2x_degree(Fi); long nb = F2xqX_quad_nbroots(F2x_rem(Q, Fi), F2x_rem(P, Fi), Fi); GEN kqf = nb==1 ? oneminusxd(d): nb==2 ? ZX_sqr(oneminusxd(d)) : oneminusxd(2*d); kp = gmul(kp, oneminusxd(d)); kq = gmul(kq, kqf); } } if (maxss(v[1],2*v[2])<5) { GEN kqoo = v[1]>2*v[2] ? oneminusxd(1): v[1]<2*v[2] ? ZX_sqr(oneminusxd(1)) : oneminusxd(2); kp = gmul(kp, oneminusxd(1)); kq = gmul(kq, kqoo); } tor = RgX_div(ZX_mul(oneminusxd(1),kq), ZX_mul(ki, kp)); return ginv( ZX_mul(abe, tor) ); } GEN lfungenus2(GEN G) { pari_sp ltop = avma; GEN Ldata; GEN gr = genus2red(G, NULL); GEN N = gel(gr, 1), M = gel(gr, 2), Q = gel(gr, 3), L = gel(gr, 4); GEN PQ = genus2_redmodel2(Q); GEN e; long i, lL = lg(L), ram2; ram2 = absequaliu(gmael(M,1,1),2); if (ram2 && equalis(gmael(M,2,1),-1)) pari_warn(warner,"unknown valuation of conductor at 2"); e = cgetg(lL+(ram2?0:1), t_VEC); gel(e,1) = mkvec2(gen_2, ram2 ? genus2_eulerfact2(PQ) : ginv( RgX_recip(hyperellcharpoly(gmul(PQ,gmodulss(1,2))))) ); for(i = ram2? 2: 1; i < lL; i++) { GEN Li = gel(L, i); GEN p = gel(Li, 1); gel(e, ram2 ? i: i+1) = mkvec2(p, genus2_eulerfact(Q,p)); } Ldata = mkvecn(6, tag(mkvec2(Q,e), t_LFUN_GENUS2), gen_0, mkvec4(gen_0, gen_0, gen_1, gen_1), gen_2, N, gen_0); return gerepilecopy(ltop, Ldata); } /*************************************************************/ /* ETA QUOTIENTS */ /* An eta quotient is a matrix with 2 columns [m, r_m] with */ /* m >= 1 representing f(\tau)=\prod_m\eta(m\tau)^{r_m}. */ /*************************************************************/ /* eta(x^v) + O(x^L) */ GEN eta_ZXn(long v, long L) { long n, k = 0, v2 = 2*v, bn = v, cn = 0; GEN P; if (!L) return zeropol(0); P = cgetg(L+2,t_POL); P[1] = evalsigne(1); for(n = 0; n < L; n++) gel(P,n+2) = gen_0; for(n = 0;; n++, bn += v2, cn += v) { /* k = v * (3*n-1) * n / 2; bn = v * (2*n+1); cn = v * n */ long k2; gel(P, k+2) = odd(n)? gen_m1: gen_1; k2 = k+cn; if (k2 >= L) break; k = k2; /* k = v * (3*n+1) * n / 2 */; gel(P, k+2) = odd(n)? gen_m1: gen_1; k2 = k+bn; if (k2 >= L) break; k = k2; } setlg(P, k+3); return P; } GEN eta_product_ZXn(GEN eta, long L) { pari_sp av = avma; GEN P = NULL, D = gel(eta,1), R = gel(eta,2); long i, l = lg(D); for (i = 1; i < l; ++i) { GEN Q = eta_ZXn(D[i], L); long r = R[i]; if (r < 0) { Q = RgXn_inv_i(Q, L); r = -r; } if (r != 1) Q = RgXn_powu_i(Q, r, L); P = P? ZXn_mul(P, Q, L): Q; if (gc_needed(av,1) && i > 1) { if (DEBUGMEM>1) pari_warn(warnmem,"eta_product_ZXn"); P = gerepilecopy(av, P); } } return P; } static GEN vecan_eta(GEN an, long L) { GEN v = RgX_to_RgC(eta_product_ZXn(an, L), L); settyp(v, t_VEC); return v; } /* return 1 if cuspidal, 0 if holomorphic, -1 otherwise */ static int etacuspidal(GEN N, GEN k, GEN B, GEN R, GEN NB) { long i, j, lD, l, cusp = 1; GEN D; if (gsigne(k) < 0) return -1; D = divisors(N); lD = lg(D); l = lg(B); for (i = 1; i < lD; i++) { GEN t = gen_0, d = gel(D,i); long s; for (j = 1; j < l; j++) t = addii(t, mulii(gel(NB,j), mulii(gel(R,j), sqri(gcdii(d, gel(B,j)))))); s = signe(t); if (s < 0) return -1; if (!s) cusp = 0; } return cusp; } /* u | 24, level = u*N0, N0 = lcm(B), NB[i] = N0/B[i] */ static int etaselfdual(GEN B, GEN R, GEN NB, ulong u) { long i, l = lg(B); for (i = 1; i < l; ++i) { GEN t = muliu(gel(NB,i), u); /* *pN / B[i] */ long j = ZV_search(B, t); if (!j || !equalii(gel(R,i),gel(R,j))) return 0; } return 1; } /* return Nebentypus of eta quotient, k2 = 2*k integral */ static GEN etachar(GEN B, GEN R, GEN k2) { long i, l = lg(B); GEN P = gen_1; for (i = 1; i < l; ++i) if (mpodd(gel(R,i))) P = mulii(P, gel(B,i)); switch(Mod4(k2)) { case 0: break; case 2: P = negi(P); break; default: P = shifti(P, 1); break; } return coredisc(P); } /* Return 0 if not on gamma_0(N). Sets conductor, modular weight, character, * canonical matrix, v_q(eta), sd = 1 iff self-dual, cusp = 1 iff cuspidal * [0 if holomorphic at all cusps, else -1] */ long etaquotype(GEN *peta, GEN *pN, GEN *pk, GEN *CHI, long *pv, long *sd, long *cusp) { GEN B, R, S, T, N, NB, eta = *peta; long l, i, u, S24; if (lg(eta) != 3) pari_err_TYPE("lfunetaquo", eta); switch(typ(eta)) { case t_VEC: eta = mkmat2(mkcol(gel(eta,1)), mkcol(gel(eta,2))); break; case t_MAT: break; default: pari_err_TYPE("lfunetaquo", eta); } if (!RgV_is_ZVpos(gel(eta,1)) || !RgV_is_ZV(gel(eta,2))) pari_err_TYPE("lfunetaquo", eta); *peta = eta = famat_reduce(eta); B = gel(eta,1); l = lg(B); /* sorted in increasing order */ R = gel(eta,2); N = glcm0(B, NULL); NB = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(NB,i) = diviiexact(N, gel(B,i)); S = gen_0; T = gen_0; u = 0; for (i = 1; i < l; ++i) { GEN b = gel(B,i), r = gel(R,i); S = addii(S, mulii(b, r)); T = addii(T, r); u += umodiu(r,24) * umodiu(gel(NB,i), 24); } S = divis_rem(S, 24, &S24); if (S24) return 0; /* non-integral valuation at oo */ u %= 24; if (u < 0) u += 24; u = 24/ugcd(24, u); *pN = muliu(N, u); /* level */ *pk = gmul2n(T,-1); /* weight */ *pv = itos(S); /* valuation */ if (cusp) *cusp = etacuspidal(*pN, *pk, B, R, NB); if (sd) *sd = etaselfdual(B, R, NB, u); if (CHI) *CHI = etachar(B, R, T); return 1; } GEN lfunetaquo(GEN eta0) { pari_sp ltop = avma; GEN Ldata, N, BR, k, eta = eta0; long v, sd, cusp; if (!etaquotype(&eta, &N, &k, NULL, &v, &sd, &cusp)) pari_err_TYPE("lfunetaquo", eta0); if (!cusp) pari_err_IMPL("noncuspidal eta quotient"); if (v != 1) pari_err_IMPL("valuation != 1"); if (!sd) pari_err_IMPL("non self-dual eta quotient"); if (typ(k) != t_INT) pari_err_TYPE("lfunetaquo [non-integral weight]", eta0); BR = mkvec2(ZV_to_zv(gel(eta,1)), ZV_to_zv(gel(eta,2))); Ldata = mkvecn(6, tag(BR,t_LFUN_ETA), gen_0, mkvec2(gen_0,gen_1), k,N, gen_1); return gerepilecopy(ltop, Ldata); } static GEN vecan_qf(GEN Q, long L) { GEN v, w = qfrep0(Q, utoi(L), 1); long i; v = cgetg(L+1, t_VEC); for (i = 1; i <= L; i++) gel(v,i) = utoi(2 * w[i]); return v; } long qf_iseven(GEN M) { long i, l = lg(M); for (i=1; i> 1; M = Q_primpart(M); Mi = ZM_inv(M, &d); /* d M^(-1) */ if (!qf_iseven(M)) { M = gmul2n(M, 1); d = shifti(d,1); } if (!qf_iseven(Mi)){ Mi= gmul2n(Mi,1); d = shifti(d,1); } /* det(Mi) = d^n/det(M), D^2 = det(Mi)/det(M) */ D = gdiv(powiu(d,k), ZM_det(M)); if (!issquareall(D, &eno)) eno = gsqrt(D, prec); dual = gequal1(D) ? gen_0: tag(Mi, t_LFUN_QF); res0 = RgX_to_ser(deg1pol_shallow(gen_m2, gen_0, 0), 3); setvalp(res0, -1); res2 = RgX_to_ser(deg1pol_shallow(gmulgs(eno,2), gen_0, 0), 3); setvalp(res2, -1); poles = mkcol2(mkvec2(stoi(k),res2), mkvec2(gen_0,res0)); Ldata = mkvecn(7, tag(M, t_LFUN_QF), dual, mkvec2(gen_0, gen_1), stoi(k), d, eno, poles); return gerepilecopy(ltop, Ldata); } /********************************************************************/ /** Artin L function, based on a GP script by Charlotte Euvrard **/ /********************************************************************/ static GEN artin_charfromgens(GEN G, GEN M) { GEN R, V, ord = gal_get_orders(G), grp = gal_get_group(G); long i, j, k, n = lg(ord)-1, m = lg(grp)-1; if (lg(M)-1 != n) pari_err_DIM("lfunartin"); R = cgetg(m+1, t_VEC); gel(R, 1) = matid(lg(gel(M, 1))-1); for (i = 1, k = 1; i <= n; ++i) { long c = k*(ord[i] - 1); gel(R, ++k) = gel(M, i); for (j = 2; j <= c; ++j) gel(R, ++k) = gmul(gel(R,j), gel(M,i)); } V = cgetg(m+1, t_VEC); for (i = 1; i <= m; i++) gel(V, gel(grp,i)[1]) = gtrace(gel(R,i)); return V; } static GEN galois_get_conj(GEN G) { GEN grp = gal_get_group(G); long i, k, r = lg(grp)-1; GEN b = zero_F2v(r); for (k = 2; k <= r; ++k) { GEN g = gel(grp,k); if (!F2v_coeff(b,g[1]) && g[g[1]]==1) { pari_sp av = avma; GEN F = galoisfixedfield(G, g, 1, -1); if (ZX_sturmpart(F, NULL) > 0) { avma = av; return g; } for (i = 1; i<=r; i++) { GEN h = gel(grp, i); long t = h[1]; while (h[t]!=1) t = h[t]; F2v_set(b, h[g[t]]); } avma = av; } } pari_err_BUG("galois_get_conj"); return NULL; } static GEN cyclotoi(GEN v) { return simplify_shallow(lift_shallow(v)); } static long cyclotos(GEN v) { return gtos(cyclotoi(v)); } static long char_dim(GEN ch) { return cyclotos(gel(ch,1)); } static GEN artin_gamma(GEN N, GEN G, GEN ch) { long a, t, d = char_dim(ch); if (nf_get_r2(N) == 0) return vec01(d, 0); a = galois_get_conj(G)[1]; t = cyclotos(gel(ch,a)); return vec01((d+t) / 2, (d-t) / 2); } static long artin_dim(GEN ind, GEN ch) { long n = lg(ch)-1; GEN elts = group_elts(ind, n); long i, d = lg(elts)-1; GEN s = gen_0; for(i=1; i<=d; i++) s = gadd(s, gel(ch, gel(elts,i)[1])); return gtos(gdivgs(cyclotoi(s), d)); } static GEN artin_ind(GEN elts, GEN ch, GEN p) { long i, d = lg(elts)-1; GEN s = gen_0; for(i=1; i<=d; i++) s = gadd(s, gel(ch, gmul(gel(elts,i),p)[1])); return gdivgs(s, d); } static GEN artin_ram(GEN nf, GEN gal, GEN aut, GEN pr, GEN ramg, GEN ch, long d) { pari_sp av = avma; long i, v, n; GEN p, q, V, elts; if (d==0) return pol_1(0); n = degpol(gal_get_pol(gal)); q = p = idealramfrobenius_aut(nf, gal, pr, ramg, aut); elts = group_elts(gel(ramg,2), n); v = fetch_var_higher(); V = cgetg(d+3, t_POL); V[1] = evalsigne(1)|evalvarn(v); gel(V,2) = gen_0; for(i=1; i<=d; i++) { gel(V,i+2) = gdivgs(artin_ind(elts, ch, q), -i); q = gmul(q, p); } delete_var(); V = RgXn_exp(V,d+1); setvarn(V,0); return gerepileupto(av, ginv(V)); } /* [Artin conductor, vec of [p, Lp]] */ static GEN artin_badprimes(GEN N, GEN G, GEN aut, GEN ch) { pari_sp av = avma; long i, d = char_dim(ch); GEN P = gel(absZ_factor(nf_get_disc(N)), 1); long lP = lg(P); GEN B = cgetg(lP, t_VEC), C = cgetg(lP, t_VEC); for (i = 1; i < lP; ++i) { GEN p = gel(P, i), pr = idealprimedec_galois(N, p); GEN J = idealramgroups_aut(N, G, pr, aut); GEN G0 = gel(J,2); /* inertia group */ long lJ = lg(J); long sdec = artin_dim(G0, ch); long ndec = group_order(G0); long j, v = ndec * (d - sdec); for (j = 3; j < lJ; ++j) { GEN Jj = gel(J, j); long s = artin_dim(Jj, ch); v += group_order(Jj) * (d - s); } gel(C, i) = powiu(p, v/ndec); gel(B, i) = mkvec2(p, artin_ram(N, G, aut, pr, J, ch, sdec)); } return gerepilecopy(av, mkvec2(ZV_prod(C), B)); } struct dir_artin { GEN nf, G, V, aut; }; /* p does not divide nf.index */ static GEN idealfrobenius_easy(GEN nf, GEN gal, GEN aut, GEN T, GEN p) { long i, l = lg(aut), f = degpol(T); GEN D, Dzk, DzkT, DXp, grp = gal_get_group(gal); pari_sp av = avma; if (f==1) return gel(grp,1); Dzk = nf_get_zkprimpart(nf); D = modii(nf_get_zkden(nf), p); DzkT = RgV_to_RgM(FqV_red(Dzk, T, p), f); DXp = RgX_to_RgC(FpX_Frobenius(T, p), f); if (!equali1(D)) DXp = FpC_Fp_mul(DXp, D, p); for(i=1; i < l; i++) { GEN g = gel(grp,i); if (perm_order(g)==f) { GEN A = FpM_FpC_mul(DzkT, gel(aut,g[1]), p); if (ZV_equal(A, DXp)) {avma = av; return g; } } } return NULL; /* LCOV_EXCL_LINE */ } /* true nf; p divides nf.index, pr/p unramified */ static GEN idealfrobenius_hard(GEN nf, GEN gal, GEN aut, GEN pr) { long i, l = lg(aut), f = pr_get_f(pr); GEN modpr, p, T, X, Xp, pi, grp = gal_get_group(gal); pari_sp av = avma; if (f==1) return gel(grp,1); pi = pr_get_gen(pr); modpr = zkmodprinit(nf, pr); p = modpr_get_p(modpr); T = modpr_get_T(modpr); X = modpr_genFq(modpr); Xp = FpX_Frobenius(T, p); for (i = 1; i < l; i++) { GEN g = gel(grp,i); if (perm_order(g)==f) { GEN S = gel(aut,g[1]); GEN A = nf_to_Fq(nf, zk_galoisapplymod(nf,X,S,p), modpr); /* sigma(X) = X^p (mod pr) and sigma(pi) in pr */ if (ZX_equal(A, Xp) && (f == nf_get_degree(nf) || ZC_prdvd(zk_galoisapplymod(nf,pi,S,p),pr))) { avma=av; return g; } } } return NULL; /* LCOV_EXCL_LINE */ } static GEN dirartin(void *E, GEN p, long n) { pari_sp av = avma; struct dir_artin *d = (struct dir_artin *) E; GEN nf = d->nf, pr, frob; /* pick one maximal ideal in the conjugacy class above p */ GEN T = nf_get_pol(nf); if (!dvdii(nf_get_index(nf), p)) { /* simple case */ GEN F = FpX_factor(T, p), P = gmael(F,1,1); frob = idealfrobenius_easy(nf, d->G, d->aut, P, p); } else { pr = idealprimedec_galois(nf,p); frob = idealfrobenius_hard(nf, d->G, d->aut, pr); } avma = av; return RgXn_inv(gel(d->V, frob[1]), n); } static GEN vecan_artin(GEN an, long L, long prec) { struct dir_artin d; GEN A, Sbad = gel(an,5); long n = itos(gel(an,6)), isreal = lg(an)<8 ? 0: !itos(gel(an,7)); d.nf = gel(an,1); d.G = gel(an,2); d.V = gel(an,3); d.aut = gel(an,4); A = lift_shallow(direuler_bad(&d, dirartin, gen_2, stoi(L), NULL, Sbad)); A = RgXV_RgV_eval(A, grootsof1(n, prec)); if (isreal) A = real_i(A); return A; } static GEN char_expand(GEN conj, GEN ch) { long i, l = lg(conj); GEN V = cgetg(l, t_COL); for (i=1; i1 && typ(gel(ch,1))==t_MAT) chx = artin_charfromgens(gal, gmul(ch,mod)); else { if (lg(repr) != lg(ch)) pari_err_DIM("lfunartin"); chx = char_expand(conj, gmul(ch,mod)); } chx = handle_zeta(nf_get_degree(nf), chx, &tmult); ch = shallowextract(chx, repr); if (!gequal0(chx)) { GEN real = char_is_real(chx, gel(mod,1))? gen_0: gen_1; aut = nfgaloispermtobasis(nf, gal); V = gmul(char_expand(conj, galoischarpoly(gal, ch, o)), mod); bc = artin_badprimes(nf, gal, aut, chx); Ldata = mkvecn(6, tag(mkcoln(7, nf, gal, V, aut, gel(bc, 2), stoi(o), real), t_LFUN_ARTIN), real, artin_gamma(nf, gal, chx), gen_1, gel(bc,1), gen_0); } if (tmult==0 && Ldata==NULL) pari_err_TYPE("lfunartin",ch); if (tmult) { long i; if (Ldata==NULL) { Ldata = lfunzeta(); tmult--; } for(i=1; i<=tmult; i++) Ldata = lfunmul(Ldata, gen_1, bitprec); } return gerepilecopy(av, Ldata); } static GEN lfunzetakinit_artin(GEN nf, GEN gal, GEN dom, long der, long bitprec) { pari_sp ltop = avma; GEN To = galoischartable(gal), T = gel(To, 1); long o = itos(gel(To, 2)); GEN F, E, M, domain; long i, l = lg(T); F = cgetg(l, t_VEC); E = cgetg(l, t_VECSMALL); for (i = 1; i < l; ++i) { GEN L = lfunartin(nf, gal, gel(T,i), o, bitprec); gel(F, i) = lfuninit(L, dom, der, bitprec); E[i] = char_dim(gel(T,i)); } domain = mkvec2(dom, mkvecsmall2(der, bitprec)); M = mkvec3(F, E, zero_zv(l-1)); return gerepilecopy(ltop, lfuninit_make(t_LDESC_PRODUCT, lfunzetak_i(nf), M, domain)); } /********************************************************************/ /** High-level Constructors **/ /********************************************************************/ enum { t_LFUNMISC_POL, t_LFUNMISC_CHIQUAD, t_LFUNMISC_CHICONREY, t_LFUNMISC_CHIGEN, t_LFUNMISC_ELLINIT, t_LFUNMISC_ETAQUO }; static long lfundatatype(GEN data) { long l; switch(typ(data)) { case t_INT: return t_LFUNMISC_CHIQUAD; case t_INTMOD: return t_LFUNMISC_CHICONREY; case t_POL: return t_LFUNMISC_POL; case t_VEC: if (checknf_i(data)) return t_LFUNMISC_POL; l = lg(data); if (l == 17) return t_LFUNMISC_ELLINIT; if (l == 3 && typ(gel(data,1)) == t_VEC) return t_LFUNMISC_CHIGEN; break; } return -1; } static GEN lfunmisc_to_ldata_i(GEN ldata, long shallow) { long lx; if (is_linit(ldata)) ldata = linit_get_ldata(ldata); lx = lg(ldata); if (typ(ldata)==t_VEC && (lx == 7 || lx == 8) && is_tagged(ldata)) { if (!shallow) ldata = gcopy(ldata); checkldata(ldata); return ldata; } switch (lfundatatype(ldata)) { case t_LFUNMISC_POL: return lfunzetak(ldata); case t_LFUNMISC_CHIQUAD: return lfunchiquad(ldata); case t_LFUNMISC_CHICONREY: { GEN G = znstar0(gel(ldata,1), 1); return lfunchiZ(G, gel(ldata,2)); } case t_LFUNMISC_CHIGEN: return lfunchigen(gel(ldata,1), gel(ldata,2)); case t_LFUNMISC_ELLINIT: return lfunell(ldata); } pari_err_TYPE("lfunmisc_to_ldata",ldata); return NULL; /* LCOV_EXCL_LINE */ } GEN lfunmisc_to_ldata(GEN ldata) { return lfunmisc_to_ldata_i(ldata, 0); } GEN lfunmisc_to_ldata_shallow(GEN ldata) { return lfunmisc_to_ldata_i(ldata, 1); } /********************************************************************/ /** High-level an expansion **/ /********************************************************************/ /* van is the output of ldata_get_an: return a_1,...a_L at precision prec */ GEN ldata_vecan(GEN van, long L, long prec) { GEN an = gel(van, 2); long t = mael(van,1,1); pari_timer ti; if (DEBUGLEVEL >= 1) err_printf("Lfun: computing %ld coeffs, prec %ld, type %ld\n", L, prec, t); if (DEBUGLEVEL >= 2) timer_start(&ti); switch (t) { long n; case t_LFUN_GENERIC: an = vecan_closure(an, L, prec); n = lg(an)-1; if (n < L) pari_warn(warner, "#an = %ld < %ld, results may be imprecise", n, L); break; case t_LFUN_ZETA: an = const_vecsmall(L, 1); break; case t_LFUN_NF: an = dirzetak(an, stoi(L)); break; case t_LFUN_ELL: an = ellan(an, L); break; case t_LFUN_KRONECKER: an = vecan_Kronecker(an, L); break; case t_LFUN_CHIZ: an = vecan_chiZ(an, L, prec); break; case t_LFUN_CHIGEN: an = vecan_chigen(an, L, prec); break; case t_LFUN_ARTIN: an = vecan_artin(an, L, prec); break; case t_LFUN_ETA: an = vecan_eta(an, L); break; case t_LFUN_QF: an = vecan_qf(an, L); break; case t_LFUN_DIV: an = vecan_div(an, L, prec); break; case t_LFUN_MUL: an = vecan_mul(an, L, prec); break; case t_LFUN_CONJ: an = vecan_conj(an, L, prec); break; case t_LFUN_SYMPOW_ELL: an = vecan_ellsympow(an, L); break; case t_LFUN_GENUS2: an = vecan_genus2(an, L); break; case t_LFUN_MFCLOS: { GEN F = gel(an,1), E = gel(an,2), c = gel(an,3); an = mfcoefs(F,L,1) + 1; /* skip a_0 */ an[0] = evaltyp(t_VEC)|evallg(L+1); an = mfvecembed(E, an); if (!isint1(c)) an = RgV_Rg_mul(an,c); break; } case t_LFUN_TWIST: an = vecan_twist(an, L, prec); break; default: pari_err_TYPE("ldata_vecan", van); } if (DEBUGLEVEL >= 2) timer_printf(&ti, "ldata_vecan"); return an; } pari-2.11.2/src/basemath/hnf_snf.c0000644000175000017500000022472013326135265015333 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /**************************************************************/ /** **/ /** HERMITE NORMAL FORM REDUCTION **/ /** **/ /**************************************************************/ static GEN ZV_hnfgcdext(GEN A); static GEN hnfallgen(GEN x) { GEN z = cgetg(3, t_VEC); gel(z,1) = RgM_hnfall(x, (GEN*)(z+2), 1); return z; } GEN mathnf0(GEN x, long flag) { switch(typ(x)) { case t_VEC: if (RgV_is_ZV(x)) switch (flag) { case 0: if (lg(x) == 1) return cgetg(1, t_MAT); retmkmat(mkcol(ZV_content(x))); case 1: case 4: return ZV_hnfgcdext(x); } x = gtomat(x); break; case t_MAT: break; default: pari_err_TYPE("mathnf0",x); } switch(flag) { case 0: case 2: return RgM_is_ZM(x)? ZM_hnf(x): RgM_hnfall(x,NULL,1); case 1: case 3: return RgM_is_ZM(x)? hnfall(x): hnfallgen(x); case 4: RgM_check_ZM(x, "mathnf0"); return hnflll(x); case 5: RgM_check_ZM(x, "mathnf0"); return hnfperm(x); default: pari_err_FLAG("mathnf"); } return NULL; /* LCOV_EXCL_LINE */ } /*******************************************************************/ /* */ /* SPECIAL HNF (FOR INTERNAL USE !!!) */ /* */ /*******************************************************************/ static int count(GEN mat, long row, long len, long *firstnonzero) { long j, n = 0; for (j=1; j<=len; j++) { long p = mael(mat,j,row); if (p) { if (labs(p)!=1) return -1; n++; *firstnonzero=j; } } return n; } static int count2(GEN mat, long row, long len) { long j; for (j=len; j; j--) if (labs(mael(mat,j,row)) == 1) return j; return 0; } static GEN hnffinal(GEN matgen,GEN perm,GEN* ptdep,GEN* ptB,GEN* ptC) { GEN p1,p2,U,H,Hnew,Bnew,Cnew,diagH1; GEN B = *ptB, C = *ptC, dep = *ptdep, depnew; pari_sp av; long i,j,k,s,i1,j1,zc; long co = lg(C); long col = lg(matgen)-1; long lnz, nlze, lig; if (col == 0) return matgen; lnz = nbrows(matgen); /* was called lnz-1 - nr in hnfspec */ nlze = nbrows(dep); lig = nlze + lnz; /* H: lnz x lnz [disregarding initial 0 cols], U: col x col */ H = ZM_hnflll(matgen, &U, 0); H += (lg(H)-1 - lnz); H[0] = evaltyp(t_MAT) | evallg(lnz+1); /* Only keep the part above the H (above the 0s is 0 since the dep rows * are dependent from the ones in matgen) */ zc = col - lnz; /* # of 0 columns, correspond to units */ if (nlze) { dep = ZM_mul(dep,U); dep += zc; } diagH1 = new_chunk(lnz+1); /* diagH1[i] = 0 iff H[i,i] != 1 (set later) */ av = avma; Cnew = cgetg(co, typ(C)); setlg(C, col+1); p1 = gmul(C,U); for (j=1; j<=col; j++) gel(Cnew,j) = gel(p1,j); for ( ; j1) pari_warn(warnmem,"hnffinal, i = %ld",i); gerepileall(av, 2, &Cnew, &B); } } p1 = cgetg(lnz+1,t_VEC); p2 = perm + nlze; for (i1=0, j1=lnz-s, i=1; i<=lnz; i++) /* push the 1 rows down */ if (diagH1[i]) gel(p1,++j1) = gel(p2,i); else gel(p2,++i1) = gel(p2,i); for (i=i1+1; i<=lnz; i++) gel(p2,i) = gel(p1,i); /* s = # extra redundant generators taken from H * zc col-s co zc = col - lnz * [ 0 |dep | ] i = nlze + lnz - s = lig - s * nlze [--------| B' ] * [ 0 | H' | ] H' = H minus the s rows with a 1 on diagonal * i [--------|-----] lig-s (= "1-rows") * [ 0 | Id ] * [ | ] li */ lig -= s; col -= s; lnz -= s; Hnew = cgetg(lnz+1,t_MAT); depnew = cgetg(lnz+1,t_MAT); /* only used if nlze > 0 */ Bnew = cgetg(co-col,t_MAT); C = shallowcopy(Cnew); for (j=1,i1=j1=0; j<=lnz+s; j++) { GEN z = gel(H,j); if (diagH1[j]) { /* hit exactly s times */ i1++; C[i1+col] = Cnew[j+zc]; p1 = cgetg(lig+1,t_COL); gel(Bnew,i1) = p1; for (i=1; i<=nlze; i++) gel(p1,i) = gcoeff(dep,i,j); p1 += nlze; } else { j1++; C[j1+zc] = Cnew[j+zc]; p1 = cgetg(lnz+1,t_COL); gel(Hnew,j1) = p1; depnew[j1] = dep[j]; } for (i=k=1; k<=lnz; i++) if (!diagH1[i]) p1[k++] = z[i]; } for (j=s+1; j 6) err_printf("matgen = %Ps\n", zm_to_ZM( rowpermute(mat, perm) )); avma = av; } static GEN col_dup(long l, GEN col) { GEN c = new_chunk(l); memcpy(c,col,l * sizeof(long)); return c; } /* permutation giving imagecompl(x') | image(x'), x' = transpose of x */ static GEN ZM_rowrankprofile(GEN x, long *nlze) { pari_sp av = avma; GEN d, y; long i, j, k, l, r; x = shallowtrans(x); l = lg(x); (void)new_chunk(l); /* HACK */ d = ZM_pivots(x,&r); avma = av; *nlze = r; if (!d) return identity_perm(l-1); y = cgetg(l,t_VECSMALL); for (i = j = 1, k = r+1; i 300 && co > 1.5 * li) { /* treat the rest at the end */ co = (long)(1.2 * li); setlg(C, co); } if (DEBUGLEVEL>5) { err_printf("Entering hnfspec\n"); p_mat(mat0,perm,0); } matt = cgetg(co, t_MAT); /* dense part of mat (top) */ mat = cgetg(co, t_MAT); for (j = 1; j < co; j++) { GEN matj = col_dup(li, gel(mat0,j)); p1 = cgetg(k0+1,t_COL); gel(matt,j) = p1; gel(mat,j) = matj; for (i=1; i<=k0; i++) gel(p1,i) = stoi(matj[perm[i]]); } av = avma; i = lig = li-1; col = co-1; lk0 = k0; T = (k0 || (lg(C) > 1 && lgcols(C) > 1))? matid(col): NULL; /* Look for lines with a single non-0 entry, equal to 1 in absolute value */ while (i > lk0 && col) switch( count(mat,perm[i],col,&n) ) { case 0: /* move zero lines between k0+1 and lk0 */ lk0++; lswap(perm[i], perm[lk0]); i = lig; continue; case 1: /* move trivial generator between lig+1 and li */ lswap(perm[i], perm[lig]); if (T) swap(gel(T,n), gel(T,col)); swap(gel(mat,n), gel(mat,col)); p = gel(mat,col); if (p[perm[lig]] < 0) /* = -1 */ { /* convert relation -g = 0 to g = 0 */ for (i=lk0+1; i5) { err_printf(" after phase1:\n"); p_mat(mat,perm,0); } #define absmax(s,z) {long _z; _z = labs(z); if (_z > s) s = _z;} /* Get rid of all lines containing only 0 and +/- 1, keeping track of column * operations in T. Leave the rows 1..lk0 alone [up to k0, coefficient * explosion, between k0+1 and lk0, row is 0] */ s = 0; while (lig > lk0 && col && s < (long)(HIGHBIT>>1)) { for (i=lig; i>lk0; i--) if (count(mat,perm[i],col,&n) > 0) break; if (i == lk0) break; /* only 0, +/- 1 entries, at least 2 of them non-zero */ lswap(perm[i], perm[lig]); swap(gel(mat,n), gel(mat,col)); p = gel(mat,col); if (T) swap(gel(T,n), gel(T,col)); if (p[perm[lig]] < 0) { for (i=lk0+1; i<=lig; i++) p[perm[i]] = -p[perm[i]]; if (T) ZV_togglesign(gel(T,col)); } for (j=1; j1) pari_warn(warnmem,"hnfspec[1]"); if (T) T = gerepilecopy(av, T); else avma = av; } } /* As above with lines containing a +/- 1 (no other assumption). * Stop when single precision becomes dangerous */ vmax = cgetg(co,t_VECSMALL); for (j=1; j<=col; j++) { GEN matj = gel(mat,j); for (s=0, i=lk0+1; i<=lig; i++) absmax(s, matj[i]); vmax[j] = s; } while (lig > lk0 && col) { for (i=lig; i>lk0; i--) if ( (n = count2(mat,perm[i],col)) ) break; if (i == lk0) break; lswap(vmax[n], vmax[col]); lswap(perm[i], perm[lig]); swap(gel(mat,n), gel(mat,col)); p = gel(mat,col); if (T) swap(gel(T,n), gel(T,col)); if (p[perm[lig]] < 0) { for (i=lk0+1; i<=lig; i++) p[perm[i]] = -p[perm[i]]; if (T) ZV_togglesign(gel(T,col)); } for (j=1; j= (HIGHBIT-vmax[j]) / vmax[col]) goto END2; for (s=0, i=lk0+1; i<=lig; i++) absmax(s, matj[perm[i]] -= t*p[perm[i]]); vmax[j] = s; if (T) ZC_lincomb1_inplace(gel(T,j), gel(T,col), stoi(-t)); } lig--; col--; if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"hnfspec[2]"); gerepileall(av, T? 2: 1, &vmax, &T); } } END2: /* clean up mat: remove everything to the right of the 1s on diagonal */ /* go multiprecision first */ matb = cgetg(co,t_MAT); /* bottom part (complement of matt) */ for (j=1; j5) { err_printf(" after phase2:\n"); p_mat(mat,perm,lk0); } for (i=li-2; i>lig; i--) { long h, i0 = i - k0, k = i + co-li; GEN Bk = gel(matb,k); for (j=k+1; j 0) /* v = 1 */ { for (h=1; h1) pari_warn(warnmem,"hnfspec[3], (i,j) = %ld,%ld", i,j); for (h=1; h5) err_printf(" matb cleaned up (using Id block)\n"); nlze = lk0 - k0; /* # of 0 rows */ lnz = lig-nlze+1; /* 1 + # of non-0 rows (!= 0...0 1 0 ... 0) */ if (T) matt = ZM_mul(matt,T); /* update top rows */ extramat = cgetg(col+1,t_MAT); /* = new C minus the 0 rows */ for (j=1; j<=col; j++) { GEN z = gel(matt,j); GEN t = (gel(matb,j)) + nlze - k0; p2=cgetg(lnz,t_COL); gel(extramat,j) = p2; for (i=1; i<=k0; i++) gel(p2,i) = gel(z,i); /* top k0 rows */ for ( ; i co) { /* treat the rest, N cols at a time (hnflll slow otherwise) */ const long N = 300; long a, L = CO - co, l = minss(L, N); /* L columns to add */ GEN CC = *ptC, m0 = mat0; setlg(CC, CO); /* restore */ CC += co-1; m0 += co-1; for (a = l;;) { GEN MAT, emb; gerepileall(av, 4, &H,&C,ptB,ptdep); MAT = cgetg(l + 1, t_MAT); emb = cgetg(l + 1, typ(C)); for (j = 1 ; j <= l; j++) { gel(MAT,j) = gel(m0,j); emb[j] = CC[j]; } H = hnfadd_i(H, perm, ptdep, ptB, &C, MAT, emb); if (a == L) break; CC += l; m0 += l; a += l; if (a > L) { l = L - (a - l); a = L; } } } *ptC = C; return H; } GEN hnfspec(GEN mat, GEN perm, GEN* ptdep, GEN* ptB, GEN* ptC, long k0) { pari_sp av = avma; GEN H = hnfspec_i(mat, perm, ptdep, ptB, ptC, k0); gerepileall(av, 4, ptC, ptdep, ptB, &H); return H; } /* HNF reduce x, apply same transforms to C */ GEN mathnfspec(GEN x, GEN *ptperm, GEN *ptdep, GEN *ptB, GEN *ptC) { long i,j,k,ly,lx = lg(x); GEN z, perm; if (lx == 1) return cgetg(1, t_MAT); ly = lgcols(x); *ptperm = perm = identity_perm(ly-1); z = cgetg(lx,t_MAT); for (i=1; i 1 && lgcols(*ptC) > 1) pari_err_IMPL("mathnfspec with large entries"); x = ZM_hnf(x); lx = lg(x); j = ly; k = 0; for (i=1; i5) err_printf(" 1st phase done\n"); permpro = ZM_rowrankprofile(extramat, &nlze); extramat = rowpermute(extramat, permpro); *ptB = rowpermute(B, permpro); permpro = vecsmallpermute(perm, permpro); for (i=1; i<=lig; i++) perm[i] = permpro[i]; /* perm o= permpro */ *ptdep = rowslice(extramat, 1, nlze); matb = rowslice(extramat, nlze+1, lig); if (DEBUGLEVEL>5) err_printf(" 2nd phase done\n"); H = hnffinal(matb,perm,ptdep,ptB,&Cnew); *ptC = shallowconcat(vecslice(C, 1, col-lH), Cnew); return H; } GEN hnfadd(GEN H, GEN perm, GEN* ptdep, GEN* ptB, GEN* ptC, /* cf hnfspec */ GEN extramat,GEN extraC) { pari_sp av = avma; H = hnfadd_i(H, perm, ptdep, ptB, ptC, ZM_to_zm(extramat), extraC); gerepileall(av, 4, ptC, ptdep, ptB, &H); return H; } /* zero aj = Aij (!= 0) using ak = Aik (maybe 0), via linear combination of * A[j] and A[k] of determinant 1. If U != NULL, likewise update its columns */ static void ZC_elem(GEN aj, GEN ak, GEN A, GEN U, long j, long k) { GEN p1,u,v,d; if (!signe(ak)) { swap(gel(A,j), gel(A,k)); if (U) swap(gel(U,j), gel(U,k)); return; } d = bezout(aj,ak,&u,&v); /* frequent special case (u,v) = (1,0) or (0,1) */ if (!signe(u)) { /* ak | aj */ p1 = diviiexact(aj,ak); togglesign(p1); ZC_lincomb1_inplace(gel(A,j), gel(A,k), p1); if (U) ZC_lincomb1_inplace(gel(U,j), gel(U,k), p1); return; } if (!signe(v)) { /* aj | ak */ p1 = diviiexact(ak,aj); togglesign(p1); ZC_lincomb1_inplace(gel(A,k), gel(A,j), p1); swap(gel(A,j), gel(A,k)); if (U) { ZC_lincomb1_inplace(gel(U,k), gel(U,j), p1); swap(gel(U,j), gel(U,k)); } return; } if (!is_pm1(d)) { aj = diviiexact(aj, d); ak = diviiexact(ak, d); } p1 = gel(A,k); aj = negi(aj); /* NOT togglesign */ gel(A,k) = ZC_lincomb(u,v, gel(A,j),p1); gel(A,j) = ZC_lincomb(aj,ak, p1,gel(A,j)); if (U) { p1 = gel(U,k); gel(U,k) = ZC_lincomb(u,v, gel(U,j),p1); gel(U,j) = ZC_lincomb(aj,ak, p1,gel(U,j)); } } INLINE int is_RgX(GEN a, long v) { return typ(a) == t_POL && varn(a)==v; } /* set u,v such that au + bv = gcd(a,b), divide a,b by the gcd */ static GEN gbezout_step(GEN *pa, GEN *pb, GEN *pu, GEN *pv, long vx) { GEN a = *pa, b = *pb, d; if (gequal0(a)) { *pa = gen_0; *pu = gen_0; *pb = gen_1; *pv = gen_1; return b; } a = is_RgX(a,vx)? RgX_renormalize(a): scalarpol(a, vx); b = is_RgX(b,vx)? RgX_renormalize(b): scalarpol(b, vx); d = RgX_extgcd(a,b, pu,pv); if (degpol(d)) { a = RgX_div(a, d); b = RgX_div(b, d); } else if (typ(gel(d,2)) == t_REAL && lg(gel(d,2)) <= 3) #if 1 { /* possible accuracy problem */ GEN D = RgX_gcd_simple(a,b); if (degpol(D)) { D = RgX_normalize(D); a = RgX_div(a, D); b = RgX_div(b, D); d = RgX_extgcd(a,b, pu,pv); /* retry now */ d = RgX_mul(d, D); } } #else { /* less stable */ d = RgX_extgcd_simple(a,b, pu,pv); if (degpol(d)) { a = RgX_div(a, d); b = RgX_div(b, d); } } #endif *pa = a; *pb = b; return d; } static GEN col_mul(GEN x, GEN c) { if (typ(x) == t_INT) { long s = signe(x); if (!s) return NULL; if (is_pm1(x)) return (s > 0)? c: RgC_neg(c); } return RgC_Rg_mul(c, x); } static void do_zero(GEN x) { long i, lx = lg(x); for (i=1; i (long)BITS_IN_LONG)) { T = normalizepol_lg(T, lg(T)-1); if (!signe(T)) { *pd = gen_1; return T; } d = leading_coeff(T); } if (degpol(T)) T = RgX_Rg_div(T,d); else { d = gel(T,2); T = gen_1; } *pd = d; return T; } /* reduce A[i,j] mod A[i,j0] for j=j0+1... via column operations */ static void RgM_reduce(GEN A, GEN U, long i, long j0, long vx) { long j, lA = lg(A); GEN d, T = normalize_as_RgX(gcoeff(A,i,j0), vx, &d); if (U && !gequal1(d)) gel(U,j0) = RgC_Rg_div(gel(U,j0), d); gcoeff(A,i,j0) = T; for (j=j0+1; j 0. Return Au * in Z^n (v in Z^n not computed), such that Au + Bv = [1, 0, ..., 0] */ GEN hnfmerge_get_1(GEN A, GEN B) { pari_sp av = avma; long j, k, l = lg(A), lb; GEN b, U = cgetg(l + 1, t_MAT), C = cgetg(l + 1, t_VEC); b = gcoeff(B,1,1); lb = lgefint(b); for (j = 1; j < l; j++) { GEN t; long c = j+1; gel(U,j) = col_ei(l-1, j); gel(U,c) = zerocol(l-1); /* dummy */ gel(C,j) = vecslice(gel(A,j), 1,j); gel(C,c) = vecslice(gel(B,j), 1,j); for (k = j; k > 0; k--) { t = gcoeff(C,k,c); if (gequal0(t)) continue; setlg(C[c], k+1); ZC_elem(t, gcoeff(C,k,k), C, U, c, k); if (lgefint(gcoeff(C,k,k)) > lb) gel(C,k) = FpC_red(gel(C,k), b); if (j > 4) { GEN u = gel(U,k); long h; for (h=1; h lb) gel(u,h) = remii(gel(u,h), b); } } if (j == 1) t = gcoeff(C,1,1); else { GEN u; t = bezout(gcoeff(C,1,1), b, &u, NULL); /* >= 0 */ if (signe(u) && !equali1(u)) gel(U,1) = ZC_Z_mul(gel(U,1), u); gcoeff(C,1,1) = t; } if (equali1(t)) break; } if (j >= l) return NULL; b = lcmii(gcoeff(A,1,1),b); A = FpC_red(ZM_ZC_mul(A,gel(U,1)), b); return gerepileupto(av, FpC_center(A, b, shifti(b,-1))); } /* remove the first r columns */ static void remove_0cols(long r, GEN *pA, GEN *pB, long remove) { GEN A = *pA, B = *pB; long l = lg(A); A += r; A[0] = evaltyp(t_MAT) | evallg(l-r); if (B && remove == 2) { B += r; B[0] = A[0]; } *pA = A; *pB = B; } /* Inefficient compared to hnfall. 'remove' = throw away lin.dep columns */ static GEN hnf_i(GEN A, int remove) { pari_sp av0 = avma, av; long s, n, m, j, k, li, def, ldef; RgM_dimensions(A, &m, &n); if (!n) return cgetg(1,t_MAT); av = avma; A = RgM_shallowcopy(A); def = n; ldef = (m>n)? m-n: 0; for (li=m; li>ldef; li--) { for (j=def-1; j; j--) { GEN a = gcoeff(A,li,j); if (!signe(a)) continue; /* zero a = Aij using b = Aik */ k = (j==1)? def: j-1; ZC_elem(a,gcoeff(A,li,k), A,NULL, j,k); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnf[1]. li=%ld",li); A = gerepilecopy(av, A); } } s = signe(gcoeff(A,li,def)); if (s) { if (s < 0) ZV_neg_inplace(gel(A,def)); ZM_reduce(A, NULL, li,def); def--; } else if (ldef) ldef--; if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnf[2]. li=%ld",li); A = gerepilecopy(av, A); } } /* rank A = n - def */ if (remove) { GEN B = NULL; remove_0cols(def, &A, &B, remove); } return gerepileupto(av0, ZM_copy(A)); } GEN ZM_hnf(GEN x) { return lg(x) > 8? ZM_hnfall(x, NULL, 1): hnf_i(x, 1); } /* u*z[1..k] mod p, in place */ static void FpV_Fp_mul_part_ip(GEN z, GEN u, GEN p, long k) { long i; if (is_pm1(u)) { if (signe(u) > 0) { for (i = 1; i <= k; i++) if (signe(gel(z,i))) gel(z,i) = modii(gel(z,i), p); } else { for (i = 1; i <= k; i++) if (signe(gel(z,i))) gel(z,i) = modii(negi(gel(z,i)), p); } } else { for (i = 1; i <= k; i++) if (signe(gel(z,i))) gel(z,i) = Fp_mul(u,gel(z,i), p); } } static void FpV_red_part_ipvec(GEN z, GEN p, long k) { long i; for (i = 1; i <= k; i++) gel(z,i) = modii(gel(z,i), gel(p,i)); } /* return x * U, in echelon form (mod p^m), where (det(U),p) = 1. * If early_abort is set, return NULL as soon as one pivot is 0 (mod p^m) */ GEN ZpM_echelon(GEN x, long early_abort, GEN p, GEN pm) { pari_sp av0 = avma, av; long m, li, co, i, j, k, def, ldef; co = lg(x); if (co == 1) return cgetg(1,t_MAT); li = lgcols(x); av = avma; x = RgM_shallowcopy(x); m = Z_pval(pm, p); ldef = (li > co)? li - co: 0; for (def = co-1,i = li-1; i > ldef; i--) { long vmin = LONG_MAX, kmin = 0; GEN umin = gen_0, pvmin, q; for (k = 1; k <= def; k++) { GEN u = gcoeff(x,i,k); long v; if (!signe(u)) continue; v = Z_pvalrem(u, p, &u); if (v >= m) gcoeff(x,i,k) = gen_0; else if (v < vmin) { vmin = v; kmin = k; umin = u; if (!vmin) break; } } if (!kmin) { if (early_abort) return NULL; gcoeff(x,i,def) = gen_0; ldef--; if (ldef < 0) ldef = 0; continue; } if (kmin != def) swap(gel(x,def), gel(x,kmin)); q = vmin? powiu(p, m-vmin): pm; /* pivot has valuation vmin */ umin = modii(umin, q); if (!equali1(umin)) FpV_Fp_mul_part_ip(gel(x,def), Fp_inv(umin,q), pm, i-1); gcoeff(x, i, def) = pvmin = powiu(p, vmin); for (j = def-1; j; j--) { /* zero x[i, 1..def-1] using x[i,def] = pvmin */ GEN t, a = gcoeff(x,i,j) = modii(gcoeff(x,i,j), pm); if (!signe(a)) continue; t = diviiexact(a, pvmin); togglesign(t); ZC_lincomb1_inplace(gel(x,j), gel(x,def), t); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZpM_echelon. i=%ld",i); x = gerepilecopy(av, x); pvmin = gcoeff(x,i,def); } } def--; } if (co > li) { x += co - li; x[0] = evaltyp(t_MAT) | evallg(li); } return gerepilecopy(av0, x); } GEN zlm_echelon(GEN x, long early_abort, ulong p, ulong pm) { pari_sp av0 = avma; long li, co, i, j, k, def, ldef; ulong m; co = lg(x); if (co == 1) return cgetg(1,t_MAT); li = lgcols(x); x = Flm_copy(x); m = u_lval(pm, p); ldef = (li > co)? li - co: 0; for (def = co-1,i = li-1; i > ldef; i--) { long vmin = LONG_MAX, kmin = 0; ulong umin = 0, pvmin, q; for (k = 1; k <= def; k++) { ulong u = ucoeff(x,i,k); long v; if (!u) continue; v = u_lvalrem(u, p, &u); if (v >= (long) m) ucoeff(x,i,k) = 0; else if (v < vmin) { vmin = v; kmin = k; umin = u; if (!vmin) break; } } if (!kmin) { if (early_abort) return NULL; ucoeff(x,i,def) = 0; ldef--; if (ldef < 0) ldef = 0; continue; } if (kmin != def) swap(gel(x,def), gel(x,kmin)); q = vmin? upowuu(p, m-vmin): pm; /* pivot has valuation vmin */ umin %= q; if (umin != 1) Flv_Fl_mul_part_inplace(gel(x,def), Fl_inv(umin,q), pm, i-1); ucoeff(x, i, def) = pvmin = upowuu(p, vmin); for (j = def-1; j; j--) { /* zero x[i, 1..def-1] using x[i,def] = pvmin */ ulong t, a = ucoeff(x,i,j); if (!a) continue; t = Fl_neg(a / pvmin, q); Flc_lincomb1_inplace(gel(x,j), gel(x,def), t, pm); } def--; } if (co > li) { x += co - li; x[0] = evaltyp(t_MAT) | evallg(li); } return gerepilecopy(av0, x); } static int ZV_allequal(GEN v) { long i, l = lg(v); if (l > 1) { GEN x = gel(v,1); for (i = 2; i < l; i++) if (!equalii(x,gel(v,i))) return 0; } return 1; } /* compute optimal D for hnfmod: x upper triangular */ static GEN optimal_D(GEN x, GEN D) { long i, n = nbrows(x); GEN C = shallowcopy(D); gel(C,1) = gcoeff(x,1,1); for (i = 2; i < n; i++) { GEN c = mulii(gel(C,i-1), gcoeff(x,i,i)); if (signe(c) < 0) togglesign(c); if (cmpii(c, gel(D,i)) >= 0) break; gel(C,i) = c; } return C; } /* D = multiple of det x (usually detint(x)) or vector of positive moduli * (compute hnf(x | D)) * flag & hnf_MODID: reduce mod D * matid [ otherwise as above ]. * flag & hnf_PART: don't reduce once diagonal is known * flag & hnf_CENTER: centermod HNF (2|x[i,j]| <] x[i,i]) */ GEN ZM_hnfmodall_i(GEN x, GEN D, long flag) { pari_sp av; const long center = (flag & hnf_CENTER); long moddiag, modsame, nli, li, co, i, j, k, def, ldef; GEN u, LDM; co = lg(x); if (co == 1) { if (typ(D) == t_INT || lg(D) == 1) return cgetg(1,t_MAT); x = diagonal_shallow(D); /* handle flags properly */ co = lg(x); } li = lgcols(x); if (li == 1) { if (typ(D) != t_INT && lg(D) != li) pari_err_DIM("ZM_hnfmod"); return cgetg(1,t_MAT); } nli = li - 1; modsame = typ(D)==t_INT; if (!modsame) { if (lg(D) != li) pari_err_DIM("ZM_hnfmod"); if (ZV_allequal(D)) { modsame = 1; D = gel(D,1); } } moddiag = (flag & hnf_MODID) || !modsame; /* modsame: triangularize mod fixed d*Id; * moddiag: modulo diagonal matrix, else modulo multiple of determinant */ if (modsame) { LDM = const_vecsmall(nli, 2*lgefint(D)-2); D = const_vec(nli,D); } else { LDM = cgetg(li, t_VECSMALL); for (i=1; i co) { ldef = li - co; if (!moddiag) pari_err_DOMAIN("ZM_hnfmod","nb lines",">", strtoGENstr("nb columns"), x); } for (def = co-1,i = nli; i > ldef; i--,def--) { GEN d = gel(D,i); long add_N = modsame; for (j = 1; j < def; j++) { GEN p1, p2, b, a = gcoeff(x,i,j) = remii(gcoeff(x,i,j), d); if (!signe(a)) continue; k = j+1; b = gcoeff(x,i,k) = remii(gcoeff(x,i,k), d); if (!signe(b)) { swap(gel(x,j), gel(x,k)); continue; } if (add_N) { /* ensure the moving pivot on row i divides d from now on */ add_N = 0; if (!equali1(a)) { /* x[j] *= u; after this, a = x[i,j] | d */ GEN u = Fp_invgen(a, d, &a); long t; p1 = gel(x,j); for (t = 1; t < i; t++) gel(p1,t) = mulii(gel(p1,t), u); FpV_red_part_ipvec(p1, D, i-1); gel(p1,i) = a; if (2*lg(a) < lg(b)) { /* reduce x[i,k] mod x[i,j]: helps ZC_elem */ GEN r, q = dvmdii(b, a, &r); togglesign(q); ZC_lincomb1_inplace_i(gel(x,k), gel(x,j), q, i-1); FpV_red_part_ipvec(gel(x,k), D, i-1); gcoeff(x,i,k) = b = r; } } } ZC_elem(a,b, x, NULL, j,k); p1 = gel(x,j); p2 = gel(x,k); /* prevent coeffs explosion */ for (k = 1; k < i; k++) { if (lgefint(gel(p1,k)) > LDM[k]) gel(p1,k) = remii(gel(p1,k),gel(D,k)); if (lgefint(gel(p2,k)) > LDM[k]) gel(p2,k) = remii(gel(p2,k),gel(D,k)); } } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnfmod[1]. i=%ld",i); x = gerepilecopy(av, x); } if (moddiag && !signe(gcoeff(x,i,def))) { /* missing pivot on line i, insert column */ GEN a = cgetg(co + 1, t_MAT); for (k = 1; k <= def; k++) gel(a,k) = gel(x,k); gel(a,k++) = Rg_col_ei(gel(D,i), nli, i); for ( ; k <= co; k++) gel(a,k) = gel(x,k-1); ldef--; if (ldef < 0) ldef = 0; co++; def++; x = a; } } if (co < li) { /* implies moddiag, add missing diag(D) components */ GEN a = cgetg(li+1, t_MAT); for (k = 1; k <= li-co; k++) gel(a,k) = Rg_col_ei(gel(D,k), nli, k); for (i = 1; i < co; i++) gel(a,k-1+i) = gel(x,i); gel(a,li) = zerocol(nli); x = a; } else { x += co - li; x[0] = evaltyp(t_MAT) | evallg(li); /* kill 0 columns */ if (moddiag) x = shallowconcat(x, zerocol(nli)); } if (moddiag) { /* x[li]: extra column, an accumulator discarded at the end */ GEN D2; gcoeff(x,1,1) = gcdii(gcoeff(x,1,1), gel(D,1)); D2 = optimal_D(x,D); /* add up missing diag(D) components */ for (i = nli; i > 0; i--) { gcoeff(x, i, li) = gel(D,i); for (j = i; j > 0; j--) { GEN a = gcoeff(x, j, li); if (!signe(a)) continue; ZC_elem(a, gcoeff(x,j,j), x, NULL, li,j); FpV_red_part_ipvec(gel(x,li), D, j-1); FpV_red_part_ipvec(gel(x,j), D, j-1); } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnfmod[2]. i=%ld", i); gerepileall(av, 2, &x, &D2); } } D = D2; } else { GEN b = gel(D,1); for (i = nli; i > 0; i--) { GEN d = bezout(gcoeff(x,i,i),b, &u,NULL); gcoeff(x,i,i) = d; FpV_Fp_mul_part_ip(gel(x,i), u, b, i-1); if (i > 1) b = diviiexact(b,d); } D = optimal_D(x,D); } x[0] = evaltyp(t_MAT) | evallg(li); /* kill 0 columns / discard accumulator */ if (flag & hnf_PART) return x; for (i = nli; i > 0; i--) { GEN diag = gcoeff(x,i,i); if (signe(diag) < 0) { gel(x,i) = ZC_neg(gel(x,i)); diag = gcoeff(x,i,i); } if (i != nli) for (j = 1; j < i; j++) gcoeff(x,j,i) = remii(gcoeff(x,j,i), gel(D,j)); for (j = i+1; j < li; j++) { GEN b = gcoeff(x,i,j) = remii(gcoeff(x,i,j), gel(D,i)); GEN r, q = truedvmdii(b, diag, &r); /* ensure -diag/2 <= r < diag/2 */ if (center && signe(r) && abscmpii(shifti(r,1),diag) >= 0) { r = subii(r,diag); q = addiu(q,1); } if (!signe(q)) continue; togglesign(q); ZC_lincomb1_inplace_i(gel(x,j), gel(x,i), q, i-1); gcoeff(x,i,j) = r; } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnfmod[3]. i=%ld", i); gerepileall(av, 2, &x, &D); } } return x; } GEN ZM_hnfmodall(GEN x, GEN dm, long flag) { pari_sp av = avma; return gerepilecopy(av, ZM_hnfmodall_i(x, dm, flag)); } GEN ZM_hnfmod(GEN x, GEN d) { return ZM_hnfmodall(x,d,0); } GEN ZM_hnfmodid(GEN x, GEN d) { return ZM_hnfmodall(x,d,hnf_MODID); } /* return the column echelon form of x with 1's as pivots, * P contains the row indices containing the pivots in increasing order */ static GEN FpM_echelon(GEN x, GEN *pP, GEN p) { pari_sp av; long iP, li, co, i, j, k, def, ldef; GEN P; co = lg(x); if (co == 1) { *pP = cgetg(1,t_VECSMALL); return cgetg(1,t_MAT); } li = lgcols(x); iP = 1; *pP = P = cgetg(li, t_VECSMALL); av = avma; x = FpM_red(x, p); ldef = (li > co)? li - co: 0; for (def = co-1,i = li-1; i > ldef; i--) { GEN u = NULL; for (k = def; k; k--) { u = gcoeff(x,i,k); if (signe(u)) break; } if (!k) { if (--ldef < 0) ldef = 0; continue; } P[iP++] = i; if (k != def) swap(gel(x,def), gel(x,k)); if (!equali1(u)) FpV_Fp_mul_part_ip(gel(x,def), Fp_inv(u,p), p, i-1); gcoeff(x, i, def) = gen_1; for (j = def-1; j; j--) { /* zero x[i, 1..def-1] using x[i,def] = 1*/ GEN xj = gel(x,j), u = gel(xj,i); if (!signe(u)) continue; ZC_lincomb1_inplace(xj, gel(x,def), negi(u)); for (k = 1; k < i; k++) gel(xj,k) = modii(gel(xj,k), p); } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpM_echelon. i=%ld",i); x = gerepilecopy(av, x); } def--; } /* rank = iP - 1 */ setlg(P, iP); vecsmall_sort(P); if (co > iP) x += co - iP; x[0] = evaltyp(t_MAT) | evallg(iP); return x; } /* given x square of maximal rank with 1 or p on diagonal from hnfmodid * (=> a column containing p has its other entries at 0 ), return the HNF */ static GEN FpM_hnfend(pari_sp av, GEN x, GEN p) { long i, l = lgcols(x); for (i = l-1; i > 0; i--) { GEN diag = gcoeff(x,i,i); long j; if (is_pm1(diag)) for (j = i+1; j < l; j++) { GEN xj = gel(x,j), b = gel(xj,i); long k; if (!signe(b)) continue; ZC_lincomb1_inplace(xj, gel(x,i), negi(b)); for (k=1; k 3) gel(xj,k) = remii(gel(xj,k), p); } else for (j = i+1; j < l; j++) gcoeff(x,i,j) = modii(gcoeff(x,i,j), p); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"FpM_hnfend. i=%ld",i); x = gerepilecopy(av, x); } } return x; } GEN ZM_hnfmodprime(GEN x, GEN p) { pari_sp av = avma; GEN P, y; long l, lP, i; if (lg(x) == 1) return cgetg(1, t_MAT); l = lgcols(x); x = FpM_echelon(x, &P, p); lP = lg(P); /* rank = lP-1 */ if (lP == l) { avma = av; return matid(l-1); } y = scalarmat_shallow(p, l-1); for (i = 1; i < lP; i++) gel(y,P[i]) = gel(x,i); return gerepilecopy(av, FpM_hnfend(av,y,p)); } static GEN allhnfmod(GEN x, GEN dm, int flag) { if (typ(x)!=t_MAT) pari_err_TYPE("allhnfmod",x); RgM_check_ZM(x, "allhnfmod"); if (isintzero(dm)) return ZM_hnf(x); return ZM_hnfmodall(x, dm, flag); } GEN hnfmod(GEN x, GEN d) { if (typ(d) != t_INT) pari_err_TYPE("mathnfmod",d); return allhnfmod(x, d, 0); } GEN hnfmodid(GEN x, GEN d) { switch(typ(d)) { case t_INT: break; case t_VEC: case t_COL: if (RgV_is_ZV(d)) break; default: pari_err_TYPE("mathnfmodid",d); } return allhnfmod(x, d, hnf_MODID); } /* M a ZM in HNF. Normalize with *centered* residues */ GEN ZM_hnfcenter(GEN M) { long i, j, k, N = lg(M)-1; pari_sp av = avma; for (j=N-1; j>0; j--) /* skip last line */ { GEN Mj = gel(M,j), a = gel(Mj,j); for (k = j+1; k <= N; k++) { GEN Mk = gel(M,k), q = diviiround(gel(Mk,j), a); long s = signe(q); if (!s) continue; if (is_pm1(q)) { if (s < 0) for (i = 1; i <= j; i++) gel(Mk,i) = addii(gel(Mk,i), gel(Mj,i)); else for (i = 1; i <= j; i++) gel(Mk,i) = subii(gel(Mk,i), gel(Mj,i)); } else for (i = 1; i <= j; i++) gel(Mk,i) = subii(gel(Mk,i), mulii(q,gel(Mj,i))); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnfcenter, j = %ld",j); M = gerepilecopy(av, M); } } } return M; } /***********************************************************************/ /* */ /* HNFLLL (Havas, Majewski, Mathews) */ /* */ /***********************************************************************/ static void Minus(long j, GEN lambda) { long k, n = lg(lambda); for (k=1 ; k 0) q = diviiround(gcoeff(lambda,j,k), gel(D,j)); else return; if (signe(q)) { GEN Lk = gel(lambda,k), Lj = gel(lambda,j); togglesign_safe(&q); if (*row0) ZC_lincomb1_inplace(gel(A,k),gel(A,j),q); if (B) ZC_lincomb1_inplace(gel(B,k),gel(B,j),q); gel(Lk,j) = addmulii(gel(Lk,j), q, gel(D,j)); if (is_pm1(q)) { if (signe(q) > 0) { for (i=1; i>1 : if h = 2i even, no need to swap c[i] and itself */ for (i=(h-1)>>1; i; i--) swap(gel(c,i), gel(c,h-i)); } return A; } /* decide whether to swap */ static int must_swap(long k, GEN lambda, GEN D) { pari_sp av = avma; GEN z = addii(mulii(gel(D,k-2),gel(D,k)), sqri(gcoeff(lambda,k-1,k))); long s = cmpii(z, sqri(gel(D,k-1))); avma = av; return s < 0; } GEN ZM_hnflll(GEN A, GEN *ptB, int remove) { pari_sp av = avma; long n, k, kmax; GEN B, lambda, D; n = lg(A); A = reverse_rows(ZM_copy(A)); /* ZM_copy for in place findi_normalize() */ B = ptB? matid(n-1): NULL; D = const_vec(n, gen_1) + 1; lambda = zeromatcopy(n-1,n-1); k = kmax = 2; while (k < n) { long row0, row1; int do_swap; reduce2(A,B,k,k-1,&row0,&row1,lambda,D); if (row0) do_swap = (!row1 || row0 <= row1); else if (row1) do_swap = 0; else do_swap = must_swap(k,lambda,D); if (do_swap) { hnfswap(A,B,k,lambda,D); if (k > 2) k--; } else { long i; for (i=k-2; i; i--) { long row0, row1; reduce2(A,B,k,i,&row0,&row1,lambda,D); if (gc_needed(av,3)) { GEN b = D-1; if (DEBUGMEM>1) pari_warn(warnmem,"hnflll (reducing), kmax = %ld",kmax); gerepileall(av, B? 4: 3, &A, &lambda, &b, &B); D = b+1; } } if (++k > kmax) kmax = k; } if (gc_needed(av,3)) { GEN b = D-1; if (DEBUGMEM>1) pari_warn(warnmem,"hnflll, kmax = %ld / %ld",kmax,n-1); gerepileall(av, B? 4: 3, &A, &lambda, &b, &B); D = b+1; } } /* handle trivial case: return negative diag coefficient otherwise */ if (n == 2) (void)findi_normalize(gel(A,1), B,1,lambda); A = reverse_rows(A); if (remove) { long i; for (i = 1; i < n; i++) if (!ZV_equal0(gel(A,i))) break; remove_0cols(i-1, &A, &B, remove); } gerepileall(av, B? 2: 1, &A, &B); if (B) *ptB = B; return A; } GEN hnflll(GEN x) { GEN z = cgetg(3, t_VEC); gel(z,1) = ZM_hnflll(x, &gel(z,2), 1); return z; } /* Variation on HNFLLL: Extended GCD */ static void reduce1(GEN A, GEN B, long k, long j, GEN lambda, GEN D) { GEN q; long i; if (signe(gel(A,j))) q = diviiround(gel(A,k),gel(A,j)); else if (abscmpii(shifti(gcoeff(lambda,j,k), 1), gel(D,j)) > 0) q = diviiround(gcoeff(lambda,j,k), gel(D,j)); else return; if (signe(q)) { GEN Lk = gel(lambda,k), Lj = gel(lambda,j); togglesign_safe(&q); gel(A,k) = addmulii(gel(A,k), q, gel(A,j)); ZC_lincomb1_inplace(gel(B,k),gel(B,j),q); gel(Lk,j) = addmulii(gel(Lk,j), q, gel(D,j)); for (i=1; i 2) k--; } else { long i; for (i=k-2; i; i--) reduce1(A,B,k,i,lambda,D); k++; } } if (signe(gel(A,n-1)) < 0) { gel(A,n-1) = negi(gel(A,n-1)); ZV_togglesign(gel(B,n-1)); } return mkvec2(gel(A,n-1), B); } GEN ZV_extgcd(GEN A) { pari_sp av = avma; return gerepilecopy(av, ZV_gcdext_i(A)); } /* as ZV_extgcd, transforming the gcd into a t_MAT, for mathnf0 */ static GEN ZV_hnfgcdext(GEN A) { pari_sp av = avma; GEN z; if (lg(A) == 1) retmkvec2(cgetg(1,t_MAT),cgetg(1,t_MAT)); z = ZV_gcdext_i(A); gel(z,1) = mkmat(mkcol(gel(z,1))); return gerepilecopy(av, z); } /* HNF with permutation. */ GEN ZM_hnfperm(GEN A, GEN *ptU, GEN *ptperm) { GEN U, c, l, perm, d, p, q, b; pari_sp av = avma, av1; long r, t, i, j, j1, k, m, n; n = lg(A)-1; if (!n) { if (ptU) *ptU = cgetg(1,t_MAT); if (ptperm) *ptperm = cgetg(1,t_VEC); return cgetg(1, t_MAT); } m = nbrows(A); c = zero_zv(m); l = zero_zv(n); perm = cgetg(m+1, t_VECSMALL); av1 = avma; A = RgM_shallowcopy(A); U = ptU? matid(n): NULL; /* U base change matrix : A0*U = A all along */ for (r=0, k=1; k <= n; k++) { for (j=1; j 0) { p = q; t = i; } } perm[++r] = l[k] = t; c[t] = k; if (signe(p) < 0) { ZV_neg_inplace(gel(A,k)); if (U) ZV_togglesign(gel(U,k)); p = gcoeff(A,t,k); } /* p > 0 */ for (j=1; j1) pari_warn(warnmem,"hnfperm, k=%ld",k); gerepileall(av1, U? 2: 1, &A, &U); } } if (r < m) { for (i=1,k=r; i<=m; i++) if (!c[i]) perm[++k] = i; } /* We have A0*U=A, U in Gl(n,Z) * basis for Im(A): columns of A s.t l[j]>0 (r cols) * basis for Ker(A): columns of U s.t l[j]=0 (n-r cols) */ p = cgetg(r+1,t_MAT); for (i=1; i<=m/2; i++) lswap(perm[i], perm[m+1-i]); if (U) { GEN u = cgetg(n+1,t_MAT); for (t=1,k=r,j=1; j<=n; j++) if (l[j]) { u[k + n-r] = U[j]; gel(p,k--) = vecpermute(gel(A,j), perm); } else u[t++] = U[j]; *ptU = u; if (ptperm) *ptperm = perm; gerepileall(av, ptperm? 3: 2, &p, ptU, ptperm); } else { for (k=r,j=1; j<=n; j++) if (l[j]) gel(p,k--) = vecpermute(gel(A,j), perm); if (ptperm) *ptperm = perm; gerepileall(av, ptperm? 2: 1, &p, ptperm); } return p; } GEN ZM_hnf_knapsack(GEN x) { GEN t, perm, H = ZM_hnfperm(x,NULL,&perm); long i,j, l = lg(H), h = lgcols(H); for (i=1; ili; i--) { a = gcoeff(A,i,j); k = c[i]; /* zero a = Aij using Aik */ if (signe(a)) ZC_elem(a,gcoeff(A,i,k), A,B,j,k); ZM_reduce(A,B, i,k); /* ensure reduced entries even if a = 0 */ if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnfall[1], li = %ld, j = %ld", li, j); gerepileall(av, B? 2: 1, &A, &B); } } if (signe( gcoeff(A,li,j) )) break; h[j] = li-1; } if (j == r) continue; r--; if (j < r) /* A[j] != 0 */ { swap(gel(A,j), gel(A,r)); if (B) swap(gel(B,j), gel(B,r)); h[j] = h[r]; h[r] = li; c[li] = r; } if (signe(gcoeff(A,li,r)) < 0) { ZV_neg_inplace(gel(A,r)); if (B) ZV_togglesign(gel(B,r)); } ZM_reduce(A,B, li,r); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnfall[2], li = %ld", li); gerepileall(av, B? 2: 1, &A, &B); } } if (DEBUGLEVEL>5) err_printf("\nhnfall, final phase: "); r--; /* first r cols are in the image the n-r (independent) last ones */ for (j=1; j<=r; j++) for (i=h[j]; i; i--) { a = gcoeff(A,i,j); k = c[i]; if (signe(a)) ZC_elem(a,gcoeff(A,i,k), A,B, j,k); ZM_reduce(A,B, i,k); /* ensure reduced entries, even if a = 0 */ if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ZM_hnfall[3], j = %ld", j); gerepileall(av, B? 2: 1, &A, &B); } } if (DEBUGLEVEL>5) err_printf("\n"); if (remove) remove_0cols(r, &A, &B, remove); if (ptB) *ptB = B; return A; } GEN ZM_hnfall(GEN A, GEN *ptB, long remove) { pari_sp av = avma; A = ZM_hnfall_i(A, ptB, remove); gerepileall(av, ptB? 2: 1, &A, ptB); return A; } GEN hnfall(GEN x) { GEN z = cgetg(3, t_VEC); gel(z,1) = ZM_hnfall(x, (GEN*)(z+2), 1); return z; } GEN hnf(GEN x) { return mathnf0(x,0); } /* C = A^(-1)t where A and C are integral, A is upper triangular, t t_INT */ GEN hnf_invscale(GEN A, GEN t) { long n = lg(A)-1, i,j,k; GEN m, c = cgetg(n+1,t_MAT); if (!n) return c; for (k=1; k<=n; k++) { /* cf hnf_divscale with B = id, thus b = e_k */ GEN u = cgetg(n+1, t_COL); pari_sp av = avma; gel(c,k) = u; gel(u,n) = k == n? gerepileuptoint(av, diviiexact(t, gcoeff(A,n,n))): gen_0; for (i=n-1; i>0; i--) { av = avma; m = i == k? t: gen_0; for (j=i+1; j<=n; j++) m = subii(m, mulii(gcoeff(A,i,j),gel(u,j))); gel(u,i) = gerepileuptoint(av, diviiexact(m, gcoeff(A,i,i))); } } return c; } /* C = A^(-1)(tB) where A, B, C are integral, A is upper triangular, t t_INT */ GEN hnf_divscale(GEN A, GEN B, GEN t) { long n = lg(A)-1, i,j,k; GEN m, c = cgetg(n+1,t_MAT); if (!n) return c; for (k=1; k<=n; k++) { GEN u = cgetg(n+1, t_COL), b = gel(B,k); pari_sp av = avma; gel(c,k) = u; m = mulii(gel(b,n),t); gel(u,n) = gerepileuptoint(av, diviiexact(m, gcoeff(A,n,n))); for (i=n-1; i>0; i--) { av = avma; m = mulii(gel(b,i),t); for (j=i+1; j<=n; j++) m = subii(m, mulii(gcoeff(A,i,j),gel(u,j))); gel(u,i) = gerepileuptoint(av, diviiexact(m, gcoeff(A,i,i))); } } return c; } /* A, B integral upper HNF. A^(-1) B integral ? */ int hnfdivide(GEN A, GEN B) { pari_sp av = avma; long n = lg(A)-1, i,j,k; GEN u, b, m, r; if (!n) return 1; if (lg(B)-1 != n) pari_err_DIM("hnfdivide"); u = cgetg(n+1, t_COL); for (k=1; k<=n; k++) { b = gel(B,k); m = gel(b,k); gel(u,k) = dvmdii(m, gcoeff(A,k,k), &r); if (r != gen_0) { avma = av; return 0; } for (i=k-1; i>0; i--) { m = gel(b,i); for (j=i+1; j<=k; j++) m = subii(m, mulii(gcoeff(A,i,j),gel(u,j))); m = dvmdii(m, gcoeff(A,i,i), &r); if (r != gen_0) { avma = av; return 0; } gel(u,i) = m; } } avma = av; return 1; } /* A upper HNF, b integral vector. Return A^(-1) b if integral, * NULL otherwise. Assume #A[,1] = #b. */ GEN hnf_invimage(GEN A, GEN b) { pari_sp av = avma; long n = lg(A)-1, m, i, k; GEN u, r; if (!n) return lg(b)==1? cgetg(1,t_COL):NULL; m = nbrows(A); /* m >= n */ u = cgetg(n+1, t_COL); for (i = n, k = m; k > 0; k--) { pari_sp av2 = avma; long j; GEN t = gel(b,k), Aki = gcoeff(A,k,i); if (typ(t) != t_INT) pari_err_TYPE("hnf_invimage",t); for (j=i+1; j<=n; j++) t = subii(t, mulii(gcoeff(A,k,j),gel(u,j))); if (!signe(Aki)) { if (signe(t)) { avma = av;return NULL; } avma = av2; gel(u,i) = gen_0; continue; } t = dvmdii(t, Aki, &r); if (r != gen_0) { avma = av; return NULL; } gel(u,i) = gerepileuptoint(av2, t); if (--i == 0) break; } /* If there is a solution, it must be u. Check remaining equations */ for (; k > 0; k--) { pari_sp av2 = avma; long j; GEN t = gel(b,k); if (typ(t) != t_INT) pari_err_TYPE("hnf_invimage",t); for (j=1; j<=n; j++) t = subii(t, mulii(gcoeff(A,k,j),gel(u,j))); if (signe(t)) { avma = av;return NULL; } avma = av2; } return u; } /* A upper HNF, B integral matrix or column. Return A^(-1) B if integral, * NULL otherwise */ GEN hnf_solve(GEN A, GEN B) { pari_sp av; long i, l; GEN C; if (typ(B) == t_COL) return hnf_invimage(A, B); av = avma; C = cgetg_copy(B, &l); for (i = 1; i < l; i++) { GEN c = hnf_invimage(A, gel(B,i)); if (!c) { avma = av; return NULL; } gel(C,i) = c; } return C; } /***************************************************************/ /** **/ /** SMITH NORMAL FORM REDUCTION **/ /** **/ /***************************************************************/ static GEN trivsmith(long all) { GEN z; if (!all) return cgetg(1,t_VEC); z=cgetg(4,t_VEC); gel(z,1) = cgetg(1,t_MAT); gel(z,2) = cgetg(1,t_MAT); gel(z,3) = cgetg(1,t_MAT); return z; } static void snf_pile(pari_sp av, GEN *x, GEN *U, GEN *V) { GEN *gptr[3]; int c = 1; gptr[0]=x; if (*U) gptr[c++] = U; if (*V) gptr[c++] = V; gerepilemany(av,gptr,c); } static GEN bezout_step(GEN *pa, GEN *pb, GEN *pu, GEN *pv) { GEN a = *pa, b = *pb, d; if (absequalii(a,b)) { long sa = signe(a), sb = signe(b); *pv = gen_0; if (sb == sa) { *pa = *pb = gen_1; if (sa > 0) {*pu=gen_1; return a;} else {*pu=gen_m1; return absi(a);} } if (sa > 0) { *pa = *pu = gen_1; *pb = gen_m1; return a; } *pa = *pu = gen_m1; *pb = gen_1; return b; } d = bezout(a,b, pu,pv); *pa = diviiexact(a, d); *pb = diviiexact(b, d); return d; } static int negcmpii(void *E, GEN x, GEN y) { (void)E; return -cmpii(x,y); } /* does b = x[i,i] divide all entries in x[1..i-1,1..i-1] ? If so, return 0; * else return the index of a problematic row */ static long ZM_snf_no_divide(GEN x, long i) { GEN b = gcoeff(x,i,i); long j, k; if (!signe(b)) { /* impossible in the current implementation : x square of maximal rank */ for (k = 1; k < i; k++) for (j = 1; j < i; j++) if (signe(gcoeff(x,k,j))) return k; return 0; } if (is_pm1(b)) return 0; for (k = 1; k < i; k++) for (j = 1; j < i; j++) if (!dvdii(gcoeff(x,k,j),b)) return k; return 0; } /* Return the SNF D of matrix X. If ptU/ptV non-NULL set them to U/V * to that D = UXV */ GEN ZM_snfall_i(GEN x, GEN *ptU, GEN *ptV, int return_vec) { pari_sp av0 = avma, av; long i, j, k, m0, m, n0, n; GEN p1, u, v, U, V, V0, mdet, ys, perm = NULL; n0 = n = lg(x)-1; if (!n) { if (ptU) *ptU = cgetg(1,t_MAT); if (ptV) *ptV = cgetg(1,t_MAT); return cgetg(1, return_vec? t_VEC: t_MAT); } av = avma; m0 = m = nbrows(x); U = ptU? gen_1: NULL; /* TRANSPOSE of row transform matrix [act on columns]*/ V = ptV? gen_1: NULL; V0 = NULL; x = RgM_shallowcopy(x); if (m == n && ZM_ishnf(x)) { mdet = ZM_det_triangular(x); if (V) *ptV = matid(n); } else { mdet = ZM_detmult(x); if (signe(mdet)) { if (!V) p1 = ZM_hnfmod(x,mdet); else { if (m == n) { p1 = ZM_hnfmod(x,mdet); *ptV = RgM_solve(x,p1); } else p1 = ZM_hnfperm(x, ptV, ptU? &perm: NULL); } mdet = ZM_det_triangular(p1); } else p1 = ZM_hnfperm(x, ptV, ptU? &perm: NULL); x = p1; } n = lg(x)-1; if (V) { V = *ptV; if (n != n0) { V0 = vecslice(V, 1, n0 - n); /* kernel */ V = vecslice(V, n0-n+1, n0); av = avma; } } /* independent columns */ if (!signe(mdet)) { if (n) { x = ZM_snfall_i(shallowtrans(x), ptV, ptU, return_vec); /* swap ptV,ptU */ if (typ(x) == t_MAT && n != m) x = shallowtrans(x); if (V) V = ZM_mul(V, shallowtrans(*ptV)); if (U) U = *ptU; /* TRANSPOSE */ } else /* 0 matrix */ { x = cgetg(1,t_MAT); if (V) V = cgetg(1, t_MAT); if (U) U = matid(m); } goto THEEND; } if (U) U = matid(n); /* square, maximal rank n */ p1 = gen_indexsort(RgM_diagonal_shallow(x), NULL, &negcmpii); ys = cgetg(n+1,t_MAT); for (j=1; j<=n; j++) gel(ys,j) = vecpermute(gel(x, p1[j]), p1); x = ys; if (U) U = vecpermute(U, p1); if (V) V = vecpermute(V, p1); p1 = ZM_hnfmod(x, mdet); if (V) V = ZM_mul(V, RgM_solve(x,p1)); x = p1; if (DEBUGLEVEL>7) err_printf("starting SNF loop"); for (i=n; i>1; i--) { if (DEBUGLEVEL>7) err_printf("\ni = %ld: ",i); for(;;) { int c = 0; GEN a, b; for (j=i-1; j>=1; j--) { b = gcoeff(x,i,j); if (!signe(b)) continue; a = gcoeff(x,i,i); ZC_elem(b, a, x,V, j,i); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"[1]: ZM_snfall i = %ld", i); snf_pile(av, &x,&U,&V); } } if (DEBUGLEVEL>7) err_printf("; "); for (j=i-1; j>=1; j--) { GEN d; b = gcoeff(x,j,i); if (!signe(b)) continue; a = gcoeff(x,i,i); d = bezout_step(&a, &b, &u, &v); for (k = 1; k < i; k++) { GEN t = addii(mulii(u,gcoeff(x,i,k)),mulii(v,gcoeff(x,j,k))); gcoeff(x,j,k) = subii(mulii(a,gcoeff(x,j,k)), mulii(b,gcoeff(x,i,k))); gcoeff(x,i,k) = t; } gcoeff(x,j,i) = gen_0; gcoeff(x,i,i) = d; if (U) update(u,v,a,b,(GEN*)(U+i),(GEN*)(U+j)); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"[2]: ZM_snfall, i = %ld", i); snf_pile(av, &x,&U,&V); } c = 1; } if (!c) { k = ZM_snf_no_divide(x, i); if (!k) break; /* x[k,j] != 0 mod b */ for (j=1; j<=i; j++) gcoeff(x,i,j) = addii(gcoeff(x,i,j),gcoeff(x,k,j)); if (U) gel(U,i) = gadd(gel(U,i),gel(U,k)); } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"[3]: ZM_snfall"); snf_pile(av, &x,&U,&V); } } } if (DEBUGLEVEL>7) err_printf("\n"); for (k=1; k<=n; k++) if (signe(gcoeff(x,k,k)) < 0) { if (V) ZV_togglesign(gel(V,k)); togglesign(gcoeff(x,k,k)); } THEEND: if (return_vec) { long l = lg(x)-1; if (typ(x) == t_MAT) x = RgM_diagonal_shallow(x); if (m0 > l) x = shallowconcat(zerovec(m0-l), x); } if (V0) { if (!return_vec) x = shallowconcat(zeromat(m,n0-n), x); if (V) V = shallowconcat(V0, V); } if (U) { U = shallowtrans(U); if (perm) U = vecpermute(U, perm_inv(perm)); } snf_pile(av0, &x,&U,&V); if (ptU) *ptU = U; if (ptV) *ptV = V; return x; } GEN ZM_snfall(GEN x, GEN *U, GEN *V) { return ZM_snfall_i(x, U, V, 0); } GEN ZM_snf(GEN x) { return ZM_snfall_i(x, NULL,NULL, 1); } GEN smith(GEN x) { if (typ(x)!=t_MAT) pari_err_TYPE("smith",x); RgM_check_ZM(x, "smith"); return ZM_snfall_i(x, NULL,NULL, 1); } GEN smithall(GEN x) { GEN z = cgetg(4, t_VEC); if (typ(x)!=t_MAT) pari_err_TYPE("smithall",x); RgM_check_ZM(x, "smithall"); gel(z,3) = ZM_snfall_i(x, (GEN*)(z+1),(GEN*)(z+2), 0); return z; } void ZM_snfclean(GEN d, GEN u, GEN v) { long i, c, l = lg(d); if (typ(d) == t_VEC) for (c=1; c l) { /* D = vconcat(zero matrix, diagonal matrix) */ for (c=1+h-l, d=1; c 1) { if (h > l) { for (i=1+h-l, j=1; i 16 + gexpo(b) - prec2nbits(gprecision(r))) ) return k; } return 0; } /* Hermite Normal Form, with base change matrix if ptB != NULL. * If 'remove' = 1, remove 0 columns (do NOT update *ptB accordingly) * If 'remove' = 2, remove 0 columns and update *ptB accordingly */ GEN RgM_hnfall(GEN A, GEN *pB, long remove) { pari_sp av; long li, j, k, m, n, def, ldef; GEN B; long vx = gvar(A); n = lg(A)-1; if (vx==NO_VARIABLE || !n) { RgM_check_ZM(A, "mathnf0"); return ZM_hnfall(A, pB, remove); } m = nbrows(A); av = avma; A = RgM_shallowcopy(A); B = pB? matid(n): NULL; def = n; ldef = (m>n)? m-n: 0; for (li=m; li>ldef; li--) { GEN d, T; for (j=def-1; j; j--) { GEN a = gcoeff(A,li,j); if (gequal0(a)) continue; k = (j==1)? def: j-1; RgC_elem(a,gcoeff(A,li,k), A,B, j,k, li, vx); } T = normalize_as_RgX(gcoeff(A,li,def), vx, &d); if (gequal0(T)) { if (ldef) ldef--; } else { gcoeff(A,li,def) = T; if (B && !gequal1(d)) gel(B, def) = RgC_Rg_div(gel(B, def), d); RgM_reduce(A, B, li, def, vx); def--; } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"ghnfall"); gerepileall(av, B? 2: 1, &A, &B); } } /* rank A = n - def */ if (remove) remove_0cols(def, &A, &B, remove); gerepileall(av, B? 2: 1, &A, &B); if (B) *pB = B; return A; } static GEN gsmithall_i(GEN x,long all) { pari_sp av; long i, j, k, n; GEN z, u, v, U, V; long vx = gvar(x); if (typ(x)!=t_MAT) pari_err_TYPE("gsmithall",x); if (vx==NO_VARIABLE) return all? smithall(x): smith(x); n = lg(x)-1; if (!n) return trivsmith(all); if (lgcols(x) != n+1) pari_err_DIM("gsmithall"); av = avma; x = RgM_shallowcopy(x); if (all) { U = matid(n); V = matid(n); } for (i=n; i>=2; i--) { for(;;) { GEN a, b, d; int c = 0; for (j=i-1; j>=1; j--) { b = gcoeff(x,i,j); if (gequal0(b)) continue; a = gcoeff(x,i,i); d = gbezout_step(&b, &a, &v, &u, vx); for (k = 1; k < i; k++) { GEN t = gadd(gmul(u,gcoeff(x,k,i)),gmul(v,gcoeff(x,k,j))); gcoeff(x,k,j) = gsub(gmul(a,gcoeff(x,k,j)),gmul(b,gcoeff(x,k,i))); gcoeff(x,k,i) = t; } gcoeff(x,i,j) = gen_0; gcoeff(x,i,i) = d; if (all) update(u,v,a,b,(GEN*)(V+i),(GEN*)(V+j)); } for (j=i-1; j>=1; j--) { b = gcoeff(x,j,i); if (gequal0(b)) continue; a = gcoeff(x,i,i); d = gbezout_step(&b, &a, &v, &u, vx); for (k = 1; k < i; k++) { GEN t = gadd(gmul(u,gcoeff(x,i,k)),gmul(v,gcoeff(x,j,k))); gcoeff(x,j,k) = gsub(gmul(a,gcoeff(x,j,k)),gmul(b,gcoeff(x,i,k))); gcoeff(x,i,k) = t; } gcoeff(x,j,i) = gen_0; gcoeff(x,i,i) = d; if (all) update(u,v,a,b,(GEN*)(U+i),(GEN*)(U+j)); c = 1; } if (!c) { k = gsnf_no_divide(x, i, vx); if (!k) break; for (j=1; j<=i; j++) gcoeff(x,i,j) = gadd(gcoeff(x,i,j),gcoeff(x,k,j)); if (all) gel(U,i) = gadd(gel(U,i),gel(U,k)); } if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"gsmithall"); gerepileall(av, all? 3: 1, &x, &U, &V); } } } for (k=1; k<=n; k++) { GEN d, T = normalize_as_RgX(gcoeff(x,k,k), vx, &d); if (gequal0(T)) continue; if (all && !gequal1(d)) gel(V,k) = RgC_Rg_div(gel(V,k), d); gcoeff(x,k,k) = T; } z = all? mkvec3(shallowtrans(U), V, x): RgM_diagonal_shallow(x); return gerepilecopy(av, z); } GEN matsnf0(GEN x,long flag) { pari_sp av = avma; if (flag > 7) pari_err_FLAG("matsnf"); if (typ(x) == t_VEC && flag & 4) return smithclean(x); if (flag & 2) x = flag&1 ? gsmithall(x): gsmith(x); else x = flag&1 ? smithall(x): smith(x); if (flag & 4) x = gerepileupto(av, smithclean(x)); return x; } GEN gsmith(GEN x) { return gsmithall_i(x,0); } GEN gsmithall(GEN x) { return gsmithall_i(x,1); } /* H is a relation matrix, either in HNF or a t_VEC (diagonal HNF) */ static GEN snf_group(GEN H, GEN D, GEN *newU, GEN *newUi) { long i, j, l; ZM_snfclean(D, newU? *newU: NULL, newUi? *newUi: NULL); l = lg(D); if (newU) { GEN U = *newU; for (i = 1; i < l; i++) { GEN d = gel(D,i), d2 = shifti(d, 1); for (j = 1; j < lg(U); j++) gcoeff(U,i,j) = centermodii(gcoeff(U,i,j), d, d2); } *newU = U; } if (newUi && l > 1) { /* UHV=D -> U^-1 = (HV)D^-1 -> U^-1 = H(VD^-1 mod 1) mod H */ /* Ui = ZM_inv(U, NULL); setlg(Ui, l); */ GEN V = *newUi, Ui; int Hvec = (typ(H) == t_VEC); for (i = 1; i < l; i++) gel(V,i) = FpC_red(gel(V,i), gel(D,i)); if (!Hvec) { if (ZM_isdiagonal(H)) { H = RgM_diagonal_shallow(H); Hvec = 1; } } Ui = Hvec? ZM_diag_mul(H, V): ZM_mul(H, V); for (i = 1; i < l; i++) gel(Ui,i) = ZC_Z_divexact(gel(Ui,i), gel(D,i)); if (Hvec) { for (i = 1; i < l; i++) gel(Ui,i) = vecmodii(gel(Ui,i), H); } else Ui = ZM_hnfrem(Ui, H); *newUi = Ui; } return D; } /* H relation matrix among row of generators g in HNF. Let URV = D its SNF, * newU R newV = newD its clean SNF (no 1 in Dnew). Return the diagonal of * newD, newU and newUi such that 1/U = (newUi, ?). * Rationale: let (G,0) = g Ui be the new generators then * 0 = G U R --> G D = 0, g = G newU and G = g newUi */ GEN ZM_snf_group(GEN H, GEN *newU, GEN *newUi) { GEN D = ZM_snfall_i(H, newU, newUi, 1); return snf_group(H, D, newU, newUi); } /* D a ZV: SNF for matdiagonal(D). Faster because we only ensure elementary * divisors condition: d[n] | ... | d[1] and need not convert D to matrix form*/ GEN ZV_snfall(GEN D, GEN *pU, GEN *pV) { pari_sp av = avma; long j, n = lg(D)-1; GEN U = pU? matid(n): NULL; GEN V = pV? matid(n): NULL; GEN p; D = leafcopy(D); for (j = n; j > 0; j--) { GEN b = gel(D,j); if (signe(b) < 0) { gel(D,j) = negi(b); if (V) ZV_togglesign(gel(V,j)); } } /* entries are non-negative integers */ p = gen_indexsort(D, NULL, &negcmpii); D = vecpermute(D, p); if (U) U = vecpermute(U, p); if (V) V = vecpermute(V, p); /* entries are sorted by decreasing value */ for (j = n; j > 0; j--) { GEN b = gel(D,j); long i; for (i = j-1; i > 0; i--) { /* invariant: a >= b. If au+bv = d is a Bezout relation, A=a/d and B=b/d * we have [B,-A;u,v]*diag(a,b)*[1-u*A,1; -u*A,1]] = diag(Ab, d) */ GEN a = gel(D,i), u,v, d = bezout(a,b, &u,&v), A, Wi, Wj; if (equalii(d,b)) continue; A = diviiexact(a,d); if (V) { GEN t = mulii(u,A); Wi = ZC_lincomb(subui(1,t), negi(t), gel(V,i), gel(V,j)); Wj = ZC_add(gel(V,i), gel(V,j)); gel(V,i) = Wi; gel(V,j) = Wj; } if (U) { GEN B = diviiexact(b,d); Wi = ZC_lincomb(B, negi(A), gel(U,i), gel(U,j)); Wj = ZC_lincomb(u, v, gel(U,i), gel(U,j)); gel(U,i) = Wi; gel(U,j) = Wj; } gel(D,i) = mulii(A,b); /* lcm(a,b) */ gel(D,j) = d; /* gcd(a,b) */ b = gel(D,j); if (equali1(b)) break; } } snf_pile(av, &D,&U,&V); if (U) *pU = shallowtrans(U); if (V) *pV = V; return D; } GEN ZV_snf_group(GEN d, GEN *newU, GEN *newUi) { GEN D = ZV_snfall(d, newU, newUi); return snf_group(d, D, newU, newUi); } /* D a vector of elementary divisors. Truncate (setlg) to leave out trivial * entries (= 1) */ void ZV_snf_trunc(GEN D) { long i, l = lg(D); for (i = 1; i < l; i++) if (is_pm1(gel(D,i))) { setlg(D,i); break; } } pari-2.11.2/src/basemath/ZG.c0000644000175000017500000000725113326135265014230 0ustar billbill/* Copyright (C) 2011 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "pari.h" #include "paripriv.h" static int cmp_G(void *E, GEN x, GEN y) { (void)E; return cmp_universal(x,y); } /* a ZG is either a t_INT or a t_VEC of pairs [g,e] representing * \sum e_i [g_i], e_i in Z, g_i in G. */ GEN ZG_normalize(GEN x) { if (typ(x) == t_INT) return x; return sort_factor(shallowcopy(x), NULL, &cmp_G); } GEN ZG_add(GEN x, GEN y) { if (typ(x) == t_INT) { if (!signe(x)) return y; if (typ(y) == t_INT) { if (!signe(y)) return x; return addii(x,y); } x = to_famat_shallow(gen_1,x); } else if (typ(y) == t_INT) { if (!signe(y)) return x; y = to_famat_shallow(gen_1,y); } x = merge_factor(x, y, NULL, &cmp_G); if (lg(gel(x,1)) == 1) return gen_0; return x; } GEN ZG_neg(GEN x) { if (typ(x) == t_INT) return negi(x); return mkmat2(gel(x,1),ZC_neg(gel(x,2))); } GEN ZG_sub(GEN x, GEN y) { return ZG_add(x, ZG_neg(y)); } /* x * c.[1], x in Z[G] */ GEN ZG_Z_mul(GEN x, GEN c) { if (is_pm1(c)) return signe(c) > 0? x: ZG_neg(x); if (typ(x) == t_INT) return mulii(x,c); return mkmat2(gel(x,1), ZC_Z_mul(gel(x,2), c)); } GEN ZG_mul(GEN x, GEN y) { pari_sp av; GEN z, XG, XE; long i, l; if (typ(x) == t_INT) return ZG_Z_mul(y, x); if (typ(y) == t_INT) return ZG_Z_mul(x, y); av = avma; XG = gel(x,1); XE = gel(x,2); l = lg(XG); z = ZG_Z_mul(G_ZG_mul(gel(XG,1), y), gel(XE,1)); for (i = 2; i < l; i++) { z = ZG_add(z, ZG_Z_mul(G_ZG_mul(gel(XG,i), y), gel(XE,i))); if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZG_mul, i = %ld/%ld",i,l-1); z = gerepilecopy(av, z); } } return z; } GEN ZGCs_add(GEN x, GEN y) { GEN xi = gel(x,1), xv = gel(x,2); GEN yi = gel(y,1), yv = gel(y,2); long i = 1, j = 1, k = 1, lx = lg(xi), ly = lg(yi), l = lx+ly-1; GEN zi = cgetg(l, t_VECSMALL), zv = cgetg(l, t_VEC); while (i < lx && j < ly) { if (xi[i] < yi[j]) { zi[k] = xi[i]; gel(zv,k) = gel(xv,i); i++; } else if (xi[i] > yi[j]) { zi[k] = yi[j]; gel(zv,k) = gel(yv,j); j++; } else { zi[k] = xi[i]; gel(zv,k) = ZG_add(gel(xv,i),gel(yv,j)); i++; j++; } k++; } for(; i < lx; i++,k++) { zi[k] = xi[i]; gel(zv,k) = gel(xv,i); } for(; j < ly; j++,k++) { zi[k] = yi[j]; gel(zv,k) = gel(yv,j); } setlg(zi,k); setlg(zv,k); return mkvec2(zi, zv); } GEN ZG_G_mul(GEN x, GEN y) { long i, l; GEN z, X; if (typ(x) == t_INT) return signe(x)? to_famat_shallow(y, x): gen_0; X = gel(x,1); z = cgetg_copy(X, &l); for (i = 1; i < l; i++) gel(z,i) = gmul(gel(X,i), y); return ZG_normalize( mkmat2(z, gel(x,2)) ); } GEN G_ZG_mul(GEN x, GEN y) { long i, l; GEN z, Y; if (typ(y) == t_INT) return to_famat_shallow(x, y); Y = gel(y,1); z = cgetg_copy(Y, &l); for (i = 1; i < l; i++) gel(z,i) = gmul(x, gel(Y,i)); return ZG_normalize( mkmat2(z, gel(y,2)) ); } void ZGC_G_mul_inplace(GEN v, GEN x) { long i, l = lg(v); for (i = 1; i < l; i++) gel(v,i) = ZG_G_mul(gel(v,i), x); } GEN ZGC_G_mul(GEN v, GEN x) { pari_APPLY_same(ZG_G_mul(gel(v,i), x)); } GEN G_ZGC_mul(GEN x, GEN v) { pari_APPLY_same(G_ZG_mul(gel(v,i), x)); } GEN ZGC_Z_mul(GEN v, GEN x) { pari_APPLY_same(ZG_Z_mul(gel(v,i), x)); } pari-2.11.2/src/basemath/mftrace.c0000644000175000017500000126615513447371554015353 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*************************************************************************/ /* */ /* Modular forms package based on trace formulas */ /* */ /*************************************************************************/ #include "pari.h" #include "paripriv.h" enum { MF_SPLIT = 1, MF_EISENSPACE, MF_FRICKE, MF_MF2INIT, MF_SPLITN }; typedef struct { GEN vnew, vfull, DATA, VCHIP; long n, newHIT, newTOTAL, cuspHIT, cuspTOTAL; } cachenew_t; static void init_cachenew(cachenew_t *c, long n, long N, GEN f); static GEN mfinit_i(GEN NK, long space); static GEN mfinit_Nkchi(long N, long k, GEN CHI, long space, long flraw); static GEN mf2init_Nkchi(long N, long k, GEN CHI, long space, long flraw); static GEN mf2basis(long N, long r, GEN CHI, long space); static GEN mfeisensteinbasis(long N, long k, GEN CHI); static GEN mfeisensteindec(GEN mf, GEN F); static GEN initwt1newtrace(GEN mf); static GEN initwt1trace(GEN mf); static GEN myfactoru(long N); static GEN mydivisorsu(long N); static GEN mygmodulo_lift(long k, long ord, GEN C, long vt); static GEN mfcoefs_i(GEN F, long n, long d); static GEN bhnmat_extend(GEN M, long m,long l, GEN S, cachenew_t *cache); static GEN initnewtrace(long N, GEN CHI); static void dbg_cachenew(cachenew_t *C); static GEN hecke_i(long m, long l, GEN V, GEN F, GEN DATA); static GEN c_Ek(long n, long d, GEN F); static GEN RgV_heckef2(long n, long d, GEN V, GEN F, GEN DATA); static GEN mfcusptrace_i(long N, long k, long n, GEN Dn, GEN TDATA); static GEN mfnewtracecache(long N, long k, long n, cachenew_t *cache); static GEN colnewtrace(long n0, long n, long d, long N, long k, cachenew_t *c); static GEN dihan(GEN bnr, GEN w, GEN k0j, ulong n); static GEN sigchi(long k, GEN CHI, long n); static GEN sigchi2(long k, GEN CHI1, GEN CHI2, long n, long ord); static GEN mflineardivtomat(long N, GEN vF, long n); static GEN mfdihedralcusp(long N, GEN CHI); static long mfdihedralcuspdim(long N, GEN CHI); static GEN mfdihedralnew(long N, GEN CHI); static GEN mfdihedralall(GEN LIM); static long mfwt1cuspdim(long N, GEN CHI); static long mf2dim_Nkchi(long N, long k, GEN CHI, ulong space); static long mfdim_Nkchi(long N, long k, GEN CHI, long space); static GEN charLFwtk(long k, GEN CHI, long ord); static GEN mfeisensteingacx(GEN E,long w,GEN ga,long n,long prec); static GEN mfgaexpansion(GEN mf, GEN F, GEN gamma, long n, long prec); static GEN mfEHmat(long n, long r); static GEN mfEHcoef(long r, long N); static GEN mftobasis_i(GEN mf, GEN F); static GEN mkgNK(GEN N, GEN k, GEN CHI, GEN P) { return mkvec4(N, k, CHI, P); } static GEN mkNK(long N, long k, GEN CHI) { return mkgNK(stoi(N), stoi(k), CHI, pol_x(1)); } GEN MF_get_CHI(GEN mf) { return gmael(mf,1,3); } GEN MF_get_gN(GEN mf) { return gmael(mf,1,1); } long MF_get_N(GEN mf) { return itou(MF_get_gN(mf)); } GEN MF_get_gk(GEN mf) { return gmael(mf,1,2); } long MF_get_k(GEN mf) { GEN gk = MF_get_gk(mf); if (typ(gk)!=t_INT) pari_err_IMPL("half-integral weight"); return itou(gk); } long MF_get_r(GEN mf) { GEN gk = MF_get_gk(mf); if (typ(gk) == t_INT) pari_err_IMPL("integral weight"); return itou(gel(gk, 1)) >> 1; } long MF_get_space(GEN mf) { return itos(gmael(mf,1,4)); } GEN MF_get_E(GEN mf) { return gel(mf,2); } GEN MF_get_S(GEN mf) { return gel(mf,3); } GEN MF_get_basis(GEN mf) { return shallowconcat(gel(mf,2), gel(mf,3)); } long MF_get_dim(GEN mf) { switch(MF_get_space(mf)) { case mf_FULL: return lg(MF_get_S(mf)) - 1 + lg(MF_get_E(mf))-1; case mf_EISEN: return lg(MF_get_E(mf))-1; default: /* mf_NEW, mf_CUSP, mf_OLD */ return lg(MF_get_S(mf)) - 1; } } GEN MFnew_get_vj(GEN mf) { return gel(mf,4); } GEN MFcusp_get_vMjd(GEN mf) { return gel(mf,4); } GEN MF_get_M(GEN mf) { return gmael(mf,5,3); } GEN MF_get_Minv(GEN mf) { return gmael(mf,5,2); } GEN MF_get_Mindex(GEN mf) { return gmael(mf,5,1); } /* ordinary gtocol forgets about initial 0s */ GEN sertocol(GEN S) { return gtocol0(S, -(lg(S) - 2 + valp(S))); } /*******************************************************************/ /* Linear algebra in cyclotomic fields (TODO: export this) */ /*******************************************************************/ /* return r and split prime p giving projection Q(zeta_n) -> Fp, zeta -> r */ static ulong QabM_init(long n, ulong *p) { ulong pinit = 1000000007; forprime_t T; if (n <= 1) { *p = pinit; return 0; } u_forprime_arith_init(&T, pinit, ULONG_MAX, 1, n); *p = u_forprime_next(&T); return Flx_oneroot(ZX_to_Flx(polcyclo(n, 0), *p), *p); } static ulong Qab_to_Fl(GEN P, ulong r, ulong p) { ulong t; GEN den; P = Q_remove_denom(liftpol_shallow(P), &den); if (typ(P) == t_POL) { GEN Pp = ZX_to_Flx(P, p); t = Flx_eval(Pp, r, p); } else t = umodiu(P, p); if (den) t = Fl_div(t, umodiu(den, p), p); return t; } static GEN QabC_to_Flc(GEN C, ulong r, ulong p) { long i, l = lg(C); GEN A = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) uel(A,i) = Qab_to_Fl(gel(C,i), r, p); return A; } static GEN QabM_to_Flm(GEN M, ulong r, ulong p) { long i, l; GEN A = cgetg_copy(M, &l); for (i = 1; i < l; i++) gel(A, i) = QabC_to_Flc(gel(M, i), r, p); return A; } /* A a t_POL */ static GEN QabX_to_Flx(GEN A, ulong r, ulong p) { long i, l = lg(A); GEN a = cgetg(l, t_VECSMALL); a[1] = ((ulong)A[1])&VARNBITS; for (i = 2; i < l; i++) uel(a,i) = Qab_to_Fl(gel(A,i), r, p); return Flx_renormalize(a, l); } /* FIXME: remove */ static GEN ZabM_pseudoinv_i(GEN M, GEN P, long n, GEN *pv, GEN *den, int ratlift) { GEN v = ZabM_indexrank(M, P, n); if (pv) *pv = v; M = shallowmatextract(M,gel(v,1),gel(v,2)); return ratlift? ZabM_inv_ratlift(M, P, n, den): ZabM_inv(M, P, n, den); } /* M matrix with coeff in Q(\chi)), where Q(\chi) = Q(X)/(P) for * P = cyclotomic Phi_n. Assume M rational if n <= 2 */ static GEN QabM_ker(GEN M, GEN P, long n) { GEN B; if (n <= 2) B = ZM_ker(Q_primpart(M)); else B = ZabM_ker(Q_primpart(liftpol_shallow(M)), P, n); return B; } /* pseudo-inverse of M */ static GEN QabM_pseudoinv(GEN M, GEN P, long n, GEN *pv, GEN *pden) { GEN cM, Mi; if (n <= 2) { M = Q_primitive_part(M, &cM); Mi = ZM_pseudoinv(M, pv, pden); /* M^(-1) = Mi / (cM * den) */ } else { M = Q_primitive_part(liftpol_shallow(M), &cM); Mi = ZabM_pseudoinv(M, P, n, pv, pden); Mi = gmodulo(Mi, P); } *pden = mul_content(*pden, cM); return Mi; } static GEN QabM_indexrank(GEN M, GEN P, long n) { GEN z; if (n <= 2) { M = vec_Q_primpart(M); z = ZM_indexrank(M); /* M^(-1) = Mi / (cM * den) */ } else { M = vec_Q_primpart(liftpol_shallow(M)); z = ZabM_indexrank(M, P, n); } return z; } /*********************************************************************/ /* Simple arithmetic functions */ /*********************************************************************/ /* TODO: most of these should be exported and used in ifactor1.c */ /* phi(n) */ static ulong myeulerphiu(ulong n) { pari_sp av; GEN fa; if (n == 1) return 1; av = avma; fa = myfactoru(n); avma = av; return eulerphiu_fact(fa); } static long mymoebiusu(ulong n) { pari_sp av; GEN fa; if (n == 1) return 1; av = avma; fa = myfactoru(n); avma = av; return moebiusu_fact(fa); } static long mynumdivu(long N) { pari_sp av; GEN fa; if (N == 1) return 1; av = avma; fa = myfactoru(N); avma = av; return numdivu_fact(fa); } /* N\prod_{p|N} (1+1/p) */ static long mypsiu(ulong N) { pari_sp av = avma; GEN P = gel(myfactoru(N), 1); long j, l = lg(P), res = N; for (j = 1; j < l; j++) res += res/P[j]; avma = av; return res; } /* write n = mf^2. Return m, set f. */ static ulong mycore(ulong n, long *pf) { pari_sp av = avma; GEN fa = myfactoru(n), P = gel(fa,1), E = gel(fa,2); long i, l = lg(P), m = 1, f = 1; for (i = 1; i < l; i++) { long j, p = P[i], e = E[i]; if (e & 1) m *= p; for (j = 2; j <= e; j+=2) f *= p; } avma = av; *pf = f; return m; } /* fa = factorization of -D > 0, return -D0 > 0 (where D0 is fundamental) */ static long corediscs_fact(GEN fa) { GEN P = gel(fa,1), E = gel(fa,2); long i, l = lg(P), m = 1; for (i = 1; i < l; i++) { long p = P[i], e = E[i]; if (e & 1) m *= p; } if ((m&3L) != 3) m <<= 2; return m; } static long mubeta(long n) { pari_sp av = avma; GEN E = gel(myfactoru(n), 2); long i, s = 1, l = lg(E); for (i = 1; i < l; i++) { long e = E[i]; if (e >= 3) { avma = av; return 0; } if (e == 1) s *= -2; } avma = av; return s; } /* n = n1*n2, n1 = ppo(n, m); return mubeta(n1)*moebiusu(n2). * N.B. If n from newt_params we, in fact, never return 0 */ static long mubeta2(long n, long m) { pari_sp av = avma; GEN fa = myfactoru(n), P = gel(fa,1), E = gel(fa,2); long i, s = 1, l = lg(P); for (i = 1; i < l; i++) { long p = P[i], e = E[i]; if (m % p) { /* p^e in n1 */ if (e >= 3) { avma = av; return 0; } if (e == 1) s *= -2; } else { /* in n2 */ if (e >= 2) { avma = av; return 0; } s = -s; } } avma = av; return s; } /* write N = prod p^{ep} and n = df^2, d squarefree. * set g = ppo(gcd(sqfpart(N), f), FC) * N2 = prod p^if(e==1 || p|n, ep-1, ep-2) */ static void newt_params(long N, long n, long FC, long *pg, long *pN2) { GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2); long i, g = 1, N2 = 1, l = lg(P); for (i = 1; i < l; i++) { long p = P[i], e = E[i]; if (e == 1) { if (FC % p && n % (p*p) == 0) g *= p; } else N2 *= upowuu(p,(n % p)? e-2: e-1); } *pg = g; *pN2 = N2; } /* simplified version of newt_params for n = 1 (newdim) */ static void newd_params(long N, long *pN2) { GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2); long i, N2 = 1, l = lg(P); for (i = 1; i < l; i++) { long p = P[i], e = E[i]; if (e > 2) N2 *= upowuu(p, e-2); } *pN2 = N2; } static long newd_params2(long N) { GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2); long i, N2 = 1, l = lg(P); for (i = 1; i < l; i++) { long p = P[i], e = E[i]; if (e >= 2) N2 *= upowuu(p, e); } return N2; } /*******************************************************************/ /* Relative trace between cyclotomic fields (TODO: export this) */ /*******************************************************************/ /* g>=1; return g * prod_{p | g, (p,q) = 1} (1-1/p) */ static long phipart(long g, long q) { if (g > 1) { GEN P = gel(myfactoru(g), 1); long i, l = lg(P); for (i = 1; i < l; i++) { long p = P[i]; if (q % p) g -= g / p; } } return g; } /* Trace(zeta_n^k) from Q(\zeta_n) to Q(\zeta_m) with n = m*d; k > 0 */ static GEN tracerelz(long d, long m, long k, long vt) { long s, v, g = ugcd(k, d), q = d / g, muq = mymoebiusu(q); if (!muq) return gen_0; if (m == 1) { s = phipart(g, q); if (muq < 0) s = -s; return stoi(s); } if (ugcd(q, m) > 1) return gen_0; s = phipart(g, m*q); if (muq < 0) s = -s; v = Fl_inv(q % m, m); v = (v*(k/g)) % m; return mygmodulo_lift(v, m, stoi(s), vt); } /* m | n, both not 2 mod 4. Pn = polcyclo(n) */ GEN Qab_trace_init(GEN Pn, long n, long m) { GEN T, Pm; long a, i, d, vt; if (m == n) return mkvec(Pn); d = degpol(Pn); vt = varn(Pn); Pm = polcyclo(m, vt); T = cgetg(d+1, t_VEC); gel(T,1) = utoipos(d / degpol(Pm)); /* Tr 1 */ a = n / m; for (i = 1; i < d; i++) gel(T,i+1) = tracerelz(a, m, i, vt); return mkvec3(Pm, Pn, T); } /* x a t_POL modulo Phi_n; n, m not 2 mod 4, degrel != 1*/ static GEN tracerel_i(GEN T, GEN x) { long k, l = lg(x); GEN S = gen_0; for (k = 2; k < l; k++) S = gadd(S, gmul(gel(T,k-1), gel(x,k))); return S; } /* v = Qab_trace_init(n,m); x is a t_VEC of polmodulo Phi_n * Tr_{Q(zeta_n)/Q(zeta_m)} (zeta_n^t * x) */ GEN QabV_tracerel(GEN v, long t, GEN x) { long l, j, degrel; GEN y, z, Pm, Pn, T; if (lg(v) != 4) return x; y = cgetg_copy(x, &l); Pm = gel(v,1); Pn = gel(v,2); T = gel(v,3); degrel = degpol(Pn) / degpol(Pm); z = RgX_rem(pol_xn(t, varn(Pn)), Pn); for (j = 1; j < l; j++) { GEN a = liftpol_shallow(gel(x,j)); a = simplify_shallow( gmul(a, z) ); if (typ(a) == t_POL) { a = gdivgs(tracerel_i(T, RgX_rem(a, Pn)), degrel); if (typ(a) == t_POL) a = RgX_rem(a, Pm); } gel(y,j) = a; } return y; } /* Operations on Dirichlet characters */ /* A Dirichlet character can be given in GP in different formats, but in this * package, it will be a vector CHI=[G,chi,ord], where G is the (Z/MZ)^* to * which the character belongs, chi is the character in Conrey format, ord is * the order */ static GEN gmfcharorder(GEN CHI) { return gel(CHI, 3); } long mfcharorder(GEN CHI) { return itou(gmfcharorder(CHI)); } static long mfcharistrivial(GEN CHI) { return !CHI || mfcharorder(CHI) == 1; } static GEN gmfcharmodulus(GEN CHI) { return gmael3(CHI, 1, 1, 1); } long mfcharmodulus(GEN CHI) { return itou(gmfcharmodulus(CHI)); } GEN mfcharpol(GEN CHI) { return gel(CHI,4); } static long ord_canon(long ord) { if ((ord & 3L) == 2) ord >>= 1; return ord; } static long mfcharorder_canon(GEN CHI) { return ord_canon(mfcharorder(CHI)); } /* t^k mod polcyclo(ord), ord = order(CHI) > 1 */ static GEN mygmodulo(GEN CHI, long k) { GEN C, Pn; long ord; if (!k) return gen_1; ord = mfcharorder(CHI); if ((k << 1) == ord) return gen_m1; Pn = mfcharpol(CHI); if ((ord&3L) != 2) C = gen_1; else { ord >>= 1; if (odd(k)) { C = gen_m1; k += ord; } else C = gen_1; k >>= 1; } return gmodulo(monomial(C, k, varn(Pn)), Pn); } /* C*zeta_ord^k */ static GEN mygmodulo_lift(long k, long ord, GEN C, long vt) { if (!k) return C; if ((k << 1) == ord) return gneg(C); if ((ord&3L) == 2) { if (odd(k)) { C = gneg(C); k += ord >> 1; } k >>= 1; } return monomial(C, k, vt); } /* vz[i+1] = image of (zeta_ord)^i in Fp */ static ulong mygmodulo_Fl(long k, GEN vz, ulong C, ulong p) { long ord; if (!k) return C; ord = lg(vz)-2; if ((k << 1) == ord) return Fl_neg(C,p); if ((ord&3L) == 2) { if (odd(k)) { C = Fl_neg(C,p); k += ord >> 1; } k >>= 1; } return Fl_mul(C, vz[k+1], p); } static long znchareval_i(GEN CHI, long n, GEN ord) { return itos(znchareval(gel(CHI,1), gel(CHI,2), stoi(n), ord)); } /* G a znstar, L a Conrey log: return a 'mfchar' */ static GEN mfcharGL(GEN G, GEN L) { GEN o = zncharorder(G,L); long ord = ord_canon(itou(o)), vt = fetch_user_var("t"); return mkvec4(G, L, o, polcyclo(ord,vt)); } static GEN mfchartrivial() { return mfcharGL(znstar0(gen_1,1), cgetg(1,t_COL)); } /* convert a generic character into an 'mfchar' */ static GEN get_mfchar(GEN CHI) { GEN G, L; if (typ(CHI) != t_VEC) CHI = znchar(CHI); else { long l = lg(CHI); if ((l != 3 && l != 5) || !checkznstar_i(gel(CHI,1))) pari_err_TYPE("checkNF [chi]", CHI); if (l == 5) return CHI; } G = gel(CHI,1); L = gel(CHI,2); if (typ(L) != t_COL) L = znconreylog(G,L); return mfcharGL(G, L); } /* parse [N], [N,k], [N,k,CHI]. If 'joker' is set, allow wildcard for CHI */ static GEN checkCHI(GEN NK, long N, int joker) { GEN CHI; if (lg(NK) == 3) CHI = mfchartrivial(); else { long i, l; CHI = gel(NK,3); l = lg(CHI); if (isintzero(CHI) && joker) CHI = NULL; /* all character orbits */ else if (isintm1(CHI) && joker > 1) CHI = gen_m1; /* sum over all character orbits */ else if ((typ(CHI) == t_VEC && (l == 1 || l != 3 || !checkznstar_i(gel(CHI,1)))) && joker) { CHI = shallowtrans(CHI); /* list of characters */ for (i = 1; i < l; i++) gel(CHI,i) = get_mfchar(gel(CHI,i)); } else { CHI = get_mfchar(CHI); /* single char */ if (N % mfcharmodulus(CHI)) pari_err_TYPE("checkNF [chi]", NK); } } return CHI; } /* support half-integral weight */ static void checkNK2(GEN NK, long *N, long *nk, long *dk, GEN *CHI, int joker) { long l = lg(NK); GEN T; if (typ(NK) != t_VEC || l < 3 || l > 4) pari_err_TYPE("checkNK", NK); T = gel(NK,1); if (typ(T) != t_INT) pari_err_TYPE("checkNF [N]", NK); *N = itos(T); if (*N <= 0) pari_err_TYPE("checkNF [N <= 0]", NK); T = gel(NK,2); switch(typ(T)) { case t_INT: *nk = itos(T); *dk = 1; break; case t_FRAC: *nk = itos(gel(T,1)); *dk = itou(gel(T,2)); if (*dk == 2) break; default: pari_err_TYPE("checkNF [k]", NK); } *CHI = checkCHI(NK, *N, joker); } /* don't support half-integral weight */ static void checkNK(GEN NK, long *N, long *k, GEN *CHI, int joker) { long d; checkNK2(NK, N, k, &d, CHI, joker); if (d != 1) pari_err_TYPE("checkNF [k]", NK); } static GEN mfchargalois(long N, int odd, GEN flagorder) { GEN G = znstar0(utoi(N), 1), L = chargalois(G, flagorder); long l = lg(L), i, j; for (i = j = 1; i < l; i++) { GEN chi = znconreyfromchar(G, gel(L,i)); if (zncharisodd(G,chi) == odd) gel(L,j++) = mfcharGL(G,chi); } setlg(L, j); return L; } /* possible characters for non-trivial S_1(N, chi) */ static GEN mfwt1chars(long N, GEN vCHI) { if (vCHI) return vCHI; /*do not filter, user knows best*/ /* Tate's theorem */ return mfchargalois(N, 1, uisprime(N)? mkvecsmall2(2,4): NULL); } static GEN mfchars(long N, long k, long dk, GEN vCHI) { return vCHI? vCHI: mfchargalois(N, (dk == 2)? 0: (k & 1), NULL); } /* wrappers from mfchar to znchar */ static long mfcharparity(GEN CHI) { if (!CHI) return 1; return zncharisodd(gel(CHI,1), gel(CHI,2)) ? -1 : 1; } /* if CHI is primitive, return CHI itself, not a copy */ static GEN mfchartoprimitive(GEN CHI, long *pF) { pari_sp av; GEN chi, F; if (!CHI) { if (pF) *pF = 1; return mfchartrivial(); } av = avma; F = znconreyconductor(gel(CHI,1), gel(CHI,2), &chi); if (typ(F) == t_INT) avma = av; else { CHI = leafcopy(CHI); gel(CHI,1) = znstar0(F, 1); gel(CHI,2) = chi; } if (pF) *pF = mfcharmodulus(CHI); return CHI; } static long mfcharconductor(GEN CHI) { pari_sp ltop = avma; GEN res = znconreyconductor(gel(CHI,1), gel(CHI,2), NULL); long FC; if (typ(res) == t_VEC) res = gel(res, 1); FC = itos(res); avma = ltop; return FC; } /* n coprime with the modulus of CHI */ static GEN mfchareval_i(GEN CHI, long n) { GEN ord = gmfcharorder(CHI); if (equali1(ord)) return gen_1; return mygmodulo(CHI, znchareval_i(CHI, n, ord)); } /* d a multiple of ord(CHI); n coprime with char modulus; * return x s.t. CHI(n) = \zeta_d^x] */ static long mfcharevalord(GEN CHI, long n, long d) { if (mfcharorder(CHI) == 1) return 0; return znchareval_i(CHI, n, utoi(d)); } /* Operations on mf closures */ static GEN tagparams(long t, GEN NK) { return mkvec2(mkvecsmall(t), NK); } static GEN lfuntag(long t, GEN x) { return mkvec2(mkvecsmall(t), x); } static GEN tag0(long t, GEN NK) { retmkvec(tagparams(t,NK)); } static GEN tag(long t, GEN NK, GEN x) { retmkvec2(tagparams(t,NK), x); } static GEN tag2(long t, GEN NK, GEN x, GEN y) { retmkvec3(tagparams(t,NK), x,y); } static GEN tag3(long t, GEN NK, GEN x,GEN y,GEN z) { retmkvec4(tagparams(t,NK), x,y,z); } /* is F a "modular form" ? */ int checkmf_i(GEN F) { return typ(F) == t_VEC && lg(F) > 1 && typ(gel(F,1)) == t_VEC && lg(gel(F,1)) == 3 && typ(gmael(F,1,1)) == t_VECSMALL && typ(gmael(F,1,2)) == t_VEC; } long mf_get_type(GEN F) { return gmael(F,1,1)[1]; } GEN mf_get_gN(GEN F) { return gmael3(F,1,2,1); } GEN mf_get_gk(GEN F) { return gmael3(F,1,2,2); } /* k - 1/2, assume k in 1/2 + Z */ long mf_get_r(GEN F) { return itou(gel(mf_get_gk(F),1)) >> 1; } long mf_get_N(GEN F) { return itou(mf_get_gN(F)); } long mf_get_k(GEN F) { GEN gk = mf_get_gk(F); if (typ(gk)!=t_INT) pari_err_IMPL("half-integral weight"); return itou(gk); } GEN mf_get_CHI(GEN F) { return gmael3(F,1,2,3); } GEN mf_get_field(GEN F) { return gmael3(F,1,2,4); } GEN mf_get_NK(GEN F) { return gmael(F,1,2); } static void mf_setfield(GEN f, GEN P) { gel(f,1) = leafcopy(gel(f,1)); gmael(f,1,2) = leafcopy(gmael(f,1,2)); gmael3(f,1,2,4) = P; } /* UTILITY FUNCTIONS */ GEN mftocol(GEN F, long lim, long d) { GEN c = mfcoefs_i(F, lim, d); settyp(c,t_COL); return c; } GEN mfvectomat(GEN vF, long lim, long d) { long j, l = lg(vF); GEN M = cgetg(l, t_MAT); for (j = 1; j < l; j++) gel(M,j) = mftocol(gel(vF,j), lim, d); return M; } static GEN RgV_to_ser_full(GEN x) { return RgV_to_ser(x, 0, lg(x)+1); } /* TODO: delete */ static GEN mfcoefsser(GEN F, long n) { return RgV_to_ser_full(mfcoefs_i(F,n,1)); } static GEN sertovecslice(GEN S, long n) { GEN v = gtovec0(S, -(lg(S) - 2 + valp(S))); long l = lg(v), n2 = n + 2; if (l < n2) pari_err_BUG("sertovecslice [n too large]"); return (l == n2)? v: vecslice(v, 1, n2-1); } /* a, b two RgV of the same length, multiply as truncated power series */ static GEN RgV_mul_RgXn(GEN a, GEN b) { long n = lg(a)-1; GEN c; a = RgV_to_RgX(a,0); b = RgV_to_RgX(b,0); c = RgXn_mul(a, b, n); c = RgX_to_RgC(c,n); settyp(c,t_VEC); return c; } /* divide as truncated power series */ static GEN RgV_div_RgXn(GEN a, GEN b) { long n = lg(a)-1; GEN c; a = RgV_to_RgX(a,0); b = RgV_to_RgX(b,0); c = RgXn_mul(a, RgXn_inv(b,n), n); c = RgX_to_RgC(c,n); settyp(c,t_VEC); return c; } /* a^b */ static GEN RgV_pows_RgXn(GEN a, long b) { long n = lg(a)-1; GEN c; a = RgV_to_RgX(a,0); if (b < 0) { a = RgXn_inv(a, n); b = -b; } c = RgXn_powu_i(a,b,n); c = RgX_to_RgC(c,n); settyp(c,t_VEC); return c; } /* assume lg(V) >= n*d + 2 */ static GEN c_deflate(long n, long d, GEN v) { long i, id, l = n+2; GEN w; if (d == 1) return lg(v) == l ? v: vecslice(v, 1, l-1); w = cgetg(l, typ(v)); for (i = id = 1; i < l; i++, id += d) gel(w, i) = gel(v, id); return w; } static GEN c_mul(long n, long d, GEN F, GEN G) { pari_sp av = avma; long nd = n*d; GEN VF = mfcoefs_i(F, nd, 1); GEN VG = mfcoefs_i(G, nd, 1); return gerepilecopy(av, c_deflate(n, d, RgV_mul_RgXn(VF,VG))); } static GEN c_pow(long n, long d, GEN F, GEN a) { pari_sp av = avma; long nd = n*d; GEN f = RgV_pows_RgXn(mfcoefs_i(F,nd,1), itos(a)); return gerepilecopy(av, c_deflate(n, d, f)); } /* F * Theta */ static GEN mfmultheta(GEN F) { if (typ(mf_get_gk(F)) == t_FRAC && mf_get_type(F) == t_MF_DIV) { GEN T = gel(F,3); /* hopefully mfTheta() */ if (mf_get_type(T) == t_MF_THETA && mf_get_N(T) == 4) return gel(F,2); } return mfmul(F, mfTheta(NULL)); } static GEN c_bracket(long n, long d, GEN F, GEN G, GEN gm) { pari_sp av = avma; long i, nd = n*d; GEN VF = mfcoefs_i(F, nd, 1), tF = cgetg(nd+2, t_VEC); GEN VG = mfcoefs_i(G, nd, 1), tG = cgetg(nd+2, t_VEC); GEN C, mpow, res = NULL, gk = mf_get_gk(F), gl = mf_get_gk(G); ulong j, m = itou(gm); /* pow[i,j+1] = i^j */ mpow = cgetg(m+2, t_MAT); gel(mpow,1) = const_col(nd, gen_1); for (j = 1; j <= m; j++) { GEN c = cgetg(nd+1, t_COL); gel(mpow,j+1) = c; for (i = 1; i <= nd; i++) gel(c,i) = muliu(gcoeff(mpow,i,j), i); } C = binomial(gaddgs(gk, m-1), m); if (odd(m)) C = gneg(C); for (j = 0; j <= m; j++) { /* C = (-1)^(m-j) binom(m+l-1, j) binom(m+k-1,m-j) */ GEN c; gel(tF,1) = j == 0? gel(VF,1): gen_0; gel(tG,1) = j == m? gel(VG,1): gen_0; gel(tF,2) = gel(VF,2); gel(tG,2) = gel(VG,2); for (i = 2; i <= nd; i++) { gel(tF, i+1) = gmul(gcoeff(mpow,i,j+1), gel(VF, i+1)); gel(tG, i+1) = gmul(gcoeff(mpow,i,m-j+1), gel(VG, i+1)); } c = gmul(C, c_deflate(n, d, RgV_mul_RgXn(tF, tG))); res = res? gadd(res, c): c; if (j < m) C = gdiv(gmul(C, gmulsg(m-j, gaddgs(gl,m-j-1))), gmulsg(-(j+1), gaddgs(gk,j))); } return gerepileupto(av, res); } /* linear combination \sum L[j] vecF[j] */ static GEN c_linear(long n, long d, GEN F, GEN L, GEN dL) { pari_sp av = avma; long j, l = lg(L); GEN S = NULL; for (j = 1; j < l; j++) { GEN c = gel(L,j); if (gequal0(c)) continue; c = gmul(c, mfcoefs_i(gel(F,j), n, d)); S = S? gadd(S,c): c; } if (!S) return zerovec(n+1); if (!is_pm1(dL)) S = gdiv(S, dL); return gerepileupto(av, S); } /* B_d(T_j Trace^new) as t_MF_BD(t_MF_HECKE(t_MF_NEWTRACE)) or * t_MF_HECKE(t_MF_NEWTRACE) * or t_MF_NEWTRACE in level N. Set d and j, return t_MF_NEWTRACE component*/ static GEN bhn_parse(GEN f, long *d, long *j) { long t = mf_get_type(f); *d = *j = 1; if (t == t_MF_BD) { *d = itos(gel(f,3)); f = gel(f,2); t = mf_get_type(f); } if (t == t_MF_HECKE) { *j = gel(f,2)[1]; f = gel(f,3); } return f; } /* f as above, return the t_MF_NEWTRACE component */ static GEN bhn_newtrace(GEN f) { long t = mf_get_type(f); if (t == t_MF_BD) { f = gel(f,2); t = mf_get_type(f); } if (t == t_MF_HECKE) f = gel(f,3); return f; } static int ok_bhn_linear(GEN vf) { long i, N0 = 0, l = lg(vf); GEN CHI, gk; if (l == 1) return 1; gk = mf_get_gk(gel(vf,1)); CHI = mf_get_CHI(gel(vf,1)); for (i = 1; i < l; i++) { GEN f = bhn_newtrace(gel(vf,i)); long N = mf_get_N(f); if (mf_get_type(f) != t_MF_NEWTRACE) return 0; if (N < N0) return 0; /* largest level must come last */ N0 = N; if (!gequal(gk,mf_get_gk(f))) return 0; /* same k */ if (!gequal(gel(mf_get_CHI(f),2), gel(CHI,2))) return 0; /* same CHI */ } return 1; } /* vF not empty, same hypotheses as bhnmat_extend */ static GEN bhnmat_extend_nocache(GEN M, long N, long n, long d, GEN vF) { cachenew_t cache; long l = lg(vF); GEN f; if (l == 1) return M? M: cgetg(1, t_MAT); f = bhn_newtrace(gel(vF,1)); /* N.B. mf_get_N(f) divides N */ init_cachenew(&cache, n*d, N, f); M = bhnmat_extend(M, n, d, vF, &cache); dbg_cachenew(&cache); return M; } /* c_linear of "bhn" mf closures, same hypotheses as bhnmat_extend */ static GEN c_linear_bhn(long n, long d, GEN F) { pari_sp av; GEN M, v, vF = gel(F,2), L = gel(F,3), dL = gel(F,4); if (lg(L) == 1) return zerovec(n+1); av = avma; M = bhnmat_extend_nocache(NULL, mf_get_N(F), n, d, vF); v = RgM_RgC_mul(M,L); settyp(v, t_VEC); if (!is_pm1(dL)) v = gdiv(v, dL); return gerepileupto(av, v); } /* c in K, K := Q[X]/(T) vz = vector of consecutive powers of root z of T * attached to an embedding s: K -> C. Return s(c) in C */ static GEN Rg_embed1(GEN c, GEN vz) { long t = typ(c); if (t == t_POLMOD) { c = gel(c,2); t = typ(c); } if (t == t_POL) c = RgX_RgV_eval(c, vz); return c; } /* return s(P) in C[X] */ static GEN RgX_embed1(GEN P, GEN vz) { long i, l; GEN Q = cgetg_copy(P, &l); Q[1] = P[1]; for (i = 2; i < l; i++) gel(Q,i) = Rg_embed1(gel(P,i), vz); return normalizepol_lg(Q,l); /* normally a no-op */ } /* return s(P) in C^n */ static GEN vecembed1(GEN P, GEN vz) { long i, l; GEN Q = cgetg_copy(P, &l); for (i = 1; i < l; i++) gel(Q,i) = Rg_embed1(gel(P,i), vz); return Q; } /* P in L = K[X]/(U), K = Q[t]/T; s an embedding of K -> C attached * to a root of T, extended to an embedding of L -> C attached to a root * of s(U); vT powers of the root of T, vU powers of the root of s(U). * Return s(P) in C^n */ static GEN Rg_embed2(GEN P, long vt, GEN vT, GEN vU) { long i, l; GEN Q; P = liftpol_shallow(P); if (typ(P) != t_POL) return P; if (varn(P) == vt) return Rg_embed1(P, vT); /* varn(P) == vx */ Q = cgetg_copy(P, &l); Q[1] = P[1]; for (i = 2; i < l; i++) gel(Q,i) = Rg_embed1(gel(P,i), vT); return Rg_embed1(Q, vU); } static GEN vecembed2(GEN P, long vt, GEN vT, GEN vU) { long i, l; GEN Q = cgetg_copy(P, &l); for (i = 1; i < l; i++) gel(Q,i) = Rg_embed2(gel(P,i), vt, vT, vU); return Q; } static GEN RgX_embed2(GEN P, long vt, GEN vT, GEN vU) { long i, l; GEN Q = cgetg_copy(P, &l); for (i = 2; i < l; i++) gel(Q,i) = Rg_embed2(gel(P,i), vt, vT, vU); Q[1] = P[1]; return normalizepol_lg(Q,l); } /* embed polynomial f in variable vx [ may be a scalar ], E from getembed */ static GEN RgX_embed(GEN f, long vx, GEN E) { GEN vT; if (typ(f) != t_POL || varn(f) != vx) return mfembed(E, f); if (lg(E) == 1) return f; vT = gel(E,2); if (lg(E) == 3) f = RgX_embed1(f, vT); else f = RgX_embed2(f, varn(gel(E,1)), vT, gel(E,3)); return f; } /* embed vector, E from getembed */ GEN mfvecembed(GEN E, GEN v) { GEN vT; if (lg(E) == 1) return v; vT = gel(E,2); if (lg(E) == 3) v = vecembed1(v, vT); else v = vecembed2(v, varn(gel(E,1)), vT, gel(E,3)); return v; } GEN mfmatembed(GEN E, GEN f) { long i, l; GEN g; if (lg(E) == 1) return f; g = cgetg_copy(f, &l); for (i = 1; i < l; i++) gel(g,i) = mfvecembed(E, gel(f,i)); return g; } /* embed vector of polynomials in var vx */ static GEN RgXV_embed(GEN f, long vx, GEN E) { long i, l; GEN v; if (lg(E) == 1) return f; v = cgetg_copy(f, &l); for (i = 1; i < l; i++) gel(v,i) = RgX_embed(gel(f,i), vx, E); return v; } /* embed scalar */ GEN mfembed(GEN E, GEN f) { GEN vT; if (lg(E) == 1) return f; vT = gel(E,2); if (lg(E) == 3) f = Rg_embed1(f, vT); else f = Rg_embed2(f, varn(gel(E,1)), vT, gel(E,3)); return f; } /* vector of the sigma(f), sigma in vE */ static GEN RgX_embedall(GEN f, long vx, GEN vE) { long i, l = lg(vE); GEN v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = RgX_embed(f, vx, gel(vE,i)); return l == 2? gel(v,1): v; } /* matrix whose colums are the sigma(v), sigma in vE */ static GEN RgC_embedall(GEN v, GEN vE) { long j, l = lg(vE); GEN M = cgetg(l, t_MAT); for (j = 1; j < l; j++) gel(M,j) = mfvecembed(gel(vE,j), v); return M; } /* vector of the sigma(v), sigma in vE */ static GEN Rg_embedall_i(GEN v, GEN vE) { long j, l = lg(vE); GEN M = cgetg(l, t_VEC); for (j = 1; j < l; j++) gel(M,j) = mfembed(gel(vE,j), v); return M; } /* vector of the sigma(v), sigma in vE; if #vE == 1, return v */ static GEN Rg_embedall(GEN v, GEN vE) { return (lg(vE) == 2)? mfembed(gel(vE,1), v): Rg_embedall_i(v, vE); } static GEN c_div_i(long n, GEN F, GEN G) { GEN VF, VG, a0, a0i, H; VF = mfcoefsser(F, n); VG = mfcoefsser(G, n); a0 = polcoef_i(VG, 0, -1); if (gequal0(a0) || gequal1(a0)) a0 = a0i = NULL; else { a0i = ginv(a0); VG = gmul(ser_unscale(VG,a0), a0i); VF = gmul(ser_unscale(VF,a0), a0i); } H = gdiv(VF, VG); if (a0) H = ser_unscale(H,a0i); return sertovecslice(H, n); } static GEN c_div(long n, long d, GEN F, GEN G) { pari_sp av = avma; GEN D = (d==1)? c_div_i(n, F,G): c_deflate(n, d, c_div_i(n*d, F,G)); return gerepilecopy(av, D); } static GEN c_shift(long n, long d, GEN F, GEN gsh) { pari_sp av = avma; GEN vF; long sh = itos(gsh), n1 = n*d + sh; if (n1 < 0) return zerovec(n+1); vF = mfcoefs_i(F, n1, 1); if (sh < 0) vF = shallowconcat(zerovec(-sh), vF); else vF = vecslice(vF, sh+1, n1+1); return gerepilecopy(av, c_deflate(n, d, vF)); } static GEN c_deriv(long n, long d, GEN F, GEN gm) { pari_sp av = avma; GEN V = mfcoefs_i(F, n, d), res; long i, m = itos(gm); if (!m) return V; res = cgetg(n+2, t_VEC); gel(res,1) = gen_0; if (m < 0) { for (i=1; i <= n; i++) gel(res, i+1) = gdiv(gel(V, i+1), powuu(i,-m)); } else { for (i=1; i <= n; i++) gel(res, i+1) = gmul(gel(V,i+1), powuu(i,m)); } return gerepileupto(av, res); } static GEN c_derivE2(long n, long d, GEN F, GEN gm) { pari_sp av = avma; GEN VF, VE, res, tmp, gk; long i, m = itos(gm), nd; if (m == 0) return mfcoefs_i(F, n, d); nd = n*d; VF = mfcoefs_i(F, nd, 1); VE = mfcoefs_i(mfEk(2), nd, 1); gk = mf_get_gk(F); if (m == 1) { res = cgetg(n+2, t_VEC); for (i = 0; i <= n; i++) gel(res, i+1) = gmulsg(i, gel(VF, i*d+1)); tmp = c_deflate(n, d, RgV_mul_RgXn(VF, VE)); return gerepileupto(av, gsub(res, gmul(gdivgs(gk, 12), tmp))); } else { long j; for (j = 1; j <= m; j++) { tmp = RgV_mul_RgXn(VF, VE); for (i = 0; i <= nd; i++) gel(VF, i+1) = gmulsg(i, gel(VF, i+1)); VF = gsub(VF, gmul(gdivgs(gaddgs(gk, 2*(j-1)), 12), tmp)); } return gerepilecopy(av, c_deflate(n, d, VF)); } } /* Twist by the character (D/.) */ static GEN c_twist(long n, long d, GEN F, GEN D) { pari_sp av = avma; GEN V = mfcoefs_i(F, n, d), res = cgetg(n+2, t_VEC); long i; for (i = 0; i <= n; i++) gel(res, i + 1) = gmulsg(krois(D, i), gel(V, i+1)); return gerepileupto(av, res); } /* form F given by closure, compute T(n)(F) as closure */ static GEN c_hecke(long m, long l, GEN DATA, GEN F) { pari_sp av = avma; return gerepilecopy(av, hecke_i(m, l, NULL, F, DATA)); } static GEN c_const(long n, long d, GEN C) { GEN V = zerovec(n+1); long i, j, l = lg(C); if (l > d*n+2) l = d*n+2; for (i = j = 1; i < l; i+=d, j++) gel(V, j) = gcopy(gel(C,i)); return V; } /* m > 0 */ static GEN eta3_ZXn(long m) { long l = m+2, n, k; GEN P = cgetg(l,t_POL); P[1] = evalsigne(1)|evalvarn(0); for (n = 2; n < l; n++) gel(P,n) = gen_0; for (n = k = 0;; n++) { if (k + n >= m) { setlg(P, k+3); return P; } k += n; /* now k = n(n+1) / 2 */ gel(P, k+2) = odd(n)? utoineg(2*n+1): utoipos(2*n+1); } } static GEN c_delta(long n, long d) { pari_sp ltop = avma; long N = n*d; GEN e; if (!N) return mkvec(gen_0); e = eta3_ZXn(N); e = ZXn_sqr(e,N); e = ZXn_sqr(e,N); e = ZXn_sqr(e,N); /* eta(x)^24 */ settyp(e, t_VEC); gel(e,1) = gen_0; /* Delta(x) = x*eta(x)^24 as a t_VEC */ return gerepilecopy(ltop, c_deflate(n, d, e)); } /* return s(d) such that s|f <=> d | f^2 */ static long mysqrtu(ulong d) { GEN fa = myfactoru(d), P = gel(fa,1), E = gel(fa,2); long l = lg(P), i, s = 1; for (i = 1; i < l; i++) s *= upowuu(P[i], (E[i]+1)>>1); return s; } static GEN c_theta(long n, long d, GEN psi) { long lim = usqrt(n*d), F = mfcharmodulus(psi), par = mfcharparity(psi); long f, d2 = d == 1? 1: mysqrtu(d); GEN V = zerovec(n + 1); for (f = d2; f <= lim; f += d2) if (ugcd(F, f) == 1) { pari_sp av = avma; GEN c = mfchareval_i(psi, f); gel(V, f*f/d + 1) = gerepileupto(av, par < 0 ? gmulgs(c,2*f) : gmul2n(c,1)); } if (F == 1) gel(V, 1) = gen_1; return V; /* no gerepile needed */ } static GEN c_etaquo(long n, long d, GEN eta, GEN gs) { pari_sp av = avma; long s = itos(gs), nd = n*d, nds = nd - s + 1; GEN c; if (nds <= 0) return zerovec(n+1); c = RgX_to_RgC(eta_product_ZXn(eta, nds), nds); settyp(c, t_VEC); if (s > 0) c = shallowconcat(zerovec(s), c); return gerepilecopy(av, c_deflate(n, d, c)); } static GEN c_ell(long n, long d, GEN E) { pari_sp av = avma; GEN v; if (d == 1) return concat(gen_0, anell(E, n)); v = shallowconcat(gen_0, anell(E, n*d)); return gerepilecopy(av, c_deflate(n, d, v)); } static GEN c_cusptrace(long n, long d, GEN F) { pari_sp av = avma; GEN D = gel(F,2), res = cgetg(n+2, t_VEC); long i, N = mf_get_N(F), k = mf_get_k(F); gel(res, 1) = gen_0; for (i = 1; i <= n; i++) gel(res, i+1) = mfcusptrace_i(N, k, i*d, mydivisorsu(i*d), D); return gerepilecopy(av, res); } static GEN c_newtrace(long n, long d, GEN F) { pari_sp av = avma; cachenew_t cache; long N = mf_get_N(F); GEN v; init_cachenew(&cache, n*d, N, F); v = colnewtrace(0, n, d, N, mf_get_k(F), &cache); settyp(v, t_VEC); return gerepilecopy(av, v); } static GEN c_Bd(long n, long d, GEN F, GEN A) { pari_sp av = avma; long a = itou(A), ad = ugcd(a,d), aad = a/ad, i, j; GEN w, v = mfcoefs_i(F, n/aad, d/ad); if (a == 1) return v; n++; w = zerovec(n); for (i = j = 1; j <= n; i++, j += aad) gel(w,j) = gcopy(gel(v,i)); return gerepileupto(av, w); } static GEN c_dihedral(long n, long d, GEN bnr, GEN w, GEN k0j) { pari_sp av = avma; GEN V = dihan(bnr, w, k0j, n*d); GEN Tinit = gel(w,3), Pm = gel(Tinit,1); GEN A = c_deflate(n, d, V); if (degpol(Pm) == 1 || RgV_is_ZV(A)) return gerepilecopy(av, A); return gerepileupto(av, gmodulo(A, Pm)); } static GEN c_mfEH(long n, long d, GEN F) { pari_sp av = avma; GEN v, M, A; long i, r = mf_get_r(F); if (n == 1) return gerepilecopy(av, mkvec2(mfEHcoef(r,0),mfEHcoef(r,d))); /* speedup mfcoef */ if (r == 1) { v = cgetg(n+2, t_VEC); gel(v,1) = sstoQ(-1,12); for (i = 1; i <= n; i++) { long id = i*d, a = id & 3; gel(v,i+1) = (a==1 || a==2)? gen_0: sstoQ(hclassno6u(id), 6); } return v; /* no gerepile needed */ } M = mfEHmat(n*d+1,r); if (d > 1) { long l = lg(M); for (i = 1; i < l; i++) gel(M,i) = c_deflate(n, d, gel(M,i)); } A = gel(F,2); /* [num(B), den(B)] */ v = RgC_Rg_div(RgM_RgC_mul(M, gel(A,1)), gel(A,2)); settyp(v,t_VEC); return gerepileupto(av, v); } static GEN c_mfeisen(long n, long d, GEN F) { pari_sp av = avma; GEN v, vchi, E0, P, T, CHI, gk = mf_get_gk(F); long i, k; if (typ(gk) != t_INT) return c_mfEH(n, d, F); k = itou(gk); vchi = gel(F,2); E0 = gel(vchi,1); T = gel(vchi,2); P = gel(T,1); CHI = gel(vchi,3); v = cgetg(n+2, t_VEC); gel(v, 1) = gcopy(E0); /* E(0) */ if (lg(vchi) == 5) { /* E_k(chi1,chi2) */ GEN CHI2 = gel(vchi,4), F3 = gel(F,3); long ord = F3[1], j = F3[2]; for (i = 1; i <= n; i++) gel(v, i+1) = sigchi2(k, CHI, CHI2, i*d, ord); if (lg(T) == 4) v = QabV_tracerel(T, j, v); } else { /* E_k(chi) */ for (i = 1; i <= n; i++) gel(v, i+1) = sigchi(k, CHI, i*d); } if (degpol(P) != 1 && !RgV_is_QV(v)) return gerepileupto(av, gmodulo(v, P)); return gerepilecopy(av, v); } /* L(chi_D, 1-k) */ static GEN lfunquadneg(long D, long k) { GEN B, dS, S = gen_0; long r, N = labs(D); pari_sp av; if (k == 1 && N == 1) return gneg(ghalf); /* B = N^k * denom(B) * B(x/N) */ B = ZX_rescale(Q_remove_denom(bernpol(k, 0), &dS), utoi(N)); dS = mul_denom(dS, stoi(-N*k)); av = avma; for (r = 0; r < N; r++) { long c = kross(D, r); if (c) { GEN tmp = poleval(B, utoi(r)); S = c > 0 ? addii(S, tmp) : subii(S, tmp); S = gerepileuptoint(av, S); } } return gdiv(S, dS); } /* Returns vector of coeffs from F[0], F[d], ..., F[d*n] */ static GEN mfcoefs_i(GEN F, long n, long d) { if (n < 0) return gen_0; switch(mf_get_type(F)) { case t_MF_CONST: return c_const(n, d, gel(F,2)); case t_MF_EISEN: return c_mfeisen(n, d, F); case t_MF_Ek: return c_Ek(n, d, F); case t_MF_DELTA: return c_delta(n, d); case t_MF_THETA: return c_theta(n, d, gel(F,2)); case t_MF_ETAQUO: return c_etaquo(n, d, gel(F,2), gel(F,3)); case t_MF_ELL: return c_ell(n, d, gel(F,2)); case t_MF_MUL: return c_mul(n, d, gel(F,2), gel(F,3)); case t_MF_POW: return c_pow(n, d, gel(F,2), gel(F,3)); case t_MF_BRACKET: return c_bracket(n, d, gel(F,2), gel(F,3), gel(F,4)); case t_MF_LINEAR: return c_linear(n, d, gel(F,2), gel(F,3), gel(F,4)); case t_MF_LINEAR_BHN: return c_linear_bhn(n, d, F); case t_MF_DIV: return c_div(n, d, gel(F,2), gel(F,3)); case t_MF_SHIFT: return c_shift(n, d, gel(F,2), gel(F,3)); case t_MF_DERIV: return c_deriv(n, d, gel(F,2), gel(F,3)); case t_MF_DERIVE2: return c_derivE2(n, d, gel(F,2), gel(F,3)); case t_MF_TWIST: return c_twist(n, d, gel(F,2), gel(F,3)); case t_MF_HECKE: return c_hecke(n, d, gel(F,2), gel(F,3)); case t_MF_BD: return c_Bd(n, d, gel(F,2), gel(F,3)); case t_MF_TRACE: return c_cusptrace(n, d, F); case t_MF_NEWTRACE: return c_newtrace(n, d, F); case t_MF_DIHEDRAL: return c_dihedral(n, d, gel(F,2), gel(F,3), gel(F,4)); default: pari_err_TYPE("mfcoefs",F); return NULL;/*LCOV_EXCL_LINE*/ } } static GEN matdeflate(long n, long d, GEN M) { long i, l; GEN A; /* if (d == 1) return M; */ A = cgetg_copy(M,&l); for (i = 1; i < l; i++) gel(A,i) = c_deflate(n,d,gel(M,i)); return A; } static int space_is_cusp(long space) { return space != mf_FULL && space != mf_EISEN; } /* safe with flraw mf */ static GEN mfcoefs_mf(GEN mf, long n, long d) { GEN MS, ME, E = MF_get_E(mf), S = MF_get_S(mf), M = MF_get_M(mf); long lE = lg(E), lS = lg(S), l = lE+lS-1; if (l == 1) return cgetg(1, t_MAT); if (typ(M) == t_MAT && lg(M) != 1 && (n+1)*d < nbrows(M)) return matdeflate(n, d, M); /*cached; lg = 1 is possible from mfinit */ ME = (lE == 1)? cgetg(1, t_MAT): mfvectomat(E, n, d); if (lS == 1) MS = cgetg(1, t_MAT); else if (mf_get_type(gel(S,1)) == t_MF_DIV) /*k 1/2-integer or k=1 (exotic)*/ MS = matdeflate(n,d, mflineardivtomat(MF_get_N(mf), S, n*d)); else if (MF_get_k(mf) == 1) /* k = 1 (dihedral) */ { GEN M = mfvectomat(gmael(S,1,2), n, d); long i; MS = cgetg(lS, t_MAT); for (i = 1; i < lS; i++) { GEN f = gel(S,i), dc = gel(f,4), c = RgM_RgC_mul(M, gel(f,3)); if (!equali1(dc)) c = RgC_Rg_div(c,dc); gel(MS,i) = c; } } else /* k >= 2 integer */ MS = bhnmat_extend_nocache(NULL, MF_get_N(mf), n, d, S); return shallowconcat(ME,MS); } GEN mfcoefs(GEN F, long n, long d) { if (!checkmf_i(F)) { pari_sp av = avma; GEN mf = checkMF_i(F); if (!mf) pari_err_TYPE("mfcoefs", F); return gerepilecopy(av, mfcoefs_mf(mf,n,d)); } if (d <= 0) pari_err_DOMAIN("mfcoefs", "d", "<=", gen_0, stoi(d)); if (n < 0) return cgetg(1, t_VEC); return mfcoefs_i(F, n, d); } /* assume k >= 0 */ static GEN mfak_i(GEN F, long k) { if (!k) return gel(mfcoefs_i(F,0,1), 1); return gel(mfcoefs_i(F,1,k), 2); } GEN mfcoef(GEN F, long n) { pari_sp av = avma; if (!checkmf_i(F)) pari_err_TYPE("mfcoef",F); return n < 0? gen_0: gerepilecopy(av, mfak_i(F, n)); } static GEN paramconst() { return tagparams(t_MF_CONST, mkNK(1,0,mfchartrivial())); } static GEN mftrivial(void) { retmkvec2(paramconst(), cgetg(1,t_VEC)); } static GEN mf1(void) { retmkvec2(paramconst(), mkvec(gen_1)); } /* induce mfchar CHI to G */ static GEN induce(GEN G, GEN CHI) { GEN o, chi; if (typ(CHI) == t_INT) /* Kronecker */ { chi = znchar_quad(G, CHI); o = ZV_equal0(chi)? gen_1: gen_2; CHI = mkvec4(G,chi,o,cgetg(1,t_VEC)); } else { if (mfcharmodulus(CHI) == itos(znstar_get_N(G))) return CHI; CHI = leafcopy(CHI); chi = zncharinduce(gel(CHI,1), gel(CHI,2), G); gel(CHI,1) = G; gel(CHI,2) = chi; } return CHI; } /* induce mfchar CHI to znstar(G) */ static GEN induceN(long N, GEN CHI) { if (mfcharmodulus(CHI) != N) CHI = induce(znstar0(utoipos(N),1), CHI); return CHI; } /* *pCHI1 and *pCHI2 are mfchar, induce to common modulus */ static void char2(GEN *pCHI1, GEN *pCHI2) { GEN CHI1 = *pCHI1, G1 = gel(CHI1,1), N1 = znstar_get_N(G1); GEN CHI2 = *pCHI2, G2 = gel(CHI2,1), N2 = znstar_get_N(G2); if (!equalii(N1,N2)) { GEN G, d = gcdii(N1,N2); if (equalii(N2,d)) *pCHI2 = induce(G1, CHI2); else if (equalii(N1,d)) *pCHI1 = induce(G2, CHI1); else { if (!equali1(d)) N2 = diviiexact(N2,d); G = znstar0(mulii(N1,N2), 1); *pCHI1 = induce(G, CHI1); *pCHI2 = induce(G, CHI2); } } } /* mfchar or charinit wrt same modulus; outputs a mfchar */ static GEN mfcharmul_i(GEN CHI1, GEN CHI2) { GEN G = gel(CHI1,1), chi3 = zncharmul(G, gel(CHI1,2), gel(CHI2,2)); return mfcharGL(G, chi3); } /* mfchar or charinit; outputs a mfchar */ static GEN mfcharmul(GEN CHI1, GEN CHI2) { char2(&CHI1, &CHI2); return mfcharmul_i(CHI1,CHI2); } /* mfchar or charinit; outputs a mfchar */ static GEN mfcharpow(GEN CHI, GEN n) { GEN G, chi; G = gel(CHI,1); chi = zncharpow(G, gel(CHI,2), n); return mfcharGL(G, chi); } /* mfchar or charinit wrt same modulus; outputs a mfchar */ static GEN mfchardiv_i(GEN CHI1, GEN CHI2) { GEN G = gel(CHI1,1), chi3 = znchardiv(G, gel(CHI1,2), gel(CHI2,2)); return mfcharGL(G, chi3); } /* mfchar or charinit; outputs a mfchar */ static GEN mfchardiv(GEN CHI1, GEN CHI2) { char2(&CHI1, &CHI2); return mfchardiv_i(CHI1,CHI2); } static GEN mfcharconj(GEN CHI) { CHI = leafcopy(CHI); gel(CHI,2) = zncharconj(gel(CHI,1), gel(CHI,2)); return CHI; } /* CHI mfchar, assume 4 | N. Multiply CHI by \chi_{-4} */ static GEN mfchilift(GEN CHI, long N) { CHI = induceN(N, CHI); return mfcharmul_i(CHI, induce(gel(CHI,1), stoi(-4))); } /* CHI defined mod N, N4 = N/4; * if CHI is defined mod N4 return CHI; * else if CHI' = CHI*(-4,.) is defined mod N4, return CHI' (primitive) * else return NULL */ static GEN mfcharchiliftprim(GEN CHI, long N4) { long FC = mfcharconductor(CHI); if (N4 % FC == 0) return CHI; CHI = mfchilift(CHI, N4 << 2); CHI = mfchartoprimitive(CHI, &FC); return (N4 % FC == 0)? CHI: NULL; } static GEN mfchiadjust(GEN CHI, GEN gk, long N) { long par = mfcharparity(CHI); if (typ(gk) == t_INT && mpodd(gk)) par = -par; return par == 1 ? CHI : mfchilift(CHI, N); } static GEN mfsamefield(GEN P, GEN Q) { if (degpol(P) == 1) return Q; if (degpol(Q) == 1) return P; if (!gequal(P,Q)) pari_err_TYPE("mfsamefield [different fields]",mkvec2(P,Q)); return P; } GEN mfmul(GEN f, GEN g) { pari_sp av = avma; GEN N, K, NK, CHI; if (!checkmf_i(f)) pari_err_TYPE("mfmul",f); if (!checkmf_i(g)) pari_err_TYPE("mfmul",g); N = lcmii(mf_get_gN(f), mf_get_gN(g)); K = gadd(mf_get_gk(f), mf_get_gk(g)); CHI = mfcharmul(mf_get_CHI(f), mf_get_CHI(g)); CHI = mfchiadjust(CHI, K, itos(N)); NK = mkgNK(N, K, CHI, mfsamefield(mf_get_field(f), mf_get_field(g))); return gerepilecopy(av, tag2(t_MF_MUL, NK, f, g)); } GEN mfpow(GEN f, long n) { pari_sp av = avma; GEN KK, NK, gn, CHI; if (!checkmf_i(f)) pari_err_TYPE("mfpow",f); if (!n) return mf1(); if (n == 1) return gcopy(f); KK = gmulsg(n,mf_get_gk(f)); gn = stoi(n); CHI = mfcharpow(mf_get_CHI(f), gn); CHI = mfchiadjust(CHI, KK, mf_get_N(f)); NK = mkgNK(mf_get_gN(f), KK, CHI, mf_get_field(f)); return gerepilecopy(av, tag2(t_MF_POW, NK, f, gn)); } GEN mfbracket(GEN f, GEN g, long m) { pari_sp av = avma; GEN N, K, NK, CHI; if (!checkmf_i(f)) pari_err_TYPE("mfbracket",f); if (!checkmf_i(g)) pari_err_TYPE("mfbracket",g); if (m < 0) pari_err_TYPE("mfbracket [m<0]",stoi(m)); K = gaddgs(gadd(mf_get_gk(f), mf_get_gk(g)), 2*m); if (gsigne(K) < 0) pari_err_IMPL("mfbracket for this form"); N = lcmii(mf_get_gN(f), mf_get_gN(g)); CHI = mfcharmul(mf_get_CHI(f), mf_get_CHI(g)); CHI = mfchiadjust(CHI, K, itou(N)); NK = mkgNK(N, K, CHI, mfsamefield(mf_get_field(f), mf_get_field(g))); return gerepilecopy(av, tag3(t_MF_BRACKET, NK, f, g, utoi(m))); } /* remove 0 entries in L */ static int mflinear_strip(GEN *pF, GEN *pL) { pari_sp av = avma; GEN F = *pF, L = *pL; long i, j, l = lg(L); GEN F2 = cgetg(l, t_VEC), L2 = cgetg(l, t_VEC); for (i = j = 1; i < l; i++) { if (gequal0(gel(L,i))) continue; gel(F2,j) = gel(F,i); gel(L2,j) = gel(L,i); j++; } if (j == l) avma = av; else { setlg(F2,j); *pF = F2; setlg(L2,j); *pL = L2; } return (j > 1); } static GEN taglinear_i(long t, GEN NK, GEN F, GEN L) { GEN dL; L = Q_remove_denom(L, &dL); if (!dL) dL = gen_1; return tag3(t, NK, F, L, dL); } static GEN taglinear(GEN NK, GEN F, GEN L) { long t = ok_bhn_linear(F)? t_MF_LINEAR_BHN: t_MF_LINEAR; return taglinear_i(t, NK, F, L); } /* assume F has parameters NK = [N,K,CHI] */ static GEN mflinear_i(GEN NK, GEN F, GEN L) { if (!mflinear_strip(&F,&L)) return mftrivial(); return taglinear(NK, F,L); } static GEN mflinear_bhn(GEN mf, GEN L) { long i, l; GEN P, NK, F = MF_get_S(mf); if (!mflinear_strip(&F,&L)) return mftrivial(); l = lg(L); P = pol_x(1); for (i = 1; i < l; i++) { GEN c = gel(L,i); if (typ(c) == t_POLMOD && varn(gel(c,1)) == 1) P = mfsamefield(P,gel(c,1)); } NK = mkgNK(MF_get_gN(mf), MF_get_gk(mf), MF_get_CHI(mf), P); return taglinear_i(t_MF_LINEAR_BHN, NK, F,L); } /* F vector of forms with same weight and character but varying level, return * global [N,k,chi,P] */ static GEN vecmfNK(GEN F) { long i, l = lg(F); GEN N, f; if (l == 1) return mkNK(1, 0, mfchartrivial()); f = gel(F,1); N = mf_get_gN(f); for (i = 2; i < l; i++) N = lcmii(N, mf_get_gN(gel(F,i))); return mkgNK(N, mf_get_gk(f), mf_get_CHI(f), mf_get_field(f)); } /* do not use mflinear: mflineardivtomat rely on F being constant across the * basis where mflinear strips the ones matched by 0 coeffs. Assume k and CHI * constant, N is allowed to vary. */ static GEN vecmflinear(GEN F, GEN C) { long i, t, l = lg(C); GEN NK, v = cgetg(l, t_VEC); if (l == 1) return v; t = ok_bhn_linear(F)? t_MF_LINEAR_BHN: t_MF_LINEAR; NK = vecmfNK(F); for (i = 1; i < l; i++) gel(v,i) = taglinear_i(t, NK, F, gel(C,i)); return v; } /* vecmflinear(F,C), then divide everything by E, which has valuation 0 */ static GEN vecmflineardiv0(GEN F, GEN C, GEN E) { GEN v = vecmflinear(F, C); long i, l = lg(v); for (i = 1; i < l; i++) gel(v,i) = mfdiv_val(gel(v,i), E, 0); return v; } /* Non empty linear combination of linear combinations of same * F_j=\sum_i \mu_{i,j}G_i so R = \sum_i (\sum_j(\la_j\mu_{i,j})) G_i */ static GEN mflinear_linear(GEN F, GEN L, int strip) { long l = lg(F), j; GEN vF, M = cgetg(l, t_MAT); for (j = 1; j < l; j++) { GEN f = gel(F,j), c = gel(f,3), d = gel(f,4); if (typ(c) == t_VEC) c = shallowtrans(c); if (!isint1(d)) c = RgC_Rg_div(c, d); gel(M,j) = c; } vF = gmael(F,1,2); L = RgM_RgC_mul(M,L); if (strip && !mflinear_strip(&vF,&L)) return mftrivial(); return taglinear(vecmfNK(vF), vF, L); } /* F non-empty vector of forms of the form mfdiv(mflinear(B,v), E) where E * does not vanish at oo, or mflinear(B,v). Apply mflinear(F, L) */ static GEN mflineardiv_linear(GEN F, GEN L, int strip) { long l = lg(F), j; GEN v, E, f; if (lg(L) != l) pari_err_DIM("mflineardiv_linear"); f = gel(F,1); /* l > 1 */ if (mf_get_type(f) != t_MF_DIV) return mflinear_linear(F,L,strip); E = gel(f,3); v = cgetg(l, t_VEC); for (j = 1; j < l; j++) { GEN f = gel(F,j); gel(v,j) = gel(f,2); } return mfdiv_val(mflinear_linear(v,L,strip), E, 0); } static GEN vecmflineardiv_linear(GEN F, GEN M) { long i, l = lg(M); GEN v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = mflineardiv_linear(F, gel(M,i), 0); return v; } static GEN tobasis(GEN mf, GEN F, GEN L) { if (checkmf_i(L) && mf) return mftobasis(mf, L, 0); if (typ(F) != t_VEC) pari_err_TYPE("mflinear",F); if (!is_vec_t(typ(L))) pari_err_TYPE("mflinear",L); if (lg(L) != lg(F)) pari_err_DIM("mflinear"); return L; } GEN mflinear(GEN F, GEN L) { pari_sp av = avma; GEN G, NK, P, mf = checkMF_i(F), N = NULL, K = NULL, CHI = NULL; long i, l; if (mf) { GEN gk = MF_get_gk(mf); F = MF_get_basis(F); if (typ(gk) != t_INT) return gerepilecopy(av, mflineardiv_linear(F, L, 1)); if (itou(gk) > 1 && space_is_cusp(MF_get_space(mf))) { L = tobasis(mf, F, L); return gerepilecopy(av, mflinear_bhn(mf, L)); } } L = tobasis(mf, F, L); if (!mflinear_strip(&F,&L)) return mftrivial(); l = lg(F); if (l == 2 && gequal1(gel(L,1))) return gerepilecopy(av, gel(F,1)); P = pol_x(1); for (i = 1; i < l; i++) { GEN f = gel(F,i), c = gel(L,i), Ni, Ki; if (!checkmf_i(f)) pari_err_TYPE("mflinear", f); Ni = mf_get_gN(f); N = N? lcmii(N, Ni): Ni; Ki = mf_get_gk(f); if (!K) K = Ki; else if (!gequal(K, Ki)) pari_err_TYPE("mflinear [different weights]", mkvec2(K,Ki)); P = mfsamefield(P, mf_get_field(f)); if (typ(c) == t_POLMOD && varn(gel(c,1)) == 1) P = mfsamefield(P, gel(c,1)); } G = znstar0(N,1); for (i = 1; i < l; i++) { GEN CHI2 = mf_get_CHI(gel(F,i)); CHI2 = induce(G, CHI2); if (!CHI) CHI = CHI2; else if (!gequal(CHI, CHI2)) pari_err_TYPE("mflinear [different characters]", mkvec2(CHI,CHI2)); } NK = mkgNK(N, K, CHI, P); return gerepilecopy(av, taglinear(NK,F,L)); } GEN mfshift(GEN F, long sh) { pari_sp av = avma; if (!checkmf_i(F)) pari_err_TYPE("mfshift",F); return gerepilecopy(av, tag2(t_MF_SHIFT, mf_get_NK(F), F, stoi(sh))); } static long mfval(GEN F) { pari_sp av = avma; long i = 0, n, sb; GEN gk, gN; if (!checkmf_i(F)) pari_err_TYPE("mfval", F); gN = mf_get_gN(F); gk = mf_get_gk(F); sb = mfsturmNgk(itou(gN), gk); for (n = 1; n <= sb;) { GEN v; if (n > 0.5*sb) n = sb+1; v = mfcoefs_i(F, n, 1); for (; i <= n; i++) if (!gequal0(gel(v, i+1))) { avma = av; return i; } n <<= 1; } avma = av; return -1; } GEN mfdiv_val(GEN f, GEN g, long vg) { GEN N, K, NK, CHI; if (vg) { f = mfshift(f,vg); g = mfshift(g,vg); } N = lcmii(mf_get_gN(f), mf_get_gN(g)); K = gsub(mf_get_gk(f), mf_get_gk(g)); CHI = mfchardiv(mf_get_CHI(f), mf_get_CHI(g)); CHI = mfchiadjust(CHI, K, itos(N)); NK = mkgNK(N, K, CHI, mfsamefield(mf_get_field(f), mf_get_field(g))); return tag2(t_MF_DIV, NK, f, g); } GEN mfdiv(GEN F, GEN G) { pari_sp av = avma; long v = mfval(G); if (!checkmf_i(F)) pari_err_TYPE("mfdiv", F); if (v < 0 || (v && !gequal0(mfcoefs(F, v-1, 1)))) pari_err_DOMAIN("mfdiv", "ord(G)", ">", strtoGENstr("ord(F)"), mkvec2(F, G)); return gerepilecopy(av, mfdiv_val(F, G, v)); } GEN mfderiv(GEN F, long m) { pari_sp av = avma; GEN NK, gk; if (!checkmf_i(F)) pari_err_TYPE("mfderiv",F); gk = gaddgs(mf_get_gk(F), 2*m); NK = mkgNK(mf_get_gN(F), gk, mf_get_CHI(F), mf_get_field(F)); return gerepilecopy(av, tag2(t_MF_DERIV, NK, F, stoi(m))); } GEN mfderivE2(GEN F, long m) { pari_sp av = avma; GEN NK, gk; if (!checkmf_i(F)) pari_err_TYPE("mfderivE2",F); if (m < 0) pari_err_DOMAIN("mfderivE2","m","<",gen_0,stoi(m)); gk = gaddgs(mf_get_gk(F), 2*m); NK = mkgNK(mf_get_gN(F), gk, mf_get_CHI(F), mf_get_field(F)); return gerepilecopy(av, tag2(t_MF_DERIVE2, NK, F, stoi(m))); } GEN mftwist(GEN F, GEN D) { pari_sp av = avma; GEN NK, CHI, NT, Da; long q; if (!checkmf_i(F)) pari_err_TYPE("mftwist", F); if (typ(D) != t_INT) pari_err_TYPE("mftwist", D); Da = mpabs_shallow(D); CHI = mf_get_CHI(F); q = mfcharconductor(CHI); NT = glcm(glcm(mf_get_gN(F), mulsi(q, Da)), sqri(Da)); NK = mkgNK(NT, mf_get_gk(F), CHI, mf_get_field(F)); return gerepilecopy(av, tag2(t_MF_TWIST, NK, F, D)); } /***************************************************************/ /* Generic cache handling */ /***************************************************************/ enum { cache_FACT, cache_DIV, cache_H, cache_D, cache_DIH }; typedef struct { const char *name; GEN cache; ulong minself; ulong maxself; void (*init)(long); ulong miss; ulong maxmiss; } cache; static void constfact(long lim); static void constdiv(long lim); static void consttabh(long lim); static void consttabdihedral(long lim); static void constcoredisc(long lim); static THREAD cache caches[] = { { "Factors", NULL, 50000, 50000, &constfact, 0, 0 }, { "Divisors", NULL, 50000, 50000, &constdiv, 0, 0 }, { "H", NULL, 100000, 10000000, &consttabh, 0, 0 }, { "CorediscF",NULL, 100000, 10000000, &constcoredisc, 0, 0 }, { "Dihedral", NULL, 1000, 3000, &consttabdihedral, 0, 0 }, }; static void cache_reset(long id) { caches[id].miss = caches[id].maxmiss = 0; } static void cache_delete(long id) { if (caches[id].cache) gunclone(caches[id].cache); } static void cache_set(long id, GEN S) { GEN old = caches[id].cache; caches[id].cache = gclone(S); if (old) gunclone(old); } /* handle a cache miss: store stats, possibly reset table; return value * if (now) cached; return NULL on failure. HACK: some caches contain an * ulong where the 0 value is impossible, and return it (typecase to GEN) */ static GEN cache_get(long id, ulong D) { cache *S = &caches[id]; /* cache_H is compressed: D=0,1 mod 4 */ const ulong d = (id == cache_H)? D>>1: D; ulong max, l; if (!S->cache) { max = maxuu(minuu(D, S->maxself), S->minself); S->init(max); l = lg(S->cache); } else { l = lg(S->cache); if (l <= d) { if (D > S->maxmiss) S->maxmiss = D; if (DEBUGLEVEL >= 3) err_printf("miss in cache %s: %lu, max = %lu\n", S->name, D, S->maxmiss); if (S->miss++ >= 5 && D < S->maxself) { max = minuu(S->maxself, (long)(S->maxmiss * 1.2)); if (max <= S->maxself) { if (DEBUGLEVEL >= 3) err_printf("resetting cache %s to %lu\n", S->name, max); S->init(max); l = lg(S->cache); } } } } return (l <= d)? NULL: gel(S->cache, d); } static GEN cache_report(long id) { cache *S = &caches[id]; GEN v = zerocol(5); gel(v,1) = strtoGENstr(S->name); if (S->cache) { gel(v,2) = utoi(lg(S->cache)-1); gel(v,3) = utoi(S->miss); gel(v,4) = utoi(S->maxmiss); gel(v,5) = utoi(gsizebyte(S->cache)); } return v; } GEN getcache(void) { pari_sp av = avma; GEN M = cgetg(6, t_MAT); gel(M,1) = cache_report(cache_FACT); gel(M,2) = cache_report(cache_DIV); gel(M,3) = cache_report(cache_H); gel(M,4) = cache_report(cache_D); gel(M,5) = cache_report(cache_DIH); return gerepilecopy(av, shallowtrans(M)); } void pari_close_mf(void) { cache_delete(cache_FACT); cache_delete(cache_DIV); cache_delete(cache_H); cache_delete(cache_D); cache_delete(cache_DIH); } /*************************************************************************/ /* a odd, update local cache (recycle memory) */ static GEN update_factor_cache(long a, long lim, long *pb) { const long step = 16000; /* even; don't increase this: RAM cache thrashing */ if (a + 2*step > lim) *pb = lim; /* fuse last 2 chunks */ else *pb = a + step; return vecfactoroddu_i(a, *pb); } /* assume lim < MAX_LONG/8 */ static void constcoredisc(long lim) { pari_sp av2, av = avma; GEN D = caches[cache_D].cache, CACHE = NULL; long cachea, cacheb, N, LIM = !D ? 4 : lg(D)-1; if (lim <= 0) lim = 5; if (lim <= LIM) return; cache_reset(cache_D); D = zero_zv(lim); av2 = avma; cachea = cacheb = 0; for (N = 1; N <= lim; N+=2) { /* N odd */ long i, d, d2; GEN F; if (N > cacheb) { avma = av2; cachea = N; CACHE = update_factor_cache(N, lim, &cacheb); } F = gel(CACHE, ((N-cachea)>>1)+1); /* factoru(N) */ D[N] = d = corediscs_fact(F); /* = 3 mod 4 or 4 mod 16 */ d2 = odd(d)? d<<3: d<<1; for (i = 1;;) { if ((N << i) > lim) break; D[N< lim) break; D[N< 1, D = divisors(n); sets L = 2*lambda(n), S = sigma(n) */ static void lamsig(GEN D, long *pL, long *pS) { pari_sp av = avma; long i, l = lg(D), L = 1, S = D[l-1]+1; for (i = 2; i < l; i++) /* skip d = 1 */ { long d = D[i], nd = D[l-i]; /* nd = n/d */ if (d < nd) { L += d; S += d + nd; } else { L <<= 1; if (d == nd) { L += d; S += d; } break; } } avma = av; *pL = L; *pS = S; } /* table of 6 * Hurwitz class numbers D <= lim */ static void consttabh(long lim) { pari_sp av = avma, av2; GEN VHDH0, VDIV, CACHE = NULL; GEN VHDH = caches[cache_H].cache; long r, N, cachea, cacheb, lim0 = VHDH? lg(VHDH)-1: 2, LIM = lim0 << 1; if (lim <= 0) lim = 5; if (lim <= LIM) return; cache_reset(cache_H); r = lim&3L; if (r) lim += 4-r; cache_get(cache_DIV, lim); VDIV = caches[cache_DIV].cache; VHDH0 = cgetg(lim/2 + 1, t_VECSMALL); VHDH0[1] = 2; VHDH0[2] = 3; for (N = 3; N <= lim0; N++) VHDH0[N] = VHDH[N]; av2 = avma; cachea = cacheb = 0; for (N = LIM + 3; N <= lim; N += 4) { long s = 0, limt = usqrt(N>>2), flsq = 0, ind, t, L, S; GEN DN, DN2; if (N + 2 >= lg(VDIV)) { /* use local cache */ GEN F; if (N + 2 > cacheb) { avma = av2; cachea = N; CACHE = update_factor_cache(N, lim+2, &cacheb); } F = gel(CACHE, ((N-cachea)>>1)+1); /* factoru(N) */ DN = divisorsu_fact(F); F = gel(CACHE, ((N-cachea)>>1)+2); /* factoru(N+2) */ DN2 = divisorsu_fact(F); } else { /* use global cache */ DN = gel(VDIV,N); DN2 = gel(VDIV,N+2); } ind = N >> 1; for (t = 1; t <= limt; t++) { ind -= (t<<2)-2; /* N/2 - 2t^2 */ if (ind) s += VHDH0[ind]; else flsq = 1; } lamsig(DN, &L,&S); VHDH0[N >> 1] = 2*S - 3*L - 2*s + flsq; s = 0; flsq = 0; limt = (usqrt(N+2) - 1) >> 1; ind = (N+1) >> 1; for (t = 1; t <= limt; t++) { ind -= t<<2; /* (N+1)/2 - 2t(t+1) */ if (ind) s += VHDH0[ind]; else flsq = 1; } lamsig(DN2, &L,&S); VHDH0[(N+1) >> 1] = S - 3*(L >> 1) - s - flsq; } cache_set(cache_H, VHDH0); avma = av; } /*************************************************************************/ /* Core functions using factorizations, divisors of class numbers caches */ /* TODO: myfactoru and factorization cache should be exported */ static GEN myfactoru(long N) { GEN z = cache_get(cache_FACT, N); return z? gcopy(z): factoru(N); } static GEN mydivisorsu(long N) { GEN z = cache_get(cache_DIV, N); return z? leafcopy(z): divisorsu(N); } /* write -n = Df^2, D < 0 fundamental discriminant. Return D, set f. */ static long mycoredisc2neg(ulong n, long *pf) { ulong m, D = (ulong)cache_get(cache_D, n); if (D) { *pf = usqrt(n/D); return -(long)D; } m = mycore(n, pf); if ((m&3) != 3) { m <<= 2; *pf >>= 1; } return (long)-m; } /* write n = Df^2, D > 0 fundamental discriminant. Return D, set f. */ static long mycoredisc2pos(ulong n, long *pf) { ulong m = mycore(n, pf); if ((m&3) != 1) { m <<= 2; *pf >>= 1; } return (long)m; } /* 1+p+...+p^e, e >= 1 */ static ulong usumpow(ulong p, long e) { ulong q = 1+p; long i; for (i = 1; i < e; i++) q = p*q + 1; return q; } /* Hurwitz(D0 F^2)/ Hurwitz(D0) * = \sum_{f|F} f \prod_{p|f} (1-kro(D0/p)/p) * = \prod_{p^e || F} (1 + (p^e-1) / (p-1) * (p-kro(D0/p))) */ static long get_sh(long F, long D0) { GEN fa = myfactoru(F), P = gel(fa,1), E = gel(fa,2); long i, l = lg(P), t = 1; for (i = 1; i < l; i++) { long p = P[i], e = E[i], s = kross(D0,p); if (e == 1) { t *= 1 + p - s; continue; } if (s == 1) { t *= upowuu(p,e); continue; } t *= 1 + usumpow(p,e-1)*(p-s); } return t; } /* d > 0, d = 0,3 (mod 4). Return 6*hclassno(d); -d must be fundamental * Faster than quadclassunit up to 5*10^5 or so */ static ulong hclassno6u_count(ulong d) { ulong a, b, b2, h = 0; int f = 0; if (d > 500000) return 6 * itou(gel(quadclassunit0(utoineg(d), 0, NULL, 0), 1)); /* this part would work with -d non fundamental */ b = d&1; b2 = (1+d)>>2; if (!b) { for (a=1; a*a>2; } while (b2*3 < d) { if (b2%b == 0) h++; for (a=b+1; a*a < b2; a++) if (b2%a == 0) h += 2; if (a*a == b2) h++; b += 2; b2 = (b*b+d)>>2; } if (b2*3 == d) return 6*h+2; if (f) return 6*h+3; return 6*h; } /* D > 0; 6 * hclassno(D), using D = D0*F^2 */ static long hclassno6u_2(ulong D, long D0, long F) { long h; if (F == 1) h = hclassno6u_count(D); else { /* second chance */ h = (ulong)cache_get(cache_H, -D0); if (!h) h = hclassno6u_count(-D0); h *= get_sh(F,D0); } return h; } /* D > 0; 6 * hclassno(D) (6*Hurwitz). Beware, cached value for D (=0,3 mod 4) * is stored at D>>1 */ ulong hclassno6u(ulong D) { ulong z = (ulong)cache_get(cache_H, D); long D0, F; if (z) return z; D0 = mycoredisc2neg(D, &F); return hclassno6u_2(D,D0,F); } /* same, where the decomposition D = D0*F^2 is already known */ static ulong hclassno6u_i(ulong D, long D0, long F) { ulong z = (ulong)cache_get(cache_H, D); if (z) return z; return hclassno6u_2(D,D0,F); } #if 0 /* D > 0, return h(-D) [ordinary class number]. * Assume consttabh(D or more) was previously called */ static long hfromH(long D) { pari_sp ltop = avma; GEN m, d, fa = myfactoru(D), P = gel(fa,1), E = gel(fa,2); GEN VH = caches[cache_H].cache; long i, nd, S, l = lg(P); /* n = d[i] loops through squarefree divisors of f, where f^2 = largest square * divisor of N = |D|; m[i] = moebius(n) */ nd = 1 << (l-1); d = cgetg(nd+1, t_VECSMALL); m = cgetg(nd+1, t_VECSMALL); d[1] = 1; S = VH[D >> 1]; /* 6 hclassno(-D) */ m[1] = 1; nd = 1; i = 1; if (P[1] == 2 && E[1] <= 3) /* need D/n^2 to be a discriminant */ { if (odd(E[1]) || (E[1] == 2 && (D & 15) == 4)) i = 2; } for (; i> 1]; /* 6 hclassno(-D/n^2) */ if (s > 0) S += hn; else S -= hn; } nd <<= 1; } avma = ltop; return S/6; } #endif /* D < -4 fundamental, h(D), ordinary class number */ static long myh(long D) { ulong z = (ulong)cache_get(cache_H, -D); if (z) return z/6; /* should be hfromH(-D) if D non-fundamental */ return itou(quadclassno(stoi(D))); } /*************************************************************************/ /* TRACE FORMULAS */ /* CHIP primitive, initialize for t_POLMOD output */ static GEN mfcharinit(GEN CHIP) { long n, o, l, vt, N = mfcharmodulus(CHIP); GEN c, v, V, G, Pn; if (N == 1) return mkvec2(mkvec(gen_1), pol_x(0)); G = gel(CHIP,1); v = ncharvecexpo(G, znconrey_normalized(G, gel(CHIP,2))); l = lg(v); V = cgetg(l, t_VEC); o = mfcharorder(CHIP); Pn = mfcharpol(CHIP); vt = varn(Pn); if (o <= 2) { for (n = 1; n < l; n++) { if (v[n] < 0) c = gen_0; else c = v[n]? gen_m1: gen_1; gel(V,n) = c; } } else { for (n = 1; n < l; n++) { if (v[n] < 0) c = gen_0; else { c = mygmodulo_lift(v[n], o, gen_1, vt); if (typ(c) == t_POL && lg(c) >= lg(Pn)) c = RgX_rem(c, Pn); } gel(V,n) = c; } } return mkvec2(V, Pn); } static GEN vchip_lift(GEN VCHI, long x, GEN C) { GEN V = gel(VCHI,1); long F = lg(V)-1; if (F == 1) return C; x %= F; if (!x) return C; if (x <= 0) x += F; return gmul(C, gel(V, x)); } static long vchip_FC(GEN VCHI) { return lg(gel(VCHI,1))-1; } static GEN vchip_mod(GEN VCHI, GEN S) { return (typ(S) == t_POL)? RgX_rem(S, gel(VCHI,2)): S; } static GEN vchip_polmod(GEN VCHI, GEN S) { return (typ(S) == t_POL)? mkpolmod(S, gel(VCHI,2)): S; } /* ceil(m/d) */ static long ceildiv(long m, long d) { long q; if (!m) return 0; q = m/d; return m%d? q+1: q; } /* contribution of scalar matrices in dimension formula */ static GEN A1(long N, long k) { return sstoQ(mypsiu(N)*(k-1), 12); } static long ceilA1(long N, long k) { return ceildiv(mypsiu(N) * (k-1), 12); } /* sturm bound, slightly larger than dimension */ long mfsturmNk(long N, long k) { return 1 + (mypsiu(N)*k)/12; } long mfsturmNgk(long N, GEN k) { long n,d; Qtoss(k,&n,&d); return (d == 1)? mfsturmNk(N,n): 1 + (mypsiu(N)*n)/24; } /* List of all solutions of x^2 + x + 1 = 0 modulo N, x modulo N */ static GEN sqrtm3modN(long N) { pari_sp av; GEN fa, P, E, B, mB, A, Q, T, R, v, gen_m3; long l, i, n, ct, fl3 = 0, Ninit; if (!odd(N) || (N%9) == 0) return cgetg(1,t_VECSMALL); Ninit = N; if ((N%3) == 0) { N /= 3; fl3 = 1; } fa = myfactoru(N); P = gel(fa, 1); E = gel(fa, 2); l = lg(P); for (i = 1; i < l; i++) if ((P[i]%3) == 2) return cgetg(1,t_VECSMALL); A = cgetg(l, t_VECSMALL); B = cgetg(l, t_VECSMALL); mB= cgetg(l, t_VECSMALL); Q = cgetg(l, t_VECSMALL); gen_m3 = utoineg(3); for (i = 1; i < l; i++) { long p = P[i], e = E[i]; Q[i] = upowuu(p,e); B[i] = itou( Zp_sqrt(gen_m3, utoipos(p), e) ); mB[i]= Q[i] - B[i]; } ct = 1 << (l-1); T = ZV_producttree(Q); R = ZV_chinesetree(Q,T); v = cgetg(ct+1, t_VECSMALL); av = avma; for (n = 1; n <= ct; n++) { long m = n-1, r; for (i = 1; i < l; i++) { A[i] = (m&1L)? mB[i]: B[i]; m >>= 1; } r = itou( ZV_chinese_tree(A, Q, T, R) ); if (fl3) while (r%3) r += N; avma = av; v[n] = odd(r) ? (r-1) >> 1 : (r+Ninit-1) >> 1; } return v; } /* number of elliptic points of order 3 in X0(N) */ static long nu3(long N) { long i, l; GEN P; if (!odd(N) || (N%9) == 0) return 0; if ((N%3) == 0) N /= 3; P = gel(myfactoru(N), 1); l = lg(P); for (i = 1; i < l; i++) if ((P[i]%3) == 2) return 0; return 1L<<(l-1); } /* number of elliptic points of order 2 in X0(N) */ static long nu2(long N) { long i, l; GEN P; if ((N&3L) == 0) return 0; if (!odd(N)) N >>= 1; P = gel(myfactoru(N), 1); l = lg(P); for (i = 1; i < l; i++) if ((P[i]&3L) == 3) return 0; return 1L<<(l-1); } /* contribution of elliptic matrices of order 3 in dimension formula * Only depends on CHIP the primitive char attached to CHI */ static GEN A21(long N, long k, GEN CHI) { GEN res, G, chi, o; long a21, i, limx, S; if ((N&1L) == 0) return gen_0; a21 = k%3 - 1; if (!a21) return gen_0; if (N <= 3) return sstoQ(a21, 3); if (!CHI) return sstoQ(nu3(N) * a21, 3); res = sqrtm3modN(N); limx = (N - 1) >> 1; G = gel(CHI,1); chi = gel(CHI,2); o = gmfcharorder(CHI); for (S = 0, i = 1; i < lg(res); i++) { /* (x,N) = 1; S += chi(x) + chi(x^2) */ long x = res[i]; if (x <= limx) { /* CHI(x)=e(c/o), 3rd-root of 1 */ GEN c = znchareval(G, chi, utoi(x), o); if (!signe(c)) S += 2; else S--; } } return sstoQ(a21 * S, 3); } /* List of all square roots of -1 modulo N */ static GEN sqrtm1modN(long N) { pari_sp av; GEN fa, P, E, B, mB, A, Q, T, R, v; long l, i, n, ct, fleven = 0; if ((N&3L) == 0) return cgetg(1,t_VECSMALL); if ((N&1L) == 0) { N >>= 1; fleven = 1; } fa = myfactoru(N); P = gel(fa,1); E = gel(fa,2); l = lg(P); for (i = 1; i < l; i++) if ((P[i]&3L) == 3) return cgetg(1,t_VECSMALL); A = cgetg(l, t_VECSMALL); B = cgetg(l, t_VECSMALL); mB= cgetg(l, t_VECSMALL); Q = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) { long p = P[i], e = E[i]; Q[i] = upowuu(p,e); B[i] = itou( Zp_sqrt(gen_m1, utoipos(p), e) ); mB[i]= Q[i] - B[i]; } ct = 1 << (l-1); T = ZV_producttree(Q); R = ZV_chinesetree(Q,T); v = cgetg(ct+1, t_VECSMALL); av = avma; for (n = 1; n <= ct; n++) { long m = n-1, r; for (i = 1; i < l; i++) { A[i] = (m&1L)? mB[i]: B[i]; m >>= 1; } r = itou( ZV_chinese_tree(A, Q, T, R) ); if (fleven && !odd(r)) r += N; avma = av; v[n] = r; } return v; } /* contribution of elliptic matrices of order 4 in dimension formula. * Only depends on CHIP the primitive char attached to CHI */ static GEN A22(long N, long k, GEN CHI) { GEN G, chi, o, res; long S, a22, i, limx, o2; if ((N&3L) == 0) return gen_0; a22 = (k & 3L) - 1; /* (k % 4) - 1 */ if (!a22) return gen_0; if (N <= 2) return sstoQ(a22, 4); if (!CHI) return sstoQ(nu2(N)*a22, 4); if (mfcharparity(CHI) == -1) return gen_0; res = sqrtm1modN(N); limx = (N - 1) >> 1; G = gel(CHI,1); chi = gel(CHI,2); o = gmfcharorder(CHI); o2 = itou(o)>>1; for (S = 0, i = 1; i < lg(res); i++) { /* (x,N) = 1, S += real(chi(x)) */ long x = res[i]; if (x <= limx) { /* CHI(x)=e(c/o), 4th-root of 1 */ long c = itou( znchareval(G, chi, utoi(x), o) ); if (!c) S++; else if (c == o2) S--; } } return sstoQ(a22 * S, 2); } /* sumdiv(N,d,eulerphi(gcd(d,N/d))) */ static long nuinf(long N) { GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2); long i, t = 1, l = lg(P); for (i=1; i>1) << 1; else t *= upowuu(p,(e>>1)-1) * (p+1); } return t; } /* contribution of hyperbolic matrices in dimension formula */ static GEN A3(long N, long FC) { long i, S, NF, l; GEN D; if (FC == 1) return sstoQ(nuinf(N),2); D = mydivisorsu(N); l = lg(D); S = 0; NF = N/FC; for (i = 1; i < l; i++) { long g = ugcd(D[i], D[l-i]); if (NF%g == 0) S += myeulerphiu(g); } return sstoQ(S, 2); } /* special contribution in weight 2 in dimension formula */ static long A4(long k, long FC) { return (k==2 && FC==1)? 1: 0; } /* gcd(x,N) */ static long myugcd(GEN GCD, ulong x) { ulong N = lg(GCD)-1; if (x >= N) x %= N; return GCD[x+1]; } /* 1_{gcd(x,N) = 1} * chi(x), return NULL if 0 */ static GEN mychicgcd(GEN GCD, GEN VCHI, long x) { long N = lg(GCD)-1; if (N == 1) return gen_1; x = smodss(x, N); if (GCD[x+1] != 1) return NULL; x %= vchip_FC(VCHI); if (!x) return gen_1; return gel(gel(VCHI,1), x); } /* contribution of scalar matrices to trace formula */ static GEN TA1(long N, long k, GEN VCHI, GEN GCD, long n) { GEN S; ulong m; if (!uissquareall(n, &m)) return gen_0; if (m == 1) return A1(N,k); /* common */ S = mychicgcd(GCD, VCHI, m); return S? gmul(gmul(powuu(m, k-2), A1(N,k)), S): gen_0; } /* All square roots modulo 4N, x modulo 2N, precomputed to accelerate TA2 */ static GEN mksqr(long N) { pari_sp av = avma; long x, N2 = N << 1, N4 = N << 2; GEN v = const_vec(N2, cgetg(1, t_VECSMALL)); gel(v, N2) = mkvecsmall(0); /* x = 0 */ for (x = 1; x <= N; x++) { long r = (((x*x - 1)%N4) >> 1) + 1; gel(v,r) = vecsmall_append(gel(v,r), x); } return gerepilecopy(av, v); } static GEN mkgcd(long N) { GEN GCD, d; long i, N2; if (N == 1) return mkvecsmall(N); GCD = cgetg(N + 1, t_VECSMALL); d = GCD+1; /* GCD[i+1] = d[i] = gcd(i,N) = gcd(N-i,N), i = 0..N-1 */ d[0] = N; d[1] = d[N-1] = 1; N2 = N>>1; for (i = 2; i <= N2; i++) d[i] = d[N-i] = ugcd(N, i); return GCD; } /* Table of \sum_{x^2-tx+n=0 mod Ng}chi(x) for all g dividing gcd(N,F), * F^2 largest such that (t^2-4n)/F^2=0 or 1 mod 4; t >= 0 */ static GEN mutglistall(long t, long N, long NF, GEN VCHI, long n, GEN MUP, GEN li, GEN GCD) { long i, lx = lg(li); GEN DNF = mydivisorsu(NF), v = zerovec(NF); long j, g, lDNF = lg(DNF); for (i = 1; i < lx; i++) { long x = (li[i] + t) >> 1, y, lD; GEN D, c = mychicgcd(GCD, VCHI, x); if (li[i] && li[i] != N) { GEN c2 = mychicgcd(GCD, VCHI, t - x); if (c2) c = c? gadd(c, c2): c2; } if (!c) continue; y = (x*(x - t) + n) / N; /* exact division */ D = mydivisorsu(ugcd(labs(y), NF)); lD = lg(D); for (j=1; j < lD; j++) { g = D[j]; gel(v,g) = gadd(gel(v,g), c); } } /* j = 1 corresponds to g = 1, and MUP[1] = 1 */ for (j=2; j < lDNF; j++) { g = DNF[j]; gel(v,g) = gmulsg(MUP[g], gel(v,g)); } return v; } /* special case (N,F) = 1: easier */ static GEN mutg1(long t, long N, GEN VCHI, GEN li, GEN GCD) { /* (N,F) = 1 */ GEN S = NULL; long i, lx = lg(li); for (i = 1; i < lx; i++) { long x = (li[i] + t) >> 1; GEN c = mychicgcd(GCD, VCHI, x); if (c) S = S? gadd(S, c): c; if (li[i] && li[i] != N) { c = mychicgcd(GCD, VCHI, t - x); if (c) S = S? gadd(S, c): c; } if (S && !signe(S)) S = NULL; /* strive hard to add gen_0 */ } return S; /* single value */ } /* Gegenbauer pol; n > 2, P = \sum_{0<=j<=n/2} (-1)^j (n-j)!/j!(n-2*j)! X^j */ static GEN mfrhopol(long n) { #ifdef LONG_IS_64BIT const long M = 2642249; #else const long M = 1629; #endif long j, d = n >> 1; /* >= 1 */ GEN P = cgetg(d + 3, t_POL); if (n > M) pari_err_IMPL("mfrhopol for large weight"); /* avoid overflow */ P[1] = evalvarn(0)|evalsigne(1); gel(P,2) = gen_1; gel(P,3) = utoineg(n-1); /* j = 1 */ if (d > 1) gel(P,4) = utoipos(((n-3)*(n-2)) >> 1); /* j = 2 */ if (d > 2) gel(P,5) = utoineg(((n-5)*(n-4)*(n-3)) / 6); /* j = 3 */ for (j = 4; j <= d; j++) gel(P,j+2) = divis(mulis(gel(P,j+1), (n-2*j+1)*(n-2*j+2)), (n-j+1)*(-j)); return P; } /* polrecip(Q)(t2), assume Q(0) = 1 */ static GEN ZXrecip_u_eval(GEN Q, ulong t2) { GEN T = addiu(gel(Q,3), t2); long l = lg(Q), j; for (j = 4; j < l; j++) T = addii(gel(Q,j), mului(t2, T)); return T; } /* return sh * sqrt(n)^nu * G_nu(t/(2*sqrt(n))) for t != 0 * else (sh/2) * sqrt(n)^nu * G_nu(0) [ implies nu is even ] * G_nu(z) = \sum_{0<=j<=nu/2} (-1)^j (nu-j)!/j!(nu-2*j)! * (2z)^(nu-2*j)) */ static GEN mfrhopowsimp(GEN Q, GEN sh, long nu, long t, long t2, long n) { GEN T; switch (nu) { case 0: return t? sh: gmul2n(sh,-1); case 1: return gmulsg(t, sh); case 2: return t? gmulsg(t2 - n, sh): gmul(gmul2n(stoi(-n), -1), sh); case 3: return gmul(mulss(t, t2 - 2*n), sh); default: if (!t) return gmul(gmul2n(gel(Q, lg(Q) - 1), -1), sh); T = ZXrecip_u_eval(Q, t2); if (odd(nu)) T = mulsi(t, T); return gmul(T, sh); } } /* contribution of elliptic matrices to trace formula */ static GEN TA2(long N, long k, GEN VCHI, long n, GEN SQRTS, GEN MUP, GEN GCD) { const long n4 = n << 2, N4 = N << 2, nu = k - 2; const long st = (!odd(N) && odd(n)) ? 2 : 1; long limt, t; GEN S, Q; limt = usqrt(n4); if (limt*limt == n4) limt--; Q = nu > 3 ? ZX_z_unscale(mfrhopol(nu), n) : NULL; S = gen_0; for (t = odd(k)? st: 0; t <= limt; t += st) /* t^2 < 4n */ { pari_sp av = avma; long t2 = t*t, D = n4 - t2, F, D0, NF; GEN sh, li; li = gel(SQRTS, (smodss(-D - 1, N4) >> 1) + 1); if (lg(li) == 1) continue; D0 = mycoredisc2neg(D, &F); NF = myugcd(GCD, F); if (NF == 1) { /* (N,F) = 1 => single value in mutglistall */ GEN mut = mutg1(t, N, VCHI, li, GCD); if (!mut) { avma = av; continue; } sh = gmul(sstoQ(hclassno6u_i(D,D0,F),6), mut); } else { GEN v = mutglistall(t, N, NF, VCHI, n, MUP, li, GCD); GEN DF = mydivisorsu(F); long i, lDF = lg(DF); sh = gen_0; for (i = 1; i < lDF; i++) { long Ff, f = DF[i], g = myugcd(GCD, f); GEN mut = gel(v, g); if (gequal0(mut)) continue; Ff = DF[lDF-i]; /* F/f */ if (Ff == 1) sh = gadd(sh, mut); else { GEN P = gel(myfactoru(Ff), 1); long j, lP = lg(P); for (j = 1; j < lP; j++) { long p = P[j]; Ff -= kross(D0, p)*Ff/p; } sh = gadd(sh, gmulsg(Ff, mut)); } } if (gequal0(sh)) { avma = av; continue; } if (D0 == -3) sh = gdivgs(sh, 3); else if (D0 == -4) sh = gdivgs(sh, 2); else sh = gmulgs(sh, myh(D0)); } S = gerepileupto(av, gadd(S, mfrhopowsimp(Q,sh,nu,t,t2,n))); } return S; } /* compute global auxiliary data for TA3 */ static GEN mkbez(long N, long FC) { long ct, i, NF = N/FC; GEN w, D = mydivisorsu(N); long l = lg(D); w = cgetg(l, t_VEC); for (i = ct = 1; i < l; i++) { long u, v, h, c = D[i], Nc = D[l-i]; if (c > Nc) break; h = cbezout(c, Nc, &u, &v); if (h == 1) /* shortcut */ gel(w, ct++) = mkvecsmall4(1,u*c,1,i); else if (!(NF%h)) gel(w, ct++) = mkvecsmall4(h,u*(c/h),myeulerphiu(h),i); } setlg(w,ct); stackdummy((pari_sp)(w+ct),(pari_sp)(w+l)); return w; } /* contribution of hyperbolic matrices to trace formula, d * nd = n, * DN = divisorsu(N) */ static GEN auxsum(GEN VCHI, GEN GCD, long d, long nd, GEN DN, GEN BEZ) { GEN S = gen_0; long ct, g = nd - d, lDN = lg(DN), lBEZ = lg(BEZ); for (ct = 1; ct < lBEZ; ct++) { GEN y, B = gel(BEZ, ct); long ic, c, Nc, uch, h = B[1]; if (g%h) continue; uch = B[2]; ic = B[4]; c = DN[ic]; Nc= DN[lDN - ic]; /* Nc = N/c */ if (ugcd(Nc, nd) == 1) y = mychicgcd(GCD, VCHI, d + uch*g); /* 0 if (c,d) > 1 */ else y = NULL; if (c != Nc && ugcd(Nc, d) == 1) { GEN y2 = mychicgcd(GCD, VCHI, nd - uch*g); /* 0 if (c,nd) > 1 */ if (y2) y = y? gadd(y, y2): y2; } if (y) S = gadd(S, gmulsg(B[3], y)); } return S; } static GEN TA3(long N, long k, GEN VCHI, GEN GCD, GEN Dn, GEN BEZ) { GEN S = gen_0, DN = mydivisorsu(N); long i, l = lg(Dn); for (i = 1; i < l; i++) { long d = Dn[i], nd = Dn[l-i]; /* = n/d */ GEN t, u; if (d > nd) break; t = auxsum(VCHI, GCD, d, nd, DN, BEZ); if (isintzero(t)) continue; u = powuu(d,k-1); if (d == nd) u = gmul2n(u,-1); S = gadd(S, gmul(u,t)); } return S; } /* special contribution in weight 2 in trace formula */ static long TA4(long k, GEN VCHIP, GEN Dn, GEN GCD) { long i, l, S; if (k != 2 || vchip_FC(VCHIP) != 1) return 0; l = lg(Dn); S = 0; for (i = 1; i < l; i++) { long d = Dn[i]; /* gcd(N,n/d) == 1? */ if (myugcd(GCD, Dn[l-i]) == 1) S += d; } return S; } /* precomputation of products occurring im mutg, again to accelerate TA2 */ static GEN mkmup(long N) { GEN fa = myfactoru(N), P = gel(fa,1), D = divisorsu_fact(fa); long i, lP = lg(P), lD = lg(D); GEN MUP = zero_zv(N); MUP[1] = 1; for (i = 2; i < lD; i++) { long j, g = D[i], Ng = D[lD-i]; /* N/g */ for (j = 1; j < lP; j++) { long p = P[j]; if (Ng%p) g += g/p; } MUP[D[i]] = g; } return MUP; } /* quadratic non-residues mod p; p odd prime, p^2 fits in a long */ static GEN non_residues(long p) { long i, j, p2 = p >> 1; GEN v = cgetg(p2+1, t_VECSMALL), w = const_vecsmall(p-1, 1); for (i = 2; i <= p2; i++) w[(i*i) % p] = 0; /* no need to check 1 */ for (i = 2, j = 1; i < p; i++) if (w[i]) v[j++] = i; return v; } /* CHIP primitive. Return t_VECSMALL v of length q such that * Tr^new_{N,CHIP}(n) = 0 whenever v[(n%q) + 1] is non-zero */ static GEN mfnewzerodata(long N, GEN CHIP) { GEN V, M, L, faN = myfactoru(N), PN = gel(faN,1), EN = gel(faN,2); GEN G = gel(CHIP,1), chi = gel(CHIP,2); GEN fa = znstar_get_faN(G), P = ZV_to_zv(gel(fa,1)), E = gel(fa,2); long i, mod, j = 1, l = lg(PN); M = cgetg(l, t_VECSMALL); M[1] = 0; V = cgetg(l, t_VEC); /* Tr^new(n) = 0 if (n mod M[i]) in V[i] */ if ((N & 3) == 0) { long e = EN[1]; long c = (lg(P) > 1 && P[1] == 2)? E[1]: 0; /* c = v_2(FC) */ /* e >= 2 */ if (c == e-1) return NULL; /* Tr^new = 0 */ if (c == e) { if (e == 2) { /* sc: -4 */ gel(V,1) = mkvecsmall(3); M[1] = 4; } else if (e == 3) { /* sc: -8 (CHI_2(-1)=-1<=>chi[1]=1) and 8 (CHI_2(-1)=1 <=> chi[1]=0) */ long t = signe(gel(chi,1))? 7: 3; gel(V,1) = mkvecsmall2(5, t); M[1] = 8; } } else if (e == 5 && c == 3) { /* sc: -8 (CHI_2(-1)=-1<=>chi[1]=1) and 8 (CHI_2(-1)=1 <=> chi[1]=0) */ long t = signe(gel(chi,1))? 7: 3; gel(V,1) = mkvecsmalln(6, 2L,4L,5L,6L,8L,t); M[1] = 8; } else if ((e == 4 && c == 2) || (e == 5 && c <= 2) || (e == 6 && c <= 2) || (e >= 7 && c == e - 3)) { /* sc: 4 */ gel(V,1) = mkvecsmall3(0,2,3); M[1] = 4; } else if ((e <= 4 && c == 0) || (e >= 5 && c == e - 2)) { /* sc: 2 */ gel(V,1) = mkvecsmall(0); M[1] = 2; } else if ((e == 6 && c == 3) || (e >= 7 && c <= e - 4)) { /* sc: -2 */ gel(V,1) = mkvecsmalln(7, 0L,2L,3L,4L,5L,6L,7L); M[1] = 8; } } j = M[1]? 2: 1; for (i = odd(N)? 1: 2; i < l; i++) /* skip p=2, done above */ { long p = PN[i], e = EN[i]; long z = zv_search(P, p), c = z? E[z]: 0; /* c = v_p(FC) */ if ((e <= 2 && c == 1 && itos(gel(chi,z)) == (p>>1)) /* ord(CHI_p)=2 */ || (e >= 3 && c <= e - 2)) { /* sc: -p */ GEN v = non_residues(p); if (e != 1) v = vecsmall_prepend(v, 0); gel(V,j) = v; M[j] = p; j++; } else if (e >= 2 && c < e) { /* sc: p */ gel(V,j) = mkvecsmall(0); M[j] = p; j++; } } if (j == 1) return cgetg(1, t_VECSMALL); setlg(V,j); setlg(M,j); mod = zv_prod(M); L = zero_zv(mod); for (i = 1; i < j; i++) { GEN v = gel(V,i); long s, m = M[i], lv = lg(v); for (s = 1; s < lv; s++) { long a = v[s] + 1; do { L[a] = 1; a += m; } while (a <= mod); } } return L; } /* v=mfnewzerodata(N,CHI); returns TRUE if newtrace(n) must be zero, * (but newtrace(n) may still be zero if we return FALSE) */ static long mfnewchkzero(GEN v, long n) { long q = lg(v)-1; return q && v[(n%q) + 1]; } /* if (!VCHIP): from mftraceform_cusp; * else from initnewtrace and CHI is known to be primitive */ static GEN inittrace(long N, GEN CHI, GEN VCHIP) { long FC; if (VCHIP) FC = mfcharmodulus(CHI); else VCHIP = mfcharinit(mfchartoprimitive(CHI, &FC)); return mkvecn(5, mksqr(N), mkmup(N), mkgcd(N), VCHIP, mkbez(N, FC)); } /* p > 2 prime; return a sorted t_VECSMALL of primes s.t Tr^new(p) = 0 for all * weights > 2 */ static GEN inittrconj(long N, long FC) { GEN fa, P, E, v; long i, k, l; if (FC != 1) return cgetg(1,t_VECSMALL); fa = myfactoru(N >> vals(N)); P = gel(fa,1); l = lg(P); E = gel(fa,2); v = cgetg(l, t_VECSMALL); for (i = k = 1; i < l; i++) { long j, p = P[i]; /* > 2 */ for (j = 1; j < l; j++) if (j != i && E[j] == 1 && kross(-p, P[j]) == 1) v[k++] = p; } setlg(v,k); return v; } /* assume CHIP primitive, f(CHIP) | N; NZ = mfnewzerodata(N,CHIP) */ static GEN initnewtrace_i(long N, GEN CHIP, GEN NZ) { GEN T = const_vec(N, cgetg(1,t_VEC)), D, VCHIP; long FC = mfcharmodulus(CHIP), N1, N2, i, l; if (!NZ) NZ = mkvecsmall(1); /*Tr^new = 0; initialize data nevertheless*/ VCHIP = mfcharinit(CHIP); N1 = N/FC; newd_params(N1, &N2); D = mydivisorsu(N1/N2); l = lg(D); N2 *= FC; for (i = 1; i < l; i++) { long M = D[i]*N2; gel(T,M) = inittrace(M, CHIP, VCHIP); } gel(T,N) = shallowconcat(gel(T,N), mkvec2(NZ, inittrconj(N,FC))); return T; } /* don't initialize if Tr^new = 0, return NULL */ static GEN initnewtrace(long N, GEN CHI) { GEN CHIP = mfchartoprimitive(CHI, NULL), NZ = mfnewzerodata(N,CHIP); return NZ? initnewtrace_i(N, CHIP, NZ): NULL; } /* (-1)^k */ static long m1pk(long k) { return odd(k)? -1 : 1; } static long badchar(long N, long k, GEN CHI) { return mfcharparity(CHI) != m1pk(k) || (CHI && N % mfcharconductor(CHI)); } /* dimension of space of cusp forms S_k(\G_0(N),CHI) * Only depends on CHIP the primitive char attached to CHI */ long mfcuspdim(long N, long k, GEN CHI) { pari_sp av = avma; long FC; GEN s; if (k <= 0) return 0; if (k == 1) return mfwt1cuspdim(N, CHI); FC = CHI? mfcharconductor(CHI): 1; if (FC == 1) CHI = NULL; s = gsub(A1(N, k), gadd(A21(N, k, CHI), A22(N, k, CHI))); s = gadd(s, gsubsg(A4(k, FC), A3(N, FC))); avma = av; return itos(s); } /* dimension of whole space M_k(\G_0(N),CHI) * Only depends on CHIP the primitive char attached to CHI; assumes !badchar */ long mffulldim(long N, long k, GEN CHI) { pari_sp av = avma; long FC = CHI? mfcharconductor(CHI): 1; GEN s; if (k <= 0) return (k == 0 && FC == 1)? 1: 0; if (k == 1) { long dim = itos(A3(N, FC)); avma = av; return dim + mfwt1cuspdim(N, CHI); } if (FC == 1) CHI = NULL; s = gsub(A1(N, k), gadd(A21(N, k, CHI), A22(N, k, CHI))); s = gadd(s, A3(N, FC)); avma = av; return itos(s); } /* Dimension of the space of Eisenstein series */ long mfeisensteindim(long N, long k, GEN CHI) { pari_sp av = avma; long s, FC = CHI? mfcharconductor(CHI): 1; if (k <= 0) return (k == 0 && FC == 1)? 1: 0; s = itos(gmul2n(A3(N, FC), 1)); if (k > 1) s -= A4(k, FC); else s >>= 1; avma = av; return s; } enum { _SQRTS = 1, _MUP, _GCD, _VCHIP, _BEZ, _NEWLZ, _TRCONJ }; /* Trace of T(n) on space of cuspforms; only depends on CHIP the primitive char * attached to CHI */ static GEN mfcusptrace_i(long N, long k, long n, GEN Dn, GEN S) { pari_sp av = avma; GEN a, b, VCHIP, GCD; long t; if (!n) return gen_0; VCHIP = gel(S,_VCHIP); GCD = gel(S,_GCD); t = TA4(k, VCHIP, Dn, GCD); a = TA1(N, k, VCHIP, GCD, n); if (t) a = gaddgs(a,t); b = TA2(N, k, VCHIP, n, gel(S,_SQRTS), gel(S,_MUP), GCD); b = gadd(b, TA3(N, k, VCHIP, GCD, Dn, gel(S,_BEZ))); b = gsub(a,b); if (typ(b) != t_POL) return gerepileupto(av, b); return gerepilecopy(av, vchip_polmod(VCHIP, b)); } static GEN mfcusptracecache(long N, long k, long n, GEN Dn, GEN S, cachenew_t *cache) { GEN C = NULL, T = gel(cache->vfull,N); long lcache = lg(T); if (n < lcache) C = gel(T, n); if (C) cache->cuspHIT++; else C = mfcusptrace_i(N, k, n, Dn, S); cache->cuspTOTAL++; if (n < lcache) gel(T,n) = C; return C; } /* return the divisors of n, known to be among the elements of D */ static GEN div_restrict(GEN D, ulong n) { long i, j, l; GEN v, VDIV = caches[cache_DIV].cache; if (lg(VDIV) > n) return gel(VDIV,n); l = lg(D); v = cgetg(l, t_VECSMALL); for (i = j = 1; i < l; i++) { ulong d = D[i]; if (n % d == 0) v[j++] = d; } setlg(v,j); return v; } /* for some prime divisors of N, Tr^new(p) = 0 */ static int trconj(GEN T, long N, long n) { return (lg(T) > 1 && N % n == 0 && zv_search(T, n)); } /* n > 0; trace formula on new space */ static GEN mfnewtrace_i(long N, long k, long n, cachenew_t *cache) { GEN VCHIP, s, Dn, DN1, SN, S = cache->DATA; long FC, N1, N2, N1N2, g, i, j, lDN1; if (!S) return gen_0; SN = gel(S,N); if (mfnewchkzero(gel(SN,_NEWLZ), n)) return gen_0; if (k > 2 && trconj(gel(SN,_TRCONJ), N, n)) return gen_0; VCHIP = gel(SN, _VCHIP); FC = vchip_FC(VCHIP); N1 = N/FC; newt_params(N1, n, FC, &g, &N2); N1N2 = N1/N2; DN1 = mydivisorsu(N1N2); lDN1 = lg(DN1); N2 *= FC; Dn = mydivisorsu(n); /* this one is probably out of cache */ s = gmulsg(mubeta2(N1N2,n), mfcusptracecache(N2, k, n, Dn, gel(S,N2), cache)); for (i = 2; i < lDN1; i++) { /* skip M1 = 1, done above */ long M1 = DN1[i], N1M1 = DN1[lDN1-i]; GEN Dg = mydivisorsu(ugcd(M1, g)); M1 *= N2; s = gadd(s, gmulsg(mubeta2(N1M1,n), mfcusptracecache(M1, k, n, Dn, gel(S,M1), cache))); for (j = 2; j < lg(Dg); j++) /* skip d = 1, done above */ { long d = Dg[j], ndd = n/(d*d), M = M1/d; GEN z = mulsi(mubeta2(N1M1,ndd), powuu(d,k-1)), C = vchip_lift(VCHIP,d,z); GEN Dndd = div_restrict(Dn, ndd); s = gadd(s, gmul(C, mfcusptracecache(M, k, ndd, Dndd, gel(S,M), cache))); } s = vchip_mod(VCHIP, s); } return vchip_polmod(VCHIP, s); } /* mfcuspdim(N,k,CHI) - mfnewdim(N,k,CHI); CHIP primitive (for efficiency) */ static long mfolddim_i(long N, long k, GEN CHIP) { long S, i, l, FC = mfcharmodulus(CHIP), N1 = N/FC, N2; GEN D; newd_params(N1, &N2); /* will ensure mubeta != 0 */ D = mydivisorsu(N1/N2); l = lg(D); N2 *= FC; S = 0; for (i = 2; i < l; i++) { long M = D[l-i]*N2, d = mfcuspdim(M, k, CHIP); if (d) S -= mubeta(D[i]) * d; } return S; } long mfolddim(long N, long k, GEN CHI) { pari_sp av = avma; GEN CHIP = mfchartoprimitive(CHI, NULL); long S = mfolddim_i(N, k, CHIP); avma = av; return S; } /* Only depends on CHIP the primitive char attached to CHI; assumes !badchar */ long mfnewdim(long N, long k, GEN CHI) { pari_sp av = avma; long S; GEN CHIP = mfchartoprimitive(CHI, NULL); S = mfcuspdim(N, k, CHIP); if (!S) return 0; S -= mfolddim_i(N, k, CHIP); avma = av; return S; } /* trace form, given as closure */ static GEN mftraceform_new(long N, long k, GEN CHI) { GEN T; if (k == 1) return initwt1newtrace(mfinit_Nkchi(N, 1, CHI, mf_CUSP, 0)); T = initnewtrace(N,CHI); if (!T) return mftrivial(); return tag(t_MF_NEWTRACE, mkNK(N,k,CHI), T); } static GEN mftraceform_cusp(long N, long k, GEN CHI) { if (k == 1) return initwt1trace(mfinit_Nkchi(N, 1, CHI, mf_CUSP, 0)); return tag(t_MF_TRACE, mkNK(N,k,CHI), inittrace(N,CHI,NULL)); } static GEN mftraceform_i(GEN NK, long space) { GEN CHI; long N, k; checkNK(NK, &N, &k, &CHI, 0); if (!mfdim_Nkchi(N, k, CHI, space)) return mftrivial(); switch(space) { case mf_NEW: return mftraceform_new(N, k, CHI); case mf_CUSP:return mftraceform_cusp(N, k, CHI); } pari_err_DOMAIN("mftraceform", "space", "=", utoi(space), NK); return NULL;/*LCOV_EXCL_LINE*/ } GEN mftraceform(GEN NK, long space) { pari_sp av = avma; return gerepilecopy(av, mftraceform_i(NK,space)); } static GEN hecke_data(long N, long n) { return mkvecsmall3(n, u_ppo(n, N), N); } /* 1/2-integral weight */ static GEN heckef2_data(long N, long n) { ulong f, fN, fN2; if (!uissquareall(n, &f)) return NULL; fN = u_ppo(f, N); fN2 = fN*fN; return mkvec2(myfactoru(fN), mkvecsmall4(n, N, fN2, n/fN2)); } /* N = mf_get_N(F) or a multiple */ static GEN mfhecke_i(long n, long N, GEN F) { if (n == 1) return F; return tag2(t_MF_HECKE, mf_get_NK(F), hecke_data(N,n), F); } GEN mfhecke(GEN mf, GEN F, long n) { pari_sp av = avma; GEN NK, CHI, gk, DATA; long N, nk, dk; mf = checkMF(mf); if (!checkmf_i(F)) pari_err_TYPE("mfhecke",F); if (n <= 0) pari_err_TYPE("mfhecke [n <= 0]", stoi(n)); if (n == 1) return gcopy(F); gk = mf_get_gk(F); Qtoss(gk,&nk,&dk); CHI = mf_get_CHI(F); N = MF_get_N(mf); if (dk == 2) { DATA = heckef2_data(N,n); if (!DATA) return mftrivial(); } else DATA = hecke_data(N,n); NK = mkgNK(lcmii(stoi(N), mf_get_gN(F)), gk, CHI, mf_get_field(F)); return gerepilecopy(av, tag2(t_MF_HECKE, NK, DATA, F)); } /* form F given by closure, compute B(d)(F) as closure (q -> q^d) */ static GEN mfbd_i(GEN F, long d) { GEN D, NK, gk, CHI; if (d == 1) return F; if (d <= 0) pari_err_TYPE("mfbd [d <= 0]", stoi(d)); if (mf_get_type(F) != t_MF_BD) D = utoi(d); else { D = mului(d, gel(F,3)); F = gel(F,2); } gk = mf_get_gk(F); CHI = mf_get_CHI(F); if (typ(gk) != t_INT) CHI = mfcharmul(CHI, get_mfchar(utoi(d << 2))); NK = mkgNK(muliu(mf_get_gN(F), d), gk, CHI, mf_get_field(F)); return tag2(t_MF_BD, NK, F, D); } GEN mfbd(GEN F, long d) { pari_sp av = avma; if (!checkmf_i(F)) pari_err_TYPE("mfbd",F); return gerepilecopy(av, mfbd_i(F, d)); } /* CHI is a character defined modulo N4 */ static GEN RgV_shimura(GEN V, long n, long D, long N4, long r, GEN CHI) { GEN R, a0, Pn = mfcharpol(CHI); long m, Da, ND, ord = mfcharorder(CHI), vt = varn(Pn), d4 = D & 3L; if (d4 == 2 || d4 == 3) D *= 4; Da = labs(D); ND = N4*Da; R = cgetg(n + 2, t_VEC); a0 = gel(V, 1); if (!gequal0(a0)) { long D4 = D << 2; GEN CHID = induceN(ulcm(mfcharmodulus(CHI), labs(D4)), CHI); CHID = mfcharmul_i(CHID, induce(gel(CHID,1), stoi(D4))); a0 = gmul(a0, charLFwtk(r, CHID, mfcharorder(CHID))); } if (odd(ND) && !odd(mfcharmodulus(CHI))) ND <<= 1; gel(R, 1) = a0; for (m = 1; m <= n; m++) { GEN Dm = mydivisorsu(u_ppo(m, ND)), S = gel(V, m*m + 1); long i, l = lg(Dm); for (i = 2; i < l; i++) { /* (e,ND) = 1; skip i = 1: e = 1, done above */ long e = Dm[i], me = m / e; long a = mfcharevalord(CHI, e, ord); GEN c, C = powuu(e, r - 1); if (kross(D, e) == -1) C = negi(C); c = mygmodulo_lift(a, ord, C, vt); S = gadd(S, gmul(c, gel(V, me*me + 1))); } gel(R, m+1) = S; } return degpol(Pn) > 1? gmodulo(R, Pn): R; } static GEN c_shimura(long n, GEN F, long D, GEN CHI) { GEN v = mfcoefs_i(F, n*n, labs(D)); return RgV_shimura(v, n, D, mf_get_N(F)>>2, mf_get_r(F), CHI); } static long mfisinkohnen(GEN mf, GEN F) { GEN v, gk = MF_get_gk(mf), CHI = MF_get_CHI(mf); long i, sb, eps, N4 = MF_get_N(mf) >> 2, r = MF_get_r(mf); sb = mfsturmNgk(N4 << 4, gk) + 1; eps = N4 % mfcharconductor(CHI)? -1 : 1; if (odd(r)) eps = -eps; v = mfcoefs(F, sb, 1); for (i = 0; i <= sb; i++) { long j = i & 3L; if ((j == 2 || j == 2 + eps) && !gequal0(gel(v,i+1))) return 0; } return 1; } static long mfshimura_space_cusp(GEN mf) { long fl = 1, r = MF_get_r(mf), M = MF_get_N(mf) >> 2; if (r == 1 && M >= 4) { GEN E = gel(myfactoru(M), 2); long ma = vecsmall_max(E); if (ma > 2 || (ma == 2 && !mfcharistrivial(MF_get_CHI(mf)))) fl = 0; } return fl; } /* D is either a discriminant (not necessarily fundamental) with sign(D)=(-1)^{k-1/2}*eps, or a positive squarefree integer t, which is then transformed into a fundamental discriminant of the correct sign. */ GEN mfshimura(GEN mf, GEN F, long D) { pari_sp av = avma; GEN gk, G, res, mf2, CHI, CHIP; long M, r, space, cusp, N4, flagdisc = 0; if (!checkmf_i(F)) pari_err_TYPE("mfshimura",F); gk = mf_get_gk(F); if (typ(gk) != t_FRAC) pari_err_TYPE("mfshimura [integral weight]", F); r = MF_get_r(mf); if (r <= 0) pari_err_DOMAIN("mfshimura", "weight", "<=", ghalf, gk); N4 = MF_get_N(mf) >> 2; CHI = MF_get_CHI(mf); CHIP = mfcharchiliftprim(CHI, N4); if (!CHIP) CHIP = CHI; else { long epsD = CHI == CHIP? D: -D, rd = D & 3L; if (odd(r)) epsD = -epsD; if (epsD > 0 && (rd == 0 || rd == 1)) flagdisc = 1; else { if (D < 0 || !uissquarefree(D)) pari_err_TYPE("shimura [incorrect D]", stoi(D)); D = epsD; } } M = N4; cusp = mfiscuspidal(mf,F); space = cusp && mfshimura_space_cusp(mf)? mf_CUSP : mf_FULL; if (!cusp || !flagdisc || !mfisinkohnen(mf,F)) M <<= 1; mf2 = mfinit_Nkchi(M, r << 1, mfcharpow(CHI, gen_2), space, 0); G = c_shimura(mfsturm(mf2), F, D, CHIP); res = mftobasis_i(mf2, G); /* not mflinear(mf2,): we want lowest possible level */ G = mflinear(MF_get_basis(mf2), res); return gerepilecopy(av, mkvec3(mf2, G, res)); } /* W ZabM (ZM if n = 1), a t_INT or NULL, b t_INT, ZXQ mod P or NULL. * Write a/b = A/d with d t_INT and A Zab return [W,d,A,P] */ static GEN mkMinv(GEN W, GEN a, GEN b, GEN P) { GEN A = (b && typ(b) == t_POL)? Q_remove_denom(QXQ_inv(b,P), &b): NULL; if (a && b) { a = Qdivii(a,b); if (typ(a) == t_INT) b = gen_1; else { b = gel(a,2); a = gel(a,1); } if (is_pm1(a)) a = NULL; } if (a) A = A? ZX_Z_mul(A,a): a; else if (!A) A = gen_1; if (!b) b = gen_1; if (!P) P = gen_0; return mkvec4(W,b,A,P); } /* M square invertible QabM, return [M',d], M*M' = d*Id */ static GEN QabM_Minv(GEN M, GEN P, long n) { GEN dW, W, dM; M = Q_remove_denom(M, &dM); W = P? ZabM_inv(liftpol_shallow(M), P, n, &dW): ZM_inv(M, &dW); return mkMinv(W, dM, dW, P); } /* Simplified form of mfclean, after a QabM_indexrank: M a ZabM with full * column rank and z = indexrank(M) is known */ static GEN mfclean2(GEN M, GEN z, GEN P, long n) { GEN d, Minv, y = gel(z,1), W = rowpermute(M, y); W = P? ZabM_inv(liftpol_shallow(W), P, n, &d): ZM_inv(W, &d); M = rowslice(M, 1, y[lg(y)-1]); Minv = mkMinv(W, NULL, d, P); return mkvec3(y, Minv, M); } /* M QabM, lg(M)>1 and [y,z] its rank profile. Let Minv be the inverse of the * invertible square matrix in mkMinv format. Return [y,Minv, M[..y[#y],]] * P cyclotomic polynomial of order n != 2 mod 4 or NULL */ static GEN mfclean(GEN M, GEN P, long n, int ratlift) { GEN W, v, y, z, d, Minv, dM, MdM = Q_remove_denom(M, &dM); if (n == 1) W = ZM_pseudoinv(MdM, &v, &d); else W = ZabM_pseudoinv_i(liftpol_shallow(MdM), P, n, &v, &d, ratlift); y = gel(v,1); z = gel(v,2); if (lg(z) != lg(MdM)) M = vecpermute(M,z); M = rowslice(M, 1, y[lg(y)-1]); Minv = mkMinv(W, dM, d, P); return mkvec3(y, Minv, M); } /* call mfclean using only CHI */ static GEN mfcleanCHI(GEN M, GEN CHI, int ratlift) { long n = mfcharorder_canon(CHI); GEN P = (n == 1)? NULL: mfcharpol(CHI); return mfclean(M, P, n, ratlift); } /* DATA component of a t_MF_NEWTRACE. Was it stripped to save memory ? */ static int newtrace_stripped(GEN DATA) { return DATA && (lg(DATA) == 5 && typ(gel(DATA,3)) == t_INT); } /* f a t_MF_NEWTRACE */ static GEN newtrace_DATA(long N, GEN f) { GEN DATA = gel(f,2); return newtrace_stripped(DATA)? initnewtrace(N, DATA): DATA; } /* reset cachenew for new level incorporating new DATA, tf a t_MF_NEWTRACE * (+ possibly initialize 'full' for new allowed levels) */ static void reset_cachenew(cachenew_t *cache, long N, GEN tf) { long i, n, l; GEN v, DATA = newtrace_DATA(N,tf); cache->DATA = DATA; if (!DATA) return; n = cache->n; v = cache->vfull; l = N+1; /* = lg(DATA) */ for (i = 1; i < l; i++) if (typ(gel(v,i)) == t_INT && lg(gel(DATA,i)) != 1) gel(v,i) = const_vec(n, NULL); cache->VCHIP = gel(gel(DATA,N),_VCHIP); } /* initialize a cache of newtrace / cusptrace up to index n and level | N; * DATA may be NULL (<=> Tr^new = 0). tf a t_MF_NEWTRACE */ static void init_cachenew(cachenew_t *cache, long n, long N, GEN tf) { long i, l = N+1; /* = lg(tf.DATA) when DATA != NULL */ GEN v; cache->n = n; cache->vnew = v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = (N % i)? gen_0: const_vec(n, NULL); cache->newHIT = cache->newTOTAL = cache->cuspHIT = cache->cuspTOTAL = 0; cache->vfull = v = zerovec(N); reset_cachenew(cache, N, tf); } static void dbg_cachenew(cachenew_t *C) { if (DEBUGLEVEL >= 2 && C) err_printf("newtrace cache hits: new = %ld/%ld, cusp = %ld/%ld\n", C->newHIT, C->newTOTAL, C->cuspHIT, C->cuspTOTAL); } /* newtrace_{N,k}(d*i), i = n0, ..., n */ static GEN colnewtrace(long n0, long n, long d, long N, long k, cachenew_t *cache) { GEN v = cgetg(n-n0+2, t_COL); long i; for (i = n0; i <= n; i++) gel(v, i-n0+1) = mfnewtracecache(N, k, i*d, cache); return v; } /* T_n(l*m0, l*(m0+1), ..., l*m) F, F = t_MF_NEWTRACE [N,k],DATA, cache * contains DATA != NULL as well as cached values of F */ static GEN heckenewtrace(long m0, long m, long l, long N, long NBIG, long k, long n, cachenew_t *cache) { long lD, a, k1, nl = n*l; GEN D, V, v = colnewtrace(m0, m, nl, N, k, cache); /* d=1 */ GEN VCHIP; if (n == 1) return v; VCHIP = cache->VCHIP; D = mydivisorsu(u_ppo(n, NBIG)); lD = lg(D); k1 = k - 1; for (a = 2; a < lD; a++) { /* d > 1, (d,NBIG) = 1 */ long i, j, d = D[a], c = ugcd(l, d), dl = d/c, m0d = ceildiv(m0, dl); GEN C = vchip_lift(VCHIP, d, powuu(d, k1)); /* m0=0: i = 1 => skip F(0) = 0 */ if (!m0) { i = 1; j = dl; } else { i = 0; j = m0d*dl; } V = colnewtrace(m0d, m/dl, nl/(d*c), N, k, cache); /* C = chi(d) d^(k-1) */ for (; j <= m; i++, j += dl) gel(v,j-m0+1) = gadd(gel(v,j-m0+1), vchip_mod(VCHIP, gmul(C,gel(V,i+1)))); } return v; } /* Given v = an[i], return an[d*i] */ static GEN anextract(GEN v, long n, long d) { GEN w = cgetg(n+2, t_VEC); long i; for (i = 0; i <= n; i++) gel(w, i+1) = gel(v, i*d+1); return w; } /* T_n(F)(0, l, ..., l*m) */ static GEN hecke_i(long m, long l, GEN V, GEN F, GEN DATA) { long k, n, nNBIG, NBIG, lD, M, a, t, nl; GEN D, v, CHI; if (typ(DATA) == t_VEC) { /* 1/2-integral k */ if (!V) { GEN S = gel(DATA,2); V = mfcoefs_i(F, m*l*S[3], S[4]); } return RgV_heckef2(m, l, V, F, DATA); } k = mf_get_k(F); n = DATA[1]; nl = n*l; nNBIG = DATA[2]; NBIG = DATA[3]; if (nNBIG == 1) return V? V: mfcoefs_i(F,m,nl); if (!V && mf_get_type(F) == t_MF_NEWTRACE) { /* inline F to allow cache, T_n at level NBIG acting on Tr^new(N,k,CHI) */ cachenew_t cache; long N = mf_get_N(F); init_cachenew(&cache, m*nl, N, F); v = heckenewtrace(0, m, l, N, NBIG, k, n, &cache); dbg_cachenew(&cache); settyp(v, t_VEC); return v; } CHI = mf_get_CHI(F); D = mydivisorsu(nNBIG); lD = lg(D); M = m + 1; t = nNBIG * ugcd(nNBIG, l); if (!V) V = mfcoefs_i(F, m * t, nl / t); /* usually nl = t */ v = anextract(V, m, t); /* mfcoefs(F, m, nl); d = 1 */ for (a = 2; a < lD; a++) { /* d > 1, (d, NBIG) = 1 */ long d = D[a], c = ugcd(l, d), dl = d/c, i, idl; GEN C = gmul(mfchareval_i(CHI, d), powuu(d, k-1)); GEN w = anextract(V, m/dl, t/(d*c)); /* mfcoefs(F, m/dl, nl/(d*c)) */ for (i = idl = 1; idl <= M; i++, idl += dl) gel(v,idl) = gadd(gel(v,idl), gmul(C, gel(w,i))); } return v; } static GEN mkmf(GEN x1, GEN x2, GEN x3, GEN x4, GEN x5) { GEN MF = obj_init(5, MF_SPLITN); gel(MF,1) = x1; gel(MF,2) = x2; gel(MF,3) = x3; gel(MF,4) = x4; gel(MF,5) = x5; return MF; } /* return an integer b such that p | b => T_p^k Tr^new = 0, for all k > 0 */ static long get_badj(long N, long FC) { GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2); long i, b = 1, l = lg(P); for (i = 1; i < l; i++) if (E[i] > 1 && u_lval(FC, P[i]) < E[i]) b *= P[i]; return b; } /* in place, assume perm strictly increasing */ static void vecpermute_inplace(GEN v, GEN perm) { long i, l = lg(perm); for (i = 1; i < l; i++) gel(v,i) = gel(v,perm[i]); } /* Find basis of newspace using closures; assume k >= 2 and !badchar. * Return NULL if space is empty, else * [mf1, list of closures T(j)traceform, list of corresponding j, matrix] */ static GEN mfnewinit(long N, long k, GEN CHI, cachenew_t *cache, long init) { GEN S, vj, M, CHIP, mf1, listj, P, tf; long j, ct, ctlj, dim, jin, SB, sb, two, ord, FC, badj; dim = mfnewdim(N, k, CHI); if (!dim && !init) return NULL; sb = mfsturmNk(N, k); CHIP = mfchartoprimitive(CHI, &FC); /* remove newtrace data from S to save space in output: negligible slowdown */ tf = tag(t_MF_NEWTRACE, mkNK(N,k,CHIP), CHIP); badj = get_badj(N, FC); /* try sbsmall first: Sturm bound not sharp for new space */ SB = ceilA1(N, k); listj = cgetg(2*sb + 3, t_VECSMALL); for (j = ctlj = 1; ctlj < 2*sb + 3; j++) if (ugcd(j, badj) == 1) listj[ctlj++] = j; if (init) { init_cachenew(cache, (SB+1)*listj[dim+1], N, tf); if (init == -1 || !dim) return NULL; /* old space or dim = 0 */ } else reset_cachenew(cache, N, tf); /* cache.DATA is not NULL */ ord = mfcharorder_canon(CHIP); P = ord == 1? NULL: mfcharpol(CHIP); vj = cgetg(dim+1, t_VECSMALL); M = cgetg(dim+1, t_MAT); for (two = 1, ct = 0, jin = 1; two <= 2; two++) { long a, jlim = jin + sb; for (a = jin; a <= jlim; a++) { GEN z, vecz; ct++; vj[ct] = listj[a]; gel(M, ct) = heckenewtrace(0, SB, 1, N, N, k, vj[ct], cache); if (ct < dim) continue; z = QabM_indexrank(M, P, ord); vecz = gel(z, 2); ct = lg(vecz) - 1; if (ct == dim) { M = mkvec3(z, gen_0, M); break; } /*maximal rank, done*/ vecpermute_inplace(M, vecz); vecpermute_inplace(vj, vecz); } if (a <= jlim) break; /* sbsmall was not sufficient, use Sturm bound: must extend M */ for (j = 1; j <= ct; j++) { GEN t = heckenewtrace(SB + 1, sb, 1, N, N, k, vj[j], cache); gel(M,j) = shallowconcat(gel(M, j), t); } jin = jlim + 1; SB = sb; } S = cgetg(dim + 1, t_VEC); for (j = 1; j <= dim; j++) gel(S, j) = mfhecke_i(vj[j], N, tf); dbg_cachenew(cache); mf1 = mkvec4(utoipos(N), utoipos(k), CHI, utoi(mf_NEW)); return mkmf(mf1, cgetg(1,t_VEC), S, vj, M); } /* k > 1 integral, mf space is mf_CUSP or mf_FULL */ static GEN mfinittonew(GEN mf) { GEN CHI = MF_get_CHI(mf), S = MF_get_S(mf), vMjd = MFcusp_get_vMjd(mf); GEN M = MF_get_M(mf), vj, mf1; long i, j, l, l0 = lg(S), N0 = MF_get_N(mf); for (i = l0-1; i > 0; i--) { long N = gel(vMjd,i)[1]; if (N != N0) break; } if (i == l0-1) return NULL; S = vecslice(S, i+1, l0-1); /* forms of conductor N0 */ l = lg(S); vj = cgetg(l, t_VECSMALL); for (j = 1; j < l; j++) vj[j] = gel(vMjd,j+i)[2]; M = vecslice(M, lg(M)-lg(S)+1, lg(M)-1); /* their coefficients */ M = mfcleanCHI(M, CHI, 0); mf1 = mkvec4(utoipos(N0), MF_get_gk(mf), CHI, utoi(mf_NEW)); return mkmf(mf1, cgetg(1,t_VEC), S, vj, M); } /* Bd(f)[m0..m], v = f[ceil(m0/d)..floor(m/d)], m0d = ceil(m0/d) */ static GEN RgC_Bd_expand(long m0, long m, GEN v, long d, long m0d) { long i, j; GEN w; if (d == 1) return v; w = zerocol(m-m0+1); if (!m0) { i = 1; j = d; } else { i = 0; j = m0d*d; } for (; j <= m; i++, j += d) gel(w,j-m0+1) = gel(v,i+1); return w; } /* S a non-empty vector of t_MF_BD(t_MF_HECKE(t_MF_NEWTRACE)); M the matrix * of their coefficients r*0, r*1, ..., r*m0 (~ mfvectomat) or NULL (empty), * extend it to coeffs up to m > m0. The forms B_d(T_j(tf_N))in S should be * sorted by level N, then j, then increasing d. No reordering here. */ static GEN bhnmat_extend(GEN M, long m, long r, GEN S, cachenew_t *cache) { long i, mr, m0, m0r, Nold = 0, jold = 0, l = lg(S); GEN MAT = cgetg(l, t_MAT), v = NULL; if (M) { m0 = nbrows(M); m0r = m0 * r; } else m0 = m0r = 0; mr = m*r; for (i = 1; i < l; i++) { long d, j, md, N; GEN c, f = bhn_parse(gel(S,i), &d,&j); /* t_MF_NEWTRACE */ N = mf_get_N(f); md = ceildiv(m0r,d); if (N != Nold) { reset_cachenew(cache, N, f); Nold = N; jold = 0; } if (!cache->DATA) { gel(MAT,i) = zerocol(m+1); continue; } if (j != jold || md) { v = heckenewtrace(md, mr/d, 1, N, N, mf_get_k(f), j,cache); jold=j; } c = RgC_Bd_expand(m0r, mr, v, d, md); if (r > 1) c = c_deflate(m-m0, r, c); if (M) c = shallowconcat(gel(M,i), c); gel(MAT,i) = c; } return MAT; } static GEN mfinitcusp(long N, long k, GEN CHI, cachenew_t *cache, long space) { long L, l, lDN1, FC, N1, d1, i, init; GEN vS, vMjd, DN1, vmf, CHIP = mfchartoprimitive(CHI, &FC); d1 = (space == mf_OLD)? mfolddim_i(N, k, CHIP): mfcuspdim(N, k, CHIP); if (!d1) return NULL; N1 = N/FC; DN1 = mydivisorsu(N1); lDN1 = lg(DN1); init = (space == mf_OLD)? -1: 1; vmf = cgetg(lDN1, t_VEC); for (i = lDN1 - 1, l = 1; i; i--) { /* by decreasing level to allow cache */ GEN mf = mfnewinit(FC*DN1[i], k, CHIP, cache, init); if (mf) gel(vmf, l++) = mf; init = 0; } setlg(vmf,l); vmf = vecreverse(vmf); /* reorder by increasing level */ L = mfsturmNk(N, k)+1; vS = vectrunc_init(L); vMjd = vectrunc_init(L); for (i = 1; i < l; i++) { GEN DNM, mf = gel(vmf,i), S = MF_get_S(mf), vj = MFnew_get_vj(mf); long a, lDNM, lS = lg(S), M = MF_get_N(mf); DNM = mydivisorsu(N / M); lDNM = lg(DNM); for (a = 1; a < lS; a++) { GEN tf = gel(S,a); long b, j = vj[a]; for (b = 1; b < lDNM; b++) { long d = DNM[b]; vectrunc_append(vS, mfbd_i(tf, d)); vectrunc_append(vMjd, mkvecsmall3(M, j, d)); } } } return mkmf(NULL, cgetg(1, t_VEC), vS, vMjd, NULL); } long mfsturm_mf(GEN mf) { GEN Mindex = MF_get_Mindex(mf); long n = lg(Mindex)-1; return n? Mindex[n]: 0; } long mfsturm(GEN T) { long N, nk, dk; GEN CHI, mf = checkMF_i(T); if (mf) return mfsturm_mf(mf); checkNK2(T, &N, &nk, &dk, &CHI, 0); return dk == 1 ? mfsturmNk(N, nk) : mfsturmNk(N, (nk + 1) >> 1); } long mfisequal(GEN F, GEN G, long lim) { pari_sp av = avma; long t, sb; if (!checkmf_i(F)) pari_err_TYPE("mfisequal",F); if (!checkmf_i(G)) pari_err_TYPE("mfisequal",G); if (lim) sb = lim; else { GEN gN, gk; gN = mf_get_gN(F); gk = mf_get_gk(F); sb = mfsturmNgk(itou(gN), gk); gN = mf_get_gN(G); gk = mf_get_gk(G); sb = maxss(sb, mfsturmNgk(itou(gN), gk)); } t = gequal(mfcoefs_i(F, sb+1, 1), mfcoefs_i(G, sb+1, 1)); avma = av; return t; } GEN mffields(GEN mf) { if (checkmf_i(mf)) return gcopy(mf_get_field(mf)); mf = checkMF(mf); return gcopy(MF_get_fields(mf)); } GEN mfeigenbasis(GEN mf) { pari_sp ltop = avma; GEN F, S, v, vP; long i, l, k, dS; mf = checkMF(mf); k = MF_get_k(mf); S = MF_get_S(mf); dS = lg(S)-1; if (!dS) return cgetg(1, t_VEC); F = MF_get_newforms(mf); vP = MF_get_fields(mf); if (k == 1) { if (MF_get_space(mf) == mf_FULL) { long dE = lg(MF_get_E(mf)) - 1; if (dE) F = rowslice(F, dE+1, dE+dS); } v = vecmflineardiv_linear(S, F); l = lg(v); } else { GEN (*L)(GEN, GEN) = (MF_get_space(mf) == mf_FULL)? mflinear: mflinear_bhn; l = lg(F); v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = L(mf, gel(F,i)); } for (i = 1; i < l; i++) mf_setfield(gel(v,i), gel(vP,i)); return gerepilecopy(ltop, v); } /* Minv = [M, d, A], v a t_COL; A a Zab, d a t_INT; return (A/d) * M*v */ static GEN Minv_RgC_mul(GEN Minv, GEN v) { GEN M = gel(Minv,1), d = gel(Minv,2), A = gel(Minv,3); v = RgM_RgC_mul(M, v); if (!equali1(A)) { if (typ(A) == t_POL && degpol(A) > 0) A = mkpolmod(A, gel(Minv,4)); v = RgC_Rg_mul(v, A); } if (!equali1(d)) v = RgC_Rg_div(v, d); return v; } static GEN Minv_RgM_mul(GEN Minv, GEN B) { long j, l = lg(B); GEN M = cgetg(l, t_MAT); for (j = 1; j < l; j++) gel(M,j) = Minv_RgC_mul(Minv, gel(B,j)); return M; } /* B * Minv; allow B = NULL for Id */ static GEN RgM_Minv_mul(GEN B, GEN Minv) { GEN M = gel(Minv,1), d = gel(Minv,2), A = gel(Minv,3); if (B) M = RgM_mul(B, M); if (!equali1(A)) { if (typ(A) == t_POL) A = mkpolmod(A, gel(Minv,4)); M = RgM_Rg_mul(M, A); } if (!equali1(d)) M = RgM_Rg_div(M,d); return M; } /* perm vector of strictly increasing indices, v a vector or arbitrary length; * the last r entries of perm fall beyond v. * Return v o perm[1..(-r)], discarding the last r entries of v */ static GEN vecpermute_partial(GEN v, GEN perm, long *r) { long i, n = lg(v)-1, l = lg(perm); GEN w; if (perm[l-1] <= n) { *r = 0; return vecpermute(v,perm); } for (i = 1; i < l; i++) if (perm[i] > n) break; *r = l - i; l = i; w = cgetg(l, typ(v)); for (i = 1; i < l; i++) gel(w,i) = gel(v,perm[i]); return w; } /* given form F, find coeffs of F on mfbasis(mf). If power series, not * guaranteed correct if precision less than Sturm bound */ static GEN mftobasis_i(GEN mf, GEN F) { GEN v, Mindex, Minv; if (!MF_get_dim(mf)) return cgetg(1, t_COL); Mindex = MF_get_Mindex(mf); Minv = MF_get_Minv(mf); if (checkmf_i(F)) { long n = Mindex[lg(Mindex)-1]; v = vecpermute(mfcoefs_i(F, n, 1), Mindex); return Minv_RgC_mul(Minv, v); } else { GEN A = gel(Minv,1), d = gel(Minv,2); long r; v = F; switch(typ(F)) { case t_SER: v = sertocol(v); case t_VEC: case t_COL: break; default: pari_err_TYPE("mftobasis", F); } if (lg(v) == 1) pari_err_TYPE("mftobasis",v); v = vecpermute_partial(v, Mindex, &r); if (!r) return Minv_RgC_mul(Minv, v); /* single solution */ /* affine space of dimension r */ v = RgM_RgC_mul(vecslice(A, 1, lg(v)-1), v); if (!equali1(d)) v = RgC_Rg_div(v,d); return mkvec2(v, vecslice(A, lg(A)-r, lg(A)-1)); } } static GEN const_mat(long n, GEN x) { long j, l = n+1; GEN A = cgetg(l,t_MAT); for (j = 1; j < l; j++) gel(A,j) = const_col(n, x); return A; } /* L is the mftobasis of a form on CUSP space. We allow mf_FULL or mf_CUSP */ static GEN mftonew_i(GEN mf, GEN L, long *plevel) { GEN S, listMjd, CHI, res, Aclos, Acoef, D, perm; long N1, LC, lD, i, l, t, level, N = MF_get_N(mf); if (MF_get_k(mf) == 1) pari_err_IMPL("mftonew in weight 1"); listMjd = MFcusp_get_vMjd(mf); CHI = MF_get_CHI(mf); LC = mfcharconductor(CHI); S = MF_get_S(mf); N1 = N/LC; D = mydivisorsu(N1); lD = lg(D); perm = cgetg(N1+1, t_VECSMALL); for (i = 1; i < lD; i++) perm[D[i]] = i; Aclos = const_mat(lD-1, cgetg(1,t_VEC)); Acoef = const_mat(lD-1, cgetg(1,t_VEC)); l = lg(listMjd); for (i = 1; i < l; i++) { long M, d; GEN v; if (gequal0(gel(L,i))) continue; v = gel(listMjd, i); M = perm[ v[1]/LC ]; d = perm[ v[3] ]; gcoeff(Aclos,M,d) = vec_append(gcoeff(Aclos,M,d), gel(S,i)); gcoeff(Acoef,M,d) = shallowconcat(gcoeff(Acoef,M,d), gel(L,i)); } res = cgetg(l, t_VEC); level = 1; for (i = t = 1; i < lD; i++) { long j, M = D[i]*LC; GEN gM = utoipos(M); for (j = 1; j < lD; j++) { GEN f = gcoeff(Aclos,i,j), C, NK; long d; if (lg(f) == 1) continue; NK = mf_get_NK(gel(f,1)); d = D[j]; C = gcoeff(Acoef,i,j); level = ulcm(level, M*d); gel(res,t++) = mkvec3(gM, utoipos(d), mflinear_i(NK,f,C)); } } if (plevel) *plevel = level; setlg(res, t); return res; } GEN mftonew(GEN mf, GEN F) { pari_sp av = avma; GEN ES; long s; mf = checkMF(mf); s = MF_get_space(mf); if (s != mf_FULL && s != mf_CUSP) pari_err_TYPE("mftonew [not a full or cuspidal space]", mf); ES = mftobasisES(mf,F); if (!gequal0(gel(ES,1))) pari_err_TYPE("mftonew [not a cuspidal form]", F); F = gel(ES,2); return gerepilecopy(av, mftonew_i(mf,F, NULL)); } static GEN mfeisenstein_i(long k, GEN CHI1, GEN CHI2); /* mfinit(F * Theta) */ static GEN mf2init(GEN mf) { GEN CHI = MF_get_CHI(mf), gk = gadd(MF_get_gk(mf), ghalf); long N = MF_get_N(mf); return mfinit_Nkchi(N, itou(gk), mfchiadjust(CHI, gk, N), mf_FULL, 0); } static long mfvec_first_cusp(GEN v) { long i, l = lg(v); for (i = 1; i < l; i++) { GEN F = gel(v,i); long t = mf_get_type(F); if (t == t_MF_BD) { F = gel(F,2); t = mf_get_type(F); } if (t == t_MF_HECKE) { F = gel(F,3); t = mf_get_type(F); } if (t == t_MF_NEWTRACE) break; } return i; } /* vF a vector of mf F of type DIV(LINEAR(BAS,L), f) in (lcm) level N, * F[2]=LINEAR(BAS,L), F[2][2]=BAS=fixed basis (Eisentstein or bhn type), * F[2][3]=L, F[3]=f; mfvectomat(vF, n) */ static GEN mflineardivtomat(long N, GEN vF, long n) { GEN F, M, f, fc, V, ME, B, a0; long lM, lF = lg(vF), i, j; if (lF == 1) return cgetg(1,t_MAT); F = gel(vF,1); M = gmael(F,2,2); /* BAS */ lM = lg(M); i = mfvec_first_cusp(M); if (i == 1) ME = NULL; else { /* BAS starts by Eisenstein */ ME = mfvectomat(vecslice(M,1,i-1), n, 1); M = vecslice(M, i,lM-1); } M = bhnmat_extend_nocache(NULL, N, n, 1, M); if (ME) M = shallowconcat(ME,M); /* M = mfcoefs of BAS */ f = mfcoefsser(gel(F,3),n); a0 = polcoef_i(f, 0, -1); if (gequal0(a0) || gequal1(a0)) a0 = NULL; else f = gdiv(ser_unscale(f, a0), a0); fc = ginv(f); V = cgetg(lM, t_VEC); for (i = 1; i < lM; i++) { pari_sp av = avma; GEN LISer = RgV_to_ser_full(gel(M,i)), f; if (a0) LISer = gdiv(ser_unscale(LISer, a0), a0); f = gmul(LISer, fc); if (a0) f = ser_unscale(f, ginv(a0)); f = sertocol(f); setlg(f, n+2); gel(V,i) = gerepileupto(av,f); } B = cgetg(lF, t_MAT); for (j = 1; j < lF; j++) { pari_sp av = avma; GEN S = gen_0, coe; F = gel(vF, j); /* t_MF_DIV */ coe = gdiv(gmael(F,2,3), gmael(F,2,4)); for (i = 1; i < lM; i++) { GEN co = gel(coe, i); if (!gequal0(co)) S = gadd(S, gmul(co, gel(V, i))); } gel(B,j) = gerepileupto(av, S); } return B; } static GEN mfheckemat_mfcoefs(GEN mf, GEN B, GEN DATA) { GEN Mindex = MF_get_Mindex(mf), Minv = MF_get_Minv(mf); long j, l = lg(B), sb = mfsturm_mf(mf)-1; GEN b = MF_get_basis(mf), Q = cgetg(l, t_VEC); for (j = 1; j < l; j++) { GEN v = hecke_i(sb, 1, gel(B,j), gel(b,j), DATA); /* Tn b[j] */ settyp(v,t_COL); gel(Q,j) = vecpermute(v, Mindex); } return Minv_RgM_mul(Minv,Q); } /* T_p^2, p prime, 1/2-integral weight; B = mfcoefs(mf,sb*p^2,1) or (mf,sb,p^2) * if p|N */ static GEN mfheckemat_mfcoefs_p2(GEN mf, long p, GEN B) { pari_sp av = avma; GEN DATA = heckef2_data(MF_get_N(mf), p*p); return gerepileupto(av, mfheckemat_mfcoefs(mf, B, DATA)); } /* convert Mindex from row-index to mfcoef indexation: a(n) is stored in * mfcoefs()[n+1], so subtract 1 from all indices */ static GEN Mindex_as_coef(GEN mf) { GEN v, Mindex = MF_get_Mindex(mf); long i, l = lg(Mindex); v = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) v[i] = Mindex[i]-1; return v; } /* T_p, p prime; B = mfcoefs(mf,sb*p,1) or (mf,sb,p) if p|N; integral weight */ static GEN mfheckemat_mfcoefs_p(GEN mf, long p, GEN B) { pari_sp av = avma; GEN vm, Q, C, Minv = MF_get_Minv(mf); long lm, k, i, j, l = lg(B), N = MF_get_N(mf); if (N % p == 0) return Minv_RgM_mul(Minv, rowpermute(B, MF_get_Mindex(mf))); k = MF_get_k(mf); C = gmul(mfchareval_i(MF_get_CHI(mf), p), powuu(p, k-1)); vm = Mindex_as_coef(mf); lm = lg(vm); Q = cgetg(l, t_MAT); for (j = 1; j < l; j++) gel(Q,j) = cgetg(lm, t_COL); for (i = 1; i < lm; i++) { long m = vm[i], mp = m*p; GEN Cm = (m % p) == 0? C : NULL; for (j = 1; j < l; j++) { GEN S = gel(B,j), s = gel(S, mp + 1); if (Cm) s = gadd(s, gmul(C, gel(S, m/p + 1))); gcoeff(Q, i, j) = s; } } return gerepileupto(av, Minv_RgM_mul(Minv,Q)); } /* Matrix of T(p), p prime, dim(mf) > 0 and integral weight */ static GEN mfheckemat_p(GEN mf, long p) { pari_sp av = avma; long N = MF_get_N(mf), sb = mfsturm_mf(mf)-1; GEN B = (N % p)? mfcoefs_mf(mf, sb * p, 1): mfcoefs_mf(mf, sb, p); return gerepileupto(av, mfheckemat_mfcoefs(mf, B, hecke_data(N,p))); } /* mf_NEW != (0), weight > 1, p prime. Use * T(p) T(j) = T(j*p) + p^{k-1} \chi(p) 1_{p | j, p \nmid N} T(j/p) */ static GEN mfnewmathecke_p(GEN mf, long p) { pari_sp av = avma; GEN tf, vj = MFnew_get_vj(mf), CHI = MF_get_CHI(mf); GEN Mindex = MF_get_Mindex(mf), Minv = MF_get_Minv(mf); long N = MF_get_N(mf), k = MF_get_k(mf); long i, j, lvj = lg(vj), lim = vj[lvj-1] * p; GEN M, perm, V, need = zero_zv(lim); GEN C = (N % p)? gmul(mfchareval_i(CHI,p), powuu(p,k-1)): NULL; tf = mftraceform_new(N, k, CHI); for (i = 1; i < lvj; i++) { j = vj[i]; need[j*p] = 1; if (N % p && j % p == 0) need[j/p] = 1; } perm = zero_zv(lim); V = cgetg(lim+1, t_VEC); for (i = j = 1; i <= lim; i++) if (need[i]) { gel(V,j) = mfhecke_i(i, N, tf); perm[i] = j; j++; } setlg(V, j); V = bhnmat_extend_nocache(NULL, N, mfsturm_mf(mf)-1, 1, V); V = rowpermute(V, Mindex); /* V[perm[i]] = coeffs(T_i newtrace) */ M = cgetg(lvj, t_MAT); for (i = 1; i < lvj; i++) { GEN t; j = vj[i]; t = gel(V, perm[j*p]); if (C && j % p == 0) t = RgC_add(t, RgC_Rg_mul(gel(V, perm[j/p]),C)); gel(M,i) = t; } return gerepileupto(av, Minv_RgM_mul(Minv, M)); } GEN mfheckemat(GEN mf, GEN vn) { pari_sp av = avma; long lv, lvP, i, N, dim, nk, dk, p, sb, flint = (typ(vn)==t_INT); GEN CHI, res, vT, FA, B, vP; mf = checkMF(mf); if (typ(vn) != t_VECSMALL) vn = gtovecsmall(vn); N = MF_get_N(mf); CHI = MF_get_CHI(mf); Qtoss(MF_get_gk(mf), &nk, &dk); dim = MF_get_dim(mf); lv = lg(vn); res = cgetg(lv, t_VEC); FA = cgetg(lv, t_VEC); vP = cgetg(lv, t_VEC); vT = const_vec(vecsmall_max(vn), NULL); for (i = 1; i < lv; i++) { ulong n = (ulong)labs(vn[i]); GEN fa; if (!n) pari_err_TYPE("mfheckemat", vn); if (dk == 1 || uissquareall(n, &n)) fa = myfactoru(n); else { n = 0; fa = myfactoru(1); } /* dummy: T_{vn[i]} = 0 */ vn[i] = n; gel(FA,i) = fa; gel(vP,i) = gel(fa,1); } vP = shallowconcat1(vP); vecsmall_sort(vP); vP = vecsmall_uniq_sorted(vP); /* all primes occurring in vn */ lvP = lg(vP); if (lvP == 1) goto END; p = vP[lvP-1]; sb = mfsturm_mf(mf)-1; if (dk == 1 && nk != 1 && MF_get_space(mf) == mf_NEW) B = NULL; /* special purpose mfnewmathecke_p is faster */ else if (lvP == 2 && N % p == 0) B = mfcoefs_mf(mf, sb, dk==2? p*p: p); /* single prime | N, can optimize */ else B = mfcoefs_mf(mf, sb * (dk==2? p*p: p), 1); /* general initialization */ for (i = 1; i < lvP; i++) { long j, l, q, e = 1; GEN C, Tp, u1, u0; p = vP[i]; for (j = 1; j < lv; j++) e = maxss(e, z_lval(vn[j], p)); if (!B) Tp = mfnewmathecke_p(mf, p); else if (dk == 2) Tp = mfheckemat_mfcoefs_p2(mf,p, (lvP==2||N%p)? B: matdeflate(sb,p*p,B)); else Tp = mfheckemat_mfcoefs_p(mf, p, (lvP==2||N%p)? B: matdeflate(sb,p,B)); gel(vT, p) = Tp; if (e == 1) continue; u0 = gen_1; if (dk == 2) { C = N % p? gmul(mfchareval_i(CHI,p*p), powuu(p, nk-2)): NULL; if (e == 2) u0 = sstoQ(p+1,p); /* special case T_{p^4} */ } else C = N % p? gmul(mfchareval_i(CHI,p), powuu(p, nk-1)): NULL; for (u1=Tp, q=p, l=2; l <= e; l++) { /* u0 = T_{p^{l-2}}, u1 = T_{p^{l-1}} for l > 2 */ GEN v = gmul(Tp, u1); if (C) v = gsub(v, gmul(C, u0)); /* q = p^l, vT[q] = T_q for k integer else T_{q^2} */ q *= p; u0 = u1; gel(vT, q) = u1 = v; } } END: /* vT[p^e] = T_{p^e} for all p^e occurring below */ for (i = 1; i < lv; i++) { long n = vn[i], j, lP; GEN fa, P, E, M; if (n == 0) { gel(res,i) = zeromat(dim,dim); continue; } if (n == 1) { gel(res,i) = matid(dim); continue; } fa = gel(FA,i); P = gel(fa,1); lP = lg(P); E = gel(fa,2); M = gel(vT, upowuu(P[1], E[1])); for (j = 2; j < lP; j++) M = RgM_mul(M, gel(vT, upowuu(P[j], E[j]))); gel(res,i) = M; } if (flint) res = gel(res,1); return gerepilecopy(av, res); } /* f = \sum_i v[i] T_listj[i] (Trace Form) attached to v; replace by f/a_1(f) */ static GEN mf_normalize(GEN mf, GEN v) { GEN c, dc = NULL, M = MF_get_M(mf), Mindex = MF_get_Mindex(mf); v = Q_primpart(v); c = RgMrow_RgC_mul(M, v, 2); /* a_1(f) */ if (gequal1(c)) return v; if (typ(c) == t_POL) c = gmodulo(c, mfcharpol(MF_get_CHI(mf))); if (typ(c) == t_POLMOD && varn(gel(c,1)) == 1 && degpol(gel(c,1)) >= 40 && Mindex[1] == 2 && mfcharorder(MF_get_CHI(mf)) <= 2) { /* normalize using expansion at infinity (small coefficients) */ GEN w, P = gel(c,1), a1 = gel(c,2); long i, l = lg(Mindex); w = cgetg(l, t_COL); gel(w,1) = gen_1; for (i = 2; i < l; i++) { c = liftpol_shallow(RgMrow_RgC_mul(M, v, Mindex[i])); gel(w,i) = QXQ_div_ratlift(c, a1, P); } /* w = expansion at oo of normalized form */ v = Minv_RgC_mul(MF_get_Minv(mf), Q_remove_denom(w, &dc)); v = gmodulo(v, P); /* back to mfbasis coefficients */ } else { c = ginv(c); if (typ(c) == t_POLMOD) c = Q_remove_denom(c, &dc); v = RgC_Rg_mul(v, c); } if (dc) v = RgC_Rg_div(v, dc); return v; } static void pol_red(GEN NF, GEN *pP, GEN *pa, long flag) { GEN dP, a, P = *pP; long d = degpol(P); *pa = a = pol_x(varn(P)); if (d > 30) return; dP = RgX_disc(P); if (typ(dP) != t_INT) { dP = gnorm(dP); if (typ(dP) != t_INT) pari_err_BUG("mfnewsplit"); } if (d == 2 || expi(dP) < 62) { if (expi(dP) < 31) P = NF? rnfpolredabs(NF, P,flag): polredabs0(P,flag); else P = NF? rnfpolredbest(NF,P,flag): polredbest(P,flag); if (flag) { a = gel(P,2); if (typ(a) == t_POLMOD) a = gel(a,2); P = gel(P,1); } } *pP = P; *pa = a; } /* Diagonalize and normalize. See mfsplit for meaning of flag. */ static GEN mfspclean(GEN mf, GEN mf0, GEN NF, long ord, GEN simplesp, long flag) { const long vz = 1; long i, l = lg(simplesp), dim = MF_get_dim(mf); GEN res = cgetg(l, t_MAT), pols = cgetg(l, t_VEC); GEN zeros = (mf == mf0)? NULL: zerocol(dim - MF_get_dim(mf0)); for (i = 1; i < l; i++) { GEN ATP = gel(simplesp, i), A = gel(ATP,1), P = gel(ATP,3); long d = degpol(P); GEN a, v = (flag && d > flag)? NULL: gel(A,1); if (d == 1) P = pol_x(vz); else { pol_red(NF, &P, &a, !!v); if (v) { /* Mod(a,P) root of charpoly(T), K*gpowers(a) = eigenvector of T */ GEN K, den, M = cgetg(d+1, t_MAT), T = gel(ATP,2); long j; T = shallowtrans(T); gel(M,1) = vec_ei(d,1); /* basis of cyclic vectors */ for (j = 2; j <= d; j++) gel(M,j) = RgM_RgC_mul(T, gel(M,j-1)); M = Q_primpart(M); K = NF? ZabM_inv(liftpol_shallow(M), nf_get_pol(NF), ord, &den) : ZM_inv(M,&den); K = shallowtrans(K); v = gequalX(a)? pol_x_powers(d, vz): RgXQ_powers(a, d-1, P); v = gmodulo(RgM_RgC_mul(A, RgM_RgC_mul(K,v)), P); } } if (v) { v = mf_normalize(mf0, v); if (zeros) v = shallowconcat(zeros,v); gel(res,i) = v; if (flag) setlg(res,i+1); } else gel(res,i) = zerocol(dim); gel(pols,i) = P; } return mkvec2(res, pols); } /* return v = v_{X-r}(P), and set Z = P / (X-r)^v */ static long RgX_valrem_root(GEN P, GEN r, GEN *Z) { long v; for (v = 0; degpol(P); v++) { GEN t, Q = RgX_div_by_X_x(P, r, &t); if (!gequal0(t)) break; P = Q; } *Z = P; return v; } static GEN mynffactor(GEN NF, GEN P, long dimlim) { long i, l, v; GEN R, E; if (dimlim != 1) { R = NF? nffactor(NF, P): QX_factor(P); if (!dimlim) return R; E = gel(R,2); R = gel(R,1); l = lg(R); for (i = 1; i < l; i++) if (degpol(gel(R,i)) > dimlim) break; if (i == 1) return NULL; setlg(E,i); setlg(R,i); return mkmat2(R, E); } /* dimlim = 1 */ R = nfroots(NF, P); l = lg(R); if (l == 1) return NULL; v = varn(P); settyp(R, t_COL); if (degpol(P) == l-1) E = const_col(l-1, gen_1); else { E = cgetg(l, t_COL); for (i = 1; i < l; i++) gel(E,i) = utoi(RgX_valrem_root(P, gel(R,i), &P)); } R = deg1_from_roots(R, v); return mkmat2(R, E); } /* Let K be a number field attached to NF (Q if NF = NULL). A K-vector * space of dimension d > 0 is given by a t_MAT A (n x d, full column rank) * giving a K-basis, X a section (d x n: left pseudo-inverse of A). Return a * pair (T, fa), where T is an element of the Hecke algebra (a sum of Tp taken * from vector vTp) acting on A (a d x d t_MAT) and fa is the factorization of * its characteristic polynomial, limited to factors of degree <= dimlim if * dimlim != 0 (return NULL if there are no factors of degree <= dimlim) */ static GEN findbestsplit(GEN NF, GEN vTp, GEN A, GEN X, long dimlim, long vz) { GEN T = NULL, Tkeep = NULL, fakeep = NULL; long lmax = 0, i, lT = lg(vTp); for (i = 1; i < lT; i++) { GEN D, P, E, fa, TpA = gel(vTp,i); long l; if (typ(TpA) == t_INT) break; if (lg(TpA) > lg(A)) TpA = RgM_mul(X, RgM_mul(TpA, A)); /* Tp | A */ T = T ? RgM_add(T, TpA) : TpA; if (!NF) { P = QM_charpoly_ZX(T); setvarn(P, vz); } else { P = charpoly(Q_remove_denom(T, &D), vz); if (D) P = gdiv(RgX_unscale(P, D), powiu(D, degpol(P))); } fa = mynffactor(NF, P, dimlim); if (!fa) return NULL; E = gel(fa, 2); /* characteristic polynomial is separable ? */ if (isint1(vecmax(E))) { Tkeep = T; fakeep = fa; break; } l = lg(E); /* characteristic polynomial has more factors than before ? */ if (l > lmax) { lmax = l; Tkeep = T; fakeep = fa; } } return mkvec2(Tkeep, fakeep); } static GEN nfcontent(GEN nf, GEN v) { long i, l = lg(v); GEN c = gel(v,1); for (i = 2; i < l; i++) c = idealadd(nf, c, gel(v,i)); if (typ(c) == t_MAT && gequal1(gcoeff(c,1,1))) c = gen_1; return c; } static GEN nf_primpart(GEN nf, GEN B) { switch(typ(B)) { case t_COL: { GEN A = matalgtobasis(nf, B), c = nfcontent(nf, A); if (typ(c) == t_INT) return B; c = idealred_elt(nf,c); A = Q_primpart( nfC_nf_mul(nf, A, Q_primpart(nfinv(nf,c))) ); A = liftpol_shallow( matbasistoalg(nf, A) ); if (gexpo(A) > gexpo(B)) A = B; return A; } case t_MAT: { long i, l; GEN A = cgetg_copy(B, &l); for (i = 1; i < l; i++) gel(A,i) = nf_primpart(nf, gel(B,i)); return A; } default: pari_err_TYPE("nf_primpart", B); return NULL; /*LCOV_EXCL_LINE*/ } } /* rotate entries of v to accomodate new entry 'x' (push out oldest entry) */ static void vecpush(GEN v, GEN x) { long i; for (i = lg(v)-1; i > 1; i--) gel(v,i) = gel(v,i-1); gel(v,1) = x; } /* sort t_VEC of vector spaces by increasing dimension */ static GEN sort_by_dim(GEN v) { long i, l = lg(v); GEN D = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) D[i] = lg(gmael(v,i,2)); return vecpermute(v , vecsmall_indexsort(D)); } static GEN split_starting_space(GEN mf) { long d = MF_get_dim(mf), d2; GEN id = matid(d); switch(MF_get_space(mf)) { case mf_NEW: case mf_CUSP: return mkvec2(id, id); } d2 = lg(MF_get_S(mf))-1; return mkvec2(vecslice(id, d-d2+1,d), shallowconcat(zeromat(d2,d-d2),matid(d2))); } /* If dimlim > 0, keep only the dimension <= dimlim eigenspaces. * See mfsplit for the meaning of flag. */ static GEN split_ii(GEN mf, long dimlim, long flag, long *pnewd) { forprime_t iter; GEN CHI = MF_get_CHI(mf), empty = cgetg(1, t_VEC), mf0 = mf; GEN NF, POLCYC, todosp, Tpbigvec, simplesp; long N = MF_get_N(mf), k = MF_get_k(mf); long ord, FC, NEWT, dimsimple = 0, newd = -1; const long NBH = 5, vz = 1; ulong p; switch(MF_get_space(mf)) { case mf_NEW: break; case mf_CUSP: case mf_FULL: if (k > 1) { mf0 = mfinittonew(mf); break; } newd = lg(MF_get_S(mf))-1 - mfolddim(N, k, CHI); break; default: pari_err_TYPE("mfsplit [space does not contain newspace]", mf); return NULL; /*LCOV_EXCL_LINE*/ } if (newd < 0) newd = mf0? MF_get_dim(mf0): 0; *pnewd = newd; if (!newd) return mkvec2(cgetg(1, t_MAT), empty); NEWT = (k > 1 && MF_get_space(mf0) == mf_NEW); todosp = mkvec( split_starting_space(mf0) ); simplesp = empty; FC = mfcharconductor(CHI); ord = mfcharorder_canon(CHI); if (ord == 1) NF = POLCYC = NULL; else { POLCYC = mfcharpol(CHI); NF = nfinit(POLCYC,DEFAULTPREC); } Tpbigvec = zerovec(NBH); u_forprime_init(&iter, 2, ULONG_MAX); while (dimsimple < newd && (p = u_forprime_next(&iter))) { GEN nextsp; long ind; if (N % (p*p) == 0 && N/p % FC == 0) continue; /* T_p = 0 in this case */ vecpush(Tpbigvec, NEWT? mfnewmathecke_p(mf0,p): mfheckemat_p(mf0,p)); nextsp = empty; for (ind = 1; ind < lg(todosp); ind++) { GEN tmp = gel(todosp, ind), fa, P, E, D, Tp, DTp; GEN A = gel(tmp, 1); GEN X = gel(tmp, 2); long lP, i; tmp = findbestsplit(NF, Tpbigvec, A, X, dimlim, vz); if (!tmp) continue; /* nothing there */ Tp = gel(tmp, 1); fa = gel(tmp, 2); P = gel(fa, 1); E = gel(fa, 2); lP = lg(P); /* lP > 1 */ if (DEBUGLEVEL) err_printf("Exponents = %Ps\n", E); if (lP == 2) { GEN P1 = gel(P,1); long e1 = itos(gel(E,1)), d1 = degpol(P1); if (e1 * d1 == lg(Tp)-1) { if (e1 > 1) nextsp = vec_append(nextsp, mkvec2(A,X)); else { /* simple module */ simplesp = vec_append(simplesp, mkvec3(A,Tp,P1)); dimsimple += d1; } continue; } } /* Found splitting */ DTp = Q_remove_denom(Tp, &D); for (i = 1; i < lP; i++) { GEN Ai, Xi, dXi, AAi, v, y, Pi = gel(P,i); Ai = RgX_RgM_eval(D? RgX_rescale(Pi,D): Pi, DTp); Ai = QabM_ker(Ai, POLCYC, ord); if (NF) Ai = nf_primpart(NF, Ai); AAi = RgM_mul(A, Ai); /* gives section, works on nonsquare matrices */ Xi = QabM_pseudoinv(Ai, POLCYC, ord, &v, &dXi); Xi = RgM_Rg_div(Xi, dXi); y = gel(v,1); if (isint1(gel(E,i))) { GEN Tpi = RgM_mul(Xi, RgM_mul(rowpermute(Tp,y), Ai)); simplesp = vec_append(simplesp, mkvec3(AAi, Tpi, Pi)); dimsimple += degpol(Pi); } else { Xi = RgM_mul(Xi, rowpermute(X,y)); nextsp = vec_append(nextsp, mkvec2(AAi, Xi)); } } } todosp = nextsp; if (lg(todosp) == 1) break; } if (DEBUGLEVEL) err_printf("end split, need to clean\n"); return mfspclean(mf, mf0, NF, ord, sort_by_dim(simplesp), flag); } static GEN dim_filter(GEN v, long dim) { GEN P = gel(v,2); long j, l = lg(P); for (j = 1; j < l; j++) if (degpol(gel(P,j)) > dim) { v = mkvec2(vecslice(gel(v,1),1,j-1), vecslice(P,1,j-1)); break; } return v; } static long dim_sum(GEN v) { GEN P = gel(v,2); long j, l = lg(P), d = 0; for (j = 1; j < l; j++) d += degpol(gel(P,j)); return d; } static GEN split_i(GEN mf, long dimlim, long flag) { long junk; return split_ii(mf, dimlim, flag, &junk); } /* mf is either already split or output by mfinit. Splitting is done only for * newspace except in weight 1. If flag = 0 (default) split completely. * If flag = d > 0, only give the Galois polynomials in degree > d * Flag is ignored if dimlim = 1. */ GEN mfsplit(GEN mf0, long dimlim, long flag) { pari_sp av = avma; GEN v, mf = checkMF_i(mf0); if (!mf) pari_err_TYPE("mfsplit", mf0); if ((v = obj_check(mf, MF_SPLIT))) { if (dimlim) v = dim_filter(v, dimlim); } else if (dimlim && (v = obj_check(mf, MF_SPLITN))) { v = (itos(gel(v,1)) >= dimlim)? dim_filter(gel(v,2), dimlim): NULL; } if (!v) { long newd; v = split_ii(mf, dimlim, flag, &newd); if (lg(v) == 1) obj_insert(mf, MF_SPLITN, mkvec2(utoi(dimlim), v)); else if (!flag) { if (dim_sum(v) == newd) obj_insert(mf, MF_SPLIT,v); else obj_insert(mf, MF_SPLITN, mkvec2(utoi(dimlim), v)); } } return gerepilecopy(av, v); } static GEN split(GEN mf) { return split_i(mf,0,0); } GEN MF_get_newforms(GEN mf) { return gel(obj_checkbuild(mf,MF_SPLIT,&split),1); } GEN MF_get_fields(GEN mf) { return gel(obj_checkbuild(mf,MF_SPLIT,&split),2); } /*************************************************************************/ /* Modular forms of Weight 1 */ /*************************************************************************/ /* S_1(G_0(N)), small N. Return 1 if definitely empty; return 0 if maybe * non-empty */ static int wt1empty(long N) { if (N <= 100) switch (N) { /* non-empty [32/100] */ case 23: case 31: case 39: case 44: case 46: case 47: case 52: case 55: case 56: case 57: case 59: case 62: case 63: case 68: case 69: case 71: case 72: case 76: case 77: case 78: case 79: case 80: case 83: case 84: case 87: case 88: case 92: case 93: case 94: case 95: case 99: case 100: return 0; default: return 1; } if (N <= 600) switch(N) { /* empty [111/500] */ case 101: case 102: case 105: case 106: case 109: case 113: case 121: case 122: case 123: case 125: case 130: case 134: case 137: case 146: case 149: case 150: case 153: case 157: case 162: case 163: case 169: case 170: case 173: case 178: case 181: case 182: case 185: case 187: case 193: case 194: case 197: case 202: case 205: case 210: case 218: case 221: case 226: case 233: case 241: case 242: case 245: case 246: case 250: case 257: case 265: case 267: case 269: case 274: case 277: case 281: case 289: case 293: case 298: case 305: case 306: case 313: case 314: case 317: case 326: case 337: case 338: case 346: case 349: case 353: case 361: case 362: case 365: case 369: case 370: case 373: case 374: case 377: case 386: case 389: case 394: case 397: case 401: case 409: case 410: case 421: case 425: case 427: case 433: case 442: case 449: case 457: case 461: case 466: case 481: case 482: case 485: case 490: case 493: case 509: case 514: case 521: case 530: case 533: case 534: case 538: case 541: case 545: case 554: case 557: case 562: case 565: case 569: case 577: case 578: case 586: case 593: return 1; default: return 0; } return 0; } static GEN initwt1trace(GEN mf) { GEN S = MF_get_S(mf), v, H; long l, i; if (lg(S) == 1) return mftrivial(); H = mfheckemat(mf, Mindex_as_coef(mf)); l = lg(H); v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = gtrace(gel(H,i)); v = Minv_RgC_mul(MF_get_Minv(mf), v); return mflineardiv_linear(S, v, 1); } static GEN initwt1newtrace(GEN mf) { GEN v, D, S, Mindex, CHI = MF_get_CHI(mf); long FC, lD, i, sb, N1, N2, lM, N = MF_get_N(mf); CHI = mfchartoprimitive(CHI, &FC); if (N % FC || mfcharparity(CHI) == 1) return mftrivial(); D = mydivisorsu(N/FC); lD = lg(D); S = MF_get_S(mf); if (lg(S) == 1) return mftrivial(); N2 = newd_params2(N); N1 = N / N2; Mindex = MF_get_Mindex(mf); lM = lg(Mindex); sb = Mindex[lM-1]; v = zerovec(sb+1); for (i = 1; i < lD; i++) { long M = FC*D[i], j; GEN tf = initwt1trace(M == N? mf: mfinit_Nkchi(M, 1, CHI, mf_CUSP, 0)); GEN listd, w; if (mf_get_type(tf) == t_MF_CONST) continue; w = mfcoefs_i(tf, sb, 1); if (M == N) { v = gadd(v, w); continue; } listd = mydivisorsu(u_ppo(ugcd(N/M, N1), FC)); for (j = 1; j < lg(listd); j++) { long d = listd[j], d2 = d*d; /* coprime to FC */ GEN dk = mfchareval_i(CHI, d); long NMd = N/(M*d), m; for (m = 1; m <= sb/d2; m++) { long be = mubeta2(NMd, m); if (be) { GEN c = gmul(dk, gmulsg(be, gel(w, m+1))); long n = m*d2; gel(v, n+1) = gadd(gel(v, n+1), c); } } } } if (gequal0(gel(v,2))) return mftrivial(); v = vecpermute(v,Mindex); v = Minv_RgC_mul(MF_get_Minv(mf), v); return mflineardiv_linear(S, v, 1); } /* Matrix of T(p), p \nmid N */ static GEN Tpmat(long p, long lim, GEN CHI) { GEN M = zeromatcopy(lim, p*lim), chip = mfchareval_i(CHI, p); /* != 0 */ long i, j, pi, pj; gcoeff(M, 1, 1) = gaddsg(1, chip); for (i = 1, pi = p; i < lim; i++, pi += p) gcoeff(M, i+1, pi+1) = gen_1; for (j = 1, pj = p; pj < lim; j++, pj += p) gcoeff(M, pj+1, j+1) = chip; return M; } /* assume !wt1empty(N), in particular N>25 */ /* Returns [[lim,p], mf (weight 2), p*lim x dim matrix] */ static GEN mfwt1_pre(long N) { GEN M, mf = mfinit_Nkchi(N, 2, mfchartrivial(), mf_CUSP, 0); /*not empty for N>25*/ long p, lim; if (uisprime(N)) { p = 2; /*N>25 is not 2 */ lim = ceilA1(N, 3); } else { forprime_t S; u_forprime_init(&S, 2, N); while ((p = u_forprime_next(&S))) if (N % p) break; lim = mfsturm_mf(mf) + 1; } /* p = smalllest prime not dividing N */ M = bhnmat_extend_nocache(MF_get_M(mf), N, p*lim-1, 1, MF_get_S(mf)); return mkvec3(mkvecsmall2(lim, p), mf, M); } /* lg(A) > 1, E a t_POL */ static GEN mfmatsermul(GEN A, GEN E) { long j, l = lg(A), r = nbrows(A); GEN M = cgetg(l, t_MAT); E = RgXn_red_shallow(E, r+1); for (j = 1; j < l; j++) { GEN c = RgV_to_RgX(gel(A,j), 0); gel(M, j) = RgX_to_RgC(RgXn_mul(c, E, r+1), r); } return M; } /* lg(Ap) > 1, Ep an Flxn */ static GEN mfmatsermul_Fl(GEN Ap, GEN Ep, ulong p) { long j, l = lg(Ap), r = nbrows(Ap); GEN M = cgetg(l, t_MAT); for (j = 1; j < l; j++) { GEN c = Flv_to_Flx(gel(Ap,j), 0); gel(M,j) = Flx_to_Flv(Flxn_mul(c, Ep, r+1, p), r); } return M; } /* CHI mod F | N, return mfchar of modulus N. * FIXME: wasteful, G should be precomputed */ static GEN mfcharinduce(GEN CHI, long N) { GEN G, chi; if (mfcharmodulus(CHI) == N) return CHI; G = znstar0(utoipos(N), 1); chi = zncharinduce(gel(CHI,1), gel(CHI,2), G); CHI = leafcopy(CHI); gel(CHI,1) = G; gel(CHI,2) = chi; return CHI; } static GEN gmfcharno(GEN CHI) { GEN G = gel(CHI,1), chi = gel(CHI,2); return mkintmod(znconreyexp(G, chi), znstar_get_N(G)); } static long mfcharno(GEN CHI) { GEN n = znconreyexp(gel(CHI,1), gel(CHI,2)); return itou(n); } /* return k such that minimal mfcharacter in Galois orbit of CHI is CHI^k */ static long mfconreyminimize(GEN CHI) { GEN G = gel(CHI,1), cyc, chi; cyc = ZV_to_zv(znstar_get_cyc(G)); chi = ZV_to_zv(znconreychar(G, gel(CHI,2))); return zv_cyc_minimize(cyc, chi, coprimes_zv(mfcharorder(CHI))); } /* find scalar c such that first non-0 entry of c*v is 1; return c*v * (set c = NULL for 1) */ static GEN RgV_normalize(GEN v, GEN *pc) { long i, l = lg(v); *pc = NULL; for (i = 1; i < l; i++) { GEN c = gel(v,i); if (!gequal0(c)) { if (gequal1(c)) { *pc = gen_1; return v; } *pc = ginv(c); return RgV_Rg_mul(v, *pc); } } return v; } /* ordchi != 2 mod 4 */ static GEN mftreatdihedral(GEN DIH, GEN POLCYC, long ordchi, long biglim, GEN *pS) { GEN M, Minv, C; long l, i; l = lg(DIH); if (l == 1) return NULL; if (!pS) return DIH; C = cgetg(l, t_VEC); M = cgetg(l, t_MAT); for (i = 1; i < l; i++) { GEN c, v = mfcoefs_i(gel(DIH,i), biglim, 1); gel(M,i) = RgV_normalize(v, &c); gel(C,i) = Rg_col_ei(c, l-1, i); } Minv = gel(mfclean(M,POLCYC,ordchi,0),2); M = RgM_Minv_mul(M, Minv); C = RgM_Minv_mul(C, Minv); *pS = vecmflinear(DIH, C); return M; } static GEN mfstabiter(GEN M, GEN A2, GEN E1inv, long lim, GEN P, long ordchi) { GEN A, VC, con; E1inv = primitive_part(E1inv, &con); VC = con? ginv(con): gen_1; A = mfmatsermul(A2, E1inv); while(1) { GEN R = shallowconcat(RgM_mul(M,A), rowslice(A,1,lim)); GEN B = QabM_ker(R, P, ordchi); long lA = lg(A), lB = lg(B); if (lB == 1) return NULL; if (lB == lA) return mkvec2(A, VC); B = rowslice(B, 1, lA-1); if (ordchi != 1) B = gmodulo(B, P); A = Q_primitive_part(RgM_mul(A,B), &con); VC = gmul(VC,B); /* first VC is a scalar, then a RgM */ if (con) VC = RgM_Rg_div(VC, con); } } static long mfstabitermodp(GEN Mp, GEN Ap, long p, long lim) { GEN VC = NULL; while (1) { GEN Rp = shallowconcat(Flm_mul(Mp,Ap,p), rowslice(Ap,1,lim)); GEN Bp = Flm_ker(Rp, p); long lA = lg(Ap), lB = lg(Bp); if (lB == 1) return 0; if (lB == lA) return lA-1; Bp = rowslice(Bp, 1, lA-1); Ap = Flm_mul(Ap, Bp, p); VC = VC? Flm_mul(VC, Bp, p): Bp; } } static GEN mfintereis(GEN A, GEN M2, GEN y, GEN den, GEN E2, GEN P, long ordchi) { GEN z, M1 = mfmatsermul(A,E2), M1den = is_pm1(den)? M1: RgM_Rg_mul(M1,den); M2 = RgM_mul(M2, rowpermute(M1, y)); z = QabM_ker(RgM_sub(M2,M1den), P, ordchi); if (ordchi != 1) z = gmodulo(z, P); return mkvec2(RgM_mul(A,z), z); } static GEN mfintereismodp(GEN A, GEN M2, GEN E2, ulong p) { GEN M1 = mfmatsermul_Fl(A, E2, p), z; long j, lx = lg(A); z = Flm_ker(shallowconcat(M1, M2), p); for (j = lg(z) - 1; j; j--) setlg(z[j], lx); return mkvec2(Flm_mul(A,z,p), z); } static GEN mfcharinv_i(GEN CHI) { GEN G = gel(CHI,1); CHI = leafcopy(CHI); gel(CHI,2) = zncharconj(G, gel(CHI,2)); return CHI; } /* upper bound dim S_1(Gamma_0(N),chi) performing the linear algebra mod p */ static long mfwt1dimmodp(GEN A, GEN ES, GEN M, long ordchi, long dih, long lim) { GEN Ap, ApF, ES1p, VC; ulong p, r = QabM_init(ordchi, &p); ApF = Ap = QabM_to_Flm(A, r, p); VC = NULL; ES1p = QabX_to_Flx(gel(ES,1), r, p); if (lg(ES) >= 3) { GEN M2 = mfmatsermul_Fl(ApF, ES1p, p); pari_sp av = avma; long i; for (i = 2; i < lg(ES); i++) { GEN ESip = QabX_to_Flx(gel(ES,i), r, p); GEN C, ApC = mfintereismodp(Ap, M2, ESip, p); Ap = gel(ApC,1); if (lg(Ap)-1 == dih) return dih; C = gel(ApC,2); VC = VC? Flm_mul(VC, C, p): C; gerepileall(av, 2, &Ap,&VC); } } /* intersection of Eisenstein series quotients non empty: use Schaeffer */ Ap = mfmatsermul_Fl(Ap, Flxn_inv(ES1p,nbrows(Ap),p), p); return mfstabitermodp(QabM_to_Flm(M,r,p), Ap, p, lim); } /* Compute the full S_1(\G_0(N),\chi). If pS is NULL, only the dimension * dim, in the form of a vector having dim components. Otherwise output * a basis: ptvf contains a pointer to the vector of forms, and the * program returns the corresponding matrix of Fourier expansions. * ptdimdih gives the dimension of the subspace generated by dihedral forms; * TMP is from mfwt1_pre or NULL. */ static GEN mfwt1basis(long N, GEN CHI, GEN TMP, GEN *pS, long *ptdimdih) { GEN ES, mf, A, M, Tp, tmp1, tmp2, den; GEN S, ESA, VC, C, POLCYC, ES1, ES1INV, DIH, a0, a0i; long plim, lim, biglim, i, p, dA, dimp, ordchi, dih; if (ptdimdih) *ptdimdih = 0; if (pS) *pS = NULL; if (wt1empty(N) || mfcharparity(CHI) != -1) return NULL; ordchi = mfcharorder_canon(CHI); if (uisprime(N) && ordchi > 4) return NULL; if (!pS) { dih = mfdihedralcuspdim(N, CHI); DIH = zerovec(dih); } else { DIH = mfdihedralcusp(N, CHI); dih = lg(DIH) - 1; } POLCYC = (ordchi == 1)? NULL: mfcharpol(CHI); if (ptdimdih) *ptdimdih = dih; biglim = mfsturmNk(N, 2); if (N <= 600) switch(N) { long m; case 219: case 273: case 283: case 331: case 333: case 344: case 416: case 438: case 468: case 491: case 504: case 546: case 553: case 563: case 566: case 581: case 592: break; /* one chi with both exotic and dihedral forms */ default: /* only dihedral forms */ if (!dih) return NULL; /* fall through */ case 124: case 133: case 148: case 171: case 201: case 209: case 224: case 229: case 248: case 261: case 266: case 288: case 296: case 301: case 309: case 325: case 342: case 371: case 372: case 380: case 399: case 402: case 403: case 404: case 408: case 418: case 432: case 444: case 448: case 451: case 453: case 458: case 496: case 497: case 513: case 522: case 527: case 532: case 576: case 579: /* no chi with both exotic and dihedral; one chi with exotic forms */ if (dih) return mftreatdihedral(DIH, POLCYC, ordchi, biglim, pS); CHI = mfcharinduce(CHI,N); m = mfcharno(CHI); if (N == 124 && (m != 67 && m != 87)) return NULL; if (N == 133 && (m != 83 && m !=125)) return NULL; if (N == 148 && (m !=105 && m !=117)) return NULL; if (N == 171 && (m != 94 && m !=151)) return NULL; if (N == 201 && (m != 29 && m !=104)) return NULL; if (N == 209 && (m != 87 && m !=197)) return NULL; if (N == 224 && (m != 95 && m !=191)) return NULL; if (N == 229 && (m !=107 && m !=122)) return NULL; if (N == 248 && (m != 87 && m !=191)) return NULL; if (N == 261 && (m != 46 && m !=244)) return NULL; if (N == 266 && (m != 83 && m !=125)) return NULL; if (N == 288 && (m != 31 && m !=223)) return NULL; if (N == 296 && (m !=105 && m !=265)) return NULL; } if (!TMP) TMP = mfwt1_pre(N); tmp1= gel(TMP,1); lim = tmp1[1]; p = tmp1[2]; plim = p*lim; mf = gel(TMP,2); A = gel(TMP,3); /* p*lim x dim matrix */ S = MF_get_S(mf); ESA = mfeisensteinbasis(N, 1, mfcharinv_i(CHI)); ES = RgM_to_RgXV(mfvectomat(ESA, plim+1, 1), 0); ES1 = gel(ES,1); /* does not vanish at oo */ Tp = Tpmat(p, lim, CHI); dimp = mfwt1dimmodp(A, ES, Tp, ordchi, dih, lim); if (!dimp) return NULL; if (dimp == dih) return mftreatdihedral(DIH, POLCYC, ordchi, biglim, pS); VC = gen_1; if (lg(ES) >= 3) { pari_sp btop; long lim2 = (3*lim)/2 + 1; GEN Ash = rowslice(A, 1, lim2), M2 = mfmatsermul(Ash, ES1); GEN v, y, M2M2I, M2I; M2I = QabM_pseudoinv(M2, POLCYC, ordchi, &v, &den); y = gel(v,1); M2M2I = RgM_mul(M2,M2I); btop = avma; for (i = 2; i < lg(ES); i++) { GEN APC = mfintereis(Ash, M2M2I, y, den, gel(ES,i), POLCYC,ordchi); Ash = gel(APC,1); if (lg(Ash) == 1) return NULL; VC = gmul(VC, gel(APC,2)); if (gc_needed(btop, 1)) { if (DEBUGMEM > 1) pari_warn(warnmem,"mfwt1basis i = %ld", i); gerepileall(btop, 2, &Ash, &VC); } } A = RgM_mul(A, vecslice(VC,1, lg(Ash)-1)); } a0 = gel(ES1,2); /* non-zero */ if (gequal1(a0)) a0 = a0i = NULL; else { a0i = ginv(a0); ES1 = RgX_Rg_mul(RgX_unscale(ES1,a0), a0i); } ES1INV = RgXn_inv(ES1, plim-1); if (a0) ES1INV = RgX_Rg_mul(RgX_unscale(ES1INV, a0i), a0i); tmp2 = mfstabiter(Tp, A, ES1INV, lim, POLCYC, ordchi); if (!tmp2) return NULL; A = gel(tmp2,1); dA = lg(A); VC = gmul(VC, gel(tmp2,2)); C = cgetg(dA, t_VEC); M = cgetg(dA, t_MAT); for (i = 1; i < dA; i++) { GEN c, v = gel(A,i); gel(M,i) = RgV_normalize(v, &c); gel(C,i) = RgC_Rg_mul(gel(VC,i), c); } if (pS) { GEN Minv = gel(mfclean(M, POLCYC, ordchi, 0), 2); M = RgM_Minv_mul(M, Minv); C = RgM_Minv_mul(C, Minv); *pS = vecmflineardiv0(S, C, gel(ESA,1)); } return M; } static void MF_set_space(GEN mf, long x) { gmael(mf,1,4) = utoi(x); } static GEN mfwt1_cusptonew(GEN mf) { const long vy = 1; GEN vP, F, S, Snew, vF, v = split(mf); long i, lP, dSnew, ct; F = gel(v,1); vP= gel(v,2); lP = lg(vP); if (lP == 1) { obj_insert(mf, MF_SPLIT, v); return NULL; } MF_set_space(mf, mf_NEW); S = MF_get_S(mf); dSnew = dim_sum(v); Snew = cgetg(dSnew + 1, t_VEC); ct = 0; vF = cgetg(lP, t_MAT); for (i = 1; i < lP; i++) { GEN V, P = gel(vP,i), f = liftpol_shallow(gel(F,i)); long j, d = degpol(P); gel(vF,i) = V = zerocol(dSnew); if (d == 1) { gel(Snew, ct+1) = mflineardiv_linear(S, f, 0); gel(V, ct+1) = gen_1; } else { f = RgXV_to_RgM(f,d); for (j = 1; j <= d; j++) { gel(Snew, ct+j) = mflineardiv_linear(S, row(f,j), 0); gel(V, ct+j) = mkpolmod(pol_xn(j-1,vy), P); } } ct += d; } obj_insert(mf, MF_SPLIT, mkvec2(vF, vP)); gel(mf,3) = Snew; return mf; } static GEN mfwt1init(long N, GEN CHI, GEN TMP, long space, long flraw) { GEN mf, mf1, S, M = mfwt1basis(N, CHI, TMP, &S, NULL); if (!M) return NULL; mf1 = mkvec4(stoi(N), gen_1, CHI, utoi(mf_CUSP)); mf = mkmf(mf1, cgetg(1,t_VEC), S, gen_0, NULL); if (space == mf_NEW) { gel(mf,5) = mfcleanCHI(M,CHI, 0); mf = mfwt1_cusptonew(mf); if (!mf) return NULL; if (!flraw) M = mfcoefs_mf(mf, mfsturmNk(N,1)+1, 1); } gel(mf,5) = flraw? zerovec(3): mfcleanCHI(M, CHI, 0); return mf; } static GEN mfEMPTY(GEN mf1) { GEN Minv = mkMinv(cgetg(1,t_MAT), NULL,NULL,NULL); GEN M = mkvec3(cgetg(1,t_VECSMALL), Minv, cgetg(1,t_MAT)); return mkmf(mf1, cgetg(1,t_VEC), cgetg(1,t_VEC), cgetg(1,t_VEC), M); } static GEN mfEMPTYall(long N, GEN gk, GEN vCHI, long space) { long i, l; GEN v, gN, gs; if (!vCHI) return cgetg(1, t_VEC); gN = utoipos(N); gs = utoi(space); l = lg(vCHI); v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = mfEMPTY(mkvec4(gN,gk,gel(vCHI,i),gs)); return v; } static GEN fmt_dim(GEN CHI, long d, long dih) { return mkvec4(gmfcharorder(CHI), gmfcharno(CHI), utoi(d), stoi(dih)); } /* merge two vector of fmt_dim's for the same vector of characters. If CHI * is not NULL, remove dim-0 spaces and add character from CHI */ static GEN merge_dims(GEN V, GEN W, GEN CHI) { long i, j, id, l = lg(V); GEN A = cgetg(l, t_VEC); if (l == 1) return A; id = CHI? 1: 3; for (i = j = 1; i < l; i++) { GEN v = gel(V,i), w = gel(W,i); long dv = itou(gel(v,id)), dvh = itou(gel(v,id+1)), d; long dw = itou(gel(w,id)), dwh = itou(gel(w,id+1)); d = dv + dw; if (d || CHI) gel(A,j++) = CHI? fmt_dim(gel(CHI,i),d, dvh+dwh) : mkvec2s(d,dvh+dwh); } setlg(A, j); return A; } static GEN mfdim0all(GEN w) { if (w) retconst_vec(lg(w)-1, zerovec(2)); return cgetg(1,t_VEC); } static long mfwt1cuspdim_i(long N, GEN CHI, GEN TMP, long *dih) { pari_sp av = avma; GEN b = mfwt1basis(N, CHI, TMP, NULL, dih); avma = av; return b? lg(b)-1: 0; } static long mfwt1cuspdim(long N, GEN CHI) { return mfwt1cuspdim_i(N, CHI, NULL, NULL); } static GEN mfwt1cuspdimall(long N, GEN vCHI) { GEN z, TMP, w; long i, j, l; if (wt1empty(N)) return mfdim0all(vCHI); w = mfwt1chars(N,vCHI); l = lg(w); if (l == 1) return cgetg(1,t_VEC); z = cgetg(l, t_VEC); TMP = mfwt1_pre(N); for (i = j = 1; i < l; i++) { GEN CHI = gel(w,i); long dih, d = mfwt1cuspdim_i(N, CHI, TMP, &dih); if (vCHI) gel(z,j++) = mkvec2s(d, dih); else if (d) gel(z,j++) = fmt_dim(CHI, d, dih); } setlg(z,j); return z; } /* dimension of S_1(Gamma_1(N)) */ static long mfwt1cuspdimsum(long N) { pari_sp av = avma; GEN v = mfwt1cuspdimall(N, NULL); long i, ct = 0, l = lg(v); for (i = 1; i < l; i++) { GEN w = gel(v,i); /* [ord(CHI),*,dim,*] */ ct += itou(gel(w,3))*myeulerphiu(itou(gel(w,1))); } avma = av; return ct; } static GEN mfwt1newdimall(long N, GEN vCHI) { GEN z, w, vTMP, fa, P, E; long i, c, l, lw, P1; if (wt1empty(N)) return mfdim0all(vCHI); w = mfwt1chars(N,vCHI); lw = lg(w); if (lw == 1) return cgetg(1,t_VEC); vTMP = const_vec(N, NULL); gel(vTMP,N) = mfwt1_pre(N); /* if p || N and p \nmid F(CHI), S_1^new(G0(N),chi) = 0 */ fa = znstar_get_faN(gmael(w,1,1)); P = gel(fa,1); l = lg(P); E = gel(fa,2); for (i = P1 = 1; i < l; i++) if (E[i] == 1) P1 *= itou(gel(P,i)); /* P1 = \prod_{v_p(N) = 1} p */ z = cgetg(lw, t_VEC); for (i = c = 1; i < lw; i++) { long S, j, l, F, dihnew; GEN D, CHI = gel(w,i), CHIP = mfchartoprimitive(CHI,&F); S = F % P1? 0: mfwt1cuspdim_i(N, CHI, gel(vTMP,N), &dihnew); if (!S) { if (vCHI) gel(z, c++) = zerovec(2); continue; } D = mydivisorsu(N/F); l = lg(D); for (j = l-2; j > 0; j--) /* skip last M = N */ { long M = D[j]*F, m, s, dih; GEN TMP = gel(vTMP,M); if (wt1empty(M) || !(m = mubeta(D[l-j]))) continue; /*m = mubeta(N/M)*/ if (!TMP) gel(vTMP,M) = TMP = mfwt1_pre(M); s = mfwt1cuspdim_i(M, CHIP, TMP, &dih); if (s) { S += m * s; dihnew += m * dih; } } if (vCHI) gel(z,c++) = mkvec2s(S, dihnew); else if (S) gel(z, c++) = fmt_dim(CHI, S, dihnew); } setlg(z,c); return z; } static GEN mfwt1olddimall(long N, GEN vCHI) { long i, j, l; GEN z, w; if (wt1empty(N)) return mfdim0all(vCHI); w = mfwt1chars(N,vCHI); l = lg(w); z = cgetg(l, t_VEC); for (i = j = 1; i < l; i++) { GEN CHI = gel(w,i); long d = mfolddim(N, 1, CHI); if (vCHI) gel(z,j++) = mkvec2s(d,d?-1:0); else if (d) gel(z, j++) = fmt_dim(CHI, d, -1); } setlg(z,j); return z; } static long mfwt1olddimsum(long N) { GEN D; long N2, i, l, S = 0; newd_params(N, &N2); /* will ensure mubeta != 0 */ D = mydivisorsu(N/N2); l = lg(D); for (i = 2; i < l; i++) { long M = D[l-i]*N2, d = mfwt1cuspdimsum(M); if (d) S -= mubeta(D[i]) * d; } return S; } static long mfwt1newdimsum(long N) { long S = mfwt1cuspdimsum(N); return S? S - mfwt1olddimsum(N): 0; } static long mfisdihedral(GEN vF, GEN DIH) { GEN vG = gel(DIH,1), M = gel(DIH,2), v, G, bnr, w, gen, cyc, D, f, nf, con; GEN f0, f0b, xin; long i, l, e, j, L, n; if (lg(M) == 1) return 0; v = RgM_RgC_invimage(M, vF); if (!v) return 0; l = lg(v); for (i = 1; i < l; i++) if (!gequal0(gel(v,i))) break; if (i == l) return 0; G = gel(vG,i); bnr = gel(G,2); cyc = bnr_get_cyc(bnr); D = gel(cyc,1); w = gel(G,3); f = bnr_get_mod(bnr); nf = bnr_get_nf(bnr); con = gel(galoisconj(nf,gen_1), 2); f0 = gel(f,1); f0b = galoisapply(nf, con, f0); xin = zv_to_ZV(gel(w,2)); /* xi(bnr.gen[i]) = e(xin[i] / D) */ if (!gequal(f0,f0b)) { /* finite part of conductor not ambiguous */ GEN a = idealmul(nf, f0, idealdivexact(nf, f0b, idealadd(nf, f0, f0b))); GEN bnr0 = bnr; bnr = bnrinit0(bnr_get_bnf(bnr), mkvec2(a, gel(f,2)), 1); xin = RgV_RgM_mul(xin, bnrsurjection(bnr, bnr0)); /* still xi(gen[i]) = e(xin[i] / D), for the new generators */ } gen = bnr_get_gen(bnr); L = lg(gen); for (j = 1, e = itou(D); j < L; j++) { GEN Ng = idealnorm(nf, gel(gen,j)); GEN a = shifti(gel(xin,j), 1); /* xi(g_j^2) = e(a/D) */ GEN b = FpV_dotproduct(xin, isprincipalray(bnr,Ng), D); GEN m = Fp_sub(a, b, D); /* xi(g_j/\bar{g_j}) = e(m/D) */ e = ugcd(e, itou(m)); if (e == 1) break; } n = itou(D) / e; return n == 1? 4: 2*n; } static ulong radical_u(ulong n) { return zv_prod(gel(myfactoru(n),1)); } /* list of fundamental discriminants unramified outside N, with sign s * [s = 0 => no sign condition] */ static GEN mfunram(long N, long s) { long cN = radical_u(N >> vals(N)), p = 1, m = 1, l, c, i; GEN D = mydivisorsu(cN), res; l = lg(D); if (s == 1) m = 0; else if (s == -1) p = 0; res = cgetg(6*l - 5, t_VECSMALL); c = 1; if (!odd(N)) { /* d = 1 */ if (p) res[c++] = 8; if (m) { res[c++] =-8; res[c++] =-4; } } for (i = 2; i < l; i++) { /* skip d = 1, done above */ long d = D[i], d4 = d & 3L; /* d odd, squarefree, d4 = 1 or 3 */ if (d4 == 1) { if (p) res[c++] = d; } else { if (m) res[c++] =-d; } if (!odd(N)) { if (p) { res[c++] = 8*d; if (d4 == 3) res[c++] = 4*d; } if (m) { res[c++] =-8*d; if (d4 == 1) res[c++] =-4*d; } } } setlg(res, c); return res; } /* Return 1 if F is definitely not S4 type; return 0 on failure. */ static long mfisnotS4(long N, GEN w) { GEN D = mfunram(N, 0); long i, lD = lg(D), lw = lg(w); for (i = 1; i < lD; i++) { long p, d = D[i], ok = 0; for (p = 2; p < lw; p++) if (w[p] && kross(d,p) == -1) { ok = 1; break; } if (!ok) return 0; } return 1; } /* Return 1 if Q(sqrt(5)) \not\subset Q(F), i.e. F is definitely not A5 type; * return 0 on failure. */ static long mfisnotA5(GEN F) { GEN CHI = mf_get_CHI(F), P = mfcharpol(CHI), T, Q; if (mfcharorder(CHI) % 5 == 0) return 0; T = mf_get_field(F); if (degpol(T) == 1) return 1; if (degpol(P) > 1) T = rnfequation(P,T); Q = gsubgs(pol_xn(2,varn(T)), 5); return (typ(nfisincl(Q, T)) == t_INT); } /* Given x = z + 1/z with z prim. root of unity of order n, find n */ static long mffindrootof1(GEN u1) { GEN u0 = gen_2, u1k = u1, u2; long c = 1; while (!gequalsg(2, liftpol_shallow(u1))) /* u1 = z^c + z^-c */ { u2 = gsub(gmul(u1k, u1), u0); u0 = u1; u1 = u2; c++; } return c; } /* we known that F is not dihedral */ static long mfgaloistype_i(long N, GEN CHI, GEN F, GEN v) { forprime_t iter; long lim = lg(v)-2; GEN w = zero_zv(lim); pari_sp av; ulong p; u_forprime_init(&iter, 2, lim); av = avma; while((p = u_forprime_next(&iter))) { GEN u; long n; if (!(N%p)) continue; u = gel(v, p+1); if (gequal0(u)) continue; u = gdiv(gsqr(u), mfchareval_i(CHI, p)); n = mffindrootof1(gsubgs(u,2)); if (n == 3) w[p] = 1; if (n == 4) return -24; /* S4 */ if (n == 5) return -60; /* A5 */ if (n > 5) pari_err_DOMAIN("mfgaloistype", "form", "not a", strtoGENstr("cuspidal eigenform"), F); avma = av; } if (mfisnotS4(N,w) && mfisnotA5(F)) return -12; /* A4 */ return 0; /* FAILURE */ } static GEN mfgaloistype0(long N, GEN CHI, GEN F, GEN DIH, long lim) { pari_sp av = avma; GEN vF = mftocol(F, lim, 1); long t = mfisdihedral(vF, DIH); if (t) { avma = av; return stoi(t); } for(;;) { t = mfgaloistype_i(N, CHI, F, vF); avma = av; if (t) return stoi(t); lim += lim >> 1; vF = mfcoefs_i(F,lim,1); } } /* If f is NULL, give all the galoistypes, otherwise just for f */ GEN mfgaloistype(GEN NK, GEN f) { pari_sp av = avma; GEN CHI, T, F, DIH, mf = checkMF_i(NK); long N, k, lL, i, lim, SB; if (f && !checkmf_i(f)) pari_err_TYPE("mfgaloistype", f); if (mf) { N = MF_get_N(mf); k = MF_get_k(mf); CHI = MF_get_CHI(mf); } else { checkNK(NK, &N, &k, &CHI, 0); mf = f? NULL: mfinit_i(NK, mf_NEW); } if (k != 1) pari_err_DOMAIN("mfgaloistype", "k", "!=", gen_1, stoi(k)); SB = mf? mfsturm_mf(mf): mfsturmNk(N,1); DIH = mfdihedralnew(N,CHI); lim = lg(DIH) == 1? 200: SB; DIH = mkvec2(DIH, mfvectomat(DIH,SB,1)); if (f) return gerepileuptoint(av, mfgaloistype0(N,CHI, f, DIH, lim)); F = mfeigenbasis(mf); lL = lg(F); T = cgetg(lL, t_VEC); for (i=1; i < lL; i++) gel(T,i) = mfgaloistype0(N, CHI, gel(F,i), DIH, lim); return gerepileupto(av, T); } /******************************************************************/ /* Find all dihedral forms. */ /******************************************************************/ /* lim >= 2 */ static void consttabdihedral(long lim) { cache_set(cache_DIH, mfdihedralall(mkvecsmall2(1,lim))); } /* a ideal coprime to bnr modulus */ static long mfdiheval(GEN bnr, GEN w, GEN a) { GEN L, cycn = gel(w,1), chin = gel(w,2); long ordmax = cycn[1]; L = ZV_to_Flv(isprincipalray(bnr,a), ordmax); return Flv_dotproduct(chin, L, ordmax); } /* A(x^k) mod T */ static GEN Galois(GEN A, long k, GEN T) { if (typ(A) != t_POL) return A; return gmod(RgX_inflate(A, k), T); } static GEN vecGalois(GEN v, long k, GEN T) { long i, l; GEN w = cgetg_copy(v,&l); for (i = 1; i < l; i++) gel(w,i) = Galois(gel(v,i), k, T); return w; } static GEN fix_pol(GEN S, GEN Pn, int *trace) { if (typ(S) != t_POL) return S; S = RgX_rem(S, Pn); if (typ(S) == t_POL) { switch(lg(S)) { case 2: return gen_0; case 3: return gel(S,2); } *trace = 1; } return S; } static GEN dihan(GEN bnr, GEN w, GEN k0j, ulong lim) { GEN nf = bnr_get_nf(bnr), f = bid_get_ideal(bnr_get_bid(bnr)); GEN v = zerovec(lim+1), cycn = gel(w,1), Tinit = gel(w,3); GEN Pn = gel(Tinit,lg(Tinit)==4? 2: 1); long j, ordmax = cycn[1], k0 = k0j[1], jdeg = k0j[2]; long D = itos(nf_get_disc(nf)), vt = varn(Pn); int trace = 0; ulong p, n; forprime_t T; if (!lim) return v; gel(v,2) = gen_1; u_forprime_init(&T, 2, lim); /* fill in prime powers first */ while ((p = u_forprime_next(&T))) { GEN vP, vchiP, S; long k, lP; ulong q, qk; if (kross(D,p) >= 0) q = p; else if (!(q = umuluu_le(p,p,lim))) continue; /* q = Norm P */ vP = idealprimedec(nf, utoipos(p)); lP = lg(vP); vchiP = cgetg(lP, t_VECSMALL); for (j = k = 1; j < lP; j++) { GEN P = gel(vP,j); if (!idealval(nf, f, P)) vchiP[k++] = mfdiheval(bnr,w,P); } if (k == 1) continue; setlg(vchiP, k); lP = k; if (lP == 2) { /* one prime above p not dividing f */ long s, s0 = vchiP[1]; for (qk=q, s = s0;; s = Fl_add(s,s0,ordmax)) { S = mygmodulo_lift(s, ordmax, gen_1, vt); gel(v, qk+1) = fix_pol(S, Pn, &trace); if (!(qk = umuluu_le(qk,q,lim))) break; } } else /* two primes above p not dividing f */ { long s, s0 = vchiP[1], s1 = vchiP[2]; for (qk=q, k = 1;; k++) { /* sum over a,b s.t. Norm( P1^a P2^b ) = q^k, i.e. a+b = k */ long a; GEN S = gen_0; for (a = 0; a <= k; a++) { s = Fl_add(Fl_mul(a, s0, ordmax), Fl_mul(k-a, s1, ordmax), ordmax); S = gadd(S, mygmodulo_lift(s, ordmax, gen_1, vt)); } gel(v, qk+1) = fix_pol(S, Pn, &trace); if (!(qk = umuluu_le(qk,q,lim))) break; } } } /* complete with non-prime powers */ for (n = 2; n <= lim; n++) { GEN S, fa = myfactoru(n), P = gel(fa, 1), E = gel(fa, 2); long q; if (lg(P) == 2) continue; /* not a prime power */ q = upowuu(P[1],E[1]); S = gmul(gel(v, q + 1), gel(v, n/q + 1)); gel(v, n+1) = fix_pol(S, Pn, &trace); } if (trace) { if (lg(Tinit) == 4) v = QabV_tracerel(Tinit, jdeg, v); /* Apply Galois Mod(k0, ordw) */ if (k0 > 1) { GEN Pm = gel(Tinit,1); v = vecGalois(v, k0, Pm); } } return v; } /* as cyc_normalize for t_VECSMALL cyc */ static GEN cyc_normalize_zv(GEN cyc) { long i, o = cyc[1], l = lg(cyc); /* > 1 */ GEN D = cgetg(l, t_VECSMALL); D[1] = o; for (i = 2; i < l; i++) D[i] = o / cyc[i]; return D; } /* as char_normalize for t_VECSMALLs */ static GEN char_normalize_zv(GEN chi, GEN ncyc) { long i, l = lg(chi); GEN c = cgetg(l, t_VECSMALL); if (l > 1) { c[1] = chi[1]; for (i = 2; i < l; i++) c[i] = chi[i] * ncyc[i]; } return c; } static GEN dihan_bnf(long D) { setrand(gen_1); return Buchall(quadpoly(stoi(D)), 0, LOWDEFAULTPREC); } static GEN dihan_bnr(GEN bnf, GEN A) { setrand(gen_1); return bnrinit0(bnf, A, 1); } /* Hecke xi * (D/.) = Dirichlet chi, return v in Q^r st chi(g_i) = e(v[i]). * cycn = cyc_normalize_zv(bnr.cyc), chin = char_normalize_zv(chi,cyc) */ static GEN bnrchartwist2conrey(GEN chin, GEN cycn, GEN bnrconreyN, GEN kroconreyN) { long l = lg(bnrconreyN), c1 = cycn[1], i; GEN v = cgetg(l, t_COL); for (i = 1; i < l; i++) { GEN d = sstoQ(zv_dotproduct(chin, gel(bnrconreyN,i)), c1); if (kroconreyN[i] < 0) d = gadd(d, ghalf); gel(v,i) = d; } return v; } /* chi(g_i) = e(v[i]) denormalize wrt Conrey generators orders */ static GEN conreydenormalize(GEN znN, GEN v) { GEN gcyc = znstar_get_conreycyc(znN), w; long l = lg(v), i; w = cgetg(l, t_COL); for (i = 1; i < l; i++) gel(w,i) = modii(gmul(gel(v,i), gel(gcyc,i)), gel(gcyc,i)); return w; } static long Miyake(GEN vchi, GEN gb, GEN cycn) { long i, e = cycn[1], lb = lg(gb); GEN v = char_normalize_zv(vchi, cycn); for (i = 1; i < lb; i++) if ((zv_dotproduct(v, gel(gb,i)) - v[i]) % e) return 1; return 0; } /* list of Hecke characters not induced by a Dirichlet character up to Galois * conjugation, whose conductor is bnr.cond; cycn = cyc_normalize(bnr.cyc)*/ static GEN mklvchi(GEN bnr, GEN con, GEN cycn) { GEN gb = NULL, cyc = bnr_get_cyc(bnr), cycsmall = ZV_to_zv(cyc); GEN vchi = cyc2elts(cycsmall); long ordmax = cycsmall[1], c, i, l; if (con) { GEN g = bnr_get_gen(bnr), nf = bnr_get_nf(bnr); long lg = lg(g); gb = cgetg(lg, t_VEC); for (i = 1; i < lg; i++) gel(gb,i) = ZV_to_zv(isprincipalray(bnr, galoisapply(nf, con, gel(g,i)))); } l = lg(vchi); for (i = c = 1; i < l; i++) { GEN chi = gel(vchi,i); if (!con || Miyake(chi, gb, cycn)) gel(vchi, c++) = Flv_to_ZV(chi); } setlg(vchi, c); l = c; for (i = 1; i < l; i++) { GEN chi = gel(vchi,i); long n; if (!chi) continue; for (n = 2; n < ordmax; n++) if (ugcd(n, ordmax) == 1) { GEN tmp = vecmodii(gmulsg(n, chi), cyc); long j; for (j = i+1; j < l; j++) if (gel(vchi,j) && gequal(gel(vchi,j), tmp)) gel(vchi,j) = NULL; } } for (i = c = 1; i < l; i++) { GEN chi = gel(vchi,i); if (chi && bnrisconductor(bnr, chi)) gel(vchi, c++) = chi; } setlg(vchi, c); return vchi; } /* con = NULL if D > 0 or if D < 0 and id != idcon. */ static GEN mfdihedralcommon(GEN bnf, GEN id, GEN znN, GEN kroconreyN, long N, long D, GEN con) { GEN bnr, bnrconreyN, cyc, cycn, cycN, Lvchi, res, g, P; long i, j, ordmax, l, lc, deghecke, degrel; bnr = dihan_bnr(bnf, id); cyc = ZV_to_zv( bnr_get_cyc(bnr) ); lc = lg(cyc); if (lc == 1) return NULL; g = znstar_get_conreygen(znN); l = lg(g); bnrconreyN = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(bnrconreyN,i) = ZV_to_zv(isprincipalray(bnr,gel(g,i))); cycn = cyc_normalize_zv(cyc); cycN = ZV_to_zv(znstar_get_cyc(znN)); ordmax = cyc[1]; P = polcyclo(ord_canon(ordmax), fetch_user_var("t")); deghecke = myeulerphiu(ordmax); Lvchi = mklvchi(bnr, con, cycn); l = lg(Lvchi); if (l == 1) return NULL; res = cgetg(l, t_VEC); for (j = 1; j < l; j++) { GEN T, Tinit, v, vchi = ZV_to_zv(gel(Lvchi,j)); GEN chi, chin = char_normalize_zv(vchi, cycn); long ordw, vnum, k0; v = bnrchartwist2conrey(chin, cycn, bnrconreyN, kroconreyN); ordw = itou(Q_denom(v)); Tinit = Qab_trace_init(P, ord_canon(ordmax), ord_canon(ordw)); chi = conreydenormalize(znN, v); vnum = itou(znconreyexp(znN, chi)); chi = ZV_to_zv(znconreychar(znN,chi)); degrel = deghecke / myeulerphiu(ordw); k0 = zv_cyc_minimize(cycN, chi, coprimes_zv(ordw)); vnum = Fl_powu(vnum, k0, N); /* encodes degrel forms: jdeg = 0..degrel-1 */ T = mkvecsmalln(6, N, k0, vnum, D, ordmax, degrel); gel(res,j) = mkvec3(T, id, mkvec3(cycn,chin,Tinit)); } return res; } /* Append to v all dihedral weight 1 forms coming from D, if fundamental. * level in [l1, l2] */ static void append_dihedral(GEN v, long D, long l1, long l2) { long Da = labs(D), no, N, i, numi, ct, min, max; GEN bnf, con, LI, resall, varch; pari_sp av; /* min <= Nf <= max */ max = l2 / Da; if (l1 == l2) { /* assume Da | l2 */ min = max; if (D > 0 && min < 3) return; } else /* assume l1 < l2 */ min = (l1 + Da-1)/Da; if (!sisfundamental(D)) return; av = avma; bnf = dihan_bnf(D); con = gel(galoisconj(bnf,gen_1), 2); LI = ideallist(bnf, max); numi = 0; for (i = min; i <= max; i++) numi += lg(gel(LI, i)) - 1; if (D > 0) { numi <<= 1; varch = mkvec2(mkvec2(gen_1,gen_0), mkvec2(gen_0,gen_1)); } else varch = NULL; resall = cgetg(numi+1, t_VEC); ct = 1; for (no = min; no <= max; no++) { GEN LIs, znN, conreyN, kroconreyN; long flcond, lgc, lglis; if (D < 0) flcond = (no == 2 || no == 3 || (no == 4 && (D&7L)==1)); else flcond = (no == 4 && (D&7L) != 1); if (flcond) continue; LIs = gel(LI, no); N = Da*no; znN = znstar0(utoi(N), 1); conreyN = znstar_get_conreygen(znN); lgc = lg(conreyN); kroconreyN = cgetg(lgc, t_VECSMALL); for (i = 1; i < lgc; i++) kroconreyN[i] = krosi(D, gel(conreyN, i)); lglis = lg(LIs); for (i = 1; i < lglis; i++) { GEN id = gel(LIs, i), idcon, conk; long j, inf, maxinf; if (typ(id) == t_INT) continue; idcon = galoisapply(bnf, con, id); conk = (D < 0 && gequal(idcon, id)) ? con : NULL; for (j = i; j < lglis; j++) if (gequal(idcon, gel(LIs, j))) { gel(LIs, j) = gen_0; break; } maxinf = (D < 0 || gequal(idcon,id))? 1: 2; for (inf = 1; inf <= maxinf; inf++) { GEN ide = (D > 0)? mkvec2(id, gel(varch,inf)): id; GEN res = mfdihedralcommon(bnf, ide, znN, kroconreyN, N, D, conk); if (res) gel(resall, ct++) = res; } } } if (ct == 1) avma = av; else { setlg(resall, ct); vectrunc_append(v, gerepilecopy(av, shallowconcat1(resall))); } } static long di_N(GEN a) { return gel(a,1)[1]; } /* All primitive dihedral wt1 forms: LIM a t_VECSMALL with a single component * (only level LIM) or 2 components [m,M], m < M (between m and M) */ static GEN mfdihedralall(GEN LIM) { GEN res, z; long limD, ct, i, l1, l2; if (lg(LIM) == 2) l1 = l2 = LIM[1]; else { l1 = LIM[1]; l2 = LIM[2]; } limD = l2; res = vectrunc_init(2*limD); if (l1 == l2) { GEN D = mydivisorsu(l1); long l = lg(D), j; for (j = 2; j < l; j++) { /* skip d = 1 */ long d = D[j]; if (d == 2) continue; append_dihedral(res, -d, l1,l2); if (d >= 5 && D[l-j] >= 3) append_dihedral(res, d, l1,l2); /* Nf >= 3 */ } } else { long D; for (D = -3; D >= -limD; D--) append_dihedral(res, D, l1,l2); limD /= 3; /* Nf >= 3 (GTM 193, prop 3.3.18) */ for (D = 5; D <= limD; D++) append_dihedral(res, D, l1,l2); } ct = lg(res); if (ct > 1) res = shallowconcat1(res); if (l1 == l2) return res; /* single level */ if (ct > 1) { /* sort wrt N */ res = vecpermute(res, indexvecsort(res, mkvecsmall(1))); ct = lg(res); } z = const_vec(l2-l1+1, cgetg(1,t_VEC)); for (i = 1; i < ct;) { /* regroup result sharing the same N */ long n = di_N(gel(res,i)), j = i+1, k; GEN v; while (j < ct && di_N(gel(res,j)) == n) j++; n -= l1-1; gel(z, n) = v = cgetg(j-i+1, t_VEC); for (k = 1; i < j; k++,i++) gel(v,k) = gel(res,i); } return z; } /* return [vF, index], where vecpermute(vF,index) generates dihedral forms * for character CHI */ static GEN mfdihedralnew_i(long N, GEN CHI) { GEN bnf, Tinit, Pm, vf, M, V, NK, SP; long Dold, d, ordw, i, SB, c, l, k0, k1, chino, chinoorig, lv; SP = cache_get(cache_DIH, N); if (!SP) SP = mfdihedralall(mkvecsmall(N)); lv = lg(SP); if (lv == 1) return NULL; CHI = mfcharinduce(CHI,N); ordw = mfcharorder(CHI); chinoorig = mfcharno(CHI); k0 = mfconreyminimize(CHI); chino = Fl_powu(chinoorig, k0, N); k1 = Fl_inv(k0 % ordw, ordw); V = cgetg(lv, t_VEC); d = 0; for (i = l = 1; i < lv; i++) { GEN sp = gel(SP,i), T = gel(sp,1); if (T[3] != chino) continue; d += T[6]; if (k1 != 1) { GEN t = leafcopy(T); t[3] = chinoorig; t[2] = (t[2]*k1)%ordw; sp = mkvec4(t, gel(sp,2), gel(sp,3), gel(sp,4)); } gel(V, l++) = sp; } setlg(V, l); /* dihedral forms of level N and character CHI */ if (l == 1) return NULL; SB = myeulerphiu(ordw) * mfsturmNk(N,1) + 1; M = cgetg(d+1, t_MAT); vf = cgetg(d+1, t_VEC); NK = mkNK(N, 1, CHI); bnf = NULL; Dold = 0; for (i = c = 1; i < l; i++) { /* T = [N, k0, conreyno, D, ordmax, degrel] */ GEN bnr, Vi = gel(V,i), T = gel(Vi,1), id = gel(Vi,2), w = gel(Vi,3); long jdeg, k0i = T[2], D = T[4], degrel = T[6]; if (D != Dold) { Dold = D; bnf = dihan_bnf(D); } bnr = dihan_bnr(bnf, id); for (jdeg = 0; jdeg < degrel; jdeg++,c++) { GEN k0j = mkvecsmall2(k0i, jdeg), an = dihan(bnr, w, k0j, SB); settyp(an, t_COL); gel(M,c) = Q_primpart(an); gel(vf,c) = tag3(t_MF_DIHEDRAL, NK, bnr, w, k0j); } } Tinit = gmael3(V,1,3,3); Pm = gel(Tinit,1); V = QabM_indexrank(M, degpol(Pm)==1? NULL: Pm, ord_canon(ordw)); return mkvec2(vf,gel(V,2)); } static long mfdihedralnewdim(long N, GEN CHI) { pari_sp av = avma; GEN S = mfdihedralnew_i(N, CHI); long d = S ? lg(gel(S,2))-1: 0; avma = av; return d; } static GEN mfdihedralnew(long N, GEN CHI) { pari_sp av = avma; GEN S = mfdihedralnew_i(N, CHI); if (!S) { avma = av; return cgetg(1, t_VEC); } return vecpermute(gel(S,1), gel(S,2)); } static long mfdihedralcuspdim(long N, GEN CHI) { pari_sp av = avma; GEN D, CHIP; long F, i, lD, dim; CHIP = mfchartoprimitive(CHI, &F); D = mydivisorsu(N/F); lD = lg(D); dim = mfdihedralnewdim(N, CHI); /* d = 1 */ for (i = 2; i < lD; i++) { long d = D[i], M = N/d, a = mfdihedralnewdim(M, CHIP); if (a) dim += a * mynumdivu(d); } avma = av; return dim; } static GEN mfbdall(GEN E, long N) { GEN v, D = mydivisorsu(N); long i, j, nD = lg(D) - 1, nE = lg(E) - 1; v = cgetg(nD*nE + 1, t_VEC); for (j = 1; j <= nE; j++) { GEN Ej = gel(E, j); for (i = 0; i < nD; i++) gel(v, i*nE + j) = mfbd_i(Ej, D[i+1]); } return v; } static GEN mfdihedralcusp(long N, GEN CHI) { pari_sp av = avma; GEN D, CHIP, z; long F, i, lD; CHIP = mfchartoprimitive(CHI, &F); D = mydivisorsu(N/F); lD = lg(D); z = cgetg(lD, t_VEC); gel(z,1) = mfdihedralnew(N, CHI); for (i = 2; i < lD; i++) /* skip 1 */ { long d = D[i], M = N / d; GEN LF = mfdihedralnew(M, mfcharinduce(CHIP, M)); gel(z,i) = mfbdall(LF, d); } return gerepilecopy(av, shallowconcat1(z)); } /* used to decide between ratlift and comatrix for ZM_inv; ratlift is better * when N has many divisors */ static int abundant(ulong N) { return mynumdivu(N) >= 8; } /* CHI an mfchar */ static int cmp_ord(void *E, GEN a, GEN b) { GEN chia = MF_get_CHI(a), chib = MF_get_CHI(b); (void)E; return cmpii(gmfcharorder(chia), gmfcharorder(chib)); } /* mfinit structure. -- mf[1] contains [N,k,CHI,space], -- mf[2] contains vector of closures of Eisenstein series, empty if not full space. -- mf[3] contains vector of closures, so #mf[3] = dimension of cusp/new space. -- mf[4] contains the corresponding indices: either j for T(j)tf if newspace, or [M,j,d] for B(d)T(j)tf_M if cuspspace or oldspace. -- mf[5] contains the matrix M of first coefficients of basis, never cleaned. * NK is either [N,k] or [N,k,CHI]. * mfinit does not do the splitting, only the basis generation. */ /* Set flraw to 1 if do not need mf[5]: no mftobasis etc..., only the expansions of the basis elements are needed. */ static GEN mfinit_Nkchi(long N, long k, GEN CHI, long space, long flraw) { GEN M = NULL, mf = NULL, mf1 = mkvec4(utoi(N), stoi(k), CHI, utoi(space)); long sb = mfsturmNk(N, k); cachenew_t cache; if (k < 0 || badchar(N, k, CHI)) return mfEMPTY(mf1); if (k == 0) /*nothing*/; else if (k == 1) { switch (space) { case mf_NEW: case mf_FULL: case mf_CUSP: mf = mfwt1init(N, CHI, NULL, space, flraw); break; case mf_EISEN:break; case mf_OLD: pari_err_IMPL("mfinit in weight 1 for old space"); default: pari_err_FLAG("mfinit"); } } else /* k >= 2 */ { long ord = mfcharorder_canon(CHI); GEN z = NULL, P = (ord == 1)? NULL: mfcharpol(CHI); switch(space) { case mf_EISEN: break; case mf_NEW: mf = mfnewinit(N, k, CHI, &cache, 1); if (mf && !flraw) { M = MF_get_M(mf); z = MF_get_Mindex(mf); } break; case mf_OLD: case mf_CUSP: case mf_FULL: mf = mfinitcusp(N, k, CHI, &cache, space); if (mf && !flraw) { GEN S = MF_get_S(mf); M = bhnmat_extend(M, sb+1, 1, S, &cache); if (space != mf_FULL) gel(mf,5) = mfcleanCHI(M, CHI, abundant(N)); } dbg_cachenew(&cache); break; default: pari_err_FLAG("mfinit"); } if (z) gel(mf,5) = mfclean2(M, z, P, ord); } if (!mf) mf = mfEMPTY(mf1); else { gel(mf,1) = mf1; if (flraw) gel(mf,5) = zerovec(3); } if (!space_is_cusp(space)) { GEN E = mfeisensteinbasis(N, k, CHI); gel(mf,2) = E; if (!flraw) { if (M) M = shallowconcat(mfvectomat(E, sb+1, 1), M); else M = mfcoefs_mf(mf, sb+1, 1); gel(mf,5) = mfcleanCHI(M, CHI, abundant(N)); } } return mf; } /* mfinit for k = nk/dk */ static GEN mfinit_Nndkchi(long N, long nk, long dk, GEN CHI, long space, long flraw) { return (dk == 2)? mf2init_Nkchi(N, nk >> 1, CHI, space, flraw) : mfinit_Nkchi(N, nk, CHI, space, flraw); } static GEN mfinit_i(GEN NK, long space) { GEN CHI, mf; long N, k, dk, joker; if (checkmf_i(NK)) { N = mf_get_N(NK); Qtoss(mf_get_gk(NK), &k, &dk); CHI = mf_get_CHI(NK); } else if ((mf = checkMF_i(NK))) { long s = MF_get_space(mf); if (s == space) return mf; Qtoss(MF_get_gk(mf), &k, &dk); if (dk == 1 && k > 1 && space == mf_NEW && (s == mf_CUSP || s == mf_FULL)) return mfinittonew(mf); N = MF_get_N(mf); CHI = MF_get_CHI(mf); } else checkNK2(NK, &N, &k, &dk, &CHI, 1); joker = !CHI || typ(CHI) == t_COL; if (joker) { GEN mf, vCHI = CHI; long i, j, l; if (CHI && lg(CHI) == 1) return cgetg(1,t_VEC); if (k < 0) return mfEMPTYall(N, sstoQ(k,dk), CHI, space); if (k == 1 && dk == 1 && space != mf_EISEN) { GEN TMP, gN, gs; if (space != mf_CUSP && space != mf_NEW) pari_err_IMPL("mfinit([N,1,wildcard], space != cusp or new space)"); if (wt1empty(N)) return mfEMPTYall(N, gen_1, CHI, space); vCHI = mfwt1chars(N,vCHI); l = lg(vCHI); mf = cgetg(l, t_VEC); if (l == 1) return mf; TMP = mfwt1_pre(N); gN = utoipos(N); gs = utoi(space); for (i = j = 1; i < l; i++) { pari_sp av = avma; GEN c = gel(vCHI,i), z = mfwt1init(N, c, TMP, space, 0); if (!z) { avma = av; if (CHI) z = mfEMPTY(mkvec4(gN,gen_1,c,gs)); } if (z) gel(mf, j++) = z; } } else { vCHI = mfchars(N,k,dk,vCHI); l = lg(vCHI); mf = cgetg(l, t_VEC); for (i = j = 1; i < l; i++) { pari_sp av = avma; GEN v = mfinit_Nndkchi(N, k, dk, gel(vCHI,i), space, 0); if (MF_get_dim(v) || CHI) gel(mf, j++) = v; else avma = av; } } setlg(mf,j); if (!CHI) gen_sort_inplace(mf, NULL, &cmp_ord, NULL); return mf; } return mfinit_Nndkchi(N, k, dk, CHI, space, 0); } GEN mfinit(GEN NK, long space) { pari_sp av = avma; return gerepilecopy(av, mfinit_i(NK, space)); } /* UTILITY FUNCTIONS */ static void cusp_canon(GEN cusp, long N, long *pA, long *pC) { pari_sp av = avma; long A, C, tc, cg; if (N <= 0) pari_err_DOMAIN("mfcuspwidth","N","<=",gen_0,stoi(N)); if (!cusp || (tc = typ(cusp)) == t_INFINITY) { *pA = 1; *pC = N; return; } if (tc != t_INT && tc != t_FRAC) pari_err_TYPE("checkcusp", cusp); Qtoss(cusp, &A,&C); if (N % C) { ulong uC; long u = Fl_invgen((C-1)%N + 1, N, &uC); A = Fl_mul(A, u, N); C = (long)uC; } cg = ugcd(C, N/C); while (ugcd(A, N) > 1) A += cg; *pA = A % N; *pC = C; avma = av; } static long mfcuspcanon_width(long N, long C) { return (!C || C == N)? 1 : N / ugcd(N, Fl_sqr(umodsu(C,N),N)); } /* v = [a,c] a ZC, width of cusp (a:c) */ static long mfZC_width(long N, GEN v) { ulong C = umodiu(gel(v,2), N); return (C == 0)? 1: N / ugcd(N, Fl_sqr(C,N)); } long mfcuspwidth(GEN gN, GEN cusp) { long N = 0, A, C; GEN mf; if (typ(gN) == t_INT) N = itos(gN); else if ((mf = checkMF_i(gN))) N = MF_get_N(mf); else pari_err_TYPE("mfcuspwidth", gN); cusp_canon(cusp, N, &A, &C); return mfcuspcanon_width(N, C); } /* Q a t_INT */ static GEN findq(GEN al, GEN Q) { long n; if (typ(al) == t_FRAC && cmpii(gel(al,2), Q) <= 0) return mkvec(mkvec2(gel(al,1), gel(al,2))); n = 1 + (long)ceil(2.0781*gtodouble(glog(Q, LOWDEFAULTPREC))); return contfracpnqn(gboundcf(al,n), n); } static GEN findqga(long N, GEN z) { GEN Q, LDC, CK = NULL, DK = NULL, ma, x, y = imag_i(z); long j, l; if (gcmpgs(gmulsg(2*N, y), 1) >= 0) return NULL; x = real_i(z); Q = ground(ginv(gsqrt(gmulsg(N, y), LOWDEFAULTPREC))); LDC = findq(gmulsg(-N,x), Q); ma = gen_1; l = lg(LDC); for (j = 1; j < l; j++) { GEN D, DC = gel(LDC,j), C1 = gel(DC,2); if (cmpii(C1,Q) > 0) break; D = gel(DC,1); if (ugcdiu(D,N) == 1) { GEN C = mului(N, C1), den; den = gadd(gsqr(gmul(C,y)), gsqr(gadd(D, gmul(C,x)))); if (gcmp(den, ma) < 0) { ma = den; CK = C; DK = D; } } } return DK? mkvec2(CK, DK): NULL; } static long valNC2(GEN P, GEN E, long e) { long i, d = 1, l = lg(P); for (i = 1; i < l; i++) { long v = u_lval(e, P[i]) << 1; if (v == E[i] + 1) v--; d *= upowuu(P[i], v); } return d; } static GEN findqganew(long N, GEN z) { GEN MI, DI, x = real_i(z), y = imag_i(z), Ck = gen_0, Dk = gen_1, fa, P, E; long i; MI = ginv(utoi(N)); DI = mydivisorsu(mysqrtu(N)); fa = myfactoru(N); P = gel(fa,1); E = gel(fa,2); for (i = 1; i < lg(DI); i++) { long e = DI[i], g; GEN U, C, D, m; (void)cxredsl2(gmulsg(e, z), &U); C = gcoeff(U,2,1); if (!signe(C)) continue; D = gcoeff(U,2,2); g = ugcdiu(D,e); if (g > 1) { C = muliu(C,e/g); D = diviuexact(D,g); } else C = muliu(C,e); m = gadd(gsqr(gadd(gmul(C, x), D)), gsqr(gmul(C, y))); m = gdivgs(m, valNC2(P, E, e)); if (gcmp(m, MI) < 0) { MI = m; Ck = C; Dk = D; } } return signe(Ck)? mkvec2(Ck, Dk): NULL; } /* Return z' and U = [a,b;c,d] \in SL_2(Z), z' = U*z, * Im(z')/width(U.oo) > sqrt(3)/(2N). Set *pczd = c*z+d */ static GEN cxredga0N(long N, GEN z, GEN *pU, GEN *pczd, long flag) { GEN v = NULL, A, B, C, D; long e; if (N == 1) return cxredsl2_i(z, pU, pczd); e = gexpo(gel(z,2)); if (e < 0) z = gprec_wensure(z, precision(z) + nbits2extraprec(-e)); v = flag? findqganew(N,z): findqga(N,z); if (!v) { *pU = matid(2); *pczd = gen_1; return z; } C = gel(v,1); D = gel(v,2); if (!is_pm1(bezout(C,D, &B,&A))) pari_err_BUG("cxredga0N [gcd > 1]"); B = negi(B); *pU = mkmat2(mkcol2(A,C), mkcol2(B,D)); *pczd = gadd(gmul(C,z), D); return gdiv(gadd(gmul(A,z), B), *pczd); } static GEN lfunthetaall(GEN b, GEN vL, GEN t, long bitprec) { long i, l = lg(vL); GEN v = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN T, L = gel(vL,i), a0 = gel(L,1), ldata = gel(L,2); GEN van = gel(ldata_get_an(ldata),2); if (lg(van) == 1) { T = gmul(b, a0); if (isexactzero(T)) { GEN z = real_0_bit(-bitprec); T = mkcomplex(z,z); } } else { T = gmul2n(lfuntheta(ldata, t, 0, bitprec), -1); T = gmul(b, gadd(a0, T)); } gel(v,i) = T; } return l == 2? gel(v,1): v; } /* P in ZX */ static GEN ZX_roots(GEN P, long prec) { long d = degpol(P); if (d == 1) return mkvec(gen_0); if (d == 2 && isint1(gel(P,2)) && isintzero(gel(P,3)) && isint1(gel(P,4))) return mkvec2(powIs(3), gen_I()); /* order as polroots */ return (ZX_sturm(P) == d)? realroots(P,NULL,prec): QX_complex_roots(P,prec); } /* initializations for RgX_RgV_eval / RgC_embed */ static GEN rootspowers(GEN v) { long i, l = lg(v); GEN w = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(w,i) = gpowers(gel(v,i), l-2); return w; } /* mf embeddings attached to Q(chi)/(T), chi attached to cyclotomic P */ static GEN getembed(GEN P, GEN T, GEN zcyclo, long prec) { long i, l; GEN v; if (degpol(P) == 1) P = NULL; /* mfcharpol for quadratic char */ if (degpol(T) == 1) T = NULL; /* dim 1 orbit */ if (T && P) { /* K(y) / (T(y)), K = Q(t)/(P) cyclotomic */ GEN vr = RgX_is_ZX(T)? ZX_roots(T,prec): roots(RgX_embed1(T,zcyclo), prec); v = rootspowers(vr); l = lg(v); for (i = 1; i < l; i++) gel(v,i) = mkcol3(P,zcyclo,gel(v,i)); } else if (T) { /* Q(y) / (T(y)), T non-cyclotomic */ GEN vr = ZX_roots(T, prec); v = rootspowers(vr); l = lg(v); for (i = 1; i < l; i++) gel(v,i) = mkcol2(T, gel(v,i)); } else /* cyclotomic or rational */ v = mkvec(P? mkvec2(P, zcyclo): cgetg(1,t_VEC)); return v; } static GEN grootsof1_CHI(GEN CHI, long prec) { return grootsof1(mfcharorder_canon(CHI), prec); } /* return the [Q(F):Q(chi)] embeddings of F */ static GEN mfgetembed(GEN F, long prec) { GEN T = mf_get_field(F), CHI = mf_get_CHI(F), P = mfcharpol(CHI); return getembed(P, T, grootsof1_CHI(CHI, prec), prec); } static GEN mfchiembed(GEN mf, long prec) { GEN CHI = MF_get_CHI(mf), P = mfcharpol(CHI); return getembed(P, pol_x(0), grootsof1_CHI(CHI, prec), prec); } /* mfgetembed for the successive eigenforms in MF_get_newforms */ static GEN mfeigenembed(GEN mf, long prec) { GEN vP = MF_get_fields(mf), vF = MF_get_newforms(mf); GEN zcyclo, vE, CHI = MF_get_CHI(mf), P = mfcharpol(CHI); long i, l = lg(vP); vF = Q_remove_denom(liftpol_shallow(vF), NULL); prec += nbits2extraprec(gexpo(vF)); zcyclo = grootsof1_CHI(CHI, prec); vE = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(vE,i) = getembed(P, gel(vP,i), zcyclo, prec); return vE; } static int checkPv(GEN P, GEN v) { return typ(P) == t_POL && typ(v) == t_VEC && lg(v)-1 >= degpol(P); } static int checkemb_i(GEN E) { long t = typ(E), l = lg(E); if (t == t_VEC) return l == 1 || (l == 3 && checkPv(gel(E,1), gel(E,2))); if (t != t_COL) return 0; if (l == 3) return checkPv(gel(E,1), gel(E,2)); return l == 4 && typ(gel(E,2)) == t_VEC && checkPv(gel(E,1), gel(E,3)); } static GEN anyembed(GEN v, GEN E) { switch(typ(v)) { case t_VEC: case t_COL: return mfvecembed(E, v); case t_MAT: return mfmatembed(E, v); } return mfembed(E, v); } GEN mfembed0(GEN E, GEN v, long prec) { pari_sp av = avma; GEN mf, vE = NULL; if (checkmf_i(E)) vE = mfgetembed(E, prec); else if ((mf = checkMF_i(E))) vE = mfchiembed(mf, prec); if (vE) { long i, l = lg(vE); GEN w; if (!v) return gerepilecopy(av, l == 2? gel(vE,1): vE); w = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(w,i) = anyembed(v, gel(vE,i)); return gerepilecopy(av, l == 2? gel(w,1): w); } if (!checkemb_i(E) || !v) pari_err_TYPE("mfembed", E); return gerepilecopy(av, anyembed(v,E)); } /* dummy lfun create for theta evaluation */ static GEN mfthetaancreate(GEN van, GEN N, GEN k) { GEN L = zerovec(6); gel(L,1) = lfuntag(t_LFUN_GENERIC, van); gel(L,3) = mkvec2(gen_0, gen_1); gel(L,4) = k; gel(L,5) = N; return L; } /* destroy van and prepare to evaluate theta(sigma(van)), for all sigma in * embeddings vector vE */ static GEN van_embedall(GEN van, GEN vE, GEN gN, GEN gk) { GEN a0 = gel(van,1), vL; long i, lE = lg(vE), l = lg(van); van++; van[0] = evaltyp(t_VEC) | evallg(l-1); /* remove a0 */ vL = cgetg(lE, t_VEC); for (i = 1; i < lE; i++) { GEN E = gel(vE,i), v = mfvecembed(E, van); gel(vL,i) = mkvec2(mfembed(E,a0), mfthetaancreate(v, gN, gk)); } return vL; } static int cusp_AC(GEN cusp, long *A, long *C) { switch(typ(cusp)) { case t_INFINITY: *A = 1; *C = 0; break; case t_INT: *A = itos(cusp); *C = 1; break; case t_FRAC: *A = itos(gel(cusp, 1)); *C = itos(gel(cusp, 2)); break; case t_REAL: case t_COMPLEX: *A = 0; *C = 0; if (gsigne(imag_i(cusp)) <= 0) pari_err_DOMAIN("mfeval","imag(tau)","<=",gen_0,cusp); return 0; default: pari_err_TYPE("cusp_AC", cusp); } return 1; } static GEN cusp2mat(long A, long C) { long B, D; cbezout(A, C, &D, &B); return mkmat22s(A, -B, C, D); } static GEN mkS(void) { return mkmat22s(0,-1,1,0); } /* if t is a cusp, return F(t), else NULL */ static GEN evalcusp(GEN mf, GEN F, GEN t, long prec) { long A, C; GEN R; if (!cusp_AC(t, &A,&C)) return NULL; if (C % mf_get_N(F) == 0) return gel(mfcoefs_i(F, 0, 1), 1); R = mfgaexpansion(mf, F, cusp2mat(A,C), 0, prec); return gequal0(gel(R,1))? gmael(R,3,1): gen_0; } /* Evaluate an mf closure numerically, i.e., in the usual sense, either for a * single tau or a vector of tau; for each, return a vector of results * corresponding to all complex embeddings of F. If flag is non-zero, allow * replacing F by F | gamma to increase imag(gamma^(-1).tau) [ expensive if * MF_EISENSPACE not present ] */ static GEN mfeval_i(GEN mf, GEN F, GEN vtau, long flag, long bitprec) { GEN L0, vL, vb, sqN, vczd, vTAU, vs, van, vE; long N = mf_get_N(F), N0, ta, lv, i, prec = nbits2prec(bitprec); GEN gN = utoipos(N), gk = mf_get_gk(F), gk1 = gsubgs(gk,1), vgk; long flscal = 0; /* gen_0 is ignored, second component assumes Ramanujan-Petersson in * 1/2-integer weight */ vgk = mkvec2(gen_0, mfiscuspidal(mf,F)? gmul2n(gk1,-1): gk1); ta = typ(vtau); if (!is_vec_t(ta)) { flscal = 1; vtau = mkvec(vtau); ta = t_VEC; } lv = lg(vtau); sqN = sqrtr_abs(utor(N, prec)); vs = const_vec(lv-1, NULL); vb = const_vec(lv-1, NULL); vL = cgetg(lv, t_VEC); vTAU = cgetg(lv, t_VEC); vczd = cgetg(lv, t_VEC); L0 = mfthetaancreate(NULL, gN, vgk); /* only for thetacost */ vE = mfgetembed(F, prec); N0 = 0; for (i = 1; i < lv; i++) { GEN z = gel(vtau,i), tau, U; long w, n; gel(vs,i) = evalcusp(mf, F, z, prec); if (gel(vs,i)) continue; tau = cxredga0N(N, z, &U, &gel(vczd,i), flag); if (!flag) w = 0; else { w = mfZC_width(N, gel(U,1)); tau = gdivgs(tau,w); } gel(vTAU,i) = mulcxmI(gmul(tau, sqN)); n = lfunthetacost(L0, real_i(gel(vTAU,i)), 0, bitprec); if (N0 < n) N0 = n; if (flag) { GEN A, al, v = mfslashexpansion(mf, F, ZM_inv(U,NULL), N0, 0, &A, prec); gel(vL,i) = van_embedall(v, vE, gN, vgk); al = gel(A,1); if (!gequal0(al)) gel(vb,i) = gexp(gmul(gmul(gmulsg(w,al),PiI2(prec)), tau), prec); } } if (!flag) { van = mfcoefs_i(F, N0, 1); vL = const_vec(lv-1, van_embedall(van, vE, gN, vgk)); } for (i = 1; i < lv; i++) { GEN T; if (gel(vs,i)) continue; T = gpow(gel(vczd,i), gneg(gk), prec); if (flag && gel(vb,i)) T = gmul(T, gel(vb,i)); gel(vs,i) = lfunthetaall(T, gel(vL,i), gel(vTAU,i), bitprec); } return flscal? gel(vs,1): vs; } static long mfistrivial(GEN F) { switch(mf_get_type(F)) { case t_MF_CONST: return lg(gel(F,2)) == 1; case t_MF_LINEAR: case t_MF_LINEAR_BHN: return gequal0(gel(F,3)); default: return 0; } } static long mf_same_k(GEN mf, GEN f) { return gequal(MF_get_gk(mf), mf_get_gk(f)); } static long mf_same_CHI(GEN mf, GEN f) { GEN F1, F2, chi1, chi2, CHI1 = MF_get_CHI(mf), CHI2 = mf_get_CHI(f); /* are the primitive chars attached to CHI1 and CHI2 equal ? */ F1 = znconreyconductor(gel(CHI1,1), gel(CHI1,2), &chi1); if (typ(F1) == t_VEC) F1 = gel(F1,1); F2 = znconreyconductor(gel(CHI2,1), gel(CHI2,2), &chi2); if (typ(F2) == t_VEC) F2 = gel(F2,1); return equalii(F1,F2) && ZV_equal(chi1,chi2); } /* check k and CHI rigorously, but not coefficients nor N */ static long mfisinspace_i(GEN mf, GEN F) { return mfistrivial(F) || (mf_same_k(mf,F) && mf_same_CHI(mf,F)); } static void err_space(GEN F) { pari_err_DOMAIN("mftobasis", "form", "does not belong to", strtoGENstr("space"), F); } static long mfcheapeisen(GEN mf) { long k, L, N = MF_get_N(mf); GEN P; if (N <= 70) return 1; k = itos(gceil(MF_get_gk(mf))); if (odd(k)) k--; switch (k) { case 2: L = 190; break; case 4: L = 162; break; case 6: case 8: L = 88; break; case 10: L = 78; break; default: L = 66; break; } P = gel(myfactoru(N), 1); return P[lg(P)-1] <= L; } static GEN myimag_i(GEN tau) { long tc = typ(tau); if (tc == t_INFINITY || tc == t_INT || tc == t_FRAC) return gen_1; if (tc == t_VEC) { long ltau, i; GEN z = cgetg_copy(tau, <au); for (i=1; i= 0) flnew = 0; return gerepilecopy(av, mfeval_i(mf, F, vtau, flnew, bitprec)); } static long val(GEN v, long bit) { long c, l = lg(v); for (c = 1; c < l; c++) if (gexpo(gel(v,c)) > -bit) return c-1; return -1; } GEN mfcuspval(GEN mf, GEN F, GEN cusp, long bitprec) { pari_sp av = avma; long lvE, w, N, sb, n, A, C, prec = nbits2prec(bitprec); GEN ga, gk, vE; mf = checkMF(mf); if (!checkmf_i(F)) pari_err_TYPE("mfcuspval",F); N = MF_get_N(mf); cusp_canon(cusp, N, &A, &C); gk = mf_get_gk(F); if (typ(gk) != t_INT) { GEN FT = mfmultheta(F), mf2 = obj_checkbuild(mf, MF_MF2INIT, &mf2init); GEN r = mfcuspval(mf2, FT, cusp, bitprec); if ((C & 3L) == 2) { GEN z = sstoQ(1,4); r = gsub(r, typ(r) == t_VEC? const_vec(lg(r)-1, z): z); } return gerepileupto(av, r); } vE = mfgetembed(F, prec); lvE = lg(vE); w = mfcuspcanon_width(N, C); sb = w * mfsturmNk(N, itos(gk)); ga = cusp2mat(A,C); for (n = 8;; n = minss(sb, n << 1)) { GEN R = mfgaexpansion(mf, F, ga, n, prec), res = liftpol_shallow(gel(R,3)); GEN v = cgetg(lvE-1, t_VECSMALL); long j, ok = 1; res = RgC_embedall(res, vE); for (j = 1; j < lvE; j++) { v[j] = val(gel(res,j), bitprec/2); if (v[j] < 0) ok = 0; } if (ok) { res = cgetg(lvE, t_VEC); for (j = 1; j < lvE; j++) gel(res,j) = gadd(gel(R,1), sstoQ(v[j], w)); return gerepilecopy(av, lvE==2? gel(res,1): res); } if (n == sb) return lvE==2? mkoo(): const_vec(lvE-1, mkoo()); /* 0 */ } } long mfiscuspidal(GEN mf, GEN F) { pari_sp av = avma; GEN mf2; if (space_is_cusp(MF_get_space(mf))) return 1; if (typ(mf_get_gk(F)) == t_INT) { GEN v = mftobasis(mf, F, 0); long s = gequal0(vecslice(v, 1, lg(MF_get_E(mf)) - 1)); avma = av; return s; } if (!gequal0(mfak_i(F, 0))) return 0; mf2 = obj_checkbuild(mf, MF_MF2INIT, &mf2init); return mfiscuspidal(mf2, mfmultheta(F)); } /* F = vector of newforms in mftobasis format */ static GEN mffrickeeigen_i(GEN mf, GEN F, GEN vE, long prec) { GEN M, Z, L0, gN = MF_get_gN(mf), gk = MF_get_gk(mf); long N0, i, lM, bit = prec2nbits(prec), k = itou(gk); long LIM = 5; /* Sturm bound is enough */ L0 = mfthetaancreate(NULL, gN, gk); /* only for thetacost */ START: N0 = lfunthetacost(L0, gen_1, LIM, bit); M = mfcoefs_mf(mf, N0, 1); lM = lg(F); Z = cgetg(lM, t_VEC); for (i = 1; i < lM; i++) { /* expansion of D * F[i] */ GEN D, z, van = RgM_RgC_mul(M, Q_remove_denom(gel(F,i), &D)); GEN L = van_embedall(van, gel(vE,i), gN, gk); long l = lg(L), j, bit_add = D? expi(D): 0; gel(Z,i) = z = cgetg(l, t_VEC); for (j = 1; j < l; j++) { GEN v, C, C0; long m, e; for (m = 0; m <= LIM; m++) { v = lfuntheta(gmael(L,j,2), gen_1, m, bit); if (gexpo(v) > bit_add - bit/2) break; } if (m > LIM) { LIM <<= 1; goto START; } C = mulcxpowIs(gdiv(v,conj_i(v)), 2*m - k); C0 = grndtoi(C, &e); if (e < 5-bit_accuracy(precision(C))) C = C0; gel(z,j) = C; } } return Z; } static GEN mffrickeeigen(GEN mf, GEN vE, long prec) { GEN D = obj_check(mf, MF_FRICKE); if (D) { long p = gprecision(D); if (!p || p >= prec) return D; } D = mffrickeeigen_i(mf, MF_get_newforms(mf), vE, prec); return obj_insert(mf, MF_FRICKE, D); } /* integral weight, new space for primitive quadratic character CHIP; * MF = vector of embedded eigenforms coefs on mfbasis, by orbit. * Assume N > Q > 1 and (Q,f(CHIP)) = 1 */ static GEN mfatkineigenquad(GEN mf, GEN CHIP, long Q, GEN MF, long bitprec) { GEN L0, la2, S, F, vP, tau, wtau, Z, va, vb, den, coe, sqrtQ, sqrtN; GEN M, gN, gk = MF_get_gk(mf); long N0, x, yq, i, j, lF, dim, muQ, prec = nbits2prec(bitprec); long N = MF_get_N(mf), k = itos(gk), NQ = N / Q; /* Q coprime to FC */ F = MF_get_newforms(mf); vP = MF_get_fields(mf); lF = lg(F); Z = cgetg(lF, t_VEC); S = MF_get_S(mf); dim = lg(S) - 1; muQ = mymoebiusu(Q); if (muQ) { GEN SQ = cgetg(dim+1,t_VEC), Qk = gpow(stoi(Q), sstoQ(k-2, 2), prec); long i, bit2 = bitprec >> 1; for (j = 1; j <= dim; j++) gel(SQ,j) = mfak_i(gel(S,j), Q); for (i = 1; i < lF; i++) { GEN S = RgV_dotproduct(gel(F,i), SQ), T = gel(vP,i); long e; if (degpol(T) > 1 && typ(S) != t_POLMOD) S = gmodulo(S, T); S = grndtoi(gdiv(conjvec(S, prec), Qk), &e); if (e > -bit2) pari_err_PREC("mfatkineigenquad"); if (muQ == -1) S = gneg(S); gel(Z,i) = S; } return Z; } la2 = mfchareval_i(CHIP, Q); /* 1 or -1 */ (void)cbezout(Q, NQ, &x, &yq); sqrtQ = sqrtr_abs(utor(Q,prec)); tau = mkcomplex(gadd(sstoQ(-1, NQ), ginv(utoi(1000))), divru(sqrtQ, N)); den = gaddgs(gmulsg(NQ, tau), 1); wtau = gdiv(gsub(gmulsg(x, tau), sstoQ(yq, Q)), den); coe = gpowgs(gmul(sqrtQ, den), k); sqrtN = sqrtr_abs(utor(N,prec)); tau = mulcxmI(gmul(tau, sqrtN)); wtau = mulcxmI(gmul(wtau, sqrtN)); gN = utoipos(N); L0 = mfthetaancreate(NULL, gN, gk); /* only for thetacost */ N0 = maxss(lfunthetacost(L0,real_i(tau), 0,bitprec), lfunthetacost(L0,real_i(wtau),0,bitprec)); M = mfcoefs_mf(mf, N0, 1); va = cgetg(dim+1, t_VEC); vb = cgetg(dim+1, t_VEC); for (j = 1; j <= dim; j++) { GEN L, v = vecslice(gel(M,j), 2, N0+1); /* remove a0 */ settyp(v, t_VEC); L = mfthetaancreate(v, gN, gk); gel(va,j) = lfuntheta(L, tau,0,bitprec); gel(vb,j) = lfuntheta(L,wtau,0,bitprec); } for (i = 1; i < lF; i++) { GEN z, FE = gel(MF,i); long l = lg(FE); z = cgetg(l, t_VEC); for (j = 1; j < l; j++) { GEN f = gel(FE,j), a = RgV_dotproduct(va,f), b = RgV_dotproduct(vb,f); GEN la = ground( gdiv(b, gmul(a,coe)) ); if (!gequal(gsqr(la), la2)) pari_err_PREC("mfatkineigenquad"); if (typ(la) == t_INT) { if (j != 1) pari_err_BUG("mfatkineigenquad"); z = const_vec(l-1, la); break; } gel(z,j) = la; } gel(Z,i) = z; } return Z; } static GEN myusqrt(ulong a, long prec) { if (a == 1UL) return gen_1; if (uissquareall(a, &a)) return utoipos(a); return sqrtr_abs(utor(a, prec)); } /* Assume mf is a non-trivial new space, rational primitive character CHIP * and (Q,FC) = 1 */ static GEN mfatkinmatnewquad(GEN mf, GEN CHIP, long Q, long flag, long PREC) { GEN cM, M, D, MF, den, vE, F = MF_get_newforms(mf); long i, c, e, prec, bitprec, lF = lg(F), N = MF_get_N(mf), k = MF_get_k(mf); if (Q == 1) return mkvec4(gen_0, matid(MF_get_dim(mf)), gen_1, mf); den = gel(MF_get_Minv(mf), 2); bitprec = expi(den) + 64; if (!flag) bitprec = maxss(bitprec, prec2nbits(PREC)); START: prec = nbits2prec(bitprec); vE = mfeigenembed(mf, prec); M = cgetg(lF, t_VEC); for (i = 1; i < lF; i++) gel(M,i) = RgC_embedall(gel(F,i), gel(vE,i)); if (Q != N) { D = mfatkineigenquad(mf, CHIP, Q, M, bitprec); c = odd(k)? Q: 1; } else { D = mffrickeeigen(mf, vE, DEFAULTPREC); c = mfcharmodulus(CHIP); if (odd(k)) c = -Q/c; } D = shallowconcat1(D); if (vec_isconst(D)) { MF = diagonal_shallow(D); flag = 0; } else { M = shallowconcat1(M); MF = RgM_mul(matmuldiagonal(M,D), ginv(M)); } if (!flag) return mkvec4(gen_0, MF, gen_1, mf); if (c > 0) cM = myusqrt(c, PREC); else { MF = imag_i(MF); c = -c; cM = mkcomplex(gen_0, myusqrt(c,PREC)); } if (c != 1) MF = RgM_Rg_mul(MF, myusqrt(c,prec)); MF = grndtoi(RgM_Rg_mul(MF,den), &e); if (e > -32) { bitprec <<= 1; goto START; } MF = RgM_Rg_div(MF, den); if (is_rational_t(typ(cM)) && !isint1(cM)) { MF = RgM_Rg_div(MF, cM); cM = gen_1; } return mkvec4(gen_0, MF, cM, mf); } /* let CHI mod N, Q || N, return \bar{CHI_Q} * CHI_{N/Q} */ static GEN mfcharAL(GEN CHI, long Q) { GEN G = gel(CHI,1), c = gel(CHI,2), cycc, d, P, E, F; long l = lg(c), N = mfcharmodulus(CHI), i; if (N == Q) return mfcharconj(CHI); if (N == 1) return CHI; CHI = leafcopy(CHI); gel(CHI,2) = d = leafcopy(c); F = znstar_get_faN(G); P = gel(F,1); E = gel(F,2); cycc = znstar_get_conreycyc(G); if (!odd(Q) && equaliu(gel(P,1), 2) && E[1] >= 3) gel(d,2) = Fp_neg(gel(d,2), gel(cycc,2)); else for (i = 1; i < l; i++) if (!umodui(Q, gel(P,i))) gel(d,i) = Fp_neg(gel(d,i), gel(cycc,i)); return CHI; } static long atkin_get_NQ(long N, long Q, const char *f) { long NQ = N / Q; if (N % Q) pari_err_DOMAIN(f,"N % Q","!=",gen_0,utoi(Q)); if (ugcd(NQ, Q) > 1) pari_err_DOMAIN(f,"gcd(Q,N/Q)","!=",gen_1,utoi(Q)); return NQ; } /* transform mf to new_NEW if possible */ static GEN MF_set_new(GEN mf) { GEN vMjd, vj, gk = MF_get_gk(mf); long l, j; if (MF_get_space(mf) != mf_CUSP || typ(gk) != t_INT || itou(gk) == 1) return mf; vMjd = MFcusp_get_vMjd(mf); l = lg(vMjd); if (l > 1 && gel(vMjd,1)[1] != MF_get_N(mf)) return mf; /* oldspace != 0 */ mf = shallowcopy(mf); gel(mf,1) = shallowcopy(gel(mf,1)); MF_set_space(mf, mf_NEW); vj = cgetg(l, t_VECSMALL); for (j = 1; j < l; j++) vj[j] = gel(vMjd, j)[2]; gel(mf,4) = vj; return mf; } /* if flag = 1, rationalize, else don't */ static GEN mfatkininit_i(GEN mf, long Q, long flag, long prec) { GEN M, B, C, CHI, CHIAL, G, chi, P, z, g, mfB, s, Mindex, Minv; long j, l, lim, ord, FC, NQ, cQ, nk, dk, N = MF_get_N(mf); B = MF_get_basis(mf); l = lg(B); M = cgetg(l, t_MAT); if (l == 1) return mkvec4(gen_0,M,gen_1,mf); Qtoss(MF_get_gk(mf), &nk,&dk); Q = labs(Q); NQ = atkin_get_NQ(N, Q, "mfatkininit"); CHI = MF_get_CHI(mf); CHI = mfchartoprimitive(CHI, &FC); ord = mfcharorder_canon(CHI); mf = MF_set_new(mf); if (MF_get_space(mf) == mf_NEW && ord == 1 && NQ % FC == 0 && dk == 1) return mfatkinmatnewquad(mf, CHI, Q, flag, prec); /* now flag != 0 */ G = gel(CHI,1); chi = gel(CHI,2); if (Q == N) { g = mkmat22s(0, -1, N, 0); cQ = NQ; } /* Fricke */ else { GEN F, gQP = utoi(ugcd(Q, FC)); long t, v; chi = znchardecompose(G, chi, gQP); F = znconreyconductor(G, chi, &chi); G = znstar0(F,1); (void)cbezout(Q, NQ, &t, &v); g = mkmat22s(Q*t, 1, -N*v, Q); cQ = -NQ*v; } C = s = gen_1; /* N.B. G,chi are G_Q,chi_Q [primitive] at this point */ if (lg(chi) != 1) C = ginv( znchargauss(G, chi, gen_1, prec2nbits(prec)) ); if (dk == 1) { if (odd(nk)) s = myusqrt(Q,prec); } else { long r = nk >> 1; /* k-1/2 */ s = gpow(utoipos(Q), mkfracss(odd(r)? 1: 3, 4), prec); if (odd(cQ)) { long t = r + ((cQ-1) >> 1); s = mkcomplex(s, odd(t)? gneg(s): s); } } if (!isint1(s)) C = gmul(C, s); CHIAL = mfcharAL(CHI, Q); if (dk == 2) CHIAL = mfcharmul(CHIAL, induce(gel(CHIAL,1), utoipos(odd(Q) ? Q<<2 : Q))); CHIAL = mfchartoprimitive(CHIAL,NULL); mfB = gequal(CHIAL,CHI)? mf: mfinit_Nndkchi(N,nk,dk,CHIAL,MF_get_space(mf),0); Mindex = MF_get_Mindex(mfB); Minv = MF_get_Minv(mfB); P = z = NULL; if (ord != 1) { P = mfcharpol(CHI); z = rootsof1u_cx(ord, prec); } lim = maxss(mfsturm(mfB), mfsturm(mf)) + 1; for (j = 1; j < l; j++) { GEN v = mfslashexpansion(mf, gel(B,j), g, lim, 0, NULL, prec+1); long junk; if (!isint1(C)) v = RgV_Rg_mul(v, C); v = bestapprnf(v, P, z, prec); v = vecpermute_partial(v, Mindex, &junk); v = Minv_RgC_mul(Minv, v); /* cf mftobasis_i */ gel(M, j) = v; } if (is_rational_t(typ(C)) && !gequal1(C)) { M = gdiv(M, C); C = gen_1; } if (mfB == mf) mfB = gen_0; return mkvec4(mfB, M, C, mf); } GEN mfatkininit(GEN mf, long Q, long prec) { pari_sp av = avma; mf = checkMF(mf); return gerepilecopy(av, mfatkininit_i(mf, Q, 1, prec)); } static void checkmfa(GEN z) { if (typ(z) != t_VEC || lg(z) != 5 || typ(gel(z,2)) != t_MAT || !checkMF_i(gel(z,4)) || (!isintzero(gel(z,1)) && !checkMF_i(gel(z,1)))) pari_err_TYPE("mfatkin [please apply mfatkininit()]",z); } /* Apply atkin Q to closure F */ GEN mfatkin(GEN mfa, GEN F) { pari_sp av = avma; GEN z, mfB, MQ, mf; checkmfa(mfa); mfB= gel(mfa,1); MQ = gel(mfa,2); mf = gel(mfa,4); if (typ(mfB) == t_INT) mfB = mf; z = RgM_RgC_mul(MQ, mftobasis_i(mf,F)); return gerepileupto(av, mflinear(mfB, z)); } GEN mfatkineigenvalues(GEN mf, long Q, long prec) { pari_sp av = avma; GEN vF, L, CHI, M, mfatk, C, MQ, vE, mfB; long N, NQ, l, i; mf = checkMF(mf); N = MF_get_N(mf); vF = MF_get_newforms(mf); l = lg(vF); /* N.B. k is integral */ if (l == 1) { avma = av; return cgetg(1, t_VEC); } L = cgetg(l, t_VEC); if (Q == 1) { GEN vP = MF_get_fields(mf); for (i = 1; i < l; i++) gel(L,i) = const_vec(degpol(gel(vP,i)), gen_1); return L; } vE = mfeigenembed(mf,prec); if (Q == N) return gerepileupto(av, mffrickeeigen(mf, vE, prec)); Q = labs(Q); NQ = atkin_get_NQ(N, Q, "mfatkineigenvalues"); /* != 1 */ mfatk = mfatkininit(mf, Q, prec); mfB= gel(mfatk,1); if (typ(mfB) != t_VEC) mfB = mf; MQ = gel(mfatk,2); C = gel(mfatk,3); M = row(mfcoefs_mf(mfB,1,1), 2); /* vec of a_1(b_i) for mfbasis functions */ for (i = 1; i < l; i++) { GEN c = RgV_dotproduct(RgM_RgC_mul(MQ,gel(vF,i)), M); /* C * eigen_i */ gel(L,i) = Rg_embedall_i(c, gel(vE,i)); } if (!gequal1(C)) L = gdiv(L, C); CHI = MF_get_CHI(mf); if (mfcharorder(CHI) <= 2 && NQ % mfcharconductor(CHI) == 0) L = ground(L); return gerepilecopy(av, L); } /* expand B_d V, keeping same length */ static GEN bdexpand(GEN V, long d) { GEN W; long N, n; if (d == 1) return V; N = lg(V)-1; W = zerovec(N); for (n = 0; n <= (N-1)/d; n++) gel(W, n*d+1) = gel(V, n+1); return W; } /* expand B_d V, increasing length up to lim */ static GEN bdexpandall(GEN V, long d, long lim) { GEN W; long N, n; if (d == 1) return V; N = lg(V)-1; W = zerovec(lim); for (n = 0; n <= N-1 && n*d <= lim; n++) gel(W, n*d+1) = gel(V, n+1); return W; } static void parse_vecj(GEN T, GEN *E1, GEN *E2) { if (lg(T)==3) { *E1 = gel(T,1); *E2 = gel(T,2); } else { *E1 = T; *E2 = NULL; } } /* g in M_2(Z) ? */ static int check_M2Z(GEN g) { return typ(g) == t_MAT && lg(g) == 3 && lgcols(g) == 3 && RgM_is_ZM(g); } /* g in SL_2(Z) ? */ static int check_SL2Z(GEN g) { return check_M2Z(g) && equali1(ZM_det(g)); } static GEN mfcharcxeval(GEN CHI, long n, long prec) { GEN ordg; ulong ord; if (ugcd(mfcharmodulus(CHI), labs(n)) > 1) return gen_0; ordg = gmfcharorder(CHI); ord = itou(ordg); return rootsof1q_cx(znchareval_i(CHI,n,ordg), ord, prec); } static GEN RgV_shift(GEN V, GEN gn) { long i, n, l; GEN W; if (typ(gn) != t_INT) pari_err_BUG("RgV_shift [n not integral]"); n = itos(gn); if (n < 0) pari_err_BUG("RgV_shift [n negative]"); if (!n) return V; W = cgetg_copy(V, &l); if (n > l-1) n = l-1; for (i=1; i <= n; i++) gel(W,i) = gen_0; for ( ; i < l; i++) gel(W,i) = gel(V, i-n); return W; } static GEN hash_eisengacx(hashtable *H, void *E, long w, GEN ga, long n, long prec) { ulong h = H->hash(E); hashentry *e = hash_search2(H, E, h); GEN v; if (e) v = (GEN)e->val; else { v = mfeisensteingacx((GEN)E, w, ga, n, prec); hash_insert2(H, E, (void*)v, h); } return v; } static GEN vecj_expand(GEN B, hashtable *H, long w, GEN ga, long n, long prec) { GEN E1, E2, v; parse_vecj(B, &E1, &E2); v = hash_eisengacx(H, (void*)E1, w, ga, n, prec); if (E2) { GEN u = hash_eisengacx(H, (void*)E2, w, ga, n, prec); GEN a = gadd(gel(v,1), gel(u,1)); GEN b = RgV_mul_RgXn(gel(v,2), gel(u,2)); v = mkvec2(a,b); } return v; } static GEN shift_M(GEN M, GEN Valpha, long w) { long i, l = lg(Valpha); GEN almin = vecmin(Valpha); for (i = 1; i < l; i++) { GEN alpha = gel(Valpha, i), gsh = gmulsg(w, gsub(alpha,almin)); gel(M,i) = RgV_shift(gel(M,i), gsh); } return almin; } static GEN mfeisensteinspaceinit(GEN NK); #if 0 /* ga in M_2^+(Z)), n >= 0 */ static GEN mfgaexpansion_init(GEN mf, GEN ga, long n, long prec) { GEN M, Mvecj, vecj, almin, Valpha; long i, w, l, N = MF_get_N(mf), c = itos(gcoeff(ga,2,1)); hashtable *H; if (c % N == 0) { /* ga in G_0(N), trivial case; w = 1 */ GEN chid = mfcharcxeval(MF_get_CHI(mf), itos(gcoeff(ga,2,2)), prec); return mkvec2(chid, utoi(n)); } Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit); if (lg(Mvecj) < 5) pari_err_IMPL("mfgaexpansion_init in this case"); w = mfcuspcanon_width(N, c); vecj = gel(Mvecj, 3); l = lg(vecj); M = cgetg(l, t_VEC); Valpha = cgetg(l, t_VEC); H = hash_create(l, (ulong(*)(void*))&hash_GEN, (int(*)(void*,void*))&gidentical, 1); for (i = 1; i < l; i++) { GEN v = vecj_expand(gel(vecj,i), H, w, ga, n, prec); gel(Valpha,i) = gel(v,1); gel(M,i) = gel(v,2); } almin = shift_M(M, Valpha, w); return mkvec3(almin, utoi(w), M); } /* half-integer weight not supported; vF = [F,eisendec(F)]. * Minit = mfgaexpansion_init(mf, ga, n, prec) */ static GEN mfgaexpansion_with_init(GEN Minit, GEN vF) { GEN v; if (lg(Minit) == 3) { /* ga in G_0(N) */ GEN chid = gel(Minit,1), gn = gel(Minit,2); v = mfcoefs_i(gel(vF,1), itou(gn), 1); v = mkvec3(gen_0, gen_1, RgV_Rg_mul(v,chid)); } else { GEN V = RgM_RgC_mul(gel(Minit,3), gel(vF,2)); v = mkvec3(gel(Minit,1), gel(Minit,2), V); } return v; } #endif /* B = mfeisensteindec(F) already embedded, ga in M_2^+(Z)), n >= 0 */ static GEN mfgaexpansion_i(GEN mf, GEN B0, GEN ga, long n, long prec) { GEN M, Mvecj, vecj, almin, Valpha, B, E = NULL; long i, j, w, nw, l, N = MF_get_N(mf), bit = prec2nbits(prec) / 2; hashtable *H; Mvecj = obj_check(mf, MF_EISENSPACE); if (lg(Mvecj) < 5) { E = gel(Mvecj, 2); Mvecj = gel(Mvecj, 1); } vecj = gel(Mvecj, 3); l = lg(vecj); B = cgetg(l, t_COL); M = cgetg(l, t_VEC); Valpha = cgetg(l, t_VEC); w = mfZC_width(N, gel(ga,1)); nw = E ? n + w : n; H = hash_create(l, (ulong(*)(void*))&hash_GEN, (int(*)(void*,void*))&gidentical, 1); for (i = j = 1; i < l; i++) { GEN v; if (gequal0(gel(B0,i))) continue; v = vecj_expand(gel(vecj,i), H, w, ga, nw, prec); gel(B,j) = gel(B0,i); gel(Valpha,j) = gel(v,1); gel(M,j) = gel(v,2); j++; } setlg(Valpha, j); setlg(B, j); setlg(M, j); l = j; if (l == 1) return mkvec3(gen_0, utoi(w), zerovec(n+1)); almin = shift_M(M, Valpha, w); B = RgM_RgC_mul(M, B); l = lg(B); for (i = 1; i < l; i++) if (gexpo(gel(B,i)) < -bit) gel(B,i) = gen_0; settyp(B, t_VEC); if (E) { GEN v = hash_eisengacx(H, (void*)E, w, ga, n, prec); long ell = 0; almin = gsub(almin, gel(v,1)); if (gsigne(almin) < 0) { GEN gell = gceil(gmulsg(-w, almin)); ell = itos(gell); almin = gadd(almin, gdivgs(gell, w)); if (nw < ell) pari_err_IMPL("alpha < 0 in mfgaexpansion"); } B = vecslice(B, ell + 1, n + ell + 1); B = RgV_div_RgXn(B, gel(v,2)); } return mkvec3(almin, utoi(w), B); } /* Theta multiplier: assume 4 | C, (C,D)=1 */ static GEN mfthetamultiplier(long C, long D) { long s = kross(C, D); if ((D&3L) == 1) return stoi(s); return s > 0 ? powIs(3) : gen_I(); } static GEN mfthetaexpansion(GEN M, long n) { GEN s, al, sla, V = zerovec(n + 1); long w, lim, la, f, C = itos(gcoeff(M, 2, 1)), D = itos(gcoeff(M, 2, 2)); switch (C & 3L) { case 0: al = gen_0; w = 1; s = mfthetamultiplier(C,D); lim = usqrt(n); gel(V, 1) = s; s = gmul2n(s, 1); for (f = 1; f <= lim; f++) gel(V, f*f + 1) = s; break; case 2: al = sstoQ(1,4); w = 1; s = gmul2n(mfthetamultiplier(C - 2*D, D), 1); lim = (usqrt(n << 2) - 1) >> 1; for (f = 0; f <= lim; f++) gel(V, f*(f+1) + 1) = s; break; default: al = gen_0; w = 4; la = (-D*C) & 3L; s = mfthetamultiplier(-(D + la*C), C); s = gsub(s, mulcxI(s)); sla = gmul(s, powIs(-la)); lim = usqrt(n); gel(V, 1) = gmul2n(s, -1); for (f = 1; f <= lim; f++) gel(V, f*f + 1) = odd(f) ? sla : s; break; } return mkvec3(al, stoi(w), V); } /* F 1/2 integral weight */ static GEN mf2gaexpansion(GEN mf2, GEN F, GEN ga, long n, long prec) { GEN FT = mfmultheta(F), mf = obj_checkbuild(mf2, MF_MF2INIT, &mf2init); GEN res, V1, Tres, V2, al, V, gsh; long w2, C = itos(gcoeff(ga,2,1)), w = mfcuspcanon_width(MF_get_N(mf), C); long ext = ((C & 3L) != 2)? 0: (w+3) >> 2; long prec2 = prec + nbits2extraprec((long)M_PI/(2*M_LN2)*sqrt(n + ext)); res = mfgaexpansion(mf, FT, ga, n + ext, prec2); Tres = mfthetaexpansion(ga, n + ext); V1 = gel(res,3); V2 = gel(Tres,3); al = gsub(gel(res,1), gel(Tres,1)); w2 = itos(gel(Tres,2)); if (w != itos(gel(res,2)) || w % w2) pari_err_BUG("mf2gaexpansion [incorrect w2 or w]"); if (w2 != w) V2 = bdexpand(V2, w/w2); V = RgV_div_RgXn(V1, V2); gsh = gfloor(gmulsg(w, al)); if (!gequal0(gsh)) { al = gsub(al, gdivgs(gsh, w)); if (gsigne(gsh) > 0) { V = RgV_shift(V, gsh); V = vecslice(V, 1, n + 1); } else { long sh = -itos(gsh), i; if (sh > ext) pari_err_BUG("mf2gaexpansion [incorrect sh]"); for (i = 1; i <= sh; i++) if (!gequal0(gel(V,i))) pari_err_BUG("mf2gaexpansion [sh too large]"); V = vecslice(V, sh+1, n + sh+1); } } obj_free(mf); return mkvec3(al, stoi(w), gprec_wtrunc(V, prec)); } static GEN mfgaexpansionatkin(GEN mf, GEN F, GEN C, GEN D, long Q, long n, long prec) { GEN mfa = mfatkininit_i(mf, Q, 0, prec), MQ = gel(mfa,2); long i, FC, k = MF_get_k(mf); GEN x, v, V, z, s, CHI = mfchartoprimitive(MF_get_CHI(mf), &FC); /* V = mfcoefs(F | w_Q, n), can't use mfatkin because MQ non-rational */ V = RgM_RgC_mul(mfcoefs_mf(mf,n,1), RgM_RgC_mul(MQ, mftobasis_i(mf,F))); (void)bezout(utoipos(Q), C, &x, &v); s = mfchareval_i(CHI, (umodiu(x, FC) * umodiu(D, FC)) % FC); s = gdiv(s, gpow(utoipos(Q), sstoQ(k,2), prec)); V = RgV_Rg_mul(V, s); z = rootsof1powinit(umodiu(D,Q)*umodiu(v,Q) % Q, Q, prec); for (i = 1; i <= n+1; i++) gel(V,i) = gmul(gel(V,i), rootsof1pow(z, i-1)); return mkvec3(gen_0, utoipos(Q), V); } /* allow F of the form [F, mf_eisendec(F)]~ */ static GEN mfgaexpansion(GEN mf, GEN F, GEN ga, long n, long prec) { GEN v, EF = NULL, res, Mvecj, c, d; long precnew, N; if (n < 0) pari_err_DOMAIN("mfgaexpansion", "n", "<", gen_0, stoi(n)); if (typ(F) == t_COL && lg(F) == 3) { EF = gel(F,2); F = gel(F,1); } if (!checkmf_i(F)) pari_err_TYPE("mfgaexpansion", F); if (!check_SL2Z(ga)) pari_err_TYPE("mfgaexpansion",ga); if (typ(mf_get_gk(F)) != t_INT) return mf2gaexpansion(mf, F, ga, n, prec); c = gcoeff(ga,2,1); d = gcoeff(ga,2,2); N = MF_get_N(mf); if (!umodiu(c, mf_get_N(F))) { /* trivial case: ga in Gamma_0(N) */ long w = mfcuspcanon_width(N, umodiu(c,N)); GEN CHI = mf_get_CHI(F); GEN chid = mfcharcxeval(CHI, umodiu(d,mfcharmodulus(CHI)), prec); v = mfcoefs_i(F, n/w, 1); if (!isint1(chid)) v = RgV_Rg_mul(v,chid); return mkvec3(gen_0, stoi(w), bdexpandall(v,w,n+1)); } mf = MF_set_new(mf); if (MF_get_space(mf) == mf_NEW) { long cN = umodiu(c,N), g = ugcd(cN,N), Q = N/g; GEN CHI = MF_get_CHI(mf); if (ugcd(cN, Q)==1 && mfcharorder(CHI) <= 2 && g % mfcharconductor(CHI) == 0 && degpol(mf_get_field(F)) == 1) return mfgaexpansionatkin(mf, F, c, d, Q, n, prec); } Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit); precnew = prec; if (lg(Mvecj) < 5) { long e, w = mfZC_width(N, gel(ga,1)); GEN v, E = gel(Mvecj,2); v = mfeisensteingacx(E, w, ga, n, LOWDEFAULTPREC); v = gel(v,2); e = gexpo(RgXn_inv(RgV_to_RgX(v,0), n+1)); if (e > 0) precnew += nbits2extraprec(e); } if (!EF) EF = mf_eisendec(mf, F, precnew); res = mfgaexpansion_i(mf, EF, ga, n, precnew); return precnew == prec ? res : gprec_wtrunc(res, prec); } /* parity = -1 or +1 */ static GEN findd(long N, long parity) { GEN L, D = mydivisorsu(N); long i, j, l = lg(D); L = cgetg(l, t_VEC); for (i = j = 1; i < l; i++) { long d = D[i]; if (parity == -1) d = -d; if (sisfundamental(d)) gel(L,j++) = stoi(d); } setlg(L,j); return L; } /* does ND contain a divisor of N ? */ static int seenD(long N, GEN ND) { long j, l = lg(ND); for (j = 1; j < l; j++) if (N % ND[j] == 0) return 1; return 0; } static GEN search_levels(GEN vN, const char *f) { switch(typ(vN)) { case t_INT: vN = mkvecsmall(itos(vN)); break; case t_VEC: case t_COL: vN = ZV_to_zv(vN); break; case t_VECSMALL: vN = leafcopy(vN); break; default: pari_err_TYPE(f, vN); } vecsmall_sort(vN); return vN; } GEN mfsearch(GEN NK, GEN V, long space) { pari_sp av = avma; GEN F, gk, NbyD, vN; long n, nk, dk, parity, nV, i, lvN; if (typ(NK) != t_VEC || lg(NK) != 3) pari_err_TYPE("mfsearch", NK); gk = gel(NK,2); if (typ(gmul2n(gk, 1)) != t_INT) pari_err_TYPE("mfsearch [k]", gk); switch(typ(V)) { case t_VEC: V = shallowtrans(V); case t_COL: break; default: pari_err_TYPE("mfsearch [V]", V); } vN = search_levels(gel(NK,1), "mfsearch [N]"); lvN = lg(vN); Qtoss(gk, &nk,&dk); parity = (dk == 1 && odd(nk)) ? -1 : 1; nV = lg(V)-2; F = cgetg(1, t_VEC); NbyD = const_vec(vN[lvN-1], cgetg(1,t_VECSMALL)); for (n = 1; n < lvN; n++) { long N = vN[n]; GEN L; if (N <= 0 || (dk == 2 && (N & 3))) continue; L = findd(N, parity); for (i = 1; i < lg(L); i++) { GEN mf, M, CO, gD = gel(L,i); GEN *ND = (GEN*)NbyD + itou(gD); /* points to NbyD[|D|] */ if (seenD(N, *ND)) continue; mf = mfinit_Nndkchi(N, nk, dk, get_mfchar(gD), space, 1); M = mfcoefs_mf(mf, nV, 1); CO = inverseimage(M, V); if (lg(CO) == 1) continue; F = vec_append(F, mflinear(mf,CO)); *ND = vecsmall_append(*ND, N); /* add to NbyD[|D|] */ } } return gerepilecopy(av, F); } static GEN search_from_split(GEN mf, GEN vap, GEN vlp) { pari_sp av = avma; long lvlp = lg(vlp), j, jv, l1; GEN v, NK, S1, S, M = NULL; S1 = gel(split_i(mf, 1, 0), 1); /* rational newforms */ l1 = lg(S1); if (l1 == 1) { avma = av; return NULL; } v = cgetg(l1, t_VEC); S = MF_get_S(mf); NK = mf_get_NK(gel(S,1)); if (lvlp > 1) M = rowpermute(mfcoefs_mf(mf, vlp[lvlp-1], 1), vlp); for (j = jv = 1; j < l1; j++) { GEN vF = gel(S1,j); long t; for (t = lvlp-1; t > 0; t--) { /* lhs = vlp[j]-th coefficient of eigenform */ GEN rhs = gel(vap,t), lhs = RgMrow_RgC_mul(M, vF, t); if (!gequal(lhs, rhs)) break; } if (!t) gel(v,jv++) = mflinear_i(NK,S,vF); } if (jv == 1) { avma = av; return NULL; } setlg(v,jv); return v; } GEN mfeigensearch(GEN NK, GEN AP) { pari_sp av = avma; GEN k, vN, vap, vlp, vres = cgetg(1, t_VEC), D; long n, lvN, i, l, even; if (!AP) l = 1; else { l = lg(AP); if (typ(AP) != t_VEC) pari_err_TYPE("mfeigensearch",AP); } vap = cgetg(l, t_VEC); vlp = cgetg(l, t_VECSMALL); if (l > 1) { GEN perm = indexvecsort(AP, mkvecsmall(1)); for (i = 1; i < l; i++) { GEN v = gel(AP,perm[i]), gp, ap; if (typ(v) != t_VEC || lg(v) != 3) pari_err_TYPE("mfeigensearch", AP); gp = gel(v,1); ap = gel(v,2); if (typ(gp) != t_INT || (typ(ap) != t_INT && typ(ap) != t_INTMOD)) pari_err_TYPE("mfeigensearch", AP); gel(vap,i) = ap; vlp[i] = itos(gp)+1; if (vlp[i] < 0) pari_err_TYPE("mfeigensearch", AP); } } l = lg(NK); if (typ(NK) != t_VEC || l != 3) pari_err_TYPE("mfeigensearch",NK); k = gel(NK,2); vN = search_levels(gel(NK,1), "mfeigensearch [N]"); lvN = lg(vN); vecsmall_sort(vlp); even = !mpodd(k); for (n = 1; n < lvN; n++) { pari_sp av2 = avma; GEN mf, L; long N = vN[n]; if (even) D = gen_1; else { long r = (N&3L); if (r == 1 || r == 2) continue; D = stoi( corediscs(-N, NULL) ); /* < 0 */ } mf = mfinit_i(mkvec3(utoipos(N), k, D), mf_NEW); L = search_from_split(mf, vap, vlp); if (L) vres = shallowconcat(vres, L); else avma = av2; } return gerepilecopy(av, vres); } /* tf_{N,k}(n) */ static GEN mfnewtracecache(long N, long k, long n, cachenew_t *cache) { GEN C = NULL, S; long lcache; if (!n) return gen_0; S = gel(cache->vnew,N); lcache = lg(S); if (n < lcache) C = gel(S, n); if (C) cache->newHIT++; else C = mfnewtrace_i(N,k,n,cache); cache->newTOTAL++; if (n < lcache) gel(S,n) = C; return C; } static long mfdim_Nkchi(long N, long k, GEN CHI, long space) { if (k < 0 || badchar(N,k,CHI)) return 0; if (k == 0) return mfcharistrivial(CHI) && !space_is_cusp(space)? 1: 0; switch(space) { case mf_NEW: return mfnewdim(N,k,CHI); case mf_CUSP:return mfcuspdim(N,k,CHI); case mf_OLD: return mfolddim(N,k,CHI); case mf_FULL:return mffulldim(N,k,CHI); case mf_EISEN: return mfeisensteindim(N,k,CHI); default: pari_err_FLAG("mfdim"); } return 0;/*LCOV_EXCL_LINE*/ } static long mfwt1dimsum(long N, long space) { switch(space) { case mf_NEW: return mfwt1newdimsum(N); case mf_CUSP: return mfwt1cuspdimsum(N); case mf_OLD: return mfwt1olddimsum(N); } pari_err_FLAG("mfdim"); return 0; /*LCOV_EXCL_LINE*/ } /* mfdim for k = nk/dk */ static long mfdim_Nndkchi(long N, long nk, long dk, GEN CHI, long space) { return (dk == 2)? mf2dim_Nkchi(N, nk >> 1, CHI, space) : mfdim_Nkchi(N, nk, CHI, space); } /* FIXME: use direct dim Gamma1(N) formula, don't compute individual spaces */ static long mfwtkdimsum(long N, long k, long dk, long space) { GEN w = mfchars(N, k, dk, NULL); long i, j, D = 0, l = lg(w); for (i = j = 1; i < l; i++) { GEN CHI = gel(w,i); long d = mfdim_Nndkchi(N,k,dk,CHI,space); if (d) D += d * myeulerphiu(mfcharorder(CHI)); } return D; } static GEN mfwt1dims(long N, GEN vCHI, long space) { GEN D = NULL; switch(space) { case mf_NEW: D = mfwt1newdimall(N, vCHI); break; case mf_CUSP:D = mfwt1cuspdimall(N, vCHI); break; case mf_OLD: D = mfwt1olddimall(N, vCHI); break; default: pari_err_FLAG("mfdim"); } return D; } static GEN mfwtkdims(long N, long k, long dk, GEN vCHI, long space) { GEN D, w = mfchars(N, k, dk, vCHI); long i, j, l = lg(w); D = cgetg(l, t_VEC); for (i = j = 1; i < l; i++) { GEN CHI = gel(w,i); long d = mfdim_Nndkchi(N,k,dk,CHI,space); if (vCHI) gel(D, j++) = mkvec2s(d, 0); else if (d) gel(D, j++) = fmt_dim(CHI, d, 0); } setlg(D,j); return D; } GEN mfdim(GEN NK, long space) { pari_sp av = avma; long N, k, dk, joker; GEN CHI, mf; if ((mf = checkMF_i(NK))) return utoi(MF_get_dim(mf)); checkNK2(NK, &N, &k, &dk, &CHI, 2); if (!CHI) joker = 1; else switch(typ(CHI)) { case t_INT: joker = 2; break; case t_COL: joker = 3; break; default: joker = 0; break; } if (joker) { long d; GEN D; if (k < 0) switch(joker) { case 1: return cgetg(1,t_VEC); case 2: return gen_0; case 3: return mfdim0all(CHI); } if (k == 0) { if (space_is_cusp(space)) switch(joker) { case 1: return cgetg(1,t_VEC); case 2: return gen_0; case 3: return mfdim0all(CHI); } switch(joker) { long i, l; case 1: retmkvec(fmt_dim(mfchartrivial(),0,0)); case 2: return gen_1; case 3: l = lg(CHI); D = cgetg(l,t_VEC); for (i = 1; i < l; i++) { long t = mfcharistrivial(gel(CHI,i)); gel(D,i) = mkvec2(t? gen_1: gen_0, gen_0); } return D; } } if (dk == 1 && k == 1 && space != mf_EISEN) { long fix = 0, space0 = space; if (space == mf_FULL) space = mf_CUSP; /* remove Eisenstein part */ if (joker == 2) { d = mfwt1dimsum(N, space); if (space0 == mf_FULL) d += mfwtkdimsum(N,k,dk,mf_EISEN);/*add it back*/ avma = av; return utoi(d); } /* must initialize explicitly: trivial spaces for E_k/S_k differ */ if (space0 == mf_FULL) { if (!CHI) fix = 1; /* must remove 0 spaces */ CHI = mfchars(N, k, dk, CHI); } D = mfwt1dims(N, CHI, space); if (space0 == mf_FULL) { GEN D2 = mfwtkdims(N, k, dk, CHI, mf_EISEN); D = merge_dims(D, D2, fix? CHI: NULL); } } else { if (joker==2) { d = mfwtkdimsum(N,k,dk,space); avma=av; return utoi(d); } D = mfwtkdims(N, k, dk, CHI, space); } if (!CHI) return gerepileupto(av, vecsort(D, mkvecsmall(1))); return gerepilecopy(av, D); } return utoi( mfdim_Nndkchi(N, k, dk, CHI, space) ); } GEN mfbasis(GEN NK, long space) { pari_sp av = avma; long N, k, dk; GEN mf, CHI; if ((mf = checkMF_i(NK))) return concat(gel(mf,2), gel(mf,3)); checkNK2(NK, &N, &k, &dk, &CHI, 0); if (dk == 2) return gerepilecopy(av, mf2basis(N, k>>1, CHI, space)); mf = mfinit_Nkchi(N, k, CHI, space, 1); return gerepilecopy(av, MF_get_basis(mf)); } static GEN deg1ser_shallow(GEN a1, GEN a0, long v, long e) { return RgX_to_ser(deg1pol_shallow(a1, a0, v), e+2); } /* r / x + O(1) */ static GEN simple_pole(GEN r) { GEN S = deg1ser_shallow(gen_0, r, 0, 1); setvalp(S, -1); return S; } /* F form, E embedding; mfa = mfatkininit or root number (eigenform case) */ static GEN mflfuncreate(GEN mfa, GEN F, GEN E, GEN N, GEN gk) { GEN LF = cgetg(8,t_VEC), polar = cgetg(1,t_COL), eps; long k = itou(gk); gel(LF,1) = lfuntag(t_LFUN_MFCLOS, mkvec3(F,E,gen_1)); if (typ(mfa) != t_VEC) eps = mfa; /* cuspidal eigenform: root number; no poles */ else { /* mfatkininit */ GEN a0, b0, vF, vG, G = NULL, M = gdiv(gel(mfa,2), gel(mfa,3)), mf = gel(mfa,4); vF = mftobasis_i(mf, F); vG = RgM_RgC_mul(M, vF); if (gequal(vF,vG)) eps = gen_1; else if (gequal(vF,gneg(vG))) eps = gen_m1; else { /* not self-dual */ eps = NULL; G = mfatkin(mfa, F); gel(LF,2) = lfuntag(t_LFUN_MFCLOS, mkvec3(G,E,ginv(gel(mfa,3)))); gel(LF,6) = powIs(k); } /* polar part */ a0 = mfcoef(F,0); b0 = eps? gmul(eps,a0): mfcoef(G,0); if (!gequal0(b0)) { b0 = mulcxpowIs(gmul2n(b0,1), k); polar = vec_append(polar, mkvec2(gk, simple_pole(b0))); } if (!gequal0(a0)) { a0 = gneg(gmul2n(a0,1)); polar = vec_append(polar, mkvec2(gen_0, simple_pole(a0))); } } if (eps) /* self-dual */ { gel(LF,2) = mfcharorder(mf_get_CHI(F)) <= 2? gen_0: gen_1; gel(LF,6) = mulcxpowIs(eps,k); } gel(LF,3) = mkvec2(gen_0, gen_1); gel(LF,4) = gk; gel(LF,5) = N; if (lg(polar) == 1) setlg(LF,7); else gel(LF,7) = polar; return LF; } static GEN mflfuncreateall(long sd, GEN mfa, GEN F, GEN vE, GEN gN, GEN gk) { long i, l = lg(vE); GEN L = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(L,i) = mflfuncreate(sd? gel(mfa,i): mfa, F, gel(vE,i), gN, gk); return L; } GEN lfunmf(GEN mf, GEN F, long bitprec) { pari_sp av = avma; long i, l, prec = nbits2prec(bitprec); GEN L, gk, gN; mf = checkMF(mf); gk = MF_get_gk(mf); gN = MF_get_gN(mf); if (typ(gk)!=t_INT) pari_err_IMPL("half-integral weight"); if (F) { GEN v; long s = MF_get_space(mf); if (!checkmf_i(F)) pari_err_TYPE("lfunmf", F); if (!mfisinspace_i(mf, F)) err_space(F); L = NULL; if ((s == mf_NEW || s == mf_CUSP || s == mf_FULL) && gequal(mfcoefs_i(F,1,1), mkvec2(gen_0,gen_1))) { /* check if eigenform */ GEN vP, vF, b = mftobasis_i(mf, F); long lF, d = degpol(mf_get_field(F)); v = mfsplit(mf, d, 0); vF = gel(v,1); vP = gel(v,2); lF = lg(vF); for (i = 1; i < lF; i++) if (degpol(gel(vP,i)) == d && gequal(gel(vF,i), b)) { GEN vE = mfgetembed(F, prec); GEN Z = mffrickeeigen_i(mf, mkvec(b), mkvec(vE), prec); L = mflfuncreateall(1, gel(Z,1), F, vE, gN, gk); break; } } if (!L) { /* not an eigenform: costly general case */ GEN mfa = mfatkininit_i(mf, itou(gN), 1, prec); L = mflfuncreateall(0,mfa, F, mfgetembed(F,prec), gN, gk); } if (lg(L) == 2) L = gel(L,1); } else { GEN M = mfeigenbasis(mf), vE = mfeigenembed(mf, prec); GEN v = mffrickeeigen(mf, vE, prec); l = lg(vE); L = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(L,i) = mflfuncreateall(1,gel(v,i), gel(M,i), gel(vE,i), gN, gk); } return gerepilecopy(av, L); } GEN mffromell(GEN E) { pari_sp av = avma; GEN mf, F, z, v, S; long N, i, l; checkell(E); if (ell_get_type(E) != t_ELL_Q) pari_err_TYPE("mfffromell [E not over Q]", E); N = itos(ellQ_get_N(E)); mf = mfinit_i(mkvec2(utoi(N), gen_2), mf_NEW); v = split_i(mf, 1, 0); S = gel(v,1); l = lg(S); /* rational newforms */ F = tag(t_MF_ELL, mkNK(N,2,mfchartrivial()), E); z = mftobasis_i(mf, F); for(i = 1; i < l; i++) if (gequal(z, gel(S,i))) break; if (i == l) pari_err_BUG("mffromell [E is not modular]"); return gerepilecopy(av, mkvec3(mf, F, z)); } /* returns -1 if not, degree otherwise */ long polishomogeneous(GEN P) { long i, D, l; if (typ(P) != t_POL) return 0; D = -1; l = lg(P); for (i = 2; i < l; i++) { GEN c = gel(P,i); long d; if (gequal0(c)) continue; d = polishomogeneous(c); if (d < 0) return -1; if (D < 0) D = d + i-2; else if (D != d + i-2) return -1; } return D; } /* P a t_POL, 1 if spherical, 0 otherwise */ static long RgX_isspherical(GEN Qi, GEN P) { pari_sp av = avma; GEN va, S; long lva, i, j, r; if (degpol(P) <= 1) return 1; va = variables_vecsmall(P); lva = lg(va); if (lva > lg(Qi)) pari_err(e_MISC, "too many variables in mffromqf"); S = gen_0; for (j = 1; j < lva; j++) { GEN col = gel(Qi, j), Pj = deriv(P, va[j]); for (i = 1; i <= j; i++) { GEN coe = gel(col, i); if (i != j) coe = gmul2n(coe, 1); if (!gequal0(coe)) S = gadd(S, gmul(coe, deriv(Pj, va[i]))); } } r = gequal0(S); avma = av; return r; } static GEN c_QFsimple_i(long n, GEN Q, GEN P) { pari_sp av = avma; GEN V, v = qfrep0(Q, utoi(n), 1); long i, l = lg(v); V = cgetg(l+1, t_VEC); if (!P || equali1(P)) { gel(V,1) = gen_1; for (i = 2; i <= l; i++) gel(V,i) = utoi(v[i-1] << 1); } else { gel(V,1) = gcopy(P); for (i = 2; i <= l; i++) gel(V,i) = gmulgs(P, v[i-1] << 1); } return gerepileupto(av, V); } static GEN c_QF_i(long n, GEN Q, GEN P) { pari_sp av = avma; GEN V, v, va; long i, lva, lq, l; if (!P || typ(P) != t_POL) return c_QFsimple_i(n, Q, P); v = gel(minim(Q, utoi(2*n), NULL), 3); va = variables_vec(P); lq = lg(Q) - 1; lva = lg(va) - 1; V = zerovec(n + 1); l = lg(v); for (i = 1; i < l; i++) { GEN X = gel(v,i); long ind = (itos(qfeval0(Q, X, NULL)) >> 1) + 1; if (lq > lva) X = vecslice(X, 1, lva); gel(V, ind) = gadd(gel(V, ind), gsubstvec(P, va, X)); } return gerepilecopy(av, gmul2n(V, 1)); } GEN mffromqf(GEN Q, GEN P) { pari_sp av = avma; GEN G, Qi, F, D, N, mf, v, gk, gwt, chi; long m, d, space; if (typ(Q) != t_MAT) pari_err_TYPE("mffromqf", Q); if (!RgM_is_ZM(Q) || !qf_iseven(Q)) pari_err_TYPE("mffromqf [not integral or even]", Q); m = lg(Q)-1; gk = sstoQ(m, 2); Qi = ZM_inv(Q, &N); if (!qf_iseven(Qi)) N = shifti(N, 1); d = 0; if (!P || gequal1(P)) P = NULL; else { P = simplify_shallow(P); if (typ(P) == t_POL) { d = polishomogeneous(P); if (d < 0) pari_err_TYPE("mffromqf [not homogeneous t_POL]", P); if (!RgX_isspherical(Qi, P)) pari_err_TYPE("mffromqf [not a spherical t_POL]", P); } } D = ZM_det(Q); if (typ(gk) == t_INT) { if (mpodd(gk)) D = negi(D); } else D = shifti(D, 1); space = d > 0 ? mf_CUSP : mf_FULL; G = znstar0(N,1); chi = mkvec2(G, znchar_quad(G,D)); gwt = gaddgs(gk, d); mf = mfinit(mkvec3(N, gwt, chi), space); if (odd(d)) { F = mftrivial(); v = zerocol(MF_get_dim(mf)); } else { F = c_QF_i(mfsturm(mf), Q, P); v = mftobasis_i(mf, F); F = mflinear(mf, v); } return gerepilecopy(av, mkvec3(mf, F, v)); } /***********************************************************************/ /* Eisenstein Series */ /***********************************************************************/ /* \sigma_{k-1}(\chi,n) */ static GEN sigchi(long k, GEN CHI, long n) { pari_sp av = avma; GEN S = gen_1, D = mydivisorsu(u_ppo(n,mfcharmodulus(CHI))); long i, l = lg(D), ord = mfcharorder(CHI), vt = varn(mfcharpol(CHI)); for (i = 2; i < l; i++) /* skip D[1] = 1 */ { long d = D[i], a = mfcharevalord(CHI, d, ord); S = gadd(S, mygmodulo_lift(a, ord, powuu(d, k-1), vt)); } return gerepileupto(av,S); } /* write n = n0*n1*n2, (n0,N1*N2) = 1, n1 | N1^oo, n2 | N2^oo; * return NULL if (n,N1,N2) > 1, else return factoru(n0) */ static GEN sigchi2_dec(long n, long N1, long N2, long *pn1, long *pn2) { GEN P0, E0, P, E, fa = myfactoru(n); long i, j, l; *pn1 = 1; *pn2 = 1; if (N1 == 1 && N2 == 1) return fa; P = gel(fa,1); l = lg(P); E = gel(fa,2); P0 = cgetg(l, t_VECSMALL); E0 = cgetg(l, t_VECSMALL); for (i = j = 1; i < l; i++) { long p = P[i], e = E[i]; if (N1 % p == 0) { if (N2 % p == 0) return NULL; *pn1 *= upowuu(p,e); } else if (N2 % p == 0) *pn2 *= upowuu(p,e); else { P0[j] = p; E0[j] = e; j++; } } setlg(P0, j); setlg(E0, j); return mkvec2(P0,E0); } /* sigma_{k-1}(\chi_1,\chi_2,n), ord multiple of lcm(ord(CHI1),ord(CHI2)) */ static GEN sigchi2(long k, GEN CHI1, GEN CHI2, long n, long ord) { pari_sp av = avma; GEN S = gen_0, D; long i, l, n1, n2, vt, N1 = mfcharmodulus(CHI1), N2 = mfcharmodulus(CHI2); D = sigchi2_dec(n, N1, N2, &n1, &n2); if (!D) { avma = av; return S; } D = divisorsu_fact(D); l = lg(D); vt = varn(mfcharpol(CHI1)); for (i = 1; i < l; i++) { /* S += d^(k-1)*chi1(d)*chi2(n/d) */ long a, d = n2*D[i], nd = n1*D[l-i]; /* (d,N1)=1; (n/d,N2) = 1 */ a = mfcharevalord(CHI1, d, ord) + mfcharevalord(CHI2, nd, ord); if (a >= ord) a -= ord; S = gadd(S, mygmodulo_lift(a, ord, powuu(d, k-1), vt)); } return gerepileupto(av, S); } /**************************************************************************/ /** Dirichlet characters with precomputed values **/ /**************************************************************************/ /* CHI mfchar */ static GEN mfcharcxinit(GEN CHI, long prec) { GEN G = gel(CHI,1), chi = gel(CHI,2), z, V; GEN v = ncharvecexpo(G, znconrey_normalized(G,chi)); long n, l = lg(v), o = mfcharorder(CHI); V = cgetg(l, t_VEC); z = grootsof1(o, prec); /* Mod(t, Phi_o(t)) -> e(1/o) */ for (n = 1; n < l; n++) gel(V,n) = v[n] < 0? gen_0: gel(z, v[n]+1); return mkvecn(6, G, chi, gmfcharorder(CHI), v, V, mfcharpol(CHI)); } /* v a "CHIvec" */ static long CHIvec_N(GEN v) { return itou(znstar_get_N(gel(v,1))); } static GEN CHIvec_CHI(GEN v) { return mkvec4(gel(v,1), gel(v,2), gel(v,3), gel(v,6)); } /* character order */ static long CHIvec_ord(GEN v) { return itou(gel(v,3)); } /* character exponents, i.e. t such that chi(n) = e(t) */ static GEN CHIvec_expo(GEN v) { return gel(v,4); } /* character values chi(n) */ static GEN CHIvec_val(GEN v) { return gel(v,5); } /* CHI(n) */ static GEN mychareval(GEN v, long n) { long N = CHIvec_N(v), ind = n%N; if (ind <= 0) ind += N; return gel(CHIvec_val(v), ind); } /* return c such that CHI(n) = e(c / ordz) or -1 if (n,N) > 1 */ static long mycharexpo(GEN v, long n) { long N = CHIvec_N(v), ind = n%N; if (ind <= 0) ind += N; return CHIvec_expo(v)[ind]; } /* faster than mfcharparity */ static long CHIvec_parity(GEN v) { return mycharexpo(v,-1) ? -1: 1; } /**************************************************************************/ static ulong sigchi2_Fl(long k, GEN CHI1vec, GEN CHI2vec, long n, GEN vz, ulong p) { pari_sp av = avma; long ordz = lg(vz)-2, i, l, n1, n2; ulong S = 0; GEN D = sigchi2_dec(n, CHIvec_N(CHI1vec), CHIvec_N(CHI2vec), &n1, &n2); if (!D) { avma = av; return S; } D = divisorsu_fact(D); l = lg(D); for (i = 1; i < l; i++) { /* S += d^(k-1)*chi1(d)*chi2(n/d) */ long a, d = n2*D[i], nd = n1*D[l-i]; /* (d,N1)=1, (n/d,N2)=1 */ a = mycharexpo(CHI2vec, nd) + mycharexpo(CHI1vec, d); if (a >= ordz) a -= ordz; S = Fl_add(S, mygmodulo_Fl(a, vz, Fl_powu(d,k-1,p), p), p); } avma = av; return S; } /**********************************************************************/ /* Fourier expansions of Eisenstein series */ /**********************************************************************/ /* L(CHI,0) / 2, order(CHI) | ord != 0 */ static GEN charLFwt1(GEN CHI, long ord) { GEN S; long r, vt, m = mfcharmodulus(CHI); if (m == 1) return mkfrac(gen_m1,stoi(4)); S = gen_0; vt = varn(mfcharpol(CHI)); for (r = 1; r < m; r++) { /* S += r*chi(r) */ long a; if (ugcd(m,r) != 1) continue; a = mfcharevalord(CHI,r,ord); S = gadd(S, mygmodulo_lift(a, ord, utoi(r), vt)); } return gdivgs(S, -2*m); } /* L(CHI,0) / 2, mod p */ static ulong charLFwt1_Fl(GEN CHIvec, GEN vz, ulong p) { long r, m = CHIvec_N(CHIvec); ulong S; if (m == 1) return Rg_to_Fl(mkfrac(gen_m1,stoi(4)), p); S = 0; for (r = 1; r < m; r++) { /* S += r*chi(r) */ long a = mycharexpo(CHIvec,r); if (a < 0) continue; S = Fl_add(S, mygmodulo_Fl(a, vz, r, p), p); } return Fl_div(Fl_neg(S,p), 2*m, p); } /* L(CHI,1-k) / 2, order(CHI) | ord != 0 */ static GEN charLFwtk(long k, GEN CHI, long ord) { GEN S, P, dS; long r, m, vt; if (k == 1) return charLFwt1(CHI, ord); m = mfcharmodulus(CHI); if (m == 1) return gdivgs(bernfrac(k),-2*k); S = gen_0; vt = varn(mfcharpol(CHI)); P = ZX_rescale(Q_remove_denom(bernpol(k,0), &dS), utoi(m)); dS = mul_denom(dS, stoi(-2*m*k)); for (r = 1; r < m; r++) { /* S += P(r)*chi(r) */ long a; if (ugcd(r,m) != 1) continue; a = mfcharevalord(CHI,r,ord); S = gadd(S, mygmodulo_lift(a, ord, poleval(P, utoi(r)), vt)); } return gdiv(S, dS); } /* L(CHI,1-k) / 2, mod p */ static ulong charLFwtk_Fl(long k, GEN CHIvec, GEN vz, ulong p) { GEN P; long r, m; ulong S; if (k == 1) return charLFwt1_Fl(CHIvec, vz, p); m = CHIvec_N(CHIvec); if (m == 1) return Rg_to_Fl(gdivgs(bernfrac(k),-2*k), p); S = 0; P = RgX_to_Flx(RgX_rescale(bernpol(k,0), utoi(m)), p); for (r = 1; r < m; r++) { /* S += P(r)*chi(r) */ long a = mycharexpo(CHIvec,r); if (a < 0) continue; S = Fl_add(S, mygmodulo_Fl(a, vz, Flx_eval(P,r,p), p), p); } return Fl_div(Fl_neg(S,p), 2*k*m, p); } static GEN mfeisenstein2_0(long k, GEN CHI1, GEN CHI2, long ord) { if (k == 1 && mfcharistrivial(CHI1)) return charLFwt1(CHI2, ord); else if (mfcharistrivial(CHI2)) return charLFwtk(k, CHI1, ord); else return gen_0; } static ulong mfeisenstein2_0_Fl(long k, GEN CHI1vec, GEN CHI2vec, GEN vz, ulong p) { if (k == 1 && CHIvec_ord(CHI1vec) == 1) return charLFwtk_Fl(k, CHI2vec, vz, p); else if (CHIvec_ord(CHI2vec) == 1) return charLFwtk_Fl(k, CHI1vec, vz, p); else return 0; } static GEN NK_eisen2(long k, GEN CHI1, GEN CHI2) { long N = mfcharmodulus(CHI1)*mfcharmodulus(CHI2); return mkNK(N, k, mfcharmul(CHI1,CHI2)); } static GEN mfeisenstein_i(long k, GEN CHI1, GEN CHI2) { long s = 1, ord, vt; GEN E0, NK, vchi, T; if (CHI2) { CHI2 = get_mfchar(CHI2); if (mfcharparity(CHI2) < 0) s = -s; } if (CHI1) { CHI1 = get_mfchar(CHI1); if (mfcharparity(CHI1) < 0) s = -s; } if (s != m1pk(k)) return mftrivial(); if (!CHI1) CHI1 = mfchartrivial(); if (!CHI2) { /* E_k(chi1) */ vt = varn(mfcharpol(CHI1)); ord = mfcharorder(CHI1); NK = mkNK(mfcharmodulus(CHI1), k, CHI1); E0 = charLFwtk(k, CHI1, ord); vchi = mkvec3(E0, mkvec(mfcharpol(CHI1)), CHI1); return tag(t_MF_EISEN, NK, vchi); } /* E_k(chi1,chi2) */ vt = varn(mfcharpol(CHI1)); NK = NK_eisen2(k, CHI1, CHI2); ord = ulcm(mfcharorder(CHI1), mfcharorder(CHI2)); E0 = mfeisenstein2_0(k, CHI1, CHI2, ord); T = mkvec(polcyclo(ord_canon(ord), vt)); vchi = mkvec4(E0, T, CHI1, CHI2); return tag2(t_MF_EISEN, NK, vchi, mkvecsmall2(ord,0)); } GEN mfeisenstein(long k, GEN CHI1, GEN CHI2) { pari_sp av = avma; if (k < 1) pari_err_DOMAIN("mfeisenstein", "k", "<", gen_1, stoi(k)); return gerepilecopy(av, mfeisenstein_i(k, CHI1, CHI2)); } static GEN mfeisenstein2all(long N0, GEN NK, long k, GEN CHI1, GEN CHI2, GEN T, long o) { GEN E, E0 = mfeisenstein2_0(k, CHI1,CHI2, o), vchi = mkvec4(E0, T, CHI1,CHI2); long j, d = (lg(T)==4)? itou(gmael(T,3,1)): 1; E = cgetg(d+1, t_VEC); for (j=1; j<=d; j++) gel(E,j) = tag2(t_MF_EISEN, NK,vchi,mkvecsmall2(o,j-1)); return mfbdall(E, N0 / mf_get_N(gel(E,1))); } static GEN zncharsG(GEN G) { long i, l, N = itou(znstar_get_N(G)); GEN vCHI, V; if (N == 1) return mkvec2(gen_1,cgetg(1,t_COL)); vCHI = const_vec(N,NULL); V = cyc2elts(znstar_get_conreycyc(G)); l = lg(V); for (i = 1; i < l; i++) { GEN chi0, chi = zc_to_ZC(gel(V,i)), n, F; F = znconreyconductor(G, chi, &chi0); if (typ(F) != t_INT) F = gel(F,1); n = znconreyexp(G, chi); gel(vCHI, itos(n)) = mkvec2(F, chi0); } return vCHI; } /* CHI primitive, f(CHI) | N. Return pairs (CHI1,CHI2) both primitive * such that f(CHI1)*f(CHI2) | N and CHI1 * CHI2 = CHI; * if k = 1, CHI1 is even; if k = 2, omit (1,1) if CHI = 1 */ static GEN mfeisensteinbasis_i(long N0, long k, GEN CHI) { GEN G = gel(CHI,1), chi = gel(CHI,2), vT = const_vec(myeulerphiu(N0), NULL); GEN CHI0, GN, chiN, Lchi, LG, V, RES, NK, T; long i, j, l, n, n1, N, ord = mfcharorder(CHI), OC = ord_canon(ord); long F = mfcharmodulus(CHI), vt = varn(mfcharpol(CHI)); CHI0 = (F == 1)? CHI: mfchartrivial(); j = 1; RES = cgetg(N0+1, t_VEC); T = gel(vT,OC) = Qab_trace_init(polcyclo(OC,vt), OC, OC); if (F != 1 || k != 2) { /* N1 = 1 */ NK = mkNK(F, k, CHI); gel(RES, j++) = mfeisenstein2all(N0, NK, k, CHI0, CHI, T, ord); if (F != 1 && k != 1) gel(RES, j++) = mfeisenstein2all(N0, NK, k, CHI, CHI0, T, ord); } if (N0 == 1) { setlg(RES,j); return RES; } GN = G; chiN = chi; if (F == N0) N = N0; else { GEN faN = myfactoru(N0), P = gel(faN,1), E = gel(faN,2); long lP = lg(P); for (i = N = 1; i < lP; i++) { long p = P[i]; N *= upowuu(p, maxuu(E[i]/2, z_lval(F,p))); } if ((N & 3) == 2) N >>= 1; if (N == 1) { setlg(RES,j); return RES; } if (F != N) { GN = znstar0(utoipos(N),1); chiN = zncharinduce(G, chi, GN); } } LG = const_vec(N, NULL); /* LG[d] = znstar(d,1) or NULL */ gel(LG,1) = gel(CHI0,1); gel(LG,F) = G; gel(LG,N) = GN; Lchi = coprimes_zv(N); n = itou(znconreyexp(GN,chiN)); V = zncharsG(GN); l = lg(V); for (n1 = 2; n1 < l; n1++) /* skip 1 (trivial char) */ { GEN v = gel(V,n1), w, chi1, chi2, G1, G2, CHI1, CHI2; long N12, N1, N2, no, oc, o12, t, m; if (!Lchi[n1]) continue; chi1 = gel(v,2); N1 = itou(gel(v,1)); /* conductor of chi1 */ w = gel(V, Fl_div(n,n1,N)); chi2 = gel(w,2); N2 = itou(gel(w,1)); /* conductor of chi2 */ N12 = N1 * N2; if (N2 == 1 || N0 % N12) continue; G1 = gel(LG,N1); if (!G1) gel(LG,N1) = G1 = znstar0(utoipos(N1), 1); if (k == 1 && zncharisodd(G1,chi1)) continue; G2 = gel(LG,N2); if (!G2) gel(LG,N2) = G2 = znstar0(utoipos(N2), 1); CHI1 = mfcharGL(G1, chi1); CHI2 = mfcharGL(G2, chi2); o12 = ulcm(mfcharorder(CHI1), mfcharorder(CHI2)); /* remove Galois orbit: same trace */ no = Fl_powu(n1, ord, N); for (t = 1+ord, m = n1; t <= o12; t += ord) { /* m <-> CHI1^t, if t in Gal(Q(chi1,chi2)/Q), omit (CHI1^t,CHI2^t) */ m = Fl_mul(m, no, N); if (!m) break; if (ugcd(t, o12) == 1) Lchi[m] = 0; } oc = ord_canon(o12); T = gel(vT,oc); if (!T) T = gel(vT,oc) = Qab_trace_init(polcyclo(oc,vt), oc, OC); NK = mkNK(N12, k, CHI); gel(RES, j++) = mfeisenstein2all(N0, NK, k, CHI1, CHI2, T, o12); } setlg(RES,j); return RES; } static GEN mfbd_E2(GEN E2, long d, GEN CHI) { GEN E2d = mfbd_i(E2, d); GEN F = mkvec2(E2, E2d), L = mkvec2(gen_1, utoineg(d)); /* cannot use mflinear_i: E2 and E2d do not have the same level */ return tag3(t_MF_LINEAR, mkNK(d,2,CHI), F, L, gen_1); } /* C-basis of E_k(Gamma_0(N),chi). If k = 1, the first basis element must not * vanish at oo [used in mfwt1basis]. Here E_1(CHI), whose q^0 coefficient * does not vanish (since L(CHI,0) does not) *if* CHI is not trivial; which * must be the case in weight 1. * * (k>=3): In weight k >= 3, basis is B(d) E(CHI1,(CHI/CHI1)_prim), where * CHI1 is primitive modulo N1, and if N2 is the conductor of CHI/CHI1 * then d*N1*N2 | N. * (k=2): In weight k=2, same if CHI is nontrivial. If CHI is trivial, must * not take CHI1 trivial, and must add E_2(tau)-dE_2(d tau)), where * d|N, d > 1. * (k=1): In weight k=1, same as k >= 3 except that we restrict to CHI1 even */ static GEN mfeisensteinbasis(long N, long k, GEN CHI) { long i, F; GEN L; if (badchar(N, k, CHI)) return cgetg(1, t_VEC); if (k == 0) return mfcharistrivial(CHI)? mkvec(mf1()): cgetg(1, t_VEC); CHI = mfchartoprimitive(CHI, &F); L = mfeisensteinbasis_i(N, k, CHI); if (F == 1 && k == 2) { GEN v, E2 = mfeisenstein(2, NULL, NULL), D = mydivisorsu(N); long nD = lg(D)-1; v = cgetg(nD, t_VEC); L = vec_append(L,v); for (i = 1; i < nD; i++) gel(v,i) = mfbd_E2(E2, D[i+1], CHI); } return lg(L) == 1? L: shallowconcat1(L); } static GEN not_in_space(GEN F, long flag) { if (!flag) err_space(F); return cgetg(1, t_COL); } /* when flag set, no error */ GEN mftobasis(GEN mf, GEN F, long flag) { pari_sp av2, av = avma; GEN G, v, y, gk; long N, B, ismf = checkmf_i(F); mf = checkMF(mf); if (ismf) { if (mfistrivial(F)) return zerocol(MF_get_dim(mf)); if (!mf_same_k(mf, F) || !mf_same_CHI(mf, F)) return not_in_space(F, flag); } N = MF_get_N(mf); gk = MF_get_gk(mf); if (ismf) { long NF = mf_get_N(F); B = maxuu(mfsturmNgk(NF,gk), mfsturmNgk(N,gk)) + 1; v = mfcoefs_i(F,B,1); } else { B = mfsturmNgk(N, gk) + 1; switch(typ(F)) { /* F(0),...,F(lg(v)-2) */ case t_SER: v = sertocol(F); settyp(v,t_VEC); break; case t_VEC: v = F; break; case t_COL: v = shallowtrans(F); break; default: pari_err_TYPE("mftobasis",F); v = NULL;/*LCOV_EXCL_LINE*/ } if (flag) B = minss(B, lg(v)-2); } y = mftobasis_i(mf, v); if (typ(y) == t_VEC) { if (flag) return gerepilecopy(av, y); pari_err(e_MISC, "not enough coefficients in mftobasis"); } av2 = avma; if (MF_get_space(mf) == mf_FULL || mfsturm(mf)+1 == B) return y; G = mflinear(mf, y); if (!gequal(v, mfcoefs_i(G, lg(v)-2,1))) y = NULL; if (!y) { avma = av; return not_in_space(F, flag); } avma = av2; return gerepileupto(av, y); } /* assume N > 0; first cusp is always 0 */ static GEN mfcusps_i(long N) { long i, c, l; GEN D, v; if (N == 1) return mkvec(gen_0); D = mydivisorsu(N); l = lg(D); /* left on stack */ c = mfnumcuspsu_fact(myfactoru(N)); v = cgetg(c + 1, t_VEC); for (i = c = 1; i < l; i++) { long C = D[i], NC = D[l-i], lima = ugcd(C, NC), A0, A; for (A0 = 0; A0 < lima; A0++) if (ugcd(A0, lima) == 1) { A = A0; while (ugcd(A,C) > 1) A += lima; gel(v, c++) = sstoQ(A, C); } } return v; } /* List of cusps of Gamma_0(N) */ GEN mfcusps(GEN gN) { long N; GEN mf; if (typ(gN) == t_INT) N = itos(gN); else if ((mf = checkMF_i(gN))) N = MF_get_N(mf); else { pari_err_TYPE("mfcusps", gN); N = 0; } if (N <= 0) pari_err_DOMAIN("mfcusps", "N", "<=", gen_0, stoi(N)); return mfcusps_i(N); } long mfcuspisregular(GEN NK, GEN cusp) { long v, N, dk, nk, t, o; GEN mf, CHI, go, A, C, g, c, d; if ((mf = checkMF_i(NK))) { GEN gk = MF_get_gk(mf); N = MF_get_N(mf); CHI = MF_get_CHI(mf); Qtoss(gk, &nk, &dk); } else checkNK2(NK, &N, &nk, &dk, &CHI, 0); if (typ(cusp) == t_INFINITY) return 1; if (typ(cusp) == t_FRAC) { A = gel(cusp,1); C = gel(cusp,2); } else { A = cusp; C = gen_1; } g = diviuexact(mului(N,C), ugcd(N, Fl_sqr(umodiu(C,N), N))); c = mulii(negi(C),g); d = addiu(mulii(A,g), 1); if (!CHI) return 1; go = gmfcharorder(CHI); v = vali(go); if (v < 2) go = shifti(go, 2-v); t = itou( znchareval(gel(CHI,1), gel(CHI,2), d, go) ); if (dk == 1) return t == 0; o = itou(go); if (kronecker(c,d) < 0) t = Fl_add(t, o/2, o); if (Mod4(d) == 1) return t == 0; t = Fl_sub(t, Fl_mul(o/4, nk, o), o); return t == 0; } /* Some useful closures */ /* sum_{d|n} d^k */ static GEN mysumdivku(ulong n, ulong k) { GEN fa = myfactoru(n); return k == 1? usumdiv_fact(fa): usumdivk_fact(fa,k); } static GEN c_Ek(long n, long d, GEN F) { GEN E = cgetg(n + 2, t_VEC), C = gel(F,2); long i, k = mf_get_k(F); gel (E, 1) = gen_1; for (i = 1; i <= n; i++) { pari_sp av = avma; gel(E, i+1) = gerepileupto(av, gmul(C, mysumdivku(i*d, k-1))); } return E; } GEN mfEk(long k) { pari_sp av = avma; GEN E0, NK; if (k < 0 || odd(k)) pari_err_TYPE("mfEk [incorrect k]", stoi(k)); if (!k) return mf1(); E0 = gdivsg(-2*k, bernfrac(k)); NK = mkNK(1,k,mfchartrivial()); return gerepilecopy(av, tag(t_MF_Ek, NK, E0)); } GEN mfDelta(void) { pari_sp av = avma; return gerepilecopy(av, tag0(t_MF_DELTA, mkNK(1,12,mfchartrivial()))); } GEN mfTheta(GEN psi) { pari_sp av = avma; GEN N, gk, psi2; long par; if (!psi) { psi = mfchartrivial(); N = utoipos(4); par = 1; } else { long FC; psi = get_mfchar(psi); FC = mfcharconductor(psi); if (mfcharmodulus(psi) != FC) pari_err_TYPE("mfTheta [nonprimitive character]", psi); par = mfcharparity(psi); N = shifti(sqru(FC),2); } if (par > 0) { gk = ghalf; psi2 = psi; } else { gk = gsubsg(2, ghalf); psi2 = mfcharmul(psi, get_mfchar(stoi(-4))); } return gerepilecopy(av, tag(t_MF_THETA, mkgNK(N, gk, psi2, pol_x(1)), psi)); } /* Output 0 if not desired eta product: if flag=0 (default) require * holomorphic at cusps. If flag set, accept meromorphic, but sill in some * modular function space */ GEN mffrometaquo(GEN eta, long flag) { pari_sp av = avma; GEN NK, N, k, BR, P; long v, cusp = 0; if (!etaquotype(&eta, &N,&k,&P, &v, NULL, flag? NULL: &cusp) || cusp < 0) { avma = av; return gen_0; } if (lg(gel(eta,1)) == 1) { avma = av; return mf1(); } BR = mkvec2(ZV_to_zv(gel(eta,1)), ZV_to_zv(gel(eta,2))); if (v < 0) v = 0; NK = mkgNK(N, k, get_mfchar(P), pol_x(1)); return gerepilecopy(av, tag2(t_MF_ETAQUO, NK, BR, utoi(v))); } #if 0 /* number of primitive characters modulo N */ static ulong numprimchars(ulong N) { GEN fa, P, E; long i, l; ulong n; if ((N & 3) == 2) return 0; fa = myfactoru(N); P = gel(fa,1); l = lg(P); E = gel(fa,2); for (i = n = 1; i < l; i++) { ulong p = P[i], e = E[i]; if (e == 2) n *= p-2; else n *= (p-1)*(p-1)*upowuu(p,e-2); } return n; } #endif /* Space generated by products of two Eisenstein series */ INLINE int cmp_small(long a, long b) { return a>b? 1: (a 1) */ static GEN charsmodN(long N) { GEN D, G, prio, phio, dummy = cgetg(1,t_VEC); GEN vP, vG = const_vec(N,NULL), vCHI = const_vec(N,NULL); GEN bymod = const_vec(N,NULL); long pn, i, l, vt = fetch_user_var("t"); D = mydivisorsu(N); l = lg(D); for (i = 1; i < l; i++) gel(bymod, D[i]) = vecsmalltrunc_init(myeulerphiu(D[i])+1); gel(vG,N) = G = znstar0(utoipos(N),1); pn = znstar_get_expo(G); /* exponent(Z/NZ)^* */ vP = const_vec(pn,NULL); for (i = 1; i <= N; i++) { GEN P, gF, G0, chi0, nchi0, chi, v, go; long j, F, o; if (ugcd(i,N) != 1) continue; chi = znconreylog(G, utoipos(i)); gF = znconreyconductor(G, chi, &chi0); F = (typ(gF) == t_INT)? itou(gF): itou(gel(gF,1)); G0 = gel(vG, F); if (!G0) G0 = gel(vG,F) = znstar0(gF, 1); nchi0 = znconreylog_normalize(G0,chi0); go = gel(nchi0,1); o = itou(go); /* order(chi0) */ v = ncharvecexpo(G0, nchi0); if (!equaliu(go, pn)) v = zv_z_mul(v, pn / o); P = gel(vP, o); if (!P) P = gel(vP,o) = polcyclo(o,vt); /* mfcharcxinit with dummy complex powers */ gel(vCHI,i) = mkvecn(6, G0, chi0, go, v, dummy, P); D = mydivisorsu(N / F); l = lg(D); for (j = 1; j < l; j++) vecsmalltrunc_append(gel(bymod, F*D[j]), i); } phio = zero_zv(pn); l = lg(vCHI); prio = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN CHI = gel(vCHI,i); long o; if (!CHI) continue; o = CHIvec_ord(CHI); if (!phio[o]) phio[o] = myeulerphiu(o); prio[i] = phio[o]; } l = lg(bymod); /* sort characters by increasing value of phi(order) */ for (i = 1; i < l; i++) { GEN z = gel(bymod,i); if (z) gen_sort_inplace(z, (void*)prio, &cmp_small_priority, NULL); } return mkvec3(vCHI, bymod, vG); } static GEN mfeisenstein2pure(long k, GEN CHI1, GEN CHI2, long ord, GEN P, long lim) { GEN c, V = cgetg(lim+2, t_COL); long n; c = mfeisenstein2_0(k, CHI1, CHI2, ord); if (P) c = grem(c, P); gel(V,1) = c; for (n=1; n <= lim; n++) { c = sigchi2(k, CHI1, CHI2, n, ord); if (P) c = grem(c, P); gel(V,n+1) = c; } return V; } static GEN mfeisenstein2pure_Fl(long k, GEN CHI1vec, GEN CHI2vec, GEN vz, ulong p, long lim) { GEN V = cgetg(lim+2, t_VECSMALL); long n; V[1] = mfeisenstein2_0_Fl(k, CHI1vec, CHI2vec, vz, p); for (n=1; n <= lim; n++) V[n+1] = sigchi2_Fl(k, CHI1vec, CHI2vec, n, vz, p); return V; } static GEN getcolswt2(GEN M, GEN D, ulong p) { GEN R, v = gel(M,1); long i, l = lg(M) - 1; R = cgetg(l, t_MAT); /* skip D[1] = 1 */ for (i = 1; i < l; i++) { GEN w = Flv_Fl_mul(gel(M,i+1), D[i+1], p); gel(R,i) = Flv_sub(v, w, p); } return R; } static GEN expandbd(GEN V, long d) { long L, n, nd; GEN W; if (d == 1) return V; L = lg(V)-1; W = zerocol(L); /* nd = n/d */ for (n = nd = 0; n < L; n += d, nd++) gel(W, n+1) = gel(V, nd+1); return W; } static GEN expandbd_Fl(GEN V, long d) { long L, n, nd; GEN W; if (d == 1) return V; L = lg(V)-1; W = zero_Flv(L); /* nd = n/d */ for (n = nd = 0; n < L; n += d, nd++) W[n+1] = V[nd+1]; return W; } static void getcols_i(GEN *pM, GEN *pvj, GEN gk, GEN CHI1vec, GEN CHI2vec, long NN1, GEN vz, ulong p, long lim) { GEN CHI1 = CHIvec_CHI(CHI1vec), CHI2 = CHIvec_CHI(CHI2vec); long N2 = CHIvec_N(CHI2vec); GEN vj, M, D = mydivisorsu(NN1/N2); long i, l = lg(D), k = gk[2]; GEN V = mfeisenstein2pure_Fl(k, CHI1vec, CHI2vec, vz, p, lim); M = cgetg(l, t_MAT); for (i = 1; i < l; i++) gel(M,i) = expandbd_Fl(V, D[i]); if (k == 2 && N2 == 1 && CHIvec_N(CHI1vec) == 1) { M = getcolswt2(M, D, p); l--; D = vecslice(D, 2, l); } *pM = M; *pvj = vj = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(vj,i) = mkvec4(gk, CHI1, CHI2, utoipos(D[i])); } /* find all CHI1, CHI2 mod N such that CHI1*CHI2 = CHI, f(CHI1)*f(CHI2) | N. * set M = mfcoefs(B_e E(CHI1,CHI2), lim), vj = [e,i1,i2] */ static void getcols(GEN *pM, GEN *pv, long k, long nCHI, GEN allN, GEN vz, ulong p, long lim) { GEN vCHI = gel(allN,1), gk = utoi(k); GEN M = cgetg(1,t_MAT), v = cgetg(1,t_VEC); long i1, N = lg(vCHI)-1; for (i1 = 1; i1 <= N; i1++) { GEN CHI1vec = gel(vCHI, i1), CHI2vec, M1, v1; long NN1, i2; if (!CHI1vec) continue; if (k == 1 && CHIvec_parity(CHI1vec) == -1) continue; NN1 = N/CHIvec_N(CHI1vec); /* N/f(chi1) */; i2 = Fl_div(nCHI,i1, N); if (!i2) i2 = 1; CHI2vec = gel(vCHI,i2); if (NN1 % CHIvec_N(CHI2vec)) continue; /* f(chi1)f(chi2) | N ? */ getcols_i(&M1, &v1, gk, CHI1vec, CHI2vec, NN1, vz, p, lim); M = shallowconcat(M, M1); v = shallowconcat(v, v1); } *pM = M; *pv = v; } static void update_Mj(GEN *M, GEN *vecj, GEN *pz, ulong p) { GEN perm; *pz = Flm_indexrank(*M, p); perm = gel(*pz,2); *M = vecpermute(*M, perm); *vecj = vecpermute(*vecj, perm); } static int getcolsgen(long dim, GEN *pM, GEN *pvj, GEN *pz, long k, long ell, long nCHI, GEN allN, GEN vz, ulong p, long lim) { GEN vCHI = gel(allN,1), bymod = gel(allN,2), gell = utoi(ell); long i1, N = lg(vCHI)-1; long L = lim+1; if (lg(*pvj)-1 >= dim) update_Mj(pM, pvj, pz, p); if (lg(*pvj)-1 == dim) return 1; for (i1 = 1; i1 <= N; i1++) { GEN CHI1vec = gel(vCHI, i1), T; long par1, j, l, N1, NN1; if (!CHI1vec) continue; par1 = CHIvec_parity(CHI1vec); if (ell == 1 && par1 == -1) continue; if (odd(ell)) par1 = -par1; N1 = CHIvec_N(CHI1vec); NN1 = N/N1; T = gel(bymod, NN1); l = lg(T); for (j = 1; j < l; j++) { long i2 = T[j], l1, l2, j1, s, nC; GEN M, M1, M2, vj, vj1, vj2, CHI2vec = gel(vCHI, i2); if (CHIvec_parity(CHI2vec) != par1) continue; nC = Fl_div(nCHI, Fl_mul(i1,i2,N), N); getcols(&M2, &vj2, k-ell, nC, allN, vz, p, lim); l2 = lg(M2); if (l2 == 1) continue; getcols_i(&M1, &vj1, gell, CHI1vec, CHI2vec, NN1, vz, p, lim); l1 = lg(M1); M1 = Flm_to_FlxV(M1, 0); M2 = Flm_to_FlxV(M2, 0); M = cgetg((l1-1)*(l2-1) + 1, t_MAT); vj = cgetg((l1-1)*(l2-1) + 1, t_VEC); for (j1 = s = 1; j1 < l1; j1++) { GEN E = gel(M1,j1), v = gel(vj1,j1); long j2; for (j2 = 1; j2 < l2; j2++, s++) { GEN c = Flx_to_Flv(Flxn_mul(E, gel(M2,j2), L, p), L); gel(M,s) = c; gel(vj,s) = mkvec2(v, gel(vj2,j2)); } } *pM = shallowconcat(*pM, M); *pvj = shallowconcat(*pvj, vj); if (lg(*pvj)-1 >= dim) update_Mj(pM, pvj, pz, p); if (lg(*pvj)-1 == dim) return 1; } } if (ell == 1) { update_Mj(pM, pvj, pz, p); return (lg(*pvj)-1 == dim); } return 0; } static GEN mkF2bd(long d, long lim) { GEN V = zerovec(lim + 1); long n; gel(V, 1) = ginv(stoi(-24)); for (n = 1; n <= lim/d; n++) gel(V, n*d + 1) = mysumdivku(n, 1); return V; } static GEN mkeisen(GEN E, long ord, GEN P, long lim) { long k = itou(gel(E,1)), e = itou(gel(E,4)); GEN CHI1 = gel(E,2), CHI2 = gel(E,3); if (k == 2 && mfcharistrivial(CHI1) && mfcharistrivial(CHI2)) return gsub(mkF2bd(1,lim), gmulgs(mkF2bd(e,lim), e)); else { GEN V = mfeisenstein2pure(k, CHI1, CHI2, ord, P, lim); return expandbd(V, e); } } static GEN mkM(GEN vj, long pn, GEN P, long lim) { long j, l = lg(vj), L = lim+1; GEN M = cgetg(l, t_MAT); for (j = 1; j < l; j++) { GEN E1, E2; parse_vecj(gel(vj,j), &E1,&E2); E1 = RgV_to_RgX(mkeisen(E1, pn, P, lim), 0); if (E2) { E2 = RgV_to_RgX(mkeisen(E2, pn, P, lim), 0); E1 = RgXn_mul(E1, E2, L); } E1 = RgX_to_RgC(E1, L); if (P && E2) E1 = RgXQV_red(E1, P); gel(M,j) = E1; } return M; } /* assume N > 2 */ static GEN mffindeisen1(long N) { GEN G = znstar0(utoipos(N), 1), L = chargalois(G, NULL), chi0 = NULL; long j, m = N, l = lg(L); for (j = 1; j < l; j++) { GEN chi = gel(L,j); long r = myeulerphiu(itou(zncharorder(G,chi))); if (r >= m) continue; chi = znconreyfromchar(G, chi); if (zncharisodd(G,chi)) { m = r; chi0 = chi; if (r == 1) break; } } if (!chi0) pari_err_BUG("mffindeisen1 [no Eisenstein series found]"); chi0 = znchartoprimitive(G,chi0); return mfcharGL(gel(chi0,1), gel(chi0,2)); } static GEN mfeisensteinspaceinit_i(long N, long k, GEN CHI) { GEN M, Minv, vj, vG, GN, allN, P, vz, z = NULL; long nCHI, lim, ell, ord, pn, dim = mffulldim(N, k, CHI); ulong r, p; if (!dim) retmkvec3(cgetg(1,t_VECSMALL), mkvec2(cgetg(1,t_MAT),gen_1),cgetg(1,t_VEC)); lim = mfsturmNk(N, k) + 1; allN = charsmodN(N); vG = gel(allN,3); GN = gel(vG,N); pn = znstar_get_expo(GN); ord = ord_canon(pn); P = ord == 1? NULL: polcyclo(ord, varn(mfcharpol(CHI))); CHI = induce(GN, CHI); /* lift CHI mod N before mfcharno*/ nCHI = mfcharno(CHI); r = QabM_init(ord, &p); vz = Fl_powers(r, pn, p); getcols(&M, &vj, k, nCHI, allN, vz, p, lim); for (ell = k>>1; ell >= 1; ell--) if (getcolsgen(dim, &M, &vj, &z, k, ell, nCHI, allN, vz, p, lim)) break; if (!z) update_Mj(&M, &vj, &z, p); if (lg(vj) - 1 < dim) return NULL; M = mkM(vj, pn, P, lim); Minv = QabM_Minv(rowpermute(M, gel(z,1)), P, ord); return mkvec4(gel(z,1), Minv, vj, utoi(ord)); } /* true mf */ static GEN mfeisensteinspaceinit(GEN mf) { pari_sp av = avma; GEN z, CHI = MF_get_CHI(mf); long N = MF_get_N(mf), k = MF_get_k(mf); if (!CHI) CHI = mfchartrivial(); z = mfeisensteinspaceinit_i(N, k, CHI); if (!z) { GEN E, CHIN = mffindeisen1(N), CHI0 = mfchartrivial(); z = mfeisensteinspaceinit_i(N, k+1, mfcharmul(CHI, CHIN)); if (z) E = mkvec4(gen_1, CHI0, CHIN, gen_1); else { z = mfeisensteinspaceinit_i(N, k+2, CHI); E = mkvec4(gen_2, CHI0, CHI0, utoipos(N)); } z = mkvec2(z, E); } return gerepilecopy(av, z); } /* decomposition of modular form on eisenspace */ static GEN mfeisensteindec(GEN mf, GEN F) { pari_sp av = avma; GEN M, Mindex, Mvecj, V, B, CHI; long o, ord; Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit); if (lg(Mvecj) < 5) { GEN E, e = gel(Mvecj,2), gkE = gel(e,1); long dE = itou(gel(e,4)); Mvecj = gel(Mvecj,1); E = mfeisenstein(itou(gkE), NULL, gel(e,3)); if (dE != 1) E = mfbd_E2(E, dE, gel(e,2)); /* here k = 2 */ F = mfmul(F, E); } M = gel(Mvecj, 2); if (lg(M) == 1) return cgetg(1, t_VEC); Mindex = gel(Mvecj, 1); ord = itou(gel(Mvecj,4)); V = mfcoefs(F, Mindex[lg(Mindex)-1]-1, 1); settyp(V, t_COL); CHI = mf_get_CHI(F); o = mfcharorder_canon(CHI); if (o > 1 && o != ord) { /* convert Mod(.,polcyclo(o)) to Mod(., polcyclo(N)) for o | N, * o and N both != 2 (mod 4) */ GEN z, P = gel(M,4); /* polcyclo(ord) */ long vt = varn(P); z = gmodulo(pol_xn(ord/o, vt), P); if (ord % o) pari_err_TYPE("mfeisensteindec", V); V = gsubst(liftpol_shallow(V), vt, z); } B = Minv_RgC_mul(M, vecpermute(V, Mindex)); return gerepileupto(av, B); } /*********************************************************************/ /* END EISENSPACE */ /*********************************************************************/ static GEN sertocol2(GEN S, long l) { GEN C = cgetg(l + 2, t_COL); long i; for (i = 0; i <= l; i++) gel(C, i+1) = polcoef_i(S, i, -1); return C; } /* Compute polynomial P0 such that F=E4^(k/4)P0(E6/E4^(3/2)). */ static GEN mfcanfindp0(GEN F, long k) { pari_sp ltop = avma; GEN E4, E6, V, V1, Q, W, res, M, B; long l, j; l = k/6 + 2; V = mfcoefsser(F,l); E4 = mfcoefsser(mfEk(4),l); E6 = mfcoefsser(mfEk(6),l); V1 = gdiv(V, gpow(E4, sstoQ(k,4), 0)); Q = gdiv(E6, gpow(E4, sstoQ(3,2), 0)); W = gpowers(Q, l - 1); M = cgetg(l + 1, t_MAT); for (j = 1; j <= l; j++) gel(M,j) = sertocol2(gel(W,j), l); B = sertocol2(V1, l); res = inverseimage(M, B); if (lg(res) == 1) err_space(F); return gerepilecopy(ltop, gtopolyrev(res, 0)); } /* Compute the first n+1 Taylor coeffs at tau=I of a modular form * on SL_2(Z). */ GEN mftaylor(GEN F, long n, long flreal, long prec) { pari_sp ltop = avma; GEN P0, Pm1 = gen_0, v; GEN X2 = mkpoln(3, ghalf,gen_0,gneg(ghalf)); /* (x^2-1) / 2 */ long k, m; if (!checkmf_i(F)) pari_err_TYPE("mftaylor",F); k = mf_get_k(F); if (mf_get_N(F) != 1 || k < 0) pari_err_IMPL("mftaylor for this form"); P0 = mfcanfindp0(F, k); v = cgetg(n+2, t_VEC); gel(v, 1) = RgX_coeff(P0,0); for (m = 0; m < n; m++) { GEN P1 = gdivgs(gmulsg(-(k + 2*m), RgX_shift(P0,1)), 12); P1 = gadd(P1, gmul(X2, RgX_deriv(P0))); if (m) P1 = gsub(P1, gdivgs(gmulsg(m*(m+k-1), Pm1), 144)); Pm1 = P0; P0 = P1; gel(v, m+2) = RgX_coeff(P0, 0); } if (flreal) { GEN pi2 = Pi2n(1, prec), pim4 = gmulsg(-2, pi2), VPC; GEN C = gmulsg(3, gdiv(gpowgs(ggamma(ginv(utoi(4)), prec), 8), gpowgs(pi2, 6))); /* E_4(i): */ GEN facn = gen_1; VPC = gpowers(gmul(pim4, gsqrt(C, prec)), n); C = gpow(C, sstoQ(k,4), prec); for (m = 0; m <= n; m++) { gel(v, m+1) = gdiv(gmul(C, gmul(gel(v, m+1), gel(VPC, m+1))), facn); facn = gmulgs(facn, m+1); } } return gerepilecopy(ltop, v); } #if 0 /* To be used in mfeigensearch() */ GEN mfreadratfile() { GEN eqn; pariFILE *F = pari_fopengz("rateigen300.gp"); eqn = gp_readvec_stream(F->file); pari_fclose(F); return eqn; } #endif /*****************************************************************/ /* EISENSTEIN CUSPS: COMPLEX DIRECTLY: one F_k */ /*****************************************************************/ /* CHIvec = charinit(CHI); data = [N1g/g1,N2g/g2,g1/g,g2/g,C/g1,C/g2, * (N1g/g1)^{-1},(N2g/g2)^{-1}] */ /* nm = n/m; * z1 = powers of \z_{C/g}^{(Ae/g)^{-1}}, * z2 = powers of \z_N^{A^{-1}(g1g2/C)}] * N.B. : we compute value and conjugate at the end, so it is (Ae/g)^{-1} * and not -(Ae/g)^{-1} */ static GEN eiscnm(long nm, long m, GEN CHI1vec, GEN CHI2vec, GEN data, GEN z1) { long Cg1 = data[5], s10 = (nm*data[7]) % Cg1, r10 = (nm - data[1]*s10) / Cg1; long Cg2 = data[6], s20 = (m *data[8]) % Cg2, r20 = (m - data[2]*s20) / Cg2; long j1, r1, s1; GEN T = gen_0; for (j1 = 0, r1 = r10, s1 = s10; j1 < data[3]; j1++, r1 -= data[1], s1 += Cg1) { GEN c1 = mychareval(CHI1vec, r1); if (!gequal0(c1)) { long j2, r2, s2; GEN S = gen_0; for (j2 = 0, r2 = r20, s2 = s20; j2 < data[4]; j2++, r2 -= data[2], s2 += Cg2) { GEN c2 = mychareval(CHI2vec, r2); if (!gequal0(c2)) S = gadd(S, gmul(c2, rootsof1pow(z1, s1*s2))); } T = gadd(T, gmul(c1, S)); } } return conj_i(T); } static GEN fg1g2n(long n, long k, GEN CHI1vec, GEN CHI2vec, GEN data, GEN z1, GEN z2) { pari_sp av = avma; GEN S = gen_0, D = mydivisorsu(n); long i, l = lg(D); for (i = 1; i < l; i++) { long m = D[i], nm = D[l-i]; /* n/m */ GEN u = eiscnm( nm, m, CHI1vec, CHI2vec, data, z1); GEN v = eiscnm(-nm, -m, CHI1vec, CHI2vec, data, z1); GEN w = odd(k) ? gsub(u, v) : gadd(u, v); S = gadd(S, gmul(powuu(m, k-1), w)); } return gerepileupto(av, gmul(S, rootsof1pow(z2, n))); } static GEN gausssumcx(GEN CHIvec, long prec) { GEN z, S, V = CHIvec_val(CHIvec); long m, N = CHIvec_N(CHIvec); z = rootsof1u_cx(N, prec); S = gmul(z, gel(V, N)); for (m = N-1; m >= 1; m--) S = gmul(z, gadd(gel(V, m), S)); return S; } /* Computation of Q_k(\z_N^s) as a polynomial in \z_N^s. FIXME: explicit * formula ? */ static GEN mfqk(long k, long N) { GEN X = pol_x(0), P = gsubgs(gpowgs(X,N), 1), ZI, Q, Xm1, invden; long i; ZI = cgetg(N, t_VEC); for (i = 1; i < N; i++) gel(ZI, i) = utoi(i); ZI = gdivgs(gmul(X, gtopolyrev(ZI, 0)), N); if (k == 1) return ZI; invden = RgXQ_powu(ZI, k, P); Q = gneg(X); Xm1 = gsubgs(X, 1); for (i = 2; i < k; i++) Q = gmul(X, ZX_add(gmul(Xm1, ZX_deriv(Q)), gmulsg(-i, Q))); return RgXQ_mul(Q, invden, P); } /* CHI mfchar */ /* Warning: M is a multiple of the conductor of CHI, but is NOT necessarily its modulus */ static GEN mfskcx(long k, GEN CHI, long M, long prec) { GEN S, CHIvec, P; long F, m, i, l; CHI = mfchartoprimitive(CHI, &F); CHIvec = mfcharcxinit(CHI, prec); if (F == 1) S = gdivgs(bernfrac(k), k); else { GEN Q = mfqk(k, F), V = CHIvec_val(CHIvec); S = gmul(gel(V, F), RgX_coeff(Q, 0)); for (m = 1; m < F; m++) S = gadd(S, gmul(gel(V, m), RgX_coeff(Q, m))); S = conj_i(S); } /* prime divisors of M not dividing f(chi) */ P = gel(myfactoru(u_ppo(M/F,F)), 1); l = lg(P); for (i = 1; i < l; i++) { long p = P[i]; S = gmul(S, gsubsg(1, gdiv(mychareval(CHIvec, p), powuu(p, k)))); } return gmul(gmul(gausssumcx(CHIvec, prec), S), powuu(M/F, k)); } static GEN f00_i(long k, GEN CHI1vec, GEN CHI2vec, GEN G2, GEN S, long prec) { GEN c, a; long N1 = CHIvec_N(CHI1vec), N2 = CHIvec_N(CHI2vec); if (S[2] != N1) return gen_0; c = mychareval(CHI1vec, S[3]); if (isintzero(c)) return gen_0; a = mfskcx(k, mfchardiv(CHIvec_CHI(CHI2vec), CHIvec_CHI(CHI1vec)), N1*N2, prec); a = gmul(a, conj_i(gmul(c,G2))); return gdiv(a, mulsi(-N2, powuu(S[1], k-1))); } static GEN f00(long k, GEN CHI1vec,GEN CHI2vec, GEN G1,GEN G2, GEN data, long prec) { GEN T1, T2; T2 = f00_i(k, CHI1vec, CHI2vec, G2, data, prec); if (k > 1) return T2; T1 = f00_i(k, CHI2vec, CHI1vec, G1, data, prec); return gadd(T1, T2); } /* ga in SL_2(Z), find beta [a,b;c,d] in Gamma_0(N) and mu in Z such that * beta * ga * T^u = [A',B';C',D'] with C' | N and N | B', C' > 0 */ static void mfgatogap(GEN ga, long N, long *pA, long *pC, long *pD, long *pd, long *pmu) { GEN A = gcoeff(ga,1,1), B = gcoeff(ga,1,2); GEN C = gcoeff(ga,2,1), D = gcoeff(ga,2,2), a, b, c, d; long t, Ap, Cp, B1, D1, mu; Cp = itou(bezout(muliu(A,N), C, &c, &d)); /* divides N */ t = 0; if (Cp > 1) { /* (d, N/Cp) = 1, find t such that (d - t*(A*N/Cp), N) = 1 */ long dN = umodiu(d,Cp), Q = (N/Cp * umodiu(A,Cp)) % Cp; while (ugcd(dN, Cp) > 1) { t++; dN = Fl_sub(dN, Q, Cp); } } if (t) { c = addii(c, mului(t, diviuexact(C,Cp))); d = subii(d, mului(t, muliu(A, N/Cp))); /* (d,N) = 1 */ } D1 = umodiu(mulii(d,D), N); (void)bezout(d, mulis(c,-N), &a, &b); /* = 1 */ t = 0; Ap = umodiu(addii(mulii(a,A), mulii(b,C)), N); /* (Ap,Cp) = 1 */ while (ugcd(Ap, N) > 1) { t++; Ap = Fl_add(Ap, Cp, N); } B1 = umodiu(a,N)*umodiu(B,N) + umodiu(b,N)*umodiu(D,N) + t*D1; B1 %= N; *pmu = mu = Fl_neg(Fl_div(B1, Ap, N), N); /* A', D' and d only needed modulo N */ *pd = umodiu(d, N); *pA = Ap; *pC = Cp; *pD = (D1 + Cp*mu) % N; } #if 0 /* CHI is a mfchar, return alpha(CHI) */ static long mfalchi(GEN CHI, long AN, long cg) { GEN G = gel(CHI,1), chi = gel(CHI,2), go = gmfcharorder(CHI); long o = itou(go), a = itos( znchareval(G, chi, stoi(1 + AN/cg), go) ); if (a < 0 || (cg * a) % o) pari_err_BUG("mfalchi"); return (cg * a) / o; } #endif /* return A such that CHI1(t) * CHI2(t) = e(A) or NULL if (t,N1*N2) > 1 */ static GEN mfcharmuleval(GEN CHI1vec, GEN CHI2vec, long t) { long a1 = mycharexpo(CHI1vec, t), o1 = CHIvec_ord(CHI1vec); long a2 = mycharexpo(CHI2vec, t), o2 = CHIvec_ord(CHI2vec);; if (a1 < 0 || a2 < 0) return NULL; return sstoQ(a1*o2 + a2*o1, o1*o2); } static GEN mfcharmulcxeval(GEN CHI1vec, GEN CHI2vec, long t, long prec) { GEN A = mfcharmuleval(CHI1vec, CHI2vec, t); long n, d; if (!A) return gen_0; Qtoss(A, &n,&d); return rootsof1q_cx(n, d, prec); } /* alpha(CHI1 * CHI2) */ static long mfalchi2(GEN CHI1vec, GEN CHI2vec, long AN, long cg) { GEN A = mfcharmuleval(CHI1vec, CHI2vec, 1 + AN/cg); long a; if (!A) pari_err_BUG("mfalchi2"); A = gmulsg(cg, A); if (typ(A) != t_INT) pari_err_BUG("mfalchi2"); a = itos(A) % cg; if (a < 0) a += cg; return a; } /* return g = (a,b), set u >= 0 s.t. g = a * u (mod b) */ static long mybezout(long a, long b, long *pu) { long junk, g = cbezout(a, b, pu, &junk); if (*pu < 0) *pu += b/g; return g; } /* E = [k, CHI1,CHI2, e], CHI1 and CHI2 primitive mfchars such that, * CHI1(-1)*CHI2(-1) = (-1)^k; expansion of (B_e (E_k(CHI1,CHI2))) | ga. * w is the width for the space of the calling function. */ static GEN mfeisensteingacx(GEN E, long w, GEN ga, long lim, long prec) { GEN CHI1vec, CHI2vec, CHI1 = gel(E,2), CHI2 = gel(E,3), v, S, ALPHA; GEN G1, G2, z1, z2, data; long k = itou(gel(E,1)), e = itou(gel(E,4)); long N1 = mfcharmodulus(CHI1); long N2 = mfcharmodulus(CHI2), N = e * N1 * N2; long NsurC, cg, wN, A, C, Ai, d, mu, alchi, na, da; long eg, g, gH, U, u0, u1, u2, Aig, H, m, n, t, Cg, NC1, NC2; mfgatogap(ga, N, &A, &C, &Ai, &d, &mu); CHI1vec = mfcharcxinit(CHI1, prec); CHI2vec = mfcharcxinit(CHI2, prec); NsurC = N/C; cg = ugcd(C, NsurC); wN = NsurC / cg; if (w%wN) pari_err_BUG("mfeisensteingacx [wN does not divide w]"); alchi = mfalchi2(CHI1vec, CHI2vec, A*N, cg); ALPHA = sstoQ(alchi, NsurC); g = mybezout(A*e, C, &u0); Cg = C/g; eg = e/g; NC1 = mybezout(N1, Cg, &u1); NC2 = mybezout(N2, Cg, &u2); H = (NC1*NC2*g)/Cg; Aig = (Ai*H)%N; if (Aig < 0) Aig += N; z1 = rootsof1powinit(u0, Cg, prec); z2 = rootsof1powinit(Aig, N, prec); data = mkvecsmalln(8, N1/NC1, N2/NC2, NC1, NC2, Cg/NC1, Cg/NC2, u1, u2); v = zerovec(lim + 1); /* need n*H = alchi (mod cg) */ gH = mybezout(H, cg, &U); if (gH > 1) { if (alchi % gH) return mkvec2(gen_0, v); alchi /= gH; cg /= gH; H /= gH; } G1 = gausssumcx(CHI1vec, prec); G2 = gausssumcx(CHI2vec, prec); if (!alchi) gel(v,1) = f00(k, CHI1vec,CHI2vec,G1,G2, mkvecsmall3(NC2,Cg,A*eg), prec); n = Fl_mul(alchi,U,cg); if (!n) n = cg; m = (n*H - alchi) / cg; /* positive, exact division */ for (; m <= lim; n+=cg, m+=H) gel(v, m+1) = fg1g2n(n, k, CHI1vec, CHI2vec, data, z1,z2); t = (2*e)/g; if (odd(k)) t = -t; v = gdiv(v, gmul(conj_i(gmul(G1,G2)), mulsi(t, powuu(eg*N2/NC2, k-1)))); if (k == 2 && N1 == 1 && N2 == 1) v = gsub(mkF2bd(wN,lim), gmulsg(e,v)); Qtoss(ALPHA, &na,&da); S = conj_i( mfcharmulcxeval(CHI1vec,CHI2vec,d,prec) ); /* CHI(1/d) */ if (wN > 1) { GEN z = rootsof1powinit(-mu, wN, prec); long i, l = lg(v); for (i = 1; i < l; i++) gel(v,i) = gmul(gel(v,i), rootsof1pow(z,i-1)); } v = RgV_Rg_mul(v, gmul(S, rootsof1q_cx(-mu*na, da, prec))); return mkvec2(ALPHA, bdexpand(v, w/wN)); } /*****************************************************************/ /* END EISENSTEIN CUSPS */ /*****************************************************************/ static GEN mfchisimpl(GEN CHI) { GEN G, chi; if (typ(CHI) == t_INT) return CHI; G = gel(CHI, 1); chi = gel(CHI, 2); switch(mfcharorder(CHI)) { case 1: chi = gen_1; break; case 2: chi = znchartokronecker(G,chi,1); break; default:chi = mkintmod(znconreyexp(G,chi), znstar_get_N(G)); break; } return chi; } GEN mfparams(GEN F) { pari_sp av = avma; GEN z, mf; if ((mf = checkMF_i(F))) { long N = MF_get_N(mf); GEN gk = MF_get_gk(mf); z = mkvec4(utoi(N), gk, MF_get_CHI(mf), utoi(MF_get_space(mf))); } else { if (!checkmf_i(F)) pari_err_TYPE("mfparams", F); z = shallowcopy( mf_get_NK(F) ); } gel(z,3) = mfchisimpl(gel(z,3)); return gerepilecopy(av, z); } GEN mfisCM(GEN F) { pari_sp av = avma; forprime_t S; GEN D, v; long N, k, lD, sb, p, i; if (!checkmf_i(F)) pari_err_TYPE("mfisCM", F); N = mf_get_N(F); k = mf_get_k(F); if (N < 0 || k < 0) pari_err_IMPL("mfisCM for this F"); D = mfunram(N, -1); lD = lg(D); sb = maxss(mfsturmNk(N, k), 4*N); v = mfcoefs_i(F, sb, 1); u_forprime_init(&S, 2, sb); while ((p = u_forprime_next(&S))) { GEN ap = gel(v, p+1); if (!gequal0(ap)) for (i = 1; i < lD; i++) if (kross(D[i], p) == -1) { D = vecsplice(D, i); lD--; } } if (lD == 1) { avma = av; return gen_0; } if (lD == 2) { avma = av; return stoi(D[1]); } if (k > 1) pari_err_BUG("mfisCM"); return gerepileupto(av, zv_to_ZV(D)); } static long mfspace_i(GEN mf, GEN F) { GEN v, vF, gk; long n, nE, i, l, s, N; mf = checkMF(mf); s = MF_get_space(mf); if (!F) return s; if (!checkmf_i(F)) pari_err_TYPE("mfspace",F); v = mftobasis(mf, F, 1); n = lg(v)-1; if (!n) return -1; nE = lg(MF_get_E(mf))-1; switch(s) { case mf_NEW: case mf_OLD: case mf_EISEN: return s; case mf_FULL: if (mf_get_type(F) == t_MF_THETA) return mf_EISEN; if (!gequal0(vecslice(v,1,nE))) return gequal0(vecslice(v,nE+1,n))? mf_EISEN: mf_FULL; } /* mf is mf_CUSP or mf_FULL, F a cusp form */ gk = mf_get_gk(F); if (typ(gk) == t_FRAC || equali1(gk)) return mf_CUSP; vF = mftonew_i(mf, vecslice(v, nE+1, n), &N); if (N != MF_get_N(mf)) return mf_OLD; l = lg(vF); for (i = 1; i < l; i++) if (itos(gmael(vF,i,1)) != N) return mf_CUSP; return mf_NEW; } long mfspace(GEN mf, GEN F) { pari_sp av = avma; long s = mfspace_i(mf,F); avma = av; return s; } static GEN lfunfindchi(GEN ldata, GEN van, long prec) { GEN gN = ldata_get_conductor(ldata), G = znstar0(gN,1), L, go, vz; long k = ldata_get_k(ldata), N = itou(gN), bit = 10 - prec2nbits(prec); long i, j, o, l, odd = k & 1, B0 = 2, B = lg(van)-1; van = shallowcopy(van); L = cyc2elts(znstar_get_conreycyc(G)); l = lg(L); for (i = j = 1; i < l; i++) { GEN chi = zc_to_ZC(gel(L,i)); if (zncharisodd(G,chi) == odd) gel(L,j++) = mfcharGL(G,chi); } setlg(L,j); l = j; if (l <= 2) return gel(L,1); o = znstar_get_expo(G); go = utoi(o); vz = grootsof1(o, prec); for (;;) { long n; for (n = B0; n <= B; n++) { GEN an = gel(van,n), r; long j; if (ugcd(n, N) != 1 || gexpo(an) < bit) continue; r = gdiv(an, conj_i(an)); for (i = 1; i < l; i++) { GEN CHI = gel(L,i); if (gexpo(gsub(r, gel(vz, znchareval_i(CHI,n,go)+1))) > bit) gel(L,i) = NULL; } for (i = j = 1; i < l; i++) if (gel(L,i)) gel(L,j++) = gel(L,i); l = j; setlg(L,l); if (l == 2) return gel(L,1); } B0 = B+1; B <<= 1; van = ldata_vecan(ldata_get_an(ldata), B, prec); } } GEN mffromlfun(GEN L, long prec) { pari_sp av = avma; GEN ldata = lfunmisc_to_ldata_shallow(L), Vga = ldata_get_gammavec(ldata); GEN van, a0, CHI, NK; long k, N, space; if (!gequal(Vga, mkvec2(gen_0, gen_1))) pari_err_TYPE("mffromlfun", L); k = ldata_get_k(ldata); N = itou(ldata_get_conductor(ldata)); van = ldata_vecan(ldata_get_an(ldata), mfsturmNk(N,k) + 2, prec); CHI = lfunfindchi(ldata, van, prec); space = (lg(ldata) == 7)? mf_CUSP: mf_FULL; a0 = (space == mf_CUSP)? gen_0: gneg(lfun(L, gen_0, prec2nbits(prec))); NK = mkvec3(utoi(N), utoi(k), mfchisimpl(CHI)); return gerepilecopy(av, mkvec3(NK, utoi(space), shallowconcat(a0, van))); } /*******************************************************************/ /* */ /* HALF-INTEGRAL WEIGHT */ /* */ /*******************************************************************/ /* We use the prefix mf2; k represents the weight -1/2, so e.g. k = 2 is weight 5/2. N is the level, so 4\mid N, and CHI is the character, always even. */ static long lamCO(long r, long s, long p) { if ((s << 1) <= r) { long rp = r >> 1; if (odd(r)) return upowuu(p, rp) << 1; else return (p + 1)*upowuu(p, rp - 1); } else return upowuu(p, r - s) << 1; } static int condC(GEN faN, GEN valF) { GEN P = gel(faN, 1), E = gel(faN, 2); long l = lg(P), i; for (i = 1; i < l; i++) if ((P[i] & 3L) == 3) { long r = E[i]; if (odd(r) || r < (valF[i] << 1)) return 1; } return 0; } /* returns 2*zetaCO; weight is k + 1/2 */ static long zeta2CO(GEN faN, GEN valF, long r2, long s2, long k) { if (r2 >= 4) return lamCO(r2, s2, 2) << 1; if (r2 == 3) return 6; if (condC(faN, valF)) return 4; if (odd(k)) return s2 ? 3 : 5; else return s2 ? 5: 3; } /* returns 4 times last term in formula */ static long dim22(long N, long F, long k) { pari_sp av = avma; GEN vF, faN = myfactoru(N), P = gel(faN, 1), E = gel(faN, 2); long i, D, l = lg(P); vF = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) vF[i] = u_lval(F, P[i]); D = zeta2CO(faN, vF, E[1], vF[1], k); for (i = 2; i < l; i++) D *= lamCO(E[i], vF[i], P[i]); avma = av; return D; } /* PSI not necessarily primitive, of conductor F */ static int charistotallyeven(GEN PSI, long F) { pari_sp av = avma; GEN P = gel(myfactoru(F), 1); GEN G = gel(PSI,1), psi = gel(PSI,2); long i; for (i = 1; i < lg(P); i++) { GEN psip = znchardecompose(G, psi, utoipos(P[i])); if (zncharisodd(G, psip)) { avma = av; return 0; } } avma = av; return 1; } static GEN get_PSI(GEN CHI, long t) { long r = t & 3L, t2 = (r == 2 || r == 3) ? t << 2 : t; return mfcharmul_i(CHI, induce(gel(CHI,1), utoipos(t2))); } /* space = mf_CUSP, mf_EISEN or mf_FULL, weight k + 1/2 */ static long mf2dimwt12(long N, GEN CHI, long space) { pari_sp av = avma; GEN D = mydivisorsu(N >> 2); long i, l = lg(D), dim3 = 0, dim4 = 0; CHI = induceN(N, CHI); for (i = 1; i < l; i++) { long rp, t = D[i], Mt = D[l-i]; GEN PSI = get_PSI(CHI,t); rp = mfcharconductor(PSI); if (Mt % (rp*rp) == 0) { dim4++; if (charistotallyeven(PSI,rp)) dim3++; } } avma = av; switch (space) { case mf_CUSP: return dim4 - dim3; case mf_EISEN:return dim3; case mf_FULL: return dim4; } return 0; /*LCOV_EXCL_LINE*/ } static long mf2dimwt32(long N, GEN CHI, long F, long space) { long D; switch(space) { case mf_CUSP: D = mypsiu(N) - 6*dim22(N, F, 1); if (D%24) pari_err_BUG("mfdim"); return D/24 + mf2dimwt12(N, CHI, 4); case mf_FULL: D = mypsiu(N) + 6*dim22(N, F, 0); if (D%24) pari_err_BUG("mfdim"); return D/24 + mf2dimwt12(N, CHI, 1); case mf_EISEN: D = dim22(N, F, 0) + dim22(N, F, 1); if (D & 3L) pari_err_BUG("mfdim"); return (D >> 2) - mf2dimwt12(N, CHI, 3); } return 0; /*LCOV_EXCL_LINE*/ } /* F = conductor(CHI), weight k = r+1/2 */ static long checkmf2(long N, long r, GEN CHI, long F, long space) { switch(space) { case mf_FULL: case mf_CUSP: case mf_EISEN: break; case mf_NEW: case mf_OLD: pari_err_TYPE("half-integral weight [new/old spaces]", utoi(space)); default: pari_err_TYPE("half-integral weight [incorrect space]",utoi(space)); } if (N & 3L) pari_err_DOMAIN("half-integral weight", "N % 4", "!=", gen_0, stoi(N)); return r >= 0 && mfcharparity(CHI) == 1 && N % F == 0; } /* weight k = r + 1/2 */ static long mf2dim_Nkchi(long N, long r, GEN CHI, ulong space) { long D, D2, F = mfcharconductor(CHI); if (!checkmf2(N, r, CHI, F, space)) return 0; if (r == 0) return mf2dimwt12(N, CHI, space); if (r == 1) return mf2dimwt32(N, CHI, F, space); if (space == mf_EISEN) { D = dim22(N, F, r) + dim22(N, F, 1-r); if (D & 3L) pari_err_BUG("mfdim"); return D >> 2; } D2 = space == mf_FULL? dim22(N, F, 1-r): -dim22(N, F, r); D = (2*r-1)*mypsiu(N) + 6*D2; if (D%24) pari_err_BUG("mfdim"); return D/24; } /* weight k=r+1/2 */ static GEN mf2init_Nkchi(long N, long r, GEN CHI, long space, long flraw) { GEN Minv, Minvmat, B, M, gk = gaddsg(r,ghalf); GEN mf1 = mkvec4(utoi(N),gk,CHI,utoi(space)); long L; if (!checkmf2(N, r, CHI, mfcharconductor(CHI), space)) return mfEMPTY(mf1); if (space==mf_EISEN) pari_err_IMPL("half-integral weight Eisenstein space"); L = mfsturmNgk(N, gk) + 1; B = mf2basis(N, r, CHI, space); M = mflineardivtomat(N,B,L); if (flraw) M = mkvec3(gen_0,gen_0,M); else { M = mfcleanCHI(M, CHI, 0); Minv = gel(M,2); Minvmat = RgM_Minv_mul(NULL, Minv); B = vecmflineardiv_linear(B, Minvmat); gel(M,3) = RgM_Minv_mul(gel(M,3), Minv); gel(M,2) = mkMinv(matid(lg(B)-1), NULL,NULL,NULL); } return mkmf(mf1, cgetg(1,t_VEC), B, gen_0, M); } /**************************************************************************/ /* Kohnen + space */ /**************************************************************************/ static GEN mfkohnenbasis_i(GEN mf, GEN CHIP, long eps, long sb) { GEN M = shallowtrans(mfcoefs_mf(mf, sb, 1)), ME; long c, i, n; ME = cgetg(sb + 2, t_MAT); for (i = 0, c = 1; i <= sb; i++) { long j = i & 3L; if (j == 2 || j == 2 + eps) gel(ME, c++) = gel(M, i+1); } setlg(ME, c); ME = shallowtrans(Q_primpart(ME)); n = mfcharorder_canon(CHIP); return n == 1? ZM_ker(ME): ZabM_ker(liftpol_shallow(ME), mfcharpol(CHIP), n); } GEN mfkohnenbasis(GEN mf) { pari_sp av = avma; GEN gk, CHI, CHIP, K; long N4, r, eps, sb; mf = checkMF(mf); if (MF_get_space(mf) != mf_CUSP) pari_err_TYPE("mfkohnenbasis [not a cuspidal space", mf); if (!MF_get_dim(mf)) return cgetg(1, t_MAT); N4 = MF_get_N(mf) >> 2; gk = MF_get_gk(mf); CHI = MF_get_CHI(mf); if (typ(gk) == t_INT) pari_err_TYPE("mfkohnenbasis", gk); r = MF_get_r(mf); CHIP = mfcharchiliftprim(CHI, N4); eps = CHIP==CHI? 1: -1; if (!CHIP) pari_err_TYPE("mfkohnenbasis [incorrect CHI]", CHI); if (odd(r)) eps = -eps; if (uissquarefree(N4)) { long d = mfdim_Nkchi(N4, 2*r, mfcharpow(CHI, gen_2), mf_CUSP); sb = mfsturmNgk(N4 << 2, gk) + 1; K = mfkohnenbasis_i(mf, CHIP, eps, sb); if (lg(K) - 1 == d) return gerepilecopy(av, K); } sb = mfsturmNgk(N4 << 4, gk) + 1; K = mfkohnenbasis_i(mf, CHIP, eps, sb); return gerepilecopy(av, K); } /* return [mf3, bijection, mfkohnenbasis, codeshi] */ static GEN mfkohnenbijection_i(GEN mf) { GEN vB, mf3, K, SHI, P, CHI = MF_get_CHI(mf); long n, lK, i, dim, m, lw, sb3, N4 = MF_get_N(mf)>>2, r = MF_get_r(mf); long Dp[] = {1, 5, 8, 12, 13, 17, 21, 24}; long Dm[] = {-3, -4, -7, -8, -11, -15, -19, -20}, *D = odd(r)? Dm: Dp; const long nbD = 8, MAXm = 6560; /* #D, 3^#D - 1 */ K = mfkohnenbasis(mf); lK = lg(K); mf3 = mfinit_Nkchi(N4, r<<1, mfcharpow(CHI,gen_2), mf_CUSP, 0); if (MF_get_dim(mf3) != lK - 1) pari_err_BUG("mfkohnenbijection [different dimensions]"); if (lK == 1) return mkvec4(mf3, cgetg(1, t_MAT), K, cgetg(1, t_VEC)); CHI = mfcharchiliftprim(CHI, N4); if (!CHI) pari_err_TYPE("mfkohnenbijection [incorrect CHI]", CHI); n = mfcharorder_canon(CHI); P = n==1? NULL: mfcharpol(CHI); SHI = cgetg(nbD+1, t_VEC); sb3 = mfsturm(mf3); vB = RgM_mul(mfcoefs_mf(mf, labs(D[nbD-1])*sb3*sb3, 1), K); dim = MF_get_dim(mf3); for (m = 1, lw = 0; m <= MAXm; m += (m%3)? 2: 1) { pari_sp av; ulong m1, y, v = u_lvalrem(m, 3, &y); GEN z, M; long j; if (y == 1) { long d = D[v]; GEN a = cgetg(lK, t_MAT); for (i = 1; i < lK; i++) { pari_sp av2 = avma; GEN f = c_deflate(sb3*sb3, labs(d), gel(vB,i)); f = mftobasis_i(mf3, RgV_shimura(f, sb3, d, N4, r, CHI)); gel(a,i) = gerepileupto(av2, f); } lw++; gel(SHI,v+1) = a; } av = avma; M = NULL; for (j = 1, m1 = m; j <= lw; j++, m1/=3) { long s = m1%3; if (s) { GEN t = gel(SHI,j); if (M) M = (s == 2)? RgM_sub(M, t): RgM_add(M, t); else M = (s == 2)? RgM_neg(t): t; } } z = QabM_indexrank(M,P,n); if (lg(gel(z,2)) > dim) { GEN d = ZV_to_zv( digits(utoipos(m), utoipos(3)) ); GEN mres, dMi, Mi = QabM_pseudoinv(M,P,n, NULL,&dMi); long ld = lg(d), c = 1; if (DEBUGLEVEL>1) err_printf("mfkohnenbijection: used %ld discriminants\n",lw); mres = cgetg(ld, t_VEC); for (j = ld-1; j >= 1; j--) if (d[j]) gel(mres,c++) = mkvec2s(D[ld-j-1], d[j]); setlg(mres,c); return mkvec4(mf3, RgM_Rg_div(Mi,dMi), K, mres); } avma = av; } pari_err_BUG("mfkohnenbijection"); return NULL; /*LCOV_EXCL_LINE*/ } GEN mfkohnenbijection(GEN mf) { pari_sp av = avma; long N; mf = checkMF(mf); N = MF_get_N(mf); if (!uissquarefree(N >> 2)) pari_err_TYPE("mfkohnenbijection [N/4 not squarefree]", utoi(N)); if (MF_get_space(mf) != mf_CUSP || MF_get_r(mf) == 0 || !mfshimura_space_cusp(mf)) pari_err_TYPE("mfkohnenbijection [incorrect mf for Kohnen]", mf); return gerepilecopy(av, mfkohnenbijection_i(mf)); } static int checkbij_i(GEN b) { return typ(b) == t_VEC && lg(b) == 5 && checkMF_i(gel(b,1)) && typ(gel(b,2)) == t_MAT && typ(gel(b,3)) == t_MAT && typ(gel(b,4)) == t_VEC; } /* bij is the output of mfkohnenbijection */ GEN mfkohneneigenbasis(GEN mf, GEN bij) { pari_sp av = avma; GEN mf3, mf30, B, KM, M, k; long r, i, l, N4; mf = checkMF(mf); if (!checkbij_i(bij)) pari_err_TYPE("mfkohneneigenbasis [bijection]", bij); if (MF_get_space(mf) != mf_CUSP) pari_err_TYPE("mfkohneneigenbasis [not a cuspidal space]", mf); if (!MF_get_dim(mf)) retmkvec3(cgetg(1, t_VEC), cgetg(1, t_VEC), cgetg(1, t_VEC)); N4 = MF_get_N(mf) >> 2; k = MF_get_gk(mf); if (typ(k) == t_INT) pari_err_TYPE("mfkohneneigenbasis", k); if (!uissquarefree(N4)) pari_err_TYPE("mfkohneneigenbasis [N not squarefree]", utoipos(N4)); r = MF_get_r(mf); KM = RgM_mul(gel(bij,3), gel(bij,2)); mf3 = gel(bij,1); mf30 = mfinit_Nkchi(N4, 2*r, MF_get_CHI(mf3), mf_NEW, 0); B = mfcoefs_mf(mf30, mfsturm_mf(mf3), 1); l = lg(B); M = cgetg(l, t_MAT); for (i=1; i 0, N >= 0 */ static GEN mfEHcoef(long r, long N) { long D0, f, i, l; GEN S, Df; if (r == 1) return hclassno(utoi(N)); if (N == 0) return gdivgs(bernfrac(2*r), -2*r); if (r&1L) { long s = N&3L; if (s == 2 || s == 1) return gen_0; D0 = mycoredisc2neg(N,&f); } else { long s = N&3L; if (s == 2 || s == 3) return gen_0; D0 = mycoredisc2pos(N,&f); } Df = mydivisorsu(u_pporad(f, D0)); l = lg(Df); S = gen_0; for (i = 1; i < l; i++) { long d = Df[i], s = mymoebiusu(d)*kross(D0, d); /* != 0 */ GEN c = gmul(powuu(d, r-1), mysumdivku(f/d, 2*r-1)); S = s > 0? addii(S, c): subii(S, c); } return gmul(lfunquadneg(D0, r), S); } static GEN mfEHmat(long lim, long r) { long j, l, d = r/2; GEN f2, th4, th3, v, vth4, vf2; c_F2TH4(lim, &f2, &th4); f2 = RgV_to_ser(f2, 0, lim+3); th4 = RgV_to_ser(th4, 0, lim+3); th3 = RgV_to_ser(c_theta(lim, 1, mfchartrivial()), 0, lim+3); if (odd(r)) th3 = gpowgs(th3, 3); vth4 = gpowers(th4, d); vf2 = gpowers0(f2, d, th3); /* th3 f2^j */ l = d+2; v = cgetg(l, t_VEC); for (j = 1; j < l; j++) gel(v, j) = ser2rfrac_i(gmul(gel(vth4, l-j), gel(vf2, j))); return RgXV_to_RgM(v, lim); } static GEN Hfind(long r, GEN *pden) { long lim = (r/2)+3, i; GEN res, M, B; if (r <= 0) pari_err_DOMAIN("mfEH", "r", "<=", gen_0, stoi(r)); M = mfEHmat(lim, r); B = cgetg(lim+1, t_COL); for (i = 1; i <= lim; i++) gel(B, i) = mfEHcoef(r, i-1); res = inverseimage(M, B); if (lg(res) == 1) pari_err_BUG("mfEH"); return Q_remove_denom(res,pden); } GEN mfEH(GEN gk) { pari_sp av = avma; GEN v, d, NK, gr = gsub(gk, ghalf); long r; if (typ(gr) != t_INT) pari_err_TYPE("mfEH", gk); r = itos(gr); switch (r) { case 1: v=cgetg(1,t_VEC); d=gen_1; break; case 2: v=mkvec2s(1,-20); d=utoipos(120); break; case 3: v=mkvec2s(-1,14); d=utoipos(252); break; case 4: v=mkvec3s(1,-16,16); d=utoipos(240); break; case 5: v=mkvec3s(-1,22,-88); d=utoipos(132); break; case 6: v=mkvec4s(691,-18096,110136,-4160); d=utoipos(32760); break; case 7: v=mkvec4s(-1,30,-240,224); d=utoipos(12); break; default: v = Hfind(r, &d); break; } NK = mkgNK(utoipos(4), gaddgs(ghalf,r), mfchartrivial(), pol_x(1)); return gerepilecopy(av, tag(t_MF_EISEN, NK, mkvec2(v,d))); } /**********************************************************/ /* T(f^2) for half-integral weight */ /**********************************************************/ /* T_p^2 V, p2 = p^2, c1 = chi(p) (-1/p)^r p^(r-1), c2 = chi(p^2)*p^(2r-1) */ static GEN tp2apply(GEN V, long p, long p2, GEN c1, GEN c2) { long lw = (lg(V) - 2)/p2 + 1, m, n; GEN a0 = gel(V,1), W = cgetg(lw + 1, t_VEC); gel(W,1) = gequal0(a0)? gen_0: gmul(a0, gaddsg(1, c2)); for (n = 1; n < lw; n++) { GEN c = gel(V, p2*n + 1); if (n%p) c = gadd(c, gmulsg(kross(n,p), gmul(gel(V,n+1), c1))); gel(W, n+1) = c; /* a(p^2*n) + c1 * (n/p) a(n) */ } for (m = 1, n = p2; n < lw; m++, n += p2) gel(W, n+1) = gadd(gel(W,n+1), gmul(gel(V,m+1), c2)); return W; } /* T_{p^{2e}} V; can derecursify [Purkait, Hecke operators in half-integral * weight, Prop 4.3], not worth it */ static GEN tp2eapply(GEN V, long p, long p2, long e, GEN q, GEN c1, GEN c2) { GEN V4 = NULL; if (e > 1) { V4 = vecslice(V, 1, (lg(V) - 2)/(p2*p2) + 1); V = tp2eapply(V, p, p2, e-1, q, c1, c2); } V = tp2apply(V, p, p2, c1, c2); if (e > 1) V = gsub(V, (e == 2)? gmul(q, V4) : gmul(c2, tp2eapply(V4, p, p2, e-2, q, c1, c2))); return V; } /* weight k = r+1/2 */ static GEN RgV_heckef2(long n, long d, GEN V, GEN F, GEN DATA) { GEN CHI = mf_get_CHI(F), fa = gel(DATA,1), P = gel(fa,1), E = gel(fa,2); long i, l = lg(P), r = mf_get_r(F), s4 = odd(r)? -4: 4, k2m2 = (r<<1)-1; if (typ(V) == t_COL) V = shallowtrans(V); for (i = 1; i < l; i++) { /* p does not divide N */ long p = P[i], e = E[i], p2 = p*p; GEN c1, c2, a, b, q = NULL, C = mfchareval_i(CHI,p), C2 = gsqr(C); a = r? powuu(p,r-1): mkfrac(gen_1,utoipos(p)); /* p^(r-1) = p^(k-3/2) */ b = r? mulii(powuu(p,r), a): a; /* p^(2r-1) = p^(2k-2) */ c1 = gmul(C, gmulsg(kross(s4,p),a)); c2 = gmul(C2, b); if (e > 1) { q = r? powuu(p,k2m2): a; if (e == 2) q = gmul(q, sstoQ(p+1,p)); /* special case T_{p^4} */ q = gmul(C2, q); /* chi(p^2) [ p^(2k-2) or (p+1)p^(2k-3) ] */ } V = tp2eapply(V, p, p2, e, q, c1, c2); } return c_deflate(n, d, V); } static GEN GL2toSL2(GEN g, GEN *abd) { GEN A, B, C, D, u, v, a, b, d, q; g = Q_primpart(g); if (!check_M2Z(g)) pari_err_TYPE("GL2toSL2", g); A = gcoeff(g,1,1); B = gcoeff(g,1,2); C = gcoeff(g,2,1); D = gcoeff(g,2,2); a = bezout(A, C, &u, &v); if (!equali1(a)) { A = diviiexact(A,a); C = diviiexact(C,a); } d = subii(mulii(A,D), mulii(B,C)); if (signe(d) <= 0) pari_err_TYPE("GL2toSL2",g); q = dvmdii(addii(mulii(u,B), mulii(v,D)), d, &b); *abd = (equali1(a) && equali1(d))? NULL: mkvec3(a, b, d); return mkmat22(A, subii(mulii(q,A), v), C, addii(mulii(q,C), u)); } static GEN Rg_approx(GEN t, long bit) { GEN a = real_i(t), b = imag_i(t); long e1 = gexpo(a), e2 = gexpo(b); if (e2 < -bit) { t = e1 < -bit? gen_0: a; } else if (e1 < -bit) t = gmul(b, gen_I()); return t; } static GEN RgV_approx(GEN v, long bit) { long i, l = lg(v); GEN w = cgetg_copy(v, &l); for (i = 1; i < lg(v); i++) gel(w,i) = Rg_approx(gel(v,i), bit); return w; } /* m != 2 (mod 4), D t_INT; V has "denominator" D, recognize in Q(zeta_m) */ static GEN bestapprnf2(GEN V, long m, GEN D, long prec) { long i, j, f, vt = fetch_user_var("t"), bit = prec2nbits_mul(prec, 0.8); GEN Tinit, Vl, H, Pf, P = polcyclo(m, vt); V = liftpol_shallow(V); V = gmul(RgV_approx(V, bit), D); V = bestapprnf(V, P, NULL, prec); Vl = liftpol_shallow(V); H = coprimes_zv(m); for (i = 2; i < m; i++) { if (H[i] != 1) continue; if (!gequal(Vl, vecGalois(Vl, i, P))) H[i] = 0; else for (j = i; j < m; j *= i) H[i] = 3; } f = znstar_conductor_bits(Flv_to_F2v(H)); if (f == 1) return gdiv(V, D); if (f == m) return gmodulo(gdiv(V, D), P); Tinit = Qab_trace_init(P, m, f); Pf = gel(Tinit,1); Vl = QabV_tracerel(Tinit, 0, Vl); return gmodulo(gdiv(Vl, muliu(D, degpol(P)/degpol(Pf))), Pf); } /* f | ga expansion; [f, mf_eisendec(f)]~ allowed */ GEN mfslashexpansion(GEN mf, GEN f, GEN ga, long n, long flrat, GEN *params, long prec) { pari_sp av = avma; GEN a, b, d, res, al, V, M, ad, abd, gk, A, awd = NULL; long i, w; mf = checkMF(mf); gk = MF_get_gk(mf); M = GL2toSL2(ga, &abd); if (abd) { a = gel(abd,1); b = gel(abd,2); d = gel(abd,3); } else { a = d = gen_1; b = gen_0; } ad = gdiv(a,d); res = mfgaexpansion(mf, f, M, n, prec); al = gel(res,1); w = itou(gel(res,2)); V = gel(res,3); if (flrat) { GEN CHI = MF_get_CHI(mf); long N = MF_get_N(mf), F = mfcharconductor(CHI); long ord = mfcharorder_canon(CHI), k, deg; long B = umodiu(gcoeff(M,1,2), N); long C = umodiu(gcoeff(M,2,1), N); long D = umodiu(gcoeff(M,2,2), N); long CD = (C * D) % N, BC = (B * C) % F; GEN CV, t; /* weight of f * Theta in 1/2-integral weight */ k = typ(gk) == t_INT? itou(gk): MF_get_r(mf)+1; CV = odd(k) ? powuu(N, k - 1) : powuu(N, k >> 1); deg = ulcm(ulcm(ord, N/ugcd(N,CD)), F/ugcd(F,BC)); V = bestapprnf2(V, deg, CV, prec); if (abd && !signe(b)) { /* can [a,0; 0,d] be simplified to id ? */ long nk, dk; Qtoss(gk, &nk, &dk); if (ispower(ad, utoipos(2*dk), &t)) /* t^(2*dk) = a/d or t = NULL */ { V = RgV_Rg_mul(V, powiu(t,nk)); awd = gdiv(a, muliu(d,w)); } } } else if (abd) { /* ga = M * [a,b;0,d] * rational, F := f | M = q^al * \sum V[j] q^(j/w) */ GEN u, t = NULL, wd = muliu(d,w); /* a > 0, 0 <= b < d; f | ga = (a/d)^(k/2) * F(tau + b/d) */ if (signe(b)) { long ns, ds; GEN z; Qtoss(gdiv(b, wd), &ns, &ds); z = rootsof1powinit(ns, ds, prec); for (i = 1; i <= n+1; i++) gel(V,i) = gmul(gel(V,i), rootsof1pow(z, i-1)); if (!gequal0(al)) t = gexp(gmul(PiI2(prec), gmul(al, gdiv(b,d))), prec); } awd = gdiv(a, wd); u = gpow(ad, gmul2n(gk,-1), prec); t = t? gmul(t, u): u; V = RgV_Rg_mul(V, t); } if (!awd) A = mkmat22(a, b, gen_0, d); else { /* rescale and update w from [a,0; 0,d] */ long ns; Qtoss(awd, &ns, &w); /* update w */ V = bdexpand(V, ns); if (!gequal0(al)) { GEN adal = gmul(ad, al), sh = gfloor(adal); al = gsub(adal, sh); V = RgV_shift(V, sh); } A = matid(2); } if (params) *params = mkvec3(al, utoipos(w), A); gerepileall(av,params?2:1,&V,params); return V; } /**************************************************************/ /* Alternative method for 1/2-integral weight */ /**************************************************************/ static GEN mf2basis(long N, long r, GEN CHI, long space) { GEN CHI1, CHI2, mf1, mf2, B1, B2, BT1, BT2, M1, M2, M, T1, T2; GEN M2I, K, POLCYC, v, den; long sb, k1, N2, ordchi; k1 = r + 1; if (odd(k1)) { CHI1 = mfcharmul(CHI, get_mfchar(stoi(-4))); CHI2 = mfcharmul(CHI, get_mfchar(stoi(-8))); } else { CHI1 = CHI; CHI2 = mfcharmul(CHI, get_mfchar(utoi(8))); } mf1 = mfinit_Nkchi(N, k1, CHI1, space, 1); B1 = MF_get_basis(mf1); if (lg(B1) == 1) return cgetg(1,t_VEC); N2 = ulcm(8, N); mf2 = mfinit_Nkchi(N2, k1, CHI2, space, 1); B2 = MF_get_basis(mf2); if (lg(B2) == 1) return cgetg(1,t_VEC); sb = mfsturmNgk(N2, gaddsg(k1, ghalf)); M1 = mfcoefs_mf(mf1, sb, 1); M2 = mfcoefs_mf(mf2, sb, 1); T1 = mfTheta(NULL); BT1 = RgV_to_RgX(mfcoefs_i(T1, sb, 1), 0); T2 = mfbd_i(T1, 2); BT2 = RgV_to_RgX(mfcoefs_i(T2, sb, 1), 0); M1 = mfmatsermul(M1, BT2); M2 = mfmatsermul(M2, BT1); ordchi = mfcharorder_canon(CHI); POLCYC = (ordchi == 1)? NULL: mfcharpol(CHI); M2I = QabM_pseudoinv(M2, POLCYC, ordchi, &v, &den); M = RgM_mul(M2, RgM_mul(M2I, rowpermute(M1, gel(v,1)))); M = gsub(RgM_Rg_mul(M1, den), M); K = QabM_ker(M, POLCYC, ordchi); return vecmflineardiv0(B1, K, T1); } #if 0 /* alternative method for weight 1 */ GEN mfwt1basisalt(long N, GEN CHI, long space) { pari_sp ltop = avma; GEN CHI1, mf1, mf2, B1, B2, BT1, BT2, M1, M2, M, T1, T2; GEN M2I, K, POLCYC, v, den; long sb, N1, N2, ordchi; CHI = get_mfchar(CHI); CHI1 = mfcharmul(CHI, get_mfchar(stoi(-4))); N1 = ulcm(4, N); mf1 = mfinit_Nkchi(N1, 2, CHI1, space, 1); B1 = MF_get_basis(mf1); if (lg(B1) == 1) { avma = ltop; return cgetg(1,t_VEC); } N2 = ulcm(8, N); mf2 = mfinit_Nkchi(N2, 2, CHI1, space, 1); B2 = MF_get_basis(mf2); if (lg(B2) == 1) { avma = ltop; return cgetg(1,t_VEC); } sb = mfsturmNk(N2, 3); M1 = mfcoefs_mf(mf1, sb, 1); M2 = mfcoefs_mf(mf2, sb, 1); T1 = mfTheta(NULL); T1 = mfmul(T1, T1); BT1 = RgV_to_RgX(mfcoefs_i(T1, sb, 1), 0); T2 = mfbd_i(T1, 2); BT2 = RgV_to_RgX(mfcoefs_i(T2, sb, 1), 0); M1 = mfmatsermul(M1, BT2); M2 = mfmatsermul(M2, BT1); ordchi = mfcharorder_canon(CHI); POLCYC = (ordchi == 1)? NULL: mfcharpol(CHI); M2I = QabM_pseudoinv(M2, POLCYC, ordchi, &v, &den); M = RgM_mul(M2, RgM_mul(M2I, rowpermute(M1, gel(v,1)))); M = gsub(RgM_Rg_mul(M1, den), M); K = QabM_ker(M, POLCYC, ordchi); return gerepilecopy(ltop, vecmflineardiv0(B1, K, T1)); } #endif /*******************************************************************/ /* Integration */ /*******************************************************************/ static GEN vanembed(GEN F, GEN v, long prec) { GEN CHI = mf_get_CHI(F); long o = mfcharorder_canon(CHI); if (o > 1 || degpol(mf_get_field(F)) > 1) v = liftpol_shallow(v); if (o > 1) v = gsubst(v, varn(mfcharpol(CHI)), rootsof1u_cx(o, prec)); return v; } static long mfperiod_prelim_double(double t0, long k, long bitprec) { double nlim, c = 2*M_PI*t0; nlim = ceil(bitprec * M_LN2 / c); c -= (k - 1)/(2*nlim); if (c < 1) c = 1.; nlim += ceil((0.7 + (k-1)/2*log(nlim))/c); return (long)nlim; } static long mfperiod_prelim(GEN t0, long k, long bitprec) { return mfperiod_prelim_double(gtodouble(t0), k, bitprec); } /* (-X)^(k-2) * P(-1/X) = (-1)^{k-2} P|_{k-2} S */ static GEN RgX_act_S(GEN P, long k) { P = RgX_unscale(RgX_recipspec_shallow(P+2, lgpol(P), k-1), gen_m1); setvarn(P,0); return P; } static int RgX_act_typ(GEN P, long k) { switch(typ(P)) { case t_RFRAC: return t_RFRAC; case t_POL: if (varn(P) == 0) { long d = degpol(P); if (d > k-2) return t_RFRAC; if (d) return t_POL; } } return 0; } static GEN act_S(GEN P, long k) { GEN X; switch(RgX_act_typ(P, k)) { case t_RFRAC: X = gneg(pol_x(0)); return gmul(gsubst(P, 0, ginv(X)), gpowgs(X, k - 2)); case t_POL: return RgX_act_S(P, k); } return P; } static GEN AX_B(GEN M) { GEN A = gcoeff(M,1,1), B = gcoeff(M,1,2); return deg1pol_shallow(A,B,0); } static GEN CX_D(GEN M) { GEN C = gcoeff(M,2,1), D = gcoeff(M,2,2); return deg1pol_shallow(C,D,0); } /* P|_{2-k}M = (CX+D)^{k-2}P((AX+B)/(CX+D)) */ static GEN RgX_act_gen(GEN P, GEN M, long k) { GEN S = gen_0, PCD, PAB; long i; PCD = gpowers(CX_D(M), k-2); PAB = gpowers(AX_B(M), k-2); for (i = 0; i <= k-2; i++) { GEN t = RgX_coeff(P, i); if (!gequal0(t)) S = gadd(S, gmul(t, gmul(gel(PCD, k-i-1), gel(PAB, i+1)))); } return S; } static GEN act_GL2(GEN P, GEN M, long k) { switch(RgX_act_typ(P, k)) { case t_RFRAC: { GEN AB = AX_B(M), CD = CX_D(M); return gmul(gsubst(P, 0, gdiv(AB, CD)), gpowgs(CD, k - 2)); } case t_POL: return RgX_act_gen(P, M, k); } return P; } static GEN normalizeapprox(GEN R, long bit) { GEN X = gen_1, Q; long i, l; if (is_vec_t(typ(R))) { Q = cgetg_copy(R, &l); for (i = 1; i < l; i++) { pari_sp av = avma; gel(Q,i) = gerepileupto(av, normalizeapprox(gel(R,i), bit)); } return Q; } if (typ(R) == t_RFRAC && varn(gel(R,2)) == 0) { X = gel(R,2); R = gel(R,1); } if (typ(R) != t_POL || varn(R) != 0) return gdiv(R, X); Q = cgetg_copy(R, &l); Q[1] = R[1]; for (i = 2; i < l; ++i) gel(Q,i) = Rg_approx(gel(R,i),bit); Q = normalizepol_lg(Q,l); return gdiv(Q, X); } /* make sure T is a t_POL in variable 0 */ static GEN toRgX0(GEN T) { return typ(T) == t_POL && varn(T) == 0? T: scalarpol_shallow(T,0); } /* integrate by summing nlim+1 terms of van [may be < lg(van)] * van can be an expansion with vector coefficients * \int_A^oo \sum_n van[n] * q^(n/w + al) * P(z-A) dz, q = e(z) */ static GEN intAoo(GEN van, long nlim, GEN al, long w, GEN P, GEN A, long k, long prec) { GEN alw, P1, piI2A, q, S, van0; long n, vz = varn(gel(P,2)); if (nlim < 1) nlim = 1; alw = gmulsg(w, al); P1 = RgX_translate(P, gneg(A)); piI2A = gmul(PiI2n(1, prec), A); q = gexp(gdivgs(piI2A, w), prec); S = gen_0; for (n = nlim; n >= 1; n--) { GEN t = gsubst(P1, vz, gdivsg(w, gaddsg(n, alw))); S = gadd(gmul(gel(van, n+1), t), gmul(q, S)); } S = gmul(q, S); van0 = gel(van, 1); if (!gequal0(al)) { S = gadd(S, gmul(gsubst(P1, vz, ginv(al)), van0)); S = gmul(S, gexp(gmul(piI2A, al), prec)); } else if (!gequal0(van0)) S = gsub(S, gdivgs(gmul(van0, gpowgs(gsub(pol_x(0), A), k-1)), k-1)); if (is_vec_t(typ(S))) { long j, l = lg(S); for (j = 1; j < l; j++) gel(S,j) = toRgX0(gel(S,j)); } else S = toRgX0(S); return gneg(S); } /* \sum_{j <= k} X^j * (Y / (2I\pi))^{k+1-j} k! / j! */ static GEN get_P(long k, long v, long prec) { GEN a, S = cgetg(k + 1, t_POL), u = invr(Pi2n(1, prec+EXTRAPRECWORD)); long j, K = k-2; S[1] = evalsigne(1)|evalvarn(0); a = u; gel(S,K+2) = monomial(mulcxpowIs(a,3), 1, v); /* j = K */ for(j = K-1; j >= 0; j--) { a = mulrr(mulru(a,j+1), u); gel(S,j+2) = monomial(mulcxpowIs(a,3*(K+1-j)), K+1-j, v); } return S; } static GEN getw1w2(long N, GEN ga) { return mkvecsmall2(mfZC_width(N, gel(ga,1)), mfZC_width(N, gel(ga,2))); } static GEN intAoowithvanall(GEN mf, GEN vanall, GEN P, GEN cosets, long bitprec) { GEN vvan = gel(vanall,1), vaw = gel(vanall,2), W1W2, resall; long prec = nbits2prec(bitprec), N, k, lco, j; N = MF_get_N(mf); k = MF_get_k(mf); lco = lg(cosets); W1W2 = cgetg(lco, t_VEC); resall = cgetg(lco, t_VEC); for (j = 1; j < lco; j++) gel(W1W2,j) = getw1w2(N, gel(cosets, j)); for (j = 1; j < lco; j++) { GEN w1w2j = gel(W1W2,j), alj, M, VAN, RES, AR, Q; long jq, c, w1, w2, w; if (!w1w2j) continue; alj = gel(vaw,j); w1 = w1w2j[1]; Q = cgetg(lco, t_VECSMALL); w2 = w1w2j[2]; M = cgetg(lco, t_COL); for (c = 1, jq = j; jq < lco; jq++) { GEN W = gel(W1W2, jq); if (jq == j || (W && gequal(W, w1w2j) && gequal(gel(vaw, jq), alj))) { Q[c] = jq; gel(W1W2, jq) = NULL; gel(M, c) = gel(vvan, jq); c++; } } setlg(M,c); VAN = shallowmatconcat(M); AR = mkcomplex(gen_0, sqrtr_abs(divru(utor(w1, prec+1), w2))); w = itos(gel(alj,2)); RES = intAoo(VAN, lg(VAN)-2, gel(alj,1),w, P, AR, k, prec); for (jq = 1; jq < c; jq++) gel(resall, Q[jq]) = gel(RES, jq); } return resall; } GEN mftobasisES(GEN mf, GEN F) { GEN v = mftobasis(mf, F, 0); long nE = lg(MF_get_E(mf))-1; return mkvec2(vecslice(v,1,nE), vecslice(v,nE+1,lg(v)-1)); } static long wt1mulcond(GEN F, long D, long space) { GEN E = mfeisenstein_i(1, mfchartrivial(), get_mfchar(stoi(D))), mf; F = mfmul(F, E); mf = mfinit_Nkchi(mf_get_N(F), mf_get_k(F), mf_get_CHI(F), space, 0); return mfconductor(mf, F); } static int wt1newlevel(long N) { GEN P = gel(myfactoru(N),1); long l = lg(P), i; for (i = 1; i < l; i++) if (!wt1empty(N/P[i])) return 0; return 1; } long mfconductor(GEN mf, GEN F) { pari_sp av = avma; GEN gk; long space, N, M; mf = checkMF(mf); if (!checkmf_i(F)) pari_err_TYPE("mfconductor",F); if (mfistrivial(F)) return 1; space = MF_get_space(mf); if (space == mf_NEW) return mf_get_N(F); gk = MF_get_gk(mf); if (isint1(gk)) { N = mf_get_N(F); if (!wt1newlevel(N)) { long s = space_is_cusp(space)? mf_CUSP: mf_FULL; N = ugcd(N, wt1mulcond(F,-3,s)); if (!wt1newlevel(N)) N = ugcd(N, wt1mulcond(F,-4,s)); } avma = av; return N; } if (typ(gk) != t_INT) { F = mfmultheta(F); mf = obj_checkbuild(mf, MF_MF2INIT, &mf2init); /* mf_FULL */ } N = 1; if (space_is_cusp(space)) { F = mftobasis_i(mf, F); if (typ(gk) != t_INT) F = vecslice(F, lg(MF_get_E(mf)), lg(F) - 1); } else { GEN EF = mftobasisES(mf, F), vE = gel(EF,1), B = MF_get_E(mf); long i, l = lg(B); for (i = 1; i < l; i++) if (!gequal0(gel(vE,i))) N = ulcm(N, mf_get_N(gel(B, i))); F = gel(EF,2); } (void)mftonew_i(mf, F, &M); /* M = conductor of cuspidal part */ avma = av; return ulcm(M, N); } static GEN fs_get_MF(GEN fs) { return gel(fs,1); } static GEN fs_get_vES(GEN fs) { return gel(fs,2); } static GEN fs_get_pols(GEN fs) { return gel(fs,3); } static GEN fs_get_cosets(GEN fs) { return gel(fs,4); } static long fs_get_bitprec(GEN fs) { return itou(gel(fs,5)); } static GEN fs_get_vE(GEN fs) { return gel(fs,6); } static GEN fs_get_EF(GEN fs) { return gel(fs,7); } static GEN fs_get_expan(GEN fs) { return gel(fs,8); } static GEN fs_set_expan(GEN fs, GEN vanall) { GEN f = shallowcopy(fs); gel(f,8) = vanall; return f; } static int mfs_checkmf(GEN fs, GEN mf) { GEN mfF = fs_get_MF(fs); return gequal(gel(mfF,1), gel(mf,1)); } static long checkfs_i(GEN v) { return typ(v) == t_VEC && lg(v) == 9 && checkMF_i(fs_get_MF(v)) && typ(fs_get_vES(v)) == t_VEC && typ(fs_get_pols(v)) == t_VEC && typ(fs_get_cosets(v)) == t_VEC && typ(fs_get_vE(v)) == t_VEC && lg(fs_get_pols(v)) == lg(fs_get_cosets(v)) && typ(fs_get_expan(v)) == t_VEC && lg(fs_get_expan(v)) == 3 && lg(gel(fs_get_expan(v), 1)) == lg(fs_get_cosets(v)) && typ(gel(v,5)) == t_INT; } GEN checkMF_i(GEN mf) { long l = lg(mf); GEN v; if (typ(mf) != t_VEC) return NULL; if (l == 9) return checkMF_i(fs_get_MF(mf)); if (l != 7) return NULL; v = gel(mf,1); if (typ(v) != t_VEC || lg(v) != 5) return NULL; return (typ(gel(v,1)) == t_INT && typ(gmul2n(gel(v,2), 1)) == t_INT && typ(gel(v,3)) == t_VEC && typ(gel(v,4)) == t_INT)? mf: NULL; } GEN checkMF(GEN T) { GEN mf = checkMF_i(T); if (!mf) pari_err_TYPE("checkMF [please use mfinit]", T); return mf; } /* c,d >= 0; c * Nc = N, find coset whose image in P1(Z/NZ) ~ (c, d + k(N/c)) */ static GEN coset_complete(long c, long d, long Nc) { long a, b; while (ugcd(c, d) > 1) d += Nc; (void)cbezout(c, d, &b, &a); return mkmat22s(a, -b, c, d); } /* right cosets of $\G_0(N)$: $\G=\bigsqcup_j \G_0(N)\ga_j$. */ /* We choose them with c\mid N and d mod N/c, not the reverse */ GEN mfcosets(GEN gN) { pari_sp av = avma; GEN V, D, mf; long l, i, ct, N = 0; if (typ(gN) == t_INT) N = itos(gN); else if ((mf = checkMF_i(gN))) N = MF_get_N(mf); else pari_err_TYPE("mfcosets", gN); if (N <= 0) pari_err_DOMAIN("mfcosets", "N", "<=", gen_0, stoi(N)); V = cgetg(mypsiu(N) + 1, t_VEC); D = mydivisorsu(N); l = lg(D); for (i = ct = 1; i < l; i++) { long d, c = D[i], Nc = D[l-i], e = ugcd(Nc, c); for (d = 0; d < Nc; d++) if (ugcd(d,e) == 1) gel(V, ct++) = coset_complete(c, d, Nc); } return gerepilecopy(av, V); } static int cmp_coset(void *E, GEN A, GEN B) { long N = (long)E, Nc, c = itou(gcoeff(A,2,1)); long r = cmp_small(c, itou(gcoeff(B,2,1))); if (r) return r; Nc = N / c; return cmp_small(umodiu(gcoeff(A,2,2), Nc), umodiu(gcoeff(B,2,2), Nc)); } /* M in SL_2(Z) */ static long mftocoset_i(ulong N, GEN M, GEN cosets) { pari_sp av = avma; long A = itos(gcoeff(M,1,1)), c, u, v, Nc, i; long C = itos(gcoeff(M,2,1)), D = itos(gcoeff(M,2,2)); GEN ga; c = cbezout(N*A, C, &u, &v); Nc = N/c; ga = coset_complete(c, smodss(v*D, Nc), Nc); i = gen_search(cosets, ga, 0, (void*)N, &cmp_coset); if (!i) pari_err_BUG("mftocoset [no coset found]"); avma = av; return i; } /* (U * V^(-1))[2,2] mod N, assuming V in SL2(Z) */ static long SL2_div_D(ulong N, GEN U, GEN V) { long c = umodiu(gcoeff(U,2,1), N), d = umodiu(gcoeff(U,2,2), N); long a2 = umodiu(gcoeff(V,1,1), N), b2 = umodiu(gcoeff(V,1,2), N); return (a2*d - b2*c) % (long)N; } static long mftocoset_iD(ulong N, GEN M, GEN cosets, long *D) { long i = mftocoset_i(N, M, cosets); *D = SL2_div_D(N, M, gel(cosets,i)); return i; } GEN mftocoset(ulong N, GEN M, GEN cosets) { long i; if (!check_SL2Z(M)) pari_err_TYPE("mftocoset",M); i = mftocoset_i(N, M, cosets); retmkvec2(gdiv(M,gel(cosets,i)), utoipos(i)); } static long getnlim2(long N, long w1, long w2, long nlim, long k, long bitprec) { if (w2 == N) return nlim; return mfperiod_prelim_double(1./sqrt((double)w1*w2), k, bitprec + 32); } /* g * S, g 2x2 */ static GEN ZM_mulS(GEN g) { return mkmat2(gel(g,2), ZC_neg(gel(g,1))); } /* g * T, g 2x2 */ static GEN ZM_mulT(GEN g) { return mkmat2(gel(g,1), ZC_add(gel(g,2), gel(g,1))); } /* g * T^(-1), g 2x2 */ static GEN ZM_mulTi(GEN g) { return mkmat2(gel(g,1), ZC_sub(gel(g,2), gel(g,1))); } /* Compute all slashexpansions for all cosets */ static GEN mfgaexpansionall(GEN mf, GEN FE, GEN cosets, double height, long prec) { GEN CHI = MF_get_CHI(mf), vres, vresaw; long lco, j, k = MF_get_k(mf), N = MF_get_N(mf), bitprec = prec2nbits(prec); lco = lg(cosets); vres = const_vec(lco-1, NULL); vresaw = cgetg(lco, t_VEC); for (j = 1; j < lco; j++) if (!gel(vres,j)) { GEN ga = gel(cosets, j), van, aw, al, z, gai; long w1 = mfZC_width(N, gel(ga,1)); long w2 = mfZC_width(N, gel(ga,2)); long nlim, nlim2, daw, da, na, i; double sqNinvdbl = height ? height/w1 : 1./sqrt((double)w1*N); nlim = mfperiod_prelim_double(sqNinvdbl, k, bitprec + 32); van = mfslashexpansion(mf, FE, ga, nlim, 0, &aw, prec + 1); van = vanembed(gel(FE, 1), van, prec + 1); al = gel(aw, 1); nlim2 = height? nlim: getnlim2(N, w1, w2, nlim, k, bitprec); gel(vres, j) = vecslice(van, 1, nlim2 + 1); gel(vresaw, j) = aw; Qtoss(al, &na, &da); daw = da*w1; z = rootsof1powinit(1, daw, prec + 1); gai = ga; for (i = 1; i < w1; i++) { GEN V, coe; long Di, n, ind, w2, s = ((i*na) % da) * w1, t = i*da; gai = ZM_mulT(gai); ind = mftocoset_iD(N, gai, cosets, &Di); w2 = mfZC_width(N, gel(gel(cosets,ind), 2)); nlim2 = height? nlim: getnlim2(N, w1, w2, nlim, k, bitprec); gel(vresaw, ind) = aw; V = cgetg(nlim2 + 2, t_VEC); for (n = 0; n <= nlim2; n++, s = Fl_add(s, t, daw)) gel(V, n+1) = gmul(gel(van, n+1), rootsof1pow(z, s)); coe = mfcharcxeval(CHI, Di, prec + 1); if (!gequal1(coe)) V = RgV_Rg_mul(V, conj_i(coe)); gel(vres, ind) = V; } } return mkvec2(vres, vresaw); } /* Compute all period pols of F|_k\ga_j, vF = mftobasis(F_S) */ static GEN mfperiodpols_i(GEN mf, GEN FE, GEN cosets, GEN *pvan, long bit) { long N, i, prec = nbits2prec(bit), k = MF_get_k(mf); GEN vP, P, CHI, intall = gen_0; *pvan = gen_0; if (k == 0 && gequal0(gel(FE,2))) return cosets? const_vec(lg(cosets)-1, pol_0(0)): pol_0(0); N = MF_get_N(mf); CHI = MF_get_CHI(mf); P = get_P(k, fetch_var(), prec); if (!cosets) { /* ga = id */ long nlim, PREC = prec + EXTRAPRECWORD; GEN F = gel(FE,1), sqNinv = invr(sqrtr_abs(utor(N, PREC))); /* A/w */ GEN AR, v, van, T1, T2; nlim = mfperiod_prelim(sqNinv, k, bit + 32); /* F|id: al = 0, w = 1 */ v = mfcoefs_i(F, nlim, 1); van = vanembed(F, v, PREC); AR = mkcomplex(gen_0, sqNinv); T1 = intAoo(van, nlim, gen_0,1, P, AR, k, prec); if (N == 1) T2 = T1; else { /* F|S: al = 0, w = N */ v = mfgaexpansion(mf, FE, mkS(), nlim, PREC); van = vanembed(F, gel(v,3), PREC); AR = mkcomplex(gen_0, mulur(N,sqNinv)); T2 = intAoo(van, nlim, gen_0,N, P, AR, k, prec); } T1 = gsub(T1, act_S(T2, k)); T1 = normalizeapprox(T1, bit-20); vP = gprec_wtrunc(T1, prec); } else { long lco = lg(cosets); GEN vanall = mfgaexpansionall(mf, FE, cosets, 0, prec); *pvan = vanall; intall = intAoowithvanall(mf, vanall, P, cosets, bit); vP = const_vec(lco-1, NULL); for (i = 1; i < lco; i++) { GEN P, P1, P2, c, ga = gel(cosets, i); long iS, DS; if (gel(vP,i)) continue; P1 = gel(intall, i); iS = mftocoset_iD(N, ZM_mulS(ga), cosets, &DS); c = mfcharcxeval(CHI, DS, prec + EXTRAPRECWORD); P2 = gel(intall, iS); P = act_S(isint1(c)? P2: gmul(c, P2), k); P = normalizeapprox(gsub(P1, P), bit-20); gel(vP,i) = gprec_wtrunc(P, prec); if (iS == i) continue; P = act_S(isint1(c)? P1: gmul(conj_i(c), P1), k); if (!odd(k)) P = gneg(P); P = normalizeapprox(gadd(P, P2), bit-20); gel(vP,iS) = gprec_wtrunc(P, prec); } } delete_var(); return vP; } /* when cosets = NULL, return a "fake" symbol containing only fs(oo->0) */ static GEN mfsymbol_i(GEN mf, GEN F, GEN cosets, long bit) { GEN FE, van, vP, vE, Mvecj, vES = mftobasisES(mf,F); long precnew, prec = nbits2prec(bit), k = MF_get_k(mf); vE = mfgetembed(F, prec); Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit); if (lg(Mvecj) >= 5) precnew = prec; else { long n = mfperiod_prelim_double(1/(double)MF_get_N(mf), k, bit + 32); precnew = prec + nbits2extraprec(n >> 1); } FE = mkcol2(F, mf_eisendec(mf,F,precnew)); vP = mfperiodpols_i(mf, FE, cosets, &van, bit); return mkvecn(8, mf, vES, vP, cosets, utoi(bit), vE, FE, van); } static GEN fs2_get_cusps(GEN f) { return gel(f,3); } static GEN fs2_get_MF(GEN f) { return gel(f,1); } static GEN fs2_get_W(GEN f) { return gel(f,2); } static GEN fs2_get_F(GEN f) { return gel(f,4); } static long fs2_get_bitprec(GEN f) { return itou(gel(f,5)); } static GEN fs2_get_al0(GEN f) { return gel(f,6); } static GEN fs2_get_den(GEN f) { return gel(f,7); } static int checkfs2_i(GEN f) { GEN W, C, F, al0; long l; if (typ(f) != t_VEC || lg(f) != 8 || typ(gel(f,5)) != t_INT) return 0; C = fs2_get_cusps(f); l = lg(C); W = fs2_get_W(f); F = fs2_get_F(f); al0 = fs2_get_al0(f); return checkMF_i(fs2_get_MF(f)) && typ(W) == t_VEC && typ(F) == t_VEC && typ(al0) == t_VECSMALL && lg(W) == l && lg(F) == l && lg(al0) == l; } static GEN fs2_init(GEN mf, GEN F, long bit); GEN mfsymbol(GEN mf, GEN F, long bit) { pari_sp av = avma; GEN cosets = NULL; if (!F) { F = mf; if (!checkmf_i(F)) pari_err_TYPE("mfsymbol", F); mf = mfinit_i(F, mf_FULL); } else if (!checkmf_i(F)) pari_err_TYPE("mfsymbol", F); if (checkfs2_i(mf)) return fs2_init(mf, F, bit); if (checkfs_i(mf)) { cosets = fs_get_cosets(mf); mf = fs_get_MF(mf); } else if (checkMF_i(mf)) { GEN gk = MF_get_gk(mf); if (typ(gk) != t_INT || equali1(gk)) return fs2_init(mf, F, bit); if (signe(gk) <= 0) pari_err_TYPE("mfsymbol [k <= 0]", mf); cosets = mfcosets(MF_get_gN(mf)); } else pari_err_TYPE("mfsymbol",mf); return gerepilecopy(av, mfsymbol_i(mf, F, cosets, bit)); } static GEN RgX_by_parity(GEN P, long odd) { long i, l = lg(P); GEN Q; if (l < 4) return odd ? pol_x(0): P; Q = cgetg(l, t_POL); Q[1] = P[1]; for (i = odd? 2: 3; i < l; i += 2) gel(Q,i) = gen_0; for (i = odd? 3: 2; i < l; i += 2) gel(Q,i) = gel(P,i); return normalizepol_lg(Q, l); } /* flag 0: period polynomial of F, >0 or <0 with corresponding parity */ GEN mfperiodpol(GEN mf0, GEN F, long flag, long bit) { pari_sp av = avma; GEN pol, mf = checkMF_i(mf0); if (!mf) pari_err_TYPE("mfperiodpol",mf0); if (checkfs_i(F)) { GEN mfpols = fs_get_pols(F); if (!mfs_checkmf(F, mf)) pari_err_TYPE("mfperiodpol [different mf]",F); pol = gel(mfpols, lg(mfpols)-1); /* trivial coset is last */ } else { GEN gk = MF_get_gk(mf); if (typ(gk) != t_INT) pari_err_TYPE("mfperiodpol [half-integral k]", mf); if (equali1(gk)) pari_err_TYPE("mfperiodpol [k = 1]", mf); F = mfsymbol_i(mf, F, NULL, bit); pol = fs_get_pols(F); } if (flag) pol = RgX_by_parity(pol, flag < 0); return gerepilecopy(av, RgX_embedall(pol, 0, fs_get_vE(F))); } static int mfs_iscusp(GEN mfs) { return gequal0(gmael(mfs,2,1)); } /* given cusps s1 and s2 (rationals or oo) * compute $\int_{s1}^{s2}(X-\tau)^{k-2}F|_k\ga_j(\tau)\,d\tau$ */ /* If flag = 1, do not give an error message if divergent, but give the rational function as result. */ static GEN col2cusp(GEN v) { GEN A, C; if (lg(v) != 3 || !RgV_is_ZV(v)) pari_err_TYPE("col2cusp",v); A = gel(v,1); C = gel(v,2); if (gequal0(C)) { if (gequal0(A)) pari_err_TYPE("mfsymboleval", mkvec2(A, C)); return mkoo(); } return gdiv(A, C); } /* g.oo */ static GEN mat2cusp(GEN g) { return col2cusp(gel(g,1)); } static GEN pathmattovec(GEN path) { return mkvec2(col2cusp(gel(path,1)), col2cusp(gel(path,2))); } static void get_mf_F(GEN fs, GEN *mf, GEN *F) { if (lg(fs) == 3) { *mf = gel(fs,1); *F = gel(fs,2); } else { *mf = fs_get_MF(fs); *F = NULL; } } static GEN mfgetvan(GEN fs, GEN ga, GEN *pal, long nlim, long prec) { GEN van, mf, F, W; long PREC; get_mf_F(fs, &mf, &F); if (!F) { GEN vanall = fs_get_expan(fs), cosets = fs_get_cosets(fs); long D, jga = mftocoset_iD(MF_get_N(mf), ga, cosets, &D); van = gmael(vanall, 1, jga); W = gmael(vanall, 2, jga); if (lg(van) >= nlim + 2) { GEN z = mfcharcxeval(MF_get_CHI(mf), D, prec); if (!gequal1(z)) van = RgV_Rg_mul(van, z); *pal = gel(W,1); return van; } F = gel(fs_get_EF(fs), 1); } PREC = prec + EXTRAPRECWORD; van = mfslashexpansion(mf, F, ga, nlim, 0, &W, PREC); van = vanembed(F, van, PREC); *pal = gel(W,1); return van; } /* Computation of int_A^oo (f | ga)(t)(X-t)^{k-2} dt, assuming convergence; * fs is either a symbol or a triple [mf,F,bitprec]. A != oo and im(A) > 0 */ static GEN intAoo0(GEN fs, GEN A, GEN ga, GEN P, long bit) { long nlim, N, k, w, prec = nbits2prec(bit); GEN van, mf, F, al; get_mf_F(fs, &mf,&F); N = MF_get_N(mf); k = MF_get_k(mf); w = mfZC_width(N, gel(ga,1)); nlim = mfperiod_prelim(gdivgs(imag_i(A), w), k, bit + 32); van = mfgetvan(fs, ga, &al, nlim, prec); return intAoo(van, nlim, al,w, P, A, k, prec); } /* fs symbol, naive summation, A != oo, im(A) > 0 and B = oo or im(B) > 0 */ static GEN mfsymboleval_direct(GEN fs, GEN path, GEN ga, GEN P) { GEN A, B, van, S, al, mf = fs_get_MF(fs); long w, nlimA, nlimB = 0, N = MF_get_N(mf), k = MF_get_k(mf); long bit = fs_get_bitprec(fs), prec = nbits2prec(bit); A = gel(path, 1); B = gel(path, 2); if (typ(B) == t_INFINITY) B = NULL; w = mfZC_width(N, gel(ga,1)); nlimA = mfperiod_prelim(gdivgs(imag_i(A),w), k, bit + 32); if (B) nlimB = mfperiod_prelim(gdivgs(imag_i(B),w), k, bit + 32); van = mfgetvan(fs, ga, &al, maxss(nlimA,nlimB), prec); S = intAoo(van, nlimA, al,w, P, A, k, prec); if (B) S = gsub(S, intAoo(van, nlimB, al,w, P, B, k, prec)); return RgX_embedall(S, 0, fs_get_vE(fs)); } /* Computation of int_A^oo (f | ga)(t)(X-t)^{k-2} dt, assuming convergence; * fs is either a symbol or a pair [mf,F]. */ static GEN mfsymbolevalpartial(GEN fs, GEN A, GEN ga, long bit) { GEN Y, F, S, P, mf; long N, k, w, prec = nbits2prec(bit); get_mf_F(fs, &mf, &F); N = MF_get_N(mf); w = mfZC_width(N, gel(ga,1)); k = MF_get_k(mf); Y = gdivgs(imag_i(A), w); P = get_P(k, fetch_var(), prec); if (lg(fs) != 3 && gtodouble(Y)*(2*N) < 1) { /* true symbol + low imaginary part: use GL_2 action to improve */ GEN U, ga2, czd, A2 = cxredga0N(N, A, &U, &czd, 1), oo = mkoo(); ga2 = ZM_mul(ga, ZM_inv(U, NULL)); S = intAoo0(fs, A2, ga2, P, bit); S = gsub(S, mfsymboleval(fs, mkvec2(mat2cusp(U), oo), ga2, bit)); S = act_GL2(S, U, k); } else S = intAoo0(fs, A, ga, P, bit); S = RgX_embedall(S, 0, F? mfgetembed(F,prec): fs_get_vE(fs)); delete_var(); return normalizeapprox(S, bit-20); } static GEN actal(GEN x, GEN vabd) { if (typ(x) == t_INFINITY) return x; return gdiv(gadd(gmul(gel(vabd,1), x), gel(vabd,2)), gel(vabd,3)); } static GEN unact(GEN z, GEN vabd, long k, long prec) { GEN res = gsubst(z, 0, actal(pol_x(0), vabd)); GEN CO = gpow(gdiv(gel(vabd,3), gel(vabd,1)), sstoQ(k-2, 2), prec); return gmul(CO, res); } GEN mfsymboleval(GEN fs, GEN path, GEN ga, long bitprec) { pari_sp av = avma; GEN tau, V, LM, S, CHI, mfpols, cosets, al, be, mf, F, vabd = NULL; long D, B, m, u, v, a, b, c, d, j, k, N, prec, tsc1, tsc2; if (checkfs_i(fs)) { get_mf_F(fs, &mf, &F); bitprec = minss(bitprec, fs_get_bitprec(fs)); } else { if (checkfs2_i(fs)) pari_err_TYPE("mfsymboleval [need integral k > 1]",fs); if (typ(fs) != t_VEC || lg(fs) != 3) pari_err_TYPE("mfsymboleval",fs); get_mf_F(fs, &mf, &F); mf = checkMF_i(mf); if (!mf ||!checkmf_i(F)) pari_err_TYPE("mfsymboleval",fs); } if (lg(path) != 3) pari_err_TYPE("mfsymboleval",path); if (typ(path) == t_MAT) path = pathmattovec(path); if (typ(path) != t_VEC) pari_err_TYPE("mfsymboleval",path); al = gel(path,1); be = gel(path,2); ga = ga? GL2toSL2(ga, &vabd): matid(2); if (vabd) { al = actal(al, vabd); be = actal(be, vabd); path = mkvec2(al, be); } tsc1 = cusp_AC(al, &a, &c); tsc2 = cusp_AC(be, &b, &d); prec = nbits2prec(bitprec); k = MF_get_k(mf); if (!tsc1) { GEN z2, z = mfsymbolevalpartial(fs, al, ga, bitprec); if (tsc2) z2 = d? mfsymboleval(fs, mkvec2(be, mkoo()), ga, bitprec): gen_0; else z2 = mfsymbolevalpartial(fs, be, ga, bitprec); z = gsub(z, z2); if (vabd) z = unact(z, vabd, k, prec); return gerepileupto(av, normalizeapprox(z, bitprec-20)); } else if (!tsc2) { GEN z = mfsymbolevalpartial(fs, be, ga, bitprec); if (c) z = gsub(mfsymboleval(fs, mkvec2(al, mkoo()), ga, bitprec), z); if (vabd) z = unact(z, vabd, k, prec); return gerepileupto(av, normalizeapprox(z, bitprec-20)); } if (F) pari_err_TYPE("mfsymboleval", fs); D = a*d-b*c; if (!D) { avma = av; return gen_0; } mfpols = fs_get_pols(fs); cosets = fs_get_cosets(fs); CHI = MF_get_CHI(mf); N = MF_get_N(mf); cbezout(a, c, &u, &v); B = u*b + v*d; tau = mkmat22s(a, -v, c, u); V = gcf(sstoQ(B, D)); LM = shallowconcat(mkcol2(gen_1, gen_0), contfracpnqn(V, lg(V))); S = gen_0; m = lg(LM) - 2; for (j = 0; j < m; j++) { GEN M, P; long D, iN; M = mkmat2(gel(LM, j+2), gel(LM, j+1)); if (!odd(j)) gel(M,1) = ZC_neg(gel(M,1)); M = ZM_mul(tau, M); iN = mftocoset_iD(N, ZM_mul(ga, M), cosets, &D); P = gmul(gel(mfpols,iN), mfcharcxeval(CHI,D,prec)); S = gadd(S, act_GL2(P, ZM_inv(M, NULL), k)); } if (typ(S) == t_RFRAC) { GEN R, S1, co; gel(S,2) = primitive_part(gel(S,2), &co); if (co) gel(S,1) = gdiv(gel(S,1), gtofp(co,prec)); S1 = poldivrem(gel(S,1), gel(S,2), &R); if (gexpo(R) < -bitprec + 20) S = S1; } if (vabd) S = unact(S, vabd, k, prec); S = RgX_embedall(S, 0, fs_get_vE(fs)); return gerepileupto(av, normalizeapprox(S, bitprec-20)); } /* v a scalar or t_POL; set *pw = a if expo(a) > E for some coefficient; * take the 'a' with largest exponent */ static void improve(GEN v, GEN *pw, long *E) { if (typ(v) != t_POL) { long e = gexpo(v); if (e > *E) { *E = e; *pw = v; } } else { long j, l = lg(v); for (j = 2; j < l; j++) improve(gel(v,j), pw, E); } } static GEN polabstorel(GEN rnfeq, GEN T) { long i, l; GEN U; if (typ(T) != t_POL) return T; U = cgetg_copy(T, &l); U[1] = T[1]; for (i = 2; i < l; i++) gel(U,i) = eltabstorel(rnfeq, gel(T,i)); return U; } static GEN bestapprnfrel(GEN x, GEN polabs, GEN roabs, GEN rnfeq, long prec) { x = bestapprnf(x, polabs, roabs, prec); if (rnfeq) x = polabstorel(rnfeq, liftpol_shallow(x)); return x; } /* v vector of polynomials polynomial in C[X] (possibly scalar). * Set *w = coeff with largest exponent and return T / *w, rationalized */ static GEN normal(GEN v, GEN polabs, GEN roabs, GEN rnfeq, GEN *w, long prec) { long i, l = lg(v), E = -(long)HIGHEXPOBIT; GEN dv; for (i = 1; i < l; i++) improve(gel(v,i), w, &E); v = RgV_Rg_mul(v, ginv(*w)); for (i = 1; i < l; i++) gel(v,i) = bestapprnfrel(gel(v,i), polabs,roabs,rnfeq,prec); v = Q_primitive_part(v,&dv); if (dv) *w = gmul(*w,dv); return v; } static GEN mfpetersson_i(GEN FS, GEN GS); GEN mfmanin(GEN FS, long bitprec) { pari_sp av = avma; GEN mf, M, vp, vm, cosets, CHI, vpp, vmm, f, T, P, vE, polabs, roabs, rnfeq; GEN pet; long N, k, lco, i, prec, lvE; if (!checkfs_i(FS)) { if (checkfs2_i(FS)) pari_err_TYPE("mfmanin [need integral k > 1]",FS); pari_err_TYPE("mfmanin",FS); } if (!mfs_iscusp(FS)) pari_err_TYPE("mfmanin [noncuspidal]",FS); mf = fs_get_MF(FS); vp = fs_get_pols(FS); cosets = fs_get_cosets(FS); bitprec = fs_get_bitprec(FS); N = MF_get_N(mf); k = MF_get_k(mf); CHI = MF_get_CHI(mf); lco = lg(cosets); vm = cgetg(lco, t_VEC); prec = nbits2prec(bitprec); for (i = 1; i < lco; i++) { GEN g = gel(cosets, i), c; long A = itos(gcoeff(g,1,1)), B = itos(gcoeff(g,1,2)); long C = itos(gcoeff(g,2,1)), D = itos(gcoeff(g,2,2)); long Dbar, ibar = mftocoset_iD(N, mkmat22s(-B,-A,D,C), cosets, &Dbar); c = mfcharcxeval(CHI, Dbar, prec); if (odd(k)) c = gneg(c); T = RgX_Rg_mul(gel(vp,ibar), c); if (typ(T) == t_POL && varn(T) == 0) T = RgX_recip(T); gel(vm,i) = T; } vpp = gadd(vp,vm); vmm = gsub(vp,vm); vE = fs_get_vE(FS); lvE = lg(vE); f = gel(fs_get_EF(FS), 1); P = mf_get_field(f); if (degpol(P) == 1) P = NULL; T = mfcharpol(CHI); if (degpol(T) == 1) T = NULL; if (T && P) { rnfeq = nf_rnfeqsimple(T, P); polabs = gel(rnfeq,1); roabs = gel(QX_complex_roots(polabs,prec), 1); } else { rnfeq = roabs = NULL; polabs = P? P: T; } pet = mfpetersson_i(FS, NULL); M = cgetg(lvE, t_VEC); for (i = 1; i < lvE; i++) { GEN p, m, wp, wm, petdiag, r, E = gel(vE,i); p = normal(RgXV_embed(vpp,0,E), polabs, roabs, rnfeq, &wp, prec); m = normal(RgXV_embed(vmm,0,E), polabs, roabs, rnfeq, &wm, prec); petdiag = typ(pet)==t_MAT? gcoeff(pet,i,i): pet; r = gdiv(imag_i(gmul(wp, conj_i(wm))), petdiag); r = bestapprnfrel(r, polabs, roabs, rnfeq, prec); gel(M,i) = mkvec2(mkvec2(p,m), mkvec3(wp,wm,r)); } return gerepilecopy(av, lvE == 2? gel(M,1): M); } /* flag = 0: full, flag = +1 or -1, odd/even */ /* Basis of period polynomials in level 1. */ GEN mfperiodpolbasis(long k, long flag) { pari_sp av = avma; long i, j, km2 = k - 2; GEN M, C; if (k <= 4) return cgetg(1,t_VEC); M = cgetg(k, t_MAT); C = matpascal(km2); if (!flag) for (j = 0; j <= km2; j++) { GEN v = cgetg(k, t_COL); for (i = 0; i <= j; i++) gel(v, i+1) = gcoeff(C, j+1, i+1); for (; i <= km2; i++) gel(v, i+1) = gcoeff(C, km2-j+1, i-j+1); gel(M, j+1) = v; } else for (j = 0; j <= km2; j++) { GEN v = cgetg(k, t_COL); for (i = 0; i <= km2; i++) { GEN a = i < j ? gcoeff(C, j+1, i+1) : gen_0; if (i + j >= km2) { GEN b = gcoeff(C, j+1, i+j-km2+1); a = flag < 0 ? addii(a,b) : subii(a,b); } gel(v, i+1) = a; } gel(M, j+1) = v; } return gerepilecopy(av, RgM_to_RgXV(ZM_ker(M), 0)); } static int zero_at_cusp(GEN mf, GEN F, GEN c) { GEN v = evalcusp(mf, F, c, LOWDEFAULTPREC); return (gequal0(v) || gexpo(v) <= -62); } /* Compute list E of j such that F|_k g_j vanishes at oo: return [E, s(E)] */ static void mffvanish(GEN mf, GEN F, GEN G, GEN cosets, GEN *pres, GEN *press) { long j, lc = lg(cosets), N = MF_get_N(mf); GEN v, vs; *pres = v = zero_zv(lc-1); *press= vs = zero_zv(lc-1); for (j = 1; j < lc; j++) { GEN ga = gel(cosets,j), c = mat2cusp(ga); if (zero_at_cusp(mf, F, c)) v[j] = vs[ mftocoset_i(N, ZM_mulS(ga), cosets) ] = 1; else if (!zero_at_cusp(mf, G, c)) pari_err_IMPL("divergent Petersson product"); } } static GEN Haberland(GEN PF, GEN PG, GEN vEF, GEN vEG, long k) { GEN S = gen_0, vC = vecbinomial(k-2); /* vC[n+1] = (-1)^n binom(k-2,n) */ long n, j, l = lg(PG); for (n = 2; n < k; n+=2) gel(vC,n) = negi(gel(vC,n)); for (j = 1; j < l; j++) { GEN PFj = gel(PF,j), PGj = gel(PG,j); for (n = 0; n <= k-2; n++) { GEN a = RgX_coeff(PGj, k-2-n), b = RgX_coeff(PFj, n); a = Rg_embedall(a, vEG); b = Rg_embedall(b, vEF); a = conj_i(a); if (typ(a) == t_VEC) settyp(a, t_COL); /* a*b = scalar or t_VEC or t_COL or t_MAT */ S = gadd(S, gdiv(gmul(a,b), gel(vC,n+1))); } } S = mulcxpowIs(gmul2n(S, 1-k), 1+k); return vEF==vEG? real_i(S): S; } /* F1S, F2S both symbols, same mf */ static GEN mfpeterssonnoncusp(GEN F1S, GEN F2S) { pari_sp av = avma; GEN mf, F1, F2, GF1, GF2, P2, cosets, vE1, vE2, FE1, FE2, P; GEN I, IP1, RHO, RHOP1, INF, res, ress; const double height = sqrt(3.)/2; long k, r, j, bitprec, prec; mf = fs_get_MF(F1S); FE1 = fs_get_EF(F1S); F1 = gel(FE1, 1); FE2 = fs_get_EF(F2S); F2 = gel(FE2, 1); cosets = fs_get_cosets(F1S); bitprec = minuu(fs_get_bitprec(F1S), fs_get_bitprec(F2S)); prec = nbits2prec(bitprec); F1S = fs_set_expan(F1S, mfgaexpansionall(mf, FE1, cosets, height, prec)); if (F2S != F1S) F2S = fs_set_expan(F2S, mfgaexpansionall(mf, FE2, cosets, height, prec)); k = MF_get_k(mf); r = lg(cosets) - 1; vE1 = fs_get_vE(F1S); vE2 = fs_get_vE(F2S); I = gen_I(); IP1 = mkcomplex(gen_1,gen_1); RHO = rootsof1u_cx(3, prec+1); RHOP1 = gaddsg(1, RHO); INF = mkoo(); mffvanish(mf, F1, F2, cosets, &res, &ress); P2 = fs_get_pols(F2S); GF1 = cgetg(r+1, t_VEC); GF2 = cgetg(r+1, t_VEC); P = get_P(k, fetch_var(), prec); for (j = 1; j <= r; j++) { GEN g = gel(cosets,j); if (res[j]) { gel(GF1,j) = mfsymboleval_direct(F1S, mkvec2(RHOP1,INF), g, P); gel(GF2,j) = mfsymboleval_direct(F2S, mkvec2(I,IP1), g, P); } else if (ress[j]) { gel(GF1,j) = mfsymboleval_direct(F1S, mkvec2(RHOP1,RHO), g, P); gel(GF2,j) = mfsymboleval_direct(F2S, mkvec2(I,INF), g, P); } else { gel(GF1,j) = mfsymboleval_direct(F1S, mkvec2(RHO,I), g, P); gel(GF2,j) = gneg(gel(P2,j)); /* - symboleval(F2S, [0,oo] */ } } delete_var(); return gerepileupto(av, gdivgs(Haberland(GF1,GF2, vE1,vE2, k), r)); } /* Petersson product of F and G, given by mfsymbol's [k > 1 integral] */ static GEN mfpetersson_i(GEN FS, GEN GS) { pari_sp av = avma; GEN mf, ESF, ESG, PF, PG, PH, CHI, cosets, vEF, vEG; long k, r, j, N, bitprec, prec; if (!checkfs_i(FS)) pari_err_TYPE("mfpetersson",FS); mf = fs_get_MF(FS); ESF = fs_get_vES(FS); if (!GS) GS = FS; else { if (!checkfs_i(GS)) pari_err_TYPE("mfpetersson",GS); if (!mfs_checkmf(GS, mf)) pari_err_TYPE("mfpetersson [different mf]", mkvec2(FS,GS)); } ESG = fs_get_vES(GS); if (!gequal0(gel(ESF,1)) && !gequal0(gel(ESG,1))) return mfpeterssonnoncusp(FS, GS); if (gequal0(gel(ESF,2)) || gequal0(gel(ESG,2))) { avma = av; return gen_0; } N = MF_get_N(mf); k = MF_get_k(mf); CHI = MF_get_CHI(mf); PF = fs_get_pols(FS); vEF = fs_get_vE(FS); PG = fs_get_pols(GS); vEG = fs_get_vE(GS); cosets = fs_get_cosets(FS); bitprec = minuu(fs_get_bitprec(FS), fs_get_bitprec(GS)); prec = nbits2prec(bitprec); r = lg(PG)-1; PH = cgetg(r+1, t_VEC); for (j = 1; j <= r; j++) { GEN ga = gel(cosets,j), PGj1, PGjm1; long iT, D; iT = mftocoset_iD(N, ZM_mulTi(ga), cosets, &D); PGj1 = RgX_translate(gel(PG, iT), gen_1); PGj1 = RgX_Rg_mul(PGj1, mfcharcxeval(CHI, D, prec)); iT = mftocoset_iD(N, ZM_mulT(ga), cosets, &D); PGjm1 = RgX_translate(gel(PG,iT), gen_m1); PGjm1 = RgX_Rg_mul(PGjm1, mfcharcxeval(CHI, D, prec)); gel(PH,j) = gsub(PGj1, PGjm1); } return gerepileupto(av, gdivgs(Haberland(PF, PH, vEF, vEG, k), 6*r)); } /****************************************************************/ /* Petersson products using Nelson-Collins */ /****************************************************************/ /* Compute W(k,z) = \sum_{m >= 1} (mz)^{k-1}(mzK_{k-2}(mz)-K_{k-1}(mz)) * for z>0 and absolute accuracy < 2^{-B}. * K_k(x) ~ (\pi/(2x))^{1/2}e^{-x} */ static void Wcomputeparams(GEN *ph, long *pN, long k, GEN x, long prec) { double B = prec2nbits(prec) + 10; double dx = gtodouble(x); double C = B + k*log(dx)/M_LN2 + 1; double D = C*M_LN2 + 2.065; double F = 2*((C - 1)*M_LN2 + log(gtodouble(mpfact(k))))/dx; double T = log(F) * (1 + 2*k/dx/F); double PI2 = M_PI*M_PI; *pN = (long)ceil((T/PI2) * (D + log(D/PI2))); *ph = gprec_w(dbltor(T / *pN), prec); } static void Wcomputecoshall(GEN *pCOSH, GEN *pCOSHK, GEN *pCOSHKm1, GEN h, long N, long k, long prec) { GEN COSH, COSHK, COSHKm1, z = gexp(h, prec), zkm1 = gpowgs(z, k - 1); GEN PO = gpowers(z, N), INV = ginv(gel(PO, N + 1)); GEN POKm1 = gpowers(zkm1, N), INVKm1 = ginv(gel(POKm1, N + 1)); long j; *pCOSH = COSH = cgetg(N+2, t_VEC); *pCOSHK = COSHK = cgetg(N+2, t_VEC); *pCOSHKm1 = COSHKm1 = cgetg(N+2, t_VEC); gel(COSH, 1) = gen_1; gel(COSHK, 1) = gen_1; gel(COSHKm1, 1) = gen_1; for (j = 1; j <= N; j++) { GEN ejh = gel(PO, j+1), emjh = gmul(gel(PO, N-j+1), INV); GEN ekm1jh = gel(POKm1, j+1), ekm1mjh = gmul(gel(POKm1, N-j+1), INVKm1); gel(COSH, j+1) = gmul2n(gadd(ejh, emjh), -1); gel(COSHKm1, j+1) = gmul2n(gadd(ekm1jh, ekm1mjh), -1); gel(COSHK, j+1) = gmul2n(gadd(gmul(ejh, ekm1jh), gmul(emjh, ekm1mjh)), -1); } } /* computing W(k,x) via integral */ static GEN Wint(long k, GEN VP, GEN x, long prec) { GEN Pk, Pkm1, Sm1, S, h, COSH, COSHK, COSHKm1; long N, j; Wcomputeparams(&h, &N, k, x, prec); Pk = gel(VP,k+1); Pkm1 = gel(VP,k); Wcomputecoshall(&COSH, &COSHK, &COSHKm1, h, N, k, prec); Sm1 = gen_0; S = gen_0; for (j = 0; j <= N; j++) { GEN ch = gexp(gmul(x, gel(COSH, j+1)), prec); GEN chm1 = gsubgs(ch, 1), chm1km1 = gpowgs(chm1, k); GEN tkm1, tk; tk = gmul(gdiv(gsubst(Pk, 0, ch), gmul(chm1, chm1km1)), gel(COSHK, j+1)); tkm1 = gmul(gdiv(gsubst(Pkm1, 0, ch), chm1km1), gel(COSHKm1, j+1)); if (!j) { tk = gmul2n(tk, -1); tkm1 = gmul2n(tkm1, -1); } S = gadd(S, tk); Sm1 = gadd(Sm1, tkm1); } return gmul(gmul(h, gpowgs(x, k-1)), gsub(gmul(x, S), gmulsg(2*k-1, Sm1))); } /* P_j given P_{j-1} */ static GEN nextP(GEN P, long j, GEN Xm1) { return RgX_shift_shallow(gsub(gmulsg(j, P), gmul(Xm1, ZX_deriv(P))), 1); } static GEN get_vP(long k) { GEN v = cgetg(k+2, t_VEC), Xm1 = deg1pol_shallow(gen_1,gen_m1,0); long j; gel(v,1) = gen_1; gel(v,2) = pol_x(0); for (j = 2; j <= k; j++) gel(v,j+1) = nextP(gel(v,j), j, Xm1); return v; } /* vector of (-1)^j(1/(exp(x)-1))^(j) [x = z] * z^j for 0<=j<=k */ static GEN VS(long k, GEN z, GEN V, long prec) { GEN ex = gexp(z, prec), c = ginv(gsubgs(ex,1)); GEN po = gpowers0(gmul(c, z), k, c); long j; V = gsubst(V, 0, ex); for (j = 1; j <= k + 1; j++) gel(V,j) = gmul(gel(V,j), gel(po, j)); return V; } /* U(k,x)=sum_{m >= 1} (mx)^{k+1/2}K_{k+1/2}(mx) */ static GEN Unelsonhalf(long k, GEN V) { GEN S = gel(V,k+1), C = gen_1; /* (k+j)! / j! / (k-j)! */ long j; if (!k) return S; for (j = 1; j <= k; j++) { C = gdivgs(gmulgs(C, (k+j)*(k-j+1)), j); S = gadd(S, gmul2n(gmul(C, gel(V, k-j+1)), -j)); } return S; } /* W(k+1/2,z) / sqrt(Pi/2) */ static GEN Whalfint(long k, GEN VP, GEN z, long prec) { GEN R, V = VS(k, z, VP, prec); R = Unelsonhalf(k, V); if (k) R = gsub(R, gmulsg(2*k, Unelsonhalf(k-1, V))); return R; } static GEN WfromZ(GEN Z, GEN VP, GEN gkm1, long k2, GEN pi4, long prec) { GEN Zk = gpow(Z, gkm1, prec), z = gmul(pi4, gsqrt(Z,prec)); z = odd(k2)? Whalfint(k2 >> 1, VP, z, prec) : Wint(k2 >> 1, VP, z, prec); return gdiv(z, Zk); } static long mfindex(long N) { GEN fa; long P = N, i; if (N == 1) return 1; fa = gel(factoru(N), 1); for (i = 1; i < lg(fa); ++i) P += P/fa[i]; return P; } /* mf a true mf or an fs2 */ static GEN fs2_init(GEN mf, GEN F, long bit) { pari_sp av = avma; long i, l, lim, N, k, k2, prec = nbits2prec(bit); GEN DEN, cusps, tab, gk, gkm1, W0, vW, vVW, vVF, vP, al0; GEN vE = mfgetembed(F, prec), pi4 = Pi2n(2, prec); if (lg(mf) == 7) { vW = NULL; /* true mf */ DEN = cusps = NULL; /* -Wall */ } else { /* mf already an fs2, reset if its precision is too low */ vW = (fs2_get_bitprec(mf) < bit)? NULL: fs2_get_W(mf); cusps = fs2_get_cusps(mf); DEN = fs2_get_den(mf); mf = fs2_get_MF(mf); } N = MF_get_N(mf); gk = MF_get_gk(mf); gkm1 = gsubgs(gk, 1); k2 = itos(gmul2n(gk,1)); k = k2 >> 1; vP = get_vP(k); if (vW) { tab = gel(vW,1); /* attached to cusp 0, width N */ lim = (lg(tab)-1) / N; } else { /* true mf */ double kd = gtodouble(gk), B = (bit + 10)*M_LN2; double L = (B + kd*log(B) + kd*kd*log(B)/B) / (4*M_PI); long n, Lw; lim = ((long)ceil(L*L)); Lw = N*lim; tab = cgetg(Lw+1,t_VEC); for (n = 1; n <= Lw; n++) { pari_sp av = avma; gel(tab,n) = gerepileupto(av, WfromZ(sstoQ(n,N),vP, gkm1, k2, pi4, prec)); } cusps = mfcusps_i(N); DEN = gmul2n(gmulgs(gpow(Pi2n(3, prec), gkm1, prec), mfindex(N)), -2); if (odd(k2)) DEN = gdiv(DEN, sqrtr_abs(Pi2n(-1,prec))); } l = lg(cusps); vVF = cgetg(l, t_VEC); vVW = cgetg(l, t_VEC); al0 = cgetg(l, t_VECSMALL); W0 = k2==1? ginv(pi4): gen_0; for (i = 1; i < l; i++) { long A, C, w, wi, Lw, n; GEN VF, W, paramsf, al; (void)cusp_AC(gel(cusps,i), &A,&C); wi = ugcd(N, C*C); w = N / wi; Lw = w*lim; VF = mfslashexpansion(mf, F, cusp2mat(A,C), Lw, 0, ¶msf, prec); /* paramsf[2] = w */ av = avma; al = gel(paramsf, 1); if (gequal0(al)) al = NULL; for (n = 0; n <= Lw; n++) { GEN a = gel(VF,n+1); gel(VF,n+1) = gequal0(a)? gen_0: Rg_embedall(a, vE); } if (vW) W = gel(vW, i); else { W = cgetg(Lw+2, t_VEC); for (n = 0; n <= Lw; n++) { GEN c; if (!al) c = n? gel(tab, n * wi): W0; else { pari_sp av = avma; c = gerepileupto(av, WfromZ(gadd(al,sstoQ(n,w)),vP,gkm1,k2,pi4, prec)); } gel(W,n+1) = c; } } al0[i] = !al; gel(vVF, i) = VF; gel(vVW, i) = W; } if (k2 <= 1) al0 = zero_zv(l-1); /* no need to test for convergence */ return gerepilecopy(av, mkvecn(7, mf,vVW,cusps,vVF,utoipos(bit),al0,DEN)); } static GEN mfpetersson2(GEN Fs, GEN Gs) { pari_sp av = avma; GEN VC, RES, vF, vG, vW = fs2_get_W(Fs), al0 = fs2_get_al0(Fs); long N = MF_get_N(fs2_get_MF(Fs)), j, lC; VC = fs2_get_cusps(Fs); lC = lg(VC); vF = fs2_get_F(Fs); vG = Gs? fs2_get_F(Gs): vF; RES = gen_0; for (j = 1; j < lC; j++) { GEN W = gel(vW,j), VF = gel(vF,j), VG = gel(vG,j), T = gen_0; long A, C, w, n, L = lg(W); pari_sp av = avma; (void)cusp_AC(gel(VC,j), &A,&C); w = N/ugcd(N, C*C); if (al0[j] && !isintzero(gel(VF,1)) && !isintzero(gel(VG,1))) pari_err_IMPL("divergent Petersson product"); for (n = 1; n < L; n++) { GEN b = gel(VF,n), a = gel(VG,n); if (!isintzero(a) && !isintzero(b)) { T = gadd(T, gmul(gel(W,n), gmul(conj_i(a),b))); if (gc_needed(av,2)) T = gerepileupto(av,T); } } if (w != 1) T = gmulgs(T,w); RES = gerepileupto(av, gadd(RES, T)); } if (!Gs) RES = real_i(RES); return gerepileupto(av, gdiv(RES, fs2_get_den(Fs))); } static long symbol_type(GEN F) { if (checkfs_i(F)) return 1; if (checkfs2_i(F)) return 2; return 0; } static int symbol_same_mf(GEN F, GEN G) { return gequal(gmael(F,1,1), gmael(G,1,1)); } GEN mfpetersson(GEN F, GEN G) { long tF = symbol_type(F); if (!tF) pari_err_TYPE("mfpetersson",F); if (G) { long tG = symbol_type(G); if (!tG) pari_err_TYPE("mfpetersson",F); if (tF != tG || !symbol_same_mf(F,G)) pari_err_TYPE("mfpetersson [incompatible symbols]", mkvec2(F,G)); } return (tF == 1)? mfpetersson_i(F, G): mfpetersson2(F, G); } pari-2.11.2/src/basemath/ZV.c0000644000175000017500000010673513326135265014256 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" static int check_ZV(GEN x, long l) { long i; for (i=1; i prec) prec = l; } return prec; } long ZV_max_lg(GEN x) { return ZV_max_lg_i(x, lg(x)); } static long ZM_max_lg_i(GEN x, long n, long m) { long prec = 2; if (n != 1) { long j; for (j=1; j prec) prec = l; } } return prec; } long ZM_max_lg(GEN x) { long n = lg(x); if (n==1) return 2; return ZM_max_lg_i(x, n, lgcols(x)); } GEN ZM_supnorm(GEN x) { long i, j, h, lx = lg(x); GEN s = gen_0; if (lx == 1) return gen_1; h = lgcols(x); for (j=1; j 0) s = c; } } return absi(s); } /********************************************************************/ /** **/ /** MULTIPLICATION **/ /** **/ /********************************************************************/ /* x non-empty ZM, y a compatible nc (dimension > 0). */ static GEN ZM_nc_mul_i(GEN x, GEN y, long c, long l) { long i, j; pari_sp av; GEN z = cgetg(l,t_COL), s; for (i=1; i 0). */ static GEN ZM_zc_mul_i(GEN x, GEN y, long c, long l) { long i, j; GEN z = cgetg(l,t_COL); for (i=1; i 0). */ GEN zv_ZM_mul(GEN x, GEN y) { long i,j, lx = lg(x), ly = lg(y); GEN z; if (lx == 1) return zerovec(ly-1); z = cgetg(ly,t_VEC); for (j=1; j 0). */ GEN ZM_zm_mul(GEN x, GEN y) { long j, c, l = lg(x), ly = lg(y); GEN z = cgetg(ly, t_MAT); if (l == 1) return z; c = lgcols(x); for (j = 1; j < ly; j++) gel(z,j) = ZM_zc_mul_i(x, gel(y,j), l,c); return z; } /* x ZM, y a compatible zn (dimension > 0). */ GEN ZM_nm_mul(GEN x, GEN y) { long j, c, l = lg(x), ly = lg(y); GEN z = cgetg(ly, t_MAT); if (l == 1) return z; c = lgcols(x); for (j = 1; j < ly; j++) gel(z,j) = ZM_nc_mul_i(x, gel(y,j), l,c); return z; } /* Strassen-Winograd algorithm */ /* Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb] as an (m x n)-matrix, padding the input with zeroes as necessary. */ static GEN add_slices(long m, long n, GEN A, long ma, long da, long na, long ea, GEN B, long mb, long db, long nb, long eb) { long min_d = minss(da, db), min_e = minss(ea, eb), i, j; GEN M = cgetg(n + 1, t_MAT), C; for (j = 1; j <= min_e; j++) { gel(M, j) = C = cgetg(m + 1, t_COL); for (i = 1; i <= min_d; i++) gel(C, i) = addii(gcoeff(A, ma + i, na + j), gcoeff(B, mb + i, nb + j)); for (; i <= da; i++) gel(C, i) = gcoeff(A, ma + i, na + j); for (; i <= db; i++) gel(C, i) = gcoeff(B, mb + i, nb + j); for (; i <= m; i++) gel(C, i) = gen_0; } for (; j <= ea; j++) { gel(M, j) = C = cgetg(m + 1, t_COL); for (i = 1; i <= da; i++) gel(C, i) = gcoeff(A, ma + i, na + j); for (; i <= m; i++) gel(C, i) = gen_0; } for (; j <= eb; j++) { gel(M, j) = C = cgetg(m + 1, t_COL); for (i = 1; i <= db; i++) gel(C, i) = gcoeff(B, mb + i, nb + j); for (; i <= m; i++) gel(C, i) = gen_0; } for (; j <= n; j++) gel(M, j) = zerocol(m); return M; } /* Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb] as an (m x n)-matrix, padding the input with zeroes as necessary. */ static GEN subtract_slices(long m, long n, GEN A, long ma, long da, long na, long ea, GEN B, long mb, long db, long nb, long eb) { long min_d = minss(da, db), min_e = minss(ea, eb), i, j; GEN M = cgetg(n + 1, t_MAT), C; for (j = 1; j <= min_e; j++) { gel(M, j) = C = cgetg(m + 1, t_COL); for (i = 1; i <= min_d; i++) gel(C, i) = subii(gcoeff(A, ma + i, na + j), gcoeff(B, mb + i, nb + j)); for (; i <= da; i++) gel(C, i) = gcoeff(A, ma + i, na + j); for (; i <= db; i++) gel(C, i) = negi(gcoeff(B, mb + i, nb + j)); for (; i <= m; i++) gel(C, i) = gen_0; } for (; j <= ea; j++) { gel(M, j) = C = cgetg(m + 1, t_COL); for (i = 1; i <= da; i++) gel(C, i) = gcoeff(A, ma + i, na + j); for (; i <= m; i++) gel(C, i) = gen_0; } for (; j <= eb; j++) { gel(M, j) = C = cgetg(m + 1, t_COL); for (i = 1; i <= db; i++) gel(C, i) = negi(gcoeff(B, mb + i, nb + j)); for (; i <= m; i++) gel(C, i) = gen_0; } for (; j <= n; j++) gel(M, j) = zerocol(m); return M; } static GEN ZM_mul_i(GEN x, GEN y, long l, long lx, long ly); /* Strassen-Winograd matrix product A (m x n) * B (n x p) */ static GEN ZM_mul_sw(GEN A, GEN B, long m, long n, long p) { pari_sp av = avma; long m1 = (m + 1)/2, m2 = m/2, n1 = (n + 1)/2, n2 = n/2, p1 = (p + 1)/2, p2 = p/2; GEN A11, A12, A22, B11, B21, B22, S1, S2, S3, S4, T1, T2, T3, T4, M1, M2, M3, M4, M5, M6, M7, V1, V2, V3, C11, C12, C21, C22, C; T2 = subtract_slices(n1, p2, B, 0, n1, p1, p2, B, n1, n2, p1, p2); S1 = subtract_slices(m2, n1, A, m1, m2, 0, n1, A, 0, m2, 0, n1); M2 = ZM_mul_i(S1, T2, m2 + 1, n1 + 1, p2 + 1); if (gc_needed(av, 1)) gerepileall(av, 2, &T2, &M2); /* destroy S1 */ T3 = subtract_slices(n1, p1, T2, 0, n1, 0, p2, B, 0, n1, 0, p1); if (gc_needed(av, 1)) gerepileall(av, 2, &M2, &T3); /* destroy T2 */ S2 = add_slices(m2, n1, A, m1, m2, 0, n1, A, m1, m2, n1, n2); T1 = subtract_slices(n1, p1, B, 0, n1, p1, p2, B, 0, n1, 0, p2); M3 = ZM_mul_i(S2, T1, m2 + 1, n1 + 1, p2 + 1); if (gc_needed(av, 1)) gerepileall(av, 4, &M2, &T3, &S2, &M3); /* destroy T1 */ S3 = subtract_slices(m1, n1, S2, 0, m2, 0, n1, A, 0, m1, 0, n1); if (gc_needed(av, 1)) gerepileall(av, 4, &M2, &T3, &M3, &S3); /* destroy S2 */ A11 = matslice(A, 1, m1, 1, n1); B11 = matslice(B, 1, n1, 1, p1); M1 = ZM_mul_i(A11, B11, m1 + 1, n1 + 1, p1 + 1); if (gc_needed(av, 1)) gerepileall(av, 5, &M2, &T3, &M3, &S3, &M1); /* destroy A11, B11 */ A12 = matslice(A, 1, m1, n1 + 1, n); B21 = matslice(B, n1 + 1, n, 1, p1); M4 = ZM_mul_i(A12, B21, m1 + 1, n2 + 1, p1 + 1); if (gc_needed(av, 1)) gerepileall(av, 6, &M2, &T3, &M3, &S3, &M1, &M4); /* destroy A12, B21 */ C11 = add_slices(m1, p1, M1, 0, m1, 0, p1, M4, 0, m1, 0, p1); if (gc_needed(av, 1)) gerepileall(av, 6, &M2, &T3, &M3, &S3, &M1, &C11); /* destroy M4 */ M5 = ZM_mul_i(S3, T3, m1 + 1, n1 + 1, p1 + 1); S4 = subtract_slices(m1, n2, A, 0, m1, n1, n2, S3, 0, m1, 0, n2); if (gc_needed(av, 1)) gerepileall(av, 7, &M2, &T3, &M3, &M1, &C11, &M5, &S4); /* destroy S3 */ T4 = add_slices(n2, p1, B, n1, n2, 0, p1, T3, 0, n2, 0, p1); if (gc_needed(av, 1)) gerepileall(av, 7, &M2, &M3, &M1, &C11, &M5, &S4, &T4); /* destroy T3 */ V1 = subtract_slices(m1, p1, M1, 0, m1, 0, p1, M5, 0, m1, 0, p1); if (gc_needed(av, 1)) gerepileall(av, 6, &M2, &M3, &S4, &T4, &C11, &V1); /* destroy M1, M5 */ B22 = matslice(B, n1 + 1, n, p1 + 1, p); M6 = ZM_mul_i(S4, B22, m1 + 1, n2 + 1, p2 + 1); if (gc_needed(av, 1)) gerepileall(av, 6, &M2, &M3, &T4, &C11, &V1, &M6); /* destroy S4, B22 */ A22 = matslice(A, m1 + 1, m, n1 + 1, n); M7 = ZM_mul_i(A22, T4, m2 + 1, n2 + 1, p1 + 1); if (gc_needed(av, 1)) gerepileall(av, 6, &M2, &M3, &C11, &V1, &M6, &M7); /* destroy A22, T4 */ V3 = add_slices(m1, p2, V1, 0, m1, 0, p2, M3, 0, m2, 0, p2); C12 = add_slices(m1, p2, V3, 0, m1, 0, p2, M6, 0, m1, 0, p2); if (gc_needed(av, 1)) gerepileall(av, 6, &M2, &M3, &C11, &V1, &M7, &C12); /* destroy V3, M6 */ V2 = add_slices(m2, p1, V1, 0, m2, 0, p1, M2, 0, m2, 0, p2); if (gc_needed(av, 1)) gerepileall(av, 5, &M3, &C11, &M7, &C12, &V2); /* destroy V1, M2 */ C21 = add_slices(m2, p1, V2, 0, m2, 0, p1, M7, 0, m2, 0, p1); if (gc_needed(av, 1)) gerepileall(av, 5, &M3, &C11, &C12, &V2, &C21); /* destroy M7 */ C22 = add_slices(m2, p2, V2, 0, m2, 0, p2, M3, 0, m2, 0, p2); if (gc_needed(av, 1)) gerepileall(av, 4, &C11, &C12, &C21, &C22); /* destroy V2, M3 */ C = mkmat2(mkcol2(C11, C21), mkcol2(C12, C22)); return gerepilecopy(av, shallowmatconcat(C)); } /* x[i,]*y. Assume lg(x) > 1 and 0 < i < lgcols(x) */ static GEN ZMrow_ZC_mul_i(GEN x, GEN y, long i, long lx) { pari_sp av = avma; GEN c = mulii(gcoeff(x,i,1), gel(y,1)), ZERO = gen_0; long k; for (k = 2; k < lx; k++) { GEN t = mulii(gcoeff(x,i,k), gel(y,k)); if (t != ZERO) c = addii(c, t); } return gerepileuptoint(av, c); } GEN ZMrow_ZC_mul(GEN x, GEN y, long i) { return ZMrow_ZC_mul_i(x, y, i, lg(x)); } /* return x * y, 1 < lx = lg(x), l = lgcols(x) */ static GEN ZM_ZC_mul_i(GEN x, GEN y, long lx, long l) { GEN z = cgetg(l,t_COL); long i; for (i=1; i= ZM_sw_bound */ static GEN ZM_mul_i(GEN x, GEN y, long l, long lx, long ly) { long s = maxss(ZM_max_lg_i(x,lx,l), ZM_max_lg_i(y,ly,lx)); long ZM_sw_bound = s > 60 ? 2: s > 25 ? 4: s>15 ? 8 : s > 8 ? 16 : 32; if (l <= ZM_sw_bound || lx <= ZM_sw_bound || ly <= ZM_sw_bound) return ZM_mul_classical(x, y, l, lx, ly); else return ZM_mul_sw(x, y, l - 1, lx - 1, ly - 1); } GEN ZM_mul(GEN x, GEN y) { long lx=lg(x), ly=lg(y); if (ly==1) return cgetg(1,t_MAT); if (lx==1) return zeromat(0, ly-1); return ZM_mul_i(x, y, lgcols(x), lx, ly); } GEN QM_mul(GEN x, GEN y) { GEN dx, nx = Q_primitive_part(x, &dx); GEN dy, ny = Q_primitive_part(y, &dy); GEN z = ZM_mul(nx, ny); if (dx || dy) { GEN d = dx ? dy ? gmul(dx, dy): dx : dy; if (!gequal1(d)) z = ZM_Q_mul(z, d); } return z; } GEN QM_QC_mul(GEN x, GEN y) { GEN dx, nx = Q_primitive_part(x, &dx); GEN dy, ny = Q_primitive_part(y, &dy); GEN z = ZM_ZC_mul(nx, ny); if (dx || dy) { GEN d = dx ? dy ? gmul(dx, dy): dx : dy; if (!gequal1(d)) z = ZC_Q_mul(z, d); } return z; } /* assume result is symmetric */ GEN ZM_multosym(GEN x, GEN y) { long j, lx, ly = lg(y); GEN M; if (ly == 1) return cgetg(1,t_MAT); lx = lg(x); /* = lgcols(y) */ if (lx == 1) return cgetg(1,t_MAT); /* ly = lgcols(x) */ M = cgetg(ly, t_MAT); for (j=1; j 1 is lg(x) = lg(y) */ static GEN ZV_dotproduct_i(GEN x, GEN y, long lx) { pari_sp av = avma; GEN c = mulii(gel(x,1), gel(y,1)); long i; for (i = 2; i < lx; i++) { GEN t = mulii(gel(x,i), gel(y,i)); if (t != gen_0) c = addii(c, t); } return gerepileuptoint(av, c); } /* x~ * y, assuming result is symmetric */ GEN ZM_transmultosym(GEN x, GEN y) { long i, j, l, ly = lg(y); GEN M; if (ly == 1) return cgetg(1,t_MAT); /* lg(x) = ly */ l = lgcols(y); /* = lgcols(x) */ M = cgetg(ly, t_MAT); for (i=1; i 60 ? 2: s > 25 ? 4: s>15 ? 8 : s > 8 ? 16 : 32; if (l <= ZM_sw_bound) return ZM_mul_classical(x, x, l, l, l); else return ZM_mul_sw(x, x, l - 1, l - 1, l - 1); } GEN ZM_sqr(GEN x) { long lx=lg(x); if (lx==1) return cgetg(1,t_MAT); return ZM_sqr_i(x, lx); } GEN ZM_ZC_mul(GEN x, GEN y) { long lx = lg(x); return lx==1? cgetg(1,t_COL): ZM_ZC_mul_i(x, y, lx, lgcols(x)); } GEN ZC_Z_div(GEN x, GEN c) { pari_APPLY_type(t_COL, Qdivii(gel(x,i), c)) } GEN ZM_Z_div(GEN x, GEN c) { pari_APPLY_same(ZC_Z_div(gel(x, i), c)) } GEN ZC_Q_mul(GEN A, GEN z) { pari_sp av = avma; long i, l = lg(A); GEN d, n, Ad, B, u; if (typ(z)==t_INT) return ZC_Z_mul(A,z); n = gel(z, 1); d = gel(z, 2); Ad = FpC_red(A, d); u = gcdii(d, FpV_factorback(Ad, NULL, d)); B = cgetg(l, t_COL); if (equali1(u)) { for(i=1; i 0)? ZC_copy(x): ZC_neg(x); pari_APPLY_type(t_COL, mulii(gel(x,i), c)) } GEN ZC_z_mul(GEN x, long c) { if (!c) return zerocol(lg(x)-1); if (c == 1) return ZC_copy(x); if (c ==-1) return ZC_neg(x); pari_APPLY_type(t_COL, mulsi(c, gel(x,i))) } GEN zv_z_mul(GEN x, long n) { pari_APPLY_long(x[i]*n) } /* return a ZM */ GEN nm_Z_mul(GEN X, GEN c) { long i, j, h, l = lg(X), s = signe(c); GEN A; if (l == 1) return cgetg(1, t_MAT); h = lgcols(X); if (!s) return zeromat(h-1, l-1); if (is_pm1(c)) { if (s > 0) return Flm_to_ZM(X); X = Flm_to_ZM(X); ZM_togglesign(X); return X; } A = cgetg(l, t_MAT); for (j = 1; j < l; j++) { GEN a = cgetg(h, t_COL), x = gel(X, j); for (i = 1; i < h; i++) gel(a,i) = muliu(c, x[i]); gel(A,j) = a; } return A; } GEN ZM_Z_mul(GEN X, GEN c) { long i, j, h, l = lg(X); GEN A; if (l == 1) return cgetg(1, t_MAT); h = lgcols(X); if (!signe(c)) return zeromat(h-1, l-1); if (is_pm1(c)) return (signe(c) > 0)? ZM_copy(X): ZM_neg(X); A = cgetg(l, t_MAT); for (j = 1; j < l; j++) { GEN a = cgetg(h, t_COL), x = gel(X, j); for (i = 1; i < h; i++) gel(a,i) = mulii(c, gel(x,i)); gel(A,j) = a; } return A; } void ZC_lincomb1_inplace_i(GEN X, GEN Y, GEN v, long n) { long i; for (i = n; i; i--) gel(X,i) = addmulii_inplace(gel(X,i), gel(Y,i), v); } /* X <- X + v Y (elementary col operation) */ void ZC_lincomb1_inplace(GEN X, GEN Y, GEN v) { if (lgefint(v) != 2) return ZC_lincomb1_inplace_i(X, Y, v, lg(X)-1); } void Flc_lincomb1_inplace(GEN X, GEN Y, ulong v, ulong q) { long i; if (!v) return; /* v = 0 */ for (i = lg(X)-1; i; i--) X[i] = Fl_add(X[i], Fl_mul(Y[i], v, q), q); } /* X + v Y, wasteful if (v = 0) */ static GEN ZC_lincomb1(GEN v, GEN x, GEN y) { pari_APPLY_type(t_COL, addmulii(gel(x,i), gel(y,i), v)) } /* -X + vY */ static GEN ZC_lincomb_1(GEN v, GEN x, GEN y) { pari_APPLY_type(t_COL, mulsubii(gel(y,i), v, gel(x,i))) } /* X,Y compatible ZV; u,v in Z. Returns A = u*X + v*Y */ GEN ZC_lincomb(GEN u, GEN v, GEN X, GEN Y) { long su, sv; GEN A; su = signe(u); if (!su) return ZC_Z_mul(Y, v); sv = signe(v); if (!sv) return ZC_Z_mul(X, u); if (is_pm1(v)) { if (is_pm1(u)) { if (su != sv) A = ZC_sub(X, Y); else A = ZC_add(X, Y); if (su < 0) ZV_togglesign(A); /* in place but was created above */ } else { if (sv > 0) A = ZC_lincomb1 (u, Y, X); else A = ZC_lincomb_1(u, Y, X); } } else if (is_pm1(u)) { if (su > 0) A = ZC_lincomb1 (v, X, Y); else A = ZC_lincomb_1(v, X, Y); } else { /* not cgetg_copy: x may be a t_VEC */ long i, lx = lg(X); A = cgetg(lx,t_COL); for (i=1; i 0) gel(M,l) = negi(gel(M,l)); } GEN ZC_neg(GEN x) { pari_APPLY_type(t_COL, negi(gel(x,i))) } GEN zv_neg(GEN x) { pari_APPLY_long(-x[i]) } GEN zv_neg_inplace(GEN M) { long l = lg(M); while (--l > 0) M[l] = -M[l]; return M; } GEN ZM_neg(GEN x) { pari_APPLY_same(ZC_neg(gel(x,i))) } void ZV_togglesign(GEN M) { long l = lg(M); while (--l > 0) togglesign_safe(&gel(M,l)); } void ZM_togglesign(GEN M) { long l = lg(M); while (--l > 0) ZV_togglesign(gel(M,l)); } /********************************************************************/ /** **/ /** "DIVISION" mod HNF **/ /** **/ /********************************************************************/ /* Reduce ZC x modulo ZM y in HNF, may return x itself (not a copy) */ GEN ZC_hnfremdiv(GEN x, GEN y, GEN *Q) { long i, l = lg(x); GEN q; if (Q) *Q = cgetg(l,t_COL); if (l == 1) return cgetg(1,t_COL); for (i = l-1; i>0; i--) { q = diviiround(gel(x,i), gcoeff(y,i,i)); if (signe(q)) { togglesign(q); x = ZC_lincomb(gen_1, q, x, gel(y,i)); } if (Q) gel(*Q, i) = q; } return x; } /* x = y Q + R, may return some columns of x (not copies) */ GEN ZM_hnfdivrem(GEN x, GEN y, GEN *Q) { long lx = lg(x), i; GEN R = cgetg(lx, t_MAT); if (Q) { GEN q = cgetg(lx, t_MAT); *Q = q; for (i=1; i 0) if (V[l]) return 0; return 1; } int ZV_equal0(GEN V) { long l = lg(V); while (--l > 0) if (signe(gel(V,l))) return 0; return 1; } static int ZV_equal_lg(GEN V, GEN W, long l) { while (--l > 0) if (!equalii(gel(V,l), gel(W,l))) return 0; return 1; } int ZV_equal(GEN V, GEN W) { long l = lg(V); if (lg(W) != l) return 0; return ZV_equal_lg(V, W, l); } int ZM_equal(GEN A, GEN B) { long i, m, l = lg(A); if (lg(B) != l) return 0; if (l == 1) return 1; m = lgcols(A); if (lgcols(B) != m) return 0; for (i = 1; i < l; i++) if (!ZV_equal_lg(gel(A,i), gel(B,i), m)) return 0; return 1; } int ZM_equal0(GEN A) { long i, j, m, l = lg(A); if (l == 1) return 1; m = lgcols(A); for (j = 1; j < l; j++) for (i = 1; i < m; i++) if (signe(gcoeff(A,i,j))) return 0; return 1; } int zv_equal(GEN V, GEN W) { long l = lg(V); if (lg(W) != l) return 0; while (--l > 0) if (V[l] != W[l]) return 0; return 1; } int zvV_equal(GEN V, GEN W) { long l = lg(V); if (lg(W) != l) return 0; while (--l > 0) if (!zv_equal(gel(V,l),gel(W,l))) return 0; return 1; } int ZM_ishnf(GEN x) { long i,j, lx = lg(x); for (i=1; i=0) return 0; } } return 1; } int ZM_isidentity(GEN x) { long i,j, lx = lg(x); if (lx == 1) return 1; if (lx != lgcols(x)) return 0; for (j=1; j> 1; V = cgetg(m + (odd(n)? 2: 1), t_VEC); for (k = 1; k <= m; k++) gel(V,k) = muluu(v[k<<1], v[(k<<1)-1]); if (odd(n)) gel(V,k) = utoipos(v[n]); return gerepileuptoint(av, gen_product(V, NULL, &_mulii)); } GEN vecsmall_prod(GEN v) { pari_sp av = avma; long k, m, n = lg(v)-1; GEN V; switch (n) { case 0: return gen_1; case 1: return stoi(v[1]); case 2: return mulss(v[1], v[2]); } m = n >> 1; V = cgetg(m + (odd(n)? 2: 1), t_VEC); for (k = 1; k <= m; k++) gel(V,k) = mulss(v[k<<1], v[(k<<1)-1]); if (odd(n)) gel(V,k) = stoi(v[n]); return gerepileuptoint(av, gen_product(V, NULL, &_mulii)); } GEN ZV_prod(GEN v) { pari_sp av = avma; long i, l = lg(v); GEN n; if (l == 1) return gen_1; if (l > 7) return gerepileuptoint(av, gen_product(v, NULL, _mulii)); n = gel(v,1); if (l == 2) return icopy(n); for (i = 2; i < l; i++) n = mulii(n, gel(v,i)); return gerepileuptoint(av, n); } /* assumes no overflow */ long zv_sum(GEN v) { long n, i, l = lg(v); if (l == 1) return 0; n = v[1]; for (i = 2; i < l; i++) n += v[i]; return n; } GEN ZV_sum(GEN v) { pari_sp av = avma; long i, l = lg(v); GEN n; if (l == 1) return gen_0; n = gel(v,1); if (l == 2) return icopy(n); for (i = 2; i < l; i++) n = addii(n, gel(v,i)); return gerepileuptoint(av, n); } /********************************************************************/ /** **/ /** GRAM SCHMIDT REDUCTION (integer matrices) **/ /** **/ /********************************************************************/ /* L[k,] += q * L[l,], l < k. Inefficient if q = 0 */ static void Zupdate_row(long k, long l, GEN q, GEN L, GEN B) { long i, qq = itos_or_0(q); if (!qq) { for(i=1;i= 1; k--) ZRED(nx,k, x,L,gel(B,k+1)); return gel(x,nx); } GEN ZC_reducemodmatrix(GEN v, GEN y) { pari_sp av = avma; return gerepilecopy(av, ZC_reducemodmatrix_i(v,y)); } /* Variant reducemodinvertible(ZM v, ZM y), when y singular. * Very inefficient if y is not LLL-reduced of maximal rank */ static GEN ZM_reducemodmatrix_i(GEN v, GEN y) { GEN B, L, V; long j, k, lv = lg(v), nx = lg(y), lx = nx+1; V = cgetg(lv, t_MAT); B = scalarcol_shallow(gen_1, lx); L = zeromatcopy(nx, nx); for (k=1; k < nx; k++) ZincrementalGS(y, L, B, k); for (j = 1; j < lg(v); j++) { GEN x = shallowconcat(y, gel(v,j)); ZincrementalGS(x, L, B, nx); /* overwrite last */ for (k = nx-1; k >= 1; k--) ZRED(nx,k, x,L,gel(B,k+1)); gel(V,j) = gel(x,nx); } return V; } GEN ZM_reducemodmatrix(GEN v, GEN y) { pari_sp av = avma; return gerepilecopy(av, ZM_reducemodmatrix_i(v,y)); } GEN ZC_reducemodlll(GEN x,GEN y) { pari_sp av = avma; GEN z = ZC_reducemodmatrix(x, ZM_lll(y, 0.75, LLL_INPLACE)); return gerepilecopy(av, z); } GEN ZM_reducemodlll(GEN x,GEN y) { pari_sp av = avma; GEN z = ZM_reducemodmatrix(x, ZM_lll(y, 0.75, LLL_INPLACE)); return gerepilecopy(av, z); } pari-2.11.2/src/basemath/perm.c0000644000175000017500000007360113326135265014655 0ustar billbill/* Copyright (C) 2000-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*************************************************************************/ /** **/ /** Routines for handling VEC/COL **/ /** **/ /*************************************************************************/ int vec_isconst(GEN v) { long i, l = lg(v); GEN w; if (l==1) return 1; w = gel(v,1); for(i=2;i>1, ny=n-nx; long m, ix, iy; GEN x, y; if (n<=2) { if (n==1) w[0]=v[0]; else if (n==2) { long v0=v[0], v1=v[1]; if (v0<=v1) { w[0]=v0; w[1]=v1; } else { w[0]=v1; w[1]=v0; } } return; } x=new_chunk(nx); y=new_chunk(ny); vecsmall_sortspec(v,nx,x); vecsmall_sortspec(v+nx,ny,y); for (m=0, ix=0, iy=0; ix>1; ny = n-nx; w = cgetg(n+1,t_VECSMALL); x = vecsmall_indexsortspec(v,nx); y = vecsmall_indexsortspec(v+nx,ny); for (m=1, ix=1, iy=1; ix<=nx && iy<=ny; ) if (v[x[ix]] <= v[y[iy]+nx]) w[m++] = x[ix++]; else w[m++] = y[iy++]+nx; for(;ix<=nx;) w[m++] = x[ix++]; for(;iy<=ny;) w[m++] = y[iy++]+nx; avma = (pari_sp)w; return w; } /*indirect sort.*/ GEN vecsmall_indexsort(GEN V) { long l=lg(V)-1; if (l==0) return cgetg(1, t_VECSMALL); return vecsmall_indexsortspec(V,l); } /* assume V sorted */ GEN vecsmall_uniq_sorted(GEN V) { GEN W; long i,j, l = lg(V); if (l == 1) return vecsmall_copy(V); W = cgetg(l,t_VECSMALL); W[1] = V[1]; for(i=j=2; i m) m = t; } return m; } /*************************************************************************/ /** **/ /** Routines for handling permutations **/ /** **/ /*************************************************************************/ /* Permutations may be given by * perm (VECSMALL): a bijection from 1...n to 1...n i-->perm[i] * cyc (VEC of VECSMALL): a product of disjoint cycles. */ /* Multiply (compose) two permutations, putting the result in the second one. */ static void perm_mul_inplace2(GEN s, GEN t) { long i, l = lg(s); for (i = 1; i < l; i++) t[i] = s[t[i]]; } /* Orbits of the subgroup generated by v on {1,..,n} */ static GEN vecperm_orbits_i(GEN v, long n) { long mj = 1, lv = lg(v), k, l; GEN cycle = cgetg(n+1, t_VEC), bit = const_vecsmall(n, 0); for (k = 1, l = 1; k <= n;) { long m = 1; GEN cy = cgetg(n+1, t_VECSMALL); for ( ; bit[mj]; mj++) /*empty*/; k++; cy[m++] = mj; bit[mj++] = 1; for(;;) { long o, mold = m; for (o = 1; o < lv; o++) { GEN vo = gel(v,o); long p; for (p = 1; p < m; p++) /* m increases! */ { long j = vo[ cy[p] ]; if (!bit[j]) cy[m++] = j; bit[j] = 1; } } if (m == mold) break; k += m - mold; } setlg(cy, m); gel(cycle,l++) = cy; } setlg(cycle, l); return cycle; } /* memory clean version */ GEN vecperm_orbits(GEN v, long n) { pari_sp av = avma; return gerepilecopy(av, vecperm_orbits_i(v, n)); } /* Compute the cyclic decomposition of a permutation */ GEN perm_cycles(GEN v) { pari_sp av = avma; return gerepilecopy(av, vecperm_orbits_i(mkvec(v), lg(v)-1)); } static long isperm(GEN v) { pari_sp av = avma; long i, n = lg(v)-1; GEN w; if (typ(v) != t_VECSMALL) return 0; w = zero_zv(n); for (i=1; i<=n; i++) { long d = v[i]; if (d < 1 || d > n || w[d]) { avma = av; return 0; } w[d] = 1; } avma = av; return 1; } /* Output the order of p */ long perm_order(GEN v) { pari_sp ltop = avma; GEN c = vecperm_orbits_i(mkvec(v), lg(v)-1); long i, d; for(i=1, d=1; i=1; r--) { ulong a; x = absdiviu_rem(x, n+1-r, &a); for (i=r+1; i<=(ulong)n; i++) if (uel(v,i) > a) uel(v,i)++; uel(v,r) = a+1; } avma = av; return v; } GEN numtoperm(long n, GEN x) { if (n < 0) pari_err_DOMAIN("numtoperm", "n", "<", gen_0, stoi(n)); if (typ(x) != t_INT) pari_err_TYPE("numtoperm",x); return Z_to_perm(n, x); } /* destroys v */ static GEN perm_to_Z_inplace(GEN v) { long l = lg(v), i, r; GEN x = gen_0; if (!isperm(v)) pari_err_TYPE("permsign",v); for (i = 1; i < l; i++) { long vi = v[i]; if (vi <= 0) return NULL; x = i==1 ? utoi(vi-1): addiu(muliu(x,l-i), vi-1); for (r = i+1; r < l; r++) if (v[r] > vi) v[r]--; } return x; } GEN perm_to_Z(GEN v) { pari_sp av = avma; GEN x = perm_to_Z_inplace(leafcopy(v)); if (!x) pari_err_TYPE("permtonum",v); return gerepileuptoint(av, x); } GEN permtonum(GEN p) { pari_sp av = avma; GEN v, x; switch(typ(p)) { case t_VECSMALL: return perm_to_Z(p); case t_VEC: case t_COL: if (RgV_is_ZV(p)) { v = ZV_to_zv(p); break; } default: pari_err_TYPE("permtonum",p); return NULL; } x = perm_to_Z_inplace(v); if (!x) pari_err_TYPE("permtonum",p); return gerepileuptoint(av, x); } GEN cyc_pow(GEN cyc, long exp) { long i, j, k, l, r; GEN c; for (r = j = 1; j < lg(cyc); j++) { long n = lg(gel(cyc,j)) - 1; r += cgcd(n, exp); } c = cgetg(r, t_VEC); for (r = j = 1; j < lg(cyc); j++) { GEN v = gel(cyc,j); long n = lg(v) - 1, e = smodss(exp,n), g = (long)ugcd(n, e), m = n / g; for (i = 0; i < g; i++) { GEN p = cgetg(m+1, t_VECSMALL); gel(c,r++) = p; for (k = 1, l = i; k <= m; k++) { p[k] = v[l+1]; l += e; if (l >= n) l -= n; } } } return c; } /* Compute the power of a permutation given by product of cycles * Ouput a perm, not a cyc */ GEN cyc_pow_perm(GEN cyc, long exp) { long e, j, k, l, n; GEN p; for (n = 0, j = 1; j < lg(cyc); j++) n += lg(gel(cyc,j))-1; p = cgetg(n + 1, t_VECSMALL); for (j = 1; j < lg(cyc); j++) { GEN v = gel(cyc,j); n = lg(v) - 1; e = smodss(exp, n); for (k = 1, l = e; k <= n; k++) { p[v[k]] = v[l+1]; if (++l == n) l = 0; } } return p; } GEN perm_pow(GEN perm, long exp) { long i, r = lg(perm)-1; GEN p = zero_zv(r); pari_sp av = avma; GEN v = cgetg(r+1, t_VECSMALL); for (i=1; i<=r; i++) { long e, n, k, l; if (p[i]) continue; v[1] = i; for (n=1, k=perm[i]; k!=i; k=perm[k], n++) v[n+1] = k; e = smodss(exp, n); for (k = 1, l = e; k <= n; k++) { p[v[k]] = v[l+1]; if (++l == n) l = 0; } } avma = av; return p; } static GEN perm_to_GAP(GEN p) { pari_sp ltop=avma; GEN gap; GEN x; long i; long nb, c=0; char *s; long sz; long lp=lg(p)-1; if (typ(p) != t_VECSMALL) pari_err_TYPE("perm_to_GAP",p); x = perm_cycles(p); sz = (long) ((bfffo(lp)+1) * LOG10_2 + 1); /*Dry run*/ for (i = 1, nb = 1; i < lg(x); ++i) { GEN z = gel(x,i); long lz = lg(z)-1; nb += 1+lz*(sz+2); } nb++; /*Real run*/ gap = cgetg(nchar2nlong(nb) + 1, t_STR); s = GSTR(gap); for (i = 1; i < lg(x); ++i) { long j; GEN z = gel(x,i); if (lg(z) > 2) { s[c++] = '('; for (j = 1; j < lg(z); ++j) { if (j > 1) { s[c++] = ','; s[c++] = ' '; } sprintf(s+c,"%ld",z[j]); while(s[c++]) /* empty */; c--; } s[c++] = ')'; } } if (!c) { s[c++]='('; s[c++]=')'; } s[c] = '\0'; return gerepileupto(ltop,gap); } int perm_commute(GEN s, GEN t) { long i, l = lg(t); for (i = 1; i < l; i++) if (t[ s[i] ] != s[ t[i] ]) return 0; return 1; } /*************************************************************************/ /** **/ /** Routines for handling groups **/ /** **/ /*************************************************************************/ /* A Group is a t_VEC [gen,orders] * gen (vecvecsmall): list of generators given by permutations * orders (vecsmall): relatives orders of generators. */ INLINE GEN grp_get_gen(GEN G) { return gel(G,1); } INLINE GEN grp_get_ord(GEN G) { return gel(G,2); } /* A Quotient Group is a t_VEC [gen,coset] * gen (vecvecsmall): coset generators * coset (vecsmall): gen[coset[p[1]]] generate the p-coset. */ INLINE GEN quo_get_gen(GEN C) { return gel(C,1); } INLINE GEN quo_get_coset(GEN C) { return gel(C,2); } static GEN trivialsubgroups(void) { GEN L = cgetg(2, t_VEC); gel(L,1) = trivialgroup(); return L; } /* Compute the order of p modulo the group given by a set */ long perm_relorder(GEN p, GEN set) { pari_sp ltop = avma; long n = 1; long q = p[1]; while (!F2v_coeff(set,q)) { q = p[q]; n++; } avma = ltop; return n; } GEN perm_generate(GEN S, GEN H, long o) { long i, n = lg(H)-1; GEN L = cgetg(n*o + 1, t_VEC); for(i=1; i<=n; i++) gel(L,i) = vecsmall_copy(gel(H,i)); for( ; i <= n*o; i++) gel(L,i) = perm_mul(gel(L,i-n), S); return L; } /*Return the order (cardinality) of a group */ long group_order(GEN G) { return zv_prod(grp_get_ord(G)); } /* G being a subgroup of S_n, output n */ long group_domain(GEN G) { GEN gen = grp_get_gen(G); if (lg(gen) < 2) pari_err_DOMAIN("group_domain", "#G", "=", gen_1,G); return lg(gel(gen,1)) - 1; } /*Left coset of g mod G: gG*/ GEN group_leftcoset(GEN G, GEN g) { GEN gen = grp_get_gen(G), ord = grp_get_ord(G); GEN res = cgetg(group_order(G)+1, t_VEC); long i, j, k; gel(res,1) = vecsmall_copy(g); k = 1; for (i = 1; i < lg(gen); i++) { long c = k * (ord[i] - 1); for (j = 1; j <= c; j++) gel(res,++k) = perm_mul(gel(res,j), gel(gen,i)); } return res; } /*Right coset of g mod G: Gg*/ GEN group_rightcoset(GEN G, GEN g) { GEN gen = grp_get_gen(G), ord = grp_get_ord(G); GEN res = cgetg(group_order(G)+1, t_VEC); long i, j, k; gel(res,1) = vecsmall_copy(g); k = 1; for (i = 1; i < lg(gen); i++) { long c = k * (ord[i] - 1); for (j = 1; j <= c; j++) gel(res,++k) = perm_mul(gel(gen,i), gel(res,j)); } return res; } /*Elements of a group from the generators, cf group_leftcoset*/ GEN group_elts(GEN G, long n) { GEN gen = grp_get_gen(G), ord = grp_get_ord(G); GEN res = cgetg(group_order(G)+1, t_VEC); long i, j, k; gel(res,1) = identity_perm(n); k = 1; for (i = 1; i < lg(gen); i++) { long c = k * (ord[i] - 1); /* j = 1, use res[1] = identity */ gel(res,++k) = vecsmall_copy(gel(gen,i)); for (j = 2; j <= c; j++) gel(res,++k) = perm_mul(gel(res,j), gel(gen,i)); } return res; } GEN groupelts_set(GEN elts, long n) { GEN res = zero_F2v(n); long i, l = lg(elts); for(i=1; i G/H */ /*The ouput is [gen,hash]*/ /* gen (vecvecsmall): coset generators * coset (vecsmall): vecsmall of coset number) */ GEN group_quotient(GEN G, GEN H) { pari_sp ltop = avma; GEN p2, p3; long i, j, a = 1; long n = group_domain(G), o = group_order(H); GEN elt = group_elts(G,n), el; long le = lg(elt)-1; GEN used = zero_F2v(le+1); long l = le/o; p2 = cgetg(l+1, t_VEC); p3 = zero_zv(n); el = zero_zv(n); for (i = 1; i<=le; i++) el[mael(elt,i,1)]=i; for (i = 1; i <= l; ++i) { GEN V; while(F2v_coeff(used,a)) a++; V = group_leftcoset(H,gel(elt,a)); gel(p2,i) = gel(V,1); for(j=1;j G/H * * Lift a subgroup S of G/H to a subgroup of G containing H */ GEN quotient_subgroup_lift(GEN C, GEN H, GEN S) { GEN genH = grp_get_gen(H); GEN genS = grp_get_gen(S); GEN genC = quo_get_gen(C); long l1 = lg(genH)-1; long l2 = lg(genS)-1, j; GEN p1 = cgetg(3, t_VEC), L = cgetg(l1+l2+1, t_VEC); for (j = 1; j <= l1; ++j) gel(L,j) = gel(genH,j); for (j = 1; j <= l2; ++j) gel(L,l1+j) = gel(genC, mael(genS,j,1)); gel(p1,1) = L; gel(p1,2) = vecsmall_concat(grp_get_ord(H), grp_get_ord(S)); return p1; } /* Let G a group and C a quotient map G --> G/H * Assume H is normal, return the group G/H */ GEN quotient_group(GEN C, GEN G) { pari_sp ltop = avma; GEN Qgen, Qord, Qelt, Qset, Q; GEN Cgen = quo_get_gen(C); GEN Ggen = grp_get_gen(G); long i,j, n = lg(Cgen)-1, l = lg(Ggen); Qord = cgetg(l, t_VECSMALL); Qgen = cgetg(l, t_VEC); Qelt = mkvec(identity_perm(n)); Qset = groupelts_set(Qelt, n); for (i = 1, j = 1; i < l; ++i) { GEN g = quotient_perm(C, gel(Ggen,i)); long o = perm_relorder(g, Qset); gel(Qgen,j) = g; Qord[j] = o; if (o != 1) { Qelt = perm_generate(g, Qelt, o); Qset = groupelts_set(Qelt, n); j++; } } setlg(Qgen,j); setlg(Qord,j); Q = mkvec2(Qgen, Qord); return gerepilecopy(ltop,Q); } /* Return 1 if g normalizes N, 0 otherwise */ long group_perm_normalize(GEN N, GEN g) { pari_sp ltop = avma; long r = gequal(vecvecsmall_sort(group_leftcoset(N, g)), vecvecsmall_sort(group_rightcoset(N, g))); avma = ltop; return r; } /* L is a list of subgroups, C is a coset and r a relative order.*/ static GEN liftlistsubgroups(GEN L, GEN C, long r) { pari_sp ltop = avma; long c = lg(C)-1, l = lg(L)-1, n = lg(gel(C,1))-1, i, k; GEN R; if (!l) return cgetg(1,t_VEC); R = cgetg(l*c+1, t_VEC); for (i = 1, k = 1; i <= l; ++i) { GEN S = gel(L,i), Selt = group_set(S,n); GEN gen = grp_get_gen(S); GEN ord = grp_get_ord(S); long j; for (j = 1; j <= c; ++j) { GEN p = gel(C,j); if (perm_relorder(p, Selt) == r && group_perm_normalize(S, p)) gel(R,k++) = mkvec2(vec_append(gen, p), vecsmall_append(ord, r)); } } setlg(R, k); return gerepilecopy(ltop, R); } /* H is a normal subgroup, C is the quotient map G -->G/H, * S is a subgroup of G/H, and G is embedded in Sym(l) * Return all the subgroups K of G such that * S= K mod H and K inter H={1} */ static GEN liftsubgroup(GEN C, GEN H, GEN S) { pari_sp ltop = avma; GEN V = trivialsubgroups(); GEN Sgen = grp_get_gen(S); GEN Sord = grp_get_ord(S); GEN Cgen = quo_get_gen(C); long n = lg(Sgen), i; for (i = 1; i < n; ++i) { /*loop over generators of S*/ GEN W = group_leftcoset(H, gel(Cgen, mael(Sgen, i, 1))); V = liftlistsubgroups(V, W, Sord[i]); } return gerepilecopy(ltop,V); } /* 1:A4 2:S4 0: other */ long group_isA4S4(GEN G) { GEN elt = grp_get_gen(G); GEN ord = grp_get_ord(G); long n = lg(ord); if (n != 4 && n != 5) return 0; if (ord[1]!=2 || ord[2]!=2 || ord[3]!=3) return 0; if (perm_commute(gel(elt,1),gel(elt,3))) return 0; if (n==4) return 1; if (ord[4]!=2) return 0; if (perm_commute(gel(elt,3),gel(elt,4))) return 0; return 2; } /* compute all the subgroups of a group G */ GEN group_subgroups(GEN G) { pari_sp ltop = avma; GEN p1, H, C, Q, M, sg1, sg2, sg3; GEN gen = grp_get_gen(G); GEN ord = grp_get_ord(G); long lM, i, j, n = lg(gen); if (n == 1) return trivialsubgroups(); if (group_isA4S4(G)) { GEN s = gel(gen,1); /*s = (1,2)(3,4) */ GEN t = gel(gen,2); /*t = (1,3)(2,4) */ GEN st = perm_mul(s, t); /*st = (1,4)(2,3) */ H = dicyclicgroup(s, t, 2, 2); /* sg3 is the list of subgroups intersecting only partially with H*/ sg3 = cgetg((n==4)?4: 10, t_VEC); gel(sg3,1) = cyclicgroup(s, 2); gel(sg3,2) = cyclicgroup(t, 2); gel(sg3,3) = cyclicgroup(st, 2); if (n==5) { GEN u = gel(gen,3); GEN v = gel(gen,4), w, u2; if (zv_equal(perm_conj(u,s), t)) /*u=(2,3,4)*/ u2 = perm_mul(u,u); else { u2 = u; u = perm_mul(u,u); } if (perm_order(v)==2) { if (!perm_commute(s,v)) /*v=(1,2)*/ { v = perm_conj(u,v); if (!perm_commute(s,v)) v = perm_conj(u,v); } w = perm_mul(v,t); /*w=(1,4,2,3)*/ } else { w = v; if (!zv_equal(perm_mul(w,w), s)) /*w=(1,4,2,3)*/ { w = perm_conj(u,w); if (!zv_equal(perm_mul(w,w), s)) w = perm_conj(u,w); } v = perm_mul(w,t); /*v=(1,2)*/ } gel(sg3,4) = dicyclicgroup(s,v,2,2); gel(sg3,5) = dicyclicgroup(t,perm_conj(u,v),2,2); gel(sg3,6) = dicyclicgroup(st,perm_conj(u2,v),2,2); gel(sg3,7) = dicyclicgroup(s,w,2,2); gel(sg3,8) = dicyclicgroup(t,perm_conj(u,w),2,2); gel(sg3,9) = dicyclicgroup(st,perm_conj(u2,w),2,2); } } else { long osig = mael(factoru(ord[1]), 1, 1); GEN sig = perm_pow(gel(gen,1), ord[1]/osig); H = cyclicgroup(sig,osig); sg3 = NULL; } C = group_quotient(G,H); Q = quotient_group(C,G); M = group_subgroups(Q); lM = lg(M); /* sg1 is the list of subgroups containing H*/ sg1 = cgetg(lM, t_VEC); for (i = 1; i < lM; ++i) gel(sg1,i) = quotient_subgroup_lift(C,H,gel(M,i)); /*sg2 is a list of lists of subgroups not intersecting with H*/ sg2 = cgetg(lM, t_VEC); /* Loop over all subgroups of G/H */ for (j = 1; j < lM; ++j) gel(sg2,j) = liftsubgroup(C, H, gel(M,j)); p1 = gconcat(sg1, shallowconcat1(sg2)); if (sg3) { p1 = gconcat(p1, sg3); if (n==5) /*ensure that the D4 subgroups of S4 are in supersolvable format*/ for(j = 3; j <= 5; j++) { GEN c = gmael(p1,j,1); if (!perm_commute(gel(c,1),gel(c,3))) { if (perm_commute(gel(c,2),gel(c,3))) { swap(gel(c,1), gel(c,2)); } else perm_mul_inplace2(gel(c,2), gel(c,1)); } } } return gerepileupto(ltop,p1); } /*return 1 if G is abelian, else 0*/ long group_isabelian(GEN G) { GEN g = grp_get_gen(G); long i, j, n = lg(g); for(i=2; i 1 && group_domain(G) != group_domain(H)) pari_err_DOMAIN("group_subgroup_isnormal","domain(H)","!=", strtoGENstr("domain(G)"), H); for(i=1; i 1) gel(s,k++) = comma; gel(s,k++) = perm_to_GAP(gel(g,i)); } gel(s,k++) = strtoGENstr(")"); return gerepilecopy(av, shallowconcat1(s)); } GEN group_export_MAGMA(GEN G) { pari_sp av = avma; GEN s, comma, g = grp_get_gen(G); long i, k, l = lg(g); if (l == 1) return strtoGENstr("PermutationGroup<1|>"); s = cgetg(2*l, t_VEC); comma = strtoGENstr(", "); gel(s,1) = gsprintf("PermutationGroup<%ld|",group_domain(G)); for (i=1, k=2; i < l; ++i) { if (i > 1) gel(s,k++) = comma; gel(s,k++) = GENtoGENstr( vecsmall_to_vec(gel(g,i)) ); } gel(s,k++) = strtoGENstr(">"); return gerepilecopy(av, shallowconcat1(s)); } GEN group_export(GEN G, long format) { switch(format) { case 0: return group_export_GAP(G); case 1: return group_export_MAGMA(G); } pari_err_FLAG("galoisexport"); return NULL; /*-Wall*/ } pari-2.11.2/src/basemath/trans3.c0000644000175000017500000031535613457603001015123 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** TRANSCENDENTAL FONCTIONS **/ /** (part 3) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" #define HALF_E 1.3591409 /* Exponential / 2 */ static const long EXTRAPREC = #ifdef LONG_IS_64BIT 1; #else 2; #endif /***********************************************************************/ /** **/ /** BESSEL FUNCTIONS **/ /** **/ /***********************************************************************/ /* n! sum_{k=0}^m Z^k / (k!*(k+n)!), with Z := (-1)^flag*z^2/4 */ static GEN _jbessel(GEN n, GEN z, long flag, long m) { pari_sp av; GEN Z,s; long k; Z = gmul2n(gsqr(z),-2); if (flag & 1) Z = gneg(Z); if (typ(z) == t_SER) { long v = valp(z); if (v < 0) pari_err_DOMAIN("besselj","valuation", "<", gen_0, z); k = lg(Z)-2 - v; if (v == 0) pari_err_IMPL("besselj around a!=0"); if (k <= 0) return scalarser(gen_1, varn(z), 2*v); setlg(Z, k+2); } s = gen_1; av = avma; for (k=m; k>=1; k--) { s = gaddsg(1, gdiv(gmul(Z,s), gmulgs(gaddgs(n,k),k))); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"besselj"); s = gerepileupto(av, s); } } return s; } /* return L * approximate solution to x log x = B */ static long bessel_get_lim(double B, double L) { long lim; double x = 1 + B; /* 3 iterations are enough except in pathological cases */ x = (x + B)/(log(x)+1); x = (x + B)/(log(x)+1); x = (x + B)/(log(x)+1); x = L*x; lim = (long)x; if (lim < 2) lim = 2; return lim; } static GEN jbesselintern(GEN n, GEN z, long flag, long prec); static GEN kbesselintern(GEN n, GEN z, long flag, long prec); static GEN jbesselvec(GEN n, GEN x, long fl, long prec) { long i, l; GEN y = cgetg_copy(x, &l); for (i=1; i= 1.0) precnew += nbits2extraprec((long)(L/(HALF_E*M_LN2) + BITS_IN_LONG)); if (issmall(n,&ki)) { k = labs(ki); n = utoi(k); } else { i = precision(n); if (i && i < precnew) n = gtofp(n,precnew); } z = gtofp(z,precnew); B = prec2nbits_mul(prec, M_LN2/2) / L; lim = bessel_get_lim(B, L); p1 = gprec_wtrunc(_jbessel(n,z,flag,lim), prec); return gerepileupto(av, gmul(p2,p1)); } case t_VEC: case t_COL: case t_MAT: return jbesselvec(n, z, flag, prec); case t_POLMOD: y = jbesselvec(n, polmod_to_embed(z, prec), flag, prec); return gerepileupto(av,y); case t_PADIC: pari_err_IMPL("p-adic jbessel function"); default: if (!(y = toser_i(z))) break; if (issmall(n,&ki)) n = utoi(labs(ki)); return gerepileupto(av, _jbessel(n,y,flag,lg(y)-2)); } pari_err_TYPE("jbessel",z); return NULL; /* LCOV_EXCL_LINE */ } GEN jbessel(GEN n, GEN z, long prec) { return jbesselintern(n,z,1,prec); } GEN ibessel(GEN n, GEN z, long prec) { return jbesselintern(n,z,0,prec); } static GEN _jbesselh(long k, GEN z, long prec) { GEN s,c,p0,p1,p2, zinv = ginv(z); long i; gsincos(z,&s,&c,prec); p1 = gmul(zinv,s); if (k) { p0 = p1; p1 = gmul(zinv,gsub(p0,c)); for (i=2; i<=k; i++) { p2 = gsub(gmul(gmulsg(2*i-1,zinv),p1), p0); p0 = p1; p1 = p2; } } return p1; } /* J_{n+1/2}(z) */ GEN jbesselh(GEN n, GEN z, long prec) { long k, i; pari_sp av; GEN y; if (typ(n)!=t_INT) pari_err_TYPE("jbesselh",n); k = itos(n); if (k < 0) return jbessel(gadd(ghalf,n), z, prec); switch(typ(z)) { case t_INT: case t_FRAC: case t_QUAD: case t_REAL: case t_COMPLEX: { long bits, precnew, gz, pr; GEN p1; if (gequal0(z)) { av = avma; p1 = gmul(gsqrt(gdiv(z,mppi(prec)),prec),gpowgs(z,k)); p1 = gdiv(p1, mulu_interval(k+1, 2*k+1)); /* x k! / (2k+1)! */ return gerepileupto(av, gmul2n(p1,2*k)); } gz = gexpo(z); if ( (pr = precision(z)) ) prec = pr; y = cgetc(prec); bits = -2*k*gz + BITS_IN_LONG; av = avma; if (bits <= 0) precnew = prec; else { precnew = prec + nbits2extraprec(bits); if (pr) z = gtofp(z, precnew); } p1 = gmul(_jbesselh(k,z,prec), gsqrt(gdiv(z,Pi2n(-1,prec)),prec)); avma = av; return affc_fixlg(p1, y); } case t_VEC: case t_COL: case t_MAT: return jbesselhvec(n, z, prec); case t_POLMOD: av = avma; return gerepileupto(av, jbesselhvec(n, polmod_to_embed(z,prec), prec)); case t_PADIC: pari_err_IMPL("p-adic jbesselh function"); default: { long t, v; av = avma; if (!(y = toser_i(z))) break; if (gequal0(y)) return gerepileupto(av, gpowgs(y,k)); v = valp(y); if (v < 0) pari_err_DOMAIN("besseljh","valuation", "<", gen_0, y); t = lg(y)-2; if (v) y = sertoser(y, t + (2*k+1)*v); if (!k) y = gdiv(gsin(y,prec), y); else { GEN T, a = _jbesselh(k, y, prec); if (v) y = sertoser(y, t + k*v); /* lower precision */ y = gdiv(a, gpowgs(y, k)); T = cgetg(k+1, t_VECSMALL); for (i = 1; i <= k; i++) T[i] = 2*i+1; y = gmul(y, zv_prod_Z(T)); } return gerepileupto(av, y); } } pari_err_TYPE("besseljh",z); return NULL; /* LCOV_EXCL_LINE */ } static GEN kbessel2(GEN nu, GEN x, long prec) { pari_sp av = avma; GEN p1, x2, a; if (typ(x)==t_REAL) prec = realprec(x); x2 = gshift(x,1); a = gtofp(gaddgs(gshift(nu,1), 1), prec); p1 = hyperu(gshift(a,-1),a,x2,prec); p1 = gmul(gmul(p1,gpow(x2,nu,prec)), sqrtr(mppi(prec))); return gerepileupto(av, gmul(p1,gexp(gneg(x),prec))); } static GEN kbessel1(GEN nu, GEN gx, long prec) { GEN x, y, p1, zf, zz, r, s, t, u, ak, pitemp, nu2; long l, lnew, k, k2, l1, n2, n, ex; pari_sp av; if (typ(nu)==t_COMPLEX) return kbessel2(nu,gx,prec); l = (typ(gx)==t_REAL)? realprec(gx): prec; ex = gexpo(gx); if (ex < 0) { long rab = nbits2extraprec(-ex); lnew = l + rab; prec += rab; } else lnew = l; y = cgetr(l); l1=lnew+1; av = avma; x = gtofp(gx, lnew); nu = gtofp(nu, lnew); nu2 = gmul2n(sqrr(nu), 2); togglesign(nu2); n = (long) (prec2nbits_mul(l,M_LN2) + M_PI*fabs(rtodbl(nu))) / 2; n2 = n<<1; pitemp=mppi(l1); r = gmul2n(x,1); if (cmprs(x, n) < 0) { GEN q = stor(n2, l1), v, c, e, f; pari_sp av1, av2; u=cgetr(l1); v=cgetr(l1); e=cgetr(l1); f=cgetr(l1); av1 = avma; zf = sqrtr(divru(pitemp,n2)); zz = invr(stor(n2<<2, prec)); s = real_1(prec); t = real_0(prec); for (k=n2,k2=2*n2-1; k > 0; k--,k2-=2) { p1 = addri(nu2, sqrs(k2)); ak = divrs(mulrr(p1,zz),-k); s = addsr(1, mulrr(ak,s)); t = addsr(k2,mulrr(ak,t)); } mulrrz(zf, s, u); shiftr_inplace(t, -1); divrsz(addrr(mulrr(t,zf),mulrr(u,nu)),-n2,v); for(;; avma = av1) { GEN d = real_1(l1); c = divur(5,q); if (expo(c) >= -1) c = real2n(-1,l1); p1 = subsr(1,divrr(r,q)); if (cmprr(c,p1)>0) c = p1; togglesign(c); affrr(u,e); affrr(v,f); av2 = avma; for (k=1;; k++, avma=av2) { GEN w = addrr(gmul2n(mulur(2*k-1,u), -1), mulrr(subrs(q,k),v)); w = addrr(w, mulrr(nu, subrr(u,gmul2n(v,1)))); divrsz(mulrr(q,v),k,u); divrsz(w,k,v); mulrrz(d,c,d); addrrz(e,mulrr(d,u),e); p1=mulrr(d,v); addrrz(f,p1,f); if (gexpo(p1) - gexpo(f) <= 1-prec2nbits(precision(p1))) break; } swap(e, u); swap(f, v); affrr(mulrr(q,addrs(c,1)), q); if (expo(subrr(q,r)) - expo(r) <= 1-prec2nbits(lnew)) break; } u = mulrr(u, gpow(divru(x,n),nu,prec)); } else { zf = sqrtr(divrr(pitemp,r)); zz = ginv(gmul2n(r,2)); s = real_1(prec); for (k=n2,k2=2*n2-1; k > 0; k--,k2-=2) { p1 = addri(nu2, sqrs(k2)); ak = divru(mulrr(p1,zz), k); s = subsr(1, mulrr(ak,s)); } u = mulrr(s, zf); } affrr(mulrr(u, mpexp(mpneg(x))), y); avma = av; return y; } /* sum_{k=0}^m Z^k (H(k)+H(k+n)) / (k! (k+n)!) * + sum_{k=0}^{n-1} (-Z)^(k-n) (n-k-1)!/k! with Z := (-1)^flag*z^2/4. * Warning: contrary to _jbessel, no n! in front. * When flag > 1, compute exactly the H(k) and factorials (slow) */ static GEN _kbessel1(long n, GEN z, long flag, long m, long prec) { GEN Z, p1, p2, s, H; pari_sp av; long k; Z = gmul2n(gsqr(z),-2); if (flag & 1) Z = gneg(Z); if (typ(z) == t_SER) { long v = valp(z); if (v < 0) pari_err_DOMAIN("_kbessel1","valuation", "<", gen_0, z); k = lg(Z)-2 - v; if (v == 0) pari_err_IMPL("Bessel K around a!=0"); if (k <= 0) return gadd(gen_1, zeroser(varn(z), 2*v)); setlg(Z, k+2); } H = cgetg(m+n+2,t_VEC); gel(H,1) = gen_0; if (flag <= 1) { gel(H,2) = s = real_1(prec); for (k=2; k<=m+n; k++) gel(H,k+1) = s = divru(addsr(1,mulur(k,s)),k); } else { gel(H,2) = s = gen_1; for (k=2; k<=m+n; k++) gel(H,k+1) = s = gdivgs(gaddsg(1,gmulsg(k,s)),k); } s = gadd(gel(H,m+1), gel(H,m+n+1)); av = avma; for (k=m; k>0; k--) { s = gadd(gadd(gel(H,k),gel(H,k+n)),gdiv(gmul(Z,s),mulss(k,k+n))); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"_kbessel1"); s = gerepileupto(av, s); } } p1 = (flag <= 1) ? mpfactr(n,prec) : mpfact(n); s = gdiv(s,p1); if (n) { Z = gneg(ginv(Z)); p2 = gmulsg(n, gdiv(Z,p1)); s = gadd(s,p2); for (k=n-1; k>0; k--) { p2 = gmul(p2, gmul(mulss(k,n-k),Z)); s = gadd(s,p2); } } return s; } /* flag = 0: K / flag = 1: N */ static GEN kbesselintern(GEN n, GEN z, long flag, long prec) { const char *f = flag? "besseln": "besselk"; const long flK = (flag == 0); long i, k, ki, lim, precnew, fl2, ex; pari_sp av = avma; GEN p1, p2, y, p3, pp, pm, s, c; double B, L; switch(typ(z)) { case t_INT: case t_FRAC: case t_QUAD: case t_REAL: case t_COMPLEX: if (gequal0(z)) pari_err_DOMAIN(f, "argument", "=", gen_0, z); i = precision(z); if (i) prec = i; i = precision(n); if (i && prec > i) prec = i; ex = gexpo(z); /* experimental */ if (!flag && !gequal0(n) && ex > prec2nbits(prec)/16 + gexpo(n)) return kbessel1(n,z,prec); L = HALF_E * gtodouble(gabs(z,prec)); precnew = prec; if (L >= HALF_E) { long rab = nbits2extraprec((long) (L/(HALF_E*M_LN2))); if (flK) rab *= 2; precnew += 1 + rab; } z = gtofp(z, precnew); if (issmall(n,&ki)) { GEN z2 = gmul2n(z, -1); k = labs(ki); B = prec2nbits_mul(prec,M_LN2/2) / L; if (flK) B += 0.367879; lim = bessel_get_lim(B, L); p1 = gmul(gpowgs(z2,k), _kbessel1(k,z,flag,lim,precnew)); p2 = gadd(mpeuler(precnew), glog(z2,precnew)); p3 = jbesselintern(stoi(k),z,flag,precnew); p2 = gsub(gmul2n(p1,-1),gmul(p2,p3)); p2 = gprec_wtrunc(p2, prec); if (flK) { if (k & 1) p2 = gneg(p2); } else { p2 = gdiv(p2, Pi2n(-1,prec)); if (ki >= 0 || (k&1)==0) p2 = gneg(p2); } return gerepilecopy(av, p2); } n = gtofp(n, precnew); gsincos(gmul(n,mppi(precnew)), &s,&c,precnew); ex = gexpo(s); if (ex < 0) { long rab = nbits2extraprec(-ex); if (flK) rab *= 2; precnew += rab; } if (i && i < precnew) { n = gtofp(n,precnew); z = gtofp(z,precnew); gsincos(gmul(n,mppi(precnew)), &s,&c,precnew); } pp = jbesselintern(n, z,flag,precnew); pm = jbesselintern(gneg(n),z,flag,precnew); if (flK) p1 = gmul(gsub(pm,pp), Pi2n(-1,precnew)); else p1 = gsub(gmul(c,pp),pm); p1 = gdiv(p1, s); return gerepilecopy(av, gprec_wtrunc(p1,prec)); case t_VEC: case t_COL: case t_MAT: return kbesselvec(n,z,flag,prec); case t_POLMOD: y = kbesselvec(n,polmod_to_embed(z,prec),flag,prec); return gerepileupto(av, y); case t_PADIC: pari_err_IMPL(stack_strcat("p-adic ",f)); default: if (!(y = toser_i(z))) break; if (issmall(n,&ki)) { k = labs(ki); return gerepilecopy(av, _kbessel1(k,y,flag+2,lg(y)-2,prec)); } if (!issmall(gmul2n(n,1),&ki)) pari_err_DOMAIN(f, "2n mod Z", "!=", gen_0,n); k = labs(ki); n = gmul2n(stoi(k),-1); fl2 = (k&3)==1; pm = jbesselintern(gneg(n),y,flag,prec); if (flK) { pp = jbesselintern(n,y,flag,prec); p2 = gpowgs(y,-k); if (fl2 == 0) p2 = gneg(p2); p3 = gmul2n(diviiexact(mpfact(k + 1),mpfact((k + 1) >> 1)),-(k + 1)); p3 = gdivgs(gmul2n(gsqr(p3),1),k); p2 = gmul(p2,p3); p1 = gsub(pp,gmul(p2,pm)); } else p1 = pm; return gerepileupto(av, fl2? gneg(p1): gcopy(p1)); } pari_err_TYPE(f,z); return NULL; /* LCOV_EXCL_LINE */ } GEN kbessel(GEN n, GEN z, long prec) { return kbesselintern(n,z,0,prec); } GEN nbessel(GEN n, GEN z, long prec) { return kbesselintern(n,z,1,prec); } /* J + iN */ GEN hbessel1(GEN n, GEN z, long prec) { pari_sp av = avma; GEN J = jbessel(n,z,prec); GEN N = nbessel(n,z,prec); return gerepileupto(av, gadd(J, mulcxI(N))); } /* J - iN */ GEN hbessel2(GEN n, GEN z, long prec) { pari_sp av = avma; GEN J = jbessel(n,z,prec); GEN N = nbessel(n,z,prec); return gerepileupto(av, gadd(J, mulcxmI(N))); } /***********************************************************************/ /* **/ /** FONCTION U(a,b,z) GENERALE **/ /** ET CAS PARTICULIERS **/ /** **/ /***********************************************************************/ /* Assume gx > 0 and a,b complex */ /* This might one day be extended to handle complex gx */ /* see Temme, N. M. "The numerical computation of the confluent */ /* hypergeometric function U(a,b,z)" in Numer. Math. 41 (1983), */ /* no. 1, 63--82. */ GEN hyperu(GEN a, GEN b, GEN gx, long prec) { GEN S, P, T, x, p1, zf, u, a1, mb = gneg(b); const int ex = iscomplex(a) || iscomplex(b); long k, n, l = (typ(gx)==t_REAL)? realprec(gx): prec, l1 = l+EXTRAPRECWORD; GEN y = ex? cgetc(l): cgetr(l); pari_sp av = avma; if (gsigne(gx) <= 0) pari_err_IMPL("non-positive third argument in hyperu"); x = gtofp(gx, l); a1 = gaddsg(1, gadd(a,mb)); P = gmul(a1, a); n = (long)(prec2nbits_mul(l, M_LN2) + M_PI*sqrt(dblmodulus(P))); S = gadd(a1, a); if (cmprs(x,n) < 0) { GEN q = stor(n, l1), s = gen_1, t = gen_0, v, c, e, f; pari_sp av1, av2; if (ex) { u=cgetc(l1); v=cgetc(l1); e=cgetc(l1); f=cgetc(l1); } else { u=cgetr(l1); v=cgetr(l1); e=cgetr(l1); f=cgetr(l1); } av1 = avma; zf = gpow(stoi(n),gneg_i(a),l1); T = gadd(gadd(P, gmulsg(n-1, S)), sqrs(n-1)); for (k=n-1; k>=0; k--) { /* T = (a+k)*(a1+k) = a*a1 + k(a+a1) + k^2 = previous(T) - S - 2k + 1 */ p1 = gdiv(T, mulss(-n, k+1)); s = gaddgs(gmul(p1,s), 1); t = gadd( gmul(p1,t), gaddgs(a,k)); if (!k) break; T = gsubgs(gsub(T, S), 2*k-1); } gmulz(zf, s, u); gmulz(zf, gdivgs(t,-n), v); for(;; avma = av1) { GEN d = real_1(l1), p3 = gadd(q,mb); c = divur(5,q); if (expo(c)>= -1) c = real2n(-1, l1); p1 = subsr(1,divrr(x,q)); if (cmprr(c,p1)>0) c = p1; togglesign(c); gaffect(u,e); gaffect(v,f); av2 = avma; for(k=1;;k++, avma = av2) { GEN w = gadd(gmul(gaddgs(a,k-1),u), gmul(gaddgs(p3,1-k),v)); gmulz(divru(q,k),v, u); gaffect(gdivgs(w,k), v); mulrrz(d,c,d); gaddz(e,gmul(d,u),e); p1=gmul(d,v); gaddz(f,p1,f); if (gequal0(p1) || gexpo(p1) - gexpo(f) <= 1-prec2nbits(precision(p1))) break; } swap(e, u); swap(f, v); affrr(mulrr(q, addrs(c,1)), q); if (expo(subrr(q,x)) - expo(x) <= 1-prec2nbits(l)) break; } } else { GEN zz = invr(x), s = gen_1; togglesign(zz); /* -1/x */ zf = gpow(x,gneg_i(a),l1); T = gadd(gadd(P, gmulsg(n-1, S)), sqrs(n-1)); for (k=n-1; k>=0; k--) { p1 = gmul(T,divru(zz,k+1)); s = gaddsg(1, gmul(p1,s)); if (!k) break; T = gsubgs(gsub(T, S), 2*k-1); } u = gmul(s,zf); } gaffect(u,y); avma = av; return y; } /* incgam(0, x, prec) = eint1(x); typ(x) = t_REAL, x > 0 */ static GEN incgam_0(GEN x, GEN expx) { pari_sp av; long l = realprec(x), n, i; double mx = rtodbl(x), L = prec2nbits_mul(l,M_LN2); GEN z; if (!mx) pari_err_DOMAIN("eint1", "x","=",gen_0, x); if (mx > L) { double m = (L + mx)/4; n = (long)(1+m*m/mx); av = avma; z = divsr(-n, addsr(n<<1,x)); for (i=n-1; i >= 1; i--) { z = divsr(-i, addrr(addsr(i<<1,x), mulur(i,z))); /* -1 / (2 + z + x/i) */ if ((i & 0x1ff) == 0) z = gerepileuptoleaf(av, z); } return divrr(addrr(real_1(l),z), mulrr(expx? expx: mpexp(x), x)); } else { long prec = l + nbits2extraprec((mx+log(mx))/M_LN2 + 10); GEN S, t, H, run = real_1(prec); n = -prec2nbits(prec); x = rtor(x, prec); av = avma; S = z = t = H = run; for (i = 2; expo(t) - expo(S) >= n; i++) { H = addrr(H, divru(run,i)); /* H = sum_{k<=i} 1/k */ z = divru(mulrr(x,z), i); /* z = x^(i-1)/i! */ t = mulrr(z, H); S = addrr(S, t); if ((i & 0x1ff) == 0) gerepileall(av, 4, &z,&t,&S,&H); } return subrr(mulrr(x, divrr(S,expx? expx: mpexp(x))), addrr(mplog(x), mpeuler(prec))); } } /* real(z*log(z)-z), z = x+iy */ static double mygamma(double x, double y) { if (x == 0.) return -(M_PI/2)*fabs(y); return (x/2)*log(x*x+y*y)-x-y*atan(y/x); } /* x^s exp(-x) */ static GEN expmx_xs(GEN s, GEN x, GEN logx, long prec) { GEN z; long ts = typ(s); if (ts == t_INT || (ts == t_FRAC && absequaliu(gel(s,2), 2))) z = gmul(gexp(gneg(x), prec), gpow(x, s, prec)); else z = gexp(gsub(gmul(s, logx? logx: glog(x,prec+EXTRAPREC)), x), prec); return z; } /* Not yet: doesn't work at low accuracy #define INCGAM_CF */ #ifdef INCGAM_CF /* Is s very close to a non-positive integer ? */ static int isgammapole(GEN s, long bitprec) { pari_sp av = avma; GEN t = imag_i(s); long e, b = bitprec - 10; if (gexpo(t) > - b) return 0; s = real_i(s); if (gsigne(s) > 0 && gexpo(s) > -b) return 0; (void)grndtoi(s, &e); avma = av; return (e < -b); } /* incgam using the continued fraction. x a t_REAL or t_COMPLEX, mx ~ |x|. * Assume precision(s), precision(x) >= prec */ static GEN incgam_cf(GEN s, GEN x, double mx, long prec) { GEN ms, y, S; long n, i, j, LS, bitprec = prec2nbits(prec); double rs, is, m; if (typ(s) == t_COMPLEX) { rs = gtodouble(gel(s,1)); is = gtodouble(gel(s,2)); } else { rs = gtodouble(s); is = 0.; } if (isgammapole(s, bitprec)) LS = 0; else { double bit, LGS = mygamma(rs,is); LS = LGS <= 0 ? 0: ceil(LGS); bit = (LGS - (rs-1)*log(mx) + mx)/M_LN2; if (bit > 0) { prec += nbits2extraprec((long)bit); x = gtofp(x, prec); if (isinexactreal(s)) s = gtofp(s, prec); } } /* |ln(2*gamma(s)*sin(s*Pi))| <= ln(2) + |lngamma(s)| + |Im(s)*Pi|*/ m = bitprec*M_LN2 + LS + M_LN2 + fabs(is)*M_PI + mx; if (rs < 1) m += (1 - rs)*log(mx); m /= 4; n = (long)(1 + m*m/mx); y = expmx_xs(gsubgs(s,1), x, NULL, prec); if (rs >= 0 && bitprec >= 512) { GEN A = cgetg(n+1, t_VEC), B = cgetg(n+1, t_VEC); ms = gsubsg(1, s); for (j = 1; j <= n; ++j) { gel(A,j) = ms; gel(B,j) = gmulsg(j, gsubgs(s,j)); ms = gaddgs(ms, 2); } S = contfraceval_inv(mkvec2(A,B), x, -1); } else { GEN x_s = gsub(x, s); pari_sp av2 = avma; S = gdiv(gsubgs(s,n), gaddgs(x_s,n<<1)); for (i=n-1; i >= 1; i--) { S = gdiv(gsubgs(s,i), gadd(gaddgs(x_s,i<<1),gmulsg(i,S))); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"incgam_cf"); S = gerepileupto(av2, S); } } S = gaddgs(S,1); } return gmul(y, S); } #endif static double findextraincgam(GEN s, GEN x) { double sig = gtodouble(real_i(s)), t = gtodouble(imag_i(s)); double xr = gtodouble(real_i(x)), xi = gtodouble(imag_i(x)); double exd = 0., Nx = xr*xr + xi*xi, D = Nx - t*t; long n; if (xr < 0) { long ex = gexpo(x); if (ex > 0 && ex > gexpo(s)) exd = sqrt(Nx)*log(Nx)/2; /* |x| log |x| */ } if (D <= 0.) return exd; n = (long)(sqrt(D)-sig); if (n <= 0) return exd; return maxdd(exd, (n*log(Nx)/2 - mygamma(sig+n, t) + mygamma(sig, t)) / M_LN2); } /* use exp(-x) * (x^s/s) * sum_{k >= 0} x^k / prod(i=1, k, s+i) */ static GEN incgamc_i(GEN s, GEN x, long *ptexd, long prec) { GEN S, t, y; long l, n, i, exd; pari_sp av = avma, av2; if (gequal0(x)) { if (ptexd) *ptexd = 0.; return gtofp(x, prec); } l = precision(x); if (!l) l = prec; n = -prec2nbits(l)-1; exd = (long)findextraincgam(s, x); if (ptexd) *ptexd = exd; if (exd > 0) { long p = l + nbits2extraprec(exd); x = gtofp(x, p); if (isinexactreal(s)) s = gtofp(s, p); } else x = gtofp(x, l+EXTRAPREC); av2 = avma; S = gdiv(x, gaddsg(1,s)); t = gaddsg(1, S); for (i=2; gexpo(S) >= n; i++) { S = gdiv(gmul(x,S), gaddsg(i,s)); /* x^i / ((s+1)...(s+i)) */ t = gadd(S,t); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"incgamc"); gerepileall(av2, 2, &S, &t); } } y = expmx_xs(s, x, NULL, prec); return gerepileupto(av, gmul(gdiv(y,s), t)); } GEN incgamc(GEN s, GEN x, long prec) { return incgamc_i(s, x, NULL, prec); } /* incgamma using asymptotic expansion: * exp(-x)x^(s-1)(1 + (s-1)/x + (s-1)(s-2)/x^2 + ...) */ static GEN incgam_asymp(GEN s, GEN x, long prec) { pari_sp av = avma, av2; GEN S, q, cox, invx; long oldeq = LONG_MAX, eq, esx, j; int flint = (typ(s) == t_INT && signe(s) > 0); x = gtofp(x,prec+EXTRAPREC); invx = ginv(x); esx = -prec2nbits(prec); av2 = avma; q = gmul(gsubgs(s,1), invx); S = gaddgs(q, 1); for (j = 2;; j++) { eq = gexpo(q); if (eq < esx) break; if (!flint && (j & 3) == 0) { /* guard against divergence */ if (eq > oldeq) { avma = av; return NULL; } /* regressing, abort */ oldeq = eq; } q = gmul(q, gmul(gsubgs(s,j), invx)); S = gadd(S, q); if (gc_needed(av2, 1)) gerepileall(av2, 2, &S, &q); } if (DEBUGLEVEL > 2) err_printf("incgam: using asymp\n"); cox = expmx_xs(gsubgs(s,1), x, NULL, prec); return gerepileupto(av, gmul(cox, S)); } /* gasx = incgam(s-n,x). Compute incgam(s,x) * = (s-1)(s-2)...(s-n)gasx + exp(-x)x^(s-1) * * (1 + (s-1)/x + ... + (s-1)(s-2)...(s-n+1)/x^(n-1)) */ static GEN incgam_asymp_partial(GEN s, GEN x, GEN gasx, long n, long prec) { pari_sp av; GEN S, q, cox, invx, s1 = gsubgs(s, 1), sprod; long j; cox = expmx_xs(s1, x, NULL, prec); if (n == 1) return gadd(cox, gmul(s1, gasx)); invx = ginv(x); av = avma; q = gmul(s1, invx); S = gaddgs(q, 1); for (j = 2; j < n; j++) { q = gmul(q, gmul(gsubgs(s, j), invx)); S = gadd(S, q); if (gc_needed(av, 2)) gerepileall(av, 2, &S, &q); } sprod = gmul(gmul(q, gpowgs(x, n-1)), gsubgs(s, n)); return gadd(gmul(cox, S), gmul(sprod, gasx)); } /* Assume s != 0; called when Re(s) <= 1/2 */ static GEN incgamspec(GEN s, GEN x, GEN g, long prec) { GEN q, S, cox = gen_0, P, sk, S1, S2, S3, F3, logx, mx; long n, esk, E, k = itos(ground(gneg(real_i(s)))); /* >= 0 */ if (k && gexpo(x) > 0) { GEN xk = gdivgs(x, k); long bitprec = prec2nbits(prec); double d = (gexpo(xk) > bitprec)? bitprec*M_LN2: log(dblmodulus(xk)); d = k * (d + 1) / M_LN2; if (d > 0) prec += nbits2extraprec((long)d); if (isinexactreal(s)) s = gtofp(s, prec); } x = gtofp(x, maxss(precision(x), prec) + EXTRAPREC); sk = gaddgs(s, k); /* |Re(sk)| <= 1/2 */ logx = glog(x, prec); mx = gneg(x); if (k == 0) { S = gen_0; P = gen_1; } else { long j; q = ginv(s); S = q; P = s; for (j = 1; j < k; j++) { GEN sj = gaddgs(s, j); q = gmul(q, gdiv(x, sj)); S = gadd(S, q); P = gmul(P, sj); } cox = expmx_xs(s, x, logx, prec); /* x^s exp(-x) */ S = gmul(S, gneg(cox)); } if (k && gequal0(sk)) return gadd(S, gdiv(eint1(x, prec), P)); esk = gexpo(sk); if (esk > -7) { GEN a, b, PG = gmul(sk, P); if (g) g = gmul(g, PG); a = incgam0(gaddgs(sk,1), x, g, prec); if (k == 0) cox = expmx_xs(s, x, logx, prec); b = gmul(gpowgs(x, k), cox); return gadd(S, gdiv(gsub(a, b), PG)); } E = prec2nbits(prec) + 1; if (gexpo(x) > 0) { long X = (long)(dblmodulus(x)/M_LN2); prec += 2*nbits2extraprec(X); x = gtofp(x, prec); mx = gneg(x); logx = glog(x, prec); sk = gtofp(sk, prec); E += X; } if (isinexactreal(sk)) sk = gtofp(sk, prec+EXTRAPREC); /* |sk| < 2^-7 is small, guard against cancellation */ F3 = gexpm1(gmul(sk, logx), prec); /* ( gamma(1+sk) - exp(sk log(x))) ) / sk */ S1 = gdiv(gsub(ggamma1m1(sk, prec+EXTRAPREC), F3), sk); q = x; S3 = gdiv(x, gaddsg(1,sk)); for (n = 2; gexpo(q) - gexpo(S3) > -E; ++n) { q = gmul(q, gdivgs(mx, n)); S3 = gadd(S3, gdiv(q, gaddsg(n, sk))); } S2 = gadd(gadd(S1, S3), gmul(F3, S3)); return gadd(S, gdiv(S2, P)); } #if 0 static long precision2(GEN x, GEN y) { long px = precision(x), py = precision(y); if (!px) return py; if (!py) return px; return minss(px, py); } #endif /* return |x| */ double dblmodulus(GEN x) { if (typ(x) == t_COMPLEX) { double a = gtodouble(gel(x,1)); double b = gtodouble(gel(x,2)); return sqrt(a*a + b*b); } else return fabs(gtodouble(x)); } /* Driver routine. If g != NULL, assume that g=gamma(s,prec). */ GEN incgam0(GEN s, GEN x, GEN g, long prec) { pari_sp av; long E, l, ex; double mx; GEN z, rs, is; if (gequal0(x)) return g? gcopy(g): ggamma(s,prec); if (gequal0(s)) return eint1(x, prec); av = avma; l = precision(s); if (!l) l = prec; E = prec2nbits(l) + 1; /* avoid overflow in dblmodulus */ ex = gexpo(x); if (ex > E) mx = E; else mx = dblmodulus(x); /* use asymptotic expansion */ if (4*mx > 3*E || (typ(s) == t_INT && signe(s) > 0 && ex >= expi(s))) { z = incgam_asymp(s, x, l); if (z) return z; } rs = real_i(s); is = imag_i(s); #ifdef INCGAM_CF /* Can one use continued fraction ? */ if (gequal0(is) && gequal0(imag_i(x)) && gsigne(x) > 0) { double sd = gtodouble(rs), LB, UB; double xd = gtodouble(real_i(x)); if (sd > 0) { LB = 15 + 0.1205*E; UB = 5 + 0.752*E; } else { LB = -6 + 0.1205*E; UB = 5 + 0.752*E + fabs(sd)/54.; } if (xd >= LB && xd <= UB) { if (DEBUGLEVEL > 2) err_printf("incgam: using continued fraction\n"); return gerepileupto(av, incgam_cf(s, x, xd, prec)); } } #endif if (gsigne(rs) > 0 && gexpo(rs) >= -1) { /* use complementary incomplete gamma */ long n, egs, exd, precg, es = gexpo(s); if (es < 0) { l += nbits2extraprec(-es) + 1; x = gtofp(x, l); if (isinexactreal(s)) s = gtofp(s, l); } n = itos(gceil(rs)); if (n > 100) { GEN gasx; n -= 100; if (es > 0) { es = mygamma(gtodouble(rs) - n, gtodouble(is)) / M_LN2; if (es > 0) { l += nbits2extraprec(es); x = gtofp(x, l); if (isinexactreal(s)) s = gtofp(s, l); } } gasx = incgam0(gsubgs(s, n), x, NULL, prec); return gerepileupto(av, incgam_asymp_partial(s, x, gasx, n, prec)); } if (DEBUGLEVEL > 2) err_printf("incgam: using power series 1\n"); /* egs ~ expo(gamma(s)) */ precg = g? precision(g): 0; egs = g? gexpo(g): (long)(mygamma(gtodouble(rs), gtodouble(is)) / M_LN2); if (egs > 0) { l += nbits2extraprec(egs) + 1; x = gtofp(x, l); if (isinexactreal(s)) s = gtofp(s, l); if (precg < l) g = NULL; } z = incgamc_i(s, x, &exd, l); if (exd > 0) { l += nbits2extraprec(exd); if (isinexactreal(s)) s = gtofp(s, l); if (precg < l) g = NULL; } else { /* gamma(s) negligible ? Compute to lower accuracy */ long e = gexpo(z) - egs; if (e > 3) { E -= e; if (E <= 0) g = gen_0; else if (!g) g = ggamma(s, nbits2prec(E)); } } /* worry about possible cancellation */ if (!g) g = ggamma(s, maxss(l,precision(z))); return gerepileupto(av, gsub(g,z)); } if (DEBUGLEVEL > 2) err_printf("incgam: using power series 2\n"); return gerepileupto(av, incgamspec(s, x, g, l)); } GEN incgam(GEN s, GEN x, long prec) { return incgam0(s, x, NULL, prec); } /* x >= 0 a t_REAL */ GEN mpeint1(GEN x, GEN expx) { GEN z = cgetr(realprec(x)); pari_sp av = avma; affrr(incgam_0(x, expx), z); avma = av; return z; } static GEN cxeint1(GEN x, long prec) { pari_sp av = avma, av2; GEN q, S3; GEN run, z, H; long n, E = prec2nbits(prec) + 1, ex = gexpo(x); if ((ex > E || 4*dblmodulus(x) > 3*E) && (z = incgam_asymp(gen_0, x, prec))) return z; if (ex > 0) { /* take cancellation into account, log2(\sum |x|^n / n!) = |x| / log(2) */ double dbx = dblmodulus(x); long X = (long)((dbx + log(dbx))/M_LN2 + 10); prec += nbits2extraprec(X); x = gtofp(x, prec); E += X; } if (DEBUGLEVEL > 2) err_printf("eint1: using power series\n"); run = real_1(prec); av2 = avma; S3 = z = q = H = run; for (n = 2; gexpo(q) - gexpo(S3) >= -E; n++) { H = addrr(H, divru(run, n)); /* H = sum_{k<=n} 1/k */ z = gdivgs(gmul(x,z), n); /* z = x^(n-1)/n! */ q = gmul(z, H); S3 = gadd(S3, q); if ((n & 0x1ff) == 0) gerepileall(av2, 4, &z, &q, &S3, &H); } return gerepileupto(av, gsub(gmul(x, gdiv(S3, gexp(x, prec))), gadd(glog(x, prec), mpeuler(prec)))); } GEN eint1(GEN x, long prec) { long l, n, i; pari_sp av; GEN p1, t, S, y, res; switch(typ(x)) { case t_COMPLEX: return cxeint1(x, prec); case t_REAL: break; default: x = gtofp(x, prec); } if (signe(x) >= 0) return mpeint1(x,NULL); /* rewritten from code contributed by Manfred Radimersky */ res = cgetg(3, t_COMPLEX); av = avma; l = realprec(x); n = prec2nbits(l); y = rtor(x, l + EXTRAPREC); setsigne(y,1); if (cmprs(y, (3*n)/4) < 0) { p1 = t = S = y; for (i = 2; expo(t) - expo(S) >= -n; i++) { p1 = mulrr(y, divru(p1, i)); /* (-x)^i/i! */ t = divru(p1, i); S = addrr(S, t); } y = addrr(S, addrr(logr_abs(x), mpeuler(l))); } else { /* ~incgam_asymp: asymptotic expansion */ p1 = t = invr(y); S = addrs(t, 1); for (i = 2; expo(t) >= -n; i++) { t = mulrr(p1, mulru(t, i)); S = addrr(S, t); } y = mulrr(S, mulrr(p1, mpexp(y))); } gel(res, 1) = gerepileuptoleaf(av, negr(y)); y = mppi(prec); setsigne(y, -1); gel(res, 2) = y; return res; } GEN veceint1(GEN C, GEN nmax, long prec) { if (!nmax) return eint1(C,prec); if (typ(nmax) != t_INT) pari_err_TYPE("veceint1",nmax); if (typ(C) != t_REAL) { C = gtofp(C, prec); if (typ(C) != t_REAL) pari_err_TYPE("veceint1",C); } if (signe(C) <= 0) pari_err_DOMAIN("veceint1", "argument", "<=", gen_0,C); return mpveceint1(C, NULL, itos(nmax)); } /* j > 0, a t_REAL. Return sum_{m >= 0} a^m / j(j+1)...(j+m)). * Stop when expo(summand) < E; note that s(j-1) = (a s(j) + 1) / (j-1). */ static GEN mp_sum_j(GEN a, long j, long E, long prec) { pari_sp av = avma; GEN q = divru(real_1(prec), j), s = q; long m; for (m = 0;; m++) { if (expo(q) < E) break; q = mulrr(q, divru(a, m+j)); s = addrr(s, q); } return gerepileuptoleaf(av, s); } /* Return the s_a(j), j <= J */ static GEN sum_jall(GEN a, long J, long prec) { GEN s = cgetg(J+1, t_VEC); long j, E = -prec2nbits(prec) - 5; gel(s, J) = mp_sum_j(a, J, E, prec); for (j = J-1; j; j--) gel(s,j) = divru(addrs(mulrr(a, gel(s,j+1)), 1), j); return s; } /* T a dense t_POL with t_REAL coeffs. Return T(n) [faster than poleval] */ static GEN rX_s_eval(GEN T, long n) { long i = lg(T)-1; GEN c = gel(T,i); for (i--; i>=2; i--) c = gadd(mulrs(c,n),gel(T,i)); return c; } /* C>0 t_REAL, eC = exp(C). Return eint1(n*C) for 1<=n<=N. Absolute accuracy */ GEN mpveceint1(GEN C, GEN eC, long N) { const long prec = realprec(C); long Nmin = 15; /* >= 1. E.g. between 10 and 30, but little effect */ GEN en, v, w = cgetg(N+1, t_VEC); pari_sp av0; double DL; long n, j, jmax, jmin; if (!N) return w; for (n = 1; n <= N; n++) gel(w,n) = cgetr(prec); av0 = avma; if (N < Nmin) Nmin = N; if (!eC) eC = mpexp(C); en = eC; affrr(incgam_0(C, en), gel(w,1)); for (n = 2; n <= Nmin; n++) { pari_sp av2; en = mulrr(en,eC); /* exp(n C) */ av2 = avma; affrr(incgam_0(mulru(C,n), en), gel(w,n)); avma = av2; } if (Nmin == N) { avma = av0; return w; } DL = prec2nbits_mul(prec, M_LN2) + 5; jmin = ceil(DL/log((double)N)) + 1; jmax = ceil(DL/log((double)Nmin)) + 1; v = sum_jall(C, jmax, prec); en = powrs(eC, -N); /* exp(-N C) */ affrr(incgam_0(mulru(C,N), invr(en)), gel(w,N)); for (j = jmin, n = N-1; j <= jmax; j++) { long limN = maxss((long)ceil(exp(DL/j)), Nmin); GEN polsh; setlg(v, j+1); polsh = RgV_to_RgX_reverse(v, 0); for (; n >= limN; n--) { pari_sp av2 = avma; GEN S = divri(mulrr(en, rX_s_eval(polsh, -n)), powuu(n,j)); /* w[n+1] - exp(-n C) * polsh(-n) / (-n)^j */ GEN c = odd(j)? addrr(gel(w,n+1), S) : subrr(gel(w,n+1), S); affrr(c, gel(w,n)); avma = av2; en = mulrr(en,eC); /* exp(-n C) */ } } avma = av0; return w; } /* erfc via numerical integration : assume real(x)>=1 */ static GEN cxerfc_r1(GEN x, long prec) { GEN h, h2, eh2, denom, res, lambda; long u, v; const double D = prec2nbits_mul(prec, M_LN2); const long npoints = (long)ceil(D/M_PI)+1; pari_sp av = avma; { double t = exp(-2*M_PI*M_PI/D); /* ~exp(-2*h^2) */ v = 30; /* bits that fit in both long and double mantissa */ u = (long)floor(t*(1L<= 0) { if (cmprs(xr, 1) > 0) /* use numerical integration */ z = cxerfc_r1(x, prec); else { /* erfc(x) = incgam(1/2,x^2)/sqrt(Pi) */ GEN sqrtpi = sqrtr(mppi(prec)); z = incgam0(ghalf, gsqr(x), sqrtpi, prec); z = gdiv(z, sqrtpi); } } else { /* erfc(-x)=2-erfc(x) */ /* FIXME could decrease prec long size = nbits2extraprec((imag(x)^2-real(x)^2)/log(2)); prec = size > 0 ? prec : prec + size; */ /* NOT gsubsg(2, ...) : would create a result of * huge accuracy if re(x)>>1, rounded to 2 by subsequent affc_fixlg... */ z = gsub(real2n(1,prec+EXTRAPREC), gerfc(gneg(x), prec)); } avma = av; return affc_fixlg(z, res); } /***********************************************************************/ /** **/ /** FONCTION ZETA DE RIEMANN **/ /** **/ /***********************************************************************/ static const double log2PI = 1.83787706641; static double get_xinf(double beta) { const double maxbeta = 0.06415003; /* 3^(-2.5) */ double x0, y0, x1; if (beta < maxbeta) return beta + pow(3*beta, 1.0/3.0); x0 = beta + M_PI/2.0; for(;;) { y0 = x0*x0; x1 = (beta+atan(x0)) * (1+y0) / y0 - 1/x0; if (0.99*x0 < x1) return x1; x0 = x1; } } /* optimize for zeta( s + it, prec ), assume |s-1| > 0.1 * (if gexpo(u = s-1) < -5, we use the functional equation s->1-s) */ static void optim_zeta(GEN S, long prec, long *pp, long *pn) { double s, t, alpha, beta, n, B; long p; if (typ(S) == t_REAL) { s = rtodbl(S); t = 0.; } else { s = rtodbl(gel(S,1)); t = fabs( rtodbl(gel(S,2)) ); } B = prec2nbits_mul(prec, M_LN2); if (s > 0 && !t) /* positive real input */ { beta = B + 0.61 + s*(log2PI - log(s)); if (beta > 0) { p = (long)ceil(beta / 2.0); n = fabs(s + 2*p-1)/(2*M_PI); } else { p = 0; n = exp((B - M_LN2) / s); } } else if (s <= 0 || t < 0.01) /* s < 0 may occur if s ~ 0 */ { /* TODO: the crude bounds below are generally valid. Optimize ? */ double l,l2, la = 1.; /* heuristic */ double rlog, ilog; dcxlog(s-1,t, &rlog,&ilog); l2 = (s - 0.5)*rlog - t*ilog; /* = Re( (S - 1/2) log (S-1) ) */ l = (B - l2 + s*log2PI) / (2. * (1.+ log((double)la))); l2 = dabs(s, t)/2; if (l < l2) l = l2; p = (long) ceil(l); if (p < 2) p = 2; n = 1 + dabs(p+s/2.-.25, t/2) * la / M_PI; } else { double sn = dabs(s, t), L = log(sn/s); alpha = B - 0.39 + L + s*(log2PI - log(sn)); beta = (alpha+s)/t - atan(s/t); p = 0; if (beta > 0) { beta = 1.0 - s + t * get_xinf(beta); if (beta > 0) p = (long)ceil(beta / 2.0); } else if (s < 1.0) p = 1; n = p? dabs(s + 2*p-1, t) / (2*M_PI) : exp((B-M_LN2+L) / s); } *pp = p; *pn = (long)ceil(n); if (*pp < 0 || *pn < 0) pari_err_OVERFLOW("zeta"); } /* 1/zeta(n) using Euler product. Assume n > 0. * if (lba != 0) it is log(prec2nbits) we _really_ require */ GEN inv_szeta_euler(long n, double lba, long prec) { GEN z, res; pari_sp av, av2; double A, D; ulong p, lim; forprime_t S; if (n > prec2nbits(prec)) return real_1(prec); if (!lba) lba = prec2nbits_mul(prec, M_LN2); D = exp((lba - log((double)(n-1))) / (n-1)); lim = 1 + (ulong)ceil(D); if (lim < 3) return subir(gen_1,real2n(-n,prec)); res = cgetr(prec); incrprec(prec); av = avma; z = subir(gen_1, real2n(-n, prec)); (void)u_forprime_init(&S, 3, lim); av2 = avma; A = n / M_LN2; while ((p = u_forprime_next(&S))) { long l = prec2nbits(prec) - (long)floor(A * log((double)p)) - BITS_IN_LONG; GEN h; if (l < BITS_IN_LONG) l = BITS_IN_LONG; l = minss(prec, nbits2prec(l)); h = divrr(z, rpowuu(p, (ulong)n, l)); z = subrr(z, h); if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"inv_szeta_euler, p = %lu/%lu", p,lim); z = gerepileuptoleaf(av2, z); } } affrr(z, res); avma = av; return res; } /* assume n even > 0, if iz != NULL, assume iz = 1/zeta(n) */ static GEN bernreal_using_zeta(long n, GEN iz, long prec) { long l = prec+EXTRAPRECWORD; GEN z; if (!iz) iz = inv_szeta_euler(n, 0., l); z = divrr(mpfactr(n, l), mulrr(powru(Pi2n(1, l), n), iz)); shiftr_inplace(z, 1); /* 2 * n! * zeta(n) / (2Pi)^n */ if ((n & 3) == 0) setsigne(z, -1); return z; } /* assume n even > 0. Faster than standard bernfrac for n >= 6 */ GEN bernfrac_using_zeta(long n) { pari_sp av = avma; GEN iz, a, d, D = divisorsu(n >> 1); long i, prec, l = lg(D); double t, u; d = utoipos(6); /* 2 * 3 */ for (i = 2; i < l; i++) /* skip 1 */ { /* Clausen - von Staudt */ ulong p = 2*D[i] + 1; if (uisprime(p)) d = muliu(d, p); } /* 1.612086 ~ log(8Pi) / 2 */ t = log(gtodouble(d)) + (n + 0.5) * log((double)n) - n*(1+log2PI) + 1.612086; u = t / M_LN2; prec = nbits2prec((long)ceil(u) + BITS_IN_LONG); iz = inv_szeta_euler(n, t, prec); a = roundr( mulir(d, bernreal_using_zeta(n, iz, prec)) ); return gerepilecopy(av, mkfrac(a, d)); } static int bernreal_use_zeta_i(long n, long prec) { return (n+0.5) * log((double)n) -n*(1+log2PI) > prec2nbits_mul(prec, M_LN2); } static int bernreal_use_zeta(long n, long prec) { if (bernzone) { long k = n >> 1; if (n+1 < lg(bernzone)) { GEN B = gel(bernzone,k+1); if (typ(B) != t_REAL || realprec(B) >= prec) return 0; } } return bernreal_use_zeta_i(n, prec); } /* Return B_n */ GEN bernreal(long n, long prec) { GEN B, storeB; long k, lbern; if (n < 0) pari_err_DOMAIN("bernreal", "index", "<", gen_0, stoi(n)); if (n == 0) return real_1(prec); if (n == 1) return real_m2n(-1,prec); /*-1/2*/ if (odd(n)) return real_0(prec); k = n >> 1; if (!bernzone && k < 100) mpbern(k, prec); lbern = bernzone? lg(bernzone): 0; if (k < lbern) { B = gel(bernzone,k); if (typ(B) != t_REAL) return fractor(B, prec); if (realprec(B) >= prec) return rtor(B, prec); } /* not cached, must compute */ if (bernreal_use_zeta_i(n, prec)) B = storeB = bernreal_using_zeta(n, NULL, prec); else { storeB = bernfrac_using_zeta(n); B = fractor(storeB, prec); } if (k < lbern) { GEN old = gel(bernzone, k); gel(bernzone, k) = gclone(storeB); gunclone(old); } return B; } /* zeta(a*j+b), j=0..N-1, b>1, using sumalt. Johansonn'b thesis, Algo 4.7.1 */ static GEN veczetas(long a, long b, long N, long prec) { pari_sp av = avma; const long n = ceil(2 + prec2nbits_mul(prec, M_LN2/1.7627)); long j, k; GEN c, d, z = zerovec(N); c = d = int2n(2*n-1); for (k = n; k; k--) { GEN u, t = divii(d, powuu(k,b)); if (!odd(k)) t = negi(t); gel(z,1) = addii(gel(z,1), t); u = powuu(k,a); for (j = 1; j < N; j++) { t = divii(t,u); if (!signe(t)) break; gel(z,j+1) = addii(gel(z,j+1), t); } c = muluui(k,2*k-1,c); c = diviuuexact(c, 2*(n-k+1),n+k-1); d = addii(d,c); if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"zetaBorwein, k = %ld", k); gerepileall(av, 3, &c,&d,&z); } } for (j = 0; j < N; j++) { long u = b+a*j-1; gel(z,j+1) = rdivii(shifti(gel(z,j+1), u), subii(shifti(d,u), d), prec); } return gerepilecopy(av, z); } /* zeta(a*j+b), j=0..N-1, b>1, using sumalt */ GEN veczeta(GEN a, GEN b, long N, long prec) { pari_sp av; long n, j, k; GEN L, c, d, z; if (typ(a) == t_INT && typ(b) == t_INT) return veczetas(itos(a), itos(b), N, prec); av = avma; z = zerovec(N); n = ceil(2 + prec2nbits_mul(prec, M_LN2/1.7627)); c = d = int2n(2*n-1); for (k = n; k; k--) { GEN u, t; L = logr_abs(utor(k, prec)); /* log(k) */ t = gdiv(d, gexp(gmul(b, L), prec)); /* d / k^b */ if (!odd(k)) t = gneg(t); gel(z,1) = gadd(gel(z,1), t); u = gexp(gmul(a, L), prec); for (j = 1; j < N; j++) { t = gdiv(t,u); if (gexpo(t) < 0) break; gel(z,j+1) = gadd(gel(z,j+1), t); } c = muluui(k,2*k-1,c); c = diviuuexact(c, 2*(n-k+1),n+k-1); d = addii(d,c); if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"veczeta, k = %ld", k); gerepileall(av, 3, &c,&d,&z); } } L = mplog2(prec); for (j = 0; j < N; j++) { GEN u = gsubgs(gadd(b, gmulgs(a,j)), 1); GEN w = gexp(gmul(u, L), prec); /* 2^u */ gel(z,j+1) = gdiv(gmul(gel(z,j+1), w), gmul(d,gsubgs(w,1))); } return gerepilecopy(av, z); } /* zeta(s) using sumalt, case h=0,N=1. Assume s > 1 */ static GEN zetaBorwein(long s, long prec) { pari_sp av = avma; const long n = ceil(2 + prec2nbits_mul(prec, M_LN2/1.7627)); long k; GEN c, d, z = gen_0; c = d = int2n(2*n-1); for (k = n; k; k--) { GEN t = divii(d, powuu(k,s)); z = odd(k)? addii(z,t): subii(z,t); c = muluui(k,2*k-1,c); c = diviuuexact(c, 2*(n-k+1),n+k-1); d = addii(d,c); if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"zetaBorwein, k = %ld", k); gerepileall(av, 3, &c,&d,&z); } } z = rdivii(shifti(z, s-1), subii(shifti(d,s-1), d), prec); return gerepileuptoleaf(av, z); } /* assume k != 1 */ GEN szeta(long k, long prec) { pari_sp av = avma; GEN y; double p; /* treat trivial cases */ if (!k) { y = real2n(-1, prec); setsigne(y,-1); return y; } if (k < 0) { if ((k&1) == 0) return gen_0; /* the one value such that k < 0 and 1 - k < 0, due to overflow */ if ((ulong)k == (HIGHBIT | 1)) pari_err_OVERFLOW("zeta [large negative argument]"); k = 1-k; y = bernreal(k, prec); togglesign(y); return gerepileuptoleaf(av, divru(y, k)); } if (k > prec2nbits(prec)+1) return real_1(prec); if ((k&1) == 0) { if (bernreal_use_zeta(k, prec)) y = invr( inv_szeta_euler(k, 0, prec) ); else { y = mulrr(powru(Pi2n(1, prec), k), bernreal(k, prec)); y = divrr(y, mpfactr(k,prec)); setsigne(y, 1); shiftr_inplace(y, -1); } return gerepileuptoleaf(av, y); } /* k > 1 odd */ p = prec2nbits_mul(prec,0.393); /* 0.393 ~ 1/log_2(3+sqrt(8)) */ if (log2(p * log(p))*k > prec2nbits(prec)) return gerepileuptoleaf(av, invr( inv_szeta_euler(k, 0, prec) )); return zetaBorwein(k, prec); } /* s0 a t_INT, t_REAL or t_COMPLEX. * If a t_INT, assume it's not a trivial case (i.e we have s0 > 1, odd) * */ static GEN czeta(GEN s0, long prec) { GEN s, u, y, res, tes, sig, tau, invn2, unr, Ns, funeq_factor = NULL; long i, nn, lim, lim2; pari_sp av0 = avma, av; pari_timer T; if (DEBUGLEVEL>2) timer_start(&T); s = trans_fix_arg(&prec,&s0,&sig,&tau,&av,&res); if (typ(s0) == t_INT) return gerepileupto(av, gzeta(s0, prec)); if (!signe(tau)) /* real */ { long e = expo(sig); if (e >= -5 && (signe(sig) <= 0 || e < -1)) { /* s < 1/2 */ s = subsr(1, s); funeq_factor = gen_1; } } else { u = gsubsg(1, s); /* temp */ if (gexpo(u) < -5 || ((signe(sig) <= 0 || expo(sig) < -1) && gexpo(s) > -5)) { /* |1-s| < 1/32 || (real(s) < 1/2 && |imag(s)| > 1/32) */ s = u; funeq_factor = gen_1; } } if (funeq_factor) { /* s <--> 1-s */ GEN t; sig = real_i(s); /* Gamma(s) (2Pi)^-s 2 cos(Pi s/2) */ t = gmul(ggamma(gprec_w(s,prec),prec), gpow(Pi2n(1,prec), gneg(s), prec)); funeq_factor = gmul2n(gmul(t, gcos(gmul(Pi2n(-1,prec),s), prec)), 1); } if (gcmpgs(sig, prec2nbits(prec) + 1) > 0) { /* zeta(s) = 1 */ if (!funeq_factor) { avma = av0; return real_1(prec); } return gerepileupto(av0, funeq_factor); } optim_zeta(s, prec, &lim, &nn); if (DEBUGLEVEL>2) err_printf("lim, nn: [%ld, %ld]\n", lim, nn); incrprec(prec); unr = real_1(prec); /* one extra word of precision */ Ns = vecpowug(nn, gneg(s), prec); y = gmul2n(gel(Ns,nn), -1); for (i = nn-1; i; i--) y = gadd(y, gel(Ns,i)); if (DEBUGLEVEL>2) timer_printf(&T,"sum from 1 to N-1"); invn2 = divri(unr, sqru(nn)); lim2 = lim<<1; mpbern(lim,prec); tes = bernreal(lim2, prec); { GEN s1, s2, s3, s4, s5; pari_sp av2; s1 = gsub(gmul2n(s,1), unr); s2 = gmul(s, gsub(s,unr)); s3 = gmul2n(invn2,3); av2 = avma; s4 = gmul(invn2, gmul2n(gaddsg(4*lim-2,s1),1)); s5 = gmul(invn2, gadd(s2, gmulsg(lim2, gaddgs(s1, lim2)))); for (i = lim2-2; i>=2; i -= 2) { s5 = gsub(s5, s4); s4 = gsub(s4, s3); tes = gadd(bernreal(i,prec), divgunu(gmul(s5,tes), i+1)); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"czeta"); gerepileall(av2,3, &tes,&s5,&s4); } } u = gmul(gmul(tes,invn2), gmul2n(s2, -1)); tes = gmulsg(nn, gaddsg(1, u)); } if (DEBUGLEVEL>2) timer_printf(&T,"Bernoulli sum"); /* y += tes n^(-s) / (s-1) */ y = gadd(y, gmul(tes, gdiv(gel(Ns,nn), gsub(s, unr)))); if (funeq_factor) y = gmul(y, funeq_factor); avma = av; return affc_fixlg(y,res); } #if 0 /* return P mod x^n where P is polynomial in x */ static GEN pol_mod_xn(GEN P, long n) { long j, l = lg(P), N = n+2; GEN R; if (l > N) l = N; R = cgetg(N, t_POL); R[1] = evalvarn(0); for (j = 2; j < l; j++) gel(R,j) = gel(P,j); return normalizepol_lg(R, n+2); } /* compute the values of the twisted partial zeta function Z_f(a, c, s) for a in va */ GEN twistpartialzeta(GEN q, long f, long c, GEN va, GEN cff) { long j, k, lva = lg(va)-1, N = lg(cff)-1; pari_sp av, av2; GEN Ax, Cx, Bx, Dx, x = pol_x(0), y = pol_x(1); GEN cyc, psm, rep, eta, etaf; cyc = gdiv(gsubgs(gpowgs(y, c), 1), gsubgs(y, 1)); psm = polsym(cyc, degpol(cyc) - 1); eta = mkpolmod(y, cyc); etaf = gpowgs(eta,f); av = avma; Ax = gsubgs(gpowgs(gaddgs(x, 1), f), 1); Ax = gdiv(gmul(Ax, etaf), gsubsg(1, etaf)); Ax = gerepileupto(av, RgX_to_FqX(Ax, cyc, q)); Cx = Ax; Bx = gen_1; av = avma; for (j = 2; j <= N; j++) { Bx = gadd(Bx, Cx); Bx = FpXQX_red(Bx, cyc, q); Cx = FpXQX_mul(Cx, Ax, cyc, q); Cx = pol_mod_xn(Cx, N); if (gequal0(Cx)) break; if (gc_needed(av, 1)) { if(DEBUGMEM>1) pari_warn(warnmem, "twistpartialzeta (1), j = %ld/%ld", j, N); gerepileall(av, 2, &Cx, &Bx); } } Bx = lift_shallow(gmul(ginv(gsubsg(1, etaf)), Bx)); Bx = gerepileupto(av, RgX_to_FqX(Bx, cyc, q)); Cx = lift_shallow(gmul(eta, gaddsg(1, x))); Dx = pol_1(varn(x)); av2 = avma; for (j = lva; j > 1; j--) { GEN Ex; long e = va[j] - va[j-1]; if (e == 1) Ex = Cx; else /* e is very small in general and actually very rarely different to 1, it is always 1 for zetap (so it should be OK not to store them or to compute them in a smart way) */ Ex = gpowgs(Cx, e); Dx = gaddsg(1, FpXQX_mul(Dx, Ex, cyc, q)); if (gc_needed(av2, 1)) { if(DEBUGMEM>1) pari_warn(warnmem, "twistpartialzeta (2), j = %ld/%ld", lva-j, lva); Dx = gerepileupto(av2, FpXQX_red(Dx, cyc, q)); } } Dx = FpXQX_mul(Dx, Cx, cyc, q); /* va[1] = 1 */ Bx = gerepileupto(av, FpXQX_mul(Dx, Bx, cyc, q)); rep = gen_0; av2 = avma; for (k = 1; k <= N; k++) { GEN p2, ak = polcoef_i(Bx, k, 0); p2 = quicktrace(ak, psm); rep = modii(addii(rep, mulii(gel(cff, k), p2)), q); if (gc_needed(av2, 1)) { if(DEBUGMEM>1) pari_warn(warnmem, "twistpartialzeta (3), j = %ld/%ld", k, N); rep = gerepileupto(av2, rep); } } return rep; } /* initialize the roots of unity for the computation of the Teichmuller character (also the values of f and c) */ GEN init_teich(ulong p, GEN q, long prec) { GEN vz, gp = utoipos(p); pari_sp av = avma; long j; if (p == 2UL) return NULL; else { /* primitive (p-1)-th root of 1 */ GEN z, z0 = Zp_sqrtnlift(gen_1, utoipos(p-1), pgener_Fp(gp), gp, prec); z = z0; vz = cgetg(p, t_VEC); for (j = 1; j < (long)p-2; j++) { gel(vz, umodiu(z, p)) = z; /* z = z0^i */ z = modii(mulii(z, z0), q); } gel(vz, umodiu(z, p)) = z; /* z = z0^(p-2) */ gel(vz,1) = gen_1; /* z0^(p-1) */ } return gerepileupto(av, gcopy(vz)); } /* compute phi^(m)_s(x); s must be an integer */ GEN phi_ms(ulong p, GEN q, long m, GEN s, long x, GEN vz) { long xp = x % p; GEN p1, p2; if (!xp) return gen_0; if (vz) p1 =gel(vz,xp); /* vz[x] = Teichmuller(x) */ else p1 = (x & 2)? gen_m1: gen_1; p1 = Fp_pow(p1, addis(s, m), q); p2 = Fp_pow(stoi(x), negi(s), q); return modii(mulii(p1,p2), q); } /* compute the first N coefficients of the Mahler expansion of phi^m_s skipping the first one (which is zero) */ GEN coeff_of_phi_ms(ulong p, GEN q, long m, GEN s, long N, GEN vz) { GEN qs2 = shifti(q, -1), cff = zerovec(N); pari_sp av; long k, j; av = avma; for (k = 1; k <= N; k++) { gel(cff, k) = phi_ms(p, q, m, s, k, vz); if (gc_needed(av, 2)) { if(DEBUGMEM>1) pari_warn(warnmem, "coeff_of_phi_ms (1), k = %ld/%ld", N-k, N); cff = gerepileupto(av, gcopy(cff)); } } for (j = N; j > 1; j--) { GEN b = subii(gel(cff, j), gel(cff, j-1)); gel(cff, j) = centermodii(b, q, qs2); if (gc_needed(av, 2)) { if(DEBUGMEM>1) pari_warn(warnmem, "coeff_of_phi_ms (2), j = %ld/%ld", N-j, N); cff = gerepileupto(av, gcopy(cff)); } } for (k = 1; k < N; k++) for (j = N; j > k; j--) { GEN b = subii(gel(cff, j), gel(cff, j-1)); gel(cff, j) = centermodii(b, q, qs2); if (gc_needed(av, 2)) { if(DEBUGMEM>1) pari_warn(warnmem, "coeff_of_phi_ms (3), (k,j) = (%ld,%ld)/%ld", k, N-j, N); cff = gerepileupto(av, gcopy(cff)); } } k = N; while(gequal0(gel(cff, k))) k--; setlg(cff, k+1); if (DEBUGLEVEL > 2) err_printf(" coeff_of_phi_ms: %ld coefficients kept out of %ld\n", k, N); return gerepileupto(av, cff); } static long valfact(long N, ulong p) { long f = 0; while (N > 1) { N /= p; f += N; } return f; } static long number_of_terms(ulong p, long prec) { long N, f; if (prec == 0) return p; N = (long)((p-1)*prec + (p>>1)*(log2(prec)/log2(p))); N = p*(N/p); f = valfact(N, p); while (f > prec) { N = p*(N/p) - 1; f -= u_lval(N+1, p); } while (f < prec) { N = p*(N/p+1); f += u_lval(N, p); } return N; } static GEN zetap(GEN s) { ulong p; long N, f, c, prec = precp(s); pari_sp av = avma; GEN gp, q, vz, is, cff, val, va, cft; if (valp(s) < 0) pari_err_DOMAIN("zetap", "v_p(s)", "<", gen_0, s); if (!prec) prec = 1; gp = gel(s,2); p = itou(gp); is = gtrunc(s); /* make s an integer */ N = number_of_terms(p, prec); q = powiu(gp, prec); /* initialize the roots of unity for the computation of the Teichmuller character (also the values of f and c) */ if (DEBUGLEVEL > 1) err_printf("zetap: computing (p-1)th roots of 1\n"); vz = init_teich(p, q, prec); if (p == 2UL) { f = 4; c = 3; } else { f = (long)p; c = 2; } /* compute the first N coefficients of the Mahler expansion of phi^(-1)_s skipping the first one (which is zero) */ if (DEBUGLEVEL > 1) err_printf("zetap: computing Mahler expansion of phi^(-1)_s\n"); cff = coeff_of_phi_ms(p, q, -1, is, N, vz); /* compute the coefficients of the power series corresponding to the twisted partial zeta function Z_f(a, c, s) for a in va */ /* The line below looks a bit stupid but it is to keep the possibility of later adding p-adic Dirichlet L-functions */ va = identity_perm(f - 1); if (DEBUGLEVEL > 1) err_printf("zetap: computing values of twisted partial zeta functions\n"); val = twistpartialzeta(q, f, c, va, cff); /* sum over all a's the coefficients of the twisted partial zeta functions and integrate */ if (DEBUGLEVEL > 1) err_printf("zetap: multiplying by correcting factor\n"); /* multiply by the corrective factor */ cft = gsubgs(gmulsg(c, phi_ms(p, q, -1, is, c, vz)), 1); val = gdiv(val, cft); /* adjust the precision and return */ return gerepileupto(av, cvtop(val, gp, prec)); } #else /* s1 = s-1 or NULL (if s=1) */ static GEN hurwitzp_i(GEN cache, GEN s1, GEN x, GEN p, long prec) { long j, J = lg(cache) - 2; GEN S, x2, x2j; x = ginv(gadd(x, zeropadic_shallow(p, prec))); S = s1? gmul2n(gmul(s1, x), -1): gadd(Qp_log(x), gmul2n(x, -1)); x2j = x2 = gsqr(x); S = gaddgs(S,1); for (j = 1;; j++) { S = gadd(S, gmul(gel(cache, j+1), x2j)); if (j == J) break; x2j = gmul(x2, x2j); } if (s1) S = gmul(gdiv(S, s1), Qp_exp(gmul(s1, Qp_log(x)))); return S; } static GEN init_cache(long prec, long p, GEN s) { long j, fls = !gequal1(s), J = (((p==2)? (prec >> 1): prec) + 2) >> 1; GEN C = gen_1, cache = bernvec(J); for (j = 1; j <= J; j++) { /* B_{2j} * binomial(1-s, 2j) */ GEN t = (j > 1 || fls) ? gmul(gaddgs(s, 2*j-3), gaddgs(s, 2*j-2)) : s; C = gdiv(gmul(C, t), mulss(2*j, 2*j-1)); gel(cache, j+1) = gmul(gel(cache, j+1), C); } return cache; } static GEN zetap_i(GEN s, long D) { pari_sp av = avma; GEN cache, S, s1, gm, va, gp = gel(s,2); ulong a, p = itou(gp), m; long prec = valp(s) + precp(s); if (D <= 0) pari_err_DOMAIN("p-adic L-function", "D", "<=", gen_0, stoi(D)); if (!uposisfundamental(D)) pari_err_TYPE("p-adic L-function [D not fundamental]", stoi(D)); if (D == 1 && gequal1(s)) pari_err_DOMAIN("p-adic zeta", "argument", "=", gen_1, s); if (prec <= 0) prec = 1; cache = init_cache(prec, p, s); m = ulcm(D, p == 2? 4: p); gm = stoi(m); va = coprimes_zv(m); S = gen_0; s1 = gsubgs(s,1); if (gequal0(s1)) s1 = NULL; for (a = 1; a <= (m >> 1); a++) if (va[a]) { GEN z = hurwitzp_i(cache, s1, gdivsg(a,gm), gp, prec); S = gadd(S, gmulsg(kross(D,a), z)); } S = gdiv(gmul2n(S, 1), gm); if (D > 1) { gm = gadd(gm, zeropadic_shallow(gp, prec)); S = gmul(S, Qp_exp(gmul(gsubsg(1, s), Qp_log(gm)))); } return gerepileupto(av, S); } static GEN zetap(GEN s) { return zetap_i(s, 1); } #endif GEN gzeta(GEN x, long prec) { pari_sp av = avma; GEN y; if (gequal1(x)) pari_err_DOMAIN("zeta", "argument", "=", gen_1, x); switch(typ(x)) { case t_INT: if (is_bigint(x)) { if (signe(x) > 0) return real_1(prec); if (signe(x) < 0 && mod2(x) == 0) return real_0(prec); pari_err_OVERFLOW("zeta [large negative argument]"); } return szeta(itos(x),prec); case t_REAL: case t_COMPLEX: return czeta(x,prec); case t_PADIC: return zetap(x); default: av = avma; if (!(y = toser_i(x))) break; return gerepileupto(av, lfun(gen_1,y,prec2nbits(prec))); } return trans_eval("zeta",gzeta,x,prec); } /********************************************************/ /* Hurwitz zeta function */ /********************************************************/ static GEN hurwitzp(GEN s, GEN x) { GEN s1, T = (typ(s) == t_PADIC)? s: x, gp = gel(T,2); long p = itou(gp), vqp = (p==2)? 2: 1, prec = maxss(1, valp(T) + precp(T)); if (s == T) x = gadd(x, zeropadic_shallow(gp, prec)); else s = gadd(s, zeropadic_shallow(gp, prec)); /* now both s and x are t_PADIC */ if (valp(x) > -vqp) { GEN S = gen_0; long j, M = (p==2)? 4: p; for (j = 0; j < M; j++) { GEN y = gaddsg(j, x); if (valp(y) <= 0) S = gadd(S, hurwitzp(s, gdivgs(y, M))); } return gdivgs(S, M); } if (valp(s) <= 1/(p-1) - vqp) pari_err_DOMAIN("hurwitzp", "v(s)", "<=", stoi(1/(p-1)-vqp), s); s1 = gsubgs(s,1); if (gequal0(s1)) s1 = NULL; return hurwitzp_i(init_cache(prec,p,s), s1, x, gp, prec); } static void binsplit(GEN *pP, GEN *pR, GEN aN2, GEN isqaN, GEN s, long j, long k, long prec) { if (j + 1 == k) { long j2 = j << 1; GEN P; if (!j) P = gdiv(s, aN2); else { P = gmul(gaddgs(s, j2-1), gaddgs(s, j2)); P = gdivgs(gmul(P, isqaN), (j2+1) * (j2+2)); } if (pP) *pP = P; if (pR) *pR = gmul(bernreal(j2+2, prec), P); } else { GEN P1, R1, P2, R2; binsplit(&P1,pR? &R1: NULL, aN2, isqaN, s, j, (j+k) >> 1, prec); binsplit(pP? &P2: NULL, pR? &R2: NULL, aN2, isqaN, s, (j+k) >> 1, k, prec); if (pP) *pP = gmul(P1,P2); if (pR) *pR = gadd(R1, gmul(P1, R2)); } } /* New zetahurwitz, from Fredrik Johansson. */ GEN zetahurwitz(GEN s, GEN x, long der, long bitprec) { pari_sp av = avma; GEN al, ral, ral0, Nx, S1, S2, S3, N2, rx, sch = NULL, s0 = s, y; long j, k, m, N, precinit = nbits2prec(bitprec), prec = precinit; long fli = 0, v, prpr; pari_timer T; if (der < 0) pari_err_DOMAIN("zetahurwitz", "der", "<", gen_0, stoi(der)); if (der) { GEN z; if (!is_scalar_t(typ(s))) { z = deriv(zetahurwitz(s, x, der - 1, bitprec), -1); z = gdiv(z, deriv(s, -1)); } else { GEN sser; if (gequal1(s)) pari_err_DOMAIN("zetahurwitz", "s", "=", gen_1, s0); sser = gadd(gadd(s, pol_x(0)), zeroser(0, der + 2)); z = zetahurwitz(sser, x, 0, bitprec + der * log2(der)); z = gmul(mpfact(der), polcoeff0(z, der, -1)); } return gerepileupto(av,z); } if (typ(x) == t_PADIC || typ(s) == t_PADIC) return gerepilecopy(av, hurwitzp(s, x)); switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: rx = ground(real_i(x)); if (signe(rx) <= 0 && gexpo(gsub(x, rx)) < 17 - bitprec) pari_err_DOMAIN("zetahurwitz", "x", "<=", gen_0, x); break; default: if (!(y = toser_i(x))) pari_err_TYPE("zetahurwitz", x); x = y; rx = ground(polcoef_i(x, 0, -1)); if (typ(rx) != t_INT) pari_err_TYPE("zetahurwitz", x); } switch (typ(s)) { case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: break; default: if (!(y = toser_i(s))) pari_err_TYPE("zetahurwitz", s); if (valp(y) < 0) pari_err_DOMAIN("zetahurwitz", "val(s)", "<", gen_0, s); s0 = polcoef_i(y, 0, -1); switch(typ(s0)) { case t_INT: case t_REAL: case t_COMPLEX: case t_FRAC: break; case t_PADIC: pari_err_IMPL("zetahurwitz(t_SER of t_PADIC)"); default: pari_err_TYPE("zetahurwitz", s0); } sch = gequal0(s0)? y: serchop0(y); v = valp(sch); prpr = (lg(y) + v + 1)/v; if (gequal1(s0)) prpr += v; s = gadd(gadd(s0, pol_x(0)), zeroser(0, prpr)); } al = gneg(s0); ral = real_i(al); ral0 = ground(ral); if (gequal1(s0) && (!sch || gequal0(sch))) pari_err_DOMAIN("zetahurwitz", "s", "=", gen_1, s0); fli = (gsigne(ral0) >= 0 && gexpo(gsub(al, ral0)) < 17 - bitprec); if (!sch && fli) { /* al ~ non negative integer */ k = itos(gceil(ral)) + 1; if (odd(k)) k++; N = 1; } else { const double D = (typ(s) == t_INT)? 0.24: 0.4; GEN C, rs = real_i(gsubsg(1, s0)); long ebit = 0; if (fli) al = gadd(al, ghalf); /* hack */ if (gsigne(rs) > 0) { ebit = (long)(ceil(gtodouble(rs)*expu(bitprec))); bitprec += ebit; prec = nbits2prec(bitprec); x = gprec_w(x, prec); s = gprec_w(s, prec); al = gprec_w(al, prec); if (sch) sch = gprec_w(sch, prec); } k = maxss(itos(gceil(gadd(ral, ghalf))) + 1, 50); k = maxss(k, (long)(D*bitprec)); if (odd(k)) k++; C = gmulsg(2, gmul(binomial(al, k+1), gdivgs(bernfrac(k+2), k+2))); C = gmul2n(gabs(C,LOWDEFAULTPREC), bitprec); C = gadd(gpow(C, ginv(gsubsg(k+1, ral)), LOWDEFAULTPREC), gabs(gsubsg(1,rx), LOWDEFAULTPREC)); C = gceil(polcoef_i(C, 0, -1)); if (typ(C) != t_INT) pari_err_TYPE("zetahurwitz",s); N = itos(gceil(C)); if (N < 1) N = 1; } N = maxss(N, 1 - itos(rx)); al = gneg(s); if (DEBUGLEVEL>2) timer_start(&T); incrprec(prec); Nx = gmul(real_1(prec), gaddsg(N - 1, x)); S1 = S3 = gpow(Nx, al, prec); for (m = N - 2; m >= 0; m--) S1 = gadd(S1, gpow(gaddsg(m,x), al, prec)); if (DEBUGLEVEL>2) timer_printf(&T,"sum from 0 to N - 1"); mpbern(k >> 1, prec); N2 = ginv(gsqr(Nx)); if (typ(s0) == t_INT) { S2 = gen_0; for (j = k; j >= 2; j -= 2) { GEN t = gsubgs(al, j), u = gmul(t, gaddgs(t, 1)); u = gmul(gdivgs(u, j*(j+1)), gmul(S2, N2)); S2 = gadd(gdivgs(bernreal(j, prec), j), u); } S2 = gmul(S2, gdiv(al, Nx)); } else { binsplit(NULL,&S2, gmul2n(Nx,1), N2, s, 0, k >> 1, prec); S2 = gneg(S2); } S2 = gadd(ghalf, S2); if (DEBUGLEVEL>2) timer_printf(&T,"Bernoulli sum"); S2 = gmul(S3, gadd(gdiv(Nx, gaddsg(1, al)), S2)); S1 = gprec_wtrunc(gsub(S1, S2), precinit); if (sch) return gerepileupto(av, gsubst(S1, 0, sch)); return gerepilecopy(av, S1); } /***********************************************************************/ /** **/ /** FONCTIONS POLYLOGARITHME **/ /** **/ /***********************************************************************/ /* returns H_n = 1 + 1/2 + ... + 1/n, as a rational number (n "small") */ static GEN Harmonic(long n) { GEN h = gen_1; long i; for (i=2; i<=n; i++) h = gadd(h, mkfrac(gen_1, utoipos(i))); return h; } /* m >= 2. Validity domain |log x| < 2*Pi, contains log |x| < 5.44, * Li_m(x = e^z) = sum_{n >= 0} zeta(m-n) z^n / n! * with zeta(1) := H_{m-1} - log(-z) */ static GEN cxpolylog(long m, GEN x, long prec) { long li, n, k, real; GEN z, Z, h, q, s, S; pari_sp av; double dz; pari_timer T; if (gequal1(x)) return szeta(m,prec); /* x real <= 1 ==> Li_m(x) real */ real = (typ(x) == t_REAL && (expo(x) < 0 || signe(x) <= 0)); z = glog(x,prec); /* n = 0 */ q = gen_1; s = szeta(m,prec); for (n=1; n < m-1; n++) { q = gdivgs(gmul(q,z),n); s = gadd(s, gmul(szeta(m-n,prec), real? real_i(q): q)); } /* n = m-1 */ q = gdivgs(gmul(q,z),n); /* multiply by "zeta(1)" */ h = gmul(q, gsub(Harmonic(m-1), glog(gneg_i(z),prec))); s = gadd(s, real? real_i(h): h); /* n = m */ q = gdivgs(gmul(q,z),m); s = gadd(s, gmul(szeta(0,prec), real? real_i(q): q)); /* n = m+1 */ q = gdivgs(gmul(q,z),m+1); /* = z^(m+1) / (m+1)! */ s = gadd(s, gmul(szeta(-1,prec), real? real_i(q): q)); li = -(prec2nbits(prec)+1); if (DEBUGLEVEL) timer_start(&T); dz = dbllog2(z) - log2PI; /* ~ log2(|z|/2Pi) */ /* sum_{k >= 1} zeta(-1-2k) * z^(2k+m+1) / (2k+m+1)! * = 2 z^(m-1) sum_{k >= 1} (-1)^{k-1} zeta(2k+2) * (z/2Pi)^(2k+2) * / (2k+2)..(2k+1+m)) * Stop at k = (li - (m-1)*Lz - m) / (2*Lz - log2(2*Pi)), Lz = log2 |z| */ /* We cut the sum in two: small values of k first */ Z = gsqr(z); av = avma; for(k = 1;; k++) { GEN t = q = divgunu(gmul(q,Z), 2*k+m); /* z^(2k+m+1)/(2k+m+1)! */ if (real) t = real_i(t); t = gmul(t, gdivgs(bernfrac(2*k+2), 2*k+2)); /* - t * zeta(1-(2k+2)) */ s = gsub(s, t); if (gexpo(t) < li) return s; /* large values ? */ if (bernreal_use_zeta(2*k+4, prec + ((2*k+4)*dz) / BITS_IN_LONG)) break; if ((k & 0x1ff) == 0) gerepileall(av, 2, &s, &q); } if (DEBUGLEVEL>2) timer_printf(&T, "polylog: small k <= %ld", k); Z = gsqr(gdiv(z, Pi2n(1,prec))); q = gmul(gpowgs(z, m-1), gpowgs(Z, k+1)); /* (z/2Pi)^(2k+2) * z^(m-1) */ S = gen_0; av = avma; for(k++;; k++) { GEN t = q = gmul(q,Z); long b; if (real) t = real_i(t); b = prec + gexpo(t) / BITS_IN_LONG; /* decrease accuracy */ if (b == 2) break; /* t * zeta(2k+2) / (2k+2)..(2k+1+m) */ t = gdiv(t, mulri(inv_szeta_euler(2*k+2, 0, b), mulu_interval(2*k+2, 2*k+1+m))); S = odd(k)? gadd(S, t): gsub(S, t); if (gexpo(t) < li) break; if ((k & 0x1ff) == 0) gerepileall(av, 2, &S, &q); } if (DEBUGLEVEL>2) timer_printf(&T, "polylog: large k <= %ld", k); return gadd(s, gmul2n(S,1)); } static GEN polylog(long m, GEN x, long prec) { long l, e, i, G, sx; pari_sp av, av1; GEN X, Xn, z, p1, p2, y, res; if (m < 0) pari_err_DOMAIN("polylog", "index", "<", gen_0, stoi(m)); if (!m) return mkfrac(gen_m1,gen_2); if (gequal0(x)) return gcopy(x); if (m==1) { av = avma; return gerepileupto(av, gneg(glog(gsub(gen_1,x), prec))); } l = precision(x); if (!l) l = prec; else prec = l; res = cgetc(l); av = avma; x = gtofp(x, l+EXTRAPRECWORD); e = gexpo(gnorm(x)); if (!e || e == -1) { y = cxpolylog(m,x,prec); avma = av; return affc_fixlg(y, res); } X = (e > 0)? ginv(x): x; G = -prec2nbits(l); av1 = avma; y = Xn = X; for (i=2; ; i++) { Xn = gmul(X,Xn); p2 = gdiv(Xn,powuu(i,m)); y = gadd(y,p2); if (gexpo(p2) <= G) break; if (gc_needed(av1,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"polylog"); gerepileall(av1,2, &y, &Xn); } } if (e < 0) { avma = av; return affc_fixlg(y, res); } sx = gsigne(imag_i(x)); if (!sx) { if (m&1) sx = gsigne(gsub(gen_1, real_i(x))); else sx = - gsigne(real_i(x)); } z = divri(mppi(l), mpfact(m-1)); setsigne(z, sx); z = mkcomplex(gen_0, z); if (m == 2) { /* same formula as below, written more efficiently */ y = gneg_i(y); if (typ(x) == t_REAL && signe(x) < 0) p1 = logr_abs(x); else p1 = gsub(glog(x,l), z); p1 = gmul2n(gsqr(p1), -1); /* = (log(-x))^2 / 2 */ p1 = gadd(p1, divru(sqrr(mppi(l)), 6)); p1 = gneg_i(p1); } else { GEN logx = glog(x,l), logx2 = gsqr(logx); p1 = mkfrac(gen_m1,gen_2); for (i=m-2; i>=0; i-=2) p1 = gadd(szeta(m-i,l), gmul(p1,gdivgs(logx2,(i+1)*(i+2)))); if (m&1) p1 = gmul(logx,p1); else y = gneg_i(y); p1 = gadd(gmul2n(p1,1), gmul(z,gpowgs(logx,m-1))); if (typ(x) == t_REAL && signe(x) < 0) p1 = real_i(p1); } y = gadd(y,p1); avma = av; return affc_fixlg(y, res); } GEN dilog(GEN x, long prec) { return gpolylog(2, x, prec); } /* x a floating point number, t_REAL or t_COMPLEX of t_REAL */ static GEN logabs(GEN x) { GEN y; if (typ(x) == t_COMPLEX) { y = logr_abs( cxnorm(x) ); shiftr_inplace(y, -1); } else y = logr_abs(x); return y; } static GEN polylogD(long m, GEN x, long flag, long prec) { long k, l, fl, m2; pari_sp av; GEN p1, p2, y; if (gequal0(x)) return gcopy(x); m2 = m&1; if (gequal1(x) && m>=2) return m2? szeta(m,prec): gen_0; av = avma; l = precision(x); if (!l) { l = prec; x = gtofp(x,l); } p1 = logabs(x); k = signe(p1); if (k > 0) { x = ginv(x); fl = !m2; } else { setabssign(p1); fl = 0; } /* |x| <= 1, p1 = - log|x| >= 0 */ p2 = gen_1; y = polylog(m,x,l); y = m2? real_i(y): imag_i(y); for (k=1; k=2) return m2? szeta(m,prec): gen_0; av = avma; l = precision(x); if (!l) { l = prec; x = gtofp(x,l); } p1 = logabs(x); if (signe(p1) > 0) { x = ginv(x); fl = !m2; setsigne(p1, -1); } else fl = 0; /* |x| <= 1 */ y = polylog(m,x,l); y = m2? real_i(y): imag_i(y); if (m==1) { shiftr_inplace(p1, -1); /* log |x| / 2 */ y = gadd(y, p1); } else { /* m >= 2, \sum_{0 <= k <= m} 2^k B_k/k! (log |x|)^k Li_{m-k}(x), with Li_0(x) := -1/2 */ GEN u, t; t = polylog(m-1,x,l); u = gneg_i(p1); /* u = 2 B1 log |x| */ y = gadd(y, gmul(u, m2?real_i(t):imag_i(t))); if (m > 2) { GEN p2; shiftr_inplace(p1, 1); /* p1 = 2log|x| <= 0 */ mpbern(m>>1, l); p1 = sqrr(p1); p2 = shiftr(p1,-1); for (k=2; k 2) p2 = divgunu(gmul(p2,p1),k-1); /* p2 = 2^k/k! log^k |x|*/ t = polylog(m-k,x,l); u = gmul(p2, bernreal(k, prec)); y = gadd(y, gmul(u, m2?real_i(t):imag_i(t))); } } } if (fl) y = gneg(y); return gerepileupto(av, y); } GEN gpolylog(long m, GEN x, long prec) { long i, n, v; pari_sp av = avma; GEN a, y, p1; if (m <= 0) { GEN t = mkpoln(2, gen_m1, gen_1); /* 1 - X */ p1 = pol_x(0); for (i=2; i <= -m; i++) p1 = RgX_shift_shallow(gadd(gmul(t,ZX_deriv(p1)), gmulsg(i,p1)), 1); p1 = gdiv(p1, gpowgs(t,1-m)); return gerepileupto(av, poleval(p1,x)); } switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: case t_QUAD: return polylog(m,x,prec); case t_POLMOD: return gerepileupto(av, polylogvec(m, polmod_to_embed(x, prec), prec)); case t_INTMOD: case t_PADIC: pari_err_IMPL( "padic polylogarithm"); case t_VEC: case t_COL: case t_MAT: return polylogvec(m, x, prec); default: av = avma; if (!(y = toser_i(x))) break; if (!m) { avma = av; return mkfrac(gen_m1,gen_2); } if (m==1) return gerepileupto(av, gneg( glog(gsub(gen_1,y),prec) )); if (gequal0(y)) return gerepilecopy(av, y); v = valp(y); if (v < 0) pari_err_DOMAIN("polylog","valuation", "<", gen_0, x); if (v > 0) { n = (lg(y)-3 + v) / v; a = zeroser(varn(y), lg(y)-2); for (i=n; i>=1; i--) a = gmul(y, gadd(a, powis(utoipos(i),-m))); } else { /* v == 0 */ long vy = varn(y); GEN a0 = polcoeff0(y, 0, -1), yprimeovery = gdiv(derivser(y), y); a = gneg( glog(gsub(gen_1,y), prec) ); for (i=2; i<=m; i++) a = gadd(gpolylog(i, a0, prec), integ(gmul(yprimeovery, a), vy)); } return gerepileupto(av, a); } pari_err_TYPE("gpolylog",x); return NULL; /* LCOV_EXCL_LINE */ } GEN polylog0(long m, GEN x, long flag, long prec) { switch(flag) { case 0: return gpolylog(m,x,prec); case 1: return polylogD(m,x,0,prec); case 2: return polylogD(m,x,1,prec); case 3: return polylogP(m,x,prec); default: pari_err_FLAG("polylog"); } return NULL; /* LCOV_EXCL_LINE */ } GEN upper_to_cx(GEN x, long *prec) { long tx = typ(x), l; if (tx == t_QUAD) { x = quadtofp(x, *prec); tx = typ(x); } switch(tx) { case t_COMPLEX: if (gsigne(gel(x,2)) > 0) break; /*fall through*/ case t_REAL: case t_INT: case t_FRAC: pari_err_DOMAIN("modular function", "Im(argument)", "<=", gen_0, x); default: pari_err_TYPE("modular function", x); } l = precision(x); if (l) *prec = l; return x; } /* sqrt(3)/2 */ static GEN sqrt32(long prec) { GEN z = sqrtr_abs(stor(3,prec)); setexpo(z, -1); return z; } /* exp(i x), x = k pi/12 */ static GEN e12(ulong k, long prec) { int s, sPi, sPiov2; GEN z, t; k %= 24; if (!k) return gen_1; if (k == 12) return gen_m1; if (k >12) { s = 1; k = 24 - k; } else s = 0; /* x -> 2pi - x */ if (k > 6) { sPi = 1; k = 12 - k; } else sPi = 0; /* x -> pi - x */ if (k > 3) { sPiov2 = 1; k = 6 - k; } else sPiov2 = 0; /* x -> pi/2 - x */ z = cgetg(3, t_COMPLEX); switch(k) { case 0: gel(z,1) = icopy(gen_1); gel(z,2) = gen_0; break; case 1: t = gmul2n(addrs(sqrt32(prec), 1), -1); gel(z,1) = sqrtr(t); gel(z,2) = gmul2n(invr(gel(z,1)), -2); break; case 2: gel(z,1) = sqrt32(prec); gel(z,2) = real2n(-1, prec); break; case 3: gel(z,1) = sqrtr_abs(real2n(-1,prec)); gel(z,2) = rcopy(gel(z,1)); break; } if (sPiov2) swap(gel(z,1), gel(z,2)); if (sPi) togglesign(gel(z,1)); if (s) togglesign(gel(z,2)); return z; } /* z a t_FRAC */ static GEN eiPi_frac(GEN z, long prec) { GEN n, d; ulong q, r; n = gel(z,1); d = gel(z,2); q = uabsdivui_rem(12, d, &r); if (!r) /* relatively frequent case */ return e12(q * umodiu(n, 24), prec); n = centermodii(n, shifti(d,1), d); return expIr(divri(mulri(mppi(prec), n), d)); } /* exp(i Pi z), z a t_INT or t_FRAC */ static GEN exp_IPiQ(GEN z, long prec) { if (typ(z) == t_INT) return mpodd(z)? gen_m1: gen_1; return eiPi_frac(z, prec); } /* z a t_COMPLEX */ static GEN exp_IPiC(GEN z, long prec) { GEN r, x = gel(z,1), y = gel(z,2); GEN pi, mpi = mppi(prec); togglesign(mpi); /* mpi = -Pi */ r = gexp(gmul(mpi, y), prec); switch(typ(x)) { case t_INT: if (mpodd(x)) togglesign(r); return r; case t_FRAC: return gmul(r, eiPi_frac(x, prec)); default: pi = mpi; togglesign(mpi); /* pi = Pi */ return gmul(r, expIr(gmul(pi, x))); } } static GEN qq(GEN x, long prec) { long tx = typ(x); GEN y; if (is_scalar_t(tx)) { if (tx == t_PADIC) return x; x = upper_to_cx(x, &prec); return exp_IPiC(gmul2n(x,1), prec); /* e(x) */ } if (! ( y = toser_i(x)) ) pari_err_TYPE("modular function", x); return y; } /* return (y * X^d) + x. Assume d > 0, x != 0, valp(x) = 0 */ static GEN ser_addmulXn(GEN y, GEN x, long d) { long i, lx, ly, l = valp(y) + d; /* > 0 */ GEN z; lx = lg(x); ly = lg(y) + l; if (lx < ly) ly = lx; if (l > lx-2) return gcopy(x); z = cgetg(ly,t_SER); for (i=2; i<=l+1; i++) gel(z,i) = gel(x,i); for ( ; i < ly; i++) gel(z,i) = gadd(gel(x,i),gel(y,i-l)); z[1] = x[1]; return z; } /* q a t_POL s.t. q(0) != 0, v > 0, Q = x^v*q; return \prod_i (1-Q^i) */ static GEN RgXn_eta(GEN q, long v, long lim) { pari_sp av = avma; GEN qn, ps, y; ulong vps, vqn, n; if (!degpol(q) && isint1(gel(q,2))) return eta_ZXn(v, lim+v); y = qn = ps = pol_1(0); vps = vqn = 0; for(n = 0;; n++) { /* qn = q^n, ps = (-1)^n q^(n(3n+1)/2), * vps, vqn valuation of ps, qn HERE */ pari_sp av2 = avma; ulong vt = vps + 2*vqn + v; /* valuation of t at END of loop body */ long k1, k2; GEN t; vqn += v; vps = vt + vqn; /* valuation of qn, ps at END of body */ k1 = lim + v - vt + 1; k2 = k1 - vqn; /* = lim + v - vps + 1 */ if (k1 <= 0) break; t = RgX_mul(q, RgX_sqr(qn)); t = RgXn_red_shallow(t, k1); t = RgX_mul(ps,t); t = RgXn_red_shallow(t, k1); t = RgX_neg(t); /* t = (-1)^(n+1) q^(n(3n+1)/2 + 2n+1) */ t = gerepileupto(av2, t); y = RgX_addmulXn_shallow(t, y, vt); if (k2 <= 0) break; qn = RgX_mul(qn,q); ps = RgX_mul(t,qn); ps = RgXn_red_shallow(ps, k2); y = RgX_addmulXn_shallow(ps, y, vps); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"eta, n = %ld", n); gerepileall(av, 3, &y, &qn, &ps); } } return y; } static GEN inteta(GEN q) { long tx = typ(q); GEN ps, qn, y; y = gen_1; qn = gen_1; ps = gen_1; if (tx==t_PADIC) { if (valp(q) <= 0) pari_err_DOMAIN("eta", "v_p(q)", "<=",gen_0,q); for(;;) { GEN t = gneg_i(gmul(ps,gmul(q,gsqr(qn)))); y = gadd(y,t); qn = gmul(qn,q); ps = gmul(t,qn); t = y; y = gadd(y,ps); if (gequal(t,y)) return y; } } if (tx == t_SER) { ulong vps, vqn; long l = lg(q), v, n; pari_sp av; v = valp(q); /* handle valuation separately to avoid overflow */ if (v <= 0) pari_err_DOMAIN("eta", "v_p(q)", "<=",gen_0,q); y = ser2pol_i(q, l); /* t_SER inefficient when input has low degree */ n = degpol(y); if (n <= (l>>2)) { GEN z = RgXn_eta(y, v, l-2); setvarn(z, varn(y)); return RgX_to_ser(z, l+v); } q = leafcopy(q); av = avma; setvalp(q, 0); y = scalarser(gen_1, varn(q), l+v); vps = vqn = 0; for(n = 0;; n++) { /* qn = q^n, ps = (-1)^n q^(n(3n+1)/2) */ ulong vt = vps + 2*vqn + v; long k; GEN t; t = gneg_i(gmul(ps,gmul(q,gsqr(qn)))); /* t = (-1)^(n+1) q^(n(3n+1)/2 + 2n+1) */ y = ser_addmulXn(t, y, vt); vqn += v; vps = vt + vqn; k = l+v - vps; if (k <= 2) return y; qn = gmul(qn,q); ps = gmul(t,qn); y = ser_addmulXn(ps, y, vps); setlg(q, k); setlg(qn, k); setlg(ps, k); if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"eta"); gerepileall(av, 3, &y, &qn, &ps); } } } { long l = -prec2nbits(precision(q)); pari_sp av = avma; for(;;) { GEN t = gneg_i(gmul(ps,gmul(q,gsqr(qn)))); /* qn = q^n * ps = (-1)^n q^(n(3n+1)/2) * t = (-1)^(n+1) q^(n(3n+1)/2 + 2n+1) */ y = gadd(y,t); qn = gmul(qn,q); ps = gmul(t,qn); y = gadd(y,ps); if (gexpo(ps)-gexpo(y) < l) return y; if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"eta"); gerepileall(av, 3, &y, &qn, &ps); } } } } GEN eta(GEN x, long prec) { pari_sp av = avma; GEN z = inteta( qq(x,prec) ); if (typ(z) == t_SER) return gerepilecopy(av, z); return gerepileupto(av, z); } /* s(h,k) = sum(n = 1, k-1, (n/k)*(frac(h*n/k) - 1/2)) * Knuth's algorithm. h integer, k integer > 0, (h,k) = 1 */ GEN sumdedekind_coprime(GEN h, GEN k) { pari_sp av = avma; GEN s2, s1, p, pp; long s; if (lgefint(k) == 3 && uel(k,2) <= (2*(ulong)LONG_MAX) / 3) { ulong kk = k[2], hh = umodiu(h, kk); long s1, s2; GEN v; if (signe(k) < 0) { k = negi(k); hh = Fl_neg(hh, kk); } v = u_sumdedekind_coprime(hh, kk); s1 = v[1]; s2 = v[2]; return gerepileupto(av, gdiv(addis(mulis(k,s1), s2), muluu(12, kk))); } s = 1; s1 = gen_0; p = gen_1; pp = gen_0; s2 = h = modii(h, k); while (signe(h)) { GEN r, nexth, a = dvmdii(k, h, &nexth); if (is_pm1(h)) s2 = s == 1? addii(s2, p): subii(s2, p); s1 = s == 1? addii(s1, a): subii(s1, a); s = -s; k = h; h = nexth; r = addii(mulii(a,p), pp); pp = p; p = r; } /* at this point p = original k */ if (s == -1) s1 = subiu(s1, 3); return gerepileupto(av, gdiv(addii(mulii(p,s1), s2), muliu(p,12))); } /* as above, for ulong arguments. * k integer > 0, 0 <= h < k, (h,k) = 1. Returns [s1,s2] such that * s(h,k) = (s2 + k s1) / (12k). Requires max(h + k/2, k) < LONG_MAX * to avoid overflow, in particular k <= LONG_MAX * 2/3 is fine */ GEN u_sumdedekind_coprime(long h, long k) { long s = 1, s1 = 0, s2 = h, p = 1, pp = 0; while (h) { long r, nexth = k % h, a = k / h; /* a >= 1, a >= 2 if h = 1 */ if (h == 1) s2 += p * s; /* occurs exactly once, last step */ s1 += a * s; s = -s; k = h; h = nexth; r = a*p + pp; pp = p; p = r; /* p >= pp >= 0 */ } /* in the above computation, p increases from 1 to original k, * -k/2 <= s2 <= h + k/2, and |s1| <= k */ if (s < 0) s1 -= 3; /* |s1| <= k+3 ? */ /* But in fact, |s2 + p s1| <= k^2 + 1/2 - 3k; if (s < 0), we have * |s2| <= k/2 and it follows that |s1| < k here as well */ /* p = k; s(h,k) = (s2 + p s1)/12p. */ return mkvecsmall2(s1, s2); } GEN sumdedekind(GEN h, GEN k) { pari_sp av = avma; GEN d; if (typ(h) != t_INT) pari_err_TYPE("sumdedekind",h); if (typ(k) != t_INT) pari_err_TYPE("sumdedekind",k); d = gcdii(h,k); if (!is_pm1(d)) { h = diviiexact(h, d); k = diviiexact(k, d); } return gerepileupto(av, sumdedekind_coprime(h,k)); } /* eta(x); assume Im x >> 0 (e.g. x in SL2's standard fundamental domain) */ static GEN eta_reduced(GEN x, long prec) { GEN z = exp_IPiC(gdivgs(x, 12), prec); /* e(x/24) */ if (24 * gexpo(z) >= -prec2nbits(prec)) z = gmul(z, inteta( gpowgs(z,24) )); return z; } /* x = U.z (flag = 1), or x = U^(-1).z (flag = 0) * Return [s,t] such that eta(z) = eta(x) * sqrt(s) * exp(I Pi t) */ static GEN eta_correction(GEN x, GEN U, long flag) { GEN a,b,c,d, s,t; long sc; a = gcoeff(U,1,1); b = gcoeff(U,1,2); c = gcoeff(U,2,1); d = gcoeff(U,2,2); /* replace U by U^(-1) */ if (flag) { swap(a,d); togglesign_safe(&b); togglesign_safe(&c); } sc = signe(c); if (!sc) { if (signe(d) < 0) togglesign_safe(&b); s = gen_1; t = gdivgs(utoi(umodiu(b, 24)), 12); } else { if (sc < 0) { togglesign_safe(&a); togglesign_safe(&b); togglesign_safe(&c); togglesign_safe(&d); } /* now c > 0 */ s = mulcxmI(gadd(gmul(c,x), d)); t = gadd(gdiv(addii(a,d),muliu(c,12)), sumdedekind_coprime(negi(d),c)); /* correction : exp(I Pi (((a+d)/12c) + s(-d,c)) ) sqrt(-i(cx+d)) */ } return mkvec2(s, t); } /* returns the true value of eta(x) for Im(x) > 0, using reduction to * standard fundamental domain */ GEN trueeta(GEN x, long prec) { pari_sp av = avma; GEN U, st, s, t; if (!is_scalar_t(typ(x))) pari_err_TYPE("trueeta",x); x = upper_to_cx(x, &prec); x = cxredsl2(x, &U); st = eta_correction(x, U, 1); x = eta_reduced(x, prec); s = gel(st, 1); t = gel(st, 2); x = gmul(x, exp_IPiQ(t, prec)); if (s != gen_1) x = gmul(x, gsqrt(s, prec)); return gerepileupto(av, x); } GEN eta0(GEN x, long flag,long prec) { return flag? trueeta(x,prec): eta(x,prec); } /* eta(q) = 1 + \sum_{n>0} (-1)^n * (q^(n(3n-1)/2) + q^(n(3n+1)/2)) */ static GEN ser_eta(long prec) { GEN e = cgetg(prec+2, t_SER), ed = e+2; long n, j; e[1] = evalsigne(1)|_evalvalp(0)|evalvarn(0); gel(ed,0) = gen_1; for (n = 1; n < prec; n++) gel(ed,n) = gen_0; for (n = 1, j = 0; n < prec; n++) { GEN s; j += 3*n-2; /* = n*(3*n-1) / 2 */; if (j >= prec) break; s = odd(n)? gen_m1: gen_1; gel(ed, j) = s; if (j+n >= prec) break; gel(ed, j+n) = s; } return e; } static GEN coeffEu(GEN fa) { pari_sp av = avma; return gerepileuptoint(av, mului(65520, usumdivk_fact(fa,11))); } /* E12 = 1 + q*E/691 */ static GEN ser_E(long prec) { GEN e = cgetg(prec+2, t_SER), ed = e+2; GEN F = vecfactoru_i(2, prec); /* F[n] = factoru(n+1) */ long n; e[1] = evalsigne(1)|_evalvalp(0)|evalvarn(0); gel(ed,0) = utoipos(65520); for (n = 1; n < prec; n++) gel(ed,n) = coeffEu(gel(F,n)); return e; } /* j = E12/Delta + 432000/691, E12 = 1 + q*E/691 */ static GEN ser_j2(long prec, long v) { pari_sp av = avma; GEN iD = gpowgs(ginv(ser_eta(prec)), 24); /* q/Delta */ GEN J = gmul(ser_E(prec), iD); setvalp(iD,-1); /* now 1/Delta */ J = gadd(gdivgs(J, 691), iD); J = gerepileupto(av, J); if (prec > 1) gel(J,3) = utoipos(744); setvarn(J,v); return J; } /* j(q) = \sum_{n >= -1} c(n)q^n, * \sum_{n = -1}^{N-1} c(n) (-10n \sigma_3(N-n) + 21 \sigma_5(N-n)) * = c(N) (N+1)/24 */ static GEN ser_j(long prec, long v) { GEN j, J, S3, S5, F; long i, n; if (prec > 64) return ser_j2(prec, v); S3 = cgetg(prec+1, t_VEC); S5 = cgetg(prec+1,t_VEC); F = vecfactoru_i(1, prec); for (n = 1; n <= prec; n++) { GEN fa = gel(F,n); gel(S3,n) = mului(10, usumdivk_fact(fa,3)); gel(S5,n) = mului(21, usumdivk_fact(fa,5)); } J = cgetg(prec+2, t_SER), J[1] = evalvarn(v)|evalsigne(1)|evalvalp(-1); j = J+3; gel(j,-1) = gen_1; gel(j,0) = utoipos(744); gel(j,1) = utoipos(196884); for (n = 2; n < prec; n++) { pari_sp av = avma; GEN c, s3 = gel(S3,n+1), s5 = gel(S5,n+1); c = addii(s3, s5); for (i = 0; i < n; i++) { s3 = gel(S3,n-i); s5 = gel(S5,n-i); c = addii(c, mulii(gel(j,i), subii(s5, mului(i,s3)))); } gel(j,n) = gerepileuptoint(av, diviuexact(muliu(c,24), n+1)); } return J; } GEN jell(GEN x, long prec) { long tx = typ(x); pari_sp av = avma; GEN q, h, U; if (!is_scalar_t(tx)) { long v; if (gequalX(x)) return ser_j(precdl, varn(x)); q = toser_i(x); if (!q) pari_err_TYPE("ellj",x); v = fetch_var_higher(); h = ser_j(lg(q)-2, v); h = gsubst(h, v, q); delete_var(); return gerepileupto(av, h); } if (tx == t_PADIC) { GEN p2, p1 = gdiv(inteta(gsqr(x)), inteta(x)); p1 = gmul2n(gsqr(p1),1); p1 = gmul(x,gpowgs(p1,12)); p2 = gaddsg(768,gadd(gsqr(p1),gdivsg(4096,p1))); p1 = gmulsg(48,p1); return gerepileupto(av, gadd(p2,p1)); } /* Let h = Delta(2x) / Delta(x), then j(x) = (1 + 256h)^3 / h */ x = upper_to_cx(x, &prec); x = cxredsl2(x, &U); /* forget about Ua : j has weight 0 */ { /* cf eta_reduced, raised to power 24 * Compute * t = (inteta(q(2x)) / inteta(q(x))) ^ 24; * then * h = t * (q(2x) / q(x) = t * q(x); * but inteta(q) costly and useless if expo(q) << 1 => inteta(q) = 1. * log_2 ( exp(-2Pi Im tau) ) < -prec2nbits(prec) * <=> Im tau > prec2nbits(prec) * log(2) / 2Pi */ long C = (long)prec2nbits_mul(prec, M_LN2/(2*M_PI)); q = exp_IPiC(gmul2n(x,1), prec); /* e(x) */ if (gcmpgs(gel(x,2), C) > 0) /* eta(q(x)) = 1 : no need to compute q(2x) */ h = q; else { GEN t = gdiv(inteta(gsqr(q)), inteta(q)); h = gmul(q, gpowgs(t, 24)); } } /* real_1 important ! gaddgs(, 1) could increase the accuracy ! */ return gerepileupto(av, gdiv(gpowgs(gadd(gmul2n(h,8), real_1(prec)), 3), h)); } static GEN to_form(GEN a, GEN w, GEN C) { return mkvec3(a, w, diviiexact(C, a)); } static GEN form_to_quad(GEN f, GEN sqrtD) { long a = itos(gel(f,1)), a2 = a << 1; GEN b = gel(f,2); return mkcomplex(gdivgs(b, -a2), gdivgs(sqrtD, a2)); } static GEN eta_form(GEN f, GEN sqrtD, GEN *s_t, long prec) { GEN U, t = form_to_quad(redimagsl2(f, &U), sqrtD); *s_t = eta_correction(t, U, 0); return eta_reduced(t, prec); } /* eta(t/p)eta(t/q) / (eta(t)eta(t/pq)), t = (-w + sqrt(D)) / 2a */ GEN double_eta_quotient(GEN a, GEN w, GEN D, long p, long q, GEN pq, GEN sqrtD) { GEN C = shifti(subii(sqri(w), D), -2); GEN d, t, z, zp, zq, zpq, s_t, s_tp, s_tpq, s, sp, spq; long prec = realprec(sqrtD); z = eta_form(to_form(a, w, C), sqrtD, &s_t, prec); s = gel(s_t, 1); zp = eta_form(to_form(mului(p, a), w, C), sqrtD, &s_tp, prec); sp = gel(s_tp, 1); zpq = eta_form(to_form(mulii(pq, a), w, C), sqrtD, &s_tpq, prec); spq = gel(s_tpq, 1); if (p == q) { z = gdiv(gsqr(zp), gmul(z, zpq)); t = gsub(gmul2n(gel(s_tp,2), 1), gadd(gel(s_t,2), gel(s_tpq,2))); if (sp != gen_1) z = gmul(z, sp); } else { GEN s_tq, sq; zq = eta_form(to_form(mului(q, a), w, C), sqrtD, &s_tq, prec); sq = gel(s_tq, 1); z = gdiv(gmul(zp, zq), gmul(z, zpq)); t = gsub(gadd(gel(s_tp,2), gel(s_tq,2)), gadd(gel(s_t,2), gel(s_tpq,2))); if (sp != gen_1) z = gmul(z, gsqrt(sp, prec)); if (sq != gen_1) z = gmul(z, gsqrt(sq, prec)); } d = NULL; if (s != gen_1) d = gsqrt(s, prec); if (spq != gen_1) { GEN x = gsqrt(spq, prec); d = d? gmul(d, x): x; } if (d) z = gdiv(z, d); return gmul(z, exp_IPiQ(t, prec)); } typedef struct { GEN u; long v, t; } cxanalyze_t; /* Check whether a t_COMPLEX, t_REAL or t_INT z != 0 can be written as * z = u * 2^(v/2) * exp(I Pi/4 t), u > 0, v = 0,1 and -3 <= t <= 4. * Allow z t_INT/t_REAL to simplify handling of eta_correction() output */ static int cxanalyze(cxanalyze_t *T, GEN z) { GEN a, b; long ta, tb; T->v = 0; if (is_intreal_t(typ(z))) { T->u = mpabs_shallow(z); T->t = signe(z) < 0? 4: 0; return 1; } a = gel(z,1); ta = typ(a); b = gel(z,2); tb = typ(b); T->t = 0; if (ta == t_INT && !signe(a)) { T->u = R_abs_shallow(b); T->t = gsigne(b) < 0? -2: 2; return 1; } if (tb == t_INT && !signe(b)) { T->u = R_abs_shallow(a); T->t = gsigne(a) < 0? 4: 0; return 1; } if (ta != tb || ta == t_REAL) { T->u = z; return 0; } /* a,b both non zero, both t_INT or t_FRAC */ if (ta == t_INT) { if (!absequalii(a, b)) return 0; T->u = absi_shallow(a); T->v = 1; if (signe(a) == signe(b)) { T->t = signe(a) < 0? -3: 1; } else { T->t = signe(a) < 0? 3: -1; } } else { if (!absequalii(gel(a,2), gel(b,2)) || !absequalii(gel(a,1),gel(b,1))) return 0; T->u = absfrac_shallow(a); T->v = 1; a = gel(a,1); b = gel(b,1); if (signe(a) == signe(b)) { T->t = signe(a) < 0? -3: 1; } else { T->t = signe(a) < 0? 3: -1; } } return 1; } /* z * sqrt(st_b) / sqrt(st_a) exp(I Pi (t + t0)). Assume that * sqrt2 = gsqrt(gen_2, prec) or NULL */ static GEN apply_eta_correction(GEN z, GEN st_a, GEN st_b, GEN t0, GEN sqrt2, long prec) { GEN t, s_a = gel(st_a, 1), s_b = gel(st_b, 1); cxanalyze_t Ta, Tb; int ca, cb; t = gsub(gel(st_b,2), gel(st_a,2)); if (t0 != gen_0) t = gadd(t, t0); ca = cxanalyze(&Ta, s_a); cb = cxanalyze(&Tb, s_b); if (ca || cb) { /* compute sqrt(s_b) / sqrt(s_a) in a more efficient way: * sb = ub sqrt(2)^vb exp(i Pi/4 tb) */ GEN u = gdiv(Tb.u,Ta.u); switch(Tb.v - Ta.v) { case -1: u = gmul2n(u,-1); /* fall through: write 1/sqrt2 = sqrt2/2 */ case 1: u = gmul(u, sqrt2? sqrt2: sqrtr_abs(real2n(1, prec))); } if (!isint1(u)) z = gmul(z, gsqrt(u, prec)); t = gadd(t, gmul2n(stoi(Tb.t - Ta.t), -3)); } else { z = gmul(z, gsqrt(s_b, prec)); z = gdiv(z, gsqrt(s_a, prec)); } return gmul(z, exp_IPiQ(t, prec)); } /* sqrt(2) eta(2x) / eta(x) */ GEN weberf2(GEN x, long prec) { pari_sp av = avma; GEN z, sqrt2, a,b, Ua,Ub, st_a,st_b; x = upper_to_cx(x, &prec); a = cxredsl2(x, &Ua); b = cxredsl2(gmul2n(x,1), &Ub); if (gequal(a,b)) /* not infrequent */ z = gen_1; else z = gdiv(eta_reduced(b,prec), eta_reduced(a,prec)); st_a = eta_correction(a, Ua, 1); st_b = eta_correction(b, Ub, 1); sqrt2 = sqrtr_abs(real2n(1, prec)); z = apply_eta_correction(z, st_a, st_b, gen_0, sqrt2, prec); return gerepileupto(av, gmul(z, sqrt2)); } /* eta(x/2) / eta(x) */ GEN weberf1(GEN x, long prec) { pari_sp av = avma; GEN z, a,b, Ua,Ub, st_a,st_b; x = upper_to_cx(x, &prec); a = cxredsl2(x, &Ua); b = cxredsl2(gmul2n(x,-1), &Ub); if (gequal(a,b)) /* not infrequent */ z = gen_1; else z = gdiv(eta_reduced(b,prec), eta_reduced(a,prec)); st_a = eta_correction(a, Ua, 1); st_b = eta_correction(b, Ub, 1); z = apply_eta_correction(z, st_a, st_b, gen_0, NULL, prec); return gerepileupto(av, z); } /* exp(-I*Pi/24) * eta((x+1)/2) / eta(x) */ GEN weberf(GEN x, long prec) { pari_sp av = avma; GEN z, t0, a,b, Ua,Ub, st_a,st_b; x = upper_to_cx(x, &prec); a = cxredsl2(x, &Ua); b = cxredsl2(gmul2n(gaddgs(x,1),-1), &Ub); if (gequal(a,b)) /* not infrequent */ z = gen_1; else z = gdiv(eta_reduced(b,prec), eta_reduced(a,prec)); st_a = eta_correction(a, Ua, 1); st_b = eta_correction(b, Ub, 1); t0 = mkfrac(gen_m1, utoipos(24)); z = apply_eta_correction(z, st_a, st_b, t0, NULL, prec); if (typ(z) == t_COMPLEX && isexactzero(real_i(x))) z = gerepilecopy(av, gel(z,1)); else z = gerepileupto(av, z); return z; } GEN weber0(GEN x, long flag,long prec) { switch(flag) { case 0: return weberf(x,prec); case 1: return weberf1(x,prec); case 2: return weberf2(x,prec); default: pari_err_FLAG("weber"); } return NULL; /* LCOV_EXCL_LINE */ } /* check |q| < 1 */ static GEN check_unit_disc(const char *fun, GEN q, long prec) { GEN Q = gtofp(q, prec), Qlow; Qlow = (prec > LOWDEFAULTPREC)? gtofp(Q,LOWDEFAULTPREC): Q; if (gcmp(gnorm(Qlow), gen_1) >= 0) pari_err_DOMAIN(fun, "abs(q)", ">=", gen_1, q); return Q; } GEN theta(GEN q, GEN z, long prec) { long l, n; pari_sp av = avma, av2; GEN s, c, snz, cnz, s2z, c2z, ps, qn, y, zy, ps2, k, zold; l = precision(q); n = precision(z); if (n && n < l) l = n; if (l) prec = l; z = gtofp(z, prec); q = check_unit_disc("theta", q, prec); zold = NULL; /* gcc -Wall */ zy = imag_i(z); if (gequal0(zy)) k = gen_0; else { GEN lq = glog(q,prec); k = roundr(divrr(zy, real_i(lq))); if (signe(k)) { zold = z; z = gadd(z, mulcxmI(gmul(lq,k))); } } qn = gen_1; ps2 = gsqr(q); ps = gneg_i(ps2); gsincos(z, &s, &c, prec); s2z = gmul2n(gmul(s,c),1); /* sin 2z */ c2z = gsubgs(gmul2n(gsqr(c),1), 1); /* cos 2z */ snz = s; cnz = c; y = s; av2 = avma; for (n = 3;; n += 2) { long e; s = gadd(gmul(snz, c2z), gmul(cnz,s2z)); qn = gmul(qn,ps); y = gadd(y, gmul(qn, s)); e = gexpo(s); if (e < 0) e = 0; if (gexpo(qn) + e < -prec2nbits(prec)) break; ps = gmul(ps,ps2); c = gsub(gmul(cnz, c2z), gmul(snz,s2z)); snz = s; /* sin nz */ cnz = c; /* cos nz */ if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"theta (n = %ld)", n); gerepileall(av2, 5, &snz, &cnz, &ps, &qn, &y); } } if (signe(k)) { y = gmul(y, gmul(powgi(q,sqri(k)), gexp(gmul(mulcxI(zold),shifti(k,1)), prec))); if (mod2(k)) y = gneg_i(y); } return gerepileupto(av, gmul(y, gmul2n(gsqrt(gsqrt(q,prec),prec),1))); } GEN thetanullk(GEN q, long k, long prec) { long l, n; pari_sp av = avma; GEN p1, ps, qn, y, ps2; if (k < 0) pari_err_DOMAIN("thetanullk", "k", "<", gen_0, stoi(k)); l = precision(q); if (l) prec = l; q = check_unit_disc("thetanullk", q, prec); if (!(k&1)) { avma = av; return gen_0; } qn = gen_1; ps2 = gsqr(q); ps = gneg_i(ps2); y = gen_1; for (n = 3;; n += 2) { GEN t; qn = gmul(qn,ps); ps = gmul(ps,ps2); t = gmul(qn, powuu(n, k)); y = gadd(y, t); if (gexpo(t) < -prec2nbits(prec)) break; } p1 = gmul2n(gsqrt(gsqrt(q,prec),prec),1); if (k&2) y = gneg_i(y); return gerepileupto(av, gmul(p1, y)); } /* q2 = q^2 */ static GEN vecthetanullk_loop(GEN q2, long k, long prec) { GEN ps, qn = gen_1, y = const_vec(k, gen_1); pari_sp av = avma; const long bit = prec2nbits(prec); long i, n; if (gexpo(q2) < -2*bit) return y; ps = gneg_i(q2); for (n = 3;; n += 2) { GEN t = NULL/*-Wall*/, P = utoipos(n), N2 = sqru(n); qn = gmul(qn,ps); ps = gmul(ps,q2); for (i = 1; i <= k; i++) { t = gmul(qn, P); gel(y,i) = gadd(gel(y,i), t); P = mulii(P, N2); } if (gexpo(t) < -bit) return y; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"vecthetanullk_loop, n = %ld",n); gerepileall(av, 3, &qn, &ps, &y); } } } /* [d^i theta/dz^i(q, 0), i = 1, 3, .., 2*k - 1] */ GEN vecthetanullk(GEN q, long k, long prec) { long i, l = precision(q); pari_sp av = avma; GEN p1, y; if (l) prec = l; q = check_unit_disc("vecthetanullk", q, prec); y = vecthetanullk_loop(gsqr(q), k, prec); p1 = gmul2n(gsqrt(gsqrt(q,prec),prec),1); for (i = 2; i <= k; i+=2) gel(y,i) = gneg_i(gel(y,i)); return gerepileupto(av, gmul(p1, y)); } /* [d^i theta/dz^i(q, 0), i = 1, 3, .., 2*k - 1], q = exp(2iPi tau) */ GEN vecthetanullk_tau(GEN tau, long k, long prec) { long i, l = precision(tau); pari_sp av = avma; GEN p1, q4, y; if (l) prec = l; if (typ(tau) != t_COMPLEX || gsigne(gel(tau,2)) <= 0) pari_err_DOMAIN("vecthetanullk_tau", "imag(tau)", "<=", gen_0, tau); q4 = expIxy(Pi2n(-1, prec), tau, prec); /* q^(1/4) */ y = vecthetanullk_loop(gpowgs(q4,8), k, prec); p1 = gmul2n(q4,1); for (i = 2; i <= k; i+=2) gel(y,i) = gneg_i(gel(y,i)); return gerepileupto(av, gmul(p1, y)); } /* Return E_k(tau). Slow if tau is not in standard fundamental domain */ GEN cxEk(GEN tau, long k, long prec) { pari_sp av; GEN q, y, qn; long n, b, l = precision(tau); if (l) prec = l; b = bit_accuracy(prec); /* sum n^(k-1) x^n <= x(1 + (k!-1)x) / (1-x)^k (cf Eulerian polynomials) * S = \sum_{n > 0} n^(k-1) |q^n/(1-q^n)| <= x(1+(k!-1)x) / (1-x)^(k+1), * where x = |q| = exp(-2Pi Im(tau)) < 1. Neglegt 2/zeta(1-k) * S if * (2Pi)^k/(k-1)! x < 2^(-b-1) and k! x < 1. Use log2((2Pi)^k/(k-1)!) < 10 */ if (gcmpgs(imag_i(tau), (M_LN2 / M_PI) * (b+1+10)) > 0) return real_1(prec); q = expIxy(Pi2n(1, prec), tau, prec); q = cxtoreal(q); if (k == 2) { /* -theta^(3)(tau/2) / theta^(1)(tau/2). Assume that Im tau > 0 */ y = vecthetanullk_loop(q, 3, prec); return gdiv(gel(y,2), gel(y,1)); } av = avma; y = gen_0; qn = gen_1; for(n = 1;; n++) { /* compute y := sum_{n>0} n^(k-1) q^n / (1-q^n) */ GEN p1; qn = gmul(q,qn); p1 = gdiv(gmul(powuu(n,k-1),qn), gsubsg(1,qn)); if (gequal0(p1) || gexpo(p1) <= - prec2nbits(prec) - 5) break; y = gadd(y, p1); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"elleisnum"); gerepileall(av, 2, &y,&qn); } } return gadd(gen_1, gmul(y, gdiv(gen_2, szeta(1-k, prec)))); } /* Lambert W function : solution x of x*exp(x)=y, using Newton. y >= 0 t_REAL. * Good for low accuracy: the precision remains constant. Not memory-clean */ static GEN mplambertW0(GEN y) { long bitprec = bit_prec(y) - 2; GEN x, tmp; x = mplog(addrs(y,1)); do { tmp = x; /* f(x) = log(x)+x-log(y), f'(x) = (1+1/x) * x *= (1-log(x/y))/(x+1) */ x = mulrr(x, divrr(subsr(1, mplog(divrr(x,y))), addrs(x,1))); } while (expo(tmp) - expo(subrr(x,tmp)) < bitprec); return x; } /* Lambert W function using Newton, increasing prec */ GEN mplambertW(GEN y) { pari_sp av = avma; GEN x; long p = 1, s = signe(y); ulong mask = quadratic_prec_mask(realprec(y)-1); if (s<0) pari_err_DOMAIN("Lw", "y", "<", gen_0, y); if(s==0) return rcopy(y); x = mplambertW0(rtor(y, LOWDEFAULTPREC)); while (mask!=1) { p <<= 1; if (mask & 1) p--; mask >>= 1; x = rtor(x, p+2); x = mulrr(x, divrr(subsr(1, mplog(divrr(x,y))),addrs(x,1))); } return gerepileuptoleaf(av,x); } /* exp(t (1 + O(t^n))), n >= 1 */ static GEN serexp0(long v, long n) { GEN y = cgetg(n+3, t_SER), t; long i; y[1] = evalsigne(1) | evalvarn(v) | evalvalp(0); gel(y,2) = gel(y,3) = gen_1; t = gen_2; for (i = 2; i < n; i++, t = muliu(t,i)) gel(y,i+2) = mkfrac(gen_1,t); gel(y,i+2) = mkfrac(gen_1,t); return y; } static GEN reverse(GEN y) { GEN z = ser2rfrac_i(y); long l = lg(z); return RgX_to_ser(RgXn_reverse(z, l-2), l); } static GEN serlambertW(GEN y, long prec) { GEN x, t, y0; long n, l, vy, val, v; if (!signe(y)) return gcopy(y); v = valp(y); vy = varn(y); n = lg(y)-3; y0 = gel(y,2); for (val = 1; val < n; val++) if (!gequal0(polcoeff0(y, val, vy))) break; if (v < 0) pari_err_DOMAIN("lambertw","valuation", "<", gen_0, y); if (val >= n) { if (v) return zeroser(vy, n); x = glambertW(y0,prec); return scalarser(x, vy, n+1); } l = 3 + n/val; if (v) { t = serexp0(vy, l-3); setvalp(t, 1); /* t exp(t) */ t = reverse(t); } else { y = serchop0(y); x = glambertW(y0, prec); /* (x + t) exp(x + t) = (y0 + t y0/x) * exp(t) */ t = gmul(deg1pol_shallow(gdiv(y0,x), y0, vy), serexp0(vy, l-3)); t = gadd(x, reverse(serchop0(t))); } t = gsubst(t, vy, y); return normalize(t); } GEN glambertW(GEN y, long prec) { pari_sp av; GEN z; switch(typ(y)) { case t_REAL: return mplambertW(y); case t_COMPLEX: pari_err_IMPL("lambert(t_COMPLEX)"); default: av = avma; if (!(z = toser_i(y))) break; return gerepileupto(av, serlambertW(z, prec)); } return trans_eval("lambert",glambertW,y,prec); } #if 0 /* Another Lambert-like function: solution of exp(x)/x=y, y >= e t_REAL, * using Newton with constant prec. Good for low accuracy */ GEN mplambertX(GEN y) { long bitprec = bit_prec(y)-2; GEN tmp, x = mplog(y); if (typ(x) != t_REAL || signe(subrs(x,1))<0) pari_err(e_MISC,"Lx : argument less than e"); do { tmp = x; /* f(x)=x-log(xy), f'(x)=1-1/x */ /* x *= (log(x*y)-1)/(x-1) */ x = mulrr(x, divrr(subrs(mplog(mulrr(x,y)),1), subrs(x,1))); } while(expo(tmp)-expo(subrr(x,tmp)) < bitprec); return x; } #endif pari-2.11.2/src/basemath/galconj.c0000644000175000017500000023621413326135265015330 0ustar billbill/* Copyright (C) 2000-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*************************************************************************/ /** **/ /** GALOIS CONJUGATES **/ /** **/ /*************************************************************************/ static int is2sparse(GEN x) { long i, l = lg(x); if (odd(l-3)) return 0; for(i=3; i 1) { GEN T = real_1(prec); for (i = r1+1; i < n; i++) { GEN zi = gel(z,i), a = gel(zi,1), b = gel(zi,2); for (j = i+1; j <= n; j++) { GEN zj = gel(z,j), c = gel(zj,1), d = gel(zj,2); GEN f = gsqr(gsub(a,c)), g = gsqr(gsub(b,d)), h = gsqr(gadd(b,d)); T = gmul(T, gmul(gadd(f,g), gadd(f,h))); } } t = gmul(t, T); } t = gsqr(t); if (odd(r2)) t = gneg(t); return gerepileupto(av, t); } /* Compute bound for the coefficients of automorphisms. * T a ZX, dn a t_INT denominator or NULL */ GEN initgaloisborne(GEN T, GEN dn, long prec, GEN *ptL, GEN *ptprep, GEN *ptdis) { GEN L, prep, den, nf, r; pari_timer ti; if (DEBUGLEVEL>=4) timer_start(&ti); T = get_nfpol(T, &nf); r = nf ? nf_get_roots(nf) : NULL; if (nf && precision(gel(r, 1)) >= prec) L = embed_roots(r, nf_get_r1(nf)); else L = QX_complex_roots(T, prec); if (DEBUGLEVEL>=4) timer_printf(&ti,"roots"); prep = vandermondeinverseprep(L); if (!dn) { GEN dis, res = RgV_prod(gabs(prep,prec)); /*Add +1 to cater for accuracy error in res */ dis = ZX_disc_all(T, 1+expi(ceil_safe(res))); den = indexpartial(T,dis); if (ptdis) *ptdis = dis; } else { if (typ(dn) != t_INT || signe(dn) <= 0) pari_err_TYPE("initgaloisborne [incorrect denominator]", dn); den = dn; } if (ptprep) *ptprep = prep; *ptL = L; return den; } /* ||| M ||| with respect to || x ||_oo, M t_MAT */ GEN matrixnorm(GEN M, long prec) { long i,j,m, l = lg(M); GEN B = real_0(prec); if (l == 1) return B; m = lgcols(M); for (i = 1; i < m; i++) { GEN z = gabs(gcoeff(M,i,1), prec); for (j = 2; j < l; j++) z = gadd(z, gabs(gcoeff(M,i,j), prec)); if (gcmp(z, B) > 0) B = z; } return B; } static GEN galoisborne(GEN T, GEN dn, struct galois_borne *gb, long d) { pari_sp ltop, av2; GEN borne, borneroots, bornetrace, borneabs; long prec; GEN L, M, prep, den; pari_timer ti; const long step=3; prec = nbits2prec(bit_accuracy(ZX_max_lg(T))); den = initgaloisborne(T,dn,prec, &L,&prep,NULL); if (!dn) dn = den; ltop = avma; if (DEBUGLEVEL>=4) timer_start(&ti); M = vandermondeinverse(L, RgX_gtofp(T, prec), den, prep); if (DEBUGLEVEL>=4) timer_printf(&ti,"vandermondeinverse"); borne = matrixnorm(M, prec); borneroots = gsupnorm(L, prec); /*t_REAL*/ bornetrace = gmulsg((2*step)*degpol(T)/d, powru(borneroots, minss(degpol(T), step))); borneroots = ceil_safe(gmul(borne, borneroots)); borneabs = ceil_safe(gmax_shallow(gmul(borne, bornetrace), powru(bornetrace, d))); av2 = avma; /*We use d-1 test, so we must overlift to 2^BITS_IN_LONG*/ gb->valsol = logint(shifti(borneroots,2+BITS_IN_LONG), gb->l) + 1; gb->valabs = logint(shifti(borneabs,2), gb->l) + 1; gb->valabs = maxss(gb->valsol, gb->valabs); if (DEBUGLEVEL >= 4) err_printf("GaloisConj: val1=%ld val2=%ld\n", gb->valsol, gb->valabs); avma = av2; gb->bornesol = gerepileuptoint(ltop, shifti(borneroots,1)); if (DEBUGLEVEL >= 9) err_printf("GaloisConj: Bound %Ps\n",borneroots); gb->ladicsol = powiu(gb->l, gb->valsol); gb->ladicabs = powiu(gb->l, gb->valabs); return dn; } static GEN makeLden(GEN L,GEN den, struct galois_borne *gb) { return FpC_Fp_mul(L, den, gb->ladicsol); } /* Initialize the galois_lift structure */ static void initlift(GEN T, GEN den, GEN p, GEN L, GEN Lden, struct galois_borne *gb, struct galois_lift *gl) { pari_sp av = avma; long e; gl->gb = gb; gl->T = T; gl->den = is_pm1(den)? gen_1: den; gl->p = p; gl->L = L; gl->Lden = Lden; e = logint(shifti(gb->bornesol, 2+BITS_IN_LONG),p) + 1; avma = av; if (e < 2) e = 2; gl->e = e; gl->Q = powiu(p, e); gl->TQ = FpX_red(T,gl->Q); } /* Check whether f is (with high probability) a solution and compute its * permutation */ static int poltopermtest(GEN f, struct galois_lift *gl, GEN pf) { pari_sp av; GEN fx, fp, B = gl->gb->bornesol; long i, j, ll; for (i = 2; i < lg(f); i++) if (abscmpii(gel(f,i),B) > 0) { if (DEBUGLEVEL>=4) err_printf("GaloisConj: Solution too large.\n"); if (DEBUGLEVEL>=8) err_printf("f=%Ps\n borne=%Ps\n",f,B); return 0; } ll = lg(gl->L); fp = const_vecsmall(ll-1, 1); /* left on stack */ av = avma; for (i = 1; i < ll; i++, avma = av) { fx = FpX_eval(f, gel(gl->L,i), gl->gb->ladicsol); for (j = 1; j < ll; j++) if (fp[j] && equalii(fx, gel(gl->Lden,j))) { pf[i]=j; fp[j]=0; break; } if (j == ll) return 0; } return 1; } struct monoratlift { struct galois_lift *gl; GEN frob; long early; }; static int monoratlift(void *E, GEN S, GEN q) { struct monoratlift *d = (struct monoratlift *) E; struct galois_lift *gl = d->gl; GEN qm1old = sqrti(shifti(q,-2)); GEN tlift = FpX_ratlift(S,q,qm1old,qm1old,gl->den); if (tlift) { pari_sp ltop = avma; if(DEBUGLEVEL>=4) err_printf("MonomorphismLift: trying early solution %Ps\n",tlift); if (gl->den != gen_1) { GEN N = gl->gb->ladicsol, N2 = shifti(N,-1); tlift = FpX_center_i(FpX_red(Q_muli_to_int(tlift, gl->den), N), N,N2); } if (poltopermtest(tlift, gl, d->frob)) { if(DEBUGLEVEL>=4) err_printf("MonomorphismLift: true early solution.\n"); d->early = 1; avma = ltop; return 1; } avma = ltop; if(DEBUGLEVEL>=4) err_printf("MonomorphismLift: false early solution.\n"); } return 0; } static GEN monomorphismratlift(GEN P, GEN S, struct galois_lift *gl, GEN frob) { pari_timer ti; if (DEBUGLEVEL >= 1) timer_start(&ti); if (frob) { struct monoratlift d; d.gl = gl; d.frob = frob; d.early = 0; S = ZpX_ZpXQ_liftroot_ea(P,S,gl->T,gl->p, gl->e, (void*)&d, monoratlift); S = d.early ? NULL: S; } else S = ZpX_ZpXQ_liftroot(P,S,gl->T,gl->p, gl->e); if (DEBUGLEVEL >= 1) timer_printf(&ti, "monomorphismlift()"); return S; } /* Let T be a polynomial in Z[X] , p a prime number, S in Fp[X]/(T) so * that T(S)=0 [p,T]. Lift S in S_0 so that T(S_0)=0 [T,p^e] * Unclean stack */ static GEN automorphismlift(GEN S, struct galois_lift *gl, GEN frob) { return monomorphismratlift(gl->T, S, gl, frob); } static GEN galoisdolift(struct galois_lift *gl, GEN frob) { pari_sp av = avma; GEN Tp = FpX_red(gl->T, gl->p); GEN S = FpX_Frobenius(Tp, gl->p); return gerepileupto(av, automorphismlift(S, gl, frob)); } static void inittestlift(GEN plift, GEN Tmod, struct galois_lift *gl, struct galois_testlift *gt) { pari_timer ti; gt->n = lg(gl->L) - 1; gt->g = lg(Tmod) - 1; gt->f = gt->n / gt->g; gt->bezoutcoeff = bezout_lift_fact(gl->T, Tmod, gl->p, gl->e); if (DEBUGLEVEL >= 2) timer_start(&ti); gt->pauto = FpXQ_autpowers(plift, gt->f-1, gl->TQ, gl->Q); if (DEBUGLEVEL >= 2) timer_printf(&ti, "Frobenius power"); } /* Explanation of the intheadlong technique: * Let C be a bound, B = BITS_IN_LONG, M > C*2^B a modulus and 0 <= a_i < M for * i=1,...,n where n < 2^B. We want to test if there exist k,l, |k| < C < M/2^B, * such that sum a_i = k + l*M * We write a_i*2^B/M = b_i+c_i with b_i integer and 0<=c_i<1, so that * sum b_i - l*2^B = k*2^B/M - sum c_i * Since -1 < k*2^B/M < 1 and 0<=c_i<1, it follows that * -n-1 < sum b_i - l*2^B < 1 i.e. -n <= sum b_i -l*2^B <= 0 * So we compute z = - sum b_i [mod 2^B] and check if 0 <= z <= n. */ /* Assume 0 <= x < mod. */ static ulong intheadlong(GEN x, GEN mod) { pari_sp av = avma; long res = (long) itou(divii(shifti(x,BITS_IN_LONG),mod)); avma = av; return res; } static GEN vecheadlong(GEN W, GEN mod) { long i, l = lg(W); GEN V = cgetg(l, t_VECSMALL); for(i=1; in+2)? intheadlong(gel(P,n+2),mod): 0; } #define headlongisint(Z,N) (-(ulong)(Z)<=(ulong)(N)) static long frobeniusliftall(GEN sg, long el, GEN *psi, struct galois_lift *gl, struct galois_testlift *gt, GEN frob) { pari_sp av, ltop2, ltop = avma; long i,j,k, c = lg(sg)-1, n = lg(gl->L)-1, m = gt->g, d = m / c; GEN pf, u, v, C, Cd, SG, cache; long N1, N2, R1, Ni, ord = gt->f, c_idx = gt->g-1; ulong headcache; long hop = 0; GEN NN, NQ; pari_timer ti; *psi = pf = cgetg(m, t_VECSMALL); ltop2 = avma; NN = diviiexact(mpfact(m), mului(c, powiu(mpfact(d), c))); if (DEBUGLEVEL >= 4) err_printf("GaloisConj: I will try %Ps permutations\n", NN); N1=10000000; NQ=divis_rem(NN,N1,&R1); if (abscmpiu(NQ,1000000000)>0) { pari_warn(warner,"Combinatorics too hard : would need %Ps tests!\n" "I will skip it, but it may induce an infinite loop",NN); avma = ltop; *psi = NULL; return 0; } N2=itos(NQ); if(!N2) N1=R1; if (DEBUGLEVEL>=4) timer_start(&ti); avma = ltop2; C = gt->C; Cd= gt->Cd; v = FpXQ_mul(gel(gt->pauto, 1+el%ord), gel(gt->bezoutcoeff, m),gl->TQ,gl->Q); if (gl->den != gen_1) v = FpX_Fp_mul(v, gl->den, gl->Q); SG = cgetg(lg(sg),t_VECSMALL); for(i=1; iQ); headcache = polheadlong(v,2,gl->Q); for (i = 1; i < m; i++) pf[i] = 1 + i/d; av = avma; for (Ni = 0, i = 0; ;i++) { for (j = c_idx ; j > 0; j--) { long h = SG[pf[j]]; if (!mael(C,h,j)) { pari_sp av3 = avma; GEN r = FpXQ_mul(gel(gt->pauto,h), gel(gt->bezoutcoeff,j),gl->TQ,gl->Q); if (gl->den != gen_1) r = FpX_Fp_mul(r, gl->den, gl->Q); gmael(C,h,j) = gclone(r); mael(Cd,h,j) = polheadlong(r,1,gl->Q); avma = av3; } uel(cache,j) = uel(cache,j+1)+umael(Cd,h,j); } if (headlongisint(uel(cache,1),n)) { ulong head = headcache; for (j = 1; j < m; j++) head += polheadlong(gmael(C,SG[pf[j]],j),2,gl->Q); if (headlongisint(head,n)) { u = v; for (j = 1; j < m; j++) u = ZX_add(u, gmael(C,SG[pf[j]],j)); u = FpX_center_i(FpX_red(u, gl->Q), gl->Q, shifti(gl->Q,-1)); if (poltopermtest(u, gl, frob)) { if (DEBUGLEVEL >= 4) { timer_printf(&ti, ""); err_printf("GaloisConj: %d hops on %Ps tests\n",hop,addis(mulss(Ni,N1),i)); } avma = ltop2; return 1; } if (DEBUGLEVEL >= 4) err_printf("M"); } else hop++; } if (DEBUGLEVEL >= 4 && i % maxss(N1/20, 1) == 0) timer_printf(&ti, "GaloisConj:Testing %Ps", addis(mulss(Ni,N1),i)); avma = av; if (i == N1-1) { if (Ni==N2-1) N1 = R1; if (Ni==N2) break; Ni++; i = 0; if (DEBUGLEVEL>=4) timer_start(&ti); } for (j = 2; j < m && pf[j-1] >= pf[j]; j++) /*empty*/; /* to kill clang Warning */ for (k = 1; k < j-k && pf[k] != pf[j-k]; k++) { lswap(pf[k], pf[j-k]); } for (k = j - 1; pf[k] >= pf[j]; k--) /*empty*/; lswap(pf[j], pf[k]); c_idx = j; } if (DEBUGLEVEL>=4) err_printf("GaloisConj: not found, %d hops \n",hop); *psi = NULL; avma = ltop; return 0; } /* Compute the test matrix for the i-th line of V. Clone. */ static GEN Vmatrix(long i, struct galois_test *td) { pari_sp av = avma; GEN m = gclone( matheadlong(FpC_FpV_mul(td->L, row(td->M,i), td->ladic), td->ladic)); avma = av; return m; } /* Initialize galois_test */ static void inittest(GEN L, GEN M, GEN borne, GEN ladic, struct galois_test *td) { long i, n = lg(L)-1; GEN p = cgetg(n+1, t_VECSMALL); if (DEBUGLEVEL >= 8) err_printf("GaloisConj: Init Test\n"); td->order = p; for (i = 1; i <= n-2; i++) p[i] = i+2; p[n-1] = 1; p[n] = 2; td->borne = borne; td->lborne = subii(ladic, borne); td->ladic = ladic; td->L = L; td->M = M; td->TM = shallowtrans(M); td->PV = zero_zv(n); gel(td->PV, 2) = Vmatrix(2, td); } /* Free clones stored inside galois_test */ static void freetest(struct galois_test *td) { long i; for (i = 1; i < lg(td->PV); i++) if (td->PV[i]) { gunclone(gel(td->PV,i)); td->PV[i] = 0; } } /* Check if the integer P seen as a p-adic number is close to an integer less * than td->borne in absolute value */ static long padicisint(GEN P, struct galois_test *td) { pari_sp ltop = avma; GEN U = modii(P, td->ladic); long r = cmpii(U, td->borne) <= 0 || cmpii(U, td->lborne) >= 0; avma = ltop; return r; } /* Check if the permutation pf is valid according to td. * If not, update td to make subsequent test faster (hopefully) */ static long galois_test_perm(struct galois_test *td, GEN pf) { pari_sp av = avma; long i, j, n = lg(td->L)-1; GEN V, P = NULL; for (i = 1; i < n; i++) { long ord = td->order[i]; GEN PW = gel(td->PV, ord); if (PW) { ulong head = umael(PW,1,pf[1]); for (j = 2; j <= n; j++) head += umael(PW,j,pf[j]); if (!headlongisint(head,n)) break; } else { if (!P) P = vecpermute(td->L, pf); V = FpV_dotproduct(gel(td->TM,ord), P, td->ladic); if (!padicisint(V, td)) { gel(td->PV, ord) = Vmatrix(ord, td); if (DEBUGLEVEL >= 4) err_printf("M"); break; } } } if (i == n) { avma = av; return 1; } if (DEBUGLEVEL >= 4) err_printf("%d.", i); if (i > 1) { long z = td->order[i]; for (j = i; j > 1; j--) td->order[j] = td->order[j-1]; td->order[1] = z; if (DEBUGLEVEL >= 8) err_printf("%Ps", td->order); } avma = av; return 0; } /*Compute a*b/c when a*b will overflow*/ static long muldiv(long a,long b,long c) { return (long)((double)a*(double)b/c); } /* F = cycle decomposition of sigma, * B = cycle decomposition of cl(tau). * Check all permutations pf who can possibly correspond to tau, such that * tau*sigma*tau^-1 = sigma^s and tau^d = sigma^t, where d = ord cl(tau) * x: vector of choices, * G: vector allowing linear access to elts of F. * Choices multiple of e are not changed. */ static GEN testpermutation(GEN F, GEN B, GEN x, long s, long e, long cut, struct galois_test *td) { pari_sp av, avm = avma; long a, b, c, d, n, p1, p2, p3, p4, p5, p6, l1, l2, N1, N2, R1; long i, j, cx, hop = 0, start = 0; GEN pf, ar, G, W, NN, NQ; pari_timer ti; if (DEBUGLEVEL >= 1) timer_start(&ti); a = lg(F)-1; b = lg(gel(F,1))-1; c = lg(B)-1; d = lg(gel(B,1))-1; n = a*b; s = (b+s) % b; pf = cgetg(n+1, t_VECSMALL); av = avma; ar = cgetg(a+2, t_VECSMALL); ar[a+1]=0; G = cgetg(a+1, t_VECSMALL); W = gel(td->PV, td->order[n]); for (cx=1, i=1, j=1; cx <= a; cx++, i++) { gel(G,cx) = gel(F, coeff(B,i,j)); if (i == d) { i = 0; j++; } } NN = divis(powuu(b, c * (d - d/e)), cut); if (DEBUGLEVEL>=4) err_printf("GaloisConj: I will try %Ps permutations\n", NN); N1 = 1000000; NQ = divis_rem(NN,N1,&R1); if (abscmpiu(NQ,100000000)>0) { avma = avm; pari_warn(warner,"Combinatorics too hard: would need %Ps tests!\n" "I'll skip it but you will get a partial result...",NN); return identity_perm(n); } N2 = itos(NQ); for (l2 = 0; l2 <= N2; l2++) { long nbiter = (l2= 2 && N2) err_printf("%d%% ", muldiv(l2,100,N2)); for (l1 = 0; l1 < nbiter; l1++) { if (start) { for (i=1, j=e; i < a;) { if ((++(x[i])) != b) break; x[i++] = 0; if (i == j) { i++; j += e; } } } else { start=1; i = a-1; } /* intheadlong test: overflow in + is OK, we compute mod 2^BIL */ for (p1 = i+1, p5 = p1%d - 1 ; p1 >= 1; p1--, p5--) /* p5 = (p1%d) - 1 */ { GEN G1, G6; ulong V = 0; if (p5 == - 1) { p5 = d - 1; p6 = p1 + 1 - d; } else p6 = p1 + 1; G1 = gel(G,p1); G6 = gel(G,p6); p4 = p5 ? x[p1-1] : 0; for (p2 = 1+p4, p3 = 1 + x[p1]; p2 <= b; p2++) { V += umael(W,uel(G6,p3),uel(G1,p2)); p3 += s; if (p3 > b) p3 -= b; } p3 = 1 + x[p1] - s; if (p3 <= 0) p3 += b; for (p2 = p4; p2 >= 1; p2--) { V += umael(W,uel(G6,p3),uel(G1,p2)); p3 -= s; if (p3 <= 0) p3 += b; } uel(ar,p1) = uel(ar,p1+1) + V; } if (!headlongisint(uel(ar,1),n)) continue; /* intheadlong succeeds. Full computation */ for (p1=1, p5=d; p1 <= a; p1++, p5++) { if (p5 == d) { p5 = 0; p4 = 0; } else p4 = x[p1-1]; if (p5 == d-1) p6 = p1+1-d; else p6 = p1+1; for (p2 = 1+p4, p3 = 1 + x[p1]; p2 <= b; p2++) { pf[mael(G,p1,p2)] = mael(G,p6,p3); p3 += s; if (p3 > b) p3 -= b; } p3 = 1 + x[p1] - s; if (p3 <= 0) p3 += b; for (p2 = p4; p2 >= 1; p2--) { pf[mael(G,p1,p2)] = mael(G,p6,p3); p3 -= s; if (p3 <= 0) p3 += b; } } if (galois_test_perm(td, pf)) { if (DEBUGLEVEL >= 1) { GEN nb = addis(mulss(l2,N1),l1); timer_printf(&ti, "testpermutation(%Ps)", nb); if (DEBUGLEVEL >= 2 && hop) err_printf("GaloisConj: %d hop over %Ps iterations\n", hop, nb); } avma = av; return pf; } hop++; } } if (DEBUGLEVEL >= 1) { timer_printf(&ti, "testpermutation(%Ps)", NN); if (DEBUGLEVEL >= 2 && hop) err_printf("GaloisConj: %d hop over %Ps iterations\n", hop, NN); } avma = avm; return NULL; } /* List of subgroups of (Z/mZ)^* whose order divide o, and return the list * of their elements, sorted by increasing order */ static GEN listznstarelts(long m, long o) { pari_sp av = avma; GEN L, zn, zns; long i, phi, ind, l; if (m == 2) retmkvec(mkvecsmall(1)); zn = znstar(stoi(m)); phi = itos(gel(zn,1)); o = ugcd(o, phi); /* do we impose this on input ? */ zns = znstar_small(zn); L = cgetg(o+1, t_VEC); for (i=1,ind = phi; ind; ind -= phi/o, i++) /* by *decreasing* exact index */ gel(L,i) = subgrouplist(gel(zn,2), mkvec(utoipos(ind))); L = shallowconcat1(L); l = lg(L); for (i = 1; i < l; i++) gel(L,i) = znstar_hnf_elts(zns, gel(L,i)); return gerepilecopy(av, L); } /* A sympol is a symmetric polynomial * * Currently sympol are couple of t_VECSMALL [v,w] * v[1]...v[k], w[1]...w[k] represent the polynomial sum(i=1,k,v[i]*s_w[i]) * where s_i(X_1,...,X_n) = sum(j=1,n,X_j^i) */ /*Return s_e*/ static GEN sympol_eval_newtonsum(long e, GEN O, GEN mod) { long f = lg(O), g = lg(gel(O,1)), i, j; GEN PL = cgetg(f, t_COL); for(i=1; i 1) f = FpX_FpXQV_eval(f,pows,Tp,p); for(j=1; j=4) err_printf("FixedField: Weight: %Ps\n",W); for (i=0; i=6) err_printf("FixedField: Sym: %Ps\n",sym); L = sympol_eval(sym,NS); if (!vec_is1to1(FpC_red(L,l))) { avma = av; continue; } P = FpX_center_i(FpV_roots_to_pol(L,mod,v),mod,mod2); if (!p || FpX_is_squarefree(P,p)) return mkvec3(mkvec2(sym,W),L,P); avma = av; } return NULL; } /*Check whether the line of NS are pair-wise distinct.*/ static long sympol_is1to1_lg(GEN NS, long n) { long i, j, k, l = lgcols(NS); for (i=1; i=n) return 0; } return 1; } /* Let O a set of orbits of roots (see fixedfieldorbits) modulo mod, * l | mod and p two prime numbers. Return a vector [sym,s,P] where: * sym is a sympol, s is the set of images of sym on O and * P is the polynomial with roots s. */ static GEN fixedfieldsympol(GEN O, GEN mod, GEN l, GEN p, long v) { pari_sp ltop=avma; const long n=(BITS_IN_LONG>>1)-1; GEN NS = cgetg(n+1,t_MAT), sym = NULL, W = cgetg(n+1,t_VECSMALL); long i, e=1; if (DEBUGLEVEL>=4) err_printf("FixedField: Size: %ldx%ld\n",lg(O)-1,lg(gel(O,1))-1); for (i=1; !sym && i<=n; i++) { GEN L = sympol_eval_newtonsum(e++, O, mod); if (lg(O)>2) while (vec_isconst(L)) L = sympol_eval_newtonsum(e++, O, mod); W[i] = e-1; gel(NS,i) = L; if (sympol_is1to1_lg(NS,i+1)) sym = fixedfieldsurmer(mod,l,p,v,NS,vecsmall_shorten(W,i)); } if (!sym) pari_err_BUG("fixedfieldsympol [p too small]"); if (DEBUGLEVEL>=2) err_printf("FixedField: Found: %Ps\n",gel(sym,1)); return gerepilecopy(ltop,sym); } /* Let O a set of orbits as indices and L the corresponding roots. * Return the set of orbits as roots. */ static GEN fixedfieldorbits(GEN O, GEN L) { GEN S = cgetg(lg(O), t_MAT); long i; for (i = 1; i < lg(O); i++) gel(S,i) = vecpermute(L, gel(O,i)); return S; } static GEN fixedfieldinclusion(GEN O, GEN PL) { long i, j, f = lg(O)-1, g = lg(gel(O,1))-1; GEN S = cgetg(f*g + 1, t_COL); for (i = 1; i <= f; i++) { GEN Oi = gel(O,i); for (j = 1; j <= g; j++) gel(S, Oi[j]) = gel(PL, i); } return S; } /* Polynomial attached to a vector of conjugates. Not stack clean */ static GEN vectopol(GEN v, GEN M, GEN den , GEN mod, GEN mod2, long x) { long l = lg(v)+1, i; GEN z = cgetg(l,t_POL); z[1] = evalsigne(1)|evalvarn(x); for (i=2; i=6) err_printf("%d ",i); gel(aut,i) = permtopol(gel(res,i), L, M, den, mod, mod2, v); } return aut; } static void notgalois(long p, struct galois_analysis *ga) { if (DEBUGLEVEL >= 2) err_printf("GaloisAnalysis:non Galois for p=%ld\n", p); ga->p = p; ga->deg = 0; } /*Gather information about the group*/ static long init_group(long n, long np, GEN Fp, GEN Fe, long *porder) { const long prim_nonwss_orders[] = { 36,48,56,60,75,80,196,200 }; long i, phi_order = 1, order = 1, group = 0; /* non-WSS groups of this order? */ for (i=0; i < (long)numberof(prim_nonwss_orders); i++) if (n % prim_nonwss_orders[i] == 0) { group |= ga_non_wss; break; } if (np == 2 && Fp[2] == 3 && Fe[2] == 1 && Fe[1] > 2) group |= ga_ext_2; for (i = np; i > 0; i--) { long p = Fp[i]; if (phi_order % p == 0) { group |= ga_all_normal; break; } order *= p; phi_order *= p-1; if (Fe[i] > 1) break; } *porder = order; return group; } /*is a "better" than b ? (if so, update karma) */ static int improves(long a, long b, long plift, long p, long n, long *karma) { if (!plift || a > b) { *karma = ugcd(p-1,n); return 1; } if (a == b) { long k = ugcd(p-1,n); if (k > *karma) { *karma = k; return 1; } } return 0; /* worse */ } /* return 0 if not galois or not wss */ static int galoisanalysis(GEN T, struct galois_analysis *ga, long calcul_l) { pari_sp ltop = avma, av; long group, linf, n, p, i, karma = 0; GEN F, Fp, Fe, Fpe, O; long np, order, plift, nbmax, nbtest, deg; pari_timer ti; forprime_t S; if (DEBUGLEVEL >= 1) timer_start(&ti); n = degpol(T); O = zero_zv(n); F = factoru_pow(n); Fp = gel(F,1); np = lg(Fp)-1; Fe = gel(F,2); Fpe= gel(F,3); group = init_group(n, np, Fp, Fe, &order); /*Now we study the orders of the Frobenius elements*/ deg = Fp[np]; /* largest prime | n */ plift = 0; nbtest = 0; nbmax = 8+(n>>1); u_forprime_init(&S, n*maxss(expu(n)-3, 2), ULONG_MAX); av = avma; while (!plift || (nbtest < nbmax && (nbtest <=8 || order < (n>>1))) || (n == 24 && O[6] == 0 && O[4] == 0) || ((group&ga_non_wss) && order == Fp[np])) { long d, o, norm_o = 1; GEN D, Tp; if ((group&ga_non_wss) && nbtest >= 3*nbmax) break; /* in all cases */ nbtest++; avma = av; p = u_forprime_next(&S); if (!p) pari_err_OVERFLOW("galoisanalysis [ran out of primes]"); Tp = ZX_to_Flx(T,p); if (!Flx_is_squarefree(Tp,p)) { if (!--nbtest) nbtest = 1; continue; } D = Flx_nbfact_by_degree(Tp, &d, p); o = n / d; /* d factors, all should have degree o */ if (D[o] != d) { notgalois(p, ga); avma = ltop; return 0; } if (!O[o]) O[o] = p; if (o % deg) goto ga_end; /* NB: deg > 1 */ if ((group&ga_all_normal) && o < order) goto ga_end; /*Frob_p has order o > 1, find a power which generates a normal subgroup*/ if (o * Fp[1] >= n) norm_o = o; /*subgroups of smallest index are normal*/ else { for (i = np; i > 0; i--) { if (o % Fpe[i]) break; norm_o *= Fpe[i]; } } /* Frob_p^(o/norm_o) generates a normal subgroup of order norm_o */ if (norm_o != 1) { if (!(group&ga_all_normal) || o > order) karma = ugcd(p-1,n); else if (!improves(norm_o, deg, plift,p,n, &karma)) goto ga_end; /* karma0=0, deg0<=norm_o -> the first improves() returns 1 */ deg = norm_o; group |= ga_all_normal; /* STORE */ } else if (group&ga_all_normal) goto ga_end; else if (!improves(o, order, plift,p,n, &karma)) goto ga_end; order = o; plift = p; /* STORE */ ga_end: if (DEBUGLEVEL >= 5) err_printf("GaloisAnalysis:Nbtest=%ld,p=%ld,o=%ld,n_o=%d,best p=%ld,ord=%ld,k=%ld\n", nbtest, p, o, norm_o, plift, order,karma); } /* To avoid looping on non-wss group. * TODO: check for large groups. Would it be better to disable this check if * we are in a good case (ga_all_normal && !(ga_ext_2) (e.g. 60)) ?*/ ga->p = plift; if (!plift || ((group&ga_non_wss) && order == Fp[np])) { pari_warn(warner,"Galois group almost certainly not weakly super solvable"); return 0; } linf = 2*n*usqrt(n); if (calcul_l && O[1] <= linf) { pari_sp av2; forprime_t S2; ulong p; u_forprime_init(&S2, linf+1,ULONG_MAX); av2 = avma; while ((p = u_forprime_next(&S2))) { /*find a totally split prime l > linf*/ GEN Tp = ZX_to_Flx(T, p); long nb = Flx_nbroots(Tp, p); if (nb == n) { O[1] = p; break; } if (nb && Flx_is_squarefree(Tp,p)) { notgalois(p,ga); avma = ltop; return 0; } avma = av2; } if (!p) pari_err_OVERFLOW("galoisanalysis [ran out of primes]"); } ga->group = (enum ga_code)group; ga->deg = deg; ga->mindeg = n == 135 ? 15: 0; /* otherwise the second phase is too slow */ ga->ord = order; ga->l = O[1]; ga->p4 = n >= 4 ? O[4] : 0; if (DEBUGLEVEL >= 4) err_printf("GaloisAnalysis:p=%ld l=%ld group=%ld deg=%ld ord=%ld\n", plift, O[1], group, deg, order); if (DEBUGLEVEL >= 1) timer_printf(&ti, "galoisanalysis()"); avma = ltop; return 1; } static GEN a4galoisgen(struct galois_test *td) { const long n = 12; pari_sp ltop = avma, av, av2; long i, j, k, N, hop = 0; GEN MT, O,O1,O2,O3, ar, mt, t, u, res, orb, pft, pfu, pfv; res = cgetg(3, t_VEC); pft = cgetg(n+1, t_VECSMALL); pfu = cgetg(n+1, t_VECSMALL); pfv = cgetg(n+1, t_VECSMALL); gel(res,1) = mkvec3(pft,pfu,pfv); gel(res,2) = mkvecsmall3(2,2,3); av = avma; ar = cgetg(5, t_VECSMALL); mt = gel(td->PV, td->order[n]); t = identity_perm(n) + 1; /* Sorry for this hack */ u = cgetg(n+1, t_VECSMALL) + 1; /* too lazy to correct */ MT = cgetg(n+1, t_MAT); for (j = 1; j <= n; j++) gel(MT,j) = cgetg(n+1, t_VECSMALL); for (j = 1; j <= n; j++) for (i = 1; i < j; i++) ucoeff(MT,i,j) = ucoeff(MT,j,i) = ucoeff(mt,i,j)+ucoeff(mt,j,i); /* MT(i,i) unused */ av2 = avma; /* N = itos(gdiv(mpfact(n), mpfact(n >> 1))) >> (n >> 1); */ /* n = 2k = 12; N = (2k)! / (k! * 2^k) = 10395 */ N = 10395; if (DEBUGLEVEL>=4) err_printf("A4GaloisConj: will test %ld permutations\n", N); uel(ar,4) = umael(MT,11,12); uel(ar,3) = uel(ar,4) + umael(MT,9,10); uel(ar,2) = uel(ar,3) + umael(MT,7,8); uel(ar,1) = uel(ar,2) + umael(MT,5,6); for (i = 0; i < N; i++) { long g; if (i) { long a, x = i, y = 1; do { y += 2; a = x%y; x = x/y; } while (!a); switch (y) { case 3: lswap(t[2], t[2-a]); break; case 5: x = t[0]; t[0] = t[2]; t[2] = t[1]; t[1] = x; lswap(t[4], t[4-a]); uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]); break; case 7: x = t[0]; t[0] = t[4]; t[4] = t[3]; t[3] = t[1]; t[1] = t[2]; t[2] = x; lswap(t[6], t[6-a]); uel(ar,2) = uel(ar,3) + umael(MT,t[6],t[7]); uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]); break; case 9: x = t[0]; t[0] = t[6]; t[6] = t[5]; t[5] = t[3]; t[3] = x; lswap(t[1], t[4]); lswap(t[8], t[8-a]); uel(ar,3) = uel(ar,4) + umael(MT,t[8],t[9]); uel(ar,2) = uel(ar,3) + umael(MT,t[6],t[7]); uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]); break; case 11: x = t[0]; t[0] = t[8]; t[8] = t[7]; t[7] = t[5]; t[5] = t[1]; t[1] = t[6]; t[6] = t[3]; t[3] = t[2]; t[2] = t[4]; t[4] = x; lswap(t[10], t[10-a]); uel(ar,4) = umael(MT,t[10],t[11]); uel(ar,3) = uel(ar,4) + umael(MT,t[8],t[9]); uel(ar,2) = uel(ar,3) + umael(MT,t[6],t[7]); uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]); } } g = uel(ar,1)+umael(MT,t[0],t[1])+umael(MT,t[2],t[3]); if (headlongisint(g,n)) { for (k = 0; k < n; k += 2) { pft[t[k]] = t[k+1]; pft[t[k+1]] = t[k]; } if (galois_test_perm(td, pft)) break; hop++; } avma = av2; } if (DEBUGLEVEL >= 1 && hop) err_printf("A4GaloisConj: %ld hop over %ld iterations\n", hop, N); if (i == N) { avma = ltop; return gen_0; } /* N = itos(gdiv(mpfact(n >> 1), mpfact(n >> 2))) >> 1; */ N = 60; if (DEBUGLEVEL >= 4) err_printf("A4GaloisConj: sigma=%Ps \n", pft); for (k = 0; k < n; k += 4) { u[k+3] = t[k+3]; u[k+2] = t[k+1]; u[k+1] = t[k+2]; u[k] = t[k]; } for (i = 0; i < N; i++) { ulong g = 0; if (i) { long a, x = i, y = -2; do { y += 4; a = x%y; x = x/y; } while (!a); lswap(u[0],u[2]); switch (y) { case 2: break; case 6: lswap(u[4],u[6]); if (!(a & 1)) { a = 4 - (a>>1); lswap(u[6], u[a]); lswap(u[4], u[a-2]); } break; case 10: x = u[6]; u[6] = u[3]; u[3] = u[2]; u[2] = u[4]; u[4] = u[1]; u[1] = u[0]; u[0] = x; if (a >= 3) a += 2; a = 8 - a; lswap(u[10],u[a]); lswap(u[8], u[a-2]); break; } } for (k = 0; k < n; k += 2) g += mael(MT,u[k],u[k+1]); if (headlongisint(g,n)) { for (k = 0; k < n; k += 2) { pfu[u[k]] = u[k+1]; pfu[u[k+1]] = u[k]; } if (galois_test_perm(td, pfu)) break; hop++; } avma = av2; } if (i == N) { avma = ltop; return gen_0; } if (DEBUGLEVEL >= 1 && hop) err_printf("A4GaloisConj: %ld hop over %ld iterations\n", hop, N); if (DEBUGLEVEL >= 4) err_printf("A4GaloisConj: tau=%Ps \n", pfu); avma = av2; orb = mkvec2(pft,pfu); O = vecperm_orbits(orb, 12); if (DEBUGLEVEL >= 4) { err_printf("A4GaloisConj: orb=%Ps\n", orb); err_printf("A4GaloisConj: O=%Ps \n", O); } av2 = avma; O1 = gel(O,1); O2 = gel(O,2); O3 = gel(O,3); for (j = 0; j < 2; j++) { pfv[O1[1]] = O2[1]; pfv[O1[2]] = O2[3+j]; pfv[O1[3]] = O2[4 - (j << 1)]; pfv[O1[4]] = O2[2+j]; for (i = 0; i < 4; i++) { ulong g = 0; switch (i) { case 0: break; case 1: lswap(O3[1], O3[2]); lswap(O3[3], O3[4]); break; case 2: lswap(O3[1], O3[4]); lswap(O3[2], O3[3]); break; case 3: lswap(O3[1], O3[2]); lswap(O3[3], O3[4]); break; } pfv[O2[1]] = O3[1]; pfv[O2[3+j]] = O3[4-j]; pfv[O2[4 - (j<<1)]] = O3[2 + (j<<1)]; pfv[O2[2+j]] = O3[3-j]; pfv[O3[1]] = O1[1]; pfv[O3[4-j]] = O1[2]; pfv[O3[2 + (j<<1)]] = O1[3]; pfv[O3[3-j]] = O1[4]; for (k = 1; k <= n; k++) g += mael(mt,k,pfv[k]); if (headlongisint(g,n) && galois_test_perm(td, pfv)) { avma = av; if (DEBUGLEVEL >= 1) err_printf("A4GaloisConj: %ld hop over %d iterations max\n", hop, 10395 + 68); return res; } hop++; avma = av2; } } avma = ltop; return gen_0; /* Fail */ } /* S4 */ static void s4makelift(GEN u, struct galois_lift *gl, GEN liftpow) { GEN s = automorphismlift(u, gl, NULL); long i; gel(liftpow,1) = s; for (i = 2; i < lg(liftpow); i++) gel(liftpow,i) = FpXQ_mul(gel(liftpow,i-1), s, gl->TQ, gl->Q); } static long s4test(GEN u, GEN liftpow, struct galois_lift *gl, GEN phi) { pari_sp av = avma; GEN res, Q, Q2; long bl, i, d = lg(u)-2; pari_timer ti; if (DEBUGLEVEL >= 6) timer_start(&ti); if (!d) return 0; Q = gl->Q; Q2 = shifti(Q,-1); res = gel(u,2); for (i = 1; i < d; i++) if (lg(gel(liftpow,i))>2) res = addii(res, mulii(gmael(liftpow,i,2), gel(u,i+2))); res = remii(res,Q); if (gl->den != gen_1) res = mulii(res, gl->den); res = centermodii(res, Q,Q2); if (abscmpii(res, gl->gb->bornesol) > 0) { avma = av; return 0; } res = scalar_ZX_shallow(gel(u,2),varn(u)); for (i = 1; i < d ; i++) if (lg(gel(liftpow,i))>2) res = ZX_add(res, ZX_Z_mul(gel(liftpow,i), gel(u,i+2))); res = FpX_red(res, Q); if (gl->den != gen_1) res = FpX_Fp_mul(res, gl->den, Q); res = FpX_center_i(res, Q, shifti(Q,-1)); bl = poltopermtest(res, gl, phi); if (DEBUGLEVEL >= 6) timer_printf(&ti, "s4test()"); avma = av; return bl; } static GEN aux(long a, long b, GEN T, GEN M, GEN p, GEN *pu) { *pu = FpX_mul(gel(T,b), gel(T,a),p); return FpX_chinese_coprime(gmael(M,a,b), gmael(M,b,a), gel(T,b), gel(T,a), *pu, p); } static GEN s4releveauto(GEN misom,GEN Tmod,GEN Tp,GEN p,long a1,long a2,long a3,long a4,long a5,long a6) { pari_sp av = avma; GEN u4,u5; GEN pu1, pu2, pu3, pu4; GEN u1 = aux(a1, a2, Tmod, misom, p, &pu1); GEN u2 = aux(a3, a4, Tmod, misom, p, &pu2); GEN u3 = aux(a5, a6, Tmod, misom, p, &pu3); pu4 = FpX_mul(pu1,pu2,p); u4 = FpX_chinese_coprime(u1,u2,pu1,pu2,pu4,p); u5 = FpX_chinese_coprime(u4,u3,pu4,pu3,Tp,p); return gerepileupto(av, u5); } static GEN lincomb(GEN A, GEN B, GEN pauto, long j) { long k = (-j) & 3; if (j == k) return ZX_mul(ZX_add(A,B), gel(pauto, j+1)); return ZX_add(ZX_mul(A, gel(pauto, j+1)), ZX_mul(B, gel(pauto, k+1))); } /* FIXME: could use the intheadlong technique */ static GEN s4galoisgen(struct galois_lift *gl) { const long n = 24; struct galois_testlift gt; pari_sp av, ltop2, ltop = avma; long i, j; GEN sigma, tau, phi, res, r1,r2,r3,r4, pj, p = gl->p, Q = gl->Q, TQ = gl->TQ; GEN sg, Tp, Tmod, isom, isominv, misom, Bcoeff, pauto, liftpow, aut; res = cgetg(3, t_VEC); r1 = cgetg(n+1, t_VECSMALL); r2 = cgetg(n+1, t_VECSMALL); r3 = cgetg(n+1, t_VECSMALL); r4 = cgetg(n+1, t_VECSMALL); gel(res,1)= mkvec4(r1,r2,r3,r4); gel(res,2) = mkvecsmall4(2,2,3,2); ltop2 = avma; sg = identity_perm(6); pj = zero_zv(6); sigma = cgetg(n+1, t_VECSMALL); tau = cgetg(n+1, t_VECSMALL); phi = cgetg(n+1, t_VECSMALL); Tp = FpX_red(gl->T,p); Tmod = gel(FpX_factor(Tp,p), 1); isom = cgetg(lg(Tmod), t_VEC); isominv = cgetg(lg(Tmod), t_VEC); misom = cgetg(lg(Tmod), t_MAT); aut = galoisdolift(gl, NULL); inittestlift(aut, Tmod, gl, >); Bcoeff = gt.bezoutcoeff; pauto = gt.pauto; for (i = 1; i < lg(isom); i++) { gel(misom,i) = cgetg(lg(Tmod), t_COL); gel(isom,i) = FpX_ffisom(gel(Tmod,1), gel(Tmod,i), p); if (DEBUGLEVEL >= 6) err_printf("S4GaloisConj: Computing isomorphisms %d:%Ps\n", i, gel(isom,i)); gel(isominv,i) = FpXQ_ffisom_inv(gel(isom,i), gel(Tmod,i),p); } for (i = 1; i < lg(isom); i++) for (j = 1; j < lg(isom); j++) gmael(misom,i,j) = FpX_FpXQ_eval(gel(isominv,i),gel(isom,j), gel(Tmod,j),p); liftpow = cgetg(24, t_VEC); av = avma; for (i = 0; i < 3; i++, avma = av) { pari_sp av1, av2, av3; GEN u, u1, u2, u3; long j1, j2, j3; if (i) { if (i == 1) { lswap(sg[2],sg[3]); } else { lswap(sg[1],sg[3]); } } u = s4releveauto(misom,Tmod,Tp,p,sg[1],sg[2],sg[3],sg[4],sg[5],sg[6]); s4makelift(u, gl, liftpow); av1 = avma; for (j1 = 0; j1 < 4; j1++, avma = av1) { u1 = lincomb(gel(Bcoeff,sg[5]),gel(Bcoeff,sg[6]), pauto,j1); u1 = FpX_rem(u1, TQ, Q); av2 = avma; for (j2 = 0; j2 < 4; j2++, avma = av2) { u2 = lincomb(gel(Bcoeff,sg[3]),gel(Bcoeff,sg[4]), pauto,j2); u2 = FpX_rem(FpX_add(u1, u2, Q), TQ,Q); av3 = avma; for (j3 = 0; j3 < 4; j3++, avma = av3) { u3 = lincomb(gel(Bcoeff,sg[1]),gel(Bcoeff,sg[2]), pauto,j3); u3 = FpX_rem(FpX_add(u2, u3, Q), TQ,Q); if (DEBUGLEVEL >= 4) err_printf("S4GaloisConj: Testing %d/3:%d/4:%d/4:%d/4:%Ps\n", i,j1,j2,j3, sg); if (s4test(u3, liftpow, gl, sigma)) { pj[1] = j3; pj[2] = j2; pj[3] = j1; goto suites4; } } } } } avma = ltop; return gen_0; suites4: if (DEBUGLEVEL >= 4) err_printf("S4GaloisConj: sigma=%Ps\n", sigma); if (DEBUGLEVEL >= 4) err_printf("S4GaloisConj: pj=%Ps\n", pj); avma = av; for (j = 1; j <= 3; j++) { pari_sp av2, av3; GEN u; long w, l, z; z = sg[1]; sg[1] = sg[3]; sg[3] = sg[5]; sg[5] = z; z = sg[2]; sg[2] = sg[4]; sg[4] = sg[6]; sg[6] = z; z = pj[1]; pj[1] = pj[2]; pj[2] = pj[3]; pj[3] = z; for (l = 0; l < 2; l++, avma = av) { u = s4releveauto(misom,Tmod,Tp,p,sg[1],sg[3],sg[2],sg[4],sg[5],sg[6]); s4makelift(u, gl, liftpow); av2 = avma; for (w = 0; w < 4; w += 2, avma = av2) { GEN uu; pj[6] = (w + pj[3]) & 3; uu = lincomb(gel(Bcoeff,sg[5]),gel(Bcoeff,sg[6]), pauto, pj[6]); uu = FpX_rem(FpX_red(uu,Q), TQ, Q); av3 = avma; for (i = 0; i < 4; i++, avma = av3) { GEN u; pj[4] = i; pj[5] = (i + pj[2] - pj[1]) & 3; if (DEBUGLEVEL >= 4) err_printf("S4GaloisConj: Testing %d/3:%d/2:%d/2:%d/4:%Ps:%Ps\n", j-1, w >> 1, l, i, sg, pj); u = ZX_add(lincomb(gel(Bcoeff,sg[1]),gel(Bcoeff,sg[3]), pauto,pj[4]), lincomb(gel(Bcoeff,sg[2]),gel(Bcoeff,sg[4]), pauto,pj[5])); u = FpX_rem(FpX_add(uu,u,Q), TQ, Q); if (s4test(u, liftpow, gl, tau)) goto suites4_2; } } lswap(sg[3], sg[4]); pj[2] = (-pj[2]) & 3; } } avma = ltop; return gen_0; suites4_2: avma = av; { long abc = (pj[1] + pj[2] + pj[3]) & 3; long abcdef = ((abc + pj[4] + pj[5] - pj[6]) & 3) >> 1; GEN u; pari_sp av2; u = s4releveauto(misom,Tmod,Tp,p,sg[1],sg[4],sg[2],sg[5],sg[3],sg[6]); s4makelift(u, gl, liftpow); av2 = avma; for (j = 0; j < 8; j++) { long h, g, i; h = j & 3; g = (abcdef + ((j & 4) >> 1)) & 3; i = (h + abc - g) & 3; u = ZX_add( lincomb(gel(Bcoeff,sg[1]), gel(Bcoeff,sg[4]), pauto, g), lincomb(gel(Bcoeff,sg[2]), gel(Bcoeff,sg[5]), pauto, h)); u = FpX_add(u, lincomb(gel(Bcoeff,sg[3]), gel(Bcoeff,sg[6]), pauto, i),Q); u = FpX_rem(u, TQ, Q); if (DEBUGLEVEL >= 4) err_printf("S4GaloisConj: Testing %d/8 %d:%d:%d\n", j,g,h,i); if (s4test(u, liftpow, gl, phi)) break; avma = av2; } } if (j == 8) { avma = ltop; return gen_0; } for (i = 1; i <= n; i++) { r1[i] = sigma[tau[i]]; r2[i] = phi[sigma[tau[phi[i]]]]; r3[i] = phi[sigma[i]]; r4[i] = sigma[i]; } avma = ltop2; return res; } static GEN galoisfindgroups(GEN lo, GEN sg, long f) { pari_sp ltop = avma; long i, j, k; GEN V = cgetg(lg(lo), t_VEC); for(j=1,i=1; iden != gen_1) tlift = FpX_Fp_mul(tlift, gl->den, gl->Q); tlift = FpX_center_i(tlift, gl->Q, shifti(gl->Q,-1)); res = poltopermtest(tlift, gl, frob); avma = av; return res; } static GEN galoismakepsi(long g, GEN sg, GEN pf) { GEN psi=cgetg(g+1,t_VECSMALL); long i; for (i = 1; i < g; i++) psi[i] = sg[pf[i]]; psi[g] = sg[1]; return psi; } static GEN galoisfrobeniuslift(GEN T, GEN den, GEN L, GEN Lden, struct galois_frobenius *gf, struct galois_borne *gb) { pari_sp ltop=avma, av2; struct galois_testlift gt; struct galois_lift gl; long i, j, k, n = lg(L)-1, deg = 1, g = lg(gf->Tmod)-1; GEN F,Fp,Fe, aut, frob, ip = utoipos(gf->p), res = cgetg(lg(L), t_VECSMALL); gf->psi = const_vecsmall(g,1); av2 = avma; initlift(T, den, ip, L, Lden, gb, &gl); if (DEBUGLEVEL >= 4) err_printf("GaloisConj: p=%ld e=%ld deg=%ld fp=%ld\n", gf->p, gl.e, deg, gf->fp); aut = galoisdolift(&gl, res); if (!aut || galoisfrobeniustest(aut,&gl,res)) { avma = av2; gf->deg = gf->fp; return res; } inittestlift(aut,gf->Tmod, &gl, >); gt.C = cgetg(gf->fp+1,t_VEC); gt.Cd= cgetg(gf->fp+1,t_VEC); for (i = 1; i <= gf->fp; i++) { gel(gt.C,i) = zero_zv(gt.g); gel(gt.Cd,i) = zero_zv(gt.g); } F =factoru(gf->fp); Fp = gel(F,1); Fe = gel(F,2); frob = cgetg(lg(L), t_VECSMALL); for(k=lg(Fp)-1;k>=1;k--) { pari_sp btop=avma; GEN psi=NULL, fres=NULL, sg = identity_perm(1); long el=gf->fp, dg=1, dgf=1, e, pr; for(e=1; e<=Fe[k]; e++) { GEN lo, pf; long l; dg *= Fp[k]; el /= Fp[k]; if (DEBUGLEVEL>=4) err_printf("Trying degre %d.\n",dg); if (galoisfrobeniustest(gel(gt.pauto,el+1),&gl,frob)) { psi = const_vecsmall(g,1); dgf = dg; fres = gcopy(frob); continue; } lo = listznstarelts(dg, n / gf->fp); if (e!=1) lo = galoisfindgroups(lo, sg, dgf); if (DEBUGLEVEL>=4) err_printf("Galoisconj:Subgroups list:%Ps\n", lo); for (l = 1; l < lg(lo); l++) if (lg(gel(lo,l))>2 && frobeniusliftall(gel(lo,l), el, &pf,&gl,>, frob)) { sg = gcopy(gel(lo,l)); psi = galoismakepsi(g,sg,pf); dgf = dg; fres = gcopy(frob); break; } if (l == lg(lo)) break; } if (dgf == 1) { avma = btop; continue; } pr = deg*dgf; if (deg == 1) { for(i=1;ipsi[i]=psi[i]; } else { GEN cp = perm_mul(res,fres); for(i=1;ipsi[i] = (dgf*gf->psi[i] + deg*psi[i]) % pr; } deg = pr; avma = btop; } for (i = 1; i <= gf->fp; i++) for (j = 1; j <= gt.g; j++) if (mael(gt.C,i,j)) gunclone(gmael(gt.C,i,j)); if (DEBUGLEVEL>=4 && res) err_printf("Best lift: %d\n",deg); if (deg==1) { avma = ltop; return NULL; } else { /* Normalize result so that psi[g]=1 */ long im = Fl_inv(gf->psi[g], deg); GEN cp = perm_pow(res, im); for(i=1;ipsi);i++) gf->psi[i] = Fl_mul(im, gf->psi[i], deg); avma = av2; gf->deg = deg; return res; } } /* return NULL if not Galois */ static GEN galoisfindfrobenius(GEN T, GEN L, GEN den, struct galois_frobenius *gf, struct galois_borne *gb, const struct galois_analysis *ga) { pari_sp ltop = avma, av; long Try = 0, n = degpol(T), deg, gmask = (ga->group&ga_ext_2)? 3: 1; GEN frob, Lden = makeLden(L,den,gb); forprime_t S; u_forprime_init(&S, ga->p, ULONG_MAX); av = avma; deg = gf->deg = ga->deg; while ((gf->p = u_forprime_next(&S))) { pari_sp lbot; GEN Ti, Tp; long nb, d; avma = av; Tp = ZX_to_Flx(T, gf->p); if (!Flx_is_squarefree(Tp, gf->p)) continue; Ti = gel(Flx_factor(Tp, gf->p), 1); nb = lg(Ti)-1; d = degpol(gel(Ti,1)); if (nb > 1 && degpol(gel(Ti,nb)) != d) { avma = ltop; return NULL; } if (((gmask&1)==0 || d % deg) && ((gmask&2)==0 || odd(d))) continue; if (DEBUGLEVEL >= 1) err_printf("GaloisConj: Trying p=%ld\n", gf->p); FlxV_to_ZXV_inplace(Ti); gf->fp = d; gf->Tmod = Ti; lbot = avma; frob = galoisfrobeniuslift(T, den, L, Lden, gf, gb); if (frob) { GEN *gptr[3]; if (gf->deg < ga->mindeg) { if (DEBUGLEVEL >= 4) err_printf("GaloisConj: lift degree too small %ld < %ld\n", gf->deg, ga->mindeg); continue; } gf->Tmod = gcopy(Ti); gptr[0]=&gf->Tmod; gptr[1]=&gf->psi; gptr[2]=&frob; gerepilemanysp(ltop,lbot,gptr,3); return frob; } if ((ga->group&ga_all_normal) && d % deg == 0) gmask &= ~1; /* The first prime degree is always divisible by deg, so we don't * have to worry about ext_2 being used before regular supersolvable*/ if (!gmask) { avma = ltop; return NULL; } if ((ga->group&ga_non_wss) && ++Try > ((3*n)>>1)) { pari_warn(warner,"Galois group probably not weakly super solvable"); return NULL; } } if (!gf->p) pari_err_OVERFLOW("galoisfindfrobenius [ran out of primes]"); return NULL; } /* compute g such that tau(Pmod[#])= tau(Pmod[g]) */ static long get_image(GEN tau, GEN P, GEN Pmod, GEN p) { pari_sp av = avma; long g, gp = lg(Pmod)-1; tau = RgX_to_FpX(tau, p); tau = FpX_FpXQ_eval(gel(Pmod, gp), tau, P, p); tau = FpX_normalize(FpX_gcd(P, tau, p), p); for (g = 1; g <= gp; g++) if (ZX_equal(tau, gel(Pmod,g))) { avma = av; return g; } avma = av; return 0; } static GEN galoisgen(GEN T, GEN L, GEN M, GEN den, struct galois_borne *gb, const struct galois_analysis *ga); static GEN galoisgenfixedfield(GEN Tp, GEN Pmod, GEN V, GEN ip, struct galois_borne *gb) { GEN P, PL, Pden, PM, Pp; GEN tau, PG, Pg; long g, lP; long x=varn(Tp); P=gel(V,3); PL=gel(V,2); Pp = FpX_red(P,ip); if (DEBUGLEVEL>=6) err_printf("GaloisConj: Fixed field %Ps\n",P); if (degpol(P)==2) { PG=cgetg(3,t_VEC); gel(PG,1) = mkvec( mkvecsmall2(2,1) ); gel(PG,2) = mkvecsmall(2); tau = deg1pol_shallow(gen_m1, negi(gel(P,3)), x); g = get_image(tau, Pp, Pmod, ip); if (!g) return NULL; Pg = mkvecsmall(g); } else { struct galois_analysis Pga; struct galois_borne Pgb; GEN mod, mod2; long j; if (!galoisanalysis(P, &Pga, 0)) return NULL; Pgb.l = gb->l; Pden = galoisborne(P, NULL, &Pgb, degpol(P)); if (Pgb.valabs > gb->valabs) { if (DEBUGLEVEL>=4) err_printf("GaloisConj: increase prec of p-adic roots of %ld.\n" ,Pgb.valabs-gb->valabs); PL = ZpX_liftroots(P,PL,gb->l,Pgb.valabs); } else if (Pgb.valabs < gb->valabs) PL = FpC_red(PL, Pgb.ladicabs); PM = FpV_invVandermonde(PL, Pden, Pgb.ladicabs); PG = galoisgen(P, PL, PM, Pden, &Pgb, &Pga); if (PG == gen_0) return NULL; lP = lg(gel(PG,1)); mod = Pgb.ladicabs; mod2 = shifti(mod, -1); Pg = cgetg(lP, t_VECSMALL); for (j = 1; j < lP; j++) { pari_sp btop=avma; tau = permtopol(gmael(PG,1,j), PL, PM, Pden, mod, mod2, x); g = get_image(tau, Pp, Pmod, ip); if (!g) return NULL; Pg[j] = g; avma = btop; } } return mkvec2(PG,Pg); } /* Let sigma^m=1, tau*sigma*tau^-1=sigma^s. Return n = sum_{0<=k=1; i--) { si = Fl_powu(si,e,m); w[i] = Fl_mul(s-1, stpow(si, w[i], m), m); } return w; } static GEN galoisgenliftauto(GEN O, GEN gj, long s, long n, struct galois_test *td) { pari_sp av = avma; long sr, k; long deg = lg(gel(O,1))-1; GEN X = cgetg(lg(O), t_VECSMALL); GEN oX = cgetg(lg(O), t_VECSMALL); GEN B = perm_cycles(gj); long oj = lg(gel(B,1)) - 1; GEN F = factoru(oj); GEN Fp = gel(F,1); GEN Fe = gel(F,2); GEN pf = identity_perm(n); if (DEBUGLEVEL >= 6) err_printf("GaloisConj: %Ps of relative order %d\n", gj, oj); for (k=lg(Fp)-1; k>=1; k--) { long f, dg = 1, el = oj, osel = 1, a = 0; long p = Fp[k], e = Fe[k], op = oj / upowuu(p,e); long i; GEN pf1 = NULL, w, wg, Be = cgetg(e+1,t_VEC); gel(Be,e) = cyc_pow(B, op); for(i=e-1; i>=1; i--) gel(Be,i) = cyc_pow(gel(Be,i+1), p); w = wpow(Fl_powu(s,op,deg),deg,p,e); wg = cgetg(e+2,t_VECSMALL); wg[e+1] = deg; for (i=e; i>=1; i--) wg[i] = ugcd(wg[i+1], w[i]); for (i=1; i= 6) err_printf("GaloisConj: B=%Ps\n", Bel); sr = ugcd(stpow(sel,p,deg),deg); if (DEBUGLEVEL >= 6) err_printf("GaloisConj: exp %d: s=%ld [%ld] a=%ld w=%ld wg=%ld sr=%ld\n", dg, sel, deg, a, w[f], wg[f+1], sr); for (t = 0; t < sr; t++) if ((a+t*w[f])%wg[f+1]==0) { long i, j, k, st; for (i = 1; i < lg(X); i++) X[i] = 0; for (i = 0; i < lg(X)-1; i+=dg) for (j = 1, k = p, st = t; k <= dg; j++, k += p) { X[k+i] = (oX[j+i] + st)%deg; st = (t + st*osel)%deg; } pf1 = testpermutation(O, Bel, X, sel, p, sr, td); if (pf1) break; } if (!pf1) return NULL; for (i=1; ideg) return gen_0; x = varn(T); if (DEBUGLEVEL >= 9) err_printf("GaloisConj: denominator:%Ps\n", den); if (n == 12 && ga->ord==3 && !ga->p4) { /* A4 is very probable: test it first */ pari_sp av = avma; if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Testing A4 first\n"); inittest(L, M, gb->bornesol, gb->ladicsol, &td); PG = a4galoisgen(&td); freetest(&td); if (PG != gen_0) return gerepileupto(ltop, PG); avma = av; } if (n == 24 && ga->ord==3) { /* S4 is very probable: test it first */ pari_sp av = avma; struct galois_lift gl; if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Testing S4 first\n"); initlift(T, den, stoi(ga->p4), L, makeLden(L,den,gb), gb, &gl); PG = s4galoisgen(&gl); if (PG != gen_0) return gerepileupto(ltop, PG); avma = av; } frob = galoisfindfrobenius(T, L, den, &gf, gb, ga); if (!frob) { avma=ltop; return gen_0; } p = gf.p; ip = utoipos(p); Tmod = gf.Tmod; O = perm_cycles(frob); deg = lg(gel(O,1))-1; if (DEBUGLEVEL >= 9) err_printf("GaloisConj: Orbit:%Ps\n", O); if (deg == n) /* cyclic */ return gerepilecopy(ltop, mkvec2(mkvec(frob), mkvecsmall(deg))); sigma = permtopol(frob, L, M, den, gb->ladicabs, shifti(gb->ladicabs,-1), x); if (DEBUGLEVEL >= 9) err_printf("GaloisConj: Frobenius:%Ps\n", sigma); { pari_sp btop=avma; GEN V, Tp, Sp, Pmod; GEN OL = fixedfieldorbits(O,L); V = fixedfieldsympol(OL, gb->ladicabs, gb->l, ip, x); Tp = FpX_red(T,ip); Sp = sympol_aut_evalmod(gel(V,1),deg,sigma,Tp,ip); Pmod = fixedfieldfactmod(Sp,ip,Tmod); PG = galoisgenfixedfield(Tp, Pmod, V, ip, gb); if (PG == NULL) { avma = ltop; return gen_0; } if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Back to Earth:%Ps\n", PG); PG=gerepilecopy(btop, PG); } inittest(L, M, gb->bornesol, gb->ladicsol, &td); PG1 = gmael(PG, 1, 1); lP = lg(PG1); PG2 = gmael(PG, 1, 2); Pg = gel(PG, 2); res = cgetg(3, t_VEC); gel(res,1) = res1 = cgetg(lP + 1, t_VEC); gel(res,2) = vecsmall_prepend(PG2, deg); gel(res1, 1) = vecsmall_copy(frob); for (j = 1; j < lP; j++) { GEN pf = galoisgenliftauto(O, gel(PG1, j), gf.psi[Pg[j]], n, &td); if (!pf) { freetest(&td); avma = ltop; return gen_0; } gel(res1, j+1) = pf; } if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Fini!\n"); freetest(&td); return gerepileupto(ltop, res); } /* T = polcyclo(N) */ static GEN conjcyclo(GEN T, long N) { pari_sp av = avma; long i, k = 1, d = eulerphiu(N), v = varn(T); GEN L = cgetg(d+1,t_COL); for (i=1; i<=N; i++) if (ugcd(i, N)==1) { GEN s = pol_xn(i, v); if (i >= d) s = ZX_rem(s, T); gel(L,k++) = s; } return gerepileupto(av, gen_sort(L, (void*)&gcmp, &gen_cmp_RgX)); } /* T: polynomial or nf, den multiple of common denominator of solutions or * NULL (unknown). If T is nf, and den unknown, use den = denom(nf.zk) */ static GEN galoisconj4_main(GEN T, GEN den, long flag) { pari_sp ltop = avma; GEN nf, G, L, M, aut; struct galois_analysis ga; struct galois_borne gb; long n; pari_timer ti; T = get_nfpol(T, &nf); n = poliscyclo(T); if (n) return flag? galoiscyclo(n, varn(T)): conjcyclo(T, n); n = degpol(T); if (nf) { if (!den) den = nf_get_zkden(nf); } else { if (n <= 0) pari_err_IRREDPOL("galoisinit",T); RgX_check_ZX(T, "galoisinit"); if (!ZX_is_squarefree(T)) pari_err_DOMAIN("galoisinit","issquarefree(pol)","=",gen_0,T); if (!gequal1(gel(T,n+2))) pari_err_IMPL("galoisinit(non-monic)"); } if (n == 1) { if (!flag) { G = cgetg(2, t_COL); gel(G,1) = pol_x(varn(T)); return G;} ga.l = 3; ga.deg = 1; den = gen_1; } else if (!galoisanalysis(T, &ga, 1)) { avma = ltop; return utoipos(ga.p); } if (den) { if (typ(den) != t_INT) pari_err_TYPE("galoisconj4 [2nd arg integer]", den); den = absi_shallow(den); } gb.l = utoipos(ga.l); if (DEBUGLEVEL >= 1) timer_start(&ti); den = galoisborne(T, den, &gb, degpol(T)); if (DEBUGLEVEL >= 1) timer_printf(&ti, "galoisborne()"); L = ZpX_roots(T, gb.l, gb.valabs); if (DEBUGLEVEL >= 1) timer_printf(&ti, "ZpX_roots"); M = FpV_invVandermonde(L, den, gb.ladicabs); if (DEBUGLEVEL >= 1) timer_printf(&ti, "FpV_invVandermonde()"); if (n == 1) { G = cgetg(3, t_VEC); gel(G,1) = cgetg(1, t_VEC); gel(G,2) = cgetg(1, t_VECSMALL); } else G = galoisgen(T, L, M, den, &gb, &ga); if (DEBUGLEVEL >= 6) err_printf("GaloisConj: %Ps\n", G); if (G == gen_0) { avma = ltop; return gen_0; } if (DEBUGLEVEL >= 1) timer_start(&ti); if (flag) { GEN grp = cgetg(9, t_VEC); gel(grp,1) = ZX_copy(T); gel(grp,2) = mkvec3(utoipos(ga.l), utoipos(gb.valabs), icopy(gb.ladicabs)); gel(grp,3) = ZC_copy(L); gel(grp,4) = ZM_copy(M); gel(grp,5) = icopy(den); gel(grp,6) = group_elts(G,n); gel(grp,7) = gcopy(gel(G,1)); gel(grp,8) = gcopy(gel(G,2)); return gerepileupto(ltop, grp); } aut = galoisgrouptopol(group_elts(G, n),L,M,den,gb.ladicsol, varn(T)); if (DEBUGLEVEL >= 1) timer_printf(&ti, "Computation of polynomials"); return gerepileupto(ltop, gen_sort(aut, (void*)&gcmp, &gen_cmp_RgX)); } /* Heuristic computation of #Aut(T), pinit = first prime to be tested */ long numberofconjugates(GEN T, long pinit) { pari_sp av = avma; long c, nbtest, nbmax, n = degpol(T); ulong p; forprime_t S; if (n == 1) return 1; nbmax = (n < 10)? 20: (n<<1) + 1; nbtest = 0; #if 0 c = ZX_sturm(T); c = ugcd(c, n-c); /* too costly: finite primes are cheaper */ #else c = n; #endif u_forprime_init(&S, pinit, ULONG_MAX); while((p = u_forprime_next(&S))) { GEN L, Tp = ZX_to_Flx(T,p); long i, nb; if (!Flx_is_squarefree(Tp, p)) continue; /* unramified */ nbtest++; L = Flx_nbfact_by_degree(Tp, &nb, p); /* L[i] = #factors of degree i */ if (L[n/nb] == nb) { if (c == n && nbtest > 10) break; /* probably Galois */ } else { c = ugcd(c, L[1]); for (i = 2; i <= n; i++) if (L[i]) { c = ugcd(c, L[i]*i); if (c == 1) break; } if (c == 1) break; } if (nbtest == nbmax) break; if (DEBUGLEVEL >= 6) err_printf("NumberOfConjugates [%ld]:c=%ld,p=%ld\n", nbtest,c,p); avma = av; } if (DEBUGLEVEL >= 2) err_printf("NumberOfConjugates:c=%ld,p=%ld\n", c, p); avma = av; return c; } static GEN galoisconj4(GEN nf, GEN d) { pari_sp av = avma; GEN G, T; G = galoisconj4_main(nf, d, 0); if (typ(G) != t_INT) return G; /* Success */ avma = av; T = get_nfpol(nf, &nf); G = cgetg(2, t_COL); gel(G,1) = pol_x(varn(T)); return G; /* Fail */ } /* d multiplicative bound for the automorphism's denominators */ GEN galoisconj(GEN nf, GEN d) { pari_sp av = avma; GEN G, NF, T = get_nfpol(nf,&NF); if (degpol(T) == 2) { /* fast shortcut */ GEN a = gel(T,4), b = gel(T,3); long v = varn(T); RgX_check_ZX(T, "galoisconj"); if (!gequal1(a)) pari_err_IMPL("galoisconj(non-monic)"); b = negi(b); G = cgetg(3, t_COL); gel(G,1) = pol_x(v); gel(G,2) = deg1pol(gen_m1, b, v); return G; } G = galoisconj4_main(nf, d, 0); if (typ(G) != t_INT) return G; /* Success */ avma = av; return galoisconj1(nf); } /* FIXME: obsolete, use galoisconj(nf, d) directly */ GEN galoisconj0(GEN nf, long flag, GEN d, long prec) { (void)prec; switch(flag) { case 2: case 0: return galoisconj(nf, d); case 1: return galoisconj1(nf); case 4: return galoisconj4(nf, d); } pari_err_FLAG("nfgaloisconj"); return NULL; /*LCOV_EXCL_LINE*/ } /******************************************************************************/ /* Galois theory related algorithms */ /******************************************************************************/ GEN checkgal(GEN gal) { if (typ(gal) == t_POL) pari_err_TYPE("checkgal [apply galoisinit first]",gal); if (typ(gal) != t_VEC || lg(gal) != 9) pari_err_TYPE("checkgal",gal); return gal; } GEN galoisinit(GEN nf, GEN den) { GEN G = galoisconj4_main(nf, den, 1); return (typ(G) == t_INT)? gen_0: G; } static GEN galoispermtopol_i(GEN gal, GEN perm, GEN mod, GEN mod2) { switch (typ(perm)) { case t_VECSMALL: return permtopol(perm, gal_get_roots(gal), gal_get_invvdm(gal), gal_get_den(gal), mod, mod2, varn(gal_get_pol(gal))); case t_VEC: case t_COL: case t_MAT: { long i, lv; GEN v = cgetg_copy(perm, &lv); if (DEBUGLEVEL>=4) err_printf("GaloisPermToPol:"); for (i = 1; i < lv; i++) { gel(v,i) = galoispermtopol_i(gal, gel(perm,i), mod, mod2); if (DEBUGLEVEL>=4) err_printf("%ld ",i); } if (DEBUGLEVEL>=4) err_printf("\n"); return v; } } pari_err_TYPE("galoispermtopol", perm); return NULL; /* LCOV_EXCL_LINE */ } GEN galoispermtopol(GEN gal, GEN perm) { pari_sp av = avma; GEN mod, mod2; gal = checkgal(gal); mod = gal_get_mod(gal); mod2 = shifti(mod,-1); return gerepilecopy(av, galoispermtopol_i(gal, perm, mod, mod2)); } GEN galoiscosets(GEN O, GEN perm) { long i, j, k, u, f, l = lg(O); GEN RC, C = cgetg(l,t_VECSMALL), o = gel(O,1); pari_sp av = avma; f = lg(o); u = o[1]; RC = zero_zv(lg(perm)-1); for(i=1,j=1; j=4) err_printf("GaloisFixedField:cosets=%Ps \n",cosets); if (DEBUGLEVEL>=6) err_printf("GaloisFixedField:den=%Ps mod=%Ps \n",den,mod); V = cgetg(l,t_COL); res = cgetg(l,t_VEC); for (i = 1; i < l; i++) { pari_sp av = avma; GEN G = cgetg(l,t_VEC), Lp = vecpermute(L, gel(perm, cosets[i])); for (k = 1; k < l; k++) gel(G,k) = FpV_roots_to_pol(vecpermute(Lp, gel(O,k)), mod, x); for (j = 1; j < lo; j++) { for(k = 1; k < l; k++) gel(V,k) = gmael(G,k,j+1); gel(F,j) = vectopol(V, M, den, mod, mod2, y); } gel(res,i) = gerepileupto(av,gtopolyrev(F,x)); } return gerepileupto(ltop,res); } static void chk_perm(GEN perm, long n) { if (typ(perm) != t_VECSMALL || lg(perm)!=n+1) pari_err_TYPE("galoisfixedfield", perm); } static int is_group(GEN g) { return typ(g)==t_VEC && lg(g)==3 && typ(gel(g,1))==t_VEC && typ(gel(g,2))==t_VECSMALL; } GEN galoisfixedfield(GEN gal, GEN perm, long flag, long y) { pari_sp ltop = avma; GEN T, L, P, S, PL, O, res, mod, mod2; long vT, n, i; if (flag<0 || flag>2) pari_err_FLAG("galoisfixedfield"); gal = checkgal(gal); T = gal_get_pol(gal); vT = varn(T); L = gal_get_roots(gal); n = lg(L)-1; mod = gal_get_mod(gal); if (typ(perm) == t_VEC) { if (is_group(perm)) perm = gel(perm, 1); for (i = 1; i < lg(perm); i++) chk_perm(gel(perm,i), n); O = vecperm_orbits(perm, n); } else { chk_perm(perm, n); O = perm_cycles(perm); } { GEN OL= fixedfieldorbits(O,L); GEN V = fixedfieldsympol(OL, mod, gal_get_p(gal), NULL, vT); PL= gel(V,2); P = gel(V,3); } if (flag==1) return gerepileupto(ltop,P); mod2 = shifti(mod,-1); S = fixedfieldinclusion(O, PL); S = vectopol(S, gal_get_invvdm(gal), gal_get_den(gal), mod, mod2, vT); if (flag==0) res = cgetg(3, t_VEC); else { GEN PM, Pden; struct galois_borne Pgb; long val = itos(gal_get_e(gal)); Pgb.l = gal_get_p(gal); Pden = galoisborne(P, NULL, &Pgb, degpol(T)/degpol(P)); if (Pgb.valabs > val) { if (DEBUGLEVEL>=4) err_printf("GaloisConj: increase p-adic prec by %ld.\n", Pgb.valabs-val); PL = ZpX_liftroots(P, PL, Pgb.l, Pgb.valabs); L = ZpX_liftroots(T, L, Pgb.l, Pgb.valabs); mod = Pgb.ladicabs; mod2 = shifti(mod,-1); } PM = FpV_invVandermonde(PL, Pden, mod); if (y < 0) y = 1; if (varncmp(y, vT) <= 0) pari_err_PRIORITY("galoisfixedfield", T, "<=", y); setvarn(P, y); res = cgetg(4, t_VEC); gel(res,3) = fixedfieldfactor(L,O,gal_get_group(gal), PM,Pden,mod,mod2,vT,y); } gel(res,1) = gcopy(P); gel(res,2) = gmodulo(S, T); return gerepileupto(ltop, res); } /* gal a galois group output the underlying wss group */ GEN galois_group(GEN gal) { return mkvec2(gal_get_gen(gal), gal_get_orders(gal)); } GEN checkgroup(GEN g, GEN *S) { if (is_group(g)) { *S = NULL; return g; } g = checkgal(g); *S = gal_get_group(g); return galois_group(g); } GEN checkgroupelts(GEN G) { long i, n; if (typ(G)!=t_VEC) pari_err_TYPE("checkgroupelts", G); if (is_group(G)) { /* subgroup of S_n */ if (lg(gel(G,1))==1) return mkvec(mkvecsmall(1)); return group_elts(G, group_domain(G)); } if (lg(G)==9 && typ(gel(G,1))==t_POL) return gal_get_group(G); /* galoisinit */ /* vector of permutations ? */ n = lg(G)-1; if (n==0) pari_err_DIM("checkgroupelts"); for (i = 1; i <= n; i++) { if (typ(gel(G,i)) != t_VECSMALL) pari_err_TYPE("checkgroupelts (element)", gel(G,i)); if (lg(gel(G,i)) != lg(gel(G,1))) pari_err_DIM("checkgroupelts [length of permutations]"); } return G; } GEN galoisisabelian(GEN gal, long flag) { pari_sp av = avma; GEN S, G = checkgroup(gal,&S); if (!group_isabelian(G)) { avma=av; return gen_0; } switch(flag) { case 0: return gerepileupto(av, group_abelianHNF(G,S)); case 1: avma=av; return gen_1; case 2: return gerepileupto(av, group_abelianSNF(G,S)); default: pari_err_FLAG("galoisisabelian"); } return NULL; /* LCOV_EXCL_LINE */ } long galoisisnormal(GEN gal, GEN sub) { pari_sp av = avma; GEN S, G = checkgroup(gal, &S), H = checkgroup(sub, &S); long res = group_subgroup_isnormal(G, H); avma = av; return res; } static GEN conjclasses_count(GEN conj, long nb) { long i, l = lg(conj); GEN c = zero_zv(nb); for (i = 1; i < l; i++) c[conj[i]]++; return c; } GEN galoisconjclasses(GEN G) { pari_sp av = avma; GEN c, e, cc = group_to_cc(G); GEN elts = gel(cc,1), conj = gel(cc,2), repr = gel(cc,3); long i, l = lg(conj), lc = lg(repr); c = conjclasses_count(conj, lc-1); e = cgetg(lc, t_VEC); for (i = 1; i < lc; i++) gel(e,i) = cgetg(c[i]+1, t_VEC); for (i = 1; i < l; i++) { long ci = conj[i]; gmael(e, ci, c[ci]) = gel(elts, i); c[ci]--; } return gerepilecopy(av, e); } GEN galoissubgroups(GEN gal) { pari_sp av = avma; GEN S, G = checkgroup(gal,&S); return gerepileupto(av, group_subgroups(G)); } GEN galoissubfields(GEN G, long flag, long v) { pari_sp av = avma; GEN L = galoissubgroups(G); long i, l = lg(L); GEN S = cgetg(l, t_VEC); for (i = 1; i < l; ++i) gel(S,i) = galoisfixedfield(G, gmael(L,i,1), flag, v); return gerepileupto(av, S); } GEN galoisexport(GEN gal, long format) { pari_sp av = avma; GEN S, G = checkgroup(gal,&S); return gerepileupto(av, group_export(G,format)); } GEN galoisidentify(GEN gal) { pari_sp av = avma; GEN S, G = checkgroup(gal,&S); long idx = group_ident(G,S), card = group_order(G); avma = av; return mkvec2s(card, idx); } /* index of conjugacy class containing g */ static long cc_id(GEN cc, GEN g) { GEN conj = gel(cc,2); long k = signe(gel(cc,4))? g[1]: vecvecsmall_search(gel(cc,1),g,0); return conj[k]; } static GEN Qevproj_RgX(GEN c, long d, GEN pro) { return RgV_to_RgX(Qevproj_down(RgX_to_RgC(c,d), pro), varn(c)); } /* c in Z[X] / (X^o-1), To = polcyclo(o), T = polcyclo(expo), e = expo/o * return c(X^e) mod T as an element of Z[X] / (To) */ static GEN chival(GEN c, GEN T, GEN To, long e, GEN pro, long phie) { c = ZX_rem(c, To); if (e != 1) c = ZX_rem(RgX_inflate(c,e), T); if (pro) c = Qevproj_RgX(c, phie, pro); return c; } /* chi(g^l) = sum_{k=0}^{o-1} a_k zeta_o^{l*k} for all l; * => a_k = 1/o sum_{l=0}^{o-1} chi(g^l) zeta_o^{-k*l}. Assume o > 1 */ static GEN chiFT(GEN cp, GEN jg, GEN vze, long e, long o, ulong p, ulong pov2) { const long var = 1; ulong oinv = Fl_inv(o,p); long k, l; GEN c = cgetg(o+2, t_POL); for (k = 0; k < o; k++) { ulong a = 0; for (l=0; l 1, exponent of G */ p = unextprime(2*n+1); while (p%expo != 1) p = unextprime(p+1); /* compute character table modulo p: idempotents of Z(KG) */ al = conjclasses_algcenter(cc, utoipos(p)); dec = algsimpledec_ss(al,1); ctp = cgetg(lcl,t_VEC); for(i=1; i>1; ct = cgetg(lcl, t_MAT); if (f == 1) { /* rational representation */ for (j=1; j 2? jg[2]: jg[1]; for(i=1; i 1; j--) { /* loop over conjugacy classes, decreasing order: skip 1_G */ long e, jperm = operm[j], o = vord[jperm]; GEN To, jg = gel(vjg,jperm); /* jg[l+1] = class of g^l */ if (gel(C, jperm)) continue; /* done already */ if (dim == 1) { gel(C, jperm) = gel(vzeZX, cp[jg[2]]); continue; } e = expo / o; cj = chiFT(cp, jg, vze, e, o, p, pov2); To = gel(vT, o); if (!To) To = gel(vT,o) = polcyclo(o, var); gel(C, jperm) = chival(cj, T, To, e, pro, phie); for (k = 2; k < o; k++) { GEN ck = RgX_inflate(cj, k); /* chi(g^k) */ gel(C, jg[k+1]) = chival(ck, T, To, e, pro, phie); } } } } ct = gen_sort(ct,(void*)cmp_universal,cmp_nodata); i = 1; while (!vec_isconst(gel(ct,i))) i++; if (i > 1) swap(gel(ct,1), gel(ct,i)); return mkvec2(ct, utoipos(f)); } GEN galoischartable(GEN gal) { pari_sp av = avma; GEN cc = group_to_cc(gal); return gerepilecopy(av, cc_chartable(cc)); } static void checkgaloischar(GEN ch, GEN repr) { if (gvar(ch) == 0) pari_err_PRIORITY("galoischarpoly",ch,"=",0); if (!is_vec_t(typ(ch))) pari_err_TYPE("galoischarpoly", ch); if (lg(repr) != lg(ch)) pari_err_DIM("galoischarpoly"); } static long galoischar_dim(GEN ch) { pari_sp av = avma; long d = gtos(simplify_shallow(lift_shallow(gel(ch,1)))); avma = av; return d; } static GEN galoischar_aut_charpoly(GEN cc, GEN ch, GEN p, long d) { GEN q = p, V = cgetg(d+3, t_POL); long i; V[1] = evalsigne(1)|evalvarn(0); gel(V,2) = gen_0; for (i = 1; i <= d; i++) { gel(V,i+2) = gdivgs(gel(ch, cc_id(cc,q)), -i); if (i < d) q = perm_mul(q, p); } return liftpol_shallow(RgXn_exp(V,d+1)); } static GEN galoischar_charpoly(GEN cc, GEN ch, long o) { GEN chm, V, elts = gel(cc,1), repr = gel(cc,3); long i, d, l = lg(ch), v = gvar(ch); checkgaloischar(ch, repr); chm = v < 0 ? ch: gmodulo(ch, polcyclo(o, v)); V = cgetg(l, t_COL); d = galoischar_dim(ch); for (i = 1; i < l; i++) gel(V,i) = galoischar_aut_charpoly(cc, chm, gel(elts,repr[i]), d); return V; } GEN galoischarpoly(GEN gal, GEN ch, long o) { pari_sp av = avma; GEN cc = group_to_cc(gal); return gerepilecopy(av, galoischar_charpoly(cc, ch, o)); } static GEN cc_char_det(GEN cc, GEN ch, long o) { long i, l = lg(ch), d = galoischar_dim(ch); GEN V = galoischar_charpoly(cc, ch, o); for (i = 1; i < l; i++) gel(V,i) = leading_coeff(gel(V,i)); return odd(d)? gneg(V): V; } GEN galoischardet(GEN gal, GEN ch, long o) { pari_sp av = avma; GEN cc = group_to_cc(gal); return gerepilecopy(av, cc_char_det(cc, ch, o)); } pari-2.11.2/src/basemath/bit.c0000644000175000017500000004135513326135265014471 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*********************************************************************/ /** **/ /** BINARY DECOMPOSITION **/ /** **/ /*********************************************************************/ INLINE GEN inegate(GEN z) { return subsi(-1,z); } GEN binary_zv(GEN x) { GEN xp, z; long i, k, lx; if (!signe(x)) return cgetg(1,t_VECSMALL); xp = int_LSW(x); lx = lgefint(x); k = expi(x)+2; z = cgetg(k, t_VECSMALL); k--; for(i = 2; i < lx; i++) { ulong u = *xp; long j; for (j=0; j>j)&1UL; if (!k) break; xp = int_nextW(xp); } return z; } static GEN F2v_to_ZV_inplace(GEN v) { long i, l = lg(v); v[0] = evaltyp(t_VEC) | _evallg(l); for (i = 1; i < l; i++) gel(v,i) = v[i]? gen_1: gen_0; return v; } /* "vector" of l bits (possibly no code word) to non-negative t_INT */ GEN bits_to_int(GEN x, long l) { long i, j, lz; GEN z, zp; if (!l) return gen_0; lz = nbits2lg(l); z = cgetg(lz, t_INT); z[1] = evalsigne(1) | evallgefint(lz); zp = int_LSW(z); *zp = 0; for(i=l,j=0; i; i--,j++) { if (j==BITS_IN_LONG) { j=0; zp = int_nextW(zp); *zp = 0; } if (x[i]) *zp |= 1UL<> (BITS_IN_LONG - *r)); } else { **w = a; *w = int_nextW(*w); } } /* set k bits starting at word *w plus *r bits, * clearing subsequent bits in the last word touched */ INLINE void int_set_bits(ulong a, long k, GEN *w, long *r) { if (*r) { **w |= a << *r; a >>= BITS_IN_LONG - *r; } else { **w = a; a = 0; } *r += k; if (*r >= BITS_IN_LONG) { *w = int_nextW(*w); *r -= BITS_IN_LONG; for (; *r >= BITS_IN_LONG; *r -= BITS_IN_LONG) { **w = a; a = 0; *w = int_nextW(*w); } if (*r) **w = a; } } /* set k bits from z (t_INT) starting at word *w plus *r bits, * clearing subsequent bits in the last word touched */ INLINE void int_set_int(GEN z, long k, GEN *w, long *r) { long l = lgefint(z) - 2; GEN y; if (!l) { int_set_bits(0, k, w, r); return; } y = int_LSW(z); for (; l > 1; l--) { int_set_ulong((ulong) *y, w, r); y = int_nextW(y); k -= BITS_IN_LONG; } if (k) int_set_bits((ulong) *y, k, w, r); } GEN nv_fromdigits_2k(GEN x, long k) { long l = lg(x) - 1, r; GEN w, z; if (k == 1) return bits_to_int(x, l); if (!l) return gen_0; z = cgetipos(nbits2lg(k * l)); w = int_LSW(z); r = 0; for (; l; l--) int_set_bits(uel(x, l), k, &w, &r); return int_normalize(z, 0); } GEN fromdigits_2k(GEN x, long k) { long l, m; GEN w, y, z; for (l = lg(x) - 1; l && !signe(gel(x, 1)); x++, l--); if (!l) return gen_0; m = expi(gel(x, 1)) + 1; z = cgetipos(nbits2lg(k * (l - 1) + m)); w = int_LSW(z); if (!(k & (BITS_IN_LONG - 1))) { long i, j, t = k >> TWOPOTBITS_IN_LONG; for (; l; l--) { j = lgefint(gel(x, l)) - 2; y = int_LSW(gel(x, l)); for (i = 0; i < j; i++) { *w = *y; y = int_nextW(y); w = int_nextW(w); } for (; i < t; i++) { *w = 0; w = int_nextW(w); } } } else { long r = 0; for (; l > 1; l--) int_set_int(gel(x, l), k, &w, &r); int_set_int(gel(x, 1), m, &w, &r); } return int_normalize(z, 0); } GEN binaire(GEN x) { ulong m,u; long i,lx,ex,ly,tx=typ(x); GEN y,p1,p2; switch(tx) { case t_INT: return F2v_to_ZV_inplace( binary_zv(x) ); case t_REAL: ex = expo(x); if (!signe(x)) return zerovec(maxss(-ex,0)); lx=lg(x); y=cgetg(3,t_VEC); if (ex > bit_prec(x)) pari_err_PREC("binary"); p1 = cgetg(maxss(ex,0)+2,t_VEC); p2 = cgetg(bit_prec(x)-ex,t_VEC); gel(y,1) = p1; gel(y,2) = p2; ly = -ex; ex++; m = HIGHBIT; if (ex<=0) { gel(p1,1) = gen_0; for (i=1; i <= -ex; i++) gel(p2,i) = gen_0; i=2; } else { ly=1; for (i=2; i>=1) && ly<=ex); } ly=1; if (m) i--; else m=HIGHBIT; } for (; i>=1); m=HIGHBIT; } break; case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); for (i=1; i> *r) & mask; *r += k; if (*r >= BITS_IN_LONG) { *r -= BITS_IN_LONG; *w = int_nextW(*w); if (*r) a |= ((ulong)**w << (k - *r)) & mask; } return a; } /* extract BITS_IN_LONG bits starting at word *w plus *r bits */ INLINE ulong int_get_ulong(GEN *w, long *r) { ulong a = ((ulong) **w) >> *r; *w = int_nextW(*w); if (*r) a |= ((ulong)**w << (BITS_IN_LONG - *r)); return a; } /* extract k bits (as t_INT) starting at word *w plus *r bits */ INLINE GEN int_get_int(long k, GEN *w, long *r) { GEN z = cgetipos(nbits2lg(k)); GEN y = int_LSW(z); for (; k >= BITS_IN_LONG; k -= BITS_IN_LONG) { *y = int_get_ulong(w, r); y = int_nextW(y); } if (k) *y = int_get_bits(k, w, r); return int_normalize(z, 0); } /* assume k < BITS_IN_LONG */ GEN binary_2k_nv(GEN x, long k) { long l, n, r; GEN v, w; if (k == 1) return binary_zv(x); if (!signe(x)) return cgetg(1, t_VECSMALL); n = expi(x) + 1; l = (n + k - 1) / k; v = cgetg(l + 1, t_VECSMALL); w = int_LSW(x); r = 0; for (; l > 1; l--) { uel(v, l) = int_get_bits(k, &w, &r); n -= k; } uel(v, 1) = int_get_bits(n, &w, &r); return v; } GEN binary_2k(GEN x, long k) { long l, n; GEN v, w, y, z; if (k == 1) return binaire(x); if (!signe(x)) return cgetg(1, t_VEC); n = expi(x) + 1; l = (n + k - 1) / k; v = cgetg(l + 1, t_VEC); w = int_LSW(x); if (!(k & (BITS_IN_LONG - 1))) { long m, t = k >> TWOPOTBITS_IN_LONG, u = lgefint(x) - 2; for (; l; l--) { m = minss(t, u); z = cgetipos(m + 2); y = int_LSW(z); for (; m; m--) { *y = *w; y = int_nextW(y); w = int_nextW(w); } gel(v, l) = int_normalize(z, 0); u -= t; } } else { long r = 0; for (; l > 1; l--, n -= k) gel(v, l) = int_get_int(k, &w, &r); gel(v, 1) = int_get_int(n, &w, &r); } return v; } /* return 1 if bit n of x is set, 0 otherwise */ long bittest(GEN x, long n) { if (typ(x) != t_INT) pari_err_TYPE("bittest",x); if (!signe(x) || n < 0) return 0; if (signe(x) < 0) { pari_sp ltop=avma; long b = !int_bit(inegate(x),n); avma=ltop; return b; } return int_bit(x, n); } GEN gbittest(GEN x, long n) { return map_proto_lGL(bittest,x,n); } /***********************************************************************/ /** **/ /** BITMAP OPS **/ /** x & y (and), x | y (or), x ^ y (xor), ~x (neg), x & ~y (negimply) **/ /** **/ /***********************************************************************/ /* Truncate a non-negative integer to a number of bits. */ static GEN ibittrunc(GEN x, long bits) { long lowbits, known_zero_words, xl = lgefint(x) - 2; long len_out = nbits2nlong(bits); if (xl < len_out) return x; /* Check whether mask is trivial */ lowbits = bits & (BITS_IN_LONG-1); if (!lowbits) { if (xl == len_out) return x; } else if (len_out <= xl) { GEN xi = int_W(x, len_out-1); /* Non-trival mask is given by a formula, if x is not normalized, this works even in the exceptional case */ *xi &= (1L << lowbits) - 1; if (*xi && xl == len_out) return x; } /* Normalize */ known_zero_words = xl - len_out; if (known_zero_words < 0) known_zero_words = 0; return int_normalize(x, known_zero_words); } GEN gbitneg(GEN x, long bits) { const ulong uzero = 0; long lowbits, xl, len_out, i; if (typ(x) != t_INT) pari_err_TYPE("bitwise negation",x); if (bits < -1) pari_err_DOMAIN("bitwise negation","exponent","<",gen_m1,stoi(bits)); if (bits == -1) return inegate(x); if (bits == 0) return gen_0; if (signe(x) < 0) { /* Consider as if mod big power of 2 */ pari_sp ltop = avma; return gerepileuptoint(ltop, ibittrunc(inegate(x), bits)); } xl = lgefint(x); len_out = nbits2lg(bits); lowbits = bits & (BITS_IN_LONG-1); if (len_out > xl) /* Need to grow */ { GEN out, outp, xp = int_MSW(x); out = cgetipos(len_out); outp = int_MSW(out); if (!lowbits) *outp = ~uzero; else *outp = (1L << lowbits) - 1; for (i = 3; i < len_out - xl + 2; i++) { outp = int_precW(outp); *outp = ~uzero; } for ( ; i < len_out; i++) { outp = int_precW(outp); *outp = ~*xp; xp = int_precW(xp); } return out; } x = icopy(x); for (i = 2; i < xl; i++) x[i] = ~x[i]; return ibittrunc(int_normalize(x,0), bits); } /* bitwise 'and' of two positive integers (any integers, but we ignore sign). * Inputs are not necessary normalized. */ GEN ibitand(GEN x, GEN y) { long lx, ly, lout; long *xp, *yp, *outp; GEN out; long i; if (!signe(x) || !signe(y)) return gen_0; lx=lgefint(x); ly=lgefint(y); lout = minss(lx,ly); /* > 2 */ xp = int_LSW(x); yp = int_LSW(y); out = cgetipos(lout); outp = int_LSW(out); for (i=2; i 2 */ out = cgetipos(lx); outp = int_LSW(out); for (i=2;i 2 */ out = cgetipos(lx); outp = int_LSW(out); for (i=2;i y) == ~(~x | y) == x & ~y */ GEN ibitnegimply(GEN x, GEN y) { long lx, ly, lin; long *xp, *yp, *outp; GEN out; long i; if (!signe(x)) return gen_0; if (!signe(y)) return absi(x); lx = lgefint(x); xp = int_LSW(x); ly = lgefint(y); yp = int_LSW(y); lin = minss(lx,ly); out = cgetipos(lx); outp = int_LSW(out); for (i=2; i= 0) << 1) | (signe(y) >= 0)); } static void checkint2(const char *f,GEN x, GEN y) { if (typ(x)!=t_INT || typ(y)!=t_INT) pari_err_TYPE2(f,x,y); } GEN gbitor(GEN x, GEN y) { pari_sp ltop = avma; GEN z; checkint2("bitwise or",x,y); switch (signs(x, y)) { case 3: /*1,1*/ return ibitor(x,y); case 2: /*1,-1*/ z = ibitnegimply(inegate(y),x); break; case 1: /*-1,1*/ z = ibitnegimply(inegate(x),y); break; default: /*-1,-1*/ z = ibitand(inegate(x),inegate(y)); break; } return gerepileuptoint(ltop, inegate(z)); } GEN gbitand(GEN x, GEN y) { pari_sp ltop = avma; GEN z; checkint2("bitwise and",x,y); switch (signs(x, y)) { case 3: /*1,1*/ return ibitand(x,y); case 2: /*1,-1*/ z = ibitnegimply(x,inegate(y)); break; case 1: /*-1,1*/ z = ibitnegimply(y,inegate(x)); break; default: /*-1,-1*/ z = inegate(ibitor(inegate(x),inegate(y))); break; } return gerepileuptoint(ltop, z); } GEN gbitxor(GEN x, GEN y) { pari_sp ltop = avma; GEN z; checkint2("bitwise xor",x,y); switch (signs(x, y)) { case 3: /*1,1*/ return ibitxor(x,y); case 2: /*1,-1*/ z = inegate(ibitxor(x,inegate(y))); break; case 1: /*-1,1*/ z = inegate(ibitxor(inegate(x),y)); break; default: /*-1,-1*/ z = ibitxor(inegate(x),inegate(y)); break; } return gerepileuptoint(ltop,z); } /* x & ~y */ GEN gbitnegimply(GEN x, GEN y) { pari_sp ltop = avma; GEN z; checkint2("bitwise negated imply",x,y); switch (signs(x, y)) { case 3: /*1,1*/ return ibitnegimply(x,y); case 2: /*1,-1*/ z = ibitand(x,inegate(y)); break; case 1: /*-1,1*/ z = inegate(ibitor(y,inegate(x))); break; default: /*-1,-1*/ z = ibitnegimply(inegate(y),inegate(x)); break; } return gerepileuptoint(ltop,z); } long hammingl(ulong w) { #if 0 return __builtin_popcountl(w); #endif static long byte_weight[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 }; long sum = 0; while (w) { sum += byte_weight[w & 255]; w >>= 8; } return sum; } /* number of non-zero entries among x[a], ..., x[b] */ static long hamming_slice(GEN x, long a, long b) { long i, nb = 0; for (i = a; i <= b; i++) if (!gequal0(gel(x,i))) nb++; return nb; } static long hamming_mat(GEN x) { long i, lx = lg(x), nb = 0; for (i = 1; i < lx; i++) nb += hammingweight(gel(x,i)); return nb; } static long hamming_vecsmall(GEN x) { long i, lx = lg(x), nb = 0; for (i = 1; i < lx; i++) if (x[i]) nb++; return nb; } static long hamming_int(GEN n) { long lx = lgefint(n), i, sum; if (lx == 2) return 0; sum = hammingl(n[2]); for (i = 3; i < lx; i++) sum += hammingl(n[i]); return sum; } long hammingweight(GEN n) { switch(typ(n)) { case t_INT: return hamming_int(n); case t_VEC: case t_COL: return hamming_slice(n, 1, lg(n)-1); case t_POL: return hamming_slice(n, 2, lg(n)-1); case t_VECSMALL: return hamming_vecsmall(n); case t_MAT: return hamming_mat(n); } pari_err_TYPE("hammingweight", n); return 0;/*LCOV_EXCL_LINE*/ } pari-2.11.2/src/basemath/base2.c0000644000175000017500000031537113457566437014727 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* MAXIMAL ORDERS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" /* allow p = -1 from factorizations, avoid oo loop on p = 1 */ static long safe_Z_pvalrem(GEN x, GEN p, GEN *z) { if (is_pm1(p)) { if (signe(p) > 0) return gvaluation(x,p); /*error*/ *z = absi(x); return 1; } return Z_pvalrem(x, p, z); } /* D an integer, P a ZV, return a factorization matrix for D over P, removing * entries with 0 exponent. */ static GEN fact_from_factors(GEN D, GEN P, long flag) { long i, l = lg(P), iq = 1; GEN Q = cgetg(l+1,t_COL); GEN E = cgetg(l+1,t_COL); for (i=1; iT0 == S->T) return ZX_disc(S->T); d = degpol(S->T0); l0 = leading_coeff(S->T0); L = S->unscale; if (typ(L) == t_FRAC && abscmpii(gel(L,1), gel(L,2)) < 0) dT = ZX_disc(S->T); /* more efficient */ else { GEN a = gpowgs(gdiv(gpowgs(L, d), sqri(l0)), d-1); dT = gmul(a, ZX_disc(S->T0)); /* more efficient */ } return S->dT = dT; } /* dT != 0 */ static GEN poldiscfactors_i(GEN T, GEN dT, long flag) { GEN fa = absZ_factor_limit(dT, 0); GEN Tp, E, P = gel(fa,1); long i, l = lg(P); GEN p = gel(P,l-1); if (l == 1 || ((flag || lgefint(p)==3) && BPSW_psp(p))) return fa; settyp(P, t_VEC); Tp = ZX_deriv(T); for (i = l-1; i < lg(P); i++) { GEN p = gel(P,i), r, L; if (Z_isanypower(p, &p)) gel(P,i) = p; if ((flag || lgefint(p)==3) && BPSW_psp(p)) continue; r = FpX_gcd_check(T, Tp, p); if (r) L = Z_cba(r, diviiexact(p,r)); else { if (!flag) continue; L = gel(Z_factor(p),1); settyp(L, t_VEC); } P = shallowconcat(vecsplice(P,i), L); i--; } settyp(P, t_COL); P = ZV_sort(P); l = lg(P); E = cgetg(l, t_COL); for (i = 1; i < l; i++) gel(E,i) = utoi(Z_pvalrem(dT, gel(P,i), &dT)); return mkmat2(P,E); } GEN poldiscfactors(GEN T, long flag) { pari_sp av = avma; GEN dT; if (typ(T) != t_POL || !RgX_is_ZX(T)) pari_err_TYPE("poldiscfactors",T); if (flag < 0 || flag > 1) pari_err_FLAG("poldiscfactors"); dT = ZX_disc(T); if (!signe(dT)) retmkvec2(gen_0, Z_factor(gen_0)); return gerepilecopy(av, mkvec2(dT, poldiscfactors_i(T, dT, flag))); } static void nfmaxord_check_args(nfmaxord_t *S, GEN T, long flag) { GEN dT, L, E, P, fa = NULL; pari_timer t; long l, ty = typ(T); if (DEBUGLEVEL) timer_start(&t); if (ty == t_VEC) { if (lg(T) != 3) pari_err_TYPE("nfmaxord",T); fa = gel(T,2); T = gel(T,1); ty = typ(T); } if (ty != t_POL) pari_err_TYPE("nfmaxord",T); T = Q_primpart(T); if (degpol(T) <= 0) pari_err_CONSTPOL("nfmaxord"); RgX_check_ZX(T, "nfmaxord"); S->T0 = T; T = ZX_Q_normalize(T, &L); S->unscale = L; S->T = T; S->dT = dT = set_disc(S); if (fa) { const long MIN = 100; /* include at least all p < 101 */ long tf; if (!isint1(L)) fa = update_fact(dT, fa); tf = typ(fa); switch(tf) { case t_MAT: if (!is_Z_factornon0(fa)) pari_err_TYPE("nfmaxord",fa); fa = gel(fa,1); tf = t_COL; /* fall through */ case t_VEC: case t_COL: P = gel(absZ_factor_limit(dT, MIN), 1); l = lg(P); if (l > 1 && abscmpiu(gel(P,1), MIN) <= 0) { if (abscmpiu(gel(P,l-1), MIN) > 0) setlg(P,l-1); settyp(P,tf); fa = ZV_sort_uniq(shallowconcat(fa,P)); } fa = fact_from_factors(dT, fa, 0); break; case t_INT: fa = absZ_factor_limit(dT, (signe(fa) <= 0)? 1: maxuu(itou(fa), MIN)); break; /*fall through*/ default: pari_err_TYPE("nfmaxord",fa); } if (!signe(dT)) pari_err_IRREDPOL("nfmaxord",mkvec2(T,fa)); } else fa = poldiscfactors_i(T, dT, !(flag & nf_PARTIALFACT)); P = gel(fa,1); l = lg(P); E = gel(fa,2); if (l > 1 && is_pm1(gel(P,1))) { l--; P = vecslice(P, 2, l); E = vecslice(E, 2, l); } S->dTP = P; S->dTE = vec_to_vecsmall(E); if (DEBUGLEVEL>2) timer_printf(&t, "disc. factorisation"); } static int fnz(GEN x,long j) { long i; for (i=1; idTP ]*/ static GEN get_maxord(nfmaxord_t *S, GEN T0, long flag) { VOLATILE GEN P, E, O; VOLATILE long lP, i, k; nfmaxord_check_args(S, T0, flag); P = S->dTP; lP = lg(P); E = S->dTE; O = cgetg(1, t_VEC); for (i=1; iT, &g, p); k = FpX_normalize(k, p); B = dbasis(p, S->T, E[i], NULL, FpX_div(S->T,k,p)); O = shallowconcat(O, mkvec(B)); pari_CATCH_reset(); continue; } break; } default: pari_err(0, err); return NULL;/*LCOV_EXCL_LINE*/ } l = lg(u); gel(P,i) = gel(u,1); P = shallowconcat(P, vecslice(u, 2, l-1)); av = avma; N = S->dT; E[i] = Z_pvalrem(N, gel(P,i), &N); for (k=lP, lP=lg(P); k < lP; k++) E[k] = Z_pvalrem(N, gel(P,k), &N); } pari_RETRY { if (DEBUGLEVEL>2) err_printf("Treating p^k = %Ps^%ld\n",P[i],E[i]); O = shallowconcat(O, mkvec( maxord(gel(P,i),S->T,E[i]) )); } pari_ENDCATCH; } S->dTP = P; return O; } /* M a QM, return denominator of diagonal. All denominators are powers of * a given integer */ static GEN diag_denom(GEN M) { GEN d = gen_1; long j, l = lg(M); for (j=1; j 0) d = t; } return d; } void nfmaxord(nfmaxord_t *S, GEN T0, long flag) { GEN O = get_maxord(S, T0, flag); GEN f = S->T, P = S->dTP, a = NULL, da = NULL, P2, E2, D; long n = degpol(f), lP = lg(P), i, j, k; int centered = 0; pari_sp av = avma; /* r1 & basden not initialized here */ S->r1 = -1; S->basden = NULL; for (i=1; iindex = index; S->dK = diviiexact(S->dT, sqri(index)); } else { S->index = gen_1; S->dK = S->dT; a = matid(n); } D = S->dK; P2 = cgetg(lP, t_COL); E2 = cgetg(lP, t_VECSMALL); for (k = j = 1; j < lP; j++) { long v = Z_pvalrem(D, gel(P,j), &D); if (v) { gel(P2,k) = gel(P,j); E2[k] = v; k++; } } setlg(P2, k); S->dKP = P2; setlg(E2, k); S->dKE = E2; S->basis = RgM_to_RgXV(a, varn(f)); } GEN nfbasis(GEN x, GEN *pdK, GEN fa) { pari_sp av = avma; nfmaxord_t S; GEN B; nfmaxord(&S, fa? mkvec2(x,fa): x, 0); B = RgXV_unscale(S.basis, S.unscale); if (pdK) *pdK = S.dK; gerepileall(av, pdK? 2: 1, &B, pdK); return B; } GEN nfdisc(GEN x) { pari_sp av = avma; nfmaxord_t S; GEN O = get_maxord(&S, x, 0); long n = degpol(S.T), lP = lg(O), i, j; GEN index = gen_1; for (i=1; i f(x) */ u = Flx_gcd(f, Flx_deriv(f, p), p); /* (f,f') */ du = degpol(u); if (du) { if (du == (ulong)degpol(f)) f = Flx_radical(Flx_deflate(f,p), p); else { u = Flx_normalize(u, p); f = Flx_div(f, u, p); if (p <= du) { GEN w = Flxq_powu(f, du, u, p); w = Flx_div(u, Flx_gcd(w,u,p), p); /* u / gcd(u, v^(deg u-1)) */ f = Flx_mul(f, Flx_radical(Flx_deflate(w,p), p), p); } } } if (v0) f = Flx_shift(f, 1); return f; } /* Assume f reduced mod p, otherwise valuation at x may be wrong */ static GEN FpX_radical(GEN f, GEN p) { GEN u; long v0; if (lgefint(p) == 3) { ulong q = p[2]; return Flx_to_ZX( Flx_radical(ZX_to_Flx(f, q), q) ); } v0 = ZX_valrem(f, &f); u = FpX_gcd(f,FpX_deriv(f, p), p); if (degpol(u)) f = FpX_div(f, u, p); if (v0) f = RgX_shift(f, 1); return f; } /* f / a */ static GEN zx_z_div(GEN f, ulong a) { long i, l = lg(f); GEN g = cgetg(l, t_VECSMALL); g[1] = f[1]; for (i = 2; i < l; i++) g[i] = f[i] / a; return g; } /* Dedekind criterion; return k = gcd(g,h, (f-gh)/p), where * f = \prod f_i^e_i, g = \prod f_i, h = \prod f_i^{e_i-1} * k = 1 iff Z[X]/(f) is p-maximal */ static GEN ZX_Dedekind(GEN F, GEN *pg, GEN p) { GEN k, h, g, f, f2; ulong q = p[2]; if (lgefint(p) == 3 && q < (1UL << BITS_IN_HALFULONG)) { ulong q = p[2], q2 = q*q; f2 = ZX_to_Flx(F, q2); f = Flx_red(f2, q); g = Flx_radical(f, q); h = Flx_div(f, g, q); k = zx_z_div(Flx_sub(f2, Flx_mul(g,h,q2), q2), q); k = Flx_gcd(k, Flx_gcd(g,h,q), q); k = Flx_to_ZX(k); g = Flx_to_ZX(g); } else { f2 = FpX_red(F, sqri(p)); f = FpX_red(f2, p); g = FpX_radical(f, p); h = FpX_div(f, g, p); k = ZX_Z_divexact(ZX_sub(f2, ZX_mul(g,h)), p); k = FpX_gcd(FpX_red(k, p), FpX_gcd(g,h,p), p); } *pg = g; return k; } /* p-maximal order of Z[x]/f; mf = v_p(Disc(f)) or < 0 [unknown]. * Return gen_1 if p-maximal */ static GEN maxord(GEN p, GEN f, long mf) { const pari_sp av = avma; GEN res, g, k = ZX_Dedekind(f, &g, p); long dk = degpol(k); if (DEBUGLEVEL>2) err_printf(" ZX_dedekind: gcd has degree %ld\n", dk); if (!dk) { avma = av; return gen_1; } if (mf < 0) mf = ZpX_disc_val(f, p); k = FpX_normalize(k, p); if (2*dk >= mf-1) res = dbasis(p, f, mf, NULL, FpX_div(f,k,p)); else { GEN w, F1, F2; decomp_t S; F1 = FpX_factor(k,p); F2 = FpX_factor(FpX_div(g,k,p),p); w = merge_sort_uniq(gel(F1,1),gel(F2,1),(void*)cmpii,&gen_cmp_RgX); res = maxord_i(&S, p, f, mf, w, 0); } return gerepilecopy(av,res); } /* T monic separable ZX, p prime */ GEN ZpX_primedec(GEN T, GEN p) { const pari_sp av = avma; GEN w, F1, F2, res, g, k = ZX_Dedekind(T, &g, p); decomp_t S; if (!degpol(k)) return zm_to_ZM(FpX_degfact(T, p)); k = FpX_normalize(k, p); F1 = FpX_factor(k,p); F2 = FpX_factor(FpX_div(g,k,p),p); w = merge_sort_uniq(gel(F1,1),gel(F2,1),(void*)cmpii,&gen_cmp_RgX); res = maxord_i(&S, p, T, ZpX_disc_val(T, p), w, -1); if (!res) { long f = degpol(S.nu), e = degpol(T) / f; avma = av; retmkmat2(mkcols(f), mkcols(e)); } return gerepilecopy(av,res); } static GEN Zlx_sylvester_echelon(GEN f1, GEN f2, long early_abort, ulong p, ulong pm) { long j, n = degpol(f1); GEN h, a = cgetg(n+1,t_MAT); f1 = Flx_get_red(f1, pm); h = Flx_rem(f2,f1,pm); for (j=1;; j++) { gel(a,j) = Flx_to_Flv(h, n); if (j == n) break; h = Flx_rem(Flx_shift(h, 1), f1, pm); } return zlm_echelon(a, early_abort, p, pm); } /* Sylvester's matrix, mod p^m (assumes f1 monic). If early_abort * is set, return NULL if one pivot is 0 mod p^m */ static GEN ZpX_sylvester_echelon(GEN f1, GEN f2, long early_abort, GEN p, GEN pm) { long j, n = degpol(f1); GEN h, a = cgetg(n+1,t_MAT); h = FpXQ_red(f2,f1,pm); for (j=1;; j++) { gel(a,j) = RgX_to_RgC(h, n); if (j == n) break; h = FpX_rem(RgX_shift_shallow(h, 1), f1, pm); } return ZpM_echelon(a, early_abort, p, pm); } /* polynomial gcd mod p^m (assumes f1 monic). Return a QpX ! */ static GEN Zlx_gcd(GEN f1, GEN f2, ulong p, ulong pm) { pari_sp av = avma; GEN a = Zlx_sylvester_echelon(f1,f2,0,p,pm); long c, l = lg(a), sv = f1[1]; for (c = 1; c < l; c++) { ulong t = ucoeff(a,c,c); if (t) { a = Flx_to_ZX(Flv_to_Flx(gel(a,c), sv)); if (t == 1) return gerepilecopy(av, a); return gerepileupto(av, RgX_Rg_div(a, utoipos(t))); } } avma = av; a = cgetg(2,t_POL); a[1] = sv; return a; } GEN ZpX_gcd(GEN f1, GEN f2, GEN p, GEN pm) { pari_sp av = avma; GEN a; long c, l, v; if (lgefint(pm) == 3) { ulong q = pm[2]; return Zlx_gcd(ZX_to_Flx(f1, q), ZX_to_Flx(f2,q), p[2], q); } a = ZpX_sylvester_echelon(f1,f2,0,p,pm); l = lg(a); v = varn(f1); for (c = 1; c < l; c++) { GEN t = gcoeff(a,c,c); if (signe(t)) { a = RgV_to_RgX(gel(a,c), v); if (equali1(t)) return gerepilecopy(av, a); return gerepileupto(av, RgX_Rg_div(a, t)); } } avma = av; return pol_0(v); } /* Return m > 0, such that p^m ~ 2^16 for initial value of m; p > 1 */ static long init_m(GEN p) { if (lgefint(p) > 3) return 1; return (long)(16 / log2(p[2])); } /* reduced resultant mod p^m (assumes x monic) */ GEN ZpX_reduced_resultant(GEN x, GEN y, GEN p, GEN pm) { pari_sp av = avma; GEN z; if (lgefint(pm) == 3) { ulong q = pm[2]; z = Zlx_sylvester_echelon(ZX_to_Flx(x,q), ZX_to_Flx(y,q),0,p[2],q); if (lg(z) > 1) { ulong c = ucoeff(z,1,1); if (c) { avma = av; return utoipos(c); } } } else { z = ZpX_sylvester_echelon(x,y,0,p,pm); if (lg(z) > 1) { GEN c = gcoeff(z,1,1); if (signe(c)) return gerepileuptoint(av, c); } } avma = av; return gen_0; } /* Assume Res(f,g) divides p^M. Return Res(f, g), using dynamic p-adic * precision (until result is non-zero or p^M). */ GEN ZpX_reduced_resultant_fast(GEN f, GEN g, GEN p, long M) { GEN R, q = NULL; long m; m = init_m(p); if (m < 1) m = 1; for(;; m <<= 1) { if (M < 2*m) break; q = q? sqri(q): powiu(p, m); /* p^m */ R = ZpX_reduced_resultant(f,g, p, q); if (signe(R)) return R; } q = powiu(p, M); R = ZpX_reduced_resultant(f,g, p, q); return signe(R)? R: q; } /* v_p(Res(x,y) mod p^m), assumes (lc(x),p) = 1 */ static long ZpX_resultant_val_i(GEN x, GEN y, GEN p, GEN pm) { pari_sp av = avma; GEN z; long i, l, v; if (lgefint(pm) == 3) { ulong q = pm[2], pp = p[2]; z = Zlx_sylvester_echelon(ZX_to_Flx(x,q), ZX_to_Flx(y,q), 1, pp, q); if (!z) { avma = av; return -1; } /* failure */ v = 0; l = lg(z); for (i = 1; i < l; i++) v += u_lval(ucoeff(z,i,i), pp); } else { z = ZpX_sylvester_echelon(x, y, 1, p, pm); if (!z) { avma = av; return -1; } /* failure */ v = 0; l = lg(z); for (i = 1; i < l; i++) v += Z_pval(gcoeff(z,i,i), p); } return v; } /* assume (lc(f),p) = 1; no assumption on g */ long ZpX_resultant_val(GEN f, GEN g, GEN p, long M) { pari_sp av = avma; GEN q = NULL; long v, m; m = init_m(p); if (m < 2) m = 2; for(;; m <<= 1) { if (m > M) m = M; q = q? sqri(q): powiu(p, m); /* p^m */ v = ZpX_resultant_val_i(f,g, p, q); if (v >= 0) break; if (m == M) return M; } avma = av; return v; } /* assume f separable and (lc(f),p) = 1 */ long ZpX_disc_val(GEN f, GEN p) { pari_sp av = avma; long v; if (degpol(f) == 1) return 0; v = ZpX_resultant_val(f, ZX_deriv(f), p, LONG_MAX); avma = av; return v; } /* *e a ZX, *d, *z in Z, *d = p^(*vd). Simplify e / d by cancelling a * common factor p^v; if z!=NULL, update it by cancelling the same power of p */ static void update_den(GEN p, GEN *e, GEN *d, long *vd, GEN *z) { GEN newe; long ve = ZX_pvalrem(*e, p, &newe); if (ve) { GEN newd; long v = minss(*vd, ve); if (v) { if (v == *vd) { /* rare, denominator cancelled */ if (ve != v) newe = ZX_Z_mul(newe, powiu(p, ve - v)); newd = gen_1; *vd = 0; if (z) *z =diviiexact(*z, powiu(p, v)); } else { /* v = ve < vd, generic case */ GEN q = powiu(p, v); newd = diviiexact(*d, q); *vd -= v; if (z) *z = diviiexact(*z, q); } *e = newe; *d = newd; } } } /* return denominator, a power of p */ static GEN QpX_denom(GEN x) { long i, l = lg(x); GEN maxd = gen_1; for (i=2; i 0) maxd = gel(d,2); } return maxd; } static GEN QpXV_denom(GEN x) { long l = lg(x), i; GEN maxd = gen_1; for (i = 1; i < l; i++) { GEN d = QpX_denom(gel(x,i)); if (cmpii(d, maxd) > 0) maxd = d; } return maxd; } static GEN QpX_remove_denom(GEN x, GEN p, GEN *pdx, long *pv) { *pdx = QpX_denom(x); if (*pdx == gen_1) { *pv = 0; *pdx = NULL; } else { x = Q_muli_to_int(x,*pdx); *pv = Z_pval(*pdx, p); } return x; } /* p^v * f o g mod (T,q). q = p^vq */ static GEN compmod(GEN p, GEN f, GEN g, GEN T, GEN q, long v) { GEN D = NULL, z, df, dg, qD; long vD = 0, vdf, vdg; f = QpX_remove_denom(f, p, &df, &vdf); if (typ(g) == t_VEC) /* [num,den,v_p(den)] */ { vdg = itos(gel(g,3)); dg = gel(g,2); g = gel(g,1); } else g = QpX_remove_denom(g, p, &dg, &vdg); if (df) { D = df; vD = vdf; } if (dg) { long degf = degpol(f); D = mul_content(D, powiu(dg, degf)); vD += degf * vdg; } qD = D ? mulii(q, D): q; if (dg) f = FpX_rescale(f, dg, qD); z = FpX_FpXQ_eval(f, g, T, qD); if (!D) { if (v) { if (v > 0) z = ZX_Z_mul(z, powiu(p, v)); else z = RgX_Rg_div(z, powiu(p, -v)); } return z; } update_den(p, &z, &D, &vD, NULL); qD = mulii(D,q); if (v) vD -= v; z = FpX_center_i(z, qD, shifti(qD,-1)); if (vD > 0) z = RgX_Rg_div(z, powiu(p, vD)); else if (vD < 0) z = ZX_Z_mul(z, powiu(p, -vD)); return z; } /* fast implementation of ZM_hnfmodid(M, D) / D, D = p^k */ static GEN ZpM_hnfmodid(GEN M, GEN p, GEN D) { long i, l = lg(M); M = RgM_Rg_div(ZpM_echelon(M,0,p,D), D); for (i = 1; i < l; i++) if (gequal0(gcoeff(M,i,i))) gcoeff(M,i,i) = gen_1; return M; } /* Return Z-basis for Z[a] + U(a)/p Z[a] in Z[t]/(f), mf = v_p(disc f), U * a ZX. Special cases: a = t is coded as NULL, U = 0 is coded as NULL */ static GEN dbasis(GEN p, GEN f, long mf, GEN a, GEN U) { long n = degpol(f), i, dU; GEN b, h; if (n == 1) return matid(1); if (a && gequalX(a)) a = NULL; if (DEBUGLEVEL>5) { err_printf(" entering Dedekind Basis with parameters p=%Ps\n",p); err_printf(" f = %Ps,\n a = %Ps\n",f, a? a: pol_x(varn(f))); } if (a) { GEN pd = powiu(p, mf >> 1); GEN da, pdp = mulii(pd,p), D = pdp; long vda; dU = U ? degpol(U): 0; b = cgetg(n+1, t_MAT); h = scalarpol(pd, varn(f)); a = QpX_remove_denom(a, p, &da, &vda); if (da) D = mulii(D, da); gel(b,1) = scalarcol_shallow(pd, n); for (i=2; i<=n; i++) { if (i == dU+1) h = compmod(p, U, mkvec3(a,da,stoi(vda)), f, pdp, (mf>>1) - 1); else { h = FpXQ_mul(h, a, f, D); if (da) h = ZX_Z_divexact(h, da); } gel(b,i) = RgX_to_RgC(h,n); } return ZpM_hnfmodid(b, p, pd); } else { if (!U) return matid(n); dU = degpol(U); if (dU == n) return matid(n); U = FpX_normalize(U, p); b = cgetg(n+1, t_MAT); for (i = 1; i <= dU; i++) gel(b,i) = vec_ei(n, i); h = RgX_Rg_div(U, p); for ( ; i <= n; i++) { gel(b, i) = RgX_to_RgC(h,n); if (i == n) break; h = RgX_shift_shallow(h,1); } return b; } } static GEN get_partial_order_as_pols(GEN p, GEN f) { GEN O = maxord(p, f, -1); long v = varn(f); return O == gen_1? pol_x_powers(degpol(f), v): RgM_to_RgXV(O, v); } static long p_is_prime(decomp_t *S) { if (S->pisprime < 0) S->pisprime = BPSW_psp(S->p); return S->pisprime; } static GEN ZpX_monic_factor_squarefree(GEN f, GEN p, long prec); /* if flag = 0, maximal order, else factorization to precision r = flag */ static GEN Decomp(decomp_t *S, long flag) { pari_sp av = avma; GEN fred, pr2, pr, pk, ph2, ph, b1, b2, a, e, de, f1, f2, dt, th, chip; GEN p = S->p; long vde, vdt, k, r = maxss(flag, 2*S->df + 1); if (DEBUGLEVEL>5) err_printf(" entering Decomp: %Ps^%ld\n f = %Ps\n", p, r, S->f); else if (DEBUGLEVEL>2) err_printf(" entering Decomp\n"); chip = FpX_red(S->chi, p); if (!FpX_valrem(chip, S->nu, p, &b1)) { if (!p_is_prime(S)) pari_err_PRIME("Decomp",p); pari_err_BUG("Decomp (not a factor)"); } b2 = FpX_div(chip, b1, p); a = FpX_mul(FpXQ_inv(b2, b1, p), b2, p); /* E = e / de, e in Z[X], de in Z, E = a(phi) mod (f, p) */ th = QpX_remove_denom(S->phi, p, &dt, &vdt); if (dt) { long dega = degpol(a); vde = dega * vdt; de = powiu(dt, dega); pr = mulii(p, de); a = FpX_rescale(a, dt, pr); } else { vde = 0; de = gen_1; pr = p; } e = FpX_FpXQ_eval(a, th, S->f, pr); update_den(p, &e, &de, &vde, NULL); pk = p; k = 1; /* E, (1 - E) tend to orthogonal idempotents in Zp[X]/(f) */ while (k < r + vde) { /* E <-- E^2(3-2E) mod p^2k, with E = e/de */ GEN D; pk = sqri(pk); k <<= 1; e = ZX_mul(ZX_sqr(e), Z_ZX_sub(mului(3,de), gmul2n(e,1))); de= mulii(de, sqri(de)); vde *= 3; D = mulii(pk, de); e = FpX_rem(e, centermod(S->f, D), D); /* e/de defined mod pk */ update_den(p, &e, &de, &vde, NULL); } /* required precision of the factors */ pr = powiu(p, r); pr2 = shifti(pr, -1); ph = mulii(de,pr);ph2 = shifti(ph, -1); fred = FpX_center_i(FpX_red(S->f, ph), ph, ph2); e = FpX_center_i(FpX_red(e, ph), ph, ph2); f1 = ZpX_gcd(fred, Z_ZX_sub(de, e), p, ph); /* p-adic gcd(f, 1-e) */ fred = FpX_center_i(fred, pr, pr2); f1 = FpX_center_i(f1, pr, pr2); f2 = FpX_div(fred,f1, pr); f2 = FpX_center_i(f2, pr, pr2); if (DEBUGLEVEL>5) err_printf(" leaving Decomp: f1 = %Ps\nf2 = %Ps\ne = %Ps\nde= %Ps\n", f1,f2,e,de); if (flag < 0) { GEN m = vconcat(ZpX_primedec(f1, p), ZpX_primedec(f2, p)); return sort_factor(m, (void*)&cmpii, &cmp_nodata); } else if (flag) { gerepileall(av, 2, &f1, &f2); return shallowconcat(ZpX_monic_factor_squarefree(f1, p, flag), ZpX_monic_factor_squarefree(f2, p, flag)); } else { GEN D, d1, d2, B1, B2, M; long n, n1, n2, i; gerepileall(av, 4, &f1, &f2, &e, &de); D = de; B1 = get_partial_order_as_pols(p,f1); n1 = lg(B1)-1; B2 = get_partial_order_as_pols(p,f2); n2 = lg(B2)-1; n = n1+n2; d1 = QpXV_denom(B1); d2 = QpXV_denom(B2); if (cmpii(d1, d2) < 0) d1 = d2; if (d1 != gen_1) { B1 = Q_muli_to_int(B1, d1); B2 = Q_muli_to_int(B2, d1); D = mulii(d1, D); } fred = centermod_i(S->f, D, shifti(D,-1)); M = cgetg(n+1, t_MAT); for (i=1; i<=n1; i++) gel(M,i) = RgX_to_RgC(FpX_rem(FpX_mul(gel(B1,i),e,D), fred, D), n); e = Z_ZX_sub(de, e); B2 -= n1; for ( ; i<=n; i++) gel(M,i) = RgX_to_RgC(FpX_rem(FpX_mul(gel(B2,i),e,D), fred, D), n); return ZpM_hnfmodid(M, p, D); } } /* minimum extension valuation: L/E */ static void vstar(GEN p,GEN h, long *L, long *E) { long first, j, k, v, w, m = degpol(h); first = 1; k = 1; v = 0; for (j=1; j<=m; j++) { GEN c = gel(h, m-j+2); if (signe(c)) { w = Z_pval(c,p); if (first || w*k < v*j) { v = w; k = j; } first = 0; } } /* v/k = min_j ( v_p(h_{m-j}) / j ) */ w = (long)ugcd(v,k); *L = v/w; *E = k/w; } static GEN redelt_i(GEN a, GEN N, GEN p, GEN *pda, long *pvda) { GEN z; a = Q_remove_denom(a, pda); *pvda = 0; if (*pda) { long v = Z_pvalrem(*pda, p, &z); if (v) { *pda = powiu(p, v); *pvda = v; N = mulii(*pda, N); } else *pda = NULL; if (!is_pm1(z)) a = ZX_Z_mul(a, Fp_inv(z, N)); } return centermod(a, N); } /* reduce the element a modulo N [ a power of p ], taking first care of the * denominators */ static GEN redelt(GEN a, GEN N, GEN p) { GEN da; long vda; a = redelt_i(a, N, p, &da, &vda); if (da) a = RgX_Rg_div(a, da); return a; } /* compute the c first Newton sums modulo pp of the characteristic polynomial of a/d mod chi, d > 0 power of p (NULL = gen_1), a, chi in Zp[X], vda = v_p(da) ns = Newton sums of chi */ static GEN newtonsums(GEN p, GEN a, GEN da, long vda, GEN chi, long c, GEN pp, GEN ns) { GEN va, pa, dpa, s; long j, k, vdpa, lns = lg(ns); pari_sp av; a = centermod(a, pp); av = avma; dpa = pa = NULL; /* -Wall */ vdpa = 0; va = zerovec(c); for (j = 1; j <= c; j++) { /* pa/dpa = (a/d)^(j-1) mod (chi, pp), dpa = p^vdpa */ long l; pa = j == 1? a: FpXQ_mul(pa, a, chi, pp); l = lg(pa); if (l == 2) break; if (lns < l) l = lns; if (da) { dpa = j == 1? da: mulii(dpa, da); vdpa += vda; update_den(p, &pa, &dpa, &vdpa, &pp); } s = mulii(gel(pa,2), gel(ns,2)); /* k = 2 */ for (k = 3; k < l; k++) s = addii(s, mulii(gel(pa,k), gel(ns,k))); if (da) { GEN r; s = dvmdii(s, dpa, &r); if (r != gen_0) return NULL; } gel(va,j) = centermodii(s, pp, shifti(pp,-1)); if (gc_needed(av, 1)) { if(DEBUGMEM>1) pari_warn(warnmem, "newtonsums"); gerepileall(av, dpa?4:3, &pa, &va, &pp, &dpa); } } for (; j <= c; j++) gel(va,j) = gen_0; return va; } /* compute the characteristic polynomial of a/da mod chi (a in Z[X]), given * by its Newton sums to a precision of pp using Newton sums */ static GEN newtoncharpoly(GEN pp, GEN p, GEN NS) { long n = lg(NS)-1, j, k; GEN c = cgetg(n + 2, t_VEC), pp2 = shifti(pp,-1); gel(c,1) = (n & 1 ? gen_m1: gen_1); for (k = 2; k <= n+1; k++) { pari_sp av2 = avma; GEN s = gen_0; ulong z; long v = u_pvalrem(k - 1, p, &z); for (j = 1; j < k; j++) { GEN t = mulii(gel(NS,j), gel(c,k-j)); if (!odd(j)) t = negi(t); s = addii(s, t); } if (v) { s = gdiv(s, powiu(p, v)); if (typ(s) != t_INT) return NULL; } s = mulii(s, Fp_inv(utoipos(z), pp)); gel(c,k) = gerepileuptoint(av2, Fp_center_i(s, pp, pp2)); } for (k = odd(n)? 1: 2; k <= n+1; k += 2) gel(c,k) = negi(gel(c,k)); return gtopoly(c, 0); } static void manage_cache(decomp_t *S, GEN f, GEN pp) { GEN t = S->precns; if (!t) t = mulii(S->pmf, powiu(S->p, S->df)); if (cmpii(t, pp) < 0) t = pp; if (!S->precns || !RgX_equal(f, S->nsf) || cmpii(S->precns, t) < 0) { if (DEBUGLEVEL>4) err_printf(" Precision for cached Newton sums for %Ps: %Ps -> %Ps\n", f, S->precns? S->precns: gen_0, t); S->nsf = f; S->ns = FpX_Newton(f, degpol(f), t); S->precns = t; } } /* return NULL if a mod f is not an integer * The denominator of any integer in Zp[X]/(f) divides pdr */ static GEN mycaract(decomp_t *S, GEN f, GEN a, GEN pp, GEN pdr) { pari_sp av; GEN d, chi, prec1, prec2, prec3, ns; long vd, n = degpol(f); if (gequal0(a)) return pol_0(varn(f)); a = QpX_remove_denom(a, S->p, &d, &vd); prec1 = pp; if (lgefint(S->p) == 3) prec1 = mulii(prec1, powiu(S->p, factorial_lval(n, itou(S->p)))); if (d) { GEN p1 = powiu(d, n); prec2 = mulii(prec1, p1); prec3 = mulii(prec1, gmin_shallow(mulii(p1, d), pdr)); } else prec2 = prec3 = prec1; manage_cache(S, f, prec3); av = avma; ns = newtonsums(S->p, a, d, vd, f, n, prec2, S->ns); if (!ns) return NULL; chi = newtoncharpoly(prec1, S->p, ns); if (!chi) return NULL; setvarn(chi, varn(f)); return gerepileupto(av, centermod(chi, pp)); } static GEN get_nu(GEN chi, GEN p, long *ptl) { /* split off powers of x first for efficiency */ long v = ZX_valrem(FpX_red(chi,p), &chi), n; GEN P; if (!degpol(chi)) { *ptl = 1; return pol_x(varn(chi)); } P = gel(FpX_factor(chi,p), 1); n = lg(P)-1; *ptl = v? n+1: n; return gel(P,n); } /* Factor characteristic polynomial chi of phi mod p. If it splits, update * S->{phi, chi, nu} and return 1. In any case, set *nu to an irreducible * factor mod p of chi */ static int split_char(decomp_t *S, GEN chi, GEN phi, GEN phi0, GEN *nu) { long l; *nu = get_nu(chi, S->p, &l); if (l == 1) return 0; /* single irreducible factor: doesn't split */ /* phi o phi0 mod (p, f) */ S->phi = compmod(S->p, phi, phi0, S->f, S->p, 0); S->chi = chi; S->nu = *nu; return 1; } /* Return the prime element in Zp[phi], a t_INT (iff *Ep = 1) or QX; * nup, chip are ZX. phi = NULL codes X * If *Ep < oE or Ep divides Ediv (!=0) return NULL (uninteresting) */ static GEN getprime(decomp_t *S, GEN phi, GEN chip, GEN nup, long *Lp, long *Ep, long oE, long Ediv) { GEN z, chin, q, qp; long r, s; if (phi && dvdii(constant_coeff(chip), S->psc)) { chip = mycaract(S, S->chi, phi, S->pmf, S->prc); if (dvdii(constant_coeff(chip), S->pmf)) chip = ZXQ_charpoly(phi, S->chi, varn(chip)); } if (degpol(nup) == 1) { GEN c = gel(nup,2); /* nup = X + c */ chin = signe(c)? RgX_translate(chip, negi(c)): chip; } else chin = ZXQ_charpoly(nup, chip, varn(chip)); vstar(S->p, chin, Lp, Ep); if (*Ep < oE || (Ediv && Ediv % *Ep == 0)) return NULL; if (*Ep == 1) return S->p; (void)cbezout(*Lp, -*Ep, &r, &s); /* = 1 */ if (r <= 0) { long t = 1 + ((-r) / *Ep); r += t * *Ep; s += t * *Lp; } /* r > 0 minimal such that r L/E - s = 1/E * pi = nu^r / p^s is an element of valuation 1/E, * so is pi + O(p) since 1/E < 1. May compute nu^r mod p^(s+1) */ q = powiu(S->p, s); qp = mulii(q, S->p); nup = FpXQ_powu(nup, r, S->chi, qp); if (!phi) return RgX_Rg_div(nup, q); /* phi = X : no composition */ z = compmod(S->p, nup, phi, S->chi, qp, -s); return signe(z)? z: NULL; } static int update_phi(decomp_t *S) { GEN PHI = NULL, prc, psc, X = pol_x(varn(S->f)); long k; for (k = 1;; k++) { prc = ZpX_reduced_resultant_fast(S->chi, ZX_deriv(S->chi), S->p, S->vpsc); if (!equalii(prc, S->psc)) break; /* increase precision */ S->vpsc = maxss(S->vpsf, S->vpsc + 1); S->psc = (S->vpsc == S->vpsf)? S->psf: mulii(S->psc, S->p); PHI = S->phi; if (S->phi0) PHI = compmod(S->p, PHI, S->phi0, S->f, S->psc, 0); PHI = gadd(PHI, ZX_Z_mul(X, mului(k, S->p))); S->chi = mycaract(S, S->f, PHI, S->psc, S->pdf); } psc = mulii(sqri(prc), S->p); if (!PHI) /* ok above for k = 1 */ { PHI = S->phi; if (S->phi0) { PHI = compmod(S->p, PHI, S->phi0, S->f, psc, 0); S->chi = mycaract(S, S->f, PHI, psc, S->pdf); } } S->phi = PHI; S->chi = FpX_red(S->chi, psc); /* may happen if p is unramified */ if (is_pm1(prc)) return 0; S->psc = psc; S->vpsc = 2*Z_pval(prc, S->p) + 1; S->prc = mulii(prc, S->p); return 1; } /* return 1 if at least 2 factors mod p ==> chi splits * Replace S->phi such that F increases (to D) */ static int testb2(decomp_t *S, long D, GEN theta) { long v = varn(S->chi), dlim = degpol(S->chi)-1; GEN T0 = S->phi, chi, phi, nu; if (DEBUGLEVEL>4) err_printf(" Increasing Fa\n"); for (;;) { phi = gadd(theta, random_FpX(dlim, v, S->p)); chi = mycaract(S, S->chi, phi, S->psf, S->prc); /* phi non-primary ? */ if (split_char(S, chi, phi, T0, &nu)) return 1; if (degpol(nu) == D) break; } /* F_phi=lcm(F_alpha, F_theta)=D and E_phi=E_alpha */ S->phi0 = T0; S->chi = chi; S->phi = phi; S->nu = nu; return 0; } /* return 1 if at least 2 factors mod p ==> chi can be split. * compute a new S->phi such that E = lcm(Ea, Et); * A a ZX, T a t_INT (iff Et = 1, probably impossible ?) or QX */ static int testc2(decomp_t *S, GEN A, long Ea, GEN T, long Et) { GEN c, chi, phi, nu, T0 = S->phi; if (DEBUGLEVEL>4) err_printf(" Increasing Ea\n"); if (Et == 1) /* same as other branch, split for efficiency */ c = A; /* Et = 1 => s = 1, r = 0, t = 0 */ else { long r, s, t; (void)cbezout(Ea, Et, &r, &s); t = 0; while (r < 0) { r = r + Et; t++; } while (s < 0) { s = s + Ea; t++; } /* A^s T^r / p^t */ c = RgXQ_mul(RgXQ_powu(A, s, S->chi), RgXQ_powu(T, r, S->chi), S->chi); c = RgX_Rg_div(c, powiu(S->p, t)); c = redelt(c, S->psc, S->p); } phi = RgX_add(c, pol_x(varn(S->chi))); chi = mycaract(S, S->chi, phi, S->psf, S->prc); if (split_char(S, chi, phi, T0, &nu)) return 1; /* E_phi = lcm(E_alpha,E_theta) */ S->phi0 = T0; S->chi = chi; S->phi = phi; S->nu = nu; return 0; } /* Return h^(-degpol(P)) P(x * h) if result is integral, NULL otherwise */ static GEN ZX_rescale_inv(GEN P, GEN h) { long i, l = lg(P); GEN Q = cgetg(l,t_POL), hi = h; gel(Q,l-1) = gel(P,l-1); for (i=l-2; i>=2; i--) { GEN r; gel(Q,i) = dvmdii(gel(P,i), hi, &r); if (signe(r)) return NULL; if (i == 2) break; hi = mulii(hi,h); } Q[1] = P[1]; return Q; } /* x p^-eq nu^-er mod p */ static GEN get_gamma(decomp_t *S, GEN x, long eq, long er) { GEN q, g = x, Dg = powiu(S->p, eq); long vDg = eq; if (er) { if (!S->invnu) { while (gdvd(S->chi, S->nu)) S->nu = RgX_Rg_add(S->nu, S->p); S->invnu = QXQ_inv(S->nu, S->chi); S->invnu = redelt_i(S->invnu, S->psc, S->p, &S->Dinvnu, &S->vDinvnu); } if (S->Dinvnu) { Dg = mulii(Dg, powiu(S->Dinvnu, er)); vDg += er * S->vDinvnu; } q = mulii(S->p, Dg); g = ZX_mul(g, FpXQ_powu(S->invnu, er, S->chi, q)); g = FpX_rem(g, S->chi, q); update_den(S->p, &g, &Dg, &vDg, NULL); g = centermod(g, mulii(S->p, Dg)); } if (!is_pm1(Dg)) g = RgX_Rg_div(g, Dg); return g; } static GEN get_g(decomp_t *S, long Ea, long L, long E, GEN beta, GEN *pchig, long *peq, long *per) { long eq, er; GEN g, chig, chib = NULL; for(;;) /* at most twice */ { if (L < 0) { chib = ZXQ_charpoly(beta, S->chi, varn(S->chi)); vstar(S->p, chib, &L, &E); } eq = L / E; er = L*Ea / E - eq*Ea; /* floor(L Ea/E) = eq Ea + er */ if (er || !chib) { /* g might not be an integer ==> chig = NULL */ g = get_gamma(S, beta, eq, er); chig = mycaract(S, S->chi, g, S->psc, S->prc); } else { /* g = beta/p^eq, special case of the above */ GEN h = powiu(S->p, eq); g = RgX_Rg_div(beta, h); chig = ZX_rescale_inv(chib, h); /* chib(x h) / h^N */ if (chig) chig = FpX_red(chig, S->pmf); } /* either success or second consecutive failure */ if (chig || chib) break; /* if g fails the v*-test, v(beta) was wrong. Retry once */ L = -1; } *pchig = chig; *peq = eq; *per = er; return g; } /* return 1 if at least 2 factors mod p ==> chi can be split */ static int loop(decomp_t *S, long Ea) { pari_sp av = avma; GEN beta = FpXQ_powu(S->nu, Ea, S->chi, S->p); long N = degpol(S->f), v = varn(S->f); S->invnu = NULL; for (;;) { /* beta tends to a factor of chi */ long L, i, Fg, eq, er; GEN chig = NULL, d, g, nug; if (DEBUGLEVEL>4) err_printf(" beta = %Ps\n", beta); L = ZpX_resultant_val(S->chi, beta, S->p, S->mf+1); if (L > S->mf) L = -1; /* from scratch */ g = get_g(S, Ea, L, N, beta, &chig, &eq, &er); if (DEBUGLEVEL>4) err_printf(" (eq,er) = (%ld,%ld)\n", eq,er); /* g = beta p^-eq nu^-er (a unit), chig = charpoly(g) */ if (split_char(S, chig, g,S->phi, &nug)) return 1; Fg = degpol(nug); if (Fg == 1) { /* frequent special case nug = x - d */ long Le, Ee; GEN chie, nue, e, pie; d = negi(gel(nug,2)); chie = RgX_translate(chig, d); nue = pol_x(v); e = RgX_Rg_sub(g, d); pie = getprime(S, e, chie, nue, &Le, &Ee, 0,Ea); if (pie) return testc2(S, S->nu, Ea, pie, Ee); } else { long Fa = degpol(S->nu), vdeng; GEN deng, numg, nume; if (Fa % Fg) return testb2(S, ulcm(Fa,Fg), g); /* nu & nug irreducible mod p, deg nug | deg nu. To improve beta, look * for a root d of nug in Fp[phi] such that v_p(g - d) > 0 */ if (ZX_equal(nug, S->nu)) d = pol_x(v); else { if (!p_is_prime(S)) pari_err_PRIME("FpX_ffisom",S->p); d = FpX_ffisom(nug, S->nu, S->p); } /* write g = numg / deng, e = nume / deng */ numg = QpX_remove_denom(g, S->p, &deng, &vdeng); for (i = 1; i <= Fg; i++) { GEN chie, nue, e; if (i != 1) d = FpXQ_pow(d, S->p, S->nu, S->p); /* next root */ nume = ZX_sub(numg, ZX_Z_mul(d, deng)); /* test e = nume / deng */ if (ZpX_resultant_val(S->chi, nume, S->p, vdeng*N+1) <= vdeng*N) continue; e = RgX_Rg_div(nume, deng); chie = mycaract(S, S->chi, e, S->psc, S->prc); if (split_char(S, chie, e,S->phi, &nue)) return 1; if (RgX_is_monomial(nue)) { /* v_p(e) = v_p(g - d) > 0 */ long Le, Ee; GEN pie; pie = getprime(S, e, chie, nue, &Le, &Ee, 0,Ea); if (pie) return testc2(S, S->nu, Ea, pie, Ee); break; } } if (i > Fg) { if (!p_is_prime(S)) pari_err_PRIME("nilord",S->p); pari_err_BUG("nilord (no root)"); } } if (eq) d = gmul(d, powiu(S->p, eq)); if (er) d = gmul(d, gpowgs(S->nu, er)); beta = gsub(beta, d); if (gc_needed(av,1)) { if (DEBUGMEM > 1) pari_warn(warnmem, "nilord"); gerepileall(av, S->invnu? 6: 4, &beta, &(S->precns), &(S->ns), &(S->nsf), &(S->invnu), &(S->Dinvnu)); } } } /* E and F cannot decrease; return 1 if O = Zp[phi], 2 if we can get a * decomposition and 0 otherwise */ static long progress(decomp_t *S, GEN *ppa, long *pE) { long E = *pE, F; GEN pa = *ppa; S->phi0 = NULL; /* no delayed composition */ for(;;) { long l, La, Ea; /* N.B If E = 0, getprime cannot return NULL */ GEN pia = getprime(S, NULL, S->chi, S->nu, &La, &Ea, E,0); if (pia) { /* success, we break out in THIS loop */ pa = (typ(pia) == t_POL)? RgX_RgXQ_eval(pia, S->phi, S->f): pia; E = Ea; if (La == 1) break; /* no need to change phi so that nu = pia */ } /* phi += prime elt */ S->phi = typ(pa) == t_INT? RgX_Rg_add_shallow(S->phi, pa) : RgX_add(S->phi, pa); /* recompute char. poly. chi from scratch */ S->chi = mycaract(S, S->f, S->phi, S->psf, S->pdf); S->nu = get_nu(S->chi, S->p, &l); if (l > 1) return 2; if (!update_phi(S)) return 1; /* unramified */ if (pia) break; } *pE = E; *ppa = pa; F = degpol(S->nu); if (DEBUGLEVEL>4) err_printf(" (E, F) = (%ld,%ld)\n", E, F); if (E * F == degpol(S->f)) return 1; if (loop(S, E)) return 2; if (!update_phi(S)) return 1; return 0; } /* flag != 0 iff we're looking for the p-adic factorization, in which case it is the p-adic precision we want */ static GEN maxord_i(decomp_t *S, GEN p, GEN f, long mf, GEN w, long flag) { long oE, n = lg(w)-1; /* factor of largest degree */ GEN opa, D = ZpX_reduced_resultant_fast(f, ZX_deriv(f), p, mf); S->pisprime = -1; S->p = p; S->mf = mf; S->nu = gel(w,n); S->df = Z_pval(D, p); S->pdf = powiu(p, S->df); S->phi = pol_x(varn(f)); S->chi = S->f = f; if (n > 1) return Decomp(S, flag); /* FIXME: use bezout_lift_fact */ if (DEBUGLEVEL>4) err_printf(" entering Nilord: %Ps^%ld\n f = %Ps, nu = %Ps\n", p, S->df, S->f, S->nu); else if (DEBUGLEVEL>2) err_printf(" entering Nilord\n"); S->psf = S->psc = mulii(sqri(D), p); S->vpsf = S->vpsc = 2*S->df + 1; S->prc = mulii(D, p); S->chi = FpX_red(S->f, S->psc); S->pmf = powiu(p, S->mf+1); S->precns = NULL; for(opa = NULL, oE = 0;;) { long n = progress(S, &opa, &oE); if (n == 1) return flag? NULL: dbasis(p, S->f, S->mf, S->phi, S->chi); if (n == 2) return Decomp(S, flag); } } static int expo_is_squarefree(GEN e) { long i, l = lg(e); for (i=1; i 0. Return list of * irreducible factors in Zp[X] (computed mod p^prec) */ static GEN ZpX_monic_factor_squarefree(GEN f, GEN p, long prec) { pari_sp av = avma; GEN L, fa, w, e; long i, l; if (degpol(f) == 1) return mkvec(f); fa = FpX_factor(f,p); w = gel(fa,1); e = gel(fa,2); /* no repeated factors: Hensel lift */ if (expo_is_squarefree(e)) return ZpX_liftfact(f, w, powiu(p,prec), p, prec); l = lg(w); if (l == 2) { L = ZpX_round4(f,p,w,prec); if (lg(L) == 2) { avma = av; return mkvec(f); } } else { /* >= 2 factors mod p: partial Hensel lift */ GEN D = ZpX_reduced_resultant_fast(f, ZX_deriv(f), p, ZpX_disc_val(f,p)); long r = maxss(2*Z_pval(D,p)+1, prec); GEN W = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(W,i) = e[i] == 1? gel(w,i): FpX_powu(gel(w,i), e[i], p); L = ZpX_liftfact(f, W, powiu(p,r), p, r); for (i = 1; i < l; i++) gel(L,i) = e[i] == 1? mkvec(gel(L,i)) : ZpX_round4(gel(L,i), p, mkvec(gel(w,i)), prec); L = shallowconcat1(L); } return gerepilecopy(av, L); } /* assume f a ZX with leading_coeff 1, degree > 0 */ GEN ZpX_monic_factor(GEN f, GEN p, long prec) { GEN poly, ex, P, E; long l, i; if (degpol(f) == 1) return mkmat2(mkcol(f), mkcol(gen_1)); poly = ZX_squff(f,&ex); l = lg(poly); P = cgetg(l, t_VEC); E = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN L = ZpX_monic_factor_squarefree(gel(poly,i), p, prec); gel(P,i) = L; settyp(L, t_COL); gel(E,i) = const_col(lg(L)-1, utoipos(ex[i])); } return mkmat2(shallowconcat1(P), shallowconcat1(E)); } /* DT = multiple of disc(T) or NULL * Return a multiple of the denominator of an algebraic integer (in Q[X]/(T)) * when expressed in terms of the power basis */ GEN indexpartial(GEN T, GEN DT) { pari_sp av = avma; long i, nb; GEN fa, E, P, res = gen_1, dT = ZX_deriv(T); if (!DT) DT = ZX_disc(T); fa = absZ_factor_limit(DT, 0); P = gel(fa,1); E = gel(fa,2); nb = lg(P)-1; for (i = 1; i <= nb; i++) { long e = itou(gel(E,i)), e2 = e >> 1; GEN p = gel(P,i), q = p; if (i == nb) q = powiu(p, (odd(e) && !BPSW_psp(p))? e2+1: e2); else if (e2 >= 2) q = ZpX_reduced_resultant_fast(T, dT, p, e2); res = mulii(res, q); } return gerepileuptoint(av,res); } /*******************************************************************/ /* */ /* 2-ELT REPRESENTATION FOR PRIME IDEALS (dividing index) */ /* */ /*******************************************************************/ /* to compute norm of elt in basis form */ typedef struct { long r1; GEN M; /* via embed_norm */ GEN D, w, T; /* via resultant if M = NULL */ } norm_S; static GEN get_norm(norm_S *S, GEN a) { if (S->M) { long e; GEN N = grndtoi( embed_norm(RgM_RgC_mul(S->M, a), S->r1), &e ); if (e > -5) pari_err_PREC( "get_norm"); return N; } if (S->w) a = RgV_RgC_mul(S->w, a); return ZX_resultant_all(S->T, a, S->D, 0); } static void init_norm(norm_S *S, GEN nf, GEN p) { GEN T = nf_get_pol(nf), M = nf_get_M(nf); long N = degpol(T), ex = gexpo(M) + gexpo(mului(8 * N, p)); S->r1 = nf_get_r1(nf); if (N * ex <= prec2nbits(gprecision(M)) - 20) { /* enough prec to use embed_norm */ S->M = M; S->D = NULL; S->w = NULL; S->T = NULL; } else { GEN w = leafcopy(nf_get_zkprimpart(nf)), D = nf_get_zkden(nf), Dp = sqri(p); long i; if (!equali1(D)) { GEN w1 = D; long v = Z_pval(D, p); D = powiu(p, v); Dp = mulii(D, Dp); gel(w, 1) = remii(w1, Dp); } for (i=2; i<=N; i++) gel(w,i) = FpX_red(gel(w,i), Dp); S->M = NULL; S->D = D; S->w = w; S->T = T; } } /* f = f(pr/p), q = p^(f+1), a in pr. * Return 1 if v_pr(a) = 1, and 0 otherwise */ static int is_uniformizer(GEN a, GEN q, norm_S *S) { return !dvdii(get_norm(S,a), q); } /* Return x * y, x, y are t_MAT (Fp-basis of in O_K/p), assume (x,y)=1. * Either x or y may be NULL (= O_K), not both */ static GEN mul_intersect(GEN x, GEN y, GEN p) { if (!x) return y; if (!y) return x; return FpM_intersect(x, y, p); } /* Fp-basis of (ZK/pr): applied to the primes found in primedec_aux() * true nf */ static GEN Fp_basis(GEN nf, GEN pr) { long i, j, l; GEN x, y; /* already in basis form (from Buchman-Lenstra) ? */ if (typ(pr) == t_MAT) return pr; /* ordinary prid (from Kummer) */ x = pr_hnf(nf, pr); l = lg(x); y = cgetg(l, t_MAT); for (i=j=1; i=2; i--) gel(B,i-1) = mul_intersect(gel(B,i), gel(LW,i), p); for (i=1; i<=l; i++) gel(LV,i) = mul_intersect(gel(A,i), gel(B,i), p); return LV; } static void errprime(GEN p) { pari_err_PRIME("idealprimedec",p); } /* P = Fp-basis (over O_K/p) for pr. * V = Z-basis for I_p/pr. ramif != 0 iff some pr|p is ramified. * Return a p-uniformizer for pr. Assume pr not inert, i.e. m > 0 */ static GEN uniformizer(GEN nf, norm_S *S, GEN P, GEN V, GEN p, int ramif) { long i, l, f, m = lg(P)-1, N = nf_get_degree(nf); GEN u, Mv, x, q; f = N - m; /* we want v_p(Norm(x)) = p^f */ q = powiu(p,f+1); u = FpM_FpC_invimage(shallowconcat(P, V), col_ei(N,1), p); setlg(u, lg(P)); u = centermod(ZM_ZC_mul(P, u), p); if (is_uniformizer(u, q, S)) return u; if (signe(gel(u,1)) <= 0) /* make sure u[1] in ]-p,p] */ gel(u,1) = addii(gel(u,1), p); /* try u + p */ else gel(u,1) = subii(gel(u,1), p); /* try u - p */ if (!ramif || is_uniformizer(u, q, S)) return u; /* P/p ramified, u in P^2, not in Q for all other Q|p */ Mv = zk_multable(nf, Z_ZC_sub(gen_1,u)); l = lg(P); for (i=1; i1) */ t = poltobasis(nf, FpX_div(T,u,p)); t = centermod(t, p); u = FpX_center_i(u, p, shifti(p,-1)); if (e == 1 && ZpX_resultant_val(T, u, p, f+1) > f) gel(u,2) = addii(gel(u,2), p); u = poltobasis(nf,u); t = zk_multable(nf, t); /* t never a scalar here since pr is not inert */ } return mk_pr(p,u,e,f,t); } typedef struct { GEN nf, p; long I; } eltmod_muldata; static GEN sqr_mod(void *data, GEN x) { eltmod_muldata *D = (eltmod_muldata*)data; return FpC_red(nfsqri(D->nf, x), D->p); } static GEN ei_msqr_mod(void *data, GEN x) { GEN x2 = sqr_mod(data, x); eltmod_muldata *D = (eltmod_muldata*)data; return FpC_red(zk_ei_mul(D->nf, x2, D->I), D->p); } /* nf a true nf; compute lift(nf.zk[I]^p mod p) */ static GEN pow_ei_mod_p(GEN nf, long I, GEN p) { pari_sp av = avma; eltmod_muldata D; long N = nf_get_degree(nf); GEN y = col_ei(N,I); if (I == 1) return y; D.nf = nf; D.p = p; D.I = I; y = gen_pow_fold(y, p, (void*)&D, &sqr_mod, &ei_msqr_mod); return gerepileupto(av,y); } /* nf a true nf; return a Z basis of Z_K's p-radical, phi = x--> x^p-x */ static GEN pradical(GEN nf, GEN p, GEN *phi) { long i, N = nf_get_degree(nf); GEN q,m,frob,rad; /* matrix of Frob: x->x^p over Z_K/p */ frob = cgetg(N+1,t_MAT); for (i=1; i<=N; i++) gel(frob,i) = pow_ei_mod_p(nf,i,p); m = frob; q = p; while (abscmpiu(q,N) < 0) { q = mulii(q,p); m = FpM_mul(m, frob, p); } rad = FpM_ker(m, p); /* m = Frob^k, s.t p^k >= N */ for (i=1; i<=N; i++) gcoeff(frob,i,i) = subiu(gcoeff(frob,i,i), 1); *phi = frob; return rad; } /* return powers of a: a^0, ... , a^d, d = dim A */ static GEN get_powers(GEN mul, GEN p) { long i, d = lgcols(mul); GEN z, pow = cgetg(d+2,t_MAT), P = pow+1; gel(P,0) = scalarcol_shallow(gen_1, d-1); z = gel(mul,1); for (i=1; i<=d; i++) { gel(P,i) = z; /* a^i */ if (i!=d) z = FpM_FpC_mul(mul, z, p); } return pow; } /* minimal polynomial of a in A (dim A = d). * mul = multiplication table by a in A */ static GEN pol_min(GEN mul, GEN p) { pari_sp av = avma; GEN z = FpM_deplin(get_powers(mul, p), p); return gerepilecopy(av, RgV_to_RgX(z,0)); } static GEN get_pr(GEN nf, norm_S *S, GEN p, GEN P, GEN V, int ramif, long N, long flim) { GEN u, t; long e, f; if (typ(P) == t_VEC) { /* already done (Kummer) */ f = pr_get_f(P); if (flim > 0 && f > flim) return NULL; if (flim == -2) return (GEN)f; return P; } f = N - (lg(P)-1); if (flim > 0 && f > flim) return NULL; if (flim == -2) return (GEN)f; /* P = (p,u) prime. t is an anti-uniformizer: Z_K + t/p Z_K = P^(-1), * so that v_P(t) = e(P/p)-1 */ if (f == N) { u = scalarcol_shallow(p,N); t = gen_1; e = 1; } else { GEN mt; u = uniformizer(nf, S, P, V, p, ramif); t = FpM_deplin(zk_multable(nf,u), p); mt = zk_multable(nf, t); e = ramif? 1 + ZC_nfval(t,mk_pr(p,u,0,0,mt)): 1; t = mt; } return mk_pr(p,u,e,f,t); } /* true nf */ static GEN primedec_end(GEN nf, GEN L, GEN p, long flim) { long i, j, l = lg(L), N = nf_get_degree(nf); GEN LV = get_LV(nf, L,p,N); int ramif = dvdii(nf_get_disc(nf), p); norm_S S; init_norm(&S, nf, p); for (i = j = 1; i < l; i++) { GEN P = get_pr(nf, &S, p, gel(L,i), gel(LV,i), ramif, N, flim); if (!P) continue; gel(L,j++) = P; if (flim == -1) return P; } setlg(L, j); return L; } /* prime ideal decomposition of p; if flim>0, restrict to f(P,p) <= flim * if flim = -1 return only the first P * if flim = -2 return only the f(P/p) in a t_VECSMALL */ static GEN primedec_aux(GEN nf, GEN p, long flim) { const long TYP = (flim == -2)? t_VECSMALL: t_VEC; GEN E, F, L, Ip, phi, f, g, h, UN, T = nf_get_pol(nf); long i, k, c, iL, N; int kummer; F = FpX_factor(T, p); E = gel(F,2); F = gel(F,1); k = lg(F); if (k == 1) errprime(p); if ( !dvdii(nf_get_index(nf),p) ) /* p doesn't divide index */ { L = cgetg(k, TYP); for (i=1; i 0 && f > flim) { setlg(L, i); break; } if (flim == -2) L[i] = f; else gel(L,i) = idealprimedec_kummer(nf, t, E[i],p); if (flim == -1) return gel(L,1); } return L; } kummer = 0; g = FpXV_prod(F, p); h = FpX_div(T,g,p); f = FpX_red(ZX_Z_divexact(ZX_sub(ZX_mul(g,h), T), p), p); N = degpol(T); L = cgetg(N+1,TYP); iL = 1; for (i=1; i x^p - x in algebra Z_K/p */ Ip = pradical(nf,p,&phi); /* split etale algebra Z_K / (p,Ip) */ h = cgetg(N+1,t_VEC); if (kummer) { /* split off Kummer factors */ GEN mb, b = NULL; for (i=1; i M2 * Mi2 projector A --> A2 */ GEN M, Mi, M2, Mi2, phi2, mat1, H = gel(h,c); /* maximal rank */ long dim, r = lg(H)-1; M = FpM_suppl(shallowconcat(H,UN), p); Mi = FpM_inv(M, p); M2 = vecslice(M, r+1,N); /* M = (H|M2) invertible */ Mi2 = rowslice(Mi,r+1,N); /* FIXME: FpM_mul(,M2) could be done with vecpermute */ phi2 = FpM_mul(Mi2, FpM_mul(phi,M2, p), p); mat1 = FpM_ker(phi2, p); dim = lg(mat1)-1; /* A2 product of 'dim' fields */ if (dim > 1) { /* phi2 v = 0 => a = M2 v in Ker phi, a not in Fp.1 + H */ GEN R, a, mula, mul2, v = gel(mat1,2); long n; a = FpM_FpC_mul(M2,v, p); /* not a scalar */ mula = FpM_red(zk_multable(nf,a), p); mul2 = FpM_mul(Mi2, FpM_mul(mula,M2, p), p); R = FpX_roots(pol_min(mul2,p), p); /* totally split mod p */ n = lg(R)-1; for (i=1; i<=n; i++) { GEN I = RgM_Rg_sub_shallow(mula, gel(R,i)); gel(h,c++) = FpM_image(shallowconcat(H, I), p); } if (n == dim) for (i=1; i<=n; i++) gel(L,iL++) = gel(h,--c); } else /* A2 field ==> H maximal, f = N-r = dim(A2) */ gel(L,iL++) = H; } setlg(L, iL); return primedec_end(nf, L, p, flim); } GEN idealprimedec_limit_f(GEN nf, GEN p, long f) { pari_sp av = avma; GEN v; if (typ(p) != t_INT) pari_err_TYPE("idealprimedec",p); if (f < 0) pari_err_DOMAIN("idealprimedec", "f", "<", gen_0, stoi(f)); v = primedec_aux(checknf(nf), p, f); v = gen_sort(v, (void*)&cmp_prime_over_p, &cmp_nodata); return gerepileupto(av,v); } GEN idealprimedec_galois(GEN nf, GEN p) { pari_sp av = avma; GEN v = primedec_aux(checknf(nf), p, -1); return gerepilecopy(av,v); } GEN idealprimedec_degrees(GEN nf, GEN p) { pari_sp av = avma; GEN v = primedec_aux(checknf(nf), p, -2); vecsmall_sort(v); return gerepileuptoleaf(av, v); } GEN idealprimedec_limit_norm(GEN nf, GEN p, GEN B) { return idealprimedec_limit_f(nf, p, logint(B,p)); } GEN idealprimedec(GEN nf, GEN p) { return idealprimedec_limit_f(nf, p, 0); } GEN nf_pV_to_prV(GEN nf, GEN P) { long i, l; GEN Q = cgetg_copy(P,&l); if (l == 1) return Q; for (i = 1; i < l; i++) gel(Q,i) = idealprimedec(nf, gel(P,i)); return shallowconcat1(Q); } /* return [Fp[x]: Fp] */ static long ffdegree(GEN x, GEN frob, GEN p) { pari_sp av = avma; long d, f = lg(frob)-1; GEN y = x; for (d=1; d < f; d++) { y = FpM_FpC_mul(frob, y, p); if (ZV_equal(y, x)) break; } avma = av; return d; } static GEN lift_to_zk(GEN v, GEN c, long N) { GEN w = zerocol(N); long i, l = lg(c); for (i=1; i= e(Q/p) for other Q | p */ z = ZM_hnfmodid(FpM_red(b,p), p); /* ideal (p) / pr^e, coprime to pr */ z = idealaddtoone_raw(nf, pr, z); return Z_ZC_sub(gen_1, FpC_center(FpC_red(z,p), p, shifti(p,-1))); } #define mpr_TAU 1 #define mpr_FFP 2 #define mpr_NFP 5 #define SMALLMODPR 4 #define LARGEMODPR 6 static GEN modpr_TAU(GEN modpr) { GEN tau = gel(modpr,mpr_TAU); return isintzero(tau)? NULL: tau; } /* prh = HNF matrix, which is identity but for the first line. Return a * projector to ZK / prh ~ Z/prh[1,1] */ GEN dim1proj(GEN prh) { long i, N = lg(prh)-1; GEN ffproj = cgetg(N+1, t_VEC); GEN x, q = gcoeff(prh,1,1); gel(ffproj,1) = gen_1; for (i=2; i<=N; i++) { x = gcoeff(prh,1,i); if (signe(x)) x = subii(q,x); gel(ffproj,i) = x; } return ffproj; } /* p not necessarily prime, but coprime to denom(basis) */ GEN QXQV_to_FpM(GEN basis, GEN T, GEN p) { long i, l = lg(basis), f = degpol(T); GEN z = cgetg(l, t_MAT); for (i = 1; i < l; i++) { GEN w = gel(basis,i); if (typ(w) == t_INT) w = scalarcol_shallow(w, f); else { GEN dx; w = Q_remove_denom(w, &dx); w = FpXQ_red(w, T, p); if (dx) { dx = Fp_inv(dx, p); if (!equali1(dx)) w = FpX_Fp_mul(w, dx, p); } w = RgX_to_RgC(w, f); } gel(z,i) = w; /* w_i mod (T,p) */ } return z; } /* initialize reduction mod pr; if zk = 1, will only init data required to * reduce *integral* element. Realize (O_K/pr) as Fp[X] / (T), for a * *monic* T */ static GEN modprinit(GEN nf, GEN pr, int zk) { pari_sp av = avma; GEN res, tau, mul, x, p, T, pow, ffproj, nfproj, prh, c; long N, i, k, f; nf = checknf(nf); checkprid(pr); f = pr_get_f(pr); N = nf_get_degree(nf); prh = pr_hnf(nf, pr); tau = zk? gen_0: anti_uniformizer(nf, pr); p = pr_get_p(pr); if (f == 1) { res = cgetg(SMALLMODPR, t_COL); gel(res,mpr_TAU) = tau; gel(res,mpr_FFP) = dim1proj(prh); gel(res,3) = pr; return gerepilecopy(av, res); } c = cgetg(f+1, t_VECSMALL); ffproj = cgetg(N+1, t_MAT); for (k=i=1; i<=N; i++) { x = gcoeff(prh, i,i); if (!is_pm1(x)) { c[k] = i; gel(ffproj,i) = col_ei(N, i); k++; } else gel(ffproj,i) = ZC_neg(gel(prh,i)); } ffproj = rowpermute(ffproj, c); if (! dvdii(nf_get_index(nf), p)) { GEN basis = nf_get_zkprimpart(nf), D = nf_get_zkden(nf); if (N == f) { /* pr inert */ T = nf_get_pol(nf); T = FpX_red(T,p); ffproj = RgV_to_RgM(basis, lg(basis)-1); } else { T = RgV_RgC_mul(basis, pr_get_gen(pr)); T = FpX_normalize(T,p); basis = FqV_red(vecpermute(basis,c), T, p); basis = RgV_to_RgM(basis, lg(basis)-1); ffproj = ZM_mul(basis, ffproj); } ffproj = FpM_red(ffproj, p); if (!equali1(D)) { D = modii(D,p); if (!equali1(D)) ffproj = FpM_Fp_mul(ffproj, Fp_inv(D,p), p); } res = cgetg(SMALLMODPR+1, t_COL); gel(res,mpr_TAU) = tau; gel(res,mpr_FFP) = ffproj; gel(res,3) = pr; gel(res,4) = T; return gerepilecopy(av, res); } if (uisprime(f)) { mul = ei_multable(nf, c[2]); mul = vecpermute(mul, c); } else { GEN v, u, u2, frob; long deg,deg1,deg2; /* matrix of Frob: x->x^p over Z_K/pr = < w[c1], ..., w[cf] > over Fp */ frob = cgetg(f+1, t_MAT); for (i=1; i<=f; i++) { x = pow_ei_mod_p(nf,c[i],p); gel(frob,i) = FpM_FpC_mul(ffproj, x, p); } u = col_ei(f,2); k = 2; deg1 = ffdegree(u, frob, p); while (deg1 < f) { k++; u2 = col_ei(f, k); deg2 = ffdegree(u2, frob, p); deg = ulcm(deg1,deg2); if (deg == deg1) continue; if (deg == deg2) { deg1 = deg2; u = u2; continue; } u = ZC_add(u, u2); while (ffdegree(u, frob, p) < deg) u = ZC_add(u, u2); deg1 = deg; } v = lift_to_zk(u,c,N); mul = cgetg(f+1,t_MAT); gel(mul,1) = v; /* assume w_1 = 1 */ for (i=2; i<=f; i++) gel(mul,i) = zk_ei_mul(nf,v,c[i]); } /* Z_K/pr = Fp(v), mul = mul by v */ mul = FpM_red(mul, p); mul = FpM_mul(ffproj, mul, p); pow = get_powers(mul, p); T = RgV_to_RgX(FpM_deplin(pow, p), nf_get_varn(nf)); nfproj = cgetg(f+1, t_MAT); for (i=1; i<=f; i++) gel(nfproj,i) = lift_to_zk(gel(pow,i), c, N); setlg(pow, f+1); ffproj = FpM_mul(FpM_inv(pow, p), ffproj, p); res = cgetg(LARGEMODPR, t_COL); gel(res,mpr_TAU) = tau; gel(res,mpr_FFP) = ffproj; gel(res,3) = pr; gel(res,4) = T; gel(res,mpr_NFP) = nfproj; return gerepilecopy(av, res); } GEN nfmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 0); } GEN zkmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 1); } /* x may be a modpr */ static int ok_modpr(GEN x) { return typ(x) == t_COL && lg(x) >= SMALLMODPR && lg(x) <= LARGEMODPR; } void checkmodpr(GEN x) { if (!ok_modpr(x)) pari_err_TYPE("checkmodpr [use nfmodprinit]", x); checkprid(modpr_get_pr(x)); } GEN get_modpr(GEN x) { return ok_modpr(x)? x: NULL; } int checkprid_i(GEN x) { return (typ(x) == t_VEC && lg(x) == 6 && typ(gel(x,2)) == t_COL && typ(gel(x,3)) == t_INT && typ(gel(x,5)) != t_COL); /* tau changed to t_MAT/t_INT in 2.6 */ } void checkprid(GEN x) { if (!checkprid_i(x)) pari_err_TYPE("checkprid",x); } GEN get_prid(GEN x) { long lx = lg(x); if (lx == 3 && typ(x) == t_VEC) x = gel(x,1); if (checkprid_i(x)) return x; if (ok_modpr(x)) { x = modpr_get_pr(x); if (checkprid_i(x)) return x; } return NULL; } static GEN to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p, int zk) { GEN modpr = ok_modpr(*pr)? *pr: modprinit(nf, *pr, zk); *T = modpr_get_T(modpr); *pr = modpr_get_pr(modpr); *p = pr_get_p(*pr); return modpr; } /* Return an element of O_K which is set to x Mod T */ GEN modpr_genFq(GEN modpr) { switch(lg(modpr)) { case SMALLMODPR: /* Fp */ return gen_1; case LARGEMODPR: /* painful case, p \mid index */ return gmael(modpr,mpr_NFP, 2); default: /* trivial case : p \nmid index */ { long v = varn( modpr_get_T(modpr) ); return pol_x(v); } } } GEN nf_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p) { GEN modpr = to_ff_init(nf,pr,T,p,0); GEN tau = modpr_TAU(modpr); if (!tau) gel(modpr,mpr_TAU) = anti_uniformizer(nf, *pr); return modpr; } GEN zk_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p) { return to_ff_init(nf,pr,T,p,1); } /* assume x in 'basis' form (t_COL) */ GEN zk_to_Fq(GEN x, GEN modpr) { GEN pr = modpr_get_pr(modpr), p = pr_get_p(pr); GEN ffproj = gel(modpr,mpr_FFP); GEN T = modpr_get_T(modpr); return T? FpM_FpC_mul_FpX(ffproj,x, p, varn(T)): FpV_dotproduct(ffproj,x, p); } /* REDUCTION Modulo a prime ideal */ /* nf a true nf */ static GEN Rg_to_ff(GEN nf, GEN x0, GEN modpr) { GEN x = x0, den, pr = modpr_get_pr(modpr), p = pr_get_p(pr); long tx = typ(x); if (tx == t_POLMOD) { x = gel(x,2); tx = typ(x); } switch(tx) { case t_INT: return modii(x, p); case t_FRAC: return Rg_to_Fp(x, p); case t_POL: switch(lg(x)) { case 2: return gen_0; case 3: return Rg_to_Fp(gel(x,2), p); } x = Q_remove_denom(x, &den); x = poltobasis(nf, x); /* content(x) and den may not be coprime */ break; case t_COL: x = Q_remove_denom(x, &den); /* content(x) and den are coprime */ if (lg(x)-1 == nf_get_degree(nf)) break; default: pari_err_TYPE("Rg_to_ff",x); return NULL;/*LCOV_EXCL_LINE*/ } if (den) { long v = Z_pvalrem(den, p, &den); if (v) { if (tx == t_POL) v -= ZV_pvalrem(x, p, &x); /* now v = valuation(true denominator of x) */ if (v > 0) { GEN tau = modpr_TAU(modpr); if (!tau) pari_err_TYPE("zk_to_ff", x0); x = nfmuli(nf,x, nfpow_u(nf, tau, v)); v -= ZV_pvalrem(x, p, &x); } if (v > 0) pari_err_INV("Rg_to_ff", mkintmod(gen_0,p)); if (v) return gen_0; if (is_pm1(den)) den = NULL; } x = FpC_red(x, p); } x = zk_to_Fq(x, modpr); if (den) { GEN c = Fp_inv(den, p); x = typ(x) == t_INT? Fp_mul(x,c,p): FpX_Fp_mul(x,c,p); } return x; } GEN nfreducemodpr(GEN nf, GEN x, GEN modpr) { pari_sp av = avma; nf = checknf(nf); checkmodpr(modpr); return gerepileupto(av, algtobasis(nf, Fq_to_nf(Rg_to_ff(nf,x,modpr),modpr))); } GEN nfmodpr(GEN nf, GEN x, GEN pr) { pari_sp av = avma; GEN T, p, modpr; nf = checknf(nf); modpr = nf_to_Fq_init(nf, &pr, &T, &p); x = Rg_to_ff(nf, x, modpr); x = Fq_to_FF(x, Tp_to_FF(T,p)); return gerepilecopy(av, x); } GEN nfmodprlift(GEN nf, GEN x, GEN pr) { pari_sp av = avma; GEN y, T, p, modpr; long i, l, d; nf = checknf(nf); switch(typ(x)) { case t_INT: return icopy(x); case t_FFELT: break; case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x,&l); for (i = 1; i < l; i++) gel(y,i) = nfmodprlift(nf,gel(x,i),pr); return y; default: pari_err_TYPE("nfmodprlit",x); } x = FF_to_FpXQ_i(x); d = degpol(x); if (d <= 0) { avma = av; return d? gen_0: icopy(gel(x,2)); } modpr = nf_to_Fq_init(nf, &pr, &T, &p); return gerepilecopy(av, Fq_to_nf(x, modpr)); } /* lift A from residue field to nf */ GEN Fq_to_nf(GEN A, GEN modpr) { long dA; if (typ(A) == t_INT || lg(modpr) < LARGEMODPR) return A; dA = degpol(A); if (dA <= 0) return dA ? gen_0: gel(A,2); return ZM_ZX_mul(gel(modpr,mpr_NFP), A); } GEN FqV_to_nfV(GEN x, GEN modpr) { pari_APPLY_same(Fq_to_nf(gel(x,i), modpr)) } GEN FqM_to_nfM(GEN A, GEN modpr) { long i,j,h,l = lg(A); GEN B = cgetg(l, t_MAT); if (l == 1) return B; h = lgcols(A); for (j=1; j= db) { long i, k = da; GEN A = gel(a, k+2); for (i = db-1, k--; i >= 0; i--, k--) gel(a,k+2) = nfsub(nf, gel(a,k+2), nfmul(nf, A, gel(b,i+2))); a = normalizepol_lg(a, lg(a)-1); da = degpol(a); } return a; } static GEN nfXQ_mul(GEN nf, GEN a, GEN b, GEN T) { GEN c = nfX_mul(nf, a, b); if (typ(c) != t_POL) return c; return nfX_rem(nf, c, T); } static void fill(long l, GEN H, GEN Hx, GEN I, GEN Ix) { long i; if (typ(Ix) == t_VEC) /* standard */ for (i=1; imultab,x) : tablemul_ei_ej(D->multab,D->h,D->h); return FqV_red(z,D->T,D->p); } static GEN _msqr(void *data, GEN x) { GEN x2 = _sqr(data, x), z; rnfeltmod_muldata *D = (rnfeltmod_muldata *) data; z = tablemul_ei(D->multab, x2, D->h); return FqV_red(z,D->T,D->p); } /* Compute W[h]^n mod (T,p) in the extension, assume n >= 0. T a ZX */ static GEN rnfeltid_powmod(GEN multab, long h, GEN n, GEN T, GEN p) { pari_sp av = avma; GEN y; rnfeltmod_muldata D; if (!signe(n)) return gen_1; D.multab = multab; D.h = h; D.T = T; D.p = p; y = gen_pow_fold(NULL, n, (void*)&D, &_sqr, &_msqr); return gerepilecopy(av, y); } /* P != 0 has at most degpol(P) roots. Look for an element in Fq which is not * a root, cf repres() */ static GEN FqX_non_root(GEN P, GEN T, GEN p) { long dP = degpol(P), f, vT; long i, j, k, pi, pp; GEN v; if (dP == 0) return gen_1; pp = is_bigint(p) ? dP+1: itos(p); v = cgetg(dP + 2, t_VEC); gel(v,1) = gen_0; if (T) { f = degpol(T); vT = varn(T); } else { f = 1; vT = 0; } for (i=pi=1; i<=f; i++,pi*=pp) { GEN gi = i == 1? gen_1: pol_xn(i-1, vT), jgi = gi; for (j=1; j only_maximal = 1 */ { if (mpr < 0) return NULL; if (! RgX_valrem(Ppr, &Ppr)) { /* non-zero constant coefficient */ Ppr = RgX_shift_shallow(RgX_recip_shallow(Ppr), m - mpr); P = RgX_recip_shallow(P); } else { GEN z = FqX_non_root(Ppr, T, p); if (!z) pari_err_IMPL( "Dedekind in the difficult case"); z = Fq_to_nf(z, modpr); if (typ(z) == t_INT) P = RgX_translate(P, z); else P = RgXQX_translate(P, z, T); P = RgX_recip_shallow(P); Ppr = nfX_to_FqX(P, nf, modpr); /* degpol(P) = degpol(Ppr) = m */ } } A = gel(FqX_factor(Ppr,T,p),1); r = lg(A); /* > 1 */ g = gel(A,1); for (i=2; i nfval(nf,b,pr)) a = b; return a; } /* nf a true nf. Return NULL if power order if pr-maximal */ static GEN rnfmaxord(GEN nf, GEN pol, GEN pr, long vdisc) { pari_sp av = avma, av1; long i, j, k, n, nn, vpol, cnt, sep; GEN q, q1, p, T, modpr, W, I, p1; GEN prhinv, mpi, Id; if (DEBUGLEVEL>1) err_printf(" treating %Ps^%ld\n", pr, vdisc); modpr = nf_to_Fq_init(nf,&pr,&T,&p); av1 = avma; p1 = rnfdedekind_i(nf, pol, modpr, vdisc, 0); if (!p1) { avma = av; return NULL; } if (is_pm1(gel(p1,1))) return gerepilecopy(av,gel(p1,2)); sep = itos(gel(p1,3)); W = gmael(p1,2,1); I = gmael(p1,2,2); gerepileall(av1, 2, &W, &I); mpi = zk_multable(nf, pr_get_gen(pr)); n = degpol(pol); nn = n*n; vpol = varn(pol); q1 = q = pr_norm(pr); while (abscmpiu(q1,n) < 0) q1 = mulii(q1,q); Id = matid(n); prhinv = pr_inv(pr); av1 = avma; for(cnt=1;; cnt++) { GEN I0 = leafcopy(I), W0 = leafcopy(W); GEN Wa, Winv, Ip, A, MW, MWmod, F, pseudo, C, G; GEN Tauinv = cgetg(n+1, t_VEC), Tau = cgetg(n+1, t_VEC); if (DEBUGLEVEL>1) err_printf(" pass no %ld\n",cnt); for (j=1; j<=n; j++) { GEN tau, tauinv; if (ideal_is1(gel(I,j))) { gel(I,j) = gel(Tau,j) = gel(Tauinv,j) = gen_1; continue; } gel(Tau,j) = tau = minval(nf, gel(I,j), pr); gel(Tauinv,j) = tauinv = nfinv(nf, tau); gel(W,j) = nfC_nf_mul(nf, gel(W,j), tau); gel(I,j) = idealmul(nf, tauinv, gel(I,j)); /* v_pr(I[j]) = 0 */ } /* W = (Z_K/pr)-basis of O/pr. O = (W0,I0) ~ (W, I) */ /* compute MW: W_i*W_j = sum MW_k,(i,j) W_k */ Wa = RgM_to_RgXV(W,vpol); Winv = nfM_inv(nf, W); MW = cgetg(nn+1, t_MAT); /* W_1 = 1 */ for (j=1; j<=n; j++) gel(MW, j) = gel(MW, (j-1)*n+1) = gel(Id,j); for (i=2; i<=n; i++) for (j=i; j<=n; j++) { GEN z = nfXQ_mul(nf, gel(Wa,i), gel(Wa,j), pol); if (typ(z) != t_POL) z = nfC_nf_mul(nf, gel(Winv,1), z); else { z = RgX_to_RgC(z, lg(Winv)-1); z = nfM_nfC_mul(nf, Winv, z); } gel(MW, (i-1)*n+j) = gel(MW, (j-1)*n+i) = z; } /* compute Ip = pr-radical [ could use Ker(trace) if q large ] */ MWmod = nfM_to_FqM(MW,nf,modpr); F = cgetg(n+1, t_MAT); gel(F,1) = gel(Id,1); for (j=2; j<=n; j++) gel(F,j) = rnfeltid_powmod(MWmod, j, q1, T,p); Ip = FqM_ker(F,T,p); if (lg(Ip) == 1) { W = W0; I = I0; break; } /* Fill C: W_k A_j = sum_i C_(i,j),k A_i */ A = FqM_to_nfM(FqM_suppl(Ip,T,p), modpr); for (j = lg(Ip); j<=n; j++) gel(A,j) = nfC_multable_mul(gel(A,j), mpi); MW = nfM_mul(nf, nfM_inv(nf,A), MW); C = cgetg(n+1, t_MAT); for (k=1; k<=n; k++) { GEN mek = vecslice(MW, (k-1)*n+1, k*n), Ck; gel(C,k) = Ck = cgetg(nn+1, t_COL); for (j=1; j<=n; j++) { GEN z = nfM_nfC_mul(nf, mek, gel(A,j)); for (i=1; i<=n; i++) gel(Ck, (j-1)*n+i) = nf_to_Fq(nf,gel(z,i),modpr); } } G = FqM_to_nfM(FqM_ker(C,T,p), modpr); pseudo = rnfjoinmodules_i(nf, G,prhinv, Id,I); /* express W in terms of the power basis */ W = nfM_mul(nf, W, gel(pseudo,1)); I = gel(pseudo,2); /* restore the HNF property W[i,i] = 1. NB: W upper triangular, with * W[i,i] = Tau[i] */ for (j=1; j<=n; j++) if (gel(Tau,j) != gen_1) { gel(W,j) = nfC_nf_mul(nf, gel(W,j), gel(Tauinv,j)); gel(I,j) = idealmul(nf, gel(Tau,j), gel(I,j)); } if (DEBUGLEVEL>3) err_printf(" new order:\n%Ps\n%Ps\n", W, I); if (sep <= 3 || gequal(I,I0)) break; if (gc_needed(av1,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"rnfmaxord"); gerepileall(av1,2, &W,&I); } } return gerepilecopy(av, mkvec2(W, I)); } GEN Rg_nffix(const char *f, GEN T, GEN c, int lift) { switch(typ(c)) { case t_INT: case t_FRAC: return c; case t_POL: if (lg(c) >= lg(T)) c = RgX_rem(c,T); break; case t_POLMOD: if (!RgX_equal_var(gel(c,1), T)) pari_err_MODULUS(f, gel(c,1),T); c = gel(c,2); switch(typ(c)) { case t_POL: break; case t_INT: case t_FRAC: return c; default: pari_err_TYPE(f, c); } break; default: pari_err_TYPE(f,c); } /* typ(c) = t_POL */ if (varn(c) != varn(T)) pari_err_VAR(f, c,T); switch(lg(c)) { case 2: return gen_0; case 3: c = gel(c,2); if (is_rational_t(typ(c))) return c; pari_err_TYPE(f,c); } RgX_check_QX(c, f); return lift? c: mkpolmod(c, T); } /* check whether P is a polynomials with coeffs in number field Q[y]/(T) */ GEN RgX_nffix(const char *f, GEN T, GEN P, int lift) { long i, l, vT = varn(T); GEN Q = cgetg_copy(P, &l); if (typ(P) != t_POL) pari_err_TYPE(stack_strcat(f," [t_POL expected]"), P); if (varncmp(varn(P), vT) >= 0) pari_err_PRIORITY(f, P, ">=", vT); Q[1] = P[1]; for (i=2; i 0) { c = gcoeff(H,i,i); ic = i; } if (!ic) break; vj[j++] = ic; U = shallowconcat(H, gel(vU, ic)); } setlg(vj, j); B = vecpermute(B, vj); l = lg(B); A = cgetg(l,t_MAT); for (j = 1; j < l; j++) { GEN t = eltabstorel_lift(rnfeq, gel(B,j)); gel(A,j) = Rg_to_RgC(t, n); } A = RgM_to_nfM(nf, A); A = Q_remove_denom(A, &dA); if (!dA) { /* order is maximal */ z = triv_order(n); if (pf) *pf = gen_1; } else { GEN fi; /* the first n columns of A are probably in HNF already */ A = shallowconcat(vecslice(A,n+1,lg(A)-1), vecslice(A,1,n)); A = mkvec2(A, const_vec(l-1,gen_1)); if (DEBUGLEVEL > 2) err_printf("rnfallbase: nfhnf in dim %ld\n", l-1); z = nfhnfmod(nf, A, nfdetint(nf,A)); gel(z,2) = gdiv(gel(z,2), dA); fi = idealprod(nf,gel(z,2)); D = idealmul(nf, D, idealsqr(nf, fi)); if (pf) *pf = idealinv(nf, fi); } if (RgM_isscalar(D,NULL)) D = gcoeff(D,1,1); *pD = mkvec2(D, get_d(nf, disc)); return z; } pol = lift_shallow(pol); fa = idealfactor_limit(nf, disc, lim); P = gel(fa,1); l = lg(P); z = NULL; E = gel(fa,2); Pf = cgetg(l, t_COL); Ef = cgetg(l, t_COL); for (i = j = jf = 1; i < l; i++) { GEN pr = gel(P,i); long e = itos(gel(E,i)); if (e > 1) { GEN vD = rnfmaxord(nf, pol, pr, e); if (vD) { long ef = idealprodval(nf, gel(vD,2), pr); z = rnfjoinmodules(nf, z, vD); if (ef) { gel(Pf, jf) = pr; gel(Ef, jf++) = stoi(-ef); } e += 2 * ef; } } if (e) { gel(P, j) = pr; gel(E, j++) = stoi(e); } } setlg(P,j); setlg(E,j); if (pf) { setlg(Pf, jf); setlg(Ef, jf); *pf = pr_factorback_scal(nf, mkmat2(Pf,Ef)); } *pD = mkvec2(pr_factorback_scal(nf,fa), get_d(nf, disc)); return z? z: triv_order(degpol(pol)); } GEN rnfpseudobasis(GEN nf, GEN pol) { pari_sp av = avma; GEN D, z; ulong lim; nf = checknf(nf); pol = check_polrel(nf, pol, &lim); z = rnfallbase(nf, pol, lim, NULL, &D, NULL); return gerepilecopy(av, shallowconcat(z,D)); } GEN rnfdisc_factored(GEN nf, GEN pol, GEN *pd) { long i, j, l; ulong lim; GEN fa, E, P, disc; nf = checknf(nf); pol = check_polrel(nf, pol, &lim); disc = nf_to_scalar_or_basis(nf, RgX_disc(pol)); pol = lift_shallow(pol); fa = idealfactor_limit(nf, disc, lim); P = gel(fa,1); l = lg(P); E = gel(fa,2); for (i = j = 1; i < l; i++) { long e = itos(gel(E,i)); GEN pr = gel(P,i); if (e > 1) { GEN vD = rnfmaxord(nf, pol, pr, e); if (vD) e += 2*idealprodval(nf, gel(vD,2), pr); } if (e) { gel(P, j) = pr; gel(E, j++) = stoi(e); } } if (pd) *pd = get_d(nf, disc); setlg(P, j); setlg(E, j); return fa; } GEN rnfdiscf(GEN nf, GEN pol) { pari_sp av = avma; GEN d, fa = rnfdisc_factored(nf, pol, &d); return gerepilecopy(av, mkvec2(pr_factorback_scal(nf,fa), d)); } GEN gen_if_principal(GEN bnf, GEN x) { pari_sp av = avma; GEN z = bnfisprincipal0(bnf,x, nf_GEN_IF_PRINCIPAL | nf_FORCE); if (isintzero(z)) { avma = av; return NULL; } return z; } static int is_pseudo_matrix(GEN O) { return (typ(O) ==t_VEC && lg(O) >= 3 && typ(gel(O,1)) == t_MAT && typ(gel(O,2)) == t_VEC && lgcols(O) == lg(gel(O,2))); } /* given bnf and a pseudo-basis of an order in HNF [A,I], tries to simplify * the HNF as much as possible. The resulting matrix will be upper triangular * but the diagonal coefficients will not be equal to 1. The ideals are * guaranteed to be integral and primitive. */ GEN rnfsimplifybasis(GEN bnf, GEN x) { pari_sp av = avma; long i, l; GEN y, Az, Iz, nf, A, I; bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); if (!is_pseudo_matrix(x)) pari_err_TYPE("rnfsimplifybasis",x); A = gel(x,1); I = gel(x,2); l = lg(I); y = cgetg(3, t_VEC); Az = cgetg(l, t_MAT); gel(y,1) = Az; Iz = cgetg(l, t_VEC); gel(y,2) = Iz; for (i = 1; i < l; i++) { GEN c, d; if (ideal_is1(gel(I,i))) { gel(Iz,i) = gen_1; gel(Az,i) = gel(A,i); continue; } gel(Iz,i) = Q_primitive_part(gel(I,i), &c); gel(Az,i) = c? RgC_Rg_mul(gel(A,i),c): gel(A,i); if (c && ideal_is1(gel(Iz,i))) continue; d = gen_if_principal(bnf, gel(Iz,i)); if (d) { gel(Iz,i) = gen_1; gel(Az,i) = nfC_nf_mul(nf, gel(Az,i), d); } } return gerepilecopy(av, y); } static GEN get_order(GEN nf, GEN O, const char *s) { if (typ(O) == t_POL) return rnfpseudobasis(nf, O); if (!is_pseudo_matrix(O)) pari_err_TYPE(s, O); return O; } GEN rnfdet(GEN nf, GEN order) { pari_sp av = avma; GEN A, I, D; nf = checknf(nf); order = get_order(nf, order, "rnfdet"); A = gel(order,1); I = gel(order,2); D = idealmul(nf, nfM_det(nf,A), idealprod(nf,I)); return gerepileupto(av, D); } /* Given two fractional ideals a and b, gives x in a, y in b, z in b^-1, t in a^-1 such that xt-yz=1. In the present version, z is in Z. */ static void nfidealdet1(GEN nf, GEN a, GEN b, GEN *px, GEN *py, GEN *pz, GEN *pt) { GEN x, uv, y, da, db; a = idealinv(nf,a); a = Q_remove_denom(a, &da); b = Q_remove_denom(b, &db); x = idealcoprime(nf,a,b); uv = idealaddtoone(nf, idealmul(nf,x,a), b); y = gel(uv,2); if (da) x = gmul(x,da); if (db) y = gdiv(y,db); *px = x; *py = y; *pz = db ? negi(db): gen_m1; *pt = nfdiv(nf, gel(uv,1), x); } /* given a pseudo-basis of an order in HNF [A,I] (or [A,I,D,d]), gives an * n x n matrix (not in HNF) of a pseudo-basis and an ideal vector * [1,1,...,1,I] such that order = Z_K^(n-1) x I. * Uses the approximation theorem ==> slow. */ GEN rnfsteinitz(GEN nf, GEN order) { pari_sp av = avma; long i, n, l; GEN A, I, p1; nf = checknf(nf); order = get_order(nf, order, "rnfsteinitz"); A = RgM_to_nfM(nf, gel(order,1)); I = leafcopy(gel(order,2)); n=lg(A)-1; for (i=1; in) return 1; P = gel(I,j); for (j++; j<=n; j++) if (!ideal_is1(gel(I,j))) P = idealmul(nf,P,gel(I,j)); return gequal0( isprincipal(bnf,P) ); } long rnfisfree(GEN bnf, GEN order) { pari_sp av = avma; long n = rnfisfree_aux(bnf, order); avma = av; return n; } /**********************************************************************/ /** **/ /** COMPOSITUM OF TWO NUMBER FIELDS **/ /** **/ /**********************************************************************/ static GEN compositum_fix(GEN nf, GEN A) { int ok; if (nf) { long i, l = lg(A); A = shallowcopy(A); for (i=2; i=0) pari_err_PRIORITY("polcompositum", nf, ">=", v); } same = (A == B || RgX_equal(A,B)); A = compositum_fix(nf,A); if (!same) B = compositum_fix(nf,B); D = LPRS = NULL; /* -Wall */ k = same? -1: 1; if (nf) { long v0 = fetch_var(); GEN q; for(;; k = nextk(k)) { GEN chgvar = deg1pol_shallow(stoi(k),pol_x(v0),v); GEN B1 = poleval(B,chgvar); C = RgX_resultant_all(A,B1,&q); C = gsubst(C,v0,pol_x(v)); if (nfissquarefree(nf,C)) break; } C = lift_if_rational(C); if (flag&1) { GEN H0, H1; H0 = gsubst(gel(q,2),v0,pol_x(v)); H1 = gsubst(gel(q,3),v0,pol_x(v)); if (typ(H0) != t_POL) H0 = scalarpol_shallow(H0,v); if (typ(H1) != t_POL) H1 = scalarpol_shallow(H1,v); H0 = lift_if_rational(H0); H1 = lift_if_rational(H1); LPRS = mkvec2(H0,H1); } } else { B = leafcopy(B); setvarn(B,fetch_var_higher()); C = ZX_ZXY_resultant_all(A, B, &k, (flag&1)? &LPRS: NULL); setvarn(C, v); } /* C = Res_Y (A(Y), B(X + kY)) guaranteed squarefree */ if (same) { D = RgX_rescale(A, stoi(1 - k)); C = RgX_div(C, D); if (degpol(C) <= 0) C = mkvec(D); else C = shallowconcat(nf? gel(nffactor(nf,C),1): ZX_DDF(C), D); } else if (flag & 2) C = mkvec(C); else C = nf? gel(nffactor(nf,C),1): ZX_DDF(C); gen_sort_inplace(C, (void*)(nf?&cmp_RgX: &cmpii), &gen_cmp_RgX, NULL); if (flag&1) { /* a,b,c root of A,B,C = compositum, c = b - k a */ long i, l = lg(C); GEN a, b, mH0 = RgX_neg(gel(LPRS,1)), H1 = gel(LPRS,2); setvarn(mH0,v); setvarn(H1,v); for (i=1; i (ulong)-59) return 0; #else if (n > (ulong)-5) return 0; #endif /* here n > 7 */ n |= 1; /* make it odd */ rc = rc0 = n % 210; /* find next prime residue class mod 210 */ for(;;) { rcn = (long)(prc210_no[rc>>1]); if (rcn != NPRC) break; rc += 2; /* cannot wrap since 209 is coprime and rc odd */ } if (rc > rc0) n += rc - rc0; /* now find an actual (pseudo)prime */ for(;;) { if (uisprime(n)) break; rcd = prc210_d1[rcn]; if (++rcn > 47) rcn = 0; n += rcd; } return n; } GEN nextprime(GEN n) { long rc, rc0, rcd, rcn; pari_sp av = avma; if (typ(n) != t_INT) { n = gceil(n); if (typ(n) != t_INT) pari_err_TYPE("nextprime",n); } if (signe(n) <= 0) { avma = av; return gen_2; } if (lgefint(n) == 3) { ulong k = unextprime(uel(n,2)); avma = av; if (k) return utoipos(k); #ifdef LONG_IS_64BIT return uutoi(1,13); #else return uutoi(1,15); #endif } /* here n > 7 */ if (!mod2(n)) n = addui(1,n); rc = rc0 = umodiu(n, 210); /* find next prime residue class mod 210 */ for(;;) { rcn = (long)(prc210_no[rc>>1]); if (rcn != NPRC) break; rc += 2; /* cannot wrap since 209 is coprime and rc odd */ } if (rc > rc0) n = addui(rc - rc0, n); /* now find an actual (pseudo)prime */ for(;;) { if (BPSW_psp(n)) break; rcd = prc210_d1[rcn]; if (++rcn > 47) rcn = 0; n = addui(rcd, n); } if (avma == av) return icopy(n); return gerepileuptoint(av, n); } ulong uprecprime(ulong n) { long rc, rc0, rcd, rcn; { /* check if n <= 10 */ if (n <= 1) return 0; if (n == 2) return 2; if (n <= 4) return 3; if (n <= 6) return 5; if (n <= 10) return 7; } /* here n >= 11 */ if (!(n % 2)) n--; rc = rc0 = n % 210; /* find previous prime residue class mod 210 */ for(;;) { rcn = (long)(prc210_no[rc>>1]); if (rcn != NPRC) break; rc -= 2; /* cannot wrap since 1 is coprime and rc odd */ } if (rc < rc0) n += rc - rc0; /* now find an actual (pseudo)prime */ for(;;) { if (uisprime(n)) break; if (--rcn < 0) rcn = 47; rcd = prc210_d1[rcn]; n -= rcd; } return n; } GEN precprime(GEN n) { long rc, rc0, rcd, rcn; pari_sp av = avma; if (typ(n) != t_INT) { n = gfloor(n); if (typ(n) != t_INT) pari_err_TYPE("nextprime",n); } if (signe(n) <= 0) { avma = av; return gen_0; } if (lgefint(n) <= 3) { ulong k = uel(n,2); avma = av; return utoi(uprecprime(k)); } if (!mod2(n)) n = subiu(n,1); rc = rc0 = umodiu(n, 210); /* find previous prime residue class mod 210 */ for(;;) { rcn = (long)(prc210_no[rc>>1]); if (rcn != NPRC) break; rc -= 2; /* cannot wrap since 1 is coprime and rc odd */ } if (rc0 > rc) n = subiu(n, rc0 - rc); /* now find an actual (pseudo)prime */ for(;;) { if (BPSW_psp(n)) break; if (--rcn < 0) rcn = 47; rcd = prc210_d1[rcn]; n = subiu(n, rcd); } if (avma == av) return icopy(n); return gerepileuptoint(av, n); } /* Find next single-word prime strictly larger than p. * If **d is non-NULL (somewhere in a diffptr), this is p + *(*d)++; * otherwise imitate nextprime(). * *rcn = NPRC or the correct residue class for the current p; we'll use this * to track the current prime residue class mod 210 once we're out of range of * the diffptr table, and we'll update it before that if it isn't NPRC. * * *q is incremented whenever q!=NULL and we wrap from 209 mod 210 to * 1 mod 210 * k = second argument for Fl_MR_Jaeschke(). --GN1998Aug22 */ ulong snextpr(ulong p, byteptr *d, long *rcn, long *q, long k) { ulong n; if (**d) { byteptr dd = *d; long d1 = 0; NEXT_PRIME_VIADIFF(d1,dd); /* d1 = nextprime(p+1) - p */ if (*rcn != NPRC) { while (d1 > 0) { d1 -= prc210_d1[*rcn]; if (++*rcn > 47) { *rcn = 0; if (q) (*q)++; } } /* assert(d1 == 0) */ } NEXT_PRIME_VIADIFF(p,*d); return p; } /* we are beyond the diffptr table */ /* initialize */ if (*rcn == NPRC) *rcn = prc210_no[(p % 210) >> 1]; /* != NPRC */ /* look for the next one */ n = p + prc210_d1[*rcn]; if (++*rcn > 47) *rcn = 0; while (!Fl_MR_Jaeschke(n, k)) { n += prc210_d1[*rcn]; if (n <= 11) pari_err_OVERFLOW("snextpr"); if (++*rcn > 47) { *rcn = 0; if (q) (*q)++; } } return n; } /********************************************************************/ /** **/ /** INTEGER FACTORIZATION **/ /** **/ /********************************************************************/ int factor_add_primes = 0, factor_proven = 0; /***********************************************************************/ /** **/ /** FACTORIZATION (ECM) -- GN Jul-Aug 1998 **/ /** Integer factorization using the elliptic curves method (ECM). **/ /** ellfacteur() returns a non trivial factor of N, assuming N>0, **/ /** is composite, and has no prime divisor below 2^14 or so. **/ /** Thanks to Paul Zimmermann for much helpful advice and to **/ /** Guillaume Hanrot and Igor Schein for intensive testing **/ /** **/ /***********************************************************************/ #define nbcmax 64 /* max number of simultaneous curves */ static const ulong TB1[] = { 142,172,208,252,305,370,450,545,661,801,972,1180,1430, 1735,2100,2550,3090,3745,4540,5505,6675,8090,9810,11900, 14420,17490,21200,25700,31160,37780UL,45810UL,55550UL,67350UL, 81660UL,99010UL,120050UL,145550UL,176475UL,213970UL,259430UL, 314550UL,381380UL,462415UL,560660UL,679780UL,824220UL,999340UL, 1211670UL,1469110UL,1781250UL,2159700UL,2618600UL,3175000UL, 3849600UL,4667500UL,5659200UL,6861600UL,8319500UL,10087100UL, 12230300UL,14828900UL,17979600UL,21799700UL,26431500UL, 32047300UL,38856400UL, /* 110 times that still fits into 32bits */ #ifdef LONG_IS_64BIT 47112200UL,57122100UL,69258800UL,83974200UL,101816200UL, 123449000UL,149678200UL,181480300UL,220039400UL,266791100UL, 323476100UL,392204900UL,475536500UL,576573500UL,699077800UL, 847610500UL,1027701900UL,1246057200UL,1510806400UL,1831806700UL, 2221009800UL,2692906700UL,3265067200UL,3958794400UL,4799917500UL #endif }; static const ulong TB1_for_stage[] = { /* Start below the optimal B1 for finding factors which would just have been * missed by pollardbrent(), and escalate, changing curves to give good * coverage of the small factor ranges. Entries grow faster than what would * be optimal but a table instead of a 2D array keeps the code simple */ 500,520,560,620,700,800,900,1000,1150,1300,1450,1600,1800,2000, 2200,2450,2700,2950,3250,3600,4000,4400,4850,5300,5800,6400, 7100,7850,8700,9600,10600,11700,12900,14200,15700,17300, 19000,21000,23200,25500,28000,31000,34500UL,38500UL,43000UL, 48000UL,53800UL,60400UL,67750UL,76000UL,85300UL,95700UL, 107400UL,120500UL,135400UL,152000UL,170800UL,191800UL,215400UL, 241800UL,271400UL,304500UL,341500UL,383100UL,429700UL,481900UL, 540400UL,606000UL,679500UL,761800UL,854100UL,957500UL,1073500UL }; /* addition/doubling/multiplication of a point on an 'elliptic curve mod N' * may result in one of three things: * - a new bona fide point * - a point at infinity (denominator divisible by N) * - a point at infinity mod some p | N but finite mod q | N betraying itself * by a denominator which has nontrivial gcd with N. * * In the second case, addition/doubling aborts, copying one of the summands * to the destination array of points unless they coincide. * Multiplication will stop at some unpredictable intermediate stage: The * destination will contain _some_ multiple of the input point, but not * necessarily the desired one, which doesn't matter. As long as we're * multiplying (B1 phase) we simply carry on with the next multiplier. * During the B2 phase, the only additions are the giant steps, and the * worst that can happen here is that we lose one residue class mod 210 * of prime multipliers on 4 of the curves, so again, we ignore the problem * and just carry on.) * * Idea: select nbc curves mod N and one point P on each of them. For each * such P, compute [M]P = Q where M is the product of all powers <= B2 of * primes <= nextprime(B1). Then check whether [p]Q for p < nextprime(B2) * betrays a factor. This second stage looks separately at the primes in * each residue class mod 210, four curves at a time, and steps additively * to ever larger multipliers, by comparing X coordinates of points which we * would need to add in order to reach another prime multiplier in the same * residue class. 'Comparing' means that we accumulate a product of * differences of X coordinates, and from time to time take a gcd of this * product with N. Montgomery's multi-inverse trick is used heavily. */ /* *** auxiliary functions for ellfacteur: *** */ /* (Rx,Ry) <- (Px,Py)+(Qx,Qy) over Z/NZ, z=1/(Px-Qx). If Ry = NULL, don't set */ static void FpE_add_i(GEN N, GEN z, GEN Px, GEN Py, GEN Qx, GEN Qy, GEN *Rx, GEN *Ry) { GEN slope = modii(mulii(subii(Py, Qy), z), N); GEN t = subii(sqri(slope), addii(Qx, Px)); affii(modii(t, N), *Rx); if (Ry) { t = subii(mulii(slope, subii(Px, *Rx)), Py); affii(modii(t, N), *Ry); } } /* X -> Z; cannot add on one of the curves: make sure Z contains * something useful before letting caller proceed */ static void ZV_aff(long n, GEN *X, GEN *Z) { if (X != Z) { long k; for (k = n; k--; ) affii(X[k],Z[k]); } } /* Parallel addition on nbc curves, assigning the result to locations at and * following *X3, *Y3. (If Y-coords of result not desired, set Y=NULL.) * Safe even if (X3,Y3) = (X2,Y2), _not_ if (X1,Y1). It is also safe to * overwrite Y2 with X3. If nbc1 < nbc, the first summand is * assumed to hold only nbc1 distinct points, repeated as often as we need * them (to add one point on each of a few curves to several other points on * the same curves): only used with nbc1 = nbc or nbc1 = 4 | nbc. * * Return 0 [SUCCESS], 1 [N | den], 2 [gcd(den, N) is a factor of N, preserved * in gl. * Stack space is bounded by a constant multiple of lgefint(N)*nbc: * - Phase 2 creates 12 items on the stack per iteration, of which 4 are twice * as long and 1 is thrice as long as N, i.e. 18 units per iteration. * - Phase 1 creates 4 units. * Total can be as large as 4*nbcmax + 18*8 units; ecm_elladd2() is * just as bad, and elldouble() comes to 3*nbcmax + 29*8 units. */ static int ecm_elladd0(GEN N, GEN *gl, long nbc, long nbc1, GEN *X1, GEN *Y1, GEN *X2, GEN *Y2, GEN *X3, GEN *Y3) { const ulong mask = (nbc1 == 4)? 3: ~0UL; /*nbc1 = 4 or nbc*/ GEN W[2*nbcmax], *A = W+nbc; /* W[0],A[0] unused */ long i; pari_sp av = avma; W[1] = subii(X1[0], X2[0]); for (i=1; i copy Y2->Y3 */ ZV_aff(2*nbc, X5,X6); /* also copy Y5->Y6 */ avma = av; return 1; } while (j--) /* nbc times */ { pari_sp av2 = avma; GEN Px = X4[j], Py = Y4[j], Qx = X5[j], Qy = Y5[j]; GEN z = mulii(*gl,W[--i]); /*1/(Px-Qx)*/ FpE_add_i(N,z, Px,Py, Qx,Qy, X6+j,Y6+j); avma = av2; *gl = modii(mulii(*gl, A[i]), N); } while (i--) /* nbc times */ { pari_sp av2 = avma; GEN Px = X1[i], Py = Y1[i], Qx = X2[i], Qy = Y2[i]; GEN z = i? mulii(*gl, W[i]): *gl; /*1/(Px-Qx)*/ FpE_add_i(N,z, Px,Py, Qx,Qy, X3+i,Y3+i); if (!i) break; avma = av2; *gl = modii(mulii(*gl, A[i]), N); } avma = av; return 0; } /* Parallel doubling on nbc curves, assigning the result to locations at * and following *X2. Safe to be called with X2 equal to X1. Return * value as for ecm_elladd. If we find a point at infinity mod N, * and if X1 != X2, we copy the points at X1 to X2. */ static int elldouble(GEN N, GEN *gl, long nbc, GEN *X1, GEN *X2) { GEN *Y1 = X1+nbc, *Y2 = X2+nbc; GEN W[nbcmax+1]; /* W[0] unused */ long i; pari_sp av = avma; /*W[0] = gen_1;*/ W[1] = Y1[0]; for (i=1; iY2 */ avma = av; return 1; } while (i--) /* nbc times */ { pari_sp av2; GEN v, w, L, z = i? mulii(*gl,W[i]): *gl; if (i) *gl = modii(mulii(*gl, Y1[i]), N); av2 = avma; L = modii(mulii(addui(1, mului(3, Fp_sqr(X1[i],N))), z), N); if (signe(L)) /* half of zero is still zero */ L = shifti(mod2(L)? addii(L, N): L, -1); v = modii(subii(sqri(L), shifti(X1[i],1)), N); w = modii(subii(mulii(L, subii(X1[i], v)), Y1[i]), N); affii(v, X2[i]); affii(w, Y2[i]); avma = av2; } avma = av; return 0; } /* Parallel multiplication by an odd prime k on nbc curves, storing the * result to locations at and following *X2. Safe to be called with X2 = X1. * Return values as ecm_elladd. Uses (a simplified variant of) Montgomery's * PRAC algorithm; see ftp://ftp.cwi.nl/pub/pmontgom/Lucas.ps.gz . * With thanks to Paul Zimmermann for the reference. --GN1998Aug13 */ static int get_rule(ulong d, ulong e) { if (d <= e + (e>>2)) /* floor(1.25*e) */ { if ((d+e)%3 == 0) return 0; /* rule 1 */ if ((d-e)%6 == 0) return 1; /* rule 2 */ } /* d <= 4*e but no ofl */ if ((d+3)>>2 <= e) return 2; /* rule 3, common case */ if ((d&1)==(e&1)) return 1; /* rule 4 = rule 2 */ if (!(d&1)) return 3; /* rule 5 */ if (d%3 == 0) return 4; /* rule 6 */ if ((d+e)%3 == 0) return 5; /* rule 7 */ if ((d-e)%3 == 0) return 6; /* rule 8 */ /* when we get here, e is even, otherwise one of rules 4,5 would apply */ return 7; /* rule 9 */ } /* PRAC implementation notes - main changes against the paper version: * (1) The general function [m+n]P = f([m]P,[n]P,[m-n]P) collapses (for m!=n) * to an ecm_elladd() which does not depend on the third argument; thus * references to the third variable (C in the paper) can be eliminated. * (2) Since our multipliers are prime, the outer loop of the paper * version executes only once, and thus is invisible above. * (3) The first step in the inner loop of the paper version will always be * rule 3, but the addition requested by this rule amounts to a doubling, and * will always be followed by a swap, so we have unrolled this first iteration. * (4) Simplifications in rules 6 and 7 are possible given the above, and we * save one addition in each of the two cases. NB none of the other * ecm_elladd()s in the loop can ever degenerate into an elldouble. * (5) I tried to optimize for rule 3, which is used more frequently than all * others together, but it didn't improve things, so I removed the nested * tight loop again. --GN */ /* The main loop body of ellfacteur() runs _slower_ under PRAC than under a * straightforward left-shift binary multiplication when N has <30 digits and * B1 is small; PRAC wins when N and B1 get larger. Weird. --GN */ /* k>2 assumed prime, XAUX = scratchpad */ static int ellmult(GEN N, GEN *gl, long nbc, ulong k, GEN *X1, GEN *X2, GEN *XAUX) { ulong r, d, e, e1; int res; GEN *A = X2, *B = XAUX, *T = XAUX + 2*nbc; ZV_aff(2*nbc,X1,XAUX); /* first doubling picks up X1; after this we'll be working in XAUX and * X2 only, mostly via A and B and T */ if ((res = elldouble(N, gl, nbc, X1, X2)) != 0) return res; /* split the work at the golden ratio */ r = (ulong)(k*0.61803398875 + .5); d = k - r; e = r - d; /* d+e == r, so no danger of ofl below */ while (d != e) { /* apply one of the nine transformations from PM's Table 4. */ switch(get_rule(d,e)) { case 0: /* rule 1 */ if ( (res = ecm_elladd(N, gl, nbc, A, B, T)) ) return res; if ( (res = ecm_elladd2(N, gl, nbc, T, A, A, T, B, B)) != 0) return res; e1 = d - e; d = (d + e1)/3; e = (e - e1)/3; break; case 1: /* rules 2 and 4 */ if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res; if ( (res = elldouble(N, gl, nbc, A, A)) ) return res; d = (d-e)>>1; break; case 3: /* rule 5 */ if ( (res = elldouble(N, gl, nbc, A, A)) ) return res; d >>= 1; break; case 4: /* rule 6 */ if ( (res = elldouble(N, gl, nbc, A, T)) ) return res; if ( (res = ecm_elladd(N, gl, nbc, T, A, A)) ) return res; if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res; d = d/3 - e; break; case 2: /* rule 3 */ if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res; d -= e; break; case 5: /* rule 7 */ if ( (res = elldouble(N, gl, nbc, A, T)) ) return res; if ( (res = ecm_elladd2(N, gl, nbc, T, A, A, T, B, B)) != 0) return res; d = (d - 2*e)/3; break; case 6: /* rule 8 */ if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res; if ( (res = elldouble(N, gl, nbc, A, T)) ) return res; if ( (res = ecm_elladd(N, gl, nbc, T, A, A)) ) return res; d = (d - e)/3; break; case 7: /* rule 9 */ if ( (res = elldouble(N, gl, nbc, B, B)) ) return res; e >>= 1; break; } /* swap d <-> e and A <-> B if necessary */ if (d < e) { lswap(d,e); pswap(A,B); } } return ecm_elladd(N, gl, nbc, XAUX, X2, X2); } struct ECM { pari_timer T; long nbc, nbc2, seed; GEN *X, *XAUX, *XT, *XD, *XB, *XB2, *XH, *Xh, *Yh; }; /* memory layout in ellfacteur(): a large array of GEN pointers, and one * huge chunk of memory containing all the actual GEN (t_INT) objects. * nbc is constant throughout the invocation: * - The B1 stage of each iteration through the main loop needs little * space: enough for the X and Y coordinates of the current points, * and twice as much again as scratchpad for ellmult(). * - The B2 stage, starting from some current set of points Q, needs, in * succession: * + space for [2]Q, [4]Q, ..., [10]Q, and [p]Q for building the helix; * + space for 48*nbc X and Y coordinates to hold the helix. This could * re-use [2]Q,...,[8]Q, but only with difficulty, since we don't * know in advance which residue class mod 210 our p is going to be in. * It can and should re-use [p]Q, though; * + space for (temporarily [30]Q and then) [210]Q, [420]Q, and several * further doublings until the giant step multiplier is reached. This * can re-use the remaining cells from above. The computation of [210]Q * will have been the last call to ellmult() within this iteration of the * main loop, so the scratchpad is now also free to be re-used. We also * compute [630]Q by a parallel addition; we'll need it later to get the * baby-step table bootstrapped a little faster. * + Finally, for no more than 4 curves at a time, room for up to 1024 X * coordinates only: the Y coordinates needed whilst setting up this baby * step table are temporarily stored in the upper half, and overwritten * during the last series of additions. * * Graphically: after end of B1 stage (X,Y are the coords of Q): * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- * | X Y | scratch | [2]Q| [4]Q| [6]Q| [8]Q|[10]Q| ... | ... * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- * *X *XAUX *XT *XD *XB * * [30]Q is computed from [10]Q. [210]Q can go into XY, etc: * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- * |[210]|[420]|[630]|[840]|[1680,3360,6720,...,2048*210] |bstp table... * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- * *X *XAUX *XT *XD [*XG, somewhere here] *XB .... *XH * * So we need (13 + 48) * 2 * nbc slots here + 4096 slots for the baby step * table (not all of which will be used when we start with a small B1, but * better to allocate and initialize ahead of time all the slots that might * be needed later). * * Note on memory locality: During the B2 phase, accesses to the helix * (once it is set up) will be clustered by curves (4 out of nbc at a time). * Accesses to the baby steps table will wander from one end of the array to * the other and back, one such cycle per giant step, and during a full cycle * we would expect on the order of 2E4 accesses when using the largest giant * step size. Thus we shouldn't be doing too bad with respect to thrashing * a 512KBy L2 cache. However, we don't want the baby step table to grow * larger than this, even if it would reduce the number of EC operations by a * few more per cent for very large B2, lest cache thrashing slow down * everything disproportionally. --GN */ /* Auxiliary routines need < (3*nbc+240)*lN words on the PARI stack, in * addition to the spc*(lN+1) words occupied by our main table. */ static void ECM_alloc(struct ECM *E, long lN) { const long bstpmax = 1024; /* max number of baby step table entries */ long spc = (13 + 48) * E->nbc2 + bstpmax * 4; long len = spc + 385 + spc*lN; long i, tw = evallg(lN) | evaltyp(t_INT); GEN w, *X = (GEN*)new_chunk(len); /* hack for X[i] = cgeti(lN). X = current point in B1 phase */ w = (GEN)(X + spc + 385); for (i = spc-1; i >= 0; i--) { X[i] = w; *w = tw; w += lN; } E->X = X; E->XAUX = E->X + E->nbc2; /* scratchpad for ellmult() */ E->XT = E->XAUX + E->nbc2; /* ditto, will later hold [3*210]Q */ E->XD = E->XT + E->nbc2; /* room for various multiples */ E->XB = E->XD + 10*E->nbc2; /* start of baby steps table */ E->XB2 = E->XB + 2 * bstpmax; /* middle of baby steps table */ E->XH = E->XB2 + 2 * bstpmax; /* end of bstps table, start of helix */ E->Xh = E->XH + 48*E->nbc2; /* little helix, X coords */ E->Yh = E->XH + 192; /* ditto, Y coords */ /* XG,YG set inside the main loop, since they depend on B2 */ /* E.Xh range of 384 pointers not set; these will later duplicate the pointers * in the E.XH range, 4 curves at a time. Some of the cells reserved here for * the E.XB range will never be used, instead, we'll warp the pointers to * connect to (read-only) GENs in the X/E.XD range */ } /* N.B. E->seed is not initialized here */ static void ECM_init(struct ECM *E, GEN N, long nbc) { if (nbc < 0) { /* choose a sensible default */ const long size = expi(N) + 1; nbc = ((size >> 3) << 2) - 80; if (nbc < 8) nbc = 8; } if (nbc > nbcmax) nbc = nbcmax; E->nbc = nbc; E->nbc2 = nbc << 1; ECM_alloc(E, lgefint(N)); } static GEN ECM_loop(struct ECM *E, GEN N, ulong B1) { const long MR_foolproof = 16;/* B1 phase, foolproof below 10^12 */ const long MR_fast = 1; /* B2 phase, not foolproof, 2xfaster */ /* MR_fast will let thousands of composites slip through, which doesn't * harm ECM; but ellmult() in the B1 phase should only be fed actual primes */ const ulong B2 = 110 * B1, B2_rt = usqrt(B2); const ulong nbc = E->nbc, nbc2 = E->nbc2; pari_sp av1, avtmp; byteptr d0, d = diffptr; long i, gse, gss, bstp, bstp0, rcn0, rcn; ulong B2_p, m, p, p0; GEN g, *XG, *YG; GEN *X = E->X, *XAUX = E->XAUX, *XT = E->XT, *XD = E->XD; GEN *XB = E->XB, *XB2 = E->XB2, *XH = E->XH, *Xh = E->Xh, *Yh = E->Yh; /* pick curves */ for (i = nbc2; i--; ) affui(E->seed++, X[i]); /* pick giant step exponent and size */ gse = B1 < 656 ? (B1 < 200? 5: 6) : (B1 < 10500 ? (B1 < 2625? 7: 8) : (B1 < 42000? 9: 10)); gss = 1UL << gse; /* With 32 baby steps, a giant step corresponds to 32*420 = 13440, * appropriate for the smallest B2s. With 1024, a giant step will be 430080; * appropriate for B1 >~ 42000, where 512 baby steps would imply roughly * the same number of curve additions. */ XG = XT + gse*nbc2; /* will later hold [2^(gse+1)*210]Q */ YG = XG + nbc; if (DEBUGLEVEL >= 4) { err_printf("ECM: time = %6ld ms\nECM: B1 = %4lu,", timer_delay(&E->T), B1); err_printf("\tB2 = %6lu,\tgss = %4ld*420\n", B2, gss); } p = 0; NEXT_PRIME_VIADIFF(p,d); /* ---B1 PHASE--- */ /* treat p=2 separately */ B2_p = B2 >> 1; for (m=1; m<=B2_p; m<<=1) { int fl = elldouble(N, &g, nbc, X, X); if (fl > 1) return g; else if (fl) break; } rcn = NPRC; /* multipliers begin at the beginning */ /* p=3,...,nextprime(B1) */ while (p < B1 && p <= B2_rt) { pari_sp av2 = avma; p = snextpr(p, &d, &rcn, NULL, MR_foolproof); B2_p = B2/p; /* beware integer overflow on 32-bit CPUs */ for (m=1; m<=B2_p; m*=p) { int fl = ellmult(N, &g, nbc, p, X, X, XAUX); if (fl > 1) return g; else if (fl) break; avma = av2; } avma = av2; } /* primes p larger than sqrt(B2) appear only to the 1st power */ while (p < B1) { pari_sp av2 = avma; p = snextpr(p, &d, &rcn, NULL, MR_foolproof); if (ellmult(N, &g, nbc, p, X, X, XAUX) > 1) return g; avma = av2; } if (DEBUGLEVEL >= 4) { err_printf("ECM: time = %6ld ms, B1 phase done, ", timer_delay(&E->T)); err_printf("p = %lu, setting up for B2\n", p); } /* ---B2 PHASE--- */ /* compute [2]Q,...,[10]Q, needed to build the helix */ if (elldouble(N, &g, nbc, X, XD) > 1) return g; /*[2]Q*/ if (elldouble(N, &g, nbc, XD, XD + nbc2) > 1) return g; /*[4]Q*/ if (ecm_elladd(N, &g, nbc, XD, XD + nbc2, XD + (nbc<<2)) > 1) return g; /* [6]Q */ if (ecm_elladd2(N, &g, nbc, XD, XD + (nbc<<2), XT + (nbc<<3), XD + nbc2, XD + (nbc<<2), XD + (nbc<<3)) > 1) return g; /* [8]Q and [10]Q */ if (DEBUGLEVEL >= 7) err_printf("\t(got [2]Q...[10]Q)\n"); /* get next prime (still using the foolproof test) */ p = snextpr(p, &d, &rcn, NULL, MR_foolproof); /* make sure we have the residue class number (mod 210) */ if (rcn == NPRC) { rcn = prc210_no[(p % 210) >> 1]; if (rcn == NPRC) { err_printf("ECM: %lu should have been prime but isn\'t\n", p); pari_err_BUG("ellfacteur"); } } /* compute [p]Q and put it into its place in the helix */ if (ellmult(N, &g, nbc, p, X, XH + rcn*nbc2, XAUX) > 1) return g; if (DEBUGLEVEL >= 7) err_printf("\t(got [p]Q, p = %lu = prc210_rp[%ld] mod 210)\n", p, rcn); /* save current p, d, and rcn; we'll need them more than once below */ p0 = p; d0 = d; rcn0 = rcn; /* remember where the helix wraps */ bstp0 = 0; /* p is at baby-step offset 0 from itself */ /* fill up the helix, stepping forward through the prime residue classes * mod 210 until we're back at the r'class of p0. Keep updating p so * that we can print meaningful diagnostics if a factor shows up; don't * bother checking which of these p's are in fact prime */ for (i = 47; i; i--) /* 47 iterations */ { ulong dp = (ulong)prc210_d1[rcn]; p += dp; if (rcn == 47) { /* wrap mod 210 */ if (ecm_elladd(N, &g, nbc, XT+dp*nbc, XH+rcn*nbc2, XH) > 1) return g; rcn = 0; continue; } if (ecm_elladd(N, &g, nbc, XT+dp*nbc, XH+rcn*nbc2, XH+rcn*nbc2+nbc2) > 1) return g; rcn++; } if (DEBUGLEVEL >= 7) err_printf("\t(got initial helix)\n"); /* compute [210]Q etc, needed for the baby step table */ if (ellmult(N, &g, nbc, 3, XD + (nbc<<3), X, XAUX) > 1) return g; if (ellmult(N, &g, nbc, 7, X, X, XAUX) > 1) return g; /* [210]Q */ /* this was the last call to ellmult() in the main loop body; may now * overwrite XAUX and slots XD and following */ if (elldouble(N, &g, nbc, X, XAUX) > 1) return g; /* [420]Q */ if (ecm_elladd(N, &g, nbc, X, XAUX, XT) > 1) return g;/*[630]Q*/ if (ecm_elladd(N, &g, nbc, X, XT, XD) > 1) return g; /*[840]Q*/ for (i=1; i <= gse; i++) if (elldouble(N, &g, nbc, XT + i*nbc2, XD + i*nbc2) > 1) return g; /* (the last iteration has initialized XG to [210*2^(gse+1)]Q) */ if (DEBUGLEVEL >= 4) err_printf("ECM: time = %6ld ms, entering B2 phase, p = %lu\n", timer_delay(&E->T), p); for (i = nbc - 4; i >= 0; i -= 4) { /* loop over small sets of 4 curves at a time */ GEN *Xb; long j, k; if (DEBUGLEVEL >= 6) err_printf("ECM: finishing curves %ld...%ld\n", i, i+3); /* Copy relevant pointers from XH to Xh. Memory layout in XH: * nbc X coordinates, nbc Y coordinates for residue class * 1 mod 210, then the same for r.c. 11 mod 210, etc. Memory layout for * Xh is: four X coords for 1 mod 210, four for 11 mod 210, ..., four * for 209 mod 210, then the corresponding Y coordinates in the same * order. This allows a giant step on Xh using just three calls to * ecm_elladd0() each acting on 64 points in parallel */ for (j = 48; j--; ) { k = nbc2*j + i; m = j << 2; /* X coordinates */ Xh[m] = XH[k]; Xh[m+1] = XH[k+1]; Xh[m+2] = XH[k+2]; Xh[m+3] = XH[k+3]; k += nbc; /* Y coordinates */ Yh[m] = XH[k]; Yh[m+1] = XH[k+1]; Yh[m+2] = XH[k+2]; Yh[m+3] = XH[k+3]; } /* Build baby step table of X coords of multiples of [210]Q. XB[4*j] * will point at X coords on four curves from [(j+1)*210]Q. Until * we're done, we need some Y coords as well, which we keep in the * second half of the table, overwriting them at the end when gse=10. * Multiples which we already have (by 1,2,3,4,8,16,...,2^gse) are * entered simply by copying the pointers, ignoring the few slots in w * that were initially reserved for them. Here are the initial entries */ for (Xb=XB,k=2,j=i; k--; Xb=XB2,j+=nbc) /* first X, then Y coords */ { Xb[0] = X[j]; Xb[1] = X[j+1]; /* [210]Q */ Xb[2] = X[j+2]; Xb[3] = X[j+3]; Xb[4] = XAUX[j]; Xb[5] = XAUX[j+1]; /* [420]Q */ Xb[6] = XAUX[j+2]; Xb[7] = XAUX[j+3]; Xb[8] = XT[j]; Xb[9] = XT[j+1]; /* [630]Q */ Xb[10] = XT[j+2]; Xb[11] = XT[j+3]; Xb += 4; /* points at [420]Q */ /* ... entries at powers of 2 times 210 .... */ for (m = 2; m < (ulong)gse+k; m++) /* omit Y coords of [2^gse*210]Q */ { long m2 = m*nbc2 + j; Xb += (2UL<= 7) err_printf("\t(extracted precomputed helix / baby step entries)\n"); /* ... glue in between, up to 16*210 ... */ if (ecm_elladd0(N, &g, 12, 4, /* 12 pts + (4 pts replicated thrice) */ XB + 12, XB2 + 12, XB, XB2, XB + 16, XB2 + 16) > 1) return g; /*4+{1,2,3} = {5,6,7}*/ if (ecm_elladd0(N, &g, 28, 4, /* 28 pts + (4 pts replicated 7fold) */ XB + 28, XB2 + 28, XB, XB2, XB + 32, XB2 + 32) > 1) return g;/*8+{1...7} = {9...15}*/ /* ... and the remainder of the lot */ for (m = 5; m <= (ulong)gse; m++) { /* fill in from 2^(m-1)+1 to 2^m-1 in chunks of 64 and 60 points */ ulong m2 = 2UL << m; /* will point at 2^(m-1)+1 */ for (j = 0; (ulong)j < m2-64; j+=64) /* executed 0 times when m = 5 */ { if (ecm_elladd0(N, &g, 64, 4, XB + m2-4, XB2 + m2-4, XB + j, XB2 + j, XB + m2+j, (m<(ulong)gse? XB2+m2+j: NULL)) > 1) return g; } /* j = m2-64 here, 60 points left */ if (ecm_elladd0(N, &g, 60, 4, XB + m2-4, XB2 + m2-4, XB + j, XB2 + j, XB + m2+j, (m<(ulong)gse? XB2+m2+j: NULL)) > 1) return g; /* when m=gse, drop Y coords of result, and when both equal 1024, * overwrite Y coords of second argument with X coords of result */ } if (DEBUGLEVEL >= 7) err_printf("\t(baby step table complete)\n"); /* initialize a few other things */ bstp = bstp0; p = p0; d = d0; rcn = rcn0; g = gen_1; av1 = avma; /* scratchspace for prod (x_i-x_j) */ avtmp = (pari_sp)new_chunk(8 * lgefint(N)); /* The correct entry in XB to use depends on bstp and on where we are * on the helix. As we skip from prime to prime, bstp is incremented * by snextpr each time we wrap around through residue class number 0 * (1 mod 210), but the baby step should not be taken until rcn>=rcn0, * i.e. until we pass again the residue class of p0. * * The correct signed multiplier is thus k = bstp - (rcn < rcn0), * and the offset from XB is four times (|k| - 1). When k=0, we ignore * the current prime: if it had led to a factorization, this * would have been noted during the last giant step, or -- when we * first get here -- whilst initializing the helix. When k > gss, * we must do a giant step and bump bstp back by -2*gss. * * The gcd of the product of X coord differences against N is taken just * before we do a giant step. */ while (p < B2) {/* loop over probable primes p0 < p <= nextprime(B2), inserting giant * steps as necessary */ p = snextpr(p, &d, &rcn, &bstp, MR_fast); /* next probable prime */ /* work out the corresponding baby-step multiplier */ k = bstp - (rcn < rcn0 ? 1 : 0); if (k > gss) { /* giant-step time, take gcd */ g = gcdii(g, N); if (!is_pm1(g) && !equalii(g, N)) return g; g = gen_1; avma = av1; while (k > gss) { /* giant step */ if (DEBUGLEVEL >= 7) err_printf("\t(giant step at p = %lu)\n", p); if (ecm_elladd0(N, &g, 64, 4, XG + i, YG + i, Xh, Yh, Xh, Yh) > 1) return g; if (ecm_elladd0(N, &g, 64, 4, XG + i, YG + i, Xh + 64, Yh + 64, Xh + 64, Yh + 64) > 1) return g; if (ecm_elladd0(N, &g, 64, 4, XG + i, YG + i, Xh + 128, Yh + 128, Xh + 128, Yh + 128) > 1) return g; bstp -= (gss << 1); k = bstp - (rcn < rcn0? 1: 0); /* recompute multiplier */ } } if (!k) continue; /* point of interest is already in Xh */ if (k < 0) k = -k; m = ((ulong)k - 1) << 2; /* accumulate product of differences of X coordinates */ j = rcn<<2; avma = avtmp; /* go to garbage zone */ g = modii(mulii(g, subii(XB[m], Xh[j])), N); g = modii(mulii(g, subii(XB[m+1], Xh[j+1])), N); g = modii(mulii(g, subii(XB[m+2], Xh[j+2])), N); g = mulii(g, subii(XB[m+3], Xh[j+3])); avma = av1; g = modii(g, N); } avma = av1; } return NULL; } /* ellfacteur() tuned to be useful as a first stage before MPQS, especially for * large arguments, when 'insist' is false, and now also for the case when * 'insist' is true, vaguely following suggestions by Paul Zimmermann * (http://www.loria.fr/~zimmerma/records/ecmnet.html). --GN 1998Jul,Aug */ static GEN ellfacteur(GEN N, int insist) { const long size = expi(N) + 1; pari_sp av = avma; struct ECM E; long nbc, dsn, dsnmax, rep = 0; if (insist) { const long DSNMAX = numberof(TB1)-1; dsnmax = (size >> 2) - 10; if (dsnmax < 0) dsnmax = 0; else if (dsnmax > DSNMAX) dsnmax = DSNMAX; E.seed = 1 + (nbcmax<<7)*(size&0xffff); /* seed for choice of curves */ dsn = (size >> 3) - 5; if (dsn < 0) dsn = 0; else if (dsn > 47) dsn = 47; /* pick up the torch where non-insistent stage would have given up */ nbc = dsn + (dsn >> 2) + 9; /* 8 or more curves in parallel */ nbc &= ~3; /* 4 | nbc */ } else { dsn = (size - 140) >> 3; if (dsn < 0) { #ifndef __EMX__ /* unless DOS/EMX: MPQS's disk access is abysmally slow */ if (DEBUGLEVEL >= 4) err_printf("ECM: number too small to justify this stage\n"); return NULL; /* too small, decline the task */ #endif dsn = 0; } else if (dsn > 12) dsn = 12; rep = (size <= 248 ? (size <= 176 ? (size - 124) >> 4 : (size - 148) >> 3) : (size - 224) >> 1); #ifdef __EMX__ /* DOS/EMX: extra rounds (shun MPQS) */ rep += 20; #endif dsnmax = 72; /* Use disjoint sets of curves for non-insist and insist phases; moreover, * repeated calls acting on factors of the same original number should try * to use fresh curves. The following achieves this */ E.seed = 1 + (nbcmax<<3)*(size & 0xf); nbc = -1; } ECM_init(&E, N, nbc); if (DEBUGLEVEL >= 4) { timer_start(&E.T); err_printf("ECM: working on %ld curves at a time; initializing", E.nbc); if (!insist) { if (rep == 1) err_printf(" for one round"); else err_printf(" for up to %ld rounds", rep); } err_printf("...\n"); } if (dsn > dsnmax) dsn = dsnmax; for(;;) { ulong B1 = insist? TB1[dsn]: TB1_for_stage[dsn]; GEN g = ECM_loop(&E, N, B1); if (g) { if (DEBUGLEVEL >= 4) err_printf("ECM: time = %6ld ms\n\tfound factor = %Ps\n", timer_delay(&E.T), g); return gerepilecopy(av, g); } if (dsn < dsnmax) { if (insist) dsn++; else { dsn += 2; if (dsn > dsnmax) dsn = dsnmax; } } if (!insist && !--rep) { if (DEBUGLEVEL >= 4) err_printf("ECM: time = %6ld ms,\tellfacteur giving up.\n", timer_delay(&E.T)); avma = av; return NULL; } } } /* assume rounds >= 1, seed >= 1, B1 <= ULONG_MAX / 110 */ GEN Z_ECM(GEN N, long rounds, long seed, ulong B1) { pari_sp av = avma; struct ECM E; long i; E.seed = seed; ECM_init(&E, N, -1); if (DEBUGLEVEL >= 4) timer_start(&E.T); for (i = rounds; i--; ) { GEN g = ECM_loop(&E, N, B1); if (g) return gerepilecopy(av, g); } avma = av; return NULL; } /***********************************************************************/ /** **/ /** FACTORIZATION (Pollard-Brent rho) --GN1998Jun18-26 **/ /** pollardbrent() returns a nontrivial factor of n, assuming n is **/ /** composite and has no small prime divisor, or NULL if going on **/ /** would take more time than we want to spend. Sometimes it finds **/ /** more than one factor, and returns a structure suitable for **/ /** interpretation by ifac_crack. (Cf Algo 8.5.2 in ACiCNT) **/ /** **/ /***********************************************************************/ #define VALUE(x) gel(x,0) #define EXPON(x) gel(x,1) #define CLASS(x) gel(x,2) INLINE void INIT(GEN x, GEN v, GEN e, GEN c) { VALUE(x) = v; EXPON(x) = e; CLASS(x) = c; } static void ifac_delete(GEN x) { INIT(x,NULL,NULL,NULL); } static void rho_dbg(pari_timer *T, long c, long msg_mask) { if (c & msg_mask) return; err_printf("Rho: time = %6ld ms,\t%3ld round%s\n", timer_delay(T), c, (c==1?"":"s")); } static void one_iter(GEN *x, GEN *P, GEN x1, GEN n, long delta) { *x = addis(remii(sqri(*x), n), delta); *P = modii(mulii(*P, subii(x1, *x)), n); } /* Return NULL when we run out of time, or a single t_INT containing a * nontrivial factor of n, or a vector of t_INTs, each triple of successive * entries containing a factor, an exponent (equal to one), and a factor * class (NULL for unknown or zero for known composite), matching the * internal representation used by the ifac_*() routines below. Repeated * factors may arise; the caller will sort the factors anyway. Result * is not gerepile-able (contains NULL) */ static GEN pollardbrent_i(GEN n, long size, long c0, long retries) { long tf = lgefint(n), delta, msg_mask, c, k, k1, l; pari_sp av; GEN x, x1, y, P, g, g1, res; pari_timer T; if (DEBUGLEVEL >= 4) timer_start(&T); c = c0 << 5; /* 2^5 iterations per round */ msg_mask = (size >= 448? 0x1fff: (size >= 192? (256L<<((size-128)>>6))-1: 0xff)); y = cgeti(tf); x1= cgeti(tf); av = avma; PB_RETRY: /* trick to make a 'random' choice determined by n. Don't use x^2+0 or * x^2-2, ever. Don't use x^2-3 or x^2-7 with a starting value of 2. * x^2+4, x^2+9 are affine conjugate to x^2+1, so don't use them either. * * (the point being that when we get called again on a composite cofactor * of something we've already seen, we had better avoid the same delta) */ switch ((size + retries) & 7) { case 0: delta= 1; break; case 1: delta= -1; break; case 2: delta= 3; break; case 3: delta= 5; break; case 4: delta= -5; break; case 5: delta= 7; break; case 6: delta= 11; break; /* case 7: */ default: delta=-11; break; } if (DEBUGLEVEL >= 4) { if (!retries) err_printf("Rho: searching small factor of %ld-bit integer\n", size); else err_printf("Rho: restarting for remaining rounds...\n"); err_printf("Rho: using X^2%+1ld for up to %ld rounds of 32 iterations\n", delta, c >> 5); } x = gen_2; P = gen_1; g1 = NULL; k = 1; l = 1; affui(2, y); affui(2, x1); for (;;) /* terminated under the control of c */ { /* use the polynomial x^2 + delta */ one_iter(&x, &P, x1, n, delta); if ((--c & 0x1f)==0) { /* one round complete */ g = gcdii(n, P); if (!is_pm1(g)) goto fin; if (c <= 0) { /* getting bored */ if (DEBUGLEVEL >= 4) err_printf("Rho: time = %6ld ms,\tPollard-Brent giving up.\n", timer_delay(&T)); return NULL; } P = gen_1; if (DEBUGLEVEL >= 4) rho_dbg(&T, c0-(c>>5), msg_mask); affii(x,y); x = y; avma = av; } if (--k) continue; /* normal end of loop body */ if (c & 0x1f) /* otherwise, we already checked */ { g = gcdii(n, P); if (!is_pm1(g)) goto fin; P = gen_1; } /* Fast forward phase, doing l inner iterations without computing gcds. * Check first whether it would take us beyond the alloted time. * Fast forward rounds count only half (although they're taking * more like 2/3 the time of normal rounds). This to counteract the * nuisance that all c0 between 4096 and 6144 would act exactly as * 4096; with the halving trick only the range 4096..5120 collapses * (similarly for all other powers of two) */ if ((c -= (l>>1)) <= 0) { /* got bored */ if (DEBUGLEVEL >= 4) err_printf("Rho: time = %6ld ms,\tPollard-Brent giving up.\n", timer_delay(&T)); return NULL; } c &= ~0x1f; /* keep it on multiples of 32 */ /* Fast forward loop */ affii(x, x1); avma = av; x = x1; k = l; l <<= 1; /* don't show this for the first several (short) fast forward phases. */ if (DEBUGLEVEL >= 4 && (l>>7) > msg_mask) err_printf("Rho: fast forward phase (%ld rounds of 64)...\n", l>>7); for (k1=k; k1; k1--) { one_iter(&x, &P, x1, n, delta); if ((k1 & 0x1f) == 0) gerepileall(av, 2, &x, &P); } if (DEBUGLEVEL >= 4 && (l>>7) > msg_mask) err_printf("Rho: time = %6ld ms,\t%3ld rounds, back to normal mode\n", timer_delay(&T), c0-(c>>5)); affii(x,y); P = gerepileuptoint(av, P); x = y; } /* forever */ fin: /* An accumulated gcd was > 1 */ if (!equalii(g,n)) { /* if it isn't n, and looks prime, return it */ if (MR_Jaeschke(g)) { if (DEBUGLEVEL >= 4) { rho_dbg(&T, c0-(c>>5), 0); err_printf("\tfound factor = %Ps\n",g); } return g; } avma = av; g1 = icopy(g); /* known composite, keep it safe */ av = avma; } else g1 = n; /* and work modulo g1 for backtracking */ /* Here g1 is known composite */ if (DEBUGLEVEL >= 4 && size > 192) err_printf("Rho: hang on a second, we got something here...\n"); x = y; for(;;) { /* backtrack until period recovered. Must terminate */ x = addis(remii(sqri(x), g1), delta); g = gcdii(subii(x1, x), g1); if (!is_pm1(g)) break; if (DEBUGLEVEL >= 4 && (--c & 0x1f) == 0) rho_dbg(&T, c0-(c>>5), msg_mask); } if (g1 == n || equalii(g,g1)) { if (g1 == n && equalii(g,g1)) { /* out of luck */ if (DEBUGLEVEL >= 4) { rho_dbg(&T, c0-(c>>5), 0); err_printf("\tPollard-Brent failed.\n"); } if (++retries >= 4) pari_err_BUG(""); goto PB_RETRY; } /* half lucky: we've split n, but g1 equals either g or n */ if (DEBUGLEVEL >= 4) { rho_dbg(&T, c0-(c>>5), 0); err_printf("\tfound %sfactor = %Ps\n", (g1!=n ? "composite " : ""), g); } res = cgetg(7, t_VEC); /* g^1: known composite when g1!=n */ INIT(res+1, g, gen_1, (g1!=n? gen_0: NULL)); /* cofactor^1: status unknown */ INIT(res+4, diviiexact(n,g), gen_1, NULL); return res; } /* g < g1 < n : our lucky day -- we've split g1, too */ res = cgetg(10, t_VEC); /* unknown status for all three factors */ INIT(res+1, g, gen_1, NULL); INIT(res+4, diviiexact(g1,g), gen_1, NULL); INIT(res+7, diviiexact(n,g1), gen_1, NULL); if (DEBUGLEVEL >= 4) { rho_dbg(&T, c0-(c>>5), 0); err_printf("\tfound factors = %Ps, %Ps,\n\tand %Ps\n", gel(res,1), gel(res,4), gel(res,7)); } return res; } /* Tuning parameter: for input up to 64 bits long, we must not spend more * than a very short time, for fear of slowing things down on average. * With the current tuning formula, increase our efforts somewhat at 49 bit * input (an extra round for each bit at first), and go up more and more * rapidly after we pass 80 bits.-- Changed this to adjust for the presence of * squfof, which will finish input up to 59 bits quickly. */ static GEN pollardbrent(GEN n) { const long tune_pb_min = 14; /* even 15 seems too much. */ long c0, size = expi(n) + 1; if (size <= 28) c0 = 32;/* amounts very nearly to 'insist'. Now that we have squfof(), we * don't insist any more when input is 2^29 ... 2^32 */ else if (size <= 42) c0 = tune_pb_min; else if (size <= 59) /* match squfof() cutoff point */ c0 = tune_pb_min + ((size - 42)<<1); else if (size <= 72) c0 = tune_pb_min + size - 24; else if (size <= 301) /* nonlinear increase in effort, kicking in around 80 bits */ /* 301 gives 48121 + tune_pb_min */ c0 = tune_pb_min + size - 60 + ((size-73)>>1)*((size-70)>>3)*((size-56)>>4); else c0 = 49152; /* ECM is faster when it'd take longer */ return pollardbrent_i(n, size, c0, 0); } GEN Z_pollardbrent(GEN n, long rounds, long seed) { pari_sp av = avma; GEN v = pollardbrent_i(n, expi(n)+1, rounds, seed); if (!v) return NULL; if (typ(v) == t_INT) v = mkvec2(v, diviiexact(n,v)); else if (lg(v) == 7) v = mkvec2(gel(v,1), gel(v,4)); else v = mkvec3(gel(v,1), gel(v,4), gel(v,7)); return gerepilecopy(av, v); } /***********************************************************************/ /** FACTORIZATION (Shanks' SQUFOF) --GN2000Sep30-Oct01 **/ /** squfof() returns a nontrivial factor of n, assuming n is odd, **/ /** composite, not a pure square, and has no small prime divisor, **/ /** or NULL if it fails to find one. It works on two discriminants **/ /** simultaneously (n and 5n for n=1(4), 3n and 4n for n=3(4)). **/ /** Present implementation is limited to input <2^59, and works most **/ /** of the time in signed arithmetic on integers <2^31 in absolute **/ /** size. (Cf. Algo 8.7.2 in ACiCNT) **/ /***********************************************************************/ /* The following is invoked to walk back along the ambiguous cycle* until we * hit an ambiguous form and thus the desired factor, which it returns. If it * fails for any reason, it returns 0. It doesn't interfere with timing and * diagnostics, which it leaves to squfof(). * * Before we invoke this, we've found a form (A, B, -C) with A = a^2, where a * isn't blacklisted and where gcd(a, B) = 1. According to ACiCANT, we should * now proceed reducing the form (a, -B, -aC), but it is easy to show that the * first reduction step always sends this to (-aC, B, a), and the next one, * with q computed as usual from B and a (occupying the c position), gives a * reduced form, whose third member is easiest to recover by going back to D. * From this point onwards, we're once again working with single-word numbers. * No need to track signs, just work with the abs values of the coefficients. */ static long squfof_ambig(long a, long B, long dd, GEN D) { long b, c, q, qa, qc, qcb, a0, b0, b1, c0; long cnt = 0; /* count reduction steps on the cycle */ q = (dd + (B>>1)) / a; qa = q * a; b = (qa - B) + qa; /* avoid overflow */ { pari_sp av = avma; c = itos(divis(shifti(subii(D, sqrs(b)), -2), a)); avma = av; } #ifdef DEBUG_SQUFOF err_printf("SQUFOF: ambigous cycle of discriminant %Ps\n", D); err_printf("SQUFOF: Form on ambigous cycle (%ld, %ld, %ld)\n", a, b, c); #endif a0 = a; b0 = b1 = b; /* end of loop detection and safeguard */ for (;;) /* reduced cycles are finite */ { /* reduction step */ c0 = c; if (c0 > dd) q = 1; else q = (dd + (b>>1)) / c0; if (q == 1) { qcb = c0 - b; b = c0 + qcb; c = a - qcb; } else { qc = q*c0; qcb = qc - b; b = qc + qcb; c = a - q*qcb; } a = c0; cnt++; if (b == b1) break; /* safeguard against infinite loop: recognize when we've walked the entire * cycle in vain. (I don't think this can actually happen -- exercise.) */ if (b == b0 && a == a0) return 0; b1 = b; } q = a&1 ? a : a>>1; if (DEBUGLEVEL >= 4) { if (q > 1) err_printf("SQUFOF: found factor %ld from ambiguous form\n" "\tafter %ld steps on the ambiguous cycle\n", q / ugcd(q,15), cnt); else err_printf("SQUFOF: ...found nothing on the ambiguous cycle\n" "\tafter %ld steps there\n", cnt); if (DEBUGLEVEL >= 6) err_printf("SQUFOF: squfof_ambig returned %ld\n", q); } return q; } #define SQUFOF_BLACKLIST_SZ 64 /* assume 2,3,5 do not divide n */ static GEN squfof(GEN n) { ulong d1, d2; long tf = lgefint(n), nm4, cnt = 0; long a1, b1, c1, dd1, L1, a2, b2, c2, dd2, L2, a, q, c, qc, qcb; GEN D1, D2; pari_sp av = avma; long blacklist1[SQUFOF_BLACKLIST_SZ], blacklist2[SQUFOF_BLACKLIST_SZ]; long blp1 = 0, blp2 = 0; int act1 = 1, act2 = 1; #ifdef LONG_IS_64BIT if (tf > 3 || (tf == 3 && uel(n,2) >= (1UL << (BITS_IN_LONG-5)))) #else /* 32 bits */ if (tf > 4 || (tf == 4 && (ulong)(*int_MSW(n)) >= (1UL << (BITS_IN_LONG-5)))) #endif return NULL; /* n too large */ /* now we have 5 < n < 2^59 */ nm4 = mod4(n); if (nm4 == 1) { /* n = 1 (mod4): run one iteration on D1 = n, another on D2 = 5n */ D1 = n; D2 = mului(5,n); d2 = itou(sqrti(D2)); dd2 = (long)((d2>>1) + (d2&1)); b2 = (long)((d2-1) | 1); /* b1, b2 will always stay odd */ } else { /* n = 3 (mod4): run one iteration on D1 = 3n, another on D2 = 4n */ D1 = mului(3,n); D2 = shifti(n,2); dd2 = itou(sqrti(n)); d2 = dd2 << 1; b2 = (long)(d2 & (~1UL)); /* largest even below d2, will stay even */ } d1 = itou(sqrti(D1)); b1 = (long)((d1-1) | 1); /* largest odd number not exceeding d1 */ c1 = itos(shifti(subii(D1, sqru((ulong)b1)), -2)); if (!c1) pari_err_BUG("squfof [caller of] (n or 3n is a square)"); c2 = itos(shifti(subii(D2, sqru((ulong)b2)), -2)); if (!c2) pari_err_BUG("squfof [caller of] (5n is a square)"); L1 = (long)usqrt(d1); L2 = (long)usqrt(d2); /* dd1 used to compute floor((d1+b1)/2) as dd1+floor(b1/2), without * overflowing the 31bit signed integer size limit. Same for dd2. */ dd1 = (long) ((d1>>1) + (d1&1)); a1 = a2 = 1; /* The two (identity) forms (a1,b1,-c1) and (a2,b2,-c2) are now set up. * * a1 and c1 represent the absolute values of the a,c coefficients; we keep * track of the sign separately, via the iteration counter cnt: when cnt is * even, c is understood to be negative, else c is positive and a < 0. * * L1, L2 are the limits for blacklisting small leading coefficients * on the principal cycle, to guarantee that when we find a square form, * its square root will belong to an ambiguous cycle (i.e. won't be an * earlier form on the principal cycle). * * When n = 3(mod 4), D2 = 12(mod 16), and b^2 is always 0 or 4 mod 16. * It follows that 4*a*c must be 4 or 8 mod 16, respectively, so at most * one of a,c can be divisible by 2 at most to the first power. This fact * is used a couple of times below. * * The flags act1, act2 remain true while the respective cycle is still * active; we drop them to false when we return to the identity form with- * out having found a square form (or when the blacklist overflows, which * shouldn't happen). */ if (DEBUGLEVEL >= 4) err_printf("SQUFOF: entering main loop with forms\n" "\t(1, %ld, %ld) and (1, %ld, %ld)\n\tof discriminants\n" "\t%Ps and %Ps, respectively\n", b1, -c1, b2, -c2, D1, D2); /* MAIN LOOP: walk around the principal cycle looking for a square form. * Blacklist small leading coefficients. * * The reduction operator can be computed entirely in 32-bit arithmetic: * Let q = floor(floor((d1+b1)/2)/c1) (when c1>dd1, q=1, which happens * often enough to special-case it). Then the new b1 = (q*c1-b1) + q*c1, * which does not overflow, and the new c1 = a1 - q*(q*c1-b1), which is * bounded by d1 in abs size since both the old and the new a1 are positive * and bounded by d1. */ while (act1 || act2) { if (act1) { /* send first form through reduction operator if active */ c = c1; q = (c > dd1)? 1: (dd1 + (b1>>1)) / c; if (q == 1) { qcb = c - b1; b1 = c + qcb; c1 = a1 - qcb; } else { qc = q*c; qcb = qc - b1; b1 = qc + qcb; c1 = a1 - q*qcb; } a1 = c; if (a1 <= L1) { /* blacklist this */ if (blp1 >= SQUFOF_BLACKLIST_SZ) /* overflows: shouldn't happen */ act1 = 0; /* silently */ else { if (DEBUGLEVEL >= 6) err_printf("SQUFOF: blacklisting a = %ld on first cycle\n", a1); blacklist1[blp1++] = a1; } } } if (act2) { /* send second form through reduction operator if active */ c = c2; q = (c > dd2)? 1: (dd2 + (b2>>1)) / c; if (q == 1) { qcb = c - b2; b2 = c + qcb; c2 = a2 - qcb; } else { qc = q*c; qcb = qc - b2; b2 = qc + qcb; c2 = a2 - q*qcb; } a2 = c; if (a2 <= L2) { /* blacklist this */ if (blp2 >= SQUFOF_BLACKLIST_SZ) /* overflows: shouldn't happen */ act2 = 0; /* silently */ else { if (DEBUGLEVEL >= 6) err_printf("SQUFOF: blacklisting a = %ld on second cycle\n", a2); blacklist2[blp2++] = a2; } } } /* bump counter, loop if this is an odd iteration (i.e. if the real * leading coefficients are negative) */ if (++cnt & 1) continue; /* second half of main loop entered only when the leading coefficients * are positive (i.e., during even-numbered iterations) */ /* examine first form if active */ if (act1 && a1 == 1) /* back to identity */ { /* drop this discriminant */ act1 = 0; if (DEBUGLEVEL >= 4) err_printf("SQUFOF: first cycle exhausted after %ld iterations,\n" "\tdropping it\n", cnt); } if (act1) { if (uissquareall((ulong)a1, (ulong*)&a)) { /* square form */ if (DEBUGLEVEL >= 4) err_printf("SQUFOF: square form (%ld^2, %ld, %ld) on first cycle\n" "\tafter %ld iterations\n", a, b1, -c1, cnt); if (a <= L1) { /* blacklisted? */ long j; for (j = 0; j < blp1; j++) if (a == blacklist1[j]) { a = 0; break; } } if (a > 0) { /* not blacklisted */ q = ugcd(a, b1); /* imprimitive form? */ if (q > 1) { /* q^2 divides D1 hence n [ assuming n % 3 != 0 ] */ avma = av; if (DEBUGLEVEL >= 4) err_printf("SQUFOF: found factor %ld^2\n", q); return mkvec3(utoipos(q), gen_2, NULL);/* exponent 2, unknown status */ } /* chase the inverse root form back along the ambiguous cycle */ q = squfof_ambig(a, b1, dd1, D1); if (nm4 == 3 && q % 3 == 0) q /= 3; if (q > 1) { avma = av; return utoipos(q); } /* SUCCESS! */ } else if (DEBUGLEVEL >= 4) /* blacklisted */ err_printf("SQUFOF: ...but the root form seems to be on the " "principal cycle\n"); } } /* examine second form if active */ if (act2 && a2 == 1) /* back to identity form */ { /* drop this discriminant */ act2 = 0; if (DEBUGLEVEL >= 4) err_printf("SQUFOF: second cycle exhausted after %ld iterations,\n" "\tdropping it\n", cnt); } if (act2) { if (uissquareall((ulong)a2, (ulong*)&a)) { /* square form */ if (DEBUGLEVEL >= 4) err_printf("SQUFOF: square form (%ld^2, %ld, %ld) on second cycle\n" "\tafter %ld iterations\n", a, b2, -c2, cnt); if (a <= L2) { /* blacklisted? */ long j; for (j = 0; j < blp2; j++) if (a == blacklist2[j]) { a = 0; break; } } if (a > 0) { /* not blacklisted */ q = ugcd(a, b2); /* imprimitive form? */ /* NB if b2 is even, a is odd, so the gcd is always odd */ if (q > 1) { /* q^2 divides D2 hence n [ assuming n % 5 != 0 ] */ avma = av; if (DEBUGLEVEL >= 4) err_printf("SQUFOF: found factor %ld^2\n", q); return mkvec3(utoipos(q), gen_2, NULL);/* exponent 2, unknown status */ } /* chase the inverse root form along the ambiguous cycle */ q = squfof_ambig(a, b2, dd2, D2); if (nm4 == 1 && q % 5 == 0) q /= 5; if (q > 1) { avma = av; return utoipos(q); } /* SUCCESS! */ } else if (DEBUGLEVEL >= 4) /* blacklisted */ err_printf("SQUFOF: ...but the root form seems to be on the " "principal cycle\n"); } } } /* end main loop */ /* both discriminants turned out to be useless. */ if (DEBUGLEVEL>=4) err_printf("SQUFOF: giving up\n"); avma = av; return NULL; } /***********************************************************************/ /* DETECTING ODD POWERS --GN1998Jun28 */ /* Factoring engines like MPQS which ultimately rely on computing */ /* gcd(N, x^2-y^2) to find a nontrivial factor of N can't split */ /* N = p^k for an odd prime p, since (Z/p^k)^* is then cyclic. Here */ /* is an analogue of Z_issquareall() for 3rd, 5th and 7th powers. */ /* The general case is handled by is_kth_power */ /***********************************************************************/ /* Multistage sieve. First stages work mod 211, 209, 61, 203 in this order * (first reduce mod the product of these and then take the remainder apart). * Second stages use 117, 31, 43, 71. Moduli which are no longer interesting * are skipped. Everything is encoded in a table of 106 24-bit masks. We only * need the first half of the residues. Three bits per modulus indicate which * residues are 7th (bit 2), 5th (bit 1) or 3rd (bit 0) powers; the eight * moduli above are assigned right-to-left. The table was generated using: */ #if 0 L = [71, 43, 31, [O(3^2),O(13)], [O(7),O(29)], 61, [O(11),O(19)], 211]; ispow(x, N, k)= { if (type(N) == "t_INT", return (ispower(Mod(x,N), k))); for (i = 1, #N, if (!ispower(x + N[i], k), return (0))); 1 } check(r) = { print1(" 0"); for (i=1,#L, N = 0; if (ispow(r, L[i], 3), N += 1); if (ispow(r, L[i], 5), N += 2); if (ispow(r, L[i], 7), N += 4); print1(N); ); print("ul, /* ", r, " */") } for (r = 0, 105, check(r)) #endif static ulong powersmod[106] = { 077777777ul, /* 0 */ 077777777ul, /* 1 */ 013562440ul, /* 2 */ 012402540ul, /* 3 */ 013562440ul, /* 4 */ 052662441ul, /* 5 */ 016603440ul, /* 6 */ 016463450ul, /* 7 */ 013573551ul, /* 8 */ 012462540ul, /* 9 */ 012462464ul, /* 10 */ 013462771ul, /* 11 */ 012406473ul, /* 12 */ 012463641ul, /* 13 */ 052463646ul, /* 14 */ 012503446ul, /* 15 */ 013562440ul, /* 16 */ 052466440ul, /* 17 */ 012472451ul, /* 18 */ 012462454ul, /* 19 */ 032463550ul, /* 20 */ 013403664ul, /* 21 */ 013463460ul, /* 22 */ 032562565ul, /* 23 */ 012402540ul, /* 24 */ 052662441ul, /* 25 */ 032672452ul, /* 26 */ 013573551ul, /* 27 */ 012467541ul, /* 28 */ 012567640ul, /* 29 */ 032706450ul, /* 30 */ 012762452ul, /* 31 */ 033762662ul, /* 32 */ 012502562ul, /* 33 */ 032463562ul, /* 34 */ 013563440ul, /* 35 */ 016663440ul, /* 36 */ 036662550ul, /* 37 */ 012462552ul, /* 38 */ 033502450ul, /* 39 */ 012462643ul, /* 40 */ 033467540ul, /* 41 */ 017403441ul, /* 42 */ 017463462ul, /* 43 */ 017472460ul, /* 44 */ 033462470ul, /* 45 */ 052566450ul, /* 46 */ 013562640ul, /* 47 */ 032403640ul, /* 48 */ 016463450ul, /* 49 */ 016463752ul, /* 50 */ 033402440ul, /* 51 */ 012462540ul, /* 52 */ 012472540ul, /* 53 */ 053562462ul, /* 54 */ 012463465ul, /* 55 */ 012663470ul, /* 56 */ 052607450ul, /* 57 */ 012566553ul, /* 58 */ 013466440ul, /* 59 */ 012502741ul, /* 60 */ 012762744ul, /* 61 */ 012763740ul, /* 62 */ 012763443ul, /* 63 */ 013573551ul, /* 64 */ 013462471ul, /* 65 */ 052502460ul, /* 66 */ 012662463ul, /* 67 */ 012662451ul, /* 68 */ 012403550ul, /* 69 */ 073567540ul, /* 70 */ 072463445ul, /* 71 */ 072462740ul, /* 72 */ 012472442ul, /* 73 */ 012462644ul, /* 74 */ 013406650ul, /* 75 */ 052463471ul, /* 76 */ 012563474ul, /* 77 */ 013503460ul, /* 78 */ 016462441ul, /* 79 */ 016462440ul, /* 80 */ 012462540ul, /* 81 */ 013462641ul, /* 82 */ 012463454ul, /* 83 */ 013403550ul, /* 84 */ 057563540ul, /* 85 */ 017466441ul, /* 86 */ 017606471ul, /* 87 */ 053666573ul, /* 88 */ 012562561ul, /* 89 */ 013473641ul, /* 90 */ 032573440ul, /* 91 */ 016763440ul, /* 92 */ 016702640ul, /* 93 */ 033762552ul, /* 94 */ 012562550ul, /* 95 */ 052402451ul, /* 96 */ 033563441ul, /* 97 */ 012663561ul, /* 98 */ 012677560ul, /* 99 */ 012462464ul, /* 100 */ 032562642ul, /* 101 */ 013402551ul, /* 102 */ 032462450ul, /* 103 */ 012467445ul, /* 104 */ 032403440ul, /* 105 */ }; static int check_res(ulong x, ulong N, int shift, ulong *mask) { long r = x%N; if ((ulong)r> (N>>1)) r = N - r; *mask &= (powersmod[r] >> shift); return *mask; } /* is x mod 211*209*61*203*117*31*43*71 a 3rd, 5th or 7th power ? */ int uis_357_powermod(ulong x, ulong *mask) { if ( !check_res(x, 211UL, 0, mask)) return 0; if (*mask & 3 && !check_res(x, 209UL, 3, mask)) return 0; if (*mask & 3 && !check_res(x, 61UL, 6, mask)) return 0; if (*mask & 5 && !check_res(x, 203UL, 9, mask)) return 0; if (*mask & 1 && !check_res(x, 117UL,12, mask)) return 0; if (*mask & 3 && !check_res(x, 31UL,15, mask)) return 0; if (*mask & 5 && !check_res(x, 43UL,18, mask)) return 0; if (*mask & 6 && !check_res(x, 71UL,21, mask)) return 0; return 1; } /* asume x > 0 and pt != NULL */ int uis_357_power(ulong x, ulong *pt, ulong *mask) { double logx; if (!odd(x)) { long v = vals(x); if (v % 7) *mask &= ~4; if (v % 5) *mask &= ~2; if (v % 3) *mask &= ~1; if (!*mask) return 0; } if (!uis_357_powermod(x, mask)) return 0; logx = log((double)x); while (*mask) { long e, b; ulong y, ye; if (*mask & 1) { b = 1; e = 3; } else if (*mask & 2) { b = 2; e = 5; } else { b = 4; e = 7; } y = (ulong)(exp(logx / e) + 0.5); ye = upowuu(y,e); if (ye == x) { *pt = y; return e; } #ifdef LONG_IS_64BIT if (ye > x) y--; else y++; ye = upowuu(y,e); if (ye == x) { *pt = y; return e; } #endif *mask &= ~b; /* turn the bit off */ } return 0; } #ifndef LONG_IS_64BIT /* as above, split in two functions */ /* is x mod 211*209*61*203 a 3rd, 5th or 7th power ? */ static int uis_357_powermod_32bit_1(ulong x, ulong *mask) { if ( !check_res(x, 211UL, 0, mask)) return 0; if (*mask & 3 && !check_res(x, 209UL, 3, mask)) return 0; if (*mask & 3 && !check_res(x, 61UL, 6, mask)) return 0; if (*mask & 5 && !check_res(x, 203UL, 9, mask)) return 0; return 1; } /* is x mod 117*31*43*71 a 3rd, 5th or 7th power ? */ static int uis_357_powermod_32bit_2(ulong x, ulong *mask) { if (*mask & 1 && !check_res(x, 117UL,12, mask)) return 0; if (*mask & 3 && !check_res(x, 31UL,15, mask)) return 0; if (*mask & 5 && !check_res(x, 43UL,18, mask)) return 0; if (*mask & 6 && !check_res(x, 71UL,21, mask)) return 0; return 1; } #endif /* Returns 3, 5, or 7 if x is a cube (but not a 5th or 7th power), a 5th * power (but not a 7th), or a 7th power, and in this case creates the * base on the stack and assigns its address to *pt. Otherwise returns 0. * x must be of type t_INT and positive; this is not checked. The *mask * argument tells us which things to check -- bit 0: 3rd, bit 1: 5th, * bit 2: 7th pwr; set a bit to have the corresponding power examined -- * and is updated appropriately for a possible follow-up call */ int is_357_power(GEN x, GEN *pt, ulong *mask) { long lx = lgefint(x); ulong r; pari_sp av; GEN y; if (!*mask) return 0; /* useful when running in a loop */ if (DEBUGLEVEL>4) err_printf("OddPwrs: examining %ld-bit integer\n", expi(x)); if (lgefint(x) == 3) { ulong t; long e = uis_357_power(x[2], &t, mask); if (e) { if (pt) *pt = utoi(t); return e; } return 0; } #ifdef LONG_IS_64BIT r = (lx == 3)? uel(x,2): umodiu(x, 6046846918939827UL); if (!uis_357_powermod(r, mask)) return 0; #else r = (lx == 3)? uel(x,2): umodiu(x, 211*209*61*203); if (!uis_357_powermod_32bit_1(r, mask)) return 0; r = (lx == 3)? uel(x,2): umodiu(x, 117*31*43*71); if (!uis_357_powermod_32bit_2(r, mask)) return 0; #endif av = avma; while (*mask) { long e, b; /* priority to higher powers: if we have a 21st, it is easier to rediscover * that its 7th root is a cube than that its cube root is a 7th power */ if (*mask & 4) { b = 4; e = 7; } else if (*mask & 2) { b = 2; e = 5; } else { b = 1; e = 3; } y = mpround( sqrtnr(itor(x, nbits2prec(64 + bit_accuracy(lx) / e)), e) ); if (equalii(powiu(y,e), x)) { if (!pt) { avma = av; return e; } avma = (pari_sp)y; *pt = gerepileuptoint(av, y); return e; } *mask &= ~b; /* turn the bit off */ avma = av; } return 0; } /* Is x a n-th power ? * if d = NULL, n not necessarily prime, otherwise, n prime and d the * corresponding diffptr to go on looping over primes. * If pt != NULL, it receives the n-th root */ ulong is_kth_power(GEN x, ulong n, GEN *pt) { forprime_t T; long j; ulong q, residue; GEN y; pari_sp av = avma; (void)u_forprime_arith_init(&T, odd(n)? 2*n+1: n+1, ULONG_MAX, 1,n); /* we'll start at q, smallest prime >= n */ /* Modular checks, use small primes q congruent 1 mod n */ /* A non n-th power nevertheless passes the test with proba n^(-#checks), * We'd like this < 1e-6 but let j = floor(log(1e-6) / log(n)) which * ensures much less. */ if (n < 16) j = 5; else if (n < 32) j = 4; else if (n < 101) j = 3; else if (n < 1001) j = 2; else if (n < 17886697) /* smallest such that smallest suitable q is > 2^32 */ j = 1; else j = 0; for (; j > 0; j--) { if (!(q = u_forprime_next(&T))) break; /* q a prime = 1 mod n */ residue = umodiu(x, q); if (residue == 0) { if (Z_lval(x,q) % n) { avma = av; return 0; } continue; } /* n-th power mod q ? */ if (Fl_powu(residue, (q-1)/n, q) != 1) { avma = av; return 0; } } avma = av; if (DEBUGLEVEL>4) err_printf("\nOddPwrs: [%lu] passed modular checks\n",n); /* go to the horse's mouth... */ y = roundr( sqrtnr(itor(x, nbits2prec((expi(x)+16*n)/n)), n) ); if (!equalii(powiu(y, n), x)) { if (DEBUGLEVEL>4) err_printf("\tBut it wasn't a pure power.\n"); avma = av; return 0; } if (!pt) avma = av; else { avma = (pari_sp)y; *pt = gerepileuptoint(av, y); } return 1; } /* is x a p^i-th power, p >= 11 prime ? Similar to is_357_power(), but instead * of the mask, we keep the current test exponent around. Cut off when * log_2 x^(1/k) < cutoffbits since we would have found it by trial division. * Everything needed here (primitive roots etc.) is computed from scratch on * the fly; compared to the size of numbers under consideration, these * word-sized computations take negligible time. * Any cutoffbits > 0 is safe, but direct root extraction attempts are faster * when trial division has been used to discover very small bases. We become * competitive at cutoffbits ~ 10 */ int is_pth_power(GEN x, GEN *pt, forprime_t *T, ulong cutoffbits) { long cnt=0, size = expi(x) /* not +1 */; ulong p; pari_sp av = avma; while ((p = u_forprime_next(T)) && size/p >= cutoffbits) { long v = 1; if (DEBUGLEVEL>5 && cnt++==2000) { cnt=0; err_printf("%lu%% ", 100*p*cutoffbits/size); } while (is_kth_power(x, p, pt)) { v *= p; x = *pt; size = expi(x); } if (v > 1) { if (DEBUGLEVEL>5) err_printf("\nOddPwrs: is a %ld power\n",v); return v; } } if (DEBUGLEVEL>5) err_printf("\nOddPwrs: not a power\n",p); avma = av; return 0; /* give up */ } /***********************************************************************/ /** FACTORIZATION (master iteration) **/ /** Driver for the various methods of finding large factors **/ /** (after trial division has cast out the very small ones). **/ /** GN1998Jun24--30 **/ /***********************************************************************/ /* Direct use: * ifac_start_hint(n,moebius,hint) registers with the iterative factorizer * - an integer n (without prime factors < tridiv_bound(n)) * - registers whether or not we should terminate early if we find a square * factor, * - a hint about which method(s) to use. * This must always be called first. If input is not composite, oo loop. * The routine decomposes n nontrivially into a product of two factors except * in squarefreeness ('Moebius') mode. * * ifac_start(n,moebius) same using default hint. * * ifac_primary_factor() returns a prime divisor (not necessarily the * smallest) and the corresponding exponent. * * Encapsulated user interface: Many arithmetic functions have a 'contributor' * ifac_xxx, to be called on any large composite cofactor left over after trial * division by small primes: xxx is one of moebius, issquarefree, totient, etc. * * We never test whether the input number is prime or composite, since * presumably it will have come out of the small factors finder stage * (which doesn't really exist yet but which will test the left-over * cofactor for primality once it does). */ /* The data structure in which we preserve whatever we know about our number N * is kept on the PARI stack, and updated as needed. * This makes the machinery re-entrant, and avoids memory leaks when a lengthy * factorization is interrupted. We try to keep the whole affair connected, * and the parent object is always older than its children. This may in * rare cases lead to some extra copying around, and knowing what is garbage * at any given time is not trivial. See below for examples how to do it right. * (Connectedness is destroyed if callers of ifac_main() create stuff on the * stack in between calls. This is harmless as long as ifac_realloc() is used * to re-create a connected object at the head of the stack just before * collecting garbage.) * A t_INT may well have > 10^6 distinct prime factors larger than 2^16. Since * we need not find factors in order of increasing size, we must be prepared to * drag a very large amount of data around. We start with a small structure * and extend it when necessary. */ /* The idea of the algorithm is: * Let N0 be whatever is currently left of N after dividing off all the * prime powers we have already returned to the caller. Then we maintain * N0 as a product * (1) N0 = \prod_i P_i^{e_i} * \prod_j Q_j^{f_j} * \prod_k C_k^{g_k} * where the P_i and Q_j are distinct primes, each C_k is known composite, * none of the P_i divides any C_k, and we also know the total ordering * of all the P_i, Q_j and C_k; in particular, we will never try to divide * a C_k by a larger Q_j. Some of the C_k may have common factors. * * Caveat implementor: Taking gcds among C_k's is very likely to cost at * least as much time as dividing off any primes as we find them, and book- * keeping would be tough (since D=gcd(C_1,C_2) can still have common factors * with both C_1/D and C_2/D, and so on...). * * At startup, we just initialize the structure to * (2) N = C_1^1 (composite). * * Whenever ifac_primary_factor() or one of the arithmetic user interface * routines needs a primary factor, and the smallest thing in our list is P_1, * we return that and its exponent, and remove it from our list. (When nothing * is left, we return a sentinel value -- gen_1. And in Moebius mode, when we * see something with exponent > 1, whether prime or composite, we return gen_0 * or 0, depending on the function). In all other cases, ifac_main() iterates * the following steps until we have a P_1 in the smallest position. * * When the smallest item is C_1, as it is initially: * (3.1) Crack C_1 into a nontrivial product U_1 * U_2 by whatever method * comes to mind for this size. (U for 'unknown'.) Cracking will detect * perfect powers, so we may instead see a power of some U_1 here, or even * something of the form U_1^k*U_2^k; of course the exponent already attached * to C_1 is taken into account in the following. * (3.2) If we have U_1*U_2, sort the two factors (distinct: squares are caught * in stage 3.1). N.B. U_1 and U_2 are smaller than anything else in our list. * (3.3) Check U_1 and U_2 for primality, and flag them accordingly. * (3.4) Iterate. * * When the smallest item is Q_1: * This is the unpleasant case. We go through the entire list and try to * divide Q_1 off each of the current C_k's, which usually fails, but may * succeed several times. When a division was successful, the corresponding * C_k is removed from our list, and the cofactor becomes a U_l for the moment * unless it is 1 (which happens when C_k was a power of Q_1). When we're * through we upgrade Q_1 to P_1 status, then do a primality check on each U_l * and sort it back into the list either as a Q_j or as a C_k. If during the * insertion sort we discover that some U_l equals some P_i or Q_j or C_k we * already have, we just add U_l's exponent to that of its twin. (The sorting * therefore happens before the primality test). Since this may produce one or * more elements smaller than the P_1 we just confirmed, we may have to repeat * the iteration. * A trick avoids some Q_1 instances: just after the sweep classifying * all current unknowns as either composites or primes, we do another downward * sweep beginning with the largest current factor and stopping just above the * largest current composite. Every Q_j we pass is turned into a P_i. * (Different primes are automatically coprime among each other, and primes do * not divide smaller composites.) * NB: We have no use for comparing the square of a prime to N0. Normally * we will get called after casting out only the smallest primes, and * since we cannot guarantee that we see the large prime factors in as- * cending order, we cannot stop when we find one larger than sqrt(N0). */ /* Data structure: We keep everything in a single t_VEC of t_INTs. The * first 2 components are read-only: * 1) the first records whether we're doing full (NULL) or Moebius (gen_1) * factorization; in the latter case subroutines return a sentinel value as * soon as they spot an exponent > 1. * 2) the second records the hint from factorint()'s optional flag, for use by * ifac_crack(). * * The remaining components (initially 15) are used in groups of three: * [ factor (t_INT), exponent (t_INT), factor class ], where factor class is * NULL : unknown * gen_0: known composite C_k * gen_1: known prime Q_j awaiting trial division * gen_2: finished prime P_i. * When during the division stage we re-sort a C_k-turned-U_l to a lower * position, we rotate any intervening material upward towards its old * slot. When a C_k was divided down to 1, its slot is left empty at * first; similarly when the re-sorting detects a repeated factor. * After the sorting phase, we de-fragment the list and squeeze all the * occupied slots together to the high end, so that ifac_crack() has room * for new factors. When this doesn't suffice, we abandon the current vector * and allocate a somewhat larger one, defragmenting again while copying. * * For internal use: note that all exponents will fit into C longs, given * PARI's lgefint field size. When we work with them, we sometimes read * out the GEN pointer, and sometimes do an itos, whatever is more con- * venient for the task at hand. */ /*** Overview ***/ /* The '*where' argument in the following points into *partial at the first of * the three fields of the first occupied slot. It's there because the caller * would already know where 'here' is, so we don't want to search for it again. * We do not preserve this from one user-interface call to the next. */ /* In the most common cases, control flows from the user interface to * ifac_main() and then to a succession of ifac_crack()s and ifac_divide()s, * with (typically) none of the latter finding anything. */ static long ifac_insert_multiplet(GEN *, GEN *, GEN, long); #define LAST(x) x+lg(x)-3 #define FIRST(x) x+3 #define MOEBIUS(x) gel(x,1) #define HINT(x) gel(x,2) /* y <- x */ INLINE void SHALLOWCOPY(GEN x, GEN y) { VALUE(y) = VALUE(x); EXPON(y) = EXPON(x); CLASS(y) = CLASS(x); } /* y <- x */ INLINE void COPY(GEN x, GEN y) { icopyifstack(VALUE(x), VALUE(y)); icopyifstack(EXPON(x), EXPON(y)); CLASS(y) = CLASS(x); } /* Diagnostics */ static void ifac_factor_dbg(GEN x) { GEN c = CLASS(x), v = VALUE(x); if (c == gen_2) err_printf("IFAC: factor %Ps\n\tis prime (finished)\n", v); else if (c == gen_1) err_printf("IFAC: factor %Ps\n\tis prime\n", v); else if (c == gen_0) err_printf("IFAC: factor %Ps\n\tis composite\n", v); } static void ifac_check(GEN partial, GEN where) { if (!where || where < FIRST(partial) || where > LAST(partial)) pari_err_BUG("ifac_check ['where' out of bounds]"); } static void ifac_print(GEN part, GEN where) { long l = lg(part); GEN p; err_printf("ifac partial factorization structure: %ld slots, ", (l-3)/3); if (MOEBIUS(part)) err_printf("Moebius mode, "); err_printf("hint = %ld\n", itos(HINT(part))); ifac_check(part, where); for (p = part+3; p < part + l; p += 3) { GEN v = VALUE(p), e = EXPON(p), c = CLASS(p); const char *s = ""; if (!v) { err_printf("[empty slot]\n"); continue; } if (c == NULL) s = "unknown"; else if (c == gen_0) s = "composite"; else if (c == gen_1) s = "unfinished prime"; else if (c == gen_2) s = "prime"; else pari_err_BUG("unknown factor class"); err_printf("[%Ps, %Ps, %s]\n", v, e, s); } err_printf("Done.\n"); } static const long decomp_default_hint = 0; /* assume n > 0, which we can assign to */ /* return initial data structure, see ifac_crack() for the hint argument */ static GEN ifac_start_hint(GEN n, int moebius, long hint) { const long ifac_initial_length = 3 + 7*3; /* codeword, moebius, hint, 7 slots -- a 512-bit product of distinct 8-bit * primes needs at most 7 slots at a time) */ GEN here, part = cgetg(ifac_initial_length, t_VEC); MOEBIUS(part) = moebius? gen_1 : NULL; HINT(part) = stoi(hint); if (isonstack(n)) n = absi(n); /* make copy, because we'll later want to replace it in place. * If it's not on stack, then we assume it is a clone made for us by * ifactor, and we assume the sign has already been set positive */ /* fill first slot at the top end */ here = part + ifac_initial_length - 3; /* LAST(part) */ INIT(here, n,gen_1,gen_0); /* n^1: composite */ while ((here -= 3) > part) ifac_delete(here); return part; } GEN ifac_start(GEN n, int moebius) { return ifac_start_hint(n,moebius,decomp_default_hint); } /* Return next nonempty slot after 'here', NULL if none exist */ static GEN ifac_find(GEN partial) { GEN scan, end = partial + lg(partial); #ifdef IFAC_DEBUG ifac_check(partial, partial); #endif for (scan = partial+3; scan < end; scan += 3) if (VALUE(scan)) return scan; return NULL; } /* Defragment: squeeze out unoccupied slots above *where. Unoccupied slots * arise when a composite factor dissolves completely whilst dividing off a * prime, or when ifac_resort() spots a coincidence and merges two factors. * Update *where */ static void ifac_defrag(GEN *partial, GEN *where) { GEN scan_new = LAST(*partial), scan_old; for (scan_old = scan_new; scan_old >= *where; scan_old -= 3) { if (!VALUE(scan_old)) continue; /* empty slot */ if (scan_old < scan_new) SHALLOWCOPY(scan_old, scan_new); scan_new -= 3; /* point at next slot to be written */ } scan_new += 3; /* back up to last slot written */ *where = scan_new; while ((scan_new -= 3) > *partial) ifac_delete(scan_new); /* erase junk */ } /* Move to a larger main vector, updating *where if it points into it, and * *partial in any case. Can be used as a specialized gcopy before * a gerepileupto() (pass 0 as the new length). Normally, one would pass * new_lg=1 to let this function guess the new size. To be used sparingly. * Complex version of ifac_defrag(), combined with reallocation. If new_lg * is 0, use the old length, so this acts just like gcopy except that the * 'where' pointer is carried along; if it is 1, we make an educated guess. * Exception: If new_lg is 0, the vector is full to the brim, and the first * entry is composite, we make it longer to avoid being called again a * microsecond later. It is safe to call this with *where = NULL: * if it doesn't point anywhere within the old structure, it is left alone */ static void ifac_realloc(GEN *partial, GEN *where, long new_lg) { long old_lg = lg(*partial); GEN newpart, scan_new, scan_old; if (new_lg == 1) new_lg = 2*old_lg - 6; /* from 7 slots to 13 to 25... */ else if (new_lg <= old_lg) /* includes case new_lg == 0 */ { GEN first = *partial + 3; new_lg = old_lg; /* structure full and first entry composite or unknown */ if (VALUE(first) && (CLASS(first) == gen_0 || CLASS(first)==NULL)) new_lg += 6; /* give it a little more breathing space */ } newpart = cgetg(new_lg, t_VEC); if (DEBUGMEM >= 3) err_printf("IFAC: new partial factorization structure (%ld slots)\n", (new_lg - 3)/3); MOEBIUS(newpart) = MOEBIUS(*partial); icopyifstack(HINT(*partial), HINT(newpart)); /* Downward sweep through the old *partial. Pick up 'where' and carry it * over if we pass it. (Only useful if it pointed at a non-empty slot.) * Factors are COPY'd so that we again have a nice object (parent older * than children, connected), except the one factor that may still be living * in a clone where n originally was; exponents are similarly copied if they * aren't global constants; class-of-factor fields are global constants so we * need only copy them as pointers. Caller may then do a gerepileupto() */ scan_new = newpart + new_lg - 3; /* LAST(newpart) */ scan_old = *partial + old_lg - 3; /* LAST(*partial) */ for (; scan_old > *partial + 2; scan_old -= 3) { if (*where == scan_old) *where = scan_new; if (!VALUE(scan_old)) continue; /* skip empty slots */ COPY(scan_old, scan_new); scan_new -= 3; } scan_new += 3; /* back up to last slot written */ while ((scan_new -= 3) > newpart) ifac_delete(scan_new); *partial = newpart; } /* Re-sort one (typically unknown) entry from washere to a new position, * rotating intervening entries upward to fill the vacant space. If the new * position is the same as the old one, or the new value of the entry coincides * with a value already occupying a lower slot, then we just add exponents (and * use the 'more known' class, and return 1 immediately when in Moebius mode). * Slots between *where and washere must be in sorted order, so a sweep using * this to re-sort several unknowns must proceed upward, see ifac_resort(). * Bubble-sort-of-thing sort. Won't be exercised frequently, so this is ok */ static void ifac_sort_one(GEN *where, GEN washere) { GEN old, scan = washere - 3; GEN value, exponent, class0, class1; long cmp_res; if (scan < *where) return; /* nothing to do, washere==*where */ value = VALUE(washere); exponent = EXPON(washere); class0 = CLASS(washere); cmp_res = -1; /* sentinel */ while (scan >= *where) /* at least once */ { if (VALUE(scan)) { /* current slot nonempty, check against where */ cmp_res = cmpii(value, VALUE(scan)); if (cmp_res >= 0) break; /* have found where to stop */ } /* copy current slot upward by one position and move pointers down */ SHALLOWCOPY(scan, scan+3); scan -= 3; } scan += 3; /* At this point there are the following possibilities: * 1) cmp_res == -1. Either value is less than that at *where, or *where was * pointing at vacant slots and any factors we saw en route were larger than * value. At any rate, scan == *where now, and scan is pointing at an empty * slot, into which we'll stash our entry. * 2) cmp_res == 0. The entry at scan-3 is the one, we compare class0 * fields and add exponents, and put it all into the vacated scan slot, * NULLing the one at scan-3 (and possibly updating *where). * 3) cmp_res == 1. The slot at scan is the one to store our entry into. */ if (cmp_res) { if (cmp_res < 0 && scan != *where) pari_err_BUG("ifact_sort_one [misaligned partial]"); INIT(scan, value, exponent, class0); return; } /* case cmp_res == 0: repeated factor detected */ if (DEBUGLEVEL >= 4) err_printf("IFAC: repeated factor %Ps\n\tin ifac_sort_one\n", value); old = scan - 3; /* if old class0 was composite and new is prime, or vice versa, complain * (and if one class0 was unknown and the other wasn't, use the known one) */ class1 = CLASS(old); if (class0) /* should never be used */ { if (class1) { if (class0 == gen_0 && class1 != gen_0) pari_err_BUG("ifac_sort_one (composite = prime)"); else if (class0 != gen_0 && class1 == gen_0) pari_err_BUG("ifac_sort_one (prime = composite)"); else if (class0 == gen_2) CLASS(scan) = class0; } else CLASS(scan) = class0; } /* else stay with the existing known class0 */ CLASS(scan) = class1; /* in any case, add exponents */ if (EXPON(old) == gen_1 && exponent == gen_1) EXPON(scan) = gen_2; else EXPON(scan) = addii(EXPON(old), exponent); /* move the value over and null out the vacated slot below */ old = scan - 3; *scan = *old; ifac_delete(old); /* finally, see whether *where should be pulled in */ if (old == *where) *where += 3; } /* Sort all current unknowns downward to where they belong. Sweeps in the * upward direction. Not needed after ifac_crack(), only when ifac_divide() * returned true. Update *where. */ static void ifac_resort(GEN *partial, GEN *where) { GEN scan, end; ifac_defrag(partial, where); end = LAST(*partial); for (scan = *where; scan <= end; scan += 3) if (VALUE(scan) && !CLASS(scan)) ifac_sort_one(where, scan); /*unknown*/ ifac_defrag(partial, where); /* remove newly created gaps */ } /* Let x be a t_INT known not to have small divisors (< 2^14). Return 0 if x * is a proven composite. Return 1 if we believe it to be prime (fully proven * prime if factor_proven is set). */ int ifac_isprime(GEN x) { if (!BPSW_psp_nosmalldiv(x)) return 0; /* composite */ if (factor_proven && ! BPSW_isprime(x)) { pari_warn(warner, "IFAC: pseudo-prime %Ps\n\tis not prime. PLEASE REPORT!\n", x); return 0; } return 1; } static int ifac_checkprime(GEN x) { int res = ifac_isprime(VALUE(x)); CLASS(x) = res? gen_1: gen_0; if (DEBUGLEVEL>2) ifac_factor_dbg(x); return res; } /* Determine primality or compositeness of all current unknowns, and set * class Q primes to finished (class P) if everything larger is already * known to be prime. When after_crack >= 0, only look at the * first after_crack things in the list (do nothing when it's 0) */ static void ifac_whoiswho(GEN *partial, GEN *where, long after_crack) { GEN scan, scan_end = LAST(*partial); #ifdef IFAC_DEBUG ifac_check(*partial, *where); #endif if (after_crack == 0) return; if (after_crack > 0) /* check at most after_crack entries */ scan = *where + 3*(after_crack - 1); /* assert(scan <= scan_end) */ else for (scan = scan_end; scan >= *where; scan -= 3) { if (CLASS(scan)) { /* known class of factor */ if (CLASS(scan) == gen_0) break; if (CLASS(scan) == gen_1) { if (DEBUGLEVEL>=3) { err_printf("IFAC: factor %Ps\n\tis prime (no larger composite)\n", VALUE(*where)); err_printf("IFAC: prime %Ps\n\tappears with exponent = %ld\n", VALUE(*where), itos(EXPON(*where))); } CLASS(scan) = gen_2; } continue; } if (!ifac_checkprime(scan)) break; /* must disable Q-to-P */ CLASS(scan) = gen_2; /* P_i, finished prime */ if (DEBUGLEVEL>2) ifac_factor_dbg(scan); } /* go on, Q-to-P trick now disabled */ for (; scan >= *where; scan -= 3) { if (CLASS(scan)) continue; (void)ifac_checkprime(scan); /* Qj | Ck */ } } /* Divide all current composites by first (prime, class Q) entry, updating its * exponent, and turning it into a finished prime (class P). Return 1 if any * such divisions succeeded (in Moebius mode, the update may then not have * been completed), or 0 if none of them succeeded. Doesn't modify *where. * Here we normally do not check that the first entry is a not-finished * prime. Stack management: we may allocate a new exponent */ static long ifac_divide(GEN *partial, GEN *where, long moebius_mode) { GEN scan, scan_end = LAST(*partial); long res = 0, exponent, newexp, otherexp; #ifdef IFAC_DEBUG ifac_check(*partial, *where); if (CLASS(*where) != gen_1) pari_err_BUG("ifac_divide [division by composite or finished prime]"); if (!VALUE(*where)) pari_err_BUG("ifac_divide [division by nothing]"); #endif newexp = exponent = itos(EXPON(*where)); if (exponent > 1 && moebius_mode) return 1; /* should've been caught by caller */ for (scan = *where+3; scan <= scan_end; scan += 3) { if (CLASS(scan) != gen_0) continue; /* the other thing ain't composite */ otherexp = 0; /* divide in place to keep stack clutter minimal */ while (dvdiiz(VALUE(scan), VALUE(*where), VALUE(scan))) { if (moebius_mode) return 1; /* immediately */ if (!otherexp) otherexp = itos(EXPON(scan)); newexp += otherexp; } if (newexp > exponent) /* did anything happen? */ { EXPON(*where) = (newexp == 2 ? gen_2 : utoipos(newexp)); exponent = newexp; if (is_pm1((GEN)*scan)) /* factor dissolved completely */ { ifac_delete(scan); if (DEBUGLEVEL >= 4) err_printf("IFAC: a factor was a power of another prime factor\n"); } else { CLASS(scan) = NULL; /* at any rate it's Unknown now */ if (DEBUGLEVEL >= 4) err_printf("IFAC: a factor was divisible by another prime factor,\n" "\tleaving a cofactor = %Ps\n", VALUE(scan)); } res = 1; if (DEBUGLEVEL >= 5) err_printf("IFAC: prime %Ps\n\tappears at least to the power %ld\n", VALUE(*where), newexp); } } /* for */ CLASS(*where) = gen_2; /* make it a finished prime */ if (DEBUGLEVEL >= 3) err_printf("IFAC: prime %Ps\n\tappears with exponent = %ld\n", VALUE(*where), newexp); return res; } /* found out our integer was factor^exp. Update */ static void update_pow(GEN where, GEN factor, long exp, pari_sp *av) { GEN ex = EXPON(where); if (DEBUGLEVEL>3) err_printf("IFAC: found %Ps =\n\t%Ps ^%ld\n", *where, factor, exp); affii(factor, VALUE(where)); avma = *av; if (ex == gen_1) { EXPON(where) = exp == 2? gen_2: utoipos(exp); *av = avma; } else if (ex == gen_2) { EXPON(where) = utoipos(exp<<1); *av = avma; } else affsi(exp * itos(ex), EXPON(where)); } /* hint = 0 : Use a default strategy * hint & 1 : avoid MPQS * hint & 2 : avoid first-stage ECM (may fall back to ECM if MPQS gives up) * hint & 4 : avoid Pollard and SQUFOF stages. * hint & 8 : avoid final ECM; may flag a composite as prime. */ #define get_hint(partial) (itos(HINT(*partial)) & 15) /* Split the first (composite) entry. There _must_ already be room for another * factor below *where, and *where is updated. Two cases: * - entry = factor^k is a pure power: factor^k is inserted, leaving *where * unchanged; * - entry = factor * cofactor (not necessarily coprime): both factors are * inserted in the correct order, updating *where * The inserted factors class is set to unknown, they inherit the exponent * (or a multiple thereof) of their ancestor. * * Returns number of factors written into the structure, normally 2 (1 if pure * power, maybe > 2 if a factoring engine returned a vector of factors instead * of a single factor). Can reallocate the data structure in the * vector-of-factors case, not in the most common single-factor case. * Stack housekeeping: this routine may create one or more objects (a new * factor, or possibly several, and perhaps one or more new exponents > 2) */ static long ifac_crack(GEN *partial, GEN *where, long moebius_mode) { long cmp_res, hint = get_hint(partial); GEN factor, exponent; #ifdef IFAC_DEBUG ifac_check(*partial, *where); if (*where < *partial + 6) pari_err_BUG("ifac_crack ['*where' out of bounds]"); if (!(VALUE(*where)) || typ(VALUE(*where)) != t_INT) pari_err_BUG("ifac_crack [incorrect VALUE(*where)]"); if (CLASS(*where) != gen_0) pari_err_BUG("ifac_crack [operand not known composite]"); #endif if (DEBUGLEVEL>2) { err_printf("IFAC: cracking composite\n\t%Ps\n", **where); if (DEBUGLEVEL>3) err_printf("IFAC: checking for pure square\n"); } /* MPQS cannot factor prime powers. Look for pure powers even if MPQS is * blocked by hint: fast and useful in bounded factorization */ { forprime_t T; ulong exp = 1, mask = 7; long good = 0; pari_sp av = avma; (void)u_forprime_init(&T, 11, ULONG_MAX); /* crack squares */ while (Z_issquareall(VALUE(*where), &factor)) { good = 1; /* remember we succeeded once */ update_pow(*where, factor, 2, &av); if (moebius_mode) return 0; /* no need to carry on */ } while ( (exp = is_357_power(VALUE(*where), &factor, &mask)) ) { good = 1; /* remember we succeeded once */ update_pow(*where, factor, exp, &av); if (moebius_mode) return 0; /* no need to carry on */ } /* cutoff at 14 bits as trial division must have found everything below */ while ( (exp = is_pth_power(VALUE(*where), &factor, &T, 15)) ) { good = 1; /* remember we succeeded once */ update_pow(*where, factor, exp, &av); if (moebius_mode) return 0; /* no need to carry on */ } if (good && hint != 15 && ifac_checkprime(*where)) { /* our composite was a prime power */ if (DEBUGLEVEL>3) err_printf("IFAC: factor %Ps\n\tis prime\n", VALUE(*where)); return 0; /* bypass subsequent ifac_whoiswho() call */ } } /* pure power stage */ factor = NULL; if (!(hint & 4)) { /* pollardbrent() Rho usually gets a first chance */ if (DEBUGLEVEL >= 4) err_printf("IFAC: trying Pollard-Brent rho method\n"); factor = pollardbrent(VALUE(*where)); if (!factor) { /* Shanks' squfof() */ if (DEBUGLEVEL >= 4) err_printf("IFAC: trying Shanks' SQUFOF, will fail silently if input\n" " is too large for it.\n"); factor = squfof(VALUE(*where)); } } if (!factor && !(hint & 2)) { /* First ECM stage */ if (DEBUGLEVEL >= 4) err_printf("IFAC: trying Lenstra-Montgomery ECM\n"); factor = ellfacteur(VALUE(*where), 0); /* do not insist */ } if (!factor && !(hint & 1)) { /* MPQS stage */ if (DEBUGLEVEL >= 4) err_printf("IFAC: trying MPQS\n"); factor = mpqs(VALUE(*where)); } if (!factor) { if (!(hint & 8)) { /* still no luck? Final ECM stage, guaranteed to succeed */ if (DEBUGLEVEL >= 4) err_printf("IFAC: forcing ECM, may take some time\n"); factor = ellfacteur(VALUE(*where), 1); } else { /* limited factorization */ if (DEBUGLEVEL >= 2) { if (hint != 15) pari_warn(warner, "IFAC: unfactored composite declared prime"); else pari_warn(warner, "IFAC: untested integer declared prime"); /* don't print it out at level 3 or above, where it would appear * several times before and after this message already */ if (DEBUGLEVEL == 2) err_printf("\t%Ps\n", VALUE(*where)); } CLASS(*where) = gen_1; /* might as well trial-divide by it... */ return 1; } } if (typ(factor) == t_VEC) /* delegate this case */ return ifac_insert_multiplet(partial, where, factor, moebius_mode); /* typ(factor) == t_INT */ /* got single integer back: work out the cofactor (in place) */ if (!dvdiiz(VALUE(*where), factor, VALUE(*where))) { err_printf("IFAC: factoring %Ps\n", VALUE(*where)); err_printf("\tyielded 'factor' %Ps\n\twhich isn't!\n", factor); pari_err_BUG("factoring"); } /* factoring engines report the factor found; tell about the cofactor */ if (DEBUGLEVEL >= 4) err_printf("IFAC: cofactor = %Ps\n", VALUE(*where)); /* The two factors are 'factor' and VALUE(*where), find out which is larger */ cmp_res = cmpii(factor, VALUE(*where)); CLASS(*where) = NULL; /* mark factor /cofactor 'unknown' */ exponent = EXPON(*where); *where -= 3; CLASS(*where) = NULL; /* mark factor /cofactor 'unknown' */ EXPON(*where) = isonstack(exponent)? icopy(exponent): exponent; if (cmp_res < 0) VALUE(*where) = factor; /* common case */ else if (cmp_res > 0) { /* factor > cofactor, rearrange */ GEN old = *where + 3; VALUE(*where) = VALUE(old); /* move cofactor pointer to lowest slot */ VALUE(old) = factor; /* save factor */ } else pari_err_BUG("ifac_crack [Z_issquareall miss]"); return 2; } /* Gets called to complete ifac_crack's job when a factoring engine splits * the current factor into a product of three or more new factors. Makes room * for them if necessary, sorts them, gives them the right exponents and class. * Also returns the number of factors actually written, which may be less than * the number of components in facvec if there are duplicates.--- Vectors of * factors (cf pollardbrent()) actually contain 'slots' of three GENs per * factor with the three fields interpreted as in our partial factorization * data structure. Thus 'engines' can tell us what they already happen to * know about factors being prime or composite and/or appearing to a power * larger than the first. * Don't collect garbage. No diagnostics: the factoring engine should have * printed what it found. facvec contains slots of three components per factor; * repeated factors are allowed (and their classes shouldn't contradict each * other whereas their exponents will be added up) */ static long ifac_insert_multiplet(GEN *partial, GEN *where, GEN facvec, long moebius_mode) { long j,k=1, lfv=lg(facvec)-1, nf=lfv/3, room=(long)(*where-*partial); /* one of the factors will go into the *where slot, so room is now 3 times * the number of slots we can use */ long needroom = lfv - room; GEN e, newexp, cur, sorted, auxvec = cgetg(nf+1, t_VEC), factor; long exponent = itos(EXPON(*where)); /* the old exponent */ if (DEBUGLEVEL >= 5) /* squfof may return a single squared factor as a set */ err_printf("IFAC: incorporating set of %ld factor(s)\n", nf); if (needroom > 0) /* one extra slot for paranoia, errm, future use */ ifac_realloc(partial, where, lg(*partial) + needroom + 3); /* create sort permutation from the values of the factors */ for (j=nf; j; j--) auxvec[j] = facvec[3*j-2]; /* just the pointers */ sorted = indexsort(auxvec); /* and readjust the result for the triple spacing */ for (j=nf; j; j--) sorted[j] = 3*sorted[j]-2; /* store factors, beginning at *where, and catching any duplicates */ cur = facvec + sorted[nf]; VALUE(*where) = VALUE(cur); newexp = EXPON(cur); if (newexp != gen_1) /* new exponent > 1 */ { if (exponent == 1) e = isonstack(newexp)? icopy(newexp): newexp; else e = mului(exponent, newexp); EXPON(*where) = e; } /* if new exponent is 1, the old exponent already in place will do */ CLASS(*where) = CLASS(cur); if (DEBUGLEVEL >= 6) err_printf("\tstored (largest) factor no. %ld...\n", nf); for (j=nf-1; j; j--) { cur = facvec + sorted[j]; factor = VALUE(cur); if (equalii(factor, VALUE(*where))) { if (DEBUGLEVEL >= 6) err_printf("\tfactor no. %ld is a duplicate%s\n", j, (j>1? "...": "")); /* update exponent, ignore class which would already have been set, * then forget current factor */ newexp = EXPON(cur); if (newexp != gen_1) /* new exp > 1 */ e = addis(EXPON(*where), exponent * itos(newexp)); else if (EXPON(*where) == gen_1 && exponent == 1) e = gen_2; else e = addis(EXPON(*where), exponent); EXPON(*where) = e; if (moebius_mode) return 0; /* stop now, but with exponent updated */ continue; } *where -= 3; CLASS(*where) = CLASS(cur); /* class as given */ newexp = EXPON(cur); if (newexp != gen_1) /* new exp > 1 */ { if (exponent == 1 && newexp == gen_2) e = gen_2; else /* exponent*newexp > 2 */ e = mului(exponent, newexp); } else e = (exponent == 1 ? gen_1 : (exponent == 2 ? gen_2 : utoipos(exponent))); /* inherit parent's exponent */ EXPON(*where) = e; /* keep components younger than *partial */ VALUE(*where) = isonstack(factor) ? icopy(factor) : factor; k++; if (DEBUGLEVEL >= 6) err_printf("\tfactor no. %ld was unique%s\n", j, j>1? " (so far)...": ""); } /* make the 'sorted' object safe for garbage collection (it should be in the * garbage zone from everybody's perspective, but it's easy to do it) */ *sorted = evaltyp(t_INT) | evallg(nf+1); return k; } /* main loop: iterate until smallest entry is a finished prime; returns * a 'where' pointer, or NULL if nothing left, or gen_0 in Moebius mode if * we aren't squarefree */ static GEN ifac_main(GEN *partial) { const long moebius_mode = !!MOEBIUS(*partial); GEN here = ifac_find(*partial); long nf; if (!here) return NULL; /* nothing left */ /* loop until first entry is a finished prime. May involve reallocations, * thus updates of *partial */ while (CLASS(here) != gen_2) { if (CLASS(here) == gen_0) /* composite: crack it */ { /* make sure there's room for another factor */ if (here < *partial + 6) { ifac_defrag(partial, &here); if (here < *partial + 6) ifac_realloc(partial, &here, 1); /* no luck */ } nf = ifac_crack(partial, &here, moebius_mode); if (moebius_mode && EXPON(here) != gen_1) /* that was a power */ { if (DEBUGLEVEL >= 3) err_printf("IFAC: main loop: repeated new factor\n\t%Ps\n", *here); return gen_0; } /* deal with the new unknowns. No sort: ifac_crack did it */ ifac_whoiswho(partial, &here, nf); continue; } if (CLASS(here) == gen_1) /* prime but not yet finished: finish it */ { if (ifac_divide(partial, &here, moebius_mode)) { if (moebius_mode) { if (DEBUGLEVEL >= 3) err_printf("IFAC: main loop: another factor was divisible by\n" "\t%Ps\n", *here); return gen_0; } ifac_resort(partial, &here); /* sort new cofactors down */ ifac_whoiswho(partial, &here, -1); } continue; } pari_err_BUG("ifac_main [non-existent factor class]"); } /* while */ if (moebius_mode && EXPON(here) != gen_1) { if (DEBUGLEVEL >= 3) err_printf("IFAC: after main loop: repeated old factor\n\t%Ps\n", *here); return gen_0; } if (DEBUGLEVEL >= 4) { nf = (*partial + lg(*partial) - here - 3)/3; if (nf) err_printf("IFAC: main loop: %ld factor%s left\n", nf, (nf>1)? "s": ""); else err_printf("IFAC: main loop: this was the last factor\n"); } if (factor_add_primes && !(get_hint(partial) & 8)) { GEN p = VALUE(here); if (lgefint(p)>3 || uel(p,2) > 0x1000000UL) (void)addprimes(p); } return here; } /* Encapsulated routines */ /* prime/exponent pairs need to appear contiguously on the stack, but we also * need our data structure somewhere, and we don't know in advance how many * primes will turn up. The following discipline achieves this: When * ifac_decomp() is called, n should point at an object older than the oldest * small prime/exponent pair (ifactor() guarantees this). * We allocate sufficient space to accommodate several pairs -- eleven pairs * ought to fit in a space not much larger than n itself -- before calling * ifac_start(). If we manage to complete the factorization before we run out * of space, we free the data structure and cull the excess reserved space * before returning. When we do run out, we have to leapfrog to generate more * (guesstimating the requirements from what is left in the partial * factorization structure); room for fresh pairs is allocated at the head of * the stack, followed by an ifac_realloc() to reconnect the data structure and * move it out of the way, followed by a few pointer tweaks to connect the new * pairs space to the old one. This whole affair translates into a surprisingly * compact routine. */ /* find primary factors of n; destroy n */ static long ifac_decomp(GEN n, long hint) { pari_sp av = avma; long nb = 0; GEN part, here, workspc, pairs = (GEN)av; /* workspc will be doled out in pairs of smaller t_INTs. For n = prod p^{e_p} * (p not necessarily prime), need room to store all p and e_p [ cgeti(3) ], * bounded by * sum_{p | n} ( log_{2^BIL} (p) + 6 ) <= log_{2^BIL} n + 6 log_2 n */ workspc = new_chunk((expi(n) + 1) * 7); part = ifac_start_hint(n, 0, hint); for (;;) { here = ifac_main(&part); if (!here) break; if (gc_needed(av,1)) { long offset; if(DEBUGMEM>1) { pari_warn(warnmem,"[2] ifac_decomp"); ifac_print(part, here); } ifac_realloc(&part, &here, 0); offset = here - part; part = gerepileupto((pari_sp)workspc, part); here = part + offset; } nb++; pairs = icopy_avma(VALUE(here), (pari_sp)pairs); pairs = icopy_avma(EXPON(here), (pari_sp)pairs); ifac_delete(here); } avma = (pari_sp)pairs; if (DEBUGLEVEL >= 3) err_printf("IFAC: found %ld large prime (power) factor%s.\n", nb, (nb>1? "s": "")); return nb; } /***********************************************************************/ /** ARITHMETIC FUNCTIONS WITH EARLY-ABORT **/ /** needing direct access to the factoring machinery to avoid work: **/ /** e.g. if we find a square factor, moebius returns 0, core doesn't **/ /** need to factor it, etc. **/ /***********************************************************************/ /* memory management */ static void ifac_GC(pari_sp av, GEN *part) { GEN here = NULL; if(DEBUGMEM>1) pari_warn(warnmem,"ifac_xxx"); ifac_realloc(part, &here, 0); *part = gerepileupto(av, *part); } /* destroys n */ static long ifac_moebius(GEN n) { long mu = 1; pari_sp av = avma; GEN part = ifac_start(n, 1); for(;;) { long v; GEN p; if (!ifac_next(&part,&p,&v)) return v? 0: mu; mu = -mu; if (gc_needed(av,1)) ifac_GC(av,&part); } } int ifac_read(GEN part, GEN *p, long *e) { GEN here = ifac_find(part); if (!here) return 0; *p = VALUE(here); *e = EXPON(here)[2]; return 1; } void ifac_skip(GEN part) { GEN here = ifac_find(part); if (here) ifac_delete(here); } /* destroys n */ static int ifac_ispowerful(GEN n) { pari_sp av = avma; GEN part = ifac_start(n, 0); for(;;) { long e; GEN p; if (!ifac_read(part,&p,&e)) return 1; /* power: skip */ if (e != 1 || Z_isanypower(p,NULL)) { ifac_skip(part); continue; } if (!ifac_next(&part,&p,&e)) return 1; if (e == 1) return 0; if (gc_needed(av,1)) ifac_GC(av,&part); } } /* destroys n */ static GEN ifac_core(GEN n) { GEN m = gen_1, c = cgeti(lgefint(n)); pari_sp av = avma; GEN part = ifac_start(n, 0); for(;;) { long e; GEN p; if (!ifac_read(part,&p,&e)) return m; /* square: skip */ if (!odd(e) || Z_issquare(p)) { ifac_skip(part); continue; } if (!ifac_next(&part,&p,&e)) return m; if (odd(e)) m = mulii(m, p); if (gc_needed(av,1)) { affii(m,c); m=c; ifac_GC(av,&part); } } } /* Where to stop trial dividing in factorization. Guaranteed >= 2^14 */ ulong tridiv_bound(GEN n) { ulong l = (ulong)expi(n) + 1; if (l <= 32) return 1UL<<14; if (l <= 512) return (l-16) << 10; return 1UL<<19; /* Rho is generally faster above this */ } /* return a value <= (48 << 10) = 49152 < primelinit */ static ulong utridiv_bound(ulong n) { #ifdef LONG_IS_64BIT if (n & HIGHMASK) return ((ulong)expu(n) + 1 - 16) << 10; #else (void)n; #endif return 1UL<<14; } /* destroys n */ static void ifac_factoru(GEN n, long hint, GEN P, GEN E, long *pi) { GEN part = ifac_start_hint(n, 0, hint); for(;;) { long v; GEN p; if (!ifac_next(&part,&p,&v)) return; P[*pi] = itou(p); E[*pi] = v; (*pi)++; } } /* destroys n */ static long ifac_moebiusu(GEN n) { GEN part = ifac_start(n, 1); long s = 1; for(;;) { long v; GEN p; if (!ifac_next(&part,&p,&v)) return v? 0: s; s = -s; } } INLINE ulong u_forprime_next_fast(forprime_t *T) { if (*(T->d)) { NEXT_PRIME_VIADIFF(T->p, T->d); return T->p > T->b ? 0: T->p; } return u_forprime_next(T); } /* Factor n and output [p,e] where * p, e are vecsmall with n = prod{p[i]^e[i]} */ static GEN factoru_sign(ulong n, ulong all, long hint) { GEN f, E, E2, P, P2; pari_sp av; ulong p, lim; long i; forprime_t S; if (n == 0) retmkvec2(mkvecsmall(0), mkvecsmall(1)); if (n == 1) retmkvec2(cgetg(1,t_VECSMALL), cgetg(1,t_VECSMALL)); f = cgetg(3,t_VEC); av = avma; lim = all; if (!lim) lim = utridiv_bound(n); /* enough room to store <= 15 primes and exponents (OK if n < 2^64) */ (void)new_chunk(16*2); P = cgetg(16, t_VECSMALL); i = 1; E = cgetg(16, t_VECSMALL); if (lim > 2) { long v = vals(n), oldi; if (v) { P[1] = 2; E[1] = v; i = 2; n >>= v; if (n == 1) goto END; } u_forprime_init(&S, 3, lim-1); oldi = i; while ( (p = u_forprime_next_fast(&S)) ) { int stop; /* tiny integers without small factors are often primes */ if (p == 673) { oldi = i; if (uisprime_661(n)) { P[i] = n; E[i] = 1; i++; goto END; } } v = u_lvalrem_stop(&n, p, &stop); if (v) { P[i] = p; E[i] = v; i++; } if (stop) { if (n != 1) { P[i] = n; E[i] = 1; i++; } goto END; } } if (oldi != i && uisprime_661(n)) { P[i] = n; E[i] = 1; i++; goto END; } } if (all) { /* smallfact: look for easy pure powers then stop */ #ifdef LONG_IS_64BIT ulong mask = all > 563 ? (all > 7129 ? 1: 3): 7; #else ulong mask = all > 22 ? (all > 83 ? 1: 3): 7; #endif long k = 1, ex; while (uissquareall(n, &n)) k <<= 1; while ( (ex = uis_357_power(n, &n, &mask)) ) k *= ex; P[i] = n; E[i] = k; i++; goto END; } { GEN perm; ifac_factoru(utoipos(n), hint, P, E, &i); setlg(P, i); perm = vecsmall_indexsort(P); P = vecsmallpermute(P, perm); E = vecsmallpermute(E, perm); } END: avma = av; P2 = cgetg(i, t_VECSMALL); gel(f,1) = P2; E2 = cgetg(i, t_VECSMALL); gel(f,2) = E2; while (--i >= 1) { P2[i] = P[i]; E2[i] = E[i]; } return f; } GEN factoru(ulong n) { return factoru_sign(n, 0, decomp_default_hint); } long moebiusu_fact(GEN f) { GEN E = gel(f,2); long i, l = lg(E); for (i = 1; i < l; i++) if (E[i] > 1) return 0; return odd(l)? 1: -1; } long moebiusu(ulong n) { pari_sp av; ulong p; long s, v, test_prime; forprime_t S; switch(n) { case 0: (void)check_arith_non0(gen_0,"moebius");/*error*/ case 1: return 1; case 2: return -1; } v = vals(n); if (v == 0) s = 1; else { if (v > 1) return 0; n >>= 1; s = -1; } av = avma; u_forprime_init(&S, 3, utridiv_bound(n)); test_prime = 0; while ((p = u_forprime_next_fast(&S))) { int stop; /* tiny integers without small factors are often primes */ if (p == 673) { test_prime = 0; if (uisprime_661(n)) { avma = av; return -s; } } v = u_lvalrem_stop(&n, p, &stop); if (v) { if (v > 1) { avma = av; return 0; } test_prime = 1; s = -s; } if (stop) { avma = av; return n == 1? s: -s; } } avma = av; if (test_prime && uisprime_661(n)) return -s; else { long t = ifac_moebiusu(utoipos(n)); avma = av; if (t == 0) return 0; return (s == t)? 1: -1; } } long moebius(GEN n) { pari_sp av = avma; GEN F; ulong p; long i, l, s, v; forprime_t S; if ((F = check_arith_non0(n,"moebius"))) { GEN E; F = clean_Z_factor(F); E = gel(F,2); l = lg(E); for(i = 1; i < l; i++) if (!equali1(gel(E,i))) { avma = av; return 0; } avma = av; return odd(l)? 1: -1; } if (lgefint(n) == 3) return moebiusu(uel(n,2)); p = mod4(n); if (!p) return 0; if (p == 2) { s = -1; n = shifti(n, -1); } else { s = 1; n = icopy(n); } setabssign(n); u_forprime_init(&S, 3, tridiv_bound(n)); while ((p = u_forprime_next_fast(&S))) { int stop; v = Z_lvalrem_stop(&n, p, &stop); if (v) { if (v > 1) { avma = av; return 0; } s = -s; if (stop) { avma = av; return is_pm1(n)? s: -s; } } } l = lg(primetab); for (i = 1; i < l; i++) { v = Z_pvalrem(n, gel(primetab,i), &n); if (v) { if (v > 1) { avma = av; return 0; } s = -s; if (is_pm1(n)) { avma = av; return s; } } } if (ifac_isprime(n)) { avma = av; return -s; } /* large composite without small factors */ v = ifac_moebius(n); avma = av; return (s<0 ? -v : v); /* correct also if v==0 */ } long ispowerful(GEN n) { pari_sp av = avma; GEN F; ulong p, bound; long i, l, v; forprime_t S; if ((F = check_arith_all(n, "ispowerful"))) { GEN p, P = gel(F,1), E = gel(F,2); if (lg(P) == 1) return 1; /* 1 */ p = gel(P,1); if (!signe(p)) return 1; /* 0 */ i = is_pm1(p)? 2: 1; /* skip -1 */ l = lg(E); for (; i < l; i++) if (equali1(gel(E,i))) return 0; return 1; } if (!signe(n)) return 1; if (mod4(n) == 2) return 0; n = shifti(n, -vali(n)); if (is_pm1(n)) return 1; setabssign(n); bound = tridiv_bound(n); u_forprime_init(&S, 3, bound); while ((p = u_forprime_next_fast(&S))) { int stop; v = Z_lvalrem_stop(&n, p, &stop); if (v) { if (v == 1) { avma = av; return 0; } if (stop) { avma = av; return is_pm1(n); } } } l = lg(primetab); for (i = 1; i < l; i++) { v = Z_pvalrem(n, gel(primetab,i), &n); if (v) { if (v == 1) { avma = av; return 0; } if (is_pm1(n)) { avma = av; return 1; } } } /* no need to factor: must be p^2 or not powerful */ if(cmpii(powuu(bound+1, 3), n) > 0) { long res = Z_issquare(n); avma = av; return res; } if (ifac_isprime(n)) { avma=av; return 0; } /* large composite without small factors */ v = ifac_ispowerful(n); avma = av; return v; } ulong coreu_fact(GEN f) { GEN P = gel(f,1), E = gel(f,2); long i, l = lg(P), m = 1; for (i = 1; i < l; i++) { ulong p = P[i], e = E[i]; if (e & 1) m *= p; } return m; } ulong coreu(ulong n) { if (n == 0) return 0; else { pari_sp av = avma; long m = coreu_fact(factoru(n)); avma = av; return m; } } GEN core(GEN n) { pari_sp av = avma; GEN m, F; ulong p; long i, l, v; forprime_t S; if ((F = check_arith_all(n, "core"))) { GEN p, x, P = gel(F,1), E = gel(F,2); long j = 1; if (lg(P) == 1) return gen_1; p = gel(P,1); if (!signe(p)) return gen_0; l = lg(P); x = cgetg(l, t_VEC); for (i = 1; i < l; i++) if (mpodd(gel(E,i))) gel(x,j++) = gel(P,i); setlg(x, j); return ZV_prod(x); } switch(lgefint(n)) { case 2: return gen_0; case 3: p = coreu(uel(n,2)); return signe(n) > 0? utoipos(p): utoineg(p); } m = signe(n) < 0? gen_m1: gen_1; n = absi_shallow(n); u_forprime_init(&S, 2, tridiv_bound(n)); while ((p = u_forprime_next_fast(&S))) { int stop; v = Z_lvalrem_stop(&n, p, &stop); if (v) { if (v & 1) m = muliu(m, p); if (stop) { if (!is_pm1(n)) m = mulii(m, n); return gerepileuptoint(av, m); } } } l = lg(primetab); for (i = 1; i < l; i++) { GEN q = gel(primetab,i); v = Z_pvalrem(n, q, &n); if (v) { if (v & 1) m = mulii(m, q); if (is_pm1(n)) return gerepileuptoint(av, m); } } if (ifac_isprime(n)) { m = mulii(m, n); return gerepileuptoint(av, m); } if (m == gen_1) n = icopy(n); /* ifac_core destroys n */ /* large composite without small factors */ return gerepileuptoint(av, mulii(m, ifac_core(n))); } long Z_issmooth(GEN m, ulong lim) { pari_sp av=avma; ulong p = 2; forprime_t S; u_forprime_init(&S, 2, lim); while ((p = u_forprime_next_fast(&S))) { int stop; (void)Z_lvalrem_stop(&m, p, &stop); if (stop) { avma = av; return abscmpiu(m,lim)<=0; } } avma = av; return 0; } GEN Z_issmooth_fact(GEN m, ulong lim) { pari_sp av=avma; GEN F, P, E; ulong p; long i = 1, l = expi(m)+1; forprime_t S; P = cgetg(l, t_VECSMALL); E = cgetg(l, t_VECSMALL); F = mkmat2(P,E); u_forprime_init(&S, 2, lim); while ((p = u_forprime_next_fast(&S))) { long v; int stop; if ((v = Z_lvalrem_stop(&m, p, &stop))) { P[i] = p; E[i] = v; i++; if (stop) { if (abscmpiu(m,lim) > 0) break; P[i] = m[2]; E[i] = 1; i++; setlg(P, i); setlg(E, i); avma = (pari_sp)F; return F; } } } avma = av; return NULL; } /***********************************************************************/ /** **/ /** COMPUTING THE MATRIX OF PRIME DIVISORS AND EXPONENTS **/ /** **/ /***********************************************************************/ static GEN aux_end(GEN M, GEN n, long nb) { GEN P,E, z = (GEN)avma; long i; if (n) gunclone(n); P = cgetg(nb+1,t_COL); E = cgetg(nb+1,t_COL); for (i=nb; i; i--) { /* allow a stackdummy in the middle */ while (typ(z) != t_INT) z += lg(z); gel(E,i) = z; z += lg(z); gel(P,i) = z; z += lg(z); } gel(M,1) = P; gel(M,2) = E; return sort_factor(M, (void*)&abscmpii, cmp_nodata); } static void STORE(long *nb, GEN x, long e) { (*nb)++; (void)x; (void)utoipos(e); } static void STOREu(long *nb, ulong x, long e) { STORE(nb, utoipos(x), e); } static void STOREi(long *nb, GEN x, long e) { STORE(nb, icopy(x), e); } /* no prime less than p divides n */ static int special_primes(GEN n, ulong p, long *nb, GEN T) { long i, l = lg(T); if (l > 1) { /* pp = square of biggest p tried so far */ long pp[] = { evaltyp(t_INT)|_evallg(4), 0,0,0 }; pari_sp av = avma; affii(sqru(p), pp); avma = av; for (i = 1; i < l; i++) if (dvdiiz(n,gel(T,i), n)) { long k = 1; while (dvdiiz(n,gel(T,i), n)) k++; STOREi(nb, gel(T,i), k); if (abscmpii(pp, n) > 0) return 1; } } return 0; } /* factor(sn*|n|), where sn = -1,1 or 0. * all != 0 : only look for prime divisors < all */ static GEN ifactor_sign(GEN n, ulong all, long hint, long sn) { GEN M, N; pari_sp av; long nb = 0, i; ulong lim; forprime_t T; if (!sn) retmkmat2(mkcol(gen_0), mkcol(gen_1)); if (lgefint(n) == 3) { /* small integer */ GEN f, Pf, Ef, P, E, F = cgetg(3, t_MAT); long l; av = avma; /* enough room to store <= 15 primes and exponents (OK if n < 2^64) */ (void)new_chunk((15*3 + 15 + 1) * 2); f = factoru_sign(uel(n,2), all, hint); avma = av; Pf = gel(f,1); Ef = gel(f,2); l = lg(Pf); if (sn < 0) { /* add sign */ long L = l+1; gel(F,1) = P = cgetg(L, t_COL); gel(F,2) = E = cgetg(L, t_COL); gel(P,1) = gen_m1; P++; gel(E,1) = gen_1; E++; } else { gel(F,1) = P = cgetg(l, t_COL); gel(F,2) = E = cgetg(l, t_COL); } for (i = 1; i < l; i++) { gel(P,i) = utoipos(Pf[i]); gel(E,i) = utoipos(Ef[i]); } return F; } M = cgetg(3,t_MAT); if (sn < 0) STORE(&nb, utoineg(1), 1); if (is_pm1(n)) return aux_end(M,NULL,nb); n = N = gclone(n); setabssign(n); /* trial division bound */ lim = all; if (!lim) lim = tridiv_bound(n); if (lim > 2) { ulong maxp, p; pari_sp av2; i = vali(n); if (i) { STOREu(&nb, 2, i); av = avma; affii(shifti(n,-i), n); avma = av; } if (is_pm1(n)) return aux_end(M,n,nb); /* trial division */ maxp = maxprime(); av = avma; u_forprime_init(&T, 3, minss(lim, maxp)); av2 = avma; /* first pass: known to fit in private prime table */ while ((p = u_forprime_next_fast(&T))) { pari_sp av3 = avma; int stop; long k = Z_lvalrem_stop(&n, p, &stop); if (k) { affii(n, N); n = N; avma = av3; STOREu(&nb, p, k); } if (stop) { if (!is_pm1(n)) STOREi(&nb, n, 1); stackdummy(av, av2); return aux_end(M,n,nb); } } stackdummy(av, av2); if (lim > maxp) { /* second pass, usually empty: outside private prime table */ av = avma; u_forprime_init(&T, maxp+1, lim); av2 = avma; while ((p = u_forprime_next(&T))) { pari_sp av3 = avma; int stop; long k = Z_lvalrem_stop(&n, p, &stop); if (k) { affii(n, N); n = N; avma = av3; STOREu(&nb, p, k); } if (stop) { if (!is_pm1(n)) STOREi(&nb, n, 1); stackdummy(av, av2); return aux_end(M,n,nb); } } stackdummy(av, av2); } } /* trial divide by the special primes */ if (special_primes(n, lim, &nb, primetab)) { if (!is_pm1(n)) STOREi(&nb, n, 1); return aux_end(M,n,nb); } if (all) { /* smallfact: look for easy pure powers then stop. Cf Z_isanypower */ GEN x; long k; av = avma; k = isanypower_nosmalldiv(n, &x); if (k > 1) affii(x, n); avma = av; STOREi(&nb, n, k); if (DEBUGLEVEL >= 2) { pari_warn(warner, "IFAC: untested %ld-bit integer declared prime", expi(n)); if (expi(n) <= 256) err_printf("\t%Ps\n", n); } return aux_end(M,n,nb); } if (ifac_isprime(n)) { STOREi(&nb, n, 1); return aux_end(M,n,nb); } nb += ifac_decomp(n, hint); return aux_end(M,n, nb); } static GEN ifactor(GEN n, ulong all, long hint) { return ifactor_sign(n, all, hint, signe(n)); } int ifac_next(GEN *part, GEN *p, long *e) { GEN here = ifac_main(part); if (here == gen_0) { *p = NULL; *e = 1; return 0; } if (!here) { *p = NULL; *e = 0; return 0; } *p = VALUE(here); *e = EXPON(here)[2]; ifac_delete(here); return 1; } /* see before ifac_crack for current semantics of 'hint' (factorint's 'flag') */ GEN factorint(GEN n, long flag) { GEN F; if ((F = check_arith_all(n,"factorint"))) return gcopy(F); return ifactor(n,0,flag); } GEN Z_factor_limit(GEN n, ulong all) { if (!all) all = GP_DATA->primelimit + 1; return ifactor(n,all,decomp_default_hint); } GEN absZ_factor_limit(GEN n, ulong all) { if (!all) all = GP_DATA->primelimit + 1; return ifactor_sign(n,all,decomp_default_hint, signe(n)?1 : 0); } GEN Z_factor(GEN n) { return ifactor(n,0,decomp_default_hint); } GEN absZ_factor(GEN n) { return ifactor_sign(n, 0, decomp_default_hint, signe(n)? 1: 0); } /* Factor until the unfactored part is smaller than limit. Return the * factored part. Hence factorback(output) may be smaller than n */ GEN Z_factor_until(GEN n, GEN limit) { pari_sp av2, av = avma; ulong B = tridiv_bound(n); GEN q, part, F = ifactor(n, B, decomp_default_hint); GEN P = gel(F,1), E = gel(F,2); long l = lg(P); av2 = avma; q = gel(P,l-1); if (abscmpiu(q, B) <= 0 || cmpii(q, sqru(B)) < 0 || ifac_isprime(q)) { avma = av2; return F; } /* q = composite unfactored part, remove from P/E */ setlg(E,l-1); setlg(P,l-1); if (cmpii(q, limit) > 0) { /* factor further */ long l2 = expi(q)+1; GEN P2 = coltrunc_init(l2); GEN E2 = coltrunc_init(l2); GEN F2 = mkmat2(P2,E2); part = ifac_start(icopy(q), 0); /* ifac_next would destroy q */ for(;;) { long e; GEN p; if (!ifac_next(&part,&p,&e)) break; vectrunc_append(P2, p); vectrunc_append(E2, utoipos(e)); q = diviiexact(q, powiu(p, e)); if (cmpii(q, limit) <= 0) break; } F2 = sort_factor(F2, (void*)&abscmpii, cmp_nodata); F = merge_factor(F, F2, (void*)&abscmpii, cmp_nodata); } return gerepilecopy(av, F); } static void matsmalltrunc_append(GEN m, ulong p, ulong e) { GEN P = gel(m,1), E = gel(m,2); long l = lg(P); P[l] = p; lg_increase(P); E[l] = e; lg_increase(E); } static GEN matsmalltrunc_init(long l) { GEN P = vecsmalltrunc_init(l); GEN E = vecsmalltrunc_init(l); return mkvec2(P,E); } /* If a <= c <= b , factoru(c) = L[c-a+1] */ GEN vecfactoru_i(ulong a, ulong b) { ulong N, k, p, n = b-a+1; GEN v = const_vecsmall(n, 1); GEN L = cgetg(n+1, t_VEC); forprime_t T; if (b < 510510UL) N = 7; else if (b < 9699690UL) N = 8; #ifdef LONG_IS_64BIT else if (b < 223092870UL) N = 9; else if (b < 6469693230UL) N = 10; else if (b < 200560490130UL) N = 11; else if (b < 7420738134810UL) N = 12; else if (b < 304250263527210UL) N = 13; else N = 16; /* don't bother */ #else else N = 9; #endif for (k = 1; k <= n; k++) gel(L,k) = matsmalltrunc_init(N); u_forprime_init(&T, 2, usqrt(b)); while ((p = u_forprime_next(&T))) { /* p <= sqrt(b) */ ulong pk = p, K = ulogint(b, p); for (k = 1; k <= K; k++) { ulong j, t = a / pk, ap = t * pk; if (ap < a) { ap += pk; t++; } /* t = (j+a-1) \ pk */ for (j = ap-a+1; j <= n; j += pk, t++) if (t % p) { v[j] *= pk; matsmalltrunc_append(gel(L,j), p,k); } pk *= p; } } /* complete factorisation of non-sqrt(b)-smooth numbers */ for (k = 1, N = a; k <= n; k++, N++) if (uel(v,k) != N) matsmalltrunc_append(gel(L,k), N/uel(v,k),1UL); return L; } GEN vecfactoru(ulong a, ulong b) { pari_sp av = avma; return gerepilecopy(av, vecfactoru_i(a,b)); } /* Assume a and b odd, return L s.t. L[k] = factoru(a + 2*(k-1)) * If a <= c <= b odd, factoru(c) = L[(c-a)>>1 + 1] */ GEN vecfactoroddu_i(ulong a, ulong b) { ulong N, k, p, n = ((b-a)>>1) + 1; GEN v = const_vecsmall(n, 1); GEN L = cgetg(n+1, t_VEC); forprime_t T; /* f(N)=my(a=primes(n+1));vecprod(a[2..#a]); */ if (b < 255255UL) N = 6; else if (b < 4849845UL) N = 7; else if (b < 111546435UL) N = 8; #ifdef LONG_IS_64BIT else if (b < 3234846615UL) N = 9; else if (b < 100280245065UL) N = 10; else if (b < 3710369067405UL) N = 11; else if (b < 152125131763605UL) N = 12; else N = 16; /* don't bother */ #else else N = 9; #endif for (k = 1; k <= n; k++) gel(L,k) = matsmalltrunc_init(N); u_forprime_init(&T, 3, usqrt(b)); while ((p = u_forprime_next(&T))) { /* p <= sqrt(b) */ ulong pk = p, K = ulogint(b, p); for (k = 1; k <= K; k++) { ulong j, t = (a / pk) | 1UL, ap = t * pk; /* t and ap are odd, ap multiple of pk = p^k */ if (ap < a) { ap += pk<<1; t+=2; } /* c=t*p^k by steps of 2*p^k; factorization of c*=p^k if (t,p)=1 */ for (j = ((ap-a)>>1)+1; j <= n; j += pk, t+=2) if (t % p) { v[j] *= pk; matsmalltrunc_append(gel(L,j), p,k); } pk *= p; } } /* complete factorisation of non-sqrt(b)-smooth numbers */ for (k = 1, N = a; k <= n; k++, N+=2) if (uel(v,k) != N) matsmalltrunc_append(gel(L,k), N/uel(v,k),1UL); return L; } GEN vecfactoroddu(ulong a, ulong b) { pari_sp av = avma; return gerepilecopy(av, vecfactoroddu_i(a,b)); } /* If 0 <= a <= c <= b; L[c-a+1] = factoru(c)[,1] if c squarefree, else NULL */ GEN vecfactorsquarefreeu(ulong a, ulong b) { ulong N, k, p, n = b-a+1; GEN v = const_vecsmall(n, 1); GEN L = cgetg(n+1, t_VEC); forprime_t T; if (b < 510510UL) N = 7; else if (b < 9699690UL) N = 8; #ifdef LONG_IS_64BIT else if (b < 223092870UL) N = 9; else if (b < 6469693230UL) N = 10; else if (b < 200560490130UL) N = 11; else if (b < 7420738134810UL) N = 12; else if (b < 304250263527210UL) N = 13; else N = 16; /* don't bother */ #else else N = 9; #endif for (k = 1; k <= n; k++) gel(L,k) = vecsmalltrunc_init(N); u_forprime_init(&T, 2, usqrt(b)); while ((p = u_forprime_next(&T))) { /* p <= sqrt(b), kill non-squarefree */ ulong j, pk = p*p, t = a / pk, ap = t * pk; if (ap < a) { ap += pk; t++; } /* t = (j+a-1) \ pk */ for (j = ap-a+1; j <= n; j += pk, t++) gel(L,j) = NULL; t = a / p; ap = t * p; if (ap < a) { ap += p; t++; } for (j = ap-a+1; j <= n; j += p, t++) if (gel(L,j)) { v[j] *= p; vecsmalltrunc_append(gel(L,j), p); } } /* complete factorisation of non-sqrt(b)-smooth numbers */ for (k = 1, N = a; k <= n; k++, N++) if (gel(L,k) && uel(v,k) != N) vecsmalltrunc_append(gel(L,k), N/uel(v,k)); return L; } GEN vecsquarefreeu(ulong a, ulong b) { ulong j, k, p, n = b-a+1; GEN L = const_vecsmall(n, 1); forprime_t T; u_forprime_init(&T, 2, usqrt(b)); while ((p = u_forprime_next(&T))) { /* p <= sqrt(b), kill non-squarefree */ ulong pk = p*p, t = a / pk, ap = t * pk; if (ap < a) { ap += pk; t++; } /* t = (j+a-1) \ pk */ for (j = ap-a+1; j <= n; j += pk, t++) L[j] = 0; } for (k = j = 1; k <= n; k++) if (L[k]) L[j++] = a+k-1; setlg(L,j); return L; } pari-2.11.2/src/basemath/dirichlet.c0000644000175000017500000001147613326135265015663 0ustar billbill/* Copyright (C) 2015 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** Dirichlet series through Euler product **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" static void err_direuler(GEN x) { pari_err_DOMAIN("direuler","constant term","!=", gen_1,x); } /* s = t_POL (tolerate t_SER of valuation 0) of constant term = 1 * d = minimal such that p^d > X * V indexed by 1..X will contain the a_n * v[1..n] contains the indices nj such that V[nj] != 0 */ static long dirmuleuler_small(GEN V, GEN v, long n, ulong p, GEN s, long d) { long i, j, m = n, D = minss(d+2, lg(s)); ulong q = 1, X = lg(V)-1; for (i = 3, q = p; i < D; i++, q *= p) /* q*p does not overflow */ { GEN aq = gel(s,i); if (gequal0(aq)) continue; /* j = 1 */ gel(V,q) = aq; v[++n] = q; for (j = 2; j <= m; j++) { ulong nj = umuluu_le(uel(v,j), q, X); if (!nj) continue; gel(V,nj) = gmul(aq, gel(V,v[j])); v[++n] = nj; } } return n; } /* ap != 0 for efficiency, p > sqrt(X) */ static void dirmuleuler_large(GEN V, ulong p, GEN ap) { long j, jp, X = lg(V)-1; gel(V,p) = ap; for (j = 2, jp = 2*p; jp <= X; j++, jp += p) gel(V,jp) = gmul(ap, gel(V,j)); } static ulong direulertou(GEN a, GEN fl(GEN)) { if (typ(a) != t_INT) { a = fl(a); if (typ(a) != t_INT) pari_err_TYPE("direuler", a); } return signe(a)<=0 ? 0: itou(a); } GEN direuler_bad(void *E, GEN (*eval)(void *,GEN,long), GEN a,GEN b,GEN c, GEN Sbad) { ulong au, bu, X, sqrtX, n, p; pari_sp av0 = avma; GEN gp, v, V; forprime_t T; long i; au = direulertou(a, gceil); bu = direulertou(b, gfloor); X = c ? direulertou(c, gfloor): bu; if (X == 0) return cgetg(1,t_VEC); if (bu > X) bu = X; if (!u_forprime_init(&T, au, bu)) { avma = av0; return mkvec(gen_1); } v = vecsmall_ei(X, 1); V = vec_ei(X, 1); n = 1; if (Sbad) { long l = lg(Sbad); GEN pbad = gen_1; for (i = 1; i < l; i++) { GEN ai = gel(Sbad,i); ulong q; if (typ(ai) != t_VEC || lg(ai) != 3) pari_err_TYPE("direuler [bad primes]",ai); q = gtou(gel(ai,1)); if (q <= X) { long d = ulogint(X, q) + 1; GEN s = direuler_factor(gel(ai,2), d); n = dirmuleuler_small(V, v, n, q, s, d); pbad = muliu(pbad, q); } } Sbad = pbad; } p = 1; gp = cgetipos(3); sqrtX = usqrt(X); while (p <= sqrtX && (p = u_forprime_next(&T))) if (!Sbad || umodiu(Sbad, p)) { long d = ulogint(X, p) + 1; /* minimal d such that p^d > X */ GEN s; gp[2] = p; s = eval(E, gp, d); n = dirmuleuler_small(V, v, n, p, s, d); } while ((p = u_forprime_next(&T))) /* sqrt(X) < p <= X */ if (!Sbad || umodiu(Sbad, p)) { GEN s; gp[2] = p; s = eval(E, gp, 2); if (degpol(s) && !gequal0(gel(s,3))) dirmuleuler_large(V, p, gel(s,3)); } return gerepilecopy(av0,V); } /* return a t_SER or a truncated t_POL to precision n */ GEN direuler_factor(GEN s, long n) { long t = typ(s); if (is_scalar_t(t)) { if (!gequal1(s)) err_direuler(s); return scalarpol_shallow(s,0); } switch(t) { case t_POL: break; /* no need to RgXn_red */ case t_RFRAC: { GEN p = gel(s,1), q = gel(s,2); q = RgXn_red_shallow(q,n); s = RgXn_inv(q, n); if (typ(p) == t_POL && varn(p) == varn(q)) { p = RgXn_red_shallow(p, n); s = RgXn_mul(s, p, n); } else if (!gequal1(p)) s = RgX_Rg_mul(s, p); if (!signe(s) || !gequal1(gel(s,2))) err_direuler(s); break; } case t_SER: if (!signe(s) || valp(s) || !gequal1(gel(s,2))) err_direuler(s); break; default: pari_err_TYPE("direuler", s); } return s; } struct eval_bad { void *E; GEN (*eval)(void *, GEN); }; static GEN eval_bad(void *E, GEN p, long n) { struct eval_bad *d = (struct eval_bad*) E; return direuler_factor(d->eval(d->E, p), n); } GEN direuler(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, GEN c) { struct eval_bad d; d.E= E; d.eval = eval; return direuler_bad((void*)&d, eval_bad, a, b, c, NULL); } pari-2.11.2/src/basemath/arith2.c0000644000175000017500000007642513457566437015130 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*********************************************************************/ /** **/ /** ARITHMETIC FUNCTIONS **/ /** (second part) **/ /** **/ /*********************************************************************/ #include "pari.h" #include "paripriv.h" GEN boundfact(GEN n, ulong lim) { switch(typ(n)) { case t_INT: return Z_factor_limit(n,lim); case t_FRAC: { pari_sp av = avma; GEN a = Z_factor_limit(gel(n,1),lim); GEN b = Z_factor_limit(gel(n,2),lim); gel(b,2) = ZC_neg(gel(b,2)); return gerepilecopy(av, merge_factor(a,b,(void*)&cmpii,cmp_nodata)); } } pari_err_TYPE("boundfact",n); return NULL; /* LCOV_EXCL_LINE */ } /* NOT memory clean */ GEN Z_smoothen(GEN N, GEN L, GEN *pP, GEN *pe) { long i, j, l = lg(L); GEN e = new_chunk(l), P = new_chunk(l); for (i = j = 1; i < l; i++) { ulong p = uel(L,i); long v = Z_lvalrem(N, p, &N); if (v) { P[j] = p; e[j] = v; j++; if (is_pm1(N)) { N = NULL; break; } } } P[0] = evaltyp(t_VECSMALL) | evallg(j); *pP = P; e[0] = evaltyp(t_VECSMALL) | evallg(j); *pe = e; return N; } /***********************************************************************/ /** **/ /** SIMPLE FACTORISATIONS **/ /** **/ /***********************************************************************/ /* Factor n and output [p,e,c] where * p, e and c are vecsmall with n = prod{p[i]^e[i]} and c[i] = p[i]^e[i] */ GEN factoru_pow(ulong n) { GEN f = cgetg(4,t_VEC); pari_sp av = avma; GEN F, P, E, p, e, c; long i, l; /* enough room to store <= 15 * [p,e,p^e] (OK if n < 2^64) */ (void)new_chunk((15 + 1)*3); F = factoru(n); P = gel(F,1); E = gel(F,2); l = lg(P); avma = av; gel(f,1) = p = cgetg(l,t_VECSMALL); gel(f,2) = e = cgetg(l,t_VECSMALL); gel(f,3) = c = cgetg(l,t_VECSMALL); for(i = 1; i < l; i++) { p[i] = P[i]; e[i] = E[i]; c[i] = upowuu(p[i], e[i]); } return f; } static GEN factorlim(GEN n, ulong lim) { return lim? Z_factor_limit(n, lim): Z_factor(n); } /* factor p^n - 1, assuming p prime. If lim != 0, limit factorization to * primes <= lim */ GEN factor_pn_1_limit(GEN p, long n, ulong lim) { pari_sp av = avma; GEN A = factorlim(subiu(p,1), lim), d = divisorsu(n); long i, pp = itos_or_0(p); for(i=2; i 1) { if (B) { gel(B,1) = shallowconcat(gel(B,1), p); gel(B,2) = shallowconcat(gel(B,2), utoipos(e-1)); } else B = to_mat(p, e-1); } } avma = av; if (!B) return v? to_mat(gen_2, v): trivial_fact(); A = cgetg(3, t_MAT); P = gel(B,1); E = gel(B,2); l = lg(P); AP = cgetg(l+1, t_COL); gel(A,1) = AP; AP++; AE = cgetg(l+1, t_COL); gel(A,2) = AE; AE++; /* prepend "2^v" */ gel(AP,0) = gen_2; gel(AE,0) = utoipos(v); for (i = 1; i < l; i++) { gel(AP,i) = icopy(gel(P,i)); gel(AE,i) = icopy(gel(E,i)); } return A; } #endif /***********************************************************************/ /** **/ /** CHECK FACTORIZATION FOR ARITHMETIC FUNCTIONS **/ /** **/ /***********************************************************************/ int RgV_is_ZVpos(GEN v) { long i, l = lg(v); for (i = 1; i < l; i++) { GEN c = gel(v,i); if (typ(c) != t_INT || signe(c) <= 0) return 0; } return 1; } /* check whether v is a ZV with non-0 entries */ int RgV_is_ZVnon0(GEN v) { long i, l = lg(v); for (i = 1; i < l; i++) { GEN c = gel(v,i); if (typ(c) != t_INT || !signe(c)) return 0; } return 1; } /* check whether v is a ZV with non-zero entries OR exactly [0] */ static int RgV_is_ZV0(GEN v) { long i, l = lg(v); for (i = 1; i < l; i++) { GEN c = gel(v,i); long s; if (typ(c) != t_INT) return 0; s = signe(c); if (!s) return (l == 2); } return 1; } static int RgV_is_prV(GEN v) { long l = lg(v), i; for (i = 1; i < l; i++) if (!checkprid_i(gel(v,i))) return 0; return 1; } int is_nf_factor(GEN F) { return typ(F) == t_MAT && lg(F) == 3 && RgV_is_prV(gel(F,1)) && RgV_is_ZVpos(gel(F,2)); } int is_nf_extfactor(GEN F) { return typ(F) == t_MAT && lg(F) == 3 && RgV_is_prV(gel(F,1)) && RgV_is_ZV(gel(F,2)); } static int is_Z_factor_i(GEN f) { return typ(f) == t_MAT && lg(f) == 3 && RgV_is_ZVpos(gel(f,2)); } int is_Z_factorpos(GEN f) { return is_Z_factor_i(f) && RgV_is_ZVpos(gel(f,1)); } int is_Z_factor(GEN f) { return is_Z_factor_i(f) && RgV_is_ZV0(gel(f,1)); } /* as is_Z_factorpos, also allow factor(0) */ int is_Z_factornon0(GEN f) { return is_Z_factor_i(f) && RgV_is_ZVnon0(gel(f,1)); } GEN clean_Z_factor(GEN f) { GEN P = gel(f,1); long n = lg(P)-1; if (n && equalim1(gel(P,1))) return mkmat2(vecslice(P,2,n), vecslice(gel(f,2),2,n)); return f; } GEN fuse_Z_factor(GEN f, GEN B) { GEN P = gel(f,1), E = gel(f,2), P2,E2; long i, l = lg(P); if (l == 1) return f; for (i = 1; i < l; i++) if (abscmpii(gel(P,i), B) > 0) break; if (i == l) return f; /* tail / initial segment */ P2 = vecslice(P, i, l-1); P = vecslice(P, 1, i-1); E2 = vecslice(E, i, l-1); E = vecslice(E, 1, i-1); P = shallowconcat(P, mkvec(factorback2(P2,E2))); E = shallowconcat(E, mkvec(gen_1)); return mkmat2(P, E); } /* n attached to a factorization of a positive integer: either N (t_INT) * a factorization matrix faN, or a t_VEC: [N, faN] */ GEN check_arith_pos(GEN n, const char *f) { switch(typ(n)) { case t_INT: if (signe(n) <= 0) pari_err_DOMAIN(f, "argument", "<=", gen_0, gen_0); return NULL; case t_VEC: if (lg(n) != 3 || typ(gel(n,1)) != t_INT || signe(gel(n,1)) <= 0) break; n = gel(n,2); /* fall through */ case t_MAT: if (!is_Z_factorpos(n)) break; return n; } pari_err_TYPE(f,n); return NULL; } /* n attached to a factorization of a non-0 integer */ GEN check_arith_non0(GEN n, const char *f) { switch(typ(n)) { case t_INT: if (!signe(n)) pari_err_DOMAIN(f, "argument", "=", gen_0, gen_0); return NULL; case t_VEC: if (lg(n) != 3 || typ(gel(n,1)) != t_INT || !signe(gel(n,1))) break; n = gel(n,2); /* fall through */ case t_MAT: if (!is_Z_factornon0(n)) break; return n; } pari_err_TYPE(f,n); return NULL; } /* n attached to a factorization of an integer */ GEN check_arith_all(GEN n, const char *f) { switch(typ(n)) { case t_INT: return NULL; case t_VEC: if (lg(n) != 3 || typ(gel(n,1)) != t_INT) break; n = gel(n,2); /* fall through */ case t_MAT: if (!is_Z_factor(n)) break; return n; } pari_err_TYPE(f,n); return NULL; } /***********************************************************************/ /** **/ /** MISCELLANEOUS ARITHMETIC FUNCTIONS **/ /** (ultimately depend on Z_factor()) **/ /** **/ /***********************************************************************/ /* set P,E from F. Check whether F is an integer and kill "factor" -1 */ static void set_fact_check(GEN F, GEN *pP, GEN *pE, int *isint) { GEN E, P; if (lg(F) != 3) pari_err_TYPE("divisors",F); P = gel(F,1); E = gel(F,2); RgV_check_ZV(E, "divisors"); *isint = RgV_is_ZV(P); if (*isint) { long i, l = lg(P); /* skip -1 */ if (l>1 && signe(gel(P,1)) < 0) { E++; P = vecslice(P,2,--l); } /* test for 0 */ for (i = 1; i < l; i++) if (!signe(gel(P,i)) && signe(gel(E,i))) pari_err_DOMAIN("divisors", "argument", "=", gen_0, F); } *pP = P; *pE = E; } static void set_fact(GEN F, GEN *pP, GEN *pE) { *pP = gel(F,1); *pE = gel(F,2); } int divisors_init(GEN n, GEN *pP, GEN *pE) { long i,l; GEN E, P, e; int isint; switch(typ(n)) { case t_INT: if (!signe(n)) pari_err_DOMAIN("divisors", "argument", "=", gen_0, gen_0); set_fact(absZ_factor(n), &P,&E); isint = 1; break; case t_VEC: if (lg(n) != 3 || typ(gel(n,2)) !=t_MAT) pari_err_TYPE("divisors",n); set_fact_check(gel(n,2), &P,&E, &isint); break; case t_MAT: set_fact_check(n, &P,&E, &isint); break; default: set_fact(factor(n), &P,&E); isint = 0; break; } l = lg(P); e = cgetg(l, t_VECSMALL); for (i=1; i> 1)); } return mkvec2(c,f); } GEN corepartial(GEN n, long all) { pari_sp av = avma; if (typ(n) != t_INT) pari_err_TYPE("corepartial",n); return gerepileuptoint(av, corefa(Z_factor_limit(n,all))); } GEN core2partial(GEN n, long all) { pari_sp av = avma; if (typ(n) != t_INT) pari_err_TYPE("core2partial",n); return gerepilecopy(av, core2fa(Z_factor_limit(n,all))); } /* given an arithmetic function argument, return the underlying integer */ static GEN arith_n(GEN A) { switch(typ(A)) { case t_INT: return A; case t_VEC: return gel(A,1); default: return factorback(A); } } static GEN core2_i(GEN n) { GEN f = core(n); if (!signe(f)) return mkvec2(gen_0, gen_1); return mkvec2(f, sqrtint(diviiexact(arith_n(n), f))); } GEN core2(GEN n) { pari_sp av = avma; return gerepilecopy(av, core2_i(n)); } GEN core0(GEN n,long flag) { return flag? core2(n): core(n); } static long _mod4(GEN c) { long r, s = signe(c); if (!s) return 0; r = mod4(c); if (s < 0) r = 4-r; return r; } long corediscs(long D, ulong *f) { /* D = f^2 dK */ long dK = D>=0 ? (long) coreu(D) : -(long) coreu(-(ulong) D); ulong dKmod4 = ((ulong)dK)&3UL; if (dKmod4 == 2 || dKmod4 == 3) dK *= 4; if (f) *f = usqrt((ulong)(D/dK)); return D; } GEN coredisc(GEN n) { pari_sp av = avma; GEN c = core(n); if (_mod4(c)<=1) return c; /* c = 0 or 1 mod 4 */ return gerepileuptoint(av, shifti(c,2)); } GEN coredisc2(GEN n) { pari_sp av = avma; GEN y = core2_i(n); GEN c = gel(y,1), f = gel(y,2); if (_mod4(c)<=1) return gerepilecopy(av, y); y = cgetg(3,t_VEC); gel(y,1) = shifti(c,2); gel(y,2) = gmul2n(f,-1); return gerepileupto(av, y); } GEN coredisc0(GEN n,long flag) { return flag? coredisc2(n): coredisc(n); } long omegau(ulong n) { pari_sp av; GEN F; if (n == 1UL) return 0; av = avma; F = factoru(n); avma = av; return lg(gel(F,1))-1; } long omega(GEN n) { pari_sp av; GEN F, P; if ((F = check_arith_non0(n,"omega"))) { long n; P = gel(F,1); n = lg(P)-1; if (n && equalim1(gel(P,1))) n--; return n; } if (lgefint(n) == 3) return omegau(n[2]); av = avma; F = absZ_factor(n); P = gel(F,1); avma = av; return lg(P)-1; } long bigomegau(ulong n) { pari_sp av; GEN F; if (n == 1) return 0; av = avma; F = factoru(n); avma = av; return zv_sum(gel(F,2)); } long bigomega(GEN n) { pari_sp av = avma; GEN F, E; if ((F = check_arith_non0(n,"bigomega"))) { GEN P = gel(F,1); long n = lg(P)-1; E = gel(F,2); if (n && equalim1(gel(P,1))) E = vecslice(E,2,n); } else if (lgefint(n) == 3) return bigomegau(n[2]); else E = gel(absZ_factor(n), 2); E = ZV_to_zv(E); avma = av; return zv_sum(E); } /* assume f = factoru(n), possibly with 0 exponents. Return phi(n) */ ulong eulerphiu_fact(GEN f) { GEN P = gel(f,1), E = gel(f,2); long i, m = 1, l = lg(P); for (i = 1; i < l; i++) { ulong p = P[i], e = E[i]; if (!e) continue; if (p == 2) { if (e > 1) m <<= e-1; } else { m *= (p-1); if (e > 1) m *= upowuu(p, e-1); } } return m; } ulong eulerphiu(ulong n) { pari_sp av = avma; GEN F; if (!n) return 2; F = factoru(n); avma = av; return eulerphiu_fact(F); } GEN eulerphi(GEN n) { pari_sp av = avma; GEN Q, F, P, E; long i, l; if ((F = check_arith_all(n,"eulerphi"))) { F = clean_Z_factor(F); n = arith_n(n); if (lgefint(n) == 3) { ulong e; F = mkmat2(ZV_to_nv(gel(F,1)), ZV_to_nv(gel(F,2))); e = eulerphiu_fact(F); avma = av; return utoipos(e); } } else if (lgefint(n) == 3) return utoipos(eulerphiu(uel(n,2))); else F = absZ_factor(n); if (!signe(n)) return gen_2; P = gel(F,1); E = gel(F,2); l = lg(P); Q = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN p = gel(P,i), q; ulong v = itou(gel(E,i)); q = subiu(p,1); if (v != 1) q = mulii(q, v == 2? p: powiu(p, v-1)); gel(Q,i) = q; } return gerepileuptoint(av, ZV_prod(Q)); } long numdivu_fact(GEN fa) { GEN E = gel(fa,2); long n = 1, i, l = lg(E); for (i = 1; i < l; i++) n *= E[i]+1; return n; } long numdivu(long N) { pari_sp av; GEN fa; if (N == 1) return 1; av = avma; fa = factoru(N); avma = av; return numdivu_fact(fa); } static GEN numdiv_aux(GEN F) { GEN x, E = gel(F,2); long i, l = lg(E); x = cgetg(l, t_VECSMALL); for (i=1; i 1; v--) u = addui(1, mului(p, u)); return u; } /* 1 + q + ... + q^v */ static GEN euler_sumdiv(GEN q, long v) { GEN u = addui(1, q); for (; v > 1; v--) u = addui(1, mulii(q, u)); return u; } static GEN sumdiv_aux(GEN F) { GEN x, P = gel(F,1), E = gel(F,2); long i, l = lg(P); x = cgetg(l, t_VEC); for (i=1; i 0) return gerepileuptoint(av, v); } if (F) n = arith_n(n); if (k != 1) n = powiu(n,k); return gerepileupto(av, gdiv(v, n)); } GEN usumdiv_fact(GEN f) { GEN P = gel(f,1), E = gel(f,2); long i, l = lg(P); GEN v = cgetg(l, t_VEC); for (i=1; i 1) return 0; return 1; } long uissquarefree(ulong n) { if (!n) return 0; return moebiusu(n)? 1: 0; } long Z_issquarefree(GEN n) { switch(lgefint(n)) { case 2: return 0; case 3: return uissquarefree(n[2]); } return moebius(n)? 1: 0; } static int fa_issquarefree(GEN F) { GEN P = gel(F,1), E = gel(F,2); long i, s, l = lg(P); if (l == 1) return 1; s = signe(gel(P,1)); /* = signe(x) */ if (!s) return 0; for(i = 1; i < l; i++) if (!equali1(gel(E,i))) return 0; return 1; } long issquarefree(GEN x) { pari_sp av; GEN d; switch(typ(x)) { case t_INT: return Z_issquarefree(x); case t_POL: if (!signe(x)) return 0; av = avma; d = RgX_gcd(x, RgX_deriv(x)); avma = av; return (lg(d) == 3); case t_VEC: case t_MAT: return fa_issquarefree(check_arith_all(x,"issquarefree")); default: pari_err_TYPE("issquarefree",x); return 0; /* LCOV_EXCL_LINE */ } } /*********************************************************************/ /** **/ /** DIGITS / SUM OF DIGITS **/ /** **/ /*********************************************************************/ /* set v[i] = 1 iff B^i is needed in the digits_dac algorithm */ static void set_vexp(GEN v, long l) { long m; if (v[l]) return; v[l] = 1; m = l>>1; set_vexp(v, m); set_vexp(v, l-m); } /* return all needed B^i for DAC algorithm, for lz digits */ static GEN get_vB(GEN T, long lz, void *E, struct bb_ring *r) { GEN vB, vexp = const_vecsmall(lz, 0); long i, l = (lz+1) >> 1; vexp[1] = 1; vexp[2] = 1; set_vexp(vexp, lz); vB = zerovec(lz); /* unneeded entries remain = 0 */ gel(vB, 1) = T; for (i = 2; i <= l; i++) if (vexp[i]) { long j = i >> 1; GEN B2j = r->sqr(E, gel(vB,j)); gel(vB,i) = odd(i)? r->mul(E, B2j, T): B2j; } return vB; } static void gen_digits_dac(GEN x, GEN vB, long l, GEN *z, void *E, GEN div(void *E, GEN a, GEN b, GEN *r)) { GEN q, r; long m = l>>1; if (l==1) { *z=x; return; } q = div(E, x, gel(vB,m), &r); gen_digits_dac(r, vB, m, z, E, div); gen_digits_dac(q, vB, l-m, z+m, E, div); } static GEN gen_fromdigits_dac(GEN x, GEN vB, long i, long l, void *E, GEN add(void *E, GEN a, GEN b), GEN mul(void *E, GEN a, GEN b)) { GEN a, b; long m = l>>1; if (l==1) return gel(x,i); a = gen_fromdigits_dac(x, vB, i, m, E, add, mul); b = gen_fromdigits_dac(x, vB, i+m, l-m, E, add, mul); return add(E, a, mul(E, b, gel(vB, m))); } static GEN gen_digits_i(GEN x, GEN B, long n, void *E, struct bb_ring *r, GEN (*div)(void *E, GEN x, GEN y, GEN *r)) { GEN z, vB; if (n==1) retmkvec(gcopy(x)); vB = get_vB(B, n, E, r); z = cgetg(n+1, t_VEC); gen_digits_dac(x, vB, n, (GEN*)(z+1), E, div); return z; } GEN gen_digits(GEN x, GEN B, long n, void *E, struct bb_ring *r, GEN (*div)(void *E, GEN x, GEN y, GEN *r)) { pari_sp av = avma; return gerepilecopy(av, gen_digits_i(x, B, n, E, r, div)); } GEN gen_fromdigits(GEN x, GEN B, void *E, struct bb_ring *r) { pari_sp av = avma; long n = lg(x)-1; GEN vB = get_vB(B, n, E, r); GEN z = gen_fromdigits_dac(x, vB, 1, n, E, r->add, r->mul); return gerepilecopy(av, z); } static GEN _addii(void *data /* ignored */, GEN x, GEN y) { (void)data; return addii(x,y); } static GEN _sqri(void *data /* ignored */, GEN x) { (void)data; return sqri(x); } static GEN _mulii(void *data /* ignored */, GEN x, GEN y) { (void)data; return mulii(x,y); } static GEN _dvmdii(void *data /* ignored */, GEN x, GEN y, GEN *r) { (void)data; return dvmdii(x,y,r); } static struct bb_ring Z_ring = { _addii, _mulii, _sqri }; static GEN check_basis(GEN B) { if (!B) return utoipos(10); if (typ(B)!=t_INT) pari_err_TYPE("digits",B); if (abscmpiu(B,2)<0) pari_err_DOMAIN("digits","B","<",gen_2,B); return B; } /* x has l digits in base B, write them to z[0..l-1], vB[i] = B^i */ static void digits_dacsmall(GEN x, GEN vB, long l, ulong* z) { pari_sp av = avma; GEN q,r; long m; if (l==1) { *z=itou(x); return; } m=l>>1; q = dvmdii(x, gel(vB,m), &r); digits_dacsmall(q,vB,l-m,z); digits_dacsmall(r,vB,m,z+l-m); avma = av; } GEN digits(GEN x, GEN B) { pari_sp av=avma; long lz; GEN z, vB; if (typ(x)!=t_INT) pari_err_TYPE("digits",x); B = check_basis(B); if (signe(B)<0) pari_err_DOMAIN("digits","B","<",gen_0,B); if (!signe(x)) {avma = av; return cgetg(1,t_VEC); } if (abscmpii(x,B)<0) {avma = av; retmkvec(absi(x)); } if (Z_ispow2(B)) { long k = expi(B); if (k == 1) return binaire(x); if (k < BITS_IN_LONG) { (void)new_chunk(4*(expi(x) + 2)); /* HACK */ z = binary_2k_nv(x, k); avma = av; return Flv_to_ZV(z); } else { avma = av; return binary_2k(x, k); } } x = absi_shallow(x); lz = logint(x,B) + 1; if (lgefint(B)>3) { z = gerepileupto(av, gen_digits_i(x, B, lz, NULL, &Z_ring, _dvmdii)); vecreverse_inplace(z); return z; } else { vB = get_vB(B, lz, NULL, &Z_ring); (void)new_chunk(3*lz); /* HACK */ z = zero_zv(lz); digits_dacsmall(x,vB,lz,(ulong*)(z+1)); avma = av; return Flv_to_ZV(z); } } static GEN fromdigitsu_dac(GEN x, GEN vB, long i, long l) { GEN a, b; long m = l>>1; if (l==1) return utoi(uel(x,i)); if (l==2) return addumului(uel(x,i), uel(x,i+1), gel(vB, m)); a = fromdigitsu_dac(x, vB, i, m); b = fromdigitsu_dac(x, vB, i+m, l-m); return addii(a, mulii(b, gel(vB, m))); } GEN fromdigitsu(GEN x, GEN B) { pari_sp av = avma; long n = lg(x)-1; GEN vB, z; if (n==0) return gen_0; vB = get_vB(B, n, NULL, &Z_ring); z = fromdigitsu_dac(x, vB, 1, n); return gerepileuptoint(av, z); } static int ZV_in_range(GEN v, GEN B) { long i, l = lg(v); for(i=1; i < l; i++) { GEN vi = gel(v, i); if (signe(vi) < 0 || cmpii(vi, B) >= 0) return 0; } return 1; } GEN fromdigits(GEN x, GEN B) { pari_sp av = avma; if (typ(x)!=t_VEC || !RgV_is_ZV(x)) pari_err_TYPE("fromdigits",x); if (lg(x)==1) return gen_0; B = check_basis(B); if (Z_ispow2(B) && ZV_in_range(x, B)) return fromdigits_2k(x, expi(B)); x = vecreverse(x); return gerepileuptoint(av, gen_fromdigits(x, B, NULL, &Z_ring)); } static const ulong digsum[] ={ 0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,10,2,3,4,5,6,7,8,9,10,11,3,4,5,6,7,8, 9,10,11,12,4,5,6,7,8,9,10,11,12,13,5,6,7,8,9,10,11,12,13,14,6,7,8,9,10,11, 12,13,14,15,7,8,9,10,11,12,13,14,15,16,8,9,10,11,12,13,14,15,16,17,9,10,11, 12,13,14,15,16,17,18,1,2,3,4,5,6,7,8,9,10,2,3,4,5,6,7,8,9,10,11,3,4,5,6,7,8, 9,10,11,12,4,5,6,7,8,9,10,11,12,13,5,6,7,8,9,10,11,12,13,14,6,7,8,9,10,11, 12,13,14,15,7,8,9,10,11,12,13,14,15,16,8,9,10,11,12,13,14,15,16,17,9,10,11, 12,13,14,15,16,17,18,10,11,12,13,14,15,16,17,18,19,2,3,4,5,6,7,8,9,10,11,3, 4,5,6,7,8,9,10,11,12,4,5,6,7,8,9,10,11,12,13,5,6,7,8,9,10,11,12,13,14,6,7,8, 9,10,11,12,13,14,15,7,8,9,10,11,12,13,14,15,16,8,9,10,11,12,13,14,15,16,17, 9,10,11,12,13,14,15,16,17,18,10,11,12,13,14,15,16,17,18,19,11,12,13,14,15, 16,17,18,19,20,3,4,5,6,7,8,9,10,11,12,4,5,6,7,8,9,10,11,12,13,5,6,7,8,9,10, 11,12,13,14,6,7,8,9,10,11,12,13,14,15,7,8,9,10,11,12,13,14,15,16,8,9,10,11, 12,13,14,15,16,17,9,10,11,12,13,14,15,16,17,18,10,11,12,13,14,15,16,17,18, 19,11,12,13,14,15,16,17,18,19,20,12,13,14,15,16,17,18,19,20,21,4,5,6,7,8,9, 10,11,12,13,5,6,7,8,9,10,11,12,13,14,6,7,8,9,10,11,12,13,14,15,7,8,9,10,11, 12,13,14,15,16,8,9,10,11,12,13,14,15,16,17,9,10,11,12,13,14,15,16,17,18,10, 11,12,13,14,15,16,17,18,19,11,12,13,14,15,16,17,18,19,20,12,13,14,15,16,17, 18,19,20,21,13,14,15,16,17,18,19,20,21,22,5,6,7,8,9,10,11,12,13,14,6,7,8,9, 10,11,12,13,14,15,7,8,9,10,11,12,13,14,15,16,8,9,10,11,12,13,14,15,16,17,9, 10,11,12,13,14,15,16,17,18,10,11,12,13,14,15,16,17,18,19,11,12,13,14,15,16, 17,18,19,20,12,13,14,15,16,17,18,19,20,21,13,14,15,16,17,18,19,20,21,22,14, 15,16,17,18,19,20,21,22,23,6,7,8,9,10,11,12,13,14,15,7,8,9,10,11,12,13,14, 15,16,8,9,10,11,12,13,14,15,16,17,9,10,11,12,13,14,15,16,17,18,10,11,12,13, 14,15,16,17,18,19,11,12,13,14,15,16,17,18,19,20,12,13,14,15,16,17,18,19,20, 21,13,14,15,16,17,18,19,20,21,22,14,15,16,17,18,19,20,21,22,23,15,16,17,18, 19,20,21,22,23,24,7,8,9,10,11,12,13,14,15,16,8,9,10,11,12,13,14,15,16,17,9, 10,11,12,13,14,15,16,17,18,10,11,12,13,14,15,16,17,18,19,11,12,13,14,15,16, 17,18,19,20,12,13,14,15,16,17,18,19,20,21,13,14,15,16,17,18,19,20,21,22,14, 15,16,17,18,19,20,21,22,23,15,16,17,18,19,20,21,22,23,24,16,17,18,19,20,21, 22,23,24,25,8,9,10,11,12,13,14,15,16,17,9,10,11,12,13,14,15,16,17,18,10,11, 12,13,14,15,16,17,18,19,11,12,13,14,15,16,17,18,19,20,12,13,14,15,16,17,18, 19,20,21,13,14,15,16,17,18,19,20,21,22,14,15,16,17,18,19,20,21,22,23,15,16, 17,18,19,20,21,22,23,24,16,17,18,19,20,21,22,23,24,25,17,18,19,20,21,22,23, 24,25,26,9,10,11,12,13,14,15,16,17,18,10,11,12,13,14,15,16,17,18,19,11,12, 13,14,15,16,17,18,19,20,12,13,14,15,16,17,18,19,20,21,13,14,15,16,17,18,19, 20,21,22,14,15,16,17,18,19,20,21,22,23,15,16,17,18,19,20,21,22,23,24,16,17, 18,19,20,21,22,23,24,25,17,18,19,20,21,22,23,24,25,26,18,19,20,21,22,23,24, 25,26,27 }; ulong sumdigitsu(ulong n) { ulong s = 0; while (n) { s += digsum[n % 1000]; n /= 1000; } return s; } /* res=array of 9-digits integers, return \sum_{0 <= i < l} sumdigits(res[i]) */ static ulong sumdigits_block(ulong *res, long l) { long s = sumdigitsu(*--res); while (--l > 0) s += sumdigitsu(*--res); return s; } GEN sumdigits(GEN n) { pari_sp av = avma; ulong s, *res; long l; if (typ(n) != t_INT) pari_err_TYPE("sumdigits", n); l = lgefint(n); switch(l) { case 2: return gen_0; case 3: return utoipos(sumdigitsu(n[2])); } res = convi(n, &l); if ((ulong)l < ULONG_MAX / 81) { s = sumdigits_block(res, l); avma = av; return utoipos(s); } else /* Huge. Overflows ulong */ { const long L = (long)(ULONG_MAX / 81); GEN S = gen_0; while (l > L) { S = addiu(S, sumdigits_block(res, L)); res += L; l -= L; } if (l) S = addiu(S, sumdigits_block(res, l)); return gerepileuptoint(av, S); } } GEN sumdigits0(GEN x, GEN B) { pari_sp av = avma; GEN z; long lz; if (!B) return sumdigits(x); if (typ(x) != t_INT) pari_err_TYPE("sumdigits", x); B = check_basis(B); if (Z_ispow2(B)) { long k = expi(B); if (k == 1) { avma = av; return utoi(hammingweight(x)); } if (k < BITS_IN_LONG) { GEN z = binary_2k_nv(x, k); if (lg(z)-1 > 1L<<(BITS_IN_LONG-k)) /* may overflow */ return gerepileuptoint(av, ZV_sum(Flv_to_ZV(z))); avma = av; return utoi(zv_sum(z)); } return gerepileuptoint(av, ZV_sum(binary_2k(x, k))); } if (!signe(x)) { avma = av; return gen_0; } if (abscmpii(x,B)<0) { avma = av; return absi(x); } if (absequaliu(B,10)) { avma = av; return sumdigits(x); } x = absi_shallow(x); lz = logint(x,B) + 1; z = gen_digits_i(x, B, lz, NULL, &Z_ring, _dvmdii); return gerepileuptoint(av, ZV_sum(z)); } pari-2.11.2/src/basemath/Flxq_log.c0000644000175000017500000004650613326135265015471 0ustar billbill/* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Let [ be the following order on Fp: 0 [ p-1 [ 1 [ p-2 [ 2 .. [ p\2 and [[ the lexicographic extension of [ to Fp[T]. Compute the isomorphism (Fp[X], [[) -> (N,<) on P */ static long Flx_cindex(GEN P, ulong p) { long d = degpol(P), i; ulong s = 0, p2 = (p-1)>>1; for (i = 0; i <= d; ++i) { ulong x = P[d-i+2]; if (x<=p2) x = 2*x; else x = 1+2*(p-1-x); s = p*s+x; } return s; } /* Compute the polynomial immediately after t for the [[ order */ static void Flx_cnext(GEN t, ulong p) { long i; long p2 = p>>1; for(i=2;;i++) if (t[i]==p2) t[i]=0; else { t[i] = t[i]>1) : x>>1; c/=p; } return Flx_renormalize(P, d+3); } static GEN factorel(GEN h, ulong p) { GEN F = Flx_factor(h, p); GEN F1 = gel(F, 1), F2 = gel(F, 2); long i, l1 = lg(F1)-1; GEN p2 = cgetg(l1+1, t_VECSMALL); GEN e2 = cgetg(l1+1, t_VECSMALL); for (i = 1; i <= l1; ++i) { p2[i] = Flx_cindex(gel(F1, i), p); e2[i] = F2[i]; } return mkmat2(p2, e2); } static long Flx_addifsmooth3(pari_sp *av, struct Flxq_log_rel *r, GEN h, long u, long v, long w, ulong p) { long off = r->off; r->nbtest++; if (Flx_is_smooth(h, r->r, p)) { GEN z = factorel(h, p); if (v<0) z = mkmat2(vecsmall_append(gel(z,1),off+u),vecsmall_append(gel(z,2),-1)); else z = famatsmall_reduce(mkmat2( vecsmall_concat(gel(z,1),mkvecsmall3(off+u,off+v,off+w)), vecsmall_concat(gel(z,2),mkvecsmall3(-1,-1,-1)))); gel(r->rel,++r->nbrel) = gerepilecopy(*av,z); if (DEBUGLEVEL && (r->nbrel&511UL)==0) err_printf("%ld%% ",r->nbrel*100/r->nbexp); *av = avma; } else avma = *av; return r->nbrel==r->nb || r->nbrel==r->nbmax; } static void Flx_renormalize_inplace(GEN x, long lx) { long i; for (i = lx-1; i>1; i--) if (x[i]) break; setlg(x, i+1); } /* Let T*X^e=C^3-R a+b+c = 0 (C+a)*(C+b)*(C+c) = C^3+ (a*b+a*c+b*c)*C+a*b*c = R + (a*b+a*c+b*c)*C+a*b*c = R + (a*b-c^2)*C+a*b*c */ static void Flxq_log_cubic(struct Flxq_log_rel *r, GEN C, GEN R, ulong p) { long l = lg(C); GEN a = zero_zv(l); /*We allocate one extra word to catch overflow*/ GEN b = zero_zv(l); pari_sp av = avma; long i,j,k; for(i=0; ; i++, Flx_cnext(a, p)) { Flx_renormalize_inplace(a, l+1); r->nb++; if (Flx_addifsmooth3(&av, r, Flx_add(a, C, p), i, -1, -1, p)) return; for(j=2; j<=l; j++) b[j] = 0; for(j=0; j<=i; j++, Flx_cnext(b, p)) { GEN h,c; GEN pab,pabc,pabc2; Flx_renormalize_inplace(b, l+1); c = Flx_neg(Flx_add(a,b,p),p); k = Flx_cindex(c, p); if (k > j) continue; pab = Flx_mul(a, b, p); pabc = Flx_mul(pab,c,p); pabc2= Flx_sub(pab,Flx_sqr(c,p),p); h = Flx_add(R,Flx_add(Flx_mul(C,pabc2,p),pabc,p), p); h = Flx_normalize(h, p); if (Flx_addifsmooth3(&av, r, h, i, j, k, p)) return; } } } static GEN Flxq_log_find_rel(GEN b, long r, GEN T, ulong p, GEN *g, long *e) { pari_sp av = avma; while (1) { GEN M; *g = Flxq_mul(*g, b, T, p); (*e)++; M = Flx_halfgcd(*g,T,p); if (Flx_is_smooth(gcoeff(M,1,1), r, p)) { GEN z = Flx_add(Flx_mul(gcoeff(M,1,1),*g,p), Flx_mul(gcoeff(M,1,2),T,p),p); if (Flx_is_smooth(z, r, p)) { GEN F = factorel(z, p); GEN G = factorel(gcoeff(M,1,1), p); GEN rel = mkmat2(vecsmall_concat(gel(F, 1),gel(G, 1)), vecsmall_concat(gel(F, 2),zv_neg(gel(G, 2)))); gerepileall(av,2,g,&rel); return rel; } } if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"Flxq_log_find_rel"); *g = gerepilecopy(av, *g); } } } /* Generalised Odlyzko formulae ( EUROCRYPT '84, LNCS 209, pp. 224-314, 1985. ) */ /* Return the number of monic, k smooth, degree n polynomials for k=1..r */ static GEN smoothness_vec(ulong p, long r, long n) { long i,j,k; GEN R = cgetg(r+1, t_VEC); GEN V = cgetg(n+1, t_VEC); for (j = 1; j <= n; ++j) gel(V, j) = binomialuu(p+j-1,j); gel(R, 1) = gel(V, n); for (k = 2; k <= r; ++k) { GEN W = cgetg(n+1, t_VEC); GEN Ik = ffnbirred(utoi(p),k); for (j = 1; j <= n; ++j) { long l = j/k; GEN s = gen_0; pari_sp av2 = avma; if (l*k == j) { s = binomial(addiu(Ik,l-1), l); l--; } for (i = 0; i <= l; ++i) s = addii(s, mulii(gel(V, j-k*i), binomial(addis(Ik,i-1), i))); gel(W, j) = gerepileuptoint(av2, s); } V = W; gel(R, k) = gel(V, n); } return R; } /* Solve N^2*pr/6 + N*prC = N+fb N^2*pr/6 + N*(prC-1) -fb = 0 */ static GEN smooth_cost(GEN fb, GEN pr, GEN prC) { GEN a = gdivgs(pr,6); GEN b = gsubgs(prC,1); GEN c = gneg(fb); GEN vD = gsqrt(gsub(gsqr(b),gmul2n(gmul(a,c),2)),BIGDEFAULTPREC); return ceil_safe(gdiv(gsub(vD,b),gmul2n(a,1))); } /* Return best choice of r. We loop over d until there is sufficiently many triples (a,b,c) (a+b+c=0) of degree <=d with respect to the probability of smoothness of (a*b-c^2)*C */ static GEN smooth_best(long p, long n, long *pt_r, long *pt_nb) { pari_sp av = avma, av2; GEN bestc = NULL; long bestr = 0, bestFB = 0; long r,d, dC = (n+2)/3; for (r = 1; r < dC; ++r) { GEN fb = ffsumnbirred(utoi(p), r); GEN smoothC = smoothness_vec(p,r,dC); GEN prC = gdiv(gel(smoothC,r), powuu(p,dC)); ulong rels = 0; av2 = avma; for(d=0; d= 0) { rels = itou_or_0(addui(rels, gceil(gmul(gdivgs(sqri(Nmax),6),pr)))); if (!rels) rels = ULONG_MAX; avma = av2; continue; } c = gdivgs(addii(powuu(p,2*d),sqri(N)),6); FB = addii(FB,N); if ((!bestc || gcmp(gmul2n(c,r), gmul2n(bestc,bestr)) < 0)) { if (DEBUGLEVEL) err_printf("r=%ld d=%ld fb=%Ps early rels=%lu P=%.5Pe -> C=%.5Pe \n", r, dt, FB, rels, pr, c); bestc = c; bestr = r; bestFB = itos_or_0(FB); } break; } } *pt_r=bestr; *pt_nb=bestFB; return bestc ? gerepileupto(av, gceil(bestc)): NULL; } static GEN check_kernel(long r, GEN M, long nbi, long nbrow, GEN T, ulong p, GEN m) { pari_sp av = avma; long N = 3*upowuu(p, r); GEN K = FpMs_leftkernel_elt(M, nbrow, m); long i, f=0, tbs; long lm = lgefint(m), u=1; GEN tab, g; GEN q = powuu(p,degpol(T)); GEN idx = diviiexact(subiu(q,1),m); pari_timer ti; if (DEBUGLEVEL) timer_start(&ti); while (signe(gel(K,u))==0) u++; K = FpC_Fp_mul(K, Fp_inv(gel(K, u), m), m); g = Flxq_pow(cindex_Flx(u, r, p, T[1]), idx, T, p); tbs = maxss(1, expu(nbi/expi(m))); tab = Flxq_pow_init(g, q, tbs, T, p); setlg(K, N); for (i=1; i1) timer_printf(&ti,"%ld-smooth element",r); F = gel(V,1); E = gel(V,2); l = lg(F); Ao = gen_0; for(i=1; i=0) { avma = av; return NULL; } nbi = itos(ffsumnbirred(stoi(p), r)); if (DEBUGLEVEL) { err_printf("Size FB=%ld, looking for %ld relations, %Ps tests needed\n", nbi, nb,cost); timer_start(&ti); } T = smallirred_Flx(p,n,get_Flx_var(T0)); for(;;) { S = Flx_ffisom(T0,T,p); a = Flx_Flxq_eval(a0, S, T, p); b = Flx_Flxq_eval(b0, S, T, p); C = Flx_shift(pol1_Flx(get_Flx_var(T)), (n+2)/3); R = Flxq_powu(C,3,T,p); if (DEBUGLEVEL) timer_printf(&ti," model change: %Ps",Flx_to_ZX(T)); rel.nbmax=2*nb; M = cgetg(rel.nbmax+1, t_VEC); rel.rel = M; rel.nbrel = 0; rel.r = r; rel.off = 3*upowuu(p,r); rel.nb = nbi; rel.nbexp = nb; rel.nbtest=0; Flxq_log_cubic(&rel, C, R, p); setlg(M,1+rel.nbrel); if (DEBUGLEVEL) { err_printf("\n"); timer_printf(&ti," %ld relations, %ld generators (%ld tests)",rel.nbrel,rel.nb,rel.nbtest); } W = check_kernel(r, M, nbi, rel.off + rel.nb - nbi, T, p, m); if (W) break; if (DEBUGLEVEL) timer_start(&ti); smallirred_Flx_next(T,p); } if (DEBUGLEVEL) timer_start(&ti); Ao = Flxq_log_rec(W, a, r, T, p, m); if (DEBUGLEVEL) timer_printf(&ti,"smooth element"); Bo = Flxq_log_rec(W, b, r, T, p, m); if (DEBUGLEVEL) timer_printf(&ti,"smooth generator"); e = Fp_div(Ao, Bo, m); if (!Flx_equal(Flxq_pow(b0, e, T0, p), a0)) pari_err_BUG("Flxq_log"); return gerepileupto(av, e); } INLINE GEN Flx_frob(GEN u, ulong p) { return Flx_inflate(u, p); } static GEN rel_Coppersmith(long r, GEN u, GEN v, long h, GEN R, long d, ulong p) { GEN a, b, F, G, M; if (degpol(Flx_gcd(u,v,p))) return NULL; a = Flx_add(Flx_shift(u, h), v, p); if (lgpol(a)==0 || !Flx_is_smooth(a, r, p)) return NULL; b = Flx_add(Flx_mul(R, Flx_frob(u, p), p), Flx_shift(Flx_frob(v, p),d), p); if (!Flx_is_smooth(b, r, p)) return NULL; F = factorel(a, p); G = factorel(b, p); M = mkmat2(vecsmall_concat(gel(F, 1), vecsmall_append(gel(G, 1), 2*p)), vecsmall_concat(zv_z_mul(gel(F, 2),p), vecsmall_append(zv_neg(gel(G, 2)),d))); return famatsmall_reduce(M); } GEN Flxq_log_Coppersmith_worker(GEN u, long i, GEN V, GEN R) { long r = V[1], h = V[2], d = V[3], p = V[4], dT = V[5]; pari_sp ltop = avma; GEN v = zero_zv(dT+2); GEN L = cgetg(2*i+1, t_VEC); pari_sp av = avma; long j; long nbtest=0, rel = 1; ulong lu = Flx_lead(u), lv; for (j=1; j<=i; j++) { GEN z; Flx_cnext(v, p); Flx_renormalize_inplace(v, dT+2); lv = Flx_lead(v); avma = av; if (lu != 1 && lv != 1) continue; if (degpol(Flx_gcd(u, v, p))!=0) continue; if (lu==1) { z = rel_Coppersmith(r, u, v, h, R, d, p); nbtest++; if (z) { gel(L, rel++) = z; av = avma; } } if (i==j) continue; if (lv==1) { z = rel_Coppersmith(r, v, u, h, R, d, p); nbtest++; if (z) { gel(L, rel++) = z; av = avma; } } } setlg(L,rel); return gerepilecopy(ltop, mkvec2(stoi(nbtest), L)); } static GEN Flxq_log_Coppersmith(long nbrel, long r, GEN T, ulong p) { pari_sp av; long dT = degpol(T); long h = dT/p, d = dT-(h*p); GEN R = Flx_sub(Flx_shift(pol1_Flx(T[1]), dT), T, p); GEN u = zero_zv(dT+2); GEN done; long nbtest = 0, rel = 0; GEN M = cgetg(nbrel+1, t_VEC); long i = 1; GEN worker = snm_closure(is_entry("_Flxq_log_Coppersmith_worker"), mkvec2(mkvecsmall5(r,h,d,p,dT), R)); struct pari_mt pt; long running, pending = 0, stop=0; if (DEBUGLEVEL) err_printf("Coppersmith (R = %ld): ",degpol(R)); mt_queue_start(&pt, worker); av = avma; while ((running = !stop) || pending) { GEN L; long l, j; Flx_cnext(u, p); Flx_renormalize_inplace(u, dT+2); mt_queue_submit(&pt, 0, running ? mkvec2(u, stoi(i)): NULL); done = mt_queue_get(&pt, NULL, &pending); if (!done) continue; L = gel(done, 2); nbtest += itos(gel(done,1)); l = lg(L); if (l > 1) { for (j=1; jnbrel) break; gel(M,++rel) = gel(L,j); if (DEBUGLEVEL && (rel&511UL)==0) err_printf("%ld%%[%ld] ",rel*100/nbrel,i); } av = avma; } else avma = av; if (rel>nbrel) stop = 1; i++; } mt_queue_end(&pt); if (DEBUGLEVEL) err_printf(": %ld tests\n", nbtest); return M; } static GEN Flxq_log_Coppersmith_d(GEN W, GEN g, long r, GEN T, ulong p, GEN mo); static GEN Flxq_log_from_rel(GEN W, GEN rel, long r, GEN T, ulong p, GEN m) { pari_sp av = avma; GEN F = gel(rel,1), E = gel(rel,2), o = gen_0; long i, l = lg(F); for(i=1; i1) err_printf("Found %lu\n", idx); } return gerepileuptoint(av, l); } } avma = av; return NULL; } static GEN Flxq_log_Coppersmith_rec(GEN W, long r2, GEN a, long r, GEN T, ulong p, GEN m) { GEN b = polx_Flx(T[1]); long AV = 0; GEN g = a, bad = pol0_Flx(T[1]); pari_timer ti; while(1) { long i, l; GEN V, F, E, Ao; timer_start(&ti); V = Flxq_log_find_rel(b, r2, T, p, &g, &AV); if (DEBUGLEVEL>1) timer_printf(&ti,"%ld-smooth element",r2); F = gel(V,1); E = gel(V,2); l = lg(F); Ao = gen_0; for(i=1; i41)) return Flxq_log_index_Coppersmith(a, b, m, T, p); else return Flxq_log_index_cubic(a, b, m, T, p); } int Flxq_log_use_index(GEN m, GEN T, ulong p) { long d = get_Flx_degree(T); if (p==3 || (p==5 && d>41)) return 1; else if (d<=4 || d==6) return 0; else return Flxq_log_use_index_cubic(m, T, p); } pari-2.11.2/src/basemath/modsym.c0000644000175000017500000040750613461311601015215 0ustar billbill/* Copyright (C) 2011 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "pari.h" #include "paripriv.h" /* Adapted from shp_package/moments by Robert Pollack * http://www.math.mcgill.ca/darmon/programs/shp/shp.html */ static GEN mskinit(ulong N, long k, long sign); static GEN mshecke_i(GEN W, ulong p); static GEN ZSl2_star(GEN v); static GEN getMorphism(GEN W1, GEN W2, GEN v); static GEN voo_act_Gl2Q(GEN g, long k); /* Input: P^1(Z/NZ) (formed by create_p1mod) Output: # P^1(Z/NZ) */ static long p1_size(GEN p1N) { return lg(gel(p1N,1)) - 1; } static ulong p1N_get_N(GEN p1N) { return gel(p1N,3)[2]; } static GEN p1N_get_hash(GEN p1N) { return gel(p1N,2); } static GEN p1N_get_fa(GEN p1N) { return gel(p1N,4); } static GEN p1N_get_div(GEN p1N) { return gel(p1N,5); } static GEN p1N_get_invsafe(GEN p1N) { return gel(p1N,6); } static GEN p1N_get_inverse(GEN p1N) { return gel(p1N,7); } /* ms-specific accessors */ /* W = msinit, return the output of msinit_N */ static GEN get_msN(GEN W) { return lg(W) == 4? gel(W,1): W; } static GEN msN_get_p1N(GEN W) { return gel(W,1); } static GEN msN_get_genindex(GEN W) { return gel(W,5); } static GEN msN_get_E2fromE1(GEN W) { return gel(W,7); } static GEN msN_get_annT2(GEN W) { return gel(W,8); } static GEN msN_get_annT31(GEN W) { return gel(W,9); } static GEN msN_get_singlerel(GEN W) { return gel(W,10); } static GEN msN_get_section(GEN W) { return gel(W,12); } static GEN ms_get_p1N(GEN W) { return msN_get_p1N(get_msN(W)); } static long ms_get_N(GEN W) { return p1N_get_N(ms_get_p1N(W)); } static GEN ms_get_hashcusps(GEN W) { W = get_msN(W); return gel(W,16); } static GEN ms_get_section(GEN W) { return msN_get_section(get_msN(W)); } static GEN ms_get_genindex(GEN W) { return msN_get_genindex(get_msN(W)); } static long ms_get_nbgen(GEN W) { return lg(ms_get_genindex(W))-1; } static long ms_get_nbE1(GEN W) { GEN W11; W = get_msN(W); W11 = gel(W,11); return W11[4] - W11[3]; } /* msk-specific accessors */ static long msk_get_dim(GEN W) { return gmael(W,3,2)[2]; } static GEN msk_get_basis(GEN W) { return gmael(W,3,1); } static long msk_get_weight(GEN W) { return gmael(W,3,2)[1]; } static long msk_get_sign(GEN W) { GEN t = gel(W,2); return typ(t)==t_INT? 0: itos(gel(t,1)); } static GEN msk_get_star(GEN W) { return gmael(W,2,2); } static GEN msk_get_starproj(GEN W) { return gmael(W,2,3); } static int is_Qevproj(GEN x) { return typ(x) == t_VEC && lg(x) == 5 && typ(gel(x,1)) == t_MAT; } long msdim(GEN W) { if (is_Qevproj(W)) return lg(gel(W,1)) - 1; checkms(W); if (!msk_get_sign(W)) return msk_get_dim(W); return lg(gel(msk_get_starproj(W), 1)) - 1; } long msgetlevel(GEN W) { checkms(W); return ms_get_N(W); } long msgetweight(GEN W) { checkms(W); return msk_get_weight(W); } long msgetsign(GEN W) { checkms(W); return msk_get_sign(W); } void checkms(GEN W) { if (typ(W) != t_VEC || lg(W) != 4) pari_err_TYPE("checkms [please apply msinit]", W); } /** MODULAR TO SYM **/ /* q a t_FRAC or t_INT */ static GEN Q_log_init(ulong N, GEN q) { long l, n; GEN Q; q = gboundcf(q, 0); l = lg(q); Q = cgetg(l, t_VECSMALL); Q[1] = 1; for (n=2; n 1, gcd(c,d)=1. * Furthermore, d != d0 (mod N/c) with c,d0 already in the list */ l = lg(divN) - 1; /* c = 1 first */ gel(ret, ++curn) = mkvecsmall2(1,0); for (d = 2; d < N; d++) if (ugcd(d,N) != 1UL) gel(ret, ++curn) = mkvecsmall2(1,d); /* omit c = 1 (first) and c = N (last) */ for (i=2; i < l; i++) { ulong Novc, d0; c = divN[i]; Novc = N / c; for (d0 = 2; d0 <= Novc; d0++) { ulong k, d = d0; if (ugcd(d, Novc) == 1UL) continue; for (k = 0; k < c; k++, d += Novc) if (ugcd(c,d) == 1UL) { gel(ret, ++curn) = mkvecsmall2(c,d); break; } } } if (curn != num) pari_err_BUG("generatemsymbols [wrong number of symbols]"); return ret; } static GEN inithashmsymbols(ulong N, GEN symbols) { GEN H = zerovec(N); long k, l = lg(symbols); /* skip the (c:1), 0 <= c < N and (1:0) */ for (k=N+2; k < l; k++) { GEN s = gel(symbols, k); ulong c = s[1], d = s[2], Novc = N/c; if (gel(H,c) == gen_0) gel(H,c) = const_vecsmall(Novc+1,0); if (c != 1) { d %= Novc; if (!d) d = Novc; } mael(H, c, d) = k; } return H; } /** Helper functions for Sl2(Z) / Gamma_0(N) **/ /* M a 2x2 ZM in SL2(Z) */ static GEN SL2_inv(GEN M) { GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2); GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2); return mkmat22(d,negi(b), negi(c),a); } /* SL2_inv(M)[2] */ static GEN SL2_inv2(GEN M) { GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2); return mkcol2(negi(b),a); } /* M a 2x2 mat2 in SL2(Z) */ static GEN sl2_inv(GEN M) { long a=coeff(M,1,1), b=coeff(M,1,2), c=coeff(M,2,1), d=coeff(M,2,2); return mkvec2(mkvecsmall2(d, -c), mkvecsmall2(-b, a)); } /* Return the mat2 [a,b; c,d], not a zm to avoid GP problems */ static GEN mat2(long a, long b, long c, long d) { return mkvec2(mkvecsmall2(a,c), mkvecsmall2(b,d)); } static GEN mat2_to_ZM(GEN M) { GEN A = gel(M,1), B = gel(M,2); retmkmat2(mkcol2s(A[1],A[2]), mkcol2s(B[1],B[2])); } /* Input: a = 2-vector = path = {r/s,x/y} * Output: either [r,x;s,y] or [-r,x;-s,y], whichever has determinant > 0 */ static GEN path_to_ZM(GEN a) { GEN v = gel(a,1), w = gel(a,2); long r = v[1], s = v[2], x = w[1], y = w[2]; if (cmpii(mulss(r,y), mulss(x,s)) < 0) { r = -r; s = -s; } return mkmat22(stoi(r),stoi(x),stoi(s),stoi(y)); } static GEN path_to_zm(GEN a) { GEN v = gel(a,1), w = gel(a,2); long r = v[1], s = v[2], x = w[1], y = w[2]; if (cmpii(mulss(r,y), mulss(x,s)) < 0) { r = -r; s = -s; } return mat2(r,x,s,y); } /* path from c1 to c2 */ static GEN mkpath(GEN c1, GEN c2) { return mat2(c1[1], c2[1], c1[2], c2[2]); } static long cc(GEN M) { GEN v = gel(M,1); return v[2]; } static long dd(GEN M) { GEN v = gel(M,2); return v[2]; } /*Input: a,b = 2 paths, N = integer *Output: 1 if the a,b are \Gamma_0(N)-equivalent; 0 otherwise */ static int gamma_equiv(GEN a, GEN b, ulong N) { pari_sp av = avma; GEN m = path_to_zm(a); GEN n = path_to_zm(b); GEN d = subii(mulss(cc(m),dd(n)), mulss(dd(m),cc(n))); ulong res = umodiu(d, N); avma = av; return res == 0; } /* Input: a,b = 2 paths that are \Gamma_0(N)-equivalent, N = integer * Output: M in \Gamma_0(N) such that Mb=a */ static GEN gamma_equiv_matrix(GEN a, GEN b) { GEN m = path_to_ZM(a); GEN n = path_to_ZM(b); return ZM_mul(m, SL2_inv(n)); } /*************/ /* P^1(Z/NZ) */ /*************/ /* a != 0 in Z/NZ. Return v in (Z/NZ)^* such that av = gcd(a, N) (mod N)*/ static ulong Fl_inverse(ulong a, ulong N) { ulong g; return Fl_invgen(a,N,&g); } /* Input: N = integer * Output: creates P^1(Z/NZ) = [symbols, H, N] * symbols: list of vectors [x,y] that give a set of representatives * of P^1(Z/NZ) * H: an M by M grid whose value at the r,c-th place is the index of the * "standard representative" equivalent to [r,c] occuring in the first * list. If gcd(r,c,N) > 1 the grid has value 0. */ static GEN create_p1mod(ulong N) { GEN fa = factoru(N), div = divisorsu_fact(fa); ulong i, nsym = count_Manin_symbols(N, gel(fa,1)); GEN symbols = generatemsymbols(N, nsym, div); GEN H = inithashmsymbols(N,symbols); GEN invsafe = cgetg(N, t_VECSMALL), inverse = cgetg(N, t_VECSMALL); for (i = 1; i < N; i++) { invsafe[i] = Fl_invsafe(i,N); inverse[i] = Fl_inverse(i,N); } return mkvecn(7, symbols, H, utoipos(N), fa, div, invsafe, inverse); } /* Let (c : d) in P1(Z/NZ). * If c = 0 return (0:1). If d = 0 return (1:0). * Else replace by (cu : du), where u in (Z/NZ)^* such that C := cu = gcd(c,N). * In create_p1mod(), (c : d) is represented by (C:D) where D = du (mod N/c) * is smallest such that gcd(C,D) = 1. Return (C : du mod N/c), which need * not belong to P1(Z/NZ) ! A second component du mod N/c = 0 is replaced by * N/c in this case to avoid problems with array indices */ static void p1_std_form(long *pc, long *pd, GEN p1N) { ulong N = p1N_get_N(p1N); ulong u; *pc = smodss(*pc, N); if (!*pc) { *pd = 1; return; } *pd = smodss(*pd, N); if (!*pd) { *pc = 1; return; } u = p1N_get_invsafe(p1N)[*pd]; if (u) { *pc = Fl_mul(*pc,u,N); *pd = 1; return; } /* (d,N) = 1 */ u = p1N_get_inverse(p1N)[*pc]; if (u > 1) { *pc = Fl_mul(*pc,u,N); *pd = Fl_mul(*pd,u,N); } /* c | N */ if (*pc != 1) *pd %= (N / *pc); if (!*pd) *pd = N / *pc; } /* Input: v = [x,y] = elt of P^1(Z/NZ) = class in Gamma_0(N) \ PSL2(Z) * Output: returns the index of the standard rep equivalent to v */ static long p1_index(long x, long y, GEN p1N) { ulong N = p1N_get_N(p1N); GEN H = p1N_get_hash(p1N); p1_std_form(&x, &y, p1N); if (y == 1) return x+1; if (y == 0) return N+1; if (mael(H,x,y) == 0) pari_err_BUG("p1_index"); return mael(H,x,y); } /* Cusps for \Gamma_0(N) */ /* \sum_{d | N} \phi(gcd(d, N/d)), using multiplicativity. fa = factor(N) */ ulong mfnumcuspsu_fact(GEN fa) { GEN P = gel(fa,1), E = gel(fa,2); long i, l = lg(P); ulong T = 1; for (i = 1; i < l; i++) { long e = E[i], e2 = e >> 1; /* floor(E[i] / 2) */ ulong p = P[i]; if (odd(e)) T *= 2 * upowuu(p, e2); else T *= (p+1) * upowuu(p, e2-1); } return T; } ulong mfnumcuspsu(ulong n) { pari_sp av = avma; ulong t = mfnumcuspsu_fact( factoru(n) ); avma = av; return t; } /* \sum_{d | N} \phi(gcd(d, N/d)), using multiplicativity. fa = factor(N) */ GEN mfnumcusps_fact(GEN fa) { GEN P = gel(fa,1), E = gel(fa,2), T = gen_1; long i, l = lg(P); for (i = 1; i < l; i++) { GEN p = gel(P,i), c; long e = itos(gel(E,i)), e2 = e >> 1; /* floor(E[i] / 2) */ if (odd(e)) c = shifti(powiu(p, e2), 1); else c = mulii(addiu(p,1), powiu(p, e2-1)); T = T? mulii(T, c): c; } return T? T: gen_1; } GEN mfnumcusps(GEN n) { pari_sp av = avma; GEN F = check_arith_pos(n,"mfnumcusps"); if (!F) { if (lgefint(n) == 3) return utoi( mfnumcuspsu(n[2]) ); F = absZ_factor(n); } return gerepileuptoint(av, mfnumcusps_fact(F)); } /* to each cusp in \Gamma_0(N) P1(Q), represented by p/q, we associate a * unique index. Canonical representative: (1:0) or (p:q) with q | N, q < N, * p defined modulo d := gcd(N/q,q), (p,d) = 1. * Return [[N, nbcusps], H, cusps]*/ static GEN inithashcusps(GEN p1N) { ulong N = p1N_get_N(p1N); GEN div = p1N_get_div(p1N), H = zerovec(N+1); long k, ind, l = lg(div), ncusp = mfnumcuspsu_fact(p1N_get_fa(p1N)); GEN cusps = cgetg(ncusp+1, t_VEC); gel(H,1) = mkvecsmall2(0/*empty*/, 1/* first cusp: (1:0) */); gel(cusps, 1) = mkvecsmall2(1,0); ind = 2; for (k=1; k < l-1; k++) /* l-1: remove q = N */ { ulong p, q = div[k], d = ugcd(q, N/q); GEN h = const_vecsmall(d+1,0); gel(H,q+1) = h ; for (p = 0; p < d; p++) if (ugcd(p,d) == 1) { h[p+1] = ind; gel(cusps, ind) = mkvecsmall2(p,q); ind++; } } return mkvec3(mkvecsmall2(N,ind-1), H, cusps); } /* c = [p,q], (p,q) = 1, return a canonical representative for * \Gamma_0(N)(p/q) */ static GEN cusp_std_form(GEN c, GEN S) { long p, N = gel(S,1)[1], q = smodss(c[2], N); ulong u, d; if (q == 0) return mkvecsmall2(1, 0); p = smodss(c[1], N); u = Fl_inverse(q, N); q = Fl_mul(q,u, N); d = ugcd(q, N/q); return mkvecsmall2(Fl_div(p % d,u % d, d), q); } /* c = [p,q], (p,q) = 1, return the index of the corresponding cusp. * S from inithashcusps */ static ulong cusp_index(GEN c, GEN S) { long p, q; GEN H = gel(S,2); c = cusp_std_form(c, S); p = c[1]; q = c[2]; if (!mael(H,q+1,p+1)) pari_err_BUG("cusp_index"); return mael(H,q+1,p+1); } /* M a square invertible ZM, return a ZM iM such that iM M = M iM = d.Id */ static GEN ZM_inv_denom(GEN M) { GEN diM, iM = ZM_inv(M, &diM); return mkvec2(iM, diM); } /* return M^(-1) v, dinv = ZM_inv_denom(M) OR Qevproj_init(M) */ static GEN ZC_apply_dinv(GEN dinv, GEN v) { GEN x, c, iM; if (lg(dinv) == 3) { iM = gel(dinv,1); c = gel(dinv,2); } else { /* Qevproj_init */ iM = gel(dinv,2); c = gel(dinv,3); v = typ(v) == t_MAT? rowpermute(v, gel(dinv,4)) : vecpermute(v, gel(dinv,4)); } x = RgM_RgC_mul(iM, v); if (!isint1(c)) x = RgC_Rg_div(x, c); return x; } /* M an n x d ZM of rank d (basis of a Q-subspace), n >= d. * Initialize a projector on M */ GEN Qevproj_init(GEN M) { GEN v, perm, MM, iM, diM; v = ZM_indexrank(M); perm = gel(v,1); MM = rowpermute(M, perm); /* square invertible */ iM = ZM_inv(MM, &diM); return mkvec4(M, iM, diM, perm); } /* same with typechecks */ static GEN Qevproj_init0(GEN M) { switch(typ(M)) { case t_VEC: if (lg(M) == 5) return M; break; case t_COL: M = mkmat(M);/*fall through*/ case t_MAT: M = Q_primpart(M); RgM_check_ZM(M,"Qevproj_init"); return Qevproj_init(M); } pari_err_TYPE("Qevproj_init",M); return NULL; } /* T an n x n QM, pro = Qevproj_init(M), pro2 = Qevproj_init(M2); TM \subset M2. * Express these column vectors on M2's basis */ static GEN Qevproj_apply2(GEN T, GEN pro, GEN pro2) { GEN M = gel(pro,1), iM = gel(pro2,2), ciM = gel(pro2,3), perm = gel(pro2,4); return RgM_Rg_div(RgM_mul(iM, RgM_mul(rowpermute(T,perm), M)), ciM); } /* T an n x n QM, stabilizing d-dimensional Q-vector space spanned by the * d columns of M, pro = Qevproj_init(M). Return dxd matrix of T acting on M */ GEN Qevproj_apply(GEN T, GEN pro) { return Qevproj_apply2(T, pro, pro); } /* Qevproj_apply(T,pro)[,k] */ GEN Qevproj_apply_vecei(GEN T, GEN pro, long k) { GEN M = gel(pro,1), iM = gel(pro,2), ciM = gel(pro,3), perm = gel(pro,4); GEN v = RgM_RgC_mul(iM, RgM_RgC_mul(rowpermute(T,perm), gel(M,k))); return RgC_Rg_div(v, ciM); } static GEN QM_ker_r(GEN M) { return ZM_ker(Q_primpart(M)); } static GEN QM_image(GEN A) { A = vec_Q_primpart(A); return vecpermute(A, ZM_indeximage(A)); } static int cmp_dim(void *E, GEN a, GEN b) { long k; (void)E; a = gel(a,1); b = gel(b,1); k = lg(a)-lg(b); return k? ((k > 0)? 1: -1): 0; } /* FIXME: could use ZX_roots for deglim = 1 */ static GEN ZX_factor_limit(GEN T, long deglim, long *pl) { GEN fa = ZX_factor(T), P, E; long i, l; P = gel(fa,1); *pl = l = lg(P); if (deglim <= 0) return fa; E = gel(fa,2); for (i = 1; i < l; i++) if (degpol(gel(P,i)) > deglim) break; setlg(P,i); setlg(E,i); return fa; } /* Decompose the subspace H (Qevproj format) in simple subspaces. * Eg for H = msnew */ static GEN mssplit_i(GEN W, GEN H, long deglim) { ulong p, N = ms_get_N(W); long first, dim; forprime_t S; GEN T1 = NULL, T2 = NULL, V; dim = lg(gel(H,1))-1; V = vectrunc_init(dim+1); if (!dim) return V; (void)u_forprime_init(&S, 2, ULONG_MAX); vectrunc_append(V, H); first = 1; /* V[1..first-1] contains simple subspaces */ while ((p = u_forprime_next(&S))) { GEN T; long j, lV; if (N % p == 0) continue; if (T1 && T2) { T = RgM_add(T1,T2); T2 = NULL; } else { T2 = T1; T1 = T = mshecke(W, p, NULL); } lV = lg(V); for (j = first; j < lV; j++) { pari_sp av = avma; long lP; GEN Vj = gel(V,j), P = gel(Vj,1); GEN TVj = Qevproj_apply(T, Vj); /* c T | V_j */ GEN ch = QM_charpoly_ZX(TVj), fa = ZX_factor_limit(ch,deglim, &lP); GEN F = gel(fa, 1), E = gel(fa, 2); long k, lF = lg(F); if (lF == 2 && lP == 2) { if (isint1(gel(E,1))) { /* simple subspace */ swap(gel(V,first), gel(V,j)); first++; } else avma = av; } else if (lF == 1) /* discard V[j] */ { swap(gel(V,j), gel(V,lg(V)-1)); setlg(V, lg(V)-1); } else { /* can split Vj */ GEN pows; long D = 1; for (k = 1; k < lF; k++) { long d = degpol(gel(F,k)); if (d > D) D = d; } /* remove V[j] */ swap(gel(V,j), gel(V,lg(V)-1)); setlg(V, lg(V)-1); pows = RgM_powers(TVj, minss((long)2*sqrt((double)D), D)); for (k = 1; k < lF; k++) { GEN f = gel(F,k); GEN K = QM_ker_r( RgX_RgMV_eval(f, pows)) ; /* Ker f(TVj) */ GEN p = vec_Q_primpart( RgM_mul(P, K) ); vectrunc_append(V, Qevproj_init(p)); if (lg(K) == 2 || isint1(gel(E,k))) { /* simple subspace */ swap(gel(V,first), gel(V, lg(V)-1)); first++; } } if (j < first) j = first; } } if (first >= lg(V)) { gen_sort_inplace(V, NULL, cmp_dim, NULL); return V; } } pari_err_BUG("subspaces not found"); return NULL; } GEN mssplit(GEN W, GEN H, long deglim) { pari_sp av = avma; checkms(W); if (!msk_get_sign(W)) pari_err_DOMAIN("mssplit","abs(sign)","!=",gen_1,gen_0); if (!H) H = msnew(W); H = Qevproj_init0(H); return gerepilecopy(av, mssplit_i(W,H,deglim)); } /* proV = Qevproj_init of a Hecke simple subspace, return [ a_n, n <= B ] */ static GEN msqexpansion_i(GEN W, GEN proV, ulong B) { ulong p, N = ms_get_N(W), sqrtB; long i, d, k = msk_get_weight(W); forprime_t S; GEN T1=NULL, T2=NULL, TV=NULL, ch=NULL, v, dTiv, Tiv, diM, iM, L; switch(B) { case 0: return cgetg(1,t_VEC); case 1: return mkvec(gen_1); } (void)u_forprime_init(&S, 2, ULONG_MAX); while ((p = u_forprime_next(&S))) { GEN T; if (N % p == 0) continue; if (T1 && T2) { T = RgM_add(T1,T2); T2 = NULL; } else { T2 = T1; T1 = T = mshecke(W, p, NULL); } TV = Qevproj_apply(T, proV); /* T | V */ ch = QM_charpoly_ZX(TV); if (ZX_is_irred(ch)) break; ch = NULL; } if (!ch) pari_err_BUG("q-Expansion not found"); /* T generates the Hecke algebra (acting on V) */ d = degpol(ch); v = vec_ei(d, 1); /* take v = e_1 */ Tiv = cgetg(d+1, t_MAT); /* Tiv[i] = T^(i-1)v */ gel(Tiv, 1) = v; for (i = 2; i <= d; i++) gel(Tiv, i) = RgM_RgC_mul(TV, gel(Tiv,i-1)); Tiv = Q_remove_denom(Tiv, &dTiv); iM = ZM_inv(Tiv, &diM); if (dTiv) diM = gdiv(diM, dTiv); L = const_vec(B,NULL); sqrtB = usqrt(B); gel(L,1) = d > 1? mkpolmod(gen_1,ch): gen_1; for (p = 2; p <= B; p++) { pari_sp av = avma; GEN T, u, Tv, ap, P; ulong m; if (gel(L,p)) continue; /* p not prime */ T = mshecke(W, p, NULL); Tv = Qevproj_apply_vecei(T, proV, 1); /* Tp.v */ /* Write Tp.v = \sum u_i T^i v */ u = RgC_Rg_div(RgM_RgC_mul(iM, Tv), diM); ap = gerepilecopy(av, RgV_to_RgX(u, 0)); if (d > 1) ap = mkpolmod(ap,ch); else ap = simplify_shallow(ap); gel(L,p) = ap; if (!(N % p)) { /* p divides the level */ ulong C = B/p; for (m=1; m<=C; m++) if (gel(L,m)) gel(L,m*p) = gmul(gel(L,m), ap); continue; } P = powuu(p,k-1); if (p <= sqrtB) { ulong pj, oldpj = 1; for (pj = p; pj <= B; oldpj=pj, pj *= p) { GEN apj = (pj==p)? ap : gsub(gmul(ap,gel(L,oldpj)), gmul(P,gel(L,oldpj/p))); gel(L,pj) = apj; for (m = B/pj; m > 1; m--) if (gel(L,m) && m%p) gel(L,m*pj) = gmul(gel(L,m), apj); } } else { gel(L,p) = ap; for (m = B/p; m > 1; m--) if (gel(L,m)) gel(L,m*p) = gmul(gel(L,m), ap); } } return L; } GEN msqexpansion(GEN W, GEN proV, ulong B) { pari_sp av = avma; checkms(W); proV = Qevproj_init0(proV); return gerepilecopy(av, msqexpansion_i(W,proV,B)); } static GEN Qevproj_apply0(GEN T, GEN pro) { GEN iM = gel(pro,2), perm = gel(pro,4); return vec_Q_primpart(ZM_mul(iM, rowpermute(T,perm))); } /* T a ZC or ZM */ GEN Qevproj_down(GEN T, GEN pro) { GEN iM = gel(pro,2), ciM = gel(pro,3), perm = gel(pro,4); if (typ(T) == t_COL) return RgC_Rg_div(ZM_ZC_mul(iM, vecpermute(T,perm)), ciM); else return RgM_Rg_div(ZM_mul(iM, rowpermute(T,perm)), ciM); } static GEN Qevproj_star(GEN W, GEN H) { long s = msk_get_sign(W); if (s) { /* project on +/- component */ GEN A = RgM_mul(msk_get_star(W), H); A = (s > 0)? gadd(A, H): gsub(A, H); /* Im(star + sign) = Ker(star - sign) */ H = QM_image(A); H = Qevproj_apply0(H, msk_get_starproj(W)); } return H; } static GEN Tp_matrices(ulong p) { GEN v = cgetg(p+2, t_VEC); ulong i; for (i = 1; i <= p; i++) gel(v,i) = mat2(1, i-1, 0, p); gel(v,i) = mat2(p, 0, 0, 1); return v; } static GEN Up_matrices(ulong p) { GEN v = cgetg(p+1, t_VEC); ulong i; for (i = 1; i <= p; i++) gel(v,i) = mat2(1, i-1, 0, p); return v; } /* M = N/p. Classes of Gamma_0(M) / Gamma_O(N) when p | M */ static GEN NP_matrices(ulong M, ulong p) { GEN v = cgetg(p+1, t_VEC); ulong i; for (i = 1; i <= p; i++) gel(v,i) = mat2(1, 0, (i-1)*M, 1); return v; } /* M = N/p. Extra class of Gamma_0(M) / Gamma_O(N) when p \nmid M */ static GEN NP_matrix_extra(ulong M, ulong p) { long w,z, d = cbezout(p, -M, &w, &z); if (d != 1) return NULL; return mat2(w,z,M,p); } static GEN WQ_matrix(long N, long Q) { long w,z, d = cbezout(Q, N/Q, &w, &z); if (d != 1) return NULL; return mat2(Q,1,-N*z,Q*w); } GEN msnew(GEN W) { pari_sp av = avma; GEN S = mscuspidal(W, 0); ulong N = ms_get_N(W); long s = msk_get_sign(W), k = msk_get_weight(W); if (N > 1 && (!uisprime(N) || (k == 12 || k > 14))) { GEN p1N = ms_get_p1N(W), P = gel(p1N_get_fa(p1N), 1); long i, nP = lg(P)-1; GEN v = cgetg(2*nP + 1, t_COL); S = gel(S,1); /* Q basis */ for (i = 1; i <= nP; i++) { pari_sp av = avma, av2; long M = N/P[i]; GEN T1,Td, Wi = mskinit(M, k, s); GEN v1 = NP_matrices(M, P[i]); GEN vd = Up_matrices(P[i]); /* p^2 \nmid N */ if (M % P[i]) { v1 = shallowconcat(v1, mkvec(NP_matrix_extra(M,P[i]))); vd = shallowconcat(vd, mkvec(WQ_matrix(N,P[i]))); } T1 = getMorphism(W, Wi, v1); Td = getMorphism(W, Wi, vd); if (s) { T1 = Qevproj_apply2(T1, msk_get_starproj(W), msk_get_starproj(Wi)); Td = Qevproj_apply2(Td, msk_get_starproj(W), msk_get_starproj(Wi)); } av2 = avma; T1 = RgM_mul(T1,S); Td = RgM_mul(Td,S); /* multiply by S = restrict to mscusp */ gerepileallsp(av, av2, 2, &T1, &Td); gel(v,2*i-1) = T1; gel(v,2*i) = Td; } S = ZM_mul(S, QM_ker_r(matconcat(v))); /* Snew */ S = Qevproj_init(vec_Q_primpart(S)); } return gerepilecopy(av, S); } /* Solve the Manin relations for a congruence subgroup \Gamma by constructing * a well-formed fundamental domain for the action of \Gamma on upper half * space. See * Pollack and Stevens, Overconvergent modular symbols and p-adic L-functions * Annales scientifiques de l'ENS 44, fascicule 1 (2011), 1-42 * http://math.bu.edu/people/rpollack/Papers/Overconvergent_modular_symbols_and_padic_Lfunctions.pdf * * FIXME: Implemented for \Gamma = \Gamma_0(N) only. */ #if 0 /* Pollack-Stevens shift their paths so as to solve equations of the form f(z+1) - f(z) = g. We don't (to avoid mistakes) so we will have to solve eqs of the form f(z-1) - f(z) = g */ /* c = a/b; as a t_VECSMALL [a,b]; return c-1 as a t_VECSMALL */ static GEN Shift_left_cusp(GEN c) { long a=c[1], b=c[2]; return mkvecsmall2(a - b, b); } /* c = a/b; as a t_VECSMALL [a,b]; return c+1 as a t_VECSMALL */ static GEN Shift_right_cusp(GEN c) { long a=c[1], b=c[2]; return mkvecsmall2(a + b, b); } /*Input: path = [r,s] (thought of as a geodesic between these points) *Output: The path shifted by one to the left, i.e. [r-1,s-1] */ static GEN Shift_left(GEN path) { GEN r = gel(path,1), s = gel(path,2); return mkvec2(Shift_left_cusp(r), Shift_left_cusp(s)); } /*Input: path = [r,s] (thought of as a geodesic between these points) *Output: The path shifted by one to the right, i.e. [r+1,s+1] */ GEN Shift_right(GEN path) { GEN r = gel(path,1), s = gel(path,2); return mkvec2(Shift_right_cusp(r), Shift_right_cusp(s)); } #endif /* linked lists */ typedef struct list_t { GEN data; struct list_t *next; } list_t; static list_t * list_new(GEN x) { list_t *L = (list_t*)stack_malloc(sizeof(list_t)); L->data = x; L->next = NULL; return L; } static void list_insert(list_t *L, GEN x) { list_t *l = list_new(x); l->next = L->next; L->next = l; } /*Input: N > 1, p1N = P^1(Z/NZ) *Output: a connected fundamental domain for the action of \Gamma_0(N) on * upper half space. When \Gamma_0(N) is torsion free, the domain has the * property that all of its vertices are cusps. When \Gamma_0(N) has * three-torsion, 2 extra triangles need to be added. * * The domain is constructed by beginning with the triangle with vertices 0,1 * and oo. Each adjacent triangle is successively tested to see if it contains * points not \Gamma_0(N) equivalent to some point in our region. If a * triangle contains new points, it is added to the region. This process is * continued until the region can no longer be extended (and still be a * fundamental domain) by added an adjacent triangle. The list of cusps * between 0 and 1 are then returned * * Precisely, the function returns a list such that the elements of the list * with odd index are the cusps in increasing order. The even elements of the * list are either an "x" or a "t". A "t" represents that there is an element * of order three such that its fixed point is in the triangle directly * adjacent to the our region with vertices given by the cusp before and after * the "t". The "x" represents that this is not the case. */ enum { type_X, type_DO /* ? */, type_T }; static GEN form_list_of_cusps(ulong N, GEN p1N) { pari_sp av = avma; long i, position, nbC = 2; GEN v, L; list_t *C, *c; /* Let t be the index of a class in PSL2(Z) / \Gamma in our fixed enumeration * v[t] != 0 iff it is the class of z tau^r for z a previous alpha_i * or beta_i. * For \Gamma = \Gamma_0(N), the enumeration is given by p1_index. * We write cl(gamma) = the class of gamma mod \Gamma */ v = const_vecsmall(p1_size(p1N), 0); i = p1_index( 0, 1, p1N); v[i] = 1; i = p1_index( 1,-1, p1N); v[i] = 2; i = p1_index(-1, 0, p1N); v[i] = 3; /* the value is unused [debugging]: what matters is whether it is != 0 */ position = 4; /* at this point, Fund = R, v contains the classes of Id, tau, tau^2 */ C = list_new(mkvecsmall3(0,1, type_X)); list_insert(C, mkvecsmall3(1,1,type_DO)); /* C is a list of triples[a,b,t], where c = a/b is a cusp, and t is the type * of the path between c and the PREVIOUS cusp in the list, coded as * type_DO = "?", type_X = "x", type_T = "t" * Initially, C = [0/1,"?",1/1]; */ /* loop through the current set of cusps C and check to see if more cusps * should be added */ for (;;) { int done = 1; for (c = C; c; c = c->next) { GEN cusp1, cusp2, gam; long pos, b1, b2, b; if (!c->next) break; cusp1 = c->data; /* = a1/b1 */ cusp2 = (c->next)->data; /* = a2/b2 */ if (cusp2[3] != type_DO) continue; /* gam (oo -> 0) = (cusp2 -> cusp1), gam in PSL2(Z) */ gam = path_to_zm(mkpath(cusp2, cusp1)); /* = [a2,a1;b2,b1] */ /* we have normalized the cusp representation so that a1 b2 - a2 b1 = 1 */ b1 = coeff(gam,2,1); b2 = coeff(gam,2,2); /* gam.1 = (a1 + a2) / (b1 + b2) */ b = b1 + b2; /* Determine whether the adjacent triangle *below* (cusp1->cusp2) * should be added */ pos = p1_index(b1,b2, p1N); /* did we see cl(gam) before ? */ if (v[pos]) cusp2[3] = type_X; /* NO */ else { /* YES */ ulong B1, B2; v[pos] = position; i = p1_index(-(b1+b2), b1, p1N); v[i] = position+1; i = p1_index(b2, -(b1+b2), p1N); v[i] = position+2; /* add cl(gam), cl(gam*TAU), cl(gam*TAU^2) to v */ position += 3; /* gam tau gam^(-1) in \Gamma ? */ B1 = smodss(b1, N); B2 = smodss(b2, N); if ((Fl_sqr(B2,N) + Fl_sqr(B1,N) + Fl_mul(B1,B2,N)) % N == 0) cusp2[3] = type_T; else { long a1 = coeff(gam, 1,1), a2 = coeff(gam, 1,2); long a = a1 + a2; /* gcd(a,b) = 1 */ list_insert(c, mkvecsmall3(a,b,type_DO)); c = c->next; nbC++; done = 0; } } } if (done) break; } L = cgetg(nbC+1, t_VEC); i = 1; for (c = C; c; c = c->next) gel(L,i++) = c->data; return gerepilecopy(av, L); } /* W an msN. M in PSL2(Z). Return index of M in P1^(Z/NZ) = Gamma0(N) \ PSL2(Z), * and M0 in Gamma_0(N) such that M = M0 * M', where M' = chosen * section( PSL2(Z) -> P1^(Z/NZ) ). */ static GEN Gamma0N_decompose(GEN W, GEN M, long *index) { GEN p1N = msN_get_p1N(W), W3 = gel(W,3), section = msN_get_section(W); GEN A; ulong N = p1N_get_N(p1N); ulong c = umodiu(gcoeff(M,2,1), N); ulong d = umodiu(gcoeff(M,2,2), N); long s, ind = p1_index(c, d, p1N); /* as an elt of P1(Z/NZ) */ *index = W3[ind]; /* as an elt of F, E2, ... */ M = ZM_zm_mul(M, sl2_inv(gel(section,ind))); /* normalize mod +/-Id */ A = gcoeff(M,1,1); s = signe(A); if (s < 0) M = ZM_neg(M); else if (!s) { GEN C = gcoeff(M,2,1); if (signe(C) < 0) M = ZM_neg(M); } return M; } /* W an msN; as above for a path. Return [[ind], M] */ static GEN path_Gamma0N_decompose(GEN W, GEN path) { GEN p1N = msN_get_p1N(W); GEN p1index_to_ind = gel(W,3); GEN section = msN_get_section(W); GEN M = path_to_zm(path); long p1index = p1_index(cc(M), dd(M), p1N); long ind = p1index_to_ind[p1index]; GEN M0 = ZM_zm_mul(mat2_to_ZM(M), sl2_inv(gel(section,p1index))); return mkvec2(mkvecsmall(ind), M0); } /*Form generators of H_1(X_0(N),{cusps},Z) * *Input: N = integer > 1, p1N = P^1(Z/NZ) *Output: [cusp_list,E,F,T2,T3,E1] where * cusps_list = list of cusps describing fundamental domain of * \Gamma_0(N). * E = list of paths in the boundary of the fundamental domains and oriented * clockwise such that they do not contain a point * fixed by an element of order 2 and they are not an edge of a * triangle containing a fixed point of an element of order 3 * F = list of paths in the interior of the domain with each * orientation appearing separately * T2 = list of paths in the boundary of domain containing a point fixed * by an element of order 2 (oriented clockwise) * T3 = list of paths in the boundard of domain which are the edges of * some triangle containing a fixed point of a matrix of order 3 (both * orientations appear) * E1 = a sublist of E such that every path in E is \Gamma_0(N)-equivalent to * either an element of E1 or the flip (reversed orientation) of an element * of E1. * (Elements of T2 are \Gamma_0(N)-equivalent to their own flip.) * * sec = a list from 1..#p1N of matrices describing a section of the map * SL_2(Z) to P^1(Z/NZ) given by [a,b;c,d]-->[c,d]. * Given our fixed enumeration of P^1(Z/NZ), the j-th element of the list * represents the image of the j-th element of P^1(Z/NZ) under the section. */ /* insert path in set T */ static void set_insert(hashtable *T, GEN path) { hash_insert(T, path, (void*)(T->nb + 1)); } static GEN hash_to_vec(hashtable *h) { GEN v = cgetg(h->nb + 1, t_VEC); ulong i; for (i = 0; i < h->len; i++) { hashentry *e = h->table[i]; while (e) { GEN key = (GEN)e->key; long index = (long)e->val; gel(v, index) = key; e = e->next; } } return v; } static long path_to_p1_index(GEN path, GEN p1N) { GEN M = path_to_zm(path); return p1_index(cc(M), dd(M), p1N); } /* Pollack-Stevens sets */ typedef struct PS_sets_t { hashtable *F, *T2, *T31, *T32, *E1, *E2; GEN E2fromE1, stdE1; } PS_sets_t; static hashtable * set_init(long max) { return hash_create(max, (ulong(*)(void*))&hash_GEN, (int(*)(void*,void*))&gidentical, 1); } /* T = E2fromE1[i] = [c, gamma] */ static ulong E2fromE1_c(GEN T) { return itou(gel(T,1)); } static GEN E2fromE1_Zgamma(GEN T) { return gel(T,2); } static GEN E2fromE1_gamma(GEN T) { return gcoeff(gel(T,2),1,1); } static void insert_E(GEN path, PS_sets_t *S, GEN p1N) { GEN rev = vecreverse(path); long std = path_to_p1_index(rev, p1N); GEN v = gel(S->stdE1, std); if (v) { /* [s, p1], where E1[s] is the path p1 = vecreverse(path) mod \Gamma */ GEN gamma, p1 = gel(v,2); long r, s = itou(gel(v,1)); set_insert(S->E2, path); r = S->E2->nb; if (gel(S->E2fromE1, r) != gen_0) pari_err_BUG("insert_E"); gamma = gamma_equiv_matrix(rev, p1); /* reverse(E2[r]) = gamma * E1[s] */ gel(S->E2fromE1, r) = mkvec2(utoipos(s), to_famat_shallow(gamma,gen_m1)); } else { set_insert(S->E1, path); std = path_to_p1_index(path, p1N); gel(S->stdE1, std) = mkvec2(utoipos(S->E1->nb), path); } } static GEN cusp_infinity(void) { return mkvecsmall2(1,0); } static void form_E_F_T(ulong N, GEN p1N, GEN *pC, PS_sets_t *S) { GEN C, cusp_list = form_list_of_cusps(N, p1N); long nbgen = lg(cusp_list)-1, nbmanin = p1_size(p1N), r, s, i; hashtable *F, *T2, *T31, *T32, *E1, *E2; *pC = C = cgetg(nbgen+1, t_VEC); for (i = 1; i <= nbgen; i++) { GEN c = gel(cusp_list,i); gel(C,i) = mkvecsmall2(c[1], c[2]); } S->F = F = set_init(nbmanin); S->E1 = E1 = set_init(nbgen); S->E2 = E2 = set_init(nbgen); S->T2 = T2 = set_init(nbgen); S->T31 = T31 = set_init(nbgen); S->T32 = T32 = set_init(nbgen); /* T31 represents the three torsion paths going from left to right */ /* T32 represents the three torsion paths going from right to left */ for (r = 1; r < nbgen; r++) { GEN c2 = gel(cusp_list,r+1); if (c2[3] == type_T) { GEN c1 = gel(cusp_list,r), path = mkpath(c1,c2), path2 = vecreverse(path); set_insert(T31, path); set_insert(T32, path2); } } /* to record relations between E2 and E1 */ S->E2fromE1 = zerovec(nbgen); S->stdE1 = const_vec(nbmanin, NULL); /* Assumption later: path [oo,0] is E1[1], path [1,oo] is E2[1] */ { GEN oo = cusp_infinity(); GEN p1 = mkpath(oo, mkvecsmall2(0,1)); /* [oo, 0] */ GEN p2 = mkpath(mkvecsmall2(1,1), oo); /* [1, oo] */ insert_E(p1, S, p1N); insert_E(p2, S, p1N); } for (r = 1; r < nbgen; r++) { GEN c1 = gel(cusp_list,r); for (s = r+1; s <= nbgen; s++) { pari_sp av = avma; GEN c2 = gel(cusp_list,s), path; GEN d = subii(mulss(c1[1],c2[2]), mulss(c1[2],c2[1])); avma = av; if (!is_pm1(d)) continue; path = mkpath(c1,c2); if (r+1 == s) { GEN w = path; ulong hash = T31->hash(w); /* T31, T32 use the same hash function */ if (!hash_search2(T31, w, hash) && !hash_search2(T32, w, hash)) { if (gamma_equiv(path, vecreverse(path), N)) set_insert(T2, path); else insert_E(path, S, p1N); } } else { set_insert(F, mkvec2(path, mkvecsmall2(r,s))); set_insert(F, mkvec2(vecreverse(path), mkvecsmall2(s,r))); } } } setlg(S->E2fromE1, E2->nb+1); } /* v = \sum n_i g_i, g_i in Sl(2,Z), return \sum n_i g_i^(-1) */ static GEN ZSl2_star(GEN v) { long i, l; GEN w, G; if (typ(v) == t_INT) return v; G = gel(v,1); w = cgetg_copy(G, &l); for (i = 1; i < l; i++) { GEN g = gel(G,i); if (typ(g) == t_MAT) g = SL2_inv(g); gel(w,i) = g; } return ZG_normalize(mkmat2(w, gel(v,2))); } /* Input: h = set of unimodular paths, p1N = P^1(Z/NZ) = Gamma_0(N)\PSL2(Z) * Output: Each path is converted to a matrix and then an element of P^1(Z/NZ) * Append the matrix to W[12], append the index that represents * these elements of P^1 (the classes mod Gamma_0(N) via our fixed * enumeration to W[2]. */ static void paths_decompose(GEN W, hashtable *h, int flag) { GEN p1N = ms_get_p1N(W), section = ms_get_section(W); GEN v = hash_to_vec(h); long i, l = lg(v); for (i = 1; i < l; i++) { GEN e = gel(v,i); GEN M = path_to_zm(flag? gel(e,1): e); long index = p1_index(cc(M), dd(M), p1N); vecsmalltrunc_append(gel(W,2), index); gel(section, index) = M; } } static void fill_W2_W12(GEN W, PS_sets_t *S) { GEN p1N = msN_get_p1N(W); long n = p1_size(p1N); gel(W, 2) = vecsmalltrunc_init(n+1); gel(W,12) = cgetg(n+1, t_VEC); /* F contains [path, [index cusp1, index cusp2]]. Others contain paths only */ paths_decompose(W, S->F, 1); paths_decompose(W, S->E2, 0); paths_decompose(W, S->T32, 0); paths_decompose(W, S->E1, 0); paths_decompose(W, S->T2, 0); paths_decompose(W, S->T31, 0); } /* x t_VECSMALL, corresponds to a map x(i) = j, where 1 <= j <= max for all i * Return y s.t. y[j] = i or 0 (not in image) */ static GEN reverse_list(GEN x, long max) { GEN y = const_vecsmall(max, 0); long r, lx = lg(x); for (r = 1; r < lx; r++) y[ x[r] ] = r; return y; } /* go from C[a] to C[b]; return the indices of paths * E.g. if a < b * (C[a]->C[a+1], C[a+1]->C[a+2], ... C[b-1]->C[b]) * (else reverse direction) * = b - a paths */ static GEN F_indices(GEN W, long a, long b) { GEN v = cgetg(labs(b-a) + 1, t_VEC); long s, k = 1; if (a < b) { GEN index_forward = gel(W,13); for (s = a; s < b; s++) gel(v,k++) = gel(index_forward,s); } else { GEN index_backward = gel(W,14); for (s = a; s > b; s--) gel(v,k++) = gel(index_backward,s); } return v; } /* go from C[a] to C[b] via oo; return the indices of paths * E.g. if a < b * (C[a]->C[a-1], ... C[2]->C[1], * C[1]->oo, oo-> C[end], * C[end]->C[end-1], ... C[b+1]->C[b]) * a-1 + 2 + end-(b+1)+1 = end - b + a + 1 paths */ static GEN F_indices_oo(GEN W, long end, long a, long b) { GEN index_oo = gel(W,15); GEN v = cgetg(end-labs(b-a)+1 + 1, t_VEC); long s, k = 1; if (a < b) { GEN index_backward = gel(W,14); for (s = a; s > 1; s--) gel(v,k++) = gel(index_backward,s); gel(v,k++) = gel(index_backward,1); /* C[1] -> oo */ gel(v,k++) = gel(index_oo,2); /* oo -> C[end] */ for (s = end; s > b; s--) gel(v,k++) = gel(index_backward,s); } else { GEN index_forward = gel(W,13); for (s = a; s < end; s++) gel(v,k++) = gel(index_forward,s); gel(v,k++) = gel(index_forward,end); /* C[end] -> oo */ gel(v,k++) = gel(index_oo,1); /* oo -> C[1] */ for (s = 1; s < b; s++) gel(v,k++) = gel(index_forward,s); } return v; } /* index of oo -> C[1], oo -> C[end] */ static GEN indices_oo(GEN W, GEN C) { long end = lg(C)-1; GEN w, v = cgetg(2+1, t_VEC), oo = cusp_infinity(); w = mkpath(oo, gel(C,1)); /* oo -> C[1]=0 */ gel(v,1) = path_Gamma0N_decompose(W, w); w = mkpath(oo, gel(C,end)); /* oo -> C[end]=1 */ gel(v,2) = path_Gamma0N_decompose(W, w); return v; } /* index of C[1]->C[2], C[2]->C[3], ... C[end-1]->C[end], C[end]->oo * Recall that C[1] = 0, C[end] = 1 */ static GEN indices_forward(GEN W, GEN C) { long s, k = 1, end = lg(C)-1; GEN v = cgetg(end+1, t_VEC); for (s = 1; s <= end; s++) { GEN w = mkpath(gel(C,s), s == end? cusp_infinity(): gel(C,s+1)); gel(v,k++) = path_Gamma0N_decompose(W, w); } return v; } /* index of C[1]->oo, C[2]->C[1], ... C[end]->C[end-1] */ static GEN indices_backward(GEN W, GEN C) { long s, k = 1, end = lg(C)-1; GEN v = cgetg(end+1, t_VEC); for (s = 1; s <= end; s++) { GEN w = mkpath(gel(C,s), s == 1? cusp_infinity(): gel(C,s-1)); gel(v,k++) = path_Gamma0N_decompose(W, w); } return v; } /*[0,-1;1,-1]*/ static GEN mkTAU() { return mkmat22(gen_0,gen_m1, gen_1,gen_m1); } /* S */ static GEN mkS() { return mkmat22(gen_0,gen_1, gen_m1,gen_0); } /* N = integer > 1. Returns data describing Delta_0 = Z[P^1(Q)]_0 seen as * a Gamma_0(N) - module. */ static GEN msinit_N(ulong N) { GEN p1N, C, vecF, vecT2, vecT31, TAU, W, W2, singlerel, annT2, annT31; GEN F_index; ulong r, s, width; long nball, nbgen, nbp1N; hashtable *F, *T2, *T31, *T32, *E1, *E2; PS_sets_t S; W = zerovec(16); gel(W,1) = p1N = create_p1mod(N); gel(W,16)= inithashcusps(p1N); TAU = mkTAU(); if (N == 1) { gel(W,5) = mkvecsmall(1); /* cheat because sets are not disjoint if N=1 */ gel(W,11) = mkvecsmall5(0, 0, 1, 1, 2); gel(W,12) = mkvec(mat2(1,0,0,1)); gel(W,8) = mkvec( mkmat22(gen_1,gen_1, mkS(),gen_1) ); gel(W,9) = mkvec( mkmat2(mkcol3(gen_1,TAU,ZM_sqr(TAU)), mkcol3(gen_1,gen_1,gen_1)) ); return W; } nbp1N = p1_size(p1N); form_E_F_T(N,p1N, &C, &S); E1 = S.E1; E2 = S.E2; T31 = S.T31; T32 = S.T32; F = S.F; T2 = S.T2; nbgen = lg(C)-1; /* Put our paths in the order: F,E2,T32,E1,T2,T31 * W2[j] associates to the j-th element of this list its index in P1. */ fill_W2_W12(W, &S); W2 = gel(W, 2); nball = lg(W2)-1; gel(W,3) = reverse_list(W2, nbp1N); gel(W,5) = vecslice(gel(W,2), F->nb + E2->nb + T32->nb + 1, nball); gel(W,4) = reverse_list(gel(W,5), nbp1N); gel(W,13) = indices_forward(W, C); gel(W,14) = indices_backward(W, C); gel(W,15) = indices_oo(W, C); gel(W,11) = mkvecsmall5(F->nb, F->nb + E2->nb, F->nb + E2->nb + T32->nb, F->nb + E2->nb + T32->nb + E1->nb, F->nb + E2->nb + T32->nb + E1->nb + T2->nb); /* relations between T32 and T31 [not stored!] * T32[i] = - T31[i] */ /* relations of F */ width = E1->nb + T2->nb + T31->nb; /* F_index[r] = [index_1, ..., index_k], where index_i is the p1_index() * of the elementary unimodular path between 2 consecutive cusps * [in E1,E2,T2,T31 or T32] */ F_index = cgetg(F->nb+1, t_VEC); vecF = hash_to_vec(F); for (r = 1; r <= F->nb; r++) { GEN w = gel(gel(vecF,r), 2); long a = w[1], b = w[2], d = labs(b - a); /* c1 = cusp_list[a], c2 = cusp_list[b], ci != oo */ gel(F_index,r) = (nbgen-d >= d-1)? F_indices(W, a,b) : F_indices_oo(W, lg(C)-1,a,b); } singlerel = cgetg(width+1, t_VEC); /* form the single boundary relation */ for (s = 1; s <= E2->nb; s++) { /* reverse(E2[s]) = gamma * E1[c] */ GEN T = gel(S.E2fromE1,s), gamma = E2fromE1_gamma(T); gel(singlerel, E2fromE1_c(T)) = mkmat22(gen_1,gen_1, gamma,gen_m1); } for (r = E1->nb + 1; r <= width; r++) gel(singlerel, r) = gen_1; /* form the 2-torsion relations */ annT2 = cgetg(T2->nb+1, t_VEC); vecT2 = hash_to_vec(T2); for (r = 1; r <= T2->nb; r++) { GEN w = gel(vecT2,r); GEN gamma = gamma_equiv_matrix(vecreverse(w), w); gel(annT2, r) = mkmat22(gen_1,gen_1, gamma,gen_1); } /* form the 3-torsion relations */ annT31 = cgetg(T31->nb+1, t_VEC); vecT31 = hash_to_vec(T31); for (r = 1; r <= T31->nb; r++) { GEN M = path_to_ZM( vecreverse(gel(vecT31,r)) ); GEN gamma = ZM_mul(ZM_mul(M, TAU), SL2_inv(M)); gel(annT31, r) = mkmat2(mkcol3(gen_1,gamma,ZM_sqr(gamma)), mkcol3(gen_1,gen_1,gen_1)); } gel(W,6) = F_index; gel(W,7) = S.E2fromE1; gel(W,8) = annT2; gel(W,9) = annT31; gel(W,10)= singlerel; return W; } static GEN cusp_to_P1Q(GEN c) { return c[2]? gdivgs(stoi(c[1]), c[2]): mkoo(); } static GEN mspathgens_i(GEN W) { GEN R, r, g, section, gen, annT2, annT31; long i, l; checkms(W); W = get_msN(W); section = msN_get_section(W); gen = ms_get_genindex(W); l = lg(gen); g = cgetg(l,t_VEC); for (i = 1; i < l; i++) { GEN p = gel(section,gen[i]); gel(g,i) = mkvec2(cusp_to_P1Q(gel(p,1)), cusp_to_P1Q(gel(p,2))); } annT2 = msN_get_annT2(W); annT31= msN_get_annT31(W); if (ms_get_N(W) == 1) { R = cgetg(3, t_VEC); gel(R,1) = mkvec( mkvec2(gel(annT2,1), gen_1) ); gel(R,2) = mkvec( mkvec2(gel(annT31,1), gen_1) ); } else { GEN singlerel = msN_get_singlerel(W); long j, nbT2 = lg(annT2)-1, nbT31 = lg(annT31)-1, nbE1 = ms_get_nbE1(W); R = cgetg(nbT2+nbT31+2, t_VEC); l = lg(singlerel); r = cgetg(l, t_VEC); for (i = 1; i <= nbE1; i++) gel(r,i) = mkvec2(gel(singlerel, i), utoi(i)); for (; i < l; i++) gel(r,i) = mkvec2(gen_1, utoi(i)); gel(R,1) = r; j = 2; for (i = 1; i <= nbT2; i++,j++) gel(R,j) = mkvec( mkvec2(gel(annT2,i), utoi(i + nbE1)) ); for (i = 1; i <= nbT31; i++,j++) gel(R,j) = mkvec( mkvec2(gel(annT31,i), utoi(i + nbE1 + nbT2)) ); } return mkvec2(g,R); } GEN mspathgens(GEN W) { pari_sp av = avma; return gerepilecopy(av, mspathgens_i(W)); } /* Modular symbols in weight k: Hom_Gamma(Delta, Q[x,y]_{k-2}) */ /* A symbol phi is represented by the {phi(g_i)}, {phi(g'_i)}, {phi(g''_i)} * where the {g_i, g'_i, g''_i} are the Z[\Gamma]-generators of Delta, * g_i corresponds to E1, g'_i to T2, g''_i to T31. */ /* FIXME: export. T^1, ..., T^n */ static GEN RgX_powers(GEN T, long n) { GEN v = cgetg(n+1, t_VEC); long i; gel(v, 1) = T; for (i = 1; i < n; i++) gel(v,i+1) = RgX_mul(gel(v,i), T); return v; } /* g = [a,b;c,d] a mat2. Return (X^{k-2} | g)(X,Y)[X = 1]. */ static GEN voo_act_Gl2Q(GEN g, long k) { GEN mc = stoi(-coeff(g,2,1)), d = stoi(coeff(g,2,2)); return RgX_to_RgC(gpowgs(deg1pol_shallow(mc, d, 0), k-2), k-1); } struct m_act { long dim, k, p; GEN q; GEN(*act)(struct m_act *,GEN); }; /* g = [a,b;c,d]. Return (P | g)(X,Y)[X = 1] = P(dX - cY, -b X + aY)[X = 1], * for P = X^{k-2}, X^{k-3}Y, ..., Y^{k-2} */ GEN RgX_act_Gl2Q(GEN g, long k) { GEN a,b,c,d, V1,V2,V; long i; if (k == 2) return matid(1); a = gcoeff(g,1,1); b = gcoeff(g,1,2); c = gcoeff(g,2,1); d = gcoeff(g,2,2); V1 = RgX_powers(deg1pol_shallow(gneg(c), d, 0), k-2); /* d - c Y */ V2 = RgX_powers(deg1pol_shallow(a, gneg(b), 0), k-2); /*-b + a Y */ V = cgetg(k, t_MAT); gel(V,1) = RgX_to_RgC(gel(V1, k-2), k-1); for (i = 1; i < k-2; i++) { GEN v1 = gel(V1, k-2-i); /* (d-cY)^(k-2-i) */ GEN v2 = gel(V2, i); /* (-b+aY)^i */ gel(V,i+1) = RgX_to_RgC(RgX_mul(v1,v2), k-1); } gel(V,k-1) = RgX_to_RgC(gel(V2, k-2), k-1); return V; /* V[i+1] = X^i | g */ } /* z in Z[Gl2(Q)], return the matrix of z acting on V */ static GEN act_ZGl2Q(GEN z, struct m_act *T, hashtable *H) { GEN S = NULL, G, E; pari_sp av; long l, j; /* paranoia: should not occur */ if (typ(z) == t_INT) return scalarmat_shallow(z, T->dim); G = gel(z,1); l = lg(G); E = gel(z,2); av = avma; for (j = 1; j < l; j++) { GEN M, g = gel(G,j), n = gel(E,j); if (typ(g) == t_INT) /* = 1 */ M = n; /* n*Id_dim */ else { /*search in H succeeds because of preload*/ M = H? (GEN)hash_search(H,g)->val: T->act(T,g); if (is_pm1(n)) { if (signe(n) < 0) M = RgM_neg(M); } else M = RgM_Rg_mul(M, n); } if (!S) { S = M; continue; } S = gadd(S, M); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"act_ZGl2Q, j = %ld",j); S = gerepileupto(av, S); } } return gerepilecopy(av, S); } static GEN _RgX_act_Gl2Q(struct m_act *S, GEN z) { return RgX_act_Gl2Q(z, S->k); } /* acting on (X^{k-2},...,Y^{k-2}) */ GEN RgX_act_ZGl2Q(GEN z, long k) { struct m_act T; T.k = k; T.dim = k-1; T.act=&_RgX_act_Gl2Q; return act_ZGl2Q(z, &T, NULL); } /* First pass, identify matrices in Sl_2 to convert to operators; * insert operators in hashtable. This allows GC in act_ZGl2Q */ static void hash_preload(GEN M, struct m_act *S, hashtable *H) { if (typ(M) != t_INT) { ulong h = H->hash(M); hashentry *e = hash_search2(H, M, h); if (!e) hash_insert2(H, M, S->act(S,M), h); } } /* z a sparse operator */ static void hash_vecpreload(GEN z, struct m_act *S, hashtable *H) { GEN G = gel(z,1); long i, l = lg(G); for (i = 1; i < l; i++) hash_preload(gel(G,i), S, H); } static void ZGl2QC_preload(struct m_act *S, GEN v, hashtable *H) { GEN val = gel(v,2); long i, l = lg(val); for (i = 1; i < l; i++) hash_vecpreload(gel(val,i), S, H); } /* Given a sparse vector of elements in Z[G], convert it to a (sparse) vector * of operators on V (given by t_MAT) */ static void ZGl2QC_to_act(struct m_act *S, GEN v, hashtable *H) { GEN val = gel(v,2); long i, l = lg(val); for (i = 1; i < l; i++) gel(val,i) = act_ZGl2Q(gel(val,i), S, H); } /* For all V[i] in Z[\Gamma], find the P such that P . V[i]^* = 0; * write P in basis X^{k-2}, ..., Y^{k-2} */ static GEN ZGV_tors(GEN V, long k) { long i, l = lg(V); GEN v = cgetg(l, t_VEC); for (i = 1; i < l; i++) { GEN a = ZSl2_star(gel(V,i)); gel(v,i) = ZM_ker(RgX_act_ZGl2Q(a,k)); } return v; } static long set_from_index(GEN W11, long i) { if (i <= W11[1]) return 1; if (i <= W11[2]) return 2; if (i <= W11[3]) return 3; if (i <= W11[4]) return 4; if (i <= W11[5]) return 5; return 6; } /* det M = 1 */ static void treat_index(GEN W, GEN M, long index, GEN v) { GEN W11 = gel(W,11); long shift = W11[3]; /* #F + #E2 + T32 */ switch(set_from_index(W11, index)) { case 1: /*F*/ { GEN F_index = gel(W,6), ind = gel(F_index, index); long j, l = lg(ind); for (j = 1; j < l; j++) { GEN IND = gel(ind,j), M0 = gel(IND,2); long index = mael(IND,1,1); treat_index(W, ZM_mul(M,M0), index, v); } break; } case 2: /*E2, E2[r] + gamma * E1[s] = 0 */ { long r = index - W11[1]; GEN z = gel(msN_get_E2fromE1(W), r); index = E2fromE1_c(z); M = G_ZG_mul(M, E2fromE1_Zgamma(z)); /* M * (-gamma) */ gel(v, index) = ZG_add(gel(v, index), M); break; } case 3: /*T32, T32[i] = -T31[i] */ { long T3shift = W11[5] - W11[2]; /* #T32 + #E1 + #T2 */ index += T3shift; index -= shift; gel(v, index) = ZG_add(gel(v, index), to_famat_shallow(M,gen_m1)); break; } default: /*E1,T2,T31*/ index -= shift; gel(v, index) = ZG_add(gel(v, index), to_famat_shallow(M,gen_1)); break; } } static void treat_index_trivial(GEN v, GEN W, long index) { GEN W11 = gel(W,11); long shift = W11[3]; /* #F + #E2 + T32 */ switch(set_from_index(W11, index)) { case 1: /*F*/ { GEN F_index = gel(W,6), ind = gel(F_index, index); long j, l = lg(ind); for (j = 1; j < l; j++) { GEN IND = gel(ind,j); treat_index_trivial(v, W, mael(IND,1,1)); } break; } case 2: /*E2, E2[r] + gamma * E1[s] = 0 */ { long r = index - W11[1]; long s = E2fromE1_c(gel(msN_get_E2fromE1(W), r)); v[s]--; break; } case 3: case 5: case 6: /*T32,T2,T31*/ break; case 4: /*E1*/ v[index-shift]++; break; } } static GEN M2_log(GEN W, GEN M) { GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2); GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2); GEN u, v, D, V; long index, s; W = get_msN(W); V = zerovec(ms_get_nbgen(W)); D = subii(mulii(a,d), mulii(b,c)); s = signe(D); if (!s) return V; if (is_pm1(D)) { /* shortcut, no need to apply Manin's trick */ if (s < 0) { b = negi(b); d = negi(d); } M = Gamma0N_decompose(W, mkmat22(a,b, c,d), &index); treat_index(W, M, index, V); } else { GEN U, B, P, Q, PQ, C1,C2; long i, l; (void)bezout(a,c,&u,&v); B = addii(mulii(b,u), mulii(d,v)); /* [u,v;-c,a] [a,b; c,d] = [1,B; 0,D], i.e. M = U [1,B;0,D] */ U = mkmat22(a,negi(v), c,u); /* {1/0 -> B/D} as \sum g_i, g_i unimodular paths */ PQ = ZV_allpnqn( gboundcf(gdiv(B,D), 0) ); P = gel(PQ,1); l = lg(P); Q = gel(PQ,2); C1 = gel(U,1); for (i = 1; i < l; i++, C1 = C2) { GEN M; C2 = ZM_ZC_mul(U, mkcol2(gel(P,i), gel(Q,i))); if (!odd(i)) C1 = ZC_neg(C1); M = Gamma0N_decompose(W, mkmat2(C1,C2), &index); treat_index(W, M, index, V); } } return V; } /* express +oo->q=a/b in terms of the Z[G]-generators, trivial action */ static void Q_log_trivial(GEN v, GEN W, GEN q) { GEN Q, W3 = gel(W,3), p1N = msN_get_p1N(W); ulong c,d, N = p1N_get_N(p1N); long i, lx; Q = Q_log_init(N, q); lx = lg(Q); c = 0; for (i = 1; i < lx; i++, c = d) { long index; d = Q[i]; if (c && !odd(i)) c = N - c; index = W3[ p1_index(c,d,p1N) ]; treat_index_trivial(v, W, index); } } static void M2_log_trivial(GEN V, GEN W, GEN M) { GEN p1N = gel(W,1), W3 = gel(W,3); ulong N = p1N_get_N(p1N); GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2); GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2); GEN u, v, D; long index, s; D = subii(mulii(a,d), mulii(b,c)); s = signe(D); if (!s) return; if (is_pm1(D)) { /* shortcut, not need to apply Manin's trick */ if (s < 0) d = negi(d); index = W3[ p1_index(umodiu(c,N),umodiu(d,N),p1N) ]; treat_index_trivial(V, W, index); } else { GEN U, B, P, Q, PQ; long i, l; if (!signe(c)) { Q_log_trivial(V,W,gdiv(b,d)); return; } (void)bezout(a,c,&u,&v); B = addii(mulii(b,u), mulii(d,v)); /* [u,v;-c,a] [a,b; c,d] = [1,B; 0,D], i.e. M = U [1,B;0,D] */ U = mkvec2(c, u); /* {1/0 -> B/D} as \sum g_i, g_i unimodular paths */ PQ = ZV_allpnqn( gboundcf(gdiv(B,D), 0) ); P = gel(PQ,1); l = lg(P); Q = gel(PQ,2); for (i = 1; i < l; i++, c = d) { d = addii(mulii(gel(U,1),gel(P,i)), mulii(gel(U,2),gel(Q,i))); if (!odd(i)) c = negi(c); index = W3[ p1_index(umodiu(c,N),umodiu(d,N),p1N) ]; treat_index_trivial(V, W, index); } } } static GEN cusp_to_ZC(GEN c) { switch(typ(c)) { case t_INFINITY: return mkcol2(gen_1,gen_0); case t_INT: return mkcol2(c,gen_1); case t_FRAC: return mkcol2(gel(c,1),gel(c,2)); case t_VECSMALL: return mkcol2(stoi(c[1]), stoi(c[2])); default: pari_err_TYPE("mspathlog",c); return NULL; } } static GEN path2_to_M2(GEN p) { return mkmat2(cusp_to_ZC(gel(p,1)), cusp_to_ZC(gel(p,2))); } static GEN path_to_M2(GEN p) { if (lg(p) != 3) pari_err_TYPE("mspathlog",p); switch(typ(p)) { case t_MAT: RgM_check_ZM(p,"mspathlog"); break; case t_VEC: p = path2_to_M2(p); break; default: pari_err_TYPE("mspathlog",p); } return p; } /* Expresses path p as \sum x_i g_i, where the g_i are our distinguished * generators and x_i \in Z[\Gamma]. Returns [x_1,...,x_n] */ GEN mspathlog(GEN W, GEN p) { pari_sp av = avma; checkms(W); return gerepilecopy(av, M2_log(W, path_to_M2(p))); } /** HECKE OPERATORS **/ /* [a,b;c,d] * cusp */ static GEN cusp_mul(long a, long b, long c, long d, GEN cusp) { long x = cusp[1], y = cusp[2]; long A = a*x+b*y, B = c*x+d*y, u = cgcd(A,B); if (u != 1) { A /= u; B /= u; } return mkcol2s(A, B); } /* f in Gl2(Q), act on path (zm), return path_to_M2(f.path) */ static GEN Gl2Q_act_path(GEN f, GEN path) { long a = coeff(f,1,1), b = coeff(f,1,2); long c = coeff(f,2,1), d = coeff(f,2,2); GEN c1 = cusp_mul(a,b,c,d, gel(path,1)); GEN c2 = cusp_mul(a,b,c,d, gel(path,2)); return mkmat2(c1,c2); } static GEN init_act_trivial(GEN W) { return const_vecsmall(ms_get_nbE1(W), 0); } static GEN mspathlog_trivial(GEN W, GEN p) { GEN v; W = get_msN(W); v = init_act_trivial(W); M2_log_trivial(v, W, path_to_M2(p)); return v; } /* map from W1=Hom(Delta_0(N1),Q) -> W2=Hom(Delta_0(N2),Q), weight 2, * trivial action. v a Gl2_Q or a t_VEC of Gl2_Q (\sum v[i] in Z[Gl2(Q)]). * Return the matrix attached to the action of v. */ static GEN getMorphism_trivial(GEN WW1, GEN WW2, GEN v) { GEN T, section, gen, W1 = get_msN(WW1), W2 = get_msN(WW2); long j, lv, d2; if (ms_get_N(W1) == 1) return cgetg(1,t_MAT); if (ms_get_N(W2) == 1) return zeromat(0, ms_get_nbE1(W1)); section = msN_get_section(W2); gen = msN_get_genindex(W2); d2 = ms_get_nbE1(W2); T = cgetg(d2+1, t_MAT); lv = lg(v); for (j = 1; j <= d2; j++) { GEN w = gel(section, gen[j]); GEN t = init_act_trivial(W1); pari_sp av = avma; long l; for (l = 1; l < lv; l++) M2_log_trivial(t, W1, Gl2Q_act_path(gel(v,l), w)); gel(T,j) = t; avma = av; } return shallowtrans(zm_to_ZM(T)); } static GEN RgV_sparse(GEN v, GEN *pind) { long i, l, k; GEN w = cgetg_copy(v,&l), ind = cgetg(l, t_VECSMALL); for (i = k = 1; i < l; i++) { GEN c = gel(v,i); if (typ(c) == t_INT) continue; gel(w,k) = c; ind[k] = i; k++; } setlg(w,k); setlg(ind,k); *pind = ind; return w; } static int mat2_isidentity(GEN M) { GEN A = gel(M,1), B = gel(M,2); return A[1] == 1 && A[2] == 0 && B[1] == 0 && B[2] == 1; } /* path a mat22/mat22s, return log(f.path)^* . f in sparse form */ static GEN M2_logf(GEN Wp, GEN path, GEN f) { pari_sp av = avma; GEN ind, L; long i, l; if (f) path = Gl2Q_act_path(f, path); else if (typ(gel(path,1)) == t_VECSMALL) path = path2_to_M2(path); L = M2_log(Wp, path); L = RgV_sparse(L,&ind); l = lg(L); for (i = 1; i < l; i++) gel(L,i) = ZSl2_star(gel(L,i)); if (f) ZGC_G_mul_inplace(L, mat2_to_ZM(f)); return gerepilecopy(av, mkvec2(ind,L)); } static hashtable * Gl2act_cache(long dim) { return set_init(dim*10); } /* f zm/ZM in Gl_2(Q), acts from the left on Delta, which is generated by * (g_i) as Z[Gamma1]-module, and by (G_i) as Z[Gamma2]-module. * We have f.G_j = \sum_i \lambda_{i,j} g_i, \lambda_{i,j} in Z[Gamma1] * For phi in Hom_Gamma1(D,V), g in D, phi | f is in Hom_Gamma2(D,V) and * (phi | f)(G_j) = phi(f.G_j) | f * = phi( \sum_i \lambda_{i,j} g_i ) | f * = \sum_i phi(g_i) | (\lambda_{i,j}^* f) * = \sum_i phi(g_i) | \mu_{i,j}(f) * More generally * (\sum_k (phi |v_k))(G_j) = \sum_i phi(g_i) | \Mu_{i,j} * with \Mu_{i,j} = \sum_k \mu{i,j}(v_k) * Return the \Mu_{i,j} matrix as vector of sparse columns of operators on V */ static GEN init_dual_act(GEN v, GEN W1, GEN W2, struct m_act *S) { GEN section = ms_get_section(W2), gen = ms_get_genindex(W2); /* HACK: the actions we consider in dimension 1 are trivial and in * characteristic != 2, 3 => torsion generators are 0 * [satisfy e.g. (1+gamma).g = 0 => \phi(g) | 1+gamma = 0 => \phi(g) = 0 */ long j, lv = lg(v), dim = S->dim == 1? ms_get_nbE1(W2): lg(gen)-1; GEN T = cgetg(dim+1, t_VEC); hashtable *H = Gl2act_cache(dim); for (j = 1; j <= dim; j++) { pari_sp av = avma; GEN w = gel(section, gen[j]); /* path_to_zm( E1/T2/T3 element ) */ GEN t = NULL; long k; for (k = 1; k < lv; k++) { GEN tk, f = gel(v,k); if (typ(gel(f,1)) != t_VECSMALL) f = ZM_to_zm(f); if (mat2_isidentity(f)) f = NULL; tk = M2_logf(W1, w, f); /* mu_{.,j}(v[k]) as sparse vector */ t = t? ZGCs_add(t, tk): tk; } gel(T,j) = gerepilecopy(av, t); } for (j = 1; j <= dim; j++) { ZGl2QC_preload(S, gel(T,j), H); ZGl2QC_to_act(S, gel(T,j), H); } return T; } /* modular symbol given by phi[j] = \phi(G_j) * \sum L[i]*phi[i], L a sparse column of operators */ static GEN dense_act_col(GEN col, GEN phi) { GEN s = NULL, colind = gel(col,1), colval = gel(col,2); long i, l = lg(colind), lphi = lg(phi); for (i = 1; i < l; i++) { long a = colind[i]; GEN t; if (a >= lphi) break; /* happens if k=2: torsion generator t omitted */ t = gel(phi, a); /* phi(G_a) */ t = RgM_RgC_mul(gel(colval,i), t); s = s? RgC_add(s, t): t; } return s; } /* modular symbol given by \phi( G[ind[j]] ) = val[j] * \sum L[i]*phi[i], L a sparse column of operators */ static GEN sparse_act_col(GEN col, GEN phi) { GEN s = NULL, colind = gel(col,1), colval = gel(col,2); GEN ind = gel(phi,2), val = gel(phi,3); long a, l = lg(ind); if (lg(gel(phi,1)) == 1) return RgM_RgC_mul(gel(colval,1), gel(val,1)); for (a = 1; a < l; a++) { GEN t = gel(val, a); /* phi(G_i) */ long i = zv_search(colind, ind[a]); if (!i) continue; t = RgM_RgC_mul(gel(colval,i), t); s = s? RgC_add(s, t): t; } return s; } static int phi_sparse(GEN phi) { return typ(gel(phi,1)) == t_VECSMALL; } /* phi in Hom_Gamma1(Delta, V), return the matrix whose colums are the * \sum_i phi(g_i) | \mu_{i,j} = (phi|f)(G_j), * see init_dual_act. */ static GEN dual_act(long dimV, GEN act, GEN phi) { long l = lg(act), j; GEN v = cgetg(l, t_MAT); GEN (*ACT)(GEN,GEN) = phi_sparse(phi)? sparse_act_col: dense_act_col; for (j = 1; j < l; j++) { pari_sp av = avma; GEN s = ACT(gel(act,j), phi); gel(v,j) = s? gerepileupto(av,s): zerocol(dimV); } return v; } /* in level N > 1 */ static void msk_get_st(GEN W, long *s, long *t) { GEN st = gmael(W,3,3); *s = st[1]; *t = st[2]; } static GEN msk_get_link(GEN W) { return gmael(W,3,4); } static GEN msk_get_inv(GEN W) { return gmael(W,3,5); } /* \phi in Hom(Delta, V), \phi(G_k) = phi[k]. Write \phi as * \sum_{i,j} mu_{i,j} phi_{i,j}, mu_{i,j} in Q */ static GEN getMorphism_basis(GEN W, GEN phi) { GEN R, Q, Ls, T0, T1, Ts, link, basis, inv = msk_get_inv(W); long i, j, r, s, t, dim, lvecT; if (ms_get_N(W) == 1) return ZC_apply_dinv(inv, gel(phi,1)); lvecT = lg(phi); basis = msk_get_basis(W); dim = lg(basis)-1; R = zerocol(dim); msk_get_st(W, &s, &t); link = msk_get_link(W); for (r = 2; r < lvecT; r++) { GEN Tr, L; if (r == s) continue; Tr = gel(phi,r); /* Phi(G_r), r != 1,s */ L = gel(link, r); Q = ZC_apply_dinv(gel(inv,r), Tr); /* write Phi(G_r) as sum_{a,b} mu_{a,b} Phi_{a,b}(G_r) */ for (j = 1; j < lg(L); j++) gel(R, L[j]) = gel(Q,j); } Ls = gel(link, s); T1 = gel(phi,1); /* Phi(G_1) */ gel(R, Ls[t]) = gel(T1, 1); T0 = NULL; for (i = 2; i < lg(link); i++) { GEN L; if (i == s) continue; L = gel(link,i); for (j =1 ; j < lg(L); j++) { long n = L[j]; /* phi_{i,j} = basis[n] */ GEN mu_ij = gel(R, n); GEN phi_ij = gel(basis, n), pols = gel(phi_ij,3); GEN z = RgC_Rg_mul(gel(pols, 3), mu_ij); T0 = T0? RgC_add(T0, z): z; /* += mu_{i,j} Phi_{i,j} (G_s) */ } } Ts = gel(phi,s); /* Phi(G_s) */ if (T0) Ts = RgC_sub(Ts, T0); /* solve \sum_{j!=t} mu_{s,j} Phi_{s,j}(G_s) = Ts */ Q = ZC_apply_dinv(gel(inv,s), Ts); for (j = 1; j < t; j++) gel(R, Ls[j]) = gel(Q,j); /* avoid mu_{s,t} */ for (j = t; j < lg(Q); j++) gel(R, Ls[j+1]) = gel(Q,j); return R; } /* a = s(g_i) for some modular symbol s; b in Z[G] * return s(b.g_i) = b^* . s(g_i) */ static GEN ZGl2Q_act_s(GEN b, GEN a, long k) { if (typ(b) == t_INT) { if (!signe(b)) return gen_0; switch(typ(a)) { case t_POL: a = RgX_to_RgC(a, k-1); /*fall through*/ case t_COL: a = RgC_Rg_mul(a,b); break; default: a = scalarcol_shallow(b,k-1); } } else { b = RgX_act_ZGl2Q(ZSl2_star(b), k); switch(typ(a)) { case t_POL: a = RgX_to_RgC(a, k-1); /*fall through*/ case t_COL: a = RgM_RgC_mul(b,a); break; default: a = RgC_Rg_mul(gel(b,1),a); } } return a; } static int checksymbol(GEN W, GEN s) { GEN t, annT2, annT31, singlerel; long i, k, l, nbE1, nbT2, nbT31; k = msk_get_weight(W); W = get_msN(W); nbE1 = ms_get_nbE1(W); singlerel = gel(W,10); l = lg(singlerel); if (k == 2) { for (i = nbE1+1; i < l; i++) if (!gequal0(gel(s,i))) return 0; return 1; } annT2 = msN_get_annT2(W); nbT2 = lg(annT2)-1; annT31 = msN_get_annT31(W);nbT31 = lg(annT31)-1; t = NULL; for (i = 1; i < l; i++) { GEN a = gel(s,i); a = ZGl2Q_act_s(gel(singlerel,i), a, k); t = t? gadd(t, a): a; } if (!gequal0(t)) return 0; for (i = 1; i <= nbT2; i++) { GEN a = gel(s,i + nbE1); a = ZGl2Q_act_s(gel(annT2,i), a, k); if (!gequal0(a)) return 0; } for (i = 1; i <= nbT31; i++) { GEN a = gel(s,i + nbE1 + nbT2); a = ZGl2Q_act_s(gel(annT31,i), a, k); if (!gequal0(a)) return 0; } return 1; } GEN msissymbol(GEN W, GEN s) { long k, nbgen; checkms(W); k = msk_get_weight(W); nbgen = ms_get_nbgen(W); switch(typ(s)) { case t_VEC: /* values s(g_i) */ if (lg(s)-1 != nbgen) return gen_0; break; case t_COL: if (msk_get_sign(W)) { GEN star = gel(msk_get_starproj(W), 1); if (lg(star) == lg(s)) return gen_1; } if (k == 2) /* on the dual basis of (g_i) */ { if (lg(s)-1 != nbgen) return gen_0; } else { GEN basis = msk_get_basis(W); return (lg(s) == lg(basis))? gen_1: gen_0; } break; case t_MAT: { long i, l = lg(s); GEN v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = msissymbol(W,gel(s,i))? gen_1: gen_0; return v; } default: return gen_0; } return checksymbol(W,s)? gen_1: gen_0; } /* map op: W1 = Hom(Delta_0(N1),V) -> W2 = Hom(Delta_0(N2),V), given by * \sum v[i], v[i] in Gl2(Q) */ static GEN getMorphism(GEN W1, GEN W2, GEN v) { struct m_act S; GEN B1, M, act; long a, l, k = msk_get_weight(W1); if (k == 2) return getMorphism_trivial(W1,W2,v); S.k = k; S.dim = k-1; S.act = &_RgX_act_Gl2Q; act = init_dual_act(v,W1,W2,&S); B1 = msk_get_basis(W1); l = lg(B1); M = cgetg(l, t_MAT); for (a = 1; a < l; a++) { pari_sp av = avma; GEN phi = dual_act(S.dim, act, gel(B1,a)); GEN D = getMorphism_basis(W2, phi); gel(M,a) = gerepilecopy(av, D); } return M; } static GEN msendo(GEN W, GEN v) { return getMorphism(W, W, v); } static GEN endo_project(GEN W, GEN e, GEN H) { if (msk_get_sign(W)) e = Qevproj_apply(e, msk_get_starproj(W)); if (H) e = Qevproj_apply(e, Qevproj_init0(H)); return e; } static GEN mshecke_i(GEN W, ulong p) { GEN v = ms_get_N(W) % p? Tp_matrices(p): Up_matrices(p); return msendo(W,v); } GEN mshecke(GEN W, long p, GEN H) { pari_sp av = avma; GEN T; checkms(W); if (p <= 1) pari_err_PRIME("mshecke",stoi(p)); T = mshecke_i(W,p); T = endo_project(W,T,H); return gerepilecopy(av, T); } static GEN msatkinlehner_i(GEN W, long Q) { long N = ms_get_N(W); GEN v; if (Q == 1) return matid(msk_get_dim(W)); if (Q == N) return msendo(W, mkvec(mat2(0,1,-N,0))); if (N % Q) pari_err_DOMAIN("msatkinlehner","N % Q","!=",gen_0,stoi(Q)); v = WQ_matrix(N, Q); if (!v) pari_err_DOMAIN("msatkinlehner","gcd(Q,N/Q)","!=",gen_1,stoi(Q)); return msendo(W,mkvec(v)); } GEN msatkinlehner(GEN W, long Q, GEN H) { pari_sp av = avma; GEN w; long k; checkms(W); k = msk_get_weight(W); if (Q <= 0) pari_err_DOMAIN("msatkinlehner","Q","<=",gen_0,stoi(Q)); w = msatkinlehner_i(W,Q); w = endo_project(W,w,H); if (k > 2 && Q != 1) w = RgM_Rg_div(w, powuu(Q,(k-2)>>1)); return gerepilecopy(av, w); } static GEN msstar_i(GEN W) { return msendo(W, mkvec(mat2(-1,0,0,1))); } GEN msstar(GEN W, GEN H) { pari_sp av = avma; GEN s; checkms(W); s = msstar_i(W); s = endo_project(W,s,H); return gerepilecopy(av, s); } #if 0 /* is \Gamma_0(N) cusp1 = \Gamma_0(N) cusp2 ? */ static int iscuspeq(ulong N, GEN cusp1, GEN cusp2) { long p1, q1, p2, q2, s1, s2, d; p1 = cusp1[1]; p2 = cusp2[1]; q1 = cusp1[2]; q2 = cusp2[2]; d = Fl_mul(smodss(q1,N),smodss(q2,N), N); d = ugcd(d, N); s1 = q1 > 2? Fl_inv(smodss(p1,q1), q1): 1; s2 = q2 > 2? Fl_inv(smodss(p2,q2), q2): 1; return Fl_mul(s1,q2,d) == Fl_mul(s2,q1,d); } #endif /* return E_c(r) */ static GEN get_Ec_r(GEN c, long k) { long p = c[1], q = c[2], u, v; GEN gr; (void)cbezout(p, q, &u, &v); gr = mat2(p, -v, q, u); /* g . (1:0) = (p:q) */ return voo_act_Gl2Q(sl2_inv(gr), k); } /* N > 1; returns the modular symbol attached to the cusp c := p/q via the rule * E_c(path from a to b in Delta_0) := E_c(b) - E_c(a), where * E_c(r) := 0 if r != c mod Gamma * v_oo | gamma_r^(-1) * where v_oo is stable by T = [1,1;0,1] (i.e x^(k-2)) and * gamma_r . (1:0) = r, for some gamma_r in SL_2(Z) * */ static GEN msfromcusp_trivial(GEN W, GEN c) { GEN section = ms_get_section(W), gen = ms_get_genindex(W); GEN S = ms_get_hashcusps(W); long j, ic = cusp_index(c, S), l = ms_get_nbE1(W)+1; GEN phi = cgetg(l, t_COL); for (j = 1; j < l; j++) { GEN vj, g = gel(section, gen[j]); /* path_to_zm(generator) */ GEN c1 = gel(g,1), c2 = gel(g,2); long i1 = cusp_index(c1, S); long i2 = cusp_index(c2, S); if (i1 == ic) vj = (i2 == ic)? gen_0: gen_1; else vj = (i2 == ic)? gen_m1: gen_0; gel(phi, j) = vj; } return phi; } static GEN msfromcusp_i(GEN W, GEN c) { GEN section, gen, S, phi; long j, ic, l, k = msk_get_weight(W); if (k == 2) { long N = ms_get_N(W); return N == 1? cgetg(1,t_COL): msfromcusp_trivial(W, c); } k = msk_get_weight(W); section = ms_get_section(W); gen = ms_get_genindex(W); S = ms_get_hashcusps(W); ic = cusp_index(c, S); l = lg(gen); phi = cgetg(l, t_COL); for (j = 1; j < l; j++) { GEN vj = NULL, g = gel(section, gen[j]); /* path_to_zm(generator) */ GEN c1 = gel(g,1), c2 = gel(g,2); long i1 = cusp_index(c1, S); long i2 = cusp_index(c2, S); if (i1 == ic) vj = get_Ec_r(c1, k); if (i2 == ic) { GEN s = get_Ec_r(c2, k); vj = vj? gsub(vj, s): gneg(s); } if (!vj) vj = zerocol(k-1); gel(phi, j) = vj; } return getMorphism_basis(W, phi); } GEN msfromcusp(GEN W, GEN c) { pari_sp av = avma; long N; checkms(W); N = ms_get_N(W); switch(typ(c)) { case t_INFINITY: c = mkvecsmall2(1,0); break; case t_INT: c = mkvecsmall2(smodis(c,N), 1); break; case t_FRAC: c = mkvecsmall2(smodis(gel(c,1),N), smodis(gel(c,2),N)); break; default: pari_err_TYPE("msfromcusp",c); } return gerepilecopy(av, msfromcusp_i(W,c)); } static GEN mseisenstein_i(GEN W) { GEN M, S = ms_get_hashcusps(W), cusps = gel(S,3); long i, l = lg(cusps); if (msk_get_weight(W)==2) l--; M = cgetg(l, t_MAT); for (i = 1; i < l; i++) gel(M,i) = msfromcusp_i(W, gel(cusps,i)); return Qevproj_star(W, QM_image(M)); } GEN mseisenstein(GEN W) { pari_sp av = avma; checkms(W); return gerepilecopy(av, Qevproj_init(mseisenstein_i(W))); } /* upper bound for log_2 |charpoly(T_p|S)|, where S is a cuspidal subspace of * dimension d, k is the weight */ #if 0 static long TpS_char_bound(ulong p, long k, long d) { /* |eigenvalue| <= 2 p^(k-1)/2 */ return d * (2 + (log2((double)p)*(k-1))/2); } #endif static long TpE_char_bound(ulong p, long k, long d) { /* |eigenvalue| <= 2 p^(k-1) */ return d * (2 + log2((double)p)*(k-1)); } GEN mscuspidal(GEN W, long flag) { pari_sp av = avma; GEN S, E, M, T, TE, chE; long bit; forprime_t F; ulong p, N; pari_timer ti; E = mseisenstein(W); N = ms_get_N(W); (void)u_forprime_init(&F, 2, ULONG_MAX); while ((p = u_forprime_next(&F))) if (N % p) break; if (DEBUGLEVEL) timer_start(&ti); T = mshecke(W, p, NULL); if (DEBUGLEVEL) timer_printf(&ti,"Tp, p = %ld", p); TE = Qevproj_apply(T, E); /* T_p | E */ if (DEBUGLEVEL) timer_printf(&ti,"Qevproj_init(E)"); bit = TpE_char_bound(p, msk_get_weight(W), lg(TE)-1); chE = QM_charpoly_ZX_bound(TE, bit); chE = ZX_radical(chE); M = RgX_RgM_eval(chE, T); S = Qevproj_init(QM_image(M)); return gerepilecopy(av, flag? mkvec2(S,E): S); } /** INIT ELLSYM STRUCTURE **/ /* V a vector of ZM. If all of them have 0 last row, return NULL. * Otherwise return [m,i,j], where m = V[i][last,j] contains the value * of smallest absolute value */ static GEN RgMV_find_non_zero_last_row(long offset, GEN V) { long i, lasti = 0, lastj = 0, lV = lg(V); GEN m = NULL; for (i = 1; i < lV; i++) { GEN M = gel(V,i); long j, n, l = lg(M); if (l == 1) continue; n = nbrows(M); for (j = 1; j < l; j++) { GEN a = gcoeff(M, n, j); if (!gequal0(a) && (!m || abscmpii(a, m) < 0)) { m = a; lasti = i; lastj = j; if (is_pm1(m)) goto END; } } } END: if (!m) return NULL; return mkvec2(m, mkvecsmall2(lasti+offset, lastj)); } /* invert the d_oo := (\gamma_oo - 1) operator, acting on * [x^(k-2), ..., y^(k-2)] */ static GEN Delta_inv(GEN doo, long k) { GEN M = RgX_act_ZGl2Q(doo, k); M = RgM_minor(M, k-1, 1); /* 1st column and last row are 0 */ return ZM_inv_denom(M); } /* The ZX P = \sum a_i x^i y^{k-2-i} is given by the ZV [a_0, ..., a_k-2]~, * return Q and d such that P = doo Q + d y^k-2, where d in Z and Q */ static GEN doo_decompose(GEN dinv, GEN P, GEN *pd) { long l = lg(P); *pd = gel(P, l-1); P = vecslice(P, 1, l-2); return shallowconcat(gen_0, ZC_apply_dinv(dinv, P)); } static GEN get_phi_ij(long i,long j,long n, long s,long t,GEN P_st,GEN Q_st,GEN d_st, GEN P_ij, GEN lP_ij, GEN dinv) { GEN ind, pols; if (i == s && j == t) { ind = mkvecsmall(1); pols = mkvec(scalarcol_shallow(gen_1, lg(P_st)-1)); /* x^{k-2} */ } else { GEN d_ij, Q_ij = doo_decompose(dinv, lP_ij, &d_ij); GEN a = ZC_Z_mul(P_ij, d_st); GEN b = ZC_Z_mul(P_st, negi(d_ij)); GEN c = RgC_sub(RgC_Rg_mul(Q_ij, d_st), RgC_Rg_mul(Q_st, d_ij)); if (i == s) { /* j != t */ ind = mkvecsmall2(1, s); pols = mkvec2(c, ZC_add(a, b)); } else { ind = mkvecsmall3(1, i, s); pols = mkvec3(c, a, b); /* image of g_1, g_i, g_s */ } pols = Q_primpart(pols); } return mkvec3(mkvecsmall3(i,j,n), ind, pols); } static GEN mskinit_trivial(GEN WN) { long dim = ms_get_nbE1(WN); return mkvec3(WN, gen_0, mkvec2(gen_0,mkvecsmall2(2, dim))); } /* sum of #cols of the matrices contained in V */ static long RgMV_dim(GEN V) { long l = lg(V), d = 0, i; for (i = 1; i < l; i++) d += lg(gel(V,i)) - 1; return d; } static GEN mskinit_nontrivial(GEN WN, long k) { GEN annT2 = gel(WN,8), annT31 = gel(WN,9), singlerel = gel(WN,10); GEN link, basis, monomials, Inv; long nbE1 = ms_get_nbE1(WN); GEN dinv = Delta_inv(ZG_neg( ZSl2_star(gel(singlerel,1)) ), k); GEN p1 = cgetg(nbE1+1, t_VEC), remove; GEN p2 = ZGV_tors(annT2, k); GEN p3 = ZGV_tors(annT31, k); GEN gentor = shallowconcat(p2, p3); GEN P_st, lP_st, Q_st, d_st; long n, i, dim, s, t, u; gel(p1, 1) = cgetg(1,t_MAT); /* dummy */ for (i = 2; i <= nbE1; i++) /* skip 1st element = (\gamma_oo-1)g_oo */ { GEN z = gel(singlerel, i); gel(p1, i) = RgX_act_ZGl2Q(ZSl2_star(z), k); } remove = RgMV_find_non_zero_last_row(nbE1, gentor); if (!remove) remove = RgMV_find_non_zero_last_row(0, p1); if (!remove) pari_err_BUG("msinit [no y^k-2]"); remove = gel(remove,2); /* [s,t] */ s = remove[1]; t = remove[2]; /* +1 because of = x^(k-2), but -1 because of Manin relation */ dim = (k-1)*(nbE1-1) + RgMV_dim(p2) + RgMV_dim(p3); /* Let (g_1,...,g_d) be the Gamma-generators of Delta, g_1 = g_oo. * We describe modular symbols by the collection phi(g_1), ..., phi(g_d) * \in V := Q[x,y]_{k-2}, with right Gamma action. * For each i = 1, .., d, let V_i \subset V be the Q-vector space of * allowed values for phi(g_i): with basis (P^{i,j}) given by the monomials * x^(j-1) y^{k-2-(j-1)}, j = 1 .. k-1 * (g_i in E_1) or the solution of the torsion equations (1 + gamma)P = 0 * (g_i in T2) or (1 + gamma + gamma^2)P = 0 (g_i in T31). All such P * are chosen in Z[x,y] with Q_content 1. * * The Manin relation (singlerel) is of the form \sum_i \lambda_i g_i = 0, * where \lambda_i = 1 if g_i in T2 or T31, and \lambda_i = (1 - \gamma_i) * for g_i in E1. * * If phi \in Hom_Gamma(Delta, V), it is defined by phi(g_i) := P_i in V * with \sum_i P_i . \lambda_i^* = 0, where (\sum n_i g_i)^* := * \sum n_i \gamma_i^(-1). * * We single out gamma_1 / g_1 (g_oo in Pollack-Stevens paper) and * write P_{i,j} \lambda_i^* = Q_{i,j} (\gamma_1 - 1)^* + d_{i,j} y^{k-2} * where d_{i,j} is a scalar and Q_{i,j} in V; we normalize Q_{i,j} to * that the coefficient of x^{k-2} is 0. * * There exist (s,t) such that d_{s,t} != 0. * A Q-basis of the (dual) space of modular symbols is given by the * functions phi_{i,j}, 2 <= i <= d, 1 <= j <= k-1, mapping * g_1 -> d_{s,t} Q_{i,j} - d_{i,j} Q_{s,t} + [(i,j)=(s,t)] x^{k-2} * If i != s * g_i -> d_{s,t} P_{i,j} * g_s -> - d_{i,j} P_{s,t} * If i = s, j != t * g_i -> d_{s,t} P_{i,j} - d_{i,j} P_{s,t} * And everything else to 0. Again we normalize the phi_{i,j} such that * their image has content 1. */ monomials = matid(k-1); /* represent the monomials x^{k-2}, ... , y^{k-2} */ if (s <= nbE1) /* in E1 */ { P_st = gel(monomials, t); lP_st = gmael(p1, s, t); /* P_{s,t} lambda_s^* */ } else /* in T2, T31 */ { P_st = gmael(gentor, s - nbE1, t); lP_st = P_st; } Q_st = doo_decompose(dinv, lP_st, &d_st); basis = cgetg(dim+1, t_VEC); link = cgetg(nbE1 + lg(gentor), t_VEC); gel(link,1) = cgetg(1,t_VECSMALL); /* dummy */ n = 1; for (i = 2; i <= nbE1; i++) { GEN L = cgetg(k, t_VECSMALL); long j; /* link[i][j] = n gives correspondance between phi_{i,j} and basis[n] */ gel(link,i) = L; for (j = 1; j < k; j++) { GEN lP_ij = gmael(p1, i, j); /* P_{i,j} lambda_i^* */ GEN P_ij = gel(monomials,j); L[j] = n; gel(basis, n) = get_phi_ij(i,j,n, s,t, P_st, Q_st, d_st, P_ij, lP_ij, dinv); n++; } } for (u = 1; u < lg(gentor); u++,i++) { GEN V = gel(gentor,u); long j, lV = lg(V); GEN L = cgetg(lV, t_VECSMALL); gel(link,i) = L; for (j = 1; j < lV; j++) { GEN lP_ij = gel(V, j); /* P_{i,j} lambda_i^* = P_{i,j} */ GEN P_ij = lP_ij; L[j] = n; gel(basis, n) = get_phi_ij(i,j,n, s,t, P_st, Q_st, d_st, P_ij, lP_ij, dinv); n++; } } Inv = cgetg(lg(link), t_VEC); gel(Inv,1) = cgetg(1, t_MAT); /* dummy */ for (i = 2; i < lg(link); i++) { GEN M, inv, B = gel(link,i); long j, lB = lg(B); if (i == s) { B = vecsplice(B, t); lB--; } /* remove phi_st */ M = cgetg(lB, t_MAT); for (j = 1; j < lB; j++) { GEN phi_ij = gel(basis, B[j]), pols = gel(phi_ij,3); gel(M, j) = gel(pols, 2); /* phi_ij(g_i) */ } if (i <= nbE1 && i != s) /* maximal rank k-1 */ inv = ZM_inv_denom(M); else /* i = s (rank k-2) or from torsion: rank k/3 or k/2 */ inv = Qevproj_init(M); gel(Inv,i) = inv; } return mkvec3(WN, gen_0, mkvec5(basis, mkvecsmall2(k, dim), mkvecsmall2(s,t), link, Inv)); } static GEN add_star(GEN W, long sign) { GEN s = msstar_i(W); GEN K = sign? QM_ker_r(gsubgs(s, sign)): cgetg(1,t_MAT); gel(W,2) = mkvec3(stoi(sign), s, Qevproj_init(K)); return W; } /* WN = msinit_N(N) */ static GEN mskinit(ulong N, long k, long sign) { GEN W, WN = msinit_N(N); if (N == 1) { GEN basis, M = RgXV_to_RgM(mfperiodpolbasis(k, 0), k-1); GEN T = cgetg(1, t_VECSMALL), ind = mkvecsmall(1); long i, l = lg(M); basis = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(basis,i) = mkvec3(T, ind, mkvec(gel(M,i))); W = mkvec3(WN, gen_0, mkvec5(basis, mkvecsmall2(k, l-1), mkvecsmall2(0,0), gen_0, Qevproj_init(M))); } else W = k == 2? mskinit_trivial(WN) : mskinit_nontrivial(WN, k); return add_star(W, sign); } GEN msinit(GEN N, GEN K, long sign) { pari_sp av = avma; GEN W; long k; if (typ(N) != t_INT) pari_err_TYPE("msinit", N); if (typ(K) != t_INT) pari_err_TYPE("msinit", K); k = itos(K); if (k < 2) pari_err_DOMAIN("msinit","k", "<", gen_2,K); if (odd(k)) pari_err_IMPL("msinit [odd weight]"); if (signe(N) <= 0) pari_err_DOMAIN("msinit","N", "<=", gen_0,N); W = mskinit(itou(N), k, sign); return gerepilecopy(av, W); } /* W = msinit, xpm integral modular symbol of weight 2, c t_FRAC * Return image of c> */ static GEN Q_xpm(GEN W, GEN xpm, GEN c) { pari_sp av = avma; GEN v; W = get_msN(W); v = init_act_trivial(W); Q_log_trivial(v, W, c); /* oo -> (a:b), c = a/b */ return gerepileuptoint(av, ZV_zc_mul(xpm, v)); } static GEN eval_single(GEN s, long k, GEN B, long v) { long i, l; GEN A = cgetg_copy(s,&l); for (i=1; i 0? 2: 1; } /* E minimal */ static GEN ellperiod(GEN E, long s) { GEN w = ellR_omega(E,DEFAULTPREC); if (s == 1) w = gel(w,1); else if (nb_components(E) == 2) w = gneg(gel(w,2)); else w = mkcomplex(gen_0, gneg(gmul2n(imag_i(gel(w,2)), 1))); return w; } /* Let W = msinit(conductor(E), 2), xpm an integral modular symbol with the same * eigenvalues as L_E. There exist a unique C such that * C*L(E,(D/.),1)_{xpm} = L(E,(D/.),1) / w1(E_D) != 0, for all D fundamental, * sign(D) = s, and such that E_D has rank 0. Return C * ellperiod(E,s) */ static GEN ell_get_Cw(GEN LE, GEN W, GEN xpm, long s) { long f, NE = ms_get_N(W); const long bit = 64; for (f = 1;; f++) { /* look for chi with conductor f coprime to N(E) and parity s * such that L(E,chi,1) != 0 */ pari_sp av = avma; GEN vchi, vx, G; long l, i; if ((f & 3) == 2 || ugcd(NE,f) != 1) continue; vx = allxpm(W, xpm, f); if (!vx) continue; G = znstar0(utoipos(f),1); vchi = chargalois(G,NULL); l = lg(vchi); for (i = 1; i < l; i++) { pari_sp av2 = avma; GEN tau, z, S, L, chi = gel(vchi,i); long o = zncharisodd(G,chi); if ((s > 0 && o) || (s < 0 && !o) || itos(zncharconductor(G, chi)) != f) continue; S = seval(G, chi, vx); if (!S) { avma = av2; continue; } L = lfuntwist(LE, mkvec2(G, zncharconj(G,chi))); z = lfun(L, gen_1, bit); tau = znchargauss(G, chi, gen_1, bit); return gdiv(gmul(z, tau), S); /* C * w */ } avma = av; } } static GEN ell_get_scale(GEN LE, GEN W, long sign, GEN x) { if (sign) return ell_get_Cw(LE, W, gel(x,1), sign); else { GEN Cwp = ell_get_Cw(LE, W, gel(x,1), 1); GEN Cwm = ell_get_Cw(LE, W, gel(x,2),-1); return mkvec2(Cwp, Cwm); } } /* E minimal */ static GEN msfromell_scale(GEN x, GEN Cw, GEN E, long s) { GEN B = int2n(32); if (s) { GEN C = gdiv(Cw, ellperiod(E,s)); return ZC_Q_mul(gel(x,1), bestappr(C,B)); } else { GEN xp = gel(x,1), Cp = gdiv(gel(Cw,1), ellperiod(E, 1)), L; GEN xm = gel(x,2), Cm = gdiv(gel(Cw,2), ellperiod(E,-1)); xp = ZC_Q_mul(xp, bestappr(Cp,B)); xm = ZC_Q_mul(xm, bestappr(Cm,B)); if (signe(ell_get_disc(E)) > 0) L = mkmat2(xp, xm); /* E(R) has 2 connected components */ else L = mkmat2(gsub(xp,xm), gmul2n(xm,1)); return mkvec3(xp, xm, L); } } /* v != 0 */ static GEN Flc_normalize(GEN v, ulong p) { long i, l = lg(v); for (i = 1; i < l; i++) if (v[i]) { if (v[i] != 1) v = Flv_Fl_div(v, v[i], p); return v; } return NULL; } /* K \cap Ker M [F_l vector spaces]. K = NULL means full space */ static GEN msfromell_ker(GEN K, GEN M, ulong l) { GEN B, Ml = ZM_to_Flm(M, l); if (K) Ml = Flm_mul(Ml, K, l); B = Flm_ker(Ml, l); if (!K) K = B; else if (lg(B) < lg(K)) K = Flm_mul(K, B, l); return K; } /* K = \cap_p Ker(T_p - a_p), 2-dimensional. Set *xl to the 1-dimensional * Fl-basis such that star . xl = sign . xl if sign != 0 and * star * xl[1] = xl[1]; star * xl[2] = -xl[2] if sign = 0 */ static void msfromell_l(GEN *pxl, GEN K, GEN star, long sign, ulong l) { GEN s = ZM_to_Flm(star, l); GEN a = gel(K,1), Sa = Flm_Flc_mul(s,a,l); GEN b = gel(K,2); GEN t = Flv_add(a,Sa,l), xp, xm; if (zv_equal0(t)) { xm = a; xp = Flv_add(b,Flm_Flc_mul(s,b,l), l); } else { xp = t; t = Flv_sub(a, Sa, l); xm = zv_equal0(t)? Flv_sub(b, Flm_Flc_mul(s,b,l), l): t; } /* xp = 0 on Im(S - 1), xm = 0 on Im(S + 1) */ if (sign > 0) *pxl = mkmat(Flc_normalize(xp, l)); else if (sign < 0) *pxl = mkmat(Flc_normalize(xm, l)); else *pxl = mkmat2(Flc_normalize(xp, l), Flc_normalize(xm, l)); } /* return a primitive symbol */ static GEN msfromell_ratlift(GEN x, GEN q) { GEN B = sqrti(shifti(q,-1)); GEN r = FpM_ratlift(x, q, B, B, NULL); if (r) r = Q_primpart(r); return r; } static int msfromell_check(GEN x, GEN vT, GEN star, long sign) { long i, l; GEN sx; if (!x) return 0; l = lg(vT); for (i = 1; i < l; i++) { GEN T = gel(vT,i); if (!gequal0(ZM_mul(T, x))) return 0; /* fail */ } sx = ZM_mul(star,x); if (sign) return ZV_equal(gel(sx,1), sign > 0? gel(x,1): ZC_neg(gel(x,1))); else return ZV_equal(gel(sx,1),gel(x,1)) && ZV_equal(gel(sx,2),ZC_neg(gel(x,2))); } GEN msfromell(GEN E0, long sign) { pari_sp av = avma, av2; GEN T, Cw, E, NE, star, q, vT, xl, xr, W, x = NULL, K = NULL; long lE, single; ulong p, l, N; forprime_t S, Sl; if (typ(E0) != t_VEC) pari_err_TYPE("msfromell",E0); lE = lg(E0); if (lE == 1) return cgetg(1,t_VEC); single = (typ(gel(E0,1)) != t_VEC); E = single ? E0: gel(E0,1); NE = ellQ_get_N(E); /* must make it integral for ellap; we have minimal model at hand */ T = obj_check(E, Q_MINIMALMODEL); if (lg(T) != 2) E = gel(T,3); N = itou(NE); av2 = avma; W = gerepilecopy(av2, mskinit(N,2,0)); star = msk_get_star(W); init_modular_small(&Sl); /* loop for p <= count_Manin_symbols(N) / 6 would be enough */ (void)u_forprime_init(&S, 2, ULONG_MAX); vT = cgetg(1, t_VEC); l = u_forprime_next(&Sl); while( (p = u_forprime_next(&S)) ) { GEN M; if (N % p == 0) continue; av2 = avma; M = RgM_Rg_sub_shallow(mshecke_i(W, p), ellap(E, utoipos(p))); M = gerepilecopy(av2, M); vT = shallowconcat(vT, mkvec(M)); /* for certification at the end */ K = msfromell_ker(K, M, l); if (lg(K) == 3) break; } if (!p) pari_err_BUG("msfromell: ran out of primes"); /* mod one l should be enough */ msfromell_l(&xl, K, star, sign, l); x = ZM_init_CRT(xl, l); q = utoipos(l); xr = msfromell_ratlift(x, q); /* paranoia */ while (!msfromell_check(xr, vT, star, sign) && (l = u_forprime_next(&Sl)) ) { GEN K = NULL; long i, lvT = lg(vT); for (i = 1; i < lvT; i++) { K = msfromell_ker(K, gel(vT,i), l); if (lg(K) == 3) break; } if (i >= lvT) { x = NULL; continue; } msfromell_l(&xl, K, star, sign, l); ZM_incremental_CRT(&x, xl, &q, l); xr = msfromell_ratlift(x, q); } /* linear form = 0 on all Im(Tp - ap) and Im(S - sign) if sign != 0 */ Cw = ell_get_scale(lfuncreate(E), W, sign, xr); if (single) x = msfromell_scale(xr, Cw, E, sign); else { /* assume all E0[i] isogenous, given by minimal models */ GEN v = cgetg(lE, t_VEC); long i; for (i=1; ik, D = S->dim; GEN a = gcoeff(f,1,1), b = gcoeff(f,1,2); GEN c = gcoeff(f,2,1), d = gcoeff(f,2,2); GEN u, z, q = S->q, mat = cgetg(D+1, t_MAT); a = modii(a,q); c = modii(c,q); z = FpX_powu(deg1pol(c,a,0), k-2, q); /* (a+cx)^(k-2) */ /* u := (b+dx) / (a+cx) mod (q,x^D) = (b/a +d/a*x) / (1 - (-c/a)*x) */ if (!equali1(a)) { GEN ai = Fp_inv(a,q); b = Fp_mul(b,ai,q); c = Fp_mul(c,ai,q); d = Fp_mul(d,ai,q); } u = deg1pol_shallow(d, b, 0); /* multiply by 1 / (1 - (-c/a)*x) */ if (signe(c)) { GEN C = Fp_neg(c,q), v = cgetg(D+2,t_POL); v[1] = evalsigne(1)|evalvarn(0); gel(v, 2) = gen_1; gel(v, 3) = C; for (j = 4; j < D+2; j++) { GEN t = Fp_mul(gel(v,j-1), C, q); if (!signe(t)) { setlg(v,j); break; } gel(v,j) = t; } u = FpXn_mul(u, v, D, q); } for (j = 1; j <= D; j++) { gel(mat,j) = RgX_to_RgC(z, D); /* (a+cx)^(k-2) * ((b+dx)/(a+cx))^(j-1) */ if (j != D) z = FpXn_mul(z, u, D, q); } return shallowtrans(mat); } static GEN moments_act(struct m_act *S, GEN f) { pari_sp av = avma; return gerepilecopy(av, moments_act_i(S,f)); } static GEN init_moments_act(GEN W, long p, long n, GEN q, GEN v) { struct m_act S; long k = msk_get_weight(W); S.p = p; S.k = k; S.q = q; S.dim = n+k-1; S.act = &moments_act; return init_dual_act(v,W,W,&S); } static void clean_tail(GEN phi, long c, GEN q) { long a, l = lg(phi); for (a = 1; a < l; a++) { GEN P = FpV_red(gel(phi,a), q); /* phi(G_a) = vector of moments */ long j, lP = lg(P); for (j = c; j < lP; j++) gel(P,j) = gen_0; /* reset garbage to 0 */ gel(phi,a) = P; } } /* concat z to all phi[i] */ static GEN concat2(GEN phi, GEN z) { long i, l; GEN v = cgetg_copy(phi,&l); for (i = 1; i < l; i++) gel(v,i) = shallowconcat(gel(phi,i), z); return v; } static GEN red_mod_FilM(GEN phi, ulong p, long k, long flag) { long a, l; GEN den = gen_1, v = cgetg_copy(phi, &l); if (flag) { phi = Q_remove_denom(phi, &den); if (!den) { den = gen_1; flag = 0; } } for (a = 1; a < l; a++) { GEN P = gel(phi,a), q = den; long j; for (j = lg(P)-1; j >= k+1; j--) { q = muliu(q,p); gel(P,j) = modii(gel(P,j),q); } q = muliu(q,p); for ( ; j >= 1; j--) gel(P,j) = modii(gel(P,j),q); gel(v,a) = P; } if (flag) v = gdiv(v, den); return v; } /* denom(C) | p^(2(k-1) - v_p(ap)) */ static GEN oms_dim2(GEN W, GEN phi, GEN C, GEN ap) { long t, i, k = mspadic_get_weight(W); long p = mspadic_get_p(W), n = mspadic_get_n(W); GEN phi1 = gel(phi,1), phi2 = gel(phi,2); GEN v, q = mspadic_get_q(W); GEN act = mspadic_get_actUp(W); t = signe(ap)? Z_lval(ap,p) : k-1; phi1 = concat2(phi1, zerovec(n)); phi2 = concat2(phi2, zerovec(n)); for (i = 1; i <= n; i++) { phi1 = dual_act(k-1, act, phi1); phi1 = dual_act(k-1, act, phi1); clean_tail(phi1, k + i*t, q); phi2 = dual_act(k-1, act, phi2); phi2 = dual_act(k-1, act, phi2); clean_tail(phi2, k + i*t, q); } C = gpowgs(C,n); v = RgM_RgC_mul(C, mkcol2(phi1,phi2)); phi1 = red_mod_FilM(gel(v,1), p, k, 1); phi2 = red_mod_FilM(gel(v,2), p, k, 1); return mkvec2(phi1,phi2); } /* flag = 0 iff alpha is a p-unit */ static GEN oms_dim1(GEN W, GEN phi, GEN alpha, long flag) { long i, k = mspadic_get_weight(W); long p = mspadic_get_p(W), n = mspadic_get_n(W); GEN q = mspadic_get_q(W); GEN act = mspadic_get_actUp(W); phi = concat2(phi, zerovec(n)); for (i = 1; i <= n; i++) { phi = dual_act(k-1, act, phi); clean_tail(phi, k + i, q); } phi = gmul(lift_shallow(gpowgs(alpha,n)), phi); phi = red_mod_FilM(phi, p, k, flag); return mkvec(phi); } /* lift polynomial P in RgX[X,Y]_{k-2} to a distribution \mu such that * \int (Y - X z)^(k-2) d\mu(z) = P(X,Y) * Return the t_VEC of k-1 first moments of \mu: \int z^i d\mu(z), 0<= i < k-1. * \sum_j (-1)^(k-2-j) binomial(k-2,j) Y^j \int z^(k-2-j) d\mu(z) = P(1,Y) * Input is P(1,Y), bin = vecbinomial(k-2): bin[j] = binomial(k-2,j-1) */ static GEN RgX_to_moments(GEN P, GEN bin) { long j, k = lg(bin); GEN Pd, Bd; if (typ(P) != t_POL) P = scalarpol(P,0); P = RgX_to_RgC(P, k-1); /* deg <= k-2 */ settyp(P, t_VEC); Pd = P+1; /* Pd[i] = coeff(P,i) */ Bd = bin+1;/* Bd[i] = binomial(k-2,i) */ for (j = 1; j < k-2; j++) { GEN c = gel(Pd,j); if (odd(j)) c = gneg(c); gel(Pd,j) = gdiv(c, gel(Bd,j)); } return vecreverse(P); } static GEN RgXC_to_moments(GEN v, GEN bin) { long i, l; GEN w = cgetg_copy(v,&l); for (i=1; iq): zerocol(S->dim); } return v; } GEN msomseval(GEN W, GEN phi, GEN path) { struct m_act S; pari_sp av = avma; GEN v, Wp; long n, vden; checkmspadic(W); if (typ(phi) != t_COL || lg(phi) != 4) pari_err_TYPE("msomseval",phi); vden = itos(gel(phi,2)); phi = gel(phi,1); n = mspadic_get_n(W); Wp= mspadic_get_Wp(W); S.k = mspadic_get_weight(W); S.p = mspadic_get_p(W); S.q = powuu(S.p, n+vden); S.dim = n + S.k - 1; S.act = &moments_act; path = path_to_M2(path); v = omseval_int(&S, phi, M2_logf(Wp,path,NULL), NULL); return gerepilecopy(av, v); } /* W = msinit(N,k,...); if flag < 0 or flag >= k-1, allow all symbols; * else commit to v_p(a_p) <= flag (ordinary if flag = 0)*/ GEN mspadicinit(GEN W, long p, long n, long flag) { pari_sp av = avma; long a, N, k; GEN P, C, M, bin, Wp, Tp, q, pn, actUp, teich, pas; checkms(W); N = ms_get_N(W); k = msk_get_weight(W); if (flag < 0) flag = 1; /* worst case */ else if (flag >= k) flag = k-1; bin = vecbinomial(k-2); Tp = mshecke(W, p, NULL); if (N % p == 0) { if ((N/p) % p == 0) pari_err_IMPL("mspadicinit when p^2 | N"); /* a_p != 0 */ Wp = W; M = gen_0; flag = (k-2) / 2; /* exact valuation */ /* will multiply by matrix with denominator p^(k-2)/2 in mspadicint. * Except if p = 2 (multiply by alpha^2) */ if (p == 2) n += k-2; else n += (k-2)/2; pn = powuu(p,n); /* For accuracy mod p^n, oms_dim1 require p^(k/2*n) */ q = powiu(pn, k/2); } else { /* p-stabilize */ long s = msk_get_sign(W); GEN M1, M2; Wp = mskinit(N*p, k, s); M1 = getMorphism(W, Wp, mkvec(mat2(1,0,0,1))); M2 = getMorphism(W, Wp, mkvec(mat2(p,0,0,1))); if (s) { GEN SW = msk_get_starproj(W), SWp = msk_get_starproj(Wp); M1 = Qevproj_apply2(M1, SW, SWp); M2 = Qevproj_apply2(M2, SW, SWp); } M = mkvec2(M1,M2); n += Z_lval(Q_denom(M), p); /*den. introduced by p-stabilization*/ /* in supersingular case: will multiply by matrix with denominator p^k * in mspadicint. Except if p = 2 (multiply by alpha^2) */ if (flag) { if (p == 2) n += 2*k-2; else n += k; } pn = powuu(p,n); /* For accuracy mod p^n, supersingular require p^((2k-1-v_p(a_p))*n) */ if (flag) /* k-1 also takes care of a_p = 0. Worst case v_p(a_p) = flag */ q = powiu(pn, 2*k-1 - flag); else q = pn; } actUp = init_moments_act(Wp, p, n, q, Up_matrices(p)); if (p == 2) C = gen_0; else { pas = matpascal(n); teich = teichmullerinit(p, n+1); P = gpowers(utoipos(p), n); C = cgetg(p, t_VEC); for (a = 1; a < p; a++) { /* powb[j+1] = ((a - w(a)) / p)^j mod p^n */ GEN powb = Fp_powers(diviuexact(subui(a, gel(teich,a)), p), n, pn); GEN Ca = cgetg(n+2, t_VEC); long j, r, ai = Fl_inv(a, p); /* a^(-1) */ gel(C,a) = Ca; for (j = 0; j <= n; j++) { GEN Caj = cgetg(j+2, t_VEC); GEN atij = gel(teich, Fl_powu(ai,j,p));/* w(a)^(-j) = w(a^(-j) mod p) */ gel(Ca,j+1) = Caj; for (r = 0; r <= j; r++) { GEN c = Fp_mul(gcoeff(pas,j+1,r+1), gel(powb, j-r+1), pn); c = Fp_mul(c,atij,pn); /* binomial(j,r)*b^(j-r)*w(a)^(-j) mod p^n */ gel(Caj,r+1) = mulii(c, gel(P,j+1)); /* p^j * c mod p^(n+j) */ } } } } return gerepilecopy(av, mkvecn(8, Wp,Tp, bin, actUp, q, mkvecsmall3(p,n,flag), M, C)); } #if 0 /* assume phi an ordinary OMS */ static GEN omsactgl2(GEN W, GEN phi, GEN M) { GEN q, Wp, act; long p, k, n; checkmspadic(W); Wp = mspadic_get_Wp(W); p = mspadic_get_p(W); k = mspadic_get_weight(W); n = mspadic_get_n(W); q = mspadic_get_q(W); act = init_moments_act(Wp, p, n, q, M); phi = gel(phi,1); return dual_act(k-1, act, gel(phi,1)); } #endif static GEN eigenvalue(GEN T, GEN x) { long i, l = lg(x); for (i = 1; i < l; i++) if (!isintzero(gel(x,i))) break; if (i == l) pari_err_DOMAIN("mstooms", "phi", "=", gen_0, x); return gdiv(RgMrow_RgC_mul(T,x,i), gel(x,i)); } /* p coprime to ap, return unit root of x^2 - ap*x + p^(k-1), accuracy p^n */ GEN mspadic_unit_eigenvalue(GEN ap, long k, GEN p, long n) { GEN sqrtD, D = subii(sqri(ap), shifti(powiu(p,k-1),2)); if (absequaliu(p,2)) { n++; sqrtD = Zp_sqrt(D, p, n); if (mod4(sqrtD) != mod4(ap)) sqrtD = negi(sqrtD); } else sqrtD = Zp_sqrtlift(D, ap, p, n); /* sqrtD = ap (mod p) */ return gmul2n(gadd(ap, cvtop(sqrtD,p,n)), -1); } /* W = msinit(N,k,...); phi = T_p/U_p - eigensymbol */ GEN mstooms(GEN W, GEN phi) { pari_sp av = avma; GEN Wp, bin, Tp, c, alpha, ap, phi0, M; long k, p, vden; checkmspadic(W); if (typ(phi) != t_COL) { if (!is_Qevproj(phi)) pari_err_TYPE("mstooms",phi); phi = gel(phi,1); if (lg(phi) != 2) pari_err_TYPE("mstooms [dim_Q (eigenspace) > 1]",phi); phi = gel(phi,1); } Wp = mspadic_get_Wp(W); Tp = mspadic_get_Tp(W); bin = mspadic_get_bin(W); k = msk_get_weight(Wp); p = mspadic_get_p(W); M = mspadic_get_M(W); phi = Q_remove_denom(phi, &c); ap = eigenvalue(Tp, phi); vden = c? Z_lvalrem(c, p, &c): 0; if (typ(M) == t_INT) { /* p | N */ GEN c1; alpha = ap; alpha = ginv(alpha); phi0 = mseval(Wp, phi, NULL); phi0 = RgXC_to_moments(phi0, bin); phi0 = Q_remove_denom(phi0, &c1); if (c1) { vden += Z_lvalrem(c1, p, &c1); c = mul_denom(c,c1); } if (umodiu(ap,p)) /* p \nmid a_p */ phi = oms_dim1(W, phi0, alpha, 0); else { phi = oms_dim1(W, phi0, alpha, 1); phi = Q_remove_denom(phi, &c1); if (c1) { vden += Z_lvalrem(c1, p, &c1); c = mul_denom(c,c1); } } } else { /* p-stabilize */ GEN M1, M2, phi1, phi2, c1; if (typ(M) != t_VEC || lg(M) != 3) pari_err_TYPE("mstooms",W); M1 = gel(M,1); M2 = gel(M,2); phi1 = RgM_RgC_mul(M1, phi); phi2 = RgM_RgC_mul(M2, phi); phi1 = mseval(Wp, phi1, NULL); phi2 = mseval(Wp, phi2, NULL); phi1 = RgXC_to_moments(phi1, bin); phi2 = RgXC_to_moments(phi2, bin); phi = Q_remove_denom(mkvec2(phi1,phi2), &c1); phi1 = gel(phi,1); phi2 = gel(phi,2); if (c1) { vden += Z_lvalrem(c1, p, &c1); c = mul_denom(c,c1); } /* all polynomials multiplied by c p^vden */ if (umodiu(ap, p)) { alpha = mspadic_unit_eigenvalue(ap, k, utoipos(p), mspadic_get_n(W)); alpha = ginv(alpha); phi0 = gsub(phi1, gmul(lift_shallow(alpha),phi2)); phi = oms_dim1(W, phi0, alpha, 0); } else { /* p | ap, alpha = [a_p, -1; p^(k-1), 0] */ long flag = mspadic_get_flag(W); if (!flag || (signe(ap) && Z_lval(ap,p) < flag)) pari_err_TYPE("mstooms [v_p(ap) > mspadicinit flag]", phi); alpha = mkmat22(ap,gen_m1, powuu(p, k-1),gen_0); alpha = ginv(alpha); phi = oms_dim2(W, mkvec2(phi1,phi2), gsqr(alpha), ap); phi = Q_remove_denom(phi, &c1); if (c1) { vden += Z_lvalrem(c1, p, &c1); c = mul_denom(c,c1); } } } if (vden) c = mul_denom(c, powuu(p,vden)); if (p == 2) alpha = gsqr(alpha); if (c) alpha = gdiv(alpha,c); if (typ(alpha) == t_MAT) { /* express in basis (omega,-p phi(omega)) */ gcoeff(alpha,2,1) = gdivgs(gcoeff(alpha,2,1), -p); gcoeff(alpha,2,2) = gdivgs(gcoeff(alpha,2,2), -p); /* at the end of mspadicint we shall multiply result by [1,0;0,-1/p]*alpha * vden + k is the denominator of this matrix */ } /* phi is integral-valued */ return gerepilecopy(av, mkcol3(phi, stoi(vden), alpha)); } /* HACK: the v[j] have different lengths */ static GEN FpVV_dotproduct(GEN v, GEN w, GEN p) { long j, l = lg(v); GEN T = cgetg(l, t_VEC); for (j = 1; j < l; j++) gel(T,j) = FpV_dotproduct(gel(v,j),w,p); return T; } /* \int (-4z)^j given \int z^j */ static GEN twistmoment_m4(GEN v) { long i, l; GEN w = cgetg_copy(v, &l); for (i = 1; i < l; i++) { GEN c = gel(v,i); if (i > 1) c = gmul2n(c, (i-1)<<1); gel(w,i) = odd(i)? c: gneg(c); } return w; } /* \int (4z)^j given \int z^j */ static GEN twistmoment_4(GEN v) { long i, l; GEN w = cgetg_copy(v, &l); for (i = 1; i < l; i++) { GEN c = gel(v,i); if (i > 1) c = gmul2n(c, (i-1)<<1); gel(w,i) = c; } return w; } /* W an mspadic, phi eigensymbol, p \nmid D. Return C(x) mod FilM */ GEN mspadicmoments(GEN W, GEN PHI, long D) { pari_sp av = avma; long na, ia, b, lphi, aD = labs(D), pp, p, k, n, vden; GEN Wp, Dact, vL, v, C, pn, phi; struct m_act S; hashtable *H; checkmspadic(W); Wp = mspadic_get_Wp(W); p = mspadic_get_p(W); k = mspadic_get_weight(W); n = mspadic_get_n(W); C = mspadic_get_C(W); if (typ(PHI) != t_COL || lg(PHI) != 4 || typ(gel(PHI,1)) != t_VEC) PHI = mstooms(W, PHI); vden = itos( gel(PHI,2) ); phi = gel(PHI,1); lphi = lg(phi); if (p == 2) { na = 2; pp = 4; } else { na = p-1; pp = p; } pn = powuu(p, n + vden); S.p = p; S.k = k; S.q = pn; S.dim = n+k-1; S.act = &moments_act; H = Gl2act_cache(ms_get_nbgen(Wp)); if (D == 1) Dact = NULL; else { GEN gaD = utoi(aD), Dk = Fp_pows(stoi(D), 2-k, pn); if (!sisfundamental(D)) pari_err_TYPE("mspadicmoments", stoi(D)); if (D % p == 0) pari_err_DOMAIN("mspadicmoments","p","|", stoi(D), utoi(p)); Dact = cgetg(aD, t_VEC); for (b = 1; b < aD; b++) { GEN z = NULL; long s = kross(D, b); if (s) { pari_sp av2 = avma; GEN d; z = moments_act_i(&S, mkmat22(gaD,utoipos(b), gen_0,gaD)); d = s > 0? Dk: Fp_neg(Dk, pn); z = equali1(d)? gerepilecopy(av2, z) : gerepileupto(av2, FpM_Fp_mul(z, d, pn)); } gel(Dact,b) = z; } } vL = cgetg(na+1,t_VEC); /* first pass to precompute log(paths), preload matrices and allow GC later */ for (ia = 1; ia <= na; ia++) { GEN path, La; long a = (p == 2 && ia == 2)? -1: ia; if (Dact) { /* twist by D */ La = cgetg(aD, t_VEC); for (b = 1; b < aD; b++) { GEN Actb = gel(Dact,b); if (!Actb) continue; /* oo -> a/pp + b/|D|*/ path = mkmat22(gen_1, addii(mulss(a, aD), muluu(pp, b)), gen_0, muluu(pp, aD)); gel(La,b) = M2_logf(Wp,path,NULL); ZGl2QC_preload(&S, gel(La,b), H); } } else { path = mkmat22(gen_1,stoi(a), gen_0, utoipos(pp)); La = M2_logf(Wp,path,NULL); ZGl2QC_preload(&S, La, H); } gel(vL,ia) = La; } v = cgetg(na+1,t_VEC); /* second pass, with GC */ for (ia = 1; ia <= na; ia++) { pari_sp av2 = avma; GEN vca, Ca = gel(C,ia), La = gel(vL,ia), va = cgetg(lphi, t_VEC); long i; if (!Dact) vca = omseval_int(&S, phi, La, H); else { /* twist by D */ vca = cgetg(lphi,t_VEC); for (b = 1; b < aD; b++) { GEN T, Actb = gel(Dact,b); if (!Actb) continue; T = omseval_int(&S, phi, gel(La,b), H); for (i = 1; i < lphi; i++) { GEN z = FpM_FpC_mul(Actb, gel(T,i), pn); gel(vca,i) = b==1? z: ZC_add(gel(vca,i), z); } } } if (p != 2) { for (i=1; i= n) break; /* S = log(1+x)^j */ gel(vlog,j+1) = mspadicint(oms,teichi,S); S = S? RgXn_mul(S, L, n+1): L; } m = j; u = utoipos(p == 2? 5: 1+p); logu = glog(cvtop(u, utoipos(p), 4*m), 0); X = gdiv(pol_x(0), logu); s = cgetg(m+1, t_VEC); s2 = oms_is_supersingular(oms)? cgetg(m+1, t_VEC): NULL; bin = pol_1(0); for (j = 0; j < m; j++) { /* bin = binomial(x/log(1+p+O(p^(4*n))), j) mod x^m */ GEN a, v = mspadicint_RgXlog(bin, vlog); int done = 1; gel(s,j+1) = a = gel(v,1); if (!gequal0(a) || valp(a) > 0) done = 0; else setlg(s,j+1); if (s2) { gel(s2,j+1) = a = gel(v,2); if (!gequal0(a) || valp(a) > 0) done = 0; else setlg(s2,j+1); } if (done || j == m-1) break; bin = RgXn_mul(bin, gdivgs(gsubgs(X, j), j+1), m); } s = RgV_to_ser(s,0,lg(s)+1); if (s2) { s2 = RgV_to_ser(s2,0,lg(s2)+1); s = mkvec2(s, s2); } if (kross(oms_get_D(oms), p) >= 0) return gerepilecopy(av, s); return gerepileupto(av, gneg(s)); } void mspadic_parse_chi(GEN s, GEN *s1, GEN *s2) { if (!s) *s1 = *s2 = gen_0; else switch(typ(s)) { case t_INT: *s1 = *s2 = s; break; case t_VEC: if (lg(s) == 3) { *s1 = gel(s,1); *s2 = gel(s,2); if (typ(*s1) == t_INT && typ(*s2) == t_INT) break; } default: pari_err_TYPE("mspadicL",s); *s1 = *s2 = NULL; } } /* oms from mspadicmoments * r-th derivative of L(f,chi^s,psi) in direction - s \in Z_p \times \Z/(p-1)\Z, s-> chi^s=<\chi>^s_1 omega^s_2) - Z -> Z_p \times \Z/(p-1)\Z par s-> (s, s mod p-1). */ GEN mspadicL(GEN oms, GEN s, long r) { pari_sp av = avma; GEN s1, s2, z, S; long p, n, teich; checkoms(oms); p = oms_get_p(oms); n = oms_get_n(oms); mspadic_parse_chi(s, &s1,&s2); teich = umodiu(subii(s2,s1), p==2? 2: p-1); S = xlog1x(n, itos(s1), r, &teich); z = mspadicint(oms, teich, S); if (lg(z) == 2) z = gel(z,1); if (kross(oms_get_D(oms), p) < 0) z = gneg(z); return gerepilecopy(av, z); } /****************************************************************************/ struct siegel { GEN V, Ast; long N; /* level */ long oo; /* index of the [oo,0] path */ long k1, k2; /* two distinguished indices */ long n; /* #W, W = initial segment [in siegelstepC] already normalized */ }; static void siegel_init(struct siegel *C, GEN M) { GEN CPI, CP, MM, V, W, Ast; GEN m = gel(M,11), M2 = gel(M,2), S = msN_get_section(M); GEN E2fromE1 = msN_get_E2fromE1(M); long m0 = lg(M2)-1; GEN E2 = vecslice(M2, m[1]+1, m[2]);/* E2 */ GEN E1T = vecslice(M2, m[3]+1, m0); /* E1,T2,T31 */ GEN L = shallowconcat(E1T, E2); long i, l = lg(L), n = lg(E1T)-1, lE = lg(E2); Ast = cgetg(l, t_VECSMALL); for (i = 1; i < lE; ++i) { long j = E2fromE1_c(gel(E2fromE1,i)); Ast[n+i] = j; Ast[j] = n+i; } for (; i<=n; ++i) Ast[i] = i; MM = cgetg (l,t_VEC); for (i = 1; i < l; i++) { GEN c = gel(S, L[i]); long c12, c22, c21 = ucoeff(c,2,1); if (!c21) { gel(MM,i) = gen_0; continue; } c22 = ucoeff(c,2,2); if (!c22) { gel(MM,i) = gen_m1; continue; } c12 = ucoeff(c,1,2); gel(MM,i) = gdivgs(stoi(c12), c22); /* right extremity > 0 */ } CP = indexsort(MM); CPI = cgetg(l, t_VECSMALL); V = cgetg(l, t_VEC); W = cgetg(l, t_VECSMALL); for (i = 1; i < l; ++i) { gel(V,i) = mat2_to_ZM(gel(S, L[CP[i]])); CPI[CP[i]] = i; } for (i = 1; i < l; ++i) W[CPI[i]] = CPI[Ast[i]]; C->V = V; C->Ast = W; C->n = 0; C->oo = 2; C->N = ms_get_N(M); } static double ZMV_size(GEN v) { long i, l = lg(v); GEN z = cgetg(l, t_VECSMALL); for (i = 1; i < l; i++) z[i] = gexpo(gel(v,i)); return ((double)zv_sum(z)) / (4*(l-1)); } /* apply permutation perm to struct S. Don't follow k1,k2 */ static void siegel_perm0(struct siegel *S, GEN perm) { long i, l = lg(S->V); GEN V2 = cgetg(l, t_VEC), Ast2 = cgetg(l, t_VECSMALL); GEN V = S->V, Ast = S->Ast; for (i = 1; i < l; i++) gel(V2,perm[i]) = gel(V,i); for (i = 1; i < l; i++) Ast2[perm[i]] = perm[Ast[i]]; S->oo = perm[S->oo]; S->Ast = Ast2; S->V = V2; } /* apply permutation perm to full struct S */ static void siegel_perm(struct siegel *S, GEN perm) { siegel_perm0(S, perm); S->k1 = perm[S->k1]; S->k2 = perm[S->k2]; } /* cyclic permutation of lg = l-1 moving a -> 1, a+1 -> 2, etc. */ static GEN rotate_perm(long l, long a) { GEN p = cgetg(l, t_VECSMALL); long i, j = 1; for (i = a; i < l; i++) p[i] = j++; for (i = 1; i < a; i++) p[i] = j++; return p; } /* a1 < c1 <= a2 < c2*/ static GEN basic_op_perm(long l, long a1, long a2, long c1, long c2) { GEN p = cgetg(l, t_VECSMALL); long i, j = 1; p[a1] = j++; for (i = c1; i < a2; i++) p[i] = j++; for (i = a1+1; i < c1; i++) p[i] = j++; p[a2] = j++; for (i = c2; i < l; i++) p[i] = j++; for (i = 1; i < a1; i++) p[i] = j++; for (i = a2+1; i < c2; i++) p[i] = j++; return p; } static GEN basic_op_perm_elliptic(long l, long a1) { GEN p = cgetg(l, t_VECSMALL); long i, j = 1; p[a1] = j++; for (i = 1; i < a1; i++) p[i] = j++; for (i = a1+1; i < l; i++) p[i] = j++; return p; } static GEN ZM2_rev(GEN T) { return mkmat2(gel(T,2), ZC_neg(gel(T,1))); } /* In place, V = vector of consecutive paths, between x <= y. * V[x..y-1] <- g*V[x..y-1] */ static void path_vec_mul(GEN V, long x, long y, GEN g) { long j; GEN M; if (x == y) return; M = gel(V,x); gel(V,x) = ZM_mul(g,M); for (j = x+1; j < y; j++) /* V[j] <- g*V[j], optimized */ { GEN Mnext = gel(V,j); /* Mnext[,1] = M[,2] */ GEN gM = gel(V,j-1), u = gel(gM,2); if (!ZV_equal(gel(M,2), gel(Mnext,1))) u = ZC_neg(u); gel(V,j) = mkmat2(u, ZM_ZC_mul(g,gel(Mnext,2))); M = Mnext; } } static long prev(GEN V, long i) { return (i == 1)? lg(V)-1: i-1; } static long next(GEN V, long i) { return (i == lg(V)-1)? 1: i+1; } static GEN ZM_det2(GEN u, GEN v) { GEN a = gel(u,1), c = gel(u,2); GEN b = gel(v,1), d = gel(v,2); return subii(mulii(a,d), mulii(b,c)); } static GEN ZM2_det(GEN T) { return ZM_det2(gel(T,1),gel(T,2)); } static void fill1(GEN V, long a) { long p = prev(V,a), n = next(V,a); GEN u = gmael(V,p,2), v = gmael(V,n,1); if (signe(ZM_det2(u,v)) < 0) v = ZC_neg(v); gel(V,a) = mkmat2(u, v); } /* a1 < a2 */ static void fill2(GEN V, long a1, long a2) { if (a2 != a1+1) { fill1(V,a1); fill1(V,a2); } /* non adjacent, reconnect */ else /* parabolic */ { long p = prev(V,a1), n = next(V,a2); GEN u, v, C = gmael(V,a1,2), mC = ZC_neg(C); /* = \pm V[a2][1] */ u = gmael(V,p,2); v = (signe(ZM_det2(u,C)) < 0)? mC: C; gel(V,a1) = mkmat2(u,v); v = gmael(V,n,1); u = (signe(ZM_det2(C,v)) < 0)? mC: C; gel(V,a2) = mkmat2(u,v); } } /* DU = det(U), return g = T*U^(-1) or NULL if not in Gamma0(N); if N = 0, * only test whether g is integral */ static GEN ZM2_div(GEN T, GEN U, GEN DU, long N) { GEN a=gcoeff(U,1,1), b=gcoeff(U,1,2), c=gcoeff(U,2,1), d=gcoeff(U,2,2); GEN e=gcoeff(T,1,1), f=gcoeff(T,1,2), g=gcoeff(T,2,1), h=gcoeff(T,2,2); GEN A, B, C, D, r; C = dvmdii(subii(mulii(d,g), mulii(c,h)), DU, &r); if (r != gen_0 || (N && smodis(C,N))) return NULL; A = dvmdii(subii(mulii(d,e), mulii(c,f)), DU, &r); if (r != gen_0) return NULL; B = dvmdii(subii(mulii(a,f), mulii(b,e)), DU, &r); if (r != gen_0) return NULL; D = dvmdii(subii(mulii(a,h), mulii(g,b)), DU, &r); if (r != gen_0) return NULL; return mkmat22(A,B,C,D); } static GEN get_g(struct siegel *S, long a1) { long a2 = S->Ast[a1]; GEN a = gel(S->V,a1), ar = ZM2_rev(gel(S->V,a2)), Dar = ZM2_det(ar); GEN g = ZM2_div(a, ar, Dar, S->N); if (!g) { GEN tau = mkmat22(gen_0,gen_m1, gen_1,gen_m1); /*[0,-1;1,-1]*/ g = ZM2_div(ZM_mul(ar, tau), ar, Dar, 0); } return g; } /* input V = (X1 a X2 | X3 a^* X4) + Ast * a1 = index of a * a2 = index of a^*, inferred from a1. We must have a != a^* * c1 = first cut [ index of first path in X3 ] * c2 = second cut [ either in X4 or X1, index of first path ] * Assume a < a^* (cf Paranoia below): c1 or c2 must be in * ]a,a^*], and the other in the "complement" ]a^*,a] */ static void basic_op(struct siegel *S, long a1, long c1, long c2) { long l = lg(S->V), a2 = S->Ast[a1]; GEN g; if (a1 == a2) { /* a = a^* */ g = get_g(S, a1); path_vec_mul(S->V, a1+1, l, g); siegel_perm(S, basic_op_perm_elliptic(l, a1)); /* fill the hole left at a1, reconnect the path */ fill1(S->V, a1); return; } /* Paranoia: (a,a^*) conjugate, call 'a' the first one */ if (a2 < a1) lswap(a1,a2); /* Now a1 < a2 */ if (c1 <= a1 || c1 > a2) lswap(c1,c2); /* ensure a1 < c1 <= a2 */ if (c2 < a1) { /* if cut c2 is in X1 = X11|X12, rotate to obtain (a X2 | X3 a^* X4 X11|X12): then a1 = 1 */ GEN p = rotate_perm(l, a1); siegel_perm(S, p); a1 = 1; /* = p[a1] */ a2 = S->Ast[1]; /* > a1 */ c1 = p[c1]; c2 = p[c2]; } /* Now a1 < c1 <= a2 < c2; a != a^* */ g = get_g(S, a1); if (S->oo >= c1 && S->oo < c2) /* W inside [c1..c2[ */ { /* c2 -> c1 excluding a1 */ GEN gi = SL2_inv(g); /* g a^* = a; gi a = a^* */ path_vec_mul(S->V, 1, a1, gi); path_vec_mul(S->V, a1+1, c1, gi); path_vec_mul(S->V, c2, l, gi); } else { /* c1 -> c2 excluding a2 */ path_vec_mul(S->V, c1, a2, g); path_vec_mul(S->V, a2+1, c2, g); } siegel_perm(S, basic_op_perm(l, a1,a2, c1,c2)); /* fill the holes left at a1,a2, reconnect the path */ fill2(S->V, a1, a2); } /* a = a^* (elliptic case) */ static void basic_op_elliptic(struct siegel *S, long a1) { long l = lg(S->V); GEN g = get_g(S, a1); path_vec_mul(S->V, a1+1, l, g); siegel_perm(S, basic_op_perm_elliptic(l, a1)); /* fill the hole left at a1 (now at 1), reconnect the path */ fill1(S->V, 1); } /* input V = W X a b Y a^* Z b^* T, W already normalized * X = [n+1, k1-1], Y = [k2+1, Ast[k1]-1], * Z = [Ast[k1]+1, Ast[k2]-1], T = [Ast[k2]+1, oo]. * Assume that X doesn't start by c c^* or a b a^* b^*. */ static void siegelstep(struct siegel *S) { if (S->Ast[S->k1] == S->k1) { basic_op_elliptic(S, S->k1); S->n++; } else if (S->Ast[S->k1] == S->k1+1) { basic_op(S, S->k1, S->Ast[S->k1], 1); /* 1: W starts there */ S->n += 2; } else { basic_op(S, S->k2, S->Ast[S->k1], 1); /* 1: W starts there */ basic_op(S, S->k1, S->k2, S->Ast[S->k2]); basic_op(S, S->Ast[S->k2], S->k2, S->Ast[S->k1]); basic_op(S, S->k1, S->Ast[S->k1], S->Ast[S->k2]); S->n += 4; } } /* normalize hyperbolic polygon */ static void mssiegel(struct siegel *S) { pari_sp av = avma; long k, t, nv; #ifdef COUNT long countset[16]; for (k = 0; k < 16; k++) countset[k] = 0; #endif nv = lg(S->V)-1; if (DEBUGLEVEL>1) err_printf("nv = %ld, expo = %.2f\n", nv,ZMV_size(S->V)); t = 0; while (S->n < nv) { if (S->Ast[S->n+1] == S->n+1) { S->n++; continue; } if (S->Ast[S->n+1] == S->n+2) { S->n += 2; continue; } if (S->Ast[S->n+1] == S->n+3 && S->Ast[S->n+2] == S->n+4) { S->n += 4; continue; } k = nv; while (k > S->n) { if (S->Ast[k] == k) { k--; continue; } if (S->Ast[k] == k-1) { k -= 2; continue; } if (S->Ast[k] == k-2 && S->Ast[k-1] == k-3) { k -= 4; continue; } break; } if (k != nv) { siegel_perm0(S, rotate_perm(nv+1, k+1)); S->n += nv-k; } for (k = S->n+1; k <= nv; k++) if (S->Ast[k] <= k) { t = S->Ast[k]; break; } S->k1 = t; S->k2 = t+1; #ifdef COUNT countset[ ((S->k1-1 == S->n) | ((S->k2 == S->Ast[S->k1]-1) << 1) | ((S->Ast[S->k1] == S->Ast[S->k2]-1) << 2) | ((S->Ast[S->k2] == nv) << 3)) ]++; #endif siegelstep(S); if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"mspolygon, n = %ld",S->n); gerepileall(av, 2, &S->V, &S->Ast); } } if (DEBUGLEVEL>1) err_printf("expo = %.2f\n", ZMV_size(S->V)); #ifdef COUNT for (k = 0; k < 16; k++) err_printf("%3ld: %6ld\n", k, countset[k]); #endif } /* return a vector of char */ static GEN Ast2v(GEN Ast) { long j = 0, k, l = lg(Ast); GEN v = const_vec(l-1, NULL); for (k=1; k < l; k++) { char *sj; if (gel(v,k)) continue; j++; sj = stack_sprintf("$%ld$", j); gel(v,k) = (GEN)sj; if (Ast[k] != k) gel(v,Ast[k]) = (GEN)stack_sprintf("$%ld^*$", j); } return v; }; static GEN M2Q(GEN p) { GEN c = gel(p,1); return gdiv(gel(c,1), gel(c,2)); } static void maybe_decorate(pari_str *s, GEN Ast, GEN G, long k, double c) { GEN g; if (Ast[k] != k) return; g = ZM_sqr(gel(G,k)); if (gequal1(g) || gequalm1(g)) /* \pm Id */ str_printf(s, " node [midway] {$\\circ$}\n"); else str_printf(s, ";\n \\draw (start) arc (180:60:%.4f) node {$\\bullet$} arc (120:0:%.4f)\n",2*c/3,2*c/3); } static GEN polygon2tex(GEN V, GEN Ast, GEN G) { pari_sp av = avma; GEN v = Ast2v(Ast); pari_str s; long j, l = lg(V), flag; double c; str_init(&s, 1); flag = (l <= 16); str_puts(&s, "\n\\begin{tikzpicture}[scale=10]\n"); str_puts(&s, "\\draw (0,0.5)--(0,0) node [very near start, right] {$1^*$} node [below] {$0$}"); for (j=4; j < l; j++) { GEN a = M2Q(gel(V,j-1)), b = M2Q(gel(V,j)); c = gtodouble(gsub(b,a)) / 2; str_printf(&s, "node (start) {} arc (180:0:%.4f)\n", c); if (flag) { long sb = itos(numer_i(b)); long sa = itos(denom_i(b)); str_printf(&s, "node [midway, above] {%s} node [below]{$\\frac{%ld}{%ld}$}\n", (char*)gel(v,j-1), sb, sa); } maybe_decorate(&s,Ast,G,j-1,c); } c = (1- gtodouble(M2Q(gel(V,l-1)))) / 2; str_printf(&s, "node (start) {} arc (180:0:%.4f)\n", c); if (flag) str_printf(&s, "node [midway, above] {%s}", (char*)gel(v,l-1)); maybe_decorate(&s,Ast,G,l-1,c); str_printf(&s,"node [below] {$1$} -- (1,0.5) node [very near end, left] {$1$};"); str_printf(&s, "\n\\end{tikzpicture}"); return gerepileuptoleaf(av, strtoGENstr(s.string)); } static GEN circle2tex(GEN Ast, GEN G) { pari_sp av = avma; GEN v = Ast2v(Ast); pari_str s; long u, n = lg(Ast)-1; const double ang = 360./n; if (n > 30) { v = const_vec(n, (GEN)""); gel(v,1) = (GEN)"$(1,\\infty)$"; } str_init(&s, 1); str_puts(&s, "\n\\begingroup\n\ \\def\\geo#1#2{(#2:1) arc (90+#2:270+#1:{tan((#2-#1)/2)})}\n\ \\def\\sgeo#1#2{(#2:1) -- (#1:1)}\n\ \\def\\unarc#1#2#3{({#1 * #3}:1.2) node {#2}}\n\ \\def\\cell#1#2{({#1 * #2}:0.95) circle(0.05)}\n\ \\def\\link#1#2#3#4#5{\\unarc{#1}{#2}{#5}\\geo{#1*#5}{#3*#5}\\unarc{#3}{#4}{#5}}\n\ \\def\\slink#1#2#3#4#5{\\unarc{#1}{#2}{#5}\\sgeo{#1*#5}{#3*#5}\\unarc{#3}{#4}{#5}}"); str_puts(&s, "\n\\begin{tikzpicture}[scale=4]\n"); str_puts(&s, "\\draw (0, 0) circle(1);\n"); for (u=1; u <= n; u++) { if (Ast[u] == u) { str_printf(&s,"\\draw\\unarc{%ld}{%s}{%.4f}; \\draw\\cell{%ld}{%.4f};\n", u, v[u], ang, u, ang); if (ZM_isscalar(gpowgs(gel(G,u),3), NULL)) str_printf(&s,"\\fill \\cell{%ld}{%.4f};\n", u, ang); } else if(Ast[u] > u) str_printf(&s, "\\draw \\%slink {%ld}{%s}{%ld}{%s}{%.4f};\n", Ast[u]-u==n/2? "s": "", u, v[u], Ast[u], v[Ast[u]], ang); } str_printf(&s, "\\end{tikzpicture}\\endgroup"); return gerepileuptoleaf(av, strtoGENstr(s.string)); } GEN mspolygon(GEN M, long flag) { pari_sp av = avma; struct siegel T; long i, l; GEN v, G, msN; if (typ(M) == t_INT) { long N = itos(M); if (N <= 0) pari_err_DOMAIN("msinit","N", "<=", gen_0,M); msN = msinit_N(N); } else { checkms(M); msN = get_msN(M); } if (flag < 0 || flag > 3) pari_err_FLAG("mspolygon"); if (ms_get_N(msN) == 1) { GEN S = mkS(); T.V = mkvec2(matid(2), S); T.Ast = mkvecsmall2(1,2); G = mkvec2(S, mkTAU()); } else { siegel_init(&T, msN); l = lg(T.V); if (flag & 1) { long oo2 = 0; mssiegel(&T); for (i = 1; i < l; i++) { GEN c = gel(T.V, i); GEN c22 = gcoeff(c,2,2); if (!signe(c22)) { oo2 = i; break; } } if (!oo2) pari_err_BUG("mspolygon"); siegel_perm0(&T, rotate_perm(l, oo2)); } G = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(G,i) = get_g(&T, i); } if (flag & 2) v = mkvec5(T.V, T.Ast, G, polygon2tex(T.V,T.Ast,G), circle2tex(T.Ast,G)); else v = mkvec3(T.V, T.Ast, G); return gerepilecopy(av, v); } #if 0 static int iselliptic(GEN Ast, long i) { return i == Ast[i]; } static int isparabolic(GEN Ast, long i) { long i2 = Ast[i]; return (i2 == i+1 || i2 == i-1); } #endif /* M from msinit, F QM maximal rank */ GEN mslattice(GEN M, GEN F) { pari_sp av = avma; long i, ivB, j, k, l, lF; GEN D, U, G, A, vB, m, d; checkms(M); if (!F) F = gel(mscuspidal(M, 0), 1); else { if (is_Qevproj(F)) F = gel(F,1); if (typ(F) != t_MAT) pari_err_TYPE("mslattice",F); } lF = lg(F); if (lF == 1) return cgetg(1, t_MAT); D = mspolygon(M,0); k = msk_get_weight(M); F = vec_Q_primpart(F); if (typ(F)!=t_MAT || !RgM_is_ZM(F)) pari_err_TYPE("mslattice",F); G = gel(D,3); l = lg(G); A = gel(D,2); vB = cgetg(l, t_COL); d = mkcol2(gen_0,gen_1); m = mkmat2(d, d); for (i = ivB = 1; i < l; i++) { GEN B, vb, g = gel(G,i); if (A[i] < i) continue; gel(m,2) = SL2_inv2(g); vb = mseval(M, F, m); if (k == 2) B = vb; else { long lB; B = RgXV_to_RgM(vb, k-1); /* add coboundaries */ B = shallowconcat(B, RgM_Rg_sub(RgX_act_Gl2Q(g, k), gen_1)); /* beware: the basis for RgX_act_Gl2Q is (X^(k-2),...,Y^(k-2)) */ lB = lg(B); for (j = 1; j < lB; j++) gel(B,j) = vecreverse(gel(B,j)); } gel(vB, ivB++) = B; } setlg(vB, ivB); vB = shallowmatconcat(vB); if (ZM_equal0(vB)) return gerepilecopy(av, F); (void)QM_ImQ_hnfall(vB, &U, 0); if (k > 2) U = rowslice(U, 1, lgcols(U)-k); /* remove coboundary part */ U = Q_remove_denom(U, &d); F = ZM_hnf(ZM_mul(F, U)); if (d) F = RgM_Rg_div(F, d); return gerepileupto(av, F); } /**** Petersson scalar product ****/ /* oo -> g^(-1) oo */ static GEN cocycle(GEN g) { return mkmat22(gen_1, gcoeff(g,2,2), gen_0, negi(gcoeff(g,2,1))); } /* C = vecbinome(k-2) */ static GEN bil(GEN P, GEN Q, GEN C) { long i, n = lg(C)-2; /* k - 2 */ GEN s; if (!n) return gmul(P,Q); if (typ(P) != t_POL) P = scalarpol_shallow(P,0); if (typ(Q) != t_POL) Q = scalarpol_shallow(Q,0); s = gen_0; for (i = 0; i <= n; i++) { GEN t = gdiv(gmul(RgX_coeff(P,i), RgX_coeff(Q, n-i)), gel(C,i+1)); s = odd(i)? gsub(s, t): gadd(s, t); } return s; } static void mspetersson_i(GEN W, GEN F, GEN G, GEN *pvf, GEN *pvg, GEN *pC) { GEN WN = get_msN(W), annT2, annT31, section, c, vf, vg; long i, n1, n2, n3; annT2 = msN_get_annT2(WN); annT31 = msN_get_annT31(WN); section = msN_get_section(WN); if (ms_get_N(WN) == 1) { vf = cgetg(3, t_VEC); vg = cgetg(3, t_VEC); gel(vf,1) = mseval(W, F, gel(section,1)); gel(vf,2) = gneg(gel(vf,1)); n1 = 0; } else { GEN singlerel = msN_get_singlerel(WN); GEN gen = msN_get_genindex(WN); long l = lg(gen); vf = cgetg(l, t_VEC); vg = cgetg(l, t_VEC); /* generators of Delta ordered as E1,T2,T31 */ for (i = 1; i < l; i++) gel(vf, i) = mseval(W, F, gel(section,gen[i])); n1 = ms_get_nbE1(WN); /* E1 */ for (i = 1; i <= n1; i++) { c = cocycle(gcoeff(gel(singlerel,i),2,1)); gel(vg, i) = mseval(W, G, c); } } n2 = lg(annT2)-1; /* T2 */ for (i = 1; i <= n2; i++) { c = cocycle(gcoeff(gel(annT2,i), 2,1)); gel(vg, i+n1) = gmul2n(mseval(W, G, c), -1); } n3 = lg(annT31)-1; /* T31 */ for (i = 1; i <= n3; i++) { GEN f; c = cocycle(gcoeff(gel(annT31,i), 2,1)); f = mseval(W, G, c); c = cocycle(gcoeff(gel(annT31,i), 3,1)); gel(vg, i+n1+n2) = gdivgs(gadd(f, mseval(W, G, c)), 3); } *pC = vecbinome(msk_get_weight(W) - 2); *pvf = vf; *pvg = vg; } /* Petersson product on Hom_G(Delta_0, V_k) */ GEN mspetersson(GEN W, GEN F, GEN G) { pari_sp av = avma; GEN vf, vg, C; long k, l, tG, tF; checkms(W); if (!F) F = matid(msdim(W)); if (!G) G = F; tF = typ(F); tG = typ(G); if (tF == t_MAT && tG != t_MAT) pari_err_TYPE("mspetersson",G); if (tG == t_MAT && tF != t_MAT) pari_err_TYPE("mspetersson",F); mspetersson_i(W, F, G, &vf, &vg, &C); l = lg(vf); if (tF != t_MAT) { /* , two symbols */ GEN s = gen_0; for (k = 1; k < l; k++) s = gadd(s, bil(gel(vf,k), gel(vg,k), C)); return gerepileupto(av, s); } else if (F != G) { /* <(f_1,...,f_m), (g_1,...,g_n)> */ long iF, iG, lF = lg(F), lG = lg(G); GEN M = cgetg(lG, t_MAT); for (iG = 1; iG < lG; iG++) { GEN c = cgetg(lF, t_COL); gel(M,iG) = c; for (iF = 1; iF < lF; iF++) { GEN s = gen_0; for (k = 1; k < l; k++) s = gadd(s, bil(gmael(vf,k,iF), gmael(vg,k,iG), C)); gel(c,iF) = s; /* M[iF,iG] = */ } } return gerepilecopy(av, M); } else { /* <(f_1,...,f_n), (f_1,...,f_n)> */ long iF, iG, n = lg(F)-1; GEN M = zeromatcopy(n,n); for (iG = 1; iG <= n; iG++) for (iF = iG+1; iF <= n; iF++) { GEN s = gen_0; for (k = 1; k < l; k++) s = gadd(s, bil(gmael(vf,k,iF), gmael(vg,k,iG), C)); gcoeff(M,iF,iG) = s; /* */ gcoeff(M,iG,iF) = gneg(s); } return gerepilecopy(av, M); } } pari-2.11.2/src/basemath/rootpol.c0000644000175000017500000022710713457566440015422 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* ROOTS OF COMPLEX POLYNOMIALS */ /* (original code contributed by Xavier Gourdon, INRIA RR 1852) */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" static const double pariINFINITY = 1./0.; static long isvalidcoeff(GEN x) { switch (typ(x)) { case t_INT: case t_REAL: case t_FRAC: return 1; case t_COMPLEX: return isvalidcoeff(gel(x,1)) && isvalidcoeff(gel(x,2)); } return 0; } static void checkvalidpol(GEN p, const char *f) { long i,n = lg(p); for (i=2; i 0, lP = lgpol(P) */ static GEN CX_square_spec(GEN P, long lP) { GEN s, t; long i, j, l, nn, n = lP - 1; pari_sp av; nn = n<<1; s = cgetg(nn+3,t_POL); s[1] = evalsigne(1)|evalvarn(0); gel(s,2) = sqrCC(gel(P,0)); /* i = 0 */ for (i=1; i<=n; i++) { av = avma; l = (i+1)>>1; t = mulCC(gel(P,0), gel(P,i)); /* j = 0 */ for (j=1; j>1))); gel(s,i+2) = gerepileupto(av, t); } gel(s,nn+2) = sqrCC(gel(P,n)); /* i = nn */ for ( ; i>1; t = mulCC(gel(P,i-n),gel(P,n)); /* j = i-n */ for (j=i-n+1; j>1))); gel(s,i+2) = gerepileupto(av, t); } return normalizepol_lg(s, nn+3); } /* nx = lgpol(x) */ static GEN RgX_s_mulspec(GEN x, long nx, long s) { GEN z, t; long i; if (!s || !nx) return pol_0(0); z = cgetg(nx+2, t_POL); z[1] = evalsigne(1)|evalvarn(0); t = z + 2; for (i=0; i < nx; i++) gel(t,i) = gmulgs(gel(x,i), s); return z; } /* nx = lgpol(x), return x << s. Inefficient if s = 0... */ static GEN RgX_shiftspec(GEN x, long nx, long s) { GEN z, t; long i; if (!nx) return pol_0(0); z = cgetg(nx+2, t_POL); z[1] = evalsigne(1)|evalvarn(0); t = z + 2; for (i=0; i < nx; i++) gel(t,i) = gmul2n(gel(x,i), s); return z; } /* spec function. nP = lgpol(P) */ static GEN karasquare(GEN P, long nP) { GEN Q, s0, s1, s2, a, t; long n0, n1, i, l, N, N0, N1, n = nP - 1; /* degree(P) */ pari_sp av; if (n <= KARASQUARE_LIMIT) return nP? CX_square_spec(P, nP): pol_0(0); av = avma; n0 = (n>>1) + 1; n1 = nP - n0; s0 = karasquare(P, n0); Q = P + n0; s2 = karasquare(Q, n1); s1 = RgX_addspec_shallow(P, Q, n0, n1); s1 = RgX_sub(karasquare(s1+2, lgpol(s1)), RgX_add(s0,s2)); N = (n<<1) + 1; a = cgetg(N + 2, t_POL); a[1] = evalsigne(1)|evalvarn(0); t = a+2; l = lgpol(s0); s0 += 2; N0 = n0<<1; for (i=0; i < l; i++) gel(t,i) = gel(s0,i); for ( ; i < N0; i++) gel(t,i) = gen_0; t = a+2 + N0; l = lgpol(s2); s2 += 2; N1 = N - N0; for (i=0; i < l; i++) gel(t,i) = gel(s2,i); for ( ; i < N1; i++) gel(t,i) = gen_0; t = a+2 + n0; l = lgpol(s1); s1 += 2; for (i=0; i < l; i++) gel(t,i) = gadd(gel(t,i), gel(s1,i)); return gerepilecopy(av, normalizepol_lg(a, N+2)); } /* spec function. nP = lgpol(P) */ static GEN cook_square(GEN P, long nP) { GEN Q, p0, p1, p2, p3, q, r, t, vp, vm; long n0, n3, i, j, n = nP - 1; pari_sp av; if (n <= COOKSQUARE_LIMIT) return nP? karasquare(P, nP): pol_0(0); av = avma; n0 = (n+1) >> 2; n3 = n+1 - 3*n0; p0 = P; p1 = p0+n0; p2 = p1+n0; p3 = p2+n0; /* lgpol(p0,p1,p2) = n0, lgpol(p3) = n3 */ q = cgetg(8,t_VEC) + 4; Q = cook_square(p0, n0); r = RgX_addspec_shallow(p0,p2, n0,n0); t = RgX_addspec_shallow(p1,p3, n0,n3); gel(q,-1) = RgX_sub(r,t); gel(q,1) = RgX_add(r,t); r = RgX_addspec_shallow(p0,RgX_shiftspec(p2,n0, 2)+2, n0,n0); t = gmul2n(RgX_addspec_shallow(p1,RgX_shiftspec(p3,n3, 2)+2, n0,n3), 1); gel(q,-2) = RgX_sub(r,t); gel(q,2) = RgX_add(r,t); r = RgX_addspec_shallow(p0,RgX_s_mulspec(p2,n0, 9)+2, n0,n0); t = gmulsg(3, RgX_addspec_shallow(p1,RgX_s_mulspec(p3,n3, 9)+2, n0,n3)); gel(q,-3) = RgX_sub(r,t); gel(q,3) = RgX_add(r,t); r = new_chunk(7); vp = cgetg(4,t_VEC); vm = cgetg(4,t_VEC); for (i=1; i<=3; i++) { GEN a = gel(q,i), b = gel(q,-i); a = cook_square(a+2, lgpol(a)); b = cook_square(b+2, lgpol(b)); gel(vp,i) = RgX_add(b, a); gel(vm,i) = RgX_sub(b, a); } gel(r,0) = Q; gel(r,1) = gdivgs(gsub(gsub(gmulgs(gel(vm,2),9),gel(vm,3)), gmulgs(gel(vm,1),45)), 60); gel(r,2) = gdivgs(gadd(gadd(gmulgs(gel(vp,1),270),gmulgs(Q,-490)), gadd(gmulgs(gel(vp,2),-27),gmulgs(gel(vp,3),2))), 360); gel(r,3) = gdivgs(gadd(gadd(gmulgs(gel(vm,1),13),gmulgs(gel(vm,2),-8)), gel(vm,3)), 48); gel(r,4) = gdivgs(gadd(gadd(gmulgs(Q,56),gmulgs(gel(vp,1),-39)), gsub(gmulgs(gel(vp,2),12),gel(vp,3))), 144); gel(r,5) = gdivgs(gsub(gadd(gmulgs(gel(vm,1),-5),gmulgs(gel(vm,2),4)), gel(vm,3)), 240); gel(r,6) = gdivgs(gadd(gadd(gmulgs(Q,-20),gmulgs(gel(vp,1),15)), gadd(gmulgs(gel(vp,2),-6),gel(vp,3))), 720); q = cgetg(2*n+3,t_POL); q[1] = evalsigne(1)|evalvarn(0); t = q+2; for (i=0; i<=2*n; i++) gel(t,i) = gen_0; for (i=0; i<=6; i++,t += n0) { GEN h = gel(r,i); long d = lgpol(h); h += 2; for (j=0; j>1)+1; n1 = n+1 - n0; /* n1 <= n0 <= n1+1 */ p0 = new_chunk(n0); p1 = new_chunk(n1); for (i=0; i 2^21, it is correct to 2 ulp */ static double mydbllog2i(GEN x) { #ifdef LONG_IS_64BIT const double W = 1/(4294967296. * 4294967296.); /* 2^-64 */ #else const double W = 1/4294967296.; /*2^-32*/ #endif GEN m; long lx = lgefint(x); double l; if (lx == 2) return -pariINFINITY; m = int_MSW(x); l = (double)(ulong)*m; if (lx == 3) return log2(l); l += ((double)(ulong)*int_precW(m)) * W; /* at least m = min(53,BIL) bits are correct in the mantissa, thus log2 * is correct with error < log(1 + 2^-m) ~ 2^-m. Adding the correct * exponent BIL(lx-3) causes 1ulp further round-off error */ return log2(l) + (double)(BITS_IN_LONG*(lx-3)); } /* return log(|x|) or -pariINFINITY */ static double mydbllogr(GEN x) { if (!signe(x)) return -pariINFINITY; return M_LN2*dbllog2r(x); } /* return log2(|x|) or -pariINFINITY */ static double mydbllog2r(GEN x) { if (!signe(x)) return -pariINFINITY; return dbllog2r(x); } double dbllog2(GEN z) { double x, y; switch(typ(z)) { case t_INT: return mydbllog2i(z); case t_FRAC: return mydbllog2i(gel(z,1))-mydbllog2i(gel(z,2)); case t_REAL: return mydbllog2r(z); default: /*t_COMPLEX*/ x = dbllog2(gel(z,1)); y = dbllog2(gel(z,2)); if (x == -pariINFINITY) return y; if (y == -pariINFINITY) return x; if (fabs(x-y) > 10) return maxdd(x,y); return x + 0.5*log2(1 + exp2(2*(y-x))); } } static GEN /* beware overflow */ dblexp(double x) { return fabs(x) < 100.? dbltor(exp(x)): mpexp(dbltor(x)); } /* find s such that A_h <= 2^s <= 2 A_i for one h and all i < n = deg(p), * with A_i := (binom(n,i) lc(p) / p_i) ^ 1/(n-i), and p = sum p_i X^i */ static long findpower(GEN p) { double x, L, mins = pariINFINITY; long n = degpol(p),i; L = dbllog2(gel(p,n+2)); /* log2(lc * binom(n,i)) */ for (i=n-1; i>=0; i--) { L += log2((double)(i+1) / (double)(n-i)); x = dbllog2(gel(p,i+2)); if (x != -pariINFINITY) { double s = (L - x) / (double)(n-i); if (s < mins) mins = s; } } i = (long)ceil(mins); if (i - mins > 1 - 1e-12) i--; return i; } /* returns the exponent for logmodulus(), from the Newton diagram */ static long newton_polygon(GEN p, long k) { pari_sp av = avma; double *logcoef, slope; long n = degpol(p), i, j, h, l, *vertex; logcoef = (double*)stack_malloc_align((n+1)*sizeof(double), sizeof(double)); vertex = (long*)new_chunk(n+1); /* vertex[i] = 1 if i a vertex of convex hull, 0 otherwise */ for (i=0; i<=n; i++) { logcoef[i] = dbllog2(gel(p,2+i)); vertex[i] = 0; } vertex[0] = 1; /* sentinel */ for (i=0; i < n; i=h) { slope = logcoef[i+1]-logcoef[i]; for (j = h = i+1; j<=n; j++) { double pij = (logcoef[j]-logcoef[i])/(double)(j-i); if (slope < pij) { slope = pij; h = j; } } vertex[h] = 1; } h = k; while (!vertex[h]) h++; l = k-1; while (!vertex[l]) l--; avma = av; return (long)floor((logcoef[h]-logcoef[l])/(double)(h-l) + 0.5); } /* change z into z*2^e, where z is real or complex of real */ static void myshiftrc(GEN z, long e) { if (typ(z)==t_COMPLEX) { if (signe(gel(z,1))) shiftr_inplace(gel(z,1), e); if (signe(gel(z,2))) shiftr_inplace(gel(z,2), e); } else if (signe(z)) shiftr_inplace(z, e); } /* return z*2^e, where z is integer or complex of integer (destroy z) */ static GEN myshiftic(GEN z, long e) { if (typ(z)==t_COMPLEX) { gel(z,1) = signe(gel(z,1))? mpshift(gel(z,1),e): gen_0; gel(z,2) = mpshift(gel(z,2),e); return z; } return signe(z)? mpshift(z,e): gen_0; } static GEN RgX_gtofp_bit(GEN q, long bit) { if (bit < 0) bit = 0; return RgX_gtofp(q, nbits2prec(bit)); } static GEN mygprecrc(GEN x, long prec, long e) { GEN y; switch(typ(x)) { case t_REAL: return signe(x)? rtor(x, prec): real_0_bit(e); case t_COMPLEX: y = cgetg(3,t_COMPLEX); gel(y,1) = mygprecrc(gel(x,1),prec,e); gel(y,2) = mygprecrc(gel(x,2),prec,e); return y; default: return gcopy(x); } } /* gprec behaves badly with the zero for polynomials. The second parameter in mygprec is the precision in base 2 */ static GEN mygprec(GEN x, long bit) { long lx, i, e, prec; GEN y; if (bit < 0) bit = 0; /* should rarely happen */ e = gexpo(x) - bit; prec = nbits2prec(bit); switch(typ(x)) { case t_POL: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i0; i--) { gel(r,i+2) = gmul(t, gel(q,i+2)); t = mulrr(t, iR); } gel(r,2) = gmul(t, gel(q,2)); return r; } /* change q in 2^(n*e) p(x*2^(-e)), n=deg(q) [ ~as above with R = 2^-e ]*/ static void homothetie2n(GEN p, long e) { if (e) { long i,n = lg(p)-1; for (i=2; i<=n; i++) myshiftrc(gel(p,i), (n-i)*e); } } /* return 2^f * 2^(n*e) p(x*2^(-e)), n=deg(q) */ static void homothetie_gauss(GEN p, long e, long f) { if (e || f) { long i, n = lg(p)-1; for (i=2; i<=n; i++) gel(p,i) = myshiftic(gel(p,i), f+(n-i)*e); } } /* Lower bound on the modulus of the largest root z_0 * k is set to an upper bound for #{z roots, |z-z_0| < eps} */ static double lower_bound(GEN p, long *k, double eps) { long n = degpol(p), i, j; pari_sp ltop = avma; GEN a, s, S, ilc; double r, R, rho; if (n < 4) { *k = n; return 0.; } S = cgetg(5,t_VEC); a = cgetg(5,t_VEC); ilc = gdiv(real_1(DEFAULTPREC), gel(p,n+2)); for (i=1; i<=4; i++) gel(a,i) = gmul(ilc,gel(p,n+2-i)); /* i = 1 split out from next loop for efficiency and initialization */ s = gel(a,1); gel(S,1) = gneg(s); /* Newton sum S_i */ rho = r = gtodouble(gabs(s,3)); R = r / n; for (i=2; i<=4; i++) { s = gmulsg(i,gel(a,i)); for (j=1; j 0.) { r = exp(log(r/n) / (double)i); if (r > R) R = r; } } if (R > 0. && eps < 1.2) *k = (long)floor((rho/R + n) / (1 + exp(-eps)*cos(eps))); else *k = n; avma = ltop; return R; } /* return R such that exp(R - tau) <= rho_n(P) <= exp(R + tau) * P(0) != 0 and P non constant */ static double logmax_modulus(GEN p, double tau) { GEN r, q, aux, gunr; pari_sp av, ltop = avma; long i,k,n=degpol(p),nn,bit,M,e; double rho,eps, tau2 = (tau > 3.0)? 0.5: tau/6.; r = cgeti(BIGDEFAULTPREC); av = avma; eps = - 1/log(1.5*tau2); /* > 0 */ bit = (long) ((double) n*log2(1./tau2)+3*log2((double) n))+1; gunr = real_1_bit(bit+2*n); aux = gdiv(gunr, gel(p,2+n)); q = RgX_Rg_mul(p, aux); gel(q,2+n) = gunr; e = findpower(q); homothetie2n(q,e); affsi(e, r); q = pol_to_gaussint(q, bit); M = (long) (log2( log(4.*n) / (2*tau2) )) + 2; nn = n; for (i=0,e=0;;) { /* nn = deg(q) */ rho = lower_bound(q, &k, eps); if (rho > exp2(-(double)e)) e = (long)-floor(log2(rho)); affii(shifti(addis(r,e), 1), r); if (++i == M) break; bit = (long) ((double)k * log2(1./tau2) + (double)(nn-k)*log2(1./eps) + 3*log2((double)nn)) + 1; homothetie_gauss(q, e, bit-(long)floor(dbllog2(gel(q,2+nn))+0.5)); nn -= RgX_valrem(q, &q); set_karasquare_limit(gexpo(q)); q = gerepileupto(av, graeffe(q)); tau2 *= 1.5; if (tau2 > 0.9) tau2 = 0.5; eps = -1/log(tau2); /* > 0 */ e = findpower(q); } if (!signe(r)) { avma = ltop; return 0.; } r = itor(r, DEFAULTPREC); shiftr_inplace(r, -M); avma = ltop; return -rtodbl(r) * M_LN2; /* -log(2) sum e_i 2^-i */ } static GEN RgX_normalize1(GEN x) { long i, n = lg(x)-1; GEN y; for (i = n; i > 1; i--) if (!gequal0( gel(x,i) )) break; if (i == n) return x; pari_warn(warner,"normalizing a polynomial with 0 leading term"); if (i == 1) pari_err_ROOTS0("roots"); y = cgetg(i+1, t_POL); y[1] = x[1]; for (; i > 1; i--) gel(y,i) = gel(x,i); return y; } static GEN polrootsbound_i(GEN P, double TAU) { pari_sp av = avma; double d; (void)RgX_valrem_inexact(P,&P); P = RgX_normalize1(P); switch(degpol(P)) { case -1: pari_err_ROOTS0("roots"); case 0: avma = av; return gen_0; } d = logmax_modulus(P, TAU) + TAU; /* not dblexp: result differs on ARM emulator */ return gerepileuptoleaf(av, mpexp(dbltor(d))); } GEN polrootsbound(GEN P, GEN tau) { if (typ(P) != t_POL) pari_err_TYPE("polrootsbound",P); checkvalidpol(P, "polrootsbound"); return polrootsbound_i(P, tau? gtodouble(tau): 0.01); } /* log of modulus of the smallest root of p, with relative error tau */ static double logmin_modulus(GEN p, double tau) { pari_sp av = avma; double r; if (gequal0(gel(p,2))) return -pariINFINITY; r = - logmax_modulus(RgX_recip_shallow(p),tau); avma = av; return r; } /* return the log of the k-th modulus (ascending order) of p, rel. error tau*/ static double logmodulus(GEN p, long k, double tau) { GEN q; long i, kk = k, imax, n = degpol(p), nn, bit, e; pari_sp av, ltop=avma; double r, tau2 = tau/6; bit = (long)(n * (2. + log2(3.*n/tau2))); av = avma; q = gprec_w(p, nbits2prec(bit)); q = RgX_gtofp_bit(q, bit); e = newton_polygon(q,k); r = (double)e; homothetie2n(q,e); imax = (long)(log2(3./tau) + log2(log(4.*n)))+1; for (i=1; i 1.) tau2 = 1.; bit = 1 + (long)(nn*(2. + log2(3.*nn/tau2))); } avma = ltop; return -r * M_LN2; } /* return the log of the k-th modulus r_k of p, rel. error tau, knowing that * rmin < r_k < rmax. This information helps because we may reduce precision * quicker */ static double logpre_modulus(GEN p, long k, double tau, double lrmin, double lrmax) { GEN q; long n = degpol(p), i, imax, imax2, bit; pari_sp ltop = avma, av; double lrho, aux, tau2 = tau/6.; aux = (lrmax - lrmin) / 2. + 4*tau2; imax = (long) log2(log((double)n)/ aux); if (imax <= 0) return logmodulus(p,k,tau); lrho = (lrmin + lrmax) / 2; av = avma; bit = (long)(n*(2. + aux / M_LN2 - log2(tau2))); q = homothetie(p, lrho, bit); imax2 = (long)(log2(3./tau * log(4.*n))) + 1; if (imax > imax2) imax = imax2; for (i=0; i L) { L = d; k = i; } } return k; } /* Returns k such that r_k e^(-tau) < R < r_{k+1} e^tau. * Assume that l <= k <= n-l */ static long dual_modulus(GEN p, double lrho, double tau, long l) { long i, imax, delta_k = 0, n = degpol(p), nn, v2, v, bit, ll = l; double tau2 = tau * 7./8.; pari_sp av = avma; GEN q; bit = 6*n - 5*l + (long)(n*(-log2(tau2) + tau2 * 8./7.)); q = homothetie(p, lrho, bit); imax = (long)(log(log(2.*n)/tau2)/log(7./4.)+1); for (i=0; i>2; l2 = 2*l1; l3 = l1+l2; step4 = step<<2; fft(Omega,p, f, step4,l1); fft(Omega,p+step, f+l1,step4,l1); fft(Omega,p+(step<<1),f+l2,step4,l1); fft(Omega,p+3*step, f+l3,step4,l1); ff = cgetg(l+1,t_VEC); for (i=0; i l) pari_err_DIM("FFT"); if (n < l) { z = cgetg(l, t_VECSMALL); /* cf stackdummy */ for (i = 1; i < n; i++) z[i] = x[i]; for ( ; i < l; i++) gel(z,i) = gen_0; } else z = x; y = cgetg(l, t_VEC); fft(Omega+1, z+1, y+1, 1, l-1); return y; } /* returns 1 if p has only real coefficients, 0 else */ static int isreal(GEN p) { long i; for (i = lg(p)-1; i > 1; i--) if (typ(gel(p,i)) == t_COMPLEX) return 0; return 1; } /* x non complex */ static GEN abs_update_r(GEN x, double *mu) { GEN y = gtofp(x, DEFAULTPREC); double ly = mydbllogr(y); if (ly < *mu) *mu = ly; setabssign(y); return y; } /* return |x|, low accuracy. Set *mu = min(log(y), *mu) */ static GEN abs_update(GEN x, double *mu) { GEN y, xr, yr; double ly; if (typ(x) != t_COMPLEX) return abs_update_r(x, mu); xr = gel(x,1); yr = gel(x,2); if (gequal0(xr)) return abs_update_r(yr,mu); if (gequal0(yr)) return abs_update_r(xr,mu); /* have to treat 0 specially: 0E-10 + 1e-20 = 0E-10 */ xr = gtofp(xr, DEFAULTPREC); yr = gtofp(yr, DEFAULTPREC); y = sqrtr(addrr(sqrr(xr), sqrr(yr))); ly = mydbllogr(y); if (ly < *mu) *mu = ly; return y; } static void initdft(GEN *Omega, GEN *prim, long N, long Lmax, long bit) { long prec = nbits2prec(bit); *Omega = grootsof1(Lmax, prec) + 1; *prim = rootsof1u_cx(N, prec); } static void parameters(GEN p, long *LMAX, double *mu, double *gamma, int polreal, double param, double param2) { GEN q, pc, Omega, A, RU, prim, g, TWO; long n = degpol(p), bit, NN, K, i, j, Lmax; pari_sp av2, av = avma; bit = gexpo(p) + (long)param2+8; Lmax = 4; while (Lmax <= n) Lmax <<= 1; NN = (long)(param*3.14)+1; if (NN < Lmax) NN = Lmax; K = NN/Lmax; if (K & 1) K++; NN = Lmax*K; if (polreal) K = K/2+1; initdft(&Omega, &prim, NN, Lmax, bit); q = mygprec(p,bit) + 2; A = cgetg(Lmax+1,t_VEC); A++; pc= cgetg(Lmax+1,t_VEC); pc++; for (i=0; i <= n; i++) gel(pc,i)= gel(q,i); for ( ; i0 && i1) pari_warn(warnmem,"parameters"); gerepileall(av2,2, &g,&RU); } } *gamma = mydbllog2r(divru(g,NN)); *LMAX = Lmax; avma = av; } /* NN is a multiple of Lmax */ static void dft(GEN p, long k, long NN, long Lmax, long bit, GEN F, GEN H, long polreal) { GEN Omega, q, qd, pc, pd, A, B, C, RU, aux, U, W, prim, prim2; long n = degpol(p), i, j, K; pari_sp ltop; initdft(&Omega, &prim, NN, Lmax, bit); RU = cgetg(n+2,t_VEC) + 1; K = NN/Lmax; if (polreal) K = K/2+1; q = mygprec(p,bit); qd = RgX_deriv(q); A = cgetg(Lmax+1,t_VEC); A++; B = cgetg(Lmax+1,t_VEC); B++; C = cgetg(Lmax+1,t_VEC); C++; pc = cgetg(Lmax+1,t_VEC); pc++; pd = cgetg(Lmax+1,t_VEC); pd++; pc[0] = q[2]; for (i=n+1; i0 && i-bit && i1) pari_warn(warnmem,"refine_H"); gerepileall(ltop,2, &D,&H); } bit1 = -error + Sbit; aux = RgX_mul(mygprec(H,bit1), mygprec(D,bit1)); aux = RgX_rem(mygprec(aux,bit1), mygprec(F,bit1)); bit1 = -error*2 + Sbit; if (bit1 > bit2) bit1 = bit2; H = RgX_add(mygprec(H,bit1), aux); D = Rg_RgX_sub(gen_1, RgX_rem(RgX_mul(H,G),F)); error = gexpo(D); if (error < -bit1) error = -bit1; } if (error > -bit/2) return NULL; /* FAIL */ return gerepilecopy(ltop,H); } /* return 0 if fails, 1 else */ static long refine_F(GEN p, GEN *F, GEN *G, GEN H, long bit, double gamma) { GEN f0, FF, GG, r, HH = H; long error, i, bit1 = 0, bit2, Sbit, Sbit2, enh, normF, normG, n = degpol(p); pari_sp av = avma; FF = *F; GG = RgX_divrem(p, FF, &r); error = gexpo(r); if (error <= -bit) error = 1-bit; normF = gexpo(FF); normG = gexpo(GG); enh = gexpo(H); if (enh < 0) enh = 0; Sbit = normF + 2*normG + enh + (long)(4.*log2((double)n)+gamma) + 1; Sbit2 = enh + 2*(normF+normG) + (long)(2.*gamma+5.*log2((double)n)) + 1; bit2 = bit + Sbit; for (i=0; error>-bit && i= 2) { Sbit += n; Sbit2 += n; bit2 += n; } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"refine_F"); gerepileall(av,4, &FF,&GG,&r,&HH); } bit1 = -error + Sbit2; HH = refine_H(mygprec(FF,bit1), mygprec(GG,bit1), mygprec(HH,bit1), 1-error, Sbit2); if (!HH) return 0; /* FAIL */ bit1 = -error + Sbit; r = RgX_mul(mygprec(HH,bit1), mygprec(r,bit1)); f0 = RgX_rem(mygprec(r,bit1), mygprec(FF,bit1)); bit1 = -2*error + Sbit; if (bit1 > bit2) bit1 = bit2; FF = gadd(mygprec(FF,bit1),f0); bit1 = -3*error + Sbit; if (bit1 > bit2) bit1 = bit2; GG = RgX_divrem(mygprec(p,bit1), mygprec(FF,bit1), &r); error = gexpo(r); if (error < -bit1) error = -bit1; } if (error>-bit) return 0; /* FAIL */ *F = FF; *G = GG; return 1; } /* returns F and G from the unit circle U such that |p-FG|<2^(-bit) |cd|, where cd is the leading coefficient of p */ static void split_fromU(GEN p, long k, double delta, long bit, GEN *F, GEN *G, double param, double param2) { GEN pp, FF, GG, H; long n = degpol(p), NN, bit2, Lmax; int polreal = isreal(p); pari_sp ltop; double mu, gamma; pp = gdiv(p, gel(p,2+n)); parameters(pp, &Lmax,&mu,&gamma, polreal,param,param2); H = cgetg(k+2,t_POL); H[1] = p[1]; FF = cgetg(k+3,t_POL); FF[1]= p[1]; gel(FF,k+2) = gen_1; NN = (long)(0.5/delta); NN |= 1; if (NN < 2) NN = 2; NN *= Lmax; ltop = avma; for(;;) { bit2 = (long)(((double)NN*delta-mu)/M_LN2) + gexpo(pp) + 8; dft(pp, k, NN, Lmax, bit2, FF, H, polreal); if (refine_F(pp,&FF,&GG,H,bit,gamma)) break; NN <<= 1; avma = ltop; } *G = gmul(GG,gel(p,2+n)); *F = FF; } static void optimize_split(GEN p, long k, double delta, long bit, GEN *F, GEN *G, double param, double param2) { long n = degpol(p); GEN FF, GG; if (k <= n/2) split_fromU(p,k,delta,bit,F,G,param,param2); else { split_fromU(RgX_recip_shallow(p),n-k,delta,bit,&FF,&GG,param,param2); *F = RgX_recip_shallow(GG); *G = RgX_recip_shallow(FF); } } /********************************************************************/ /** **/ /** SEARCH FOR SEPARATING CIRCLE **/ /** **/ /********************************************************************/ /* return p(2^e*x) *2^(-n*e) */ static void scalepol2n(GEN p, long e) { long i,n=lg(p)-1; for (i=2; i<=n; i++) gel(p,i) = gmul2n(gel(p,i),(i-n)*e); } /* returns p(x/R)*R^n */ static GEN scalepol(GEN p, GEN R, long bit) { GEN q,aux,gR; long i; aux = gR = mygprec(R,bit); q = mygprec(p,bit); for (i=lg(p)-2; i>=2; i--) { gel(q,i) = gmul(aux,gel(q,i)); aux = gmul(aux,gR); } return q; } /* return (conj(a)X-1)^n * p[ (X-a) / (conj(a)X-1) ] */ static GEN conformal_pol(GEN p, GEN a) { GEN z, r, ma = gneg(a), ca = conj_i(a); long n = degpol(p), i; pari_sp av = avma; z = mkpoln(2, ca, gen_m1); r = scalarpol(gel(p,2+n), 0); for (i=n-1; ; i--) { r = RgX_addmulXn_shallow(r, gmul(ma,r), 1); /* r *= (X - a) */ r = gadd(r, gmul(z, gel(p,2+i))); if (i == 0) return gerepileupto(av, r); z = RgX_addmulXn_shallow(gmul(z,ca), gneg(z), 1); /* z *= conj(a)X - 1 */ if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"conformal_pol"); gerepileall(av,2, &r,&z); } } } static const double UNDEF = -100000.; static double logradius(double *radii, GEN p, long k, double aux, double *delta) { long i, n = degpol(p); double lrho, lrmin, lrmax; if (k > 1) { i = k-1; while (i>0 && radii[i] == UNDEF) i--; lrmin = logpre_modulus(p,k,aux, radii[i], radii[k]); } else /* k=1 */ lrmin = logmin_modulus(p,aux); radii[k] = lrmin; if (k+1=1; i--) { if (radii[i] == UNDEF || radii[i] > lrho) radii[i] = lrho; else lrho = radii[i]; } lrho = radii[k+1]; for (i=k+1; i<=n; i++) { if (radii[i] == UNDEF || radii[i] < lrho) radii[i] = lrho; else lrho = radii[i]; } *delta = (lrmax - lrmin) / 2; if (*delta > 1.) *delta = 1.; return (lrmin + lrmax) / 2; } static void update_radius(long n, double *radii, double lrho, double *par, double *par2) { double t, param = 0., param2 = 0.; long i; for (i=1; i<=n; i++) { radii[i] -= lrho; t = fabs(rtodbl( invr(subsr(1, dblexp(radii[i]))) )); param += t; if (t > 1.) param2 += log2(t); } *par = param; *par2 = param2; } /* apply the conformal mapping then split from U */ static void conformal_mapping(double *radii, GEN ctr, GEN p, long k, long bit, double aux, GEN *F,GEN *G) { long bit2, n = degpol(p), i; pari_sp ltop = avma, av; GEN q, FF, GG, a, R; double lrho, delta, param, param2; /* n * (2.*log2(2.732)+log2(1.5)) + 1 */ bit2 = bit + (long)(n*3.4848775) + 1; a = sqrtr_abs( stor(3, 2*MEDDEFAULTPREC - 2) ); a = divrs(a, -6); a = gmul(mygprec(a,bit2), mygprec(ctr,bit2)); /* a = -ctr/2sqrt(3) */ av = avma; q = conformal_pol(mygprec(p,bit2), a); for (i=1; i<=n; i++) if (radii[i] != UNDEF) /* update array radii */ { pari_sp av2 = avma; GEN t, r = dblexp(radii[i]), r2 = sqrr(r); /* 2(r^2 - 1) / (r^2 - 3(r-1)) */ t = divrr(shiftr((subrs(r2,1)),1), subrr(r2, mulur(3,subrs(r,1)))); radii[i] = mydbllogr(addsr(1,t)) / 2; avma = av2; } lrho = logradius(radii, q,k,aux/10., &delta); update_radius(n, radii, lrho, ¶m, ¶m2); bit2 += (long)(n * fabs(lrho)/M_LN2 + 1.); R = mygprec(dblexp(-lrho), bit2); q = scalepol(q,R,bit2); gerepileall(av,2, &q,&R); optimize_split(q,k,delta,bit2,&FF,&GG,param,param2); bit2 += n; R = invr(R); FF = scalepol(FF,R,bit2); GG = scalepol(GG,R,bit2); a = mygprec(a,bit2); FF = conformal_pol(FF,a); GG = conformal_pol(GG,a); a = invr(subsr(1, gnorm(a))); FF = RgX_Rg_mul(FF, powru(a,k)); GG = RgX_Rg_mul(GG, powru(a,n-k)); *F = mygprec(FF,bit+n); *G = mygprec(GG,bit+n); gerepileall(ltop,2, F,G); } /* split p, this time without scaling. returns in F and G two polynomials * such that |p-FG|< 2^(-bit)|p| */ static void split_2(GEN p, long bit, GEN ctr, double thickness, GEN *F, GEN *G) { GEN q, FF, GG, R; double aux, delta, param, param2; long n = degpol(p), i, j, k, bit2; double lrmin, lrmax, lrho, *radii; radii = (double*) stack_malloc_align((n+1) * sizeof(double), sizeof(double)); for (i=2; i i+1) { if (i+j == n+1) lrho = (lrmin + lrmax) / 2; else { double kappa = 2. - log(1. + minss(i,n-j)) / log(1. + minss(j,n-i)); if (i+j < n+1) lrho = lrmax * kappa + lrmin; else lrho = lrmin * kappa + lrmax; lrho /= 1+kappa; } aux = (lrmax - lrmin) / (4*(j-i)); k = dual_modulus(p, lrho, aux, minss(i,n+1-j)); if (k-i < j-k-1 || (k-i == j-k-1 && 2*k > n)) { lrmax = lrho; j=k+1; radii[j] = lrho - aux; } else { lrmin = lrho; i=k; radii[i] = lrho + aux; } } aux = lrmax - lrmin; if (ctr) { lrho = (lrmax + lrmin) / 2; for (i=1; i<=n; i++) if (radii[i] != UNDEF) radii[i] -= lrho; bit2 = bit + (long)(n * fabs(lrho)/M_LN2 + 1.); R = mygprec(dblexp(-lrho), bit2); q = scalepol(p,R,bit2); conformal_mapping(radii, ctr, q, k, bit2, aux, &FF, &GG); } else { lrho = logradius(radii, p, k, aux/10., &delta); update_radius(n, radii, lrho, ¶m, ¶m2); bit2 = bit + (long)(n * fabs(lrho)/M_LN2 + 1.); R = mygprec(dblexp(-lrho), bit2); q = scalepol(p,R,bit2); optimize_split(q, k, delta, bit2, &FF, &GG, param, param2); } bit += n; bit2 += n; R = invr(mygprec(R,bit2)); *F = mygprec(scalepol(FF,R,bit2), bit); *G = mygprec(scalepol(GG,R,bit2), bit); } /* procedure corresponding to steps 5,6,.. page 44 in RR n. 1852 */ /* put in F and G two polynomial such that |p-FG|<2^(-bit)|p| * where the maximum modulus of the roots of p is <=1. * Assume sum of roots is 0. */ static void split_1(GEN p, long bit, GEN *F, GEN *G) { long i, imax, n = degpol(p), polreal = isreal(p), ep = gexpo(p), bit2 = bit+n; GEN ctr, q, qq, FF, GG, v, gr, r, newq; double lrmin, lrmax, lthick; const double LOG3 = 1.098613; lrmax = logmax_modulus(p, 0.01); gr = mygprec(dblexp(-lrmax), bit2); q = scalepol(p,gr,bit2); bit2 = bit + gexpo(q) - ep + (long)((double)n*2.*log2(3.)+1); v = cgetg(5,t_VEC); gel(v,1) = gen_2; gel(v,2) = gen_m2; gel(v,3) = mkcomplex(gen_0, gel(v,1)); gel(v,4) = mkcomplex(gen_0, gel(v,2)); q = mygprec(q,bit2); lthick = 0; newq = ctr = NULL; /* -Wall */ imax = polreal? 3: 4; for (i=1; i<=imax; i++) { qq = RgX_translate(q, gel(v,i)); lrmin = logmin_modulus(qq,0.05); if (LOG3 > lrmin + lthick) { double lquo = logmax_modulus(qq,0.05) - lrmin; if (lquo > lthick) { lthick = lquo; newq = qq; ctr = gel(v,i); } } if (lthick > M_LN2) break; if (polreal && i==2 && lthick > LOG3 - M_LN2) break; } bit2 = bit + gexpo(newq) - ep + (long)(n*LOG3/M_LN2 + 1); split_2(newq, bit2, ctr, lthick, &FF, &GG); r = gneg(mygprec(ctr,bit2)); FF = RgX_translate(FF,r); GG = RgX_translate(GG,r); gr = invr(gr); bit2 = bit - ep + gexpo(FF)+gexpo(GG); *F = scalepol(FF,gr,bit2); *G = scalepol(GG,gr,bit2); } /* put in F and G two polynomials such that |P-FG|<2^(-bit)|P|, where the maximum modulus of the roots of p is < 0.5 */ static int split_0_2(GEN p, long bit, GEN *F, GEN *G) { GEN q, b; long n = degpol(p), k, bit2, eq; double aux0 = dbllog2(gel(p,n+2)); /* != -oo */ double aux1 = dbllog2(gel(p,n+1)), aux; if (aux1 == -pariINFINITY) /* p1 = 0 */ aux = 0; else { aux = aux1 - aux0; /* log2(p1/p0) */ /* beware double overflow */ if (aux >= 0 && (aux > 1e4 || exp2(aux) > 2.5*n)) return 0; aux = (aux < -300)? 0.: n*log2(1 + exp2(aux)/(double)n); } bit2 = bit+1 + (long)(log2((double)n) + aux); q = mygprec(p,bit2); if (aux1 == -pariINFINITY) b = NULL; else { b = gdivgs(gdiv(gel(q,n+1),gel(q,n+2)),-n); q = RgX_translate(q,b); } gel(q,n+1) = gen_0; eq = gexpo(q); k = 0; while (k <= n/2 && (- gexpo(gel(q,k+2)) > bit2 + 2*(n-k) + eq || gequal0(gel(q,k+2)))) k++; if (k > 0) { if (k > n/2) k = n/2; bit2 += k<<1; *F = pol_xn(k, 0); *G = RgX_shift_shallow(q, -k); } else { split_1(q,bit2,F,G); bit2 = bit + gexpo(*F) + gexpo(*G) - gexpo(p) + (long)aux+1; *F = mygprec(*F,bit2); } *G = mygprec(*G,bit2); if (b) { GEN mb = mygprec(gneg(b), bit2); *F = RgX_translate(*F, mb); *G = RgX_translate(*G, mb); } return 1; } /* put in F and G two polynomials such that |P-FG|<2^(-bit)|P|. * Assume max_modulus(p) < 2 */ static void split_0_1(GEN p, long bit, GEN *F, GEN *G) { GEN FF, GG; long n, bit2, normp; if (split_0_2(p,bit,F,G)) return; normp = gexpo(p); scalepol2n(p,2); /* p := 4^(-n) p(4*x) */ n = degpol(p); bit2 = bit + 2*n + gexpo(p) - normp; split_1(mygprec(p,bit2), bit2,&FF,&GG); scalepol2n(FF,-2); scalepol2n(GG,-2); bit2 = bit + gexpo(FF) + gexpo(GG) - normp; *F = mygprec(FF,bit2); *G = mygprec(GG,bit2); } /* put in F and G two polynomials such that |P-FG|<2^(-bit)|P| */ static void split_0(GEN p, long bit, GEN *F, GEN *G) { const double LOG1_9 = 0.6418539; long n = degpol(p), k = 0; GEN q; while (gexpo(gel(p,k+2)) < -bit && k <= n/2) k++; if (k > 0) { if (k > n/2) k = n/2; *F = pol_xn(k, 0); *G = RgX_shift_shallow(p, -k); } else { double lr = logmax_modulus(p, 0.05); if (lr < LOG1_9) split_0_1(p, bit, F, G); else { q = RgX_recip_shallow(p); lr = logmax_modulus(q,0.05); if (lr < LOG1_9) { split_0_1(q, bit, F, G); *F = RgX_recip_shallow(*F); *G = RgX_recip_shallow(*G); } else split_2(p,bit,NULL, 1.2837,F,G); } } } /********************************************************************/ /** **/ /** ERROR ESTIMATE FOR THE ROOTS **/ /** **/ /********************************************************************/ static GEN root_error(long n, long k, GEN roots_pol, long err, GEN shatzle) { GEN rho, d, eps, epsbis, eps2, aux, rap = NULL; long i, j; d = cgetg(n+1,t_VEC); for (i=1; i<=n; i++) { if (i!=k) { aux = gsub(gel(roots_pol,i), gel(roots_pol,k)); gel(d,i) = gabs(mygprec(aux,31), DEFAULTPREC); } } rho = gabs(mygprec(gel(roots_pol,k),31), DEFAULTPREC); if (expo(rho) < 0) rho = real_1(DEFAULTPREC); eps = mulrr(rho, shatzle); aux = shiftr(powru(rho,n), err); for (j=1; j<=2 || (j<=5 && cmprr(rap, dbltor(1.2)) > 0); j++) { GEN prod = NULL; /* 1. */ long m = n; epsbis = mulrr(eps, dbltor(1.25)); for (i=1; i<=n; i++) { if (i != k && cmprr(gel(d,i),epsbis) > 0) { GEN dif = subrr(gel(d,i),eps); prod = prod? mulrr(prod, dif): dif; m--; } } eps2 = prod? divrr(aux, prod): aux; if (m > 1) eps2 = sqrtnr(shiftr(eps2, 2*m-2), m); rap = divrr(eps,eps2); eps = eps2; } return eps; } /* round a complex or real number x to an absolute value of 2^(-bit) */ static GEN mygprec_absolute(GEN x, long bit) { long e; GEN y; switch(typ(x)) { case t_REAL: e = expo(x) + bit; return (e <= 0 || !signe(x))? real_0_bit(-bit): rtor(x, nbits2prec(e)); case t_COMPLEX: if (gexpo(gel(x,2)) < -bit) return mygprec_absolute(gel(x,1),bit); y = cgetg(3,t_COMPLEX); gel(y,1) = mygprec_absolute(gel(x,1),bit); gel(y,2) = mygprec_absolute(gel(x,2),bit); return y; default: return x; } } static long a_posteriori_errors(GEN p, GEN roots_pol, long err) { long i, n = degpol(p), e_max = -(long)EXPOBITS; GEN sigma, shatzle; err += (long)log2((double)n) + 1; if (err > -2) return 0; sigma = real2n(-err, LOWDEFAULTPREC); /* 2 / ((s - 1)^(1/n) - 1) */ shatzle = divur(2, subrs(sqrtnr(subrs(sigma,1),n), 1)); for (i=1; i<=n; i++) { pari_sp av = avma; GEN x = root_error(n,i,roots_pol,err,shatzle); long e = gexpo(x); avma = av; if (e > e_max) e_max = e; gel(roots_pol,i) = mygprec_absolute(gel(roots_pol,i), -e); } return e_max; } /********************************************************************/ /** **/ /** MAIN **/ /** **/ /********************************************************************/ static GEN append_clone(GEN r, GEN a) { a = gclone(a); vectrunc_append(r, a); return a; } /* put roots in placeholder roots_pol so that |P - L_1...L_n| < 2^(-bit)|P| * returns prod (x-roots_pol[i]) */ static GEN split_complete(GEN p, long bit, GEN roots_pol) { long n = degpol(p); pari_sp ltop; GEN p1, F, G, a, b, m1, m2; if (n == 1) { a = gneg_i(gdiv(gel(p,2), gel(p,3))); (void)append_clone(roots_pol,a); return p; } ltop = avma; if (n == 2) { F = gsub(gsqr(gel(p,3)), gmul2n(gmul(gel(p,2),gel(p,4)), 2)); F = gsqrt(F, nbits2prec(bit)); p1 = ginv(gmul2n(gel(p,4),1)); a = gneg_i(gmul(gadd(F,gel(p,3)), p1)); b = gmul(gsub(F,gel(p,3)), p1); a = append_clone(roots_pol,a); b = append_clone(roots_pol,b); avma = ltop; a = mygprec(a, 3*bit); b = mygprec(b, 3*bit); return gmul(gel(p,4), mkpoln(3, gen_1, gneg(gadd(a,b)), gmul(a,b))); } split_0(p,bit,&F,&G); m1 = split_complete(F,bit,roots_pol); m2 = split_complete(G,bit,roots_pol); return gerepileupto(ltop, gmul(m1,m2)); } static GEN quicktofp(GEN x) { const long prec = DEFAULTPREC; switch(typ(x)) { case t_INT: return itor(x, prec); case t_REAL: return rtor(x, prec); case t_FRAC: return fractor(x, prec); case t_COMPLEX: { GEN a = gel(x,1), b = gel(x,2); /* avoid problem with 0, e.g. x = 0 + I*1e-100. We don't want |x| = 0. */ if (isintzero(a)) return cxcompotor(b, prec); if (isintzero(b)) return cxcompotor(a, prec); a = cxcompotor(a, prec); b = cxcompotor(b, prec); return sqrtr(addrr(sqrr(a), sqrr(b))); } default: pari_err_TYPE("quicktofp",x); return NULL;/*LCOV_EXCL_LINE*/ } } /* bound log_2 |largest root of p| (Fujiwara's bound) */ double fujiwara_bound(GEN p) { pari_sp av = avma; long i, n = degpol(p); GEN cc; double loglc, Lmax; if (n <= 0) pari_err_CONSTPOL("fujiwara_bound"); loglc = mydbllog2r( quicktofp(gel(p,n+2)) ); /* log_2 |lc(p)| */ cc = gel(p, 2); if (gequal0(cc)) Lmax = -pariINFINITY-1; else Lmax = (mydbllog2r(quicktofp(cc)) - loglc - 1) / n; for (i = 1; i < n; i++) { GEN y = gel(p,i+2); double L; if (gequal0(y)) continue; L = (mydbllog2r(quicktofp(y)) - loglc) / (n-i); if (L > Lmax) Lmax = L; } avma = av; return Lmax + 1; } /* Fujiwara's bound, real roots. Based on the following remark: if * p = x^n + sum a_i x^i and q = x^n + sum min(a_i,0)x^i * then for all x >= 0, p(x) >= q(x). Thus any bound for the (positive) roots * of q is a bound for the positive roots of p. */ double fujiwara_bound_real(GEN p, long sign) { pari_sp av = avma; GEN x; long n = degpol(p), i, signodd, signeven; double fb; if (n <= 0) pari_err_CONSTPOL("fujiwara_bound"); x = shallowcopy(p); if (gsigne(gel(x, n+2)) > 0) { signeven = 1; signodd = sign; } else { signeven = -1; signodd = -sign; } for (i = 0; i < n; i++) { if ((n - i) % 2) { if (gsigne(gel(x, i+2)) == signodd ) gel(x, i+2) = gen_0; } else { if (gsigne(gel(x, i+2)) == signeven) gel(x, i+2) = gen_0; } } fb = fujiwara_bound(x); avma = av; return fb; } static GEN mygprecrc_special(GEN x, long prec, long e) { GEN y; switch(typ(x)) { case t_REAL: if (!signe(x)) return real_0_bit(minss(e, expo(x))); return (prec > realprec(x))? rtor(x, prec): x; case t_COMPLEX: y = cgetg(3,t_COMPLEX); gel(y,1) = mygprecrc_special(gel(x,1),prec,e); gel(y,2) = mygprecrc_special(gel(x,2),prec,e); return y; default: return x; } } /* like mygprec but keep at least the same precision as before */ static GEN mygprec_special(GEN x, long bit) { long lx, i, e, prec; GEN y; if (bit < 0) bit = 0; /* should not happen */ e = gexpo(x) - bit; prec = nbits2prec(bit); switch(typ(x)) { case t_POL: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i 1) m = gmul(m,lc); e = gexpo(gsub(q, m)) - gexpo(lc) + (long)log2((double)n) + 1; if (e < -2*bit2) e = -2*bit2; /* avoid e = -pariINFINITY */ if (e < 0) { e = bit + a_posteriori_errors(p,roots_pol,e); if (e < 0) return roots_pol; } if (DEBUGLEVEL > 7) err_printf("all_roots: restarting, i = %ld, e = %ld\n", i,e); } } INLINE int isexactscalar(GEN x) { long tx = typ(x); return is_rational_t(tx); } static int isexactpol(GEN p) { long i,n = degpol(p); for (i=0; i<=n; i++) if (!isexactscalar(gel(p,i+2))) return 0; return 1; } static GEN solve_exact_pol(GEN p, long bit) { long i, j, k, m, n = degpol(p), iroots = 0; GEN ex, factors, v = zerovec(n); factors = ZX_squff(Q_primpart(p), &ex); for (i=1; i= e) return -1; /* |Im x| ~ |Im y| ~ 0 */ } else if (!syi) { if (sxi && expo(xi) >= e) return 1; /* |Im x| ~ |Im y| ~ 0 */ } else { long sz; z = addrr_sign(xi, 1, yi, -1); sz = signe(z); if (sz && expo(z) >= e) return (int)sz; } /* |Im x| ~ |Im y|, sort according to real parts */ z = subrr(xr, yr); if (expo(z) >= e) return (int)signe(z); /* Re x ~ Re y. Place negative absolute value before positive */ return (int) (sxi - syi); } static GEN clean_roots(GEN L, long l, long bit, long clean) { long i, n = lg(L), ex = 5 - bit; GEN res = cgetg(n,t_COL); for (i=1; i 3? all_roots(Q_primpart(p), bit): cgetg(1,t_COL); if (v) L = shallowconcat(const_vec(v, real_0_bit(-bit)), L); return gerepileupto(av, clean_roots(L, l, bit, 1)); } /********************************************************************/ /** **/ /** REAL ROOTS OF INTEGER POLYNOMIAL **/ /** **/ /********************************************************************/ /* Count sign changes in the coefficients of (x+1)^deg(P)*P(1/(x+1)) * The inversion is implicit (we take coefficients backwards). Roots of P * at 0 and 1 (mapped to oo and 0) are ignored here and must be dealt with * by the caller. Set root1 if P(1) = 0 */ static long X2XP1(GEN P, long deg, int *root1, GEN *Premapped) { const pari_sp av = avma; GEN v = shallowcopy(P); long i, j, vlim, nb, s; for (i = 0, vlim = deg+2;;) { for (j = 2; j < vlim; j++) gel(v, j+1) = addii(gel(v, j), gel(v, j+1)); s = -signe(gel(v, vlim)); vlim--; i++; if (s) break; } if (vlim == deg+1) *root1 = 0; else { *root1 = 1; if (Premapped) setlg(v, vlim + 2); } nb = 0; for (; i < deg; i++) { long s2 = -signe(gel(v, 2)); int flag = (s2 == s); for (j = 2; j < vlim; j++) { gel(v, j+1) = addii(gel(v, j), gel(v, j+1)); if (flag) flag = (s2 != signe(gel(v, j+1))); } if (s == signe(gel(v, vlim))) { if (++nb >= 2) { avma = av; return 2; } s = -s; } /* if flag is set there will be no further sign changes */ if (flag && (!Premapped || !nb)) goto END; vlim--; if (gc_needed(av, 3)) { if (DEBUGMEM>1) pari_warn(warnmem, "X2XP1, i = %ld/%ld", i, deg-1); if (!Premapped) setlg(v, vlim + 2); v = gerepilecopy(av, v); } } if (vlim >= 2 && s == signe(gel(v, vlim))) nb++; END: if (Premapped && nb == 1) *Premapped = v; else avma = av; return nb; } static long _intervalcmp(GEN x, GEN y) { if (typ(x) == t_VEC) x = gel(x, 1); if (typ(y) == t_VEC) y = gel(y, 1); return gcmp(x, y); } static GEN _gen_nored(void *E, GEN x) { (void)E; return x; } static GEN _mp_add(void *E, GEN x, GEN y) { (void)E; return mpadd(x, y); } static GEN _mp_sub(void *E, GEN x, GEN y) { (void)E; return mpsub(x, y); } static GEN _mp_mul(void *E, GEN x, GEN y) { (void)E; return mpmul(x, y); } static GEN _mp_sqr(void *E, GEN x) { (void)E; return mpsqr(x); } static GEN _gen_one(void *E) { (void)E; return gen_1; } static GEN _gen_zero(void *E) { (void)E; return gen_0; } static struct bb_algebra mp_algebra = { _gen_nored, _mp_add, _mp_sub, _mp_mul, _mp_sqr, _gen_one, _gen_zero }; static GEN _mp_cmul(void *E, GEN P, long a, GEN x) {(void)E; return mpmul(gel(P,a+2), x);} /* Split the polynom P in two parts, whose coeffs have constant sign: * P(X) = X^D*Pp + Pm. Also compute the two parts of the derivative of P, * Pprimem = Pm', Pprimep = X*Pp'+ D*Pp => P' = X^(D-1)*Pprimep + Pprimem; * Pprimep[i] = (i+D) Pp[i]. Return D */ static long split_pols(GEN P, GEN *pPp, GEN *pPm, GEN *pPprimep, GEN *pPprimem) { long i, D, dP = degpol(P), s0 = signe(gel(P,2)); GEN Pp, Pm, Pprimep, Pprimem; for(i=1; i <= dP; i++) if (signe(gel(P, i+2)) == -s0) break; D = i; Pm = cgetg(D + 2, t_POL); Pprimem = cgetg(D + 1, t_POL); Pp = cgetg(dP-D + 3, t_POL); Pprimep = cgetg(dP-D + 3, t_POL); Pm[1] = Pp[1] = Pprimem[1] = Pprimep[1] = P[1]; for(i=0; i < D; i++) { GEN c = gel(P, i+2); gel(Pm, i+2) = c; if (i) gel(Pprimem, i+1) = mului(i, c); } for(; i <= dP; i++) { GEN c = gel(P, i+2); gel(Pp, i+2-D) = c; gel(Pprimep, i+2-D) = mului(i, c); } *pPm = normalizepol_lg(Pm, D+2); *pPprimem = normalizepol_lg(Pprimem, D+1); *pPp = normalizepol_lg(Pp, dP-D+3); *pPprimep = normalizepol_lg(Pprimep, dP-D+3); return dP - degpol(*pPp); } static GEN bkeval_single_power(long d, GEN V) { long mp = lg(V) - 2; if (d > mp) return gmul(gpowgs(gel(V, mp+1), d/mp), gel(V, (d%mp)+1)); return gel(V, d+1); } static GEN splitpoleval(GEN Pp, GEN Pm, GEN pows, long D, long bitprec) { GEN vp = gen_bkeval_powers(Pp, degpol(Pp), pows, NULL, &mp_algebra, _mp_cmul); GEN vm = gen_bkeval_powers(Pm, degpol(Pm), pows, NULL, &mp_algebra, _mp_cmul); GEN xa = bkeval_single_power(D, pows); GEN r; if (!signe(vp)) return vm; vp = gmul(vp, xa); r = gadd(vp, vm); if (gexpo(vp) - (signe(r)? gexpo(r): 0) > prec2nbits(realprec(vp)) - bitprec) return NULL; return r; } /* optimized Cauchy bound for P = X^D*Pp + Pm, D > deg(Pm) */ static GEN splitcauchy(GEN Pp, GEN Pm, long prec) { GEN S = gel(Pp,2), A = gel(Pm,2); long i, lPm = lg(Pm), lPp = lg(Pp); for (i=3; i < lPm; i++) { GEN c = gel(Pm,i); if (abscmpii(A, c) < 0) A = c; } for (i=3; i < lPp; i++) S = addii(S, gel(Pp, i)); return subsr(1, rdivii(A, S, prec)); /* 1 + |Pm|_oo / |Pp|_1 */ } /* Newton for polynom P, P(0)!=0, with unique sign change => one root in ]0,oo[ * P' has also at most one zero there */ static GEN polsolve(GEN P, long bitprec) { pari_sp av = avma, av2; GEN Pp, Pm, Pprimep, Pprimem, Pprime, Pprime2, ra, rb, rc, Pc; long deg = degpol(P); long expoold = LONG_MAX, cprec = DEFAULTPREC, prec = nbits2prec(bitprec); long iter, D, rt, s0, bitaddprec, addprec; if (deg == 1) return gerepileuptoleaf(av, rdivii(negi(gel(P,2)), gel(P,3), prec)); Pprime = ZX_deriv(P); Pprime2 = ZX_deriv(Pprime); bitaddprec = 1 + 2*expu(deg); addprec = nbits2prec(bitaddprec); D = split_pols(P, &Pp, &Pm, &Pprimep, &Pprimem); /* P = X^D*Pp + Pm */ s0 = signe(gel(P, 2)); rt = maxss(D, brent_kung_optpow(maxss(degpol(Pp), degpol(Pm)), 2, 1)); rb = splitcauchy(Pp, Pm, DEFAULTPREC); for(;;) { GEN pows = gen_powers(rb, rt, 1, NULL, _mp_sqr, _mp_mul, _gen_one); Pc = splitpoleval(Pp, Pm, pows, D, bitaddprec); if (!Pc) { cprec++; rb = rtor(rb, cprec); continue; } if (signe(Pc) != s0) break; shiftr_inplace(rb,1); } ra = NULL; iter = 0; for(;;) { GEN wdth; iter++; if (ra) rc = shiftr(addrr(ra, rb), -1); else rc = shiftr(rb, -1); do { GEN pows = gen_powers(rc, rt, 1, NULL, _mp_sqr, _mp_mul, _gen_one); Pc = splitpoleval(Pp, Pm, pows, D, bitaddprec+2); if (Pc) break; cprec++; rc = rtor(rc, cprec); } while (1); if (signe(Pc) == s0) ra = rc; else rb = rc; if (!ra) continue; wdth = subrr(rb, ra); if (!(iter % 8)) { GEN m1 = poleval(Pprime, ra), M2; if (signe(m1) == s0) continue; M2 = poleval(Pprime2, rb); if (abscmprr(gmul(M2, wdth), shiftr(m1, 1)) > 0) continue; break; } else if (gexpo(wdth) <= -bitprec) break; } rc = rb; av2 = avma; for(;; rc = gerepileuptoleaf(av2, rc)) { long exponew; GEN Ppc, dist, rcold = rc; GEN pows = gen_powers(rc, rt, 1, NULL, _mp_sqr, _mp_mul, _gen_one); Ppc = splitpoleval(Pprimep, Pprimem, pows, D-1, bitaddprec+4); if (Ppc) Pc = splitpoleval(Pp, Pm, pows, D, bitaddprec+4); if (!Ppc || !Pc) { if (cprec >= prec+addprec) cprec += EXTRAPRECWORD; else cprec = minss(2*cprec, prec+addprec); rc = rtor(rc, cprec); continue; /* backtrack one step */ } dist = typ(Ppc) == t_REAL? divrr(Pc, Ppc): divri(Pc, Ppc); rc = subrr(rc, dist); if (cmprr(ra, rc) > 0 || cmprr(rb, rc) < 0) { if (cprec >= prec+addprec) break; cprec = minss(2*cprec, prec+addprec); rc = rtor(rcold, cprec); continue; /* backtrack one step */ } if (expoold == LONG_MAX) { expoold = expo(dist); continue; } exponew = expo(dist); if (exponew < -bitprec - 1) { if (cprec >= prec+addprec) break; cprec = minss(2*cprec, prec+addprec); rc = rtor(rc, cprec); continue; } if (exponew > expoold - 2) { if (cprec >= prec+addprec) break; expoold = LONG_MAX; cprec = minss(2*cprec, prec+addprec); rc = rtor(rc, cprec); continue; } expoold = exponew; } return gerepileuptoleaf(av, rtor(rc, prec)); } static GEN usp(GEN Q0, long deg, long flag, long bitprec) { const pari_sp av = avma; GEN Q, sol, c, Lc, Lk; long listsize = 64, nbr = 0, nb_todo, ind, deg0, indf, i, k, nb; sol = zerocol(deg); deg0 = deg; Lc = zerovec(listsize); Lk = cgetg(listsize+1, t_VECSMALL); c = gen_0; k = Lk[1] = 0; ind = 1; indf = 2; Q = leafcopy(Q0); nb_todo = 1; while (nb_todo) { GEN nc = gel(Lc, ind), Qremapped; pari_sp av2; int root1; if (Lk[ind] == k + 1) { deg0 = deg; setlg(Q0, deg + 3); Q0 = ZX_rescale2n(Q0, 1); Q = Q_primpart(Q0); c = gen_0; } if (!equalii(nc, c)) Q = ZX_translate(Q, subii(nc, c)); k = Lk[ind]; c = nc; ind++; nb_todo--; if (equalii(gel(Q, 2), gen_0)) { /* Q(0) = 0 */ GEN s = gmul2n(c, -k); long j; for (j = 1; j <= nbr; j++) if (gequal(gel(sol, j), s)) break; if (j > nbr) gel(sol, ++nbr) = s; deg0--; for (j = 2; j <= deg0 + 2; j++) gel(Q, j) = gel(Q, j+1); setlg(Q, j); } av2 = avma; nb = X2XP1(Q, deg0, &root1, flag == 1 ? &Qremapped : NULL); if (nb == 0) /* no root in this open interval */; else if (nb == 1) /* exactly one root */ { GEN s = gen_0; if (flag == 0) s = mkvec2(gmul2n(c,-k), gmul2n(addiu(c,1),-k)); else if (flag == 1) /* Caveat: Qremapped is the reciprocal polynomial */ { s = polsolve(Qremapped, bitprec+1); s = divrr(s, addsr(1, s)); s = gmul2n(addir(c, s), -k); s = rtor(s, nbits2prec(bitprec)); } gel(sol, ++nbr) = gerepileupto(av2, s); } else { /* unknown, add two nodes to refine */ if (indf + 2 > listsize) { if (ind>1) { for (i = ind; i < indf; i++) { gel(Lc, i-ind+1) = gel(Lc, i); Lk[i-ind+1] = Lk[i]; } indf -= ind-1; ind = 1; } if (indf + 2 > listsize) { listsize *= 2; Lc = vec_lengthen(Lc, listsize); Lk = vecsmall_lengthen(Lk, listsize); } for (i = indf; i <= listsize; i++) gel(Lc, i) = gen_0; } nc = shifti(c, 1); gel(Lc, indf) = nc; gel(Lc, indf + 1) = addiu(nc, 1); Lk[indf] = Lk[indf + 1] = k + 1; indf += 2; nb_todo += 2; } if (root1) { /* Q(1) = 0 */ GEN s = gmul2n(addiu(c,1), -k); long j; for (j = 1; j <= nbr; j++) if (gequal(gel(sol, j), s)) break; if (j > nbr) gel(sol, ++nbr) = s; } if (gc_needed(av, 2)) { gerepileall(av, 6, &Q0, &Q, &c, &Lc, &Lk, &sol); if (DEBUGMEM > 1) pari_warn(warnmem, "ZX_Uspensky", avma); } } setlg(sol, nbr+1); return gerepilecopy(av, sol); } static GEN ZX_Uspensky_cst_pol(long nbz, long flag, long bitprec) { switch(flag) { case 0: return zerocol(nbz); case 1: retconst_col(nbz, real_0_bit(-bitprec)); default: return utoi(nbz); } } /* ZX_Uspensky(P, [a,a], flag) */ static GEN ZX_Uspensky_equal(GEN P, GEN a, long flag) { if (typ(a) != t_INFINITY && gequal0(poleval(P, a))) return flag <= 1 ? mkcol(a): gen_1; else return flag <= 1 ? cgetg(1, t_COL) : gen_0; } GEN ZX_Uspensky(GEN P, GEN ab, long flag, long bitprec) { pari_sp av = avma; GEN a, b, sol = NULL, Pcur; double fb; long nbz, deg; deg = degpol(P); if (deg == 0) return flag <= 1 ? cgetg(1, t_COL) : gen_0; if (ab) { if (typ(ab) == t_VEC) { if (lg(ab) != 3) pari_err_DIM("ZX_Uspensky"); a = gel(ab, 1); b = gel(ab, 2); } else { a = ab; b = mkoo(); } } else { a = mkmoo(); b = mkoo(); } switch (gcmp(a, b)) { case 1: avma = av; return flag <= 1 ? cgetg(1, t_COL) : gen_0; case 0: return gerepilecopy(av, ZX_Uspensky_equal(P, a, flag)); } nbz = ZX_valrem(P, &Pcur); deg -= nbz; if (!nbz) Pcur = P; if (nbz && (gsigne(a) > 0 || gsigne(b) < 0)) nbz = 0; if (deg == 0) { avma = av; return ZX_Uspensky_cst_pol(nbz, flag, bitprec); } if (deg == 1) { sol = gdiv(gneg(gel(Pcur, 2)), pollead(Pcur, -1)); if (gcmp(a, sol) > 0 || gcmp(sol, b) > 0) { avma = av; return ZX_Uspensky_cst_pol(nbz, flag, bitprec); } if (flag >= 2) { avma = av; return utoi(nbz+1); } sol = gconcat(zerocol(nbz), mkcol(sol)); if (flag == 1) sol = RgC_gtofp(sol, nbits2prec(bitprec)); return gerepilecopy(av, sol); } switch(flag) { case 0: sol = zerocol(nbz); break; case 1: sol = const_col(nbz, real_0_bit(-bitprec)); break; /* case 2: nothing */ } if (typ(a) == t_INFINITY && typ(b) != t_INFINITY && gsigne(b)) { fb = fujiwara_bound_real(Pcur, -1); if (fb <= -pariINFINITY) a = gen_0; else if (fb < 0) a = gen_m1; else a = negi(int2n((long)ceil(fb))); } if (typ(b) == t_INFINITY && typ(a) != t_INFINITY && gsigne(a)) { fb = fujiwara_bound_real(Pcur, 1); if (fb <= -pariINFINITY) b = gen_0; else if (fb < 0) b = gen_1; else b = int2n((long)ceil(fb)); } if (typ(a) != t_INFINITY && typ(b) != t_INFINITY) { GEN den, diff, unscaledres, co, Pdiv, ascaled; pari_sp av1; long i; if (gequal(a,b)) /* can occur if one of a,b was initially a t_INFINITY */ return gerepilecopy(av, ZX_Uspensky_equal(P, a, flag)); den = lcmii(Q_denom(a), Q_denom(b)); if (!is_pm1(den)) { Pcur = ZX_rescale(Pcur, den); ascaled = gmul(a, den); } else { den = NULL; ascaled = a; } diff = subii(den ? gmul(b,den) : b, ascaled); Pcur = ZX_unscale(ZX_translate(Pcur, ascaled), diff); av1 = avma; Pdiv = cgetg(deg+2, t_POL); Pdiv[1] = Pcur[1]; co = gel(Pcur, deg+2); for (i = deg; --i >= 0; ) { gel(Pdiv, i+2) = co; co = addii(co, gel(Pcur, i+2)); } if (!signe(co)) { Pcur = Pdiv; deg--; if (flag <= 1) sol = gconcat(sol, b); else nbz++; } else avma = av1; unscaledres = usp(Pcur, deg, flag, bitprec); if (flag <= 1) { for (i = 1; i < lg(unscaledres); i++) { GEN z = gmul(diff, gel(unscaledres, i)); if (typ(z) == t_VEC) { gel(z, 1) = gadd(ascaled, gel(z, 1)); gel(z, 2) = gadd(ascaled, gel(z, 2)); } else z = gadd(ascaled, z); if (den) z = gdiv(z, den); gel(unscaledres, i) = z; } sol = gconcat(sol, unscaledres); } else nbz += lg(unscaledres) - 1; } if (typ(b) == t_INFINITY && (fb=fujiwara_bound_real(Pcur, 1)) > -pariINFINITY) { GEN Pcurp, unscaledres; long bp = (long)ceil(fb); if (bp < 0) bp = 0; Pcurp = ZX_unscale2n(Pcur, bp); unscaledres = usp(Pcurp, deg, flag, bitprec); if (flag <= 1) sol = shallowconcat(sol, gmul2n(unscaledres, bp)); else nbz += lg(unscaledres)-1; } if (typ(a) == t_INFINITY && (fb=fujiwara_bound_real(Pcur,-1)) > -pariINFINITY) { GEN Pcurm, unscaledres; long i, bm = (long)ceil(fb); if (bm < 0) bm = 0; Pcurm = ZX_unscale2n(ZX_z_unscale(Pcur, -1), bm); unscaledres = usp(Pcurm, deg, flag, bitprec); if (flag <= 1) { for (i = 1; i < lg(unscaledres); i++) { GEN z = gneg(gmul2n(gel(unscaledres, i), bm)); if (typ(z) == t_VEC) swap(gel(z, 1), gel(z, 2)); gel(unscaledres, i) = z; } sol = shallowconcat(unscaledres, sol); } else nbz += lg(unscaledres)-1; } if (flag >= 2) return utoi(nbz); if (flag) sol = sort(sol); else sol = gen_sort(sol, (void *)_intervalcmp, cmp_nodata); return gerepileupto(av, sol); } /* x a scalar */ static GEN rootsdeg0(GEN x) { if (!is_real_t(typ(x))) pari_err_TYPE("realroots",x); if (gequal0(x)) pari_err_ROOTS0("realroots"); return cgetg(1,t_COL); /* constant polynomial */ } static void checkbound(GEN a) { switch(typ(a)) { case t_INT: case t_FRAC: case t_INFINITY: break; default: pari_err_TYPE("polrealroots", a); } } static GEN check_ab(GEN ab) { GEN a, b; if (!ab) return NULL; if (typ(ab) != t_VEC || lg(ab) != 3) pari_err_TYPE("polrootsreal",ab); a = gel(ab,1); checkbound(a); b = gel(ab,2); checkbound(b); if (typ(a) == t_INFINITY && inf_get_sign(a) < 0 && typ(b) == t_INFINITY && inf_get_sign(b) > 0) ab = NULL; return ab; } GEN realroots(GEN P, GEN ab, long prec) { pari_sp av = avma; long nrr = 0; GEN sol = NULL, fa, ex; long i, j, v; ab = check_ab(ab); if (typ(P) != t_POL) return rootsdeg0(P); switch(degpol(P)) { case -1: return rootsdeg0(gen_0); case 0: return rootsdeg0(gel(P,2)); } if (!RgX_is_ZX(P)) P = RgX_rescale_to_int(P); P = Q_primpart(P); v = ZX_valrem(P,&P); if (v && (!ab || (gsigne(gel(ab,1)) <= 0 && gsigne(gel(ab,2)) >= 0))) sol = const_col(v, real_0(prec)); fa = ZX_squff(P, &ex); for (i = 1; i < lg(fa); i++) { GEN Pi = gel(fa, i), soli, soli2 = NULL; long n, nrri = 0, h; if (ab) h = 1; else Pi = ZX_deflate_max(Pi, &h); soli = ZX_Uspensky(Pi, h%2 ? ab: gen_0, 1, prec2nbits(prec)); n = lg(soli); if (!(h % 2)) soli2 = cgetg(n, t_COL); for (j = 1; j < n; j++) { GEN elt = gel(soli, j); /* != 0 */ if (typ(elt) != t_REAL) { nrri++; if (h > 1 && !(h % 2)) nrri++; elt = gtofp(elt, prec); gel(soli, j) = elt; } if (h > 1) { GEN r; if (h == 2) r = sqrtr(elt); else { if (signe(elt) < 0) r = negr(sqrtnr(negr(elt), h)); else r = sqrtnr(elt, h); } gel(soli, j) = r; if (!(h % 2)) gel(soli2, j) = negr(r); } } if (!(h % 2)) soli = shallowconcat(soli, soli2); if (ex[i] > 1) soli = shallowconcat1( const_vec(ex[i], soli) ); sol = sol? shallowconcat(sol, soli): soli; nrr += ex[i]*nrri; } if (!sol) { avma = av; return cgetg(1,t_COL); } if (DEBUGLEVEL > 4) { err_printf("Number of real roots: %d\n", lg(sol)-1); err_printf(" -- of which 2-integral: %ld\n", nrr); } return gerepileupto(av, sort(sol)); } /* P non-constant, squarefree ZX */ long ZX_sturm(GEN P) { pari_sp av = avma; long h, r; P = ZX_deflate_max(P, &h); if (odd(h)) r = itos(ZX_Uspensky(P, NULL, 2, 0)); else r = 2*itos(ZX_Uspensky(P, gen_0, 2, 0)); avma = av; return r; } /* P non-constant, squarefree ZX */ long ZX_sturmpart(GEN P, GEN ab) { pari_sp av = avma; long r; if (!check_ab(ab)) return ZX_sturm(P); r = itos(ZX_Uspensky(P, ab, 2, 0)); avma = av; return r; } pari-2.11.2/src/basemath/gen1.c0000644000175000017500000025556513457700327014561 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** GENERIC OPERATIONS **/ /** (first part) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /* assume z[1] was created last */ #define fix_frac_if_int(z) if (equali1(gel(z,2)))\ z = gerepileupto((pari_sp)(z+3), gel(z,1)); /* assume z[1] was created last */ #define fix_frac_if_int_GC(z,tetpil) { if (equali1(gel(z,2)))\ z = gerepileupto((pari_sp)(z+3), gel(z,1));\ else\ gerepilecoeffssp((pari_sp)z, tetpil, z+1, 2); } static void warn_coercion(GEN x, GEN y, GEN z) { if (DEBUGLEVEL) pari_warn(warner,"coercing quotient rings; moduli %Ps and %Ps -> %Ps",x,y,z); } static long kro_quad(GEN x, GEN y) { pari_sp av=avma; long k = kronecker(quad_disc(x), y); avma = av; return k; } /* is -1 not a square in Zp, assume p prime */ INLINE int Zp_nosquare_m1(GEN p) { return (mod4(p) & 2); /* 2 or 3 mod 4 */ } static GEN addsub_pp(GEN x, GEN y, GEN(*op)(GEN,GEN)); static GEN addsub_frac(GEN x, GEN y, GEN (*op)(GEN,GEN)); static GEN mulpp(GEN x, GEN y); static GEN divpp(GEN x, GEN y); /* Argument codes for inline routines * c: complex, p: padic, q: quad, f: floating point (REAL, some complex) * R: without imaginary part (INT, REAL, INTMOD, FRAC, PADIC if -1 not square) * T: some type (to be converted to PADIC) */ static GEN addRc(GEN x, GEN y) { GEN z = cgetg(3,t_COMPLEX); gel(z,1) = gadd(x,gel(y,1)); gel(z,2) = gcopy(gel(y,2)); return z; } static GEN mulRc(GEN x, GEN y) { GEN z = cgetg(3,t_COMPLEX); gel(z,1) = isintzero(gel(y,1))? gen_0: gmul(x,gel(y,1)); gel(z,2) = gmul(x,gel(y,2)); return z; } /* for INTMODs: can't simplify when Re(x) = gen_0 */ static GEN mulRc_direct(GEN x, GEN y) { GEN z = cgetg(3,t_COMPLEX); gel(z,1) = gmul(x,gel(y,1)); gel(z,2) = gmul(x,gel(y,2)); return z; } static GEN divRc(GEN x, GEN y) { GEN t = gdiv(x, cxnorm(y)), mt = gneg(t); /* left on stack for efficiency */ GEN z = cgetg(3,t_COMPLEX); gel(z,1) = isintzero(gel(y,1))? gen_0: gmul(t, gel(y,1)); gel(z,2) = gmul(mt, gel(y,2)); return z; } static GEN divcR(GEN x, GEN y) { GEN z = cgetg(3,t_COMPLEX); gel(z,1) = isintzero(gel(x,1))? gen_0: gdiv(gel(x,1), y); gel(z,2) = gdiv(gel(x,2), y); return z; } static GEN addRq(GEN x, GEN y) { GEN z = cgetg(4,t_QUAD); gel(z,1) = ZX_copy(gel(y,1)); gel(z,2) = gadd(x, gel(y,2)); gel(z,3) = gcopy(gel(y,3)); return z; } static GEN mulRq(GEN x, GEN y) { GEN z = cgetg(4,t_QUAD); gel(z,1) = ZX_copy(gel(y,1)); gel(z,2) = gmul(x,gel(y,2)); gel(z,3) = gmul(x,gel(y,3)); return z; } static GEN addqf(GEN x, GEN y, long prec) { pari_sp av = avma; long i = gexpo(x) - gexpo(y); if (i > 0) prec += nbits2extraprec( i ); return gerepileupto(av, gadd(y, quadtofp(x, prec))); } static GEN mulrfrac(GEN x, GEN y) { pari_sp av = avma; GEN z, a = gel(y,1), b = gel(y,2); if (is_pm1(a)) /* frequent special case */ { z = divri(x, b); if (signe(a) < 0) togglesign(z); return z; } return gerepileuptoleaf(av, divri(mulri(x,gel(y,1)), gel(y,2))); } static GEN mulqf(GEN x, GEN y, long prec) { pari_sp av = avma; return gerepileupto(av, gmul(y, quadtofp(x, prec))); } static GEN divqf(GEN x, GEN y, long prec) { pari_sp av = avma; return gerepileupto(av, gdiv(quadtofp(x,prec), y)); } static GEN divfq(GEN x, GEN y, long prec) { pari_sp av = avma; return gerepileupto(av, gdiv(x, quadtofp(y,prec))); } /* y PADIC, x + y by converting x to padic */ static GEN addTp(GEN x, GEN y) { pari_sp av = avma; GEN z; if (!valp(y)) z = cvtop2(x,y); else { long l = signe(gel(y,4))? valp(y) + precp(y): valp(y); z = cvtop(x, gel(y,2), l); } return gerepileupto(av, addsub_pp(z, y, addii)); } /* y PADIC, x * y by converting x to padic */ static GEN mulTp(GEN x, GEN y) { pari_sp av = avma; return gerepileupto(av, mulpp(cvtop2(x,y), y)); } /* y PADIC, non zero x / y by converting x to padic */ static GEN divTp(GEN x, GEN y) { pari_sp av = avma; return gerepileupto(av, divpp(cvtop2(x,y), y)); } /* x PADIC, x / y by converting y to padic. Assume x != 0; otherwise y * converted to O(p^e) and division by 0 */ static GEN divpT(GEN x, GEN y) { pari_sp av = avma; return gerepileupto(av, divpp(x, cvtop2(y,x))); } /* z := Mod(x,X) + Mod(y,X) [ t_INTMOD preallocated ], x,y,X INT, 0 <= x,y < X * clean memory from z on */ static GEN add_intmod_same(GEN z, GEN X, GEN x, GEN y) { if (lgefint(X) == 3) { ulong u = Fl_add(itou(x),itou(y), X[2]); avma = (pari_sp)z; gel(z,2) = utoi(u); } else { GEN u = addii(x,y); if (cmpii(u, X) >= 0) u = subii(u, X); gel(z,2) = gerepileuptoint((pari_sp)z, u); } gel(z,1) = icopy(X); return z; } static GEN sub_intmod_same(GEN z, GEN X, GEN x, GEN y) { if (lgefint(X) == 3) { ulong u = Fl_sub(itou(x),itou(y), X[2]); avma = (pari_sp)z; gel(z,2) = utoi(u); } else { GEN u = subii(x,y); if (signe(u) < 0) u = addii(u, X); gel(z,2) = gerepileuptoint((pari_sp)z, u); } gel(z,1) = icopy(X); return z; } /* cf add_intmod_same */ static GEN mul_intmod_same(GEN z, GEN X, GEN x, GEN y) { if (lgefint(X) == 3) { ulong u = Fl_mul(itou(x),itou(y), X[2]); avma = (pari_sp)z; gel(z,2) = utoi(u); } else gel(z,2) = gerepileuptoint((pari_sp)z, remii(mulii(x,y), X) ); gel(z,1) = icopy(X); return z; } /* cf add_intmod_same */ static GEN div_intmod_same(GEN z, GEN X, GEN x, GEN y) { if (lgefint(X) == 3) { ulong m = uel(X,2), u = Fl_div(itou(x), itou(y), m); avma = (pari_sp)z; gel(z,2) = utoi(u); } else gel(z,2) = gerepileuptoint((pari_sp)z, remii(mulii(x, Fp_inv(y,X)), X) ); gel(z,1) = icopy(X); return z; } /*******************************************************************/ /* */ /* REDUCTION to IRREDUCIBLE TERMS (t_FRAC/t_RFRAC) */ /* */ /* (static routines are not memory clean, but OK for gerepileupto) */ /*******************************************************************/ /* Compute the denominator of (1/y) * (n/d) = n/yd, y a "scalar". * Sanity check : avoid (1/2) / (Mod(1,2)*x + 1) "=" 1 / (0 * x + 1) */ static GEN rfrac_denom_mul_scal(GEN d, GEN y) { GEN D = RgX_Rg_mul(d, y); if (lg(D) != lg(d)) { /* try to generate a meaningful diagnostic */ D = gdiv(leading_coeff(d), y); /* should fail */ pari_err_INV("gred_rfrac", y); /* better than nothing */ } return D; } /* d a t_POL, n a coprime t_POL of same var or "scalar". Not memory clean */ GEN gred_rfrac_simple(GEN n, GEN d) { GEN c, cn, cd, z; long dd = degpol(d); if (dd <= 0) { if (dd < 0) pari_err_INV("gred_rfrac_simple", d); n = gdiv(n, gel(d,2)); if (typ(n) != t_POL || varn(n) != varn(d)) n = scalarpol(n, varn(d)); return n; } cd = content(d); while (typ(n) == t_POL && !degpol(n)) n = gel(n,2); cn = (typ(n) == t_POL && varn(n) == varn(d))? content(n): n; if (!gequal1(cd)) { d = RgX_Rg_div(d,cd); if (!gequal1(cn)) { if (gequal0(cn)) { if (isexactzero(cn)) return scalarpol(cn, varn(d)); n = (cn != n)? RgX_Rg_div(n,cd): gdiv(n, cd); c = gen_1; } else { n = (cn != n)? RgX_Rg_div(n,cn): gen_1; c = gdiv(cn,cd); } } else c = ginv(cd); } else { if (!gequal1(cn)) { if (gequal0(cn)) { if (isexactzero(cn)) return scalarpol(cn, varn(d)); c = gen_1; } else { n = (cn != n)? RgX_Rg_div(n,cn): gen_1; c = cn; } } else { GEN y = cgetg(3,t_RFRAC); gel(y,1) = gcopy(n); gel(y,2) = RgX_copy(d); return y; } } if (typ(c) == t_POL) { z = c; do { z = content(z); } while (typ(z) == t_POL); cd = denom_i(z); cn = gmul(c, cd); } else { cn = numer_i(c); cd = denom_i(c); } z = cgetg(3,t_RFRAC); gel(z,1) = gmul(n, cn); gel(z,2) = rfrac_denom_mul_scal(d, cd); return z; } /* in rare cases x may be a t_POL, after 0/x for instance -> pol_0() */ static GEN fix_rfrac(GEN x, long d) { GEN z, N, D; if (!d || typ(x) == t_POL) return x; z = cgetg(3, t_RFRAC); N = gel(x,1); D = gel(x,2); if (d > 0) { gel(z, 1) = (typ(N)==t_POL && varn(N)==varn(D))? RgX_shift(N,d) : monomialcopy(N,d,varn(D)); gel(z, 2) = RgX_copy(D); } else { gel(z, 1) = gcopy(N); gel(z, 2) = RgX_shift(D, -d); } return z; } /* assume d != 0 */ static GEN gred_rfrac2(GEN n, GEN d) { GEN y, z; long v, vd, vn; n = simplify_shallow(n); if (isintzero(n)) return scalarpol(Rg_get_0(d), varn(d)); d = simplify_shallow(d); if (typ(d) != t_POL) return gdiv(n,d); vd = varn(d); if (typ(n) != t_POL) { if (varncmp(vd, gvar(n)) >= 0) return gdiv(n,d); if (varncmp(vd, gvar2(n)) < 0) return gred_rfrac_simple(n,d); pari_err_BUG("gred_rfrac2 [incompatible variables]"); } vn = varn(n); if (varncmp(vd, vn) < 0) return gred_rfrac_simple(n,d); if (varncmp(vd, vn) > 0) return RgX_Rg_div(n,d); /* now n and d are t_POLs in the same variable */ v = RgX_valrem(n, &n) - RgX_valrem(d, &d); if (!degpol(d)) { n = RgX_Rg_div(n,gel(d,2)); return v? RgX_mulXn(n,v): n; } /* X does not divide gcd(n,d), deg(d) > 0 */ if (!isinexact(n) && !isinexact(d)) { y = RgX_divrem(n, d, &z); if (!signe(z)) { cgiv(z); return v? RgX_mulXn(y, v): y; } z = RgX_gcd(d, z); if (degpol(z)) { n = RgX_div(n,z); d = RgX_div(d,z); } } return fix_rfrac(gred_rfrac_simple(n,d), v); } /* x,y t_INT, return x/y in reduced form */ GEN Qdivii(GEN x, GEN y) { pari_sp av = avma; GEN r, q; if (is_pm1(y)) return (signe(y) < 0)? negi(x): icopy(x); if (equali1(x)) { long s = signe(y); if (!s) pari_err_INV("gdiv",y); if (signe(x) < 0) s = -s; q = cgetg(3, t_FRAC); gel(q,1) = s<0? gen_m1: gen_1; gel(q,2) = absi(y); return q; } q = dvmdii(x,y,&r); if (r == gen_0) return q; /* gen_0 intended */ r = gcdii(y,r); if (lgefint(r) == 3) { ulong t = r[2]; avma = av; if (t == 1) q = mkfraccopy(x,y); else { q = cgetg(3,t_FRAC); gel(q,1) = diviuexact(x,t); gel(q,2) = diviuexact(y,t); } } else { /* rare: r and q left on stack for efficiency */ q = cgetg(3,t_FRAC); gel(q,1) = diviiexact(x,r); gel(q,2) = diviiexact(y,r); } normalize_frac(q); return q; } /*******************************************************************/ /* */ /* CONJUGATION */ /* */ /*******************************************************************/ /* lift( conj(Mod(x, y)) ), assuming degpol(y) = 2, degpol(x) < 2 */ static GEN quad_polmod_conj(GEN x, GEN y) { GEN z, u, v, a, b; if (typ(x) != t_POL) return gcopy(x); if (varn(x) != varn(y) || degpol(x) <= 0) return RgX_copy(x); a = gel(y,4); u = gel(x,3); /*Mod(ux + v, ax^2 + bx + c)*/ b = gel(y,3); v = gel(x,2); z = cgetg(4, t_POL); z[1] = x[1]; gel(z,2) = gsub(v, gdiv(gmul(u,b), a)); gel(z,3) = gneg(u); return z; } static GEN quad_polmod_norm(GEN x, GEN y) { GEN z, u, v, a, b, c; if (typ(x) != t_POL || varn(x) != varn(y) || degpol(x) <= 0) return gsqr(x); a = gel(y,4); u = gel(x,3); /*Mod(ux + v, ax^2 + bx + c)*/ b = gel(y,3); v = gel(x,2); c = gel(y,2); z = gmul(u, gsub(gmul(c,u), gmul(b,v))); if (!gequal1(a)) z = gdiv(z, a); return gadd(z, gsqr(v)); } GEN conj_i(GEN x) { long lx, i; GEN y; switch(typ(x)) { case t_INT: case t_REAL: case t_INTMOD: case t_FRAC: case t_PADIC: return x; case t_COMPLEX: return mkcomplex(gel(x,1), gneg(gel(x,2))); case t_QUAD: y = cgetg(4,t_QUAD); gel(y,1) = gel(x,1); gel(y,2) = gequal0(gmael(x,1,3))? gel(x,2) : gadd(gel(x,2), gel(x,3)); gel(y,3) = gneg(gel(x,3)); return y; case t_POL: case t_SER: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i= r) { avma = av; return zeropadic(p, e+r); } if (c) { mod = diviiexact(mod, powiu(p,c)); r -= c; e += c; } } u = modii(u, mod); avma = av; z = cgetg(5,t_PADIC); z[1] = evalprecp(r) | evalvalp(e); gel(z,2) = icopy(p); gel(z,3) = icopy(mod); gel(z,4) = icopy(u); return z; } /* Rg_to_Fp(t_FRAC) without GC */ static GEN Q_to_Fp(GEN x, GEN p) { return mulii(gel(x,1), Fp_inv(gel(x,2),p)); } /* return x + y, where y t_PADIC and x is a non-zero t_INT or t_FRAC */ static GEN addQp(GEN x, GEN y) { pari_sp av = avma; long d, r, e, vy = valp(y), py = precp(y); GEN z, q, mod, u, p = gel(y,2); e = Q_pvalrem(x, p, &x); d = vy - e; r = d + py; if (r <= 0) { avma = av; return gcopy(y); } mod = gel(y,3); u = gel(y,4); (void)new_chunk(5 + ((lgefint(mod) + lgefint(p)*labs(d)) << 1)); if (d > 0) { q = powiu(p,d); mod = mulii(mod, q); if (typ(x) != t_INT) x = Q_to_Fp(x, mod); u = addii(x, mulii(u, q)); } else if (d < 0) { q = powiu(p,-d); if (typ(x) != t_INT) x = Q_to_Fp(x, mod); u = addii(u, mulii(x, q)); r = py; e = vy; } else { long c; if (typ(x) != t_INT) x = Q_to_Fp(x, mod); u = addii(u, x); if (!signe(u) || (c = Z_pvalrem(u,p,&u)) >= r) { avma = av; return zeropadic(p,e+r); } if (c) { mod = diviiexact(mod, powiu(p,c)); r -= c; e += c; } } u = modii(u, mod); avma = av; z = cgetg(5,t_PADIC); z[1] = evalprecp(r) | evalvalp(e); gel(z,2) = icopy(p); gel(z,3) = icopy(mod); gel(z,4) = icopy(u); return z; } /* Mod(x,X) + Mod(y,X) */ #define addsub_polmod_same addsub_polmod_scal /* Mod(x,X) +/- Mod(y,Y) */ static GEN addsub_polmod(GEN X, GEN Y, GEN x, GEN y, GEN(*op)(GEN,GEN)) { long T[3] = { evaltyp(t_POLMOD) | _evallg(3),0,0 }; GEN z = cgetg(3,t_POLMOD); long vx = varn(X), vy = varn(Y); if (vx==vy) { pari_sp av; gel(z,1) = RgX_gcd(X,Y); av = avma; warn_coercion(X,Y,gel(z,1)); gel(z,2) = gerepileupto(av, gmod(op(x, y), gel(z,1))); return z; } if (varncmp(vx, vy) < 0) { gel(z,1) = RgX_copy(X); gel(T,1) = Y; gel(T,2) = y; y = T; } else { gel(z,1) = RgX_copy(Y); gel(T,1) = X; gel(T,2) = x; x = T; } gel(z,2) = op(x, y); return z; } /* Mod(y, Y) +/- x, x scalar or polynomial in same var and reduced degree */ static GEN addsub_polmod_scal(GEN Y, GEN y, GEN x, GEN(*op)(GEN,GEN)) { retmkpolmod(degpol(Y)? op(y, x): gen_0, RgX_copy(Y)); } /* typ(y) == t_SER, x "scalar" [e.g object in lower variable] */ static GEN add_ser_scal(GEN y, GEN x) { long i, l, ly, vy; GEN z; if (isrationalzero(x)) return gcopy(y); ly = lg(y); l = valp(y); if (l < 3-ly) return gcopy(y); /* l + ly >= 3 */ if (l < 0) { z = cgetg(ly,t_SER); z[1] = y[1]; for (i = 2; i <= 1-l; i++) gel(z,i) = gcopy(gel(y,i)); gel(z,i) = gadd(x,gel(y,i)); i++; for ( ; i < ly; i++) gel(z,i) = gcopy(gel(y,i)); return z; } vy = varn(y); if (l > 0) { if (ser_isexactzero(y)) return scalarser(ly == 2? x: gadd(x,gel(y,2)), vy, l); y -= l; ly += l; z = cgetg(ly,t_SER); x = gcopy(x); for (i=3; i<=l+1; i++) gel(z,i) = gen_0; } else { /* l = 0, ly >= 3. Also OK if ser_isexactzero(y) */ z = cgetg(ly,t_SER); x = gadd(x, gel(y,2)); i = 3; } for (; i lx) return gcopy(x); z = cgetg(ly,t_SER); for (i=2; i<=n+1; i++) gel(z,i) = gcopy(gel(x,i)); for ( ; i < ly; i++) gel(z,i) = gadd(gel(x,i),gel(y,i-n)); } else { z = cgetg(ly,t_SER); for (i=2; i < ly; i++) gel(z,i) = gadd(gel(x,i),gel(y,i)); } z[1] = x[1]; return normalize(z); } /* typ(y) == RFRAC, x polynomial in same variable or "scalar" */ static GEN add_rfrac_scal(GEN y, GEN x) { pari_sp av; GEN n; if (isintzero(x)) return gcopy(y); /* frequent special case */ av = avma; n = gadd(gmul(x, gel(y,2)), gel(y,1)); return gerepileupto(av, gred_rfrac_simple(n, gel(y,2))); } /* x "scalar", ty != t_MAT and non-scalar */ static GEN add_scal(GEN y, GEN x, long ty) { switch(ty) { case t_POL: return RgX_Rg_add(y, x); case t_SER: return add_ser_scal(y, x); case t_RFRAC: return add_rfrac_scal(y, x); case t_COL: return RgC_Rg_add(y, x); case t_VEC: if (isintzero(x)) return gcopy(y); break; } pari_err_TYPE2("+",x,y); return NULL; /* LCOV_EXCL_LINE */ } static GEN addsub_frac(GEN x, GEN y, GEN (*op)(GEN,GEN)) { pari_sp av0 = avma; GEN x1 = gel(x,1), x2 = gel(x,2), z = cgetg(3,t_FRAC); GEN y1 = gel(y,1), y2 = gel(y,2), q, r, n, d, delta; int s = cmpii(x2, y2); if (!s) { /* common denominator: (x1 op y1) / x2 */ n = op(x1, y1); if (!signe(n)) { avma = av0; return gen_0; } d = x2; q = dvmdii(n, d, &r); if (r == gen_0) { avma = av0; return icopy(q); } r = gcdii(d, r); if (!equali1(r)) { n = diviiexact(n, r); d = diviiexact(d, r); } avma = (pari_sp)z; gel(z,1) = icopy(n); gel(z,2) = icopy(d); return z; } if (s < 0) { GEN Q = dvmdii(y2, x2, &r); if (r == gen_0) { /* y2 = Q x2: 1/x2 . (Q x1 op y1)/Q, where latter is in coprime form */ pari_sp av = avma; n = op(mulii(Q,x1), y1); q = dvmdii(n, x2, &r); if (r == gen_0) { gel(z,1) = gerepileuptoint(av, q); gel(z,2) = Q; return z; } r = gcdii(x2, r); if (!equali1(r)) { n = diviiexact(n, r); x2 = diviiexact(x2, r); } d = mulii(x2,Q); avma = (pari_sp)z; gel(z,1) = icopy(n); gel(z,2) = icopy(d); return z; } delta = gcdii(x2,r); } else { GEN Q = dvmdii(x2, y2, &r); if (r == gen_0) { /* x2 = Q y2: 1/y2 . (x1 op Q y1)/Q, where latter is in coprime form */ pari_sp av = avma; n = op(x1, mulii(Q,y1)); q = dvmdii(n, y2, &r); if (r == gen_0) { gel(z,1) = gerepileuptoint(av, q); gel(z,2) = Q; return z; } r = gcdii(y2, r); if (!equali1(r)) { n = diviiexact(n, r); y2 = diviiexact(y2, r); } d = mulii(y2,Q); avma=(pari_sp)z; gel(z,1) = icopy(n); gel(z,2) = icopy(d); return z; } delta = gcdii(y2,r); } /* delta = gcd(x2,y2) */ if (equali1(delta)) { /* numerator is non-zero */ gel(z,1) = gerepileuptoint((pari_sp)z, op(mulii(x1,y2), mulii(y1,x2))); gel(z,2) = mulii(x2,y2); return z; } x2 = diviiexact(x2,delta); y2 = diviiexact(y2,delta); n = op(mulii(x1,y2), mulii(y1,x2)); if (!signe(n)) { avma = av0; return gen_0; } d = mulii(x2, y2); q = dvmdii(n, delta, &r); if (r == gen_0) { if (equali1(d)) { avma = av0; return icopy(q); } avma = (pari_sp)z; gel(z,2) = icopy(d); gel(z,1) = icopy(q); return z; } r = gcdii(delta, r); if (!equali1(r)) { n = diviiexact(n, r); delta = diviiexact(delta, r); } d = mulii(d,delta); avma = (pari_sp)z; gel(z,1) = icopy(n); gel(z,2) = icopy(d); return z; } /* assume x2, y2 are t_POLs in the same variable */ static GEN add_rfrac(GEN x, GEN y) { pari_sp av = avma; GEN x1 = gel(x,1), x2 = gel(x,2); GEN y1 = gel(y,1), y2 = gel(y,2), q, r, n, d, delta; delta = RgX_gcd(x2,y2); if (!degpol(delta)) { n = simplify_shallow( gadd(gmul(x1,y2), gmul(y1,x2)) ); d = RgX_mul(x2, y2); return gerepileupto(av, gred_rfrac_simple(n, d)); } x2 = RgX_div(x2,delta); y2 = RgX_div(y2,delta); n = gadd(gmul(x1,y2), gmul(y1,x2)); if (!signe(n)) { n = simplify_shallow(n); if (isrationalzero(n)) return gerepileupto(av, zeropol(varn(x2))); return gerepilecopy(av, mkrfrac(n, RgX_mul(gel(x,2),y2))); } if (degpol(n) == 0) return gerepileupto(av, gred_rfrac_simple(gel(n,2), RgX_mul(gel(x,2),y2))); q = RgX_divrem(n, delta, &r); /* we want gcd(n,delta) */ if (isexactzero(r)) { GEN z; d = RgX_mul(x2, y2); /* "constant" denominator ? */ z = lg(d) == 3? RgX_Rg_div(q, gel(d,2)): gred_rfrac_simple(q, d); return gerepileupto(av, z); } r = RgX_gcd(delta, r); if (degpol(r)) { n = RgX_div(n, r); d = RgX_mul(RgX_mul(x2,y2), RgX_div(delta, r)); } else d = RgX_mul(gel(x,2), y2); return gerepileupto(av, gred_rfrac_simple(n, d)); } GEN gadd(GEN x, GEN y) { long tx = typ(x), ty = typ(y), vx, vy, lx, i, l; pari_sp av, tetpil; GEN z, p1; if (tx == ty) switch(tx) /* shortcut to generic case */ { case t_INT: return addii(x,y); case t_REAL: return addrr(x,y); case t_INTMOD: { GEN X = gel(x,1), Y = gel(y,1); z = cgetg(3,t_INTMOD); if (X==Y || equalii(X,Y)) return add_intmod_same(z, X, gel(x,2), gel(y,2)); gel(z,1) = gcdii(X,Y); warn_coercion(X,Y,gel(z,1)); av = avma; p1 = addii(gel(x,2),gel(y,2)); gel(z,2) = gerepileuptoint(av, remii(p1, gel(z,1))); return z; } case t_FRAC: return addsub_frac(x,y,addii); case t_COMPLEX: z = cgetg(3,t_COMPLEX); gel(z,2) = gadd(gel(x,2),gel(y,2)); if (isintzero(gel(z,2))) { avma = (pari_sp)(z+3); return gadd(gel(x,1),gel(y,1)); } gel(z,1) = gadd(gel(x,1),gel(y,1)); return z; case t_PADIC: if (!equalii(gel(x,2),gel(y,2))) pari_err_OP("+",x,y); return addsub_pp(x,y, addii); case t_QUAD: z = cgetg(4,t_QUAD); if (!ZX_equal(gel(x,1),gel(y,1))) pari_err_OP("+",x,y); gel(z,1) = ZX_copy(gel(x,1)); gel(z,2) = gadd(gel(x,2),gel(y,2)); gel(z,3) = gadd(gel(x,3),gel(y,3)); return z; case t_POLMOD: if (RgX_equal_var(gel(x,1), gel(y,1))) return addsub_polmod_same(gel(x,1), gel(x,2), gel(y,2), &gadd); return addsub_polmod(gel(x,1), gel(y,1), gel(x,2), gel(y,2), &gadd); case t_FFELT: return FF_add(x,y); case t_POL: vx = varn(x); vy = varn(y); if (vx != vy) { if (varncmp(vx, vy) < 0) return RgX_Rg_add(x, y); else return RgX_Rg_add(y, x); } return RgX_add(x, y); case t_SER: vx = varn(x); vy = varn(y); if (vx != vy) { if (varncmp(vx, vy) < 0) return add_ser_scal(x, y); else return add_ser_scal(y, x); } return ser_add(x, y); case t_RFRAC: vx = varn(gel(x,2)); vy = varn(gel(y,2)); if (vx != vy) { if (varncmp(vx, vy) < 0) return add_rfrac_scal(x, y); else return add_rfrac_scal(y, x); } return add_rfrac(x,y); case t_VEC: if (lg(y) != lg(x)) pari_err_OP("+",x,y); return RgV_add(x,y); case t_COL: if (lg(y) != lg(x)) pari_err_OP("+",x,y); return RgC_add(x,y); case t_MAT: lx = lg(x); if (lg(y) != lx) pari_err_OP("+",x,y); if (lx == 1) return cgetg(1, t_MAT); if (lgcols(y) != lgcols(x)) pari_err_OP("+",x,y); return RgM_add(x,y); default: pari_err_TYPE2("+",x,y); } /* tx != ty */ if (tx > ty) { swap(x,y); lswap(tx,ty); } if (is_const_t(ty)) switch(tx) /* tx < ty, is_const_t(tx) && is_const_t(ty) */ { case t_INT: switch(ty) { case t_REAL: return addir(x,y); case t_INTMOD: z = cgetg(3, t_INTMOD); return add_intmod_same(z, gel(y,1), gel(y,2), modii(x, gel(y,1))); case t_FRAC: z = cgetg(3,t_FRAC); gel(z,1) = gerepileuptoint((pari_sp)z, addii(gel(y,1), mulii(gel(y,2),x))); gel(z,2) = icopy(gel(y,2)); return z; case t_COMPLEX: return addRc(x, y); case t_PADIC: if (!signe(x)) return gcopy(y); return addQp(x,y); case t_QUAD: return addRq(x, y); case t_FFELT: return FF_Z_add(y,x); } case t_REAL: switch(ty) { case t_FRAC: if (!signe(gel(y,1))) return rcopy(x); if (!signe(x)) { lx = expi(gel(y,1)) - expi(gel(y,2)) - expo(x); return lx <= 0? rcopy(x): fractor(y, nbits2prec(lx)); } av=avma; z=addir(gel(y,1),mulir(gel(y,2),x)); tetpil=avma; return gerepile(av,tetpil,divri(z,gel(y,2))); case t_COMPLEX: return addRc(x, y); case t_QUAD: return gequal0(y)? rcopy(x): addqf(y, x, lg(x)); default: pari_err_TYPE2("+",x,y); } case t_INTMOD: switch(ty) { case t_FRAC: { GEN X = gel(x,1); z = cgetg(3, t_INTMOD); p1 = Fp_div(gel(y,1), gel(y,2), X); return add_intmod_same(z, X, p1, gel(x,2)); } case t_FFELT: if (!equalii(gel(x,1),FF_p_i(y))) pari_err_OP("+",x,y); return FF_Z_add(y,gel(x,2)); case t_COMPLEX: return addRc(x, y); case t_PADIC: { GEN X = gel(x,1); z = cgetg(3, t_INTMOD); return add_intmod_same(z, X, gel(x,2), padic_to_Fp(y, X)); } case t_QUAD: return addRq(x, y); } case t_FRAC: switch (ty) { case t_COMPLEX: return addRc(x, y); case t_PADIC: if (!signe(gel(x,1))) return gcopy(y); return addQp(x,y); case t_QUAD: return addRq(x, y); case t_FFELT: return FF_Q_add(y, x); } case t_FFELT: pari_err_TYPE2("+",x,y); case t_COMPLEX: switch(ty) { case t_PADIC: return Zp_nosquare_m1(gel(y,2))? addRc(y, x): addTp(x, y); case t_QUAD: lx = precision(x); if (!lx) pari_err_OP("+",x,y); return gequal0(y)? gcopy(x): addqf(y, x, lx); } case t_PADIC: /* ty == t_QUAD */ return (kro_quad(y,gel(x,2)) == -1)? addRq(x, y): addTp(y, x); } /* tx < ty, !is_const_t(y) */ switch(ty) { case t_MAT: if (is_matvec_t(tx)) pari_err_TYPE2("+",x,y); if (isrationalzero(x)) return gcopy(y); return RgM_Rg_add(y, x); case t_COL: if (tx == t_VEC) pari_err_TYPE2("+",x,y); return RgC_Rg_add(y, x); case t_POLMOD: /* is_const_t(tx) in this case */ return addsub_polmod_scal(gel(y,1), gel(y,2), x, &gadd); } if (is_scalar_t(tx)) { if (tx == t_POLMOD) { vx = varn(gel(x,1)); vy = gvar(y); if (vx == vy) y = gmod(y, gel(x,1)); /* error if ty == t_SER */ else if (varncmp(vx,vy) > 0) return add_scal(y, x, ty); return addsub_polmod_scal(gel(x,1), gel(x,2), y, &gadd); } return add_scal(y, x, ty); } /* x and y are not scalars, ty != t_MAT */ vx = gvar(x); vy = gvar(y); if (vx != vy) { /* x or y is treated as a scalar */ if (is_vec_t(tx) || is_vec_t(ty)) pari_err_TYPE2("+",x,y); return (varncmp(vx, vy) < 0)? add_scal(x, y, tx) : add_scal(y, x, ty); } /* vx = vy */ switch(tx) { case t_POL: switch (ty) { case t_SER: if (lg(x) == 2) return gcopy(y); i = RgX_val(x); if (i == LONG_MAX) i = 0; /* e.g. x = Mod(0,3)*x^0 */ i = lg(y) + valp(y) - i; if (i < 3) return gcopy(y); p1 = RgX_to_ser(x,i); y = ser_add(p1,y); settyp(p1, t_VECSMALL); /* p1 left on stack */ return y; case t_RFRAC: return add_rfrac_scal(y, x); } break; case t_SER: if (ty == t_RFRAC) { GEN n, d; long vn, vd; av = avma; n = gel(y,1); vn = gval(n, vy); d = gel(y,2); vd = RgX_valrem(d, &d); l = lg(x) + valp(x) - (vn - vd); if (l < 3) { avma = av; return gcopy(x); } /* take advantage of y = t^n ! */ if (degpol(d)) y = gdiv(n, RgX_to_ser_inexact(d,l)); else { y = gdiv(n, gel(d,2)); if (gvar(y) == vy) y = RgX_to_ser(y,l); else y = scalarser(y, vy, l); } setvalp(y, valp(y) - vd); return gerepileupto(av, gadd(y, x)); } break; } pari_err_TYPE2("+",x,y); return NULL; /* LCOV_EXCL_LINE */ } GEN gaddsg(long x, GEN y) { long ty = typ(y); GEN z; switch(ty) { case t_INT: return addsi(x,y); case t_REAL: return addsr(x,y); case t_INTMOD: z = cgetg(3, t_INTMOD); return add_intmod_same(z, gel(y,1), gel(y,2), modsi(x, gel(y,1))); case t_FRAC: z = cgetg(3,t_FRAC); gel(z,1) = gerepileuptoint((pari_sp)z, addii(gel(y,1), mulis(gel(y,2),x))); gel(z,2) = icopy(gel(y,2)); return z; case t_COMPLEX: z = cgetg(3, t_COMPLEX); gel(z,1) = gaddsg(x, gel(y,1)); gel(z,2) = gcopy(gel(y,2)); return z; default: return gadd(stoi(x), y); } } GEN gsubsg(long x, GEN y) { GEN z, a, b; pari_sp av; switch(typ(y)) { case t_INT: return subsi(x,y); case t_REAL: return subsr(x,y); case t_INTMOD: z = cgetg(3, t_INTMOD); a = gel(y,1); b = gel(y,2); return add_intmod_same(z, a, Fp_neg(b,a), modsi(x, a)); case t_FRAC: z = cgetg(3,t_FRAC); a = gel(y,1); b = gel(y,2); gel(z,1) = gerepileuptoint((pari_sp)z, subii(mulis(b,x), a)); gel(z,2) = icopy(gel(y,2)); return z; case t_COMPLEX: z = cgetg(3, t_COMPLEX); gel(z,1) = gsubsg(x, gel(y,1)); gel(z,2) = gneg(gel(y,2)); return z; } av = avma; return gerepileupto(av, gadd(stoi(x), gneg_i(y))); } /********************************************************************/ /** **/ /** SUBTRACTION **/ /** **/ /********************************************************************/ GEN gsub(GEN x, GEN y) { long tx = typ(x), ty = typ(y); pari_sp av; GEN z; if (tx == ty) switch(tx) /* shortcut to generic case */ { case t_INT: return subii(x,y); case t_REAL: return subrr(x,y); case t_INTMOD: { GEN p1, X = gel(x,1), Y = gel(y,1); z = cgetg(3,t_INTMOD); if (X==Y || equalii(X,Y)) return sub_intmod_same(z, X, gel(x,2), gel(y,2)); gel(z,1) = gcdii(X,Y); warn_coercion(X,Y,gel(z,1)); av = avma; p1 = subii(gel(x,2),gel(y,2)); gel(z,2) = gerepileuptoint(av, modii(p1, gel(z,1))); return z; } case t_FRAC: return addsub_frac(x,y, subii); case t_COMPLEX: z = cgetg(3,t_COMPLEX); gel(z,2) = gsub(gel(x,2),gel(y,2)); if (isintzero(gel(z,2))) { avma = (pari_sp)(z+3); return gsub(gel(x,1),gel(y,1)); } gel(z,1) = gsub(gel(x,1),gel(y,1)); return z; case t_PADIC: if (!equalii(gel(x,2),gel(y,2))) pari_err_OP("+",x,y); return addsub_pp(x,y, subii); case t_QUAD: z = cgetg(4,t_QUAD); if (!ZX_equal(gel(x,1),gel(y,1))) pari_err_OP("+",x,y); gel(z,1) = ZX_copy(gel(x,1)); gel(z,2) = gsub(gel(x,2),gel(y,2)); gel(z,3) = gsub(gel(x,3),gel(y,3)); return z; case t_POLMOD: if (RgX_equal_var(gel(x,1), gel(y,1))) return addsub_polmod_same(gel(x,1), gel(x,2), gel(y,2), &gsub); return addsub_polmod(gel(x,1), gel(y,1), gel(x,2), gel(y,2), &gsub); case t_FFELT: return FF_sub(x,y); case t_POL: { long vx = varn(x); long vy = varn(y); if (vx != vy) { if (varncmp(vx, vy) < 0) return RgX_Rg_sub(x, y); else return Rg_RgX_sub(x, y); } return RgX_sub(x, y); } case t_VEC: if (lg(y) != lg(x)) pari_err_OP("+",x,y); return RgV_sub(x,y); case t_COL: if (lg(y) != lg(x)) pari_err_OP("+",x,y); return RgC_sub(x,y); case t_MAT: { long lx = lg(x); if (lg(y) != lx) pari_err_OP("+",x,y); if (lx == 1) return cgetg(1, t_MAT); if (lgcols(y) != lgcols(x)) pari_err_OP("+",x,y); return RgM_sub(x,y); } case t_RFRAC: case t_SER: break; default: pari_err_TYPE2("+",x,y); } av = avma; return gerepileupto(av, gadd(x,gneg_i(y))); } /********************************************************************/ /** **/ /** MULTIPLICATION **/ /** **/ /********************************************************************/ static GEN mul_ser_scal(GEN y, GEN x) { long ly, i; GEN z; if (isexactzero(x)) return gmul(Rg_get_0(y), x); if (ser_isexactzero(y)) { if (lg(y) == 2) return gcopy(y); return scalarser(gmul(x,gel(y,2)), varn(y), valp(y)); } z = cgetg_copy(y, &ly); z[1] = y[1]; for (i = 2; i < ly; i++) gel(z,i) = gmul(x,gel(y,i)); return normalize(z); } /* (n/d) * x, x "scalar" or polynomial in the same variable as d * [n/d a valid RFRAC] */ static GEN mul_rfrac_scal(GEN n, GEN d, GEN x) { pari_sp av = avma; GEN z; switch(typ(x)) { case t_PADIC: n = gmul(n, x); d = gcvtop(d, gel(x,2), signe(gel(x,4))? precp(x): 1); return gerepileupto(av, gdiv(n,d)); case t_INTMOD: case t_POLMOD: n = gmul(n, x); d = gmul(d, gmodulo(gen_1, gel(x,1))); return gerepileupto(av, gdiv(n,d)); } z = gred_rfrac2(x, d); n = simplify_shallow(n); if (typ(z) == t_RFRAC) { n = gmul(gel(z,1), n); d = gel(z,2); if (typ(n) == t_POL && varncmp(varn(n), varn(d)) < 0) z = RgX_Rg_div(n, d); else z = gred_rfrac_simple(n, d); } else z = gmul(z, n); return gerepileupto(av, z); } static GEN mul_scal(GEN y, GEN x, long ty) { switch(ty) { case t_POL: if (lg(y) == 2) return scalarpol(gmul(gen_0,x), varn(y)); return RgX_Rg_mul(y, x); case t_SER: return mul_ser_scal(y, x); case t_RFRAC: return mul_rfrac_scal(gel(y,1),gel(y,2), x); case t_QFI: case t_QFR: if (typ(x) == t_INT && gequal1(x)) return gcopy(y); /* fall through */ } pari_err_TYPE2("*",x,y); return NULL; /* LCOV_EXCL_LINE */ } static GEN mul_gen_rfrac(GEN X, GEN Y) { GEN y1 = gel(Y,1), y2 = gel(Y,2); long vx = gvar(X), vy = varn(y2); return (varncmp(vx, vy) <= 0)? mul_scal(Y, X, typ(Y)): gred_rfrac_simple(gmul(y1,X), y2); } /* (x1/x2) * (y1/y2) */ static GEN mul_rfrac(GEN x1, GEN x2, GEN y1, GEN y2) { GEN z, X, Y; pari_sp av = avma; X = gred_rfrac2(x1, y2); Y = gred_rfrac2(y1, x2); if (typ(X) == t_RFRAC) { if (typ(Y) == t_RFRAC) { x1 = gel(X,1); x2 = gel(X,2); y1 = gel(Y,1); y2 = gel(Y,2); z = gred_rfrac_simple(gmul(x1,y1), gmul(x2,y2)); } else z = mul_gen_rfrac(Y, X); } else if (typ(Y) == t_RFRAC) z = mul_gen_rfrac(X, Y); else z = gmul(X, Y); return gerepileupto(av, z); } /* (x1/x2) /y2, x2 and y2 are t_POL in the same variable */ static GEN div_rfrac_pol(GEN x1, GEN x2, GEN y2) { pari_sp av = avma; GEN X = gred_rfrac2(x1, y2); if (typ(X) == t_RFRAC && varn(gel(X,2)) == varn(x2)) { x2 = RgX_mul(gel(X,2), x2); x1 = gel(X,1); } else x1 = X; return gerepileupto(av, gred_rfrac_simple(x1, x2)); } /* Mod(y, Y) * x, assuming x scalar */ static GEN mul_polmod_scal(GEN Y, GEN y, GEN x) { retmkpolmod(gmul(x,y), RgX_copy(Y)); } /* cf mulqq */ static GEN quad_polmod_mul(GEN P, GEN x, GEN y) { GEN T = cgetg(4, t_POL), b = gel(P,3), c = gel(P,2), p1, p2, p3, p4; pari_sp tetpil, av = avma; T[1] = x[1]; p2 = gmul(gel(x,2), gel(y,2)); p3 = gmul(gel(x,3), gel(y,3)); p1 = gmul(gneg_i(c),p3); /* operands are usually small: gadd ~ gmul and Karatsuba is a waste */ if (typ(b) == t_INT) { if (signe(b)) { p4 = gadd(gmul(gel(x,2), gel(y,3)), gmul(gel(x,3), gel(y,2))); if (is_pm1(b)) { if (signe(b) > 0) p3 = gneg(p3); } else p3 = gmul(negi(b), p3); } else { p3 = gmul(gel(x,2),gel(y,3)); p4 = gmul(gel(x,3),gel(y,2)); } } else { p4 = gadd(gmul(gel(x,2), gel(y,3)), gmul(gel(x,3), gel(y,2))); p3 = gmul(gneg_i(b), p3); } tetpil = avma; gel(T,2) = gadd(p2, p1); gel(T,3) = gadd(p4, p3); gerepilecoeffssp(av,tetpil,T+2,2); return normalizepol_lg(T,4); } /* Mod(x,T) * Mod(y,T) */ static GEN mul_polmod_same(GEN T, GEN x, GEN y) { GEN z = cgetg(3,t_POLMOD), a; long v = varn(T), lx = lg(x), ly = lg(y); gel(z,1) = RgX_copy(T); /* x * y mod T optimised */ if (typ(x) != t_POL || varn(x) != v || lx <= 3 || typ(y) != t_POL || varn(y) != v || ly <= 3) a = gmul(x, y); else { if (lg(T) == 5 && isint1(gel(T,4))) /* quadratic fields */ a = quad_polmod_mul(T, x, y); else a = RgXQ_mul(x, y, gel(z,1)); } gel(z,2) = a; return z; } static GEN sqr_polmod(GEN T, GEN x) { GEN a, z = cgetg(3,t_POLMOD); gel(z,1) = RgX_copy(T); if (typ(x) != t_POL || varn(x) != varn(T) || lg(x) <= 3) a = gsqr(x); else { pari_sp av = avma; a = RgXQ_sqr(x, gel(z,1)); a = gerepileupto(av, a); } gel(z,2) = a; return z; } /* Mod(x,X) * Mod(y,Y) */ static GEN mul_polmod(GEN X, GEN Y, GEN x, GEN y) { long T[3] = { evaltyp(t_POLMOD) | _evallg(3),0,0 }; long vx = varn(X), vy = varn(Y); GEN z = cgetg(3,t_POLMOD); if (vx==vy) { pari_sp av; gel(z,1) = RgX_gcd(X,Y); av = avma; warn_coercion(X,Y,gel(z,1)); gel(z,2) = gerepileupto(av, gmod(gmul(x, y), gel(z,1))); return z; } if (varncmp(vx, vy) < 0) { gel(z,1) = RgX_copy(X); gel(T,1) = Y; gel(T,2) = y; y = T; } else { gel(z,1) = RgX_copy(Y); gel(T,1) = X; gel(T,2) = x; x = T; } gel(z,2) = gmul(x, y); return z; } #if 0 /* used by 3M only */ /* set z = x+y and return 1 if x,y have the same sign * set z = x-y and return 0 otherwise */ static int did_add(GEN x, GEN y, GEN *z) { long tx = typ(x), ty = typ(y); if (tx == ty) switch(tx) { case t_INT: *z = addii(x,y); return 1; case t_FRAC: *z = addsub_frac(x,y,addii); return 1; case t_REAL: if (signe(x) == -signe(y)) { *z = subrr(x,y); return 0; } else { *z = addrr(x,y); return 1; } } if (tx == t_REAL) switch(ty) { case t_INT: if (signe(x) == -signe(y)) { *z = subri(x,y); return 0; } else { *z = addri(x,y); return 1; } case t_FRAC: if (signe(x) == -signe(gel(y,1))) { *z = gsub(x,y); return 0; } else { *z = gadd(x,y); return 1; } } else if (ty == t_REAL) switch(tx) { case t_INT: if (signe(x) == -signe(y)) { *z = subir(x,y); return 0; } else { *z = addir(x,y); return 1; } case t_FRAC: if (signe(gel(x,1)) == -signe(y)) { *z = gsub(x,y); return 0; } else { *z = gadd(x,y); return 1; } } *z = gadd(x,y); return 1; } #endif /* x * I * y, x t_COMPLEX with non-intzero real part, y non-intzero "scalar" */ static GEN mulcIR(GEN x, GEN y) { GEN z = cgetg(3,t_COMPLEX); pari_sp av = avma; gel(z,1) = gerepileupto(av, gneg(gmul(y,gel(x,2)))); gel(z,2) = gmul(y, gel(x,1)); return z; } /* x,y COMPLEX */ static GEN mulcc(GEN x, GEN y) { GEN xr = gel(x,1), xi = gel(x,2); GEN yr = gel(y,1), yi = gel(y,2); GEN p1, p2, p3, p4, z; pari_sp tetpil, av; if (isintzero(xr)) { if (isintzero(yr)) { av = avma; return gerepileupto(av, gneg(gmul(xi,yi))); } return mulcIR(y, xi); } if (isintzero(yr)) return mulcIR(x, yi); z = cgetg(3,t_COMPLEX); av = avma; #if 0 /* 3M method avoiding catastrophic cancellation, BUT loses accuracy due to * e.g. xr + xi if exponents differ */ if (did_add(xr, xi, &p3)) { if (did_add(yr, yi, &p4)) { /* R = xr*yr - xi*yi * I = (xr+xi)(yr+yi) - xr*yr - xi*yi */ p1 = gmul(xr,yr); p2 = gmul(xi,yi); p2 = gneg(p2); p3 = gmul(p3, p4); p4 = gsub(p2, p1); } else { /* R = (xr + xi) * (yr - yi) + (xr * yi - xi * yr) * I = xr*yi + xi*yr */ p1 = gmul(p3,p4); p3 = gmul(xr,yi); p4 = gmul(xi,yr); p2 = gsub(p3, p4); } } else { if (did_add(yr, yi, &p4)) { /* R = (xr - xi) * (yr + yi) + (xi * yr - xr * yi) * I = xr*yi +xi*yr */ p1 = gmul(p3,p4); p3 = gmul(xr,yi); p4 = gmul(xi,yr); p2 = gsub(p4, p3); } else { /* R = xr*yr - xi*yi * I = -(xr-xi)(yr-yi) + xr*yr + xi*yi */ p3 = gneg( gmul(p3, p4) ); p1 = gmul(xr,yr); p2 = gmul(xi,yi); p4 = gadd(p1, p2); p2 = gneg(p2); } } tetpil = avma; gel(z,1) = gadd(p1,p2); gel(z,2) = gadd(p3,p4); #else if (typ(xr)==t_INT && typ(yr)==t_INT && typ(xi)==t_INT && typ(yi)==t_INT) { /* 3M formula */ p3 = addii(xr,xi); p4 = addii(yr,yi); p1 = mulii(xr,yr); p2 = mulii(xi,yi); p3 = mulii(p3,p4); p4 = addii(p2,p1); tetpil = avma; gel(z,1) = subii(p1,p2); gel(z,2) = subii(p3,p4); if (!signe(gel(z,2))) return gerepileuptoint((pari_sp)(z+3), gel(z,1)); } else { /* naive 4M formula: avoid all loss of accuracy */ p1 = gmul(xr,yr); p2 = gmul(xi,yi); p3 = gmul(xr,yi); p4 = gmul(xi,yr); tetpil = avma; gel(z,1) = gsub(p1,p2); gel(z,2) = gadd(p3,p4); if (isintzero(gel(z,2))) { cgiv(gel(z,2)); return gerepileupto((pari_sp)(z+3), gel(z,1)); } } #endif gerepilecoeffssp(av,tetpil, z+1,2); return z; } /* x,y PADIC */ static GEN mulpp(GEN x, GEN y) { long l = valp(x) + valp(y); pari_sp av; GEN z, t; if (!equalii(gel(x,2),gel(y,2))) pari_err_OP("*",x,y); if (!signe(gel(x,4))) return zeropadic(gel(x,2), l); if (!signe(gel(y,4))) return zeropadic(gel(x,2), l); t = (precp(x) > precp(y))? y: x; z = cgetp(t); setvalp(z,l); av = avma; affii(remii(mulii(gel(x,4),gel(y,4)), gel(t,3)), gel(z,4)); avma = av; return z; } /* x,y QUAD */ static GEN mulqq(GEN x, GEN y) { GEN z = cgetg(4,t_QUAD); GEN p1, p2, p3, p4, P = gel(x,1), b = gel(P,3), c = gel(P,2); pari_sp av, tetpil; if (!ZX_equal(P, gel(y,1))) pari_err_OP("*",x,y); gel(z,1) = ZX_copy(P); av = avma; p2 = gmul(gel(x,2),gel(y,2)); p3 = gmul(gel(x,3),gel(y,3)); p1 = gmul(gneg_i(c),p3); if (signe(b)) p4 = gadd(gmul(gel(x,2),gel(y,3)), gmul(gel(x,3),gel(y,2))); else { p3 = gmul(gel(x,2),gel(y,3)); p4 = gmul(gel(x,3),gel(y,2)); } tetpil = avma; gel(z,2) = gadd(p2,p1); gel(z,3) = gadd(p4,p3); gerepilecoeffssp(av,tetpil,z+2,2); return z; } GEN mulcxI(GEN x) { GEN z; switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: return mkcomplex(gen_0, x); case t_COMPLEX: if (isintzero(gel(x,1))) return gneg(gel(x,2)); z = cgetg(3,t_COMPLEX); gel(z,1) = gneg(gel(x,2)); gel(z,2) = gel(x,1); return z; default: return gmul(gen_I(), x); } } GEN mulcxmI(GEN x) { GEN z; switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: return mkcomplex(gen_0, gneg(x)); case t_COMPLEX: if (isintzero(gel(x,1))) return gel(x,2); z = cgetg(3,t_COMPLEX); gel(z,1) = gel(x,2); gel(z,2) = gneg(gel(x,1)); return z; default: return gmul(mkcomplex(gen_0, gen_m1), x); } } /* x * I^k */ GEN mulcxpowIs(GEN x, long k) { switch (k & 3) { case 1: return mulcxI(x); case 2: return gneg(x); case 3: return mulcxmI(x); } return x; } /* fill in coefficients of t_SER z from coeffs of t_POL y */ static GEN fill_ser(GEN z, GEN y) { long i, lx = lg(z), ly = lg(y); if (ly >= lx) { for (i = 2; i < lx; i++) gel(z,i) = gel(y,i); } else { for (i = 2; i < ly; i++) gel(z,i) = gel(y,i); for ( ; i < lx; i++) gel(z,i) = gen_0; } return normalize(z); } GEN gmul(GEN x, GEN y) { long tx, ty, lx, ly, vx, vy, i, l; pari_sp av, tetpil; GEN z, p1, p2; if (x == y) return gsqr(x); tx = typ(x); ty = typ(y); if (tx == ty) switch(tx) { case t_INT: return mulii(x,y); case t_REAL: return mulrr(x,y); case t_INTMOD: { GEN X = gel(x,1), Y = gel(y,1); z = cgetg(3,t_INTMOD); if (X==Y || equalii(X,Y)) return mul_intmod_same(z, X, gel(x,2), gel(y,2)); gel(z,1) = gcdii(X,Y); warn_coercion(X,Y,gel(z,1)); av = avma; p1 = mulii(gel(x,2),gel(y,2)); gel(z,2) = gerepileuptoint(av, remii(p1, gel(z,1))); return z; } case t_FRAC: { GEN x1 = gel(x,1), x2 = gel(x,2); GEN y1 = gel(y,1), y2 = gel(y,2); z=cgetg(3,t_FRAC); p1 = gcdii(x1, y2); if (!equali1(p1)) { x1 = diviiexact(x1,p1); y2 = diviiexact(y2,p1); } p1 = gcdii(x2, y1); if (!equali1(p1)) { x2 = diviiexact(x2,p1); y1 = diviiexact(y1,p1); } tetpil = avma; gel(z,2) = mulii(x2,y2); gel(z,1) = mulii(x1,y1); fix_frac_if_int_GC(z,tetpil); return z; } case t_COMPLEX: return mulcc(x, y); case t_PADIC: return mulpp(x, y); case t_QUAD: return mulqq(x, y); case t_FFELT: return FF_mul(x, y); case t_POLMOD: if (RgX_equal_var(gel(x,1), gel(y,1))) return mul_polmod_same(gel(x,1), gel(x,2), gel(y,2)); return mul_polmod(gel(x,1), gel(y,1), gel(x,2), gel(y,2)); case t_POL: vx = varn(x); vy = varn(y); if (vx != vy) { if (varncmp(vx, vy) < 0) return RgX_Rg_mul(x, y); else return RgX_Rg_mul(y, x); } return RgX_mul(x, y); case t_SER: { vx = varn(x); vy = varn(y); if (vx != vy) { if (varncmp(vx, vy) < 0) return mul_ser_scal(x, y); else return mul_ser_scal(y, x); } lx = lg(x); ly = lg(y); if (lx > ly) { lx = ly; swap(x, y); } if (lx == 2) return zeroser(vx, valp(x)+valp(y)); av = avma; z = cgetg(lx,t_SER); z[1] = evalvalp(valp(x)+valp(y)) | evalvarn(vx) | evalsigne(1); x = ser2pol_i(x, lx); y = ser2pol_i(y, lx); y = RgXn_mul(x, y, lx-2); return gerepilecopy(av, fill_ser(z,y)); } case t_QFI: return qficomp(x,y); case t_QFR: return qfrcomp(x,y); case t_RFRAC: return mul_rfrac(gel(x,1),gel(x,2), gel(y,1),gel(y,2)); case t_MAT: return RgM_mul(x, y); case t_VECSMALL: /* multiply as permutation. cf perm_mul */ z = cgetg_copy(x, &l); if (l != lg(y)) break; for (i=1; i= l) pari_err_TYPE2("*",x,y); z[i] = x[yi]; } return z; default: pari_err_TYPE2("*",x,y); } /* tx != ty */ if (is_const_t(ty) && is_const_t(tx)) { if (tx > ty) { swap(x,y); lswap(tx,ty); } switch(tx) { case t_INT: switch(ty) { case t_REAL: return signe(x)? mulir(x,y): gen_0; case t_INTMOD: z = cgetg(3, t_INTMOD); return mul_intmod_same(z, gel(y,1), gel(y,2), modii(x, gel(y,1))); case t_FRAC: if (!signe(x)) return gen_0; z=cgetg(3,t_FRAC); p1 = gcdii(x,gel(y,2)); if (equali1(p1)) { avma = (pari_sp)z; gel(z,2) = icopy(gel(y,2)); gel(z,1) = mulii(gel(y,1), x); } else { x = diviiexact(x,p1); tetpil = avma; gel(z,2) = diviiexact(gel(y,2), p1); gel(z,1) = mulii(gel(y,1), x); fix_frac_if_int_GC(z,tetpil); } return z; case t_COMPLEX: return signe(x)? mulRc(x, y): gen_0; case t_PADIC: return signe(x)? mulTp(x, y): gen_0; case t_QUAD: return mulRq(x,y); case t_FFELT: return FF_Z_mul(y,x); } case t_REAL: switch(ty) { case t_FRAC: return mulrfrac(x, y); case t_COMPLEX: return mulRc(x, y); case t_QUAD: return mulqf(y, x, realprec(x)); default: pari_err_TYPE2("*",x,y); } case t_INTMOD: switch(ty) { case t_FRAC: { GEN X = gel(x,1); z = cgetg(3, t_INTMOD); p1 = Fp_mul(gel(y,1), gel(x,2), X); return div_intmod_same(z, X, p1, remii(gel(y,2), X)); } case t_COMPLEX: return mulRc_direct(x,y); case t_PADIC: { GEN X = gel(x,1); z = cgetg(3, t_INTMOD); return mul_intmod_same(z, X, gel(x,2), padic_to_Fp(y, X)); } case t_QUAD: return mulRq(x, y); case t_FFELT: if (!equalii(gel(x,1),FF_p_i(y))) pari_err_OP("*",x,y); return FF_Z_mul(y,gel(x,2)); } case t_FRAC: switch(ty) { case t_COMPLEX: return mulRc(x, y); case t_PADIC: return signe(gel(x,1))? mulTp(x, y): gen_0; case t_QUAD: return mulRq(x, y); case t_FFELT: return FF_Z_Z_muldiv(y, gel(x,1),gel(x,2)); } case t_FFELT: pari_err_TYPE2("*",x,y); case t_COMPLEX: switch(ty) { case t_PADIC: return Zp_nosquare_m1(gel(y,2))? mulRc(y, x): mulTp(x, y); case t_QUAD: lx = precision(x); if (!lx) pari_err_OP("*",x,y); return mulqf(y, x, lx); } case t_PADIC: /* ty == t_QUAD */ return (kro_quad(y,gel(x,2))== -1)? mulRq(x, y): mulTp(y, x); } } if (is_matvec_t(ty)) { if (!is_matvec_t(tx)) { if (is_noncalc_t(tx)) pari_err_TYPE2( "*",x,y); /* necessary if ly = 1 */ z = cgetg_copy(y, &ly); for (i=1; i ty) { swap(x,y); lswap(tx,ty); } /* tx < ty, !ismatvec(x and y) */ if (ty == t_POLMOD) /* is_const_t(tx) in this case */ return mul_polmod_scal(gel(y,1), gel(y,2), x); if (is_scalar_t(tx)) { if (tx == t_POLMOD) { vx = varn(gel(x,1)); vy = gvar(y); if (vx != vy) { if (varncmp(vx,vy) > 0) return mul_scal(y, x, ty); return mul_polmod_scal(gel(x,1), gel(x,2), y); } /* error if ty == t_SER */ av = avma; y = gmod(y, gel(x,1)); return gerepileupto(av, mul_polmod_same(gel(x,1), gel(x,2), y)); } return mul_scal(y, x, ty); } /* x and y are not scalars, nor matvec */ vx = gvar(x); vy = gvar(y); if (vx != vy) /* x or y is treated as a scalar */ return (varncmp(vx, vy) < 0)? mul_scal(x, y, tx) : mul_scal(y, x, ty); /* vx = vy */ switch(tx) { case t_POL: switch (ty) { case t_SER: { long vn; if (lg(x) == 2) return zeropol(vx); if (lg(y) == 2) return zeroser(vx, valp(y)+RgX_val(x)); av = avma; vn = RgX_valrem(x, &x); /* take advantage of x = t^n ! */ if (degpol(x)) { p1 = RgX_to_ser(x,lg(y)); if (vn) settyp(x, t_VECSMALL); /* *new* x left on stack */ p2 = gmul(p1,y); settyp(p1, t_VECSMALL); /* p1 left on stack */ } else { avma = av; p2 = mul_ser_scal(y, gel(x,2)); } setvalp(p2, valp(p2) + vn); return p2; } case t_RFRAC: return mul_rfrac_scal(gel(y,1),gel(y,2), x); } break; case t_SER: switch (ty) { case t_RFRAC: av = avma; return gerepileupto(av, gdiv(gmul(gel(y,1),x), gel(y,2))); } break; } pari_err_TYPE2("*",x,y); return NULL; /* LCOV_EXCL_LINE */ } /* return a non-normalized result */ GEN sqr_ser_part(GEN x, long l1, long l2) { long i, j, l; pari_sp av; GEN Z, z, p1, p2; long mi; if (l2 < l1) return zeroser(varn(x), 2*valp(x)); p2 = cgetg(l2+2, t_VECSMALL)+1; /* left on stack on exit */ Z = cgetg(l2-l1+3, t_SER); Z[1] = evalvalp(2*valp(x)) | evalvarn(varn(x)); z = Z + 2-l1; x += 2; mi = 0; for (i=0; i>1) - 1; for (j=i-mi; j<=minss(l,mi); j++) if (p2[j] && p2[i-j]) p1 = gadd(p1, gmul(gel(x,j),gel(x,i-j))); p1 = gshift(p1,1); if ((i&1) == 0 && p2[i>>1]) p1 = gadd(p1, gsqr(gel(x,i>>1))); gel(z,i) = gerepileupto(av,p1); } return Z; } GEN gsqr(GEN x) { long i, lx; pari_sp av, tetpil; GEN z, p1, p2, p3, p4; switch(typ(x)) { case t_INT: return sqri(x); case t_REAL: return sqrr(x); case t_INTMOD: { GEN X = gel(x,1); z = cgetg(3,t_INTMOD); gel(z,2) = gerepileuptoint((pari_sp)z, remii(sqri(gel(x,2)), X)); gel(z,1) = icopy(X); return z; } case t_FRAC: return sqrfrac(x); case t_COMPLEX: if (isintzero(gel(x,1))) { av = avma; return gerepileupto(av, gneg(gsqr(gel(x,2)))); } z = cgetg(3,t_COMPLEX); av = avma; p1 = gadd(gel(x,1),gel(x,2)); p2 = gsub(gel(x,1), gel(x,2)); p3 = gmul(gel(x,1),gel(x,2)); tetpil = avma; gel(z,1) = gmul(p1,p2); gel(z,2) = gshift(p3,1); gerepilecoeffssp(av,tetpil,z+1,2); return z; case t_PADIC: z = cgetg(5,t_PADIC); i = (absequaliu(gel(x,2), 2) && signe(gel(x,4)))? 1: 0; if (i && precp(x) == 1) i = 2; /* (1 + O(2))^2 = 1 + O(2^3) */ z[1] = evalprecp(precp(x)+i) | evalvalp(valp(x)*2); gel(z,2) = icopy(gel(x,2)); gel(z,3) = shifti(gel(x,3), i); av = avma; gel(z,4) = gerepileuptoint(av, remii(sqri(gel(x,4)), gel(z,3))); return z; case t_QUAD: z = cgetg(4,t_QUAD); p1 = gel(x,1); gel(z,1) = ZX_copy(p1); av = avma; p2 = gsqr(gel(x,2)); p3 = gsqr(gel(x,3)); p4 = gmul(gneg_i(gel(p1,2)),p3); if (gequal0(gel(p1,3))) { tetpil = avma; gel(z,2) = gerepile(av,tetpil,gadd(p4,p2)); av = avma; p2 = gmul(gel(x,2),gel(x,3)); tetpil = avma; gel(z,3) = gerepile(av,tetpil,gmul2n(p2,1)); return z; } p1 = gmul2n(gmul(gel(x,2),gel(x,3)), 1); tetpil = avma; gel(z,2) = gadd(p2,p4); gel(z,3) = gadd(p1,p3); gerepilecoeffssp(av,tetpil,z+2,2); return z; case t_POLMOD: return sqr_polmod(gel(x,1), gel(x,2)); case t_FFELT: return FF_sqr(x); case t_POL: return RgX_sqr(x); case t_SER: lx = lg(x); if (ser_isexactzero(x)) { GEN z = gcopy(x); setvalp(z, 2*valp(x)); return z; } if (lx < 40) return normalize( sqr_ser_part(x, 0, lx-3) ); else { pari_sp av = avma; GEN z = cgetg(lx,t_SER); z[1] = evalvalp(2*valp(x)) | evalvarn(varn(x)) | evalsigne(1); x = ser2pol_i(x,lx); x = RgXn_sqr(x, lx-2); return gerepilecopy(av, fill_ser(z,x)); } case t_RFRAC: z = cgetg(3,t_RFRAC); gel(z,1) = gsqr(gel(x,1)); gel(z,2) = gsqr(gel(x,2)); return z; case t_MAT: return RgM_sqr(x); case t_QFR: return qfrsqr(x); case t_QFI: return qfisqr(x); case t_VECSMALL: z = cgetg_copy(x, &lx); for (i=1; i= lx) pari_err_TYPE2("*",x,x); z[i] = x[xi]; } return z; } pari_err_TYPE2("*",x,x); return NULL; /* LCOV_EXCL_LINE */ } /********************************************************************/ /** **/ /** DIVISION **/ /** **/ /********************************************************************/ static GEN div_rfrac_scal(GEN x, GEN y) { pari_sp av = avma; GEN d = rfrac_denom_mul_scal(gel(x,2), y); return gerepileupto(av, gred_rfrac_simple(gel(x,1), d)); } static GEN div_scal_rfrac(GEN x, GEN y) { GEN y1 = gel(y,1), y2 = gel(y,2); pari_sp av = avma; if (typ(y1) == t_POL && varn(y2) == varn(y1)) { if (degpol(y1)) return gerepileupto(av, gred_rfrac_simple(gmul(x, y2), y1)); y1 = gel(y1,2); } return RgX_Rg_mul(y2, gdiv(x,y1)); } static GEN div_rfrac(GEN x, GEN y) { return mul_rfrac(gel(x,1),gel(x,2), gel(y,2),gel(y,1)); } static GEN div_ser_scal(GEN x, GEN y) { long i, lx; GEN z; if (ser_isexactzero(x)) { if (lg(x) == 2) return gcopy(x); return scalarser(gdiv(gel(x,2), y), varn(x), valp(x)); } z = cgetg_copy(x, &lx); z[1] = x[1]; for (i=2; i 2; l--, ly--, y++) { y_lead = gel(y,2); if (!gequal0(y_lead)) break; } if (ly <= 2) pari_err_INV("div_ser", y0); } if (ly < lx) lx = ly; p2 = cgetg(lx, t_VECSMALL); /* left on stack for efficiency */ for (i=3; i b) { M = gel(y,3); } else { M = gel(x,3); b = a; } z = cgetg(5, t_PADIC); z[1] = _evalprecp(b) | evalvalp(valp(x) - valp(y)); gel(z,2) = icopy(gel(x,2)); gel(z,3) = icopy(M); av = avma; gel(z,4) = gerepileuptoint(av, remii(mulii(gel(x,4), Fp_inv(gel(y,4), M)), M) ); return z; } static GEN div_polmod_same(GEN T, GEN x, GEN y) { long v = varn(T); GEN a, z = cgetg(3, t_POLMOD); gel(z,1) = RgX_copy(T); if (typ(y) != t_POL || varn(y) != v || lg(y) <= 3) a = gdiv(x, y); else if (typ(x) != t_POL || varn(x) != v || lg(x) <= 3) { pari_sp av = avma; a = gerepileupto(av, gmul(x, RgXQ_inv(y, T))); } else if (degpol(T) == 2 && isint1(gel(T,4))) /* quadratic fields */ { pari_sp av = avma; a = quad_polmod_mul(T, x, quad_polmod_conj(y, T)); a = RgX_Rg_div(a, quad_polmod_norm(y, T)); a = gerepileupto(av, a); } else { pari_sp av = avma; a = RgXQ_mul(x, ginvmod(y, gel(z,1)), gel(z,1)); a = gerepileupto(av, a); } gel(z,2) = a; return z; } GEN gdiv(GEN x, GEN y) { long tx = typ(x), ty = typ(y), lx, ly, vx, vy, i; pari_sp av, tetpil; GEN z, p1, p2; if (tx == ty) switch(tx) { case t_INT: return Qdivii(x,y); case t_REAL: return divrr(x,y); case t_INTMOD: { GEN X = gel(x,1), Y = gel(y,1); z = cgetg(3,t_INTMOD); if (X==Y || equalii(X,Y)) return div_intmod_same(z, X, gel(x,2), gel(y,2)); gel(z,1) = gcdii(X,Y); warn_coercion(X,Y,gel(z,1)); av = avma; p1 = mulii(gel(x,2), Fp_inv(gel(y,2), gel(z,1))); gel(z,2) = gerepileuptoint(av, remii(p1, gel(z,1))); return z; } case t_FRAC: { GEN x1 = gel(x,1), x2 = gel(x,2); GEN y1 = gel(y,1), y2 = gel(y,2); z = cgetg(3, t_FRAC); p1 = gcdii(x1, y1); if (!equali1(p1)) { x1 = diviiexact(x1,p1); y1 = diviiexact(y1,p1); } p1 = gcdii(x2, y2); if (!equali1(p1)) { x2 = diviiexact(x2,p1); y2 = diviiexact(y2,p1); } tetpil = avma; gel(z,2) = mulii(x2,y1); gel(z,1) = mulii(x1,y2); normalize_frac(z); fix_frac_if_int_GC(z,tetpil); return z; } case t_COMPLEX: if (isintzero(gel(y,1))) { y = gel(y,2); if (isintzero(gel(x,1))) return gdiv(gel(x,2), y); z = cgetg(3,t_COMPLEX); gel(z,1) = gdiv(gel(x,2), y); av = avma; gel(z,2) = gerepileupto(av, gneg(gdiv(gel(x,1), y))); return z; } av = avma; p1 = cxnorm(y); p2 = mulcc(x, conj_i(y)); tetpil = avma; return gerepile(av, tetpil, gdiv(p2,p1)); case t_PADIC: if (!equalii(gel(x,2),gel(y,2))) pari_err_OP("/",x,y); return divpp(x, y); case t_QUAD: if (!ZX_equal(gel(x,1),gel(y,1))) pari_err_OP("/",x,y); av = avma; p1 = quadnorm(y); p2 = mulqq(x, conj_i(y)); tetpil = avma; return gerepile(av, tetpil, gdiv(p2,p1)); case t_FFELT: return FF_div(x,y); case t_POLMOD: if (RgX_equal_var(gel(x,1), gel(y,1))) z = div_polmod_same(gel(x,1), gel(x,2), gel(y,2)); else { av = avma; z = gerepileupto(av, gmul(x, ginv(y))); } return z; case t_POL: vx = varn(x); vy = varn(y); if (vx != vy) { if (varncmp(vx, vy) < 0) return RgX_Rg_div(x, y); else return div_scal_pol(x, y); } if (!signe(y)) pari_err_INV("gdiv",y); if (lg(y) == 3) return RgX_Rg_div(x,gel(y,2)); av = avma; return gerepileupto(av, gred_rfrac2(x,y)); case t_SER: vx = varn(x); vy = varn(y); if (vx != vy) { if (varncmp(vx, vy) < 0) return div_ser_scal(x, y); else return div_scal_ser(x, y); } return div_ser(x, y, vx); case t_RFRAC: vx = varn(gel(x,2)); vy = varn(gel(y,2)); if (vx != vy) { if (varncmp(vx, vy) < 0) return div_rfrac_scal(x, y); else return div_scal_rfrac(x, y); } return div_rfrac(x,y); case t_QFI: av = avma; return gerepileupto(av, qficomp(x, ginv(y))); case t_QFR: av = avma; return gerepileupto(av, qfrcomp(x, ginv(y))); case t_MAT: av = avma; p1 = RgM_inv(y); if (!p1) pari_err_INV("gdiv",y); return gerepileupto(av, RgM_mul(x, p1)); default: pari_err_TYPE2("/",x,y); } if (tx==t_INT && is_const_t(ty)) /* optimized for speed */ { long s = signe(x); if (!s) { if (gequal0(y)) pari_err_INV("gdiv",y); switch (ty) { default: return gen_0; case t_INTMOD: z = cgetg(3,t_INTMOD); gel(z,1) = icopy(gel(y,1)); gel(z,2) = gen_0; return z; case t_FFELT: return FF_zero(y); } } if (is_pm1(x)) { if (s > 0) return ginv(y); av = avma; return gerepileupto(av, ginv(gneg(y))); } switch(ty) { case t_REAL: return divir(x,y); case t_INTMOD: z = cgetg(3, t_INTMOD); return div_intmod_same(z, gel(y,1), modii(x, gel(y,1)), gel(y,2)); case t_FRAC: z = cgetg(3,t_FRAC); p1 = gcdii(x,gel(y,1)); if (equali1(p1)) { avma = (pari_sp)z; gel(z,2) = icopy(gel(y,1)); gel(z,1) = mulii(gel(y,2), x); normalize_frac(z); fix_frac_if_int(z); } else { x = diviiexact(x,p1); tetpil = avma; gel(z,2) = diviiexact(gel(y,1), p1); gel(z,1) = mulii(gel(y,2), x); normalize_frac(z); fix_frac_if_int_GC(z,tetpil); } return z; case t_FFELT: return Z_FF_div(x,y); case t_COMPLEX: return divRc(x,y); case t_PADIC: return divTp(x, y); case t_QUAD: av = avma; p1 = quadnorm(y); p2 = mulRq(x, conj_i(y)); tetpil = avma; return gerepile(av, tetpil, gdiv(p2,p1)); } } if (gequal0(y)) { if (is_matvec_t(tx) && lg(x) == 1) return gcopy(x); if (ty != t_MAT) pari_err_INV("gdiv",y); } if (is_const_t(tx) && is_const_t(ty)) switch(tx) { case t_REAL: switch(ty) { case t_INT: return divri(x,y); case t_FRAC: av = avma; z = divri(mulri(x,gel(y,2)), gel(y,1)); return gerepileuptoleaf(av, z); case t_COMPLEX: return divRc(x, y); case t_QUAD: return divfq(x, y, realprec(x)); default: pari_err_TYPE2("/",x,y); } case t_INTMOD: switch(ty) { case t_INT: z = cgetg(3, t_INTMOD); return div_intmod_same(z, gel(x,1), gel(x,2), modii(y, gel(x,1))); case t_FRAC: { GEN X = gel(x,1); z = cgetg(3,t_INTMOD); p1 = remii(mulii(gel(y,2), gel(x,2)), X); return div_intmod_same(z, X, p1, modii(gel(y,1), X)); } case t_FFELT: if (!equalii(gel(x,1),FF_p_i(y))) pari_err_OP("/",x,y); return Z_FF_div(gel(x,2),y); case t_COMPLEX: av = avma; return gerepileupto(av, mulRc_direct(gdiv(x,cxnorm(y)), conj_i(y))); case t_QUAD: av = avma; p1 = quadnorm(y); p2 = gmul(x,conj_i(y)); tetpil = avma; return gerepile(av,tetpil, gdiv(p2,p1)); case t_PADIC: { GEN X = gel(x,1); z = cgetg(3, t_INTMOD); return div_intmod_same(z, X, gel(x,2), padic_to_Fp(y, X)); } case t_REAL: pari_err_TYPE2("/",x,y); } case t_FRAC: switch(ty) { case t_INT: z = cgetg(3, t_FRAC); p1 = gcdii(y,gel(x,1)); if (equali1(p1)) { avma = (pari_sp)z; tetpil = 0; gel(z,1) = icopy(gel(x,1)); } else { y = diviiexact(y,p1); tetpil = avma; gel(z,1) = diviiexact(gel(x,1), p1); } gel(z,2) = mulii(gel(x,2),y); normalize_frac(z); if (tetpil) fix_frac_if_int_GC(z,tetpil); return z; case t_REAL: av=avma; p1=mulri(y,gel(x,2)); tetpil=avma; return gerepile(av, tetpil, divir(gel(x,1), p1)); case t_INTMOD: { GEN Y = gel(y,1); z = cgetg(3,t_INTMOD); p1 = remii(mulii(gel(y,2),gel(x,2)), Y); return div_intmod_same(z, Y, modii(gel(x,1), Y), p1); } case t_FFELT: av=avma; return gerepileupto(av,Z_FF_div(gel(x,1),FF_Z_mul(y,gel(x,2)))); case t_COMPLEX: return divRc(x, y); case t_PADIC: if (!signe(gel(x,1))) return gen_0; return divTp(x, y); case t_QUAD: av=avma; p1=quadnorm(y); p2=gmul(x,conj_i(y)); tetpil=avma; return gerepile(av,tetpil,gdiv(p2,p1)); } case t_FFELT: switch (ty) { case t_INT: return FF_Z_Z_muldiv(x,gen_1,y); case t_FRAC: return FF_Z_Z_muldiv(x,gel(y,2),gel(y,1)); case t_INTMOD: if (!equalii(gel(y,1),FF_p_i(x))) pari_err_OP("/",x,y); return FF_Z_Z_muldiv(x,gen_1,gel(y,2)); default: pari_err_TYPE2("/",x,y); } break; case t_COMPLEX: switch(ty) { case t_INT: case t_REAL: case t_FRAC: return divcR(x,y); case t_INTMOD: return mulRc_direct(ginv(y), x); case t_PADIC: return Zp_nosquare_m1(gel(y,2))? divcR(x,y): divTp(x, y); case t_QUAD: lx = precision(x); if (!lx) pari_err_OP("/",x,y); return divfq(x, y, lx); } case t_PADIC: switch(ty) { case t_INT: case t_FRAC: { GEN p = gel(x,2); return signe(gel(x,4))? divpT(x, y) : zeropadic(p, valp(x) - Q_pval(y,p)); } case t_INTMOD: { GEN Y = gel(y,1); z = cgetg(3, t_INTMOD); return div_intmod_same(z, Y, padic_to_Fp(x, Y), gel(y,2)); } case t_COMPLEX: case t_QUAD: av=avma; p1=gmul(x,conj_i(y)); p2=gnorm(y); tetpil=avma; return gerepile(av,tetpil,gdiv(p1,p2)); case t_REAL: pari_err_TYPE2("/",x,y); } case t_QUAD: switch (ty) { case t_INT: case t_INTMOD: case t_FRAC: z = cgetg(4,t_QUAD); gel(z,1) = ZX_copy(gel(x,1)); gel(z,2) = gdiv(gel(x,2), y); gel(z,3) = gdiv(gel(x,3), y); return z; case t_REAL: return divqf(x, y, realprec(y)); case t_PADIC: return divTp(x, y); case t_COMPLEX: ly = precision(y); if (!ly) pari_err_OP("/",x,y); return divqf(x, y, ly); } } switch(ty) { case t_REAL: case t_INTMOD: case t_PADIC: case t_POLMOD: return gmul(x, ginv(y)); /* missing gerepile, for speed */ case t_MAT: av = avma; p1 = RgM_inv(y); if (!p1) pari_err_INV("gdiv",y); return gerepileupto(av, gmul(x, p1)); case t_VEC: case t_COL: case t_LIST: case t_STR: case t_VECSMALL: case t_CLOSURE: pari_err_TYPE2("/",x,y); } switch(tx) { case t_VEC: case t_COL: case t_MAT: z = cgetg_copy(x, &lx); for (i=1; i 0) return div_scal_T(x, y, ty); retmkpolmod(gdiv(gel(x,2), y), RgX_copy(X)); } /* y is POL, SER or RFRAC */ av = avma; switch(ty) { case t_RFRAC: y = gmod(ginv(y), X); break; default: y = ginvmod(gmod(y,X), X); } return gerepileupto(av, mul_polmod_same(X, gel(x,2), y)); } /* x and y are not both is_scalar_t. If one of them is scalar, it's not a * POLMOD (done already), hence its variable is NO_VARIABLE. If the other has * variable NO_VARIABLE, then the operation is incorrect */ vx = gvar(x); if (vx != vy) { /* includes cases where one is scalar */ if (varncmp(vx, vy) < 0) return div_T_scal(x, y, tx); else return div_scal_T(x, y, ty); } switch(tx) { case t_POL: switch(ty) { case t_SER: if (lg(y) == 2) return zeroser(vx, RgX_val(x) - valp(y)); p1 = RgX_to_ser(x,lg(y)); p2 = div_ser(p1, y, vx); settyp(p1, t_VECSMALL); /* p1 left on stack */ return p2; case t_RFRAC: { GEN y1 = gel(y,1), y2 = gel(y,2); if (typ(y1) == t_POL && varn(y1) == vx) return mul_rfrac_scal(y2, y1, x); av = avma; return gerepileupto(av, RgX_Rg_div(RgX_mul(y2, x), y1)); } } break; case t_SER: switch(ty) { case t_POL: if (lg(x) == 2) return zeroser(vx, valp(x) - RgX_val(y)); p1 = RgX_to_ser_inexact(y,lg(x)); p2 = div_ser(x, p1, vx); settyp(p1, t_VECSMALL); /* p1 left on stack */ return p2; case t_RFRAC: av = avma; return gerepileupto(av, gdiv(gmul(x,gel(y,2)), gel(y,1))); } break; case t_RFRAC: switch(ty) { case t_POL: return div_rfrac_pol(gel(x,1),gel(x,2), y); case t_SER: av = avma; z = RgX_to_ser_inexact(gel(x,2), lg(y)); return gerepileupto(av, gdiv(gel(x,1), gmul(z,y))); } break; } pari_err_TYPE2("/",x,y); return NULL; /* LCOV_EXCL_LINE */ } /********************************************************************/ /** **/ /** SIMPLE MULTIPLICATION **/ /** **/ /********************************************************************/ GEN gmulsg(long s, GEN y) { long ly, i; pari_sp av; GEN z; switch(typ(y)) { case t_INT: return mulsi(s,y); case t_REAL: return mulsr(s,y); case t_INTMOD: { GEN p = gel(y,1); z = cgetg(3,t_INTMOD); gel(z,2) = gerepileuptoint((pari_sp)z, modii(mulsi(s,gel(y,2)), p)); gel(z,1) = icopy(p); return z; } case t_FFELT: return FF_Z_mul(y,stoi(s)); case t_FRAC: if (!s) return gen_0; z = cgetg(3,t_FRAC); i = labs(s); i = ugcd(i, umodiu(gel(y,2), i)); if (i == 1) { gel(z,2) = icopy(gel(y,2)); gel(z,1) = mulis(gel(y,1), s); } else { gel(z,2) = divis(gel(y,2), i); gel(z,1) = mulis(gel(y,1), s/i); fix_frac_if_int(z); } return z; case t_COMPLEX: z = cgetg(3, t_COMPLEX); gel(z,1) = gmulsg(s,gel(y,1)); gel(z,2) = gmulsg(s,gel(y,2)); return z; case t_PADIC: if (!s) return gen_0; av = avma; return gerepileupto(av, mulpp(cvtop2(stoi(s),y), y)); case t_QUAD: z = cgetg(4, t_QUAD); gel(z,1) = ZX_copy(gel(y,1)); gel(z,2) = gmulsg(s,gel(y,2)); gel(z,3) = gmulsg(s,gel(y,3)); return z; case t_POLMOD: retmkpolmod(gmulsg(s,gel(y,2)), RgX_copy(gel(y,1))); case t_POL: if (!signe(y)) return RgX_copy(y); if (!s) return scalarpol(Rg_get_0(y), varn(y)); z = cgetg_copy(y, &ly); z[1]=y[1]; for (i=2; i=0) return shifti(x,n); if (!signe(x)) return gen_0; l = vali(x); n = -n; if (n<=l) return shifti(x,-n); z = cgetg(3,t_FRAC); gel(z,1) = shifti(x,-l); gel(z,2) = int2n(n-l); return z; case t_REAL: return shiftr(x,n); case t_INTMOD: b = gel(x,1); a = gel(x,2); z = cgetg(3,t_INTMOD); if (n <= 0) return div_intmod_same(z, b, a, modii(int2n(-n), b)); gel(z,2) = gerepileuptoint((pari_sp)z, modii(shifti(a,n), b)); gel(z,1) = icopy(b); return z; case t_FFELT: return FF_mul2n(x,n); case t_FRAC: a = gel(x,1); b = gel(x,2); l = vali(a); k = vali(b); if (n+l >= k) { if (expi(b) == k) return shifti(a,n-k); /* b power of 2 */ l = n-k; k = -k; } else { k = -(l+n); l = -l; } z = cgetg(3,t_FRAC); gel(z,1) = shifti(a,l); gel(z,2) = shifti(b,k); return z; case t_COMPLEX: z = cgetg(3,t_COMPLEX); gel(z,1) = gmul2n(gel(x,1),n); gel(z,2) = gmul2n(gel(x,2),n); return z; case t_QUAD: z = cgetg(4,t_QUAD); gel(z,1) = ZX_copy(gel(x,1)); gel(z,2) = gmul2n(gel(x,2),n); gel(z,3) = gmul2n(gel(x,3),n); return z; case t_POLMOD: retmkpolmod(gmul2n(gel(x,2),n), RgX_copy(gel(x,1))); case t_POL: z = cgetg_copy(x, &lx); z[1] = x[1]; for (i=2; i 0? icopy(b): negi(b); z = cgetg(3,t_FRAC); gel(z,1) = icopy(b); gel(z,2) = icopy(a); normalize_frac(z); return z; } case t_COMPLEX: av=avma; p1=cxnorm(x); p2=mkcomplex(gel(x,1), gneg(gel(x,2))); tetpil=avma; return gerepile(av,tetpil,divcR(p2,p1)); case t_QUAD: av=avma; p1=gnorm(x); p2=conj_i(x); tetpil=avma; return gerepile(av,tetpil,gdiv(p2,p1)); case t_PADIC: z = cgetg(5,t_PADIC); if (!signe(gel(x,4))) pari_err_INV("ginv",x); z[1] = _evalprecp(precp(x)) | evalvalp(-valp(x)); gel(z,2) = icopy(gel(x,2)); gel(z,3) = icopy(gel(x,3)); gel(z,4) = Fp_inv(gel(x,4),gel(z,3)); return z; case t_POLMOD: return inv_polmod(gel(x,1), gel(x,2)); case t_FFELT: return FF_inv(x); case t_POL: return gred_rfrac_simple(gen_1,x); case t_SER: return gdiv(gen_1,x); case t_RFRAC: { GEN n = gel(x,1), d = gel(x,2); pari_sp av = avma, ltop; if (gequal0(n)) pari_err_INV("ginv",x); n = simplify_shallow(n); if (typ(n) != t_POL || varn(n) != varn(d)) { if (gequal1(n)) { avma = av; return RgX_copy(d); } ltop = avma; z = RgX_Rg_div(d,n); } else { ltop = avma; z = cgetg(3,t_RFRAC); gel(z,1) = RgX_copy(d); gel(z,2) = RgX_copy(n); } stackdummy(av, ltop); return z; } case t_QFR: av = avma; z = cgetg(5, t_QFR); gel(z,1) = gel(x,1); gel(z,2) = negi( gel(x,2) ); gel(z,3) = gel(x,3); gel(z,4) = negr( gel(x,4) ); return gerepileupto(av, redreal(z)); case t_QFI: y = gcopy(x); if (!equalii(gel(x,1),gel(x,2)) && !equalii(gel(x,1),gel(x,3))) togglesign(gel(y,2)); return y; case t_MAT: y = RgM_inv(x); if (!y) pari_err_INV("ginv",x); return y; case t_VECSMALL: { long i, lx = lg(x)-1; y = zero_zv(lx); for (i=1; i<=lx; i++) { long xi = x[i]; if (xi<1 || xi>lx || y[xi]) pari_err_TYPE("ginv [not a permutation]", x); y[xi] = i; } return y; } } pari_err_TYPE("inverse",x); return NULL; /* LCOV_EXCL_LINE */ } pari-2.11.2/src/basemath/gen3.c0000644000175000017500000032011713447371554014552 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** GENERIC OPERATIONS **/ /** (third part) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /********************************************************************/ /** **/ /** PRINCIPAL VARIABLE NUMBER **/ /** **/ /********************************************************************/ static void recvar(hashtable *h, GEN x) { long i = 1, lx = lg(x); void *v; switch(typ(x)) { case t_POL: case t_SER: v = (void*)varn(x); if (!hash_search(h, v)) hash_insert(h, v, NULL); i = 2; break; case t_POLMOD: case t_RFRAC: case t_VEC: case t_COL: case t_MAT: break; case t_LIST: x = list_data(x); lx = x? lg(x): 1; break; default: return; } for (; i < lx; i++) recvar(h, gel(x,i)); } GEN variables_vecsmall(GEN x) { hashtable *h = hash_create_ulong(100, 1); recvar(h, x); return vars_sort_inplace(hash_keys(h)); } GEN variables_vec(GEN x) { return x? vars_to_RgXV(variables_vecsmall(x)): gpolvar(NULL); } long gvar(GEN x) { long i, v, w, lx; switch(typ(x)) { case t_POL: case t_SER: return varn(x); case t_POLMOD: return varn(gel(x,1)); case t_RFRAC: return varn(gel(x,2)); case t_VEC: case t_COL: case t_MAT: lx = lg(x); break; case t_LIST: x = list_data(x); lx = x? lg(x): 1; break; default: return NO_VARIABLE; } v = NO_VARIABLE; for (i=1; i < lx; i++) { w = gvar(gel(x,i)); if (varncmp(w,v) < 0) v = w; } return v; } /* T main polynomial in R[X], A auxiliary in R[X] (possibly degree 0). * Guess and return the main variable of R */ static long var2_aux(GEN T, GEN A) { long a = gvar2(T); long b = (typ(A) == t_POL && varn(A) == varn(T))? gvar2(A): gvar(A); if (varncmp(a, b) > 0) a = b; return a; } static long var2_rfrac(GEN x) { return var2_aux(gel(x,2), gel(x,1)); } static long var2_polmod(GEN x) { return var2_aux(gel(x,1), gel(x,2)); } /* main variable of x, with the convention that the "natural" main * variable of a POLMOD is mute, so we want the next one. */ static long gvar9(GEN x) { return (typ(x) == t_POLMOD)? var2_polmod(x): gvar(x); } /* main variable of the ring over wich x is defined */ long gvar2(GEN x) { long i, v, w; switch(typ(x)) { case t_POLMOD: return var2_polmod(x); case t_POL: case t_SER: v = NO_VARIABLE; for (i=2; i < lg(x); i++) { w = gvar9(gel(x,i)); if (varncmp(w,v) < 0) v=w; } return v; case t_RFRAC: return var2_rfrac(x); case t_VEC: case t_COL: case t_MAT: v = NO_VARIABLE; for (i=1; i < lg(x); i++) { w = gvar2(gel(x,i)); if (varncmp(w,v)<0) v=w; } return v; } return NO_VARIABLE; } /*******************************************************************/ /* */ /* PRECISION OF SCALAR OBJECTS */ /* */ /*******************************************************************/ static long prec0(long e) { return (e < 0)? nbits2prec(-e): 2; } static long precREAL(GEN x) { return signe(x) ? realprec(x): prec0(expo(x)); } /* x t_REAL, y an exact non-complex type. Return precision(|x| + |y|) */ static long precrealexact(GEN x, GEN y) { long lx, ey = gexpo(y), ex, e; if (ey == -(long)HIGHEXPOBIT) return precREAL(x); ex = expo(x); e = ey - ex; if (!signe(x)) return prec0((e >= 0)? -e: ex); lx = realprec(x); return (e > 0)? lx + nbits2extraprec(e): lx; } static long precCOMPLEX(GEN z) { /* ~ precision(|x| + |y|) */ GEN x = gel(z,1), y = gel(z,2); long e, ex, ey, lz, lx, ly; if (typ(x) != t_REAL) { if (typ(y) != t_REAL) return 0; return precrealexact(y, x); } if (typ(y) != t_REAL) return precrealexact(x, y); /* x, y are t_REALs, cf addrr_sign */ ex = expo(x); ey = expo(y); e = ey - ex; if (!signe(x)) { if (!signe(y)) return prec0( minss(ex,ey) ); if (e <= 0) return prec0(ex); lz = nbits2prec(e); ly = realprec(y); if (lz > ly) lz = ly; return lz; } if (!signe(y)) { if (e >= 0) return prec0(ey); lz = nbits2prec(-e); lx = realprec(x); if (lz > lx) lz = lx; return lz; } if (e < 0) { swap(x, y); e = -e; } lx = realprec(x); ly = realprec(y); if (e) { long d = nbits2extraprec(e), l = ly-d; return (l > lx)? lx + d: ly; } return minss(lx, ly); } long precision(GEN z) { switch(typ(z)) { case t_REAL: return precREAL(z); case t_COMPLEX: return precCOMPLEX(z); } return 0; } long gprecision(GEN x) { long i, k, l; switch(typ(x)) { case t_REAL: return precREAL(x); case t_COMPLEX: return precCOMPLEX(x); case t_INT: case t_INTMOD: case t_FRAC: case t_FFELT: case t_PADIC: case t_QUAD: case t_POLMOD: return 0; case t_POL: case t_SER: k = LONG_MAX; for (i=lg(x)-1; i>1; i--) { l = gprecision(gel(x,i)); if (l && l0; i--) { l = gprecision(gel(x,i)); if (l && l=imin; i--) { t = padicprec_relative(gel(x,i)); if (t=imin; i--) { t = padicprec(gel(x,i),p); if (t=imin; i--) { t = serprec(gel(x,i),v); if (t= 0, * wrt to main variable if v < 0. */ long poldegree(GEN x, long v) { const long DEGREE0 = -LONG_MAX; long tx = typ(x), lx,w,i,d; if (is_scalar_t(tx)) return gequal0(x)? DEGREE0: 0; switch(tx) { case t_POL: if (!signe(x)) return DEGREE0; w = varn(x); if (v < 0 || v == w) return degpol(x); if (varncmp(v, w) < 0) return 0; lx = lg(x); d = DEGREE0; for (i=2; i d) d = e; } return d; case t_RFRAC: { GEN a = gel(x,1), b = gel(x,2); if (gequal0(a)) return DEGREE0; if (v < 0) { v = varn(b); d = -degpol(b); if (typ(a) == t_POL && varn(a) == v) d += degpol(a); return d; } return poldegree(a,v) - poldegree(b,v); } } pari_err_TYPE("degree",x); return 0; /* LCOV_EXCL_LINE */ } GEN gppoldegree(GEN x, long v) { long d = poldegree(x,v); return d == -LONG_MAX? mkmoo(): stoi(d); } /* assume v >= 0 and x is a POLYNOMIAL in v, return deg_v(x) */ long RgX_degree(GEN x, long v) { long tx = typ(x), lx, w, i, d; if (is_scalar_t(tx)) return gequal0(x)? -1: 0; switch(tx) { case t_POL: if (!signe(x)) return -1; w = varn(x); if (v == w) return degpol(x); if (varncmp(v, w) < 0) return 0; lx = lg(x); d = -1; for (i=2; i d) d = e; } return d; case t_RFRAC: w = varn(gel(x,2)); if (varncmp(v, w) < 0) return 0; if (RgX_degree(gel(x,2),v)) pari_err_TYPE("RgX_degree", x); return RgX_degree(gel(x,1),v); } pari_err_TYPE("RgX_degree",x); return 0; /* LCOV_EXCL_LINE */ } long degree(GEN x) { return poldegree(x,-1); } /* If v<0, leading coeff with respect to the main variable, otherwise wrt v. */ GEN pollead(GEN x, long v) { long tx = typ(x), w; pari_sp av; if (is_scalar_t(tx)) return gcopy(x); w = varn(x); switch(tx) { case t_POL: if (v < 0 || v == w) { long l = lg(x); return (l==2)? gen_0: gcopy(gel(x,l-1)); } break; case t_SER: if (v < 0 || v == w) return signe(x)? gcopy(gel(x,2)): gen_0; if (varncmp(v, w) > 0) x = polcoef_i(x, valp(x), v); break; default: pari_err_TYPE("pollead",x); return NULL; /* LCOV_EXCL_LINE */ } if (varncmp(v, w) < 0) return gcopy(x); av = avma; w = fetch_var_higher(); x = gsubst(x, v, pol_x(w)); x = pollead(x, w); delete_var(); return gerepileupto(av, x); } /* returns 1 if there's a real component in the structure, 0 otherwise */ int isinexactreal(GEN x) { long i; switch(typ(x)) { case t_REAL: return 1; case t_COMPLEX: return (typ(gel(x,1))==t_REAL || typ(gel(x,2))==t_REAL); case t_INT: case t_INTMOD: case t_FRAC: case t_FFELT: case t_PADIC: case t_QUAD: case t_QFR: case t_QFI: return 0; case t_RFRAC: case t_POLMOD: return isinexactreal(gel(x,1)) || isinexactreal(gel(x,2)); case t_POL: case t_SER: for (i=lg(x)-1; i>1; i--) if (isinexactreal(gel(x,i))) return 1; return 0; case t_VEC: case t_COL: case t_MAT: for (i=lg(x)-1; i>0; i--) if (isinexactreal(gel(x,i))) return 1; return 0; default: return 0; } } /* Check if x is approximately real with precision e */ int isrealappr(GEN x, long e) { long i; switch(typ(x)) { case t_INT: case t_REAL: case t_FRAC: return 1; case t_COMPLEX: return (gexpo(gel(x,2)) < e); case t_POL: case t_SER: for (i=lg(x)-1; i>1; i--) if (! isrealappr(gel(x,i),e)) return 0; return 1; case t_RFRAC: case t_POLMOD: return isrealappr(gel(x,1),e) && isrealappr(gel(x,2),e); case t_VEC: case t_COL: case t_MAT: for (i=lg(x)-1; i>0; i--) if (! isrealappr(gel(x,i),e)) return 0; return 1; default: pari_err_TYPE("isrealappr",x); return 0; } } /* returns 1 if there's an inexact component in the structure, and * 0 otherwise. */ int isinexact(GEN x) { long lx, i; switch(typ(x)) { case t_REAL: case t_PADIC: case t_SER: return 1; case t_INT: case t_INTMOD: case t_FFELT: case t_FRAC: case t_QFR: case t_QFI: return 0; case t_COMPLEX: case t_QUAD: case t_RFRAC: case t_POLMOD: return isinexact(gel(x,1)) || isinexact(gel(x,2)); case t_POL: for (i=lg(x)-1; i>1; i--) if (isinexact(gel(x,i))) return 1; return 0; case t_VEC: case t_COL: case t_MAT: for (i=lg(x)-1; i>0; i--) if (isinexact(gel(x,i))) return 1; return 0; case t_LIST: x = list_data(x); lx = x? lg(x): 1; for (i=1; i 0; } pari_err_TYPE("iscomplex",x); return 0; /* LCOV_EXCL_LINE */ } /*******************************************************************/ /* */ /* GENERIC REMAINDER */ /* */ /*******************************************************************/ /* euclidean quotient for scalars of admissible types */ static GEN _quot(GEN x, GEN y) { GEN q = gdiv(x,y), f = gfloor(q); if (gsigne(y) < 0 && !gequal(f,q)) f = gaddgs(f, 1); return f; } /* y t_REAL, x \ y */ static GEN _quotsr(long x, GEN y) { GEN q, f; if (!x) return gen_0; q = divsr(x,y); f = floorr(q); if (signe(y) < 0 && signe(subir(f,q))) f = addiu(f, 1); return f; } /* x t_REAL, x \ y */ static GEN _quotrs(GEN x, long y) { GEN q = divrs(x,y), f = floorr(q); if (y < 0 && signe(subir(f,q))) f = addiu(f, 1); return f; } static GEN _quotri(GEN x, GEN y) { GEN q = divri(x,y), f = floorr(q); if (signe(y) < 0 && signe(subir(f,q))) f = addiu(f, 1); return f; } /* y t_FRAC, x \ y */ static GEN _quotsf(long x, GEN y) { return truedivii(mulis(gel(y,2),x), gel(y,1)); } /* x t_FRAC, x \ y */ static GEN _quotfs(GEN x, long y) { return truedivii(gel(x,1),mulis(gel(x,2),y)); } /* x t_FRAC, y t_INT, x \ y */ static GEN _quotfi(GEN x, GEN y) { return truedivii(gel(x,1),mulii(gel(x,2),y)); } static GEN quot(GEN x, GEN y) { pari_sp av = avma; return gerepileupto(av, _quot(x, y)); } static GEN quotrs(GEN x, long y) { pari_sp av = avma; return gerepileuptoleaf(av, _quotrs(x,y)); } static GEN quotfs(GEN x, long s) { pari_sp av = avma; return gerepileuptoleaf(av, _quotfs(x,s)); } static GEN quotsr(long x, GEN y) { pari_sp av = avma; return gerepileuptoleaf(av, _quotsr(x, y)); } static GEN quotsf(long x, GEN y) { pari_sp av = avma; return gerepileuptoleaf(av, _quotsf(x, y)); } static GEN quotfi(GEN x, GEN y) { pari_sp av = avma; return gerepileuptoleaf(av, _quotfi(x, y)); } static GEN quotri(GEN x, GEN y) { pari_sp av = avma; return gerepileuptoleaf(av, _quotri(x, y)); } static GEN modrs(GEN x, long y) { pari_sp av = avma; GEN q = _quotrs(x,y); if (!signe(q)) { avma = av; return rcopy(x); } return gerepileuptoleaf(av, subri(x, mulis(q,y))); } static GEN modsr(long x, GEN y) { pari_sp av = avma; GEN q = _quotsr(x,y); if (!signe(q)) { avma = av; return stoi(x); } return gerepileuptoleaf(av, subsr(x, mulir(q,y))); } static GEN modsf(long x, GEN y) { pari_sp av = avma; return gerepileupto(av, Qdivii(modii(mulis(gel(y,2),x), gel(y,1)), gel(y,2))); } /* assume y a t_REAL, x a t_INT, t_FRAC or t_REAL. * Return x mod y or NULL if accuracy error */ GEN modRr_safe(GEN x, GEN y) { GEN q, f; long e; if (isintzero(x)) return gen_0; q = gdiv(x,y); /* t_REAL */ e = expo(q); if (e >= 0 && nbits2prec(e+1) > realprec(q)) return NULL; f = floorr(q); if (signe(y) < 0 && signe(subri(q,f))) f = addiu(f, 1); return signe(f)? gsub(x, mulir(f,y)): x; } GEN gmod(GEN x, GEN y) { pari_sp av; long i, lx, ty, tx; GEN z; tx = typ(x); if (tx == t_INT && !is_bigint(x)) return gmodsg(itos(x),y); ty = typ(y); if (ty == t_INT && !is_bigint(y)) return gmodgs(x,itos(y)); if (is_matvec_t(tx)) { z = cgetg_copy(x, &lx); for (i=1; i 0) return gmul(x, gmodulsg(1,y)); if (vx == vy && tx == t_POLMOD) return grem(x,y); retmkpolmod(grem(x,y), RgX_copy(y)); } pari_err_TYPE2("%",x,y); return NULL; /* LCOV_EXCL_LINE */ } /*******************************************************************/ /* */ /* GENERIC EUCLIDEAN DIVISION */ /* */ /*******************************************************************/ GEN gdivent(GEN x, GEN y) { long tx, ty; tx = typ(x); if (tx == t_INT && !is_bigint(x)) return gdiventsg(itos(x),y); ty = typ(y); if (ty == t_INT && !is_bigint(y)) return gdiventgs(x,itos(y)); if (is_matvec_t(tx)) { long i, lx; GEN z = cgetg_copy(x, &lx); for (i=1; i= 0) /* If 2*|r| >= |y| */ { long sz = signe(x)*signe(y); if (fl || sz > 0) q = gerepileuptoint(av, addis(q,sz)); } return q; } /* If x and y are not both scalars, same as gdivent. * Otherwise, compute the quotient x/y, rounded to the nearest integer * (towards +oo in case of tie). */ GEN gdivround(GEN x, GEN y) { pari_sp av; long tx=typ(x),ty=typ(y); GEN q,r; if (tx==t_INT && ty==t_INT) return diviiround(x,y); av = avma; if (is_real_t(tx) && is_real_t(ty)) { /* same as diviiround but less efficient */ pari_sp av1; int fl; q = quotrem(x,y,&r); av1 = avma; fl = gcmp(gmul2n(R_abs_shallow(r),1), R_abs_shallow(y)); avma = av1; cgiv(r); if (fl >= 0) /* If 2*|r| >= |y| */ { long sz = gsigne(y); if (fl || sz > 0) q = gerepileupto(av, gaddgs(q, sz)); } return q; } if (is_matvec_t(tx)) { long i, lx; GEN z = cgetg_copy(x, &lx); for (i=1; i t_POL, ignoring valp. INTERNAL ! */ GEN ser2pol_i(GEN x, long lx) { long i = lx-1; GEN y; while (i > 1 && isexactzero(gel(x,i))) i--; y = cgetg(i+1, t_POL); y[1] = x[1] & ~VALPBITS; for ( ; i > 1; i--) gel(y,i) = gel(x,i); return y; } GEN ser_inv(GEN b) { pari_sp av = avma; long l = lg(b), e = valp(b), prec = l-2; GEN y = RgXn_inv_i(ser2pol_i(b, l), prec); GEN x = RgX_to_ser(y, l); setvalp(x, -e); return gerepilecopy(av, x); } /* T t_POL in var v, mod out by T components of x which are * t_POL/t_RFRAC in v. Recursively */ static GEN mod_r(GEN x, long v, GEN T) { long i, w, lx, tx = typ(x); GEN y; if (is_const_t(tx)) return x; switch(tx) { case t_POLMOD: w = varn(gel(x,1)); if (w == v) pari_err_PRIORITY("subst", gel(x,1), "=", v); if (varncmp(v, w) < 0) return x; return gmodulo(mod_r(gel(x,2),v,T), mod_r(gel(x,1),v,T)); case t_SER: w = varn(x); if (w == v) break; /* fail */ if (varncmp(v, w) < 0 || ser_isexactzero(x)) return x; y = cgetg_copy(x, &lx); y[1] = x[1]; for (i = 2; i < lx; i++) gel(y,i) = mod_r(gel(x,i),v,T); return normalize(y); case t_POL: w = varn(x); if (w == v) return RgX_rem(x, T); if (varncmp(v, w) < 0) return x; y = cgetg_copy(x, &lx); y[1] = x[1]; for (i = 2; i < lx; i++) gel(y,i) = mod_r(gel(x,i),v,T); return normalizepol_lg(y, lx); case t_RFRAC: return gdiv(mod_r(gel(x,1),v,T), mod_r(gel(x,2),v,T)); case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); for (i = 1; i < lx; i++) gel(y,i) = mod_r(gel(x,i),v,T); return y; case t_LIST: y = mklist(); list_data(y) = list_data(x)? mod_r(list_data(x),v,T): NULL; return y; } pari_err_TYPE("substpol",x); return NULL;/*LCOV_EXCL_LINE*/ } GEN gsubstpol(GEN x, GEN T, GEN y) { pari_sp av = avma; long v; GEN z; if (typ(T) == t_POL && RgX_is_monomial(T) && gequal1(leading_coeff(T))) { /* T = t^d */ long d = degpol(T); v = varn(T); z = (d==1)? x: gdeflate(x, v, d); if (z) return gerepileupto(av, gsubst(z, v, y)); } v = fetch_var(); T = simplify_shallow(T); if (typ(T) == t_RFRAC) z = gsub(gel(T,1), gmul(pol_x(v), gel(T,2))); else z = gsub(T, pol_x(v)); z = mod_r(x, gvar(T), z); z = gsubst(z, v, y); (void)delete_var(); return gerepileupto(av, z); } long RgX_deflate_order(GEN x) { ulong d = 0, i, lx = (ulong)lg(x); for (i=3; i 0) return gcopy(x); av = avma; V = valp(x); lx = lg(x); if (lx == 2) return zeroser(v, V / d); y = ser2pol_i(x, lx); dy = degpol(y); if (V % d != 0 || (dy > 0 && RgX_deflate_order(y) % d != 0)) { const char *s = stack_sprintf("valuation(x) %% %ld", d); pari_err_DOMAIN("gdeflate", s, "!=", gen_0,x); } if (dy > 0) y = RgX_deflate(y, d); y = RgX_to_ser(y, 3 + (lx-3)/d); setvalp(y, V/d); return gerepilecopy(av, y); } static GEN poldeflate(GEN x, long v, long d) { long vx = varn(x); pari_sp av; if (varncmp(vx, v) < 0) return vdeflate(x,v,d); if (varncmp(vx, v) > 0 || degpol(x) <= 0) return gcopy(x); av = avma; /* x non-constant */ if (RgX_deflate_order(x) % d != 0) return NULL; return gerepilecopy(av, RgX_deflate(x,d)); } static GEN listdeflate(GEN x, long v, long d) { GEN y = NULL, z = mklist(); if (list_data(x)) { y = vdeflate(list_data(x),v,d); if (!y) return NULL; } list_data(z) = y; return z; } /* return NULL if substitution fails */ GEN gdeflate(GEN x, long v, long d) { if (d <= 0) pari_err_DOMAIN("gdeflate", "degree", "<=", gen_0,stoi(d)); switch(typ(x)) { case t_INT: case t_REAL: case t_INTMOD: case t_FRAC: case t_FFELT: case t_COMPLEX: case t_PADIC: case t_QUAD: return gcopy(x); case t_POL: return poldeflate(x,v,d); case t_SER: return serdeflate(x,v,d); case t_POLMOD: if (varncmp(varn(gel(x,1)), v) >= 0) return gcopy(x); /* fall through */ case t_RFRAC: case t_VEC: case t_COL: case t_MAT: return vdeflate(x,v,d); case t_LIST: return listdeflate(x,v,d); } pari_err_TYPE("gdeflate",x); return NULL; /* LCOV_EXCL_LINE */ } /* set *m to the largest d such that x0 = A(X^d); return A */ GEN RgX_deflate_max(GEN x, long *m) { *m = RgX_deflate_order(x); return RgX_deflate(x, *m); } GEN ZX_deflate_max(GEN x, long *m) { *m = ZX_deflate_order(x); return RgX_deflate(x, *m); } static int serequalXk(GEN x) { long i, l = lg(x); if (l == 2 || !isint1(gel(x,2))) return 0; for (i = 3; i < l; i++) if (!isintzero(gel(x,i))) return 0; return 1; } GEN gsubst(GEN x, long v, GEN y) { long tx = typ(x), ty = typ(y), lx = lg(x), ly = lg(y); long l, vx, vy, ex, ey, i, j, k, jb; pari_sp av, av2; GEN X, t, p1, p2, z; switch(ty) { case t_MAT: if (ly==1) return cgetg(1,t_MAT); if (ly == lgcols(y)) break; /* fall through */ case t_QFR: case t_QFI: case t_VEC: case t_COL: pari_err_TYPE2("substitution",x,y); break; /* LCOV_EXCL_LINE */ } if (is_scalar_t(tx)) { GEN modp1; if (tx != t_POLMOD || varncmp(v, varn(gel(x,1))) <= 0) return ty==t_MAT? scalarmat(x,ly-1): gcopy(x); av = avma; p1 = gsubst(gel(x,1),v,y); if (typ(p1) != t_POL) pari_err_TYPE2("substitution",x,y); p2 = gsubst(gel(x,2),v,y); vx = varn(p1); if (typ(p2) != t_POL || varncmp(varn(p2), vx) >= 0) return gerepileupto(av, gmodulo(p2, p1)); modp1 = mkpolmod(gen_1,p1); lx = lg(p2); z = cgetg(lx,t_POL); z[1] = p2[1]; for (i=2; i= 0) c = gmodulo(c,p1); else c = gmul(c, modp1); gel(z,i) = c; } return gerepileupto(av, normalizepol_lg(z,lx)); } switch(tx) { case t_POL: vx = varn(x); if (lx==2) { GEN z; if (vx != v) return gcopy(x); z = Rg_get_0(y); return ty == t_MAT? scalarmat(z,ly-1): z; } if (varncmp(vx, v) > 0) return ty == t_MAT? scalarmat(x,ly-1): RgX_copy(x); if (varncmp(vx, v) < 0) { av = avma; z = cgetg(lx, t_POL); z[1] = x[1]; for (i=2; i 0) return (ty==t_MAT)? scalarmat(x,ly-1): gcopy(x); ex = valp(x); if (varncmp(vx, v) < 0) { if (lx == 2) return (ty==t_MAT)? scalarmat(x,ly-1): gcopy(x); av = avma; X = pol_x(vx); av2 = avma; z = gadd(gsubst(gel(x,lx-1),v,y), zeroser(vx,1)); for (i = lx-2; i>=2; i--) { z = gadd(gmul(z,X), gsubst(gel(x,i),v,y)); if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gsubst (i = %ld)", i); z = gerepileupto(av2, z); } } if (ex) z = gmul(z, pol_xnall(ex,vx)); return gerepileupto(av, z); } switch(ty) /* here vx == v */ { case t_SER: vy = varn(y); ey = valp(y); if (ey < 1 || lx == 2) return zeroser(vy, ey*(ex+lx-2)); if (ey == 1 && serequalXk(y) && (varncmp(vx,vy) >= 0 || varncmp(gvar2(x), vy) >= 0)) { /* y = t + O(t^N) */ if (lx > ly) { /* correct number of significant terms */ l = ly; if (!ex) for (i = 3; i < lx; i++) if (++l >= lx || !gequal0(gel(x,i))) break; lx = l; } z = cgetg(lx, t_SER); z[1] = x[1]; for (i = 2; i < lx; i++) gel(z,i) = gcopy(gel(x,i)); if (vx != vy) setvarn(z,vy); return z; } if (vy != vx) { av = avma; z = gel(x,lx-1); for (i=lx-2; i>=2; i--) { z = gadd(gmul(y,z), gel(x,i)); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"gsubst (i = %ld)", i); z = gerepileupto(av, z); } } if (ex) z = gmul(z, gpowgs(y,ex)); return gerepileupto(av,z); } l = (lx-2)*ey+2; if (ex) { if (l>ly) l = ly; } else if (lx != 3) { long l2; for (i = 3; i < lx; i++) if (!isexactzero(gel(x,i))) break; l2 = (i-2)*ey + (gequal0(y)? 2 : ly); if (l > l2) l = l2; } av = avma; t = leafcopy(y); if (l < ly) setlg(t, l); z = scalarser(gel(x,2),varn(y),l-2); for (i=3,jb=ey; jb<=l-2; i++,jb+=ey) { if (i < lx) { for (j=jb+2; j1; j--) { p1 = gen_0; for (k=2; k1) pari_warn(warnmem,"gsubst"); gerepileall(av,2, &z,&t); } } if (!ex) return gerepilecopy(av,z); return gerepileupto(av, gmul(z,gpowgs(y, ex))); case t_POL: case t_RFRAC: { long N, n = lx-2; GEN cx; vy = gvar(y); ey = gval(y,vy); if (ey == LONG_MAX) { /* y = 0 */ if (ex < 0) pari_err_INV("gsubst",y); if (!n) return gcopy(x); if (ex > 0) return Rg_get_0(ty == t_RFRAC? gel(y,2): y); y = Rg_get_1(ty == t_RFRAC? gel(y,2): y); return gmul(y, gel(x,2)); } if (ey < 1 || n == 0) return zeroser(vy, ey*(ex+n)); av = avma; n *= ey; N = ex? n: maxss(n-ey,1); y = (ty == t_RFRAC)? rfrac_to_ser(y, N+2): RgX_to_ser(y, N+2); if (lg(y)-2 > n) setlg(y, n+2); x = ser2pol_i(x, lx); x = primitive_part(x, &cx); if (varncmp(vy,vx) > 0) z = gadd(poleval(x, y), zeroser(vy,n)); else { z = RgXn_eval(x, ser2rfrac_i(y), n); if (varn(z) == vy) z = RgX_to_ser(z, n+2); } switch(typ(z)) { case t_SER: case t_POL: if (varncmp(varn(z),vy) <= 0) break; default: z = scalarser(z, vy, n); } if (cx) z = gmul(z, cx); if (!ex && !cx) return gerepilecopy(av, z); if (ex) z = gmul(z, gpowgs(y,ex)); return gerepileupto(av, z); } default: if (isexactzero(y)) { if (ex < 0) pari_err_INV("gsubst",y); if (ex > 0) return gcopy(y); if (lx > 2) return gadd(gel(x,2), y); /*add maps to correct ring*/ } pari_err_TYPE2("substitution",x,y); } break; case t_RFRAC: av=avma; p1=gsubst(gel(x,1),v,y); p2=gsubst(gel(x,2),v,y); return gerepileupto(av, gdiv(p1,p2)); case t_VEC: case t_COL: case t_MAT: z = cgetg_copy(x, &lx); for (i=1; i=2; i--) y = gadd(gmul(y,pol_x(vx)),diffop(gel(x,i),v,dv)); if (idx) y = gadd(y, gmul(gel(dv,idx),RgX_deriv(x))); return gerepileupto(av, y); case t_SER: if (signe(x)==0) return gen_0; vx = varn(x); idx = lookup(v,vx); if (!idx) return gen_0; av = avma; if (ser_isexactzero(x)) y = x; else { y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i 0) y = gerepileuptoint(av, addui(1,y)); return y; case t_RFRAC: return gdeuc(gel(x,1),gel(x,2)); case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); for (i=1; i0? gen_1: absrnz_equal2n(x)? gen_0: gen_m1; av = avma; x = round_i(x, &ex); if (ex >= 0) pari_err_PREC( "roundr (precision loss in truncation)"); return gerepileuptoint(av, x); } GEN roundr_safe(GEN x) { long ex, s = signe(x); pari_sp av; if (!s || (ex = expo(x)) < -1) return gen_0; if (ex == -1) return s>0? gen_1: absrnz_equal2n(x)? gen_0: gen_m1; av = avma; x = round_i(x, &ex); return gerepileuptoint(av, x); } GEN ground(GEN x) { GEN y; long i, lx; pari_sp av; switch(typ(x)) { case t_INT: return icopy(x); case t_INTMOD: case t_QUAD: return gcopy(x); case t_REAL: return roundr(x); case t_FRAC: return diviiround(gel(x,1), gel(x,2)); case t_POLMOD: retmkpolmod(ground(gel(x,2)), RgX_copy(gel(x,1))); case t_COMPLEX: av = avma; y = cgetg(3, t_COMPLEX); gel(y,2) = ground(gel(x,2)); if (!signe(gel(y,2))) { avma = av; return ground(gel(x,1)); } gel(y,1) = ground(gel(x,1)); return y; case t_POL: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i *e) *e = e1; return y; case t_POLMOD: retmkpolmod(grndtoi(gel(x,2), e), RgX_copy(gel(x,1))); case t_POL: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i *e) *e = e1; } return normalizepol_lg(y, lx); case t_SER: if (ser_isexactzero(x)) return gcopy(x); y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i *e) *e = e1; } return normalize(y); case t_RFRAC: y = cgetg(3,t_RFRAC); gel(y,1) = grndtoi(gel(x,1),&e1); if (e1 > *e) *e = e1; gel(y,2) = grndtoi(gel(x,2),&e1); if (e1 > *e) *e = e1; return y; case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); for (i=1; i *e) *e = e1; } return y; } pari_err_TYPE("grndtoi",x); return NULL; /* LCOV_EXCL_LINE */ } /* trunc(x * 2^s). lindep() sanity checks rely on this function to return a * t_INT or fail when fed a non-t_COMPLEX input; so do not make this one * recursive [ or change the lindep call ] */ GEN gtrunc2n(GEN x, long s) { GEN z; switch(typ(x)) { case t_INT: return shifti(x, s); case t_REAL: return trunc2nr(x, s); case t_FRAC: { pari_sp av; GEN a = gel(x,1), b = gel(x,2), q; if (s == 0) return divii(a, b); av = avma; if (s < 0) q = divii(shifti(a, s), b); else { GEN r; q = dvmdii(a, b, &r); q = addii(shifti(q,s), divii(shifti(r,s), b)); } return gerepileuptoint(av, q); } case t_COMPLEX: z = cgetg(3, t_COMPLEX); gel(z,2) = gtrunc2n(gel(x,2), s); if (!signe(gel(z,2))) { avma = (pari_sp)(z + 3); return gtrunc2n(gel(x,1), s); } gel(z,1) = gtrunc2n(gel(x,1), s); return z; default: pari_err_TYPE("gtrunc2n",x); return NULL; /* LCOV_EXCL_LINE */ } } /* e = number of error bits on integral part */ GEN gcvtoi(GEN x, long *e) { long tx = typ(x), lx, e1; GEN y; if (tx == t_REAL) { long ex = expo(x); if (ex < 0) { *e = ex; return gen_0; } e1 = ex - bit_prec(x) + 1; y = mantissa2nr(x, e1); if (e1 <= 0) { pari_sp av = avma; e1 = expo(subri(x,y)); avma = av; } *e = e1; return y; } *e = -(long)HIGHEXPOBIT; if (is_matvec_t(tx)) { long i; y = cgetg_copy(x, &lx); for (i=1; i *e) *e = e1; } return y; } return gtrunc(x); } int isint(GEN n, GEN *ptk) { switch(typ(n)) { case t_INT: *ptk = n; return 1; case t_REAL: { pari_sp av0 = avma; GEN z = floorr(n); pari_sp av = avma; long s = signe(subri(n, z)); if (s) { avma = av0; return 0; } *ptk = z; avma = av; return 1; } case t_FRAC: return 0; case t_COMPLEX: return gequal0(gel(n,2)) && isint(gel(n,1),ptk); case t_QUAD: return gequal0(gel(n,3)) && isint(gel(n,2),ptk); default: pari_err_TYPE("isint",n); return 0; /* LCOV_EXCL_LINE */ } } int issmall(GEN n, long *ptk) { pari_sp av = avma; GEN z; long k; if (!isint(n, &z)) return 0; k = itos_or_0(z); avma = av; if (k || lgefint(z) == 2) { *ptk = k; return 1; } return 0; } /* smallest integer greater than any incarnations of the real x * Avoid "precision loss in truncation" */ GEN ceil_safe(GEN x) { pari_sp av = avma; long e, tx = typ(x); GEN y; if (is_rational_t(tx)) return gceil(x); y = gcvtoi(x,&e); if (gsigne(x) >= 0) { if (e < 0) e = 0; y = addii(y, int2n(e)); } return gerepileuptoint(av, y); } /* largest integer smaller than any incarnations of the real x * Avoid "precision loss in truncation" */ GEN floor_safe(GEN x) { pari_sp av = avma; long e, tx = typ(x); GEN y; if (is_rational_t(tx)) return gfloor(x); y = gcvtoi(x,&e); if (gsigne(x) <= 0) { if (e < 0) e = 0; y = subii(y, int2n(e)); } return gerepileuptoint(av, y); } GEN ser2rfrac_i(GEN x) { long e = valp(x); GEN a = ser2pol_i(x, lg(x)); if (e) { if (e > 0) a = RgX_shift_shallow(a, e); else a = gred_rfrac_simple(a, pol_xn(-e, varn(a))); } return a; } static GEN ser2rfrac(GEN x) { pari_sp av = avma; return gerepilecopy(av, ser2rfrac_i(x)); } /* x t_PADIC, truncate to rational (t_INT/t_FRAC) */ GEN padic_to_Q(GEN x) { GEN u = gel(x,4), p; long v; if (!signe(u)) return gen_0; v = valp(x); if (!v) return icopy(u); p = gel(x,2); if (v>0) { pari_sp av = avma; return gerepileuptoint(av, mulii(u, powiu(p,v))); } retmkfrac(icopy(u), powiu(p,-v)); } GEN padic_to_Q_shallow(GEN x) { GEN u = gel(x,4), p, q, q2; long v; if (!signe(u)) return gen_0; q = gel(x,3); q2 = shifti(q,-1); v = valp(x); u = Fp_center_i(u, q, q2); if (!v) return u; p = gel(x,2); if (v>0) return mulii(powiu(p,v), u); return mkfrac(u, powiu(p,-v)); } GEN QpV_to_QV(GEN v) { long i, l; GEN w = cgetg_copy(v, &l); for (i = 1; i < l; i++) { GEN c = gel(v,i); switch(typ(c)) { case t_INT: case t_FRAC: break; case t_PADIC: c = padic_to_Q_shallow(c); break; default: pari_err_TYPE("padic_to_Q", v); } gel(w,i) = c; } return w; } GEN gtrunc(GEN x) { switch(typ(x)) { case t_INT: return icopy(x); case t_REAL: return truncr(x); case t_FRAC: return divii(gel(x,1),gel(x,2)); case t_PADIC: return padic_to_Q(x); case t_POL: return RgX_copy(x); case t_RFRAC: return gdeuc(gel(x,1),gel(x,2)); case t_SER: return ser2rfrac(x); case t_VEC: case t_COL: case t_MAT: { long i, lx; GEN y = cgetg_copy(x, &lx); for (i=1; i INT, POL & SER */ /* */ /*******************************************************************/ /* return a_(n-1) B^(n-1) + ... + a_0, where B = 2^32. * The a_i are 32bits integers */ GEN mkintn(long n, ...) { va_list ap; GEN x, y; long i; #ifdef LONG_IS_64BIT long e = (n&1); n = (n+1) >> 1; #endif va_start(ap,n); x = cgetipos(n+2); y = int_MSW(x); for (i=0; i = 0; i--) gel(y,i) = va_arg(ap, GEN); va_end(ap); return normalizepol_lg(x, l); } /* return [a_1, ..., a_n] */ GEN mkvecn(long n, ...) { va_list ap; GEN x; long i; va_start(ap,n); x = cgetg(n+1, t_VEC); for (i=1; i <= n; i++) gel(x,i) = va_arg(ap, GEN); va_end(ap); return x; } GEN mkcoln(long n, ...) { va_list ap; GEN x; long i; va_start(ap,n); x = cgetg(n+1, t_COL); for (i=1; i <= n; i++) gel(x,i) = va_arg(ap, GEN); va_end(ap); return x; } GEN mkvecsmalln(long n, ...) { va_list ap; GEN x; long i; va_start(ap,n); x = cgetg(n+1, t_VECSMALL); for (i=1; i <= n; i++) x[i] = va_arg(ap, long); va_end(ap); return x; } GEN scalarpol(GEN x, long v) { GEN y; if (isrationalzero(x)) return zeropol(v); y = cgetg(3,t_POL); y[1] = gequal0(x)? evalvarn(v) : evalvarn(v) | evalsigne(1); gel(y,2) = gcopy(x); return y; } GEN scalarpol_shallow(GEN x, long v) { GEN y; if (isrationalzero(x)) return zeropol(v); y = cgetg(3,t_POL); y[1] = gequal0(x)? evalvarn(v) : evalvarn(v) | evalsigne(1); gel(y,2) = x; return y; } /* x0 + x1*T, do not assume x1 != 0 */ GEN deg1pol(GEN x1, GEN x0,long v) { GEN x = cgetg(4,t_POL); x[1] = evalsigne(1) | evalvarn(v); gel(x,2) = x0 == gen_0? x0: gcopy(x0); /* gen_0 frequent */ gel(x,3) = gcopy(x1); return normalizepol_lg(x,4); } /* same, no copy */ GEN deg1pol_shallow(GEN x1, GEN x0,long v) { GEN x = cgetg(4,t_POL); x[1] = evalsigne(1) | evalvarn(v); gel(x,2) = x0; gel(x,3) = x1; return normalizepol_lg(x,4); } GEN deg2pol_shallow(GEN x2, GEN x1, GEN x0, long v) { GEN x = cgetg(5,t_POL); x[1] = evalsigne(1) | evalvarn(v); gel(x,2) = x0; gel(x,3) = x1; gel(x,4) = x2; return normalizepol_lg(x,5); } static GEN _gtopoly(GEN x, long v, int reverse) { long tx = typ(x); GEN y; if (v<0) v = 0; switch(tx) { case t_POL: if (varncmp(varn(x), v) < 0) pari_err_PRIORITY("gtopoly", x, "<", v); y = RgX_copy(x); break; case t_SER: if (varncmp(varn(x), v) < 0) pari_err_PRIORITY("gtopoly", x, "<", v); y = ser2rfrac(x); if (typ(y) != t_POL) pari_err_DOMAIN("gtopoly", "valuation", "<", gen_0, x); break; case t_RFRAC: { GEN a = gel(x,1), b = gel(x,2); long vb = varn(b); if (varncmp(vb, v) < 0) pari_err_PRIORITY("gtopoly", x, "<", v); if (typ(a) != t_POL || varn(a) != vb) return zeropol(v); y = RgX_div(a,b); break; } case t_VECSMALL: x = zv_to_ZV(x); /* fall through */ case t_QFR: case t_QFI: case t_VEC: case t_COL: case t_MAT: { long j, k, lx = lg(x); GEN z; if (tx == t_QFR) lx--; if (varncmp(gvar(x), v) <= 0) pari_err_PRIORITY("gtopoly", x, "<=", v); y = cgetg(lx+1, t_POL); y[1] = evalvarn(v); if (reverse) { x--; for (j=2; j<=lx; j++) gel(y,j) = gel(x,j); } else { for (j=2, k=lx; k>=2; j++) gel(y,j) = gel(x,--k); } z = RgX_copy(normalizepol_lg(y,lx+1)); settyp(y, t_VECSMALL);/* left on stack */ return z; } default: if (is_scalar_t(tx)) return scalarpol(x,v); pari_err_TYPE("gtopoly",x); return NULL; /* LCOV_EXCL_LINE */ } setvarn(y,v); return y; } GEN gtopolyrev(GEN x, long v) { return _gtopoly(x,v,1); } GEN gtopoly(GEN x, long v) { return _gtopoly(x,v,0); } static GEN gtovecpost(GEN x, long n) { long i, imax, lx, tx = typ(x); GEN y = zerovec(n); if (is_scalar_t(tx) || tx == t_RFRAC) { gel(y,1) = gcopy(x); return y; } switch(tx) { case t_POL: lx=lg(x); imax = minss(lx-2, n); for (i=1; i<=imax; i++) gel(y,i) = gcopy(gel(x,lx-i)); return y; case t_SER: lx=lg(x); imax = minss(lx-2, n); x++; for (i=1; i<=imax; i++) gel(y,i) = gcopy(gel(x,i)); return y; case t_QFR: case t_QFI: case t_VEC: case t_COL: lx=lg(x); imax = minss(lx-1, n); for (i=1; i<=imax; i++) gel(y,i) = gcopy(gel(x,i)); return y; case t_LIST: if (list_typ(x) == t_LIST_MAP) pari_err_TYPE("gtovec",x); x = list_data(x); lx = x? lg(x): 1; imax = minss(lx-1, n); for (i=1; i<=imax; i++) gel(y,i) = gcopy(gel(x,i)); return y; case t_VECSMALL: lx=lg(x); imax = minss(lx-1, n); for (i=1; i<=imax; i++) gel(y,i) = stoi(x[i]); return y; default: pari_err_TYPE("gtovec",x); return NULL; /*LCOV_EXCL_LINE*/ } } static GEN init_vectopre(long a, long n, GEN y, long *imax) { *imax = minss(a, n); return (n == *imax)? y: y + n - a; } static GEN gtovecpre(GEN x, long n) { long i, imax, lx, tx = typ(x); GEN y = zerovec(n), y0; if (is_scalar_t(tx) || tx == t_RFRAC) { gel(y,n) = gcopy(x); return y; } switch(tx) { case t_POL: lx=lg(x); y0 = init_vectopre(lx-2, n, y, &imax); for (i=1; i<=imax; i++) gel(y0,i) = gcopy(gel(x,lx-i)); return y; case t_SER: lx=lg(x); x++; y0 = init_vectopre(lx-2, n, y, &imax); for (i=1; i<=imax; i++) gel(y0,i) = gcopy(gel(x,i)); return y; case t_QFR: case t_QFI: case t_VEC: case t_COL: lx=lg(x); y0 = init_vectopre(lx-1, n, y, &imax); for (i=1; i<=imax; i++) gel(y0,i) = gcopy(gel(x,i)); return y; case t_LIST: if (list_typ(x) == t_LIST_MAP) pari_err_TYPE("gtovec",x); x = list_data(x); lx = x? lg(x): 1; y0 = init_vectopre(lx-1, n, y, &imax); for (i=1; i<=imax; i++) gel(y0,i) = gcopy(gel(x,i)); return y; case t_VECSMALL: lx=lg(x); y0 = init_vectopre(lx-1, n, y, &imax); for (i=1; i<=imax; i++) gel(y0,i) = stoi(x[i]); return y; default: pari_err_TYPE("gtovec",x); return NULL; /*LCOV_EXCL_LINE*/ } } GEN gtovec0(GEN x, long n) { if (!n) return gtovec(x); if (n > 0) return gtovecpost(x, n); return gtovecpre(x, -n); } GEN gtovec(GEN x) { long i, lx, tx = typ(x); GEN y; if (is_scalar_t(tx)) return mkveccopy(x); switch(tx) { case t_POL: lx=lg(x); y=cgetg(lx-1,t_VEC); for (i=1; i<=lx-2; i++) gel(y,i) = gcopy(gel(x,lx-i)); return y; case t_SER: lx=lg(x); y=cgetg(lx-1,t_VEC); x++; for (i=1; i<=lx-2; i++) gel(y,i) = gcopy(gel(x,i)); return y; case t_RFRAC: return mkveccopy(x); case t_QFR: case t_QFI: case t_VEC: case t_COL: case t_MAT: lx=lg(x); y=cgetg(lx,t_VEC); for (i=1; i>1, i; for (i = 1; i <= lim; i++) swap(gel(y,i), gel(y,ly-i)); return y; } GEN gtocolrev(GEN x) { return gtocolrev0(x, 0); } static long Itos(GEN x) { if (typ(x) != t_INT) pari_err_TYPE("vectosmall",x); return itos(x); } static GEN gtovecsmallpost(GEN x, long n) { long i, imax, lx; GEN y = zero_Flv(n); switch(typ(x)) { case t_INT: y[1] = itos(x); return y; case t_POL: lx=lg(x); imax = minss(lx-2, n); for (i=1; i<=imax; i++) y[i] = Itos(gel(x,lx-i)); return y; case t_SER: lx=lg(x); imax = minss(lx-2, n); x++; for (i=1; i<=imax; i++) y[i] = Itos(gel(x,i)); return y; case t_VEC: case t_COL: lx=lg(x); imax = minss(lx-1, n); for (i=1; i<=imax; i++) y[i] = Itos(gel(x,i)); return y; case t_LIST: x = list_data(x); lx = x? lg(x): 1; imax = minss(lx-1, n); for (i=1; i<=imax; i++) y[i] = Itos(gel(x,i)); return y; case t_VECSMALL: lx=lg(x); imax = minss(lx-1, n); for (i=1; i<=imax; i++) y[i] = x[i]; return y; default: pari_err_TYPE("gtovecsmall",x); return NULL; /*LCOV_EXCL_LINE*/ } } static GEN gtovecsmallpre(GEN x, long n) { long i, imax, lx; GEN y = zero_Flv(n), y0; switch(typ(x)) { case t_INT: y[n] = itos(x); return y; case t_POL: lx=lg(x); y0 = init_vectopre(lx-2, n, y, &imax); for (i=1; i<=imax; i++) y0[i] = Itos(gel(x,lx-i)); return y; case t_SER: lx=lg(x); x++; y0 = init_vectopre(lx-2, n, y, &imax); for (i=1; i<=imax; i++) y0[i] = Itos(gel(x,i)); return y; case t_VEC: case t_COL: lx=lg(x); y0 = init_vectopre(lx-1, n, y, &imax); for (i=1; i<=imax; i++) y0[i] = Itos(gel(x,i)); return y; case t_LIST: x = list_data(x); lx = x? lg(x): 1; y0 = init_vectopre(lx-1, n, y, &imax); for (i=1; i<=imax; i++) y0[i] = Itos(gel(x,i)); return y; case t_VECSMALL: lx=lg(x); y0 = init_vectopre(lx-1, n, y, &imax); for (i=1; i<=imax; i++) y0[i] = x[i]; return y; default: pari_err_TYPE("gtovecsmall",x); return NULL; /*LCOV_EXCL_LINE*/ } } GEN gtovecsmall0(GEN x, long n) { if (!n) return gtovecsmall(x); if (n > 0) return gtovecsmallpost(x, n); return gtovecsmallpre(x, -n); } GEN gtovecsmall(GEN x) { GEN V; long l, i; switch(typ(x)) { case t_INT: return mkvecsmall(itos(x)); case t_STR: { unsigned char *s = (unsigned char*)GSTR(x); l = strlen((const char *)s); V = cgetg(l+1, t_VECSMALL); s--; for (i=1; i<=l; i++) V[i] = (long)s[i]; return V; } case t_VECSMALL: return leafcopy(x); case t_LIST: x = list_data(x); if (!x) return cgetg(1, t_VECSMALL); /* fall through */ case t_VEC: case t_COL: l = lg(x); V = cgetg(l,t_VECSMALL); for(i=1; i= lx) pari_err_COMPONENT("", ">", utoi(lx-1), stoi(n)); return stoi(x[n]); } pari_err_TYPE("component [leaf]", x); } if (n < 1) pari_err_COMPONENT("", "<", gen_1, stoi(n)); if (tx == t_LIST) { x = list_data(x); tx = t_VEC; lx = (ulong)(x? lg(x): 1); } l = (ulong)lontyp[tx] + (ulong)n-1; /* beware overflow */ if (l >= lx) pari_err_COMPONENT("", ">", utoi(lx-lontyp[tx]), stoi(n)); return gcopy(gel(x,l)); } /* assume x a t_POL */ static GEN _polcoef(GEN x, long n, long v) { long i, w, lx = lg(x), dx = lx-3; GEN z; if (dx < 0) return gen_0; if (v < 0 || v == (w=varn(x))) return (n < 0 || n > dx)? gen_0: gel(x,n+2); if (varncmp(w,v) > 0) return n? gen_0: x; /* w < v */ z = cgetg(lx, t_POL); z[1] = x[1]; for (i = 2; i < lx; i++) gel(z,i) = polcoef_i(gel(x,i), n, v); z = normalizepol_lg(z, lx); switch(lg(z)) { case 2: z = gen_0; break; case 3: z = gel(z,2); break; } return z; } /* assume x a t_SER */ static GEN _sercoef(GEN x, long n, long v) { long i, w = varn(x), lx = lg(x), dx = lx-3, N; GEN z; if (v < 0) v = w; N = v == w? n - valp(x): n; if (dx < 0) { if (N >= 0) pari_err_DOMAIN("polcoef", "t_SER", "=", x, x); return gen_0; } if (v == w) { if (N > dx) pari_err_DOMAIN("polcoef", "degree", ">", stoi(dx+valp(x)), stoi(n)); return (N < 0)? gen_0: gel(x,N+2); } if (varncmp(w,v) > 0) return N? gen_0: x; /* w < v */ z = cgetg(lx, t_SER); z[1] = x[1]; for (i = 2; i < lx; i++) gel(z,i) = polcoef_i(gel(x,i), n, v); return normalize(z); } /* assume x a t_RFRAC(n) */ static GEN _rfraccoef(GEN x, long n, long v) { GEN P,Q, p = gel(x,1), q = gel(x,2); long vp = gvar(p), vq = gvar(q); if (v < 0) v = varncmp(vp, vq) < 0? vp: vq; P = (vp == v)? p: swap_vars(p, v); Q = (vq == v)? q: swap_vars(q, v); if (!RgX_is_monomial(Q)) pari_err_TYPE("polcoef", x); n += degpol(Q); return gdiv(_polcoef(P, n, v), leading_coeff(Q)); } GEN polcoef_i(GEN x, long n, long v) { long tx = typ(x); switch(tx) { case t_POL: return _polcoef(x,n,v); case t_SER: return _sercoef(x,n,v); case t_RFRAC: return _rfraccoef(x,n,v); } if (!is_scalar_t(tx)) pari_err_TYPE("polcoef", x); return n? gen_0: x; } /* with respect to the main variable if v<0, with respect to the variable v * otherwise. v ignored if x is not a polynomial/series. */ GEN polcoef(GEN x, long n, long v) { pari_sp av = avma; x = polcoef_i(x,n,v); if (x == gen_0) return x; return (avma == av)? gcopy(x): gerepilecopy(av, x); } static GEN vecdenom(GEN v, long imin, long imax) { long i = imin; GEN s; if (imin > imax) return gen_1; s = denom_i(gel(v,i)); for (i++; i<=imax; i++) { GEN t = denom_i(gel(v,i)); if (t != gen_1) s = glcm(s,t); } return s; } static GEN denompol(GEN x, long v); static GEN vecdenompol(GEN v, long imin, long imax, long vx) { long i = imin; GEN s; if (imin > imax) return gen_1; s = denompol(gel(v,i), vx); for (i++; i<=imax; i++) { GEN t = denompol(gel(v,i), vx); if (t != gen_1) s = glcm(s,t); } return s; } GEN denom_i(GEN x) { switch(typ(x)) { case t_INT: case t_REAL: case t_INTMOD: case t_FFELT: case t_PADIC: case t_SER: case t_VECSMALL: return gen_1; case t_FRAC: return gel(x,2); case t_COMPLEX: return vecdenom(x,1,2); case t_QUAD: return vecdenom(x,2,3); case t_POLMOD: return denom_i(gel(x,2)); case t_RFRAC: return gel(x,2); case t_POL: return pol_1(varn(x)); case t_VEC: case t_COL: case t_MAT: return vecdenom(x, 1, lg(x)-1); } pari_err_TYPE("denom",x); return NULL; /* LCOV_EXCL_LINE */ } /* v has lower (or equal) priority as x's main variable */ static GEN denompol(GEN x, long v) { long vx, tx = typ(x); if (is_scalar_t(tx)) return gen_1; switch(typ(x)) { case t_SER: if (varn(x) != v) return x; vx = valp(x); return vx < 0? pol_xn(-vx, v): pol_1(v); case t_RFRAC: x = gel(x,2); return varn(x) == v? x: pol_1(v); case t_POL: return pol_1(v); case t_VEC: case t_COL: case t_MAT: return vecdenompol(x, 1, lg(x)-1, v); } pari_err_TYPE("denom",x); return NULL; /* LCOV_EXCL_LINE */ } GEN denom(GEN x) { pari_sp av = avma; return gerepilecopy(av, denom_i(x)); } static GEN denominator_v(GEN x, long v) { long v0 = gvar(x); GEN d; if (v0 == NO_VARIABLE || varncmp(v0,v) > 0) return pol_1(v); if (v0 != v) { v0 = fetch_var_higher(); x = gsubst(x, v, pol_x(v0)); } d = denompol(x, v0); if (v0 != v) { d = gsubst(d, v0, pol_x(v)); (void)delete_var(); } return d; } GEN denominator(GEN x, GEN D) { pari_sp av = avma; GEN d; if (!D) return denom(x); if (isint1(D)) { d = Q_denom_safe(x); if (!d) { avma = av; return gen_1; } return gerepilecopy(av, d); } if (!gequalX(D)) pari_err_TYPE("denominator", D); return gerepileupto(av, denominator_v(x, varn(D))); } GEN numerator(GEN x, GEN D) { pari_sp av = avma; long v; if (!D) return numer(x); if (isint1(D)) return Q_remove_denom(x,NULL); if (!gequalX(D)) pari_err_TYPE("numerator", D); v = varn(D); /* optimization */ if (typ(x) == t_RFRAC && varn(gel(x,2)) == v) return gcopy(gel(x,2)); return gerepileupto(av, gmul(x, denominator_v(x,v))); } GEN content0(GEN x, GEN D) { pari_sp av = avma; long v, v0; GEN d; if (!D) return content(x); if (isint1(D)) { d = Q_content_safe(x); return d? d: gen_1; } if (!gequalX(D)) pari_err_TYPE("content", D); v = varn(D); v0 = gvar(x); if (v0 == NO_VARIABLE || varncmp(v0,v) > 0) return pol_1(v); if (v0 != v) { v0 = fetch_var_higher(); x = gsubst(x, v, pol_x(v0)); } d = content(x); /* gsubst is needed because of content([x]) = x */ if (v0 != v) { d = gsubst(d, v0, pol_x(v)); (void)delete_var(); } return gerepileupto(av, d); } GEN numer_i(GEN x) { switch(typ(x)) { case t_INT: case t_REAL: case t_INTMOD: case t_FFELT: case t_PADIC: case t_SER: case t_VECSMALL: case t_POL: return x; case t_POLMOD: return mkpolmod(numer_i(gel(x,2)), gel(x,1)); case t_FRAC: case t_RFRAC: return gel(x,1); case t_COMPLEX: case t_QUAD: case t_VEC: case t_COL: case t_MAT: return gmul(denom_i(x),x); } pari_err_TYPE("numer",x); return NULL; /* LCOV_EXCL_LINE */ } GEN numer(GEN x) { pari_sp av = avma; return gerepilecopy(av, numer_i(x)); } /* Lift only intmods if v does not occur in x, lift with respect to main * variable of x if v < 0, with respect to variable v otherwise */ GEN lift0(GEN x, long v) { long lx, i; GEN y; switch(typ(x)) { case t_INT: return icopy(x); case t_INTMOD: return v < 0? icopy(gel(x,2)): gcopy(x); case t_POLMOD: if (v < 0 || v == varn(gel(x,1))) return gcopy(gel(x,2)); y = cgetg(3, t_POLMOD); gel(y,1) = lift0(gel(x,1),v); gel(y,2) = lift0(gel(x,2),v); return y; case t_PADIC: return v < 0? padic_to_Q(x): gcopy(x); case t_POL: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i 0)? subii(x,y): icopy(x); } /* see lift0 */ GEN centerlift0(GEN x, long v) { return v < 0? centerlift(x): lift0(x,v); } GEN centerlift(GEN x) { long i, v, lx; GEN y; switch(typ(x)) { case t_INT: return icopy(x); case t_INTMOD: return centerliftii(gel(x,2), gel(x,1)); case t_POLMOD: return gcopy(gel(x,2)); case t_POL: y = cgetg_copy(x, &lx); y[1] = x[1]; for (i=2; i=0) { /* here p^v is an integer */ GEN z = centerliftii(gel(x,4), gel(x,3)); pari_sp av; if (!v) return z; av = avma; y = powiu(gel(x,2),v); return gerepileuptoint(av, mulii(y,z)); } y = cgetg(3,t_FRAC); gel(y,1) = centerliftii(gel(x,4), gel(x,3)); gel(y,2) = powiu(gel(x,2),-v); return y; default: return gcopy(x); } } /*******************************************************************/ /* */ /* REAL & IMAGINARY PARTS */ /* */ /*******************************************************************/ static GEN op_ReIm(GEN f(GEN), GEN x) { long lx, i, j; pari_sp av; GEN z; switch(typ(x)) { case t_POL: z = cgetg_copy(x, &lx); z[1] = x[1]; for (j=2; j=0? gen_1: gen_0; } GEN ggt(GEN x, GEN y) { return gcmp(x,y)>0? gen_1: gen_0; } GEN geq(GEN x, GEN y) { return _egal(x,y)? gen_1: gen_0; } GEN gne(GEN x, GEN y) { return _egal(x,y)? gen_0: gen_1; } GEN gnot(GEN x) { return gequal0(x)? gen_1: gen_0; } /*******************************************************************/ /* */ /* FORMAL SIMPLIFICATIONS */ /* */ /*******************************************************************/ GEN geval_gp(GEN x, GEN t) { long lx, i, tx = typ(x); pari_sp av; GEN y, z; if (is_const_t(tx) || tx==t_VECSMALL) return gcopy(x); switch(tx) { case t_STR: return localvars_read_str(GSTR(x),t); case t_POLMOD: av = avma; return gerepileupto(av, gmodulo(geval_gp(gel(x,2),t), geval_gp(gel(x,1),t))); case t_POL: lx=lg(x); if (lx==2) return gen_0; z = fetch_var_value(varn(x),t); if (!z) return RgX_copy(x); av = avma; y = geval_gp(gel(x,lx-1),t); for (i=lx-2; i>1; i--) y = gadd(geval_gp(gel(x,i),t), gmul(z,y)); return gerepileupto(av, y); case t_SER: pari_err_IMPL( "evaluation of a power series"); case t_RFRAC: av = avma; return gerepileupto(av, gdiv(geval_gp(gel(x,1),t), geval_gp(gel(x,2),t))); case t_QFR: case t_QFI: case t_VEC: case t_COL: case t_MAT: y = cgetg_copy(x, &lx); for (i=1; i 1 */ z = gmul(gcoeff(q,1,1), gsqr(gel(x,1))); for (i=2; i 2 */ xc = conj_i(x); z = mulreal(gcoeff(q,2,1), gmul(gel(x,2),gel(xc,1))); for (i=3;i=imin; i--) p1 = gadd(gmul(p1,y),gel(x,i)); #endif /* specific attention to sparse polynomials */ for ( ; i>=imin; i=j-1) { for (j=i; isexactzero(gel(x,j)); j--) if (j==imin) { if (i!=j) y = gpowgs(y, i-j+1); return gerepileupto(av0, gmul(p1,y)); } r = (i==j)? y: gpowgs(y, i-j+1); p1 = gadd(gmul(p1,r), gel(x,j)); if (gc_needed(av0,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"poleval: i = %ld",i); p1 = gerepileupto(av0, p1); } } return gerepileupto(av0,p1); } p2 = gel(x,i); i--; r = gtrace(y); s = gneg_i(gnorm(y)); av = avma; for ( ; i>=imin; i--) { GEN p3 = gadd(p2, gmul(r, p1)); p2 = gadd(gel(x,i), gmul(s, p1)); p1 = p3; if (gc_needed(av0,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"poleval: i = %ld",i); gerepileall(av, 2, &p1, &p2); } } return gerepileupto(av0, gadd(p2, gmul(y,p1))); } /* Evaluate a polynomial using Horner. Unstable! * If ui != NULL, ui = 1/u, evaluate P(1/u)*u^(deg P): useful for |u|>1 */ GEN RgX_cxeval(GEN T, GEN u, GEN ui) { pari_sp ltop = avma; GEN S; long n, lim = lg(T)-1; if (lim == 1) return gen_0; if (lim == 2) return gcopy(gel(T,2)); if (!ui) { n = lim; S = gel(T,n); for (n--; n >= 2; n--) S = gadd(gmul(u,S), gel(T,n)); } else { n = 2; S = gel(T,2); for (n++; n <= lim; n++) S = gadd(gmul(ui,S), gel(T,n)); S = gmul(gpowgs(u, lim-2), S); } return gerepileupto(ltop, S); } pari-2.11.2/src/basemath/QX_factor.c0000644000175000017500000010770313457566440015611 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* x,y two ZX, y non constant. Return q = x/y if y divides x in Z[X] and NULL * otherwise. If not NULL, B is a t_INT upper bound for ||q||_oo. */ static GEN ZX_divides_i(GEN x, GEN y, GEN B) { long dx, dy, dz, i, j; pari_sp av; GEN z,p1,y_lead; dy=degpol(y); dx=degpol(x); dz=dx-dy; if (dz<0) return NULL; z=cgetg(dz+3,t_POL); z[1] = x[1]; x += 2; y += 2; z += 2; y_lead = gel(y,dy); if (equali1(y_lead)) y_lead = NULL; p1 = gel(x,dx); if (y_lead) { GEN r; p1 = dvmdii(p1,y_lead, &r); if (r != gen_0) return NULL; } else p1 = icopy(p1); gel(z,dz) = p1; for (i=dx-1; i>=dy; i--) { av = avma; p1 = gel(x,i); for (j=i-dy+1; j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); if (y_lead) { GEN r; p1 = dvmdii(p1,y_lead, &r); if (r != gen_0) return NULL; } if (B && abscmpii(p1, B) > 0) return NULL; p1 = gerepileuptoint(av, p1); gel(z,i-dy) = p1; } av = avma; for (; i >= 0; i--) { p1 = gel(x,i); /* we always enter this loop at least once */ for (j=0; j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); if (signe(p1)) return NULL; avma = av; } return z - 2; } static GEN ZX_divides(GEN x, GEN y) { return ZX_divides_i(x,y,NULL); } #if 0 /* cf Beauzamy et al: upper bound for * lc(x) * [2^(5/8) / pi^(3/8)] e^(1/4n) 2^(n/2) sqrt([x]_2)/ n^(3/8) * where [x]_2 = sqrt(\sum_i=0^n x[i]^2 / binomial(n,i)). One factor has * all coeffs less than then bound */ static GEN two_factor_bound(GEN x) { long i, j, n = lg(x) - 3; pari_sp av = avma; GEN *invbin, c, r = cgetr(3), z; x += 2; invbin = (GEN*)new_chunk(n+1); z = real_1(LOWDEFAULTPREC); /* invbin[i] = 1 / binomial(n, i) */ for (i=0,j=n; j >= i; i++,j--) { invbin[i] = invbin[j] = z; z = divru(mulru(z, i+1), n-i); } z = invbin[0]; /* = 1 */ for (i=0; i<=n; i++) { c = gel(x,i); if (!signe(c)) continue; affir(c, r); z = addrr(z, mulrr(sqrr(r), invbin[i])); } z = shiftr(sqrtr(z), n); z = divrr(z, dbltor(pow((double)n, 0.75))); z = roundr_safe(sqrtr(z)); z = mulii(z, absi_shallow(gel(x,n))); return gerepileuptoint(av, shifti(z, 1)); } #endif /* A | S ==> |a_i| <= binom(d-1, i-1) || S ||_2 + binom(d-1, i) lc(S) */ static GEN Mignotte_bound(GEN S) { long i, d = degpol(S); GEN C, N2, t, binlS, lS = leading_coeff(S), bin = vecbinomial(d-1); N2 = sqrtr(RgX_fpnorml2(S,DEFAULTPREC)); binlS = is_pm1(lS)? bin: ZC_Z_mul(bin, lS); /* i = 0 */ C = gel(binlS,1); /* i = d */ t = N2; if (gcmp(C, t) < 0) C = t; for (i = 1; i < d; i++) { t = addri(mulir(gel(bin,i), N2), gel(binlS,i+1)); if (mpcmp(C, t) < 0) C = t; } return C; } /* A | S ==> |a_i|^2 <= 3^{3/2 + d} / (4 \pi d) [P]_2^2, * where [P]_2 is Bombieri's 2-norm */ static GEN Beauzamy_bound(GEN S) { const long prec = DEFAULTPREC; long i, d = degpol(S); GEN bin, lS, s, C; bin = vecbinomial(d); s = real_0(prec); for (i=0; i<=d; i++) { GEN c = gel(S,i+2); if (gequal0(c)) continue; /* s += P_i^2 / binomial(d,i) */ s = addrr(s, divri(itor(sqri(c), prec), gel(bin,i+1))); } /* s = [S]_2^2 */ C = powruhalf(stor(3,prec), 3 + 2*d); /* 3^{3/2 + d} */ C = divrr(mulrr(C, s), mulur(4*d, mppi(prec))); lS = absi_shallow(leading_coeff(S)); return mulir(lS, sqrtr(C)); } static GEN factor_bound(GEN S) { pari_sp av = avma; GEN a = Mignotte_bound(S); GEN b = Beauzamy_bound(S); if (DEBUGLEVEL>2) { err_printf("Mignotte bound: %Ps\n",a); err_printf("Beauzamy bound: %Ps\n",b); } return gerepileupto(av, ceil_safe(gmin_shallow(a, b))); } /* Naive recombination of modular factors: combine up to maxK modular * factors, degree <= klim * * target = polynomial we want to factor * famod = array of modular factors. Product should be congruent to * target/lc(target) modulo p^a * For true factors: S1,S2 <= p^b, with b <= a and p^(b-a) < 2^31 */ static GEN cmbf(GEN pol, GEN famod, GEN bound, GEN p, long a, long b, long klim, long *pmaxK, int *done) { long K = 1, cnt = 1, i,j,k, curdeg, lfamod = lg(famod)-1; ulong spa_b, spa_bs2, Sbound; GEN lc, lcpol, pa = powiu(p,a), pas2 = shifti(pa,-1); GEN trace1 = cgetg(lfamod+1, t_VECSMALL); GEN trace2 = cgetg(lfamod+1, t_VECSMALL); GEN ind = cgetg(lfamod+1, t_VECSMALL); GEN deg = cgetg(lfamod+1, t_VECSMALL); GEN degsofar = cgetg(lfamod+1, t_VECSMALL); GEN listmod = cgetg(lfamod+1, t_VEC); GEN fa = cgetg(lfamod+1, t_VEC); *pmaxK = cmbf_maxK(lfamod); lc = absi_shallow(leading_coeff(pol)); if (equali1(lc)) lc = NULL; lcpol = lc? ZX_Z_mul(pol, lc): pol; { GEN pa_b,pa_bs2,pb, lc2 = lc? sqri(lc): NULL; pa_b = powiu(p, a-b); /* < 2^31 */ pa_bs2 = shifti(pa_b,-1); pb= powiu(p, b); for (i=1; i <= lfamod; i++) { GEN T1,T2, P = gel(famod,i); long d = degpol(P); deg[i] = d; P += 2; T1 = gel(P,d-1);/* = - S_1 */ T2 = sqri(T1); if (d > 1) T2 = subii(T2, shifti(gel(P,d-2),1)); T2 = modii(T2, pa); /* = S_2 Newton sum */ if (lc) { T1 = Fp_mul(lc, T1, pa); T2 = Fp_mul(lc2,T2, pa); } uel(trace1,i) = itou(diviiround(T1, pb)); uel(trace2,i) = itou(diviiround(T2, pb)); } spa_b = uel(pa_b,2); /* < 2^31 */ spa_bs2 = uel(pa_bs2,2); /* < 2^31 */ } degsofar[0] = 0; /* sentinel */ /* ind runs through strictly increasing sequences of length K, * 1 <= ind[i] <= lfamod */ nextK: if (K > *pmaxK || 2*K > lfamod) goto END; if (DEBUGLEVEL > 3) err_printf("\n### K = %d, %Ps combinations\n", K,binomial(utoipos(lfamod), K)); setlg(ind, K+1); ind[1] = 1; Sbound = (ulong) ((K+1)>>1); i = 1; curdeg = deg[ind[1]]; for(;;) { /* try all combinations of K factors */ for (j = i; j < K; j++) { degsofar[j] = curdeg; ind[j+1] = ind[j]+1; curdeg += deg[ind[j+1]]; } if (curdeg <= klim) /* trial divide */ { GEN y, q, list; pari_sp av; ulong t; /* d - 1 test */ for (t=uel(trace1,ind[1]),i=2; i<=K; i++) t = Fl_add(t, uel(trace1,ind[i]), spa_b); if (t > spa_bs2) t = spa_b - t; if (t > Sbound) { if (DEBUGLEVEL>6) err_printf("."); goto NEXT; } /* d - 2 test */ for (t=uel(trace2,ind[1]),i=2; i<=K; i++) t = Fl_add(t, uel(trace2,ind[i]), spa_b); if (t > spa_bs2) t = spa_b - t; if (t > Sbound) { if (DEBUGLEVEL>6) err_printf("|"); goto NEXT; } av = avma; /* check trailing coeff */ y = lc; for (i=1; i<=K; i++) { GEN q = constant_coeff(gel(famod,ind[i])); if (y) q = mulii(y, q); y = centermodii(q, pa, pas2); } if (!signe(y) || !dvdii(constant_coeff(lcpol), y)) { if (DEBUGLEVEL>3) err_printf("T"); avma = av; goto NEXT; } y = lc; /* full computation */ for (i=1; i<=K; i++) { GEN q = gel(famod,ind[i]); if (y) q = gmul(y, q); y = centermod_i(q, pa, pas2); } /* y is the candidate factor */ if (! (q = ZX_divides_i(lcpol,y,bound)) ) { if (DEBUGLEVEL>3) err_printf("*"); avma = av; goto NEXT; } /* found a factor */ list = cgetg(K+1, t_VEC); gel(listmod,cnt) = list; for (i=1; i<=K; i++) list[i] = famod[ind[i]]; y = Q_primpart(y); gel(fa,cnt++) = y; /* fix up pol */ pol = q; if (lc) pol = Q_div_to_int(pol, leading_coeff(y)); for (i=j=k=1; i <= lfamod; i++) { /* remove used factors */ if (j <= K && i == ind[j]) j++; else { gel(famod,k) = gel(famod,i); uel(trace1,k) = uel(trace1,i); uel(trace2,k) = uel(trace2,i); deg[k] = deg[i]; k++; } } lfamod -= K; *pmaxK = cmbf_maxK(lfamod); if (lfamod < 2*K) goto END; i = 1; curdeg = deg[ind[1]]; bound = factor_bound(pol); if (lc) lc = absi_shallow(leading_coeff(pol)); lcpol = lc? ZX_Z_mul(pol, lc): pol; if (DEBUGLEVEL>3) err_printf("\nfound factor %Ps\nremaining modular factor(s): %ld\n", y, lfamod); continue; } NEXT: for (i = K+1;;) { if (--i == 0) { K++; goto nextK; } if (++ind[i] <= lfamod - K + i) { curdeg = degsofar[i-1] + deg[ind[i]]; if (curdeg <= klim) break; } } } END: *done = 1; if (degpol(pol) > 0) { /* leftover factor */ if (signe(leading_coeff(pol)) < 0) pol = ZX_neg(pol); if (lfamod >= 2*K) *done = 0; setlg(famod, lfamod+1); gel(listmod,cnt) = leafcopy(famod); gel(fa,cnt++) = pol; } if (DEBUGLEVEL>6) err_printf("\n"); setlg(listmod, cnt); setlg(fa, cnt); return mkvec2(fa, listmod); } /* recombination of modular factors: van Hoeij's algorithm */ /* Q in Z[X], return Q(2^n) */ static GEN shifteval(GEN Q, long n) { long i, l = lg(Q); GEN s; if (!signe(Q)) return gen_0; s = gel(Q,l-1); for (i = l-2; i > 1; i--) s = addii(gel(Q,i), shifti(s, n)); return s; } /* return integer y such that all |a| <= y if P(a) = 0 */ static GEN root_bound(GEN P0) { GEN Q = leafcopy(P0), lP = absi_shallow(leading_coeff(Q)), x,y,z; long k, d = degpol(Q); /* P0 = lP x^d + Q, deg Q < d */ Q = normalizepol_lg(Q, d+2); for (k=lg(Q)-1; k>1; k--) gel(Q,k) = absi_shallow(gel(Q,k)); k = (long)(fujiwara_bound(P0)); for ( ; k >= 0; k--) { pari_sp av = avma; /* y = 2^k; Q(y) >= lP y^d ? */ if (cmpii(shifteval(Q,k), shifti(lP, d*k)) >= 0) break; avma = av; } if (k < 0) k = 0; x = int2n(k); y = int2n(k+1); for(k=0; ; k++) { z = shifti(addii(x,y), -1); if (equalii(x,z) || k > 5) break; if (cmpii(poleval(Q,z), mulii(lP, powiu(z, d))) < 0) y = z; else x = z; } return y; } GEN chk_factors_get(GEN lt, GEN famod, GEN c, GEN T, GEN N) { long i = 1, j, l = lg(famod); GEN V = cgetg(l, t_VEC); for (j = 1; j < l; j++) if (signe(gel(c,j))) gel(V,i++) = gel(famod,j); if (lt && i > 1) gel(V,1) = RgX_Rg_mul(gel(V,1), lt); setlg(V, i); return T? FpXQXV_prod(V, T, N): FpXV_prod(V,N); } static GEN chk_factors(GEN P, GEN M_L, GEN bound, GEN famod, GEN pa) { long i, r; GEN pol = P, list, piv, y, ltpol, lt, paov2; piv = ZM_hnf_knapsack(M_L); if (!piv) return NULL; if (DEBUGLEVEL>7) err_printf("ZM_hnf_knapsack output:\n%Ps\n",piv); r = lg(piv)-1; list = cgetg(r+1, t_VEC); lt = absi_shallow(leading_coeff(pol)); if (equali1(lt)) lt = NULL; ltpol = lt? ZX_Z_mul(pol, lt): pol; paov2 = shifti(pa,-1); for (i = 1;;) { if (DEBUGLEVEL) err_printf("LLL_cmbf: checking factor %ld\n",i); y = chk_factors_get(lt, famod, gel(piv,i), NULL, pa); y = FpX_center_i(y, pa, paov2); if (! (pol = ZX_divides_i(ltpol,y,bound)) ) return NULL; if (lt) y = Q_primpart(y); gel(list,i) = y; if (++i >= r) break; if (lt) { pol = ZX_Z_divexact(pol, leading_coeff(y)); lt = absi_shallow(leading_coeff(pol)); ltpol = ZX_Z_mul(pol, lt); } else ltpol = pol; } y = Q_primpart(pol); gel(list,i) = y; return list; } GEN LLL_check_progress(GEN Bnorm, long n0, GEN m, int final, long *ti_LLL) { GEN norm, u; long i, R; pari_timer T; if (DEBUGLEVEL>2) timer_start(&T); u = ZM_lll_norms(m, final? 0.999: 0.75, LLL_INPLACE, &norm); if (DEBUGLEVEL>2) *ti_LLL += timer_delay(&T); for (R=lg(m)-1; R > 0; R--) if (cmprr(gel(norm,R), Bnorm) < 0) break; for (i=1; i<=R; i++) setlg(u[i], n0+1); if (R <= 1) { if (!R) pari_err_BUG("LLL_cmbf [no factor]"); return NULL; /* irreducible */ } setlg(u, R+1); return u; } static ulong next2pow(ulong a) { ulong b = 1; while (b < a) b <<= 1; return b; } /* Recombination phase of Berlekamp-Zassenhaus algorithm using a variant of * van Hoeij's knapsack * * P = squarefree in Z[X]. * famod = array of (lifted) modular factors mod p^a * bound = Mignotte bound for the size of divisors of P (for the sup norm) * previously recombined all set of factors with less than rec elts */ static GEN LLL_cmbf(GEN P, GEN famod, GEN p, GEN pa, GEN bound, long a, long rec) { const long N0 = 1; /* # of traces added at each step */ double BitPerFactor = 0.4; /* nb bits in p^(a-b) / modular factor */ long i,j,tmax,n0,C, dP = degpol(P); double logp = log((double)itos(p)), LOGp2 = M_LN2/logp; double b0 = log((double)dP*2) / logp, logBr; GEN lP, Br, Bnorm, Tra, T2, TT, CM_L, m, list, ZERO; pari_sp av, av2; long ti_LLL = 0, ti_CF = 0; lP = absi_shallow(leading_coeff(P)); if (equali1(lP)) lP = NULL; Br = root_bound(P); if (lP) Br = mulii(lP, Br); logBr = gtodouble(glog(Br, DEFAULTPREC)) / logp; n0 = lg(famod) - 1; C = (long)ceil( sqrt(N0 * n0 / 4.) ); /* > 1 */ Bnorm = dbltor(n0 * (C*C + N0*n0/4.) * 1.00001); ZERO = zeromat(n0, N0); av = avma; TT = cgetg(n0+1, t_VEC); Tra = cgetg(n0+1, t_MAT); for (i=1; i<=n0; i++) { TT[i] = 0; gel(Tra,i) = cgetg(N0+1, t_COL); } CM_L = scalarmat_s(C, n0); /* tmax = current number of traces used (and computed so far) */ for (tmax = 0;; tmax += N0) { long b, bmin, bgood, delta, tnew = tmax + N0, r = lg(CM_L)-1; GEN M_L, q, CM_Lp, oldCM_L; int first = 1; pari_timer ti2, TI; bmin = (long)ceil(b0 + tnew*logBr); if (DEBUGLEVEL>2) err_printf("\nLLL_cmbf: %ld potential factors (tmax = %ld, bmin = %ld)\n", r, tmax, bmin); /* compute Newton sums (possibly relifting first) */ if (a <= bmin) { a = (long)ceil(bmin + 3*N0*logBr) + 1; /* enough for 3 more rounds */ a = (long)next2pow((ulong)a); pa = powiu(p,a); famod = ZpX_liftfact(P, famod, pa, p, a); for (i=1; i<=n0; i++) TT[i] = 0; } for (i=1; i<=n0; i++) { GEN p1 = gel(Tra,i); GEN p2 = polsym_gen(gel(famod,i), gel(TT,i), tnew, NULL, pa); gel(TT,i) = p2; p2 += 1+tmax; /* ignore traces number 0...tmax */ for (j=1; j<=N0; j++) gel(p1,j) = gel(p2,j); if (lP) { /* make Newton sums integral */ GEN lPpow = powiu(lP, tmax); for (j=1; j<=N0; j++) { lPpow = mulii(lPpow,lP); gel(p1,j) = mulii(gel(p1,j), lPpow); } } } /* compute truncation parameter */ if (DEBUGLEVEL>2) { timer_start(&ti2); timer_start(&TI); } oldCM_L = CM_L; av2 = avma; delta = b = 0; /* -Wall */ AGAIN: M_L = Q_div_to_int(CM_L, utoipos(C)); T2 = centermod( ZM_mul(Tra, M_L), pa ); if (first) { /* initialize lattice, using few p-adic digits for traces */ double t = gexpo(T2) - maxdd(32.0, BitPerFactor*r); bgood = (long) (t * LOGp2); b = maxss(bmin, bgood); delta = a - b; } else { /* add more p-adic digits and continue reduction */ long b0 = (long)(gexpo(T2) * LOGp2); if (b0 < b) b = b0; b = maxss(b-delta, bmin); if (b - delta/2 < bmin) b = bmin; /* near there. Go all the way */ } q = powiu(p, b); m = vconcat( CM_L, gdivround(T2, q) ); if (first) { GEN P1 = scalarmat(powiu(p, a-b), N0); first = 0; m = shallowconcat( m, vconcat(ZERO, P1) ); /* [ C M_L 0 ] * m = [ ] square matrix * [ T2' p^(a-b) I_N0 ] T2' = Tra * M_L truncated */ } CM_L = LLL_check_progress(Bnorm, n0, m, b == bmin, /*dbg:*/ &ti_LLL); if (DEBUGLEVEL>2) err_printf("LLL_cmbf: (a,b) =%4ld,%4ld; r =%3ld -->%3ld, time = %ld\n", a,b, lg(m)-1, CM_L? lg(CM_L)-1: 1, timer_delay(&TI)); if (!CM_L) { list = mkvec(P); break; } if (b > bmin) { CM_L = gerepilecopy(av2, CM_L); goto AGAIN; } if (DEBUGLEVEL>2) timer_printf(&ti2, "for this block of traces"); i = lg(CM_L) - 1; if (i == r && ZM_equal(CM_L, oldCM_L)) { CM_L = oldCM_L; avma = av2; continue; } CM_Lp = FpM_image(CM_L, utoipos(27449)); /* inexpensive test */ if (lg(CM_Lp) != lg(CM_L)) { if (DEBUGLEVEL>2) err_printf("LLL_cmbf: rank decrease\n"); CM_L = ZM_hnf(CM_L); } if (i <= r && i*rec < n0) { pari_timer ti; if (DEBUGLEVEL>2) timer_start(&ti); list = chk_factors(P, Q_div_to_int(CM_L,utoipos(C)), bound, famod, pa); if (DEBUGLEVEL>2) ti_CF += timer_delay(&ti); if (list) break; if (DEBUGLEVEL>2) err_printf("LLL_cmbf: chk_factors failed"); } CM_L = gerepilecopy(av2, CM_L); if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"LLL_cmbf"); gerepileall(av, 5, &CM_L, &TT, &Tra, &famod, &pa); } } if (DEBUGLEVEL>2) err_printf("* Time LLL: %ld\n* Time Check Factor: %ld\n",ti_LLL,ti_CF); return list; } /* Find a,b minimal such that A < q^a, B < q^b, 1 << q^(a-b) < 2^31 */ static int cmbf_precs(GEN q, GEN A, GEN B, long *pta, long *ptb, GEN *qa, GEN *qb) { long a,b,amin,d = (long)(31 * M_LN2/gtodouble(glog(q,DEFAULTPREC)) - 1e-5); int fl = 0; b = logintall(B, q, qb) + 1; *qb = mulii(*qb, q); amin = b + d; if (gcmp(powiu(q, amin), A) <= 0) { a = logintall(A, q, qa) + 1; *qa = mulii(*qa, q); b = a - d; *qb = powiu(q, b); } else { /* not enough room */ a = amin; *qa = powiu(q, a); fl = 1; } if (DEBUGLEVEL > 3) { err_printf("S_2 bound: %Ps^%ld\n", q,b); err_printf("coeff bound: %Ps^%ld\n", q,a); } *pta = a; *ptb = b; return fl; } /* use van Hoeij's knapsack algorithm */ static GEN combine_factors(GEN target, GEN famod, GEN p, long klim) { GEN la, B, A, res, L, pa, pb, listmod; long a,b, l, maxK, n = degpol(target); int done; pari_timer T; A = factor_bound(target); la = absi_shallow(leading_coeff(target)); B = mului(n, sqri(mulii(la, root_bound(target)))); /* = bound for S_2 */ (void)cmbf_precs(p, A, B, &a, &b, &pa, &pb); if (DEBUGLEVEL>2) timer_start(&T); famod = ZpX_liftfact(target, famod, pa, p, a); if (DEBUGLEVEL>2) timer_printf(&T, "Hensel lift (mod %Ps^%ld)", p,a); L = cmbf(target, famod, A, p, a, b, klim, &maxK, &done); if (DEBUGLEVEL>2) timer_printf(&T, "Naive recombination"); res = gel(L,1); listmod = gel(L,2); l = lg(listmod)-1; famod = gel(listmod,l); if (maxK > 0 && lg(famod)-1 > 2*maxK) { if (l!=1) A = factor_bound(gel(res,l)); if (DEBUGLEVEL > 4) err_printf("last factor still to be checked\n"); L = LLL_cmbf(gel(res,l), famod, p, pa, A, a, maxK); if (DEBUGLEVEL>2) timer_printf(&T,"Knapsack"); /* remove last elt, possibly unfactored. Add all new ones. */ setlg(res, l); res = shallowconcat(res, L); } return res; } /* Assume 'a' a squarefree ZX; return 0 if no root (fl=1) / irreducible (fl=0). * Otherwise return prime p such that a mod p has fewest roots / factors */ static ulong pick_prime(GEN a, long fl, pari_timer *T) { pari_sp av = avma, av1; const long MAXNP = 7, da = degpol(a); long nmax = da+1, np; ulong chosenp = 0; GEN lead = gel(a,da+2); forprime_t S; if (equali1(lead)) lead = NULL; u_forprime_init(&S, 2, ULONG_MAX); av1 = avma; for (np = 0; np < MAXNP; avma = av1) { ulong p = u_forprime_next(&S); long nfacp; GEN z; if (!p) pari_err_OVERFLOW("DDF [out of small primes]"); if (lead && !umodiu(lead,p)) continue; z = ZX_to_Flx(a, p); if (!Flx_is_squarefree(z, p)) continue; if (fl) { nfacp = Flx_nbroots(z, p); if (!nfacp) { chosenp = 0; break; } /* no root */ } else { nfacp = Flx_nbfact(z, p); if (nfacp == 1) { chosenp = 0; break; } /* irreducible */ } if (DEBUGLEVEL>4) err_printf("...tried prime %3lu (%-3ld %s). Time = %ld\n", p, nfacp, fl? "roots": "factors", timer_delay(T)); if (nfacp < nmax) { nmax = nfacp; chosenp = p; if (da > 100 && nmax < 5) break; /* large degree, few factors. Enough */ } np++; } avma = av; return chosenp; } /* Assume A a squarefree ZX; return the vector of its rational roots */ static GEN DDF_roots(GEN A) { GEN p, lc, lcpol, z, pe, pes2, bound; long i, m, e, lz; ulong pp; pari_sp av; pari_timer T; if (DEBUGLEVEL>2) timer_start(&T); pp = pick_prime(A, 1, &T); if (!pp) return cgetg(1,t_VEC); /* no root */ p = utoipos(pp); lc = leading_coeff(A); if (is_pm1(lc)) { lc = NULL; lcpol = A; } else { lc = absi_shallow(lc); lcpol = ZX_Z_mul(A, lc); } bound = root_bound(A); if (lc) bound = mulii(lc, bound); e = logintall(addiu(shifti(bound, 1), 1), p, &pe) + 1; pe = mulii(pe, p); pes2 = shifti(pe, -1); if (DEBUGLEVEL>2) timer_printf(&T, "Root bound"); av = avma; z = ZpX_roots(A, p, e); lz = lg(z); z = deg1_from_roots(z, varn(A)); if (DEBUGLEVEL>2) timer_printf(&T, "Hensel lift (mod %lu^%ld)", pp,e); for (m=1, i=1; i < lz; i++) { GEN q, r, y = gel(z,i); if (lc) y = ZX_Z_mul(y, lc); y = centermod_i(y, pe, pes2); if (! (q = ZX_divides(lcpol, y)) ) continue; lcpol = q; r = negi( constant_coeff(y) ); if (lc) { r = gdiv(r,lc); lcpol = Q_primpart(lcpol); lc = absi_shallow( leading_coeff(lcpol) ); if (is_pm1(lc)) lc = NULL; else lcpol = ZX_Z_mul(lcpol, lc); } gel(z,m++) = r; if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"DDF_roots, m = %ld", m); gerepileall(av, lc? 3:2, &z, &lcpol, &lc); } } if (DEBUGLEVEL>2) timer_printf(&T, "Recombination"); z[0] = evaltyp(t_VEC) | evallg(m); return z; } /* Assume a squarefree ZX, deg(a) > 0, return rational factors. * In fact, a(0) != 0 but we don't use this */ static GEN DDF(GEN a) { GEN ap, prime, famod, z; long ti = 0; ulong p = 0; pari_sp av = avma; pari_timer T, T2; if (DEBUGLEVEL>2) { timer_start(&T); timer_start(&T2); } p = pick_prime(a, 0, &T2); if (!p) return mkvec(a); prime = utoipos(p); ap = Flx_normalize(ZX_to_Flx(a, p), p); famod = gel(Flx_factor(ap, p), 1); if (DEBUGLEVEL>2) { if (DEBUGLEVEL>4) timer_printf(&T2, "splitting mod p = %lu", p); ti = timer_delay(&T); err_printf("Time setup: %ld\n", ti); } z = combine_factors(a, FlxV_to_ZXV(famod), prime, degpol(a)-1); if (DEBUGLEVEL>2) err_printf("Total Time: %ld\n===========\n", ti + timer_delay(&T)); return gerepilecopy(av, z); } /* Distinct Degree Factorization (deflating first) * Assume x squarefree, degree(x) > 0, x(0) != 0 */ GEN ZX_DDF(GEN x) { GEN L; long m; x = ZX_deflate_max(x, &m); L = DDF(x); if (m > 1) { GEN e, v, fa = factoru(m); long i,j,k, l; e = gel(fa,2); k = 0; fa= gel(fa,1); l = lg(fa); for (i=1; i ggcd). Return (P), set *ex = (e) */ GEN ZX_squff(GEN f, GEN *ex) { GEN T, V, P, e; long i, k, n, val; if (signe(leading_coeff(f)) < 0) f = gneg_i(f); val = ZX_valrem(f, &f); n = 1 + degpol(f); if (val) n++; e = cgetg(n,t_VECSMALL); P = cgetg(n,t_COL); T = ZX_gcd_all(f, ZX_deriv(f), &V); for (k=i=1;; k++) { pari_sp av = avma; GEN W = ZX_gcd_all(T,V, &T); long dW = degpol(W); /* W = prod P^e, e > k; V = prod P^e, e >= k */ if (dW == degpol(V)) /* V | T */ { GEN U; if (!dW) { avma = av; break; } while ( (U = ZX_divides(T, V)) ) { k++; T = U; } T = gerepilecopy(av, T); } else { gel(P,i) = Q_primpart(RgX_div(V,W)); e[i] = k; i++; if (!dW) break; V = W; } } if (val) { gel(P,i) = pol_x(varn(f)); e[i] = val; i++;} setlg(P,i); setlg(e,i); *ex = e; return P; } static GEN fact_from_DDF(GEN fa, GEN e, long n) { GEN v,w, y = cgetg(3, t_MAT); long i,j,k, l = lg(fa); v = cgetg(n+1,t_COL); gel(y,1) = v; w = cgetg(n+1,t_COL); gel(y,2) = w; for (k=i=1; i 1) { if (!signe(gel(x,2))) return 0; x = RgX_deflate(x, m); } d = ZX_gcd(x,ZX_deriv(x)); r = (lg(d) == 3); avma = av; return r; } #if 0 /* ceil( || p ||_oo / lc(p) ) */ static GEN maxnorm(GEN p) { long i, n = degpol(p), av = avma; GEN x, m = gen_0; p += 2; for (i=0; i 0) m = x; } m = divii(m, gel(p,n)); return gerepileuptoint(av, addiu(absi_shallow(m),1)); } #endif /* A, B in Z[X] */ GEN ZX_gcd_all(GEN A, GEN B, GEN *Anew) { GEN R, a, b, q, H, Hp, g, Ag, Bg; long m, n, valX, valA, vA = varn(A); ulong p; int small; pari_sp ltop, av; forprime_t S; if (!signe(A)) { if (Anew) *Anew = pol_0(vA); return ZX_copy(B); } if (!signe(B)) { if (Anew) *Anew = pol_1(vA); return ZX_copy(A); } valA = ZX_valrem(A, &A); valX = minss(valA, ZX_valrem(B, &B)); ltop = avma; n = 1 + minss(degpol(A), degpol(B)); /* > degree(gcd) */ g = gcdii(leading_coeff(A), leading_coeff(B)); /* multiple of lead(gcd) */ if (is_pm1(g)) { g = NULL; Ag = A; Bg = B; } else { Ag = ZX_Z_mul(A,g); Bg = ZX_Z_mul(B,g); } small = (ZX_max_lg(A) == 3 && ZX_max_lg(B) == 3); init_modular_big(&S); av = avma; R = NULL;/*-Wall*/ H = NULL; while ((p = u_forprime_next(&S))) { if (g && !umodiu(g,p)) continue; a = ZX_to_Flx(A, p); b = ZX_to_Flx(B, p); Hp = Flx_gcd(a,b, p); m = degpol(Hp); if (m == 0) { /* coprime. DONE */ avma = ltop; if (Anew) { if (valA != valX) A = RgX_shift(A, valA - valX); *Anew = A; } return pol_xn(valX, vA); } if (m > n) continue; /* p | Res(A/G, B/G). Discard */ if (!g) /* make sure lead(H) = g mod p */ Hp = Flx_normalize(Hp, p); else { ulong t = Fl_mul(umodiu(g, p), Fl_inv(Hp[m+2],p), p); Hp = Flx_Fl_mul(Hp, t, p); } if (m < n) { /* First time or degree drop [all previous p were as above; restart]. */ H = ZX_init_CRT(Hp,p,vA); q = utoipos(p); n = m; if (!small) continue; /* if gcd is small, try our luck */ } else if (!ZX_incremental_CRT(&H, Hp, &q, p)) continue; if (DEBUGLEVEL>5) err_printf("gcd mod %lu (bound 2^%ld)\n", p,expi(q)); /* H stable: check divisibility */ if (!ZX_divides(Bg, H)) continue; R = ZX_divides(Ag, H); if (R) break; if (gc_needed(av,1)) { if (DEBUGMEM>1) pari_warn(warnmem,"QX_gcd"); gerepileall(av, 3, &H, &q, &Hp); } } if (!p) pari_err_OVERFLOW("ZX_gcd_all [ran out of primes]"); if (Anew) { A = R; if (valA != valX) A = RgX_shift(A, valA - valX); *Anew = A; } return valX ? RgX_shift(H, valX): H; } GEN ZX_gcd(GEN A, GEN B) { return ZX_gcd_all(A,B,NULL); } GEN ZX_radical(GEN A) { GEN B; (void)ZX_gcd_all(A,ZX_deriv(A),&B); return B; } static GEN _gcd(GEN a, GEN b) { if (!a) a = gen_1; if (!b) b = gen_1; return Q_gcd(a,b); } /* A0 and B0 in Q[X] */ GEN QX_gcd(GEN A0, GEN B0) { GEN a, b, D; pari_sp av = avma, av2; D = ZX_gcd(Q_primitive_part(A0, &a), Q_primitive_part(B0, &b)); av2 = avma; a = _gcd(a,b); if (isint1(a)) avma = av2; else D = ZX_Q_mul(D, a); return gerepileupto(av, D); } /***************************************************************************** * Variants of the Bradford-Davenport algorithm: look for cyclotomic * * factors, and decide whether a ZX is cyclotomic or a product of cyclotomic * *****************************************************************************/ /* f of degree 1, return a cyclotomic factor (Phi_1 or Phi_2) or NULL */ static GEN BD_deg1(GEN f) { GEN a = gel(f,3), b = gel(f,2); /* f = ax + b */ if (!absequalii(a,b)) return NULL; return polcyclo((signe(a) == signe(b))? 2: 1, varn(f)); } /* f a squarefree ZX; not divisible by any Phi_n, n even */ static GEN BD_odd(GEN f) { while(degpol(f) > 1) { GEN f1 = ZX_graeffe(f); /* contain all cyclotomic divisors of f */ if (ZX_equal(f1, f)) return f; /* product of cyclotomics */ f = ZX_gcd(f, f1); } if (degpol(f) == 1) return BD_deg1(f); return NULL; /* no cyclotomic divisor */ } static GEN myconcat(GEN v, GEN x) { if (typ(x) != t_VEC) x = mkvec(x); if (!v) return x; return shallowconcat(v, x); } /* Bradford-Davenport algorithm. * f a squarefree ZX of degree > 0, return NULL or a vector of coprime * cyclotomic factors of f [ possibly reducible ] */ static GEN BD(GEN f) { GEN G = NULL, Gs = NULL, Gp = NULL, Gi = NULL; GEN fs2, fp, f2, f1, fe, fo, fe1, fo1; RgX_even_odd(f, &fe, &fo); fe1 = ZX_eval1(fe); fo1 = ZX_eval1(fo); if (absequalii(fe1, fo1)) /* f(1) = 0 or f(-1) = 0 */ { long i, v = varn(f); if (!signe(fe1)) G = mkvec2(polcyclo(1, v), polcyclo(2, v)); /* both 0 */ else if (signe(fe1) == signe(fo1)) G = mkvec(polcyclo(2, v)); /*f(-1) = 0*/ else G = mkvec(polcyclo(1, v)); /*f(1) = 0*/ for (i = lg(G)-1; i; i--) f = RgX_div(f, gel(G,i)); } /* f no longer divisible by Phi_1 or Phi_2 */ if (degpol(f) <= 1) return G; f1 = ZX_graeffe(f); /* has at most square factors */ if (ZX_equal(f1, f)) return myconcat(G,f); /* f = product of Phi_n, n odd */ fs2 = ZX_gcd_all(f1, ZX_deriv(f1), &f2); /* fs2 squarefree */ if (degpol(fs2)) { /* fs contains all Phi_n | f, 4 | n; and only those */ /* In that case, Graeffe(Phi_n) = Phi_{n/2}^2, and Phi_n = Phi_{n/2}(x^2) */ GEN fs = RgX_inflate(fs2, 2); (void)ZX_gcd_all(f, fs, &f); /* remove those Phi_n | f, 4 | n */ Gs = BD(fs2); if (Gs) { long i; for (i = lg(Gs)-1; i; i--) gel(Gs,i) = RgX_inflate(gel(Gs,i), 2); /* prod Gs[i] is the product of all Phi_n | f, 4 | n */ G = myconcat(G, Gs); } /* f2 = f1 / fs2 */ f1 = RgX_div(f2, fs2); /* f1 / fs2^2 */ } fp = ZX_gcd(f, f1); /* contains all Phi_n | f, n > 1 odd; and only those */ if (degpol(fp)) { Gp = BD_odd(fp); /* Gp is the product of all Phi_n | f, n odd */ if (Gp) G = myconcat(G, Gp); f = RgX_div(f, fp); } if (degpol(f)) { /* contains all Phi_n originally dividing f, n = 2 mod 4, n > 2; * and only those * In that case, Graeffe(Phi_n) = Phi_{n/2}, and Phi_n = Phi_{n/2}(-x) */ Gi = BD_odd(ZX_z_unscale(f, -1)); if (Gi) { /* N.B. Phi_2 does not divide f */ Gi = ZX_z_unscale(Gi, -1); /* Gi is the product of all Phi_n | f, n = 2 mod 4 */ G = myconcat(G, Gi); } } return G; } /* Let f be a non-zero QX, return the (squarefree) product of cyclotomic * divisors of f */ GEN polcyclofactors(GEN f) { pari_sp av = avma; if (typ(f) != t_POL || !signe(f)) pari_err_TYPE("polcyclofactors",f); (void)RgX_valrem(f, &f); f = Q_primpart(f); RgX_check_ZX(f,"polcyclofactors"); if (degpol(f)) { f = BD(ZX_radical(f)); if (f) return gerepilecopy(av, f); } avma = av; return cgetg(1,t_VEC); } /* return t*x mod T(x), T a monic ZX. Assume deg(t) < deg(T) */ static GEN ZXQ_mul_by_X(GEN t, GEN T) { GEN lt; t = RgX_shift_shallow(t, 1); if (degpol(t) < degpol(T)) return t; lt = leading_coeff(t); if (is_pm1(lt)) return signe(lt) > 0 ? ZX_sub(t, T): ZX_add(t, T); return ZX_sub(t, ZX_Z_mul(T, leading_coeff(t))); } /* f a product of Phi_n, all n odd; deg f > 1. Is it irreducible ? */ static long BD_odd_iscyclo(GEN f) { pari_sp av; long d, e, n, bound; GEN t; f = ZX_deflate_max(f, &e); av = avma; /* The original f is cyclotomic (= Phi_{ne}) iff the present one is Phi_n, * where all prime dividing e also divide n. If current f is Phi_n, * then n is odd and squarefree */ d = degpol(f); /* = phi(n) */ /* Let e > 0, g multiplicative such that g(p) = p / (p-1)^(1+e) < 1 iff p < (p-1)^(1+e) For all squarefree odd n, we have g(n) < C, hence n < C phi(n)^(1+e), where C = \prod_{p odd | p > (p-1)^(1+e)} g(p) For e = 1/10, we obtain p = 3, 5 and C < 1.523 For e = 1/100, we obtain p = 3, 5, ..., 29 and C < 2.573 In fact, for n <= 10^7 odd & squarefree, we have n < 2.92 * phi(n) By the above, n<10^7 covers all d <= (10^7/2.573)^(1/(1+1/100)) < 3344391. */ if (d <= 3344391) bound = (long)(2.92 * d); else bound = (long)(2.573 * pow(d,1.01)); /* IF f = Phi_n, n squarefree odd, then n <= bound */ t = pol_xn(d-1, varn(f)); for (n = d; n <= bound; n++) { t = ZXQ_mul_by_X(t, f); /* t = (X mod f(X))^d */ if (degpol(t) == 0) break; if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"BD_odd_iscyclo"); t = gerepilecopy(av, t); } } if (n > bound || eulerphiu(n) != (ulong)d) return 0; if (e > 1) return (u_ppo(e, n) == 1)? e * n : 0; return n; } /* Checks if f, monic squarefree ZX with |constant coeff| = 1, is a cyclotomic * polynomial. Returns n if f = Phi_n, and 0 otherwise */ static long BD_iscyclo(GEN f) { pari_sp av = avma; GEN f2, fn, f1; if (degpol(f) == 1) return isint1(gel(f,2))? 2: 1; f1 = ZX_graeffe(f); /* f = product of Phi_n, n odd */ if (ZX_equal(f, f1)) { avma = av; return BD_odd_iscyclo(f); } fn = ZX_z_unscale(f, -1); /* f(-x) */ /* f = product of Phi_n, n = 2 mod 4 */ if (ZX_equal(f1, fn)) return 2*BD_odd_iscyclo(fn); if (issquareall(f1, &f2)) { GEN lt = leading_coeff(f2); long c; if (signe(lt) < 0) f2 = ZX_neg(f2); c = BD_iscyclo(f2); return odd(c)? 0: 2*c; } avma = av; return 0; } long poliscyclo(GEN f) { long d; if (typ(f) != t_POL) pari_err_TYPE("poliscyclo", f); d = degpol(f); if (d <= 0 || !RgX_is_ZX(f)) return 0; if (!equali1(gel(f,d+2)) || !is_pm1(gel(f,2))) return 0; if (d == 1) return signe(gel(f,2)) > 0? 2: 1; return ZX_is_squarefree(f)? BD_iscyclo(f): 0; } long poliscycloprod(GEN f) { pari_sp av = avma; long i, d = degpol(f); if (typ(f) != t_POL) pari_err_TYPE("poliscycloprod",f); if (!RgX_is_ZX(f)) return 0; if (!ZX_is_monic(f) || !is_pm1(constant_coeff(f))) return 0; if (d < 2) return (d == 1); if ( degpol(ZX_gcd_all(f, ZX_deriv(f), &f)) ) { d = degpol(f); if (d == 1) return 1; } f = BD(f); if (!f) return 0; for (i = lg(f)-1; i; i--) d -= degpol(gel(f,i)); avma = av; return d == 0; } pari-2.11.2/src/basemath/kummer.c0000644000175000017500000012241513455133537015213 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* KUMMER EXTENSIONS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" typedef struct { GEN R; /* nf.pol */ GEN x; /* tau ( Mod(x, R) ) */ GEN zk;/* action of tau on nf.zk (as t_MAT) */ } tau_s; typedef struct { GEN polnf, invexpoteta1, powg; tau_s *tau; long m; } toK_s; typedef struct { GEN R; /* ZX, compositum(P,Q) */ GEN p; /* QX, Mod(p,R) root of P */ GEN q; /* QX, Mod(q,R) root of Q */ long k; /* Q[X]/R generated by q + k p */ GEN rev; } compo_s; static long prank(GEN cyc, long ell) { long i; for (i=1; i= d); for (j = i+1; j < k; j++) y[j] = 0; return 1; } static int ok_congruence(GEN X, ulong ell, long lW, GEN vecMsup) { long i, l; if (zv_equal0(X)) return 0; l = lg(X); for (i=lW; i1) err_printf("reducing beta = %Ps\n",b); b = reduce_mod_Qell(nf, b, ell); /* reduce l-th root */ y = idealsqrtn(nf, b, ell, 0); /* (b) = y^ell I, I integral */ if (typ(y) == t_MAT && !is_pm1(gcoeff(y,1,1))) { GEN T = idealred(nf, mkvec2(y, gen_1)), t = gel(T,2); /* (t)*T[1] = y, T[1] integral and small */ if (gcmp(idealnorm(nf,t), gen_1) > 0) b = nfmul(nf, b, nfpow(nf, t, negi(ell))); } if (DEBUGLEVEL>1) err_printf("beta reduced via ell-th root = %Ps\n",b); b = Q_primitive_part(b, &cb); if (cb) { y = nfroots(nf, gsub(monomial(gen_1, itou(ell), fetch_var_higher()), basistoalg(nf,b))); delete_var(); } if (cb && lg(y) != 1) b = gen_1; else { /* log. embeddings of fu^ell */ GEN fu = bnf_get_fu_nocheck(bnfz), logfu = bnf_get_logfu(bnfz); GEN elllogfu = RgM_Rg_mul(real_i(logfu), ell); long prec = nf_get_prec(nf); for (;;) { GEN emb, z = get_arch_real(nf, b, &emb, prec); if (z) { GEN ex = RgM_Babai(elllogfu, z); if (ex) { y = nffactorback(nf, fu, RgC_Rg_mul(ex,ell)); b = nfdiv(nf, b, y); break; } } prec = precdbl(prec); if (DEBUGLEVEL) pari_warn(warnprec,"reducebeta",prec); nf = nfnewprec_shallow(nf,prec); } } if (cb) b = gmul(b, cb); if (DEBUGLEVEL>1) err_printf("beta LLL-reduced mod U^l = %Ps\n",b); return b; } /* FIXME: remove */ static GEN tauofalg(GEN x, tau_s *tau) { long tx = typ(x); if (tx == t_POLMOD) { x = gel(x,2); tx = typ(x); } if (tx == t_POL) x = RgX_RgXQ_eval(x, tau->x, tau->R); return mkpolmod(x, tau->R); } /* compute Gal(K(\zeta_l)/K) */ static void get_tau(tau_s *tau, GEN nf, compo_s *C, ulong g) { GEN U; /* compute action of tau: q^g + kp */ U = RgX_add(RgXQ_powu(C->q, g, C->R), RgX_muls(C->p, C->k)); U = RgX_RgXQ_eval(C->rev, U, C->R); tau->x = U; tau->R = C->R; tau->zk = nfgaloismatrix(nf, U); } static GEN tauoffamat(GEN x, tau_s *tau); static GEN tauofelt(GEN x, tau_s *tau) { switch(typ(x)) { case t_COL: return RgM_RgC_mul(tau->zk, x); case t_MAT: return tauoffamat(x, tau); default: return tauofalg(x, tau); } } static GEN tauofvec(GEN x, tau_s *tau) { long i, l; GEN y = cgetg_copy(x, &l); for (i=1; itau; long i, m = T->m; GEN y = trivial_fact(), powg = T->powg; /* powg[i] = g^i */ for (i=1; izk, id), gcoeff(id, 1,1)); } static int isprimeidealconj(GEN P, GEN Q, tau_s *tau) { GEN p = pr_get_p(P); GEN x = pr_get_gen(P); if (!equalii(p, pr_get_p(Q)) || pr_get_e(P) != pr_get_e(Q) || pr_get_f(P) != pr_get_f(Q)) return 0; if (ZV_equal(x, pr_get_gen(Q))) return 1; for(;;) { if (ZC_prdvd(x,Q)) return 1; x = FpC_red(tauofelt(x, tau), p); if (ZC_prdvd(x,P)) return 0; } } static int isconjinprimelist(GEN S, GEN pr, tau_s *tau) { long i, l; if (!tau) return 0; l = lg(S); for (i=1; iinvexpoteta1) - 1; GEN y = gmul(T->invexpoteta1, Rg_to_RgC(lift_shallow(x), degKz)); return gmodulo(gtopolyrev(y,varn(T->polnf)), T->polnf); } static GEN no_sol(long all, long i) { if (!all) pari_err_BUG(stack_sprintf("kummer [bug%ld]", i)); return cgetg(1,t_VEC); } static GEN get_gell(GEN bnr, GEN subgp, long all) { GEN gell; if (all && all != -1) return utoipos(labs(all)); if (!subgp) return ZV_prod(bnr_get_cyc(bnr)); gell = det(subgp); if (typ(gell) != t_INT) pari_err_TYPE("rnfkummer",gell); return gell; } typedef struct { GEN Sm, Sml1, Sml2, Sl, ESml2; } primlist; static int build_list_Hecke(primlist *L, GEN nfz, GEN fa, GEN gothf, GEN gell, tau_s *tau) { GEN listpr, listex, pr, factell; long vp, i, l, ell = itos(gell), degKz = nf_get_degree(nfz); if (!fa) fa = idealfactor(nfz, gothf); listpr = gel(fa,1); listex = gel(fa,2); l = lg(listpr); L->Sm = vectrunc_init(l); L->Sml1= vectrunc_init(l); L->Sml2= vectrunc_init(l); L->Sl = vectrunc_init(l+degKz); L->ESml2=vecsmalltrunc_init(l); for (i=1; iSm,pr,tau)) vectrunc_append(L->Sm,pr); } else { long e = pr_get_e(pr), vd = (vp-1)*(ell-1)-ell*e; if (vd > 0) return 4; if (vd==0) { if (!isconjinprimelist(L->Sml1,pr,tau)) vectrunc_append(L->Sml1, pr); } else { if (vp==1) return 2; if (!isconjinprimelist(L->Sml2,pr,tau)) { vectrunc_append(L->Sml2, pr); vecsmalltrunc_append(L->ESml2, vp); } } } } factell = idealprimedec(nfz,gell); l = lg(factell); for (i=1; iSl,pr,tau)) vectrunc_append(L->Sl, pr); } return 0; /* OK */ } /* Return a Flm */ static GEN logall(GEN nf, GEN vec, long lW, long mginv, long ell, GEN pr, long ex) { GEN m, M, sprk = zlog_pr_init(nf, pr, ex); long ellrank, i, l = lg(vec); ellrank = prank(gel(sprk,1), ell); M = cgetg(l,t_MAT); for (i=1; i1) err_printf("beta reduced = %Ps\n",be); return be; } static GEN get_Selmer(GEN bnf, GEN cycgen, long rc) { GEN U = bnf_build_units(bnf), tu = gel(U,1), fu = vecslice(U, 2, lg(U)-1); return shallowconcat(shallowconcat(fu,mkvec(tu)), vecslice(cycgen,1,rc)); } GEN lift_if_rational(GEN x) { long lx, i; GEN y; switch(typ(x)) { default: break; case t_POLMOD: y = gel(x,2); if (typ(y) == t_POL) { long d = degpol(y); if (d > 0) return x; return (d < 0)? gen_0: gel(y,2); } return y; case t_POL: lx = lg(x); for (i=2; i= lW; ) { for (j=dK; j > 0; j--) if (coeff(K, i, j)) break; if (!j) { /* Do our best to ensure that K[dK,i] != 0 */ if (coeff(K, i, dK)) continue; for (j = idx; j < dK; j++) if (coeff(K, i, j) && coeff(K, Kidx[j], dK) != ell - 1) Flv_add_inplace(gel(K,dK), gel(K,j), ell); } if (j != --idx) swap(gel(K, j), gel(K, idx)); Kidx[idx] = i; if (coeff(K,i,idx) != 1) Flv_Fl_div_inplace(gel(K,idx), coeff(K,i,idx), ell); Ki = gel(K,idx); if (coeff(K,i,dK) != 1) { ulong t = Fl_sub(coeff(K,i,dK), 1, ell); Flv_sub_inplace(gel(K,dK), Flv_Fl_mul(Ki, t, ell), ell); } for (j = dK; --j > 0; ) { if (j == idx) continue; if (coeff(K,i,j)) Flv_sub_inplace(gel(K,j), Flv_Fl_mul(Ki, coeff(K,i,j), ell), ell); } } /* ffree = first vector that is not "free" for the scalar products */ ffree = idx; /* Second step: for each hyperplane equation in vecMsup, do the same * thing as before. */ for (i=1; i < lg(vecMsup); i++) { GEN Msup = gel(vecMsup,i); ulong dotprod; if (lgcols(Msup) != 2) continue; Msup = zm_row(Msup, 1); for (j=ffree; --j > 0; ) { dotprod = Flv_dotproduct(Msup, gel(K,j), ell); if (dotprod) { if (j != --ffree) swap(gel(K, j), gel(K, ffree)); if (dotprod != 1) Flv_Fl_div_inplace(gel(K, ffree), dotprod, ell); break; } } if (!j) { /* Do our best to ensure that vecMsup.K[dK] != 0 */ if (Flv_dotproduct(Msup, gel(K,dK), ell) == 0) { for (j = ffree-1; j <= dK; j++) if (Flv_dotproduct(Msup, gel(K,j), ell) && coeff(K,Kidx[j],dK) != ell-1) Flv_add_inplace(gel(K,dK), gel(K,j), ell); } continue; } Ki = gel(K,ffree); dotprod = Flv_dotproduct(Msup, gel(K,dK), ell); if (dotprod != 1) { ulong t = Fl_sub(dotprod,1,ell); Flv_sub_inplace(gel(K,dK), Flv_Fl_mul(Ki,t,ell), ell); } for (j = dK; --j > 0; ) { if (j == ffree) continue; dotprod = Flv_dotproduct(Msup, gel(K,j), ell); if (dotprod) Flv_sub_inplace(gel(K,j), Flv_Fl_mul(Ki,dotprod,ell), ell); } } if (ell == 2) { for (i = ffree, j = ffree-1; i <= dK && j; i++, j--) { swap(gel(K,i), gel(K,j)); } } /* Try to ensure that y = vec_ei(n, i) gives a good candidate */ for (i = 1; i < dK; i++) Flv_add_inplace(gel(K,i), gel(K,dK), ell); return gerepilecopy(av, K); } static GEN Flm_init(long m, long n) { GEN M = cgetg(n+1, t_MAT); long i; for (i = 1; i <= n; i++) gel(M,i) = cgetg(m+1, t_VECSMALL); return M; } static void Flv_fill(GEN v, GEN y) { long i, l = lg(y); for (i = 1; i < l; i++) v[i] = y[i]; } static GEN get_badbnf(GEN bnf) { long i, l; GEN bad = gen_1, gen = bnf_get_gen(bnf); l = lg(gen); for (i = 1; i < l; i++) { GEN g = gel(gen,i); bad = lcmii(bad, gcoeff(g,1,1)); } return bad; } /* Let K base field, L/K described by bnr (conductor f) + H. Return a list of * primes coprime to f*ell of degree 1 in K whose images in Cl_f(K) generate H: * thus they all split in Lz/Kz; t in Kz is such that * t^(1/p) generates Lz => t is an ell-th power in k(pr) for all such primes. * Restrict to primes not dividing * - the index fz of the polynomial defining Kz, or * - the modulus, or * - ell, or * - a generator in bnf.gen or bnfz.gen */ static GEN get_prlist(GEN bnr, GEN H, ulong ell, GEN bnfz) { pari_sp av0 = avma; forprime_t T; ulong p; GEN L, nf, cyc, bad, cond, condZ, Hsofar; L = cgetg(1, t_VEC); cyc = bnr_get_cyc(bnr); nf = bnr_get_nf(bnr); cond = gel(bnr_get_mod(bnr), 1); condZ = gcoeff(cond,1,1); bad = get_badbnf(bnr_get_bnf(bnr)); if (bnfz) { GEN badz = lcmii(get_badbnf(bnfz), nf_get_index(bnf_get_nf(bnfz))); bad = mulii(bad,badz); } bad = lcmii(muliu(condZ, ell), bad); /* restrict to primes not dividing bad */ u_forprime_init(&T, 2, ULONG_MAX); Hsofar = cgetg(1, t_MAT); while ((p = u_forprime_next(&T))) { GEN LP; long i, l; if (p == ell || !umodiu(bad, p)) continue; LP = idealprimedec_limit_f(nf, utoipos(p), 1); l = lg(LP); for (i = 1; i < l; i++) { pari_sp av = avma; GEN M, P = gel(LP,i), v = bnrisprincipal(bnr, P, 0); if (!hnf_invimage(H, v)) { avma = av; continue; } M = shallowconcat(Hsofar, v); M = ZM_hnfmodid(M, cyc); if (ZM_equal(M, Hsofar)) continue; L = shallowconcat(L, mkvec(P)); Hsofar = M; /* the primes in L generate H */ if (ZM_equal(M, H)) return gerepilecopy(av0, L); } } pari_err_BUG("rnfkummer [get_prlist]"); return NULL; } /*Lprz list of prime ideals in Kz that must split completely in Lz/Kz, vecWA * generators for the S-units used to build the Kummer generators. Return * matsmall M such that \prod WA[j]^x[j] ell-th power mod pr[i] iff * \sum M[i,j] x[j] = 0 (mod ell) */ static GEN subgroup_info(GEN bnfz, GEN Lprz, long ell, GEN vecWA) { GEN nfz = bnf_get_nf(bnfz), M, gell = utoipos(ell), Lell = mkvec(gell); long i, j, l = lg(vecWA), lz = lg(Lprz); M = cgetg(l, t_MAT); for (j=1; jm, T->tau), 0); long i, l = lg(P); for (i=2; i Cl_m(K), lift subgroup from bnr to bnrz using Algo 4.1.11 */ static GEN invimsubgroup(GEN bnrz, GEN bnr, GEN subgroup, toK_s *T) { long l, j; GEN P, cyc, gen, U, polrel, StZk; GEN nf = bnr_get_nf(bnr), nfz = bnr_get_nf(bnrz); GEN polz = nf_get_pol(nfz), zkzD = nf_get_zkprimpart(nfz); polrel = polrelKzK(T, pol_x(varn(polz))); StZk = Stelt(nf, zkzD, polrel); cyc = bnr_get_cyc(bnrz); l = lg(cyc); gen = bnr_get_gen(bnrz); P = cgetg(l,t_MAT); for (j=1; j= varn(x) */ static GEN split_pol(GEN x, long v, long a, long b) { long i, l = degpol(x); GEN y = x + a, z; if (l < b) b = l; if (a > b || varn(x) != v) return pol_0(v); l = b-a + 3; z = cgetg(l, t_POL); z[1] = x[1]; for (i = 2; i < l; i++) gel(z,i) = gel(y,i); return normalizepol_lg(z, l); } /* return (den_a * z) mod (v^ell - num_a/den_a), assuming deg(z) < 2*ell * allow either num/den to be NULL (= 1) */ static GEN mod_Xell_a(GEN z, long v, long ell, GEN num_a, GEN den_a) { GEN z1 = split_pol(z, v, ell, degpol(z)); GEN z0 = split_pol(z, v, 0, ell-1); /* z = v^ell z1 + z0*/ if (den_a) z0 = gmul(den_a, z0); if (num_a) z1 = gmul(num_a, z1); return gadd(z0, z1); } static GEN to_alg(GEN nfz, GEN c, long v) { GEN z, D; if (typ(c) != t_COL) return c; z = gmul(nf_get_zkprimpart(nfz), c); if (typ(z) == t_POL) setvarn(z, v); D = nf_get_zkden(nfz); if (!equali1(D)) z = RgX_Rg_div(z, D); return z; } /* th. 5.3.5. and prop. 5.3.9. */ static GEN compute_polrel(GEN nfz, toK_s *T, GEN be, long g, long ell) { long i, k, m = T->m, vT = fetch_var(), vz = fetch_var(); GEN r, powtaubet, S, p1, root, num_t, den_t, nfzpol, powtau_prim_invbe; GEN prim_Rk, C_Rk, prim_root, C_root, prim_invbe, C_invbe; pari_timer ti; r = cgetg(m+1,t_VECSMALL); /* r[i+1] = g^i mod ell */ r[1] = 1; for (i=2; i<=m; i++) r[i] = (r[i-1] * g) % ell; powtaubet = powtau(be, m, T->tau); if (DEBUGLEVEL>1) { err_printf("Computing Newton sums: "); timer_start(&ti); } prim_invbe = Q_primitive_part(nfinv(nfz, be), &C_invbe); powtau_prim_invbe = powtau(prim_invbe, m, T->tau); root = cgetg(ell + 2, t_POL); root[1] = evalsigne(1) | evalvarn(0); for (i = 0; i < ell; i++) gel(root,2+i) = gen_0; for (i = 0; i < m; i++) { /* compute (1/be) ^ (-mu) instead of be^mu [mu << 0]. * 1/be = C_invbe * prim_invbe */ GEN mmu = get_mmu(i, r, ell); /* p1 = prim_invbe ^ -mu */ p1 = to_alg(nfz, nffactorback(nfz, powtau_prim_invbe, mmu), vz); if (C_invbe) p1 = gmul(p1, powgi(C_invbe, RgV_sumpart(mmu, m))); /* root += zeta_ell^{r_i} T^{r_i} be^mu_i */ gel(root, 2 + r[i+1]) = monomial(p1, r[i+1], vT); } /* Other roots are as above with z_ell --> z_ell^j. * Treat all contents (C_*) and principal parts (prim_*) separately */ prim_Rk = prim_root = Q_primitive_part(root, &C_root); C_Rk = C_root; r = vecsmall_reverse(r); /* theta^ell = be^( sum tau^a r_{d-1-a} ) */ /* Compute modulo X^ell - 1, T^ell - t, nfzpol(vz) */ p1 = to_alg(nfz, nffactorback(nfz, powtaubet, r), vz); num_t = Q_remove_denom(p1, &den_t); nfzpol = leafcopy(nf_get_pol(nfz)); setvarn(nfzpol, vz); S = cgetg(ell+1, t_VEC); /* Newton sums */ gel(S,1) = gen_0; for (k = 2; k <= ell; k++) { /* compute the k-th Newton sum */ pari_sp av = avma; GEN z, D, Rk = gmul(prim_Rk, prim_root); C_Rk = mul_content(C_Rk, C_root); Rk = mod_Xell_a(Rk, 0, ell, NULL, NULL); /* mod X^ell - 1 */ for (i = 2; i < lg(Rk); i++) { if (typ(gel(Rk,i)) != t_POL) continue; z = mod_Xell_a(gel(Rk,i), vT, ell, num_t,den_t); /* mod T^ell - t */ gel(Rk,i) = RgXQX_red(z, nfzpol); /* mod nfz.pol */ } if (den_t) C_Rk = mul_content(C_Rk, ginv(den_t)); prim_Rk = Q_primitive_part(Rk, &D); C_Rk = mul_content(C_Rk, D); /* root^k = prim_Rk * C_Rk */ /* Newton sum is ell * constant coeff (in X), which has degree 0 in T */ z = polcoef_i(prim_Rk, 0, 0); z = polcoef_i(z , 0,vT); z = downtoK(T, gmulgs(z, ell)); if (C_Rk) z = gmul(z, C_Rk); gerepileall(av, C_Rk? 3: 2, &z, &prim_Rk, &C_Rk); if (DEBUGLEVEL>1) { err_printf("%ld(%ld) ", k, timer_delay(&ti)); err_flush(); } gel(S,k) = z; } if (DEBUGLEVEL>1) err_printf("\n"); (void)delete_var(); (void)delete_var(); return pol_from_Newton(S); } /* lift elt t in nf to nfz, algebraic form */ static GEN lifttoKz(GEN nf, GEN t, compo_s *C) { GEN x = nf_to_scalar_or_alg(nf, t); if (typ(x) != t_POL) return x; return RgX_RgXQ_eval(x, C->p, C->R); } /* lift ideal id in nf to nfz */ static GEN ideallifttoKz(GEN nfz, GEN nf, GEN id, compo_s *C) { GEN I = idealtwoelt(nf,id); GEN x = nf_to_scalar_or_alg(nf, gel(I,2)); if (typ(x) != t_POL) return gel(I,1); gel(I,2) = algtobasis(nfz, RgX_RgXQ_eval(x, C->p, C->R)); return idealhnf_two(nfz,I); } /* lift ideal pr in nf to ONE prime in nfz (the others are conjugate under tau * and bring no further information on e_1 W). Assume pr coprime to * index of both nf and nfz, and unramified in Kz/K (minor simplification) */ static GEN prlifttoKz(GEN nfz, GEN nf, GEN pr, compo_s *C) { GEN F, p = pr_get_p(pr), t = pr_get_gen(pr), T = nf_get_pol(nfz); if (nf_get_degree(nf) != 1) { /* restrict to primes above pr */ t = Q_primpart( lifttoKz(nf,t,C) ); T = FpX_gcd(FpX_red(T,p), FpX_red(t,p), p); T = FpX_normalize(T, p); } F = FpX_factor(T, p); return idealprimedec_kummer(nfz,gcoeff(F,1,1), pr_get_e(pr), p); } static GEN get_przlist(GEN L, GEN nfz, GEN nf, compo_s *C) { long i, l; GEN M = cgetg_copy(L, &l); for (i = 1; i < l; i++) gel(M,i) = prlifttoKz(nfz, nf, gel(L,i), C); return M; } static void compositum_red(compo_s *C, GEN P, GEN Q) { GEN p, q, a, z = gel(compositum2(P, Q),1); a = gel(z,1); p = gel(gel(z,2), 2); q = gel(gel(z,3), 2); C->k = itos( gel(z,4) ); /* reduce R. FIXME: should be polredbest(a, 1), but breaks rnfkummer bench */ z = polredabs0(a, nf_ORIG|nf_PARTIALFACT); C->R = gel(z,1); a = gel(gel(z,2), 2); C->p = RgX_RgXQ_eval(p, a, C->R); C->q = RgX_RgXQ_eval(q, a, C->R); C->rev = QXQ_reverse(a, C->R); if (DEBUGLEVEL>1) err_printf("polred(compositum) = %Ps\n",C->R); } /* replace P->C^(-deg P) P(xC) for the largest integer C such that coefficients * remain algebraic integers. Lift *rational* coefficients */ static void nfX_Z_normalize(GEN nf, GEN P) { long i, l; GEN C, Cj, PZ = cgetg_copy(P, &l); PZ[1] = P[1]; for (i = 2; i < l; i++) /* minor variation on RgX_to_nfX (create PZ) */ { GEN z = nf_to_scalar_or_basis(nf, gel(P,i)); if (typ(z) == t_INT) gel(PZ,i) = gel(P,i) = z; else gel(PZ,i) = ZV_content(z); } (void)ZX_Z_normalize(PZ, &C); if (C == gen_1) return; Cj = C; for (i = l-2; i > 1; i--) { if (i != l-2) Cj = mulii(Cj, C); gel(P,i) = gdiv(gel(P,i), Cj); } } static GEN _rnfkummer_step4(GEN bnfz, GEN gen, GEN cycgen, GEN u, ulong ell, long rc, long d, long m, long g, tau_s *tau) { long i, j; GEN vecB, vecC, Tc, Q; vecB=cgetg(rc+1,t_VEC); Tc=cgetg(rc+1,t_MAT); for (j=1; j<=rc; j++) { GEN p1 = tauofideal(gel(gen,j), tau); p1 = isprincipalell(bnfz, p1, cycgen,u,ell,rc); gel(Tc,j) = gel(p1,1); gel(vecB,j)= gel(p1,2); } if (!rc) vecC = cgetg(1,t_VEC); else { GEN p1, p2; vecC = const_vec(rc, trivial_fact()); p1 = Flm_powers(Tc, m-2, ell); p2 = vecB; for (j=1; j<=m-1; j++) { GEN z = Flm_Fl_mul(gel(p1,m-j), Fl_mul(j,d,ell), ell); p2 = tauofvec(p2, tau); for (i=1; i<=rc; i++) gel(vecC,i) = famat_mul_shallow(gel(vecC,i), famat_factorbacks(p2, gel(z,i))); } for (i=1; i<=rc; i++) gel(vecC,i) = famat_reduce(gel(vecC,i)); } Q = Flm_ker(Flm_Fl_add(Flm_transpose(Tc), Fl_neg(g, ell), ell), ell); return mkvec2(vecC, Q); } static GEN _rnfkummer_step5(GEN bnfz, GEN vselmer, GEN cycgen, GEN gell, long rc, long rv, long g, tau_s *tau) { GEN Tv, P, vecW; long j, lW; ulong ell = itou(gell); GEN cyc = bnf_get_cyc(bnfz); Tv = cgetg(rv+1,t_MAT); for (j=1; j<=rv; j++) { GEN p1 = tauofelt(gel(vselmer,j), tau); if (typ(p1) == t_MAT) /* famat */ p1 = nffactorback(bnfz, gel(p1,1), FpC_red(gel(p1,2),gell)); gel(Tv,j) = ZV_to_Flv(isvirtualunit(bnfz, p1, cycgen,cyc,gell,rc), ell); } P = Flm_ker(Flm_Fl_add(Tv, Fl_neg(g, ell), ell), ell); lW = lg(P); vecW = cgetg(lW,t_VEC); for (j=1; j2) err_printf("Step 18\n"); dK = lg(K)-1; y = cgetg(dK+1,t_VECSMALL); if (all) res = cgetg(1, t_VEC); if (all < 0) { ncyc = dK; rk = 0; mat = zero_Flm(lg(M)-1, ncyc); } do { dK = lg(K)-1; while (dK) { for (i=1; i1) err_printf("polrel(beta) = %Ps\n", P); if (!all) { H = rnfnormgroup(bnr, P); if (ZM_equal(subgroup, H)) return P; /* DONE */ avma = av; continue; } else { GEN P0 = Q_primpart(lift_shallow(P)); GEN g = nfgcd(P0, RgX_deriv(P0), polnf, nf_get_index(nf)); if (degpol(g)) continue; H = rnfnormgroup(bnr, P); if (!ZM_equal(subgroup,H) && !bnrisconductor(bnr,H)) continue; } P = gerepilecopy(av, P); res = shallowconcat(res, P); if (all < 0 && rk == ncyc) return res; if (firstpass) break; } } while (increment(y, dK, ell)); y[dK--] = 0; } } while (firstpass--); return res; } static GEN _rnfkummer(GEN bnr, GEN subgroup, long all, long prec) { long i, j, m, d, dc, rc, ru, rv, mginv, degK, degKz, vnf; long lSp, lSml2, lSl2, lW; ulong g, ell; GEN polnf,bnf,nf,bnfz,nfz,bid,ideal,cycgen,gell,p1,vselmer; GEN cyc, gen, step4; GEN Q,idealz,gothf; GEN res=NULL,u,M,vecMsup,vecW,vecWA,vecWB,vecC,vecAp,vecBp; GEN matP, Sp, listprSp; primlist L; toK_s T; tau_s tau; compo_s COMPO; pari_timer t; if (DEBUGLEVEL) timer_start(&t); checkbnr(bnr); bnf = bnr_get_bnf(bnr); nf = bnf_get_nf(bnf); polnf = nf_get_pol(nf); vnf = varn(polnf); if (!vnf) pari_err_PRIORITY("rnfkummer", polnf, "=", 0); /* step 7 */ p1 = bnrconductor_i(bnr, subgroup, 2); if (DEBUGLEVEL) timer_printf(&t, "[rnfkummer] conductor"); bnr = gel(p1,2); subgroup = gel(p1,3); gell = get_gell(bnr,subgroup,all); ell = itou(gell); if (ell == 1) return pol_x(0); if (!uisprime(ell)) pari_err_IMPL("kummer for composite relative degree"); if (all && all != -1 && umodiu(bnr_get_no(bnr), ell)) return cgetg(1, t_VEC); if (bnf_get_tuN(bnf) % ell == 0) return rnfkummersimple(bnr, subgroup, gell, all); if (all == -1) all = 0; bid = bnr_get_bid(bnr); ideal = bid_get_ideal(bid); /* step 1 of alg 5.3.5. */ if (DEBUGLEVEL>2) err_printf("Step 1\n"); compositum_red(&COMPO, polnf, polcyclo(ell,vnf)); /* step 2 */ if (DEBUGLEVEL>2) err_printf("Step 2\n"); if (DEBUGLEVEL) timer_printf(&t, "[rnfkummer] compositum"); degK = degpol(polnf); degKz = degpol(COMPO.R); m = degKz / degK; d = (ell-1) / m; g = Fl_powu(pgener_Fl(ell), d, ell); if (Fl_powu(g, m, ell*ell) == 1) g += ell; /* ord(g) = m in all (Z/ell^k)^* */ /* step 3 */ if (DEBUGLEVEL>2) err_printf("Step 3\n"); /* could factor disc(R) using th. 2.1.6. */ bnfz = Buchall(COMPO.R, nf_FORCE, maxss(prec,BIGDEFAULTPREC)); if (DEBUGLEVEL) timer_printf(&t, "[rnfkummer] bnfinit(Kz)"); cycgen = bnf_build_cycgen(bnfz); nfz = bnf_get_nf(bnfz); cyc = bnf_get_cyc(bnfz); rc = prank(cyc,ell); gen = bnf_get_gen(bnfz); u = get_u(ZV_to_Flv(cyc, ell), rc, ell); vselmer = get_Selmer(bnfz, cycgen, rc); if (DEBUGLEVEL) timer_printf(&t, "[rnfkummer] Selmer group"); ru = (degKz>>1)-1; rv = rc+ru+1; get_tau(&tau, nfz, &COMPO, g); /* step 4 */ if (DEBUGLEVEL>2) err_printf("Step 4\n"); step4 = _rnfkummer_step4(bnfz, gen, cycgen, u, ell, rc, d, m, g, &tau); vecC = gel(step4,1); Q = gel(step4,2); /* step 5 */ if (DEBUGLEVEL>2) err_printf("Step 5\n"); vecW = _rnfkummer_step5(bnfz, vselmer, cycgen, gell, rc, rv, g, &tau); lW = lg(vecW); /* step 8 */ if (DEBUGLEVEL>2) err_printf("Step 8\n"); p1 = RgXQ_matrix_pow(COMPO.p, degKz, degK, COMPO.R); T.invexpoteta1 = RgM_inv(p1); /* left inverse */ T.polnf = polnf; T.tau = τ T.m = m; T.powg = Fl_powers(g, m, ell); idealz = ideallifttoKz(nfz, nf, ideal, &COMPO); if (umodiu(gcoeff(ideal,1,1), ell)) gothf = idealz; else { /* ell | N(ideal) */ GEN bnrz = Buchray(bnfz, idealz, nf_INIT|nf_GEN); GEN subgroupz = invimsubgroup(bnrz, bnr, subgroup, &T); gothf = bnrconductor_i(bnrz,subgroupz,0); } /* step 9, 10, 11 */ if (DEBUGLEVEL>2) err_printf("Step 9, 10 and 11\n"); i = build_list_Hecke(&L, nfz, NULL, gothf, gell, &tau); if (i) return no_sol(all,i); lSml2 = lg(L.Sml2); Sp = shallowconcat(L.Sm, L.Sml1); lSp = lg(Sp); listprSp = shallowconcat(L.Sml2, L.Sl); lSl2 = lg(listprSp); /* step 12 */ if (DEBUGLEVEL>2) err_printf("Step 12\n"); vecAp = cgetg(lSp, t_VEC); vecBp = cgetg(lSp, t_VEC); matP = cgetg(lSp, t_MAT); for (j = 1; j < lSp; j++) { GEN e, a; p1 = isprincipalell(bnfz, gel(Sp,j), cycgen,u,ell,rc); e = gel(p1,1); gel(matP,j) = gel(p1, 1); a = gel(p1,2); gel(vecBp,j) = famat_mul_shallow(famat_factorbacks(vecC, zv_neg(e)), a); } vecAp = lambdaofvec(vecBp, &T); /* step 13 */ if (DEBUGLEVEL>2) err_printf("Step 13\n"); vecWA = shallowconcat(vecW, vecAp); vecWB = shallowconcat(vecW, vecBp); /* step 14, 15, and 17 */ if (DEBUGLEVEL>2) err_printf("Step 14, 15 and 17\n"); mginv = Fl_div(m, g, ell); vecMsup = cgetg(lSml2,t_VEC); M = NULL; for (i = 1; i < lSl2; i++) { GEN pr = gel(listprSp,i); long e = pr_get_e(pr), z = ell * (e / (ell-1)); if (i < lSml2) { z += 1 - L.ESml2[i]; gel(vecMsup,i) = logall(nfz, vecWA,lW,mginv,ell, pr,z+1); } M = vconcat(M, logall(nfz, vecWA,lW,mginv,ell, pr,z)); } dc = lg(Q)-1; if (dc) { GEN QtP = Flm_mul(Flm_transpose(Q), matP, ell); M = vconcat(M, shallowconcat(zero_Flm(dc,lW-1), QtP)); } if (!M) M = zero_Flm(1, lSp-1 + lW-1); if (!all) { /* primes landing in subgroup must be totally split */ GEN lambdaWB = shallowconcat(lambdaofvec(vecW, &T), vecAp);/*vecWB^lambda*/ GEN Lpr = get_prlist(bnr, subgroup, ell, bnfz); GEN Lprz= get_przlist(Lpr, nfz, nf, &COMPO); GEN M2 = subgroup_info(bnfz, Lprz, ell, lambdaWB); M = vconcat(M, M2); } if (DEBUGLEVEL>2) err_printf("Step 16\n"); /* step 16 && 18 & ff */ res = _rnfkummer_step18(&T,bnr,subgroup,bnfz, M, vecWB, vecMsup, g, gell, lW, all); return res? res: gen_0; } GEN rnfkummer(GEN bnr, GEN subgroup, long all, long prec) { pari_sp av = avma; return gerepilecopy(av, _rnfkummer(bnr, subgroup, all, prec)); } pari-2.11.2/src/basemath/qfsolve.c0000644000175000017500000010003413326135265015360 0ustar billbill/* Copyright (C) 2000-2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Copyright (C) 2014 Denis Simon * Adapted from qfsolve.gp v. 09/01/2014 * http://www.math.unicaen.fr/~simon/qfsolve.gp * * Author: Denis SIMON */ #include "pari.h" #include "paripriv.h" /* LINEAR ALGEBRA */ /* complete by 0s, assume l-1 <= n */ static GEN vecextend(GEN v, long n) { long i, l = lg(v); GEN w = cgetg(n+1, t_COL); for (i = 1; i < l; i++) gel(w,i) = gel(v,i); for ( ; i <=n; i++) gel(w,i) = gen_0; return w; } /* Gives a unimodular matrix with the last column(s) equal to Mv. * Mv can be a column vector or a rectangular matrix. * redflag = 0 or 1. If redflag = 1, LLL-reduce the n-#v first columns. */ static GEN completebasis(GEN Mv, long redflag) { GEN U; long m, n; if (typ(Mv) == t_COL) Mv = mkmat(Mv); n = lg(Mv)-1; m = nbrows(Mv); /* m x n */ if (m == n) return Mv; (void)ZM_hnfall_i(shallowtrans(Mv), &U, 0); U = ZM_inv(shallowtrans(U),NULL); if (m==1 || !redflag) return U; /* LLL-reduce the m-n first columns */ return shallowconcat(ZM_lll(vecslice(U,1,m-n), 0.99, LLL_INPLACE), vecslice(U, m-n+1,m)); } /* Compute the kernel of M mod p. * returns [d,U], where * d = dim (ker M mod p) * U in GLn(Z), and its first d columns span the kernel. */ static GEN kermodp(GEN M, GEN p, long *d) { long j, l; GEN K, B, U; K = FpM_center(FpM_ker(M, p), p, shifti(p,-1)); B = completebasis(K,0); l = lg(M); U = cgetg(l, t_MAT); for (j = 1; j < l; j++) gel(U,j) = gel(B,l-j); *d = lg(K)-1; return U; } /* INVARIANTS COMPUTATIONS */ static GEN principal_minor(GEN G, long i) { return matslice(G,1,i,1,i); } static GEN det_minors(GEN G) { long i, l = lg(G); GEN v = cgetg(l+1, t_VEC); gel(v,1) = gen_1; for (i = 2; i <= l; i++) gel(v,i) = ZM_det(principal_minor(G,i-1)); return v; } /* Given a symmetric matrix G over Z, compute the Witt invariant * of G at the prime p (at real place if p = NULL) * Assume that none of the determinant G[1..i,1..i] is 0. */ static long qflocalinvariant(GEN G, GEN p) { long i, j, c, l = lg(G); GEN diag, v = det_minors(G); /* Diagonalize G first. */ diag = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(diag,i) = mulii(gel(v,i+1), gel(v,i)); /* Then compute the product of the Hilbert symbols */ /* (diag[i],diag[j])_p for i < j */ c = 1; for (i = 1; i < l-1; i++) for (j = i+1; j < l; j++) if (hilbertii(gel(diag,i), gel(diag,j), p) < 0) c = -c; return c; } static GEN hilberts(GEN a, GEN b, GEN P, long lP) { GEN v = cgetg(lP, t_VECSMALL); long i; for (i = 1; i < lP; i++) v[i] = hilbertii(a, b, gel(P,i)) < 0; return v; } /* G symmetrix matrix or qfb or list of quadratic forms with same discriminant. * P must be equal to factor(-abs(2*matdet(G)))[,1]. */ static GEN qflocalinvariants(GEN G, GEN P) { GEN sol; long i, j, l, lP = lg(P); /* convert G into a vector of symmetric matrices */ G = (typ(G) == t_VEC)? shallowcopy(G): mkvec(G); l = lg(G); for (j = 1; j < l; j++) { GEN g = gel(G,j); if (typ(g) == t_QFI || typ(g) == t_QFR) gel(G,j) = gtomat(g); } sol = cgetg(l, t_MAT); if (lg(gel(G,1)) == 3) { /* in dimension 2, each invariant is a single Hilbert symbol. */ GEN d = negi(ZM_det(gel(G,1))); for (j = 1; j < l; j++) { GEN a = gcoeff(gel(G,j),1,1); gel(sol,j) = hilberts(a, d, P, lP); } } else /* in dimension n > 2, we compute a product of n Hilbert symbols. */ for (j = 1; j = 1; k--) if (hilbertii(negi(gel(v,k)), gel(v,k+1),p) < 0) h = -h; w[i] = h < 0; } } return sol; } /* QUADRATIC FORM REDUCTION */ static GEN qfb(GEN D, GEN a, GEN b, GEN c) { if (signe(D) < 0) return mkqfi(a,b,c); retmkqfr(a,b,c,real_0(DEFAULTPREC)); } /* Gauss reduction of the binary quadratic form * Q = a*X^2+2*b*X*Y+c*Y^2 of discriminant D (divisible by 4) * returns the reduced form */ static GEN qfbreduce(GEN D, GEN Q) { GEN a = gel(Q,1), b = shifti(gel(Q,2),-1), c = gel(Q,3); while (signe(a)) { GEN r, q, nexta, nextc; q = dvmdii(b,a, &r); /* FIXME: export as dvmdiiround ? */ if (signe(r) > 0 && abscmpii(shifti(r,1), a) > 0) { r = subii(r, absi_shallow(a)); q = addis(q, signe(a)); } nextc = a; nexta = subii(c, mulii(q, addii(r,b))); if (abscmpii(nexta, a) >= 0) break; c = nextc; b = negi(r); a = nexta; } return qfb(D,a,shifti(b,1),c); } /* private version of qfgaussred: * - early abort if k-th principal minor is singular, return stoi(k) * - else return a matrix whose upper triangular part is qfgaussred(a) */ static GEN partialgaussred(GEN a) { long n = lg(a)-1, k; a = RgM_shallowcopy(a); for(k = 1; k < n; k++) { GEN ak, p = gcoeff(a,k,k); long i, j; if (isintzero(p)) return stoi(k); ak = row(a, k); for (i=k+1; i<=n; i++) gcoeff(a,k,i) = gdiv(gcoeff(a,k,i), p); for (i=k+1; i<=n; i++) { GEN c = gel(ak,i); if (gequal0(c)) continue; for (j=i; j<=n; j++) gcoeff(a,i,j) = gsub(gcoeff(a,i,j), gmul(c,gcoeff(a,k,j))); } } if (isintzero(gcoeff(a,n,n))) return stoi(n); return a; } /* LLL-reduce a positive definite qf QD bounding the indefinite G, dim G > 1. * Then finishes by looking for trivial solution */ static GEN qftriv(GEN G, GEN z, long base); static GEN qflllgram_indef(GEN G, long base, int *fail) { GEN M, R, g, DM, S, dR; long i, j, n = lg(G)-1; *fail = 0; R = partialgaussred(G); if (typ(R) == t_INT) return qftriv(G, R, base); R = Q_remove_denom(R, &dR); /* avoid rational arithmetic */ M = zeromatcopy(n,n); DM = zeromatcopy(n,n); for (i = 1; i <= n; i++) { GEN d = absi_shallow(gcoeff(R,i,i)); if (dR) { gcoeff(M,i,i) = dR; gcoeff(DM,i,i) = mulii(d,dR); } else { gcoeff(M,i,i) = gen_1; gcoeff(DM,i,i) = d; } for (j = i+1; j <= n; j++) { gcoeff(M,i,j) = gcoeff(R,i,j); gcoeff(DM,i,j) = mulii(d, gcoeff(R,i,j)); } } /* G = M~*D*M, D diagonal, DM=|D|*M, g = M~*|D|*M */ g = ZM_transmultosym(M,DM); S = lllgramint(Q_primpart(g)); R = qftriv(qf_apply_ZM(G,S), NULL, base); switch(typ(R)) { case t_COL: return ZM_ZC_mul(S,R); case t_MAT: *fail = 1; return mkvec2(R, S); default: gel(R,2) = ZM_mul(S, gel(R,2)); return R; } } /* G symmetric, i < j, let E = E_{i,j}(a), G <- E~*G*E, U <- U*E. * Everybody integral */ static void qf_apply_transvect_Z(GEN G, GEN U, long i, long j, GEN a) { long k, n = lg(G)-1; gel(G, j) = ZC_lincomb(gen_1, a, gel(G,j), gel(G,i)); for (k = 1; k < n; k++) gcoeff(G, j, k) = gcoeff(G, k, j); gcoeff(G,j,j) = addmulii(gcoeff(G,j,j), a, addmulii(gcoeff(G,i,j), a,gcoeff(G,i,i))); gel(U, j) = ZC_lincomb(gen_1, a, gel(U,j), gel(U,i)); } /* LLL reduction of the quadratic form G (Gram matrix) * where we go on, even if an isotropic vector is found. */ static GEN qflllgram_indefgoon(GEN G) { GEN red, U, A, U1,U2,U3,U5,U6, V, B, G2,G3,G4,G5, G6, a, g; long i, j, n = lg(G)-1; int fail; red = qflllgram_indef(G,1, &fail); if (fail) return red; /*no isotropic vector found: nothing to do*/ /* otherwise a solution is found: */ U1 = gel(red,2); G2 = gel(red,1); /* G2[1,1] = 0 */ U2 = gel(ZV_extgcd(row(G2,1)), 2); G3 = qf_apply_ZM(G2,U2); U = ZM_mul(U1,U2); /* qf_apply(G,U) = G3 */ /* G3[1,] = [0,...,0,g], g^2 | det G */ g = gcoeff(G3,1,n); a = diviiround(negi(gcoeff(G3,n,n)), shifti(g,1)); if (signe(a)) qf_apply_transvect_Z(G3,U,1,n,a); /* G3[n,n] reduced mod 2g */ if (n == 2) return mkvec2(G3,U); V = rowpermute(vecslice(G3, 2,n-1), mkvecsmall2(1,n)); A = mkmat2(mkcol2(gcoeff(G3,1,1),gcoeff(G3,1,n)), mkcol2(gcoeff(G3,1,n),gcoeff(G3,2,2))); B = ground(RgM_neg(RgM_mul(RgM_inv(A), V))); U3 = matid(n); for (j = 2; j < n; j++) { gcoeff(U3,1,j) = gcoeff(B,1,j-1); gcoeff(U3,n,j) = gcoeff(B,2,j-1); } G4 = qf_apply_ZM(G3,U3); /* the last column of G4 is reduced */ U = ZM_mul(U,U3); if (n == 3) return mkvec2(G4,U); red = qflllgram_indefgoon(matslice(G4,2,n-1,2,n-1)); if (typ(red) == t_MAT) return mkvec2(G4,U); /* Let U5:=matconcat(diagonal[1,red[2],1]) * return [qf_apply_ZM(G5, U5), U*U5] */ G5 = gel(red,1); U5 = gel(red,2); G6 = cgetg(n+1,t_MAT); gel(G6,1) = gel(G4,1); gel(G6,n) = gel(G4,n); for (j=2; j= 2 * G symmetric integral * Returns [G',U,factd] with U in GLn(Q) such that G'=U~*G*U*constant * is integral and has minimal determinant. * In dimension 3 or 4, may return a prime p if the reduction at p is * impossible because of local non-solvability. * P,E = factor(+/- det(G)), "prime" -1 is ignored. Destroy E. */ static GEN qfsolvemodp(GEN G, GEN p); static GEN qfminimize(GEN G, GEN P, GEN E) { GEN d, U, Ker, sol, aux, faE, faP; long n = lg(G)-1, lP = lg(P), i, dimKer, m; faP = vectrunc_init(lP); faE = vecsmalltrunc_init(lP); U = NULL; for (i = 1; i < lP; i++) { GEN p = gel(P,i); long vp = E[i]; if (!vp || !p) continue; if (DEBUGLEVEL >= 4) err_printf(" p^v = %Ps^%ld\n", p,vp); /* The case vp = 1 can be minimized only if n is odd. */ if (vp == 1 && n%2 == 0) { vectrunc_append(faP, p); vecsmalltrunc_append(faE, 1); continue; } Ker = kermodp(G,p, &dimKer); /* dimKer <= vp */ if (DEBUGLEVEL >= 4) err_printf(" dimKer = %ld\n",dimKer); if (dimKer == n) { /* trivial case: dimKer = n */ if (DEBUGLEVEL >= 4) err_printf(" case 0: dimKer = n\n"); G = ZsymM_Z_divexact(G, p); E[i] -= n; i--; continue; /* same p */ } G = qf_apply_ZM(G, Ker); U = U? RgM_mul(U,Ker): Ker; /* 1st case: dimKer < vp */ /* then the kernel mod p contains a kernel mod p^2 */ if (dimKer < vp) { if (DEBUGLEVEL >= 4) err_printf(" case 1: dimker < vp\n"); if (dimKer == 1) { long j; gel(G,1) = ZC_Z_divexact(gel(G,1), p); for (j = 1; j<=n; j++) gcoeff(G,1,j) = diviiexact(gcoeff(G,1,j), p); gel(U,1) = RgC_Rg_div(gel(U,1), p); E[i] -= 2; } else { GEN A,B,C, K2 = ZsymM_Z_divexact(principal_minor(G,dimKer),p); long j, dimKer2; K2 = kermodp(K2, p, &dimKer2); for (j = dimKer2+1; j <= dimKer; j++) gel(K2,j) = ZC_Z_mul(gel(K2,j),p); /* Write G = [A,B;B~,C] and apply [K2,0;0,p*Id]/p by blocks */ blocks4(G, dimKer,n, &A,&B,&C); A = ZsymM_Z_divexact(qf_apply_ZM(A,K2), sqri(p)); B = ZM_Z_divexact(ZM_transmul(B,K2), p); G = shallowmatconcat(mkmat2(mkcol2(A,B), mkcol2(shallowtrans(B), C))); /* U *= [K2,0;0,Id] */ U = shallowconcat(RgM_Rg_div(RgM_mul(vecslice(U,1,dimKer),K2), p), vecslice(U,dimKer+1,n)); E[i] -= 2*dimKer2; } i--; continue; /* same p */ } /* vp = dimKer * 2nd case: kernel has dim >= 2 and contains an element of norm 0 mod p^2 * search for an element of norm p^2... in the kernel */ sol = NULL; if (dimKer > 2) { if (DEBUGLEVEL >= 4) err_printf(" case 2.1\n"); dimKer = 3; sol = qfsolvemodp(ZsymM_Z_divexact(principal_minor(G,3),p), p); sol = FpC_red(sol, p); } else if (dimKer == 2) { GEN a = modii(diviiexact(gcoeff(G,1,1),p), p); GEN b = modii(diviiexact(gcoeff(G,1,2),p), p); GEN c = diviiexact(gcoeff(G,2,2),p); GEN di= modii(subii(sqri(b), mulii(a,c)), p); if (kronecker(di,p) >= 0) { if (DEBUGLEVEL >= 4) err_printf(" case 2.2\n"); sol = signe(a)? mkcol2(Fp_sub(Fp_sqrt(di,p), b, p), a): vec_ei(2,1); } } if (sol) { long j; sol = FpC_center(sol, p, shifti(p,-1)); sol = Q_primpart(sol); if (DEBUGLEVEL >= 4) err_printf(" sol = %Ps\n", sol); Ker = completebasis(vecextend(sol,n), 1); for(j=1; j= 0) || (vp==2 && odd(n) && n >= 5) || (vp==2 && !odd(n) && kronecker(modii(diviiexact(d,sqri(p)), p),p) < 0)) { long j; if (DEBUGLEVEL >= 4) err_printf(" case 3\n"); Ker = matid(n); for (j = dimKer+1; j <= n; j++) gcoeff(Ker,j,j) = p; G = ZsymM_Z_divexact(qf_apply_ZM(G, Ker), p); U = RgM_mul(U,Ker); E[i] -= 2*dimKer-n; i--; continue; /* same p */ } /* Minimization was not possible so far. */ /* If n == 3 or 4, this proves the local non-solubility at p. */ if (n == 3 || n == 4) { if (DEBUGLEVEL >= 1) err_printf(" no local solution at %Ps\n",p); return(p); } vectrunc_append(faP, p); vecsmalltrunc_append(faE, vp); } if (!U) U = matid(n); else { /* apply LLL to avoid coefficient explosion */ aux = lllint(Q_primpart(U)); G = qf_apply_ZM(G,aux); U = RgM_mul(U,aux); } return mkvec4(G, U, faP, faE); } /* CLASS GROUP COMPUTATIONS */ /* Compute the square root of the quadratic form q of discriminant D. Not * fully implemented; it only works for detqfb squarefree except at 2, where * the valuation is 2 or 3. * mkmat2(P,zv_to_ZV(E)) = factor(2*abs(det q)) */ static GEN qfbsqrt(GEN D, GEN q, GEN P, GEN E) { GEN a = gel(q,1), b = shifti(gel(q,2),-1), c = gel(q,3), mb = negi(b); GEN m,n, aux,Q1,M, A,B,C; GEN d = subii(mulii(a,c), sqri(b)); long i; /* 1st step: solve m^2 = a (d), m*n = -b (d), n^2 = c (d) */ m = n = mkintmod(gen_0,gen_1); E[1] -= 3; for (i = 1; i < lg(P); i++) { GEN p = gel(P,i), N, M; if (!E[i]) continue; if (dvdii(a,p)) { aux = Fp_sqrt(c, p); N = aux; M = Fp_div(mb, aux, p); } else { aux = Fp_sqrt(a, p); M = aux; N = Fp_div(mb, aux, p); } n = chinese(n, mkintmod(N,p)); m = chinese(m, mkintmod(M,p)); } m = centerlift(m); n = centerlift(n); if (DEBUGLEVEL >=4) err_printf(" [m,n] = [%Ps, %Ps]\n",m,n); /* 2nd step: build Q1, with det=-1 such that Q1(x,y,0) = G(x,y) */ A = diviiexact(subii(sqri(n),c), d); B = diviiexact(addii(b, mulii(m,n)), d); C = diviiexact(subii(sqri(m), a), d); Q1 = mkmat3(mkcol3(A,B,n), mkcol3(B,C,m), mkcol3(n,m,d)); Q1 = gneg(adj(Q1)); /* 3rd step: reduce Q1 to [0,0,-1;0,1,0;-1,0,0] */ M = qflllgram_indefgoon2(Q1); if (signe(gel(M,1)) < 0) M = ZC_neg(M); a = gel(M,1); b = gel(M,2); c = gel(M,3); if (mpodd(a)) return qfb(D, a, shifti(b,1), shifti(c,1)); else return qfb(D, c, shifti(negi(b),1), shifti(a,1)); } /* \prod gen[i]^e[i] as a Qfb, e in {0,1}^n non-zero */ static GEN qfb_factorback(GEN D, GEN gen, GEN e) { GEN q = NULL; long j, l = lg(gen), n = 0; for (j = 1; j < l; j++) if (e[j]) { n++; q = q? qfbcompraw(q, gel(gen,j)): gel(gen,j); } return (n <= 1)? q: qfbreduce(D, q); } /* unit form, assuming 4 | D */ static GEN id(GEN D) { return mkmat2(mkcol2(gen_1,gen_0),mkcol2(gen_0,shifti(negi(D),-2))); } /* Shanks/Bosma-Stevenhagen algorithm to compute the 2-Sylow of the class * group of discriminant D. Only works for D = fundamental discriminant. * When D = 1(4), work with 4D. * P2D,E2D = factor(abs(2*D)) * Pm2D = factor(-abs(2*D))[,1]. * Return a form having Witt invariants W at Pm2D */ static GEN quadclass2(GEN D, GEN P2D, GEN E2D, GEN Pm2D, GEN W, int n_is_4) { GEN gen, Wgen, U2; long i, n, r, m, vD; if (mpodd(D)) { D = shifti(D,2); E2D = shallowcopy(E2D); E2D[1] = 3; } if (zv_equal0(W)) return id(D); n = lg(Pm2D)-1; /* >= 3 since W != 0 */ r = n-3; m = (signe(D)>0)? r+1: r; /* n=4: look among forms of type q or 2*q, since Q can be imprimitive */ U2 = n_is_4? mkmat(hilberts(gen_2, D, Pm2D, lg(Pm2D))): NULL; if (U2 && zv_equal(gel(U2,1),W)) return gmul2n(id(D),1); gen = cgetg(m+1, t_VEC); for (i = 1; i <= m; i++) /* no need to look at Pm2D[1]=-1, nor Pm2D[2]=2 */ { GEN p = gel(Pm2D,i+2), d; long vp = Z_pvalrem(D,p, &d); gel(gen,i) = qfb(D, powiu(p,vp), gen_0, negi(shifti(d,-2))); } vD = Z_lval(D,2); /* = 2 or 3 */ if (vD == 2 && smodis(D,16) != 4) { GEN q2 = qfb(D, gen_2,gen_2, shifti(subsi(4,D),-3)); m++; r++; gen = shallowconcat(gen, mkvec(q2)); } if (vD == 3) { GEN q2 = qfb(D, gen_2,gen_0, negi(shifti(D,-3))); m++; r++; gen = shallowconcat(gen, mkvec(q2)); } if (!r) return id(D); Wgen = qflocalinvariants(gen,Pm2D); for(;;) { GEN Wgen2, gen2, Ker, indexim = gel(Flm_indexrank(Wgen,2), 2); long dKer; if (lg(indexim)-1 >= r) { GEN W2 = Wgen, V; if (lg(indexim) < lg(Wgen)) W2 = vecpermute(Wgen,indexim); if (U2) W2 = shallowconcat(W2,U2); V = Flm_Flc_invimage(W2, W,2); if (V) { GEN Q = qfb_factorback(D, vecpermute(gen,indexim), V); Q = gtomat(Q); if (U2 && V[lg(V)-1]) Q = gmul2n(Q,1); return Q; } } Ker = Flm_ker(Wgen,2); dKer = lg(Ker)-1; gen2 = cgetg(m+1, t_VEC); Wgen2 = cgetg(m+1, t_MAT); for (i = 1; i <= dKer; i++) { GEN q = qfb_factorback(D, gen, gel(Ker,i)); q = qfbsqrt(D,q,P2D,E2D); gel(gen2,i) = q; gel(Wgen2,i) = gel(qflocalinvariants(q,Pm2D), 1); } for (; i <=m; i++) { long j = indexim[i-dKer]; gel(gen2,i) = gel(gen,j); gel(Wgen2,i) = gel(Wgen,j); } gen = gen2; Wgen = Wgen2; } } /* QUADRATIC EQUATIONS */ /* is x*y = -1 ? */ static int both_pm1(GEN x, GEN y) { return is_pm1(x) && is_pm1(y) && signe(x) == -signe(y); } /* Try to solve G = 0 with small coefficients. This is proved to work if * - det(G) = 1, dim <= 6 and G is LLL reduced * Returns G if no solution is found. * Exit with a norm 0 vector if one such is found. * If base == 1 and norm 0 is obtained, returns [H~*G*H,H] where * the 1st column of H is a norm 0 vector */ static GEN qftriv(GEN G, GEN R, long base) { long n = lg(G)-1, i; GEN s, H; /* case 1: A basis vector is isotropic */ for (i = 1; i <= n; i++) if (!signe(gcoeff(G,i,i))) { if (!base) return col_ei(n,i); H = matid(n); swap(gel(H,1), gel(H,i)); return mkvec2(qf_apply_tau(G,1,i),H); } /* case 2: G has a block +- [1,0;0,-1] on the diagonal */ for (i = 2; i <= n; i++) if (!signe(gcoeff(G,i-1,i)) && both_pm1(gcoeff(G,i-1,i-1),gcoeff(G,i,i))) { s = col_ei(n,i); gel(s,i-1) = gen_m1; if (!base) return s; H = matid(n); gel(H,i) = gel(H,1); gel(H,1) = s; return mkvec2(qf_apply_ZM(G,H),H); } if (!R) return G; /* fail */ /* case 3: a principal minor is 0 */ s = ZM_ker(principal_minor(G, itos(R))); s = vecextend(Q_primpart(gel(s,1)), n); if (!base) return s; H = completebasis(s, 0); gel(H,n) = ZC_neg(gel(H,1)); gel(H,1) = s; return mkvec2(qf_apply_ZM(G,H),H); } /* p a prime number, G 3x3 symmetric. Finds X!=0 such that X^t G X = 0 mod p. * Allow returning a shorter X: to be completed with 0s. */ static GEN qfsolvemodp(GEN G, GEN p) { GEN a,b,c,d,e,f, v1,v2,v3,v4,v5, x1,x2,x3,N1,N2,N3,s,r; /* principal_minor(G,3) = [a,b,d; b,c,e; d,e,f] */ a = modii(gcoeff(G,1,1), p); if (!signe(a)) return mkcol(gen_1); v1 = a; b = modii(gcoeff(G,1,2), p); c = modii(gcoeff(G,2,2), p); v2 = modii(subii(mulii(a,c), sqri(b)), p); if (!signe(v2)) return mkcol2(Fp_neg(b,p), a); d = modii(gcoeff(G,1,3), p); e = modii(gcoeff(G,2,3), p); f = modii(gcoeff(G,3,3), p); v4 = modii(subii(mulii(c,d), mulii(e,b)), p); v5 = modii(subii(mulii(a,e), mulii(d,b)), p); v3 = subii(mulii(v2,f), addii(mulii(v4,d), mulii(v5,e))); /* det(G) */ v3 = modii(v3, p); N1 = Fp_neg(v2, p); x3 = mkcol3(v4, v5, N1); if (!signe(v3)) return x3; /* now, solve in dimension 3... reduction to the diagonal case: */ x1 = mkcol3(gen_1, gen_0, gen_0); x2 = mkcol3(negi(b), a, gen_0); if (kronecker(N1,p) == 1) return ZC_lincomb(Fp_sqrt(N1,p),gen_1,x1,x2); N2 = Fp_div(Fp_neg(v3,p), v1, p); if (kronecker(N2,p) == 1) return ZC_lincomb(Fp_sqrt(N2,p),gen_1,x2,x3); N3 = Fp_mul(v2, N2, p); if (kronecker(N3,p) == 1) return ZC_lincomb(Fp_sqrt(N3,p),gen_1,x1,x3); r = gen_1; for(;;) { s = Fp_sub(gen_1, Fp_mul(N1,Fp_sqr(r,p),p), p); if (kronecker(s, p) <= 0) break; r = randomi(p); } s = Fp_sqrt(Fp_div(s,N3,p), p); return ZC_add(x1, ZC_lincomb(r,s,x2,x3)); } /* assume G square integral */ static void check_symmetric(GEN G) { long i,j, l = lg(G); for (i = 1; i < l; i++) for(j = 1; j < i; j++) if (!equalii(gcoeff(G,i,j), gcoeff(G,j,i))) pari_err_TYPE("qfsolve [not symmetric]",G); } /* Given a square matrix G of dimension n >= 1, */ /* solves over Z the quadratic equation X^tGX = 0. */ /* G is assumed to have integral coprime coefficients. */ /* The solution might be a vectorv or a matrix. */ /* If no solution exists, returns an integer, that can */ /* be a prime p such that there is no local solution at p, */ /* or -1 if there is no real solution, */ /* or 0 in some rare cases. */ static GEN qfsolve_i(GEN G) { GEN M, signG, Min, U, G1, M1, G2, M2, solG2, P, E; GEN solG1, sol, Q, d, dQ, detG2, fam2detG; long n, np, codim, dim; int fail; if (typ(G) != t_MAT) pari_err_TYPE("qfsolve", G); n = lg(G)-1; if (n == 0) pari_err_DOMAIN("qfsolve", "dimension" , "=", gen_0, G); if (n != nbrows(G)) pari_err_DIM("qfsolve"); G = Q_primpart(G); RgM_check_ZM(G, "qfsolve"); check_symmetric(G); /* Trivial case: det = 0 */ d = ZM_det(G); if (!signe(d)) { if (n == 1) return mkcol(gen_1); sol = ZM_ker(G); if (lg(sol) == 2) sol = gel(sol,1); return sol; } /* Small dimension: n <= 2 */ if (n == 1) return gen_m1; if (n == 2) { GEN t, a = gcoeff(G,1,1); if (!signe(a)) return mkcol2(gen_1, gen_0); if (signe(d) > 0) return gen_m1; /* no real solution */ if (!Z_issquareall(negi(d), &t)) return gen_m2; return mkcol2(subii(t,gcoeff(G,1,2)), a); } /* 1st reduction of the coefficients of G */ M = qflllgram_indef(G,0,&fail); if (typ(M) == t_COL) return M; G = gel(M,1); M = gel(M,2); /* real solubility */ signG = ZV_to_zv(qfsign(G)); { long r = signG[1], s = signG[2]; if (!r || !s) return gen_m1; if (r < s) { G = ZM_neg(G); signG = mkvecsmall2(s,r); } } /* factorization of the determinant */ fam2detG = absZ_factor(d); P = gel(fam2detG,1); E = ZV_to_zv(gel(fam2detG,2)); /* P,E = factor(|det(G)|) */ /* Minimization and local solubility */ Min = qfminimize(G, P, E); if (typ(Min) == t_INT) return Min; M = RgM_mul(M, gel(Min,2)); G = gel(Min,1); P = gel(Min,3); E = gel(Min,4); /* P,E = factor(|det(G))| */ /* Now, we know that local solutions exist (except maybe at 2 if n==4) * if n==3, det(G) = +-1 * if n==4, or n is odd, det(G) is squarefree. * if n>=6, det(G) has all its valuations <=2. */ /* Reduction of G and search for trivial solutions. */ /* When |det G|=1, such trivial solutions always exist. */ U = qflllgram_indef(G,0,&fail); if(typ(U) == t_COL) return Q_primpart(RgM_RgC_mul(M,U)); G = gel(U,1); M = RgM_mul(M, gel(U,2)); /* P,E = factor(|det(G))| */ /* If n >= 6 is even, need to increment the dimension by 1 to suppress all * squares from det(G) */ np = lg(P)-1; if (n < 6 || odd(n) || !np) { codim = 0; G1 = G; M1 = NULL; } else { GEN aux; long i; codim = 1; n++; /* largest square divisor of d */ aux = gen_1; for (i = 1; i <= np; i++) if (E[i] == 2) { aux = mulii(aux, gel(P,i)); E[i] = 3; } /* Choose sign(aux) so as to balance the signature of G1 */ if (signG[1] > signG[2]) { signG[2]++; aux = negi(aux); } else signG[1]++; G1 = shallowmatconcat(diagonal_shallow(mkvec2(G,aux))); /* P,E = factor(|det G1|) */ Min = qfminimize(G1, P, E); G1 = gel(Min,1); M1 = gel(Min,2); P = gel(Min,3); E = gel(Min,4); np = lg(P)-1; } /* now, d is squarefree */ if (!np) { /* |d| = 1 */ G2 = G1; M2 = NULL; } else { /* |d| > 1: increment dimension by 2 */ GEN factdP, factdE, W; long i, lfactdP; codim += 2; d = ZV_prod(P); /* d = abs(matdet(G1)); */ if (odd(signG[2])) togglesign_safe(&d); /* d = matdet(G1); */ /* solubility at 2 (this is the only remaining bad prime). */ if (n == 4 && smodis(d,8) == 1 && qflocalinvariant(G,gen_2) == 1) return gen_2; P = shallowconcat(mpodd(d)? mkvec2(NULL,gen_2): mkvec(NULL), P); /* build a binary quadratic form with given Witt invariants */ W = const_vecsmall(lg(P)-1, 0); /* choose signature of Q (real invariant and sign of the discriminant) */ dQ = absi(d); if (signG[1] > signG[2]) togglesign_safe(&dQ); /* signQ = [2,0]; */ if (n == 4 && smodis(dQ,4) != 1) dQ = shifti(dQ,2); if (n >= 5) dQ = shifti(dQ,3); /* p-adic invariants */ if (n == 4) { GEN t = qflocalinvariants(ZM_neg(G1),P); for (i = 3; i < lg(P); i++) W[i] = ucoeff(t,i,1); } else { long s = signe(dQ) == signe(d)? 1: -1; GEN t; if (odd((n-3)/2)) s = -s; t = s > 0? utoipos(8): utoineg(8); for (i = 3; i < lg(P); i++) W[i] = hilbertii(t, gel(P,i), gel(P,i)) > 0; } /* for p = 2, the choice is fixed from the product formula */ W[2] = Flv_sum(W, 2); /* Construction of the 2-class group of discriminant dQ until some product * of the generators gives the desired invariants. */ factdP = vecsplice(P, 1); lfactdP = lg(factdP); factdE = cgetg(lfactdP, t_VECSMALL); for (i = 1; i < lfactdP; i++) factdE[i] = Z_pval(dQ, gel(factdP,i)); factdE[1]++; /* factdP,factdE = factor(2|dQ|), P = factor(-2|dQ|)[,1] */ Q = quadclass2(dQ, factdP,factdE, P, W, n == 4); /* Build a form of dim=n+2 potentially unimodular */ G2 = shallowmatconcat(diagonal_shallow(mkvec2(G1,ZM_neg(Q)))); /* Minimization of G2 */ detG2 = mulii(d, ZM_det(Q)); for (i = 1; i < lfactdP; i++) factdE[i] = Z_pval(detG2, gel(factdP,i)); /* factdP,factdE = factor(|det G2|) */ Min = qfminimize(G2, factdP,factdE); M2 = gel(Min,2); G2 = gel(Min,1); } /* |det(G2)| = 1, find a totally isotropic subspace for G2 */ solG2 = qflllgram_indefgoon(G2); /* G2 must have a subspace of solutions of dimension > codim */ dim = codim+2; while(gequal0(principal_minor(gel(solG2,1), dim))) dim ++; solG2 = vecslice(gel(solG2,2), 1, dim-1); if (!M2) solG1 = solG2; else { /* solution of G1 is simultaneously in solG2 and x[n+1] = x[n+2] = 0*/ GEN K; solG1 = RgM_mul(M2,solG2); K = ker(rowslice(solG1,n+1,n+2)); solG1 = RgM_mul(rowslice(solG1,1,n), K); } if (!M1) sol = solG1; else { /* solution of G1 is simultaneously in solG2 and x[n] = 0 */ GEN K; sol = RgM_mul(M1,solG1); K = ker(rowslice(sol,n,n)); sol = RgM_mul(rowslice(sol,1,n-1), K); } sol = Q_primpart(RgM_mul(M, sol)); if (lg(sol) == 2) sol = gel(sol,1); return sol; } GEN qfsolve(GEN G) { pari_sp av = avma; return gerepilecopy(av, qfsolve_i(G)); } /* G is a symmetric 3x3 matrix, and sol a solution of sol~*G*sol=0. * Returns a parametrization of the solutions with the good invariants, * as a matrix 3x3, where each line contains * the coefficients of each of the 3 quadratic forms. * If fl!=0, the fl-th form is reduced. */ GEN qfparam(GEN G, GEN sol, long fl) { pari_sp av = avma; GEN U, G1, G2, a, b, c, d, e; long n, tx = typ(sol); if (typ(G) != t_MAT) pari_err_TYPE("qfsolve", G); if (!is_vec_t(tx)) pari_err_TYPE("qfsolve", G); if (tx == t_VEC) sol = shallowtrans(sol); n = lg(G)-1; if (n == 0) pari_err_DOMAIN("qfsolve", "dimension" , "=", gen_0, G); if (n != nbrows(G) || n != 3 || lg(sol) != 4) pari_err_DIM("qfsolve"); G = Q_primpart(G); RgM_check_ZM(G,"qfsolve"); check_symmetric(G); sol = Q_primpart(sol); RgV_check_ZV(sol,"qfsolve"); /* build U such that U[,3] = sol, and |det(U)| = 1 */ U = completebasis(sol,1); G1 = qf_apply_ZM(G,U); /* G1 has a 0 at the bottom right corner */ a = shifti(gcoeff(G1,1,2),1); b = shifti(negi(gcoeff(G1,1,3)),1); c = shifti(negi(gcoeff(G1,2,3)),1); d = gcoeff(G1,1,1); e = gcoeff(G1,2,2); G2 = mkmat3(mkcol3(b,gen_0,d), mkcol3(c,b,a), mkcol3(gen_0,c,e)); sol = ZM_mul(U,G2); if (fl) { GEN v = row(sol,fl); int fail; a = gel(v,1); b = gmul2n(gel(v,2),-1); c = gel(v,3); U = qflllgram_indef(mkmat2(mkcol2(a,b),mkcol2(b,c)), 1, &fail); U = gel(U,2); a = gcoeff(U,1,1); b = gcoeff(U,1,2); c = gcoeff(U,2,1); d = gcoeff(U,2,2); U = mkmat3(mkcol3(sqri(a),mulii(a,c),sqri(c)), mkcol3(shifti(mulii(a,b),1), addii(mulii(a,d),mulii(b,c)), shifti(mulii(c,d),1)), mkcol3(sqri(b),mulii(b,d),sqri(d))); sol = ZM_mul(sol,U); } return gerepileupto(av, sol); } pari-2.11.2/src/basemath/qfisom.c0000644000175000017500000015144713326135265015215 0ustar billbill/* Copyright (C) 2012 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "pari.h" #include "paripriv.h" /*To be moved elsewhere */ static long Z_trunc(GEN z) { long s = signe(z); return s==0 ? 0: (long)(s*mod2BIL(z)); } static GEN ZV_trunc_to_zv(GEN z) { long i, l = lg(z); GEN x = cgetg(l, t_VECSMALL); for (i=1; i>1); return gerepileupto(av, C); } static int zv_canon(GEN V) { long l = lg(V), j, k; for (j = 1; j < l && V[j] == 0; ++j); if (j < l && V[j] < 0) { for (k = j; k < l; ++k) V[k] = -V[k]; return -1; } return 1; } static GEN ZM_to_zm_canon(GEN V) { GEN W = ZM_to_zm(V); long i, l = lg(W); for(i=1; i I && Wj[k] == mael3(F,k,J,J); ++k) /* check the scalar products with the basis-vectors */ for (i = 1; i <= I; ++i) if (zv_dotproduct(Vj,gmael(Ftr,k,per[i])) != coeff(gel(F,k),J,per[i])) break; if (k == f+1 && i > I) ++count; /* the same for the negative vector */ i = I+1; for (k = 1; k <= f && i > I && Wj[k] == mael3(F,k,J,J); ++k) for (i = 1; i <= I ; ++i) if (zv_dotproduct(Vj,gmael(Ftr,k,per[i])) != -coeff(gel(F,k),J,per[i])) break; if (k == f+1 && i > I) ++count; } return count; } static void fingerprint(struct fingerprint *fp, struct qfauto *qf) { pari_sp av; GEN V=qf->V, W=qf->W, F=qf->F; GEN Mf; long i, j, k, min; long dim = qf->dim, n = lg(V)-1, f = lg(F)-1; GEN Ftr; fp->per = identity_perm(dim); fp->e = cgetg(dim+1, t_VECSMALL); fp->diag = cgetg(dim+1, t_VECSMALL); av = avma; Ftr = cgetg(f+1,t_VEC); for (i = 1; i <= f; ++i) gel(Ftr,i) = zm_transpose(gel(F,i)); Mf = zero_Flm_copy(dim, dim); /* the first row of the fingerprint has as entry nr. i the number of vectors, which have the same length as the i-th basis-vector with respect to every invariant form */ for (j = 1; j <= n; ++j) { GEN Wj = gel(W,j); for (i = 1; i <= dim; ++i) { for (k = 1; k <= f && Wj[k] == mael3(F,k,i,i); ++k); if (k == f+1) mael(Mf,1,i) += 2; } } for (i = 1; i <= dim-1; ++i) { /* a minimal entry != 0 in the i-th row is chosen */ min = i; for (j = i+1; j <= dim; ++j) { if (mael(Mf,i,fp->per[j]) < mael(Mf,i,fp->per[min])) min = j; } lswap(fp->per[i],fp->per[min]); /* the column below the minimal entry is set to 0 */ for (j = i+1; j <= dim; ++j) mael(Mf,j,fp->per[i]) = 0; /* compute the row i+1 of the fingerprint */ for (j = i+1; j <= dim; ++j) mael(Mf,i+1,fp->per[j]) = possible(F, Ftr, V, W, fp->per, i, fp->per[j]); } /* only the diagonal of f will be needed later */ for (i = 1; i <= dim; ++i) fp->diag[i] = mael(Mf,i,fp->per[i]); for (i = 1; i <= dim; ++i) { fp->e[i] = vecvecsmall_search(V,vecsmall_ei(dim,fp->per[i]),0); if (!fp->e[i]) pari_err_BUG("qfisom, standard basis vector not found"); } avma = av; } /* The Bacher-polynomial for v[I] with scalar product S is * defined as follows: let list be the vectors which have the same length as * v[I] and with scalar product S with v[I], for each vector w in list let n_w * be the number of pairs (y,z) of vectors in list, such that all scalar * products between w,y and z are S, then the Bacher-polynomial is the sum over * the w in list of the monomials X^n_w */ static GEN bacher(long I, long S, struct qfauto *qf) { pari_sp av=avma; GEN V=qf->V, W=qf->W, Fv=gel(qf->v,1); GEN list, listxy, counts, vI; long i, j, k, nlist, nxy; long n = lg(V)-1; long sum, mind, maxd; GEN coef; /* the Bacher-polynomials of v[I] and -v[I] are equal */ I = labs(I); vI = gel(V,I); /* list of vectors that have scalar product S with v[I] */ list = zero_Flv(2*n); nlist = 0; for (i = 1; i <= n; ++i) if (mael(W,i,1) == mael(W,I,1)) { long s = zv_dotproduct(vI, gel(Fv,i)); if (s == S) list[++nlist] = i; if (-s == S) list[++nlist] = -i; } /* there are nlist vectors that have scalar product S with v[I] */ sum = nlist; if (nlist==0) retmkvec2(mkvecsmall3(0,0,0),cgetg(1,t_VEC)); counts = cgetg(nlist+1, t_VECSMALL); listxy = cgetg(nlist+1, t_VECSMALL); for (i = 1; i <= nlist; ++i) { long S1; /* listxy is the list of the nxy vectors from list that have scalar product S with v[list[i]] */ for (j = 1; j <= nlist; ++j) listxy[j] = 0; nxy = 0; S1 = list[i] > 0 ? S : -S; for (j = 1; j <= nlist; ++j) { long S2 = list[j] > 0 ? S1 : -S1; /* note: for i > 0 is v[-i] = -v[i] */ if (zv_dotproduct(gel(V,labs(list[i])), gel(Fv,labs(list[j]))) == S2) listxy[++nxy] = list[j]; } /* counts[i] is the number of pairs for the vector v[list[i]] */ counts[i] = 0; for (j = 1; j <= nxy; ++j) { long S1 = listxy[j] > 0 ? S : -S; for (k = j+1; k <= nxy; ++k) { long S2 = listxy[k] > 0 ? S1 : -S1; long lj = labs(listxy[j]), lk = labs(listxy[k]); if (zv_dotproduct(gel(V,lj), gel(Fv,lk)) == S2) counts[i] += 1; } } } /* maxd is the maximal degree of the Bacher-polynomial, mind the minimal degree */ maxd = counts[1]; mind = counts[1]; for (i = 2; i <= nlist; ++i) { if (counts[i] > maxd) maxd = counts[i]; else if (counts[i] < mind) mind = counts[i]; } coef = zero_Flv(maxd - mind + 1); for (i = 1; i <= nlist; ++i) coef[1+counts[i] - mind] += 1; if (DEBUGLEVEL) err_printf("QFIsom: mind=%ld maxd=%ld sum=%ld\n",mind,maxd,sum); /* the Bacher-polynomial is now: sum from i=mind to maxd over coef[i - mind] * X^i */ return gerepilecopy(av, mkvec2(mkvecsmall3(sum, mind, maxd),coef)); } static GEN init_bacher(long bachdep, struct fingerprint *fp, struct qfauto *qf) { GEN z = cgetg(bachdep+1,t_VEC); long i; for (i=1;i<=bachdep;i++) { long bachscp = mael(qf->W,fp->e[i],1) / 2; gel(z,i) = bacher(fp->e[i], bachscp, qf); } return z; } /* checks, whether the vector v[I] has the Bacher-polynomial pol */ static long bachcomp(GEN pol, long I, GEN V, GEN W, GEN Fv) { pari_sp av = avma; GEN co, list, listxy, vI; long i, j, k; long nlist, nxy, count; const long n = lg(V)-1, S = mael(W,I,1) / 2; long sum = mael(pol,1,1), mind = mael(pol,1,2), maxd = mael(pol,1,3); GEN coef = gel(pol,2); vI = gel(V,I); list = zero_Flv(sum); /* nlist should be equal to pol.sum */ nlist = 0; for (i = 1; i <= n && nlist <= sum; ++i) { if (mael(W,i,1) == mael(W,I,1)) { long s = zv_dotproduct(vI, gel(Fv,i)); if (s == S) { if (nlist < sum) list[nlist+1] = i; nlist++; } if (-s == S) { if (nlist < sum) list[nlist+1] = -i; nlist++; } } } if (nlist != sum) { /* the number of vectors with scalar product S is already different */ avma=av; return 0; } if (nlist == 0) { avma=av; return 1; } /* listxy is the list of the nxy vectors from list that have scalar product S with v[list[i]] */ listxy = cgetg(nlist+1,t_VECSMALL); co = zero_Flv(maxd - mind + 1); for (i = 1; i <= nlist; ++i) { long S1 = list[i] > 0 ? S : -S; for (j = 1; j <= nlist; ++j) listxy[j] = 0; nxy = 0; for (j = 1; j <= nlist; ++j) { long S2 = list[j] > 0 ? S1 : -S1; if (zv_dotproduct(gel(V,labs(list[i])), gel(Fv,labs(list[j]))) == S2) listxy[++nxy] = list[j]; } /* count is the number of pairs */ count = 0; for (j = 1; j <= nxy && count <= maxd; ++j) { long S1 = listxy[j] > 0 ? S : -S; for (k = j+1; k <= nxy && count <= maxd; ++k) { long S2 = listxy[k] > 0 ? S1 : -S1; long lj = labs(listxy[j]), lk = labs(listxy[k]); if (zv_dotproduct(gel(V,lj), gel(Fv,lk)) == S2) count++; } } if (count < mind || count > maxd || co[count-mind+1] >= coef[count-mind+1]) /* if the number of pairs is smaller than pol.mind or larger than pol.maxd or if the coefficient of X^count becomes now larger than the one in pol, then the Bacher-polynomials can not be equal */ { avma = av; return 0; } else co[count-mind+1]++; } /* the Bacher-polynomials are equal */ avma = av; return 1; } static GEN checkvecs(GEN V, GEN F, GEN norm) { long i, j, k; long n = lg(V)-1, f = lg(F)-1; GEN W = cgetg(n+1, t_MAT); j = 0; for (i = 1; i <= n; ++i) { GEN normvec = cgetg(f+1, t_VECSMALL); GEN Vi = gel(V,i); for (k = 1; k <= f; ++k) normvec[k] = scp(Vi, gel(F,k), Vi); if (!vecvecsmall_search(norm,normvec,0)) ++j; else { gel(V,i-j) = Vi; gel(W,i-j) = normvec; } } setlg(V, n+1-j); setlg(W, n+1-j); return W; } static long operate(long nr, GEN A, GEN V) { pari_sp av = avma; long im,eps; GEN w = zm_zc_mul(A,gel(V,labs(nr))); eps = zv_canon(w); if (nr < 0) eps = -eps; /* -w */ im = vecvecsmall_search(V,w,0); if (!im) pari_err_BUG("qfauto, image of vector not found"); avma = av; return eps*im; } static GEN orbit(GEN pt, long ipt, long npt, GEN H, GEN V) { pari_sp av = avma; long i, cnd, im; long n = lg(V)-1, nH = lg(H)-1, no = npt; GEN flag = zero_Flv(2*n+1)+n+1; /*We need negative indices*/ GEN orb = cgetg(2*n+1,t_VECSMALL); for (i = 1; i <= npt; ++i) { orb[i] = pt[ipt+i]; flag[pt[ipt+i]] = 1; } for (cnd=1; cnd <= no; ++cnd) for (i = 1; i <= nH; ++i) { im = operate(orb[cnd], gel(H,i), V); if (flag[im] == 0) /* the image is a new point in the orbit */ { orb[++no] = im; flag[im] = 1; } } setlg(orb,no+1); return gerepileuptoleaf(av, orb); } /* return the length of the orbit of pt under the first nG matrices in G */ static long orbitlen(long pt, long orblen, GEN G, long nG, GEN V) { pari_sp av = avma; long i, len, cnd; long n = lg(V)-1; GEN orb, flag; /* if flag[i + n+1] = 1, -n <= i <= n, then the point i is already in the orbit */ flag = zero_Flv(2*n + 1)+n+1; orb = zero_Flv(orblen); orb[1] = pt; flag[pt] = 1; len = 1; for(cnd = 1; cnd <= len && len < orblen; ++cnd) for (i = 1; i <= nG && len < orblen; ++i) { long im = operate(orb[cnd], gel(G,i), V); if (flag[im] == 0) /* the image is a new point in the orbit */ { orb[++len] = im; flag[im] = 1; } } avma = av; return len; } /* delete the elements in orb2 from orb1, an entry 0 marks the end of the * list, returns the length of orb1 */ static long orbdelete(GEN orb1, GEN orb2) { long i, j, len; long l1 = lg(orb1)-1; long l2 = lg(orb2)-1; for (i = 1; i <= l1 && orb1[i] != 0; ++i); len = i - 1; for (i = 1; i <= l2 && orb2[i] != 0; ++i) { long o2i = orb2[i]; for (j = 1; j <= len && orb1[j] != o2i; ++j); /* orb1[j] = orb2[i], hence delete orb1[j] from orb1 */ if (j <= len) { orb1[j] = orb1[len]; orb1[len--] = 0; } } return len; } static long orbsubtract(GEN Cs, GEN pt, long ipt, long npt, GEN H, GEN V, long *len) { pari_sp av = avma; long nC; GEN orb = orbit(pt, ipt, npt, H, V); if (len) *len = lg(orb)-1; nC = orbdelete(Cs, orb); avma = av; return nC; } /* Generates the matrix X which has as row per[i] the vector nr. x[i] from the * list V */ static GEN matgen(GEN x, GEN per, GEN V) { long i, j; long dim = lg(x)-1; GEN X = cgetg(dim+1,t_MAT); for (i = 1; i <= dim; ++i) { long xi = x[i]; GEN Xp = cgetg(dim+1,t_VECSMALL); for (j = 1; j <= dim; ++j) Xp[j] = xi > 0? mael(V,xi,j): -mael(V,-xi,j); gel(X,per[i]) = Xp; } return X; } /* x1 corresponds to an element X1 mapping some vector e on p1, x2 to an * element X2 mapping e on p2 and G is a generator mapping p1 on p2, then * S = X1*G*X2^-1 stabilizes e */ static GEN stabil(GEN x1, GEN x2, GEN per, GEN G, GEN V, ulong p) { pari_sp av = avma; long i; GEN x, XG, X2; long dim = lg(x1)-1; x = cgetg(dim+1,t_VECSMALL); for (i = 1; i <= dim; ++i) x[i] = operate(x1[i], G, V); /* XG is the composite mapping of the matrix corresponding to x1 and G */ XG = matgen(x, per, V); X2 = matgen(x2, per, V); return gerepileupto(av,zm_divmod(X2,XG,p)); } /* computes the orbit of fp.e[I] under the generators in G->g[I]...G->g[n-1] * and elements stabilizing fp.e[I], has some heuristic break conditions, the * generators in G->g[i] stabilize fp.e[0]...fp.e[i-1] but not fp.e[i], * G->ng[i] is the number of generators in G->g[i], the first G->nsg[i] of * which are elements which are obtained as stabilizer elements in * g[0],...,G->g[i-1]>, G->ord[i] is the orbit length of fp.e[i] under * g[i],...,G->g[n-1]> */ static void stab(long I, struct group *G, struct fingerprint *fp, GEN V, ulong p) { long len, cnd, tmplen; GEN orb, w, flag, H, Hj, S; long i, j, k, l, im, nH, nHj, fail; long Maxfail, Rest; long dim = lg(fp->diag)-1, n = lg(V)-1; /* Some heuristic break conditions for the computation of stabilizer elements: it would be too expensive to calculate all the stabilizer generators, which are obtained from the orbit, since this is highly redundant, on the other hand every new generator which enlarges the group is much cheaper than one obtained from the backtrack, after Maxfail subsequent stabilizer elements, that do not enlarge the group, Rest more elements are calculated even if they leave the group unchanged, since it turned out that this is often useful in the following steps, increasing the parameters will possibly decrease the number of generators for the group, but will increase the running time, there is no magic behind this heuristic, tuning might be appropriate */ for (Rest = 0, i = I; i <= dim; ++i) if (fp->diag[i] > 1 && G->ord[i] < fp->diag[i]) ++Rest; for (Maxfail = Rest, i = 1; i <= dim; ++i) if (fp->diag[i] > 1) ++Maxfail; for (nH = 0, i = I; i <= dim; ++i) nH += G->ng[i]; /* H are the generators of the group in which the stabilizer is computed */ H = cgetg(nH+1,t_MAT); Hj = cgetg(nH+2,t_MAT); k = 0; for (i = I; i <= dim; ++i) for (j = 1; j <= G->ng[i]; ++j) gel(H,++k) = gmael(G->g,i,j); /* in w[V.n+i] an element is stored that maps fp.e[I] on v[i] */ w = cgetg(2*n+2,t_VEC); /* orb contains the orbit of fp.e[I] */ orb = zero_Flv(2*n); /* if flag[i + V.n] = 1, then the point i is already in the orbit */ flag = zero_Flv(2*n+1); orb[1] = fp->e[I]; flag[orb[1]+n+1] = 1; gel(w,orb[1]+n+1) = cgetg(dim+1,t_VECSMALL); for (i = 1; i <= dim; ++i) mael(w,orb[1]+n+1,i) = fp->e[i]; cnd = 1; len = 1; /* fail is the number of successive failures */ fail = 0; while (cnd <= len && fail < Maxfail+Rest) { for (i = 1; i <= nH && fail < Maxfail+Rest; ++i) { if (fail >= Maxfail) /* there have already been Maxfail successive failures, now a random generator is applied to a random point of the orbit to get Rest more stabilizer elements */ { cnd = 1+(long)random_Fl(len); i = 1+(long)random_Fl(nH); } im = operate(orb[cnd], gel(H,i), V); if (flag[im+n+1] == 0) /* a new element is found, appended to the orbit and an element mapping fp.e[I] to im is stored in w[im+V.n] */ { GEN wim; orb[++len] = im; flag[im+n+1] = 1; wim = cgetg(dim+1,t_VECSMALL); gel(w,im+n+1) = wim; for (j = 1; j <= dim; ++j) wim[j] = operate(mael(w,orb[cnd]+n+1,j), gel(H,i), V); } else /* the image was already in the orbit */ { /* j is the first index where the images of the old and the new element mapping e[I] on im differ */ for (j = I; j <= dim; j++) if (operate(mael(w,orb[cnd]+n+1,j), gel(H,i), V) != mael(w,im+n+1,j)) break; if (j <= dim && (G->ord[j] < fp->diag[j] || fail >= Maxfail)) { GEN wo = gel(w,orb[cnd]+n+1); /* new stabilizer element S = w[orb[cnd]+V.n] * H[i] * (w[im+V.n])^-1 */ S = stabil(wo, gel(w,im+n+1), fp->per, gel(H,i), V, p); gel(Hj,1) = S; nHj = 1; for (k = j; k <= dim; ++k) for (l = 1; l <= G->ng[k]; ++l) gel(Hj,++nHj) = gmael(G->g,k,l); tmplen = orbitlen(fp->e[j], fp->diag[j], Hj, nHj, V); if (tmplen > G->ord[j] || fail >= Maxfail) /* the new stabilizer element S either enlarges the orbit of e[j] or it is one of the additional elements after MAXFAIL failures */ { GEN Ggj; G->ord[j] = tmplen; G->ng[j]++; G->nsg[j]++; /* allocate memory for the new generator */ gel(G->g,j) = vec_lengthen(gel(G->g,j),G->ng[j]); Ggj = gel(G->g,j); /* the new generator is inserted as stabilizer element nr. nsg[j]-1 */ for (k = G->ng[j]; k > G->nsg[j]; --k) gel(Ggj,k) = gel(Ggj,k-1); gel(Ggj,G->nsg[j]) = S; nH++; H = vec_lengthen(H, nH); Hj = vec_lengthen(Hj, nH+1); /* the new generator is appended to H */ gel(H,nH) = gel(Ggj,G->nsg[j]); /* the number of failures is reset to 0 */ if (fail < Maxfail) fail = 0; else ++fail; } else /*the new stabilizer element S does not enlarge the orbit of e[j]*/ ++fail; } else if ((j < dim && fail < Maxfail) || (j == dim && fail >= Maxfail)) ++fail; /* if S is the identity and fail < Maxfail, nothing is done */ } } if (fail < Maxfail) ++cnd; } } /* tests, whether x[1],...,x[I-1] is a partial automorphism, using scalar * product combinations and Bacher-polynomials depending on the chosen options, * puts the candidates for x[I] (i.e. the vectors vec such that the scalar * products of x[1],...,x[I-1],vec are correct) on CI, returns their number * (should be fp.diag[I]) */ static long qfisom_candidates_novec(GEN CI, long I, GEN x, struct qfauto *qf, struct qfauto *qff, struct fingerprint *fp) { pari_sp av = avma; long i, j, k, okp, okm, nr, fail; GEN vec; GEN F =qf->F, V=qff->V, W=qff->W, v=qff->v; long n = lg(V)-1, f = lg(F)-1; vec = cgetg(I,t_VECSMALL); /* CI is the list for the candidates */ for (i = 1; i <= fp->diag[I]; ++i) CI[i] = 0; nr = 0; fail = 0; for (j = 1; j <= n && fail == 0; ++j) { GEN Vj = gel(V,j), Wj = gel(W, j); okp = 0; okm = 0; for (i = 1; i <= f; ++i) { GEN FAiI = gmael(F,i,fp->per[I]); GEN FFvi = gel(v,i); /* vec is the vector of scalar products of V.v[j] with the first I base vectors x[0]...x[I-1] */ for (k = 1; k < I; ++k) { long xk = x[k]; if (xk > 0) vec[k] = zv_dotproduct(Vj, gel(FFvi,xk)); else vec[k] = -zv_dotproduct(Vj, gel(FFvi,-xk)); } for (k = 1; k < I && vec[k] == FAiI[fp->per[k]]; ++k); if (k == I && Wj[i] == FAiI[fp->per[I]]) /* V.v[j] is a candidate for x[I] with respect to the form F.A[i] */ ++okp; for (k = 1; k < I && vec[k] == -FAiI[fp->per[k]]; ++k); if (k == I && Wj[i] == FAiI[fp->per[I]]) /* -V.v[j] is a candidate for x[I] with respect to the form F.A[i] */ ++okm; } if (okp == f) /* V.v[j] is a candidate for x[I] */ { if (nr < fp->diag[I]) CI[++nr] = j; else /* there are too many candidates */ fail = 1; } if (okm == f) /* -V.v[j] is a candidate for x[I] */ { if (nr < fp->diag[I]) CI[++nr] = -j; else /* there are too many candidates */ fail = 1; } } if (fail == 1) nr = 0; avma = av; return nr; } static long qfisom_candidates(GEN CI, long I, GEN x, struct qfauto *qf, struct qfauto *qff, struct fingerprint *fp, struct qfcand *qfcand) { pari_sp av = avma; long i, j, k, okp, okm, nr, fail; GEN vec; GEN xvec, xbase, Fxbase, scpvec; long vj, rank, num; GEN com, list, trans, ccoef, cF; GEN F =qf->F, V=qff->V, W=qff->W, v=qff->v, FF= qff->F; long dim = qf->dim, n = lg(V)-1, f = lg(F)-1; long nc; long DEP = qfcand->cdep, len = f * DEP; if (I >= 2 && I <= lg(qfcand->bacher_pol)) { long t = labs(x[I-1]); GEN bpolI = gel(qfcand->bacher_pol,I-1); if (bachcomp(bpolI, t, V, W, gel(v,1)) == 0) return 0; } if (I==1 || DEP ==0) return qfisom_candidates_novec(CI,I,x,qf,qff,fp); vec = cgetg(I,t_VECSMALL); scpvec = cgetg(len+1,t_VECSMALL); com = gel(qfcand->comb,I-1); list=gel(com,1); trans = gel(com,2); ccoef = gel(com,3); cF=gel(com,4); rank = lg(trans)-1; nc = lg(list)-2; /* xvec is the list of vector sums which are computed with respect to the partial basis in x */ xvec = zero_Flm_copy(dim,nc+1); /* xbase should be a basis for the lattice generated by the vectors in xvec, it is obtained via the transformation matrix comb[I-1].trans */ xbase = cgetg(rank+1,t_MAT); for (i = 1; i <= rank; ++i) gel(xbase,i) = cgetg(dim+1,t_VECSMALL); /* Fxbase is the product of a form F with the base xbase */ Fxbase = cgetg(rank+1,t_MAT); for (i = 1; i <= rank; ++i) gel(Fxbase,i) = cgetg(dim+1,t_VECSMALL); /* CI is the list for the candidates */ for (i = 1; i <= fp->diag[I]; ++i) CI[i] = 0; nr = 0; fail = 0; for (j = 1; j <= n && fail == 0; ++j) { long sign; GEN Vj = gel(V,j), Wj = gel(W, j); okp = 0; okm = 0; for (k = 1; k <= len; ++k) scpvec[k] = 0; for (i = 1; i <= f; ++i) { GEN FAiI = gmael(F,i,fp->per[I]); GEN FFvi = gel(v,i); /* vec is the vector of scalar products of V.v[j] with the first I base vectors x[0]...x[I-1] */ for (k = 1; k < I; ++k) { long xk = x[k]; if (xk > 0) vec[k] = zv_dotproduct(Vj, gel(FFvi,xk)); else vec[k] = -zv_dotproduct(Vj, gel(FFvi,-xk)); } for (k = 1; k < I && vec[k] == FAiI[fp->per[k]]; ++k); if (k == I && Wj[i] == FAiI[fp->per[I]]) /* V.v[j] is a candidate for x[I] with respect to the form F.A[i] */ ++okp; for (k = 1; k < I && vec[k] == -FAiI[fp->per[k]]; ++k); if (k == I && Wj[i] == FAiI[fp->per[I]]) /* -V.v[j] is a candidate for x[I] with respect to the form F.A[i] */ ++okm; for (k = I-1; k >= 1 && k > I-1-DEP; --k) scpvec[(i-1)*DEP+I-k] = vec[k]; } /* check, whether the scalar product combination scpvec is contained in the list comb[I-1].list */ if (!zv_equal0(scpvec)) { sign = zv_canon(scpvec); num = vecvecsmall_search(list,scpvec,0); if (!num) /* scpvec is not found, hence x[0]...x[I-1] is not a partial automorphism */ fail = 1; else /* scpvec is found and the vector is added to the corresponding vector sum */ { GEN xnum = gel(xvec,num); for (k = 1; k <= dim; ++k) xnum[k] += sign * Vj[k]; } } if (okp == f) /* V.v[j] is a candidate for x[I] */ { if (nr < fp->diag[I]) CI[++nr] = j; else /* there are too many candidates */ fail = 1; } if (okm == f) /* -V.v[j] is a candidate for x[I] */ { if (nr < fp->diag[I]) CI[++nr] = -j; else /* there are too many candidates */ fail = 1; } } if (fail == 1) nr = 0; if (nr == fp->diag[I]) { /* compute the basis of the lattice generated by the vectors in xvec via the transformation matrix comb[I-1].trans */ for (i = 1; i <= rank; ++i) { GEN comtri = gel(trans,i); for (j = 1; j <= dim; ++j) { long xbij = 0; for (k = 1; k <= nc+1; ++k) xbij += comtri[k] * mael(xvec,k,j); mael(xbase,i,j) = xbij; } } /* check, whether the base xbase has the right scalar products */ for (i = 1; i <= f && nr > 0; ++i) { for (j = 1; j <= rank; ++j) for (k = 1; k <= dim; ++k) mael(Fxbase,j,k) = zv_dotproduct(gmael(FF,i,k), gel(xbase,j)); for (j = 1; j <= rank && nr > 0; ++j) for (k = 1; k <= j && nr > 0; ++k) { if (zv_dotproduct(gel(xbase,j), gel(Fxbase,k)) != mael3(cF,i,j,k)) /* a scalar product is wrong */ nr = 0; } } for (i = 1; i <= nc+1 && nr > 0; ++i) { GEN comcoi = gel(ccoef,i); for (j = 1; j <= dim && nr > 0; ++j) { vj = 0; for (k = 1; k <= rank; ++k) vj += comcoi[k] * mael(xbase,k,j); if (vj != mael(xvec,i,j)) /* an entry is wrong */ nr = 0; } } } avma = av; return nr; } static long aut(long step, GEN x, GEN C, struct group *G, struct qfauto *qf, struct fingerprint *fp, struct qfcand *cand) { long dim = qf->dim; GEN orb = cgetg(2,t_VECSMALL); while (mael(C,step,1) != 0) { if (step < dim) { long nbc; /* choose the image of the base-vector nr. step */ gel(x,step) = gmael(C,step,1); /* check, whether x[0]...x[step] is a partial automorphism and compute the candidates for x[step+1] */ nbc = qfisom_candidates(gel(C,step+1), step+1, x, qf, qf, fp, cand); if (nbc == fp->diag[step+1]) /* go deeper into the recursion */ if (aut(step+1, x, C, G, qf, fp, cand)) return 1; orb[1] = x[step]; /* delete the chosen vector from the list of candidates */ (void)orbdelete(gel(C,step), orb); } else { /* a new automorphism is found */ gel(x,dim) = gmael(C,dim,1); return 1; } } return 0; } /* search new automorphisms until on all levels representatives for all orbits * have been tested */ static void autom(struct group *G, struct qfauto *qf, struct fingerprint *fp, struct qfcand *cand) { long i, j, step, im, nC, nH, found, tries; GEN x, bad, H; long nbad; GEN V = qf->V; long dim = qf->dim, n = lg(V)-1; long STAB = 1; GEN C = cgetg(dim+1,t_VEC); /* C[i] is the list of candidates for the image of the i-th base-vector */ for (i = 1; i <= dim; ++i) gel(C,i) = cgetg(fp->diag[i]+1, t_VECSMALL); /* x is the new base i.e. x[i] is the index in V.v of the i-th base-vector */ x = cgetg(dim+1, t_VECSMALL); for (step = STAB; step <= dim; ++step) { if(DEBUGLEVEL) err_printf("QFAuto: Step %ld/%ld\n",step,dim); nH = 0; for (nH = 0, i = step; i <= dim; ++i) nH += G->ng[i]; H = cgetg(nH+1,t_VEC); for (nH = 0, i = step; i <= dim; ++i) for (j = 1; j <= G->ng[i]; ++j) gel(H,++nH) = gmael(G->g,i,j); bad = zero_Flv(2*n); nbad = 0; /* the first step base-vectors are fixed */ for (i = 1; i < step; ++i) x[i] = fp->e[i]; /* compute the candidates for x[step] */ if (fp->diag[step] > 1) /* if fp.diag[step] > 1 compute the candidates for x[step] */ nC = qfisom_candidates(gel(C,step), step, x, qf, qf, fp, cand); else /* if fp.diag[step] == 1, fp.e[step] is the only candidate */ { mael(C,step,1) = fp->e[step]; nC = 1; } /* delete the orbit of the step-th base-vector from the candidates */ nC = orbsubtract(gel(C,step), fp->e, step-1, 1, H, V, &(G->ord[step])); while (nC > 0 && (im = mael(C,step,1)) != 0) { found = 0; /* tries vector V.v[im] as image of the step-th base-vector */ x[step] = im; if (step < dim) { long nbc; /* check, whether x[0]...x[step] is a partial basis and compute the candidates for x[step+1] */ nbc = qfisom_candidates(gel(C,step+1), step+1, x, qf, qf, fp, cand); if (nbc == fp->diag[step+1]) /* go into the recursion */ found = aut(step+1, x, C, G, qf, fp, cand); else found = 0; } else found = 1; if (found == 0) /* x[0]...x[step] can not be continued to an automorphism */ { /* delete the orbit of im from the candidates for x[step] */ nC = orbsubtract(gel(C,step),mkvecsmall(im), 0, 1, H, V, NULL); bad[++nbad] = im; } else /* a new generator has been found */ { GEN Gstep; ++G->ng[step]; /* append the new generator to G->g[step] */ Gstep = vec_lengthen(gel(G->g,step),G->ng[step]); gel(Gstep,G->ng[step]) = matgen(x, fp->per, V); gel(G->g,step) = Gstep; ++nH; H = cgetg(nH+1, t_VEC); for (nH = 0, i = step; i <= dim; ++i) for (j = 1; j <= G->ng[i]; ++j) gel(H,++nH) = gmael(G->g,i,j); nC = orbsubtract(gel(C,step), fp->e, step-1, 1, H, V, &(G->ord[step])); nC = orbsubtract(gel(C,step), bad, 0, nbad, H, V, NULL); } } /* test, whether on step STAB some generators may be omitted */ if (step == STAB) for (tries = G->nsg[step]; tries <= G->ng[step]; ++tries) { nH = 0; for (j = 1; j < tries; ++j) gel(H,++nH) = gmael(G->g,step,j); for (j = tries+1; j < G->ng[step]; ++j) gel(H,++nH) = gmael(G->g,step,j); for (i = step+1; i <= dim; ++i) for (j = 1; j <= G->ng[i]; ++j) gel(H,++nH) = gmael(G->g,i,j); if (orbitlen(fp->e[step], G->ord[step], H, nH, V) == G->ord[step]) /* the generator g[step][tries] can be omitted */ { G->ng[step]--; for (i = tries; i < G->ng[step]; ++i) gmael(G->g,step,i) = gmael(G->g,step,i+1); tries--; } } if (step < dim && G->ord[step] > 1) /* calculate stabilizer elements fixing the basis-vectors fp.e[0]...fp.e[step] */ stab(step, G, fp, V, qf->p); } } #define MAXENTRY (1L<<((BITS_IN_LONG-2)>>1)) #define MAXNORM (1L<<(BITS_IN_LONG-2)) static long zm_maxdiag(GEN A) { long dim = lg(A)-1; long max = coeff(A,1,1); long i; for (i = 2; i <= dim; ++i) if (coeff(A,i,i) > max) max = coeff(A,i,i); return max; } static GEN init_qfauto(GEN F, GEN U, long max, struct qfauto *qf, GEN norm, GEN minvec) { long i, j, k; GEN W, v; GEN M = minvec? minvec: gel(minim(zm_to_ZM(gel(F,1)), stoi(max), NULL), 3); GEN V = ZM_to_zm_canon(M); long n = lg(V)-1, f = lg(F)-1, dim = lg(gel(F,1))-1; for (i = 1; i <= n; ++i) { GEN Vi = gel(V,i); for (k = 1; k <= dim; ++k) { long l = labs(Vi[k]); if (l > max) max = l; } } if (max > MAXENTRY) pari_err_OVERFLOW("qfisom [lattice too large]"); qf->p = unextprime(2*max+1); V = vecvecsmall_sort_uniq(V); if (!norm) { norm = cgetg(dim+1,t_VEC); for (i = 1; i <= dim; ++i) { GEN Ni = cgetg(f+1,t_VECSMALL); for (k = 1; k <= f; ++k) Ni[k] = mael3(F,k,i,i); gel(norm,i) = Ni; } norm = vecvecsmall_sort_uniq(norm); } W = checkvecs(V, F, norm); v = cgetg(f+1,t_VEC); /* the product of the maximal entry in the short vectors with the maximal entry in v[i] should not exceed MAXNORM to avoid overflow */ max = MAXNORM / max; for (i = 1; i <= f; ++i) { GEN Fi = gel(F,i), vi; vi = cgetg(n+1,t_MAT); gel(v,i) = vi; for (j = 1; j <= n; ++j) { GEN Vj = gel(V,j); GEN vij = cgetg(dim+1, t_VECSMALL); gel(vi,j) = vij; for (k = 1; k <= dim; ++k) { vij[k] = zv_dotproduct(gel(Fi,k), Vj); if (labs(vij[k]) > max) pari_err_OVERFLOW("qfisom [lattice too large]"); } } } qf->dim = dim; qf->F = F; qf->V = V; qf->W = W; qf->v = v; qf->U = U; return norm; } static void init_qfgroup(struct group *G, struct fingerprint *fp, struct qfauto *qf) { GEN H, M, V = qf->V; long nH; long i, j, k; long dim = qf->dim; G->ng = zero_Flv(dim+1); G->nsg = zero_Flv(dim+1); G->ord = cgetg(dim+1,t_VECSMALL); G->g = cgetg(dim+1,t_VEC); for (i = 1; i <= dim; ++i) gel(G->g,i) = mkvec(gen_0); M = matid_Flm(dim); gmael(G->g,1,1) = M; G->ng[1] = 1; /* -Id is always an automorphism */ for (i = 1; i <= dim; ++i) mael(M,i,i) = -1; nH = 0; for (i = 1; i <= dim; ++i) nH += G->ng[i]; H = cgetg(nH+1,t_MAT); /* calculate the orbit lengths under the automorphisms known so far */ for (i = 1; i <= dim; ++i) { if (G->ng[i] > 0) { nH = 0; for (j = i; j <= dim; ++j) for (k = 1; k <= G->ng[j]; ++k) gel(H,++nH) = gmael(G->g,j,k); G->ord[i] = orbitlen(fp->e[i], fp->diag[i], H, nH, V); } else G->ord[i] = 1; } } /* calculates the scalar products of the vector w with the base vectors * v[b[I]] down to v[b[I-dep+1]] with respect to all invariant forms and puts * them on scpvec */ static GEN scpvector(GEN w, GEN b, long I, long dep, GEN v) { long i, j, n = lg(v)-1; GEN scpvec = zero_Flv(dep*n); for (i = I; i >= 1 && i > I-dep; --i) { long bi = b[i]; if (bi > 0) for (j = 1; j <= n; ++j) scpvec[1+(j-1)*dep + I-i] = zv_dotproduct(w, gmael(v,j,bi)); else for (j = 1; j <= n; ++j) scpvec[1+(j-1)*dep + I-i] = -zv_dotproduct(w, gmael(v,j,-bi)); } return scpvec; } /* computes the list of scalar product combinations of the vectors * in V.v with the basis-vectors in b */ static GEN scpvecs(GEN *pt_vec, long I, GEN b, long dep, struct qfauto *qf) { long i, j, nr, sign; GEN list, vec; GEN vecnr; GEN V = qf->V, F = qf->F, v = qf->v; long n = lg(V)-1; long dim = lg(gel(F,1))-1; long len = (lg(F)-1)*dep; /* the first vector in the list is the 0-vector and is not counted */ list = mkmat(zero_Flv(len)); vec = mkmat(zero_Flv(dim)); for (j = 1; j <= n; ++j) { GEN Vvj = gel(V,j); GEN scpvec = scpvector(Vvj, b, I, dep, v); if (zv_equal0(scpvec)) nr = -1; else { sign = zv_canon(scpvec); nr = vecvecsmall_search(list,scpvec,0); } /* scpvec is already in list */ if (nr > 0) { vecnr = gel(vec,nr); for (i = 1; i <= dim; ++i) vecnr[i] += sign * Vvj[i]; } /* scpvec is a new scalar product combination */ else if (nr==0) { nr = vecvecsmall_search(list,scpvec,1); list=vec_insert(list,nr,scpvec); vec=vec_insert(vec,nr,sign < 0 ? zv_neg(Vvj) : zv_copy(Vvj)); } } settyp(list,t_MAT); settyp(vec,t_MAT); *pt_vec = vec; return list; } /* com->F[i] is the Gram-matrix of the basis b with respect to F.A[i] */ static GEN scpforms(GEN b, struct qfauto *qf) { long i, j, k; GEN F = qf->F; long n = lg(F)-1, dim = lg(gel(F,1))-1; long nb = lg(b)-1; GEN gram = cgetg(n+1, t_VEC); /* Fbi is the list of products of F.A[i] with the vectors in b */ GEN Fbi = cgetg(nb+1, t_MAT); for (j = 1; j <= nb; ++j) gel(Fbi, j) = cgetg(dim+1, t_VECSMALL); for (i = 1; i <= n; ++i) { GEN FAi = gel(F,i); gel(gram, i) = cgetg(nb+1, t_MAT); for (j = 1; j <= nb; ++j) for (k = 1; k <= dim; ++k) mael(Fbi,j,k) = zv_dotproduct(gel(FAi,k), gel(b,j)); for (j = 1; j <= nb; ++j) { GEN comFij = cgetg(nb+1, t_VECSMALL); for (k = 1; k <= nb; ++k) comFij[k] = zv_dotproduct(gel(b,j), gel(Fbi,k)); gmael(gram,i,j) = comFij; } } return gram; } static GEN gen_comb(long cdep, GEN A, GEN e, struct qfauto *qf, long lim) { long i, dim = lg(A)-1; GEN comb = cgetg(dim+1,t_VEC); for (i = 1; i <= dim; ++i) { pari_sp av = avma; GEN trans, ccoef, cF, B, BI; GEN sumveclist, sumvecbase; GEN list = scpvecs(&sumveclist, i, e, cdep, qf); GEN M = zm_to_ZM(sumveclist); GEN T = lllgramint(qf_apply_ZM(A,M)); if (lim && lg(T)-1>=lim) return NULL; B = ZM_mul(M,T); BI = RgM_inv(B); sumvecbase = ZM_trunc_to_zm(B); trans = ZM_trunc_to_zm(T); ccoef = ZM_trunc_to_zm(RgM_mul(BI,M)); cF = scpforms(sumvecbase, qf); gel(comb,i) = gerepilecopy(av, mkvec4(list, trans, ccoef, cF)); } return comb; } static void init_comb(struct qfcand *cand, GEN A, GEN e, struct qfauto *qf) { long dim = lg(A)-1; GEN Am = zm_to_ZM(A); for (cand->cdep = 1; ; cand->cdep++) { cand->comb = gen_comb(cand->cdep, Am, e, qf, (dim+1)>>1); if (!cand->comb) break; } cand->cdep= maxss(1, cand->cdep-1); cand->comb = gen_comb(cand->cdep, Am, e, qf, 0); } static void init_flags(struct qfcand *cand, GEN A, struct fingerprint *fp, struct qfauto *qf, GEN flags) { if (!flags) { init_comb(cand, A, fp->e, qf); cand->bacher_pol = init_bacher(0, fp, qf); } else { long cdep, bach; if (typ(flags)!=t_VEC || lg(flags)!=3) pari_err_TYPE("qfisominit",flags); cdep = gtos(gel(flags,1)); bach = minss(gtos(gel(flags,2)),lg(fp->e)-1); if (cdep<0 || bach<0) pari_err_FLAG("qfisom"); cand->cdep = cdep; cand->comb = cdep ? gen_comb(cdep, zm_to_ZM(A), fp->e, qf, 0): NULL; cand->bacher_pol = init_bacher(bach, fp, qf); } } static GEN gen_group(struct group *G, GEN U) { GEN V; long i, j, n=1, dim = lg(G->ord)-1; GEN o = gen_1; for (i = 1; i <= dim; ++i) o = muliu(o, G->ord[i]); for (i = 1; i <= dim; ++i) n += G->ng[i]-G->nsg[i]; V = cgetg(n, t_VEC); n = 1; for (i = 1; i <= dim; ++i) for (j=G->nsg[i]+1; j<=G->ng[i]; j++) gel(V,n++) = U ? zm_mul(gel(U,1), zm_mul(gmael(G->g,i,j), gel(U,2))) : gmael(G->g,i,j); return mkvec2(o, V); } static long is_qfisom(GEN F) { return (lg(F)==6 && typ(F)==t_VEC && typ(gel(F,1))==t_VEC && typ(gel(F,3))==t_VEC && typ(gel(F,4))==t_VEC); } static GEN unpack_qfisominit(GEN F, GEN *norm, struct qfauto *qf, struct fingerprint *fp, struct qfcand *cand) { GEN QF = gel(F,3); qf->F = gel(QF,1); qf->V = gel(QF,2); qf->W = gel(QF,3); qf->v = gel(QF,4); qf->p = itou(gel(QF,5)); qf->U = lg(QF)>6 ? gel(QF,6):NULL; QF = gel(F,4); fp->diag = gel(QF,1); fp->per = gel(QF,2); fp->e = gel(QF,3); QF = gel(F,5); cand->cdep =itos(gel(QF,1)); cand->comb = gel(QF,2); cand->bacher_pol = gel(QF,3); *norm = gel(F,2); qf->dim = lg(gmael(F,1,1))-1; return qf->F; } static GEN qfisom_bestmat(GEN A, long *pt_max) { long max = zm_maxdiag(A), max2; GEN A1 = zm_to_ZM(A), A2; GEN U = lllgramint(A1); if (lg(U) != lg(A1)) pari_err_DOMAIN("qfisom","form","is not", strtoGENstr("positive definite"), A1); A2 = ZM_to_zm(qf_apply_ZM(A1, U)); max2 = zm_maxdiag(A2); if (max2 < max) { *pt_max = max2; return mkvec2(ZM_to_zm(U),ZM_to_zm(ZM_inv(U,NULL))); } else { *pt_max = max; return NULL; } } static GEN init_qfisom(GEN F, struct fingerprint *fp, struct qfcand *cand, struct qfauto *qf, GEN flags, long *max, GEN minvec) { GEN U, A, norm; if (is_qfisom(F)) { F = unpack_qfisominit(F, &norm, qf, fp, cand); A = gel(F,1); *max = zm_maxdiag(A); if (flags) init_flags(cand, A, fp, qf, flags); } else { if (lg(F)<2) pari_err_TYPE("qfisom",F); A = gel(F,1); if (lg(A)<2) pari_err_TYPE("qfisom",A); if (!minvec) { U = qfisom_bestmat(A, max); if (DEBUGLEVEL) err_printf("QFIsom: max=%ld\n",*max); if (U) F = zmV_apply_zm(F, gel(U,1)); } else { *max = zm_maxdiag(A); U = NULL; if (typ(minvec)==t_VEC && lg(minvec)==4 && typ(gel(minvec,2))==t_INT) { long n = itos(gel(minvec,2)); if (n != *max) pari_err_DOMAIN("qfisominit","m[2]","!=",stoi(*max),stoi(n)); minvec = gel(minvec, 3); } if (typ(minvec)!=t_MAT || lg(gel(minvec,1))!=lg(A)) pari_err_TYPE("qfisominit",minvec); } norm = init_qfauto(F, U, *max, qf, NULL, minvec); fingerprint(fp, qf); if (DEBUGLEVEL) err_printf("QFIsom: fp=%Ps\n",fp->diag); init_flags(cand, A, fp, qf, flags); } return norm; } GEN qfauto(GEN F, GEN flags) { pari_sp av = avma; struct fingerprint fp; struct group G; struct qfcand cand; struct qfauto qf; long max; (void)init_qfisom(F, &fp, &cand, &qf, flags, &max, NULL); init_qfgroup(&G, &fp, &qf); autom(&G, &qf, &fp, &cand); return gerepilecopy(av, gen_group(&G, qf.U)); } static GEN qf_to_zmV(GEN F) { return typ(F)==t_MAT ? (RgM_is_ZM(F) ? mkvec(ZM_to_zm(F)): NULL) : typ(F)==t_VEC ? (RgV_is_ZMV(F) ? ZMV_to_zmV(F): NULL) : NULL; } GEN qfauto0(GEN x, GEN flags) { pari_sp av = avma; GEN F, G; if (is_qfisom(x)) F = x; else { F = qf_to_zmV(x); if (!F) pari_err_TYPE("qfauto",x); } G = qfauto(F, flags); return gerepilecopy(av, mkvec2(gel(G,1), zmV_to_ZMV(gel(G,2)))); } /* computes the orbit of V.v[pt] under the generators G[0],...,G[nG-1] and * elements stabilizing V.v[pt], which are stored in H, returns the number of * generators in H */ static GEN isostab(long pt, GEN G, GEN V, long Maxfail, ulong p) { pari_sp av = avma; long len, cnd, orblen, tmplen, rpt; GEN w, flag, orb; long i, im, nH, fail; long dim = lg(gel(V,1))-1, n = lg(V)-1, nG = lg(G)-1; GEN H; /* a heuristic break condition for the computation of stabilizer elements: it would be too expensive to calculate all the stabilizer generators, which are obtained from the orbit, since this is highly redundant, on the other hand every new generator which enlarges the group reduces the number of orbits and hence the number of candidates to be tested, after Maxfail subsequent stabilizer elements, that do not enlarge the group, the procedure stops, increasing Maxfail will possibly decrease the number of tests, but will increase the running time of the stabilizer computation there is no magic behind the heuristic, tuning might be appropriate */ /* H are the generators of the stabilizer of V.v[pt] */ H = cgetg(2,t_VEC); nH = 0; /* w[i+V.n] is a matrix that maps V.v[pt] on V.v[i] */ w = cgetg(2*n+2,t_MAT); orb = zero_Flv(2*n); /* orblen is the length of the orbit of a random vector in V.v */ orblen = 1; /* if flag[i+V.n] = 1, then the point i is already in the orbit */ flag = zero_Flv(2*n+1); orb[1] = pt; flag[orb[1]+n+1] = 1; /* w[pt+V.n] is the Identity */ gel(w,orb[1]+n+1) = matid_Flm(dim); cnd = 1; len = 1; /* fail is the number of successive failures */ fail = 0; while (cnd <= len && fail < Maxfail) { for (i = 1; i <= nG && fail < Maxfail; ++i) { im = operate(orb[cnd], gel(G,i), V); if (flag[im+n+1] == 0) /* a new element is found, appended to the orbit and an element mapping V.v[pt] to im is stored in w[im+V.n] */ { orb[++len] = im; flag[im+n+1] = 1; gel(w,im+n+1)= zm_mul(gel(G,i), gel(w,orb[cnd]+n+1)); } else /* the image was already in the orbit */ { GEN B = zm_mul(gel(G,i), gel(w,orb[cnd]+n+1)); /* check whether the old and the new element mapping pt on im differ */ if (!zvV_equal(B, gel(w,im+n+1))) { gel(H,nH+1) = zm_divmod(gel(w,im+n+1),B,p); rpt = 1+(long)random_Fl(n); tmplen = orbitlen(rpt, 2*n, H, nH+1, V); while (tmplen < orblen) /* the orbit of this vector is shorter than a previous one, hence choose a new random vector */ { rpt = 1+(long)random_Fl(n); tmplen = orbitlen(rpt, 2*n, H, nH+1, V); } if (tmplen > orblen) /* the new stabilizer element H[nH] enlarges the group generated by H */ { orblen = tmplen; /* allocate memory for the new generator */ H = vec_lengthen(H, (++nH)+1); fail = 0; } else /* the new stabilizer element does not enlarge the orbit of a random vector */ ++fail; } /* if H[nH] is the identity, nothing is done */ } } ++cnd; } setlg(H,nH+1); return gerepilecopy(av, H); } /* the heart of the program: the recursion */ static long iso(long step, GEN x, GEN C, struct qfauto *qf, struct qfauto *qff, struct fingerprint *fp, GEN G, struct qfcand *cand) { int i, Maxfail; GEN H; long dim = qf->dim; long found = 0; while (mael(C,step,1) != 0 && found == 0) { if (step < dim) { long nbc; /* choose the image of the base-vector nr. step */ x[step] = mael(C,step,1); /* check whether x[0]...x[step] is a partial automorphism and compute the candidates for x[step+1] */ nbc = qfisom_candidates(gel(C,step+1), step+1, x, qf, qff, fp, cand); if (nbc == fp->diag[step+1]) { /* go deeper into the recursion */ Maxfail = 0; /* determine the heuristic value of Maxfail for the break condition in isostab */ for (i = 1; i <= step; ++i) if (fp->diag[i] > 1) Maxfail += 1; for (i = step+1; i <= dim; ++i) if (fp->diag[i] > 1) Maxfail += 2; /* compute the stabilizer H of x[step] in G */ H = isostab(x[step], G, qff->V, Maxfail,qff->p); found = iso(step+1, x, C, qf, qff, fp, H, cand); } if (found == 1) return 1; /* delete the orbit of the chosen vector from the list of candidates */ orbsubtract(gel(C,step), x, step-1, 1, G, qff->V, NULL); } else { /* an isomorphism is found */ x[dim] = mael(C,dim,1); found = 1; } } return found; } /* search for an isometry */ static GEN isometry(struct qfauto *qf, struct qfauto *qff, struct fingerprint *fp, GEN G, struct qfcand *cand) { long i, found; GEN x; long dim = qf->dim; GEN C = cgetg(dim+1,t_VEC); /* C[i] is the list of candidates for the image of the i-th base-vector */ for (i = 1; i <= dim; ++i) gel(C,i) = cgetg(fp->diag[i]+1, t_VECSMALL); x = cgetg(dim+1, t_VECSMALL); /* compute the candidates for x[1] */ qfisom_candidates(gel(C,1), 1, x, qf, qff, fp, cand); found = iso(1, x, C, qf, qff, fp, G, cand); return found ? matgen(x, fp->per, qff->V): NULL; } GEN qfisominit(GEN F, GEN flags, GEN minvec) { pari_sp av = avma; struct fingerprint fp; struct qfauto qf; struct qfcand cand; long max; GEN norm = init_qfisom(F, &fp, &cand, &qf, flags, &max, minvec); return gerepilecopy(av, mkvec5(F, norm, mkvecn(qf.U?6:5, qf.F, qf.V, qf.W, qf.v, utoi(qf.p), qf.U), mkvec3(fp.diag, fp.per, fp.e), mkvec3(stoi(cand.cdep),cand.comb?cand.comb:cgetg(1,t_VEC), cand.bacher_pol))); } GEN qfisominit0(GEN x, GEN flags, GEN minvec) { pari_sp av = avma; GEN F = qf_to_zmV(x); if (!F) pari_err_TYPE("qfisom",x); return gerepileupto(av, qfisominit(F, flags, minvec)); } GEN qfisom(GEN F, GEN FF, GEN flags, GEN G) { pari_sp av = avma; struct fingerprint fp; GEN res; struct qfauto qf, qff; struct qfcand cand; long max; GEN norm = init_qfisom(F, &fp, &cand, &qf, flags, &max, NULL); init_qfauto(FF, NULL, max, &qff, norm, NULL); if (lg(qf.W)!=lg(qff.W) || !zvV_equal(vecvecsmall_sort(qf.W), vecvecsmall_sort(qff.W))) { avma=av; return gen_0; } if (!G) G = mkvec(scalar_Flm(-1, qff.dim)); res = isometry(&qf, &qff, &fp, G, &cand); if (!res) { avma=av; return gen_0; } return gerepilecopy(av, zm_to_ZM(qf.U? zm_mul(res,gel(qf.U, 2)):res)); } static GEN check_qfauto(GEN G) { if (typ(G)==t_VEC && lg(G)==3 && typ(gel(G,1))==t_INT) G = gel(G,2); return qf_to_zmV(G); } GEN qfisom0(GEN x, GEN y, GEN flags, GEN G) { pari_sp av = avma; GEN F, FF; if (is_qfisom(x)) F = x; else { F = qf_to_zmV(x); if (!F) pari_err_TYPE("qfisom",x); } FF = qf_to_zmV(y); if (!FF) pari_err_TYPE("qfisom",y); if (G) G = check_qfauto(G); return gerepileupto(av, qfisom(F, FF, flags, G)); } static GEN ZM_to_GAP(GEN M) { pari_sp ltop=avma; long rows = nbrows(M), cols = lg(M)-1; long i, j, c; GEN comma = strtoGENstr(", "); GEN bra = strtoGENstr("["); GEN ket = strtoGENstr("]"); GEN s = cgetg(2*rows*cols+2*rows+2,t_VEC); gel(s,1) = bra; c=2; for (i = 1; i <= rows; ++i) { if (i > 1) gel(s,c++) = comma; gel(s,c++) = bra; for (j = 1; j <= cols; ++j) { if (j > 1) gel(s,c++) = comma; gel(s,c++) = GENtoGENstr(gcoeff(M,i,j)); } gel(s,c++) = ket; } gel(s,c++) = ket; return gerepilecopy(ltop,shallowconcat1(s)); } GEN qfautoexport(GEN G, long flag) { pari_sp av = avma; long i, lgen, c = 2; GEN gen, str, comma = strtoGENstr(", "); if (typ(G)!=t_VEC || lg(G)!=3) pari_err_TYPE("qfautoexport", G); if (flag!=0 && flag!=1) pari_err_FLAG("qfautoexport"); gen = gel(G,2); lgen = lg(gen)-1; str = cgetg(2+2*lgen,t_VEC); /* in GAP or MAGMA the matrix group is called BG */ if (flag == 0) gel(str,1) = strtoGENstr("Group("); else { long dim = lg(gmael(gen,1,1))-1; gel(str,1) = gsprintf("MatrixGroup<%d, Integers() |",dim); } for(i = 1; i <= lgen; i++) { if (i!=1) gel(str,c++) = comma; gel(str,c++) = ZM_to_GAP(gel(gen,i)); } gel(str,c++) = strtoGENstr(flag ? ">":")"); return gerepilecopy(av, shallowconcat1(str)); } GEN qforbits(GEN G, GEN V) { pari_sp av = avma; GEN gen, w, W, p, v, orb, o; long i, j, n, ng; long nborbits = 0; gen = check_qfauto(G); if (!gen) pari_err_TYPE("qforbits", G); if (typ(V)==t_VEC && lg(V)==4 && typ(gel(V,1))==t_INT && typ(gel(V,2))==t_INT) V = gel(V,3); if (typ(V)!=t_MAT || !RgM_is_ZM(V)) pari_err_TYPE("qforbits", V); n = lg(V)-1; ng = lg(gen)-1; W = ZM_to_zm_canon(V); p = vecvecsmall_indexsort(W); v = vecpermute(W, p); w = zero_zv(n); orb = cgetg(n+1, t_VEC); o = cgetg(n+1, t_VECSMALL); if (lg(v) != lg(V)) return gen_0; for (i=1; i<=n; i++) { long cnd, no = 1; GEN T; if (w[i]) continue; w[i] = ++nborbits; o[1] = i; for (cnd=1; cnd <= no; ++cnd) for(j=1; j <= ng; j++) { long k; GEN Vij = zm_zc_mul(gel(gen, j), gel(v, o[cnd])); (void) zv_canon(Vij); k = vecvecsmall_search(v, Vij, 0); if (k == 0) { avma = av; return gen_0; } if (w[k] == 0) { o[++no] = k; w[k] = nborbits; } } T = cgetg(no+1, t_VEC); for (j=1; j<=no; j++) gel(T,j) = gel(V,p[o[j]]); gel(orb, nborbits) = T; } setlg(orb, nborbits+1); return gerepilecopy(av, orb); } pari-2.11.2/src/basemath/Qfb.c0000644000175000017500000011472313326135265014423 0ustar billbill/* Copyright (C) 2000-2005 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* QUADRATIC POLYNOMIAL ASSOCIATED TO A DISCRIMINANT */ /* */ /*******************************************************************/ void check_quaddisc(GEN x, long *s, long *r, const char *f) { if (typ(x) != t_INT) pari_err_TYPE(f,x); *s = signe(x); if (Z_issquare(x)) pari_err_DOMAIN(f,"issquare(disc)","=", gen_1,x); *r = mod4(x); if (*s < 0 && *r) *r = 4 - *r; if (*r > 1) pari_err_DOMAIN(f,"disc % 4",">", gen_1,x); } void check_quaddisc_real(GEN x, long *r, const char *f) { long sx; check_quaddisc(x, &sx, r, f); if (sx < 0) pari_err_DOMAIN(f, "disc","<",gen_0,x); } void check_quaddisc_imag(GEN x, long *r, const char *f) { long sx; check_quaddisc(x, &sx, r, f); if (sx > 0) pari_err_DOMAIN(f, "disc",">",gen_0,x); } /* X^2 + b X + c is the canonical quadratic t_POL of discriminant D. * Dodd is non-zero iff D is odd */ static void quadpoly_bc(GEN D, long Dodd, GEN *b, GEN *c) { if (Dodd) { pari_sp av = avma; *b = gen_m1; *c = gerepileuptoint(av, shifti(subui(1,D), -2)); } else { *b = gen_0; *c = shifti(D,-2); togglesign(*c); } } /* X^2 - X - (D-1)/4 or X^2 - D/4 */ GEN quadpoly(GEN D) { long Dmod4, s; GEN b, c, y = cgetg(5,t_POL); check_quaddisc(D, &s, &Dmod4, "quadpoly"); y[1] = evalsigne(1) | evalvarn(0); quadpoly_bc(D, Dmod4, &b,&c); gel(y,2) = c; gel(y,3) = b; gel(y,4) = gen_1; return y; } GEN quadpoly0(GEN x, long v) { GEN T = quadpoly(x); if (v > 0) setvarn(T, v); return T; } GEN quadgen(GEN x) { retmkquad(quadpoly(x), gen_0, gen_1); } GEN quadgen0(GEN x, long v) { if (v==-1) v = fetch_user_var("w"); retmkquad(quadpoly0(x, v), gen_0, gen_1); } /***********************************************************************/ /** **/ /** BINARY QUADRATIC FORMS **/ /** **/ /***********************************************************************/ GEN qfi(GEN x, GEN y, GEN z) { if (signe(x) < 0) pari_err_IMPL("negative definite t_QFI"); retmkqfi(icopy(x),icopy(y),icopy(z)); } GEN qfr(GEN x, GEN y, GEN z, GEN d) { if (typ(d) != t_REAL) pari_err_TYPE("qfr",d); retmkqfr(icopy(x),icopy(y),icopy(z),rcopy(d)); } GEN Qfb0(GEN x, GEN y, GEN z, GEN d, long prec) { pari_sp av = avma; GEN D; long s, r; if (typ(x)!=t_INT) pari_err_TYPE("Qfb",x); if (typ(y)!=t_INT) pari_err_TYPE("Qfb",y); if (typ(z)!=t_INT) pari_err_TYPE("Qfb",z); D = qfb_disc3(x,y,z); check_quaddisc(D, &s, &r, "Qfb"); avma = av; if (s < 0) return qfi(x, y, z); d = d? gtofp(d,prec): real_0(prec); return qfr(x,y,z,d); } /* composition */ static void qfb_sqr(GEN z, GEN x) { GEN c, d1, x2, v1, v2, c3, m, p1, r; d1 = bezout(gel(x,2),gel(x,1),&x2, NULL); /* usually 1 */ c = gel(x,3); m = mulii(c,x2); if (equali1(d1)) v1 = v2 = gel(x,1); else { v1 = diviiexact(gel(x,1),d1); v2 = mulii(v1, gcdii(d1,c)); /* = v1 iff x primitive */ c = mulii(c, d1); } togglesign(m); r = modii(m,v2); p1 = mulii(r, v1); c3 = addii(c, mulii(r,addii(gel(x,2),p1))); gel(z,1) = mulii(v1,v2); gel(z,2) = addii(gel(x,2), shifti(p1,1)); gel(z,3) = diviiexact(c3,v2); } /* z <- x * y */ static void qfb_comp(GEN z, GEN x, GEN y) { GEN n, c, d, y1, v1, v2, c3, m, p1, r; if (x == y) { qfb_sqr(z,x); return; } n = shifti(subii(gel(y,2),gel(x,2)), -1); v1 = gel(x,1); v2 = gel(y,1); c = gel(y,3); d = bezout(v2,v1,&y1,NULL); if (equali1(d)) m = mulii(y1,n); else { GEN s = subii(gel(y,2), n); GEN x2, y2, d1 = bezout(s,d,&x2,&y2); /* x2 s + y2 (x1 v1 + y1 v2) = d1 */ if (!equali1(d1)) { v1 = diviiexact(v1,d1); v2 = diviiexact(v2,d1); /* gcd = 1 iff x or y primitive */ v1 = mulii(v1, gcdii(c,gcdii(gel(x,3),gcdii(d1,n)))); c = mulii(c, d1); } m = addii(mulii(mulii(y1,y2),n), mulii(gel(y,3),x2)); } togglesign(m); r = modii(m, v1); p1 = mulii(r, v2); c3 = addii(c, mulii(r,addii(gel(y,2),p1))); gel(z,1) = mulii(v1,v2); gel(z,2) = addii(gel(y,2), shifti(p1,1)); gel(z,3) = diviiexact(c3,v1); } static GEN redimag_av(pari_sp av, GEN q); static GEN qficomp0(GEN x, GEN y, int raw) { pari_sp av = avma; GEN z = cgetg(4,t_QFI); qfb_comp(z, x,y); if (raw) return gerepilecopy(av,z); return redimag_av(av, z); } static GEN qfrcomp0(GEN x, GEN y, int raw) { pari_sp av = avma; GEN z = cgetg(5,t_QFR); qfb_comp(z, x,y); gel(z,4) = addrr(gel(x,4),gel(y,4)); if (raw) return gerepilecopy(av,z); return gerepileupto(av, redreal(z)); } GEN qfrcomp(GEN x, GEN y) { return qfrcomp0(x,y,0); } GEN qfrcompraw(GEN x, GEN y) { return qfrcomp0(x,y,1); } GEN qficomp(GEN x, GEN y) { return qficomp0(x,y,0); } GEN qficompraw(GEN x, GEN y) { return qficomp0(x,y,1); } GEN qfbcompraw(GEN x, GEN y) { long tx = typ(x); if (typ(y) != tx) pari_err_TYPE2("*",x,y); switch(tx) { case t_QFI: return qficompraw(x,y); case t_QFR: return qfrcompraw(x,y); } pari_err_TYPE("composition",x); return NULL; /* LCOV_EXCL_LINE */ } static GEN qfisqr0(GEN x, long raw) { pari_sp av = avma; GEN z = cgetg(4,t_QFI); if (typ(x)!=t_QFI) pari_err_TYPE("composition",x); qfb_sqr(z,x); if (raw) return gerepilecopy(av,z); return redimag_av(av, z); } static GEN qfrsqr0(GEN x, long raw) { pari_sp av = avma; GEN z = cgetg(5,t_QFR); if (typ(x)!=t_QFR) pari_err_TYPE("composition",x); qfb_sqr(z,x); gel(z,4) = shiftr(gel(x,4),1); if (raw) return gerepilecopy(av,z); return gerepileupto(av, redreal(z)); } GEN qfrsqr(GEN x) { return qfrsqr0(x,0); } GEN qfrsqrraw(GEN x) { return qfrsqr0(x,1); } GEN qfisqr(GEN x) { return qfisqr0(x,0); } GEN qfisqrraw(GEN x) { return qfisqr0(x,1); } static GEN qfr_1_by_disc(GEN D, long prec) { GEN y = cgetg(5,t_QFR), isqrtD; pari_sp av = avma; long r; check_quaddisc_real(D, &r, "qfr_1_by_disc"); gel(y,1) = gen_1; isqrtD = sqrti(D); if ((r & 1) != mod2(isqrtD)) /* we know isqrtD > 0 */ isqrtD = gerepileuptoint(av, subiu(isqrtD,1)); gel(y,2) = isqrtD; av = avma; gel(y,3) = gerepileuptoint(av, shifti(subii(sqri(isqrtD), D),-2)); gel(y,4) = real_0(prec); return y; } GEN qfr_1(GEN x) { if (typ(x) != t_QFR) pari_err_TYPE("qfr_1",x); return qfr_1_by_disc(qfb_disc(x), precision(gel(x,4))); } static void qfr_1_fill(GEN y, struct qfr_data *S) { pari_sp av = avma; GEN y2 = S->isqrtD; gel(y,1) = gen_1; if (mod2(S->D) != mod2(y2)) y2 = subiu(y,1); gel(y,2) = y2; av = avma; gel(y,3) = gerepileuptoint(av, shifti(subii(sqri(y2), S->D),-2)); } static GEN qfr5_1(struct qfr_data *S, long prec) { GEN y = cgetg(6, t_VEC); qfr_1_fill(y, S); gel(y,4) = gen_0; gel(y,5) = real_1(prec); return y; } static GEN qfr3_1(struct qfr_data *S) { GEN y = cgetg(4, t_VEC); qfr_1_fill(y, S); return y; } /* Assume D < 0 is the discriminant of a t_QFI */ static GEN qfi_1_by_disc(GEN D) { GEN b,c, y = cgetg(4,t_QFI); quadpoly_bc(D, mod2(D), &b,&c); if (b == gen_m1) b = gen_1; gel(y,1) = gen_1; gel(y,2) = b; gel(y,3) = c; return y; } GEN qfi_1(GEN x) { if (typ(x) != t_QFI) pari_err_TYPE("qfi_1",x); return qfi_1_by_disc(qfb_disc(x)); } static GEN invraw(GEN x) { GEN y = gcopy(x); if (typ(y) == t_QFR) togglesign(gel(y,4)); togglesign(gel(y,2)); return y; } GEN qfrpowraw(GEN x, long n) { pari_sp av = avma; long m; GEN y; if (typ(x) != t_QFR) pari_err_TYPE("qfrpowraw",x); if (!n) return qfr_1(x); if (n== 1) return gcopy(x); if (n==-1) return invraw(x); y = NULL; m = labs(n); for (; m>1; m>>=1) { if (m&1) y = y? qfrcompraw(y,x): x; x = qfrsqrraw(x); } y = y? qfrcompraw(y,x): x; if (n < 0) y = invraw(y); return gerepileupto(av,y); } GEN qfipowraw(GEN x, long n) { pari_sp av = avma; long m; GEN y; if (typ(x) != t_QFI) pari_err_TYPE("qfipow",x); if (!n) return qfi_1(x); if (n== 1) return gcopy(x); if (n==-1) return invraw(x); y = NULL; m = labs(n); for (; m>1; m>>=1) { if (m&1) y = y? qficompraw(y,x): x; x = qfisqrraw(x); } y = y? qficompraw(y,x): x; if (n < 0) y = invraw(y); return gerepileupto(av,y); } GEN qfbpowraw(GEN x, long n) { return (typ(x)==t_QFI)? qfipowraw(x,n): qfrpowraw(x,n); } static long parteucl(GEN L, GEN *d, GEN *v3, GEN *v, GEN *v2) { long z; *v = gen_0; *v2 = gen_1; for (z=0; abscmpii(*v3,L) > 0; z++) { GEN t3, t2 = subii(*v, mulii(truedvmdii(*d,*v3,&t3),*v2)); *v = *v2; *d = *v3; *v2 = t2; *v3 = t3; } return z; } /* composition: Shanks' NUCOMP & NUDUPL */ /* L = floor((|d|/4)^(1/4)) */ GEN nucomp(GEN x, GEN y, GEN L) { pari_sp av = avma; long z; GEN a, a1, a2, b2, b, d, d1, g, n, p1, q1, q2, s, u, u1, v, v2, v3, Q; if (x==y) return nudupl(x,L); if (typ(x) != t_QFI) pari_err_TYPE("nucomp",x); if (typ(y) != t_QFI) pari_err_TYPE("nucomp",y); if (abscmpii(gel(x,1),gel(y,1)) < 0) swap(x, y); s = shifti(addii(gel(x,2),gel(y,2)), -1); n = subii(gel(y,2), s); a1 = gel(x,1); a2 = gel(y,1); d = bezout(a2,a1,&u,&v); if (equali1(d)) { a = negi(mulii(u,n)); d1 = d; } else if (dvdii(s,d)) /* d | s */ { a = negi(mulii(u,n)); d1 = d; a1 = diviiexact(a1, d1); a2 = diviiexact(a2, d1); s = diviiexact(s, d1); } else { GEN p2, l; d1 = bezout(s,d,&u1,NULL); if (!equali1(d1)) { a1 = diviiexact(a1,d1); a2 = diviiexact(a2,d1); s = diviiexact(s,d1); d = diviiexact(d,d1); } p1 = remii(gel(x,3),d); p2 = remii(gel(y,3),d); l = modii(mulii(negi(u1), addii(mulii(u,p1),mulii(v,p2))), d); a = subii(mulii(l,diviiexact(a1,d)), mulii(u,diviiexact(n,d))); } a = modii(a,a1); p1 = subii(a,a1); if (abscmpii(a,p1) > 0) a = p1; d = a1; v3 = a; z = parteucl(L, &d,&v3, &v,&v2); Q = cgetg(4,t_QFI); if (!z) { g = diviiexact(addii(mulii(v3,s),gel(y,3)), d); b = a2; b2 = gel(y,2); v2 = d1; gel(Q,1) = mulii(d,b); } else { GEN e, q3, q4; if (z&1) { v3 = negi(v3); v2 = negi(v2); } b = diviiexact(addii(mulii(a2,d), mulii(n,v)), a1); e = diviiexact(addii(mulii(s,d),mulii(gel(y,3),v)), a1); q3 = mulii(e,v2); q4 = subii(q3,s); b2 = addii(q3,q4); g = diviiexact(q4,v); if (!equali1(d1)) { v2 = mulii(d1,v2); v = mulii(d1,v); b2 = mulii(d1,b2); } gel(Q,1) = addii(mulii(d,b), mulii(e,v)); } q1 = mulii(b, v3); q2 = addii(q1,n); gel(Q,2) = addii(b2, z? addii(q1,q2): shifti(q1, 1)); gel(Q,3) = addii(mulii(v3,diviiexact(q2,d)), mulii(g,v2)); return redimag_av(av, Q); } GEN nudupl(GEN x, GEN L) { pari_sp av = avma; long z; GEN u, v, d, d1, p1, a, b, c, a2, b2, c2, Q, v2, v3, g; if (typ(x) != t_QFI) pari_err_TYPE("nudupl",x); a = gel(x,1); b = gel(x,2); d1 = bezout(b,a, &u,NULL); if (!equali1(d1)) { a = diviiexact(a, d1); b = diviiexact(b, d1); } c = modii(negi(mulii(u,gel(x,3))), a); p1 = subii(c,a); if (abscmpii(c,p1) > 0) c = p1; d = a; v3 = c; z = parteucl(L, &d,&v3, &v,&v2); a2 = sqri(d); c2 = sqri(v3); Q = cgetg(4,t_QFI); if (!z) { g = diviiexact(addii(mulii(v3,b),gel(x,3)), d); b2 = gel(x,2); v2 = d1; gel(Q,1) = a2; } else { GEN e; if (z&1) { v = negi(v); d = negi(d); } e = diviiexact(addii(mulii(gel(x,3),v), mulii(b,d)), a); g = diviiexact(subii(mulii(e,v2), b), v); b2 = addii(mulii(e,v2), mulii(v,g)); if (!equali1(d1)) { b2 = mulii(d1,b2); v = mulii(d1,v); v2 = mulii(d1,v2); } gel(Q,1) = addii(a2, mulii(e,v)); } gel(Q,2) = addii(b2, subii(sqri(addii(d,v3)), addii(a2,c2))); gel(Q,3) = addii(c2, mulii(g,v2)); return redimag_av(av, Q); } static GEN mul_nucomp(void *l, GEN x, GEN y) { return nucomp(x, y, (GEN)l); } static GEN mul_nudupl(void *l, GEN x) { return nudupl(x, (GEN)l); } GEN nupow(GEN x, GEN n, GEN L) { pari_sp av; GEN y, D; if (typ(n) != t_INT) pari_err_TYPE("nupow",n); if (typ(x) != t_QFI) pari_err_TYPE("nupow",x); if (gequal1(n)) return gcopy(x); av = avma; D = qfb_disc(x); y = qfi_1_by_disc(D); if (!signe(n)) return y; if (!L) L = sqrtnint(absi_shallow(D), 4); y = gen_pow(x, n, (void*)L, &mul_nudupl, &mul_nucomp); if (signe(n) < 0 && !absequalii(gel(y,1),gel(y,2)) && !absequalii(gel(y,1),gel(y,3))) togglesign(gel(y,2)); return gerepileupto(av, y); } /* Reduction */ /* assume a > 0. Write b = q*2a + r, with -a < r <= a */ static GEN dvmdii_round(GEN b, GEN a, GEN *r) { GEN a2 = shifti(a, 1), q = dvmdii(b, a2, r); if (signe(b) >= 0) { if (abscmpii(*r, a) > 0) { q = addiu(q, 1); *r = subii(*r, a2); } } else { /* r <= 0 */ if (abscmpii(*r, a) >= 0){ q = subiu(q, 1); *r = addii(*r, a2); } } return q; } /* Assume 0 < a <= LONG_MAX. Ensure no overflow */ static long dvmdsu_round(long b, ulong a, long *r) { ulong a2 = a << 1, q, ub, ur; if (b >= 0) { ub = b; q = ub / a2; ur = ub % a2; if (ur > a) { ur -= a; q++; *r = (long)ur; *r -= (long)a; } else *r = (long)ur; return (long)q; } else { /* r <= 0 */ ub = (ulong)-b; /* |b| */ q = ub / a2; ur = ub % a2; if (ur >= a) { ur -= a; q++; *r = (long)ur; *r = (long)a - *r; } else *r = -(long)ur; return -(long)q; } } /* reduce b mod 2*a. Update b,c */ static void REDB(GEN a, GEN *b, GEN *c) { GEN r, q = dvmdii_round(*b, a, &r); if (!signe(q)) return; *c = subii(*c, mulii(q, shifti(addii(*b, r),-1))); *b = r; } /* Assume a > 0. Reduce b mod 2*a. Update b,c */ static void sREDB(ulong a, long *b, ulong *c) { long r, q; ulong uz; if (a > LONG_MAX) return; /* b already reduced */ q = dvmdsu_round(*b, a, &r); if (q == 0) return; /* Final (a,r,c2) satisfies |r| <= |b| hence c2 <= c, c2 = c - q*z, * where z = (b+r) / 2, representable as long, has the same sign as q. */ if (*b < 0) { /* uz = -z >= 0, q < 0 */ if (r >= 0) /* different signs=>no overflow, exact division */ uz = (ulong)-((*b + r)>>1); else { ulong ub = (ulong)-*b, ur = (ulong)-r; uz = (ub + ur) >> 1; } *c -= (-q) * uz; /* c -= qz */ } else { /* uz = z >= 0, q > 0 */ if (r <= 0) uz = (*b + r)>>1; else { ulong ub = (ulong)*b, ur = (ulong)r; uz = ((ub + ur) >> 1); } *c -= q * uz; /* c -= qz */ } *b = r; } static void REDBU(GEN a, GEN *b, GEN *c, GEN u1, GEN *u2) { /* REDB(a,b,c) */ GEN r, q = dvmdii_round(*b, a, &r); *c = subii(*c, mulii(q, shifti(addii(*b, r),-1))); *b = r; *u2 = subii(*u2, mulii(q, u1)); } /* q t_QFI, return reduced representative and set base change U in Sl2(Z) */ GEN redimagsl2(GEN q, GEN *U) { GEN Q = cgetg(4, t_QFI); pari_sp av = avma, av2; GEN z, u1,u2,v1,v2, a = gel(q,1), b = gel(q,2), c = gel(q,3); long cmp; /* upper bound for size of final (a,b,c) */ (void)new_chunk(2*(lgefint(a) + lgefint(b) + lgefint(c) + 3)); av2 = avma; u1 = gen_1; u2 = gen_0; cmp = abscmpii(a, b); if (cmp < 0) REDBU(a,&b,&c, u1,&u2); else if (cmp == 0 && signe(b) < 0) { /* b = -a */ b = negi(b); u2 = gen_1; } for(;;) { cmp = abscmpii(a, c); if (cmp <= 0) break; swap(a,c); b = negi(b); z = u1; u1 = u2; u2 = negi(z); REDBU(a,&b,&c, u1,&u2); if (gc_needed(av, 1)) { if (DEBUGMEM>1) pari_warn(warnmem, "redimagsl2"); gerepileall(av2, 5, &a,&b,&c, &u1,&u2); } } if (cmp == 0 && signe(b) < 0) { b = negi(b); z = u1; u1 = u2; u2 = negi(z); } avma = av; a = icopy(a); gel(Q,1) = a; b = icopy(b); gel(Q,2) = b; c = icopy(c); gel(Q,3) = c; u1 = icopy(u1); u2 = icopy(u2); av = avma; /* Let q = (A,B,C). q o [u1,u2; v1,v2] = Q implies * [v1,v2] = (1/C) [(b-B)/2 u1 - a u2, c u1 - (b+B)/2 u2] */ z = shifti(subii(b, gel(q,2)), -1); v1 = subii(mulii(z, u1), mulii(a, u2)); v1 = diviiexact(v1, gel(q,3)); z = subii(z, b); v2 = addii(mulii(z, u2), mulii(c, u1)); v2 = diviiexact(v2, gel(q,3)); avma = av; v1 = icopy(v1); v2 = icopy(v2); *U = mkmat2(mkcol2(u1,v1), mkcol2(u2,v2)); return Q; } static GEN setq_b0(ulong a, ulong c) { retmkqfi( utoipos(a), gen_0, utoipos(c) ); } /* assume |sb| = 1 */ static GEN setq(ulong a, ulong b, ulong c, long sb) { retmkqfi( utoipos(a), sb == 1? utoipos(b): utoineg(b), utoipos(c) ); } /* 0 < a, c < 2^BIL, b = 0 */ static GEN redimag_1_b0(ulong a, ulong c) { return (a <= c)? setq_b0(a, c): setq_b0(c, a); } /* 0 < a, c < 2^BIL: single word affair */ static GEN redimag_1(pari_sp av, GEN a, GEN b, GEN c) { ulong ua, ub, uc; long sb; for(;;) { /* at most twice */ long lb = lgefint(b); /* <= 3 after first loop */ if (lb == 2) return redimag_1_b0(a[2],c[2]); if (lb == 3 && uel(b,2) <= (ulong)LONG_MAX) break; REDB(a,&b,&c); if (uel(a,2) <= uel(c,2)) { /* lg(b) <= 3 but may be too large for itos */ long s = signe(b); avma = av; if (!s) return redimag_1_b0(a[2], c[2]); if (a[2] == c[2]) s = 1; return setq(a[2], b[2], c[2], s); } swap(a,c); b = negi(b); } /* b != 0 */ avma = av; ua = a[2]; ub = sb = b[2]; if (signe(b) < 0) sb = -sb; uc = c[2]; if (ua < ub) sREDB(ua, &sb, &uc); else if (ua == ub && sb < 0) sb = (long)ub; while(ua > uc) { lswap(ua,uc); sb = -sb; sREDB(ua, &sb, &uc); } if (!sb) return setq_b0(ua, uc); else { long s = 1; if (sb < 0) { sb = -sb; if (ua != uc) s = -1; } return setq(ua, sb, uc, s); } } static GEN redimag_av(pari_sp av, GEN q) { GEN a = gel(q,1), b = gel(q,2), c = gel(q,3); long cmp, lc = lgefint(c); if (lgefint(a) == 3 && lc == 3) return redimag_1(av, a, b, c); cmp = abscmpii(a, b); if (cmp < 0) REDB(a,&b,&c); else if (cmp == 0 && signe(b) < 0) b = negi(b); for(;;) { cmp = abscmpii(a, c); if (cmp <= 0) break; lc = lgefint(a); /* lg(future c): we swap a & c next */ if (lc == 3) return redimag_1(av, a, b, c); swap(a,c); b = negi(b); /* apply rho */ REDB(a,&b,&c); } if (cmp == 0 && signe(b) < 0) b = negi(b); /* size of reduced Qfb(a,b,c) <= 3 lg(c) + 4 <= 4 lg(c) */ (void)new_chunk(lc<<2); a = icopy(a); b = icopy(b); c = icopy(c); avma = av; retmkqfi(icopy(a), icopy(b), icopy(c)); } GEN redimag(GEN q) { return redimag_av(avma, q); } static GEN rhoimag(GEN x) { GEN a = gel(x,1), b = gel(x,2), c = gel(x,3); int fl = abscmpii(a, c); if (fl <= 0) { int fg = abscmpii(a, b); if (fg >= 0) { x = qfi(a,b,c); if ((!fl || !fg) && signe(gel(x,2)) < 0) setsigne(gel(x,2), 1); return x; } } x = cgetg(4, t_QFI); (void)new_chunk(lgefint(a) + lgefint(b) + lgefint(c) + 3); swap(a,c); b = negi(b); REDB(a, &b, &c); avma = (pari_sp)x; gel(x,1) = icopy(a); gel(x,2) = icopy(b); gel(x,3) = icopy(c); return x; } /* qfr3 / qfr5 */ /* t_QFR are unusable: D, sqrtD, isqrtD are recomputed all the time and the * logarithmic Shanks's distance is costly and hard to control. * qfr3 / qfr5 routines take a container of t_INTs (e.g a t_VEC) as argument, * at least 3 (resp. 5) components [it is a feature that they do not check the * precise type or length of the input]. They return a vector of length 3 * (resp. 5). A qfr3 [a,b,c] contains the form coeffs, in a qfr5 [a,b,c, e,d] * the t_INT e is a binary exponent, d a t_REAL, coding the distance in * multiplicative form: the true distance is obtained from qfr5_dist. * All other qfr routines are obsolete (inefficient) wrappers */ /* static functions are not stack-clean. Unless mentionned otherwise, public * functions are. */ #define EMAX 22 static void fix_expo(GEN x) { if (expo(gel(x,5)) >= (1L << EMAX)) { gel(x,4) = addiu(gel(x,4), 1); shiftr_inplace(gel(x,5), - (1L << EMAX)); } } /* (1/2) log (d * 2^{e * 2^EMAX}). Not stack clean if e != 0 */ GEN qfr5_dist(GEN e, GEN d, long prec) { GEN t = logr_abs(d); if (signe(e)) { GEN u = mulir(e, mplog2(prec)); shiftr_inplace(u, EMAX); t = addrr(t, u); } shiftr_inplace(t, -1); return t; } static void rho_get_BC(GEN *B, GEN *C, GEN b, GEN c, struct qfr_data *S) { GEN t, u; u = shifti(c,1); t = (abscmpii(S->isqrtD,c) >= 0)? S->isqrtD: c; u = remii(addii_sign(t,1, b,signe(b)), u); *B = addii_sign(t, 1, u, -signe(u)); /* |t| - (|t|+b) % |2c| */ if (*B == gen_0) { u = shifti(S->D, -2); setsigne(u, -1); } else u = shifti(addii_sign(sqri(*B),1, S->D,-1), -2); *C = diviiexact(u, c); /* = (B^2-D)/4c */ } /* Not stack-clean */ GEN qfr3_rho(GEN x, struct qfr_data *S) { GEN B, C, b = gel(x,2), c = gel(x,3); rho_get_BC(&B, &C, b, c, S); return mkvec3(c,B,C); } /* Not stack-clean */ GEN qfr5_rho(GEN x, struct qfr_data *S) { GEN B, C, y, b = gel(x,2), c = gel(x,3); long sb = signe(b); rho_get_BC(&B, &C, b, c, S); y = mkvec5(c,B,C, gel(x,4), gel(x,5)); if (sb) { GEN t = subii(sqri(b), S->D); if (sb < 0) t = divir(t, sqrr(subir(b,S->sqrtD))); else t = divri(sqrr(addir(b,S->sqrtD)), t); /* t = (b + sqrt(D)) / (b - sqrt(D)), evaluated stably */ gel(y,5) = mulrr(t, gel(y,5)); fix_expo(y); } return y; } /* Not stack-clean */ GEN qfr_to_qfr5(GEN x, long prec) { return mkvec5(gel(x,1),gel(x,2),gel(x,3),gen_0,real_1(prec)); } /* d0 = initial distance, x = [a,b,c, expo(d), d], d = exp(2*distance) */ GEN qfr5_to_qfr(GEN x, GEN d0) { GEN y; if (lg(x) == 6) { GEN n = gel(x,4), d = absr(gel(x,5)); if (signe(n)) { n = addis(shifti(n, EMAX), expo(d)); setexpo(d, 0); d = logr_abs(d); if (signe(n)) d = addrr(d, mulir(n, mplog2(lg(d0)))); shiftr_inplace(d, -1); d0 = addrr(d0, d); } else if (!gequal1(d)) /* avoid loss of precision */ { d = logr_abs(d); shiftr_inplace(d, -1); d0 = addrr(d0, d); } } y = cgetg(5, t_QFR); gel(y,1) = gel(x,1); gel(y,2) = gel(x,2); gel(y,3) = gel(x,3); gel(y,4) = d0; return y; } /* Not stack-clean */ GEN qfr3_to_qfr(GEN x, GEN d) { GEN z = cgetg(5, t_QFR); gel(z,1) = gel(x,1); gel(z,2) = gel(x,2); gel(z,3) = gel(x,3); gel(z,4) = d; return z; } static int ab_isreduced(GEN a, GEN b, GEN isqrtD) { if (signe(b) > 0 && abscmpii(b, isqrtD) <= 0) { GEN t = addii_sign(isqrtD,1, shifti(a,1),-1); long l = abscmpii(b, t); /* compare |b| and |floor(sqrt(D)) - |2a|| */ if (l > 0 || (l == 0 && signe(t) < 0)) return 1; } return 0; } INLINE int qfr_isreduced(GEN x, GEN isqrtD) { return ab_isreduced(gel(x,1),gel(x,2),isqrtD); } /* Not stack-clean */ GEN qfr5_red(GEN x, struct qfr_data *S) { pari_sp av = avma; while (!qfr_isreduced(x, S->isqrtD)) { x = qfr5_rho(x, S); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"qfr5_red"); x = gerepilecopy(av, x); } } return x; } /* Not stack-clean */ GEN qfr3_red(GEN x, struct qfr_data *S) { pari_sp av = avma; while (!qfr_isreduced(x, S->isqrtD)) { x = qfr3_rho(x, S); if (gc_needed(av,2)) { if (DEBUGMEM>1) pari_warn(warnmem,"qfr3_red"); x = gerepilecopy(av, x); } } return x; } static void get_disc(GEN x, struct qfr_data *S) { if (!S->D) S->D = qfb_disc(x); else if (typ(S->D) != t_INT) pari_err_TYPE("qfr_init",S->D); if (!signe(S->D)) pari_err_DOMAIN("qfr_init", "disc", "=", gen_0,x); } void qfr_data_init(GEN D, long prec, struct qfr_data *S) { S->D = D; S->sqrtD = sqrtr(itor(S->D,prec)); S->isqrtD = truncr(S->sqrtD); } static GEN qfr5_init(GEN x, struct qfr_data *S) { GEN d = gel(x,4); long prec = realprec(d), l = -expo(d); if (l < BITS_IN_LONG) l = BITS_IN_LONG; prec = maxss(prec, nbits2prec(l)); x = qfr_to_qfr5(x,prec); get_disc(x, S); if (!S->sqrtD) S->sqrtD = sqrtr(itor(S->D,prec)); else if (typ(S->sqrtD) != t_REAL) pari_err_TYPE("qfr_init",S->sqrtD); if (!S->isqrtD) { pari_sp av=avma; long e; S->isqrtD = gcvtoi(S->sqrtD,&e); if (e>-2) { avma = av; S->isqrtD = sqrti(S->D); } } else if (typ(S->isqrtD) != t_INT) pari_err_TYPE("qfr_init",S->isqrtD); return x; } static GEN qfr3_init(GEN x, struct qfr_data *S) { get_disc(x, S); if (!S->isqrtD) S->isqrtD = sqrti(S->D); else if (typ(S->isqrtD) != t_INT) pari_err_TYPE("qfr_init",S->isqrtD); return x; } #define qf_NOD 2 #define qf_STEP 1 static GEN redreal0(GEN x, long flag, GEN D, GEN isqrtD, GEN sqrtD) { pari_sp av = avma; struct qfr_data S; GEN d; if (typ(x) != t_QFR) pari_err_TYPE("redreal",x); d = gel(x,4); S.D = D; S.sqrtD = sqrtD; S.isqrtD = isqrtD; x = (flag & qf_NOD)? qfr3_init(x, &S): qfr5_init(x, &S); switch(flag) { case 0: x = qfr5_red(x,&S); break; case qf_NOD: x = qfr3_red(x,&S); break; case qf_STEP: x = qfr5_rho(x,&S); break; case qf_STEP|qf_NOD: x = qfr3_rho(x,&S); break; default: pari_err_FLAG("qfbred"); } return gerepilecopy(av, qfr5_to_qfr(x,d)); } GEN redreal(GEN x) { return redreal0(x,0,NULL,NULL,NULL); } GEN rhoreal(GEN x) { return redreal0(x,qf_STEP,NULL,NULL,NULL); } GEN redrealnod(GEN x, GEN isqrtD) { return redreal0(x,qf_NOD,NULL,isqrtD,NULL); } GEN rhorealnod(GEN x, GEN isqrtD) { return redreal0(x,qf_STEP|qf_NOD,NULL,isqrtD,NULL); } GEN qfbred0(GEN x, long flag, GEN D, GEN isqrtD, GEN sqrtD) { if (typ(x) == t_QFI) return (flag & qf_STEP)? rhoimag(x): redimag(x); return redreal0(x,flag,D,isqrtD,sqrtD); } GEN qfr5_comp(GEN x, GEN y, struct qfr_data *S) { pari_sp av = avma; GEN z = cgetg(6,t_VEC); qfb_comp(z,x,y); if (x == y) { gel(z,4) = shifti(gel(x,4),1); gel(z,5) = sqrr(gel(x,5)); } else { gel(z,4) = addii(gel(x,4),gel(y,4)); gel(z,5) = mulrr(gel(x,5),gel(y,5)); } fix_expo(z); z = qfr5_red(z,S); return gerepilecopy(av,z); } /* Not stack-clean */ GEN qfr3_comp(GEN x, GEN y, struct qfr_data *S) { GEN z = cgetg(4,t_VEC); qfb_comp(z,x,y); return qfr3_red(z, S); } /* valid for t_QFR, qfr3, qfr5 */ static GEN qfr_inv(GEN x) { GEN z = shallowcopy(x); gel(z,2) = negi(gel(z,2)); return z; } /* return x^n. Not stack-clean */ GEN qfr5_pow(GEN x, GEN n, struct qfr_data *S) { GEN y = NULL; long i, m, s = signe(n); if (!s) return qfr5_1(S, lg(gel(x,5))); for (i=lgefint(n)-1; i>1; i--) { m = n[i]; for (; m; m>>=1) { if (m&1) y = y? qfr5_comp(y,x,S): x; if (m == 1 && i == 2) break; x = qfr5_comp(x,x,S); } } return y; } /* return x^n. Not stack-clean */ GEN qfr3_pow(GEN x, GEN n, struct qfr_data *S) { GEN y = NULL; long i, m, s = signe(n); if (!s) return qfr3_1(S); if (s < 0) x = qfr_inv(x); for (i=lgefint(n)-1; i>1; i--) { m = n[i]; for (; m; m>>=1) { if (m&1) y = y? qfr3_comp(y,x,S): x; if (m == 1 && i == 2) break; x = qfr3_comp(x,x,S); } } return y; } GEN qfrpow(GEN x, GEN n) { struct qfr_data S = { NULL, NULL, NULL }; long s = signe(n); pari_sp av = avma; GEN d0; if (!s) return qfr_1(x); if (is_pm1(n)) return s > 0? redreal(x): ginv(x); if (s < 0) x = qfr_inv(x); d0 = gel(x,4); if (!signe(d0)) { x = qfr3_init(x, &S); x = qfr3_pow(x, n, &S); x = qfr3_to_qfr(x, d0); } else { x = qfr5_init(x, &S); x = qfr5_pow(qfr_to_qfr5(x, lg(S.sqrtD)), n, &S); x = qfr5_to_qfr(x, mulri(d0,n)); } return gerepilecopy(av, x); } /* Prime forms attached to prime ideals of degree 1 */ /* assume x != 0 a t_INT, p > 0 * Return a t_QFI, but discriminant sign is not checked: can be used for * real forms as well */ GEN primeform_u(GEN x, ulong p) { GEN c, y = cgetg(4, t_QFI); pari_sp av = avma; ulong b; long s; s = mod8(x); if (signe(x) < 0 && s) s = 8-s; /* 2 or 3 mod 4 */ if (s & 2) pari_err_DOMAIN("primeform", "disc % 4", ">",gen_1, x); if (p == 2) { switch(s) { case 0: b = 0; break; case 1: b = 1; break; case 4: b = 2; break; default: pari_err_SQRTN("primeform", mkintmod(x,utoi(p)) ); b = 0; /* -Wall */ } c = shifti(subsi(s,x), -3); } else { b = Fl_sqrt(umodiu(x,p), p); if (b == ~0UL) pari_err_SQRTN("primeform", mkintmod(x,utoi(p)) ); /* mod(b) != mod2(x) ? */ if ((b ^ s) & 1) b = p - b; c = diviuexact(shifti(subii(sqru(b), x), -2), p); } gel(y,3) = gerepileuptoint(av, c); gel(y,2) = utoi(b); gel(y,1) = utoipos(p); return y; } /* special case: p = 1 return unit form */ GEN primeform(GEN x, GEN p, long prec) { const char *f = "primeform"; pari_sp av; long s, sx = signe(x), sp = signe(p); GEN y, b, absp; if (typ(x) != t_INT) pari_err_TYPE(f,x); if (typ(p) != t_INT) pari_err_TYPE(f,p); if (!sp) pari_err_DOMAIN(f,"p","=",gen_0,p); if (!sx) pari_err_DOMAIN(f,"D","=",gen_0,x); if (lgefint(p) == 3) { ulong pp = p[2]; if (pp == 1) { if (sx < 0) { long r; if (sp < 0) pari_err_IMPL("negative definite t_QFI"); r = mod4(x); if (r && r != 3) pari_err_DOMAIN(f,"disc % 4",">", gen_1,x); return qfi_1_by_disc(x); } y = qfr_1_by_disc(x,prec); if (sp < 0) { gel(y,1) = gen_m1; togglesign(gel(y,3)); } return y; } y = primeform_u(x, pp); if (sx < 0) { if (sp < 0) pari_err_IMPL("negative definite t_QFI"); return y; } if (sp < 0) { togglesign(gel(y,1)); togglesign(gel(y,3)); } return gcopy( qfr3_to_qfr(y, real_0(prec)) ); } s = mod8(x); if (sx < 0) { if (sp < 0) pari_err_IMPL("negative definite t_QFI"); if (s) s = 8-s; y = cgetg(4, t_QFI); } else { y = cgetg(5, t_QFR); gel(y,4) = real_0(prec); } /* 2 or 3 mod 4 */ if (s & 2) pari_err_DOMAIN(f, "disc % 4", ">",gen_1, x); absp = absi_shallow(p); av = avma; b = Fp_sqrt(x, absp); if (!b) pari_err_SQRTN(f, mkintmod(x,absp)); s &= 1; /* s = x mod 2 */ /* mod(b) != mod2(x) ? [Warning: we may have b == 0] */ if ((!signe(b) && s) || mod2(b) != s) b = gerepileuptoint(av, subii(absp,b)); av = avma; gel(y,3) = gerepileuptoint(av, diviiexact(shifti(subii(sqri(b), x), -2), p)); gel(y,2) = b; gel(y,1) = icopy(p); return y; } /* Let M and N in SL2(Z), return (N*M^-1)[,1] */ static GEN SL2_div_mul_e1(GEN N, GEN M) { GEN b = gcoeff(M,2,1), d = gcoeff(M,2,2); GEN p = subii(mulii(gcoeff(N,1,1), d), mulii(gcoeff(N,1,2), b)); GEN q = subii(mulii(gcoeff(N,2,1), d), mulii(gcoeff(N,2,2), b)); return mkvec2(p,q); } /* Let M and N in SL2(Z), return (N*[1,0;0,-1]*M^-1)[,1] */ static GEN SL2_swap_div_mul_e1(GEN N, GEN M) { GEN b = gcoeff(M,2,1), d = gcoeff(M,2,2); GEN p = addii(mulii(gcoeff(N,1,1), d), mulii(gcoeff(N,1,2), b)); GEN q = addii(mulii(gcoeff(N,2,1), d), mulii(gcoeff(N,2,2), b)); return mkvec2(p,q); } /* Test equality modulo GL2 of two reduced forms */ static int GL2_qfb_equal(GEN a, GEN b) { return equalii(gel(a,1),gel(b,1)) && absequalii(gel(a,2),gel(b,2)) && equalii(gel(a,3),gel(b,3)); } static GEN qfbsolve_cornacchia(GEN c, GEN p, int swap) { pari_sp av = avma; GEN M, N; if (kronecker(negi(c), p) < 0 || !cornacchia(c, p, &M,&N)) { avma = av; return gen_0; } return gerepilecopy(av, swap? mkvec2(N,M): mkvec2(M,N)); } GEN qfisolvep(GEN Q, GEN p) { GEN M, N, x,y, a,b,c, d; pari_sp av = avma; if (!signe(gel(Q,2))) { a = gel(Q,1); c = gel(Q,3); /* if principal form, use faster cornacchia */ if (equali1(a)) return qfbsolve_cornacchia(c, p, 0); if (equali1(c)) return qfbsolve_cornacchia(a, p, 1); } d = qfb_disc(Q); if (kronecker(d,p) < 0) return gen_0; a = redimagsl2(Q, &N); if (equali1(gel(a,1))) /* principal form */ { long r; if (!signe(gel(a,2))) { a = qfbsolve_cornacchia(gel(a,3), p, 0); if (a == gen_0) { avma = av; return gen_0; } a = ZM_ZC_mul(N, a); a[0] = evaltyp(t_VEC) | _evallg(3); /* transpose */ return gerepileupto(av, a); } /* x^2 + xy + ((1-d)/4)y^2 = p <==> (2x + y)^2 - d y^2 = 4p */ if (!cornacchia2(negi(d), p, &x, &y)) { avma = av; return gen_0; } x = divis_rem(subii(x,y), 2, &r); if (r) { avma = av; return gen_0; } a = ZM_ZC_mul(N, mkvec2(x,y)); a[0] = evaltyp(t_VEC) | _evallg(3); /* transpose */ return gerepileupto(av, a); } b = redimagsl2(primeform(d, p, 0), &M); if (!GL2_qfb_equal(a,b)) { avma = av; return gen_0; } if (signe(gel(a,2))==signe(gel(b,2))) x = SL2_div_mul_e1(N,M); else x = SL2_swap_div_mul_e1(N,M); return gerepilecopy(av, x); } GEN redrealsl2step(GEN A, GEN d, GEN rd) { pari_sp ltop = avma; GEN N, V = gel(A,1), M = gel(A,2); GEN a = gel(V,1), b = gel(V,2), c = gel(V,3); GEN C = mpabs_shallow(c); GEN t = addii(b, gmax_shallow(rd, C)); GEN r, q = truedvmdii(t, shifti(C,1), &r); b = subii(t, addii(r,b)); a = c; c = truedivii(subii(sqri(b), d), shifti(c,2)); if (signe(a) < 0) togglesign(q); N = mkmat2(gel(M,2), mkcol2(subii(mulii(q, gcoeff(M, 1, 2)), gcoeff(M, 1, 1)), subii(mulii(q, gcoeff(M, 2, 2)), gcoeff(M, 2, 1)))); return gerepilecopy(ltop, mkvec2(mkvec3(a,b,c),N)); } GEN redrealsl2(GEN V, GEN d, GEN rd) { pari_sp ltop = avma; GEN M, u1, u2, v1, v2; GEN a = gel(V,1), b = gel(V,2), c = gel(V,3); u1 = v2 = gen_1; v1 = u2 = gen_0; while (!ab_isreduced(a,b,rd)) { GEN C = mpabs_shallow(c); GEN t = addii(b, gmax_shallow(rd,C)); GEN r, q = truedvmdii(t, shifti(C,1), &r); b = subii(t, addii(r,b)); a = c; c = truedivii(subii(sqri(b), d), shifti(c,2)); if (signe(a) < 0) togglesign(q); r = u1; u1 = v1; v1 = subii(mulii(q, v1), r); r = u2; u2 = v2; v2 = subii(mulii(q, v2), r); if (gc_needed(ltop, 1)) { if (DEBUGMEM>1) pari_warn(warnmem,"redrealsl2"); gerepileall(ltop, 7, &a,&b,&c,&u1,&u2,&v1,&v2); } } M = mkmat2(mkcol2(u1,u2), mkcol2(v1,v2)); return gerepilecopy(ltop, mkvec2(mkvec3(a,b,c), M)); } GEN qfbredsl2(GEN q, GEN S) { GEN v, D, isD; pari_sp av; switch(typ(q)) { case t_QFI: if (S) pari_err_TYPE("qfbredsl2",S); v = cgetg(3,t_VEC); gel(v,1) = redimagsl2(q, &gel(v,2)); return v; case t_QFR: av = avma; if (S) { if (typ(S) != t_VEC || lg(S) != 3) pari_err_TYPE("qfbredsl2",S); D = gel(S,1); isD = gel(S,2); if (typ(D) != t_INT || signe(D) <= 0 || typ(isD) != t_INT) pari_err_TYPE("qfbredsl2",S); } else { D = qfb_disc(q); isD = sqrtint(D); } v = redrealsl2(q,D,isD); gel(v,1) = qfr3_to_qfr(gel(v,1), real_0(precision(gel(q,4)))); return gerepilecopy(av, v); default: pari_err_TYPE("qfbredsl2",q); return NULL; } } GEN qfrsolvep(GEN Q, GEN p) { pari_sp ltop = avma, btop; GEN N, P, P1, P2, M, rd, d = qfb_disc(Q); if (kronecker(d, p) < 0) { avma = ltop; return gen_0; } rd = sqrti(d); M = N = redrealsl2(Q, d,rd); P = primeform(d, p, DEFAULTPREC); P1 = redrealsl2(P, d,rd); togglesign( gel(P,2) ); P2 = redrealsl2(P, d,rd); btop = avma; for(;;) { if (ZV_equal(gel(M,1), gel(P1,1))) { N = gel(P1,2); break; } if (ZV_equal(gel(M,1), gel(P2,1))) { N = gel(P2,2); break; } M = redrealsl2step(M, d,rd); if (ZV_equal(gel(M,1), gel(N,1))) { avma = ltop; return gen_0; } if (gc_needed(btop, 1)) M = gerepileupto(btop, M); } return gerepilecopy(ltop, SL2_div_mul_e1(gel(M,2),N)); } GEN qfbsolve(GEN Q,GEN n) { if (typ(n)!=t_INT) pari_err_TYPE("qfbsolve",n); switch(typ(Q)) { case t_QFI: return qfisolvep(Q,n); case t_QFR: return qfrsolvep(Q,n); default: pari_err_TYPE("qfbsolve",Q); return NULL; /* LCOV_EXCL_LINE */ } } /* 1 if there exists x,y such that x^2 + dy^2 = p [prime], 0 otherwise */ long cornacchia(GEN d, GEN p, GEN *px, GEN *py) { pari_sp av = avma, av2; GEN a, b, c, L, r; if (typ(d) != t_INT) pari_err_TYPE("cornacchia", d); if (typ(p) != t_INT) pari_err_TYPE("cornacchia", p); if (signe(d) <= 0) pari_err_DOMAIN("cornacchia", "d","<=",gen_0,d); *px = *py = gen_0; b = subii(p, d); if (signe(b) < 0) return 0; if (signe(b) == 0) { avma = av; *py = gen_1; return 1; } b = Fp_sqrt(b, p); /* sqrt(-d) */ if (!b) { avma = av; return 0; } if (abscmpii(shifti(b,1), p) > 0) b = subii(b,p); a = p; L = sqrti(p); av2 = avma; while (abscmpii(b, L) > 0) { r = remii(a, b); a = b; b = r; if (gc_needed(av2, 1)) { if (DEBUGMEM>1) pari_warn(warnmem,"cornacchia"); gerepileall(av2, 2, &a,&b); } } a = subii(p, sqri(b)); c = dvmdii(a, d, &r); if (r != gen_0 || !Z_issquareall(c, &c)) { avma = av; return 0; } avma = av; *px = icopy(b); *py = icopy(c); return 1; } static long cornacchia2_helper(long av, GEN d, GEN p, GEN b, GEN px4, GEN *px, GEN *py) { pari_sp av2 = avma; GEN a, c, r, L; long k = mod4(d); if (!signe(b)) { /* d = p,2p,3p,4p */ avma = av; if (absequalii(d, px4)){ *py = gen_1; return 1; } if (absequalii(d, p)) { *py = gen_2; return 1; } return 0; } if (mod2(b) != (k & 1)) b = subii(p,b); a = shifti(p,1); L = sqrti(px4); av2 = avma; while (cmpii(b, L) > 0) { r = remii(a, b); a = b; b = r; if (gc_needed(av2, 1)) { if (DEBUGMEM>1) pari_warn(warnmem,"cornacchia"); gerepileall(av2, 2, &a,&b); } } a = subii(px4, sqri(b)); c = dvmdii(a, d, &r); if (r != gen_0 || !Z_issquareall(c, &c)) { avma = av; return 0; } avma = av; *px = icopy(b); *py = icopy(c); return 1; } /* 1 if there exists x,y such that x^2 + dy^2 = 4p [p prime], 0 otherwise */ long cornacchia2(GEN d, GEN p, GEN *px, GEN *py) { pari_sp av = avma; GEN b, px4; long k; if (typ(d) != t_INT) pari_err_TYPE("cornacchia2", d); if (typ(p) != t_INT) pari_err_TYPE("cornacchia2", p); if (signe(d) <= 0) pari_err_DOMAIN("cornacchia2", "d","<=",gen_0,d); *px = *py = gen_0; k = mod4(d); if (k == 1 || k == 2) pari_err_DOMAIN("cornacchia2","-d mod 4", ">",gen_1,d); px4 = shifti(p,2); if (abscmpii(px4, d) < 0) { avma = av; return 0; } if (absequaliu(p, 2)) { avma = av; switch (itou_or_0(d)) { case 4: *px = gen_2; break; case 7: *px = gen_1; break; default: return 0; } *py = gen_1; return 1; } b = Fp_sqrt(negi(d), p); if (!b) { avma = av; return 0; } return cornacchia2_helper(av, d, p, b, px4, px, py); } /* 1 if there exists x,y such that x^2 + dy^2 = 4p [p prime], 0 otherwise */ long cornacchia2_sqrt(GEN d, GEN p, GEN b, GEN *px, GEN *py) { pari_sp av = avma; GEN px4; *px = *py = gen_0; px4 = shifti(p,2); if (abscmpii(px4, d) < 0) { avma = av; return 0; } return cornacchia2_helper(av, d, p, b, px4, px, py); } pari-2.11.2/src/basemath/subgroup.c0000644000175000017500000003774213326135265015566 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" typedef struct slist { struct slist *next; long *data; long prec; } slist; typedef struct { GEN cyc, gen; ulong count; slist *list; } sublist_t; /* SUBGROUPS * G = Gp x I, with Gp a p-Sylow (I assumed small). * Compute subgroups of I by recursive calls * Loop through subgroups Hp of Gp using Birkhoff's algorithm. * If (I is non trivial) * lift Hp to G (mul by exponent of I) * for each subgp of I, lift it to G (mult by exponent of Gp) * consider the group generated by the two subgroups (concat) * * type(H) = mu --> H = Z/p^mu[1] x ... x Z/p^mu[len(mu)] */ typedef struct subgp_iter { long *M, *L; /* mu = p-subgroup type, lambda = p-group type */ GEN *powlist; /* [i] = p^i, i = 0.. */ long *c, *maxc; GEN *a, *maxa, **g, **maxg; long *available; GEN **H; /* p-subgroup of type mu, in matrix form */ GEN cyc; /* cyclic factors of G */ GEN subq;/* subgrouplist(I) */ GEN subqpart; /* J in subq s.t [I:J][Gp:Hp] <= indexbound */ GEN bound; /* if != NULL, impose a "bound" on [G:H] (see boundtype) */ long boundtype; long countsub; /* number of subgroups of type M (so far) */ long count; /* number of p-subgroups so far [updated when M completed] */ GEN expoI; /* exponent of I */ long(*fun)(void*, GEN); /* callback applied to each subgroup */ void *fundata; /* data for fun */ long stop; } subgp_iter; /* MAX: [G:H] <= bound, EXACT: [G:H] = bound, TYPE: type(H) = bound */ enum { b_NONE, b_MAX, b_EXACT, b_TYPE }; #define len(x) (x)[0] #define setlen(x,l) len(x)=(l) static void printtyp(const long *typ) /*Used only for ddebugging */ { long i, l = len(typ); for (i=1; i<=l; i++) err_printf(" %ld ",typ[i]); err_printf("\n"); } /* compute conjugate partition of typ */ static long* conjugate(long *typ) { long *t, i, k = len(typ), l, last; if (!k) { t = new_chunk(1); setlen(t,0); return t; } l = typ[1]; t = new_chunk(l+2); t[1] = k; last = k; for (i=2; i<=l; i++) { while (typ[last] < i) last--; t[i] = last; } t[i] = 0; setlen(t,l); return t; } /* ----subgp_iter 'fun' attached to subgrouplist ------------- */ static void addcell(sublist_t *S, GEN H) { long *pt,i,j,L, n = lg(H)-1; slist *cell; L = 3; for (j=1; j<=n; j++) { /* H in HNF, largest entries are on diagonal */ long l = lgefint(gcoeff(H,j,j)); if (l > L) L = l; } L -= 2; cell = (slist*) pari_malloc(sizeof(slist) + ((n*(n+1)) >> 1) * sizeof(long) * L); S->list->next = cell; cell->data = pt = (long*) (cell + 1); cell->prec = L; for (j=1; j<=n; j++) for(i=1; i<=j; i++) { GEN z = gcoeff(H,i,j); long h, lz = lgefint(z) - 2; for (h = 0; h < L - lz; h++) *pt++ = 0; for (h = 0; h < lz; h++) *pt++ = z[h+2]; } S->list = cell; S->count++; } static long list_fun(void *E, GEN x) { sublist_t *S = (sublist_t*)E; GEN H = ZM_hnfmodid(x, S->cyc); if (!S->gen || subgroup_conductor_ok(H, S->gen)) addcell(S, H); return 0; } /* -------------------------------------------------------------- */ /* treat subgroup Hp (not in HNF, T->fun should do it if desired) */ static void treatsub(subgp_iter *T, GEN H) { long i; if (!T->subq) {T->stop = T->fun(T->fundata, H); T->countsub++; } else { /* not a p group, add the trivial part */ GEN Hp = gmul(T->expoI, H); /* lift H to G */ long n = lg(T->subqpart)-1; for (i=1; i<=n; i++) if (T->fun(T->fundata, shallowconcat(Hp, gel(T->subqpart,i)))) { T->stop = 1; break; } T->countsub += n; } } /* x a t_INT, x++. Could be optimized... */ static void inc(GEN x) { affii(addiu(x,1), x); } /* assume t>0 and l>1 */ static void dogroup(subgp_iter *T) { const GEN *powlist = T->powlist; long *M = T->M; long *L = T->L; long *c = T->c; GEN *a = T->a, *maxa = T->maxa; GEN **g = T->g, **maxg = T->maxg; GEN **H = T->H; pari_sp av; long i,j,k,r,n,t2,ind, t = len(M), l = len(L); t2 = (l==t)? t-1: t; n = t2 * l - (t2*(t2+1))/2; /* number of gamma_ij */ for (i=1, r=t+1; ; i++) { if (T->available[i]) c[r++] = i; if (r > l) break; } if (DEBUGLEVEL>6) { err_printf(" column selection:"); printtyp(c); } /* a/g and maxa/maxg access the same data indexed differently */ for (ind=0,i=1; i<=t; ind+=(l-i),i++) { maxg[i] = maxa + (ind - (i+1)); /* only access maxg[i][i+1..l] */ g[i] = a + (ind - (i+1)); for (r=i+1; r<=l; r++) if (c[r] < c[i]) maxg[i][r] = powlist[M[i]-M[r]-1]; else if (L[c[r]] < M[i]) maxg[i][r] = powlist[L[c[r]]-M[r]]; else maxg[i][r] = powlist[M[i]-M[r]]; } /* allocate correct lg */ for (i = 0; i<= n-1; i++) a[i] = icopy(maxa[i]); affui(0, a[n-1]); for (i=0; istop;) { inc(a[n-1]); if (cmpii(a[n-1], maxa[n-1]) > 0) { j=n-2; while (j>=0 && equalii(a[j], maxa[j])) j--; if (j < 0) return; inc(a[j]); for (k=j+1; k 0) e = mulii(e, powlist[d]); H[i][c[r]] = e; } } treatsub(T, (GEN)H); avma = av; } } /* T->c[1],...,T->c[r-1] filled */ static void loop(subgp_iter *T, long r) { long j; if (r > len(T->M)) { pari_sp av = avma; dogroup(T); avma = av; return; } if (r!=1 && (T->M[r-1] == T->M[r])) j = T->c[r-1]+1; else j = 1; for ( ; j<=T->maxc[r]; j++) if (T->available[j]) { T->c[r] = j; T->available[j] = 0; loop(T, r+1); T->available[j] = 1; } } static void dopsubtyp(subgp_iter *T) { pari_sp av = avma; long i,r, l = len(T->L), t = len(T->M); if (!t) { treatsub(T, mkmat( zerocol(l) )); avma = av; return; } if (l==1) /* imply t = 1 */ { GEN p1 = gtomat(T->powlist[T->L[1]-T->M[1]]); treatsub(T, p1); avma = av; return; } T->c = new_chunk(l+1); setlen(T->c, l); T->maxc = new_chunk(l+1); T->available = new_chunk(l+1); T->a = (GEN*)new_chunk(l*(t+1)); T->maxa= (GEN*)new_chunk(l*(t+1)); T->g = (GEN**)new_chunk(t+1); T->maxg = (GEN**)new_chunk(t+1); if (DEBUGLEVEL>4) { err_printf(" subgroup:"); printtyp(T->M); } for (i=1; i<=t; i++) { for (r=1; r<=l; r++) if (T->M[i] > T->L[r]) break; T->maxc[i] = r-1; } T->H = (GEN**)cgetg(t+1, t_MAT); for (i=1; i<=t; i++) T->H[i] = (GEN*)cgetg(l+1, t_COL); for (i=1; i<=l; i++) T->available[i]=1; for (i=1; i<=t; i++) T->c[i]=0; /* go through all column selections */ loop(T, 1); avma = av; return; } static long weight(long *typ) { long i, l = len(typ), w = 0; for (i=1; i<=l; i++) w += typ[i]; return w; } static void dopsub(subgp_iter *T, GEN p, GEN indexsubq) { long *M, *L = T->L; long w,i,j,k,lsubq, wG = weight(L), wmin = 0, wmax = wG, n = len(L); if (DEBUGLEVEL>4) { err_printf("\ngroup:"); printtyp(L); } T->count = 0; switch(T->boundtype) { case b_MAX: /* upper bound */ wmin = (long) (wG - (log(gtodouble(T->bound)) / log(gtodouble(p)))); if (cmpii(powiu(p, wG - wmin), T->bound) > 0) wmin++; break; case b_EXACT: /* exact value */ wmin = wmax = wG - Z_pval(T->bound, p); break; } T->M = M = new_chunk(n+1); if (T->subq) { lsubq = lg(T->subq); T->subqpart = T->bound? cgetg(lsubq, t_VEC): T->subq; } else lsubq = 0; /* -Wall */ M[1] = -1; for (i=2; i<=n; i++) M[i]=0; for(;!T->stop;) /* go through all vectors mu_{i+1} <= mu_i <= lam_i */ { M[1]++; if (M[1] > L[1]) { for (j=2; j<=n; j++) if (M[j] < L[j] && M[j] < M[j-1]) break; if (j > n) return; M[j]++; for (k=1; k= wmin && w <= wmax) { GEN p1 = gen_1; if (T->subq && T->bound) /* G not a p-group */ { pari_sp av = avma; GEN indexH = powiu(p, wG - w); GEN B = divii(T->bound, indexH); k = 1; for (i=1; isubqpart[k++] = T->subq[i]; setlg(T->subqpart, k); avma = av; } if (DEBUGLEVEL>4) { long *Lp = conjugate(L); long *Mp = conjugate(M); GEN BINMAT = matqpascal(len(L)+1, p); if (DEBUGLEVEL>7) { err_printf(" lambda = "); printtyp(L); err_printf(" lambda'= "); printtyp(Lp); err_printf(" mu = "); printtyp(M); err_printf(" mu'= "); printtyp(Mp); } for (j=1; j<=len(Mp); j++) { p1 = mulii(p1, powiu(p, Mp[j+1]*(Lp[j]-Mp[j]))); p1 = mulii(p1, gcoeff(BINMAT, Lp[j]-Mp[j+1]+1, Mp[j]-Mp[j+1]+1)); } err_printf(" alpha_lambda(mu,p) = %Ps\n",p1); } T->countsub = 0; dopsubtyp(T); T->count += T->countsub; if (DEBUGLEVEL>4) { err_printf(" countsub = %ld\n", T->countsub); if (T->subq) p1 = muliu(p1,lg(T->subqpart)-1); if (!absequaliu(p1,T->countsub)) { err_printf(" alpha = %Ps\n",p1); pari_err_BUG("forsubgroup (alpha != countsub)"); } } } } } static void parse_bound(subgp_iter *T) { GEN b, B = T->bound; if (!B) { T->boundtype = b_NONE; return; } switch(typ(B)) { case t_INT: /* upper bound */ T->boundtype = b_MAX; break; case t_VEC: /* exact value */ b = gel(B,1); if (lg(B) != 2 || typ(b) != t_INT) pari_err_TYPE("subgroup", B); T->boundtype = b_EXACT; T->bound = b; break; case t_COL: /* exact type */ pari_err_IMPL("exact type in subgrouplist"); if (lg(B) > len(T->L)+1) pari_err_TYPE("subgroup",B); T->boundtype = b_TYPE; break; default: pari_err_TYPE("subgroup",B); } if (signe(T->bound) <= 0) pari_err_DOMAIN("subgroup", "index bound", "<=", gen_0, T->bound); } static GEN expand_sub(GEN x, long n) { long i,j, m = lg(x); GEN p = matid(n-1), q,c; for (i=1; icyc; long i,j,k,imax,lprim, n = lg(cyc); if (typ(cyc) != t_VEC) { if (typ(cyc) != t_MAT) pari_err_TYPE("forsubgroup",cyc); cyc = RgM_diagonal_shallow(cyc); } for (i=1; iboundtype) { case b_EXACT: if (!is_pm1(T->bound)) break; default: T->fun(T->fundata, cyc); } avma = av; return; } if (!signe(gel(cyc,1))) pari_err_TYPE("forsubgroup [infinite group]", cyc); fa = Z_factor(gel(cyc,1)); primlist = gel(fa,1); listL = cgetg_copy(primlist, &lprim); imax = k = 0; for (i=1; i k) { k = j; imax = i; } gel(listL,i) = L; } L = gel(listL,imax); p = gel(primlist,imax); k = L[1]; T->L = L; T->powlist = (GEN*)init_powlist(k, p); B = T->bound; parse_bound(T); if (lprim == 2) { T->subq = NULL; if (T->boundtype == b_EXACT) { (void)Z_pvalrem(T->bound,p,&B); if (!is_pm1(B)) { avma = av; return; } } } else { /* not a p-group */ GEN cycI = leafcopy(cyc); long lsubq; for (i=1; ipowlist[L[i]]); if (is_pm1(gel(cycI,i))) break; } setlg(cycI, i); /* cyclic factors of I */ if (T->boundtype == b_EXACT) { (void)Z_pvalrem(T->bound,p,&B); B = mkvec(B); } T->expoI = gel(cycI,1); T->subq = subgrouplist_i(cycI, B, T->expoI, NULL); lsubq = lg(T->subq); for (i=1; isubq,i) = expand_sub(gel(T->subq,i), n); if (T->bound) { indexsubq = cgetg(lsubq,t_VEC); for (i=1; isubq,i)); } /* lift subgroups of I to G */ for (i=1; isubq,i) = gmul(T->powlist[k],gel(T->subq,i)); if (DEBUGLEVEL>6) err_printf("(lifted) subgp of prime to %Ps part:\n%Ps\n",p, T->subq); } dopsub(T, p,indexsubq); if (DEBUGLEVEL>4) { err_printf("nb subgroup = %ld\n",T->count); err_flush(); } avma = av; } static GEN get_snf(GEN x, long *N) { GEN cyc; long n; switch(typ(x)) { case t_MAT: if (!RgM_isdiagonal(x)) return NULL; cyc = RgM_diagonal_shallow(x); break; case t_VEC: if (lg(x) == 4 && typ(gel(x,2)) == t_VEC) x = gel(x,2); case t_COL: cyc = leafcopy(x); break; default: return NULL; } *N = lg(cyc)-1; for (n = *N; n > 0; n--) /* take care of trailing 1s */ { GEN c = gel(cyc,n); if (typ(c) != t_INT || signe(c) <= 0) return NULL; if (!is_pm1(c)) break; } setlg(cyc, n+1); for ( ; n > 0; n--) { GEN c = gel(cyc,n); if (typ(c) != t_INT || signe(c) <= 0) return NULL; } return cyc; } void forsubgroup(void *E, long call(void*, GEN), GEN cyc, GEN bound) { subgp_iter T; long N; T.fun = call; T.cyc = get_snf(cyc,&N); if (!T.cyc) pari_err_TYPE("forsubgroup",cyc); T.bound = bound; T.fundata = E; T.stop = 0; subgroup_engine(&T); } void forsubgroup0(GEN cyc, GEN bound, GEN code) { push_lex(gen_0, code); forsubgroup((void*)code, &gp_evalvoid, cyc, bound); pop_lex(1); } static GEN packtoi(long *pt, long L) { long i, l; GEN z; for (i=0; inext; pari_free(list); pt = sublist->data; L = sublist->prec; H = cgetg(N+1,t_MAT); gel(z,ii) = H; for (j=1; j<=n; j++) { gel(H,j) = cgetg(N+1, t_COL); for (i=1; i<=j; i++) { gcoeff(H,i,j) = packtoi(pt, L); pt += L; } for ( ; i<=N; i++) gcoeff(H,i,j) = gen_0; } for ( ; j<=N; j++) gel(H,j) = col_ei(N, j); } pari_free(sublist); return z; } GEN subgrouplist(GEN cyc, GEN bound) { return subgrouplist_i(cyc,bound,NULL,NULL); } GEN subgroupcondlist(GEN cyc, GEN bound, GEN L) { return subgrouplist_i(cyc,bound,NULL,L); } pari-2.11.2/src/basemath/trans2.c0000644000175000017500000016007113457553246015131 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** TRANSCENDENTAL FUNCTIONS **/ /** (part 2) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" GEN trans_fix_arg(long *prec, GEN *s0, GEN *sig, GEN *tau, pari_sp *av, GEN *res) { GEN p1, s = *s0 = cxtoreal(*s0); long l; l = precision(s); if (!l) l = *prec; if (l < LOWDEFAULTPREC) l = LOWDEFAULTPREC; *res = cgetc(l); *av = avma; if (typ(s) == t_COMPLEX) { /* s = sig + i t */ s = cxtofp(s, l+EXTRAPRECWORD); *sig = gel(s,1); *tau = gel(s,2); } else /* real number */ { *sig = s = gtofp(s, l+EXTRAPRECWORD); *tau = gen_0; p1 = trunc2nr(s, 0); if (!signe(subri(s,p1))) *s0 = p1; } *prec = l; return s; } /********************************************************************/ /** **/ /** ARCTANGENT **/ /** **/ /********************************************************************/ /* atan(b/a), real a and b, suitable for gerepileupto */ static GEN atan2_agm(GEN a, GEN b, long prec) { return gel(logagmcx(mkcomplex(a, b), prec), 2); } static GEN mpatan(GEN x) { long l, l1, l2, n, m, i, lp, e, s, sx = signe(x); pari_sp av0, av; double alpha, beta, delta; GEN y, p1, p2, p3, p4, p5, unr; int inv; if (!sx) return real_0_bit(expo(x)); l = lp = realprec(x); if (absrnz_equal1(x)) { /* |x| = 1 */ y = Pi2n(-2, l+EXTRAPRECWORD); if (sx < 0) setsigne(y,-1); return y; } if (l > AGM_ATAN_LIMIT) { av = avma; return gerepileuptoleaf(av, atan2_agm(gen_1, x, l)); } e = expo(x); inv = (e >= 0); /* = (|x| > 1 ) */ if (e > 0) lp += nbits2extraprec(e); y = cgetr(lp); av0 = avma; p1 = rtor(x, l+EXTRAPRECWORD); setabssign(p1); /* p1 = |x| */ if (inv) p1 = invr(p1); e = expo(p1); if (e < -100) alpha = 1.65149612947 - e; /* log_2(Pi) - e */ else alpha = log2(M_PI / atan(rtodbl(p1))); beta = (double)(prec2nbits(l)>>1); delta = 1 + beta - alpha/2; if (delta <= 0) { n = 1; m = 0; } else { double fi = alpha-2; if (delta >= fi*fi) { double t = 1 + sqrt(delta); n = (long)t; m = (long)(t - fi); } else { n = (long)(1+beta/fi); m = 0; } } l2 = l + nbits2extraprec(m); p2 = rtor(p1, l2); av = avma; for (i=1; i<=m; i++) { p5 = addsr(1, sqrr(p2)); setprec(p5,l2); p5 = addsr(1, sqrtr_abs(p5)); setprec(p5,l2); affrr(divrr(p2,p5), p2); avma = av; } p3 = sqrr(p2); l1 = minss(LOWDEFAULTPREC+EXTRAPRECWORD, l2); /* l1 increases to l2 */; unr = real_1(l2); setprec(unr,l1); p4 = cgetr(l2); setprec(p4,l1); affrr(divru(unr,2*n+1), p4); s = 0; e = expo(p3); av = avma; for (i = n; i > 1; i--) /* n >= 1. i = 1 done outside for efficiency */ { setprec(p3,l1); p5 = mulrr(p4,p3); l1 += dvmdsBIL(s - e, &s); if (l1 > l2) l1 = l2; setprec(unr,l1); p5 = subrr(divru(unr,2*i-1), p5); setprec(p4,l1); affrr(p5,p4); avma = av; } setprec(p3, l2); p5 = mulrr(p4,p3); /* i = 1 */ setprec(unr,l2); p4 = subrr(unr, p5); p4 = mulrr(p2,p4); shiftr_inplace(p4, m); if (inv) p4 = subrr(Pi2n(-1, lp), p4); if (sx < 0) togglesign(p4); affrr_fixlg(p4,y); avma = av0; return y; } GEN gatan(GEN x, long prec) { pari_sp av; GEN a, y; switch(typ(x)) { case t_REAL: return mpatan(x); case t_COMPLEX: /* atan(x) = -i atanh(ix) */ if (ismpzero(gel(x,2))) return gatan(gel(x,1), prec); av = avma; return gerepilecopy(av, mulcxmI(gatanh(mulcxI(x),prec))); default: av = avma; if (!(y = toser_i(x))) break; if (valp(y) < 0) pari_err_DOMAIN("atan","valuation", "<", gen_0, x); if (lg(y)==2) return gerepilecopy(av, y); /* lg(y) > 2 */ a = integser(gdiv(derivser(y), gaddsg(1,gsqr(y)))); if (!valp(y)) a = gadd(a, gatan(gel(y,2),prec)); return gerepileupto(av, a); } return trans_eval("atan",gatan,x,prec); } /********************************************************************/ /** **/ /** ARCSINE **/ /** **/ /********************************************************************/ /* |x| < 1, x != 0 */ static GEN mpasin(GEN x) { pari_sp av = avma; GEN z, a = sqrtr(subsr(1, sqrr(x))); if (realprec(x) > AGM_ATAN_LIMIT) z = atan2_agm(a, x, realprec(x)); else z = mpatan(divrr(x, a)); return gerepileuptoleaf(av, z); } static GEN mpacosh(GEN x); GEN gasin(GEN x, long prec) { long sx; pari_sp av; GEN a, y, p1; switch(typ(x)) { case t_REAL: sx = signe(x); if (!sx) return real_0_bit(expo(x)); if (absrnz_equal1(x)) { /* |x| = 1 */ if (sx > 0) return Pi2n(-1, realprec(x)); /* 1 */ y = Pi2n(-1, realprec(x)); setsigne(y, -1); return y; /* -1 */ } if (expo(x) < 0) return mpasin(x); y = cgetg(3,t_COMPLEX); gel(y,1) = Pi2n(-1, realprec(x)); gel(y,2) = mpacosh(x); if (sx < 0) togglesign(gel(y,1)); else togglesign(gel(y,2)); return y; case t_COMPLEX: /* asin(z) = -i asinh(iz) */ if (ismpzero(gel(x,2))) return gasin(gel(x,1), prec); av = avma; return gerepilecopy(av, mulcxmI(gasinh(mulcxI(x), prec))); default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) return gerepilecopy(av, y); /* lg(y) > 2*/ if (valp(y) < 0) pari_err_DOMAIN("asin","valuation", "<", gen_0, x); p1 = gsubsg(1,gsqr(y)); if (gequal0(p1)) { GEN t = Pi2n(-1,prec); if (gsigne(gel(y,2)) < 0) setsigne(t, -1); return gerepileupto(av, scalarser(t, varn(y), valp(p1)>>1)); } p1 = gdiv(derivser(y), gsqrt(p1,prec)); a = integser(p1); if (!valp(y)) a = gadd(a, gasin(gel(y,2),prec)); return gerepileupto(av, a); } return trans_eval("asin",gasin,x,prec); } /********************************************************************/ /** **/ /** ARCCOSINE **/ /** **/ /********************************************************************/ static GEN acos0(long e) { return Pi2n(-1, nbits2prec(e<0? -e: 1)); } /* |x| < 1, x != 0 */ static GEN mpacos(GEN x) { pari_sp av = avma; GEN z, a = sqrtr(subsr(1, sqrr(x))); if (realprec(x) > AGM_ATAN_LIMIT) z = atan2_agm(x, a, realprec(x)); else { z = mpatan(divrr(a, x)); if (signe(x) < 0) z = addrr(mppi(realprec(z)), z); } return gerepileuptoleaf(av, z); } GEN gacos(GEN x, long prec) { long sx; pari_sp av; GEN a, y, p1; switch(typ(x)) { case t_REAL: sx = signe(x); if (!sx) return acos0(expo(x)); if (absrnz_equal1(x)) /* |x| = 1 */ return sx > 0? real_0_bit( -(bit_prec(x)>>1) ) : mppi(realprec(x)); if (expo(x) < 0) return mpacos(x); y = cgetg(3,t_COMPLEX); p1 = mpacosh(x); if (sx < 0) { gel(y,1) = mppi(realprec(x)); togglesign(p1); } else gel(y,1) = gen_0; gel(y,2) = p1; return y; case t_COMPLEX: if (ismpzero(gel(x,2))) return gacos(gel(x,1), prec); av = avma; p1 = gadd(x, mulcxI(gsqrt(gsubsg(1,gsqr(x)), prec))); y = glog(p1,prec); /* log(x + I*sqrt(1-x^2)) */ return gerepilecopy(av, mulcxmI(y)); default: av = avma; if (!(y = toser_i(x))) break; if (valp(y) < 0) pari_err_DOMAIN("acos","valuation", "<", gen_0, x); if (lg(y) > 2) { p1 = gsubsg(1,gsqr(y)); if (gequal0(p1)) { avma = av; return zeroser(varn(y), valp(p1)>>1); } p1 = integser(gdiv(gneg(derivser(y)), gsqrt(p1,prec))); /*y(t) = 1+O(t)*/ if (gequal1(gel(y,2)) && !valp(y)) return gerepileupto(av, p1); } else p1 = y; a = (lg(y)==2 || valp(y))? Pi2n(-1, prec): gacos(gel(y,2),prec); return gerepileupto(av, gadd(a,p1)); } return trans_eval("acos",gacos,x,prec); } /********************************************************************/ /** **/ /** ARGUMENT **/ /** **/ /********************************************************************/ /* we know that x and y are not both 0 */ static GEN mparg(GEN x, GEN y) { long prec, sx = signe(x), sy = signe(y); GEN z; if (!sy) { if (sx > 0) return real_0_bit(expo(y) - expo(x)); return mppi(realprec(x)); } prec = realprec(y); if (prec < realprec(x)) prec = realprec(x); if (!sx) { z = Pi2n(-1, prec); if (sy < 0) setsigne(z,-1); return z; } if (expo(x)-expo(y) > -2) { z = mpatan(divrr(y,x)); if (sx > 0) return z; return addrr_sign(z, signe(z), mppi(prec), sy); } z = mpatan(divrr(x,y)); return addrr_sign(z, -signe(z), Pi2n(-1, prec), sy); } static GEN rfix(GEN x,long prec) { switch(typ(x)) { case t_INT: return itor(x, prec); case t_FRAC: return fractor(x, prec); case t_REAL: break; default: pari_err_TYPE("rfix (conversion to t_REAL)",x); } return x; } static GEN cxarg(GEN x, GEN y, long prec) { pari_sp av = avma; x = rfix(x,prec); y = rfix(y,prec); return gerepileuptoleaf(av, mparg(x,y)); } GEN garg(GEN x, long prec) { long l; if (gequal0(x)) pari_err_DOMAIN("arg", "argument", "=", gen_0, x); switch(typ(x)) { case t_REAL: prec = realprec(x); /* fall through */ case t_INT: case t_FRAC: return (gsigne(x)>0)? real_0(prec): mppi(prec); case t_COMPLEX: l = precision(x); if (l) prec = l; return cxarg(gel(x,1),gel(x,2),prec); } return trans_eval("arg",garg,x,prec); } /********************************************************************/ /** **/ /** HYPERBOLIC COSINE **/ /** **/ /********************************************************************/ static GEN mpcosh(GEN x) { pari_sp av; GEN z; if (!signe(x)) { /* 1 + x */ long e = expo(x); return e >= 0? real_0_bit(e): real_1_bit(-e); } av = avma; z = mpexp(x); z = addrr(z, invr(z)); shiftr_inplace(z, -1); return gerepileuptoleaf(av, z); } GEN gcosh(GEN x, long prec) { pari_sp av; GEN y, p1; switch(typ(x)) { case t_REAL: return mpcosh(x); case t_COMPLEX: if (isintzero(gel(x,1))) return gcos(gel(x,2),prec); /* fall through */ case t_PADIC: av = avma; p1 = gexp(x,prec); p1 = gadd(p1, ginv(p1)); return gerepileupto(av, gmul2n(p1,-1)); default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y) && valp(y) == 0) return gerepilecopy(av, y); p1 = gexp(y,prec); p1 = gadd(p1, ginv(p1)); return gerepileupto(av, gmul2n(p1,-1)); } return trans_eval("cosh",gcosh,x,prec); } /********************************************************************/ /** **/ /** HYPERBOLIC SINE **/ /** **/ /********************************************************************/ static GEN mpsinh(GEN x) { pari_sp av; long ex = expo(x), lx; GEN z, res; if (!signe(x)) return real_0_bit(ex); lx = realprec(x); res = cgetr(lx); av = avma; if (ex < 1 - BITS_IN_LONG) { /* y = e^x-1; e^x - e^(-x) = y(1 + 1/(y+1)) */ GEN y = mpexpm1(x); z = addrs(y,1); if (lg(z) > lx+1) z = rtor(z,lx+1); /* e^x */ z = mulrr(y, addsr(1,invr(z))); } else { z = mpexp(x); z = subrr(z, invr(z)); } shiftr_inplace(z, -1); affrr(z, res); avma = av; return res; } GEN gsinh(GEN x, long prec) { pari_sp av; GEN y, p1; switch(typ(x)) { case t_REAL: return mpsinh(x); case t_COMPLEX: if (isintzero(gel(x,1))) retmkcomplex(gen_0, gsin(gel(x,2),prec)); /* fall through */ case t_PADIC: av = avma; p1 = gexp(x,prec); p1 = gsub(p1, ginv(p1)); return gerepileupto(av, gmul2n(p1,-1)); default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y) && valp(y) == 0) return gerepilecopy(av, y); p1 = gexp(y, prec); p1 = gsub(p1, ginv(p1)); return gerepileupto(av, gmul2n(p1,-1)); } return trans_eval("sinh",gsinh,x,prec); } /********************************************************************/ /** **/ /** HYPERBOLIC TANGENT **/ /** **/ /********************************************************************/ static GEN mptanh(GEN x) { long lx, s = signe(x); GEN y; if (!s) return real_0_bit(expo(x)); lx = realprec(x); if (abscmprr(x, stor(prec2nbits(lx), LOWDEFAULTPREC)) >= 0) { y = real_1(lx); } else { pari_sp av = avma; long ex = expo(x); GEN t; if (ex < 1 - BITS_IN_LONG) x = rtor(x, lx + nbits2extraprec(-ex)-1); t = exp1r_abs(gmul2n(x,1)); /* exp(|2x|) - 1 */ y = gerepileuptoleaf(av, divrr(t, addsr(2,t))); } if (s < 0) togglesign(y); /* tanh is odd */ return y; } GEN gtanh(GEN x, long prec) { pari_sp av; GEN y, t; switch(typ(x)) { case t_REAL: return mptanh(x); case t_COMPLEX: if (isintzero(gel(x,1))) retmkcomplex(gen_0, gtan(gel(x,2),prec)); /* fall through */ case t_PADIC: av = avma; t = gexp(gmul2n(x,1),prec); t = gdivsg(-2, gaddgs(t,1)); return gerepileupto(av, gaddsg(1,t)); default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) return gerepilecopy(av, y); t = gexp(gmul2n(y, 1),prec); t = gdivsg(-2, gaddgs(t,1)); return gerepileupto(av, gaddsg(1,t)); } return trans_eval("tanh",gtanh,x,prec); } static GEN mpcotanh(GEN x) { long lx, s = signe(x); GEN y; if (!s) pari_err_DOMAIN("cotan", "argument", "=", gen_0, x); lx = realprec(x); if (abscmprr(x, stor(prec2nbits(lx), LOWDEFAULTPREC)) >= 0) { y = real_1(lx); } else { pari_sp av = avma; long ex = expo(x); GEN t; if (ex < 1 - BITS_IN_LONG) x = rtor(x, lx + nbits2extraprec(-ex)-1); t = exp1r_abs(gmul2n(x,1)); /* exp(|2x|) - 1 */ y = gerepileuptoleaf(av, divrr(addsr(2,t), t)); } if (s < 0) togglesign(y); /* cotanh is odd */ return y; } GEN gcotanh(GEN x, long prec) { pari_sp av; GEN y, t; switch(typ(x)) { case t_REAL: return mpcotanh(x); case t_COMPLEX: if (isintzero(gel(x,1))) retmkcomplex(gen_0, gcotan(gel(x,2),prec)); /* fall through */ case t_PADIC: av = avma; t = gexpm1(gmul2n(x,1),prec); return gerepileupto(av, gaddsg(1, gdivsg(2,t))); default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) return gerepilecopy(av, y); t = gexpm1(gmul2n(y,1),prec); return gerepileupto(av, gaddsg(1, gdivsg(2,t))); } return trans_eval("cotanh",gcotanh,x,prec); } /********************************************************************/ /** **/ /** AREA HYPERBOLIC SINE **/ /** **/ /********************************************************************/ /* x != 0 */ static GEN mpasinh(GEN x) { GEN z, res; pari_sp av; long lx = realprec(x), ex = expo(x); res = cgetr(lx); av = avma; if (ex < 1 - BITS_IN_LONG) x = rtor(x, lx + nbits2extraprec(-ex)-1); z = logr_abs( addrr_sign(x,1, sqrtr_abs( addrs(sqrr(x), 1) ), 1) ); if (signe(x) < 0) togglesign(z); affrr(z, res); avma = av; return res; } GEN gasinh(GEN x, long prec) { pari_sp av; GEN a, y, p1; switch(typ(x)) { case t_REAL: if (!signe(x)) return rcopy(x); return mpasinh(x); case t_COMPLEX: { GEN a, b, d; if (ismpzero(gel(x,2))) return gasinh(gel(x,1), prec); av = avma; if (ismpzero(gel(x,1))) /* avoid cancellation */ return gerepilecopy(av, mulcxI(gasin(gel(x,2), prec))); d = gsqrt(gaddsg(1,gsqr(x)), prec); /* Re(d) >= 0 */ a = gadd(d, x); b = gsub(d, x); /* avoid cancellation as much as possible */ if (gprecision(a) < gprecision(b)) y = gneg(glog(b,prec)); else y = glog(a,prec); return gerepileupto(av, y); /* log (x + sqrt(1+x^2)) */ } default: av = avma; if (!(y = toser_i(x))) break; if (gequal0(y)) return gerepilecopy(av, y); if (valp(y) < 0) pari_err_DOMAIN("asinh","valuation", "<", gen_0, x); p1 = gaddsg(1,gsqr(y)); if (gequal0(p1)) { GEN t = PiI2n(-1,prec); if ( gsigne(imag_i(gel(y,2))) < 0 ) setsigne(gel(t,2), -1); return gerepileupto(av, scalarser(t, varn(y), valp(p1)>>1)); } p1 = gdiv(derivser(y), gsqrt(p1,prec)); a = integser(p1); if (!valp(y)) a = gadd(a, gasinh(gel(y,2),prec)); return gerepileupto(av, a); } return trans_eval("asinh",gasinh,x,prec); } /********************************************************************/ /** **/ /** AREA HYPERBOLIC COSINE **/ /** **/ /********************************************************************/ /* |x| >= 1, return ach(|x|) */ static GEN mpacosh(GEN x) { pari_sp av = avma; GEN z; if (absrnz_equal1(x)) return real_0_bit(- bit_prec(x) >> 1); z = logr_abs( addrr_sign(x, 1, sqrtr( subrs(sqrr(x), 1) ), 1) ); return gerepileuptoleaf(av, z); } GEN gacosh(GEN x, long prec) { pari_sp av; GEN y; switch(typ(x)) { case t_REAL: { long s = signe(x), e = expo(x); GEN a, b; if (s > 0 && e >= 0) return mpacosh(x); /* x < 1 */ y = cgetg(3,t_COMPLEX); a = gen_0; if (s == 0) b = acos0(e); else if (e < 0) b = mpacos(x); /* -1 < x < 1 */ else { if (!absrnz_equal1(x)) a = mpacosh(x); b = mppi(realprec(x)); } gel(y,1) = a; gel(y,2) = b; return y; } case t_COMPLEX: { GEN a, b, d; if (ismpzero(gel(x,2))) return gacosh(gel(x,1), prec); av = avma; d = gsqrt(gaddsg(-1,gsqr(x)), prec); /* Re(d) >= 0 */ a = gadd(x, d); b = gsub(x, d); /* avoid cancellation as much as possible */ if (gprecision(a) < gprecision(b)) y = glog(b,prec); else y = glog(a,prec); /* y = \pm log(x + sqrt(x^2-1)) */ if (gsigne(real_i(y)) < 0) y = gneg(y); return gerepileupto(av, y); } default: { GEN a, d; long v; av = avma; if (!(y = toser_i(x))) break; v = valp(y); if (v < 0) pari_err_DOMAIN("acosh","valuation", "<", gen_0, x); if (gequal0(y)) { if (!v) return gerepilecopy(av, y); return gerepileupto(av, gadd(y, PiI2n(-1, prec))); } d = gsubgs(gsqr(y),1); if (gequal0(d)) { avma = av; return zeroser(varn(y), valp(d)>>1); } d = gdiv(derivser(y), gsqrt(d,prec)); a = integser(d); if (v) d = PiI2n(-1, prec); /* I Pi/2 */ else { d = gel(y,2); if (gequal1(d)) return gerepileupto(av,a); d = gacosh(d, prec); } return gerepileupto(av, gadd(d,a)); } } return trans_eval("acosh",gacosh,x,prec); } /********************************************************************/ /** **/ /** AREA HYPERBOLIC TANGENT **/ /** **/ /********************************************************************/ /* |x| < 1, x != 0 */ static GEN mpatanh(GEN x) { pari_sp av = avma; long ex = expo(x); GEN z; if (ex < 1 - BITS_IN_LONG) x = rtor(x, realprec(x) + nbits2extraprec(-ex)-1); z = invr( subsr(1,x) ); shiftr_inplace(z, 1); /* 2/(1-x)*/ z = logr_abs( addrs(z,-1) ); shiftr_inplace(z, -1); return gerepileuptoleaf(av, z); } GEN gatanh(GEN x, long prec) { long sx; pari_sp av; GEN a, y, z; switch(typ(x)) { case t_REAL: sx = signe(x); if (!sx) return real_0_bit(expo(x)); if (expo(x) < 0) return mpatanh(x); y = cgetg(3,t_COMPLEX); av = avma; z = subrs(x,1); if (!signe(z)) pari_err_DOMAIN("atanh", "argument", "=", gen_1, x); z = invr(z); shiftr_inplace(z, 1); /* 2/(x-1)*/ z = addrs(z,1); if (!signe(z)) pari_err_DOMAIN("atanh", "argument", "=", gen_m1, x); z = logr_abs(z); shiftr_inplace(z, -1); /* (1/2)log((1+x)/(x-1)) */ gel(y,1) = gerepileuptoleaf(av, z); gel(y,2) = Pi2n(-1, realprec(x)); if (sx > 0) togglesign(gel(y,2)); return y; case t_COMPLEX: /* 2/(1-z) - 1 = (1+z) / (1-z) */ if (ismpzero(gel(x,2))) return gatanh(gel(x,1), prec); av = avma; z = glog( gaddgs(gdivsg(2,gsubsg(1,x)),-1), prec ); return gerepileupto(av, gmul2n(z,-1)); default: av = avma; if (!(y = toser_i(x))) break; if (valp(y) < 0) pari_err_DOMAIN("atanh","valuation", "<", gen_0, x); z = gdiv(derivser(y), gsubsg(1,gsqr(y))); a = integser(z); if (!valp(y)) a = gadd(a, gatanh(gel(y,2),prec)); return gerepileupto(av, a); } return trans_eval("atanh",gatanh,x,prec); } /********************************************************************/ /** **/ /** CACHE BERNOULLI NUMBERS B_2k **/ /** **/ /********************************************************************/ static GEN bern(GEN B, long pr) { if (typ(B) != t_REAL) return fractor(B, pr); if (realprec(B) < pr) return rtor(B,pr); return B; } static const long BERN_MINNB = 5; /* need B[2..2*nb] at least prec accuracy. If prec = 0, compute exactly */ void mpbern(long nb, long prec) { const pari_sp av = avma; long n, pr, n_is_small = 1, lbern = 0; GEN B; pari_timer T; /* pr = accuracy for computation, prec = required accuracy for result */ if (prec) { pr = prec; incrprec(pr); } else pr = prec = LONG_MAX; /* oo */ if (nb < BERN_MINNB) nb = BERN_MINNB; if (bernzone) { /* don't recompute known Bernoulli */ long i, min, max; lbern = lg(bernzone); if (lbern-1 < nb) { min = lbern-1; max = nb; } else { min = nb; max = lbern-1; } /* skip B_2, ..., B_{2*MINNB}, always included as t_FRAC */ for (n = BERN_MINNB+1; n <= min; n++) { GEN c = gel(bernzone,n); /* also stop if prec = 0 (compute exactly) */ if (typ(c) == t_REAL && realprec(c) < prec) break; } /* B[1..n-1] are OK */ if (n > nb) return; B = cgetg_block(max+1, t_VEC); for (i = 1; i < n; i++) gel(B,i) = gel(bernzone,i); /* keep B[nb+1..max] */ for (i = nb+1; i <= max; i++) gel(B,i) = gel(bernzone,i); } else { B = cgetg_block(nb+1, t_VEC); gel(B,1) = gclone(mkfrac(gen_1, utoipos(6))); gel(B,2) = gclone(mkfrac(gen_m1, utoipos(30))); gel(B,3) = gclone(mkfrac(gen_1, utoipos(42))); gel(B,4) = gel(B,2); gel(B,5) = gclone(mkfrac(utoipos(5), utoipos(66))); n = BERN_MINNB+1; } avma = av; if (DEBUGLEVEL) { err_printf("caching Bernoulli numbers 2 to 2*%ld, prec = %ld\n", nb, prec == LONG_MAX? 0: prec); timer_start(&T); } /* B_{2n} = (2n-1) / (4n+2) - * sum_{a = 1}^{n-1} (2n)...(2n+2-2a) / (2...(2a-1)2a) B_{2a} */ n_is_small = 1; for (; n <= nb; n++, avma = av) { /* compute and store B[n] = B_{2n} */ GEN S; if (n < lbern) { GEN b = gel(bernzone,n); if (typ(b)!=t_REAL || realprec(b)>=prec) { gel(B,n) = b; continue; } } /* Not cached, must compute */ /* huge accuracy ? May as well compute exactly */ if (n_is_small && (prec == LONG_MAX || 2*n * log((double)2*n) < prec2nbits_mul(prec, M_LN2))) S = bernfrac_using_zeta(2*n); else { #ifdef LONG_IS_64BIT const ulong mul_overflow = 3037000500UL; #else const ulong mul_overflow = 46341UL; #endif ulong u = 8, v = 5, a = n-1, b = 2*n-3; n_is_small = 0; S = bern(gel(B,a), pr); /* B_2a */ for (;;) { /* b = 2a-1, u = 2v-2, 2a + v = 2n+3 */ if (a == 1) { S = mulri(S, muluu(u,v)); break; } /* a=b=1, v=2n+1, u=4n */ /* beware overflow */ S = (v <= mul_overflow)? mulru(S, u*v): mulri(S, muluu(u,v)); S = (a <= mul_overflow)? divru(S, a*b): divri(S, muluu(a,b)); u += 4; v += 2; a--; b -= 2; S = addrr(bern(gel(B,a), pr), S); if ((a & 127) == 0) S = gerepileuptoleaf(av, S); } S = divru(subsr(2*n, S), 2*n+1); shiftr_inplace(S, -2*n); if (realprec(S) != prec) S = rtor(S, prec); } gel(B,n) = gclone(S); /* S = B_2n */ } if (DEBUGLEVEL) timer_printf(&T, "Bernoulli"); swap(B, bernzone); if (B) { /* kill old non-reused values */ for (n = lbern-1; n; n--) { if (gel(B,n) != gel(bernzone,n)) gunclone(gel(B,n)); } killblock(B); } avma = av; } GEN bernfrac(long n) { long k; if (n < 0) pari_err_DOMAIN("bernfrac", "index", "<", gen_0, stoi(n)); if (n == 0) return gen_1; if (n == 1) return mkfrac(gen_m1,gen_2); if (odd(n)) return gen_0; k = n >> 1; if (!bernzone && k <= BERN_MINNB) mpbern(BERN_MINNB, 0); if (bernzone && k < lg(bernzone)) { GEN B = gel(bernzone, k), C; if (typ(B) != t_REAL) return B; C = bernfrac_using_zeta(n); gel(bernzone, k) = gclone(C); gunclone(B); return C; } return bernfrac_using_zeta(n); } /* mpbern as exact fractions */ static GEN bernvec_old(long nb) { long n, i; GEN y; if (nb < 0) return cgetg(1, t_VEC); if (nb > 46340 && BITS_IN_LONG == 32) pari_err_IMPL( "bernvec for n > 46340"); y = cgetg(nb+2, t_VEC); gel(y,1) = gen_1; for (n = 1; n <= nb; n++) { /* compute y[n+1] = B_{2n} */ pari_sp av = avma; GEN b = gmul2n(utoineg(2*n - 1), -1); /* 1 + (2n+1)B_1 = -(2n-1) /2 */ GEN c = gen_1; ulong u1 = 2*n + 1, u2 = n, d1 = 1, d2 = 1; for (i = 1; i < n; i++) { c = diviiexact(muliu(c, u1*u2), utoipos(d1*d2));/*= binomial(2n+1, 2*i) */ b = gadd(b, gmul(c, gel(y,i+1))); u1 -= 2; u2--; d1++; d2 += 2; } gel(y,n+1) = gerepileupto(av, gdivgs(b, -(1+2*n))); } return y; } GEN bernvec(long nb) { long i, l = nb+2; GEN y = cgetg(l, t_VEC); if (nb < 20) return bernvec_old(nb); for (i = 1; i < l; i++) gel(y,i) = bernfrac((i-1) << 1); return y; } /* x := pol_x(v); B_k(x) = \sum_{i=0}^k binomial(k, i) B_i x^{k-i} */ static GEN bernpol_i(long k, long v) { GEN B, C; long i; if (v < 0) v = 0; if (k < 0) pari_err_DOMAIN("bernpol", "index", "<", gen_0, stoi(k)); mpbern(k >> 1, 0); /* cache B_2, ..., B_2[k/2] */ C = vecbinomial(k); B = cgetg(k + 3, t_POL); for (i = 0; i <= k; ++i) gel(B, k-i+2) = gmul(gel(C,i+1), bernfrac(i)); B[1] = evalsigne(1) | evalvarn(v); return B; } GEN bernpol(long k, long v) { pari_sp av = avma; return gerepileupto(av, bernpol_i(k, v)); } /* x := pol_x(v); return 1^e + ... + x^e = x^e + (B_{e+1}(x) - B_{e+1})/(e+1) */ static GEN faulhaber(long e, long v) { GEN B; if (e == 0) return pol_x(v); B = RgX_integ(bernpol_i(e, v)); /* (B_{e+1}(x) - B_{e+1}) / (e+1) */ gel(B,e+2) = gaddgs(gel(B,e+2), 1); /* add x^e, in place */ return B; } /* sum_v T(v), T a polynomial expression in v */ GEN sumformal(GEN T, long v) { pari_sp av = avma, av2; long i, t, d; GEN R; T = simplify_shallow(T); t = typ(T); if (is_scalar_t(t)) return gerepileupto(av, monomialcopy(T, 1, v < 0? 0: v)); if (t != t_POL) pari_err_TYPE("sumformal [not a t_POL]", T); if (v < 0) v = varn(T); av2 = avma; R = gen_0; d = poldegree(T,v); for (i = d; i >= 0; i--) { GEN c = polcoeff0(T, i, v); if (gequal0(c)) continue; R = gadd(R, gmul(c, faulhaber(i, v))); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"sumformal, i = %ld/%ld", i,d); R = gerepileupto(av2, R); } } return gerepileupto(av, R); } /********************************************************************/ /** **/ /** EULER'S GAMMA **/ /** **/ /********************************************************************/ /* x / (i*(i+1)) */ GEN divrunu(GEN x, ulong i) { if (i <= LOWMASK) /* i(i+1) < 2^BITS_IN_LONG*/ return divru(x, i*(i+1)); else return divru(divru(x, i), i+1); } /* x / (i*(i+1)) */ GEN divgunu(GEN x, ulong i) { #ifdef LONG_IS_64BIT if (i < 3037000500L) /* i(i+1) < 2^63 */ #else if (i < 46341L) /* i(i+1) < 2^31 */ #endif return gdivgs(x, i*(i+1)); else return gdivgs(gdivgs(x, i), i+1); } /* arg(s+it) */ double darg(double s, double t) { double x; if (!t) return (s>0)? 0.: M_PI; if (!s) return (t>0)? M_PI/2: -M_PI/2; x = atan(t/s); return (s>0)? x : ((t>0)? x+M_PI : x-M_PI); } void dcxlog(double s, double t, double *a, double *b) { *a = log(s*s + t*t) / 2; /* log |s| = Re(log(s)) */ *b = darg(s,t); /* Im(log(s)) */ } double dabs(double s, double t) { return sqrt( s*s + t*t ); } double dnorm(double s, double t) { return s*s + t*t; } #if 0 /* x, z t_REAL. Compute unique x in ]-z,z] congruent to x mod 2z */ static GEN red_mod_2z(GEN x, GEN z) { GEN Z = gmul2n(z, 1), d = subrr(z, x); /* require little accuracy */ if (!signe(d)) return x; setprec(d, nbits2prec(expo(d) - expo(Z))); return addrr(mulir(floorr(divrr(d, Z)), Z), x); } #endif /* lngamma(1+z) = -Euler*z + sum_{i > 1} zeta(i)/i (-z)^i * at relative precision prec, |z| < 1 is small */ static GEN lngamma1(GEN z, long prec) { /* sum_{i > l} |z|^(i-1) = |z|^l / (1-|z|) < 2^-B * for l > (B+1) / |log2(|z|)| */ long i, l = ceil((bit_accuracy(prec) + 1) / - dbllog2(z)); GEN zet, me = mpeuler(prec), s = gen_0; setsigne(me, -1); /* -Euler */ if (l <= 1) return gmul(me, z); zet = veczeta(gen_1, gen_2, l-1, prec); /* z[i] = zeta(i+1) */ for (i = l; i > 1; i--) { GEN c = divru(gel(zet,i-1), i); if (odd(i)) setsigne(c, -1); s = gadd(gmul(s,z), c); } return gmul(z, gadd(gmul(s,z), me)); } static GEN cxgamma(GEN s0, int dolog, long prec) { GEN s, u, a, y, res, tes, sig, tau, invn2, p1, nnx, pi, pi2, sqrtpi2; long i, lim, nn, esig, et; pari_sp av, av2; int funeq = 0; pari_timer T; if (DEBUGLEVEL>5) timer_start(&T); s = trans_fix_arg(&prec,&s0,&sig,&tau,&av,&res); esig = expo(sig); et = signe(tau)? expo(tau): 0; if ((signe(sig) <= 0 || esig < -1) && et <= 16) { /* s <--> 1-s */ funeq = 1; s = gsubsg(1, s); sig = real_i(s); } /* find "optimal" parameters [lim, nn] */ if (esig > 300 || et > 300) { /* |s| is HUGE ! Play safe and avoid inf / NaN */ GEN S, iS, l2, la, u; double logla, l; S = gprec_w(s,LOWDEFAULTPREC); /* l2 ~ |lngamma(s))|^2 */ l2 = gnorm(gmul(S, glog(S, LOWDEFAULTPREC))); l = (prec2nbits_mul(prec, M_LN2) - rtodbl(glog(l2,LOWDEFAULTPREC))/2) / 2.; if (l < 0) l = 0.; iS = imag_i(S); if (et > 0 && l > 0) { GEN t = gmul(iS, dbltor(M_PI / l)), logt = glog(t,LOWDEFAULTPREC); la = gmul(t, logt); if (gcmpgs(la, 3) < 0) { logla = log(3.); la = stoi(3); } else if (gcmpgs(la, 150) > 0) { logla = rtodbl(logt); la = t; } else logla = rtodbl(mplog(la)); } else { logla = log(3.); la = stoi(3); } lim = (long)ceil(l / (1.+ logla)); if (lim == 0) lim = 1; u = gmul(la, dbltor((lim-0.5)/M_PI)); l2 = gsub(gsqr(u), gsqr(iS)); if (signe(l2) > 0) { l2 = gsub(gsqrt(l2,3), sig); if (signe(l2) > 0) nn = itos( gceil(l2) ); else nn = 1; } else nn = 1; } else { /* |s| is moderate. Use floats */ double ssig = rtodbl(sig); double st = typ(s) == t_REAL? 0.0: rtodbl(imag_i(s)); double la, l,l2,u,v, rlogs, ilogs; if (fabs(ssig-1) + fabs(st) < 1e-16) { /* s ~ 1: loggamma(1+u) ~ - Euler * u, cancellation */ if (funeq) /* s0 ~ 0: use lngamma(s0)+log(s0) = lngamma(s0+1) */ { if (dolog) y = gsub(lngamma1(s0,prec), glog(s0,prec)); else y = gdiv(gexp(lngamma1(s0,prec), prec), s0); } else { if (isint1(s0)) { avma = av; return dolog? real_0(prec): real_1(prec); } y = lngamma1(gsubgs(s0,1),prec); if (!dolog) y = gexp(y,prec); } avma = av; return affc_fixlg(y, res); } dcxlog(ssig,st, &rlogs,&ilogs); /* Re (s - 1/2) log(s) */ u = (ssig - 0.5)*rlogs - st * ilogs; /* Im (s - 1/2) log(s) */ v = (ssig - 0.5)*ilogs + st * rlogs; /* l2 = | (s - 1/2) log(s) - s + log(2Pi)/2 |^2 ~ |lngamma(s))|^2 */ u = u - ssig + log(2.*M_PI)/2; v = v - st; l2 = u*u + v*v; if (l2 < 0.000001) l2 = 0.000001; l = (prec2nbits_mul(prec, M_LN2) - log(l2)/2) / 2.; if (l < 0) l = 0.; la = 3.; /* FIXME: heuristic... */ if (st > 1 && l > 0) { double t = st * M_PI / l; la = t * log(t); if (la < 3) la = 3.; if (la > 150) la = t; } lim = (long)ceil(l / (1.+ log(la))); if (lim == 0) lim = 1; u = (lim-0.5) * la / M_PI; l2 = u*u - st*st; if (l2 > 0) { double t = ceil(sqrt(l2) - ssig); nn = (t < 1)? 1: (long)t; if (nn < 1) nn = 1; } else nn = 1; if (DEBUGLEVEL>5) err_printf("lim, nn: [%ld, %ld], la = %lf\n",lim,nn,la); } incrprec(prec); av2 = avma; y = s; if (typ(s0) == t_INT) { if (signe(s0) <= 0) pari_err_DOMAIN("gamma","argument", "=", strtoGENstr("non-positive integer"), s0); if (is_bigint(s0)) { for (i=1; i < nn; i++) { y = mulri(y, addiu(s0, i)); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"gamma"); y = gerepileuptoleaf(av2, y); } } } else { ulong ss = itou(s0); for (i=1; i < nn; i++) { y = mulru(y, ss + i); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"gamma"); y = gerepileuptoleaf(av2, y); } } } if (dolog) y = logr_abs(y); } else { /* Compute lngamma mod 2 I Pi */ GEN sq = gsqr(s); pari_sp av3 = avma; for (i = 1; i < nn - 1; i += 2) { y = gmul(y, gaddsg(i*(i + 1), gadd(gmulsg(2*i + 1, s), sq))); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"gamma"); y = gerepileupto(av3, y); } } if (!odd(nn)) y = gmul(y, gaddsg(nn - 1, s)); if (dolog) { if (typ(s) == t_REAL) y = logr_abs(y); else { /* fix imaginary part */ long prec0 = LOWDEFAULTPREC; GEN s0 = gprec_w(s, prec0), y0 = s0, k; y0 = garg(y0, prec0); /* Im log(s) at low accuracy */ for (i=1; i < nn; i++) y0 = gadd(y0, garg(gaddgs(s0,i), prec0)); y = glog(y, prec); k = ground( gdiv(gsub(y0, imag_i(y)), Pi2n(1,prec0)) ); if (signe(k)) y = gadd(y, mulcxI(mulir(k, Pi2n(1, prec)))); } } } if (DEBUGLEVEL>5) timer_printf(&T,"product from 0 to N-1"); nnx = gaddgs(s, nn); a = ginv(nnx); invn2 = gsqr(a); av2 = avma; mpbern(lim,prec); tes = divrunu(bernreal(2*lim,prec), 2*lim-1); /* B2l / (2l-1) 2l*/ if (DEBUGLEVEL>5) timer_printf(&T,"Bernoullis"); for (i = 2*lim-2; i > 1; i -= 2) { u = divrunu(bernreal(i,prec), i-1); /* Bi / i(i-1) */ tes = gadd(u, gmul(invn2,tes)); if (gc_needed(av2,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"gamma"); tes = gerepileupto(av2, tes); } } if (DEBUGLEVEL>5) timer_printf(&T,"Bernoulli sum"); p1 = gsub(gmul(gsub(nnx, ghalf), glog(nnx,prec)), nnx); p1 = gadd(p1, gmul(tes, a)); pi = mppi(prec); pi2 = shiftr(pi, 1); sqrtpi2 = sqrtr(pi2); if (dolog) { if (funeq) { /* recall that s = 1 - s0 */ GEN T = shiftr(sqrtpi2,-1); /* sqrt(2Pi)/2 */ if (typ(s) != t_REAL) { /* We compute log(sin(Pi s0)) so that it has branch cuts along * (-oo, 0] and [1, oo). To do this in a numerically stable way * we must compute the log first then mangle its imaginary part. * The rounding operation below is stable because we're rounding * a number which is already within 1/4 of an integer. */ /* z = log( sin(Pi s0) / (sqrt(2Pi)/2) ) */ GEN z = glog(gdiv(gsin(gmul(pi,s0),prec), T), prec); /* b = (2 Re(s) - 1) / 4 */ GEN b = shiftr(subrs(shiftr(sig, 1), 1), -2); y = gsub(y, z); if (gsigne(imag_i(s)) > 0) togglesign(b); /* z = 2Pi round( Im(z)/2Pi - b ) */ z = gmul(roundr(gsub(gdiv(imag_i(z), pi2), b)), pi2); if (signe(z)) { /* y += I*z, z a t_REAL */ if (typ(y) == t_COMPLEX) gel(y,2) = gadd(gel(y,2), z); else y = mkcomplex(y, z); } } else { /* s0 < 0, formula simplifies: imag(lngamma(s0)) = - Pi * floor(s0) */ GEN z = logr_abs(divrr(mpsin(gmul(pi,s0)), T)); y = gsub(y, z); y = mkcomplex(y, mulri(pi, gfloor(s0))); } p1 = gneg(p1); } else /* y --> sqrt(2Pi) / y */ y = gsub(logr_abs(sqrtpi2), y); y = gadd(p1, y); } else { if (funeq) { /* y --> y Pi/(sin(Pi s) * sqrt(2Pi)) = y sqrt(Pi/2)/sin(Pi s) */ y = gdiv(gmul(shiftr(sqrtpi2,-1),y), gsin(gmul(pi,s0), prec)); /* don't use s above: sin(pi s0) = sin(pi s) and the former is * more accurate, esp. if s0 ~ 0 */ p1 = gneg(p1); } else /* y --> sqrt(2Pi) / y */ y = gdiv(sqrtpi2, y); y = gmul(gexp(p1, prec), y); } avma = av; return affc_fixlg(y, res); } /* Gamma((m+1) / 2) */ static GEN gammahs(long m, long prec) { GEN y = cgetr(prec), z; pari_sp av = avma; long ma = labs(m); if (ma > 200 + 50*(prec-2)) /* heuristic */ { z = stor(m + 1, prec); shiftr_inplace(z, -1); affrr(cxgamma(z,0,prec), y); avma = av; return y; } z = sqrtr( mppi(prec) ); if (m) { GEN p1 = mulu_interval(ma/2 + 1, ma); long v = vali(p1); p1 = shifti(p1, -v); v -= ma; if (m >= 0) z = mulri(z,p1); else { z = divri(z,p1); v = -v; if ((m&3) == 2) setsigne(z,-1); } shiftr_inplace(z, v); } affrr(z, y); avma = av; return y; } GEN ggammah(GEN x, long prec) { switch(typ(x)) { case t_INT: { long k = itos(x); if (labs(k) > 962353) pari_err_OVERFLOW("gammah"); return gammahs(k<<1, prec); } case t_REAL: case t_COMPLEX: case t_PADIC: case t_SER: { pari_sp av = avma; return gerepileupto(av, ggamma(gadd(x,ghalf), prec)); } } return trans_eval("gammah",ggammah,x,prec); } /* find n such that n+v_p(n!)>=k p^2/(p-1)^2 */ static long nboft(long k, long p) { pari_sp av = avma; long s, n; if (k <= 0) return 0; k = itou( gceil(gdiv(mului(k, sqru(p)), sqru(p-1))) ); avma = av; for (s=0, n=0; n+s < k; n++, s += u_lval(n, p)); return n; } /* Using Dwork's expansion, compute \Gamma(px+1)=-\Gamma(px) with x a unit. * See p-Adic Gamma Functions and Dwork Cohomology, Maurizio Boyarsky * Transactions of the AMS, Vol. 257, No. 2. (Feb., 1980), pp. 359-369. * Inspired by a GP script by Fernando Rodriguez-Villegas */ static GEN gadw(GEN x, long p) { pari_sp ltop = avma; GEN s, t, u = cgetg(p+1, t_VEC); long j, k, kp, n = nboft(precp(x)+valp(x)+1, p); t = s = gaddsg(1, zeropadic(gel(x,2), n)); gel(u, 1) = s; gel(u, 2) = s; for (j = 2; j < p; ++j) gel(u, j+1) = gdivgs(gel(u, j), j); for (k = 1, kp = p; k < n; ++k, kp += p) /* kp = k*p */ { GEN c; gel(u, 1) = gdivgs(gadd(gel(u, 1), gel(u, p)), kp); for (j = 1; j < p; ++j) gel(u, j+1) = gdivgs(gadd(gel(u, j), gel(u, j+1)), kp + j); t = gmul(t, gaddgs(x, k-1)); c = leafcopy(gel(u,1)); setvalp(c, valp(c) + k); /* c = u[1] * p^k */ s = gadd(s, gmul(c, t)); if ((k&0xFL)==0) gerepileall(ltop, 3, &u,&s,&t); } return gneg(s); } /*Use Dwork expansion*/ /*This is a O(p*e*log(pe)) algorithm, should be used when p small * If p==2 this is a O(pe) algorithm. */ static GEN Qp_gamma_Dwork(GEN x, long p) { pari_sp ltop = avma; long k = padic_to_Fl(x, p); GEN p1; long j; long px = precp(x); if (p==2 && px) { x = shallowcopy(x); setprecp(x, px+1); gel(x,3) = shifti(gel(x,3),1); } if (k) { GEN x_k = gsubgs(x,k); x = gdivgs(x_k, p); p1 = gadw(x, p); if (!odd(k)) p1 = gneg(p1); for (j = 1; j < k; ++j) p1 = gmul(p1, gaddgs(x_k, j)); } else p1 = gneg(gadw(gdivgs(x, p), p)); return gerepileupto(ltop, p1); } /* Compute Qp_gamma using the definition. This is a O(x*M(log(pe))) algorithm. * This should be used if x is very small. */ static GEN Qp_gamma_Morita(long n, GEN p, long e) { pari_sp ltop=avma; GEN p2 = gaddsg((n&1)?-1:1, zeropadic(p, e)); long i; long pp=is_bigint(p)? 0: itos(p); for (i = 2; i < n; i++) if (!pp || i%pp) { p2 = gmulgs(p2, i); if ((i&0xFL) == 0xFL) p2 = gerepileupto(ltop, p2); } return gerepileupto(ltop, p2); } /* x\in\N: Gamma(-x)=(-1)^(1+x+x\p)*Gamma(1+x) */ static GEN Qp_gamma_neg_Morita(long n, GEN p, long e) { GEN g = ginv(Qp_gamma_Morita(n+1, p, e)); return ((n^sdivsi(n,p)) & 1)? g: gneg(g); } /* p-adic Gamma function for x a p-adic integer */ /* If n < p*e : use Morita's definition. * Else : use Dwork's expansion. * If both n and p are big : itos(p) will fail. * TODO: handle p=2 better (Qp_gamma_Dwork is slow for p=2). */ GEN Qp_gamma(GEN x) { GEN n, m, N, p = gel(x,2); long s, e = precp(x); if (absequaliu(p, 2) && e == 2) e = 1; if (valp(x) < 0) pari_err_DOMAIN("gamma","v_p(x)", "<", gen_0, x); n = gtrunc(x); m = gtrunc(gneg(x)); N = cmpii(n,m)<=0?n:m; s = itos_or_0(N); if (s && cmpsi(s, muliu(p,e)) < 0) /* s < p*e */ return (N == n) ? Qp_gamma_Morita(s,p,e): Qp_gamma_neg_Morita(s,p,e); return Qp_gamma_Dwork(x, itos(p)); } /* gamma(1+x) - 1, |x| < 1 is "small" */ GEN ggamma1m1(GEN x, long prec) { return gexpm1(lngamma1(x, prec), prec); } /* lngamma(y) with 0 constant term, using (lngamma y)' = y' psi(y) */ static GEN serlngamma0(GEN y, long prec) { GEN t; if (valp(y)) pari_err_DOMAIN("lngamma","valuation", "!=", gen_0, y); t = derivser(y); /* don't compute psi if y'=0 */ if (signe(t)) t = gmul(t, gpsi(y,prec)); return integser(t); } static GEN serlngamma(GEN y, long prec) { GEN z, y0, Y; if (lg(y) == 2) pari_err_DOMAIN("gamma", "argument", "=", gen_0,y); /* exp(lngamma) */ if (valp(y) > 0) return gdiv(gexp(glngamma(gaddgs(y,1),prec),prec),y); y0 = simplify_shallow(gel(y,2)); z = NULL; Y = y; if (isint(y0, &y0)) { /* fun eq. avoids log singularity of lngamma at negative ints */ long s = signe(y0); /* possible if y[2] is an inexact 0 */ if (!s) return gdiv(gexp(glngamma(gaddgs(y,1),prec),prec),y); if (signe(y0) < 0) { Y = gsubsg(1, y); y0 = subsi(1, y0); } if (abscmpiu(y0, 50) < 0) z = mpfact(itos(y0)-1); /* more precise */ } if (!z) z = ggamma(y0,prec); z = gmul(z, gexp(serlngamma0(Y,prec),prec)); if (Y != y) { GEN pi = mppi(prec); z = gdiv(mpodd(y0)? pi: negr(pi), gmul(z, gsin(gmul(pi,serchop0(y)), prec))); } return z; } GEN ggamma(GEN x, long prec) { pari_sp av; GEN y; switch(typ(x)) { case t_INT: if (signe(x) <= 0) pari_err_DOMAIN("gamma","argument", "=", strtoGENstr("non-positive integer"), x); if (abscmpiu(x,481177) > 0) pari_err_OVERFLOW("gamma"); return mpfactr(itos(x) - 1, prec); case t_REAL: case t_COMPLEX: return cxgamma(x, 0, prec); case t_FRAC: { GEN a = gel(x,1), b = gel(x,2), c; long m; if (absequaliu(b,2)) { if (is_bigint(a) || labs(m = itos(a)) > 962354) { pari_err_OVERFLOW("gamma"); return NULL; /* LCOV_EXCL_LINE */ } return gammahs(m-1, prec); } av = avma; c = subii(a,b); if (expi(c) - expi(b) < -50) { /* x = 1 + c/b is close to 1 */ x = mkfrac(c,b); if (lgefint(b) >= prec) x = fractor(x,prec); y = mpexp(lngamma1(x, prec)); } else if (signe(a) < 0 || cmpii(shifti(a,1), b) < 0) { /* gamma will use functional equation x -> z = 1-x = -c/b >= 1/2. * Gamma(x) = Pi / (sin(Pi z) * Gamma(z)) */ GEN z = mkfrac(negi(c), b), q = ground(z), r = gsub(z,q); GEN pi = mppi(prec); /* |r| <= 1/2 */ z = fractor(z, prec+EXTRAPRECWORD); y = divrr(pi, mulrr(mpsin(gmul(pi, r)), cxgamma(z, 0, prec))); if (mpodd(q)) togglesign(y); } else { x = fractor(x, prec); y = cxgamma(x, 0, prec); } return gerepileupto(av, y); } case t_PADIC: return Qp_gamma(x); default: av = avma; if (!(y = toser_i(x))) break; return gerepileupto(av, serlngamma(y, prec)); } return trans_eval("gamma",ggamma,x,prec); } GEN mpfactr(long n, long prec) { GEN f = cgetr(prec); pari_sp av = avma; if (n+1 > 350 + 70*(prec-2)) /* heuristic */ affrr(cxgamma(stor(n+1, prec), 0, prec), f); else affir(mpfact(n), f); avma = av; return f; } GEN glngamma(GEN x, long prec) { pari_sp av = avma; GEN y, y0, t; switch(typ(x)) { case t_INT: if (signe(x) <= 0) pari_err_DOMAIN("lngamma","argument", "=", strtoGENstr("non-positive integer"), x); if (abscmpiu(x,200 + 50*(prec-2)) > 0) /* heuristic */ return cxgamma(x, 1, prec); return gerepileuptoleaf(av, logr_abs( itor(mpfact(itos(x) - 1), prec) )); case t_FRAC: { GEN a = gel(x,1), b = gel(x,2), c = subii(a,b); long e = expi(b) - expi(c); if (e > 50) { x = mkfrac(c,b); if (lgefint(b) >= prec) x = fractor(x,prec + nbits2nlong(e)); y = lngamma1(x, prec); } else if (signe(a) < 0 || cmpii(shifti(a,1), b) < 0) { /* gamma will use functional equation x -> z = 1-x = -c/b >= 1/2. * lngamma(x) = log |Pi / (sin(Pi z) * Gamma(z))| + I*Pi * floor(x) */ GEN z = mkfrac(negi(c), b), q = ground(z), r = gsub(z,q); GEN pi = mppi(prec); /* |r| <= 1/2 */ z = fractor(z, prec+EXTRAPRECWORD); y = subrr(logr_abs(divrr(pi, mpsin(gmul(pi, r)))), cxgamma(z, 1, prec)); if (signe(a) < 0) y = gadd(y, mkcomplex(gen_0, mulri(pi, gfloor(x)))); } else { x = fractor(x, e > 1? prec+EXTRAPRECWORD: prec); y = cxgamma(x, 1, prec); } return gerepileupto(av, y); } case t_REAL: case t_COMPLEX: return cxgamma(x, 1, prec); default: if (!(y = toser_i(x))) break; if (lg(y) == 2) pari_err_DOMAIN("lngamma", "argument", "=", gen_0,y); t = serlngamma0(y,prec); y0 = simplify_shallow(gel(y,2)); /* no constant term if y0 = 1 or 2 */ if (!isint(y0,&y0) || signe(y0) <= 0 || abscmpiu(y0,2) > 2) t = gadd(t, glngamma(y0,prec)); return gerepileupto(av, t); case t_PADIC: return gerepileupto(av, Qp_log(Qp_gamma(x))); } return trans_eval("lngamma",glngamma,x,prec); } /********************************************************************/ /** **/ /** PSI(x) = GAMMA'(x)/GAMMA(x) **/ /** **/ /********************************************************************/ static GEN cxpsi(GEN s0, long prec) { pari_sp av, av2; GEN sum,z,a,res,tes,in2,sig,tau,s,unr,s2,sq; long lim,nn,k; const long la = 3; int funeq = 0; pari_timer T; if (DEBUGLEVEL>2) timer_start(&T); s = trans_fix_arg(&prec,&s0,&sig,&tau,&av,&res); if (signe(sig) <= 0) { funeq = 1; s = gsub(gen_1, s); sig = real_i(s); } if (typ(s0) == t_INT && signe(s0) <= 0) pari_err_DOMAIN("psi","argument", "=", strtoGENstr("non-positive integer"), s0); if (expo(sig) > 300 || (typ(s) == t_COMPLEX && gexpo(gel(s,2)) > 300)) { /* |s| is HUGE. Play safe */ GEN L, S = gprec_w(s,LOWDEFAULTPREC), rS = real_i(S), iS = imag_i(S); double l; l = rtodbl( gnorm(glog(S, 3)) ); l = log(l) / 2.; lim = 2 + (long)ceil((prec2nbits_mul(prec, M_LN2) - l) / (2*(1+log((double)la)))); if (lim < 2) lim = 2; l = (2*lim-1)*la / (2.*M_PI); L = gsub(dbltor(l*l), gsqr(iS)); if (signe(L) < 0) L = gen_0; L = gsub(gsqrt(L, 3), rS); if (signe(L) > 0) nn = (long)ceil(rtodbl(L)); else nn = 1; if (DEBUGLEVEL>2) err_printf("lim, nn: [%ld, %ld]\n",lim,nn); } else { double ssig = rtodbl(sig); double st = typ(s) == t_REAL? 0.0: rtodbl(imag_i(s)); double l; { double rlog, ilog; /* log (s - Euler) */ dcxlog(ssig - 0.57721566, st, &rlog,&ilog); l = dnorm(rlog,ilog); } if (l < 0.000001) l = 0.000001; l = log(l) / 2.; lim = 2 + (long)ceil((prec2nbits_mul(prec, M_LN2) - l) / (2*(1+log((double)la)))); if (lim < 2) lim = 2; l = (2*lim-1)*la / (2.*M_PI); l = l*l - st*st; if (l < 0.) l = 0.; nn = (long)ceil( sqrt(l) - ssig ); if (nn < 1) nn = 1; if (DEBUGLEVEL>2) err_printf("lim, nn: [%ld, %ld]\n",lim,nn); } incrprec(prec); unr = real_1(prec); /* one extra word of precision */ s2 = gmul2n(s, 1); sq = gsqr(s); a = gdiv(unr, gaddgs(s, nn)); /* 1 / (s+n) */ av2 = avma; sum = gmul2n(a, -1); for (k = 0; k < nn - 1; k += 2) { GEN tmp = gaddsg(k*(k + 1), gadd(gmulsg(2*k + 1, s), sq)); sum = gadd(sum, gdiv(gaddsg(2*k + 1, s2), tmp)); if ((k & 1023) == 0) sum = gerepileupto(av2, sum); } if (odd(nn)) sum = gadd(sum, gdiv(unr, gaddsg(nn - 1, s))); z = gsub(glog(gaddgs(s, nn), prec), sum); if (DEBUGLEVEL>2) timer_printf(&T,"sum from 0 to N - 1"); in2 = gsqr(a); mpbern(lim,prec); av2 = avma; tes = divru(bernreal(2*lim, prec), 2*lim); for (k=2*lim-2; k>=2; k-=2) { tes = gadd(gmul(in2,tes), divru(bernreal(k, prec), k)); if ((k & 255) == 0) tes = gerepileupto(av2, tes); } if (DEBUGLEVEL>2) timer_printf(&T,"Bernoulli sum"); z = gsub(z, gmul(in2,tes)); if (funeq) { GEN pi = mppi(prec); z = gadd(z, gmul(pi, gcotan(gmul(pi,s), prec))); } avma = av; return affc_fixlg(z, res); } /* n > 0; return psi(1+x) + O(x^n), x = pol_x(v) */ static GEN serpsi1(long n, long v, long prec) { long i, l = n+3; GEN z, g, s = cgetg(l, t_SER); s[1] = evalsigne(1)|evalvalp(0)|evalvarn(v); g = mpeuler(prec); setsigne(g, -1); z = veczeta(gen_1, gen_2, n, prec); /* zeta(2..n) */ gel(s,2) = g; for (i = 2; i < l-1; i++) { GEN c = gel(z,i-1); /* zeta(i) */ if (odd(i)) setsigne(c, -1); gel(s,i+1) = c; } return s; } /* T an RgX, return T(X + z0) + O(X^L) */ static GEN tr(GEN T, GEN z0, long L) { GEN s = RgX_to_ser(RgX_translate(T, z0), L+3); setvarn(s, 0); return s; } /* z0 a complex number with Re(z0) > 1/2; return psi(z0+x) + O(x^L) * using Luke's rational approximation for psi(x) */ static GEN serpsiz0(GEN z0, long L, long v, long prec) { pari_sp av; GEN A,A1,A2, B,B1,B2, Q; long n; n = gprecision(z0); if (n) prec = n; z0 = gtofp(z0, prec + EXTRAPRECWORD); /* Start from n = 3; in Luke's notation, A2 := A_{n-2}, A1 := A_{n-1}, * A := A_n. Same for B */ av = avma; A2= gdivgs(mkpoln(2, gen_1, utoipos(6)), 2); B2 = scalarpol_shallow(utoipos(4), 0); A1= gdivgs(mkpoln(3, gen_1, utoipos(82), utoipos(96)), 6); B1 = mkpoln(2, utoipos(8), utoipos(28)); A = gdivgs(mkpoln(4, gen_1, utoipos(387), utoipos(2906), utoipos(1920)), 12); B = mkpoln(3, utoipos(14), utoipos(204), utoipos(310)); A2= tr(A2,z0, L); B2= tr(B2,z0, L); A1= tr(A1,z0, L); B1= tr(B1,z0, L); A = tr(A, z0, L); B = tr(B, z0, L); Q = gdiv(A, B); /* work with z0+x as a variable */ for (n = 4;; n++) { GEN Q0 = Q, a, b, r, c3,c2,c1,c0 = muluu(2*n-3, n+1); GEN u = subiu(muluu(n, 7*n-9), 6); GEN t = addiu(muluu(n, 7*n-19), 4); /* c1=(2*n-1)*(3*(n-1)*z+7*n^2-9*n-6); * c2=(2*n-3)*(z-n-1)*(-3*(n-1)*z+7*n^2-19*n+4); * c3=(2*n-1)*(n-3)*(z-n)*(z-(n+1))*(z+(n-4)); */ c1 = deg1pol_shallow(muluu(3*(n-1),2*n-1), muliu(u,2*n-1), 0); c2 = ZX_mul(deg1pol_shallow(utoipos(2*n-3), negi(muluu(2*n-3,n+1)), 0), deg1pol_shallow(utoineg(3*(n-1)), t, 0)); r = mkvec3(utoipos(n), utoipos(n+1), stoi(4-n)); c3 = ZX_Z_mul(roots_to_pol(r,0), muluu(2*n-1,n-3)); c1 = tr(c1, z0, L+3); c2 = tr(c2, z0, L+3); c3 = tr(c3, z0, L+3); /* A_{n+1}, B_{n+1} */ a = gdiv(gadd(gadd(gmul(c1,A),gmul(c2,A1)),gmul(c3,A2)), c0); b = gdiv(gadd(gadd(gmul(c1,B),gmul(c2,B1)),gmul(c3,B2)), c0); Q = gdiv(a,b); if (gexpo(gsub(Q,Q0)) < -prec2nbits(prec)) break; A2 = A1; A1 = A; A = a; B2 = B1; B1 = B; B = b; if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"serpsiz0, n = %ld", n); gerepileall(av, 7, &A,&A1,&A2, &B,&B1,&B2, &Q); } } Q = gmul(Q, gmul2n(gsubsg(1, ginv(tr(pol_x(v),z0, L))), 1)); setvarn(Q, v); return gadd(negr(mpeuler(prec)), Q); } /* sum (-1)^k*H(m,k)x^k + O(x^L); L > 0; * H(m,k) = (-1)^{k * \delta_{m > 0}} sum_{1<=i 2) { ik = divru(ik, i); if (expo(ik) < bit) break; } gel(H,k) = gadd(gel(H,k), ik); } if (gc_needed(av,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"Hseries, i = %ld/%ld", i,M); H = gerepilecopy(av, H); } } if (m > 0) for (k = 3; k < l; k+=2) togglesign_safe(&gel(H,k)); return H; } static GEN serpsi(GEN y, long prec) { GEN Q = NULL, z0, Y = y, Y2; long L = lg(y)-2, v = varn(y), vy = valp(y); if (!L) pari_err_DOMAIN("psi", "argument", "=", gen_0,y); if (vy < 0) pari_err_DOMAIN("psi", "series valuation", "<", gen_0,y); if (vy) z0 = gen_0; else { z0 = simplify_shallow(gel(y,2)); (void)isint(z0, &z0); } if (typ(z0) == t_INT && !is_bigint(z0)) { long m = itos(z0); if (abscmpiu(muluu(prec2nbits(prec),L), labs(m)) > 0) { /* psi(m+x) = psi(1+x) + sum_{1 <= i < m} 1/(i+x) for m > 0 psi(1+x) - sum_{0 <= i < -m} 1/(i+x) for m <= 0 */ GEN H = NULL; if (m <= 0) L--; /* lose series accuracy due to 1/x term */ if (L) { Q = serpsi1(L, v, prec); if (m && m != 1) { H = Hseries(m, L, v, prec); Q = gadd(Q, H); } if (m <= 0) Q = gsub(Q, ginv(pol_x(v))); } else { Q = scalarser(gen_m1, v, 1); setvalp(Q,-1); } } } if (!Q) { /* use psi(1-y)=psi(y)+Pi*cotan(Pi*y) ? */ if (gcmp(real_i(z0),ghalf) < 0) { z0 = gsubsg(1,z0); Y = gsubsg(1,y); } Q = serpsiz0(z0, L, v, prec); } Y2 = serchop0(Y); if (signe(Y2)) Q = gsubst(Q, v, Y2); /* psi(z0 + Y2) = psi(Y) */ if (Y != y) { /* psi(y) = psi(Y) + Pi cotan(Pi Y) */ GEN pi = mppi(prec); if (typ(z0) == t_INT) Y = Y2; /* in this case cotan(Pi*Y2) = cotan(Pi*Y) */ Q = gadd(Q, gmul(pi, gcotan(gmul(pi,Y), prec))); } return Q; } GEN gpsi(GEN x, long prec) { pari_sp av; GEN y; switch(typ(x)) { case t_REAL: case t_COMPLEX: return cxpsi(x,prec); default: av = avma; if (!(y = toser_i(x))) break; return gerepileupto(av, serpsi(y,prec)); } return trans_eval("psi",gpsi,x,prec); } pari-2.11.2/src/basemath/mellininv.c0000644000175000017500000004515513326135265015712 0ustar billbill/* Copyright (C) 2015 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* Computation of inverse Mellin */ /* transforms of gamma products. */ /*******************************************************************/ #ifndef M_E #define M_E 2.7182818284590452354 #endif /* rough approximation to W0(a > -1/e), < 1% relative error */ double dbllambertW0(double a) { if (a < -0.2583) { const double c2 = -1./3, c3 = 11./72, c4 = -43./540, c5 = 769./17280; double p = sqrt(2*(M_E*a+1)); if (a < -0.3243) return -1+p*(1+p*(c2+p*c3)); return -1+p*(1+p*(c2+p*(c3+p*(c4+p*c5)))); } else { double Wd = log(1.+a); Wd *= (1.-log(Wd/a))/(1.+Wd); if (a < 0.6482 && a > -0.1838) return Wd; return Wd*(1.-log(Wd/a))/(1.+Wd); } } /* rough approximation to W_{-1}(0 > a > -1/e), < 1% relative error */ double dbllambertW_1(double a) { if (a < -0.2464) { const double c2 = -1./3, c3 = 11./72, c4 = -43./540, c5 = 769./17280; double p = -sqrt(2*(M_E*a+1)); if (a < -0.3243) return -1+p*(1+p*(c2+p*c3)); return -1+p*(1+p*(c2+p*(c3+p*(c4+p*c5)))); } else { double Wd; a = -a; Wd = -log(a); Wd *= (1.-log(Wd/a))/(1.-Wd); if (a < 0.0056) return -Wd; return -Wd*(1.-log(Wd/a))/(1.-Wd); } } /* ac != 0 */ static double lemma526_i(double ac, double c, double t, double B) { double D = -B/ac; /* sgn(t) = sgn(a) = - sgn(D) */ if (D <= 0) { if (D > -100) { D = -exp(D) / t; if (D < - 1/M_E) return 0; D = dbllambertW_1(D); } else { /* avoid underflow, use asymptotic expansion */ double U = D - log(t); D = U - log(-U); } return pow(maxdd(t, -t * D), c); } else { if (D < 100) D = dbllambertW0(-exp(D) / t); else { /* avoid overflow, use asymptotic expansion */ double U = D - log(-t); D = U - log(U); } return pow(-t * D, c); } } /* b > 0, c > 0; solve x^a exp(-b x^(1/c)) < e^(-B) for x >= 0 */ double dbllemma526(double a, double b, double c, double B) { double ac; if (!a) return B <= 0? 0: pow(B/b, c); ac = a*c; if (B < 0) B = 1e-9; return lemma526_i(ac, c, ac/b, B); } /* Same, special case b/c = 2Pi, the only one needed: for c = d/2 */ double dblcoro526(double a, double c, double B) { if (!a) return B <= 0? 0: pow(B/(2*M_PI*c), c); if (B < 0) B = 1e-9; return lemma526_i(a*c, c, a/(2*M_PI), B); } static const double MELLININV_CUTOFF = 121.; /* C*C */ static GEN MOD2(GEN x) { GEN q = gdivent(x,gen_2); return gsub(x,gmul2n(q,1)); } static GEN RgV_MOD2(GEN v) { long i, l; GEN w = cgetg_copy(v,&l); for (i=1; i 2) c = RgX_Rg_div(c, mpfact(k-1)); gel(C,k) = RgX_to_RgC(c, lgpol(c)); } } /* Algo 3.3: * \phi^(m)(t) = sum_j t^m_j sum_k (-ln t)^k mat[j,k](t^2) */ return gerepilecopy(av, mkvec3(lj,RgV_neg(mj),mat)); } /* Evaluate a vector considered as a polynomial using Horner. Unstable! * If ui != NULL, ui = 1/u, evaluate P(1/u)*u^(deg P): useful for |u|>1 */ static GEN evalvec(GEN vec, long lim, GEN u, GEN ui) { pari_sp ltop = avma; GEN S = gen_0; long n; lim = minss(lim, lg(vec)-1); if (!ui) for (n = lim; n >= 1; --n) S = gmul(u, gadd(gel(vec,n), S)); else { for (n = 1; n <= lim; ++n) S = gmul(ui, gadd(gel(vec,n), S)); S = gmul(gpowgs(u, n), S); } return gerepileupto(ltop, S); } /* gammamellininvinit accessors */ static double get_tmax(long bitprec) { return (M_LN2 / MELLININV_CUTOFF) * bitprec ; } static GEN GMi_get_Vga(GEN K) { return gel(K,2); } static long GMi_get_m(GEN K) { return itos( gel(K,3) ); } static GEN /* [lj,mj,mat], Kderivsmall only */ GMi_get_VS(GEN K) { return gel(K,4); } static GEN /* [Ms,cd,A2], Kderivlarge only */ GMi_get_VL(GEN K) { return gel(K,5); } static double GMi_get_tmax(GEN K, long bitprec) { return (typ(GMi_get_VS(K)) == t_INT)? -1.0 : get_tmax(bitprec); } /* Compute m-th derivative of inverse Mellin at x by generalized power series * around x = 0; x2d = x^(2/d), x is possibly NULL (don't bother about * complex branches). Assume |x|^(2/d) <= tmax = M_LN2*bitprec/MELLININV_CUTOFF*/ static GEN Kderivsmall(GEN K, GEN x, GEN x2d, long bitprec) { pari_sp ltop = avma; GEN Vga = GMi_get_Vga(K), VS = GMi_get_VS(K); GEN lj = gel(VS,1), mj = gel(VS,2), mat = gel(VS,3); GEN d2, Lx, x2, x2i, A, S, pi; long prec, d, N, j, k, limn, m = GMi_get_m(K); double Ed, xd, Wd; N = lg(lj)-1; d = lg(Vga)-1; A = vecsum(Vga); Ed = M_LN2*bitprec / d; xd = maxdd(M_PI*dblmodulus(x2d), 1E-13); /* pi |x|^2/d unless x tiny */ if (xd > Ed) pari_err_BUG("Kderivsmall (x2d too large)"); /* Lemma 5.2.6 (2), a = 1 + log(Pi x^(2/d)) = log(e / xd), * B = log(2)*bitprec / d = Ed */ Wd = dbllambertW0( Ed / (M_E*xd) ); /* solution of w exp(w) = B exp(-a)*/ limn = (long) ceil(2*Ed/Wd); prec = nbits2prec((long) ceil(bitprec+d*xd/M_LN2)); pi = mppi(prec); d2 = gdivsg(d,gen_2); if (x) x = gmul(gtofp(x,prec), gpow(pi,d2,prec)); else x = gpow(gmul(gtofp(x2d,prec),pi), d2, prec); /* at this stage, x has been replaced by pi^(d/2) x */ x2 = gsqr(x); Lx = gpowers(gneg(glog(x,prec)), vecsmall_max(lj)); x2i = (gcmp(gnorml2(x2), gen_1) <= 0)? NULL: ginv(x2); S = gen_0; for (j = 1; j <= N; ++j) { long ljj = lj[j]; GEN s = gen_0; for (k = 1; k <= ljj; k++) s = gadd(s, gmul(gel(Lx,k), evalvec(gmael(mat,j,k), limn, x2, x2i))); S = gadd(S, gmul(gpow(x, gel(mj,j), prec), s)); } A = gsubsg(m*d, A); if (!gequal0(A)) S = gmul(S, gsqrt(gpow(pi, A, prec), prec)); return gerepileupto(ltop, gtofp(S, nbits2prec(bitprec))); } /* In Klarge, we conpute K(t) as (asymptotic) * F(z), where F ~ 1 is given by * a continued fraction and z = Pi t^(2/d). If we take 2n terms in F (n terms * in Euler form), F_n(z) - F(z) is experimentally in exp(- C sqrt(n*z)) * where C ~ 8 for d > 2 [HEURISTIC] and C = 4 (theorem) for d = 1 or d = 2 * and vga = [0,1]. For e^(-E) absolute error, we want * exp(-C sqrt(nz)) < e^-(E+a), where a ~ ln(asymptotic) * i.e. 2n > (E+a)^2 / t^(2/d) * 2/(C^2 Pi); C^2*Pi/2 ~ 100.5 ~ 101 * * In fact, this model becomes wrong for z large: we use instead * * exp(- sqrt(D * nz/log(z+1))) < e^-(E+a), * i.e. 2n > (E+a)^2 * log(1 + Pi t^(2/d))/ t^(2/d) * 2/(D Pi); */ static double get_D(long d) { return d <= 2 ? 157. : 180.; } /* if (abs), absolute error rather than relative */ static void Kderivlarge_optim(GEN K, long abs, GEN t2d,GEN gcd, long *pbitprec, long *pnlim) { GEN Vga = GMi_get_Vga(K), VL = GMi_get_VL(K), A2 = gel(VL,3); long bitprec = *pbitprec, d = lg(Vga)-1; const double D = get_D(d), td = dblmodulus(t2d), cd = gtodouble(gcd); double a, rtd, E = M_LN2*bitprec; rtd = (typ(t2d) == t_COMPLEX)? gtodouble(gel(t2d,1)): td; /* A2/2 = A, log(td) = (2/d)*log t */ a = d*gtodouble(A2)*log2(td)/2 - (M_PI/M_LN2)*d*rtd + log2(cd); /*log2 K(t)~a*/ /* if bitprec <= 0, caller should return K(t) ~ 0 */ bitprec += 64; if (abs) { bitprec += ceil(a); if (a <= -65) E = M_LN2*bitprec; /* guarantees E <= initial E */ } *pbitprec = bitprec; *pnlim = ceil(E*E * log2(1+M_PI*td) / (D*td)); } /* Compute m-th derivative of inverse Mellin at t by continued fraction of * asymptotic expansion; t2d = t^(2/d). If t is NULL, "lfun" mode: don't * bother about complex branches + use absolute (rather than relative) * accuracy */ static GEN Kderivlarge(GEN K, GEN t, GEN t2d, long bitprec0) { pari_sp ltop = avma; GEN tdA, P, S, pi, z, Vga = GMi_get_Vga(K); const long d = lg(Vga)-1; GEN M, VL = GMi_get_VL(K), Ms = gel(VL,1), cd = gel(VL,2), A2 = gel(VL,3); long status, prec, nlim, m = GMi_get_m(K), bitprec = bitprec0; Kderivlarge_optim(K, !t, t2d, cd, &bitprec, &nlim); if (bitprec <= 0) return gen_0; prec = nbits2prec(bitprec); t2d = gtofp(t2d, prec); if (t) tdA = gpow(t, gdivgs(A2,d), prec); else tdA = gpow(t2d, gdivgs(A2,2), prec); tdA = gmul(cd, tdA); pi = mppi(prec); z = gmul(pi, t2d); P = gmul(tdA, gexp(gmulsg(-d, z), prec)); if (m) P = gmul(P, gpowgs(mulsr(-2, pi), m)); M = gel(Ms,1); status = itos(gel(Ms,2)); if (status == 2) { if (lg(M) == 2) /* shortcut: continued fraction is constant */ S = gel(M,1); else S = poleval(RgV_to_RgX(M, 0), ginv(z)); } else { S = contfraceval_inv(M, z, nlim/2); if (DEBUGLEVEL>3) { GEN S0 = contfraceval_inv(M, z, nlim/2 + 1); long e = gexpo(gmul(P, gabs(gsub(S,S0),0))); if (-e < bitprec0) err_printf("Kderivlarge: e = %ld, bit = %ld\n",e,bitprec0); } if (status == 1) S = gmul(S, gsubsg(1, ginv(gmul(z, pi)))); } return gerepileupto(ltop, gmul(P, S)); } /* Dokchitser's coefficients used for asymptotic expansion of inverse Mellin * 2 <= p <= min(n+1, d) */ static GEN fun_vp(long p, long n, long d, GEN SM, GEN vsinh) { pari_sp ltop = avma; long m, j, k; GEN s = gen_0; for (m = 0; m <= p; ++m) { GEN pr = gen_1, s2 = gen_0, sh = gel(vsinh, d-p+1);/* (sh(x)/x)^(d-p) */ long pm = p-m; for (j = m; j < p; ++j) pr = muliu(pr, d-j); for (k = 0; k <= pm; k+=2) { GEN e = gdiv(powuu(2*n-p+1, pm-k), mpfact(pm-k)); s2 = gadd(s2, gmul(e, RgX_coeff(sh, k))); } s = gadd(s, gmul(gmul(gel(SM, m+1), pr), s2)); if (gc_needed(ltop, 1)) s = gerepilecopy(ltop, s); } return gerepileupto(ltop, gmul(gdivsg(-d, powuu(2*d, p)), s)); } /* Asymptotic expansion of inverse Mellin, to length nlimmax. Set status = 0 * (regular), 1 (one Hankel determinant vanishes => contfracinit will fail) * or 2 (same as 1, but asymptotic expansion is finite!) * * If status = 2, the asymptotic expansion is finite so return only * the necessary number of terms nlim <= nlimmax + d. */ static GEN Klargeinit0(GEN Vga, long nlimmax, long *status) { const long prec = LOWDEFAULTPREC; const long d = lg(Vga)-1; long k, n, m, cnt; GEN pol, SM, nS1, se, vsinh, M, dk; if (d==1 || (d==2 && gequal1(gabs(gsub(gel(Vga,1), gel(Vga,2)), prec)))) { /* shortcut */ *status = 2; return mkvec(gen_1); } /* d >= 2 */ *status = 0; pol = roots_to_pol(gneg(Vga), 0); /* deg(pol) = d */ nS1 = gpowers(gneg(RgX_coeff(pol, d-1)), d); dk = gpowers(utoi(d), d-1); SM = cgetg(d+3, t_VEC); for (m = 0; m <= d; ++m) { pari_sp btop = avma; GEN s = gmul(gdivgs(gel(nS1, m+1), d), binomialuu(d, m)); for (k = 1; k <= m; ++k) { GEN e = gmul(gel(nS1, m-k+1), gel(dk, k)); s = gadd(s, gmul(gmul(e, binomialuu(d-k, m-k)), RgX_coeff(pol, d-k))); } gel(SM, m+1) = gerepileupto(btop, s); } se = gdiv(gsinh(RgX_to_ser(pol_x(0), d+2), prec), pol_x(0)); vsinh = gpowers(se, d); M = vectrunc_init(nlimmax + d); vectrunc_append(M, gen_1); for (n=2, cnt=0; (n <= nlimmax) || cnt; ++n) { pari_sp btop = avma; long p, ld = minss(d, n); GEN s = gen_0; for (p = 2; p <= ld; ++p) s = gadd(s, gmul(fun_vp(p, n-1, d, SM, vsinh), gel(M, n+1-p))); s = gerepileupto(btop, gdivgs(s, n-1)); vectrunc_append(M, s); if (!isintzero(s)) { if (n >= nlimmax) break; cnt = 0; } else { cnt++; *status = 1; if (cnt >= d-1) { *status = 2; setlg(M, lg(M) - (d-1)); break; } } } return M; } /* remove trailing zeros from vector. */ static void stripzeros(GEN M) { long i; for(i = lg(M)-1; i >= 1; --i) if (!gequal0(gel(M, i))) break; setlg(M, i+1); } /* Asymptotic expansion of the m-th derivative of inverse Mellin, to length * nlimmax. If status = 2, the asymptotic expansion is finite so return only * the necessary number of terms nlim <= nlimmax + d. */ static GEN gammamellininvasymp_i(GEN Vga, long nlimmax, long m, long *status) { pari_sp ltop = avma; GEN M, A, Aadd; long d, i, nlim, n; M = Klargeinit0(Vga, nlimmax, status); if (!m) return gerepilecopy(ltop, M); d = lg(Vga)-1; /* half the exponent of t in asymptotic expansion. */ A = gdivgs(gaddsg(1-d, vecsum(Vga)), 2*d); if (*status == 2) M = shallowconcat(M, zerovec(m)); nlim = lg(M)-1; Aadd = gdivgs(stoi(2-d), 2*d); /* (1/d) - (1/2) */ for (i = 1; i <= m; i++, A = gadd(A,Aadd)) for (n = nlim-1; n >= 1; --n) gel(M, n+1) = gsub(gel(M, n+1), gmul(gel(M, n), gsub(A, gdivgs(stoi(n-1), d)))); stripzeros(M); return gerepilecopy(ltop, M); } GEN gammamellininvasymp(GEN Vga, long nlimmax, long m) { long status; if (!is_vec_t(typ(Vga))) pari_err_TYPE("gammamellininvinit",Vga); return gammamellininvasymp_i(Vga, nlimmax, m, &status); } /* Does the continued fraction of the asymptotic expansion M at oo of inverse * Mellin transform attached to Vga have zero Hankel determinants ? */ static long ishankelspec(GEN Vga, GEN M) { long status, i, d = lg(Vga)-1; if (d == 5 || d == 7) { /* known bad cases: a x 5 and a x 7 */ GEN v1 = gel(Vga, 1); for (i = 2; i <= d; ++i) if (!gequal(gel(Vga,i), v1)) break; if (i > d) return 1; } status = 0; /* Heuristic: if 6 first terms in contfracinit don't fail, assume it's OK */ pari_CATCH(e_INV) { status = 1; } pari_TRY { contfracinit(M, minss(lg(M)-2,6)); } pari_ENDCATCH; return status; } /* Initialize data for computing m-th derivative of inverse Mellin */ GEN gammamellininvinit(GEN Vga, long m, long bitprec) { pari_sp ltop = avma; GEN A2, M, VS, VL, cd; long d = lg(Vga)-1, status; const double C2 = MELLININV_CUTOFF, D = get_D(d); double E = M_LN2*bitprec, tmax = get_tmax(bitprec); /* = E/C2 */ const long nlimmax = ceil(E*log2(1+M_PI*tmax)*C2/D); if (!is_vec_t(typ(Vga))) pari_err_TYPE("gammamellininvinit",Vga); A2 = gaddsg(m*(2-d) + 1-d, vecsum(Vga)); cd = (d <= 2)? gen_2: gsqrt(gdivgs(int2n(d+1), d), nbits2prec(bitprec)); /* if in Klarge, we have |t| > tmax = E/C2, thus nlim < E*C2/D. */ M = gammamellininvasymp_i(Vga, nlimmax, m, &status); if (status == 2) { tmax = -1.; /* only use Klarge */ VS = gen_0; } else { long prec = nbits2prec((4*bitprec)/3); VS = Kderivsmallinit(Vga, m, bitprec); if (status == 0 && ishankelspec(Vga, M)) status = 1; if (status == 1) { /* a Hankel determinant vanishes => contfracinit is undefined. So compute K(t) / (1 - 1/(pi^2*t)) instead of K(t)*/ GEN t = ginv(mppi(prec)); long i; for (i = 2; i < lg(M); ++i) gel(M, i) = gadd(gel(M, i), gmul(gel(M, i-1), t)); } else M = RgC_gtofp(M, prec); /* convert from rationals to t_REAL: faster */ M = contfracinit(M, lg(M)-2); } VL = mkvec3(mkvec2(M, stoi(status)), cd, A2); return gerepilecopy(ltop, mkvec5(dbltor(tmax), Vga, stoi(m), VS, VL)); } /* Compute m-th derivative of inverse Mellin at s2d = s^(d/2) using * initialization data. Use Taylor expansion at 0 for |s2d| < tmax, and * asymptotic expansion at oo otherwise. WARNING: assume that accuracy * has been increased according to tmax by the CALLING program. */ GEN gammamellininvrt(GEN K, GEN s2d, long bitprec) { if (dblmodulus(s2d) < GMi_get_tmax(K, bitprec)) return Kderivsmall(K, NULL, s2d, bitprec); else return Kderivlarge(K, NULL, s2d, bitprec); } /* Compute inverse Mellin at s. K from gammamellininv OR a Vga, in which * case the initialization data is computed. */ GEN gammamellininv(GEN K, GEN s, long m, long bitprec) { pari_sp av = avma; GEN z, s2d; long d; if (!is_vec_t(typ(K))) pari_err_TYPE("gammamellininv",K); if (lg(K) != 6 || !is_vec_t(typ(GMi_get_Vga(K)))) K = gammamellininvinit(K, m, bitprec); d = lg(GMi_get_Vga(K))-1; s2d = gpow(s, gdivgs(gen_2, d), nbits2prec(bitprec)); if (dblmodulus(s2d) < GMi_get_tmax(K, bitprec)) z = Kderivsmall(K, s, s2d, bitprec); else z = Kderivlarge(K, s, s2d, bitprec); return gerepileupto(av, z); } pari-2.11.2/src/basemath/FlxqE.c0000644000175000017500000013523113326135265014727 0ustar billbill/* Copyright (C) 2012 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* Not so fast arithmetic with points over elliptic curves over Fq, small characteristic. */ /***********************************************************************/ /** **/ /** FlxqE **/ /** **/ /***********************************************************************/ /* Theses functions deal with point over elliptic curves over Fq defined * by an equation of the form y^2=x^3+a4*x+a6. * Most of the time a6 is omitted since it can be recovered from any point * on the curve. */ GEN RgE_to_FlxqE(GEN x, GEN T, ulong p) { if (ell_is_inf(x)) return x; retmkvec2(Rg_to_Flxq(gel(x,1),T,p),Rg_to_Flxq(gel(x,2),T,p)); } GEN FlxqE_changepoint(GEN x, GEN ch, GEN T, ulong p) { pari_sp av = avma; GEN p1,z,u,r,s,t,v,v2,v3; if (ell_is_inf(x)) return x; u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); v = Flxq_inv(u, T, p); v2 = Flxq_sqr(v, T, p); v3 = Flxq_mul(v,v2, T, p); p1 = Flx_sub(gel(x,1),r, p); z = cgetg(3,t_VEC); gel(z,1) = Flxq_mul(v2, p1, T, p); gel(z,2) = Flxq_mul(v3, Flx_sub(gel(x,2), Flx_add(Flxq_mul(s, p1, T, p),t, p), p), T, p); return gerepileupto(av, z); } GEN FlxqE_changepointinv(GEN x, GEN ch, GEN T, ulong p) { GEN u, r, s, t, X, Y, u2, u3, u2X, z; if (ell_is_inf(x)) return x; X = gel(x,1); Y = gel(x,2); u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4); u2 = Flxq_sqr(u, T, p); u3 = Flxq_mul(u,u2, T, p); u2X = Flxq_mul(u2,X, T, p); z = cgetg(3, t_VEC); gel(z,1) = Flx_add(u2X,r, p); gel(z,2) = Flx_add(Flxq_mul(u3,Y, T, p), Flx_add(Flxq_mul(s,u2X, T, p), t, p), p); return z; } static ulong nonsquare_Fl(ulong p) { ulong a; do a = random_Fl(p); while (krouu(a, p) >= 0); return a; } static GEN nonsquare_Flxq(GEN T, ulong p) { pari_sp av = avma; long n = degpol(T), vs = T[1]; GEN a; if (odd(n)) return mkvecsmall2(vs, nonsquare_Fl(p)); do { avma = av; a = random_Flx(n, vs, p); } while (Flxq_issquare(a, T, p)); return a; } void Flxq_elltwist(GEN a, GEN a6, GEN T, ulong p, GEN *pt_a, GEN *pt_a6) { GEN d = nonsquare_Flxq(T, p); GEN d2 = Flxq_sqr(d, T, p), d3 = Flxq_mul(d2, d, T, p); if (typ(a)==t_VECSMALL) { *pt_a = Flxq_mul(a, d2, T, p); *pt_a6 = Flxq_mul(a6, d3, T, p); } else { *pt_a = mkvec(Flxq_mul(gel(a,1), d, T, p)); *pt_a6 = Flxq_mul(a6, d3, T, p); } } static GEN FlxqE_dbl_slope(GEN P, GEN a4, GEN T, ulong p, GEN *slope) { GEN x, y, Q; if (ell_is_inf(P) || !lgpol(gel(P,2))) return ellinf(); x = gel(P,1); y = gel(P,2); if (p==3UL) *slope = typ(a4)==t_VEC ? Flxq_div(Flxq_mul(x, gel(a4, 1), T, p), y, T, p) : Flxq_div(a4, Flx_neg(y, p), T, p); else { GEN sx = Flx_add(Flx_triple(Flxq_sqr(x, T, p), p), a4, p); *slope = Flxq_div(sx, Flx_double(y, p), T, p); } Q = cgetg(3,t_VEC); gel(Q, 1) = Flx_sub(Flxq_sqr(*slope, T, p), Flx_double(x, p), p); if (typ(a4)==t_VEC) gel(Q, 1) = Flx_sub(gel(Q, 1), gel(a4, 1), p); gel(Q, 2) = Flx_sub(Flxq_mul(*slope, Flx_sub(x, gel(Q, 1), p), T, p), y, p); return Q; } GEN FlxqE_dbl(GEN P, GEN a4, GEN T, ulong p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FlxqE_dbl_slope(P,a4, T, p,&slope)); } static GEN FlxqE_add_slope(GEN P, GEN Q, GEN a4, GEN T, ulong p, GEN *slope) { GEN Px, Py, Qx, Qy, R; if (ell_is_inf(P)) return Q; if (ell_is_inf(Q)) return P; Px = gel(P,1); Py = gel(P,2); Qx = gel(Q,1); Qy = gel(Q,2); if (Flx_equal(Px, Qx)) { if (Flx_equal(Py, Qy)) return FlxqE_dbl_slope(P, a4, T, p, slope); else return ellinf(); } *slope = Flxq_div(Flx_sub(Py, Qy, p), Flx_sub(Px, Qx, p), T, p); R = cgetg(3,t_VEC); gel(R, 1) = Flx_sub(Flx_sub(Flxq_sqr(*slope, T, p), Px, p), Qx, p); if (typ(a4)==t_VEC) gel(R, 1) = Flx_sub(gel(R, 1),gel(a4, 1), p); gel(R, 2) = Flx_sub(Flxq_mul(*slope, Flx_sub(Px, gel(R, 1), p), T, p), Py, p); return R; } GEN FlxqE_add(GEN P, GEN Q, GEN a4, GEN T, ulong p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FlxqE_add_slope(P,Q,a4, T, p,&slope)); } static GEN FlxqE_neg_i(GEN P, ulong p) { if (ell_is_inf(P)) return P; return mkvec2(gel(P,1), Flx_neg(gel(P,2), p)); } GEN FlxqE_neg(GEN P, GEN T, ulong p) { (void) T; if (ell_is_inf(P)) return ellinf(); return mkvec2(gcopy(gel(P,1)), Flx_neg(gel(P,2), p)); } GEN FlxqE_sub(GEN P, GEN Q, GEN a4, GEN T, ulong p) { pari_sp av = avma; GEN slope; return gerepileupto(av, FlxqE_add_slope(P, FlxqE_neg_i(Q, p), a4, T, p, &slope)); } struct _FlxqE { GEN a4, a6; GEN T; ulong p; }; static GEN _FlxqE_dbl(void *E, GEN P) { struct _FlxqE *ell = (struct _FlxqE *) E; return FlxqE_dbl(P, ell->a4, ell->T, ell->p); } static GEN _FlxqE_add(void *E, GEN P, GEN Q) { struct _FlxqE *ell=(struct _FlxqE *) E; return FlxqE_add(P, Q, ell->a4, ell->T, ell->p); } static GEN _FlxqE_mul(void *E, GEN P, GEN n) { pari_sp av = avma; struct _FlxqE *e=(struct _FlxqE *) E; long s = signe(n); if (!s || ell_is_inf(P)) return ellinf(); if (s<0) P = FlxqE_neg(P, e->T, e->p); if (is_pm1(n)) return s>0? gcopy(P): P; return gerepileupto(av, gen_pow(P, n, e, &_FlxqE_dbl, &_FlxqE_add)); } GEN FlxqE_mul(GEN P, GEN n, GEN a4, GEN T, ulong p) { struct _FlxqE E; E.a4= a4; E.T = T; E.p = p; return _FlxqE_mul(&E, P, n); } /* 3*x^2+2*a2*x = -a2*x, and a2!=0 */ /* Finds a random non-singular point on E */ static GEN random_F3xqE(GEN a2, GEN a6, GEN T) { pari_sp ltop = avma; GEN x, y, rhs; const ulong p=3; do { avma= ltop; x = random_Flx(get_Flx_degree(T),get_Flx_var(T),p); rhs = Flx_add(Flxq_mul(Flxq_sqr(x, T, p), Flx_add(x, a2, p), T, p), a6, p); } while ((!lgpol(rhs) && !lgpol(x)) || !Flxq_issquare(rhs, T, p)); y = Flxq_sqrt(rhs, T, p); if (!y) pari_err_PRIME("random_F3xqE", T); return gerepilecopy(ltop, mkvec2(x, y)); } /* Finds a random non-singular point on E */ GEN random_FlxqE(GEN a4, GEN a6, GEN T, ulong p) { pari_sp ltop = avma; GEN x, x2, y, rhs; if (typ(a4)==t_VEC) return random_F3xqE(gel(a4,1), a6, T); do { avma= ltop; x = random_Flx(get_Flx_degree(T),get_Flx_var(T),p); x2 = Flxq_sqr(x, T, p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */ rhs = Flx_add(Flxq_mul(x, Flx_add(x2, a4, p), T, p), a6, p); } while ((!lgpol(rhs) && !lgpol(Flx_add(Flx_triple(x2, p), a4, p))) || !Flxq_issquare(rhs, T, p)); y = Flxq_sqrt(rhs, T, p); if (!y) pari_err_PRIME("random_FlxqE", T); return gerepilecopy(ltop, mkvec2(x, y)); } static GEN _FlxqE_rand(void *E) { struct _FlxqE *ell=(struct _FlxqE *) E; return random_FlxqE(ell->a4, ell->a6, ell->T, ell->p); } static const struct bb_group FlxqE_group={_FlxqE_add,_FlxqE_mul,_FlxqE_rand,hash_GEN,zvV_equal,ell_is_inf, NULL}; const struct bb_group * get_FlxqE_group(void ** pt_E, GEN a4, GEN a6, GEN T, ulong p) { struct _FlxqE *e = (struct _FlxqE *) stack_malloc(sizeof(struct _FlxqE)); e->a4 = a4; e->a6 = a6; e->T = Flx_get_red(T, p); e->p = p; *pt_E = (void *) e; return &FlxqE_group; } GEN FlxqE_order(GEN z, GEN o, GEN a4, GEN T, ulong p) { pari_sp av = avma; struct _FlxqE e; e.a4=a4; e.T=T; e.p=p; return gerepileuptoint(av, gen_order(z, o, (void*)&e, &FlxqE_group)); } GEN FlxqE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, ulong p) { pari_sp av = avma; struct _FlxqE e; e.a4=a4; e.T=T; e.p=p; return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &FlxqE_group)); } /***********************************************************************/ /** **/ /** Pairings **/ /** **/ /***********************************************************************/ /* Derived from APIP from and by Jerome Milan, 2012 */ static GEN FlxqE_vert(GEN P, GEN Q, GEN a4, GEN T, ulong p) { long vT = get_Flx_var(T); GEN df; if (ell_is_inf(P)) return pol1_Flx(vT); if (!Flx_equal(gel(Q, 1), gel(P, 1))) return Flx_sub(gel(Q, 1), gel(P, 1), p); if (lgpol(gel(P,2))!=0) return pol1_Flx(vT); df = typ(a4)==t_VEC ? Flxq_mul(gel(P,1), Flx_mulu(gel(a4, 1), 2, p), T, p) : a4; return Flxq_inv(Flx_add(Flx_mulu(Flxq_sqr(gel(P,1), T, p), 3, p), df, p), T, p); } static GEN FlxqE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN T, ulong p) { long vT = get_Flx_var(T); GEN x = gel(Q, 1), y = gel(Q, 2); GEN tmp1 = Flx_sub(x, gel(R, 1), p); GEN tmp2 = Flx_add(Flxq_mul(tmp1, slope, T, p), gel(R, 2), p); if (!Flx_equal(y, tmp2)) return Flx_sub(y, tmp2, p); if (lgpol(y) == 0) return pol1_Flx(vT); else { GEN s1, s2, a2 = typ(a4)==t_VEC ? gel(a4,1): NULL; GEN y2i = Flxq_inv(Flx_mulu(y, 2, p), T, p); GEN df = a2 ? Flxq_mul(x, Flx_mulu(a2, 2, p), T, p): a4; GEN x3, ddf; s1 = Flxq_mul(Flx_add(Flx_mulu(Flxq_sqr(x, T, p), 3, p), df, p), y2i, T, p); if (!Flx_equal(s1, slope)) return Flx_sub(s1, slope, p); x3 = Flx_mulu(x, 3, p); ddf = a2 ? Flx_add(x3, a2, p): x3; s2 = Flxq_mul(Flx_sub(ddf, Flxq_sqr(s1, T, p), p), y2i, T, p); return lgpol(s2)!=0 ? s2: y2i; } } /* Computes the equation of the line tangent to R and returns its evaluation at the point Q. Also doubles the point R. */ static GEN FlxqE_tangent_update(GEN R, GEN Q, GEN a4, GEN T, ulong p, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = ellinf(); return pol1_Flx(get_Flx_var(T)); } else if (!lgpol(gel(R,2))) { *pt_R = ellinf(); return FlxqE_vert(R, Q, a4, T, p); } else { GEN slope; *pt_R = FlxqE_dbl_slope(R, a4, T, p, &slope); return FlxqE_Miller_line(R, Q, slope, a4, T, p); } } /* Computes the equation of the line through R and P, and returns its evaluation at the point Q. Also adds P to the point R. */ static GEN FlxqE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN T, ulong p, GEN *pt_R) { if (ell_is_inf(R)) { *pt_R = gcopy(P); return FlxqE_vert(P, Q, a4, T, p); } else if (ell_is_inf(P)) { *pt_R = gcopy(R); return FlxqE_vert(R, Q, a4, T, p); } else if (Flx_equal(gel(P, 1), gel(R, 1))) { if (Flx_equal(gel(P, 2), gel(R, 2))) return FlxqE_tangent_update(R, Q, a4, T, p, pt_R); else { *pt_R = ellinf(); return FlxqE_vert(R, Q, a4, T, p); } } else { GEN slope; *pt_R = FlxqE_add_slope(P, R, a4, T, p, &slope); return FlxqE_Miller_line(R, Q, slope, a4, T, p); } } /* Returns the Miller function f_{m, Q} evaluated at the point P using the standard Miller algorithm. */ struct _FlxqE_miller { ulong p; GEN T, a4, P; }; static GEN FlxqE_Miller_dbl(void* E, GEN d) { struct _FlxqE_miller *m = (struct _FlxqE_miller *)E; ulong p = m->p; GEN T = m->T, a4 = m->a4, P = m->P; GEN v, line; GEN num = Flxq_sqr(gel(d,1), T, p); GEN denom = Flxq_sqr(gel(d,2), T, p); GEN point = gel(d,3); line = FlxqE_tangent_update(point, P, a4, T, p, &point); num = Flxq_mul(num, line, T, p); v = FlxqE_vert(point, P, a4, T, p); denom = Flxq_mul(denom, v, T, p); return mkvec3(num, denom, point); } static GEN FlxqE_Miller_add(void* E, GEN va, GEN vb) { struct _FlxqE_miller *m = (struct _FlxqE_miller *)E; ulong p = m->p; GEN T = m->T, a4 = m->a4, P = m->P; GEN v, line, point; GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3); GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3); GEN num = Flxq_mul(na, nb, T, p); GEN denom = Flxq_mul(da, db, T, p); line = FlxqE_chord_update(pa, pb, P, a4, T, p, &point); num = Flxq_mul(num, line, T, p); v = FlxqE_vert(point, P, a4, T, p); denom = Flxq_mul(denom, v, T, p); return mkvec3(num, denom, point); } static GEN FlxqE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN T, ulong p) { pari_sp ltop = avma; struct _FlxqE_miller d; GEN v, num, denom, g1; d.a4 = a4; d.T = T; d.p = p; d.P = P; g1 = pol1_Flx(get_Flx_var(T)); v = gen_pow(mkvec3(g1,g1,Q), m, (void*)&d, FlxqE_Miller_dbl, FlxqE_Miller_add); num = gel(v,1); denom = gel(v,2); return gerepileupto(ltop, Flxq_div(num, denom, T, p)); } GEN FlxqE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p) { pari_sp ltop = avma; GEN num, denom, result; if (ell_is_inf(P) || ell_is_inf(Q) || Flx_equal(P,Q)) return pol1_Flx(get_Flx_var(T)); num = FlxqE_Miller(P, Q, m, a4, T, p); denom = FlxqE_Miller(Q, P, m, a4, T, p); result = Flxq_div(num, denom, T, p); if (mpodd(m)) result = Flx_neg(result, p); return gerepileupto(ltop, result); } GEN FlxqE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p) { if (ell_is_inf(P) || ell_is_inf(Q)) return pol1_Flx(get_Flx_var(T)); return FlxqE_Miller(P, Q, m, a4, T, p); } static GEN _FlxqE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F) { struct _FlxqE *e = (struct _FlxqE *) E; return Flxq_order(FlxqE_weilpairing(P,Q,m,e->a4,e->T,e->p), F, e->T, e->p); } GEN Flxq_ellgroup(GEN a4, GEN a6, GEN N, GEN T, ulong p, GEN *pt_m) { struct _FlxqE e; GEN q = powuu(p, get_Flx_degree(T)); e.a4=a4; e.a6=a6; e.T=T; e.p=p; return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &FlxqE_group, _FlxqE_pairorder); } GEN Flxq_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, ulong p) { GEN P; pari_sp av = avma; struct _FlxqE e; e.a4=a4; e.a6=a6; e.T=T; e.p=p; switch(lg(D)-1) { case 0: return cgetg(1,t_VEC); case 1: P = gen_gener(gel(D,1), (void*)&e, &FlxqE_group); P = mkvec(FlxqE_changepoint(P, ch, T, p)); break; default: P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FlxqE_group, _FlxqE_pairorder); gel(P,1) = FlxqE_changepoint(gel(P,1), ch, T, p); gel(P,2) = FlxqE_changepoint(gel(P,2), ch, T, p); break; } return gerepilecopy(av, P); } /***********************************************************************/ /** **/ /** Point counting **/ /** **/ /***********************************************************************/ static GEN _can_invl(void *E, GEN V) {(void) E; return V; } static GEN _can_lin(void *E, GEN F, GEN V, GEN q) { GEN v = RgX_splitting(V, 3); (void) E; return FpX_sub(V,ZXV_dotproduct(v, F), q); } static GEN _can_iter(void *E, GEN f, GEN q) { GEN h = RgX_splitting(f,3); GEN h1s = ZX_sqr(gel(h,1)), h2s = ZX_sqr(gel(h,2)), h3s = ZX_sqr(gel(h,3)); GEN h12 = ZX_mul(gel(h,1), gel(h,2)); GEN h13 = ZX_mul(gel(h,1), gel(h,3)); GEN h23 = ZX_mul(gel(h,2), gel(h,3)); GEN h1c = ZX_mul(gel(h,1), h1s); GEN h3c = ZX_mul(gel(h,3), h3s); GEN th = ZX_mul(ZX_sub(h2s,ZX_mulu(h13,3)),gel(h,2)); GEN y = FpX_sub(f,ZX_add(RgX_shift_shallow(h3c,2),ZX_add(RgX_shift_shallow(th,1),h1c)),q); (void) E; return mkvecn(7,y,h1s,h2s,h3s,h12,h13,h23); } static GEN _can_invd(void *E, GEN V, GEN v, GEN qM, long M) { GEN h1s=gel(v,2), h2s=gel(v,3), h3s=gel(v,4); GEN h12=gel(v,5), h13=gel(v,6), h23=gel(v,7); GEN F = mkvec3(ZX_sub(h1s,RgX_shift_shallow(h23,1)),RgX_shift_shallow(ZX_sub(h2s,h13),1), ZX_sub(RgX_shift_shallow(h3s,2),RgX_shift_shallow(h12,1))); (void)E; return gen_ZpX_Dixon(ZXV_Z_mul(F, utoi(3)), V, qM, utoi(3), M, NULL, _can_lin, _can_invl); } static GEN F3x_canonlift(GEN P, long n) { return gen_ZpX_Newton(Flx_to_ZX(P),utoi(3), n, NULL, _can_iter, _can_invd); } static GEN _can5_invl(void *E, GEN V) {(void) E; return V; } static GEN _can5_lin(void *E, GEN F, GEN V, GEN q) { ulong p = *(ulong*)E; GEN v = RgX_splitting(V, p); return FpX_sub(V,ZXV_dotproduct(v, F), q); } /* P(X,t) -> P(X*t^n,t) mod (t^p-1) */ static GEN _shift(GEN P, long n, ulong p, long v) { long i, l=lg(P); GEN r = cgetg(l,t_POL); r[1] = P[1]; for(i=2;ip, get_FpX_var(d->T)); GEN c = FpXQX_mul(a, bn, d->T, d->q); return mkvec2(c, addii(gel(A,2), gel(B,2))); } static GEN _can5_sqr(void *E, GEN A) { return _can5_mul(E,A,A); } static GEN _can5_iter(void *E, GEN f, GEN q) { pari_sp av = avma; struct _can_mul D; ulong p = *(ulong*)E; long i, vT = fetch_var(); GEN N, P, d, V, fs; D.q = q; D.T = ZX_Z_sub(pol_xn(p,vT),gen_1); D.p = p; fs = mkvec2(_shift(f, 1, p, vT), gen_1); N = gel(gen_powu(fs,p-1,(void*)&D,_can5_sqr,_can5_mul),1); N = simplify_shallow(FpXQX_red(N,polcyclo(p,vT),q)); P = FpX_mul(N,f,q); P = RgX_deflate(P, p); d = RgX_splitting(N, p); V = cgetg(p+1,t_VEC); gel(V,1) = ZX_mulu(gel(d,1), p); for(i=2; i<= (long)p; i++) gel(V,i) = ZX_mulu(RgX_shift_shallow(gel(d,p+2-i), 1), p); (void)delete_var(); return gerepilecopy(av, mkvec2(ZX_sub(f,P),V)); } static GEN _can5_invd(void *E, GEN H, GEN v, GEN qM, long M) { ulong p = *(long*)E; return gen_ZpX_Dixon(gel(v,2), H, qM, utoi(p), M, E, _can5_lin, _can5_invl); } static GEN Flx_canonlift(GEN P, long n, ulong p) { return p==3 ? F3x_canonlift(P,n): gen_ZpX_Newton(Flx_to_ZX(P),utoi(p), n, &p, _can5_iter, _can5_invd); } /* assume a and n are coprime */ static GEN RgX_circular_shallow(GEN P, long a, long n) { long i, l = lgpol(P); GEN Q = cgetg(2+n,t_POL); Q[1] = P[1]; for(i=0; iTp; ulong p = d->p; GEN xai = Flxq_mul(ZX_to_Flx(x, p), d->ai, T, p); return Flx_to_ZX(Flxq_lroot_fast(xai, d->sqx, T, p)); } static GEN _lift_lin(void *E, GEN F, GEN x2, GEN q) { struct _lift_lin *d = (struct _lift_lin *) E; pari_sp av = avma; GEN T = gel(F,3), Xm = gel(F,4); GEN y2 = ZpXQ_frob(x2, Xm, T, q, d->p); GEN lin = FpX_add(ZX_mul(gel(F,1), y2), ZX_mul(gel(F,2), x2), q); return gerepileupto(av, FpX_rem(lin, T, q)); } static GEN FpM_FpXV_bilinear(GEN P, GEN X, GEN Y, GEN p) { pari_sp av = avma; GEN s = ZX_mul(FpXV_FpC_mul(X,gel(P,1),p),gel(Y,1)); long i, l = lg(P); for(i=2; ip; long n = lg(d->phi)-2; GEN TN = FpXT_red(d->T, q), XN = FpXV_red(d->Xm, q); GEN y2 = ZpXQ_frob(x2, XN, TN, q, p); GEN xp = FpXQ_powers(x2, n, TN, q); GEN yp = FpXQ_powers(y2, n, TN, q); GEN V = FpM_FpXQV_bilinear(d->phi,xp,yp,TN,q); return mkvec3(V,xp,yp); } static GEN _lift_invd(void *E, GEN V, GEN v, GEN qM, long M) { struct _lift_iso *d = (struct _lift_iso *) E; struct _lift_lin e; ulong p = d->p; GEN TM = FpXT_red(d->T, qM), XM = FpXV_red(d->Xm, qM); GEN xp = FpXV_red(gel(v,2), qM); GEN yp = FpXV_red(gel(v,3), qM); GEN Dx = FpM_FpXQV_bilinear(d->phi, FpXC_powderiv(xp, qM), yp, TM, qM); GEN Dy = FpM_FpXQV_bilinear(d->phi, xp, FpXC_powderiv(yp, qM), TM, qM); GEN F = mkvec4(Dy, Dx, TM, XM); e.ai = Flxq_inv(ZX_to_Flx(Dy,p),d->Tp,p); e.sqx = d->sqx; e.Tp = d->Tp; e.p=p; e.Xm = XM; return gen_ZpX_Dixon(F,V,qM,utoi(p),M,(void*) &e, _lift_lin, _lift_invl); } static GEN lift_isogeny(GEN phi, GEN x0, long n, GEN Xm, GEN T, GEN sqx, GEN Tp, ulong p) { struct _lift_iso d; d.phi=phi; d.Xm=Xm; d.T=T; d.sqx=sqx; d.Tp=Tp; d.p=p; return gen_ZpX_Newton(x0, utoi(p), n,(void*)&d, _lift_iter, _lift_invd); } static GEN getc2(GEN act, GEN X, GEN T, GEN q, ulong p, long N) { GEN A1 = RgV_to_RgX(gel(act,1),0), A2 = RgV_to_RgX(gel(act,2),0); long n = brent_kung_optpow(maxss(degpol(A1),degpol(A2)),2,1); GEN xp = FpXQ_powers(X,n,T,q); GEN P = FpX_FpXQV_eval(A1, xp, T, q); GEN Q = FpX_FpXQV_eval(A2, xp, T, q); return ZpXQ_div(P, Q, T, q, utoi(p), N); } struct _ZpXQ_norm { long n; GEN T, p; }; static GEN ZpXQ_norm_mul(void *E, GEN x, GEN y) { struct _ZpXQ_norm *D = (struct _ZpXQ_norm*)E; GEN P = gel(x,1), Q = gel(y,1); long a = mael(x,2,1), b = mael(y,2,1); retmkvec2(FpXQ_mul(P,ZpXQ_frob_cyc(Q, D->T, D->p, a), D->T, D->p), mkvecsmall((a*b)%D->n)); } static GEN ZpXQ_norm_sqr(void *E, GEN x) { return ZpXQ_norm_mul(E, x, x); } /* Assume T = Phi_(n) and n prime */ GEN ZpXQ_norm_pcyc(GEN x, GEN T, GEN q, GEN p) { GEN z; struct _ZpXQ_norm D; long d = get_FpX_degree(T); D.T = T; D.p = q; D.n = d+1; if (d==1) return ZX_copy(x); z = mkvec2(x,mkvecsmall(p[2])); z = gen_powu(z,d,(void*)&D,ZpXQ_norm_sqr,ZpXQ_norm_mul); return gmael(z,1,2); } /* Assume T = Phi_(n) and n prime */ static GEN ZpXQ_sqrtnorm_pcyc(GEN x, GEN T, GEN q, GEN p, long e) { GEN z = ZpXQ_norm_pcyc(x, T, q, p); return Zp_sqrtlift(z,Fp_sqrt(z,p),p,e); } /* Assume a = 1 [p], return the square root of the norm */ static GEN ZpXQ_sqrtnorm(GEN a, GEN T, GEN q, GEN p, long e) { GEN s = Fp_div(FpXQ_trace(ZpXQ_log(a, T, p, e), T, q), gen_2, q); return modii(gel(Qp_exp(cvtop(s, p, e-1)),4), q); } struct _teich_lin { ulong p; GEN sqx, Tp; long m; }; static GEN _teich_invl(void *E, GEN x) { struct _teich_lin *d = (struct _teich_lin *) E; ulong p = d->p; GEN T = d->Tp; return Flx_to_ZX(Flxq_lroot_fast(ZX_to_Flx(x, p), d->sqx, T, p)); } static GEN _teich_lin(void *E, GEN F, GEN x2, GEN q) { struct _teich_lin *d = (struct _teich_lin *) E; pari_sp av = avma; GEN T = gel(F,2), Xm = gel(F,3); GEN y2 = ZpXQ_frob(x2, Xm, T, q, d->p); GEN lin = FpX_sub(y2, ZX_mulu(ZX_mul(gel(F,1), x2), d->p), q); return gerepileupto(av, FpX_rem(lin, T, q)); } struct _teich_iso { GEN Xm, T; GEN sqx, Tp; ulong p; }; static GEN _teich_iter(void *E, GEN x2, GEN q) { struct _teich_iso *d = (struct _teich_iso *) E; ulong p = d->p; GEN TN = FpXT_red(d->T, q), XN = FpXV_red(d->Xm, q); GEN y2 = ZpXQ_frob(x2, XN, TN, q, d->p); GEN x1 = FpXQ_powu(x2, p-1, TN, q); GEN xp = FpXQ_mul(x2, x1, TN, q); GEN V = FpX_sub(y2,xp,q); return mkvec2(V,x1); } static GEN _teich_invd(void *E, GEN V, GEN v, GEN qM, long M) { struct _teich_iso *d = (struct _teich_iso *) E; struct _teich_lin e; ulong p = d->p; GEN TM = FpXT_red(d->T, qM), XM = FpXV_red(d->Xm, qM); GEN x1 = FpX_red(gel(v,2), qM); GEN F = mkvec3(x1, TM, XM); e.sqx = d->sqx; e.Tp = d->Tp; e.p=p; return gen_ZpX_Dixon(F,V,qM,utoi(p),M,(void*) &e, _teich_lin, _teich_invl); } static GEN Teichmuller_lift(GEN x, GEN Xm, GEN T, GEN sqx, GEN Tp, ulong p, long N) { struct _teich_iso d; d.Xm = Xm; d.T = T; d.sqx = sqx; d.Tp = Tp; d.p = p; return gen_ZpX_Newton(x,utoi(p), N,(void*)&d, _teich_iter, _teich_invd); } static GEN get_norm(GEN a4, GEN a6, GEN T, ulong p, long N) { long sv=T[1]; GEN a; if (p==3) a = gel(a4,1); else { GEN P = mkpoln(4, pol1_Flx(sv), pol0_Flx(sv), a4, a6); a = gel(FlxqX_powu(P,p>>1,T,p),2+p-1); } return Zp_sqrtnlift(gen_1,subss(p,1),utoi(Flxq_norm(a,T,p)),utoi(p), N); } static GEN fill_pols(long n, const long *v, long m, const long *vn, const long *vd, GEN *act) { long i, j; long d = upowuu(n,12/(n-1)); GEN N, D, M = zeromatcopy(n+1,n+1); gmael(M,1,n+1) = gen_1; for(i=2;i<=n+1;i++) for(j=i-1;j<=n;j++) gmael(M,i,j) = mulis(powuu(d,i-2),v[j-i+1]); N = cgetg(m+1,t_COL); D = cgetg(m+1,t_COL); for(i=1;i<=m;i++) { gel(N,i) = stoi(*vn++); gel(D,i) = stoi(*vd++); } *act = mkmat2(N,D); return M; } /* These polynomials were extracted from the ECHIDNA databases available at and computed by David R. Kohel. Return the matrix of the modular polynomial, set act to the parametrization, and set dj to the opposite of the supersingular j-invariant. */ static GEN get_Kohel_polynomials(ulong p, GEN *act, long *dj) { const long mat3[] = {-1,-36,-270}; const long num3[] = {1,-483,-21141,-59049}; const long den3[] = {1,261, 4347, -6561}; const long mat5[] = {-1,-30,-315,-1300,-1575}; const long num5[] = {-1,490,20620,158750,78125}; const long den5[] = {-1,-254,-4124,-12250,3125}; const long mat7[] = {-1,-28,-322,-1904,-5915,-8624,-4018}; const long num7[] = {1,-485,-24058,-343833,-2021642,-4353013,-823543}; const long den7[] = {1,259,5894,49119,168406,166355,-16807}; const long mat13[]= {-1,-26,-325,-2548,-13832,-54340,-157118,-333580,-509366, -534820,-354536,-124852,-15145}; const long num13[]= {1,-487,-24056,-391463,-3396483,-18047328,-61622301, -133245853,-168395656,-95422301,-4826809}; const long den13[]= {1,257,5896,60649,364629,1388256,3396483,5089019,4065464, 1069939,-28561}; switch(p) { case 3: *dj = 0; return fill_pols(3,mat3,4,num3,den3,act); case 5: *dj = 0; return fill_pols(5,mat5,5,num5,den5,act); case 7: *dj = 1; return fill_pols(7,mat7,7,num7,den7,act); case 13: *dj = 8; return fill_pols(13,mat13,11,num13,den13,act); } *dj=0; *act = NULL; return NULL; /* LCOV_EXCL_LINE */ } long zx_is_pcyc(GEN T) { long i, n = degpol(T); if (!uisprime(n+1)) return 0; for (i=0; i<=n; i++) if (T[i+2]!=1UL) return 0; return 1; } static GEN Flxq_ellcard_Kohel(GEN a4, GEN a6, GEN T, ulong p) { pari_sp av = avma, av2; pari_timer ti; long n = get_Flx_degree(T), N = (n+4)/2, dj; GEN q = powuu(p, N); GEN T2, Xm, s1, c2, t, lr; GEN S1, sqx; GEN Nc2, Np; GEN act, phi = get_Kohel_polynomials(p, &act, &dj); long ispcyc = zx_is_pcyc(get_Flx_mod(T)); timer_start(&ti); if (!ispcyc) { T2 = Flx_canonlift(get_Flx_mod(T),N,p); if (DEBUGLEVEL) timer_printf(&ti,"Teich"); } else T2 = Flx_to_ZX(get_Flx_mod(T)); T2 = FpX_get_red(T2, q); T = ZXT_to_FlxT(T2, p); av2 = avma; if (DEBUGLEVEL) timer_printf(&ti,"Barrett"); if (!ispcyc) { Xm = FpXQ_powers(pol_xn(n,get_FpX_var(T2)),p-1,T2,q); if (DEBUGLEVEL) timer_printf(&ti,"Xm"); } else Xm = cgetg(1,t_VEC); s1 = Flxq_inv(Flx_Fl_add(Flxq_ellj(a4,a6,T,p),dj, p),T,p); lr = Flxq_lroot(polx_Flx(get_Flx_var(T)), T, p); sqx = Flxq_powers(lr, p-1, T, p); S1 = lift_isogeny(phi, Flx_to_ZX(s1), N, Xm, T2, sqx, T ,p); if (DEBUGLEVEL) timer_printf(&ti,"Lift isogeny"); c2 = getc2(act, S1, T2, q, p, N); if (DEBUGLEVEL) timer_printf(&ti,"c^2"); if (p>3 && !ispcyc) { GEN c2p = Flx_to_ZX(Flxq_inv(ZX_to_Flx(c2,p),T,p)); GEN tc2 = Teichmuller_lift(c2p,Xm, T2,sqx,T,p,N); if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fq"); c2 = FpX_rem(FpX_mul(tc2,c2,q),T2,q); } c2 = gerepileupto(av2, c2); if (DEBUGLEVEL) timer_printf(&ti,"tc2"); Nc2 = (ispcyc? ZpXQ_sqrtnorm_pcyc: ZpXQ_sqrtnorm)(c2, T2, q, utoi(p), N); if (DEBUGLEVEL) timer_printf(&ti,"Norm"); Np = get_norm(a4,a6,T,p,N); if (p>3 && ispcyc) { GEN Ncpi = utoi(Fl_inv(umodiu(Nc2,p), p)); GEN tNc2 = Zp_sqrtnlift(gen_1, subss(p,1), Ncpi, utoi(p),N); if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fp"); Nc2 = Fp_mul(Nc2,tNc2,q); } t = Fp_center_i(Fp_mul(Nc2,Np,q),q,shifti(q,-1)); return gerepileupto(av, subii(addiu(powuu(p,n),1),t)); } static void liftcurve(GEN J, GEN T, GEN q, ulong p, long N, GEN *A4, GEN *A6) { pari_sp av = avma; GEN r = ZpXQ_inv(Z_ZX_sub(utoi(1728),J),T,utoi(p),N); GEN g = FpXQ_mul(J,r,T,q); *A4 = FpX_mulu(g,3,q); *A6 = FpX_mulu(g,2,q); gerepileall(av,2,A4,A6); } static GEN getc5(GEN H, GEN A40, GEN A60, GEN A41, GEN A61, GEN T, GEN q, ulong p, long N) { long d = lg(H)-1; GEN s1 = gel(H,d-1), s2 = gel(H,d-2), s3 = d<5 ? pol_0(varn(T)): gel(H,d-3); GEN s12 = FpXQ_sqr(s1,T,q); GEN h2 = ZX_sub(ZX_shifti(s2,1),s12); /*2*s2-s1^2*/ GEN h3 = ZX_sub(FpXQ_mul(ZX_add(h2,s2),s1,T,q),ZX_mulu(s3,3)); /*3*s2*s1-s1^3-3s3*/ GEN alpha= ZX_sub(ZX_mulu(h2,30), ZX_mulu(A40,5*p-6)); /* 30*h2+A40*(6-5*p)*/ GEN beta = ZX_sub(ZX_sub(ZX_mulu(FpXQ_mul(A40,s1,T,q),42),ZX_mulu(A60,14*p-15)), ZX_mulu(h3,70)); /* 42*A40*s1-A60*(14*p-15)-70*h3 */ GEN u2 = FpXQ_mul(FpXQ_mul(A41,beta,T,q), ZpXQ_inv(FpXQ_mul(A61,alpha,T,q),T,utoi(p),N),T,q); return u2; } static GEN ZpXQX_liftrootmod_vald(GEN f, GEN H, long v, GEN T, GEN p, long e) { pari_sp av = avma, av2; GEN pv = p, q, qv, W, df, Tq, fr, dfr; ulong mask; pari_timer ti; if (e <= v+1) return H; df = RgX_deriv(f); if (v) { pv = powiu(p,v); qv = mulii(pv,p); df = ZXX_Z_divexact(df, pv); } else qv = p; mask = quadratic_prec_mask(e-v); Tq = FpXT_red(T, qv); dfr = FpXQX_red(df, Tq, p); if (DEBUGLEVEL) timer_start(&ti); W = FpXQXQ_inv(FpXQX_rem(dfr, H, Tq, p), H, Tq, p); /* 1/f'(a) mod (T,p) */ if (DEBUGLEVEL) timer_printf(&ti,"FpXQXQ_inv"); q = p; av2 = avma; for (;;) { GEN u, fa, qv, q2v, Tq2, fadH; GEN H2 = H, q2 = q; q = sqri(q); if (mask & 1) q = diviiexact(q,p); mask >>= 1; if (v) { qv = mulii(q, pv); q2v = mulii(q2, pv); } else { qv = q; q2v = q2; } Tq2 = FpXT_red(T, q2v); Tq = FpXT_red(T, qv); fr = FpXQX_red(f, Tq, qv); fa = FpXQX_rem(fr, H, Tq, qv); fa = ZXX_Z_divexact(fa, q2v); fadH = FpXQXQ_mul(RgX_deriv(H),fa,H,Tq2,q2); H = FpXX_add(H, gmul(FpXQXQ_mul(W, fadH, H, Tq2, q2v), q2), qv); if (mask == 1) return gerepileupto(av, H); dfr = FpXQX_rem(FpXQX_red(df, Tq, q),H,Tq,q); u = ZXX_Z_divexact(ZXX_Z_add_shallow(FpXQXQ_mul(W,dfr,H,Tq,q),gen_m1),q2); W = gsub(W,gmul(FpXQXQ_mul(u,W,H2,Tq2,q2),q2)); if (gc_needed(av2,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQX_liftroot, e = %ld", e); gerepileall(av2, 3, &H, &W, &q); } } } static GEN get_H1(GEN A41, GEN A61, GEN T2, ulong p) { GEN q = utoi(p), T = FpXT_red(T2,q); GEN pol = FpXQ_elldivpol(FpX_red(A41,q),FpX_red(A61,q),p,T,q); return FpXQX_normalize(RgX_deflate(pol,p),T,q); } static GEN Flxq_ellcard_Harley(GEN a4, GEN a6, GEN T, ulong p) { pari_sp av = avma, av2; pari_timer ti; long n = get_Flx_degree(T), N = (n+5)/2; GEN q = powuu(p, N); GEN T2, j, t; GEN J1,A40,A41,A60,A61, sqx,Xm; GEN pol, h1, H; GEN c2, tc2, c2p, Nc2, Np; long ispcyc = zx_is_pcyc(get_Flx_mod(T)); timer_start(&ti); if (!ispcyc) { T2 = Flx_canonlift(get_Flx_mod(T),N,p); if (DEBUGLEVEL) timer_printf(&ti,"Teich"); } else T2 = Flx_to_ZX(get_Flx_mod(T)); T2 = FpX_get_red(T2, q); T = ZXT_to_FlxT(T2, p); av2 = avma; if (DEBUGLEVEL) timer_printf(&ti,"Barrett"); if (!ispcyc) { Xm = FpXQ_powers(pol_xn(n,get_FpX_var(T2)),p-1,T2,q); if (DEBUGLEVEL) timer_printf(&ti,"Xm"); } else Xm = cgetg(1,t_VEC); if (DEBUGLEVEL) timer_printf(&ti,"Xm"); j = Flxq_ellj(a4,a6,T,p); sqx = Flxq_powers(Flxq_lroot(polx_Flx(T[1]), T, p), p-1, T, p); J1 = lift_isogeny(polmodular_ZM(p, 0), Flx_to_ZX(j), N, Xm, T2,sqx,T,p); if (DEBUGLEVEL) timer_printf(&ti,"Lift isogeny"); liftcurve(J1,T2,q,p,N,&A41,&A61); A40 = ZpXQ_frob(A41, Xm, T2, q, p); A60 = ZpXQ_frob(A61, Xm, T2, q, p); if (DEBUGLEVEL) timer_printf(&ti,"liftcurve"); pol = FpXQ_elldivpol(A40,A60,p,T2,q); if (DEBUGLEVEL) timer_printf(&ti,"p-division"); h1 = get_H1(A41,A61,T2,p); H = ZpXQX_liftrootmod_vald(pol,h1,1,T2,utoi(p),N); q = diviuexact(q,p); N--; if (DEBUGLEVEL) timer_printf(&ti,"kernel"); c2 = getc5(H,A40,A60,A41,A61,T2,q,p,N); if (DEBUGLEVEL) timer_printf(&ti,"c^2"); if (!ispcyc) { c2p = Flx_to_ZX(Flxq_inv(ZX_to_Flx(c2,p),T,p)); tc2 = Teichmuller_lift(c2p,Xm, T2,sqx,T,p,N); if (DEBUGLEVEL) timer_printf(&ti,"teichmuller"); c2 = FpX_rem(FpX_mul(tc2,c2,q),T2,q); } c2 = gerepileupto(av2, c2); q = powuu(p, N); Nc2 = (ispcyc? ZpXQ_sqrtnorm_pcyc: ZpXQ_sqrtnorm)(c2, T2, q, utoi(p), N); if (DEBUGLEVEL) timer_printf(&ti,"Norm"); Np = get_norm(a4,a6,T,p,N); if (ispcyc) { GEN Ncpi = utoi(Fl_inv(umodiu(Nc2,p), p)); GEN tNc2 = Zp_sqrtnlift(gen_1, subss(p,1), Ncpi, utoi(p), N); if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fp"); Nc2 = Fp_mul(Nc2,tNc2,q); } t = Fp_center_i(Fp_mul(Nc2,Np,q),q,shifti(q,-1)); return gerepileupto(av, subii(addiu(powuu(p,n),1),t)); } /***************************************************************************/ /* */ /* Shanks Mestre */ /* */ /***************************************************************************/ /* Return the lift of a (mod b), which is closest to h */ static GEN closest_lift(GEN a, GEN b, GEN h) { return addii(a, mulii(b, diviiround(subii(h,a), b))); } static GEN FlxqE_find_order(GEN f, GEN h, GEN bound, GEN B, GEN a4, GEN T, ulong p) { pari_sp av = avma, av1; pari_timer Ti; long s = itos( gceil(gsqrt(gdiv(bound,B),DEFAULTPREC)) ) >> 1; GEN tx, ti; GEN fh = FlxqE_mul(f, h, a4, T, p); GEN F, P = fh, fg; long i; if (DEBUGLEVEL >= 6) timer_start(&Ti); if (ell_is_inf(fh)) return h; F = FlxqE_mul(f, B, a4, T, p); if (s < 3) { /* we're nearly done: naive search */ GEN Q = P; for (i=1;; i++) { P = FlxqE_add(P, F, a4, T, p); /* h.f + i.F */ if (ell_is_inf(P)) return gerepileupto(av, addii(h, mului(i,B))); Q = FlxqE_sub(Q, F, a4, T, p); /* h.f - i.F */ if (ell_is_inf(Q)) return gerepileupto(av, subii(h, mului(i,B))); } } tx = cgetg(s+1,t_VECSMALL); /* Baby Step/Giant Step */ av1 = avma; for (i=1; i<=s; i++) { /* baby steps */ tx[i] = hash_GEN(gel(P, 1)); P = FlxqE_add(P, F, a4, T, p); /* h.f + i.F */ if (ell_is_inf(P)) return gerepileupto(av, addii(h, mului(i,B))); if (gc_needed(av1,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"[Flxq_ellcard] baby steps, i=%ld",i); P = gerepileupto(av1,P); } } if (DEBUGLEVEL >= 6) timer_printf(&Ti, "[Flxq_ellcard] baby steps, s = %ld",s); /* giant steps: fg = s.F */ fg = gerepileupto(av1, FlxqE_sub(P, fh, a4, T, p)); if (ell_is_inf(fg)) return gerepileupto(av,mului(s,B)); ti = vecsmall_indexsort(tx); /* = permutation sorting tx */ tx = perm_mul(tx,ti); if (DEBUGLEVEL >= 6) timer_printf(&Ti, "[Flxq_ellcard] sorting"); av1 = avma; for (P=fg, i=1; ; i++) { long k = hash_GEN(gel(P,1)); long r = zv_search(tx, k); if (r) { while (r && tx[r] == k) r--; for (r++; r <= s && tx[r] == k; r++) { long j = ti[r]-1; GEN Q = FlxqE_add(FlxqE_mul(F, stoi(j), a4, T, p), fh, a4, T, p); if (DEBUGLEVEL >= 6) timer_printf(&Ti, "[Flxq_ellcard] giant steps, i = %ld",i); if (Flx_equal(gel(P,1), gel(Q,1))) { if (Flx_equal(gel(P,2), gel(Q,2))) i = -i; return gerepileupto(av,addii(h, mulii(addis(mulss(s,i), j), B))); } } } P = FlxqE_add(P,fg,a4,T,p); if (gc_needed(av1,3)) { if(DEBUGMEM>1) pari_warn(warnmem,"[Flxq_ellcard] giants steps, i=%ld",i); P = gerepileupto(av1,P); } } } static void Flx_next(GEN t, ulong p) { long i; for(i=2;;i++) if (uel(t,i)==p-1) t[i]=0; else { t[i]++; break; } } static void Flx_renormalize_ip(GEN x, long lx) { long i; for (i = lx-1; i>=2; i--) if (x[i]) break; setlg(x, i+1); } static ulong F3xq_ellcard_naive(GEN a2, GEN a6, GEN T) { pari_sp av = avma; long i, d = get_Flx_degree(T), lx = d+2; long q = upowuu(3, d), a; GEN x = zero_zv(lx); x[1] = get_Flx_var(T); for(a=1, i=0; i= bound, it is completely determined */ /* how many 2-torsion points ? */ switch(FlxqX_nbroots(mkpoln(4, pol1_Flx(vn), pol0_Flx(vn), a4, a6), T, p)) { case 3: A = gen_0; B = utoipos(4); break; case 1: A = gen_0; B = gen_2; break; default: A = gen_1; B = gen_2; break; /* 0 */ } m = diviuexact(subiu(powuu(p,n), 1), p-1); for(;;) { h = closest_lift(A, B, q1p); /* [ux, u^2] is on E_u: y^2 = x^3 + c4 u^2 x + c6 u^3 * E_u isomorphic to E (resp. E') iff KRO = 1 (resp. -1) * #E(F_p) = p+1 - a_p, #E'(F_p) = p+1 + a_p * * #E_u(Flxq) = A (mod B), h is close to #E_u(Flxq) */ KRO = -KRO; f = Flxq_ellpoint(KRO, a4,a6, m,n,vn, T,p); ta4 = Flxq_mul(a4, gel(f,2), T, p); /* a4 for E_u */ h = FlxqE_find_order(f, h, bound, B, ta4,T,p); h = FlxqE_order(f, h, ta4, T, p); /* h | #E_u(Flxq) = A (mod B) */ A = Z_chinese_all(A, gen_0, B, h, &B); if (cmpii(B, bound) >= 0) break; /* not done, update A mod B for the _next_ curve, isomorphic to * the quadratic twist of this one */ A = remii(subii(q2p,A), B); /* #E(Fq)+#E'(Fq) = 2q+2 */ } h = closest_lift(A, B, q1p); return gerepileuptoint(av, KRO == 1? h: subii(q2p,h)); } static GEN F3xq_ellcard(GEN a2, GEN a6, GEN T) { long n = get_Flx_degree(T); if (n <= 2) return utoi(F3xq_ellcard_naive(a2, a6, T)); else { GEN q1 = addiu(powuu(3, get_Flx_degree(T)), 1), t; GEN a = Flxq_div(a6,Flxq_powu(a2,3,T,3),T,3); if (Flx_equal1(Flxq_powu(a, 8, T, 3))) { GEN P = Flxq_minpoly(a,T,3); long dP = degpol(P); /* dP <= 2 */ ulong q = upowuu(3,dP); GEN A2 = pol1_Flx(P[1]), A6 = Flx_rem(polx_Flx(P[1]), P, 3); long tP = q + 1 - F3xq_ellcard_naive(A2, A6, P); t = elltrace_extension(stoi(tP), n/dP, utoi(q)); if (umodiu(t, 3)!=1) t = negi(t); return Flx_equal1(a2) || Flxq_issquare(a2,T,3) ? subii(q1,t): addii(q1,t); } else return Flxq_ellcard_Kohel(mkvec(a2), a6, T, 3); } } static GEN Flxq_ellcard_Satoh(GEN a4, GEN a6, GEN j, GEN T, ulong p) { long n = get_Flx_degree(T); if (n <= 2) return utoi(Flxq_ellcard_naive(a4, a6, T, p)); else { GEN jp = Flxq_powu(j, p, T, p); GEN s = Flx_add(j, jp, p); if (degpol(s) <= 0) { /* it is assumed j not in F_p */ GEN m = Flxq_mul(j, jp, T, p); if (degpol(m) <= 0) { GEN q = sqru(p); GEN q1 = addiu(powuu(p, get_Flx_degree(T)), 1); GEN sk = Flx_Fl_add(Flx_neg(j, p), 1728%p, p); GEN sA4 = Flx_triple(Flxq_mul(sk, j, T, p), p); GEN u = Flxq_div(a4, sA4, T, p); ulong ns = lgpol(s) ? Fl_neg(s[2], p): 0UL; GEN P = mkvecsmall4(T[1], m[2], ns, 1L); GEN A4, A6, t, tP; Flxq_ellj_to_a4a6(polx_Flx(T[1]), P, p, &A4, &A6); tP = addis(q, 1 - Flxq_ellcard_naive(A4, A6, P, p)); t = elltrace_extension(tP, n>>1, q); return Flxq_is2npower(u, 2, T, p) ? subii(q1,t): addii(q1,t); } } if (p<=7 || p==13 ) return Flxq_ellcard_Kohel(a4, a6, T, p); else return Flxq_ellcard_Harley(a4, a6, T, p); } } static GEN Flxq_ellcard_Kedlaya(GEN a4, GEN a6, GEN T, ulong p) { pari_sp av = avma; GEN H = mkpoln(4, gen_1, gen_0, Flx_to_ZX(a4), Flx_to_ZX(a6)); GEN Tp = Flx_to_ZX(get_Flx_mod(T)); long n = degpol(Tp), e = ((p < 16 ? n+1: n)>>1)+1; GEN M = ZlXQX_hyperellpadicfrobenius(H, Tp, p, e); GEN N = ZpXQM_prodFrobenius(M, Tp, utoi(p), e); GEN q = powuu(p, e); GEN tp = Fq_add(gcoeff(N,1,1), gcoeff(N,2,2), Tp, q); GEN t = Fp_center_i(typ(tp)==t_INT ? tp: leading_coeff(tp), q, shifti(q,-1)); return gerepileupto(av, subii(addiu(powuu(p, n), 1), t)); } GEN Flxq_ellj(GEN a4, GEN a6, GEN T, ulong p) { pari_sp av=avma; if (p==3) { GEN J; if (typ(a4)!=t_VEC) return pol0_Flx(get_Flx_var(T)); J = Flxq_div(Flxq_powu(gel(a4,1),3, T, p),Flx_neg(a6,p), T, p); return gerepileuptoleaf(av, J); } else { pari_sp av=avma; GEN a43 = Flxq_mul(a4,Flxq_sqr(a4,T,p),T,p); GEN a62 = Flxq_sqr(a6,T,p); GEN num = Flx_mulu(a43,6912,p); GEN den = Flx_add(Flx_mulu(a43,4,p),Flx_mulu(a62,27,p),p); return gerepileuptoleaf(av, Flxq_div(num, den, T, p)); } } void Flxq_ellj_to_a4a6(GEN j, GEN T, ulong p, GEN *pt_a4, GEN *pt_a6) { ulong zagier = 1728 % p; if (lgpol(j)==0) { *pt_a4 = pol0_Flx(T[1]); *pt_a6 =pol1_Flx(T[1]); } else if (lgpol(j)==1 && uel(j,2) == zagier) { *pt_a4 = pol1_Flx(T[1]); *pt_a6 =pol0_Flx(T[1]); } else { GEN k = Flx_Fl_add(Flx_neg(j, p), zagier, p); GEN kj = Flxq_mul(k, j, T, p); GEN k2j = Flxq_mul(kj, k, T, p); *pt_a4 = Flx_triple(kj, p); *pt_a6 = Flx_double(k2j, p); } } static GEN F3xq_ellcardj(GEN a4, GEN a6, GEN T, GEN q, long n) { const ulong p = 3; ulong t; GEN q1 = addiu(q,1); GEN na4 = Flx_neg(a4,p), ra4; if (!Flxq_issquare(na4,T,p)) return q1; ra4 = Flxq_sqrt(na4,T,p); t = Flxq_trace(Flxq_div(a6,Flxq_mul(na4,ra4,T,p),T,p),T,p); if (n%2==1) { GEN q3; if (t==0) return q1; q3 = powuu(p,(n+1)>>1); return (t==1)^(n%4==1) ? subii(q1,q3): addii(q1,q3); } else { GEN q22, q2 = powuu(p,n>>1); GEN W = Flxq_pow(a4,shifti(q,-2),T,p); long s = (W[2]==1)^(n%4==2); if (t!=0) return s ? addii(q1,q2): subii(q1, q2); q22 = shifti(q2,1); return s ? subii(q1,q22): addii(q1, q22); } } static GEN Flxq_ellcardj(GEN a4, GEN a6, ulong j, GEN T, GEN q, ulong p, long n) { GEN q1 = addiu(q,1); if (j==0) { ulong w; GEN W, t, N; if (umodiu(q,6)!=1) return q1; N = Fp_ffellcard(gen_0,gen_1,q,n,utoi(p)); t = subii(q1, N); W = Flxq_pow(a6,diviuexact(shifti(q,-1), 3),T,p); if (degpol(W)>0) /*p=5 mod 6*/ return Flx_equal1(Flxq_powu(W,3,T,p)) ? addii(q1,shifti(t,-1)): subii(q1,shifti(t,-1)); w = W[2]; if (w==1) return N; if (w==p-1) return addii(q1,t); else /*p=1 mod 6*/ { GEN u = shifti(t,-1), v = sqrtint(diviuexact(subii(q,sqri(u)),3)); GEN a = addii(u,v), b = shifti(v,1); if (Fl_powu(w,3,p)==1) { if (Fl_add(umodiu(a,p),Fl_mul(w,umodiu(b,p),p),p)==0) return subii(q1,subii(shifti(b,1),a)); else return addii(q1,addii(a,b)); } else { if (Fl_sub(umodiu(a,p),Fl_mul(w,umodiu(b,p),p),p)==0) return subii(q1,subii(a,shifti(b,1))); else return subii(q1,addii(a,b)); } } } else if (j==1728%p) { ulong w; GEN W, N, t; if (mod4(q)==3) return q1; W = Flxq_pow(a4,shifti(q,-2),T,p); if (degpol(W)>0) return q1; /*p=3 mod 4*/ w = W[2]; N = Fp_ffellcard(gen_1,gen_0,q,n,utoi(p)); if(w==1) return N; t = subii(q1, N); if(w==p-1) return addii(q1, t); else /*p=1 mod 4*/ { GEN u = shifti(t,-1), v = sqrtint(subii(q,sqri(u))); if (Fl_add(umodiu(u,p),Fl_mul(w,umodiu(v,p),p),p)==0) return subii(q1,shifti(v,1)); else return addii(q1,shifti(v,1)); } } else { ulong g = Fl_div(j, Fl_sub(1728%p, j, p), p); GEN l = Flxq_div(Flx_triple(a6,p),Flx_double(a4,p),T,p); GEN N = Fp_ffellcard(utoi(Fl_triple(g,p)),utoi(Fl_double(g,p)),q,n,utoi(p)); if (Flxq_issquare(l,T,p)) return N; return subii(shifti(q1,1),N); } } GEN Flxq_ellcard(GEN a4, GEN a6, GEN T, ulong p) { pari_sp av = avma; long n = get_Flx_degree(T); GEN J, r, q = powuu(p, n); if (typ(a4)==t_VEC) r = F3xq_ellcard(gel(a4,1), a6, T); else if (p==3) r = F3xq_ellcardj(a4, a6, T, q, n); else if (degpol(a4)<=0 && degpol(a6)<=0) r = Fp_ffellcard(utoi(Flx_eval(a4,0,p)),utoi(Flx_eval(a6,0,p)),q,n,utoi(p)); else if (degpol(J=Flxq_ellj(a4,a6,T,p))<=0) r = Flxq_ellcardj(a4,a6,lgpol(J)?J[2]:0,T,q,p,n); else if (p <= 7) r = Flxq_ellcard_Satoh(a4, a6, J, T, p); else if (cmpis(q,100)<0) r = utoi(Flxq_ellcard_naive(a4, a6, T, p)); else if (p == 13 || (7*p <= (ulong)10*n && (BITS_IN_LONG==64 || p <= 103))) r = Flxq_ellcard_Satoh(a4, a6, J, T, p); else if (p <= (ulong)2*n) r = Flxq_ellcard_Kedlaya(a4, a6, T, p); else if (expi(q)<=62) r = Flxq_ellcard_Shanks(a4, a6, q, T, p); else r = Fq_ellcard_SEA(Flx_to_ZX(a4),Flx_to_ZX(a6),q,Flx_to_ZX(T),utoi(p),0); return gerepileuptoint(av, r); } pari-2.11.2/src/basemath/base5.c0000644000175000017500000014016213457566441014717 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* */ /* RNF STRUCTURE AND OPERATIONS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" /* must return a t_POL */ GEN eltreltoabs(GEN rnfeq, GEN x) { long i, k, v; pari_sp av = avma; GEN T, pol, teta, a, s; pol = gel(rnfeq,1); a = gel(rnfeq,2); k = itos(gel(rnfeq,3)); T = gel(rnfeq,4); v = varn(pol); if (varncmp(gvar(x), v) > 0) x = scalarpol(x,v); x = RgX_nffix("eltreltoabs", T, x, 1); /* Mod(X - k a, pol(X)), a root of the polynomial defining base */ teta = gadd(pol_x(v), gmulsg(-k,a)); s = gen_0; for (i=lg(x)-1; i>1; i--) { GEN c = gel(x,i); if (typ(c) == t_POL) c = RgX_RgXQ_eval(c, a, pol); s = RgX_rem(gadd(c, gmul(teta,s)), pol); } return gerepileupto(av, s); } GEN rnfeltreltoabs(GEN rnf,GEN x) { const char *f = "rnfeltreltoabs"; GEN pol; checkrnf(rnf); pol = rnf_get_polabs(rnf); switch(typ(x)) { case t_INT: return icopy(x); case t_FRAC: return gcopy(x); case t_POLMOD: if (RgX_equal_var(gel(x,1), pol)) { /* already in 'abs' form, unless possibly if nf = Q */ if (rnf_get_nfdegree(rnf) == 1) { GEN y = gel(x,2); pari_sp av = avma; y = simplify_shallow(liftpol_shallow(y)); return gerepilecopy(av, mkpolmod(y, pol)); } return gcopy(x); } x = polmod_nffix(f,rnf,x,0); if (typ(x) == t_POLMOD) return rnfeltup(rnf,x); retmkpolmod(eltreltoabs(rnf_get_map(rnf), x), ZX_copy(pol)); case t_POL: if (varn(x) == rnf_get_nfvarn(rnf)) return rnfeltup(rnf,x); retmkpolmod(eltreltoabs(rnf_get_map(rnf), x), ZX_copy(pol)); } pari_err_TYPE(f,x); return NULL; } GEN eltabstorel_lift(GEN rnfeq, GEN P) { GEN k, T = gel(rnfeq,4), relpol = gel(rnfeq,5); if (is_scalar_t(typ(P))) return P; k = gel(rnfeq,3); P = lift_shallow(P); if (signe(k)) P = RgXQX_translate(P, deg1pol_shallow(k, gen_0, varn(T)), T); P = RgXQX_rem(P, relpol, T); return QXQX_to_mod_shallow(P, T); } /* rnfeq = [pol,a,k,T,relpol], P a t_POL or scalar * Return Mod(P(x + k Mod(y, T(y))), pol(x)) */ GEN eltabstorel(GEN rnfeq, GEN P) { GEN T = gel(rnfeq,4), relpol = gel(rnfeq,5); return mkpolmod(eltabstorel_lift(rnfeq,P), QXQX_to_mod_shallow(relpol,T)); } GEN rnfeltabstorel(GEN rnf,GEN x) { const char *f = "rnfeltabstorel"; pari_sp av = avma; GEN pol, T, P, NF; checkrnf(rnf); T = rnf_get_nfpol(rnf); P = rnf_get_pol(rnf); pol = rnf_get_polabs(rnf); switch(typ(x)) { case t_INT: return icopy(x); case t_FRAC: return gcopy(x); case t_POLMOD: if (RgX_equal_var(P, gel(x,1))) { x = polmod_nffix(f, rnf, x, 0); P = QXQX_to_mod_shallow(P,T); return gerepilecopy(av, mkpolmod(x,P)); } if (RgX_equal_var(T, gel(x,1))) { x = Rg_nffix(f, T, x, 0); goto END; } if (!RgX_equal_var(pol, gel(x,1))) pari_err_MODULUS(f, gel(x,1),pol); x = gel(x,2); break; case t_POL: break; case t_COL: NF = obj_check(rnf, rnf_NFABS); if (!NF) pari_err_TYPE("rnfeltabstorel, apply nfinit(rnf)",x); x = nf_to_scalar_or_alg(NF,x); break; default: pari_err_TYPE(f,x); return NULL; } switch(typ(x)) { case t_INT: return icopy(x); case t_FRAC: return gcopy(x); case t_POL: break; default: pari_err_TYPE(f, x); } RgX_check_QX(x,f); if (varn(x) != varn(pol)) { if (varn(x) == varn(T)) { x = Rg_nffix(f,T,x,0); goto END; } pari_err_VAR(f, x,pol); } switch(lg(x)) { case 2: avma = av; return gen_0; case 3: return gerepilecopy(av, gel(x,2)); } END: return gerepilecopy(av, eltabstorel(rnf_get_map(rnf), x)); } /* x a t_VEC of rnf elements in 'alg' form (t_POL). Assume maximal rank or 0 */ static GEN modulereltoabs(GEN rnf, GEN x) { GEN W=gel(x,1), I=gel(x,2), rnfeq = rnf_get_map(rnf), polabs = gel(rnfeq,1); long i, j, k, m, N = lg(W)-1; GEN zknf, dzknf, M; if (!N) return cgetg(1, t_VEC); zknf = rnf_get_nfzk(rnf); dzknf = gel(zknf,1); m = rnf_get_nfdegree(rnf); M = cgetg(N*m+1, t_VEC); for (k=i=1; i<=N; i++) { GEN c0, cid, w = gel(W,i), id = gel(I,i); if (lg(id) == 1) continue; /* must be a t_MAT */ id = Q_primitive_part(id, &cid); w = Q_primitive_part(eltreltoabs(rnfeq,w), &c0); c0 = mul_content(c0, mul_content(cid,inv_content(dzknf))); if (typ(id) == t_INT) for (j=1; j<=m; j++) { GEN z = RgX_rem(gmul(w, gel(zknf,j)), polabs); if (c0) z = RgX_Rg_mul(z, c0); gel(M,k++) = z; } else for (j=1; j<=m; j++) { GEN c, z = Q_primitive_part(RgV_RgC_mul(zknf,gel(id,j)), &c); z = RgX_rem(gmul(w, z), polabs); c = mul_content(c, c0); if (c) z = RgX_Rg_mul(z, c); gel(M,k++) = z; } } setlg(M, k); return M; } /* Z-basis for absolute maximal order: [NF.pol, NF.zk] */ GEN rnf_zkabs(GEN rnf) { GEN d, M = modulereltoabs(rnf, rnf_get_zk(rnf)); GEN T = rnf_get_polabs(rnf); long n = degpol(T); M = Q_remove_denom(M, &d); /* t_VEC of t_POL */ if (d) { M = RgXV_to_RgM(M,n); M = ZM_hnfmodall(M, d, hnf_MODID|hnf_CENTER); M = RgM_Rg_div(M, d); } else M = matid(n); return mkvec2(T, RgM_to_RgXV(M, varn(T))); } static GEN mknfabs(GEN rnf, long prec) { GEN NF; if ((NF = obj_check(rnf,rnf_NFABS))) { if (nf_get_prec(NF) < prec) NF = nfnewprec_shallow(NF,prec); } else NF = nfinit(rnf_zkabs(rnf), prec); return NF; } static GEN mkupdown(GEN rnf) { GEN NF = obj_check(rnf, rnf_NFABS), M, zknf, dzknf; long i, l; zknf = rnf_get_nfzk(rnf); dzknf = gel(zknf,1); if (gequal1(dzknf)) dzknf = NULL; l = lg(zknf); M = cgetg(l, t_MAT); gel(M,1) = vec_ei(nf_get_degree(NF), 1); for (i = 2; i < l; i++) { GEN c = poltobasis(NF, gel(zknf,i)); if (dzknf) c = gdiv(c, dzknf); gel(M,i) = c; } return Qevproj_init(M); } GEN rnf_build_nfabs(GEN rnf, long prec) { GEN NF = obj_checkbuild_prec(rnf, rnf_NFABS, &mknfabs, &nf_get_prec, prec); (void)obj_checkbuild(rnf, rnf_MAPS, &mkupdown); return NF; } void rnfcomplete(GEN rnf) { (void)rnf_build_nfabs(rnf, nf_get_prec(rnf_get_nf(rnf))); } GEN nf_nfzk(GEN nf, GEN rnfeq) { GEN pol = gel(rnfeq,1), a = gel(rnfeq,2); return Q_primpart(QXV_QXQ_eval(nf_get_zkprimpart(nf), a, pol)); } /* true nf */ GEN check_polrel(GEN nf, GEN P, ulong *lim) { if (typ(P) != t_VEC || lg(P) != 3) *lim = 0; else { *lim = gtou(gel(P,2)); P = gel(P,1); } if (typ(P) != t_POL) pari_err_TYPE("rnfinit",P); P = RgX_nffix("rnfinit", nf_get_pol(nf), P, 0); if (!gequal1(leading_coeff(P))) pari_err_IMPL("non-monic relative polynomials"); return P; } GEN rnfinit0(GEN nf, GEN T, long flag) { pari_sp av = avma; GEN bas, D, f, B, T0, rnfeq, rnf = obj_init(11, 2); ulong lim; nf = checknf(nf); T0 = check_polrel(nf, T, &lim); T = lift_shallow(T0); gel(rnf,11) = rnfeq = nf_rnfeq(nf,T); gel(rnf,2) = nf_nfzk(nf, rnfeq); bas = rnfallbase(nf, T0, lim, rnf, &D, &f); B = matbasistoalg(nf,gel(bas,1)); gel(bas,1) = lift_if_rational( RgM_to_RgXV(B,varn(T)) ); gel(rnf,1) = T; gel(rnf,3) = D; gel(rnf,4) = f; gel(rnf,5) = cgetg(1, t_VEC); /* dummy */ gel(rnf,6) = cgetg(1, t_VEC); /* dummy */ gel(rnf,7) = bas; gel(rnf,8) = lift_if_rational( RgM_inv_upper(B) ); gel(rnf,9) = typ(f) == t_INT? powiu(f, nf_get_degree(nf)) : RgM_det_triangular(f); gel(rnf,10)= nf; rnf = gerepilecopy(av, rnf); if (flag) rnfcomplete(rnf); return rnf; } GEN rnfinit(GEN nf, GEN T) { return rnfinit0(nf,T,0); } GEN rnfeltup0(GEN rnf, GEN x, long flag) { pari_sp av = avma; GEN zknf, nf, NF, POL; long tx = typ(x); checkrnf(rnf); if (flag) rnfcomplete(rnf); NF = obj_check(rnf,rnf_NFABS); POL = rnf_get_polabs(rnf); if (tx == t_POLMOD && RgX_equal_var(gel(x,1), POL)) { if (flag) x = nf_to_scalar_or_basis(NF,x); return gerepilecopy(av, x); } if (NF && tx == t_COL && lg(x)-1 == nf_get_degree(NF)) { x = flag? nf_to_scalar_or_basis(NF,x) : mkpolmod(nf_to_scalar_or_alg(NF,x), POL); return gerepilecopy(av, x); } nf = rnf_get_nf(rnf); if (NF) { GEN d, proj; x = nf_to_scalar_or_basis(nf, x); if (typ(x) != t_COL) return gerepilecopy(av, x); proj = obj_check(rnf,rnf_MAPS); x = Q_remove_denom(x,&d); x = ZM_ZC_mul(gel(proj,1), x); if (d) x = gdiv(x,d); if (!flag) x = basistoalg(NF,x); } else { zknf = rnf_get_nfzk(rnf); x = nfeltup(nf, x, zknf); if (typ(x) == t_POL) x = mkpolmod(x, POL); } return gerepilecopy(av, x); } GEN rnfeltup(GEN rnf, GEN x) { return rnfeltup0(rnf,x,0); } GEN nfeltup(GEN nf, GEN x, GEN zknf) { GEN c, dzknf = gel(zknf,1); x = nf_to_scalar_or_basis(nf, x); if (typ(x) != t_COL) return x; x = Q_primitive_part(x, &c); if (!RgV_is_ZV(x)) pari_err_TYPE("rnfeltup", x); if (gequal1(dzknf)) dzknf = NULL; c = mul_content(c, inv_content(dzknf)); x = RgV_RgC_mul(zknf, x); if (c) x = RgX_Rg_mul(x, c); return x; } static void fail(const char *f, GEN x) { pari_err_DOMAIN(f,"element","not in", strtoGENstr("the base field"),x); } /* x t_COL of length degabs */ static GEN eltdown(GEN rnf, GEN x, long flag) { GEN z,y, d, proj = obj_check(rnf,rnf_MAPS); GEN M= gel(proj,1), iM=gel(proj,2), diM=gel(proj,3), perm=gel(proj,4); x = Q_remove_denom(x,&d); if (!RgV_is_ZV(x)) pari_err_TYPE("rnfeltdown", x); y = ZM_ZC_mul(iM, vecpermute(x, perm)); z = ZM_ZC_mul(M,y); if (!isint1(diM)) z = ZC_Z_mul(z,diM); if (!ZV_equal(z,x)) fail("rnfeltdown",x); d = mul_denom(d, diM); if (d) y = gdiv(y,d); if (!flag) y = basistoalg(rnf_get_nf(rnf), y); return y; } GEN rnfeltdown0(GEN rnf, GEN x, long flag) { const char *f = "rnfeltdown"; pari_sp av = avma; GEN z, T, NF, nf; long v; checkrnf(rnf); NF = obj_check(rnf,rnf_NFABS); nf = rnf_get_nf(rnf); T = nf_get_pol(nf); v = varn(T); switch(typ(x)) { /* directly belonging to base field ? */ case t_INT: return icopy(x); case t_FRAC:return gcopy(x); case t_POLMOD: if (RgX_equal_var(gel(x,1), rnf_get_polabs(rnf))) { if (degpol(T) == 1) { x = simplify_shallow(liftpol_shallow(gel(x,2))); if (typ(x) != t_POL) return gerepilecopy(av,x); } break; } x = polmod_nffix(f,rnf,x,0); /* x was defined mod the relative polynomial & non constant => fail */ if (typ(x) == t_POL) fail(f,x); if (flag) x = nf_to_scalar_or_basis(nf,x); return gerepilecopy(av, x); case t_POL: if (varn(x) != v) break; x = Rg_nffix(f,T,x,0); if (flag) x = nf_to_scalar_or_basis(nf,x); return gerepilecopy(av, x); case t_COL: { long n = lg(x)-1; if (n == degpol(T) && RgV_is_QV(x)) { if (RgV_isscalar(x)) return gcopy(gel(x,1)); if (!flag) return gcopy(x); return basistoalg(nf,x); } if (NF) break; } default: pari_err_TYPE(f, x); } /* x defined mod the absolute equation */ if (NF) { x = nf_to_scalar_or_basis(NF, x); if (typ(x) == t_COL) x = eltdown(rnf,x,flag); return gerepilecopy(av, x); } z = rnfeltabstorel(rnf,x); switch(typ(z)) { case t_INT: case t_FRAC: return z; } /* typ(z) = t_POLMOD, varn of both components is rnf_get_varn(rnf) */ z = gel(z,2); if (typ(z) == t_POL) { if (lg(z) != 3) fail(f,x); z = gel(z,2); } return gerepilecopy(av, z); } GEN rnfeltdown(GEN rnf, GEN x) { return rnfeltdown0(rnf,x,0); } /* vector of rnf elt -> matrix of nf elts */ static GEN rnfV_to_nfM(GEN rnf, GEN x) { long i, l = lg(x); GEN y = cgetg(l, t_MAT); for (i = 1; i < l; i++) gel(y,i) = rnfalgtobasis(rnf,gel(x,i)); return y; } static GEN rnfprincipaltohnf(GEN rnf,GEN x) { pari_sp av = avma; GEN bas = rnf_get_zk(rnf), nf = rnf_get_nf(rnf); x = rnfbasistoalg(rnf,x); x = gmul(x, gmodulo(gel(bas,1), rnf_get_pol(rnf))); return gerepileupto(av, nfhnf(nf, mkvec2(rnfV_to_nfM(rnf,x), gel(bas,2)))); } /* pseudo-basis for the 0 ideal */ static GEN rnfideal0(void) { retmkvec2(cgetg(1,t_MAT),cgetg(1,t_VEC)); } GEN rnfidealhnf(GEN rnf, GEN x) { GEN z, nf, bas; checkrnf(rnf); nf = rnf_get_nf(rnf); switch(typ(x)) { case t_INT: case t_FRAC: if (isintzero(x)) return rnfideal0(); bas = rnf_get_zk(rnf); z = cgetg(3,t_VEC); gel(z,1) = matid(rnf_get_degree(rnf)); gel(z,2) = gmul(x, gel(bas,2)); return z; case t_VEC: if (lg(x) == 3 && typ(gel(x,1)) == t_MAT) return nfhnf(nf, x); case t_MAT: return rnfidealabstorel(rnf, x); case t_POLMOD: case t_POL: case t_COL: return rnfprincipaltohnf(rnf,x); } pari_err_TYPE("rnfidealhnf",x); return NULL; /* LCOV_EXCL_LINE */ } static GEN prodidnorm(GEN nf, GEN I) { long i, l = lg(I); GEN z; if (l == 1) return gen_1; z = idealnorm(nf, gel(I,1)); for (i=2; i vector of 2 generators (relative polmods) */ GEN rnfidealtwoelement(GEN rnf, GEN x) { pari_sp av = avma; GEN y, cy, z, NF; y = rnfidealreltoabs_i(rnf,x); rnfcomplete(rnf); NF = obj_check(rnf,rnf_NFABS); y = matalgtobasis(NF, y); settyp(y, t_MAT); y = Q_primitive_part(y, &cy); y = ZM_hnf(y); if (lg(y) == 1) { avma = av; return mkvec2(gen_0, gen_0); } y = idealtwoelt(NF, y); if (cy) y = RgV_Rg_mul(y, cy); z = gel(y,2); if (typ(z) == t_COL) z = rnfeltabstorel(rnf, nf_to_scalar_or_alg(NF, z)); return gerepilecopy(av, mkvec2(gel(y,1), z)); } GEN rnfidealmul(GEN rnf,GEN x,GEN y) { pari_sp av = avma; GEN nf, z, x1, x2, p1, p2, bas; y = rnfidealtwoelement(rnf,y); if (isintzero(gel(y,1))) { avma = av; return rnfideal0(); } nf = rnf_get_nf(rnf); bas = rnf_get_zk(rnf); x = rnfidealhnf(rnf,x); x1 = gmodulo(gmul(gel(bas,1), matbasistoalg(nf,gel(x,1))), rnf_get_pol(rnf)); x2 = gel(x,2); p1 = gmul(gel(y,1), gel(x,1)); p2 = rnfV_to_nfM(rnf, gmul(gel(y,2), x1)); z = mkvec2(shallowconcat(p1, p2), shallowconcat(x2, x2)); return gerepileupto(av, nfhnf(nf,z)); } static GEN rnfidealprimedec_1(GEN rnf, GEN SL, GEN prK) { GEN v, piL = rnfeltup0(rnf, pr_get_gen(prK), 1); long i, c, l; if (typ(piL) != t_COL) return SL; /* p inert in K/Q */ v = cgetg_copy(SL, &l); for (i = c = 1; i < l; i++) { GEN P = gel(SL,i); if (ZC_prdvd(piL, P)) gel(v,c++) = P; } setlg(v, c); return v; } GEN rnfidealprimedec(GEN rnf, GEN pr) { pari_sp av = avma; GEN p, z, NF, nf, SL; checkrnf(rnf); rnfcomplete(rnf); NF = obj_check(rnf,rnf_NFABS); nf = rnf_get_nf(rnf); if (typ(pr) == t_INT) { p = pr; pr = NULL; } else { checkprid(pr); p = pr_get_p(pr); } SL = idealprimedec(NF, p); if (pr) z = rnfidealprimedec_1(rnf, SL, pr); else { GEN vK = idealprimedec(nf, p), vL; long l = lg(vK), i; vL = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(vL,i) = rnfidealprimedec_1(rnf, SL, gel(vK,i)); z = mkvec2(vK, vL); } return gerepilecopy(av, z); } GEN rnfidealfactor(GEN rnf, GEN x) { pari_sp av = avma; GEN NF; checkrnf(rnf); rnfcomplete(rnf); NF = obj_check(rnf,rnf_NFABS); return gerepileupto(av, idealfactor(NF, rnfidealreltoabs0(rnf, x, 1))); } GEN rnfequationall(GEN A, GEN B, long *pk, GEN *pLPRS) { long lA, lB; GEN nf, C; A = get_nfpol(A, &nf); lA = lg(A); if (!nf) { if (lA<=3) pari_err_CONSTPOL("rnfequation"); RgX_check_ZX(A,"rnfequation"); } B = RgX_nffix("rnfequation", A,B,1); lB = lg(B); if (lB<=3) pari_err_CONSTPOL("rnfequation"); B = Q_primpart(B); if (!nfissquarefree(A,B)) pari_err_DOMAIN("rnfequation","issquarefree(B)","=",gen_0,B); *pk = 0; C = ZX_ZXY_resultant_all(A, B, pk, pLPRS); if (signe(leading_coeff(C)) < 0) C = ZX_neg(C); *pk = -*pk; return Q_primpart(C); } GEN rnfequation0(GEN A, GEN B, long flall) { pari_sp av = avma; GEN LPRS, C; long k; C = rnfequationall(A, B, &k, flall? &LPRS: NULL); if (flall) { /* a,b,c root of A,B,C = compositum, c = b + k a */ GEN a, mH0 = RgX_neg(gel(LPRS,1)), H1 = gel(LPRS,2); a = RgXQ_mul(mH0, QXQ_inv(H1, C), C); C = mkvec3(C, mkpolmod(a, C), stoi(k)); } return gerepilecopy(av, C); } GEN rnfequation(GEN nf, GEN pol) { return rnfequation0(nf,pol,0); } GEN rnfequation2(GEN nf, GEN pol) { return rnfequation0(nf,pol,1); } GEN nf_rnfeq(GEN nf, GEN relpol) { GEN pol, a, k, junk, eq; relpol = liftpol_shallow(relpol); eq = rnfequation2(nf, relpol); pol = gel(eq,1); a = gel(eq,2); if (typ(a) == t_POLMOD) a = gel(a,2); k = gel(eq,3); return mkvec5(pol,a,k,get_nfpol(nf, &junk),relpol); } /* only allow abstorel */ GEN nf_rnfeqsimple(GEN nf, GEN relpol) { long sa; GEN junk, pol; relpol = liftpol_shallow(relpol); pol = rnfequationall(nf, relpol, &sa, NULL); return mkvec5(pol,gen_0/*dummy*/,stoi(sa),get_nfpol(nf, &junk),relpol); } /*******************************************************************/ /* */ /* RELATIVE LLL */ /* */ /*******************************************************************/ static GEN nftau(long r1, GEN x) { long i, l = lg(x); GEN s = r1? gel(x,1): gmul2n(real_i(gel(x,1)),1); for (i=2; i<=r1; i++) s = gadd(s, gel(x,i)); for ( ; i < l; i++) s = gadd(s, gmul2n(real_i(gel(x,i)),1)); return s; } static GEN initmat(long l) { GEN x = cgetg(l, t_MAT); long i; for (i = 1; i < l; i++) gel(x,i) = cgetg(l, t_COL); return x; } static GEN nftocomplex(GEN nf, GEN x) { GEN M = nf_get_M(nf); x = nf_to_scalar_or_basis(nf,x); if (typ(x) != t_COL) return const_col(nbrows(M), x); return RgM_RgC_mul(M, x); } /* assume x a square t_MAT, return a t_VEC of embeddings of its columns */ static GEN mattocomplex(GEN nf, GEN x) { long i,j, l = lg(x); GEN v = cgetg(l, t_VEC); for (j=1; j= 0) return NULL; /* precision problem */ m = ZM_ZC_mul(x, m); if (cx) m = ZC_Q_mul(m, cx); return gerepileupto(av, m); } static int RED(long k, long l, GEN U, GEN mu, GEN MC, GEN nf, GEN I, GEN *Ik_inv) { GEN x, xc, ideal; long i; if (!*Ik_inv) *Ik_inv = idealinv(nf, gel(I,k)); ideal = idealmul(nf,gel(I,l), *Ik_inv); x = findmin(nf, ideal, gcoeff(mu,k,l)); if (!x) return 0; if (gequal0(x)) return 1; xc = nftocomplex(nf,x); gel(MC,k) = gsub(gel(MC,k), vecmul(xc,gel(MC,l))); gel(U,k) = gsub(gel(U,k), gmul(coltoalg(nf,x), gel(U,l))); gcoeff(mu,k,l) = gsub(gcoeff(mu,k,l), xc); for (i=1; i 0) return 0; swap(gel(MC,k-1),gel(MC,k)); swap(gel(h,k-1), gel(h,k)); swap(gel(I,k-1), gel(I,k)); for (j=1; j<=k-2; j++) swap(gcoeff(mu,k-1,j),gcoeff(mu,k,j)); muf = gcoeff(mu,k,k-1); mufc = conj_i(muf); Bf = gadd(gel(B,k), vecmul(real_i(vecmul(muf,mufc)), gel(B,k-1))); if (check_0(Bf)) return 1; /* precision problem */ p1 = vecdiv(gel(B,k-1),Bf); gcoeff(mu,k,k-1) = vecmul(mufc,p1); temp = gel(MCS,k-1); gel(MCS,k-1) = gadd(gel(MCS,k), vecmul(muf,gel(MCS,k-1))); gel(MCS,k) = gsub(vecmul(vecdiv(gel(B,k),Bf), temp), vecmul(gcoeff(mu,k,k-1), gel(MCS,k))); gel(B,k) = vecmul(gel(B,k),p1); gel(B,k-1) = Bf; for (i=k+1; i<=kmax; i++) { temp = gcoeff(mu,i,k); gcoeff(mu,i,k) = gsub(gcoeff(mu,i,k-1), vecmul(muf, gcoeff(mu,i,k))); gcoeff(mu,i,k-1) = gadd(temp, vecmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k))); } return 1; } static GEN rel_T2(GEN nf, GEN pol, long lx, long prec) { long ru, i, j, k, l; GEN T2, s, unro, roorder, powreorder; roorder = nf_all_roots(nf, pol, prec); if (!roorder) return NULL; ru = lg(roorder); unro = cgetg(lx,t_COL); for (i=1; i kmax) { /* Incremental Gram-Schmidt */ kmax = k; gel(MCS,k) = gel(MC,k); for (j=1; j 2) k--; } else { for (l=k-2; l; l--) if (!RED(k, l, h, mu, MC, nf, I, &Ik_inv)) goto PRECPB; k++; } if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"rnflllgram"); gerepileall(av, H?10:9, &nf,&mth,&h,&MPOL,&B,&MC,&MCS,&mu,&I,&H); } } while (k < lx); MPOL = gmul(MPOL,h); if (H) h = gmul(H, h); if (DEBUGLEVEL) err_printf("\n"); MPOL = RgM_to_nfM(nf,MPOL); h = RgM_to_nfM(nf,h); return gerepilecopy(av, mkvec2(mkvec2(MPOL,I), h)); } GEN rnfpolred(GEN nf, GEN pol, long prec) { pari_sp av = avma; long i, j, n, v = varn(pol); GEN id, w, I, O, bnf, nfpol; if (typ(pol)!=t_POL) pari_err_TYPE("rnfpolred",pol); bnf = nf; nf = checknf(bnf); bnf = (nf == bnf)? NULL: checkbnf(bnf); if (degpol(pol) <= 1) { w = cgetg(2, t_VEC); gel(w,1) = pol_x(v); return w; } nfpol = nf_get_pol(nf); id = rnfpseudobasis(nf,pol); if (bnf && is_pm1( bnf_get_no(bnf) )) /* if bnf is principal */ { GEN newI, newO; O = gel(id,1); I = gel(id,2); n = lg(I)-1; newI = cgetg(n+1,t_VEC); newO = cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { GEN al = gen_if_principal(bnf,gel(I,j)); gel(newI,j) = gen_1; gel(newO,j) = nfC_nf_mul(nf, gel(O,j), al); } id = mkvec2(newO, newI); } id = gel(rnflllgram(nf,pol,id,prec),1); O = gel(id,1); I = gel(id,2); n = lg(I)-1; w = cgetg(n+1,t_VEC); pol = lift_shallow(pol); for (j=1; j<=n; j++) { GEN newpol, L, a, Ij = gel(I,j); a = RgC_Rg_mul(gel(O,j), (typ(Ij) == t_MAT)? gcoeff(Ij,1,1): Ij); for (i=n; i; i--) gel(a,i) = nf_to_scalar_or_alg(nf, gel(a,i)); a = RgV_to_RgX(a, v); newpol = RgXQX_red(RgXQ_charpoly(a, pol, v), nfpol); newpol = Q_primpart(newpol); (void)nfgcd_all(newpol, RgX_deriv(newpol), nfpol, nf_get_index(nf), &newpol); L = leading_coeff(newpol); gel(w,j) = (typ(L) == t_POL)? RgXQX_div(newpol, L, nfpol) : RgX_Rg_div(newpol, L); } return gerepilecopy(av,w); } /*******************************************************************/ /* */ /* LINEAR ALGEBRA OVER Z_K (HNF,SNF) */ /* */ /*******************************************************************/ /* A torsion-free module M over Z_K is given by [A,I]. * I=[a_1,...,a_k] is a row vector of k fractional ideals given in HNF. * A is an n x k matrix (same k) such that if A_j is the j-th column of A then * M=a_1 A_1+...+a_k A_k. We say that [A,I] is a pseudo-basis if k=n */ /* Given an element x and an ideal I in HNF, gives an r such that x-r is in H * and r is small */ GEN nfreduce(GEN nf, GEN x, GEN I) { pari_sp av = avma; GEN aI; x = nf_to_scalar_or_basis(checknf(nf), x); if (idealtyp(&I,&aI) != id_MAT || lg(I)==1) pari_err_TYPE("nfreduce",I); if (typ(x) != t_COL) x = scalarcol( gmod(x, gcoeff(I,1,1)), lg(I)-1 ); else x = reducemodinvertible(x, I); return gerepileupto(av, x); } /* Given an element x and an ideal in HNF, gives an a in ideal such that * x-a is small. No checks */ static GEN element_close(GEN nf, GEN x, GEN ideal) { pari_sp av = avma; GEN y = gcoeff(ideal,1,1); x = nf_to_scalar_or_basis(nf, x); if (typ(y) == t_INT && is_pm1(y)) return ground(x); if (typ(x) == t_COL) x = closemodinvertible(x, ideal); else x = gmul(y, gdivround(x,y)); return gerepileupto(av, x); } /* A + v B */ static GEN colcomb1(GEN nf, GEN v, GEN A, GEN B) { if (isintzero(v)) return A; return RgC_to_nfC(nf, RgC_add(A, nfC_nf_mul(nf,B,v))); } /* u A + v B */ static GEN colcomb(GEN nf, GEN u, GEN v, GEN A, GEN B) { if (isintzero(u)) return nfC_nf_mul(nf,B,v); if (u != gen_1) A = nfC_nf_mul(nf,A,u); return colcomb1(nf, v, A, B); } /* return m[i,1..lim] * x */ static GEN element_mulvecrow(GEN nf, GEN x, GEN m, long i, long lim) { long j, l = minss(lg(m), lim+1); GEN dx, y = cgetg(l, t_VEC); x = nf_to_scalar_or_basis(nf, x); if (typ(x) == t_COL) { x = zk_multable(nf, Q_remove_denom(x, &dx)); for (j=1; jidef; i--) { GEN d, di = NULL; j=def; while (j>=1 && isintzero(gcoeff(A,i,j))) j--; if (!j) { /* no pivot on line i */ if (idef) idef--; continue; } if (j==def) j--; else { swap(gel(A,j), gel(A,def)); swap(gel(I,j), gel(I,def)); if (U) swap(gel(U,j), gel(U,def)); } for ( ; j; j--) { GEN a,b, u,v,w, S, T, S0, T0 = gel(A,j); b = gel(T0,i); if (isintzero(b)) continue; S0 = gel(A,def); a = gel(S0,i); d = nfbezout(nf, a,b, gel(I,def),gel(I,j), &u,&v,&w,&di,1); S = colcomb(nf, u,v, S0,T0); T = colcomb(nf, a,gneg(b), T0,S0); gel(A,def) = S; gel(A,j) = T; gel(I,def) = d; gel(I,j) = w; if (U) { S0 = gel(U,def); T0 = gel(U,j); gel(U,def) = colcomb(nf, u,v, S0,T0); gel(U,j) = colcomb(nf, a,gneg(b), T0,S0); } } y = gcoeff(A,i,def); if (!isint1(y)) { GEN yi = nfinv(nf,y); gel(A,def) = nfC_nf_mul(nf, gel(A,def), yi); gel(I,def) = idealmul(nf, y, gel(I,def)); if (U) gel(U,def) = nfC_nf_mul(nf, gel(U,def), yi); di = NULL; } if (!di) di = idealinv(nf,gel(I,def)); d = gel(I,def); gel(J,def) = di; for (j=def+1; j<=n; j++) { GEN mc, c = gcoeff(A,i,j); if (isintzero(c)) continue; c = element_close(nf, c, idealmul(nf,d,gel(J,j))); mc = gneg(c); gel(A,j) = colcomb1(nf, mc, gel(A,j),gel(A,def)); if (U) gel(U,j) = colcomb1(nf, mc, gel(U,j),gel(U,def)); } def--; if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"nfhnf, i = %ld", i); gerepileall(av,U?4:3, &A,&I,&J,&U); } } n -= def; A += def; A[0] = evaltyp(t_MAT)|evallg(n+1); I += def; I[0] = evaltyp(t_VEC)|evallg(n+1); idV_simplify(I); x = mkvec2(A,I); if (U) x = mkvec2(x,U); return gerepilecopy(av0, x); } GEN nfhnf(GEN nf, GEN x) { return nfhnf0(nf, x, 0); } static GEN RgV_find_denom(GEN x) { long i, l = lg(x); for (i = 1; i < l; i++) if (Q_denom(gel(x,i)) != gen_1) return gel(x,i); return NULL; } /* A torsion module M over Z_K will be given by a row vector [A,I,J] with * three components. I=[b_1,...,b_n] is a row vector of n fractional ideals * given in HNF, J=[a_1,...,a_n] is a row vector of n fractional ideals in * HNF. A is an nxn matrix (same n) such that if A_j is the j-th column of A * and e_n is the canonical basis of K^n, then * M=(b_1e_1+...+b_ne_n)/(a_1A_1+...a_nA_n) */ /* x=[A,I,J] a torsion module as above. Output the * smith normal form as K=[c_1,...,c_n] such that x = Z_K/c_1+...+Z_K/c_n */ GEN nfsnf0(GEN nf, GEN x, long flag) { long i, j, k, l, n, m; pari_sp av; GEN z,u,v,w,d,dinv,A,I,J, U,V; nf = checknf(nf); if (typ(x)!=t_VEC || lg(x)!=4) pari_err_TYPE("nfsnf",x); A = gel(x,1); I = gel(x,2); J = gel(x,3); if (typ(A)!=t_MAT) pari_err_TYPE("nfsnf",A); n = lg(A)-1; if (typ(I)!=t_VEC) pari_err_TYPE("nfsnf",I); if (typ(J)!=t_VEC) pari_err_TYPE("nfsnf",J); if (lg(I)!=n+1 || lg(J)!=n+1) pari_err_DIM("nfsnf"); RgM_dimensions(A, &m, &n); if (!n || n != m) pari_err_IMPL("nfsnf for empty or non square matrices"); av = avma; if (!flag) U = V = NULL; else { U = matid(m); V = matid(n); } A = RgM_to_nfM(nf, A); I = leafcopy(I); J = leafcopy(J); for (i = 1; i <= n; i++) gel(J,i) = idealinv(nf, gel(J,i)); z = zerovec(n); for (i=n; i>=1; i--) { GEN Aii, a, b, db; long c = 0; for (j=i-1; j>=1; j--) { GEN S, T, S0, T0 = gel(A,j); b = gel(T0,i); if (gequal0(b)) continue; S0 = gel(A,i); a = gel(S0,i); d = nfbezout(nf, a,b, gel(J,i),gel(J,j), &u,&v,&w,&dinv,1); S = colcomb(nf, u,v, S0,T0); T = colcomb(nf, a,gneg(b), T0,S0); gel(A,i) = S; gel(A,j) = T; gel(J,i) = d; gel(J,j) = w; if (V) { T0 = gel(V,j); S0 = gel(V,i); gel(V,i) = colcomb(nf, u,v, S0,T0); gel(V,j) = colcomb(nf, a,gneg(b), T0,S0); } } for (j=i-1; j>=1; j--) { GEN ri, rj; b = gcoeff(A,j,i); if (gequal0(b)) continue; a = gcoeff(A,i,i); d = nfbezout(nf, a,b, gel(I,i),gel(I,j), &u,&v,&w,&dinv,1); ri = rowcomb(nf, u,v, i,j, A, i); rj = rowcomb(nf, a,gneg(b), j,i, A, i); for (k=1; k<=i; k++) { gcoeff(A,j,k) = gel(rj,k); gcoeff(A,i,k) = gel(ri,k); } if (U) { ri = rowcomb(nf, u,v, i,j, U, m); rj = rowcomb(nf, a,gneg(b), j,i, U, m); for (k=1; k<=m; k++) { gcoeff(U,j,k) = gel(rj,k); gcoeff(U,i,k) = gel(ri,k); } } gel(I,i) = d; gel(I,j) = w; c = 1; } if (c) { i++; continue; } Aii = gcoeff(A,i,i); if (gequal0(Aii)) continue; gel(J,i) = idealmul(nf, gel(J,i), Aii); gcoeff(A,i,i) = gen_1; if (V) gel(V,i) = nfC_nf_mul(nf, gel(V,i), nfinv(nf,Aii)); gel(z,i) = idealmul(nf,gel(J,i),gel(I,i)); b = Q_remove_denom(gel(z,i), &db); for (k=1; k1) pari_warn(warnmem,"nfsnf"); gerepileall(av,U?6:4, &A,&I,&J,&z,&U,&V); } if (c) i++; /* iterate on row/column i */ } if (U) z = mkvec3(z,U,V); return gerepilecopy(av, z); } GEN nfsnf(GEN nf, GEN x) { return nfsnf0(nf,x,0); } /* Given a pseudo-basis x, outputs a multiple of its ideal determinant */ GEN nfdetint(GEN nf, GEN x) { GEN pass,c,v,det1,piv,pivprec,vi,p1,A,I,id,idprod; long i, j, k, rg, n, m, m1, cm=0, N; pari_sp av = avma, av1; nf = checknf(nf); N = nf_get_degree(nf); check_ZKmodule(x, "nfdetint"); A = gel(x,1); I = gel(x,2); n = lg(A)-1; if (!n) return gen_1; m1 = lgcols(A); m = m1-1; id = matid(N); c = new_chunk(m1); for (k=1; k<=m; k++) c[k] = 0; piv = pivprec = gen_1; av1 = avma; det1 = idprod = gen_0; /* dummy for gerepileall */ pass = cgetg(m1,t_MAT); v = cgetg(m1,t_COL); for (j=1; j<=m; j++) { gel(pass,j) = zerocol(m); gel(v,j) = gen_0; /* dummy */ } for (rg=0,k=1; k<=n; k++) { long t = 0; for (i=1; i<=m; i++) if (!c[i]) { vi=nfmul(nf,piv,gcoeff(A,i,k)); for (j=1; j<=m; j++) if (c[j]) vi=gadd(vi,nfmul(nf,gcoeff(pass,i,j),gcoeff(A,j,k))); gel(v,i) = vi; if (!t && !gequal0(vi)) t=i; } if (t) { pivprec = piv; if (rg == m-1) { if (!cm) { cm=1; idprod = id; for (i=1; i<=m; i++) if (i!=t) idprod = (idprod==id)? gel(I,c[i]) : idealmul(nf,idprod,gel(I,c[i])); } p1 = idealmul(nf,gel(v,t),gel(I,k)); c[t]=0; det1 = (typ(det1)==t_INT)? p1: idealadd(nf,p1,det1); } else { rg++; piv=gel(v,t); c[t]=k; for (i=1; i<=m; i++) if (!c[i]) { for (j=1; j<=m; j++) if (c[j] && j!=t) { p1 = gsub(nfmul(nf,piv,gcoeff(pass,i,j)), nfmul(nf,gel(v,i),gcoeff(pass,t,j))); gcoeff(pass,i,j) = rg>1? nfdiv(nf,p1,pivprec) : p1; } gcoeff(pass,i,t) = gneg(gel(v,i)); } } } if (gc_needed(av1,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"nfdetint"); gerepileall(av1,6, &det1,&piv,&pivprec,&pass,&v,&idprod); } } if (!cm) { avma = av; return cgetg(1,t_MAT); } return gerepileupto(av, idealmul(nf,idprod,det1)); } /* reduce in place components of x[1..lim] mod D (destroy x). D in HNF */ static void nfcleanmod(GEN nf, GEN x, long lim, GEN D) { GEN DZ, DZ2, dD; long i; D = Q_remove_denom(D, &dD); DZ = gcoeff(D,1,1); DZ2 = shifti(DZ, -1); for (i = 1; i <= lim; i++) { GEN c = nf_to_scalar_or_basis(nf, gel(x,i)); switch(typ(c)) /* c = centermod(c, D) */ { case t_INT: if (!signe(c)) break; if (dD) c = mulii(c, dD); c = centermodii(c, DZ, DZ2); if (dD) c = Qdivii(c,dD); break; case t_FRAC: { GEN dc = gel(c,2), nc = gel(c,1), N = mulii(DZ, dc); if (dD) nc = mulii(nc, dD); c = centermodii(nc, N, shifti(N,-1)); c = Qdivii(c, dD ? mulii(dc,dD): dc); break; } case t_COL: { GEN dc; c = Q_remove_denom(c, &dc); if (dD) c = ZC_Z_mul(c, dD); c = ZC_hnfrem(c, dc? ZM_Z_mul(D,dc): D); dc = mul_content(dc, dD); if (ZV_isscalar(c)) { c = gel(c,1); if (dc) c = Qdivii(c,dc); } else if (dc) c = RgC_Rg_div(c, dc); break; } } gel(x,i) = c; } } GEN nfhnfmod(GEN nf, GEN x, GEN D) { long li, co, i, j, def, ldef; pari_sp av0=avma, av; GEN dA, dI, d0, w, p1, d, u, v, A, I, J, di; nf = checknf(nf); check_ZKmodule(x, "nfhnfmod"); A = gel(x,1); I = gel(x,2); co = lg(A); if (co==1) return cgetg(1,t_MAT); li = lgcols(A); if (typ(D)!=t_MAT) D = idealhnf_shallow(nf, D); D = Q_remove_denom(D, NULL); RgM_check_ZM(D, "nfhnfmod"); av = avma; A = RgM_to_nfM(nf, A); A = Q_remove_denom(A, &dA); I = Q_remove_denom(leafcopy(I), &dI); dA = mul_denom(dA,dI); if (dA) D = ZM_Z_mul(D, powiu(dA, minss(li,co))); def = co; ldef = (li>co)? li-co+1: 1; for (i=li-1; i>=ldef; i--) { def--; j=def; while (j>=1 && isintzero(gcoeff(A,i,j))) j--; if (!j) continue; if (j==def) j--; else { swap(gel(A,j), gel(A,def)); swap(gel(I,j), gel(I,def)); } for ( ; j; j--) { GEN a, b, S, T, S0, T0 = gel(A,j); b = gel(T0,i); if (isintzero(b)) continue; S0 = gel(A,def); a = gel(S0,i); d = nfbezout(nf, a,b, gel(I,def),gel(I,j), &u,&v,&w,&di,0); S = colcomb(nf, u,v, S0,T0); T = colcomb(nf, a,gneg(b), T0,S0); if (u != gen_0 && v != gen_0) /* already reduced otherwise */ nfcleanmod(nf, S, i, idealmul(nf,D,di)); nfcleanmod(nf, T, i, idealdiv(nf,D,w)); gel(A,def) = S; gel(A,j) = T; gel(I,def) = d; gel(I,j) = w; } if (gc_needed(av,2)) { if(DEBUGMEM>1) pari_warn(warnmem,"[1]: nfhnfmod, i = %ld", i); gerepileall(av,dA? 4: 3, &A,&I,&D,&dA); } } def--; d0 = D; A += def; A[0] = evaltyp(t_MAT)|evallg(li); I += def; I[0] = evaltyp(t_VEC)|evallg(li); J = cgetg(li,t_VEC); for (i=li-1; i>=1; i--) { GEN b = gcoeff(A,i,i); d = nfbezout(nf, gen_1,b, d0,gel(I,i), &u,&v,&w,&di,0); p1 = nfC_nf_mul(nf,gel(A,i),v); if (i > 1) { d0 = idealmul(nf,d0,di); nfcleanmod(nf, p1, i, d0); } gel(A,i) = p1; gel(p1,i) = gen_1; gel(I,i) = d; gel(J,i) = di; } for (i=li-2; i>=1; i--) { d = gel(I,i); for (j=i+1; j1) pari_warn(warnmem,"[2]: nfhnfmod, i = %ld", i); gerepileall(av,dA? 4: 3, &A,&I,&J,&dA); } } idV_simplify(I); if (dA) I = gdiv(I,dA); return gerepilecopy(av0, mkvec2(A, I)); } pari-2.11.2/src/basemath/ZX.c0000644000175000017500000006160513447371554014263 0ustar billbill/* Copyright (C) 2007 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* ZX */ /* */ /*******************************************************************/ void RgX_check_QX(GEN x, const char *s) { if (!RgX_is_QX(x)) pari_err_TYPE(stack_strcat(s," [not in Q[X]]"), x); } void RgX_check_ZX(GEN x, const char *s) { if (!RgX_is_ZX(x)) pari_err_TYPE(stack_strcat(s," [not in Z[X]]"), x); } long ZX_max_lg(GEN x) { long i, prec = 0, lx = lg(x); for (i=2; i prec) prec = l; } return prec; } GEN ZX_add(GEN x, GEN y) { long lx,ly,i; GEN z; lx = lg(x); ly = lg(y); if (lx < ly) swapspec(x,y, lx,ly); z = cgetg(lx,t_POL); z[1] = x[1]; for (i=2; i= ly) { z = cgetg(lx,t_POL); z[1] = x[1]; for (i=2; i1; i--) /* z[i] = a[i+1] + z[i+1] */ { GEN t = addii(gel(a0--,0), gel(z0--,0)); gel(z0,0) = t; } if (r) *r = addii(gel(a0,0), gel(z0,0)); return z; } /* Return 2^(n degpol(P)) P(x >> n), not memory clean if P is a ZX */ GEN ZX_rescale2n(GEN P, long n) { long i, l = lg(P), ni = n; GEN Q = cgetg(l,t_POL); Q[l-1] = P[l-1]; for (i=l-2; i>=2; i--) { gel(Q,i) = shifti(gel(P,i), ni); ni += n; } Q[1] = P[1]; return Q; } /* Return h^deg(P) P(x / h), not memory clean. h integer, P ZX */ GEN ZX_rescale(GEN P, GEN h) { long l = lg(P); GEN Q = cgetg(l,t_POL); if (l != 2) { long i = l-1; GEN hi = h; gel(Q,i) = gel(P,i); if (l != 3) { i--; gel(Q,i) = mulii(gel(P,i), h); } for (i--; i>=2; i--) { hi = mulii(hi,h); gel(Q,i) = mulii(gel(P,i), hi); } } Q[1] = P[1]; return Q; } /* Return h^(deg(P)-1) P(x / h), P!=0, h=lt(P), memory unclean; monic result */ GEN ZX_rescale_lt(GEN P) { long l = lg(P); GEN Q = cgetg(l,t_POL); gel(Q,l-1) = gen_1; if (l != 3) { long i = l-1; GEN h = gel(P,i), hi = h; i--; gel(Q,i) = gel(P,i); if (l != 4) { i--; gel(Q,i) = mulii(gel(P,i), h); } for (i--; i>=2; i--) { hi = mulii(hi,h); gel(Q,i) = mulii(gel(P,i), hi); } } Q[1] = P[1]; return Q; } /*Eval x in 2^(k*BIL) in linear time*/ static GEN ZX_eval2BILspec(GEN x, long k, long nx) { pari_sp av = avma; long i,j, lz = k*nx, ki; GEN pz = cgetipos(2+lz); GEN nz = cgetipos(2+lz); for(i=0; i < lz; i++) { *int_W(pz,i) = 0UL; *int_W(nz,i) = 0UL; } for(i=0, ki=0; i 0) for (j=0; j m) m = e; } return m; } static GEN Z_mod2BIL_ZX(GEN x, long bs, long d, long vx) { long i, offset, lm = lgefint(x)-2, l = d+vx+3, sx = signe(x); GEN s1 = int2n(bs*BITS_IN_LONG), pol = cgetg(l, t_POL); int carry = 0; pol[1] = evalsigne(1); for (i=0; i 0 ?adduispec_offset(carry, x, offset, lz): utoi(carry); if (lgefint(z) == 3+bs) { carry = 1; z = gen_0;} else { carry = (lgefint(z) == 2+bs && (HIGHBIT & *int_W(z,bs-1))); if (carry) z = gerepileuptoint(av, (sx==-1)? subii(s1,z): subii(z,s1)); else if (sx==-1) togglesign(z); } gel(pol,i+2) = z; } return ZX_renormalize(pol,l); } static GEN ZX_sqrspec_sqri(GEN x, long nx, long ex, long v) { long e = 2*ex + expu(nx) + 3; long N = divsBIL(e)+1; GEN z = sqri(ZX_eval2BILspec(x,N,nx)); return Z_mod2BIL_ZX(z, N, nx*2-2, v); } static GEN ZX_mulspec_mulii(GEN x, GEN y, long nx, long ny, long ex, long ey, long v) { long e = ex + ey + expu(minss(nx,ny)) + 3; long N = divsBIL(e)+1; GEN z = mulii(ZX_eval2BILspec(x,N,nx), ZX_eval2BILspec(y,N,ny)); return Z_mod2BIL_ZX(z, N, nx+ny-2, v); } INLINE GEN ZX_sqrspec_basecase_limb(GEN x, long a, long i) { pari_sp av = avma; GEN s = gen_0; long j, l = (i+1)>>1; for (j=a; j>1); if (signe(t)) s = addii(s, sqri(t)); } return gerepileuptoint(av,s); } static GEN ZX_sqrspec_basecase(GEN x, long nx, long v) { long i, lz, nz; GEN z; lz = (nx << 1) + 1; nz = lz-2; lz += v; z = cgetg(lz,t_POL); z[1] = evalsigne(1); z += 2; for (i=0; i=dy; i--) { av=avma; p1=gel(x,i); for (j=i-dy+1; j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); gel(z,i-dy) = avma == av? icopy(p1): gerepileuptoint(av, p1); } rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3); for (sx=0; ; i--) { p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); if (signe(p1)) { sx = 1; break; } if (!i) break; avma=av; } lr=i+3; rem -= lr; rem[0] = evaltyp(t_POL) | evallg(lr); rem[1] = z[-1]; p1 = gerepileuptoint((pari_sp)rem, p1); rem += 2; gel(rem,i) = p1; for (i--; i>=0; i--) { av=avma; p1 = gel(x,i); for (j=0; j<=i && j<=dz; j++) p1 = subii(p1, mulii(gel(z,j),gel(y,i-j))); gel(rem,i) = avma == av? icopy(p1): gerepileuptoint(av, p1); } rem -= 2; if (!sx) (void)ZX_renormalize(rem, lr); return gerepileupto(av0,rem); } /* return x(1) */ GEN ZX_eval1(GEN x) { pari_sp av = avma; long i = lg(x)-1; GEN s; if (i < 2) return gen_0; s = gel(x,i); i--; if (i == 1) return icopy(s); for ( ; i>=2; i--) { GEN c = gel(x,i); if (signe(c)) s = addii(s, c); } return gerepileuptoint(av,s); } /* reduce T mod X^n - 1. Shallow function */ GEN ZX_mod_Xnm1(GEN T, ulong n) { long i, j, L = lg(T), l = n+2; GEN S; if (L <= l) return T; S = cgetg(l, t_POL); S[1] = T[1]; for (i = 2; i < l; i++) gel(S,i) = gel(T,i); for (j = 2; i < L; i++) { gel(S,j) = addii(gel(S,j), gel(T,i)); if (++j == l) j = 2; } return normalizepol_lg(S, l); } /*******************************************************************/ /* */ /* ZXV */ /* */ /*******************************************************************/ int ZXV_equal(GEN V, GEN W) { long l = lg(V); if (l!=lg(W)) return 0; while (--l > 0) if (!ZX_equal(gel(V,l), gel(W,l))) return 0; return 1; } GEN ZXV_Z_mul(GEN x, GEN y) { pari_APPLY_same(ZX_Z_mul(gel(x,i), y)) } GEN ZXV_remi2n(GEN x, long N) { pari_APPLY_same(ZX_remi2n(gel(x,i), N)) } GEN ZXV_dotproduct(GEN x, GEN y) { pari_sp av = avma; long i, lx = lg(x); GEN c; if (lx == 1) return pol_0(varn(x)); c = ZX_mul(gel(x,1), gel(y,1)); for (i = 2; i < lx; i++) { GEN t = ZX_mul(gel(x,i), gel(y,i)); if (signe(t)) c = ZX_add(c, t); } return gerepileupto(av, c); } /*******************************************************************/ /* */ /* ZXQM */ /* */ /*******************************************************************/ GEN ZXn_mul(GEN x, GEN y, long n) { return RgXn_red_shallow(ZX_mul(x, y), n); } GEN ZXn_sqr(GEN x, long n) { return RgXn_red_shallow(ZX_sqr(x), n); } /*******************************************************************/ /* */ /* ZXQM */ /* */ /*******************************************************************/ static long ZX_expi(GEN x) { if (signe(x)==0) return 0; if (typ(x)==t_INT) return expi(x); return ZX_expispec(x+2, lgpol(x)); } static long ZXC_expi(GEN x) { long i, l = lg(x), m=0; for(i = 1; i < l; i++) { long e = ZX_expi(gel(x,i)); if (e > m) m = e; } return m; } static long ZXM_expi(GEN x) { long i, l = lg(x), m=0; for(i = 1; i < l; i++) { long e = ZXC_expi(gel(x,i)); if (e > m) m = e; } return m; } static GEN ZX_eval2BIL(GEN x, long k) { if (signe(x)==0) return gen_0; if (typ(x)==t_INT) return x; return ZX_eval2BILspec(x+2, k, lgpol(x)); } /*Eval x in 2^(k*BIL) in linear time*/ static GEN ZXC_eval2BIL(GEN x, long k) { long i, lx = lg(x); GEN A = cgetg(lx, t_COL); for (i=1; i1; k--) { GEN t = gel(x,k); switch(typ(t)) { case t_INT: break; case t_POL: if (RgX_is_ZX(t)) break; /* fall through */ default: pari_err_TYPE(stack_strcat(s, " not in Z[X,Y]"),x); } } } /*Renormalize (in place) polynomial with t_INT or ZX coefficients.*/ GEN ZXX_renormalize(GEN x, long lx) { long i; for (i = lx-1; i>1; i--) if (signe(gel(x,i))) break; stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + (i+1))); setlg(x, i+1); setsigne(x, i!=1); return x; } long ZXX_max_lg(GEN x) { long i, prec = 0, lx = lg(x); for (i=2; i prec) prec = l; } return prec; } GEN ZXX_Z_mul(GEN y, GEN x) { long i, l = lg(y); GEN z = cgetg(l,t_POL); z[1] = y[1]; for(i=2; i ZX: * P(X,Y) = sum_{0<=i= n) pari_err_BUG("ZXX_to_Kronecker, P is not reduced mod Q"); for (j=2; j < l; j++) gel(y,k++) = gel(c,j); } if (i == lP-1) break; for ( ; j < N; j++) gel(y,k++) = gen_0; } y-=2; setlg(y, k+2); y[1] = evalsigne(1); return y; } GEN ZXX_to_Kronecker(GEN P, long n) { GEN z = ZXX_to_Kronecker_spec(P+2, lgpol(P), n); setvarn(z,varn(P)); return z; } GEN ZXQX_sqr(GEN x, GEN T) { pari_sp av = avma; long n = degpol(T); GEN z = ZXX_sqr_Kronecker(x, n); z = Kronecker_to_ZXX(z, n, varn(T)); return gerepileupto(av, z); } GEN ZXQX_mul(GEN x, GEN y, GEN T) { pari_sp av = avma; long n = degpol(T); GEN z = ZXX_mul_Kronecker(x, y, n); z = Kronecker_to_ZXX(z, n, varn(T)); return gerepileupto(av, z); } GEN QX_mul(GEN x, GEN y) { GEN dx, nx = Q_primitive_part(x, &dx); GEN dy, ny = Q_primitive_part(y, &dy); GEN z = ZX_mul(nx, ny); if (dx || dy) { GEN d = dx ? dy ? gmul(dx, dy): dx : dy; return ZX_Q_mul(z, d); } else return z; } GEN QX_sqr(GEN x) { GEN dx, nx = Q_primitive_part(x, &dx); GEN z = ZX_sqr(nx); if (dx) return ZX_Q_mul(z, gsqr(dx)); else return z; } GEN QX_ZX_rem(GEN x, GEN y) { pari_sp av = avma; GEN d, nx = Q_primitive_part(x, &d); GEN r = ZX_rem(nx, y); if (d) r = ZX_Q_mul(r, d); return gerepileupto(av, r); } pari-2.11.2/src/basemath/zetamult.c0000644000175000017500000003006613326135265015555 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** MULTIPLE ZETA VALUES (AKHILESH ALGORITHM) **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" static long la(long e, long f) { return (e == f)? 2: (e? 1: 3); } static GEN lamul(long la, GEN s) { switch(la) { case 2: return gmul2n(s,1); case 3: return gmulgs(s,3); default: return s; } } /* dual of evec[1..l-1] */ static GEN revslice(GEN evec, long l) { GEN res = cgetg(l, t_VECSMALL); long i; for (i = 1; i < l; ++i) res[i] = 1 - evec[l-i]; return res; } /* N.B. evec[ne] = 1 */ static GEN etoa(GEN evec) { long ct = 0, ctold = 0, i = 1, le = lg(evec); GEN avec = cgetg(le, t_VECSMALL); while (++ct < le) if (evec[ct] == 1) { avec[i++] = ct - ctold; ctold = ct; } setlg(avec, i); return avec; } static GEN atoe(GEN avec) { long i, l = lg(avec); GEN evec = cgetg(l, t_VEC); for (i = 1; i < l; i++) { long a = avec[i]; gel(evec,i) = vecsmall_ei(a,a); } return shallowconcat1(evec); } /* vphi[i] contains phip(j,avec[i..r]) for 1<= j < L * vpow[a][j] = j^-a as a t_INT or t_REAL; j < L */ static GEN phip(GEN avec, GEN vpow) { long i, r = lg(avec) - 1; GEN vphi = cgetg(r+1, t_VEC); gel(vphi, r) = gel(vpow, avec[r]); for (i = r-1; i >= 1; i--) { GEN t, u, phi = gel(vphi,i+1), pow = gel(vpow, avec[i]); long j, L = lg(pow); gel(vphi, i) = u = cgetg(L, t_VEC); gel(u,1) = gen_0; gel(u,2) = (i==r-1)? gel(pow,2): gen_0; t = gel(phi,1); /* 0 or 1 */ for (j = 3; j < L; j++) { t = mpadd(t, gel(phi,j-1)); gel(u,j) = mpmul(t, gel(pow,j)); /* t / j^avec[i] */ } } return vphi; } /* Return 1 if vec2 RHS of vec1, -1 if vec1 RHS of vec2, 0 else */ static long isrhs(GEN v1, GEN v2) { long s = 1, i, l1 = lg(v1), l2 = lg(v2); if (l1 < l2) { s = -1; swap(v1,v2); lswap(l1,l2); } for (i = l2-1; i >= 1; --i) if (v2[i] != v1[l1-l2+i]) return 0; return s; } static long istruerhs(GEN v1, GEN v2) { long i, l1 = lg(v1), l2 = lg(v2); if (l1 < l2) return 0; for (i = l2-1; i >= 1; --i) if (v2[i] != v1[l1-l2+i]) return 0; return l1-l2+1; } /* a is a rhs of a unique v[m] */ static GEN isinphi(GEN v, GEN a, GEN vphi) { long m, l = lg(v); for (m = 1; m < l; m++) { long s = istruerhs(gel(v,m), a); if (s) return gmael(vphi,m,s); } return NULL; /* LCOV_EXCL_LINE */ } /* If v RHS of LR[i] for some i, return LR. If LR[i] RHS (strict) of v, replace * LR[i] by v. If none, add v to LR. */ static GEN addevec(GEN LR, GEN v) { long s, i, l1 = lg(LR); for (i = 1; i < l1; i++) { s = isrhs(gel(LR,i), v); if (s == 1) return LR; if (s ==-1) { gel(LR,i) = v; return LR; } } return vec_append(LR,v); } /* N > 2 */ static GEN get_vbin(long N, long prec) { GEN v = cgetg(N+1, t_VEC); long n; gel(v,1) = gen_0; /* unused */ gel(v,2) = invr(utor(6,prec)); for (n = 3; n <= N; n++) gel(v,n) = divru(mulru(gel(v,n-1), n), 4*n-2); return v; } /* m < k */ static GEN zetamultinit_i(long k, long m, long bitprec) { long i, N, prec; GEN vpow = cgetg(m+1, t_VEC); bitprec += 64*(1+(k>>5)); prec = nbits2prec(bitprec); N = 5 + bitprec/2; gel(vpow,1) = vecpowug(N, gen_m1, prec); for (i = 2; i <= m; i++) { GEN pow = cgetg(N+1, t_VEC), powm = gel(vpow,i-1); long j; gel(pow,1) = gen_1; gel(pow,2) = real2n(-i, prec); for (j = 3; j <= N; j++) gel(pow,j) = divru(gel(powm,j), j); gel(vpow,i) = pow; } return mkvec2(vpow, get_vbin(N, prec)); } GEN zetamultinit(long k, long prec) { pari_sp av = avma; if (k <= 0) pari_err_DOMAIN("zetamultinit", "weight", "<=", gen_0, stoi(k)); return gerepilecopy(av, zetamultinit_i(k, k-1, prec2nbits(prec))); } GEN zetamult0(GEN avec, GEN T, long prec) { pari_sp ltop = avma; long k, n, i, j, l, lbin; GEN vpow, vphi, vbin, S, s, LR, MA, MR, evec = gen_0; avec = zetamultconvert(avec, 1); if (lg(avec) == 1) return gen_1; evec = atoe(avec); k = lg(evec)-1; /* weight */ LR = cgetg(1, t_VEC); MA = cgetg(k, t_VEC); MR = cgetg(k, t_VEC); for (i = 1; i < k; ++i) { gel(MA,i) = etoa(revslice(evec, i+1)); gel(MR,i) = etoa(vecslice(evec, i+1, k)); LR = addevec(addevec(LR, gel(MA,i)), gel(MR,i)); } if (!T) { long m = vecvecsmall_max(LR); /* < k */ T = zetamultinit_i(k, m, prec2nbits(prec)); } else { long M; if (typ(T) != t_VEC || lg(T) != 3) pari_err_TYPE("zetamult", T); M = lg(gel(T,1)); /* need M > m, which is < k */ if (M < k) pari_err_DOMAIN("zetamult", "weight", ">", utoi(M), utoi(k)); } vpow = gel(T,1); vbin = gel(T,2); l = lg(LR); vphi = cgetg(l, t_VEC); for (j = 1; j < l; j++) gel(vphi,j) = phip(gel(LR,j), vpow); lbin = lg(vbin); S = cgetg(lbin, t_VEC); for (i = 1; i < k; i++) { long LA = la(evec[i],evec[i+1]); GEN phi1 = isinphi(LR, gel(MA,i), vphi); GEN phi2 = isinphi(LR, gel(MR,i), vphi); if (i == 1) for (n = 1; n < lbin; n++) gel(S,n) = lamul(LA, mpmul(gel(phi1,n), gel(phi2,n))); else for (n = 1; n < lbin; n++) gel(S,n) = mpadd(gel(S,n), lamul(LA, mpmul(gel(phi1,n), gel(phi2,n)))); } s = gmul2n(gel(S,1), -1); for (n = 2; n < lbin; n++) s = gadd(s, mpmul(gel(S,n), gel(vbin,n))); return gerepileuptoleaf(ltop, rtor(s,prec)); } GEN zetamult(GEN avec, long prec) { return zetamult0(avec, NULL, prec); } /**************************************************************/ /* ALL MZV's */ /**************************************************************/ /* vecsmall to binary */ static long myfd(GEN evec, long ini, long fin) { long i, s = 0; for (i = ini; i <= fin; ++i) s = evec[i] | (s << 1); return s; } /* Given admissible evec w = 0e_2....e_{k-1}1, compute a,b,v such that * w=0{1}_{b-1}v{0}_{a-1}1 with v empty or admissible. * Input: binary vector evec */ static void findabv(GEN w, long *pa, long *pb, long *pminit, long *pmmid, long *pmfin) { long le = lg(w) - 2; if (le == 0) { *pa = 1; *pb = 1; *pminit = 2; *pmfin = 2; *pmmid = 1; } else { long a, b, j, lv; for (j = 1; j <= le; ++j) if (!w[j+1]) break; b = j; for (j = le; j >= 1; --j) if (w[j+1]) break; a = le + 1 - j; lv = le + 2 - a - b; if (lv > 0) { long v = myfd(w, b + 1, le - a + 2); *pa = a; *pb = b; *pminit = (((1 << b) - 1) << (lv - 1)) + (v/2) + 2; *pmfin = (((1 << (lv - 1)) + v) << (a - 1)) + 2; *pmmid = (1 << (lv - 2)) + (v/2) + 2; } else { *pa = a; *pb = b; *pminit = (1 << (b - 1)) + 1; *pmfin = (a == 1) ? 2 : (1 << (a - 2)) + 2; *pmmid = 1; } } } /* Returns 'all': * all[1] contains zeta(emptyset)_{n-1,n-1}, * all[2] contains zeta({0})_{n-1,n-1}=zeta({1})_{n-1,n-1} for n >= 2, * all[m+2][n] : 1 <= m < 2^{k-2}, 1 <= n <= N + 1 * contains zeta(w)_{n-1,n-1}, w corresponding to m,n * all[m+2] : 2^{k-2} <= m < 2^{k-1} contains zeta(w), w corresponding to m (code: w=0y1 iff m=1y). */ static GEN fillall(long k, long bitprec) { long N = 1 + bitprec/2, prec = nbits2prec(bitprec); long k1, j, n, m, mbar = 0, K = 1 << (k - 1), K2 = K/2; GEN all, v, p1, p2, r1, pab, S; r1 = real_1(prec); pab = cgetg(N+1, t_VEC); gel(pab, 1) = gen_0; /* not needed */ for (n = 2; n <= N; n++) gel(pab, n) = powersr(divru(r1, n), k); /* 1/n^a = gmael(pab, n, a + 1) */ all = cgetg(K + 2, t_VEC); gel(all,1) = v = cgetg(N+1, t_VEC); gel(v,1) = gen_0; /* unused */ gel(v,2) = real2n(-1,prec); gel(v,3) = invr(utor(6,prec)); /* cf get_vbin: shifted by 1 :-( */ for (n = 3; n < N; n++) gel(v,n+1) = divru(mulru(gel(v,n), n), 4*n-2); gel(all,2) = p1 = cgetg(N+1, t_VEC); gel(p1,1) = gen_0; /* unused */ for (j = 2; j <= N; j++) gel(p1,j) = divru(gel(v,j), j-1); for (m = 1; m < K2; m++) { gel(all, m+2) = p1 = cgetg(N+1, t_VEC); for (n = 1; n < N; n++) gel(p1, n) = cgetr(prec); gel(p1, n) = gen_0; } for (m = K2; m < K; m++) gel(all, m+2) = utor(0, prec); for (k1 = 2; k1 <= k; k1++) { /* Assume length evec < k1 filled */ /* If evec = 0e_2...e_{k_1-1}1 then m = (1e_2...e_{k_1-1})_2 */ GEN w = cgetg(k1, t_VECSMALL); long M = 1 << (k1 - 2); pari_sp av = avma; for (m = M; m < 2*M; m++) { GEN pinit, pfin, pmid; long comp, a, b, minit, mfin, mmid, mc = m, ii = 0; p1 = gel(all, m + 2); for (j = k1 - 1; j >= 2; --j) { w[j] = mc & 1; ii = (1 - w[j]) | (ii<<1); mc >>= 1; } mbar = M + ii; comp = mbar - m; if (comp < 0) continue; p2 = gel(all, mbar + 2); findabv(w, &a,&b,&minit,&mmid,&mfin); pinit= gel(all, minit); pfin = gel(all, mfin); pmid = gel(all, mmid); for (n = N-1; n > 1; n--, avma = av) { GEN t = mpmul(gel(pinit,n+1), gmael(pab, n, a+1)); GEN u = mpmul(gel(pfin, n+1), gmael(pab, n, b+1)); GEN v = mpmul(gel(pmid, n+1), gmael(pab, n, a+b+1)); S = mpadd(k1 < k ? gel(p1, n+1) : p1, mpadd(mpadd(t, u), v)); if (!signe(S)) S = gen_0; mpaff(S, k1 < k ? gel(p1, n) : p1); if (comp > 0 && k1 < k) mpaff(S, gel(p2, n)); } { /* n = 1: same formula simplifies */ GEN t = gel(pinit,2), u = gel(pfin,2), v = gel(pmid,2); S = mpadd(k1 < k ? gel(p1,2) : p1, mpadd(mpadd(t, u), v)); if (!signe(S)) S = gen_0; mpaff(S, k1 < k ? gel(p1,1) : p1); if (comp > 0 && k1 < k) mpaff(S, gel(p2, 1)); avma = av; } if (comp > 0 && k1 == k) mpaff(p1, p2); } } for (j = 1; j < K; j++) gel(all, j) = j < K2 ? gmael(all, j+2, 1) : gel(all, j+2); setlg(all, K); return all; } GEN zetamultall(long k, long prec) { pari_sp av = avma; if (k < 1) pari_err_DOMAIN("zetamultall", "k", "<", gen_1, stoi(k)); if (k >= 64) pari_err_OVERFLOW("zetamultall"); return gerepilecopy(av, fillall(k, prec2nbits(prec) + 32)); } /* m > 0 */ static GEN mtoevec(GEN m) { GEN e = vecsmall_append(binary_zv(m), 1); e[1] = 0; return e; } static GEN etoindex(GEN evec) { long k = lg(evec) - 1; return utoipos((1 << (k-2)) + myfd(evec, 2, k-1)); } /* Conversions: types are evec, avec, m (if evec=0y1, m=(1y)_2). fl is respectively 0, 1, 2. Type of a is autodetected. */ GEN zetamultconvert(GEN a, long fl) { pari_sp av = avma; long i, l; if (fl < 0 || fl > 2) pari_err_FLAG("zetamultconvert"); switch(typ(a)) { case t_INT: if (signe(a) <= 0) pari_err_TYPE("zetamultconvert",a); switch (fl) { case 0: a = mtoevec(a); break; case 1: a = etoa(mtoevec(a)); break; case 2: a = icopy(a); break; } break; case t_VEC: case t_COL: case t_VECSMALL: a = gtovecsmall(a); l = lg(a); if (a[1] == 0) { if (!a[l-1]) pari_err_TYPE("zetamultconvert", a); for (i = 1; i < l; i++) if (a[i] & ~1UL) pari_err_TYPE("zetamultconvert", a); switch (fl) { case 1: a = etoa(a); break; case 2: a = etoindex(a); } } else { if (a[1] < 2) pari_err_TYPE("zetamultconvert", a); for (i = 2; i < l; i++) if (a[i] <= 0) pari_err_TYPE("zetamultconvert", a); switch (fl) { case 0: a = atoe(a); break; case 2: a = etoindex(atoe(a)); } } break; default: pari_err_TYPE("zetamultconvert", a); } return gerepileuptoleaf(av, a); } pari-2.11.2/src/basemath/bnflog.c0000644000175000017500000003272713326135265015165 0ustar billbill/* Copyright (C) 2016 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* LOGARITHMIC CLASS GROUP */ /*******************************************************************/ /* min(v, v(Log_p Norm_{F_\p/Q_p}(x))) */ static long vlognorm(GEN nf, GEN T, GEN x, GEN p, long v) { GEN a = nf_to_scalar_or_alg(nf, x); GEN N = RgXQ_norm(a, T); if (typ(N) != t_PADIC) N = cvtop(N, p, v); return minss(v, valp( Qp_log(N) )); } /* K number field, pr a maximal ideal, let K_pr be the attached local * field, K_pr = Q_p[X] / (T), T irreducible. Return \tilde{e}(K_pr/Q_p) */ static long etilde(GEN nf, GEN pr, GEN T) { GEN gp = pr_get_p(pr); ulong e = pr_get_e(pr); long v, voo, vmin, p, k; if (!u_pval(e, gp)) { v = u_pval(pr_get_f(pr), gp); return itou( mului(e, powiu(gp, v)) ); } nf = checknf(nf); p = itou(gp); k = e / (p-1) + 1; /* log Norm_{F_P/Q_p} (1 + P^k) = Tr(P^k) = p^[(k + v(Diff))/ e] Z_p */ voo = (k + idealval(nf, nf_get_diff(nf), pr)) / e; vmin = vlognorm(nf, T, pr_get_gen(pr), gp, voo); if (k > 1) { GEN U = idealprincipalunits(nf, pr, k); GEN gen = abgrp_get_gen(U), cyc = abgrp_get_cyc(U); long i, l = lg(cyc); for (i = 1; i < l; i++) { if (voo - Z_lval(gel(cyc,i), p) >= vmin) break; vmin = vlognorm(nf, T, gel(gen,i), gp, vmin); } } v = u_lval(degpol(T), p) + (p == 2UL? 2 : 1) - vmin; (void)u_lvalrem(e, p, &e); return e * upowuu(p,v); } static long ftilde_from_e(GEN pr, long e) { return pr_get_e(pr) * pr_get_f(pr) / e; } static long ftilde(GEN K, GEN pr, GEN T) { return ftilde_from_e(pr, etilde(K,pr, T)); } static long get_ZpX_index(GEN K, GEN pr, GEN T) { GEN p, pi; long j, l = lg(T); if (l == 2) return 1; p = pr_get_p(pr); pi = nf_to_scalar_or_alg(K, pr_get_gen(pr)); for (j = 1; j < l; j++) { GEN t = gel(T,j); if (t && gvaluation(RgXQ_norm(pi, t), p)) return j; } return 0; } /* Given a number field K and a prime p, return * S = places of K above p [primedec] * R = corresponding p-adic factors of K.pol (mod p^k), in the same order */ static GEN padicfact(GEN K, GEN S, long k) { GEN R, p = pr_get_p(gel(S,1)); GEN T = gel(factorpadic(nf_get_pol(K), p, k), 1); long l, i; S = idealprimedec(K, p); R = cgetg_copy(S, &l); for (i = 1; i < l; i++) { long j = get_ZpX_index(K, gel(S,i), T); gel(R,i) = gel(T,j); gel(T,j) = NULL; } return R; } /* K a bnf, compute Cl'(K) = ell-Sylow of Cl(K) / (places above ell). * Return [D, u, R0, U0, ordS] * - D: cyclic factors for Cl'(K) * - u: generators of cyclic factors (all coprime to ell) * - R0: subgroup isprincipal() (divides K.cyc) * - U0: generators of R0 are of the form S . U0 * - ordS[i] = order of S[i] in CL(K) */ static GEN CL_prime(GEN K, GEN ell, GEN Sell) { GEN g, ordS, R0, U0, U, D, u, cyc = bnf_get_cyc(K); long i, l, lD, lS = lg(Sell); g = leafcopy(bnf_get_gen(K)); l = lg(g); for (i = 1; i < l; i++) { GEN A = gel(g,i), a = gcoeff(A,1,1); long v = Z_pvalrem(a, ell, &a); if (v) gel(g,i) = hnfmodid(A, a); /* make coprime to ell */ } R0 = cgetg(lS, t_MAT); ordS = cgetg(lS, t_VEC); for (i = 1; i < lS; i++) { gel(R0,i) = isprincipal(K, gel(Sell,i)); gel(ordS,i) = charorder(cyc, gel(R0,i)); /* order of Sell[i] */ } R0 = shallowconcat(R0, diagonal_shallow(cyc)); /* R0 = subgroup generated by S in Cl(K) [ divides diagonal(K.cyc) ]*/ R0 = ZM_hnfall(R0, &U0, 2); /* [S | cyc] * U0 = R0 in HNF */ D = ZM_snfall(R0, &U,NULL); D = RgM_diagonal_shallow(D); lD = lg(D); u = ZM_inv(U, NULL); settyp(u, t_VEC); for (i = 1; i < lD; i++) gel(u,i) = idealfactorback(K,g,gel(u,i),1); setlg(U0, l); U0 = rowslice(U0,1,lS-1); /* restrict to 'S' part */ return mkvec5(D, u, R0, U0, ordS); } static GEN ell1(GEN ell) { return equaliu(ell,2)? utoipos(5): addiu(ell,1); } /* log N_{F_P/Q_p}(x) / deg_F P */ static GEN vtilde_i(GEN K, GEN x, GEN T, GEN deg, GEN ell, long prec) { GEN L, cx; if (typ(x) != t_POL) x = nf_to_scalar_or_alg(K, x); if (typ(x) != t_POL) { cx = x; L = gen_0; } else { GEN N; x = Q_primitive_part(x,&cx); N = RgXQ_norm(x, T); L = Qp_log(cvtop(N,ell,prec)); } if (cx) { Q_pvalrem(cx, ell, &cx); if (!isint1(cx)) L = gadd(L, gmulsg(degpol(T), Qp_log(cvtop(cx,ell,prec)))); } return gdiv(L, deg); } static GEN vtilde(GEN K, GEN x, GEN T, GEN deg, GEN ell, long prec) { GEN G, E, vG; long i, l; if (typ(x) != t_MAT) return vtilde_i(K,x,T,deg,ell,prec); G = gel(x,1); vG = cgetg_copy(G, &l); E = gel(x,2); for (i = 1; i < l; i++) gel(vG, i) = vtilde_i(K, gel(G,i),T,deg,ell,prec); return RgV_dotproduct(E, vG); } /* v[i] = deg S[i] mod p^prec */ static GEN get_vdegS(GEN Ftilde, GEN ell, long prec) { long i, l = lg(Ftilde); GEN v = cgetg(l, t_VEC), degell = Qp_log( cvtop(ell1(ell), ell, prec) ); for (i = 1; i < l; i++) gel(v,i) = gmulsg(Ftilde[i], degell); return v; } /* K a bnf. Compute kernel \tilde{Cl}_K(ell); return cyclic factors. * Set *pM to (vtilde_S[i](US[j]))_{i,j} */ static GEN CL_tilde(GEN K, GEN US, GEN ell, GEN T, GEN Ftilde, GEN *pM, long prec) { GEN D, M, ellk, vdegS; long i, j, imin, vmin, k, lD, l = lg(T), lU = lg(US); *pM = cgetg(1, t_MAT); if (l == 2) return cgetg(1, t_VEC); /* p = P^e: \tilde{Cl}(l) = (1) */ vdegS = get_vdegS(Ftilde, ell, prec); imin = 1; vmin = l; /* upper bound */ for (i = 1; i < l; i++) { long v = z_pval(Ftilde[i], ell); if (v < vmin) { vmin = v; imin = i; } } M = cgetg(lU, t_MAT); for (j = 1; j < lU; j++) { GEN c = cgetg(l, t_COL), a = gel(US,j); for (i = 1; i < l; i++) gel(c,i) = vtilde(K, a, gel(T,i), gel(vdegS,i), ell, prec); gel(M,j) = c; } k = padicprec(M, ell); ellk = powiu(ell, k); *pM = M = gmod(M, ellk); M = rowsplice(M, imin); l--; if (l == 1) return cgetg(1, t_VEC); M = ZM_hnfmodid(M, ellk); D = matsnf0(M, 4); lD = lg(D); if (lD > 1 && Z_pval(gel(D,1), ell) >= k) return NULL; return D; } /* [L:K] = ell^k; return 1 if L/K is locally cyclotomic at ell, 0 otherwise */ long rnfislocalcyclo(GEN rnf) { pari_sp av = avma; GEN K, L, S, SK, TK, SLs, SL2, TL, ell; ulong ll; long i, j, k, lk, lSK; checkrnf(rnf); lk = rnf_get_degree(rnf); if (lk == 1) return 1; k = uisprimepower(lk, &ll); if (!k) pari_err_IMPL("rnfislocalcyclo for non-l-extensions"); ell = utoi(ll); K = rnf_get_nf(rnf); L = rnf_build_nfabs(rnf, nf_get_prec(K)); S = rnfidealprimedec(rnf, ell); SK = gel(S,1); SLs = gel(S,2); SL2 = shallowconcat1(SLs); TK = padicfact(K, SK, 100); lSK = lg(SK); TL = padicfact(L, SL2, 100); for (i = 1; i < lSK; i++) { long eK = etilde(K, gel(SK,i), gel(TK,i)); GEN SL = gel(SLs,i); long lSL = lg(SL); for (j = 1; j < lSL; j++) { long iS = gen_search(SL2, gel(SL,j), 0, (void*)&cmp_prime_over_p, &cmp_nodata); long eL = etilde(L, gel(SL,j), gel(TL,iS)); if (dvdui(eL/eK, ell)) { avma = av; return 0; } } }; avma = av; return 1; } #if 0 /* Return 1 if L/Q is locally cyclotomic at ell */ static int islocalcycloQ(GEN L, GEN ell) { GEN SL = idealprimedec(L,ell), TL; long i, lSL = lg(SL); TL = padicfact(L, SL, 100); for (i = 1; i < lSL; i++) { long eL = etilde(L, gel(SL,i), gel(TL,i)); if (dvdui(eL,ell)) return 0; } return 1; } #endif /* true nf, pr a prid */ static long nfislocalpower_i(GEN nf, GEN pr, GEN a, GEN n) { long v, e, t; GEN p, G, L; a = nf_to_scalar_or_basis(nf,a); if (!signe(n)) return isint1(a); v = nfvalrem(nf, a, pr, &a); if (!dvdsi(v, n)) return 0; p = pr_get_p(pr); v = Z_pvalrem(n, p, &n); if (!equali1(n)) { GEN T, modpr = zk_to_Fq_init(nf, &pr, &T, &p); GEN ap = nf_to_Fq(nf, a, modpr); if (!Fq_ispower(ap, n, T, p)) return 0; } if (!v) return 1; e = pr_get_e(pr); if (v == 1) /* optimal formula */ t = itos( divii(mului(e,p), subiu(p,1)) ) + 1; else /* straight Hensel */ t = 2 * e * v + 1; G = Idealstarprk(nf, pr, t, nf_INIT); L = ideallog(nf, a, G); return (ZV_equal0(L) || ZV_pval(L, p) >= v); } long nfislocalpower(GEN nf, GEN pr, GEN a, GEN n) { pari_sp av = avma; long r; if (typ(n) != t_INT) pari_err_TYPE("nfislocalpower",n); nf = checknf(nf); checkprid(pr); r = nfislocalpower_i(nf, pr, a, n); avma = av; return r; } /* v_ell( exponent(D) ) */ static long ellexpo(GEN D, GEN ell) { return lg(D) == 1? 0: Z_pval(gel(D,1), ell); } static GEN ellsylow(GEN cyc, GEN ell) { long i, l; GEN d = cgetg_copy(cyc, &l); for (i = 1; i < l; i++) { GEN c = gel(cyc,i), a; if (!Z_pvalrem(c, ell, &a)) break; gel(d,i) = diviiexact(c, a); } setlg(d, i); return d; } static long vnorm_x(GEN nf, GEN x, GEN ell) { x = nf_to_scalar_or_alg(nf,x); if (typ(x) != t_POL) return 0; x = Q_primpart(x); return Q_pval(nfnorm(nf,x), ell); } static long vtilde_prec_x(GEN nf, GEN x, GEN ell) { long i, l, v; GEN G; if (typ(x) != t_MAT) return vnorm_x(nf,x,ell); G = gel(x,1); l = lg(G); v = 0; for (i = 1; i < l; i++) v = maxss(v, vnorm_x(nf,gel(G,i),ell)); return v; } /* upper bound for \delta(vec): estimate loss of accuracy when evaluating * \tilde{v} on the vec[i] */ static long vtilde_prec(GEN nf, GEN vec, GEN ell) { long v0 = 0, i, l = lg(vec); for (i = 1; i < l; i++) v0 = maxss(v0, vtilde_prec_x(nf, gel(vec,i), ell)); return 3 + v0 + z_pval(nf_get_degree(nf), ell); } static GEN bnflog_i(GEN bnf, GEN ell) { long prec0, prec; GEN nf, US, vdegS, S, T, M, CLp, CLt, Ftilde, vtG, ellk; GEN D, Ap, cycAp, bnfS; long i, j, lS, lvAp; checkbnf(bnf); nf = checknf(bnf); S = idealprimedec(nf, ell); bnfS = bnfsunit0(bnf, S, nf_GENMAT, LOWDEFAULTPREC); /* S-units */ US = leafcopy(gel(bnfS,1)); prec0 = maxss(30, vtilde_prec(nf, US, ell)); US = shallowconcat(bnf_get_fu(bnf), US); settyp(US, t_COL); T = padicfact(nf, S, prec0); lS = lg(S); Ftilde = cgetg(lS, t_VECSMALL); for (j = 1; j < lS; j++) Ftilde[j] = ftilde(nf, gel(S,j), gel(T,j)); CLp = CL_prime(bnf, ell, S); cycAp = gel(CLp,1); Ap = gel(CLp,2); for(;;) { CLt = CL_tilde(nf, US, ell, T, Ftilde, &vtG, prec0); if (CLt) break; prec0 <<= 1; T = padicfact(nf, S, prec0); } prec = ellexpo(cycAp, ell) + ellexpo(CLt,ell) + 1; if (prec == 1) return mkvec3(cgetg(1,t_VEC), cgetg(1,t_VEC), cgetg(1,t_VEC)); vdegS = get_vdegS(Ftilde, ell, prec0); ellk = powiu(ell, prec); lvAp = lg(Ap); if (lvAp > 1) { GEN Kcyc = bnf_get_cyc(bnf); GEN C = zeromatcopy(lvAp-1, lS-1); GEN Rell = gel(CLp,3), Uell = gel(CLp,4), ordS = gel(CLp,5); for (i = 1; i < lvAp; i++) { GEN a, b, bi, A = gel(Ap,i), d = gel(cycAp,i); bi = isprincipal(bnf, A); a = vecmodii(ZC_Z_mul(bi,d), Kcyc); /* a in subgroup generated by S = Rell; hence b integral */ b = hnf_invimage(Rell, a); b = vecmodii(ZM_ZC_mul(Uell, ZC_neg(b)), ordS); A = mkvec2(A, trivial_fact()); A = idealpowred(nf, A, d); /* find a principal representative of A_i^cycA_i up to elements of S */ a = isprincipalfact(bnf,gel(A,1),S,b,nf_GENMAT|nf_FORCE); if (!gequal0(gel(a,1))) pari_err_BUG("bnflog"); a = famat_mul_shallow(gel(A,2), gel(a,2)); /* principal part */ if (lg(a) == 1) continue; for (j = 1; j < lS; j++) gcoeff(C,i,j) = vtilde(nf, a, gel(T,j), gel(vdegS,j), ell, prec0); } C = gmod(gneg(C),ellk); C = shallowtrans(C); M = mkmat2(mkcol2(diagonal_shallow(cycAp), C), mkcol2(gen_0, vtG)); M = shallowmatconcat(M); /* relation matrix */ } else M = vtG; M = ZM_hnfmodid(M, ellk); D = matsnf0(M, 4); if (lg(D) == 1 || !dvdii(gel(D,1), ellk)) pari_err_BUG("bnflog [missing Z_l component]"); D = vecslice(D,2,lg(D)-1); return mkvec3(D, CLt, ellsylow(cycAp, ell)); } GEN bnflog(GEN bnf, GEN ell) { pari_sp av = avma; return gerepilecopy(av, bnflog_i(bnf, ell)); } GEN bnflogef(GEN nf, GEN pr) { pari_sp av = avma; long e, f, ef; GEN p; checkprid(pr); p = pr_get_p(pr); nf = checknf(nf); e = pr_get_e(pr); f = pr_get_f(pr); ef = e*f; if (u_pval(ef, p)) { GEN T = gel(factorpadic(nf_get_pol(nf), p, 100), 1); long j = get_ZpX_index(nf, pr, T); e = etilde(nf, pr, gel(T,j)); f = ef / e; } avma = av; return mkvec2s(e,f); } GEN bnflogdegree(GEN nf, GEN A, GEN ell) { pari_sp av = avma; GEN AZ, A0Z, NA0; long vAZ; if (typ(ell) != t_INT) pari_err_TYPE("bnflogdegree", ell); nf = checknf(nf); A = idealhnf(nf, A); AZ = gcoeff(A,1,1); vAZ = Z_pvalrem(AZ, ell, &A0Z); if (is_pm1(A0Z)) NA0 = gen_1; else (void)Z_pvalrem(idealnorm(nf,A), ell, &NA0); if (vAZ) { GEN Aell = ZM_hnfmodid(A, powiu(ell,vAZ)); GEN S = idealprimedec(nf, ell), T; long l, i, s = 0; T = padicfact(nf, S, 100); l = lg(S); for (i = 1; i < l; i++) { GEN P = gel(S,i); long v = idealval(nf, Aell, P); if (v) s += v * ftilde(nf, P, gel(T,i)); } if (s) NA0 = gmul(NA0, gpowgs(ell1(ell), s)); } return gerepileupto(av, NA0); } pari-2.11.2/src/basemath/volcano.c0000644000175000017500000005451713326135265015360 0ustar billbill/* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pari.h" #include "paripriv.h" /* FIXME: Implement {ascend,descend}_volcano() in terms of the "new" * volcano traversal functions at the bottom of the file. */ /* Is j = 0 or 1728 (mod p)? */ INLINE int is_j_exceptional(ulong j, ulong p) { return j == 0 || j == 1728 % p; } INLINE long node_degree(GEN phi, long L, ulong j, ulong p, ulong pi) { pari_sp av = avma; long n = Flx_nbroots(Flm_Fl_polmodular_evalx(phi, L, j, p, pi), p); avma = av; return n; } /* Given an array path = [j0, j1] of length 2, return the polynomial * * \Phi_L(X, j1) / (X - j0) * * where \Phi_L(X, Y) is the modular polynomial of level L. An error * is raised if X - j0 does not divide \Phi_L(X, j1) */ INLINE GEN nhbr_polynomial(ulong path[], GEN phi, ulong p, ulong pi, long L) { pari_sp ltop = avma; GEN modpol = Flm_Fl_polmodular_evalx(phi, L, path[0], p, pi); ulong rem; GEN nhbr_pol = Flx_div_by_X_x(modpol, path[-1], p, &rem); /* If disc End(path[0]) <= L^2, it's possible for path[0] to appear among the * roots of nhbr_pol. This should have been obviated by earlier choices */ if (rem) pari_err_BUG("nhbr_polynomial: invalid preceding j"); return gerepileupto(ltop, nhbr_pol); } /* Path is an array with space for at least max_len+1 * elements, whose first * and second elements are the beginning of the path. I.e., the path starts * (path[0], path[1]) * If the result is less than max_len, then the last element of path is on the * floor. If the result equals max_len, then it is unknown whether the last * element of path is on the floor or not */ static long extend_path(ulong path[], GEN phi, ulong p, ulong pi, long L, long max_len) { pari_sp av = avma; long d = 1; for ( ; d < max_len; d++) { GEN nhbr_pol = nhbr_polynomial(path + d, phi, p, pi, L); ulong nhbr = Flx_oneroot(nhbr_pol, p); avma = av; if (nhbr == p) break; /* no root: we are on the floor. */ path[d+1] = nhbr; } return d; } /* This is Sutherland 2009 Algorithm Ascend (p12) */ ulong ascend_volcano(GEN phi, ulong j, ulong p, ulong pi, long level, long L, long depth, long steps) { pari_sp ltop = avma, av; /* path will never hold more than max_len < depth elements */ GEN path_g = cgetg(depth + 2, t_VECSMALL); ulong *path = zv_to_ulongptr(path_g); long max_len = depth - level; int first_iter = 1; if (steps <= 0 || max_len < 0) pari_err_BUG("ascend_volcano: bad params"); av = avma; while (steps--) { GEN nhbr_pol = first_iter? Flm_Fl_polmodular_evalx(phi, L, j, p, pi) : nhbr_polynomial(path+1, phi, p, pi, L); GEN nhbrs = Flx_roots(nhbr_pol, p); long nhbrs_len = lg(nhbrs)-1, i; pari_sp btop = avma; path[0] = j; first_iter = 0; j = nhbrs[nhbrs_len]; for (i = 1; i < nhbrs_len; i++) { ulong next_j = nhbrs[i], last_j; long len; if (is_j_exceptional(next_j, p)) { /* Fouquet & Morain, Section 4.3, if j = 0 or 1728, then it is on the * surface. So we just return it. */ if (steps) pari_err_BUG("ascend_volcano: Got to the top with more steps to go!"); j = next_j; break; } path[1] = next_j; len = extend_path(path, phi, p, pi, L, max_len); last_j = path[len]; if (len == max_len /* Ended up on the surface */ && (is_j_exceptional(last_j, p) || node_degree(phi, L, last_j, p, pi) > 1)) { j = next_j; break; } avma = btop; } path[1] = j; /* For nhbr_polynomial() at the top. */ max_len++; avma = av; } avma = ltop; return j; } static void random_distinct_neighbours_of(ulong *nhbr1, ulong *nhbr2, GEN phi, ulong j, ulong p, ulong pi, long L, long must_have_two_neighbours) { pari_sp av = avma; GEN modpol = Flm_Fl_polmodular_evalx(phi, L, j, p, pi); ulong rem; *nhbr1 = Flx_oneroot(modpol, p); if (*nhbr1 == p) pari_err_BUG("random_distinct_neighbours_of [no neighbour]"); modpol = Flx_div_by_X_x(modpol, *nhbr1, p, &rem); *nhbr2 = Flx_oneroot(modpol, p); if (must_have_two_neighbours && *nhbr2 == p) pari_err_BUG("random_distinct_neighbours_of [single neighbour]"); avma = av; } /* * This is Sutherland 2009 Algorithm Descend (p12). */ ulong descend_volcano(GEN phi, ulong j, ulong p, ulong pi, long level, long L, long depth, long steps) { pari_sp ltop = avma; GEN path_g; ulong *path, res; long max_len; if (steps <= 0 || level + steps > depth) pari_err_BUG("descend_volcano"); max_len = depth - level; path_g = cgetg(max_len + 1 + 1, t_VECSMALL); path = zv_to_ulongptr(path_g); path[0] = j; /* level = 0 means we're on the volcano surface... */ if (!level) { /* Look for any path to the floor. One of j's first three neighbours leads * to the floor, since at most two neighbours are on the surface. */ GEN nhbrs = Flx_roots(Flm_Fl_polmodular_evalx(phi, L, j, p, pi), p); long i; for (i = 1; i <= 3; i++) { long len; path[1] = nhbrs[i]; len = extend_path(path, phi, p, pi, L, max_len); /* If nhbrs[i] took us to the floor: */ if (len < max_len || node_degree(phi, L, path[len], p, pi) == 1) break; } if (i > 3) pari_err_BUG("descend_volcano [2]"); } else { ulong nhbr1, nhbr2; long len; random_distinct_neighbours_of(&nhbr1, &nhbr2, phi, j, p, pi, L, 1); path[1] = nhbr1; len = extend_path(path, phi, p, pi, L, max_len); /* If last j isn't on the floor */ if (len == max_len /* Ended up on the surface. */ && (is_j_exceptional(path[len], p) || node_degree(phi, L, path[len], p, pi) != 1)) { /* The other neighbour leads to the floor */ path[1] = nhbr2; (void) extend_path(path, phi, p, pi, L, steps); } } res = path[steps]; avma = ltop; return res; } long j_level_in_volcano( GEN phi, ulong j, ulong p, ulong pi, long L, long depth) { pari_sp av = avma; GEN chunk; ulong *path1, *path2; long lvl; /* Fouquet & Morain, Section 4.3, if j = 0 or 1728 then it is on the * surface. Also, if the volcano depth is zero then j has level 0 */ if (depth == 0 || is_j_exceptional(j, p)) return 0; chunk = new_chunk(2 * (depth + 1)); path1 = (ulong *) &chunk[0]; path2 = (ulong *) &chunk[depth + 1]; path1[0] = path2[0] = j; random_distinct_neighbours_of(&path1[1], &path2[1], phi, j, p, pi, L, 0); if (path2[1] == p) lvl = depth; /* Only one neighbour => j is on the floor => level = depth */ else { long path1_len = extend_path(path1, phi, p, pi, L, depth); long path2_len = extend_path(path2, phi, p, pi, L, path1_len); lvl = depth - path2_len; } avma = av; return lvl; } #define vecsmall_len(v) (lg(v) - 1) INLINE GEN Flx_remove_root(GEN f, ulong a, ulong p) { ulong r; GEN g = Flx_div_by_X_x(f, a, p, &r); if (r) pari_err_BUG("Flx_remove_root"); return g; } INLINE GEN get_nbrs(GEN phi, long L, ulong J, const ulong *xJ, ulong p, ulong pi) { pari_sp av = avma; GEN f = Flm_Fl_polmodular_evalx(phi, L, J, p, pi); if (xJ) f = Flx_remove_root(f, *xJ, p); return gerepileupto(av, Flx_roots(f, p)); } /* Return a path of length n along the surface of an L-volcano of height h * starting from surface node j0. Assumes (D|L) = 1 where D = disc End(j0). * * Actually, if j0's endomorphism ring is a suborder, we return the * corresponding shorter path. W must hold space for n + h nodes. * * TODO: have two versions of this function: one that assumes J has the correct * endomorphism ring (hence avoiding several branches in the inner loop) and a * second that does not and accordingly checks for repetitions */ static long surface_path( ulong W[], long n, GEN phi, long L, long h, ulong J, const ulong *nJ, ulong p, ulong pi) { pari_sp av = avma, bv; GEN T, v; long j, k, w, x; ulong W0; W[0] = W0 = J; if (n == 1) return 1; T = cgetg(h+2, t_VEC); bv = avma; v = get_nbrs(phi, L, J, nJ, p, pi); /* Insert known neighbour first */ if (nJ) v = gerepileupto(bv, vecsmall_prepend(v, *nJ)); gel(T,1) = v; k = vecsmall_len(v); switch (k) { case 0: pari_err_BUG("surface_path"); /* We must always have neighbours */ case 1: /* If volcano is not flat, then we must have more than one neighbour */ if (h) pari_err_BUG("surface_path"); W[1] = uel(v, 1); avma = av; /* Check for bad endo ring */ if (W[1] == W[0]) return 1; return 2; case 2: /* If L=2 the only way we can have 2 neighbours is if we have a double root * which can only happen for |D| <= 16 (Thm 2.2 of Fouquet-Morain) * and if it does we must have a 2-cycle. Happens for D=-15. */ if (L == 2) { /* The double root is the neighbour on the surface, with exactly one * neighbour other than J; the other neighbour of J has either 0 or 2 * neighbours that are not J */ GEN u = get_nbrs(phi, L, uel(v, 1), &J, p, pi); long n = vecsmall_len(u) - !!vecsmall_isin(u, J); W[1] = n == 1 ? uel(v,1) : uel(v,2); avma = av; return 2; } /* Volcano is not flat but found only 2 neighbours for the surface node J */ if (h) pari_err_BUG("surface_path"); W[1] = uel(v,1); /* TODO: Can we use the other root uel(v,2) somehow? */ for (w = 2; w < n; w++) { v = get_nbrs(phi, L, W[w-1], &W[w-2], p, pi); /* A flat volcano must have exactly one non-previous neighbour */ if (vecsmall_len(v) != 1) pari_err_BUG("surface_path"); W[w] = uel(v, 1); /* Detect cycle in case J doesn't have the right endo ring. */ avma = av; if (W[w] == W0) return w; } avma = av; return n; } if (!h) pari_err_BUG("surface_path"); /* Can't have a flat volcano if k > 2 */ /* At this point, each surface node has L+1 distinct neighbours, 2 of which * are on the surface */ w = 1; for (x = 0;; x++) { /* Get next neighbour of last known surface node to attempt to * extend the path. */ W[w] = umael(T, ((w-1) % h) + 1, x + 1); /* Detect cycle in case the given J didn't have the right endo ring */ if (W[w] == W0) { avma = av; return w; } /* If we have to test the last neighbour, we know it's on the * surface, and if we're done there's no need to extend. */ if (x == k-1 && w == n-1) { avma = av; return n; } /* Walk forward until we hit the floor or finish. */ /* NB: We don't keep the stack clean here; usage is in the order of Lh, * i.e. L roots for each level of the volcano of height h. */ for (j = w;;) { long m; /* We must get 0 or L neighbours here. */ v = get_nbrs(phi, L, W[j], &W[j-1], p, pi); m = vecsmall_len(v); if (!m) { /* We hit the floor: save the neighbours of W[w-1] and dump the rest */ GEN nbrs = gel(T, ((w-1) % h) + 1); gel(T, ((w-1) % h) + 1) = gerepileupto(bv, nbrs); break; } if (m != L) pari_err_BUG("surface_path"); gel(T, (j % h) + 1) = v; W[++j] = uel(v, 1); /* If we have our path by h nodes, we know W[w] is on the surface */ if (j == w + h) { ++w; /* Detect cycle in case the given J didn't have the right endo ring */ if (W[w] == W0) { avma = av; return w; } x = 0; k = L; } if (w == n) { avma = av; return w; } } } } long next_surface_nbr( ulong *nJ, GEN phi, long L, long h, ulong J, const ulong *pJ, ulong p, ulong pi) { pari_sp av = avma, bv; GEN S; ulong *P; long i, k; S = get_nbrs(phi, L, J, pJ, p, pi); k = vecsmall_len(S); /* If there is a double root and pJ is set, then k will be zero. */ if (!k) { avma = av; return 0; } if (k == 1 || ( ! pJ && k == 2)) { *nJ = uel(S, 1); avma = av; return 1; } if (!h) pari_err_BUG("next_surface_nbr"); P = (ulong *) new_chunk(h + 1); bv = avma; P[0] = J; for (i = 0; i < k; i++) { long j; P[1] = uel(S, i + 1); for (j = 1; j <= h; j++) { GEN T = get_nbrs(phi, L, P[j], &P[j - 1], p, pi); if (!vecsmall_len(T)) break; P[j + 1] = uel(T, 1); } if (j < h) pari_err_BUG("next_surface_nbr"); avma = bv; if (j > h) break; } /* TODO: We could save one get_nbrs call by iterating from i up to k-1 and * assume that the last (kth) nbr is the one we want. For now we're careful * and check that this last nbr really is on the surface */ if (i == k) pari_err_BUG("next_surf_nbr"); *nJ = uel(S, i+1); avma = av; return 1; } /* Return the number of distinct neighbours (1 or 2) */ INLINE long common_nbr(ulong *nbr, ulong J1, GEN Phi1, long L1, ulong J2, GEN Phi2, long L2, ulong p, ulong pi) { pari_sp av = avma; GEN d, f, g, r; long rlen; g = Flm_Fl_polmodular_evalx(Phi1, L1, J1, p, pi); f = Flm_Fl_polmodular_evalx(Phi2, L2, J2, p, pi); d = Flx_gcd(f, g, p); if (degpol(d) == 1) { *nbr = Flx_deg1_root(d, p); avma = av; return 1; } if (degpol(d) != 2) pari_err_BUG("common_neighbour"); r = Flx_roots(d, p); rlen = vecsmall_len(r); if (!rlen) pari_err_BUG("common_neighbour"); /* rlen is 1 or 2 depending on whether the root is unique or not. */ nbr[0] = uel(r, 1); nbr[1] = uel(r, rlen); avma = av; return rlen; } /* Return gcd(Phi1(X,J1)/(X - J0), Phi2(X,J2)). Not stack clean. */ INLINE GEN common_nbr_pred_poly( ulong J1, GEN Phi1, long L1, ulong J2, GEN Phi2, long L2, ulong J0, ulong p, ulong pi) { GEN f, g; g = Flm_Fl_polmodular_evalx(Phi1, L1, J1, p, pi); g = Flx_remove_root(g, J0, p); f = Flm_Fl_polmodular_evalx(Phi2, L2, J2, p, pi); return Flx_gcd(f, g, p); } /* Find common neighbour of J1 and J2, where J0 is an L1 predecessor of J1. * Return 1 if successful, 0 if not. */ INLINE int common_nbr_pred(ulong *nbr, ulong J1, GEN Phi1, long L1, ulong J2, GEN Phi2, long L2, ulong J0, ulong p, ulong pi) { pari_sp av = avma; GEN d = common_nbr_pred_poly(J1, Phi1, L1, J2, Phi2, L2, J0, p, pi); int res = (degpol(d) == 1); if (res) *nbr = Flx_deg1_root(d, p); avma = av; return res; } INLINE long common_nbr_verify(ulong *nbr, ulong J1, GEN Phi1, long L1, ulong J2, GEN Phi2, long L2, ulong J0, ulong p, ulong pi) { pari_sp av = avma; GEN d = common_nbr_pred_poly(J1, Phi1, L1, J2, Phi2, L2, J0, p, pi); if (!degpol(d)) { avma = av; return 0; } if (degpol(d) > 1) pari_err_BUG("common_neighbour_verify"); *nbr = Flx_deg1_root(d, p); avma = av; return 1; } INLINE ulong Flm_Fl_polmodular_evalxy(GEN Phi, long L, ulong x, ulong y, ulong p, ulong pi) { pari_sp av = avma; GEN f = Flm_Fl_polmodular_evalx(Phi, L, x, p, pi); ulong r = Flx_eval_pre(f, y, p, pi); avma = av; return r; } /* Find a common L1-neighbor of J1 and L2-neighbor of J2, given J0 an * L2-neighbor of J1 and an L1-neighbor of J2. Return 1 if successful, 0 * otherwise. Will only fail if initial J-invariant had the wrong endo ring */ INLINE int common_nbr_corner(ulong *nbr, ulong J1, GEN Phi1, long L1, long h1, ulong J2, GEN Phi2, long L2, ulong J0, ulong p, ulong pi) { ulong nbrs[2]; if (common_nbr(nbrs, J1,Phi1,L1, J2,Phi2,L2, p, pi) == 2) { ulong nJ1, nJ2; if (!next_surface_nbr(&nJ2, Phi1, L1, h1, J2, &J0, p, pi) || !next_surface_nbr(&nJ1, Phi1, L1, h1, nbrs[0], &J1, p, pi)) return 0; if (Flm_Fl_polmodular_evalxy(Phi2, L2, nJ1, nJ2, p, pi)) nbrs[0] = nbrs[1]; else if (!next_surface_nbr(&nJ1, Phi1, L1, h1, nbrs[1], &J1, p, pi) || !Flm_Fl_polmodular_evalxy(Phi2, L2, nJ1, nJ2, p, pi)) return 0; } *nbr = nbrs[0]; return 1; } /* Enumerate a surface L1-cycle using gcds with Phi_L2, where c_L2=c_L1^e and * |c_L1|=n, where c_a is the class of the pos def reduced primeform . * Assumes n > e > 1 and roots[0],...,roots[e-1] are already present in W */ static long surface_gcd_cycle( ulong W[], ulong V[], long n, GEN Phi1, long L1, GEN Phi2, long L2, long e, ulong p, ulong pi) { pari_sp av = avma; long i1, i2, j1, j2; i1 = j2 = 0; i2 = j1 = e - 1; /* If W != V we assume V actually points to an L2-isogenous parallel L1-path. * e should be 2 in this case */ if (W != V) { i1 = j1+1; i2 = n-1; } do { ulong t0, t1, t2, h10, h11, h20, h21; long k; GEN f, g, h1, h2; f = Flm_Fl_polmodular_evalx(Phi2, L2, V[i1], p, pi); g = Flm_Fl_polmodular_evalx(Phi1, L1, W[j1], p, pi); g = Flx_remove_root(g, W[j1 - 1], p); h1 = Flx_gcd(f, g, p); if (degpol(h1) != 1) break; /* Error */ h11 = Flx_coeff(h1, 1); h10 = Flx_coeff(h1, 0); avma = av; f = Flm_Fl_polmodular_evalx(Phi2, L2, V[i2], p, pi); g = Flm_Fl_polmodular_evalx(Phi1, L1, W[j2], p, pi); k = j2 + 1; if (k == n) k = 0; g = Flx_remove_root(g, W[k], p); h2 = Flx_gcd(f, g, p); if (degpol(h2) != 1) break; /* Error */ h21 = Flx_coeff(h2, 1); h20 = Flx_coeff(h2, 0); avma = av; i1++; i2--; if (i2 < 0) i2 = n-1; j1++; j2--; if (j2 < 0) j2 = n-1; t0 = Fl_mul_pre(h11, h21, p, pi); t1 = Fl_inv(t0, p); t0 = Fl_mul_pre(t1, h21, p, pi); t2 = Fl_mul_pre(t0, h10, p, pi); W[j1] = Fl_neg(t2, p); t0 = Fl_mul_pre(t1, h11, p, pi); t2 = Fl_mul_pre(t0, h20, p, pi); W[j2] = Fl_neg(t2, p); } while (j2 > j1 + 1); /* Usually the loop exits when j2 = j1 + 1, in which case we return n. * If we break early because of an error, then (j2 - (j1+1)) > 0 is the * number of elements we haven't calculated yet, and we return n minus that * quantity */ avma = av; return n - j2 + (j1 + 1); } static long surface_gcd_path( ulong W[], ulong V[], long n, GEN Phi1, long L1, GEN Phi2, long L2, long e, ulong p, ulong pi) { pari_sp av = avma; long i, j; i = 0; j = e; /* If W != V then assume V actually points to a L2-isogenous * parallel L1-path. e should be 2 in this case */ if (W != V) i = j; while (j < n) { GEN f, g, d; f = Flm_Fl_polmodular_evalx(Phi2, L2, V[i], p, pi); g = Flm_Fl_polmodular_evalx(Phi1, L1, W[j - 1], p, pi); g = Flx_remove_root(g, W[j - 2], p); d = Flx_gcd(f, g, p); if (degpol(d) != 1) break; /* Error */ W[j] = Flx_deg1_root(d, p); i++; j++; avma = av; } avma = av; return j; } /* Given a path V of length n on an L1-volcano, and W[0] L2-isogenous to V[0], * extends the path W to length n on an L1-volcano, with W[i] L2-isogenous * to V[i]. Uses gcds unless L2 is too large to make it helpful. Always uses * GCD to get W[1] to ensure consistent orientation. * * Returns the new length of W. This will almost always be n, but could be * lower if V was started with a J-invariant with bad endomorphism ring */ INLINE long surface_parallel_path( ulong W[], ulong V[], long n, GEN Phi1, long L1, GEN Phi2, long L2, ulong p, ulong pi, long cycle) { ulong W2, nbrs[2]; if (common_nbr(nbrs, W[0], Phi1, L1, V[1], Phi2, L2, p, pi) == 2) { if (n <= 2) return 1; /* Error: Two choices with n = 2; ambiguous */ if (!common_nbr_verify(&W2,nbrs[0], Phi1,L1,V[2], Phi2,L2,W[0], p,pi)) nbrs[0] = nbrs[1]; /* nbrs[1] must be the correct choice */ else if (common_nbr_verify(&W2,nbrs[1], Phi1,L1,V[2], Phi2,L2,W[0], p,pi)) return 1; /* Error: Both paths extend successfully */ } W[1] = nbrs[0]; if (n <= 2) return n; return cycle? surface_gcd_cycle(W, V, n, Phi1, L1, Phi2, L2, 2, p, pi) : surface_gcd_path (W, V, n, Phi1, L1, Phi2, L2, 2, p, pi); } GEN enum_roots(ulong J0, norm_eqn_t ne, GEN fdb, classgp_pcp_t G) { /* MAX_HEIGHT >= max_{p,n} val_p(n) where p and n are ulongs */ enum { MAX_HEIGHT = BITS_IN_LONG }; pari_sp av, ltop = avma; long s = !!G->L0; long *n = G->n + s, *L = G->L + s, *o = G->o + s, k = G->k - s; long i, t, vlen, *e, *h, *off, *poff, *M, N = G->enum_cnt; ulong p = ne->p, pi = ne->pi, *roots; GEN Phi, vshape, vp, ve, roots_; if (!k) return mkvecsmall(J0); roots_ = cgetg(N + MAX_HEIGHT, t_VECSMALL); roots = zv_to_ulongptr(roots_); av = avma; /* TODO: Shouldn't be factoring this every time. Store in *ne? */ vshape = factoru(ne->v); vp = gel(vshape, 1); ve = gel(vshape, 2); vlen = vecsmall_len(vp); Phi = new_chunk(k); e = new_chunk(k); off = new_chunk(k); poff = new_chunk(k); /* TODO: Surely we can work these out ahead of time? */ /* h[i] is the valuation of p[i] in v */ h = new_chunk(k); for (i = 0; i < k; ++i) { h[i] = 0; for (t = 1; t <= vlen; ++t) if (vp[t] == L[i]) { h[i] = uel(ve, t); break; } e[i] = 0; off[i] = 0; gel(Phi, i) = polmodular_db_getp(fdb, L[i], p); } M = new_chunk(k); for (M[0] = 1, i = 1; i < k; ++i) M[i] = M[i-1] * n[i-1]; t = surface_path(roots, n[0], gel(Phi, 0), L[0], h[0], J0, NULL, p, pi); /* Error: J0 has bad endo ring */ if (t < n[0]) { avma = ltop; return NULL; } if (k == 1) { avma = av; setlg(roots_, t + 1); return roots_; } i = 1; while (i < k) { long j, t0; for (j = i + 1; j < k && ! e[j]; ++j); if (j < k) { if (e[i]) { if (! common_nbr_pred( &roots[t], roots[off[i]], gel(Phi,i), L[i], roots[t - M[j]], gel(Phi, j), L[j], roots[poff[i]], p, pi)) { break; /* Error: J0 has bad endo ring */ } } else if ( ! common_nbr_corner( &roots[t], roots[off[i]], gel(Phi,i), L[i], h[i], roots[t - M[j]], gel(Phi, j), L[j], roots[poff[j]], p, pi)) { break; /* Error: J0 has bad endo ring */ } } else if ( ! next_surface_nbr( &roots[t], gel(Phi,i), L[i], h[i], roots[off[i]], e[i] ? &roots[poff[i]] : NULL, p, pi)) break; /* Error: J0 has bad endo ring */ if (roots[t] == roots[0]) break; /* Error: J0 has bad endo ring */ poff[i] = off[i]; off[i] = t; e[i]++; for (j = i-1; j; --j) { e[j] = 0; off[j] = off[j+1]; } t0 = surface_parallel_path(&roots[t], &roots[poff[i]], n[0], gel(Phi, 0), L[0], gel(Phi, i), L[i], p, pi, n[0] == o[0]); if (t0 < n[0]) break; /* Error: J0 has bad endo ring */ /* TODO: Do I need to check if any of the new roots is a repeat in * the case where J0 has bad endo ring? */ t += n[0]; for (i = 1; i < k && e[i] == n[i]-1; i++); } /* Check if J0 had wrong endo ring */ if (t != N) { avma = ltop; return NULL; } avma = av; setlg(roots_, t + 1); return roots_; } pari-2.11.2/src/basemath/aprcl.c0000644000175000017500000007725713326135265015026 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*******************************************************************/ /* THE APRCL PRIMALITY TEST */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" typedef struct Red { /* global data */ GEN N; /* prime we are certifying */ GEN N2; /* floor(N/2) */ /* global data for flexible window */ long k, lv; ulong mask; /* reduction data */ long n; GEN C; /* polcyclo(n) */ GEN (*red)(GEN x, struct Red*); } Red; #define cache_aall(C) (gel((C),1)) #define cache_tall(C) (gel((C),2)) #define cache_cyc(C) (gel((C),3)) #define cache_E(C) (gel((C),4)) #define cache_eta(C) (gel((C),5)) #define cache_matvite(C) (gel((C),6)) #define cache_matinvvite(C) (gel((C),7)) #define cache_avite(C) (gel((C),8)) #define cache_pkvite(C) (gel((C),9)) static GEN makepoldeg1(GEN c, GEN d) { GEN z; if (signe(c)) { z = cgetg(4,t_POL); z[1] = evalsigne(1); gel(z,2) = d; gel(z,3) = c; } else if (signe(d)) { z = cgetg(3,t_POL); z[1] = evalsigne(1); gel(z,2) = d; } else { z = cgetg(2,t_POL); z[1] = evalsigne(0); } return z; } /* T mod polcyclo(p), assume deg(T) < 2p */ static GEN red_cyclop(GEN T, long p) { long i, d; GEN y, z; d = degpol(T) - p; /* < p */ if (d <= -2) return T; /* reduce mod (x^p - 1) */ y = ZX_mod_Xnm1(T, p); z = y+2; /* reduce mod x^(p-1) + ... + 1 */ d = p-1; if (degpol(y) == d) for (i=0; ipow2; i--) x[i-pow2] -= x[i]; for (; i>0; i--) if (x[i]) break; i += 2; z = cgetg(i, t_POL); z[1] = evalsigne(1); for (i--; i>=2; i--) gel(z,i) = stoi(x[i-1]); return z; } /* x t_POL, n > 0. Return x mod polcyclo(2^n) = (x^(2^(n-1)) + 1). IN PLACE */ static GEN red_cyclo2n_ip(GEN x, long n) { long i, pow2 = 1L<<(n-1); for (i = lg(x)-1; i>pow2+1; i--) if (signe(gel(x,i))) gel(x,i-pow2) = subii(gel(x,i-pow2), gel(x,i)); return normalizepol_lg(x, i+1); } static GEN red_cyclo2n(GEN x, long n) { return red_cyclo2n_ip(leafcopy(x), n); } /* x a non-zero VECSMALL */ static GEN smallpolrev(GEN x) { long i,j, lx = lg(x); GEN y; while (lx-- && x[lx]==0) /* empty */; i = lx+2; y = cgetg(i,t_POL); y[1] = evalsigne(1); for (j=2; jC = polcyclo(2^n) */ static GEN _red_cyclo2n(GEN x, Red *R) { return centermod_i(red_cyclo2n(x, R->n), R->N, R->N2); } /* special case R->C = polcyclo(p) */ static GEN _red_cyclop(GEN x, Red *R) { return centermod_i(red_cyclop(x, R->n), R->N, R->N2); } static GEN _red(GEN x, Red *R) { return centermod_i(grem(x, R->C), R->N, R->N2); } static GEN _redsimple(GEN x, Red *R) { return centermodii(x, R->N, R->N2); } static GEN sqrmod(GEN x, Red *R) { return R->red(gsqr(x), R); } static GEN sqrconst(GEN pol, Red *R) { GEN z = cgetg(3,t_POL); gel(z,2) = centermodii(sqri(gel(pol,2)), R->N, R->N2); z[1] = pol[1]; return z; } /* pol^2 mod (x^2+x+1, N) */ static GEN sqrmod3(GEN pol, Red *R) { GEN a,b,bma,A,B; long lv = lg(pol); if (lv==2) return pol; if (lv==3) return sqrconst(pol, R); a = gel(pol,3); b = gel(pol,2); bma = subii(b,a); A = centermodii(mulii(a,addii(b,bma)), R->N, R->N2); B = centermodii(mulii(bma,addii(a,b)), R->N, R->N2); return makepoldeg1(A,B); } /* pol^2 mod (x^2+1,N) */ static GEN sqrmod4(GEN pol, Red *R) { GEN a,b,A,B; long lv = lg(pol); if (lv==2) return pol; if (lv==3) return sqrconst(pol, R); a = gel(pol,3); b = gel(pol,2); A = centermodii(mulii(a, shifti(b,1)), R->N, R->N2); B = centermodii(mulii(subii(b,a),addii(b,a)), R->N, R->N2); return makepoldeg1(A,B); } /* pol^2 mod (polcyclo(5),N) */ static GEN sqrmod5(GEN pol, Red *R) { GEN c2,b,c,d,A,B,C,D; long lv = lg(pol); if (lv==2) return pol; if (lv==3) return sqrconst(pol, R); c = gel(pol,3); c2 = shifti(c,1); d = gel(pol,2); if (lv==4) { A = sqri(d); B = mulii(c2, d); C = sqri(c); A = centermodii(A, R->N, R->N2); B = centermodii(B, R->N, R->N2); C = centermodii(C, R->N, R->N2); return mkpoln(3,A,B,C); } b = gel(pol,4); if (lv==5) { A = mulii(b, subii(c2,b)); B = addii(sqri(c), mulii(b, subii(shifti(d,1),b))); C = subii(mulii(c2,d), sqri(b)); D = mulii(subii(d,b), addii(d,b)); } else { /* lv == 6 */ GEN a = gel(pol,5), a2 = shifti(a,1); /* 2a(d - c) + b(2c - b) */ A = addii(mulii(a2, subii(d,c)), mulii(b, subii(c2,b))); /* c(c - 2a) + b(2d - b) */ B = addii(mulii(c, subii(c,a2)), mulii(b, subii(shifti(d,1),b))); /* (a-b)(a+b) + 2c(d - a) */ C = addii(mulii(subii(a,b),addii(a,b)), mulii(c2,subii(d,a))); /* 2a(b - c) + (d-b)(d+b) */ D = addii(mulii(a2, subii(b,c)), mulii(subii(d,b), addii(d,b))); } A = centermodii(A, R->N, R->N2); B = centermodii(B, R->N, R->N2); C = centermodii(C, R->N, R->N2); D = centermodii(D, R->N, R->N2); return mkpoln(4,A,B,C,D); } static GEN _mul(GEN x, GEN y, Red *R) { return R->red(gmul(x,y), R); } /* jac^floor(N/pk) mod (N, polcyclo(pk)), flexible window */ static GEN _powpolmod(GEN C, GEN jac, Red *R, GEN (*_sqr)(GEN, Red *)) { const GEN taba = cache_aall(C); const GEN tabt = cache_tall(C); const long efin = lg(taba)-1, lv = R->lv; GEN L, res = jac, pol2 = _sqr(res, R); long f; pari_sp av0 = avma, av; L = cgetg(lv+1, t_VEC); gel(L,1) = res; for (f=2; f<=lv; f++) gel(L,f) = _mul(gel(L,f-1), pol2, R); av = avma; for (f = efin; f >= 1; f--) { GEN t = gel(L, taba[f]); long tf = tabt[f]; res = (f==efin)? t: _mul(t, res, R); while (tf--) { res = _sqr(res, R); if (gc_needed(av,1)) { res = gerepilecopy(av, res); if(DEBUGMEM>1) pari_warn(warnmem,"powpolmod: f = %ld",f); } } } return gerepilecopy(av0, res); } static GEN _powpolmodsimple(GEN C, Red *R, GEN jac) { pari_sp av = avma; GEN w = ZM_ZX_mul(cache_matvite(C), jac); long j, ph = lg(w); R->red = &_redsimple; for (j=1; jN, R->N2), R, &sqrmod); w = centermod_i( gmul(cache_matinvvite(C), w), R->N, R->N2 ); w = gerepileupto(av, w); return RgV_to_RgX(w, 0); } static GEN powpolmod(GEN C, Red *R, long p, long k, GEN jac) { GEN (*_sqr)(GEN, Red *); if (!isintzero(cache_matvite(C))) return _powpolmodsimple(C, R, jac); if (p == 2) /* p = 2 */ { if (k == 2) _sqr = &sqrmod4; else _sqr = &sqrmod; R->n = k; R->red = &_red_cyclo2n; } else if (k == 1) { if (p == 3) _sqr = &sqrmod3; else if (p == 5) _sqr = &sqrmod5; else _sqr = &sqrmod; R->n = p; R->red = &_red_cyclop; } else { R->red = &_red; _sqr = &sqrmod; } return _powpolmod(C, jac, R, _sqr); } /* Return e(t) = \prod_{p-1 | t} p^{1+v_p(t)}} * faet contains the odd prime divisors of e(t) */ static GEN compute_e(ulong t, GEN *faet) { GEN L, P, D = divisorsu(t); long l = lg(D); ulong k; P = vecsmalltrunc_init(l); L = vecsmalltrunc_init(l); for (k=l-1; k>1; k--) /* k != 1: avoid d = 1 */ { ulong d = D[k]; if (uisprime(++d)) { /* we want q = 1 (mod p) prime, not too large */ #ifdef LONG_IS_64BIT if (d > 5000000000UL) return gen_0; #endif vecsmalltrunc_append(P, d); vecsmalltrunc_append(L, upowuu(d, 1 + u_lval(t,d))); } } if (faet) *faet = P; return shifti(zv_prod_Z(L), 2 + u_lval(t,2)); } /* Table obtained by the following script: install(compute_e, "LD&"); \\ remove 'static' first table(first = 6, step = 6, MAXT = 6983776800)= { emax = 0; forstep(t = first, MAXT, step, e = compute_e(t); if (e > 1.9*emax, emax = e; printf(" if (C < %7.2f) return %8d;\n", 2*log(e)/log(2) - 1e-2, t) ); ); } table(,, 147026880); table(147026880,5040, 6983776800); */ /* assume C < 20003.8 */ static ulong compute_t_small(double C) { if (C < 17.94) return 6; if (C < 31.99) return 12; if (C < 33.99) return 24; if (C < 54.07) return 36; if (C < 65.32) return 60; if (C < 68.45) return 72; if (C < 70.78) return 108; if (C < 78.04) return 120; if (C < 102.41) return 180; if (C < 127.50) return 360; if (C < 136.68) return 420; if (C < 153.44) return 540; if (C < 165.67) return 840; if (C < 169.18) return 1008; if (C < 178.53) return 1080; if (C < 192.69) return 1200; if (C < 206.35) return 1260; if (C < 211.96) return 1620; if (C < 222.10) return 1680; if (C < 225.12) return 2016; if (C < 244.20) return 2160; if (C < 270.31) return 2520; if (C < 279.52) return 3360; if (C < 293.64) return 3780; if (C < 346.70) return 5040; if (C < 348.73) return 6480; if (C < 383.37) return 7560; if (C < 396.71) return 8400; if (C < 426.08) return 10080; if (C < 458.38) return 12600; if (C < 527.20) return 15120; if (C < 595.43) return 25200; if (C < 636.34) return 30240; if (C < 672.58) return 42840; if (C < 684.96) return 45360; if (C < 708.84) return 55440; if (C < 771.37) return 60480; if (C < 775.93) return 75600; if (C < 859.69) return 85680; if (C < 893.24) return 100800; if (C < 912.35) return 110880; if (C < 966.22) return 128520; if (C < 1009.18) return 131040; if (C < 1042.04) return 166320; if (C < 1124.98) return 196560; if (C < 1251.09) return 257040; if (C < 1375.13) return 332640; if (C < 1431.11) return 393120; if (C < 1483.46) return 514080; if (C < 1546.46) return 655200; if (C < 1585.94) return 665280; if (C < 1661.44) return 786240; if (C < 1667.67) return 831600; if (C < 1677.07) return 917280; if (C < 1728.17) return 982800; if (C < 1747.57) return 1081080; if (C < 1773.76) return 1179360; if (C < 1810.81) return 1285200; if (C < 1924.66) return 1310400; if (C < 2001.27) return 1441440; if (C < 2096.51) return 1663200; if (C < 2166.02) return 1965600; if (C < 2321.86) return 2162160; if (C < 2368.45) return 2751840; if (C < 2377.39) return 2827440; if (C < 2514.97) return 3326400; if (C < 2588.72) return 3341520; if (C < 2636.84) return 3603600; if (C < 2667.46) return 3931200; if (C < 3028.92) return 4324320; if (C < 3045.76) return 5654880; if (C < 3080.78) return 6652800; if (C < 3121.88) return 6683040; if (C < 3283.38) return 7207200; if (C < 3514.94) return 8648640; if (C < 3725.71) return 10810800; if (C < 3817.49) return 12972960; if (C < 3976.57) return 14414400; if (C < 3980.72) return 18378360; if (C < 4761.70) return 21621600; if (C < 5067.62) return 36756720; if (C < 5657.30) return 43243200; if (C < 5959.24) return 64864800; if (C < 6423.60) return 73513440; if (C < 6497.01) return 86486400; if (C < 6529.89) return 113097600; if (C < 6899.19) return 122522400; if (C < 7094.26) return 129729600; if (C < 7494.60) return 147026880; if (C < 7606.21) return 172972800; if (C < 7785.10) return 183783600; if (C < 7803.68) return 216216000; if (C < 8024.18) return 220540320; if (C < 8278.12) return 245044800; if (C < 8316.48) return 273873600; if (C < 8544.02) return 294053760; if (C < 8634.14) return 302702400; if (C < 9977.69) return 367567200; if (C < 10053.06) return 514594080; if (C < 10184.29) return 551350800; if (C < 11798.33) return 735134400; if (C < 11812.60) return 821620800; if (C < 11935.31) return 1029188160; if (C < 12017.99) return 1074427200; if (C < 12723.99) return 1102701600; if (C < 13702.71) return 1470268800; if (C < 13748.76) return 1643241600; if (C < 13977.37) return 2058376320; if (C < 14096.03) return 2148854400UL; if (C < 15082.25) return 2205403200UL; if (C < 15344.18) return 2572970400UL; if (C < 15718.37) return 2940537600UL; if (C < 15868.65) return 3491888400UL; if (C < 15919.88) return 3675672000UL; if (C < 16217.23) return 4108104000UL; #ifdef LONG_IS_64BIT if (C < 17510.32) return 4410806400UL; if (C < 18312.87) return 5145940800UL; return 6983776800UL; #else pari_err_IMPL("APRCL for large numbers on 32bit arch"); return 0; #endif } /* return t such that e(t) > sqrt(N), set *faet = odd prime divisors of e(t) */ static ulong compute_t(GEN N, GEN *e, GEN *faet) { /* 2^e b <= N < 2^e (b+1), where b >= 2^52. Approximating log_2 N by * log2(gtodouble(N)) ~ e+log2(b), the error is less than log(1+1/b) < 1e-15*/ double C = dbllog2(N) + 1e-10; /* > log_2 N at least for N < 2^(2^21) */ ulong t; /* Return "smallest" t such that f(t) >= C, which implies e(t) > sqrt(N) */ /* For N < 2^20003.8 ~ 5.5 10^6021 */ if (C < 20003.8) { t = compute_t_small(C); *e = compute_e(t, faet); } else { #ifdef LONG_IS_64BIT GEN B = sqrti(N); for (t = 6983776800UL+5040UL;; t+=5040) { pari_sp av = avma; *e = compute_e(t, faet); if (cmpii(*e, B) > 0) break; avma = av; } #else *e = NULL; /* LCOV_EXCL_LINE */ t = 0; /* LCOV_EXCL_LINE */ #endif } return t; } /* T[i] = discrete log of i in (Z/q)^*, q odd prime * To save on memory, compute half the table: T[q-x] = T[x] + (q-1)/2 */ static GEN computetabdl(ulong q) { ulong g, a, i, qs2 = q>>1; /* (q-1)/2 */ GEN T = cgetg(qs2+2,t_VECSMALL); g = pgener_Fl(q); a = 1; for (i=1; i < qs2; i++) /* g^((q-1)/2) = -1 */ { a = Fl_mul(g,a,q); if (a > qs2) T[q-a] = i+qs2; else T[a] = i; } T[qs2+1] = T[qs2] + qs2; T[1] = 0; return T; } /* Return T: T[x] = dl of x(1-x) */ static GEN compute_g(ulong q) { const ulong qs2 = q>>1; /* (q-1)/2 */ ulong x, a; GEN T = computetabdl(q); /* updated in place to save on memory */ a = 0; /* dl[1] */ for (x=2; x<=qs2+1; x++) { /* a = dl(x) */ ulong b = T[x]; /* = dl(x) */ T[x] = b + a + qs2; /* dl(x) + dl(x-1) + dl(-1) */ a = b; } return T; } /* p odd prime */ static GEN get_jac(GEN C, ulong q, long pk, GEN tabg) { ulong x, qs2 = q>>1; /* (q-1)/2 */ GEN vpk = zero_zv(pk); for (x=2; x<=qs2; x++) vpk[ tabg[x]%pk + 1 ] += 2; vpk[ tabg[x]%pk + 1 ]++; /* x = (q+1)/2 */ return u_red(vpk, cache_cyc(C)); } /* p = 2 */ static GEN get_jac2(GEN N, ulong q, long k, GEN *j2q, GEN *j3q) { GEN jpq, vpk, T = computetabdl(q); ulong x, pk, i, qs2; /* could store T[x+1] + T[x] + qs2 (cf compute_g). * Recompute instead, saving half the memory. */ pk = 1UL << k;; vpk = zero_zv(pk); qs2 = q>>1; /* (q-1)/2 */ for (x=2; x<=qs2; x++) vpk[ (T[x]+T[x-1]+qs2)%pk + 1 ] += 2; vpk[ (T[x]+T[x-1]+qs2)%pk + 1 ]++; jpq = u_red_cyclo2n_ip(vpk, k); if (k == 2) return jpq; if (mod8(N) >= 5) { GEN v8 = cgetg(9,t_VECSMALL); for (x=1; x<=8; x++) v8[x] = 0; for (x=2; x<=qs2; x++) v8[ ((3*T[x]+T[x-1]+qs2)&7) + 1 ]++; for ( ; x<=q-1; x++) v8[ ((3*T[q-x]+T[q-x+1]-3*qs2)&7) + 1 ]++; *j2q = RgX_inflate(ZX_sqr(u_red_cyclo2n_ip(v8,3)), pk>>3); *j2q = red_cyclo2n_ip(*j2q, k); } for (i=1; i<=pk; i++) vpk[i] = 0; for (x=2; x<=qs2; x++) vpk[ (2*T[x]+T[x-1]+qs2)%pk + 1 ]++; for ( ; x<=q-1; x++) vpk[ (2*T[q-x]+T[q-x+1]-2*qs2)%pk + 1 ]++; *j3q = ZX_mul(jpq, u_red_cyclo2n_ip(vpk,k)); *j3q = red_cyclo2n_ip(*j3q, k); return jpq; } /* N = 1 mod p^k, return an elt of order p^k in (Z/N)^* */ static GEN finda(GEN Cp, GEN N, long pk, long p) { GEN a, pv; if (Cp && !isintzero(cache_avite(Cp))) { a = cache_avite(Cp); pv = cache_pkvite(Cp); } else { GEN ph, b, q; ulong u = 2; long v = Z_lvalrem(subiu(N,1), p, &q); ph = powuu(p, v-1); pv = muliu(ph, p); /* N - 1 = p^v q */ if (p > 2) { for (;;u++) { a = Fp_pow(utoipos(u), q, N); b = Fp_pow(a, ph, N); if (!gequal1(b)) break; } } else { while (krosi(u,N) >= 0) u++; a = Fp_pow(utoipos(u), q, N); b = Fp_pow(a, ph, N); } /* checking b^p = 1 mod N done economically in caller */ b = gcdii(subiu(b,1), N); if (!gequal1(b)) return NULL; if (Cp) { cache_avite(Cp) = a; /* a has order p^v */ cache_pkvite(Cp) = pv; } } return Fp_pow(a, divis(pv, pk), N); } /* return 0: N not a prime, 1: no problem so far */ static long filltabs(GEN C, GEN Cp, Red *R, long p, long pk, long ltab) { pari_sp av; long i, j; long e; GEN tabt, taba, m; cache_cyc(C) = polcyclo(pk,0); if (p > 2) { long LE = pk - pk/p + 1; GEN E = cgetg(LE, t_VECSMALL), eta = cgetg(pk+1,t_VEC); for (i=1,j=0; iN); gel(eta,i) = FpX_center_i(z, R->N, R->N2); } cache_eta(C) = eta; } else if (pk >= 8) { long LE = (pk>>2) + 1; GEN E = cgetg(LE, t_VECSMALL); for (i=1,j=0; i 2 && umodiu(R->N,pk) == 1) { GEN vpa, p1, p2, p3, a2 = NULL, a = finda(Cp, R->N, pk, p); long jj, ph; if (!a) return 0; ph = pk - pk/p; vpa = cgetg(ph+1,t_COL); gel(vpa,1) = a; if (pk > p) a2 = centermodii(sqri(a), R->N, R->N2); jj = 1; for (i=2; iN, R->N2); } if (!gequal1( centermodii( mulii(a, gel(vpa,ph)), R->N, R->N2) )) return 0; p1 = cgetg(ph+1,t_MAT); p2 = cgetg(ph+1,t_COL); gel(p1,1) = p2; for (i=1; i<=ph; i++) gel(p2,i) = gen_1; j = 2; gel(p1,j) = vpa; p3 = vpa; for (j++; j <= ph; j++) { p2 = cgetg(ph+1,t_COL); gel(p1,j) = p2; for (i=1; i<=ph; i++) gel(p2,i) = centermodii(mulii(gel(vpa,i),gel(p3,i)), R->N, R->N2); p3 = p2; } cache_matvite(C) = p1; cache_matinvvite(C) = FpM_inv(p1, R->N); } tabt = cgetg(ltab+1, t_VECSMALL); taba = cgetg(ltab+1, t_VECSMALL); av = avma; m = divis(R->N, pk); for (e=1; e<=ltab && signe(m); e++) { long s = vali(m); m = shifti(m,-s); tabt[e] = e==1? s: s + R->k; taba[e] = signe(m)? ((mod2BIL(m) & R->mask)+1)>>1: 0; m = shifti(m, -R->k); } setlg(taba, e); cache_aall(C) = taba; setlg(tabt, e); cache_tall(C) = tabt; avma = av; return 1; } static GEN calcglobs(Red *R, ulong t, long *plpC, long *pltab, GEN *pP) { GEN fat, P, E, PE; long lv, i, k, b; GEN pC; b = expi(R->N)+1; k = 3; while (((k+1)*(k+2) << (k-1)) < b) k++; *pltab = (b/k)+2; R->k = k; R->lv = 1L << (k-1); R->mask = (1UL << k) - 1; fat = factoru_pow(t); P = gel(fat,1); E = gel(fat,2); PE= gel(fat,3); *plpC = lv = vecsmall_max(PE); /* max(p^e, p^e | t) */ pC = zerovec(lv); gel(pC,1) = zerovec(9); /* to be used as temp in step5() */ for (i = 2; i <= lv; i++) gel(pC,i) = gen_0; for (i=1; i zeta^a. Assume * a reduced mod pk := p^k*/ static GEN aut(long pk, GEN z, long a) { GEN v; long b, i, dz = degpol(z); if (a == 1 || dz < 0) return z; v = cgetg(pk+2,t_POL); v[1] = evalvarn(0); b = 0; gel(v,2) = gel(z,2); /* i = 0 */ for (i = 1; i < pk; i++) { b += a; if (b > pk) b -= pk; /* b = (a*i) % pk */ gel(v,i+2) = b > dz? gen_0: gel(z,b+2); } return normalizepol_lg(v, pk+2); } /* z^v for v in Z[G], represented by couples [sig_x^{-1},x] */ static GEN autvec_TH(long pk, GEN z, GEN v, GEN C) { long i, lv = lg(v); GEN s = pol_1(varn(C)); for (i=1; iN, pk); GEN s = pol_1(varn(R->C)); long i, lv = lg(v); for (i=1; iC), R->C); } return s; } /* 0 <= i < pk, such that x^i = z mod polcyclo(pk), -1 if no such i exist */ static long look_eta(GEN eta, long pk, GEN z) { long i; for (i=1; i<=pk; i++) if (ZX_equal(z, gel(eta,i))) return i-1; return -1; } /* same pk = 2^k */ static long look_eta2(long k, GEN z) { long d, s; if (typ(z) != t_POL) d = 0; /* t_INT */ else { if (!RgX_is_monomial(z)) return -1; d = degpol(z); z = gel(z,d+2); /* leading term */ } s = signe(z); if (!s || !is_pm1(z)) return -1; return (s > 0)? d: d + (1L<<(k-1)); } static long step4a(GEN C, Red *R, ulong q, long p, long k, GEN tabg) { const long pk = upowuu(p,k); long ind; GEN jpq, s1, s2, s3; if (!tabg) tabg = compute_g(q); jpq = get_jac(C, q, pk, tabg); s1 = autvec_TH(pk, jpq, cache_E(C), cache_cyc(C)); s2 = powpolmod(C,R, p,k, s1); s3 = autvec_AL(pk, jpq, cache_E(C), R); s3 = _red(gmul(s3,s2), R); ind = look_eta(cache_eta(C), pk, s3); if (ind < 0) return -1; return (ind%p) != 0; } /* x == -1 mod N ? */ static long is_m1(GEN x, GEN N) { return equalii(addiu(x,1), N); } /* p=2, k>=3 */ static long step4b(GEN C, Red *R, ulong q, long k) { const long pk = 1L << k; long ind; GEN s1, s2, s3, j2q = NULL, j3q = NULL; (void)get_jac2(R->N,q,k, &j2q,&j3q); s1 = autvec_TH(pk, j3q, cache_E(C), cache_cyc(C)); s2 = powpolmod(C,R, 2,k, s1); s3 = autvec_AL(pk, j3q, cache_E(C), R); s3 = _red(gmul(s3,s2), R); if (j2q) s3 = _red(gmul(j2q, s3), R); ind = look_eta2(k, s3); if (ind < 0) return -1; if ((ind&1)==0) return 0; s3 = Fp_pow(utoipos(q), R->N2, R->N); return is_m1(s3, R->N); } /* p=2, k=2 */ static long step4c(GEN C, Red *R, ulong q) { long ind; GEN s0,s1,s3, jpq = get_jac2(R->N,q,2, NULL,NULL); s0 = sqrmod4(jpq, R); s1 = gmulsg(q,s0); s3 = powpolmod(C,R, 2,2, s1); if (mod4(R->N) == 3) s3 = _red(gmul(s0,s3), R); ind = look_eta2(2, s3); if (ind < 0) return -1; if ((ind&1)==0) return 0; s3 = Fp_pow(utoipos(q), R->N2, R->N); return is_m1(s3, R->N); } /* p=2, k=1 */ static long step4d(Red *R, ulong q) { GEN s1 = Fp_pow(utoipos(q), R->N2, R->N); if (is_pm1(s1)) return 0; if (is_m1(s1, R->N)) return (mod4(R->N) == 1); return -1; } static GEN _res(long a, long b) { return b? mkvec2s(a, b): mkvecs(a); } /* return 1 [OK so far] or <= 0 [not a prime] */ static GEN step5(GEN pC, Red *R, long p, GEN et, ulong ltab, long lpC) { pari_sp av; ulong q; long pk, k, fl = -1; GEN C, Cp; forprime_t T; (void)u_forprime_arith_init(&T, 3, ULONG_MAX, 1,p); while( (q = u_forprime_next(&T)) ) { /* q = 1 (mod p) */ if (umodiu(et,q) == 0) continue; if (umodiu(R->N,q) == 0) return _res(1,p); k = u_lval(q-1, p); pk = upowuu(p,k); if (pk <= lpC && !isintzero(gel(pC,pk))) { C = gel(pC,pk); Cp = gel(pC,p); } else { C = gel(pC,1); Cp = NULL; cache_matvite(C) = gen_0; /* re-init */ } av = avma; if (!filltabs(C, Cp, R, p, pk, ltab)) return _res(1,0); R->C = cache_cyc(C); if (p >= 3) fl = step4a(C,R, q,p,k, NULL); else if (k >= 3) fl = step4b(C,R, q,k); else if (k == 2) fl = step4c(C,R, q); else fl = step4d(R, q); if (fl == -1) return _res(q,p); if (fl == 1) return NULL; /*OK*/ avma = av; } pari_err_BUG("aprcl test fails! This is highly improbable"); return NULL; } GEN aprcl_step6_worker(GEN r, long t, GEN N, GEN N1, GEN et) { long i; pari_sp av = avma; for (i=1; i<=t; i++) { r = remii(mulii(r,N1), et); if (equali1(r)) break; if (dvdii(N,r) && !equalii(r,N)) return mkvec2(r, gen_0); if ((i & 0x1f) == 0) r = gerepileuptoint(av, r); } return gen_0; } static GEN step6(GEN N, ulong t, GEN et) { GEN r, rk, N1 = remii(N, et); ulong k = 10000; ulong i; GEN worker, res = NULL; long pending = 0; struct pari_mt pt; pari_sp btop; worker = strtoclosure("_aprcl_step6_worker", 3, N, N1, et); r = gen_1; rk = Fp_powu(N1, k, et); mt_queue_start_lim(&pt, worker, (t-1+k-1)/k); btop = avma; for (i=1; (i1) pari_warn(warnmem,"APRCL: i = %ld",i); r = gerepileupto(btop, r); } } mt_queue_end(&pt); if (res) return res; return gen_1; } GEN aprcl_step4_worker(ulong q, GEN pC, GEN N, GEN v) { pari_sp av1 = avma, av2 = avma; long j, k; Red R; GEN faq = factoru_pow(q-1), tabg = compute_g(q); GEN P = gel(faq,1), E = gel(faq,2), PE = gel(faq,3); long lfaq = lg(P); GEN flags = cgetg(lfaq, t_VECSMALL); R.N = N; R.N2= shifti(N, -1); R.k = v[1]; R.lv = v[2]; R.mask = uel(v,3); R.n = v[4]; av2 = avma; for (j=1, k=1; j= 3) fl = step4a(C,&R, q,p,e, tabg); else if (e >= 3) fl = step4b(C,&R, q,e); else if (e == 2) fl = step4c(C,&R, q); else fl = step4d(&R, q); if (fl == -1) return _res(q,p); if (fl == 1) flags[k++] = p; } setlg(flags, k); return gerepileuptoleaf(av1, flags); } static GEN aprcl(GEN N) { GEN et, fat, flaglp, faet = NULL; /*-Wall*/ long i, j, l, ltab, lfat, lpC; ulong t; Red R; GEN pC; GEN worker, res = NULL; long pending = 0, workid; struct pari_mt pt; if (typ(N) != t_INT) pari_err_TYPE("aprcl",N); if (cmpis(N,12) <= 0) switch(itos(N)) { case 2: case 3: case 5: case 7: case 11: return gen_1; default: return _res(0,0); } if (Z_issquare(N)) return _res(0,0); t = compute_t(N, &et, &faet); if (DEBUGLEVEL) err_printf("Starting APRCL with t = %ld\n",t); if (cmpii(sqri(et),N) < 0) pari_err_BUG("aprcl: e(t) too small"); if (!equali1(gcdii(N,mului(t,et)))) return _res(1,0); R.N = N; R.N2= shifti(N, -1); pC = calcglobs(&R, t, &lpC, <ab, &fat); if (!pC) return _res(1,0); lfat = lg(fat); flaglp = cgetg(lfat, t_VECSMALL); flaglp[1] = 0; for (i=2; i2) err_printf("Step4: %ld q-values\n", l-1); mt_queue_start_lim(&pt, worker, l-1); for (i=l-1; (i>0 && !res) || pending; i--) { GEN done; ulong q = i>0 ? faet[i]: 0; mt_queue_submit(&pt, q, q>0? mkvec(utoi(q)): NULL); done = mt_queue_get(&pt, &workid, &pending); if (done) { long lf = lg(done); if (typ(done) == t_VEC) res = done; for (j=1; j2) err_printf("testing Jacobi sums for q = %ld...OK\n", workid); } } mt_queue_end(&pt); if (res) return res; if (DEBUGLEVEL>2) err_printf("Step5: testing conditions lp\n"); for (i=2; i2) err_printf("Step6: testing potential divisors\n"); return step6(N, t, et); } long isprimeAPRCL(GEN N) { pari_sp av = avma; GEN res = aprcl(N); avma = av; return (typ(res) == t_INT); } /*******************************************************************/ /* DIVISORS IN RESIDUE CLASSES (LENSTRA) */ /*******************************************************************/ /* This would allow to replace e(t) > N^(1/2) by e(t) > N^(1/3), but step6 * becomes so expensive that, at least up to 6000 bits, this is useless * in this application. */ static void set_add(hashtable *H, void *d) { ulong h = H->hash(d); if (!hash_search2(H, d, h)) hash_insert2(H, d, NULL, h); } static GEN GEN_hash_keys(hashtable *H) { GEN v = hash_keys(H); settyp(v, t_VEC); return ZV_sort(v); } static void add(hashtable *H, GEN t1, GEN t2, GEN a, GEN b, GEN r, GEN s) { GEN ra, qa = dvmdii(t1, a, &ra); if (!signe(ra) && dvdii(t2, b) && equalii(modii(qa, s), r)) set_add(H, (void*)qa); } /* T^2 - B*T + C has integer roots ? */ static void check_t(hashtable *H, GEN B, GEN C4, GEN a, GEN b, GEN r, GEN s) { GEN d, t1, t2, D = subii(sqri(B), C4); if (!Z_issquareall(D, &d)) return; t1 = shifti(addii(B, d), -1); /* >= 0 */ t2 = subii(B, t1); add(H, t1,t2, a,b,r,s); if (signe(t2) >= 0) add(H, t2,t1, a,b,r,s); } /* N > s > r >= 0, (r,s) = 1 */ GEN divisorslenstra(GEN N, GEN r, GEN s) { pari_sp av = avma; GEN u, Ns2, rp, a0, a1, b0, b1, c0, c1, s2; hashtable *H = hash_create(11, (ulong(*)(void*))&hash_GEN, (int(*)(void*,void*))&equalii, 1); long j; if (typ(N) != t_INT) pari_err_TYPE("divisorslenstra", N); if (typ(r) != t_INT) pari_err_TYPE("divisorslenstra", r); if (typ(s) != t_INT) pari_err_TYPE("divisorslenstra", s); u = Fp_inv(r, s); rp = Fp_mul(u, N, s); /* r' */ s2 = sqri(s); a0 = s; b0 = gen_0; c0 = gen_0; if (dvdii(N, r)) set_add(H, (void*)r); /* case i = 0 */ a1 = Fp_mul(u, rp, s); if (!signe(a1)) a1 = s; /* 0 < a1 <= s */ b1 = gen_1; c1 = Fp_mul(u, diviiexact(subii(N,mulii(r,rp)), s), s); Ns2 = divii(N, s2); j = 1; for (;;) { GEN Cs, q, c, ab = mulii(a1,b1); long i, lC; if (j == 0) /* i even, a1 >= 0 */ { if (!signe(c1)) Cs = mkvec(gen_0); else { GEN cs = mulii(c1, s); Cs = mkvec2(subii(cs,s2), cs); } } else { /* i odd, a1 > 0 */ GEN X = shifti(ab,1); c = c1; /* smallest c >= 2ab, c = c1 (mod s) */ if (cmpii(c, X) < 0) { GEN rX, qX = dvmdii(subii(X,c), s, &rX); if (signe(rX)) qX = addiu(qX,1); /* ceil((X-c)/s) */ c = addii(c, mulii(s, qX)); } Cs = (cmpii(c, addii(Ns2,ab)) <= 0)? mkvec(mulii(c,s)): cgetg(1,t_VEC); } lC = lg(Cs); if (signe(a1)) { GEN abN4 = shifti(mulii(ab, N), 2); GEN B = addii(mulii(a1,r), mulii(b1,rp)); for (i = 1; i < lC; i++) check_t(H, addii(B, gel(Cs,i)), abN4, a1, b1, r, s); } else { /* a1 = 0, last batch */ for (i = 1; i < lC; i++) { GEN ry, ys = dvmdii(gel(Cs,i), b1, &ry); if (!signe(ry)) { GEN d = addii(ys, rp); if (signe(d) > 0) { d = dvmdii(N, d, &ry); if (!signe(ry)) set_add(H, (void*)d); } } } break; /* DONE */ } j = 1-j; q = dvmdii(a0, a1, &c); if (j == 1 && !signe(c)) { q = subiu(q,1); c = a1; } a0 = a1; a1 = c; if (equali1(q)) /* frequent */ { c = subii(b0, b1); b0 = b1; b1 = c; c = Fp_sub(c0, c1, s); c0 = c1; c1 = c; } else { c = subii(b0, mulii(q,b1)); b0 = b1; b1 = c; c = modii(subii(c0, mulii(q,c1)), s); c0 = c1; c1 = c; } } return gerepileupto(av, GEN_hash_keys(H)); } pari-2.11.2/src/basemath/lfun.c0000644000175000017500000021146613457566441014672 0ustar billbill/* Copyright (C) 2015 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** L-functions **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* Accessors */ /*******************************************************************/ static GEN mysercoeff(GEN x, long n) { long N = n - valp(x); return (N < 0)? gen_0: gel(x, N+2); } long ldata_get_type(GEN ldata) { return mael3(ldata, 1, 1, 1); } GEN ldata_get_an(GEN ldata) { return gel(ldata, 1); } GEN ldata_get_dual(GEN ldata) { return gel(ldata, 2); } long ldata_isreal(GEN ldata) { return isintzero(gel(ldata, 2)); } GEN ldata_get_gammavec(GEN ldata) { return gel(ldata, 3); } long ldata_get_degree(GEN ldata) { return lg(gel(ldata, 3))-1; } long ldata_get_k(GEN ldata) { GEN w = gel(ldata,4); if (typ(w) == t_VEC) w = gel(w,1); return itos(w); } /* a_n = O(n^{k1 + epsilon}) */ static double ldata_get_k1(GEN ldata) { GEN w = gel(ldata,4); long k; if (typ(w) == t_VEC) return gtodouble(gel(w,2)); /* by default, assume that k1 = k-1 and even (k-1)/2 for entire functions */ k = itos(w); return ldata_get_residue(ldata)? k-1: (k-1)/2.; } GEN ldata_get_conductor(GEN ldata) { return gel(ldata, 5); } GEN ldata_get_rootno(GEN ldata) { return gel(ldata, 6); } GEN ldata_get_residue(GEN ldata) { return lg(ldata) == 7 ? NULL: gel(ldata, 7); } long linit_get_type(GEN linit) { return mael(linit, 1, 1); } GEN linit_get_ldata(GEN linit) { return gel(linit, 2); } GEN linit_get_tech(GEN linit) { return gel(linit, 3); } long is_linit(GEN data) { return lg(data) == 4 && typ(data) == t_VEC && typ(gel(data, 1)) == t_VECSMALL; } GEN lfun_get_step(GEN tech) { return gmael(tech, 2, 1);} GEN lfun_get_pol(GEN tech) { return gmael(tech, 2, 2);} GEN lfun_get_Residue(GEN tech) { return gmael(tech, 2, 3);} GEN lfun_get_k2(GEN tech) { return gmael(tech, 3, 1);} GEN lfun_get_w2(GEN tech) { return gmael(tech, 3, 2);} GEN lfun_get_expot(GEN tech) { return gmael(tech, 3, 3);} GEN lfun_get_factgammavec(GEN tech) { return gmael(tech, 3, 4); } static long vgaell(GEN Vga) { GEN c; long d = lg(Vga)-1; if (d != 2) return 0; c = gsub(gel(Vga,1), gel(Vga,2)); return gequal1(c) || gequalm1(c); } static long vgaeasytheta(GEN Vga) { return lg(Vga)-1 == 1 || vgaell(Vga); } /* return b(n) := a(n) * n^c, when vgaeasytheta(Vga) is set */ static GEN antwist(GEN an, GEN Vga, long prec) { long l, i; GEN b, c = vecmin(Vga); if (gequal0(c)) return an; l = lg(an); b = cgetg(l, t_VEC); if (gequal1(c)) { if (typ(an) == t_VECSMALL) for (i = 1; i < l; i++) gel(b,i) = mulss(an[i], i); else for (i = 1; i < l; i++) gel(b,i) = gmulgs(gel(an,i), i); } else { GEN v = vecpowug(l-1, c, prec); if (typ(an) == t_VECSMALL) for (i = 1; i < l; i++) gel(b,i) = gmulsg(an[i], gel(v,i)); else for (i = 1; i < l; i++) gel(b,i) = gmul(gel(an,i), gel(v,i)); } return b; } static GEN theta_dual(GEN theta, GEN bn) { if (typ(bn)==t_INT) return NULL; else { GEN thetad = shallowcopy(theta), ldata = linit_get_ldata(theta); GEN Vga = ldata_get_gammavec(ldata); GEN tech = shallowcopy(linit_get_tech(theta)); GEN an = theta_get_an(tech); long prec = nbits2prec(theta_get_bitprec(tech)); GEN vb = ldata_vecan(bn, lg(an)-1, prec); if (!theta_get_m(tech) && vgaeasytheta(Vga)) vb = antwist(vb, Vga, prec); gel(tech,1) = vb; gel(thetad,3) = tech; return thetad; } } static GEN domain_get_dom(GEN domain) { return gel(domain,1); } static long domain_get_der(GEN domain) { return mael2(domain, 2, 1); } static long domain_get_bitprec(GEN domain) { return mael2(domain, 2, 2); } GEN lfun_get_domain(GEN tech) { return gel(tech,1); } long lfun_get_bitprec(GEN tech){ return domain_get_bitprec(lfun_get_domain(tech)); } GEN lfun_get_dom(GEN tech) { return domain_get_dom(lfun_get_domain(tech)); } GEN lfunprod_get_fact(GEN tech) { return gel(tech, 2); } GEN theta_get_an(GEN tdata) { return gel(tdata, 1);} GEN theta_get_K(GEN tdata) { return gel(tdata, 2);} GEN theta_get_R(GEN tdata) { return gel(tdata, 3);} long theta_get_bitprec(GEN tdata) { return itos(gel(tdata, 4));} long theta_get_m(GEN tdata) { return itos(gel(tdata, 5));} GEN theta_get_tdom(GEN tdata) { return gel(tdata, 6);} GEN theta_get_sqrtN(GEN tdata) { return gel(tdata, 7);} /*******************************************************************/ /* Helper functions related to Gamma products */ /*******************************************************************/ /* return -itos(s) >= 0 if s is (approximately) equal to a non-positive * integer, and -1 otherwise */ static long isnegint(GEN s) { GEN r = ground(real_i(s)); if (signe(r) <= 0 && gequal(s, r)) return -itos(r); return -1; } /* pi^(-s/2) Gamma(s/2) */ static GEN gamma_R(GEN s, long prec) { GEN s2 = gdivgs(s, 2), pi = mppi(prec); long ms = isnegint(s2); if (ms >= 0) { GEN pr = gmul(powru(pi, ms), gdivsg(odd(ms)? -2: 2, mpfact(ms))); GEN S = scalarser(pr, 0, 1); setvalp(S,-1); return S; } return gdiv(ggamma(s2,prec), gpow(pi,s2,prec)); } /* gamma_R(s)gamma_R(s+1) = 2 (2pi)^(-s) Gamma(s) */ static GEN gamma_C(GEN s, long prec) { GEN pi2 = Pi2n(1,prec); long ms = isnegint(s); if (ms >= 0) { GEN pr = gmul(powrs(pi2, ms), gdivsg(odd(ms)? -2: 2, mpfact(ms))); GEN S = scalarser(pr, 0, 1); setvalp(S,-1); return S; } return gmul2n(gdiv(ggamma(s,prec), gpow(pi2,s,prec)), 1); } static GEN gammafrac(GEN r, long d) { GEN pr, a = gmul2n(r, -1); GEN polj = cgetg(labs(d)+1, t_COL); long i, v=0; if (d > 0) for (i = 1; i <= d; ++i) gel(polj, i) = deg1pol_shallow(ghalf, gaddgs(a, i-1), v); else for (i = 1; i <= -d; ++i) gel(polj, i) = deg1pol_shallow(ghalf, gsubgs(a, i), v); pr = RgV_prod(polj); return d < 0 ? ginv(pr): pr; } static GEN gammafactor(GEN Vga) { pari_sp av = avma; long i, m, d = lg(Vga)-1, dr, dc; GEN pol = pol_1(0), pi = gen_0, R = cgetg(d+1,t_VEC); GEN P, F, FR, FC, E, ER, EC; for (i = 1; i <= d; ++i) { GEN a = gel(Vga,i), qr = gdiventres(real_i(a), gen_2); long q = itos(gel(qr,1)); gel(R, i) = gadd(gel(qr,2), imag_i(a)); if (q) { pol = gmul(pol, gammafrac(gel(R,i), q)); pi = addis(pi, q); } } gen_sort_inplace(R, (void*)cmp_universal, cmp_nodata, &P); F = cgetg(d+1, t_VEC); E = cgetg(d+1, t_VECSMALL); for (i = 1, m = 0; i <= d;) { long k; GEN u = gel(R, i); for(k = i + 1; k <= d; ++k) if (cmp_universal(gel(R, k), u)) break; m++; E[m] = k - i; gel(F, m) = u; i = k; } setlg(F, m+1); setlg(E, m+1); R = cgetg(m+1, t_VEC); for (i = 1; i <= m; i++) { GEN qr = gdiventres(gel(F,i), gen_1); gel(R, i) = mkvec2(gel(qr,2), stoi(E[i])); } gen_sort_inplace(R, (void*)cmp_universal, cmp_nodata, &P); FR = cgetg(m+1, t_VEC); ER = cgetg(m+1, t_VECSMALL); FC = cgetg(m+1, t_VEC); EC = cgetg(m+1, t_VECSMALL); for (i = 1, dr = 1, dc = 1; i <= m;) { if (i==m || cmp_universal(gel(R,i), gel(R,i+1))) { gel(FR, dr) = gel(F, P[i]); ER[dr] = E[P[i]]; dr++; i++; } else { if (gequal(gaddgs(gmael(R,i,1), 1), gmael(R,i+1,1))) gel(FC, dc) = gel(F, P[i+1]); else gel(FC, dc) = gel(F, P[i]); EC[dc] = E[P[i]]; dc++; i+=2; } } setlg(FR, dr); setlg(ER, dr); setlg(FC, dc); setlg(EC, dc); return gerepilecopy(av, mkvec4(pol, pi, mkvec2(FR,ER), mkvec2(FC,EC))); } static GEN deg1ser_shallow(GEN a1, GEN a0, long v, long e) { return RgX_to_ser(deg1pol_shallow(a1, a0, v), e+2); } /* To test: GR(s)=Pi^-(s/2)*gamma(s/2); GC(s)=2*(2*Pi)^-s*gamma(s) gam_direct(F,s)=prod(i=1,#F,GR(s+F[i])) gam_fact(F,s)=my([P,p,R,C]=gammafactor(F));subst(P,x,s)*Pi^-p*prod(i=1,#R[1],GR(s+R[1][i])^R[2][i])*prod(i=1,#C[1],GC(s+C[1][i])^C[2][i]) */ static GEN polgammaeval(GEN F, GEN s) { GEN r = poleval(F, s); if (typ(s)!=t_SER && gequal0(r)) { long e = gvaluation(F, deg1pol(gen_1, gneg(s), varn(F))); r = poleval(F, deg1ser_shallow(gen_1, s, 0, e+1)); } return r; } static GEN fracgammaeval(GEN F, GEN s) { if (typ(F)==t_POL) return polgammaeval(F, s); else if (typ(F)==t_RFRAC) return gdiv(polgammaeval(gel(F,1), s), polgammaeval(gel(F,2), s)); return F; } static GEN gammafactproduct(GEN F, GEN s, long prec) { pari_sp av = avma; GEN P = fracgammaeval(gel(F,1), s); GEN p = gpow(mppi(prec),gneg(gel(F,2)), prec), z = gmul(P, p); GEN R = gel(F,3), Rw = gel(R,1), Re=gel(R,2); GEN C = gel(F,4), Cw = gel(C,1), Ce=gel(C,2); long i, lR = lg(Rw), lC = lg(Cw); for (i=1; i< lR; i++) z = gmul(z, gpowgs(gamma_R(gadd(s,gel(Rw, i)), prec), Re[i])); for (i=1; i< lC; i++) z = gmul(z, gpowgs(gamma_C(gadd(s,gel(Cw, i)), prec), Ce[i])); return gerepileupto(av, z); } static int gammaordinary(GEN Vga, GEN s) { long i, d = lg(Vga)-1; for (i = 1; i <= d; i++) { GEN z = gadd(s, gel(Vga,i)); long e; if (gsigne(z) <= 0) { (void)grndtoi(z, &e); if (e < -10) return 0; } } return 1; } /* Exponent A of t in asymptotic expansion; K(t) ~ C t^A exp(-pi d t^(2/d)). * suma = vecsum(Vga)*/ static double gammavec_expo(long d, double suma) { return (1 - d + suma) / d; } /*******************************************************************/ /* First part: computations only involving Theta(t) */ /*******************************************************************/ static void get_cone(GEN t, double *r, double *a) { const long prec = LOWDEFAULTPREC; if (typ(t) == t_COMPLEX) { t = gprec_w(t, prec); *r = gtodouble(gabs(t, prec)); *a = fabs(gtodouble(garg(t, prec))); } else { *r = fabs(gtodouble(t)); *a = 0.; } if (!*r && !*a) pari_err_DOMAIN("lfunthetainit","t","=",gen_0,t); } /* slightly larger cone than necessary, to avoid round-off problems */ static void get_cone_fuzz(GEN t, double *r, double *a) { get_cone(t, r, a); *r -= 1e-10; if (*a) *a += 1e-10; } /* Initialization m-th Theta derivative. tdom is either * - [rho,alpha]: assume |t| >= rho and |arg(t)| <= alpha * - a positive real scalar: assume t real, t >= tdom; * - a complex number t: compute at t; * N is the conductor (either the true one from ldata or a guess from * lfunconductor) */ long lfunthetacost(GEN ldata, GEN tdom, long m, long bitprec) { pari_sp av = avma; GEN Vga = ldata_get_gammavec(ldata); long d = lg(Vga)-1; long k1 = ldata_get_k1(ldata); double c = d/2., a, A, B, logC, al, rho, T; double N = gtodouble(ldata_get_conductor(ldata)); if (!N) pari_err_TYPE("lfunthetaneed [missing conductor]", ldata); if (typ(tdom) == t_VEC && lg(tdom) == 3) { rho= gtodouble(gel(tdom,1)); al = gtodouble(gel(tdom,2)); } else get_cone_fuzz(tdom, &rho, &al); A = gammavec_expo(d, gtodouble(vecsum(Vga))); avma = av; a = (A+k1+1) + (m-1)/c; if (fabs(a) < 1e-10) a = 0.; logC = c*M_LN2 - log(c)/2; /* +1: fudge factor */ B = M_LN2*bitprec+logC+m*log(2*M_PI) + 1 + (k1+1)*log(N)/2 - (k1+m+1)*log(rho); if (al) { /* t = rho e^(i*al), T^(1/c) = Re(t^(1/c)) > 0, T = rho cos^c(al/c) */ double z = cos(al/c); T = (d == 2 && typ(tdom) != t_VEC)? gtodouble(real_i(tdom)): rho*pow(z,c); if (z <= 0) pari_err_DOMAIN("lfunthetaneed", "arg t", ">", dbltor(c*M_PI/2), tdom); B -= log(z) * (c * (k1+A+1) + m); } else T = rho; return B <= 0? 0: floor(0.9 + dblcoro526(a,c,B) / T * sqrt(N)); } long lfunthetacost0(GEN L, GEN tdom, long m, long bitprec) { long n; if (is_linit(L) && linit_get_type(L)==t_LDESC_THETA) { GEN tech = linit_get_tech(L); n = lg(theta_get_an(tech))-1; } else { pari_sp av = avma; GEN ldata = lfunmisc_to_ldata_shallow(L); n = lfunthetacost(ldata, tdom? tdom: gen_1, m, bitprec); avma = av; } return n; } static long fracgammadegree(GEN FVga) { GEN F = gel(FVga,1); return (typ(F)==t_RFRAC)? degpol(gel(F,2)): 0; } /* Poles of a L-function can be represented in the following ways: * 1) Nothing (ldata has only 6 components, ldata_get_residue = NULL). * 2) a complex number (single pole at s = k with given residue, unknown if 0). * 3) A vector (possibly empty) of 2-component vectors [a, ra], where a is the * pole, ra a t_SER: its Taylor expansion at a. A t_VEC encodes the polar * part of L, a t_COL, the polar part of Lambda */ /* 'a' a complex number (pole), 'r' the polar part of L at 'a'; * return 'R' the polar part of Lambda at 'a' */ static GEN rtoR(GEN a, GEN r, GEN FVga, GEN N, long prec) { long v = lg(r)-2; GEN as = deg1ser_shallow(gen_1, a, varn(r), v); GEN Na = gpow(N, gdivgs(as, 2), prec); long d = fracgammadegree(FVga); if (d) as = sertoser(as, v+d); /* make up for a possible loss of accuracy */ return gmul(gmul(r, Na), gammafactproduct(FVga, as, prec)); } /* assume r in normalized form: t_VEC of pairs [be,re] */ GEN lfunrtopoles(GEN r) { long j, l = lg(r); GEN v = cgetg(l, t_VEC); for (j = 1; j < l; j++) { GEN rj = gel(r,j), a = gel(rj,1); gel(v,j) = a; } gen_sort_inplace(v, (void*)&cmp_universal, cmp_nodata, NULL); return v; } /* r / x + O(1) */ static GEN simple_pole(GEN r) { GEN S; if (isintzero(r)) return gen_0; S = deg1ser_shallow(gen_0, r, 0, 1); setvalp(S, -1); return S; } static GEN normalize_simple_pole(GEN r, GEN k) { long tx = typ(r); if (is_vec_t(tx)) return r; if (!is_scalar_t(tx)) pari_err_TYPE("lfunrootres [poles]", r); return mkvec(mkvec2(k, simple_pole(r))); } /* normalize the description of a polar part */ static GEN normalizepoles(GEN r, long k) { long iv, j, l; GEN v; if (!is_vec_t(typ(r))) return normalize_simple_pole(r, stoi(k)); v = cgetg_copy(r, &l); for (j = iv = 1; j < l; j++) { GEN rj = gel(r,j), a = gel(rj,1), ra = gel(rj,2); if (!is_scalar_t(typ(a)) || typ(ra) != t_SER) pari_err_TYPE("lfunrootres [poles]",r); if (valp(ra) >= 0) continue; gel(v,iv++) = rj; } setlg(v, iv); return v; } static int residues_known(GEN r) { long i, l = lg(r); if (isintzero(r)) return 0; if (!is_vec_t(typ(r))) return 1; for (i = 1; i < l; i++) { GEN ri = gel(r,i); if (!is_vec_t(typ(ri)) || lg(ri)!=3) pari_err_TYPE("lfunrootres [poles]",r); if (isintzero(gel(ri, 2))) return 0; } return 1; } /* Compute R's from r's (r = Taylor devts of L(s), R of Lambda(s)). * 'r/eno' passed to override the one from ldata */ static GEN lfunrtoR_i(GEN ldata, GEN r, GEN eno, long prec) { GEN Vga = ldata_get_gammavec(ldata), N = ldata_get_conductor(ldata); GEN R, vr, FVga; pari_sp av = avma; long lr, j, jR, k = ldata_get_k(ldata); if (!r || isintzero(eno) || !residues_known(r)) return gen_0; r = normalizepoles(r, k); if (typ(r) == t_COL) return gerepilecopy(av, r); if (typ(ldata_get_dual(ldata)) != t_INT) pari_err(e_MISC,"please give the Taylor development of Lambda"); vr = lfunrtopoles(r); lr = lg(vr); FVga = gammafactor(Vga); R = cgetg(2*lr, t_VEC); for (j = jR = 1; j < lr; j++) { GEN rj = gel(r,j), a = gel(rj,1), ra = gel(rj,2); GEN Ra = rtoR(a, ra, FVga, N, prec); GEN b = gsubsg(k, conj_i(a)); if (lg(Ra)-2 < -valp(Ra)) pari_err(e_MISC, "please give more terms in L function's Taylor development at %Ps", a); gel(R,jR++) = mkvec2(a, Ra); if (!tablesearch(vr, b, (int (*)(GEN,GEN))&cmp_universal)) { GEN mX = gneg(pol_x(varn(Ra))); GEN Rb = gmul(eno, gsubst(conj_i(Ra), varn(Ra), mX)); gel(R,jR++) = mkvec2(b, Rb); } } setlg(R, jR); return gerepilecopy(av, R); } static GEN lfunrtoR_eno(GEN ldata, GEN eno, long prec) { return lfunrtoR_i(ldata, ldata_get_residue(ldata), eno, prec); } static GEN lfunrtoR(GEN ldata, long prec) { return lfunrtoR_eno(ldata, ldata_get_rootno(ldata), prec); } /* thetainit using {an: n <= L}; if (m = 0 && easytheta), an2 is an * n^al */ static GEN lfunthetainit0(GEN ldata, GEN tdom, GEN an2, long m, long bitprec, long extrabit) { long prec = nbits2prec(bitprec); GEN tech, N = ldata_get_conductor(ldata); GEN Vga = ldata_get_gammavec(ldata); GEN K = gammamellininvinit(Vga, m, bitprec + extrabit); GEN R = lfunrtoR(ldata, prec); if (!tdom) tdom = gen_1; if (typ(tdom) != t_VEC) { double r, a; get_cone_fuzz(tdom, &r, &a); tdom = mkvec2(dbltor(r), a? dbltor(a): gen_0); } tech = mkvecn(7, an2,K,R, stoi(bitprec), stoi(m), tdom, gsqrt(N,prec)); return mkvec3(mkvecsmall(t_LDESC_THETA), ldata, tech); } /* tdom: 1) positive real number r, t real, t >= r; or * 2) [r,a], describing the cone |t| >= r, |arg(t)| <= a */ static GEN lfunthetainit_i(GEN data, GEN tdom, long m, long bitprec) { GEN ldata = lfunmisc_to_ldata_shallow(data); long L = lfunthetacost(ldata, tdom, m, bitprec), prec = nbits2prec(bitprec); GEN an = ldata_vecan(ldata_get_an(ldata), L, prec); GEN Vga = ldata_get_gammavec(ldata); if (m == 0 && vgaeasytheta(Vga)) an = antwist(an, Vga, prec); return lfunthetainit0(ldata, tdom, an, m, bitprec, 32); } GEN lfunthetainit(GEN ldata, GEN tdom, long m, long bitprec) { pari_sp av = avma; GEN S = lfunthetainit_i(ldata, tdom? tdom: gen_1, m, bitprec); return gerepilecopy(av, S); } GEN lfunan(GEN ldata, long L, long prec) { pari_sp av = avma; GEN an ; ldata = lfunmisc_to_ldata_shallow(ldata); an = gerepilecopy(av, ldata_vecan(ldata_get_an(ldata), L, prec)); if (typ(an) != t_VEC) an = vecsmall_to_vec_inplace(an); return an; } /* [1^B,...,N^B] */ GEN vecpowuu(long N, ulong B) { GEN v; long p, i; forprime_t T; if (B <= 2) { if (!B) return const_vec(N,gen_1); v = cgetg(N+1, t_VEC); if (N == 0) return v; gel(v,1) = gen_1; if (B == 1) for (i = 2; i <= N; i++) gel(v,i) = utoipos(i); else for (i = 2; i <= N; i++) gel(v,i) = sqru(i); return v; } v = const_vec(N, NULL); u_forprime_init(&T, 3, N); while ((p = u_forprime_next(&T))) { long m, pk, oldpk; gel(v,p) = powuu(p, B); for (pk = p, oldpk = p; pk; oldpk = pk, pk = umuluu_le(pk,p,N)) { if (pk != p) gel(v,pk) = mulii(gel(v,oldpk), gel(v,p)); for (m = N/pk; m > 1; m--) if (gel(v,m) && m%p) gel(v, m*pk) = mulii(gel(v,m), gel(v,pk)); } } gel(v,1) = gen_1; for (i = 2; i <= N; i+=2) { long vi = vals(i); gel(v,i) = shifti(gel(v,i >> vi), B * vi); } return v; } /* [1^B,...,N^B] */ GEN vecpowug(long N, GEN B, long prec) { GEN v = const_vec(N, NULL); long p, eB = gexpo(B); long prec0 = eB < 5? prec: prec + nbits2extraprec(eB); forprime_t T; u_forprime_init(&T, 2, N); gel(v,1) = gen_1; while ((p = u_forprime_next(&T))) { long m, pk, oldpk; gel(v,p) = gpow(utor(p,prec0), B, prec); if (prec0 != prec) gel(v,p) = gprec_wtrunc(gel(v,p), prec); for (pk = p, oldpk = p; pk; oldpk = pk, pk = umuluu_le(pk,p,N)) { if (pk != p) gel(v,pk) = gmul(gel(v,oldpk), gel(v,p)); for (m = N/pk; m > 1; m--) if (gel(v,m) && m%p) gel(v, m*pk) = gmul(gel(v,m), gel(v,pk)); } } return v; } /* return [1^(2/d), 2^(2/d),...,lim^(2/d)] */ static GEN mkvroots(long d, long lim, long prec) { if (d <= 4) { GEN v = cgetg(lim+1,t_VEC); long n; switch(d) { case 1: for (n=1; n <= lim; n++) gel(v,n) = sqru(n); return v; case 2: for (n=1; n <= lim; n++) gel(v,n) = utoipos(n); return v; case 4: for (n=1; n <= lim; n++) gel(v,n) = sqrtr(utor(n, prec)); return v; } } return vecpowug(lim, gdivgs(gen_2,d), prec); } GEN lfunthetacheckinit(GEN data, GEN t, long m, long bitprec) { if (is_linit(data) && linit_get_type(data)==t_LDESC_THETA) { GEN tdom, thetainit = linit_get_tech(data); long bitprecnew = theta_get_bitprec(thetainit); long m0 = theta_get_m(thetainit); double r, al, rt, alt; if (m0 != m) pari_err_DOMAIN("lfuntheta","derivative order","!=", stoi(m),stoi(m0)); if (bitprec > bitprecnew) goto INIT; get_cone(t, &rt, &alt); tdom = theta_get_tdom(thetainit); r = rtodbl(gel(tdom,1)); al= rtodbl(gel(tdom,2)); if (rt >= r && alt <= al) return data; } INIT: return lfunthetainit_i(data, t, m, bitprec); } static GEN get_an(GEN an, long n) { if (typ(an) == t_VECSMALL) { long a = an[n]; if (a) return stoi(a); } else { GEN a = gel(an,n); if (a && !gequal0(a)) return a; } return NULL; } /* x * an[n] */ static GEN mul_an(GEN an, long n, GEN x) { if (typ(an) == t_VECSMALL) { long a = an[n]; if (a) return gmulsg(a,x); } else { GEN a = gel(an,n); if (a && !gequal0(a)) return gmul(a,x); } return NULL; } /* 2*t^a * x **/ static GEN mulT(GEN t, GEN a, GEN x, long prec) { if (gequal0(a)) return gmul2n(x,1); return gmul(x, gmul2n(gequal1(a)? t: gpow(t,a,prec), 1)); } static GEN vecan_cmul(void *E, GEN P, long a, GEN x) { (void)E; return (a==0 || !gel(P,a))? NULL: gmul(gel(P,a), x); } /* d=2, 2 sum_{n <= limt} a(n) (n t)^al q^n, q = exp(-2pi t), * an2[n] = a(n) * n^al */ static GEN theta2(GEN an2, long limt, GEN t, GEN al, long prec) { GEN S, q, pi2 = Pi2n(1,prec); const struct bb_algebra *alg = get_Rg_algebra(); setsigne(pi2,-1); q = gexp(gmul(pi2, t), prec); /* Brent-Kung in case the a_n are small integers */ S = gen_bkeval(an2, limt, q, 1, NULL, alg, vecan_cmul); return mulT(t, al, S, prec); } /* d=1, 2 sum_{n <= limt} a_n (n t)^al q^(n^2), q = exp(-pi t^2), * an2[n] is a_n n^al */ static GEN theta1(GEN an2, long limt, GEN t, GEN al, long prec) { GEN q = gexp(gmul(negr(mppi(prec)), gsqr(t)), prec); GEN vexp = gsqrpowers(q, limt), S = gen_0; pari_sp av = avma; long n; for (n = 1; n <= limt; n++) { GEN c = mul_an(an2, n, gel(vexp,n)); if (c) { S = gadd(S, c); if (gc_needed(av, 3)) S = gerepileupto(av, S); } } return mulT(t, al, S, prec); } /* If m > 0, compute m-th derivative of theta(t) = theta0(t/sqrt(N)) * with absolute error 2^-bitprec; theta(t)=\sum_{n\ge1}a(n)K(nt/N^(1/2)) */ GEN lfuntheta(GEN data, GEN t, long m, long bitprec) { pari_sp ltop = avma; long limt, d; GEN sqN, vecan, Vga, ldata, theta, thetainit, S; long n, prec = nbits2prec(bitprec); t = gprec_w(t, prec); theta = lfunthetacheckinit(data, t, m, bitprec); ldata = linit_get_ldata(theta); thetainit = linit_get_tech(theta); vecan = theta_get_an(thetainit); sqN = theta_get_sqrtN(thetainit); limt = lg(vecan)-1; if (theta == data) limt = minss(limt, lfunthetacost(ldata, t, m, bitprec)); if (!limt) { avma = ltop; S = real_0_bit(-bitprec); if (!is_real_t(typ(t)) || !ldata_isreal(ldata)) S = gerepilecopy(ltop, mkcomplex(S,S)); return S; } t = gdiv(t, sqN); Vga = ldata_get_gammavec(ldata); d = lg(Vga)-1; if (m == 0 && vgaeasytheta(Vga)) { if (theta_get_m(thetainit) > 0) vecan = antwist(vecan, Vga, prec); if (d == 1) S = theta1(vecan, limt, t, gel(Vga,1), prec); else S = theta2(vecan, limt, t, vecmin(Vga), prec); return gerepileupto(ltop, S); } else { GEN K = theta_get_K(thetainit); GEN vroots = mkvroots(d, limt, prec); pari_sp av; t = gpow(t, gdivgs(gen_2,d), prec); S = gen_0; av = avma; for (n = 1; n <= limt; ++n) { GEN nt, an = get_an(vecan, n); if (!an) continue; nt = gmul(gel(vroots,n), t); if (m) an = gmul(an, powuu(n, m)); S = gadd(S, gmul(an, gammamellininvrt(K, nt, bitprec))); if ((n & 0x1ff) == 0) S = gerepileupto(av, S); } if (m) S = gdiv(S, gpowgs(sqN, m)); return gerepileupto(ltop, S); } } /*******************************************************************/ /* Second part: Computation of L-Functions. */ /*******************************************************************/ struct lfunp { long precmax, Dmax, D, M, m0, nmax, d; double k1, E, logN2, logC, A, hd, dc, dw, dh, MAXs, sub; GEN L, vprec, an, bn; }; static void lfunparams(GEN ldata, long der, long bitprec, struct lfunp *S) { const long derprec = (der > 1)? dbllog2(mpfact(der)): 0; /* log2(der!) */ GEN Vga, N, L; long k, k1, d, m, M, flag, nmax; double a, E, hd, Ep, d2, suma, maxs, mins, sub, B0,B1, Lestimate, Mestimate; Vga = ldata_get_gammavec(ldata); S->d = d = lg(Vga)-1; d2 = d/2.; suma = gtodouble(vecsum(Vga)); k = ldata_get_k(ldata); N = ldata_get_conductor(ldata); S->logN2 = log(gtodouble(N)) / 2; maxs = S->dc + S->dw; mins = S->dc - S->dw; S->MAXs = maxdd(maxs, k-mins); /* we compute Lambda^(der)(s) / der!; need to compensate for L^(der)(s) * ln |gamma(s)| ~ (pi/4) d |t|; max with 1: fudge factor */ S->D = (long)ceil(bitprec + derprec + maxdd((M_PI/(4*M_LN2))*d*S->dh, 1)); S->E = E = M_LN2*S->D; /* D:= required absolute bitprec */ Ep = E + maxdd(M_PI * S->dh * d2, (d*S->MAXs + suma - 1) * log(E)); hd = d2*M_PI*M_PI / Ep; S->m0 = (long)ceil(M_LN2/hd); S->hd = M_LN2/S->m0; S->logC = d2*M_LN2 - log(d2)/2; k1 = ldata_get_k1(ldata); S->k1 = k1; /* assume |a_n| << n^k1 with small implied constant */ S->A = gammavec_expo(d, suma); sub = 0.; if (mins > 1) { GEN sig = dbltor(mins); sub += S->logN2*mins; if (gammaordinary(Vga, sig)) { GEN FVga = gammafactor(Vga); GEN gas = gammafactproduct(FVga, sig, LOWDEFAULTPREC); if (typ(gas) != t_SER) { double dg = dbllog2(gas); if (dg > 0) sub += dg * M_LN2; } } } S->sub = sub; M = 1000; L = cgetg(M+2, t_VECSMALL); a = S->k1 + S->A; B0 = 5 + S->E - S->sub + S->logC + S->k1*S->logN2; /* 5 extra bits */ B1 = S->hd * (S->MAXs - S->k1); Lestimate = dblcoro526(a + S->MAXs - 2./d, d/2., S->E - S->sub + S->logC - log(2*M_PI*S->hd) + S->MAXs*S->logN2); Mestimate = ((Lestimate > 0? log(Lestimate): 0) + S->logN2) / S->hd; nmax = 0; flag = 0; for (m = 0;; m++) { double x, H = S->logN2 - m*S->hd, B = B0 + m*B1; long n; x = dblcoro526(a, d/2., B); n = floor(x*exp(H)); if (n > nmax) nmax = n; if (m > M) { M *= 2; L = vecsmall_lengthen(L,M+2); } L[m+1] = n; if (n == 0) { if (++flag > 2 && m > Mestimate) break; } else flag = 0; } m -= 2; while (m > 0 && !L[m]) m--; if (m == 0) { nmax = 1; L[1] = 1; m = 1; } /* can happen for tiny bitprec */ setlg(L, m+1); S->M = m-1; S->L = L; S->nmax = nmax; S->Dmax = S->D + (long)ceil((S->M * S->hd * S->MAXs - S->sub) / M_LN2); if (S->Dmax < S->D) S->Dmax = S->D; S->precmax = nbits2prec(S->Dmax); if (DEBUGLEVEL > 1) err_printf("Dmax=%ld, D=%ld, M = %ld, nmax = %ld, m0 = %ld\n", S->Dmax,S->D,S->M,S->nmax, S->m0); } /* x0 * [1,x,..., x^n] */ static GEN powersshift(GEN x, long n, GEN x0) { long i, l = n+2; GEN V = cgetg(l, t_VEC); gel(V,1) = x0; for(i = 2; i < l; i++) gel(V,i) = gmul(gel(V,i-1),x); return V; } static GEN lfuninit_pol(GEN vecc, GEN poqk, long M, long prec) { long m; GEN pol = cgetg(M+3, t_POL); pol[1] = evalsigne(1) | evalvarn(0); gel(pol, 2) = gprec_w(gmul2n(gel(vecc,1), -1), prec); for (m = 2; m <= M+1; m++) gel(pol, m+1) = gprec_w(gmul(gel(poqk,m), gel(vecc,m)), prec); return RgX_renormalize_lg(pol, M+3); } static GEN lfuninit_vecc2_sum(GEN an, GEN qk, GEN a, struct lfunp *Q, GEN poqk) { const long M = Q->M, prec = Q->precmax; GEN L = Q->L; long m, L0 = lg(an)-1; GEN v = cgetg(M + 2, t_VEC); if (typ(an) == t_VEC) an = RgV_kill0(an); for (m = 0; m <= M; m++) { pari_sp av = avma; GEN t = gel(qk, m+1), S = theta2(an, minss(L[m+1],L0), t, a, prec); gel(v, m+1) = gerepileupto(av, S); /* theta(exp(mh)) */ } return lfuninit_pol(v, poqk, M, prec); } /* theta(exp(mh)) ~ sum_{n <= L[m]} a(n) k[m,n] */ static GEN lfuninit_vecc_sum(GEN L, long M, GEN an, GEN vK, GEN pokq, long prec) { long m, L0 = lg(an)-1; GEN vecc = cgetg(M+2, t_VEC); for (m = 0; m <= M; ++m) { pari_sp av = avma; GEN s = gen_0, vKm = gel(vK,m+1); long n, N = minss(L0, L[m+1]); for (n = 1; n <= N; n++) { GEN c = mul_an(an, n, gel(vKm,n)); if (c) { s = gadd(s, c); if (gc_needed(av, 3)) s = gerepileupto(av, s); } } gel(vecc,m+1) = gerepileupto(av, s); } return lfuninit_pol(vecc, pokq, M, prec); } /* return [\theta(exp(mh)), m=0..M], theta(t) = sum a(n) K(n/sqrt(N) t), * h = log(2)/m0 */ static GEN lfuninit_vecc(GEN theta, GEN h, struct lfunp *S, GEN poqk) { const long m0 = S->m0, M = S->M; GEN tech = linit_get_tech(theta); GEN va, vK, L, K, d2, vroots, eh2d, peh2d; GEN sqN = theta_get_sqrtN(tech), an = S->an, bn = S->bn, vprec = S->vprec; long d, prec, m, n, neval; if (!vprec) { /* d=2 and Vga = [a,a+1] */ GEN ldata = linit_get_ldata(theta); GEN a = vecmin(ldata_get_gammavec(ldata)); GEN qk = powersshift(mpexp(h), M, ginv(sqN)); va = lfuninit_vecc2_sum(an, qk, a, S, poqk); return bn? mkvec2(va, lfuninit_vecc2_sum(bn, qk, a, S, poqk)): va; } d = S->d; L = S->L; prec = S->precmax; K = theta_get_K(tech); /* For all 0<= m <= M, and all n <= L[m+1] such that a_n!=0, we must compute * k[m,n] = K(n exp(mh)/sqrt(N)) * with ln(absolute error) <= E + max(mh sigma - sub, 0) + k1 * log(n). * N.B. we use the 'rt' variant and pass argument (n exp(mh)/sqrt(N))^(2/d). * Speedup: if n' = 2n and m' = m - m0 >= 0; then k[m,n] = k[m',n']. */ /* vroots[n] = n^(2/d) */ vroots = mkvroots(d, S->nmax, prec); d2 = gdivgs(gen_2, d); eh2d = gexp(gmul(d2,h), prec); /* exp(2h/d) */ /* peh2d[m+1] = (exp(mh)/sqrt(N))^(2/d) */ peh2d = gpowers0(eh2d, M, invr(gpow(sqN, d2, prec))); neval = 0; /* vK[m+1,n] will contain k[m,n]. For each 0 <= m <= M, sum for n<=L[m+1] */ vK = cgetg(M+2, t_VEC); for (m = 0; m <= M; m++) gel(vK,m+1) = const_vec(L[m+1], NULL); for (m = M; m >= 0; m--) for (n = 1; n <= L[m+1]; n++) { GEN t2d, kmn = gmael(vK,m+1,n); long nn, mm, p = 0; if (kmn) continue; /* done already */ /* p = largest (absolute) accuracy to which we need k[m,n] */ for (mm=m,nn=n; mm>=0 && nn <= L[mm+1]; nn<<=1,mm-=m0) if (gel(an, nn) || (bn && gel(bn, nn))) p = maxuu(p, umael(vprec,mm+1,nn)); if (!p) continue; /* a_{n 2^v} = 0 for all v in range */ t2d = mpmul(gel(vroots, n), gel(peh2d,m+1)); /*(n exp(mh)/sqrt(N))^(2/d)*/ neval++; kmn = gammamellininvrt(K, t2d, p); for (mm=m,nn=n; mm>=0 && nn <= L[mm+1]; nn<<=1,mm-=m0) gmael(vK,mm+1,nn) = kmn; } if (DEBUGLEVEL >= 1) err_printf("true evaluations: %ld\n", neval); va = lfuninit_vecc_sum(L, M, an, vK, poqk, S->precmax); return bn? mkvec2(va, lfuninit_vecc_sum(L, M, bn, vK, poqk, S->precmax)): va; } static void parse_dom(long k, GEN dom, struct lfunp *S) { long l = lg(dom); if (typ(dom)!=t_VEC) pari_err_TYPE("lfuninit [domain]", dom); if (l == 2) { S->dc = k/2.; S->dw = 0.; S->dh = gtodouble(gel(dom,1)); } else if (l == 3) { S->dc = k/2.; S->dw = gtodouble(gel(dom,1)); S->dh = gtodouble(gel(dom,2)); } else if (l == 4) { S->dc = gtodouble(gel(dom,1)); S->dw = gtodouble(gel(dom,2)); S->dh = gtodouble(gel(dom,3)); } else { pari_err_TYPE("lfuninit [domain]", dom); S->dc = S->dw = S->dh = 0; /*-Wall*/ } if (S->dw < 0 || S->dh < 0) pari_err_TYPE("lfuninit [domain]", dom); } /* do we have dom \subset dom0 ? dom = [center, width, height] */ int sdomain_isincl(long k, GEN dom, GEN dom0) { struct lfunp S0, S; parse_dom(k, dom, &S); parse_dom(k, dom0, &S0); return S0.dc - S0.dw <= S.dc - S.dw && S0.dc + S0.dw >= S.dc + S.dw && S0.dh >= S.dh; } static int checklfuninit(GEN linit, GEN dom, long der, long bitprec) { GEN ldata = linit_get_ldata(linit); GEN domain = lfun_get_domain(linit_get_tech(linit)); return domain_get_der(domain) >= der && domain_get_bitprec(domain) >= bitprec && sdomain_isincl(ldata_get_k(ldata), dom, domain_get_dom(domain)); } GEN lfuninit_make(long t, GEN ldata, GEN molin, GEN domain) { GEN Vga = ldata_get_gammavec(ldata); long d = lg(Vga)-1; long k = ldata_get_k(ldata); GEN k2 = gdivgs(stoi(k), 2); GEN expot = gdivgs(gadd(gmulsg(d, gsubgs(k2, 1)), vecsum(Vga)), 4); GEN eno = ldata_get_rootno(ldata); long prec = nbits2prec( domain_get_bitprec(domain) ); GEN w2 = ginv(gsqrt(eno, prec)); GEN hardy = mkvec4(k2, w2, expot, gammafactor(Vga)); return mkvec3(mkvecsmall(t),ldata, mkvec3(domain, molin, hardy)); } static void lfunparams2(struct lfunp *S) { GEN vprec, L = S->L, an = S->an, bn = S->bn; double sig0, pmax, sub2; long m, nan, nmax, neval, M = S->M; /* try to reduce parameters now we know the a_n (some may be 0) */ if (typ(an) == t_VEC) an = RgV_kill0(an); nan = S->nmax; /* lg(an)-1 may be large than this */ nmax = neval = 0; if (!bn) for (m = 0; m <= M; m++) { long n = minss(nan, L[m+1]); while (n > 0 && !gel(an,n)) n--; if (n > nmax) nmax = n; neval += n; L[m+1] = n; /* reduce S->L[m+1] */ } else { if (typ(bn) == t_VEC) bn = RgV_kill0(bn); for (m = 0; m <= M; m++) { long n = minss(nan, L[m+1]); while (n > 0 && !gel(an,n) && !gel(bn,n)) n--; if (n > nmax) nmax = n; neval += n; L[m+1] = n; /* reduce S->L[m+1] */ } } if (DEBUGLEVEL >= 1) err_printf("expected evaluations: %ld\n", neval); for (; M > 0; M--) if (L[M+1]) break; setlg(L, M+2); S->M = M; S->nmax = nmax; pmax = 0; sig0 = S->MAXs/S->m0; sub2 = S->sub / M_LN2; vprec = cgetg(S->M+2, t_VEC); /* compute accuracy to which we will need k[m,n] = K(n*exp(mh)/sqrt(N)) * vprec[m+1,n] = absolute accuracy to which we need k[m,n] */ for (m = 0; m <= S->M; m++) { double c = S->D + maxdd(m*sig0 - sub2, 0); GEN t; if (!S->k1) { t = const_vecsmall(L[m+1]+1, c); pmax = maxdd(pmax,c); } else { long n; t = cgetg(L[m+1]+1, t_VECSMALL); for (n = 1; n <= L[m+1]; n++) { t[n] = c + S->k1 * log2(n); pmax = maxdd(pmax, t[n]); } } gel(vprec,m+1) = t; } S->vprec = vprec; S->Dmax = pmax; S->precmax = nbits2prec(pmax); } static GEN lfun_init_theta(GEN ldata, GEN eno, struct lfunp *S) { GEN an2, dual, tdom = NULL, Vga = ldata_get_gammavec(ldata); long L; if (eno) L = S->nmax; else { tdom = dbltor(sqrt(0.5)); L = maxss(S->nmax, lfunthetacost(ldata, tdom, 0, S->D)); } dual = ldata_get_dual(ldata); S->an = ldata_vecan(ldata_get_an(ldata), L, S->precmax); S->bn = typ(dual)==t_INT? NULL: ldata_vecan(dual, S->nmax, S->precmax); if (!vgaell(Vga)) lfunparams2(S); else { S->an = antwist(S->an, Vga, S->precmax); if (S->bn) S->bn = antwist(S->bn, Vga, S->precmax); S->vprec = NULL; } an2 = lg(Vga)-1 == 1? antwist(S->an, Vga, S->precmax): S->an; return lfunthetainit0(ldata, tdom, an2, 0, S->Dmax, 0); } GEN lfuncost(GEN L, GEN dom, long der, long bitprec) { pari_sp av = avma; GEN ldata = lfunmisc_to_ldata_shallow(L); long k = ldata_get_k(ldata); struct lfunp S; parse_dom(k, dom, &S); lfunparams(ldata, der, bitprec, &S); avma = av; return mkvecsmall2(S.nmax, S.Dmax); } GEN lfuncost0(GEN L, GEN dom, long der, long bitprec) { pari_sp av = avma; GEN C; if (is_linit(L)) { GEN tech = linit_get_tech(L); GEN domain = lfun_get_domain(tech); dom = domain_get_dom(domain); der = domain_get_der(domain); bitprec = domain_get_bitprec(domain); if (linit_get_type(L) == t_LDESC_PRODUCT) { GEN v = lfunprod_get_fact(linit_get_tech(L)), F = gel(v,1); long i, l = lg(F); C = cgetg(l, t_VEC); for (i = 1; i < l; ++i) gel(C, i) = zv_to_ZV( lfuncost(gel(F,i), dom, der, bitprec) ); return gerepileupto(av, C); } } if (!dom) pari_err_TYPE("lfuncost [missing s domain]", L); C = lfuncost(L,dom,der,bitprec); return gerepileupto(av, zv_to_ZV(C)); } GEN lfuninit(GEN lmisc, GEN dom, long der, long bitprec) { pari_sp ltop = avma; GEN R, h, theta, ldata, qk, poqk, pol, eno, r, domain, molin; long k; struct lfunp S; if (is_linit(lmisc)) { long t = linit_get_type(lmisc); if (t==t_LDESC_INIT || t==t_LDESC_PRODUCT) { if (checklfuninit(lmisc, dom, der, bitprec)) return lmisc; pari_warn(warner,"lfuninit: insufficient initialization"); } } ldata = lfunmisc_to_ldata_shallow(lmisc); if (ldata_get_type(ldata)==t_LFUN_NF) { GEN T = gel(ldata_get_an(ldata), 2); return lfunzetakinit(T, dom, der, 0, bitprec); } k = ldata_get_k(ldata); parse_dom(k, dom, &S); lfunparams(ldata, der, bitprec, &S); r = ldata_get_residue(ldata); /* Note: all guesses should already have been performed (thetainit more * expensive than needed: should be either tdom = 1 or bitprec = S.D). * BUT if the root number / polar part do not have an algebraic * expression, there is no way to do this until we know the * precision, i.e. now. So we can't remove guessing code from here and * lfun_init_theta */ if (r && isintzero(r)) eno = NULL; else { eno = ldata_get_rootno(ldata); if (isintzero(eno)) eno = NULL; } theta = lfun_init_theta(ldata, eno, &S); if (eno && lg(ldata)==7) R = gen_0; else { GEN v = lfunrootres(theta, S.D); ldata = shallowcopy(ldata); gel(ldata, 6) = gel(v,3); r = gel(v,1); if (isintzero(r)) setlg(ldata,7); /* no pole */ else gel(ldata, 7) = r; R = lfunrtoR(ldata, nbits2prec(S.D)); } h = divru(mplog2(S.precmax), S.m0); k = ldata_get_k(ldata); qk = gprec_w(mpexp(gmul2n(gmulsg(k,h), -1)), S.precmax); /* exp(kh/2) */ poqk = gpowers(qk, S.M); pol = lfuninit_vecc(theta, h, &S, poqk); molin = mkvec3(h, pol, R); domain = mkvec2(dom, mkvecsmall2(der, bitprec)); return gerepilecopy(ltop, lfuninit_make(t_LDESC_INIT, ldata, molin, domain)); } GEN lfuninit0(GEN lmisc, GEN dom, long der, long bitprec) { GEN z = lfuninit(lmisc, dom, der, bitprec); return z == lmisc? gcopy(z): z; } /* If s is a pole of Lambda, return polar part at s; else return NULL */ static GEN lfunpoleresidue(GEN R, GEN s) { long j; for (j = 1; j < lg(R); j++) { GEN Rj = gel(R, j), be = gel(Rj, 1); if (gequal(s, be)) return gel(Rj, 2); } return NULL; } /* Compute contribution of polar part at s when not a pole. */ static GEN veccothderivn(GEN a, long n) { long i; pari_sp av = avma; GEN c = pol_x(0), cp = mkpoln(3, gen_m1, gen_0, gen_1); GEN v = cgetg(n+2, t_VEC); gel(v, 1) = poleval(c, a); for(i = 2; i <= n+1; i++) { c = ZX_mul(ZX_deriv(c), cp); gel(v, i) = gdiv(poleval(c, a), mpfact(i-1)); } return gerepilecopy(av, v); } static GEN polepart(long n, GEN h, GEN C) { GEN h2n = gpowgs(gdiv(h, gen_2), n-1); GEN res = gmul(h2n, gel(C,n)); return odd(n)? res : gneg(res); } static GEN lfunsumcoth(GEN R, GEN s, GEN h, long prec) { long i,j; GEN S = gen_0; for (j = 1; j < lg(R); ++j) { GEN r = gel(R,j), be = gel(r,1), Rj = gel(r, 2); long e = valp(Rj); GEN z1 = gexpm1(gmul(h, gsub(s,be)), prec); /* exp(h(s-beta))-1 */ GEN c1 = gaddgs(gdivsg(2, z1), 1); /* coth((h/2)(s-beta)) */ GEN C1 = veccothderivn(c1, 1-e); for (i = e; i < 0; i++) { GEN Rbe = mysercoeff(Rj, i); GEN p1 = polepart(-i, h, C1); S = gadd(S, gmul(Rbe, p1)); } } return gmul2n(S, -1); } static GEN lfunlambda_OK(GEN linit, GEN s, GEN sdom, long bitprec); /* L is a t_LDESC_PRODUCT Linit */ static GEN lfunlambda_product(GEN L, GEN s, GEN sdom, long bitprec) { GEN ldata = linit_get_ldata(L), v = lfunprod_get_fact(linit_get_tech(L)); GEN r = gen_1, F = gel(v,1), E = gel(v,2), C = gel(v,3), cs = conj_i(s); long i, l = lg(F), isreal = gequal(imag_i(s), imag_i(cs)); for (i = 1; i < l; ++i) { GEN f = lfunlambda_OK(gel(F, i), s, sdom, bitprec); if (E[i]) r = gmul(r, gpowgs(f, E[i])); if (C[i]) { GEN fc = isreal? f: lfunlambda_OK(gel(F, i), cs, sdom, bitprec); r = gmul(r, gpowgs(conj_i(fc), C[i])); } } return (ldata_isreal(ldata) && gequal0(imag_i(s)))? real_i(r): r; } /* s a t_SER */ static long der_level(GEN s) { return signe(s)? lg(s)-3: valp(s)-1; } /* s a t_SER; return coeff(s, X^0) */ static GEN ser_coeff0(GEN s) { return simplify_shallow(polcoef_i(s, 0, -1)); } static GEN get_domain(GEN s, GEN *dom, long *der) { GEN sa = s; *der = 0; switch(typ(s)) { case t_POL: case t_RFRAC: s = toser_i(s); case t_SER: *der = der_level(s); sa = ser_coeff0(s); } *dom = mkvec3(real_i(sa), gen_0, gabs(imag_i(sa),DEFAULTPREC)); return s; } /* assume lmisc is an linit, s went through get_domain and s/bitprec belong * to domain */ static GEN lfunlambda_OK(GEN linit, GEN s, GEN sdom, long bitprec) { GEN eno, ldata, tech, h, pol; GEN S, S0 = NULL, k2, cost; long prec, prec0; struct lfunp D, D0; if (linit_get_type(linit) == t_LDESC_PRODUCT) return lfunlambda_product(linit, s, sdom, bitprec); ldata = linit_get_ldata(linit); eno = ldata_get_rootno(ldata); tech = linit_get_tech(linit); h = lfun_get_step(tech); prec = realprec(h); /* try to reduce accuracy */ parse_dom(0, sdom, &D0); parse_dom(0, domain_get_dom(lfun_get_domain(tech)), &D); if (0.8 * D.dh > D0.dh) { cost = lfuncost(linit, sdom, typ(s)==t_SER? der_level(s): 0, bitprec); prec0 = nbits2prec(cost[2]); if (prec0 < prec) { prec = prec0; h = gprec_w(h, prec); } } pol = lfun_get_pol(tech); s = gprec_w(s, prec); if (ldata_get_residue(ldata)) { GEN R = lfun_get_Residue(tech); GEN Ra = lfunpoleresidue(R, s); if (Ra) return gprec_w(Ra, nbits2prec(bitprec)); S0 = lfunsumcoth(R, s, h, prec); } k2 = lfun_get_k2(tech); if (typ(pol)==t_POL && typ(s) != t_SER && gequal(real_i(s), k2)) { /* on critical line: shortcut */ GEN polz, b = imag_i(s); polz = gequal0(b)? poleval(pol,gen_1): poleval(pol, expIr(gmul(h,b))); S = gadd(polz, gmul(eno, conj_i(polz))); } else { GEN z = gexp(gmul(h, gsub(s, k2)), prec); GEN zi = ginv(z), zc = conj_i(zi); if (typ(pol)==t_POL) S = gadd(poleval(pol, z), gmul(eno, conj_i(poleval(pol, zc)))); else S = gadd(poleval(gel(pol,1), z), gmul(eno, poleval(gel(pol,2), zi))); } if (S0) S = gadd(S,S0); return gprec_w(gmul(S,h), nbits2prec(bitprec)); } GEN lfunlambda(GEN lmisc, GEN s, long bitprec) { pari_sp av = avma; GEN linit, dom, z; long der; s = get_domain(s, &dom, &der); linit = lfuninit(lmisc, dom, der, bitprec); z = lfunlambda_OK(linit,s, dom, bitprec); return gerepilecopy(av, z); } /* assume lmisc is an linit, s went through get_domain and s/bitprec belong * to domain */ static GEN lfun_OK(GEN linit, GEN s, GEN sdom, long bitprec) { GEN N, gas, S, FVga, res, ss = s; long prec = nbits2prec(bitprec); FVga = lfun_get_factgammavec(linit_get_tech(linit)); S = lfunlambda_OK(linit, s, sdom, bitprec); if (typ(S)==t_SER) { long d = lg(S) - 2 + fracgammadegree(FVga); if (typ(s) == t_SER) ss = sertoser(s, d); else ss = deg1ser_shallow(gen_1, s, varn(S), d); } gas = gammafactproduct(FVga, ss, prec); N = ldata_get_conductor(linit_get_ldata(linit)); res = gdiv(S, gmul(gpow(N, gdivgs(ss, 2), prec), gas)); if (typ(s)!=t_SER && typ(res)==t_SER) { long v = valp(res); if (v > 0) return gen_0; if (v == 0) res = gel(res, 2); else setlg(res, minss(lg(res), 2-v)); } return gprec_w(res, prec); } GEN lfun(GEN lmisc, GEN s, long bitprec) { pari_sp av = avma; GEN linit, dom, z; long der; s = get_domain(s, &dom, &der); linit = lfuninit(lmisc, dom, der, bitprec); z = lfun_OK(linit, s, dom, bitprec); return gerepilecopy(av, z); } /* given a t_SER a+x*s(x), return x*s(x), shallow */ static GEN sersplit1(GEN s, GEN *head) { long i, l = lg(s); GEN y; *head = simplify_shallow(mysercoeff(s, 0)); if (valp(s) > 0) return s; y = cgetg(l-1, t_SER); y[1] = s[1]; setvalp(y, 1); for (i=3; i < l; i++) gel(y,i-1) = gel(s,i); return normalize(y); } /* n-th derivative of t_SER x, n > 0 */ static GEN derivnser(GEN x, long n) { long i, vx = varn(x), e = valp(x), lx = lg(x); GEN y; if (ser_isexactzero(x)) { x = gcopy(x); if (e) setvalp(x,e-n); return x; } if (e < 0 || e >= n) { y = cgetg(lx,t_SER); y[1] = evalsigne(1)| evalvalp(e-n) | evalvarn(vx); for (i=0; i 0 of L (flag = 0) or Lambda (flag = 1) */ static GEN lfunderiv(GEN lmisc, long m, GEN s, long flag, long bitprec) { pari_sp ltop = avma; GEN res, S = NULL, linit, dom; long der, prec = nbits2prec(bitprec); if (m <= 0) pari_err_DOMAIN("lfun", "D", "<=", gen_0, stoi(m)); s = get_domain(s, &dom, &der); linit = lfuninit(lmisc, dom, der + m, bitprec); if (typ(s) == t_SER) { long v, l = lg(s)-1; GEN sh; if (valp(s) < 0) pari_err_DOMAIN("lfun","valuation", "<", gen_0, s); S = sersplit1(s, &sh); v = valp(S); s = deg1ser_shallow(gen_1, sh, varn(S), m + (l+v-1)/v); } else { long ex = lfunlambdaord(linit, s); /* HACK: pretend lfuninit was done to right accuracy */ s = deg1ser_shallow(gen_1, s, 0, m+1+ex); } res = flag ? lfunlambda_OK(linit, s, dom, bitprec): lfun_OK(linit, s, dom, bitprec); if (S) res = gsubst(derivnser(res, m), varn(S), S); else if (typ(res)==t_SER) { long v = valp(res); if (v > m) { avma = ltop; return gen_0; } if (v >= 0) res = gmul(mysercoeff(res, m), mpfact(m)); else res = derivnser(res, m); } return gerepilecopy(ltop, gprec_w(res, prec)); } GEN lfunlambda0(GEN lmisc, GEN s, long der, long bitprec) { return der ? lfunderiv(lmisc, der, s, 1, bitprec): lfunlambda(lmisc, s, bitprec); } GEN lfun0(GEN lmisc, GEN s, long der, long bitprec) { return der ? lfunderiv(lmisc, der, s, 0, bitprec): lfun(lmisc, s, bitprec); } GEN lfunhardy(GEN lmisc, GEN t, long bitprec) { pari_sp ltop = avma; long prec = nbits2prec(bitprec), k, d; GEN argz, z, linit, ldata, tech, dom, w2, k2, expot, h, a; switch(typ(t)) { case t_INT: case t_FRAC: case t_REAL: break; default: pari_err_TYPE("lfunhardy",t); } ldata = lfunmisc_to_ldata_shallow(lmisc); if (!is_linit(lmisc)) lmisc = ldata; k = ldata_get_k(ldata); d = ldata_get_degree(ldata); dom = mkvec3(dbltor(k/2.), gen_0, gabs(t,LOWDEFAULTPREC)); linit = lfuninit(lmisc, dom, 0, bitprec); tech = linit_get_tech(linit); w2 = lfun_get_w2(tech); k2 = lfun_get_k2(tech); expot = lfun_get_expot(tech); z = mkcomplex(k2, t); argz = gatan(gdiv(t, k2), prec); /* more accurate than garg since k/2 \in Q */ /* prec may have increased: don't lose accuracy if |z|^2 is exact */ prec = precision(argz); a = gsub(gmulsg(d, gmul(t, gmul2n(argz,-1))), gmul(expot,glog(gnorm(z),prec))); h = lfunlambda_OK(linit, z, mkvec(t), bitprec); if (typ(ldata_get_dual(ldata))==t_INT) h = mulreal(h, w2); else h = gmul(h, w2); if (typ(h) == t_COMPLEX && gexpo(imag_i(h)) < -(bitprec >> 1)) h = real_i(h); return gerepileupto(ltop, gmul(h, gexp(a, prec))); } /* L = log(t); return \sum_{i = 0}^{v-1} R[-i-1] L^i/i! */ static GEN theta_pole_contrib(GEN R, long v, GEN L) { GEN s = mysercoeff(R,-v); long i; for (i = v-1; i >= 1; i--) s = gadd(mysercoeff(R,-i), gdivgs(gmul(s,L), i)); return s; } /* subtract successively rather than adding everything then subtracting. * The polar part is "large" and suffers from cancellation: a little stabler * this way */ static GEN theta_add_polar_part(GEN S, GEN R, GEN t, long prec) { GEN logt = NULL; long j, l = lg(R); for (j = 1; j < l; j++) { GEN Rj = gel(R,j), b = gel(Rj,1), Rb = gel(Rj,2); long v = -valp(Rb); if (v > 1 && !logt) logt = glog(t, prec); S = gsub(S, gmul(theta_pole_contrib(Rb,v,logt), gpow(t,b,prec))); } return S; } /* Check whether the coefficients, conductor, weight, polar part and root * number are compatible with the functional equation at t0 and 1/t0. * Different from lfunrootres. */ long lfuncheckfeq(GEN lmisc, GEN t0, long bitprec) { GEN ldata, theta, thetad, t0i, S0, S0i, w, eno; long e, prec; pari_sp av; if (is_linit(lmisc) && linit_get_type(lmisc)==t_LDESC_PRODUCT) { GEN v = lfunprod_get_fact(linit_get_tech(lmisc)), F = gel(v,1); long i, b = -bitprec, l = lg(F); for (i = 1; i < l; i++) b = maxss(b, lfuncheckfeq(gel(F,i), t0, bitprec)); return b; } av = avma; prec = nbits2prec(bitprec); if (!t0) { t0 = gadd(gdivgs(mppi(prec), 3), gdivgs(gen_I(), 7)); t0i = ginv(t0); } else if (gcmpgs(gnorm(t0), 1) < 0) { t0i = t0; t0 = ginv(t0); } else t0i = ginv(t0); /* |t0| >= 1 */ theta = lfunthetacheckinit(lmisc, t0i, 0, bitprec); ldata = linit_get_ldata(theta); thetad = theta_dual(theta, ldata_get_dual(ldata)); if (thetad) S0 = lfuntheta(thetad, t0, 0, bitprec); else S0 = conj_i(lfuntheta(theta, conj_i(t0), 0, bitprec)); S0i = lfuntheta(theta, t0i, 0, bitprec); eno = ldata_get_rootno(ldata); if (ldata_get_residue(ldata)) { GEN R = theta_get_R(linit_get_tech(theta)); if (gequal0(R)) { GEN v, r; if (ldata_get_type(ldata) == t_LFUN_NF) { /* inefficient since theta not needed; no need to optimize for this (artificial) query [e.g. lfuncheckfeq(t_POL)] */ GEN T = gel(ldata_get_an(ldata), 2); GEN L = lfunzetakinit(T,zerovec(3),0,0,bitprec); long e = lfuncheckfeq(L,t0,bitprec); avma = av; return e; } v = lfunrootres(theta, bitprec); r = gel(v,1); if (gequal0(eno)) eno = gel(v,3); R = lfunrtoR_i(ldata, r, eno, nbits2prec(bitprec)); } S0i = theta_add_polar_part(S0i, R, t0, prec); } if (gequal0(S0i) || gequal0(S0)) pari_err_PREC("lfuncheckfeq"); w = gdiv(S0i, gmul(S0, gpowgs(t0, ldata_get_k(ldata)))); /* missing rootno: guess it */ if (gequal0(eno)) eno = lfunrootno(theta, bitprec); w = gsub(w, eno); if (thetad) w = gdiv(w, eno); /* |eno| may be large in non-dual case */ e = gexpo(w); avma = av; return e; } /*******************************************************************/ /* Compute root number and residues */ /*******************************************************************/ /* round root number to \pm 1 if close to integer. */ static GEN ropm1(GEN eno, long prec) { long e; GEN r = grndtoi(eno, &e); return (e < -prec2nbits(prec)/2)? r: eno; } /* theta for t=1/sqrt(2) and t2==2t simultaneously, saving 25% of the work. * Assume correct initialization (no thetacheck) */ static void lfunthetaspec(GEN linit, long bitprec, GEN *pv, GEN *pv2) { pari_sp av = avma; GEN t, Vga, an, K, ldata, thetainit, v, v2, vroots; long L, prec, n, d; ldata = linit_get_ldata(linit); thetainit = linit_get_tech(linit); prec = nbits2prec(bitprec); Vga = ldata_get_gammavec(ldata); d = lg(Vga)-1; if (vgaeasytheta(Vga)) { GEN v2 = sqrtr(real2n(1, nbits2prec(bitprec))); GEN v = shiftr(v2,-1); *pv = lfuntheta(linit, v, 0, bitprec); *pv2= lfuntheta(linit, v2, 0, bitprec); return; } an = RgV_kill0( theta_get_an(thetainit) ); L = lg(an)-1; /* to compute theta(1/sqrt(2)) */ t = ginv(gsqrt(gmul2n(ldata_get_conductor(ldata), 1), prec)); /* t = 1/sqrt(2N) */ /* From then on, the code is generic and could be used to compute * theta(t) / theta(2t) without assuming t = 1/sqrt(2) */ K = theta_get_K(thetainit); vroots = mkvroots(d, L, prec); t = gpow(t, gdivgs(gen_2, d), prec); /* rt variant: t->t^(2/d) */ /* v = \sum_{n <= L, n odd} a_n K(nt) */ for (v = gen_0, n = 1; n <= L; n+=2) { GEN tn, Kn, a = gel(an, n); if (!a) continue; tn = gmul(t, gel(vroots,n)); Kn = gammamellininvrt(K, tn, bitprec); v = gadd(v, gmul(a,Kn)); } /* v += \sum_{n <= L, n even} a_n K(nt), v2 = \sum_{n <= L/2} a_n K(2n t) */ for (v2 = gen_0, n = 1; n <= L/2; n++) { GEN t2n, K2n, a = gel(an, n), a2 = gel(an,2*n); if (!a && !a2) continue; t2n = gmul(t, gel(vroots,2*n)); K2n = gammamellininvrt(K, t2n, bitprec); if (a) v2 = gadd(v2, gmul(a, K2n)); if (a2) v = gadd(v, gmul(a2,K2n)); } *pv = v; *pv2 = v2; gerepileall(av, 2, pv,pv2); } static GEN Rtor(GEN a, GEN R, GEN ldata, long prec) { GEN FVga = gammafactor(ldata_get_gammavec(ldata)); GEN Na = gpow(ldata_get_conductor(ldata), gdivgs(a,2), prec); return gdiv(R, gmul(Na, gammafactproduct(FVga, a, prec))); } /* v = theta~(t), vi = theta(1/t) */ static GEN get_eno(GEN R, long k, GEN t, GEN v, GEN vi, long vx, long bitprec, long force) { GEN a0, a1, S = deg1pol(gmul(gpowgs(t,k), gneg(v)), vi, vx); long prec = nbits2prec(bitprec); S = theta_add_polar_part(S, R, t, prec); if (typ(S) != t_POL || degpol(S) != 1) return NULL; a1 = gel(S,3); if (!force && gexpo(a1) < -bitprec/4) return NULL; a0 = gel(S,2); return gdiv(a0, gneg(a1)); } /* Return w using theta(1/t) - w t^k \bar{theta}(t) = polar_part(t,w). * The full Taylor development of L must be known */ GEN lfunrootno(GEN linit, long bitprec) { GEN ldata, t, eno, v, vi, R, thetad; long k, c = 0, prec = nbits2prec(bitprec), vx = fetch_var(); pari_sp av; /* initialize for t > 1/sqrt(2) */ linit = lfunthetacheckinit(linit, dbltor(sqrt(0.5)), 0, bitprec); ldata = linit_get_ldata(linit); k = ldata_get_k(ldata); R = ldata_get_residue(ldata)? lfunrtoR_eno(ldata, pol_x(vx), prec) : cgetg(1, t_VEC); t = gen_1; v = lfuntheta(linit, t, 0, bitprec); thetad = theta_dual(linit, ldata_get_dual(ldata)); vi = !thetad ? conj_i(v): lfuntheta(thetad, t, 0, bitprec); eno = get_eno(R,k,t,vi,v, vx, bitprec, 0); if (!eno && !thetad) { /* t = sqrt(2), vi = theta(1/t), v = theta(t) */ lfunthetaspec(linit, bitprec, &vi, &v); t = sqrtr(utor(2, prec)); eno = get_eno(R,k,t,conj_i(v),vi, vx, bitprec, 0); } av = avma; while (!eno) { t = addsr(1, shiftr(utor(pari_rand(), prec), -2-BITS_IN_LONG)); /* t in [1,1.25[ */ v = thetad? lfuntheta(thetad, t, 0, bitprec) : conj_i(lfuntheta(linit, t, 0, bitprec)); vi = lfuntheta(linit, ginv(t), 0, bitprec); eno = get_eno(R,k,t,v,vi, vx, bitprec, c++ == 5); avma = av; } delete_var(); return ropm1(eno,prec); } /* Find root number and/or residues when L-function coefficients and conductor are known. For the moment at most a single residue allowed. */ GEN lfunrootres(GEN data, long bitprec) { pari_sp ltop = avma; GEN w, r, R, a, b, e, v, v2, be, ldata, linit; long k, prec; ldata = lfunmisc_to_ldata_shallow(data); r = ldata_get_residue(ldata); k = ldata_get_k(ldata); if (r) r = normalize_simple_pole(r, stoi(k)); if (!r || residues_known(r)) { w = lfunrootno(data, bitprec); if (!r) r = R = gen_0; else R = lfunrtoR_eno(ldata, w, nbits2prec(bitprec)); return gerepilecopy(ltop, mkvec3(r, R, w)); } linit = lfunthetacheckinit(data, dbltor(sqrt(0.5)), 0, bitprec); prec = nbits2prec(bitprec); if (lg(r) > 2) pari_err_IMPL("multiple poles in lfunrootres"); /* Now residue unknown, and r = [[be,0]]. */ be = gmael(r, 1, 1); w = ldata_get_rootno(ldata); if (ldata_isreal(ldata) && gequalm1(w)) R = lfuntheta(linit, gen_1, 0, bitprec); else { lfunthetaspec(linit, bitprec, &v2, &v); if (gequalgs(gmulsg(2, be), k)) pari_err_IMPL("pole at k/2 in lfunrootres"); if (gequalgs(be, k)) { GEN p2k = int2n(k); a = conj_i(gsub(gmul(p2k, v), v2)); b = subiu(p2k, 1); e = gmul(gsqrt(p2k, prec), gsub(v2, v)); } else { GEN tk2 = gsqrt(int2n(k), prec); GEN tbe = gpow(gen_2, be, prec); GEN tkbe = gpow(gen_2, gdivgs(gsubsg(k, be), 2), prec); a = conj_i(gsub(gmul(tbe, v), v2)); b = gsub(gdiv(tbe, tkbe), tkbe); e = gsub(gmul(gdiv(tbe, tk2), v2), gmul(tk2, v)); } if (!isintzero(w)) R = gdiv(gsub(e, gmul(a, w)), b); else { /* Now residue unknown, r = [[be,0]], and w unknown. */ GEN t0 = mkfrac(stoi(11),stoi(10)); GEN th1 = lfuntheta(linit, t0, 0, bitprec); GEN th2 = lfuntheta(linit, ginv(t0), 0, bitprec); GEN tbe = gpow(t0, gmulsg(2, be), prec); GEN tkbe = gpow(t0, gsubsg(k, be), prec); GEN tk2 = gpowgs(t0, k); GEN c = conj_i(gsub(gmul(tbe, th1), th2)); GEN d = gsub(gdiv(tbe, tkbe), tkbe); GEN f = gsub(gmul(gdiv(tbe, tk2), th2), gmul(tk2, th1)); GEN D = gsub(gmul(a, d), gmul(b, c)); w = gdiv(gsub(gmul(d, e), gmul(b, f)), D); R = gdiv(gsub(gmul(a, f), gmul(c, e)), D); } } r = normalize_simple_pole(Rtor(be, R, ldata, prec), be); R = lfunrtoR_i(ldata, r, w, prec); return gerepilecopy(ltop, mkvec3(r, R, ropm1(w, prec))); } /*******************************************************************/ /* Zeros */ /*******************************************************************/ struct lhardyz_t { long bitprec, prec; GEN linit; }; static GEN lfunhardyzeros(void *E, GEN t) { struct lhardyz_t *S = (struct lhardyz_t*)E; long prec = S->prec; GEN h = lfunhardy(S->linit, t, S->bitprec); if (typ(h) == t_REAL && realprec(h) < prec) h = gprec_w(h, prec); return h; } /* initialize for computation on critical line up to height h, zero * of order <= m */ static GEN lfuncenterinit(GEN lmisc, double h, long m, long bitprec) { if (m < 0) { /* choose a sensible default */ if (!is_linit(lmisc) || linit_get_type(lmisc) != t_LDESC_INIT) m = 4; else { GEN domain = lfun_get_domain(linit_get_tech(lmisc)); m = domain_get_der(domain); } } return lfuninit(lmisc, mkvec(dbltor(h)), m, bitprec); } long lfunorderzero(GEN lmisc, long m, long bitprec) { pari_sp ltop = avma; GEN eno, ldata, linit, k2; long G, c0, c, st, k; if (is_linit(lmisc) && linit_get_type(lmisc) == t_LDESC_PRODUCT) { GEN M = gmael(linit_get_tech(lmisc), 2,1); long i; for (c=0,i=1; i < lg(M); i++) c += lfunorderzero(gel(M,i), m, bitprec); return c; } linit = lfuncenterinit(lmisc, 0, m, bitprec); ldata = linit_get_ldata(linit); eno = ldata_get_rootno(ldata); G = -bitprec/2; c0 = 0; st = 1; if (ldata_isreal(ldata)) { if (!gequal1(eno)) c0 = 1; st = 2; } k = ldata_get_k(ldata); k2 = gdivgs(stoi(k), 2); for (c = c0;; c += st) if (gexpo(lfun0(linit, k2, c, bitprec)) > G) break; avma = ltop; return c; } GEN lfunzeros(GEN ldata, GEN lim, long divz, long bitprec) { pari_sp ltop = avma; GEN ldataf, linit, N, pi2, cN, pi2div, w, T, Vga, h1, h2; long i, d, W, NEWD, precinit, ct, s, prec = nbits2prec(bitprec); double maxt; GEN maxtr, maxtr1; struct lhardyz_t S; if (typ(lim) == t_VEC) { if (lg(lim) != 3 || gcmp(gel(lim,1),gel(lim,2)) >= 0 || gcmp(gel(lim,1),gen_0) < 0) pari_err_TYPE("lfunzeros",lim); h1 = gel(lim,1); h2 = gel(lim,2); } else { if (gcmp(lim,gen_0) <= 0) pari_err_TYPE("lfunzeros",lim); h1 = gen_0; h2 = lim; } maxt = gtodouble(h2); if (is_linit(ldata) && linit_get_type(ldata) == t_LDESC_PRODUCT) { GEN v, M = gmael(linit_get_tech(ldata), 2,1); long l = lg(M); v = cgetg(l, t_VEC); for (i = 1; i < l; i++) gel(v,i) = lfunzeros(gel(M,i), lim, divz, bitprec); return gerepileupto(ltop, vecsort0(shallowconcat1(v), NULL, 0)); } S.linit = linit = lfuncenterinit(ldata, maxt + 1, -1, bitprec); S.bitprec = bitprec; S.prec = prec; ldataf = linit_get_ldata(linit); Vga = ldata_get_gammavec(ldataf); d = lg(Vga) - 1; N = ldata_get_conductor(ldataf); NEWD = minss((long) ceil(bitprec+(M_PI/(4*M_LN2))*d*maxt), lfun_get_bitprec(linit_get_tech(linit))); precinit = prec; prec = nbits2prec(NEWD); pi2 = Pi2n(1, prec); cN = gdiv(N, gpowgs(Pi2n(-1, prec), d)); cN = gexpo(cN) >= 0? gaddsg(d, gmulsg(2, glog(cN, prec))): stoi(d); pi2div = gdivgs(pi2, labs(divz)); ct = 0; T = h1; if (gequal0(h1)) { GEN r = ldata_get_residue(ldataf); if (!r || gequal0(r)) { ct = lfunorderzero(linit, -1, bitprec); if (ct) T = real2n(-prec2nbits(prec)/(2*ct), prec); } } /* initialize for 100 further zeros, double later if needed */ W = 100 + ct; w = cgetg(W+1,t_VEC); for (i=1; i<=ct; i++) gel(w,i) = gen_0; s = gsigne(lfunhardyzeros(&S, T)); maxtr = h2; maxtr1 = gaddsg(1, maxtr); while (gcmp(T, maxtr1) < 0) { pari_sp av = avma; GEN T0 = T, z; for(;;) { long s0; GEN L; if (gcmp(T, pi2) >= 0) L = gadd(cN, gmulsg(d, glog(gdiv(T, pi2), prec))); else L = cN; T = gadd(T, gdiv(pi2div, L)); if (gcmp(T, maxtr1) > 0) goto END; s0 = gsigne(lfunhardyzeros(&S, T)); if (s0 != s) { s = s0; break; } } T = gerepileupto(av, T); z = zbrent(&S, lfunhardyzeros, T0, T, prec); if (gcmp(z, maxtr) > 0) break; if (typ(z) == t_REAL) z = rtor(z, precinit); /* room for twice as many zeros */ if (ct >= W) { W *= 2; w = vec_lengthen(w, W); } gel(w, ++ct) = z; } END: setlg(w, ct+1); return gerepilecopy(ltop, w); } /*******************************************************************/ /* Guess conductor */ /*******************************************************************/ struct huntcond_t { long k; GEN data, thetad; GEN *pM, *psqrtM, *pMd, *psqrtMd; }; /* M should eventually converge to N, the conductor. L has no pole. */ static GEN wrap1(void *E, GEN M) { struct huntcond_t *S = (struct huntcond_t*)E; GEN data = S->data, thetainit, tk, p1, p1inv; GEN t = mkfrac(stoi(11), stoi(10)); long prec, bitprec; thetainit = linit_get_tech(data); bitprec = theta_get_bitprec(thetainit); prec = nbits2prec(bitprec); *(S->pM) = M; *(S->psqrtM) = gsqrt(M, prec); tk = gpowgs(t, S->k); if (S->thetad) { *(S->pMd) = M; *(S->psqrtMd) = *(S->psqrtM); p1 = lfuntheta(S->thetad, t, 0, bitprec); } else p1 = lfuntheta(data, t, 0, bitprec); p1inv = lfuntheta(data, ginv(t), 0, bitprec); return glog(gabs(gmul(tk, gdiv(p1, p1inv)), prec), prec); } /* M should eventually converge to N, the conductor. L has a pole. */ static GEN wrap2(void *E, GEN M) { struct huntcond_t *S = (struct huntcond_t*)E; GEN data = S->data, t1k, t2k, p1, p1inv, p2, p2inv; GEN thetainit, R; GEN t1 = mkfrac(stoi(11), stoi(10)), t2 = mkfrac(stoi(13), stoi(11)); GEN t1be, t2be, t1bemk, t2bemk, t1kmbe, t2kmbe; GEN F11, F12, F21, F22, P1, P2, res; long k = S->k, prec, bitprec; thetainit = linit_get_tech(data); bitprec = theta_get_bitprec(thetainit); prec = nbits2prec(bitprec); *(S->pM) = M; *(S->psqrtM) = gsqrt(M, prec); p1 = lfuntheta(data, t1, 0, bitprec); p2 = lfuntheta(data, t2, 0, bitprec); p1inv = lfuntheta(data, ginv(t1), 0, bitprec); p2inv = lfuntheta(data, ginv(t2), 0, bitprec); t1k = gpowgs(t1, k); t2k = gpowgs(t2, k); R = theta_get_R(thetainit); if (typ(R) == t_VEC) { GEN be = gmael(R, 1, 1); t1be = gpow(t1, be, prec); t1bemk = gdiv(gsqr(t1be), t1k); t2be = gpow(t2, be, prec); t2bemk = gdiv(gsqr(t2be), t2k); t1kmbe = gdiv(t1k, t1be); t2kmbe = gdiv(t2k, t2be); } else { /* be = k */ t1be = t1k; t1bemk = t1k; t1kmbe = gen_1; t2be = t2k; t2bemk = t2k; t2kmbe = gen_1; } F11 = conj_i(gsub(gmul(gsqr(t1be), p1), p1inv)); F12 = conj_i(gsub(gmul(gsqr(t2be), p2), p2inv)); F21 = gsub(gmul(t1k, p1), gmul(t1bemk, p1inv)); F22 = gsub(gmul(t2k, p2), gmul(t2bemk, p2inv)); P1 = gsub(gmul(t1bemk, t1be), t1kmbe); P2 = gsub(gmul(t2bemk, t2be), t2kmbe); res = gdiv(gsub(gmul(P2,F21), gmul(P1,F22)), gsub(gmul(P2,F11), gmul(P1,F12))); return glog(gabs(res, prec), prec); } /* If flag = 0 (default) return all conductors found as integers. If flag = 1, return the approximations, not the integers. If flag = 2, return all, even nonintegers. */ static GEN checkconductor(GEN v, long bit, long flag) { GEN w; long e, j, k, l = lg(v); if (flag == 2) return v; w = cgetg(l, t_VEC); for (j = k = 1; j < l; j++) { GEN N = grndtoi(gel(v,j), &e); if (e < -bit) gel(w,k++) = flag ? gel(v,j): N; } if (k == 2) return gel(w,1); setlg(w,k); return w; } static void parse_maxcond(GEN maxcond, GEN *pm, GEN *pM) { GEN m = gen_1, M; if (!maxcond) M = utoipos(10000); else if (typ(maxcond) == t_VEC) { if (lg(maxcond) != 3) pari_err_TYPE("lfunconductor", maxcond); m = gel(maxcond,1); M = gel(maxcond,2); } else M = maxcond; m = (typ(m) == t_INT)? gsub(m,ghalf): gfloor(m); if (signe(m) <= 0) m = ghalf; M = (typ(M) == t_INT)? addiu(M, 1): gceil(M); *pm = m; *pM = M; } GEN lfunconductor(GEN data, GEN maxcond, long flag, long bitprec) { struct huntcond_t S; pari_sp ltop = avma; GEN ld, r, v, ldata, theta, thetad, m, M, tdom; GEN (*eval)(void *, GEN); bitprec = 3*bitprec/2; ldata = lfunmisc_to_ldata_shallow(data); parse_maxcond(maxcond, &m,&M); r = ldata_get_residue(ldata); if (r && typ(r) == t_VEC) { if (lg(r) > 2) pari_err_IMPL("multiple poles in lfunconductor"); r = gmael(r,1,2); } if (!r) { eval = wrap1; tdom = mkfrac(stoi(10), stoi(11)); } else { eval = wrap2; tdom = mkfrac(stoi(11), stoi(13)); } ld = shallowcopy(ldata); gel(ld, 5) = M; theta = lfunthetainit_i(ld, tdom, 0, bitprec); thetad = theta_dual(theta, ldata_get_dual(ldata)); gel(theta,3) = shallowcopy(linit_get_tech(theta)); S.k = ldata_get_k(ldata); S.data = theta; S.thetad = thetad; S.pM = &gel(linit_get_ldata(theta),5); S.psqrtM = &gel(linit_get_tech(theta),7); if (thetad) { S.pMd = &gel(linit_get_ldata(thetad),5); S.psqrtMd = &gel(linit_get_tech(thetad),7); } v = solvestep((void*)&S, eval, m, M, gen_2, 14, nbits2prec(bitprec)); return gerepilecopy(ltop, checkconductor(v, bitprec/2, flag)); } /* assume chi primitive */ static GEN znchargauss_i(GEN G, GEN chi, long bitprec) { GEN z, q, F = znstar_get_N(G); long prec; if (equali1(F)) return gen_1; prec = nbits2prec(bitprec); q = sqrtr_abs(itor(F, prec)); z = lfuntheta(mkvec2(G,chi), gen_1, 0, bitprec); if (gexpo(z) < 10 - bitprec) { if (equaliu(F,300)) { GEN z = rootsof1u_cx(25, prec); GEN n = znconreyexp(G, chi); if (equaliu(n, 131)) return gmul(q, gpowgs(z,14)); if (equaliu(n, 71)) return gmul(q, gpowgs(z,11)); } if (equaliu(F,600)) { GEN z = rootsof1u_cx(25, prec); GEN n = znconreyexp(G, chi); if (equaliu(n, 491)) return gmul(q, gpowgs(z,7)); if (equaliu(n, 11)) return gmul(q, gpowgs(z,18)); } pari_err_BUG("znchargauss [ Theta(chi,1) = 0 ]"); } z = gmul(gdiv(z, conj_i(z)), q); if (zncharisodd(G,chi)) z = mulcxI(z); return z; } static GEN Z_radical(GEN N, long *om) { GEN P = gel(Z_factor(N), 1); *om = lg(P)-1; return ZV_prod(P); } GEN znchargauss(GEN G, GEN chi, GEN a, long bitprec) { GEN v, T, N, F, b0, b1, b2, bF, a1, aF, A, r, GF, tau, B, faB, u, S; long omb0, prec = nbits2prec(bitprec); pari_sp av = avma; if (typ(chi) != t_COL) chi = znconreylog(G,chi); T = znchartoprimitive(G, chi); GF = gel(T,1); chi = gel(T,2); /* now primitive */ N = znstar_get_N(G); F = znstar_get_N(GF); if (equalii(N,F)) b1 = bF = gen_1; else { v = Z_ppio(diviiexact(N,F), F); bF = gel(v,2); /* (N/F, F^oo) */ b1 = gel(v,3); /* cofactor */ } if (!a) a = a1 = aF = gen_1; else { if (typ(a) != t_INT) pari_err_TYPE("znchargauss",a); a = modii(a, N); v = Z_ppio(a, F); aF = gel(v,2); a1 = gel(v,3); } if (!equalii(aF, bF)) { avma = av; return gen_0; } b0 = Z_radical(b1, &omb0); b2 = diviiexact(b1, b0); A = dvmdii(a1, b2, &r); if (r != gen_0) { avma = av; return gen_0; } B = gcdii(A,b0); faB = Z_factor(B); /* squarefree */ S = eulerphi(mkvec2(B,faB)); if (odd(omb0 + lg(gel(faB,1))-1)) S = negi(S); /* moebius(b0/B) * phi(B) */ S = mulii(S, mulii(aF,b2)); tau = znchargauss_i(GF, chi, bitprec); u = Fp_div(b0, A, F); if (!equali1(u)) { GEN ord = zncharorder(GF, chi), z = rootsof1_cx(ord, prec); tau = gmul(tau, znchareval(GF, chi, u, mkvec2(z,ord))); } return gerepileupto(av, gmul(tau, S)); } pari-2.11.2/src/basemath/hyperell.c0000644000175000017500000005223113447371554015541 0ustar billbill/* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** HYPERELLIPTIC CURVES **/ /** **/ /********************************************************************/ #include "pari.h" #include "paripriv.h" /* Implementation of Kedlaya Algorithm for counting point on hyperelliptic curves by Bill Allombert based on a GP script by Bernadette Perrin-Riou. References: Pierrick Gaudry and Nicolas G\"urel Counting Points in Medium Characteristic Using Kedlaya's Algorithm Experiment. Math. Volume 12, Number 4 (2003), 395-402. http://projecteuclid.org/euclid.em/1087568016 Harrison, M. An extension of Kedlaya's algorithm for hyperelliptic curves. Journal of Symbolic Computation, 47 (1) (2012), 89-101. http://arxiv.org/pdf/1006.4206v3.pdf */ /* We use the basis of differentials (x^i*dx/y^k) (i=1 to 2*g-1), with k either 1 or 3, depending on p and d, see Harrison paper */ static long get_basis(long p, long d) { if (odd(d)) return p < d-1 ? 3 : 1; else return 2*p <= d-2 ? 3 : 1; } static GEN FpXXQ_red(GEN S, GEN T, GEN p) { pari_sp av = avma; long i, dS = degpol(S); GEN A, C; if (signe(S)==0) return pol_0(varn(T)); A = cgetg(dS+3, t_POL); C = pol_0(varn(T)); for(i=dS; i>0; i--) { GEN Si = FpX_add(C, gel(S,i+2), p); GEN R, Q = FpX_divrem(Si, T, p, &R); gel(A,i+2) = R; C = Q; } gel(A,2) = FpX_add(C, gel(S,2), p); A[1] = S[1]; return gerepilecopy(av, FpXX_renormalize(A,dS+3)); } static GEN FpXXQ_sqr(GEN x, GEN T, GEN p) { pari_sp av = avma; long n = degpol(T); GEN z = FpX_red(ZXX_sqr_Kronecker(x, n), p); z = Kronecker_to_ZXX(z, n, varn(T)); return gerepileupto(av, FpXXQ_red(z, T, p)); } static GEN FpXXQ_mul(GEN x, GEN y, GEN T, GEN p) { pari_sp av = avma; long n = degpol(T); GEN z = FpX_red(ZXX_mul_Kronecker(x, y, n), p); z = Kronecker_to_ZXX(z, n, varn(T)); return gerepileupto(av, FpXXQ_red(z, T, p)); } static GEN ZpXXQ_invsqrt(GEN S, GEN T, ulong p, long e) { pari_sp av = avma, av2; ulong mask; long v = varn(S), n=1; GEN a = pol_1(v); if (e <= 1) return gerepilecopy(av, a); mask = quadratic_prec_mask(e); av2 = avma; for (;mask>1;) { GEN q, q2, q22, f, fq, afq; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; q = powuu(p,n); q2 = powuu(p,n2); f = RgX_sub(FpXXQ_mul(FpXX_red(S, q), FpXXQ_sqr(a, T, q), T, q), pol_1(v)); fq = ZXX_Z_divexact(f, q2); q22 = shifti(addiu(q2,1),-1); afq = FpXX_Fp_mul(FpXXQ_mul(a, fq, T, q2), q22, q2); a = RgX_sub(a, ZXX_Z_mul(afq, q2)); if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_invsqrt, e = %ld", n); a = gerepileupto(av2, a); } } return gerepileupto(av, a); } static GEN to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; } static void is_sing(GEN H, ulong p) { pari_err_DOMAIN("hyperellpadicfrobenius","H","is singular at",utoi(p),H); } static void get_UV(GEN *U, GEN *V, GEN T, ulong p, long e) { GEN q = powuu(p,e), d; GEN dT = FpX_deriv(T, q); GEN R = polresultantext(T, dT); long v = varn(T); if (dvdiu(gel(R,3),p)) is_sing(T, p); d = Fp_inv(gel(R,3), q); *U = FpX_Fp_mul(FpX_red(to_ZX(gel(R,1),v),q),d,q); *V = FpX_Fp_mul(FpX_red(to_ZX(gel(R,2),v),q),d,q); } static GEN frac_to_Fp(GEN a, GEN b, GEN p) { GEN d = gcdii(a, b); return Fp_div(diviiexact(a, d), diviiexact(b, d), p); } static GEN ZpXXQ_frob(GEN S, GEN U, GEN V, long k, GEN T, ulong p, long e) { pari_sp av = avma, av2; long i, pr = degpol(S), dT = degpol(T), vT = varn(T); GEN q = powuu(p,e); GEN Tp = FpX_deriv(T, q), Tp1 = RgX_shift_shallow(Tp, 1); GEN M = to_ZX(gel(S,pr+2),vT) , R; av2 = avma; for(i = pr-1; i>=k; i--) { GEN A, B, H, Bc; ulong v, r; H = FpX_divrem(FpX_mul(V,M,q), T, q, &B); A = FpX_add(FpX_mul(U,M,q), FpX_mul(H, Tp, q),q); v = u_lvalrem(2*i+1,p,&r); Bc = ZX_deriv(B); Bc = FpX_Fp_mul(ZX_Z_divexact(Bc,powuu(p,v)),Fp_div(gen_2, utoi(r), q), q); M = FpX_add(to_ZX(gel(S,i+2),vT), FpX_add(A, Bc, q), q); if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_frob, step 1, i = %ld", i); M = gerepileupto(av2, M); } } if (degpol(M)=1; i--) { GEN B, c; R = RgX_shift_shallow(R, 1); gel(R,2) = gel(M, i+1); if (degpol(R) < dT) continue; B = FpX_add(FpX_mulu(T, 2*i, q), Tp1, q); c = frac_to_Fp(leading_coeff(R), leading_coeff(B), q); R = FpX_sub(R, FpX_Fp_mul(B, c, q), q); if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_frob, step 2, i = %ld", i); R = gerepileupto(av2, R); } } if (degpol(R)==dT-1) { GEN c = frac_to_Fp(leading_coeff(R), leading_coeff(Tp), q); R = FpX_sub(R, FpX_Fp_mul(Tp, c, q), q); return gerepileupto(av, R); } else return gerepilecopy(av, R); } static GEN revdigits(GEN v) { long i, n = lg(v)-1; GEN w = cgetg(n+2, t_POL); w[1] = evalsigne(1)|evalvarn(0); for (i=0; i1) timer_start(&ti); Q = revdigits(FpX_digits(A,T,p)); n = degpol(Q); if (DEBUGLEVEL>1) timer_printf(&ti,"reddigits"); sQ = FpXXQ_mul(s,Q,T,p); if (DEBUGLEVEL>1) timer_printf(&ti,"redmul"); qS = RgX_shift_shallow(sQ,m-n); v = ZX_val(sQ); if (n > m + v) { long i, l = n-m-v; GEN rS = cgetg(l+1,t_VEC); for (i = l-1; i >=0 ; i--) gel(rS,i+1) = to_ZX(gel(sQ, 1+v+l-i), vT); rS = FpXV_FpX_fromdigits(rS,T,p); gel(qS,2) = FpX_add(FpX_mul(rS, T, p), gel(qS, 2), p); if (DEBUGLEVEL>1) timer_printf(&ti,"redadd"); } return qS; } static GEN ZC_to_padic(GEN C, GEN q) { long i, l = lg(C); GEN V = cgetg(l,t_COL); for(i = 1; i < l; i++) gel(V, i) = gadd(gel(C, i), q); return V; } static GEN ZM_to_padic(GEN M, GEN q) { long i, l = lg(M); GEN V = cgetg(l,t_MAT); for(i = 1; i < l; i++) gel(V, i) = ZC_to_padic(gel(M, i), q); return V; } static GEN ZX_to_padic(GEN P, GEN q) { long i, l = lg(P); GEN Q = cgetg(l, t_POL); Q[1] = P[1]; for (i=2; i1) timer_start(&ti); s = revdigits(FpX_digits(RgX_inflate(Q, p), Q, pN1)); if (DEBUGLEVEL>1) timer_printf(&ti,"s1"); s = ZpXXQ_invsqrt(s, Q, p, N); if (k==3) s = FpXXQ_mul(s, FpXXQ_sqr(s, Q, pN1), Q, pN1); if (DEBUGLEVEL>1) timer_printf(&ti,"invsqrt"); get_UV(&U, &V, Q, p, N+1); F = cgetg(d, t_MAT); for (i = 1; i < d; i++) { pari_sp av2 = avma; GEN M, D; D = diff_red(s, monomial(utoi(p),p*i-1,1),(k*p-1)>>1, Q, pN1); if (DEBUGLEVEL>1) timer_printf(&ti,"red"); M = ZpXXQ_frob(D, U, V, (k-1)>>1, Q, p, N + 1); if (DEBUGLEVEL>1) timer_printf(&ti,"frob"); gel(F, i) = gerepilecopy(av2, RgX_to_RgC(M, d-1)); } return gerepileupto(av, F); } GEN hyperellpadicfrobenius(GEN H, ulong p, long n) { pari_sp av = avma; GEN M = ZlX_hyperellpadicfrobenius(H, p, n); GEN q = zeropadic(utoi(p),n); return gerepileupto(av, ZM_to_padic(M, q)); } INLINE GEN FpXXX_renormalize(GEN x, long lx) { return ZXX_renormalize(x,lx); } static GEN ZpXQXXQ_red(GEN F, GEN S, GEN T, GEN q, GEN p, long e) { pari_sp av = avma; long i, dF = degpol(F); GEN A, C; if (signe(F)==0) return pol_0(varn(S)); A = cgetg(dF+3, t_POL); C = pol_0(varn(S)); for(i=dF; i>0; i--) { GEN Fi = FpXX_add(C, gel(F,i+2), q); GEN R, Q = ZpXQX_divrem(Fi, S, T, q, p, e, &R); gel(A,i+2) = R; C = Q; } gel(A,2) = FpXX_add(C, gel(F,2), q); A[1] = F[1]; return gerepilecopy(av, FpXXX_renormalize(A,dF+3)); } static GEN ZpXQXXQ_sqr(GEN x, GEN S, GEN T, GEN q, GEN p, long e) { pari_sp av = avma; GEN z, kx; long n = degpol(S); kx = ZXX_to_Kronecker(x, n); z = Kronecker_to_ZXX(FpXQX_sqr(kx, T, q), n, varn(S)); return gerepileupto(av, ZpXQXXQ_red(z, S, T, q, p, e)); } static GEN ZpXQXXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN q, GEN p, long e) { pari_sp av = avma; GEN z, kx, ky; long n = degpol(S); kx = ZXX_to_Kronecker(x, n); ky = ZXX_to_Kronecker(y, n); z = Kronecker_to_ZXX(FpXQX_mul(ky, kx, T, q), n, varn(S)); return gerepileupto(av, ZpXQXXQ_red(z, S, T, q, p, e)); } static GEN FpXXX_red(GEN z, GEN p) { GEN res; long i, l = lg(z); res = cgetg(l,t_POL); res[1] = z[1]; for (i=2; i1) timer_start(&ti); if (e <= 1) return gerepilecopy(av, a); mask = quadratic_prec_mask(e); av2 = avma; for (;mask>1;) { GEN q, q2, q22, f, fq, afq; long n2 = n; n<<=1; if (mask & 1) n--; mask >>= 1; q = powuu(p,n); q2 = powuu(p,n2); av3 = avma; f = RgX_sub(ZpXQXXQ_mul(F, ZpXQXXQ_sqr(a, S, T, q, pp, n), S, T, q, pp, n), pol_1(v)); fq = gerepileupto(av3, RgX_Rg_divexact(f, q2)); q22 = shifti(addiu(q2,1),-1); afq = FpXXX_Fp_mul(ZpXQXXQ_mul(a, fq, S, T, q2, pp, n2), q22, q2); a = RgX_sub(a, RgX_Rg_mul(afq, q2)); if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQXXQ_invsqrt, e = %ld", n); a = gerepileupto(av2, a); } } return gerepileupto(av, a); } static GEN frac_to_Fq(GEN a, GEN b, GEN T, GEN q, GEN p, long e) { GEN d = gcdii(ZX_content(a), ZX_content(b)); return ZpXQ_div(ZX_Z_divexact(a, d), ZX_Z_divexact(b, d), T, q, p, e); } static GEN ZpXQXXQ_frob(GEN F, GEN U, GEN V, long k, GEN S, GEN T, ulong p, long e) { pari_sp av = avma, av2; long i, pr = degpol(F), dS = degpol(S), v = varn(T); GEN q = powuu(p,e), pp = utoi(p); GEN Sp = RgX_deriv(S), Sp1 = RgX_shift_shallow(Sp, 1); GEN M = gel(F,pr+2), R; av2 = avma; for(i = pr-1; i>=k; i--) { GEN A, B, H, Bc; ulong v, r; H = ZpXQX_divrem(FpXQX_mul(V, M, T, q), S, T, q, utoi(p), e, &B); A = FpXX_add(FpXQX_mul(U, M, T, q), FpXQX_mul(H, Sp, T, q),q); v = u_lvalrem(2*i+1,p,&r); Bc = RgX_deriv(B); Bc = FpXX_Fp_mul(ZXX_Z_divexact(Bc,powuu(p,v)), Fp_div(gen_2, utoi(r), q), q); M = FpXX_add(gel(F,i+2), FpXX_add(A, Bc, q), q); if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQXXQ_frob, step 1, i = %ld", i); M = gerepileupto(av2, M); } } if (degpol(M)=1; i--) { GEN B, c; R = RgX_shift_shallow(R, 1); gel(R,2) = gel(M, i+1); if (degpol(R) < dS) continue; B = FpXX_add(FpXX_mulu(S, 2*i, q), Sp1, q); c = frac_to_Fq(to_ZX(leading_coeff(R),v), to_ZX(leading_coeff(B),v), T, q, pp, e); R = FpXX_sub(R, FpXQX_FpXQ_mul(B, c, T, q), q); if (gc_needed(av2,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_frob, step 2, i = %ld", i); R = gerepileupto(av2, R); } } if (degpol(R)==dS-1) { GEN c = frac_to_Fq(to_ZX(leading_coeff(R),v), to_ZX(leading_coeff(Sp),v), T, q, pp, e); R = FpXX_sub(R, FpXQX_FpXQ_mul(Sp, c, T, q), q); return gerepileupto(av, R); } else return gerepilecopy(av, R); } static GEN Fq_diff_red(GEN s, GEN A, long m, GEN S, GEN T, GEN q, GEN p, long e) { long v, n; GEN Q, sQ, qS; pari_timer ti; if (DEBUGLEVEL>1) timer_start(&ti); Q = revdigits(ZpXQX_digits(A, S, T, q, p, e)); n = degpol(Q); if (DEBUGLEVEL>1) timer_printf(&ti,"reddigits"); sQ = ZpXQXXQ_mul(s, Q, S, T, q, p, e); if (DEBUGLEVEL>1) timer_printf(&ti,"redmul"); qS = RgX_shift_shallow(sQ,m-n); v = ZX_val(sQ); if (n > m + v) { long i, l = n-m-v; GEN rS = cgetg(l+1,t_VEC); for (i = l-1; i >=0 ; i--) gel(rS,i+1) = gel(sQ, 1+v+l-i); rS = FpXQXV_FpXQX_fromdigits(rS, S, T, q); gel(qS,2) = FpXX_add(FpXQX_mul(rS, S, T, q), gel(qS, 2), q); if (DEBUGLEVEL>1) timer_printf(&ti,"redadd"); } return qS; } static void Fq_get_UV(GEN *U, GEN *V, GEN S, GEN T, ulong p, long e) { GEN q = powuu(p, e), d; GEN dS = RgX_deriv(S); GEN R = polresultantext(S, dS), C; long v = varn(S); if (signe(FpX_red(to_ZX(gel(R,3),v),utoi(p)))==0) is_sing(S, p); C = FpXQ_red(to_ZX(gel(R, 3),v), T, q); d = ZpXQ_inv(C, T, utoi(p), e); *U = FpXQX_FpXQ_mul(FpXQX_red(to_ZX(gel(R,1),v),T,q),d,T,q); *V = FpXQX_FpXQ_mul(FpXQX_red(to_ZX(gel(R,2),v),T,q),d,T,q); } static GEN ZXX_to_FpXC(GEN x, long N, GEN p, long v) { long i, l; GEN z; l = lg(x)-1; x++; if (l > N+1) l = N+1; /* truncate higher degree terms */ z = cgetg(N+1,t_COL); for (i=1; i1) timer_start(&ti); xp = ZpX_Frobenius(T, pp, N1); s = RgX_inflate(FpXY_FpXQ_evalx(Q, xp, T, pN1), p); s = revdigits(ZpXQX_digits(s, Q, T, pN1, pp, N1)); if (DEBUGLEVEL>1) timer_printf(&ti,"s1"); s = ZpXQXXQ_invsqrt(s, Q, T, p, N); if (k==3) s = ZpXQXXQ_mul(s, ZpXQXXQ_sqr(s, Q, T, pN1, pp, N1), Q, T, pN1, pp, N1); if (DEBUGLEVEL>1) timer_printf(&ti,"invsqrt"); Fq_get_UV(&U, &V, Q, T, p, N+1); if (DEBUGLEVEL>1) timer_printf(&ti,"get_UV"); F = cgetg(d, t_MAT); for (i = 1; i < d; i++) { pari_sp av2 = avma; GEN M, D; D = Fq_diff_red(s, monomial(pp,p*i-1,1),(k*p-1)>>1, Q, T, pN1, pp, N1); if (DEBUGLEVEL>1) timer_printf(&ti,"red"); M = ZpXQXXQ_frob(D, U, V, (k - 1)>>1, Q, T, p, N1); if (DEBUGLEVEL>1) timer_printf(&ti,"frob"); gel(F, i) = gerepileupto(av2, ZXX_to_FpXC(M, d-1, q, varn(T))); } return gerepileupto(av, F); } GEN nfhyperellpadicfrobenius(GEN H, GEN T, ulong p, long n) { pari_sp av = avma; GEN M = ZlXQX_hyperellpadicfrobenius(lift_shallow(H),T,p,n); GEN MM = ZpXQM_prodFrobenius(M, T, utoi(p), n); GEN q = zeropadic(utoi(p),n); GEN m = gmul(ZXM_to_padic(MM, q), gmodulo(gen_1, T)); return gerepileupto(av, m); } static GEN F2x_genus2charpoly_naive(GEN P, GEN Q) { long a, b = 1, c = 0; GEN T = mkvecsmall2(P[1], 7); GEN PT = F2x_rem(P, T), QT = F2x_rem(Q, T); long q0 = F2x_eval(Q, 0), q1 = F2x_eval(Q, 1); long dP = F2x_degree(P), dQ = F2x_degree(Q); a= dQ<3 ? 0: dP<=5 ? 1: -1; a += (q0? F2x_eval(P, 0)? -1: 1: 0) + (q1? F2x_eval(P, 1)? -1: 1: 0); b += q0 + q1; if (lgpol(QT)) c = (F2xq_trace(F2xq_div(PT, F2xq_sqr(QT, T), T), T)==0 ? 1: -1); return mkvecsmalln(6, 0UL, 4, 2*a, (b+2*c+a*a)>>1, a, 1UL); } static GEN Flx_difftable(GEN P, ulong p) { long i, n = degpol(P); GEN V = cgetg(n+2, t_VEC); gel(V, n+1) = P; for(i = n; i >= 1; i--) gel(V, i) = Flx_diff1(gel(V, i+1), p); return V; } static GEN FlxV_Fl2_eval_pre(GEN V, GEN x, ulong D, ulong p, ulong pi) { long i, n = lg(V)-1; GEN r = cgetg(n+1, t_VEC); for (i = 1; i <= n; i++) gel(r, i) = Flx_Fl2_eval_pre(gel(V, i), x, D, p, pi); return r; } static GEN Fl2V_next(GEN V, ulong p) { long i, n = lg(V)-1; GEN r = cgetg(n+1, t_VEC); gel(r, 1) = gel(V, 1); for (i = 2; i <= n; i++) gel(r, i) = Flv_add(gel(V, i), gel(V, i-1), p); return r; } static GEN Flx_genus2charpoly_naive(GEN H, ulong p) { pari_sp av = avma, av2; ulong pi = get_Fl_red(p); ulong i, j, p2 = p>>1, D = 2, e = ((p&2UL) == 0) ? -1 : 1; long a, b, c = 0, n = degpol(H); GEN t, k = const_vecsmall(p, -1); k[1] = 0; for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p)) k[j+1] = 1; while (k[1+D] >= 0) D++; b = n == 5 ? 0 : 1; a = b ? k[1+Flx_lead(H)]: 0; t = Flx_difftable(H, p); av2 = avma; for (i=0; i < p; i++) { ulong v = Flx_eval(H, i, p); a += k[1+v]; b += !!v; } for (j=1; j <= p2; j++) { GEN V = FlxV_Fl2_eval_pre(t, mkvecsmall2(0, j), D, p, pi); for (i=0;; i++) { GEN r2 = gel(V, n+1); c += uel(r2,2) ? (uel(r2,1) ? k[1+Fl2_norm_pre(r2, D, p, pi)]: e) : !!uel(r2,1); if (i == p-1) break; V = Fl2V_next(V, p); } avma = av2; } avma = av; return mkvecsmalln(6, 0UL, p*p, a*p, (b+2*c+a*a)>>1, a, 1UL); } static GEN charpoly_funceq(GEN P, GEN q) { long i, l, g = degpol(P)>>1; GEN Q = cgetg_copy(P, &l); Q[1] = P[1]; for (i=0; i<=g; i++) gel(Q, i+2) = mulii(gel(P, 2*g-i+2), powiu(q, g-i)); for (; i<=2*g; i++) gel(Q, i+2) = icopy(gel(P, i+2)); return Q; } static long hyperell_Weil_bound(GEN q, ulong g, GEN p) { pari_sp av = avma; GEN w = mulii(binomialuu(2*g,g),sqrtint(shifti(powiu(q, g),2))); long e = logint(w, p) + 1; avma = av; return e; } GEN hyperellcharpoly(GEN PQ) { pari_sp av = avma; GEN H, M, R, T=NULL, pp=NULL, q; long d, n, eps = 0; ulong p; if (is_vec_t(typ(PQ)) && lg(PQ)==3) H = gadd(gsqr(gel(PQ, 2)), gmul2n(gel(PQ, 1), 2)); else H = PQ; if (typ(H)!=t_POL || !RgX_is_FpXQX(H, &T, &pp) || !pp) pari_err_TYPE("hyperellcharpoly",H); p = itou(pp); if (!T) { if (p==2 && is_vec_t(typ(PQ))) { long dP, dQ, v = varn(H); GEN P = gel(PQ,1), Q = gel(PQ,2); if (typ(P)!=t_POL) P = scalarpol(P, v); if (typ(Q)!=t_POL) Q = scalarpol(Q, v); dP = degpol(P); dQ = degpol(Q); if (dP<=6 && dQ <=3 && (dQ==3 || dP>=5)) { GEN P2 = RgX_to_F2x(P), Q2 = RgX_to_F2x(Q); GEN D = F2x_add(F2x_mul(P2, F2x_sqr(F2x_deriv(Q2))), F2x_sqr(F2x_deriv(P2))); if (F2x_degree(F2x_gcd(D, Q2))) is_sing(PQ, 2); if (dP==6 && dQ<3 && F2x_coeff(P2,5)==F2x_coeff(Q2,2)) is_sing(PQ, 2); /* The curve is singular at infinity */ R = zx_to_ZX(F2x_genus2charpoly_naive(P2, Q2)); return gerepileupto(av, R); } } H = RgX_to_FpX(H, pp); d = degpol(H); if (d <= 0) is_sing(H, p); if (p > 2 && ((d == 5 && p < 17500) || (d == 6 && p < 24500))) { GEN Hp = ZX_to_Flx(H, p); if (!Flx_is_squarefree(Hp, p)) is_sing(H, p); R = zx_to_ZX(Flx_genus2charpoly_naive(Hp, p)); return gerepileupto(av, R); } n = hyperell_Weil_bound(pp, (d-1)>>1, pp); eps = odd(d)? 0: Fp_issquare(leading_coeff(H), pp); M = hyperellpadicfrobenius(H, p, n); R = centerlift(carberkowitz(M, 0)); q = pp; } else { int fixvar; T = typ(T)==t_FFELT? FF_mod(T): RgX_to_FpX(T, pp); q = powuu(p, degpol(T)); fixvar = (varncmp(varn(T),varn(H)) <= 0); if (fixvar) setvarn(T, fetch_var()); H = RgX_to_FpXQX(H, T, pp); d = degpol(H); if (d <= 0) is_sing(H, p); eps = odd(d)? 0: Fq_issquare(leading_coeff(H), T, pp); n = hyperell_Weil_bound(q, (d-1)>>1, pp); M = nfhyperellpadicfrobenius(H, T, p, n); R = simplify_shallow(centerlift(liftpol_shallow(carberkowitz(M, 0)))); if (fixvar) (void)delete_var(); } if (!odd(d)) { GEN b = get_basis(p, d) == 3 ? gen_1 : q; GEN pn = powuu(p, n); R = FpX_div_by_X_x(R, eps? b: negi(b), pn, NULL); R = FpX_center_i(R, pn, shifti(pn,-1)); } R = charpoly_funceq(R, q); return gerepilecopy(av, R); } pari-2.11.2/src/kernel/0000755000175000017500000000000013461316051013225 5ustar billbillpari-2.11.2/src/kernel/aarch64/0000755000175000017500000000000013461316051014455 5ustar billbillpari-2.11.2/src/kernel/aarch64/asm0.h0000644000175000017500000001126113201017466015467 0ustar billbill#line 2 "../src/kernel/aarch64/asm0.h" /* Copyright (C) 2015 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM addll mulll bfffo NOASM divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("adds %0,%2,%3\n\tadc %1,xzr,xzr\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2): "cc"); \ __value; \ }) #define addllx(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subs xzr,%4,#1\n\tadcs %0,%2,%3\n\tadc %1,xzr,xzr\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow): "cc"); \ __value; \ }) #define addllx8(a,b,c,overflow) \ do { long *__arg1 = a, *__arg2 = b, *__out = c; \ ulong __temp1, __temp2; \ __asm__( \ "subs xzr,%6,#1\n\t" \ " ldr %0, [%3] \n\t ldr %1, [%4] \n\t adcs %1, %0, %1\n\t str %1, [%5] \n\t" \ " ldr %0, [%3,-8] \n\t ldr %1, [%4,-8] \n\t adcs %1, %0, %1\n\t str %1, [%5,-8] \n\t" \ " ldr %0, [%3,-16] \n\t ldr %1, [%4,-16]\n\t adcs %1, %0, %1\n\t str %1, [%5,-16]\n\t" \ " ldr %0, [%3,-24] \n\t ldr %1, [%4,-24]\n\t adcs %1, %0, %1\n\t str %1, [%5,-24]\n\t" \ " ldr %0, [%3,-32] \n\t ldr %1, [%4,-32]\n\t adcs %1, %0, %1\n\t str %1, [%5,-32]\n\t" \ " ldr %0, [%3,-40] \n\t ldr %1, [%4,-40]\n\t adcs %1, %0, %1\n\t str %1, [%5,-40]\n\t" \ " ldr %0, [%3,-48] \n\t ldr %1, [%4,-48]\n\t adcs %1, %0, %1\n\t str %1, [%5,-48]\n\t" \ " ldr %0, [%3,-56] \n\t ldr %1, [%4,-56]\n\t adcs %1, %0, %1\n\t str %1, [%5,-56]\n\t" \ "adc %2,xzr,xzr\n\t" \ : "=&r" (__temp1), "=&r" (__temp2), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (__out), "r" (overflow), \ "0" ((ulong)0), "1" ((ulong)0) \ : "cc"); \ } while(0) #define subll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subs %0,%2,%3\n\tngc %1,xzr\n\tsub %1,xzr,%1\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2): "cc"); \ __value; \ }) #define subllx(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subs xzr,xzr,%4\n\tsbcs %0,%2,%3\n\tngc %1,xzr\n\tsub %1,xzr,%1\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow): "cc"); \ __value; \ }) #define subllx8(a,b,c,overflow) \ do { long *__arg1 = a, *__arg2 = b, *__out = c; \ ulong __temp1, __temp2; \ __asm__( \ "subs xzr,xzr,%6\n\t" \ " ldr %0, [%3] \n\t ldr %1, [%4] \n\t sbcs %1, %0, %1\n\t str %1, [%5] \n\t" \ " ldr %0, [%3,-8] \n\t ldr %1, [%4,-8] \n\t sbcs %1, %0, %1\n\t str %1, [%5,-8] \n\t" \ " ldr %0, [%3,-16] \n\t ldr %1, [%4,-16]\n\t sbcs %1, %0, %1\n\t str %1, [%5,-16]\n\t" \ " ldr %0, [%3,-24] \n\t ldr %1, [%4,-24]\n\t sbcs %1, %0, %1\n\t str %1, [%5,-24]\n\t" \ " ldr %0, [%3,-32] \n\t ldr %1, [%4,-32]\n\t sbcs %1, %0, %1\n\t str %1, [%5,-32]\n\t" \ " ldr %0, [%3,-40] \n\t ldr %1, [%4,-40]\n\t sbcs %1, %0, %1\n\t str %1, [%5,-40]\n\t" \ " ldr %0, [%3,-48] \n\t ldr %1, [%4,-48]\n\t sbcs %1, %0, %1\n\t str %1, [%5,-48]\n\t" \ " ldr %0, [%3,-56] \n\t ldr %1, [%4,-56]\n\t sbcs %1, %0, %1\n\t str %1, [%5,-56]\n\t" \ "ngc %2,xzr\n\tsub %2,xzr,%2\n\t" \ : "=&r" (__temp1), "=&r" (__temp2), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (__out), "r" (overflow), \ "0" ((ulong)0), "1" ((ulong)0) \ : "cc"); \ } while(0) #define mulll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("mul %0,%1,%2\n\t" \ : "=r" (__value) : "r" (__arg1), "r" (__arg2)); \ __asm__ ("umulh %0,%1,%2\n\t" \ : "=r" (hiremainder) : "r" (__arg1), "r" (__arg2)); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __hi; \ __asm__ ("madd %0,%1,%2,%3\n\t" \ : "=r" (__value) : "r" (__arg1), "r" (__arg2), "r" (hiremainder)); \ __asm__ ("umulh %0,%1,%2\n\t" \ : "=r" (__hi) : "r" (__arg1), "r" (__arg2)); \ hiremainder = (__value < hiremainder) ? __hi+1: __hi;\ __value; \ }) #define bfffo(a) \ __extension__ ({ ulong __a = (a), __value; \ __asm__ ("clz %0, %1" : "=r" (__value) : "r" (__a)); \ __value; \ }) #endif pari-2.11.2/src/kernel/ix86/0000755000175000017500000000000013461316051014023 5ustar billbillpari-2.11.2/src/kernel/ix86/asm0.h0000644000175000017500000001215713036414402015037 0ustar billbill#line 2 "../src/kernel/ix86/asm0.h" /* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file defines some "level 0" kernel functions for Intel ix86 */ /* It is intended for use with an external "asm" definition */ /* ASM addll mulll bfffo divll */ #ifdef ASMINLINE /* Written by Bruno Haible, 1996-1998. addllx8/subllx8 by Bill Allombert, 2011. */ /* This file can assume the GNU C extensions. (It is included only if __GNUC__ is defined.) */ /* Use local variables whenever possible. */ #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("addl %3,%0 ; adcl %1,%1" \ : "=r" (__value), "=r" (overflow) \ : "0" (__arg1), "g" (__arg2), "1" ((ulong)0) \ : "cc"); \ __value; \ }) #define addllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("subl %5,%2 ; adcl %4,%0 ; adcl %1,%1" \ : "=r" (__value), "=&r" (overflow), "=&r" (__temp) \ : "0" (__arg1), "g" (__arg2), "g" (overflow), "1" ((ulong)0), "2" ((ulong)0) \ : "cc"); \ __value; \ }) #define addllx8(a,b,c,overflow) \ do { long *__arg1 = a, *__arg2 = b, *__out = c; \ ulong __temp; \ __asm__ ("subl %5, %0 \n\t" \ "movl (%2), %0 ; adcl (%3),%0; movl %0, (%4) \n\t" \ "movl -4(%2), %0 ; adcl -4(%3),%0; movl %0, -4(%4) \n\t" \ "movl -8(%2), %0 ; adcl -8(%3),%0; movl %0, -8(%4) \n\t" \ "movl -12(%2), %0 ; adcl -12(%3),%0; movl %0, -12(%4) \n\t" \ "movl -16(%2), %0 ; adcl -16(%3),%0; movl %0, -16(%4) \n\t" \ "movl -20(%2), %0 ; adcl -20(%3),%0; movl %0, -20(%4) \n\t" \ "movl -24(%2), %0 ; adcl -24(%3),%0; movl %0, -24(%4) \n\t" \ "movl -28(%2), %0 ; adcl -28(%3),%0; movl %0, -28(%4) \n\t" \ "adcl %1, %1" \ : "=&r" (__temp), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (__out), "g" (overflow), "0" ((ulong)0), "1" ((ulong)0) : "cc"); \ } while(0) #define subll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subl %3,%0 ; adcl %1,%1" \ : "=r" (__value), "=r" (overflow) \ : "0" (__arg1), "g" (__arg2), "1" ((ulong)0) \ : "cc"); \ __value; \ }) #define subllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("subl %5,%2 ; sbbl %4,%0 ; adcl %1,%1" \ : "=r" (__value), "=&r" (overflow), "=&r" (__temp) \ : "0" (__arg1), "g" (__arg2), "g" (overflow), "1" ((ulong)0), "2" ((ulong)0) \ : "cc"); \ __value; \ }) #define subllx8(a,b,c,overflow) \ do { long *__arg1 = a, *__arg2 = b, *__out = c; \ ulong __temp; \ __asm__ ("subl %5, %0 \n\t" \ "movl (%2), %0 ; sbbl (%3),%0; movl %0, (%4) \n\t" \ "movl -4(%2), %0 ; sbbl -4(%3),%0; movl %0, -4(%4) \n\t" \ "movl -8(%2), %0 ; sbbl -8(%3),%0; movl %0, -8(%4) \n\t" \ "movl -12(%2), %0 ; sbbl -12(%3),%0; movl %0, -12(%4) \n\t" \ "movl -16(%2), %0 ; sbbl -16(%3),%0; movl %0, -16(%4) \n\t" \ "movl -20(%2), %0 ; sbbl -20(%3),%0; movl %0, -20(%4) \n\t" \ "movl -24(%2), %0 ; sbbl -24(%3),%0; movl %0, -24(%4) \n\t" \ "movl -28(%2), %0 ; sbbl -28(%3),%0; movl %0, -28(%4) \n\t" \ "adcl %1, %1" \ : "=&r" (__temp), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (__out), "g" (overflow), "0" ((ulong)0), "1" ((ulong)0) : "cc"); \ } while(0) #define mulll(a,b) \ __extension__ ({ ulong __valuelo, __arg1 = (a), __arg2 = (b); \ __asm__ ("mull %3" \ : "=a" /* %eax */ (__valuelo), "=d" /* %edx */ (hiremainder) \ : "0" (__arg1), "rm" (__arg2)); \ __valuelo; \ }) #define addmul(a,b) \ __extension__ ({ ulong __valuelo, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("mull %4 ; addl %5,%0 ; adcl %6,%1" \ : "=a" /* %eax */ (__valuelo), "=&d" /* %edx */ (hiremainder), "=r" (__temp) \ : "0" (__arg1), "rm" (__arg2), "g" (hiremainder), "2" ((ulong)0)); \ __valuelo; \ }) #define divll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("divl %4" \ : "=a" /* %eax */ (__value), "=d" /* %edx */ (hiremainder) \ : "0" /* %eax */ (__arg1), "1" /* %edx */ (hiremainder), "mr" (__arg2)); \ __value; \ }) #define bfffo(x) \ __extension__ ({ ulong __arg = (x); \ int leading_one_position; \ __asm__ ("bsrl %1,%0" : "=r" (leading_one_position) : "rm" (__arg)); \ 31 - leading_one_position; \ }) #endif pari-2.11.2/src/kernel/none/0000755000175000017500000000000013461316051014164 5ustar billbillpari-2.11.2/src/kernel/none/divll.h0000644000175000017500000001543313201017466015455 0ustar billbill#line 2 "../src/kernel/none/divll.h" /* Copyright (C) 2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file originally adapted from gmp-3.1.1 (from T. Granlund), files * longlong.h and gmp-impl.h Copyright (C) 2000 Free Software Foundation, Inc. */ #undef LOCAL_HIREMAINDER #define LOCAL_HIREMAINDER extern ulong hiremainder; #if !defined(INLINE) extern long divll(ulong x, ulong y); #else #define __GLUE(hi, lo) (((hi) << BITS_IN_HALFULONG) | (lo)) #define __SPLIT(a, b, c) b = HIGHWORD(a); c = LOWWORD(a) #define __LDIV(a, b, q, r) q = a / b; r = a - q*b extern ulong hiremainder; /* divide (hiremainder * 2^BITS_IN_LONG + n0) by d; assume hiremainder < d. * Return quotient, set hiremainder to remainder */ #if defined(__GNUC__) && !defined(DISABLE_INLINE) #undef LOCAL_HIREMAINDER #define LOCAL_HIREMAINDER register ulong hiremainder #define divll(n0, d) \ __extension__ ({ \ ulong __d1, __d0, __q1, __q0, __r1, __r0, __m, __n1, __n0; \ ulong __k, __d; \ \ __n1 = hiremainder; __n0 = n0; __d = d; \ if (__n1 == 0) \ { /* Only one division needed */ \ __LDIV(__n0, __d, __q1, hiremainder); \ } \ else if (__d < LOWMASK) \ { /* Two half-word divisions */ \ __n1 = __GLUE(__n1, HIGHWORD(__n0)); \ __LDIV(__n1, __d, __q1, __r1); \ __n1 = __GLUE(__r1, LOWWORD(__n0)); \ __LDIV(__n1, __d, __q0, hiremainder); \ __q1 = __GLUE(__q1, __q0); \ } \ else \ { /* General case */ \ if (__d & HIGHBIT) \ { \ __k = 0; __SPLIT(__d, __d1, __d0); \ } \ else \ { \ __k = bfffo(__d); \ __n1 = (__n1 << __k) | (__n0 >> (BITS_IN_LONG - __k)); \ __n0 <<= __k; \ __d = __d << __k; __SPLIT(__d, __d1, __d0); \ } \ __LDIV(__n1, __d1, __q1, __r1); \ __m = __q1 * __d0; \ __r1 = __GLUE(__r1, HIGHWORD(__n0)); \ if (__r1 < __m) \ { \ __q1--, __r1 += __d; \ if (__r1 >= __d) /* we didn't get carry when adding to __r1 */ \ if (__r1 < __m) __q1--, __r1 += __d; \ } \ __r1 -= __m; \ __LDIV(__r1, __d1, __q0, __r0); \ __m = __q0 * __d0; \ __r0 = __GLUE(__r0, LOWWORD(__n0)); \ if (__r0 < __m) \ { \ __q0--, __r0 += __d; \ if (__r0 >= __d) \ if (__r0 < __m) __q0--, __r0 += __d; \ } \ hiremainder = (__r0 - __m) >> __k; \ __q1 = __GLUE(__q1, __q0); \ } \ __q1; \ }) #else /* __GNUC__ */ INLINE long divll(ulong n0, ulong d) { ulong __d1, __d0, __q1, __q0, __r1, __r0, __m, __n1, __n0; ulong __k, __d; __n1 = hiremainder; __n0 = n0; __d = d; if (__n1 == 0) { /* Only one division needed */ __LDIV(__n0, __d, __q1, hiremainder); } else if (__d < LOWMASK) { /* Two half-word divisions */ __n1 = __GLUE(__n1, HIGHWORD(__n0)); __LDIV(__n1, __d, __q1, __r1); __n1 = __GLUE(__r1, LOWWORD(__n0)); __LDIV(__n1, __d, __q0, hiremainder); __q1 = __GLUE(__q1, __q0); } else { /* General case */ if (__d & HIGHBIT) { __k = 0; __SPLIT(__d, __d1, __d0); } else { __k = bfffo(__d); __n1 = (__n1 << __k) | (__n0 >> (BITS_IN_LONG - __k)); __n0 = __n0 << __k; __d = __d << __k; __SPLIT(__d, __d1, __d0); } __LDIV(__n1, __d1, __q1, __r1); __m = __q1 * __d0; __r1 = __GLUE(__r1, HIGHWORD(__n0)); if (__r1 < __m) { __q1--, __r1 += __d; if (__r1 >= __d) /* we didn't get carry when adding to __r1 */ if (__r1 < __m) __q1--, __r1 += __d; } __r1 -= __m; __LDIV(__r1, __d1, __q0, __r0); __m = __q0 * __d0; __r0 = __GLUE(__r0, LOWWORD(__n0)); if (__r0 < __m) { __q0--, __r0 += __d; if (__r0 >= __d) if (__r0 < __m) __q0--, __r0 += __d; } hiremainder = (__r0 - __m) >> __k; __q1 = __GLUE(__q1, __q0); } return __q1; } #endif /* __GNUC__ */ #endif pari-2.11.2/src/kernel/none/tune.h0000644000175000017500000001446113326135265015324 0ustar billbill#ifdef LONG_IS_64BIT #define __AGM_ATAN_LIMIT 56 #define __DIVRR_GMP_LIMIT -1 #define __EXPNEWTON_LIMIT 66 #define __F2x_MUL_KARATSUBA_LIMIT 15 #define __F2xqX_BARRETT_LIMIT 17 #define __F2xqX_DIVREM_BARRETT_LIMIT 46 #define __F2xqX_INVBARRETT_LIMIT 22 #define __F2xqX_REM_BARRETT_LIMIT 48 #define __Flx_BARRETT_HALFMULII_LIMIT 29 #define __Flx_BARRETT_KARATSUBA_LIMIT 2561 #define __Flx_BARRETT_MULII2_LIMIT 30 #define __Flx_BARRETT_MULII_LIMIT 1681 #define __Flx_BARRETT_QUARTMULII_LIMIT 29 #define __Flx_DIVREM_BARRETT_LIMIT 2804 #define __Flx_EXTGCD_LIMIT 284 #define __Flx_GCD_LIMIT 1890 #define __Flx_HALFGCD_HALFMULII_LIMIT 60 #define __Flx_HALFGCD_KARATSUBA_LIMIT 58 #define __Flx_HALFGCD_MULII2_LIMIT 64 #define __Flx_HALFGCD_MULII_LIMIT 90 #define __Flx_HALFGCD_QUARTMULII_LIMIT 60 #define __Flx_INVBARRETT_HALFMULII_LIMIT 424 #define __Flx_INVBARRETT_KARATSUBA_LIMIT 5120 #define __Flx_INVBARRETT_MULII2_LIMIT 36 #define __Flx_INVBARRETT_MULII_LIMIT 3840 #define __Flx_INVBARRETT_QUARTMULII_LIMIT 424 #define __Flx_MUL_HALFMULII_LIMIT 5 #define __Flx_MUL_KARATSUBA_LIMIT 147 #define __Flx_MUL_MULII2_LIMIT 5 #define __Flx_MUL_MULII_LIMIT 1639 #define __Flx_MUL_QUARTMULII_LIMIT 5 #define __Flx_REM_BARRETT_LIMIT 3577 #define __Flx_SQR_HALFSQRI_LIMIT 3 #define __Flx_SQR_KARATSUBA_LIMIT 330 #define __Flx_SQR_QUARTSQRI_LIMIT 3 #define __Flx_SQR_SQRI2_LIMIT 8 #define __Flx_SQR_SQRI_LIMIT 5 #define __FlxqX_BARRETT_LIMIT 17 #define __FlxqX_DIVREM_BARRETT_LIMIT 46 #define __FlxqX_EXTGCD_LIMIT 44 #define __FlxqX_GCD_LIMIT 796 #define __FlxqX_HALFGCD_LIMIT 191 #define __FlxqX_INVBARRETT_LIMIT 22 #define __FlxqX_REM_BARRETT_LIMIT 48 #define __FpXQX_BARRETT_LIMIT 12 #define __FpXQX_DIVREM_BARRETT_LIMIT 30 #define __FpXQX_EXTGCD_LIMIT 34 #define __FpXQX_GCD_LIMIT 254 #define __FpXQX_HALFGCD_LIMIT 56 #define __FpXQX_INVBARRETT_LIMIT 40 #define __FpXQX_REM_BARRETT_LIMIT 30 #define __FpX_BARRETT_LIMIT 85 #define __FpX_DIVREM_BARRETT_LIMIT 292 #define __FpX_EXTGCD_LIMIT 117 #define __FpX_GCD_LIMIT 731 #define __FpX_HALFGCD_LIMIT 75 #define __FpX_INVBARRETT_LIMIT 254 #define __FpX_REM_BARRETT_LIMIT 306 #define __Fp_POW_BARRETT_LIMIT 101 #define __Fp_POW_REDC_LIMIT 99 #define __INVMOD_GMP_LIMIT -1 #define __INVNEWTON_LIMIT 550 #define __LOGAGMCX_LIMIT 13 #define __LOGAGM_LIMIT 16 #define __MULII_FFT_LIMIT 1441 #define __MULII_KARATSUBA_LIMIT 23 #define __MULRR_MULII_LIMIT 210 #define __RgX_MUL_LIMIT 9 #define __RgX_SQR_LIMIT 35 #define __SQRI_FFT_LIMIT 1651 #define __SQRI_KARATSUBA_LIMIT 36 #define __SQRR_SQRI_LIMIT 54 #else #define __AGM_ATAN_LIMIT 159 #define __DIVRR_GMP_LIMIT -1 #define __EXPNEWTON_LIMIT 66 #define __F2x_MUL_KARATSUBA_LIMIT 23 #define __F2xqX_BARRETT_LIMIT 17 #define __F2xqX_DIVREM_BARRETT_LIMIT 46 #define __F2xqX_INVBARRETT_LIMIT 22 #define __F2xqX_REM_BARRETT_LIMIT 48 #define __Flx_BARRETT_HALFMULII_LIMIT 244 #define __Flx_BARRETT_KARATSUBA_LIMIT 905 #define __Flx_BARRETT_MULII2_LIMIT 1004 #define __Flx_BARRETT_MULII_LIMIT 2715 #define __Flx_BARRETT_QUARTMULII_LIMIT 244 #define __Flx_DIVREM_BARRETT_LIMIT 3942 #define __Flx_EXTGCD_LIMIT 850 #define __Flx_GCD_LIMIT 7165 #define __Flx_HALFGCD_HALFMULII_LIMIT 116 #define __Flx_HALFGCD_KARATSUBA_LIMIT 230 #define __Flx_HALFGCD_MULII2_LIMIT 1045 #define __Flx_HALFGCD_MULII_LIMIT 168 #define __Flx_HALFGCD_QUARTMULII_LIMIT 116 #define __Flx_INVBARRETT_HALFMULII_LIMIT 898 #define __Flx_INVBARRETT_KARATSUBA_LIMIT 3471 #define __Flx_INVBARRETT_MULII2_LIMIT 3672 #define __Flx_INVBARRETT_MULII_LIMIT 4196 #define __Flx_INVBARRETT_QUARTMULII_LIMIT 898 #define __Flx_MUL_HALFMULII_LIMIT 8 #define __Flx_MUL_KARATSUBA_LIMIT 85 #define __Flx_MUL_MULII2_LIMIT 3755 #define __Flx_MUL_MULII_LIMIT 698 #define __Flx_MUL_QUARTMULII_LIMIT 8 #define __Flx_REM_BARRETT_LIMIT 3942 #define __Flx_SQR_HALFSQRI_LIMIT 6 #define __Flx_SQR_KARATSUBA_LIMIT 159 #define __Flx_SQR_QUARTSQRI_LIMIT 6 #define __Flx_SQR_SQRI2_LIMIT 4139 #define __Flx_SQR_SQRI_LIMIT 1276 #define __FlxqX_BARRETT_LIMIT 17 #define __FlxqX_DIVREM_BARRETT_LIMIT 46 #define __FlxqX_EXTGCD_LIMIT 44 #define __FlxqX_GCD_LIMIT 2544 #define __FlxqX_HALFGCD_LIMIT 427 #define __FlxqX_INVBARRETT_LIMIT 22 #define __FlxqX_REM_BARRETT_LIMIT 48 #define __FpXQX_BARRETT_LIMIT 12 #define __FpXQX_DIVREM_BARRETT_LIMIT 30 #define __FpXQX_EXTGCD_LIMIT 28 #define __FpXQX_GCD_LIMIT 254 #define __FpXQX_HALFGCD_LIMIT 48 #define __FpXQX_INVBARRETT_LIMIT 40 #define __FpXQX_REM_BARRETT_LIMIT 30 #define __FpX_BARRETT_LIMIT 144 #define __FpX_DIVREM_BARRETT_LIMIT 306 #define __FpX_EXTGCD_LIMIT 238 #define __FpX_GCD_LIMIT 1292 #define __FpX_HALFGCD_LIMIT 145 #define __FpX_INVBARRETT_LIMIT 337 #define __FpX_REM_BARRETT_LIMIT 306 #define __Fp_POW_BARRETT_LIMIT 97 #define __Fp_POW_REDC_LIMIT 99 #define __INVMOD_GMP_LIMIT -1 #define __INVNEWTON_LIMIT 66 #define __LOGAGMCX_LIMIT 58 #define __LOGAGM_LIMIT 55 #define __MULII_FFT_LIMIT 1386 #define __MULII_KARATSUBA_LIMIT 18 #define __MULRR_MULII_LIMIT 422 #define __RgX_MUL_LIMIT 5 #define __RgX_SQR_LIMIT 26 #define __SQRI_FFT_LIMIT 1469 #define __SQRI_KARATSUBA_LIMIT 27 #define __SQRR_SQRI_LIMIT 20 #endif pari-2.11.2/src/kernel/none/add.c0000644000175000017500000001754513201017466015074 0ustar billbill#line 2 "../src/kernel/none/add.c" /* Copyright (C) 2002-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ INLINE GEN icopy_sign(GEN x, long sx) { GEN y=icopy(x); setsigne(y,sx); return y; } GEN addsi_sign(long x, GEN y, long sy) { long sx,ly; GEN z; if (!x) return icopy_sign(y, sy); if (!sy) return stoi(x); if (x<0) { sx=-1; x=-x; } else sx=1; if (sx==sy) { z = adduispec(x,y+2, lgefint(y)-2); setsigne(z,sy); return z; } ly=lgefint(y); if (ly==3) { const long d = (long)(uel(y,2) - (ulong)x); if (!d) return gen_0; z=cgeti(3); if (y[2] < 0 || d > 0) { z[1] = evalsigne(sy) | evallgefint(3); z[2] = d; } else { z[1] = evalsigne(-sy) | evallgefint(3); z[2] =-d; } return z; } z = subiuspec(y+2,x, ly-2); setsigne(z,sy); return z; } GEN addui_sign(ulong x, GEN y, long sy) { long ly; GEN z; if (!x) return icopy_sign(y, sy); if (!sy) return utoipos(x); if (sy == 1) return adduispec(x,y+2, lgefint(y)-2); ly=lgefint(y); if (ly==3) { const ulong t = y[2]; if (x == t) return gen_0; z=cgeti(3); if (x < t) { z[1] = evalsigne(-1) | evallgefint(3); z[2] = t - x; } else { z[1] = evalsigne(1) | evallgefint(3); z[2] = x - t; } return z; } z = subiuspec(y+2,x, ly-2); setsigne(z,-1); return z; } /* return gen_0 when the sign is 0 */ GEN addii_sign(GEN x, long sx, GEN y, long sy) { long lx,ly; GEN z; if (!sx) return sy? icopy_sign(y, sy): gen_0; if (!sy) return icopy_sign(x, sx); lx = lgefint(x); ly = lgefint(y); if (sx==sy) z = addiispec(x+2,y+2,lx-2,ly-2); else { /* sx != sy */ long i = cmpiispec(x+2,y+2,lx-2,ly-2); if (!i) return gen_0; /* we must ensure |x| > |y| for subiispec */ if (i < 0) { sx = sy; z = subiispec(y+2,x+2,ly-2,lx-2); } else z = subiispec(x+2,y+2,lx-2,ly-2); } setsigne(z,sx); return z; } INLINE GEN rcopy_sign(GEN x, long sx) { GEN y = rcopy(x); setsigne(y,sx); return y; } GEN addir_sign(GEN x, long sx, GEN y, long sy) { long e, l, ly; GEN z; if (!sx) return rcopy_sign(y, sy); e = expo(y) - expi(x); if (!sy) { if (e >= 0) return rcopy_sign(y, sy); z = itor(x, nbits2prec(-e)); setsigne(z, sx); return z; } ly = lg(y); if (e > 0) { l = ly - divsBIL(e); if (l < 3) return rcopy_sign(y, sy); } else l = ly + nbits2extraprec(-e); z = (GEN)avma; y = addrr_sign(itor(x,l), sx, y, sy); ly = lg(y); while (ly--) *--z = y[ly]; avma = (pari_sp)z; return z; } static GEN addsr_sign(long x, GEN y, long sy) { long e, l, ly, sx; GEN z; if (!x) return rcopy_sign(y, sy); if (x < 0) { sx = -1; x = -x; } else sx = 1; e = expo(y) - expu(x); if (!sy) { if (e >= 0) return rcopy_sign(y, sy); if (sx == -1) x = -x; return stor(x, nbits2prec(-e)); } ly = lg(y); if (e > 0) { l = ly - divsBIL(e); if (l < 3) return rcopy_sign(y, sy); } else l = ly + nbits2extraprec(-e); z = (GEN)avma; y = addrr_sign(stor(x,l), sx, y, sy); ly = lg(y); while (ly--) *--z = y[ly]; avma = (pari_sp)z; return z; } GEN addsr(long x, GEN y) { return addsr_sign(x, y, signe(y)); } GEN subsr(long x, GEN y) { return addsr_sign(x, y, -signe(y)); } GEN addrr_sign(GEN x, long sx, GEN y, long sy) { long lx, ex = expo(x); long ly, ey = expo(y), e = ey - ex; long i, j, lz, ez, m; int extend, f2; GEN z; LOCAL_OVERFLOW; if (!sy) { if (!sx) { if (e > 0) ex = ey; return real_0_bit(ex); } if (e >= 0) return real_0_bit(ey); lz = nbits2prec(-e); lx = lg(x); if (lz > lx) lz = lx; z = cgetr(lz); while(--lz) z[lz] = x[lz]; setsigne(z,sx); return z; } if (!sx) { if (e <= 0) return real_0_bit(ex); lz = nbits2prec(e); ly = lg(y); if (lz > ly) lz = ly; z = cgetr(lz); while (--lz) z[lz] = y[lz]; setsigne(z,sy); return z; } if (e < 0) { swap(x,y); lswap(sx,sy); ey=ex; e=-e; } /* now ey >= ex */ lx = lg(x); ly = lg(y); /* If exponents differ, need to shift one argument, here x. If * extend = 1: extension of x,z by m < BIL bits (round to 1 word) */ /* in this case, lz = lx + d + 1, otherwise lx + d */ extend = 0; if (e) { long d = dvmdsBIL(e, &m), l = ly-d; if (l <= 2) return rcopy_sign(y, sy); if (l > lx) { lz = lx + d + 1; extend = 1; } else { lz = ly; lx = l; } if (m) { /* shift x right m bits */ const pari_sp av = avma; const ulong sh = BITS_IN_LONG-m; GEN p1 = x; x = new_chunk(lx + lz + 1); shift_right(x,p1,2,lx, 0,m); if (extend) uel(x,lx) = uel(p1,lx-1) << sh; avma = av; /* HACK: cgetr(lz) will not overwrite x */ } } else { /* d = 0 */ m = 0; if (lx > ly) lx = ly; lz = lx; } if (sx == sy) { /* addition */ i = lz-1; j = lx-1; if (extend) { ulong garde = addll(x[lx], y[i]); if (m < 4) /* don't extend for few correct bits */ z = cgetr(--lz); else { z = cgetr(lz); z[i] = garde; } } else { z = cgetr(lz); z[i] = addll(x[j], y[i]); j--; } i--; for (; j>=2; i--,j--) z[i] = addllx(x[j],y[i]); if (overflow) { z[1] = 1; /* stops since z[1] != 0 */ for (;;) { z[i] = uel(y,i)+1; if (z[i--]) break; } if (i <= 0) { shift_right(z,z, 2,lz, 1,1); z[1] = evalsigne(sx) | evalexpo(ey+1); return z; } } for (; i>=2; i--) z[i] = y[i]; z[1] = evalsigne(sx) | evalexpo(ey); return z; } /* subtraction */ if (e) f2 = 1; else { i = 2; while (i < lx && x[i] == y[i]) i++; if (i==lx) return real_0_bit(ey+1 - prec2nbits(lx)); f2 = (uel(y,i) > uel(x,i)); } /* result is non-zero. f2 = (y > x) */ i = lz-1; z = cgetr(lz); if (f2) { j = lx-1; if (extend) z[i] = subll(y[i], x[lx]); else z[i] = subll(y[i], x[j--]); for (i--; j>=2; i--) z[i] = subllx(y[i], x[j--]); if (overflow) /* stops since y[1] != 0 */ for (;;) { z[i] = uel(y,i)-1; if (y[i--]) break; } for (; i>=2; i--) z[i] = y[i]; sx = sy; } else { if (extend) z[i] = subll(x[lx], y[i]); else z[i] = subll(x[i], y[i]); for (i--; i>=2; i--) z[i] = subllx(x[i], y[i]); } x = z+2; i = 0; while (!x[i]) i++; lz -= i; z += i; j = bfffo(z[2]); /* need to shift left by j bits to normalize mantissa */ ez = ey - (j | (i * BITS_IN_LONG)); if (extend) { /* z was extended by d+1 words [should be e bits = d words + m bits] */ /* not worth keeping extra word if less than 5 significant bits in there */ if (m - j < 5 && lz > 3) { /* shorten z */ ulong last = (ulong)z[--lz]; /* cancelled word */ /* if we need to shift anyway, shorten from left * If not, shorten from right, neutralizing last word of z */ if (j == 0) /* stackdummy((pari_sp)(z + lz+1), (pari_sp)(z + lz)); */ z[lz] = evaltyp(t_VECSMALL) | _evallg(1); else { GEN t = z; z++; shift_left(z,t,2,lz-1, last,j); } if ((last< 1) i--; if (i == 1) { ez++; z[2] = (long)HIGHBIT; } } } else if (j) shift_left(z,z,2,lz-1, 0,j); } else if (j) shift_left(z,z,2,lz-1, 0,j); z[1] = evalsigne(sx) | evalexpo(ez); z[0] = evaltyp(t_REAL) | evallg(lz); avma = (pari_sp)z; return z; } pari-2.11.2/src/kernel/none/ratlift.c0000644000175000017500000002473113326135265016012 0ustar billbill#line 2 "../src/kernel/none/ratlift.c" /* Copyright (C) 2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*========================================================== * Fp_ratlift(GEN x, GEN m, GEN *a, GEN *b, GEN amax, GEN bmax) *========================================================== * Reconstruct rational number from its residue x mod m * Given t_INT x, m, amax>=0, bmax>0 such that * 0 <= x < m; 2*amax*bmax < m * attempts to find t_INT a, b such that * (1) a = b*x (mod m) * (2) |a| <= amax, 0 < b <= bmax * (3) gcd(m, b) = gcd(a, b) * If unsuccessful, it will return 0 and leave a,b unchanged (and * caller may deduce no such a,b exist). If successful, sets a,b * and returns 1. If there exist a,b satisfying (1), (2), and * (3') gcd(m, b) = 1 * then they are uniquely determined subject to (1),(2) and * (3'') gcd(a, b) = 1, * and will be returned by the routine. (The caller may wish to * check gcd(a,b)==1, either directly or based on known prime * divisors of m, depending on the application.) * Reference: @article {MR97c:11116, AUTHOR = {Collins, George E. and Encarnaci{\'o}n, Mark J.}, TITLE = {Efficient rational number reconstruction}, JOURNAL = {J. Symbolic Comput.}, VOLUME = {20}, YEAR = {1995}, NUMBER = {3}, PAGES = {287--297}, } * Preprint available from: * ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1994/94-64.ps.gz */ static ulong get_vmax(GEN r, long lb, long lbb) { long lr = lb - lgefint(r); ulong vmax; if (lr > 1) /* still more than a word's worth to go */ vmax = ULONG_MAX; /* (cannot in fact happen) */ else { /* take difference of bit lengths */ long lbr = bfffo(*int_MSW(r)); lr = lr*BITS_IN_LONG - lbb + lbr; if ((ulong)lr > BITS_IN_LONG) vmax = ULONG_MAX; else if (lr == 0) vmax = 1UL; else vmax = 1UL << (lr-1); /* pessimistic but faster than a division */ } return vmax; } /* Assume x,m,amax >= 0,bmax > 0 are t_INTs, 0 <= x < m, 2 amax * bmax < m */ int Fp_ratlift(GEN x, GEN m, GEN amax, GEN bmax, GEN *a, GEN *b) { GEN d, d1, v, v1, q, r; pari_sp av = avma, av1; long lb, lbb, s, s0; ulong vmax; ulong xu, xu1, xv, xv1; /* Lehmer stage recurrence matrix */ int lhmres; /* Lehmer stage return value */ /* special cases x=0 and/or amax=0 */ if (!signe(x)) { *a = gen_0; *b = gen_1; return 1; } if (!signe(amax)) return 0; /* assert: m > x > 0, amax > 0 */ /* check whether a=x, b=1 is a solution */ if (cmpii(x,amax) <= 0) { *a = icopy(x); *b = gen_1; return 1; } /* There is no special case for single-word numbers since this is * mainly meant to be used with large moduli. */ (void)new_chunk(lgefint(bmax) + lgefint(amax)); /* room for a,b */ d = m; d1 = x; v = gen_0; v1 = gen_1; /* assert d1 > amax, v1 <= bmax here */ lb = lgefint(bmax); lbb = bfffo(*int_MSW(bmax)); s = 1; av1 = avma; /* General case: Euclidean division chain starting with m div x, and * with bounds on the sequence of convergents' denoms v_j. * Just to be different from what invmod and bezout are doing, we work * here with the all-nonnegative matrices [u,u1;v,v1]=prod_j([0,1;1,q_j]). * Loop invariants: * (a) (sign)*[-v,v1]*x = [d,d1] (mod m) (componentwise) * (sign initially +1, changes with each Euclidean step) * so [a,b] will be obtained in the form [-+d,v] or [+-d1,v1]; * this congruence is a consequence of * * (b) [x,m]~ = [u,u1;v,v1]*[d1,d]~, * where u,u1 is the usual numerator sequence starting with 1,0 * instead of 0,1 (just multiply the eqn on the left by the inverse * matrix, which is det*[v1,-u1;-v,u], where "det" is the same as the * "(sign)" in (a)). From m = v*d1 + v1*d and * * (c) d > d1 >= 0, 0 <= v < v1, * we have d >= m/(2*v1), so while v1 remains smaller than m/(2*amax), * the pair [-(sign)*d,v] satisfies (1) but violates (2) (d > amax). * Conversely, v1 > bmax indicates that no further solutions will be * forthcoming; [-(sign)*d,v] will be the last, and first, candidate. * Thus there's at most one point in the chain division where a solution * can live: v < bmax, v1 >= m/(2*amax) > bmax, and this is acceptable * iff in fact d <= amax (e.g. m=221, x=34 or 35, amax=bmax=10 fail on * this count while x=32,33,36,37 succeed). However, a division may leave * a zero residue before we ever reach this point (consider m=210, x=35, * amax=bmax=10), and our caller may find that gcd(d,v) > 1 (Examples: * keep m=210 and consider any of x=29,31,32,33,34,36,37,38,39,40,41). * Furthermore, at the start of the loop body we have in fact * * (c') 0 <= v < v1 <= bmax, d > d1 > amax >= 0, * (and are never done already). * * Main loop is similar to those of invmod() and bezout(), except for * having to determine appropriate vmax bounds, and checking termination * conditions. The signe(d1) condition is only for paranoia */ while (lgefint(d) > 3 && signe(d1)) { /* determine vmax for lgcdii so as to ensure v won't overshoot. * If v+v1 > bmax, the next step would take v1 beyond the limit, so * since [+-d1,v1] is not a solution, we give up. Otherwise if v+v1 * is way shorter than bmax, use vmax=MAXULUNG. Otherwise, set vmax * to a crude lower approximation of bmax/(v+v1), or to 1, which will * allow the inner loop to do one step */ r = addii(v,v1); if (cmpii(r,bmax) > 0) { avma = av; return 0; } /* done, not found */ vmax = get_vmax(r, lb, lbb); /* do a Lehmer-Jebelean round */ lhmres = lgcdii((ulong *)d, (ulong *)d1, &xu, &xu1, &xv, &xv1, vmax); if (lhmres) /* check progress */ { /* apply matrix */ if (lhmres == 1 || lhmres == -1) { s = -s; if (xv1 == 1) { /* re-use v+v1 computed above */ v = v1; v1 = r; r = subii(d,d1); d = d1; d1 = r; } else { r = subii(d, mului(xv1,d1)); d = d1; d1 = r; r = addii(v, mului(xv1,v1)); v = v1; v1 = r; } } else { r = subii(muliu(d,xu), muliu(d1,xv)); d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r; r = addii(muliu(v,xu), muliu(v1,xv)); v1 = addii(muliu(v,xu1), muliu(v1,xv1)); v = r; if (lhmres&1) { togglesign(d); s = -s; } else togglesign(d1); } /* check whether we're done. Assert v <= bmax here. Examine v1: * if v1 > bmax, check d and return 0 or 1 depending on the outcome; * if v1 <= bmax, check d1 and return 1 if d1 <= amax, otherwise proceed*/ if (cmpii(v1,bmax) > 0) { avma = av; if (cmpii(d,amax) > 0) return 0; /* done, not found */ /* done, found */ *a = icopy(d); setsigne(*a,-s); *b = icopy(v); return 1; } if (cmpii(d1,amax) <= 0) { /* done, found */ avma = av; if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); } else *a = gen_0; *b = icopy(v1); return 1; } } /* lhmres != 0 */ if (lhmres <= 0 && signe(d1)) { q = dvmdii(d,d1,&r); d = d1; d1 = r; r = addii(v, mulii(q,v1)); v = v1; v1 = r; s = -s; /* check whether we are done now. Since we weren't before the div, it * suffices to examine v1 and d1 -- the new d (former d1) cannot cut it */ if (cmpii(v1,bmax) > 0) { avma = av; return 0; } /* done, not found */ if (cmpii(d1,amax) <= 0) /* done, found */ { avma = av; if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); } else *a = gen_0; *b = icopy(v1); return 1; } } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"ratlift"); gerepileall(av1, 4, &d, &d1, &v, &v1); } } /* end while */ /* Postprocessing - final sprint. Since we usually underestimate vmax, * this function needs a loop here instead of a simple conditional. * Note we can only get here when amax fits into one word (which will * typically not be the case!). The condition is bogus -- d1 is never * zero at the start of the loop. There will be at most a few iterations, * so we don't bother collecting garbage */ while (signe(d1)) { /* Assertions: lgefint(d)==lgefint(d1)==3. * Moreover, we aren't done already, or we would have returned by now. * Recompute vmax */ r = addii(v,v1); if (cmpii(r,bmax) > 0) { avma = av; return 0; } /* done, not found */ vmax = get_vmax(r, lb, lbb); /* single-word "Lehmer", discarding the gcd or whatever it returns */ (void)rgcduu((ulong)*int_MSW(d), (ulong)*int_MSW(d1), vmax, &xu, &xu1, &xv, &xv1, &s0); if (xv1 == 1) /* avoid multiplications */ { /* re-use r = v+v1 computed above */ v = v1; v1 = r; r = subii(d,d1); d = d1; d1 = r; s = -s; } else if (xu == 0) /* and xv==1, xu1==1, xv1 > 1 */ { r = subii(d, mului(xv1,d1)); d = d1; d1 = r; r = addii(v, mului(xv1,v1)); v = v1; v1 = r; s = -s; } else { r = subii(muliu(d,xu), muliu(d1,xv)); d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r; r = addii(muliu(v,xu), muliu(v1,xv)); v1 = addii(muliu(v,xu1), muliu(v1,xv1)); v = r; if (s0 < 0) { togglesign(d); s = -s; } else togglesign(d1); } /* check whether we're done, as above. Assert v <= bmax. * if v1 > bmax, check d and return 0 or 1 depending on the outcome; * if v1 <= bmax, check d1 and return 1 if d1 <= amax, otherwise proceed. */ if (cmpii(v1,bmax) > 0) { avma = av; if (cmpii(d,amax) > 0) return 0; /* done, not found */ /* done, found */ *a = icopy(d); setsigne(*a,-s); *b = icopy(v); return 1; } if (cmpii(d1,amax) <= 0) { /* done, found */ avma = av; if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); } else *a = gen_0; *b = icopy(v1); return 1; } } /* while */ /* We have run into d1 == 0 before returning. This cannot happen */ pari_err_BUG("ratlift failed to catch d1 == 0"); return 0; /* LCOV_EXCL_LINE */ } pari-2.11.2/src/kernel/none/asm0.h0000644000175000017500000000114113036414402015167 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* NOASM addll mulll bfffo divll */ pari-2.11.2/src/kernel/none/bfffo.h0000644000175000017500000000372713036414402015425 0ustar billbill#line 2 "../src/kernel/none/bfffo.h" /* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #if !defined(INLINE) extern int bfffo(ulong x); #else #if defined(__GNUC__) && !defined(DISABLE_INLINE) #ifdef LONG_IS_64BIT # define bfffo(x) \ __extension__ ({ \ static int __bfffo_tabshi[16]={4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0};\ int __value = BITS_IN_LONG - 4; \ ulong __arg1=(x); \ if (__arg1 & ~0xffffffffUL) {__value -= 32; __arg1 >>= 32;}\ if (__arg1 & ~0xffffUL) {__value -= 16; __arg1 >>= 16;} \ if (__arg1 & ~0x00ffUL) {__value -= 8; __arg1 >>= 8;} \ if (__arg1 & ~0x000fUL) {__value -= 4; __arg1 >>= 4;} \ __value + __bfffo_tabshi[__arg1]; \ }) #else # define bfffo(x) \ __extension__ ({ \ static int __bfffo_tabshi[16]={4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0};\ int __value = BITS_IN_LONG - 4; \ ulong __arg1=(x); \ if (__arg1 & ~0xffffUL) {__value -= 16; __arg1 >>= 16;} \ if (__arg1 & ~0x00ffUL) {__value -= 8; __arg1 >>= 8;} \ if (__arg1 & ~0x000fUL) {__value -= 4; __arg1 >>= 4;} \ __value + __bfffo_tabshi[__arg1]; \ }) #endif #else INLINE int bfffo(ulong x) { static int tabshi[16]={4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0}; int value = BITS_IN_LONG - 4; ulong arg1=x; #ifdef LONG_IS_64BIT if (arg1 & ~0xffffffffUL) {value -= 32; arg1 >>= 32;} #endif if (arg1 & ~0xffffUL) {value -= 16; arg1 >>= 16;} if (arg1 & ~0x00ffUL) {value -= 8; arg1 >>= 8;} if (arg1 & ~0x000fUL) {value -= 4; arg1 >>= 4;} return value + tabshi[arg1]; } #endif #endif pari-2.11.2/src/kernel/none/mp_indep.c0000644000175000017500000005705413326135265016144 0ustar billbill#line 2 "../src/kernel/none/mp_indep.c" /* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Find c such that 1=c*b mod 2^BITS_IN_LONG, assuming b odd (unchecked) */ ulong invmod2BIL(ulong b) { static int tab[] = { 0, 0, 0, 8, 0, 8, 0, 0 }; ulong x = b + tab[b & 7]; /* b^(-1) mod 2^4 */ /* Newton applied to 1/x - b = 0 */ #ifdef LONG_IS_64BIT x = x*(2-b*x); /* one more pass necessary */ #endif x = x*(2-b*x); x = x*(2-b*x); return x*(2-b*x); } void affrr(GEN x, GEN y) { long i, lx, ly = lg(y); if (!signe(x)) { y[1] = evalexpo(minss(expo(x), -bit_accuracy(ly))); return; } y[1] = x[1]; lx = lg(x); if (lx <= ly) { for (i=2; i ly: round properly */ if (x[ly] & HIGHBIT) roundr_up_ip(y, ly); } GEN trunc2nr(GEN x, long n) { long ex; if (!signe(x)) return gen_0; ex = expo(x) + n; if (ex < 0) return gen_0; return mantissa2nr(x, ex - bit_prec(x) + 1); } /* x a t_REAL, x = i/2^e, i a t_INT */ GEN mantissa_real(GEN x, long *e) { *e = bit_prec(x)-1-expo(x); return mantissa2nr(x, 0); } GEN mului(ulong x, GEN y) { long s = signe(y); GEN z; if (!s || !x) return gen_0; z = muluispec(x, y+2, lgefint(y)-2); setsigne(z,s); return z; } GEN mulsi(long x, GEN y) { long s = signe(y); GEN z; if (!s || !x) return gen_0; if (x<0) { s = -s; x = -x; } z = muluispec((ulong)x, y+2, lgefint(y)-2); setsigne(z,s); return z; } GEN mulss(long x, long y) { long p1; LOCAL_HIREMAINDER; if (!x || !y) return gen_0; if (x<0) { x = -x; if (y<0) { y = -y; p1 = mulll(x,y); return uutoi(hiremainder, p1); } p1 = mulll(x,y); return uutoineg(hiremainder, p1); } else { if (y<0) { y = -y; p1 = mulll(x,y); return uutoineg(hiremainder, p1); } p1 = mulll(x,y); return uutoi(hiremainder, p1); } } GEN sqrs(long x) { long p1; LOCAL_HIREMAINDER; if (!x) return gen_0; if (x<0) x = -x; p1 = mulll(x,x); return uutoi(hiremainder, p1); } GEN muluu(ulong x, ulong y) { long p1; LOCAL_HIREMAINDER; if (!x || !y) return gen_0; p1 = mulll(x,y); return uutoi(hiremainder, p1); } GEN sqru(ulong x) { long p1; LOCAL_HIREMAINDER; if (!x) return gen_0; p1 = mulll(x,x); return uutoi(hiremainder, p1); } /* assume x > 1, y != 0. Return u * y with sign s */ static GEN mulur_2(ulong x, GEN y, long s) { long m, sh, i, lx = lg(y), e = expo(y); GEN z = cgetr(lx); ulong garde; LOCAL_HIREMAINDER; y--; garde = mulll(x,y[lx]); for (i=lx-1; i>=3; i--) z[i]=addmul(x,y[i]); z[2]=hiremainder; /* != 0 since y normalized and |x| > 1 */ sh = bfffo(hiremainder); m = BITS_IN_LONG-sh; if (sh) shift_left(z,z, 2,lx-1, garde,sh); z[1] = evalsigne(s) | evalexpo(m+e); if ((garde << sh) & HIGHBIT) roundr_up_ip(z, lx); return z; } INLINE GEN mul0r(GEN x) { long l = lg(x), e = expo(x); e = (l > 2)? -prec2nbits(l) + e: (e < 0? 2*e: 0); return real_0_bit(e); } /* lg(x) > 2 */ INLINE GEN div0r(GEN x) { long l = lg(x), e = expo(x); return real_0_bit(-prec2nbits(l) - e); } GEN mulsr(long x, GEN y) { long s; if (!x) return mul0r(y); s = signe(y); if (!s) { if (x < 0) x = -x; return real_0_bit( expo(y) + expu(x) ); } if (x==1) return rcopy(y); if (x==-1) return negr(y); if (x < 0) return mulur_2((ulong)-x, y, -s); else return mulur_2((ulong)x, y, s); } GEN mulur(ulong x, GEN y) { long s; if (!x) return mul0r(y); s = signe(y); if (!s) return real_0_bit( expo(y) + expu(x) ); if (x==1) return rcopy(y); return mulur_2(x, y, s); } INLINE void mulrrz_end(GEN z, GEN hi, long lz, long sz, long ez, ulong garde) { long i; if (hi[2] < 0) { if (z != hi) for (i=2; i1 && z[i]==0); if (i == 1) { z[2] = (long)HIGHBIT; ez++; } } z[1] = evalsigne(sz)|evalexpo(ez); } /* mulrrz_end for lz = 3, minor simplifications. z[2]=hiremainder from mulll */ INLINE void mulrrz_3end(GEN z, long sz, long ez, ulong garde) { if (z[2] < 0) { /* z2 < (2^BIL-1)^2 / 2^BIL, hence z2+1 != 0 */ if (garde & HIGHBIT) z[2]++; /* round properly */ ez++; } else { uel(z,2) = (uel(z,2)<<1) | (garde>>(BITS_IN_LONG-1)); if (garde & (1UL<<(BITS_IN_LONG-2))) { uel(z,2)++; /* round properly, z2+1 can overflow */ if (!uel(z,2)) { uel(z,2) = HIGHBIT; ez++; } } } z[1] = evalsigne(sz)|evalexpo(ez); } /* set z <-- x^2 != 0, floating point multiplication. * lz = lg(z) = lg(x) */ INLINE void sqrz_i(GEN z, GEN x, long lz) { long ez = 2*expo(x); long i, j, lzz, p1; ulong garde; GEN x1; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (lz > SQRR_SQRI_LIMIT) { pari_sp av = avma; GEN hi = sqrispec_mirror(x+2, lz-2); mulrrz_end(z, hi, lz, 1, ez, hi[lz]); avma = av; return; } if (lz == 3) { garde = mulll(x[2],x[2]); z[2] = hiremainder; mulrrz_3end(z, 1, ez, garde); return; } lzz = lz-1; p1 = x[lzz]; if (p1) { (void)mulll(p1,x[3]); garde = addmul(p1,x[2]); z[lzz] = hiremainder; } else { garde = 0; z[lzz] = 0; } for (j=lz-2, x1=x-j; j>=3; j--) { p1 = x[j]; x1++; if (p1) { (void)mulll(p1,x1[lz+1]); garde = addll(addmul(p1,x1[lz]), garde); for (i=lzz; i>j; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,x1[i]), z[i]); } z[j] = hiremainder+overflow; } else z[j]=0; } p1 = x[2]; x1++; garde = addll(mulll(p1,x1[lz]), garde); for (i=lzz; i>2; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,x1[i]), z[i]); } z[2] = hiremainder+overflow; mulrrz_end(z, z, lz, 1, ez, garde); } /* lz "large" = lg(y) = lg(z), lg(x) > lz if flag = 1 and >= if flag = 0 */ INLINE void mulrrz_int(GEN z, GEN x, GEN y, long lz, long flag, long sz) { pari_sp av = avma; GEN hi = muliispec_mirror(y+2, x+2, lz+flag-2, lz-2); mulrrz_end(z, hi, lz, sz, expo(x)+expo(y), hi[lz]); avma = av; } /* lz = 3 */ INLINE void mulrrz_3(GEN z, GEN x, GEN y, long flag, long sz) { ulong garde; LOCAL_HIREMAINDER; if (flag) { (void)mulll(x[2],y[3]); garde = addmul(x[2],y[2]); } else garde = mulll(x[2],y[2]); z[2] = hiremainder; mulrrz_3end(z, sz, expo(x)+expo(y), garde); } /* set z <-- x*y, floating point multiplication. Trailing 0s for x are * treated efficiently (important application: mulir). * lz = lg(z) = lg(x) <= ly <= lg(y), sz = signe(z). flag = lg(x) < lg(y) */ INLINE void mulrrz_i(GEN z, GEN x, GEN y, long lz, long flag, long sz) { long ez, i, j, lzz, p1; ulong garde; GEN y1; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (x == y) { sqrz_i(z,x,lz); return; } if (lz > MULRR_MULII_LIMIT) { mulrrz_int(z,x,y,lz,flag,sz); return; } if (lz == 3) { mulrrz_3(z,x,y,flag,sz); return; } ez = expo(x) + expo(y); if (flag) { (void)mulll(x[2],y[lz]); garde = hiremainder; } else garde = 0; lzz=lz-1; p1=x[lzz]; if (p1) { (void)mulll(p1,y[3]); garde = addll(addmul(p1,y[2]), garde); z[lzz] = overflow+hiremainder; } else z[lzz]=0; for (j=lz-2, y1=y-j; j>=3; j--) { p1 = x[j]; y1++; if (p1) { (void)mulll(p1,y1[lz+1]); garde = addll(addmul(p1,y1[lz]), garde); for (i=lzz; i>j; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,y1[i]), z[i]); } z[j] = hiremainder+overflow; } else z[j]=0; } p1 = x[2]; y1++; garde = addll(mulll(p1,y1[lz]), garde); for (i=lzz; i>2; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,y1[i]), z[i]); } z[2] = hiremainder+overflow; mulrrz_end(z, z, lz, sz, ez, garde); } GEN mulrr(GEN x, GEN y) { long flag, ly, lz, sx, sy; GEN z; if (x == y) return sqrr(x); sx = signe(x); if (!sx) return real_0_bit(expo(x) + expo(y)); sy = signe(y); if (!sy) return real_0_bit(expo(x) + expo(y)); if (sy < 0) sx = -sx; lz = lg(x); ly = lg(y); if (lz > ly) { lz = ly; swap(x, y); flag = 1; } else flag = (lz != ly); z = cgetr(lz); mulrrz_i(z, x,y, lz,flag, sx); return z; } GEN sqrr(GEN x) { long lz, sx = signe(x); GEN z; if (!sx) return real_0_bit(2*expo(x)); lz = lg(x); z = cgetr(lz); sqrz_i(z, x, lz); return z; } GEN mulir(GEN x, GEN y) { long sx = signe(x), sy; if (!sx) return mul0r(y); if (lgefint(x) == 3) { GEN z = mulur(uel(x,2), y); if (sx < 0) togglesign(z); return z; } sy = signe(y); if (!sy) return real_0_bit(expi(x) + expo(y)); if (sy < 0) sx = -sx; { long lz = lg(y), lx = lgefint(x); GEN hi, z = cgetr(lz); pari_sp av = avma; if (lx < (lz>>1) || (lx < lz && lz > MULRR_MULII_LIMIT)) { /* size mantissa of x < half size of mantissa z, or lx < lz so large * that mulrr will call mulii anyway: mulii */ x = itor(x, lx); hi = muliispec_mirror(y+2, x+2, lz-2, lx-2); mulrrz_end(z, hi, lz, sx, expo(x)+expo(y), hi[lz]); } else /* dubious: complete x with 0s and call mulrr */ mulrrz_i(z, itor(x,lz), y, lz, 0, sx); avma = av; return z; } } /* x + y*z, generic. If lgefint(z) <= 3, caller should use faster variants */ static GEN addmulii_gen(GEN x, GEN y, GEN z, long lz) { long lx = lgefint(x), ly; pari_sp av; GEN t; if (lx == 2) return mulii(z,y); ly = lgefint(y); if (ly == 2) return icopy(x); /* y = 0, wasteful copy */ av = avma; (void)new_chunk(lx+ly+lz); /*HACK*/ t = mulii(z, y); avma = av; return addii(t,x); } /* x + y*z, lgefint(z) == 3 */ static GEN addmulii_lg3(GEN x, GEN y, GEN z) { long s = signe(z), lx, ly; ulong w = z[2]; pari_sp av; GEN t; if (w == 1) return (s > 0)? addii(x,y): subii(x,y); /* z = +- 1 */ lx = lgefint(x); ly = lgefint(y); if (lx == 2) { /* x = 0 */ if (ly == 2) return gen_0; t = muluispec(w, y+2, ly-2); if (signe(y) < 0) s = -s; setsigne(t, s); return t; } if (ly == 2) return icopy(x); /* y = 0, wasteful copy */ av = avma; (void)new_chunk(1+lx+ly);/*HACK*/ t = muluispec(w, y+2, ly-2); if (signe(y) < 0) s = -s; setsigne(t, s); avma = av; return addii(x,t); } /* x + y*z */ GEN addmulii(GEN x, GEN y, GEN z) { long lz = lgefint(z); switch(lz) { case 2: return icopy(x); /* z = 0, wasteful copy */ case 3: return addmulii_lg3(x, y, z); default:return addmulii_gen(x, y, z, lz); } } /* x + y*z, returns x itself and not a copy when y*z = 0 */ GEN addmulii_inplace(GEN x, GEN y, GEN z) { long lz; if (lgefint(y) == 2) return x; lz = lgefint(z); switch(lz) { case 2: return x; case 3: return addmulii_lg3(x, y, z); default:return addmulii_gen(x, y, z, lz); } } /* written by Bruno Haible following an idea of Robert Harley */ long vals(ulong z) { static char tab[64]={-1,0,1,12,2,6,-1,13,3,-1,7,-1,-1,-1,-1,14,10,4,-1,-1,8,-1,-1,25,-1,-1,-1,-1,-1,21,27,15,31,11,5,-1,-1,-1,-1,-1,9,-1,-1,24,-1,-1,20,26,30,-1,-1,-1,-1,23,-1,19,29,-1,22,18,28,17,16,-1}; #ifdef LONG_IS_64BIT long s; #endif if (!z) return -1; #ifdef LONG_IS_64BIT if (! (z&0xffffffff)) { s = 32; z >>=32; } else s = 0; #endif z |= ~z + 1; z += z << 4; z += z << 6; z ^= z << 16; /* or z -= z<<16 */ #ifdef LONG_IS_64BIT return s + tab[(z&0xffffffff)>>26]; #else return tab[z>>26]; #endif } GEN divsi(long x, GEN y) { long p1, s = signe(y); LOCAL_HIREMAINDER; if (!s) pari_err_INV("divsi",gen_0); if (!x || lgefint(y)>3 || ((long)y[2])<0) return gen_0; hiremainder=0; p1=divll(labs(x),y[2]); if (x<0) { hiremainder = -((long)hiremainder); p1 = -p1; } if (s<0) p1 = -p1; return stoi(p1); } GEN divir(GEN x, GEN y) { GEN z; long ly = lg(y), lx = lgefint(x); pari_sp av; if (ly == 2) pari_err_INV("divir",y); if (lx == 2) return div0r(y); if (lx == 3) { z = divur(x[2], y); if (signe(x) < 0) togglesign(z); return z; } z = cgetr(ly); av = avma; affrr(divrr(itor(x, ly+1), y), z); avma = av; return z; } GEN divur(ulong x, GEN y) { pari_sp av; long ly = lg(y); GEN z; if (ly == 2) pari_err_INV("divur",y); if (!x) return div0r(y); if (ly > INVNEWTON_LIMIT) { av = avma; z = invr(y); if (x == 1) return z; return gerepileuptoleaf(av, mulur(x, z)); } z = cgetr(ly); av = avma; affrr(divrr(utor(x,ly+1), y), z); avma = av; return z; } GEN divsr(long x, GEN y) { pari_sp av; long ly = lg(y); GEN z; if (ly == 2) pari_err_INV("divsr",y); if (!x) return div0r(y); if (ly > INVNEWTON_LIMIT) { av = avma; z = invr(y); if (x == 1) return z; if (x ==-1) { togglesign(z); return z; } return gerepileuptoleaf(av, mulsr(x, z)); } z = cgetr(ly); av = avma; affrr(divrr(stor(x,ly+1), y), z); avma = av; return z; } /* returns 1/y, assume y != 0 */ static GEN invr_basecase(GEN y) { long ly = lg(y); GEN z = cgetr(ly); pari_sp av = avma; affrr(divrr(real_1(ly+1), y), z); avma = av; return z; } /* returns 1/b, Newton iteration */ GEN invr(GEN b) { const long s = 6; long i, p, l = lg(b); GEN x, a; ulong mask; if (l <= maxss(INVNEWTON_LIMIT, (1L<>= 1; } x = cgetr(l); a = rcopy(b); a[1] = _evalexpo(0) | evalsigne(1); affrr(invr_basecase(rtor(a, p+2)), x); while (mask > 1) { p <<= 1; if (mask & 1) p--; mask >>= 1; setlg(a, p + 2); setlg(x, p + 2); /* TODO: mulrr(a,x) should be a half product (the higher half is known). * mulrr(x, ) already is */ affrr(addrr(x, mulrr(x, subsr(1, mulrr(a,x)))), x); avma = (pari_sp)a; } x[1] = (b[1] & SIGNBITS) | evalexpo(expo(x)-expo(b)); avma = (pari_sp)x; return x; } GEN modii(GEN x, GEN y) { switch(signe(x)) { case 0: return gen_0; case 1: return remii(x,y); default: { pari_sp av = avma; (void)new_chunk(lgefint(y)); x = remii(x,y); avma=av; if (x==gen_0) return x; return subiispec(y+2,x+2,lgefint(y)-2,lgefint(x)-2); } } } void modiiz(GEN x, GEN y, GEN z) { const pari_sp av = avma; affii(modii(x,y),z); avma=av; } GEN divrs(GEN x, long y) { GEN z; if (y < 0) { z = divru(x, (ulong)-y); togglesign(z); } else z = divru(x, (ulong)y); return z; } GEN divru(GEN x, ulong y) { long i, lx, sh, e, s = signe(x); ulong garde; GEN z; LOCAL_HIREMAINDER; if (!y) pari_err_INV("divru",gen_0); if (!s) return real_0_bit(expo(x) - expu(y)); if (!(y & (y-1))) /* power of 2 */ { if (y == 1) return rcopy(x); return shiftr(x, -expu(y)); } e = expo(x); lx = lg(x); z = cgetr(lx); if (lx == 3) { if (y <= uel(x,2)) { hiremainder = 0; z[2] = divll(x[2],y); /* we may have hiremainder != 0 ==> garde */ garde = divll(0,y); } else { hiremainder = x[2]; z[2] = divll(0,y); garde = hiremainder; e -= BITS_IN_LONG; } } else { ulong yp = get_Fl_red(y); if (y <= uel(x,2)) { hiremainder = 0; for (i=2; i garde */ garde = divll_pre(0,y,yp); } else { long l = lx-1; hiremainder = x[2]; for (i=2; i= 0) { if (z) *z = utoi(r); return q; } q = gerepileuptoint(av, addis(q, (y < 0)? 1: -1)); if (z) *z = utoi(r + labs(y)); return q; } GEN truedvmdsi(long x, GEN y, GEN *z) { long q, r; if (z == ONLY_REM) return modsi(x, y); q = sdivsi_rem(x,y,&r); if (r >= 0) { if (z) *z = utoi(r); return stoi(q); } q = q - signe(y); if (!z) return stoi(q); *z = subiuspec(y+2,(ulong)-r, lgefint(y)-2); return stoi(q); } /* 2^n = shifti(gen_1, n) */ GEN int2n(long n) { long i, m, l; GEN z; if (n < 0) return gen_0; if (n == 0) return gen_1; l = dvmdsBIL(n, &m) + 3; z = cgetipos(l); for (i = 2; i < l; i++) z[i] = 0; *int_MSW(z) = 1UL << m; return z; } /* To avoid problems when 2^(BIL-1) < n. Overflow cleanly, where int2n * returns gen_0 */ GEN int2u(ulong n) { ulong i, m, l; GEN z; if (n == 0) return gen_1; l = dvmduBIL(n, &m) + 3; z = cgetipos(l); for (i = 2; i < l; i++) z[i] = 0; *int_MSW(z) = 1UL << m; return z; } /* 2^n - 1 */ GEN int2um1(ulong n) { ulong i, m, l; GEN z; if (n == 0) return gen_0; l = dvmduBIL(n, &m); l += m? 3: 2; z = cgetipos(l); for (i = 2; i < l; i++) z[i] = ~0UL; if (m) *int_MSW(z) = (1UL << m) - 1; return z; } GEN shifti(GEN x, long n) { long s = signe(x); GEN y; if(s == 0) return gen_0; y = shiftispec(x + 2, lgefint(x) - 2, n); if (signe(y)) setsigne(y, s); return y; } /* actual operations will take place on a+2 and b+2: we strip the codewords */ GEN mulii(GEN a,GEN b) { long sa,sb; GEN z; sa=signe(a); if (!sa) return gen_0; sb=signe(b); if (!sb) return gen_0; if (sb<0) sa = -sa; z = muliispec(a+2,b+2, lgefint(a)-2,lgefint(b)-2); setsigne(z,sa); return z; } GEN sqri(GEN a) { return sqrispec(a+2, lgefint(a)-2); } /* sqrt()'s result may be off by 1 when a is not representable exactly as a * double [64bit machine] */ ulong usqrt(ulong a) { ulong x = (ulong)sqrt((double)a); #ifdef LONG_IS_64BIT if (x > LOWMASK || x*x > a) x--; #endif return x; } /********************************************************************/ /** **/ /** EXPONENT / CONVERSION t_REAL --> double **/ /** **/ /********************************************************************/ #ifdef LONG_IS_64BIT long dblexpo(double x) { union { double f; ulong i; } fi; const int mant_len = 52; /* mantissa bits (excl. hidden bit) */ const int exp_mid = 0x3ff;/* exponent bias */ if (x==0.) return -exp_mid; fi.f = x; return ((fi.i & (HIGHBIT-1)) >> mant_len) - exp_mid; } ulong dblmantissa(double x) { union { double f; ulong i; } fi; const int expo_len = 11; /* number of bits of exponent */ if (x==0.) return 0; fi.f = x; return (fi.i << expo_len) | HIGHBIT; } GEN dbltor(double x) { GEN z; long e; union { double f; ulong i; } fi; const int mant_len = 52; /* mantissa bits (excl. hidden bit) */ const int exp_mid = 0x3ff;/* exponent bias */ const int expo_len = 11; /* number of bits of exponent */ if (x==0.) return real_0_bit(-exp_mid); fi.f = x; z = cgetr(DEFAULTPREC); { const ulong a = fi.i; ulong A; e = ((a & (HIGHBIT-1)) >> mant_len) - exp_mid; if (e == exp_mid+1) pari_err_OVERFLOW("dbltor [NaN or Infinity]"); A = a << expo_len; if (e == -exp_mid) { /* unnormalized values */ int sh = bfffo(A); e -= sh-1; z[2] = A << sh; } else z[2] = HIGHBIT | A; z[1] = _evalexpo(e) | evalsigne(x<0? -1: 1); } return z; } double rtodbl(GEN x) { long ex,s=signe(x); ulong a; union { double f; ulong i; } fi; const int mant_len = 52; /* mantissa bits (excl. hidden bit) */ const int exp_mid = 0x3ff;/* exponent bias */ const int expo_len = 11; /* number of bits of exponent */ if (!s || (ex=expo(x)) < - exp_mid) return 0.0; /* start by rounding to closest */ a = (x[2] & (HIGHBIT-1)) + 0x400; if (a & HIGHBIT) { ex++; a=0; } if (ex >= exp_mid) pari_err_OVERFLOW("t_REAL->double conversion"); fi.i = ((ex + exp_mid) << mant_len) | (a >> expo_len); if (s<0) fi.i |= HIGHBIT; return fi.f; } #else /* LONG_IS_64BIT */ #if PARI_DOUBLE_FORMAT == 1 # define INDEX0 1 # define INDEX1 0 #elif PARI_DOUBLE_FORMAT == 0 # define INDEX0 0 # define INDEX1 1 #endif long dblexpo(double x) { union { double f; ulong i[2]; } fi; const int mant_len = 52; /* mantissa bits (excl. hidden bit) */ const int exp_mid = 0x3ff;/* exponent bias */ const int shift = mant_len-32; if (x==0.) return -exp_mid; fi.f = x; { const ulong a = fi.i[INDEX0]; return ((a & (HIGHBIT-1)) >> shift) - exp_mid; } } ulong dblmantissa(double x) { union { double f; ulong i[2]; } fi; const int expo_len = 11; /* number of bits of exponent */ if (x==0.) return 0; fi.f = x; { const ulong a = fi.i[INDEX0]; const ulong b = fi.i[INDEX1]; return HIGHBIT | b >> (BITS_IN_LONG-expo_len) | (a << expo_len); } } GEN dbltor(double x) { GEN z; long e; union { double f; ulong i[2]; } fi; const int mant_len = 52; /* mantissa bits (excl. hidden bit) */ const int exp_mid = 0x3ff;/* exponent bias */ const int expo_len = 11; /* number of bits of exponent */ const int shift = mant_len-32; if (x==0.) return real_0_bit(-exp_mid); fi.f = x; z = cgetr(DEFAULTPREC); { const ulong a = fi.i[INDEX0]; const ulong b = fi.i[INDEX1]; ulong A, B; e = ((a & (HIGHBIT-1)) >> shift) - exp_mid; if (e == exp_mid+1) pari_err_OVERFLOW("dbltor [NaN or Infinity]"); A = b >> (BITS_IN_LONG-expo_len) | (a << expo_len); B = b << expo_len; if (e == -exp_mid) { /* unnormalized values */ int sh; if (A) { sh = bfffo(A); e -= sh-1; z[2] = (A << sh) | (B >> (32-sh)); z[3] = B << sh; } else { sh = bfffo(B); /* B != 0 */ e -= sh-1 + 32; z[2] = B << sh; z[3] = 0; } } else { z[3] = B; z[2] = HIGHBIT | A; } z[1] = _evalexpo(e) | evalsigne(x<0? -1: 1); } return z; } double rtodbl(GEN x) { long ex,s=signe(x),lx=lg(x); ulong a,b,k; union { double f; ulong i[2]; } fi; const int mant_len = 52; /* mantissa bits (excl. hidden bit) */ const int exp_mid = 0x3ff;/* exponent bias */ const int expo_len = 11; /* number of bits of exponent */ const int shift = mant_len-32; if (!s || (ex=expo(x)) < - exp_mid) return 0.0; /* start by rounding to closest */ a = x[2] & (HIGHBIT-1); if (lx > 3) { b = x[3] + 0x400UL; if (b < 0x400UL) a++; if (a & HIGHBIT) { ex++; a=0; } } else b = 0; if (ex >= exp_mid) pari_err_OVERFLOW("t_REAL->double conversion"); ex += exp_mid; k = (a >> expo_len) | (ex << shift); if (s<0) k |= HIGHBIT; fi.i[INDEX0] = k; fi.i[INDEX1] = (a << (BITS_IN_LONG-expo_len)) | (b >> expo_len); return fi.f; } #endif /* LONG_IS_64BIT */ pari-2.11.2/src/kernel/none/tune-gen.h0000644000175000017500000001066213326135265016072 0ustar billbill#ifdef PARI_TUNE long AGM_ATAN_LIMIT = __AGM_ATAN_LIMIT; long DIVRR_GMP_LIMIT = __DIVRR_GMP_LIMIT; long EXPNEWTON_LIMIT = __EXPNEWTON_LIMIT; long F2x_MUL_KARATSUBA_LIMIT = __F2x_MUL_KARATSUBA_LIMIT; long Flx_BARRETT_QUARTMULII_LIMIT = __Flx_BARRETT_QUARTMULII_LIMIT; long Flx_BARRETT_HALFMULII_LIMIT = __Flx_BARRETT_HALFMULII_LIMIT; long Flx_BARRETT_KARATSUBA_LIMIT = __Flx_BARRETT_KARATSUBA_LIMIT; long Flx_BARRETT_MULII2_LIMIT = __Flx_BARRETT_MULII2_LIMIT; long Flx_BARRETT_MULII_LIMIT = __Flx_BARRETT_MULII_LIMIT; long Flx_DIVREM_BARRETT_LIMIT = __Flx_DIVREM_BARRETT_LIMIT; long Flx_EXTGCD_LIMIT = __Flx_EXTGCD_LIMIT; long Flx_GCD_LIMIT = __Flx_GCD_LIMIT; long Flx_HALFGCD_QUARTMULII_LIMIT = __Flx_HALFGCD_QUARTMULII_LIMIT; long Flx_HALFGCD_HALFMULII_LIMIT = __Flx_HALFGCD_HALFMULII_LIMIT; long Flx_HALFGCD_KARATSUBA_LIMIT = __Flx_HALFGCD_KARATSUBA_LIMIT; long Flx_HALFGCD_MULII2_LIMIT = __Flx_HALFGCD_MULII2_LIMIT; long Flx_HALFGCD_MULII_LIMIT = __Flx_HALFGCD_MULII_LIMIT; long Flx_INVBARRETT_QUARTMULII_LIMIT = __Flx_INVBARRETT_QUARTMULII_LIMIT; long Flx_INVBARRETT_HALFMULII_LIMIT = __Flx_INVBARRETT_HALFMULII_LIMIT; long Flx_INVBARRETT_KARATSUBA_LIMIT = __Flx_INVBARRETT_KARATSUBA_LIMIT; long Flx_INVBARRETT_MULII2_LIMIT = __Flx_INVBARRETT_MULII2_LIMIT; long Flx_INVBARRETT_MULII_LIMIT = __Flx_INVBARRETT_MULII_LIMIT; long Flx_MUL_QUARTMULII_LIMIT = __Flx_MUL_QUARTMULII_LIMIT; long Flx_MUL_HALFMULII_LIMIT = __Flx_MUL_HALFMULII_LIMIT; long Flx_MUL_KARATSUBA_LIMIT = __Flx_MUL_KARATSUBA_LIMIT; long Flx_MUL_MULII2_LIMIT = __Flx_MUL_MULII2_LIMIT; long Flx_MUL_MULII_LIMIT = __Flx_MUL_MULII_LIMIT; long Flx_REM_BARRETT_LIMIT = __Flx_REM_BARRETT_LIMIT; long Flx_SQR_QUARTSQRI_LIMIT = __Flx_SQR_QUARTSQRI_LIMIT; long Flx_SQR_HALFSQRI_LIMIT = __Flx_SQR_HALFSQRI_LIMIT; long Flx_SQR_KARATSUBA_LIMIT = __Flx_SQR_KARATSUBA_LIMIT; long Flx_SQR_SQRI2_LIMIT = __Flx_SQR_SQRI2_LIMIT; long Flx_SQR_SQRI_LIMIT = __Flx_SQR_SQRI_LIMIT; long F2xqX_BARRETT_LIMIT = __F2xqX_BARRETT_LIMIT; long F2xqX_DIVREM_BARRETT_LIMIT = __F2xqX_DIVREM_BARRETT_LIMIT; long F2xqX_INVBARRETT_LIMIT = __F2xqX_INVBARRETT_LIMIT; long F2xqX_REM_BARRETT_LIMIT = __F2xqX_REM_BARRETT_LIMIT; long FlxqX_BARRETT_LIMIT = __FlxqX_BARRETT_LIMIT; long FlxqX_DIVREM_BARRETT_LIMIT = __FlxqX_DIVREM_BARRETT_LIMIT; long FlxqX_EXTGCD_LIMIT = __FlxqX_EXTGCD_LIMIT; long FlxqX_GCD_LIMIT = __FlxqX_GCD_LIMIT; long FlxqX_HALFGCD_LIMIT = __FlxqX_HALFGCD_LIMIT; long FlxqX_INVBARRETT_LIMIT = __FlxqX_INVBARRETT_LIMIT; long FlxqX_REM_BARRETT_LIMIT = __FlxqX_REM_BARRETT_LIMIT; long FpX_BARRETT_LIMIT = __FpX_BARRETT_LIMIT; long FpX_DIVREM_BARRETT_LIMIT = __FpX_DIVREM_BARRETT_LIMIT; long FpX_EXTGCD_LIMIT = __FpX_EXTGCD_LIMIT; long FpX_GCD_LIMIT = __FpX_GCD_LIMIT; long FpX_HALFGCD_LIMIT = __FpX_HALFGCD_LIMIT; long FpX_INVBARRETT_LIMIT = __FpX_INVBARRETT_LIMIT; long FpX_REM_BARRETT_LIMIT = __FpX_REM_BARRETT_LIMIT; long FpXQX_BARRETT_LIMIT = __FpXQX_BARRETT_LIMIT; long FpXQX_DIVREM_BARRETT_LIMIT = __FpXQX_DIVREM_BARRETT_LIMIT; long FpXQX_EXTGCD_LIMIT = __FpXQX_EXTGCD_LIMIT; long FpXQX_GCD_LIMIT = __FpXQX_GCD_LIMIT; long FpXQX_HALFGCD_LIMIT = __FpXQX_HALFGCD_LIMIT; long FpXQX_INVBARRETT_LIMIT = __FpXQX_INVBARRETT_LIMIT; long FpXQX_REM_BARRETT_LIMIT = __FpXQX_REM_BARRETT_LIMIT; long Fp_POW_BARRETT_LIMIT = __Fp_POW_BARRETT_LIMIT; long Fp_POW_REDC_LIMIT = __Fp_POW_REDC_LIMIT; long INVMOD_GMP_LIMIT = __INVMOD_GMP_LIMIT; long INVNEWTON_LIMIT = __INVNEWTON_LIMIT; long LOGAGMCX_LIMIT = __LOGAGMCX_LIMIT; long LOGAGM_LIMIT = __LOGAGM_LIMIT; long MULII_FFT_LIMIT = __MULII_FFT_LIMIT; long MULII_KARATSUBA_LIMIT = __MULII_KARATSUBA_LIMIT; long MULRR_MULII_LIMIT = __MULRR_MULII_LIMIT; long RgX_MUL_LIMIT = __RgX_MUL_LIMIT; long RgX_SQR_LIMIT = __RgX_SQR_LIMIT; long SQRI_FFT_LIMIT = __SQRI_FFT_LIMIT; long SQRI_KARATSUBA_LIMIT = __SQRI_KARATSUBA_LIMIT; long SQRR_SQRI_LIMIT = __SQRR_SQRI_LIMIT; #endif pari-2.11.2/src/kernel/none/gcdext.c0000644000175000017500000001355213326135265015622 0ustar billbill#line 2 "../src/kernel/none/gcdext.c" /* Copyright (C) 2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*================================== * bezout(a,b,pu,pv) *================================== * Return g = gcd(a,b) >= 0, and assign GENs u,v through pointers pu,pv * such that g = u*a + v*b. * Special cases: * a == b == 0 ==> pick u=1, v=0 * a != 0 == b ==> keep v=0 * a == 0 != b ==> keep u=0 * |a| == |b| != 0 ==> keep u=0, set v=+-1 * Assignments through pu,pv will be suppressed when the corresponding * pointer is NULL (but the computations will happen nonetheless). */ GEN bezout(GEN a, GEN b, GEN *pu, GEN *pv) { GEN t,u,u1,v,v1,d,d1,q,r; GEN *pt; pari_sp av, av1; long s, sa, sb; ulong g; ulong xu,xu1,xv,xv1; /* Lehmer stage recurrence matrix */ int lhmres; /* Lehmer stage return value */ s = abscmpii(a,b); if (s < 0) { t=b; b=a; a=t; pt=pu; pu=pv; pv=pt; } /* now |a| >= |b| */ sa = signe(a); sb = signe(b); if (!sb) { if (pv) *pv = gen_0; switch(sa) { case 0: if (pu) *pu = gen_0; return gen_0; case 1: if (pu) *pu = gen_1; return icopy(a); case -1: if (pu) *pu = gen_m1; return(negi(a)); } } if (s == 0) /* |a| == |b| != 0 */ { if (pu) *pu = gen_0; if (sb > 0) { if (pv) *pv = gen_1; return icopy(b); } else { if (pv) *pv = gen_m1; return(negi(b)); } } /* now |a| > |b| > 0 */ if (lgefint(a) == 3) /* single-word affair */ { g = xxgcduu(uel(a,2), uel(b,2), 0, &xu, &xu1, &xv, &xv1, &s); sa = s > 0 ? sa : -sa; sb = s > 0 ? -sb : sb; if (pu) { if (xu == 0) *pu = gen_0; /* can happen when b divides a */ else if (xu == 1) *pu = sa < 0 ? gen_m1 : gen_1; else if (xu == 2) *pu = sa < 0 ? gen_m2 : gen_2; else { *pu = cgeti(3); (*pu)[1] = evalsigne(sa)|evallgefint(3); (*pu)[2] = xu; } } if (pv) { if (xv == 1) *pv = sb < 0 ? gen_m1 : gen_1; else if (xv == 2) *pv = sb < 0 ? gen_m2 : gen_2; else { *pv = cgeti(3); (*pv)[1] = evalsigne(sb)|evallgefint(3); (*pv)[2] = xv; } } if (g == 1) return gen_1; else if (g == 2) return gen_2; else return utoipos(g); } /* general case */ av = avma; (void)new_chunk(lgefint(b) + (lgefint(a)<<1)); /* room for u,v,gcd */ /* if a is significantly larger than b, calling lgcdii() is not the best * way to start -- reduce a mod b first */ if (lgefint(a) > lgefint(b)) { d = absi_shallow(b); q = dvmdii(absi_shallow(a), d, &d1); if (!signe(d1)) /* a == qb */ { avma = av; if (pu) *pu = gen_0; if (pv) *pv = sb < 0 ? gen_m1 : gen_1; return icopy(d); } else { u = gen_0; u1 = v = gen_1; v1 = negi(q); } /* if this results in lgefint(d) == 3, will fall past main loop */ } else { d = absi_shallow(a); d1 = absi_shallow(b); u = v1 = gen_1; u1 = v = gen_0; } av1 = avma; /* main loop is almost identical to that of invmod() */ while (lgefint(d) > 3 && signe(d1)) { lhmres = lgcdii((ulong *)d, (ulong *)d1, &xu, &xu1, &xv, &xv1, ULONG_MAX); if (lhmres != 0) /* check progress */ { /* apply matrix */ if ((lhmres == 1) || (lhmres == -1)) { if (xv1 == 1) { r = subii(d,d1); d=d1; d1=r; a = subii(u,u1); u=u1; u1=a; a = subii(v,v1); v=v1; v1=a; } else { r = subii(d, mului(xv1,d1)); d=d1; d1=r; a = subii(u, mului(xv1,u1)); u=u1; u1=a; a = subii(v, mului(xv1,v1)); v=v1; v1=a; } } else { r = subii(muliu(d,xu), muliu(d1,xv)); d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r; a = subii(muliu(u,xu), muliu(u1,xv)); u1 = subii(muliu(u,xu1), muliu(u1,xv1)); u = a; a = subii(muliu(v,xu), muliu(v1,xv)); v1 = subii(muliu(v,xu1), muliu(v1,xv1)); v = a; if (lhmres&1) { togglesign(d); togglesign(u); togglesign(v); } else { togglesign(d1); togglesign(u1); togglesign(v1); } } } if (lhmres <= 0 && signe(d1)) { q = dvmdii(d,d1,&r); a = subii(u,mulii(q,u1)); u=u1; u1=a; a = subii(v,mulii(q,v1)); v=v1; v1=a; d=d1; d1=r; } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"bezout"); gerepileall(av1,6, &d,&d1,&u,&u1,&v,&v1); } } /* end while */ /* Postprocessing - final sprint */ if (signe(d1)) { /* Assertions: lgefint(d)==lgefint(d1)==3, and * gcd(d,d1) is nonzero and fits into one word */ g = xxgcduu(uel(d,2), uel(d1,2), 0, &xu, &xu1, &xv, &xv1, &s); u = subii(muliu(u,xu), muliu(u1, xv)); v = subii(muliu(v,xu), muliu(v1, xv)); if (s < 0) { sa = -sa; sb = -sb; } avma = av; if (pu) *pu = sa < 0 ? negi(u) : icopy(u); if (pv) *pv = sb < 0 ? negi(v) : icopy(v); if (g == 1) return gen_1; else if (g == 2) return gen_2; else return utoipos(g); } /* get here when the final sprint was skipped (d1 was zero already). * Now the matrix is final, and d contains the gcd. */ avma = av; if (pu) *pu = sa < 0 ? negi(u) : icopy(u); if (pv) *pv = sb < 0 ? negi(v) : icopy(v); return icopy(d); } pari-2.11.2/src/kernel/none/mulll.h0000644000175000017500000000773013036414402015466 0ustar billbill#line 2 "../src/kernel/none/mulll.h" /* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #undef LOCAL_HIREMAINDER #define LOCAL_HIREMAINDER extern ulong hiremainder; /* Version Peter Montgomery */ /* * Assume (for presentation) that BITS_IN_LONG = 32. * Then 0 <= xhi, xlo, yhi, ylo <= 2^16 - 1. Hence * * -2^31 + 2^16 <= (xhi-2^15)*(ylo-2^15) + (xlo-2^15)*(yhi-2^15) <= 2^31. * * If xhi*ylo + xlo*yhi = 2^32*overflow + xymid, then * * -2^32 + 2^16 <= 2^32*overflow + xymid - 2^15*(xhi + ylo + xlo + yhi) <= 0. * * 2^16*overflow <= (xhi+xlo+yhi+ylo)/2 - xymid/2^16 <= 2^16*overflow + 2^16-1 * * This inequality was derived using exact (rational) arithmetic; * it remains valid when we truncate the two middle terms. */ #if !defined(INLINE) extern long mulll(ulong x, ulong y); extern long addmul(ulong x, ulong y); #else #if defined(__GNUC__) && !defined(DISABLE_INLINE) #undef LOCAL_HIREMAINDER #define LOCAL_HIREMAINDER register ulong hiremainder #define mulll(x, y) \ __extension__ ({ \ const ulong __x = (x), __y = (y);\ const ulong __xlo = LOWWORD(__x), __xhi = HIGHWORD(__x); \ const ulong __ylo = LOWWORD(__y), __yhi = HIGHWORD(__y); \ ulong __xylo,__xymid,__xyhi,__xymidhi,__xymidlo; \ ulong __xhl,__yhl; \ \ __xylo = __xlo*__ylo; __xyhi = __xhi*__yhi; \ __xhl = __xhi+__xlo; __yhl = __yhi+__ylo; \ __xymid = __xhl*__yhl - (__xyhi+__xylo); \ \ __xymidhi = HIGHWORD(__xymid); \ __xymidlo = __xymid << BITS_IN_HALFULONG; \ \ __xylo += __xymidlo; \ hiremainder = __xyhi + __xymidhi + (__xylo < __xymidlo) \ + ((((__xhl + __yhl) >> 1) - __xymidhi) & HIGHMASK); \ \ __xylo; \ }) #define addmul(x, y) \ __extension__ ({ \ const ulong __x = (x), __y = (y);\ const ulong __xlo = LOWWORD(__x), __xhi = HIGHWORD(__x); \ const ulong __ylo = LOWWORD(__y), __yhi = HIGHWORD(__y); \ ulong __xylo,__xymid,__xyhi,__xymidhi,__xymidlo; \ ulong __xhl,__yhl; \ \ __xylo = __xlo*__ylo; __xyhi = __xhi*__yhi; \ __xhl = __xhi+__xlo; __yhl = __yhi+__ylo; \ __xymid = __xhl*__yhl - (__xyhi+__xylo); \ \ __xylo += hiremainder; __xyhi += (__xylo < hiremainder); \ \ __xymidhi = HIGHWORD(__xymid); \ __xymidlo = __xymid << BITS_IN_HALFULONG; \ \ __xylo += __xymidlo; \ hiremainder = __xyhi + __xymidhi + (__xylo < __xymidlo) \ + ((((__xhl + __yhl) >> 1) - __xymidhi) & HIGHMASK); \ \ __xylo; \ }) #else INLINE long mulll(ulong x, ulong y) { const ulong xlo = LOWWORD(x), xhi = HIGHWORD(x); const ulong ylo = LOWWORD(y), yhi = HIGHWORD(y); ulong xylo,xymid,xyhi,xymidhi,xymidlo; ulong xhl,yhl; xylo = xlo*ylo; xyhi = xhi*yhi; xhl = xhi+xlo; yhl = yhi+ylo; xymid = xhl*yhl - (xyhi+xylo); xymidhi = HIGHWORD(xymid); xymidlo = xymid << BITS_IN_HALFULONG; xylo += xymidlo; hiremainder = xyhi + xymidhi + (xylo < xymidlo) + ((((xhl + yhl) >> 1) - xymidhi) & HIGHMASK); return xylo; } INLINE long addmul(ulong x, ulong y) { const ulong xlo = LOWWORD(x), xhi = HIGHWORD(x); const ulong ylo = LOWWORD(y), yhi = HIGHWORD(y); ulong xylo,xymid,xyhi,xymidhi,xymidlo; ulong xhl,yhl; xylo = xlo*ylo; xyhi = xhi*yhi; xhl = xhi+xlo; yhl = yhi+ylo; xymid = xhl*yhl - (xyhi+xylo); xylo += hiremainder; xyhi += (xylo < hiremainder); xymidhi = HIGHWORD(xymid); xymidlo = xymid << BITS_IN_HALFULONG; xylo += xymidlo; hiremainder = xyhi + xymidhi + (xylo < xymidlo) + ((((xhl + yhl) >> 1) - xymidhi) & HIGHMASK); return xylo; } #endif #endif pari-2.11.2/src/kernel/none/mpinl.c0000644000175000017500000000131313036414402015442 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define PARI_NO_PARIINL_H #define INLINE #ifndef DISABLE_INLINE # define DISABLE_INLINE #endif #include "pari.h" ulong hiremainder, overflow; pari-2.11.2/src/kernel/none/divll_pre.h0000644000175000017500000000754313201017466016326 0ustar billbill#line 2 "../src/kernel/none/divll_pre.h" /* Copyright (C) 2014 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #undef LOCAL_HIREMAINDER extern ulong hiremainder; #if defined(INLINE) && defined(__GNUC__) && !defined(DISABLE_INLINE) #define LOCAL_HIREMAINDER register ulong hiremainder #else #define LOCAL_HIREMAINDER #endif #if defined(INLINE) && defined(__GNUC__) && !defined(DISABLE_INLINE) INLINE ulong /* precompute inverse of n */ get_Fl_red(ulong n) { LOCAL_HIREMAINDER; n <<= bfffo(n); hiremainder = ~n; return divll(~0UL, n); } #else INLINE ulong /* precompute inverse of n */ get_Fl_red(ulong n) { ulong q, oldhi = hiremainder; n <<= bfffo(n); hiremainder = ~n; q = divll(~0UL, n); hiremainder = oldhi; return q; } #endif INLINE ulong /* requires u1 <= n, n normalised */ divll_pre_normalized(ulong u1, ulong u0, ulong n, ulong ninv, ulong *pt_r) { ulong q0, q1, r; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; q0 = mulll(ninv, u1); q1 = hiremainder; q0 = addll(q0, u0); q1 = addllx(q1+1, u1); r = u0 - q1 * n; if (r > q0) { r += n; q1--; } if (r >= n) { r -= n; q1++; } *pt_r = r; return q1; } INLINE ulong /* requires u1 <= n, n normalised */ remll_pre_normalized(ulong u1, ulong u0, ulong n, ulong ninv) { ulong q0, q1, r; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; q0 = mulll(ninv, u1); q1 = hiremainder; q0 = addll(q0, u0); q1 = addllx(q1, u1); r = u0 - (q1 + 1) * n; if (r >= q0) r += n; return r < n ? r : r - n; } INLINE ulong /* reduce mod n */ remll_pre(ulong a_hi, ulong a_lo, ulong n, ulong ninv) { int norm = bfffo(n); int bits = BITS_IN_LONG - norm; ulong sn = n << norm; if (a_hi >= n) /* reduce a_hi first */ { const ulong u1 = norm ? a_hi >> bits : 0; const ulong u0 = a_hi << norm; a_hi = remll_pre_normalized(u1, u0, sn, ninv) >> norm; } /* now reduce */ { const ulong u1 = ((a_hi << norm) | (norm ? a_lo >> bits: 0)); const ulong u0 = a_lo << norm; return remll_pre_normalized(u1, u0, sn, ninv) >> norm; } } #if !defined(INLINE) extern ulong divll_pre(ulong a_lo, ulong n, ulong ninv); #else #if defined(__GNUC__) && !defined(DISABLE_INLINE) #define divll_pre(a, n, ninv) \ __extension__ ({ \ ulong __a = (a); \ ulong __n = (n); \ int norm = bfffo(__n); \ int bits = BITS_IN_LONG - norm; \ ulong r, sn = __n << norm; \ const ulong u1 = ((hiremainder << norm) | (norm ? __a >> bits: 0)); \ const ulong u0 = __a << norm; \ const ulong q = divll_pre_normalized(u1, u0, sn, ninv, &r); \ hiremainder = r>>norm; q; \ }) #else /* __GNUC__ */ INLINE ulong divll_pre(ulong a_lo, ulong n, ulong ninv) { int norm = bfffo(n); int bits = BITS_IN_LONG - norm; ulong r, sn = n << norm; const ulong u1 = ((hiremainder << norm) | (norm ? a_lo >> bits: 0)); const ulong u0 = a_lo << norm; const ulong q = divll_pre_normalized(u1, u0, sn, ninv, &r); hiremainder = r>>norm; return q; } #endif /* __GNUC__ */ #endif pari-2.11.2/src/kernel/none/level1.h0000644000175000017500000011227513326135265015543 0ustar billbill#line 2 "../src/kernel/none/level1.h" /* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file defines "level 1" kernel functions. * These functions can be inline; they are also defined externally in * mpinl.c, which includes this file and never needs to be changed */ INLINE long evallg(long x) { if (x & ~LGBITS) pari_err_OVERFLOW("lg()"); return _evallg(x); } INLINE long evalvalp(long x) { long v = _evalvalp(x); if (v & ~VALPBITS) pari_err_OVERFLOW("valp()"); return v; } INLINE long evalexpo(long x) { long v = _evalexpo(x); if (v & ~EXPOBITS) pari_err_OVERFLOW("expo()"); return v; } INLINE long evalprecp(long x) { long v = _evalprecp(x); if (x & ~((1UL<<(BITS_IN_LONG-VALPnumBITS))-1)) pari_err_OVERFLOW("precp()"); return v; } INLINE int varncmp(long x, long y) { if (varpriority[x] < varpriority[y]) return 1; if (varpriority[x] > varpriority[y]) return -1; return 0; } INLINE long varnmin(long x, long y) { return (varpriority[x] <= varpriority[y])? x: y; } INLINE long varnmax(long x, long y) { return (varpriority[x] >= varpriority[y])? x: y; } /* Inhibit some area gerepile-wise: declare it to be a non recursive * type, of length l. Thus gerepile won't inspect the zone, just copy it. * For the following situation: * z = cgetg(t,a); av = avma; garbage(); ltop = avma; * for (i=1; i 0) { GEN z = (GEN)ltop; z[0] = evaltyp(t_VECSMALL) | evallg(l); #ifdef DEBUG { long i; for (i = 1; i < l; i++) z[i] = 0; } #endif } } INLINE void fixlg(GEN x, long ly) { long lx = lg(x), l = lx - ly; if (l > 0) { /* stackdummy(x+lx, x+ly) */ GEN z = x + ly; z[0] = evaltyp(t_VECSMALL) | evallg(l); setlg(x, ly); #ifdef DEBUG { long i; for (i = 1; i < l; i++) z[i] = 0; } #endif } } /* update lg(z) before affrr(y, z) [ to cater for precision loss ]*/ INLINE void affrr_fixlg(GEN y, GEN z) { fixlg(z, lg(y)); affrr(y, z); } /*******************************************************************/ /* */ /* ALLOCATE ON STACK */ /* */ /*******************************************************************/ INLINE GEN new_chunk(size_t x) /* x is a number of longs */ { GEN z = ((GEN) avma) - x; CHECK_CTRLC if (x > (avma-pari_mainstack->bot) / sizeof(long)) new_chunk_resize(x); avma = (pari_sp)z; #ifdef MEMSTEP if (DEBUGMEM>1 && pari_mainstack->memused != DISABLE_MEMUSED) { long d = (long)pari_mainstack->memused - (long)z; if (labs(d) > 4*MEMSTEP) { pari_mainstack->memused = (pari_sp)z; err_printf("...%4.0lf Mbytes used\n", (pari_mainstack->top-pari_mainstack->memused)/1048576.); } } #endif return z; } INLINE char * stack_malloc(size_t N) { long n = nchar2nlong(N); return (char*)new_chunk(n); } INLINE char * stack_malloc_align(size_t N, long k) { ulong d = ((ulong)avma) % k; if (d) (void)new_chunk(d/sizeof(long)); return (char*) new_chunk(nchar2nlong(N)); } INLINE char * stack_calloc(size_t N) { char *p = stack_malloc(N); memset(p, 0, N); return p; } /* cgetg(lg(x), typ(x)), set *lx. Implicit unsetisclone() */ INLINE GEN cgetg_copy(GEN x, long *plx) { GEN y; *plx = lg(x); y = new_chunk((size_t)*plx); y[0] = x[0] & (TYPBITS|LGBITS); return y; } INLINE GEN cgetg_block(long x, long y) { GEN z = newblock((size_t)x); z[0] = CLONEBIT | evaltyp(y) | evallg(x); return z; } INLINE GEN cgetg(long x, long y) { GEN z = new_chunk((size_t)x); z[0] = evaltyp(y) | evallg(x); return z; } INLINE GEN cgeti(long x) { GEN z = new_chunk((size_t)x); z[0] = evaltyp(t_INT) | evallg(x); return z; } INLINE GEN cgetipos(long x) { GEN z = cgeti(x); z[1] = evalsigne(1) | evallgefint(x); return z; } INLINE GEN cgetineg(long x) { GEN z = cgeti(x); z[1] = evalsigne(-1) | evallgefint(x); return z; } INLINE GEN cgetr_block(long x) { GEN z = newblock((size_t)x); z[0] = CLONEBIT | evaltyp(t_REAL) | evallg(x); return z; } INLINE GEN cgetr(long x) { GEN z = new_chunk((size_t)x); z[0] = evaltyp(t_REAL) | evallg(x); return z; } /*******************************************************************/ /* */ /* COPY, NEGATION, ABSOLUTE VALUE */ /* */ /*******************************************************************/ /* cannot do memcpy because sometimes x and y overlap */ INLINE GEN leafcopy(GEN x) { register long lx = lg(x); GEN y = new_chunk(lx); /* can't use cgetg_copy, in case x,y overlap */ while (--lx > 0) y[lx] = x[lx]; y[0] = x[0] & (TYPBITS|LGBITS); return y; } INLINE GEN icopy(GEN x) { long i = lgefint(x), lx = i; GEN y = new_chunk(lx); /* can't use cgeti, in case x,y overlap */ while (--i > 0) y[i] = x[i]; y[0] = evaltyp(t_INT) | evallg(lx); return y; } INLINE GEN icopyspec(GEN x, long nx) { long i = nx+2, lx = i; GEN y = new_chunk(lx); /* can't use cgeti, in case x,y overlap */ x -= 2; while (--i >= 2) y[i] = x[i]; y[1] = evalsigne(1) | evallgefint(lx); y[0] = evaltyp(t_INT) | evallg(lx); return y; } INLINE GEN rcopy(GEN x) { return leafcopy(x); } INLINE GEN mpcopy(GEN x) { return leafcopy(x); } INLINE GEN mpabs(GEN x) { GEN y = leafcopy(x); setabssign(y); return y; } INLINE GEN mpabs_shallow(GEN x) { return signe(x) < 0? mpabs(x): x; } INLINE GEN absi(GEN x) { return mpabs(x); } INLINE GEN absi_shallow(GEN x) { return signe(x) < 0? negi(x): x; } INLINE GEN absr(GEN x) { return mpabs(x); } INLINE GEN mpneg(GEN x) { GEN y = leafcopy(x); togglesign(y); return y; } INLINE GEN negi(GEN x) { return mpneg(x); } INLINE GEN negr(GEN x) { return mpneg(x); } INLINE GEN gmax_shallow(GEN x, GEN y) { return gcmp(x,y)<0? y: x; } INLINE GEN gmin_shallow(GEN x, GEN y) { return gcmp(x,y)<0? x: y; } /* negate in place */ INLINE void togglesign(GEN x) { if (x[1] & SIGNBITS) { x[1] ^= HIGHBIT; } } INLINE void setabssign(GEN x) { x[1] &= ~HIGHBIT; } /* negate in place, except universal constants */ INLINE void togglesign_safe(GEN *px) { switch(*px - gen_1) /* gen_1, gen_2, gen_m1, gen_m2 */ { case 0: *px = gen_m1; break; case 3: *px = gen_m2; break; case 6: *px = gen_1; break; case 9: *px = gen_2; break; default: togglesign(*px); } } /* setsigne(y, signe(x)) */ INLINE void affectsign(GEN x, GEN y) { y[1] = (x[1] & SIGNBITS) | (y[1] & ~SIGNBITS); } /* copies sign in place, except for universal constants */ INLINE void affectsign_safe(GEN x, GEN *py) { if (((*py)[1] ^ x[1]) & HIGHBIT) togglesign_safe(py); } /*******************************************************************/ /* */ /* GEN -> LONG, LONG -> GEN */ /* */ /*******************************************************************/ /* assume x != 0, return -x as a t_INT */ INLINE GEN utoineg(ulong x) { GEN y = cgetineg(3); y[2] = x; return y; } /* assume x != 0, return utoi(x) */ INLINE GEN utoipos(ulong x) { GEN y = cgetipos(3); y[2] = x; return y; } INLINE GEN utoi(ulong x) { return x? utoipos(x): gen_0; } INLINE GEN stoi(long x) { if (!x) return gen_0; return x > 0? utoipos((ulong)x): utoineg((ulong)-x); } /* x 2^BIL + y */ INLINE GEN uutoi(ulong x, ulong y) { GEN z; if (!x) return utoi(y); z = cgetipos(4); *int_W_lg(z, 1, 4) = x; *int_W_lg(z, 0, 4) = y; return z; } /* - (x 2^BIL + y) */ INLINE GEN uutoineg(ulong x, ulong y) { GEN z; if (!x) return y? utoineg(y): gen_0; z = cgetineg(4); *int_W_lg(z, 1, 4) = x; *int_W_lg(z, 0, 4) = y; return z; } INLINE long itos(GEN x) { long s = signe(x); long u; if (!s) return 0; u = x[2]; if (lgefint(x) > 3 || u < 0) pari_err_OVERFLOW("t_INT-->long assignment"); return (s>0) ? u : -u; } /* as itos, but return 0 if too large. Cf is_bigint */ INLINE long itos_or_0(GEN x) { long n; if (lgefint(x) != 3 || (n = x[2]) & HIGHBIT) return 0; return signe(x) > 0? n: -n; } INLINE ulong itou(GEN x) { switch(lgefint(x)) { case 2: return 0; case 3: return x[2]; default: pari_err_OVERFLOW("t_INT-->ulong assignment"); return 0; /* LCOV_EXCL_LINE */ } } /* as itou, but return 0 if too large. Cf is_bigint */ INLINE ulong itou_or_0(GEN x) { if (lgefint(x) != 3) return 0; return (ulong)x[2]; } INLINE ulong umuluu_or_0(ulong x, ulong y) { ulong z; LOCAL_HIREMAINDER; z = mulll(x, y); return hiremainder? 0: z; } /* return x*y if <= n, else 0. Beware overflow */ INLINE ulong umuluu_le(ulong x, ulong y, ulong n) { ulong z; LOCAL_HIREMAINDER; z = mulll(x, y); return (hiremainder || z > n)? 0: z; } INLINE GEN real_0_bit(long bitprec) { GEN x=cgetr(2); x[1]=evalexpo(bitprec); return x; } INLINE GEN real_0(long prec) { return real_0_bit(-prec2nbits(prec)); } INLINE GEN real_1_bit(long bit) { return real_1(nbits2prec(bit)); } INLINE GEN real_1(long prec) { GEN x = cgetr(prec); long i; x[1] = evalsigne(1) | _evalexpo(0); x[2] = (long)HIGHBIT; for (i=3; i> r) & 1UL:0; } /*******************************************************************/ /* */ /* COMPARISON */ /* */ /*******************************************************************/ INLINE int cmpir(GEN x, GEN y) { pari_sp av; GEN z; if (!signe(x)) return -signe(y); if (!signe(y)) { if (expo(y) >= expi(x)) return 0; return signe(x); } av=avma; z = itor(x, realprec(y)); avma=av; return cmprr(z,y); /* cmprr does no memory adjustment */ } INLINE int cmpri(GEN x, GEN y) { return -cmpir(y,x); } INLINE int cmpsr(long x, GEN y) { pari_sp av; GEN z; if (!x) return -signe(y); av=avma; z = stor(x, LOWDEFAULTPREC); avma=av; return cmprr(z,y); } INLINE int cmprs(GEN x, long y) { return -cmpsr(y,x); } /* compare x and y */ INLINE int cmpui(ulong x, GEN y) { ulong p; if (!x) return -signe(y); if (signe(y) <= 0) return 1; if (lgefint(y) > 3) return -1; p = y[2]; if (p == x) return 0; return p < x ? 1 : -1; } INLINE int cmpiu(GEN x, ulong y) { return -cmpui(y,x); } /* compare x and |y| */ INLINE int abscmpui(ulong x, GEN y) { long l = lgefint(y); ulong p; if (!x) return (l > 2)? -1: 0; if (l == 2) return 1; if (l > 3) return -1; p = y[2]; if (p == x) return 0; return p < x ? 1 : -1; } INLINE int abscmpiu(GEN x, ulong y) { return -abscmpui(y,x); } INLINE int cmpsi(long x, GEN y) { ulong p; if (!x) return -signe(y); if (x > 0) { if (signe(y)<=0) return 1; if (lgefint(y)>3) return -1; p = y[2]; if (p == (ulong)x) return 0; return p < (ulong)x ? 1 : -1; } if (signe(y)>=0) return -1; if (lgefint(y)>3) return 1; p = y[2]; if (p == (ulong)-x) return 0; return p < (ulong)(-x) ? -1 : 1; } INLINE int cmpis(GEN x, long y) { return -cmpsi(y,x); } INLINE int mpcmp(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? cmpii(x,y) : cmpir(x,y); return (typ(y)==t_INT) ? -cmpir(y,x) : cmprr(x,y); } /* x == y ? */ INLINE int equalui(ulong x, GEN y) { if (!x) return !signe(y); if (signe(y) <= 0 || lgefint(y) != 3) return 0; return ((ulong)y[2] == (ulong)x); } /* x == y ? */ INLINE int equalsi(long x, GEN y) { if (!x) return !signe(y); if (x > 0) { if (signe(y) <= 0 || lgefint(y) != 3) return 0; return ((ulong)y[2] == (ulong)x); } if (signe(y) >= 0 || lgefint(y) != 3) return 0; return ((ulong)y[2] == (ulong)-x); } /* x == |y| ? */ INLINE int absequalui(ulong x, GEN y) { if (!x) return !signe(y); return (lgefint(y) == 3 && (ulong)y[2] == x); } INLINE int absequaliu(GEN x, ulong y) { return absequalui(y,x); } INLINE int equalis(GEN x, long y) { return equalsi(y,x); } INLINE int equaliu(GEN x, ulong y) { return equalui(y,x); } /* assume x != 0, is |x| == 2^n ? */ INLINE int absrnz_equal2n(GEN x) { if ((ulong)x[2]==HIGHBIT) { long i, lx = lg(x); for (i = 3; i < lx; i++) if (x[i]) return 0; return 1; } return 0; } /* assume x != 0, is |x| == 1 ? */ INLINE int absrnz_equal1(GEN x) { return !expo(x) && absrnz_equal2n(x); } INLINE long maxss(long x, long y) { return x>y?x:y; } INLINE long minss(long x, long y) { return xy?x:y; } INLINE double maxdd(double x, double y) { return x>y?x:y; } INLINE double mindd(double x, double y) { return x 0) return y > 0? adduu(x,y): subuu(x, -y); if (y > 0) return subuu(y, -x); else { /* - adduu(-x, -y) */ ulong t = (-x)+(-y); return uutoineg((t < (ulong)(-x)), t); } } INLINE GEN subss(long x, long y) { return addss(-y,x); } INLINE GEN subii(GEN x, GEN y) { if (x==y) return gen_0; /* frequent with x = y = gen_0 */ return addii_sign(x, signe(x), y, -signe(y)); } INLINE GEN addii(GEN x, GEN y) { return addii_sign(x, signe(x), y, signe(y)); } INLINE GEN addrr(GEN x, GEN y) { return addrr_sign(x, signe(x), y, signe(y)); } INLINE GEN subrr(GEN x, GEN y) { return addrr_sign(x, signe(x), y, -signe(y)); } INLINE GEN addir(GEN x, GEN y) { return addir_sign(x, signe(x), y, signe(y)); } INLINE GEN subir(GEN x, GEN y) { return addir_sign(x, signe(x), y, -signe(y)); } INLINE GEN subri(GEN x, GEN y) { return addir_sign(y, -signe(y), x, signe(x)); } INLINE GEN addsi(long x, GEN y) { return addsi_sign(x, y, signe(y)); } INLINE GEN addui(ulong x, GEN y) { return addui_sign(x, y, signe(y)); } INLINE GEN subsi(long x, GEN y) { return addsi_sign(x, y, -signe(y)); } INLINE GEN subui(ulong x, GEN y) { return addui_sign(x, y, -signe(y)); } /*******************************************************************/ /* */ /* MOD, REM, DIV */ /* */ /*******************************************************************/ INLINE ulong mod2BIL(GEN x) { return *int_LSW(x); } INLINE long mod64(GEN x) { return mod2BIL(x) & 63; } INLINE long mod32(GEN x) { return mod2BIL(x) & 31; } INLINE long mod16(GEN x) { return mod2BIL(x) & 15; } INLINE long mod8(GEN x) { return mod2BIL(x) & 7; } INLINE long mod4(GEN x) { return mod2BIL(x) & 3; } INLINE long mod2(GEN x) { return mod2BIL(x) & 1; } INLINE int mpodd(GEN x) { return signe(x) && mod2(x); } /* x mod 2^n, n < BITS_IN_LONG */ INLINE ulong umodi2n(GEN x, long n) { long s = signe(x); const ulong _2n = 1UL << n; ulong m; if (!s) return 0; m = *int_LSW(x) & (_2n - 1); if (s < 0 && m) m = _2n - m; return m; } INLINE ulong Mod64(GEN x){ return umodi2n(x,6); } INLINE ulong Mod32(GEN x){ return umodi2n(x,5); } INLINE ulong Mod16(GEN x){ return umodi2n(x,4); } INLINE ulong Mod8(GEN x) { return umodi2n(x,3); } INLINE ulong Mod4(GEN x) { return umodi2n(x,2); } INLINE ulong Mod2(GEN x) { return umodi2n(x,1); } INLINE GEN truedivii(GEN a,GEN b) { return truedvmdii(a,b,NULL); } INLINE GEN truedivis(GEN a, long b) { return truedvmdis(a,b,NULL); } INLINE GEN truedivsi(long a, GEN b) { return truedvmdsi(a,b,NULL); } INLINE GEN divii(GEN a, GEN b) { return dvmdii(a,b,NULL); } INLINE GEN remii(GEN a, GEN b) { return dvmdii(a,b,ONLY_REM); } INLINE GEN divss(long x, long y) { return stoi(x / y); } INLINE GEN modss(long x, long y) { return stoi(smodss(x, y)); } INLINE GEN remss(long x, long y) { return stoi(x % y); } INLINE long smodss(long x, long y) { long r = x%y; return (r >= 0)? r: labs(y) + r; } INLINE ulong umodsu(long x, ulong y) { return x>=0 ? x%y: Fl_neg((-x)%y, y); } INLINE long sdivss_rem(long x, long y, long *r) { long q; LOCAL_HIREMAINDER; if (!y) pari_err_INV("sdivss_rem",gen_0); hiremainder = 0; q = divll((ulong)labs(x),(ulong)labs(y)); if (x < 0) { hiremainder = -((long)hiremainder); q = -q; } if (y < 0) q = -q; *r = hiremainder; return q; } INLINE GEN divss_rem(long x, long y, long *r) { return stoi(sdivss_rem(x,y,r)); } INLINE ulong udivuu_rem(ulong x, ulong y, ulong *r) { if (!y) pari_err_INV("udivuu_rem",gen_0); *r = x % y; return x / y; } INLINE ulong ceildivuu(ulong a, ulong b) { ulong c = a/b; return (a%b)? c+1: c; } INLINE ulong uabsdivui_rem(ulong x, GEN y, ulong *r) { long q, s = signe(y); LOCAL_HIREMAINDER; if (!s) pari_err_INV("uabsdivui_rem",gen_0); if (!x || lgefint(y)>3) { *r = x; return 0; } hiremainder=0; q = (long)divll(x, (ulong)y[2]); if (s < 0) q = -q; *r = hiremainder; return q; } /* assume d != 0 and |n| / d can be represented as an ulong. * Return |n|/d, set *r = |n| % d */ INLINE ulong uabsdiviu_rem(GEN n, ulong d, ulong *r) { switch(lgefint(n)) { case 2: *r = 0; return 0; case 3: { ulong nn = n[2]; *r = nn % d; return nn / d; } default: /* 4 */ { ulong n1, n0, q; LOCAL_HIREMAINDER; n0 = *int_W(n,0); n1 = *int_W(n,1); hiremainder = n1; q = divll(n0, d); *r = hiremainder; return q; } } } INLINE long sdivsi_rem(long x, GEN y, long *r) { long q, s = signe(y); LOCAL_HIREMAINDER; if (!s) pari_err_INV("sdivsi_rem",gen_0); if (!x || lgefint(y)>3 || ((long)y[2]) < 0) { *r = x; return 0; } hiremainder=0; q = (long)divll(labs(x), (ulong)y[2]); if (x < 0) { hiremainder = -((long)hiremainder); q = -q; } if (s < 0) q = -q; *r = hiremainder; return q; } INLINE GEN divsi_rem(long s, GEN y, long *r) { return stoi(sdivsi_rem(s,y,r)); } INLINE long sdivsi(long x, GEN y) { long q, s = signe(y); if (!s) pari_err_INV("sdivsi",gen_0); if (!x || lgefint(y)>3 || ((long)y[2]) < 0) return 0; q = labs(x) / y[2]; if (x < 0) q = -q; if (s < 0) q = -q; return q; } INLINE GEN dvmdss(long x, long y, GEN *z) { long r; GEN q = divss_rem(x,y, &r); *z = stoi(r); return q; } INLINE long dvmdsBIL(long n, long *r) { *r = remsBIL(n); return divsBIL(n); } INLINE ulong dvmduBIL(ulong n, ulong *r) { *r = remsBIL(n); return divsBIL(n); } INLINE GEN dvmdsi(long x, GEN y, GEN *z) { long r; GEN q = divsi_rem(x,y, &r); *z = stoi(r); return q; } INLINE GEN dvmdis(GEN x, long y, GEN *z) { long r; GEN q = divis_rem(x,y, &r); *z = stoi(r); return q; } INLINE long smodis(GEN x, long y) { pari_sp av = avma; long r; (void)divis_rem(x,y, &r); avma = av; return (r >= 0) ? r: labs(y) + r; } INLINE GEN modis(GEN x, long y) { return stoi(smodis(x,y)); } INLINE GEN modsi(long x, GEN y) { long r; (void)sdivsi_rem(x, y, &r); return (r >= 0)? stoi(r): addsi_sign(r, y, 1); } INLINE ulong umodui(ulong x, GEN y) { if (!signe(y)) pari_err_INV("umodui",gen_0); if (!x || lgefint(y) > 3) return x; return x % (ulong)y[2]; } INLINE ulong ugcdiu(GEN x, ulong y) { return ugcd(umodiu(x,y), y); } INLINE ulong ugcdui(ulong y, GEN x) { return ugcd(umodiu(x,y), y); } INLINE GEN remsi(long x, GEN y) { long r; (void)sdivsi_rem(x,y, &r); return stoi(r); } INLINE GEN remis(GEN x, long y) { pari_sp av = avma; long r; (void)divis_rem(x,y, &r); avma = av; return stoi(r); } INLINE GEN rdivis(GEN x, long y, long prec) { GEN z = cgetr(prec); pari_sp av = avma; affrr(divrs(itor(x,prec), y),z); avma = av; return z; } INLINE GEN rdivsi(long x, GEN y, long prec) { GEN z = cgetr(prec); pari_sp av = avma; affrr(divsr(x, itor(y,prec)), z); avma = av; return z; } INLINE GEN rdivss(long x, long y, long prec) { GEN z = cgetr(prec); pari_sp av = avma; affrr(divrs(stor(x, prec), y), z); avma = av; return z; } INLINE void rdiviiz(GEN x, GEN y, GEN z) { pari_sp av = avma; long prec = realprec(z); affir(x, z); if (!is_bigint(y)) { affrr(divrs(z, y[2]), z); if (signe(y) < 0) togglesign(z); } else affrr(divrr(z, itor(y,prec)), z); avma = av; } INLINE GEN rdivii(GEN x, GEN y, long prec) { GEN z = cgetr(prec); pari_sp av = avma; affir(x, z); if (lg(y) == 3) { affrr(divru(z, y[2]), z); if (signe(y) < 0) togglesign(z); } else affrr(divrr(z, itor(y,prec)), z); avma = av; return z; } INLINE GEN fractor(GEN x, long prec) { return rdivii(gel(x,1), gel(x,2), prec); } INLINE int dvdii(GEN x, GEN y) { pari_sp av=avma; GEN r = remii(x,y); avma = av; return r == gen_0; } INLINE int dvdsi(long x, GEN y) { if (!signe(y)) return x == 0; if (lgefint(y) != 3) return 0; return x % y[2] == 0; } INLINE int dvdui(ulong x, GEN y) { if (!signe(y)) return x == 0; if (lgefint(y) != 3) return 0; return x % y[2] == 0; } INLINE int dvdis(GEN x, long y) { return y? smodis(x, y) == 0: signe(x) == 0; } INLINE int dvdiu(GEN x, ulong y) { return y? umodiu(x, y) == 0: signe(x) == 0; } INLINE int dvdisz(GEN x, long y, GEN z) { const pari_sp av = avma; long r; GEN p1 = divis_rem(x,y, &r); avma = av; if (r) return 0; affii(p1,z); return 1; } INLINE int dvdiuz(GEN x, ulong y, GEN z) { const pari_sp av = avma; ulong r; GEN p1 = absdiviu_rem(x,y, &r); avma = av; if (r) return 0; affii(p1,z); return 1; } INLINE int dvdiiz(GEN x, GEN y, GEN z) { const pari_sp av=avma; GEN p2; const GEN p1=dvmdii(x,y,&p2); if (signe(p2)) { avma=av; return 0; } affii(p1,z); avma=av; return 1; } INLINE ulong remlll_pre(ulong u2, ulong u1, ulong u0, ulong n, ulong ninv) { u1 = remll_pre(u2, u1, n, ninv); return remll_pre(u1, u0, n, ninv); } INLINE ulong Fl_sqr_pre(ulong a, ulong p, ulong pi) { register ulong x; LOCAL_HIREMAINDER; x = mulll(a,a); return remll_pre(hiremainder, x, p, pi); } INLINE ulong Fl_mul_pre(ulong a, ulong b, ulong p, ulong pi) { register ulong x; LOCAL_HIREMAINDER; x = mulll(a,b); return remll_pre(hiremainder, x, p, pi); } INLINE ulong Fl_addmul_pre(ulong y0, ulong x0, ulong x1, ulong p, ulong pi) { ulong l0, h0; LOCAL_HIREMAINDER; hiremainder = y0; l0 = addmul(x0, x1); h0 = hiremainder; return remll_pre(h0, l0, p, pi); } INLINE ulong Fl_addmulmul_pre(ulong x0, ulong y0, ulong x1, ulong y1, ulong p, ulong pi) { ulong l0, l1, h0, h1; LOCAL_OVERFLOW; LOCAL_HIREMAINDER; l0 = mulll(x0, y0); h0 = hiremainder; l1 = mulll(x1, y1); h1 = hiremainder; l0 = addll(l0, l1); h0 = addllx(h0, h1); return overflow ? remlll_pre(1, h0, l0, p, pi): remll_pre(h0, l0, p, pi); } INLINE ulong Fl_ellj_pre(ulong a4, ulong a6, ulong p, ulong pi) { /* a43 = 4 a4^3 */ ulong a43 = Fl_double(Fl_double( Fl_mul_pre(a4, Fl_sqr_pre(a4, p, pi), p, pi), p), p); /* a62 = 27 a6^2 */ ulong a62 = Fl_mul_pre(Fl_sqr_pre(a6, p, pi), 27 % p, p, pi); ulong z1 = Fl_mul_pre(a43, 1728 % p, p, pi); ulong z2 = Fl_add(a43, a62, p); return Fl_div(z1, z2, p); } /*******************************************************************/ /* */ /* MP (INT OR REAL) */ /* */ /*******************************************************************/ INLINE GEN mptrunc(GEN x) { return typ(x)==t_INT? icopy(x): truncr(x); } INLINE GEN mpfloor(GEN x) { return typ(x)==t_INT? icopy(x): floorr(x); } INLINE GEN mpceil(GEN x) { return typ(x)==t_INT? icopy(x): ceilr(x); } INLINE GEN mpround(GEN x) { return typ(x) == t_INT? icopy(x): roundr(x); } INLINE long mpexpo(GEN x) { return typ(x) == t_INT? expi(x): expo(x); } INLINE GEN mpadd(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? addii(x,y) : addir(x,y); return (typ(y)==t_INT) ? addir(y,x) : addrr(x,y); } INLINE GEN mpsub(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? subii(x,y) : subir(x,y); return (typ(y)==t_INT) ? subri(x,y) : subrr(x,y); } INLINE GEN mpmul(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? mulii(x,y) : mulir(x,y); return (typ(y)==t_INT) ? mulir(y,x) : mulrr(x,y); } INLINE GEN mpsqr(GEN x) { return (typ(x)==t_INT) ? sqri(x) : sqrr(x); } INLINE GEN mpdiv(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? divii(x,y) : divir(x,y); return (typ(y)==t_INT) ? divri(x,y) : divrr(x,y); } /*******************************************************************/ /* */ /* Z/nZ, n ULONG */ /* */ /*******************************************************************/ INLINE ulong Fl_double(ulong a, ulong p) { ulong res = a << 1; return (res >= p || res < a) ? res - p : res; } INLINE ulong Fl_triple(ulong a, ulong p) { ulong res = a << 1; if (res >= p || res < a) res -= p; res += a; return (res >= p || res < a)? res - p: res; } INLINE ulong Fl_halve(ulong a, ulong p) { ulong ap, ap2; if ((a&1UL)==0) return a>>1; ap = a + p; ap2 = ap>>1; return ap>=a ? ap2: (ap2|HIGHBIT); } INLINE ulong Fl_add(ulong a, ulong b, ulong p) { ulong res = a + b; return (res >= p || res < a) ? res - p : res; } INLINE ulong Fl_neg(ulong x, ulong p) { return x ? p - x: 0; } INLINE ulong Fl_sub(ulong a, ulong b, ulong p) { ulong res = a - b; return (res > a) ? res + p: res; } /* centerlift(u mod p) */ INLINE long Fl_center(ulong u, ulong p, ulong ps2) { return (long) (u > ps2)? u - p: u; } INLINE ulong Fl_mul(ulong a, ulong b, ulong p) { register ulong x; LOCAL_HIREMAINDER; x = mulll(a,b); if (!hiremainder) return x % p; (void)divll(x,p); return hiremainder; } INLINE ulong Fl_sqr(ulong a, ulong p) { register ulong x; LOCAL_HIREMAINDER; x = mulll(a,a); if (!hiremainder) return x % p; (void)divll(x,p); return hiremainder; } INLINE ulong Fl_div(ulong a, ulong b, ulong p) { return Fl_mul(a, Fl_inv(b, p), p); } /*******************************************************************/ /* */ /* DEFINED FROM EXISTING ONE EXPLOITING COMMUTATIVITY */ /* */ /*******************************************************************/ INLINE GEN addri(GEN x, GEN y) { return addir(y,x); } INLINE GEN addis(GEN x, long s) { return addsi(s,x); } INLINE GEN addiu(GEN x, ulong s) { return addui(s,x); } INLINE GEN addrs(GEN x, long s) { return addsr(s,x); } INLINE GEN subiu(GEN x, long y) { GEN z = subui(y, x); togglesign(z); return z; } INLINE GEN subis(GEN x, long y) { return addsi(-y,x); } INLINE GEN subrs(GEN x, long y) { return addsr(-y,x); } INLINE GEN mulis(GEN x, long s) { return mulsi(s,x); } INLINE GEN muliu(GEN x, ulong s) { return mului(s,x); } INLINE GEN mulru(GEN x, ulong s) { return mulur(s,x); } INLINE GEN mulri(GEN x, GEN s) { return mulir(s,x); } INLINE GEN mulrs(GEN x, long s) { return mulsr(s,x); } /*******************************************************************/ /* */ /* VALUATION, EXPONENT, SHIFTS */ /* */ /*******************************************************************/ INLINE long vali(GEN x) { long i; GEN xp; if (!signe(x)) return -1; xp=int_LSW(x); for (i=0; !*xp; i++) xp=int_nextW(xp); return vals(*xp) + i * BITS_IN_LONG; } /* assume x > 0 */ INLINE long expu(ulong x) { return (BITS_IN_LONG-1) - (long)bfffo(x); } INLINE long expi(GEN x) { const long lx=lgefint(x); return lx==2? -(long)HIGHEXPOBIT: bit_accuracy(lx)-(long)bfffo(*int_MSW(x))-1; } INLINE GEN shiftr(GEN x, long n) { const long e = evalexpo(expo(x)+n); const GEN y = rcopy(x); if (e & ~EXPOBITS) pari_err_OVERFLOW("expo()"); y[1] = (y[1]&~EXPOBITS) | e; return y; } INLINE GEN mpshift(GEN x,long s) { return (typ(x)==t_INT)?shifti(x,s):shiftr(x,s); } /* FIXME: adapt/use mpn_[lr]shift instead */ /* z2[imin..imax] := z1[imin..imax].f shifted left sh bits * (feeding f from the right). Assume sh > 0 */ INLINE void shift_left(GEN z2, GEN z1, long imin, long imax, ulong f, ulong sh) { GEN sb = z1 + imin, se = z1 + imax, te = z2 + imax; ulong l, m = BITS_IN_LONG - sh, k = f >> m; while (se > sb) { l = *se--; *te-- = (l << sh) | k; k = l >> m; } *te = (((ulong)*se) << sh) | k; } /* z2[imin..imax] := f.z1[imin..imax-1] shifted right sh bits * (feeding f from the left). Assume sh > 0 */ INLINE void shift_right(GEN z2, GEN z1, long imin, long imax, ulong f, ulong sh) { GEN sb = z1 + imin, se = z1 + imax, tb = z2 + imin; ulong k, l = *sb++, m = BITS_IN_LONG - sh; *tb++ = (l >> sh) | (f << m); while (sb < se) { k = l << m; l = *sb++; *tb++ = (l >> sh) | k; } } /* Backward compatibility. Inefficient && unused */ extern ulong hiremainder; INLINE ulong shiftl(ulong x, ulong y) { hiremainder = x>>(BITS_IN_LONG-y); return (x<>y); } INLINE void shiftr_inplace(GEN z, long d) { setexpo(z, expo(z)+d); } /*******************************************************************/ /* */ /* ASSIGNMENT */ /* */ /*******************************************************************/ INLINE void affii(GEN x, GEN y) { long lx = lgefint(x); if (lg(y)t_INT assignment"); while (--lx) y[lx] = x[lx]; } INLINE void affsi(long s, GEN x) { if (!s) x[1] = evalsigne(0) | evallgefint(2); else { if (s > 0) { x[1] = evalsigne( 1) | evallgefint(3); x[2] = s; } else { x[1] = evalsigne(-1) | evallgefint(3); x[2] = -s; } } } INLINE void affui(ulong u, GEN x) { if (!u) x[1] = evalsigne(0) | evallgefint(2); else { x[1] = evalsigne(1) | evallgefint(3); x[2] = u; } } INLINE void affsr(long x, GEN y) { long sh, i, ly = lg(y); if (!x) { y[1] = evalexpo(-prec2nbits(ly)); return; } if (x < 0) { x = -x; sh = bfffo(x); y[1] = evalsigne(-1) | _evalexpo((BITS_IN_LONG-1)-sh); } else { sh = bfffo(x); y[1] = evalsigne(1) | _evalexpo((BITS_IN_LONG-1)-sh); } y[2] = ((ulong)x)< 1 */ { if (!x) return y; /* fix up x */ while (!(x&1)) x>>=1; if (x==1) return 1; if (x==y) return y; else if (x>y) goto xislarger;/* will be rare, given how we'll use this */ /* loop invariants: x,y odd and distinct. */ yislarger: if ((x^y)&2) /* ...01, ...11 or vice versa */ y=(x>>2)+(y>>2)+1; /* ==(x+y)>>2 except it can't overflow */ else /* ...01,...01 or ...11,...11 */ y=(y-x)>>2; /* now y!=0 in either case */ while (!(y&1)) y>>=1; /* kill any windfall-gained powers of 2 */ if (y==1) return 1; /* comparand == return value... */ if (x==y) return y; /* this and the next is just one comparison */ else if (x>2)+(y>>2)+1; else x=(x-y)>>2; /* x!=0 */ while (!(x&1)) x>>=1; if (x==1) return 1; if (x==y) return y; else if (x>y) goto xislarger; goto yislarger; } /* Gotos are useful, and Programming is an Art. D.E.Knuth. */ /* PS: Of course written with Dijkstra's lessons firmly in mind... --GN */ /* at least one of a or b is odd, return gcd(a,b) */ INLINE ulong mygcduodd(ulong a, ulong b) { ulong c; if (b&1) { if (a==1 || b==1) c = 1; else c = gcduodd(a, b); } else { if (a==1) c = 1; else c = gcduodd(b, a); } return c; } /* modified right shift binary algorithm with at most one division */ ulong ugcd(ulong a,ulong b) { long v; if (!b) return a; if (!a) return b; if (a>b) { a %= b; if (!a) return b; } else { b %= a; if (!b) return a; } v = vals(a|b); return mygcduodd(a>>v, b>>v) << v; } long cgcd(long a,long b) { return (long)ugcd(labs(a), labs(b)); } /* For gcdii(): assume a>b>0, return gcd(a,b) as a GEN */ static GEN igcduu(ulong a, ulong b) { long v; a %= b; if (!a) return utoipos(b); v = vals(a|b); return utoipos( mygcduodd(a>>v, b>>v) << v ); } /*Warning: overflows silently if lcm does not fit*/ ulong ulcm(ulong a, ulong b) { ulong d = ugcd(a,b); if (!d) return 0; return d == 1? a*b: a*(b/d); } long clcm(long a,long b) { return ulcm(labs(a), labs(b)); } /********************************************************************/ /** **/ /** INTEGER EXTENDED GCD (AND INVMOD) **/ /** **/ /********************************************************************/ /* GN 1998Oct25, originally developed in January 1998 under 2.0.4.alpha, * in the context of trying to improve elliptic curve cryptosystem attacking * algorithms. 2001Jan02 -- added bezout() functionality. * * Two basic ideas - (1) avoid many integer divisions, especially when the * quotient is 1 (which happens more than 40% of the time). (2) Use Lehmer's * trick as modified by Jebelean of extracting a couple of words' worth of * leading bits from both operands, and compute partial quotients from them * as long as we can be sure of their values. The Jebelean modifications * consist in reliable inequalities from which we can decide fast whether * to carry on or to return to the outer loop, and in re-shifting after the * first word's worth of bits has been used up. All of this is described * in R. Lercier's these [pp148-153 & 163f.], except his outer loop isn't * quite right (the catch-up divisions needed when one partial quotient is * larger than a word are missing). * * The API consists of invmod() and bezout() below; the single-word routines * xgcduu and xxgcduu may be called directly if desired; lgcdii() probably * doesn't make much sense out of context. * * The whole lot is a factor 6 .. 8 faster on word-sized operands, and asym- * ptotically about a factor 2.5 .. 3, depending on processor architecture, * than the naive continued-division code. Unfortunately, thanks to the * unrolled loops and all, the code is a bit lengthy. */ /*================================== * xgcduu(d,d1,f,v,v1,s) * xxgcduu(d,d1,f,u,u1,v,v1,s) * rgcduu(d,d1,vmax,u,u1,v,v1,s) *==================================*/ /* * Fast `final' extended gcd algorithm, acting on two ulongs. Ideally this * should be replaced with assembler versions wherever possible. The present * code essentially does `subtract, compare, and possibly divide' at each step, * which is reasonable when hardware division (a) exists, (b) is a bit slowish * and (c) does not depend a lot on the operand values (as on i486). When * wordsize division is in fact an assembler routine based on subtraction, * this strategy may not be the most efficient one. * * xxgcduu() should be called with d > d1 > 0, returns gcd(d,d1), and assigns * the usual signless cont.frac. recurrence matrix to [u, u1; v, v1] (i.e., * the product of all the [0, 1; 1 q_j] where the leftmost factor arises from * the quotient of the first division step), and the information about the * implied signs to s (-1 when an odd number of divisions has been done, * 1 otherwise). xgcduu() is exactly the same except that u,u1 are not com- * puted (and not returned, of course). * * The input flag f should be set to 1 if we know in advance that gcd(d,d1)==1 * (so we can stop the chain division one step early: as soon as the remainder * equals 1). Use this when you intend to use only what would be v, or only * what would be u and v, after that final division step, but not u1 and v1. * With the flag in force and thus without that final step, the interesting * quantity/ies will still sit in [u1 and] v1, of course. * * For computing the inverse of a single-word INTMOD known to exist, pass f=1 * to xgcduu(), and obtain the result from s and v1. (The routine does the * right thing when d1==1 already.) For finishing a multiword modinv known * to exist, pass f=1 to xxgcduu(), and multiply the returned matrix (with * properly adjusted signs) onto the values v' and v1' previously obtained * from the multiword division steps. Actually, just take the scalar product * of [v',v1'] with [u1,-v1], and change the sign if s==-1. (If the final * step had been carried out, it would be [-u,v], and s would also change.) * For reducing a rational number to lowest terms, pass f=0 to xgcduu(). * Finally, f=0 with xxgcduu() is useful for Bezout computations. * [Harrumph. In the above prescription, the sign turns out to be precisely * wrong.] * (It is safe for invmod() to call xgcduu() with f=1, because f&1 doesn't * make a difference when gcd(d,d1)>1. The speedup is negligible.) * * In principle, when gcd(d,d1) is known to be 1, it is straightforward to * recover the final u,u1 given only v,v1 and s. However, it probably isn't * worthwhile, as it trades a few multiplications for a division. * * Note that these routines do not know and do not need to know about the * PARI stack. * * Added 2001Jan15: * rgcduu() is a variant of xxgcduu() which does not have f (the effect is * that of f=0), but instead has a ulong vmax parameter, for use in rational * reconstruction below. It returns when v1 exceeds vmax; v will never * exceed vmax. (vmax=0 is taken as a synonym of ULONG_MAX i.e. unlimited, * in which case rgcduu behaves exactly like xxgcduu with f=0.) The return * value of rgcduu() is typically meaningless; the interesting part is the * matrix. */ ulong xgcduu(ulong d, ulong d1, int f, ulong* v, ulong* v1, long *s) { ulong xv,xv1, xs, q,res; LOCAL_HIREMAINDER; /* The above blurb contained a lie. The main loop always stops when d1 * has become equal to 1. If (d1 == 1 && !(f&1)) after the loop, we do * the final `division' of d by 1 `by hand' as it were. * * The loop has already been unrolled once. Aggressive optimization could * well lead to a totally unrolled assembler version... * * On modern x86 architectures, this loop is a pig anyway. The division * instruction always puts its result into the same pair of registers, and * we always want to use one of them straight away, so pipeline performance * will suck big time. An assembler version should probably do a first loop * computing and storing all the quotients -- their number is bounded in * advance -- and then assembling the matrix in a second pass. On other * architectures where we can cycle through four or so groups of registers * and exploit a fast ALU result-to-operand feedback path, this is much less * of an issue. (Intel sucks. See http://www.x86.org/ ...) */ xs = res = 0; xv = 0UL; xv1 = 1UL; while (d1 > 1UL) { d -= d1; /* no need to use subll */ if (d >= d1) { hiremainder = 0; q = 1 + divll(d,d1); d = hiremainder; xv += q * xv1; } else xv += xv1; /* possible loop exit */ if (d <= 1UL) { xs=1; break; } /* repeat with inverted roles */ d1 -= d; if (d1 >= d) { hiremainder = 0; q = 1 + divll(d1,d); d1 = hiremainder; xv1 += q * xv; } else xv1 += xv; } /* while */ if (!(f&1)) /* division by 1 postprocessing if needed */ { if (xs && d==1) { xv1 += d1 * xv; xs = 0; res = 1UL; } else if (!xs && d1==1) { xv += d * xv1; xs = 1; res = 1UL; } } if (xs) { *s = -1; *v = xv1; *v1 = xv; return (res ? res : (d==1 ? 1UL : d1)); } else { *s = 1; *v = xv; *v1 = xv1; return (res ? res : (d1==1 ? 1UL : d)); } } ulong xxgcduu(ulong d, ulong d1, int f, ulong* u, ulong* u1, ulong* v, ulong* v1, long *s) { ulong xu,xu1, xv,xv1, xs, q,res; LOCAL_HIREMAINDER; xs = res = 0; xu = xv1 = 1UL; xu1 = xv = 0UL; while (d1 > 1UL) { d -= d1; /* no need to use subll */ if (d >= d1) { hiremainder = 0; q = 1 + divll(d,d1); d = hiremainder; xv += q * xv1; xu += q * xu1; } else { xv += xv1; xu += xu1; } /* possible loop exit */ if (d <= 1UL) { xs=1; break; } /* repeat with inverted roles */ d1 -= d; if (d1 >= d) { hiremainder = 0; q = 1 + divll(d1,d); d1 = hiremainder; xv1 += q * xv; xu1 += q * xu; } else { xv1 += xv; xu1 += xu; } } /* while */ if (!(f&1)) /* division by 1 postprocessing if needed */ { if (xs && d==1) { xv1 += d1 * xv; xu1 += d1 * xu; xs = 0; res = 1UL; } else if (!xs && d1==1) { xv += d * xv1; xu += d * xu1; xs = 1; res = 1UL; } } if (xs) { *s = -1; *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return (res ? res : (d==1 ? 1UL : d1)); } else { *s = 1; *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return (res ? res : (d1==1 ? 1UL : d)); } } ulong rgcduu(ulong d, ulong d1, ulong vmax, ulong* u, ulong* u1, ulong* v, ulong* v1, long *s) { ulong xu,xu1, xv,xv1, xs, q, res=0; int f = 0; LOCAL_HIREMAINDER; if (vmax == 0) vmax = ULONG_MAX; xs = res = 0; xu = xv1 = 1UL; xu1 = xv = 0UL; while (d1 > 1UL) { d -= d1; /* no need to use subll */ if (d >= d1) { hiremainder = 0; q = 1 + divll(d,d1); d = hiremainder; xv += q * xv1; xu += q * xu1; } else { xv += xv1; xu += xu1; } /* possible loop exit */ if (xv > vmax) { f=xs=1; break; } if (d <= 1UL) { xs=1; break; } /* repeat with inverted roles */ d1 -= d; if (d1 >= d) { hiremainder = 0; q = 1 + divll(d1,d); d1 = hiremainder; xv1 += q * xv; xu1 += q * xu; } else { xv1 += xv; xu1 += xu; } /* possible loop exit */ if (xv1 > vmax) { f=1; break; } } /* while */ if (!(f&1)) /* division by 1 postprocessing if needed */ { if (xs && d==1) { xv1 += d1 * xv; xu1 += d1 * xu; xs = 0; res = 1UL; } else if (!xs && d1==1) { xv += d * xv1; xu += d * xu1; xs = 1; res = 1UL; } } if (xs) { *s = -1; *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return (res ? res : (d==1 ? 1UL : d1)); } else { *s = 1; *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return (res ? res : (d1==1 ? 1UL : d)); } } /*================================== * cbezout(a,b,uu,vv) *================================== * Same as bezout() but for C longs. * Return g = gcd(a,b) >= 0, and assign longs u,v through pointers uu,vv * such that g = u*a + v*b. * Special cases: * a == b == 0 ==> pick u=1, v=0 (and return 1, surprisingly) * a != 0 == b ==> keep v=0 * a == 0 != b ==> keep u=0 * |a| == |b| != 0 ==> keep u=0, set v=+-1 * Assignments through uu,vv happen unconditionally; non-NULL pointers * _must_ be used. */ long cbezout(long a,long b,long *uu,long *vv) { long s,*t; ulong d = labs(a), d1 = labs(b); ulong r,u,u1,v,v1; if (!b) { *vv=0L; if (!a) { *uu=1L; return 0L; } *uu = a < 0 ? -1L : 1L; return (long)d; } else if (!a || (d == d1)) { *uu = 0L; *vv = b < 0 ? -1L : 1L; return (long)d1; } else if (d == 1) /* frequently used by nfinit */ { *uu = a; *vv = 0L; return 1L; } else if (d < d1) { /* bug in gcc-2.95.3: * s = a; a = b; b = s; produces wrong result a = b. This is OK: */ { long _x = a; a = b; b = _x; } /* in order to keep the right signs */ r = d; d = d1; d1 = r; t = uu; uu = vv; vv = t; } /* d > d1 > 0 */ r = xxgcduu(d, d1, 0, &u, &u1, &v, &v1, &s); if (s < 0) { *uu = a < 0 ? (long)u : -(long)u; *vv = b < 0 ? -(long)v : (long)v; } else { *uu = a < 0 ? -(long)u : (long)u; *vv = b < 0 ? (long)v : -(long)v; } return (long)r; } /*================================== * lgcdii(d,d1,u,u1,v,v1,vmax) *==================================*/ /* Lehmer's partial extended gcd algorithm, acting on two t_INT GENs. * * Tries to determine, using the leading 2*BITS_IN_LONG significant bits of d * and a quantity of bits from d1 obtained by a shift of the same displacement, * as many partial quotients of d/d1 as possible, and assigns to [u,u1;v,v1] * the product of all the [0,1; 1,qj] thus obtained, where the leftmost * factor arises from the quotient of the first division step. * * For use in rational reconstruction, vmax can be given a nonzero value. * In this case, we will return early as soon as v1 > vmax (i.e. v <= vmax) * * MUST be called with d > d1 > 0, and with d occupying more than one * significant word. Returns the number of reduction/swap steps carried out, * possibly zero, or under certain conditions minus that number. When the * return value is nonzero, the caller should use the returned recurrence * matrix to update its own copies of d,d1. When the return value is * non-positive, and the latest remainder after updating turns out to be * nonzero, the caller should at once attempt a full division, rather than * trying lgcdii() again -- this typically happens when we are about to * encounter a quotient larger than half a word. (This is not detected * infallibly -- after a positive return value, it is possible that the next * stage will end up needing a full division. After a negative return value, * however, this is certain, and should be acted upon.) * * (The sign information, for which xgcduu() has its return argument s, is now * implicit in the LSB of our return value, and the caller may take advantage * of the fact that a return value of +-1 implies u==0,u1==v==1 [only v1 pro- * vides interesting information in this case]. One might also use the fact * that if the return value is +-2, then u==1, but this is rather marginal.) * * If it was not possible to determine even the first quotient, either because * we're too close to an integer quotient or because the quotient would be * larger than one word (if the `leading digit' of d1 after shifting is all * zeros), we return 0 and do not assign anything to the last four args. * * The division chain might even run to completion. It is up to the caller to * detect this case. This routine does not change d or d1; this is also up to * the caller */ int lgcdii(ulong* d, ulong* d1, ulong* u, ulong* u1, ulong* v, ulong* v1, ulong vmax) { /* Strategy: (1) Extract/shift most significant bits. We assume that d * has at least two significant words, but we can cope with a one-word d1. * Let dd,dd1 be the most significant dividend word and matching part of the * divisor. * (2) Check for overflow on the first division. For our purposes, this * happens when the upper half of dd1 is zero. (Actually this is detected * during extraction.) * (3) Get a fix on the first quotient. We compute q = floor(dd/dd1), which * is an upper bound for floor(d/d1), and which gives the true value of the * latter if (and-almost-only-if) the remainder dd' = dd-q*dd1 is >= q. * (If it isn't, we give up. This is annoying because the subsequent full * division will repeat some work already done, but it happens infrequently. * Doing the extra-bit-fetch in this case would be awkward.) * (4) Finish initializations. * * The remainder of the action is comparatively boring... The main loop has * been unrolled once (so we don't swap things and we can apply Jebelean's * termination conditions which alternatingly take two different forms during * successive iterations). When we first run out of sufficient bits to form * a quotient, and have an extra word of each operand, we pull out two whole * word's worth of dividend bits, and divisor bits of matching significance; * to these we apply our partial matrix (disregarding overflow because the * result mod 2^(2*BITS_IN_LONG) will in fact give the correct values), and * re-extract one word's worth of the current dividend and a matching amount * of divisor bits. The affair will normally terminate with matrix entries * just short of a whole word. (We terminate the inner loop before these can * possibly overflow.) */ ulong dd,dd1,ddlo,dd1lo, sh,shc; /* `digits', shift count */ ulong xu,xu1, xv,xv1, q,res; /* recurrences, partial quotient, count */ ulong tmp0,tmp1,tmp2,tmpd,tmpu,tmpv; /* temps */ ulong dm1, d1m1; long ld, ld1, lz; int skip = 0; LOCAL_OVERFLOW; LOCAL_HIREMAINDER; /* following is just for convenience: vmax==0 means no bound */ if (vmax == 0) vmax = ULONG_MAX; ld = lgefint(d); ld1 = lgefint(d1); lz = ld - ld1; /* >= 0 */ if (lz > 1) return 0; /* rare */ d = int_MSW(d); dm1 = *int_precW(d); d1 = int_MSW(d1);d1m1 = *int_precW(d1); dd1lo = 0; /* unless we find something better */ sh = bfffo(*d); if (sh) { /* do the shifting */ shc = BITS_IN_LONG - sh; if (lz) { /* dividend longer than divisor */ dd1 = (*d1 >> shc); if (!(HIGHMASK & dd1)) return 0; /* overflow detected */ if (ld1 > 3) dd1lo = (*d1 << sh) + (d1m1 >> shc); else dd1lo = (*d1 << sh); } else { /* dividend and divisor have the same length */ dd1 = (*d1 << sh); if (!(HIGHMASK & dd1)) return 0; if (ld1 > 3) { dd1 += (d1m1 >> shc); if (ld1 > 4) dd1lo = (d1m1 << sh) + (*int_precW(int_precW(d1)) >> shc); else dd1lo = (d1m1 << sh); } } /* following lines assume d to have 2 or more significant words */ dd = (*d << sh) + (dm1 >> shc); if (ld > 4) ddlo = (dm1 << sh) + (*int_precW(int_precW(d)) >> shc); else ddlo = (dm1 << sh); } else { /* no shift needed */ if (lz) return 0; /* dividend longer than divisor: overflow */ dd1 = *d1; if (!(HIGHMASK & dd1)) return 0; if(ld1 > 3) dd1lo = d1m1; /* assume again that d has another significant word */ dd = *d; ddlo = dm1; } /* First subtraction/division stage. (If a subtraction initially suffices, * we don't divide at all.) If a Jebelean condition is violated, and we * can't fix it even by looking at the low-order bits in ddlo,dd1lo, we * give up and ask for a full division. Otherwise we commit the result, * possibly deciding to re-shift immediately afterwards. */ dd -= dd1; if (dd < dd1) { /* first quotient known to be == 1 */ xv1 = 1UL; if (!dd) /* !(Jebelean condition), extraspecial case */ { /* note this can actually happen... Now q==1 is known, but we underflow * already. OTOH we've just shortened d by a whole word. Thus we are * happy and return. */ *u = 0; *v = *u1 = *v1 = 1UL; return -1; /* Next step will be a full division. */ } } else { /* division indicated */ hiremainder = 0; xv1 = 1 + divll(dd, dd1); /* xv1: alternative spelling of `q', here ;) */ dd = hiremainder; if (dd < xv1) /* !(Jebelean cond'), non-extra special case */ { /* Attempt to complete the division using the less significant bits, * before skipping right past the 1st loop to the reshift stage. */ ddlo = subll(ddlo, mulll(xv1, dd1lo)); dd = subllx(dd, hiremainder); /* If we now have an overflow, q was too large. Thanks to our decision * not to get here unless the original dd1 had bits set in the upper half * of the word, we now know that the correct quotient is in fact q-1. */ if (overflow) { xv1--; ddlo = addll(ddlo,dd1lo); dd = addllx(dd,dd1); /* overflows again which cancels the borrow */ /* ...and fall through to skip=1 below */ } else /* Test Jebelean condition anew, at this point using _all_ the extracted * bits we have. This is clutching at straws; we have a more or less * even chance of succeeding this time. Note that if we fail, we really * do not know whether the correct quotient would have been q or some * smaller value. */ if (!dd && ddlo < xv1) return 0; /* Otherwise, we now know that q is correct, but we cannot go into the * 1st loop. Raise a flag so we'll remember to skip past the loop. * Get here also after the q-1 adjustment case. */ skip = 1; } /* if !(Jebelean) then */ } res = 1; if (xv1 > vmax) { /* gone past the bound already */ *u = 0UL; *u1 = 1UL; *v = 1UL; *v1 = xv1; return res; } xu = 0UL; xv = xu1 = 1UL; /* Some invariants from here across the first loop: * * At this point, and again after we are finished with the first loop and * subsequent conditional, a division and the attached update of the * recurrence matrix have just been carried out completely. The matrix * xu,xu1;xv,xv1 has been initialized (or updated, possibly with permuted * columns), and the current remainder == next divisor (dd at the moment) * is nonzero (it might be zero here, but then skip will have been set). * * After the first loop, or when skip is set already, it will also be the * case that there aren't sufficiently many bits to continue without re- * shifting. If the divisor after reshifting is zero, or indeed if it * doesn't have more than half a word's worth of bits, we will have to * return at that point. Otherwise, we proceed into the second loop. * * Furthermore, when we reach the re-shift stage, dd:ddlo and dd1:dd1lo will * already reflect the result of applying the current matrix to the old * ddorig:ddlo and dd1orig:dd1lo. (For the first iteration above, this * was easy to achieve, and we didn't even need to peek into the (now * no longer existent!) saved words. After the loop, we'll stop for a * moment to merge in the ddlo,dd1lo contributions.) * * Note that after the 1st division, even an a priori quotient of 1 cannot be * trusted until we've checked Jebelean's condition: it might be too small */ if (!skip) { for(;;) { /* First half of loop divides dd into dd1, and leaves the recurrence * matrix xu,...,xv1 groomed the wrong way round (xu,xv will be the newer * entries) when successful. */ tmpd = dd1 - dd; if (tmpd < dd) { /* quotient suspected to be 1 */ tmpu = xu + xu1; /* cannot overflow -- everything bounded by * the original dd during first loop */ tmpv = xv + xv1; } else { /* division indicated */ hiremainder = 0; q = 1 + divll(tmpd, dd); tmpd = hiremainder; tmpu = xu + q*xu1; /* can't overflow, but may need to be undone */ tmpv = xv + q*xv1; } tmp0 = addll(tmpv, xv1); if ((tmpd < tmpu) || overflow || (dd - tmpd < tmp0)) /* !(Jebelean cond.) */ break; /* skip ahead to reshift stage */ else { /* commit dd1, xu, xv */ res++; dd1 = tmpd; xu = tmpu; xv = tmpv; if (xv > vmax) { *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return res; } } /* Second half of loop divides dd1 into dd, and the matrix returns to its * normal arrangement. */ tmpd = dd - dd1; if (tmpd < dd1) { /* quotient suspected to be 1 */ tmpu = xu1 + xu; /* cannot overflow */ tmpv = xv1 + xv; } else { /* division indicated */ hiremainder = 0; q = 1 + divll(tmpd, dd1); tmpd = hiremainder; tmpu = xu1 + q*xu; tmpv = xv1 + q*xv; } tmp0 = addll(tmpu, xu); if ((tmpd < tmpv) || overflow || (dd1 - tmpd < tmp0)) /* !(Jebelean cond.) */ break; /* skip ahead to reshift stage */ else { /* commit dd, xu1, xv1 */ res++; dd = tmpd; xu1 = tmpu; xv1 = tmpv; if (xv1 > vmax) { *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return res; } } } /* end of first loop */ /* Intermezzo: update dd:ddlo, dd1:dd1lo. (But not if skip is set.) */ if (res&1) { /* after failed division in 1st half of loop: * [dd1:dd1lo,dd:ddlo] = [ddorig:ddlo,dd1orig:dd1lo] * * [ -xu, xu1 ; xv, -xv1 ] * Actually, we only multiply [ddlo,dd1lo] onto the matrix and add the * high-order remainders + overflows onto [dd1,dd] */ tmp1 = mulll(ddlo, xu); tmp0 = hiremainder; tmp1 = subll(mulll(dd1lo,xv), tmp1); dd1 += subllx(hiremainder, tmp0); tmp2 = mulll(ddlo, xu1); tmp0 = hiremainder; ddlo = subll(tmp2, mulll(dd1lo,xv1)); dd += subllx(tmp0, hiremainder); dd1lo = tmp1; } else { /* after failed division in 2nd half of loop: * [dd:ddlo,dd1:dd1lo] = [ddorig:ddlo,dd1orig:dd1lo] * * [ xu1, -xu ; -xv1, xv ] * Actually, we only multiply [ddlo,dd1lo] onto the matrix and add the * high-order remainders + overflows onto [dd,dd1] */ tmp1 = mulll(ddlo, xu1); tmp0 = hiremainder; tmp1 = subll(tmp1, mulll(dd1lo,xv1)); dd += subllx(tmp0, hiremainder); tmp2 = mulll(ddlo, xu); tmp0 = hiremainder; dd1lo = subll(mulll(dd1lo,xv), tmp2); dd1 += subllx(hiremainder, tmp0); ddlo = tmp1; } } /* end of skip-pable section: get here also, with res==1, when there * was a problem immediately after the very first division. */ /* Re-shift. Note: the shift count _can_ be zero, viz. under the following * precise conditions: The original dd1 had its topmost bit set, so the 1st * q was 1, and after subtraction, dd had its topmost bit unset. If now * dd==0, we'd have taken the return exit already, so we couldn't have got * here. If not, then it must have been the second division which has gone * amiss (because dd1 was very close to an exact multiple of the remainder * dd value, so this will be very rare). At this point, we'd have a fairly * slim chance of fixing things by re-examining dd1:dd1lo vs. dd:ddlo, but * this is not guaranteed to work. Instead of trying, we return at once. * The caller will see to it that the initial subtraction is re-done using * _all_ the bits of both operands, which already helps, and the next round * will either be a full division (if dd occupied a halfword or less), or * another llgcdii() first step. In the latter case, since we try a little * harder during our first step, we may actually be able to fix the problem, * and get here again with improved low-order bits and with another step * under our belt. Otherwise we'll have given up above and forced a full- * blown division. * * If res is even, the shift count _cannot_ be zero. (The first step forces * a zero into the remainder's MSB, and all subsequent remainders will have * inherited it.) * * The re-shift stage exits if the next divisor has at most half a word's * worth of bits. * * For didactic reasons, the second loop will be arranged in the same way * as the first -- beginning with the division of dd into dd1, as if res * was odd. To cater for this, if res is actually even, we swap things * around during reshifting. (During the second loop, the parity of res * does not matter; we know in which half of the loop we are when we decide * to return.) */ if (res&1) { /* after odd number of division(s) */ if (dd1 && (sh = bfffo(dd1))) { shc = BITS_IN_LONG - sh; dd = (ddlo >> shc) + (dd << sh); if (!(HIGHMASK & dd)) { *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return -res; /* full division asked for */ } dd1 = (dd1lo >> shc) + (dd1 << sh); } else { /* time to return: <= 1 word left, or sh==0 */ *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return res; } } else { /* after even number of divisions */ if (dd) { sh = bfffo(dd); /* > 0 */ shc = BITS_IN_LONG - sh; /* dd:ddlo will become the new dd1, and v.v. */ tmpd = (ddlo >> shc) + (dd << sh); dd = (dd1lo >> shc) + (dd1 << sh); dd1 = tmpd; /* This completes the swap; now dd is again the current divisor */ if (HIGHMASK & dd) { /* recurrence matrix is the wrong way round; swap it */ tmp0 = xu; xu = xu1; xu1 = tmp0; tmp0 = xv; xv = xv1; xv1 = tmp0; } else { /* recurrence matrix is the wrong way round; fix this */ *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return -res; /* full division asked for */ } } else { /* time to return: <= 1 word left */ *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return res; } } /* end reshift */ /* The Second Loop. Rip-off of the first, but we now check for overflow * in the recurrences. Returns instead of breaking when we cannot fix the * quotient any longer. */ for(;;) { /* First half of loop divides dd into dd1, and leaves the recurrence * matrix xu,...,xv1 groomed the wrong way round (xu,xv will be the newer * entries) when successful */ tmpd = dd1 - dd; if (tmpd < dd) { /* quotient suspected to be 1 */ tmpu = xu + xu1; tmpv = addll(xv, xv1); /* xv,xv1 will overflow first */ tmp1 = overflow; } else { /* division indicated */ hiremainder = 0; q = 1 + divll(tmpd, dd); tmpd = hiremainder; tmpu = xu + q*xu1; tmpv = addll(xv, mulll(q,xv1)); tmp1 = overflow | hiremainder; } tmp0 = addll(tmpv, xv1); if ((tmpd < tmpu) || overflow || tmp1 || (dd - tmpd < tmp0)) /* !(Jebelean cond.) */ { /* The recurrence matrix has not yet been warped... */ *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; break; } /* commit dd1, xu, xv */ res++; dd1 = tmpd; xu = tmpu; xv = tmpv; if (xv > vmax) { *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return res; } /* Second half of loop divides dd1 into dd, and the matrix returns to its * normal arrangement */ tmpd = dd - dd1; if (tmpd < dd1) { /* quotient suspected to be 1 */ tmpu = xu1 + xu; tmpv = addll(xv1, xv); tmp1 = overflow; } else { /* division indicated */ hiremainder = 0; q = 1 + divll(tmpd, dd1); tmpd = hiremainder; tmpu = xu1 + q*xu; tmpv = addll(xv1, mulll(q, xv)); tmp1 = overflow | hiremainder; } tmp0 = addll(tmpu, xu); if ((tmpd < tmpv) || overflow || tmp1 || (dd1 - tmpd < tmp0)) /* !(Jebelean cond.) */ { /* The recurrence matrix has not yet been unwarped, so it is * the wrong way round; fix this. */ *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; break; } res++; /* commit dd, xu1, xv1 */ dd = tmpd; xu1 = tmpu; xv1 = tmpv; if (xv1 > vmax) { *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return res; } } /* end of second loop */ return res; } /* 1 / Mod(x,p). Assume x < p */ ulong Fl_invsafe(ulong x, ulong p) { long s; ulong xv, xv1, g = xgcduu(p, x, 1, &xv, &xv1, &s); if (g != 1UL) return 0UL; xv = xv1 % p; if (s < 0) xv = p - xv; return xv; } /* result known to be representable as an ulong */ static ulong lcmuu(ulong a, ulong b) { ulong d = ugcd(a,b); return (a/d) * b; } /* assume 0 < x < N; return u in (Z/NZ)^* such that u x = gcd(x,N) (mod N); * set *pd = gcd(x,N) */ ulong Fl_invgen(ulong x, ulong N, ulong *pd) { ulong d, d0, e, v, v1; long s; *pd = d = xgcduu(N, x, 0, &v, &v1, &s); if (s > 0) v = N - v; if (d == 1) return v; /* vx = gcd(x,N) (mod N), v coprime to N/d but need not be coprime to N */ e = N / d; d0 = u_ppo(d, e); /* d = d0 d1, d0 coprime to N/d, rad(d1) | N/d */ if (d0 == 1) return v; e = lcmuu(e, d / d0); return u_chinese_coprime(v, 1, e, d0, e*d0); } /* 1 / Mod(x,p). Assume x < p */ ulong Fl_inv(ulong x, ulong p) { ulong xv = Fl_invsafe(x, p); if (!xv && p!=1UL) pari_err_INV("Fl_inv", mkintmod(utoi(x), utoi(p))); return xv; } pari-2.11.2/src/kernel/none/MakeLVL1.SH0000644000175000017500000000077712314242551015746 0ustar billbillcat >> $file << EOT L1OBJS=$kern1/int.h $knone/level1.h parilvl1.h: \$(L1OBJS) $src/headers/paritune.h if test -r ./tune.h; then d=.; else d=$kern1; fi;\ cat \$\$d/tune.h \$(L1OBJS) > parilvl1.h MP_C=$kern1/mp.c $knone/cmp.c $knone/gcdll.c $knone/ratlift.c\ $knone/invmod.c $kern1/gcd.c $kern1/gcdext.c $knone/mp_indep.c $knone/add.c mpker.c: \$(MP_C) cat \$(MP_C) > mpker.c mpker\$(_O): .headers mpker.c \$(CC) -c \$(CFLAGS) \$(KERNELCFLAGS) \$(DLCFLAGS) \$(CPPFLAGS) -o mpker\$(_O) mpker.c EOT pari-2.11.2/src/kernel/none/int.h0000644000175000017500000000260713036414402015131 0ustar billbill#line 2 "../src/kernel/none/int.h" /* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define int_MSW(x) ((x)+2) /*x being a t_INT, return a pointer to the most significant word of x.*/ #define int_LSW(x) ((x)+lgefint((x))-1) /*x being a t_INT, return a pointer to the least significant word of x.*/ #define int_precW(x) ((x)+1) /*x pointing to a mantissa word, return the previous (less significant) * mantissa word.*/ #define int_nextW(x) ((x)-1) /*x pointing to a mantissa word, return the next (more significant) mantissa * word.*/ #define int_W(x,l) ((x)+lgefint((x))-1-(l)) /*x being a t_INT, return a pointer to the l-th least significant word of x.*/ #define int_W_lg(x,l,lx) ((x)+lx-1-(l)) /*x being a t_INT, return a pointer to the l-th least significant word of x, * assuming lgefint(x) = lx.*/ #define PARI_KERNEL_NONE /*This macro should not be used in libpari itself.*/ pari-2.11.2/src/kernel/none/gcd.c0000644000175000017500000000623213326135265015076 0ustar billbill#line 2 "../src/kernel/none/gcd.c" /* Copyright (C) 2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* assume y > x > 0. return y mod x */ static ulong resiu(GEN y, ulong x) { long i, ly = lgefint(y); ulong xi = get_Fl_red(x); LOCAL_HIREMAINDER; hiremainder = 0; for (i=2; iy>0, both of them odd. return x-y if x=y mod 4, x+y otherwise */ static void gcd_plus_minus(GEN x, GEN y, GEN res) { pari_sp av = avma; long lx = lgefint(x)-1; long ly = lgefint(y)-1, lt,m,i; GEN t; if ((x[lx]^y[ly]) & 3) /* x != y mod 4*/ t = addiispec(x+2,y+2,lx-1,ly-1); else t = subiispec(x+2,y+2,lx-1,ly-1); lt = lgefint(t)-1; while (!t[lt]) lt--; m = vals(t[lt]); lt++; if (m == 0) /* 2^32 | t */ { for (i = 2; i < lt; i++) res[i] = t[i]; } else if (t[2] >> m) { shift_right(res,t, 2,lt, 0,m); } else { lt--; t++; shift_right(res,t, 2,lt, t[1],m); } res[1] = evalsigne(1)|evallgefint(lt); avma = av; } /* uses modified right-shift binary algorithm now --GN 1998Jul23 */ GEN gcdii(GEN a, GEN b) { long v, w; pari_sp av; GEN t, p1; switch (abscmpii(a,b)) { case 0: return absi(a); case -1: swap(a,b); } if (!signe(b)) return absi(a); /* here |a|>|b|>0. Try single precision first */ if (lgefint(a)==3) return igcduu((ulong)a[2], (ulong)b[2]); if (lgefint(b)==3) { ulong u = resiu(a,(ulong)b[2]); if (!u) return absi(b); return igcduu((ulong)b[2], u); } /* larger than gcd: "avma=av" gerepile (erasing t) is valid */ av = avma; (void)new_chunk(lgefint(b)); /* HACK */ t = remii(a,b); if (!signe(t)) { avma = av; return absi(b); } a = b; b = t; v = vali(a); a = shifti(a,-v); setabssign(a); w = vali(b); b = shifti(b,-w); setabssign(b); if (w < v) v = w; switch(abscmpii(a,b)) { case 0: avma = av; a = shifti(a,v); return a; case -1: swap(a,b); } if (is_pm1(b)) { avma = av; return int2n(v); } /* we have three consecutive memory locations: a,b,t. * All computations are done in place */ /* a and b are odd now, and a>b>1 */ while (lgefint(a) > 3) { /* if a=b mod 4 set t=a-b, otherwise t=a+b, then strip powers of 2 */ /* so that t <= (a+b)/4 < a/2 */ gcd_plus_minus(a,b, t); if (is_pm1(t)) { avma = av; return int2n(v); } switch(abscmpii(t,b)) { case -1: p1 = a; a = b; b = t; t = p1; break; case 1: swap(a,t); break; case 0: avma = av; b = shifti(b,v); return b; } } { long r[] = {evaltyp(t_INT)|_evallg(3), evalsigne(1)|evallgefint(3), 0}; r[2] = (long) gcduodd((ulong)b[2], (ulong)a[2]); avma = av; return shifti(r,v); } } pari-2.11.2/src/kernel/none/mp.c0000644000175000017500000015157413326135265014767 0ustar billbill#line 2 "../src/kernel/none/mp.c" /* Copyright (C) 2000-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /***********************************************************************/ /** **/ /** MULTIPRECISION KERNEL **/ /** **/ /***********************************************************************/ #include "pari.h" #include "paripriv.h" #include "../src/kernel/none/tune-gen.h" void pari_kernel_init(void) { } void pari_kernel_close(void) { } /* NOTE: arguments of "spec" routines (muliispec, addiispec, etc.) aren't * GENs but pairs (long *a, long na) representing a list of digits (in basis * BITS_IN_LONG) : a[0], ..., a[na-1]. [ In ordre to facilitate splitting: no * need to reintroduce codewords ] */ #define LIMBS(x) ((x)+2) #define NLIMBS(x) (lgefint(x)-2) /* Normalize a non-negative integer */ GEN int_normalize(GEN x, long known_zero_words) { long i, lx = lgefint(x); GEN x0; if (lx == 2) { x[1] = evalsigne(0) | evallgefint(2); return x; } if (!known_zero_words && x[2]) return x; for (i = 2+known_zero_words; i < lx; i++) if (x[i]) break; x0 = x; i -= 2; x += i; if (x0 == (GEN)avma) avma = (pari_sp)x; else stackdummy((pari_sp)(x0+i), (pari_sp)x0); lx -= i; x[0] = evaltyp(t_INT) | evallg(lx); if (lx == 2) x[1] = evalsigne(0) | evallgefint(lx); else x[1] = evalsigne(1) | evallgefint(lx); return x; } /***********************************************************************/ /** **/ /** ADDITION / SUBTRACTION **/ /** **/ /***********************************************************************/ GEN setloop(GEN a) { pari_sp av = avma; (void)cgetg(lgefint(a) + 3, t_VECSMALL); return icopy_avma(a, av); /* two cells of extra space before a */ } /* we had a = setloop(?), then some incloops. Reset a to b */ GEN resetloop(GEN a, GEN b) { long lb = lgefint(b); a += lgefint(a) - lb; a[0] = evaltyp(t_INT) | evallg(lb); affii(b, a); return a; } /* assume a > 0, initialized by setloop. Do a++ */ static GEN incpos(GEN a) { long i, l = lgefint(a); for (i=l-1; i>1; i--) if (++a[i]) return a; l++; a--; /* use extra cell */ a[0]=evaltyp(t_INT) | _evallg(l); a[1]=evalsigne(1) | evallgefint(l); a[2]=1; return a; } /* assume a < 0, initialized by setloop. Do a++ */ static GEN incneg(GEN a) { long i, l = lgefint(a)-1; if (uel(a,l)--) { if (l == 2 && !a[2]) { a++; /* save one cell */ a[0] = evaltyp(t_INT) | _evallg(2); a[1] = evalsigne(0) | evallgefint(2); } return a; } for (i = l-1;; i--) /* finishes since a[2] != 0 */ if (uel(a,i)--) break; if (!a[2]) { a++; /* save one cell */ a[0] = evaltyp(t_INT) | _evallg(l); a[1] = evalsigne(-1) | evallgefint(l); } return a; } /* assume a initialized by setloop. Do a++ */ GEN incloop(GEN a) { switch(signe(a)) { case 0: a--; /* use extra cell */ a[0]=evaltyp(t_INT) | _evallg(3); a[1]=evalsigne(1) | evallgefint(3); a[2]=1; return a; case -1: return incneg(a); default: return incpos(a); } } INLINE GEN adduispec(ulong s, GEN x, long nx) { GEN xd, zd = (GEN)avma; long lz; if (nx == 1) return adduu(s, uel(x,0)); lz = nx+3; (void)new_chunk(lz); xd = x + nx; *--zd = (ulong)*--xd + s; if ((ulong)*zd < s) for(;;) { if (xd == x) { *--zd = 1; break; } /* enlarge z */ *--zd = ((ulong)*--xd) + 1; if (*zd) { lz--; break; } } else lz--; while (xd > x) *--zd = *--xd; *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)zd; return zd; } GEN adduispec_offset(ulong s, GEN x, long offset, long nx) { GEN xd = x+lgefint(x)-nx-offset; while (nx && *xd==0) {xd++; nx--;} if (!nx) return utoi(s); return adduispec(s,xd,nx); } static GEN addiispec(GEN x, GEN y, long nx, long ny) { GEN xd, yd, zd; long lz, i = -2; LOCAL_OVERFLOW; if (nx < ny) swapspec(x,y, nx,ny); if (ny == 1) return adduispec(*y,x,nx); zd = (GEN)avma; lz = nx+3; (void)new_chunk(lz); xd = x + nx; yd = y + ny; zd[-1] = addll(xd[-1], yd[-1]); #ifdef addllx8 for ( ; i-8 > -ny; i-=8) addllx8(xd+i, yd+i, zd+i, overflow); #endif for ( ; i >= -ny; i--) zd[i] = addllx(xd[i], yd[i]); if (overflow) for(;;) { if (i < -nx) { zd[i] = 1; i--; break; } /* enlarge z */ zd[i] = uel(xd,i) + 1; if (zd[i]) { i--; lz--; break; } i--; } else lz--; for (; i >= -nx; i--) zd[i] = xd[i]; zd += i+1; *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)zd; return zd; } /* assume x >= s */ INLINE GEN subiuspec(GEN x, ulong s, long nx) { GEN xd, zd = (GEN)avma; long lz; LOCAL_OVERFLOW; if (nx == 1) return utoi(x[0] - s); lz = nx+2; (void)new_chunk(lz); xd = x + nx; *--zd = subll(*--xd, s); if (overflow) for(;;) { *--zd = ((ulong)*--xd) - 1; if (*xd) break; } if (xd == x) while (*zd == 0) { zd++; lz--; } /* shorten z */ else do *--zd = *--xd; while (xd > x); *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)zd; return zd; } /* assume x > y */ static GEN subiispec(GEN x, GEN y, long nx, long ny) { GEN xd,yd,zd; long lz, i = -2; LOCAL_OVERFLOW; if (ny==1) return subiuspec(x,*y,nx); zd = (GEN)avma; lz = nx+2; (void)new_chunk(lz); xd = x + nx; yd = y + ny; zd[-1] = subll(xd[-1], yd[-1]); #ifdef subllx8 for ( ; i-8 > -ny; i-=8) subllx8(xd+i, yd+i, zd+i, overflow); #endif for ( ; i >= -ny; i--) zd[i] = subllx(xd[i], yd[i]); if (overflow) for(;;) { zd[i] = uel(xd,i) - 1; if (xd[i--]) break; } if (i>=-nx) for (; i >= -nx; i--) zd[i] = xd[i]; else while (zd[i+1] == 0) { i++; lz--; } /* shorten z */ zd += i+1; *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)zd; return zd; } static void roundr_up_ip(GEN x, long l) { long i = l; for(;;) { if (++uel(x,--i)) break; if (i == 2) { x[2] = (long)HIGHBIT; shiftr_inplace(x, 1); break; } } } void affir(GEN x, GEN y) { const long s = signe(x), ly = lg(y); long lx, sh, i; if (!s) { y[1] = evalexpo(-prec2nbits(ly)); return; } lx = lgefint(x); sh = bfffo(x[2]); y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-sh-1); if (sh) { if (lx <= ly) { for (i=lx; i ly: round properly */ if ((uel(x,ly)< ly: round properly */ if (uel(x,ly) & HIGHBIT) roundr_up_ip(y, ly); } } INLINE GEN shiftispec(GEN x, long nx, long n) { long ny, i, m; GEN y, yd; if (!n) return icopyspec(x, nx); if (n > 0) { GEN z = (GEN)avma; long d = dvmdsBIL(n, &m); ny = nx+d; y = new_chunk(ny + 2); yd = y + 2; for ( ; d; d--) *--z = 0; if (!m) for (i=0; i> sh; /* Extend y on the left? */ if (i) { ny++; y = new_chunk(1); y[2] = i; } } } else { ny = nx - dvmdsBIL(-n, &m); if (ny<1) return gen_0; y = new_chunk(ny + 2); yd = y + 2; if (m) { shift_right(yd,x, 0,ny, 0,m); if (yd[0] == 0) { if (ny==1) { avma = (pari_sp)(y+3); return gen_0; } ny--; avma = (pari_sp)(++y); } } else { for (i=0; i lg(x)) pari_err_PREC( "truncr (precision loss in truncation)"); y=cgeti(d); y[1] = evalsigne(s) | evallgefint(d); if (++m == BITS_IN_LONG) for (i=2; i= 0) return truncr(x); if ((e=expo(x)) < 0) return gen_m1; d = nbits2lg(e+1); m = remsBIL(e); lx=lg(x); if (d>lx) pari_err_PREC( "floorr (precision loss in truncation)"); y = new_chunk(d); if (++m == BITS_IN_LONG) { for (i=2; i=2; i--) { uel(y,i)++; if (y[i]) goto END; } y=new_chunk(1); y[2]=1; d++; END: y[1] = evalsigne(-1) | evallgefint(d); y[0] = evaltyp(t_INT) | evallg(d); return y; } INLINE int cmpiispec(GEN x, GEN y, long lx, long ly) { long i; if (lx < ly) return -1; if (lx > ly) return 1; i = 0; while (i uel(y,i))? 1: -1; } INLINE int equaliispec(GEN x, GEN y, long lx, long ly) { long i; if (lx != ly) return 0; i = ly-1; while (i>=0 && x[i]==y[i]) i--; return i < 0; } /***********************************************************************/ /** **/ /** MULTIPLICATION **/ /** **/ /***********************************************************************/ /* assume ny > 0 */ INLINE GEN muluispec(ulong x, GEN y, long ny) { GEN yd, z = (GEN)avma; long lz = ny+3; LOCAL_HIREMAINDER; (void)new_chunk(lz); yd = y + ny; *--z = mulll(x, *--yd); while (yd > y) *--z = addmul(x,*--yd); if (hiremainder) *--z = hiremainder; else lz--; *--z = evalsigne(1) | evallgefint(lz); *--z = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)z; return z; } /* a + b*|Y| */ GEN addumului(ulong a, ulong b, GEN Y) { GEN yd,y,z; long ny,lz; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (!b || !signe(Y)) return utoi(a); y = LIMBS(Y); z = (GEN)avma; ny = NLIMBS(Y); lz = ny+3; (void)new_chunk(lz); yd = y + ny; *--z = addll(a, mulll(b, *--yd)); if (overflow) hiremainder++; /* can't overflow */ while (yd > y) *--z = addmul(b,*--yd); if (hiremainder) *--z = hiremainder; else lz--; *--z = evalsigne(1) | evallgefint(lz); *--z = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)z; return z; } /***********************************************************************/ /** **/ /** DIVISION **/ /** **/ /***********************************************************************/ ulong umodiu(GEN y, ulong x) { long sy=signe(y),ly,i; ulong xi; LOCAL_HIREMAINDER; if (!x) pari_err_INV("umodiu",gen_0); if (!sy) return 0; ly = lgefint(y); if (x <= uel(y,2)) { hiremainder=0; if (ly==3) { hiremainder=uel(y,2)%x; if (!hiremainder) return 0; return (sy > 0)? hiremainder: x - hiremainder; } } else { if (ly==3) return (sy > 0)? uel(y,2): x - uel(y,2); hiremainder=uel(y,2); ly--; y++; } xi = get_Fl_red(x); for (i=2; i 0)? hiremainder: x - hiremainder; } /* return |y| \/ x */ GEN absdiviu_rem(GEN y, ulong x, ulong *rem) { long ly,i; GEN z; ulong xi; LOCAL_HIREMAINDER; if (!x) pari_err_INV("absdiviu_rem",gen_0); if (!signe(y)) { *rem = 0; return gen_0; } ly = lgefint(y); if (x <= uel(y,2)) { hiremainder=0; if (ly==3) { z = cgetipos(3); z[2] = divll(uel(y,2),x); *rem = hiremainder; return z; } } else { if (ly==3) { *rem = uel(y,2); return gen_0; } hiremainder = uel(y,2); ly--; y++; } xi = get_Fl_red(x); z = cgetipos(ly); for (i=2; i3)? x[3]: 0; LOCAL_HIREMAINDER; if (k < uel(y,2)) e--; else { l >>= 1; if (k&1) l |= HIGHBIT; k >>= 1; } hiremainder = k; k = divll(l,y[2]); if (hiremainder & HIGHBIT) { k++; if (!k) { k = HIGHBIT; e++; } } r = cgetr(3); r[1] = evalsigne(sx) | evalexpo(e); r[2] = k; return r; } lr = minss(lx,ly); r = new_chunk(lr); r1 = r-1; r1[1] = 0; for (i=2; ily)? x[lr]: 0; y0 = y[2]; y1 = y[3]; for (i=0; i y0) /* can't happen if i=0 */ { GEN y1 = y+1; j = lr-i; r1[j] = subll(r1[j],y1[j]); for (j--; j>0; j--) r1[j] = subllx(r1[j],y1[j]); j=i; do uel(r,--j)++; while (j && !uel(r,j)); } hiremainder = r1[1]; overflow = 0; qp = divll(r1[2],y0); k = hiremainder; } j = lr-i+1; if (!overflow) { long k3, k4; k3 = mulll(qp,y1); if (j == 3) /* i = lr - 2 maximal, r1[3] undefined -> 0 */ k4 = subll(hiremainder,k); else { k3 = subll(k3, r1[3]); k4 = subllx(hiremainder,k); } while (!overflow && k4) { qp--; k3 = subll(k3,y1); k4 = subllx(k4,y0); } } if (j1; j--) { r1[j] = subll(r1[j], addmul(qp,y[j])); hiremainder += overflow; } if (uel(r1,1) != hiremainder) { if (uel(r1,1) < hiremainder) { qp--; j = lr-i-(lr-i>=ly); r1[j] = addll(r1[j], y[j]); for (j--; j>1; j--) r1[j] = addllx(r1[j], y[j]); } else { r1[1] -= hiremainder; while (r1[1]) { qp++; if (!qp) { j=i; do uel(r,--j)++; while (j && !r[j]); } j = lr-i-(lr-i>=ly); r1[j] = subll(r1[j],y[j]); for (j--; j>1; j--) r1[j] = subllx(r1[j],y[j]); r1[1] -= overflow; } } } *++r1 = qp; } /* i = lr-1 */ /* round correctly */ if (uel(r1,1) > (y0>>1)) { j=i; do uel(r,--j)++; while (j && !r[j]); } r1 = r-1; for (j=i; j>=2; j--) r[j]=r1[j]; if (r[0] == 0) e--; else if (r[0] == 1) { shift_right(r,r, 2,lr, 1,1); } else { /* possible only when rounding up to 0x2 0x0 ... */ r[2] = (long)HIGHBIT; e++; } r[0] = evaltyp(t_REAL)|evallg(lr); r[1] = evalsigne(sx) | evalexpo(e); return r; } GEN divri(GEN x, GEN y) { long lx, s = signe(y); pari_sp av; GEN z; if (!s) pari_err_INV("divri",y); if (!signe(x)) return real_0_bit(expo(x) - expi(y)); if (!is_bigint(y)) { GEN z = divru(x, y[2]); if (s < 0) togglesign(z); return z; } lx = lg(x); z = cgetr(lx); av = avma; affrr(divrr(x, itor(y, lx+1)), z); avma = av; return z; } /* Integer division x / y: such that sign(r) = sign(x) * if z = ONLY_REM return remainder, otherwise return quotient * if z != NULL set *z to remainder * *z is the last object on stack (and thus can be disposed of with cgiv * instead of gerepile) * If *z is zero, we put gen_0 here and no copy. * space needed: lx + ly */ GEN dvmdii(GEN x, GEN y, GEN *z) { long sx = signe(x), sy = signe(y); long lx, ly = lgefint(y), lz, i, j, sh, lq, lr; pari_sp av; ulong y0,y0i,y1, *xd,*rd,*qd; GEN q, r, r1; if (!sx) { if (ly < 3) pari_err_INV("dvmdii",gen_0); if (!z || z == ONLY_REM) return gen_0; *z=gen_0; return gen_0; } if (ly <= 3) { ulong rem; if (ly < 3) pari_err_INV("dvmdii",gen_0); if (z == ONLY_REM) { rem = umodiu(x,uel(y,2)); if (!rem) return gen_0; return (sx < 0)? utoineg(uel(y,2) - rem): utoipos(rem); } q = absdiviu_rem(x, uel(y,2), &rem); if (sx != sy) togglesign(q); if (!z) return q; if (!rem) *z = gen_0; else *z = sx < 0? utoineg(rem): utoipos(rem); return q; } lx=lgefint(x); lz=lx-ly; if (lz <= 0) { if (lz == 0) { for (i=2; i uel(y,i)) goto DIVIDE; goto TRIVIAL; } if (z == ONLY_REM) return gen_0; if (z) *z = gen_0; if (sx < 0) sy = -sy; return stoi(sy); } TRIVIAL: if (z == ONLY_REM) return icopy(x); if (z) *z = icopy(x); return gen_0; } DIVIDE: /* quotient is non-zero */ av=avma; if (sx<0) sy = -sy; r1 = new_chunk(lx); sh = bfffo(y[2]); if (sh) { /* normalize so that highbit(y) = 1 (shift left x and y by sh bits)*/ register const ulong m = BITS_IN_LONG - sh; r = new_chunk(ly); shift_left(r, y,2,ly-1, 0,sh); y = r; shift_left(r1,x,2,lx-1, 0,sh); r1[1] = uel(x,2) >> m; } else { r1[1] = 0; for (j=2; j1; j--) { r1[j] = subll(r1[j], addmul(qp,y[j])); hiremainder += overflow; } if (uel(r1,1) < hiremainder) { qp--; j = ly-1; r1[j] = addll(r1[j],y[j]); for (j--; j>1; j--) r1[j] = addllx(r1[j],y[j]); } *++r1 = qp; } lq = lz+2; if (!z) { qd = (ulong*)av; xd = (ulong*)(x + lq); if (x[1]) { lz++; lq++; } while (lz--) *--qd = *--xd; *--qd = evalsigne(sy) | evallgefint(lq); *--qd = evaltyp(t_INT) | evallg(lq); avma = (pari_sp)qd; return (GEN)qd; } j=lq; while (j> sh; *--rd = l | (*--xd << shl); } l = *xd >> sh; if (l) *--rd = l; else lr--; } *--rd = evalsigne(sx) | evallgefint(lr); *--rd = evaltyp(t_INT) | evallg(lr); avma = (pari_sp)rd; return (GEN)rd; } lr = lz+2; rd = NULL; /* gcc -Wall */ if (lz) { /* non zero remainder: initialize rd */ xd = (ulong*)(x + lx); if (!sh) { rd = (ulong*)avma; (void)new_chunk(lr); while (lz--) *--rd = *--xd; } else { /* shift remainder right by sh bits */ const ulong shl = BITS_IN_LONG - sh; ulong l; rd = (ulong*)x; /* overwrite shifted y */ xd--; while (--lz) { l = *xd >> sh; *--rd = l | (*--xd << shl); } l = *xd >> sh; if (l) *--rd = l; else lr--; } *--rd = evalsigne(sx) | evallgefint(lr); *--rd = evaltyp(t_INT) | evallg(lr); rd += lr; } qd = (ulong*)av; xd = (ulong*)(x + lq); if (x[1]) lq++; j = lq-2; while (j--) *--qd = *--xd; *--qd = evalsigne(sy) | evallgefint(lq); *--qd = evaltyp(t_INT) | evallg(lq); q = (GEN)qd; if (lr==2) *z = gen_0; else { /* rd has been properly initialized: we had lz > 0 */ while (lr--) *--qd = *--rd; *z = (GEN)qd; } avma = (pari_sp)qd; return q; } /* Montgomery reduction. * N has k words, assume T >= 0 has less than 2k. * Return res := T / B^k mod N, where B = 2^BIL * such that 0 <= res < T/B^k + N and res has less than k words */ GEN red_montgomery(GEN T, GEN N, ulong inv) { pari_sp av; GEN Te, Td, Ne, Nd, scratch; ulong i, j, m, t, d, k = NLIMBS(N); int carry; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (k == 0) return gen_0; d = NLIMBS(T); /* <= 2*k */ if (d == 0) return gen_0; #ifdef DEBUG if (d > 2*k) pari_err_BUG("red_montgomery"); #endif if (k == 1) { /* as below, special cased for efficiency */ ulong n = uel(N,2); if (d == 1) { hiremainder = uel(T,2); m = hiremainder * inv; (void)addmul(m, n); /* t + m*n = 0 */ return utoi(hiremainder); } else { /* d = 2 */ hiremainder = uel(T,3); m = hiremainder * inv; (void)addmul(m, n); /* t + m*n = 0 */ t = addll(hiremainder, uel(T,2)); if (overflow) t -= n; /* t > n doesn't fit in 1 word */ return utoi(t); } } /* assume k >= 2 */ av = avma; scratch = new_chunk(k<<1); /* >= k + 2: result fits */ /* copy T to scratch space (pad with zeroes to 2k words) */ Td = (GEN)av; Te = T + (d+2); for (i=0; i < d ; i++) *--Td = *--Te; for ( ; i < (k<<1); i++) *--Td = 0; Te = (GEN)av; /* 1 beyond end of current T mantissa (in scratch) */ Ne = N + k+2; /* 1 beyond end of N mantissa */ carry = 0; for (i=0; i N overflows (k+1 words), set Td := Td - N */ Td = Te; Nd = Ne; t = subll(*--Td, *--Nd); *Td = t; while (Td > scratch) { t = subllx(*--Td, *--Nd); *Td = t; } } /* copy result */ Td = (GEN)av; while (*scratch == 0 && Te > scratch) scratch++; /* strip leading 0s */ while (Te > scratch) *--Td = *--Te; k = (GEN)av - Td; if (!k) { avma = av; return gen_0; } k += 2; *--Td = evalsigne(1) | evallgefint(k); *--Td = evaltyp(t_INT) | evallg(k); #ifdef DEBUG { long l = NLIMBS(N), s = BITS_IN_LONG*l; GEN R = int2n(s); GEN res = remii(mulii(T, Fp_inv(R, N)), N); if (k > lgefint(N) || !equalii(remii(Td,N),res) || cmpii(Td, addii(shifti(T, -s), N)) >= 0) pari_err_BUG("red_montgomery"); } #endif avma = (pari_sp)Td; return Td; } /* EXACT INTEGER DIVISION */ /* assume xy>0, the division is exact and y is odd. Destroy x */ static GEN diviuexact_i(GEN x, ulong y) { long i, lz, lx; ulong q, yinv; GEN z, z0, x0, x0min; if (y == 1) return icopy(x); lx = lgefint(x); if (lx == 3) { q = uel(x,2) / y; if (!q) pari_err_OP("exact division", x, utoi(y)); return utoipos(q); } yinv = invmod2BIL(y); lz = (y <= uel(x,2)) ? lx : lx-1; z = new_chunk(lz); z0 = z + lz; x0 = x + lx; x0min = x + lx-lz+2; while (x0 > x0min) { *--z0 = q = yinv*uel(--x0,0); /* i-th quotient */ if (!q) continue; /* x := x - q * y */ { /* update neither lowest word (could set it to 0) nor highest ones */ register GEN x1 = x0 - 1; LOCAL_HIREMAINDER; (void)mulll(q,y); if (hiremainder) { if (uel(x1,0) < hiremainder) { uel(x1,0) -= hiremainder; do uel(--x1,0)--; while (uel(x1,0) == ULONG_MAX); } else uel(x1,0) -= hiremainder; } } } i=2; while(!z[i]) i++; z += i-2; lz -= i-2; z[0] = evaltyp(t_INT)|evallg(lz); z[1] = evalsigne(1)|evallg(lz); if (lz == 2) pari_err_OP("exact division", x, utoi(y)); avma = (pari_sp)z; return z; } /* assume y != 0 and the division is exact */ GEN diviuexact(GEN x, ulong y) { pari_sp av; long lx, vy, s = signe(x); GEN z; if (!s) return gen_0; if (y == 1) return icopy(x); lx = lgefint(x); if (lx == 3) { ulong q = uel(x,2) / y; if (!q) pari_err_OP("exact division", x, utoi(y)); return (s > 0)? utoipos(q): utoineg(q); } av = avma; (void)new_chunk(lx); vy = vals(y); if (vy) { y >>= vy; if (y == 1) { avma = av; return shifti(x, -vy); } x = shifti(x, -vy); if (lx == 3) { ulong q = uel(x,2) / y; avma = av; if (!q) pari_err_OP("exact division", x, utoi(y)); return (s > 0)? utoipos(q): utoineg(q); } } else x = icopy(x); avma = av; z = diviuexact_i(x, y); setsigne(z, s); return z; } /* Find z such that x=y*z, knowing that y | x (unchecked) * Method: y0 z0 = x0 mod B = 2^BITS_IN_LONG ==> z0 = 1/y0 mod B. * Set x := (x - z0 y) / B, updating only relevant words, and repeat */ GEN diviiexact(GEN x, GEN y) { long lx, ly, lz, vy, i, ii, sx = signe(x), sy = signe(y); pari_sp av; ulong y0inv,q; GEN z; if (!sy) pari_err_INV("diviiexact",gen_0); if (!sx) return gen_0; lx = lgefint(x); if (lx == 3) { q = uel(x,2) / uel(y,2); if (!q) pari_err_OP("exact division", x, y); return (sx+sy) ? utoipos(q): utoineg(q); } vy = vali(y); av = avma; (void)new_chunk(lx); /* enough room for z */ if (vy) { /* make y odd */ y = shifti(y,-vy); x = shifti(x,-vy); lx = lgefint(x); } else x = icopy(x); /* necessary because we destroy x */ avma = av; /* will erase our x,y when exiting */ /* now y is odd */ ly = lgefint(y); if (ly == 3) { z = diviuexact_i(x,uel(y,2)); /* x != 0 */ setsigne(z, (sx+sy)? 1: -1); return z; } y0inv = invmod2BIL(y[ly-1]); i=2; while (i=2; i--,ii--) { long limj; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; z[i] = q = y0inv*uel(x,ii); /* i-th quotient */ if (!q) continue; /* x := x - q * y */ (void)mulll(q,y[0]); limj = maxss(lx - lz, ii+3-ly); { /* update neither lowest word (could set it to 0) nor highest ones */ register GEN x0 = x + (ii - 1), y0 = y - 1, xlim = x + limj; for (; x0 >= xlim; x0--, y0--) { *x0 = subll(*x0, addmul(q,*y0)); hiremainder += overflow; } if (hiremainder && limj != lx - lz) { if ((ulong)*x0 < hiremainder) { *x0 -= hiremainder; do (*--x0)--; while ((ulong)*x0 == ULONG_MAX); } else *x0 -= hiremainder; } } } i=2; while(!z[i]) i++; z += i-2; lz -= (i-2); z[0] = evaltyp(t_INT)|evallg(lz); z[1] = evalsigne((sx+sy)? 1: -1) | evallg(lz); if (lz == 2) pari_err_OP("exact division", x, y); avma = (pari_sp)z; return z; } /* assume yz != and yz | x */ GEN diviuuexact(GEN x, ulong y, ulong z) { long tmp[4]; ulong t; LOCAL_HIREMAINDER; t = mulll(y, z); if (!hiremainder) return diviuexact(x, t); tmp[0] = evaltyp(t_INT)|_evallg(4); tmp[1] = evalsigne(1)|evallgefint(4); tmp[2] = hiremainder; tmp[3] = t; return diviiexact(x, tmp); } /********************************************************************/ /** **/ /** INTEGER MULTIPLICATION (BASECASE) **/ /** **/ /********************************************************************/ /* nx >= ny = num. of digits of x, y (not GEN, see mulii) */ INLINE GEN muliispec_basecase(GEN x, GEN y, long nx, long ny) { GEN z2e,z2d,yd,xd,ye,zd; long p1,lz; LOCAL_HIREMAINDER; if (ny == 1) return muluispec((ulong)*y, x, nx); if (ny == 0) return gen_0; zd = (GEN)avma; lz = nx+ny+2; (void)new_chunk(lz); xd = x + nx; yd = y + ny; ye = yd; p1 = *--xd; *--zd = mulll(p1, *--yd); z2e = zd; while (yd > y) *--zd = addmul(p1, *--yd); *--zd = hiremainder; while (xd > x) { LOCAL_OVERFLOW; yd = ye; p1 = *--xd; z2d = --z2e; *z2d = addll(mulll(p1, *--yd), *z2d); z2d--; while (yd > y) { hiremainder += overflow; *z2d = addll(addmul(p1, *--yd), *z2d); z2d--; } *--zd = hiremainder + overflow; } if (*zd == 0) { zd++; lz--; } /* normalize */ *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)zd; return zd; } INLINE GEN sqrispec_basecase(GEN x, long nx) { GEN z2e,z2d,yd,xd,zd,x0,z0; long p1,lz; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (nx == 1) return sqru((ulong)*x); if (nx == 0) return gen_0; zd = (GEN)avma; lz = (nx+1) << 1; z0 = new_chunk(lz); if (nx == 1) { *--zd = mulll(*x, *x); *--zd = hiremainder; goto END; } xd = x + nx; /* compute double products --> zd */ p1 = *--xd; yd = xd; --zd; *--zd = mulll(p1, *--yd); z2e = zd; while (yd > x) *--zd = addmul(p1, *--yd); *--zd = hiremainder; x0 = x+1; while (xd > x0) { LOCAL_OVERFLOW; p1 = *--xd; yd = xd; z2e -= 2; z2d = z2e; *z2d = addll(mulll(p1, *--yd), *z2d); z2d--; while (yd > x) { hiremainder += overflow; *z2d = addll(addmul(p1, *--yd), *z2d); z2d--; } *--zd = hiremainder + overflow; } /* multiply zd by 2 (put result in zd - 1) */ zd[-1] = ((*zd & HIGHBIT) != 0); shift_left(zd, zd, 0, (nx<<1)-3, 0, 1); /* add the squares */ xd = x + nx; zd = z0 + lz; p1 = *--xd; zd--; *zd = mulll(p1,p1); zd--; *zd = addll(hiremainder, *zd); while (xd > x) { p1 = *--xd; zd--; *zd = addll(mulll(p1,p1)+ overflow, *zd); zd--; *zd = addll(hiremainder + overflow, *zd); } END: if (*zd == 0) { zd++; lz--; } /* normalize */ *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(pari_sp)zd; return zd; } /********************************************************************/ /** **/ /** INTEGER MULTIPLICATION (FFT) **/ /** **/ /********************************************************************/ /* Compute parameters for FFT: len: result length k: FFT depth. n: number of blocks (2^k) bs: block size mod: Modulus is M=2^(BIL*mod)+1 ord: order of 2 in Z/MZ. We must have: bs*n >= l 2^(BIL*mod) > nb*2^(2*BIL*bs) 2^k | 2*BIL*mod */ static void mulliifft_params(long len, long *k, long *mod, long *bs, long *n, ulong *ord) { long r; *k = expu((3*len)>>2)-3; do { (*k)--; r = *k-(TWOPOTBITS_IN_LONG+2); *n = 1L<<*k; *bs = (len+*n-1)>>*k; *mod= 2**bs+1; if (r>0) *mod=((*mod+(1L<>r)<=3**bs); *ord= 4**mod*BITS_IN_LONG; } /* Zf_: arithmetic in ring Z/MZ where M= 2^(BITS_IN_LONG*mod)+1 * for some mod. * Do not garbage collect. */ static GEN Zf_add(GEN a, GEN b, GEN M) { GEN y, z = addii(a,b); long mod = lgefint(M)-3; long l = NLIMBS(z); if (l<=mod) return z; y = subiu(z, 1); if (NLIMBS(y)<=mod) return z; return int_normalize(y,1); } static GEN Zf_sub(GEN a, GEN b, GEN M) { GEN z = subii(a,b); return signe(z)>=0? z: addii(M,z); } /* destroy z */ static GEN Zf_red_destroy(GEN z, GEN M) { long mod = lgefint(M)-3; long l = NLIMBS(z); GEN y; if (l<=mod) return z; y = shifti(z, -mod*BITS_IN_LONG); z = int_normalize(z, NLIMBS(y)); y = Zf_red_destroy(y, M); z = subii(z, y); if (signe(z)<0) z = addii(z, M); return z; } INLINE GEN Zf_shift(GEN a, ulong s, GEN M) { return Zf_red_destroy(shifti(a, s), M); } /* Multiply by sqrt(2)^s We use the formula sqrt(2)=z_8*(1-z_4)) && z_8=2^(ord/16) [2^(ord/4)+1] */ static GEN Zf_mulsqrt2(GEN a, ulong s, ulong ord, GEN M) { ulong hord = ord>>1; if (!signe(a)) return gen_0; if (odd(s)) /* Multiply by 2^(s/2) */ { GEN az8 = Zf_shift(a, ord>>4, M); GEN az83 = Zf_shift(az8, ord>>3, M); a = Zf_sub(az8, az83, M); s--; } if (s < hord) return Zf_shift(a, s>>1, M); else return subii(M,Zf_shift(a, (s-hord)>>1, M)); } INLINE GEN Zf_sqr(GEN a, GEN M) { return Zf_red_destroy(sqri(a), M); } INLINE GEN Zf_mul(GEN a, GEN b, GEN M) { return Zf_red_destroy(mulii(a,b), M); } /* In place, bit reversing FFT */ static void muliifft_dit(ulong o, ulong ord, GEN M, GEN FFT, long d, long step) { pari_sp av = avma; long i; ulong j, no = (o<<1)%ord; long hstep=step>>1; for (i = d+1, j = 0; i <= d+hstep; ++i, j =(j+o)%ord) { GEN a = Zf_add(gel(FFT,i), gel(FFT,i+hstep), M); GEN b = Zf_mulsqrt2(Zf_sub(gel(FFT,i), gel(FFT,i+hstep), M), j, ord, M); affii(a,gel(FFT,i)); affii(b,gel(FFT,i+hstep)); avma = av; } if (hstep>1) { muliifft_dit(no, ord, M, FFT, d, hstep); muliifft_dit(no, ord, M, FFT, d+hstep, hstep); } } /* In place, bit reversed FFT, inverse of muliifft_dit */ static void muliifft_dis(ulong o, ulong ord, GEN M, GEN FFT, long d, long step) { pari_sp av = avma; long i; ulong j, no = (o<<1)%ord; long hstep=step>>1; if (hstep>1) { muliifft_dis(no, ord, M, FFT, d, hstep); muliifft_dis(no, ord, M, FFT, d+hstep, hstep); } for (i = d+1, j = 0; i <= d+hstep; ++i, j =(j+o)%ord) { GEN z = Zf_mulsqrt2(gel(FFT,i+hstep), j, ord, M); GEN a = Zf_add(gel(FFT,i), z, M); GEN b = Zf_sub(gel(FFT,i), z, M); affii(a,gel(FFT,i)); affii(b,gel(FFT,i+hstep)); avma = av; } } static GEN muliifft_spliti(GEN a, long na, long bs, long n, long mod) { GEN ap = a+na-1; GEN c = cgetg(n+1, t_VEC); long i,j; for(i=1;i<=n;i++) { GEN z = cgeti(mod+3); if (na) { long m = minss(bs, na), v=0; GEN zp, aa=ap-m+1; while (!*aa && v>k; M = int2n(mod*BITS_IN_LONG); M[2+mod] = 1; FFT = muliifft_spliti(a, na, bs, n, mod); muliifft_dit(o, ord, M, FFT, 0, n); av = avma; for(i=1; i<=n; i++) { affii(Zf_sqr(gel(FFT,i), M), gel(FFT,i)); avma=av; } muliifft_dis(ord-o, ord, M, FFT, 0, n); for(i=1; i<=n; i++) { affii(Zf_shift(gel(FFT,i), (ord>>1)-k, M), gel(FFT,i)); avma=av; } return gerepileuptoint(ltop, muliifft_unspliti(FFT,bs,2+len)); } static GEN muliispec_fft(GEN a, GEN b, long na, long nb) { pari_sp av, av2, ltop = avma; long len = na+nb; long k, mod, bs, n; GEN FFT, FFTb, M; long i; ulong o, ord; mulliifft_params(len,&k,&mod,&bs,&n,&ord); o = ord>>k; M = int2n(mod*BITS_IN_LONG); M[2+mod] = 1; FFT = muliifft_spliti(a, na, bs, n, mod); av=avma; muliifft_dit(o, ord, M, FFT, 0, n); FFTb = muliifft_spliti(b, nb, bs, n, mod); av2 = avma; muliifft_dit(o, ord, M, FFTb, 0, n); for(i=1; i<=n; i++) { affii(Zf_mul(gel(FFT,i), gel(FFTb,i), M), gel(FFT,i)); avma=av2; } avma=av; muliifft_dis(ord-o, ord, M, FFT, 0, n); for(i=1; i<=n; i++) { affii(Zf_shift(gel(FFT,i),(ord>>1)-k,M), gel(FFT,i)); avma=av; } return gerepileuptoint(ltop, muliifft_unspliti(FFT,bs,2+len)); } /********************************************************************/ /** **/ /** INTEGER MULTIPLICATION (KARATSUBA) **/ /** **/ /********************************************************************/ /* return (x shifted left d words) + y. Assume d > 0, x > 0 and y >= 0 */ static GEN addshiftw(GEN x, GEN y, long d) { GEN z,z0,y0,yd, zd = (GEN)avma; long a,lz,ly = lgefint(y); z0 = new_chunk(d); a = ly-2; yd = y+ly; if (a >= d) { y0 = yd-d; while (yd > y0) *--zd = *--yd; /* copy last d words of y */ a -= d; if (a) z = addiispec(LIMBS(x), LIMBS(y), NLIMBS(x), a); else z = icopy(x); } else { y0 = yd-a; while (yd > y0) *--zd = *--yd; /* copy last a words of y */ while (zd > z0) *--zd = 0; /* complete with 0s */ z = icopy(x); } lz = lgefint(z)+d; z[1] = evalsigne(1) | evallgefint(lz); z[0] = evaltyp(t_INT) | evallg(lz); return z; } /* Fast product (Karatsuba) of integers. a and b are "special" GENs * c,c0,c1,c2 are genuine GENs. */ GEN muliispec(GEN a, GEN b, long na, long nb) { GEN a0,c,c0; long n0, n0a, i; pari_sp av; if (na < nb) swapspec(a,b, na,nb); if (nb < MULII_KARATSUBA_LIMIT) return muliispec_basecase(a,b,na,nb); if (nb >= MULII_FFT_LIMIT) return muliispec_fft(a,b,na,nb); i=(na>>1); n0=na-i; na=i; av=avma; a0=a+na; n0a=n0; while (n0a && !*a0) { a0++; n0a--; } if (n0a && nb > n0) { /* nb <= na <= n0 */ GEN b0,c1,c2; long n0b; nb -= n0; c = muliispec(a,b,na,nb); b0 = b+nb; n0b = n0; while (n0b && !*b0) { b0++; n0b--; } if (n0b) { c0 = muliispec(a0,b0, n0a,n0b); c2 = addiispec(a0,a, n0a,na); c1 = addiispec(b0,b, n0b,nb); c1 = muliispec(LIMBS(c1),LIMBS(c2), NLIMBS(c1),NLIMBS(c2)); c2 = addiispec(LIMBS(c0),LIMBS(c), NLIMBS(c0),NLIMBS(c)); c1 = subiispec(LIMBS(c1),LIMBS(c2), NLIMBS(c1),NLIMBS(c2)); } else { c0 = gen_0; c1 = muliispec(a0,b, n0a,nb); } c = addshiftw(c,c1, n0); } else { c = muliispec(a,b,na,nb); c0 = muliispec(a0,b,n0a,nb); } return gerepileuptoint(av, addshiftw(c,c0, n0)); } GEN muluui(ulong x, ulong y, GEN z) { long t, s = signe(z); GEN r; LOCAL_HIREMAINDER; if (!x || !y || !signe(z)) return gen_0; t = mulll(x,y); if (!hiremainder) r = muluispec(t, z+2, lgefint(z)-2); else { long tmp[2]; tmp[0] = hiremainder; tmp[1] = t; r = muliispec(z+2,tmp,lgefint(z)-2,2); } setsigne(r,s); return r; } #define sqrispec_mirror sqrispec #define muliispec_mirror muliispec /* x % (2^n), assuming n >= 0 */ GEN remi2n(GEN x, long n) { long hi,l,k,lx,ly, sx = signe(x); GEN z, xd, zd; if (!sx || !n) return gen_0; k = dvmdsBIL(n, &l); lx = lgefint(x); if (lx < k+3) return icopy(x); xd = x + (lx-k-1); /* x = |_|...|#|1|...|k| : copy the last l bits of # and the last k words * ^--- initial xd */ hi = ((ulong)*xd) & ((1UL<= SQRI_FFT_LIMIT) return sqrispec_fft(a,na); i=(na>>1); n0=na-i; na=i; av=avma; a0=a+na; n0a=n0; while (n0a && !*a0) { a0++; n0a--; } c = sqrispec(a,na); if (n0a) { GEN t, c1, c0 = sqrispec(a0,n0a); #if 0 c1 = shifti(muliispec(a0,a, n0a,na),1); #else /* faster */ t = addiispec(a0,a,n0a,na); t = sqrispec(LIMBS(t),NLIMBS(t)); c1= addiispec(LIMBS(c0),LIMBS(c), NLIMBS(c0), NLIMBS(c)); c1= subiispec(LIMBS(t),LIMBS(c1), NLIMBS(t), NLIMBS(c1)); #endif c = addshiftw(c,c1, n0); c = addshiftw(c,c0, n0); } else c = addshiftw(c,gen_0,n0<<1); return gerepileuptoint(av, c); } /********************************************************************/ /** **/ /** KARATSUBA SQUARE ROOT **/ /** adapted from Paul Zimmermann's implementation of **/ /** his algorithm in GMP (mpn_sqrtrem) **/ /** **/ /********************************************************************/ /* Square roots table */ static const unsigned char approx_tab[192] = { 128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142, 143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155, 156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168, 169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180, 181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191, 192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201, 202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211, 212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221, 221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230, 230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238, 239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247, 247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255 }; /* N[0], assume N[0] >= 2^(BIL-2). * Return r,s such that s^2 + r = N, 0 <= r <= 2s */ static void p_sqrtu1(ulong *N, ulong *ps, ulong *pr) { ulong prec, r, s, q, u, n0 = N[0]; q = n0 >> (BITS_IN_LONG - 8); /* 2^6 = 64 <= q < 256 = 2^8 */ s = approx_tab[q - 64]; /* 128 <= s < 255 */ r = (n0 >> (BITS_IN_LONG - 16)) - s * s; /* r <= 2*s */ if (r > (s << 1)) { r -= (s << 1) | 1; s++; } /* 8-bit approximation from the high 8-bits of N[0] */ prec = 8; n0 <<= 2 * prec; while (2 * prec < BITS_IN_LONG) { /* invariant: s has prec bits, and r <= 2*s */ r = (r << prec) + (n0 >> (BITS_IN_LONG - prec)); n0 <<= prec; u = 2 * s; q = r / u; u = r - q * u; s = (s << prec) + q; u = (u << prec) + (n0 >> (BITS_IN_LONG - prec)); q = q * q; r = u - q; if (u < q) { s--; r += (s << 1) | 1; } n0 <<= prec; prec = 2 * prec; } *ps = s; *pr = r; } /* N[0..1], assume N[0] >= 2^(BIL-2). * Return 1 if remainder overflows, 0 otherwise */ static int p_sqrtu2(ulong *N, ulong *ps, ulong *pr) { ulong cc, qhl, r, s, q, u, n1 = N[1]; LOCAL_OVERFLOW; p_sqrtu1(N, &s, &r); /* r <= 2s */ qhl = 0; while (r >= s) { qhl++; r -= s; } /* now r < s < 2^(BIL/2) */ r = (r << BITS_IN_HALFULONG) | (n1 >> BITS_IN_HALFULONG); u = s << 1; q = r / u; u = r - q * u; q += (qhl & 1) << (BITS_IN_HALFULONG - 1); qhl >>= 1; /* (initial r)<<(BIL/2) + n1>>(BIL/2) = (qhl<<(BIL/2) + q) * 2s + u */ s = ((s + qhl) << BITS_IN_HALFULONG) + q; cc = u >> BITS_IN_HALFULONG; r = (u << BITS_IN_HALFULONG) | (n1 & LOWMASK); r = subll(r, q * q); cc -= overflow + qhl; /* now subtract 2*q*2^(BIL/2) + 2^BIL if qhl is set */ if ((long)cc < 0) { if (s) { r = addll(r, s); cc += overflow; s--; } else { cc++; s = ~0UL; } r = addll(r, s); cc += overflow; } *ps = s; *pr = r; return cc; } static void xmpn_zero(GEN x, long n) { while (--n >= 0) x[n]=0; } static void xmpn_copy(GEN z, GEN x, long n) { long k = n; while (--k >= 0) z[k] = x[k]; } /* a[0..la-1] * 2^(lb BIL) | b[0..lb-1] */ static GEN catii(GEN a, long la, GEN b, long lb) { long l = la + lb + 2; GEN z = cgetipos(l); xmpn_copy(LIMBS(z), a, la); xmpn_copy(LIMBS(z) + la, b, lb); return int_normalize(z, 0); } /* sqrt n[0..1], assume n normalized */ static GEN sqrtispec2(GEN n, GEN *pr) { ulong s, r; int hi = p_sqrtu2((ulong*)n, &s, &r); GEN S = utoi(s); *pr = hi? uutoi(1,r): utoi(r); return S; } /* sqrt n[0], _dont_ assume n normalized */ static GEN sqrtispec1_sh(GEN n, GEN *pr) { GEN S; ulong r, s, u0 = uel(n,0); int sh = bfffo(u0) & ~1UL; if (sh) u0 <<= sh; p_sqrtu1(&u0, &s, &r); /* s^2 + r = u0, s < 2^(BIL/2). Rescale back: * 2^(2k) n = S^2 + R * so 2^(2k) n = (S - s0)^2 + (2*S*s0 - s0^2 + R), s0 = S mod 2^k. */ if (sh) { int k = sh >> 1; ulong s0 = s & ((1L<>= k; r >>= sh; } S = utoi(s); if (pr) *pr = utoi(r); return S; } /* sqrt n[0..1], _dont_ assume n normalized */ static GEN sqrtispec2_sh(GEN n, GEN *pr) { GEN S; ulong U[2], r, s, u0 = uel(n,0), u1 = uel(n,1); int hi, sh = bfffo(u0) & ~1UL; if (sh) { u0 = (u0 << sh) | (u1 >> (BITS_IN_LONG-sh)); u1 <<= sh; } U[0] = u0; U[1] = u1; hi = p_sqrtu2(U, &s, &r); /* s^2 + R = u0|u1. Rescale back: * 2^(2k) n = S^2 + R * so 2^(2k) n = (S - s0)^2 + (2*S*s0 - s0^2 + R), s0 = S mod 2^k. */ if (sh) { int k = sh >> 1; ulong s0 = s & ((1L<>= k; r = (r>>sh) | (hiremainder << (BITS_IN_LONG-sh)); hi = (hiremainder & (1L<> 1; h = n - l; /* N = a3(h) | a2(h) | a1(l) | a0(l words) */ S = sqrtispec(N, h, &R); /* S^2 + R = a3|a2 */ z = catii(LIMBS(R), NLIMBS(R), N + 2*h, l); /* = R | a1(l) */ q = dvmdii(z, shifti(S,1), &u); z = catii(LIMBS(u), NLIMBS(u), N + n + h, l); /* = u | a0(l) */ S = addshiftw(S, q, l); R = subii(z, sqri(q)); if (signe(R) < 0) { GEN S2 = shifti(S,1); R = addis(subiispec(LIMBS(S2),LIMBS(R), NLIMBS(S2),NLIMBS(R)), -1); S = addis(S, -1); } *r = R; return S; } /* Return S (and set R) s.t S^2 + R = N, 0 <= R <= 2S. * As for dvmdii, R is last on stack and guaranteed to be gen_0 in case the * remainder is 0. R = NULL is allowed. */ GEN sqrtremi(GEN N, GEN *r) { pari_sp av; GEN S, R, n = N+2; long k, l2, ln = NLIMBS(N); int sh; if (ln <= 2) { if (ln == 2) return sqrtispec2_sh(n, r); if (ln == 1) return sqrtispec1_sh(n, r); if (r) *r = gen_0; return gen_0; } av = avma; sh = bfffo(n[0]) >> 1; l2 = (ln + 1) >> 1; if (sh || (ln & 1)) { /* normalize n, so that n[0] >= 2^BIL / 4 */ GEN s0, t = new_chunk(ln + 1); t[ln] = 0; if (sh) shift_left(t, n, 0,ln-1, 0, sh << 1); else xmpn_copy(t, n, ln); S = sqrtispec(t, l2, &R); /* t normalized, 2 * l2 words */ /* Rescale back: * 2^(2k) n = S^2 + R, k = sh + (ln & 1)*BIL/2 * so 2^(2k) n = (S - s0)^2 + (2*S*s0 - s0^2 + R), s0 = S mod 2^k. */ k = sh + (ln & 1) * (BITS_IN_LONG/2); s0 = remi2n(S, k); R = addii(shifti(R,-1), mulii(s0, S)); R = shifti(R, 1 - (k<<1)); S = shifti(S, -k); } else S = sqrtispec(n, l2, &R); if (!r) { avma = (pari_sp)S; return gerepileuptoint(av, S); } gerepileall(av, 2, &S, &R); *r = R; return S; } /* compute sqrt(|a|), assuming a != 0 */ #if 1 GEN sqrtr_abs(GEN x) { long l = realprec(x) - 2, e = expo(x), er = e>>1; GEN b, c, res = cgetr(2 + l); res[1] = evalsigne(1) | evalexpo(er); if (e&1) { b = new_chunk(l << 1); xmpn_copy(b, x+2, l); xmpn_zero(b + l,l); b = sqrtispec(b, l, &c); xmpn_copy(res+2, b+2, l); if (cmpii(c, b) > 0) roundr_up_ip(res, l+2); } else { ulong u; b = new_chunk(2 + (l << 1)); shift_left(b+1, x+2, 0,l-1, 0, BITS_IN_LONG-1); b[0] = uel(x,2)>>1; xmpn_zero(b + l+1,l+1); b = sqrtispec(b, l+1, &c); xmpn_copy(res+2, b+2, l); u = uel(b,l+2); if ( u&HIGHBIT || (u == ~HIGHBIT && cmpii(c,b) > 0)) roundr_up_ip(res, l+2); } avma = (pari_sp)res; return res; } #else /* use t_REAL: currently much slower (quadratic division) */ #ifdef LONG_IS_64BIT /* 64 bits of b = sqrt(a[0] * 2^64 + a[1]) [ up to 1ulp ] */ static ulong sqrtu2(ulong *a) { ulong c, b = dblmantissa( sqrt((double)a[0]) ); LOCAL_HIREMAINDER; LOCAL_OVERFLOW; /* > 32 correct bits, 1 Newton iteration to reach 64 */ if (b <= a[0]) return HIGHBIT | (a[0] >> 1); hiremainder = a[0]; c = divll(a[1], b); return (addll(c, b) >> 1) | HIGHBIT; } /* 64 bits of sqrt(a[0] * 2^63) */ static ulong sqrtu2_1(ulong *a) { ulong t[2]; t[0] = (a[0] >> 1); t[1] = (a[0] << (BITS_IN_LONG-1)) | (a[1] >> 1); return sqrtu2(t); } #else /* 32 bits of sqrt(a[0] * 2^32) */ static ulong sqrtu2(ulong *a) { return dblmantissa( sqrt((double)a[0]) ); } /* 32 bits of sqrt(a[0] * 2^31) */ static ulong sqrtu2_1(ulong *a) { return dblmantissa( sqrt(2. * a[0]) ); } #endif GEN sqrtr_abs(GEN x) { long l1, i, l = lg(x), ex = expo(x); GEN a, t, y = cgetr(l); pari_sp av, av0 = avma; a = rtor(x, l+1); t = cgetr(l+1); if (ex & 1) { /* odd exponent */ a[1] = evalsigne(1) | _evalexpo(1); t[2] = (long)sqrtu2((ulong*)a + 2); } else { /* even exponent */ a[1] = evalsigne(1) | _evalexpo(0); t[2] = (long)sqrtu2_1((ulong*)a + 2); } t[1] = evalsigne(1) | _evalexpo(0); for (i = 3; i <= l; i++) t[i] = 0; /* |x| = 2^(ex/2) a, t ~ sqrt(a) */ l--; l1 = 1; av = avma; while (l1 < l) { /* let t := (t + a/t)/2 */ l1 <<= 1; if (l1 > l) l1 = l; setlg(a, l1 + 2); setlg(t, l1 + 2); affrr(addrr(t, divrr(a,t)), t); shiftr_inplace(t, -1); avma = av; } affrr(t,y); shiftr_inplace(y, (ex>>1)); avma = av0; return y; } #endif /******************************************************************* * * * Base Conversion * * * *******************************************************************/ static void convi_dac(GEN x, ulong l, ulong *res) { pari_sp ltop=avma; ulong m; GEN x1,x2; if (l==1) { *res=itou(x); return; } m=l>>1; x1=dvmdii(x,powuu(1000000000UL,m),&x2); convi_dac(x1,l-m,res+m); convi_dac(x2,m,res); avma=ltop; } /* convert integer --> base 10^9 [not memory clean] */ ulong * convi(GEN x, long *l) { long lz, lx = lgefint(x); ulong *z; if (lx == 3 && uel(x,2) < 1000000000UL) { z = (ulong*)new_chunk(1); *z = x[2]; *l = 1; return z+1; } lz = 1 + (long)bit_accuracy_mul(lx, LOG10_2/9); z = (ulong*)new_chunk(lz); convi_dac(x,(ulong)lz,z); while (z[lz-1]==0) lz--; *l=lz; return z+lz; } pari-2.11.2/src/kernel/none/addll.h0000644000175000017500000000617413201017466015425 0ustar billbill#line 2 "../src/kernel/none/addll.h" /* Copyright (C) 2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file originally adapted from gmp-3.1.1 (from T. Granlund), files * longlong.h and gmp-impl.h Copyright (C) 2000 Free Software Foundation, Inc. */ #undef LOCAL_OVERFLOW #define LOCAL_OVERFLOW extern ulong overflow; #if !defined(INLINE) extern long addll(ulong x, ulong y); extern long addllx(ulong x, ulong y); extern long subll(ulong x, ulong y); extern long subllx(ulong x, ulong y); #else #if defined(__GNUC__) && !defined(DISABLE_INLINE) #undef LOCAL_OVERFLOW #define LOCAL_OVERFLOW register ulong overflow #define addll(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value = __arg1 + __arg2; \ overflow = (__value < __arg1); \ __value; \ }) #define addllx(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value, __tmp = __arg1 + overflow;\ overflow = (__tmp < __arg1); \ __value = __tmp + __arg2; \ overflow |= (__value < __tmp); \ __value; \ }) #define subll(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b); \ overflow = (__arg2 > __arg1); \ __arg1 - __arg2; \ }) #define subllx(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value, __tmp = __arg1 - overflow;\ overflow = (__arg1 < overflow); \ __value = __tmp - __arg2; \ overflow |= (__arg2 > __tmp); \ __value; \ }) #else /* __GNUC__ */ INLINE long addll(ulong x, ulong y) { const ulong z = x+y; overflow=(zx); return (long) z; } INLINE long subllx(ulong x, ulong y) { const ulong z = x-y-overflow; overflow = (z>x || (z==x && overflow)); return (long) z; } #endif /* __GNUC__ */ #endif pari-2.11.2/src/kernel/none/invmod.c0000644000175000017500000000776513326135265015651 0ustar billbill#line 2 "../src/kernel/none/invmod.c" /* Copyright (C) 2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*================================== * invmod(a,b,res) *================================== * If a is invertible, return 1, and set res = a^{ -1 } * Otherwise, return 0, and set res = gcd(a,b) * * This is sufficiently different from bezout() to be implemented separately * instead of having a bunch of extra conditionals in a single function body * to meet both purposes. */ #ifdef INVMOD_PARI INLINE int invmod_pari(GEN a, GEN b, GEN *res) #else int invmod(GEN a, GEN b, GEN *res) #endif { GEN v,v1,d,d1,q,r; pari_sp av, av1; long s; ulong g; ulong xu,xu1,xv,xv1; /* Lehmer stage recurrence matrix */ int lhmres; /* Lehmer stage return value */ if (!signe(b)) { *res=absi(a); return 0; } av = avma; if (lgefint(b) == 3) /* single-word affair */ { ulong d1 = umodiu(a, uel(b,2)); if (d1 == 0) { if (b[2] == 1L) { *res = gen_0; return 1; } else { *res = absi(b); return 0; } } g = xgcduu(uel(b,2), d1, 1, &xv, &xv1, &s); avma = av; if (g != 1UL) { *res = utoipos(g); return 0; } xv = xv1 % uel(b,2); if (s < 0) xv = uel(b,2) - xv; *res = utoipos(xv); return 1; } (void)new_chunk(lgefint(b)); d = absi_shallow(b); d1 = modii(a,d); v=gen_0; v1=gen_1; /* general case */ av1 = avma; while (lgefint(d) > 3 && signe(d1)) { lhmres = lgcdii((ulong*)d, (ulong*)d1, &xu, &xu1, &xv, &xv1, ULONG_MAX); if (lhmres != 0) /* check progress */ { /* apply matrix */ if (lhmres == 1 || lhmres == -1) { if (xv1 == 1) { r = subii(d,d1); d=d1; d1=r; a = subii(v,v1); v=v1; v1=a; } else { r = subii(d, mului(xv1,d1)); d=d1; d1=r; a = subii(v, mului(xv1,v1)); v=v1; v1=a; } } else { r = subii(muliu(d,xu), muliu(d1,xv)); a = subii(muliu(v,xu), muliu(v1,xv)); d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r; v1 = subii(muliu(v,xu1), muliu(v1,xv1)); v = a; if (lhmres&1) { togglesign(d); togglesign(v); } else { togglesign(d1); togglesign(v1); } } } if (lhmres <= 0 && signe(d1)) { q = dvmdii(d,d1,&r); a = subii(v,mulii(q,v1)); v=v1; v1=a; d=d1; d1=r; } if (gc_needed(av,1)) { if(DEBUGMEM>1) pari_warn(warnmem,"invmod"); gerepileall(av1, 4, &d,&d1,&v,&v1); } } /* end while */ /* Postprocessing - final sprint */ if (signe(d1)) { /* Assertions: lgefint(d)==lgefint(d1)==3, and * gcd(d,d1) is nonzero and fits into one word */ g = xxgcduu(uel(d,2), uel(d1,2), 1, &xu, &xu1, &xv, &xv1, &s); if (g != 1UL) { avma = av; *res = utoipos(g); return 0; } /* (From the xgcduu() blurb:) * For finishing the multiword modinv, we now have to multiply the * returned matrix (with properly adjusted signs) onto the values * v' and v1' previously obtained from the multiword division steps. * Actually, it is sufficient to take the scalar product of [v',v1'] * with [u1,-v1], and change the sign if s==1. */ v = subii(muliu(v,xu1),muliu(v1,xv1)); if (s > 0) setsigne(v,-signe(v)); avma = av; *res = modii(v,b); return 1; } /* get here when the final sprint was skipped (d1 was zero already) */ avma = av; if (!equalii(d,gen_1)) { *res = icopy(d); return 0; } *res = modii(v,b); return 1; } pari-2.11.2/src/kernel/none/cmp.c0000644000175000017500000000704713201017466015117 0ustar billbill#line 2 "../src/kernel/none/cmp.c" /* Copyright (C) 2002-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /********************************************************************/ /** **/ /** Comparison routines **/ /** **/ /********************************************************************/ /*They depend on cmpiispec and equaliispec in mp.c*/ int equalii(GEN x, GEN y) { if ((x[1] & (LGBITS|SIGNBITS)) != (y[1] & (LGBITS|SIGNBITS))) return 0; return equaliispec(x+2, y+2, lgefint(x)-2, lgefint(y)-2); } int cmpii(GEN x, GEN y) { const long sx = signe(x), sy = signe(y); if (sxsy) return 1; if (!sx) return 0; if (sx>0) return cmpiispec(x+2, y+2, lgefint(x)-2, lgefint(y)-2); else return -cmpiispec(x+2, y+2, lgefint(x)-2, lgefint(y)-2); } int equalrr(GEN x, GEN y) { long lx, ly, i; if (!signe(x)) { if (!signe(y)) return 1; /* all zeroes are equal */ return expo(x) >= expo(y); } if (!signe(y)) return expo(y) >= expo(x); if (x[1] != y[1]) return 0; lx = lg(x); ly = lg(y); if (lx < ly) { i=2; while (i= expo(y)) return 0; return sy > 0? -1: 1; } if (!sy) { if (expo(y) >= expo(x)) return 0; return sx > 0? 1: -1; } if (sxsy) return 1; ex=expo(x); ey=expo(y); if (ex>ey) return sx; if (ex (ulong)y[i]) ? sx : -sx; if (lx>=ly) { while (iey) return 1; if (ex (ulong)y[i])? 1: -1; if (lx>=ly) { while (i.h to supplement whatever is provided by asm0.h. CAVEAT: if bfffo and divll are both mentioned, they must appear in this order (divll depends on bfffo). * Inline Level 1 symbols, in mpinl.o: the definitions are in none/level1.h. Inlining may or may not be possible, but a symbol must be defined in mpinl.o in any case. * Non-Inline Level 1 symbols, defined in mp.o: the definitions are in various *.c files in none/ and gmp/ concatenated into $objdir/mp.c. pari-2.11.2/src/kernel/ia64/0000755000175000017500000000000013461316051013770 5ustar billbillpari-2.11.2/src/kernel/ia64/asm0.h0000644000175000017500000000521213036414402014776 0ustar billbill#line 2 "../src/kernel/ia64/asm0.h" /* Copyright (C) 2006 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM mulll bfffo NOASM addll divll */ #ifdef ASMINLINE /* Written by Guillaume Hanrot */ #define LOCAL_HIREMAINDER register ulong hiremainder #define bfffo(a) \ __extension__ ({ ulong __arg1 = (a), __tmp, _a, _c; \ __asm__ ("mux1 %0 = %1, @rev" : "=r" (__tmp) : "r" (__arg1)); \ __asm__ ("czx1.l %0 = %1" : "=r" (_a) : "r" (-__tmp | __tmp)); \ _c = (_a - 1) << 3; \ __arg1 >>= _c; \ if (__arg1 >= 1 << 4) \ __arg1 >>= 4, _c += 4; \ if (__arg1 >= 1 << 2) \ __arg1 >>= 2, _c += 2; \ _c += __arg1 >> 1; \ 63 - _c; \ }) #define mulll(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value; \ __asm__ ("xma.hu %0 = %2, %3, f0\n\t;;\n\txma.l %1 = %2, %3, f0" \ : "=&f" (hiremainder), "=f" (__value) \ : "f" (__arg1), "f" (__arg2)); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value; \ __asm__ ("xma.hu %0 = %2, %3, %4\n\txma.l %1 = %2, %3, %4" \ : "=&f" (hiremainder), "=f" (__value) \ : "f" (__arg1), "f" (__arg2), "f" (hiremainder)); \ __value; \ }) #endif pari-2.11.2/src/kernel/ia64/asm1.h0000644000175000017500000000406111636712103015003 0ustar billbill/* Extracted from gmp-4.1.2 * FIXME: This file is unused until somebody implements * invert_word(x) = return floor( 2^(2*BIL)/x ) */ extern ulong invert_word(ulong); #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __extension__ ({ \ ulong __x; \ __x = (al) - (bl); \ (sh) = (ah) - (bh) - (__x > (al)); \ (sl) = __x; \ }) #define divll(x, y) \ __extension__ ({ \ register ulong _di, _x = (x), _y = (y), _q, _ql, _r; \ register ulong _xh, _xl, _k, __hire; \ \ if (_y & 0x8000000000000000UL) \ { _k = 0; __hire = hiremainder; } \ else \ { \ _k = bfffo(_y); \ __hire = (hiremainder << _k) | (_x >> (64 - _k)); \ _x <<= _k; _y <<= _k; \ } \ _di = invert_word(_y); \ _ql = mulll (__hire, _di); \ _q = __hire + hiremainder; \ _xl = mulll(_q, _y); _xh = hiremainder; \ sub_ddmmss (_xh, _r, __hire, _x, _xh, _xl); \ if (_xh != 0) \ { \ sub_ddmmss (_xh, _r, _xh, _r, 0, _y); _q += 1; \ if (_xh != 0) \ { sub_ddmmss (_xh, _r, _xh, _r, 0, _y); _q += 1; } \ } \ if (_r >= _y) \ { _r -= _y; _q += 1; } \ hiremainder = _r >> _k; \ _q; \ }) pari-2.11.2/src/kernel/hppa/0000755000175000017500000000000013461316051014155 5ustar billbillpari-2.11.2/src/kernel/hppa/asm0.h0000644000175000017500000000541713036414402015172 0ustar billbill#line 2 "../src/kernel/hppa/asm0.h" /* Copyright (C) 2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file was made using idea from Bruno Haible ix86 asm inline kernel * and code from Nigel Smart hppa asm kernel. mulll was inspired from * longlong.h from the GNU MP package.*/ /* ASM addll mulll NOASM bfffo divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("add %2,%3,%0\n\taddc %%r0,%%r0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2) \ : "cc"); \ __value; \ }) #define addllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("sub %4,%5,%%r0\n\taddc %2,%3,%0\n\taddc %%r0,%%r0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow), "r" ((ulong) 1)\ : "cc"); \ __value; \ }) #define subll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("sub %2,%3,%0\n\taddc %%r0,%%r0,%1\n\tsubi 1,%1,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2) \ : "cc"); \ __value; \ }) #define subllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("sub %%r0,%4,%%r0\n\tsubb %2,%3,%0\n\taddc %%r0,%%r0,%1\n\tsubi 1,%1,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow)\ : "cc"); \ __value; \ }) #define mulll(a,b) \ __extension__ ({ ulong __arg1 = (a), __arg2 = (b); \ union {double z; ulong x[2];} __vtab; \ __asm__ ("xmpyu %1,%2,%0" \ : "=f" (__vtab.z) \ : "f" (__arg1), "f" (__arg2) \ : "cc"); \ hiremainder=__vtab.x[0]; \ __vtab.x[1]; \ }) #define addmul(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ union {double z; ulong x[2];} __vtab; \ __asm__ ("xmpyu %1,%2,%0" \ : "=f" (__vtab.z) \ : "f" (__arg1), "f" (__arg2) \ : "cc"); \ __asm__ ("add %2,%3,%0\n\taddc %%r0, %4, %1" \ : "=&r" (__value), "=r" (hiremainder) \ : "r" (__vtab.x[1]),"r" (hiremainder), "r" (__vtab.x[0]) \ : "cc"); \ __value; \ }) #endif pari-2.11.2/src/kernel/hppa64/0000755000175000017500000000000013461316051014327 5ustar billbillpari-2.11.2/src/kernel/hppa64/asm0.h0000644000175000017500000001000213036414402015326 0ustar billbill#line 2 "../src/kernel/hppa64/asm0.h" /* Copyright (C) 2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file was made using idea from Bruno Haible ix86 asm inline kernel * and code from Nigel Smart hppa asm kernel. mulll was inspired from * longlong.h from the GNU MP package.*/ /* ASM addll mulll NOASM bfffo divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("add %2,%3,%0\n\tadd,dc %%r0,%%r0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2) \ : "cc"); \ __value; \ }) #define addllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("sub %4,%5,%%r0\n\tadd,dc %2,%3,%0\n\tadd,dc %%r0,%%r0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow), "r" ((ulong) 1)\ : "cc"); \ __value; \ }) #define subll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("sub %2,%3,%0\n\tadd,dc %%r0,%%r0,%1\n\tsubi 1,%1,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2) \ : "cc"); \ __value; \ }) #define subllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("sub %%r0,%4,%%r0\n\tsub,db %2,%3,%0\n\tadd,dc %%r0,%%r0,%1\n\tsubi 1,%1,%1" \ : "=&r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow)\ : "cc"); \ __value; \ }) /* z=a+b; c+= carry; return z */ #define __addllc(a,b,c) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("add %2,%3,%0\n\tadd,dc %4,%%r0,%1" \ : "=&r" (__value), "=r" (c) \ : "r" (__arg1), "r" (__arg2), "r" (c) \ : "cc"); \ __value; \ }) /* 32x32->64 multiply*/ #define __mulhh(a,b) \ __extension__ ({ unsigned int __arg1 = (a), __arg2 = (b); \ ulong __value; \ __asm__ ("xmpyu %1,%2,%0" \ : "=f" (__value) \ : "f" (__arg1), "f" (__arg2) \ : "cc"); \ __value; \ }) #define mulll(arg1,arg2) \ __extension__ ({ \ const ulong __x=(arg1), __y=(arg2); \ const ulong __xlo = LOWWORD(__x), __xhi = HIGHWORD(__x); \ const ulong __ylo = LOWWORD(__y), __yhi = HIGHWORD(__y); \ ulong __xylo,__xymid,__xyhi,__xymidhi,__xymidlo; \ ulong __xylh,__xyhl; \ __xylo = __mulhh(__xlo,__ylo); __xyhi = __mulhh(__xhi,__yhi); \ __xylh = __mulhh(__xlo,__yhi); __xyhl = __mulhh(__xhi,__ylo); \ __xymid = __xylh+__xyhl; \ if (__xymid<__xylh) __xyhi += (1UL << BITS_IN_HALFULONG); \ __xymidhi = HIGHWORD(__xymid); \ __xymidlo = __xymid << BITS_IN_HALFULONG; \ __xylo = __addllc(__xylo,__xymidlo,__xyhi); \ hiremainder = __xyhi + __xymidhi; \ __xylo; \ }) #define addmul(arg1,arg2) \ __extension__ ({ \ const ulong __x=(arg1), __y=(arg2); \ const ulong __xlo = LOWWORD(__x), __xhi = HIGHWORD(__x); \ const ulong __ylo = LOWWORD(__y), __yhi = HIGHWORD(__y); \ ulong __xylo,__xymid,__xyhi,__xymidhi,__xymidlo; \ ulong __xylh,__xyhl; \ __xylo = __mulhh(__xlo,__ylo); __xyhi = __mulhh(__xhi,__yhi); \ __xylh = __mulhh(__xlo,__yhi); __xyhl = __mulhh(__xhi,__ylo); \ __xymid = __xylh+__xyhl; \ if (__xymid<__xylh) __xyhi += (1UL << BITS_IN_HALFULONG); \ __xylo = __addllc(__xylo,hiremainder,__xyhi); \ __xymidhi = HIGHWORD(__xymid); \ __xymidlo = __xymid << BITS_IN_HALFULONG; \ __xylo = __addllc(__xylo,__xymidlo,__xyhi); \ hiremainder = __xyhi + __xymidhi; \ __xylo; \ }) #endif pari-2.11.2/src/kernel/ppc64/0000755000175000017500000000000013461316051014161 5ustar billbillpari-2.11.2/src/kernel/ppc64/asm0.h0000644000175000017500000000502513036414402015171 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM addll mulll bfffo NOASM divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("addc %0,%2,%3\n\txor %1,%2,%2\n\taddze %1,%4\n\t" \ : "=&r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "1" ((ulong) 0)); \ __value; \ }) #define addllx(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("addc %0,%3,%4\n\tli %1,0\n\taddze %1,%4\n\taddc %0,%2,%5\n\taddze %1,%4\n\t" \ : "=&r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "1" (overflow), "0" ((ulong) 0)); \ __value; \ }) #define bfffo(a) \ __extension__ ({ ulong __a = (a), __value; \ __asm__ ("cntlzd %0, %1" : "=r" (__value) : "r" (__a)); \ __value; \ }) #define subll(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subfc %0,%3,%2\n\tli %1,0\n\taddme %1,%4\n\tneg %1,%4" \ : "=&r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "1" ((ulong)0)); \ __value; \ }) #define subllx(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subfc %0,%5,%2\n\tli %1,0\n\taddme %1,%5\n\tsubfc %0,%3,%4\n\taddme %1,%5\n\tneg %1,%5" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "0" ((ulong)0), "1" (overflow)); \ __value; \ }) #define mulll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("mulhdu %1,%2,%3\n\tmulld %0,%2,%3\n\t" \ : "=r" (__value), "=&r" (hiremainder) \ : "r" (__arg1), "r" (__arg2)); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("mulld %0,%3,%4\n\tmulhdu %2,%3,%4\n\taddc %0,%5,%6\n\taddze %1,%7\n\t" \ : "=&r" (__value), "=r" (hiremainder), "=r" (__temp) \ : "r" (__arg1), "r" (__arg2), "0" ((ulong) 0), "1" (hiremainder), "2" ((ulong) 0)); \ __value; \ }) #endif pari-2.11.2/src/kernel/sparcv8_micro/0000755000175000017500000000000013461316051016004 5ustar billbillpari-2.11.2/src/kernel/sparcv8_micro/MakeLVL0.SH0000644000175000017500000000020411636712103017547 0ustar billbillcat >> $file << EOT parilvl0.h: $kern0/asm0-common.h \$(L0MODS) $cfg/genkernel $kern0/asm0-common.h $kern0/asm0.h > parilvl0.h EOT pari-2.11.2/src/kernel/sparcv8_micro/asm0.h0000644000175000017500000000170513036414402017015 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM divll */ #ifdef ASMINLINE #define divll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __tmp; \ __asm__( "mov %1, %%y; nop;nop;nop;\n\t\ udivcc %3,%4,%0;\n\tumul %0,%4,%2;\n\tsub %3,%2,%1"\ : "=&r" (__value), "=&r" (hiremainder), "=&r" (__tmp) \ : "r" (__arg1), "r" (__arg2), "1" (hiremainder) \ : "cc"); \ __value;}) #endif pari-2.11.2/src/kernel/sparcv8_micro/asm0-common.h0000644000175000017500000000476313036414402020312 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file is common to SuperSparc and MicroSparc */ /* ASM addll mulll NOASM bfffo */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER ulong hiremainder #define LOCAL_OVERFLOW ulong overflow #define addll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ( "addcc %2,%3,%0; \ addx %%g0,%%g0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2) \ : "cc"); \ __value; }) #define addllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ( "subcc %%g0,%1,%%g0; \ addxcc %2,%3,%0; \ addx %%g0,%%g0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "1" (overflow) \ : "cc"); \ __value; }) #define subll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ( "subcc %2,%3,%0; \ addx %%g0,%%g0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2) \ : "cc"); \ __value; }) #define subllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ( "subcc %%g0,%1,%%g0; \ subxcc %2,%3,%0; \ addx %%g0,%%g0,%1" \ : "=r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "1" (overflow) \ : "cc"); \ __value; }) #define mulll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ( "umul %2,%3,%0; \ rd %%y,%1" \ : "=r" (__value), "=r" (hiremainder) \ : "r" (__arg1), "r" (__arg2)); \ __value;}) #define addmul(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __tmp; \ __asm__ ( "umul %3,%4,%0; \ rd %%y,%2; \ addcc %0,%1,%0; \ addx %%g0,%2,%1" \ : "=&r" (__value), "=&r" (hiremainder), "=&r" (__tmp) \ : "r" (__arg1), "r" (__arg2), "1" (hiremainder) \ : "cc"); \ __value;}) #endif pari-2.11.2/src/kernel/x86_64/0000755000175000017500000000000013461316051014163 5ustar billbillpari-2.11.2/src/kernel/x86_64/asm0.h0000644000175000017500000001154513036414402015177 0ustar billbill#line 2 "../src/kernel/x86-64/asm0.h" /* Copyright (C) 2004 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM addll mulll bfffo divll */ /* Written by Bill Allombert from the ix86 version by Bruno Haible. Basically * change insl to insq*/ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("addq %3,%0 ; adcq %1,%1" \ : "=r" (__value), "=r" (overflow) \ : "0" (__arg1), "g" (__arg2), "1" ((ulong)0) \ : "cc"); \ __value; \ }) #define addllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("subq %5,%2 ; adcq %4,%0 ; adcq %1,%1" \ : "=r" (__value), "=&r" (overflow), "=&r" (__temp) \ : "0" (__arg1), "g" (__arg2), "g" (overflow), "1" ((ulong)0), "2" ((ulong)0) \ : "cc"); \ __value; \ }) #define addllx8(a,b,c,overflow) \ do { long *__arg1 = a, *__arg2 = b, *__out = c; \ ulong __temp; \ __asm__ ("subq %5, %0 \n\t" \ "movq (%2), %0 ; adcq (%3),%0; movq %0, (%4) \n\t" \ "movq -8(%2), %0 ; adcq -8(%3),%0; movq %0, -8(%4) \n\t" \ "movq -16(%2), %0 ; adcq -16(%3),%0; movq %0, -16(%4) \n\t" \ "movq -24(%2), %0 ; adcq -24(%3),%0; movq %0, -24(%4) \n\t" \ "movq -32(%2), %0 ; adcq -32(%3),%0; movq %0, -32(%4) \n\t" \ "movq -40(%2), %0 ; adcq -40(%3),%0; movq %0, -40(%4) \n\t" \ "movq -48(%2), %0 ; adcq -48(%3),%0; movq %0, -48(%4) \n\t" \ "movq -56(%2), %0 ; adcq -56(%3),%0; movq %0, -56(%4) \n\t" \ "adcq %1, %1" \ : "=&r" (__temp), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (__out), "g" (overflow), "0" ((ulong)0), "1" ((ulong)0) \ : "cc"); \ } while(0) #define subll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subq %3,%0 ; adcq %1,%1" \ : "=r" (__value), "=r" (overflow) \ : "0" (__arg1), "g" (__arg2), "1" ((ulong)0) \ : "cc"); \ __value; \ }) #define subllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("subq %5,%2 ; sbbq %4,%0 ; adcq %1,%1" \ : "=r" (__value), "=&r" (overflow), "=&r" (__temp) \ : "0" (__arg1), "g" (__arg2), "g" (overflow), "1" ((ulong)0), "2" ((ulong)0) \ : "cc"); \ __value; \ }) #define subllx8(a,b,c,overflow) \ do { long *__arg1 = a, *__arg2 = b, *__out = c; \ ulong __temp; \ __asm__ ("subq %5, %0 \n\t" \ "movq (%2), %0 ; sbbq (%3),%0; movq %0, (%4) \n\t" \ "movq -8(%2), %0 ; sbbq -8(%3),%0; movq %0, -8(%4) \n\t" \ "movq -16(%2), %0 ; sbbq -16(%3),%0; movq %0, -16(%4) \n\t" \ "movq -24(%2), %0 ; sbbq -24(%3),%0; movq %0, -24(%4) \n\t" \ "movq -32(%2), %0 ; sbbq -32(%3),%0; movq %0, -32(%4) \n\t" \ "movq -40(%2), %0 ; sbbq -40(%3),%0; movq %0, -40(%4) \n\t" \ "movq -48(%2), %0 ; sbbq -48(%3),%0; movq %0, -48(%4) \n\t" \ "movq -56(%2), %0 ; sbbq -56(%3),%0; movq %0, -56(%4) \n\t" \ "adcq %1, %1" \ : "=&r" (__temp), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (__out), "g" (overflow), "0" ((ulong)0), "1" ((ulong)0) \ : "cc"); \ } while(0) #define mulll(a,b) \ __extension__ ({ ulong __valuelo, __arg1 = (a), __arg2 = (b); \ __asm__ ("mulq %3" \ : "=a" /* %eax */ (__valuelo), "=d" /* %edx */ (hiremainder) \ : "0" (__arg1), "rm" (__arg2)); \ __valuelo; \ }) #define addmul(a,b) \ __extension__ ({ ulong __valuelo, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("mulq %4 ; addq %5,%0 ; adcq %6,%1" \ : "=a" /* %eax */ (__valuelo), "=&d" /* %edx */ (hiremainder), "=r" (__temp) \ : "0" (__arg1), "rm" (__arg2), "g" (hiremainder), "2" ((ulong)0)); \ __valuelo; \ }) #define divll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("divq %4" \ : "=a" /* %eax */ (__value), "=d" /* %edx */ (hiremainder) \ : "0" /* %eax */ (__arg1), "1" /* %edx */ (hiremainder), "mr" (__arg2)); \ __value; \ }) #define bfffo(x) \ __extension__ ({ ulong __arg = (x); \ long leading_one_position; \ __asm__ ("bsrq %1,%0" : "=r" (leading_one_position) : "rm" (__arg)); \ 63 - leading_one_position; \ }) #endif pari-2.11.2/src/kernel/alpha/0000755000175000017500000000000013461316051014312 5ustar billbillpari-2.11.2/src/kernel/alpha/asm0.h0000644000175000017500000000477513036414402015335 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM addll mulll NOASM bfffo divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("addq %2,%3,%0\n\tcmpult %4,%2,%1" \ : "=&r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "0" ((ulong) 0)); \ __value; \ }) #define addllx(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("addq %3,%4,%0\n\tcmpult %5,%3,%2\n\taddq %5,%6,%0\n\tcmpult %5,%6,%1\n\taddq %6,%7,%1\n\t" \ : "=&r" (__value), "=r" (overflow), "=r" (__temp) \ : "r" (__arg1), "r" (__arg2), "0" ((ulong) 0), "1" (overflow), "2" ((ulong) 0)); \ __value; \ }) #define subll(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subq %2,%3,%0\n\tcmpult %2,%4,%1" \ : "=&r" (__value), "=r" (overflow) \ : "r" (__arg1), "r" (__arg2), "0" ((ulong)0)); \ __value; \ }) #define subllx(a, b)\ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp1, __temp2; \ __asm__ ("subq %4,%5,%2\n\tcmpult %4,%8,%3\n\tsubq %8,%7,%0\n\tcmpult %8,%6,%1\n\taddq %7,%9,%1\n\t" \ : "=r" (__value), "=r" (overflow), "=&r" (__temp1), "=r" (__temp2) \ : "r" (__arg1), "r" (__arg2), "0" ((ulong)0), "1" (overflow), "2" ((ulong)0), "3" ((ulong)0)); \ __value; \ }) #define mulll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("umulh %2,%3,%1\n\tmulq %2,%3,%0\n\t" \ : "=r" (__value), "=&r" (hiremainder) \ : "r" (__arg1), "r" (__arg2)); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("mulq %3,%4,%0\n\tumulh %3,%4,%2\n\taddq %5,%6,%0\n\tcmpult %5,%6,%1\n\taddq %7,%6,%1\n\t" \ : "=&r" (__value), "=r" (hiremainder), "=r" (__temp) \ : "r" (__arg1), "r" (__arg2), "0" ((ulong) 0), "1" (hiremainder), "2" ((ulong) 0)); \ __value; \ }) #endif pari-2.11.2/src/kernel/alpha/asm1.h0000644000175000017500000000705613201017466015334 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file is a slight adaptation of source code extracted from gmp-3.1.1 (from T. Granlund), files longlong.h and gmp-impl.h Copyright (C) 2000 Free Software Foundation, Inc. * FIXME: This file is unused until somebody implements * invert_word(x) = return floor( 2^(2*BIL)/x ) */ extern ulong invert_word(ulong); #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ ulong __x; \ __x = (al) - (bl); \ (sh) = (ah) - (bh) - (__x > (al)); \ (sl) = __x; \ } while (0) #ifdef __GNUC__ #define divll(x, y) \ __extension__ ({ \ register ulong _di, _x = (x), _y = (y), _q, _ql, _r; \ register ulong _xh, _xl, _k, __hire; \ \ if (_y & 0x8000000000000000UL) \ { _k = 0; __hire = hiremainder; } \ else \ { \ _k = bfffo(_y); \ __hire = (hiremainder << _k) | (_x >> (64 - _k)); \ _x <<= _k; _y <<= _k; \ } \ _di = invert_word(_y); \ _ql = mulll (__hire, _di); \ _q = __hire + hiremainder; \ _xl = mulll(_q, _y); _xh = hiremainder; \ sub_ddmmss (_xh, _r, __hire, _x, _xh, _xl); \ if (_xh != 0) \ { \ sub_ddmmss (_xh, _r, _xh, _r, 0, _y); _q += 1; \ if (_xh != 0) \ { sub_ddmmss (_xh, _r, _xh, _r, 0, _y); _q += 1; } \ } \ if (_r >= _y) \ { _r -= _y; _q += 1; } \ hiremainder = _r >> _k; \ _q; \ }) #else /* __GNUC__ */ static ulong divll(ulong x, ulong y) { register ulong _di, _x = (x), _y = (y), _q, _ql, _r; register ulong _xh, _xl, _k, __hire; if (_y & 0x8000000000000000UL) { _k = 0; __hire = hiremainder; } else { _k = bfffo(_y); __hire = (hiremainder << _k) | (_x >> (64 - _k)); _x <<= _k; _y <<= _k; } _di = invert_word(_y); _ql = mulll (__hire, _di); _q = __hire + hiremainder; _xl = mulll(_q, _y); _xh = hiremainder; sub_ddmmss (_xh, _r, __hire, _x, _xh, _xl); if (_xh != 0) { sub_ddmmss (_xh, _r, _xh, _r, 0, _y); _q += 1; if (_xh != 0) { sub_ddmmss (_xh, _r, _xh, _r, 0, _y); _q += 1; } } if (_r >= _y) { _r -= _y; _q += 1; } hiremainder = _r >> _k; return _q; } #endif /* __GNUC__ */ pari-2.11.2/src/kernel/m68k/0000755000175000017500000000000013461316051014012 5ustar billbillpari-2.11.2/src/kernel/m68k/asm0.h0000644000175000017500000001201113036414402015013 0ustar billbill#line 2 "../src/kernel/m68k/asm0.h" /* Copyright (C) 2006 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Written by Bill Allombert and dedicated to thoses who wrote the original * m68k kernel mp.s */ /* ASM addll mulll bfffo divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("add.l %2,%0 ; addx.l %1,%1" \ : "=&d" (__value), "=d" (overflow) \ : "rm" (__arg1), "0" (__arg2), "1" (0UL) \ : "cc"); \ __value; \ }) #define addllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("neg.l %2 ; addx.l %4,%0 ; addx.l %1,%1" \ : "=d" (__value), "=d" (overflow), "=d" (__temp) \ : "0" (__arg1), "d" (__arg2), "2" (overflow), "1" (0UL) \ : "cc"); \ __value; \ }) #define subll(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("sub.l %3,%0 ; addx.l %1,%1" \ : "=&d" (__value), "=d" (overflow) \ : "0" (__arg1), "rm" (__arg2), "1" (0UL) \ : "cc"); \ __value; \ }) #define subllx(a,b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("neg.l %2 ; subx.l %4,%0 ; addx.l %1,%1" \ : "=d" (__value), "=d" (overflow), "=d" (__temp) \ : "0" (__arg1), "d" (__arg2), "2" (overflow), "1" (0UL) \ : "cc"); \ __value; \ }) #define mulll(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value; \ __asm__ ("mulu.l %2, %0:%1" \ : "=d" (hiremainder), "=d" (__value) \ : "md" (__arg1) , "1" (__arg2) \ : "cc"); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value; \ __asm__ ("mulu.l %2, %0:%1; add.l %4,%1; addx.l %5,%0" \ : "=&d" (hiremainder), "=&d" (__value) \ : "md" (__arg1), "1" (__arg2), "d" (hiremainder), "d" (0UL) \ : "cc" ); \ __value; \ }) #define bfffo(a) \ __extension__ ({ \ ulong __arg1 = (a), __value; \ __asm__ ("bfffo %1{#0:#0}, %0" \ : "=d" (__value) \ : "md" (__arg1) \ : "cc" ); \ __value; \ }) #define divll(a, b) \ __extension__ ({ \ ulong __arg2 = (b), __value =(a); \ __asm__ ("divu.l %2, %0:%1" \ : "+d" (hiremainder), "+d" (__value) \ : "md" (__arg2) \ : "cc"); \ __value; \ }) #endif pari-2.11.2/src/kernel/gmp/0000755000175000017500000000000013461316051014010 5ustar billbillpari-2.11.2/src/kernel/gmp/tune.h0000644000175000017500000001440413326135265015145 0ustar billbill#ifdef LONG_IS_64BIT #define __AGM_ATAN_LIMIT 60 #define __DIVRR_GMP_LIMIT 4 #define __EXPNEWTON_LIMIT 66 #define __F2x_MUL_KARATSUBA_LIMIT 15 #define __F2xqX_BARRETT_LIMIT 48 #define __F2xqX_DIVREM_BARRETT_LIMIT 292 #define __F2xqX_INVBARRETT_LIMIT 46 #define __F2xqX_REM_BARRETT_LIMIT 292 #define __Flx_BARRETT_HALFMULII_LIMIT 21 #define __Flx_BARRETT_KARATSUBA_LIMIT 1172 #define __Flx_BARRETT_MULII2_LIMIT 16 #define __Flx_BARRETT_MULII_LIMIT 448 #define __Flx_BARRETT_QUARTMULII_LIMIT 23 #define __Flx_DIVREM_BARRETT_LIMIT 768 #define __Flx_EXTGCD_LIMIT 241 #define __Flx_GCD_LIMIT 1017 #define __Flx_HALFGCD_HALFMULII_LIMIT 48 #define __Flx_HALFGCD_KARATSUBA_LIMIT 77 #define __Flx_HALFGCD_MULII2_LIMIT 25 #define __Flx_HALFGCD_MULII_LIMIT 71 #define __Flx_HALFGCD_QUARTMULII_LIMIT 52 #define __Flx_INVBARRETT_HALFMULII_LIMIT 231 #define __Flx_INVBARRETT_KARATSUBA_LIMIT 5067 #define __Flx_INVBARRETT_MULII2_LIMIT 26 #define __Flx_INVBARRETT_MULII_LIMIT 1154 #define __Flx_INVBARRETT_QUARTMULII_LIMIT 139 #define __Flx_MUL_HALFMULII_LIMIT 5 #define __Flx_MUL_KARATSUBA_LIMIT 142 #define __Flx_MUL_MULII2_LIMIT 5 #define __Flx_MUL_MULII_LIMIT 7 #define __Flx_MUL_QUARTMULII_LIMIT 5 #define __Flx_REM_BARRETT_LIMIT 1266 #define __Flx_SQR_HALFSQRI_LIMIT 3 #define __Flx_SQR_KARATSUBA_LIMIT 316 #define __Flx_SQR_QUARTSQRI_LIMIT 3 #define __Flx_SQR_SQRI2_LIMIT 7 #define __Flx_SQR_SQRI_LIMIT 5 #define __FlxqX_BARRETT_LIMIT 17 #define __FlxqX_DIVREM_BARRETT_LIMIT 46 #define __FlxqX_EXTGCD_LIMIT 44 #define __FlxqX_GCD_LIMIT 470 #define __FlxqX_HALFGCD_LIMIT 60 #define __FlxqX_INVBARRETT_LIMIT 22 #define __FlxqX_REM_BARRETT_LIMIT 48 #define __FpXQX_BARRETT_LIMIT 12 #define __FpXQX_DIVREM_BARRETT_LIMIT 30 #define __FpXQX_EXTGCD_LIMIT 28 #define __FpXQX_GCD_LIMIT 191 #define __FpXQX_HALFGCD_LIMIT 35 #define __FpXQX_INVBARRETT_LIMIT 40 #define __FpXQX_REM_BARRETT_LIMIT 30 #define __FpX_BARRETT_LIMIT 38 #define __FpX_DIVREM_BARRETT_LIMIT 113 #define __FpX_EXTGCD_LIMIT 87 #define __FpX_GCD_LIMIT 406 #define __FpX_HALFGCD_LIMIT 58 #define __FpX_INVBARRETT_LIMIT 111 #define __FpX_REM_BARRETT_LIMIT 111 #define __Fp_POW_BARRETT_LIMIT 127 #define __Fp_POW_REDC_LIMIT 17 #define __INVMOD_GMP_LIMIT 3 #define __INVNEWTON_LIMIT 75 #define __LOGAGMCX_LIMIT 22 #define __LOGAGM_LIMIT 6 #define __MULII_FFT_LIMIT -1 #define __MULII_KARATSUBA_LIMIT -1 #define __MULRR_MULII_LIMIT 55 #define __RgX_MUL_LIMIT 9 #define __RgX_SQR_LIMIT 38 #define __SQRI_FFT_LIMIT -1 #define __SQRI_KARATSUBA_LIMIT -1 #define __SQRR_SQRI_LIMIT 12 #else #define __AGM_ATAN_LIMIT 89 #define __DIVRR_GMP_LIMIT 4 #define __EXPNEWTON_LIMIT 197 #define __F2x_MUL_KARATSUBA_LIMIT 23 #define __F2xqX_BARRETT_LIMIT 17 #define __F2xqX_DIVREM_BARRETT_LIMIT 46 #define __F2xqX_INVBARRETT_LIMIT 22 #define __F2xqX_REM_BARRETT_LIMIT 48 #define __Flx_BARRETT_HALFMULII_LIMIT 23 #define __Flx_BARRETT_KARATSUBA_LIMIT 905 #define __Flx_BARRETT_MULII2_LIMIT 647 #define __Flx_BARRETT_MULII_LIMIT 433 #define __Flx_BARRETT_QUARTMULII_LIMIT 20 #define __Flx_DIVREM_BARRETT_LIMIT 1289 #define __Flx_EXTGCD_LIMIT 632 #define __Flx_GCD_LIMIT 2514 #define __Flx_HALFGCD_HALFMULII_LIMIT 78 #define __Flx_HALFGCD_KARATSUBA_LIMIT 139 #define __Flx_HALFGCD_MULII2_LIMIT 537 #define __Flx_HALFGCD_MULII_LIMIT 91 #define __Flx_HALFGCD_QUARTMULII_LIMIT 37 #define __Flx_INVBARRETT_HALFMULII_LIMIT 240 #define __Flx_INVBARRETT_KARATSUBA_LIMIT 3600 #define __Flx_INVBARRETT_MULII2_LIMIT 1815 #define __Flx_INVBARRETT_MULII_LIMIT 1293 #define __Flx_INVBARRETT_QUARTMULII_LIMIT 73 #define __Flx_MUL_HALFMULII_LIMIT 7 #define __Flx_MUL_KARATSUBA_LIMIT 90 #define __Flx_MUL_MULII2_LIMIT 152 #define __Flx_MUL_MULII_LIMIT 8 #define __Flx_MUL_QUARTMULII_LIMIT 7 #define __Flx_REM_BARRETT_LIMIT 689 #define __Flx_SQR_HALFSQRI_LIMIT 4 #define __Flx_SQR_KARATSUBA_LIMIT 159 #define __Flx_SQR_QUARTSQRI_LIMIT 4 #define __Flx_SQR_SQRI2_LIMIT 470 #define __Flx_SQR_SQRI_LIMIT 5 #define __FlxqX_BARRETT_LIMIT 17 #define __FlxqX_DIVREM_BARRETT_LIMIT 46 #define __FlxqX_EXTGCD_LIMIT 44 #define __FlxqX_GCD_LIMIT 1289 #define __FlxqX_HALFGCD_LIMIT 89 #define __FlxqX_INVBARRETT_LIMIT 22 #define __FlxqX_REM_BARRETT_LIMIT 48 #define __FpXQX_BARRETT_LIMIT 12 #define __FpXQX_DIVREM_BARRETT_LIMIT 30 #define __FpXQX_EXTGCD_LIMIT 28 #define __FpXQX_GCD_LIMIT 182 #define __FpXQX_HALFGCD_LIMIT 35 #define __FpXQX_INVBARRETT_LIMIT 40 #define __FpXQX_REM_BARRETT_LIMIT 30 #define __FpX_BARRETT_LIMIT 44 #define __FpX_DIVREM_BARRETT_LIMIT 116 #define __FpX_EXTGCD_LIMIT 81 #define __FpX_GCD_LIMIT 414 #define __FpX_HALFGCD_LIMIT 55 #define __FpX_INVBARRETT_LIMIT 121 #define __FpX_REM_BARRETT_LIMIT 127 #define __Fp_POW_BARRETT_LIMIT 11 #define __Fp_POW_REDC_LIMIT 3 #define __INVMOD_GMP_LIMIT 3 #define __INVNEWTON_LIMIT 93 #define __LOGAGMCX_LIMIT 32 #define __LOGAGM_LIMIT 45 #define __MULII_FFT_LIMIT -1 #define __MULII_KARATSUBA_LIMIT -1 #define __MULRR_MULII_LIMIT 19 #define __RgX_MUL_LIMIT 7 #define __RgX_SQR_LIMIT 34 #define __SQRI_FFT_LIMIT -1 #define __SQRI_KARATSUBA_LIMIT -1 #define __SQRR_SQRI_LIMIT 9 #endif pari-2.11.2/src/kernel/gmp/gcdext.c0000644000175000017500000001174513201017466015442 0ustar billbill#line 2 "../src/kernel/gmp/gcdext.c" /* Copyright (C) 2000-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*================================== * invmod(a,b,res) *================================== * If a is invertible, return 1, and set res = a^{ -1 } * Otherwise, return 0, and set res = gcd(a,b) */ int invmod(GEN a, GEN b, GEN *res) { if (!signe(b)) { *res=absi(a); return 0; } if (NLIMBS(b) < INVMOD_GMP_LIMIT) return invmod_pari(a,b,res); { /* General case: use gcdext(a+b, b) since mpn_gcdext require S1>=S2 */ pari_sp av = avma; GEN ca, cb, u, d; long l, su, sa = signe(a), lb,lna; mp_size_t lu; GEN na; if (!sa) { avma = av; *res = absi(b); return 0; } if (signe(b) < 0) b = negi(b); if (abscmpii(a, b) < 0) na = sa > 0? addii(a, b): subii(a, b); else na = a; /* Copy serves two purposes: * 1) mpn_gcdext destroys its input and needs an extra limb * 2) allows us to use icopy instead of gerepile later. */ lb = lgefint(b); lna = lgefint(na); ca = icopy_ef(na,lna+1); cb = icopy_ef( b,lb+1); /* must create u first else final icopy could fail. */ u = cgeti(lna+1); d = cgeti(lna+1); /* na >= b */ l = mpn_gcdext(LIMBS(d), LIMBS(u), &lu, LIMBS(ca), NLIMBS(ca), LIMBS(cb), NLIMBS(cb)); d[1] = evalsigne(1)|evallgefint(l+2); if (!is_pm1(d)) {avma=av; *res=icopy(d); return 0;} su = lu?((sa ^ lu) < 0)? -1: 1: 0; u[1] = evalsigne(su) | evallgefint(labs(lu)+2); if (su < 0) u = addii(u, b); avma=av; *res=icopy(u); return 1; } } /*================================== * bezout(a,b,pu,pv) *================================== * Return g = gcd(a,b) >= 0, and assign GENs u,v through pointers pu,pv * such that g = u*a + v*b. * Special cases: * a == b == 0 ==> pick u=1, v=0 * a != 0 == b ==> keep v=0 * a == 0 != b ==> keep u=0 * |a| == |b| != 0 ==> keep u=0, set v=+-1 * Assignments through pu,pv will be suppressed when the corresponding * pointer is NULL (but the computations will happen nonetheless). */ GEN bezout(GEN a, GEN b, GEN *pu, GEN *pv) { long s, sa, sb; ulong g; ulong xu,xu1,xv,xv1; /* Lehmer stage recurrence matrix */ s = abscmpii(a,b); if (s < 0) { swap(a,b); pswap(pu,pv); } /* now |a| >= |b| */ sa = signe(a); sb = signe(b); if (!sb) { if (pv) *pv = gen_0; switch(sa) { case 0: if (pu) *pu = gen_0; return gen_0; case 1: if (pu) *pu = gen_1; return icopy(a); case -1: if (pu) *pu = gen_m1; return negi(a); } } if (s == 0) /* |a| == |b| != 0 */ { if (pu) *pu = gen_0; if (sb > 0) { if (pv) *pv = gen_1; return icopy(b); } else { if (pv) *pv = gen_m1; return negi(b); } } /* now |a| > |b| > 0 */ if (lgefint(a) == 3) /* single-word affair */ { g = xxgcduu((ulong)a[2], (ulong)b[2], 0, &xu, &xu1, &xv, &xv1, &s); sa = s > 0 ? sa : -sa; sb = s > 0 ? -sb : sb; if (pu) { if (xu == 0) *pu = gen_0; /* can happen when b divides a */ else if (xu == 1) *pu = sa < 0 ? gen_m1 : gen_1; else if (xu == 2) *pu = sa < 0 ? gen_m2 : gen_2; else { *pu = cgeti(3); (*pu)[1] = evalsigne(sa)|evallgefint(3); (*pu)[2] = xu; } } if (pv) { if (xv == 1) *pv = sb < 0 ? gen_m1 : gen_1; else if (xv == 2) *pv = sb < 0 ? gen_m2 : gen_2; else { *pv = cgeti(3); (*pv)[1] = evalsigne(sb)|evallgefint(3); (*pv)[2] = xv; } } if (g == 1) return gen_1; else if (g == 2) return gen_2; else return utoipos(g); } else { /* general case */ pari_sp av = avma; /*Copy serves two purposes: * 1) mpn_gcdext destroys its input and needs an extra limb * 2) allows us to use icopy instead of gerepile later. * NOTE: we must put u before d else the final icopy could fail. */ GEN ca = icopy_ef(a,lgefint(a)+1); GEN cb = icopy_ef(b,lgefint(b)+1); GEN u = cgeti(lgefint(a)+1), v = NULL; GEN d = cgeti(lgefint(a)+1); long su,l; mp_size_t lu; l = mpn_gcdext(LIMBS(d), LIMBS(u), &lu, LIMBS(ca), NLIMBS(ca), LIMBS(cb), NLIMBS(cb)); if (lu<=0) { if (lu==0) su=0; else {su=-1;lu=-lu;} } else su=1; if (sa<0) su=-su; d[1] = evalsigne(1)|evallgefint(l+2); u[1] = evalsigne(su)|evallgefint(lu+2); if (pv) v=diviiexact(subii(d,mulii(u,a)),b); avma = av; if (pu) *pu=icopy(u); if (pv) *pv=icopy(v); return icopy(d); } } pari-2.11.2/src/kernel/gmp/MakeLVL1.SH0000644000175000017500000000101612314242551015555 0ustar billbillcat >> $file << EOT L1OBJS=$kern1/int.h $knone/level1.h parilvl1.h: \$(L1OBJS) $src/headers/paritune.h if test -r ./tune.h; then d=.; else d=$kern1; fi;\ cat \$\$d/tune.h \$(L1OBJS) > parilvl1.h MP_C=$kern1/mp.c $knone/cmp.c $knone/gcdll.c $knone/ratlift.c\ $knone/invmod.c $kern1/gcd.c $kern1/gcdext.c $knone/mp_indep.c $knone/add.c mpker.c: \$(MP_C) cat \$(MP_C) > mpker.c mpker\$(_O): .headers mpker.c \$(CC) -c \$(CFLAGS) \$(KERNELCFLAGS) \$(DLCFLAGS) \$(CPPFLAGS) \$(GMPINCLUDE) -o mpker\$(_O) mpker.c EOT pari-2.11.2/src/kernel/gmp/int.h0000644000175000017500000000256513036414402014760 0ustar billbill#line 2 "../src/kernel/gmp/int.h" /* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define int_MSW(x) ((x)+lgefint((x))-1) /*x being a t_INT, return a pointer to the most significant word of x.*/ #define int_LSW(x) ((x)+2) /*x being a t_INT, return a pointer to the least significant word of x.*/ #define int_precW(x) ((x)-1) /*x pointing to a mantissa word, return the previous (less significant) * mantissa word.*/ #define int_nextW(x) ((x)+1) /*x pointing to a mantissa word, return the next (more significant) mantissa * word.*/ #define int_W(x,l) ((x)+2+(l)) /*x being a t_INT, return a pointer to the l-th least significant word of x.*/ #define int_W_lg(x,l,lx) ((x)+2+(l)) /*x being a t_INT, return a pointer to the l-th least significant word of x, * assuming lgefint(x) = lx.*/ #define PARI_KERNEL_GMP /*This macro should not be used in libpari itself.*/ pari-2.11.2/src/kernel/gmp/gcd.c0000644000175000017500000000413113201017466014710 0ustar billbill#line 2 "../src/kernel/gmp/gcd.c" /* Copyright (C) 2000-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* assume y > x > 0. return y mod x */ static ulong resiu(GEN y, ulong x) { return mpn_mod_1(LIMBS(y), NLIMBS(y), x); } GEN gcdii(GEN a, GEN b) { long v, w; pari_sp av; GEN t; switch (abscmpii(a,b)) { case 0: return absi(a); case -1: swap(a,b); } if (!signe(b)) return absi(a); /* here |a|>|b|>0. Try single precision first */ if (lgefint(a)==3) return igcduu((ulong)a[2], (ulong)b[2]); if (lgefint(b)==3) { ulong u = resiu(a,(ulong)b[2]); if (!u) return absi(b); return igcduu((ulong)b[2], u); } /* larger than gcd: "avma=av" gerepile (erasing t) is valid */ av = avma; (void)new_chunk(lgefint(b)+1); /* HACK */ t = remii(a,b); if (!signe(t)) { avma=av; return absi(b); } a = b; b = t; v = vali(a); a = shifti(a,-v); setabssign(a); w = vali(b); b = shifti(b,-w); setabssign(b); if (w < v) v = w; switch(abscmpii(a,b)) { case 0: avma=av; a=shifti(a,v); return a; case -1: swap(a,b); } if (is_pm1(b)) { avma=av; return int2n(v); } { /* general case */ /*This serve two purposes: 1) mpn_gcd destroy its input and need an extra * limb 2) this allows us to use icopy instead of gerepile later. NOTE: we * must put u before d else the final icopy could fail. */ GEN res= cgeti(lgefint(a)+1); GEN ca = icopy_ef(a,lgefint(a)+1); GEN cb = icopy_ef(b,lgefint(b)+1); long l = mpn_gcd(LIMBS(res), LIMBS(ca), NLIMBS(ca), LIMBS(cb), NLIMBS(cb)); res[1] = evalsigne(1)|evallgefint(l+2); avma=av; return shifti(res,v); } } pari-2.11.2/src/kernel/gmp/mp.c0000644000175000017500000010353713447371554014616 0ustar billbill#line 2 "../src/kernel/gmp/mp.c" /* Copyright (C) 2002-2003 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /***********************************************************************/ /** **/ /** GMP KERNEL **/ /** BA2002Sep24 **/ /***********************************************************************/ /* GMP t_INT as just like normal t_INT, just the mantissa is the other way * round * * `How would you like to live in Looking-glass House, Kitty? I * wonder if they'd give you milk in there? Perhaps Looking-glass * milk isn't good to drink--But oh, Kitty! now we come to the * passage. You can just see a little PEEP of the passage in * Looking-glass House, if you leave the door of our drawing-room * wide open: and it's very like our passage as far as you can see, * only you know it may be quite different on beyond. Oh, Kitty! * how nice it would be if we could only get through into Looking- * glass House! I'm sure it's got, oh! such beautiful things in it! * * Through the Looking Glass, Lewis Carrol * * (pityful attempt to beat GN code/comments rate) * */ #include #include "pari.h" #include "paripriv.h" #include "../src/kernel/none/tune-gen.h" /*We need PARI invmod renamed to invmod_pari*/ #define INVMOD_PARI static void *pari_gmp_realloc(void *ptr, size_t old_size, size_t new_size) { (void)old_size; return (void *) pari_realloc(ptr,new_size); } static void pari_gmp_free(void *ptr, size_t old_size){ (void)old_size; pari_free(ptr); } static void *(*old_gmp_malloc)(size_t new_size); static void *(*old_gmp_realloc)(void *ptr, size_t old_size, size_t new_size); static void (*old_gmp_free)(void *ptr, size_t old_size); void pari_kernel_init(void) { mp_get_memory_functions (&old_gmp_malloc, &old_gmp_realloc, &old_gmp_free); mp_set_memory_functions((void *(*)(size_t)) pari_malloc, pari_gmp_realloc, pari_gmp_free); } void pari_kernel_close(void) { void *(*new_gmp_malloc)(size_t new_size); void *(*new_gmp_realloc)(void *ptr, size_t old_size, size_t new_size); void (*new_gmp_free)(void *ptr, size_t old_size); mp_get_memory_functions (&new_gmp_malloc, &new_gmp_realloc, &new_gmp_free); if (new_gmp_malloc==pari_malloc) new_gmp_malloc = old_gmp_malloc; if (new_gmp_realloc==pari_gmp_realloc) new_gmp_realloc = old_gmp_realloc; if (new_gmp_free==pari_gmp_free) new_gmp_free = old_gmp_free; mp_set_memory_functions(new_gmp_malloc, new_gmp_realloc, new_gmp_free); } #define LIMBS(x) ((mp_limb_t *)((x)+2)) #define NLIMBS(x) (lgefint(x)-2) /*This one is for t_REALs to emphasize they are not t_INTs*/ #define RLIMBS(x) ((mp_limb_t *)((x)+2)) #define RNLIMBS(x) (lg(x)-2) INLINE void xmpn_copy(mp_limb_t *x, mp_limb_t *y, long n) { while (--n >= 0) x[n]=y[n]; } INLINE void xmpn_mirror(mp_limb_t *x, long n) { long i; for(i=0;i<(n>>1);i++) { ulong m=x[i]; x[i]=x[n-1-i]; x[n-1-i]=m; } } INLINE void xmpn_mirrorcopy(mp_limb_t *z, mp_limb_t *x, long n) { long i; for(i=0;i= 0) x[n]=0; } INLINE GEN icopy_ef(GEN x, long l) { register long lx = lgefint(x); const GEN y = cgeti(l); while (--lx > 0) y[lx]=x[lx]; return y; } /* NOTE: arguments of "spec" routines (muliispec, addiispec, etc.) aren't * GENs but pairs (long *a, long na) representing a list of digits (in basis * BITS_IN_LONG) : a[0], ..., a[na-1]. [ In ordre to facilitate splitting: no * need to reintroduce codewords ] * Use speci(a,na) to visualize the corresponding GEN. */ /***********************************************************************/ /** **/ /** ADDITION / SUBTRACTION **/ /** **/ /***********************************************************************/ GEN setloop(GEN a) { pari_sp av = avma - 2 * sizeof(long); (void)cgetg(lgefint(a) + 3, t_VECSMALL); return icopy_avma(a, av); /* two cells of extra space after a */ } /* we had a = setloop(?), then some incloops. Reset a to b */ GEN resetloop(GEN a, GEN b) { a[0] = evaltyp(t_INT) | evallg(lgefint(b)); affii(b, a); return a; } /* assume a > 0, initialized by setloop. Do a++ */ static GEN incpos(GEN a) { long i, l = lgefint(a); for (i=2; i= y */ INLINE GEN subiuspec(GEN x, ulong s, long nx) { GEN zd; long lz; if (nx == 1) return utoi(x[0] - s); lz = nx + 2; zd = cgeti(lz); mpn_sub_1 (LIMBS(zd), (mp_limb_t *)x, nx, s); if (! zd[lz - 1]) { --lz; } zd[1] = evalsigne(1) | evallgefint(lz); return zd; } /* assume x > y */ INLINE GEN subiispec(GEN x, GEN y, long nx, long ny) { GEN zd; long lz; if (ny==1) return subiuspec(x,*y,nx); lz = nx+2; zd = cgeti(lz); mpn_sub (LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny); while (lz >= 3 && zd[lz - 1] == 0) { lz--; } zd[1] = evalsigne(1) | evallgefint(lz); return zd; } static void roundr_up_ip(GEN x, long l) { long i = l; for(;;) { if (++((ulong*)x)[--i]) break; if (i == 2) { x[2] = HIGHBIT; shiftr_inplace(x, 1); break; } } } void affir(GEN x, GEN y) { const long s = signe(x), ly = lg(y); long lx, sh, i; if (!s) { y[1] = evalexpo(-bit_accuracy(ly)); return; } lx = lgefint(x); sh = bfffo(*int_MSW(x)); y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-sh-1); if (sh) { if (lx <= ly) { for (i=lx; i> (BITS_IN_LONG-sh); xmpn_mirror(LIMBS(y),ly-2); /* lx > ly: round properly */ if ((uel(x,lx-ly+1)< ly: round properly */ if (uel(x,lx-ly+1) & HIGHBIT) roundr_up_ip(y, ly); } } INLINE GEN shiftispec(GEN x, long nx, long n) { long ny,m; GEN yd, y; if (!n) return icopyspec(x, nx); if (n > 0) { long d = dvmdsBIL(n, &m); long i; ny = nx + d + (m!=0); y = cgeti(ny + 2); yd = y + 2; for (i=0; i 0) { GEN z = (GEN)avma; long d = dvmdsBIL(n, &m); ly = lx+d; y = new_chunk(ly); for ( ; d; d--) *--z = 0; if (!m) for (i=2; i> sh; /* Extend y on the left? */ if (i) { ly++; y = new_chunk(1); y[2] = i; } } } else { ly = lx - dvmdsBIL(-n, &m); if (ly<3) return gen_0; y = new_chunk(ly); if (m) { shift_right(y,x, 2,ly, 0,m); if (y[2] == 0) { if (ly==3) { avma = (pari_sp)(y+3); return gen_0; } ly--; avma = (pari_sp)(++y); } } else { for (i=2; i lg(x)) pari_err_PREC( "truncr (precision loss in truncation)"); y=cgeti(d); y[1] = evalsigne(s) | evallgefint(d); if (++m == BITS_IN_LONG) for (i=2; i= 0) return truncr(x); if ((e=expo(x)) < 0) return gen_m1; d = nbits2lg(e+1); m = remsBIL(e); lx=lg(x); if (d>lx) pari_err_PREC( "floorr (precision loss in truncation)"); y = cgeti(d+1); if (++m == BITS_IN_LONG) { for (i=2; i ly) return 1; return mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx); } INLINE int equaliispec(GEN x, GEN y, long lx, long ly) { if (lx != ly) return 0; return !mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx); } /***********************************************************************/ /** **/ /** MULTIPLICATION **/ /** **/ /***********************************************************************/ /* assume ny > 0 */ INLINE GEN muluispec(ulong x, GEN y, long ny) { if (ny == 1) return muluu(x, *y); else { long lz = ny+3; GEN z = cgeti(lz); ulong hi = mpn_mul_1 (LIMBS(z), (mp_limb_t *)y, ny, x); if (hi) { z[lz - 1] = hi; } else lz--; z[1] = evalsigne(1) | evallgefint(lz); return z; } } /* a + b*|y| */ GEN addumului(ulong a, ulong b, GEN y) { GEN z; long i, lz; ulong hi; if (!b || !signe(y)) return utoi(a); lz = lgefint(y)+1; z = cgeti(lz); z[2]=a; for(i=3;i 0)? hi: x - hi; } /* return |y| \/ x */ GEN absdiviu_rem(GEN y, ulong x, ulong *rem) { long ly; GEN z; if (!x) pari_err_INV("absdiviu_rem",gen_0); if (!signe(y)) { *rem = 0; return gen_0; } ly = lgefint(y); if (ly == 3 && (ulong)x > uel(y,2)) { *rem = uel(y,2); return gen_0; } z = cgeti(ly); *rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x); if (z [ly - 1] == 0) ly--; z[1] = evallgefint(ly) | evalsigne(1); return z; } GEN divis_rem(GEN y, long x, long *rem) { long sy=signe(y),ly,s; GEN z; if (!x) pari_err_INV("divis_rem",gen_0); if (!sy) { *rem = 0; return gen_0; } if (x<0) { s = -sy; x = -x; } else s = sy; ly = lgefint(y); if (ly == 3 && (ulong)x > uel(y,2)) { *rem = itos(y); return gen_0; } z = cgeti(ly); *rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x); if (sy<0) *rem = - *rem; if (z[ly - 1] == 0) ly--; z[1] = evallgefint(ly) | evalsigne(s); return z; } GEN divis(GEN y, long x) { long sy=signe(y),ly,s; GEN z; if (!x) pari_err_INV("divis",gen_0); if (!sy) return gen_0; if (x<0) { s = -sy; x = -x; } else s=sy; ly = lgefint(y); if (ly == 3 && (ulong)x > uel(y,2)) return gen_0; z = cgeti(ly); (void)mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x); if (z[ly - 1] == 0) ly--; z[1] = evallgefint(ly) | evalsigne(s); return z; } /* We keep llx bits of x and lly bits of y*/ static GEN divrr_with_gmp(GEN x, GEN y) { long lx=RNLIMBS(x),ly=RNLIMBS(y); long lw=minss(lx,ly); long lly=minss(lw+1,ly); GEN w=cgetr(lw+2); long lu=lw+lly; long llx=minss(lu,lx); mp_limb_t *u=(mp_limb_t *)new_chunk(lu); mp_limb_t *z=(mp_limb_t *)new_chunk(lly); mp_limb_t *q,*r; long e=expo(x)-expo(y); long sx=signe(x),sy=signe(y); xmpn_mirrorcopy(z,RLIMBS(y),lly); xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx); xmpn_zero(u,lu-llx); q = (mp_limb_t *)new_chunk(lw+1); r = (mp_limb_t *)new_chunk(lly); mpn_tdiv_qr(q,r,0,u,lu,z,lly); /*Round up: This is not exactly correct we should test 2*r>z*/ if (uel(r,lly-1) > (uel(z,lly-1)>>1)) mpn_add_1(q,q,lw+1,1); xmpn_mirrorcopy(RLIMBS(w),q,lw); if (q[lw] == 0) e--; else if (q[lw] == 1) { shift_right(w,w, 2,lw+2, 1,1); } else { w[2] = HIGHBIT; e++; } if (sy < 0) sx = -sx; w[1] = evalsigne(sx) | evalexpo(e); avma=(pari_sp) w; return w; } /* We keep llx bits of x and lly bits of y*/ static GEN divri_with_gmp(GEN x, GEN y) { long llx=RNLIMBS(x),ly=NLIMBS(y); long lly=minss(llx+1,ly); GEN w=cgetr(llx+2); long lu=llx+lly, ld=ly-lly; mp_limb_t *u=(mp_limb_t *)new_chunk(lu); mp_limb_t *z=(mp_limb_t *)new_chunk(lly); mp_limb_t *q,*r; long sh=bfffo(y[ly+1]); long e=expo(x)-expi(y); long sx=signe(x),sy=signe(y); if (sh) mpn_lshift(z,LIMBS(y)+ld,lly,sh); else xmpn_copy(z,LIMBS(y)+ld,lly); xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx); xmpn_zero(u,lu-llx); q = (mp_limb_t *)new_chunk(llx+1); r = (mp_limb_t *)new_chunk(lly); mpn_tdiv_qr(q,r,0,u,lu,z,lly); /*Round up: This is not exactly correct we should test 2*r>z*/ if (uel(r,lly-1) > (uel(z,lly-1)>>1)) mpn_add_1(q,q,llx+1,1); xmpn_mirrorcopy(RLIMBS(w),q,llx); if (q[llx] == 0) e--; else if (q[llx] == 1) { shift_right(w,w, 2,llx+2, 1,1); } else { w[2] = HIGHBIT; e++; } if (sy < 0) sx = -sx; w[1] = evalsigne(sx) | evalexpo(e); avma=(pari_sp) w; return w; } GEN divri(GEN x, GEN y) { long s = signe(y); if (!s) pari_err_INV("divri",gen_0); if (!signe(x)) return real_0_bit(expo(x) - expi(y)); if (!is_bigint(y)) { GEN z = divru(x, y[2]); if (s < 0) togglesign(z); return z; } return divri_with_gmp(x,y); } GEN divrr(GEN x, GEN y) { long sx=signe(x), sy=signe(y), lx,ly,lr,e,i,j; ulong y0,y1; GEN r, r1; if (!sy) pari_err_INV("divrr",y); e = expo(x) - expo(y); if (!sx) return real_0_bit(e); if (sy<0) sx = -sx; lx=lg(x); ly=lg(y); if (ly==3) { ulong k = x[2], l = (lx>3)? x[3]: 0; LOCAL_HIREMAINDER; if (k < uel(y,2)) e--; else { l >>= 1; if (k&1) l |= HIGHBIT; k >>= 1; } hiremainder = k; k = divll(l,y[2]); if (hiremainder & HIGHBIT) { k++; if (!k) { k = HIGHBIT; e++; } } r = cgetr(3); r[1] = evalsigne(sx) | evalexpo(e); r[2] = k; return r; } if (ly>=DIVRR_GMP_LIMIT) return divrr_with_gmp(x,y); lr = minss(lx,ly); r = new_chunk(lr); r1 = r-1; r1[1] = 0; for (i=2; ily)? x[lr]: 0; y0 = y[2]; y1 = y[3]; for (i=0; i y0) /* can't happen if i=0 */ { GEN y1 = y+1; j = lr-i; r1[j] = subll(r1[j],y1[j]); for (j--; j>0; j--) r1[j] = subllx(r1[j],y1[j]); j=i; do uel(r,--j)++; while (j && !r[j]); } hiremainder = r1[1]; overflow = 0; qp = divll(r1[2],y0); k = hiremainder; } j = lr-i+1; if (!overflow) { long k3, k4; k3 = mulll(qp,y1); if (j == 3) /* i = lr - 2 maximal, r1[3] undefined -> 0 */ k4 = subll(hiremainder,k); else { k3 = subll(k3, r1[3]); k4 = subllx(hiremainder,k); } while (!overflow && k4) { qp--; k3=subll(k3,y1); k4=subllx(k4,y0); } } if (j1; j--) { r1[j] = subll(r1[j], addmul(qp,y[j])); hiremainder += overflow; } if (uel(r1,1) != hiremainder) { if (uel(r1,1) < hiremainder) { qp--; j = lr-i-(lr-i>=ly); r1[j] = addll(r1[j], y[j]); for (j--; j>1; j--) r1[j] = addllx(r1[j], y[j]); } else { uel(r1,1) -= hiremainder; while (r1[1]) { qp++; if (!qp) { j=i; do uel(r,--j)++; while (j && !r[j]); } j = lr-i-(lr-i>=ly); r1[j] = subll(r1[j],y[j]); for (j--; j>1; j--) r1[j] = subllx(r1[j],y[j]); uel(r1,1) -= overflow; } } } *++r1 = qp; } /* i = lr-1 */ /* round correctly */ if (uel(r1,1) > (y0>>1)) { j=i; do uel(r,--j)++; while (j && !r[j]); } r1 = r-1; for (j=i; j>=2; j--) r[j]=r1[j]; if (r[0] == 0) e--; else if (r[0] == 1) { shift_right(r,r, 2,lr, 1,1); } else { /* possible only when rounding up to 0x2 0x0 ... */ r[2] = (long)HIGHBIT; e++; } r[0] = evaltyp(t_REAL)|evallg(lr); r[1] = evalsigne(sx) | evalexpo(e); return r; } /* Integer division x / y: such that sign(r) = sign(x) * if z = ONLY_REM return remainder, otherwise return quotient * if z != NULL set *z to remainder * *z is the last object on stack (and thus can be disposed of with cgiv * instead of gerepile) * If *z is zero, we put gen_0 here and no copy. * space needed: lx + ly */ GEN dvmdii(GEN x, GEN y, GEN *z) { long sx=signe(x),sy=signe(y); long lx, ly, lq; pari_sp av; GEN r,q; if (!sy) pari_err_INV("dvmdii",y); if (!sx) { if (!z || z == ONLY_REM) return gen_0; *z=gen_0; return gen_0; } lx=lgefint(x); ly=lgefint(y); lq=lx-ly; if (lq <= 0) { if (lq == 0) { long s=mpn_cmp(LIMBS(x),LIMBS(y),NLIMBS(x)); if (s>0) goto DIVIDE; if (s==0) { if (z == ONLY_REM) return gen_0; if (z) *z = gen_0; if (sx < 0) sy = -sy; return stoi(sy); } } if (z == ONLY_REM) return icopy(x); if (z) *z = icopy(x); return gen_0; } DIVIDE: /* quotient is non-zero */ av=avma; if (sx<0) sy = -sy; if (ly==3) { ulong lq = lx; ulong si; q = cgeti(lq); si = mpn_divrem_1(LIMBS(q), 0, LIMBS(x), NLIMBS(x), y[2]); if (q[lq - 1] == 0) lq--; if (z == ONLY_REM) { avma=av; if (!si) return gen_0; r=cgeti(3); r[1] = evalsigne(sx) | evallgefint(3); r[2] = si; return r; } q[1] = evalsigne(sy) | evallgefint(lq); if (!z) return q; if (!si) { *z=gen_0; return q; } r=cgeti(3); r[1] = evalsigne(sx) | evallgefint(3); r[2] = si; *z=r; return q; } if (z == ONLY_REM) { ulong lr = lgefint(y); ulong lq = lgefint(x)-lgefint(y)+3; GEN r = cgeti(lr); GEN q = cgeti(lq); mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y)); if (!r[lr - 1]) { while(lr>2 && !r[lr - 1]) lr--; if (lr == 2) {avma=av; return gen_0;} /* exact division */ } r[1] = evalsigne(sx) | evallgefint(lr); avma = (pari_sp) r; return r; } else { ulong lq = lgefint(x)-lgefint(y)+3; ulong lr = lgefint(y); GEN q = cgeti(lq); GEN r = cgeti(lr); mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y)); if (q[lq - 1] == 0) lq--; q[1] = evalsigne(sy) | evallgefint(lq); if (!z) { avma = (pari_sp)q; return q; } if (!r[lr - 1]) { while(lr>2 && !r[lr - 1]) lr--; if (lr == 2) {avma=(pari_sp) q; *z=gen_0; return q;} /* exact division */ } r[1] = evalsigne(sx) | evallgefint(lr); avma = (pari_sp) r; *z = r; return q; } } /* Montgomery reduction. * N has k words, assume T >= 0 has less than 2k. * Return res := T / B^k mod N, where B = 2^BIL * such that 0 <= res < T/B^k + N and res has less than k words */ GEN red_montgomery(GEN T, GEN N, ulong inv) { pari_sp av; GEN Te, Td, Ne, Nd, scratch; ulong i, j, m, t, d, k = NLIMBS(N); int carry; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (k == 0) return gen_0; d = NLIMBS(T); /* <= 2*k */ if (d == 0) return gen_0; #ifdef DEBUG if (d > 2*k) pari_err_BUG("red_montgomery"); #endif if (k == 1) { /* as below, special cased for efficiency */ ulong n = uel(N,2); if (d == 1) { hiremainder = uel(T,2); m = hiremainder * inv; (void)addmul(m, n); /* t + m*n = 0 */ return utoi(hiremainder); } else { /* d = 2 */ hiremainder = uel(T,2); m = hiremainder * inv; (void)addmul(m, n); /* t + m*n = 0 */ t = addll(hiremainder, uel(T,3)); if (overflow) t -= n; /* t > n doesn't fit in 1 word */ return utoi(t); } } /* assume k >= 2 */ av = avma; scratch = new_chunk(k<<1); /* >= k + 2: result fits */ /* copy T to scratch space (pad with zeroes to 2k words) */ Td = scratch; Te = T + 2; for (i=0; i < d ; i++) *Td++ = *Te++; for ( ; i < (k<<1); i++) *Td++ = 0; Te = scratch - 1; /* 1 beyond end of current T mantissa (in scratch) */ Ne = N + 1; /* 1 beyond end of N mantissa */ carry = 0; for (i=0; i N overflows (k+1 words), set Td := Td - N */ GEN NE = N + k+1; Td = Te; Nd = Ne; t = subll(*++Td, *++Nd); *Td = t; while (Nd < NE) { t = subllx(*++Td, *++Nd); *Td = t; } } /* copy result */ Td = (GEN)av - 1; /* *Td = high word of final result */ while (*Td == 0 && Te < Td) Td--; /* strip leading 0s */ k = Td - Te; if (!k) { avma = av; return gen_0; } Td = (GEN)av - k; /* will write mantissa there */ (void)memmove(Td, Te+1, k*sizeof(long)); Td -= 2; Td[0] = evaltyp(t_INT) | evallg(k+2); Td[1] = evalsigne(1) | evallgefint(k+2); #ifdef DEBUG { long l = NLIMBS(N), s = BITS_IN_LONG*l; GEN R = int2n(s); GEN res = remii(mulii(T, Fp_inv(R, N)), N); if (k > lgefint(N) || !equalii(remii(Td,N),res) || cmpii(Td, addii(shifti(T, -s), N)) >= 0) pari_err_BUG("red_montgomery"); } #endif avma = (pari_sp)Td; return Td; } /* EXACT INTEGER DIVISION */ /* use undocumented GMP interface */ static void GEN2mpz(mpz_t X, GEN x) { long l = lgefint(x)-2; X->_mp_alloc = l; X->_mp_size = signe(x) > 0? l: -l; X->_mp_d = LIMBS(x); } static void mpz2GEN(GEN z, mpz_t Z) { long l = Z->_mp_size; z[1] = evalsigne(l > 0? 1: -1) | evallgefint(labs(l)+2); } #ifdef mpn_divexact_1 static GEN diviuexact_i(GEN x, ulong y) { long l = lgefint(x); GEN z = cgeti(l); mpn_divexact_1(LIMBS(z), LIMBS(x), NLIMBS(x), y); if (z[l-1] == 0) l--; z[1] = evallgefint(l) | evalsigne(signe(x)); return z; } #elif 1 && !defined(_WIN64) /* mpz_divexact_ui is not LLP64 friendly */ /* assume y != 0 and the division is exact */ static GEN diviuexact_i(GEN x, ulong y) { long l = lgefint(x); GEN z = cgeti(l); mpz_t X, Z; GEN2mpz(X, x); Z->_mp_alloc = l-2; Z->_mp_size = l-2; Z->_mp_d = LIMBS(z); mpz_divexact_ui(Z, X, y); mpz2GEN(z, Z); return z; } #else /* assume y != 0 and the division is exact */ static GEN diviuexact_i(GEN x, ulong y) { /*TODO: implement true exact division.*/ return divii(x,utoi(y)); } #endif GEN diviuexact(GEN x, ulong y) { GEN z; if (!signe(x)) return gen_0; z = diviuexact_i(x, y); if (lgefint(z) == 2) pari_err_OP("exact division", x, utoi(y)); return z; } /* Find z such that x=y*z, knowing that y | x (unchecked) */ GEN diviiexact(GEN x, GEN y) { GEN z; if (!signe(y)) pari_err_INV("diviiexact",y); if (!signe(x)) return gen_0; if (lgefint(y) == 3) { z = diviuexact_i(x, y[2]); if (signe(y) < 0) togglesign(z); } else { long l = lgefint(x); mpz_t X, Y, Z; z = cgeti(l); GEN2mpz(X, x); GEN2mpz(Y, y); Z->_mp_alloc = l-2; Z->_mp_size = l-2; Z->_mp_d = LIMBS(z); mpz_divexact(Z, X, Y); mpz2GEN(z, Z); } if (lgefint(z) == 2) pari_err_OP("exact division", x, y); return z; } /* assume yz != and yz | x */ GEN diviuuexact(GEN x, ulong y, ulong z) { long tmp[4]; ulong t; LOCAL_HIREMAINDER; t = mulll(y, z); if (!hiremainder) return diviuexact(x, t); tmp[0] = evaltyp(t_INT)|_evallg(4); tmp[1] = evalsigne(1)|evallgefint(4); tmp[2] = t; tmp[3] = hiremainder; return diviiexact(x, tmp); } /********************************************************************/ /** **/ /** INTEGER MULTIPLICATION **/ /** **/ /********************************************************************/ /* nx >= ny = num. of digits of x, y (not GEN, see mulii) */ GEN muliispec(GEN x, GEN y, long nx, long ny) { GEN zd; long lz; ulong hi; if (nx < ny) swapspec(x,y, nx,ny); if (!ny) return gen_0; if (ny == 1) return muluispec((ulong)*y, x, nx); lz = nx+ny+2; zd = cgeti(lz); hi = mpn_mul(LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny); if (!hi) lz--; /*else zd[lz-1]=hi; GH tell me it is not necessary.*/ zd[1] = evalsigne(1) | evallgefint(lz); return zd; } GEN muluui(ulong x, ulong y, GEN z) { long t, s = signe(z); GEN r; LOCAL_HIREMAINDER; if (!x || !y || !signe(z)) return gen_0; t = mulll(x,y); if (!hiremainder) r = muluispec(t, z+2, lgefint(z)-2); else { long tmp[2]; tmp[1] = hiremainder; tmp[0] = t; r = muliispec(z+2,tmp, lgefint(z)-2, 2); } setsigne(r,s); return r; } GEN sqrispec(GEN x, long nx) { GEN zd; long lz; if (!nx) return gen_0; if (nx==1) return sqru(*x); lz = (nx<<1)+2; zd = cgeti(lz); #ifdef mpn_sqr mpn_sqr(LIMBS(zd), (mp_limb_t *)x, nx); #else mpn_mul_n(LIMBS(zd), (mp_limb_t *)x, (mp_limb_t *)x, nx); #endif if (zd[lz-1]==0) lz--; zd[1] = evalsigne(1) | evallgefint(lz); return zd; } INLINE GEN sqrispec_mirror(GEN x, long nx) { GEN cx=new_chunk(nx); GEN z; xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx); z=sqrispec(cx, nx); xmpn_mirror(LIMBS(z), NLIMBS(z)); return z; } /* leaves garbage on the stack. */ INLINE GEN muliispec_mirror(GEN x, GEN y, long nx, long ny) { GEN cx, cy, z; long s = 0; while (nx && x[nx-1]==0) { nx--; s++; } while (ny && y[ny-1]==0) { ny--; s++; } cx=new_chunk(nx); cy=new_chunk(ny); xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx); xmpn_mirrorcopy((mp_limb_t *)cy,(mp_limb_t *)y,ny); z = nx>=ny ? muliispec(cx, cy, nx, ny): muliispec(cy, cx, ny, nx); if (s) { long i, lz = lgefint(z) + s; (void)new_chunk(s); z -= s; for (i=0; i= 0 */ GEN remi2n(GEN x, long n) { ulong hi; long l, k, lx, ly, sx = signe(x); GEN z, xd, zd; if (!sx || !n) return gen_0; k = dvmdsBIL(n, &l); lx = lgefint(x); if (lx < k+3) return icopy(x); xd = x + (2 + k); /* x = |k|...|1|#|... : copy the last l bits of # and the first k words * ^--- initial xd */ hi = ((ulong)*xd) & ((1UL<> 1; /* 2 + ceil(na/2) */ S = cgetipos(l); if (r) { GEN R = cgeti(2 + na); nr = mpn_sqrtrem(LIMBS(S), LIMBS(R), LIMBS(a), na); if (nr) R[1] = evalsigne(1) | evallgefint(nr+2); else { avma = (pari_sp)S; R = gen_0; } *r = R; } else (void)mpn_sqrtrem(LIMBS(S), NULL, LIMBS(a), na); return S; } /* compute sqrt(|a|), assuming a != 0 */ GEN sqrtr_abs(GEN a) { GEN res; mp_limb_t *b, *c; long l = RNLIMBS(a), e = expo(a), er = e>>1; long n; res = cgetr(2 + l); res[1] = evalsigne(1) | evalexpo(er); if (e&1) { b = (mp_limb_t *) new_chunk(l<<1); xmpn_zero(b,l); xmpn_mirrorcopy(b+l, RLIMBS(a), l); c = (mp_limb_t *) new_chunk(l); n = mpn_sqrtrem(c,b,b,l<<1); /* c <- sqrt; b <- rem */ if (n>l || (n==l && mpn_cmp(b,c,l) > 0)) mpn_add_1(c,c,l,1); } else { ulong u; b = (mp_limb_t *) mantissa2nr(a,-1); b[1] = uel(a,l+1)<<(BITS_IN_LONG-1); b = (mp_limb_t *) new_chunk(l); xmpn_zero(b,l+1); /* overwrites the former b[0] */ c = (mp_limb_t *) new_chunk(l + 1); n = mpn_sqrtrem(c,b,b,(l<<1)+2); /* c <- sqrt; b <- rem */ u = (ulong)*c++; if ( u&HIGHBIT || (u == ~HIGHBIT && (n>l || (n==l && mpn_cmp(b,c,l)>0)))) mpn_add_1(c,c,l,1); } xmpn_mirrorcopy(RLIMBS(res),c,l); avma = (pari_sp)res; return res; } /* Normalize a non-negative integer */ GEN int_normalize(GEN x, long known_zero_words) { long i = lgefint(x) - 1 - known_zero_words; for ( ; i > 1; i--) if (x[i]) { setlgefint(x, i+1); return x; } x[1] = evalsigne(0) | evallgefint(2); return x; } /******************************************************************** ** ** ** Base Conversion ** ** ** ********************************************************************/ ulong * convi(GEN x, long *l) { long n = nchar2nlong(2 + (long)(NLIMBS(x) * (BITS_IN_LONG * LOG10_2))); GEN str = cgetg(n+1, t_VECSMALL); unsigned char *res = (unsigned char*) GSTR(str); long llz = mpn_get_str(res, 10, LIMBS(icopy(x)), NLIMBS(x)); long lz; ulong *z; long i, j; unsigned char *t; while (!*res) {res++; llz--;} /*Strip leading zeros*/ lz = (8+llz)/9; z = (ulong*)new_chunk(1+lz); t=res+llz+9; for(i=0;i> $file << EOT parilvl0.h: $src/kernel/sparcv8_micro/asm0-common.h \$(L0MODS) $cfg/genkernel $src/kernel/sparcv8_micro/asm0-common.h $kern0/asm0.h > parilvl0.h EOT pari-2.11.2/src/kernel/sparcv8_super/asm0.h0000644000175000017500000000002211636712103017034 0ustar billbill/* NOASM divll */ pari-2.11.2/src/kernel/mips64/0000755000175000017500000000000013461316051014347 5ustar billbillpari-2.11.2/src/kernel/mips64/asm0.h0000644000175000017500000000354013036414402015357 0ustar billbill#line 2 "../src/kernel/mips64/asm0.h" /* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM mulll NOASM addll bfffo divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define mulll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("dmultu %2,%3\n\tmfhi %1" \ : "=&l" (__value), "=&r" (hiremainder) \ : "r" (__arg1), "r" (__arg2) \ : "hi"); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value, __tmp; \ __asm__ ("dmultu %3,%4\n\tmfhi %0\n\tmflo %2\n\t" \ "daddu %1,%2,%5\n\tsltu %2,%1,%5\n\tdaddu %0,%0,%2" \ : "=&r" (hiremainder), "=&r" (__value), "=&r" (__tmp) \ : "r" (__arg1), "r" (__arg2), "r" (hiremainder) \ : "hi", "lo"); \ __value; \ }) #endif pari-2.11.2/src/kernel/mips/0000755000175000017500000000000013461316051014175 5ustar billbillpari-2.11.2/src/kernel/mips/asm0.h0000644000175000017500000000353613036414402015212 0ustar billbill#line 2 "../src/kernel/mips/asm0.h" /* Copyright (C) 2013 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* ASM mulll NOASM addll bfffo divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define mulll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("multu %2,%3\n\tmfhi %1" \ : "=&l" (__value), "=&r" (hiremainder) \ : "r" (__arg1), "r" (__arg2) \ : "hi"); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ \ ulong __arg1 = (a), __arg2 = (b), __value, __tmp; \ __asm__ ("multu %3,%4\n\tmfhi %0\n\tmflo %2\n\t" \ "addu %1,%2,%5\n\tsltu %2,%1,%5\n\taddu %0,%0,%2" \ : "=&r" (hiremainder), "=&r" (__value), "=&r" (__tmp) \ : "r" (__arg1), "r" (__arg2), "r" (hiremainder) \ : "hi", "lo"); \ __value; \ }) #endif pari-2.11.2/src/kernel/arm/0000755000175000017500000000000013461316051014004 5ustar billbillpari-2.11.2/src/kernel/arm/asm0.h0000644000175000017500000000475013036414402015020 0ustar billbill/* Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* ASM addll mulll NOASM bfffo divll */ #ifdef ASMINLINE #define LOCAL_HIREMAINDER register ulong hiremainder #define LOCAL_OVERFLOW register ulong overflow #define addll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("adds %0,%2,%3\n\tadc %1,%4,%4\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" ((ulong)0): "cc"); \ __value; \ }) #define addllx(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subs %1,%4,#1\n\tadcs %0,%2,%3\n\tadc %1,%5,%5\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow), "r" ((ulong)0) \ : "cc"); \ __value; \ }) #define subll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subs %0,%2,%3\n\tadc %1,%4,%4\n\trsb %1,%1,#1\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" ((ulong)0) \ : "cc"); \ __value; \ }) #define subllx(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("rsbs %1,%4,%5\n\tsbcs %0,%2,%3\n\tadc %1,%5,%5\n\trsb %1,%1,#1\n\t" \ : "=&r" (__value), "=&r" (overflow) \ : "r" (__arg1), "r" (__arg2), "r" (overflow), "r" ((ulong)0) \ : "cc"); \ __value; \ }) #define mulll(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("umull %0,%1,%2,%3\n\t" \ : "=&r" (__value), "=&r" (hiremainder) \ : "r" (__arg1), "r" (__arg2)); \ __value; \ }) #define addmul(a, b) \ __extension__ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("umlal %0,%1,%2,%3\n\t" \ : "=&r" (__value), "=&r" (hiremainder) \ : "r" (__arg1), "r" (__arg2), "1" ((ulong) 0), "0" (hiremainder)); \ __value; \ }) #if 0 /* Not supported by all CPU */ #define bfffo(a) \ __extension__ ({ \ ulong __arg1 = (a), __value; \ __asm__ ("clz %0,%1\n\t" \ : "=&r" (__value) \ : "r" (__arg1)); \ __value; \ }) #endif #endif pari-2.11.2/src/functions/0000755000175000017500000000000013461316051013755 5ustar billbillpari-2.11.2/src/functions/default/0000755000175000017500000000000013461316051015401 5ustar billbillpari-2.11.2/src/functions/default/new_galois_format0000644000175000017500000000072413201017466021026 0ustar billbillFunction: _def_new_galois_format Class: default Section: default C-Name: sd_new_galois_format Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). If on, the \tet{polgalois} command will use a different, more consistent, naming scheme for Galois groups. This default is provided to ensure that scripts can control this behavior and do not break unexpectedly. The default value is \kbd{0}. This value will change to $1$ (set) in the next major version. pari-2.11.2/src/functions/default/plothsizes0000644000175000017500000000034213326135265017535 0ustar billbillFunction: _def_plothsizes Class: default Section: default C-Name: sd_plothsizes Prototype: Help: Doc: if the graphic driver allows it, the array contains the size of the terminal, the size of the font, the size of the ticks. pari-2.11.2/src/functions/default/realprecision0000644000175000017500000000243113326135265020171 0ustar billbillFunction: _def_realprecision Class: default Section: default C-Name: sd_realprecision Prototype: Help: Doc: the number of significant digits used to convert exact inputs given to transcendental functions (see \secref{se:trans}), or to create absolute floating point constants (input as \kbd{1.0} or \kbd{Pi} for instance). Unless you tamper with the \tet{format} default, this is also the number of significant digits used to print a \typ{REAL} number; \kbd{format} will override this latter behavior, and allow you to have a large internal precision while outputting few digits for instance. Note that PARI's internal precision works on a word basis (by increments of 32 or 64 bits), hence may be a little larger than the number of decimal digits you expected. For instance to get 2 decimal digits you need one word of precision which, on a 64-bit machine, actually gives you 19 digits ($19 < \log_{10}(2^{64}) < 20$). The value returned when typing \kbd{default(realprecision)} is the internal number of significant digits, not the number of printed digits: \bprog ? default(realprecision, 2) realprecision = 19 significant digits (2 digits displayed) ? default(realprecision) %1 = 19 @eprog The default value is \kbd{38}, resp.~\kbd{28}, on a 64-bit, resp.~32-bit, machine. pari-2.11.2/src/functions/default/factor_proven0000644000175000017500000000124013201017466020170 0ustar billbillFunction: _def_factor_proven Class: default Section: default C-Name: sd_factor_proven Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). By default, the factors output by the integer factorization machinery are only pseudo-primes, not proven primes. If this toggle is set, a primality proof is done for each factor and all results depending on integer factorization are fully proven. This flag does not affect partial factorization when it is explicitly requested. It also does not affect the private table managed by \tet{addprimes}: its entries are included as is in factorizations, without being tested for primality. The default value is \kbd{0}. pari-2.11.2/src/functions/default/format0000644000175000017500000000260313201017466016615 0ustar billbillFunction: _def_format Class: default Section: default C-Name: sd_format Prototype: Help: Doc: of the form x$.n$, where x (conversion style) is a letter in $\{\kbd{e},\kbd{f},\kbd{g}\}$, and $n$ (precision) is an integer; this affects the way real numbers are printed: \item If the conversion style is \kbd{e}, real numbers are printed in \idx{scientific format}, always with an explicit exponent, e.g.~\kbd{3.3 E-5}. \item In style \kbd{f}, real numbers are generally printed in \idx{fixed floating point format} without exponent, e.g.~\kbd{0.000033}. A large real number, whose integer part is not well defined (not enough significant digits), is printed in style~\kbd{e}. For instance \kbd{10.\pow 100} known to ten significant digits is always printed in style \kbd{e}. \item In style \kbd{g}, non-zero real numbers are printed in \kbd{f} format, except when their decimal exponent is $< -4$, in which case they are printed in \kbd{e} format. Real zeroes (of arbitrary exponent) are printed in \kbd{e} format. The precision $n$ is the number of significant digits printed for real numbers, except if $n<0$ where all the significant digits will be printed (initial default 28, or 38 for 64-bit machines). For more powerful formatting possibilities, see \tet{printf} and \tet{Strprintf}. The default value is \kbd{"g.28"} and \kbd{"g.38"} on 32-bit and 64-bit machines, respectively. pari-2.11.2/src/functions/default/sopath0000644000175000017500000000147212314242551016625 0ustar billbillFunction: _def_sopath Class: default Section: default C-Name: sd_sopath Prototype: Help: Doc: this is a list of directories, separated by colons ':' (semicolons ';' in the DOS world, since colons are preempted for drive names). When asked to \tet{install} an external symbol from a shared library whose name is not given by an absolute path (does not start with \kbd{/}, \kbd{./} or \kbd{../}), \kbd{gp} will look for it in these directories, in the order they were written in \kbd{sopath}. Here, as usual, \kbd{.} means the current directory, and \kbd{..} its immediate parent. Environment expansion is performed. The default value is \kbd{""}, corresponding to an empty list of directories: \tet{install} will use the library name as input (and look in the current directory if the name is not an absolute path). pari-2.11.2/src/functions/default/lines0000644000175000017500000000105113201017466016433 0ustar billbillFunction: _def_lines Class: default Section: default C-Name: sd_lines Prototype: Help: Doc: if set to a positive value, \kbd{gp} prints at most that many lines from each result, terminating the last line shown with \kbd{[+++]} if further material has been suppressed. The various \kbd{print} commands (see \secref{se:gp_program}) are unaffected, so you can always type \kbd{print(\%)} or \b{a} to view the full result. If the actual screen width cannot be determined, a ``line'' is assumed to be 80 characters long. The default value is \kbd{0}. pari-2.11.2/src/functions/default/debugfiles0000644000175000017500000000046311636712103017440 0ustar billbillFunction: _def_debugfiles Class: default Section: default C-Name: sd_debugfiles Prototype: Help: Doc: file usage debugging level. If it is non-zero, \kbd{gp} will print information on file descriptors in use, from PARI's point of view (see~\b{gf}). The default value is \kbd{0} (no debugging messages). pari-2.11.2/src/functions/default/threadsize0000644000175000017500000000220613326135265017474 0ustar billbillFunction: _def_threadsize Class: default Section: default C-Name: sd_threadsize Prototype: Help: Doc: This default is specific to the \emph{parallel} version of PARI and gp (built via \kbd{Configure --mt=prthread} or \kbd{mpi}) and is ignored otherwise. In parallel mode, each thread allocates its own private \tev{stack} for its computations, see \kbd{parisize}. This value determines the size in bytes of the stacks of each thread, so the total memory allocated will be $\kbd{parisize}+\kbd{nbthreads}\times\kbd{threadsize}$. If set to $0$, the value used is the same as \kbd{parisize}. It is not easy to estimate reliably a sufficient value for this parameter because PARI itself will parallelize computations and we recommend to not set this value explicitly unless it solves a specific problem for you. For instance if you see frequent messages of the form \bprog *** Warning: not enough memory, new thread stack 10000002048 @eprog (Meaning that \kbd{threadsize} had to be temporarily increased.) On the other hand we strongly recommend to set \kbd{parisizemax} and \kbd{threadsizemax} to a non-zero value. The default value is $0$. pari-2.11.2/src/functions/default/histsize0000644000175000017500000000067311636712103017174 0ustar billbillFunction: _def_histsize Class: default Section: default C-Name: sd_histsize Prototype: Help: Doc: \kbd{gp} keeps a history of the last \kbd{histsize} results computed so far, which you can recover using the \kbd{\%} notation (see \secref{se:history}). When this number is exceeded, the oldest values are erased. Tampering with this default is the only way to get rid of the ones you do not need anymore. The default value is \kbd{5000}. pari-2.11.2/src/functions/default/prompt_cont0000644000175000017500000000053313201017466017671 0ustar billbillFunction: _def_prompt_cont Class: default Section: default C-Name: sd_prompt_cont Prototype: Help: Doc: a string that will be printed to prompt for continuation lines (e.g. in between braces, or after a line-terminating backslash). Everything that applies to \kbd{prompt} applies to \kbd{prompt\_cont} as well. The default value is \kbd{""}. pari-2.11.2/src/functions/default/help0000644000175000017500000000060413201017466016254 0ustar billbillFunction: _def_help Class: default Section: default C-Name: sd_help Prototype: Help: Doc: name of the external help program to use from within \kbd{gp} when extended help is invoked, usually through a \kbd{??} or \kbd{???} request (see \secref{se:exthelp}), or \kbd{M-H} under readline (see \secref{se:readline}). The default value is the path to the \kbd{gphelp} script we install. pari-2.11.2/src/functions/default/graphcolormap0000644000175000017500000000176613326135265020202 0ustar billbillFunction: _def_graphcolormap Class: default Section: default C-Name: sd_graphcolormap Prototype: Help: Doc: a vector of colors, to be used by hi-res graphing routines. Its length is arbitrary, but it must contain at least 3 entries: the first 3 colors are used for background, frame/ticks and axes respectively. All colors in the colormap may be freely used in \tet{plotcolor} calls. A color is either given as in the default by character strings or by an RGB code. For valid color names, see the standard \kbd{rgb.txt} file in X11 distributions, where we restrict to lowercase letters and remove all whitespace from color names. An RGB code is a vector with 3 integer entries between 0 and 255 or a \kbd{\#} followed by 6 hexadecimal digits. For instance \kbd{[250, 235, 215]}, \kbd{"\#faebd7"} and \kbd{"antiquewhite"} all represent the same color. The default value is [\kbd{"white"}, \kbd{"black"}, \kbd{"blue"}, \kbd{"violetred"}, \kbd{"red"}, \kbd{"green"}, \kbd{"grey"}, \kbd{"gainsboro"}]. pari-2.11.2/src/functions/default/primelimit0000644000175000017500000000331212314242551017475 0ustar billbillFunction: _def_primelimit Class: default Section: default C-Name: sd_primelimit Prototype: Help: Doc: \kbd{gp} precomputes a list of all primes less than \kbd{primelimit} at initialization time, and can build fast sieves on demand to quickly iterate over primes up to the \emph{square} of \kbd{primelimit}. These are used by many arithmetic functions, usually for trial division purposes. The maximal value is $2^{32} - 2049$ (resp $2^{64} - 2049$) on a 32-bit (resp.~64-bit) machine, but values beyond $10^8$, allowing to iterate over primes up to $10^{16}$, do not seem useful. Since almost all arithmetic functions eventually require some table of prime numbers, PARI guarantees that the first 6547 primes, up to and including 65557, are precomputed, even if \kbd{primelimit} is $1$. This default is only used on startup: changing it will not recompute a new table. \misctitle{Deprecated feature} \kbd{primelimit} was used in some situations by algebraic number theory functions using the \tet{nf_PARTIALFACT} flag (\tet{nfbasis}, \tet{nfdisc}, \tet{nfinit}, \dots): this assumes that all primes $p > \kbd{primelimit}$ have a certain property (the equation order is $p$-maximal). This is never done by default, and must be explicitly set by the user of such functions. Nevertheless, these functions now provide a more flexible interface, and their use of the global default \kbd{primelimit} is deprecated. \misctitle{Deprecated feature} \kbd{factor(N, 0)} was used to partially factor integers by removing all prime factors $\leq$ \kbd{primelimit}. Don't use this, supply an explicit bound: \kbd{factor(N, bound)}, which avoids relying on an unpredictable global variable. The default value is \kbd{500k}. pari-2.11.2/src/functions/default/seriesprecision0000644000175000017500000000040111636712103020525 0ustar billbillFunction: _def_seriesprecision Class: default Section: default C-Name: sd_seriesprecision Prototype: Help: Doc: number of significant terms when converting a polynomial or rational function to a power series (see~\b{ps}). The default value is \kbd{16}. pari-2.11.2/src/functions/default/HEADER0000644000175000017500000000043413326135265016263 0ustar billbillFunction: _header_default Class: header Section: default Doc: \section{GP defaults} \label{se:gp_defaults} This section documents the GP defaults, that can be set either by the GP function \tet{default} or in your GPRC. Be sure to check out \tet{parisize} and \tet{parisizemax} ! pari-2.11.2/src/functions/default/simplify0000644000175000017500000000154411636712103017164 0ustar billbillFunction: _def_simplify Class: default Section: default C-Name: sd_simplify Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). When the PARI library computes something, the type of the result is not always the simplest possible. The only type conversions which the PARI library does automatically are rational numbers to integers (when they are of type \typ{FRAC} and equal to integers), and similarly rational functions to polynomials (when they are of type \typ{RFRAC} and equal to polynomials). This feature is useful in many cases, and saves time, but can be annoying at times. Hence you can disable this and, whenever you feel like it, use the function \kbd{simplify} (see Chapter 3) which allows you to simplify objects to the simplest possible types recursively (see~\b{y}). \sidx{automatic simplification} The default value is \kbd{1}. pari-2.11.2/src/functions/default/psfile0000644000175000017500000000035313326135265016615 0ustar billbillFunction: _def_psfile Class: default Section: default C-Name: sd_psfile Prototype: Obsolete: 2018-02-01 Help: Doc: This default is obsolete, use one of plotexport, plothexport or plothrawexport functions and write the result to file. pari-2.11.2/src/functions/default/recover0000644000175000017500000000046513201017466016776 0ustar billbillFunction: _def_recover Class: default Section: default C-Name: sd_recover Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). If you change this to $0$, any error becomes fatal and causes the gp interpreter to exit immediately. Can be useful in batch job scripts. The default value is \kbd{1}. pari-2.11.2/src/functions/default/TeXstyle0000644000175000017500000000100411636712103017100 0ustar billbillFunction: _def_TeXstyle Class: default Section: default C-Name: sd_TeXstyle Prototype: Help: Doc: the bits of this default allow \kbd{gp} to use less rigid TeX formatting commands in the logfile. This default is only taken into account when $\kbd{log} = 3$. The bits of \kbd{TeXstyle} have the following meaning 2: insert \kbd{\bs right} / \kbd{\bs left} pairs where appropriate. 4: insert discretionary breaks in polynomials, to enhance the probability of a good line break. The default value is \kbd{0}. pari-2.11.2/src/functions/default/path0000644000175000017500000000131011636712103016253 0ustar billbillFunction: _def_path Class: default Section: default C-Name: sd_path Prototype: Help: Doc: this is a list of directories, separated by colons ':' (semicolons ';' in the DOS world, since colons are preempted for drive names). When asked to read a file whose name is not given by an absolute path (does not start with \kbd{/}, \kbd{./} or \kbd{../}), \kbd{gp} will look for it in these directories, in the order they were written in \kbd{path}. Here, as usual, \kbd{.} means the current directory, and \kbd{..} its immediate parent. Environment expansion is performed. The default value is \kbd{".:\til:\til/gp"} on UNIX systems, \kbd{".;C:\bs;C:\bs GP"} on DOS, OS/2 and Windows, and \kbd{"."} otherwise. pari-2.11.2/src/functions/default/nbthreads0000644000175000017500000000134313326135265017305 0ustar billbillFunction: _def_nbthreads Class: default Section: default C-Name: sd_nbthreads Prototype: Help: Doc: This default is specific to the \emph{parallel} version of PARI and gp (built via \kbd{Configure --mt=prthread} or \kbd{mpi}) and is ignored otherwise. In parallel mode, it governs the number of threads to use for parallel computing. The exact meaning and default value depend on the \kbd{mt} engine used: \item \kbd{single}: not used (always a single thread). \item \kbd{pthread}: number of threads (unlimited, default: number of cores) \item \kbd{mpi}: number of MPI processes to use (limited to the number allocated by \kbd{mpirun}, default: use all allocated processes). See also \kbd{threadsize} and \kbd{threadsizemax}. pari-2.11.2/src/functions/default/readline0000644000175000017500000000066313201017466017114 0ustar billbillFunction: _def_readline Class: default Section: default C-Name: sd_readline Prototype: Help: Doc: switches readline line-editing facilities on and off. This may be useful if you are running \kbd{gp} in a Sun \tet{cmdtool}, which interacts badly with readline. Of course, until readline is switched on again, advanced editing features like automatic completion and editing history are not available. The default value is \kbd{1}. pari-2.11.2/src/functions/default/colors0000644000175000017500000000420313036414402016621 0ustar billbillFunction: _def_colors Class: default Section: default C-Name: sd_colors Prototype: Help: Doc: this default is only usable if \kbd{gp} is running within certain color-capable terminals. For instance \kbd{rxvt}, \kbd{color\_xterm} and modern versions of \kbd{xterm} under X Windows, or standard Linux/DOS text consoles. It causes \kbd{gp} to use a small palette of colors for its output. With xterms, the colormap used corresponds to the resources \kbd{Xterm*color$n$} where $n$ ranges from $0$ to $15$ (see the file \kbd{misc/color.dft} for an example). Accepted values for this default are strings \kbd{"$a_1$,\dots,$a_k$"} where $k\le7$ and each $a_i$ is either \noindent\item the keyword \kbd{no} (use the default color, usually black on transparent background) \noindent\item an integer between 0 and 15 corresponding to the aforementioned colormap \noindent\item a triple $[c_0,c_1,c_2]$ where $c_0$ stands for foreground color, $c_1$ for background color, and $c_2$ for attributes (0 is default, 1 is bold, 4 is underline). The output objects thus affected are respectively error messages, history numbers, prompt, input line, output, help messages, timer (that's seven of them). If $k < 7$, the remaining $a_i$ are assumed to be $no$. For instance % \bprog default(colors, "9, 5, no, no, 4") @eprog \noindent typesets error messages in color $9$, history numbers in color $5$, output in color $4$, and does not affect the rest. A set of default colors for dark (reverse video or PC console) and light backgrounds respectively is activated when \kbd{colors} is set to \kbd{darkbg}, resp.~\kbd{lightbg} (or any proper prefix: \kbd{d} is recognized as an abbreviation for \kbd{darkbg}). A bold variant of \kbd{darkbg}, called \kbd{boldfg}, is provided if you find the former too pale. \emacs In the present version, this default is incompatible with PariEmacs. Changing it will just fail silently (the alternative would be to display escape sequences as is, since Emacs will refuse to interpret them). You must customize color highlighting from the PariEmacs side, see its documentation. The default value is \kbd{""} (no colors). pari-2.11.2/src/functions/default/timer0000644000175000017500000000164113201017466016446 0ustar billbillFunction: _def_timer Class: default Section: default C-Name: sd_timer Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). Every instruction sequence in the gp calculator (anything ended by a newline in your input) is timed, to some accuracy depending on the hardware and operating system. When \tet{timer} is on, each such timing is printed immediately before the output as follows: \bprog ? factor(2^2^7+1) time = 108 ms. \\ this line omitted if 'timer' is 0 %1 = [ 59649589127497217 1] [5704689200685129054721 1] @eprog\noindent (See also \kbd{\#} and \kbd{\#\#}.) The time measured is the user \idx{CPU time}, \emph{not} including the time for printing the results. If the time is negligible ($< 1$ ms.), nothing is printed: in particular, no timing should be printed when defining a user function or an alias, or installing a symbol from the library. The default value is \kbd{0} (off). pari-2.11.2/src/functions/default/debug0000644000175000017500000000041011636712103016405 0ustar billbillFunction: _def_debug Class: default Section: default C-Name: sd_debug Prototype: Help: Doc: debugging level. If it is non-zero, some extra messages may be printed, according to what is going on (see~\b{g}). The default value is \kbd{0} (no debugging messages). pari-2.11.2/src/functions/default/output0000644000175000017500000000257313036414402016670 0ustar billbillFunction: _def_output Class: default Section: default C-Name: sd_output Prototype: Help: Doc: there are three possible values: 0 (=~\var{raw}), 1 (=~\var{prettymatrix}), or 3 (=~\var{external} \var{prettyprint}). This means that, independently of the default \kbd{format} for reals which we explained above, you can print results in three ways: \item \tev{raw format}, i.e.~a format which is equivalent to what you input, including explicit multiplication signs, and everything typed on a line instead of two dimensional boxes. This can have several advantages, for instance it allows you to pick the result with a mouse or an editor, and to paste it somewhere else. \item \tev{prettymatrix format}: this is identical to raw format, except that matrices are printed as boxes instead of horizontally. This is prettier, but takes more space and cannot be used for input. Column vectors are still printed horizontally. \item \tev{external prettyprint}: pipes all \kbd{gp} output in TeX format to an external prettyprinter, according to the value of \tet{prettyprinter}. The default script (\tet{tex2mail}) converts its input to readable two-dimensional text. Independently of the setting of this default, an object can be printed in any of the three formats at any time using the commands \b{a} and \b{m} and \b{B} respectively. The default value is \kbd{1} (\var{prettymatrix}). pari-2.11.2/src/functions/default/graphcolors0000644000175000017500000000062013201017466017645 0ustar billbillFunction: _def_graphcolors Class: default Section: default C-Name: sd_graphcolors Prototype: Help: Doc: entries in the \tet{graphcolormap} that will be used to plot multi-curves. The successive curves are drawn in colors \kbd{graphcolormap[graphcolors[1]]}, \kbd{graphcolormap[graphcolors[2]]}, \dots cycling when the \kbd{graphcolors} list is exhausted. The default value is \kbd{[4,5]}. pari-2.11.2/src/functions/default/debugmem0000644000175000017500000000171013326135265017116 0ustar billbillFunction: _def_debugmem Class: default Section: default C-Name: sd_debugmem Prototype: Help: Doc: memory debugging level (see \b{gm}). If this is non-zero, \kbd{gp} will print increasingly precise notifications about memory use: \item $\kbd{debugmem} > 0$, notify when \kbd{parisize} changes (within the boundaries set by \kbd{parisizemax}); \item $\kbd{debugmem} > 1$, indicate any important garbage collection and the function it is taking place in; \item $\kbd{debugmem} > 2$, indicate the creation/destruction of ``blocks'' (or clones); expect lots of messages. \noindent {\bf Important Note:} if you are running a version compiled for debugging (see Appendix~A) and $\kbd{debugmem} > 1$, \kbd{gp} will further regularly print information on memory usage, notifying whenever stack usage goes up or down by 1 MByte. This functionality is disabled on non-debugging builds as it noticeably slows down the performance. The default value is \kbd{1}. pari-2.11.2/src/functions/default/parisize0000644000175000017500000000157713326135265017172 0ustar billbillFunction: _def_parisize Class: default Section: default C-Name: sd_parisize Prototype: Help: Doc: \kbd{gp}, and in fact any program using the PARI library, needs a \tev{stack} in which to do its computations; \kbd{parisize} is the stack size, in bytes. It is recommended to increase this default using a \tet{gprc}, to the value you believe PARI should be happy with, given your typical computation. We strongly recommend to also set \tet{parisizemax} to a much larger value in your \kbd{gprc}, about what you believe your machine can stand: PARI will then try to fit its computations within about \kbd{parisize} bytes, but will increase the stack size if needed (up to \kbd{parisizemax}). Once the memory intensive computation is over, PARI will restore the stack size to the originally requested \kbd{parisize}. The default value is 4M, resp.~8M on a 32-bit, resp.~64-bit machine. pari-2.11.2/src/functions/default/strictargs0000644000175000017500000000150013201017466017505 0ustar billbillFunction: _def_strictargs Class: default Section: default C-Name: sd_strictargs Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). If on, all arguments to \emph{new} user functions are mandatory unless the function supplies an explicit default value. Otherwise arguments have the default value $0$. In this example, \bprog fun(a,b=2)=a+b @eprog \kbd{a} is mandatory, while \kbd{b} is optional. If \kbd{strictargs} is on: \bprog ? fun() *** at top-level: fun() *** ^----- *** in function fun: a,b=2 *** ^----- *** missing mandatory argument 'a' in user function. @eprog This applies to functions defined while \kbd{strictargs} is on. Changing \kbd{strictargs} does not affect the behavior of previously defined functions. The default value is \kbd{0}. pari-2.11.2/src/functions/default/linewrap0000644000175000017500000000035513201017466017150 0ustar billbillFunction: _def_linewrap Class: default Section: default C-Name: sd_linewrap Prototype: Help: Doc: if set to a positive value, \kbd{gp} wraps every single line after printing that many characters. The default value is \kbd{0} (unset). pari-2.11.2/src/functions/default/breakloop0000644000175000017500000000044013201017466017300 0ustar billbillFunction: _def_breakloop Class: default Section: default C-Name: sd_breakloop Prototype: Help: Doc: if true, enables the ``break loop'' debugging mode, see \secref{se:break_loop}. The default value is \kbd{1} if we are running an interactive \kbd{gp} session, and \kbd{0} otherwise. pari-2.11.2/src/functions/default/prettyprinter0000644000175000017500000000061311636712103020257 0ustar billbillFunction: _def_prettyprinter Class: default Section: default C-Name: sd_prettyprinter Prototype: Help: Doc: the name of an external prettyprinter to use when \kbd{output} is~3 (alternate prettyprinter). Note that the default \tet{tex2mail} looks much nicer than the built-in ``beautified format'' ($\kbd{output} = 2$). The default value is \kbd{"tex2mail -TeX -noindent -ragged -by\_par"}. pari-2.11.2/src/functions/default/parisizemax0000644000175000017500000000231113326135265017663 0ustar billbillFunction: _def_parisizemax Class: default Section: default C-Name: sd_parisizemax Prototype: Help: Doc: \kbd{gp}, and in fact any program using the PARI library, needs a \tev{stack} in which to do its computations. If non-zero, \tet{parisizemax} is the maximum size the stack can grow to, in bytes. If zero, the stack will not automatically grow, and will be limited to the value of \kbd{parisize}. When \kbd{parisizemax} is set, PARI tries to fit its computations within about \kbd{parisize} bytes, but will increase the stack size if needed, roughly doubling it each time (up to \kbd{parisizemax} of course!) and printing a message such as \kbd{Warning: increasing stack size to} \var{some value}. Once the memory intensive computation is over, PARI will restore the stack size to the originally requested \kbd{parisize} without printing further messages. We \emph{strongly} recommend to set \tet{parisizemax} permanently to a large non-zero value in your \tet{gprc}, about what you believe your machine can stand. It is possible to increase or decrease \kbd{parisizemax} inside a running \kbd{gp} session, just use \kbd{default} as usual. The default value is $0$, for backward compatibility reasons. pari-2.11.2/src/functions/default/logfile0000644000175000017500000000037111636712103016746 0ustar billbillFunction: _def_logfile Class: default Section: default C-Name: sd_logfile Prototype: Help: Doc: name of the log file to be used when the \kbd{log} toggle is on. Environment and time expansion are performed. The default value is \kbd{"pari.log"}. pari-2.11.2/src/functions/default/factor_add_primes0000644000175000017500000000141013201017466020765 0ustar billbillFunction: _def_factor_add_primes Class: default Section: default C-Name: sd_factor_add_primes Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). If on, the integer factorization machinery calls \tet{addprimes} on prime factors that were difficult to find (larger than $2^{24}$), so they are automatically tried first in other factorizations. If a routine is performing (or has performed) a factorization and is interrupted by an error or via Control-C, this lets you recover the prime factors already found. The downside is that a huge \kbd{addprimes} table unrelated to the current computations will slow down arithmetic functions relying on integer factorization; one should then empty the table using \tet{removeprimes}. The default value is \kbd{0}. pari-2.11.2/src/functions/default/log0000644000175000017500000000140611636712103016106 0ustar billbillFunction: _def_log Class: default Section: default C-Name: sd_log Prototype: Help: Doc: this can be either 0 (off) or 1, 2, 3 (on, see below for the various modes). When logging mode is turned on, \kbd{gp} opens a log file, whose exact name is determined by the \kbd{logfile} default. Subsequently, all the commands and results will be written to that file (see \b{l}). In case a file with this precise name already existed, it will not be erased: your data will be \emph{appended} at the end. The specific positive values of \kbd{log} have the following meaning 1: plain logfile 2: emit color codes to the logfile (if \kbd{colors} is set). 3: write LaTeX output to the logfile (can be further customized using \tet{TeXstyle}). The default value is \kbd{0}. pari-2.11.2/src/functions/default/histfile0000644000175000017500000000131113326135265017135 0ustar billbillFunction: _def_histfile Class: default Section: default C-Name: sd_histfile Prototype: Help: Doc: name of a file where \kbd{gp} will keep a history of all \emph{input} commands (results are omitted). If this file exists when the value of \kbd{histfile} changes, it is read in and becomes part of the session history. Thus, setting this default in your gprc saves your readline history between sessions. Setting this default to the empty string \kbd{""} changes it to \kbd{$<$undefined$>$}. Note that, by default, the number of history entries saved is not limited: set \kbd{history-size} in readline's \kbd{.inputrc} to limit the file size. The default value is \kbd{$<$undefined$>$} (no history file). pari-2.11.2/src/functions/default/threadsizemax0000644000175000017500000000157313326135265020210 0ustar billbillFunction: _def_threadsizemax Class: default Section: default C-Name: sd_threadsizemax Prototype: Help: Doc: This default is specific to the \emph{parallel} version of PARI and gp (built via \kbd{Configure --mt=pthread} or \kbd{mpi}) and is ignored otherwise. In parallel mode, each threads allocates its own private \tev{stack} for its computations, see \kbd{parisize} and \kbd{parisizemax}. The values of \kbd{threadsize} and \kbd{threadsizemax} determine the usual and maximal size in bytes of the stacks of each thread, so the total memory allocated will be between $\kbd{parisize}+\kbd{nbthreads}\times\kbd{threadsize}$. and $\kbd{parisizemax}+\kbd{nbthreads}\times\kbd{threadsizemax}$. If set to $0$, the value used is the same as \kbd{threadsize}. We strongy recommend to set both \kbd{parisizemax} and \kbd{threadsizemax} to a non-zero value. The default value is $0$. pari-2.11.2/src/functions/default/prompt0000644000175000017500000000265113201017466016651 0ustar billbillFunction: _def_prompt Class: default Section: default C-Name: sd_prompt Prototype: Help: Doc: a string that will be printed as prompt. Note that most usual escape sequences are available there: \b{e} for Esc, \b{n} for Newline, \dots, \kbd{\bs\bs} for \kbd{\bs}. Time expansion is performed. This string is sent through the library function \tet{strftime} (on a Unix system, you can try \kbd{man strftime} at your shell prompt). This means that \kbd{\%} constructs have a special meaning, usually related to the time and date. For instance, \kbd{\%H} = hour (24-hour clock) and \kbd{\%M} = minute [00,59] (use \kbd{\%\%} to get a real \kbd{\%}). If you use \kbd{readline}, escape sequences in your prompt will result in display bugs. If you have a relatively recent \kbd{readline} (see the comment at the end of \secref{se:def,colors}), you can brace them with special sequences (\kbd{\bs[} and \kbd{\bs]}), and you will be safe. If these just result in extra spaces in your prompt, then you'll have to get a more recent \kbd{readline}. See the file \kbd{misc/gprc.dft} for an example. \emacs {\bf Caution}: PariEmacs needs to know about the prompt pattern to separate your input from previous \kbd{gp} results, without ambiguity. It is not a trivial problem to adapt automatically this regular expression to an arbitrary prompt (which can be self-modifying!). See PariEmacs's documentation. The default value is \kbd{"? "}. pari-2.11.2/src/functions/default/datadir0000644000175000017500000000055213201017466016736 0ustar billbillFunction: _def_datadir Class: default Section: default C-Name: sd_datadir Prototype: Help: Doc: the name of directory containing the optional data files. For now, this includes the \kbd{elldata}, \kbd{galdata}, \kbd{galpol}, \kbd{seadata} packages. The default value is \kbd{/usr/local/share/pari}, or the override specified via \kbd{Configure --datadir=}. pari-2.11.2/src/functions/default/strictmatch0000644000175000017500000000024313201017466017650 0ustar billbillFunction: _def_strictmatch Class: default Section: default C-Name: sd_strictmatch Prototype: Help: Obsolete: 2014-10-11 Doc: Obsolete. This toggle is now a no-op. pari-2.11.2/src/functions/default/echo0000644000175000017500000000124113326135265016246 0ustar billbillFunction: _def_echo Class: default Section: default C-Name: sd_echo Prototype: Help: Doc: this default can be 0 (off), 1 (on) or 2 (on, raw). When \kbd{echo} mode is on, each command is reprinted before being executed. This can be useful when reading a file with the \b{r} or \kbd{read} commands. For example, it is turned on at the beginning of the test files used to check whether \kbd{gp} has been built correctly (see \b{e}). When \kbd{echo} is set to 1 the input is cleaned up, removing white space and comments and uniting multi-line input. When set to 2 (raw), the input is written as-is, without any pre-processing. The default value is \kbd{0} (no echo). pari-2.11.2/src/functions/default/realbitprecision0000644000175000017500000000330513326135265020671 0ustar billbillFunction: _def_realbitprecision Class: default Section: default C-Name: sd_realbitprecision Prototype: Help: Doc: the number of significant bits used to convert exact inputs given to transcendental functions (see \secref{se:trans}), or to create absolute floating point constants (input as \kbd{1.0} or \kbd{Pi} for instance). Unless you tamper with the \tet{format} default, this is also the number of significant bits used to print a \typ{REAL} number; \kbd{format} will override this latter behavior, and allow you to have a large internal precision while outputting few digits for instance. Note that most PARI's functions currently handle precision on a word basis (by increments of 32 or 64 bits), hence bit precision may be a little larger than the number of bits you expected. For instance to get 10 bits of precision, you need one word of precision which, on a 64-bit machine, correspond to 64 bits. To make things even more confusing, this internal bit accuracy is converted to decimal digits when printing floating point numbers: now 64 bits correspond to 19 printed decimal digits ($19 < \log_{10}(2^{64}) < 20$). The value returned when typing \kbd{default(realbitprecision)} is the internal number of significant bits, not the number of printed decimal digits: \bprog ? default(realbitprecision, 10) ? \pb realbitprecision = 64 significant bits ? default(realbitprecision) %1 = 64 ? \p realprecision = 3 significant digits ? default(realprecision) %2 = 19 @eprog\noindent Note that \tet{realprecision} and \kbd{\bs p} allow to view and manipulate the internal precision in decimal digits. The default value is \kbd{128}, resp.~\kbd{96}, on a 64-bit, resp~.32-bit, machine. pari-2.11.2/src/functions/default/compatible0000644000175000017500000000024213201017466017441 0ustar billbillFunction: _def_compatible Class: default Section: default C-Name: sd_compatible Prototype: Help: Obsolete: 2014-10-11 Doc: Obsolete. This default is now a no-op. pari-2.11.2/src/functions/default/secure0000644000175000017500000000071011636712103016610 0ustar billbillFunction: _def_secure Class: default Section: default C-Name: sd_secure Prototype: Help: Doc: this toggle is either 1 (on) or 0 (off). If on, the \tet{system} and \tet{extern} command are disabled. These two commands are potentially dangerous when you execute foreign scripts since they let \kbd{gp} execute arbitrary UNIX commands. \kbd{gp} will ask for confirmation before letting you (or a script) unset this toggle. The default value is \kbd{0}. pari-2.11.2/src/functions/modular_symbols/0000755000175000017500000000000013461316051017170 5ustar billbillpari-2.11.2/src/functions/modular_symbols/mslattice0000644000175000017500000000334013326135265021106 0ustar billbillFunction: mslattice Section: modular_symbols C-Name: mslattice Prototype: GDG Help: mslattice(M, {H}): M being a full modular symbol space, as given by msinit, H a Q-subspace or a matrix of modular symbols. Return the canonical integral structure of H. Doc: Let $\Delta:=\text{Div}^0(\P^1(\Q))$ and $V_k = \Q[x,y]_{k-2}$. Let $M$ be a full modular symbol space, as given by \kbd{msinit} and let $H$ be a subspace, e.g. as given by \kbd{mscuspidal}. This function returns a canonical $\Z$ structure on $H$ defined as follows. Consider the map $c: M=\Hom_{\Gamma_0(N)}(\Delta, V_k) \to H^1(\Gamma_0(N), V_k)$ given by $\phi \mapsto \var{class}(\gamma \to \phi(\{0, \gamma^{-1} 0\}))$. Let $L_k=\Z[x,y]_{k-2}$ be the natural $\Z$-structure of $V_k$. The result of \kbd{mslattice} is a $\Z$-basis of the inverse image by $c$ of $H^1(\Gamma_0(N), L_k)$ in the space of modular symbols generated by $H$. For user convenience, $H$ can be defined by a matrix representing the $\Q$-basis of $H$ (in terms of the canonical $\Q$-basis of $M$ fixed by \kbd{msinit} and used to represent modular symbols). If omitted, $H$ is the cuspidal part of $M$ as given by \kbd{mscuspidal}. The Eisenstein part $\Hom_{\Gamma_0(N)}(\text{Div}(\P^1(\Q)), V_k)$ is in the kernel of $c$, so the result has no meaning for the Eisenstein part \kbd{H}. \bprog ? M=msinit(11,2); ? [S,E] = mscuspidal(M,1); S[1] \\ a primitive Q-basis of S %2 = [ 1 1] [-5 0] [ 0 -5] ? mslattice(M,S) %3 = [-1/5 -1/5] [ 1 0] [ 0 1] ? mslattice(M,E) %4 = [1] [0] [0] ? M=msinit(5,4); ? S=mscuspidal(M); S[1] %6 = [ 7 20] [ 3 3] [-10 -23] [-30 -30] ? mslattice(M,S) %7 = [-1/10 -11/130] [ 0 -1/130] [ 1/10 6/65] [ 0 1/13] @eprog pari-2.11.2/src/functions/modular_symbols/mspadicL0000644000175000017500000001005213201017466020645 0ustar billbillFunction: mspadicL Section: modular_symbols C-Name: mspadicL Prototype: GDGD0,L, Help: mspadicL(mu, {s = 0}, {r = 0}): given mu from mspadicmoments (p-adic distributions attached to an overconvergent symbol PHI) returns the value on a character of Z_p^* represented by s of the derivative of order r of the p-adic L-function attached to PHI. Doc: Returns the value (or $r$-th derivative) on a character $\chi^s$ of $\Z_p^*$ of the $p$-adic $L$-function attached to \kbd{mu}. Let $\Phi$ be the $p$-adic distribution-valued overconvergent symbol attached to a modular symbol $\phi$ for $\Gamma_0(N)$ (eigenvector for $T_N(p)$ for the eigenvalue $a_p$). Then $L_p(\Phi,\chi^s)=L_p(\mu,s)$ is the $p$-adic $L$ function defined by $$L_p(\Phi,\chi^s)= \int_{\Z_p^*} \chi^s(z) d\mu(z)$$ where $\mu$ is the distribution on $\Z_p^*$ defined by the restriction of $\Phi([\infty]-[0])$ to $\Z_p^*$. The $r$-th derivative is taken in direction $\langle \chi\rangle$: $$L_p^{(r)}(\Phi,\chi^s)= \int_{\Z_p^*} \chi^s(z) (\log z)^r d\mu(z).$$ In the argument list, \item \kbd{mu} is as returned by \tet{mspadicmoments} (distributions attached to $\Phi$ by restriction to discs $a + p^\nu\Z_p$, $(a,p)=1$). \item $s=[s_1,s_2]$ with $s_1 \in \Z \subset \Z_p$ and $s_2 \bmod p-1$ or $s_2 \bmod 2$ for $p=2$, encoding the $p$-adic character $\chi^s := \langle \chi \rangle^{s_1} \tau^{s_2}$; here $\chi$ is the cyclotomic character from $\text{Gal}(\Q_p(\mu_{p^\infty})/\Q_p)$ to $\Z_p^*$, and $\tau$ is the Teichm\"uller character (for $p>2$ and the character of order 2 on $(\Z/4\Z)^*$ if $p=2$); for convenience, the character $[s,s]$ can also be represented by the integer $s$. When $a_p$ is a $p$-adic unit, $L_p$ takes its values in $\Q_p$. When $a_p$ is not a unit, it takes its values in the two-dimensional $\Q_p$-vector space $D_{cris}(M(\phi))$ where $M(\phi)$ is the ``motive'' attached to $\phi$, and we return the two $p$-adic components with respect to some fixed $\Q_p$-basis. \bprog ? M = msinit(3,6,1); phi=[5, -3, -1]~; ? msissymbol(M,phi) %2 = 1 ? Mp = mspadicinit(M, 5, 4); ? mu = mspadicmoments(Mp, phi); \\ no twist \\ End of initializations ? mspadicL(mu,0) \\ L_p(chi^0) %5 = 5 + 2*5^2 + 2*5^3 + 2*5^4 + ... ? mspadicL(mu,1) \\ L_p(chi), zero for parity reasons %6 = [O(5^13)]~ ? mspadicL(mu,2) \\ L_p(chi^2) %7 = 3 + 4*5 + 4*5^2 + 3*5^5 + ... ? mspadicL(mu,[0,2]) \\ L_p(tau^2) %8 = 3 + 5 + 2*5^2 + 2*5^3 + ... ? mspadicL(mu, [1,0]) \\ L_p() %9 = 3*5 + 2*5^2 + 5^3 + 2*5^7 + 5^8 + 5^10 + 2*5^11 + O(5^13) ? mspadicL(mu,0,1) \\ L_p'(chi^0) %10 = 2*5 + 4*5^2 + 3*5^3 + ... ? mspadicL(mu, 2, 1) \\ L_p'(chi^2) %11 = 4*5 + 3*5^2 + 5^3 + 5^4 + ... @eprog Now several quadratic twists: \tet{mstooms} is indicated. \bprog ? PHI = mstooms(Mp,phi); ? mu = mspadicmoments(Mp, PHI, 12); \\ twist by 12 ? mspadicL(mu) %14 = 5 + 5^2 + 5^3 + 2*5^4 + ... ? mu = mspadicmoments(Mp, PHI, 8); \\ twist by 8 ? mspadicL(mu) %16 = 2 + 3*5 + 3*5^2 + 2*5^4 + ... ? mu = mspadicmoments(Mp, PHI, -3); \\ twist by -3 < 0 ? mspadicL(mu) %18 = O(5^13) \\ always 0, phi is in the + part and D < 0 @eprog One can locate interesting symbols of level $N$ and weight $k$ with \kbd{msnew} and \kbd{mssplit}. Note that instead of a symbol, one can input a 1-dimensional Hecke-subspace from \kbd{mssplit}: the function will automatically use the underlying basis vector. \bprog ? M=msinit(5,4,1); \\ M_4(Gamma_0(5))^+ ? L = mssplit(M, msnew(M)); \\ list of irreducible Hecke-subspaces ? phi = L[1]; \\ one Galois orbit of newforms ? #phi[1] \\... this one is rational %4 = 1 ? Mp = mspadicinit(M, 3, 4); ? mu = mspadicmoments(Mp, phi); ? mspadicL(mu) %7 = 1 + 3 + 3^3 + 3^4 + 2*3^5 + 3^6 + O(3^9) ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ ? Mp = mspadicinit(M, 3, 4); ? L = mssplit(M, msnew(M)); ? phi = L[1]; #phi[1] \\ ... this one is two-dimensional %11 = 2 ? mu = mspadicmoments(Mp, phi); *** at top-level: mu=mspadicmoments(Mp,ph *** ^-------------------- *** mspadicmoments: incorrect type in mstooms [dim_Q (eigenspace) > 1] @eprog pari-2.11.2/src/functions/modular_symbols/msfromhecke0000644000175000017500000000225513201017466021422 0ustar billbillFunction: msfromhecke Section: modular_symbols C-Name: msfromhecke Prototype: GGDG Help: msfromhecke(M, v, {H}): given a msinit M and a vector v of pairs [p, P] (where p is prime and P is a polynomial with integer coefficients), return a basis of all modular symbols such that P(Tp) * s = 0. If H is present, it must be a Hecke-stable subspace and we restrict to s in H. Doc: given a msinit $M$ and a vector $v$ of pairs $[p, P]$ (where $p$ is prime and $P$ is a polynomial with integer coefficients), return a basis of all modular symbols such that $P(T_p)(s) = 0$. If $H$ is present, it must be a Hecke-stable subspace and we restrict to $s \in H$. When $T_p$ has a rational eigenvalue and $P(x) = x-a_p$ has degree $1$, we also accept the integer $a_p$ instead of $P$. \bprog ? E = ellinit([0,-1,1,-10,-20]) \\11a1 ? ellap(E,2) %2 = -2 ? ellap(E,3) %3 = -1 ? M = msinit(11,2); ? S = msfromhecke(M, [[2,-2],[3,-1]]) %5 = [ 1 1] [-5 0] [ 0 -5] ? mshecke(M, 2, S) %6 = [-2 0] [ 0 -2] ? M = msinit(23,4); ? S = msfromhecke(M, [[5, x^4-14*x^3-244*x^2+4832*x-19904]]); ? factor( charpoly(mshecke(M,5,S)) ) %9 = [x^4 - 14*x^3 - 244*x^2 + 4832*x - 19904 2] @eprog pari-2.11.2/src/functions/modular_symbols/mshecke0000644000175000017500000000173013201017466020533 0ustar billbillFunction: mshecke Section: modular_symbols C-Name: mshecke Prototype: GLDG Help: mshecke(M,p,{H}): M being a full modular symbol space, as given by msinit, p being a prime number, and H being a Hecke-stable subspace (M if omitted), return the matrix of T_p acting on H (U_p if p divides the level). Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, $p$ being a prime number, and $H$ being a Hecke-stable subspace ($M$ if omitted) return the matrix of $T_p$ acting on $H$ ($U_p$ if $p$ divides $N$). Result is undefined if $H$ is not stable by $T_p$ (resp.~$U_p$). \bprog ? M = msinit(11,2); \\ M_2(Gamma_0(11)) ? T2 = mshecke(M,2) %2 = [3 0 0] [1 -2 0] [1 0 -2] ? M = msinit(11,2, 1); \\ M_2(Gamma_0(11))^+ ? T2 = mshecke(M,2) %4 = [ 3 0] [-1 -2] ? N = msnew(M)[1] \\ Q-basis of new cuspidal subspace %5 = [-2] [-5] ? p = 1009; mshecke(M, p, N) \\ action of T_1009 on N %6 = [-10] ? ellap(ellinit("11a1"), p) %7 = -10 @eprog pari-2.11.2/src/functions/modular_symbols/mspolygon0000644000175000017500000001221013326135265021144 0ustar billbillFunction: mspolygon Section: modular_symbols C-Name: mspolygon Prototype: GD0,L, Help: mspolygon(M, {flag = 0}): M being a full modular symbol space, as given by msinit or an integer > 1, return an hyperbolic polygon (Farey symbol) attached to the group Gamma_0(N). Binary digits of flag mean: 1=normalized polygon, 2=also add graphical representations. Doc: given an integer $N > 1$, return an hyperbolic polygon (Farey symbol) attached to the group $\Gamma_0(N)$. More precisely, \item its vertices are an ordered list in $\P^{1}(\Q)$, forming a system of representatives of cusps, \item its edges are hyperbolic arcs joining two consecutive vertices, \item given a path $(a,b)$ between two elements of $\P^{1}(\Q)$, let $\overline{(a,b)} = (b,a)$ be the opposite path. There is an involution $e \to e^*$ on the edges, where $e^*$ is $\Gamma_0(N)$ equivalent to $\overline{e}$, i.e. there exist $\gamma_e \in \Gamma_0(N)$ such that $e = \gamma_e \overline{e^*}$. The polygon is given by \item the list $E$ of its consecutive edges as matrices in $M_2(\Z)$; \item the permutation $A$ attached to the involution, such that \kbd{A[i]} is the index of $e^*$ in $E$ if $e = E[i]$ is the $i$-th edge; \item the list $G$ of pairing matrices between $e$ and $\overline{e^*}$, i.e. the matrices $\gamma_e\in \Gamma_0(N)$ such that $e = \gamma_e \overline{e^*}$. If $e = E[i]$, then $\gamma_e = G[i]$. Remark that $\gamma_{e^*}=\gamma_e^{-1}$ if $e \neq e^*$; modulo these trivial relations, the pairing matrices form a system of independant generators of $\Gamma_0(N)/\{1,-1\}$. Note that $\gamma_e$ is elliptic if and only if $e^* = e$. The above data yields a fundamental domain for $\Gamma_0(N)$ acting on Poincar\'e's half-plane: take the convex hull of the polygon defined by \item the edges in $E$ such that $e \neq e^*$ or $e^*=e$, where the pairing matrix $\gamma_e$ has order $2$; \item the edges $(r,t)$ and $(t,s)$ where the edge $e = (r,s) \in E$ is such that $e = e^*$ and $\gamma_e$ has order $3$ and the triangle $(r,t,s)$ is the image of $(0,\exp(2i\pi/3), \infty)$ by some element of $PSL_2(\Q)$ formed around the edge. Binary digits of flag mean: 1: return a normalized hyperbolic polygon if set, else a polygon with unimodular edges (matrices of determinant $1$). A polygon is normalized in the sense of compact orientable surfaces if the distance $d(a,a^*)$ between an edge $a$ and its image by the involution $a^*$ is less than 2, with equality if and only if $a$ is \emph{linked} with another edge $b$ ($a$, $b$, $a^*$ et $b^*$ appear consecutively in $E$ up to cyclic permutation). In particular, the vertices of all edges such that that $d(a,a^*) \neq 1$ (distance is 0 or 2) are all equivalent to $0$ modulo $\Gamma_0(N)$. The external vertices of $a a^*$ such that $d(a,a^*) = 1$ are also equivalent to $0$; the internal vertices $a\cap a^*$ (a single point), together with $0$, form a system of representatives of the cusps of $\Gamma_0(N)\bs \P^{1}(\Q)$. This is useful to compute the homology group $H_1(X_0(N),\Z)$ as it gives a symplectic basis for the intersection pairing. In this case, the number of parabolic matrices (trace 2) in the system of generators $G$ is $2(t-1)$, where $t$ is the number of non equivalent cusps for $\Gamma_0(N)$. 2: add graphical representations (in LaTeX form) for the hyperbolic polygon in Poincar\'e's half-space and the involution $a\to a^*$ of the Farey symbol. The corresponding character strings can be written to file and included in a LaTeX document provided the preamble contains \kbd{\bs usepackage\obr tikz\cbr}. \bprog ? [V,A,G] = mspolygon(3); ? V %2 = [[-1, 1; -1, 0], [1, 0; 0, 1], [0, 1; -1, 1]] ? A %3 = Vecsmall([2, 1, 3]) ? G %4 = [[-1, -1; 0, -1], [1, -1; 0, 1], [1, -1; 3, -2]] ? [V,A,G, D1,D2] = mspolygon(11,2); \\ D1 and D2 contains pictures ? {write("F.tex", "\\documentclass{article}\\usepackage{tikz}\\begin{document}" D1, "\n", D2, "\\end{document}");} ? [V1,A1] = mspolygon(6,1); \\ normalized ? V1 %8 = [[-1, 1; -1, 0], [1, 0; 0, 1], [0, 1; -1, 3], [1, -2; 3, -5], [-2, 1; -5, 2], [1, -1; 2, -1]] ? A1 %9 = Vecsmall([2, 1, 4, 3, 6, 5]) ? [V0,A0] = mspolygon(6); \\ not normalized V[3]^* = V[6], d(V[3],V[6]) = 3 ? A0 %11 = Vecsmall([2, 1, 6, 5, 4, 3]) ? [V,A] = mspolygon(14, 1); ? A %13 = Vecsmall([2, 1, 4, 3, 6, 5, 9, 10, 7, 8]) @eprog One can see from this last example that the (normalized) polygon has the form $$(a_1, a_1^*, a_2, a_2^*, a_3, a_3^*, a_4, a_5, a_4^*, a_5^*),$$ that $X_0(14)$ is of genus 1 (in general the genus is the number of blocks of the form $aba^*b^*$), has no elliptic points ($A$ has no fixed point) and 4 cusps (number of blocks of the form $aa^*$ plus 1). The vertices of edges $a_4$ and $a_5$ all project to $0$ in $X_0(14)$: the paths $a_4$ and $a_5$ project as loops in $X_0(14)$ and give a symplectic basis of the homology $H_1(X_0(14),\Z)$. \bprog ? [V,A] = mspolygon(15); ? apply(matdet, V) \\ all unimodular %2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ? [V,A] = mspolygon(15,1); ? apply(matdet, V) \\ normalized polygon but no longer unimodular edges %4 = [1, 1, 1, 1, 2, 2, 47, 11, 47, 11] @eprog pari-2.11.2/src/functions/modular_symbols/mspathlog0000644000175000017500000000251113326135265021116 0ustar billbillFunction: mspathlog Section: modular_symbols C-Name: mspathlog Prototype: GG Help: mspathlog(M,p): M being a full modular symbol space, as given by msinit and p being a path between two elements in P^1(Q), return (p_i) in Z[G] such that p = \sum p_i g_i, and the g_i are fixed Z[G]-generators for Div^0(P^1 Q), see mspathgens. Doc: Let $\Delta:=\text{Div}^0(\P^1(\Q))$. Let $M$ being a full modular symbol space, as given by \kbd{msinit}, encoding fixed $\Z[G]$-generators $(g_i)$ of $\Delta$ (see \tet{mspathgens}). A path $p=[a,b]$ between two elements in $\P^1(\Q)$ corresponds to $[b]-[a]\in \Delta$. The path extremities $a$ and $b$ may be given as \typ{INT}, \typ{FRAC} or $\kbd{oo} = (1:0)$. Finally, we also allow to input a path as a $2\times 2$ integer matrix, whose first and second column give $a$ and $b$ respectively, with the convention $[x,y]\til = (x:y)$ in $\P^1(\Q)$. Returns $(p_i)$ in $\Z[G]$ such that $p = \sum_i p_i g_i$. \bprog ? M = msinit(2,8); \\ M_8(Gamma_0(2)) ? [g,R] = mspathgens(M); ? g %3 = [[+oo, 0], [0, 1]] ? p = mspathlog(M, [1/2,2/3]); ? p[1] %5 = [[1, 0; 2, 1] 1] ? p[2] %6 = [[1, 0; 0, 1] 1] [[3, -1; 4, -1] 1] ? mspathlog(M, [1,2;2,3]) == p \\ give path via a 2x2 matrix %7 = 1 @eprog\noindent Note that the output depends only on the group $G$, not on the representation $V$. pari-2.11.2/src/functions/modular_symbols/msgetweight0000644000175000017500000000052213201017466021441 0ustar billbillFunction: msgetweight Section: modular_symbols C-Name: msgetweight Prototype: lG Help: msgetweight(M): M being a full modular symbol space, as given by msinit, return its weight k. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return its weight $k$. \bprog ? M = msinit(11,4); ? msgetweight(M) %2 = 4 @eprog pari-2.11.2/src/functions/modular_symbols/mspadicseries0000644000175000017500000000615413201017466021754 0ustar billbillFunction: mspadicseries Section: modular_symbols C-Name: mspadicseries Prototype: GD0,L, Help: mspadicseries(mu, {i=0}): given mu from mspadicmoments, returns the attached p-adic series with maximal p-adic precision, depending on the precision of M (i-th Teichmueller component, if present). Doc: Let $\Phi$ be the $p$-adic distribution-valued overconvergent symbol attached to a modular symbol $\phi$ for $\Gamma_0(N)$ (eigenvector for $T_N(p)$ for the eigenvalue $a_p$). If $\mu$ is the distribution on $\Z_p^*$ defined by the restriction of $\Phi([\infty]-[0])$ to $\Z_p^*$, let $$\hat{L}_p(\mu,\tau^{i})(x) = \int_{\Z_p^*} \tau^i(t) (1+x)^{\log_p(t)/\log_p(u)}d\mu(t)$$ Here, $\tau$ is the Teichm\"uller character and $u$ is a specific multiplicative generator of $1+2p\Z_p$. (Namely $1+p$ if $p>2$ or $5$ if $p=2$.) To explain the formula, let $G_\infty := \text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$, let $\chi:G_\infty\to \Z_p^*$ be the cyclotomic character (isomorphism) and $\gamma$ the element of $G_\infty$ such that $\chi(\gamma)=u$; then $\chi(\gamma)^{\log_p(t)/\log_p(u)}= \langle t \rangle$. The $p$-padic precision of individual terms is maximal given the precision of the overconvergent symbol $\mu$. \bprog ? [M,phi] = msfromell(ellinit("17a1"),1); ? Mp = mspadicinit(M, 5,7); ? mu = mspadicmoments(Mp, phi,1); \\ overconvergent symbol ? mspadicseries(mu) %4 = (4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + 4*5^6 + 3*5^7 + O(5^9)) \ + (3 + 3*5 + 5^2 + 5^3 + 2*5^4 + 5^6 + O(5^7))*x \ + (2 + 3*5 + 5^2 + 4*5^3 + 2*5^4 + O(5^5))*x^2 \ + (3 + 4*5 + 4*5^2 + O(5^3))*x^3 \ + (3 + O(5))*x^4 + O(x^5) @eprog\noindent An example with non-zero Teichm\"uller: \bprog ? [M,phi] = msfromell(ellinit("11a1"),1); ? Mp = mspadicinit(M, 3,10); ? mu = mspadicmoments(Mp, phi,1); ? mspadicseries(mu, 2) %4 = (2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 3^6 + 3^7 + 3^10 + 3^11 + O(3^12)) \ + (1 + 3 + 2*3^2 + 3^3 + 3^5 + 2*3^6 + 2*3^8 + O(3^9))*x \ + (1 + 2*3 + 3^4 + 2*3^5 + O(3^6))*x^2 \ + (3 + O(3^2))*x^3 + O(x^4) @eprog\noindent Supersingular example (not checked) \bprog ? E = ellinit("17a1"); ellap(E,3) %1 = 0 ? [M,phi] = msfromell(E,1); ? Mp = mspadicinit(M, 3,7); ? mu = mspadicmoments(Mp, phi,1); ? mspadicseries(mu) %5 = [(2*3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + 3^5 + 3^6 + O(3^7)) \ + (2 + 3^3 + O(3^5))*x \ + (1 + 2*3 + O(3^2))*x^2 + O(x^3),\ (3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + 3^5 + 3^6 + O(3^7)) \ + (1 + 2*3 + 2*3^2 + 3^3 + 2*3^4 + O(3^5))*x \ + (3^-2 + 3^-1 + O(3^2))*x^2 + O(3^-2)*x^3 + O(x^4)] @eprog\noindent Example with a twist: \bprog ? E = ellinit("11a1"); ? [M,phi] = msfromell(E,1); ? Mp = mspadicinit(M, 3,10); ? mu = mspadicmoments(Mp, phi,5); \\ twist by 5 ? L = mspadicseries(mu) %5 = (2*3^2 + 2*3^4 + 3^5 + 3^6 + 2*3^7 + 2*3^10 + O(3^12)) \ + (2*3^2 + 2*3^6 + 3^7 + 3^8 + O(3^9))*x \ + (3^3 + O(3^6))*x^2 + O(3^2)*x^3 + O(x^4) ? mspadicL(mu) %6 = [2*3^2 + 2*3^4 + 3^5 + 3^6 + 2*3^7 + 2*3^10 + O(3^12)]~ ? ellpadicL(E,3,10,,5) %7 = 2 + 2*3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + 2*3^7 + O(3^10) ? mspadicseries(mu,1) \\ must be 0 %8 = O(3^12) + O(3^9)*x + O(3^6)*x^2 + O(3^2)*x^3 + O(x^4) @eprog pari-2.11.2/src/functions/modular_symbols/msdim0000644000175000017500000000135413326135265020235 0ustar billbillFunction: msdim Section: modular_symbols C-Name: msdim Prototype: lG Help: msdim(M): M being a modular symbol space or subspace, return its dimension as a Q-vector space. Doc: $M$ being a full modular symbol space or subspace, for instance as given by \kbd{msinit} or \kbd{mscuspidal}, return its dimension as a $\Q$-vector space. \bprog ? M = msinit(11,4); msdim(M) %1 = 6 ? M = msinit(11,4,1); msdim(M) %2 = 4 \\ dimension of the '+' part ? [S,E] = mscuspidal(M,1); ? [msdim(S), msdim(E)] %4 = [2, 2] @eprog\noindent Note that \kbd{mfdim([N,k])} is going to be much faster if you only need the dimension of the space and not really to work with it. This function is only useful to quickly check the dimension of an existing space. pari-2.11.2/src/functions/modular_symbols/msatkinlehner0000644000175000017500000000152613201017466021763 0ustar billbillFunction: msatkinlehner Section: modular_symbols C-Name: msatkinlehner Prototype: GLDG Help: msatkinlehner(M,Q,{H}): M being a full modular symbol space of level N, as given by msinit, let Q | N, (Q,N/Q) = 1, and let H be a subspace stable under the Atkin-Lehner involution w_Q. Return the matrix of w_Q acting on H (M if omitted). Doc: Let $M$ be a full modular symbol space of level $N$, as given by \kbd{msinit}, let $Q \mid N$, $(Q,N/Q) = 1$, and let $H$ be a subspace stable under the Atkin-Lehner involution $w_Q$. Return the matrix of $w_Q$ acting on $H$ ($M$ if omitted). \bprog ? M = msinit(36,2); \\ M_2(Gamma_0(36)) ? w = msatkinlehner(M,4); w^2 == 1 %2 = 1 ? #w \\ involution acts on a 13-dimensional space %3 = 13 ? M = msinit(36,2, -1); \\ M_2(Gamma_0(36))^- ? w = msatkinlehner(M,4); w^2 == 1 %5 = 1 ? #w %6 = 4 @eprog pari-2.11.2/src/functions/modular_symbols/msgetsign0000644000175000017500000000060513201017466021114 0ustar billbillFunction: msgetsign Section: modular_symbols C-Name: msgetsign Prototype: lG Help: msgetsign(M): M being a full modular symbol space, as given by msinit, return its sign. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return its sign: $\pm1$ or 0 (unset). \bprog ? M = msinit(11,4, 1); ? msgetsign(M) %2 = 1 ? M = msinit(11,4); ? msgetsign(M) %4 = 0 @eprog pari-2.11.2/src/functions/modular_symbols/HEADER0000644000175000017500000000301313326135265020046 0ustar billbillFunction: _header_modular_symbols Class: header Section: modular_symbols Doc: \section{Modular symbols} Let $\Delta := \text{Div}^0(\P^1(\Q))$ be the abelian group of divisors of degree $0$ on the rational projective line. The standard $\text{GL}(2,\Q)$ action on $\P^1(\Q)$ via homographies naturally extends to $\Delta$. Given \item $G$ a finite index subgroup of $\text{SL}(2,\Z)$, \item a field $F$ and a finite dimensional representation $V/F$ of $\text{GL}(2,\Q)$, \noindent we consider the space of \emph{modular symbols} $M := \Hom_G(\Delta, V)$. This finite dimensional $F$-vector space is a $G$-module, canonically isomorphic to $H^1_c(X(G), V)$, and allows to compute modular forms for $G$. Currently, we only support the groups $\Gamma_0(N)$ ($N > 0$ an integer) and the representations $V_k = \Q[X,Y]_{k-2}$ ($k \geq 2$ an integer) over $\Q$. We represent a space of modular symbols by an \var{ms} structure, created by the function \tet{msinit}. It encodes basic data attached to the space: chosen $\Z[G]$-generators $(g_i)$ for $\Delta$ (and relations among those) and an $F$-basis of $M$. A modular symbol $s$ is thus given either in terms of this fixed basis, or as a collection of values $s(g_i)$ satisfying certain relations. A subspace of $M$ (e.g. the cuspidal or Eisenstein subspaces, the new or old modular symbols, etc.) is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix whose columns form an $F$-basis of the subspace. pari-2.11.2/src/functions/modular_symbols/mseval0000644000175000017500000000431613326135265020414 0ustar billbillFunction: mseval Section: modular_symbols C-Name: mseval Prototype: GGDG Help: mseval(M,s,{p}): M being a full modular symbol space, as given by msinit, s being a modular symbol from M and p being a path between two elements in P^1(Q), return s(p). Doc: Let $\Delta:=\text{Div}^0(\P^1 (\Q))$. Let $M$ be a full modular symbol space, as given by \kbd{msinit}, let $s$ be a modular symbol from $M$, i.e. an element of $\Hom_G(\Delta, V)$, and let $p=[a,b] \in \Delta$ be a path between two elements in $\P^1(\Q)$, return $s(p)\in V$. The path extremities $a$ and $b$ may be given as \typ{INT}, \typ{FRAC} or $\kbd{oo} = (1:0)$; it is also possible to describe the path by a $2 \times 2$ integral matrix whose columns give the two cusps. The symbol $s$ is either \item a \typ{COL} coding a modular symbol in terms of the fixed basis of $\Hom_G(\Delta,V)$ chosen in $M$; if $M$ was initialized with a non-zero \emph{sign} ($+$ or $-$), then either the basis for the full symbol space or the $\pm$-part can be used (the dimension being used to distinguish the two). \item a \typ{MAT} whose columns encode modular symbols as above. This is much faster than evaluating individual symbols on the same path $p$ independently. \item a \typ{VEC} $(v_i)$ of elements of $V$, where the $v_i = s(g_i)$ give the image of the generators $g_i$ of $\Delta$, see \tet{mspathgens}. We assume that $s$ is a proper symbol, i.e.~that the $v_i$ satisfy the \kbd{mspathgens} relations. If $p$ is omitted, convert a single symbol $s$ to the second form: a vector of the $s(g_i)$. A \typ{MAT} is converted to a vector of such. \bprog ? M = msinit(2,8,1); \\ M_8(Gamma_0(2))^+ ? g = mspathgens(M)[1] %2 = [[+oo, 0], [0, 1]] ? N = msnew(M)[1]; #N \\ Q-basis of new subspace, dimension 1 %3 = 1 ? s = N[,1] \\ t_COL representation %4 = [-3, 6, -8]~ ? S = mseval(M, s) \\ t_VEC representation %5 = [64*x^6-272*x^4+136*x^2-8, 384*x^5+960*x^4+192*x^3-672*x^2-432*x-72] ? mseval(M,s, g[1]) %6 = 64*x^6 - 272*x^4 + 136*x^2 - 8 ? mseval(M,S, g[1]) %7 = 64*x^6 - 272*x^4 + 136*x^2 - 8 @eprog\noindent Note that the symbol should have values in $V = \Q[x,y]_{k-2}$, we return the de-homogenized values corresponding to $y = 1$ instead. pari-2.11.2/src/functions/modular_symbols/mstooms0000644000175000017500000000471613201017466020624 0ustar billbillFunction: mstooms Section: modular_symbols C-Name: mstooms Prototype: GG Help: mstooms(Mp, phi): given Mp from mspadicinit, lift the (classical) eigen symbol phi to a distribution-valued overconvergent symbol in the sense of Pollack and Stevens. The resulting overconvergent eigensymbol can then be used in mspadicmoments, then mspadicL or mspadicseries. Doc: given \kbd{Mp} from \kbd{mspadicinit}, lift the (classical) eigen symbol \kbd{phi} to a $p$-adic distribution-valued overconvergent symbol in the sense of Pollack and Stevens. More precisely, let $\phi$ belong to the space $W$ of modular symbols of level $N$, $v_p(N) \leq 1$, and weight $k$ which is an eigenvector for the Hecke operator $T_N(p)$ for a non-zero eigenvalue $a_p$ and let $N_0 = \text{lcm}(N,p)$. Under the action of $T_{N_0}(p)$, $\phi$ generates a subspace $W_\phi$ of dimension $1$ (if $p\mid N$) or $2$ (if $p$ does not divide $N$) in the space of modular symbols of level $N_0$. Let $V_p=[p,0;0,1]$ and $C_p=[a_p,p^{k-1};-1,0]$. When $p$ does not divide $N$ and $a_p$ is divisible by $p$, \kbd{mstooms} returns the lift $\Phi$ of $(\phi,\phi|_k V_p)$ such that $$T_{N_0}(p) \Phi = C_p \Phi$$ When $p$ does not divide $N$ and $a_p$ is not divisible by $p$, \kbd{mstooms} returns the lift $\Phi$ of $\phi - \alpha^{-1} \phi|_k V_p$ which is an eigenvector of $T_{N_0}(p)$ for the unit eigenvalue where $\alpha^2 - a_p \alpha + p^{k-1}=0$. The resulting overconvergent eigensymbol can then be used in \tet{mspadicmoments}, then \tet{mspadicL} or \tet{mspadicseries}. \bprog ? M = msinit(3,6, 1); p = 5; ? Tp = mshecke(M, p); factor(charpoly(Tp)) %2 = [x - 3126 2] [ x - 6 1] ? phi = matker(Tp - 6)[,1] \\ generator of p-Eigenspace, a_p = 6 %3 = [5, -3, -1]~ ? Mp = mspadicinit(M, p, 10, 0); \\ restrict to ordinary symbols, mod p^10 ? PHI = mstooms(Mp, phi); ? mu = mspadicmoments(Mp, PHI); ? mspadicL(mu) %7 = 5 + 2*5^2 + 2*5^3 + ... @eprog A non ordinary symbol. \bprog ? M = msinit(4,6,1); p = 3; ? Tp = mshecke(M, p); factor(charpoly(Tp)) %2 = [x - 244 3] [ x + 12 1] ? phi = matker(Tp + 12)[,1] \\ a_p = -12 is divisible by p = 3 %3 = [-1/32, -1/4, -1/32, 1]~ ? msissymbol(M,phi) %4 = 1 ? Mp = mspadicinit(M,3,5,0); ? PHI = mstooms(Mp,phi); *** at top-level: PHI=mstooms(Mp,phi) *** ^--------------- *** mstooms: incorrect type in mstooms [v_p(ap) > mspadicinit flag] (t_VEC). ? Mp = mspadicinit(M,3,5,1); ? PHI = mstooms(Mp,phi); @eprog pari-2.11.2/src/functions/modular_symbols/mscuspidal0000644000175000017500000000160113201017466021255 0ustar billbillFunction: mscuspidal Section: modular_symbols C-Name: mscuspidal Prototype: GD0,L, Help: mscuspidal(M, {flag=0}): M being a full modular symbol space, as given by msinit, return its cuspidal part S. If flag = 1, return [S,E] its decomposition into Eisenstein and cuspidal parts. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return its cuspidal part $S$. If $\fl = 1$, return $[S,E]$ its decomposition into cuspidal and Eisenstein parts. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. \bprog ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ ? [S,E] = mscuspidal(M, 1); ? E[1] \\ 2-dimensional %3 = [0 -10] [0 -15] [0 -3] [1 0] ? S[1] \\ 1-dimensional %4 = [ 3] [30] [ 6] [-8] @eprog pari-2.11.2/src/functions/modular_symbols/mspadicinit0000644000175000017500000000365313201017466021426 0ustar billbillFunction: mspadicinit Section: modular_symbols C-Name: mspadicinit Prototype: GLLD-1,L, Help: mspadicinit(M, p, n, {flag}): M being a full modular symbol space, as given by msinit and a prime p, initialize technical data needed to compute with overconvergent modular symbols (modulo p^n). If flag is unset, allow all symbols; if flag = 0, restrict to ordinary symbols; else initialize for symbols phi such that Tp(phi) = a_p * phi, with v_p(a_p) >= flag. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, and $p$ a prime, initialize technical data needed to compute with overconvergent modular symbols, modulo $p^n$. If $\fl$ is unset, allow all symbols; else initialize only for a restricted range of symbols depending on $\fl$: if $\fl = 0$ restrict to ordinary symbols, else restrict to symbols $\phi$ such that $T_p(\phi) = a_p \phi$, with $v_p(a_p) \geq \fl$, which is faster as $\fl$ increases. (The fastest initialization is obtained for $\fl = 0$ where we only allow ordinary symbols.) For supersingular eigensymbols, such that $p\mid a_p$, we must further assume that $p$ does not divide the level. \bprog ? E = ellinit("11a1"); ? [M,phi] = msfromell(E,1); ? ellap(E,3) %3 = -1 ? Mp = mspadicinit(M, 3, 10, 0); \\ commit to ordinary symbols ? PHI = mstooms(Mp,phi); @eprog If we restrict the range of allowed symbols with \fl (for faster initialization), exceptions will occur if $v_p(a_p)$ violates this bound: \bprog ? E = ellinit("15a1"); ? [M,phi] = msfromell(E,1); ? ellap(E,7) %3 = 0 ? Mp = mspadicinit(M,7,5,0); \\ restrict to ordinary symbols ? PHI = mstooms(Mp,phi) *** at top-level: PHI=mstooms(Mp,phi) *** ^--------------- *** mstooms: incorrect type in mstooms [v_p(ap) > mspadicinit flag] (t_VEC). ? Mp = mspadicinit(M,7,5); \\ no restriction ? PHI = mstooms(Mp,phi); @eprog\noindent This function uses $O(N^2(n+k)^2p)$ memory, where $N$ is the level of $M$. pari-2.11.2/src/functions/modular_symbols/mspadicmoments0000644000175000017500000000326713201017466022146 0ustar billbillFunction: mspadicmoments Section: modular_symbols C-Name: mspadicmoments Prototype: GGD1,L, Help: mspadicmoments(Mp, PHI, {D = 1}): given Mp from mspadicinit, an overconvergent eigensymbol PHI, and optionally a fundamental discriminant D coprime to p, return the moments of the p-1 distributions PHI^D([0]-[oo]) | (a + pZp), 0 < a < p. To be used by mspadicL and mspadicseries. Doc: given \kbd{Mp} from \kbd{mspadicinit}, an overconvergent eigensymbol \kbd{PHI} from \kbd{mstooms} and a fundamental discriminant $D$ coprime to $p$, let $\kbd{PHI}^D$ denote the twisted symbol. This function computes the distribution $\mu = \kbd{PHI}^D([0] - \infty]) \mid \Z_p^*$ restricted to $\Z_p^*$. More precisely, it returns the moments of the $p-1$ distributions $\kbd{PHI}^D([0]-[\infty]) \mid (a + p\Z_p)$, $0 < a < p$. We also allow \kbd{PHI} to be given as a classical symbol, which is then lifted to an overconvergent symbol by \kbd{mstooms}; but this is wasteful if more than one twist is later needed. The returned data $\mu$ ($p$-adic distributions attached to \kbd{PHI}) can then be used in \tet{mspadicL} or \tet{mspadicseries}. This precomputation allows to quickly compute derivatives of different orders or values at different characters. \bprog ? M = msinit(3,6, 1); ? phi = [5,-3,-1]~; ? msissymbol(M, phi) %3 = 1 ? p = 5; mshecke(M,p) * phi \\ eigenvector of T_5, a_5 = 6 %4 = [30, -18, -6]~ ? Mp = mspadicinit(M, p, 10, 0); \\ restrict to ordinary symbols, mod p^10 ? PHI = mstooms(Mp, phi); ? mu = mspadicmoments(Mp, PHI); ? mspadicL(mu) %8 = 5 + 2*5^2 + 2*5^3 + ... ? mu = mspadicmoments(Mp, PHI, 12); \\ twist by 12 ? mspadicL(mu) %10 = 5 + 5^2 + 5^3 + 2*5^4 + ... @eprog pari-2.11.2/src/functions/modular_symbols/msstar0000644000175000017500000000107313201017466020425 0ustar billbillFunction: msstar Section: modular_symbols C-Name: msstar Prototype: GDG Help: msstar(M,{H}): M being a full modular symbol space, as given by msinit, return the matrix of the * involution, induced by complex conjugation, acting on the (stable) subspace H (M if omitted). Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return the matrix of the \kbd{*} involution, induced by complex conjugation, acting on the (stable) subspace $H$ ($M$ if omitted). \bprog ? M = msinit(11,2); \\ M_2(Gamma_0(11)) ? w = msstar(M); ? w^2 == 1 %3 = 1 @eprog pari-2.11.2/src/functions/modular_symbols/msnew0000644000175000017500000000115713201017466020250 0ustar billbillFunction: msnew Section: modular_symbols C-Name: msnew Prototype: G Help: msnew(M): M being a full modular symbol space, as given by msinit, return its new cuspidal subspace. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return the \emph{new} part of its cuspidal subspace. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. \bprog ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ ? N = msnew(M); ? #N[1] \\ 6-dimensional %3 = 6 @eprog pari-2.11.2/src/functions/modular_symbols/mseisenstein0000644000175000017500000000142213201017466021620 0ustar billbillFunction: mseisenstein Section: modular_symbols C-Name: mseisenstein Prototype: G Help: mseisenstein(M): M being a full modular symbol space, as given by msinit, return its Eisenstein subspace. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return its Eisenstein subspace. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. This is the same basis as given by the second component of \kbd{mscuspidal}$(M, 1)$. \bprog ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ ? E = mseisenstein(M); ? E[1] \\ 2-dimensional %3 = [0 -10] [0 -15] [0 -3] [1 0] ? E == mscuspidal(M,1)[2] %4 = 1 @eprog pari-2.11.2/src/functions/modular_symbols/msomseval0000644000175000017500000000106413201017466021122 0ustar billbillFunction: msomseval Section: modular_symbols C-Name: msomseval Prototype: GGG Help: msomseval(Mp, PHI, path): return the vectors of moments of the p-adic distribution attached to the path 'path' via the overconvergent modular symbol 'PHI'. Doc:return the vectors of moments of the $p$-adic distribution attached to the path \kbd{path} by the overconvergent modular symbol \kbd{PHI}. \bprog ? M = msinit(3,6,1); ? Mp= mspadicinit(M,5,10); ? phi = [5,-3,-1]~; ? msissymbol(M,phi) %4 = 1 ? PHI = mstooms(Mp,phi); ? ME = msomseval(Mp,PHI,[oo, 0]); @eprog pari-2.11.2/src/functions/modular_symbols/msqexpansion0000644000175000017500000000276213447371554021664 0ustar billbillFunction: msqexpansion Section: modular_symbols C-Name: msqexpansion Prototype: GGDP Help: msqexpansion(M,projH,{B = seriesprecision}): M being a full modular symbol space, as given by msinit, and projH being a projector on a Hecke-simple subspace, return the Fourier coefficients [a_n, n <= B] of the corresponding normalized newform. If B omitted, use seriesprecision. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, and \var{projH} being a projector on a Hecke-simple subspace (as given by \tet{mssplit}), return the Fourier coefficients $a_n$, $n\leq B$ of the corresponding normalized newform. If $B$ is omitted, use \kbd{seriesprecision}. This function uses a naive $O(B^2 d^3)$ algorithm, where $d = O(kN)$ is the dimension of $M_k(\Gamma_0(N))$. \bprog ? M = msinit(11,2, 1); \\ M_2(Gamma_0(11))^+ ? L = mssplit(M, msnew(M)); ? msqexpansion(M,L[1], 20) %3 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1, -4, -2, 4, 0, 2] ? ellan(ellinit("11a1"), 20) %4 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1, -4, -2, 4, 0, 2] @eprog\noindent The shortcut \kbd{msqexpansion(M, s, B)} is available for a symbol $s$, provided it is a Hecke eigenvector: \bprog ? E = ellinit("11a1"); ? [M,S] = msfromell(E); [sp,sm] = S; ? msqexpansion(M,sp,10) \\ in the + eigenspace %3 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] ? msqexpansion(M,sm,10) \\ in the - eigenspace %4 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] ? ellan(E, 10) %5 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] @eprog pari-2.11.2/src/functions/modular_symbols/msissymbol0000644000175000017500000000155513326135265021330 0ustar billbillFunction: msissymbol Section: modular_symbols C-Name: msissymbol Prototype: GG Help: msissymbol(M,s): M being a full modular symbol space, as given by msinit, check whether s is a modular symbol attached to M. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, check whether $s$ is a modular symbol attached to $M$. If $A$ is a matrix, check whether its columns represent modular symbols and return a $0-1$ vector. \bprog ? M = msinit(7,8, 1); \\ M_8(Gamma_0(7))^+ ? A = msnew(M)[1]; ? s = A[,1]; ? msissymbol(M, s) %4 = 1 ? msissymbol(M, A) %5 = [1, 1, 1] ? S = mseval(M,s); ? msissymbol(M, S) %7 = 1 ? [g,R] = mspathgens(M); g %8 = [[+oo, 0], [0, 1/2], [1/2, 1]] ? #R \\ 3 relations among the generators g_i %9 = 3 ? T = S; T[3]++; \\ randomly perturb S(g_3) ? msissymbol(M, T) %11 = 0 \\ no longer satisfies the relations @eprog pari-2.11.2/src/functions/modular_symbols/msinit0000644000175000017500000000332313326135265020425 0ustar billbillFunction: msinit Section: modular_symbols C-Name: msinit Prototype: GGD0,L, Help: msinit(G, V, {sign=0}): given G a finite index subgroup of SL(2,Z) and a finite dimensional representation V of GL(2,Q), creates a space of modular symbols, the G-module Hom_G(Div^0(P^1 Q), V). This is canonically isomorphic to H^1_c(X(G), V), and allows to compute modular forms for G. If sign is present and non-zero, it must be +1 or -1 and we consider the subspace defined by Ker (Sigma - sign), where Sigma is induced by [-1,0;0,1]. Currently the only supported groups are the Gamma_0(N), coded by the integer N. The only supported representation is V_k = Q[X,Y]_{k-2}, coded by the integer k >= 2. Doc: given $G$ a finite index subgroup of $\text{SL}(2,\Z)$ and a finite dimensional representation $V$ of $\text{GL}(2,\Q)$, creates a space of modular symbols, the $G$-module $\Hom_G(\text{Div}^0(\P^1 (\Q)), V)$. This is canonically isomorphic to $H^1_c(X(G), V)$, and allows to compute modular forms for $G$. If \emph{sign} is present and non-zero, it must be $\pm1$ and we consider the subspace defined by $\text{Ker} (\sigma - \var{sign})$, where $\sigma$ is induced by \kbd{[-1,0;0,1]}. Currently the only supported groups are the $\Gamma_0(N)$, coded by the integer $N > 0$. The only supported representation is $V_k = \Q[X,Y]_{k-2}$, coded by the integer $k \geq 2$. \bprog ? M = msinit(11,2); msdim(M) \\ Gamma0(11), weight 2 %1 = 3 ? mshecke(M,2) \\ T_2 acting on M %2 = [3 1 1] [0 -2 0] [0 0 -2] ? msstar(M) \\ * involution %3 = [1 0 0] [0 0 1] [0 1 0] ? Mp = msinit(11,2, 1); msdim(Mp) \\ + part %4 = 2 ? mshecke(Mp,2) \\ T_2 action on M^+ %5 = [3 2] [0 -2] ? msstar(Mp) %6 = [1 0] [0 1] @eprog pari-2.11.2/src/functions/modular_symbols/msfromcusp0000644000175000017500000000306213326135265021320 0ustar billbillFunction: msfromcusp Section: modular_symbols C-Name: msfromcusp Prototype: GG Help: msfromcusp(M, c): returns the modular symbol attached to the cusp c, where M is a modular symbol space of level N. Doc: returns the modular symbol attached to the cusp $c$, where $M$ is a modular symbol space of level $N$, attached to $G = \Gamma_0(N)$. The cusp $c$ in $\P^1(\Q)/G$ is given either as \kbd{oo} ($=(1:0)$) or as a rational number $a/b$ ($=(a:b)$). The attached symbol maps the path $[b] - [a] \in \text{Div}^0 (\P^1(\Q))$ to $E_c(b) - E_c(a)$, where $E_c(r)$ is $0$ when $r \neq c$ and $X^{k-2} \mid \gamma_r$ otherwise, where $\gamma_r \cdot r = (1:0)$. These symbols span the Eisenstein subspace of $M$. \bprog ? M = msinit(2,8); \\ M_8(Gamma_0(2)) ? E = mseisenstein(M); ? E[1] \\ two-dimensional %3 = [0 -10] [0 -15] [0 -3] [1 0] ? s = msfromcusp(M,oo) %4 = [0, 0, 0, 1]~ ? mseval(M, s) %5 = [1, 0] ? s = msfromcusp(M,1) %6 = [-5/16, -15/32, -3/32, 0]~ ? mseval(M,s) %7 = [-x^6, -6*x^5 - 15*x^4 - 20*x^3 - 15*x^2 - 6*x - 1] @eprog In case $M$ was initialized with a non-zero \emph{sign}, the symbol is given in terms of the fixed basis of the whole symbol space, not the $+$ or $-$ part (to which it need not belong). \bprog ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ ? E = mseisenstein(M); ? E[1] \\ still two-dimensional, in a smaller space %3 = [ 0 -10] [ 0 3] [-1 0] ? s = msfromcusp(M,oo) \\ in terms of the basis for M_8(Gamma_0(2)) ! %4 = [0, 0, 0, 1]~ ? mseval(M, s) \\ same symbol as before %5 = [1, 0] @eprog pari-2.11.2/src/functions/modular_symbols/mspathgens0000644000175000017500000000401213326135265021267 0ustar billbillFunction: mspathgens Section: modular_symbols C-Name: mspathgens Prototype: G Help: mspathgens(M): M being a full modular symbol space, as given by msinit, return a set of Z[G]-generators for Div^0(P^1 Q). The output is [g,R], where g is a minimal system of generators and R the vector of Z[G]-relations between the given generators. Doc: Let $\Delta:=\text{Div}^0(\P^1(\Q))$. Let $M$ being a full modular symbol space, as given by \kbd{msinit}, return a set of $\Z[G]$-generators for $\Delta$. The output is $[g,R]$, where $g$ is a minimal system of generators and $R$ the vector of $\Z[G]$-relations between the given generators. A relation is coded by a vector of pairs $[a_i,i]$ with $a_i\in \Z[G]$ and $i$ the index of a generator, so that $\sum_i a_i g[i] = 0$. An element $[v]-[u]$ in $\Delta$ is coded by the ``path'' $[u,v]$, where \kbd{oo} denotes the point at infinity $(1:0)$ on the projective line. An element of $\Z[G]$ is either an integer $n$ ($= n [\text{id}_2]$) or a ``factorization matrix'': the first column contains distinct elements $g_i$ of $G$ and the second integers $n_i$ and the matrix codes $\sum n_i [g_i]$: \bprog ? M = msinit(11,8); \\ M_8(Gamma_0(11)) ? [g,R] = mspathgens(M); ? g %3 = [[+oo, 0], [0, 1/3], [1/3, 1/2]] \\ 3 paths ? #R \\ a single relation %4 = 1 ? r = R[1]; #r \\ ...involving all 3 generators %5 = 3 ? r[1] %6 = [[1, 1; [1, 1; 0, 1], -1], 1] ? r[2] %7 = [[1, 1; [7, -2; 11, -3], -1], 2] ? r[3] %8 = [[1, 1; [8, -3; 11, -4], -1], 3] @eprog\noindent The given relation is of the form $\sum_i (1-\gamma_i) g_i = 0$, with $\gamma_i\in \Gamma_0(11)$. There will always be a single relation involving all generators (corresponding to a round trip along all cusps), then relations involving a single generator (corresponding to $2$ and $3$-torsion elements in the group: \bprog ? M = msinit(2,8); \\ M_8(Gamma_0(2)) ? [g,R] = mspathgens(M); ? g %3 = [[+oo, 0], [0, 1]] @eprog\noindent Note that the output depends only on the group $G$, not on the representation $V$. pari-2.11.2/src/functions/modular_symbols/msfromell0000644000175000017500000000540113326135265021121 0ustar billbillFunction: msfromell Section: modular_symbols C-Name: msfromell Prototype: GD0,L, Help: msfromell(E, {sign=0}): return the [M, x], where M is msinit(N,2) and x is the modular symbol in M attached to the elliptic curve E/Q. Doc: Let $E/\Q$ be an elliptic curve of conductor $N$. For $\varepsilon = \pm1$, we define the (cuspidal, new) modular symbol $x^\varepsilon$ in $H^1_c(X_0(N),\Q)^\varepsilon$ attached to $E$. For all primes $p$ not dividing $N$ we have $T_p(x^\varepsilon) = a_p x^\varepsilon$, where $a_p = p+1-\#E(\F_p)$. Let $\Omega^+ = \kbd{E.omega[1]}$ be the real period of $E$ (integration of the N\'eron differential $dx/(2y+a_1x+a3)$ on the connected component of $E(\R)$, i.e.~the generator of $H_1(E,\Z)^+$) normalized by $\Omega^+>0$. Let $i\Omega^-$ the integral on a generator of $H_1(E,\Z)^-$ with $\Omega^- \in \R_{>0}$. If $c_\infty$ is the number of connected components of $E(\R)$, $\Omega^-$ is equal to $(-2/c_\infty) \times \kbd{imag(E.omega[2])}$. The complex modular symbol is defined by $$F: \delta \to 2i\pi \int_{\delta} f(z) dz$$ The modular symbols $x^\varepsilon$ are normalized so that $ F = x^+ \Omega^+ + x^- i\Omega^-$. In particular, we have $$ x^+([0]-[\infty]) = L(E,1) / \Omega^+,$$ which defines $x^{\pm}$ unless $L(E,1)=0$. Furthermore, for all fundamental discriminants $D$ such that $\varepsilon \cdot D > 0$, we also have $$\sum_{0\leq a<|D|} (D|a) x^\varepsilon([a/|D|]-[\infty]) = L(E,(D|.),1) / \Omega^{\varepsilon},$$ where $(D|.)$ is the Kronecker symbol. The period $\Omega^-$ is also $2/c_\infty \times$ the real period of the twist $E^{(-4)} = \kbd{elltwist(E,-4)}$. This function returns the pair $[M, x]$, where $M$ is \kbd{msinit}$(N,2)$ and $x$ is $x^{\var{sign}}$ as above when $\var{sign}= \pm1$, and $x = [x^+,x^-, L_E]$ when \var{sign} is $0$, where $L_E$ is a matrix giving the canonical $\Z$-lattice attached to $E$ in the sense of \kbd{mslattice} applied to $\Q x^+ + \Q x^-$. Explicitly, it is generated by $(x^{+},x^{-})$ when $E(\R)$ has two connected components and by $(x^{+} - x^{-},2x^-)$ otherwise. The modular symbols $x^\pm$ are given as a \typ{COL} (in terms of the fixed basis of $\Hom_G(\Delta,\Q)$ chosen in $M$). \bprog ? E=ellinit([0,-1,1,-10,-20]); \\ X_0(11) ? [M,xp]= msfromell(E,1); ? xp %3 = [1/5, -1/2, -1/2]~ ? [M,x]= msfromell(E); ? x \\ x^+, x^- and L_E %5 = [[1/5, -1/2, -1/2]~, [0, 1/2, -1/2]~, [1/5, 0; -1, 1; 0, -1]] ? p = 23; (mshecke(M,p) - ellap(E,p))*x[1] %6 = [0, 0, 0]~ \\ true at all primes, including p = 11; same for x[2] ? (mshecke(M,p) - ellap(E,p))*x[3] == 0 %7 = 1 @eprog \noindent Instead of a single curve $E$, one may use instead a vector of \emph{isogenous} curves. The function then returns $M$ and the vector of attached modular symbols. pari-2.11.2/src/functions/modular_symbols/msgetlevel0000644000175000017500000000041613201017466021263 0ustar billbillFunction: msgetlevel Section: modular_symbols C-Name: msgetlevel Prototype: lG Help: msgetlevel(M): M being a full modular symbol space, as given by msinit, return its level N. Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return its level $N$. pari-2.11.2/src/functions/modular_symbols/mssplit0000644000175000017500000000271213326135265020616 0ustar billbillFunction: mssplit Section: modular_symbols C-Name: mssplit Prototype: GDGD0,L, Help: mssplit(M,{H},{dimlim}): M being a full modular symbol space, as given by msinit, and H being a subspace (the new subspace if omitted), split H into Hecke-simple subspaces. If dimlim is present and positive, restrict to dim <= dimlim. Doc: Let $M$ denote a full modular symbol space, as given by \kbd{msinit}$(N,k,1)$ or $\kbd{msinit}(N,k,-1)$ and let $H$ be a Hecke-stable subspace of \kbd{msnew}$(M)$ (the full new subspace if $H$ is omitted). This function splits $H$ into Hecke-simple subspaces. If \kbd{dimlim} is present and positive, restrict to subspaces of dimension $\leq \kbd{dimlim}$. A subspace is given by a structure allowing quick projection and restriction of linear operators; its first component is a matrix with integer coefficients whose columns form a $\Q$-basis of the subspace. \bprog ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ ? L = mssplit(M); \\ split msnew(M) ? #L %3 = 2 ? f = msqexpansion(M,L[1],5); f[1].mod %4 = x^2 + 8*x - 44 ? lift(f) %5 = [1, x, -6*x - 27, -8*x - 84, 20*x - 155] ? g = msqexpansion(M,L[2],5); g[1].mod %6 = x^4 - 558*x^2 + 140*x + 51744 @eprog\noindent To a Hecke-simple subspace corresponds an orbit of (normalized) newforms, defined over a number field. In the above example, we printed the polynomials defining the said fields, as well as the first 5 Fourier coefficients (at the infinite cusp) of one such form. pari-2.11.2/src/functions/modular_symbols/mspetersson0000644000175000017500000000366413326135265021514 0ustar billbillFunction: mspetersson Section: modular_symbols C-Name: mspetersson Prototype: GDGDG Help: mspetersson(M, {F}, {G=F}): M being a full modular symbol space, as given by msinit, calculate the intersection product {F,G} of modular symbols F and G on M. Doc: $M$ being a full modular symbol space for $\Gamma = \Gamma_0(N)$, as given by \kbd{msinit}, calculate the intersection product $\{F, G\}$ of modular symbols $F$ and $G$ on $M=\Hom_{\Gamma}(\Delta, V_k)$ extended to an hermitian bilinear form on $M \otimes \C$ whose radical is the Eisenstein subspace of $M$. Suppose that $f_1$ and $f_2$ are two parabolic forms. Let $F_1$ and $F_2$ be the attached modular symbols $$ F_i(\delta)= \int_{\delta} f_i(z) \cdot (z X + Y)^{k-2} \,dz$$ and let $F^{\R}_1$, $F^{\R}_2$ be the attached real modular symbols $$ F^{\R}_i(\delta)= \int_{\delta} \Re\big(f_i(z) \cdot (z X + Y)^{k-2} \,dz\big) $$ Then we have $$ \{ F^{\R}_1, F^{\R}_2 \} = -2 (2i)^{k-2} \cdot \Im(_{\var{Petersson}}) $$ and $$\{ F_1, \bar{F_2} \} = (2i)^{k-2} _{\var{Petersson}}$$ In weight 2, the intersection product $\{F, G\}$ has integer values on the $\Z$-structure on $M$ given by \kbd{mslattice} and defines a Riemann form on $H^1_{par}(\Gamma,\R)$. For user convenience, we allow $F$ and $G$ to be matrices and return the attached Gram matrix. If $F$ is omitted: treat it as the full modular space attached to $M$; if $G$ is omitted, take it equal to $F$. \bprog ? M = msinit(37,2); ? C = mscuspidal(M)[1]; ? mspetersson(M, C) %3 = [ 0 -17 -8 -17] [17 0 -8 -25] [ 8 8 0 -17] [17 25 17 0] ? mspetersson(M, mslattice(M,C)) %4 = [0 -1 0 -1] [1 0 0 -1] [0 0 0 -1] [1 1 1 0] ? E = ellinit("33a1"); ? [M,xpm] = msfromell(E); [xp,xm,L] = xpm; ? mspetersson(M, mslattice(M,L)) %7 = [0 -3] [3 0] ? ellmoddegree(E) %8 = [3, -126] @eprog \noindent The coefficient $3$ in the matrix is the degree of the modular parametrization. pari-2.11.2/src/functions/gp2c_internal/0000755000175000017500000000000013461316051016504 5ustar billbillpari-2.11.2/src/functions/gp2c_internal/_strtoclosure0000644000175000017500000000025311636712103021336 0ustar billbillFunction: _strtoclosure Class: gp2c_internal Description: (str):closure strtofunction($1) (str,gen,...):closure strtoclosure($1, ${nbarg 1 sub}, $3) pari-2.11.2/src/functions/gp2c_internal/_avma0000644000175000017500000000012211636712103017505 0ustar billbillFunction: _avma Class: gp2c_internal Description: ():pari_sp avma pari-2.11.2/src/functions/gp2c_internal/_gerepileall0000644000175000017500000000030111636712103021045 0ustar billbillFunction: _gerepileall Class: gp2c_internal Description: (pari_sp,gen):void:parens $2 = gerepilecopy($1, $2) (pari_sp,gen,...):void gerepileall($1, ${nbarg 1 sub}, ${stdref 3 code}) pari-2.11.2/src/functions/gp2c_internal/_cgetg0000644000175000017500000000024011636712103017653 0ustar billbillFunction: _cgetg Class: gp2c_internal Description: (lg,#str):gen cgetg($1, ${2 str_raw}) (gen,lg,#str):gen $1 = cgetg($2, ${3 str_raw}) pari-2.11.2/src/functions/gp2c_internal/_norange0000644000175000017500000000011413201017466020213 0ustar billbillFunction: _norange Class: gp2c_internal Description: ():small LONG_MAX pari-2.11.2/src/functions/gp2c_internal/_prec0000644000175000017500000000026513201017466017522 0ustar billbillFunction: _ndec2prec Class: gp2c_internal Description: (small):small ndec2prec($1) Function: _ndec2nbits Class: gp2c_internal Description: (small):small ndec2nbits($1) pari-2.11.2/src/functions/gp2c_internal/_gc_needed0000644000175000017500000000014713201017466020465 0ustar billbillFunction: _gc_needed Class: gp2c_internal Description: (pari_sp):bool gc_needed($1, 1) pari-2.11.2/src/functions/gp2c_internal/_typedef0000644000175000017500000000452713326135265020244 0ustar billbillFunction: _decl_base Class: gp2c_internal Description: (C!void) void (C!long) long (C!ulong) ulong (C!int) int (C!GEN) GEN (C!char*) char (C!byteptr) byteptr (C!pari_sp) pari_sp (C!func_GG) GEN (C!forprime_t) forprime_t (C!forcomposite_t) forcomposite_t (C!forpart_t) forpart_t (C!forperm_t) forperm_t (C!forvec_t) forvec_t (C!forsubset_t) forsubset_t Function: _decl_ext Class: gp2c_internal Description: (C!char*) *$1 (C!func_GG) (*$1)(GEN, GEN) Function: _typedef Class: gp2c_internal Description: (empty) void (void) void (negbool) long (bool) long (small_int) int (usmall) ulong (small) long (int) GEN (real) GEN (mp) GEN (lg) long (vecsmall) GEN (vec) GEN (list) GEN (var) long (pol) GEN (gen) GEN (closure) GEN (error) GEN (genstr) GEN (str) char* (bptr) byteptr (forcomposite) forcomposite_t (forpart) forpart_t (forperm) forperm_t (forprime) forprime_t (forsubset) forsubset_t (forvec) forvec_t (func_GG) func_GG (pari_sp) pari_sp (typ) long (errtyp) long (nf) GEN (bnf) GEN (bnr) GEN (ell) GEN (clgp) GEN (prid) GEN (gal) GEN (Fp) GEN (FpX) GEN (Fq) GEN (FqX) GEN Function: _proto_ret Class: gp2c_internal Help: Code for return value of functions Description: (C!void) v (C!int) i (C!long) l (C!ulong) u (C!GEN) Function: _proto_max_args Class: gp2c_internal Help: Max number of arguments supported by install. Description: (20) Function: _proto_code Class: gp2c_internal Help: Code for argument of a function Description: (var) n (C!long) L (C!ulong) U (C!GEN) G (C!char*) s Function: _default_marker Class: gp2c_internal Help: Code for default value of GP function Description: (C!GEN) NULL (var) -1 (small) 0 (str) "" Function: _default_check Class: gp2c_internal Help: Code to check for the default marker Description: (C!GEN):bool !$(1) (var):bool $(1) == -1 pari-2.11.2/src/functions/gp2c_internal/_gerepileupto0000644000175000017500000000053011636712103021270 0ustar billbillFunction: _gerepileupto Class: gp2c_internal Description: (pari_sp, int):int gerepileuptoint($1, $2) (pari_sp, mp):mp gerepileuptoleaf($1, $2) (pari_sp, vecsmall):vecsmall gerepileuptoleaf($1, $2) (pari_sp, vec):vec gerepileupto($1, $2) (pari_sp, gen):gen gerepileupto($1, $2) pari-2.11.2/src/functions/gp2c_internal/_tovec0000644000175000017500000000157613201017466017717 0ustar billbillFunction: _tovec Class: gp2c_internal Help: Create a vector holding the arguments (shallow) Description: ():vec cgetg(1, t_VEC) (gen):vec mkvec($1) (gen,gen):vec mkvec2($1, $2) (gen,gen,gen):vec mkvec3($1, $2, $3) (gen,gen,gen,gen):vec mkvec4($1, $2, $3, $4) (gen,gen,gen,gen,gen):vec mkvec5($1, $2, $3, $4, $5) (gen,...):vec mkvecn($#, $2) Function: _tovecprec Class: gp2c_internal Help: Create a vector holding the arguments and prec (shallow) Description: ():vec:prec mkvecs($prec) (gen):vec:prec mkvec2($1, stoi($prec)) (gen,gen):vec:prec mkvec3($1, $2, stoi($prec)) (gen,gen,gen):vec:prec mkvec4($1, $2, $3, stoi($prec)) (gen,gen,gen,gen):vec:prec mkvec5($1, $2, $3, $4, stoi($prec)) (gen,...):vec:prec mkvecn(${nbarg 1 add}, $2, stoi($prec)) pari-2.11.2/src/functions/gp2c_internal/_formatcode0000644000175000017500000000043113326135265020715 0ustar billbillFunction: _formatcode Class: gp2c_internal Description: (#small):void $1 (small):small %ld (small_int):small_int %d (#str):void $%1 (str):str %s (gen):gen %Ps pari-2.11.2/src/functions/gp2c_internal/_cast0000644000175000017500000000626113201017466017525 0ustar billbillFunction: _type_preorder Class: gp2c_internal Help: List of chains of type preorder. Description: (empty, void, bool, small, int, mp, gen) (empty, real, mp) (empty, bptr, small) (empty, bool, lg, small) (empty, bool, small_int, small) (empty, bool, usmall, small) (empty, void, negbool, bool) (empty, typ, str, genstr,gen) (empty, errtyp, str) (empty, vecsmall, gen) (empty, vec, gen) (empty, list, gen) (empty, closure, gen) (empty, error, gen) (empty, bnr, bnf, nf, vec) (empty, bnr, bnf, clgp, vec) (empty, ell, vec) (empty, prid, vec) (empty, gal, vec) (empty, var, pol, gen) (empty, Fp, Fq, gen) (empty, FpX, FqX, gen) Function: _cast Class: gp2c_internal Help: (type1):type2 : cast expression of type1 to type2 Description: (void):bool 0 (#negbool):bool ${1 value not} (negbool):bool !$(1) (small_int):bool (usmall):bool (small):bool (lg):bool:parens $(1)!=1 (bptr):bool *$(1) (gen):bool !gequal0($1) (real):bool signe($1) (int):bool signe($1) (mp):bool signe($1) (pol):bool signe($1) (void):negbool 1 (#bool):negbool ${1 value not} (bool):negbool !$(1) (lg):negbool:parens $(1)==1 (bptr):negbool !*$(1) (gen):negbool gequal0($1) (int):negbool !signe($1) (real):negbool !signe($1) (mp):negbool !signe($1) (pol):negbool !signe($1) (bool):small_int (typ):small_int (small):small_int (bool):usmall (typ):usmall (small):usmall (bool):small (typ):small (small_int):small (usmall):small (bptr):small *$(1) (int):small itos($1) (int):usmall itou($1) (#lg):small:parens ${1 value 1 sub} (lg):small:parens $(1)-1 (gen):small gtos($1) (gen):usmall gtou($1) (void):int gen_0 (-2):int gen_m2 (-1):int gen_m1 (0):int gen_0 (1):int gen_1 (2):int gen_2 (bool):int stoi($1) (small):int stoi($1) (usmall):int utoi($1) (mp):int (gen):int (mp):real (gen):real (int):mp (real):mp (gen):mp (#bool):lg:parens ${1 1 value add} (bool):lg:parens $(1)+1 (#small):lg:parens ${1 1 value add} (small):lg:parens $(1)+1 (gen):error (gen):closure (gen):vecsmall (nf):vec (bnf):vec (bnr):vec (ell):vec (clgp):vec (prid):vec (gal):vec (gen):vec (gen):list (pol):var varn($1) (gen):var gvar($1) (var):pol pol_x($1) (gen):pol (int):gen (mp):gen (vecsmall):gen (vec):gen (list):gen (pol):gen (genstr):gen (error):gen (closure):gen (Fp):gen (FpX):gen (Fq):gen (FqX):gen (gen):genstr GENtoGENstr($1) (str):genstr strtoGENstr($1) (gen):str GENtostr_unquoted($1) (genstr):str GSTR($1) (typ):str type_name($1) (errtyp):str numerr_name($1) (#str):typ ${1 str_format} (#str):errtyp ${1 str_format} (bnf):nf bnf_get_nf($1) (gen):nf (bnr):bnf bnr_get_bnf($1) (gen):bnf (gen):bnr (bnf):clgp bnf_get_clgp($1) (bnr):clgp bnr_get_clgp($1) (gen):clgp (gen):ell (gen):gal (gen):prid (Fp):Fq pari-2.11.2/src/functions/gp2c_internal/_stack_lim0000644000175000017500000000034311636712103020534 0ustar billbillFunction: _stack_lim Class: gp2c_internal Description: (pari_sp,small):pari_sp stack_lim($1, $2) Function: _low_stack_lim Class: gp2c_internal Description: (pari_sp,pari_sp):bool low_stack($1, stack_lim($2, 1)) pari-2.11.2/src/functions/gp2c_internal/_badtype0000644000175000017500000000145113326135265020225 0ustar billbillFunction: _badtype Class: gp2c_internal Help: Code to check types. If not void, will be used as if(...). Description: (int):bool:parens typ($1) != t_INT (real):bool:parens typ($1) != t_REAL (mp):negbool is_intreal_t(typ($1)) (vec):negbool is_matvec_t(typ($1)) (vecsmall):bool:parens typ($1) != t_VECSMALL (pol):bool:parens typ($1) != t_POL (list):bool:parens typ($1) != t_LIST (*nf):void:parens $1 = checknf($1) (*bnf):void:parens $1 = checkbnf($1) (bnr):void checkbnr($1) (prid):void checkprid($1) (clgp):void checkabgrp($1) (ell):void checkell($1) (*gal):void:parens $1 = checkgal($1) pari-2.11.2/src/functions/gp2c_internal/_const0000644000175000017500000000101113447371554017722 0ustar billbillFunction: _const_smallreal Class: gp2c_internal Description: (0):real:prec real_0($prec) (1):real:prec real_1($prec) (-1):real:prec real_m1($prec) (small):real:prec stor($1, $prec) Function: _const_quote Class: gp2c_internal Description: ("x"):var 0 ("y"):var 1 (str):var fetch_user_var($1) Function: _const_expr Class: gp2c_internal Description: (str):gen readseq($1) Function: _const_real Class: gp2c_internal Description: (str):real:prec strtor($1, $prec) pari-2.11.2/src/functions/gp2c_internal/_wrap0000644000175000017500000000101113201017466017530 0ustar billbillFunction: _wrap_G Class: gp2c_internal C-Name: gp_call Prototype: G Description: (gen):gen $1 Function: _wrap_Gp Class: gp2c_internal C-Name: gp_callprec Prototype: Gp Description: (gen):gen $1 Function: _wrap_GG Class: gp2c_internal C-Name: gp_call2 Prototype: GG Description: (gen):gen $1 Function: _wrap_vG Class: gp2c_internal C-Name: gp_callvoid Prototype: lG Description: (void):small 0 Function: _wrap_bG Class: gp2c_internal C-Name: gp_callbool Prototype: lG Description: (bool):bool $1 pari-2.11.2/src/functions/gp2c_internal/_maxprime0000644000175000017500000000013211636712103020404 0ustar billbillFunction: _maxprime Class: gp2c_internal Description: ():small maxprime() pari-2.11.2/src/functions/number_theoretical/0000755000175000017500000000000013461316051017630 5ustar billbillpari-2.11.2/src/functions/number_theoretical/gcdext0000644000175000017500000000214312314242551021030 0ustar billbillFunction: gcdext Section: number_theoretical C-Name: gcdext0 Prototype: GG Help: gcdext(x,y): returns [u,v,d] such that d=gcd(x,y) and u*x+v*y=d. Doc: Returns $[u,v,d]$ such that $d$ is the gcd of $x,y$, $x*u+y*v=\gcd(x,y)$, and $u$ and $v$ minimal in a natural sense. The arguments must be integers or polynomials. \sidx{extended gcd} \sidx{Bezout relation} \bprog ? [u, v, d] = gcdext(32,102) %1 = [16, -5, 2] ? d %2 = 2 ? gcdext(x^2-x, x^2+x-2) %3 = [-1/2, 1/2, x - 1] @eprog If $x,y$ are polynomials in the same variable and \emph{inexact} coefficients, then compute $u,v,d$ such that $x*u+y*v = d$, where $d$ approximately divides both and $x$ and $y$; in particular, we do not obtain \kbd{gcd(x,y)} which is \emph{defined} to be a scalar in this case: \bprog ? a = x + 0.0; gcd(a,a) %1 = 1 ? gcdext(a,a) %2 = [0, 1, x + 0.E-28] ? gcdext(x-Pi, 6*x^2-zeta(2)) %3 = [-6*x - 18.8495559, 1, 57.5726923] @eprog\noindent For inexact inputs, the output is thus not well defined mathematically, but you obtain explicit polynomials to check whether the approximation is close enough for your needs. pari-2.11.2/src/functions/number_theoretical/factormodSQF0000644000175000017500000000333013326135265022110 0ustar billbillFunction: factormodSQF Section: number_theoretical C-Name: factormodSQF Prototype: GDG Help: factormodSQF(f,{D}): squarefree factorization of the polynomial f over the finite field defined by the domain D. Doc: squarefree factorization of the polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. This is somewhat faster than full factorization. The coefficients of $f$ must be operation-compatible with the corresponding finite field. The result is a two-column matrix: \item the first column contains monic squarefree pairwise coprime polynomials dividing $f$; \item the second column contains the power to which the polynomial in column $1$ divides $f$; The factors are ordered by increasing degree and the result is canonical: it will not change across multiple calls or sessions. \bprog ? f = (x^2 + 1)^3 * (x^2-1)^2; ? factormodSQF(f, 3) \\ over F_3 %1 = [Mod(1, 3)*x^2 + Mod(2, 3) 2] [Mod(1, 3)*x^2 + Mod(1, 3) 3] ? for(i=1,10^5,factormodSQF(f,3)) time = 192 ms. ? for(i=1,10^5,factormod(f,3)) \\ full factorization is slower time = 409 ms. ? liftall( factormodSQF((x^2 + 1)^3, [3, t^2+1]) ) \\ over F_9 %4 = [x^2 + 1 3] ? t = ffgen(t^2+Mod(1,3)); factormodSQF((x^2 + t^0)^3) \\ same using t_FFELT %5 = [x^2 + 1 3] ? factormodSQF(x^8 + x^7 + x^6 + x^2 + x + Mod(1,2)) %6 = [ Mod(1, 2)*x + Mod(1, 2) 2] [Mod(1, 2)*x^2 + Mod(1, 2)*x + Mod(1, 2) 3] @eprog pari-2.11.2/src/functions/number_theoretical/content0000644000175000017500000000335613326135265021242 0ustar billbillFunction: content Section: number_theoretical C-Name: content0 Prototype: GDG Help: content(x,{D}): gcd of all the components of x, when this makes sense. Doc: computes the gcd of all the coefficients of $x$, when this gcd makes sense. This is the natural definition if $x$ is a polynomial (and by extension a power series) or a vector/matrix. This is in general a weaker notion than the \emph{ideal} generated by the coefficients: \bprog ? content(2*x+y) %1 = 1 \\ = gcd(2,y) over Q[y] @eprog If $x$ is a scalar, this simply returns the absolute value of $x$ if $x$ is rational (\typ{INT} or \typ{FRAC}), and either $1$ (inexact input) or $x$ (exact input) otherwise; the result should be identical to \kbd{gcd(x, 0)}. The content of a rational function is the ratio of the contents of the numerator and the denominator. In recursive structures, if a matrix or vector \emph{coefficient} $x$ appears, the gcd is taken not with $x$, but with its content: \bprog ? content([ [2], 4*matid(3) ]) %1 = 2 @eprog\noindent The content of a \typ{VECSMALL} is computed assuming the entries are signed integers. The optional argument $D$ allows to control over which ring we compute and get a more predictable behaviour: \item $1$: we only consider the underlying $\Q$-structure and the denominator is a (positive) rational number \item a simple variable, say \kbd{'x}: all entries are considered as rational functions in $K(x)$ for some field $K$ and the content is an element of $K$. \bprog ? f = x + 1/y + 1/2; ? content(f) \\ as a t_POL in x %2 = 1/(2*y) ? content(f, 1) \\ Q-content %3 = 1/2 ? content(f, y) \\ as a rational function in y %4 = 1/2 ? g = x^2*y + y^2*x; ? content(g, x) %6 = y ? content(g, y) %7 = x @eprog pari-2.11.2/src/functions/number_theoretical/qfbsolve0000644000175000017500000000162413201017466021377 0ustar billbillFunction: qfbsolve Section: number_theoretical C-Name: qfbsolve Prototype: GG Help: qfbsolve(Q,p): return [x,y] so that Q(x,y)=p where Q is a binary quadratic form and p a prime number, or 0 if there is no solution. Doc: Solve the equation $Q(x,y)=p$ over the integers, where $Q$ is a binary quadratic form and $p$ a prime number. Return $[x,y]$ as a two-components vector, or zero if there is no solution. Note that this function returns only one solution and not all the solutions. Let $D = \disc Q$. The algorithm used runs in probabilistic polynomial time in $p$ (through the computation of a square root of $D$ modulo $p$); it is polynomial time in $D$ if $Q$ is imaginary, but exponential time if $Q$ is real (through the computation of a full cycle of reduced forms). In the latter case, note that \tet{bnfisprincipal} provides a solution in heuristic subexponential time in $D$ assuming the GRH. pari-2.11.2/src/functions/number_theoretical/lcm0000644000175000017500000000276213201017466020335 0ustar billbillFunction: lcm Section: number_theoretical C-Name: glcm0 Prototype: GDG Help: lcm(x,{y}): least common multiple of x and y, i.e. x*y / gcd(x,y) up to units. Description: (int, int):int lcmii($1, $2) (gen):gen glcm0($1, NULL) (gen, gen):gen glcm($1, $2) Doc: least common multiple of $x$ and $y$, i.e.~such that $\lcm(x,y)*\gcd(x,y) = x*y$, up to units. If $y$ is omitted and $x$ is a vector, returns the $\text{lcm}$ of all components of $x$. For integer arguments, return the non-negative \text{lcm}. When $x$ and $y$ are both given and one of them is a vector/matrix type, the LCM is again taken recursively on each component, but in a different way. If $y$ is a vector, resp.~matrix, then the result has the same type as $y$, and components equal to \kbd{lcm(x, y[i])}, resp.~\kbd{lcm(x, y[,i])}. Else if $x$ is a vector/matrix the result has the same type as $x$ and an analogous definition. Note that for these types, \kbd{lcm} is not commutative. Note that \kbd{lcm(v)} is quite different from \bprog l = v[1]; for (i = 1, #v, l = lcm(l, v[i])) @eprog\noindent Indeed, \kbd{lcm(v)} is a scalar, but \kbd{l} may not be (if one of the \kbd{v[i]} is a vector/matrix). The computation uses a divide-conquer tree and should be much more efficient, especially when using the GMP multiprecision kernel (and more subquadratic algorithms become available): \bprog ? v = vector(10^5, i, random); ? lcm(v); time = 546 ms. ? l = v[1]; for (i = 1, #v, l = lcm(l, v[i])) time = 4,561 ms. @eprog pari-2.11.2/src/functions/number_theoretical/divisorslenstra0000644000175000017500000000162013326135265023013 0ustar billbillFunction: divisorslenstra Section: number_theoretical C-Name: divisorslenstra Prototype: GGG Help: divisorslenstra(N, r, s): finds all divisors d of N such that d = r (mod s). Assume that (r,s) = 1 and s^3 > N. Doc: Given three integers $N > s > r \geq 0$ such that $(r,s) = 1$ and $s^3 > N$, find all divisors $d$ of $N$ such that $d \equiv r \pmod{s}$. There are at most $11$ such divisors (Lenstra). \bprog ? N = 245784; r = 19; s = 65 ; ? divisorslenstra(N, r, s) %2 = [19, 84, 539, 1254, 3724, 245784] ? [ d | d <- divisors(N), d % s == r] %3 = [19, 84, 539, 1254, 3724, 245784] @eprog\noindent When the preconditions are not met, the result is undefined: \bprog ? N = 4484075232; r = 7; s = 1303; s^3 > N %4 = 0 ? divisorslenstra(N, r, s) ? [ d | d <- divisors(N), d % s == r ] %6 = [7, 2613, 9128, 19552, 264516, 3407352, 344928864] @eprog\noindent (Divisors were missing but $s^3 < N$.) pari-2.11.2/src/functions/number_theoretical/isprime0000644000175000017500000000376313326135265021242 0ustar billbillFunction: isprime Section: number_theoretical C-Name: gisprime Prototype: GD0,L, Help: isprime(x,{flag=0}): true(1) if x is a (proven) prime number, false(0) if not. If flag is 0 or omitted, use a combination of algorithms. If flag is 1, the primality is certified by the Pocklington-Lehmer Test. If flag is 2, the primality is certified using the APRCL test. If flag is 3, use ECPP. Description: (int, ?0):bool isprime($1) (gen, ?small):gen gisprime($1, $2) Doc: true (1) if $x$ is a prime number, false (0) otherwise. A prime number is a positive integer having exactly two distinct divisors among the natural numbers, namely 1 and itself. This routine proves or disproves rigorously that a number is prime, which can be very slow when $x$ is indeed a large prime integer. For instance a $1000$ digits prime should require 15 to 30 minutes with default algorithms. Use \tet{ispseudoprime} to quickly check for compositeness. Use \tet{primecert} in order to obtain a primality proof instead of a yes/no answer; see also \kbd{factor}. The function accepts vector/matrices arguments, and is then applied componentwise. If $\fl=0$, use a combination of \item Baillie-Pomerance-Selfridge-Wagstaff compositeness test (see \tet{ispseudoprime}), \item Selfridge ``$p-1$'' test if $x-1$ is smooth enough, \item Adleman-Pomerance-Rumely-Cohen-Lenstra (APRCL) for general medium-sized $x$ (less than 1500 bits), \item Atkin-Morain's Elliptic Curve Primality Prover (ECPP) for general large $x$. If $\fl=1$, use Selfridge-Pocklington-Lehmer ``$p-1$'' test; this requires partially factoring various auxilliary integers and is likely to be very slow. If $\fl=2$, use APRCL only. If $\fl=3$, use ECPP only. Function: _aprcl_step4_worker Section: programming/internals C-Name: aprcl_step4_worker Prototype: UGGG Help: worker for isprime (APRCL step 4) Function: _aprcl_step6_worker Section: programming/internals C-Name: aprcl_step6_worker Prototype: GLGGG Help: worker for isprime (APRCL step 6) pari-2.11.2/src/functions/number_theoretical/randomprime0000644000175000017500000000101113036414402022056 0ustar billbillFunction: randomprime Section: number_theoretical C-Name: randomprime Prototype: DG Help: randomprime({N = 2^31}): returns a strong pseudo prime in [2, N-1]. Doc: returns a strong pseudo prime (see \tet{ispseudoprime}) in $[2,N-1]$. A \typ{VEC} $N = [a,b]$ is also allowed, with $a \leq b$ in which case a pseudo prime $a \leq p \leq b$ is returned; if no prime exists in the interval, the function will run into an infinite loop. If the upper bound is less than $2^{64}$ the pseudo prime returned is a proven prime. pari-2.11.2/src/functions/number_theoretical/dirdiv0000644000175000017500000000051611636712103021036 0ustar billbillFunction: dirdiv Section: number_theoretical C-Name: dirdiv Prototype: GG Help: dirdiv(x,y): division of the Dirichlet series x by the Dirichlet series y. Doc: $x$ and $y$ being vectors of perhaps different lengths but with $y[1]\neq 0$ considered as \idx{Dirichlet series}, computes the quotient of $x$ by $y$, again as a vector. pari-2.11.2/src/functions/number_theoretical/divisors0000644000175000017500000000243513326135265021427 0ustar billbillFunction: divisors Section: number_theoretical C-Name: divisors0 Prototype: GD0,L, Help: divisors(x,{flag=0}): gives a vector formed by the divisors of x in increasing order. If flag = 1, return pairs [d, factor(d)]. Description: (gen,?0):vec divisors($1) (gen,1):vec divisors_factored($1) Doc: creates a row vector whose components are the divisors of $x$. The factorization of $x$ (as output by \tet{factor}) can be used instead. If $\fl = 1$, return pairs $[d, \kbd{factor}(d)]$. By definition, these divisors are the products of the irreducible factors of $n$, as produced by \kbd{factor(n)}, raised to appropriate powers (no negative exponent may occur in the factorization). If $n$ is an integer, they are the positive divisors, in increasing order. \bprog ? divisors(12) %1 = [1, 2, 3, 4, 6, 12] ? divisors(12, 1) \\ include their factorization %2 = [[1, matrix(0,2)], [2, Mat([2, 1])], [3, Mat([3, 1])], [4, Mat([2, 2])], [6, [2, 1; 3, 1]], [12, [2, 2; 3, 1]]] ? divisors(x^4 + 2*x^3 + x^2) \\ also works for polynomials %3 = [1, x, x^2, x + 1, x^2 + x, x^3 + x^2, x^2 + 2*x + 1, x^3 + 2*x^2 + x, x^4 + 2*x^3 + x^2] @eprog Variant: The functions \fun{GEN}{divisors}{GEN N} ($\fl = 0$) and \fun{GEN}{divisors_factored}{GEN N} ($\fl = 1$) are also available. pari-2.11.2/src/functions/number_theoretical/coredisc0000644000175000017500000000215111636712103021345 0ustar billbillFunction: coredisc Section: number_theoretical C-Name: coredisc0 Prototype: GD0,L, Help: coredisc(n,{flag=0}): discriminant of the quadratic field Q(sqrt(n)). If (optional) flag is non-null, output a two-component row vector [d,f], where d is the discriminant of the quadratic field Q(sqrt(n)) and n=df^2. f may be a half integer. Doc: a \emph{fundamental discriminant} is an integer of the form $t\equiv 1 \mod 4$ or $4t \equiv 8,12 \mod 16$, with $t$ squarefree (i.e.~$1$ or the discriminant of a quadratic number field). Given a non-zero integer $n$, this routine returns the (unique) fundamental discriminant $d$ such that $n=df^2$, $f$ a positive rational number. If $\fl$ is non-zero, returns the two-element row vector $[d,f]$. If $n$ is congruent to 0 or 1 modulo 4, $f$ is an integer, and a half-integer otherwise. By convention, \kbd{coredisc(0, 1))} returns $[0,1]$. Note that \tet{quaddisc}$(n)$ returns the same value as \kbd{coredisc}$(n)$, and also works with rational inputs $n\in\Q^*$. Variant: Also available are \fun{GEN}{coredisc}{GEN n} ($\fl = 0$) and \fun{GEN}{coredisc2}{GEN n} ($\fl = 1$) pari-2.11.2/src/functions/number_theoretical/factorint0000644000175000017500000000404413326135265021554 0ustar billbillFunction: factorint Section: number_theoretical C-Name: factorint Prototype: GD0,L, Help: factorint(x,{flag=0}): factor the integer x. flag is optional, whose binary digits mean 1: avoid MPQS, 2: avoid first-stage ECM (may fall back on it later), 4: avoid Pollard-Brent Rho and Shanks SQUFOF, 8: skip final ECM (huge composites will be declared prime). Doc: factors the integer $n$ into a product of pseudoprimes (see \kbd{ispseudoprime}), using a combination of the \idx{Shanks SQUFOF} and \idx{Pollard Rho} method (with modifications due to Brent), \idx{Lenstra}'s \idx{ECM} (with modifications by Montgomery), and \idx{MPQS} (the latter adapted from the \idx{LiDIA} code with the kind permission of the LiDIA maintainers), as well as a search for pure powers. The output is a two-column matrix as for \kbd{factor}: the first column contains the ``prime'' divisors of $n$, the second one contains the (positive) exponents. By convention $0$ is factored as $0^1$, and $1$ as the empty factorization; also the divisors are by default not proven primes if they are larger than $2^{64}$, they only failed the BPSW compositeness test (see \tet{ispseudoprime}). Use \kbd{isprime} on the result if you want to guarantee primality or set the \tet{factor_proven} default to $1$. Entries of the private prime tables (see \tet{addprimes}) are also included as is. This gives direct access to the integer factoring engine called by most arithmetical functions. \fl\ is optional; its binary digits mean 1: avoid MPQS, 2: skip first stage ECM (we may still fall back to it later), 4: avoid Rho and SQUFOF, 8: don't run final ECM (as a result, a huge composite may be declared to be prime). Note that a (strong) probabilistic primality test is used; thus composites might not be detected, although no example is known. You are invited to play with the flag settings and watch the internals at work by using \kbd{gp}'s \tet{debug} default parameter (level 3 shows just the outline, 4 turns on time keeping, 5 and above show an increasing amount of internal details). pari-2.11.2/src/functions/number_theoretical/addprimes0000644000175000017500000000135513201017466021527 0ustar billbillFunction: addprimes Section: number_theoretical C-Name: addprimes Prototype: DG Help: addprimes({x=[]}): add primes in the vector x to the prime table to be used in trial division. x may also be a single integer. Composite "primes" are NOT allowed. Doc: adds the integers contained in the vector $x$ (or the single integer $x$) to a special table of ``user-defined primes'', and returns that table. Whenever \kbd{factor} is subsequently called, it will trial divide by the elements in this table. If $x$ is empty or omitted, just returns the current list of extra primes. The entries in $x$ must be primes: there is no internal check, even if the \tet{factor_proven} default is set. To remove primes from the list use \kbd{removeprimes}. pari-2.11.2/src/functions/number_theoretical/issquare0000644000175000017500000000347313201017466021416 0ustar billbillFunction: issquare Section: number_theoretical C-Name: issquareall Prototype: lGD& Help: issquare(x,{&n}): true(1) if x is a square, false(0) if not. If n is given puts the exact square root there if it was computed. Description: (int):bool Z_issquare($1) (gen):bool issquare($1) (int, &int):bool Z_issquareall($1, &$2) (gen, &gen):bool issquareall($1, &$2) Doc: true (1) if $x$ is a square, false (0) if not. What ``being a square'' means depends on the type of $x$: all \typ{COMPLEX} are squares, as well as all non-negative \typ{REAL}; for exact types such as \typ{INT}, \typ{FRAC} and \typ{INTMOD}, squares are numbers of the form $s^2$ with $s$ in $\Z$, $\Q$ and $\Z/N\Z$ respectively. \bprog ? issquare(3) \\ as an integer %1 = 0 ? issquare(3.) \\ as a real number %2 = 1 ? issquare(Mod(7, 8)) \\ in Z/8Z %3 = 0 ? issquare( 5 + O(13^4) ) \\ in Q_13 %4 = 0 @eprog If $n$ is given, a square root of $x$ is put into $n$. \bprog ? issquare(4, &n) %1 = 1 ? n %2 = 2 @eprog For polynomials, either we detect that the characteristic is 2 (and check directly odd and even-power monomials) or we assume that $2$ is invertible and check whether squaring the truncated power series for the square root yields the original input. For \typ{POLMOD} $x$, we only support \typ{POLMOD}s of \typ{INTMOD}s encoding finite fields, assuming without checking that the intmod modulus $p$ is prime and that the polmod modulus is irreducible modulo $p$. \bprog ? issquare(Mod(Mod(2,3), x^2+1), &n) %1 = 1 ? n %2 = Mod(Mod(2, 3)*x, Mod(1, 3)*x^2 + Mod(1, 3)) @eprog Variant: Also available is \fun{long}{issquare}{GEN x}. Deprecated GP-specific functions \fun{GEN}{gissquare}{GEN x} and \fun{GEN}{gissquareall}{GEN x, GEN *pt} return \kbd{gen\_0} and \kbd{gen\_1} instead of a boolean value. pari-2.11.2/src/functions/number_theoretical/qfbcompraw0000644000175000017500000000065712314242551021723 0ustar billbillFunction: qfbcompraw Section: number_theoretical C-Name: qfbcompraw Prototype: GG Help: qfbcompraw(x,y): Gaussian composition without reduction of the binary quadratic forms x and y. Doc: \idx{composition} of the binary quadratic forms $x$ and $y$, without \idx{reduction} of the result. This is useful e.g.~to compute a generating element of an ideal. The result is undefined if $x$ and $y$ do not have the same discriminant. pari-2.11.2/src/functions/number_theoretical/ispolygonal0000644000175000017500000000073712314242551022121 0ustar billbillFunction: ispolygonal Section: number_theoretical C-Name: ispolygonal Prototype: lGGD& Help: ispolygonal(x,s,{&N}): true(1) if x is an s-gonal number, false(0) if not (s > 2). If N is given set it to n if x is the n-th s-gonal number. Doc: true (1) if the integer $x$ is an s-gonal number, false (0) if not. The parameter $s > 2$ must be a \typ{INT}. If $N$ is given, set it to $n$ if $x$ is the $n$-th $s$-gonal number. \bprog ? ispolygonal(36, 3, &N) %1 = 1 ? N @eprog pari-2.11.2/src/functions/number_theoretical/sumdedekind0000644000175000017500000000051113201017466022044 0ustar billbillFunction: sumdedekind Section: number_theoretical C-Name: sumdedekind Prototype: GG Help: sumdedekind(h,k): Dedekind sum attached to h,k. Doc: returns the \idx{Dedekind sum} attached to the integers $h$ and $k$, corresponding to a fast implementation of \bprog s(h,k) = sum(n = 1, k-1, (n/k)*(frac(h*n/k) - 1/2)) @eprog pari-2.11.2/src/functions/number_theoretical/gcd0000644000175000017500000000437713326135265020331 0ustar billbillFunction: gcd Section: number_theoretical C-Name: ggcd0 Prototype: GDG Help: gcd(x,{y}): greatest common divisor of x and y. Description: (small, small):small cgcd($1, $2) (int, int):int gcdii($1, $2) (gen):gen content($1) (gen, gen):gen ggcd($1, $2) Doc: creates the greatest common divisor of $x$ and $y$. If you also need the $u$ and $v$ such that $x*u + y*v = \gcd(x,y)$, use the \tet{gcdext} function. $x$ and $y$ can have rather quite general types, for instance both rational numbers. If $y$ is omitted and $x$ is a vector, returns the $\text{gcd}$ of all components of $x$, i.e.~this is equivalent to \kbd{content(x)}. When $x$ and $y$ are both given and one of them is a vector/matrix type, the GCD is again taken recursively on each component, but in a different way. If $y$ is a vector, resp.~matrix, then the result has the same type as $y$, and components equal to \kbd{gcd(x, y[i])}, resp.~\kbd{gcd(x, y[,i])}. Else if $x$ is a vector/matrix the result has the same type as $x$ and an analogous definition. Note that for these types, \kbd{gcd} is not commutative. The algorithm used is a naive \idx{Euclid} except for the following inputs: \item integers: use modified right-shift binary (``plus-minus'' variant). \item univariate polynomials with coefficients in the same number field (in particular rational): use modular gcd algorithm. \item general polynomials: use the \idx{subresultant algorithm} if coefficient explosion is likely (non modular coefficients). If $u$ and $v$ are polynomials in the same variable with \emph{inexact} coefficients, their gcd is defined to be scalar, so that \bprog ? a = x + 0.0; gcd(a,a) %1 = 1 ? b = y*x + O(y); gcd(b,b) %2 = y ? c = 4*x + O(2^3); gcd(c,c) %3 = 4 @eprog\noindent A good quantitative check to decide whether such a gcd ``should be'' non-trivial, is to use \tet{polresultant}: a value close to $0$ means that a small deformation of the inputs has non-trivial gcd. You may also use \tet{gcdext}, which does try to compute an approximate gcd $d$ and provides $u$, $v$ to check whether $u x + v y$ is close to $d$. Variant: Also available are \fun{GEN}{ggcd}{GEN x, GEN y}, if \kbd{y} is not \kbd{NULL}, and \fun{GEN}{content}{GEN x}, if $\kbd{y} = \kbd{NULL}$. pari-2.11.2/src/functions/number_theoretical/znconreyconductor0000644000175000017500000000316313326135265023354 0ustar billbillFunction: znconreyconductor Section: number_theoretical C-Name: znconreyconductor Prototype: GGD& Help: znconreyconductor(G,chi, {&chi0}): let G be znstar(q,1) and chi be a Dirichlet character on (Z/qZ)* given by its Conrey logarithm. Return the conductor of chi, and set chi0 to (the Conrey logarithm of) the attached primitive character. If chi0 != chi, return the conductor and its factorization. Doc: Let \var{G} be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{bid.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. Return the conductor of \kbd{chi}, as the \typ{INT} \kbd{bid.mod} if \kbd{chi} is primitive, and as a pair \kbd{[N, faN]} (with \kbd{faN} the factorization of $N$) otherwise. If \kbd{chi0} is present, set it to the Conrey logarithm of the attached primitive character. \bprog ? G = znstar(126000, 1); ? znconreyconductor(G,11) \\ primitive %2 = 126000 ? znconreyconductor(G,1) \\ trivial character, not primitive! %3 = [1, matrix(0,2)] ? N0 = znconreyconductor(G,1009, &chi0) \\ character mod 5^3 %4 = [125, Mat([5, 3])] ? chi0 %5 = [14]~ ? G0 = znstar(N0, 1); \\ format [N,factor(N)] accepted ? znconreyexp(G0, chi0) %7 = 9 ? znconreyconductor(G0, chi0) \\ now primitive, as expected %8 = 125 @eprog\noindent The group \kbd{G0} is not computed as part of \kbd{znconreyconductor} because it needs to be computed only once per conductor, not once per character. pari-2.11.2/src/functions/number_theoretical/znconreyexp0000644000175000017500000000217413326135265022151 0ustar billbillFunction: znconreyexp Section: number_theoretical C-Name: znconreyexp Prototype: GG Help: znconreyexp(G, chi): Conrey exponential attached to G = znstar(q, 1). Returns the element m in (Z/qZ)^* attached to the character chi on G: znconreylog(G, m) = chi. Doc: Given a \var{znstar} $G$ attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}), this function returns the Conrey exponential of the character \var{chi}: it returns the integer $m \in (\Z/q\Z)^*$ such that \kbd{znconreylog(G, $m$)} is \var{chi}. The character \var{chi} is given either as a \item \typ{VEC}: in terms of the generators \kbd{G.gen}; \item \typ{COL}: a Conrey logarithm. \bprog ? G = znstar(126000, 1) ? znconreylog(G,1) %2 = [0, 0, 0, 0, 0]~ ? znconreyexp(G,%) %3 = 1 ? G.cyc \\ SNF generators %4 = [300, 12, 2, 2, 2] ? chi = [100, 1, 0, 1, 0]; \\ some random character on SNF generators ? znconreylog(G, chi) \\ in terms of Conrey generators %6 = [0, 3, 3, 0, 2]~ ? znconreyexp(G, %) \\ apply to a Conrey log %7 = 18251 ? znconreyexp(G, chi) \\ ... or a char on SNF generators %8 = 18251 ? znconreychar(G,%) %9 = [100, 1, 0, 1, 0] @eprog pari-2.11.2/src/functions/number_theoretical/quadregulator0000644000175000017500000000057011636712103022434 0ustar billbillFunction: quadregulator Section: number_theoretical C-Name: quadregulator Prototype: Gp Help: quadregulator(x): regulator of the real quadratic field of discriminant x. Doc: regulator of the quadratic field of positive discriminant $x$. Returns an error if $x$ is not a discriminant (fundamental or not) or if $x$ is a square. See also \kbd{quadclassunit} if $x$ is large. pari-2.11.2/src/functions/number_theoretical/charker0000644000175000017500000000312013326135265021174 0ustar billbillFunction: charker Section: number_theoretical C-Name: charker0 Prototype: GG Help: charker(cyc,chi): given a finite abelian group (by its elementary divisors cyc) and a character chi, return its kernel. Doc: let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. This function returns the kernel of $\chi$, as a matrix $K$ in HNF which is a left-divisor of \kbd{matdiagonal(d)}. Its columns express in terms of the $g_j$ the generators of the subgroup. The determinant of $K$ is the kernel index. \bprog ? cyc = [15,5]; chi = [1,1]; ? charker(cyc, chi) %2 = [15 12] [ 0 1] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charker(bnf, [1]) %5 = [3] @eprog\noindent Note that for Dirichlet characters (when \kbd{cyc} is \kbd{znstar(q, 1)}), characters in Conrey representation are available, see \secref{se:dirichletchar} or \kbd{??character}. \bprog ? G = znstar(8, 1); \\ (Z/8Z)^* ? charker(G, 1) \\ Conrey label for trivial character %2 = [1 0] [0 1] @eprog Variant: Also available is \fun{GEN}{charker}{GEN cyc, GEN chi}, when \kbd{cyc} is known to be a vector of elementary divisors and \kbd{chi} a compatible character (no checks). pari-2.11.2/src/functions/number_theoretical/contfrac0000644000175000017500000000556413201017466021364 0ustar billbillFunction: contfrac Section: number_theoretical C-Name: contfrac0 Prototype: GDGD0,L, Help: contfrac(x,{b},{nmax}): continued fraction expansion of x (x rational,real or rational function). b and nmax are both optional, where b is the vector of numerators of the continued fraction, and nmax is a bound for the number of terms in the continued fraction expansion. Doc: returns the row vector whose components are the partial quotients of the \idx{continued fraction} expansion of $x$. In other words, a result $[a_0,\dots,a_n]$ means that $x \approx a_0+1/(a_1+\dots+1/a_n)$. The output is normalized so that $a_n \neq 1$ (unless we also have $n = 0$). The number of partial quotients $n+1$ is limited by \kbd{nmax}. If \kbd{nmax} is omitted, the expansion stops at the last significant partial quotient. \bprog ? \p19 realprecision = 19 significant digits ? contfrac(Pi) %1 = [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2] ? contfrac(Pi,, 3) \\ n = 2 %2 = [3, 7, 15] @eprog\noindent $x$ can also be a rational function or a power series. If a vector $b$ is supplied, the numerators are equal to the coefficients of $b$, instead of all equal to $1$ as above; more precisely, $x \approx (1/b_0)(a_0+b_1/(a_1+\dots+b_n/a_n))$; for a numerical continued fraction ($x$ real), the $a_i$ are integers, as large as possible; if $x$ is a rational function, they are polynomials with $\deg a_i = \deg b_i + 1$. The length of the result is then equal to the length of $b$, unless the next partial quotient cannot be reliably computed, in which case the expansion stops. This happens when a partial remainder is equal to zero (or too small compared to the available significant digits for $x$ a \typ{REAL}). A direct implementation of the numerical continued fraction \kbd{contfrac(x,b)} described above would be \bprog \\ "greedy" generalized continued fraction cf(x, b) = { my( a= vector(#b), t ); x *= b[1]; for (i = 1, #b, a[i] = floor(x); t = x - a[i]; if (!t || i == #b, break); x = b[i+1] / t; ); a; } @eprog\noindent There is some degree of freedom when choosing the $a_i$; the program above can easily be modified to derive variants of the standard algorithm. In the same vein, although no builtin function implements the related \idx{Engel expansion} (a special kind of \idx{Egyptian fraction} decomposition: $x = 1/a_1 + 1/(a_1a_2) + \dots$ ), it can be obtained as follows: \bprog \\ n terms of the Engel expansion of x engel(x, n = 10) = { my( u = x, a = vector(n) ); for (k = 1, n, a[k] = ceil(1/u); u = u*a[k] - 1; if (!u, break); ); a } @eprog \misctitle{Obsolete hack} (don't use this): if $b$ is an integer, \var{nmax} is ignored and the command is understood as \kbd{contfrac($x,, b$)}. Variant: Also available are \fun{GEN}{gboundcf}{GEN x, long nmax}, \fun{GEN}{gcf}{GEN x} and \fun{GEN}{gcf2}{GEN b, GEN x}. pari-2.11.2/src/functions/number_theoretical/zncharisodd0000644000175000017500000000143213326135265022071 0ustar billbillFunction: zncharisodd Section: number_theoretical C-Name: zncharisodd Prototype: lGG Help: zncharisodd(G, chi): let G be znstar(N,1), let chi be a Dirichlet character mod N, return 1 if and only if chi(-1) = -1 and 0 otherwise. Doc: Let $G$ be attached to $(\Z/N\Z)^*$ (as per \kbd{G = znstar(N,1)}) and let \kbd{chi} be a Dirichlet character on $(\Z/N\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{G.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. Return $1$ if and only if \kbd{chi}$(-1) = -1$ and $0$ otherwise. \bprog ? G = znstar(8, 1); ? zncharisodd(G, 1) \\ trivial character %2 = 0 ? zncharisodd(G, 3) %3 = 1 ? chareval(G, 3, -1) %4 = 1/2 @eprog pari-2.11.2/src/functions/number_theoretical/nextprime0000644000175000017500000000074112314242551021567 0ustar billbillFunction: nextprime Section: number_theoretical C-Name: nextprime Prototype: G Help: nextprime(x): smallest pseudoprime >= x. Description: (gen):int nextprime($1) Doc: finds the smallest pseudoprime (see \tet{ispseudoprime}) greater than or equal to $x$. $x$ can be of any real type. Note that if $x$ is a pseudoprime, this function returns $x$ and not the smallest pseudoprime strictly larger than $x$. To rigorously prove that the result is prime, use \kbd{isprime}. pari-2.11.2/src/functions/number_theoretical/ffprimroot0000644000175000017500000000214013326135265021745 0ustar billbillFunction: ffprimroot Section: number_theoretical C-Name: ffprimroot Prototype: GD& Help: ffprimroot(x, {&o}): return a primitive root of the multiplicative group of the definition field of the finite field element x (not necessarily the same as the field generated by x). If present, o is set to [ord, fa], where ord is the order of the group, and fa its factorization (useful in fflog and fforder). Doc: return a primitive root of the multiplicative group of the definition field of the finite field element $x$ (not necessarily the same as the field generated by $x$). If present, $o$ is set to a vector \kbd{[ord, fa]}, where \kbd{ord} is the order of the group and \kbd{fa} its factorization \kbd{factor(ord)}. This last parameter is useful in \tet{fflog} and \tet{fforder}, see \secref{se:DLfun}. \bprog ? t = ffgen(ffinit(nextprime(10^7), 5)); ? g = ffprimroot(t, &o); ? o[1] %3 = 100000950003610006859006516052476098 ? o[2] %4 = [2 1] [7 2] [31 1] [41 1] [67 1] [1523 1] [10498781 1] [15992881 1] [46858913131 1] ? fflog(g^1000000, g, o) time = 1,312 ms. %5 = 1000000 @eprog pari-2.11.2/src/functions/number_theoretical/ispseudoprimepower0000644000175000017500000000157113201017466023524 0ustar billbillFunction: ispseudoprimepower Section: number_theoretical C-Name: ispseudoprimepower Prototype: lGD& Help: ispseudoprimepower(x,{&n}): if x = p^k is a pseudo-prime power (p pseudo-prime, k > 0), return k, else return 0. If n is present, and the function returns a non-zero result, set n to p, the k-th root of x. Doc: if $x = p^k$ is a pseudo-prime power ($p$ pseudo-prime as per \tet{ispseudoprime}, $k > 0$), return $k$, else return 0. If a second argument $\&n$ is given and $x$ is indeed the $k$-th power of a prime $p$, sets $n$ to $p$. More precisely, $k$ is always the largest integer such that $x = n^k$ for some integer $n$ and, when $n \leq 2^{64}$ the function returns $k > 0$ if and only if $n$ is indeed prime. When $n > 2^{64}$ is larger than the threshold, the function may return $1$ even though $n$ is composite: it only passed an \kbd{ispseudoprime(n)} test. pari-2.11.2/src/functions/number_theoretical/znconreylog0000644000175000017500000000572113326135265022137 0ustar billbillFunction: znconreylog Section: number_theoretical C-Name: znconreylog Prototype: GG Help: znconreylog(G,m): Conrey logarithm attached to m in (Z/qZ)*, where G is znstar(q,1). Doc: Given a \var{znstar} attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}), this function returns the Conrey logarithm of $m \in (\Z/q\Z)^*$. Let $q = \prod_p p^{e_p}$ be the factorization of $q$ into distinct primes, where we assume $e_2 = 0$ or $e_2 \geq 2$. (If $e_2 = 1$, we can ignore $2$ from the factorization, as if we replaced $q$ by $q/2$, since $(\Z/q\Z)^* \sim (\Z/(q/2)\Z)^*$.) For all odd $p$ with $e_p > 0$, let $g_p$ be the element in $(\Z/q\Z)^*$ which is \item congruent to $1$ mod $q/p^{e_p}$, \item congruent mod $p^{e_p}$ to the smallest positive integer that generates $(\Z/p^2\Z)^*$. For $p = 2$, we let $g_4$ (if $2^{e_2} \geq 4$) and $g_8$ (if furthermore ($2^{e_2} \geq 8$) be the elements in $(\Z/q\Z)^*$ which are \item congruent to $1$ mod $q/2^{e_2}$, \item $g_4 = -1 \mod 2^{e_2}$, \item $g_8 = 5 \mod 2^{e_2}$. Then the $g_p$ (and the extra $g_4$ and $g_8$ if $2^{e_2}\geq 2$) are independent generators of $\Z/q\Z^*$, i.e. every $m$ in $(\Z/q\Z)^*$ can be written uniquely as $\prod_p g_p^{m_p}$, where $m_p$ is defined modulo the order $o_p$ of $g_p$ and $p \in S_q$, the set of prime divisors of $q$ together with $4$ if $4 \mid q$ and $8$ if $8 \mid q$. Note that the $g_p$ are in general \emph{not} SNF generators as produced by \kbd{znstar} whenever $\omega(q) \geq 2$, although their number is the same. They however allow to handle the finite abelian group $(\Z/q\Z)^*$ in a fast and elegant way. (Which unfortunately does not generalize to ray class groups or Hecke characters.) The Conrey logarithm of $m$ is the vector $(m_p)_{p\in S_q}$. The inverse function \tet{znconreyexp} recovers the Conrey label $m$ from a character. \bprog ? G = znstar(126000, 1); ? znconreylog(G,1) %2 = [0, 0, 0, 0, 0]~ ? znconreyexp(G, %) %3 = 1 ? znconreylog(G,2) \\ 2 is not coprime to modulus !!! *** at top-level: znconreylog(G,2) *** ^----------------- *** znconreylog: elements not coprime in Zideallog: 2 126000 *** Break loop: type 'break' to go back to GP prompt break> ? znconreylog(G,11) \\ wrt. Conrey generators %4 = [0, 3, 1, 76, 4]~ ? log11 = ideallog(,11,G) \\ wrt. SNF generators %5 = [178, 3, -75, 1, 0]~ @eprog\noindent For convenience, we allow to input the ordinary discrete log of $m$, $\kbd{ideallog(,m,bid)}$, which allows to convert discrete logs from \kbd{bid.gen} generators to Conrey generators. \bprog ? znconreylog(G, log11) %7 = [0, 3, 1, 76, 4]~ @eprog\noindent We also allow a character (\typ{VEC}) on \kbd{bid.gen} and return its representation on the Conrey generators. \bprog ? G.cyc %8 = [300, 12, 2, 2, 2] ? chi = [10,1,0,1,1]; ? znconreylog(G, chi) %10 = [1, 3, 3, 10, 2]~ ? n = znconreyexp(G, chi) %11 = 84149 ? znconreychar(G, n) %12 = [10, 1, 0, 1, 1] @eprog pari-2.11.2/src/functions/number_theoretical/omega0000644000175000017500000000055212314242551020644 0ustar billbillFunction: omega Section: number_theoretical C-Name: omega Prototype: lG Help: omega(x): number of distinct prime divisors of x. Doc: number of distinct prime divisors of $|x|$. $x$ must be of type integer. \bprog ? factor(392) %1 = [2 3] [7 2] ? omega(392) %2 = 2; \\ without multiplicity ? bigomega(392) %3 = 5; \\ = 3+2, with multiplicity @eprog pari-2.11.2/src/functions/number_theoretical/qfbclassno0000644000175000017500000000463013326135265021717 0ustar billbillFunction: qfbclassno Section: number_theoretical C-Name: qfbclassno0 Prototype: GD0,L, Help: qfbclassno(D,{flag=0}): class number of discriminant D using Shanks's method by default. If (optional) flag is set to 1, use Euler products. Doc: ordinary class number of the quadratic order of discriminant $D$, for ``small'' values of $D$. \item if $D > 0$ or $\fl = 1$, use a $O(|D|^{1/2})$ algorithm (compute $L(1,\chi_D)$ with the approximate functional equation). This is slower than \tet{quadclassunit} as soon as $|D| \approx 10^2$ or so and is not meant to be used for large $D$. \item if $D < 0$ and $\fl = 0$ (or omitted), use a $O(|D|^{1/4})$ algorithm (Shanks's baby-step/giant-step method). It should be faster than \tet{quadclassunit} for small values of $D$, say $|D| < 10^{18}$. \misctitle{Important warning} In the latter case, this function only implements part of \idx{Shanks}'s method (which allows to speed it up considerably). It gives unconditionnally correct results for $|D| < 2\cdot 10^{10}$, but may give incorrect results for larger values if the class group has many cyclic factors. We thus recommend to double-check results using the function \kbd{quadclassunit}, which is about 2 to 3 times slower in the range $|D| \in [10^{10}, 10^{18}]$, assuming GRH. We currently have no counter-examples but they should exist: we would appreciate a bug report if you find one. \misctitle{Warning} Contrary to what its name implies, this routine does not compute the number of classes of binary primitive forms of discriminant $D$, which is equal to the \emph{narrow} class number. The two notions are the same when $D < 0$ or the fundamental unit $\varepsilon$ has negative norm; when $D > 0$ and $N\varepsilon > 0$, the number of classes of forms is twice the ordinary class number. This is a problem which we cannot fix for backward compatibility reasons. Use the following routine if you are only interested in the number of classes of forms: \bprog QFBclassno(D) = qfbclassno(D) * if (D < 0 || norm(quadunit(D)) < 0, 1, 2) @eprog\noindent Here are a few examples: \bprog ? qfbclassno(400000028) \\ D > 0: slow time = 3,140 ms. %1 = 1 ? quadclassunit(400000028).no time = 20 ms. \\@com{ much faster, assume GRH} %2 = 1 ? qfbclassno(-400000028) \\ D < 0: fast enough time = 0 ms. %3 = 7253 ? quadclassunit(-400000028).no time = 0 ms. %4 = 7253 @eprog\noindent See also \kbd{qfbhclassno}. pari-2.11.2/src/functions/number_theoretical/direuler0000644000175000017500000000307213201017466021370 0ustar billbillFunction: direuler Section: number_theoretical C-Name: direuler0 Prototype: V=GGEDG Help: direuler(p=a,b,expr,{c}): Dirichlet Euler product of expression expr from p=a to p=b, limited to b terms. Expr should be a polynomial or rational function in p and X, and X is understood to mean p^(-s). If c is present, output only the first c terms. Wrapper: (,,G) Description: (gen,gen,closure,?gen):gen direuler(${3 cookie}, ${3 wrapper}, $1, $2, $4) Doc: computes the \idx{Dirichlet series} attached to the \idx{Euler product} of expression \var{expr} as $p$ ranges through the primes from $a$ to $b$. \var{expr} must be a polynomial or rational function in another variable than $p$ (say $X$) and $\var{expr}(X)$ is understood as the local factor $\var{expr}(p^{-s})$. The series is output as a vector of coefficients. If $c$ is omitted, output the first $b$ coefficients of the series; otherwise, output the first $c$ coefficients. The following command computes the \teb{sigma} function, attached to $\zeta(s)\zeta(s-1)$: \bprog ? direuler(p=2, 10, 1/((1-X)*(1-p*X))) %1 = [1, 3, 4, 7, 6, 12, 8, 15, 13, 18] ? direuler(p=2, 10, 1/((1-X)*(1-p*X)), 5) \\ fewer terms %2 = [1, 3, 4, 7, 6] @eprog\noindent Setting $c < b$ is useless (the same effect would be achieved by setting $b = c)$. If $c > b$, the computed coefficients are ``missing'' Euler factors: \bprog ? direuler(p=2, 10, 1/((1-X)*(1-p*X)), 15) \\ more terms, no longer = sigma ! %3 = [1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 0, 28, 0, 24, 24] @eprog \synt{direuler}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN b} pari-2.11.2/src/functions/number_theoretical/hilbert0000644000175000017500000000103011636712103021176 0ustar billbillFunction: hilbert Section: number_theoretical C-Name: hilbert Prototype: lGGDG Help: hilbert(x,y,{p}): Hilbert symbol at p of x,y. Doc: \idx{Hilbert symbol} of $x$ and $y$ modulo the prime $p$, $p=0$ meaning the place at infinity (the result is undefined if $p\neq 0$ is not prime). It is possible to omit $p$, in which case we take $p = 0$ if both $x$ and $y$ are rational, or one of them is a real number. And take $p = q$ if one of $x$, $y$ is a \typ{INTMOD} modulo $q$ or a $q$-adic. (Incompatible types will raise an error.) pari-2.11.2/src/functions/number_theoretical/factorback0000644000175000017500000000220413326135265021656 0ustar billbillFunction: factorback Section: number_theoretical C-Name: factorback2 Prototype: GDG Description: (gen):gen factorback($1) (gen,):gen factorback($1) (gen,gen):gen factorback2($1, $2) Help: factorback(f,{e}): given a factorization f, gives the factored object back. If e is present, f has to be a vector of the same length, and we return the product of the f[i]^e[i]. Doc: gives back the factored object corresponding to a factorization. The integer $1$ corresponds to the empty factorization. If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being integral), and the corresponding factorization is the product of the $f[i]^{e[i]}$. If not, and $f$ is vector, it is understood as in the preceding case with $e$ a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a regular factorization, as produced with any \kbd{factor} command. A few examples: \bprog ? factor(12) %1 = [2 2] [3 1] ? factorback(%) %2 = 12 ? factorback([2,3], [2,1]) \\ 2^3 * 3^1 %3 = 12 ? factorback([5,2,3]) %4 = 30 @eprog Variant: Also available is \fun{GEN}{factorback}{GEN f} (case $e = \kbd{NULL}$). pari-2.11.2/src/functions/number_theoretical/zncoppersmith0000644000175000017500000000435013457566440022500 0ustar billbillFunction: zncoppersmith Section: number_theoretical C-Name: zncoppersmith Prototype: GGGDG Help: zncoppersmith(P, N, X, {B=N}): finds all integers x with |x| <= X such that gcd(N, P(x)) >= B. X should be smaller than exp((log B)^2 / (deg(P) log N)). Doc: $N$ being an integer and $P\in \Z[X]$, finds all integers $x$ with $|x| \leq X$ such that $$\gcd(N, P(x)) \geq B,$$ using \idx{Coppersmith}'s algorithm, a famous application of the \idx{LLL} algorithm. The parameter $X$ must be smaller than $\exp(\log^2 B / (\deg(P) \log N))$: for $B = N$, this means $X < N^{1/\deg(P)}$. Some $x$ larger than $X$ may be returned if you are very lucky. The smaller $B$ (or the larger $X$), the slower the routine will be. The strength of Coppersmith method is the ability to find roots modulo a general \emph{composite} $N$: if $N$ is a prime or a prime power, \tet{polrootsmod} or \tet{polrootspadic} will be much faster. We shall now present two simple applications. The first one is finding non-trivial factors of $N$, given some partial information on the factors; in that case $B$ must obviously be smaller than the largest non-trivial divisor of $N$. \bprog setrand(1); \\ to make the example reproducible [a,b] = [10^30, 10^31]; D = 20; p = randomprime([a,b]); q = randomprime([a,b]); N = p*q; \\ assume we know 0) p | N; 1) p in [a,b]; 2) the last D digits of p p0 = p % 10^D; ? L = zncoppersmith(10^D*x + p0, N, b \ 10^D, a) time = 1ms. %6 = [738281386540] ? gcd(L[1] * 10^D + p0, N) == p %7 = 1 @eprog\noindent and we recovered $p$, faster than by trying all possibilities $ x < 10^{11}$. The second application is an attack on RSA with low exponent, when the message $x$ is short and the padding $P$ is known to the attacker. We use the same RSA modulus $N$ as in the first example: \bprog setrand(1); P = random(N); \\ known padding e = 3; \\ small public encryption exponent X = floor(N^0.3); \\ N^(1/e - epsilon) x0 = random(X); \\ unknown short message C = lift( (Mod(x0,N) + P)^e ); \\ known ciphertext, with padding P zncoppersmith((P + x)^3 - C, N, X) \\ result in 244ms. %14 = [2679982004001230401] ? %[1] == x0 %15 = 1 @eprog\noindent We guessed an integer of the order of $10^{18}$, almost instantly. pari-2.11.2/src/functions/number_theoretical/HEADER0000644000175000017500000001551513326135265020520 0ustar billbillFunction: _header_number_theoretical Class: header Section: number_theoretical Doc: \section{Arithmetic functions}\label{se:arithmetic} These functions are by definition functions whose natural domain of definition is either $\Z$ (or $\Z_{>0}$). The way these functions are used is completely different from transcendental functions in that there are no automatic type conversions: in general only integers are accepted as arguments. An integer argument $N$ can be given in the following alternate formats: \item \typ{MAT}: its factorization \kbd{fa = factor($N$)}, \item \typ{VEC}: a pair \kbd{[$N$, fa]} giving both the integer and its factorization. This allows to compute different arithmetic functions at a given $N$ while factoring the latter only once. \bprog ? N = 10!; faN = factor(N); ? eulerphi(N) %2 = 829440 ? eulerphi(faN) %3 = 829440 ? eulerphi(S = [N, faN]) %4 = 829440 ? sigma(S) %5 = 15334088 @eprog \subsec{Arithmetic functions and the factoring engine} All arithmetic functions in the narrow sense of the word~--- Euler's totient\sidx{Euler totient function} function, the \idx{Moebius} function, the sums over divisors or powers of divisors etc.--- call, after trial division by small primes, the same versatile factoring machinery described under \kbd{factorint}. It includes \idx{Shanks SQUFOF}, \idx{Pollard Rho}, \idx{ECM} and \idx{MPQS} stages, and has an early exit option for the functions \teb{moebius} and (the integer function underlying) \teb{issquarefree}. This machinery relies on a fairly strong probabilistic primality test, see \kbd{ispseudoprime}, but you may also set \bprog default(factor_proven, 1) @eprog\noindent to ensure that all tentative factorizations are fully proven. This should not slow down PARI too much, unless prime numbers with hundreds of decimal digits occur frequently in your application. \subsec{Orders in finite groups and Discrete Logarithm functions} \label{se:DLfun} The following functions compute the order of an element in a finite group: \kbd{ellorder} (the rational points on an elliptic curve defined over a finite field), \kbd{fforder} (the multiplicative group of a finite field), \kbd{znorder} (the invertible elements in $\Z/n\Z$). The following functions compute discrete logarithms in the same groups (whenever this is meaningful) \kbd{elllog}, \kbd{fflog}, \kbd{znlog}. All such functions allow an optional argument specifying an integer $N$, representing the order of the group. (The \emph{order} functions also allows any non-zero multiple of the order, with a minor loss of efficiency.) That optional argument follows the same format as given above: \item \typ{INT}: the integer $N$, \item \typ{MAT}: the factorization \kbd{fa = factor($N$)}, \item \typ{VEC}: this is the preferred format and provides both the integer $N$ and its factorization in a two-component vector \kbd{[$N$, fa]}. When the group is fixed and many orders or discrete logarithms will be computed, it is much more efficient to initialize this data once and for all and pass it to the relevant functions, as in \bprog ? p = nextprime(10^40); ? v = [p-1, factor(p-1)]; \\ data for discrete log & order computations ? znorder(Mod(2,p), v) %3 = 500000000000000000000000000028 ? g = znprimroot(p); ? znlog(2, g, v) %5 = 543038070904014908801878611374 @eprog \subsec{Dirichlet characters}\label{se:dirichletchar} The finite abelian group $G = (\Z/N\Z)^*$ can be written $G = \oplus_{i\leq n} (\Z/d_i\Z) g_i$, with $d_n \mid \dots \mid d_2 \mid d_1$ (SNF condition), all $d_i > 0$, and $\prod_i d_i = \phi(N)$. The SNF condition makes the $d_i$ unique, but the generators $g_i$, of respective order $d_i$, are definitely not unique. The $\oplus$ notation means that all elements of $G$ can be written uniquely as $\prod_i g_i^{n_i}$ where $n_i \in \Z/d_i\Z$. The $g_i$ are the so-called \tev{SNF generators} of $G$. \item a \tev{character} on the abelian group $\oplus (\Z/d_j\Z) g_j$ is given by a row vector $\chi = [a_1,\ldots,a_n]$ of integers $0\leq a_i < d_i$ such that $\chi(g_j) = e(a_j / d_j)$ for all $j$, with the standard notation $e(x) := \exp(2i\pi x)$. In other words, $\chi(\prod g_j^{n_j}) = e(\sum a_j n_j / d_j)$. This will be generalized to more general abelian groups in later sections (Hecke characters), but in the present case of $(\Z/N\Z)^*$, there is a useful alternate convention : namely, it is not necessary to impose the SNF condition and we can use Chinese reminders instead. If $N = \prod p^{e_p}$ is the factorization of $N$ into primes, the so-called \tev{Conrey generators} of $G$ are the generators of the $(\Z/p^{e_p}\Z)^*$ lifted to $(\Z/N\Z)^*$ by requesting that they be congruent to $1$ modulo $N/p^{e_p}$ (for $p$ odd we take the smallest positive primitive root mod $p^2$, and for $p = 2$ we take $-1$ if $e_2 > 1$ and additionally $5$ if $e_2 > 2$). We can again write $G = \oplus_{i\leq n} (\Z/D_i\Z) G_i$, where again $\prod_i D_i = \phi(N)$. These generators don't satisfy the SNF condition in general since their orders are now $(p-1)p^{e_p-1}$ for $p$ odd; for $p = 2$, the generator $-1$ has order $2$ and $5$ has order $2^{e_2-2}$ $(e_2 > 2)$. Nevertheless, any $m\in (\Z/N\Z)^*$ can be uniquely decomposed as $\prod G_i^{m_i}$ for some $m_i$ modulo $D_i$ and we can define a character by $\chi(G_j) = e(m_j / D_j)$ for all $j$. \item The \emph{column vector} of the $m_j$, $0 \leq m_j < D_j$ is called the \tev{Conrey logarithm} of $m$ (discrete logarithm in terms of the Conrey generators). Note that discrete logarithms in PARI/GP are always expressed as \typ{COL}s. \item The attached character is called the \tev{Conrey character} attached to $m$. To sum up a Dirichlet character can be defined by a \typ{INT} (the Conrey label $m$), a \typ{COL} (the Conrey logarithm of $m$, in terms of the Conrey generators) or a \typ{VEC} (in terms of the SNF generators). The \typ{COL} format, i.e. Conrey logarithms, is the preferred (fastest) representation. Concretely, this works as follows: \kbd{G = znstar(N, 1)} initializes $(\Z/N\Z)^*$, which must be given as first arguments to all functions handling Dirichlet characters. \kbd{znconreychar} transforms \typ{INT} and \typ{COL} to a SNF character. \kbd{znconreylog} transforms \typ{INT} and \typ{VEC} to a Conrey logarithm. \kbd{znconreyexp} transforms \typ{VEC} and \typ{COL} to a Conrey label. Also available are \kbd{charconj}, \kbd{chardiv}, \kbd{charmul}, \kbd{charker}, \kbd{chareval}, \kbd{charorder}, \kbd{zncharinduce}, \kbd{znconreyconductor} (also computes the primitive character attached to the input character). The prefix \kbd{char} indicates that the function applies to all characters, the prefix \kbd{znchar} that it is specific to Dirichlet characters (on $(\Z/N\Z)^*$) and the prefix \kbd{znconrey} that it is specific to Conrey representation. pari-2.11.2/src/functions/number_theoretical/znchargauss0000644000175000017500000000153013326135265022110 0ustar billbillFunction: znchargauss Section: number_theoretical C-Name: znchargauss Prototype: GGDGb Help: znchargauss(G, chi, {a=1}): given a Dirichlet character chi on G = (Z/NZ)^*, return the complex Gauss sum g(chi,a). Doc: Given a Dirichlet character $\chi$ on $G = (\Z/N\Z)^*$ (see \kbd{znchar}), return the complex Gauss sum $$g(\chi,a) = \sum_{n = 1}^N \chi(n) e(a n/N)$$ \bprog ? [G,chi] = znchar(-3); \\ quadratic Gauss sum: I*sqrt(3) ? znchargauss(G,chi) %2 = 1.7320508075688772935274463415058723670*I ? [G,chi] = znchar(5); ? znchargauss(G,chi) \\ sqrt(5) %2 = 2.2360679774997896964091736687312762354 ? G = znstar(300,1); chi = [1,1,12]~; ? znchargauss(G,chi) / sqrt(300) - exp(2*I*Pi*11/25) \\ = 0 %4 = 2.350988701644575016 E-38 + 1.4693679385278593850 E-39*I ? lfuntheta([G,chi], 1) \\ = 0 %5 = -5.79[...] E-39 - 2.71[...] E-40*I @eprog pari-2.11.2/src/functions/number_theoretical/istotient0000644000175000017500000000067212314242551021601 0ustar billbillFunction: istotient Section: number_theoretical C-Name: istotient Prototype: lGD& Help: istotient(x,{&N}): true(1) if x = eulerphi(n) for some integer n, false(0) if not. If N is given, set N = n as well. Doc: true (1) if $x = \phi(n)$ for some integer $n$, false (0) if not. \bprog ? istotient(14) %1 = 0 ? istotient(100) %2 = 0 @eprog If $N$ is given, set $N = n$ as well. \bprog ? istotient(4, &n) %1 = 1 ? n %2 = 10 @eprog pari-2.11.2/src/functions/number_theoretical/znlog0000644000175000017500000000536413326135265020722 0ustar billbillFunction: znlog Section: number_theoretical C-Name: znlog0 Prototype: GGDG Help: znlog(x,g,{o}): return the discrete logarithm of x in (Z/nZ)* in base g. If present, o represents the multiplicative order of g. Return [] if no solution exist. Doc: This functions allows two distinct modes of operation depending on $g$: \item if $g$ is the output of \tet{znstar} (with initialization), we compute the discrete logarithm of $x$ with respect to the generators contained in the structure. See \tet{ideallog} for details. \item else $g$ is an explicit element in $(\Z/N\Z)^*$, we compute the discrete logarithm of $x$ in $(\Z/N\Z)^*$ in base $g$. The rest of this entry describes the latter possibility. The result is $[]$ when $x$ is not a power of $g$, though the function may also enter an infinite loop in this case. If present, $o$ represents the multiplicative order of $g$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord} is the order of $g$. This provides a definite speedup when the discrete log problem is simple: \bprog ? p = nextprime(10^4); g = znprimroot(p); o = [p-1, factor(p-1)]; ? for(i=1,10^4, znlog(i, g, o)) time = 163 ms. ? for(i=1,10^4, znlog(i, g)) time = 200 ms. \\ a little slower @eprog The result is undefined if $g$ is not invertible mod $N$ or if the supplied order is incorrect. This function uses \item a combination of generic discrete log algorithms (see below). \item in $(\Z/N\Z)^*$ when $N$ is prime: a linear sieve index calculus method, suitable for $N < 10^{50}$, say, is used for large prime divisors of the order. The generic discrete log algorithms are: \item Pohlig-Hellman algorithm, to reduce to groups of prime order $q$, where $q | p-1$ and $p$ is an odd prime divisor of $N$, \item Shanks baby-step/giant-step ($q < 2^{32}$ is small), \item Pollard rho method ($q > 2^{32}$). The latter two algorithms require $O(\sqrt{q})$ operations in the group on average, hence will not be able to treat cases where $q > 10^{30}$, say. In addition, Pollard rho is not able to handle the case where there are no solutions: it will enter an infinite loop. \bprog ? g = znprimroot(101) %1 = Mod(2,101) ? znlog(5, g) %2 = 24 ? g^24 %3 = Mod(5, 101) ? G = znprimroot(2 * 101^10) %4 = Mod(110462212541120451003, 220924425082240902002) ? znlog(5, G) %5 = 76210072736547066624 ? G^% == 5 %6 = 1 ? N = 2^4*3^2*5^3*7^4*11; g = Mod(13, N); znlog(g^110, g) %7 = 110 ? znlog(6, Mod(2,3)) \\ no solution %8 = [] @eprog\noindent For convenience, $g$ is also allowed to be a $p$-adic number: \bprog ? g = 3+O(5^10); znlog(2, g) %1 = 1015243 ? g^% %2 = 2 + O(5^10) @eprog Variant: The function \fun{GEN}{znlog}{GEN x, GEN g, GEN o} is also available pari-2.11.2/src/functions/number_theoretical/bestappr0000644000175000017500000000414312314242551021374 0ustar billbillFunction: bestappr Section: number_theoretical C-Name: bestappr Prototype: GDG Help: bestappr(x, {B}): returns a rational approximation to x, whose denominator is limited by B, if present. This function applies to reals, intmods, p-adics, and rationals of course. Otherwise it applies recursively to all components. Doc: using variants of the extended Euclidean algorithm, returns a rational approximation $a/b$ to $x$, whose denominator is limited by $B$, if present. If $B$ is omitted, return the best approximation affordable given the input accuracy; if you are looking for true rational numbers, presumably approximated to sufficient accuracy, you should first try that option. Otherwise, $B$ must be a positive real scalar (impose $0 < b \leq B$). \item If $x$ is a \typ{REAL} or a \typ{FRAC}, this function uses continued fractions. \bprog ? bestappr(Pi, 100) %1 = 22/7 ? bestappr(0.1428571428571428571428571429) %2 = 1/7 ? bestappr([Pi, sqrt(2) + 'x], 10^3) %3 = [355/113, x + 1393/985] @eprog By definition, $a/b$ is the best rational approximation to $x$ if $|b x - a| < |v x - u|$ for all integers $(u,v)$ with $0 < v \leq B$. (Which implies that $n/d$ is a convergent of the continued fraction of $x$.) \item If $x$ is a \typ{INTMOD} modulo $N$ or a \typ{PADIC} of precision $N = p^k$, this function performs rational modular reconstruction modulo $N$. The routine then returns the unique rational number $a/b$ in coprime integers $|a| < N/2B$ and $b\leq B$ which is congruent to $x$ modulo $N$. Omitting $B$ amounts to choosing it of the order of $\sqrt{N/2}$. If rational reconstruction is not possible (no suitable $a/b$ exists), returns $[]$. \bprog ? bestappr(Mod(18526731858, 11^10)) %1 = 1/7 ? bestappr(Mod(18526731858, 11^20)) %2 = [] ? bestappr(3 + 5 + 3*5^2 + 5^3 + 3*5^4 + 5^5 + 3*5^6 + O(5^7)) %2 = -1/3 @eprog\noindent In most concrete uses, $B$ is a prime power and we performed Hensel lifting to obtain $x$. The function applies recursively to components of complex objects (polynomials, vectors, \dots). If rational reconstruction fails for even a single entry, return $[]$. pari-2.11.2/src/functions/number_theoretical/ffembed0000644000175000017500000000104713326135265021153 0ustar billbillFunction: ffembed Section: number_theoretical C-Name: ffembed Prototype: GG Help: ffembed(a, b): given two elements a and b in finite fields, return a map embedding the definition field of a to the definition field of b. Doc: given two finite fields elements $a$ and $b$, return a \var{map} embedding the definition field of $a$ to the definition field of $b$. Assume that the latter contains the former. \bprog ? a = ffgen([3,5],'a); ? b = ffgen([3,10],'b); ? m = ffembed(a, b); ? A = ffmap(m, a); ? minpoly(A) == minpoly(a) %5 = 1 @eprog pari-2.11.2/src/functions/number_theoretical/eulerphi0000644000175000017500000000101513201017466021365 0ustar billbillFunction: eulerphi Section: number_theoretical C-Name: eulerphi Prototype: G Help: eulerphi(x): Euler's totient function of x. Description: (gen):int eulerphi($1) Doc: Euler's $\phi$ (totient)\sidx{Euler totient function} function of the integer $|x|$, in other words $|(\Z/x\Z)^*|$. \bprog ? eulerphi(40) %1 = 16 @eprog\noindent According to this definition we let $\phi(0) := 2$, since $\Z^* = \{-1,1\}$; this is consistent with \kbd{znstar(0)}: we have \kbd{znstar$(n)$.no = eulerphi(n)} for all $n\in\Z$. pari-2.11.2/src/functions/number_theoretical/zncharconductor0000644000175000017500000000123413326135265022767 0ustar billbillFunction: zncharconductor Section: number_theoretical C-Name: zncharconductor Prototype: GG Help: zncharconductor(G,chi): let G be znstar(q,1) and chi be a Dirichlet character on (Z/qZ)*. Return the conductor of chi. Doc: Let \var{G} be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$ (see \secref{se:dirichletchar} or \kbd{??character}). Return the conductor of \kbd{chi}: \bprog ? G = znstar(126000, 1); ? zncharconductor(G,11) \\ primitive %2 = 126000 ? zncharconductor(G,1) \\ trivial character, not primitive! %3 = 1 ? zncharconductor(G,1009) \\ character mod 5^3 %4 = 125 @eprog pari-2.11.2/src/functions/number_theoretical/ffmap0000644000175000017500000000134413326135265020654 0ustar billbillFunction: ffmap Section: number_theoretical C-Name: ffmap Prototype: GG Help: ffmap(m, x): given a (partial) map m between two finite fields, return the image of x by m. The function is applied recursively to the component of vectors, matrices and polynomials. If m is a partial map that is not defined at x, return [] Doc: given a (partial) map $m$ between two finite fields, return the image of $x$ by $m$. The function is applied recursively to the component of vectors, matrices and polynomials. If $m$ is a partial map that is not defined at $x$, return $[]$. \bprog ? a = ffgen([3,5],'a); ? b = ffgen([3,10],'b); ? m = ffembed(a, b); ? P = x^2+a*x+1; ? Q = ffmap(m,P); ? ffmap(m,poldisc(P)) == poldisc(Q) %6 = 1 @eprog pari-2.11.2/src/functions/number_theoretical/quadhilbert0000644000175000017500000000110111636712103022050 0ustar billbillFunction: quadhilbert Section: number_theoretical C-Name: quadhilbert Prototype: Gp Help: quadhilbert(D): relative equation for the Hilbert class field of the quadratic field of discriminant D (which can also be a bnf). Doc: relative equation defining the \idx{Hilbert class field} of the quadratic field of discriminant $D$. If $D < 0$, uses complex multiplication (\idx{Schertz}'s variant). If $D > 0$ \idx{Stark units} are used and (in rare cases) a vector of extensions may be returned whose compositum is the requested class field. See \kbd{bnrstark} for details. pari-2.11.2/src/functions/number_theoretical/ispseudoprime0000644000175000017500000000336013326135265022453 0ustar billbillFunction: ispseudoprime Section: number_theoretical C-Name: gispseudoprime Prototype: GD0,L, Help: ispseudoprime(x,{flag}): true(1) if x is a strong pseudoprime, false(0) if not. If flag is 0 or omitted, use BPSW test, otherwise use strong Rabin-Miller test for flag randomly chosen bases. Description: (int,?0):bool BPSW_psp($1) (int,#small):bool millerrabin($1,$2) (int,small):bool ispseudoprime($1, $2) (gen,?small):gen gispseudoprime($1, $2) Doc: true (1) if $x$ is a strong pseudo prime (see below), false (0) otherwise. If this function returns false, $x$ is not prime; if, on the other hand it returns true, it is only highly likely that $x$ is a prime number. Use \tet{isprime} (which is of course much slower) to prove that $x$ is indeed prime. The function accepts vector/matrices arguments, and is then applied componentwise. If $\fl = 0$, checks whether $x$ has no small prime divisors (up to $101$ included) and is a Baillie-Pomerance-Selfridge-Wagstaff pseudo prime. Such a pseudo prime passes a Rabin-Miller test for base $2$, followed by a Lucas test for the sequence $(P,1)$, where $P \geq 3$ is the smallest odd integer such that $P^2 - 4$ is not a square mod $x$. (Technically, we are using an ``almost extra strong Lucas test'' that checks whether $V_n$ is $\pm 2$, without computing $U_n$.) There are no known composite numbers passing the above test, although it is expected that infinitely many such numbers exist. In particular, all composites $\leq 2^{64}$ are correctly detected (checked using \url{http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html}). If $\fl > 0$, checks whether $x$ is a strong Miller-Rabin pseudo prime for $\fl$ randomly chosen bases (with end-matching to catch square roots of $-1$). pari-2.11.2/src/functions/number_theoretical/primecert0000644000175000017500000001051713326135265021557 0ustar billbillFunction: primecert Section: number_theoretical C-Name: primecert Prototype: GD0,L, Help: primecert(N, {flag=0}): If N is a prime, return a Primality Certificate. Return 0 otherwise. If flag = 0 return an ECPP certificate (Atkin-Morain); if flag = 1 return an N-1 certificate (Pocklington-Lehmer) Doc: If N is a prime, return a PARI Primality Certificate for the prime $N$, as described below. Otherwise, return 0. A Primality Certificate $c$ can be checked using \tet{primecertisvalid}$(c)$. If $\fl = 0$ (default), return an ECPP certificate (Atkin-Morain) A PARI ECPP Primality Certificate for the prime $N$ is either a prime integer $N < 2^{64}$ or a vector \kbd{C} of length $\ell$ whose $i$th component \kbd{C[i]} is a vector of length $5$ containing $N_i$, $t_i$, $s_i$, $a_i$, $P_i$ (in that order) where $N_1 = N$. It is said to be valid if for each $i = 1, \ldots, \ell$, all of the following conditions are satisfied \item $N_i$ is a positive integer \item $t_i$ is an integer such that $t_i < 4N_i^2$ \item $s_i$ is a positive integer which divides $m_i$ where $m_i = N_i + 1 - t_i$ \item If we set $q_i = \dfrac{m_i}{s_i}$, then \quad\item $q_i > (N_i^{1/4}+1)^2$ \quad\item $q_i = N_{i+1}$ if $1 \leq i < l$ \quad\item $q_\ell \leq 2^{64}$ is prime \item $a_i$ is an integer \quad\item \kbd{P[i]} is a vector of length $2$ representing the affine point $P_i = (x_i, y_i)$ on the elliptic curve $E: y^2 = x^3 + a_ix + b_i$ modulo $N_i$ where $b_i = y_i^2 - x_i^3 - a_ix_i$ satisfying the following: \quad\item $m_i P_i = \infty$ \quad\item $s_i P_i \neq \infty$ \misctitle{Theorem} If $N$ is an integer and there exist positive integers $m, q$ and a point $P$ on the elliptic curve $E: y^2 = x^3 + ax + b$ defined modulo $N$ such that $q > (N^{1/4} + 1)^2$, $q$ is a prime divisor of $m$, $mP = \infty$ and $\dfrac{m}{q}P \neq \infty$, then $N$ is prime. Using the above theorem, the data in the vector \kbd{C} can be used to certify the primality of $N$ assuming $q_\ell$ is prime. \bprog ? primecert(10^35 + 69) %1 = [[100000000000000000000000000000000069, 5468679110354 52074, 2963504668391148, 0, [60737979324046450274283740674 208692, 24368673584839493121227731392450025]], [3374383076 4501150277, -11610830419, 734208843, 0, [26740412374402652 72 4, 6367191119818901665]], [45959444779, 299597, 2331, 0 , [18022351516, 9326882 51]]] ? primecert(nextprime(2^64)) %2 = [[18446744073709551629, -8423788454, 160388, 1, [1059 8342506117936052, 2225259013356795550]]] ? primecert(6) %3 = 0 ? primecert(41) %4 = 41 @eprog\smallskip If $\fl = 1$ (very slow), return an $N-1$ certificate (Pocklington Lehmer) A PARI $N-1$ Primality Certificate for the prime $N$ is either a prime integer $N < 2^{64}$ or a pair $[N, C]$, where $C$ is a vector with $\ell$ elements which are either a single integer $p_i < 2^{64}$ or a triple $[p_i,a_i,C_i]$ with $p_i > 2^{64}$ satisfying the following properties: \item $p_i$ is a prime divisor of $N - 1$; \item $a_i$ is an integer such that $a_i^{N-1} \equiv 1 \pmod{N}$ and $a_i^{(N-1)/p_i} - 1$ is coprime with $N$; \item $C_i$ is an $N-1$ Primality Certificate for $p_i$ \item The product $F$ of the $p_i^{v_{p_i}(N-1)}$ is strictly larger than $N^{1/3}$. Provided that all $p_i$ are indeed primes, this implies that any divisor of $N$ is congruent to $1$ modulo $F$. \item The Billhart, Lehmer, Selfridge criterion is satisfied: when we write $N = 1 + c_1 F + c_2 F^2$ in base $F$ the polynomial $1 + c_1 X + c_2 X^2$ is irreducible over $\Z$, i.e. $c_1^2 - 4c_2$ is not a square. This implies that $N$ is prime. This algorithm requires factoring partially $p-1$ for various prime integers $p$ with an unfactored parted $\leq p^{2/3}$ and this may be exceedingly slow compared to the default. The algorithm fails if one of the pseudo-prime factors is not prime, which is exceedingly unlikely and well worth a bug report. Note that if you monitor the algorithm at a high enough debug level, you may see warnings about untested integers being declared primes. This is normal: we ask for partial factorizations (sufficient to prove primality if the unfactored part is not too large), and \kbd{factor} warns us that the cofactor hasn't been tested. It may or may not be tested later, and may or may not be prime. This does not affect the validity of the whole Primality Certificate. pari-2.11.2/src/functions/number_theoretical/ispowerful0000644000175000017500000000074413201017466021757 0ustar billbillFunction: ispowerful Section: number_theoretical C-Name: ispowerful Prototype: lG Help: ispowerful(x): true(1) if x is a powerful integer (valuation at all primes dividing x is greater than 1), false(0) if not. Doc: true (1) if $x$ is a powerful integer, false (0) if not; an integer is powerful if and only if its valuation at all primes dividing $x$ is greater than 1. \bprog ? ispowerful(50) %1 = 0 ? ispowerful(100) %2 = 1 ? ispowerful(5^3*(10^1000+1)^2) %3 = 1 @eprog pari-2.11.2/src/functions/number_theoretical/znchar0000644000175000017500000000336113326135265021051 0ustar billbillFunction: znchar Section: number_theoretical C-Name: znchar Prototype: G Help: znchar(D): given a datum D describing a group G = (Z/NZ)^* and a Dirichlet character chi, return the pair [G,chi]. Doc: Given a datum $D$ describing a group $(\Z/N\Z)^*$ and a Dirichlet character $\chi$, return the pair \kbd{[G, chi]}, where \kbd{G} is \kbd{znstar(N, 1)}) and \kbd{chi} is a GP character. The following possibilities for $D$ are supported \item a non-zero \typ{INT} congruent to $0,1$ modulo $4$, return the real character modulo $D$ given by the Kronecker symbol $(D/.)$; \item a \typ{INTMOD} \kbd{Mod(m, N)}, return the Conrey character modulo $N$ of index $m$ (see \kbd{znconreylog}). \item a modular form space as per \kbd{mfinit}$([N,k,\chi])$ or a modular form for such a space, return the underlying Dirichlet character $\chi$ (which may be defined modulo a divisor of $N$ but need not be primitive). In the remaining cases, \kbd{G} is initialized by \kbd{znstar(N, 1)}. \item a pair \kbd{[G, chi]}, where \kbd{chi} is a standard GP Dirichlet character $c = (c_j)$ on \kbd{G} (generic character \typ{VEC} or Conrey characters \typ{COL} or \typ{INT}); given generators $G = \oplus (\Z/d_j\Z) g_j$, $\chi(g_j) = e(c_j/d_j)$. \item a pair \kbd{[G, chin]}, where \kbd{chin} is a \emph{normalized} representation $[n, \tilde{c}]$ of the Dirichlet character $c$; $\chi(g_j) = e(\tilde{c}_j / n)$ where $n$ is minimal (order of $\chi$). \bprog ? [G,chi] = znchar(-3); ? G.cyc %2 = [2] ? chareval(G, chi, 2) %3 = 1/2 ? kronecker(-3,2) %4 = -1 ? znchartokronecker(G,chi) %5 = -3 ? mf = mfinit([28, 5/2, Mod(2,7)]); [f] = mfbasis(mf); ? [G,chi] = znchar(mf); [G.mod, chi] %7 = [7, [2]~] ? [G,chi] = znchar(f); chi %8 = [28, [0, 2]~] @eprog pari-2.11.2/src/functions/number_theoretical/primecertisvalid0000644000175000017500000000150613326135265023131 0ustar billbillFunction: primecertisvalid Section: number_theoretical C-Name: primecertisvalid Prototype: lG Help: primecertisvalid(cert): Verifies if cert is a valid PARI ECPP Primality certificate. Doc: Verifies if cert is a valid PARI ECPP Primality certificate, as described in \kbd{??primecert}. \bprog ? cert = primecert(10^35 + 69) %1 = [[100000000000000000000000000000000069, 5468679110354 52074, 2963504668391148, 0, [60737979324046450274283740674 208692, 24368673584839493121227731392450025]], [3374383076 4501150277, -11610830419, 734208843, 0, [26740412374402652 72 4, 6367191119818901665]], [45959444779, 299597, 2331, 0 , [18022351516, 9326882 51]]] ? primecertisvalid(cert) %2 = 1 ? cert[1][1]++; \\ random perturbation ? primecertisvalid(cert) %4 = 0 \\ no longer valid ? primecertisvalid(primecert(6)) %5 = 0 @eprog pari-2.11.2/src/functions/number_theoretical/primes0000644000175000017500000000115313036414402021047 0ustar billbillFunction: primes Section: number_theoretical C-Name: primes0 Prototype: G Help: primes(n): returns the vector of the first n primes (integer), or the primes in interval n = [a,b]. Doc: creates a row vector whose components are the first $n$ prime numbers. (Returns the empty vector for $n \leq 0$.) A \typ{VEC} $n = [a,b]$ is also allowed, in which case the primes in $[a,b]$ are returned \bprog ? primes(10) \\ the first 10 primes %1 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] ? primes([0,29]) \\ the primes up to 29 %2 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] ? primes([15,30]) %3 = [17, 19, 23, 29] @eprog pari-2.11.2/src/functions/number_theoretical/qfbnupow0000644000175000017500000000105713201017466021417 0ustar billbillFunction: qfbnupow Section: number_theoretical C-Name: nupow Prototype: GGDG Help: qfbnupow(x,n,{L}): n-th power of primitive positive definite quadratic form x using nucomp and nudupl. Doc: $n$-th power of the primitive positive definite binary quadratic form $x$ using \idx{Shanks}'s NUCOMP and NUDUPL algorithms; if set, $L$ should be equal to \kbd{sqrtnint(abs(D)>>2,4)}, where $D < 0$ is the discriminant of $x$. The current implementation is slower than the generic routine for small discriminant $D$, and becomes faster for $D \approx 2^{45}$. pari-2.11.2/src/functions/number_theoretical/factormod0000644000175000017500000000422513326135265021542 0ustar billbillFunction: factormod Section: number_theoretical C-Name: factormod0 Prototype: GDGD0,L, Help: factormod(f,{D},{flag=0}): factors the polynomial f over the finite field defined by the domain D; flag is optional, and can be 0: default or 1: only the degrees of the irreducible factors are given. Doc: factors the polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. The coefficients of $f$ must be operation-compatible with the corresponding finite field. The result is a two-column matrix, the first column being the irreducible polynomials dividing $f$, and the second the exponents. By convention, the $0$ polynomial factors as $0^1$; a non-zero constant polynomial has empty factorization, a $0\times 2$ matrix. The irreducible factors are ordered by increasing degree and the result is canonical: it will not change across multiple calls or sessions. \bprog ? factormod(x^2 + 1, 3) \\ over F_3 %1 = [Mod(1, 3)*x^2 + Mod(1, 3) 1] ? liftall( factormod(x^2 + 1, [3, t^2+1]) ) \\ over F_9 %2 = [ x + t 1] [x + 2*t 1] ? t = ffgen(t^2+Mod(1,3)); factormod(x^2 + t^0) \\ same using t_FFELT %3 = [ x + t 1] [x + 2*t 1] ? factormod(x^2+Mod(1,3)) %4 = [Mod(1, 3)*x^2 + Mod(1, 3) 1] ? liftall( factormod(x^2 + Mod(Mod(1,3),y^2+1)) ) %5 = [ x + y 1] [x + 2*y 1] @eprog If $\fl$ is non-zero, outputs only the \emph{degrees} of the irreducible polynomials (for example to compute an $L$-function). By convention, a constant polynomial (including the $0$ polynomial) has empty factorization. The degrees appear in increasing order but need not correspond to the ordering with $\fl =0$ when multiplicities are present. \bprog ? f = x^3 + 2*x^2 + x + 2; ? factormod(f, 5) \\ (x+2)^2 * (x+3) %1 = [Mod(1, 5)*x + Mod(2, 5) 2] [Mod(1, 5)*x + Mod(3, 5) 1] ? factormod(f, 5, 1) \\ (deg 1) * (deg 1)^2 %2 = [1 1] [1 2] @eprog pari-2.11.2/src/functions/number_theoretical/bigomega0000644000175000017500000000056312314242551021330 0ustar billbillFunction: bigomega Section: number_theoretical C-Name: bigomega Prototype: lG Help: bigomega(x): number of prime divisors of x, counted with multiplicity. Doc: number of prime divisors of the integer $|x|$ counted with multiplicity: \bprog ? factor(392) %1 = [2 3] [7 2] ? bigomega(392) %2 = 5; \\ = 3+2 ? omega(392) %3 = 2; \\ without multiplicity @eprog pari-2.11.2/src/functions/number_theoretical/sqrtint0000644000175000017500000000067113036414402021260 0ustar billbillFunction: sqrtint Section: number_theoretical C-Name: sqrtint Prototype: G Help: sqrtint(x): integer square root of x, where x is a non-negative integer. Description: (gen):int sqrtint($1) Doc: returns the integer square root of $x$, i.e. the largest integer $y$ such that $y^2 \leq x$, where $x$ a non-negative integer. \bprog ? N = 120938191237; sqrtint(N) %1 = 347761 ? sqrt(N) %2 = 347761.68741970412747602130964414095216 @eprog pari-2.11.2/src/functions/number_theoretical/primepi0000644000175000017500000000077413326135265021236 0ustar billbillFunction: primepi Section: number_theoretical C-Name: primepi Prototype: G Help: primepi(x): the prime counting function pi(x) = #{p <= x, p prime}. Description: (gen):int primepi($1) Doc: the prime counting function. Returns the number of primes $p$, $p \leq x$. \bprog ? primepi(10) %1 = 4; ? primes(5) %2 = [2, 3, 5, 7, 11] ? primepi(10^11) %3 = 4118054813 @eprog\noindent Uses checkpointing and a naive $O(x)$ algorithm; make sure to start gp with \kbd{primelimit} at least $\sqrt{x}$. pari-2.11.2/src/functions/number_theoretical/quadunit0000644000175000017500000000152113326135265021412 0ustar billbillFunction: quadunit Section: number_theoretical C-Name: quadunit0 Prototype: GDn Help: quadunit(D,{v = 'w}): fundamental unit u of the quadratic field of discriminant D where D must be positive. If v is given, the variable name is used to display u, else 'w' is used. Doc: fundamental unit\sidx{fundamental units} $u$ of the real quadratic field $\Q(\sqrt D)$ where $D$ is the positive discriminant of the field. If $D$ is not a fundamental discriminant, this probably gives the fundamental unit of the corresponding order. $D$ must be an integer congruent to 0 or 1 modulo 4, which is not a square; the result is a quadratic number (see \secref{se:quadgen}). If \var{v} is given, the variable name is used to display $u$ else 'w' is used. Variant: When \var{v} does not matter, the function \fun{GEN}{quadunit}{GEN D} is also available. pari-2.11.2/src/functions/number_theoretical/charorder0000644000175000017500000000256713326135265021544 0ustar billbillFunction: charorder Section: number_theoretical C-Name: charorder0 Prototype: GG Help: charorder(cyc,chi): given a finite abelian group (by its elementary divisors cyc) and a character chi, return the order of chi. Doc: let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. This function returns the order of the character \kbd{chi}. \bprog ? cyc = [15,5]; chi = [1,1]; ? charorder(cyc, chi) %2 = 15 ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charorder(bnf, [1]) %5 = 3 @eprog\noindent For Dirichlet characters (when \kbd{cyc} is \kbd{znstar(q, 1)}), characters in Conrey representation are available, see \secref{se:dirichletchar} or \kbd{??character}: \bprog ? G = znstar(100, 1); \\ (Z/100Z)^* ? charorder(G, 7) \\ Conrey label %2 = 4 @eprog Variant: Also available is \fun{GEN}{charorder}{GEN cyc, GEN chi}, when \kbd{cyc} is known to be a vector of elementary divisors and \kbd{chi} a compatible character (no checks). pari-2.11.2/src/functions/number_theoretical/znstar0000644000175000017500000000271013326135265021102 0ustar billbillFunction: znstar Section: number_theoretical C-Name: znstar0 Prototype: GD0,L, Help: znstar(n,{flag=0}): 3-component vector v = [no,cyc,gen], giving the structure of the abelian group (Z/nZ)^*; no is the order (i.e. eulerphi(n)), cyc is a vector of cyclic components, and gen is a vector giving the corresponding generators. Doc: gives the structure of the multiplicative group $(\Z/n\Z)^*$. The output $G$ depends on the value of \fl: \item $\fl = 0$ (default), an abelian group structure $[h,d,g]$, where $h = \phi(n)$ is the order (\kbd{G.no}), $d$ (\kbd{G.cyc}) is a $k$-component row-vector $d$ of integers $d_i$ such that $d_i>1$, $d_i \mid d_{i-1}$ for $i \ge 2$ and $$ (\Z/n\Z)^* \simeq \prod_{i=1}^k (\Z/d_i\Z), $$ and $g$ (\kbd{G.gen}) is a $k$-component row vector giving generators of the image of the cyclic groups $\Z/d_i\Z$. \item $\fl = 1$ the result is a \kbd{bid} structure; this allows computing discrete logarithms using \tet{znlog} (also in the non-cyclic case!). \bprog ? G = znstar(40) %1 = [16, [4, 2, 2], [Mod(17, 40), Mod(21, 40), Mod(11, 40)]] ? G.no \\ eulerphi(40) %2 = 16 ? G.cyc \\ cycle structure %3 = [4, 2, 2] ? G.gen \\ generators for the cyclic components %4 = [Mod(17, 40), Mod(21, 40), Mod(11, 40)] ? apply(znorder, G.gen) %5 = [4, 2, 2] @eprog\noindent For user convenience, we define \kbd{znstar(0)} as \kbd{[2, [2], [-1]]}, corresponding to $\Z^*$, but $\fl = 1$ is not implemented in this trivial case. pari-2.11.2/src/functions/number_theoretical/qfbred0000644000175000017500000000263211636712103021021 0ustar billbillFunction: qfbred Section: number_theoretical C-Name: qfbred0 Prototype: GD0,L,DGDGDG Help: qfbred(x,{flag=0},{d},{isd},{sd}): reduction of the binary quadratic form x. All other args. are optional. The arguments d, isd and sd, if present, supply the values of the discriminant, floor(sqrt(d)) and sqrt(d) respectively. If d<0, its value is not used and all references to Shanks's distance hereafter are meaningless. flag can be any of 0: default, uses Shanks's distance function d; 1: use d, do a single reduction step; 2: do not use d; 3: do not use d, single reduction step. Doc: reduces the binary quadratic form $x$ (updating Shanks's distance function if $x$ is indefinite). The binary digits of $\fl$ are toggles meaning \quad 1: perform a single \idx{reduction} step \quad 2: don't update \idx{Shanks}'s distance The arguments $d$, \var{isd}, \var{sd}, if present, supply the values of the discriminant, $\floor{\sqrt{d}}$, and $\sqrt{d}$ respectively (no checking is done of these facts). If $d<0$ these values are useless, and all references to Shanks's distance are irrelevant. Variant: Also available are \fun{GEN}{redimag}{GEN x} (for definite $x$), \noindent and for indefinite forms: \fun{GEN}{redreal}{GEN x} \fun{GEN}{rhoreal}{GEN x} (= \kbd{qfbred(x,1)}), \fun{GEN}{redrealnod}{GEN x, GEN isd} (= \kbd{qfbred(x,2,,isd)}), \fun{GEN}{rhorealnod}{GEN x, GEN isd} (= \kbd{qfbred(x,3,,isd)}). pari-2.11.2/src/functions/number_theoretical/quadpoly0000644000175000017500000000116613326135265021423 0ustar billbillFunction: quadpoly Section: number_theoretical C-Name: quadpoly0 Prototype: GDn Help: quadpoly(D,{v='x}): quadratic polynomial corresponding to the discriminant D, in variable v. Doc: creates the ``canonical'' quadratic polynomial (in the variable $v$) corresponding to the discriminant $D$, i.e.~the minimal polynomial of $\kbd{quadgen}(D)$. $D$ must be an integer congruent to 0 or 1 modulo 4, which is not a square. \bprog ? quadpoly(5,'y) %1 = y^2 - y - 1 ? quadpoly(0,'y) *** at top-level: quadpoly(0,'y) *** ^-------------- *** quadpoly: domain error in quadpoly: issquare(disc) = 1 @eprog pari-2.11.2/src/functions/number_theoretical/logint0000644000175000017500000000171213201017466021050 0ustar billbillFunction: logint Section: number_theoretical C-Name: logint0 Prototype: lGGD& Help: logint(x,b,{&z}): return the largest integer e so that b^e <= x, where the parameters b > 1 and x > 0 are both integers. If the parameter z is present, set it to b^e. Description: (gen,2):small expi($1) (gen,gen,&int):small logint0($1, $2, &$3) Doc: Return the largest integer $e$ so that $b^e \leq x$, where the parameters $b > 1$ and $x > 0$ are both integers. If the parameter $z$ is present, set it to $b^e$. \bprog ? logint(1000, 2) %1 = 9 ? 2^9 %2 = 512 ? logint(1000, 2, &z) %3 = 9 ? z %4 = 512 @eprog\noindent The number of digits used to write $b$ in base $x$ is \kbd{1 + logint(x,b)}: \bprog ? #digits(1000!, 10) %5 = 2568 ? logint(1000!, 10) %6 = 2567 @eprog\noindent This function may conveniently replace \bprog floor( log(x) / log(b) ) @eprog\noindent which may not give the correct answer since PARI does not guarantee exact rounding. pari-2.11.2/src/functions/number_theoretical/ffnbirred0000644000175000017500000000121413216034034021506 0ustar billbillFunction: ffnbirred Section: number_theoretical C-Name: ffnbirred0 Prototype: GLD0,L, Help: ffnbirred(q,n,{fl=0}): number of monic irreducible polynomials over F_q, of degree n (fl=0, default) or at most n (fl=1). Description: (int, small, ?0):int ffnbirred($1, $2) (int, small, 1):int ffsumnbirred($1, $2) (int, small, ?small):int ffnbirred0($1, $2, $3) Doc: computes the number of monic irreducible polynomials over $\F_q$ of degree exactly $n$, ($\fl=0$ or omitted) or at most $n$ ($\fl=1$). Variant: Also available are \fun{GEN}{ffnbirred}{GEN q, long n} (for $\fl=0$) and \fun{GEN}{ffsumnbirred}{GEN q, long n} (for $\fl=1$). pari-2.11.2/src/functions/number_theoretical/qfbprimeform0000644000175000017500000000117711636712103022252 0ustar billbillFunction: qfbprimeform Section: number_theoretical C-Name: primeform Prototype: GGp Help: qfbprimeform(x,p): returns the prime form of discriminant x, whose first coefficient is p. Doc: prime binary quadratic form of discriminant $x$ whose first coefficient is $p$, where $|p|$ is a prime number. By abuse of notation, $p = \pm 1$ is also valid and returns the unit form. Returns an error if $x$ is not a quadratic residue mod $p$, or if $x < 0$ and $p < 0$. (Negative definite \typ{QFI} are not implemented.) In the case where $x>0$, the ``distance'' component of the form is set equal to zero according to the current precision. pari-2.11.2/src/functions/number_theoretical/precprime0000644000175000017500000000076112314242551021544 0ustar billbillFunction: precprime Section: number_theoretical C-Name: precprime Prototype: G Help: precprime(x): largest pseudoprime <= x, 0 if x<=1. Description: (gen):int precprime($1) Doc: finds the largest pseudoprime (see \tet{ispseudoprime}) less than or equal to $x$. $x$ can be of any real type. Returns 0 if $x\le1$. Note that if $x$ is a prime, this function returns $x$ and not the largest prime strictly smaller than $x$. To rigorously prove that the result is prime, use \kbd{isprime}. pari-2.11.2/src/functions/number_theoretical/contfracpnqn0000644000175000017500000000272313326135265022261 0ustar billbillFunction: contfracpnqn Section: number_theoretical C-Name: contfracpnqn Prototype: GD-1,L, Help: contfracpnqn(x, {n=-1}): [p_n,p_{n-1}; q_n,q_{n-1}] corresponding to the continued fraction x. If n >= 0 is present, returns all convergents from p_0/q_0 up to p_n/q_n. Doc: when $x$ is a vector or a one-row matrix, $x$ is considered as the list of partial quotients $[a_0,a_1,\dots,a_n]$ of a rational number, and the result is the 2 by 2 matrix $[p_n,p_{n-1};q_n,q_{n-1}]$ in the standard notation of continued fractions, so $p_n/q_n=a_0+1/(a_1+\dots+1/a_n)$. If $x$ is a matrix with two rows $[b_0,b_1,\dots,b_n]$ and $[a_0,a_1,\dots,a_n]$, this is then considered as a generalized continued fraction and we have similarly $p_n/q_n=(1/b_0)(a_0+b_1/(a_1+\dots+b_n/a_n))$. Note that in this case one usually has $b_0=1$. If $n \geq 0$ is present, returns all convergents from $p_0/q_0$ up to $p_n/q_n$. (All convergents if $x$ is too small to compute the $n+1$ requested convergents.) \bprog ? a = contfrac(Pi,10) %1 = [3, 7, 15, 1, 292, 1, 1, 1, 3] ? allpnqn(x) = contfracpnqn(x,#x) \\ all convergents ? allpnqn(a) %3 = [3 22 333 355 103993 104348 208341 312689 1146408] [1 7 106 113 33102 33215 66317 99532 364913] ? contfracpnqn(a) \\ last two convergents %4 = [1146408 312689] [ 364913 99532] ? contfracpnqn(a,3) \\ first three convergents %5 = [3 22 333 355] [1 7 106 113] @eprog Variant: also available is \fun{GEN}{pnqn}{GEN x} for $n = -1$. pari-2.11.2/src/functions/number_theoretical/znorder0000644000175000017500000000140111636712103021232 0ustar billbillFunction: znorder Section: number_theoretical C-Name: znorder Prototype: GDG Help: znorder(x,{o}): order of the integermod x in (Z/nZ)*. Optional o represents a multiple of the order of the element. Description: (gen):int order($1) (gen,):int order($1) (gen,int):int znorder($1, $2) Doc: $x$ must be an integer mod $n$, and the result is the order of $x$ in the multiplicative group $(\Z/n\Z)^*$. Returns an error if $x$ is not invertible. The parameter o, if present, represents a non-zero multiple of the order of $x$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord = eulerphi(n)} is the cardinality of the group. Variant: Also available is \fun{GEN}{order}{GEN x}. pari-2.11.2/src/functions/number_theoretical/fflog0000644000175000017500000000356713447371554020700 0ustar billbillFunction: fflog Section: number_theoretical C-Name: fflog Prototype: GGDG Help: fflog(x,g,{o}): return the discrete logarithm of the finite field element x in base g. If present, o must represents the multiplicative order of g. If no o is given, assume that g is a primitive root. Doc: discrete logarithm of the finite field element $x$ in base $g$, i.e.~an $e$ in $\Z$ such that $g^e = o$. If present, $o$ represents the multiplicative order of $g$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord} is the order of $g$. It may be set as a side effect of calling \tet{ffprimroot}. If no $o$ is given, assume that $g$ is a primitive root. The result is undefined if $e$ does not exist. This function uses \item a combination of generic discrete log algorithms (see \tet{znlog}) \item a cubic sieve index calculus algorithm for large fields of degree at least $5$. \item Coppersmith's algorithm for fields of characteristic at most $5$. \bprog ? t = ffgen(ffinit(7,5)); ? o = fforder(t) %2 = 5602 \\@com \emph{not} a primitive root. ? fflog(t^10,t) %3 = 10 ? fflog(t^10,t, o) %4 = 10 ? g = ffprimroot(t, &o); ? o \\ order is 16806, bundled with its factorization matrix %6 = [16806, [2, 1; 3, 1; 2801, 1]] ? fforder(g, o) %7 = 16806 ? fflog(g^10000, g, o) %8 = 10000 @eprog Function: _Flxq_log_Coppersmith_worker C-Name: Flxq_log_Coppersmith_worker Prototype: GLGG Section: programming/internals Help: Flxq_log_Coppersmith_worker: worker for Flxq_log_Coppersmith Function: _F2xq_log_Coppersmith_worker C-Name: F2xq_log_Coppersmith_worker Prototype: GLGG Section: programming/internals Help: F2xq_log_Coppersmith_worker: worker for F2xq_log_Coppersmith Function: _Fp_log_sieve_worker C-Name: Fp_log_sieve_worker Prototype: LLGGGGGG Section: programming/internals Help: Fp_log_sieve_worker: worker for Fp_log_sieve pari-2.11.2/src/functions/number_theoretical/znconreychar0000644000175000017500000000550213447371554022277 0ustar billbillFunction: znconreychar Section: number_theoretical C-Name: znconreychar Prototype: GG Help: znconreychar(G,m): Dirichlet character attached to m in (Z/qZ)* in Conrey's notation, where G is znstar(q,1). Doc: Given a \var{znstar} $G$ attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}), this function returns the Dirichlet character attached to $m \in (\Z/q\Z)^*$ via Conrey's logarithm, which establishes a ``canonical'' bijection between $(\Z/q\Z)^*$ and its dual. Let $q = \prod_p p^{e_p}$ be the factorization of $q$ into distinct primes. For all odd $p$ with $e_p > 0$, let $g_p$ be the element in $(\Z/q\Z)^*$ which is \item congruent to $1$ mod $q/p^{e_p}$, \item congruent mod $p^{e_p}$ to the smallest positive integer that generates $(\Z/p^2\Z)^*$. For $p = 2$, we let $g_4$ (if $2^{e_2} \geq 4$) and $g_8$ (if furthermore ($2^{e_2} \geq 8$) be the elements in $(\Z/q\Z)^*$ which are \item congruent to $1$ mod $q/2^{e_2}$, \item $g_4 = -1 \mod 2^{e_2}$, \item $g_8 = 5 \mod 2^{e_2}$. Then the $g_p$ (and the extra $g_4$ and $g_8$ if $2^{e_2}\geq 2$) are independent generators of $(\Z/q\Z)^*$, i.e. every $m$ in $(\Z/q\Z)^*$ can be written uniquely as $\prod_p g_p^{m_p}$, where $m_p$ is defined modulo the order $o_p$ of $g_p$ and $p \in S_q$, the set of prime divisors of $q$ together with $4$ if $4 \mid q$ and $8$ if $8 \mid q$. Note that the $g_p$ are in general \emph{not} SNF generators as produced by \kbd{znstar} whenever $\omega(q) \geq 2$, although their number is the same. They however allow to handle the finite abelian group $(\Z/q\Z)^*$ in a fast and elegant way. (Which unfortunately does not generalize to ray class groups or Hecke characters.) The Conrey logarithm of $m$ is the vector $(m_p)_{p\in S_q}$, obtained via \tet{znconreylog}. The Conrey character $\chi_q(m,\cdot)$ attached to $m$ mod $q$ maps each $g_p$, $p\in S_q$ to $e(m_p / o_p)$, where $e(x) = \exp(2i\pi x)$. This function returns the Conrey character expressed in the standard PARI way in terms of the SNF generators \kbd{G.gen}. \bprog ? G = znstar(8,1); ? G.cyc %2 = [2, 2] \\ Z/2 x Z/2 ? G.gen %3 = [7, 3] ? znconreychar(G,1) \\ 1 is always the trivial character %4 = [0, 0] ? znconreychar(G,2) \\ 2 is not coprime to 8 !!! *** at top-level: znconreychar(G,2) *** ^----------------- *** znconreychar: elements not coprime in Zideallog: 2 8 *** Break loop: type 'break' to go back to GP prompt break> ? znconreychar(G,3) %5 = [0, 1] ? znconreychar(G,5) %6 = [1, 1] ? znconreychar(G,7) %7 = [1, 0] @eprog\noindent We indeed get all 4 characters of $(\Z/8\Z)^*$. For convenience, we allow to input the \emph{Conrey logarithm} of $m$ instead of $m$: \bprog ? G = znstar(55, 1); ? znconreychar(G,7) %2 = [7, 0] ? znconreychar(G, znconreylog(G,7)) %3 = [7, 0] @eprog pari-2.11.2/src/functions/number_theoretical/chargalois0000644000175000017500000000254413326135265021702 0ustar billbillFunction: chargalois Section: number_theoretical C-Name: chargalois Prototype: GDG Help: chargalois(cyc,{ORD}): let cyc represent a finite abelian group G by its elementary divisors cyc, return a list of representatives for the Galois orbits of characters of G. If ORD is present, select characters depending on their orders: if ORD is a t_INT, restrict to orders less than this bound; if ORD is a t_VEC or t_VECSMALL, restrict to orders in the list. Doc: Let \var{cyc} represent a finite abelian group by its elementary divisors (any object which has a \kbd{.cyc} method is also allowed, i.e. the output of \kbd{znstar} or \kbd{bnrinit}). Return a list of representatives for the Galois orbits of complex characters of $G$. If \kbd{ORD} is present, select characters depending on their orders: \item if \kbd{ORD} is a \typ{INT}, restrict to orders less than this bound; \item if \kbd{ORD} is a \typ{VEC} or \typ{VECSMALL}, restrict to orders in the list. \bprog ? G = znstar(96); ? #chargalois(G) \\ 16 orbits of characters mod 96 %2 = 16 ? #chargalois(G,4) \\ order less than 4 %3 = 12 ? chargalois(G,[1,4]) \\ order 1 or 4; 5 orbits %4 = [[0, 0, 0], [2, 0, 0], [2, 1, 0], [2, 0, 1], [2, 1, 1]] @eprog\noindent Given a character $\chi$, of order $n$ (\kbd{charorder(G,chi)}), the elements in its orbit are the $\phi(n)$ characters $\chi^i$, $(i,n)=1$. pari-2.11.2/src/functions/number_theoretical/charmul0000644000175000017500000000341013326135265021212 0ustar billbillFunction: charmul Section: number_theoretical C-Name: charmul0 Prototype: GGG Help: charmul(cyc, a,b): given a finite abelian group (by its elementary divisors cyc) and two characters a and b, return the product character ab. Doc: let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $a = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. Given two characters $a$ and $b$, return the product character $ab$. \bprog ? cyc = [15,5]; a = [1,1]; b = [2,4]; ? charmul(cyc, a,b) %2 = [3, 0] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charmul(bnf, [1], [2]) %5 = [0] @eprog\noindent For Dirichlet characters on $(\Z/N\Z)^*$, additional representations are available (Conrey labels, Conrey logarithm), see \secref{se:dirichletchar} or \kbd{??character}. If the two characters are in the same format, their product is given in the same format, otherwise a Conrey logarithm is used. \bprog ? G = znstar(100, 1); ? G.cyc %2 = [20, 2] ? a = [10, 1]; \\ usual representation for characters ? b = 7; \\ Conrey label; ? c = znconreylog(G, 11); \\ Conrey log ? charmul(G, b,b) %6 = 49 \\ Conrey label ? charmul(G, a,b) %7 = [0, 15]~ \\ Conrey log ? charmul(G, a,c) %7 = [0, 6]~ \\ Conrey log @eprog Variant: Also available is \fun{GEN}{charmul}{GEN cyc, GEN a, GEN b}, when \kbd{cyc} is known to be a vector of elementary divisors and $a, b$ are compatible characters (no checks). pari-2.11.2/src/functions/number_theoretical/core0000644000175000017500000000122511636712103020503 0ustar billbillFunction: core Section: number_theoretical C-Name: core0 Prototype: GD0,L, Help: core(n,{flag=0}): unique squarefree integer d dividing n such that n/d is a square. If (optional) flag is non-null, output the two-component row vector [d,f], where d is the unique squarefree integer dividing n such that n/d=f^2 is a square. Doc: if $n$ is an integer written as $n=df^2$ with $d$ squarefree, returns $d$. If $\fl$ is non-zero, returns the two-element row vector $[d,f]$. By convention, we write $0 = 0 \times 1^2$, so \kbd{core(0, 1)} returns $[0,1]$. Variant: Also available are \fun{GEN}{core}{GEN n} ($\fl = 0$) and \fun{GEN}{core2}{GEN n} ($\fl = 1$) pari-2.11.2/src/functions/number_theoretical/bestapprPade0000644000175000017500000000452613457670572022214 0ustar billbillFunction: bestapprPade Section: number_theoretical C-Name: bestapprPade Prototype: GD-1,L, Help: bestapprPade(x, {B}): returns a rational function approximation to x. This function applies to series, polmods, and rational functions of course. Otherwise it applies recursively to all components. Doc: using variants of the extended Euclidean algorithm (Pad\'{e} approximants), returns a rational function approximation $a/b$ to $x$, whose denominator is limited by $B$, if present. If $B$ is omitted, return the best approximation affordable given the input accuracy; if you are looking for true rational functions, presumably approximated to sufficient accuracy, you should first try that option. Otherwise, $B$ must be a non-negative real (impose $0 \leq \text{degree}(b) \leq B$). \item If $x$ is a \typ{POLMOD} modulo $N$ this function performs rational modular reconstruction modulo $N$. The routine then returns the unique rational function $a/b$ in coprime polynomials, with $\text{degree}(b)\leq B$ and $\text{degree}(a)$ minimal, which is congruent to $x$ modulo $N$. Omitting $B$ amounts to choosing it equal to the floor of $\text{degree}(N) / 2$. If rational reconstruction is not possible (no suitable $a/b$ exists), returns $[]$. \bprog ? T = Mod(x^3 + x^2 + x + 3, x^4 - 2); ? bestapprPade(T) %2 = (2*x - 1)/(x - 1) ? U = Mod(1 + x + x^2 + x^3 + x^5, x^9); ? bestapprPade(U) \\ internally chooses B = 4 %3 = [] ? bestapprPade(U, 5) \\ with B = 5, a solution exists %4 = (2*x^4 + x^3 - x - 1)/(-x^5 + x^3 + x^2 - 1) @eprog \item If $x$ is a \typ{SER}, we implicitly convert the input to a \typ{POLMOD} modulo $N = t^k$ where $k$ is the series absolute precision. \bprog ? T = 1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + O(t^7); \\ mod t^7 ? bestapprPade(T) %1 = 1/(-t + 1) @eprog \item If $x$ is a \typ{RFRAC}, we implicitly convert the input to a \typ{POLMOD} modulo $N = t^k$ where $k = 2B + 1$. If $B$ was omitted, we return $x$: \bprog ? T = (4*t^2 + 2*t + 3)/(t+1)^10; ? bestapprPade(T,1) %2 = [] \\ impossible ? bestapprPade(T,2) %3 = 27/(337*t^2 + 84*t + 9) ? bestapprPade(T,3) %4 = (4253*t - 3345)/(-39007*t^3 - 28519*t^2 - 8989*t - 1115) @eprog\noindent The function applies recursively to components of complex objects (polynomials, vectors, \dots). If rational reconstruction fails for even a single entry, return $[]$. pari-2.11.2/src/functions/number_theoretical/numdiv0000644000175000017500000000033512314242551021055 0ustar billbillFunction: numdiv Section: number_theoretical C-Name: numdiv Prototype: G Help: numdiv(x): number of divisors of x. Description: (gen):int numdiv($1) Doc: number of divisors of $|x|$. $x$ must be of type integer. pari-2.11.2/src/functions/number_theoretical/dirmul0000644000175000017500000000126113036414402021044 0ustar billbillFunction: dirmul Section: number_theoretical C-Name: dirmul Prototype: GG Help: dirmul(x,y): multiplication of the Dirichlet series x by the Dirichlet series y. Doc: $x$ and $y$ being vectors of perhaps different lengths representing the \idx{Dirichlet series} $\sum_n x_n n^{-s}$ and $\sum_n y_n n^{-s}$, computes the product of $x$ by $y$, again as a vector. \bprog ? dirmul(vector(10,n,1), vector(10,n,moebius(n))) %1 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] @eprog\noindent The product length is the minimum of $\kbd{\#}x\kbd{*}v(y)$ and $\kbd{\#}y\kbd{*}v(x)$, where $v(x)$ is the index of the first non-zero coefficient. \bprog ? dirmul([0,1], [0,1]); %2 = [0, 0, 0, 1] @eprog pari-2.11.2/src/functions/number_theoretical/sumdigits0000644000175000017500000000115113457566437021605 0ustar billbillFunction: sumdigits Section: number_theoretical C-Name: sumdigits0 Prototype: GDG Help: sumdigits(n,{B=10}): sum of digits in the integer |n|, when written in base B. Doc: sum of digits in the integer $|n|$, when written in base $B > 1$. \bprog ? sumdigits(123456789) %1 = 45 ? sumdigits(123456789, 2) %1 = 16 @eprog\noindent Note that the sum of bits in $n$ is also returned by \tet{hammingweight}. This function is much faster than \kbd{vecsum(digits(n,B))} when $B$ is $10$ or a power of $2$, and only slightly faster in other cases. Variant: Also available is \fun{GEN}{sumdigits}{GEN n}, for $B = 10$. pari-2.11.2/src/functions/number_theoretical/factorcantor0000644000175000017500000000033013326135265022242 0ustar billbillFunction: factorcantor Section: number_theoretical C-Name: factmod Prototype: GG Obsolete: 2018-02-28 Help: factorcantor(x,p): this function is obsolete, use factormod. Doc: this function is obsolete, use factormod. pari-2.11.2/src/functions/number_theoretical/moebius0000644000175000017500000000030113326135265021216 0ustar billbillFunction: moebius Section: number_theoretical C-Name: moebius Prototype: lG Help: moebius(x): Moebius function of x. Doc: \idx{Moebius} $\mu$-function of $|x|$; $x$ must be a non-zero integer. pari-2.11.2/src/functions/number_theoretical/sigma0000644000175000017500000000072312314242551020654 0ustar billbillFunction: sigma Section: number_theoretical C-Name: sumdivk Prototype: GD1,L, Help: sigma(x,{k=1}): sum of the k-th powers of the divisors of x. k is optional and if omitted is assumed to be equal to 1. Description: (gen, ?1):int sumdiv($1) (gen, 0):int numdiv($1) Doc: sum of the $k^{\text{th}}$ powers of the positive divisors of $|x|$. $x$ and $k$ must be of type integer. Variant: Also available is \fun{GEN}{sumdiv}{GEN n}, for $k = 1$. pari-2.11.2/src/functions/number_theoretical/quadclassunit0000644000175000017500000000616713326135265022453 0ustar billbillFunction: quadclassunit Section: number_theoretical C-Name: quadclassunit0 Prototype: GD0,L,DGp Help: quadclassunit(D,{flag=0},{tech=[]}): compute the structure of the class group and the regulator of the quadratic field of discriminant D. See manual for the optional technical parameters. Doc: \idx{Buchmann-McCurley}'s sub-exponential algorithm for computing the class group of a quadratic order of discriminant $D$. This function should be used instead of \tet{qfbclassno} or \tet{quadregula} when $D<-10^{25}$, $D>10^{10}$, or when the \emph{structure} is wanted. It is a special case of \tet{bnfinit}, which is slower, but more robust. The result is a vector $v$ whose components should be accessed using member functions: \item \kbd{$v$.no}: the class number \item \kbd{$v$.cyc}: a vector giving the structure of the class group as a product of cyclic groups; \item \kbd{$v$.gen}: a vector giving generators of those cyclic groups (as binary quadratic forms). \item \kbd{$v$.reg}: the regulator, computed to an accuracy which is the maximum of an internal accuracy determined by the program and the current default (note that once the regulator is known to a small accuracy it is trivial to compute it to very high accuracy, see the tutorial). The $\fl$ is obsolete and should be left alone. In older versions, it supposedly computed the narrow class group when $D>0$, but this did not work at all; use the general function \tet{bnfnarrow}. Optional parameter \var{tech} is a row vector of the form $[c_1, c_2]$, where $c_1 \leq c_2$ are non-negative real numbers which control the execution time and the stack size, see \ref{se:GRHbnf}. The parameter is used as a threshold to balance the relation finding phase against the final linear algebra. Increasing the default $c_1$ means that relations are easier to find, but more relations are needed and the linear algebra will be harder. The default value for $c_1$ is $0$ and means that it is taken equal to $c_2$. The parameter $c_2$ is mostly obsolete and should not be changed, but we still document it for completeness: we compute a tentative class group by generators and relations using a factorbase of prime ideals $\leq c_1 (\log |D|)^2$, then prove that ideals of norm $\leq c_2 (\log |D|)^2$ do not generate a larger group. By default an optimal $c_2$ is chosen, so that the result is provably correct under the GRH --- a famous result of Bach states that $c_2 = 6$ is fine, but it is possible to improve on this algorithmically. You may provide a smaller $c_2$, it will be ignored (we use the provably correct one); you may provide a larger $c_2$ than the default value, which results in longer computing times for equally correct outputs (under GRH). Variant: If you really need to experiment with the \var{tech} parameter, it is usually more convenient to use \fun{GEN}{Buchquad}{GEN D, double c1, double c2, long prec}. If only the class number is needed, \fun{GEN}{quadclassno}{GEN D} will be faster (still assuming the GRH), but will not provide the group structure. For negative $D$, $|D| < 10^{20}$, \tet{qfbclassno} should be faster but may return a wrong result. pari-2.11.2/src/functions/number_theoretical/quaddisc0000644000175000017500000000103513201017466021347 0ustar billbillFunction: quaddisc Section: number_theoretical C-Name: quaddisc Prototype: G Help: quaddisc(x): discriminant of the quadratic field Q(sqrt(x)). Doc: discriminant of the \'etale algebra $\Q(\sqrt{x})$, where $x\in\Q^*$. This is the same as \kbd{coredisc}$(d)$ where $d$ is the integer square-free part of $x$, so x=$d f^2$ with $f\in \Q^*$ and $d\in\Z$. This returns $0$ for $x = 0$, $1$ for $x$ square and the discriminant of the quadratic field $\Q(\sqrt{x})$ otherwise. \bprog ? quaddisc(7) %1 = 28 ? quaddisc(-7) %2 = -7 @eprog pari-2.11.2/src/functions/number_theoretical/quadgen0000644000175000017500000000163713326135265021214 0ustar billbillFunction: quadgen Section: number_theoretical C-Name: quadgen0 Prototype: GDn Help: quadgen(D,{v = 'w}): standard generator g of quadratic order of discriminant D. If v is given, the variable name is used to display g, else 'w' is used. Doc: creates the quadratic number\sidx{omega} $\omega=(a+\sqrt{D})/2$ where $a=0$ if $D\equiv0\mod4$, $a=1$ if $D\equiv1\mod4$, so that $(1,\omega)$ is an integral basis for the quadratic order of discriminant $D$. $D$ must be an integer congruent to 0 or 1 modulo 4, which is not a square. If \var{v} is given, the variable name is used to display $g$ else 'w' is used. \bprog ? w = quadgen(5, 'w); w^2 - w - 1 %1 = 0 ? w = quadgen(0, 'w) *** at top-level: w=quadgen(0) *** ^---------- *** quadgen: domain error in quadpoly: issquare(disc) = 1 @eprog Variant: When \var{v} does not matter, the function \fun{GEN}{quadgen}{GEN D} is also available. pari-2.11.2/src/functions/number_theoretical/bestapprnf0000644000175000017500000000303513326135265021726 0ustar billbillFunction: bestapprnf Section: linear_algebra C-Name: bestapprnf Prototype: GGDGp Help: bestapprnf(V,T,{rootT}): T being an integral polynomial and V being a scalar, vector, or matrix, return a reasonable approximation of V with polmods modulo T. The rootT argument, if present, must be an element of polroots(T), i.e. a root of T fixing a complex embedding of Q[x]/(T). Doc: $T$ being an integral polynomial and $V$ being a scalar, vector, or matrix with complex coefficients, return a reasonable approximation of $V$ with polmods modulo $T$. $T$ can also be any number field structure, in which case the minimal polynomial attached to the structure (\kbd{$T$}.pol) is used. The \var{rootT} argument, if present, must be an element of \kbd{polroots($T$)} (or \kbd{$T$}.pol), i.e.~a complex root of $T$ fixing an embedding of $\Q[x]/(T)$ into $\C$. \bprog ? bestapprnf(sqrt(5), polcyclo(5)) %1 = Mod(-2*x^3 - 2*x^2 - 1, x^4 + x^3 + x^2 + x + 1) ? bestapprnf(sqrt(5), polcyclo(5), exp(4*I*Pi/5)) %2 = Mod(2*x^3 + 2*x^2 + 1, x^4 + x^3 + x^2 + x + 1) @eprog\noindent When the output has huge rational coefficients, try to increase the working \kbd{realbitprecision}: if the answer does not stabilize, consider that the reconstruction failed. Beware that if $T$ is not Galois over $\Q$, some embeddings may not allow to reconstruct $V$: \bprog ? T = x^3-2; vT = polroots(T); z = 3*2^(1/3)+1; ? bestapprnf(z, T, vT[1]) %2 = Mod(3*x + 1, x^3 - 2) ? bestapprnf(z, T, vT[2]) %3 = 4213714286230872/186454048314072 \\ close to 3*2^(1/3) + 1 @eprog pari-2.11.2/src/functions/number_theoretical/sqrtnint0000644000175000017500000000077513036414402021443 0ustar billbillFunction: sqrtnint Section: number_theoretical C-Name: sqrtnint Prototype: GL Help: sqrtnint(x,n): integer n-th root of x, where x is non-negative integer. Description: (gen,small):int sqrtnint($1, $2) Doc: returns the integer $n$-th root of $x$, i.e. the largest integer $y$ such that $y^n \leq x$, where $x$ is a non-negative integer. \bprog ? N = 120938191237; sqrtnint(N, 5) %1 = 164 ? N^(1/5) %2 = 164.63140849829660842958614676939677391 @eprog\noindent The special case $n = 2$ is \tet{sqrtint} pari-2.11.2/src/functions/number_theoretical/ffextend0000644000175000017500000000216613326135265021371 0ustar billbillFunction: ffextend Section: number_theoretical C-Name: ffextend Prototype: GGDn Help: ffextend(a, P, {v}): extend the field K of definition of a by a root of the polynomial P, assumed to be irreducible over K. Return [r, m] where r is a root of P in the extension field L and m is a map from K to L, see \kbd{ffmap}. If v is given, the variable name is used to display the generator of L, else the name of the variable of P is used. Doc: extend the field $K$ of definition of $a$ by a root of the polynomial $P\in K[X]$ assumed to be irreducible over $K$. Return $[r, m]$ where $r$ is a root of $P$ in the extension field $L$ and $m$ is a map from $K$ to $L$, see \kbd{ffmap}. If $v$ is given, the variable name is used to display the generator of $L$, else the name of the variable of $P$ is used. A generator of $L$ can be recovered using $b=ffgen(r)$. The image of $P$ in $L[X]$ can be recovered using $PL=ffmap(m,P)$. \bprog ? a = ffgen([3,5],'a); ? P = x^2-a; polisirreducible(P) %2 = 1 ? [r,m] = ffextend(a, P, 'b); ? r %3 = b^9+2*b^8+b^7+2*b^6+b^4+1 ? subst(ffmap(m, P), x, r) %4 = 0 ? ffgen(r) %5 = b @eprog pari-2.11.2/src/functions/number_theoretical/qfbnucomp0000644000175000017500000000154413201017466021551 0ustar billbillFunction: qfbnucomp Section: number_theoretical C-Name: nucomp Prototype: GGG Help: qfbnucomp(x,y,L): composite of primitive positive definite quadratic forms x and y using nucomp and nudupl, where L=[|D/4|^(1/4)] is precomputed. Doc: \idx{composition} of the primitive positive definite binary quadratic forms $x$ and $y$ (type \typ{QFI}) using the NUCOMP and NUDUPL algorithms of \idx{Shanks}, \`a la Atkin. $L$ is any positive constant, but for optimal speed, one should take $L=|D/4|^{1/4}$, i.e. \kbd{sqrtnint(abs(D)>>2,4)}, where $D$ is the common discriminant of $x$ and $y$. When $x$ and $y$ do not have the same discriminant, the result is undefined. The current implementation is slower than the generic routine for small $D$, and becomes faster when $D$ has about $45$ bits. Variant: Also available is \fun{GEN}{nudupl}{GEN x, GEN L} when $x=y$. pari-2.11.2/src/functions/number_theoretical/charpow0000644000175000017500000000325613326135265021232 0ustar billbillFunction: charpow Section: number_theoretical C-Name: charpow0 Prototype: GGG Help: charpow(cyc, a,n): given a finite abelian group (by its elementary divisors cyc) a character a and an integer n return the character a^n. Doc: let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $a = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. Given $n\in \Z$ and a character $a$, return the character $a^n$. \bprog ? cyc = [15,5]; a = [1,1]; ? charpow(cyc, a, 3) %2 = [3, 3] ? charpow(cyc, a, 5) %2 = [5, 0] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charpow(bnf, [1], 3) %5 = [0] @eprog\noindent For Dirichlet characters on $(\Z/N\Z)^*$, additional representations are available (Conrey labels, Conrey logarithm), see \secref{se:dirichletchar} or \kbd{??character} and the output uses the same format as the input. \bprog ? G = znstar(100, 1); ? G.cyc %2 = [20, 2] ? a = [10, 1]; \\ standard representation for characters ? b = 7; \\ Conrey label; ? c = znconreylog(G, 11); \\ Conrey log ? charpow(G, a,3) %6 = [10, 1] \\ standard representation ? charpow(G, b,3) %7 = 43 \\ Conrey label ? charpow(G, c,3) %8 = [1, 8]~ \\ Conrey log @eprog Variant: Also available is \fun{GEN}{charpow}{GEN cyc, GEN a, GEN n}, when \kbd{cyc} is known to be a vector of elementary divisors (no check). pari-2.11.2/src/functions/number_theoretical/issquarefree0000644000175000017500000000274213326135265022264 0ustar billbillFunction: issquarefree Section: number_theoretical C-Name: issquarefree Prototype: lG Help: issquarefree(x): true(1) if x is squarefree, false(0) if not. Description: (gen):bool issquarefree($1) Doc: true (1) if $x$ is squarefree, false (0) if not. Here $x$ can be an integer or a polynomial with coefficients in an integral domain. \bprog ? issquarefree(12) %1 = 0 ? issquarefree(6) %2 = 1 ? issquarefree(x^3+x^2) %3 = 0 ? issquarefree(Mod(1,4)*(x^2+x+1)) \\ Z/4Z is not a domain ! *** at top-level: issquarefree(Mod(1,4)*(x^2+x+1)) *** ^-------------------------------- *** issquarefree: impossible inverse in Fp_inv: Mod(2, 4). @eprog\noindent A polynomial is declared squarefree if \kbd{gcd}$(x,x')$ is $1$. In particular a non-zero polynomial with inexact coefficients is considered to be squarefree. Note that this may be inconsistent with \kbd{factor}, which first rounds the input to some exact approximation before factoring in the apropriate domain; this is correct when the input is not close to an inseparable polynomial (the resultant of $x$ and $x'$ is not close to $0$). An integer can be input in factored form as in arithmetic functions. \bprog ? issquarefree(factor(6)) %1 = 1 \\ count squarefree integers up to 10^8 ? c = 0; for(d = 1, 10^8, if (issquarefree(d), c++)); c time = 3min, 2,590 ms. %2 = 60792694 ? c = 0; forfactored(d = 1, 10^8, if (issquarefree(d), c++)); c time = 45,348 ms. \\ faster ! %3 = 60792694 @eprog pari-2.11.2/src/functions/number_theoretical/factorial0000644000175000017500000000053311636712103021520 0ustar billbillFunction: factorial Section: number_theoretical C-Name: mpfactr Prototype: Lp Help: factorial(x): factorial of x, the result being given as a real number. Doc: factorial of $x$. The expression $x!$ gives a result which is an integer, while $\kbd{factorial}(x)$ gives a real number. Variant: \fun{GEN}{mpfact}{long x} returns $x!$ as a \typ{INT}. pari-2.11.2/src/functions/number_theoretical/bezout0000644000175000017500000000026713201017466021070 0ustar billbillFunction: bezout Section: number_theoretical C-Name: gcdext0 Prototype: GG Obsolete: 2013-04-03 Help: bezout(x,y): deprecated alias for gcdext. Doc: deprecated alias for \kbd{gcdext} pari-2.11.2/src/functions/number_theoretical/factormodDDF0000644000175000017500000000351613326135265022062 0ustar billbillFunction: factormodDDF Section: number_theoretical C-Name: factormodDDF Prototype: GDG Help: factormodDDF(f,{D}): distinct-degree factorization of the squarefree polynomial f over the finite field defined by the domain D. Doc: distinct-degree factorization of the squarefree polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. This is somewhat faster than full factorization. The coefficients of $f$ must be operation-compatible with the corresponding finite field. The result is a two-column matrix: \item the first column contains monic (squarefree) pairwise coprime polynomials dividing $f$, all of whose irreducible factors have degree $d$; \item the second column contains the degrees of the irreducible factors. The factors are ordered by increasing degree and the result is canonical: it will not change across multiple calls or sessions. \bprog ? f = (x^2 + 1) * (x^2-1); ? factormodSQF(f,3) \\ squarefree over F_3 %2 = [Mod(1, 3)*x^4 + Mod(2, 3) 1] ? factormodDDF(f, 3) %3 = [Mod(1, 3)*x^2 + Mod(2, 3) 1] \\ two degree 1 factors [Mod(1, 3)*x^2 + Mod(1, 3) 2] \\ irred of degree 2 ? for(i=1,10^5,factormodDDF(f,3)) time = 424 ms. ? for(i=1,10^5,factormod(f,3)) \\ full factorization is slower time = 464 ms. ? liftall( factormodDDF(x^2 + 1, [3, t^2+1]) ) \\ over F_9 %6 = [x^2 + 1 1] \\ product of two degree 1 factors ? t = ffgen(t^2+Mod(1,3)); factormodDDF(x^2 + t^0) \\ same using t_FFELT %7 = [x^2 + 1 1] ? factormodDDF(x^2-Mod(1,3)) %8 = [Mod(1, 3)*x^2 + Mod(2, 3) 1] @eprog pari-2.11.2/src/functions/number_theoretical/ramanujantau0000644000175000017500000000172613201017466022247 0ustar billbillFunction: ramanujantau Section: number_theoretical C-Name: ramanujantau Prototype: G Help: ramanujantau(n): compute the value of Ramanujan's tau function at n, assuming the GRH. Algorithm in O(n^{1/2+eps}). Doc: compute the value of Ramanujan's tau function at an individual $n$, assuming the truth of the GRH (to compute quickly class numbers of imaginary quadratic fields using \tet{quadclassunit}). Algorithm in $\tilde{O}(n^{1/2})$ using $O(\log n)$ space. If all values up to $N$ are required, then $$\sum \tau(n)q^n = q \prod_{n\geq 1} (1-q^n)^{24}$$ will produce them in time $\tilde{O}(N)$, against $\tilde{O}(N^{3/2})$ for individual calls to \kbd{ramanujantau}; of course the space complexity then becomes $\tilde{O}(N)$. \bprog ? tauvec(N) = Vec(q*eta(q + O(q^N))^24); ? N = 10^4; v = tauvec(N); time = 26 ms. ? ramanujantau(N) %3 = -482606811957501440000 ? w = vector(N, n, ramanujantau(n)); \\ much slower ! time = 13,190 ms. ? v == w %4 = 1 @eprog pari-2.11.2/src/functions/number_theoretical/chinese0000644000175000017500000000442313326135265021202 0ustar billbillFunction: chinese Section: number_theoretical C-Name: chinese Prototype: GDG Help: chinese(x,{y}): x,y being both intmods (or polmods) computes z in the same residue classes as x and y. Description: (gen):gen chinese1($1) (gen, gen):gen chinese($1, $2) Doc: if $x$ and $y$ are both intmods or both polmods, creates (with the same type) a $z$ in the same residue class as $x$ and in the same residue class as $y$, if it is possible. \bprog ? chinese(Mod(1,2), Mod(2,3)) %1 = Mod(5, 6) ? chinese(Mod(x,x^2-1), Mod(x+1,x^2+1)) %2 = Mod(-1/2*x^2 + x + 1/2, x^4 - 1) @eprog\noindent This function also allows vector and matrix arguments, in which case the operation is recursively applied to each component of the vector or matrix. \bprog ? chinese([Mod(1,2),Mod(1,3)], [Mod(1,5),Mod(2,7)]) %3 = [Mod(1, 10), Mod(16, 21)] @eprog\noindent For polynomial arguments in the same variable, the function is applied to each coefficient; if the polynomials have different degrees, the high degree terms are copied verbatim in the result, as if the missing high degree terms in the polynomial of lowest degree had been \kbd{Mod(0,1)}. Since the latter behavior is usually \emph{not} the desired one, we propose to convert the polynomials to vectors of the same length first: \bprog ? P = x+1; Q = x^2+2*x+1; ? chinese(P*Mod(1,2), Q*Mod(1,3)) %4 = Mod(1, 3)*x^2 + Mod(5, 6)*x + Mod(3, 6) ? chinese(Vec(P,3)*Mod(1,2), Vec(Q,3)*Mod(1,3)) %5 = [Mod(1, 6), Mod(5, 6), Mod(4, 6)] ? Pol(%) %6 = Mod(1, 6)*x^2 + Mod(5, 6)*x + Mod(4, 6) @eprog If $y$ is omitted, and $x$ is a vector, \kbd{chinese} is applied recursively to the components of $x$, yielding a residue belonging to the same class as all components of $x$. Finally $\kbd{chinese}(x,x) = x$ regardless of the type of $x$; this allows vector arguments to contain other data, so long as they are identical in both vectors. Variant: \fun{GEN}{chinese1}{GEN x} is also available. Function: _polint_worker Section: programming/internals C-Name: nmV_polint_center_tree_worker Prototype: GGGGG Help: used for parallel chinese Doc: used for parallel chinese Function: _nxMV_polint_worker Section: programming/internals C-Name: nxMV_polint_center_tree_worker Prototype: GGGGG Help: used for parallel chinese Doc: used for parallel chinese pari-2.11.2/src/functions/number_theoretical/isfundamental0000644000175000017500000000135713326135265022421 0ustar billbillFunction: isfundamental Section: number_theoretical C-Name: isfundamental Prototype: lG Help: isfundamental(D): true(1) if D is a fundamental discriminant (including 1), false(0) if not. Description: (int):bool Z_isfundamental($1) (gen):bool isfundamental($1) Doc: true (1) if $D$ is equal to 1 or to the discriminant of a quadratic field, false (0) otherwise. $D$ can be input in factored form as for arithmetic functions: \bprog ? isfundamental(factor(-8)) %1 = 1 \\ count fundamental discriminants up to 10^8 ? c = 0; forfactored(d = 1, 10^8, if (isfundamental(d), c++)); c time = 40,840 ms. %2 = 30396325 ? c = 0; for(d = 1, 10^8, if (isfundamental(d), c++)); c time = 1min, 33,593 ms. \\ slower ! %3 = 30396325 @eprog pari-2.11.2/src/functions/number_theoretical/qfbpowraw0000644000175000017500000000052211636712103021562 0ustar billbillFunction: qfbpowraw Section: number_theoretical C-Name: qfbpowraw Prototype: GL Help: qfbpowraw(x,n): n-th power without reduction of the binary quadratic form x. Doc: $n$-th power of the binary quadratic form $x$, computed without doing any \idx{reduction} (i.e.~using \kbd{qfbcompraw}). Here $n$ must be non-negative and $n<2^{31}$. pari-2.11.2/src/functions/number_theoretical/isprimepower0000644000175000017500000000073012314242551022277 0ustar billbillFunction: isprimepower Section: number_theoretical C-Name: isprimepower Prototype: lGD& Help: isprimepower(x,{&n}): if x = p^k is a prime power (p prime, k > 0), return k, else return 0. If n is present, and the function returns a non-zero result, set n to p, the k-th root of x. Doc: if $x = p^k$ is a prime power ($p$ prime, $k > 0$), return $k$, else return 0. If a second argument $\&n$ is given and $x$ is indeed the $k$-th power of a prime $p$, sets $n$ to $p$. pari-2.11.2/src/functions/number_theoretical/fforder0000644000175000017500000000153412314242551021204 0ustar billbillFunction: fforder Section: number_theoretical C-Name: fforder Prototype: GDG Help: fforder(x,{o}): multiplicative order of the finite field element x. Optional o represents a multiple of the order of the element. Doc: multiplicative order of the finite field element $x$. If $o$ is present, it represents a multiple of the order of the element, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[N, factor(N)]}, where \kbd{N} is the cardinality of the multiplicative group of the underlying finite field. \bprog ? t = ffgen(ffinit(nextprime(10^8), 5)); ? g = ffprimroot(t, &o); \\@com o will be useful! ? fforder(g^1000000, o) time = 0 ms. %5 = 5000001750000245000017150000600250008403 ? fforder(g^1000000) time = 16 ms. \\@com noticeably slower, same result of course %6 = 5000001750000245000017150000600250008403 @eprog pari-2.11.2/src/functions/number_theoretical/ffinit0000644000175000017500000000127713036414402021036 0ustar billbillFunction: ffinit Section: number_theoretical C-Name: ffinit Prototype: GLDn Help: ffinit(p,n,{v='x}): monic irreducible polynomial of degree n over F_p[v]. Description: (int, small, ?var):pol ffinit($1, $2, $3) Doc: computes a monic polynomial of degree $n$ which is irreducible over $\F_p$, where $p$ is assumed to be prime. This function uses a fast variant of Adleman and Lenstra's algorithm. It is useful in conjunction with \tet{ffgen}; for instance if \kbd{P = ffinit(3,2)}, you can represent elements in $\F_{3^2}$ in term of \kbd{g = ffgen(P,'t)}. This can be abbreviated as \kbd{g = ffgen(3\pow2, 't)}, where the defining polynomial $P$ can be later recovered as \kbd{g.mod}. pari-2.11.2/src/functions/number_theoretical/znprimroot0000644000175000017500000000126213036414402021774 0ustar billbillFunction: znprimroot Section: number_theoretical C-Name: znprimroot Prototype: G Help: znprimroot(n): returns a primitive root of n when it exists. Doc: returns a primitive root (generator) of $(\Z/n\Z)^*$, whenever this latter group is cyclic ($n = 4$ or $n = 2p^k$ or $n = p^k$, where $p$ is an odd prime and $k \geq 0$). If the group is not cyclic, the result is undefined. If $n$ is a prime power, then the smallest positive primitive root is returned. This may not be true for $n = 2p^k$, $p$ odd. Note that this function requires factoring $p-1$ for $p$ as above, in order to determine the exact order of elements in $(\Z/n\Z)^*$: this is likely to be costly if $p$ is large. pari-2.11.2/src/functions/number_theoretical/factorff0000644000175000017500000000033113326135265021350 0ustar billbillFunction: factorff Section: number_theoretical C-Name: factorff Prototype: GDGDG Obsolete: 2018-03-11 Help: factorff(x,{p},{a}): obsolete, use factormod. Doc: obsolete, kept for backward compatibility: use factormod. pari-2.11.2/src/functions/number_theoretical/quadray0000644000175000017500000000114411636712103021221 0ustar billbillFunction: quadray Section: number_theoretical C-Name: quadray Prototype: GGp Help: quadray(D,f): relative equation for the ray class field of conductor f for the quadratic field of discriminant D (which can also be a bnf). Doc: relative equation for the ray class field of conductor $f$ for the quadratic field of discriminant $D$ using analytic methods. A \kbd{bnf} for $x^2 - D$ is also accepted in place of $D$. For $D < 0$, uses the $\sigma$ function and Schertz's method. For $D>0$, uses Stark's conjecture, and a vector of relative equations may be returned. See \tet{bnrstark} for more details. pari-2.11.2/src/functions/number_theoretical/znchartoprimitive0000644000175000017500000000207413326135265023345 0ustar billbillFunction: znchartoprimitive Section: number_theoretical C-Name: znchartoprimitive Prototype: GG Help: znchartoprimitive(G,chi): let G be znstar(q,1) and chi be a Dirichlet character on (Z/qZ)* of conductor q0. Return [G0,chi0], where chi0 is the primitive character attached to chi and G0 is znstar(q0). Doc: Let \var{G} be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$, of conductor $q_0 \mid q$. \bprog ? G = znstar(126000, 1); ? [G0,chi0] = znchartoprimitive(G,11) ? G0.mod %3 = 126000 ? chi0 %4 = 11 ? [G0,chi0] = znchartoprimitive(G,1);\\ trivial character, not primitive! ? G0.mod %6 = 1 ? chi0 %7 = []~ ? [G0,chi0] = znchartoprimitive(G,1009) ? G0.mod %4 = 125 ? chi0 %5 = [14]~ @eprog\noindent Note that \kbd{znconreyconductor} is more efficient since it can return $\chi_0$ and its conductor $q_0$ without needing to initialize $G_0$. (The price to pay is a more cryptic format and the need to initalize $G_0$ later but the can be done once for all characters of conductor $q_0$.) pari-2.11.2/src/functions/number_theoretical/znchardecompose0000644000175000017500000000230113326135265022741 0ustar billbillFunction: znchardecompose Section: number_theoretical C-Name: znchardecompose Prototype: GGG Help: znchardecompose(G, chi, Q): given a znstar G = (Z/NZ)^* and a Dirichlet character chi, return the product of local characters chi_p for p | (N,Q). Doc: Let $N = \prod_p p^{e_p}$ and a Dirichlet character $\chi$, we have a decomposition $\chi = \prod_p \chi_p$ into character modulo $N$ where the conductor of $\chi_p$ divides $p^{e_p}$; it equals $p^{e_p}$ for all $p$ if and only if $\chi$ is primitive. Given a \var{znstar} G describing a group $(\Z/N\Z)^*$, a Dirichlet character \kbd{chi} and an integer $Q$, return $\prod_{p \mid (Q,N)} \chi_p$. For instance, if $Q = p$ is a prime divisor of $N$, the function returns $\chi_p$ (as a character modulo $N$), given as a Conrey character (\typ{COL}). \bprog ? G = znstar(40, 1); ? G.cyc %2 = [4, 2, 2] ? chi = [2, 1, 1]; ? chi2 = znchardecompose(G, chi, 2) %4 = [1, 1, 0]~ ? chi5 = znchardecompose(G, chi, 5) %5 = [0, 0, 2]~ ? znchardecompose(G, chi, 3) %6 = [0, 0, 0]~ ? c = charmul(G, chi2, chi5) %7 = [1, 1, 2]~ \\ t_COL: in terms of Conrey generators ! ? znconreychar(G,c) %8 = [2, 1, 1] \\ t_VEC: in terms of SNF generators @eprog pari-2.11.2/src/functions/number_theoretical/primecertexport0000644000175000017500000000272713326135265023025 0ustar billbillFunction: primecertexport Section: number_theoretical C-Name: primecertexport Prototype: GD0,L, Help: primecertexport(cert, {format = 0}): Returns a string suitable for print/write to display a primality certificate. Doc: Returns a string suitable for print/write to display a primality certificate from \tet{primecert}, the format of which depends on the value of \kbd{format}: \item 0 (default): Human-readable format. \item 1: Primo format 4. \item 2: MAGMA format. Currently, only ECPP Primality Certificates are supported. \bprog ? cert = primecert(10^35+69); ? s = primecertexport(cert); \\ Human-readable ? print(s) [1] N = 100000000000000000000000000000000069 t = 546867911035452074 s = 2963504668391148 a4 = 0 D = -3 m = 99999999999999999453132088964547996 q = 33743830764501150277 E = [0, 1] P = [21567861682493263464353543707814204, 49167839501923147849639425291163552] [2] N = 33743830764501150277 t = -11610830419 s = 734208843 a4 = 0 D = -3 m = 33743830776111980697 q = 45959444779 E = [0, 25895956964997806805] P = [29257172487394218479, 3678591960085668324] \\ Primo format ? s = primecertexport(cert,1); write("cert.out", s); \\ Magma format, write to file ? s = primecertexport(cert,2); write("cert.m", s); ? cert = primecert(10^35+69, 1); \\ N-1 certificate *** at top-level: primecertexport(cert) *** ^--------------------- *** primecertexport: sorry, N-1 certificate is not yet implemented. @eprog pari-2.11.2/src/functions/number_theoretical/factor0000644000175000017500000002640413447371554021054 0ustar billbillFunction: factor Section: number_theoretical C-Name: factor0 Prototype: GDG Help: factor(x,{D}): factorization of x over domain D. If x and D are both integers, return partial factorization, using primes < D. Description: (int):vec Z_factor($1) (int,):vec Z_factor($1) (int,small):vec Z_factor_limit($1, $2) (gen):vec factor($1) (gen,):vec factor($1) (gen,gen):vec factor0($1, $2) Doc: factor $x$ over domain $D$; if $D$ is omitted, it is determined from $x$. For instance, if $x$ is an integer, it is factored in $\Z$, if it is a polynomial with rational coefficients, it is factored in $\Q[x]$, etc., see below for details. The result is a two-column matrix: the first contains the irreducibles dividing $x$ (rational or Gaussian primes, irreducible polynomials), and the second the exponents. By convention, $0$ is factored as $0^1$. \misctitle{$x \in \Q$} See \tet{factorint} for the algorithms used. The factorization includes the unit $-1$ when $x < 0$ and all other factors are positive; a denominator is factored with negative exponents. The factors are sorted in increasing order. \bprog ? factor(-7/106) %1 = [-1 1] [ 2 -1] [ 7 1] [53 -1] @eprog\noindent By convention, $1$ is factored as \kbd{matrix(0,2)} (the empty factorization, printed as \kbd{[;]}). Large rational ``primes'' $ > 2^{64}$ in the factorization are in fact \var{pseudoprimes} (see \kbd{ispseudoprime}), a priori not rigorously proven primes. Use \kbd{isprime} to prove primality of these factors, as in \bprog ? fa = factor(2^2^7 + 1) %1 = [59649589127497217 1] [5704689200685129054721 1] ? isprime( fa[,1] ) %2 = [1, 1]~ \\ both entries are proven primes @eprog\noindent Another possibility is to globally set the default \tet{factor_proven}, which will perform a rigorous primality proof for each pseudoprime factor but will slow down PARI. A \typ{INT} argument $D$ can be added, meaning that we look only for prime factors $p < D$. The limit $D$ must be non-negative. In this case, all but the last factor are proven primes, but the remaining factor may actually be a proven composite! If the remaining factor is less than $D^2$, then it is prime. \bprog ? factor(2^2^7 +1, 10^5) %3 = [340282366920938463463374607431768211457 1] @eprog\noindent \misctitle{Deprecated feature} Setting $D=0$ is the same as setting it to $\kbd{primelimit} + 1$. \smallskip This routine uses trial division and perfect power tests, and should not be used for huge values of $D$ (at most $10^9$, say): \kbd{factorint(, 1 + 8)} will in general be faster. The latter does not guarantee that all small prime factors are found, but it also finds larger factors and in a more efficient way. \bprog ? F = (2^2^7 + 1) * 1009 * (10^5+3); factor(F, 10^5) \\ fast, incomplete time = 0 ms. %4 = [1009 1] [34029257539194609161727850866999116450334371 1] ? factor(F, 10^9) \\ slow time = 3,260 ms. %6 = [1009 1] [100003 1] [340282366920938463463374607431768211457 1] ? factorint(F, 1+8) \\ much faster and all small primes were found time = 8 ms. %7 = [1009 1] [100003 1] [340282366920938463463374607431768211457 1] ? factor(F) \\ complete factorization time = 60 ms. %8 = [1009 1] [100003 1] [59649589127497217 1] [5704689200685129054721 1] @eprog\noindent Setting $D = I$ will factor in the Gaussian integers $\Z[i]$: \misctitle{$x \in \Q(i)$} The factorization is performed with Gaussian primes in $\Z[i]$ and includes Gaussian units in $\{\pm1, \pm i\}$; factors are sorted by increasing norm. Except for a possible leading unit, the Gaussian factors are normalized: rational factors are positive and irrational factors have positive imaginary part (a canonical represneta. Unless \tet{factor_proven} is set, large factors are actually pseudoprimes, not proven primes; a rational factor is prime if less than $2^{64}$ and an irrational one if its norm is less than $2^{64}$. \bprog ? factor(5*I) %1 = [ 2 + I 1] [1 + 2*I 1] @eprog\noindent One can force the factorization of a rational number by setting the domain $D = I$: \bprog ? factor(-5, I) %2 = [ I 1] [ 2 + I 1] [1 + 2*I 1] ? factorback(%) %3 = -5 @eprog \misctitle{Univariate polynomials and rational functions} PARI can factor univariate polynomials in $K[t]$. The following base fields $K$ are currently supported: $\Q$, $\R$, $\C$, $\Q_p$, finite fields and number fields. See \tet{factormod} and \tet{factorff} for the algorithms used over finite fields and \tet{nffactor} for the algorithms over number fields. The irreducible factors are sorted by increasing degree and normalized: they are monic except when $K = \Q$ where they are primitive in $\Z[t]$. The content is \emph{not} included in the factorization, in particular \kbd{factorback} will in general recover the original $x$ only up to multiplication by an element of $K^*$: when $K\neq\Q$, this scalar is \kbd{pollead}$(x)$ (since irreducible factors are monic); and when $K = \Q$ you can either ask for the $\Q$-content explicitly of use factorback: \bprog ? P = t^2 + 5*t/2 + 1; F = factor(P) %1 = [t + 2 1] [2*t + 1 1] ? content(P, 1) \\ Q-content %2 = 1/2 ? pollead(factorback(F)) / pollead(P) %3 = 2 @eprog You can specify $K$ using the optional ``domain'' argument $D$ as follows \item $K = \Q$ : $D$ a rational number (\typ{INT} or \typ{FRAC}), \item $K = \Z/p\Z$ with $p$ prime : $D$ a \typ{INTMOD} modulo $p$; factoring modulo a non-prime number is not supported. \item $K = \F_q$ : $D$ a \typ{FFELT} encoding the finite field; you can also use a \typ{POLMOD} of \typ{INTMOD} modulo a prime $p$ but this is usualy less convenient; \item $K = \Q[X]/(T)$ a number field : $D$ a \typ{POLMOD} modulo $T$, \item $K = \Q(i)$ (alternate syntax for special case): $D = I$, \item $K = \Q(w)$ a quadratic number field (alternate syntax for special case): $D$ a \typ{QUAD}, \item $K = \R$ : $D$ a real number (\typ{REAL}); truncate the factorization at accuracy \kbd{precision}$(D)$. If $x$ is inexact and \kbd{precision}$(x)$ is less than \kbd{precision}$(D)$, then the precision of $x$ is used instead. \item $K = \C$ : $D$ a complex number with a \typ{REAL} component, e.g. \kbd{I * 1.}; truncate the factorization as for $K = \R$, \item $K = \Q_p$ : $D$ a \typ{PADIC}; truncate the factorization at $p$-adic accuracy \kbd{padicprec}$(D)$, possibly less if $x$ is inexact with insufficient $p$-adic accuracy; \bprog ? T = x^2+1; ? factor(T, 1); \\ over Q ? factor(T, Mod(1,3)) \\ over F_3 ? factor(T, ffgen(ffinit(3,2,'t))^0) \\ over F_{3^2} ? factor(T, Mod(Mod(1,3), t^2+t+2)) \\ over F_{3^2}, again ? factor(T, O(3^6)) \\ over Q_3, precision 6 ? factor(T, 1.) \\ over R, current precision ? factor(T, I*1.) \\ over C ? factor(T, Mod(1, y^3-2)) \\ over Q(2^{1/3}) @eprog\noindent In most cases, it is possible and simpler to call a specialized variant rather than use the above scheme: \bprog ? factormod(T, 3) \\ over F_3 ? factormod(T, [t^2+t+2, 3]) \\ over F_{3^2} ? factormod(T, ffgen(3^2, 't)) \\ over F_{3^2} ? factorpadic(T, 3,6) \\ over Q_3, precision 6 ? nffactor(y^3-2, T) \\ over Q(2^{1/3}) ? polroots(T) \\ over C ? polrootsreal(T) \\ over R (real polynomial) @eprog It is also possible to let the routine use the smallest field containing all coefficients, taking into account quotient structures induced by \typ{INTMOD}s and \typ{POLMOD}s (e.g.~if a coefficient in $\Z/n\Z$ is known, all rational numbers encountered are first mapped to $\Z/n\Z$; different moduli will produce an error): \bprog ? T = x^2+1; ? factor(T); \\ over Q ? factor(T*Mod(1,3)) \\ over F_3 ? factor(T*ffgen(ffinit(3,2,'t))^0) \\ over F_{3^2} ? factor(T*Mod(Mod(1,3), t^2+t+2)) \\ over F_{3^2}, again ? factor(T*(1 + O(3^6)) \\ over Q_3, precision 6 ? factor(T*1.) \\ over R, current precision ? factor(T*(1.+0.*I)) \\ over C ? factor(T*Mod(1, y^3-2)) \\ over Q(2^{1/3}) @eprog\noindent Multiplying by a suitable field element equal to $1 \in K$ in this way is error-prone and is not recommanded. Factoring existing polynomials with obvious fields of coefficients is fine, the domain argument $D$ should be used instead ad hoc conversions. \misctitle{Note on inexact polynomials} Polynomials with inexact coefficients (e.g. floating point or $p$-adic numbers) are first rounded to an exact representation, then factored to (potentially) infinite accuracy and we return a truncated approximation of that virtual factorization. To avoid pitfalls, we advise to only factor \emph{exact} polynomials: \bprog ? factor(x^2-1+O(2^2)) \\ rounded to x^2 + 3, irreducible in Q_2 %1 = [(1 + O(2^2))*x^2 + O(2^2)*x + (1 + 2 + O(2^2)) 1] ? factor(x^2-1+O(2^3)) \\ rounded to x^2 + 7, reducible ! %2 = [ (1 + O(2^3))*x + (1 + 2 + O(2^3)) 1] [(1 + O(2^3))*x + (1 + 2^2 + O(2^3)) 1] ? factor(x^2-1, O(2^2)) \\ no ambiguity now %3 = [ (1 + O(2^2))*x + (1 + O(2^2)) 1] [(1 + O(2^2))*x + (1 + 2 + O(2^2)) 1] @eprog \misctitle{Note about inseparable polynomials} Polynomials with inexact coefficients are considered to be squarefree: indeed, there exist a squarefree polynomial arbitrarily close to the input, and they cannot be distinguished at the input accuracy. This means that irreducible factors are repeated according to their apparent multiplicity. On the contrary, using a specialized function such as \kbd{factorpadic} with an \emph{exact} rational input yields the correct multiplicity when the (now exact) input is not separable. Compare: \bprog ? factor(z^2 + O(5^2))) %1 = [(1 + O(5^2))*z + O(5^2) 1] [(1 + O(5^2))*z + O(5^2) 1] ? factor(z^2, O(5^2)) %2 = [1 + O(5^2))*z + O(5^2) 2] @eprog \misctitle{Multivariate polynomials and rational functions} PARI recursively factors \emph{multivariate} polynomials in $K[t_1,\dots, t_d]$ for the same fields $K$ as above and the argument $D$ is used in the same way to specify $K$. The irreducible factors are sorted by their main variable (least priority first) then by increasing degree. \bprog ? factor(x^2 + y^2, Mod(1,5)) %1 = [ x + Mod(2, 5)*y 1] [Mod(1, 5)*x + Mod(3, 5)*y 1] ? factor(x^2 + y^2, O(5^2)) %2 = [ (1 + O(5^2))*x + (O(5^2)*y^2 + (2 + 5 + O(5^2))*y + O(5^2)) 1] [(1 + O(5^2))*x + (O(5^2)*y^2 + (3 + 3*5 + O(5^2))*y + O(5^2)) 1] ? lift(%) %3 = [ x + 7*y 1] [x + 18*y 1] @eprog\noindent Note that the implementation does not really support inexact real fields ($\R$ or $\C$) and usually misses factors even if the input is exact: \bprog ? factor(x^2 + y^2, I) \\ over Q(i) %4 = [x - I*y 1] [x + I*y 1] ? factor(x^2 + y^2, I*1.) \\ over C %5 = [x^2 + y^2 1] @eprog Variant: \fun{GEN}{factor}{GEN x} \fun{GEN}{boundfact}{GEN x, ulong lim}. Function: _factor_Aurifeuille Section: programming/internals C-Name: factor_Aurifeuille Prototype: GL Help: _factor_Aurifeuille(a,d): return an algebraic factor of Phi_d(a), a != 0 Function: _factor_Aurifeuille_prime Section: programming/internals C-Name: factor_Aurifeuille_prime Prototype: GL Help: _factor_Aurifeuille_prime(p,d): return an algebraic factor of Phi_d(p), p prime pari-2.11.2/src/functions/number_theoretical/qfbhclassno0000644000175000017500000000077513326135265022075 0ustar billbillFunction: qfbhclassno Section: number_theoretical C-Name: hclassno Prototype: G Help: qfbhclassno(x): Hurwitz-Kronecker class number of x>0. Doc: \idx{Hurwitz class number} of $x$, when $x$ is non-negative and congruent to 0 or 3 modulo 4, and $0$ for other values. For $x > 5\cdot 10^5$, we assume the GRH, and use \kbd{quadclassunit} with default parameters. \bprog ? qfbhclassno(1) \\ not 0 or 3 mod 4 %1 = 0 ? qfbhclassno(3) %2 = 1/3 ? qfbhclassno(4) %3 = 1/2 ? qfbhclassno(23) %4 = 3 @eprog pari-2.11.2/src/functions/number_theoretical/chareval0000644000175000017500000000627413326135265021357 0ustar billbillFunction: chareval Section: number_theoretical C-Name: chareval Prototype: GGGDG Help: chareval(G, chi, x, {z}): given an abelian group structure affording a discrete logarithm method, e.g. G = znstar(N,1) or a bnr structure, let x be an element of G and let chi be a character of G. This function returns the value of chi at x, where the encoding depends on the optional argument z; if z is omitted, we fix a canonical o-th root of 1, zeta_o, where o is the character order and return the rational number c/o where chi(x) = (zeta_o)^c. Doc: Let $G$ be an abelian group structure affording a discrete logarithm method, e.g $G = \kbd{znstar}(N, 1)$ for $(\Z/N\Z)^*$ or a \kbd{bnr} structure, let $x$ be an element of $G$ and let \var{chi} be a character of $G$ (see the note below for details). This function returns the value of \var{chi} at $x$. \misctitle{Note on characters} Let $K$ be some field. If $G$ is an abelian group, let $\chi: G \to K^*$ be a character of finite order and let $o$ be a multiple of the character order such that $\chi(n) = \zeta^{c(n)}$ for some fixed $\zeta\in K^*$ of multiplicative order $o$ and a unique morphism $c: G \to (\Z/o\Z,+)$. Our usual convention is to write $$G = (\Z/o_1\Z) g_1 \oplus \cdots \oplus (\Z/o_d\Z) g_d$$ for some generators $(g_i)$ of respective order $d_i$, where the group has exponent $o := \text{lcm}_i o_i$. Since $\zeta^o = 1$, the vector $(c_i)$ in $\prod (\Z/o_i\Z)$ defines a character $\chi$ on $G$ via $\chi(g_i) = \zeta^{c_i (o/o_i)}$ for all $i$. Classical Dirichlet characters have values in $K = \C$ and we can take $\zeta = \exp(2i\pi/o)$. \misctitle{Note on Dirichlet characters} In the special case where \var{bid} is attached to $G = (\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}), the Dirichlet character \var{chi} can be written in one of the usual 3 formats: a \typ{VEC} in terms of \kbd{bid.gen} as above, a \typ{COL} in terms of the Conrey generators, or a \typ{INT} (Conrey label); see \secref{se:dirichletchar} or \kbd{??character}. The character value is encoded as follows, depending on the optional argument $z$: \item If $z$ is omitted: return the rational number $c(x)/o$ for $x$ coprime to $q$, where we normalize $0\leq c(x) < o$. If $x$ can not be mapped to the group (e.g. $x$ is not coprime to the conductor of a Dirichlet or Hecke character) we return the sentinel value $-1$. \item If $z$ is an integer $o$, then we assume that $o$ is a multiple of the character order and we return the integer $c(x)$ when $x$ belongs to the group, and the sentinel value $-1$ otherwise. \item $z$ can be of the form $[\var{zeta}, o]$, where \var{zeta} is an $o$-th root of $1$ and $o$ is a multiple of the character order. We return $\zeta^{c(x)}$ if $x$ belongs to the group, and the sentinel value $0$ otherwise. (Note that this coincides with the usual extension of Dirichlet characters to $\Z$, or of Hecke characters to general ideals.) \item Finally, $z$ can be of the form $[\var{vzeta}, o]$, where \var{vzeta} is a vector of powers $\zeta^0, \dots, \zeta^{o-1}$ of some $o$-th root of $1$ and $o$ is a multiple of the character order. As above, we return $\zeta^{c(x)}$ after a table lookup. Or the sentinel value $0$. pari-2.11.2/src/functions/number_theoretical/fffrobenius0000644000175000017500000000074613326135265022100 0ustar billbillFunction: fffrobenius Section: number_theoretical C-Name: fffrobenius Prototype: GD1,L, Help: fffrobenius(m,{n=1}): return the n-th power of the Frobenius map over the field of definition of m. Doc: return the $n$-th power of the Frobenius map over the field of definition of $m$. \bprog ? a = ffgen([3,5],'a); ? f = fffrobenius(a); ? ffmap(f,a) == a^3 %3 = 1 ? g = fffrobenius(a, 5); ? ffmap(g,a) == a %5 = 1 ? h = fffrobenius(a, 2); ? h == ffcompomap(f,f) %7 = 1 @eprog pari-2.11.2/src/functions/number_theoretical/znchartokronecker0000644000175000017500000000235513326135265023322 0ustar billbillFunction: znchartokronecker Section: number_theoretical C-Name: znchartokronecker Prototype: GGD0,L, Help: znchartokronecker(G, chi, {flag=0}): let G be znstar(N,1), let chi be a Dirichlet character mod N, return the discriminant D if chi is real equal to the Kronecker symbol (D/.) and 0 otherwise. If flag is set, return the fundamental discriminant attached to the corresponding primitive character. Doc: Let $G$ be attached to $(\Z/N\Z)^*$ (as per \kbd{G = znstar(N,1)}) and let \kbd{chi} be a Dirichlet character on $(\Z/N\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{bid.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. If $\fl = 0$, return the discriminant $D$ if \kbd{chi} is real equal to the Kronecker symbol $(D/.)$ and $0$ otherwise. The discriminant $D$ is fundamental if and only if \kbd{chi} is primitive. If $\fl = 1$, return the fundamental discriminant attached to the corresponding primitive character. \bprog ? G = znstar(8,1); CHARS = [1,3,5,7]; \\ Conrey labels ? apply(t->znchartokronecker(G,t), CHARS) %2 = [4, -8, 8, -4] ? apply(t->znchartokronecker(G,t,1), CHARS) %3 = [1, -8, 8, -4] @eprog pari-2.11.2/src/functions/number_theoretical/kronecker0000644000175000017500000000136612314242551021543 0ustar billbillFunction: kronecker Section: number_theoretical C-Name: kronecker Prototype: lGG Help: kronecker(x,y): kronecker symbol (x/y). Description: (small, small):small kross($1, $2) (int, small):small krois($1, $2) (small, int):small krosi($1, $2) (gen, gen):small kronecker($1, $2) Doc: \idx{Kronecker symbol} $(x|y)$, where $x$ and $y$ must be of type integer. By definition, this is the extension of \idx{Legendre symbol} to $\Z \times \Z$ by total multiplicativity in both arguments with the following special rules for $y = 0, -1$ or $2$: \item $(x|0) = 1$ if $|x| = 1$ and $0$ otherwise. \item $(x|-1) = 1$ if $x \geq 0$ and $-1$ otherwise. \item $(x|2) = 0$ if $x$ is even and $1$ if $x = 1,-1 \mod 8$ and $-1$ if $x=3,-3 \mod 8$. pari-2.11.2/src/functions/number_theoretical/qfbredsl20000644000175000017500000000122313326135265021443 0ustar billbillFunction: qfbredsl2 Section: number_theoretical C-Name: qfbredsl2 Prototype: GDG Help: qfbredsl2(x,{data}): reduction of the binary quadratic form x, return [y,g] where y is reduced and g in Sl(2,Z) is such that g.x = y; data, if present, must be equal to [D, sqrtint(D)], where D > 0 is the discriminant of x. Doc: reduction of the (real or imaginary) binary quadratic form $x$, return $[y,g]$ where $y$ is reduced and $g$ in $\text{SL}(2,\Z)$ is such that $g \cdot x = y$; \var{data}, if present, must be equal to $[D, \kbd{sqrtint}(D)]$, where $D > 0$ is the discriminant of $x$. In case $x$ is a \typ{QFR}, the distance component is unaffected. pari-2.11.2/src/functions/number_theoretical/prime0000644000175000017500000000072013326135265020674 0ustar billbillFunction: prime Section: number_theoretical C-Name: prime Prototype: L Help: prime(n): returns the n-th prime (n C-integer). Doc: the $n^{\text{th}}$ prime number \bprog ? prime(10^9) %1 = 22801763489 @eprog\noindent Uses checkpointing and a naive $O(n)$ algorithm. Will need about 30 minutes for $n$ up to $10^{11}$; make sure to start gp with \kbd{primelimit} at least $\sqrt{p_n}$, e.g. the value $\sqrt{n\log (n\log n)}$ is guaranteed to be sufficient. pari-2.11.2/src/functions/number_theoretical/charconj0000644000175000017500000000267313326135265021360 0ustar billbillFunction: charconj Section: number_theoretical C-Name: charconj0 Prototype: GG Help: charconj(cyc,chi): given a finite abelian group (by its elementary divisors cyc) and a character chi, return the conjugate character. Doc: let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. This function returns the conjugate character. \bprog ? cyc = [15,5]; chi = [1,1]; ? charconj(cyc, chi) %2 = [14, 4] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? charconj(bnf, [1]) %5 = [2] @eprog\noindent For Dirichlet characters (when \kbd{cyc} is \kbd{znstar(q,1)}), characters in Conrey representation are available, see \secref{se:dirichletchar} or \kbd{??character}: \bprog ? G = znstar(8, 1); \\ (Z/8Z)^* ? charorder(G, 3) \\ Conrey label %2 = 2 ? chi = znconreylog(G, 3); ? charorder(G, chi) \\ Conrey logarithm %4 = 2 @eprog Variant: Also available is \fun{GEN}{charconj}{GEN cyc, GEN chi}, when \kbd{cyc} is known to be a vector of elementary divisors and \kbd{chi} a compatible character (no checks). pari-2.11.2/src/functions/number_theoretical/ffgen0000644000175000017500000000345013447371554020657 0ustar billbillFunction: ffgen Section: number_theoretical C-Name: ffgen Prototype: GDn Help: ffgen(k,{v = 'x}): return a generator of the finite field k (not necessarily a generator of its multiplicative group) as a t_FFELT. k can be given by its order q, the pair [p,f] with q=p^f, by an irreducible polynomial with t_INTMOD coefficients, or by a finite field element. If v is given, the variable name is used to display g, else the variable of the polynomial or finite field element, or x if only the order was given. Doc: return a generator for the finite field $k$ as a \typ{FFELT}. The field $k$ can be given by \item its order $q$ \item the pair $[p,f]$ where $q=p^f$ \item a monic irreducible polynomial with \typ{INTMOD} coefficients modulo a prime. \item a \typ{FFELT} belonging to $k$. If \kbd{v} is given, the variable name is used to display $g$, else the variable of the polynomial or the \typ{FFELT} is used, else $x$ is used. When only the order is specified, the function uses the polynomial generated by \kbd{ffinit} and is deterministic: two calls to the function with the same parameters will always give the same generator. For efficiency, the characteristic is not checked to be prime; similarly if a polynomial is given, we do not check whether it is irreducible. To obtain a multiplicative generator, call \kbd{ffprimroot} on the result. \bprog ? g = ffgen(16, 't); ? g.mod \\ recover the underlying polynomial. %2 = t^4+t^3+t^2+t+1 ? g.p \\ recover the characteristic %3 = 2 ? fforder(g) \\ g is not a multiplicative generator %4 = 5 ? a = ffprimroot(g) \\ recover a multiplicative generator %5 = t^3+t^2+t ? fforder(a) %6 = 15 @eprog Variant: To create a generator for a prime finite field, the function \fun{GEN}{p_to_GEN}{GEN p, long v} returns \kbd{ffgen(p,v)\^{}0}. pari-2.11.2/src/functions/number_theoretical/zncharinduce0000644000175000017500000000335013326135265022237 0ustar billbillFunction: zncharinduce Section: number_theoretical C-Name: zncharinduce Prototype: GGG Help: zncharinduce(G, chi, N): let G be znstar(q,1), let chi be a Dirichlet character mod q and let N be a multiple of q. Return the character modulo N extending chi. Doc: Let $G$ be attached to $(\Z/q\Z)^*$ (as per \kbd{G = znstar(q,1)}) and let \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^*$, given by \item a \typ{VEC}: a standard character on \kbd{bid.gen}, \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^*$ or its Conrey logarithm; see \secref{se:dirichletchar} or \kbd{??character}. Let $N$ be a multiple of $q$, return the character modulo $N$ extending \kbd{chi}. As usual for arithmetic functions, the new modulus $N$ can be given as a \typ{INT}, via a factorization matrix or a pair \kbd{[N, factor(N)]}, or by \kbd{znstar(N,1)}. \bprog ? G = znstar(4, 1); ? chi = znconreylog(G,1); \\ trivial character mod 4 ? zncharinduce(G, chi, 80) \\ now mod 80 %3 = [0, 0, 0]~ ? zncharinduce(G, 1, 80) \\ same using directly Conrey label %4 = [0, 0, 0]~ ? G2 = znstar(80, 1); ? zncharinduce(G, 1, G2) \\ same %4 = [0, 0, 0]~ ? chi = zncharinduce(G, 3, G2) \\ extend the non-trivial character mod 4 %5 = [1, 0, 0]~ ? [G0,chi0] = znchartoprimitive(G2, chi); ? G0.mod %7 = 4 ? chi0 %8 = [1]~ @eprog\noindent Here is a larger example: \bprog ? G = znstar(126000, 1); ? label = 1009; ? chi = znconreylog(G, label) %3 = [0, 0, 0, 14, 0]~ ? [G0,chi0] = znchartoprimitive(G, label); \\ works also with 'chi' ? G0.mod %5 = 125 ? chi0 \\ primitive character mod 5^3 attached to chi %6 = [14]~ ? G0 = znstar(N0, 1); ? zncharinduce(G0, chi0, G) \\ induce back %8 = [0, 0, 0, 14, 0]~ ? znconreyexp(G, %) %9 = 1009 @eprog pari-2.11.2/src/functions/number_theoretical/chardiv0000644000175000017500000000341213326135265021201 0ustar billbillFunction: chardiv Section: number_theoretical C-Name: chardiv0 Prototype: GGG Help: chardiv(cyc, a,b): given a finite abelian group (by its elementary divisors cyc) and two characters a and b, return the character a/b. Doc: let \var{cyc} represent a finite abelian group by its elementary divisors, i.e. $(d_j)$ represents $\sum_{j \leq k} \Z/d_j\Z$ with $d_k \mid \dots \mid d_1$; any object which has a \kbd{.cyc} method is also allowed, e.g.~the output of \kbd{znstar} or \kbd{bnrinit}. A character on this group is given by a row vector $a = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$, where $g_j$ denotes the generator (of order $d_j$) of the $j$-th cyclic component. Given two characters $a$ and $b$, return the character $a / b = a \overline{b}$. \bprog ? cyc = [15,5]; a = [1,1]; b = [2,4]; ? chardiv(cyc, a,b) %2 = [14, 2] ? bnf = bnfinit(x^2+23); ? bnf.cyc %4 = [3] ? chardiv(bnf, [1], [2]) %5 = [2] @eprog\noindent For Dirichlet characters on $(\Z/N\Z)^*$, additional representations are available (Conrey labels, Conrey logarithm), see \secref{se:dirichletchar} or \kbd{??character}. If the two characters are in the same format, the result is given in the same format, otherwise a Conrey logarithm is used. \bprog ? G = znstar(100, 1); ? G.cyc %2 = [20, 2] ? a = [10, 1]; \\ usual representation for characters ? b = 7; \\ Conrey label; ? c = znconreylog(G, 11); \\ Conrey log ? chardiv(G, b,b) %6 = 1 \\ Conrey label ? chardiv(G, a,b) %7 = [0, 5]~ \\ Conrey log ? chardiv(G, a,c) %7 = [0, 14]~ \\ Conrey log @eprog Variant: Also available is \fun{GEN}{chardiv}{GEN cyc, GEN a, GEN b}, when \kbd{cyc} is known to be a vector of elementary divisors and $a, b$ are compatible characters (no checks). pari-2.11.2/src/functions/number_theoretical/ffinvmap0000644000175000017500000000104213447371554021373 0ustar billbillFunction: ffinvmap Section: number_theoretical C-Name: ffinvmap Prototype: G Help: ffinvmap(m): given a map m between finite fields, return a partial map that return the pre-images by the map m. Doc: $m$ being a map from $K$ to $L$ two finite fields, return the partial map $p$ from $L$ to $K$ such that for all $k\in K$, $p(m(k))=k$. \bprog ? a = ffgen([3,5],'a); ? b = ffgen([3,10],'b); ? m = ffembed(a, b); ? p = ffinvmap(m); ? u = random(a); ? v = ffmap(m, u); ? ffmap(p, v^2+v+2) == u^2+u+2 %7 = 1 ? ffmap(p, b) %8 = [] @eprog pari-2.11.2/src/functions/number_theoretical/ispower0000644000175000017500000000243013201017466021242 0ustar billbillFunction: ispower Section: number_theoretical C-Name: ispower Prototype: lGDGD& Help: ispower(x,{k},{&n}): if k > 0 is given, return true (1) if x is a k-th power, false (0) if not. If k is omitted, return the maximal k >= 2 such that x = n^k is a perfect power, or 0 if no such k exist. If n is present, and the function returns a non-zero result, set n to the k-th root of x. Description: (int):small Z_isanypower($1, NULL) (int, &int):small Z_isanypower($1, &$2) Doc: if $k$ is given, returns true (1) if $x$ is a $k$-th power, false (0) if not. What it means to be a $k$-th power depends on the type of $x$; see \tet{issquare} for details. If $k$ is omitted, only integers and fractions are allowed for $x$ and the function returns the maximal $k \geq 2$ such that $x = n^k$ is a perfect power, or 0 if no such $k$ exist; in particular \kbd{ispower(-1)}, \kbd{ispower(0)}, and \kbd{ispower(1)} all return $0$. If a third argument $\&n$ is given and $x$ is indeed a $k$-th power, sets $n$ to a $k$-th root of $x$. \noindent For a \typ{FFELT} \kbd{x}, instead of omitting \kbd{k} (which is not allowed for this type), it may be natural to set \bprog k = (x.p ^ x.f - 1) / fforder(x) @eprog Variant: Also available is \fun{long}{gisanypower}{GEN x, GEN *pty} ($k$ omitted). pari-2.11.2/src/functions/number_theoretical/ffcompomap0000644000175000017500000000130313447371554021714 0ustar billbillFunction: ffcompomap Section: number_theoretical C-Name: ffcompomap Prototype: GG Help: ffcompomap(f, g): Let k, l, m be three finite fields and f a (partial) map from l to m and g a partial map from k to l, return the (partial) map f o g from k to m. Doc: Let $k$, $l$, $m$ be three finite fields and $f$ a (partial) map from $l$ to $m$ and $g$ a (partial) map from $k$ to $l$, return the (partial) map $f \circ g$ from $k$ to $m$. \bprog a = ffgen([3,5],'a); b = ffgen([3,10],'b); c = ffgen([3,20],'c); m = ffembed(a, b); n = ffembed(b, c); rm = ffinvmap(m); rn = ffinvmap(n); nm = ffcompomap(n,m); ffmap(n,ffmap(m,a)) == ffmap(nm, a) %5 = 1 ffcompomap(rm, rn) == ffinvmap(nm) %6 = 1 @eprog pari-2.11.2/src/functions/number_theoretical/removeprimes0000644000175000017500000000073411636712103022274 0ustar billbillFunction: removeprimes Section: number_theoretical C-Name: removeprimes Prototype: DG Help: removeprimes({x=[]}): remove primes in the vector x from the prime table. x can also be a single integer. List the current extra primes if x is omitted. Doc: removes the primes listed in $x$ from the prime number table. In particular \kbd{removeprimes(addprimes())} empties the extra prime table. $x$ can also be a single integer. List the current extra primes if $x$ is omitted. pari-2.11.2/src/functions/modular_forms/0000755000175000017500000000000013461316051016626 5ustar billbillpari-2.11.2/src/functions/modular_forms/mfatkin0000644000175000017500000000201213326135265020203 0ustar billbillFunction: mfatkin Section: modular_forms C-Name: mfatkin Prototype: GG Help: mfatkin(mfatk,F): Given an mfatk output by mfatk = mfatkininit(mf,Q) and a modular form F belonging to the space mf, returns the modular form C*F|W_Q, which has polmod coefficients in Q(F), and where mfatk[3]=C, mfatk[1]=mf2 (or 0 if mf2=mf) which is the space to which F|W_Q belongs. Doc: Given a \kbd{mfatk} output by \kbd{mfatk = mfatkininit(mf,Q)} and a modular form $F$ belonging to the pace \kbd{mf}, returns the modular form $C*F|W_Q$, which has \kbd{polmod} coefficients in $\Q(F)$; \kbd{mfatk[3]} gives the constant $C$, and \kbd{mfatk[1]} gives the modular form space to which $F|W_Q$ belongs (or is set to $0$ if it is \kbd{mf}). \bprog ? mf = mfinit([35,2],0); vecF = mfbasis(mf); F = vecF[1]; ? mfcoefs(F, 4) %2 = [0, 3, -1, 0, 3] ? mfatk = mfatkininit(mf,7); ? wF = mfatkin(mfatk, F); mfcoefs(wF, 4) %4 = [0, 1, -1, -2, 7] ? mfatk = mfatkininit(mf,35); ? wF = mfatkin(mfatk, F); mfcoefs(wF, 4) %6 = [0, -3, 1, 0, -3] @eprog pari-2.11.2/src/functions/modular_forms/mfderiv0000644000175000017500000000106313447371554020222 0ustar billbillFunction: mfderiv Section: modular_forms C-Name: mfderiv Prototype: GD1,L, Help: mfderiv(F,{m=1}): m-th formal derivative of the power series corresponding to the generalized modular form F, with respect to the differential operator q.d/dq (default m=1). Doc: $m$-th formal derivative of the power series corresponding to the generalized modular form $F$, with respect to the differential operator $qd/dq$ (default $m=1$). \bprog ? D=mfDelta(); ? mfcoefs(D, 4) %2 = [0, 1, -24, 252, -1472] ? mfcoefs(mfderiv(D), 4) %3 = [0, 1, -48, 756, -5888] @eprog pari-2.11.2/src/functions/modular_forms/mfeval0000644000175000017500000000311313326135265020027 0ustar billbillFunction: mfeval Section: modular_forms C-Name: mfeval Prototype: GGGb Help: mfeval(mf,F,vtau): computes the numerical value of the modular form F at the point vtau or the vector vtau of points in the completed upper-half plane. Doc: Computes the numerical value of the modular form $F$, belonging to \var{mf}, at the complex number \kbd{vtau} or the vector \kbd{vtau} of complex numbers in the completed upper-half plane. The result is given with absolute error less than $2^{-B}$, where $B = \text{realbitprecision}$. If the field of definition $\Q(F)$ is larger than $\Q(\chi)$ then $F$ may be embedded into $\C$ in $d=[\Q(F):\Q(\chi)]$ ways, in which case a vector of the $d$ results is returned. \bprog ? mf = mfinit([11,2],0); F = mfbasis(mf)[1]; mfparams(F) %1 = [11, 2, 1, y] \\ Q(F) = Q(chi) = Q ? mfeval(mf,F,I/2) %2 = 0.039405471130100890402470386372028382117 ? mf = mfinit([35,2],0); F = mfeigenbasis(mf)[2]; mfparams(F) %3 = [35, 2, 1, y^2 - y - 4] \\ [Q(F) : Q(chi)] = 2 ? mfeval(mf,F,I/2) %4 = [0.045..., 0.0385...] \\ sigma_1(F) and sigma_2(F) at I/2 ? mf = mfinit([12,4],1); F = mfbasis(mf)[1]; ? mfeval(mf, F, 0.318+10^(-7)*I) %6 = 3.379... E-21 + 6.531... E-21*I \\ instantaneous ! @eprog\noindent In order to maximize the imaginary part of the argument, the function computes $(f \mid_k \gamma)(\gamma^{-1}\cdot\tau)$ for a suitable $\gamma$ not necessarily in $\Gamma_0(N)$ (in which case $f \mid \gamma$ is evaluated using \kbd{mfslashexpansion}). \bprog ? T = mfTheta(); mf = mfinit(T); mfeval(mf,T,[0,1/2,1,oo]) %1 = [1/2 - 1/2*I, 0, 1/2 - 1/2*I, 1] @eprog pari-2.11.2/src/functions/modular_forms/mfcoef0000644000175000017500000000064613447371554020033 0ustar billbillFunction: mfcoef Section: modular_forms C-Name: mfcoef Prototype: GL Help: mfcoef(F,n): Compute the n-th Fourier coefficient a(n) of the modular form F. Doc: Compute the $n$-th Fourier coefficient of the generalized modular form $F$. Note that this is the $n+1$-st component of the vector \kbd{mfcoefs(F,n)} as well as the second component of \kbd{mfcoefs(F,1,n)}. \bprog ? mfcoef(mfDelta(),10) %1 = -115920 @eprog pari-2.11.2/src/functions/modular_forms/mfeigenbasis0000644000175000017500000000510513326135265021214 0ustar billbillFunction: mfeigenbasis Section: modular_forms C-Name: mfeigenbasis Prototype: G Help: mfeigenbasis(mf): vector of the eigenforms for the space mf. Doc: vector of the eigenforms for the space \kbd{mf}. The initial basis of forms computed by \kbd{mfinit} before splitting is also available via \kbd{mfbasis}. \bprog ? mf = mfinit([26,2],0); ? see(L) = for(i=1,#L,print(mfcoefs(L[i],6))); ? see( mfeigenbasis(mf) ) [0, 1, -1, 1, 1, -3, -1] [0, 1, 1, -3, 1, -1, -3] ? see( mfbasis(mf) ) [0, 2, 0, -2, 2, -4, -4] [0, -2, -4, 10, -2, 0, 8] @eprog The eigenforms are internally expressed as (algebraic) linear combinations of \kbd{mfbasis(mf)} and it is very inefficient to compute many coefficients of those forms individually: you should rather use \kbd{mfcoefs(mf)} to expand the basis once and for all, then multiply by \kbd{mftobasis(mf,f)} for the forms you're interested in: \bprog ? mf = mfinit([96,6],0); B = mfeigenbasis(mf); #B %1 = 8; ? vector(#B, i, mfcoefs(B[i],1000)); \\ expanded individually: slow time = 7,881 ms. ? M = mfcoefs(mf, 1000); \\ initialize once time = 982 ms. ? vector(#B, i, M * mftobasis(mf,B[i])); \\ then expand: much faster time = 623 ms. @eprog When the eigenforms are defined over an extension field of $\Q(\chi)$ for a non-rational character, their coefficients are hard to read and you may want to lift them or to express them in an absolute number field. In the construction below $T$ defines $\Q(f)$ over $\Q$, $a$ is the image of the generator \kbd{Mod}$(t, t^2+t+1)$ of $\Q(\chi)$ in $\Q(f)$ and $y - ka$ is the image of the root $y$ of \kbd{f.mod}: \bprog ? mf = mfinit([31, 2, Mod(25,31)], 0); [f] = mfeigenbasis(mf); ? f.mod %2 = Mod(1, t^2 + t + 1)*y^2 + Mod(2*t + 2, t^2 + t + 1) ? v = liftpol(mfcoefs(f,5)) %3 = [0, 1, (-t - 1)*y - 1, t*y + (t + 1), (2*t + 2)*y + 1, t] ? [T,a,k] = rnfequation(mf.mod, f.mod, 1) %4 = [y^4 + 2*y^2 + 4, Mod(-1/2*y^2 - 1, y^4 + 2*y^2 + 4), 0] ? liftpol(substvec(v, [t,y], [a, y-k*a])) %5 = [0, 1, 1/2*y^3 - 1, -1/2*y^3 - 1/2*y^2 - y, -y^3 + 1, -1/2*y^2 - 1] @eprog\noindent Beware that the meaning of $y$ has changed in the last line is different: it now represents of root of $T$, no longer of \kbd{f.mod} (the notions coincide if $k = 0$ as here but it will not always be the case). This can be avoided with an extra variable substitution, for instance \bprog ? [T,a,k] = rnfequation(mf.mod, subst(f.mod,'y,'x), 1) %6 = [x^4 + 2*x^2 + 4, Mod(-1/2*x^2 - 1, x^4 + 2*x^2 + 4), 0] ? liftpol(substvec(v, [t,y], [a, x-k*a])) %7 = [0, 1, 1/2*x^3 - 1, -1/2*x^3 - 1/2*x^2 - x, -x^3 + 1, -1/2*x^2 - 1] @eprog pari-2.11.2/src/functions/modular_forms/mfisCM0000644000175000017500000000165613326135265017745 0ustar billbillFunction: mfisCM Section: modular_forms C-Name: mfisCM Prototype: G Help: mfisCM(F): Tests whether the eigenform F is a CM form. The answer is 0 if it is not, and if it is, either the unique negative discriminant of the CM field, or the pair of two negative discriminants of CM fields, this latter case occuring only in weight 1 when the projective image is D2=C2xC2, i.e., coded 4 by mfgaloistype. Doc: Tests whether the eigenform $F$ is a CM form. The answer is $0$ if it is not, and if it is, either the unique negative discriminant of the CM field, or the pair of two negative discriminants of CM fields, this latter case occuring only in weight $1$ when the projective image is $D_2=C_2\times C_2$, i.e., coded $4$ by \kbd{mfgaloistype}. \bprog ? F = mffromell(ellinit([0,1]))[2]; mfisCM(F) %1 = -3 ? mf = mfinit([39,1,-39],0); F=mfeigenbasis(mf)[1]; mfisCM(F) %2 = Vecsmall([-3, -39]) ? mfgaloistype(mf) %3 = [4] @eprog pari-2.11.2/src/functions/modular_forms/mftwist0000644000175000017500000000156613447371554020273 0ustar billbillFunction: mftwist Section: modular_forms C-Name: mftwist Prototype: GG Help: mftwist(F,D): returns the twist of the form F by the integer D, i.e., the form G such that mfcoef(G,n)=(D/n)mfcoef(F,n), where (D/n) is the Kronecker symbol. Doc: $F$ being a generalized modular form, returns the twist of $F$ by the integer $D$, i.e., the form $G$ such that \kbd{mfcoef(G,n)=}$(D/n)$\kbd{mfcoef(F,n)}, where $(D/n)$ is the Kronecker symbol. \bprog ? mf = mfinit([11,2],0); F = mfbasis(mf)[1]; mfcoefs(F, 5) %1 = [0, 1, -2, -1, 2, 1] ? G = mftwist(F,-3); mfcoefs(G, 5) %2 = [0, 1, 2, 0, 2, -1] ? mf2 = mfinit([99,2],0); mftobasis(mf2, G) %3 = [1/3, 0, 1/3, 0]~ @eprog\noindent Note that twisting multiplies the level by $D^2$. In particular it is not an involution: \bprog ? H = mftwist(G,-3); mfcoefs(H, 5) %4 = [0, 1, -2, 0, 2, 1] ? mfparams(G) %5 = [99, 2, 1, y] @eprog pari-2.11.2/src/functions/modular_forms/mfdescribe0000644000175000017500000000215513447371554020674 0ustar billbillFunction: mfdescribe Section: modular_forms C-Name: mfdescribe Prototype: GD& Help: mfdescribe(F,{&G}): gives a human-readable description of F, which is either a modular form space or a modular form. If the address of G is given, puts into G the vector of parameters of the outmost operator defining F (the empty vector if F is a leaf or a modular form space). Doc: gives a human-readable description of $F$, which is either a modular form space or a generalized modular form. If the address of $G$ is given, puts into $G$ the vector of parameters of the outmost operator defining $F$ (the empty vector if $F$ is a leaf or a modular form space). \bprog ? E1 = mfeisenstein(4,-3,-4); mfdescribe(E1) %1 = "F_4(-3, -4)" ? E2 = mfeisenstein(3,5,-7); mfdescribe(E2) %2 = "F_3(5, -7)" ? E3 = mfderivE2(mfmul(E1,E2), 3); mfdescribe(E3,&G) %3 = "DERE2^3(MUL(F_4(-3, -4), F_3(5, -7)))" ? mfdescribe(G[1][1]) %4 = "MUL(F_4(-3, -4), F_3(5, -7))" ? G[2] %5 = 3 ? for (i = 0, 4, mf = mfinit([37,4],i); print(mfdescribe(mf))); S_4^new(G_0(37, 1)) S_4(G_0(37, 1)) S_4^old(G_0(37, 1)) E_4(G_0(37, 1)) M_4(G_0(37, 1)) @eprog pari-2.11.2/src/functions/modular_forms/mfbracket0000644000175000017500000000076413447371554020533 0ustar billbillFunction: mfbracket Section: modular_forms C-Name: mfbracket Prototype: GGD0,L, Help: mfbracket(F,G,{m=0}): compute the m-th Rankin-Cohen bracket of the generalized modular forms F and G. Doc: compute the $m$-th Rankin--Cohen bracket of the generalized modular forms $F$ and $G$. \bprog ? E4 = mfEk(4); E6 = mfEk(6); ? D1 = mfbracket(E4,E4,2); mfcoefs(D1,5)/4800 %2 = [0, 1, -24, 252, -1472, 4830] ? D2 = mfbracket(E4,E6,1); mfcoefs(D2,10)/(-3456) %3 = [0, 1, -24, 252, -1472, 4830] @eprog pari-2.11.2/src/functions/modular_forms/mftraceform0000644000175000017500000000144113326135265021064 0ustar billbillFunction: mftraceform Section: modular_forms C-Name: mftraceform Prototype: GD0,L, Help: mftraceform(NK,{space=0}): If NK=[N,k,CHI,.] as in mfinit with k integral, gives the trace form in the corresponding subspace of S_k(G_0(N),chi). The supported values for space are 0: the newspace (default), 1: the full cuspidal space. Doc: If $NK=[N,k,CHI,.]$ as in \kbd{mfinit} with $k$ integral, gives the trace form in the corresponding subspace of $S_k(\Gamma_0(N),\chi)$. The supported values for \kbd{space} are 0: the newspace (default), 1: the full cuspidal space. \bprog ? F = mftraceform([23,2]); mfcoefs(F,16) %1 = [0, 2, -1, 0, -1, -2, -5, 2, 0, 4, 6, -6, 5, 6, 4, -10, -3] ? F = mftraceform([23,1,-23]); mfcoefs(F,16) %2 = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0, -1] @eprog pari-2.11.2/src/functions/modular_forms/mfheckemat0000644000175000017500000000121313326135265020660 0ustar billbillFunction: mfheckemat Section: modular_forms C-Name: mfheckemat Prototype: GG Help: mfheckemat(mf,vecn): if vecn is an integer, matrix of the Hecke operator T(n) on the basis formed by mfbasis(mf), if it is a vector, vector of such matrices. Doc: if \kbd{vecn} is an integer, matrix of the Hecke operator $T(n)$ on the basis formed by \kbd{mfbasis(mf)}. If it is a vector, vector of such matrices, usually faster than calling each one individually. \bprog ? mf=mfinit([32,4],0); mfheckemat(mf,3) %1 = [0 44 0] [1 0 -10] [0 -2 0] ? mfheckemat(mf,[5,7]) %2 = [[0, 0, 220; 0, -10, 0; 1, 0, 12], [0, 88, 0; 2, 0, -20; 0, -4, 0]] @eprog pari-2.11.2/src/functions/modular_forms/mfeigensearch0000644000175000017500000000364213326135265021364 0ustar billbillFunction: mfeigensearch Section: modular_forms C-Name: mfeigensearch Prototype: GDG Help: mfeigensearch(NK,{AP}): search for normalized rational eigen cuspforms with quadratic characters given a few initial coefficients. The meaning of the parameters is as follows: NK is of the form [N,k]: search given level N, weight k and quadratic character; note that the character is uniquely determined by (N,k). The level N can be replaced by a vector of allowed levels. AP is the search criterion, which can be omitted: a list of pairs [...,[p,a_p],...], where a_p is either a t_INT (exact match) or a t_INTMOD (match modulo the given integer). The result is a vector of newforms matching the search criteria, sorted by increasing level. Doc: search for a normalized rational eigen cuspform with quadratic character given restrictions on a few initial coefficients. The meaning of the parameters is as follows: \item \kbd{NK} governs the limits of the search: it is of the form $[N,k]$: search for given level $N$, weight $k$ and quadratic character; note that the character $(D/.)$ is uniquely determined by $(N,k)$. The level $N$ can be replaced by a vector of allowed levels. \item \kbd{AP} is the search criterion, which can be omitted: a list of pairs $[\ldots, [p,a_p], \ldots]$, where $p$ is a prime number and $a_p$ is either a \typ{INT} (the $p$-th Fourier coefficient must match $a_p$ exactly) or a \typ{INTMOD} \kbd{Mod}$(a,b)$ (the $p$-th coefficient must be congruent to $a$ modulo $b$). The result is a vector of newforms $f$ matching the search criteria, sorted by increasing level then increasing $|D|$. \bprog ? #mfeigensearch([[1..80],2], [[2,2],[3,-1]]) %1 = 1 ? #mfeigensearch([[1..80],2], [[2,2],[5,2]]) %2 = 1 ? v = mfeigensearch([[1..20],2], [[3,Mod(2,3)],[7,Mod(5,7)]]); #v %3 = 1 ? F=v[1]; [mfparams(F)[1], mfcoefs(F,15)] %4 = [11, [0, 1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1]] @eprog pari-2.11.2/src/functions/modular_forms/mfmul0000644000175000017500000000056313447371554017712 0ustar billbillFunction: mfmul Section: modular_forms C-Name: mfmul Prototype: GG Help: mfmul(F,G): Multiply the two forms F and G. Doc: Multiply the two generalized modular forms $F$ and $G$. \bprog ? E4 = mfEk(4); G = mfmul(mfmul(E4,E4),E4); ? mfcoefs(G, 4) %2 = [1, 720, 179280, 16954560, 396974160] ? mfcoefs(mfpow(E4,3), 4) %3 = [1, 720, 179280, 16954560, 396974160] @eprog pari-2.11.2/src/functions/modular_forms/mfhecke0000644000175000017500000000344013326135265020162 0ustar billbillFunction: mfhecke Section: modular_forms C-Name: mfhecke Prototype: GGL Help: mfhecke(mf,F,n): F being a modular form in space mf, returns T(n)F, where T(n) is the n-th Hecke operator. Warning: if F is of level M= 3/2 and bij being the output of mfkohnenbijection(mf), outputs a 3-component vector [mf0,BNEW,BEIGEN], where BNEW and BEIGEN are two matrices whose columns are the coefficients of a basis of the Kohnen new space and of the eigenforms on the basis of mf respectively, and mf0 is the corresponding new space of integral weight 2k - 1. Doc: \kbd{mf} being a cuspidal space of half-integral weight $k\ge3/2$ and \kbd{bij} being the output of \kbd{mfkohnenbijection(mf)}, outputs a $3$-component vector \kbd{[mf0,BNEW,BEIGEN]}, where \kbd{BNEW} and \kbd{BEIGEN} are two matrices whose columns are the coefficients of a basis of the Kohnen new space and of the eigenforms on the basis of \kbd{mf} respectively, and \kbd{mf0} is the corresponding new space of integral weight $2k-1$. \bprog ? mf=mfinit([44,5/2],1);bij=mfkohnenbijection(mf); ? [mf0,BN,BE]=mfkohneneigenbasis(mf,bij); ? BN~ %2 = [2 0 0 -2 2 0 -8] [2 0 0 4 14 0 -32] ? BE~ %3 = [Mod(1, y^2 - 3) Mod(0, y^2 - 3) Mod(0, y^2 - 3) Mod(y - 1, y^2 - 3)\ Mod(2*y + 1, y^2 - 3) Mod(0, y^2 - 3) Mod(-4*y - 4, y^2 - 3)] ? lift(mfcoefs(mf,20)*BE[,1]) %4 = [0, 1, 0, 0, y - 1, 2*y + 1, 0, 0, 0, -4*y - 4, 0, 0,\ -5*y + 3, 0, 0, 0, -6, 0, 0, 0, 7*y + 9]~ @eprog pari-2.11.2/src/functions/modular_forms/mffromqf0000644000175000017500000000313113326135265020372 0ustar billbillFunction: mffromqf Section: modular_forms C-Name: mffromqf Prototype: GDG Help: mffromqf(Q,{P}): Q being an even positive definite quadratic form and P a homogeneous spherical polynomial for Q, computes a 3-component vector [mf,F,coeffs], where F is the theta function corresponding to (Q, P), mf is the corresponding space of modular forms from mfinit, and coeffs are the coefficients of F on mfbasis(mf). Doc: $Q$ being an even integral positive definite quadratic form and $P$ a homogeneous spherical polynomial for $Q$, computes a 3-component vector $[\var{mf},F,v]$, where $F$ is the theta function corresponding to $(Q,P)$, \var{mf} is the corresponding space of modular forms (from \kbd{mfinit}), and $v$ gives the coefficients of $F$ on \kbd{mfbasis(mf)}. \bprog ? [mf,F,v] = mffromqf(2*matid(10)); v %1 = [64/5, 4/5, 32/5]~ ? mfcoefs(F, 5) %2 = [1, 20, 180, 960, 3380, 8424] ? mfcoef(F, 10000) \\ number of ways of writing 10000 as sum of 10 squares %3 = 128205250571893636 ? mfcoefs(F, 10000); \\ fast ! time = 220ms ? [mf,F,v] = mffromqf([2,0;0,2],x^4-6*x^2*y^2+y^4); ? mfcoefs(F,10) %6 = [0, 4, -16, 0, 64, -56, 0, 0, -256, 324, 224] ? mfcoef(F,100000) \\ instantaneous %7 = 41304367104 @eprog Odd dimensions are supported, corresponding to forms of half-integral weight: \bprog ? [mf,F,v] = mffromqf(2*matid(3)); ? mfisequal(F, mfpow(mfTheta(),3)) %2 = 1 ? mfcoefs(F, 32) \\ illustrate Legendre's 3-square theorem %3 = [ 1, 6, 12, 8, 6, 24, 24, 0, 12, 30, 24, 24, 8, 24, 48, 0, 6, 48, 36, 24,24, 48, 24, 0, 24, 30, 72, 32, 0, 72, 48, 0, 12] @eprog pari-2.11.2/src/functions/modular_forms/mfatkininit0000644000175000017500000000502213447371554021102 0ustar billbillFunction: mfatkininit Section: modular_forms C-Name: mfatkininit Prototype: GLp Help: mfatkininit(mf,Q): initializes data necessary for working with Atkin--Lehner operators W_Q, for now only the function mfatkin. The result is a 4-component vector [mfB, CM, C, mf] where mfB is either 0 or the possibly different modular form space to which F|W_Q will belong (this does not depend on F in mf); CM is the matrix of W_Q on the basis of mf multiplied by a normalizing constant C. Doc: given a modular form space with parameters $N,k,\chi$ and a primitive divisor $Q$ of the level $N$, initializes data necessary for working with the Atkin--Lehner operator $W_Q$, for now only the function \kbd{mfatkin}. We write $\chi \sim \chi_Q \chi_{N/Q}$ where the two characters are primitive with (coprime) conductors dividing $Q$ and $N/Q$ respectively. For $F\in M_k(\Gamma_0(N),\chi)$, the form $F | W_Q$ still has level $N$ and weight $k$ but its Nebentypus may no longer be $\chi$: it becomes $\overline{\chi_Q} \chi_{N/Q})$ if $k$ is integral and $\overline{\chi_Q} \chi_{N/Q})(4Q/\cdot)$ if not. The result is a technical 4-component vector \kbd{[mfB, CM, C, mf]}, where \item \kbd{mfB} encodes the modular form space to which $F|W_Q$ belongs when $F \in M_k(\Gamma_0(N), \chi)$: an \kbd{mfinit} corresponding to a new Nebentypus or the integer $0$ when the character does not change. This does not depend on $F$. \item \kbd{CM} is the matrix of $W_Q$ on the bases of \kbd{mf} and \kbd{mfB} multiplied by a normalizing constant $C(k,\chi,Q)$. This matrix has polmod coefficients in $\Q(\chi)$. \item \kbd{C} is the complex constant $C(k,\chi,Q)$. For $k$ integral, let $A(k,\chi, Q) = Q^{\varepsilon}/g(\chi_Q)$, where $\varepsilon = 0$ for $k$ even and $1/2$ for $k$ odd and where $g(\chi_Q)$ is the Gauss sum attached to $\chi_Q$). (A similar, more complicated, definition holds in half-integral weight depending on the parity of $k - 1/2$.) Then if $M$ denotes the matrix of $W_Q$ on the bases of \kbd{mf} and \kbd{mfB}, $A \cdot M$ has coefficients in $\Q(\chi)$. If $A$ is rational, we let $C = 1$ and $C = A$ as a floating point complex number otherwise, and finally $\kbd{MC} := M \cdot C$. \bprog ? mf=mfinit([32,4],0); [mfB,MC,C]=mfatkininit(mf,32); MC %1 = [5/16 11/2 55/8] [ 1/8 0 -5/4] [1/32 -1/4 11/16] ? C %2 = 1 ? mf=mfinit([32,4,8],0); [mfB,MC,C]=mfatkininit(mf,32); MC %3 = [ 1/8 -7/4] [-1/16 -1/8] ? C %4 = 0.35355339059327376220042218105242451964 ? algdep(C,2) \\ C = 1/sqrt(8) %5 = 8*x^2 - 1 @eprog pari-2.11.2/src/functions/modular_forms/mfshift0000644000175000017500000000076613447371554020237 0ustar billbillFunction: mfshift Section: modular_forms C-Name: mfshift Prototype: GL Help: mfshift(F,s): Divide the form F by q^s omitting the remainder if there is one; s can be negative. Doc: Divide the generalized modular form $F$ by $q^s$, omitting the remainder if there is one. One can have $s<0$. \bprog ? D=mfDelta(); mfcoefs(mfshift(D,1), 4) %1 = [1, -24, 252, -1472, 4830] ? mfcoefs(mfshift(D,2), 4) %2 = [-24, 252, -1472, 4830, -6048] ? mfcoefs(mfshift(D,-1), 4) %3 = [0, 0, 1, -24, 252] @eprog pari-2.11.2/src/functions/modular_forms/mfisequal0000644000175000017500000000106413447371554020555 0ustar billbillFunction: mfisequal Section: modular_forms C-Name: mfisequal Prototype: lGGD0,L, Help: mfisequal(F,G,{lim=0}): Checks whether the modular forms F and G are equal. If lim is nonzero, only check equality of the first lim+1 Fourier coefficients. Doc: Checks whether the modular forms $F$ and $G$ are equal. If \kbd{lim} is nonzero, only check equality of the first $lim+1$ Fourier coefficients and the function then also applies to generalized modular forms. \bprog ? D = mfDelta(); F = mfderiv(D); ? G = mfmul(mfEk(2), D); ? mfisequal(F, G) %2 = 1 @eprog pari-2.11.2/src/functions/modular_forms/mfatkineigenvalues0000644000175000017500000000301513447371554022446 0ustar billbillFunction: mfatkineigenvalues Section: modular_forms C-Name: mfatkineigenvalues Prototype: GLp Help: mfatkineigenvalues(mf,Q): given a modular form space mf and a primitive divisor Q of the level of mf, outputs the corresponding Atkin-Lehner eigenvalues on the new space, grouped by orbit. Doc: Given a modular form space \kbd{mf} of integral weight $k$ and a primitive divisor $Q$ of the level $N$ of \kbd{mf}, outputs the Atkin--Lehner eigenvalues of $w_Q$ on the new space, grouped by orbit. If $\chi$ is a (trivial or) quadratic character defined modulo $N/Q$, the result is rounded and the eigenvalues are $\pm i^k$. \bprog ? mf = mfinit([35,2],0); mffields(mf) %1 = [y, y^2 - y - 4] \\ two orbits, dimension 1 and 2 ? mfatkineigenvalues(mf,5) %2 = [[1], [-1, -1]] ? mf = mfinit([12,7,Mod(3,4)],0); ? mfatkineigenvalues(mf,3) %4 = [[I, -I, -I, I, I, -I]] \\ one orbit @eprog If you want the eigenvalues on a larger space than the new space, e.g. the full space, you can directly call \kbd{[mfB,M,C]=mfatkininit} and compute the eigenvalues as the roots of the characteristic polynomial of $M/C$, i.e. by dividing the roots of \kbd{charpoly(M)} by $C$. Note that the characteristic polynomial is computed exactly since $M$ has coefficients in $\Q(\chi)$, whereas $C$ may be given by a complex number. If the coefficients of the characteristic polynomial are polmods modulo $T$ they must be embedded to $\C$ first using \kbd{subst(lift(), t, exp(2*I*Pi/n))}, when $T$ is \kbd{poliscyclo(n)}; note that $T = \kbd{mf.mod}$. pari-2.11.2/src/functions/modular_forms/mfsymboleval0000644000175000017500000000555213326135265021266 0ustar billbillFunction: mfsymboleval Section: modular_forms C-Name: mfsymboleval Prototype: GGDGb Help: mfsymboleval(fs,path,{ga=id}): evaluation of the modular symbol fs output by mfsymbol on the given path, where path is either a vector [s1,s2] or an integral matrix [a,b;c,d] representing the path [a/c,b/d]. In both cases, s1 or s2 (or a/c or b/d) can also be elements of the upper half-plane. The result is the polynomial equal to the integral between s1 and s2 of (X-tau)^{k-2}F(tau). If ga in GL_2+(Q) is given, replace F by F|_k ga. If the integral diverges, the result will be a rational function. Doc: evaluation of the modular symbol $fs$ (corresponding to the modular form $f$) output by \kbd{mfsymbol} on the given path \kbd{path}, where \kbd{path} is either a vector $[s_1,s_2]$ or an integral matrix $[a,b;c,d]$ representing the path $[a/c,b/d]$. In both cases $s_1$ or $s_2$ (or $a/c$ or $b/d$) can also be elements of the upper half-plane. To avoid possibly lengthy \kbd{mfsymbol} computations, the program also accepts $fs$ of the form \kbd{[mf,F]}, but in that case $s_1$ and $s_2$ are limited to \kbd{oo} and elements of the upper half-plane. The result is the polynomial equal to $\int_{s_1}^{s_2}(X-\tau)^{k-2}F(\tau)\,d\tau$, the integral being computed along a geodesic joining $s_1$ and $s_2$. If \kbd{ga} in $GL_2^+(\Q)$ is given, replace $F$ by $F|_{k}\gamma$. Note that if the integral diverges, the result will be a rational function. If the field of definition $\Q(f)$ is larger than $\Q(\chi)$ then $f$ can be embedded into $\C$ in $d=[\Q(f):\Q(\chi)]$ ways, in which case a vector of the $d$ results is returned. \bprog ? mf=mfinit([35,2],1);f=mfbasis(mf)[1];fs=mfsymbol(mf,f); ? mfsymboleval(fs,[0,oo]) %1 = 0.31404011074188471664161704390256378537*I ? mfsymboleval(fs,[1,3;2,5]) %2 = -0.1429696291... - 0.2619975641...*I ? mfsymboleval(fs,[I,2*I]) %3 = 0.00088969563028739893631700037491116258378*I ? E2=mfEk(2);E22=mflinear([E2,mfbd(E2,2)],[1,-2]);mf=mfinit(E22); ? E2S = mfsymbol(mf,E22); ? mfsymboleval(E2S,[0,1]) %6 = (-1.00000...*x^2 + 1.00000...*x - 0.50000...)/(x^2 - x) @eprog The rational function which is given in case the integral diverges is easy to interpret. For instance: \bprog ? E4=mfEk(4);mf=mfinit(E4);ES=mfsymbol(mf,E4); ? mfsymboleval(ES,[I,oo]) %2 = 1/3*x^3 - 0.928067...*I*x^2 - 0.833333...*x + 0.234978...*I ? mfsymboleval(ES,[0,I]) %3 = (-0.234978...*I*x^3 - 0.833333...*x^2 + 0.928067...*I*x + 0.333333...)/x @eprog\noindent \kbd{mfsymboleval(ES,[a,oo])} is the limit as $T\to\infty$ of $$\int_a^{iT}(X-\tau)^{k-2}F(\tau)\,d\tau + a(0)(X-iT)^{k-1}/(k-1)\;,$$ where $a(0)$ is the $0$th coefficient of $F$ at infinity. Similarly, \kbd{mfsymboleval(ES,[0,a])} is the limit as $T\to\infty$ of $$\int_{i/T}^a(X-\tau)^{k-2}F(\tau)\,d\tau+b(0)(1+iTX)^{k-1}/(k-1)\;,$$ where $b(0)$ is the $0$th coefficient of $F|_{k} S$ at infinity. pari-2.11.2/src/functions/modular_forms/mfsearch0000644000175000017500000000432313326135265020351 0ustar billbillFunction: mfsearch Section: modular_forms C-Name: mfsearch Prototype: GGD4,L, Help: mfsearch(NK,V,{space}): NK being of the form [N,k] with k possibly half-integral, search for a modular form with rational coefficients, of weight k and level N, whose initial coefficients a(0),... are equal to V; space specifies the modular form spaces in which to search. The output is a list of matching forms with that given level and weight. Note that the character is of the form (D/.), where D is a (positive or negative) fundamental discriminant dividing N. N can be replaced by a vector of allowed levels, in which case the list of forms is sorted by increasing level, then increasing |D|. If a form is found at level N, any multiple of N with the same D is not considered Note that this is very different from mfeigensearch, which only searches for rational eigenforms. Doc: \kbd{NK} being of the form \kbd{[N,k]} with $k$ possibly half-integral, search for a modular form with rational coefficients, of weight $k$ and level $N$, whose initial coefficients $a(0)$,... are equal to $V$; \kbd{space} specifies the modular form spaces in which to search, in \kbd{mfinit} or \kbd{mfdim} notation. The output is a list of matching forms with that given level and weight. Note that the character is of the form $(D/.)$, where $D$ is a (positive or negative) fundamental discriminant dividing $N$. The forms are sorted by increasing $|D|$. The parameter $N$ can be replaced by a vector of allowed levels, in which case the list of forms is sorted by increasing level, then increasing $|D|$. If a form is found at level $N$, any multiple of $N$ with the same $D$ is not considered. Some useful possibilities are \item \kbd{[$N_1$..$N_2$]}: all levels between $N_1$ and $N_2$, endpoints included; \item \kbd{$F$ * [$N_1$..$N_2$]}: same but levels divisible by $F$; \item \kbd{divisors}$(N_0)$: all levels dividing $N_0$. Note that this is different from \kbd{mfeigensearch}, which only searches for rational eigenforms. \bprog ? F = mfsearch([[1..40], 2], [0,1,2,3,4], 1); #F %1 = 3 ? [ mfparams(f) | f <- F ] %2 = [[38, 2, 1, y], [40, 2, 8, y], [40, 2, 40, y]] ? mfcoefs(F[1],10) %3 = [0, 1, 2, 3, 4, -5, -8, 1, -7, -5, 7] @eprog pari-2.11.2/src/functions/modular_forms/mfperiodpolbasis0000644000175000017500000000076213326135265022126 0ustar billbillFunction: mfperiodpolbasis Section: modular_forms C-Name: mfperiodpolbasis Prototype: LD0,L, Help: mfperiodpolbasis(k,{flag=0}): basis of period polynomials for weight k. If flag=1 or -1, basis of odd or even period polynomials. Doc: Basis of period polynomials for weight k. If flag=1 or $-1$, basis of odd or even period polynomials. \bprog ? mfperiodpolbasis(12,1) %1 = [x^8 - 3*x^6 + 3*x^4 - x^2, x^10 - 1] ? mfperiodpolbasis(12,-1) %2 = [4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x] @eprog pari-2.11.2/src/functions/modular_forms/mfderivE20000644000175000017500000000121013447371554020403 0ustar billbillFunction: mfderivE2 Section: modular_forms C-Name: mfderivE2 Prototype: GD1,L, Help: mfderivE2(F,{m=1}): compute the Serre derivative (q.d/dq)F - kE_2F/12 of the generalized modular form F of weight k; and if m > 1, the m-th iterate. Doc: compute the Serre derivative $(q.d/dq)F - kE_2F/12$ of the generalized modular form $F$, which has weight $k+2$; if $F$ is a true modular form, then its Serre derivative is also modular. If $m>1$, compute the $m$-th iterate, of weight $k + 2m$. \bprog ? mfcoefs(mfderivE2(mfEk(4)),5)*(-3) %1 = [1, -504, -16632, -122976, -532728] ? mfcoefs(mfEk(6),5) %2 = [1, -504, -16632, -122976, -532728] @eprog pari-2.11.2/src/functions/modular_forms/mfparams0000644000175000017500000000361413447371554020400 0ustar billbillFunction: mfparams Section: modular_forms C-Name: mfparams Prototype: G Help: mfparams(F): If F is a modular form space, returns [N,k,CHI,space]: level, weight, character, and space code. If F is a modular form, returns [N,k,CHI,P], where P is the (polynomial giving the) field of definition of F: in that case the level N may be a multiple of the level of F and the polynomial P may define a larger field than Q(F). Doc: If $F$ is a modular form space, returns \kbd{[N,k,CHI,space]}, level, weight, character, and space code. If $F$ is a generalized modular form, returns \kbd{[N,k,CHI,P]}, where $P$ is the (polynomial giving the) field of definition of $F$: in that case the level $N$ may be a multiple of the level of $F$ and the polynomial $P$ may define a larger field than $\Q(F)$. If you want the true level of $F$ from this result, use \kbd{mfconductor(mfinit(F),F)}. The polynomial $P$ defines an extension of $\Q(\chi) = \Q[t]/(\Phi(t))$ for the cyclotomic polynomial of order $f(\chi)$; it has coefficients in that number field (polmods in $t$). In contrast with \kbd{mfparams(f)[4]} which always gives the polynomial $P$ defining the relative extension $\Q(f)/\Q(\chi)$, the member function \kbd{$f$.mod} returns the polynomial used to define $\Q(f)$ over $\Q$ (either a cyclotomic polynomial or a polynomial with cyclotomic coefficients). \bprog ? E1 = mfeisenstein(4,-3,-4); E2 = mfeisenstein(3,5,-7); E3 = mfmul(E1,E2); ? apply(mfparams, [E1,E2,E3]) %2 = [[12, 4, 12, y], [35, 3, -35, y], [420, 7, -420, y]] ? mf = mfinit([36,2,Mod(13,36)],0); [f] = mfeigenbasis(mf); mfparams(mf) %3 = [36, 2, Mod(13, 36), 0] ? mfparams(f) %4 = [36, 2, Mod(13, 36), y] ? f.mod %5 = t^2 + t + 1 ? mf = mfinit([36,4,Mod(13,36)],0); [f] = mfeigenbasis(mf); ? mfparams(f) %7 = [36, 4, Mod(13, 36), y^3 + Mod(2*t - 2, t^2 + t + 1)*y^2 + Mod(-4*t + 6, t^2+t+1)*y + Mod(10*t - 1, t^2+t+1)] @eprog pari-2.11.2/src/functions/modular_forms/mfcusps0000644000175000017500000000062413326135265020241 0ustar billbillFunction: mfcusps Section: modular_forms C-Name: mfcusps Prototype: G Help: mfcusps(N): list of cusps of G_0(N) in the form a/b with b dividing N. N can be either an integer or a modular form space. Doc: list of cusps of $\Gamma_0(N)$ in the form $a/b$ with $b\mid N$. $N$ can be either an integer of a modular form space. \bprog ? mfcusps(24) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/8, 1/12, 1/24] @eprog pari-2.11.2/src/functions/modular_forms/mftocoset0000644000175000017500000000121713326135265020563 0ustar billbillFunction: mftocoset Section: modular_forms C-Name: mftocoset Prototype: LGG Help: mftocoset(N,M,Lcosets): M being a matrix in SL_2(Z) and Lcosets being mfcosets(N), find the right coset of G_0(N) to which M belongs. The output is a pair [ga,i] such that M = ga * Lcosets[i], with ga in G_0(N). Doc: $M$ being a matrix in $SL_2(Z)$ and \kbd{Lcosets} being \kbd{mfcosets(N)}, a list of right cosets of $\Gamma_0(N)$, find the coset to which $M$ belongs. The output is a pair $[\gamma,i]$ such that $M = \gamma \kbd{Lcosets}[i]$, $\gamma\in\Gamma_0(N)$. \bprog ? N = 4; L = mfcosets(N); ? mftocoset(N, [1,1;2,3], L) %2 = [[-1, 1; -4, 3], 5] @eprog pari-2.11.2/src/functions/modular_forms/HEADER0000644000175000017500000000675313447371554017531 0ustar billbillFunction: _header_modular_forms Class: header Section: modular_forms Doc: \section{Modular forms} This section describes routines for working with modular forms and modular form spaces. \subsec{Modular form spaces} %GPHELPskip These structures are initialized by the \kbd{mfinit} command; supported modular form \emph{spaces} with corresponding flags are the following: \item The full modular form space $M_k(\Gamma_0(N),\chi)$, where $k$ is an integer or a half-integer and $\chi$ a Dirichlet character modulo $N$ (flag $4$, the default). \item The cuspidal space $S_k(\Gamma_0(N),\chi)$ (flag $1$). \item The Eisenstein space ${\cal E}_k(\Gamma_0(N),\chi)$ (flag $3$), so that $M_k={\cal E}_k\oplus S_k$. \item The new space $S_k^{\text{new}}(\Gamma_0(N),\chi)$ (flag $0$). \item The old space $S_k^{\text{old}}(\Gamma_0(N),\chi)$ (flag $2$), so that $S_k=S_k^{\text{new}}\oplus S_k^{\text{old}}$. These resulting \kbd{mf} structure contains a basis of modular forms, which is accessed by the function \kbd{mfbasis}; the elements of this basis have Fourier coefficients in the cyclotomic field $\Q(\chi)$. These coefficients are given algebraically, as rational numbers or \typ{POLMOD}s. The member function \kbd{mf.mod} recovers the modulus used to define $\Q(\chi)$, which is a cyclotomic polynomial $\Phi_n(t)$. When needed, the elements of $\Q(\chi)$ are considered to be canonically embedded into $\C$ via $\kbd{Mod}(t,\Phi_n(t)) \mapsto \exp(2i\pi/n)$. The basis of eigenforms for the new space is obtained by the function \kbd{mfeigenbasis}: the elements of this basis now have Fourier coefficients in a relative field extension of $\Q(\chi)$. Note that if the space is larger than the new space (i.e. is the cuspidal or full space) we nevertheless obtain only the eigenbasis for the new space. \subsec{Generalized modular forms} %GPHELPskip A modular form is represented in a special internal format giving the possibility to compute an arbitrary number of terms of its Fourier coefficients at infinity $[a(0),a(1),...,a(n)]$ using the function \kbd{mfcoefs}. These coefficients are given algebraically, as rational numbers or \typ{POLMOD}s. The member function \kbd{f.mod} recovers the modulus used in the coefficients of $f$, which will be the same as for $k = \Q(\chi)$ (a cyclotomic polynomial), or define a number field extension $K/k$. Modular forms are obtained either directly from other mathematical objects, e.g., elliptic curves, or by a specific formula, e.g., Eisenstein series or Ramanujan's Delta function, or by applying standard operators to existing forms (Hecke operators, Rankin--Cohen brackets, \dots). A function \kbd{mfparams} is provided so that one can recover the level, weight, character and field of definition corresponding to a given modular form. A number of creation functions and operations are provided. It is however important to note that strictly speaking some of these operations create objects which are \emph{not} modular forms: typical examples are derivation or integration of modular forms, the Eisenstein series $E_2$, eta quotients, or quotients of modular forms. These objects are nonetheless very important in the theory, so are not considered as errors; however the user must be aware that no attempt is made to check that the objects that he handles are really modular. When the documentation of a function does not state that it applies to generalized modular forms, then the output is undefined if the input is not a true modular form. pari-2.11.2/src/functions/modular_forms/mfsplit0000644000175000017500000000507613326135265020245 0ustar billbillFunction: mfsplit Section: modular_forms C-Name: mfsplit Prototype: GD0,L,D0,L, Help: mfsplit(mf,{dimlim=0},{flag=0}): mf containing the new space split the new space into Galois orbits of eigenforms of the newspace and return [vF,vK], where vF gives the (Galois orbit of) eigenforms in terms of mfbasis(mf) and vK is a list of polynomials defining each Galois orbit. If dimlim is set only the Galois orbits of dimension <= dimlim are computed (i.e. the rational eigenforms if dimlim = 1 and the character is real). Flag speeds up computations when the dimension is large: if flag = d > 0, when the dimension of the eigenspace is > d, only the Galois polynomial is computed. Doc: \kbd{mf} from \kbd{mfinit} with integral weight containing the new space (either the new space itself or the cuspidal space or the full space), and preferably the newspace itself for efficiency, split the space into Galois orbits of eigenforms of the newspace, satisfying various restrictions. The functions returns $[vF, vK]$, where $vF$ gives (Galois orbit of) eigenforms and $vK$ is a list of polynomials defining each Galois orbit. The eigenforms are given in \kbd{mftobasis} format, i.e. as a matrix whose columns give the forms with respect to \kbd{mfbasis(mf)}. If \kbd{dimlim} is set, only the Galois orbits of dimension $\leq \kbd{dimlim}$ are computed (i.e. the rational eigenforms if $\kbd{dimlim} = 1$ and the character is real). This can considerably speed up the function when a Galois orbit is defined over a large field. \kbd{flag} speeds up computations when the dimension is large: if $flag=d>0$, when the dimension of the eigenspace is $>d$, only the Galois polynomial is computed. Note that the function \kbd{mfeigenbasis} returns all eigenforms in an easier to use format (as modular forms which can be input as is in other functions); \kbd{mfsplit} is only useful when you can restrict to orbits of small dimensions, e.g. rational eigenforms. \bprog ? mf=mfinit([11,2],0); f=mfeigenbasis(mf)[1]; mfcoefs(f,16) %1 = [0, 1, -2, -1, ...] ? mf=mfinit([23,2],0); f=mfeigenbasis(mf)[1]; mfcoefs(f,16) %2 = [Mod(0, z^2 - z - 1), Mod(1, z^2 - z - 1), Mod(-z, z^2 - z - 1), ...] ? mf=mfinit([179,2],0); apply(poldegree, mffields(mf)) %3 = [1, 3, 11] ? mf=mfinit([719,2],0); ? [vF,vK] = mfsplit(mf, 5); \\ fast when restricting to small orbits time = 192 ms. ? #vF \\ a single orbit %5 = 1 ? poldegree(vK[1]) \\ of dimension 5 %6 = 5 ? [vF,vK] = mfsplit(mf); \\ general case is slow time = 2,104 ms. ? apply(poldegree,vK) %8 = [5, 10, 45] \\ because degree 45 is large... @eprog pari-2.11.2/src/functions/modular_forms/mfcuspval0000644000175000017500000000251513447371554020571 0ustar billbillFunction: mfcuspval Section: modular_forms C-Name: mfcuspval Prototype: GGGb Help: mfcuspval(mf,F,cusp): valuation of modular form F in the space mf at cusp, which can be either oo or any rational number, and the result is either a rational number or oo if F is zero. If Q(F) != Q(chi), return the vector of valuations attached to the [Q(F):Q(chi)] complex embeddings of F. Doc: valuation of modular form $F$ in the space \kbd{mf} at \kbd{cusp}, which can be either $\infty$ or any rational number, and the result is either a rational number or $\infty$ if $F$ is zero. If $\Q(F) \neq \Q(\chi)$, return the vector of valuations attached to the $[\Q(F):\Q(chi)]$ complex embeddings of $F$. \bprog ? T=mfTheta();mf=mfinit([12,1/2]);mfcusps(12) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/12] ? apply(x->mfcuspval(mf,T,x),%1) %2 = [0, 1/4, 0, 0, 1/4, 0] ? mf=mfinit([12,6,12],1);F=mfbasis(mf)[5]; ? apply(x->mfcuspval(mf,F,x),%1) %4 = [1/12, 1/6, 1/2, 2/3, 1/2, 2] ? mf=mfinit([12,3,-4],1);F=mfbasis(mf)[1]; ? apply(x->mfcuspval(mf,F,x),%1) %6 = [1/12, 1/6, 1/4, 2/3, 1/2, 1] ? mf = mfinit([625,2],0); [F] = mfeigenbasis(mf); mfparams(F) %7 = [625, 2, 1, y^2 - y - 1] \\ [Q(F):Q(chi)] = poldegree(y^2-y-1) ? mfcuspval(mf, F, 1/25) %8 = [1, 2] \\ one conjugate has valuation 1, and the other is 2 ? mfcuspval(mf, F, 1/5) %9 = [1/25, 1/25] @eprog pari-2.11.2/src/functions/modular_forms/mfnumcusps0000644000175000017500000000041613326135265020760 0ustar billbillFunction: mfnumcusps Section: modular_forms C-Name: mfnumcusps Prototype: G Help: mfnumcusps(N): number of cusps of Gamma_0(N) Doc: number of cusps of $\Gamma_0(N)$ \bprog ? mfnumcusps(24) %1 = 8 ? mfcusps(24) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/8, 1/12, 1/24] @eprog pari-2.11.2/src/functions/modular_forms/mfpow0000644000175000017500000000044513447371554017721 0ustar billbillFunction: mfpow Section: modular_forms C-Name: mfpow Prototype: GL Help: mfpow(F,n): compute F^n Doc: Compute $F^n$, where $n$ is an integer and $F$ is a generalized modular form: \bprog ? G = mfpow(mfEk(4), 3); \\ E4^3 ? mfcoefs(G, 4) %2 = [1, 720, 179280, 16954560, 396974160] @eprog pari-2.11.2/src/functions/modular_forms/getcache0000644000175000017500000000307713326135265020331 0ustar billbillFunction: getcache Section: modular_forms C-Name: getcache Prototype: Help: getcache(): returns information about various auto-growing caches. For each ressource, we report its name, its size, the number of cache misses (since the last extension) and the largest cache miss. Doc: returns information about various auto-growing caches. For each ressource, we report its name, its size, the number of cache misses (since the last extension), the largest cache miss and the size of the cache in bytes. The caches are initially empty, then set automatically to a small inexpensive default value, then grow on demand up to some maximal value. Their size never decreases, they are only freed on exit. The current caches are \item Hurwitz class numbers $H(D)$ for $|D| \leq N$, computed in time $O(N^{3/2})$ using $O(N)$ space. \item Factorizations of small integers up to $N$, computed in time $O(N^{1+\varepsilon})$ using $O(N\log N)$ space. \item Divisors of small integers up to $N$, computed in time $O(N^{1+\varepsilon})$ using $O(N\log N)$ space. \item Primitive dihedral forms of weight $1$ and level up to $N$, computed in time $O(N^{2+\varepsilon})$ and space $O(N^2)$. \bprog ? getcache() \\ on startup, all caches are empty %1 = [ "Factors" 0 0 0 0] ["Divisors" 0 0 0 0] [ "H" 0 0 0 0] ["Dihedral" 0 0 0 0] ? mfdim([500,1,0],0); \\ non-trivial computation time = 540 ms. ? getcache() %3 = [ "Factors" 50000 0 0 4479272] ["Divisors" 50000 1 100000 5189808] [ "H" 50000 0 0 400008] ["Dihedral" 1000 0 0 2278208] @eprog pari-2.11.2/src/functions/modular_forms/mfsymbol0000644000175000017500000000355013326135265020412 0ustar billbillFunction: mfsymbol Section: modular_forms C-Name: mfsymbol Prototype: GDGb Help: mfsymbol(mf,f): Initialize data for working with all period polynomials of the modular form f: this is essential for efficiency for functions such as mfsymboleval, mfmanin, and mfpetersson. By abuse of language, initialize data for working with mfpetersson in weight 1 or half-integral weight (where no symbol exist). Doc: Initialize data for working with all period polynomials of the modular form $f$: this is essential for efficiency for functions such as \kbd{mfsymboleval}, \kbd{mfmanin}, and \kbd{mfpetersson}. An \kbd{mfsymbol} contains an \kbd{mf} structure and can always be used whenever an \kbd{mf} would be needed. \bprog ? mf=mfinit([23,2],0);F=mfeigenbasis(mf)[1]; ? FS=mfsymbol(mf,F); ? mfsymboleval(FS,[0,oo]) %3 = [8.762565143790690142 E-39 + 0.0877907874...*I, -5.617375463602574564 E-39 + 0.0716801031...*I] ? mfpetersson(FS) %4 = [0.0039488965740025031688548076498662860143 1.2789721111175127425 E-40] [1.2630501762985554269 E-40 0.0056442542987647835101583821368582485396] @eprog\noindent By abuse of language, initialize data for working with \kbd{mfpetersson} in weight $1$ and half-integral weight (where no symbol exist); the \kbd{mf} argument may be an \kbd{mfsymbol} attached to a form on the space, which avoids recomputing data independent of the form. \bprog ? mf=mfinit([12,9/2],1); F=mfbasis(mf); ? fs=mfsymbol(mf,F[1]); time = 476 ms ? mfpetersson(fs) %2 = 1.9722437519492014682047692073275406145 E-5 ? f2s = mfsymbol(mf,F[2]); time = 484 ms. ? mfpetersson(f2s) %4 = 1.2142222531326333658647877864573002476 E-5 ? gs = mfsymbol(fs,F[2]); \\ re-use existing symbol, a little faster time = 430 ms. ? mfpetersson(gs) == %4 \\ same value %6 = 1 @eprog For simplicity, we also allow \kbd{mfsymbol(f)} instead of \kbd{mfsymbol(mfinit(f), f)}: pari-2.11.2/src/functions/modular_forms/mfshimura0000644000175000017500000000361113326135265020553 0ustar billbillFunction: mfshimura Section: modular_forms C-Name: mfshimura Prototype: GGD1,L, Help: mfshimura(mf, F, {D = 1}): F being a modular form of half-integral weight k >= 3/2 and D a (not necessarily fundamental) discriminant of suitable sign, computes the Shimura lift G of weight 2k-1 corresponding to D. This function returns [mf2,G,v], where mf2 is a modular form space containing G, and v the vector of coefficients of G on mf. By extension, D can also be a positive squarefree integer. Doc: $F$ being a modular form of half-integral weight $k\geq 3/2$ and $D$ a (not necessarily fundamental) discriminant of suitable sign, returns the Shimura lift $G$ of weight $2k-1$ corresponding to $D$. The sign of $D$ should be equal to $(-1)^{k-1/2}\epsilon$, where $\epsilon=1$ if $\chi$ is defined modulo $N/4$, $\epsilon=-1$ if $(-4/.)\chi$ is defined modulo $N/4$ (and error otherwise). This function returns $[\var{mf2},G,v]$ where \var{mf2} is a modular form space containing $G$ and $v$ expresses $G$ in terms of \kbd{mfbasis}$(\var{mf2})$; so that $G$ is \kbd{mflinear}$(\var{mf2},v)$. By extension, we allow $D$ to be a positive squarefree integer, but in that case if $(-1)^{k-1/2}\epsilon\cdot D$ is not a discriminant, the Kohnen $+$-space will in general not be sent to level $N/4$ but only $N/2$. \bprog ? F = mfpow(mfTheta(), 7); mf = mfinit(F); ? [mf2, G, v] = mfshimura(mf, F, -3); mfcoefs(G,5) %2 = [-5/9, 280, 9240, 68320, 295960, 875280] ? mfparams(G) %3 = [1, 6, 1, y] ? mfparams(mf2) %4 = [2, 6, 1, 4] \\ it may happen that G has lower level than expected ? v %5 = [280, 0]~ ? mfcoefs(mf2, 5) %6 = [-1/504 -1/504] [ 1 0] [ 33 1] [ 244 0] [ 1057 33] [ 3126 0] ? mf = mfinit([60,5/2],1); F = mflinear(mf,mfkohnenbasis(mf)[,1]); ? mfparams(mfshimura(mf,F,1)[2]) %8 = [15, 4, 1, y] ? mfparams(mfshimura(mf,F,6)[2]) %9 = [30, 4, 1, y] @eprog pari-2.11.2/src/functions/modular_forms/mfeisenstein0000644000175000017500000000174713447371554021270 0ustar billbillFunction: mfeisenstein Section: modular_forms C-Name: mfeisenstein Prototype: LDGDG Help: mfeisenstein(k,{CHI1},{CHI2}): create the Eisenstein E_k(CHI1,CHI2), where an omitted character is considered as trivial. Doc: create the Eisenstein series $E_k(\chi_1,\chi_2)$, where $k \geq 1$, $\chi_i$ are Dirichlet characters and an omitted character is considered as trivial. \bprog ? CHI = Mod(3,4); ? E = mfeisenstein(3, CHI); ? mfcoefs(E, 6) %2 = [-1/4, 1, 1, -8, 1, 26, -8] ? CHI2 = Mod(4,5); ? mfcoefs(mfeisenstein(3,CHI,CHI2), 6) %3 = [0, 1, -1, -10, 1, 25, 10] ? mfcoefs(mfeisenstein(4,CHI,CHI), 6) %4 = [0, 1, 0, -28, 0, 126, 0] ? mfcoefs(mfeisenstein(4), 6) %5 = [1/240, 1, 9, 28, 73, 126, 252] @eprog\noindent Note that \kbd{meisenstein}$(k)$ is 0 for $k$ odd and $-B_{k}/(2k) \cdot E_k$ for $k$ even, where $$E_k(q) = 1 - (2k/B_k)\sum_{n\geq 1} \sigma_{k-1}(n) q^n$$ is the standard Eisenstein series. In other words it is normalized so that its linear coefficient is $1$. pari-2.11.2/src/functions/modular_forms/mfdiv0000644000175000017500000000137413447371554017700 0ustar billbillFunction: mfdiv Section: modular_forms C-Name: mfdiv Prototype: GG Help: mfdiv(F,G): compute F/G for two modular forms F and G assuming that the quotient will not have poles at infinity. If this is the case, use mfshift before doing the division. Doc: Given two generalized modular forms $F$ and $G$, compute $F/G$ assuming that the quotient will not have poles at infinity. If this is the case, use \kbd{mfshift} before doing the division. \bprog ? D = mfDelta(); \\ Delta ? H = mfpow(mfEk(4), 3); ? J = mfdiv(H, D) *** at top-level: J=mfdiv(H,mfdeltac *** ^-------------------- *** mfdiv: domain error in mfdiv: ord(G) > ord(F) ? J = mfdiv(H, mfshift(D,1)); ? mfcoefs(J, 4) %4 = [1, 744, 196884, 21493760, 864299970] @eprog pari-2.11.2/src/functions/modular_forms/mfEH0000644000175000017500000000130713326135265017377 0ustar billbillFunction: mfEH Section: modular_forms C-Name: mfEH Prototype: G Help: mfEH(k): k being in 1/2+Z, mf corresponding to the Cohen-Eisenstein series H_k of weight k on G_0(4). Doc: $k$ being in $1/2+\Z$, returns the Cohen-Eisenstein series $H_k$ of weight $k$ on $\Gamma_0(4)$. \bprog ? H = mfEH(13/2); mfcoefs(H,4) %1 = [691/32760, -1/252, 0, 0, -2017/252] @eprog The coefficients of $H$ are given by the Cohen-Hurwitz function $H(k-1/2,N)$ and can be obtained for moderately large values of $N$ (the algorithm uses $\tilde{O}(N)$ time): \bprog ? mfcoef(H,10^5+1) time = 55 ms. %2 = -12514802881532791504208348 ? mfcoef(H,10^7+1) time = 6,044 ms. %3 = -1251433416009877455212672599325104476 @eprog pari-2.11.2/src/functions/modular_forms/mfEk0000644000175000017500000000043713326135265017445 0ustar billbillFunction: mfEk Section: modular_forms C-Name: mfEk Prototype: L Help: mfEk(k): mf corresponding to the standard Eisenstein series E_k. Doc: mf structure corresponding to the standard Eisenstein series $E_k$. \bprog ? mfcoefs(mfEk(8),4) %1 = [1, 480, 61920, 1050240, 7926240] @eprog pari-2.11.2/src/functions/modular_forms/mfspace0000644000175000017500000000206413326135265020177 0ustar billbillFunction: mfspace Section: modular_forms C-Name: mfspace Prototype: lGDG Help: mfspace(mf,{f}): identify the modular space mf, resp. the modular form f in mf. Returns 0 (newspace), 1 (cuspidal space), 2 (old space), 3 (Eisenstein space) or 4 (full space). Return -1 when the form does not belong to the space. Doc: identify the modular space \var{mf}, resp.~the modular form $f$ in \var{mf} if present, as the flag given to \kbd{mfinit}. Returns 0 (newspace), 1 (cuspidal space), 2 (old space), 3 (Eisenstein space) or 4 (full space). \bprog ? mf = mfinit([1,12],1); mfspace(mf) %1 = 1 ? mfspace(mf, mfDelta()) %2 = 0 \\ new space @eprog\noindent This function returns $-1$ when the form $f$ is modular but does not belong to the space. \bprog ? mf = mfinit([1,2]; mfspace(mf, mfEk(2)) %3 = -1 @eprog When $f$ is not modular and is for instance only quasi-modular, the function returns nonsense: \bprog ? M6 = mfinit([1,6]); ? dE4 = mfderiv(mfEk(4)); \\ not modular ! ? mfspace(M6,dE4) \\ asserts (wrongly) that E4' belongs to new space %3 = 0 @eprog pari-2.11.2/src/functions/modular_forms/mfkohnenbasis0000644000175000017500000000221713326135265021410 0ustar billbillFunction: mfkohnenbasis Section: modular_forms C-Name: mfkohnenbasis Prototype: G Help: mfkohnenbasis(mf): mf being a cuspidal space of half-integral weight k >= 3/2, gives a basis B of the Kohnen + space of mf as a matrix whose columns are the coefficients of B on the basis of mf. Doc: \kbd{mf} being a cuspidal space of half-integral weight $k\ge3/2$ with level $N$ and character $\chi$, gives a basis $B$ of the Kohnen $+$-space of \kbd{mf} as a matrix whose columns are the coefficients of $B$ on the basis of \kbd{mf}. The conductor of either $\chi$ or $\chi \cdot (-4/.)$ must divide $N/4$. \bprog ? mf = mfinit([36,5/2],1); K = mfkohnenbasis(mf); K~ %1 = [-1 0 0 2 0 0] [ 0 0 0 0 1 0] ? (mfcoefs(mf,20) * K)~ %4 = [0 -1 0 0 2 0 0 0 0 0 0 0 0 -6 0 0 8 0 0 0 0] [0 0 0 0 0 1 0 0 -2 0 0 0 0 0 0 0 0 1 0 0 2] ? mf = mfinit([40,3/2,8],1); mfkohnenbasis(mf) *** at top-level: mfkohnenbasis(mf) *** ^----------------- *** mfkohnenbasis: incorrect type in mfkohnenbasis [incorrect CHI] (t_VEC). @eprog In the final example both $\chi = (8/.)$ and $\chi \cdot (-4/.)$ have conductor $8$, which does not divide N/4 = 10. pari-2.11.2/src/functions/modular_forms/mfTheta0000644000175000017500000000121313326135265020144 0ustar billbillFunction: mfTheta Section: modular_forms C-Name: mfTheta Prototype: DG Help: mfTheta({psi=1}): the unary theta function corresponding to the primitive Dirichlet character psi, hence of weight 1/2 if psi is even, of weight 3/2 if psi is odd. Doc: the unary theta function corresponding to the primitive Dirichlet character $\psi$, hence of weight $1/2$ if $\psi$ is even, of weight $3/2$ if $\psi$ is odd. \bprog ? Ser(mfcoefs(mfTheta(),30)) %1 = 1 + 2*x + 2*x^4 + 2*x^9 + 2*x^16 + 2*x^25 + O(x^31) ? Ser(mfcoefs(mfTheta(8),30)) %2 = 2*x - 2*x^9 - 2*x^25 + O(x^31) ? Ser(mfcoefs(mfTheta(-8),30)) %3 = 2*x + 6*x^9 - 10*x^25 + O(x^31) @eprog pari-2.11.2/src/functions/modular_forms/mfcuspisregular0000644000175000017500000000074613326135265022001 0ustar billbillFunction: mfcuspisregular Section: modular_forms C-Name: mfcuspisregular Prototype: lGG Help: mfcuspisregular(NK, cusp): In the space defined by NK = [N,k,CHI] or NK = mf, determine if cusp in canonical format (oo or denominator dividing N) is regular or not. Doc: In the space defined by \kbd{NK = [N,k,CHI]} or \kbd{NK = mf}, determine if \kbd{cusp} in canonical format (oo or denominator dividing $N$) is regular or not. \bprog ? mfcuspisregular([4,3,-4],1/2) %1 = 0 @eprog pari-2.11.2/src/functions/modular_forms/mfslashexpansion0000644000175000017500000000712513326135265022146 0ustar billbillFunction: mfslashexpansion Section: modular_forms C-Name: mfslashexpansion Prototype: GGGLLD&p Help: mfslashexpansion(mf,f,g,n,flrat,{¶ms}): g being in M_2^+(Q), computes the Fourier expansion of f|_k g to n terms. f must belong to the space mf. If params is given, it is set to the parameters [alpha,w,A]. If flrat is 1, the program tries to rationalize the expression; if flag is 0, it does not. Doc: let \var{mf} be a modular form space in leven $N$, $f$ a modular form belonging to \var{mf} and let $g$ be in $M_2^+(Q)$. This function computes the Fourier expansion of $f|_k g$ to $n$ terms. We first describe the behaviour when \kbd{flrat} is 0: the result is a vector $v$ of floating point complex numbers such that $$f|_k g(\tau) = q^\alpha \sum_{m\ge0} v[m+1] q^{m/w},$$ where $q = e(\tau)$, $w$ is the width of the cusp $g(i\infty)$ (namely $(N/(c^2,N)$ if $g$ is integral) and $\alpha$ is a rational number. If \kbd{params} is given, it is set to the parameters $[\alpha,w, \kbd{matid}(2)]$. If \kbd{flrat} is 1, the program tries to rationalize the expression, i.e., to express the coefficients as rational numbers or polmods. We write $g = \lambda \cdot M \cdot A$ where $\lambda \in \Q^*$, $M\in \text{SL}_2(\Z)$ and $A = [a,b;0,d]$ is upper triangular, integral and primitive with $a > 0$, $d > 0$ and $0 \leq b < d$. Let $\alpha$ and $w$ by the parameters attached to the expansion of $F := f |_k M$ as above, i.e. $$ F(\tau) = q^\alpha \sum_{m\ge0} v[m+1] q^{m/w}.$$ The function returns the expansion $v$ of $F = f |_k M$ and sets the parameters to $[\alpha, w, A]$. Finally, the desired expansion is $(a/d)^{k/2} F(\tau + b/d)$. The latter is identical to the returned expansion when $A$ is the identity, i.e. when $g\in \text{PSL}_2(\Z)$. If this is not the case, the expansion differs from $v$ by the multiplicative constant $(a/d)^{k/2} e(\alpha b/(dw))$ and a twist by a root of unity $q^{1/w} \to e(b/(dw)) q^{1/w}$. The complications introduced by this extra matrix $A$ allow to recognize the coefficients in a much smaller cyclotomic field, hence to obtain a simpler description overall. (Note that this rationalization step may result in an error if the program cannot perform it.) \bprog ? mf = mfinit([32,4],0); f = mfbasis(mf)[1]; ? mfcoefs(f, 10) %2 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 47, 0] ? mfatk = mfatkininit(mf,32); mfcoefs(mfatkin(mfatk,f),10) / mfatk[3] %3 = [0, 1, 0, 16, 0, 22, 0, 32, 0, -27, 0] ? mfatk[3] \\ here normalizing constant C = 1, but need in general %4 = 1 ? mfslashexpansion(mf,f,[0,-1;1,0],10,1,¶ms) * 32^(4/2) %5 = [0, 1, 0, 16, 0, 22, 0, 32, 0, -27, 0] ? params %6 = [0, 32, [1, 0; 0, 1]] ? mf = mfinit([12,8],0); f = mfbasis(mf)[1]; ? mfslashexpansion(mf,f,[1,0;2,1],7,0) %7 = [0, 0, 0, 0.6666666... + 0.E-38*I, 0, -3.999999... + 6.92820...*I, 0,\ -11.99999999... - 20.78460969...*I] ? mfslashexpansion(mf,f,[1,0;2,1],7,1, ¶ms) %8 = [0, 0, 0, 2/3, 0, Mod(8*t, t^2+t+1), 0, Mod(-24*t-24, t^2+t+1)] ? params %9 = [0, 3, [1, 0; 0, 1]] @eprog If $[\Q(f):\Q(\chi)]>1$, the coefficients may be polynomials in $y$, where $y$ is any root of the polynomial giving the field of definition of $f$ (\kbd{f.mod} or \kbd{mfparams(f)[4]}). \bprog ? mf=mfinit([23,2],0);f=mfeigenbasis(mf)[1]; ? mfcoefs(f,5) %1 = [Mod(0, y^2 - y - 1), Mod(1, y^2 - y - 1), Mod(-y, y^2 - y - 1),\ Mod(2*y - 1, y^2 - y - 1), Mod(y - 1, y^2 - y - 1), Mod(-2*y, y^2 - y - 1)] ? mfslashexpansion(mf,f,[1,0;0,1],5,1) %2 = [0, 1, -y, 2*y - 1, y - 1, -2*y] ? mfslashexpansion(mf,f,[0,-1;1,0],5,1) %3 = [0, -1/23, 1/23*y, -2/23*y + 1/23, -1/23*y + 1/23, 2/23*y] @eprog pari-2.11.2/src/functions/modular_forms/mfbasis0000644000175000017500000000240313326135265020202 0ustar billbillFunction: mfbasis Section: modular_forms C-Name: mfbasis Prototype: GD4,L, Help: mfbasis(NK,{space=4}): If NK=[N,k,CHI] as in mfinit, gives a basis of the corresponding subspace of M_k(G_0(N),chi). NK can also be the output of mfinit, in which case space is ignored. To obtain the eigenforms use mfeigenbasis. Doc: If $NK=[N,k,\var{CHI}]$ as in \kbd{mfinit}, gives a basis of the corresponding subspace of $M_k(\Gamma_0(N),\chi)$. $NK$ can also be the output of \kbd{mfinit}, in which case \kbd{space} can be omitted. To obtain the eigenforms, use \kbd{mfeigenbasis}. If \kbd{space} is a full space $M_k$, the output is the union of first, a basis of the space of Eisenstein series, and second, a basis of the cuspidal space. \bprog ? see(L) = apply(f->mfcoefs(f,3), L); ? mf = mfinit([35,2],0); ? see( mfbasis(mf) ) %2 = [[0, 3, -1, 0], [0, -1, 9, -8], [0, 0, -8, 10]] ? see( mfeigenbasis(mf) ) %3 = [[0, 1, 0, 1], [Mod(0, z^2 - z - 4), Mod(1, z^2 - z - 4), \ Mod(-z, z^2 - z - 4), Mod(z - 1, z^2 - z - 4)]] ? mf = mfinit([35,2]); ? see( mfbasis(mf) ) %5 = [[1/6, 1, 3, 4], [1/4, 1, 3, 4], [17/12, 1, 3, 4], \ [0, 3, -1, 0], [0, -1, 9, -8], [0, 0, -8, 10]] ? see( mfbasis([48,4],0) ) %6 = [[0, 3, 0, -3], [0, -3, 0, 27], [0, 2, 0, 30]] @eprog pari-2.11.2/src/functions/modular_forms/mfbd0000644000175000017500000000061413447371554017477 0ustar billbillFunction: mfbd Section: modular_forms C-Name: mfbd Prototype: GL Help: mfbd(F,d): F being a generalized modular form, return B(d)(F), where B(d) is the expanding operator tau -> d tau. Doc: $F$ being a generalized modular form, return $B(d)(F)$, where $B(d)$ is the expanding operator $\tau\mapsto d\tau$. \bprog ? D2=mfbd(mfDelta(),2); mfcoefs(D2, 6) %1 = [0, 0, 1, 0, -24, 0, 252] @eprog pari-2.11.2/src/functions/modular_forms/mfembed0000644000175000017500000000755313447371554020177 0ustar billbillFunction: mfembed Section: modular_forms C-Name: mfembed0 Prototype: GDGp Help: mfembed(f,{v}): if v is omitted, f must be a modular form or a modular form space with parameters [N,k,chi] and we return a vector of complex embeddings of Q(f) or Q(chi), respectively. If v is given, it must be a scalar in Q(f), or a vector/matrix of such, we apply the embeddings coefficientwise and return a vector of results. Finally f can be replaced by a single embedding produced by mfembed(f) and we apply that particular embedding to v. Note that, in our context, Q(chi) has a single canonical embeding given by s: Mod(t, polcyclo(n,t)) -> exp(2*I*Pi/n) and Q(f) has [Q(f):Q(chi)] induced embeddings attached to the complex roots of s(P) where P = mfparams(f)[4], as ordered by polroots. In the latter case, we only support an f with Q(f) = Q(chi) or an eigenform produced by mfeigenbasis. Doc: let $f$ be a generalized modular form with parameters $[N,k,\chi,P]$ (see \kbd{mfparams}, we denote $\Q(\chi)$ the subfield of $\C$ generated by the values of $\chi$ and $\Q(f)$ the field of definition of $f$. In this context $\Q(\chi)$ has a single canonical complex embeding given by $s: \kbd{Mod(t, polcyclo(n,t))} \mapsto \exp(2i\pi/n)$ and the number field $\Q(f)$ has $[\Q(f):\Q(\chi)]$ induced embeddings attached to the complex roots of the polynomial $s(P)$. If $\Q(f)$ is stricly larger than $\Q(\chi)$ we only allow an $f$ which is an eigenform, produced by \kbd{mfeigenbasis}. This function is meant to create embeddings of $\Q(f)$ and/or apply them to the object $v$, typically a vector of Fourier coefficients of $f$ from \kbd{mfcoefs}. \item If $v$ is omitted and $f$ is a modular form as above, we return the embedding of $\Q(\chi)$ if $\Q(\chi) = \Q(f)$ and a vector containing $[\Q(f):\Q(\chi)]$ embeddings of $\Q(f)$ otherwise. \item If $v$ is given, it must be a scalar in $\Q(f)$, or a vector/matrix of such, we apply the embeddings coefficientwise and return either a single result if $\Q(f) = \Q(\chi)$ and a vector of $[\Q(f):\Q(\chi)]$ results otherwise. \item Finally $f$ can be replaced by a single embedding produced by \kbd{mfembed}$(f)$ ($v$ was omitted) and we apply that particular embedding to $v$. \bprog ? mf = mfinit([35,2,Mod(11,35)], 0); ? [f] = mfbasis(mf); ? f.mod \\@com $\Q(\chi) = \Q(\zeta_3)$ %3 = t^2 + t + 1 ? v = mfcoefs(f,5); lift(v) \\@com coefficients in $\Q(\chi)$ %4 = [0, 2, -2*t - 2, 2*t, 2*t, -2*t - 2] ? mfembed(f, v) \\ single embedding %5 = [0, 2, -1 - 1.7320...*I, -1 + 1.73205...*I, -1 + 1.7320...*I, ...] ? [F] = mfeigenbasis(mf); ? mffields(mf) %7 = [y^2 + Mod(-2*t, t^2 + t + 1)] \\@com $[\Q(f):\Q(\chi)] = 2$ ? V = liftpol( mfcoefs(F,5) ); %8 = [0, 1, y + (-t - 1), (t + 1)*y + t, (-2*t - 2)*y + t, -t - 1] ? vall = mfembed(F, V); #vall %9 = 2 \\ 2 embeddings, both applied to V ? vall[1] \\ the first %10 = [0, 1, -1.2071... - 2.0907...*I, 0.2071... - 0.3587...*I, ...] ? vall[2] \\ and the second one %11 = [0, 1, 0.2071... + 0.3587...*I, -1.2071... + 2.0907...*I, ...] ? vE = mfembed(F); #vE \\ same 2 embeddings %12 = 2 ? mfembed(vE[1], V) \\ apply first embedding to V %13 = [0, 1, -1.2071... - 2.0907...*I, 0.2071... - 0.3587...*I, ...] @eprog For convenience, we also allow a modular form space from \kbd{mfinit} instead of $f$, corresponding to the single embedding of $\Q(\chi)$. \bprog ? [mfB,MC,C] = mfatkininit(mf,7); MC \\@com coefs in $\Q(\chi)$ %13 = [ Mod(2/7*t, t^2 + t + 1) Mod(-1/7*t - 2/7, t^2 + t + 1)] [Mod(-1/7*t - 2/7, t^2 + t + 1) Mod(2/7*t, t^2 + t + 1)] ? C \\ normalizing constant %14 = 0.33863... - 0.16787*I ? M = mfembed(mf, MC) / C \\ the true matrix for the action of w_7 [-0.6294... + 0.4186...*I -0.3625... - 0.5450...*I] [-0.3625... - 0.5450...*I -0.6294... + 0.4186...*I] ? exponent(M*conj(M) - 1) \\ M * conj(M) is close to 1 %16 = -126 @eprog pari-2.11.2/src/functions/modular_forms/mfsturm0000644000175000017500000000131013326135265020247 0ustar billbillFunction: mfsturm Section: modular_forms C-Name: mfsturm Prototype: lG Help: mfsturm(NK): Sturm bound for modular forms on G_0(N) and weight k, i.e., an upper bound for the order of the zero at infinity of a nonzero form. NK is either [N,k] or an mfinit (exact bound in the latter case). Doc: Gives the Sturm bound for modular forms on $\Gamma_0(N)$ and weight $k$, i.e., an upper bound for the order of the zero at infinity of a nonzero form. \kbd{NK} is either \item a pair $[N,k]$, \item or the output of \tet{mfinit} in which case the exact upper bound is returned. \bprog ? NK = [96,6]; mfsturm(NK) %1 = 97 ? mf=mfinit(NK,1); mfsturm(mf) %2 = 76 ? mfdim(NK,0) \\ new space %3 = 72 @eprog pari-2.11.2/src/functions/modular_forms/mffrometaquo0000644000175000017500000000260113326135265021263 0ustar billbillFunction: mffrometaquo Section: modular_forms C-Name: mffrometaquo Prototype: GD0,L, Help: mffrometaquo(eta,{flag=0}): modular form corresponding to the eta quotient matrix eta. If the valuation v at infinity is fractional, return 0. If the eta quotient is not holomorphic but simply meromorphic, return 0 if flag=0, return the eta quotient (divided by q to the power -v if v < 0, i.e., with valuation 0) if flag is set. Doc: modular form corresponding to the eta quotient matrix \kbd{eta}. If the valuation $v$ at infinity is fractional, return $0$. If the eta quotient is not holomorphic but simply meromorphic, return $0$ if \kbd{flag=0}, return the eta quotient (divided by $q$ to the power $-v$ if $v < 0$, i.e., with valuation $0$) if flag is set. \bprog ? mffrometaquo(Mat([1,1]),1) %1 = 0 ? mfcoefs(mffrometaquo(Mat([1,24])),6) %2 = [0, 1, -24, 252, -1472, 4830, -6048] ? mfcoefs(mffrometaquo([1,1;23,1]),10) %3 = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0] ? F = mffrometaquo([1,2;2,-1]); mfparams(F) %4 = [16,1/2,1,y] ? mfcoefs(F,10) %5 = [1, -2, 0, 0, 2, 0, 0, 0, 0, -2, 0] ? mffrometaquo(Mat([1,-24])) %6 = 0 ? f = mffrometaquo(Mat([1,-24]),1); mfcoefs(f,6) %7 = [1, 24, 324, 3200, 25650, 176256, 1073720] @eprog\noindent For convenience, a \typ{VEC} is also accepted instead of a factorization matrix with a single row: \bprog ? f = mffrometaquo([1,24]); \\ also valid @eprog pari-2.11.2/src/functions/modular_forms/mfinit0000644000175000017500000000540613326135265020052 0ustar billbillFunction: mfinit Section: modular_forms C-Name: mfinit Prototype: GD4,L, Help: mfinit(NK,{space=4}): Create the space of modular forms corresponding to the data contained in NK and space. NK is a vector which can be either [N,k] (N level, k weight) corresponding to a subspace of M_k(G_0(N)), or [N,k,CHI] (CHI a character) corresponding to a subspace of M_k(G_0(N),chi). The subspace is described by a small integer 'space': 0 for the newspace, 1 for the cuspidal space, 2 for the oldspace, 3 for the space of Eisenstein series and 4 (default) for the full space M_k Doc: Create the space of modular forms corresponding to the data contained in \kbd{NK} and \kbd{space}. \kbd{NK} is a vector which can be either $[N,k]$ ($N$ level, $k$ weight) corresponding to a subspace of $M_k(\Gamma_0(N))$, or $[N,k,\var{CHI}]$ (\var{CHI} a character) corresponding to a subspace of $M_k(\Gamma_0(N),\chi)$. Alternatively, it can be a modular form $F$ or modular form space, in which case we use \kbd{mfparams} to define the space parameters. The subspace is described by the small integer \kbd{space}: $0$ for the newspace $S_k^{\text{new}}(\Gamma_0(N),\chi)$, $1$ for the cuspidal space $S_k$, $2$ for the oldspace $S_k^{\text{old}}$, $3$ for the space of Eisenstein series $E_k$ and $4$ for the full space $M_k$. \misctitle{Wildcards} For given level and weight, it is advantageous to compute simultaneously spaces attached to different Galois orbits of characters, especially in weight $1$. The parameter \var{CHI} may be set to 0 (wildcard), in which case we return a vector of all \kbd{mfinit}(s) of non trivial spaces in $S_k(\Gamma_1(N))$, one for each Galois orbit (see \kbd{znchargalois}). One may also set \var{CHI} to a vector of characters and we return a vector of all mfinits of subspaces of $M_k(G_0(N),\chi)$ for $\chi$ in the list, in the same order. In weight $1$, only $S_1^{\text{new}}$, $S_1$ and $E_1$ support wildcards. The output is a technical structure $S$, or a vector of structures if \var{CHI} was a wildcard, which contains the following information: $[N,k,\chi]$ is given by \kbd{mfparams}$(S)$, the space dimension is \kbd{mfdim}$(S)$ and a $\C$-basis for the space is \kbd{mfbasis}$(S)$. The structure is entirely algebraic and does not depend on the current \kbd{realbitprecision}. \bprog ? S = mfinit([36,2], 0); \\ new space ? mfdim(S) %2 = 1 ? mfparams %3 = [36, 2, 1, y] \\ trivial character ? f = mfbasis(S)[1]; mfcoefs(f,10) %4 = [0, 1, 0, 0, 0, 0, 0, -4, 0, 0, 0] ? vS = mfinit([36,2,0],0); \\ with wildcard ? #vS %6 = 4 \\ 4 non trivial spaces (mod Galois action) ? apply(mfdim,vS) %7 = [1, 2, 1, 4] ? mfdim([36,2,0], 0) %8 = [[1, Mod(1, 36), 1, 0], [2, Mod(35, 36), 2, 0], [3, Mod(13, 36), 1, 0], [6, Mod(11, 36), 4, 0]] @eprog pari-2.11.2/src/functions/modular_forms/mfmanin0000644000175000017500000000256013326135265020207 0ustar billbillFunction: mfmanin Section: modular_forms C-Name: mfmanin Prototype: Gb Help: mfmanin(FS): Given the modular symbol FS associated to an eigenform F by mfsymbol(mf,F), computes the even and odd special polynomials as well as the even and odd periods om+ and om- as a vector [[P+,P-],[om+,om-,r]], where r = imag(om+*conj(om-))/. If F has several embeddings into C, give the vector of results corresponding to each embedding. Doc: Given the modular symbol $FS$ associated to an eigenform $F$ by \kbd{mfsymbol(mf,F)}, computes the even and odd special polynomials as well as the even and odd periods $\omega^+$ and $\omega^-$ as a vector $[[P^+,P^-],[\omega^+,\omega^-,r]]$, where $r=\Im(\omega^+\overline{\omega^-})/$. If $F$ has several embeddings into $\C$, give the vector of results corresponding to each embedding. \bprog ? D=mfDelta(); mf=mfinit(D); DS=mfsymbol(mf,D); ? [pols,oms]=mfmanin(DS); pols %2 = [[4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x],\ [-36*x^10 + 691*x^8 - 2073*x^6 + 2073*x^4 - 691*x^2 + 36]] ? oms %3 = [0.018538552324740326472516069364750571812,\ -0.00033105361053212432521308691198949874026*I, 4096/691] ? mf=mfinit([11,2],0); F=mfeigenbasis(mf)[1]; FS=mfsymbol(mf,F); ? [pols,oms]=mfmanin(FS);pols %5 = [[0, 0, 0, 1, 1, 0, 0, -1, -1, 0, 0, 0],\ [2, 0, 10, 5, -5, -10, -10, -5, 5, 10, 0, -2]] ? oms[3] %6 = 24/5 @eprog pari-2.11.2/src/functions/modular_forms/mffromell0000644000175000017500000000155013326135265020543 0ustar billbillFunction: mffromell Section: modular_forms C-Name: mffromell Prototype: G Help: mffromell(E): E being an elliptic curve defined over Q given by an integral model in ellinit format, computes a 3-component vector [mf,F,v], where F is the newform corresponding to E by modularity, mf is the newspace to which F belongs, and v gives the coefficients of F on mfbasis(mf). Doc: $E$ being an elliptic curve defined over $Q$ given by an integral model in \kbd{ellinit} format, computes a 3-component vector \kbd{[mf,F,v]}, where $F$ is the newform corresponding to $E$ by modularity, \kbd{mf} is the newspace to which $F$ belongs, and \kbd{v} gives the coefficients of $F$ on \kbd{mfbasis(mf)}. \bprog ? E = ellinit("26a1"); ? [mf,F,co] = mffromell(E); ? co %2 = [3/4, 1/4]~ ? mfcoefs(F, 5) %3 = [0, 1, -1, 1, 1, -3] ? ellan(E, 5) %4 = [1, -1, 1, 1, -3] @eprog pari-2.11.2/src/functions/modular_forms/lfunmf0000644000175000017500000000254413326135265020053 0ustar billbillFunction: lfunmf Section: modular_forms C-Name: lfunmf Prototype: GDGb Help: lfunmf(mf,{F}): If F is a modular form in mf, output the L-functions corresponding to its complex embeddings. If F is omitted, output the L-functions corresponding to all eigenforms in the new space. Doc: If $F$ is a modular form in \kbd{mf}, output the L-functions corresponding to its $[\Q(F):\Q(\chi)]$ complex embeddings, ready for use with the \kbd{lfun} package. If $F$ is omitted, output the $L$-functions attached to all eigenforms in the new space; the result is a vector whose length is the number of Galois orbits of newforms. Each entry contains the vector of $L$-functions corresponding to the $d$ complex embeddings of an orbit of dimension $d$ over $\Q(\chi)$. \bprog ? mf = mfinit([35,2],0);mffields(mf) %1 = [y, y^2 - y - 4] ? f = mfeigenbasis(mf)[2]; mfparams(f) \\ orbit of dimension two %2 = [35, 2, 1, y^2 - y - 4] ? [L1,L2] = lfunmf(mf, f); \\ Two L-functions ? lfun(L1,1) %4 = 0.81018461849460161754947375433874745585 ? lfun(L2,1) %5 = 0.46007635204895314548435893464149369804 ? [ lfun(L,1) | L <- concat(lfunmf(mf)) ] %6 = [0.70291..., 0.81018..., 0.46007...] @eprog\noindent The \kbd{concat} instruction concatenates the vectors corresponding to the various (here two) orbits, so that we obtain the vector of all the $L$-functions attached to eigenforms. pari-2.11.2/src/functions/modular_forms/mfperiodpol0000644000175000017500000000174013326135265021101 0ustar billbillFunction: mfperiodpol Section: modular_forms C-Name: mfperiodpol Prototype: GGD0,L,b Help: mfperiodpol(mf,f,{flag=0}): period polynomial of the cuspidal part of the form f, in other words integral from 0 to ioo of (X-tau)^(k-2)f(tau). If flag=0, ordinary period polynomial, if flag=1 or -1, even or odd part of that polynomial. f can also be the modular symbol output by mfsymbol(mf,f). Doc: period polynomial of the cuspidal part of the form $f$, in other words $\int_0^{i\infty}(X-\tau)^{k-2}f(\tau)\,d\tau$. If \kbd{flag} is $0$, ordinary period polynomial. If it is $1$ or $-1$, even or odd part of that polynomial. $f$ can also be the modular symbol output by \kbd{mfsymbol}(mf,f). \bprog ? D = mfDelta(); mf = mfinit(D,0); ? PP = mfperiodpol(mf, D, -1); PP/=polcoeff(PP, 1); bestappr(PP) %1 = x^9 - 25/4*x^7 + 21/2*x^5 - 25/4*x^3 + x ? PM = mfperiodpol(mf, D, 1); PM/=polcoeff(PM, 0); bestappr(PM) %2 = -x^10 + 691/36*x^8 - 691/12*x^6 + 691/12*x^4 - 691/36*x^2 + 1 @eprog pari-2.11.2/src/functions/modular_forms/mfDelta0000644000175000017500000000042713326135265020136 0ustar billbillFunction: mfDelta Section: modular_forms C-Name: mfDelta Prototype: Help: mfDelta(): mf corresponding to the Ramanujan Delta function. Doc: mf structure corresponding to the Ramanujan Delta function $\Delta$. \bprog ? mfcoefs(mfDelta(),4) %1 = [0, 1, -24, 252, -1472] @eprog pari-2.11.2/src/functions/modular_forms/mfconductor0000644000175000017500000000101613326135265021100 0ustar billbillFunction: mfconductor Section: modular_forms C-Name: mfconductor Prototype: lGG Help: mfconductor(mf,F): mf being output by mfinit for the cuspidal space and F a modular form, gives the smallest level on which F is defined. Doc: \kbd{mf} being output by \kbd{mfinit} for the cuspidal space and $F$ a modular form, gives the smallest level on which $F$ is defined. \bprog ? mf=mfinit([96,6],1); vF = mfbasis(mf); mfdim(mf) %1 = 72 ? vector(10,i, mfconductor(mf, vF[i])) %2 = [3, 6, 12, 24, 48, 96, 4, 8, 12, 16] @eprog pari-2.11.2/src/functions/modular_forms/mfgaloistype0000644000175000017500000000262213326135265021264 0ustar billbillFunction: mfgaloistype Section: modular_forms C-Name: mfgaloistype Prototype: GDG Help: mfgaloistype(NK,{F}): NK being either [N,1,CHI] or an mf output by mfinit in weight 1 , gives the vector of types of Galois representations attached to each cuspidal eigenform, unless the eigenform F is specified, in which case only for F. Types A_4, S_4, A_5 are represented by minus their cardinality -12, -24, or -60, and type D_n is represented by its cardinality, the integer 2*n. Doc: \kbd{NK} being either \kbd{[N,1,CHI]} or an \kbd{mf} output by \kbd{mfinit} in weight $1$, gives the vector of types of Galois representations attached to each cuspidal eigenform, unless the modular form \kbd{F} is specified, in which case only for \kbd{F} (note that it is not tested whether \kbd{F} belongs to the correct modular form space, nor whether it is a cuspidal eigenform). Types $A_4$, $S_4$, $A_5$ are represented by minus their cardinality $-12$, $-24$, or $-60$, and type $D_n$ is represented by its cardinality, the integer $2n$: \bprog ? mfgaloistype([124,1, Mod(67,124)]) \\ A4 %1 = [-12] ? mfgaloistype([148,1, Mod(105,148)]) \\ S4 %2 = [-24] ? mfgaloistype([633,1, Mod(71,633)]) \\ D10, A5 %3 = [10, -60] ? mfgaloistype([239,1, -239]) \\ D6, D10, D30 %4 = [6, 10, 30] ? mfgaloistype([71,1, -71]) %5 = [14] ? mf = mfinit([239,1, -239],0); F = mfeigenbasis(mf)[2]; ? mfgaloistype(mf, F) %7 = 10 @eprog pari-2.11.2/src/functions/modular_forms/mftonew0000644000175000017500000000200413326135265020232 0ustar billbillFunction: mftonew Section: modular_forms C-Name: mftonew Prototype: GG Help: mftonew(mf,F): mf being a full or cuspidal space with parameters [N,k,chi] and F a cusp form in that space, returns a vector of 3-component vectors [M,d,G], where f(chi) divides M divides N, d divides N/M, and G is a form in S_k^new(G_0(M),chi) such that F is equal to the sum of the B(d)(G) over all these 3-component vectors. Doc: \kbd{mf} being being a full or cuspidal space with parameters $[N,k,\chi]$ and $F$ a cusp form in that space, returns a vector of 3-component vectors $[M,d,G]$, where $f(\chi)\mid M\mid N$, $d\mid N/M$, and $G$ is a form in $S_k^{\text{new}}(\Gamma_0(M),\chi)$ such that $F$ is equal to the sum of the $B(d)(G)$ over all these 3-component vectors. \bprog ? mf = mfinit([96,6],1); F = mfbasis(mf)[60]; s = mftonew(mf,F); #s %1 = 1 ? [M,d,G] = s[1]; [M,d] %2 = [48, 2] ? mfcoefs(F,10) %3 = [0, 0, -160, 0, 0, 0, 0, 0, 0, 0, -14400] ? mfcoefs(G,10) %4 = [0, 0, -160, 0, 0, 0, 0, 0, 0, 0, -14400] @eprog pari-2.11.2/src/functions/modular_forms/mfkohnenbijection0000644000175000017500000000551113326135265022255 0ustar billbillFunction: mfkohnenbijection Section: modular_forms C-Name: mfkohnenbijection Prototype: G Help: mfkohnenbijection(mf): mf being a cuspidal space of half-integral weight returns [mf2,M,K,shi], where M is a matrix giving a Hecke-module isomorphism from S_{2k-1}(N,CHI^2) given by mf2 to the Kohnen + space S_k+(4N,CHI), K is a basis of the Kohnen + space, and shi gives the linear combination of Shimura lifts giving M^(-1). Doc: \kbd{mf} being a cuspidal space of half-integral weight, returns \kbd{[mf2,M,K,shi]}, where $M$ is a matrix giving a Hecke-module isomorphism from the cuspidal space \kbd{mf2} giving $S_{2k-1}(\Gamma_0(N),\chi^2)$ to the Kohnen $+$-space $S_k^+(\Gamma_0(4N),\chi)$, \kbd{K} represents a basis $B$ of the Kohnen $+$-space as a matrix whose columns are the coefficients of $B$ on the basis of \kbd{mf}, and \kbd{shi} gives the linear combination of Shimura lifts giving $M^{-1}$. \bprog ? mf=mfinit([60,5/2],1); [mf2,M,K,shi]=mfkohnenbijection(mf); M %1 = [ -5/14 -1/14 1/2 3/2] [ 37/84 -1/84 1/2 1/2] [-17/84 5/84 -3/2 -9/2] [ 0 0 -1/2 -1/2] ? shi %2 = Vecsmall([1, 5]) @eprog This last command shows that the map giving the bijection is the sum of the Shimura lift with $D=1$ and the one with $D=5$. Since it gives a bijection of Hecke modules, this matrix can be used to transport modular form data from the easily computed space of level $N$ and weight $2k-1$ to the more difficult space of level $4N$ and weight $k$: matrices of Hecke operators, new space, splitting into eigenspaces and eigenforms. Examples: \bprog ? K^(-1)*mfheckemat(mf,121)*K /* matrix of T_11^2 on K. Slowish. */ time = 1,280 ms. %1 = [ 48 24 24 24] [ 0 32 0 -20] [-48 -72 -40 -72] [ 0 0 0 52] ? M*mfheckemat(mf2,11)*M^(-1) /* instantaneous via T_11 on S_{2k-1} */ time = 0 ms. %2 = [ 48 24 24 24] [ 0 32 0 -20] [-48 -72 -40 -72] [ 0 0 0 52] ? mf20=mfinit(mf2,0); [mftobasis(mf2,b) | b<-mfbasis(mf20)] %3 = [[0, 0, 1, 0]~, [0, 0, 0, 1]~] ? F1=M*[0,0,1,0]~ %4 = [1/2, 1/2, -3/2, -1/2]~ ? F2=M*[0,0,0,1]~ %5 = [3/2, 1/2, -9/2, -1/2] ? K*F1 %6 = [1, 0, 0, 1, 1, 0, 0, 1, -3, 0, 0, -3, 0, 0]~ ? K*F2 %7 = [3, 0, 0, 3, 1, 0, 0, 1, -9, 0, 0, -3, 0, 0]~ @eprog This gives a basis of the new space of $S_{5/2}^+(\Gamma_0(60))$ expressed on the initial basis of $S_{5/2}(\Gamma_0(60))$. If we want the eigenforms, we write instead: \bprog ? BE=mfeigenbasis(mf20);[E1,E2]=apply(x->K*M*mftobasis(mf2,x),BE) %1 = [[1, 0, 0, 1, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0]~,\ [0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -3, 0, 0]~ ? EI1 = mflinear(mf, E1); EI2=mflinear(mf, E2); @eprog\noindent These are the two eigenfunctions in the space \kbd{mf}, the first (resp., second) will have Shimura image a multiple of $BE[1]$ (resp., $BE[2]$). The function \kbd{mfkohneneigenbasis} does this directly. pari-2.11.2/src/functions/modular_forms/mfpetersson0000644000175000017500000000560613326135265021133 0ustar billbillFunction: mfpetersson Section: modular_forms C-Name: mfpetersson Prototype: GDG Help: mfpetersson(fs,{gs}): Petersson scalar product of the modular forms f and g belonging to the same modular form space mf, given by the corresponding "modular symbols" fs and gs output by mfsymbol (also in weight 1 and half-integral weight). If gs is omitted it is understood to be equal to fs. The scalar product is normalized by the factor 1/[G:G_0(N)]. Doc: Petersson scalar product of the modular forms $f$ and $g$ belonging to the same modular form space \kbd{mf}, given by the corresponding ``modular symbols'' \kbd{fs} and \kbd{gs} output by \kbd{mfsymbol} (also in weight $1$ and half-integral weight, where symbols do not exist). If \kbd{gs} is omitted it is understood to be equal to \kbd{fs}. The scalar product is normalized by the factor $1/[\Gamma:\Gamma_0(N)]$. Note that $f$ and $g$ can both be noncuspidal, in which case the program returns an error if the product is divergent. If the fields of definition $\Q(f)$ and $\Q(g)$ are equal to $\Q(\chi)$ the result is a scalar. If $[\Q(f):\Q(\chi)]=d>1$ and $[\Q(g):\Q(\chi)]=e>1$ the result is a $d\times e$ matrix corresponding to all the embeddings of $f$ and $g$. In the intermediate cases $d=1$ or $e=1$ the result is a row or column vector. \bprog ? D=mfDelta(); mf=mfinit(D); DS=mfsymbol(mf,D); mfpetersson(DS) %1 = 1.0353620568043209223478168122251645932 E-6 ? mf=mfinit([11,6],0);B=mfeigenbasis(mf);BS=vector(#B,i,mfsymbol(mf,B[i])); ? mfpetersson(BS[1]) %3 = 1.6190120685220988139111708455305245466 E-5 ? mfpetersson(BS[1],BS[2]) %4 = [-3.826479006582967148 E-42 - 2.801547395385577002 E-41*I,\ 1.6661127341163336125 E-41 + 1.1734725972345985061 E-41*I,\ 0.E-42 - 6.352626992842664490 E-41*I]~ ? mfpetersson(BS[2]) %5 = [ 2.7576133733... E-5 2.0... E-42 6.3... E-43 ] [ -4.1... E-42 6.77837030070... E-5 3.3...E-42 ] [ -6.32...E-43 3.6... E-42 2.27268958069... E-5] ? mf=mfinit([23,2],0); F=mfeigenbasis(mf)[1]; FS=mfsymbol(mf,F); ? mfpetersson(FS) %5 = [0.0039488965740025031688548076498662860143 -3.56 ... E-40] [ -3.5... E-40 0.0056442542987647835101583821368582485396] @eprog Noncuspidal example: \bprog ? E1=mfeisenstein(5,1,-3);E2=mfeisenstein(5,-3,1); ? mf=mfinit([12,5,-3]); cusps=mfcusps(12); ? apply(x->mfcuspval(mf,E1,x),cusps) %3 = [0, 0, 1, 0, 1, 1] ? apply(x->mfcuspval(mf,E2,x),cusps) %4 = [1/3, 1/3, 0, 1/3, 0, 0] ? E1S=mfsymbol(mf,E1);E2S=mfsymbol(mf,E2); ? mfpetersson(E1S,E2S) %6 = -1.884821671646... E-5 - 1.9... E-43*I @eprog Weight 1 and 1/2-integral weight example: \bprog ? mf=mfinit([23,1,-23],1);F=mfbasis(mf)[1];FS=mfsymbol(mf,F); ? mfpetersson(mf,FS) %2 = 0.035149946790370230814006345508484787443 ? mf=mfinit([4,9/2],1);F=mfbasis(mf)[1];FS=mfsymbol(mf,F); ? mfpetersson(FS) %4 = 0.00015577084407139192774373662467908966030 @eprog pari-2.11.2/src/functions/modular_forms/mfdim0000644000175000017500000000536413326135265017663 0ustar billbillFunction: mfdim Section: modular_forms C-Name: mfdim Prototype: GD4,L, Help: mfdim(NK,{space=4}): If NK=[N,k,CHI] as in mfinit, gives the dimension of the corresponding subspace of M_k(G_0(N),chi). The subspace is described by a small integer 'space': 0 for the newspace, 1 for the cuspidal space, 2 for the oldspace, 3 for the space of Eisenstein series and 4 (default) for the full space M_k. NK can also be the output of mfinit, in which case space must be omitted. Doc: If $NK=[N,k,\var{CHI}]$ as in \kbd{mfinit}, gives the dimension of the corresponding subspace of $M_k(\Gamma_0(N),\chi)$. $NK$ can also be the output of \kbd{mfinit}, in which case space must be omitted. The subspace is described by the small integer \kbd{space}: $0$ for the newspace $S_k^{\text{new}}(\Gamma_0(N),\chi)$, $1$ for the cuspidal space $S_k$, $2$ for the oldspace $S_k^{\text{old}}$, $3$ for the space of Eisenstein series $E_k$ and $4$ for the full space $M_k$. \misctitle{Wildcards} As in \kbd{mfinit}, \var{CHI} may be the wildcard 0 (all Galois orbits of characters); in this case, the output is a vector of $[\var{order}, \var{conrey}, \var{dim}, \var{dimdih}]$ corresponding to the non-trivial spaces, where \item \var{order} is the order of the character, \item \var{conrey} its Conrey label from which the character may be recovered via \kbd{znchar}$(\var{conrey})$, \item \var{dim} the dimension of the corresponding space, \item \var{dimdih} the dimension of the subspace of dihedral forms corresponding to Hecke characters if $k = 1$ (this is not implemented for the old space and set to $-1$ for the time being) and 0 otherwise. The spaces are sorted by increasing order of the character; the characters are taken up to Galois conjugation and the Conrey number is the minimal one among Galois conjugates. In weight $1$, this is only implemented when the space is 0 (newspace), 1 (cusp space), 2(old space) or 3(Eisenstein series). \misctitle{Wildcards for sets of characters} \var{CHI} may be a set of characters, and we return the set of $[\var{dim},\var{dimdih}]$. \misctitle{Wildcard for $M_k(\Gamma_1(N))$} Additionally, the wildcard $\var{CHI} = -1$ is available in which case we output the total dimension of the corresponding subspace of $M_k(\Gamma_1(N))$. In weight $1$, this is not implemented when the space is 4 (fullspace). \bprog ? mfdim([23,2], 0) \\ new space %1 = 2 ? mfdim([96,6], 0) %2 = 10 ? mfdim([10^9,4], 3) \\ Eisenstein space %1 = 40000 ? mfdim([10^9+7,4], 3) %2 = 2 ? mfdim([68,1,-1],0) %3 = 3 ? mfdim([68,1,0],0) %4 = [[2, Mod(67, 68), 1, 1], [4, Mod(47, 68), 1, 1]] ? mfdim([124,1,0],0) %5 = [[6, Mod(67, 124), 2, 0]] @eprog This last example shows that there exists a nondihedral form of weight 1 in level 124. pari-2.11.2/src/functions/modular_forms/mffromlfun0000644000175000017500000000351213326135265020733 0ustar billbillFunction: mffromlfun Section: modular_forms C-Name: mffromlfun Prototype: Gp Help: mffromlfun(L): L being an L-function representing a self-dual modular form, return [NK,space,v] where mf=mfinit(NK,space) contains the form and mftobasis(mf, v) containing it and v is mftobasis(mf,f). Doc: Let $L$ being an $L$-function in any of the \kbd{lfun} formats representing a self-dual modular form (for instance an eigenform). Return \kbd{[NK,space,v]} when \kbd{mf = mfinit(NK,space)} is the modular form space containing the form and \kbd{mftobasis(mf, v)} will represent it on the space basis. If $L$ has rational coefficients, this will be enough to recognize the modular form in \var{mf}: \bprog ? L = lfuncreate(x^2+1); ? lfunan(L,10) %2 = [1, 1, 0, 1, 2, 0, 0, 1, 1, 2] ? [NK,space,v] = mffromlfun(L); NK %4 = [4, 1, -4] ? mf=mfinit(NK,space); w = mftobasis(mf,v) %5 = [1.0000000000000000000000000000000000000]~ ? [f] = mfbasis(mf); mfcoefs(f,10) \\ includes a_0 ! %6 = [1/4, 1, 1, 0, 1, 2, 0, 0, 1, 1, 2] @eprog If $L$ has inexact complex coefficients, one can for instance compute an eigenbasis for \var{mf} and check whether one of the attached $L$-function is reasonably close to $L$. In the example, we cheat by producing the $L$ function from an eigenform in a known space, but the function does not use this information: \bprog ? mf = mfinit([32,6,Mod(5,32)],0); ? [poldegree(K) | K<-mffields(mf)] %2 = [19] \\ one orbit, [Q(F) : Q(chi)] = 19 ? L = lfunmf(mf)[1][1]; \\ one of the 19 L-functions attached to F ? lfunan(L,3) %4 = [1, 5.654... - 0.1812...*I, -7.876... - 19.02...*I] ? [NK,space,v] = mffromlfun(L); NK %5 = [32, 6, Mod(5, 32)] ? vL = concat(lfunmf(mf)); \\ L functions for all cuspidal eigenforms ? an = lfunan(L,10); ? for (i = 1, #vL, if (normlp(lfunan(vL[i],10) - an, oo) < 1e-10, print(i))); 1 @eprog pari-2.11.2/src/functions/modular_forms/mffields0000644000175000017500000000216413447371554020362 0ustar billbillFunction: mffields Section: modular_forms C-Name: mffields Prototype: G Help: mffields(mf): If mf is output by mfinit, gives the vector of polynomials defining each Galois orbit of the new space. Doc: Given \kbd{mf} as output by \kbd{mfinit} with parameters $(N,k,\chi)$, returns the vector of polynomials defining each Galois orbit of newforms over $\Q(\chi)$. \bprog ? mf = mfinit([35,2],0); mffields(mf) %1 = [y, y^2 - y - 4] @eprog\noindent Here the character is trivial so $\Q(\chi) = \Q)$ and there are 3 newforms: one is rational (corresponding to $y$), the other two are conjugate and defined over the quadratic field $\Q[y]/(y^2-y-4)$. \bprog ? [G,chi] = znchar(Mod(3,35)); ? zncharconductor(G,chi) %2 = 35 ? charorder(G,chi) %3 = 12 ? mf = mfinit([35, 2, [G,chi]],0); mffields(mf) %4 = [y, y] @eprog Here the character is primitive of order 12 and the two newforms are defined over $\Q(\chi) = \Q(\zeta_{12})$. \bprog ? mf = mfinit([35, 2, Mod(13,35)],0); mffields(mf) %3 = [y^2 + Mod(5*t, t^2 + 1)] @eprog This time the character has order 4 and there are two conjugate newforms over $\Q(\chi) = Q(i)$. pari-2.11.2/src/functions/modular_forms/mftaylor0000644000175000017500000000155313326135265020420 0ustar billbillFunction: mftaylor Section: modular_forms C-Name: mftaylor Prototype: GLD0,L,p Help: mftaylor(F,n,{flreal=0}): F being a modular form in M_k(SL_2(Z)), computes the first n+1 canonical Taylor expansion of F around tau=I. If flreal=0, computes only an algebraic equivalence class. If flreal is set, compute p_n such that for tau close enough to I we have f(tau)=(2I/(tau+I))^ksum_{n>=0}p_n((tau-I)/(tau+I))^n. Doc: $F$ being a form in $M_k(SL_2(\Bbb Z))$, computes the first $n+1$ canonical Taylor expansion of $F$ around $\tau=I$. If \kbd{flreal=0}, computes only an algebraic equivalence class. If \kbd{flreal} is set, compute $p_n$ such that for $\tau$ close enough to $I$ we have $$f(\tau)=(2I/(\tau+I))^k\sum_{n>=0}p_n((\tau-I)/(\tau+I))^n\;.$$ \bprog ? D=mfDelta(); ? mftaylor(D,8) %2 = [1/1728, 0, -1/20736, 0, 1/165888, 0, 1/497664, 0, -11/3981312] @eprog pari-2.11.2/src/functions/modular_forms/mfcoefs0000644000175000017500000000166513447371554020220 0ustar billbillFunction: mfcoefs Section: modular_forms C-Name: mfcoefs Prototype: GLD1,L, Help: mfcoefs(F,n,{d = 1}): Compute the vector of coefficients [a[0],a[d],...,a[nd]] of the modular form F. Doc: Compute the vector of Fourier coefficients $[a[0],a[d],...,a[nd]]$ of the generalized modular form $F$; $d$ must be positive and $d = 1$ by default. \bprog ? D = mfDelta(); ? mfcoefs(D,10) %2 = [0, 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920] ? mfcoefs(D,5,2) %3 = [0, -24, -1472, -6048, 84480, -115920] ? mfcoef(D,10) %4 = -115920 @eprog\noindent This function also applies when $F$ is a modular form space as output by \kbd{mfinit}; it then returns the matrix whose columns give the Fourier expansions of the elements of \kbd{mfbasis}$(F)$: \bprog ? mf = mfinit([1,12]); ? mfcoefs(mf,5) %2 = [691/65520 0] [ 1 1] [ 2049 -24] [ 177148 252] [ 4196353 -1472] [ 48828126 4830] @eprog pari-2.11.2/src/functions/modular_forms/mflinear0000644000175000017500000000330113447371554020360 0ustar billbillFunction: mflinear Section: modular_forms C-Name: mflinear Prototype: GG Help: mflinear(vF,v): vF being a vector of modular forms and v a vector of coefficients of same length, compute the linear combination of the entries of vF with coefficients v. Doc: \kbd{vF} being a vector of generalized modular forms and \kbd{v} a vector of coefficients of same length, compute the linear combination of the entries of \kbd{vF} with coefficients \kbd{v}. \misctitle{Note} Use this in particular to subtract two forms $F$ and $G$ (with $vF=[F,G]$ and $v=[1,-1]$), or to multiply an form by a scalar $\lambda$ (with $vF=[F]$ and $v=[\lambda]$). \bprog ? D = mfDelta(); G = mflinear([D],[-3]); ? mfcoefs(G,4) %2 = [0, -3, 72, -756, 4416] @eprog For user convenience, we allow \item a modular form space \kbd{mf} as a \kbd{vF} argument, which is understood as \kbd{mfbasis(mf)}; \item in this case, we also allow a modular form $f$ as $v$, which is understood as \kbd{mftobasis}$(\var{mf}, f)$. \bprog ? T = mfpow(mfTheta(),7); F = mfShimura(T,-3); \\ Shimura lift for D=-3 ? mfcoefs(F,8) %2 = [-5/9, 280, 9240, 68320, 295960, 875280, 2254560, 4706240, 9471000] ? mf = mfinit(F); G = mflinear(mf,F); ? mfcoefs(G,8) %4 = [-5/9, 280, 9240, 68320, 295960, 875280, 2254560, 4706240, 9471000] @eprog\noindent This last construction allows to replace a general modular form by a simpler linear combination of basis functions, which is often more efficient: \bprog ? T10=mfpow(mfTheta(),10); mfcoef(T10, 10^4) \\ direct evaluation time = 399 ms. %5 = 128205250571893636 ? mf=mfinit(T10); F=mflinear(mf,T10); \\ instantaneous ? mfcoef(F, 10^4) \\ after linearization time = 67 ms. %7 = 128205250571893636 @eprog pari-2.11.2/src/functions/modular_forms/mfcuspwidth0000644000175000017500000000070513326135265021116 0ustar billbillFunction: mfcuspwidth Section: modular_forms C-Name: mfcuspwidth Prototype: lGG Help: mfcuspwidth(N, cusp): width of cusp in Gamma_0(N), N being either an integer or a modular form space. Doc: width of \kbd{cusp} in $\Gamma_0(N)$, $N$ being either an integer or a modular form space. \bprog ? mfcusps(12) %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/12] ? [mfcuspwidth(12,c) | c <- mfcusps(12)] %2 = [12, 3, 4, 3, 1, 1] ? mfcuspwidth(12, oo) %3 = 1 @eprog pari-2.11.2/src/functions/modular_forms/mftobasis0000644000175000017500000000561413326135265020554 0ustar billbillFunction: mftobasis Section: modular_forms C-Name: mftobasis Prototype: GGD0,L, Help: mftobasis(mf,F,{flag=0}): coefficients of the form F on the basis given by the mfbasis(mf). A q-expansion or vector of coefficients can also be given instead of F, but in this case an error message may occur if the expansion is too short. An error message is also given if F does not belong to the modular form space. If flag is set, instead of error messages return an output as an affine space of solutions if a q-expansion or vector of coefficients is given, or the empty column otherwise. Doc: coefficients of the form $F$ on the basis given by \kbd{mfbasis(mf)}. A $q$-expansion or vector of coefficients can also be given instead of $F$, but in this case an error message may occur if the expansion is too short. An error message is also given if $F$ does not belong to the modular form space. If \kbd{flag} is set, instead of error messages the output is an affine space of solutions if a $q$-expansion or vector of coefficients is given, or the empty column otherwise. \bprog ? mf = mfinit([26,2],0); mfdim(mf) %1 = 2 ? F = mflinear(mf,[a,b]); mftobasis(mf,F) %2 = [a, b]~ @eprog A $q$-expansion or vector of coefficients can also be given instead of $F$. \bprog ? Th = 1 + 2*sum(n=1, 8, q^(n^2), O(q^80)); ? mf = mfinit([4,5,Mod(3,4)]); ? mftobasis(mf, Th^10) %3 = [64/5, 4/5, 32/5]~ @eprog If $F$ does not belong to the corresponding space, the result is incorrect and simply matches the coefficients of $F$ up to some bound, and the function may either return an empty column or an error message. If \kbd{flag} is set, there are no error messages, and the result is an empty column if $F$ is a modular form; if $F$ is supplied via a series or vector of coefficients which does not contain enough information to force a unique (potential) solution, the function returns $[v,K]$ where $v$ is a solution and $K$ is a matrix of maximal rank describing the affine space of potential solutions $v + K\cdot x$. \bprog ? mf = mfinit([4,12],1); ? mftobasis(mf, q-24*q^2+O(q^3), 1) %2 = [[43/64, -63/8, 800, 21/64]~, [1, 0; 24, 0; 2048, 768; -1, 0]] ? mftobasis(mf, [0,1,-24,252], 1) %3 = [[1, 0, 1472, 0]~, [0; 0; 768; 0]] ? mftobasis(mf, [0,1,-24,252,-1472], 1) %4 = [1, 0, 0, 0]~ \\ now uniquely determined ? mftobasis(mf, [0,1,-24,252,-1472,0], 1) %5 = [1, 0, 0, 0]~ \\ wrong result: no such form exists ? mfcoefs(mflinear(mf,%), 5) \\ double check %6 = [0, 1, -24, 252, -1472, 4830] ? mftobasis(mf, [0,1,-24,252,-1472,0]) *** at top-level: mftobasis(mf,[0,1, *** ^-------------------- *** mftobasis: domain error in mftobasis: form does not belong to space ? mftobasis(mf, mfEk(10)) *** at top-level: mftobasis(mf,mfEk( *** ^-------------------- *** mftobasis: domain error in mftobasis: form does not belong to space ? mftobasis(mf, mfEk(10), 1) %7 = []~ @eprog pari-2.11.2/src/functions/modular_forms/mfcosets0000644000175000017500000000150313326135265020401 0ustar billbillFunction: mfcosets Section: modular_forms C-Name: mfcosets Prototype: G Help: mfcosets(N): list of right cosets of G_0(N)\G, i.e., matrices ga_j in G such that G=U G_0(N)ga_j. The ga_j are chosen in the form [a,b;c,d] with c\mid N. N can be either a positive integer or a modular form space. Doc: list of right cosets of $\Gamma_0(N) \bs \Gamma$, i.e., matrices $\gamma_j \in \Gamma$ such that $\Gamma = \bigsqcup_j \Gamma_0(N) \gamma_j$. The $\gamma_j$ are chosen in the form $[a,b;c,d]$ with $c\mid N$. $N$ can be either a positive integer or a modular form space. \bprog ? mfcosets(4) %1 = [[0, -1; 1, 0], [1, 0; 1, 1], [0, -1; 1, 2], [0, -1; 1, 3],\ [1, 0; 2, 1], [1, 0; 4, 1]] @eprog \misctitle{Warning} in the present implementation, the trivial coset is represented by $[1,0;N,1]$ and is the last in the list. pari-2.11.2/src/functions/symbolic_operators/0000755000175000017500000000000013461316051017674 5ustar billbillpari-2.11.2/src/functions/symbolic_operators/range0000644000175000017500000000030312314242551020706 0ustar billbillFunction: [_.._] Section: programming/internals C-Name: vecrange Prototype: GG Help: [a..b] = [a,a+1,...,b] Description: (gen,gen):vec vecrange($1, $2) (small,small):vec vecrangess($1, $2) pari-2.11.2/src/functions/symbolic_operators/pow0000644000175000017500000000304313201017466020424 0ustar billbillFunction: _^_ Help: x^y: compute x to the power y. Section: symbolic_operators C-Name: gpow Prototype: GGp Description: (int, 2):int sqri($1) (int, 3):int powiu($1, 3) (int, 4):int powiu($1, 4) (int, 5):int powiu($1, 5) (real, -1):real invr($1) (mp, -1):mp ginv($1) (gen, -1):gen ginv($1) (real, 2):real sqrr($1) (mp, 2):mp mpsqr($1) (gen, 2):gen gsqr($1) (int, small):gen powis($1, $2) (real, small):real gpowgs($1, $2) (gen, small):gen gpowgs($1, $2) (real, int):real powgi($1, $2) (gen, int):gen powgi($1, $2) (gen, gen):gen:prec gpow($1, $2, $prec) (Fp, 2):Fp Fp_sqr($1, p) (Fp, usmall):Fp Fp_powu($1, $2, p) (Fp, small):Fp Fp_pows($1, $2, p) (Fp, int):Fp Fp_pow($1, $2, p) (FpX, 2):FpX FpX_sqr($1, p) (FpX, usmall):FpX FpX_powu($1, $2, p) (Fq, 2):Fq Fq_sqr($1, T, p) (Fq, usmall):Fq Fq_powu($1, $2, T, p) (Fq, int):Fq Fq_pow($1, $2, T, p) (Fq, 2):Fq Fq_sqr($1, T, p) (Fq, usmall):Fq Fq_powu($1, $2, T, p) (Fq, int):Fq Fq_pow($1, $2, T, p) (FqX, 2):FqX FqX_sqr($1, T, p) (FqX, usmall):FqX FqX_powu($1, $2, T, p) Function: _^s Help: return x^n where n is a small integer Section: programming/internals C-Name: gpowgs Prototype: GL pari-2.11.2/src/functions/symbolic_operators/not0000644000175000017500000000030413326135265020422 0ustar billbillFunction: !_ Help: !a: boolean operator "not". Section: symbolic_operators C-Name: gnot Prototype: G Description: (negbool):bool:parens $1 (bool):negbool:parens $1 pari-2.11.2/src/functions/symbolic_operators/mm0000644000175000017500000000102313326135265020232 0ustar billbillFunction: _-- Section: symbolic_operators C-Name: gsub1e Prototype: & Help: x--: set x to x-1. Description: (*bptr):bptr --$1 (*small):small --$1 (*lg):lg --$1 (*int):int:parens $1 = subis($1, 1) (*real):real:parens $1 = subrs($1, 1) (*mp):mp:parens $1 = mpsub($1, gen_1) (*pol):pol:parens $1 = gsubgs($1, 1) (*gen):gen:parens $1 = gsubgs($1, 1) pari-2.11.2/src/functions/symbolic_operators/divrounde0000644000175000017500000000052111636712103021614 0ustar billbillFunction: _\/=_ Section: symbolic_operators C-Name: gdivrounde Prototype: &G Help: x\/=y: shortcut for x=x\/y. Description: (*int, int):int:parens $1 = gdivround($1, $2) (*pol, gen):gen:parens $1 = gdivround($1, $2) (*gen, gen):gen:parens $1 = gdivround($1, $2) pari-2.11.2/src/functions/symbolic_operators/neg0000644000175000017500000000065213326135265020401 0ustar billbillFunction: -_ Help: -_: negate argument Section: symbolic_operators C-Name: gneg Prototype: G Description: (small):small:parens -$(1) (int):int negi($1) (real):real negr($1) (mp):mp mpneg($1) (gen):gen gneg($1) (Fp):Fp Fp_neg($1, p) (FpX):FpX FpX_neg($1, p) (Fq):Fq Fq_neg($1, T, p) (FqX):FqX FqX_neg($1, T, p) pari-2.11.2/src/functions/symbolic_operators/divent0000644000175000017500000000102211636712103021103 0ustar billbillFunction: _\_ Section: symbolic_operators C-Name: gdivent Help: x\y: Euclidean quotient of x and y. Prototype: GG Description: (small, small):small:parens $(1)/$(2) (int, small):int truedivis($1, $2) (small, int):int gdiventsg($1, $2) (int, int):int truedivii($1, $2) (gen, small):gen gdiventgs($1, $2) (small, gen):gen gdiventsg($1, $2) (gen, gen):gen gdivent($1, $2) pari-2.11.2/src/functions/symbolic_operators/shiftr0000644000175000017500000000050213326135265021121 0ustar billbillFunction: _>>_ Section: symbolic_operators C-Name: gshift_right Prototype: GL Help: x>>y: compute shift(x,-y). Description: (small, small):small:parens $(1)>>$(2) (int, small):int shifti($1, -$(2)) (mp, small):mp mpshift($1, -$(2)) (gen, small):mp gshift($1, -$(2)) pari-2.11.2/src/functions/symbolic_operators/call0000644000175000017500000000047013326135265020541 0ustar billbillFunction: _(_) Section: symbolic_operators Help: f(a,b,...): evaluate the function f on a,b,... Description: (gen):gen closure_callgenall($1, 0) (gen,gen):gen closure_callgen1($1, $2) (gen,gen,gen):gen closure_callgen2($1, $2, $3) (gen,gen,...):gen closure_callgenall($1, ${nbarg 1 sub}, $3) pari-2.11.2/src/functions/symbolic_operators/shiftre0000644000175000017500000000056411636712103021270 0ustar billbillFunction: _>>=_ Section: symbolic_operators C-Name: gshiftre Prototype: &L Help: x>>=y: shortcut for x=x>>y. Description: (*small, small):small:parens $1 >>= $(2) (*int, small):int:parens $1 = shifti($1, -$(2)) (*mp, small):mp:parens $1 = mpshift($1, -$(2)) (*gen, small):mp:parens $1 = gshift($1, -$(2)) pari-2.11.2/src/functions/symbolic_operators/coeff0000644000175000017500000000222113214322064020673 0ustar billbillFunction: _[_,_] Section: symbolic_operators Help: x[i{,j}]: i coefficient of a vector, i,j coefficient of a matrix Description: (mp,small):gen $"Scalar has no components" (mp,small,small):gen $"Scalar has no components" (vecsmall,small):small $(1)[$2] (vecsmall,small,small):gen $"Vecsmall are single-dimensional" (list,small):gen:copy gel(list_data($1), $2) (vec,small):gen:copy gel($1, $2) (vec,small,small):gen:copy gcoeff($1, $2, $3) (gen,small):gen:copy gel($1, $2) (gen,small,small):gen:copy gcoeff($1, $2, $3) Function: _safecoeff Section: symbolic_operators Help: safe version of x[a], x[,a] and x[a,b]. Must be lvalues. Description: (vecsmall,small):small *safeel($1, $2) (list,small):gen:copy *safelistel($1, $2) (gen,small):gen:copy *safegel($1, $2) (gen,small,small):gen:copy *safegcoeff($1, $2, $3) Function: _[_,] Section: symbolic_operators Help: x[y,]: y-th row of x. Description: (mp,small):gen $"Scalar has no rows" (vec,small):vec rowcopy($1, $2) (gen,small):vec rowcopy($1, $2) pari-2.11.2/src/functions/symbolic_operators/add0000644000175000017500000000240613201017466020351 0ustar billbillFunction: _+_ Section: symbolic_operators C-Name: gadd Prototype: GG Help: x+y: sum of x and y. Description: (lg, 1):small:parens $(1) (small, small):small:parens $(1) + $(2) (lg, small):lg:parens $(1) + $(2) (small, lg):lg:parens $(1) + $(2) (int, small):int addis($1, $2) (small, int):int addsi($1, $2) (int, int):int addii($1, $2) (real, small):real addrs($1, $2) (small, real):real addsr($1, $2) (real, real):real addrr($1, $2) (mp, real):real mpadd($1, $2) (real, mp):real mpadd($1, $2) (mp, mp):mp mpadd($1, $2) (gen, small):gen gaddgs($1, $2) (small, gen):gen gaddsg($1, $2) (gen, gen):gen gadd($1, $2) (Fp, Fp):Fp Fp_add($1, $2, p) (FpX, Fp):FpX FpX_Fp_add($1, $2, p) (Fp, FpX):FpX FpX_Fp_add($2, $1, p) (FpX, FpX):FpX FpX_add($1, $2, p) (Fq, Fq):Fq Fq_add($1, $2, T, p) (FqX, Fq):FqX FqX_Fq_add($1, $2, T, p) (Fq, FqX):FqX FqX_Fq_add($2, $1, T, p) (FqX, FqX):FqX FqX_add($1, $2, T, p) pari-2.11.2/src/functions/symbolic_operators/mod0000644000175000017500000000106613201017466020401 0ustar billbillFunction: _%_ Section: symbolic_operators C-Name: gmod Prototype: GG Help: x%y: Euclidean remainder of x and y. Description: (small, small):small smodss($1, $2) (small, int):int modsi($1, $2) (int, small):small smodis($1, $2) (int, int):int modii($1, $2) (gen, small):gen gmodgs($1, $2) (small, gen):gen gmodsg($1, $2) (gen, gen):gen gmod($1, $2) (FpX,FpX):FpX FpX_rem($1, $2, p) (FqX,FqX):FqX FqX_rem($1, $2, T, p) pari-2.11.2/src/functions/symbolic_operators/le0000644000175000017500000000151612314242551020221 0ustar billbillFunction: _<=_ Help: x<=y: return 1 if x is less or equal to y, 0 otherwise. Section: symbolic_operators C-Name: gle Prototype: GG Description: (small, small):bool:parens $(1) <= $(2) (small, lg):bool:parens $(1) < $(2) (lg, lg):bool:parens $(1) <= $(2) (small, int):bool:parens cmpsi($1, $2) <= 0 (int, lg):bool:parens cmpis($1, $2) < 0 (int, small):bool:parens cmpis($1, $2) <= 0 (int, int):bool:parens cmpii($1, $2) <= 0 (mp, mp):bool:parens mpcmp($1, $2) <= 0 (str, str):bool:parens strcmp($1, $2) <= 0 (small, gen):bool:parens gcmpsg($1, $2) <= 0 (gen, small):bool:parens gcmpgs($1, $2) <= 0 (gen, gen):bool:parens gcmp($1, $2) <= 0 pari-2.11.2/src/functions/symbolic_operators/pound0000644000175000017500000000042411636712103020744 0ustar billbillFunction: #_ Section: symbolic_operators C-Name: glength Prototype: lG Help: #x: number of non code words in x, number of characters for a string. Description: (vecsmall):lg lg($1) (vec):lg lg($1) (pol):small lgpol($1) (gen):small glength($1) pari-2.11.2/src/functions/symbolic_operators/fact0000644000175000017500000000023311636712103020532 0ustar billbillFunction: _! Section: symbolic_operators C-Name: mpfact Prototype: L Help: n!: factorial of n. Description: (small):int mpfact($1) pari-2.11.2/src/functions/symbolic_operators/lt0000644000175000017500000000141212314242551020233 0ustar billbillFunction: _<_ Help: x_ Help: x>y: return 1 if x is strictly greater than y, 0 otherwise. Section: symbolic_operators C-Name: ggt Prototype: GG Description: (small, small):bool:parens $(1) > $(2) (lg, lg):bool:parens $(1) > $(2) (small, lg):bool:parens $(1) >= $(2) (small, int):bool:parens cmpsi($1, $2) > 0 (int, small):bool:parens cmpis($1, $2) > 0 (int, int):bool:parens cmpii($1, $2) > 0 (mp, mp):bool:parens mpcmp($1, $2) > 0 (str, str):bool:parens strcmp($1, $2) > 0 (small, gen):bool:parens gcmpsg($1, $2) > 0 (gen, small):bool:parens gcmpgs($1, $2) > 0 (gen, gen):bool:parens gcmp($1, $2) > 0 pari-2.11.2/src/functions/symbolic_operators/concat0000644000175000017500000000051213326135265021072 0ustar billbillFunction: __ Help: __: integral concatenation of strings. Section: symbolic_operators Description: (genstr, genstr):genstr gconcat($1, $2) (genstr, gen):genstr gconcat($1, $2) (gen, genstr):genstr gconcat($1, $2) (gen, gen):genstr gconcat($genstr:1, $2) pari-2.11.2/src/functions/symbolic_operators/ne0000644000175000017500000000225013326135265020226 0ustar billbillFunction: _!=_ Help: a!=b: true if a and b are not equal. Section: symbolic_operators C-Name: gne Prototype: GG Description: (small, small):bool:parens $(1) != $(2) (lg, lg):bool:parens $(1) != $(2) (small, int):bool:parens cmpsi($1, $2) != 0 (int, small):bool:parens cmpis($1, $2) != 0 (int, 1):negbool equali1($1) (int, -1):negbool equalim1($1) (int, int):negbool equalii($1, $2) (real,real):bool cmprr($1, $2) != 0 (mp, mp):bool:parens mpcmp($1, $2) != 0 (errtyp, errtyp):bool:parens $(1) != $(2) (errtyp, #str):bool:parens $(1) != $(errtyp:2) (#str, errtyp):bool:parens $(errtyp:1) != $(2) (typ, typ):bool:parens $(1) != $(2) (typ, #str):bool:parens $(1) != $(typ:2) (#str, typ):bool:parens $(typ:1) != $(2) (str, str):bool strcmp($1, $2) (small, gen):negbool gequalsg($1, $2) (gen, small):negbool gequalgs($1, $2) (gen, gen):negbool gequal($1, $2) pari-2.11.2/src/functions/symbolic_operators/slice0000644000175000017500000000067012314242551020720 0ustar billbillFunction: _[_.._] Section: symbolic_operators C-Name: vecslice0 Prototype: GD0,L,L Help: x[a..b] = [x[a],x[a+1],...,x[b]] Function: _[_.._,_.._] Section: symbolic_operators C-Name: matslice0 Prototype: GD0,L,D0,L,D0,L,D0,L, Help: x[a..b,c..d] = [x[a,c], x[a+1,c], ...,x[b,c]; x[a,c+1],x[a+1,c+1],...,x[b,c+1]; ... ... ... x[a,d], x[a+1,d] ,...,x[b,d]] pari-2.11.2/src/functions/symbolic_operators/deriv0000644000175000017500000000044313201017466020731 0ustar billbillFunction: _' Section: symbolic_operators C-Name: deriv Prototype: GDn Help: x': derivative of x with respect to the main variable. Description: (gen):gen deriv($1,-1) (FpX):FpX FpX_deriv($1, p) (FqX):FqX FqX_deriv($1, T, p) pari-2.11.2/src/functions/symbolic_operators/mule0000644000175000017500000000150711636712103020564 0ustar billbillFunction: _*=_ Section: symbolic_operators C-Name: gmule Prototype: &G Help: x*=y: shortcut for x=x*y. Description: (*small, small):small:parens $1 *= $(2) (*int, small):int:parens $1 = mulis($1, $2) (*int, int):int:parens $1 = mulii($1, $2) (*real, small):real:parens $1 = mulrs($1, $2) (*real, int):real:parens $1 = mulri($1, $2) (*real, real):real:parens $1 = mulrr($1, $2) (*mp, mp):mp:parens $1 = mpmul($1, $2) (*pol, small):gen:parens $1 = gmulgs($1, $2) (*pol, gen):gen:parens $1 = gmul($1, $2) (*vec, gen):gen:parens $1 = gmul($1, $2) (*gen, small):gen:parens $1 = gmulgs($1, $2) (*gen, gen):gen:parens $1 = gmul($1, $2) pari-2.11.2/src/functions/symbolic_operators/ge0000644000175000017500000000142612314242551020214 0ustar billbillFunction: _>=_ Help: x>=y: return 1 if x is greater or equal to y, 0 otherwise. Section: symbolic_operators C-Name: gge Prototype: GG Description: (small, small):bool:parens $(1) >= $(2) (lg, lg):bool:parens $(1) >= $(2) (lg, small):bool:parens $(1) > $(2) (small, int):bool:parens cmpsi($1, $2) >= 0 (int, small):bool:parens cmpis($1, $2) >= 0 (int, int):bool:parens cmpii($1, $2) >= 0 (mp, mp):bool:parens mpcmp($1, $2) >= 0 (str, str):bool:parens strcmp($1, $2) >= 0 (small, gen):bool:parens gcmpsg($1, $2) >= 0 (gen, small):bool:parens gcmpgs($1, $2) >= 0 (gen, gen):bool:parens gcmp($1, $2) >= 0 pari-2.11.2/src/functions/symbolic_operators/adde0000644000175000017500000000157411636712103020523 0ustar billbillFunction: _+=_ C-Name: gadde Prototype: &G Help: x+=y: shortcut for x=x+y. Section: symbolic_operators Description: (*small, small):small:parens $1 += $(2) (*lg, small):lg:parens $1 += $(2) (*int, small):int:parens $1 = addis($1, $2) (*int, int):int:parens $1 = addii($1, $2) (*real, small):real:parens $1 = addrs($1, $2) (*real, int):real:parens $1 = addir($2, $1) (*real, real):real:parens $1 = addrr($1, $2) (*mp, mp):mp:parens $1 = mpadd($1, $2) (*pol, small):gen:parens $1 = gaddgs($1, $2) (*pol, gen):gen:parens $1 = gadd($1, $2) (*vec, gen):gen:parens $1 = gadd($1, $2) (*gen, small):gen:parens $1 = gaddgs($1, $2) (*gen, gen):gen:parens $1 = gadd($1, $2) pari-2.11.2/src/functions/symbolic_operators/divente0000644000175000017500000000060111636712103021252 0ustar billbillFunction: _\=_ Section: symbolic_operators C-Name: gdivente Prototype: &G Help: x\=y: shortcut for x=x\y. Description: (*small, small):small:parens $1 /= $(2) (*int, int):int:parens $1 = gdivent($1, $2) (*pol, gen):gen:parens $1 = gdivent($1, $2) (*gen, gen):gen:parens $1 = gdivent($1, $2) pari-2.11.2/src/functions/symbolic_operators/pp0000644000175000017500000000104313326135265020242 0ustar billbillFunction: _++ C-Name: gadd1e Prototype: & Section: symbolic_operators Help: x++: set x to x+1. Description: (*bptr):bptr ++$1 (*small):small ++$1 (*lg):lg ++$1 (*int):int:parens $1 = addis($1, 1) (*real):real:parens $1 = addrs($1, 1) (*mp):mp:parens $1 = mpadd($1, gen_1) (*pol):pol:parens $1 = gaddgs($1, 1) (*gen):gen:parens $1 = gaddgs($1, 1) pari-2.11.2/src/functions/symbolic_operators/or0000644000175000017500000000027113326135265020245 0ustar billbillFunction: _||_ C-Name: orpari Prototype: GE Help: a||b: boolean operator "or" (inclusive). Section: symbolic_operators Description: (bool, bool):bool:parens $(1) || $(2) pari-2.11.2/src/functions/symbolic_operators/divround0000644000175000017500000000037511636712103021456 0ustar billbillFunction: _\/_ Help: x\/y: rounded Euclidean quotient of x and y. Section: symbolic_operators C-Name: gdivround Prototype: GG Description: (int, int):int gdivround($1, $2) (gen, gen):gen gdivround($1, $2) pari-2.11.2/src/functions/symbolic_operators/sub0000644000175000017500000000220013326135265020410 0ustar billbillFunction: _-_ Section: symbolic_operators C-Name: gsub Prototype: GG Help: x-y: difference of x and y. Description: (small, small):small:parens $(1) - $(2) (lg, small):lg:parens $(1) - $(2) (int, small):int subis($1, $2) (small, int):int subsi($1, $2) (int, int):int subii($1, $2) (real, small):real subrs($1, $2) (small, real):real subsr($1, $2) (real, real):real subrr($1, $2) (mp, real):real mpsub($1, $2) (real, mp):real mpsub($1, $2) (mp, mp):mp mpsub($1, $2) (gen, small):gen gsubgs($1, $2) (small, gen):gen gsubsg($1, $2) (gen, gen):gen gsub($1, $2) (Fp, Fp):Fp Fp_sub($1, $2, p) (Fp, FpX):FpX Fp_FpX_sub($1, $2, p) (FpX, Fp):FpX FpX_Fp_sub($1, $2, p) (FpX, FpX):FpX FpX_sub($1, $2, p) (Fq, Fq):Fq Fq_sub($1, $2, T, p) (FqX, Fq):FqX FqX_Fq_sub($1, $2, T, p) (FqX, FqX):FqX FqX_sub($1, $2, T, p) pari-2.11.2/src/functions/symbolic_operators/shiftle0000644000175000017500000000055311636712103021260 0ustar billbillFunction: _<<=_ Section: symbolic_operators C-Name: gshiftle Prototype: &L Help: x<<=y: shortcut for x=x<=0 or n<0). Doc: multiplies $x$ by $2^n$. The difference with \kbd{shift} is that when $n<0$, ordinary division takes place, hence for example if $x$ is an integer the result may be a fraction, while for shifts Euclidean division takes place when $n<0$ hence if $x$ is an integer the result is still an integer. pari-2.11.2/src/functions/operators/lex0000644000175000017500000000155313201017466016512 0ustar billbillFunction: lex Section: operators C-Name: lexcmp Prototype: iGG Help: lex(x,y): compare x and y lexicographically (1 if x>y, 0 if x=y, -1 if x$ vector $>$ scalar. For example: \bprog ? lex([1,3], [1,2,5]) %1 = 1 ? lex([1,3], [1,3,-1]) %2 = -1 ? lex([1], [[1]]) %3 = -1 ? lex([1], [1]~) %4 = 0 @eprog pari-2.11.2/src/functions/operators/vecmin0000644000175000017500000000161113201017466017176 0ustar billbillFunction: vecmin Section: operators C-Name: vecmin0 Prototype: GD& Help: vecmin(x,{&v}): smallest entry in the vector/matrix x. If v is present, set it to the index of a smallest entry (indirect min). Description: (gen):gen vecmin($1) (gen, &gen):gen vecmin0($1, &$2) Doc: if $x$ is a vector or a matrix, returns the smallest entry of $x$, otherwise returns a copy of $x$. Error if $x$ is empty. If $v$ is given, set it to the index of a smallest entry (indirect minimum), when $x$ is a vector. If $x$ is a matrix, set $v$ to coordinates $[i,j]$ such that $x[i,j]$ is a smallest entry. This is ignored if $x$ is not a vector or matrix. \bprog ? vecmin([10, 20, -30, 40]) %1 = -30 ? vecmin([10, 20, -30, 40], &v); v %2 = 3 ? vecmin([10, 20; -30, 40], &v); v %3 = [2, 1] @eprog Variant: When $v$ is not needed, the function \fun{GEN}{vecmin}{GEN x} is also available. pari-2.11.2/src/functions/operators/powers0000644000175000017500000000144713201017466017243 0ustar billbillFunction: powers Section: operators C-Name: gpowers0 Prototype: GLDG Description: (gen, small):vec gpowers($1, $2) Help: powers(x,n,{x0}): return the vector [1,x,...,x^n] if x0 is omitted, and [x0, x0*x, ..., x0*x^n] otherwise. Doc: for non-negative $n$, return the vector with $n+1$ components $[1,x,\dots,x^n]$ if \kbd{x0} is omitted, and $[x_0, x_0*x, ..., x_0*x^n]$ otherwise. \bprog ? powers(Mod(3,17), 4) %1 = [Mod(1, 17), Mod(3, 17), Mod(9, 17), Mod(10, 17), Mod(13, 17)] ? powers(Mat([1,2;3,4]), 3) %2 = [[1, 0; 0, 1], [1, 2; 3, 4], [7, 10; 15, 22], [37, 54; 81, 118]] ? powers(3, 5, 2) %3 = [2, 6, 18, 54, 162, 486] @eprog\noindent When $n < 0$, the function returns the empty vector \kbd{[]}. Variant: Also available is \fun{GEN}{gpowers}{GEN x, long n} when \kbd{x0} is \kbd{NULL}. pari-2.11.2/src/functions/operators/sign0000644000175000017500000000056313201017466016662 0ustar billbillFunction: sign Section: operators C-Name: gsigne Prototype: iG Help: sign(x): sign of x, of type integer, real or fraction. Description: (mp):small signe($1) (gen):small gsigne($1) Doc: \idx{sign} ($0$, $1$ or $-1$) of $x$, which must be of type integer, real or fraction; \typ{QUAD} with positive discriminants and \typ{INFINITY} are also supported. pari-2.11.2/src/functions/operators/HEADER0000644000175000017500000002234313326135265016660 0ustar billbillFunction: _header_operators Class: header Section: operators Doc: \section{Standard monadic or dyadic operators} \subseckbd{+$/$-} The expressions \kbd{+}$x$ and \kbd{-}$x$ refer to monadic operators (the first does nothing, the second negates $x$). The library syntax is \fun{GEN}{gneg}{GEN x} for \kbd{-}$x$. \subseckbd{+} The expression $x$ \kbd{+} $y$ is the \idx{sum} of $x$ and $y$. Addition between a scalar type $x$ and a \typ{COL} or \typ{MAT} $y$ returns respectively $[y[1] + x, y[2],\dots]$ and $y + x \text{Id}$. Other additions between a scalar type and a vector or a matrix, or between vector/matrices of incompatible sizes are forbidden. The library syntax is \fun{GEN}{gadd}{GEN x, GEN y}. \subseckbd{-} The expression $x$ \kbd{-} $y$ is the \idx{difference} of $x$ and $y$. Subtraction between a scalar type $x$ and a \typ{COL} or \typ{MAT} $y$ returns respectively $[y[1] - x, y[2],\dots]$ and $y - x \text{Id}$. Other subtractions between a scalar type and a vector or a matrix, or between vector/matrices of incompatible sizes are forbidden. The library syntax is \fun{GEN}{gsub}{GEN x, GEN y} for $x$ \kbd{-} $y$. \subseckbd{*} The expression $x$ \kbd{*} $y$ is the \idx{product} of $x$ and $y$. Among the prominent impossibilities are multiplication between vector/matrices of incompatible sizes, between a \typ{INTMOD} or \typ{PADIC} Restricted to scalars, \kbd{*} is commutative; because of vector and matrix operations, it is not commutative in general. Multiplication between two \typ{VEC}s or two \typ{COL}s is not allowed; to take the \idx{scalar product} of two vectors of the same length, transpose one of the vectors (using the operator \kbd{\til} or the function \kbd{mattranspose}, see \secref{se:linear_algebra}) and multiply a line vector by a column vector: \bprog ? a = [1,2,3]; ? a * a *** at top-level: a*a *** ^-- *** _*_: forbidden multiplication t_VEC * t_VEC. ? a * a~ %2 = 14 @eprog If $x,y$ are binary quadratic forms, compose them; see also \kbd{qfbnucomp} and \kbd{qfbnupow}. If $x,y$ are \typ{VECSMALL} of the same length, understand them as permutations and compose them. The library syntax is \fun{GEN}{gmul}{GEN x, GEN y} for $x$ \kbd{*} $y$. Also available is \fun{GEN}{gsqr}{GEN x} for $x$ \kbd{*} $x$. \subseckbd{/} The expression $x$ \kbd{/} $y$ is the \idx{quotient} of $x$ and $y$. In addition to the impossibilities for multiplication, note that if the divisor is a matrix, it must be an invertible square matrix, and in that case the result is $x*y^{-1}$. Furthermore note that the result is as exact as possible: in particular, division of two integers always gives a rational number (which may be an integer if the quotient is exact) and \emph{not} the Euclidean quotient (see $x$ \kbd{\bs} $y$ for that), and similarly the quotient of two polynomials is a rational function in general. To obtain the approximate real value of the quotient of two integers, add \kbd{0.} to the result; to obtain the approximate $p$-adic value of the quotient of two integers, add \kbd{O(p\pow k)} to the result; finally, to obtain the \idx{Taylor series} expansion of the quotient of two polynomials, add \kbd{O(X\pow k)} to the result or use the \kbd{taylor} function (see \secref{se:taylor}). \label{se:gdiv} The library syntax is \fun{GEN}{gdiv}{GEN x, GEN y} for $x$ \kbd{/} $y$. \subseckbd{\bs} The expression \kbd{$x$ \bs\ $y$} is the \idx{Euclidean quotient} of $x$ and $y$. If $y$ is a real scalar, this is defined as \kbd{floor($x$/$y$)} if $y > 0$, and \kbd{ceil($x$/$y$)} if $y < 0$ and the division is not exact. Hence the remainder \kbd{$x$ - ($x$\bs$y$)*$y$} is in $[0, |y|[$. Note that when $y$ is an integer and $x$ a polynomial, $y$ is first promoted to a polynomial of degree $0$. When $x$ is a vector or matrix, the operator is applied componentwise. The library syntax is \fun{GEN}{gdivent}{GEN x, GEN y} for $x$ \kbd{\bs} $y$. \subseckbd{\bs/} The expression $x$ \b{/} $y$ evaluates to the rounded \idx{Euclidean quotient} of $x$ and $y$. This is the same as \kbd{$x$ \bs\ $y$} except for scalar division: the quotient is such that the corresponding remainder is smallest in absolute value and in case of a tie the quotient closest to $+\infty$ is chosen (hence the remainder would belong to $]{-}|y|/2, |y|/2]$). When $x$ is a vector or matrix, the operator is applied componentwise. The library syntax is \fun{GEN}{gdivround}{GEN x, GEN y} for $x$ \b{/} $y$. \subseckbd{\%} The expression \kbd{$x$ \% $y$} evaluates to the modular \idx{Euclidean remainder} of $x$ and $y$, which we now define. When $x$ or $y$ is a non-integral real number, \kbd{$x$\%$y$} is defined as \kbd{$x$ - ($x$\bs$y$)*$y$}. Otherwise, if $y$ is an integer, this is the smallest non-negative integer congruent to $x$ modulo $y$. (This actually coincides with the previous definition if and only if $x$ is an integer.) If $y$ is a polynomial, this is the polynomial of smallest degree congruent to $x$ modulo $y$. For instance: \bprog ? (1/2) % 3 %1 = 2 ? 0.5 % 3 %2 = 0.5000000000000000000000000000 ? (1/2) % 3.0 %3 = 1/2 @eprog Note that when $y$ is an integer and $x$ a polynomial, $y$ is first promoted to a polynomial of degree $0$. When $x$ is a vector or matrix, the operator is applied componentwise. The library syntax is \fun{GEN}{gmod}{GEN x, GEN y} for $x$ \kbd{\%} $y$. \subseckbd{\pow} The expression $x\hbox{\kbd{\pow}}n$ is \idx{powering}. \item If the exponent $n$ is an integer, then exact operations are performed using binary (left-shift) powering techniques. If $x$ is a $p$-adic number, its precision will increase if $v_p(n) > 0$. Powering a binary quadratic form (types \typ{QFI} and \typ{QFR}) returns a representative of the class, which is always reduced if the input was. (In particular, \kbd{x \pow 1} returns $x$ itself, whether it is reduced or not.) PARI is able to rewrite the multiplication $x * x$ of two \emph{identical} objects as $x^2$, or $\kbd{sqr}(x)$. Here, identical means the operands are two different labels referencing the same chunk of memory; no equality test is performed. This is no longer true when more than two arguments are involved. \item If the exponent $n$ is not an integer, powering is treated as the transcendental function $\exp(n\log x)$, and in particular acts componentwise on vector or matrices, even square matrices ! (See \secref{se:trans}.) \item As an exception, if the exponent is a rational number $p/q$ and $x$ an integer modulo a prime or a $p$-adic number, return a solution $y$ of $y^q=x^p$ if it exists. Currently, $q$ must not have large prime factors. Beware that \bprog ? Mod(7,19)^(1/2) %1 = Mod(11, 19) /* is any square root */ ? sqrt(Mod(7,19)) %2 = Mod(8, 19) /* is the smallest square root */ ? Mod(7,19)^(3/5) %3 = Mod(1, 19) ? %3^(5/3) %4 = Mod(1, 19) /* Mod(7,19) is just another cubic root */ @eprog \item If the exponent is a negative integer, an \idx{inverse} must be computed. For non-invertible \typ{INTMOD} $x$, this will fail and implicitly exhibit a non trivial factor of the modulus: \bprog ? Mod(4,6)^(-1) *** at top-level: Mod(4,6)^(-1) *** ^----- *** _^_: impossible inverse modulo: Mod(2, 6). @eprog\noindent (Here, a factor 2 is obtained directly. In general, take the gcd of the representative and the modulus.) This is most useful when performing complicated operations modulo an integer $N$ whose factorization is unknown. Either the computation succeeds and all is well, or a factor $d$ is discovered and the computation may be restarted modulo $d$ or $N/d$. For non-invertible \typ{POLMOD} $x$, the behavior is the same: \bprog ? Mod(x^2, x^3-x)^(-1) *** at top-level: Mod(x^2,x^3-x)^(-1) *** ^----- *** _^_: impossible inverse in RgXQ_inv: Mod(x^2, x^3 - x). @eprog\noindent Note that the underlying algorihm (subresultant) assumes the base ring is a domain: \bprog ? a = Mod(3*y^3+1, 4); b = y^6+y^5+y^4+y^3+y^2+y+1; c = Mod(a,b); ? c^(-1) *** at top-level: Mod(a,b)^(-1) *** ^----- *** _^_: impossible inverse modulo: Mod(2, 4). @eprog\noindent In fact $c$ is invertible, but $\Z/4\Z$ is not a domain and the algorithm fails. It is possible for the algorithm to succeed in such situations and any returned result will be correct, but chances are an error will occur first. In this specific case, one should work with $2$-adics. In general, one can also try the following approach \bprog ? inversemod(a, b) = { my(m, v = variable(b)); m = polsylvestermatrix(polrecip(a), polrecip(b)); m = matinverseimage(m, matid(#m)[,1]); Polrev(m[1..poldegree(b)], v); } ? inversemod(a,b) %2 = Mod(2,4)*y^5 + Mod(3,4)*y^3 + Mod(1,4)*y^2 + Mod(3,4)*y + Mod(2,4) @eprog\noindent This is not guaranteed to work either since \kbd{matinverseimage} must also invert pivots. See \secref{se:linear_algebra}. For a \typ{MAT} $x$, the matrix is expected to be square and invertible, except in the special case \kbd{x\pow(-1)} which returns a left inverse if one exists (rectangular $x$ with full column rank). \bprog ? x = Mat([1;2]) %1 = [1] [2] ? x^(-1) %2 = [1 0] @eprog The library syntax is \fun{GEN}{gpow}{GEN x, GEN n, long prec} for $x\hbox{\kbd{\pow}}n$. pari-2.11.2/src/functions/operators/cmp0000644000175000017500000000254513326135265016511 0ustar billbillFunction: cmp Section: operators C-Name: cmp_universal Prototype: iGG Help: cmp(x,y): compare two arbitrary objects x and y (1 if x>y, 0 if x=y, -1 if x$ vector $>$ scalar. For example: \bprog ? cmp(1, 2) %1 = -1 ? cmp(2, 1) %2 = 1 ? cmp(1, 1.0) \\ note that 1 == 1.0, but (1===1.0) is false. %3 = -1 ? cmp(x + Pi, []) %4 = -1 @eprog\noindent This function is mostly useful to handle sorted lists or vectors of arbitrary objects. For instance, if $v$ is a vector, the construction \kbd{vecsort(v, cmp)} is equivalent to \kbd{Set(v)}. pari-2.11.2/src/functions/operators/vecmax0000644000175000017500000000160713201017466017205 0ustar billbillFunction: vecmax Section: operators C-Name: vecmax0 Prototype: GD& Help: vecmax(x,{&v}): largest entry in the vector/matrix x. If v is present, set it to the index of a largest entry (indirect max). Description: (gen):gen vecmax($1) (gen, &gen):gen vecmax0($1, &$2) Doc: if $x$ is a vector or a matrix, returns the largest entry of $x$, otherwise returns a copy of $x$. Error if $x$ is empty. If $v$ is given, set it to the index of a largest entry (indirect maximum), when $x$ is a vector. If $x$ is a matrix, set $v$ to coordinates $[i,j]$ such that $x[i,j]$ is a largest entry. This flag is ignored if $x$ is not a vector or matrix. \bprog ? vecmax([10, 20, -30, 40]) %1 = 40 ? vecmax([10, 20, -30, 40], &v); v %2 = 4 ? vecmax([10, 20; -30, 40], &v); v %3 = [2, 2] @eprog Variant: When $v$ is not needed, the function \fun{GEN}{vecmax}{GEN x} is also available. pari-2.11.2/src/functions/operators/max0000644000175000017500000000104513201017466016503 0ustar billbillFunction: max Section: operators C-Name: gmax Prototype: GG Help: max(x,y): maximum of x and y. Description: (small, small):small maxss($1, $2) (small, int):int gmaxsg($1, $2) (int, small):int gmaxgs($1, $2) (int, int):int gmax($1, $2) (small, mp):mp gmaxsg($1, $2) (mp, small):mp gmaxgs($1, $2) (mp, mp):mp gmax($1, $2) (small, gen):gen gmaxsg($1, $2) (gen, small):gen gmaxgs($1, $2) (gen, gen):gen gmax($1, $2) Doc: creates the maximum of $x$ and $y$ when they can be compared. pari-2.11.2/src/functions/operators/min0000644000175000017500000000104513201017466016501 0ustar billbillFunction: min Section: operators C-Name: gmin Prototype: GG Help: min(x,y): minimum of x and y. Description: (small, small):small minss($1, $2) (small, int):int gminsg($1, $2) (int, small):int gmings($1, $2) (int, int):int gmin($1, $2) (small, mp):mp gminsg($1, $2) (mp, small):mp gmings($1, $2) (mp, mp):mp gmin($1, $2) (small, gen):gen gminsg($1, $2) (gen, small):gen gmings($1, $2) (gen, gen):gen gmin($1, $2) Doc: creates the minimum of $x$ and $y$ when they can be compared. pari-2.11.2/src/functions/operators/divrem0000644000175000017500000000214113201017466017202 0ustar billbillFunction: divrem Section: operators C-Name: divrem Prototype: GGDn Help: divrem(x,y,{v}): euclidean division of x by y giving as a 2-dimensional column vector the quotient and the remainder, with respect to v (to main variable if v is omitted). Doc: creates a column vector with two components, the first being the Euclidean quotient (\kbd{$x$ \bs\ $y$}), the second the Euclidean remainder (\kbd{$x$ - ($x$\bs$y$)*$y$}), of the division of $x$ by $y$. This avoids the need to do two divisions if one needs both the quotient and the remainder. If $v$ is present, and $x$, $y$ are multivariate polynomials, divide with respect to the variable $v$. Beware that \kbd{divrem($x$,$y$)[2]} is in general not the same as \kbd{$x$ \% $y$}; no GP operator corresponds to it: \bprog ? divrem(1/2, 3)[2] %1 = 1/2 ? (1/2) % 3 %2 = 2 ? divrem(Mod(2,9), 3)[2] *** at top-level: divrem(Mod(2,9),3)[2 *** ^-------------------- *** forbidden division t_INTMOD \ t_INT. ? Mod(2,9) % 6 %3 = Mod(2,3) @eprog Variant: Also available is \fun{GEN}{gdiventres}{GEN x, GEN y} when $v$ is not needed. pari-2.11.2/src/functions/operators/shift0000644000175000017500000000104611636712103017034 0ustar billbillFunction: shift Section: operators C-Name: gshift Prototype: GL Help: shift(x,n): shift x left n bits if n>=0, right -n bits if n<0. Doc: shifts $x$ componentwise left by $n$ bits if $n\ge0$ and right by $|n|$ bits if $n<0$. May be abbreviated as $x$ \kbd{<<} $n$ or $x$ \kbd{>>} $(-n)$. A left shift by $n$ corresponds to multiplication by $2^n$. A right shift of an integer $x$ by $|n|$ corresponds to a Euclidean division of $x$ by $2^{|n|}$ with a remainder of the same sign as $x$, hence is not the same (in general) as $x \kbd{\bs} 2^n$. pari-2.11.2/src/functions/transcendental/0000755000175000017500000000000013461316051016762 5ustar billbillpari-2.11.2/src/functions/transcendental/zetamultall0000644000175000017500000000140713326135265021253 0ustar billbillFunction: zetamultall Section: transcendental C-Name: zetamultall Prototype: Lp Help: zetamultall(n): list of all multiple zeta values for weight up to n. Doc: list of all multiple zeta values for weight $s_1 + \dots + s_k$ up to $n$. The function returns a vector with $2^{n-1}-1$ components whose $i$-th entry is the MZV of \kbd{index} $i$ (see \kbd{zetamult}). \bprog ? z = zetamultall(5); ? z[10] %2 = 0.22881039760335375976874614894168879193 ? zetamultconvert(10) \\ convert index 10 to avec %3 = Vecsmall([3, 2]) ? zetamult(%) %4 = 0.22881039760335375976874614894168879193 ? zetamult(10) %5 = 0.22881039760335375976874614894168879193 @eprog\noindent If the bit precision is $B$, this function runs in time $O(2^n n B^2)$ for an output of size $O(2^n B)$. pari-2.11.2/src/functions/transcendental/thetanullk0000644000175000017500000000073412314242551021063 0ustar billbillFunction: thetanullk Section: transcendental C-Name: thetanullk Prototype: GLp Help: thetanullk(q,k): k-th derivative at z=0 of theta(q,z). Doc: $k$-th derivative at $z=0$ of $\kbd{theta}(q,z)$. Variant: \fun{GEN}{vecthetanullk}{GEN q, long k, long prec} returns the vector of all $\dfrac{d^i\theta}{dz^i}(q,0)$ for all odd $i = 1, 3, \dots, 2k-1$. \fun{GEN}{vecthetanullk_tau}{GEN tau, long k, long prec} returns \kbd{vecthetanullk\_tau} at $q = \exp(2i\pi \kbd{tau})$. pari-2.11.2/src/functions/transcendental/sqrt0000644000175000017500000000146413201017466017703 0ustar billbillFunction: sqrt Section: transcendental C-Name: gsqrt Prototype: Gp Help: sqrt(x): square root of x. Description: (real):gen sqrtr($1) (gen):gen:prec gsqrt($1, $prec) Doc: principal branch of the square root of $x$, defined as $\sqrt{x} = \exp(\log x / 2)$. In particular, we have $\text{Arg}(\text{sqrt}(x))\in{} ]-\pi/2, \pi/2]$, and if $x\in \R$ and $x<0$, then the result is complex with positive imaginary part. Intmod a prime $p$, \typ{PADIC} and \typ{FFELT} are allowed as arguments. In the first 2 cases (\typ{INTMOD}, \typ{PADIC}), the square root (if it exists) which is returned is the one whose first $p$-adic digit is in the interval $[0,p/2]$. For other arguments, the result is undefined. Variant: For a \typ{PADIC} $x$, the function \fun{GEN}{Qp_sqrt}{GEN x} is also available. pari-2.11.2/src/functions/transcendental/bernpol0000644000175000017500000000043312314242551020345 0ustar billbillFunction: bernpol Section: transcendental C-Name: bernpol Prototype: LDn Help: bernpol(n, {v = 'x}): Bernoulli polynomial B_n, in variable v. Doc: \idx{Bernoulli polynomial} $B_n$ in variable $v$. \bprog ? bernpol(1) %1 = x - 1/2 ? bernpol(3) %2 = x^3 - 3/2*x^2 + 1/2*x @eprog pari-2.11.2/src/functions/transcendental/abs0000644000175000017500000000151213201017466017451 0ustar billbillFunction: abs Section: transcendental C-Name: gabs Prototype: Gp Help: abs(x): absolute value (or modulus) of x. Description: (small):small labs($1) (int):int mpabs($1) (real):real mpabs($1) (mp):mp mpabs($1) (gen):gen:prec gabs($1, $prec) Doc: absolute value of $x$ (modulus if $x$ is complex). Rational functions are not allowed. Contrary to most transcendental functions, an exact argument is \emph{not} converted to a real number before applying \kbd{abs} and an exact result is returned if possible. \bprog ? abs(-1) %1 = 1 ? abs(3/7 + 4/7*I) %2 = 5/7 ? abs(1 + I) %3 = 1.414213562373095048801688724 @eprog\noindent If $x$ is a polynomial, returns $-x$ if the leading coefficient is real and negative else returns $x$. For a power series, the constant coefficient is considered instead. pari-2.11.2/src/functions/transcendental/psi0000644000175000017500000000027412314242551017502 0ustar billbillFunction: psi Section: transcendental C-Name: gpsi Prototype: Gp Help: psi(x): psi-function at x. Doc: the $\psi$-function of $x$, i.e.~the logarithmic derivative $\Gamma'(x)/\Gamma(x)$. pari-2.11.2/src/functions/transcendental/sinh0000644000175000017500000000020513036414402017640 0ustar billbillFunction: sinh Section: transcendental C-Name: gsinh Prototype: Gp Help: sinh(x): hyperbolic sine of x. Doc: hyperbolic sine of $x$. pari-2.11.2/src/functions/transcendental/Catalan0000644000175000017500000000056313201017466020254 0ustar billbillFunction: Catalan Section: transcendental C-Name: mpcatalan Prototype: p Help: Catalan=Catalan(): Catalan's number with current precision. Description: ():real:prec mpcatalan($prec) Doc: Catalan's constant $G = \sum_{n>=0}\dfrac{(-1)^n}{(2n+1)^2}=0.91596\cdots$. Note that \kbd{Catalan} is one of the few reserved names which cannot be used for user variables. pari-2.11.2/src/functions/transcendental/gammah0000644000175000017500000000025313036414402020134 0ustar billbillFunction: gammah Section: transcendental C-Name: ggammah Prototype: Gp Help: gammah(x): gamma of x+1/2 (x integer). Doc: gamma function evaluated at the argument $x+1/2$. pari-2.11.2/src/functions/transcendental/cosh0000644000175000017500000000021113036414402017630 0ustar billbillFunction: cosh Section: transcendental C-Name: gcosh Prototype: Gp Help: cosh(x): hyperbolic cosine of x. Doc: hyperbolic cosine of $x$. pari-2.11.2/src/functions/transcendental/exp0000644000175000017500000000060513201017466017502 0ustar billbillFunction: exp Section: transcendental C-Name: gexp Prototype: Gp Help: exp(x): exponential of x. Description: (real):real mpexp($1) (mp):mp:prec gexp($1, $prec) (gen):gen:prec gexp($1, $prec) Doc: exponential of $x$. $p$-adic arguments with positive valuation are accepted. Variant: For a \typ{PADIC} $x$, the function \fun{GEN}{Qp_exp}{GEN x} is also available. pari-2.11.2/src/functions/transcendental/besseli0000644000175000017500000000055411636712103020337 0ustar billbillFunction: besseli Section: transcendental C-Name: ibessel Prototype: GGp Help: besseli(nu,x): I-bessel function of index nu and argument x. Doc: $I$-Bessel function of index \var{nu} and argument $x$. If $x$ converts to a power series, the initial factor $(x/2)^\nu/\Gamma(\nu+1)$ is omitted (since it cannot be represented in PARI when $\nu$ is not integral). pari-2.11.2/src/functions/transcendental/besseljh0000644000175000017500000000067611636712103020515 0ustar billbillFunction: besseljh Section: transcendental C-Name: jbesselh Prototype: GGp Help: besseljh(n,x): J-bessel function of index n+1/2 and argument x, where n is a non-negative integer. Doc: $J$-Bessel function of half integral index. More precisely, $\kbd{besseljh}(n,x)$ computes $J_{n+1/2}(x)$ where $n$ must be of type integer, and $x$ is any element of $\C$. In the present version \vers, this function is not very accurate when $x$ is small. pari-2.11.2/src/functions/transcendental/acos0000644000175000017500000000073513201017466017637 0ustar billbillFunction: acos Section: transcendental C-Name: gacos Prototype: Gp Help: acos(x): arc cosine of x. Doc: principal branch of $\cos^{-1}(x) = -i \log (x + i\sqrt{1-x^2})$. In particular, $\Re(\text{acos}(x))\in [0,\pi]$ and if $x\in \R$ and $|x|>1$, then $\text{acos}(x)$ is complex. The branch cut is in two pieces: $]-\infty,-1]$ , continuous with quadrant II, and $[1,+\infty[$, continuous with quadrant IV. We have $\text{acos}(x) = \pi/2 - \text{asin}(x)$ for all $x$. pari-2.11.2/src/functions/transcendental/tan0000644000175000017500000000016211636712103017466 0ustar billbillFunction: tan Section: transcendental C-Name: gtan Prototype: Gp Help: tan(x): tangent of x. Doc: tangent of $x$. pari-2.11.2/src/functions/transcendental/theta0000644000175000017500000000034311636712103020012 0ustar billbillFunction: theta Section: transcendental C-Name: theta Prototype: GGp Help: theta(q,z): Jacobi sine theta-function. Doc: Jacobi sine theta-function $$ \theta_1(z, q) = 2q^{1/4} \sum_{n\geq 0} (-1)^n q^{n(n+1)} \sin((2n+1)z).$$ pari-2.11.2/src/functions/transcendental/eta0000644000175000017500000000212211636712103017453 0ustar billbillFunction: eta Section: transcendental C-Name: eta0 Prototype: GD0,L,p Help: eta(z,{flag=0}): if flag=0, returns prod(n=1,oo, 1-q^n), where q = exp(2 i Pi z) if z is a complex scalar (belonging to the upper half plane); q = z if z is a p-adic number or can be converted to a power series. If flag is non-zero, the function only applies to complex scalars and returns the true eta function, with the factor q^(1/24) included. Doc: Variants of \idx{Dedekind}'s $\eta$ function. If $\fl = 0$, return $\prod_{n=1}^\infty(1-q^n)$, where $q$ depends on $x$ in the following way: \item $q = e^{2i\pi x}$ if $x$ is a \emph{complex number} (which must then have positive imaginary part); notice that the factor $q^{1/24}$ is missing! \item $q = x$ if $x$ is a \typ{PADIC}, or can be converted to a \emph{power series} (which must then have positive valuation). If $\fl$ is non-zero, $x$ is converted to a complex number and we return the true $\eta$ function, $q^{1/24}\prod_{n=1}^\infty(1-q^n)$, where $q = e^{2i\pi x}$. Variant: Also available is \fun{GEN}{trueeta}{GEN x, long prec} ($\fl=1$). pari-2.11.2/src/functions/transcendental/incgamc0000644000175000017500000000063111636712103020306 0ustar billbillFunction: incgamc Section: transcendental C-Name: incgamc Prototype: GGp Help: incgamc(s,x): complementary incomplete gamma function. Doc: complementary incomplete gamma function. The arguments $x$ and $s$ are complex numbers such that $s$ is not a pole of $\Gamma$ and $|x|/(|s|+1)$ is not much larger than 1 (otherwise the convergence is very slow). The result returned is $\int_0^x e^{-t}t^{s-1}\,dt$. pari-2.11.2/src/functions/transcendental/cos0000644000175000017500000000016011636712103017466 0ustar billbillFunction: cos Section: transcendental C-Name: gcos Prototype: Gp Help: cos(x): cosine of x. Doc: cosine of $x$. pari-2.11.2/src/functions/transcendental/bernvec0000644000175000017500000000034613201017466020334 0ustar billbillFunction: bernvec Section: transcendental C-Name: bernvec Prototype: L Obsolete: 2007-03-30 Help: bernvec(x): this routine is obsolete, use bernfrac repeatedly. Doc: This routine is obsolete, kept for backward compatibility only. pari-2.11.2/src/functions/transcendental/eint10000644000175000017500000000232113201017466017723 0ustar billbillFunction: eint1 Section: transcendental C-Name: veceint1 Prototype: GDGp Help: eint1(x,{n}): exponential integral E1(x). If n is present and x > 0, computes the vector of the first n values of the exponential integral E1(n x). Doc: exponential integral $\int_x^\infty \dfrac{e^{-t}}{t}\,dt = \kbd{incgam}(0, x)$, where the latter expression extends the function definition from real $x > 0$ to all complex $x \neq 0$. If $n$ is present, we must have $x > 0$; the function returns the $n$-dimensional vector $[\kbd{eint1}(x),\dots,\kbd{eint1}(nx)]$. Contrary to other transcendental functions, and to the default case ($n$ omitted), the values are correct up to a bounded \emph{absolute}, rather than relative, error $10^{-n}$, where $n$ is \kbd{precision}$(x)$ if $x$ is a \typ{REAL} and defaults to \kbd{realprecision} otherwise. (In the most important application, to the computation of $L$-functions via approximate functional equations, those values appear as weights in long sums and small individual relative errors are less useful than controlling the absolute error.) This is faster than repeatedly calling \kbd{eint1($i$ * x)}, but less precise. Variant: Also available is \fun{GEN}{eint1}{GEN x, long prec}. pari-2.11.2/src/functions/transcendental/dilog0000644000175000017500000000035011636712103020001 0ustar billbillFunction: dilog Section: transcendental C-Name: dilog Prototype: Gp Help: dilog(x): dilogarithm of x. Doc: principal branch of the dilogarithm of $x$, i.e.~analytic continuation of the power series $\log_2(x)=\sum_{n\ge1}x^n/n^2$. pari-2.11.2/src/functions/transcendental/arg0000644000175000017500000000030513201017466017454 0ustar billbillFunction: arg Section: transcendental C-Name: garg Prototype: Gp Help: arg(x): argument of x, such that -pi0$ and even, and using modular forms for $s>0$ and odd. Power series are also allowed: \bprog ? zeta(2) - Pi^2/6 %1 = 0.E-38 ? zeta(1+x+O(x^3)) %2 = 1.0000000000000000000000000000000000000*x^-1 + \ 0.57721566490153286060651209008240243104 + O(x) @eprog For $s\neq 1$ a $p$-adic number, Kubota-Leopoldt zeta function at $s$, that is the unique continuous $p$-adic function on the $p$-adic integers that interpolates the values of $(1 - p^{-k}) \zeta(k)$ at negative integers $k$ such that $k \equiv 1 \pmod{p-1}$ (resp. $k$ is odd) if $p$ is odd (resp. $p = 2$). Power series are not allowed in this case. \bprog ? zeta(-3+O(5^10)) %1 = 4*5^-1 + 4 + 3*5 + 4*5^3 + 4*5^5 + 4*5^7 + O(5^9))))) ? (1-5^3) * zeta(-3) %2 = -1.0333333333333333333333333333333333333 ? bestappr(%) %3 = -31/30 ? zeta(-3+O(5^10)) - (-31/30) %4 = O(5^9) @eprog pari-2.11.2/src/functions/transcendental/HEADER0000644000175000017500000001341713326135265017651 0ustar billbillFunction: _header_transcendental Class: header Section: transcendental Doc: \section{Transcendental functions}\label{se:trans} Since the values of transcendental functions cannot be exactly represented, these functions will always return an inexact object: a real number, a complex number, a $p$-adic number or a power series. All these objects have a certain finite precision. As a general rule, which of course in some cases may have exceptions, transcendental functions operate in the following way: \item If the argument is either a real number or an inexact complex number (like \kbd{1.0 + I} or \kbd{Pi*I} but not \kbd{2 - 3*I}), then the computation is done with the precision of the argument. In the example below, we see that changing the precision to $50$ digits does not matter, because $x$ only had a precision of $19$ digits. \bprog ? \p 15 realprecision = 19 significant digits (15 digits displayed) ? x = Pi/4 %1 = 0.785398163397448 ? \p 50 realprecision = 57 significant digits (50 digits displayed) ? sin(x) %2 = 0.7071067811865475244 @eprog Note that even if the argument is real, the result may be complex (e.g.~$\text{acos}(2.0)$ or $\text{acosh}(0.0)$). See each individual function help for the definition of the branch cuts and choice of principal value. \item If the argument is either an integer, a rational, an exact complex number or a quadratic number, it is first converted to a real or complex number using the current \idx{precision}, which can be view and manipulated using the defaults \tet{realprecision} (in decimal digits) or \tet{realbitprecision} (in bits). This precision can be changed indifferently \item in decimal digits: use \b{p} or \kbd{default(realprecision,...)}. \item in bits: use \b{pb} or \kbd{default(realbitprecision,...)}. After this conversion, the computation proceeds as above for real or complex arguments. In library mode, the \kbd{realprecision} does not matter; instead the precision is taken from the \kbd{prec} parameter which every transcendental function has. As in \kbd{gp}, this \kbd{prec} is not used when the argument to a function is already inexact. Note that the argument \var{prec} stands for the length in words of a real number, including codewords. Hence we must have $\var{prec} \geq 3$. (Some functions allow a \kbd{bitprec} argument instead which allow finer granularity.) Some accuracies attainable on 32-bit machines cannot be attained on 64-bit machines for parity reasons. For example the default \kbd{gp} accuracy is 28 decimal digits on 32-bit machines, corresponding to \var{prec} having the value 5, but this cannot be attained on 64-bit machines. \item If the argument is a polmod (representing an algebraic number), then the function is evaluated for every possible complex embedding of that algebraic number. A column vector of results is returned, with one component for each complex embedding. Therefore, the number of components equals the degree of the \typ{POLMOD} modulus. \item If the argument is an intmod or a $p$-adic, at present only a few functions like \kbd{sqrt} (square root), \kbd{sqr} (square), \kbd{log}, \kbd{exp}, powering, \kbd{teichmuller} (Teichm\"uller character) and \kbd{agm} (arithmetic-geometric mean) are implemented. Note that in the case of a $2$-adic number, $\kbd{sqr}(x)$ may not be identical to $x*x$: for example if $x = 1+O(2^5)$ and $y = 1+O(2^5)$ then $x*y = 1+O(2^5)$ while $\kbd{sqr}(x) = 1+O(2^6)$. Here, $x * x$ yields the same result as $\kbd{sqr}(x)$ since the two operands are known to be \emph{identical}. The same statement holds true for $p$-adics raised to the power $n$, where $v_p(n) > 0$. \misctitle{Remark} If we wanted to be strictly consistent with the PARI philosophy, we should have $x*y = (4 \mod 8)$ and $\kbd{sqr}(x) = (4 \mod 32)$ when both $x$ and $y$ are congruent to $2$ modulo $4$. However, since intmod is an exact object, PARI assumes that the modulus must not change, and the result is hence $(0\, \mod\, 4)$ in both cases. On the other hand, $p$-adics are not exact objects, hence are treated differently. \item If the argument is a polynomial, a power series or a rational function, it is, if necessary, first converted to a power series using the current series precision, held in the default \tet{seriesprecision}. This precision (the number of significant terms) can be changed using \b{ps} or \kbd{default(seriesprecision,...)}. Then the Taylor series expansion of the function around $X=0$ (where $X$ is the main variable) is computed to a number of terms depending on the number of terms of the argument and the function being computed. Under \kbd{gp} this again is transparent to the user. When programming in library mode, however, it is \emph{strongly} advised to perform an explicit conversion to a power series first, as in \bprog x = gtoser(x, gvar(x), seriesprec) @eprog\noindent where the number of significant terms \kbd{seriesprec} can be specified explicitly. If you do not do this, a global variable \kbd{precdl} is used instead, to convert polynomials and rational functions to a power series with a reasonable number of terms; tampering with the value of this global variable is \emph{deprecated} and strongly discouraged. \item If the argument is a vector or a matrix, the result is the componentwise evaluation of the function. In particular, transcendental functions on square matrices, which are not implemented in the present version \vers, will have a different name if they are implemented some day. \subseckbd{\pow} If $y$ is not of type integer, \kbd{x\pow y} has the same effect as \kbd{exp(y*log(x))}. It can be applied to $p$-adic numbers as well as to the more usual types.\sidx{powering} The library syntax is \fun{GEN}{gpow}{GEN x, GEN n, long prec} for $x\hbox{\kbd{\pow}}n$. pari-2.11.2/src/functions/transcendental/sinc0000644000175000017500000000045013201017466017640 0ustar billbillFunction: sinc Section: transcendental C-Name: gsinc Prototype: Gp Help: sinc(x): sinc function of x. Doc: cardinal sine of $x$, i.e. $\sin(x)/x$ if $x\neq 0$, $1$ otherwise. Note that this function also allows to compute $$(1-\cos(x)) / x^2 = \kbd{sinc}(x/2)^2 / 2$$ accurately near $x = 0$. pari-2.11.2/src/functions/transcendental/besseln0000644000175000017500000000031111636712103020333 0ustar billbillFunction: besseln Section: transcendental C-Name: nbessel Prototype: GGp Help: besseln(nu,x): N-bessel function of index nu and argument x. Doc: $N$-Bessel function of index \var{nu} and argument $x$. pari-2.11.2/src/functions/transcendental/atanh0000644000175000017500000000052013201017466017775 0ustar billbillFunction: atanh Section: transcendental C-Name: gatanh Prototype: Gp Help: atanh(x): inverse hyperbolic tangent of x. Doc: principal branch of $\text{tanh}^{-1}(x) = \log ((1+x)/(1-x)) / 2$. In particular the imaginary part of $\text{atanh}(x)$ belongs to $[-\pi/2,\pi/2]$; if $x\in \R$ and $|x|>1$ then $\text{atanh}(x)$ is complex. pari-2.11.2/src/functions/transcendental/Euler0000644000175000017500000000050413201017466017760 0ustar billbillFunction: Euler Section: transcendental C-Name: mpeuler Prototype: p Help: Euler=Euler(): Euler's constant with current precision. Description: ():real:prec mpeuler($prec) Doc: Euler's constant $\gamma=0.57721\cdots$. Note that \kbd{Euler} is one of the few reserved names which cannot be used for user variables. pari-2.11.2/src/functions/transcendental/besselk0000644000175000017500000000031111636712103020330 0ustar billbillFunction: besselk Section: transcendental C-Name: kbessel Prototype: GGp Help: besselk(nu,x): K-bessel function of index nu and argument x. Doc: $K$-Bessel function of index \var{nu} and argument $x$. pari-2.11.2/src/functions/transcendental/gammamellininvinit0000644000175000017500000000272013201017466022572 0ustar billbillFunction: gammamellininvinit Section: transcendental C-Name: gammamellininvinit Prototype: GD0,L,b Help: gammamellininvinit(A,{m=0}): initialize data for the computation by gammamellininv() of the m-th derivative of the inverse Mellin transform of the function f(s) = Gamma_R(s+a1)*...*Gamma_R(s+ad), where A is the vector [a1,...,ad] and Gamma_R(s) = Pi^(-s/2)*gamma(s/2). Doc: initialize data for the computation by \tet{gammamellininv} of the $m$-th derivative of the inverse Mellin transform of the function $$f(s) = \Gamma_\R(s+a_1)\*\ldots\*\Gamma_\R(s+a_d)$$ where \kbd{A} is the vector $[a_1,\ldots,a_d]$ and $\Gamma_\R(s)=\pi^{-s/2}\*\Gamma(s/2)$ (Euler's \kbd{gamma}). This is the special case of Meijer's $G$ functions used to compute $L$-values via the approximate functional equation. \misctitle{Caveat} Contrary to the PARI convention, this function guarantees an \emph{absolute} (rather than relative) error bound. For instance, the inverse Mellin transform of $\Gamma_\R(s)$ is $2\exp(-\pi z^2)$: \bprog ? G = gammamellininvinit([0]); ? gammamellininv(G, 2) - 2*exp(-Pi*2^2) %2 = -4.484155085839414627 E-44 @eprog The inverse Mellin transform of $\Gamma_\R(s+1)$ is $2 z\exp(-\pi z^2)$, and its second derivative is $ 4\pi z \exp(-\pi z^2)(2\pi z^2 - 3)$: \bprog ? G = gammamellininvinit([1], 2); ? a(z) = 4*Pi*z*exp(-Pi*z^2)*(2*Pi*z^2-3); ? b(z) = gammamellininv(G,z); ? t(z) = b(z) - a(z); ? t(3/2) %3 = -1.4693679385278593850 E-39 @eprog pari-2.11.2/src/functions/transcendental/erfc0000644000175000017500000000053712314242551017630 0ustar billbillFunction: erfc Section: transcendental C-Name: gerfc Prototype: Gp Help: erfc(x): complementary error function. Doc: complementary error function, analytic continuation of $(2/\sqrt\pi)\int_x^\infty e^{-t^2}\,dt = \kbd{incgam}(1/2,x^2)/\sqrt\pi$, where the latter expression extends the function definition from real $x$ to all complex $x \neq 0$. pari-2.11.2/src/functions/transcendental/zetamultinit0000644000175000017500000000215313326135265021445 0ustar billbillFunction: zetamultinit Section: transcendental C-Name: zetamultinit Prototype: Lp Help: zetamultinit(maxw): initialize data to compute multiple zeta values at integral s = [s1,...,sk] for s1 + ... + sk <= maxw. Doc: initialize data (depending on the precision) used to compute multiple zeta values at integral points $s = [s_1,\dots,s_k]$ for any $s_1 + \dots + s_k \leq \var{maxw}$. The corresponding data is inexpensive to compute or store and provides a small speedup (usually about 10\%) when multiple values are to be computed at a given accuracy. \bprog ? for(i = 1, 2^12-1, zetamult(i)) time = 1,413 ms ? T = zetamultinit(13); \\ instantaneous ? for(i = 1, 2^12-1, zetamult(i, T)) \\ used cached data time = 1,315 ms ? zetamultall(12); \\ much faster ! time = 27 ms ? T=zetamultinit(102); sizebyte(T) \\ small even for huge weights time = 5 ms. %5 = 1440504 ? for(i = 1, 2^5, zetamult(2^100+i)) time = 633 ms. ? for(i = 1, 2^5, zetamult(2^100+i, T)) time = 550 ms. @eprog\noindent For small weights, \kbd{zetamultall} will be much more efficient; but it is not an option when the weight gets large. pari-2.11.2/src/functions/transcendental/zetahurwitz0000644000175000017500000000304513326135265021315 0ustar billbillFunction: zetahurwitz Section: transcendental C-Name: zetahurwitz Prototype: GGD0,L,b Help: zetahurwitz(s,x,{der=0}): Hurwitz zeta function at s, x, with s not 1 and x not a negative or zero integer. s can be a scalar, polynomial, rational function, or power series. If der>0, compute the der'th derivative with respect to s. Doc: Hurwitz zeta function $\zeta(s,x)=\sum_{n\ge0}(n+x)^{-s}$ and analytically continued, with $s\ne1$ and $x$ not a negative or zero integer. Note that $\zeta(s,1) = \zeta(s)$. $s$ can also be a polynomial, rational function, or power series. If \kbd{der} is positive, compute the \kbd{der}'th derivative with respect to $s$. Note that the derivative with respect to $x$ is simply $-s\zeta(s+1,x)$. \bprog ? zetahurwitz(Pi,Pi) %1 = 0.056155444497585099925180502385781494484 ? zetahurwitz(2,1) - zeta(2) %2 = -2.350988701644575016 E-38 ? zetahurwitz(Pi,3) - (zeta(Pi)-1-1/2^Pi) %3 = -2.2040519077917890774 E-39 ? zetahurwitz(-7/2,1) - zeta(-7/2) %4 = -2.295887403949780289 E-41 ? zetahurwitz(-2.3,Pi+I*log(2)) %5 = -5.1928369229555125820137832704455696057\ - 6.1349660138824147237884128986232049582*I ? zetahurwitz(-1+x^2+O(x^3),1) %6 = -0.083333333333333333333333333333333333333\ - 0.16542114370045092921391966024278064276*x^2 + O(x^3) ? zetahurwitz(1+x+O(x^4),2) %7 = 1.0000000000000000000000000000000000000*x^-1\ - 0.42278433509846713939348790991759756896\ + 0.072815845483676724860586375874901319138*x + O(x^2) ? zetahurwitz(2,1,2) \\ zeta''(2) %8 = 1.9892802342989010234208586874215163815 @eprog pari-2.11.2/src/functions/transcendental/incgam0000644000175000017500000000116212314242551020142 0ustar billbillFunction: incgam Section: transcendental C-Name: incgam0 Prototype: GGDGp Help: incgam(s,x,{g}): incomplete gamma function. g is optional and is the precomputed value of gamma(s). Doc: incomplete gamma function $\int_x^\infty e^{-t}t^{s-1}\,dt$, extended by analytic continuation to all complex $x, s$ not both $0$. The relative error is bounded in terms of the precision of $s$ (the accuracy of $x$ is ignored when determining the output precision). When $g$ is given, assume that $g=\Gamma(s)$. For small $|x|$, this will speed up the computation. Variant: Also available is \fun{GEN}{incgam}{GEN s, GEN x, long prec}. pari-2.11.2/src/functions/transcendental/cotan0000644000175000017500000000017411636712103020013 0ustar billbillFunction: cotan Section: transcendental C-Name: gcotan Prototype: Gp Help: cotan(x): cotangent of x. Doc: cotangent of $x$. pari-2.11.2/src/functions/transcendental/sqrtn0000644000175000017500000000276313201017466020064 0ustar billbillFunction: sqrtn Section: transcendental C-Name: gsqrtn Prototype: GGD&p Help: sqrtn(x,n,{&z}): nth-root of x, n must be integer. If present, z is set to a suitable root of unity to recover all solutions. If it was not possible, z is set to zero. Doc: principal branch of the $n$th root of $x$, i.e.~such that $\text{Arg}(\text{sqrtn}(x))\in{} ]-\pi/n, \pi/n]$. Intmod a prime and $p$-adics are allowed as arguments. If $z$ is present, it is set to a suitable root of unity allowing to recover all the other roots. If it was not possible, z is set to zero. In the case this argument is present and no $n$th root exist, $0$ is returned instead of raising an error. \bprog ? sqrtn(Mod(2,7), 2) %1 = Mod(3, 7) ? sqrtn(Mod(2,7), 2, &z); z %2 = Mod(6, 7) ? sqrtn(Mod(2,7), 3) *** at top-level: sqrtn(Mod(2,7),3) *** ^----------------- *** sqrtn: nth-root does not exist in gsqrtn. ? sqrtn(Mod(2,7), 3, &z) %2 = 0 ? z %3 = 0 @eprog The following script computes all roots in all possible cases: \bprog sqrtnall(x,n)= { my(V,r,z,r2); r = sqrtn(x,n, &z); if (!z, error("Impossible case in sqrtn")); if (type(x) == "t_INTMOD" || type(x)=="t_PADIC", r2 = r*z; n = 1; while (r2!=r, r2*=z;n++)); V = vector(n); V[1] = r; for(i=2, n, V[i] = V[i-1]*z); V } addhelp(sqrtnall,"sqrtnall(x,n):compute the vector of nth-roots of x"); @eprog\noindent Variant: If $x$ is a \typ{PADIC}, the function \fun{GEN}{Qp_sqrtn}{GEN x, GEN n, GEN *z} is also available. pari-2.11.2/src/functions/transcendental/zetamultconvert0000644000175000017500000000174013326135265022163 0ustar billbillFunction: zetamultconvert Section: transcendental C-Name: zetamultconvert Prototype: GD1,L, Help: zetamultconvert(a,{fl=1}): a being either an evec, avec, or index m, converts into evec (fl=0), avec (fl=1), or index m (fl=2). Doc: \kbd{a} being either an \kbd{evec}, \kbd{avec}, or index \kbd{m}, converts into \kbd{evec} (\kbd{fl=0}), \kbd{avec} (\kbd{fl=1}, default), or index \kbd{m} (\kbd{fl=2}); see \kbd{zetamult} for explanations. \bprog ? zetamultconvert(10) %1 = Vecsmall([3, 2]) ? zetamultconvert(13) %2 = Vecsmall([2, 2, 1]) ? zetamultconvert(10, 0) %3 = Vecsmall([0, 0, 1, 0, 1]) ? zetamultconvert(13, 0) %4 = Vecsmall([0, 1, 0, 1, 1]) @eprog\noindent The last two lines imply that $[3,2]$ and $[2,2,1]$ are dual (reverse order of bits and swap $0$ and $1$ in \kbd{evec} form). Hence they have the same zeta value: \bprog ? zetamult([3,2]) %5 = 0.22881039760335375976874614894168879193 ? zetamult([2,2,1]) %6 = 0.22881039760335375976874614894168879193 @eprog pari-2.11.2/src/functions/transcendental/log1p0000644000175000017500000000156113326135265017740 0ustar billbillFunction: log1p Section: transcendental C-Name: glog1p Prototype: Gp Help: log1p(x): log(1+x) Doc: return $\log(1+x)$, computed in a way that is also accurate when the real part of $x$ is near $0$. This is the reciprocal function of \kbd{expm1}$(x) = \exp(x)-1$. \bprog ? default(realprecision, 10000); x = Pi*1e-100; ? (expm1(log1p(x)) - x) / x %2 = -7.668242895059371866 E-10019 ? (log1p(expm1(x)) - x) / x %3 = -7.668242895059371866 E-10019 @eprog\noindent When $x$ is small, this function is both faster and more accurate than $\log(1+x)$: \bprog ? \p38 ? x = 1e-20; ? localprec(100); c = log1p(x); \\ reference point ? a = log1p(x); abs((a - c)/c) %6 = 0.E-38 ? b = log(1+x); abs((b - c)/c) \\ slightly less accurate %7 = 1.5930919111324522770 E-38 ? for (i=1,10^5,log1p(x)) time = 81 ms. ? for (i=1,10^5,log(1+x)) time = 100 ms. \\ slower, too @eprog pari-2.11.2/src/functions/transcendental/gammamellininv0000644000175000017500000000120513201017466021703 0ustar billbillFunction: gammamellininv Section: transcendental C-Name: gammamellininv Prototype: GGD0,L,b Help: gammamellininv(G,t,{m=0}): returns G(t), where G is as output by gammamellininvinit. The alternative syntax gammamellininv(A,t,m) is also available. Doc: returns the value at $t$ of the inverse Mellin transform $G$ initialized by \tet{gammamellininvinit}. \bprog ? G = gammamellininvinit([0]); ? gammamellininv(G, 2) - 2*exp(-Pi*2^2) %2 = -4.484155085839414627 E-44 @eprog The alternative shortcut \bprog gammamellininv(A,t,m) @eprog\noindent for \bprog gammamellininv(gammamellininvinit(A,m), t) @eprog\noindent is available. pari-2.11.2/src/functions/transcendental/teichmuller0000644000175000017500000000450013201017466021221 0ustar billbillFunction: teichmuller Section: transcendental C-Name: teichmuller Prototype: GDG Help: teichmuller(x,{tab}): teichmuller character of p-adic number x. If x = [p,n], return the lifts of all teichmuller(i + O(p^n)) for i = 1, ..., p-1. Such a vector can be fed back to teichmuller, as the optional argument tab, to speed up later computations. Doc: Teichm\"uller character of the $p$-adic number $x$, i.e. the unique $(p-1)$-th root of unity congruent to $x / p^{v_p(x)}$ modulo $p$. If $x$ is of the form $[p,n]$, for a prime $p$ and integer $n$, return the lifts to $\Z$ of the images of $i + O(p^n)$ for $i = 1, \dots, p-1$, i.e. all roots of $1$ ordered by residue class modulo $p$. Such a vector can be fed back to \kbd{teichmuller}, as the optional argument \kbd{tab}, to speed up later computations. \bprog ? z = teichmuller(2 + O(101^5)) %1 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) ? z^100 %2 = 1 + O(101^5) ? T = teichmuller([101, 5]); ? teichmuller(2 + O(101^5), T) %4 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) @eprog\noindent As a rule of thumb, if more than $$p \,/\, 2(\log_2(p) + \kbd{hammingweight}(p))$$ values of \kbd{teichmuller} are to be computed, then it is worthwile to initialize: \bprog ? p = 101; n = 100; T = teichmuller([p,n]); \\ instantaneous ? for(i=1,10^3, vector(p-1, i, teichmuller(i+O(p^n), T))) time = 60 ms. ? for(i=1,10^3, vector(p-1, i, teichmuller(i+O(p^n)))) time = 1,293 ms. ? 1 + 2*(log(p)/log(2) + hammingweight(p)) %8 = 22.316[...] @eprog\noindent Here the precompuation induces a speedup by a factor $1293/ 60 \approx 21.5$. \misctitle{Caveat} If the accuracy of \kbd{tab} (the argument $n$ above) is lower than the precision of $x$, the \emph{former} is used, i.e. the cached value is not refined to higher accuracy. It the accuracy of \kbd{tab} is larger, then the precision of $x$ is used: \bprog ? Tlow = teichmuller([101, 2]); \\ lower accuracy ! ? teichmuller(2 + O(101^5), Tlow) %10 = 2 + 83*101 + O(101^5) \\ no longer a root of 1 ? Thigh = teichmuller([101, 10]); \\ higher accuracy ? teichmuller(2 + O(101^5), Thigh) %12 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) @eprog Variant: Also available are the functions \fun{GEN}{teich}{GEN x} (\kbd{tab} is \kbd{NULL}) as well as \fun{GEN}{teichmullerinit}{long p, long n}. pari-2.11.2/src/functions/transcendental/agm0000644000175000017500000000101612314242551017446 0ustar billbillFunction: agm Section: transcendental C-Name: agm Prototype: GGp Help: agm(x,y): arithmetic-geometric mean of x and y. Doc: arithmetic-geometric mean of $x$ and $y$. In the case of complex or negative numbers, the optimal AGM is returned (the largest in absolute value over all choices of the signs of the square roots). $p$-adic or power series arguments are also allowed. Note that a $p$-adic agm exists only if $x/y$ is congruent to 1 modulo $p$ (modulo 16 for $p=2$). $x$ and $y$ cannot both be vectors or matrices. pari-2.11.2/src/functions/transcendental/polylog0000644000175000017500000000310011636712103020364 0ustar billbillFunction: polylog Section: transcendental C-Name: polylog0 Prototype: LGD0,L,p Help: polylog(m,x,{flag=0}): m-th polylogarithm of x. flag is optional, and can be 0: default, 1: D_m~-modified m-th polylog of x, 2: D_m-modified m-th polylog of x, 3: P_m-modified m-th polylog of x. Doc: one of the different polylogarithms, depending on \fl: If $\fl=0$ or is omitted: $m^\text{th}$ polylogarithm of $x$, i.e.~analytic continuation of the power series $\text{Li}_m(x)=\sum_{n\ge1}x^n/n^m$ ($x < 1$). Uses the functional equation linking the values at $x$ and $1/x$ to restrict to the case $|x|\leq 1$, then the power series when $|x|^2\le1/2$, and the power series expansion in $\log(x)$ otherwise. Using $\fl$, computes a modified $m^\text{th}$ polylogarithm of $x$. We use Zagier's notations; let $\Re_m$ denote $\Re$ or $\Im$ depending on whether $m$ is odd or even: If $\fl=1$: compute $\tilde D_m(x)$, defined for $|x|\le1$ by $$\Re_m\left(\sum_{k=0}^{m-1} \dfrac{(-\log|x|)^k}{k!}\text{Li}_{m-k}(x) +\dfrac{(-\log|x|)^{m-1}}{m!}\log|1-x|\right).$$ If $\fl=2$: compute $D_m(x)$, defined for $|x|\le1$ by $$\Re_m\left(\sum_{k=0}^{m-1}\dfrac{(-\log|x|)^k}{k!}\text{Li}_{m-k}(x) -\dfrac{1}{2}\dfrac{(-\log|x|)^m}{m!}\right).$$ If $\fl=3$: compute $P_m(x)$, defined for $|x|\le1$ by $$\Re_m\left(\sum_{k=0}^{m-1}\dfrac{2^kB_k}{k!}(\log|x|)^k\text{Li}_{m-k}(x) -\dfrac{2^{m-1}B_m}{m!}(\log|x|)^m\right).$$ These three functions satisfy the functional equation $f_m(1/x) = (-1)^{m-1}f_m(x)$. Variant: Also available is \fun{GEN}{gpolylog}{long m, GEN x, long prec} (\fl = 0). pari-2.11.2/src/functions/transcendental/asin0000644000175000017500000000073713201017466017646 0ustar billbillFunction: asin Section: transcendental C-Name: gasin Prototype: Gp Help: asin(x): arc sine of x. Doc: principal branch of $\sin^{-1}(x) = -i \log(ix + \sqrt{1 - x^2})$. In particular, $\Re(\text{asin}(x))\in [-\pi/2,\pi/2]$ and if $x\in \R$ and $|x|>1$ then $\text{asin}(x)$ is complex. The branch cut is in two pieces: $]-\infty,-1]$, continuous with quadrant II, and $[1,+\infty[$ continuous with quadrant IV. The function satisfies $i \text{asin}(x) = \text{asinh}(ix)$. pari-2.11.2/src/functions/transcendental/atan0000644000175000017500000000072613201017466017635 0ustar billbillFunction: atan Section: transcendental C-Name: gatan Prototype: Gp Help: atan(x): arc tangent of x. Doc: principal branch of $\text{tan}^{-1}(x) = \log ((1+ix)/(1-ix)) / 2i$. In particular the real part of $\text{atan}(x)$ belongs to $]-\pi/2,\pi/2[$. The branch cut is in two pieces: $]-i\infty,-i[$, continuous with quadrant IV, and $]i,+i \infty[$ continuous with quadrant II. The function satisfies $\text{atan}(x) = -i\text{atanh}(ix)$ for all $x\neq \pm i$. pari-2.11.2/src/functions/transcendental/lngamma0000644000175000017500000000200612314242551020316 0ustar billbillFunction: lngamma Section: transcendental C-Name: glngamma Prototype: Gp Help: lngamma(x): logarithm of the gamma function of x. Doc: principal branch of the logarithm of the gamma function of $x$. This function is analytic on the complex plane with non-positive integers removed, and can have much larger arguments than \kbd{gamma} itself. For $x$ a power series such that $x(0)$ is not a pole of \kbd{gamma}, compute the Taylor expansion. (PARI only knows about regular power series and can't include logarithmic terms.) \bprog ? lngamma(1+x+O(x^2)) %1 = -0.57721566490153286060651209008240243104*x + O(x^2) ? lngamma(x+O(x^2)) *** at top-level: lngamma(x+O(x^2)) *** ^----------------- *** lngamma: domain error in lngamma: valuation != 0 ? lngamma(-1+x+O(x^2)) *** lngamma: Warning: normalizing a series with 0 leading term. *** at top-level: lngamma(-1+x+O(x^2)) *** ^-------------------- *** lngamma: domain error in intformal: residue(series, pole) != 0 @eprog pari-2.11.2/src/functions/transcendental/zetamult0000644000175000017500000000330413326135265020560 0ustar billbillFunction: zetamult Section: transcendental C-Name: zetamult0 Prototype: GDGp Help: zetamult(s, {T}): multiple zeta value at integral s = [s1,...,sk]; if given, T is the output of zetamultinit. Doc: For $s$ a vector of positive integers such that $s[1] \geq 2$, returns the multiple zeta value (MZV) $$\zeta(s_1,\dots, s_k) = \sum_{n_1>\dots>n_k>0} n_1^{-s_1}\dots n_k^{-s_k}.$$ \bprog ? zetamult([2,1]) - zeta(3) \\ Euler's identity %1 = 0.E-38 @eprog\noindent If the bit precision is $B$, this function runs in time $\tilde{O}(k B^2)$. If $T$ is provided, it must be the output of \kbd{zetamultinit}$(w)$ for some $w \geq s_1 + \dots + s_k$ and will provide a small speed up, usually about 10\%. \bprog ? T = zetamultinit(20); s = [2,1,1,1,1,1,1,1,1]; ? for(i=1,10^3, zetamult(s)) time = 373 ms. ? for(i=1,10^3, zetamult(s, T)) \\ faster time = 279 ms. ? zetamult(vector(10,i,2), T) %4 = 1.7165384749821433018378232207719985786 E-10 ? zetamult(vector(11,i,2), T) \\ overshoot *** at top-level: zetamult(vector(11,i *** ^-------------------- *** zetamult: domain error in zetamult: weight > 20 @eprog In addition to the above format (\kbd{avec}), the function also accepts an internal binary format \kbd{evec} (each $s_i$ is replaced by $s_i$ bits, all of them 0 but the last one), and an \kbd{index} format (if $e$ is the positive integer attached the \kbd{evec} vector of bits, the index is the integer $e + 2^{k-2}$). The function \kbd{zetamultconvert} allows to pass from one format to the other; the function \kbd{zetamultall} computes simultaneously all MZVs of weight $\sum_{i\leq k} s_i$ up to $n$. Variant: Also available is \fun{GEN}{zetamult}{GEN avec, long prec}. pari-2.11.2/src/functions/transcendental/log0000644000175000017500000000207613201017466017473 0ustar billbillFunction: log Section: transcendental C-Name: glog Prototype: Gp Help: log(x): natural logarithm of x. Description: (gen):gen:prec glog($1, $prec) Doc: principal branch of the natural logarithm of $x \in \C^*$, i.e.~such that $\Im(\log(x))\in{} ]-\pi,\pi]$. The branch cut lies along the negative real axis, continuous with quadrant 2, i.e.~such that $\lim_{b\to 0^+} \log (a+bi) = \log a$ for $a \in\R^*$. The result is complex (with imaginary part equal to $\pi$) if $x\in \R$ and $x < 0$. In general, the algorithm uses the formula $$\log(x) \approx {\pi\over 2\text{agm}(1, 4/s)} - m \log 2, $$ if $s = x 2^m$ is large enough. (The result is exact to $B$ bits provided $s > 2^{B/2}$.) At low accuracies, the series expansion near $1$ is used. $p$-adic arguments are also accepted for $x$, with the convention that $\log(p)=0$. Hence in particular $\exp(\log(x))/x$ is not in general equal to 1 but to a $(p-1)$-th root of unity (or $\pm1$ if $p=2$) times a power of $p$. Variant: For a \typ{PADIC} $x$, the function \fun{GEN}{Qp_log}{GEN x} is also available. pari-2.11.2/src/functions/transcendental/sqr0000644000175000017500000000170311636712103017513 0ustar billbillFunction: sqr Section: transcendental C-Name: gsqr Prototype: G Help: sqr(x): square of x. NOT identical to x*x. Description: (int):int sqri($1) (mp):mp gsqr($1) (gen):gen gsqr($1) Doc: square of $x$. This operation is not completely straightforward, i.e.~identical to $x * x$, since it can usually be computed more efficiently (roughly one-half of the elementary multiplications can be saved). Also, squaring a $2$-adic number increases its precision. For example, \bprog ? (1 + O(2^4))^2 %1 = 1 + O(2^5) ? (1 + O(2^4)) * (1 + O(2^4)) %2 = 1 + O(2^4) @eprog\noindent Note that this function is also called whenever one multiplies two objects which are known to be \emph{identical}, e.g.~they are the value of the same variable, or we are computing a power. \bprog ? x = (1 + O(2^4)); x * x %3 = 1 + O(2^5) ? (1 + O(2^4))^4 %4 = 1 + O(2^6) @eprog\noindent (note the difference between \kbd{\%2} and \kbd{\%3} above). pari-2.11.2/src/functions/transcendental/cotanh0000644000175000017500000000022513201017466020160 0ustar billbillFunction: cotanh Section: transcendental C-Name: gcotanh Prototype: Gp Help: cotanh(x): hyperbolic cotangent of x. Doc: hyperbolic cotangent of $x$. pari-2.11.2/src/functions/transcendental/Pi0000644000175000017500000000045613201017466017262 0ustar billbillFunction: Pi Section: transcendental C-Name: mppi Prototype: p Help: Pi=Pi(): the constant pi, with current precision. Description: ():real:prec mppi($prec) Doc: the constant $\pi$ ($3.14159\cdots$). Note that \kbd{Pi} is one of the few reserved names which cannot be used for user variables. pari-2.11.2/src/functions/transcendental/hyperu0000644000175000017500000000046211636712103020223 0ustar billbillFunction: hyperu Section: transcendental C-Name: hyperu Prototype: GGGp Help: hyperu(a,b,x): U-confluent hypergeometric function. Doc: $U$-confluent hypergeometric function with parameters $a$ and $b$. The parameters $a$ and $b$ can be complex but the present implementation requires $x$ to be positive. pari-2.11.2/src/functions/transcendental/lambertw0000644000175000017500000000034113036414402020515 0ustar billbillFunction: lambertw Section: transcendental C-Name: glambertW Prototype: Gp Help: lambertw(y): solution of the implicit equation x*exp(x)=y. Doc: Lambert $W$ function, solution of the implicit equation $xe^x=y$, for $y > 0$. pari-2.11.2/src/functions/transcendental/sin0000644000175000017500000000015411636712103017476 0ustar billbillFunction: sin Section: transcendental C-Name: gsin Prototype: Gp Help: sin(x): sine of x. Doc: sine of $x$. pari-2.11.2/src/functions/transcendental/tanh0000644000175000017500000000021313036414402017630 0ustar billbillFunction: tanh Section: transcendental C-Name: gtanh Prototype: Gp Help: tanh(x): hyperbolic tangent of x. Doc: hyperbolic tangent of $x$. pari-2.11.2/src/functions/transcendental/besselj0000644000175000017500000000055411636712103020340 0ustar billbillFunction: besselj Section: transcendental C-Name: jbessel Prototype: GGp Help: besselj(nu,x): J-bessel function of index nu and argument x. Doc: $J$-Bessel function of index \var{nu} and argument $x$. If $x$ converts to a power series, the initial factor $(x/2)^\nu/\Gamma(\nu+1)$ is omitted (since it cannot be represented in PARI when $\nu$ is not integral). pari-2.11.2/src/functions/transcendental/besselh10000644000175000017500000000032011636712103020406 0ustar billbillFunction: besselh1 Section: transcendental C-Name: hbessel1 Prototype: GGp Help: besselh1(nu,x): H^1-bessel function of index nu and argument x. Doc: $H^1$-Bessel function of index \var{nu} and argument $x$. pari-2.11.2/src/functions/transcendental/bernfrac0000644000175000017500000000046711636712103020476 0ustar billbillFunction: bernfrac Section: transcendental C-Name: bernfrac Prototype: L Help: bernfrac(x): Bernoulli number B_x, as a rational number. Doc: Bernoulli number\sidx{Bernoulli numbers} $B_x$, where $B_0=1$, $B_1=-1/2$, $B_2=1/6$,\dots, expressed as a rational number. The argument $x$ should be of type integer. pari-2.11.2/src/functions/transcendental/gammamellininvasymp0000644000175000017500000000215513201017466022762 0ustar billbillFunction: gammamellininvasymp Section: transcendental C-Name: gammamellininvasymp Prototype: GDPD0,L, Help: gammamellininvasymp(A,n,{m=0}): return the first n terms of the asymptotic expansion at infinity of the m-th derivative K^m(t) of the inverse Mellin transform of the function f(s)=Gamma_R(s+a_1)*...*Gamma_R(s+a_d), where Vga is the vector [a_1,...,a_d] and Gamma_R(s)=Pi^(-s/2)*gamma(s/2). The result is a vector [M[1]...M[n]] with M[1]=1, such that K^m(t) = \sqrt{2^{d+1}/d}t^{a+m(2/d-1)}e^{-d pi t^{2/d}}\sum_{n\ge0}M[n+1] (pi t^{2n/d})^{-n}, with a = (1-d+sum_ja_j)/d. Doc: Return the first $n$ terms of the asymptotic expansion at infinity of the $m$-th derivative $K^{(m)}(t)$ of the inverse Mellin transform of the function $$f(s) = \Gamma_\R(s+a_1)\*\ldots\*\Gamma_\R(s+a_d)\;,$$ where \kbd{A} is the vector $[a_1,\ldots,a_d]$ and $\Gamma_\R(s)=\pi^{-s/2}\*\Gamma(s/2)$ (Euler's \kbd{gamma}). The result is a vector $[M[1]...M[n]]$ with M[1]=1, such that $$K^{(m)}(t)=\sqrt{2^{d+1}/d}t^{a+m(2/d-1)}e^{-d\pi t^{2/d}} \sum_{n\ge0} M[n+1] (\pi t^{2/d})^{-n} $$ with $a=(1-d+\sum_{1\le j\le d}a_j)/d$. pari-2.11.2/src/functions/transcendental/bernreal0000644000175000017500000000046011636712103020477 0ustar billbillFunction: bernreal Section: transcendental C-Name: bernreal Prototype: Lp Help: bernreal(x): Bernoulli number B_x, as a real number with the current precision. Doc: Bernoulli number\sidx{Bernoulli numbers} $B_x$, as \kbd{bernfrac}, but $B_x$ is returned as a real number (with the current precision). pari-2.11.2/src/functions/transcendental/gamma0000644000175000017500000000145712314242551017775 0ustar billbillFunction: gamma Section: transcendental C-Name: ggamma Prototype: Gp Help: gamma(s): gamma function at s, a complex or p-adic number, or a series. Doc: For $s$ a complex number, evaluates Euler's gamma function \sidx{gamma-function} $$\Gamma(s)=\int_0^\infty t^{s-1}\exp(-t)\,dt.$$ Error if $s$ is a non-positive integer, where $\Gamma$ has a pole. For $s$ a \typ{PADIC}, evaluates the Morita gamma function at $s$, that is the unique continuous $p$-adic function on the $p$-adic integers extending $\Gamma_p(k)=(-1)^k \prod_{j 0 (resp. flag < 0). The answer is guaranteed (i.e a is a norm iff q=1) if L/K is Galois or, under GRH, if S contains all primes less than 12.log(disc(M))^2, where M is the normal closure of L/K. Doc: similar to \kbd{bnfisnorm} but in the relative case. $T$ is as output by \tet{rnfisnorminit} applied to the extension $L/K$. This tries to decide whether the element $a$ in $K$ is the norm of some $x$ in the extension $L/K$. The output is a vector $[x,q]$, where $a = \Norm(x)*q$. The algorithm looks for a solution $x$ which is an $S$-integer, with $S$ a list of places of $K$ containing at least the ramified primes, the generators of the class group of $L$, as well as those primes dividing $a$. If $L/K$ is Galois, then this is enough; otherwise, $\fl$ is used to add more primes to $S$: all the places above the primes $p \leq \fl$ (resp.~$p|\fl$) if $\fl>0$ (resp.~$\fl<0$). The answer is guaranteed (i.e.~$a$ is a norm iff $q = 1$) if the field is Galois, or, under \idx{GRH}, if $S$ contains all primes less than $12\log^2\left|\disc(M)\right|$, where $M$ is the normal closure of $L/K$. If \tet{rnfisnorminit} has determined (or was told) that $L/K$ is \idx{Galois}, and $\fl \neq 0$, a Warning is issued (so that you can set $\fl = 1$ to check whether $L/K$ is known to be Galois, according to $T$). Example: \bprog bnf = bnfinit(y^3 + y^2 - 2*y - 1); p = x^2 + Mod(y^2 + 2*y + 1, bnf.pol); T = rnfisnorminit(bnf, p); rnfisnorm(T, 17) @eprog\noindent checks whether $17$ is a norm in the Galois extension $\Q(\beta) / \Q(\alpha)$, where $\alpha^3 + \alpha^2 - 2\alpha - 1 = 0$ and $\beta^2 + \alpha^2 + 2\alpha + 1 = 0$ (it is). pari-2.11.2/src/functions/number_fields/nfeltmod0000644000175000017500000000064713201017466020335 0ustar billbillFunction: nfeltmod Section: number_fields C-Name: nfmod Prototype: GGG Help: nfeltmod(nf,x,y): gives r such that r=x-qy is small with q algebraic integer. Doc: given two elements $x$ and $y$ in \var{nf}, computes an element $r$ of $\var{nf}$ of the form $r=x-qy$ with $q$ and algebraic integer, and such that $r$ is small. This is functionally identical to $$\kbd{x - nfmul(\var{nf},round(nfdiv(\var{nf},x,y)),y)}.$$ pari-2.11.2/src/functions/number_fields/subgrouplist0000644000175000017500000000374511636712103021271 0ustar billbillFunction: subgrouplist Section: number_fields C-Name: subgrouplist0 Prototype: GDGD0,L, Help: subgrouplist(bnr,{bound},{flag=0}): bnr being as output by bnrinit or a list of cyclic components of a finite Abelian group G, outputs the list of subgroups of G (of index bounded by bound, if not omitted), given as HNF left divisors of the SNF matrix corresponding to G. If flag=0 (default) and bnr is as output by bnrinit, gives only the subgroups for which the modulus is the conductor. Doc: \var{bnr} being as output by \kbd{bnrinit} or a list of cyclic components of a finite Abelian group $G$, outputs the list of subgroups of $G$. Subgroups are given as HNF left divisors of the SNF matrix corresponding to $G$. If $\fl=0$ (default) and \var{bnr} is as output by \kbd{bnrinit}, gives only the subgroups whose modulus is the conductor. Otherwise, the modulus is not taken into account. If \var{bound} is present, and is a positive integer, restrict the output to subgroups of index less than \var{bound}. If \var{bound} is a vector containing a single positive integer $B$, then only subgroups of index exactly equal to $B$ are computed. For instance \bprog ? subgrouplist([6,2]) %1 = [[6, 0; 0, 2], [2, 0; 0, 2], [6, 3; 0, 1], [2, 1; 0, 1], [3, 0; 0, 2], [1, 0; 0, 2], [6, 0; 0, 1], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] ? subgrouplist([6,2],3) \\@com index less than 3 %2 = [[2, 1; 0, 1], [1, 0; 0, 2], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] ? subgrouplist([6,2],[3]) \\@com index 3 %3 = [[3, 0; 0, 1]] ? bnr = bnrinit(bnfinit(x), [120,[1]], 1); ? L = subgrouplist(bnr, [8]); @eprog\noindent In the last example, $L$ corresponds to the 24 subfields of $\Q(\zeta_{120})$, of degree $8$ and conductor $120\infty$ (by setting \fl, we see there are a total of $43$ subgroups of degree $8$). \bprog ? vector(#L, i, galoissubcyclo(bnr, L[i])) @eprog\noindent will produce their equations. (For a general base field, you would have to rely on \tet{bnrstark}, or \tet{rnfkummer}.) pari-2.11.2/src/functions/number_fields/bnfisprincipal0000644000175000017500000000530513201017466021524 0ustar billbillFunction: bnfisprincipal Section: number_fields C-Name: bnfisprincipal0 Prototype: GGD1,L, Help: bnfisprincipal(bnf,x,{flag=1}): bnf being output by bnfinit (with flag<=2), gives [v,alpha], where v is the vector of exponents on the class group generators and alpha is the generator of the resulting principal ideal. In particular x is principal if and only if v is the zero vector. flag is optional, whose binary digits mean 1: output [v,alpha] (only v if unset); 2: increase precision until alpha can be computed (do not insist if unset). Doc: $\var{bnf}$ being the \sidx{principal ideal} number field data output by \kbd{bnfinit}, and $x$ being an ideal, this function tests whether the ideal is principal or not. The result is more complete than a simple true/false answer and solves general discrete logarithm problem. Assume the class group is $\oplus (\Z/d_i\Z)g_i$ (where the generators $g_i$ and their orders $d_i$ are respectively given by \kbd{bnf.gen} and \kbd{bnf.cyc}). The routine returns a row vector $[e,t]$, where $e$ is a vector of exponents $0 \leq e_i < d_i$, and $t$ is a number field element such that $$ x = (t) \prod_i g_i^{e_i}.$$ For \emph{given} $g_i$ (i.e. for a given \kbd{bnf}), the $e_i$ are unique, and $t$ is unique modulo units. In particular, $x$ is principal if and only if $e$ is the zero vector. Note that the empty vector, which is returned when the class number is $1$, is considered to be a zero vector (of dimension $0$). \bprog ? K = bnfinit(y^2+23); ? K.cyc %2 = [3] ? K.gen %3 = [[2, 0; 0, 1]] \\ a prime ideal above 2 ? P = idealprimedec(K,3)[1]; \\ a prime ideal above 3 ? v = bnfisprincipal(K, P) %5 = [[2]~, [3/4, 1/4]~] ? idealmul(K, v[2], idealfactorback(K, K.gen, v[1])) %6 = [3 0] [0 1] ? % == idealhnf(K, P) %7 = 1 @eprog \noindent The binary digits of \fl mean: \item $1$: If set, outputs $[e,t]$ as explained above, otherwise returns only $e$, which is much easier to compute. The following idiom only tests whether an ideal is principal: \bprog is_principal(bnf, x) = !bnfisprincipal(bnf,x,0); @eprog \item $2$: It may not be possible to recover $t$, given the initial accuracy to which the \kbd{bnf} structure was computed. In that case, a warning is printed and $t$ is set equal to the empty vector \kbd{[]\til}. If this bit is set, increase the precision and recompute needed quantities until $t$ can be computed. Warning: setting this may induce \emph{lengthy} computations. Variant: Instead of the above hardcoded numerical flags, one should rather use an or-ed combination of the symbolic flags \tet{nf_GEN} (include generators, possibly a place holder if too difficult) and \tet{nf_FORCE} (insist on finding the generators). pari-2.11.2/src/functions/number_fields/idealval0000644000175000017500000000103613201017466020277 0ustar billbillFunction: idealval Section: number_fields C-Name: gpidealval Prototype: GGG Help: idealval(nf,x,pr): valuation at pr given in idealprimedec format of the ideal x in the number field nf. Doc: gives the valuation of the ideal $x$ at the prime ideal \var{pr} in the number field $\var{nf}$, where \var{pr} is in \kbd{idealprimedec} format. The valuation of the $0$ ideal is \kbd{+oo}. Variant: Also available is \fun{long}{idealval}{GEN nf, GEN x, GEN pr}, which returns \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer. pari-2.11.2/src/functions/number_fields/bnfnarrow0000644000175000017500000000151113326135265020520 0ustar billbillFunction: bnfnarrow Section: number_fields C-Name: bnfnarrow Prototype: G Help: bnfnarrow(bnf): given a big number field as output by bnfinit, gives as a 3-component vector the structure of the narrow class group. Doc: \var{bnf} being as output by \kbd{bnfinit}, computes the narrow class group of \var{bnf}. The output is a 3-component row vector $v$ analogous to the corresponding class group component \kbd{\var{bnf}.clgp}: the first component is the narrow class number \kbd{$v$.no}, the second component is a vector containing the SNF\sidx{Smith normal form} cyclic components \kbd{$v$.cyc} of the narrow class group, and the third is a vector giving the generators of the corresponding \kbd{$v$.gen} cyclic groups. Note that this function is a special case of \kbd{bnrinit}; the \var{bnf} need not contain fundamental units. pari-2.11.2/src/functions/number_fields/galoisisabelian0000644000175000017500000000103611636712103021644 0ustar billbillFunction: galoisisabelian Section: number_fields C-Name: galoisisabelian Prototype: GD0,L, Help: galoisisabelian(gal,{flag=0}): gal being as output by galoisinit, return 0 if gal is not abelian, the HNF matrix of gal over gal.gen if flag=0, 1 if flag is 1, and the SNF of gal is flag=2. Doc: \var{gal} being as output by \kbd{galoisinit}, return $0$ if \var{gal} is not an abelian group, and the HNF matrix of \var{gal} over \kbd{gal.gen} if $fl=0$, $1$ if $fl=1$. This command also accepts subgroups returned by \kbd{galoissubgroups}. pari-2.11.2/src/functions/number_fields/idealinv0000644000175000017500000000063611636712103020316 0ustar billbillFunction: idealinv Section: number_fields C-Name: idealinv Prototype: GG Help: idealinv(nf,x): inverse of the ideal x in the number field nf. Description: (gen, gen):gen idealinv($1, $2) Doc: inverse of the ideal $x$ in the number field $\var{nf}$, given in HNF. If $x$ is an extended ideal\sidx{ideal (extended)}, its principal part is suitably updated: i.e. inverting $[I,t]$, yields $[I^{-1}, 1/t]$. pari-2.11.2/src/functions/number_fields/bnfsignunit0000644000175000017500000000176113201017466021051 0ustar billbillFunction: bnfsignunit Section: number_fields C-Name: signunits Prototype: G Help: bnfsignunit(bnf): matrix of signs of the real embeddings of the system of fundamental units found by bnfinit. Doc: $\var{bnf}$ being as output by \kbd{bnfinit}, this computes an $r_1\times(r_1+r_2-1)$ matrix having $\pm1$ components, giving the signs of the real embeddings of the fundamental units. The following functions compute generators for the totally positive units: \bprog /* exponents of totally positive units generators on bnf.tufu */ tpuexpo(bnf)= { my(K, S = bnfsignunit(bnf), [m,n] = matsize(S)); \\ m = bnf.r1, n = r1+r2-1 S = matrix(m,n, i,j, if (S[i,j] < 0, 1,0)); S = concat(vectorv(m,i,1), S); \\ add sign(-1) K = matker(S * Mod(1,2)); if (K, mathnfmodid(lift(K), 2), 2*matid(n+1)) } /* totally positive fundamental units */ tpu(bnf)= { my(ex = tpuexpo(bnf)[,2..-1]); \\ remove ex[,1], corresponds to 1 or -1 vector(#ex, i, nffactorback(bnf, bnf.tufu, ex[,i])); } @eprog pari-2.11.2/src/functions/number_fields/bnrgaloisapply0000644000175000017500000000070613201017466021547 0ustar billbillFunction: bnrgaloisapply Section: number_fields C-Name: bnrgaloisapply Prototype: GGG Help: bnrgaloisapply(bnr, mat, H): apply the automorphism given by its matrix mat to the congruence subgroup H given as a HNF matrix. The matrix mat can be computed with bnrgaloismatrix. Doc: apply the automorphism given by its matrix \var{mat} to the congruence subgroup $H$ given as a HNF matrix. The matrix \var{mat} can be computed with \tet{bnrgaloismatrix}. pari-2.11.2/src/functions/number_fields/nfhnf0000644000175000017500000000144113326135265017623 0ustar billbillFunction: nfhnf Section: number_fields C-Name: nfhnf0 Prototype: GGD0,L, Help: nfhnf(nf,x,{flag=0}): if x=[A,I], gives a pseudo-basis [B,J] of the module sum A_jI_j. If flag is non-zero, return [[B,J], U], where U is the transformation matrix such that AU = [0|B]. Doc: given a pseudo-matrix $(A,I)$, finds a pseudo-basis $(B,J)$ in \idx{Hermite normal form} of the module it generates. If $\fl$ is non-zero, also return the transformation matrix $U$ such that $AU = [0|B]$. Variant: Also available: \fun{GEN}{nfhnf}{GEN nf, GEN x} ($\fl = 0$). \fun{GEN}{rnfsimplifybasis}{GEN bnf, GEN x} simplifies the pseudo-basis $x = (A,I)$, returning a pseudo-basis $(B,J)$. The ideals in the list $J$ are integral, primitive and either trivial (equal to the full ring of integer) or non-principal. pari-2.11.2/src/functions/number_fields/matbasistoalg0000644000175000017500000000061713201017466021354 0ustar billbillFunction: matbasistoalg Section: number_fields C-Name: matbasistoalg Prototype: GG Obsolete: 2016-08-08 Help: matbasistoalg(nf,x): nfbasistoalg applied to every element of the matrix or vector x. Doc: This function is deprecated, use \kbd{apply}. $\var{nf}$ being a number field in \kbd{nfinit} format, and $x$ a (row or column) vector or matrix, apply \tet{nfbasistoalg} to each entry of $x$. pari-2.11.2/src/functions/number_fields/nfeltmulmodpr0000644000175000017500000000105113201017466021403 0ustar billbillFunction: nfeltmulmodpr Section: number_fields C-Name: nfmulmodpr Prototype: GGGG Obsolete: 2016-08-09 Help: nfeltmulmodpr(nf,x,y,pr): this function is obsolete, use nfmodpr. Doc: this function is obsolete, use \kbd{nfmodpr}. Given two elements $x$ and $y$ in \var{nf} and \var{pr} a prime ideal in \kbd{modpr} format (see \tet{nfmodprinit}), computes their product $x*y$ modulo the prime ideal \var{pr}. Variant: This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. pari-2.11.2/src/functions/number_fields/idealispower0000644000175000017500000000122613326135265021214 0ustar billbillFunction: idealispower Section: number_fields C-Name: idealispower Prototype: lGGLD& Help: idealispower(nf,A,n,{&B}): return 1 if A = B^n is an n-th power else return 0. Doc: let \var{nf} be a number field and $n > 0$ be a positive integer. Return $1$ if the fractional ideal $A = B^n$ is an $n$-th power and $0$ otherwise. If the argument $B$ is present, set it to the $n$-th root of $A$, in HNF. \bprog ? K = nfinit(x^3 - 2); ? A = [46875, 30966, 9573; 0, 3, 0; 0, 0, 3]; ? idealispower(K, A, 3, &B) %3 = 1 ? B %4 = [75 22 41] [ 0 1 0] [ 0 0 1] ? A = [9375, 2841, 198; 0, 3, 0; 0, 0, 3]; ? idealispower(K, A, 3) %5 = 0 @eprog\noindent pari-2.11.2/src/functions/number_fields/nfeltpowmodpr0000644000175000017500000000104013201017466021411 0ustar billbillFunction: nfeltpowmodpr Section: number_fields C-Name: nfpowmodpr Prototype: GGGG Obsolete: 2016-08-09 Help: nfeltpowmodpr(nf,x,k,pr): this function is obsolete, use nfmodpr. Doc: this function is obsolete, use \kbd{nfmodpr}. Given an element $x$ in \var{nf}, an integer $k$ and a prime ideal \var{pr} in \kbd{modpr} format (see \tet{nfmodprinit}), computes $x^k$ modulo the prime ideal \var{pr}. Variant: This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. pari-2.11.2/src/functions/number_fields/galoisgetpol0000644000175000017500000000310013457566441021220 0ustar billbillFunction: galoisgetpol Section: number_fields C-Name: galoisgetpol Prototype: LD0,L,D1,L, Description: (small):int galoisnbpol($1) (small,):int galoisnbpol($1) (small,,):int galoisnbpol($1) (small,small,small):vec galoisgetpol($1, $2 ,$3) Help: galoisgetpol(a,{b},{s}): query the galpol package for a polynomial with Galois group isomorphic to GAP4(a,b), totally real if s=1 (default) and totally complex if s=2. The output is a vector [pol, den] where pol is the polynomial and den is the common denominator of the conjugates expressed as a polynomial in a root of pol. If b and s are omitted, return the number of isomorphism classes of groups of order a. Doc: Query the \kbd{galpol} package for a polynomial with Galois group isomorphic to GAP4(a,b), totally real if $s=1$ (default) and totally complex if $s=2$. The current version of \kbd{galpol} supports groups of order $a\leq 143$. The output is a vector [\kbd{pol}, \kbd{den}] where \item \kbd{pol} is the polynomial of degree $a$ \item \kbd{den} is the denominator of \kbd{nfgaloisconj(pol)}. Pass it as an optional argument to \tet{galoisinit} or \tet{nfgaloisconj} to speed them up: \bprog ? [pol,den] = galoisgetpol(64,4,1); ? G = galoisinit(pol); time = 352ms ? galoisinit(pol, den); \\ passing 'den' speeds up the computation time = 264ms ? % == %` %4 = 1 \\ same answer @eprog If $b$ and $s$ are omitted, return the number of isomorphism classes of groups of order $a$. Variant: Also available is \fun{GEN}{galoisnbpol}{long a} when $b$ and $s$ are omitted. pari-2.11.2/src/functions/number_fields/idealintersect0000644000175000017500000000136112314242551021515 0ustar billbillFunction: idealintersect Section: number_fields C-Name: idealintersect Prototype: GGG Help: idealintersect(nf,A,B): intersection of two ideals A and B in the number field defined by nf. Doc: intersection of the two ideals $A$ and $B$ in the number field $\var{nf}$. The result is given in HNF. \bprog ? nf = nfinit(x^2+1); ? idealintersect(nf, 2, x+1) %2 = [2 0] [0 2] @eprog This function does not apply to general $\Z$-modules, e.g.~orders, since its arguments are replaced by the ideals they generate. The following script intersects $\Z$-modules $A$ and $B$ given by matrices of compatible dimensions with integer coefficients: \bprog ZM_intersect(A,B) = { my(Ker = matkerint(concat(A,B))); mathnf( A * Ker[1..#A,] ) } @eprog pari-2.11.2/src/functions/number_fields/rnfdedekind0000644000175000017500000000667013201017466021004 0ustar billbillFunction: rnfdedekind Section: number_fields C-Name: rnfdedekind Prototype: GGDGD0,L, Help: rnfdedekind(nf,pol,{pr},{flag=0}): relative Dedekind criterion over the number field K, represented by nf, applied to the order O_K[X]/(P), modulo the prime ideal pr (at all primes if pr omitted, in which case flag is automatically set to 1). P is assumed to be monic, irreducible, in O_K[X]. Returns [max,basis,v], where basis is a pseudo-basis of the enlarged order, max is 1 iff this order is pr-maximal, and v is the valuation at pr of the order discriminant. If flag is set, just return 1 if the order is maximal, and 0 if not. Doc: given a number field $K$ coded by $\var{nf}$ and a monic polynomial $P\in \Z_K[X]$, irreducible over $K$ and thus defining a relative extension $L$ of $K$, applies \idx{Dedekind}'s criterion to the order $\Z_K[X]/(P)$, at the prime ideal \var{pr}. It is possible to set \var{pr} to a vector of prime ideals (test maximality at all primes in the vector), or to omit altogether, in which case maximality at \emph{all} primes is tested; in this situation \fl\ is automatically set to $1$. The default historic behavior (\fl\ is 0 or omitted and \var{pr} is a single prime ideal) is not so useful since \kbd{rnfpseudobasis} gives more information and is generally not that much slower. It returns a 3-component vector $[\var{max}, \var{basis}, v]$: \item \var{basis} is a pseudo-basis of an enlarged order $O$ produced by Dedekind's criterion, containing the original order $\Z_K[X]/(P)$ with index a power of \var{pr}. Possibly equal to the original order. \item \var{max} is a flag equal to 1 if the enlarged order $O$ could be proven to be \var{pr}-maximal and to 0 otherwise; it may still be maximal in the latter case if \var{pr} is ramified in $L$, \item $v$ is the valuation at \var{pr} of the order discriminant. If \fl\ is non-zero, on the other hand, we just return $1$ if the order $\Z_K[X]/(P)$ is \var{pr}-maximal (resp.~maximal at all relevant primes, as described above), and $0$ if not. This is much faster than the default, since the enlarged order is not computed. \bprog ? nf = nfinit(y^2-3); P = x^3 - 2*y; ? pr3 = idealprimedec(nf,3)[1]; ? rnfdedekind(nf, P, pr3) %3 = [1, [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, 1]], 8] ? rnfdedekind(nf, P, pr3, 1) %4 = 1 @eprog\noindent In this example, \kbd{pr3} is the ramified ideal above $3$, and the order generated by the cube roots of $y$ is already \kbd{pr3}-maximal. The order-discriminant has valuation $8$. On the other hand, the order is not maximal at the prime above 2: \bprog ? pr2 = idealprimedec(nf,2)[1]; ? rnfdedekind(nf, P, pr2, 1) %6 = 0 ? rnfdedekind(nf, P, pr2) %7 = [0, [[2, 0, 0; 0, 1, 0; 0, 0, 1], [[1, 0; 0, 1], [1, 0; 0, 1], [1, 1/2; 0, 1/2]]], 2] @eprog The enlarged order is not proven to be \kbd{pr2}-maximal yet. In fact, it is; it is in fact the maximal order: \bprog ? B = rnfpseudobasis(nf, P) %8 = [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, [1, 1/2; 0, 1/2]], [162, 0; 0, 162], -1] ? idealval(nf,B[3], pr2) %9 = 2 @eprog\noindent It is possible to use this routine with non-monic $P = \sum_{i\leq n} a_i X^i \in \Z_K[X]$ if $\fl = 1$; in this case, we test maximality of Dedekind's order generated by $$1, a_n \alpha, a_n\alpha^2 + a_{n-1}\alpha, \dots, a_n\alpha^{n-1} + a_{n-1}\alpha^{n-2} + \cdots + a_1\alpha.$$ The routine will fail if $P$ is $0$ on the projective line over the residue field $\Z_K/\kbd{pr}$ (FIXME). pari-2.11.2/src/functions/number_fields/nfsolvemodpr0000644000175000017500000000147113201017466021237 0ustar billbillFunction: nfsolvemodpr Section: number_fields C-Name: nfsolvemodpr Prototype: GGGG Obsolete: 2016-08-09 Help: nfsolvemodpr(nf,a,b,P): this function is obsolete, use nfmodpr. Doc: this function is obsolete, use \kbd{nfmodpr}. Let $P$ be a prime ideal in \key{modpr} format (see \kbd{nfmodprinit}), let $a$ be a matrix, invertible over the residue field, and let $b$ be a column vector or matrix. This function returns a solution of $a\cdot x = b$; the coefficients of $x$ are lifted to \var{nf} elements. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K, 3)[1]; ? P = nfmodprinit(K, P); ? a = [y+1, y; y, 0]; b = [1, y]~ ? nfsolvemodpr(K, a,b, P) %5 = [1, 2]~ @eprog Variant: This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nfM\_to\_FqM}, then work there. pari-2.11.2/src/functions/number_fields/idealfactor0000644000175000017500000000221413326135265021000 0ustar billbillFunction: idealfactor Section: number_fields C-Name: gpidealfactor Prototype: GGDG Help: idealfactor(nf,x,{lim}): factorization of the ideal x into prime ideals in the number field nf. If lim is set return partial factorization, using primes < lim. Doc: factors into prime ideal powers the ideal $x$ in the number field $\var{nf}$. The output format is similar to the \kbd{factor} function, and the prime ideals are represented in the form output by the \kbd{idealprimedec} function. If \var{lim} is set, return partial factorization, including only prime ideals above rational primes $< \var{lim}$. \bprog ? nf = nfinit(x^3-2); ? idealfactor(nf, x) \\ a prime ideal above 2 %2 = [[2, [0, 1, 0]~, 3, 1, ...] 1] ? A = idealhnf(nf, 6*x, 4+2*x+x^2) %3 = [6 0 4] [0 6 2] [0 0 1] ? idealfactor(nf, A) %4 = [[2, [0, 1, 0]~, 3, 1, ...] 2] [[3, [1, 1, 0]~, 3, 1, ...] 2] ? idealfactor(nf, A, 3) \\ restrict to primes above p < 3 %5 = [[2, [0, 1, 0]~, 3, 1, ...] 2] @eprog Variant: This function should only be used by the \kbd{gp} interface. Use directly \fun{GEN}{idealfactor}{GEN x} or \fun{GEN}{idealfactor_limit}{GEN x, ulong lim}. pari-2.11.2/src/functions/number_fields/nfeltreduce0000644000175000017500000000054711636712103021024 0ustar billbillFunction: nfeltreduce Section: number_fields C-Name: nfreduce Prototype: GGG Help: nfeltreduce(nf,a,id): gives r such that a-r is in the ideal id and r is small. Doc: given an ideal \var{id} in Hermite normal form and an element $a$ of the number field $\var{nf}$, finds an element $r$ in $\var{nf}$ such that $a-r$ belongs to the ideal and $r$ is small. pari-2.11.2/src/functions/number_fields/rnfbasistoalg0000644000175000017500000000064611636712103021362 0ustar billbillFunction: rnfbasistoalg Section: number_fields C-Name: rnfbasistoalg Prototype: GG Help: rnfbasistoalg(rnf,x): relative version of nfbasistoalg, where rnf is a relative numberfield. Doc: computes the representation of $x$ as a polmod with polmods coefficients. Here, $\var{rnf}$ is a relative number field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an element of $L$ expressed on the relative integral basis. pari-2.11.2/src/functions/number_fields/idealappr0000644000175000017500000000221013326135265020460 0ustar billbillFunction: idealappr Section: number_fields C-Name: idealappr0 Prototype: GGD0,L, Help: idealappr(nf,x,{flag}): x being a fractional ideal, gives an element b such that v_p(b)=v_p(x) for all prime ideals p dividing x, and v_p(b)>=0 for all other p; x may also be a prime ideal factorization with possibly zero exponents. flag is deprecated (ignored), kept for backward compatibility. Doc: if $x$ is a fractional ideal (given in any form), gives an element $\alpha$ in $\var{nf}$ such that for all prime ideals $\goth{p}$ such that the valuation of $x$ at $\goth{p}$ is non-zero, we have $v_{\goth{p}}(\alpha)=v_{\goth{p}}(x)$, and $v_{\goth{p}}(\alpha)\ge0$ for all other $\goth{p}$. The argument $x$ may also be given as a prime ideal factorization, as output by \kbd{idealfactor}, but allowing zero exponents. This yields an element $\alpha$ such that for all prime ideals $\goth{p}$ occurring in $x$, $v_{\goth{p}}(\alpha) = v_{\goth{p}}(x)$; for all other prime ideals, $v_{\goth{p}}(\alpha)\ge0$. flag is deprecated (ignored), kept for backward compatibility. Variant: Use directly \fun{GEN}{idealappr}{GEN nf, GEN x} since \fl is ignored. pari-2.11.2/src/functions/number_fields/nffactorback0000644000175000017500000000146213326135265021152 0ustar billbillFunction: nffactorback Section: number_fields C-Name: nffactorback Prototype: GGDG Help: nffactorback(nf,f,{e}): given a factorization f, returns the factored object back as an nf element. Doc: gives back the \var{nf} element corresponding to a factorization. The integer $1$ corresponds to the empty factorization. If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being integral), and the corresponding factorization is the product of the $f[i]^{e[i]}$. If not, and $f$ is vector, it is understood as in the preceding case with $e$ a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a regular factorization matrix. \bprog ? nf = nfinit(y^2+1); ? nffactorback(nf, [3, y+1, [1,2]~], [1, 2, 3]) %2 = [12, -66]~ ? 3 * (I+1)^2 * (1+2*I)^3 %3 = 12 - 66*I @eprog pari-2.11.2/src/functions/number_fields/nfgaloisapply0000644000175000017500000000423313201017466021370 0ustar billbillFunction: nfgaloisapply Section: number_fields C-Name: galoisapply Prototype: GGG Help: nfgaloisapply(nf,aut,x): apply the Galois automorphism aut to the object x (element or ideal) in the number field nf. Doc: let $\var{nf}$ be a number field as output by \kbd{nfinit}, and let \var{aut} be a \idx{Galois} automorphism of $\var{nf}$ expressed by its image on the field generator (such automorphisms can be found using \kbd{nfgaloisconj}). The function computes the action of the automorphism \var{aut} on the object $x$ in the number field; $x$ can be a number field element, or an ideal (possibly extended). Because of possible confusion with elements and ideals, other vector or matrix arguments are forbidden. \bprog ? nf = nfinit(x^2+1); ? L = nfgaloisconj(nf) %2 = [-x, x]~ ? aut = L[1]; /* the non-trivial automorphism */ ? nfgaloisapply(nf, aut, x) %4 = Mod(-x, x^2 + 1) ? P = idealprimedec(nf,5); /* prime ideals above 5 */ ? nfgaloisapply(nf, aut, P[2]) == P[1] %6 = 0 \\ !!!! ? idealval(nf, nfgaloisapply(nf, aut, P[2]), P[1]) %7 = 1 @eprog\noindent The surprising failure of the equality test (\kbd{\%7}) is due to the fact that although the corresponding prime ideals are equal, their representations are not. (A prime ideal is specified by a uniformizer, and there is no guarantee that applying automorphisms yields the same elements as a direct \kbd{idealprimedec} call.) The automorphism can also be given as a column vector, representing the image of \kbd{Mod(x, nf.pol)} as an algebraic number. This last representation is more efficient and should be preferred if a given automorphism must be used in many such calls. \bprog ? nf = nfinit(x^3 - 37*x^2 + 74*x - 37); ? aut = nfgaloisconj(nf)[2]; \\ @com an automorphism in basistoalg form %2 = -31/11*x^2 + 1109/11*x - 925/11 ? AUT = nfalgtobasis(nf, aut); \\ @com same in algtobasis form %3 = [16, -6, 5]~ ? v = [1, 2, 3]~; nfgaloisapply(nf, aut, v) == nfgaloisapply(nf, AUT, v) %4 = 1 \\ @com same result... ? for (i=1,10^5, nfgaloisapply(nf, aut, v)) time = 463 ms. ? for (i=1,10^5, nfgaloisapply(nf, AUT, v)) time = 343 ms. \\ @com but the latter is faster @eprog pari-2.11.2/src/functions/number_fields/nfeltadd0000644000175000017500000000046313326135265020310 0ustar billbillFunction: nfeltadd Section: number_fields C-Name: nfadd Prototype: GGG Help: nfeltadd(nf,x,y): element x+y in nf. Doc: given two elements $x$ and $y$ in \var{nf}, computes their sum $x+y$ in the number field $\var{nf}$. \bprog ? nf = nfinit(1+x^2); ? nfeltadd(nf, 1, x) \\ 1 + I %2 = [1, 1]~ @eprog pari-2.11.2/src/functions/number_fields/bnfsunit0000644000175000017500000000220211636712103020342 0ustar billbillFunction: bnfsunit Section: number_fields C-Name: bnfsunit Prototype: GGp Help: bnfsunit(bnf,S): compute the fundamental S-units of the number field bnf output by bnfinit, S being a list of prime ideals. res[1] contains the S-units, res[5] the S-classgroup. See manual for details. Doc: computes the fundamental $S$-units of the number field $\var{bnf}$ (output by \kbd{bnfinit}), where $S$ is a list of prime ideals (output by \kbd{idealprimedec}). The output is a vector $v$ with 6 components. $v[1]$ gives a minimal system of (integral) generators of the $S$-unit group modulo the unit group. $v[2]$ contains technical data needed by \kbd{bnfissunit}. $v[3]$ is an empty vector (used to give the logarithmic embeddings of the generators in $v[1]$ in version 2.0.16). $v[4]$ is the $S$-regulator (this is the product of the regulator, the determinant of $v[2]$ and the natural logarithms of the norms of the ideals in $S$). $v[5]$ gives the $S$-class group structure, in the usual format (a row vector whose three components give in order the $S$-class number, the cyclic components and the generators). $v[6]$ is a copy of $S$. pari-2.11.2/src/functions/number_fields/rnfbasis0000644000175000017500000000141713326135265020336 0ustar billbillFunction: rnfbasis Section: number_fields C-Name: rnfbasis Prototype: GG Help: rnfbasis(bnf,M): given a projective Z_K-module M as output by rnfpseudobasis or rnfsteinitz, gives either a basis of M if it is free, or an n+1-element generating set. Doc: let $K$ the field represented by \var{bnf}, as output by \kbd{bnfinit}. $M$ is a projective $\Z_K$-module of rank $n$ ($M\otimes K$ is an $n$-dimensional $K$-vector space), given by a pseudo-basis of size $n$. The routine returns either a true $\Z_K$-basis of $M$ (of size $n$) if it exists, or an $n+1$-element generating set of $M$ if not. It is allowed to use a monic irreducible polynomial $P$ in $K[X]$ instead of $M$, in which case, $M$ is defined as the ring of integers of $K[X]/(P)$, viewed as a $\Z_K$-module. pari-2.11.2/src/functions/number_fields/rnfisfree0000644000175000017500000000077711636712103020514 0ustar billbillFunction: rnfisfree Section: number_fields C-Name: rnfisfree Prototype: lGG Help: rnfisfree(bnf,x): given an order x as output by rnfpseudobasis or rnfsteinitz, outputs true (1) or false (0) according to whether the order is free or not. Doc: given $\var{bnf}$ as output by \kbd{bnfinit}, and either a polynomial $x$ with coefficients in $\var{bnf}$ defining a relative extension $L$ of $\var{bnf}$, or a pseudo-basis $x$ of such an extension, returns true (1) if $L/\var{bnf}$ is free, false (0) if not. pari-2.11.2/src/functions/number_fields/ideallog0000644000175000017500000000245213326135265020307 0ustar billbillFunction: ideallog Section: number_fields C-Name: ideallog Prototype: DGGG Help: ideallog({nf},x,bid): if bid is a big ideal, as given by idealstar(nf,D,...), gives the vector of exponents on the generators bid.gen (even if these generators have not been explicitly computed). Doc: $\var{nf}$ is a number field, \var{bid} is as output by \kbd{idealstar(nf, D, \dots)} and $x$ a non-necessarily integral element of \var{nf} which must have valuation equal to 0 at all prime ideals in the support of $\kbd{D}$. This function computes the discrete logarithm of $x$ on the generators given in \kbd{\var{bid}.gen}. In other words, if $g_i$ are these generators, of orders $d_i$ respectively, the result is a column vector of integers $(x_i)$ such that $0\le x_i p:= (1,26)(2,5)(3,17)(4,32)(6,9)(7,11)(8,24)(10,13)(12,15)(14,27) (16,22)(18,28)(19,20)(21,29)(23,31)(25,30) gap> PermToGP(p,32); [ 26, 5, 17, 32, 2, 9, 11, 24, 6, 13, 7, 15, 10, 27, 12, 22, 3, 28, 20, 19, 29, 16, 31, 8, 30, 1, 14, 18, 21, 25, 23, 4 ] @eprog pari-2.11.2/src/functions/number_fields/idealnumden0000644000175000017500000000061113201017466021001 0ustar billbillFunction: idealnumden Section: number_fields C-Name: idealnumden Prototype: GG Help: idealnumden(nf,x): returns [A,B], where A,B are coprime integer ideals such that x = A/B. Doc: returns $[A,B]$, where $A,B$ are coprime integer ideals such that $x = A/B$, in the number field $\var{nf}$. \bprog ? nf = nfinit(x^2+1); ? idealnumden(nf, (x+1)/2) %2 = [[1, 0; 0, 1], [2, 1; 0, 1]] @eprog pari-2.11.2/src/functions/number_fields/idealprimedec0000644000175000017500000000420413201017466021305 0ustar billbillFunction: idealprimedec Section: number_fields C-Name: idealprimedec_limit_f Prototype: GGD0,L, Description: (gen, gen):vec idealprimedec($1, $2) (gen, gen, ?small):vec idealprimedec_limit_f($1, $2, $3) Help: idealprimedec(nf,p,{f=0}): prime ideal decomposition of the prime number p in the number field nf as a vector of prime ideals. If f is present and non-zero, restrict the result to primes of residue degree <= f. Doc: computes the prime ideal decomposition of the (positive) prime number $p$ in the number field $K$ represented by \var{nf}. If a non-prime $p$ is given the result is undefined. If $f$ is present and non-zero, restrict the result to primes of residue degree $\leq f$. The result is a vector of \tev{prid} structures, each representing one of the prime ideals above $p$ in the number field $\var{nf}$. The representation $\kbd{pr}=[p,a,e,f,\var{mb}]$ of a prime ideal means the following: $a$ is an algebraic integer in the maximal order $\Z_K$ and the prime ideal is equal to $\goth{p} = p\Z_K + a\Z_K$; $e$ is the ramification index; $f$ is the residual index; finally, \var{mb} is the multiplication table attached to the algebraic integer $b$ is such that $\goth{p}^{-1}=\Z_K+ b/ p\Z_K$, which is used internally to compute valuations. In other words if $p$ is inert, then \var{mb} is the integer $1$, and otherwise it is a square \typ{MAT} whose $j$-th column is $b \cdot \kbd{nf.zk[j]}$. The algebraic number $a$ is guaranteed to have a valuation equal to 1 at the prime ideal (this is automatic if $e>1$). The components of \kbd{pr} should be accessed by member functions: \kbd{pr.p}, \kbd{pr.e}, \kbd{pr.f}, and \kbd{pr.gen} (returns the vector $[p,a]$): \bprog ? K = nfinit(x^3-2); ? P = idealprimedec(K, 5); ? #P \\ 2 primes above 5 in Q(2^(1/3)) %3 = 2 ? [p1,p2] = P; ? [p1.e, p1.f] \\ the first is unramified of degree 1 %5 = [1, 1] ? [p2.e, p2.f] \\ the second is unramified of degree 2 %6 = [1, 2] ? p1.gen %7 = [5, [2, 1, 0]~] ? nfbasistoalg(K, %[2]) \\ a uniformizer for p1 %8 = Mod(x + 2, x^3 - 2) ? #idealprimedec(K, 5, 1) \\ restrict to f = 1 %9 = 1 \\ now only p1 @eprog pari-2.11.2/src/functions/number_fields/nfhnfmod0000644000175000017500000000103311636712103020312 0ustar billbillFunction: nfhnfmod Section: number_fields C-Name: nfhnfmod Prototype: GGG Help: nfhnfmod(nf,x,detx): if x=[A,I], and detx is a multiple of the ideal determinant of x, gives a pseudo-basis of the module sum A_jI_j. Doc: given a pseudo-matrix $(A,I)$ and an ideal \var{detx} which is contained in (read integral multiple of) the determinant of $(A,I)$, finds a pseudo-basis in \idx{Hermite normal form} of the module generated by $(A,I)$. This avoids coefficient explosion. \var{detx} can be computed using the function \kbd{nfdetint}. pari-2.11.2/src/functions/number_fields/nfeltsign0000644000175000017500000000225413326135265020520 0ustar billbillFunction: nfeltsign Section: number_fields C-Name: nfeltsign Prototype: GGDG Help: nfeltsign(nf,x,{pl}): signs of real embeddings of x at places given by vector pl. Doc: given an element $x$ in the number field \var{nf}, returns the signs of the real embeddings of $x$ specified by optional argument \var{pl}: \item \var{pl} omitted: return the vector of signs at all $r_1$ real places; \item \var{pl} an integer between $1$ and $r_1$: return the sign of the $i$-th embedding of $x$, attached to the $i$-th real root of \kbd{nf.pol}, i.e. \kbd{nf.roots$[i]$}; \item \var{pl} a vector or \typ{VECSMALL}: return the vector of signs; the $i$-th entry gives the sign at the real place attached to the $\var{pl}[i]$-th real root of \kbd{nf.pol}. \bprog ? nf = nfinit(polsubcyclo(11,5,'y)); \\ Q(cos(2 pi/11)) ? nf.sign %2 = [5, 0] ? x = Mod('y, nf.pol); ? nfeltsign(nf, x) %4 = [-1, -1, -1, 1, 1] ? nfeltsign(nf, x, 1) %5 = -1 ? nfeltsign(nf, x, [1..4]) %6 = [-1, -1, -1, 1] ? nfeltsign(nf, x, 6) \\ there are only 5 real embeddings *** at top-level: nfeltsign(nf,x,6) *** ^----------------- *** nfeltsign: domain error in nfeltsign: index > 5 @eprog pari-2.11.2/src/functions/number_fields/nfisideal0000644000175000017500000000036311636712103020456 0ustar billbillFunction: nfisideal Section: number_fields C-Name: isideal Prototype: lGG Help: nfisideal(nf,x): true(1) if x is an ideal in the number field nf, false(0) if not. Doc: returns 1 if $x$ is an ideal in the number field $\var{nf}$, 0 otherwise. pari-2.11.2/src/functions/number_fields/idealaddtoone0000644000175000017500000000154411636712103021316 0ustar billbillFunction: idealaddtoone Section: number_fields C-Name: idealaddtoone0 Prototype: GGDG Help: idealaddtoone(nf,x,{y}): if y is omitted, when the sum of the ideals in the number field K defined by nf and given in the vector x is equal to Z_K, gives a vector of elements of the corresponding ideals who sum to 1. Otherwise, x and y are ideals, and if they sum up to 1, find one element in each of them such that the sum is 1. Doc: $x$ and $y$ being two co-prime integral ideals (given in any form), this gives a two-component row vector $[a,b]$ such that $a\in x$, $b\in y$ and $a+b=1$. The alternative syntax $\kbd{idealaddtoone}(\var{nf},v)$, is supported, where $v$ is a $k$-component vector of ideals (given in any form) which sum to $\Z_K$. This outputs a $k$-component vector $e$ such that $e[i]\in x[i]$ for $1\le i\le k$ and $\sum_{1\le i\le k}e[i]=1$. pari-2.11.2/src/functions/number_fields/ideallist0000644000175000017500000000412613201017466020473 0ustar billbillFunction: ideallist Section: number_fields C-Name: ideallist0 Prototype: GLD4,L, Help: ideallist(nf,bound,{flag=4}): vector of vectors L of all idealstar of all ideals of norm<=bound. If (optional) flag is present, its binary digits are toggles meaning 1: give generators; 2: add units; 4: give only the ideals and not the bid. Doc: computes the list of all ideals of norm less or equal to \var{bound} in the number field \var{nf}. The result is a row vector with exactly \var{bound} components. Each component is itself a row vector containing the information about ideals of a given norm, in no specific order, depending on the value of $\fl$: The possible values of $\fl$ are: \quad 0: give the \var{bid} attached to the ideals, without generators. \quad 1: as 0, but include the generators in the \var{bid}. \quad 2: in this case, \var{nf} must be a \var{bnf} with units. Each component is of the form $[\var{bid},U]$, where \var{bid} is as case 0 and $U$ is a vector of discrete logarithms of the units. More precisely, it gives the \kbd{ideallog}s with respect to \var{bid} of \kbd{bnf.tufu}. This structure is technical, and only meant to be used in conjunction with \tet{bnrclassnolist} or \tet{bnrdisclist}. \quad 3: as 2, but include the generators in the \var{bid}. \quad 4: give only the HNF of the ideal. \bprog ? nf = nfinit(x^2+1); ? L = ideallist(nf, 100); ? L[1] %3 = [[1, 0; 0, 1]] \\@com A single ideal of norm 1 ? #L[65] %4 = 4 \\@com There are 4 ideals of norm 4 in $\Z[i]$ @eprog If one wants more information, one could do instead: \bprog ? nf = nfinit(x^2+1); ? L = ideallist(nf, 100, 0); ? l = L[25]; vector(#l, i, l[i].clgp) %3 = [[20, [20]], [16, [4, 4]], [20, [20]]] ? l[1].mod %4 = [[25, 18; 0, 1], []] ? l[2].mod %5 = [[5, 0; 0, 5], []] ? l[3].mod %6 = [[25, 7; 0, 1], []] @eprog\noindent where we ask for the structures of the $(\Z[i]/I)^*$ for all three ideals of norm $25$. In fact, for all moduli with finite part of norm $25$ and trivial Archimedean part, as the last 3 commands show. See \tet{ideallistarch} to treat general moduli. pari-2.11.2/src/functions/number_fields/rnfkummer0000644000175000017500000000250211636712103020523 0ustar billbillFunction: rnfkummer Section: number_fields C-Name: rnfkummer Prototype: GDGD0,L,p Help: rnfkummer(bnr,{subgp},{d=0}): bnr being as output by bnrinit, finds a relative equation for the class field corresponding to the module in bnr and the given congruence subgroup (the ray class field if subgp is omitted). d can be zero (default), or positive, and in this case the output is the list of all relative equations of degree d for the given bnr, with the same conductor as (bnr, subgp). Doc: \var{bnr} being as output by \kbd{bnrinit}, finds a relative equation for the class field corresponding to the module in \var{bnr} and the given congruence subgroup (the full ray class field if \var{subgp} is omitted). If $d$ is positive, outputs the list of all relative equations of degree $d$ contained in the ray class field defined by \var{bnr}, with the \emph{same} conductor as $(\var{bnr}, \var{subgp})$. \misctitle{Warning} This routine only works for subgroups of prime index. It uses Kummer theory, adjoining necessary roots of unity (it needs to compute a tough \kbd{bnfinit} here), and finds a generator via Hecke's characterization of ramification in Kummer extensions of prime degree. If your extension does not have prime degree, for the time being, you have to split it by hand as a tower / compositum of such extensions. pari-2.11.2/src/functions/number_fields/matalgtobasis0000644000175000017500000000061713201017466021354 0ustar billbillFunction: matalgtobasis Section: number_fields C-Name: matalgtobasis Prototype: GG Obsolete: 2016-08-08 Help: matalgtobasis(nf,x): nfalgtobasis applied to every element of the vector or matrix x. Doc: This function is deprecated, use \kbd{apply}. $\var{nf}$ being a number field in \kbd{nfinit} format, and $x$ a (row or column) vector or matrix, apply \tet{nfalgtobasis} to each entry of $x$. pari-2.11.2/src/functions/number_fields/rnfidealabstorel0000644000175000017500000000344113447371554022055 0ustar billbillFunction: rnfidealabstorel Section: number_fields C-Name: rnfidealabstorel Prototype: GG Help: rnfidealabstorel(rnf,x): transforms the ideal x from absolute to relative representation. Doc: let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an ideal of the absolute extension $L/\Q$. Returns the relative pseudo-matrix in HNF giving the ideal $x$ considered as an ideal of the relative extension $L/K$, i.e.~as a $\Z_K$-module. Let \kbd{Labs} be an (absolute) \kbd{nf} structure attached to $L$, obtained via \kbd{Labs = nfinit(rnf))}. Then \kbd{rnf} ``knows'' about \kbd{Labs} and $x$ may be given in any format attached to \kbd{Labs}, e.g. a prime ideal or an ideal in HNF wrt. \kbd{Labs.zk}: \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); Labs = nfinit(rnf); ? m = idealhnf(Labs, 17, x^3+2); \\ some ideal in HNF wrt. Labs.zk ? B = rnfidealabstorel(rnf, m) %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] \\ pseudo-basis for m as Z_K-module ? A = rnfidealreltoabs(rnf, B) %4 = [17, x^2 + 4, x + 8, x^3 + 8*x^2] \\ Z-basis for m in Q[x]/(rnf.polabs) ? mathnf(matalgtobasis(Labs, A)) == m %5 = 1 @eprog\noindent If on the other hand, we do not have a \kbd{Labs} at hand, because it would be too expensive to compute, but we nevertheless have a $\Z$-basis for $x$, then we can use the function with this basis as argument. The entries of $x$ may be given either modulo \kbd{rnf.polabs} (absolute form, possibly lifted) or modulo \kbd{rnf.pol} (relative form as \typ{POLMOD}s): \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? rnfidealabstorel(rnf, [17, x^2 + 4, x + 8, x^3 + 8*x^2]) %2 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] ? rnfidealabstorel(rnf, Mod([17, y + 4, x + 8, y*x + 8*y], x^2-y)) %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] @eprog pari-2.11.2/src/functions/number_fields/rnfidealhnf0000644000175000017500000000072513201017466021002 0ustar billbillFunction: rnfidealhnf Section: number_fields C-Name: rnfidealhnf Prototype: GG Help: rnfidealhnf(rnf,x): relative version of idealhnf, where rnf is a relative numberfield. Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being a relative ideal (which can be, as in the absolute case, of many different types, including of course elements), computes the HNF pseudo-matrix attached to $x$, viewed as a $\Z_K$-module. pari-2.11.2/src/functions/number_fields/galoisidentify0000644000175000017500000000212111636712103021524 0ustar billbillFunction: galoisidentify Section: number_fields C-Name: galoisidentify Prototype: G Help: galoisidentify(gal): gal being a Galois group as output by galoisinit, output the isomorphism class of the underlying abstract group as a two-components vector [o,i], where o is the group order, and i is the group index in the GAP4 small group library. Doc: \var{gal} being be a Galois group as output by \tet{galoisinit}, output the isomorphism class of the underlying abstract group as a two-components vector $[o,i]$, where $o$ is the group order, and $i$ is the group index in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and Eamonn O'Brien. This command also accepts subgroups returned by \kbd{galoissubgroups}. The current implementation is limited to degree less or equal to $127$. Some larger ``easy'' orders are also supported. The output is similar to the output of the function \kbd{IdGroup} in GAP4. Note that GAP4 \kbd{IdGroup} handles all groups of order less than $2000$ except $1024$, so you can use \tet{galoisexport} and GAP4 to identify large Galois groups. pari-2.11.2/src/functions/number_fields/nfeltval0000644000175000017500000000346613326135265020350 0ustar billbillFunction: nfeltval Section: number_fields C-Name: gpnfvalrem Prototype: GGGD& Help: nfeltval(nf,x,pr,{&y}): valuation of element x at the prime pr as output by idealprimedec. Doc: given an element $x$ in \var{nf} and a prime ideal \var{pr} in the format output by \kbd{idealprimedec}, computes the valuation $v$ at \var{pr} of the element $x$. The valuation of $0$ is \kbd{+oo}. \bprog ? nf = nfinit(x^2 + 1); ? P = idealprimedec(nf, 2)[1]; ? nfeltval(nf, x+1, P) %3 = 1 @eprog\noindent This particular valuation can also be obtained using \kbd{idealval(\var{nf},x,\var{pr})}, since $x$ is then converted to a principal ideal. If the $y$ argument is present, sets $y = x \tau^v$, where $\tau$ is a fixed ``anti-uniformizer'' for \var{pr}: its valuation at \var{pr} is $-1$; its valuation is $0$ at other prime ideals dividing \kbd{\var{pr}.p} and nonnegative at all other primes. In other words $y$ is the part of $x$ coprime to \var{pr}. If $x$ is an algebraic integer, so is $y$. \bprog ? nfeltval(nf, x+1, P, &y); y %4 = [0, 1]~ @eprog For instance if $x = \prod_i x_i^{e_i}$ is known to be coprime to \var{pr}, where the $x_i$ are algebraic integers and $e_i\in\Z$ then, if $v_i = \kbd{nfeltval}(\var{nf}, x_i, \var{pr}, \&y_i)$, we still have $x = \prod_i y_i^{e_i}$, where the $y_i$ are still algebraic integers but now all of them are coprime to \var{pr}. They can then be mapped to the residue field of \var{pr} more efficiently than if the product had been expanded beforehand: we can reduce mod \var{pr} after each ring operation. Variant: Also available are \fun{long}{nfvalrem}{GEN nf, GEN x, GEN pr, GEN *y = NULL}, which returns \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer, and \fun{long}{nfval}{GEN nf, GEN x, GEN pr}, which only returns the valuation ($y = \kbd{NULL}$). pari-2.11.2/src/functions/number_fields/nfeltreducemodpr0000644000175000017500000000105113201017466022055 0ustar billbillFunction: nfeltreducemodpr Section: number_fields C-Name: nfreducemodpr Prototype: GGG Obsolete: 2016-08-09 Help: nfeltreducemodpr(nf,x,pr): this function is obsolete, use nfmodpr. Doc: this function is obsolete, use \kbd{nfmodpr}. Given an element $x$ of the number field $\var{nf}$ and a prime ideal \var{pr} in \kbd{modpr} format compute a canonical representative for the class of $x$ modulo \var{pr}. Variant: This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. pari-2.11.2/src/functions/number_fields/nfisincl0000644000175000017500000000351613326135265020336 0ustar billbillFunction: nfisincl Section: number_fields C-Name: nfisincl Prototype: GG Help: nfisincl(f,g): let f and g define number fields, either irreducible rational polynomials or number fields as output by nfinit; tests whether the number field f is isomorphic to a subfield of g. Return 0 if not, and otherwise all the isomorphisms. Doc: let $f$ and $g$ define number fields, where $f$ and $g$ are irreducible polynomials in $\Q[X]$ and \var{nf} structures as output by \kbd{nfinit}. Tests whether the number field $f$ is conjugate to a subfield of the field $g$. If they are not, the output is the integer 0. If they are, the output is a vector of polynomials, each polynomial $a$ representing an embedding i.e.~being such that $g\mid f\circ a$. If either $f$ or $g$ is not irreducible, the result is undefined. \bprog ? T = x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10; ? U = x^3 + 3*x^2 + 3*x - 2 ? v = nfisincl(U, T); %2 = [24/179*x^5-27/179*x^4+80/179*x^3-234/179*x^2+380/179*x+94/179] ? subst(U, x, Mod(v[1],T)) %3 = Mod(0, x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10) ? #nfisincl(x^2+1, T) \\ two embeddings %4 = 2 \\ same result with nf structures ? nfisincl(U, L = nfinit(T)) == v %5 = 1 ? nfisincl(K = nfinit(U), T) == v %6 = 1 ? nfisincl(K, L) == v %7 = 1 \\ comparative bench: an nf is a little faster, esp. for the subfield ? B = 10^3; ? for (i=1, B, nfisincl(U,T)) time = 712 ms. ? for (i=1, B, nfisincl(K,T)) time = 485 ms. ? for (i=1, B, nfisincl(U,L)) time = 704 ms. ? for (i=1, B, nfisincl(K,L)) time = 465 ms. @eprog\noindent Using an \var{nf} structure for the potential subfield is faster if the structure is already available. On the other hand, the gain in \kbd{nfisincl} is usually not sufficient to make it worthwhile to initialize only for that purpose. \bprog ? for (i=1, B, nfinit(U)) time = 308 ms. @eprog pari-2.11.2/src/functions/number_fields/rnfeltup0000644000175000017500000000166713201017466020367 0ustar billbillFunction: rnfeltup Section: number_fields C-Name: rnfeltup0 Prototype: GGD0,L, Help: rnfeltup(rnf,x,{flag=0}): expresses x (belonging to the base field) on the relative field. As a t_POLMOD if flag = 0 and as a t_COL on the absolute field integer basis if flag = 1. Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $K$, computes $x$ as an element of the absolute extension $L/\Q$. As a \typ{POLMOD} modulo \kbd{\var{rnf}.pol} if $\fl = 0$ and as a \typ{COL} on the absolute field integer basis if $\fl = 1$. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltup(L, Mod(y, K.pol)) %3 = Mod(x^2, x^4 + 1) ? rnfeltup(L, y) %4 = Mod(x^2, x^4 + 1) ? rnfeltup(L, [1,2]~) \\ in terms of K.zk %5 = Mod(2*x^2 + 1, x^4 + 1) ? rnfeltup(L, y, 1) \\ in terms of nfinit(L).zk %6 = [0, 1, 0, 0]~ ? rnfeltup(L, [1,2]~, 1) %7 = [1, 2, 0, 0]~ @eprog pari-2.11.2/src/functions/number_fields/rnfidealmul0000644000175000017500000000063211636712103021021 0ustar billbillFunction: rnfidealmul Section: number_fields C-Name: rnfidealmul Prototype: GGG Help: rnfidealmul(rnf,x,y): relative version of idealmul, where rnf is a relative numberfield. Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ and $y$ being ideals of the relative extension $L/K$ given by pseudo-matrices, outputs the ideal product, again as a relative ideal. pari-2.11.2/src/functions/number_fields/nfroots0000644000175000017500000000323313201017466020211 0ustar billbillFunction: nfroots Section: number_fields C-Name: nfroots Prototype: DGG Help: nfroots({nf},x): roots of polynomial x belonging to nf (Q if omitted) without multiplicity. Doc: roots of the polynomial $x$ in the number field $\var{nf}$ given by \kbd{nfinit} without multiplicity (in $\Q$ if $\var{nf}$ is omitted). $x$ has coefficients in the number field (scalar, polmod, polynomial, column vector). The main variable of $\var{nf}$ must be of lower priority than that of $x$ (see \secref{se:priority}). However if the coefficients of the number field occur explicitly (as polmods) as coefficients of $x$, the variable of these polmods \emph{must} be the same as the main variable of $t$ (see \kbd{nffactor}). It is possible to input a defining polynomial for \var{nf} instead, but this is in general less efficient since parts of an \kbd{nf} structure will then be computed internally. This is useful in two situations: when you do not need the \kbd{nf} elsewhere, or when you cannot initialize an \kbd{nf} due to integer factorization difficulties when attempting to compute the field discriminant and maximal order. \misctitle{Caveat} \kbd{nfinit([T, listP])} allows to compute in polynomial time a conditional \var{nf} structure, which sets \kbd{nf.zk} to an order which is not guaranteed to be maximal at all primes. Always either use \kbd{nfcertify} first (which may not run in polynomial time) or make sure to input \kbd{nf.pol} instead of the conditional \var{nf}: \kbd{nfroots} is able to recover in polynomial time in this case, instead of potentially missing a factor. Variant: See also \fun{GEN}{nfrootsQ}{GEN x}, corresponding to $\kbd{nf} = \kbd{NULL}$. pari-2.11.2/src/functions/number_fields/nfislocalpower0000644000175000017500000000153113326135265021553 0ustar billbillFunction: nfislocalpower Section: number_fields C-Name: nfislocalpower Prototype: lGGGG Help: nfislocalpower(nf,pr,a,n): true(1) if a is an n-th power in the local field K_v, false(0) if not. Doc: Let \var{nf} be a \var{nf} structure attached to a number field $K$, let $a \in K$ and let \var{pr} be a \var{prid} structure attached to a maximal ideal $v$. Return $1$ if $a$ is an $n$-th power in the completed local field $K_v$, and $0$ otherwise. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K,2)[1]; \\ the ramified prime above 2 ? nfislocalpower(K,P,-1, 2) \\ -1 is a square %3 = 1 ? nfislocalpower(K,P,-1, 4) \\ ... but not a 4-th power %4 = 0 ? nfislocalpower(K,P,2, 2) \\ 2 is not a square %5 = 0 ? Q = idealprimedec(K,5)[1]; \\ a prime above 5 ? nfislocalpower(K,Q, [0, 32]~, 30) \\ 32*I is locally a 30-th power %7 = 1 @eprog pari-2.11.2/src/functions/number_fields/nfgrunwaldwang0000644000175000017500000000356413326135265021560 0ustar billbillFunction: nfgrunwaldwang Section: number_fields C-Name: nfgrunwaldwang Prototype: GGGGDn Help: nfgrunwaldwang(nf,Lpr,Ld,pl,{v='x}): a polynomial in the variable v defining a cyclic extension of nf (given in nf or bnf form) with local behavior prescribed by Lpr, Ld and pl: the extension has local degree a multiple of Ld[i] at the prime Lpr[i], and the extension is complex at the i-th real place of nf if pl[i]=-1 (no condition if pl[i]=0). The extension has degree the LCM of the local degrees. Doc: Given \var{nf} a number field in \var{nf} or \var{bnf} format, a \typ{VEC} \var{Lpr} of primes of \var{nf} and a \typ{VEC} \var{Ld} of positive integers of the same length, a \typ{VECSMALL} \var{pl} of length $r_1$ the number of real places of \var{nf}, computes a polynomial with coefficients in \var{nf} defining a cyclic extension of \var{nf} of minimal degree satisfying certain local conditions: \item at the prime~$Lpr[i]$, the extension has local degree a multiple of~$Ld[i]$; \item at the $i$-th real place of \var{nf}, it is complex if $pl[i]=-1$ (no condition if $pl[i]=0$). The extension has degree the LCM of the local degrees. Currently, the degree is restricted to be a prime power for the search, and to be prime for the construction because of the \kbd{rnfkummer} restrictions. When \var{nf} is $\Q$, prime integers are accepted instead of \kbd{prid} structures. However, their primality is not checked and the behavior is undefined if you provide a composite number. \misctitle{Warning} If the number field \var{nf} does not contain the $n$-th roots of unity where $n$ is the degree of the extension to be computed, triggers the computation of the \var{bnf} of $nf(\zeta_n)$, which may be costly. \bprog ? nf = nfinit(y^2-5); ? pr = idealprimedec(nf,13)[1]; ? pol = nfgrunwaldwang(nf, [pr], [2], [0,-1], 'x) %3 = x^2 + Mod(3/2*y + 13/2, y^2 - 5) @eprog pari-2.11.2/src/functions/number_fields/rnfpolredbest0000644000175000017500000000366513036414402021376 0ustar billbillFunction: rnfpolredbest Section: number_fields C-Name: rnfpolredbest Prototype: GGD0,L, Help: rnfpolredbest(nf,pol,{flag=0}): given a pol with coefficients in nf, finds a relative polynomial P defining the same field, hopefully simpler than pol; flag can be 0: default, 1: return [P,a], where a is a root of pol 2: return an absolute polynomial Pabs, 3: return [Pabs, a,b], where a is a root of nf.pol and b is a root of pol. Doc: relative version of \kbd{polredbest}. Given a monic polynomial \var{pol} with coefficients in $\var{nf}$, finds a simpler relative polynomial $P$ defining the same field. As opposed to \tet{rnfpolredabs} this function does not return a \emph{smallest} (canonical) polynomial with respect to some measure, but it does run in polynomial time. The binary digits of $\fl$ correspond to $1$: add information to convert elements to the new representation, $2$: absolute polynomial, instead of relative. More precisely: 0: default, return $P$ 1: returns $[P,a]$ where $P$ is the default output and $a$, a \typ{POLMOD} modulo $P$, is a root of \var{pol}. 2: returns \var{Pabs}, an absolute, instead of a relative, polynomial. Same as but faster than \bprog rnfequation(nf, rnfpolredbest(nf,pol)) @eprog 3: returns $[\var{Pabs},a,b]$, where \var{Pabs} is an absolute polynomial as above, $a$, $b$ are \typ{POLMOD} modulo \var{Pabs}, roots of \kbd{nf.pol} and \var{pol} respectively. \bprog ? K = nfinit(y^3-2); pol = x^2 +x*y + y^2; ? [P, a] = rnfpolredbest(K,pol,1); ? P %3 = x^2 - x + Mod(y - 1, y^3 - 2) ? a %4 = Mod(Mod(2*y^2+3*y+4,y^3-2)*x + Mod(-y^2-2*y-2,y^3-2), x^2 - x + Mod(y-1,y^3-2)) ? subst(K.pol,y,a) %5 = 0 ? [Pabs, a, b] = rnfpolredbest(K,pol,3); ? Pabs %7 = x^6 - 3*x^5 + 5*x^3 - 3*x + 1 ? a %8 = Mod(-x^2+x+1, x^6-3*x^5+5*x^3-3*x+1) ? b %9 = Mod(2*x^5-5*x^4-3*x^3+10*x^2+5*x-5, x^6-3*x^5+5*x^3-3*x+1) ? subst(K.pol,y,a) %10 = 0 ? substvec(pol,[x,y],[a,b]) %11 = 0 @eprog pari-2.11.2/src/functions/number_fields/galoissubcyclo0000644000175000017500000000510013326135265021542 0ustar billbillFunction: galoissubcyclo Section: number_fields C-Name: galoissubcyclo Prototype: GDGD0,L,Dn Help: galoissubcyclo(N,H,{fl=0},{v}): compute a polynomial (in variable v) defining the subfield of Q(zeta_n) fixed by the subgroup H of (Z/nZ)*. N can be an integer n, znstar(n) or bnrinit(bnfinit(y),[n,[1]]). H can be given by a generator, a set of generator given by a vector or a HNF matrix (see manual). If flag is 1, output only the conductor of the abelian extension. If flag is 2 output [pol,f] where pol is the polynomial and f the conductor. Doc: computes the subextension of $\Q(\zeta_n)$ fixed by the subgroup $H \subset (\Z/n\Z)^*$. By the Kronecker-Weber theorem, all abelian number fields can be generated in this way (uniquely if $n$ is taken to be minimal). \noindent The pair $(n, H)$ is deduced from the parameters $(N, H)$ as follows \item $N$ an integer: then $n = N$; $H$ is a generator, i.e. an integer or an integer modulo $n$; or a vector of generators. \item $N$ the output of \kbd{znstar}$(n)$ or \kbd{znstar}$(n,1)$. $H$ as in the first case above, or a matrix, taken to be a HNF left divisor of the SNF for $(\Z/n\Z)^*$ (\kbd{$N$.cyc}), giving the generators of $H$ in terms of \kbd{$N$.gen}. \item $N$ the output of \kbd{bnrinit(bnfinit(y), $m$)} where $m$ is a module. $H$ as in the first case, or a matrix taken to be a HNF left divisor of the SNF for the ray class group modulo $m$ (of type \kbd{$N$.cyc}), giving the generators of $H$ in terms of \kbd{$N$.bid.gen} (= \kbd{$N$}.gen if $N$ includes generators). In this last case, beware that $H$ is understood relatively to $N$; in particular, if the infinite place does not divide the module, e.g if $m$ is an integer, then it is not a subgroup of $(\Z/n\Z)^*$, but of its quotient by $\{\pm 1\}$. If $fl=0$, compute a polynomial (in the variable \var{v}) defining the subfield of $\Q(\zeta_n)$ fixed by the subgroup \var{H} of $(\Z/n\Z)^*$. If $fl=1$, compute only the conductor of the abelian extension, as a module. If $fl=2$, output $[pol, N]$, where $pol$ is the polynomial as output when $fl=0$ and $N$ the conductor as output when $fl=1$. The following function can be used to compute all subfields of $\Q(\zeta_n)$ (of exact degree \kbd{d}, if \kbd{d} is set): \bprog subcyclo(n, d = -1)= { my(bnr,L,IndexBound); IndexBound = if (d < 0, n, [d]); bnr = bnrinit(bnfinit(y), [n,[1]]); L = subgrouplist(bnr, IndexBound, 1); vector(#L,i, galoissubcyclo(bnr,L[i])); } @eprog\noindent Setting \kbd{L = subgrouplist(bnr, IndexBound)} would produce subfields of exact conductor $n\infty$. pari-2.11.2/src/functions/number_fields/rnfpolred0000644000175000017500000000143213201017466020511 0ustar billbillFunction: rnfpolred Section: number_fields C-Name: rnfpolred Prototype: GGp Obsolete: 2013-12-28 Help: rnfpolred(nf,pol): given a pol with coefficients in nf, finds a list of relative polynomials defining some subfields, hopefully simpler. Doc: This function is obsolete: use \tet{rnfpolredbest} instead. Relative version of \kbd{polred}. Given a monic polynomial \var{pol} with coefficients in $\var{nf}$, finds a list of relative polynomials defining some subfields, hopefully simpler and containing the original field. In the present version \vers, this is slower and less efficient than \kbd{rnfpolredbest}. \misctitle{Remark} this function is based on an incomplete reduction theory of lattices over number fields, implemented by \kbd{rnflllgram}, which deserves to be improved. pari-2.11.2/src/functions/number_fields/galoisisnormal0000644000175000017500000000105711636712103021544 0ustar billbillFunction: galoisisnormal Section: number_fields C-Name: galoisisnormal Prototype: lGG Help: galoisisnormal(gal,subgrp): gal being as output by galoisinit, and subgrp a subgroup of gal as output by galoissubgroups, return 1 if subgrp is a normal subgroup of gal, else return 0. Doc: \var{gal} being as output by \kbd{galoisinit}, and \var{subgrp} a subgroup of \var{gal} as output by \kbd{galoissubgroups},return $1$ if \var{subgrp} is a normal subgroup of \var{gal}, else return 0. This command also accepts subgroups returned by \kbd{galoissubgroups}. pari-2.11.2/src/functions/number_fields/idealprincipalunits0000644000175000017500000000141213201017466022557 0ustar billbillFunction: idealprincipalunits Section: number_fields C-Name: idealprincipalunits Prototype: GGL Help: idealprincipalunits(nf,pr,k): returns the structure [no, cyc, gen] of the multiplicative group (1 + pr) / (1 + pr^k). Doc: given a prime ideal in \tet{idealprimedec} format, returns the multiplicative group $(1 + \var{pr}) / (1 + \var{pr}^k)$ as an abelian group. This function is much faster than \tet{idealstar} when the norm of \var{pr} is large, since it avoids (useless) work in the multiplicative group of the residue field. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K,2)[1]; ? G = idealprincipalunits(K, P, 20); ? G.cyc %4 = [512, 256, 4] \\ Z/512 x Z/256 x Z/4 ? G.gen %5 = [[-1, -2]~, 1021, [0, -1]~] \\ minimal generators of given order @eprog pari-2.11.2/src/functions/number_fields/HEADER0000644000175000017500000004631213326135265017462 0ustar billbillFunction: _header_number_fields Class: header Section: number_fields Doc: \section{General number fields} In this section, we describe functions related to general number fields. Functions related to quadratic number fields are found in \secref{se:arithmetic} (Arithmetic functions). \subsec{Number field structures} %GPHELPskip Let $K = \Q[X] / (T)$ a number field, $\Z_K$ its ring of integers, $T\in\Z[X]$ is monic. Three basic number field structures can be attached to $K$ in GP: \item $\tev{nf}$ denotes a number field, i.e.~a data structure output by \tet{nfinit}. This contains the basic arithmetic data attached to the number field: signature, maximal order (given by a basis \kbd{nf.zk}), discriminant, defining polynomial $T$, etc. \item $\tev{bnf}$ denotes a ``Buchmann's number field'', i.e.~a data structure output by \tet{bnfinit}. This contains $\var{nf}$ and the deeper invariants of the field: units $U(K)$, class group $\Cl(K)$, as well as technical data required to solve the two attached discrete logarithm problems. \item $\tev{bnr}$ denotes a ``ray number field'', i.e.~a data structure output by \kbd{bnrinit}, corresponding to the ray class group structure of the field, for some modulus $f$. It contains a \var{bnf}, the modulus $f$, the ray class group $\Cl_f(K)$ and data attached to the discrete logarithm problem therein. \subsec{Algebraic numbers and ideals} %GPHELPskip \noindent An \tev{algebraic number} belonging to $K = \Q[X]/(T)$ is given as \item a \typ{INT}, \typ{FRAC} or \typ{POL} (implicitly modulo $T$), or \item a \typ{POLMOD} (modulo $T$), or \item a \typ{COL}~\kbd{v} of dimension $N = [K:\Q]$, representing the element in terms of the computed integral basis, as \kbd{sum(i = 1, N,~v[i] * nf.zk[i])}. Note that a \typ{VEC} will not be recognized. \medskip \noindent An \tev{ideal} is given in any of the following ways: \item an algebraic number in one of the above forms, defining a principal ideal. \item a prime ideal, i.e.~a 5-component vector in the format output by \kbd{idealprimedec} or \kbd{idealfactor}. \item a \typ{MAT}, square and in Hermite Normal Form (or at least upper triangular with non-negative coefficients), whose columns represent a $\Z$-basis of the ideal. One may use \kbd{idealhnf} to convert any ideal to the last (preferred) format. \item an \emph{extended ideal} \sidx{ideal (extended)} is a 2-component vector $[I, t]$, where $I$ is an ideal as above and $t$ is an algebraic number, representing the ideal $(t)I$. This is useful whenever \tet{idealred} is involved, implicitly working in the ideal class group, while keeping track of principal ideals. The following multiplicative ideal operations update the principal part: \kbd{idealmul}, \kbd{idealsqr}, \kbd{idealinv}, \kbd{idealpow} and \kbd{idealred}; e.g.~using \kbd{idealmul} on $[I,t]$, $[J,u]$, we obtain $[IJ, tu]$. In all other functions, the extended part is silently discarded, e.g.~using \kbd{idealadd} with the above input produces $I+J$. The ``principal part'' $t$ in an extended ideal may be represented in any of the above forms, and \emph{also} as a factorization matrix (in terms of number field elements, not ideals!), possibly the empty factorization matrix \kbd{factor(1)} representing $1$; the empty matrix \kbd{[;]} is also accepted as a synonym for $1$. When $t$ is such a factorization matrix, elements stay in factored form, or \tev{famat} for \emph{fa}ctorization \emph{mat}rix, which is a convenient way to avoid coefficient explosion. To recover the conventional expanded form, try \tet{nffactorback}; but many functions already accept \var{famat}s as input, for instance \tet{ideallog}, so expanding huge elements should never be necessary. \subsec{Finite abelian groups} %GPHELPskip A finite abelian group $G$ in user-readable format is given by its Smith Normal Form as a pair $[h,d]$ or triple $[h,d,g]$. Here $h$ is the cardinality of $G$, $(d_i)$ is the vector of elementary divisors, and $(g_i)$ is a vector of generators. In short, $G = \oplus_{i\leq n} (\Z/d_i\Z) g_i$, with $d_n \mid \dots \mid d_2 \mid d_1$ and $\prod d_i = h$. This information can also be retrieved as $G.\kbd{no}$, $G.\kbd{cyc}$ and $G.\kbd{gen}$. \item a \tev{character} on the abelian group $\oplus (\Z/d_j\Z) g_j$ is given by a row vector $\chi = [a_1,\ldots,a_n]$ such that $\chi(\prod g_j^{n_j}) = \exp(2\pi i\sum a_j n_j / d_j)$. \item given such a structure, a \tev{subgroup} $H$ is input as a square matrix in HNF, whose columns express generators of $H$ on the given generators $g_i$. Note that the determinant of that matrix is equal to the index $(G:H)$. \subsec{Relative extensions} %GPHELPskip We now have a look at data structures attached to relative extensions of number fields $L/K$, and to projective $\Z_K$-modules. When defining a relative extension $L/K$, the $\var{nf}$ attached to the base field $K$ must be defined by a variable having a lower priority (see \secref{se:priority}) than the variable defining the extension. For example, you may use the variable name $y$ to define the base field $K$, and $x$ to define the relative extension $L/K$. \subsubsec{Basic definitions}\label{se:ZKmodules} %GPHELPskip \item $\tev{rnf}$ denotes a relative number field, i.e.~a data structure output by \kbd{rnfinit}, attached to the extension $L/K$. The \var{nf} attached to be base field $K$ is \kbd{rnf.nf}. \item A \emph{relative matrix} is an $m\times n$ matrix whose entries are elements of $K$, in any form. Its $m$ columns $A_j$ represent elements in $K^n$. \item An \tev{ideal list} is a row vector of fractional ideals of the number field $\var{nf}$. \item A \tev{pseudo-matrix} is a 2-component row vector $(A,I)$ where $A$ is a relative $m\times n$ matrix and $I$ an ideal list of length $n$. If $I = \{\goth{a}_1,\dots, \goth{a}_n\}$ and the columns of $A$ are $(A_1,\dots, A_n)$, this data defines the torsion-free (projective) $\Z_K$-module $\goth{a}_1 A_1\oplus \goth{a}_n A_n$. \item An \tev{integral pseudo-matrix} is a 3-component row vector w$(A,I,J)$ where $A = (a_{i,j})$ is an $m\times n$ relative matrix and $I = (\goth{b}_1,\dots, \goth{b}_m)$, $J = (\goth{a}_1,\dots, \goth{a}_n)$ are ideal lists, such that $a_{i,j} \in \goth{b}_i \goth{a}_j^{-1}$ for all $i,j$. This data defines two abstract projective $\Z_K$-modules $N = \goth{a}_1\omega_1\oplus \cdots\oplus \goth{a}_n\omega_n $ in $K^n$, $P = \goth{b}_1\eta_1\oplus \cdots\oplus \goth{b}_m\eta_m$ in $K^m$, and a $\Z_K$-linear map $f:N\to P$ given by $$ f(\sum \alpha_j\omega_j) = \sum_i \Big(a_{i,j}\alpha_j\Big) \eta_i.$$ This data defines the $\Z_K$-module $M = P/f(N)$. \item Any \emph{projective} $\Z_K$-module\varsidx{projective module} $M$ of finite type in $K^m$ can be given by a pseudo matrix $(A,I)$. \item An arbitrary $\Z_K$ modules of finite type in $K^m$, with non-trivial torsion, is given by an integral pseudo-matrix $(A,I,J)$ \subsubsec{Pseudo-bases, determinant} %GPHELPskip \item The pair $(A,I)$ is a \tev{pseudo-basis} of the module it generates if the $\goth{a}_j$ are non-zero, and the $A_j$ are $K$-linearly independent. We call $n$ the \emph{size} of the pseudo-basis. If $A$ is a relative matrix, the latter condition means it is square with non-zero determinant; we say that it is in Hermite Normal Form\sidx{Hermite normal form} (HNF) if it is upper triangular and all the elements of the diagonal are equal to 1. \item For instance, the relative integer basis \kbd{rnf.zk} is a pseudo-basis $(A,I)$ of $\Z_L$, where $A = \kbd{rnf.zk[1]}$ is a vector of elements of $L$, which are $K$-linearly independent. Most \var{rnf} routines return and handle $\Z_K$-modules contained in $L$ (e.g.~$\Z_L$-ideals) via a pseudo-basis $(A',I')$, where $A'$ is a relative matrix representing a vector of elements of $L$ in terms of the fixed basis \kbd{rnf.zk[1]} \item The \emph{determinant} of a pseudo-basis $(A,I)$ is the ideal equal to the product of the determinant of $A$ by all the ideals of $I$. The determinant of a pseudo-matrix is the determinant of any pseudo-basis of the module it generates. \subsec{Class field theory}\label{se:CFT} A $\tev{modulus}$, in the sense of class field theory, is a divisor supported on the non-complex places of $K$. In PARI terms, this means either an ordinary ideal $I$ as above (no Archimedean component), or a pair $[I,a]$, where $a$ is a vector with $r_1$ $\{0,1\}$-components, corresponding to the infinite part of the divisor. More precisely, the $i$-th component of $a$ corresponds to the real embedding attached to the $i$-th real root of \kbd{K.roots}. (That ordering is not canonical, but well defined once a defining polynomial for $K$ is chosen.) For instance, \kbd{[1, [1,1]]} is a modulus for a real quadratic field, allowing ramification at any of the two places at infinity, and nowhere else. A \tev{bid} or ``big ideal'' is a structure output by \kbd{idealstar} needed to compute in $(\Z_K/I)^*$, where $I$ is a modulus in the above sense. It is a finite abelian group as described above, supplemented by technical data needed to solve discrete log problems. Finally we explain how to input ray number fields (or \var{bnr}), using class field theory. These are defined by a triple $A$, $B$, $C$, where the defining set $[A,B,C]$ can have any of the following forms: $[\var{bnr}]$, $[\var{bnr},\var{subgroup}]$, $[\var{bnr},\var{character}]$, $[\var{bnf},\var{mod}]$, $[\var{bnf},\var{mod},\var{subgroup}]$. The last two forms are kept for backward compatibility, but no longer serve any real purpose (see example below); no newly written function will accept them. \item $\var{bnf}$ is as output by \kbd{bnfinit}, where units are mandatory unless the modulus is trivial; \var{bnr} is as output by \kbd{bnrinit}. This is the ground field $K$. \item \emph{mod} is a modulus $\goth{f}$, as described above. \item \emph{subgroup} a subgroup of the ray class group modulo $\goth{f}$ of $K$. As described above, this is input as a square matrix expressing generators of a subgroup of the ray class group \kbd{\var{bnr}.clgp} on the given generators. The corresponding \var{bnr} is the subfield of the ray class field of $K$ modulo $\goth{f}$, fixed by the given subgroup. \bprog ? K = bnfinit(y^2+1); ? bnr = bnrinit(K, 13) ? %.clgp %3 = [36, [12, 3]] ? bnrdisc(bnr); \\ discriminant of the full ray class field ? bnrdisc(bnr, [3,1;0,1]); \\ discriminant of cyclic cubic extension of K ? bnrconductor(bnr, [3,1]); \\ conductor of chi: g1->zeta_12^3, g2->zeta_3 @eprog\noindent We could have written directly \bprog ? bnrdisc(K, 13); ? bnrdisc(K, 13, [3,1;0,1]); @eprog\noindent avoiding one \tet{bnrinit}, but this would actually be slower since the \kbd{bnrinit} is called internally anyway. And now twice! \subsec{General use} All the functions which are specific to relative extensions, number fields, Buchmann's number fields, Buchmann's number rays, share the prefix \kbd{rnf}, \kbd{nf}, \kbd{bnf}, \kbd{bnr} respectively. They take as first argument a number field of that precise type, respectively output by \kbd{rnfinit}, \kbd{nfinit}, \kbd{bnfinit}, and \kbd{bnrinit}. However, and even though it may not be specified in the descriptions of the functions below, it is permissible, if the function expects a $\var{nf}$, to use a $\var{bnf}$ instead, which contains much more information. On the other hand, if the function requires a \kbd{bnf}, it will \emph{not} launch \kbd{bnfinit} for you, which is a costly operation. Instead, it will give you a specific error message. In short, the types $$ \kbd{nf} \leq \kbd{bnf} \leq \kbd{bnr}$$ are ordered, each function requires a minimal type to work properly, but you may always substitute a larger type. The data types corresponding to the structures described above are rather complicated. Thus, as we already have seen it with elliptic curves, GP provides ``member functions'' to retrieve data from these structures (once they have been initialized of course). The relevant types of number fields are indicated between parentheses: \smallskip \sidx{member functions} \settabs\+xxxxxxx&(\var{bnr},x&\var{bnf},x&nf\hskip2pt&)x&: &\cr \+\tet{bid} &(\var{bnr}&&&)&: & bid ideal structure.\cr \+\tet{bnf} &(\var{bnr},& \var{bnf}&&)&: & Buchmann's number field.\cr \+\tet{clgp} &(\var{bnr},& \var{bnf}&&)&: & classgroup. This one admits the following three subclasses:\cr \+ \quad \tet{cyc} &&&&&: & \quad cyclic decomposition (SNF)\sidx{Smith normal form}.\cr \+ \quad \kbd{gen}\sidx{gen (member function)} &&&&&: & \quad generators.\cr \+ \quad \tet{no} &&&&&: & \quad number of elements.\cr \+\tet{diff} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the different ideal.\cr \+\tet{codiff}&(\var{bnr},& \var{bnf},& \var{nf}&)&: & the codifferent (inverse of the different in the ideal group).\cr \+\tet{disc} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & discriminant.\cr \+\tet{fu} &(\var{bnr},& \var{bnf}&&)&: & \idx{fundamental units}.\cr \+\tet{index} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & \idx{index} of the power order in the ring of integers.\cr \+\tet{mod} &(\var{bnr}&&&)&: & modulus.\cr \+\tet{nf} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & number field.\cr \+\tet{pol} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & defining polynomial.\cr \+\tet{r1} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the number of real embeddings.\cr \+\tet{r2} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the number of pairs of complex embeddings.\cr \+\tet{reg} &(\var{bnr},& \var{bnf}&&)&: & regulator.\cr \+\tet{roots}&(\var{bnr},& \var{bnf},& \var{nf}&)&: & roots of the polynomial generating the field.\cr \+\tet{sign} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & signature $[r1,r2]$.\cr \+\tet{t2} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the $T_2$ matrix (see \kbd{nfinit}).\cr \+\tet{tu} &(\var{bnr},& \var{bnf}&&)&: & a generator for the torsion units.\cr \+\tet{zk} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & integral basis, i.e.~a $\Z$-basis of the maximal order.\cr \+\tet{zkst} &(\var{bnr}&&&)&: & structure of $(\Z_K/m)^*$.\cr The member functions \kbd{.codiff}, \kbd{.t2} and \kbd{.zk} perform a computation and are relatively expensive in large degree: move them out of tight loops and store them in variables. \misctitle{Deprecated} The following member functions are still available, but deprecated and should not be used in new scripts : \+\tet{futu} &(\var{bnr},& \var{bnf},&&)&: & $[u_1,...,u_r,w]$, $(u_i)$ is a vector of fundamental units,\cr \+&&&&&& $w$ generates the torsion units.\cr \+\tet{tufu} &(\var{bnr},& \var{bnf},&&)&: & $[w,u_1,...,u_r]$, $(u_i)$ is a vector of fundamental units,\cr \+&&&&&& $w$ generates the torsion units.\cr For instance, assume that $\var{bnf} = \kbd{bnfinit}(\var{pol})$, for some polynomial. Then \kbd{\var{bnf}.clgp} retrieves the class group, and \kbd{\var{bnf}.clgp.no} the class number. If we had set $\var{bnf} = \kbd{nfinit}(\var{pol})$, both would have output an error message. All these functions are completely recursive, thus for instance \kbd{\var{bnr}.bnf.nf.zk} will yield the maximal order of \var{bnr}, which you could get directly with a simple \kbd{\var{bnr}.zk}. \subsec{Class group, units, and the GRH}\label{se:GRHbnf} Some of the functions starting with \kbd{bnf} are implementations of the sub-exponential algorithms for finding class and unit groups under \idx{GRH}, due to Hafner-McCurley, \idx{Buchmann} and Cohen-Diaz-Olivier. The general call to the functions concerning class groups of general number fields (i.e.~excluding \kbd{quadclassunit}) involves a polynomial $P$ and a technical vector $$\var{tech} = [c_1, c_2, \var{nrpid} ],$$ where the parameters are to be understood as follows: $P$ is the defining polynomial for the number field, which must be in $\Z[X]$, irreducible and monic. In fact, if you supply a non-monic polynomial at this point, \kbd{gp} issues a warning, then \emph{transforms your polynomial} so that it becomes monic. The \kbd{nfinit} routine will return a different result in this case: instead of \kbd{res}, you get a vector \kbd{[res,Mod(a,Q)]}, where \kbd{Mod(a,Q) = Mod(X,P)} gives the change of variables. In all other routines, the variable change is simply lost. The \var{tech} interface is obsolete and you should not tamper with these parameters. Indeed, from version 2.4.0 on, \item the results are always rigorous under \idx{GRH} (before that version, they relied on a heuristic strengthening, hence the need for overrides). \item the influence of these parameters on execution time and stack size is marginal. They \emph{can} be useful to fine-tune and experiment with the \kbd{bnfinit} code, but you will be better off modifying all tuning parameters in the C code (there are many more than just those three). We nevertheless describe it for completeness. The numbers $c_1 \leq c_2$ are non-negative real numbers. By default they are chosen so that the result is correct under GRH. For $i = 1,2$, let $B_i = c_i(\log |d_K|)^2$, and denote by $S(B)$ the set of maximal ideals of $K$ whose norm is less than $B$. We want $S(B_1)$ to generate $\Cl(K)$ and hope that $S(B_2)$ can be \emph{proven} to generate $\Cl(K)$. More precisely, $S(B_1)$ is a factorbase used to compute a tentative $\Cl(K)$ by generators and relations. We then check explicitly, using essentially \kbd{bnfisprincipal}, that the elements of $S(B_2)$ belong to the span of $S(B_1)$. Under the assumption that $S(B_2)$ generates $\Cl(K)$, we are done. User-supplied $c_i$ are only used to compute initial guesses for the bounds $B_i$, and the algorithm increases them until one can \emph{prove} under GRH that $S(B_2)$ generates $\Cl(K)$. A uniform result of Bach says that $c_2 = 12$ is always suitable, but this bound is very pessimistic and a direct algorithm due to Belabas-Diaz-Friedman is used to check the condition, assuming GRH. The default values are $c_1 = c_2 = 0$. When $c_1$ is equal to $0$ the algorithm takes it equal to $c_2$. $\var{nrpid}$ is the maximal number of small norm relations attached to each ideal in the factor base. Set it to $0$ to disable the search for small norm relations. Otherwise, reasonable values are between 4 and 20. The default is 4. \misctitle{Warning} Make sure you understand the above! By default, most of the \kbd{bnf} routines depend on the correctness of the GRH. In particular, any of the class number, class group structure, class group generators, regulator and fundamental units may be wrong, independently of each other. Any result computed from such a \kbd{bnf} may be wrong. The only guarantee is that the units given generate a subgroup of finite index in the full unit group. You must use \kbd{bnfcertify} to certify the computations unconditionally. \misctitle{Remarks} You do not need to supply the technical parameters (under the library you still need to send at least an empty vector, coded as \kbd{NULL}). However, should you choose to set some of them, they \emph{must} be given in the requested order. For example, if you want to specify a given value of \var{nrpid}, you must give some values as well for $c_1$ and $c_2$, and provide a vector $[c_1,c_2,\var{nrpid}]$. Note also that you can use an $\var{nf}$ instead of $P$, which avoids recomputing the integral basis and analogous quantities. pari-2.11.2/src/functions/number_fields/idealnorm0000644000175000017500000000032611636712103020471 0ustar billbillFunction: idealnorm Section: number_fields C-Name: idealnorm Prototype: GG Help: idealnorm(nf,x): norm of the ideal x in the number field nf. Doc: computes the norm of the ideal~$x$ in the number field~$\var{nf}$. pari-2.11.2/src/functions/number_fields/idealmin0000644000175000017500000000060111636712103020275 0ustar billbillFunction: idealmin Section: number_fields C-Name: idealmin Prototype: GGDG Help: idealmin(nf,ix,{vdir}): pseudo-minimum of the ideal ix in the direction vdir in the number field nf. Doc: \emph{This function is useless and kept for backward compatibility only, use \kbd{idealred}}. Computes a pseudo-minimum of the ideal $x$ in the direction \var{vdir} in the number field \var{nf}. pari-2.11.2/src/functions/number_fields/modreverse0000644000175000017500000000300712314242551020670 0ustar billbillFunction: modreverse Section: number_fields C-Name: modreverse Prototype: G Help: modreverse(z): reverse polmod of the polmod z, if it exists. Doc: let $z = \kbd{Mod(A, T)}$ be a polmod, and $Q$ be its minimal polynomial, which must satisfy $\text{deg}(Q) = \text{deg}(T)$. Returns a ``reverse polmod'' \kbd{Mod(B, Q)}, which is a root of $T$. This is quite useful when one changes the generating element in algebraic extensions: \bprog ? u = Mod(x, x^3 - x -1); v = u^5; ? w = modreverse(v) %2 = Mod(x^2 - 4*x + 1, x^3 - 5*x^2 + 4*x - 1) @eprog\noindent which means that $x^3 - 5x^2 + 4x -1$ is another defining polynomial for the cubic field $$\Q(u) = \Q[x]/(x^3 - x - 1) = \Q[x]/(x^3 - 5x^2 + 4x - 1) = \Q(v),$$ and that $u \to v^2 - 4v + 1$ gives an explicit isomorphism. From this, it is easy to convert elements between the $A(u)\in \Q(u)$ and $B(v)\in \Q(v)$ representations: \bprog ? A = u^2 + 2*u + 3; subst(lift(A), 'x, w) %3 = Mod(x^2 - 3*x + 3, x^3 - 5*x^2 + 4*x - 1) ? B = v^2 + v + 1; subst(lift(B), 'x, v) %4 = Mod(26*x^2 + 31*x + 26, x^3 - x - 1) @eprog If the minimal polynomial of $z$ has lower degree than expected, the routine fails \bprog ? u = Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1) ? modreverse(u) *** modreverse: domain error in modreverse: deg(minpoly(z)) < 4 *** Break loop: type 'break' to go back to GP prompt break> Vec( dbg_err() ) \\ ask for more info ["e_DOMAIN", "modreverse", "deg(minpoly(z))", "<", 4, Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1)] break> minpoly(u) x^2 - 8 @eprog pari-2.11.2/src/functions/number_fields/nfeltembed0000644000175000017500000000222013326135265020625 0ustar billbillFunction: nfeltembed Section: number_fields C-Name: nfeltembed Prototype: GGDGp Help: nfeltembed(nf,x,{pl}): complex embeddings of x at places given by vector pl. Doc: given an element $x$ in the number field \var{nf}, return the (real or) complex embeddings of $x$ specified by optional argument \var{pl}, at the current \kbd{realprecision}: \item \var{pl} omitted: return the vector of embeddings at all $r_1+r_2$ places; \item \var{pl} an integer between $1$ and $r_1+r_2$: return the $i$-th embedding of $x$, attached to the $i$-th root of \kbd{nf.pol}, i.e. \kbd{nf.roots$[i]$}; \item \var{pl} a vector or \typ{VECSMALL}: return the vector of embeddings; the $i$-th entry gives the embedding at the place attached to the $\var{pl}[i]$-th real root of \kbd{nf.pol}. \bprog ? nf = nfinit('y^3 - 2); ? nf.sign %2 = [1, 1] ? nfeltembed(nf, 'y) %3 = [1.25992[...], -0.62996[...] + 1.09112[...]*I]] ? nfeltembed(nf, 'y, 1) %4 = 1.25992[...] ? nfeltembed(nf, 'y, 3) \\ there are only 2 arch. places *** at top-level: nfeltembed(nf,'y,3) *** ^----------------- *** nfeltembed: domain error in nfeltembed: index > 2 @eprog pari-2.11.2/src/functions/number_fields/rnfeltreltoabs0000644000175000017500000000136513036414402021546 0ustar billbillFunction: rnfeltreltoabs Section: number_fields C-Name: rnfeltreltoabs Prototype: GG Help: rnfeltreltoabs(rnf,x): transforms the element x from relative to absolute representation. Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$ expressed as a polynomial or polmod with polmod coefficients, computes $x$ as an element of the absolute extension $L/\Q$ as a polynomial modulo the absolute equation \kbd{\var{rnf}.pol}. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltreltoabs(L, Mod(x, L.pol)) %3 = Mod(x, x^4 + 1) ? rnfeltreltoabs(L, Mod(y, x^2-y)) %4 = Mod(x^2, x^4 + 1) ? rnfeltreltoabs(L, Mod(y,K.pol)) %5 = Mod(x^2, x^4 + 1) @eprog pari-2.11.2/src/functions/number_fields/idealcoprime0000644000175000017500000000057011636712103021155 0ustar billbillFunction: idealcoprime Section: number_fields C-Name: idealcoprime Prototype: GGG Help: idealcoprime(nf,x,y): gives an element b in nf such that b. x is an integral ideal coprime to the integral ideal y. Doc: given two integral ideals $x$ and $y$ in the number field $\var{nf}$, returns a $\beta$ in the field, such that $\beta\cdot x$ is an integral ideal coprime to $y$. pari-2.11.2/src/functions/number_fields/galoisgetgroup0000644000175000017500000000152413457566441021572 0ustar billbillFunction: galoisgetgroup Section: number_fields C-Name: galoisgetgroup Prototype: LD0,L, Description: (small):int galoisnbpol($1) (small,):int galoisnbpol($1) (small,small):vec galoisgetgroup($1, $2) Help: galoisgetgroup(a,{b}): query the galpol package for a group of order a with index b in the GAP4 Small Group library. If b is omitted, return the number of isomorphism classes of groups of order a. Doc: Query the \kbd{galpol} package for a group of order $a$ with index $b$ in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and Eamonn O'Brien. The current version of \kbd{galpol} supports groups of order $a\leq 143$. If $b$ is omitted, return the number of isomorphism classes of groups of order $a$. Variant: Also available is \fun{GEN}{galoisnbpol}{long a} when $b$ is omitted. pari-2.11.2/src/functions/number_fields/rnfeltnorm0000644000175000017500000000103213201017466020700 0ustar billbillFunction: rnfeltnorm Section: number_fields C-Name: rnfeltnorm Prototype: GG Help: rnfeltnorm(rnf,x): returns the relative norm N_{L/K}(x), as an element of K. Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$, returns the relative norm $N_{L/K}(x)$ as an element of $K$. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? rnfeltnorm(L, Mod(x, L.pol)) %2 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltnorm(L, 2) %3 = 4 ? rnfeltnorm(L, Mod(x, x^2-y)) @eprog pari-2.11.2/src/functions/number_fields/rnfequation0000644000175000017500000000427313326135265021065 0ustar billbillFunction: rnfequation Section: number_fields C-Name: rnfequation0 Prototype: GGD0,L, Help: rnfequation(nf,pol,{flag=0}): given a pol with coefficients in nf, gives an absolute equation z of the number field defined by pol. flag is optional, and can be 0: default, or non-zero, gives [z,al,k], where z defines the absolute equation L/Q as in the default behavior, al expresses as an element of L a root of the polynomial defining the base field nf, and k is a small integer such that t = b + k al is a root of z, for b a root of pol. Doc: given a number field $\var{nf}$ as output by \kbd{nfinit} (or simply a polynomial) and a polynomial \var{pol} with coefficients in $\var{nf}$ defining a relative extension $L$ of $\var{nf}$, computes an absolute equation of $L$ over $\Q$. The main variable of $\var{nf}$ \emph{must} be of lower priority than that of \var{pol} (see \secref{se:priority}). Note that for efficiency, this does not check whether the relative equation is irreducible over $\var{nf}$, but only if it is squarefree. If it is reducible but squarefree, the result will be the absolute equation of the \'etale algebra defined by \var{pol}. If \var{pol} is not squarefree, raise an \kbd{e\_DOMAIN} exception. \bprog ? rnfequation(y^2+1, x^2 - y) %1 = x^4 + 1 ? T = y^3-2; rnfequation(nfinit(T), (x^3-2)/(x-Mod(y,T))) %2 = x^6 + 108 \\ Galois closure of Q(2^(1/3)) @eprog If $\fl$ is non-zero, outputs a 3-component row vector $[z,a,k]$, where \item $z$ is the absolute equation of $L$ over $\Q$, as in the default behavior, \item $a$ expresses as a \typ{POLMOD} modulo $z$ a root $\alpha$ of the polynomial defining the base field $\var{nf}$, \item $k$ is a small integer such that $\theta = \beta+k\alpha$ is a root of $z$, where $\beta$ is a root of $\var{pol}$. It is guaranteed that $k=0$ whenever $\Q(\beta) = L$. \bprog ? T = y^3-2; pol = x^2 +x*y + y^2; ? [z,a,k] = rnfequation(T, pol, 1); ? z %3 = x^6 + 108 ? subst(T, y, a) %4 = 0 ? alpha= Mod(y, T); ? beta = Mod(x*Mod(1,T), pol); ? subst(z, x, beta + k*alpha) %7 = 0 @eprog Variant: Also available are \fun{GEN}{rnfequation}{GEN nf, GEN pol} ($\fl = 0$) and \fun{GEN}{rnfequation2}{GEN nf, GEN pol} ($\fl = 1$). pari-2.11.2/src/functions/number_fields/bnfisintnorm0000644000175000017500000000157712314242551021237 0ustar billbillFunction: bnfisintnorm Section: number_fields C-Name: bnfisintnorm Prototype: GG Help: bnfisintnorm(bnf,x): compute a complete system of solutions (modulo units of positive norm) of the absolute norm equation N(a)=x, where a belongs to the maximal order of big number field bnf (if bnf is not certified, this depends on GRH). Doc: computes a complete system of solutions (modulo units of positive norm) of the absolute norm equation $\Norm(a)=x$, where $a$ is an integer in $\var{bnf}$. If $\var{bnf}$ has not been certified, the correctness of the result depends on the validity of \idx{GRH}. See also \tet{bnfisnorm}. Variant: The function \fun{GEN}{bnfisintnormabs}{GEN bnf, GEN a} returns a complete system of solutions modulo units of the absolute norm equation $|\Norm(x)| = |a|$. As fast as \kbd{bnfisintnorm}, but solves the two equations $\Norm(x) = \pm a$ simultaneously. pari-2.11.2/src/functions/number_fields/rnfsteinitz0000644000175000017500000000172511636712103021102 0ustar billbillFunction: rnfsteinitz Section: number_fields C-Name: rnfsteinitz Prototype: GG Help: rnfsteinitz(nf,x): given an order x as output by rnfpseudobasis, gives [A,I,D,d] where (A,I) is a pseudo basis where all the ideals except perhaps the last are trivial. Doc: given a number field $\var{nf}$ as output by \kbd{nfinit} and either a polynomial $x$ with coefficients in $\var{nf}$ defining a relative extension $L$ of $\var{nf}$, or a pseudo-basis $x$ of such an extension as output for example by \kbd{rnfpseudobasis}, computes another pseudo-basis $(A,I)$ (not in HNF in general) such that all the ideals of $I$ except perhaps the last one are equal to the ring of integers of $\var{nf}$, and outputs the four-component row vector $[A,I,D,d]$ as in \kbd{rnfpseudobasis}. The name of this function comes from the fact that the ideal class of the last ideal of $I$, which is well defined, is the \idx{Steinitz class} of the $\Z_K$-module $\Z_L$ (its image in $SK_0(\Z_K)$). pari-2.11.2/src/functions/number_fields/bnflog0000644000175000017500000000251413326135265017775 0ustar billbillFunction: bnflog Section: number_fields C-Name: bnflog Prototype: GG Help: bnflog(bnf, l): let bnf be attached to a number field F and let l be a prime number. Return the logarithmic l-class group Cl~_F. Doc: let \var{bnf} be a \var{bnf} structure attached to the number field $F$ and let $l$ be a prime number (hereafter denoted $\ell$ for typographical reasons). Return the logarithmic $\ell$-class group $\widetilde{Cl}_F$ of $F$. This is an abelian group, conjecturally finite (known to be finite if $F/\Q$ is abelian). The function returns if and only if the group is indeed finite (otherwise it would run into an infinite loop). Let $S = \{ \goth{p}_1,\dots, \goth{p}_k\}$ be the set of $\ell$-adic places (maximal ideals containing $\ell$). The function returns $[D, G(\ell), G']$, where \item $D$ is the vector of elementary divisors for $\widetilde{Cl}_F$. \item $G(\ell)$ is the vector of elementary divisors for the (conjecturally finite) abelian group $$\widetilde{\Cl}(\ell) = \{ \goth{a} = \sum_{i \leq k} a_i \goth{p}_i :~\deg_F \goth{a} = 0\},$$ where the $\goth{p}_i$ are the $\ell$-adic places of $F$; this is a subgroup of $\widetilde{\Cl}$. \item $G'$ is the vector of elementary divisors for the $\ell$-Sylow $Cl'$ of the $S$-class group of $F$; the group $\widetilde{\Cl}$ maps to $Cl'$ with a simple co-kernel. pari-2.11.2/src/functions/number_fields/nfeltdivrem0000644000175000017500000000053113201017466021034 0ustar billbillFunction: nfeltdivrem Section: number_fields C-Name: nfdivrem Prototype: GGG Help: nfeltdivrem(nf,x,y): gives [q,r] such that r=x-qy is small. Doc: given two elements $x$ and $y$ in \var{nf}, gives a two-element row vector $[q,r]$ such that $x=qy+r$, $q$ is an algebraic integer in $\var{nf}$, and the components of $r$ are reasonably small. pari-2.11.2/src/functions/number_fields/nfsplitting0000644000175000017500000000313113326135265021063 0ustar billbillFunction: nfsplitting Section: number_fields C-Name: nfsplitting Prototype: GDG Help: nfsplitting(P,{d}): defining polynomial over Q for the splitting field of P, that is the smallest field over which P is totally split. P can also be given by a nf structure. If d is given, it must be a multiple of the splitting field degree. Doc: defining polynomial over~$\Q$ for the splitting field of \var{P}, that is the smallest field over which $P$ is totally split. If $P$ can also be given by a~\kbd{nf} structure, which is more efficient. If $d$ is given, it must be a multiple of the splitting field degree. Note that if $P$ is reducible the splitting field degree can be smaller than the degree of $P$. \bprog ? K = nfinit(x^3-2); ? nfsplitting(K) %2 = x^6 + 108 ? nfsplitting(x^8-2) %3 = x^16 + 272*x^8 + 64 ? S = nfsplitting(x^6-8) // reducible %4 = x^4+2*x^2+4 ? lift(nfroots(subst(S,x,a),x^6-8)) %5 = [-a,a,-1/2*a^3-a,-1/2*a^3,1/2*a^3,1/2*a^3+a] @eprog \noindent Specifying the degree of the splitting field can make the computation faster. \bprog ? nfsplitting(x^17-123); time = 3,607 ms. ? poldegree(%) %2 = 272 ? nfsplitting(x^17-123,272); time = 150 ms. ? nfsplitting(x^17-123,273); *** nfsplitting: Warning: ignoring incorrect degree bound 273 time = 3,611 ms. @eprog \noindent The complexity of the algorithm is polynomial in the degree $d$ of the splitting field and the bitsize of $T$; if $d$ is large the result will likely be unusable, e.g. \kbd{nfinit} will not be an option: \bprog ? nfsplitting(x^6-x-1) [... degree 720 polynomial deleted ...] time = 11,020 ms. @eprog pari-2.11.2/src/functions/number_fields/bnfcertify0000644000175000017500000000265313036414402020654 0ustar billbillFunction: bnfcertify Section: number_fields C-Name: bnfcertify0 Prototype: lGD0,L, Help: bnfcertify(bnf,{flag = 0}): certify the correctness (i.e. remove the GRH) of the bnf data output by bnfinit. If flag is present, only certify that the class group is a quotient of the one computed in bnf (much simpler in general). Doc: $\var{bnf}$ being as output by \kbd{bnfinit}, checks whether the result is correct, i.e.~whether it is possible to remove the assumption of the Generalized Riemann Hypothesis\sidx{GRH}. It is correct if and only if the answer is 1. If it is incorrect, the program may output some error message, or loop indefinitely. You can check its progress by increasing the debug level. The \var{bnf} structure must contain the fundamental units: \bprog ? K = bnfinit(x^3+2^2^3+1); bnfcertify(K) *** at top-level: K=bnfinit(x^3+2^2^3+1);bnfcertify(K) *** ^------------- *** bnfcertify: missing units in bnf. ? K = bnfinit(x^3+2^2^3+1, 1); \\ include units ? bnfcertify(K) %3 = 1 @eprog If flag is present, only certify that the class group is a quotient of the one computed in bnf (much simpler in general); likewise, the computed units may form a subgroup of the full unit group. In this variant, the units are no longer needed: \bprog ? K = bnfinit(x^3+2^2^3+1); bnfcertify(K, 1) %4 = 1 @eprog Variant: Also available is \fun{GEN}{bnfcertify}{GEN bnf} ($\fl=0$). pari-2.11.2/src/functions/number_fields/bnrdisc0000644000175000017500000000272513201017466020150 0ustar billbillFunction: bnrdisc Section: number_fields C-Name: bnrdisc0 Prototype: GDGDGD0,L, Help: bnrdisc(A,{B},{C},{flag=0}): absolute or relative [N,R1,discf] of the field defined by A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf, modulus] or [bnf,modulus,subgroup], where bnf is as output by bnfinit, bnr by bnrinit, and subgroup is the HNF matrix of a subgroup of the corresponding ray class group (if omitted, the trivial subgroup). flag is optional whose binary digits mean 1: give relative data; 2: return 0 if modulus is not the conductor. Doc: $A$, $B$, $C$ defining a class field $L$ over a ground field $K$ (of type \kbd{[\var{bnr}]}, \kbd{[\var{bnr}, \var{subgroup}]}, \kbd{[\var{bnr}, \var{character}]}, \kbd{[\var{bnf}, \var{modulus}]} or \kbd{[\var{bnf}, \var{modulus}, \var{subgroup}]}, \secref{se:CFT}), outputs data $[N,r_1,D]$ giving the discriminant and signature of $L$, depending on the binary digits of \fl: \item 1: if this bit is unset, output absolute data related to $L/\Q$: $N$ is the absolute degree $[L:\Q]$, $r_1$ the number of real places of $L$, and $D$ the discriminant of $L/\Q$. Otherwise, output relative data for $L/K$: $N$ is the relative degree $[L:K]$, $r_1$ is the number of real places of $K$ unramified in $L$ (so that the number of real places of $L$ is equal to $r_1$ times $N$), and $D$ is the relative discriminant ideal of $L/K$. \item 2: if this bit is set and if the modulus is not the conductor of $L$, only return 0. pari-2.11.2/src/functions/number_fields/galoissubfields0000644000175000017500000000064713201017466021704 0ustar billbillFunction: galoissubfields Section: number_fields C-Name: galoissubfields Prototype: GD0,L,Dn Help: galoissubfields(G,{flag=0},{v}): output all the subfields of G. flag has the same meaning as for galoisfixedfield. Doc: outputs all the subfields of the Galois group \var{G}, as a vector. This works by applying \kbd{galoisfixedfield} to all subgroups. The meaning of \var{flag} is the same as for \kbd{galoisfixedfield}. pari-2.11.2/src/functions/number_fields/bnrisgalois0000644000175000017500000000254213201017466021035 0ustar billbillFunction: bnrisgalois Section: number_fields C-Name: bnrisgalois Prototype: lGGG Help: bnrisgalois(bnr, gal, H): check whether the class field attached to the subgroup H is Galois over the subfield of bnr.nf fixed by the Galois group gal, which can be given as output by galoisinit, or as a matrix or a vector of matrices as output by bnrgaloismatrix. The ray class field attached to bnr need to be Galois, which is not checked. Doc: check whether the class field attached to the subgroup $H$ is Galois over the subfield of \kbd{bnr.nf} fixed by the group \var{gal}, which can be given as output by \tet{galoisinit}, or as a matrix or a vector of matrices as output by \kbd{bnrgaloismatrix}, the second option being preferable, since it saves the recomputation of the matrices. Note: The function assumes that the ray class field attached to bnr is Galois, which is not checked. In the following example, we lists the congruence subgroups of subextension of degree at most $3$ of the ray class field of conductor $9$ which are Galois over the rationals. \bprog K=bnfinit(a^4-3*a^2+253009); G=galoisinit(K); B=bnrinit(K,9,1); L1=[H|H<-subgrouplist(B,3), bnrisgalois(B,G,H)] ## M=bnrgaloismatrix(B,G) L2=[H|H<-subgrouplist(B,3), bnrisgalois(B,M,H)] ## @eprog The second computation is much faster since \kbd{bnrgaloismatrix(B,G)} is computed only once. pari-2.11.2/src/functions/number_fields/nfhilbert0000644000175000017500000000134011636712103020471 0ustar billbillFunction: nfhilbert Section: number_fields C-Name: nfhilbert0 Prototype: lGGGDG Help: nfhilbert(nf,a,b,{pr}): if pr is omitted, global Hilbert symbol (a,b) in nf, that is 1 if X^2-aY^2-bZ^2 has a non-trivial solution (X,Y,Z) in nf, -1 otherwise. Otherwise compute the local symbol modulo the prime ideal pr. Doc: if \var{pr} is omitted, compute the global quadratic \idx{Hilbert symbol} $(a,b)$ in $\var{nf}$, that is $1$ if $x^2 - a y^2 - b z^2$ has a non trivial solution $(x,y,z)$ in $\var{nf}$, and $-1$ otherwise. Otherwise compute the local symbol modulo the prime ideal \var{pr}, as output by \kbd{idealprimedec}. Variant: Also available is \fun{long}{nfhilbert}{GEN bnf,GEN a,GEN b} (global quadratic Hilbert symbol). pari-2.11.2/src/functions/number_fields/nfelttrace0000644000175000017500000000022611636712103020645 0ustar billbillFunction: nfelttrace Section: number_fields C-Name: nftrace Prototype: GG Help: nfelttrace(nf,x): trace of x. Doc: returns the absolute trace of $x$. pari-2.11.2/src/functions/number_fields/galoissubgroups0000644000175000017500000000145613201017466021754 0ustar billbillFunction: galoissubgroups Section: number_fields C-Name: galoissubgroups Prototype: G Help: galoissubgroups(G): output all the subgroups of G. Doc: outputs all the subgroups of the Galois group \kbd{gal}. A subgroup is a vector [\var{gen}, \var{orders}], with the same meaning as for $\var{gal}.gen$ and $\var{gal}.orders$. Hence \var{gen} is a vector of permutations generating the subgroup, and \var{orders} is the relatives orders of the generators. The cardinality of a subgroup is the product of the relative orders. Such subgroup can be used instead of a Galois group in the following command: \kbd{galoisisabelian}, \kbd{galoissubgroups}, \kbd{galoisexport} and \kbd{galoisidentify}. To get the subfield fixed by a subgroup \var{sub} of \var{gal}, use \bprog galoisfixedfield(gal,sub[1]) @eprog pari-2.11.2/src/functions/number_fields/poltschirnhaus0000644000175000017500000000072211636712103021565 0ustar billbillFunction: poltschirnhaus Section: number_fields C-Name: tschirnhaus Prototype: G Help: poltschirnhaus(x): random Tschirnhausen transformation of the polynomial x. Doc: applies a random Tschirnhausen transformation to the polynomial $x$, which is assumed to be non-constant and separable, so as to obtain a new equation for the \'etale algebra defined by $x$. This is for instance useful when computing resolvents, hence is used by the \kbd{polgalois} function. pari-2.11.2/src/functions/number_fields/bnfisunit0000644000175000017500000000306311636712103020521 0ustar billbillFunction: bnfisunit Section: number_fields C-Name: bnfisunit Prototype: GG Help: bnfisunit(bnf,x): bnf being output by bnfinit, gives the column vector of exponents of x on the fundamental units and the roots of unity if x is a unit, the empty vector otherwise. Doc: \var{bnf} being the number field data output by \kbd{bnfinit} and $x$ being an algebraic number (type integer, rational or polmod), this outputs the decomposition of $x$ on the fundamental units and the roots of unity if $x$ is a unit, the empty vector otherwise. More precisely, if $u_1$,\dots,$u_r$ are the fundamental units, and $\zeta$ is the generator of the group of roots of unity (\kbd{bnf.tu}), the output is a vector $[x_1,\dots,x_r,x_{r+1}]$ such that $x=u_1^{x_1}\cdots u_r^{x_r}\cdot\zeta^{x_{r+1}}$. The $x_i$ are integers for $i\le r$ and is an integer modulo the order of $\zeta$ for $i=r+1$. Note that \var{bnf} need not contain the fundamental unit explicitly: \bprog ? setrand(1); bnf = bnfinit(x^2-x-100000); ? bnf.fu *** at top-level: bnf.fu *** ^-- *** _.fu: missing units in .fu. ? u = [119836165644250789990462835950022871665178127611316131167, \ 379554884019013781006303254896369154068336082609238336]~; ? bnfisunit(bnf, u) %3 = [-1, Mod(0, 2)]~ @eprog\noindent The given $u$ is the inverse of the fundamental unit implicitly stored in \var{bnf}. In this case, the fundamental unit was not computed and stored in algebraic form since the default accuracy was too low. (Re-run the command at \bs g1 or higher to see such diagnostics.) pari-2.11.2/src/functions/number_fields/bnrinit0000644000175000017500000000430413201017466020164 0ustar billbillFunction: bnrinit Section: number_fields C-Name: bnrinit0 Prototype: GGD0,L, Help: bnrinit(bnf,f,{flag=0}): given a bnf as output by bnfinit and a modulus f, initializes data linked to the ray class group structure corresponding to this module. flag is optional, and can be 0: default, 1: compute also the generators. Description: (gen,gen,?small):bnr bnrinit0($1, $2, $3) Doc: $\var{bnf}$ is as output by \kbd{bnfinit} (including fundamental units), $f$ is a modulus, initializes data linked to the ray class group structure corresponding to this module, a so-called \kbd{bnr} structure. One can input the attached \var{bid} with generators for $f$ instead of the module itself, saving some time. (As in \tet{idealstar}, the finite part of the conductor may be given by a factorization into prime ideals, as produced by \tet{idealfactor}.) The following member functions are available on the result: \kbd{.bnf} is the underlying \var{bnf}, \kbd{.mod} the modulus, \kbd{.bid} the \kbd{bid} structure attached to the modulus; finally, \kbd{.clgp}, \kbd{.no}, \kbd{.cyc}, \kbd{.gen} refer to the ray class group (as a finite abelian group), its cardinality, its elementary divisors, its generators (only computed if $\fl = 1$). The last group of functions are different from the members of the underlying \var{bnf}, which refer to the class group; use \kbd{\var{bnr}.bnf.\var{xxx}} to access these, e.g.~\kbd{\var{bnr}.bnf.cyc} to get the cyclic decomposition of the class group. They are also different from the members of the underlying \var{bid}, which refer to $(\Z_K/f)^*$; use \kbd{\var{bnr}.bid.\var{xxx}} to access these, e.g.~\kbd{\var{bnr}.bid.no} to get $\phi(f)$. If $\fl=0$ (default), the generators of the ray class group are not computed, which saves time. Hence \kbd{\var{bnr}.gen} would produce an error. If $\fl=1$, as the default, except that generators are computed. Variant: Instead the above hardcoded numerical flags, one should rather use \fun{GEN}{Buchray}{GEN bnf, GEN module, long flag} where flag is an or-ed combination of \kbd{nf\_GEN} (include generators) and \kbd{nf\_INIT} (if omitted, return just the cardinality of the ray class group and its structure), possibly 0. pari-2.11.2/src/functions/number_fields/bnfdecodemodule0000644000175000017500000000111713457566437021661 0ustar billbillFunction: bnfdecodemodule Section: number_fields C-Name: decodemodule Prototype: GG Help: bnfdecodemodule(nf,m): given a coded module m as in bnrdisclist, gives the true module. Doc: if $m$ is a module as output in the first component of an extension given by \kbd{bnrdisclist}, outputs the true module. \bprog ? K = bnfinit(x^2+23); L = bnrdisclist(K, 10); s = L[2] %1 = [[[Vecsmall([8]), Vecsmall([1])], [[0, 0, 0]]], [[Vecsmall([9]), Vecsmall([1])], [[0, 0, 0]]]] ? bnfdecodemodule(K, s[1][1]) %2 = [2 0] [0 1] ? bnfdecodemodule(K,s[2][1]) %3 = [2 1] [0 1] @eprog pari-2.11.2/src/functions/number_fields/rnfpseudobasis0000644000175000017500000000343413326135265021557 0ustar billbillFunction: rnfpseudobasis Section: number_fields C-Name: rnfpseudobasis Prototype: GG Help: rnfpseudobasis(nf,T): given an irreducible polynomial T with coefficients in nf, returns [A,J,D,d] where [A,J] is a pseudo basis of the maximal order of the extension, D is the relative ideal discriminant, and d is the relative discriminant in nf^*/nf*^2. Doc: given an \var{nf} structure attached to a number field $K$, as output by \kbd{nfinit}, and a monic irreducible polynomial $T$ in $K[x]$ defining a relative extension $L = K[x]/(T)$, computes the relative discriminant of $L$ and a pseudo-basis $(A,J)$ for the maximal order $\Z_L$ viewed as a $\Z_K$-module. This is output as a vector $[A,J,D,d]$, where $D$ is the relative ideal discriminant and $d$ is the relative discriminant considered as an element of $K^*/{K^*}^2$. \bprog ? K = nfinit(y^2+1); ? [A,J,D,d] = rnfpseudobasis(K, x^2+y); ? A %3 = [1 0] [0 1] ? J %4 = [1, 1] ? D %5 = [0, -4]~ ? d %6 = [0, -1]~ @eprog \misctitle{Huge discriminants, helping rnfdisc} the format $[T,B]$ is also accepted instead of $T$ and produce an order which is maximal at all primes $p < B$, see \kbd{??rnfinit}. \bprog ? p = 585403248812100232206609398101; ? q = 711171340236468512951957953369; ? T = x^2 + 3*(p*q)^2; ? [A,J,D,d] = V = rnfpseudobasis(K, T); D time = 22,178 ms. %10 = [3 0] [0 3] ? [A,J,D,d] = W = rnfpseudobasis(K, [T,100]); D time = 5 ms. %11 = [3 0] [0 3] ? V == W %12 = 1 @eprog\noindent In this example, the results are identical since $D \cap \Z$ factors over primes less than $100$. Had it not been the case, the order would have been guaranteed maximal at primes $\goth{p} | p $ for $p \leq 100$ only (and might not have been maximal at any maximal ideal $\goth{p}$ such that $\goth{p}^2$ dividing $D$. pari-2.11.2/src/functions/number_fields/bnrisconductor0000644000175000017500000000120313201017466021550 0ustar billbillFunction: bnrisconductor Section: number_fields C-Name: bnrisconductor0 Prototype: lGDGDG Help: bnrisconductor(A,{B},{C}): returns 1 if the modulus is the conductor of the subfield of the ray class field given by A,B,C (see bnrdisc), and 0 otherwise. Slightly faster than bnrconductor if this is the only desired result. Doc: fast variant of \kbd{bnrconductor}$(A,B,C)$; $A$, $B$, $C$ represent an extension of the base field, given by class field theory (see~\secref{se:CFT}). Outputs 1 if this modulus is the conductor, and 0 otherwise. This is slightly faster than \kbd{bnrconductor} when the character or subgroup is not primitive. pari-2.11.2/src/functions/number_fields/rnfidealdown0000644000175000017500000000074213036414402021172 0ustar billbillFunction: rnfidealdown Section: number_fields C-Name: rnfidealdown Prototype: GG Help: rnfidealdown(rnf,x): finds the intersection of the ideal x with the base field. Doc: let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an ideal of $L$, given either in relative form or by a $\Z$-basis of elements of $L$ (see \secref{se:rnfidealabstorel}). This function returns the ideal of $K$ below $x$, i.e.~the intersection of $x$ with $K$. pari-2.11.2/src/functions/number_fields/bnfinit0000644000175000017500000001212413201017466020147 0ustar billbillFunction: bnfinit Section: number_fields C-Name: bnfinit0 Prototype: GD0,L,DGp Help: bnfinit(P,{flag=0},{tech=[]}): compute the necessary data for future use in ideal and unit group computations, including fundamental units if they are not too large. flag and tech are both optional. flag can be any of 0: default, 1: insist on having fundamental units. See manual for details about tech. Description: (gen):bnf:prec Buchall($1, 0, $prec) (gen, 0):bnf:prec Buchall($1, 0, $prec) (gen, 1):bnf:prec Buchall($1, nf_FORCE, $prec) (gen, ?small, ?gen):bnf:prec bnfinit0($1, $2, $3, $prec) Doc: initializes a \kbd{bnf} structure. Used in programs such as \kbd{bnfisprincipal}, \kbd{bnfisunit} or \kbd{bnfnarrow}. By default, the results are conditional on the GRH, see \ref{se:GRHbnf}. The result is a 10-component vector \var{bnf}. This implements \idx{Buchmann}'s sub-exponential algorithm for computing the class group, the regulator and a system of \idx{fundamental units} of the general algebraic number field $K$ defined by the irreducible polynomial $P$ with integer coefficients. If the precision becomes insufficient, \kbd{gp} does not strive to compute the units by default ($\fl=0$). When $\fl=1$, we insist on finding the fundamental units exactly. Be warned that this can take a very long time when the coefficients of the fundamental units on the integral basis are very large. If the fundamental units are simply too large to be represented in this form, an error message is issued. They could be obtained using the so-called compact representation of algebraic numbers as a formal product of algebraic integers. The latter is implemented internally but not publicly accessible yet. $\var{tech}$ is a technical vector (empty by default, see \ref{se:GRHbnf}). Careful use of this parameter may speed up your computations, but it is mostly obsolete and you should leave it alone. \smallskip The components of a \var{bnf} or \var{sbnf} are technical and never used by the casual user. In fact: \emph{never access a component directly, always use a proper member function.} However, for the sake of completeness and internal documentation, their description is as follows. We use the notations explained in the book by H. Cohen, \emph{A Course in Computational Algebraic Number Theory}, Graduate Texts in Maths \key{138}, Springer-Verlag, 1993, Section 6.5, and subsection 6.5.5 in particular. $\var{bnf}[1]$ contains the matrix $W$, i.e.~the matrix in Hermite normal form giving relations for the class group on prime ideal generators $(\goth{p}_i)_{1\le i\le r}$. $\var{bnf}[2]$ contains the matrix $B$, i.e.~the matrix containing the expressions of the prime ideal factorbase in terms of the $\goth{p}_i$. It is an $r\times c$ matrix. $\var{bnf}[3]$ contains the complex logarithmic embeddings of the system of fundamental units which has been found. It is an $(r_1+r_2)\times(r_1+r_2-1)$ matrix. $\var{bnf}[4]$ contains the matrix $M''_C$ of Archimedean components of the relations of the matrix $(W|B)$. $\var{bnf}[5]$ contains the prime factor base, i.e.~the list of prime ideals used in finding the relations. $\var{bnf}[6]$ used to contain a permutation of the prime factor base, but has been obsoleted. It contains a dummy $0$. $\var{bnf}[7]$ or \kbd{\var{bnf}.nf} is equal to the number field data $\var{nf}$ as would be given by \kbd{nfinit}. $\var{bnf}[8]$ is a vector containing the classgroup \kbd{\var{bnf}.clgp} as a finite abelian group, the regulator \kbd{\var{bnf}.reg}, a $1$ (used to contain an obsolete ``check number''), the number of roots of unity and a generator \kbd{\var{bnf}.tu}, the fundamental units \kbd{\var{bnf}.fu}. $\var{bnf}[9]$ is a 3-element row vector used in \tet{bnfisprincipal} only and obtained as follows. Let $D = U W V$ obtained by applying the \idx{Smith normal form} algorithm to the matrix $W$ (= $\var{bnf}[1]$) and let $U_r$ be the reduction of $U$ modulo $D$. The first elements of the factorbase are given (in terms of \kbd{bnf.gen}) by the columns of $U_r$, with Archimedean component $g_a$; let also $GD_a$ be the Archimedean components of the generators of the (principal) ideals defined by the \kbd{bnf.gen[i]\pow bnf.cyc[i]}. Then $\var{bnf}[9]=[U_r, g_a, GD_a]$. $\var{bnf}[10]$ is by default unused and set equal to 0. This field is used to store further information about the field as it becomes available, which is rarely needed, hence would be too expensive to compute during the initial \kbd{bnfinit} call. For instance, the generators of the principal ideals \kbd{bnf.gen[i]\pow bnf.cyc[i]} (during a call to \tet{bnrisprincipal}), or those corresponding to the relations in $W$ and $B$ (when the \kbd{bnf} internal precision needs to be increased). Variant: Also available is \fun{GEN}{Buchall}{GEN P, long flag, long prec}, corresponding to \kbd{tech = NULL}, where \kbd{flag} is either $0$ (default) or \tet{nf_FORCE} (insist on finding fundamental units). The function \fun{GEN}{Buchall_param}{GEN P, double c1, double c2, long nrpid, long flag, long prec} gives direct access to the technical parameters. pari-2.11.2/src/functions/number_fields/rnfelttrace0000644000175000017500000000100713201017466021025 0ustar billbillFunction: rnfelttrace Section: number_fields C-Name: rnfelttrace Prototype: GG Help: rnfelttrace(rnf,x): returns the relative trace Tr_{L/K}(x), as an element of K. Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$, returns the relative trace $Tr_{L/K}(x)$ as an element of $K$. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? rnfelttrace(L, Mod(x, L.pol)) %2 = 0 ? rnfelttrace(L, 2) %3 = 4 ? rnfelttrace(L, Mod(x, x^2-y)) @eprog pari-2.11.2/src/functions/number_fields/galoischarpoly0000644000175000017500000000227513326135265021552 0ustar billbillFunction: galoischarpoly Section: number_fields C-Name: galoischarpoly Prototype: GGD1,L, Help: galoischarpoly(gal, chi, {o=1}): return the list of characteristic polynomials of the representation attached to the character chi. Doc: Let $G$ be the group attached to the \kbd{galoisinit} structure~\var{gal}, and let $\chi$ be the character of some representation $\rho$ of the group $G$, where a polynomial variable is to be interpreted as an $o$-th root of 1, e.g., if \kbd{[T,o] = galoischartable(gal)} and $\chi$ is a column of \kbd{T}. Return the list of characteristic polynomials $\det(1 - \rho(g)T)$, where $g$ runs through representatives of the conjugacy classes in \kbd{galoisconjclasses(gal)}, with the same ordering. \bprog ? T = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; ? polgalois(T) %2 = [10, 1, 1, "D(5) = 5:2"] ? K = nfsplitting(T); ? gal = galoisinit(K); \\ dihedral of order 10 ? [T,o] = galoischartable(gal); ? o %5 = 5 ? galoischarpoly(gal, T[,1], o) \\ T[,1] is the trivial character %6 = [-x + 1, -x + 1, -x + 1, -x + 1]~ ? galoischarpoly(gal, T[,3], o) %7 = [x^2 - 2*x + 1, x^2 + (y^3 + y^2 + 1)*x + 1, -x^2 + 1, x^2 + (-y^3 - y^2)*x + 1]~ @eprog pari-2.11.2/src/functions/number_fields/polredbest0000644000175000017500000000434513447371554020704 0ustar billbillFunction: polredbest Section: number_fields C-Name: polredbest Prototype: GD0,L, Help: polredbest(T,{flag=0}): reduction of the polynomial T (gives minimal polynomials only). If flag=1, gives also elements. Doc: finds a polynomial with reasonably small coefficients defining the same number field as $T$. All $T$ accepted by \tet{nfinit} are also allowed here (e.g. non-monic polynomials, \kbd{nf}, \kbd{bnf}, \kbd{[T,Z\_K\_basis]}). Contrary to \tet{polredabs}, this routine runs in polynomial time, but it offers no guarantee as to the minimality of its result. This routine computes an LLL-reduced basis for an order in $\Q[X]/(T)$, then examines small linear combinations of the basis vectors, computing their characteristic polynomials. It returns the \emph{separable} polynomial $P$ of smallest discriminant, the one with lexicographically smallest \kbd{abs(Vec(P))} in case of ties. This is a good candidate for subsequent number field computations since it guarantees that the denominators of algebraic integers, when expressed in the power basis, are reasonably small. With no claim of minimality, though. It can happen that iterating this functions yields better and better polynomials, until it stabilizes: \bprog ? \p5 ? P = X^12+8*X^8-50*X^6+16*X^4-3069*X^2+625; ? poldisc(P)*1. %2 = 1.2622 E55 ? P = polredbest(P); ? poldisc(P)*1. %4 = 2.9012 E51 ? P = polredbest(P); ? poldisc(P)*1. %6 = 8.8704 E44 @eprog\noindent In this example, the initial polynomial $P$ is the one returned by \tet{polredabs}, and the last one is stable. If $\fl = 1$: outputs a two-component row vector $[P,a]$, where $P$ is the default output and \kbd{Mod(a, P)} is a root of the original $T$. \bprog ? [P,a] = polredbest(x^4 + 8, 1) %1 = [x^4 + 2, Mod(x^3, x^4 + 2)] ? charpoly(a) %2 = x^4 + 8 @eprog\noindent In particular, the map $\Q[x]/(T) \to \Q[x]/(P)$, $x\mapsto \kbd{Mod(a,P)}$ defines an isomorphism of number fields, which can be computed as \bprog subst(lift(Q), 'x, a) @eprog\noindent if $Q$ is a \typ{POLMOD} modulo $T$; \kbd{b = modreverse(a)} returns a \typ{POLMOD} giving the inverse of the above map (which should be useless since $\Q[x]/(P)$ is a priori a better representation for the number field and its elements). pari-2.11.2/src/functions/number_fields/nfbasistoalg0000644000175000017500000000107113201017466021171 0ustar billbillFunction: nfbasistoalg Section: number_fields C-Name: basistoalg Prototype: GG Help: nfbasistoalg(nf,x): transforms the column vector x on the integral basis into an algebraic number. Doc: Given an algebraic number $x$ in the number field \var{nf}, transforms it into \typ{POLMOD} form. \bprog ? nf = nfinit(y^2 + 4); ? nf.zk %2 = [1, 1/2*y] ? nfbasistoalg(nf, [1,1]~) %3 = Mod(1/2*y + 1, y^2 + 4) ? nfbasistoalg(nf, y) %4 = Mod(y, y^2 + 4) ? nfbasistoalg(nf, Mod(y, y^2+4)) %5 = Mod(y, y^2 + 4) @eprog This is the inverse function of \kbd{nfalgtobasis}. pari-2.11.2/src/functions/number_fields/bnrchar0000644000175000017500000000240113201017466020132 0ustar billbillFunction: bnrchar Section: number_fields C-Name: bnrchar Prototype: GGDG Help: bnrchar(bnr,g,{v}): returns all characters chi on bnr.clgp such that chi(g[i]) = e(v[i]); if v is omitted, returns all characters that are trivial on the g[i]. Doc: returns all characters $\chi$ on \kbd{bnr.clgp} such that $\chi(g_i) = e(v_i)$, where $e(x) = \exp(2i\pi x)$. If $v$ is omitted, returns all characters that are trivial on the $g_i$. Else the vectors $g$ and $v$ must have the same length, the $g_i$ must be ideals in any form, and each $v_i$ is a rational number whose denominator must divide the order of $g_i$ in the ray class group. For convenience, the vector of the $g_i$ can be replaced by a matrix whose columns give their discrete logarithm, as given by \kbd{bnrisprincipal}; this allows to specify abstractly a subgroup of the ray class group. \bprog ? bnr = bnrinit(bnfinit(x), [160,[1]], 1); /* (Z/160Z)^* */ ? bnr.cyc %2 = [8, 4, 2] ? g = bnr.gen; ? bnrchar(bnr, g, [1/2,0,0]) %4 = [[4, 0, 0]] \\ a unique character ? bnrchar(bnr, [g[1],g[3]]) \\ all characters trivial on g[1] and g[3] %5 = [[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 0, 0]] ? bnrchar(bnr, [1,0,0;0,1,0;0,0,2]) %6 = [[0, 0, 1], [0, 0, 0]] \\ characters trivial on given subgroup @eprog pari-2.11.2/src/functions/number_fields/idealmul0000644000175000017500000000237313201017466020317 0ustar billbillFunction: idealmul Section: number_fields C-Name: idealmul0 Prototype: GGGD0,L, Help: idealmul(nf,x,y,{flag=0}): product of the two ideals x and y in the number field nf. If (optional) flag is non-nul, reduce the result. Description: (gen, gen, gen, ?0):gen idealmul($1, $2, $3) (gen, gen, gen, 1):gen idealmulred($1, $2, $3) (gen, gen, gen, #small):gen $"invalid flag in idealmul" (gen, gen, gen, small):gen idealmul0($1, $2, $3, $4) Doc: ideal multiplication of the ideals $x$ and $y$ in the number field \var{nf}; the result is the ideal product in HNF. If either $x$ or $y$ are extended ideals\sidx{ideal (extended)}, their principal part is suitably updated: i.e. multiplying $[I,t]$, $[J,u]$ yields $[IJ, tu]$; multiplying $I$ and $[J, u]$ yields $[IJ, u]$. \bprog ? nf = nfinit(x^2 + 1); ? idealmul(nf, 2, x+1) %2 = [4 2] [0 2] ? idealmul(nf, [2, x], x+1) \\ extended ideal * ideal %3 = [[4, 2; 0, 2], x] ? idealmul(nf, [2, x], [x+1, x]) \\ two extended ideals %4 = [[4, 2; 0, 2], [-1, 0]~] @eprog\noindent If $\fl$ is non-zero, reduce the result using \kbd{idealred}. Variant: \noindent See also \fun{GEN}{idealmul}{GEN nf, GEN x, GEN y} ($\fl=0$) and \fun{GEN}{idealmulred}{GEN nf, GEN x, GEN y} ($\fl\neq0$). pari-2.11.2/src/functions/number_fields/rnfcharpoly0000644000175000017500000000110112314242551021035 0ustar billbillFunction: rnfcharpoly Section: number_fields C-Name: rnfcharpoly Prototype: GGGDn Help: rnfcharpoly(nf,T,a,{var='x}): characteristic polynomial of a over nf, where a belongs to the algebra defined by T over nf. Returns a polynomial in variable var (x by default). Doc: characteristic polynomial of $a$ over $\var{nf}$, where $a$ belongs to the algebra defined by $T$ over $\var{nf}$, i.e.~$\var{nf}[X]/(T)$. Returns a polynomial in variable $v$ ($x$ by default). \bprog ? nf = nfinit(y^2+1); ? rnfcharpoly(nf, x^2+y*x+1, x+y) %2 = x^2 + Mod(-y, y^2 + 1)*x + 1 @eprog pari-2.11.2/src/functions/number_fields/bnflogdegree0000644000175000017500000000217513326135265021154 0ustar billbillFunction: bnflogdegree Section: number_fields C-Name: bnflogdegree Prototype: GGG Help: bnflogdegree(nf, A, l): let A be an ideal, return exp(deg_F A) the exponential of the l-adic logarithmic degree. Doc: Let \var{nf} be a \var{nf} structure attached to a number field $F$, and let $l$ be a prime number (hereafter denoted $\ell$). The $\ell$-adified group of id\`{e}les of $F$ quotiented by the group of logarithmic units is identified to the $\ell$-group of logarithmic divisors $\oplus \Z_\ell [\goth{p}]$, generated by the maximal ideals of $F$. The \emph{degree} map $\deg_F$ is additive with values in $\Z_\ell$, defined by $\deg_F \goth{p} = \tilde{f}_{\goth{p}} \deg_\ell p$, where the integer $\tilde{f}_{\goth{p}}$ is as in \tet{bnflogef} and $\deg_\ell p$ is $\log_\ell p$ for $p\neq \ell$, $\log_\ell (1 + \ell)$ for $p = \ell\neq 2$ and $\log_\ell (1 + 2^2)$ for $p = \ell = 2$. Let $A = \prod \goth{p}^{n_{\goth{p}}}$ be an ideal and let $\tilde{A} = \sum n_\goth{p} [\goth{p}]$ be the attached logarithmic divisor. Return the exponential of the $\ell$-adic logarithmic degree $\deg_F A$, which is a natural number. pari-2.11.2/src/functions/number_fields/nfisisom0000644000175000017500000000313013326135265020350 0ustar billbillFunction: nfisisom Section: number_fields C-Name: nfisisom Prototype: GG Help: nfisisom(f,g): as nfisincl but tests whether f is isomorphic to g. Doc: as \tet{nfisincl}, but tests for isomorphism. More efficient if $f$ or $g$ is a number field structure. \bprog ? f = x^6 + 30*x^5 + 495*x^4 + 1870*x^3 + 16317*x^2 - 22560*x + 59648; ? g = x^6 + 42*x^5 + 999*x^4 + 8966*x^3 + 36117*x^2 + 21768*x + 159332; ? h = x^6 + 30*x^5 + 351*x^4 + 2240*x^3 + 10311*x^2 + 35466*x + 58321; ? #nfisisom(f,g) \\ two isomorphisms %3 = 2 ? nfisisom(f,h) \\ not isomorphic %4 = 0 \\ comparative bench ? K = nfinit(f); L = nfinit(g); B = 10^3; ? for (i=1, B, nfisisom(f,g)) time = 6,124 ms. ? for (i=1, B, nfisisom(K,g)) time = 3,356 ms. ? for (i=1, B, nfisisom(f,L)) time = 3,204 ms. ? for (i=1, B, nfisisom(K,L)) time = 3,173 ms. @eprog\noindent The function is usually very fast when the fields are non-isomorphic, whenever the fields can be distinguished via a simple invariant such as degree, signature or discriminant. It may be slower when the fields share all invariants, but still faster than computing actual isomorphisms: \bprog \\ usually very fast when the answer is 'no': ? for (i=1, B, nfisisom(f,h)) time = 32 ms. \\ but not always ? u = x^6 + 12*x^5 + 6*x^4 - 377*x^3 - 714*x^2 + 5304*x + 15379 ? v = x^6 + 12*x^5 + 60*x^4 + 166*x^3 + 708*x^2 + 6600*x + 23353 ? nfisisom(u,v) %13 = 0 ? polsturm(u) == polsturm(v) %14 = 1 ? nfdisc(u) == nfdisc(v) %15 = 1 ? for(i=1,B, nfisisom(u,v)) time = 1,821 ms. ? K = nfinit(u); L = nfinit(v); ? for(i=1,B, nfisisom(K,v)) time = 232 ms. @eprog pari-2.11.2/src/functions/number_fields/idealramgroups0000644000175000017500000000326313201017466021540 0ustar billbillFunction: idealramgroups Section: number_fields C-Name: idealramgroups Prototype: GGG Help: idealramgroups(nf,gal,pr): let pr be a prime ideal in prid format, and gal the Galois group of the number field nf, return a vector g such that g[1] is the decomposition group of pr, g[2] is the inertia group, g[i] is the (i-2)th ramification group of pr, all trivial subgroups being omitted. Doc: Let $K$ be the number field defined by \var{nf} and assume that $K/\Q$ is Galois with Galois group $G$ given by \kbd{gal=galoisinit(nf)}. Let \var{pr} be the prime ideal $\goth{P}$ in prid format. This function returns a vector $g$ of subgroups of \kbd{gal} as follow: \item \kbd{g[1]} is the decomposition group of $\goth{P}$, \item \kbd{g[2]} is $G_0(\goth{P})$, the inertia group of $\goth{P}$, and for $i\geq 2$, \item \kbd{g[i]} is $G_{i-2}(\goth{P})$, the $i-2$-th \idx{ramification group} of $\goth{P}$. \noindent The length of $g$ is the number of non-trivial groups in the sequence, thus is $0$ if $e=1$ and $f=1$, and $1$ if $f>1$ and $e=1$. The following function computes the cardinality of a subgroup of $G$, as given by the components of $g$: \bprog card(H) =my(o=H[2]); prod(i=1,#o,o[i]); @eprog \bprog ? nf=nfinit(x^6+3); gal=galoisinit(nf); pr=idealprimedec(nf,3)[1]; ? g = idealramgroups(nf, gal, pr); ? apply(card,g) %3 = [6, 6, 3, 3, 3] \\ cardinalities of the G_i @eprog \bprog ? nf=nfinit(x^6+108); gal=galoisinit(nf); pr=idealprimedec(nf,2)[1]; ? iso=idealramgroups(nf,gal,pr)[2] %5 = [[Vecsmall([2, 3, 1, 5, 6, 4])], Vecsmall([3])] ? nfdisc(galoisfixedfield(gal,iso,1)) %6 = -3 @eprog\noindent The field fixed by the inertia group of $2$ is not ramified at $2$. pari-2.11.2/src/functions/number_fields/galoispermtopol0000644000175000017500000000154113201017466021737 0ustar billbillFunction: galoispermtopol Section: number_fields C-Name: galoispermtopol Prototype: GG Help: galoispermtopol(gal,perm): gal being a Galois group as output by galoisinit and perm a element of gal.group, return the polynomial defining the corresponding Galois automorphism. Doc: \var{gal} being a Galois group as output by \kbd{galoisinit} and \var{perm} a element of $\var{gal}.group$, return the polynomial defining the Galois automorphism, as output by \kbd{nfgaloisconj}, attached to the permutation \var{perm} of the roots $\var{gal}.roots$. \var{perm} can also be a vector or matrix, in this case, \kbd{galoispermtopol} is applied to all components recursively. \noindent Note that \bprog G = galoisinit(pol); galoispermtopol(G, G[6])~ @eprog\noindent is equivalent to \kbd{nfgaloisconj(pol)}, if degree of \var{pol} is greater or equal to $2$. pari-2.11.2/src/functions/number_fields/nfalgtobasis0000644000175000017500000000110413201017466021166 0ustar billbillFunction: nfalgtobasis Section: number_fields C-Name: algtobasis Prototype: GG Help: nfalgtobasis(nf,x): transforms the algebraic number x into a column vector on the integral basis nf.zk. Doc: Given an algebraic number $x$ in the number field $\var{nf}$, transforms it to a column vector on the integral basis \kbd{\var{nf}.zk}. \bprog ? nf = nfinit(y^2 + 4); ? nf.zk %2 = [1, 1/2*y] ? nfalgtobasis(nf, [1,1]~) %3 = [1, 1]~ ? nfalgtobasis(nf, y) %4 = [0, 2]~ ? nfalgtobasis(nf, Mod(y, y^2+4)) %5 = [0, 2]~ @eprog This is the inverse function of \kbd{nfbasistoalg}. pari-2.11.2/src/functions/number_fields/idealtwoelt0000644000175000017500000000374513326135265021052 0ustar billbillFunction: idealtwoelt Section: number_fields C-Name: idealtwoelt0 Prototype: GGDG Help: idealtwoelt(nf,x,{a}): two-element representation of an ideal x in the number field nf. If (optional) a is non-zero, first element will be equal to a. Doc: computes a two-element representation of the ideal $x$ in the number field $\var{nf}$, combining a random search and an approximation theorem; $x$ is an ideal in any form (possibly an extended ideal, whose principal part is ignored) \item When called as \kbd{idealtwoelt(nf,x)}, the result is a row vector $[a,\alpha]$ with two components such that $x=a\Z_K+\alpha\Z_K$ and $a$ is chosen to be the positive generator of $x\cap\Z$, unless $x$ was given as a principal ideal in which case we may choose $a = 0$. The algorithm uses a fast lazy factorization of $x\cap \Z$ and runs in randomized polynomial time. \bprog ? K = nfinit(t^5-23); ? x = idealhnf(K, t^2*(t+1), t^3*(t+1)) %2 = \\ some random ideal of norm 552*23 [552 23 23 529 23] [ 0 23 0 0 0] [ 0 0 1 0 0] [ 0 0 0 1 0] [ 0 0 0 0 1] ? [a,alpha] = idealtwoelt(K, x) %3 = [552, [23, 0, 1, 0, 0]~] ? nfbasistoalg(K, alpha) %4 = Mod(t^2 + 23, t^5 - 23) @eprog \item When called as \kbd{idealtwoelt(nf,x,a)} with an explicit non-zero $a$ supplied as third argument, the function assumes that $a \in x$ and returns $\alpha\in x$ such that $x = a\Z_K + \alpha\Z_K$. Note that we must factor $a$ in this case, and the algorithm is generally slower than the default variant and gives larger generators: \bprog ? alpha2 = idealtwoelt(K, x, 552) %5 = [-161, -161, -183, -207, 0]~ ? idealhnf(K, 552, alpha2) == x %6 = 1 @eprog\noindent Note that, in both cases, the return value is \emph{not} recognized as an ideal by GP functions; one must use \kbd{idealhnf} as above to recover a valid ideal structure from the two-element representation. Variant: Also available are \fun{GEN}{idealtwoelt}{GEN nf, GEN x} and \fun{GEN}{idealtwoelt2}{GEN nf, GEN x, GEN a}. pari-2.11.2/src/functions/number_fields/rnfidealreltoabs0000644000175000017500000000315713201017466022044 0ustar billbillFunction: rnfidealreltoabs Section: number_fields C-Name: rnfidealreltoabs0 Prototype: GGD0,L, Help: rnfidealreltoabs(rnf,x,{flag=0}): transforms the ideal x from relative to absolute representation. As a vector of t_POLMODs if flag = 0 and as an ideal in HNF in the absolute field if flag = 1. Doc: Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a relative ideal, given as a $\Z_K$-module by a pseudo matrix $[A,I]$. This function returns the ideal $x$ as an absolute ideal of $L/\Q$. If $\fl = 0$, the result is given by a vector of \typ{POLMOD}s modulo \kbd{rnf.pol} forming a $\Z$-basis; if $\fl = 1$, it is given in HNF in terms of the fixed $\Z$-basis for $\Z_L$, see \secref{se:rnfinit}. \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? P = idealprimedec(K,2)[1]; ? P = rnfidealup(rnf, P) %3 = [2, x^2 + 1, 2*x, x^3 + x] ? Prel = rnfidealhnf(rnf, P) %4 = [[1, 0; 0, 1], [[2, 1; 0, 1], [2, 1; 0, 1]]] ? rnfidealreltoabs(rnf,Prel) %5 = [2, x^2 + 1, 2*x, x^3 + x] ? rnfidealreltoabs(rnf,Prel,1) %6 = [2 1 0 0] [0 1 0 0] [0 0 2 1] [0 0 0 1] @eprog The reason why we do not return by default ($\fl = 0$) the customary HNF in terms of a fixed $\Z$-basis for $\Z_L$ is precisely because a \var{rnf} does not contain such a basis by default. Completing the structure so that it contains a \var{nf} structure for $L$ is polynomial time but costly when the absolute degree is large, thus it is not done by default. Note that setting $\fl = 1$ will complete the \var{rnf}. Variant: Also available is \fun{GEN}{rnfidealreltoabs}{GEN rnf, GEN x} ($\fl = 0$). pari-2.11.2/src/functions/number_fields/bnrstark0000644000175000017500000000430013326135265020347 0ustar billbillFunction: bnrstark Section: number_fields C-Name: bnrstark Prototype: GDGp Help: bnrstark(bnr,{subgroup}): bnr being as output by bnrinit, finds a relative equation for the class field corresponding to the module in bnr and the given congruence subgroup (the trivial subgroup if omitted) using Stark's units. The ground field and the class field must be totally real. Doc: \var{bnr} being as output by \kbd{bnrinit}, finds a relative equation for the class field corresponding to the modulus in \var{bnr} and the given congruence subgroup (as usual, omit $\var{subgroup}$ if you want the whole ray class group). The main variable of \var{bnr} must not be $x$, and the ground field and the class field must be totally real. When the base field is $\Q$, the vastly simpler \tet{galoissubcyclo} is used instead. Here is an example: \bprog bnf = bnfinit(y^2 - 3); bnr = bnrinit(bnf, 5); bnrstark(bnr) @eprog\noindent returns the ray class field of $\Q(\sqrt{3})$ modulo $5$. Usually, one wants to apply to the result one of \bprog rnfpolredabs(bnf, pol, 16) \\@com compute a reduced relative polynomial rnfpolredabs(bnf, pol, 16 + 2) \\@com compute a reduced absolute polynomial @eprog The routine uses \idx{Stark units} and needs to find a suitable auxiliary conductor, which may not exist when the class field is not cyclic over the base. In this case \kbd{bnrstark} is allowed to return a vector of polynomials defining \emph{independent} relative extensions, whose compositum is the requested class field. It was decided that it was more useful to keep the extra information thus made available, hence the user has to take the compositum herself. Even if it exists, the auxiliary conductor may be so large that later computations become unfeasible. (And of course, Stark's conjecture may simply be wrong.) In case of difficulties, try \tet{rnfkummer}: \bprog ? bnr = bnrinit(bnfinit(y^8-12*y^6+36*y^4-36*y^2+9,1), 2); ? bnrstark(bnr) *** at top-level: bnrstark(bnr) *** ^------------- *** bnrstark: need 3919350809720744 coefficients in initzeta. *** Computation impossible. ? lift( rnfkummer(bnr) ) time = 24 ms. %2 = x^2 + (1/3*y^6 - 11/3*y^4 + 8*y^2 - 5) @eprog pari-2.11.2/src/functions/number_fields/nfrootsof10000644000175000017500000000306311636712103020620 0ustar billbillFunction: nfrootsof1 Section: number_fields C-Name: rootsof1 Prototype: G Help: nfrootsof1(nf): number of roots of unity and primitive root of unity in the number field nf. Doc: Returns a two-component vector $[w,z]$ where $w$ is the number of roots of unity in the number field \var{nf}, and $z$ is a primitive $w$-th root of unity. \bprog ? K = nfinit(polcyclo(11)); ? nfrootsof1(K) %2 = [22, [0, 0, 0, 0, 0, -1, 0, 0, 0, 0]~] ? z = nfbasistoalg(K, %[2]) \\ in algebraic form %3 = Mod(-x^5, x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) ? [lift(z^11), lift(z^2)] \\ proves that the order of z is 22 %4 = [-1, -x^9 - x^8 - x^7 - x^6 - x^5 - x^4 - x^3 - x^2 - x - 1] @eprog This function guesses the number $w$ as the gcd of the $\#k(v)^*$ for unramified $v$ above odd primes, then computes the roots in \var{nf} of the $w$-th cyclotomic polynomial: the algorithm is polynomial time with respect to the field degree and the bitsize of the multiplication table in \var{nf} (both of them polynomially bounded in terms of the size of the discriminant). Fields of degree up to $100$ or so should require less than one minute. Variant: Also available is \fun{GEN}{rootsof1_kannan}{GEN nf}, that computes all algebraic integers of $T_2$ norm equal to the field degree (all roots of $1$, by Kronecker's theorem). This is in general a little faster than the default when there \emph{are} roots of $1$ in the field (say twice faster), but can be much slower (say, \emph{days} slower), since the algorithm is a priori exponential in the field degree. pari-2.11.2/src/functions/number_fields/bnrL10000644000175000017500000000546613326135265017515 0ustar billbillFunction: bnrL1 Section: number_fields C-Name: bnrL1 Prototype: GDGD0,L,p Help: bnrL1(bnr, {H}, {flag=0}): bnr being output by bnrinit and H being a square matrix defining a congruence subgroup of bnr (the trivial subgroup if omitted), for each character of bnr trivial on this subgroup, compute L(1, chi) (or equivalently the first non-zero term c(chi) of the expansion at s = 0). The binary digits of flag mean 1: if 0 then compute the term c(chi) and return [r(chi), c(chi)] where r(chi) is the order of L(s, chi) at s = 0, or if 1 then compute the value at s = 1 (and in this case, only for non-trivial characters), 2: if 0 then compute the value of the primitive L-function attached to chi, if 1 then compute the value of the L-function L_S(s, chi) where S is the set of places dividing the modulus of bnr (and the infinite places), 3: return also the characters. Doc: let \var{bnr} be the number field data output by \kbd{bnrinit} and \var{H} be a square matrix defining a congruence subgroup of the ray class group corresponding to \var{bnr} (the trivial congruence subgroup if omitted). This function returns, for each \idx{character} $\chi$ of the ray class group which is trivial on $H$, the value at $s = 1$ (or $s = 0$) of the abelian $L$-function attached to $\chi$. For the value at $s = 0$, the function returns in fact for each $\chi$ a vector $[r_\chi, c_\chi]$ where $$L(s, \chi) = c \cdot s^r + O(s^{r + 1})$$ \noindent near $0$. The argument \fl\ is optional, its binary digits mean 1: compute at $s = 0$ if unset or $s = 1$ if set, 2: compute the primitive $L$-function attached to $\chi$ if unset or the $L$-function with Euler factors at prime ideals dividing the modulus of \var{bnr} removed if set (that is $L_S(s, \chi)$, where $S$ is the set of infinite places of the number field together with the finite prime ideals dividing the modulus of \var{bnr}), 3: return also the character if set. \bprog K = bnfinit(x^2-229); bnr = bnrinit(K,1); bnrL1(bnr) @eprog\noindent returns the order and the first non-zero term of $L(s, \chi)$ at $s = 0$ where $\chi$ runs through the characters of the class group of $K = \Q(\sqrt{229})$. Then \bprog bnr2 = bnrinit(K,2); bnrL1(bnr2,,2) @eprog\noindent returns the order and the first non-zero terms of $L_S(s, \chi)$ at $s = 0$ where $\chi$ runs through the characters of the class group of $K$ and $S$ is the set of infinite places of $K$ together with the finite prime $2$. Note that the ray class group modulo $2$ is in fact the class group, so \kbd{bnrL1(bnr2,0)} returns the same answer as \kbd{bnrL1(bnr,0)}. This function will fail with the message \bprog *** bnrL1: overflow in zeta_get_N0 [need too many primes]. @eprog\noindent if the approximate functional equation requires us to sum too many terms (if the discriminant of $K$ is too large). pari-2.11.2/src/functions/number_fields/nfdisc0000644000175000017500000000357213457577775020026 0ustar billbillFunction: nfdisc Section: number_fields C-Name: nfdisc Prototype: G Help: nfdisc(T): discriminant of the number field defined by the polynomial T. An argument [T,listP] is possible, where listP is a list of primes or a prime bound. Doc: \idx{field discriminant} of the number field defined by the integral, preferably monic, irreducible polynomial $T(X)$. Returns the discriminant of the number field $\Q[X]/(T)$, using the Round $4$ algorithm. \misctitle{Local discriminants, valuations at certain primes} As in \kbd{nfbasis}, the argument $T$ can be replaced by $[T,\var{listP}]$, where \kbd{listP} is as in \kbd{nfbasis}: a vector of pairwise coprime integers (usually distinct primes), a factorization matrix, or a single integer. In that case, the function returns the discriminant of an order whose basis is given by \kbd{nfbasis(T,listP)}, which need not be the maximal order, and whose valuation at a prime entry in \kbd{listP} is the same as the valuation of the field discriminant. In particular, if \kbd{listP} is $[p]$ for a prime $p$, we can return the $p$-adic discriminant of the maximal order of $\Z_p[X]/(T)$, as a power of $p$, as follows: \bprog ? padicdisc(T,p) = p^valuation(nfdisc([T,[p]]), p); ? nfdisc(x^2 + 6) %2 = -24 ? padicdisc(x^2 + 6, 2) %3 = 8 ? padicdisc(x^2 + 6, 3) %4 = 3 @eprog\noindent The following function computes the discriminant of the maximal order under the assumption that $P$ is a vector of prime numbers containing (at least) all prime divisors of the field discriminant: \bprog globaldisc(T, P) = { my (D = nfdisc([T, P])); sign(D) * factorback(P, [valuation(D,p) | p <-P]); } ? globaldisc(x^2 + 6, [2, 3, 5]) %1 = -24 @eprog \synt{nfdisc}{GEN T} (\kbd{listP = NULL}). Also available is \fun{GEN}{nfbasis}{GEN T, GEN *d, GEN listP = NULL}, which returns the order basis, and where \kbd{*d} receives the order discriminant. pari-2.11.2/src/functions/number_fields/bnfisnorm0000644000175000017500000000276013201017466020520 0ustar billbillFunction: bnfisnorm Section: number_fields C-Name: bnfisnorm Prototype: GGD1,L, Help: bnfisnorm(bnf,x,{flag=1}): tries to tell whether x (in Q) is the norm of some fractional y (in bnf). Returns a vector [a,b] where x=Norm(a)*b. Looks for a solution which is a S-unit, with S a certain list of primes (in bnf) containing (among others) all primes dividing x. If bnf is known to be Galois, set flag=0 (in this case, x is a norm iff b=1). If flag is non zero the program adds to S all the primes: dividing flag if flag<0, or less than flag if flag>0. The answer is guaranteed (i.e x norm iff b=1) under GRH, if S contains all primes less than 12.log(disc(Bnf))^2, where Bnf is the Galois closure of bnf. Doc: tries to tell whether the rational number $x$ is the norm of some element y in $\var{bnf}$. Returns a vector $[a,b]$ where $x=Norm(a)*b$. Looks for a solution which is an $S$-unit, with $S$ a certain set of prime ideals containing (among others) all primes dividing $x$. If $\var{bnf}$ is known to be \idx{Galois}, set $\fl=0$ (in this case, $x$ is a norm iff $b=1$). If $\fl$ is non zero the program adds to $S$ the following prime ideals, depending on the sign of $\fl$. If $\fl>0$, the ideals of norm less than $\fl$. And if $\fl<0$ the ideals dividing $\fl$. Assuming \idx{GRH}, the answer is guaranteed (i.e.~$x$ is a norm iff $b=1$), if $S$ contains all primes less than $12\log(\disc(\var{Bnf}))^2$, where $\var{Bnf}$ is the Galois closure of $\var{bnf}$. See also \tet{bnfisintnorm}. pari-2.11.2/src/functions/number_fields/nfeltdivmodpr0000644000175000017500000000105413201017466021373 0ustar billbillFunction: nfeltdivmodpr Section: number_fields C-Name: nfdivmodpr Prototype: GGGG Obsolete: 2016-08-09 Help: nfeltdivmodpr(nf,x,y,pr): this function is obsolete, use nfmodpr. Doc: this function is obsolete, use \kbd{nfmodpr}. Given two elements $x$ and $y$ in \var{nf} and \var{pr} a prime ideal in \kbd{modpr} format (see \tet{nfmodprinit}), computes their quotient $x / y$ modulo the prime ideal \var{pr}. Variant: This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. pari-2.11.2/src/functions/number_fields/rnflllgram0000644000175000017500000000121011636712103020650 0ustar billbillFunction: rnflllgram Section: number_fields C-Name: rnflllgram Prototype: GGGp Help: rnflllgram(nf,pol,order): given a pol with coefficients in nf and an order as output by rnfpseudobasis or similar, gives [[neworder],U], where neworder is a reduced order and U is the unimodular transformation matrix. Doc: given a polynomial \var{pol} with coefficients in \var{nf} defining a relative extension $L$ and a suborder \var{order} of $L$ (of maximal rank), as output by \kbd{rnfpseudobasis}$(\var{nf},\var{pol})$ or similar, gives $[[\var{neworder}],U]$, where \var{neworder} is a reduced order and $U$ is the unimodular transformation matrix. pari-2.11.2/src/functions/number_fields/galoisconjclasses0000644000175000017500000000210013326135265022223 0ustar billbillFunction: galoisconjclasses Section: number_fields C-Name: galoisconjclasses Prototype: G Help: galoisconjclasses(gal): gal being output by galoisinit, return the list of conjugacy classes. Doc: \var{gal} being output by \kbd{galoisinit}, return the list of conjugacy classes of the underlying group. The ordering of the classes is consistent with \kbd{galoischartable} and the trivial class comes first. \bprog ? G = galoisinit(x^6+108); ? galoisidentify(G) %2 = [6, 1] \\ S_3 ? S = galoisconjclasses(G) %3 = [[Vecsmall([1,2,3,4,5,6])], [Vecsmall([3,1,2,6,4,5]),Vecsmall([2,3,1,5,6,4])], [Vecsmall([6,5,4,3,2,1]),Vecsmall([5,4,6,2,1,3]), Vecsmall([4,6,5,1,3,2])]] ? [[permorder(c[1]),#c] | c <- S ] %4 = [[1,1], [3,2], [2,3]] @eprog\noindent This command also accepts subgroups returned by \kbd{galoissubgroups}: \bprog ? subs = galoissubgroups(G); H = subs[5]; ? galoisidentify(H) %2 = [2, 1] \\ Z/2 ? S = galoisconjclasses(subgroups_of_G[5]); ? [[permorder(c[1]),#c] | c <- S ] %4 = [[1,1], [2,1]] @eprog\noindent pari-2.11.2/src/functions/number_fields/rnfeltabstorel0000644000175000017500000000233613201017466021550 0ustar billbillFunction: rnfeltabstorel Section: number_fields C-Name: rnfeltabstorel Prototype: GG Help: rnfeltabstorel(rnf,x): transforms the element x from absolute to relative representation. Doc: Let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an element of $L$ expressed as a polynomial modulo the absolute equation \kbd{\var{rnf}.pol}, or in terms of the absolute $\Z$-basis for $\Z_L$ if \var{rnf} contains one (as in \kbd{rnfinit(nf,pol,1)}, or after a call to \kbd{nfinit(rnf)}). Computes $x$ as an element of the relative extension $L/K$ as a polmod with polmod coefficients. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.polabs %2 = x^4 + 1 ? rnfeltabstorel(L, Mod(x, L.polabs)) %3 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltabstorel(L, 1/3) %4 = 1/3 ? rnfeltabstorel(L, Mod(x, x^2-y)) %5 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltabstorel(L, [0,0,0,1]~) \\ Z_L not initialized yet *** at top-level: rnfeltabstorel(L,[0, *** ^-------------------- *** rnfeltabstorel: incorrect type in rnfeltabstorel, apply nfinit(rnf). ? nfinit(L); \\ initialize now ? rnfeltabstorel(L, [0,0,0,1]~) %6 = Mod(Mod(y, y^2 + 1)*x, x^2 + Mod(-y, y^2 + 1)) @eprog pari-2.11.2/src/functions/number_fields/rnfidealup0000644000175000017500000000261513201017466020653 0ustar billbillFunction: rnfidealup Section: number_fields C-Name: rnfidealup0 Prototype: GGD0,L, Help: rnfidealup(rnf,x,{flag=0}): lifts the ideal x (of the base field) to the relative field. As a vector of t_POLMODs if flag = 0 and as an ideal in HNF in the absolute field if flag = 1. Doc: let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an ideal of $K$. This function returns the ideal $x\Z_L$ as an absolute ideal of $L/\Q$, in the form of a $\Z$-basis. If $\fl = 0$, the result is given by a vector of polynomials (modulo \kbd{rnf.pol}); if $\fl = 1$, it is given in HNF in terms of the fixed $\Z$-basis for $\Z_L$, see \secref{se:rnfinit}. \bprog ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? P = idealprimedec(K,2)[1]; ? rnfidealup(rnf, P) %3 = [2, x^2 + 1, 2*x, x^3 + x] ? rnfidealup(rnf, P,1) %4 = [2 1 0 0] [0 1 0 0] [0 0 2 1] [0 0 0 1] @eprog The reason why we do not return by default ($\fl = 0$) the customary HNF in terms of a fixed $\Z$-basis for $\Z_L$ is precisely because a \var{rnf} does not contain such a basis by default. Completing the structure so that it contains a \var{nf} structure for $L$ is polynomial time but costly when the absolute degree is large, thus it is not done by default. Note that setting $\fl = 1$ will complete the \var{rnf}. Variant: Also available is \fun{GEN}{rnfidealup}{GEN rnf, GEN x} ($\fl = 0$). pari-2.11.2/src/functions/number_fields/nfcompositum0000644000175000017500000000644713201017466021254 0ustar billbillFunction: nfcompositum Section: number_fields C-Name: nfcompositum Prototype: GGGD0,L, Help: nfcompositum(nf,P,Q,{flag=0}): vector of all possible compositums of the number fields defined by the polynomials P and Q; flag is optional, whose binary digits mean 1: output for each compositum, not only the compositum polynomial pol, but a vector [R,a,b,k] where a (resp. b) is a root of P (resp. Q) expressed as a polynomial modulo R, and a small integer k such that al2+k*al1 is the chosen root of R; 2: assume that the number fields defined by P and Q are linearly disjoint. Doc: Let \var{nf} be a number field structure attached to the field $K$ and let \sidx{compositum} $P$ and $Q$ be squarefree polynomials in $K[X]$ in the same variable. Outputs the simple factors of the \'etale $K$-algebra $A = K[X, Y] / (P(X), Q(Y))$. The factors are given by a list of polynomials $R$ in $K[X]$, attached to the number field $K[X]/ (R)$, and sorted by increasing degree (with respect to lexicographic ordering for factors of equal degrees). Returns an error if one of the polynomials is not squarefree. Note that it is more efficient to reduce to the case where $P$ and $Q$ are irreducible first. The routine will not perform this for you, since it may be expensive, and the inputs are irreducible in most applications anyway. In this case, there will be a single factor $R$ if and only if the number fields defined by $P$ and $Q$ are linearly disjoint (their intersection is $K$). The binary digits of $\fl$ mean 1: outputs a vector of 4-component vectors $[R,a,b,k]$, where $R$ ranges through the list of all possible compositums as above, and $a$ (resp. $b$) expresses the root of $P$ (resp. $Q$) as an element of $K[X]/(R)$. Finally, $k$ is a small integer such that $b + ka = X$ modulo $R$. 2: assume that $P$ and $Q$ define number fields that are linearly disjoint: both polynomials are irreducible and the corresponding number fields have no common subfield besides $K$. This allows to save a costly factorization over $K$. In this case return the single simple factor instead of a vector with one element. A compositum is often defined by a complicated polynomial, which it is advisable to reduce before further work. Here is an example involving the field $K(\zeta_5, 5^{1/10})$, $K=\Q(\sqrt{5})$: \bprog ? K = nfinit(y^2-5); ? L = nfcompositum(K, x^5 - y, polcyclo(5), 1); \\@com list of $[R,a,b,k]$ ? [R, a] = L[1]; \\@com pick the single factor, extract $R,a$ (ignore $b,k$) ? lift(R) \\@com defines the compositum %4 = x^10 + (-5/2*y + 5/2)*x^9 + (-5*y + 20)*x^8 + (-20*y + 30)*x^7 + \ (-45/2*y + 145/2)*x^6 + (-71/2*y + 121/2)*x^5 + (-20*y + 60)*x^4 + \ (-25*y + 5)*x^3 + 45*x^2 + (-5*y + 15)*x + (-2*y + 6) ? a^5 - y \\@com a fifth root of $y$ %5 = 0 ? [T, X] = rnfpolredbest(K, R, 1); ? lift(T) \\@com simpler defining polynomial for $K[x]/(R)$ %7 = x^10 + (-11/2*y + 25/2) ? liftall(X) \\ @com root of $R$ in $K[x]/(T(x))$ %8 = (3/4*y + 7/4)*x^7 + (-1/2*y - 1)*x^5 + 1/2*x^2 + (1/4*y - 1/4) ? a = subst(a.pol, 'x, X); \\@com \kbd{a} in the new coordinates ? liftall(a) %10 = (-3/4*y - 7/4)*x^7 - 1/2*x^2 ? a^5 - y %11 = 0 @eprog The main variables of $P$ and $Q$ must be the same and have higher priority than that of \var{nf} (see~\kbd{varhigher} and~\kbd{varlower}). pari-2.11.2/src/functions/number_fields/rnfeltdown0000644000175000017500000000301113201017466020673 0ustar billbillFunction: rnfeltdown Section: number_fields C-Name: rnfeltdown0 Prototype: GGD0,L, Help: rnfeltdown(rnf,x,{flag=0}): expresses x on the base field if possible; returns an error otherwise. Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of $L$ expressed as a polynomial or polmod with polmod coefficients (or as a \typ{COL} on \kbd{nfinit(rnf).zk}), computes $x$ as an element of $K$ as a \typ{POLMOD} if $\fl = 0$ and as a \typ{COL} otherwise. If $x$ is not in $K$, a domain error occurs. \bprog ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltdown(L, Mod(x^2, L.pol)) %3 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(x^2, L.pol), 1) %4 = [0, 1]~ ? rnfeltdown(L, Mod(y, x^2-y)) %5 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(y,K.pol)) %6 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(x, L.pol)) *** at top-level: rnfeltdown(L,Mod(x,x *** ^-------------------- *** rnfeltdown: domain error in rnfeltdown: element not in the base field ? rnfeltdown(L, Mod(y, x^2-y), 1) \\ as a t_COL %7 = [0, 1]~ ? rnfeltdown(L, [0,1,0,0]~) \\ not allowed without absolute nf struct *** rnfeltdown: incorrect type in rnfeltdown (t_COL). ? nfinit(L); \\ add absolute nf structure to L ? rnfeltdown(L, [0,1,0,0]~) \\ now OK %8 = Mod(y, y^2 + 1) @eprog\noindent If we had started with \kbd{L = rnfinit(K, x\pow2-y, 1)}, then the final would have worked directly. Variant: Also available is \fun{GEN}{rnfeltdown}{GEN rnf, GEN x} ($\fl = 0$). pari-2.11.2/src/functions/number_fields/idealfactorback0000644000175000017500000000344713326135265021632 0ustar billbillFunction: idealfactorback Section: number_fields C-Name: idealfactorback Prototype: GGDGD0,L, Help: idealfactorback(nf,f,{e},{flag = 0}): given a factorization f, gives the ideal product back. If e is present, f has to be a vector of the same length, and we return the product of the f[i]^e[i]. If flag is non-zero, perform idealred along the way. Doc: gives back the ideal corresponding to a factorization. The integer $1$ corresponds to the empty factorization. If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being integral), and the corresponding factorization is the product of the $f[i]^{e[i]}$. If not, and $f$ is vector, it is understood as in the preceding case with $e$ a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a regular factorization, as produced by \kbd{idealfactor}. \bprog ? nf = nfinit(y^2+1); idealfactor(nf, 4 + 2*y) %1 = [[2, [1, 1]~, 2, 1, [1, 1]~] 2] [[5, [2, 1]~, 1, 1, [-2, 1]~] 1] ? idealfactorback(nf, %) %2 = [10 4] [0 2] ? f = %1[,1]; e = %1[,2]; idealfactorback(nf, f, e) %3 = [10 4] [0 2] ? % == idealhnf(nf, 4 + 2*y) %4 = 1 @eprog If \kbd{flag} is non-zero, perform ideal reductions (\tet{idealred}) along the way. This is most useful if the ideals involved are all \emph{extended} ideals (for instance with trivial principal part), so that the principal parts extracted by \kbd{idealred} are not lost. Here is an example: \bprog ? f = vector(#f, i, [f[i], [;]]); \\ transform to extended ideals ? idealfactorback(nf, f, e, 1) %6 = [[1, 0; 0, 1], [2, 1; [2, 1]~, 1]] ? nffactorback(nf, %[2]) %7 = [4, 2]~ @eprog The extended ideal returned in \kbd{\%6} is the trivial ideal $1$, extended with a principal generator given in factored form. We use \tet{nffactorback} to recover it in standard form. pari-2.11.2/src/functions/number_fields/nfmodpr0000644000175000017500000000137113326135265020173 0ustar billbillFunction: nfmodpr Section: number_fields C-Name: nfmodpr Prototype: GGG Help: nfmodpr(nf,x,pr): map x to the residue field mod pr. Doc: map $x$ to a \typ{FFELT} in the residue field modulo \var{pr}. The argument \var{pr} is either a maximal ideal in \kbd{idealprimedec} format or, preferably, a \var{modpr} structure from \tet{nfmodprinit}. The function \tet{nfmodprlift} allows to lift back to $\Z_K$. Note that the function applies to number field elements and not to vector / matrices / polynomials of such. Use \kbd{apply} to convert recursive structures. \bprog ? K = nfinit(y^3-250); ? P = idealprimedec(K, 5)[2]; ? modP = nfmodprinit(K,P); ? K.zk %4 = [1, 1/5*y, 1/25*y^2] ? apply(t->nfmodpr(K,t,modP), K.zk) %5 = [1, y, 2*y + 1] @eprog pari-2.11.2/src/functions/number_fields/rnfnormgroup0000644000175000017500000000233713201017466021261 0ustar billbillFunction: rnfnormgroup Section: number_fields C-Name: rnfnormgroup Prototype: GG Help: rnfnormgroup(bnr,pol): norm group (or Artin or Takagi group) corresponding to the Abelian extension of bnr.bnf defined by pol, where the module corresponding to bnr is assumed to be a multiple of the conductor. The result is the HNF defining the norm group on the generators in bnr.gen. Doc: \var{bnr} being a big ray class field as output by \kbd{bnrinit} and \var{pol} a relative polynomial defining an \idx{Abelian extension}, computes the norm group (alias Artin or Takagi group) corresponding to the Abelian extension of $\var{bnf}=$\kbd{bnr.bnf} defined by \var{pol}, where the module corresponding to \var{bnr} is assumed to be a multiple of the conductor (i.e.~\var{pol} defines a subextension of bnr). The result is the HNF defining the norm group on the given generators of \kbd{bnr.gen}. Note that neither the fact that \var{pol} defines an Abelian extension nor the fact that the module is a multiple of the conductor is checked. The result is undefined if the assumption is not correct, but the function will return the empty matrix \kbd{[;]} if it detects a problem; it may also not detect the problem and return a wrong result. pari-2.11.2/src/functions/number_fields/bnrdisclist0000644000175000017500000000504013326135265021043 0ustar billbillFunction: bnrdisclist Section: number_fields C-Name: bnrdisclist0 Prototype: GGDG Help: bnrdisclist(bnf,bound,{arch}): list of discriminants of ray class fields of all conductors up to norm bound. The ramified Archimedean places are given by arch; all possible values are taken if arch is omitted. Supports the alternative syntax bnrdisclist(bnf,list), where list is as output by ideallist or ideallistarch (with units). Doc: $\var{bnf}$ being as output by \kbd{bnfinit} (with units), computes a list of discriminants of Abelian extensions of the number field by increasing modulus norm up to bound \var{bound}. The ramified Archimedean places are given by \var{arch}; all possible values are taken if \var{arch} is omitted. The alternative syntax $\kbd{bnrdisclist}(\var{bnf},\var{list})$ is supported, where \var{list} is as output by \kbd{ideallist} or \kbd{ideallistarch} (with units), in which case \var{arch} is disregarded. The output $v$ is a vector, where $v[k]$ is itself a vector $w$, whose length is the number of ideals of norm $k$. \item We consider first the case where \var{arch} was specified. Each component of $w$ corresponds to an ideal $m$ of norm $k$, and gives invariants attached to the ray class field $L$ of $\var{bnf}$ of conductor $[m, \var{arch}]$. Namely, each contains a vector $[m,d,r,D]$ with the following meaning: $m$ is the prime ideal factorization of the modulus, $d = [L:\Q]$ is the absolute degree of $L$, $r$ is the number of real places of $L$, and $D$ is the factorization of its absolute discriminant. We set $d = r = D = 0$ if $m$ is not the finite part of a conductor. \item If \var{arch} was omitted, all $t = 2^{r_1}$ possible values are taken and a component of $w$ has the form $[m, [[d_1,r_1,D_1], \dots, [d_t,r_t,D_t]]]$, where $m$ is the finite part of the conductor as above, and $[d_i,r_i,D_i]$ are the invariants of the ray class field of conductor $[m,v_i]$, where $v_i$ is the $i$-th Archimedean component, ordered by inverse lexicographic order; so $v_1 = [0,\dots,0]$, $v_2 = [1,0\dots,0]$, etc. Again, we set $d_i = r_i = D_i = 0$ if $[m,v_i]$ is not a conductor. Finally, each prime ideal $pr = [p,\alpha,e,f,\beta]$ in the prime factorization $m$ is coded as the integer $p\cdot n^2+(f-1)\cdot n+(j-1)$, where $n$ is the degree of the base field and $j$ is such that \kbd{pr = idealprimedec(\var{nf},p)[j]}. \noindent $m$ can be decoded using \tet{bnfdecodemodule}. Note that to compute such data for a single field, either \tet{bnrclassno} or \tet{bnrdisc} are (much) more efficient. pari-2.11.2/src/functions/number_fields/galoisinit0000644000175000017500000000743713447371554020710 0ustar billbillFunction: galoisinit Section: number_fields C-Name: galoisinit Prototype: GDG Help: galoisinit(pol,{den}): pol being a polynomial or a number field as output by nfinit defining a Galois extension of Q, compute the Galois group and all necessary information for computing fixed fields. den is optional and has the same meaning as in nfgaloisconj(,4)(see manual). Description: (gen, ?int):gal galoisinit($1, $2) Doc: computes the Galois group and all necessary information for computing the fixed fields of the Galois extension $K/\Q$ where $K$ is the number field defined by $\var{pol}$ (monic irreducible polynomial in $\Z[X]$ or a number field as output by \tet{nfinit}). The extension $K/\Q$ must be Galois with Galois group ``weakly'' super-solvable, see below; returns 0 otherwise. Hence this permits to quickly check whether a polynomial of order strictly less than $36$ is Galois or not. The algorithm used is an improved version of the paper ``An efficient algorithm for the computation of Galois automorphisms'', Bill Allombert, Math.~Comp, vol.~73, 245, 2001, pp.~359--375. A group $G$ is said to be ``weakly'' super-solvable if there exists a normal series $\{1\} = H_0 \triangleleft H_1 \triangleleft \cdots \triangleleft H_{n-1} \triangleleft H_n$ such that each $H_i$ is normal in $G$ and for $i=v_p(x) for all prime ideals p dividing x, and v_p(b)>=0 for all other p. If y is omitted, return a data structure which can be used in place of x in later calls. Doc: $x$ being a prime ideal factorization (i.e.~a 2-columns matrix whose first column contains prime ideals and the second column contains integral exponents), $y$ a vector of elements in $\var{nf}$ indexed by the ideals in $x$, computes an element $b$ such that $v_{\goth{p}}(b - y_{\goth{p}}) \geq v_{\goth{p}}(x)$ for all prime ideals in $x$ and $v_{\goth{p}}(b)\geq 0$ for all other $\goth{p}$. \bprog ? K = nfinit(t^2-2); ? x = idealfactor(K, 2^2*3) %2 = [[2, [0, 1]~, 2, 1, [0, 2; 1, 0]] 4] [ [3, [3, 0]~, 1, 2, 1] 1] ? y = [t,1]; ? idealchinese(K, x, y) %4 = [4, -3]~ @eprog The argument $x$ may also be of the form $[x, s]$ where the first component is as above and $s$ is a vector of signs, with $r_1$ components $s_i$ in $\{-1,0,1\}$: if $\sigma_i$ denotes the $i$-th real embedding of the number field, the element $b$ returned satisfies further $\kbd{sign}(\sigma_i(b)) = s_i$ for all $i$ such that $s_i = \pm1$. In other words, the sign is fixed to $s_i$ at the $i$-th embedding whenever $s_i$ is non-zero. \bprog ? idealchinese(K, [x, [1,1]], y) %5 = [16, -3]~ ? idealchinese(K, [x, [-1,-1]], y) %6 = [-20, -3]~ ? idealchinese(K, [x, [1,-1]], y) %7 = [4, -3]~ @eprog If $y$ is omitted, return a data structure which can be used in place of $x$ in later calls and allows to solve many chinese remainder problems for a given $x$ more efficiently. \bprog ? C = idealchinese(K, [x, [1,1]]); ? idealchinese(K, C, y) \\ as above %9 = [16, -3]~ ? for(i=1,10^4, idealchinese(K,C,y)) \\ ... but faster ! time = 80 ms. ? for(i=1,10^4, idealchinese(K,[x,[1,1]],y)) time = 224 ms. @eprog Finally, this structure is itself allowed in place of $x$, the new $s$ overriding the one already present in the structure. This allows to initialize for different sign conditions more efficiently when the underlying ideal factorization remains the same. \bprog ? D = idealchinese(K, [C, [1,-1]]); \\ replaces [1,1] ? idealchinese(K, D, y) %13 = [4, -3]~ ? for(i=1,10^4,idealchinese(K,[C,[1,-1]])) time = 40 ms. \\ faster than starting from scratch ? for(i=1,10^4,idealchinese(K,[x,[1,-1]])) time = 128 ms. @eprog Variant: Also available is \fun{GEN}{idealchineseinit}{GEN nf, GEN x} when $y = \kbd{NULL}$. pari-2.11.2/src/functions/number_fields/bnrconductor0000644000175000017500000000315513326135265021232 0ustar billbillFunction: bnrconductor Section: number_fields C-Name: bnrconductor0 Prototype: GDGDGD0,L, Help: bnrconductor(A,{B},{C},{flag=0}): conductor f of the subfield of the ray class field given by A,B,C. flag is optional and can be 0: default, 1: returns [f, Cl_f, H], H subgroup of the ray class group modulo f defining the extension, 2: returns [f, bnr(f), H]. Doc: conductor $f$ of the subfield of a ray class field as defined by $[A,B,C]$ (of type \kbd{[\var{bnr}]}, \kbd{[\var{bnr}, \var{subgroup}]}, \kbd{[\var{bnf}, \var{modulus}]} or \kbd{[\var{bnf}, \var{modulus}, \var{subgroup}]}, \secref{se:CFT}) If $\fl = 0$, returns $f$. If $\fl = 1$, returns $[f, Cl_f, H]$, where $Cl_f$ is the ray class group modulo $f$, as a finite abelian group; finally $H$ is the subgroup of $Cl_f$ defining the extension. If $\fl = 2$, returns $[f, \var{bnr}(f), H]$, as above except $Cl_f$ is replaced by a \kbd{bnr} structure, as output by $\tet{bnrinit}(,f)$, without generators unless the input contained a \var{bnr} with generators. In place of a subgroup $H$, this function also accepts a character \kbd{chi} $=(a_j)$, expressed as usual in terms of the generators \kbd{bnr.gen}: $\chi(g_j) = \exp(2i\pi a_j / d_j)$, where $g_j$ has order $d_j = \kbd{bnr.cyc[j]}$. In which case, the function returns respectively If $\fl = 0$, the conductor $f$ of $\text{Ker} \chi$. If $\fl = 1$, $[f, Cl_f, \chi_f]$, where $\chi_f$ is $\chi$ expressed on the minimal ray class group, whose modulus is the conductor. If $\fl = 2$, $[f, \var{bnr}(f), \chi_f]$. Variant: Also available is \fun{GEN}{bnrconductor}{GEN bnr, GEN H, long flag} pari-2.11.2/src/functions/number_fields/galoisgetname0000644000175000017500000000157113457566441021360 0ustar billbillFunction: galoisgetname Section: number_fields C-Name: galoisgetname Prototype: LL Help: galoisgetname(a,b): query the galpol package for a string describing the group of order a with index b in the GAP4 Small Group library. Doc: Query the \kbd{galpol} package for a string describing the group of order $a$ with index $b$ in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and Eamonn O'Brien. The strings were generated using the GAP4 function \kbd{StructureDescription}. It is possible for different groups to have the same name. The command below outputs the names of all abstract groups of order 12: \bprog ? N = galoisgetgroup(12); \\ # of abstract groups of order 12 ? for(i=1, N, print(i,". ",galoisgetname(12,i))) 1. C3 : C4 2. C12 3. A4 4. D12 5. C6 x C2 @eprog\noindent The current version of \kbd{galpol} supports groups of order $a\leq 143$. pari-2.11.2/src/functions/number_fields/nfbasis0000644000175000017500000001210513201017466020142 0ustar billbillFunction: nfbasis Section: number_fields C-Name: nfbasis_gp Prototype: G Help: nfbasis(T): integral basis of the field Q[a], where a is a root of the polynomial T, using the round 4 algorithm. An argument [T,listP] is possible, where listP is a list of primes (to get an order which is maximal at certain primes only) or a prime bound. Doc: Let $T(X)$ be an irreducible polynomial with integral coefficients. This function returns an \idx{integral basis} of the number field defined by $T$, that is a $\Z$-basis of its maximal order. The basis elements are given as elements in $\Q[X]/(T)$: \bprog ? nfbasis(x^2 + 1) %1 = [1, x] @eprog This function uses a modified version of the \idx{round 4} algorithm, due to David \idx{Ford}, Sebastian \idx{Pauli} and Xavier \idx{Roblot}. \misctitle{Local basis, orders maximal at certain primes} Obtaining the maximal order is hard: it requires factoring the discriminant $D$ of $T$. Obtaining an order which is maximal at a finite explicit set of primes is easy, but it may then be a strict suborder of the maximal order. To specify that we are interested in a given set of places only, we can replace the argument $T$ by an argument $[T,\var{listP}]$, where \var{listP} encodes the primes we are interested in: it must be a factorization matrix, a vector of integers or a single integer. \item Vector: we assume that it contains distinct \emph{prime} numbers. \item Matrix: we assume that it is a two-column matrix of a (partial) factorization of $D$; namely the first column contains distinct \emph{primes} and the second one the valuation of $D$ at each of these primes. \item Integer $B$: this is replaced by the vector of primes up to $B$. Note that the function will use at least $O(B)$ time: a small value, about $10^5$, should be enough for most applications. Values larger than $2^{32}$ are not supported. In all these cases, the primes may or may not divide the discriminant $D$ of $T$. The function then returns a $\Z$-basis of an order whose index is not divisible by any of these prime numbers. The result is actually a global integral basis if all prime divisors of the \emph{field} discriminant are included! Note that \kbd{nfinit} has built-in support for such a check: \bprog ? K = nfinit([T, listP]); ? nfcertify(K) \\ we computed an actual maximal order %2 = []; @eprog\noindent The first line initializes a number field structure incorporating \kbd{nfbasis([T, listP]} in place of a proven integral basis. The second line certifies that the resulting structure is correct. This allows to create an \kbd{nf} structure attached to the number field $K = \Q[X]/(T)$, when the discriminant of $T$ cannot be factored completely, whereas the prime divisors of $\disc K$ are known. Of course, if \var{listP} contains a single prime number $p$, the function returns a local integral basis for $\Z_p[X]/(T)$: \bprog ? nfbasis(x^2+x-1001) %1 = [1, 1/3*x - 1/3] ? nfbasis( [x^2+x-1001, [2]] ) %2 = [1, x] @eprog \misctitle{The Buchmann-Lenstra algorithm} We now complicate the picture: it is in fact allowed to include \emph{composite} numbers instead of primes in \kbd{listP} (Vector or Matrix case), provided they are pairwise coprime. The result will still be a correct integral basis \emph{if} the field discriminant factors completely over the actual primes in the list. Adding a composite $C$ such that $C^2$ \emph{divides} $D$ may help because when we consider $C$ as a prime and run the algorithm, two good things can happen: either we succeed in proving that no prime dividing $C$ can divide the index (without actually needing to find those primes), or the computation exhibits a non-trivial zero divisor, thereby factoring $C$ and we go on with the refined factorization. (Note that including a $C$ such that $C^2$ does not divide $D$ is useless.) If neither happen, then the computed basis need not generate the maximal order. Here is an example: \bprog ? B = 10^5; ? P = factor(poldisc(T), B)[,1]; \\ primes <= B dividing D + cofactor ? basis = nfbasis([T, listP]) ? disc = nfdisc([T, listP]) @eprog\noindent We obtain the maximal order and its discriminant if the field discriminant factors completely over the primes less than $B$ (together with the primes contained in the \tet{addprimes} table). This can be tested as follows: \bprog check = factor(disc, B); lastp = check[-1..-1,1]; if (lastp > B && !setsearch(addprimes(), lastp), warning("nf may be incorrect!")) @eprog\noindent This is a sufficient but not a necessary condition, hence the warning, instead of an error. N.B. \kbd{lastp} is the last entry in the first column of the \kbd{check} matrix, i.e. the largest prime dividing \kbd{nf.disc} if $\leq B$ or if it belongs to the prime table. The function \tet{nfcertify} speeds up and automates the above process: \bprog ? B = 10^5; ? nf = nfinit([T, B]); ? nfcertify(nf) %3 = [] \\ nf is unconditionally correct ? basis = nf.zk; ? disc = nf.disc; @eprog \synt{nfbasis}{GEN T, GEN *d, GEN listP = NULL}, which returns the order basis, and where \kbd{*d} receives the order discriminant. pari-2.11.2/src/functions/number_fields/rnfidealfactor0000644000175000017500000000174713326135265021520 0ustar billbillFunction: rnfidealfactor Section: number_fields C-Name: rnfidealfactor Prototype: GG Help: rnfidealfactor(rnf,x): factor the ideal x into prime ideals in the number field nfinit(rnf). Doc: factor into prime ideal powers the ideal $x$ in the attached absolute number field $L = \kbd{nfinit}(\var{rnf})$. The output format is similar to the \kbd{factor} function, and the prime ideals are represented in the form output by the \kbd{idealprimedec} function for $L$. \bprog ? rnf = rnfinit(nfinit(y^2+1), x^2-y+1); ? rnfidealfactor(rnf, y+1) \\ P_2^2 %2 = [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 2] ? rnfidealfactor(rnf, x) \\ P_2 %3 = [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 1] ? L = nfinit(rnf); ? id = idealhnf(L, idealhnf(L, 25, (x+1)^2)); ? idealfactor(L, id) == rnfidealfactor(rnf, id) %6 = 1 @eprog\noindent Note that ideals of the base field $K$ must be explicitly lifted to $L$ via \kbd{rnfidealup} before they can be factored. pari-2.11.2/src/functions/number_fields/rnfisabelian0000644000175000017500000000067011636712103021156 0ustar billbillFunction: rnfisabelian Section: number_fields C-Name: rnfisabelian Prototype: lGG Help: rnfisabelian(nf,T): T being a relative polynomial with coefficients in nf, return 1 if it defines an abelian extension, and 0 otherwise. Doc: $T$ being a relative polynomial with coefficients in \var{nf}, return 1 if it defines an abelian extension, and 0 otherwise. \bprog ? K = nfinit(y^2 + 23); ? rnfisabelian(K, x^3 - 3*x - y) %2 = 1 @eprog pari-2.11.2/src/functions/number_fields/bnrgaloismatrix0000644000175000017500000000177713201017466021737 0ustar billbillFunction: bnrgaloismatrix Section: number_fields C-Name: bnrgaloismatrix Prototype: GG Help: bnrgaloismatrix(bnr,aut): return the matrix of the action of the automorphism aut of the base field bnf.nf on the generators of the ray class field bnr.gen. aut can be given as a polynomial, or a vector of automorphisms or a galois group as output by galoisinit, in which case a vector of matrices is returned (in the later case, only for the generators aut.gen). Doc: return the matrix of the action of the automorphism \var{aut} of the base field \kbd{bnf.nf} on the generators of the ray class field \kbd{bnr.gen}. \var{aut} can be given as a polynomial, an algebraic number, or a vector of automorphisms or a Galois group as output by \kbd{galoisinit}, in which case a vector of matrices is returned (in the later case, only for the generators \kbd{aut.gen}). See \kbd{bnrisgalois} for an example. Variant: When $aut$ is a polynomial or an algebraic number, \fun{GEN}{bnrautmatrix}{GEN bnr, GEN aut} is available. pari-2.11.2/src/functions/number_fields/nfsubfields0000644000175000017500000000171411636712103021025 0ustar billbillFunction: nfsubfields Section: number_fields C-Name: nfsubfields Prototype: GD0,L, Help: nfsubfields(pol,{d=0}): find all subfields of degree d of number field defined by pol (all subfields if d is null or omitted). Result is a vector of subfields, each being given by [g,h], where g is an absolute equation and h expresses one of the roots of g in terms of the root x of the polynomial defining nf. Doc: finds all subfields of degree $d$ of the number field defined by the (monic, integral) polynomial \var{pol} (all subfields if $d$ is null or omitted). The result is a vector of subfields, each being given by $[g,h]$, where $g$ is an absolute equation and $h$ expresses one of the roots of $g$ in terms of the root $x$ of the polynomial defining $\var{nf}$. This routine uses J.~Kl\"uners's algorithm in the general case, and B.~Allombert's \tet{galoissubfields} when \var{nf} is Galois (with weakly supersolvable Galois group).\sidx{Galois}\sidx{subfield} pari-2.11.2/src/functions/number_fields/factornf0000644000175000017500000000250213201017466020317 0ustar billbillFunction: factornf Section: number_fields C-Name: polfnf Prototype: GG Obsolete: 2016-08-08 Help: factornf(x,t): this function is obsolete, use nffactor. Doc: This function is obsolete, use \kbd{nffactor}. factorization of the univariate polynomial $x$ over the number field defined by the (univariate) polynomial $t$. $x$ may have coefficients in $\Q$ or in the number field. The algorithm reduces to factorization over $\Q$ (\idx{Trager}'s trick). The direct approach of \tet{nffactor}, which uses \idx{van Hoeij}'s method in a relative setting, is in general faster. The main variable of $t$ must be of \emph{lower} priority than that of $x$ (see \secref{se:priority}). However if non-rational number field elements occur (as polmods or polynomials) as coefficients of $x$, the variable of these polmods \emph{must} be the same as the main variable of $t$. For example \bprog ? factornf(x^2 + Mod(y, y^2+1), y^2+1); ? factornf(x^2 + y, y^2+1); \\@com these two are OK ? factornf(x^2 + Mod(z,z^2+1), y^2+1) *** at top-level: factornf(x^2+Mod(z,z *** ^-------------------- *** factornf: inconsistent data in rnf function. ? factornf(x^2 + z, y^2+1) *** at top-level: factornf(x^2+z,y^2+1 *** ^-------------------- *** factornf: incorrect variable in rnf function. @eprog pari-2.11.2/src/functions/number_fields/bnflogef0000644000175000017500000000171013326135265020305 0ustar billbillFunction: bnflogef Section: number_fields C-Name: bnflogef Prototype: GG Help: bnflogef(nf,pr): return [e~, f~] the logarithmic ramification and residue degrees for the maximal ideal pr. Doc: let \var{nf} be a \var{nf} structure attached to a number field $F$ and let \var{pr} be a \var{prid} structure attached to a maximal ideal $\goth{p} / p$. Return $[\tilde{e}(F_\goth{p} / \Q_p), \tilde{f}(F_\goth{p} / \Q_p)]$ the logarithmic ramification and residue degrees. Let $\Q_p^c/\Q_p$ be the cyclotomic $\Z_p$-extension, then $\tilde{e} = [F_\goth{p} \colon F_\goth{p} \cap \Q_p^c]$ and $\tilde{f} = [F_\goth{p} \cap \Q_p^c \colon \Q_p]$. Note that $\tilde{e}\tilde{f} = e(\goth{p}/p) f(\goth{p}/p)$, where $e(\goth{p}/p)$ and $f(\goth{p}/p)$ denote the usual ramification and residue degrees. \bprog ? F = nfinit(y^6 - 3*y^5 + 5*y^3 - 3*y + 1); ? bnflogef(F, idealprimedec(F,2)[1]) %2 = [6, 1] ? bnflogef(F, idealprimedec(F,5)[1]) %3 = [1, 2] @eprog pari-2.11.2/src/functions/number_fields/idealpow0000644000175000017500000000160113201017466020320 0ustar billbillFunction: idealpow Section: number_fields C-Name: idealpow0 Prototype: GGGD0,L, Help: idealpow(nf,x,k,{flag=0}): k-th power of the ideal x in HNF in the number field nf. If (optional) flag is non-null, reduce the result. Doc: computes the $k$-th power of the ideal $x$ in the number field $\var{nf}$; $k\in\Z$. If $x$ is an extended ideal\sidx{ideal (extended)}, its principal part is suitably updated: i.e. raising $[I,t]$ to the $k$-th power, yields $[I^k, t^k]$. If $\fl$ is non-zero, reduce the result using \kbd{idealred}, \emph{throughout the (binary) powering process}; in particular, this is \emph{not} the same as $\kbd{idealpow}(\var{nf},x,k)$ followed by reduction. Variant: \noindent See also \fun{GEN}{idealpow}{GEN nf, GEN x, GEN k} and \fun{GEN}{idealpows}{GEN nf, GEN x, long k} ($\fl = 0$). Corresponding to $\fl=1$ is \fun{GEN}{idealpowred}{GEN nf, GEN vp, GEN k}. pari-2.11.2/src/functions/number_fields/rnfislocalcyclo0000644000175000017500000000152413326135265021714 0ustar billbillFunction: rnfislocalcyclo Section: number_fields C-Name: rnfislocalcyclo Prototype: lG Help: rnfislocalcyclo(rnf): true(1) if the l-extension attached to rnf is locally cyclotomic (locally contained in the Z_l extension of K_v at all places v | l), false(0) if not. Doc: Let \var{rnf} be a relative number field extension $L/K$ as output by \kbd{rnfinit} whose degree $[L:K]$ is a power of a prime $\ell$. Return $1$ if the $\ell$-extension is locally cyclotomic (locally contained in the cyclotomic $\Z_\ell$-extension of $K_v$ at all places $v | \ell$), and $0$ if not. \bprog ? K = nfinit(y^2 + y + 1); ? L = rnfinit(K, x^3 - y); /* = K(zeta_9), globally cyclotomic */ ? rnfislocalcyclo(L) %3 = 1 \\ we expect 3-adic continuity by Krasner's lemma ? vector(5, i, rnfislocalcyclo(rnfinit(K, x^3 - y + 3^i))) %5 = [0, 1, 1, 1, 1] @eprog pari-2.11.2/src/functions/number_fields/nfgaloisconj0000644000175000017500000000436413201017466021201 0ustar billbillFunction: nfgaloisconj Section: number_fields C-Name: galoisconj0 Prototype: GD0,L,DGp Help: nfgaloisconj(nf,{flag=0},{d}): list of conjugates of a root of the polynomial x=nf.pol in the same number field. flag is optional (set to 0 by default), meaning 0: use combination of flag 4 and 1, always complete; 1: use nfroots; 4: use Allombert's algorithm, complete if the field is Galois of degree <= 35 (see manual for details). nf can be simply a polynomial. Doc: $\var{nf}$ being a number field as output by \kbd{nfinit}, computes the conjugates of a root $r$ of the non-constant polynomial $x=\var{nf}[1]$ expressed as polynomials in $r$. This also makes sense when the number field is not \idx{Galois} since some conjugates may lie in the field. $\var{nf}$ can simply be a polynomial. If no flags or $\fl=0$, use a combination of flag $4$ and $1$ and the result is always complete. There is no point whatsoever in using the other flags. If $\fl=1$, use \kbd{nfroots}: a little slow, but guaranteed to work in polynomial time. If $\fl=4$, use \kbd{galoisinit}: very fast, but only applies to (most) Galois fields. If the field is Galois with weakly super-solvable Galois group (see \tet{galoisinit}), return the complete list of automorphisms, else only the identity element. If present, $d$ is assumed to be a multiple of the least common denominator of the conjugates expressed as polynomial in a root of \var{pol}. This routine can only compute $\Q$-automorphisms, but it may be used to get $K$-automorphism for any base field $K$ as follows: \bprog rnfgaloisconj(nfK, R) = \\ K-automorphisms of L = K[X] / (R) { my(polabs, N,al,S, ala,k, vR); R *= Mod(1, nfK.pol); \\ convert coeffs to polmod elts of K vR = variable(R); al = Mod(variable(nfK.pol),nfK.pol); [polabs,ala,k] = rnfequation(nfK, R, 1); Rt = if(k==0,R,subst(R,vR,vR-al*k)); N = nfgaloisconj(polabs) % Rt; \\ Q-automorphisms of L S = select(s->subst(Rt, vR, Mod(s,Rt)) == 0, N); if (k==0, S, apply(s->subst(s,vR,vR+k*al)-k*al,S)); } K = nfinit(y^2 + 7); rnfgaloisconj(K, x^4 - y*x^3 - 3*x^2 + y*x + 1) \\ K-automorphisms of L @eprog Variant: Use directly \fun{GEN}{galoisconj}{GEN nf, GEN d}, corresponding to $\fl = 0$, the others only have historical interest. pari-2.11.2/src/functions/number_fields/nfkermodpr0000644000175000017500000000073313201017466020670 0ustar billbillFunction: nfkermodpr Section: number_fields C-Name: nfkermodpr Prototype: GGG Obsolete: 2016-08-09 Help: nfkermodpr(nf,x,pr): this function is obsolete, use nfmodpr. Doc: this function is obsolete, use \kbd{nfmodpr}. Kernel of the matrix $a$ in $\Z_K/\var{pr}$, where \var{pr} is in \key{modpr} format (see \kbd{nfmodprinit}). Variant: This function is normally useless in library mode. Project your inputs to the residue field using \kbd{nfM\_to\_FqM}, then work there. pari-2.11.2/src/functions/number_fields/bnrclassno0000644000175000017500000000227513201017466020670 0ustar billbillFunction: bnrclassno Section: number_fields C-Name: bnrclassno0 Prototype: GDGDG Help: bnrclassno(A,{B},{C}): relative degree of the class field defined by A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf,modulus], or [bnf,modulus,subgroup]. Faster than bnrinit if only the ray class number is wanted. Doc: let $A$, $B$, $C$ define a class field $L$ over a ground field $K$ (of type \kbd{[\var{bnr}]}, \kbd{[\var{bnr}, \var{subgroup}]}, or \kbd{[\var{bnf}, \var{modulus}]}, or \kbd{[\var{bnf}, \var{modulus},\var{subgroup}]}, \secref{se:CFT}); this function returns the relative degree $[L:K]$. In particular if $A$ is a \var{bnf} (with units), and $B$ a modulus, this function returns the corresponding ray class number modulo $B$. One can input the attached \var{bid} (with generators if the subgroup $C$ is non trivial) for $B$ instead of the module itself, saving some time. This function is faster than \kbd{bnrinit} and should be used if only the ray class number is desired. See \tet{bnrclassnolist} if you need ray class numbers for all moduli less than some bound. Variant: Also available is \fun{GEN}{bnrclassno}{GEN bnf,GEN f} to compute the ray class number modulo~$f$. pari-2.11.2/src/functions/number_fields/bnrconductorofchar0000644000175000017500000000037213201017466022405 0ustar billbillFunction: bnrconductorofchar Section: number_fields C-Name: bnrconductorofchar Prototype: GG Obsolete: 2015-11-11 Help: bnrconductorofchar(bnr,chi): this function is obsolete, use bnrconductor. Doc: This function is obsolete, use \tev{bnrconductor}. pari-2.11.2/src/functions/number_fields/rnfpolredabs0000644000175000017500000000376113326135265021214 0ustar billbillFunction: rnfpolredabs Section: number_fields C-Name: rnfpolredabs Prototype: GGD0,L, Help: rnfpolredabs(nf,pol,{flag=0}): given an irreducible pol with coefficients in nf, finds a canonical relative polynomial defining the same field. Binary digits of flag mean: 1: return also the element whose characteristic polynomial is the given polynomial, 2: return an absolute polynomial, 16: partial reduction. Doc: Relative version of \kbd{polredabs}. Given an irreducible monic polynomial \var{pol} with coefficients in $\var{nf}$, finds a canonical relative polynomial defining the same field, hopefully with small coefficients. Note that the equation is only canonical for a fixed \var{nf}, using a different defining polynomial in the \var{nf} structure will produce a different relative equation. The binary digits of $\fl$ correspond to $1$: add information to convert elements to the new representation, $2$: absolute polynomial, instead of relative, $16$: possibly use a suborder of the maximal order. More precisely: 0: default, return $P$ 1: returns $[P,a]$ where $P$ is the default output and $a$, a \typ{POLMOD} modulo $P$, is a root of \var{pol}. 2: returns \var{Pabs}, an absolute, instead of a relative, polynomial. This polynomial is canonical and does not depend on the \var{nf} structure. Same as but faster than \bprog polredabs(rnfequation(nf, pol)) @eprog 3: returns $[\var{Pabs},a,b]$, where \var{Pabs} is an absolute polynomial as above, $a$, $b$ are \typ{POLMOD} modulo \var{Pabs}, roots of \kbd{nf.pol} and \var{pol} respectively. 16: possibly use a suborder of the maximal order. This is slower than the default when the relative discriminant is smooth, and much faster otherwise. In this case the result is no longer canonical; see \secref{se:polredabs}. \misctitle{Warning} The complexity of \kbd{rnfpolredabs} is exponential in the absolute degree. The function \tet{rnfpolredbest} runs in polynomial time, and tends to return polynomials with smaller discriminants. pari-2.11.2/src/functions/number_fields/polgalois0000644000175000017500000001025212314242551020506 0ustar billbillFunction: polgalois Section: number_fields C-Name: polgalois Prototype: Gp Help: polgalois(T): Galois group of the polynomial T (see manual for group coding). Return [n, s, k, name] where n is the group order, s the signature, k the index and name is the GAP4 name of the transitive group. Doc: \idx{Galois} group of the non-constant polynomial $T\in\Q[X]$. In the present version \vers, $T$ must be irreducible and the degree $d$ of $T$ must be less than or equal to 7. If the \tet{galdata} package has been installed, degrees 8, 9, 10 and 11 are also implemented. By definition, if $K = \Q[x]/(T)$, this computes the action of the Galois group of the Galois closure of $K$ on the $d$ distinct roots of $T$, up to conjugacy (corresponding to different root orderings). The output is a 4-component vector $[n,s,k,name]$ with the following meaning: $n$ is the cardinality of the group, $s$ is its signature ($s=1$ if the group is a subgroup of the alternating group $A_d$, $s=-1$ otherwise) and name is a character string containing name of the transitive group according to the GAP 4 transitive groups library by Alexander Hulpke. $k$ is more arbitrary and the choice made up to version~2.2.3 of PARI is rather unfortunate: for $d > 7$, $k$ is the numbering of the group among all transitive subgroups of $S_d$, as given in ``The transitive groups of degree up to eleven'', G.~Butler and J.~McKay, \emph{Communications in Algebra}, vol.~11, 1983, pp.~863--911 (group $k$ is denoted $T_k$ there). And for $d \leq 7$, it was ad hoc, so as to ensure that a given triple would denote a unique group. Specifically, for polynomials of degree $d\leq 7$, the groups are coded as follows, using standard notations \smallskip In degree 1: $S_1=[1,1,1]$. \smallskip In degree 2: $S_2=[2,-1,1]$. \smallskip In degree 3: $A_3=C_3=[3,1,1]$, $S_3=[6,-1,1]$. \smallskip In degree 4: $C_4=[4,-1,1]$, $V_4=[4,1,1]$, $D_4=[8,-1,1]$, $A_4=[12,1,1]$, $S_4=[24,-1,1]$. \smallskip In degree 5: $C_5=[5,1,1]$, $D_5=[10,1,1]$, $M_{20}=[20,-1,1]$, $A_5=[60,1,1]$, $S_5=[120,-1,1]$. \smallskip In degree 6: $C_6=[6,-1,1]$, $S_3=[6,-1,2]$, $D_6=[12,-1,1]$, $A_4=[12,1,1]$, $G_{18}=[18,-1,1]$, $S_4^-=[24,-1,1]$, $A_4\times C_2=[24,-1,2]$, $S_4^+=[24,1,1]$, $G_{36}^-=[36,-1,1]$, $G_{36}^+=[36,1,1]$, $S_4\times C_2=[48,-1,1]$, $A_5=PSL_2(5)=[60,1,1]$, $G_{72}=[72,-1,1]$, $S_5=PGL_2(5)=[120,-1,1]$, $A_6=[360,1,1]$, $S_6=[720,-1,1]$. \smallskip In degree 7: $C_7=[7,1,1]$, $D_7=[14,-1,1]$, $M_{21}=[21,1,1]$, $M_{42}=[42,-1,1]$, $PSL_2(7)=PSL_3(2)=[168,1,1]$, $A_7=[2520,1,1]$, $S_7=[5040,-1,1]$. \smallskip This is deprecated and obsolete, but for reasons of backward compatibility, we cannot change this behavior yet. So you can use the default \tet{new_galois_format} to switch to a consistent naming scheme, namely $k$ is always the standard numbering of the group among all transitive subgroups of $S_n$. If this default is in effect, the above groups will be coded as: \smallskip In degree 1: $S_1=[1,1,1]$. \smallskip In degree 2: $S_2=[2,-1,1]$. \smallskip In degree 3: $A_3=C_3=[3,1,1]$, $S_3=[6,-1,2]$. \smallskip In degree 4: $C_4=[4,-1,1]$, $V_4=[4,1,2]$, $D_4=[8,-1,3]$, $A_4=[12,1,4]$, $S_4=[24,-1,5]$. \smallskip In degree 5: $C_5=[5,1,1]$, $D_5=[10,1,2]$, $M_{20}=[20,-1,3]$, $A_5=[60,1,4]$, $S_5=[120,-1,5]$. \smallskip In degree 6: $C_6=[6,-1,1]$, $S_3=[6,-1,2]$, $D_6=[12,-1,3]$, $A_4=[12,1,4]$, $G_{18}=[18,-1,5]$, $A_4\times C_2=[24,-1,6]$, $S_4^+=[24,1,7]$, $S_4^-=[24,-1,8]$, $G_{36}^-=[36,-1,9]$, $G_{36}^+=[36,1,10]$, $S_4\times C_2=[48,-1,11]$, $A_5=PSL_2(5)=[60,1,12]$, $G_{72}=[72,-1,13]$, $S_5=PGL_2(5)=[120,-1,14]$, $A_6=[360,1,15]$, $S_6=[720,-1,16]$. \smallskip In degree 7: $C_7=[7,1,1]$, $D_7=[14,-1,2]$, $M_{21}=[21,1,3]$, $M_{42}=[42,-1,4]$, $PSL_2(7)=PSL_3(2)=[168,1,5]$, $A_7=[2520,1,6]$, $S_7=[5040,-1,7]$. \smallskip \misctitle{Warning} The method used is that of resolvent polynomials and is sensitive to the current precision. The precision is updated internally but, in very rare cases, a wrong result may be returned if the initial precision was not sufficient. Variant: To enable the new format in library mode, set the global variable \tet{new_galois_format} to $1$. pari-2.11.2/src/functions/number_fields/rnfidealnormrel0000644000175000017500000000067513036414402021706 0ustar billbillFunction: rnfidealnormrel Section: number_fields C-Name: rnfidealnormrel Prototype: GG Help: rnfidealnormrel(rnf,x): relative norm of the ideal x. Doc: let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a relative ideal (which can be, as in the absolute case, of many different types, including of course elements). This function computes the relative norm of $x$ as an ideal of $K$ in HNF. pari-2.11.2/src/functions/number_fields/idealstar0000644000175000017500000000554513326135265020505 0ustar billbillFunction: idealstar Section: number_fields C-Name: idealstar0 Prototype: DGGD1,L, Help: idealstar({nf},N,{flag=1}): gives the structure of (Z_K/N)^*, where N is a modulus (an ideal in any form or a vector [f0, foo], where f0 is an ideal and foo is a {0,1}-vector with r1 components. flag is optional, and can be 0: simply gives the structure as an abelian group, i.e. a 3-component vector [h,d,g] where h is the order, d the orders of the cyclic factors and g the generators; if flag=1 (default), gives a bid structure used in ideallog to compute discrete logarithms; underlying generators are well-defined but not explicitly computed, which saves time; if flag=2, same as with flag=1 except that the generators are also given. If nf is omitted, N must be an integer and we return the structure of (Z/NZ)^*. Doc: outputs a \kbd{bid} structure, necessary for computing in the finite abelian group $G = (\Z_K/N)^*$. Here, \var{nf} is a number field and $N$ is a \var{modulus}: either an ideal in any form, or a row vector whose first component is an ideal and whose second component is a row vector of $r_1$ 0 or 1. Ideals can also be given by a factorization into prime ideals, as produced by \tet{idealfactor}. This \var{bid} is used in \tet{ideallog} to compute discrete logarithms. It also contains useful information which can be conveniently retrieved as \kbd{\var{bid}.mod} (the modulus), \kbd{\var{bid}.clgp} ($G$ as a finite abelian group), \kbd{\var{bid}.no} (the cardinality of $G$), \kbd{\var{bid}.cyc} (elementary divisors) and \kbd{\var{bid}.gen} (generators). If $\fl=1$ (default), the result is a \kbd{bid} structure without generators: they are well defined but not explicitly computed, which saves time. If $\fl=2$, as $\fl=1$, but including generators. If $\fl=0$, only outputs $(\Z_K/N)^*$ as an abelian group, i.e as a 3-component vector $[h,d,g]$: $h$ is the order, $d$ is the vector of SNF\sidx{Smith normal form} cyclic components and $g$ the corresponding generators. If \var{nf} is omitted, we take it to be the rational number fields, $N$ must be an integer and we return the structure of $(\Z/N\Z)^*$. In other words \kbd{idealstar(, N, flag)} is short for \bprog idealstar(nfinit(x), N, flag) @eprog\noindent but faster. The alternative syntax \kbd{znstar(N, flag)} is also available for an analogous effect but, due to an unfortunate historical oversight, the default value of \kbd{flag} is different in the two functions (\kbd{znstar} does not initialize by default, you probably want \kbd{znstar(N,1)}). Variant: Instead the above hardcoded numerical flags, one should rather use \fun{GEN}{Idealstar}{GEN nf, GEN ideal, long flag}, where \kbd{flag} is an or-ed combination of \tet{nf_GEN} (include generators) and \tet{nf_INIT} (return a full \kbd{bid}, not a group), possibly $0$. This offers one more combination: gen, but no init. pari-2.11.2/src/functions/number_fields/idealfrobenius0000644000175000017500000000170313201017466021512 0ustar billbillFunction: idealfrobenius Section: number_fields C-Name: idealfrobenius Prototype: GGG Help: idealfrobenius(nf,gal,pr): returns the Frobenius element (pr|nf/Q) attached to the unramified prime ideal pr in prid format, in the Galois group gal of the number field nf. Doc: Let $K$ be the number field defined by $nf$ and assume $K/\Q$ be a Galois extension with Galois group given \kbd{gal=galoisinit(nf)}, and that \var{pr} is an unramified prime ideal $\goth{p}$ in \kbd{prid} format. This function returns a permutation of \kbd{gal.group} which defines the Frobenius element $\Frob_{\goth{p}}$ attached to $\goth{p}$. If $p$ is the unique prime number in $\goth{p}$, then $\Frob(x)\equiv x^p\mod\goth{p}$ for all $x\in\Z_K$. \bprog ? nf = nfinit(polcyclo(31)); ? gal = galoisinit(nf); ? pr = idealprimedec(nf,101)[1]; ? g = idealfrobenius(nf,gal,pr); ? galoispermtopol(gal,g) %5 = x^8 @eprog\noindent This is correct since $101\equiv 8\mod{31}$. pari-2.11.2/src/functions/number_fields/bnrrootnumber0000644000175000017500000000256413326135265021431 0ustar billbillFunction: bnrrootnumber Section: number_fields C-Name: bnrrootnumber Prototype: GGD0,L,p Help: bnrrootnumber(bnr,chi,{flag=0}): returns the so-called Artin Root Number, i.e. the constant W appearing in the functional equation of the Hecke L-function attached to chi. Set flag = 1 if the character is known to be primitive. Doc: if $\chi=\var{chi}$ is a \idx{character} over \var{bnr}, not necessarily primitive, let $L(s,\chi) = \sum_{id} \chi(id) N(id)^{-s}$ be the attached \idx{Artin L-function}. Returns the so-called \idx{Artin root number}, i.e.~the complex number $W(\chi)$ of modulus 1 such that % $$\Lambda(1-s,\chi) = W(\chi) \Lambda(s,\overline{\chi})$$ % \noindent where $\Lambda(s,\chi) = A(\chi)^{s/2}\gamma_\chi(s) L(s,\chi)$ is the enlarged L-function attached to $L$. You can set $\fl=1$ if the character is known to be primitive. Example: \bprog bnf = bnfinit(x^2 - x - 57); bnr = bnrinit(bnf, [7,[1,1]]); bnrrootnumber(bnr, [2,1]) @eprog\noindent returns the root number of the character $\chi$ of $\Cl_{7\infty_1\infty_2}(\Q(\sqrt{229}))$ defined by $\chi(g_1^ag_2^b) = \zeta_1^{2a}\zeta_2^b$. Here $g_1, g_2$ are the generators of the ray-class group given by \kbd{bnr.gen} and $\zeta_1 = e^{2i\pi/N_1}, \zeta_2 = e^{2i\pi/N_2}$ where $N_1, N_2$ are the orders of $g_1$ and $g_2$ respectively ($N_1=6$ and $N_2=3$ as \kbd{bnr.cyc} readily tells us). pari-2.11.2/src/functions/number_fields/nfmodprinit0000644000175000017500000000071313201017466021050 0ustar billbillFunction: nfmodprinit Section: number_fields C-Name: nfmodprinit Prototype: GG Help: nfmodprinit(nf,pr): transform the prime ideal pr into modpr format necessary for all operations mod pr in the number field nf. Doc: transforms the prime ideal \var{pr} into \tet{modpr} format necessary for all operations modulo \var{pr} in the number field \var{nf}. The functions \tet{nfmodpr} and \tet{nfmodprlift} allow to project to and lift from the residue field. pari-2.11.2/src/functions/number_fields/idealdiv0000644000175000017500000000212613326135265020306 0ustar billbillFunction: idealdiv Section: number_fields C-Name: idealdiv0 Prototype: GGGD0,L, Help: idealdiv(nf,x,y,{flag=0}): quotient x/y of two ideals x and y in HNF in the number field nf. If (optional) flag is non-null, the quotient is supposed to be an integral ideal (slightly faster). Description: (gen, gen, gen, ?0):gen idealdiv($1, $2, $3) (gen, gen, gen, 1):gen idealdivexact($1, $2, $3) (gen, gen, gen, #small):gen $"invalid flag in idealdiv" (gen, gen, gen, small):gen idealdiv0($1, $2, $3, $4) Doc: quotient $x\cdot y^{-1}$ of the two ideals $x$ and $y$ in the number field $\var{nf}$. The result is given in HNF. If $\fl$ is non-zero, the quotient $x \cdot y^{-1}$ is assumed to be an integral ideal. This can be much faster when the norm of the quotient is small even though the norms of $x$ and $y$ are large. More precisely, the algorithm cheaply removes all maximal ideals above rational primes such that $v_p(Nx) = v_p(Ny)$. Variant: Also available are \fun{GEN}{idealdiv}{GEN nf, GEN x, GEN y} ($\fl=0$) and \fun{GEN}{idealdivexact}{GEN nf, GEN x, GEN y} ($\fl=1$). pari-2.11.2/src/functions/number_fields/rnfidealnormabs0000644000175000017500000000107413036414402021663 0ustar billbillFunction: rnfidealnormabs Section: number_fields C-Name: rnfidealnormabs Prototype: GG Help: rnfidealnormabs(rnf,x): absolute norm of the ideal x. Doc: let $\var{rnf}$ be a relative number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a relative ideal (which can be, as in the absolute case, of many different types, including of course elements). This function computes the norm of the $x$ considered as an ideal of the absolute extension $L/\Q$. This is identical to \bprog idealnorm(rnf, rnfidealnormrel(rnf,x)) @eprog\noindent but faster. pari-2.11.2/src/functions/number_fields/nfeltpow0000644000175000017500000000054211636712103020355 0ustar billbillFunction: nfeltpow Section: number_fields C-Name: nfpow Prototype: GGG Help: nfeltpow(nf,x,k): element x^k in nf. Doc: given an element $x$ in \var{nf}, and a positive or negative integer $k$, computes $x^k$ in the number field $\var{nf}$. Variant: \fun{GEN}{nfinv}{GEN nf, GEN x} correspond to $k = -1$, and \fun{GEN}{nfsqr}{GEN nf,GEN x} to $k = 2$. pari-2.11.2/src/functions/number_fields/bnfissunit0000644000175000017500000000175113326135265020714 0ustar billbillFunction: bnfissunit Section: number_fields C-Name: bnfissunit Prototype: GGG Help: bnfissunit(bnf,sfu,x): bnf being output by bnfinit (with flag<=2), sfu by bnfsunit, gives the column vector of exponents of x on the fundamental S-units and the roots of unity if x is an S-unit, the empty vector otherwise. Doc: $\var{bnf}$ being output by \kbd{bnfinit}, \var{sfu} by \kbd{bnfsunit}, gives the column vector of exponents of $x$ on the fundamental $S$-units and the roots of unity, in the following order: the fundamental units~\var{bnf.fu}, the root of unity~\var{bnf.tu}, and the $S$-units~\var{sfu[1]}. If $x$ is not an $S$-unit, outputs an empty vector. \bprog ? bnf = bnfinit(x^4 - x^3 + 4*x^2 + 3*x + 9, 1); ? bnf.sign %2 = [0, 2] ? S = idealprimedec(bnf,5); #S %3 = 2 ? sfu = bnfsunit(bnf,S); ? sfu[1] %5 = [-5/6*x^3 + 4/3*x^2 - 4/3*x - 3/2, 5] ? u = [10,-40,24,11]~; ? bnfissunit(bnf,sfu,u) %7 = [1, Mod(2, 6), 2, 0]~ ? bnfissunit(bnf,sfu,3) %8 = []~ @eprog pari-2.11.2/src/functions/number_fields/nfnewprec0000644000175000017500000000127213201017466020507 0ustar billbillFunction: nfnewprec Section: number_fields C-Name: nfnewprec Prototype: Gp Help: nfnewprec(nf): transform the number field data nf into new data using the current (usually larger) precision. Doc: transforms the number field $\var{nf}$ into the corresponding data using current (usually larger) precision. This function works as expected if \var{nf} is in fact a \var{bnf} or a \var{bnr} (update structure to current precision) but may be quite slow: many generators of principal ideals have to be computed; note that in this latter case, the \var{bnf} must contain fundamental units. Variant: See also \fun{GEN}{bnfnewprec}{GEN bnf, long prec} and \fun{GEN}{bnrnewprec}{GEN bnr, long prec}. pari-2.11.2/src/functions/number_fields/rnfdet0000644000175000017500000000035311636712103020001 0ustar billbillFunction: rnfdet Section: number_fields C-Name: rnfdet Prototype: GG Help: rnfdet(nf,M): given a pseudo-matrix M, compute its determinant. Doc: given a pseudo-matrix $M$ over the maximal order of $\var{nf}$, computes its determinant. pari-2.11.2/src/functions/number_fields/rnfhnfbasis0000644000175000017500000000106211636712103021020 0ustar billbillFunction: rnfhnfbasis Section: number_fields C-Name: rnfhnfbasis Prototype: GG Help: rnfhnfbasis(bnf,x): given an order x as output by rnfpseudobasis, gives either a true HNF basis of the order if it exists, zero otherwise. Doc: given $\var{bnf}$ as output by \kbd{bnfinit}, and either a polynomial $x$ with coefficients in $\var{bnf}$ defining a relative extension $L$ of $\var{bnf}$, or a pseudo-basis $x$ of such an extension, gives either a true $\var{bnf}$-basis of $L$ in upper triangular Hermite normal form, if it exists, and returns $0$ otherwise. pari-2.11.2/src/functions/number_fields/rnfdisc0000644000175000017500000000207013326135265020153 0ustar billbillFunction: rnfdisc Section: number_fields C-Name: rnfdiscf Prototype: GG Help: rnfdisc(nf,T): given a polynomial T with coefficients in nf, gives a 2-component vector [D,d], where D is the relative ideal discriminant, and d is the relative discriminant in nf^*/nf*^2. Doc: given an \var{nf} structure attached to a number field $K$, as output by \kbd{nfinit}, and a monic irreducible polynomial $T\in K[x]$ defining a relative extension $L = K[x]/(T)$, compute the relative discriminant of $L$. This is a vector $[D,d]$, where $D$ is the relative ideal discriminant and $d$ is the relative discriminant considered as an element of $K^*/{K^*}^2$. The main variable of $\var{nf}$ \emph{must} be of lower priority than that of $T$, see \secref{se:priority}. \misctitle{Huge discriminants, helping rnfdisc} the format $[T,B]$ is also accepted instead of $T$ and computes an order which is maximal at all $p < B$, see \kbd{??rnfinit}: the valuation of $D$ is then correct at all prime ideals $\goth{p}$ above a rational prime $p < B$ but may be incorrect at other primes. pari-2.11.2/src/functions/number_fields/nffactor0000644000175000017500000000365213201017466020326 0ustar billbillFunction: nffactor Section: number_fields C-Name: nffactor Prototype: GG Help: nffactor(nf,T): factor polynomial T in number field nf. Doc: factorization of the univariate polynomial $T$ over the number field $\var{nf}$ given by \kbd{nfinit}; $T$ has coefficients in $\var{nf}$ (i.e.~either scalar, polmod, polynomial or column vector). The factors are sorted by increasing degree. The main variable of $\var{nf}$ must be of \emph{lower} priority than that of $T$, see \secref{se:priority}. However if the polynomial defining the number field occurs explicitly in the coefficients of $T$ as modulus of a \typ{POLMOD} or as a \typ{POL} coefficient, its main variable must be \emph{the same} as the main variable of $T$. For example, \bprog ? nf = nfinit(y^2 + 1); ? nffactor(nf, x^2 + y); \\@com OK ? nffactor(nf, x^2 + Mod(y, y^2+1)); \\ @com OK ? nffactor(nf, x^2 + Mod(z, z^2+1)); \\ @com WRONG @eprog It is possible to input a defining polynomial for \var{nf} instead, but this is in general less efficient since parts of an \kbd{nf} structure will then be computed internally. This is useful in two situations: when you do not need the \kbd{nf} elsewhere, or when you cannot initialize an \kbd{nf} due to integer factorization difficulties when attempting to compute the field discriminant and maximal order. In all cases, the function runs in polynomial time using Belabas's variant of \idx{van Hoeij}'s algorithm, which copes with hundreds of modular factors. \misctitle{Caveat} \kbd{nfinit([T, listP])} allows to compute in polynomial time a conditional \var{nf} structure, which sets \kbd{nf.zk} to an order which is not guaranteed to be maximal at all primes. Always either use \kbd{nfcertify} first (which may not run in polynomial time) or make sure to input \kbd{nf.pol} instead of the conditional \var{nf}: \kbd{nffactor} is able to recover in polynomial time in this case, instead of potentially missing a factor. pari-2.11.2/src/functions/number_fields/nfeltnorm0000644000175000017500000000022111636712103020515 0ustar billbillFunction: nfeltnorm Section: number_fields C-Name: nfnorm Prototype: GG Help: nfeltnorm(nf,x): norm of x. Doc: returns the absolute norm of $x$. pari-2.11.2/src/functions/number_fields/galoischardet0000644000175000017500000000221613326135265021336 0ustar billbillFunction: galoischardet Section: number_fields C-Name: galoischardet Prototype: GGD1,L, Help: galoischardet(gal, chi, {o=1}): return the determinant character of the character chi. Doc: Let $G$ be the group attached to the \kbd{galoisinit} structure~\var{gal}, and let $\chi$ be the character of some representation $\rho$ of the group $G$, where a polynomial variable is to be interpreted as an $o$-th root of 1. For instance, if \kbd{[T,o] = galoischartable(gal)} the characters $\chi$ are input as the columns of \kbd{T}. Return the degree-$1$ character $\det\rho$ as the list of $\det \rho(g)$, where $g$ runs through representatives of the conjugacy classes in \kbd{galoisconjclasses(gal)}, with the same ordering. \bprog ? P = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; ? polgalois(P) %2 = [10, 1, 1, "D(5) = 5:2"] ? K = nfsplitting(P); ? gal = galoisinit(K); \\ dihedral of order 10 ? [T,o] = galoischartable(gal); ? chi = T[,1]; \\ trivial character ? galoischardet(gal, chi, o) %7 = [1, 1, 1, 1]~ ? [galoischardet(gal, T[,i], o) | i <- [1..#T]] \\ all characters %8 = [[1, 1, 1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~] @eprog pari-2.11.2/src/functions/number_fields/galoischartable0000644000175000017500000000456713326135265021664 0ustar billbillFunction: galoischartable Section: number_fields C-Name: galoischartable Prototype: G Help: galoischartable(gal): return the character table of the underlying group of gal. Doc: Compute the character table of~$G$, where~$G$ is the underlying group of the \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed to be a \typ{VEC} of permutations that is closed under products. Let~$N$ be the number of conjugacy classes of~$G$. Return a \typ{VEC}~$[M,\var{e}]$ where $e \geq 1$ is an integer and $M$ is a square \typ{MAT} of size~$N$ giving the character table of~$G$. \item Each column corresponds to an irreducible character; the characters are ordered by increasing dimension and the first column is the trivial character (hence contains only $1$'s). \item Each row corresponds to a conjugacy class; the conjugacy classes are ordered as specified by \kbd{galoisconjclasses(gal)}, in particular the first row corresponds to the identity and gives the dimension $\chi(1)$ of the irreducible representation attached to the successive characters $\chi$. The value $M[i,j]$ of the character $j$ at the conjugacy class $i$ is represented by a polynomial in \kbd{y} whose variable should be interpreted as an $e$-th root of unity, i.e. as the lift of \bprog Mod(y, polcyclo(e,'y)) @eprog\noindent (Note that $M$ is the transpose of the usual orientation for character tables.) The integer $e$ divides the exponent of the group $G$ and is chosen as small as posible; for instance $e = 1$ when the characters are all defined over $\Q$, as is the case for $S_n$. Examples: \bprog ? K = nfsplitting(x^4+x+1); ? gal = galoisinit(K); ? [M,e] = galoischartable(gal); ? M~ \\ take the transpose to get the usual orientation %4 = [1 1 1 1 1] [1 -1 -1 1 1] [2 0 0 -1 2] [3 -1 1 0 -1] [3 1 -1 0 -1] ? e %5 = 1 ? {G = [Vecsmall([1, 2, 3, 4, 5]), Vecsmall([1, 5, 4, 3, 2]), Vecsmall([2, 1, 5, 4, 3]), Vecsmall([2, 3, 4, 5, 1]), Vecsmall([3, 2, 1, 5, 4]), Vecsmall([3, 4, 5, 1, 2]), Vecsmall([4, 3, 2, 1, 5]), Vecsmall([4, 5, 1, 2, 3]), Vecsmall([5, 1, 2, 3, 4]), Vecsmall([5, 4, 3, 2, 1])];} \\G = D10 ? [M,e] = galoischartable(G); ? M~ %8 = [1 1 1 1] [1 -1 1 1] [2 0 -y^3 - y^2 - 1 y^3 + y^2] [2 0 y^3 + y^2 -y^3 - y^2 - 1] ? e %9 = 5 @eprog pari-2.11.2/src/functions/number_fields/ideallistarch0000644000175000017500000000331013201017466021323 0ustar billbillFunction: ideallistarch Section: number_fields C-Name: ideallistarch Prototype: GGG Help: ideallistarch(nf,list,arch): list is a vector of vectors of bid's as output by ideallist. Return a vector of vectors with the same number of components as the original list. The leaves give information about moduli whose finite part is as in original list, in the same order, and Archimedean part is now arch. The information contained is of the same kind as was present in the input. Doc: \var{list} is a vector of vectors of bid's, as output by \tet{ideallist} with flag $0$ to $3$. Return a vector of vectors with the same number of components as the original \var{list}. The leaves give information about moduli whose finite part is as in original list, in the same order, and Archimedean part is now \var{arch} (it was originally trivial). The information contained is of the same kind as was present in the input; see \tet{ideallist}, in particular the meaning of \fl. \bprog ? bnf = bnfinit(x^2-2); ? bnf.sign %2 = [2, 0] \\@com two places at infinity ? L = ideallist(bnf, 100, 0); ? l = L[98]; vector(#l, i, l[i].clgp) %4 = [[42, [42]], [36, [6, 6]], [42, [42]]] ? La = ideallistarch(bnf, L, [1,1]); \\@com add them to the modulus ? l = La[98]; vector(#l, i, l[i].clgp) %6 = [[168, [42, 2, 2]], [144, [6, 6, 2, 2]], [168, [42, 2, 2]]] @eprog Of course, the results above are obvious: adding $t$ places at infinity will add $t$ copies of $\Z/2\Z$ to $(\Z_K/f)^*$. The following application is more typical: \bprog ? L = ideallist(bnf, 100, 2); \\@com units are required now ? La = ideallistarch(bnf, L, [1,1]); ? H = bnrclassnolist(bnf, La); ? H[98]; %4 = [2, 12, 2] @eprog pari-2.11.2/src/functions/number_fields/nfeltdiv0000644000175000017500000000034213201017466020330 0ustar billbillFunction: nfeltdiv Section: number_fields C-Name: nfdiv Prototype: GGG Help: nfeltdiv(nf,x,y): element x/y in nf. Doc: given two elements $x$ and $y$ in \var{nf}, computes their quotient $x/y$ in the number field $\var{nf}$. pari-2.11.2/src/functions/number_fields/bnrclassnolist0000644000175000017500000000223712314242551021561 0ustar billbillFunction: bnrclassnolist Section: number_fields C-Name: bnrclassnolist Prototype: GG Help: bnrclassnolist(bnf,list): if list is as output by ideallist or similar, gives list of corresponding ray class numbers. Doc: $\var{bnf}$ being as output by \kbd{bnfinit}, and \var{list} being a list of moduli (with units) as output by \kbd{ideallist} or \kbd{ideallistarch}, outputs the list of the class numbers of the corresponding ray class groups. To compute a single class number, \tet{bnrclassno} is more efficient. \bprog ? bnf = bnfinit(x^2 - 2); ? L = ideallist(bnf, 100, 2); ? H = bnrclassnolist(bnf, L); ? H[98] %4 = [1, 3, 1] ? l = L[1][98]; ids = vector(#l, i, l[i].mod[1]) %5 = [[98, 88; 0, 1], [14, 0; 0, 7], [98, 10; 0, 1]] @eprog The weird \kbd{l[i].mod[1]}, is the first component of \kbd{l[i].mod}, i.e. the finite part of the conductor. (This is cosmetic: since by construction the Archimedean part is trivial, I do not want to see it). This tells us that the ray class groups modulo the ideals of norm 98 (printed as \kbd{\%5}) have respectively order $1$, $3$ and $1$. Indeed, we may check directly: \bprog ? bnrclassno(bnf, ids[2]) %6 = 3 @eprog pari-2.11.2/src/functions/number_fields/rnfinit0000644000175000017500000001224413326135265020200 0ustar billbillFunction: rnfinit Section: number_fields C-Name: rnfinit0 Prototype: GGD0,L, Help: rnfinit(nf,T,{flag=0}): T being an irreducible polynomial defined over the number field nf, initializes a vector of data necessary for working in relative number fields (rnf functions). See manual for technical details. Doc: given an \var{nf} structure attached to a number field $K$, as output by \kbd{nfinit}, and a monic irreducible polynomial $T$ in $K[x]$ defining a relative extension $L = K[x]/(T)$, this computes data to work in $L/K$ The main variable of $T$ must be of higher priority (see \secref{se:priority}) than that of $\var{nf}$, and the coefficients of $T$ must be in $K$. The result is a row vector, whose components are technical. We let $m = [K:\Q]$ the degree of the base field, $n = [L:K]$ the relative degree, $r_1$ and $r_2$ the number of real and complex places of $K$. Access to this information via \emph{member functions} is preferred since the specific data organization specified below will change in the future. If $\fl = 1$, add an \var{nf} structure attached to $L$ to \var{rnf}. This is likely to be very expensive if the absolute degree $mn$ is large, but fixes an integer basis for $\Z_L$ as a $\Z$-module and allows to input and output elements of $L$ in absolute form: as \typ{COL} for elements, as \typ{MAT} in HNF for ideals, as \kbd{prid} for prime ideals. Without such a call, elements of $L$ are represented as \typ{POLMOD}, etc. Note that a subsequent \kbd{nfinit}$(\var{rnf})$ will also explicitly add such a component, and so will the following functions \kbd{rnfidealmul}, \kbd{rnfidealtwoelt}, \kbd{rnfidealprimedec}, \kbd{rnfidealup} (with flag 1) and \kbd{rnfidealreltoabs} (with flag 1). The absolute \var{nf} structure attached to $L$ can be recovered using \kbd{nfinit(rnf)}. $\var{rnf}[1]$(\kbd{rnf.pol}) contains the relative polynomial $T$. $\var{rnf}[2]$ contains the integer basis $[A,d]$ of $K$, as (integral) elements of $L/\Q$. More precisely, $A$ is a vector of polynomial with integer coefficients, $d$ is a denominator, and the integer basis is given by $A/d$. $\var{rnf}[3]$ (\kbd{rnf.disc}) is a two-component row vector $[\goth{d}(L/K),s]$ where $\goth{d}(L/K)$ is the relative ideal discriminant of $L/K$ and $s$ is the discriminant of $L/K$ viewed as an element of $K^*/(K^*)^2$, in other words it is the output of \kbd{rnfdisc}. $\var{rnf}[4]$(\kbd{rnf.index}) is the ideal index $\goth{f}$, i.e.~such that $d(T)\Z_K=\goth{f}^2\goth{d}(L/K)$. $\var{rnf}[5]$ is currently unused. $\var{rnf}[6]$ is currently unused. $\var{rnf}[7]$ (\kbd{rnf.zk}) is the pseudo-basis $(A,I)$ for the maximal order $\Z_L$ as a $\Z_K$-module: $A$ is the relative integral pseudo basis expressed as polynomials (in the variable of $T$) with polmod coefficients in $\var{nf}$, and the second component $I$ is the ideal list of the pseudobasis in HNF. $\var{rnf}[8]$ is the inverse matrix of the integral basis matrix, with coefficients polmods in $\var{nf}$. $\var{rnf}[9]$ is currently unused. $\var{rnf}[10]$ (\kbd{rnf.nf}) is $\var{nf}$. $\var{rnf}[11]$ is an extension of \kbd{rnfequation(K, T, 1)}. Namely, a vector $[P, a, k, \kbd{K.pol}, T]$ describing the \emph{absolute} extension $L/\Q$: $P$ is an absolute equation, more conveniently obtained as \kbd{rnf.polabs}; $a$ expresses the generator $\alpha = y \mod \kbd{K.pol}$ of the number field $K$ as an element of $L$, i.e.~a polynomial modulo the absolute equation $P$; $k$ is a small integer such that, if $\beta$ is an abstract root of $T$ and $\alpha$ the generator of $K$ given above, then $P(\beta + k\alpha) = 0$. It is guaranteed that $k = 0$ if $\Q(\beta) = L$. \misctitle{Caveat} Be careful if $k\neq0$ when dealing simultaneously with absolute and relative quantities since $L = \Q(\beta + k\alpha) = K(\alpha)$, and the generator chosen for the absolute extension is not the same as for the relative one. If this happens, one can of course go on working, but we advise to change the relative polynomial so that its root becomes $\beta + k \alpha$. Typical GP instructions would be \bprog [P,a,k] = rnfequation(K, T, 1); if (k, T = subst(T, x, x - k*Mod(y, K.pol))); L = rnfinit(K, T); @eprog $\var{rnf}[12]$ is by default unused and set equal to 0. This field is used to store further information about the field as it becomes available (which is rarely needed, hence would be too expensive to compute during the initial \kbd{rnfinit} call). \misctitle{Huge discriminants, helping rnfdisc} When $T$ has a discriminant which is difficult to factor, it is hard to compute $\Z_L$. As in \kbd{nfinit}, the special input format $[T,B]$ is also accepted, where $T$ is a polynomial as above and $B$ is an integer. Instead of $\Z_L$, this produces an order which is maximal at all primes less than $B$. The result is actually a complete and correct \var{rnf} structure if all prime divisors of the relative ideal discriminant divide a rational prime less than $B$. In general, the order may not be maximal at primes $\goth{p} | p $ for $p \geq B$ such that $\goth{p}^2$ divides the relative ideal discriminant. Variant: Also available is \fun{GEN}{rnfinit}{GEN nf,GEN T} ($\fl = 0$). pari-2.11.2/src/functions/number_fields/polredord0000644000175000017500000000031613201017466020510 0ustar billbillFunction: polredord Section: number_fields C-Name: polredord Prototype: G Obsolete: 2008-07-20 Help: polredord(x): this function is obsolete, use polredbest. Doc: This function is obsolete, use polredbest. pari-2.11.2/src/functions/number_fields/idealred0000644000175000017500000000541213326135265020277 0ustar billbillFunction: idealred Section: number_fields C-Name: idealred0 Prototype: GGDG Help: idealred(nf,I,{v=0}): LLL reduction of the ideal I in the number field nf along direction v, in HNF. Doc: \idx{LLL} reduction of the ideal $I$ in the number field $K$ attached to \var{nf}, along the direction $v$. The $v$ parameter is best left omitted, but if it is present, it must be an $\kbd{nf.r1} + \kbd{nf.r2}$-component vector of \emph{non-negative} integers. (What counts is the relative magnitude of the entries: if all entries are equal, the effect is the same as if the vector had been omitted.) This function finds an $a\in K^*$ such that $J = (a)I$ is ``small'' and integral (see the end for technical details). The result is the Hermite normal form of the ``reduced'' ideal $J$. \bprog ? K = nfinit(y^2+1); ? P = idealprimedec(K,5)[1]; ? idealred(K, P) %3 = [1 0] [0 1] @eprog\noindent More often than not, a \idx{principal ideal} yields the unit ideal as above. This is a quick and dirty way to check if ideals are principal, but it is not a necessary condition: a non-trivial result does not prove that the ideal is non-principal. For guaranteed results, see \kbd{bnfisprincipal}, which requires the computation of a full \kbd{bnf} structure. If the input is an extended ideal $[I,s]$, the output is $[J, sa]$; in this way, one keeps track of the principal ideal part: \bprog ? idealred(K, [P, 1]) %5 = [[1, 0; 0, 1], [2, -1]~] @eprog\noindent meaning that $P$ is generated by $[2, -1]~$. The number field element in the extended part is an algebraic number in any form \emph{or} a factorization matrix (in terms of number field elements, not ideals!). In the latter case, elements stay in factored form, which is a convenient way to avoid coefficient explosion; see also \tet{idealpow}. \misctitle{Technical note} The routine computes an LLL-reduced basis for the lattice $I^{-1}$ equipped with the quadratic form $$|| x ||_v^2 = \sum_{i=1}^{r_1+r_2} 2^{v_i}\varepsilon_i|\sigma_i(x)|^2,$$ where as usual the $\sigma_i$ are the (real and) complex embeddings and $\varepsilon_i = 1$, resp.~$2$, for a real, resp.~complex place. The element $a$ is simply the first vector in the LLL basis. The only reason you may want to try to change some directions and set some $v_i\neq 0$ is to randomize the elements found for a fixed ideal, which is heuristically useful in index calculus algorithms like \tet{bnfinit} and \tet{bnfisprincipal}. \misctitle{Even more technical note} In fact, the above is a white lie. We do not use $||\cdot||_v$ exactly but a rescaled rounded variant which gets us faster and simpler LLLs. There's no harm since we are not using any theoretical property of $a$ after all, except that it belongs to $I^{-1}$ and that $a I$ is ``expected to be small''. pari-2.11.2/src/functions/number_fields/nfmodprlift0000644000175000017500000000200013326135265021040 0ustar billbillFunction: nfmodprlift Section: number_fields C-Name: nfmodprlift Prototype: GGG Help: nfmodprlift(nf,x,pr): lift x from residue field mod pr to nf. Doc: lift the \typ{FFELT} $x$ (from \tet{nfmodpr}) in the residue field modulo \var{pr} to the ring of integers. Vectors and matrices are also supported. For polynomials, use \kbd{apply} and the present function. The argument \var{pr} is either a maximal ideal in \kbd{idealprimedec} format or, preferably, a \var{modpr} structure from \tet{nfmodprinit}. There are no compatibility checks to try and decide whether $x$ is attached the same residue field as defined by \var{pr}: the result is undefined if not. The function \tet{nfmodpr} allows to reduce to the residue field. \bprog ? K = nfinit(y^3-250); ? P = idealprimedec(K, 5)[2]; ? modP = nfmodprinit(K,P); ? K.zk %4 = [1, 1/5*y, 1/25*y^2] ? apply(t->nfmodpr(K,t,modP), K.zk) %5 = [1, y, 2*y + 1] ? nfmodprlift(K, %, modP) %6 = [1, 1/5*y, 2/5*y + 1] ? nfeltval(K, %[3] - K.zk[3], P) %7 = 1 @eprog pari-2.11.2/src/functions/number_fields/polcompositum0000644000175000017500000000765113201017466021441 0ustar billbillFunction: polcompositum Section: number_fields C-Name: polcompositum0 Prototype: GGD0,L, Help: polcompositum(P,Q,{flag=0}): vector of all possible compositums of the number fields defined by the polynomials P and Q; flag is optional, whose binary digits mean 1: output for each compositum, not only the compositum polynomial pol, but a vector [R,a,b,k] where a (resp. b) is a root of P (resp. Q) expressed as a polynomial modulo R, and a small integer k such that al2+k*al1 is the chosen root of R; 2: assume that the number fields defined by P and Q are linearly disjoint. Doc: \sidx{compositum} $P$ and $Q$ being squarefree polynomials in $\Z[X]$ in the same variable, outputs the simple factors of the \'etale $\Q$-algebra $A = \Q(X, Y) / (P(X), Q(Y))$. The factors are given by a list of polynomials $R$ in $\Z[X]$, attached to the number field $\Q(X)/ (R)$, and sorted by increasing degree (with respect to lexicographic ordering for factors of equal degrees). Returns an error if one of the polynomials is not squarefree. Note that it is more efficient to reduce to the case where $P$ and $Q$ are irreducible first. The routine will not perform this for you, since it may be expensive, and the inputs are irreducible in most applications anyway. In this case, there will be a single factor $R$ if and only if the number fields defined by $P$ and $Q$ are linearly disjoint (their intersection is $\Q$). Assuming $P$ is irreducible (of smaller degree than $Q$ for efficiency), it is in general much faster to proceed as follows \bprog nf = nfinit(P); L = nffactor(nf, Q)[,1]; vector(#L, i, rnfequation(nf, L[i])) @eprog\noindent to obtain the same result. If you are only interested in the degrees of the simple factors, the \kbd{rnfequation} instruction can be replaced by a trivial \kbd{poldegree(P) * poldegree(L[i])}. The binary digits of $\fl$ mean 1: outputs a vector of 4-component vectors $[R,a,b,k]$, where $R$ ranges through the list of all possible compositums as above, and $a$ (resp. $b$) expresses the root of $P$ (resp. $Q$) as an element of $\Q(X)/(R)$. Finally, $k$ is a small integer such that $b + ka = X$ modulo $R$. 2: assume that $P$ and $Q$ define number fields which are linearly disjoint: both polynomials are irreducible and the corresponding number fields have no common subfield besides $\Q$. This allows to save a costly factorization over $\Q$. In this case return the single simple factor instead of a vector with one element. A compositum is often defined by a complicated polynomial, which it is advisable to reduce before further work. Here is an example involving the field $\Q(\zeta_5, 5^{1/5})$: \bprog ? L = polcompositum(x^5 - 5, polcyclo(5), 1); \\@com list of $[R,a,b,k]$ ? [R, a] = L[1]; \\@com pick the single factor, extract $R,a$ (ignore $b,k$) ? R \\@com defines the compositum %3 = x^20 + 5*x^19 + 15*x^18 + 35*x^17 + 70*x^16 + 141*x^15 + 260*x^14\ + 355*x^13 + 95*x^12 - 1460*x^11 - 3279*x^10 - 3660*x^9 - 2005*x^8 \ + 705*x^7 + 9210*x^6 + 13506*x^5 + 7145*x^4 - 2740*x^3 + 1040*x^2 \ - 320*x + 256 ? a^5 - 5 \\@com a fifth root of $5$ %4 = 0 ? [T, X] = polredbest(R, 1); ? T \\@com simpler defining polynomial for $\Q[x]/(R)$ %6 = x^20 + 25*x^10 + 5 ? X \\ @com root of $R$ in $\Q[y]/(T(y))$ %7 = Mod(-1/11*x^15 - 1/11*x^14 + 1/22*x^10 - 47/22*x^5 - 29/11*x^4 + 7/22,\ x^20 + 25*x^10 + 5) ? a = subst(a.pol, 'x, X) \\@com \kbd{a} in the new coordinates %8 = Mod(1/11*x^14 + 29/11*x^4, x^20 + 25*x^10 + 5) ? a^5 - 5 %9 = 0 @eprog\noindent In the above example, $x^5-5$ and the $5$-th cyclotomic polynomial are irreducible over $\Q$; they have coprime degrees so define linearly disjoint extensions and we could have started by \bprog ? [R,a] = polcompositum(x^5 - 5, polcyclo(5), 3); \\@com $[R,a,b,k]$ @eprog Variant: Also available are \fun{GEN}{compositum}{GEN P, GEN Q} ($\fl = 0$) and \fun{GEN}{compositum2}{GEN P, GEN Q} ($\fl = 1$). pari-2.11.2/src/functions/number_fields/rnfisnorminit0000644000175000017500000000204411636712103021417 0ustar billbillFunction: rnfisnorminit Section: number_fields C-Name: rnfisnorminit Prototype: GGD2,L, Help: rnfisnorminit(pol,polrel,{flag=2}): let K be defined by a root of pol, L/K the extension defined by polrel. Compute technical data needed by rnfisnorm to solve norm equations Nx = a, for x in L, and a in K. If flag=0, do not care whether L/K is Galois or not; if flag = 1, assume L/K is Galois; if flag = 2, determine whether L/K is Galois. Doc: let $K$ be defined by a root of \var{pol}, and $L/K$ the extension defined by the polynomial \var{polrel}. As usual, \var{pol} can in fact be an \var{nf}, or \var{bnf}, etc; if \var{pol} has degree $1$ (the base field is $\Q$), polrel is also allowed to be an \var{nf}, etc. Computes technical data needed by \tet{rnfisnorm} to solve norm equations $Nx = a$, for $x$ in $L$, and $a$ in $K$. If $\fl = 0$, do not care whether $L/K$ is Galois or not. If $\fl = 1$, $L/K$ is assumed to be Galois (unchecked), which speeds up \tet{rnfisnorm}. If $\fl = 2$, let the routine determine whether $L/K$ is Galois. pari-2.11.2/src/functions/number_fields/galoisfixedfield0000644000175000017500000000372513326135265022035 0ustar billbillFunction: galoisfixedfield Section: number_fields C-Name: galoisfixedfield Prototype: GGD0,L,Dn Help: galoisfixedfield(gal,perm,{flag},{v=y}): gal being a Galois group as output by galoisinit and perm a subgroup, an element of gal.group or a vector of such elements, return [P,x] such that P is a polynomial defining the fixed field of gal[1] by the subgroup generated by perm, and x is a root of P in gal expressed as a polmod in gal.pol. If flag is 1 return only P. If flag is 2 return [P,x,F] where F is the factorization of gal.pol over the field defined by P, where the variable v stands for a root of P. Description: (gen, gen, ?small, ?var):vec galoisfixedfield($1, $2, $3, $4) Doc: \var{gal} being be a Galois group as output by \tet{galoisinit} and \var{perm} an element of $\var{gal}.group$, a vector of such elements or a subgroup of \var{gal} as returned by galoissubgroups, computes the fixed field of \var{gal} by the automorphism defined by the permutations \var{perm} of the roots $\var{gal}.roots$. $P$ is guaranteed to be squarefree modulo $\var{gal}.p$. If no flags or $\fl=0$, output format is the same as for \tet{nfsubfield}, returning $[P,x]$ such that $P$ is a polynomial defining the fixed field, and $x$ is a root of $P$ expressed as a polmod in $\var{gal}.pol$. If $\fl=1$ return only the polynomial $P$. If $\fl=2$ return $[P,x,F]$ where $P$ and $x$ are as above and $F$ is the factorization of $\var{gal}.pol$ over the field defined by $P$, where variable $v$ ($y$ by default) stands for a root of $P$. The priority of $v$ must be less than the priority of the variable of $\var{gal}.pol$ (see \secref{se:priority}). In this case, $P$ is also expressed in the variable $v$ for compatibility with $F$. Example: \bprog ? G = galoisinit(x^4+1); ? galoisfixedfield(G,G.group[2],2) %2 = [y^2 - 2, Mod(- x^3 + x, x^4 + 1), [x^2 - y*x + 1, x^2 + y*x + 1]] @eprog\noindent computes the factorization $x^4+1=(x^2-\sqrt{2}x+1)(x^2+\sqrt{2}x+1)$ pari-2.11.2/src/functions/number_fields/nfsnf0000644000175000017500000000261513201017466017634 0ustar billbillFunction: nfsnf Section: number_fields C-Name: nfsnf0 Prototype: GGD0,L, Help: nfsnf(nf,x,{flag=0}): if x=[A,I,J], outputs D=[d_1,...d_n] Smith normal form of x. If flag is non-zero return [D,U,V], where UAV = Id. Doc: given a torsion $\Z_K$-module $x$ attached to the square integral invertible pseudo-matrix $(A,I,J)$, returns an ideal list $D=[d_1,\dots,d_n]$ which is the \idx{Smith normal form} of $x$. In other words, $x$ is isomorphic to $\Z_K/d_1\oplus\cdots\oplus\Z_K/d_n$ and $d_i$ divides $d_{i-1}$ for $i\ge2$. If $\fl$ is non-zero return $[D,U,V]$, where $UAV$ is the identity. See \secref{se:ZKmodules} for the definition of integral pseudo-matrix; briefly, it is input as a 3-component row vector $[A,I,J]$ where $I = [b_1,\dots,b_n]$ and $J = [a_1,\dots,a_n]$ are two ideal lists, and $A$ is a square $n\times n$ matrix with columns $(A_1,\dots,A_n)$, seen as elements in $K^n$ (with canonical basis $(e_1,\dots,e_n)$). This data defines the $\Z_K$ module $x$ given by $$ (b_1e_1\oplus\cdots\oplus b_ne_n) / (a_1A_1\oplus\cdots\oplus a_nA_n) \enspace, $$ The integrality condition is $a_{i,j} \in b_i a_j^{-1}$ for all $i,j$. If it is not satisfied, then the $d_i$ will not be integral. Note that every finitely generated torsion module is isomorphic to a module of this form and even with $b_i=Z_K$ for all $i$. Variant: Also available: \fun{GEN}{nfsnf}{GEN nf, GEN x} ($\fl = 0$). pari-2.11.2/src/functions/number_fields/nfeltdiveuc0000644000175000017500000000062613201017466021032 0ustar billbillFunction: nfeltdiveuc Section: number_fields C-Name: nfdiveuc Prototype: GGG Help: nfeltdiveuc(nf,x,y): gives algebraic integer q such that x-qy is small. Doc: given two elements $x$ and $y$ in \var{nf}, computes an algebraic integer $q$ in the number field $\var{nf}$ such that the components of $x-qy$ are reasonably small. In fact, this is functionally identical to \kbd{round(nfdiv(\var{nf},x,y))}. pari-2.11.2/src/functions/number_fields/rnfconductor0000644000175000017500000000260413326135265021234 0ustar billbillFunction: rnfconductor Section: number_fields C-Name: rnfconductor Prototype: GG Help: rnfconductor(bnf,T): conductor of the Abelian extension of bnf defined by T. The result is [conductor,bnr,subgroup], where conductor is the conductor itself, bnr the attached bnr structure, and subgroup the HNF defining the norm group (Artin or Takagi group) on the given generators bnr.gen. Doc: given a \var{bnf} structure attached to a number field $K$, as produced by \kbd{bnfinit}, and $T$ a monic irreducible polynomial in $K[x]$ defining an \idx{Abelian extension} $L = K[x]/(T)$, computes the class field theory conductor of this Abelian extension. The result is a 3-component vector $[\var{conductor},\var{bnr},\var{subgroup}]$, where \var{conductor} is the conductor of the extension given as a 2-component row vector $[f_0,f_\infty]$, \var{bnr} is the attached \kbd{bnr} structure and \var{subgroup} is a matrix in HNF defining the subgroup of the ray class group on the ray class group generators \kbd{bnr.gen}. \misctitle{Huge discriminants, helping rnfdisc} the format $[T,B]$ is also accepted instead of $T$ and computes the conductor of the extension provided it factors completely over prime divisors of rational primes $p < B$, see \kbd{??rnfinit}: the valuation of $f_0$ is then correct at all prime ideals $\goth{p}$ above a rational prime $p < B$ but may be incorrect at other primes. pari-2.11.2/src/functions/number_fields/idealredmodpower0000644000175000017500000000274013326135265022055 0ustar billbillFunction: idealredmodpower Section: number_fields C-Name: idealredmodpower Prototype: GGUD0,U, Help: idealredmodpower(nf,x,n,{B=primelimit}): return b such that x * b^n = v is small. Doc: let \var{nf} be a number field, $x$ an ideal in \var{nf} and $n > 0$ be a positive integer. Return a number field element $b$ such that $x b^n = v$ is small. If $x$ is integral, then $v$ is also integral. More precisely, \kbd{idealnumden} reduces the problem to $x$ integral. Then, factoring out the prime ideals dividing a rational prime $p \leq B$, we rewrite $x = I J^n$ where the ideals $I$ and $J$ are both integral and $I$ is $B$-smooth. Then we return a small element $b$ in $J^{-1}$. The bound $B$ avoids a costly complete factorization of $x$; as soon as the $n$-core of $x$ is $B$-smooth (i.e., as soon as $I$ is $n$-power free), then $J$ is as large as possible and so is the expected reduction. \bprog ? T = x^6+108; nf = nfinit(T); a = Mod(x,T); ? setrand(1); u = (2*a^2+a+3)*random(2^1000*x^6)^6; ? sizebyte(u) %3 = 4864 ? b = idealredmodpower(nf,u,2); ? v2 = nfeltmul(nf,u, nfeltpow(nf,b,2)) %5 = [34, 47, 15, 35, 9, 3]~ ? b = idealredmodpower(nf,u,6); ? v6 = nfeltmul(nf,u, nfeltpow(nf,b,6)) %7 = [3, 0, 2, 6, -7, 1]~ @eprog\noindent The last element \kbd{v6}, obtained by reducing modulo $6$-th powers instead of squares, looks smaller than \kbd{v2} but its norm is actually a little larger: \bprog ? idealnorm(nf,v2) %8 = 81309 ? idealnorm(nf,v6) %9 = 731781 @eprog pari-2.11.2/src/functions/number_fields/polred0000644000175000017500000000347213326135265020017 0ustar billbillFunction: polred Section: number_fields C-Name: polred0 Prototype: GD0,L,DG Obsolete: 2013-03-27 Help: polred(T,{flag=0}): deprecated, use polredbest. Reduction of the polynomial T (gives minimal polynomials only). The following binary digits of (optional) flag are significant 1: partial reduction, 2: gives also elements. Doc: This function is \emph{deprecated}, use \tet{polredbest} instead. Finds polynomials with reasonably small coefficients defining subfields of the number field defined by $T$. One of the polynomials always defines $\Q$ (hence has degree $1$), and another always defines the same number field as $T$ if $T$ is irreducible. All $T$ accepted by \tet{nfinit} are also allowed here; in particular, the format \kbd{[T, listP]} is recommended, e.g. with $\kbd{listP} = 10^5$ or a vector containing all ramified primes. Otherwise, the maximal order of $\Q[x]/(T)$ must be computed. The following binary digits of $\fl$ are significant: 1: Possibly use a suborder of the maximal order. The primes dividing the index of the order chosen are larger than \tet{primelimit} or divide integers stored in the \tet{addprimes} table. This flag is \emph{deprecated}, the \kbd{[T, listP]} format is more flexible. 2: gives also elements. The result is a two-column matrix, the first column giving primitive elements defining these subfields, the second giving the corresponding minimal polynomials. \bprog ? M = polred(x^4 + 8, 2) %1 = [ 1 x - 1] [ 1/2*x^2 + 1 x^2 - 2*x + 3] [-1/2*x^2 + 1 x^2 - 2*x + 3] [ 1/2*x^2 x^2 + 2] [ 1/4*x^3 x^4 + 2] ? minpoly(Mod(M[2,1], x^4+8)) %2 = x^2 + 2 @eprog \synt{polred}{GEN T} ($\fl = 0$). Also available is \fun{GEN}{polred2}{GEN T} ($\fl = 2$). The function \kbd{polred0} is deprecated, provided for backward compatibility. pari-2.11.2/src/functions/number_fields/newtonpoly0000644000175000017500000000073613201017466020742 0ustar billbillFunction: newtonpoly Section: number_fields C-Name: newtonpoly Prototype: GG Help: newtonpoly(x,p): Newton polygon of polynomial x with respect to the prime p. Doc: gives the vector of the slopes of the Newton polygon of the polynomial $x$ with respect to the prime number $p$. The $n$ components of the vector are in decreasing order, where $n$ is equal to the degree of $x$. Vertical slopes occur iff the constant coefficient of $x$ is zero and are denoted by \kbd{+oo}. pari-2.11.2/src/functions/number_fields/nfpolsturm0000644000175000017500000000262513326135265020742 0ustar billbillFunction: nfpolsturm Section: number_fields C-Name: nfpolsturm Prototype: GGDG Help: nfpolsturm(nf, T, {pl}): number of distinct real roots of the polynomial s(T) where s runs through the real embeddings given by vector pl. Doc: given a polynomial $T$ with coefficients in the number field \var{nf}, returns the number of real roots of the $s(T)$ where $s$ runs through the real embeddings of the field specified by optional argument \var{pl}: \item \var{pl} omitted: all $r_1$ real places; \item \var{pl} an integer between $1$ and $r_1$: the embedding attached to the $i$-th real root of \kbd{nf.pol}, i.e. \kbd{nf.roots$[i]$}; \item \var{pl} a vector or \typ{VECSMALL}: the embeddings attached to the $\var{pl}[i]$-th real roots of \kbd{nf.pol}. \bprog ? nf = nfinit('y^2 - 2); ? nf.sign %2 = [2, 0] ? nf.roots %3 = [-1.414..., 1.414...] ? T = x^2 + 'y; ? nfpolsturm(nf, T, 1) \\ subst(T,y,sqrt(2)) has two real roots %5 = 2 ? nfpolsturm(nf, T, 2) \\ subst(T,y,-sqrt(2)) has no real root %6 = 0 ? nfpolsturm(nf, T) \\ all embeddings together %7 = [2, 0] ? nfpolsturm(nf, T, [2,1]) \\ second then first embedding %8 = [0, 2] ? nfpolsturm(nf, x^3) \\ number of distinct roots ! %9 = [1, 1] ? nfpolsturm(nf, x, 6) \\ there are only 2 real embeddings ! *** at top-level: nfpolsturm(nf,x,6) *** ^----------------- *** nfpolsturm: domain error in nfpolsturm: index > 2 @eprog pari-2.11.2/src/functions/number_fields/rnfalgtobasis0000644000175000017500000000074111636712103021356 0ustar billbillFunction: rnfalgtobasis Section: number_fields C-Name: rnfalgtobasis Prototype: GG Help: rnfalgtobasis(rnf,x): relative version of nfalgtobasis, where rnf is a relative numberfield. Doc: expresses $x$ on the relative integral basis. Here, $\var{rnf}$ is a relative number field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an element of $L$ in absolute form, i.e. expressed as a polynomial or polmod with polmod coefficients, \emph{not} on the relative integral basis. pari-2.11.2/src/functions/number_fields/nfdetint0000644000175000017500000000052611636712103020334 0ustar billbillFunction: nfdetint Section: number_fields C-Name: nfdetint Prototype: GG Help: nfdetint(nf,x): multiple of the ideal determinant of the pseudo generating set x. Doc: given a pseudo-matrix $x$, computes a non-zero ideal contained in (i.e.~multiple of) the determinant of $x$. This is particularly useful in conjunction with \kbd{nfhnfmod}. pari-2.11.2/src/functions/gp2c/0000755000175000017500000000000013461316051014610 5ustar billbillpari-2.11.2/src/functions/gp2c/unclone0000644000175000017500000000015411636712103016176 0ustar billbillFunction: unclone Class: gp2c Description: (small):void (void)0 /*unclone*/ (gen):void gunclone($1) pari-2.11.2/src/functions/gp2c/DEBUGLEVEL0000644000175000017500000000017312314242551016151 0ustar billbillFunction: DEBUGLEVEL C-Name: DEBUGLEVEL Prototype: v Class: gp2c Description: ():small DEBUGLEVEL pari-2.11.2/src/functions/gp2c/clone0000644000175000017500000000102013201017466015624 0ustar billbillFunction: clone Class: gp2c Description: (small):small:parens $1 (int):int gclone($1) (real):real gclone($1) (mp):mp gclone($1) (vecsmall):vecsmall gclone($1) (vec):vec gclone($1) (pol):pol gclone($1) (list):list gclone($1) (closure):closure gclone($1) (genstr):genstr gclone($1) (gen):gen gclone($1) pari-2.11.2/src/functions/gp2c/copy0000644000175000017500000000066013326135265015515 0ustar billbillFunction: copy Class: gp2c Description: (small):small:parens $1 (int):int icopy($1) (real):real gcopy($1) (mp):mp gcopy($1) (vecsmall):vecsmall gcopy($1) (vec):vec gcopy($1) (pol):pol gcopy($1) (list):list listinit($1) (gen):gen gcopy($1) pari-2.11.2/src/functions/programming/0000755000175000017500000000000013461316051016277 5ustar billbillpari-2.11.2/src/functions/programming/addhelp0000644000175000017500000000212613036414402017621 0ustar billbillFunction: addhelp Section: programming/specific C-Name: addhelp Prototype: vrs Help: addhelp(sym,str): add/change help message for the symbol sym. Doc: changes the help message for the symbol \kbd{sym}. The string \var{str} is expanded on the spot and stored as the online help for \kbd{sym}. It is recommended to document global variables and user functions in this way, although \kbd{gp} will not protest if you don't. You can attach a help text to an alias, but it will never be shown: aliases are expanded by the \kbd{?} help operator and we get the help of the symbol the alias points to. Nothing prevents you from modifying the help of built-in PARI functions. But if you do, we would like to hear why you needed it! Without \tet{addhelp}, the standard help for user functions consists of its name and definition. \bprog gp> f(x) = x^2; gp> ?f f = (x)->x^2 @eprog\noindent Once addhelp is applied to $f$, the function code is no longer included. It can still be consulted by typing the function name: \bprog gp> addhelp(f, "Square") gp> ?f Square gp> f %2 = (x)->x^2 @eprog pari-2.11.2/src/functions/programming/type0000644000175000017500000000114011636712103017177 0ustar billbillFunction: type Section: programming/specific C-Name: type0 Prototype: G Help: type(x): return the type of the GEN x. Description: (gen):typ typ($1) Doc: this is useful only under \kbd{gp}. Returns the internal type name of the PARI object $x$ as a string. Check out existing type names with the metacommand \b{t}. For example \kbd{type(1)} will return "\typ{INT}". Variant: The macro \kbd{typ} is usually simpler to use since it returns a \kbd{long} that can easily be matched with the symbols \typ{*}. The name \kbd{type} was avoided since it is a reserved identifier for some compilers. pari-2.11.2/src/functions/programming/read0000644000175000017500000000206013326135265017141 0ustar billbillFunction: read Section: programming/specific C-Name: gp_read_file Prototype: D"",s, Help: read({filename}): read from the input file filename. If filename is omitted, reread last input file, be it from read() or \r. Description: (str):gen gp_read_file($1) Doc: reads in the file \var{filename} (subject to string expansion). If \var{filename} is omitted, re-reads the last file that was fed into \kbd{gp}. The return value is the result of the last expression evaluated. If a GP \tet{binary file} is read using this command (see \secref{se:writebin}), the file is loaded and the last object in the file is returned. In case the file you read in contains an \tet{allocatemem} statement (to be generally avoided), you should leave \kbd{read} instructions by themselves, and not part of larger instruction sequences. \misctitle{Variants} \kbd{readvec} allows to read a whole file at once; \kbd{fileopen} followed by either \kbd{fileread} (evaluated lines) or \kbd{filereadstr} (lines as non-evaluated strings) allows to read a file one line at a time. pari-2.11.2/src/functions/programming/for0000644000175000017500000000076313201017466017016 0ustar billbillFunction: for Section: programming/control C-Name: forpari Prototype: vV=GGI Help: for(X=a,b,seq): the sequence is evaluated, X going from a up to b. If b is set to +oo, the loop will not stop. Doc: evaluates \var{seq}, where the formal variable $X$ goes from $a$ to $b$. Nothing is done if $a>b$. $a$ and $b$ must be in $\R$. If $b$ is set to \kbd{+oo}, the loop will not stop; it is expected that the caller will break out of the loop itself at some point, using \kbd{break} or \kbd{return}. pari-2.11.2/src/functions/programming/listpop0000644000175000017500000000102513201017466017712 0ustar billbillFunction: listpop Section: programming/specific C-Name: listpop0 Prototype: vWD0,L, Help: listpop(list,{n}): removes n-th element from list. If n is omitted or greater than the current list length, removes last element. Description: (list, small):void listpop($1, $2) Doc: removes the $n$-th element of the list \var{list} (which must be of type \typ{LIST}). If $n$ is omitted, or greater than the list current length, removes the last element. If the list is already empty, do nothing. This runs in time $O(\#L - n + 1)$. pari-2.11.2/src/functions/programming/default0000644000175000017500000000340313201017466017646 0ustar billbillFunction: default Section: programming/specific C-Name: default0 Prototype: DrDs Help: default({key},{val}): returns the current value of the default key. If val is present, set opt to val first. If no argument is given, print a list of all defaults as well as their values. Description: ("realprecision"):small:prec getrealprecision() ("realprecision",small):small:prec setrealprecision($2, &$prec) ("seriesprecision"):small precdl ("seriesprecision",small):small:parens precdl = $2 ("debug"):small DEBUGLEVEL ("debug",small):small:parens DEBUGLEVEL = $2 ("debugmem"):small DEBUGMEM ("debugmem",small):small:parens DEBUGMEM = $2 ("debugfiles"):small DEBUGFILES ("debugfiles",small):small:parens DEBUGFILES = $2 ("factor_add_primes"):small factor_add_primes ("factor_add_primes",small):small factor_add_primes = $2 ("factor_proven"):small factor_proven ("factor_proven",small):small factor_proven = $2 ("new_galois_format"):small new_galois_format ("new_galois_format",small):small new_galois_format = $2 Doc: returns the default corresponding to keyword \var{key}. If \var{val} is present, sets the default to \var{val} first (which is subject to string expansion first). Typing \kbd{default()} (or \b{d}) yields the complete default list as well as their current values. See \secref{se:defaults} for an introduction to GP defaults, \secref{se:gp_defaults} for a list of available defaults, and \secref{se:meta} for some shortcut alternatives. Note that the shortcuts are meant for interactive use and usually display more information than \kbd{default}. pari-2.11.2/src/functions/programming/self0000644000175000017500000000056713201017466017163 0ustar billbillFunction: self Section: programming/specific C-Name: pari_self Prototype: m Help: self(): return the calling function or closure. Useful for defining anonymous recursive functions. Doc: return the calling function or closure as a \typ{CLOSURE} object. This is useful for defining anonymous recursive functions. \bprog ? (n->if(n==0,1,n*self()(n-1)))(5) %1 = 120 @eprog pari-2.11.2/src/functions/programming/errname0000644000175000017500000000036312314242551017654 0ustar billbillFunction: errname Section: programming/specific C-Name: errname Prototype: G Help: errname(E): returns the type of the error message E. Doc: returns the type of the error message \kbd{E} as a string. Description: (gen):errtyp err_get_num($1) pari-2.11.2/src/functions/programming/listcreate0000644000175000017500000000062013201017466020357 0ustar billbillFunction: listcreate Section: programming/specific C-Name: listcreate_gp Prototype: D0,L, Obsolete: 2007-08-10 Help: listcreate({n}): this function is obsolete, use List(). Description: (?gen):list mklist() Doc: This function is obsolete, use \kbd{List}. Creates an empty list. This routine used to have a mandatory argument, which is now ignored (for backward compatibility). % \syn{NO} pari-2.11.2/src/functions/programming/mapput0000644000175000017500000000071113201017466017527 0ustar billbillFunction: mapput Section: programming/specific C-Name: mapput Prototype: vWGG Help: mapput(M,x,y): associates x to y in the map M. Doc: Associates $x$ to $y$ in the map $M$. The value $y$ can be retrieved with \tet{mapget}. \bprog ? M = Map(); ? mapput(M, "foo", 23); ? mapput(M, 7718, "bill"); ? mapget(M, "foo") %4 = 23 ? mapget(M, 7718) %5 = "bill" ? Vec(M) \\ keys %6 = [7718, "foo"] ? Mat(M) %7 = [ 7718 "bill"] ["foo" 23] @eprog pari-2.11.2/src/functions/programming/printsep0000644000175000017500000000071313326135265020075 0ustar billbillFunction: printsep Section: programming/specific C-Name: printsep Prototype: vss* Help: printsep(sep,{str}*): outputs its string arguments (in raw format), separated by 'sep', ending with a newline. Doc: outputs its arguments in raw format, ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. Successive entries are separated by \var{sep}: \bprog ? printsep(":", 1,2,3,4) 1:2:3:4 @eprog %\syn{NO} pari-2.11.2/src/functions/programming/next0000644000175000017500000000101111636712103017171 0ustar billbillFunction: next Section: programming/control C-Name: next0 Prototype: D1,L, Help: next({n=1}): interrupt execution of current instruction sequence, and start another iteration from the n-th innermost enclosing loops. Doc: interrupts execution of current $seq$, resume the next iteration of the innermost enclosing loop, within the current function call (or top level loop). If $n$ is specified, resume at the $n$-th enclosing loop. If $n$ is bigger than the number of enclosing loops, all enclosing loops are exited. pari-2.11.2/src/functions/programming/_eval_mnemonic0000644000175000017500000000021011636712103021166 0ustar billbillFunction: _eval_mnemonic C-Name: eval_mnemonic Section: programming/internals Prototype: lGs Help: Convert a mnemonic string to a flag. pari-2.11.2/src/functions/programming/setrand0000644000175000017500000000223313326135265017670 0ustar billbillFunction: setrand Section: programming/specific C-Name: setrand Prototype: vG Help: setrand(n): reset the seed of the random number generator to n. Doc: reseeds the random number generator using the seed $n$. No value is returned. The seed is a small positive integer $0 < n < 2^{64}$ used to generate deterministically a suitable state array. All gp session start by an implicit \kbd{setrand(1)}, so resetting the seed to this value allows to replay all computations since the session start. Alternatively, running a randomized computation starting by \kbd{setrand}($n$) twice with the same $n$ will generate the exact same output. In the other direction, including a call to \kbd{setrand(getwalltime())} from your gprc will cause GP to produce different streams of random numbers in each session. (Unix users may want to use \kbd{/dev/urandom} instead of \kbd{getwalltime}.) For debugging purposes, one can also record a particular random state using \kbd{getrand} (the value is encoded as a huge integer) and feed it to \kbd{setrand}: \bprog ? state = getrand(); \\ record seed ... ? setrand(state); \\ we can now replay the exact same computations @eprog pari-2.11.2/src/functions/programming/printsep10000644000175000017500000000075313326135265020162 0ustar billbillFunction: printsep1 Section: programming/specific C-Name: printsep1 Prototype: vss* Help: printsep1(sep,{str}*): outputs its string arguments (in raw format), separated by 'sep', without ending with a newline. Doc: outputs its arguments in raw format, without ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. Successive entries are separated by \var{sep}: \bprog ? printsep1(":", 1,2,3,4);print("|") 1:2:3:4| @eprog %\syn{NO} pari-2.11.2/src/functions/programming/parvector0000644000175000017500000000135013036414402020223 0ustar billbillFunction: parvector Section: programming/parallel C-Name: parvector Prototype: LVJ Description: (small,,closure):vec parvector($1, $3) Help: parvector(N,i,expr): as vector(N,i,expr) but the evaluations of expr are done in parallel. Doc: As \kbd{vector(N,i,expr)} but the evaluations of \kbd{expr} are done in parallel. The expression \kbd{expr} must not access global variables or variables declared with \kbd{local()}, and must be free of side effects. \bprog parvector(10,i,quadclassunit(2^(100+i)+1).no) @eprog\noindent computes the class numbers in parallel. %\syn{NO} Function: _parvector_worker Section: programming/internals C-Name: parvector_worker Prototype: GG Help: _parvector_worker(i,C): evaluate the closure C on i. pari-2.11.2/src/functions/programming/input0000644000175000017500000000135213201017466017362 0ustar billbillFunction: input Section: programming/specific C-Name: gp_input Prototype: Help: input(): read an expression from the input file or standard input. Doc: reads a string, interpreted as a GP expression, from the input file, usually standard input (i.e.~the keyboard). If a sequence of expressions is given, the result is the result of the last expression of the sequence. When using this instruction, it is useful to prompt for the string by using the \kbd{print1} function. Note that in the present version 2.19 of \kbd{pari.el}, when using \kbd{gp} under GNU Emacs (see \secref{se:emacs}) one \emph{must} prompt for the string, with a string which ends with the same prompt as any of the previous ones (a \kbd{"? "} will do for instance). pari-2.11.2/src/functions/programming/fold0000644000175000017500000000132213201017466017144 0ustar billbillFunction: fold Section: programming/specific C-Name: fold0 Prototype: GG Help: fold(f, A): return f(...f(f(A[1],A[2]),A[3]),...,A[#A]). Wrapper: (GG) Description: (closure,gen):gen genfold(${1 cookie}, ${1 wrapper}, $2) Doc: Apply the \typ{CLOSURE} \kbd{f} of arity $2$ to the entries of \kbd{A}, in order to return \kbd{f(\dots f(f(A[1],A[2]),A[3])\dots ,A[\#A])}. \bprog ? fold((x,y)->x*y, [1,2,3,4]) %1 = 24 ? fold((x,y)->[x,y], [1,2,3,4]) %2 = [[[1, 2], 3], 4] ? fold((x,f)->f(x), [2,sqr,sqr,sqr]) %3 = 256 ? fold((x,y)->(x+y)/(1-x*y),[1..5]) %4 = -9/19 ? bestappr(tan(sum(i=1,5,atan(i)))) %5 = -9/19 @eprog Variant: Also available is \fun{GEN}{genfold}{void *E, GEN (*fun)(void*,GEN, GEN), GEN A}. pari-2.11.2/src/functions/programming/print0000644000175000017500000000102613326135265017363 0ustar billbillFunction: print Section: programming/specific C-Name: print Prototype: vs* Help: print({str}*): outputs its string arguments (in raw format) ending with a newline. Description: (?gen,...):void pari_printf("${2 format_string}\n"${2 format_args}) Doc: outputs its arguments in raw format ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. \bprog ? m = matid(2); ? print(m) \\ raw format [1, 0; 0, 1] ? printp(m) \\ prettymatrix format [1 0] [0 1] @eprog %\syn{NO} pari-2.11.2/src/functions/programming/parselect0000644000175000017500000000136713326135265020221 0ustar billbillFunction: parselect Section: programming/parallel C-Name: parselect Prototype: GGD0,L, Help: parselect(f, A, {flag = 0}): (parallel select) selects elements of A according to the selection function f which is tested in parallel. If flag is 1, return the indices of those elements (indirect selection). Doc: selects elements of $A$ according to the selection function $f$, done in parallel. If \fl is $1$, return the indices of those elements (indirect selection) The function \kbd{f} must not access global variables or variables declared with local(), and must be free of side effects. Function: _parselect_worker Section: programming/internals C-Name: parselect_worker Prototype: GG Help: _parselect_worker(d,C): evaluate the boolean closure C on d. pari-2.11.2/src/functions/programming/writebin0000644000175000017500000000366513201017466020057 0ustar billbillFunction: writebin Section: programming/specific C-Name: gpwritebin Prototype: vsDG Help: writebin(filename,{x}): write x as a binary object to file filename. If x is omitted, write all session variables. Doc: writes (appends) to \var{filename} the object $x$ in binary format. This format is not human readable, but contains the exact internal structure of $x$, and is much faster to save/load than a string expression, as would be produced by \tet{write}. The binary file format includes a magic number, so that such a file can be recognized and correctly input by the regular \tet{read} or \b{r} function. If saved objects refer to polynomial variables that are not defined in the new session, they will be displayed as \kbd{t$n$} for some integer $n$ (the attached variable number). Installed functions and history objects can not be saved via this function. If $x$ is omitted, saves all user variables from the session, together with their names. Reading such a ``named object'' back in a \kbd{gp} session will set the corresponding user variable to the saved value. E.g after \bprog x = 1; writebin("log") @eprog\noindent reading \kbd{log} into a clean session will set \kbd{x} to $1$. The relative variables priorities (see \secref{se:priority}) of new variables set in this way remain the same (preset variables retain their former priority, but are set to the new value). In particular, reading such a session log into a clean session will restore all variables exactly as they were in the original one. Just as a regular input file, a binary file can be compressed using \tet{gzip}, provided the file name has the standard \kbd{.gz} extension.\sidx{binary file} In the present implementation, the binary files are architecture dependent and compatibility with future versions of \kbd{gp} is not guaranteed. Hence binary files should not be used for long term storage (also, they are larger and harder to compress than text files). pari-2.11.2/src/functions/programming/print10000644000175000017500000000100113326135265017435 0ustar billbillFunction: print1 Section: programming/specific C-Name: print1 Prototype: vs* Help: print1({str}*): outputs its string arguments (in raw format) without ending with newline. Description: (?gen,...):void pari_printf("${2 format_string}"${2 format_args}) Doc: outputs its arguments in raw format, without ending with a newline. Note that you can still embed newlines within your strings, using the \b{n} notation~! The arguments are converted to strings following the rules in \secref{se:strings}. %\syn{NO} pari-2.11.2/src/functions/programming/whatnow0000644000175000017500000000164413201017466017716 0ustar billbillFunction: whatnow Class: gp Section: programming/specific C-Name: whatnow0 Prototype: vr Help: whatnow(key): if key was present in GP version 1.39.15, gives the new function name. Description: (str):void whatnow($1, 0) Doc: if keyword \var{key} is the name of a function that was present in GP version 1.39.15, outputs the new function name and syntax, if it changed at all. Functions that where introduced since then, then modified are also recognized. \bprog ? whatnow("mu") New syntax: mu(n) ===> moebius(n) moebius(x): Moebius function of x. ? whatnow("sin") This function did not change @eprog When a function was removed and the underlying functionality is not available under a compatible interface, no equivalent is mentioned: \bprog ? whatnow("buchfu") This function no longer exists @eprog\noindent (The closest equivalent would be to set \kbd{K = bnfinit(T)} then access \kbd{K.fu}.) pari-2.11.2/src/functions/programming/listkill0000644000175000017500000000061313201017466020051 0ustar billbillFunction: listkill Section: programming/specific C-Name: listkill Prototype: vG Obsolete: 2007-08-10 Help: listkill(L): obsolete, retained for backward compatibility. Doc: obsolete, retained for backward compatibility. Just use \kbd{L = List()} instead of \kbd{listkill(L)}. In most cases, you won't even need that, e.g. local variables are automatically cleared when a user function returns. pari-2.11.2/src/functions/programming/filewrite0000644000175000017500000000361313326135265020225 0ustar billbillFunction: filewrite Section: programming/specific C-Name: gp_filewrite Prototype: vLs Help: filewrite(n, s): write the string s to file attached to descriptor n, ending with a newline. The file must have been opened with fileopen in "w" or "a" mode. Doc: write the string $s$ to the file attached to descriptor $n$, ending with a newline. The file must have been opened with \kbd{fileopen} in \kbd{"w"} or \kbd{"a"} mode. There is no guarantee that $s$ is completely written to disk until \kbd{fileclose$(n)$} is executed, which is automatic when quitting \kbd{gp}. If the newline is not desired, use \kbd{filewrite1}. \misctitle{Variant} The high-level function \kbd{write} is expensive when many consecutive writes are expected because it cannot use buffering. The low-level interface \kbd{fileopen} / \kbd{filewrite} / \kbd{fileclose} is more efficient: \bprog ? f = "/tmp/bigfile"; ? for (i = 1, 10^5, write(f, i^2+1)) time = 240 ms. ? v = vector(10^5, i, i^2+1); time = 10 ms. \\ computing the values is fast ? write("/tmp/bigfile2",v) time = 12 ms. \\ writing them in one operation is fast ? n = fileopen("/tmp/bigfile", "w"); ? for (i = 1, 10^5, filewrite(n, i^2+1)) time = 24 ms. \\ low-level write is ten times faster ? fileclose(n); @eprog\noindent In the final example, the file needs not be in a consistent state until the ending \kbd{fileclose} is evaluated, e.g. some lines might be half-written or not present at all even though the corresponding \kbd{filewrite} was executed already. Both a single high-level \kbd{write} and a succession of low-level \kbd{filewrite}s achieve the same efficiency, but the latter is often more natural. In fact, concatenating naively the entries to be written is quadratic in the number of entries, hence much more expensive than the original write operations: \bprog ? v = []; for (i = 1, 10^5, v = concat(v,i)) time = 1min, 41,456 ms. @eprog pari-2.11.2/src/functions/programming/call0000644000175000017500000000300513201017466017133 0ustar billbillFunction: call Section: programming/specific C-Name: call0 Prototype: GG Help: call(f, A): A being a vector, evaluates f(A[1],...,A[#A]). Doc: $A=[a_1,\dots, a_n]$ being a vector and $f$ being a function, returns the evaluation of $f(a_1,\dots,a_n)$. $f$ can also be the name of a built-in GP function. If $\# A =1$, \tet{call}($f,A$) = \tet{apply}($f,A$)[1]. If $f$ is variadic, the variadic arguments must grouped in a vector in the last component of $A$. This function is useful \item when writing a variadic function, to call another one: \bprog fprintf(file,format,args[..]) = write(file,call(Strprintf,[format,args])) @eprog \item when dealing with function arguments with unspecified arity The function below implements a global memoization interface: \bprog memo=Map(); memoize(f,A[..])= { my(res); if(!mapisdefined(memo, [f,A], &res), res = call(f,A); mapput(memo,[f,A],res)); res; } @eprog for example: \bprog ? memoize(factor,2^128+1) %3 = [59649589127497217,1;5704689200685129054721,1] ? ## *** last result computed in 76 ms. ? memoize(factor,2^128+1) %4 = [59649589127497217,1;5704689200685129054721,1] ? ## *** last result computed in 0 ms. ? memoize(ffinit,3,3) %5 = Mod(1,3)*x^3+Mod(1,3)*x^2+Mod(1,3)*x+Mod(2,3) ? fibo(n)=if(n==0,0,n==1,1,memoize(fibo,n-2)+memoize(fibo,n-1)); ? fibo(100) %7 = 354224848179261915075 @eprog \item to call operators through their internal names without using \kbd{alias} \bprog matnbelts(M) = call("_*_",matsize(M)) @eprog pari-2.11.2/src/functions/programming/forperm0000644000175000017500000000251313326135265017703 0ustar billbillFunction: _forperm_init Class: gp2c_internal Help: Initialize forperm_t Description: (forperm,gen):void forperm_init(&$1, $2) Function: _forperm_next Class: gp2c_internal Help: Compute the next permutation Description: (forperm):vecsmall forperm_next(&$1) Function: forperm Section: programming/control C-Name: forperm0 Prototype: vGVI Iterator: (gen,gen) (forperm, _forperm_init, _forperm_next) Wrapper: (,vG,,) Help: forperm(a,p,seq): the sequence is evaluated, p going through permutations of a. Doc: evaluates \var{seq}, where the formal variable $p$ goes through some permutations given by a \typ{VECSMALL}. If $a$ is a positive integer then $P$ goes through the permutations of $\{1, 2, ..., a\}$ in lexicographic order and if $a$ is a small vector then $p$ goes through the (multi)permutations lexicographically larger than or equal to $a$. \bprog ? forperm(3, p, print(p)) Vecsmall([1, 2, 3]) Vecsmall([1, 3, 2]) Vecsmall([2, 1, 3]) Vecsmall([2, 3, 1]) Vecsmall([3, 1, 2]) Vecsmall([3, 2, 1]) @eprog\noindent When $a$ is itself a \typ{VECSMALL} or a \typ{VEC} then $p$ iterates through multipermutations \bprog ? forperm([2,1,1,3], p, print(p)) Vecsmall([2, 1, 1, 3]) Vecsmall([2, 1, 3, 1]) Vecsmall([2, 3, 1, 1]) Vecsmall([3, 1, 1, 2]) Vecsmall([3, 1, 2, 1]) Vecsmall([3, 2, 1, 1]) @eprog\noindent pari-2.11.2/src/functions/programming/extern0000644000175000017500000000060713201017466017532 0ustar billbillFunction: extern Section: programming/specific C-Name: gpextern Prototype: s Help: extern(str): execute shell command str, and feeds the result to GP (as if loading from file). Doc: the string \var{str} is the name of an external command (i.e.~one you would type from your UNIX shell prompt). This command is immediately run and its output fed into \kbd{gp}, just as if read from a file. pari-2.11.2/src/functions/programming/forstep0000644000175000017500000000170013326135265017710 0ustar billbillFunction: forstep Section: programming/control C-Name: forstep Prototype: vV=GGGI Help: forstep(X=a,b,s,seq): the sequence is evaluated, X going from a to b in steps of s (can be a vector of steps). If b is set to +oo the loop will not stop. Doc: evaluates \var{seq}, where the formal variable $X$ goes from $a$ to $b$ in increments of $s$. Nothing is done if $s>0$ and $a>b$ or if $s<0$ and $aellcard(E,p), V) } @eprog computes the order of $E(\F_p)$ for $12$ random primes of $200$ bits. pari-2.11.2/src/functions/programming/my0000644000175000017500000000016311636712103016647 0ustar billbillFunction: my Section: programming/specific Help: my(x,...,z): declare x,...,z as lexically-scoped local variables. pari-2.11.2/src/functions/programming/global0000644000175000017500000000027213201017466017463 0ustar billbillFunction: global Section: programming/specific Obsolete: 2007-10-03 Help: global(list of variables): obsolete. Scheduled for deletion. Doc: obsolete. Scheduled for deletion. % \syn{NO} pari-2.11.2/src/functions/programming/alias0000644000175000017500000000345713201017466017324 0ustar billbillFunction: alias Section: programming/specific C-Name: alias0 Prototype: vrr Help: alias(newsym,sym): defines the symbol newsym as an alias for the symbol sym. Doc: defines the symbol \var{newsym} as an alias for the symbol \var{sym}: \bprog ? alias("det", "matdet"); ? det([1,2;3,4]) %1 = -2 @eprog\noindent You are not restricted to ordinary functions, as in the above example: to alias (from/to) member functions, prefix them with `\kbd{\_.}'; to alias operators, use their internal name, obtained by writing \kbd{\_} in lieu of the operators argument: for instance, \kbd{\_!} and \kbd{!\_} are the internal names of the factorial and the logical negation, respectively. \bprog ? alias("mod", "_.mod"); ? alias("add", "_+_"); ? alias("_.sin", "sin"); ? mod(Mod(x,x^4+1)) %2 = x^4 + 1 ? add(4,6) %3 = 10 ? Pi.sin %4 = 0.E-37 @eprog Alias expansion is performed directly by the internal GP compiler. Note that since alias is performed at compilation-time, it does not require any run-time processing, however it only affects GP code compiled \emph{after} the alias command is evaluated. A slower but more flexible alternative is to use variables. Compare \bprog ? fun = sin; ? g(a,b) = intnum(t=a,b,fun(t)); ? g(0, Pi) %3 = 2.0000000000000000000000000000000000000 ? fun = cos; ? g(0, Pi) %5 = 1.8830410776607851098 E-39 @eprog\noindent with \bprog ? alias(fun, sin); ? g(a,b) = intnum(t=a,b,fun(t)); ? g(0,Pi) %2 = 2.0000000000000000000000000000000000000 ? alias(fun, cos); \\ Oops. Does not affect *previous* definition! ? g(0,Pi) %3 = 2.0000000000000000000000000000000000000 ? g(a,b) = intnum(t=a,b,fun(t)); \\ Redefine, taking new alias into account ? g(0,Pi) %5 = 1.8830410776607851098 E-39 @eprog A sample alias file \kbd{misc/gpalias} is provided with the standard distribution. pari-2.11.2/src/functions/programming/pareval0000644000175000017500000000103513036414402017650 0ustar billbillFunction: pareval Section: programming/parallel C-Name: pareval Prototype: G Help: pareval(x): parallel evaluation of the elements of the vector of closures x. Doc: parallel evaluation of the elements of \kbd{x}, where \kbd{x} is a vector of closures. The closures must be of arity $0$, must not access global variables or variables declared with \kbd{local} and must be free of side effects. Function: _pareval_worker Section: programming/internals C-Name: pareval_worker Prototype: G Help: _pareval_worker(C): evaluate the closure C. pari-2.11.2/src/functions/programming/parforvec0000644000175000017500000000157313201017466020217 0ustar billbillFunction: parforvec Section: programming/parallel C-Name: parforvec0 Prototype: vV=GJDVDID0,L, Description: (gen,closure,,,?small):void parforvec($1, $2, $5, NULL, NULL) Help: parforvec(X=v,expr1,{j},{expr2},{flag}): evaluates the sequence expr2 (dependent on X and j) for X as generated by forvec, in random order, computed in parallel. Substitute for j the value of expr1 (dependent on X). Doc: evaluates the sequence \kbd{expr2} (dependent on $X$ and $j$) for $X$ as generated by \kbd{forvec}, in random order, computed in parallel. Substitute for $j$ the value of \kbd{expr1} (dependent on $X$). It is allowed fo \kbd{expr2} to exit the loop using \kbd{break}/\kbd{next}/\kbd{return}, however in that case, \kbd{expr2} will still be evaluated for all remaining value of $p$ less than the current one, unless a subsequent \kbd{break}/\kbd{next}/\kbd{return} happens. %\syn{NO} pari-2.11.2/src/functions/programming/fordiv0000644000175000017500000000205311636712103017513 0ustar billbillFunction: fordiv Section: programming/control C-Name: fordiv Prototype: vGVI Help: fordiv(n,X,seq): the sequence is evaluated, X running over the divisors of n. Doc: evaluates \var{seq}, where the formal variable $X$ ranges through the divisors of $n$ (see \tet{divisors}, which is used as a subroutine). It is assumed that \kbd{factor} can handle $n$, without negative exponents. Instead of $n$, it is possible to input a factorization matrix, i.e. the output of \kbd{factor(n)}. This routine uses \kbd{divisors} as a subroutine, then loops over the divisors. In particular, if $n$ is an integer, divisors are sorted by increasing size. To avoid storing all divisors, possibly using a lot of memory, the following (much slower) routine loops over the divisors using essentially constant space: \bprog FORDIV(N)= { my(P, E); P = factor(N); E = P[,2]; P = P[,1]; forvec( v = vector(#E, i, [0,E[i]]), X = factorback(P, v) \\ ... ); } ? for(i=1,10^5, FORDIV(i)) time = 3,445 ms. ? for(i=1,10^5, fordiv(i, d, )) time = 490 ms. @eprog pari-2.11.2/src/functions/programming/listinsert0000644000175000017500000000074113201017466020424 0ustar billbillFunction: listinsert Section: programming/specific C-Name: listinsert Prototype: WGL Help: listinsert(L,x,n): insert x at index n in list L, shifting the remaining elements to the right. Description: (list, gen, small):gen listinsert($1, $2, $3) Doc: inserts the object $x$ at position $n$ in $L$ (which must be of type \typ{LIST}). This has complexity $O(\#L - n + 1)$: all the remaining elements of \var{list} (from position $n+1$ onwards) are shifted to the right. pari-2.11.2/src/functions/programming/getstack0000644000175000017500000000043511636712103020031 0ustar billbillFunction: getstack Section: programming/specific C-Name: getstack Prototype: l Help: getstack(): current value of stack pointer avma. Doc: returns the current value of $\kbd{top}-\kbd{avma}$, i.e.~the number of bytes used up to now on the stack. Useful mainly for debugging purposes. pari-2.11.2/src/functions/programming/readvec0000644000175000017500000000170711636712103017640 0ustar billbillFunction: readvec Section: programming/specific C-Name: gp_readvec_file Prototype: D"",s, Help: readvec({filename}): create a vector whose components are the evaluation of all the expressions found in the input file filename. Description: (str):gen gp_readvec_file($1) Doc: reads in the file \var{filename} (subject to string expansion). If \var{filename} is omitted, re-reads the last file that was fed into \kbd{gp}. The return value is a vector whose components are the evaluation of all sequences of instructions contained in the file. For instance, if \var{file} contains \bprog 1 2 3 @eprog\noindent then we will get: \bprog ? \r a %1 = 1 %2 = 2 %3 = 3 ? read(a) %4 = 3 ? readvec(a) %5 = [1, 2, 3] @eprog In general a sequence is just a single line, but as usual braces and \kbd{\bs} may be used to enter multiline sequences. Variant: The underlying library function \fun{GEN}{gp_readvec_stream}{FILE *f} is usually more flexible. pari-2.11.2/src/functions/programming/forprimestep0000644000175000017500000000377313326135265020761 0ustar billbillFunction: _forprimestep_init Class: gp2c_internal Help: Initialize forprime_t. Description: (forprime,int,?int,int):void forprimestep_init(&$1,$2,$3,$4); Function: forprimestep Section: programming/control C-Name: forprimestep Prototype: vV=GDGGI Help: forprimestep(p=a,b,q,seq): the sequence is evaluated, p running over the primes in an arithmetic progression of the form a + k*q and less than b. Iterator: (*notype,small,small,gen) (forprime, _forprimestep_init, _u_forprime_next) (*notype,gen,gen,gen) (forprime, _forprimestep_init, _forprime_next_) (*small,gen,?gen,gen) (forprime, _forprimestep_init, _u_forprime_next) (*int,gen,?gen,gen) (forprime, _forprimestep_init, _forprime_next_) (gen,gen,?gen,gen) (forprime, _forprimestep_init, _forprime_next_) Doc: evaluates \var{seq}, where the formal variable $p$ ranges over the prime numbers $p$ in an arithmetic progression in $[a,b]$: $q$ is either an integer ($p \equiv a \pmod{q}$) or an intmod \kbd{Mod(c,N)} and we restrict to that congruence class. Nothing is done if $a>b$. \bprog ? forprimestep(p = 4, 30, 5, print(p)) 19 29 ? forprimestep(p = 4, 30, Mod(1,5), print(p)) 11 @eprog\noindent Setting $b$ to \kbd{+oo} means we will run through all primes $\geq a$, starting an infinite loop; it is expected that the caller will break out of the loop itself at some point, using \kbd{break} or \kbd{return}. The current implementation restricts the modulus of the arithmetic progression to an unsigned long (64 or 32 bits). \bprog ? forprimestep(p=2,oo,2^64,print(p)) *** at top-level: forprimestep(p=2,oo,2^64,print(p)) *** ^---------------------------------- *** forprimestep: overflow in t_INT-->ulong assignment. @eprog Note that the value of $p$ cannot be modified within \var{seq}: \bprog ? forprimestep(p = 2, 10, 3, p = []) *** at top-level: forprimestep(p=2,10,3,p=[]) *** ^--- *** prime index read-only: was changed to []. @eprog pari-2.11.2/src/functions/programming/HEADER0000644000175000017500000000446013326135265017164 0ustar billbillFunction: _header_programming/control Class: header Section: programming/control Doc: \section{Programming in GP: control statements} \sidx{programming}\label{se:programming} A number of control statements are available in GP. They are simpler and have a syntax slightly different from their C counterparts, but are quite powerful enough to write any kind of program. Some of them are specific to GP, since they are made for number theorists. As usual, $X$ will denote any simple variable name, and \var{seq} will always denote a sequence of expressions, including the empty sequence. \misctitle{Caveat} In constructs like \bprog for (X = a,b, seq) @eprog\noindent the variable \kbd{X} is lexically scoped to the loop, leading to possibly unexpected behavior: \bprog n = 5; for (n = 1, 10, if (something_nice(), break); ); \\ @com at this point \kbd{n} is 5 ! @eprog\noindent If the sequence \kbd{seq} modifies the loop index, then the loop is modified accordingly: \bprog ? for (n = 1, 10, n += 2; print(n)) 3 6 9 12 @eprog Function: _header_programming/specific Class: header Section: programming/specific Doc: \section{Programming in GP: other specific functions} \label{se:gp_program} In addition to the general PARI functions, it is necessary to have some functions which will be of use specifically for \kbd{gp}, though a few of these can be accessed under library mode. Before we start describing these, we recall the difference between \emph{strings} and \emph{keywords} (see \secref{se:strings}): the latter don't get expanded at all, and you can type them without any enclosing quotes. The former are dynamic objects, where everything outside quotes gets immediately expanded. Function: _header_programming/parallel Class: header Section: programming/parallel Doc: \section{Parallel programming} These function are only available if PARI was configured using \kbd{Configure --mt=\dots}. Two multithread interfaces are supported: \item POSIX threads \item Message passing interface (MPI) As a rule, POSIX threads are well-suited for single systems, while MPI is used by most clusters. However the parallel GP interface does not depend on the chosen multithread interface: a properly written GP program will work identically with both. pari-2.11.2/src/functions/programming/forsubgroup0000644000175000017500000000401513036414402020574 0ustar billbillFunction: forsubgroup Section: programming/control C-Name: forsubgroup0 Prototype: vV=GDGI Help: forsubgroup(H=G,{bound},seq): execute seq for each subgroup H of the abelian group G, whose index is bounded by bound if not omitted. H is given as a left divisor of G in HNF form. Wrapper: (,,vG) Description: (gen,?gen,closure):void forsubgroup(${3 cookie}, ${3 wrapper}, $1, $2) Doc: evaluates \var{seq} for each subgroup $H$ of the \emph{abelian} group $G$ (given in SNF\sidx{Smith normal form} form or as a vector of elementary divisors). If \var{bound} is present, and is a positive integer, restrict the output to subgroups of index less than \var{bound}. If \var{bound} is a vector containing a single positive integer $B$, then only subgroups of index exactly equal to $B$ are computed The subgroups are not ordered in any obvious way, unless $G$ is a $p$-group in which case Birkhoff's algorithm produces them by decreasing index. A \idx{subgroup} is given as a matrix whose columns give its generators on the implicit generators of $G$. For example, the following prints all subgroups of index less than 2 in $G = \Z/2\Z g_1 \times \Z/2\Z g_2$: \bprog ? G = [2,2]; forsubgroup(H=G, 2, print(H)) [1; 1] [1; 2] [2; 1] [1, 0; 1, 1] @eprog\noindent The last one, for instance is generated by $(g_1, g_1 + g_2)$. This routine is intended to treat huge groups, when \tet{subgrouplist} is not an option due to the sheer size of the output. For maximal speed the subgroups have been left as produced by the algorithm. To print them in canonical form (as left divisors of $G$ in HNF form), one can for instance use \bprog ? G = matdiagonal([2,2]); forsubgroup(H=G, 2, print(mathnf(concat(G,H)))) [2, 1; 0, 1] [1, 0; 0, 2] [2, 0; 0, 1] [1, 0; 0, 1] @eprog\noindent Note that in this last representation, the index $[G:H]$ is given by the determinant. See \tet{galoissubcyclo} and \tet{galoisfixedfield} for applications to \idx{Galois} theory. \synt{forsubgroup}{void *data, long (*call)(void*,GEN), GEN G, GEN bound}. pari-2.11.2/src/functions/programming/parforprime0000644000175000017500000000234113201017466020550 0ustar billbillFunction: parforprime Section: programming/parallel C-Name: parforprime0 Prototype: vV=GDGJDVDI Description: (gen,gen,closure):void parforprime($1, $2, $3, NULL, NULL) Help: parforprime(p=a,{b},expr1,{r},{expr2}): evaluates the expression expr1 in parallel for all primes p between a and b (if b is set to +oo, the loop will not stop), resulting in as many values; if the formal variables r and expr2 are present, evaluate sequentially expr2, in which r has been replaced by the different results obtained for expr1 and p with the corresponding arguments. Doc: behaves exactly as \kbd{parfor}, but loops only over prime values $p$. Precisely, the functions evaluates in parallel the expression \kbd{expr1} in the formal argument $p$ running through the primes from $a$ to $b$. If $b$ is set to \kbd{+oo}, the loop runs indefinitely. If $r$ and \kbd{expr2} are present, the expression \kbd{expr2} in the formal variables $r$ and $p$ is evaluated with $r$ running through all the different results obtained for \kbd{expr1} and $p$ takes the corresponding argument. It is allowed fo \kbd{expr2} to exit the loop using \kbd{break}/\kbd{next}/\kbd{return}; see the remarks in the documentation of \kbd{parfor} for details. %\syn{NO} pari-2.11.2/src/functions/programming/version0000644000175000017500000000451513036414402017711 0ustar billbillFunction: version Section: programming/specific C-Name: pari_version Prototype: Help: version(): returns the PARI version as [major,minor,patch] or [major,minor,patch,VCSversion]. Doc: returns the current version number as a \typ{VEC} with three integer components (major version number, minor version number and patchlevel); if your sources were obtained through our version control system, this will be followed by further more precise arguments, including e.g.~a~\kbd{git} \emph{commit hash}. This function is present in all versions of PARI following releases 2.3.4 (stable) and 2.4.3 (testing). Unless you are working with multiple development versions, you probably only care about the 3 first numeric components. In any case, the \kbd{lex} function offers a clever way to check against a particular version number, since it will compare each successive vector entry, numerically or as strings, and will not mind if the vectors it compares have different lengths: \bprog if (lex(version(), [2,3,5]) >= 0, \\ code to be executed if we are running 2.3.5 or more recent. , \\ compatibility code ); @eprog\noindent On a number of different machines, \kbd{version()} could return either of \bprog %1 = [2, 3, 4] \\ released version, stable branch %1 = [2, 4, 3] \\ released version, testing branch %1 = [2, 6, 1, 15174, ""505ab9b"] \\ development @eprog In particular, if you are only working with released versions, the first line of the gp introductory message can be emulated by \bprog [M,m,p] = version(); printf("GP/PARI CALCULATOR Version %s.%s.%s", M,m,p); @eprog\noindent If you \emph{are} working with many development versions of PARI/GP, the 4th and/or 5th components can be profitably included in the name of your logfiles, for instance. \misctitle{Technical note} For development versions obtained via \kbd{git}, the 4th and 5th components are liable to change eventually, but we document their current meaning for completeness. The 4th component counts the number of reachable commits in the branch (analogous to \kbd{svn}'s revision number), and the 5th is the \kbd{git} commit hash. In particular, \kbd{lex} comparison still orders correctly development versions with respect to each others or to released versions (provided we stay within a given branch, e.g. \kbd{master})! pari-2.11.2/src/functions/programming/apply0000644000175000017500000000307412314242551017352 0ustar billbillFunction: apply Section: programming/specific C-Name: apply0 Prototype: GG Help: apply(f, A): apply function f to each entry in A. Wrapper: (G) Description: (closure,gen):gen genapply(${1 cookie}, ${1 wrapper}, $2) Doc: Apply the \typ{CLOSURE} \kbd{f} to the entries of \kbd{A}. If \kbd{A} is a scalar, return \kbd{f(A)}. If \kbd{A} is a polynomial or power series, apply \kbd{f} on all coefficients. If \kbd{A} is a vector or list, return the elements $f(x)$ where $x$ runs through \kbd{A}. If \kbd{A} is a matrix, return the matrix whose entries are the $f(\kbd{A[i,j]})$. \bprog ? apply(x->x^2, [1,2,3,4]) %1 = [1, 4, 9, 16] ? apply(x->x^2, [1,2;3,4]) %2 = [1 4] [9 16] ? apply(x->x^2, 4*x^2 + 3*x+ 2) %3 = 16*x^2 + 9*x + 4 @eprog\noindent Note that many functions already act componentwise on vectors or matrices, but they almost never act on lists; in this case, \kbd{apply} is a good solution: \bprog ? L = List([Mod(1,3), Mod(2,4)]); ? lift(L) *** at top-level: lift(L) *** ^------- *** lift: incorrect type in lift. ? apply(lift, L); %2 = List([1, 2]) @eprog \misctitle{Remark} For $v$ a \typ{VEC}, \typ{COL}, \typ{LIST} or \typ{MAT}, the alternative set-notations \bprog [g(x) | x <- v, f(x)] [x | x <- v, f(x)] [g(x) | x <- v] @eprog\noindent are available as shortcuts for \bprog apply(g, select(f, Vec(v))) select(f, Vec(v)) apply(g, Vec(v)) @eprog\noindent respectively: \bprog ? L = List([Mod(1,3), Mod(2,4)]); ? [ lift(x) | x<-L ] %2 = [1, 2] @eprog \synt{genapply}{void *E, GEN (*fun)(void*,GEN), GEN a}. pari-2.11.2/src/functions/programming/error0000644000175000017500000000124212314242551017351 0ustar billbillFunction: _err_primes Class: gp2c_internal Description: ():void pari_err(e_MAXPRIME) Function: _err_type Class: gp2c_internal Description: (str,gen):void pari_err_TYPE($1,$2) Function: error Section: programming/specific C-Name: error0 Prototype: vs* Help: error({str}*): abort script with error message str. Description: (error):void pari_err(0, $1) (?gen,...):void pari_err(e_MISC, "${2 format_string}"${2 format_args}) Doc: outputs its argument list (each of them interpreted as a string), then interrupts the running \kbd{gp} program, returning to the input prompt. For instance \bprog error("n = ", n, " is not squarefree!") @eprog\noindent % \syn{NO} pari-2.11.2/src/functions/programming/until0000644000175000017500000000064511636712103017362 0ustar billbillFunction: until Section: programming/control C-Name: untilpari Prototype: vEI Help: until(a,seq): evaluate the expression sequence seq until a is nonzero. Doc: evaluates \var{seq} until $a$ is not equal to 0 (i.e.~until $a$ is true). If $a$ is initially not equal to 0, \var{seq} is evaluated once (more generally, the condition on $a$ is tested \emph{after} execution of the \var{seq}, not before as in \kbd{while}). pari-2.11.2/src/functions/programming/uninline0000644000175000017500000000027113201017466020043 0ustar billbillFunction: uninline Section: programming/specific Help: uninline(): forget all inline variables [EXPERIMENTAL]. Doc: (Experimental) Exit the scope of all current \kbd{inline} variables. pari-2.11.2/src/functions/programming/local0000644000175000017500000000017511636712103017317 0ustar billbillFunction: local Section: programming/specific Help: local(x,...,z): declare x,...,z as (dynamically scoped) local variables. pari-2.11.2/src/functions/programming/fileclose0000644000175000017500000000415413326135265020201 0ustar billbillFunction: fileclose Section: programming/specific C-Name: gp_fileclose Prototype: vL Help: fileclose(n): close the file descriptor n. Doc: close the file descriptor $n$, created via \kbd{fileopen} or \kbd{fileextern}. Finitely many files can be opened at a given time, closing them recycles file descriptors and avoids running out of them: \bprog ? n = 0; while(n++, fileopen("/tmp/test", "w")) *** at top-level: n=0;while(n++,fileopen("/tmp/test","w")) *** ^-------------------------- *** fileopen: error opening requested file: `/tmp/test'. *** Break loop: type 'break' to go back to GP prompt break> n 65533 @eprog\noindent This is a limitation of the operating system and does not depend on PARI: if you open too many files in \kbd{gp} without closing them, the operating system will also prevent unrelated applications from opening files. Independently, your operating system (e.g. Windows) may prevent other applications from accessing or deleting your file while it is opened by \kbd{gp}. Quitting \kbd{gp} implicitly calls this function on all opened file descriptors. On files opened for writing, this function also forces a write of all buffered data to the file system and completes all pending write operations. This function is implicitly called for all open file descriptors when exiting \kbd{gp} but it is cleaner and safer to call it explicitly, for instance in case of a \kbd{gp} crash or general system failure, which could cause data loss. \bprog ? n = fileopen("./here"); ? while(l = fileread(n), print(l)); ? fileclose(n); ? n = fileopen("./there", "w"); ? for (i = 1, 100, filewrite(n, i^2+1)) ? fileclose(n) @eprog Until a \kbd{fileclose}, there is no guarantee that the file on disk contains all the expected data from previous \kbd{filewrite}s. (And even then the operating system may delay the actual write to hardware.) Closing a file twice raises an exception: \bprog ? n = fileopen("/tmp/test"); ? fileclose(n) ? fileclose(n) *** at top-level: fileclose(n) *** ^------------ *** fileclose: invalid file descriptor 0 @eprog pari-2.11.2/src/functions/programming/kill0000644000175000017500000000266513201017466017166 0ustar billbillFunction: kill Section: programming/specific C-Name: kill0 Prototype: vr Help: kill(sym): restores the symbol sym to its ``undefined'' status and kill attached help messages. Doc: restores the symbol \kbd{sym} to its ``undefined'' status, and deletes any help messages attached to \kbd{sym} using \kbd{addhelp}. Variable names remain known to the interpreter and keep their former priority: you cannot make a variable ``less important" by killing it! \bprog ? z = y = 1; y %1 = 1 ? kill(y) ? y \\ restored to ``undefined'' status %2 = y ? variable() %3 = [x, y, z] \\ but the variable name y is still known, with y > z ! @eprog\noindent For the same reason, killing a user function (which is an ordinary variable holding a \typ{CLOSURE}) does not remove its name from the list of variable names. If the symbol is attached to a variable --- user functions being an important special case ---, one may use the \idx{quote} operator \kbd{a = 'a} to reset variables to their starting values. However, this will not delete a help message attached to \kbd{a}, and is also slightly slower than \kbd{kill(a)}. \bprog ? x = 1; addhelp(x, "foo"); x %1 = 1 ? x = 'x; x \\ same as 'kill', except we don't delete help. %2 = x ? ?x foo @eprog\noindent On the other hand, \kbd{kill} is the only way to remove aliases and installed functions. \bprog ? alias(fun, sin); ? kill(fun); ? install(addii, GG); ? kill(addii); @eprog pari-2.11.2/src/functions/programming/trap0000644000175000017500000000444313201017466017175 0ustar billbillFunction: trap Section: programming/specific C-Name: trap0 Prototype: DrDEDE Obsolete: 2012-01-17 Help: trap({e}, {rec}, seq): this function is obsolete, use "iferr". Try to execute seq, trapping runtime error e (all of them if e omitted); sequence rec is executed if the error occurs and is the result of the command. Wrapper: (,_,_) Description: (?str,?closure,?closure):gen trap0($1, $2, $3) Doc: This function is obsolete, use \tet{iferr}, which has a nicer and much more powerful interface. For compatibility's sake we now describe the \emph{obsolete} function \tet{trap}. This function tries to evaluate \var{seq}, trapping runtime error $e$, that is effectively preventing it from aborting computations in the usual way; the recovery sequence \var{rec} is executed if the error occurs and the evaluation of \var{rec} becomes the result of the command. If $e$ is omitted, all exceptions are trapped. See \secref{se:errorrec} for an introduction to error recovery under \kbd{gp}. \bprog ? \\@com trap division by 0 ? inv(x) = trap (e_INV, INFINITY, 1/x) ? inv(2) %1 = 1/2 ? inv(0) %2 = INFINITY @eprog\noindent Note that \var{seq} is effectively evaluated up to the point that produced the error, and the recovery sequence is evaluated starting from that same context, it does not "undo" whatever happened in the other branch (restore the evaluation context): \bprog ? x = 1; trap (, /* recover: */ x, /* try: */ x = 0; 1/x) %1 = 0 @eprog \misctitle{Note} The interface is currently not adequate for trapping individual exceptions. In the current version \vers, the following keywords are recognized, but the name list will be expanded and changed in the future (all library mode errors can be trapped: it's a matter of defining the keywords to \kbd{gp}): \kbd{e\_ALARM}: alarm time-out \kbd{e\_ARCH}: not available on this architecture or operating system \kbd{e\_STACK}: the PARI stack overflows \kbd{e\_INV}: impossible inverse \kbd{e\_IMPL}: not yet implemented \kbd{e\_OVERFLOW}: all forms of arithmetic overflow, including length or exponent overflow (when a larger value is supplied than the implementation can handle). \kbd{e\_SYNTAX}: syntax error \kbd{e\_MISC}: miscellaneous error \kbd{e\_TYPE}: wrong type \kbd{e\_USER}: user error (from the \kbd{error} function) pari-2.11.2/src/functions/programming/dbg_up0000644000175000017500000000051113036414402017454 0ustar billbillFunction: dbg_up Class: gp Section: programming/control C-Name: dbg_up Prototype: vD1,L, Help: dbg_up({n=1}): (break loop) go up n frames. Allow to inspect data of the parent function. Doc: (In the break loop) go up n frames. This allows to inspect data of the parent function. To cancel a \tet{dbg_up} call, use \tet{dbg_down} pari-2.11.2/src/functions/programming/externstr0000644000175000017500000000070013201017466020255 0ustar billbillFunction: externstr Section: programming/specific C-Name: externstr Prototype: s Help: externstr(str): execute shell command str, and returns the result as a vector of GP strings, one component per output line. Doc: the string \var{str} is the name of an external command (i.e.~one you would type from your UNIX shell prompt). This command is immediately run and its output is returned as a vector of GP strings, one component per output line. pari-2.11.2/src/functions/programming/quit0000644000175000017500000000067711636712103017216 0ustar billbillFunction: quit Class: gp Section: programming/specific C-Name: gp_quit Prototype: vD0,L, Help: quit({status = 0}): quit, return to the system with exit status 'status'. Doc: exits \kbd{gp} and return to the system with exit status \kbd{status}, a small integer. A non-zero exit status normally indicates abnormal termination. (Note: the system actually sees only \kbd{status} mod $256$, see your man pages for \kbd{exit(3)} or \kbd{wait(2)}). pari-2.11.2/src/functions/programming/parsum0000644000175000017500000000127513201017466017536 0ustar billbillFunction: parsum Section: programming/parallel C-Name: parsum Prototype: V=GGJDG Description: (gen,gen,closure,?gen):gen parsum($1, $2, $3, $4) Help: parsum(i=a,b,expr,{x}): x plus the sum (X goes from a to b) of expression expr, evaluated in parallel (in random order). Doc: sum of expression \var{expr}, initialized at $x$, the formal parameter going from $a$ to $b$, evaluated in parallel in random order. The expression \kbd{expr} must not access global variables or variables declared with \kbd{local()}, and must be free of side effects. \bprog parsum(i=1,1000,ispseudoprime(2^prime(i)-1)) @eprog returns the numbers of prime numbers among the first $1000$ Mersenne numbers. %\syn{NO} pari-2.11.2/src/functions/programming/warning0000644000175000017500000000077613201017466017701 0ustar billbillFunction: warning Section: programming/specific C-Name: warning0 Prototype: vs* Help: warning({str}*): display warning message str. Description: (?gen,...):void pari_warn(warnuser, "${2 format_string}"${2 format_args}) Doc: outputs the message ``user warning'' and the argument list (each of them interpreted as a string). If colors are enabled, this warning will be in a different color, making it easy to distinguish. \bprog warning(n, " is very large, this might take a while.") @eprog % \syn{NO} pari-2.11.2/src/functions/programming/mapdelete0000644000175000017500000000044713201017466020167 0ustar billbillFunction: mapdelete Section: programming/specific C-Name: mapdelete Prototype: vGG Help: mapdelete(M,x): removes x from the domain of the map M. Doc: removes $x$ from the domain of the map $M$. \bprog ? M = Map(["a",1; "b",3; "c",7]); ? mapdelete(M,"b"); ? Mat(M) ["a" 1] ["c" 7] @eprog pari-2.11.2/src/functions/programming/forcomposite0000644000175000017500000000272513457566440020757 0ustar billbillFunction: _forcomposite_init Class: gp2c_internal Help: Initialize forcomposite_t. Description: (forcomposite,int):void forcomposite_init(&$1, $2, NULL) (forcomposite,int,?int):void forcomposite_init(&$1, $2, $3) Function: _forcomposite_next Class: gp2c_internal Help: Compute the next composite. Description: (forcomposite):int forcomposite_next(&$1) Function: forcomposite Section: programming/control C-Name: forcomposite Prototype: vV=GDGI Help: forcomposite(n=a,{b},seq): the sequence is evaluated, n running over the composite numbers between a and b. Omitting b runs through composites >= a. Iterator: (gen,gen,?gen) (forcomposite, _forcomposite_init, _forcomposite_next) Doc: evaluates \var{seq}, where the formal variable $n$ ranges over the composite numbers between the non-negative real numbers $a$ to $b$, including $a$ and $b$ if they are composite. Nothing is done if $a>b$. \bprog ? forcomposite(n = 0, 10, print(n)) 4 6 8 9 10 @eprog\noindent Omitting $b$ means we will run through all composites $\geq a$, starting an infinite loop; it is expected that the user will break out of the loop himself at some point, using \kbd{break} or \kbd{return}. Note that the value of $n$ cannot be modified within \var{seq}: \bprog ? forcomposite(n = 2, 10, n = []) *** at top-level: forcomposite(n=2,10,n=[]) *** ^--- *** index read-only: was changed to []. @eprog pari-2.11.2/src/functions/programming/break0000644000175000017500000000075211636712103017312 0ustar billbillFunction: break Section: programming/control C-Name: break0 Prototype: D1,L, Help: break({n=1}): interrupt execution of current instruction sequence, and exit from the n innermost enclosing loops. Doc: interrupts execution of current \var{seq}, and immediately exits from the $n$ innermost enclosing loops, within the current function call (or the top level loop); the integer $n$ must be positive. If $n$ is greater than the number of enclosing loops, all enclosing loops are exited. pari-2.11.2/src/functions/programming/localbitprec0000644000175000017500000000523013447371554020702 0ustar billbillFunction: localbitprec Section: programming/specific C-Name: localbitprec Prototype: vL Help: localbitprec(p): set the real precision to p bits in the dynamic scope. Doc: set the real precision to $p$ bits in the dynamic scope. All computations are performed as if \tet{realbitprecision} was $p$: transcendental constants (e.g.~\kbd{Pi}) and conversions from exact to floating point inexact data use $p$ bits, as well as iterative routines implicitly using a floating point accuracy as a termination criterion (e.g.~\tet{solve} or \tet{intnum}). But \kbd{realbitprecision} itself is unaffected and is ``unmasked'' when we exit the dynamic (\emph{not} lexical) scope. In effect, this is similar to \bprog my(bit = default(realbitprecision)); default(realbitprecision,p); ... default(realbitprecision, bit); @eprog\noindent but is both less cumbersome, cleaner (no need to manipulate a global variable, which in fact never changes and is only temporarily masked) and more robust: if the above computation is interrupted or an exception occurs, \kbd{realbitprecision} will not be restored as intended. Such \kbd{localbitprec} statements can be nested, the innermost one taking precedence as expected. Beware that \kbd{localbitprec} follows the semantic of \tet{local}, not \tet{my}: a subroutine called from \kbd{localbitprec} scope uses the local accuracy: \bprog ? f()=bitprecision(1.0); ? f() %2 = 128 ? localbitprec(1000); f() %3 = 1024 @eprog\noindent Note that the bit precision of \emph{data} (\kbd{1.0} in the above example) increases by steps of 64 (32 on a 32-bit machine) so we get $1024$ instead of the expected $1000$; \kbd{localbitprec} bounds the relative error exactly as specified in functions that support that granularity (e.g.~\kbd{lfun}), and rounded to the next multiple of 64 (resp.~32) everywhere else. \misctitle{Warning} Changing \kbd{realbitprecision} or \kbd{realprecision} in programs is deprecated in favor of \kbd{localbitprec} and \kbd{localprec}. Think about the \kbd{realprecision} and \kbd{realbitprecision} defaults as interactive commands for the \kbd{gp} interpreter, best left out of GP programs. Indeed, the above rules imply that mixing both constructs yields surprising results: \bprog ? \p38 ? localprec(19); default(realprecision,1000); Pi %1 = 3.141592653589793239 ? \p realprecision = 1001 significant digits (1000 digits displayed) @eprog\noindent Indeed, \kbd{realprecision} itself is ignored within \kbd{localprec} scope, so \kbd{Pi} is computed to a low accuracy. And when we leave the \kbd{localprec} scope, \kbd{realprecision} only regains precedence, it is not ``restored'' to the original value. %\syn{NO} pari-2.11.2/src/functions/programming/alarm0000644000175000017500000000360613326135265017331 0ustar billbillFunction: alarm Section: programming/specific C-Name: gp_alarm Prototype: D0,L,DE Help: alarm({s = 0},{code}): if code is omitted, trigger an "e_ALARM" exception after s seconds, cancelling any previously set alarm; stop a pending alarm if s = 0 or is omitted. Otherwise, evaluate code, aborting after s seconds. Doc: if \var{code} is omitted, trigger an \var{e\_ALARM} exception after $s$ seconds, cancelling any previously set alarm; stop a pending alarm if $s = 0$ or is omitted. Otherwise, if $s$ is positive, the function evaluates \var{code}, aborting after $s$ seconds. The return value is the value of \var{code} if it ran to completion before the alarm timeout, and a \typ{ERROR} object otherwise. \bprog ? p = nextprime(10^25); q = nextprime(10^26); N = p*q; ? E = alarm(1, factor(N)); ? type(E) %3 = "t_ERROR" ? print(E) %4 = error("alarm interrupt after 964 ms.") ? alarm(10, factor(N)); \\ enough time %5 = [ 10000000000000000000000013 1] [100000000000000000000000067 1] @eprog\noindent Here is a more involved example: the function \kbd{timefact(N,sec)} below tries to factor $N$ and gives up after \var{sec} seconds, returning a partial factorization. \bprog \\ Time-bounded partial factorization default(factor_add_primes,1); timefact(N,sec)= { F = alarm(sec, factor(N)); if (type(F) == "t_ERROR", factor(N, 2^24), F); } @eprog\noindent We either return the factorization directly, or replace the \typ{ERROR} result by a simple bounded factorization \kbd{factor(N, 2\pow 24)}. Note the \tet{factor_add_primes} trick: any prime larger than $2^{24}$ discovered while attempting the initial factorization is stored and remembered. When the alarm rings, the subsequent bounded factorization finds it right away. \misctitle{Caveat} It is not possible to set a new alarm \emph{within} another \kbd{alarm} code: the new timer erases the parent one. pari-2.11.2/src/functions/programming/mapisdefined0000644000175000017500000000162213201017466020653 0ustar billbillFunction: mapisdefined Section: programming/specific C-Name: mapisdefined Prototype: iGGD& Help: mapisdefined(M,x,{&z}): true (1) if x has an image by the map M, false (0) otherwise. If z is present, set it to the image of x, if it exists. Doc: Returns true ($1$) if \kbd{x} has an image by the map $M$, false ($0$) otherwise. If \kbd{z} is present, set \kbd{z} to the image of $x$, if it exists. \bprog ? M1 = Map([1, 10; 2, 20]); ? mapisdefined(M1,3) %1 = 0 ? mapisdefined(M1, 1, &z) %2 = 1 ? z %3 = 10 @eprog \bprog ? M2 = Map(); N = 19; ? for (a=0, N-1, mapput(M2, a^3%N, a)); ? {for (a=0, N-1, if (mapisdefined(M2, a, &b), printf("%d is the cube of %d mod %d\n",a,b,N)));} 0 is the cube of 0 mod 19 1 is the cube of 11 mod 19 7 is the cube of 9 mod 19 8 is the cube of 14 mod 19 11 is the cube of 17 mod 19 12 is the cube of 15 mod 19 18 is the cube of 18 mod 19 @eprog pari-2.11.2/src/functions/programming/select0000644000175000017500000000532613201017466017507 0ustar billbillFunction: select Section: programming/specific C-Name: select0 Prototype: GGD0,L, Help: select(f, A, {flag = 0}): selects elements of A according to the selection function f. If flag is 1, return the indices of those elements (indirect selection). Wrapper: (bG) Description: (gen,gen):gen genselect(${1 cookie}, ${1 wrapper}, $2) (gen,gen,0):gen genselect(${1 cookie}, ${1 wrapper}, $2) (gen,gen,1):vecsmall genindexselect(${1 cookie}, ${1 wrapper}, $2) Doc: We first describe the default behavior, when $\fl$ is 0 or omitted. Given a vector or list \kbd{A} and a \typ{CLOSURE} \kbd{f}, \kbd{select} returns the elements $x$ of \kbd{A} such that $f(x)$ is non-zero. In other words, \kbd{f} is seen as a selection function returning a boolean value. \bprog ? select(x->isprime(x), vector(50,i,i^2+1)) %1 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] ? select(x->(x<100), %) %2 = [2, 5, 17, 37] @eprog\noindent returns the primes of the form $i^2+1$ for some $i\leq 50$, then the elements less than 100 in the preceding result. The \kbd{select} function also applies to a matrix \kbd{A}, seen as a vector of columns, i.e. it selects columns instead of entries, and returns the matrix whose columns are the selected ones. \misctitle{Remark} For $v$ a \typ{VEC}, \typ{COL}, \typ{LIST} or \typ{MAT}, the alternative set-notations \bprog [g(x) | x <- v, f(x)] [x | x <- v, f(x)] [g(x) | x <- v] @eprog\noindent are available as shortcuts for \bprog apply(g, select(f, Vec(v))) select(f, Vec(v)) apply(g, Vec(v)) @eprog\noindent respectively: \bprog ? [ x | x <- vector(50,i,i^2+1), isprime(x) ] %1 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] @eprog \noindent If $\fl = 1$, this function returns instead the \emph{indices} of the selected elements, and not the elements themselves (indirect selection): \bprog ? V = vector(50,i,i^2+1); ? select(x->isprime(x), V, 1) %2 = Vecsmall([1, 2, 4, 6, 10, 14, 16, 20, 24, 26, 36, 40]) ? vecextract(V, %) %3 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] @eprog\noindent The following function lists the elements in $(\Z/N\Z)^*$: \bprog ? invertibles(N) = select(x->gcd(x,N) == 1, [1..N]) @eprog \noindent Finally \bprog ? select(x->x, M) @eprog\noindent selects the non-0 entries in \kbd{M}. If the latter is a \typ{MAT}, we extract the matrix of non-0 columns. Note that \emph{removing} entries instead of selecting them just involves replacing the selection function \kbd{f} with its negation: \bprog ? select(x->!isprime(x), vector(50,i,i^2+1)) @eprog \synt{genselect}{void *E, long (*fun)(void*,GEN), GEN a}. Also available is \fun{GEN}{genindexselect}{void *E, long (*fun)(void*, GEN), GEN a}, corresponding to $\fl = 1$. pari-2.11.2/src/functions/programming/dbg_x0000644000175000017500000000072613216034034017306 0ustar billbillFunction: dbg_x Section: programming/control C-Name: dbgGEN Prototype: vGD-1,L, Help: dbg_x(A,{n}): print inner structure of A, complete if n is omitted, up to level n otherwise. Intended for debugging. Doc: Print the inner structure of \kbd{A}, complete if \kbd{n} is omitted, up to level \kbd{n} otherwise. This is useful for debugging. This is similar to \b{x} but does not require \kbd{A} to be an history entry. In particular, it can be used in the break loop. pari-2.11.2/src/functions/programming/getheap0000644000175000017500000000057113201017466017642 0ustar billbillFunction: getheap Section: programming/specific C-Name: getheap Prototype: Help: getheap(): 2-component vector giving the current number of objects in the heap and the space they occupy (in long words). Doc: returns a two-component row vector giving the number of objects on the heap and the amount of memory they occupy in long words. Useful mainly for debugging purposes. pari-2.11.2/src/functions/programming/fileopen0000644000175000017500000000275013326135265020035 0ustar billbillFunction: fileopen Section: programming/specific C-Name: gp_fileopen Prototype: lsD"r",s, Help: fileopen(path, mode): open the file pointed to by 'path' and return a file descriptor which can be used with other file functions. The mode is "r" (default, read), "w" (write, truncate), "a" (write, append). Doc: open the file pointed to by 'path' and return a file descriptor which can be used with other file functions. The mode can be \item \kbd{"r"} (default): open for reading; allow \kbd{fileread} and \kbd{filereadstr}. \item \kbd{"w"}: open for writing, discarding existing content; allow \kbd{filewrite}, \kbd{filewrite1}. \item \kbd{"a"}: open for writing, appending to existing content; same operations allowed as \kbd{"w"}. Eventually, the file should be closed and the descriptor recycled using \kbd{fileclose}. \bprog ? n = fileopen("./here"); \\ "r" by default ? while (l = filereadstr(n), print(l)) \\ print successive lines ? fileclose(n) \\ done @eprog\noindent In \emph{read} mode, raise an exception if the file does not exist or the user does not have read permission. In \emph{write} mode, raise an exception if the file cannot be written to. Trying to read or write to a file that was not opend with the right mode raises an exception. \bprog ? n = fileopen("./read", "r"); ? filewrite(n, "test") \\ not open for writing *** at top-level: filewrite(n,"test") *** ^------------------- *** filewrite: invalid file descriptor 0 @eprog pari-2.11.2/src/functions/programming/dbg_down0000644000175000017500000000042112314242551020001 0ustar billbillFunction: dbg_down Class: gp Section: programming/control C-Name: dbg_down Prototype: vD1,L, Help: dbg_down({n=1}): (break loop) go down n frames. Cancel a previous dbg_up. Doc: (In the break loop) go down n frames. This allows to cancel a previous call to \kbd{dbg\_up}. pari-2.11.2/src/functions/programming/listsort0000644000175000017500000000142313201017466020105 0ustar billbillFunction: listsort Section: programming/specific C-Name: listsort Prototype: vWD0,L, Help: listsort(L,{flag=0}): sort the list L in place. If flag is non-zero, suppress all but one occurence of each element in list. Doc: sorts the \typ{LIST} \var{list} in place, with respect to the (somewhat arbitrary) universal comparison function \tet{cmp}. In particular, the ordering is the same as for sets and \tet{setsearch} can be used on a sorted list. \bprog ? L = List([1,2,4,1,3,-1]); listsort(L); L %1 = List([-1, 1, 1, 2, 3, 4]) ? setsearch(L, 4) %2 = 6 ? setsearch(L, -2) %3 = 0 @eprog\noindent This is faster than the \kbd{vecsort} command since the list is sorted in place: no copy is made. No value returned. If $\fl$ is non-zero, suppresses all repeated coefficients. pari-2.11.2/src/functions/programming/return0000644000175000017500000000043711636712103017545 0ustar billbillFunction: return Section: programming/control C-Name: return0 Prototype: DG Help: return({x=0}): return from current subroutine with result x. Doc: returns from current subroutine, with result $x$. If $x$ is omitted, return the \kbd{(void)} value (return no result, like \kbd{print}). pari-2.11.2/src/functions/programming/write0000644000175000017500000000104313326135265017360 0ustar billbillFunction: write Section: programming/specific C-Name: write0 Prototype: vss* Help: write(filename,{str}*): appends the remaining arguments (same output as print) to filename. Doc: writes (appends) to \var{filename} the remaining arguments, and appends a newline (same output as \kbd{print}). \misctitle{Variant} The high-level function \kbd{write} is expensive when many consecutive writes are expected because it cannot use buffering. The low-level interface \kbd{fileopen} / \kbd{filewrite} / \kbd{fileclose} is more efficient. %\syn{NO} pari-2.11.2/src/functions/programming/getabstime0000644000175000017500000000063713326135265020362 0ustar billbillFunction: getabstime Section: programming/specific C-Name: getabstime Prototype: l Help: getabstime(): milliseconds of CPU time since startup. Doc: returns the CPU time (in milliseconds) elapsed since \kbd{gp} startup. This provides a reentrant version of \kbd{gettime}: \bprog my (t = getabstime()); ... print("Time: ", getabstime() - t); @eprog For a version giving wall-clock time, see \tet{getwalltime}. pari-2.11.2/src/functions/programming/if0000644000175000017500000000453012314242551016621 0ustar billbillFunction: if Section: programming/control C-Name: ifpari Prototype: GDEDE Help: if(a,{seq1},{seq2}): if a is nonzero, seq1 is evaluated, otherwise seq2. seq1 and seq2 are optional, and if seq2 is omitted, the preceding comma can be omitted also. Doc: evaluates the expression sequence \var{seq1} if $a$ is non-zero, otherwise the expression \var{seq2}. Of course, \var{seq1} or \var{seq2} may be empty: \kbd{if ($a$,\var{seq})} evaluates \var{seq} if $a$ is not equal to zero (you don't have to write the second comma), and does nothing otherwise, \kbd{if ($a$,,\var{seq})} evaluates \var{seq} if $a$ is equal to zero, and does nothing otherwise. You could get the same result using the \kbd{!} (\kbd{not}) operator: \kbd{if (!$a$,\var{seq})}. The value of an \kbd{if} statement is the value of the branch that gets evaluated: for instance \bprog x = if(n % 4 == 1, y, z); @eprog\noindent sets $x$ to $y$ if $n$ is $1$ modulo $4$, and to $z$ otherwise. Successive 'else' blocks can be abbreviated in a single compound \kbd{if} as follows: \bprog if (test1, seq1, test2, seq2, ... testn, seqn, seqdefault); @eprog\noindent is equivalent to \bprog if (test1, seq1 , if (test2, seq2 , ... if (testn, seqn, seqdefault)...)); @eprog For instance, this allows to write traditional switch / case constructions: \bprog if (x == 0, do0(), x == 1, do1(), x == 2, do2(), dodefault()); @eprog \misctitle{Remark} The boolean operators \kbd{\&\&} and \kbd{||} are evaluated according to operator precedence as explained in \secref{se:operators}, but, contrary to other operators, the evaluation of the arguments is stopped as soon as the final truth value has been determined. For instance \bprog if (x != 0 && f(1/x), ...) @eprog \noindent is a perfectly safe statement. \misctitle{Remark} Functions such as \kbd{break} and \kbd{next} operate on \emph{loops}, such as \kbd{for$xxx$}, \kbd{while}, \kbd{until}. The \kbd{if} statement is \emph{not} a loop. (Obviously!) Function: _void_if C-Name: ifpari_void Section: programming/internals Prototype: vGDIDI Help: internal variant of if() that does not return a value. Function: _multi_if C-Name: ifpari_multi Section: programming/internals Prototype: GE* Help: internal variant of if() that allows more than 3 arguments. pari-2.11.2/src/functions/programming/forvec0000644000175000017500000000320013201017466017501 0ustar billbillFunction: _forvec_init Class: gp2c_internal Help: Initializes parameters for forvec. Description: (forvec, gen, ?small):void forvec_init(&$1, $2, $3) Function: _forvec_next Class: gp2c_internal Help: Initializes parameters for forvec. Description: (forvec):vec forvec_next(&$1) Function: forvec Section: programming/control C-Name: forvec Prototype: vV=GID0,L, Iterator: (gen,gen,?small) (forvec, _forvec_init, _forvec_next) Help: forvec(X=v,seq,{flag=0}): v being a vector of two-component vectors of length n, the sequence is evaluated with X[i] going from v[i][1] to v[i][2] for i=n,..,1 if flag is zero or omitted. If flag = 1 (resp. flag = 2), restrict to increasing (resp. strictly increasing) sequences. Doc: Let $v$ be an $n$-component vector (where $n$ is arbitrary) of two-component vectors $[a_i,b_i]$ for $1\le i\le n$, where all entries $a_i$, $b_i$ are real numbers. This routine lets $X$ vary over the $n$-dimensional hyperrectangle given by $v$, that is, $X$ is an $n$-dimensional vector taking successively its entries $X[i]$ in the range $[a_i,b_i]$ with lexicographic ordering. (The component with the highest index moves the fastest.) The type of $X$ is the same as the type of $v$: \typ{VEC} or \typ{COL}. The expression \var{seq} is evaluated with the successive values of $X$. If $\fl=1$, generate only nondecreasing vectors $X$, and if $\fl=2$, generate only strictly increasing vectors $X$. \bprog ? forvec (X=[[0,1],[-1,1]], print(X)); [0, -1] [0, 0] [0, 1] [1, -1] [1, 0] [1, 1] ? forvec (X=[[0,1],[-1,1]], print(X), 1); [0, 0] [0, 1] [1, 1] ? forvec (X=[[0,1],[-1,1]], print(X), 2) [0, 1] @eprog pari-2.11.2/src/functions/programming/printf0000644000175000017500000001717513201017466017537 0ustar billbillFunction: printf Section: programming/specific C-Name: printf0 Prototype: vss* Help: printf(fmt,{x}*): prints its arguments according to the format fmt. Doc: This function is based on the C library command of the same name. It prints its arguments according to the format \var{fmt}, which specifies how subsequent arguments are converted for output. The format is a character string composed of zero or more directives: \item ordinary characters (not \kbd{\%}), printed unchanged, \item conversions specifications (\kbd{\%} followed by some characters) which fetch one argument from the list and prints it according to the specification. More precisely, a conversion specification consists in a \kbd{\%}, one or more optional flags (among \kbd{\#}, \kbd{0}, \kbd{-}, \kbd{+}, ` '), an optional decimal digit string specifying a minimal field width, an optional precision in the form of a period (`\kbd{.}') followed by a decimal digit string, and the conversion specifier (among \kbd{d},\kbd{i}, \kbd{o}, \kbd{u}, \kbd{x},\kbd{X}, \kbd{p}, \kbd{e},\kbd{E}, \kbd{f}, \kbd{g},\kbd{G}, \kbd{s}). \misctitle{The flag characters} The character \kbd{\%} is followed by zero or more of the following flags: \item \kbd{\#}: the value is converted to an ``alternate form''. For \kbd{o} conversion (octal), a \kbd{0} is prefixed to the string. For \kbd{x} and \kbd{X} conversions (hexa), respectively \kbd{0x} and \kbd{0X} are prepended. For other conversions, the flag is ignored. \item \kbd{0}: the value should be zero padded. For \kbd{d}, \kbd{i}, \kbd{o}, \kbd{u}, \kbd{x}, \kbd{X} \kbd{e}, \kbd{E}, \kbd{f}, \kbd{F}, \kbd{g}, and \kbd{G} conversions, the value is padded on the left with zeros rather than blanks. (If the \kbd{0} and \kbd{-} flags both appear, the \kbd{0} flag is ignored.) \item \kbd{-}: the value is left adjusted on the field boundary. (The default is right justification.) The value is padded on the right with blanks, rather than on the left with blanks or zeros. A \kbd{-} overrides a \kbd{0} if both are given. \item \kbd{` '} (a space): a blank is left before a positive number produced by a signed conversion. \item \kbd{+}: a sign (+ or -) is placed before a number produced by a signed conversion. A \kbd{+} overrides a space if both are used. \misctitle{The field width} An optional decimal digit string (whose first digit is non-zero) specifying a \emph{minimum} field width. If the value has fewer characters than the field width, it is padded with spaces on the left (or right, if the left-adjustment flag has been given). In no case does a small field width cause truncation of a field; if the value is wider than the field width, the field is expanded to contain the conversion result. Instead of a decimal digit string, one may write \kbd{*} to specify that the field width is given in the next argument. \misctitle{The precision} An optional precision in the form of a period (`\kbd{.}') followed by a decimal digit string. This gives the number of digits to appear after the radix character for \kbd{e}, \kbd{E}, \kbd{f}, and \kbd{F} conversions, the maximum number of significant digits for \kbd{g} and \kbd{G} conversions, and the maximum number of characters to be printed from an \kbd{s} conversion. Instead of a decimal digit string, one may write \kbd{*} to specify that the field width is given in the next argument. \misctitle{The length modifier} This is ignored under \kbd{gp}, but necessary for \kbd{libpari} programming. Description given here for completeness: \item \kbd{l}: argument is a \kbd{long} integer. \item \kbd{P}: argument is a \kbd{GEN}. \misctitle{The conversion specifier} A character that specifies the type of conversion to be applied. \item \kbd{d}, \kbd{i}: a signed integer. \item \kbd{o}, \kbd{u}, \kbd{x}, \kbd{X}: an unsigned integer, converted to unsigned octal (\kbd{o}), decimal (\kbd{u}) or hexadecimal (\kbd{x} or \kbd{X}) notation. The letters \kbd{abcdef} are used for \kbd{x} conversions; the letters \kbd{ABCDEF} are used for \kbd{X} conversions. \item \kbd{e}, \kbd{E}: the (real) argument is converted in the style \kbd{[ -]d.ddd e[ -]dd}, where there is one digit before the decimal point, and the number of digits after it is equal to the precision; if the precision is missing, use the current \kbd{realprecision} for the total number of printed digits. If the precision is explicitly 0, no decimal-point character appears. An \kbd{E} conversion uses the letter \kbd{E} rather than \kbd{e} to introduce the exponent. \item \kbd{f}, \kbd{F}: the (real) argument is converted in the style \kbd{[ -]ddd.ddd}, where the number of digits after the decimal point is equal to the precision; if the precision is missing, use the current \kbd{realprecision} for the total number of printed digits. If the precision is explicitly 0, no decimal-point character appears. If a decimal point appears, at least one digit appears before it. \item \kbd{g}, \kbd{G}: the (real) argument is converted in style \kbd{e} or \kbd{f} (or \kbd{E} or \kbd{F} for \kbd{G} conversions) \kbd{[ -]ddd.ddd}, where the total number of digits printed is equal to the precision; if the precision is missing, use the current \kbd{realprecision}. If the precision is explicitly 0, it is treated as 1. Style \kbd{e} is used when the decimal exponent is $< -4$, to print \kbd{0.}, or when the integer part cannot be decided given the known significant digits, and the \kbd{f} format otherwise. \item \kbd{c}: the integer argument is converted to an unsigned char, and the resulting character is written. \item \kbd{s}: convert to a character string. If a precision is given, no more than the specified number of characters are written. \item \kbd{p}: print the address of the argument in hexadecimal (as if by \kbd{\%\#x}). \item \kbd{\%}: a \kbd{\%} is written. No argument is converted. The complete conversion specification is \kbd{\%\%}. \noindent Examples: \bprog ? printf("floor: %d, field width 3: %3d, with sign: %+3d\n", Pi, 1, 2); floor: 3, field width 3: 1, with sign: +2 ? printf("%.5g %.5g %.5g\n",123,123/456,123456789); 123.00 0.26974 1.2346 e8 ? printf("%-2.5s:%2.5s:%2.5s\n", "P", "PARI", "PARIGP"); P :PARI:PARIG \\ min field width and precision given by arguments ? x = 23; y=-1/x; printf("x=%+06.2f y=%+0*.*f\n", x, 6, 2, y); x=+23.00 y=-00.04 \\ minimum fields width 5, pad left with zeroes ? for (i = 2, 5, printf("%05d\n", 10^i)) 00100 01000 10000 100000 \\@com don't truncate fields whose length is larger than the minimum width ? printf("%.2f |%06.2f|", Pi,Pi) 3.14 | 3.14| @eprog\noindent All numerical conversions apply recursively to the entries of vectors and matrices: \bprog ? printf("%4d", [1,2,3]); [ 1, 2, 3] ? printf("%5.2f", mathilbert(3)); [ 1.00 0.50 0.33] [ 0.50 0.33 0.25] [ 0.33 0.25 0.20] @eprog \misctitle{Technical note} Our implementation of \tet{printf} deviates from the C89 and C99 standards in a few places: \item whenever a precision is missing, the current \kbd{realprecision} is used to determine the number of printed digits (C89: use 6 decimals after the radix character). \item in conversion style \kbd{e}, we do not impose that the exponent has at least two digits; we never write a \kbd{+} sign in the exponent; 0 is printed in a special way, always as \kbd{0.E\var{exp}}. \item in conversion style \kbd{f}, we switch to style \kbd{e} if the exponent is greater or equal to the precision. \item in conversion \kbd{g} and \kbd{G}, we do not remove trailing zeros from the fractional part of the result; nor a trailing decimal point; 0 is printed in a special way, always as \kbd{0.E\var{exp}}. %\syn{NO} pari-2.11.2/src/functions/programming/getenv0000644000175000017500000000037412314242551017515 0ustar billbillFunction: getenv Section: programming/specific C-Name: gp_getenv Prototype: s Help: getenv(s): value of the environment variable s, 0 if it is not defined. Doc: return the value of the environment variable \kbd{s} if it is defined, otherwise return 0. pari-2.11.2/src/functions/programming/writetex0000644000175000017500000000037011636712103020075 0ustar billbillFunction: writetex Section: programming/specific C-Name: writetex Prototype: vss* Help: writetex(filename,{str}*): appends the remaining arguments (same format as print) to filename, in TeX format. Doc: as \kbd{write}, in \TeX\ format. %\syn{NO} pari-2.11.2/src/functions/programming/while0000644000175000017500000000061311636712103017332 0ustar billbillFunction: while Section: programming/control C-Name: whilepari Prototype: vEI Help: while(a,seq): while a is nonzero evaluate the expression sequence seq. Otherwise 0. Doc: while $a$ is non-zero, evaluates the expression sequence \var{seq}. The test is made \emph{before} evaluating the $seq$, hence in particular if $a$ is initially equal to zero the \var{seq} will not be evaluated at all. pari-2.11.2/src/functions/programming/fileread0000644000175000017500000000214613326135265020006 0ustar billbillFunction: fileread Section: programming/specific C-Name: gp_fileread Prototype: L Help: fileread(n): read a logical line from the file attached to the descriptor n, opened for reading with fileopen. Return 0 at end of file. Doc: read a logical line from the file attached to the descriptor $n$, opened for reading with \kbd{fileopen}. Return 0 at end of file. A logical line is a full command as it is prepared by gp's preprocessor (skipping blanks and comments or assembling multiline commands between braces) before being fed to the interpreter. The function \kbd{filereadstr} would read a \emph{raw} line exactly as input, up to the next carriage return \kbd{\bs n}. Compare raw lines \bprog ? n = fileopen("examples/bench.gp"); ? while(l = filereadstr(n), print(l)); { u=v=p=q=1; for (k=1, 2000, [u,v] = [v,u+v]; p *= v; q = lcm(q,v); if (k%50 == 0, print(k, " ", log(p)/log(q)) ) ) } @eprog\noindent and logical lines \bprog ? n = fileopen("examples/bench.gp"); ? while(l = fileread(n), print(l)); u=v=p=q=1;for(k=1,2000,[u,v]=[v,u+v];p*=v;q=lcm(q,v);[...] @eprog pari-2.11.2/src/functions/programming/forsubset0000644000175000017500000000355513326135265020254 0ustar billbillFunction: _forsubset_init Class: gp2c_internal Help: Initialize forsubset_t Description: (forsubset,small):void forallsubset_init(&$1, $2) (forsubset,gen):void forsubset_init(&$1, $2) Function: _forsubset_next Class: gp2c_internal Help: Compute the next subset Description: (forsubset):vecsmall forsubset_next(&$1) Function: forsubset Section: programming/control C-Name: forsubset0 Prototype: vGVI Iterator: (gen,gen) (forsubset, _forsubset_init, _forsubset_next) Wrapper: (,vG,,) Help: forsubset(nk, s, seq): if nk is an integer n, the sequence is evaluated, s going through all subsets of {1, 2, ..., n}; if nk is a pair [n,k] of integers s goes through k-subsets of {1, 2, ..., n}. The order is lexicographic among subsets of the same size and smaller subsets come first. Doc: if \var{nk} is a non-negative integer $n$, evaluates \kbd{seq}, where the formal variable $s$ goes through all subsets of $\{1, 2, \ldots, n\}$; if \var{nk} is a pair $[n,k]$ of integers, $s$ goes through subsets of size $k$ of $\{1, 2, \ldots, n\}$. In both cases $s$ goes through subsets in lexicographic order among subsets of the same size and smaller subsets come first. \bprog ? forsubset([5,3], s, print(s)) Vecsmall([1, 2, 3]) Vecsmall([1, 2, 4]) Vecsmall([1, 2, 5]) Vecsmall([1, 3, 4]) Vecsmall([1, 3, 5]) Vecsmall([1, 4, 5]) Vecsmall([2, 3, 4]) Vecsmall([2, 3, 5]) Vecsmall([2, 4, 5]) Vecsmall([3, 4, 5]) @eprog \bprog ? forsubset(3, s, print(s)) Vecsmall([]) Vecsmall([1]) Vecsmall([2]) Vecsmall([3]) Vecsmall([1, 2]) Vecsmall([1, 3]) Vecsmall([2, 3]) Vecsmall([1, 2, 3]) @eprog\noindent The running time is proportional to the number of subsets enumerated, respectively $2^n$ and \kbd{binomial}$(n,k)$: \bprog ? c = 0; forsubset([40,35],s,c++); c time = 128 ms. %4 = 658008 ? binomial(40,35) %5 = 658008 @eprog pari-2.11.2/src/functions/programming/iferr0000644000175000017500000002400313216034034017324 0ustar billbillFunction: _iferr_CATCH Class: gp2c_internal Description: (0) pari_CATCH(CATCH_ALL) (small) pari_CATCH2(__iferr_old$1, CATCH_ALL) Function: _iferr_ENDCATCH Class: gp2c_internal Description: (0) pari_ENDCATCH (small) pari_ENDCATCH2(__iferr_old$1) Function: _iferr_CATCH_reset Class: gp2c_internal Description: (0):void pari_CATCH_reset() (small):void pari_CATCH2_reset(__iferr_old$1) Function: _iferr_error Class: gp2c_internal Description: ():error pari_err_last() Function: _iferr_rethrow Class: gp2c_internal Description: (error):void pari_err(0, $1) Function: iferr Section: programming/control C-Name: iferrpari Prototype: EVEDE Help: iferr(seq1,E,seq2,{pred}): evaluates the expression sequence seq1. If an error occurs, set the formal parameter E set to the error data. If pred is not present or evaluates to true, catch the error and evaluate seq2. Both pred and seq2 can reference E. Doc: evaluates the expression sequence \var{seq1}. If an error occurs, set the formal parameter \var{E} set to the error data. If \var{pred} is not present or evaluates to true, catch the error and evaluate \var{seq2}. Both \var{pred} and \var{seq2} can reference \var{E}. The error type is given by \kbd{errname(E)}, and other data can be accessed using the \tet{component} function. The code \var{seq2} should check whether the error is the one expected. In the negative the error can be rethrown using \tet{error(E)} (and possibly caught by an higher \kbd{iferr} instance). The following uses \kbd{iferr} to implement Lenstra's ECM factoring method \bprog ? ecm(N, B = 1000!, nb = 100)= { for(a = 1, nb, iferr(ellmul(ellinit([a,1]*Mod(1,N)), [0,1]*Mod(1,N), B), E, return(gcd(lift(component(E,2)),N)), errname(E)=="e_INV" && type(component(E,2)) == "t_INTMOD")) } ? ecm(2^101-1) %2 = 7432339208719 @eprog The return value of \kbd{iferr} itself is the value of \var{seq2} if an error occurs, and the value of \var{seq1} otherwise. We now describe the list of valid error types, and the attached error data \var{E}; in each case, we list in order the components of \var{E}, accessed via \kbd{component(E,1)}, \kbd{component(E,2)}, etc. \misctitle{Internal errors, ``system'' errors} \item \kbd{"e\_ARCH"}. A requested feature $s$ is not available on this architecture or operating system. \var{E} has one component (\typ{STR}): the missing feature name $s$. \item \kbd{"e\_BUG"}. A bug in the PARI library, in function $s$. \var{E} has one component (\typ{STR}): the function name $s$. \item \kbd{"e\_FILE"}. Error while trying to open a file. \var{E} has two components, 1 (\typ{STR}): the file type (input, output, etc.), 2 (\typ{STR}): the file name. \item \kbd{"e\_IMPL"}. A requested feature $s$ is not implemented. \var{E} has one component, 1 (\typ{STR}): the feature name $s$. \item \kbd{"e\_PACKAGE"}. Missing optional package $s$. \var{E} has one component, 1 (\typ{STR}): the package name $s$. \misctitle{Syntax errors, type errors} \item \kbd{"e\_DIM"}. The dimensions of arguments $x$ and $y$ submitted to function $s$ does not match up. E.g., multiplying matrices of inconsistent dimension, adding vectors of different lengths,\dots \var{E} has three component, 1 (\typ{STR}): the function name $s$, 2: the argument $x$, 3: the argument $y$. \item \kbd{"e\_FLAG"}. A flag argument is out of bounds in function $s$. \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_NOTFUNC"}. Generated by the PARI evaluator; tried to use a \kbd{GEN} $x$ which is not a \typ{CLOSURE} in a function call syntax (as in \kbd{f = 1; f(2);}). \var{E} has one component, 1: the offending \kbd{GEN} $x$. \item \kbd{"e\_OP"}. Impossible operation between two objects than cannot be typecast to a sensible common domain for deeper reasons than a type mismatch, usually for arithmetic reasons. As in \kbd{O(2) + O(3)}: it is valid to add two \typ{PADIC}s, provided the underlying prime is the same; so the addition is not forbidden a priori for type reasons, it only becomes so when inspecting the objects and trying to perform the operation. \var{E} has three components, 1 (\typ{STR}): the operator name \var{op}, 2: first argument, 3: second argument. \item \kbd{"e\_TYPE"}. An argument $x$ of function $s$ had an unexpected type. (As in \kbd{factor("blah")}.) \var{E} has two components, 1 (\typ{STR}): the function name $s$, 2: the offending argument $x$. \item \kbd{"e\_TYPE2"}. Forbidden operation between two objects than cannot be typecast to a sensible common domain, because their types do not match up. (As in \kbd{Mod(1,2) + Pi}.) \var{E} has three components, 1 (\typ{STR}): the operator name \var{op}, 2: first argument, 3: second argument. \item \kbd{"e\_PRIORITY"}. Object $o$ in function $s$ contains variables whose priority is incompatible with the expected operation. E.g.~\kbd{Pol([x,1], 'y)}: this raises an error because it's not possible to create a polynomial whose coefficients involve variables with higher priority than the main variable. $E$ has four components: 1 (\typ{STR}): the function name $s$, 2: the offending argument $o$, 3 (\typ{STR}): an operator $\var{op}$ describing the priority error, 4 (\typ{POL}): the variable $v$ describing the priority error. The argument satisfies $\kbd{variable}(x)~\var{op} \kbd{variable}(v)$. \item \kbd{"e\_VAR"}. The variables of arguments $x$ and $y$ submitted to function $s$ does not match up. E.g., considering the algebraic number \kbd{Mod(t,t\pow2+1)} in \kbd{nfinit(x\pow2+1)}. \var{E} has three component, 1 (\typ{STR}): the function name $s$, 2 (\typ{POL}): the argument $x$, 3 (\typ{POL}): the argument $y$. \misctitle{Overflows} \item \kbd{"e\_COMPONENT"}. Trying to access an inexistent component in a vector/matrix/list in a function: the index is less than $1$ or greater than the allowed length. \var{E} has four components, 1 (\typ{STR}): the function name 2 (\typ{STR}): an operator $\var{op}$ ($<$ or $>$), 2 (\typ{GEN}): a numerical limit $l$ bounding the allowed range, 3 (\kbd{GEN}): the index $x$. It satisfies $x$ \var{op} $l$. \item \kbd{"e\_DOMAIN"}. An argument is not in the function's domain. \var{E} has five components, 1 (\typ{STR}): the function name, 2 (\typ{STR}): the mathematical name of the out-of-domain argument 3 (\typ{STR}): an operator $\var{op}$ describing the domain error, 4 (\typ{GEN}): the numerical limit $l$ describing the domain error, 5 (\kbd{GEN}): the out-of-domain argument $x$. The argument satisfies $x$ \var{op} $l$, which prevents it from belonging to the function's domain. \item \kbd{"e\_MAXPRIME"}. A function using the precomputed list of prime numbers ran out of primes. \var{E} has one component, 1 (\typ{INT}): the requested prime bound, which overflowed \kbd{primelimit} or $0$ (bound is unknown). \item \kbd{"e\_MEM"}. A call to \tet{pari_malloc} or \tet{pari_realloc} failed. \var{E} has no component. \item \kbd{"e\_OVERFLOW"}. An object in function $s$ becomes too large to be represented within PARI's hardcoded limits. (As in \kbd{2\pow2\pow2\pow10} or \kbd{exp(1e100)}, which overflow in \kbd{lg} and \kbd{expo}.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_PREC"}. Function $s$ fails because input accuracy is too low. (As in \kbd{floor(1e100)} at default accuracy.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_STACK"}. The PARI stack overflows. \var{E} has no component. \misctitle{Errors triggered intentionally} \item \kbd{"e\_ALARM"}. A timeout, generated by the \tet{alarm} function. \var{E} has one component (\typ{STR}): the error message to print. \item \kbd{"e\_USER"}. A user error, as triggered by \tet{error}($g_1,\dots,g_n)$. \var{E} has one component, 1 (\typ{VEC}): the vector of $n$ arguments given to \kbd{error}. \misctitle{Mathematical errors} \item \kbd{"e\_CONSTPOL"}. An argument of function $s$ is a constant polynomial, which does not make sense. (As in \kbd{galoisinit(Pol(1))}.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_COPRIME"}. Function $s$ expected coprime arguments, and did receive $x,y$, which were not. \var{E} has three component, 1 (\typ{STR}): the function name $s$, 2: the argument $x$, 3: the argument $y$. \item \kbd{"e\_INV"}. Tried to invert a non-invertible object $x$ in function $s$. \var{E} has two components, 1 (\typ{STR}): the function name $s$, 2: the non-invertible $x$. If $x = \kbd{Mod}(a,b)$ is a \typ{INTMOD} and $a$ is not $0$ mod $b$, this allows to factor the modulus, as \kbd{gcd}$(a,b)$ is a non-trivial divisor of $b$. \item \kbd{"e\_IRREDPOL"}. Function $s$ expected an irreducible polynomial, and did receive $T$, which was not. (As in \kbd{nfinit(x\pow2-1)}.) \var{E} has two component, 1 (\typ{STR}): the function name $s$, 2 (\typ{POL}): the polynomial $x$. \item \kbd{"e\_MISC"}. Generic uncategorized error. \var{E} has one component (\typ{STR}): the error message to print. \item \kbd{"e\_MODULUS"}. moduli $x$ and $y$ submitted to function $s$ are inconsistent. As in \bprog nfalgtobasis(nfinit(t^3-2), Mod(t,t^2+1) @eprog\noindent \var{E} has three component, 1 (\typ{STR}): the function $s$, 2: the argument $x$, 3: the argument $x$. \item \kbd{"e\_PRIME"}. Function $s$ expected a prime number, and did receive $p$, which was not. (As in \kbd{idealprimedec(nf, 4)}.) \var{E} has two component, 1 (\typ{STR}): the function name $s$, 2: the argument $p$. \item \kbd{"e\_ROOTS0"}. An argument of function $s$ is a zero polynomial, and we need to consider its roots. (As in \kbd{polroots(0)}.) \var{E} has one component, 1 (\typ{STR}): the function name $s$. \item \kbd{"e\_SQRTN"}. Trying to compute an $n$-th root of $x$, which does not exist, in function $s$. (As in \kbd{sqrt(Mod(-1,3))}.) \var{E} has two components, 1 (\typ{STR}): the function name $s$, 2: the argument $x$. pari-2.11.2/src/functions/programming/forpart0000644000175000017500000000510313326135265017704 0ustar billbillFunction: _forpart_init Class: gp2c_internal Help: Initialize forpart_t Description: (forpart,small,?gen,?gen):void forpart_init(&$1, $2, $3, $4) Function: _forpart_next Class: gp2c_internal Help: Compute the next part Description: (forpart):vecsmall forpart_next(&$1) Function: forpart Section: programming/control C-Name: forpart0 Prototype: vV=GIDGDG Iterator: (gen,small,?gen,?gen) (forpart, _forpart_init, _forpart_next) Wrapper: (,vG,,) Description: (small,closure,?gen,?gen):void forpart(${2 cookie}, ${2 wrapper}, $1, $3, $4) Help: forpart(X=k,seq,{a=k},{n=k}): evaluate seq where the Vecsmall X goes over the partitions of k. Optional parameter n (n=nmax or n=[nmin,nmax]) restricts the length of the partition. Optional parameter a (a=amax or a=[amin,amax]) restricts the range of the parts. Zeros are removed unless one sets amin=0 to get X of fixed length nmax (=k by default). Doc: evaluate \var{seq} over the partitions $X=[x_1,\dots x_n]$ of the integer $k$, i.e.~increasing sequences $x_1\leq x_2\dots \leq x_n$ of sum $x_1+\dots + x_n=k$. By convention, $0$ admits only the empty partition and negative numbers have no partitions. A partition is given by a \typ{VECSMALL}, where parts are sorted in nondecreasing order. The partitions are listed by increasing size and in lexicographic order when sizes are equal: \bprog ? forpart(X=4, print(X)) Vecsmall([4]) Vecsmall([1, 3]) Vecsmall([2, 2]) Vecsmall([1, 1, 2]) Vecsmall([1, 1, 1, 1]) @eprog\noindent Optional parameters $n$ and $a$ are as follows: \item $n=\var{nmax}$ (resp. $n=[\var{nmin},\var{nmax}]$) restricts partitions to length less than $\var{nmax}$ (resp. length between $\var{nmin}$ and $nmax$), where the \emph{length} is the number of nonzero entries. \item $a=\var{amax}$ (resp. $a=[\var{amin},\var{amax}]$) restricts the parts to integers less than $\var{amax}$ (resp. between $\var{amin}$ and $\var{amax}$). By default, parts are positive and we remove zero entries unless $amin\leq0$, in which case we fix the size $\#X = \var{nmax}$: \bprog \\ at most 3 non-zero parts, all <= 4 ? forpart(v=5,print(Vec(v)), 4, 3) [1, 4] [2, 3] [1, 1, 3] [1, 2, 2] \\ between 2 and 4 parts less than 5, fill with zeros ? forpart(v=5,print(Vec(v)),[0,5],[2,4]) [0, 0, 1, 4] [0, 0, 2, 3] [0, 1, 1, 3] [0, 1, 2, 2] [1, 1, 1, 2] \\ no partitions of 1 with 2 to 4 non-zero parts ? forpart(v=1,print(v),[0,5],[2,4]) ? @eprog\noindent The behavior is unspecified if $X$ is modified inside the loop. \synt{forpart}{void *data, long (*call)(void*,GEN), long k, GEN a, GEN n}. pari-2.11.2/src/functions/programming/inline0000644000175000017500000000075713201017466017511 0ustar billbillFunction: inline Section: programming/specific Help: inline(x,...,z): declares x,...,z as inline variables [EXPERIMENTAL]. Doc: (Experimental) declare $x,\ldots, z$ as inline variables. Such variables behave like lexically scoped variable (see my()) but with unlimited scope. It is however possible to exit the scope by using \kbd{uninline()}. When used in a GP script, it is recommended to call \kbd{uninline()} before the script's end to avoid inline variables leaking outside the script. pari-2.11.2/src/functions/programming/printp0000644000175000017500000000105413326135265017544 0ustar billbillFunction: printp Section: programming/specific C-Name: printp Prototype: vs* Help: printp({str}*): outputs its string arguments (in prettymatrix format) ending with a newline. Description: (?gen,...):void pari_printf("${2 format_string}\n"${2 format_args}) Doc: outputs its arguments in prettymatrix format, ending with a newline. The arguments are converted to strings following the rules in \secref{se:strings}. \bprog ? m = matid(2); ? print(m) \\ raw format [1, 0; 0, 1] ? printp(m) \\ prettymatrix format [1 0] [0 1] @eprog %\syn{NO} pari-2.11.2/src/functions/programming/printtex0000644000175000017500000000124713326135265020111 0ustar billbillFunction: printtex Section: programming/specific C-Name: printtex Prototype: vs* Help: printtex({str}*): outputs its string arguments in TeX format. Doc: outputs its arguments in \TeX\ format. This output can then be used in a \TeX\ manuscript. The arguments are converted to strings following the rules in \secref{se:strings}. The printing is done on the standard output. If you want to print it to a file you should use \kbd{writetex} (see there). Another possibility is to enable the \tet{log} default (see~\secref{se:defaults}). You could for instance do:\sidx{logfile} % \bprog default(logfile, "new.tex"); default(log, 1); printtex(result); @eprog %\syn{NO} pari-2.11.2/src/functions/programming/write10000644000175000017500000000047111636712103017437 0ustar billbillFunction: write1 Section: programming/specific C-Name: write1 Prototype: vss* Help: write1(filename,{str}*): appends the remaining arguments (same output as print1) to filename. Doc: writes (appends) to \var{filename} the remaining arguments without a trailing newline (same output as \kbd{print1}). %\syn{NO} pari-2.11.2/src/functions/programming/fileflush0000644000175000017500000000222613326135265020213 0ustar billbillFunction: fileflush Section: programming/specific C-Name: gp_fileflush0 Prototype: vDG Help: fileflush({n}): flush the file descriptor n (all descriptors to output streams if n is omitted). Doc: flushes the file descriptor $n$, created via \kbd{fileopen} or \kbd{fileextern}. On files opened for writing, this function forces a write of all buffered data to the file system and completes all pending write operations. This function is implicitly called by \kbd{fileclose} but you may want to call it explicitly at synchronization points, for instance after writing a large result to file and before printing diagnostics on screen. (In order to be sure that the file contains the expected content on inspection.) If $n$ is omitted, flush all descriptors to output streams. \bprog ? n = fileopen("./here", "w"); ? for (i = 1, 10^5, \ filewrite(n, i^2+1); \ if (i % 10000 == 0, fileflush(n))) @eprog Until a \kbd{fileflush} or \kbd{fileclose}, there is no guarantee that the file contains all the expected data from previous \kbd{filewrite}s. Variant: But the direct and more specific variant \fun{void}{gp_fileflush}{long n} is also available. pari-2.11.2/src/functions/programming/getwalltime0000644000175000017500000000052713326135265020552 0ustar billbillFunction: getwalltime Section: programming/specific C-Name: getwalltime Prototype: Help: getwalltime(): time (in milliseconds) since the UNIX Epoch. Doc: returns the time (in milliseconds) elapsed since 00:00:00 UTC Thursday 1, January 1970 (the Unix epoch). \bprog my (t = getwalltime()); ... print("Time: ", getwalltime() - t); @eprog pari-2.11.2/src/functions/programming/forsquarefree0000644000175000017500000000676013326135265021112 0ustar billbillFunction: forsquarefree Section: programming/control C-Name: forsquarefree Prototype: vV=GGI Help: forsquarefree(N=a,b,seq): the sequence is evaluated, N is of the form [n, factor(n)], n going through squarefree integers from a up to b; one must have a*b >= 0. Doc: evaluates \var{seq}, where the formal variable $N$ is $[n, \kbd{factor}(n)]$ and $n$ goes through squarefree integers from $a$ to $b$; $a$ and $b$ must be integers of the same sign. Nothing is done if $a>b$. \bprog ? forsquarefree(N=2,10,print(N)) [2, Mat([2, 1])] [3, Mat([3, 1])] [5, Mat([5, 1])] [6, [2, 1; 3, 1]] [7, Mat([7, 1])] [10, [2, 1; 5, 1]] \\ negative numbers are allowed as well ? forsquarefree(N=-10,-3,print(N)) [-10, [-1, 1; 2, 1; 5, 1]] [-7, [-1, 1; 7, 1]] [-6, [-1, 1; 2, 1; 3, 1]] [-5, [-1, 1; 5, 1]] [-3, [-1, 1; 3, 1]] \\ but not bounds of different signs ? forsquarefree(N=-3,3,print(N)) *** at top-level: forsquarefree(N=-3,3,print(N)) *** ^------------------------------ *** forsquarefree: incorrect type in forsquarefree [!= signs] (t_VEC). @eprog This function is only implemented for $|a|, |b| < 2^{64}$ ($2^{32}$ on a 32-bit machine). It uses a sieve and runs in time $O(\sqrt{b} + b-a)$. It should be at least 5 times faster than regular factorization as long as the interval length $b-a$ is much larger than $\sqrt{b}$ and get relatively faster as the bounds increase. The function slows down dramatically if $\kbd{primelimit} < \sqrt{b}$. It is comparable to \kbd{forfactored}, but about $\zeta(2) = \pi^2/6$ times faster due to the relative density of squarefree integers. \bprog ? B = 10^9; ? for (N = B, B+10^6, factor(N)) time = 4,392 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 915 ms. ? forsquarefree (N = B, B+10^6, [n,fan] = N) time = 532 ms. ? B = 10^11; ? for (N = B, B+10^6, factor(N)) time = 13,053 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 1,976 ms. ? forsquarefree (N = B, B+10^6, [n,fan] = N) time = 1,245 ms. ? B = 10^14; ? for (N = B, B+10^6, factor(N)) time = 50,612 ms. ? forsquarefree (N = B, B+10^6, [n,fan] = N) time = 46,309 ms. @eprog\noindent The last timing is with the default \kbd{primelimit} (500000) which is much less than $\sqrt{B+10^6}$; it goes down to \kbd{20,396ms} if \kbd{primelimit} gets bigger than that bound. In any case $\sqrt{B+10^6}$ is much larger than the interval length $10^6$ so \kbd{forsquarefree} gets relatively slower for that reason as well. Note that all PARI multiplicative functions accept the \kbd{[n,fan]} argument natively: \bprog ? s = 0; forsquarefree(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 3,788 ms. %1 = 6393738650 ? s = 0; for(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 28,630 ms. \\ slower, we must factor N. Twice. %2 = 6393738650 @eprog The following loops over the fundamental dicriminants less than $X$: \bprog ? X = 10^8; ? for(d=1,X, if (isfundamental(d),)) time = 1min, 29,066 ms. ? forfactored(d=1,X, if (isfundamental(d),)); time = 42,387 ms. ? forsquarefree(d=1,X, D = quaddisc(d); if (D <= X, )); time = 32,479 ms. @eprog\noindent Note that in the last loop, the fundamental discriminants $D$ are not evaluated in order (since \kbd{quaddisc(d)} for squarefree $d$ is either $d$ or $4d$). This is the price we pay for a faster evaluation, and the set of numbers we run through is the same. We can run through negative fundamental discriminants in the same way \bprog ? forsquarefree(d=-X,-1, D = quaddisc(d); if (D >= -X, )); @eprog pari-2.11.2/src/functions/programming/fileextern0000644000175000017500000000123613326135265020377 0ustar billbillFunction: fileextern Section: programming/specific C-Name: gp_fileextern Prototype: ls Help: fileextern(str): execute shell command str and returns a file descriptor attached to the command output as if it were read from a file. Doc: the string \var{str} is the name of an external command, i.e.~one you would type from your UNIX shell prompt. This command is immediately run and the function returns a file descriptor attached to the command output as if it were read from a file. \bprog ? n = fileextern("ls -l"); ? while(l = filereadstr(n), print(l)) ? fileclose(n) @eprog\noindent If the \kbd{secure} default is set, this function will raise en exception. pari-2.11.2/src/functions/programming/listput0000644000175000017500000000251313201017466017727 0ustar billbillFunction: listput Section: programming/specific C-Name: listput0 Prototype: WGD0,L, Help: listput(list,x,{n}): sets n-th element of list equal to x. If n is omitted or greater than the current list length, appends x. Description: (list, gen, small):gen listput($1, $2, $3) Doc: sets the $n$-th element of the list \var{list} (which must be of type \typ{LIST}) equal to $x$. If $n$ is omitted, or greater than the list length, appends $x$. The function returns the inserted element. \bprog ? L = List(); ? listput(L, 1) %2 = 1 ? listput(L, 2) %3 = 2 ? L %4 = List([1, 2]) @eprog You may put an element into an occupied cell (not changing the list length), but it is easier to use the standard \kbd{list[n] = x} construct. \bprog ? listput(L, 3, 1) \\ insert at position 1 %5 = 3 ? L %6 = List([3, 2]) ? L[2] = 4 \\ simpler %7 = List([3, 4]) ? L[10] = 1 \\ can't insert beyond the end of the list *** at top-level: L[10]=1 *** ^------ *** non-existent component: index > 2 ? listput(L, 1, 10) \\ but listput can %8 = 1 ? L %9 = List([3, 2, 1]) @eprog This function runs in time $O(\#L)$ in the worst case (when the list must be reallocated), but in time $O(1)$ on average: any number of successive \kbd{listput}s run in time $O(\#L)$, where $\#L$ denotes the list \emph{final} length. pari-2.11.2/src/functions/programming/fordivfactored0000644000175000017500000000256613326135265021242 0ustar billbillFunction: fordivfactored Section: programming/control C-Name: fordivfactored Prototype: vGVI Help: fordivfactored(n,X,seq): the sequence is evaluated, X running over the [d, factor(d)], d a divisor of n. Doc: evaluates \var{seq}, where the formal variable $X$ ranges through $[d, \kbd{factor}(d)]$, where $d$ is a divisors of $n$ (see \tet{divisors}, which is used as a subroutine). Note that such a pair is accepted as argument to all multiplicative functions. It is assumed that \kbd{factor} can handle $n$, without negative exponents. Instead of $n$, it is possible to input a factorization matrix, i.e. the output of \kbd{factor(n)}. This routine uses \kbd{divisors}$(,1)$ as a subroutine, then loops over the divisors. In particular, if $n$ is an integer, divisors are sorted by increasing size. This function is particularly useful when $n$ is hard to factor and one must evaluate multiplicative function on its divisors: we avoid refactoring each divisor in turn. It also provides a small speedup when $n$ is easy to factor; compare \bprog ? A = 10^8; B = A + 10^5; ? for (n = A, B, fordiv(n, d, eulerphi(d))); time = 2,091 ms. ? for (n = A, B, fordivfactored(n, d, eulerphi(d))); time = 1,298 ms. \\ avoid refactoring the divisors ? forfactored (n = A, B, fordivfactored(n, d, eulerphi(d))); time = 1,270 ms. \\ also avoid factoring the consecutive n's ! @eprog pari-2.11.2/src/functions/programming/dbg_err0000644000175000017500000000127112314242551017626 0ustar billbillFunction: dbg_err Class: gp Section: programming/control C-Name: dbg_err Prototype: Help: dbg_err(): (break loop) return the error data of the current error, if any. Doc: In the break loop, return the error data of the current error, if any. See \tet{iferr} for details about error data. Compare: \bprog ? iferr(1/(Mod(2,12019)^(6!)-1),E,Vec(E)) %1 = ["e_INV", "Fp_inv", Mod(119, 12019)] ? 1/(Mod(2,12019)^(6!)-1) *** at top-level: 1/(Mod(2,12019)^(6!)- *** ^-------------------- *** _/_: impossible inverse in Fp_inv: Mod(119, 12019). *** Break loop: type 'break' to go back to GP prompt break> Vec(dbg_err()) ["e_INV", "Fp_inv", Mod(119, 12019)] @eprog pari-2.11.2/src/functions/programming/getrand0000644000175000017500000000067211636712103017653 0ustar billbillFunction: getrand Section: programming/specific C-Name: getrand Prototype: Help: getrand(): current value of random number seed. Doc: returns the current value of the seed used by the pseudo-random number generator \tet{random}. Useful mainly for debugging purposes, to reproduce a specific chain of computations. The returned value is technical (reproduces an internal state array), and can only be used as an argument to \tet{setrand}. pari-2.11.2/src/functions/programming/forell0000644000175000017500000000233113326135265017512 0ustar billbillFunction: forell Section: programming/control C-Name: forell0 Prototype: vVLLID0,L, Help: forell(E,a,b,seq,{flag=0}): execute seq for each elliptic curves E of conductor between a and b in the elldata database. If flag is non-zero, select only the first curve in each isogeny class. Wrapper: (,,,vG,) Description: (,small,small,closure,?small):void forell(${4 cookie}, ${4 wrapper}, $2, $3, $5) Doc: evaluates \var{seq}, where the formal variable $E = [\var{name}, M, G]$ ranges through all elliptic curves of conductors from $a$ to $b$. In this notation \var{name} is the curve name in Cremona's elliptic curve database, $M$ is the minimal model, $G$ is a $\Z$-basis of the free part of the Mordell-Weil group $E(\Q)$. If flag is non-zero, select only the first curve in each isogeny class. \bprog ? forell(E, 1, 500, my([name,M,G] = E); \ if (#G > 1, print(name))) 389a1 433a1 446d1 ? c = 0; forell(E, 1, 500, c++); c \\ number of curves %2 = 2214 ? c = 0; forell(E, 1, 500, c++, 1); c \\ number of isogeny classes %3 = 971 @eprog\noindent The \tet{elldata} database must be installed and contain data for the specified conductors. \synt{forell}{void *data, long (*f)(void*,GEN), long a, long b, long flag}. pari-2.11.2/src/functions/programming/mapget0000644000175000017500000000100413201017466017472 0ustar billbillFunction: mapget Section: programming/specific C-Name: mapget Prototype: GG Help: mapget(M,x): returns the image of x by the map M. Doc: Returns the image of $x$ by the map $M$. \bprog ? M=Map(["a",23;"b",43]); ? mapget(M,"a") %2 = 23 ? mapget(M,"b") %3 = 43 @eprog\noindent Raises an exception when the key $x$ is not present in $M$. \bprog ? mapget(M,"c") *** at top-level: mapget(M,"c") *** ^------------- *** mapget: non-existent component in mapget: index not in map @eprog pari-2.11.2/src/functions/programming/gettime0000644000175000017500000000071413326135265017670 0ustar billbillFunction: gettime Section: programming/specific C-Name: gettime Prototype: l Help: gettime(): milliseconds of CPU time used since the last call to gettime. Doc: returns the CPU time (in milliseconds) used since either the last call to \kbd{gettime}, or to the beginning of the containing GP instruction (if inside \kbd{gp}), whichever came last. For a reentrant version, see \tet{getabstime}. For a version giving wall-clock time, see \tet{getwalltime}. pari-2.11.2/src/functions/programming/forprime0000644000175000017500000000461313326135265020057 0ustar billbillFunction: _diffptr Class: gp2c_internal Help: Table of difference of primes. Description: ():bptr diffptr Function: _forprime_next Class: gp2c_internal Help: Compute the next prime from the diffptr table. Description: (*small,*bptr):void NEXT_PRIME_VIADIFF($1, $2) Function: _forprime_init Class: gp2c_internal Help: Initialize forprime_t. Description: (forprime,int,?int):void forprime_init(&$1, $2, $3); Function: _forprime_next_ Class: gp2c_internal Help: Compute the next prime. Description: (forprime):int forprime_next(&$1) Function: _u_forprime_init Class: gp2c_internal Help: Initialize forprime_t (ulong version). Description: (forprime,small,):void u_forprime_init(&$1, $2, LONG_MAX); (forprime,small,small):void u_forprime_init(&$1, $2, $3); Function: _u_forprime_next Class: gp2c_internal Help: Compute the next prime (ulong version). Description: (forprime):small u_forprime_next(&$1) Function: forprime Section: programming/control C-Name: forprime Prototype: vV=GDGI Help: forprime(p=a,{b},seq): the sequence is evaluated, p running over the primes between a and b. Omitting b runs through primes >= a. Iterator: (*notype,small,small) (forprime, _u_forprime_init, _u_forprime_next) (*notype,gen,gen,gen) (forprime, _forprime_init, _forprime_next_) (*small,gen,?gen) (forprime, _u_forprime_init, _u_forprime_next) (*int,gen,?gen) (forprime, _forprime_init, _forprime_next_) (gen,gen,?gen) (forprime, _forprime_init, _forprime_next_) Doc: evaluates \var{seq}, where the formal variable $p$ ranges over the prime numbers between the real numbers $a$ to $b$, including $a$ and $b$ if they are prime. More precisely, the value of $p$ is incremented to \kbd{nextprime($p$ + 1)}, the smallest prime strictly larger than $p$, at the end of each iteration. Nothing is done if $a>b$. \bprog ? forprime(p = 4, 10, print(p)) 5 7 @eprog\noindent Setting $b$ to \kbd{+oo} means we will run through all primes $\geq a$, starting an infinite loop; it is expected that the caller will break out of the loop itself at some point, using \kbd{break} or \kbd{return}. Note that the value of $p$ cannot be modified within \var{seq}: \bprog ? forprime(p = 2, 10, p = []) *** at top-level: forprime(p=2,10,p=[]) *** ^--- *** prime index read-only: was changed to []. @eprog pari-2.11.2/src/functions/programming/filereadstr0000644000175000017500000000120313326135265020530 0ustar billbillFunction: filereadstr Section: programming/specific C-Name: gp_filereadstr Prototype: L Help: filereadstr(n): read a raw line from the file attached to the descriptor n, opened for reading with fileopen. Discard the terminating newline. Return 0 at end of file. Doc: read a raw line from the file attached to the descriptor $n$, opened for reading with \kbd{fileopen}, discarding the terminating newline. In other words the line is read exactly as input, up to the next carriage return \kbd{\bs n}. By comparison, \kbd{fileread} would read a logical line, as assembled by gp's preprocessor (skipping blanks and comments for instance). pari-2.11.2/src/functions/programming/forfactored0000644000175000017500000000406113326135265020527 0ustar billbillFunction: forfactored Section: programming/control C-Name: forfactored Prototype: vV=GGI Help: forfactored(N=a,b,seq): the sequence is evaluated, N is of the form [n, factor(n)], n going from a up to b. Doc: evaluates \var{seq}, where the formal variable $N$ is $[n, \kbd{factor}(n)]$ and $n$ goes from $a$ to $b$; $a$ and $b$ must be integers. Nothing is done if $a>b$. This function is only implemented for $|a|, |b| < 2^{64}$ ($2^{32}$ on a 32-bit machine). It uses a sieve and runs in time $O(\sqrt{b} + b-a)$. It should be at least 3 times faster than regular factorization as long as the interval length $b-a$ is much larger than $\sqrt{b}$ and get relatively faster as the bounds increase. The function slows down dramatically if $\kbd{primelimit} < \sqrt{b}$. \bprog ? B = 10^9; ? for (N = B, B+10^6, factor(N)) time = 4,538 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 1,031 ms. ? B = 10^11; ? for (N = B, B+10^6, factor(N)) time = 15,575 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 2,375 ms. ? B = 10^14; ? for (N = B, B+10^6, factor(N)) time = 1min, 4,948 ms. ? forfactored (N = B, B+10^6, [n,fan] = N) time = 58,601 ms. @eprog\noindent The last timing is with the default \kbd{primelimit} (500000) which is much less than $\sqrt{B+10^6}$; it goes down to \kbd{26,750ms} if \kbd{primelimit} gets bigger than that bound. In any case $\sqrt{B+10^6}$ is much larger than the interval length $10^6$ so \kbd{forfactored} gets relatively slower for that reason as well. Note that all PARI multiplicative functions accept the \kbd{[n,fan]} argument natively: \bprog ? s = 0; forfactored(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 6,001 ms. %1 = 6393738650 ? s = 0; for(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s time = 28,398 ms. \\ slower, we must factor N. Twice. %2 = 6393738650 @eprog The following loops over the fundamental dicriminants less than $X$: \bprog ? X = 10^8; ? forfactored(d=1,X, if (isfundamental(d),)); time = 34,030 ms. ? for(d=1,X, if (isfundamental(d),)) time = 1min, 24,225 ms. @eprog pari-2.11.2/src/functions/programming/allocatemem0000644000175000017500000001074413457566440020531 0ustar billbillFunction: allocatemem Section: programming/specific C-Name: gp_allocatemem Prototype: vDG Help: allocatemem({s=0}): allocates a new stack of s bytes. doubles the stack if s is omitted. Doc: this special operation changes the stack size \emph{after} initialization. The argument $s$ must be a non-negative integer. If $s > 0$, a new stack of at least $s$ bytes is allocated. We may allocate more than $s$ bytes if $s$ is way too small, or for alignment reasons: the current formula is $\max(16*\ceil{s/16}, 500032)$ bytes. If $s=0$, the size of the new stack is twice the size of the old one. This command is much more useful if \tet{parisizemax} is non-zero, and we describe this case first. With \kbd{parisizemax} enabled, there are three sizes of interest: \item a virtual stack size, \tet{parisizemax}, which is an absolute upper limit for the stack size; this is set by \kbd{default(parisizemax, ...)}. \item the desired typical stack size, \tet{parisize}, that will grow as needed, up to \tet{parisizemax}; this is set by \kbd{default(parisize, ...)}. \item the current stack size, which is less that \kbd{parisizemax}, typically equal to \kbd{parisize} but possibly larger and increasing dynamically as needed; \kbd{allocatemem} allows to change that one explicitly. The \kbd{allocatemem} command forces stack usage to increase temporarily (up to \kbd{parisizemax} of course); for instance if you notice using \kbd{\bs gm2} that we seem to collect garbage a lot, e.g. \bprog ? \gm2 debugmem = 2 ? default(parisize,"32M") *** Warning: new stack size = 32000000 (30.518 Mbytes). ? bnfinit('x^2+10^30-1) *** bnfinit: collecting garbage in hnffinal, i = 1. *** bnfinit: collecting garbage in hnffinal, i = 2. *** bnfinit: collecting garbage in hnffinal, i = 3. @eprog\noindent and so on for hundred of lines. Then, provided the \tet{breakloop} default is set, you can interrupt the computation, type \kbd{allocatemem(100*10\pow6)} at the break loop prompt, then let the computation go on by typing \kbd{}. Back at the \kbd{gp} prompt, the desired stack size of \kbd{parisize} is restored. Note that changing either \kbd{parisize} or \kbd{parisizemax} at the break loop prompt would interrupt the computation, contrary to the above. In most cases, \kbd{parisize} will increase automatically (up to \kbd{parisizemax}) and there is no need to perform the above maneuvers. But that the garbage collector is sufficiently efficient that a given computation can still run without increasing the stack size, albeit very slowly due to the frequent garbage collections. \misctitle{Deprecated: when \kbd{parisizemax} is unset} This is currently still the default behavior in order not to break backward compatibility. The rest of this section documents the behavior of \kbd{allocatemem} in that (deprecated) situation: it becomes a synonym for \kbd{default(parisize,...)}. In that case, there is no notion of a virtual stack, and the stack size is always equal to \kbd{parisize}. If more memory is needed, the PARI stack overflows, aborting the computation. Thus, increasing \kbd{parisize} via \kbd{allocatemem} or \kbd{default(parisize,...)} before a big computation is important. Unfortunately, either must be typed at the \kbd{gp} prompt in interactive usage, or left by itself at the start of batch files. They cannot be used meaningfully in loop-like constructs, or as part of a larger expression sequence, e.g \bprog allocatemem(); x = 1; \\@com This will not set \kbd{x}! @eprog\noindent In fact, all loops are immediately exited, user functions terminated, and the rest of the sequence following \kbd{allocatemem()} is silently discarded, as well as all pending sequences of instructions. We just go on reading the next instruction sequence from the file we are in (or from the user). In particular, we have the following possibly unexpected behavior: in \bprog read("file.gp"); x = 1 @eprog\noindent were \kbd{file.gp} contains an \kbd{allocatemem} statement, the \kbd{x = 1} is never executed, since all pending instructions in the current sequence are discarded. The reason for these unfortunate side-effects is that, with \kbd{parisizemax} disabled, increasing the stack size physically moves the stack, so temporary objects created during the current expression evaluation are not correct anymore. (In particular byte-compiled expressions, which are allocated on the stack.) To avoid accessing obsolete pointers to the old stack, this routine ends by a \kbd{longjmp}. pari-2.11.2/src/functions/programming/parploth0000644000175000017500000001246013326135265020064 0ustar billbillFunction: parploth Section: graphic C-Name: parploth Prototype: V=GGJD0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 Description: (,gen,gen,closure,?0,?0):vec parploth($2, $3, $4, $5, $6, $prec) Help: parploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean: 1=Parametric, 2=Recursive, 4=no_Rescale, 8=no_X_axis, 16=no_Y_axis, 32=no_Frame, 64=no_Lines (do not join points), 128=Points_too (plot both lines and points), 256=Splines (use cubic splines), 512=no_X_ticks, 1024= no_Y_ticks, 2048=Same_ticks (plot all ticks with the same length), 4096=Complex (the two coordinates of each point are encoded as a complex number). n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box. Doc: high precision plot of the function $y=f(x)$ represented by the expression \var{expr}, $x$ going from $a$ to $b$. This opens a specific window (which is killed whenever you click on it), and returns a four-component vector giving the coordinates of the bounding box in the form $[\var{xmin},\var{xmax},\var{ymin},\var{ymax}]$. \misctitle{Important note} \kbd{parploth} may evaluate \kbd{expr} thousands of times; given the relatively low resolution of plotting devices, few significant digits of the result will be meaningful. Hence you should keep the current precision to a minimum (e.g.~9) before calling this function. $n$ specifies the number of reference point on the graph, where a value of 0 means we use the hardwired default values (1000 for general plot, 1500 for parametric plot, and 8 for recursive plot). If no $\fl$ is given, \var{expr} is either a scalar expression $f(X)$, in which case the plane curve $y=f(X)$ will be drawn, or a vector $[f_1(X),\dots,f_k(X)]$, and then all the curves $y=f_i(X)$ will be drawn in the same window. \noindent The binary digits of $\fl$ mean: \item $1 = \kbd{Parametric}$: \tev{parametric plot}. Here \var{expr} must be a vector with an even number of components. Successive pairs are then understood as the parametric coordinates of a plane curve. Each of these are then drawn. For instance: \bprog parploth(X=0,2*Pi,[sin(X),cos(X)], "Parametric") parploth(X=0,2*Pi,[sin(X),cos(X)]) parploth(X=0,2*Pi,[X,X,sin(X),cos(X)], "Parametric") @eprog\noindent draw successively a circle, two entwined sinusoidal curves and a circle cut by the line $y=x$. \item $2 = \kbd{Recursive}$: \tev{recursive plot}. If this flag is set, only \emph{one} curve can be drawn at a time, i.e.~\var{expr} must be either a two-component vector (for a single parametric curve, and the parametric flag \emph{has} to be set), or a scalar function. The idea is to choose pairs of successive reference points, and if their middle point is not too far away from the segment joining them, draw this as a local approximation to the curve. Otherwise, add the middle point to the reference points. This is fast, and usually more precise than usual plot. Compare the results of \bprog parploth(X=-1,1, sin(1/X), "Recursive") parploth(X=-1,1, sin(1/X)) @eprog\noindent for instance. But beware that if you are extremely unlucky, or choose too few reference points, you may draw some nice polygon bearing little resemblance to the original curve. For instance you should \emph{never} plot recursively an odd function in a symmetric interval around 0. Try \bprog parploth(x = -20, 20, sin(x), "Recursive") @eprog\noindent to see why. Hence, it's usually a good idea to try and plot the same curve with slightly different parameters. The other values toggle various display options: \item $4 = \kbd{no\_Rescale}$: do not rescale plot according to the computed extrema. This is used in conjunction with \tet{plotscale} when graphing multiple functions on a rectwindow (as a \tet{plotrecth} call): \bprog s = plothsizes(); plotinit(0, s[2]-1, s[2]-1); plotscale(0, -1,1, -1,1); plotrecth(0, t=0,2*Pi, [cos(t),sin(t)], "Parametric|no_Rescale") plotdraw([0, -1,1]); @eprog\noindent This way we get a proper circle instead of the distorted ellipse produced by \bprog parploth(t=0,2*Pi, [cos(t),sin(t)], "Parametric") @eprog \item $8 = \kbd{no\_X\_axis}$: do not print the $x$-axis. \item $16 = \kbd{no\_Y\_axis}$: do not print the $y$-axis. \item $32 = \kbd{no\_Frame}$: do not print frame. \item $64 = \kbd{no\_Lines}$: only plot reference points, do not join them. \item $128 = \kbd{Points\_too}$: plot both lines and points. \item $256 = \kbd{Splines}$: use splines to interpolate the points. \item $512 = \kbd{no\_X\_ticks}$: plot no $x$-ticks. \item $1024 = \kbd{no\_Y\_ticks}$: plot no $y$-ticks. \item $2048 = \kbd{Same\_ticks}$: plot all ticks with the same length. \item $4096 = \kbd{Complex}$: is a parametric plot but where each member of \kbd{expr} is considered a complex number encoding the two coordinates of a point. For instance: \bprog parploth(X=0,2*Pi,exp(I*X), "Complex") parploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex") @eprog\noindent will draw respectively a circle and a circle cut by the line $y=x$. \synt{parploth}{GEN a,GEN b,GEN code, long flag, long n, long prec}. pari-2.11.2/src/functions/programming/parfor0000644000175000017500000000553413201017466017522 0ustar billbillFunction: parfor Section: programming/parallel C-Name: parfor0 Prototype: vV=GDGJDVDI Description: (gen,gen,closure):void parfor($1, $2, $3, NULL, NULL) Help: parfor(i=a,{b},expr1,{r},{expr2}): evaluates the expression expr1 in parallel for all i between a and b (if b is set to +oo, the loop will not stop), resulting in as many values; if the formal variables r and expr2 are present, evaluate sequentially expr2, in which r has been replaced by the different results obtained for expr1 and i with the corresponding arguments. Doc: evaluates in parallel the expression \kbd{expr1} in the formal argument $i$ running from $a$ to $b$. If $b$ is set to \kbd{+oo}, the loop runs indefinitely. If $r$ and \kbd{expr2} are present, the expression \kbd{expr2} in the formal variables $r$ and $i$ is evaluated with $r$ running through all the different results obtained for \kbd{expr1} and $i$ takes the corresponding argument. The computations of \kbd{expr1} are \emph{started} in increasing order of $i$; otherwise said, the computation for $i=c$ is started after those for $i=1, \ldots, c-1$ have been started, but before the computation for $i=c+1$ is started. Notice that the order of \emph{completion}, that is, the order in which the different $r$ become available, may be different; \kbd{expr2} is evaluated sequentially on each $r$ as it appears. The following example computes the sum of the squares of the integers from $1$ to $10$ by computing the squares in parallel and is equivalent to \kbd{parsum (i=1, 10, i\^{}2)}: \bprog ? s=0; ? parfor (i=1, 10, i^2, r, s=s+r) ? s %3 = 385 @eprog More precisely, apart from a potentially different order of evaluation due to the parallelism, the line containing \kbd{parfor} is equivalent to \bprog ? my (r); for (i=1, 10, r=i^2; s=s+r) @eprog The sequentiality of the evaluation of \kbd{expr2} ensures that the variable \kbd{s} is not modified concurrently by two different additions, although the order in which the terms are added is non-deterministic. It is allowed for \kbd{expr2} to exit the loop using \kbd{break}/\kbd{next}/\kbd{return}. If that happens for $i=c$, then the evaluation of \kbd{expr1} and \kbd{expr2} is continued for all values $i to continue; 'break' to go back to GP break> z 10 break> %2 = 13 @eprog pari-2.11.2/src/functions/programming/localprec0000644000175000017500000000425313447371554020207 0ustar billbillFunction: localprec Section: programming/specific C-Name: localprec Prototype: vL Help: localprec(p): set the real precision to p in the dynamic scope. Doc: set the real precision to $p$ in the dynamic scope. All computations are performed as if \tet{realprecision} was $p$: transcendental constants (e.g.~\kbd{Pi}) and conversions from exact to floating point inexact data use $p$ decimal digits, as well as iterative routines implicitly using a floating point accuracy as a termination criterion (e.g.~\tet{solve} or \tet{intnum}). But \kbd{realprecision} itself is unaffected and is ``unmasked'' when we exit the dynamic (\emph{not} lexical) scope. In effect, this is similar to \bprog my(prec = default(realprecision)); default(realprecision,p); ... default(realprecision, prec); @eprog\noindent but is both less cumbersome, cleaner (no need to manipulate a global variable, which in fact never changes and is only temporarily masked) and more robust: if the above computation is interrupted or an exception occurs, \kbd{realprecision} will not be restored as intended. Such \kbd{localprec} statements can be nested, the innermost one taking precedence as expected. Beware that \kbd{localprec} follows the semantic of \tet{local}, not \tet{my}: a subroutine called from \kbd{localprec} scope uses the local accuracy: \bprog ? f()=precision(1.); ? f() %2 = 38 ? localprec(19); f() %3 = 19 @eprog\noindent \misctitle{Warning} Changing \kbd{realprecision} itself in programs is now deprecated in favor of \kbd{localprec}. Think about the \kbd{realprecision} default as an interactive command for the \kbd{gp} interpreter, best left out of GP programs. Indeed, the above rules imply that mixing both constructs yields surprising results: \bprog ? \p38 ? localprec(19); default(realprecision,100); Pi %1 = 3.141592653589793239 ? \p realprecision = 115 significant digits (100 digits displayed) @eprog\noindent Indeed, \kbd{realprecision} itself is ignored within \kbd{localprec} scope, so \kbd{Pi} is computed to a low accuracy. And when we leave \kbd{localprec} scope, \kbd{realprecision} only regains precedence, it is not ``restored'' to the original value. %\syn{NO} pari-2.11.2/src/functions/programming/readstr0000644000175000017500000000060013201017466017662 0ustar billbillFunction: readstr Section: programming/specific C-Name: readstr Prototype: D"",s, Help: readstr({filename}): returns the vector of GP strings containing the lines in filename. Doc: Reads in the file \var{filename} and return a vector of GP strings, each component containing one line from the file. If \var{filename} is omitted, re-reads the last file that was fed into \kbd{gp}. pari-2.11.2/src/functions/programming/filewrite10000644000175000017500000000066313326135265020310 0ustar billbillFunction: filewrite1 Section: programming/specific C-Name: gp_filewrite1 Prototype: vLs Help: filewrite1(n, s): write the string s to file number n without ending with newline. Doc: write the string $s$ to the file attached to descriptor $n$. The file must have been opened with \kbd{fileopen} in \kbd{"w"} or \kbd{"a"} mode. If you want to append a newline at the end of $s$, you can use \kbd{Str(s,"\bs n")} or \kbd{filewrite}. pari-2.11.2/src/functions/programming/system0000644000175000017500000000062013201017466017544 0ustar billbillFunction: system Section: programming/specific C-Name: gpsystem Prototype: vs Help: system(str): str being a string, execute the system command str. Doc: \var{str} is a string representing a system command. This command is executed, its output written to the standard output (this won't get into your logfile), and control returns to the PARI system. This simply calls the C \kbd{system} command. pari-2.11.2/src/functions/programming/install0000644000175000017500000000657713201017466017707 0ustar billbillFunction: install Section: programming/specific C-Name: gpinstall Prototype: vrrD"",r,D"",s, Help: install(name,code,{gpname},{lib}): load from dynamic library 'lib' the function 'name'. Assign to it the name 'gpname' in this GP session, with prototype 'code'. If 'lib' is omitted, all symbols known to gp (includes the whole 'libpari.so' and possibly others) are available. If 'gpname' is omitted, use 'name'. Doc: loads from dynamic library \var{lib} the function \var{name}. Assigns to it the name \var{gpname} in this \kbd{gp} session, with \emph{prototype} \var{code} (see below). If \var{gpname} is omitted, uses \var{name}. If \var{lib} is omitted, all symbols known to \kbd{gp} are available: this includes the whole of \kbd{libpari.so} and possibly others (such as \kbd{libc.so}). Most importantly, \kbd{install} gives you access to all non-static functions defined in the PARI library. For instance, the function \bprog GEN addii(GEN x, GEN y) @eprog\noindent adds two PARI integers, and is not directly accessible under \kbd{gp} (it is eventually called by the \kbd{+} operator of course): \bprog ? install("addii", "GG") ? addii(1, 2) %1 = 3 @eprog\noindent It also allows to add external functions to the \kbd{gp} interpreter. For instance, it makes the function \tet{system} obsolete: \bprog ? install(system, vs, sys,/*omitted*/) ? sys("ls gp*") gp.c gp.h gp_rl.c @eprog\noindent This works because \kbd{system} is part of \kbd{libc.so}, which is linked to \kbd{gp}. It is also possible to compile a shared library yourself and provide it to gp in this way: use \kbd{gp2c}, or do it manually (see the \kbd{modules\_build} variable in \kbd{pari.cfg} for hints). Re-installing a function will print a warning and update the prototype code if needed. However, it will not reload a symbol from the library, even if the latter has been recompiled. \misctitle{Prototype} We only give a simplified description here, covering most functions, but there are many more possibilities. The full documentation is available in \kbd{libpari.dvi}, see \bprog ??prototype @eprog \item First character \kbd{i}, \kbd{l}, \kbd{v} : return type int / long / void. (Default: \kbd{GEN}) \item One letter for each mandatory argument, in the same order as they appear in the argument list: \kbd{G} (\kbd{GEN}), \kbd{\&} (\kbd{GEN*}), \kbd{L} (\kbd{long}), \kbd{s} (\kbd{char *}), \kbd{n} (variable). \item \kbd{p} to supply \kbd{realprecision} (usually \kbd{long prec} in the argument list), \kbd{P} to supply \kbd{seriesprecision} (usually \kbd{long precdl}). \noindent We also have special constructs for optional arguments and default values: \item \kbd{DG} (optional \kbd{GEN}, \kbd{NULL} if omitted), \item \kbd{D\&} (optional \kbd{GEN*}, \kbd{NULL} if omitted), \item \kbd{Dn} (optional variable, $-1$ if omitted), For instance the prototype corresponding to \bprog long issquareall(GEN x, GEN *n = NULL) @eprog\noindent is \kbd{lGD\&}. \misctitle{Caution} This function may not work on all systems, especially when \kbd{gp} has been compiled statically. In that case, the first use of an installed function will provoke a Segmentation Fault (this should never happen with a dynamically linked executable). If you intend to use this function, please check first on some harmless example such as the one above that it works properly on your machine. pari-2.11.2/src/functions/polynomials/0000755000175000017500000000000013461316051016323 5ustar billbillpari-2.11.2/src/functions/polynomials/polrootsmod0000644000175000017500000000203513326135265020635 0ustar billbillFunction: polrootsmod Section: polynomials C-Name: polrootsmod Prototype: GDG Help: polrootsmod(f,{D}): roots of the polynomial f over the finite field defined by the domain D. Doc: vector of roots of the polynomial $f$ over the finite field defined by the domain $D$ as follows: \item $D = p$ a prime: factor over $\F_p$; \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over $\F_p$: factor over $\F_p[x]/(T)$; \item $D$ a \typ{FFELT}: factor over the attached field; \item $D$ omitted: factor over the field of definition of $f$, which must be a finite field. \noindent Multiple roots are \emph{not} repeated. \bprog ? polrootsmod(x^2-1,2) %1 = [Mod(1, 2)]~ ? polrootsmod(x^2+1,3) %2 = []~ ? polrootsmod(x^2+1, [3,y^2+1]) %3 = [Mod(Mod(1, 3)*y, Mod(1, 3)*y^2 + Mod(1, 3)), Mod(Mod(2, 3)*y, Mod(1, 3)*y^2 + Mod(1, 3))]~ ? polrootsmod(x^2 + Mod(1,3)) %4 = []~ ? liftall( polrootsmod(x^2 + Mod(Mod(1,3),y^2+1)) ) %5 = [y, 2*y]~ ? t = ffgen(y^2+Mod(1,3)); polrootsmod(x^2 + t^0) %6 = [y, 2*y]~ @eprog pari-2.11.2/src/functions/polynomials/polsturm0000644000175000017500000000316413326135265020145 0ustar billbillFunction: polsturm Section: polynomials C-Name: sturmpart Prototype: lGDGDG Help: polsturm(T,{ab}): number of distinct real roots of the polynomial T (in the interval ab = [a,b] if present). Doc: number of distinct real roots of the real polynomial \var{T}. If the argument \var{ab} is present, it must be a vector $[a,b]$ with two real components (of type \typ{INT}, \typ{REAL}, \typ{FRAC} or \typ{INFINITY}) and we count roots belonging to that closed interval. If possible, you should stick to exact inputs, that is avoid \typ{REAL}s in $T$ and the bounds $a,b$: the result is then guaranteed and we use a fast algorithm (Uspensky's method, relying on Descartes's rule of sign, see \tet{polrootsreal}). Otherwise, the polynomial is rescaled and rounded first and the result may be wrong due to that initial error. If only $a$ or $b$ is inexact, on the other hand, the interval is first thickened using rational endpoints and the result remains guaranteed unless there exist a root \emph{very} close to a non-rational endpoint (which may be missed or unduly included). \bprog ? T = (x-1)*(x-2)*(x-3); ? polsturm(T) %2 = 3 ? polsturm(T, [-oo,2]) %3 = 2 ? polsturm(T, [1/2,+oo]) %4 = 3 ? polsturm(T, [1, Pi]) \\ Pi inexact: not recommended ! %5 = 3 ? polsturm(T*1., [0, 4]) \\ T*1. inexact: not recommended ! %6 = 3 ? polsturm(T^2, [0, 4]) \\ not squarefree: roots are not repeated! %7 = 3 @eprog %\syn{NO} The library syntax is \fun{long}{RgX_sturmpart}{GEN T, GEN ab} or \fun{long}{sturm}{GEN T} (for the case \kbd{ab = NULL}). The function \fun{long}{sturmpart}{GEN T, GEN a, GEN b} is obsolete and deprecated. pari-2.11.2/src/functions/polynomials/poldiscreduced0000644000175000017500000000102011636712103021230 0ustar billbillFunction: poldiscreduced Section: polynomials C-Name: reduceddiscsmith Prototype: G Help: poldiscreduced(f): vector of elementary divisors of Z[a]/f'(a)Z[a], where a is a root of the polynomial f. Doc: reduced discriminant vector of the (integral, monic) polynomial $f$. This is the vector of elementary divisors of $\Z[\alpha]/f'(\alpha)\Z[\alpha]$, where $\alpha$ is a root of the polynomial $f$. The components of the result are all positive, and their product is equal to the absolute value of the discriminant of~$f$. pari-2.11.2/src/functions/polynomials/poldiscfactors0000644000175000017500000000255413457566437021317 0ustar billbillFunction: poldiscfactors Section: polynomials C-Name: poldiscfactors Prototype: GD0,L, Help: poldiscfactors(T,{flag=0}): [D, faD], where D = discriminant of the polynomial T, and faD is a cheap partial factorization of D (entries are coprime but need not be primes); if flag is 1, finish the factorization via factorint. Doc: given a polynomial $T$ with integer coefficients, return $[D, \var{faD}]$ where $D$ is the discriminant of $T$ and \var{faD} is a cheap partial factorization of $|D|$: entries in its first column are coprime and not perfect powers but need not be primes. The factors are obtained by a combination of trial division, testing for perfect powers, factorizations in coprimes, and computing Euclidean remainder sequences for $(T,T')$ modulo composite factors $d$ of $D$ (which is likely to produce $0$-divisors in $\Z/d\Z$). If \fl\ is $1$, finish the factorization using \kbd{factorint}. \bprog ? T = x^3 - 6021021*x^2 + 12072210077769*x - 8092423140177664432; ? [D,faD] = poldiscfactors(T); print(faD); D [3, 3; 7, 2; 373, 2; 500009, 2; 24639061, 2] %2 = -27937108625866859018515540967767467 ? T = x^3 + 9*x^2 + 27*x - 125014250689643346789780229390526092263790263725; ? [D,faD] = poldiscfactors(T); print(faD) [2, 6; 3, 3; 125007125141751093502187, 4] ? [D,faD] = poldiscfactors(T, 1); print(faD) [2, 6; 3, 3; 500009, 12; 1000003, 4] @eprog pari-2.11.2/src/functions/polynomials/polrootsff0000644000175000017500000000033213326135265020447 0ustar billbillFunction: polrootsff Section: polynomials C-Name: polrootsff Prototype: GDGDG Obsolete: 2018-03-11 Help: polrootsff(x,{p},{a}): obsolete, use polrootsmod. Doc: obsolete, kept for backward compatibility: use factormod. pari-2.11.2/src/functions/polynomials/polcoef0000644000175000017500000000166713326135265017715 0ustar billbillFunction: polcoef Section: polynomials C-Name: polcoef Prototype: GLDn Help: polcoef(x,n,{v}): coefficient of degree n of x. With respect to the main variable if v is omitted, with respect to the variable v otherwise. Description: (pol, 0):gen:copy constant_coeff($1) (pol, 0,):gen:copy constant_coeff($1) (pol, small):gen:copy RgX_coeff($1, $2) (pol, small,):gen:copy RgX_coeff($1, $2) (gen, small, ?var):gen polcoef0($1, $2, $3) Doc: coefficient of degree $n$ of the polynomial $x$, with respect to the main variable if $v$ is omitted, with respect to $v$ otherwise. If $n$ is greater than the degree, the result is zero. Naturally applies to scalars (polynomial of degree $0$), as well as to rational functions whose denominator is a monomial. It also applies to power series: if $n$ is less than the valuation, the result is zero. If it is greater than the largest significant degree, then an error message is issued. pari-2.11.2/src/functions/polynomials/poldegree0000644000175000017500000000134613201017466020220 0ustar billbillFunction: poldegree Section: polynomials C-Name: gppoldegree Prototype: GDn Help: poldegree(x,{v}): degree of the polynomial or rational function x with respect to main variable if v is omitted, with respect to v otherwise. For scalar x, return 0 if x is non-zero and -oo otherwise. Doc: degree of the polynomial $x$ in the main variable if $v$ is omitted, in the variable $v$ otherwise. The degree of $0$ is \kbd{-oo}. The degree of a non-zero scalar is $0$. Finally, when $x$ is a non-zero polynomial or rational function, returns the ordinary degree of $x$. Raise an error otherwise. Variant: Also available is \fun{long}{poldegree}{GEN x, long v}, which returns \tet{-LONG_MAX} if $x = 0$ and the degree as a \kbd{long} integer. pari-2.11.2/src/functions/polynomials/polhensellift0000644000175000017500000000215513036414402021116 0ustar billbillFunction: polhensellift Section: polynomials C-Name: polhensellift Prototype: GGGL Help: polhensellift(A, B, p, e): lift the factorization B of A modulo p to a factorization modulo p^e using Hensel lift. The factors in B must be pairwise relatively prime modulo p. Doc: given a prime $p$, an integral polynomial $A$ whose leading coefficient is a $p$-unit, a vector $B$ of integral polynomials that are monic and pairwise relatively prime modulo $p$, and whose product is congruent to $A/\text{lc}(A)$ modulo $p$, lift the elements of $B$ to polynomials whose product is congruent to $A$ modulo $p^e$. More generally, if $T$ is an integral polynomial irreducible mod $p$, and $B$ is a factorization of $A$ over the finite field $\F_p[t]/(T)$, you can lift it to $\Z_p[t]/(T, p^e)$ by replacing the $p$ argument with $[p,T]$: \bprog ? { T = t^3 - 2; p = 7; A = x^2 + t + 1; B = [x + (3*t^2 + t + 1), x + (4*t^2 + 6*t + 6)]; r = polhensellift(A, B, [p, T], 6) } %1 = [x + (20191*t^2 + 50604*t + 75783), x + (97458*t^2 + 67045*t + 41866)] ? liftall( r[1] * r[2] * Mod(Mod(1,p^6),T) ) %2 = x^2 + (t + 1) @eprog pari-2.11.2/src/functions/polynomials/O0000644000175000017500000000154013201017466016444 0ustar billbillFunction: O(_^_) Section: programming/internals C-Name: ggrando Prototype: GD1,L, Help: O(p^e): p-adic or power series zero with precision given by e. Description: (gen):gen ggrando($1, 1) (1,small):gen ggrando(gen_1, $2) (int,small):gen zeropadic($1, $2) (gen,small):gen ggrando($1, $2) (var,small):gen zeroser($1, $2) Function: O Section: polynomials C-Name: ggrando Prototype: Help: O(p^e): p-adic or power series zero with precision given by e. Doc: if $p$ is an integer greater than $2$, returns a $p$-adic $0$ of precision $e$. In all other cases, returns a power series zero with precision given by $e v$, where $v$ is the $X$-adic valuation of $p$ with respect to its main variable. Variant: \fun{GEN}{zeropadic}{GEN p, long e} for a $p$-adic and \fun{GEN}{zeroser}{long v, long e} for a power series zero in variable $v$. pari-2.11.2/src/functions/polynomials/padicfields0000644000175000017500000000346112314242551020520 0ustar billbillFunction: padicfields Section: polynomials C-Name: padicfields0 Prototype: GGD0,L, Help: padicfields(p, N, {flag=0}): returns polynomials generating all the extensions of degree N of the field of p-adic rational numbers; N is allowed to be a 2-component vector [n,d], in which case, returns the extensions of degree n and discriminant p^d. flag is optional, and can be 0: default, 1: return also the ramification index, the residual degree, the valuation of the discriminant and the number of conjugate fields, or 2: return only the number of extensions in a fixed algebraic closure. Doc: returns a vector of polynomials generating all the extensions of degree $N$ of the field $\Q_p$ of $p$-adic rational numbers; $N$ is allowed to be a 2-component vector $[n,d]$, in which case we return the extensions of degree $n$ and discriminant $p^d$. The list is minimal in the sense that two different polynomials generate non-isomorphic extensions; in particular, the number of polynomials is the number of classes of non-isomorphic extensions. If $P$ is a polynomial in this list, $\alpha$ is any root of $P$ and $K = \Q_p(\alpha)$, then $\alpha$ is the sum of a uniformizer and a (lift of a) generator of the residue field of $K$; in particular, the powers of $\alpha$ generate the ring of $p$-adic integers of $K$. If $\fl = 1$, replace each polynomial $P$ by a vector $[P, e, f, d, c]$ where $e$ is the ramification index, $f$ the residual degree, $d$ the valuation of the discriminant, and $c$ the number of conjugate fields. If $\fl = 2$, only return the \emph{number} of extensions in a fixed algebraic closure (Krasner's formula), which is much faster. Variant: Also available is \fun{GEN}{padicfields}{GEN p, long n, long d, long flag}, which computes extensions of $\Q_p$ of degree $n$ and discriminant $p^d$. pari-2.11.2/src/functions/polynomials/thueinit0000644000175000017500000000721213326135265020107 0ustar billbillFunction: thueinit Section: polynomials C-Name: thueinit Prototype: GD0,L,p Help: thueinit(P,{flag=0}): initialize the tnf corresponding to P, that will be used to solve Thue equations P(x,y) = some-integer. If flag is non-zero, certify the result unconditionaly. Otherwise, assume GRH (much faster of course). Doc: initializes the \var{tnf} corresponding to $P$, a non-constant univariate polynomial with integer coefficients. The result is meant to be used in conjunction with \tet{thue} to solve Thue equations $P(X / Y)Y^{\deg P} = a$, where $a$ is an integer. Accordingly, $P$ must either have at least two distinct irreducible factors over $\Q$, or have one irreducible factor $T$ with degree $>2$ or two conjugate complex roots: under these (necessary and sufficient) conditions, the equation has finitely many integer solutions. \bprog ? S = thueinit(t^2+1); ? thue(S, 5) %2 = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]] ? S = thueinit(t+1); *** at top-level: thueinit(t+1) *** ^------------- *** thueinit: domain error in thueinit: P = t + 1 @eprog\noindent The hardest case is when $\deg P > 2$ and $P$ is irreducible with at least one real root. The routine then uses Bilu-Hanrot's algorithm. If $\fl$ is non-zero, certify results unconditionally. Otherwise, assume \idx{GRH}, this being much faster of course. In the latter case, the result may still be unconditionally correct, see \tet{thue}. For instance in most cases where $P$ is reducible (not a pure power of an irreducible), \emph{or} conditional computed class groups are trivial \emph{or} the right hand side is $\pm1$, then results are unconditional. \misctitle{Note} The general philosophy is to disprove the existence of large solutions then to enumerate bounded solutions naively. The implementation will overflow when there exist huge solutions and the equation has degree $> 2$ (the quadratic imaginary case is special, since we can stick to \kbd{bnfisintnorm}, there are no fundamental units): \bprog ? thue(t^3+2, 10^30) *** at top-level: L=thue(t^3+2,10^30) *** ^----------------- *** thue: overflow in thue (SmallSols): y <= 80665203789619036028928. ? thue(x^2+2, 10^30) \\ quadratic case much easier %1 = [[-1000000000000000, 0], [1000000000000000, 0]] @eprog \misctitle{Note} It is sometimes possible to circumvent the above, and in any case obtain an important speed-up, if you can write $P = Q(x^d)$ for some $d > 1$ and $Q$ still satisfying the \kbd{thueinit} hypotheses. You can then solve the equation attached to $Q$ then eliminate all solutions $(x,y)$ such that either $x$ or $y$ is not a $d$-th power. \bprog ? thue(x^4+1, 10^40); \\ stopped after 10 hours ? filter(L,d) = my(x,y); [[x,y] | v<-L, ispower(v[1],d,&x)&&ispower(v[2],d,&y)]; ? L = thue(x^2+1, 10^40); ? filter(L, 2) %4 = [[0, 10000000000], [10000000000, 0]] @eprog\noindent The last 2 commands use less than 20ms. \misctitle{Note} When $P$ is irreducible without a real root, the equation can be solved unconditionnally in time $|a|^{1/\deg P}$. When this latter quantity is huge and the equation has no solutions, this fact may still be ascertained via arithmetic conditions but this now implies solving norm equations, computing a \var{bnf} and possibly assuming the GRH. When there is no real root, the code does not compute a \var{bnf} (with certification if $\fl = 1$) if it expects this to be an ``easy'' computation (because the result would only be used for huge values of $a$). See \kbd{thue} for a way to compute an expensive \var{bnf} on your own and still get a result where this default cheap strategy fails. pari-2.11.2/src/functions/polynomials/polcyclo0000644000175000017500000000160013036414402020064 0ustar billbillFunction: polcyclo Section: polynomials C-Name: polcyclo_eval Prototype: LDG Help: polcyclo(n,{a = 'x}): n-th cyclotomic polynomial evaluated at a. Description: (small,?var):gen polcyclo($1,$2) (small,gen):gen polcyclo_eval($1,$2) Doc: $n$-th cyclotomic polynomial, evaluated at $a$ (\kbd{'x} by default). The integer $n$ must be positive. Algorithm used: reduce to the case where $n$ is squarefree; to compute the cyclotomic polynomial, use $\Phi_{np}(x)=\Phi_n(x^p)/\Phi(x)$; to compute it evaluated, use $\Phi_n(x) = \prod_{d\mid n} (x^d-1)^{\mu(n/d)}$. In the evaluated case, the algorithm assumes that $a^d - 1$ is either $0$ or invertible, for all $d\mid n$. If this is not the case (the base ring has zero divisors), use \kbd{subst(polcyclo(n),x,a)}. Variant: The variant \fun{GEN}{polcyclo}{long n, long v} returns the $n$-th cyclotomic polynomial in variable $v$. pari-2.11.2/src/functions/polynomials/serreverse0000644000175000017500000000061613036414402020433 0ustar billbillFunction: serreverse Section: polynomials C-Name: serreverse Prototype: G Help: serreverse(s): reversion of the power series s. Doc: reverse power series of $s$, i.e. the series $t$ such that $t(s) = x$; $s$ must be a power series whose valuation is exactly equal to one. \bprog ? \ps 8 ? t = serreverse(tan(x)) %2 = x - 1/3*x^3 + 1/5*x^5 - 1/7*x^7 + O(x^8) ? tan(t) %3 = x + O(x^8) @eprog pari-2.11.2/src/functions/polynomials/HEADER0000644000175000017500000000055413326135265017210 0ustar billbillFunction: _header_polynomials Class: header Section: polynomials Doc: \section{Polynomials and power series} We group here all functions which are specific to polynomials or power series. Many other functions which can be applied on these objects are described in the other sections. Also, some of the functions described here can be applied to other types. pari-2.11.2/src/functions/polynomials/taylor0000644000175000017500000000127611636712103017566 0ustar billbillFunction: taylor Section: polynomials C-Name: tayl Prototype: GnDP Help: taylor(x,t,{d=seriesprecision}): taylor expansion of x with respect to t, adding O(t^d) to all components of x. Doc: Taylor expansion around $0$ of $x$ with respect to the simple variable $t$. $x$ can be of any reasonable type, for example a rational function. Contrary to \tet{Ser}, which takes the valuation into account, this function adds $O(t^d)$ to all components of $x$. \bprog ? taylor(x/(1+y), y, 5) %1 = (y^4 - y^3 + y^2 - y + 1)*x + O(y^5) ? Ser(x/(1+y), y, 5) *** at top-level: Ser(x/(1+y),y,5) *** ^---------------- *** Ser: main variable must have higher priority in gtoser. @eprog pari-2.11.2/src/functions/polynomials/polinterpolate0000644000175000017500000000144313201017466021311 0ustar billbillFunction: polinterpolate Section: polynomials C-Name: polint Prototype: GDGDGD& Help: polinterpolate(X,{Y},{t = 'x},{&e}): polynomial interpolation at t according to data vectors X, Y (i.e. given P of minimal degree such that P(X[i]) = Y[i] for all i, return P(t)). If Y is omitted, take P such that P(i) = X[i]. If present, e will contain an error estimate on the returned value. Doc: given the data vectors $X$ and $Y$ of the same length $n$ ($X$ containing the $x$-coordinates, and $Y$ the corresponding $y$-coordinates), this function finds the \idx{interpolating polynomial} $P$ of minimal degree passing through these points and evaluates it at~$t$. If $Y$ is omitted, the polynomial $P$ interpolates the $(i,X[i])$. If present, $e$ will contain an error estimate on the returned value. pari-2.11.2/src/functions/polynomials/eval0000644000175000017500000000304413201017466017176 0ustar billbillFunction: eval Section: polynomials C-Name: geval_gp Prototype: GC Help: eval(x): evaluation of x, replacing variables by their value. Description: (gen):gen geval($1) Doc: replaces in $x$ the formal variables by the values that have been assigned to them after the creation of $x$. This is mainly useful in GP, and not in library mode. Do not confuse this with substitution (see \kbd{subst}). If $x$ is a character string, \kbd{eval($x$)} executes $x$ as a GP command, as if directly input from the keyboard, and returns its output. \bprog ? x1 = "one"; x2 = "two"; ? n = 1; eval(Str("x", n)) %2 = "one" ? f = "exp"; v = 1; ? eval(Str(f, "(", v, ")")) %4 = 2.7182818284590452353602874713526624978 @eprog\noindent Note that the first construct could be implemented in a simpler way by using a vector \kbd{x = ["one","two"]; x[n]}, and the second by using a closure \kbd{f = exp; f(v)}. The final example is more interesting: \bprog ? genmat(u,v) = matrix(u,v,i,j, eval( Str("x",i,j) )); ? genmat(2,3) \\ generic 2 x 3 matrix %2 = [x11 x12 x13] [x21 x22 x23] @eprog A syntax error in the evaluation expression raises an \kbd{e\_SYNTAX} exception, which can be trapped as usual: \bprog ? 1a *** syntax error, unexpected variable name, expecting $end or ';': 1a *** ^- ? E(expr) = { iferr(eval(expr), e, print("syntax error"), errname(e) == "e_SYNTAX"); } ? E("1+1") %1 = 2 ? E("1a") syntax error @eprog \synt{geval}{GEN x}. pari-2.11.2/src/functions/polynomials/serconvol0000644000175000017500000000051511636712103020261 0ustar billbillFunction: serconvol Section: polynomials C-Name: convol Prototype: GG Help: serconvol(x,y): convolution (or Hadamard product) of two power series. Doc: convolution (or \idx{Hadamard product}) of the two power series $x$ and $y$; in other words if $x=\sum a_k*X^k$ and $y=\sum b_k*X^k$ then $\kbd{serconvol}(x,y)=\sum a_k*b_k*X^k$. pari-2.11.2/src/functions/polynomials/factorpadic0000644000175000017500000000272413201017466020532 0ustar billbillFunction: factorpadic Section: polynomials C-Name: factorpadic Prototype: GGL Help: factorpadic(pol,p,r): p-adic factorization of the polynomial pol to precision r. Doc: $p$-adic factorization of the polynomial \var{pol} to precision $r$, the result being a two-column matrix as in \kbd{factor}. Note that this is not the same as a factorization over $\Z/p^r\Z$ (polynomials over that ring do not form a unique factorization domain, anyway), but approximations in $\Q/p^r\Z$ of the true factorization in $\Q_p[X]$. \bprog ? factorpadic(x^2 + 9, 3,5) %1 = [(1 + O(3^5))*x^2 + O(3^5)*x + (3^2 + O(3^5)) 1] ? factorpadic(x^2 + 1, 5,3) %2 = [ (1 + O(5^3))*x + (2 + 5 + 2*5^2 + O(5^3)) 1] [(1 + O(5^3))*x + (3 + 3*5 + 2*5^2 + O(5^3)) 1] @eprog\noindent The factors are normalized so that their leading coefficient is a power of $p$. The method used is a modified version of the \idx{round 4} algorithm of \idx{Zassenhaus}. If \var{pol} has inexact \typ{PADIC} coefficients, this is not always well-defined; in this case, the polynomial is first made integral by dividing out the $p$-adic content, then lifted to $\Z$ using \tet{truncate} coefficientwise. Hence we actually factor exactly a polynomial which is only $p$-adically close to the input. To avoid pitfalls, we advise to only factor polynomials with exact rational coefficients. \synt{factorpadic}{GEN f,GEN p, long r} . The function \kbd{factorpadic0} is deprecated, provided for backward compatibility. pari-2.11.2/src/functions/polynomials/poliscyclo0000644000175000017500000000066512314242551020434 0ustar billbillFunction: poliscyclo Section: polynomials C-Name: poliscyclo Prototype: lG Help: poliscyclo(f): returns 0 if f is not a cyclotomic polynomial, and n > 0 if f = Phi_n, the n-th cyclotomic polynomial. Doc: returns 0 if $f$ is not a cyclotomic polynomial, and $n > 0$ if $f = \Phi_n$, the $n$-th cyclotomic polynomial. \bprog ? poliscyclo(x^4-x^2+1) %1 = 12 ? polcyclo(12) %2 = x^4 - x^2 + 1 ? poliscyclo(x^4-x^2-1) %3 = 0 @eprog pari-2.11.2/src/functions/polynomials/pollead0000644000175000017500000000114213201017466017664 0ustar billbillFunction: pollead Section: polynomials C-Name: pollead Prototype: GDn Help: pollead(x,{v}): leading coefficient of polynomial or series x, or x itself if x is a scalar. Error otherwise. With respect to the main variable of x if v is omitted, with respect to the variable v otherwise. Description: (pol):gen:copy leading_coeff($1) (gen):gen pollead($1, -1) (gen, var):gen pollead($1, $2) Doc: leading coefficient of the polynomial or power series $x$. This is computed with respect to the main variable of $x$ if $v$ is omitted, with respect to the variable $v$ otherwise. pari-2.11.2/src/functions/polynomials/substpol0000644000175000017500000000211711636712103020122 0ustar billbillFunction: substpol Section: polynomials C-Name: gsubstpol Prototype: GGG Help: substpol(x,y,z): in expression x, replace the polynomial y by the expression z, using remainder decomposition of x. Doc: replace the ``variable'' $y$ by the argument $z$ in the ``polynomial'' expression $x$. Every type is allowed for $x$, but the same behavior as \kbd{subst} above apply. The difference with \kbd{subst} is that $y$ is allowed to be any polynomial here. The substitution is done moding out all components of $x$ (recursively) by $y - t$, where $t$ is a new free variable of lowest priority. Then substituting $t$ by $z$ in the resulting expression. For instance \bprog ? substpol(x^4 + x^2 + 1, x^2, y) %1 = y^2 + y + 1 ? substpol(x^4 + x^2 + 1, x^3, y) %2 = x^2 + y*x + 1 ? substpol(x^4 + x^2 + 1, (x+1)^2, y) %3 = (-4*y - 6)*x + (y^2 + 3*y - 3) @eprog Variant: Further, \fun{GEN}{gdeflate}{GEN T, long v, long d} attempts to write $T(x)$ in the form $t(x^d)$, where $x=$\kbd{pol\_x}$(v)$, and returns \kbd{NULL} if the substitution fails (for instance in the example \kbd{\%2} above). pari-2.11.2/src/functions/polynomials/polresultant0000644000175000017500000000412313326135265021010 0ustar billbillFunction: polresultant Section: polynomials C-Name: polresultant0 Prototype: GGDnD0,L, Help: polresultant(x,y,{v},{flag=0}): resultant of the polynomials x and y, with respect to the main variables of x and y if v is omitted, with respect to the variable v otherwise. flag is optional, and can be 0: default, uses either the subresultant algorithm, a modular algorithm or Sylvester's matrix, depending on the inputs; 1 uses Sylvester's matrix (should always be slower than the default). Doc: resultant of the two polynomials $x$ and $y$ with exact entries, with respect to the main variables of $x$ and $y$ if $v$ is omitted, with respect to the variable $v$ otherwise. The algorithm assumes the base ring is a domain. If you also need the $u$ and $v$ such that $x*u + y*v = \text{Res}(x,y)$, use the \tet{polresultantext} function. If $\fl=0$ (default), uses the algorithm best suited to the inputs, either the \idx{subresultant algorithm} (Lazard/Ducos variant, generic case), a modular algorithm (inputs in $\Q[X]$) or Sylvester's matrix (inexact inputs). If $\fl=1$, uses the determinant of Sylvester's matrix instead; this should always be slower than the default. If $x$ or $y$ are multivariate with a huge \emph{polynomial} content, it is advisable to remove it before calling this function. Compare: \bprog ? a = polcyclo(7) * ((t+1)/(t+2))^100; ? b = polcyclo(11)* ((t+2)/(t+3))^100); ? polresultant(a,b); time = 3,833 ms. ? ca = content(a); cb = content(b); \ polresultant(a/ca,b/cb)*ca^poldegree(b)*cb*poldegree(a); \\ instantaneous @eprog\noindent The function only removes rational denominators and does not compute automatically the content because it is generically small and potentially \emph{very} expensive (e.g. in multivariate contexts). The choice is yours, depending on your application. Function: _ZX_resultant_worker C-Name: ZX_resultant_worker Prototype: GGGG Section: programming/internals Help: worker for ZX_resultant Function: _ZX_ZXY_resultant_worker C-Name: ZX_ZXY_resultant_worker Prototype: GGGGG Section: programming/internals Help: worker for ZX_ZXY_resultant pari-2.11.2/src/functions/polynomials/polsubcyclo0000644000175000017500000000134512314242551020606 0ustar billbillFunction: polsubcyclo Section: polynomials C-Name: polsubcyclo Prototype: LLDn Help: polsubcyclo(n,d,{v='x}): finds an equation (in variable v) for the d-th degree subfields of Q(zeta_n). Output is a polynomial, or a vector of polynomials if there are several such fields or none. Doc: gives polynomials (in variable $v$) defining the sub-Abelian extensions of degree $d$ of the cyclotomic field $\Q(\zeta_n)$, where $d\mid \phi(n)$. If there is exactly one such extension the output is a polynomial, else it is a vector of polynomials, possibly empty. To get a vector in all cases, use \kbd{concat([], polsubcyclo(n,d))}. The function \tet{galoissubcyclo} allows to specify exactly which sub-Abelian extension should be computed. pari-2.11.2/src/functions/polynomials/polsym0000644000175000017500000000043511636712103017573 0ustar billbillFunction: polsym Section: polynomials C-Name: polsym Prototype: GL Help: polsym(x,n): column vector of symmetric powers of the roots of x up to n. Doc: creates the column vector of the \idx{symmetric powers} of the roots of the polynomial $x$ up to power $n$, using Newton's formula. pari-2.11.2/src/functions/polynomials/polrootspadic0000644000175000017500000000200713326135265021135 0ustar billbillFunction: polrootspadic Section: polynomials C-Name: rootpadic Prototype: GGL Help: polrootspadic(x,p,r): p-adic roots of the polynomial x to precision r. Doc: vector of $p$-adic roots of the polynomial \var{pol}, given to $p$-adic precision $r$; the integer $p$ is assumed to be a prime. Multiple roots are \emph{not} repeated. Note that this is not the same as the roots in $\Z/p^r\Z$, rather it gives approximations in $\Z/p^r\Z$ of the true roots living in $\Q_p$. \bprog ? polrootspadic(x^3 - x^2 + 64, 2, 5) %1 = [2^3 + O(2^5), 2^3 + 2^4 + O(2^5), 1 + O(2^5)]~ @eprog If \var{pol} has inexact \typ{PADIC} coefficients, this is not always well-defined; in this case, the polynomial is first made integral by dividing out the $p$-adic content, then lifted to $\Z$ using \tet{truncate} coefficientwise. Hence the roots given are approximations of the roots of an exact polynomial which is $p$-adically close to the input. To avoid pitfalls, we advise to only factor polynomials with exact rational coefficients. pari-2.11.2/src/functions/polynomials/polsylvestermatrix0000644000175000017500000000121613201017466022246 0ustar billbillFunction: polsylvestermatrix Section: polynomials C-Name: sylvestermatrix Prototype: GG Help: polsylvestermatrix(x,y): forms the sylvester matrix attached to the two polynomials x and y. Warning: the polynomial coefficients are in columns, not in rows. Doc: forms the Sylvester matrix corresponding to the two polynomials $x$ and $y$, where the coefficients of the polynomials are put in the columns of the matrix (which is the natural direction for solving equations afterwards). The use of this matrix can be essential when dealing with polynomials with inexact entries, since polynomial Euclidean division doesn't make much sense in this case. pari-2.11.2/src/functions/polynomials/polchebyshev0000644000175000017500000000231313201017466020740 0ustar billbillFunction: polchebyshev Section: polynomials C-Name: polchebyshev_eval Prototype: LD1,L,DG Help: polchebyshev(n,{flag=1},{a='x}): Chebychev polynomial of the first (flag = 1) or second (flag = 2) kind, of degree n, evaluated at a. Description: (small,?1,?var):gen polchebyshev1($1,$3) (small,2,?var):gen polchebyshev2($1,$3) (small,small,?var):gen polchebyshev($1,$2,$3) Doc: returns the $n^{\text{th}}$ \idx{Chebyshev} polynomial of the first kind $T_n$ ($\fl=1$) or the second kind $U_n$ ($\fl=2$), evaluated at $a$ (\kbd{'x} by default). Both series of polynomials satisfy the 3-term relation $$ P_{n+1} = 2xP_n - P_{n-1}, $$ and are determined by the initial conditions $U_0 = T_0 = 1$, $T_1 = x$, $U_1 = 2x$. In fact $T_n' = n U_{n-1}$ and, for all complex numbers $z$, we have $T_n(\cos z) = \cos (nz)$ and $U_{n-1}(\cos z) = \sin(nz)/\sin z$. If $n \geq 0$, then these polynomials have degree $n$. For $n < 0$, $T_n$ is equal to $T_{-n}$ and $U_n$ is equal to $-U_{-2-n}$. In particular, $U_{-1} = 0$. Variant: Also available are \fun{GEN}{polchebyshev}{long n, long flag, long v}, \fun{GEN}{polchebyshev1}{long n, long v} and \fun{GEN}{polchebyshev2}{long n, long v} for $T_n$ and $U_n$ respectively. pari-2.11.2/src/functions/polynomials/deriv0000644000175000017500000000152011636712103017355 0ustar billbillFunction: deriv Section: polynomials C-Name: deriv Prototype: GDn Help: deriv(x,{v}): derivative of x with respect to v, or to the main variable of x if v is omitted. Doc: derivative of $x$ with respect to the main variable if $v$ is omitted, and with respect to $v$ otherwise. The derivative of a scalar type is zero, and the derivative of a vector or matrix is done componentwise. One can use $x'$ as a shortcut if the derivative is with respect to the main variable of $x$. By definition, the main variable of a \typ{POLMOD} is the main variable among the coefficients from its two polynomial components (representative and modulus); in other words, assuming a polmod represents an element of $R[X]/(T(X))$, the variable $X$ is a mute variable and the derivative is taken with respect to the main variable used in the base ring $R$. pari-2.11.2/src/functions/polynomials/poliscycloprod0000644000175000017500000000076112314242551021316 0ustar billbillFunction: poliscycloprod Section: polynomials C-Name: poliscycloprod Prototype: lG Help: poliscycloprod(f): returns 1 if f is a product of cyclotomic polynonials, and 0 otherwise. Doc: returns 1 if $f$ is a product of cyclotomic polynomial, and $0$ otherwise. \bprog ? f = x^6+x^5-x^3+x+1; ? poliscycloprod(f) %2 = 1 ? factor(f) %3 = [ x^2 + x + 1 1] [x^4 - x^2 + 1 1] ? [ poliscyclo(T) | T <- %[,1] ] %4 = [3, 12] ? polcyclo(3) * polcyclo(12) %5 = x^6 + x^5 - x^3 + x + 1 @eprog pari-2.11.2/src/functions/polynomials/subst0000644000175000017500000000205611636712103017411 0ustar billbillFunction: subst Section: polynomials C-Name: gsubst Prototype: GnG Help: subst(x,y,z): in expression x, replace the variable y by the expression z. Doc: replace the simple variable $y$ by the argument $z$ in the ``polynomial'' expression $x$. Every type is allowed for $x$, but if it is not a genuine polynomial (or power series, or rational function), the substitution will be done as if the scalar components were polynomials of degree zero. In particular, beware that: \bprog ? subst(1, x, [1,2; 3,4]) %1 = [1 0] [0 1] ? subst(1, x, Mat([0,1])) *** at top-level: subst(1,x,Mat([0,1]) *** ^-------------------- *** subst: forbidden substitution by a non square matrix. @eprog\noindent If $x$ is a power series, $z$ must be either a polynomial, a power series, or a rational function. Finally, if $x$ is a vector, matrix or list, the substitution is applied to each individual entry. Use the function \kbd{substvec} to replace several variables at once, or the function \kbd{substpol} to replace a polynomial expression. pari-2.11.2/src/functions/polynomials/polrootsreal0000644000175000017500000000336013326135265021003 0ustar billbillFunction: polrootsreal Section: polynomials C-Name: realroots Prototype: GDGp Help: polrootsreal(T, {ab}): real roots of the polynomial T with real coefficients, using Uspensky's method. In interval ab = [a,b] if present. Doc: real roots of the polynomial $T$ with real coefficients, multiple roots being included according to their multiplicity. If the polynomial does not have rational coefficients, it is first rescaled and rounded. The roots are given to a relative accuracy of \kbd{realprecision}. If argument \var{ab} is present, it must be a vector $[a,b]$ with two components (of type \typ{INT}, \typ{FRAC} or \typ{INFINITY}) and we restrict to roots belonging to that closed interval. \bprog ? \p9 ? polrootsreal(x^2-2) %1 = [-1.41421356, 1.41421356]~ ? polrootsreal(x^2-2, [1,+oo]) %2 = [1.41421356]~ ? polrootsreal(x^2-2, [2,3]) %3 = []~ ? polrootsreal((x-1)*(x-2), [2,3]) %4 = [2.00000000]~ @eprog\noindent The algorithm used is a modification of Uspensky's method (relying on Descartes's rule of sign), following Rouillier and Zimmerman's article ``Efficient isolation of a polynomial real roots'' (\url{http://hal.inria.fr/inria-00072518/}). Barring bugs, it is guaranteed to converge and to give the roots to the required accuracy. \misctitle{Remark} If the polynomial $T$ is of the form $Q(x^h)$ for some $h\geq 2$ and \var{ab} is omitted, the routine will apply the algorithm to $Q$ (restricting to non-negative roots when $h$ is even), then take $h$-th roots. On the other hand, if you want to specify \var{ab}, you should apply the routine to $Q$ yourself and a suitable interval $[a',b']$ using approximate $h$-th roots adapted to your problem: the function will not perform this change of variables if \var{ab} is present. pari-2.11.2/src/functions/polynomials/diffop0000644000175000017500000000362611636712103017524 0ustar billbillFunction: diffop Section: polynomials C-Name: diffop0 Prototype: GGGD1,L, Description: (gen,gen,gen,?1):gen diffop($1, $2, $3) (gen,gen,gen,small):gen diffop0($1, $2, $3, $4) Help: diffop(x,v,d,{n=1}): apply the differential operator D to x, where D is defined by D(v[i])=d[i], where v is a vector of variable names. D is 0 for variables outside of v unless they appear as modulus of a POLMOD. If the optional parameter n is given, return D^n(x) instead. Doc: Let $v$ be a vector of variables, and $d$ a vector of the same length, return the image of $x$ by the $n$-power ($1$ if n is not given) of the differential operator $D$ that assumes the value \kbd{d[i]} on the variable \kbd{v[i]}. The value of $D$ on a scalar type is zero, and $D$ applies componentwise to a vector or matrix. When applied to a \typ{POLMOD}, if no value is provided for the variable of the modulus, such value is derived using the implicit function theorem. Some examples: This function can be used to differentiate formal expressions: If $E=\exp(X^2)$ then we have $E'=2*X*E$. We can derivate $X*exp(X^2)$ as follow: \bprog ? diffop(E*X,[X,E],[1,2*X*E]) %1 = (2*X^2 + 1)*E @eprog Let \kbd{Sin} and \kbd{Cos} be two function such that $\kbd{Sin}^2+\kbd{Cos}^2=1$ and $\kbd{Cos}'=-\kbd{Sin}$. We can differentiate $\kbd{Sin}/\kbd{Cos}$ as follow, PARI inferring the value of $\kbd{Sin}'$ from the equation: \bprog ? diffop(Mod('Sin/'Cos,'Sin^2+'Cos^2-1),['Cos],[-'Sin]) %1 = Mod(1/Cos^2, Sin^2 + (Cos^2 - 1)) @eprog Compute the Bell polynomials (both complete and partial) via the Faa di Bruno formula: \bprog Bell(k,n=-1)= { my(var(i)=eval(Str("X",i))); my(x,v,dv); v=vector(k,i,if(i==1,'E,var(i-1))); dv=vector(k,i,if(i==1,'X*var(1)*'E,var(i))); x=diffop('E,v,dv,k)/'E; if(n<0,subst(x,'X,1),polcoeff(x,n,'X)) } @eprog Variant: For $n=1$, the function \fun{GEN}{diffop}{GEN x, GEN v, GEN d} is also available. pari-2.11.2/src/functions/polynomials/polroots0000644000175000017500000000142713213263002020123 0ustar billbillFunction: polroots Section: polynomials C-Name: roots Prototype: Gp Help: polroots(T): complex roots of the polynomial T using Schonhage's method, as modified by Gourdon. Doc: complex roots of the polynomial $T$, given as a column vector where each root is repeated according to its multiplicity. The precision is given as for transcendental functions: in GP it is kept in the variable \kbd{realprecision} and is transparent to the user, but it must be explicitly given as a second argument in library mode. The algorithm used is a modification of Sch\"onhage\sidx{Sch\"onage}'s root-finding algorithm, due to and originally implemented by Gourdon. It is guaranteed to converge; if furthermore $T$ has rational coefficients, roots are guaranteed to the required relative accuracy. pari-2.11.2/src/functions/polynomials/substvec0000644000175000017500000000122611636712103020105 0ustar billbillFunction: substvec Section: polynomials C-Name: gsubstvec Prototype: GGG Help: substvec(x,v,w): in expression x, make a best effort to replace the variables v1,...,vn by the expression w1,...,wn. Doc: $v$ being a vector of monomials of degree 1 (variables), $w$ a vector of expressions of the same length, replace in the expression $x$ all occurrences of $v_i$ by $w_i$. The substitutions are done simultaneously; more precisely, the $v_i$ are first replaced by new variables in $x$, then these are replaced by the $w_i$: \bprog ? substvec([x,y], [x,y], [y,x]) %1 = [y, x] ? substvec([x,y], [x,y], [y,x+y]) %2 = [y, x + y] \\ not [y, 2*y] @eprog pari-2.11.2/src/functions/polynomials/polclass0000644000175000017500000001024513201017466020070 0ustar billbillFunction: polclass Section: polynomials C-Name: polclass Prototype: GD0,L,Dn Help: polclass(D, {inv = 0}, {x = 'x}): return a polynomial generating the Hilbert class field of Q(sqrt(D)) for the discriminant D<0. Doc: Return a polynomial in $\Z[x]$ generating the Hilbert class field for the imaginary quadratic discriminant $D$. If $inv$ is 0 (the default), use the modular $j$-function and return the classical Hilbert polynomial, otherwise use a class invariant. The following invariants correspond to the different values of $inv$, where $f$ denotes Weber's function \kbd{weber}, and $w_{p,q}$ the double eta quotient given by $w_{p,q} = \dfrac{ \eta(x/p)\*\eta(x/q) }{ \eta(x)\*\eta(x/{pq}) }$ The invariants $w_{p,q}$ are not allowed unless they satisfy the following technical conditions ensuring they do generate the Hilbert class field and not a strict subfield: \item if $p\neq q$, we need them both non-inert, prime to the conductor of $\Z[\sqrt{D}]$. Let $P, Q$ be prime ideals above $p$ and $q$; if both are unramified, we further require that $P^{\pm 1} Q^{\pm 1}$ be all distinct in the class group of $\Z[\sqrt{D}]$; if both are ramified, we require that $PQ \neq 1$ in the class group. \item if $p = q$, we want it split and prime to the conductor and the prime ideal above it must have order $\neq 1, 2, 4$ in the class group. \noindent Invariants are allowed under the additional conditions on $D$ listed below. \item 0 : $j$ \item 1 : $f$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 2 : $f^2$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 3 : $f^3$, $D = 1 \mod 8$; \item 4 : $f^4$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 5 : $\gamma_2= j^{1/3}$, $D = 1,2 \mod 3$; \item 6 : $w_{2,3}$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 8 : $f^8$, $D = 1 \mod 8$ and $D = 1,2 \mod 3$; \item 9 : $w_{3,3}$, $D = 1 \mod 2$ and $D = 1,2 \mod 3$; \item 10: $w_{2,5}$, $D \neq 60 \mod 80$ and $D = 1,2 \mod 3$; \item 14: $w_{2,7}$, $D = 1 \mod 8$; \item 15: $w_{3,5}$, $D = 1,2 \mod 3$; \item 21: $w_{3,7}$, $D = 1 \mod 2$ and $21$ does not divide $D$ \item 23: $w_{2,3}^2$, $D = 1,2 \mod 3$; \item 24: $w_{2,5}^2$, $D = 1,2 \mod 3$; \item 26: $w_{2,13}$, $D \neq 156 \mod 208$; \item 27: $w_{2,7}^2$, $D\neq 28 \mod 112$; \item 28: $w_{3,3}^2$, $D = 1,2 \mod 3$; \item 35: $w_{5,7}$, $D = 1,2 \mod 3$; \item 39: $w_{3,13}$, $D = 1 \mod 2$ and $D = 1,2 \mod 3$; The algorithm for computing the polynomial does not use the floating point approach, which would evaluate a precise modular function in a precise complex argument. Instead, it relies on a faster Chinese remainder based approach modulo small primes, in which the class invariant is only defined algebraically by the modular polynomial relating the modular function to $j$. So in fact, any of the several roots of the modular polynomial may actually be the class invariant, and more precise assertions cannot be made. For instance, while \kbd{polclass(D)} returns the minimal polynomial of $j(\tau)$ with $\tau$ (any) quadratic integer for the discriminant $D$, the polynomial returned by \kbd{polclass(D, 5)} can be the minimal polynomial of any of $\gamma_2 (\tau)$, $\zeta_3 \gamma_2 (\tau)$ or $\zeta_3^2 \gamma_2 (\tau)$, the three roots of the modular polynomial $j = \gamma_2^3$, in which $j$ has been specialised to $j (\tau)$. The modular polynomial is given by $j = {(f^{24}-16)^3 \over f^{24}}$ for Weber's function $f$. For the double eta quotients of level $N = p q$, all functions are covered such that the modular curve $X_0^+ (N)$, the function field of which is generated by the functions invariant under $\Gamma^0 (N)$ and the Fricke--Atkin--Lehner involution, is of genus $0$ with function field generated by (a power of) the double eta quotient $w$. This ensures that the full Hilbert class field (and not a proper subfield) is generated by class invariants from these double eta quotients. Then the modular polynomial is of degree $2$ in $j$, and of degree $\psi (N) = (p+1)(q+1)$ in $w$. \bprog ? polclass(-163) %1 = x + 262537412640768000 ? polclass(-51, , 'z) %2 = z^2 + 5541101568*z + 6262062317568 ? polclass(-151,1) x^7 - x^6 + x^5 + 3*x^3 - x^2 + 3*x + 1 @eprog pari-2.11.2/src/functions/polynomials/polzagier0000644000175000017500000000177413201017466020253 0ustar billbillFunction: polzagier Section: polynomials C-Name: polzag Prototype: LL Help: polzagier(n,m): Zagier's polynomials of index n,m. Doc: creates Zagier's polynomial $P_n^{(m)}$ used in the functions \kbd{sumalt} and \kbd{sumpos} (with $\fl=1$), see ``Convergence acceleration of alternating series'', Cohen et al., \emph{Experiment.~Math.}, vol.~9, 2000, pp.~3--12. If $m < 0$ or $m \ge n$, $P_n^{(m)} = 0$. We have $P_n := P_n^{(0)}$ is $T_n(2x-1)$, where $T_n$ is the Legendre polynomial of the second kind. For $n > m > 0$, $P_n^{(m)}$ is the $m$-th difference with step $2$ of the sequence $n^{m+1}P_n$; in this case, it satisfies $$2 P_n^{(m)}(sin^2 t) = \dfrac{d^{m+1}}{dt^{m+1}}(\sin(2t)^m \sin(2(n-m)t)).$$ %@article {MR2001m:11222, % AUTHOR = {Cohen, Henri and Rodriguez Villegas, Fernando and Zagier, Don}, % TITLE = {Convergence acceleration of alternating series}, % JOURNAL = {Experiment. Math.}, % VOLUME = {9}, % YEAR = {2000}, % NUMBER = {1}, % PAGES = {3--12}, %} pari-2.11.2/src/functions/polynomials/polrootsbound0000644000175000017500000000222513326135265021166 0ustar billbillFunction: polrootsbound Section: polynomials C-Name: polrootsbound Prototype: GDG Help: polrootsbound(T, {tau = 0.01}): return a sharp upper bound for the modulus of the largest complex root of the polynomial T with relative error tau. Doc: return a sharp upper bound $B$ for the modulus of the largest complex root of the polynomial $T$ with complex coefficients with relative error $\tau$. More precisely, we have $|z| \leq B$ for all roots and there exist one root such that $|z_0| \geq B \exp(-2\tau)$. Much faster than either polroots or polrootsreal. \bprog ? T=poltchebi(500); ? vecmax(abs(polroots(T))) time = 5,706 ms. %2 = 0.99999506520185816611184481744870013191 ? vecmax(abs(polrootsreal(T))) time = 1,972 ms. %3 = 0.99999506520185816611184481744870013191 ? polrootsbound(T) time = 217 ms. %4 = 1.0098792554165905155 ? polrootsbound(T, log(2)/2) \\ allow a factor 2, much faster time = 51 ms. %5 = 1.4065759938190154354 ? polrootsbound(T, 1e-4) time = 504 ms. %6 = 1.0000920717983847741 ? polrootsbound(T, 1e-6) time = 810 ms. %7 = 0.9999960628901692905 ? polrootsbound(T, 1e-10) time = 1,351 ms. %8 = 0.9999950652993869760 @eprog pari-2.11.2/src/functions/polynomials/serlaplace0000644000175000017500000000053313201017466020362 0ustar billbillFunction: serlaplace Section: polynomials C-Name: laplace Prototype: G Help: serlaplace(x): replaces the power series sum of a_n*x^n/n! by sum of a_n*x^n. For the reverse operation, use serconvol(x,exp(X)). Doc: $x$ must be a power series with non-negative exponents or a polynomial. If $x=\sum (a_k/k!)*X^k$ then the result is $\sum a_k*X^k$. pari-2.11.2/src/functions/polynomials/polresultantext0000644000175000017500000000147312314242551021527 0ustar billbillFunction: polresultantext Section: polynomials C-Name: polresultantext0 Prototype: GGDn Help: polresultantext(A,B,{v}): return [U,V,R] such that R=polresultant(A,B,v) and U*A+V*B = R, where A and B are polynomials. Doc: finds polynomials $U$ and $V$ such that $A*U + B*V = R$, where $R$ is the resultant of $U$ and $V$ with respect to the main variables of $A$ and $B$ if $v$ is omitted, and with respect to $v$ otherwise. Returns the row vector $[U,V,R]$. The algorithm used (subresultant) assumes that the base ring is a domain. \bprog ? A = x*y; B = (x+y)^2; ? [U,V,R] = polresultantext(A, B) %2 = [-y*x - 2*y^2, y^2, y^4] ? A*U + B*V %3 = y^4 ? [U,V,R] = polresultantext(A, B, y) %4 = [-2*x^2 - y*x, x^2, x^4] ? A*U+B*V %5 = x^4 @eprog Variant: Also available is \fun{GEN}{polresultantext}{GEN x, GEN y}. pari-2.11.2/src/functions/polynomials/intformal0000644000175000017500000000256513036414402020246 0ustar billbillFunction: intformal Section: polynomials C-Name: integ Prototype: GDn Help: intformal(x,{v}): formal integration of x with respect to v, or to the main variable of x if v is omitted. Doc: \idx{formal integration} of $x$ with respect to the variable $v$ (wrt. the main variable if $v$ is omitted). Since PARI cannot represent logarithmic or arctangent terms, any such term in the result will yield an error: \bprog ? intformal(x^2) %1 = 1/3*x^3 ? intformal(x^2, y) %2 = y*x^2 ? intformal(1/x) *** at top-level: intformal(1/x) *** ^-------------- *** intformal: domain error in intformal: residue(series, pole) != 0 @eprog The argument $x$ can be of any type. When $x$ is a rational function, we assume that the base ring is an integral domain of characteristic zero. By definition, the main variable of a \typ{POLMOD} is the main variable among the coefficients from its two polynomial components (representative and modulus); in other words, assuming a polmod represents an element of $R[X]/(T(X))$, the variable $X$ is a mute variable and the integral is taken with respect to the main variable used in the base ring $R$. In particular, it is meaningless to integrate with respect to the main variable of \kbd{x.mod}: \bprog ? intformal(Mod(1,x^2+1), 'x) *** intformal: incorrect priority in intformal: variable x = x @eprog pari-2.11.2/src/functions/polynomials/polhermite0000644000175000017500000000102612141040641020406 0ustar billbillFunction: polhermite Section: polynomials C-Name: polhermite_eval Prototype: LDG Help: polhermite(n,{a='x}): Hermite polynomial H(n,v) of degree n, evaluated at a. Description: (small,?var):gen polhermite($1,$2) (small,gen):gen polhermite_eval($1,$2) Doc: $n^{\text{th}}$ \idx{Hermite} polynomial $H_n$ evaluated at $a$ (\kbd{'x} by default), i.e. $$ H_n(x) = (-1)^n\*e^{x^2} \dfrac{d^n}{dx^n}e^{-x^2}.$$ Variant: The variant \fun{GEN}{polhermite}{long n, long v} returns the $n$-th Hermite polynomial in variable $v$. pari-2.11.2/src/functions/polynomials/thue0000644000175000017500000000620213326135265017221 0ustar billbillFunction: thue Section: polynomials C-Name: thue Prototype: GGDG Help: thue(tnf,a,{sol}): solve the equation P(x,y)=a, where tnf was created with thueinit(P), and sol, if present, contains the solutions of Norm(x)=a modulo units in the number field defined by P. If tnf was computed without assuming GRH (flag 1 in thueinit), the result is unconditional. If tnf is a polynomial, compute thue(thueinit(P,0), a). Doc: returns all solutions of the equation $P(x,y)=a$ in integers $x$ and $y$, where \var{tnf} was created with $\kbd{thueinit}(P)$. If present, \var{sol} must contain the solutions of $\Norm(x)=a$ modulo units of positive norm in the number field defined by $P$ (as computed by \kbd{bnfisintnorm}). If there are infinitely many solutions, an error is issued. It is allowed to input directly the polynomial $P$ instead of a \var{tnf}, in which case, the function first performs \kbd{thueinit(P,0)}. This is very wasteful if more than one value of $a$ is required. If \var{tnf} was computed without assuming GRH (flag $1$ in \tet{thueinit}), then the result is unconditional. Otherwise, it depends in principle of the truth of the GRH, but may still be unconditionally correct in some favorable cases. The result is conditional on the GRH if $a\neq \pm 1$ and $P$ has a single irreducible rational factor, whose attached tentative class number $h$ and regulator $R$ (as computed assuming the GRH) satisfy \item $h > 1$, \item $R/0.2 > 1.5$. Here's how to solve the Thue equation $x^{13} - 5y^{13} = - 4$: \bprog ? tnf = thueinit(x^13 - 5); ? thue(tnf, -4) %1 = [[1, 1]] @eprog\noindent In this case, one checks that \kbd{bnfinit(x\pow13 -5).no} is $1$. Hence, the only solution is $(x,y) = (1,1)$ and the result is unconditional. On the other hand: \bprog ? P = x^3-2*x^2+3*x-17; tnf = thueinit(P); ? thue(tnf, -15) %2 = [[1, 1]] \\ a priori conditional on the GRH. ? K = bnfinit(P); K.no %3 = 3 ? K.reg %4 = 2.8682185139262873674706034475498755834 @eprog This time the result is conditional. All results computed using this particular \var{tnf} are likewise conditional, \emph{except} for a right-hand side of $\pm 1$. The above result is in fact correct, so we did not just disprove the GRH: \bprog ? tnf = thueinit(x^3-2*x^2+3*x-17, 1 /*unconditional*/); ? thue(tnf, -15) %4 = [[1, 1]] @eprog Note that reducible or non-monic polynomials are allowed: \bprog ? tnf = thueinit((2*x+1)^5 * (4*x^3-2*x^2+3*x-17), 1); ? thue(tnf, 128) %2 = [[-1, 0], [1, 0]] @eprog\noindent Reducible polynomials are in fact much easier to handle. \misctitle{Note} When $P$ is irreducible without a real root, the default strategy is to use brute force enumeration in time $|a|^{1/\deg P}$ and avoid computing a touch \var{bnf} attached to $P$, see \kbd{thueinit}. Besides reusing a quantity you might need for other purposes, the default argument \emph{sol} can also be used to use a different strategy and prove that there are no solutions; of course you need to compute a \var{bnf} on you own to obtain \emph{sol}. If there \emph{are} solutions this won't help unless $P$ is quadratic, since the enumeration will be performed in any case. pari-2.11.2/src/functions/polynomials/padicappr0000644000175000017500000000174113457600745020227 0ustar billbillFunction: padicappr Section: polynomials C-Name: padicappr Prototype: GG Help: padicappr(pol,a): p-adic roots of the polynomial pol congruent to a mod p. Doc: vector of $p$-adic roots of the polynomial \var{pol} congruent to the $p$-adic number $a$ modulo $p$, and with the same $p$-adic precision as $a$. The number $a$ can be an ordinary $p$-adic number (type \typ{PADIC}, i.e.~an element of $\Z_p$) or can be an integral element of a finite \emph{unramified} extension $\Q_p[X]/(T)$ of $\Q_p$, given as a \typ{POLMOD} \kbd{Mod}$(A,T)$ at least one of whose coefficients is a \typ{PADIC} and $T$ irreducible modulo $p$. In this case, the result is the vector of roots belonging to the same extension of $\Q_p$ as $a$. The polynomial \var{pol} should have exact coefficients; if not, its coefficients are first rounded to $\Q$ or $\Q[X]/(T)$ and this is the polynomial whose roots we consider. Variant: Also available is \fun{GEN}{Zp_appr}{GEN f, GEN a} when $a$ is a \typ{PADIC}. pari-2.11.2/src/functions/polynomials/poltchebi0000644000175000017500000000031613201017466020217 0ustar billbillFunction: poltchebi Section: polynomials C-Name: polchebyshev1 Prototype: LDn Obsolete: 2013-04-03 Help: poltchebi(n,{v='x}): deprecated alias for polchebyshev. Doc: deprecated alias for \kbd{polchebyshev} pari-2.11.2/src/functions/polynomials/sumformal0000644000175000017500000000202012314242551020244 0ustar billbillFunction: sumformal Section: polynomials C-Name: sumformal Prototype: GDn Help: sumformal(f,{v}): formal sum of f with respect to v, or to the main variable of f if v is omitted. Doc: \idx{formal sum} of the polynomial expression $f$ with respect to the main variable if $v$ is omitted, with respect to the variable $v$ otherwise; it is assumed that the base ring has characteristic zero. In other words, considering $f$ as a polynomial function in the variable $v$, returns $F$, a polynomial in $v$ vanishing at $0$, such that $F(b) - F(a) = sum_{v = a+1}^b f(v)$: \bprog ? sumformal(n) \\ 1 + ... + n %1 = 1/2*n^2 + 1/2*n ? f(n) = n^3+n^2+1; ? F = sumformal(f(n)) \\ f(1) + ... + f(n) %3 = 1/4*n^4 + 5/6*n^3 + 3/4*n^2 + 7/6*n ? sum(n = 1, 2000, f(n)) == subst(F, n, 2000) %4 = 1 ? sum(n = 1001, 2000, f(n)) == subst(F, n, 2000) - subst(F, n, 1000) %5 = 1 ? sumformal(x^2 + x*y + y^2, y) %6 = y*x^2 + (1/2*y^2 + 1/2*y)*x + (1/3*y^3 + 1/2*y^2 + 1/6*y) ? x^2 * y + x * sumformal(y) + sumformal(y^2) == % %7 = 1 @eprog pari-2.11.2/src/functions/polynomials/bezoutres0000644000175000017500000000032713201017466020272 0ustar billbillFunction: bezoutres Section: polynomials C-Name: polresultantext0 Prototype: GGDn Obsolete: 2015-01-13 Help: bezoutres(A,B,{v}): deprecated alias for polresultantext. Doc: deprecated alias for \kbd{polresultantext} pari-2.11.2/src/functions/polynomials/polcyclofactors0000644000175000017500000000162013201017466021453 0ustar billbillFunction: polcyclofactors Section: polynomials C-Name: polcyclofactors Prototype: G Help: polcyclofactors(f): returns a vector of polynomials, whose product is the product of distinct cyclotomic polynomials dividing f. Doc: returns a vector of polynomials, whose product is the product of distinct cyclotomic polynomials dividing $f$. \bprog ? f = x^10+5*x^8-x^7+8*x^6-4*x^5+8*x^4-3*x^3+7*x^2+3; ? v = polcyclofactors(f) %2 = [x^2 + 1, x^2 + x + 1, x^4 - x^3 + x^2 - x + 1] ? apply(poliscycloprod, v) %3 = [1, 1, 1] ? apply(poliscyclo, v) %4 = [4, 3, 10] @eprog\noindent In general, the polynomials are products of cyclotomic polynomials and not themselves irreducible: \bprog ? g = x^8+2*x^7+6*x^6+9*x^5+12*x^4+11*x^3+10*x^2+6*x+3; ? polcyclofactors(g) %2 = [x^6 + 2*x^5 + 3*x^4 + 3*x^3 + 3*x^2 + 2*x + 1] ? factor(%[1]) %3 = [ x^2 + x + 1 1] [x^4 + x^3 + x^2 + x + 1 1] @eprog pari-2.11.2/src/functions/polynomials/polgraeffe0000644000175000017500000000037313201017466020363 0ustar billbillFunction: polgraeffe Section: polynomials C-Name: polgraeffe Prototype: G Help: polgraeffe(f): returns the Graeffe transform g of f, such that g(x^2) = f(x)f(-x). Doc: returns the \idx{Graeffe} transform $g$ of $f$, such that $g(x^2) = f(x) f(-x)$. pari-2.11.2/src/functions/polynomials/pollegendre0000644000175000017500000000071411636712103020550 0ustar billbillFunction: pollegendre Section: polynomials C-Name: pollegendre_eval Prototype: LDG Help: pollegendre(n,{a='x}): legendre polynomial of degree n evaluated at a. Description: (small,?var):gen pollegendre($1,$2) (small,gen):gen pollegendre_eval($1,$2) Doc: $n^{\text{th}}$ \idx{Legendre polynomial} evaluated at $a$ (\kbd{'x} by default). Variant: To obtain the $n$-th Legendre polynomial in variable $v$, use \fun{GEN}{pollegendre}{long n, long v}. pari-2.11.2/src/functions/polynomials/polisirreducible0000644000175000017500000000071412314242551021607 0ustar billbillFunction: polisirreducible Section: polynomials C-Name: isirreducible Prototype: lG Help: polisirreducible(pol): true(1) if pol is an irreducible non-constant polynomial, false(0) if pol is reducible or constant. Doc: \var{pol} being a polynomial (univariate in the present version \vers), returns 1 if \var{pol} is non-constant and irreducible, 0 otherwise. Irreducibility is checked over the smallest base field over which \var{pol} seems to be defined. pari-2.11.2/src/functions/polynomials/polrecip0000644000175000017500000000036011636712103020062 0ustar billbillFunction: polrecip Section: polynomials C-Name: polrecip Prototype: G Help: polrecip(pol): reciprocal polynomial of pol. Doc: reciprocal polynomial of \var{pol}, i.e.~the coefficients are in reverse order. \var{pol} must be a polynomial. pari-2.11.2/src/functions/polynomials/polmodular0000644000175000017500000000326413201017466020431 0ustar billbillFunction: polmodular Section: polynomials C-Name: polmodular Prototype: LD0,L,DGDnD0,L, Help: polmodular(L, {inv = 0}, {x = 'x}, {y = 'y}, {derivs = 0}): return the modular polynomial of level L and invariant inv. Doc: Return the modular polynomial of prime level $L$ in variables $x$ and $y$ for the modular function specified by \kbd{inv}. If \kbd{inv} is 0 (the default), use the modular $j$ function, if \kbd{inv} is 1 use the Weber-$f$ function, and if \kbd{inv} is 5 use $\gamma_2 = \sqrt[3]{j}$. See \kbd{polclass} for the full list of invariants. If $x$ is given as \kbd{Mod(j, p)} or an element $j$ of a finite field (as a \typ{FFELT}), then return the modular polynomial of level $L$ evaluated at $j$. If $j$ is from a finite field and \kbd{derivs} is non-zero, then return a triple where the last two elements are the first and second derivatives of the modular polynomial evaluated at $j$. \bprog ? polmodular(3) %1 = x^4 + (-y^3 + 2232*y^2 - 1069956*y + 36864000)*x^3 + ... ? polmodular(7, 1, , 'J) %2 = x^8 - J^7*x^7 + 7*J^4*x^4 - 8*J*x + J^8 ? polmodular(7, 5, 7*ffgen(19)^0, 'j) %3 = j^8 + 4*j^7 + 4*j^6 + 8*j^5 + j^4 + 12*j^2 + 18*j + 18 ? polmodular(7, 5, Mod(7,19), 'j) %4 = Mod(1, 19)*j^8 + Mod(4, 19)*j^7 + Mod(4, 19)*j^6 + ... ? u = ffgen(5)^0; T = polmodular(3,0,,'j)*u; ? polmodular(3, 0, u,'j,1) %6 = [j^4 + 3*j^2 + 4*j + 1, 3*j^2 + 2*j + 4, 3*j^3 + 4*j^2 + 4*j + 2] ? subst(T,x,u) %7 = j^4 + 3*j^2 + 4*j + 1 ? subst(T',x,u) %8 = 3*j^2 + 2*j + 4 ? subst(T'',x,u) %9 = 3*j^3 + 4*j^2 + 4*j + 2 @eprog Function: _polmodular_worker Section: programming/internals C-Name: polmodular_worker Prototype: UUUGGGGLGG Help: used by polmodular Doc: used by polmodular pari-2.11.2/src/functions/polynomials/poldisc0000644000175000017500000000140313201017466017701 0ustar billbillFunction: poldisc Section: polynomials C-Name: poldisc0 Prototype: GDn Help: poldisc(pol,{v}): discriminant of the polynomial pol, with respect to main variable if v is omitted, with respect to v otherwise. Description: (gen):gen poldisc0($1, -1) (gen, var):gen poldisc0($1, $2) Doc: discriminant of the polynomial \var{pol} in the main variable if $v$ is omitted, in $v$ otherwise. Uses a modular algorithm over $\Z$ or $\Q$, and the \idx{subresultant algorithm} otherwise. \bprog ? T = x^4 + 2*x+1; ? poldisc(T) %2 = -176 ? poldisc(T^2) %3 = 0 @eprog For convenience, the function also applies to types \typ{QUAD} and \typ{QFI}/\typ{QFR}: \bprog ? z = 3*quadgen(8) + 4; ? poldisc(z) %2 = 8 ? q = Qfb(1,2,3); ? poldisc(q) %4 = -8 @eprog pari-2.11.2/src/functions/polynomials/polcoeff0000644000175000017500000000064213326135265020053 0ustar billbillFunction: polcoeff Section: polynomials C-Name: polcoeff0 Prototype: GLDn Help: polcoeff(x,n,{v}): deprecated alias for polcoef. Description: (pol, 0):gen:copy constant_coeff($1) (pol, 0,):gen:copy constant_coeff($1) (pol, small):gen:copy RgX_coeff($1, $2) (pol, small,):gen:copy RgX_coeff($1, $2) (gen, small, ?var):gen polcoeff0($1, $2, $3) Obsolete: 2018-05-14 Doc: Deprecated alias for polcoef. pari-2.11.2/src/functions/sums/0000755000175000017500000000000013461316051014744 5ustar billbillpari-2.11.2/src/functions/sums/laurentseries0000644000175000017500000000355713447371554017603 0ustar billbillFunction: laurentseries Section: sums C-Name: laurentseries0 Prototype: GDPDnp Help: laurentseries(f, {M = seriesprecision}, {x='x}): expand f around 0 as a Laurent series in x to order M. Doc: Expand $f$ as a Laurent series around $x = 0$ to order $M$. This function computes $f(x + O(x^n))$ until $n$ is large enough: it must be possible to evaluate $f$ on a power series with $0$ constant term. \bprog ? laurentseries(t->sin(t)/(1-cos(t)), 5) %1 = 2*x^-1 - 1/6*x - 1/360*x^3 - 1/15120*x^5 + O(x^6) ? laurentseries(log) *** at top-level: laurentseries(log) *** ^------------------ *** in function laurentseries: log *** ^--- *** log: domain error in log: series valuation != 0 @eprog Note that individual Laurent coefficients of order $\leq M$ can be retrieved from $s = \kbd{laurentseries}(f,M)$ via \kbd{polcoeff(s,i)} for any $i \leq M$. The series $s$ may occasionally be more precise that the required $O(x^{M+1})$. With respect to successive calls to \tet{derivnum}, \kbd{laurentseries} is both faster and more precise: \bprog ? laurentseries(t->log(3+t),1) %1 = 1.0986122886681096913952452369225257047 + 1/3*x - 1/18*x^2 + O(x^3) ? derivnum(t=0,log(3+t),1) %2 = 0.33333333333333333333333333333333333333 ? derivnum(t=0,log(3+t),2) %3 = -0.11111111111111111111111111111111111111 ? f = x->sin(exp(x)); ? polcoeff(laurentseries(x->f(x+2), 1), 1) %5 = 3.3129294231043339804683687620360224365 ? exp(2) * cos(exp(2)); %6 = 3.3129294231043339804683687620360224365 ? derivnum(x = 2, f(x)) %7 = 3.3129294231043339804683687620360224364 \\ 1 ulp off ? default(realprecision,115); ? for(i=1,10^4, laurentseries(x->f(x+2),1)) time = 279 ms. ? for(i=1,10^4, derivnum(x=2,f(x))) \\ ... and slower time = 1,134 ms. @eprog \synt{laurentseries}{void *E, GEN (*f)(void*,GEN,long), long M, long v, long prec}. pari-2.11.2/src/functions/sums/suminf0000644000175000017500000000220513201017466016167 0ustar billbillFunction: suminf Section: sums C-Name: suminf0 Prototype: V=GEp Help: suminf(X=a,expr): infinite sum (X goes from a to infinity) of real or complex expression expr. Wrapper: (,G) Description: (gen,gen):gen:prec suminf(${2 cookie}, ${2 wrapper}, $1, $prec) Doc: \idx{infinite sum} of expression \var{expr}, the formal parameter $X$ starting at $a$. The evaluation stops when the relative error of the expression is less than the default precision for 3 consecutive evaluations. The expressions must always evaluate to a complex number. If the series converges slowly, make sure \kbd{realprecision} is low (even 28 digits may be too much). In this case, if the series is alternating or the terms have a constant sign, \tet{sumalt} and \tet{sumpos} should be used instead. \bprog ? \p28 ? suminf(i = 1, -(-1)^i / i) \\@com Had to hit \kbd{C-C} *** at top-level: suminf(i=1,-(-1)^i/i) *** ^------ *** suminf: user interrupt after 10min, 20,100 ms. ? sumalt(i = 1, -(-1)^i / i) - log(2) time = 0 ms. %1 = -2.524354897 E-29 @eprog \synt{suminf}{void *E, GEN (*eval)(void*,GEN), GEN a, long prec}. pari-2.11.2/src/functions/sums/prodeulerrat0000644000175000017500000000064613326135265017413 0ustar billbillFunction: prodeulerrat Section: sums C-Name: prodeulerrat Prototype: GDGD2,L,p Help: prodeulerrat(F,{s=1},{a=2}): product from primes p = a to infinity of F(p^s), where F is a rational function. Doc: $\prod_{p\ge a, p prime}F(p^s)$, where $F$ is a rational function. \bprog ? prodeulerrat(1+1/q^3,1) %1 = 1.1815649490102569125693997341604542605 ? zeta(3)/zeta(6) %2 = 1.1815649490102569125693997341604542606 @eprog pari-2.11.2/src/functions/sums/intnuminit0000644000175000017500000000477713326135265017112 0ustar billbillFunction: intnuminit Section: sums C-Name: intnuminit Prototype: GGD0,L,p Help: intnuminit(a,b,{m=0}): initialize tables for integrations from a to b. See help for intnum for coding of a and b. Possible types: compact interval, semi-compact (one extremity at + or - infinity) or R, and very slowly, slowly or exponentially decreasing, or sine or cosine oscillating at infinities. Doc: initialize tables for integration from $a$ to $b$, where $a$ and $b$ are coded as in \kbd{intnum}. Only the compactness, the possible existence of singularities, the speed of decrease or the oscillations at infinity are taken into account, and not the values. For instance {\tt intnuminit(-1,1)} is equivalent to {\tt intnuminit(0,Pi)}, and {\tt intnuminit([0,-1/2],oo)} is equivalent to {\tt intnuminit([-1,-1/2], -oo)}; on the other hand, the order matters and {\tt intnuminit([0,-1/2], [1,-1/3])} is \emph{not} equivalent to {\tt intnuminit([0,-1/3], [1,-1/2])} ! If $m$ is present, it must be non-negative and we multiply the default number of sampling points by $2^m$ (increasing the running time by a similar factor). The result is technical and liable to change in the future, but we document it here for completeness. Let $x=\phi(t)$, $t\in ]-\infty,\infty[$ be an internally chosen change of variable, achieving double exponential decrease of the integrand at infinity. The integrator \kbd{intnum} will compute $$ h \sum_{|n| < N} \phi'(nh) F(\phi(nh)) $$ for some integration step $h$ and truncation parameter $N$. In basic use, let \bprog [h, x0, w0, xp, wp, xm, wm] = intnuminit(a,b); @eprog \item $h$ is the integration step \item $x_0 = \phi(0)$ and $w_0 = \phi'(0)$, \item \var{xp} contains the $\phi(nh)$, $0 < n < N$, \item \var{xm} contains the $\phi(nh)$, $0 < -n < N$, or is empty. \item \var{wp} contains the $\phi'(nh)$, $0 < n < N$, \item \var{wm} contains the $\phi'(nh)$, $0 < -n < N$, or is empty. The arrays \var{xm} and \var{wm} are left empty when $\phi$ is an odd function. In complicated situations when non-default behavior is specified at end points, \kbd{intnuminit} may return up to $3$ such arrays, corresponding to a splitting of up to $3$ integrals of basic type. If the functions to be integrated later are of the form $F = f(t) k(t,z)$ for some kernel $k$ (e.g. Fourier, Laplace, Mellin, \dots), it is useful to also precompute the values of $f(\phi(nh))$, which is accomplished by \tet{intfuncinit}. The hard part is to determine the behavior of $F$ at endpoints, depending on $z$. pari-2.11.2/src/functions/sums/sumnummonieninit0000644000175000017500000000616213326135265020320 0ustar billbillFunction: sumnummonieninit Section: sums C-Name: sumnummonieninit Prototype: DGDGDGp Help: sumnummonieninit({asymp},{w},{n0 = 1}): initialize tables for Monien summation of a series with positive terms. Doc: initialize tables for Monien summation of a series $\sum_{n\geq n_0} f(n)$ where $f(1/z)$ has a complex analytic continuation in a (complex) neighbourhood of the segment $[0,1]$. By default, assume that $f(n) = O(n^{-2})$ and has a non-zero asymptotic expansion $$f(n) = \sum_{i\geq 2} a_i / n^i$$ at infinity. Note that the sum starts at $i = 2$! The argument \kbd{asymp} allows to specify different expansions: \item a real number $\beta > 0$ means $$f(n) = \sum_{i\geq 1} a_i / n^{i + \beta}$$ (Now the summation starts at $1$.) \item a vector $[\alpha,\beta]$ of reals, where we must have $\alpha > 0$ and $\alpha + \beta > 1$ to ensure convergence, means that $$f(n) = \sum_{i\geq 1} a_i / n^{\alpha i + \beta}$$ Note that $\kbd{asymp} = [1, \beta]$ is equivalent to $\kbd{asymp}=\beta$. \bprog ? \p57 ? s = sumnum(n = 1, sin(1/sqrt(n)) / n); \\ reference point ? \p38 ? sumnummonien(n = 1, sin(1/sqrt(n)) / n) - s %2 = -0.001[...] \\ completely wrong ? t = sumnummonieninit(1/2); \\ f(n) = sum_i 1 / n^(i+1/2) ? sumnummonien(n = 1, sin(1/sqrt(n)) / n, t) - s %3 = 0.E-37 \\ now correct @eprog\noindent (As a matter of fact, in the above summation, the result given by \kbd{sumnum} at \kbd{\bs p38} is slighly incorrect, so we had to increase the accuracy to \kbd{\bs p57}.) The argument $w$ is used to sum expressions of the form $$ \sum_{n\geq n_0} f(n) w(n),$$ for varying $f$ \emph{as above}, and fixed weight function $w$, where we further assume that the auxiliary sums $$g_w(m) = \sum_{n\geq n_0} w(n) / n^{\alpha m + \beta} $$ converge for all $m\geq 1$. Note that for non-negative integers $k$, and weight $w(n) = (\log n)^k$, the function $g_w(m) = \zeta^{(k)}(\alpha m + \beta)$ has a simple expression; for general weights, $g_w$ is computed using \kbd{sumnum}. The following variants are available \item an integer $k \geq 0$, to code $w(n) = (\log n)^k$; \item a \typ{CLOSURE} computing the values $w(n)$, where we assume that $w(n) = O(n^\epsilon)$ for all $\epsilon > 0$; \item a vector $[w, \kbd{fast}]$, where $w$ is a closure as above and \kbd{fast} is a scalar; we assume that $w(n) = O(n^{\kbd{fast}+\epsilon})$; note that $\kbd{w} = [w, 0]$ is equivalent to $\kbd{w} = w$. Note that if $w$ decreases exponentially, \kbd{suminf} should be used instead. The subsequent calls to \kbd{sumnummonien} \emph{must} use the same value of $n_0$ as was used here. \bprog ? \p300 ? sumnummonien(n = 1, n^-2*log(n)) + zeta'(2) time = 328 ms. %1 = -1.323[...]E-6 \\ completely wrong, f does not satisfy hypotheses ! ? tab = sumnummonieninit(, 1); \\ codes w(n) = log(n) time = 3,993 ms. ? sumnummonien(n = 1, n^-2, tab) + zeta'(2) time = 41 ms. %3 = -5.562684646268003458 E-309 \\ now perfect ? tab = sumnummonieninit(, n->log(n)); \\ generic, slower time = 9,808 ms. ? sumnummonien(n = 1, n^-2, tab) + zeta'(2) time = 40 ms. %5 = -5.562684646268003458 E-309 \\ identical result @eprog pari-2.11.2/src/functions/sums/contfracinit0000644000175000017500000000133313201017466017352 0ustar billbillFunction: contfracinit Section: sums C-Name: contfracinit Prototype: GD-1,L, Help: contfracinit(M,{lim = -1}): given M representing the power series S = sum_{n>=0} M[n+1]z^n, transform it into a continued fraction suitable for evaluation. Doc: Given $M$ representing the power series $S=\sum_{n\ge0} M[n+1]z^n$, transform it into a continued fraction; restrict to $n\leq \kbd{lim}$ if latter is non-negative. $M$ can be a vector, a power series, a polynomial, or a rational function. The result is a 2-component vector $[A,B]$ such that $S = M[1] / (1+A[1]z+B[1]z^2/(1+A[2]z+B[2]z^2/(1+...1/(1+A[lim/2]z))))$. Does not work if any coefficient of $M$ vanishes, nor for series for which certain partial denominators vanish. pari-2.11.2/src/functions/sums/sumnum0000644000175000017500000001350413326135265016224 0ustar billbillFunction: sumnum Section: sums C-Name: sumnum0 Prototype: V=GEDGp Help: sumnum(n=a,f,{tab}): numerical summation of f(n) from n = a to +infinity using Euler-MacLaurin summation. Assume that f corresponds to a series with positive terms and is a C^oo function; a must be an integer, and tab, if given, is the output of sumnuminit. Wrapper: (,G) Description: (gen,gen,?gen):gen:prec sumnum(${2 cookie}, ${2 wrapper}, $1, $3, $prec) Doc: Numerical summation of $f(n)$ at high accuracy using Euler-MacLaurin, the variable $n$ taking values from $a$ to $+\infty$, where $f$ is assumed to have positive values and is a $C^\infty$ function; \kbd{a} must be an integer and \kbd{tab}, if given, is the output of \kbd{sumnuminit}. The latter precomputes abscissas and weights, speeding up the computation; it also allows to specify the behavior at infinity via \kbd{sumnuminit([+oo, asymp])}. \bprog ? \p500 ? z3 = zeta(3); ? sumpos(n = 1, n^-3) - z3 time = 2,332 ms. %2 = 2.438468843 E-501 ? sumnum(n = 1, n^-3) - z3 \\ here slower than sumpos time = 2,752 ms. %3 = 0.E-500 @eprog \misctitle{Complexity} The function $f$ will be evaluated at $O(D \log D)$ real arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. The routine is geared towards slowly decreasing functions: if $f$ decreases exponentially fast, then one of \kbd{suminf} or \kbd{sumpos} should be preferred. If $f$ satisfies the stronger hypotheses required for Monien summation, i.e. if $f(1/z)$ is holomorphic in a complex neighbourhood of $[0,1]$, then \tet{sumnummonien} will be faster since it only requires $O(D/\log D)$ evaluations: \bprog ? sumnummonien(n = 1, 1/n^3) - z3 time = 1,985 ms. %3 = 0.E-500 @eprog\noindent The \kbd{tab} argument precomputes technical data not depending on the expression being summed and valid for a given accuracy, speeding up immensely later calls: \bprog ? tab = sumnuminit(); time = 2,709 ms. ? sumnum(n = 1, 1/n^3, tab) - z3 \\ now much faster than sumpos time = 40 ms. %5 = 0.E-500 ? tabmon = sumnummonieninit(); \\ Monien summation allows precomputations too time = 1,781 ms. ? sumnummonien(n = 1, 1/n^3, tabmon) - z3 time = 2 ms. %7 = 0.E-500 @eprog\noindent The speedup due to precomputations becomes less impressive when the function $f$ is expensive to evaluate, though: \bprog ? sumnum(n = 1, lngamma(1+1/n)/n, tab); time = 14,180 ms. ? sumnummonien(n = 1, lngamma(1+1/n)/n, tabmon); \\ fewer evaluations time = 717 ms. @eprog \misctitle{Behaviour at infinity} By default, \kbd{sumnum} assumes that \var{expr} decreases slowly at infinity, but at least like $O(n^{-2})$. If the function decreases like $n^{\alpha}$ for some $-2 < \alpha < -1$, then it must be indicated via \bprog tab = sumnuminit([+oo, alpha]); /* alpha < 0 slow decrease */ @eprog\noindent otherwise loss of accuracy is expected. If the functions decreases quickly, like $\exp(-\alpha n)$ for some $\alpha > 0$, then it must be indicated via \bprog tab = sumnuminit([+oo, alpha]); /* alpha > 0 exponential decrease */ @eprog\noindent otherwise exponent overflow will occur. \bprog ? sumnum(n=1,2^-n) *** at top-level: sumnum(n=1,2^-n) *** ^---- *** _^_: overflow in expo(). ? tab = sumnuminit([+oo,log(2)]); sumnum(n=1,2^-n, tab) %1 = 1.000[...] @eprog As a shortcut, one can also input \bprog sumnum(n = [a, asymp], f) @eprog\noindent instead of \bprog tab = sumnuminit(asymp); sumnum(n = a, f, tab) @eprog \misctitle{Further examples} \bprog ? \p200 ? sumnum(n = 1, n^(-2)) - zeta(2) \\ accurate, fast time = 200 ms. %1 = -2.376364457868949779 E-212 ? sumpos(n = 1, n^(-2)) - zeta(2) \\ even faster time = 96 ms. %2 = 0.E-211 ? sumpos(n=1,n^(-4/3)) - zeta(4/3) \\ now much slower time = 13,045 ms. %3 = -9.980730723049589073 E-210 ? sumnum(n=1,n^(-4/3)) - zeta(4/3) \\ fast but inaccurate time = 365 ms. %4 = -9.85[...]E-85 ? sumnum(n=[1,-4/3],n^(-4/3)) - zeta(4/3) \\ with decrease rate, now accurate time = 416 ms. %5 = -4.134874156691972616 E-210 ? tab = sumnuminit([+oo,-4/3]); time = 196 ms. ? sumnum(n=1, n^(-4/3), tab) - zeta(4/3) \\ faster with precomputations time = 216 ms. %5 = -4.134874156691972616 E-210 ? sumnum(n=1,-log(n)*n^(-4/3), tab) - zeta'(4/3) time = 321 ms. %7 = 7.224147951921607329 E-210 @eprog Note that in the case of slow decrease ($\alpha < 0$), the exact decrease rate must be indicated, while in the case of exponential decrease, a rough value will do. In fact, for exponentially decreasing functions, \kbd{sumnum} is given for completeness and comparison purposes only: one of \kbd{suminf} or \kbd{sumpos} should always be preferred. \bprog ? sumnum(n=[1, 1], 2^-n) \\ pretend we decrease as exp(-n) time = 240 ms. %8 = 1.000[...] \\ perfect ? sumpos(n=1, 2^-n) %9 = 1.000[...] \\ perfect and instantaneous @eprog \misctitle{Beware cancellation} The function $f(n)$ is evaluated for huge values of $n$, so beware of cancellation in the evaluation: \bprog ? f(n) = 2 - 1/n - 2*n*log(1+1/n); \\ result is O(1/n^2) ? z = -2 + log(2*Pi) - Euler; ? sumnummonien(n=1, f(n)) - z time = 149 ms. %12 = 0.E-212 \\ perfect ? sumnum(n=1, f(n)) - z time = 116 ms. %13 = -948.216[...] \\ junk @eprog\noindent As \kbd{sumnum(n=1, print(n))} shows, we evaluate $f(n)$ for $n > 1e233$ and our implementation of $f$ suffers from massive cancellation since we are summing two terms of the order of $O(1)$ for a result in $O(1/n^2)$. You can either rewrite your sum so that individual terms are evaluated without cancellation or locally replace $f(n)$ by an accurate asymptotic expansion: \bprog ? F = truncate( f(1/x + O(x^30)) ); ? sumnum(n=1, if(n > 1e7, subst(F,x,1/n), f(n))) - z %15 = 1.1 E-212 \\ now perfect @eprog \synt{sumnum}{(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec)} where an omitted \var{tab} is coded as \kbd{NULL}. pari-2.11.2/src/functions/sums/intfuncinit0000644000175000017500000000645113326135265017235 0ustar billbillFunction: intfuncinit Section: sums C-Name: intfuncinit0 Prototype: V=GGED0,L,p Help: intfuncinit(t=a,b,f,{m=0}): initialize tables for integrations from a to b using a weight f(t). For integral transforms such as Fourier or Mellin transforms. Wrapper: (,,G) Description: (gen,gen,gen,?small):gen:prec intfuncinit(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) Doc: initialize tables for use with integral transforms (such as Fourier, Laplace or Mellin transforms) in order to compute $$ \int_a^b f(t) k(t,z) \, dt $$ for some kernel $k(t,z)$. The endpoints $a$ and $b$ are coded as in \kbd{intnum}, $f$ is the function to which the integral transform is to be applied and the non-negative integer $m$ is as in \kbd{intnum}: multiply the number of sampling points roughly by $2^m$, hopefully increasing the accuracy. This function is particularly useful when the function $f$ is hard to compute, such as a gamma product. \misctitle{Limitation} the endpoints $a$ and $b$ must be at infinity, with the same asymptotic behavior. Oscillating types are not supported. This is easily overcome by integrating vectors of functions, see example below. \misctitle{Examples} \item numerical Fourier transform $$F(z) = \int_{-\infty}^{+\infty} f(t)e^{-2i\pi z t}\, dt. $$ First the easy case, assume that $f$ decrease exponentially: \bprog f(t) = exp(-t^2); A = [-oo,1]; B = [+oo,1]; \p200 T = intfuncinit(t = A,B , f(t)); F(z) = { my(a = -2*I*Pi*z); intnum(t = A,B, exp(a*t), T); } ? F(1) - sqrt(Pi)*exp(-Pi^2) %1 = -1.3... E-212 @eprog\noindent Now the harder case, $f$ decrease slowly: we must specify the oscillating behavior. Thus, we cannot precompute usefully since everything depends on the point we evaluate at: \bprog f(t) = 1 / (1+ abs(t)); \p200 \\ Fourier cosine transform FC(z) = { my(a = 2*Pi*z); intnum(t = [-oo, a*I], [+oo, a*I], cos(a*t)*f(t)); } FC(1) @eprog \item Fourier coefficients: we must integrate over a period, but \kbd{intfuncinit} does not support finite endpoints. The solution is to integrate a vector of functions ! \bprog FourierSin(f, T, k) = \\ first k sine Fourier coeffs { my (w = 2*Pi/T); my (v = vector(k+1)); intnum(t = -T/2, T/2, my (z = exp(I*w*t)); v[1] = z; for (j = 2, k, v[j] = v[j-1]*z); f(t) * imag(v)) * 2/T; } FourierSin(t->sin(2*t), 2*Pi, 10) @eprog\noindent The same technique can be used instead of \kbd{intfuncinit} to integrate $f(t) k(t,z)$ whenever the list of $z$-values is known beforehand. Note that the above code includes an unrelated optimization: the $\sin(j w t)$ are computed as imaginary parts of $\exp(i j w t)$ and the latter by successive multiplications. \item numerical Mellin inversion $$F(z) = (2i\pi)^{-1} \int_{c -i\infty}^{c+i\infty} f(s)z^{-s}\, ds = (2\pi)^{-1} \int_{-\infty}^{+\infty} f(c + i t)e^{-\log z(c + it)}\, dt. $$ We take $c = 2$ in the program below: \bprog f(s) = gamma(s)^3; \\ f(c+it) decrease as exp(-3Pi|t|/2) c = 2; \\ arbitrary A = [-oo,3*Pi/2]; B = [+oo,3*Pi/2]; T = intfuncinit(t=A,B, f(c + I*t)); F(z) = { my (a = -log(z)); intnum(t=A,B, exp(a*I*t), T)*exp(a*c) / (2*Pi); } @eprog \synt{intfuncinit}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b,long m, long prec}. pari-2.11.2/src/functions/sums/sumdivmult0000644000175000017500000000063512314242551017103 0ustar billbillFunction: sumdivmult Section: sums C-Name: sumdivmultexpr Prototype: GVE Help: sumdivmult(n,d,expr): sum of multiplicative function expr, d running over the divisors of n. Doc: sum of \emph{multiplicative} expression \var{expr} over the positive divisors $d$ of $n$. Assume that \var{expr} evaluates to $f(d)$ where $f$ is multiplicative: $f(1) = 1$ and $f(ab) = f(a)f(b)$ for coprime $a$ and $b$. %\syn{NO} pari-2.11.2/src/functions/sums/sumnumlagrangeinit0000644000175000017500000000443213326135265020611 0ustar billbillFunction: sumnumlagrangeinit Section: sums C-Name: sumnumlagrangeinit Prototype: DGDGp Help: sumnumlagrangeinit({asymp}, {c1}): initialize tables for Lagrange summation of a series. Doc: initialize tables for Lagrange summation of a series. By default, assume that the remainder $R(n) = \sum_{m \geq n} f(m)$ has an asymptotic expansion $$R(n) = \sum_{m \geq n} f(n) \approx \sum_{i\geq 1} a_i / n^i$$ at infinity. The argument \kbd{asymp} allows to specify different expansions: \item a real number $\beta$ means $$ R(n) = n^{-\beta} \sum_{i\geq 1} a_i / n^i $$ \item a \typ{CLOSURE} $g$ means $$R(n) = g(n) \sum_{i\geq 1} a_i / n^i$$ (The preceding case corresponds to $g(n) = n^{-\beta}$.) \item a pair $[\alpha,\beta]$ where $\beta$ is as above and $\alpha\in \{2, 1, 1/2, 1/3, 1/4\}$. We let $R_2(n) = R(n) - f(n)/2$ and $R_\alpha(n) = R(n)$ for $\alpha\neq 2$. Then $$R_\alpha(n) = g(n) \sum_{i\geq 1} a_i / n^{i\alpha}$$ Note that the initialization times increase considerable for the $\alpha$ is this list ($1/4$ being the slowest). The constant $c1$ is technical and computed by the program, but can be set by the user: the number of interpolation steps will be chosen close to $c1\cdot B$, where $B$ is the bit accuracy. \bprog ? \p2000 ? sumnumlagrange(n=1, n^-2); time = 173 ms. ? tab = sumnumlagrangeinit(); time = 172 ms. ? sumnumlagrange(n=1, n^-2, tab); time = 4 ms. ? \p115 ? sumnumlagrange(n=1, n^(-4/3)) - zeta(4/3); %1 = -0.1093[...] \\ junk: expansion in n^(1/3) time = 84 ms. ? tab = sumnumlagrangeinit([1/3,0]); \\ alpha = 1/3 time = 336 ms. ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) time = 84 ms. %3 = 1.0151767349262596893 E-115 \\ now OK ? tab = sumnumlagrangeinit(1/3); \\ alpha = 1, beta = 1/3: much faster time = 3ms ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) \\ ... but wrong %5 = -0.273825[...] \\ junk ! ? tab = sumnumlagrangeinit(-2/3); \\ alpha = 1, beta = -2/3 time = 3ms ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) %6 = 2.030353469852519379 E-115 \\ now OK @eprog\noindent in The final example with $\zeta(4/3)$, the remainder $R_1(n)$ is of the form $n^{-1/3} \sum_{i\geq 0} a_i / n^i$, i.e. $n^{2/3} \sum_{i\geq 1} a_i / n^i$. The explains the wrong result for $\beta = 1/3$ and the correction with $\beta = -2/3$. pari-2.11.2/src/functions/sums/sumnumapinit0000644000175000017500000000203613326135265017427 0ustar billbillFunction: sumnumapinit Section: sums C-Name: sumnumapinit Prototype: DGp Help: sumnumapinit({asymp}): initialize tables for Abel-Plana summation of a series. Doc: initialize tables for Abel--Plana summation of a series $\sum f(n)$, where $f$ is holomorphic in a right half-plane. If given, \kbd{asymp} is of the form $[\kbd{+oo}, \alpha]$, as in \tet{intnum} and indicates the decrease rate at infinity of functions to be summed. A positive $\alpha > 0$ encodes an exponential decrease of type $\exp(-\alpha n)$ and a negative $-2 < \alpha < -1$ encodes a slow polynomial decrease of type $n^{\alpha}$. \bprog ? \p200 ? sumnumap(n=1, n^-2); time = 163 ms. ? tab = sumnumapinit(); time = 160 ms. ? sumnum(n=1, n^-2, tab); \\ faster time = 7 ms. ? tab = sumnumapinit([+oo, log(2)]); \\ decrease like 2^-n time = 164 ms. ? sumnumap(n=1, 2^-n, tab) - 1 time = 36 ms. %5 = 3.0127431466707723218 E-282 ? tab = sumnumapinit([+oo, -4/3]); \\ decrease like n^(-4/3) time = 166 ms. ? sumnumap(n=1, n^(-4/3), tab); time = 181 ms. @eprog pari-2.11.2/src/functions/sums/prodeuler0000644000175000017500000000076311636712103016676 0ustar billbillFunction: prodeuler Section: sums C-Name: prodeuler0 Prototype: V=GGEp Help: prodeuler(X=a,b,expr): Euler product (X runs over the primes between a and b) of real or complex expression. Doc: product of expression \var{expr}, initialized at 1. (i.e.~to a \emph{real} number equal to 1 to the current \kbd{realprecision}), the formal parameter $X$ ranging over the prime numbers between $a$ and $b$.\sidx{Euler product} \synt{prodeuler}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b, long prec}. pari-2.11.2/src/functions/sums/solve0000644000175000017500000000131113201017466016013 0ustar billbillFunction: solve Section: sums C-Name: zbrent0 Prototype: V=GGEp Help: solve(X=a,b,expr): real root of expression expr (X between a and b), where expr(a)*expr(b)<=0. Wrapper: (,,G) Description: (gen,gen,gen):gen:prec zbrent(${3 cookie}, ${3 wrapper}, $1, $2, $prec) Doc: find a real root of expression \var{expr} between $a$ and $b$, under the condition $\var{expr}(X=a) * \var{expr}(X=b) \le 0$. (You will get an error message \kbd{roots must be bracketed in solve} if this does not hold.) This routine uses Brent's method and can fail miserably if \var{expr} is not defined in the whole of $[a,b]$ (try \kbd{solve(x=1, 2, tan(x))}). \synt{zbrent}{void *E,GEN (*eval)(void*,GEN),GEN a,GEN b,long prec}. pari-2.11.2/src/functions/sums/contfraceval0000644000175000017500000000103213201017466017332 0ustar billbillFunction: contfraceval Section: sums C-Name: contfraceval Prototype: GGD-1,L, Help: contfraceval(CF,t,{lim=-1}): given a continued fraction CF from contfracinit, evaluate the first lim terms of the continued fraction at t (all terms if lim is negative or omitted). Doc: Given a continued fraction \kbd{CF} output by \kbd{contfracinit}, evaluate the first \kbd{lim} terms of the continued fraction at \kbd{t} (all terms if \kbd{lim} is negative or omitted; if positive, \kbd{lim} must be less than or equal to the length of \kbd{CF}. pari-2.11.2/src/functions/sums/HEADER0000644000175000017500000000463513326135265015635 0ustar billbillFunction: _header_sums Class: header Section: sums Doc: \section{Sums, products, integrals and similar functions} \label{se:sums} Although the \kbd{gp} calculator is programmable, it is useful to have a number of preprogrammed loops, including sums, products, and a certain number of recursions. Also, a number of functions from numerical analysis like numerical integration and summation of series will be described here. One of the parameters in these loops must be the control variable, hence a simple variable name. In the descriptions, the letter $X$ will always denote any simple variable name, and represents the formal parameter used in the function. The expression to be summed, integrated, etc. is any legal PARI expression, including of course expressions using loops. \misctitle{Library mode} Since it is easier to program directly the loops in library mode, these functions are mainly useful for GP programming. On the other hand, numerical routines code a function (to be integrated, summed, etc.) with two parameters named \bprog GEN (*eval)(void*,GEN) void *E; \\ context: eval(E, x) must evaluate your function at x. @eprog\noindent see the Libpari manual for details. \misctitle{Numerical integration}\sidx{numerical integration} Starting with version 2.2.9 the ``double exponential'' univariate integration method is implemented in \tet{intnum} and its variants. Romberg integration is still available under the name \kbd{intnumromb}, but superseded. It is possible to compute numerically integrals to thousands of decimal places in reasonable time, as long as the integrand is regular. It is also reasonable to compute numerically integrals in several variables, although more than two becomes lengthy. The integration domain may be non-compact, and the integrand may have reasonable singularities at endpoints. To use \kbd{intnum}, you must split the integral into a sum of subintegrals where the function has no singularities except at the endpoints. Polynomials in logarithms are not considered singular, and neglecting these logs, singularities are assumed to be algebraic (asymptotic to $C(x-a)^{-\alpha}$ for some $\alpha > -1$ when $x$ is close to $a$), or to correspond to simple discontinuities of some (higher) derivative of the function. For instance, the point $0$ is a singularity of $\text{abs}(x)$. See also the discrete summation methods below, sharing the prefix \kbd{sum}. pari-2.11.2/src/functions/sums/intnumgauss0000644000175000017500000000265413201017466017253 0ustar billbillFunction: intnumgauss Section: sums C-Name: intnumgauss0 Prototype: V=GGEDGp Help: intnumgauss(X=a,b,expr,{tab}): numerical integration of expr from a to b, a compact interval, with respect to X using Gauss-Legendre quadrature. tab is either omitted (and will be recomputed) or precomputed with intnumgaussinit. Wrapper: (,,G) Description: (gen,gen,gen,?gen):gen:prec intnumgauss(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) Doc: numerical integration of \var{expr} on the compact interval $[a,b]$ with respect to $X$ using Gauss-Legendre quadrature; \kbd{tab} is either omitted or precomputed with \kbd{intnumgaussinit}. As a convenience, it can be an integer $n$ in which case we call \kbd{intnumgaussinit}$(n)$ and use $n$-point quadrature. \bprog ? test(n, b = 1) = T=intnumgaussinit(n);\ intnumgauss(x=-b,b, 1/(1+x^2),T) - 2*atan(b); ? test(0) \\ default %1 = -9.490148553624725335 E-22 ? test(40) %2 = -6.186629001816965717 E-31 ? test(50) %3 = -1.1754943508222875080 E-38 ? test(50, 2) \\ double interval length %4 = -4.891779568527713636 E-21 ? test(90, 2) \\ n must almost be doubled as well! %5 = -9.403954806578300064 E-38 @eprog\noindent On the other hand, we recommend to split the integral and change variables rather than increasing $n$ too much: \bprog ? f(x) = 1/(1+x^2); ? b = 100; ? intnumgauss(x=0,1, f(x)) + intnumgauss(x=1,1/b, f(1/x)*(-1/x^2)) - atan(b) %3 = -1.0579449157400587572 E-37 @eprog pari-2.11.2/src/functions/sums/derivnum0000644000175000017500000000451513326135265016533 0ustar billbillFunction: derivnum Section: sums C-Name: derivnum0 Prototype: V=GEDGp Help: derivnum(X=a,expr,{ind=1}): numerical derivation of expr with respect to X at X = a. The order of derivation is given by parameter 'ind'. Wrapper: (,Gp) Description: (gen,gen):gen:prec derivnum(${2 cookie}, ${2 wrapper}, $1, $prec) (gen,gen,gen):gen:prec derivfunk(${2 cookie}, ${2 wrapper}, $1, $3, $prec) Doc: numerical derivation of \var{expr} with respect to $X$ at $X=a$. The order of derivation is 1 by default. \bprog ? derivnum(x=0, sin(exp(x))) - cos(1) %1 = 0.E-38 @eprog A clumsier approach, which would not work in library mode, is \bprog ? f(x) = sin(exp(x)) ? f'(0) - cos(1) %2 = 0.E-38 @eprog \item When $a$ is a numerical type (integer, rational number, real number or \typ{COMPLEX} of such), performs numerical derivation. \item When $a$ is a (polynomial, rational function or) power series, compute \kbd{derivnum(t=a,f)} as $f'(a) = (f(a))'/a'$: \bprog ? derivnum(x = 1 + t, sqrt(x)) %1 = 1/2 - 1/4*t + 3/16*t^2 - 5/32*t^3 + ... + O(t^16) ? derivnum(x = 1/(1 + t), sqrt(x)) %2 = 1/2 + 1/4*t - 1/16*t^2 + 1/32*t^3 + ... + O(t^16) ? derivnum(x = 1 + t + O(t^17), sqrt(x)) %3 = 1/2 - 1/4*t + 3/16*t^2 - 5/32*t^3 + ... + O(t^16) @eprog If the parameter \var{ind} is present, it can be \item a non-negative integer $m$, in which case we return $f^{(m)}(x)$; \item or a vector of orders, in which case we return the vector of derivatives. \bprog ? derivnum(x = 0, exp(sin(x)), 16) \\ 16-th derivative %1 = -52635599.000000000000000000000000000000 ? round( derivnum(x = 0, exp(sin(x)), [0..13]) ) \\ 0-13-th derivatives %2 = [1, 1, 1, 0, -3, -8, -3, 56, 217, 64, -2951, -12672, 5973, 309376] @eprog \synt{derivfunk}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN ind, long prec}. Also available is \fun{GEN}{derivfun}{void *E, GEN (*eval)(void *, GEN), GEN a, long prec}. If $a$ is a numerical type (\typ{INT}, \typ{FRAC}, \typ{REAL} or \typ{COMPLEX} of such, we have \fun{GEN}{derivnumk}{void *E, GEN (*eval)(void *, GEN, long), GEN a, GEN ind, long prec} and \fun{GEN}{derivnum}{void *E, GEN (*eval)(void *, GEN, long prec), GEN a, long prec} Function: _derivfun Section: programming/internals C-Name: derivfun0 Prototype: GGp Help: _derivfun(closure,[args]) numerical derivation of closure with respect to the first variable at (args). pari-2.11.2/src/functions/sums/sumnumap0000644000175000017500000001224113326135265016542 0ustar billbillFunction: sumnumap Section: sums C-Name: sumnumap0 Prototype: V=GEDGp Help: sumnumap(n=a,f,{tab}): numerical summation of f(n) from n = a to +infinity using Abel-Plana formula. Assume that f is holomorphic in the right half-plane Re(z) > a; a must be an integer, and tab, if given, is the output of sumnumapinit. Wrapper: (,G) Description: (gen,gen,?gen):gen:prec sumnumap(${2 cookie}, ${2 wrapper}, $1, $3, $prec) Doc: Numerical summation of $f(n)$ at high accuracy using Abel-Plana, the variable $n$ taking values from $a$ to $+\infty$, where $f$ is holomorphic in the right half-place $\Re(z) > a$; \kbd{a} must be an integer and \kbd{tab}, if given, is the output of \kbd{sumnumapinit}. The latter precomputes abscissas and weights, speeding up the computation; it also allows to specify the behavior at infinity via \kbd{sumnumapinit([+oo, asymp])}. \bprog ? \p500 ? z3 = zeta(3); ? sumpos(n = 1, n^-3) - z3 time = 2,332 ms. %2 = 2.438468843 E-501 ? sumnumap(n = 1, n^-3) - z3 \\ here slower than sumpos time = 2,565 ms. %3 = 0.E-500 @eprog \misctitle{Complexity} The function $f$ will be evaluated at $O(D \log D)$ real arguments and $O(D)$ complex arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. The routine is geared towards slowly decreasing functions: if $f$ decreases exponentially fast, then one of \kbd{suminf} or \kbd{sumpos} should be preferred. The default algorithm \kbd{sumnum} is usually a little \emph{slower} than \kbd{sumnumap} but its initialization function \kbd{sumnuminit} becomes much faster as \kbd{realprecision} increases. If $f$ satisfies the stronger hypotheses required for Monien summation, i.e. if $f(1/z)$ is holomorphic in a complex neighbourhood of $[0,1]$, then \tet{sumnummonien} will be faster since it only requires $O(D/\log D)$ evaluations: \bprog ? sumnummonien(n = 1, 1/n^3) - z3 time = 1,128 ms. %3 = 0.E-500 @eprog\noindent The \kbd{tab} argument precomputes technical data not depending on the expression being summed and valid for a given accuracy, speeding up immensely later calls: \bprog ? tab = sumnumapinit(); time = 2,567 ms. ? sumnumap(n = 1, 1/n^3, tab) - z3 \\ now much faster than sumpos time = 39 ms. %5 = 0.E-500 ? tabmon = sumnummonieninit(); \\ Monien summation allows precomputations too time = 1,125 ms. ? sumnummonien(n = 1, 1/n^3, tabmon) - z3 time = 2 ms. %7 = 0.E-500 @eprog\noindent The speedup due to precomputations becomes less impressive when the function $f$ is expensive to evaluate, though: \bprog ? sumnumap(n = 1, lngamma(1+1/n)/n, tab); time = 10,762 ms. ? sumnummonien(n = 1, lngamma(1+1/n)/n, tabmon); \\ fewer evaluations time = 205 ms. @eprog \misctitle{Behaviour at infinity} By default, \kbd{sumnumap} assumes that \var{expr} decreases slowly at infinity, but at least like $O(n^{-2})$. If the function decreases like $n^{\alpha}$ for some $-2 < \alpha < -1$, then it must be indicated via \bprog tab = sumnumapinit([+oo, alpha]); /* alpha < 0 slow decrease */ @eprog\noindent otherwise loss of accuracy is expected. If the functions decreases quickly, like $\exp(-\alpha n)$ for some $\alpha > 0$, then it must be indicated via \bprog tab = sumnumapinit([+oo, alpha]); /* alpha > 0 exponential decrease */ @eprog\noindent otherwise exponent overflow will occur. \bprog ? sumnumap(n=1,2^-n) *** at top-level: sumnumap(n=1,2^-n) *** ^---- *** _^_: overflow in expo(). ? tab = sumnumapinit([+oo,log(2)]); sumnumap(n=1,2^-n, tab) %1 = 1.000[...] @eprog As a shortcut, one can also input \bprog sumnumap(n = [a, asymp], f) @eprog\noindent instead of \bprog tab = sumnumapinit(asymp); sumnumap(n = a, f, tab) @eprog \misctitle{Further examples} \bprog ? \p200 ? sumnumap(n = 1, n^(-2)) - zeta(2) \\ accurate, fast time = 169 ms. %1 = -4.752728915737899559 E-212 ? sumpos(n = 1, n^(-2)) - zeta(2) \\ even faster time = 79 ms. %2 = 0.E-211 ? sumpos(n=1,n^(-4/3)) - zeta(4/3) \\ now much slower time = 10,518 ms. %3 = -9.980730723049589073 E-210 ? sumnumap(n=1,n^(-4/3)) - zeta(4/3) \\ fast but inaccurate time = 309 ms. %4 = -2.57[...]E-78 ? sumnumap(n=[1,-4/3],n^(-4/3)) - zeta(4/3) \\ decrease rate: now accurate time = 329 ms. %6 = -5.418110963941205497 E-210 ? tab = sumnumapinit([+oo,-4/3]); time = 160 ms. ? sumnumap(n=1, n^(-4/3), tab) - zeta(4/3) \\ faster with precomputations time = 175 ms. %5 = -5.418110963941205497 E-210 ? sumnumap(n=1,-log(n)*n^(-4/3), tab) - zeta'(4/3) time = 258 ms. %7 = 9.125239518216767153 E-210 @eprog Note that in the case of slow decrease ($\alpha < 0$), the exact decrease rate must be indicated, while in the case of exponential decrease, a rough value will do. In fact, for exponentially decreasing functions, \kbd{sumnumap} is given for completeness and comparison purposes only: one of \kbd{suminf} or \kbd{sumpos} should always be preferred. \bprog ? sumnumap(n=[1, 1], 2^-n) \\ pretend we decrease as exp(-n) time = 240 ms. %8 = 1.000[...] \\ perfect ? sumpos(n=1, 2^-n) %9 = 1.000[...] \\ perfect and instantaneous @eprog \synt{sumnumap}{(void *E, GEN (*eval)(void*,GEN), GEN a, GEN tab, long prec)} where an omitted \var{tab} is coded as \kbd{NULL}. pari-2.11.2/src/functions/sums/intnumromb0000644000175000017500000000601413201017466017062 0ustar billbillFunction: intnumromb Section: sums C-Name: intnumromb0_bitprec Prototype: V=GGED0,L,b Help: intnumromb(X=a,b,expr,{flag=0}): numerical integration of expr (smooth in ]a,b[) from a to b with respect to X. flag is optional and mean 0: default. expr can be evaluated exactly on [a,b]; 1: general function; 2: a or b can be plus or minus infinity (chosen suitably), but of same sign; 3: expr has only limits at a or b. Wrapper: (,,G) Description: (gen,gen,gen,?small):gen:prec intnumromb(${3 cookie}, ${3 wrapper}, $1, $2, $4, $bitprec) Doc: numerical integration of \var{expr} (smooth in $]a,b[$), with respect to $X$. Suitable for low accuracy; if \var{expr} is very regular (e.g. analytic in a large region) and high accuracy is desired, try \tet{intnum} first. Set $\fl=0$ (or omit it altogether) when $a$ and $b$ are not too large, the function is smooth, and can be evaluated exactly everywhere on the interval $[a,b]$. If $\fl=1$, uses a general driver routine for doing numerical integration, making no particular assumption (slow). $\fl=2$ is tailored for being used when $a$ or $b$ are infinite using the change of variable $t = 1/X$. One \emph{must} have $ab>0$, and in fact if for example $b=+\infty$, then it is preferable to have $a$ as large as possible, at least $a\ge1$. If $\fl=3$, the function is allowed to be undefined at $a$ (but right continuous) or $b$ (left continuous), for example the function $\sin(x)/x$ between $x=0$ and $1$. The user should not require too much accuracy: \tet{realprecision} about 30 decimal digits (\tet{realbitprecision} about 100 bits) is OK, but not much more. In addition, analytical cleanup of the integral must have been done: there must be no singularities in the interval or at the boundaries. In practice this can be accomplished with a change of variable. Furthermore, for improper integrals, where one or both of the limits of integration are plus or minus infinity, the function must decrease sufficiently rapidly at infinity, which can often be accomplished through integration by parts. Finally, the function to be integrated should not be very small (compared to the current precision) on the entire interval. This can of course be accomplished by just multiplying by an appropriate constant. Note that \idx{infinity} can be represented with essentially no loss of accuracy by an appropriate huge number. However beware of real underflow when dealing with rapidly decreasing functions. For example, in order to compute the $\int_0^\infty e^{-x^2}\,dx$ to 28 decimal digits, then one can set infinity equal to 10 for example, and certainly not to \kbd{1e1000}. \synt{intnumromb_bitprec}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN b, long flag, long bitprec}, where $\kbd{eval}(x, E)$ returns the value of the function at $x$. You may store any additional information required by \kbd{eval} in $E$, or set it to \kbd{NULL}. The historical variant \synt{intnumromb}{\dots, long prec}, where \kbd{prec} is expressed in words, not bits, is obsolete and should no longer be used. pari-2.11.2/src/functions/sums/intnum0000644000175000017500000003170413326135265016214 0ustar billbillFunction: intnum Section: sums C-Name: intnum0 Prototype: V=GGEDGp Help: intnum(X=a,b,expr,{tab}): numerical integration of expr from a to b with respect to X. Plus/minus infinity is coded as +oo/-oo. Finally tab is either omitted (let the program choose the integration step), a non-negative integer m (divide integration step by 2^m), or data precomputed with intnuminit. Wrapper: (,,G) Description: (gen,gen,gen,?gen):gen:prec intnum(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) Doc: numerical integration of \var{expr} on $]a,b[$ with respect to $X$, using the double-exponential method, and thus $O(D\log D)$ evaluation of the integrand in precision $D$. The integrand may have values belonging to a vector space over the real numbers; in particular, it can be complex-valued or vector-valued. But it is assumed that the function is regular on $]a,b[$. If the endpoints $a$ and $b$ are finite and the function is regular there, the situation is simple: \bprog ? intnum(x = 0,1, x^2) %1 = 0.3333333333333333333333333333 ? intnum(x = 0,Pi/2, [cos(x), sin(x)]) %2 = [1.000000000000000000000000000, 1.000000000000000000000000000] @eprog\noindent An endpoint equal to $\pm\infty$ is coded as \kbd{+oo} or \kbd{-oo}, as expected: \bprog ? intnum(x = 1,+oo, 1/x^2) %3 = 1.000000000000000000000000000 @eprog\noindent In basic usage, it is assumed that the function does not decrease exponentially fast at infinity: \bprog ? intnum(x=0,+oo, exp(-x)) *** at top-level: intnum(x=0,+oo,exp(- *** ^-------------------- *** exp: overflow in expo(). @eprog\noindent We shall see in a moment how to avoid that last problem, after describing the last \emph{optional} argument \var{tab}. \misctitle{The \var{tab} argument} The routine uses weights $w_i$, which are mostly independent of the function being integrated, evaluated at many sampling points $x_i$ and approximates the integral by $\sum w_i f(x_i)$. If \var{tab} is \item a non-negative integer $m$, we multiply the number of sampling points by $2^m$, hopefully increasing accuracy. Note that the running time increases roughly by a factor $2^m$. One may try consecutive values of $m$ until they give the same value up to an accepted error. \item a set of integration tables containing precomputed $x_i$ and $w_i$ as output by \tet{intnuminit}. This is useful if several integrations of the same type are performed (on the same kind of interval and functions, for a given accuracy): we skip a precomputation of $O(D\log D)$ elementary functions in accuracy $D$, whose running time has the same order of magnitude as the evaluation of the integrand. This is in particular useful for multivariate integrals. \misctitle{Specifying the behavior at endpoints} This is done as follows. An endpoint $a$ is either given as such (a scalar, real or complex, \kbd{oo} or \kbd{-oo} for $\pm\infty$), or as a two component vector $[a,\alpha]$, to indicate the behavior of the integrand in a neighborhood of $a$. If $a$ is finite, the code $[a,\alpha]$ means the function has a singularity of the form $(x-a)^{\alpha}$, up to logarithms. (If $\alpha \ge 0$, we only assume the function is regular, which is the default assumption.) If a wrong singularity exponent is used, the result will lose decimals: \bprog ? c = -9/10; ? intnum(x=0, 1, x^c) \\@com assume $x^{-9/10}$ is regular at 0 %1 = 9.9999839078827082322596783301939063944 ? intnum(x=[0,c], 1, x^c) \\@com no, it's not %2 = 10.000000000000000000000000000000000000 ? intnum(x=[0,c/2], 1, x^c) \\@com using a wrong exponent is bad %3 = 9.9999999997122749095442279375719919769 @eprog If $a$ is $\pm\infty$, which is coded as \kbd{+oo} or \kbd{-oo}, the situation is more complicated, and $[\pm\kbd{oo},\alpha]$ means: \item $\alpha=0$ (or no $\alpha$ at all, i.e. simply $\pm\kbd{oo}$) assumes that the integrand tends to zero moderately quickly, at least as $O(x^{-2})$ but not exponentially fast. \item $\alpha>0$ assumes that the function tends to zero exponentially fast approximately as $\exp(-\alpha x)$. This includes oscillating but quickly decreasing functions such as $\exp(-x)\sin(x)$. \bprog ? intnum(x=0, +oo, exp(-2*x)) *** at top-level: intnum(x=0,+oo,exp(- *** ^-------------------- *** exp: exponent (expo) overflow ? intnum(x=0, [+oo, 2], exp(-2*x)) \\@com OK! %1 = 0.50000000000000000000000000000000000000 ? intnum(x=0, [+oo, 3], exp(-2*x)) \\@com imprecise exponent, still OK ! %2 = 0.50000000000000000000000000000000000000 ? intnum(x=0, [+oo, 10], exp(-2*x)) \\@com wrong exponent $\Rightarrow$ disaster %3 = 0.49999999999952372962457451698256707393 @eprog\noindent As the last exemple shows, the exponential decrease rate \emph{must} be indicated to avoid overflow, but the method is robust enough for a rough guess to be acceptable. \item $\alpha<-1$ assumes that the function tends to $0$ slowly, like $x^{\alpha}$. Here the algorithm is less robust and it is essential to give a sharp $\alpha$, unless $\alpha \le -2$ in which case we use the default algorithm as if $\alpha$ were missing (or equal to $0$). \bprog ? intnum(x=1, +oo, x^(-3/2)) \\ default %1 = 1.9999999999999999999999999999646391207 ? intnum(x=1, [+oo,-3/2], x^(-3/2)) \\ precise decrease rate %2 = 2.0000000000000000000000000000000000000 ? intnum(x=1, [+oo,-11/10], x^(-3/2)) \\ worse than default %3 = 2.0000000000000000000000000089298011973 @eprog \smallskip The last two codes are reserved for oscillating functions. Let $k > 0$ real, and $g(x)$ a non-oscillating function tending slowly to $0$ (e.g. like a negative power of $x$), then \item $\alpha=k * I$ assumes that the function behaves like $\cos(kx)g(x)$. \item $\alpha=-k* I$ assumes that the function behaves like $\sin(kx)g(x)$. \noindent Here it is critical to give the exact value of $k$. If the oscillating part is not a pure sine or cosine, one must expand it into a Fourier series, use the above codings, and sum the resulting contributions. Otherwise you will get nonsense. Note that $\cos(kx)$, and similarly $\sin(kx)$, means that very function, and not a translated version such as $\cos(kx+a)$. \misctitle{Note} If $f(x)=\cos(kx)g(x)$ where $g(x)$ tends to zero exponentially fast as $\exp(-\alpha x)$, it is up to the user to choose between $[\pm\kbd{oo},\alpha]$ and $[\pm\kbd{oo},k* I]$, but a good rule of thumb is that if the oscillations are weaker than the exponential decrease, choose $[\pm\kbd{oo},\alpha]$, otherwise choose $[\pm\kbd{oo},k*I]$, although the latter can reasonably be used in all cases, while the former cannot. To take a specific example, in most inverse Mellin transforms, the integrand is a product of an exponentially decreasing and an oscillating factor. If we choose the oscillating type of integral we perhaps obtain the best results, at the expense of having to recompute our functions for a different value of the variable $z$ giving the transform, preventing us to use a function such as \kbd{intfuncinit}. On the other hand using the exponential type of integral, we obtain less accurate results, but we skip expensive recomputations. See \kbd{intfuncinit} for more explanations. \misctitle{Power series limits} The limits $a$ and $b$ can be power series of non-negative valuation, giving a power series expansion for the integral -- provided it exists. \bprog ? intnum(t=0,X + O(X^3), exp(t)) %4 = 1.000...*X - 0.5000...*X^2 + O(X^3) ? bestappr( intnum(t=0,X + O(X^17), exp(t)) )- exp(X) + 1 %5 = O(X^17) @eprog\noindent The valuation of the limit cannot be negative since $\int_0^{1/X}(1+t^2)^{-1}\, dt = \pi/2 - \kbd{sign}(X)+O(X^2)$. Polynomials and rational functions are also allowed and converted to power series using current \kbd{seriesprecision}: \bprog ? bestappr( intnum(t=1,1+X, 1/t) ) %6 = X - 1/2*X^2 + 1/3*X^3 - 1/4*X^4 + [...] + 1/15*X^15 + O(X^16) @eprog\noindent The function does not work if the integral is singular with the constant coefficient of the series as limit: \bprog ? intnum(t=X^2+O(X^4),1, 1/sqrt(t)) %8 = 2.000... - 6.236608109630992528 E28*X^2 + O(X^4) @eprog\noindent however you can use \bprog ? intnum(t=[X^2+O(X^4),-1/2],1, 1/sqrt(t)) %10 = 2.000000000000000000000000000-2.000000000000000000000000000*X^2+O(X^4) @eprog\noindent whis is translated internally to \bprog ? intnum(t=[0,-1/2],1, 1/sqrt(t))-intnum(t=[0,-1/2],X^2+O(X^4), 1/sqrt(t)) @eprog\noindent For this form the argument \var{tab} can be used only as an integer, not a table precomputed by \kbd{intnuminit}. \smallskip We shall now see many examples to get a feeling for what the various parameters achieve. All examples below assume precision is set to $115$ decimal digits. We first type \bprog ? \p 115 @eprog \misctitle{Apparent singularities} In many cases, apparent singularities can be ignored. For instance, if $f(x) = 1 /(\exp(x)-1) - \exp(-x)/x$, then $\int_0^\infty f(x)\,dx=\gamma$, Euler's constant \kbd{Euler}. But \bprog ? f(x) = 1/(exp(x)-1) - exp(-x)/x ? intnum(x = 0, [oo,1], f(x)) - Euler %1 = 0.E-115 @eprog\noindent But close to $0$ the function $f$ is computed with an enormous loss of accuracy, and we are in fact lucky that it get multiplied by weights which are sufficiently close to $0$ to hide this: \bprog ? f(1e-200) %2 = -3.885337784451458142 E84 @eprog A more robust solution is to define the function differently near special points, e.g. by a Taylor expansion \bprog ? F = truncate( f(t + O(t^10)) ); \\@com expansion around t = 0 ? poldegree(F) %4 = 7 ? g(x) = if (x > 1e-18, f(x), subst(F,t,x)); \\@com note that $7 \cdot 18 > 105$ ? intnum(x = 0, [oo,1], g(x)) - Euler %2 = 0.E-115 @eprog\noindent It is up to the user to determine constants such as the $10^{-18}$ and $10$ used above. \misctitle{True singularities} With true singularities the result is worse. For instance \bprog ? intnum(x = 0, 1, x^(-1/2)) - 2 %1 = -3.5... E-68 \\@com only $68$ correct decimals ? intnum(x = [0,-1/2], 1, x^(-1/2)) - 2 %2 = 0.E-114 \\@com better @eprog \misctitle{Oscillating functions} \bprog ? intnum(x = 0, oo, sin(x) / x) - Pi/2 %1 = 16.19.. \\@com nonsense ? intnum(x = 0, [oo,1], sin(x)/x) - Pi/2 %2 = -0.006.. \\@com bad ? intnum(x = 0, [oo,-I], sin(x)/x) - Pi/2 %3 = 0.E-115 \\@com perfect ? intnum(x = 0, [oo,-I], sin(2*x)/x) - Pi/2 \\@com oops, wrong $k$ %4 = 0.06... ? intnum(x = 0, [oo,-2*I], sin(2*x)/x) - Pi/2 %5 = 0.E-115 \\@com perfect ? intnum(x = 0, [oo,-I], sin(x)^3/x) - Pi/4 %6 = -0.0008... \\@com bad ? sin(x)^3 - (3*sin(x)-sin(3*x))/4 %7 = O(x^17) @eprog\noindent We may use the above linearization and compute two oscillating integrals with endpoints \kbd{[oo, -I]} and \kbd{[oo, -3*I]} respectively, or notice the obvious change of variable, and reduce to the single integral ${1\over 2}\int_0^\infty \sin(x)/x\,dx$. We finish with some more complicated examples: \bprog ? intnum(x = 0, [oo,-I], (1-cos(x))/x^2) - Pi/2 %1 = -0.0003... \\@com bad ? intnum(x = 0, 1, (1-cos(x))/x^2) \ + intnum(x = 1, oo, 1/x^2) - intnum(x = 1, [oo,I], cos(x)/x^2) - Pi/2 %2 = 0.E-115 \\@com perfect ? intnum(x = 0, [oo, 1], sin(x)^3*exp(-x)) - 0.3 %3 = -7.34... E-55 \\@com bad ? intnum(x = 0, [oo,-I], sin(x)^3*exp(-x)) - 0.3 %4 = 8.9... E-103 \\@com better. Try higher $m$ ? tab = intnuminit(0,[oo,-I], 1); \\@com double number of sampling points ? intnum(x = 0, oo, sin(x)^3*exp(-x), tab) - 0.3 %6 = 0.E-115 \\@com perfect @eprog \misctitle{Warning} Like \tet{sumalt}, \kbd{intnum} often assigns a reasonable value to diverging integrals. Use these values at your own risk! For example: \bprog ? intnum(x = 0, [oo, -I], x^2*sin(x)) %1 = -2.0000000000... @eprog\noindent Note the formula $$ \int_0^\infty \sin(x)/x^s\,dx = \cos(\pi s/2) \Gamma(1-s)\;, $$ a priori valid only for $0 < \Re(s) < 2$, but the right hand side provides an analytic continuation which may be evaluated at $s = -2$\dots \misctitle{Multivariate integration} Using successive univariate integration with respect to different formal parameters, it is immediate to do naive multivariate integration. But it is important to use a suitable \kbd{intnuminit} to precompute data for the \emph{internal} integrations at least! For example, to compute the double integral on the unit disc $x^2+y^2\le1$ of the function $x^2+y^2$, we can write \bprog ? tab = intnuminit(-1,1); ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab),tab) - Pi/2 %2 = -7.1... E-115 \\@com OK @eprog\noindent The first \var{tab} is essential, the second optional. Compare: \bprog ? tab = intnuminit(-1,1); time = 4 ms. ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2)); time = 3,092 ms. \\@com slow ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab), tab); time = 252 ms. \\@com faster ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab)); time = 261 ms. \\@com the \emph{internal} integral matters most @eprog \synt{intnum}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b,GEN tab, long prec}, where an omitted \var{tab} is coded as \kbd{NULL}. pari-2.11.2/src/functions/sums/asympnum0000644000175000017500000000370413201017466016544 0ustar billbillFunction: asympnum Section: sums C-Name: asympnum0 Prototype: GD0,L,DGp Help: asympnum(expr,{k=20},{alpha = 1}): asymptotic expansion of expr assuming it has rational coefficients with reasonable height; k and alpha are as in limitnum. Doc: Asymptotic expansion of \var{expr}, corresponding to a sequence $u(n)$, assuming it has the shape $$u(n) \approx \sum_{i \geq 0} a_i n^{-i\alpha}$$ with rational coefficients $a_i$ with reasonable height; the algorithm is heuristic and performs repeated calls to limitnum, with \kbd{k} and \kbd{alpha} are as in \kbd{limitnum} \bprog ? f(n) = n! / (n^n*exp(-n)*sqrt(n)); ? asympnum(f) %2 = [] \\ failure ! ? l = limitnum(f) %3 = 2.5066282746310005024157652848110452530 ? asympnum(n->f(n)/l) \\ normalize %4 = [1, 1/12, 1/288, -139/51840] @eprog\noindent and we indeed get a few terms of Stirling's expansion. Note that it helps to normalize with a limit computed to higher accuracy: \bprog ? \p100 ? L = limitnum(f) ? \p38 ? asympnum(n->f(n)/L) \\ we get more terms! %6 = [1, 1/12, 1/288, -139/51840, -571/2488320, 163879/209018880,\ 5246819/75246796800, -534703531/902961561600] @eprog\noindent If \kbd{alpha} is not an integer, loss of accuracy is expected, so it should be precomputed to double accuracy, say: \bprog ? \p38 ? asympnum(n->-log(1-1/n^Pi),,Pi) %1 = [0, 1, 1/2, 1/3] ? asympnum(n->-log(1-1/sqrt(n)),,1/2) %2 = [0, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, \ 1/13, 1/14, 1/15, 1/16, 1/17, 1/18, 1/19, 1/20, 1/21, 1/22] ? localprec(100); a = Pi; ? asympnum(n->-log(1-1/n^a),,a) \\ better ! %4 = [0, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12] @eprog \synt{asympnum}{void *E, GEN (*u)(void *,GEN,long), long muli, GEN alpha, long prec}, where \kbd{u(E, n, prec)} must return $u(n)$ in precision \kbd{prec}. Also available is \fun{GEN}{asympnum0}{GEN u, long muli, GEN alpha, long prec}, where $u$ must be a vector of sufficient length as above. pari-2.11.2/src/functions/sums/limitnum0000644000175000017500000000501313326135265016532 0ustar billbillFunction: limitnum Section: sums C-Name: limitnum0 Prototype: GD0,L,DGp Help: limitnum(expr,{k = 20},{alpha=1}): numerical limit of sequence expr using Lagrange-Zagier extrapolation; k is a multiplier so that we extrapolate from expr(k*n). Assume u(n) ~ sum a_i n^(-alpha*i). Doc: Lagrange-Zagier numerical extrapolation of \var{expr}, corresponding to a sequence $u_n$, either given by a closure \kbd{n->u(n)} or by a vector of values I.e., assuming that $u_n$ tends to a finite limit $\ell$, try to determine $\ell$. This routine is purely numerical and heuristic, thus may or may not work on your examples; $k$ is ignored if $u$ is given by a vector, and otherwise is a multiplier such that we extrapolate from $u(kn)$. Assume that $u_n$ has an asymptotic expansion in $n^{-\alpha}$ : $$u_n = \ell + \sum_{i\geq 1} a_i n^{-i\alpha}$$ for some $a_i$. \bprog ? limitnum(n -> n*sin(1/n)) %1 = 1.0000000000000000000000000000000000000 ? limitnum(n -> (1+1/n)^n) - exp(1) %2 = 0.E-37 ? limitnum(n -> 2^(4*n+1)*(n!)^4 / (2*n)! /(2*n+1)! ) %3 = 3.1415926535897932384626433832795028842 ? Pi %4 = 3.1415926535897932384626433832795028842 @eprog\noindent If $u_n$ is given by a vector, it must be long enough for the extrapolation to make sense: at least $k$ times the current \kbd{realprecision}. The preferred format is thus a closure, although it becomes inconvenient when $u_n$ cannot be directly computed in time polynomial in $\log n$, for instance if it is defined as a sum or by induction. In that case, passing a vector of values is the best option. It usually pays off to interpolate $u(kn)$ for some $k > 1$: \bprog ? limitnum(vector(10,n,(1+1/n)^n)) *** ^-------------------- *** limitnum: non-existent component in limitnum: index < 20 \\ at this accuracy, we must have at least 20 values ? limitnum(vector(20,n,(1+1/n)^n)) - exp(1) %5 = -2.05... E-20 ? limitnum(vector(20,n, m=10*n;(1+1/m)^m)) - exp(1) \\ better accuracy %6 = 0.E-37 ? v = vector(20); s = 0; ? for(i=1,#v, s += 1/i; v[i]= s - log(i)); ? limitnum(v) - Euler %9 = -1.6... E-19 ? V = vector(200); s = 0; ? for(i=1,#V, s += 1/i; V[i]= s); ? v = vector(#V \ 10, i, V[10*i] - log(10*i)); ? limitnum(v) - Euler %13 = 6.43... E-29 @eprog \synt{limitnum}{void *E, GEN (*u)(void *,GEN,long), long muli, GEN alpha, long prec}, where \kbd{u(E, n, prec)} must return $u(n)$ in precision \kbd{prec}. Also available is \fun{GEN}{limitnum0}{GEN u, long muli, GEN alpha, long prec}, where $u$ must be a vector of sufficient length as above. pari-2.11.2/src/functions/sums/intcirc0000644000175000017500000000152513201017466016325 0ustar billbillFunction: intcirc Section: sums C-Name: intcirc0 Prototype: V=GGEDGp Help: intcirc(X=a,R,expr,{tab}): numerical integration of expr on the circle |z-a|=R, divided by 2*I*Pi. tab is as in intnum. Wrapper: (,,G) Description: (gen,gen,gen,?gen):gen:prec intcirc(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) Doc: numerical integration of $(2i\pi)^{-1}\var{expr}$ with respect to $X$ on the circle $|X-a| = R$. In other words, when \var{expr} is a meromorphic function, sum of the residues in the corresponding disk; \var{tab} is as in \kbd{intnum}, except that if computed with \kbd{intnuminit} it should be with the endpoints \kbd{[-1, 1]}. \bprog ? \p105 ? intcirc(s=1, 0.5, zeta(s)) - 1 time = 496 ms. %1 = 1.2883911040127271720 E-101 + 0.E-118*I @eprog \synt{intcirc}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN R,GEN tab, long prec}. pari-2.11.2/src/functions/sums/sumeulerrat0000644000175000017500000000052713326135265017251 0ustar billbillFunction: sumeulerrat Section: sums C-Name: sumeulerrat Prototype: GDGD2,L,p Help: sumeulerrat(F,{s=1},{a=2}): sum from primes p = a to infinity of F(p^s), where F is a rational function. Doc: $\sum_{p\ge a, p prime}F(p^s)$, where $F$ is a rational function. \bprog ? sumeulerrat(1/q) %1 = 0.45224742004106549850654336483224793418 @eprog pari-2.11.2/src/functions/sums/sumpos0000644000175000017500000000414713201017466016223 0ustar billbillFunction: sumpos Section: sums C-Name: sumpos0 Prototype: V=GED0,L,p Help: sumpos(X=a,expr,{flag=0}): sum of positive (or negative) series expr, the formal variable X starting at a. flag is optional, and can be 0: default, or 1: uses a slightly different method using Zagier's polynomials. Wrapper: (,G) Description: (gen,gen,?0):gen:prec sumpos(${2 cookie}, ${2 wrapper}, $1, $prec) (gen,gen,1):gen:prec sumpos2(${2 cookie}, ${2 wrapper}, $1, $prec) Doc: numerical summation of the series \var{expr}, which must be a series of terms having the same sign, the formal variable $X$ starting at $a$. The algorithm used is Van Wijngaarden's trick for converting such a series into an alternating one, then we use \tet{sumalt}. For regular functions, the function \kbd{sumnum} is in general much faster once the initializations have been made using \kbd{sumnuminit}. The routine is heuristic and assumes that \var{expr} is more or less a decreasing function of $X$. In particular, the result will be completely wrong if \var{expr} is 0 too often. We do not check either that all terms have the same sign. As \tet{sumalt}, this function should be used to try and guess the value of an infinite sum. If $\fl=1$, use \kbd{sumalt}$(,1)$ instead of \kbd{sumalt}$(,0)$, see \secref{se:sumalt}. Requiring more stringent analytic properties for rigorous use, but allowing to compute fewer series terms. To reach accuracy $10^{-p}$, both algorithms require $O(p^2)$ space; furthermore, assuming the terms decrease polynomially (in $O(n^{-C})$), both need to compute $O(p^2)$ terms. The \kbd{sumpos}$(,1)$ variant has a smaller implied constant (roughly 1.5 times smaller). Since the \kbd{sumalt}$(,1)$ overhead is now small compared to the time needed to compute series terms, this last variant should be about 1.5 faster. On the other hand, the achieved accuracy may be much worse: as for \tet{sumalt}, since conditions for rigorous use are hard to check, the routine is best used heuristically. \synt{sumpos}{void *E, GEN (*eval)(void*,GEN),GEN a,long prec}. Also available is \tet{sumpos2} with the same arguments ($\fl = 1$). pari-2.11.2/src/functions/sums/prodinf0000644000175000017500000000160613201017466016333 0ustar billbillFunction: prodinf Section: sums C-Name: prodinf0 Prototype: V=GED0,L,p Help: prodinf(X=a,expr,{flag=0}): infinite product (X goes from a to infinity) of real or complex expression. flag can be 0 (default) or 1, in which case compute the product of the 1+expr instead. Wrapper: (,G) Description: (gen,gen,?small):gen:prec prodinf(${2 cookie}, ${2 wrapper}, $1, $3, $prec) Doc: \idx{infinite product} of expression \var{expr}, the formal parameter $X$ starting at $a$. The evaluation stops when the relative error of the expression minus 1 is less than the default precision. In particular, non-convergent products result in infinite loops. The expressions must always evaluate to an element of $\C$. If $\fl=1$, do the product of the ($1+\var{expr}$) instead. \synt{prodinf}{void *E, GEN (*eval)(void*,GEN), GEN a, long prec} ($\fl=0$), or \tet{prodinf1} with the same arguments ($\fl=1$). pari-2.11.2/src/functions/sums/sumnummonien0000644000175000017500000000170013326135265017425 0ustar billbillFunction: sumnummonien Section: sums C-Name: sumnummonien0 Prototype: V=GEDGp Help: sumnummonien(n=a,f,{tab}): numerical summation from n = a to +infinity using Monien summation. Wrapper: (,G) Description: (gen,gen,?gen):gen:prec sumnummonien(${2 cookie}, ${2 wrapper}, $1, $3, $prec) Doc: numerical summation $\sum_{n\geq a} f(n)$ at high accuracy, the variable $n$ taking values from the integer $a$ to $+\infty$ using Monien summation, which assumes that $f(1/z)$ has a complex analytic continuation in a (complex) neighbourhood of the segment $[0,1]$. The function $f$ is evaluated at $O(D / \log D)$ real arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. By default, assume that $f(n) = O(n^{-2})$ and has a non-zero asymptotic expansion $$f(n) = \sum_{i\geq 2} a_i n^{-i}$$ at infinity. To handle more complicated behaviors and allow time-saving precomputations (for a given \kbd{realprecision}), see \kbd{sumnummonieninit}. pari-2.11.2/src/functions/sums/sumnumlagrange0000644000175000017500000000366213326135265017731 0ustar billbillFunction: sumnumlagrange Section: sums C-Name: sumnumlagrange0 Prototype: V=GEDGp Help: sumnumlagrange(n=a,f,{tab}): numerical summation of f(n) from n = a to +infinity using Lagrange summation. a must be an integer, and tab, if given, is the output of sumnumlagrangeinit. Wrapper: (,G) Description: (gen,gen,?gen):gen:prec sumnumlagrange(${2 cookie}, ${2 wrapper}, $1, $3, $prec) Doc: Numerical summation of $f(n)$ from $n=a$ to $+\infty$ using Lagrange summation; $a$ must be an integer, and the optional argument \kbd{tab} is the output of \kbd{sumnumlagrangeinit}. By default, the program assumes that the $N$th remainder has an asymptotic expansion in integral powers of $1/N$. If not, initialize \kbd{tab} using \kbd{sumnumlagrangeinit(al)}, where the asymptotic expansion of the remainder is integral powers of $1/N^{al}$; $al$ can be equal to $1$ (default), $1/2$, $1/3$, or $1/4$, and also equal to $2$, but in this latter case it is the $N$th remainder minus one half of the last summand which has an asymptotic expansion in integral powers of $1/N^2$. \bprog ? \p1000 ? z3 = zeta(3); ? sumpos(n = 1, n^-3) - z3 time = 8,088 ms. %2 = -2.08[...] E-1001 ? sumnumlagrange(n = 1, n^-3) - z3 \\ much faster than sumpos time = 40 ms. %3 = 0.E-1001 ? tab = sumnumlagrangeinit(2); time = 20 ms. ? sumnumlagrange(n = 1, n^-3, tab) - z3 time = 4 ms. /* even faster */ %5 = 0.E-1001 ? \p115 ? tab = sumnumlagrangeinit([1/3,1/3]); time = 316 ms. ? sumnumlagrange(n = 1, n^-(7/3), tab) - zeta(7/3) time = 24 ms. %7 = 0.E-115 ? sumnumlagrange(n = 1, n^(-2/3) - 3*(n^(1/3)-(n-1)^(1/3)), tab) - zeta(2/3) time = 32 ms. %8 = 1.0151767349262596893 E-115 @eprog \misctitle{Complexity} The function $f$ is evaluated at $O(D)$ integer arguments, where $D \approx \kbd{realprecision} \cdot \log(10)$. \synt{sumnumlagrange}{(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec)} where an omitted \var{tab} is coded as \kbd{NULL}. pari-2.11.2/src/functions/sums/sum0000644000175000017500000000114413326135265015501 0ustar billbillFunction: sum Section: sums C-Name: somme Prototype: V=GGEDG Help: sum(X=a,b,expr,{x=0}): x plus the sum (X goes from a to b) of expression expr. Doc: sum of expression \var{expr}, initialized at $x$, the formal parameter going from $a$ to $b$. As for \kbd{prod}, the initialization parameter $x$ may be given to force the type of the operations being performed. \noindent As an extreme example, compare \bprog ? sum(i=1, 10^4, 1/i); \\@com rational number: denominator has $4345$ digits. time = 236 ms. ? sum(i=1, 5000, 1/i, 0.) time = 8 ms. %2 = 9.787606036044382264178477904 @eprog % \syn{NO} pari-2.11.2/src/functions/sums/sumnuminit0000644000175000017500000000174713201017466017110 0ustar billbillFunction: sumnuminit Section: sums C-Name: sumnuminit Prototype: DGp Help: sumnuminit({asymp}): initialize tables for Euler-MacLaurin delta summation of a series with positive terms. Doc: initialize tables for Euler--MacLaurin delta summation of a series with positive terms. If given, \kbd{asymp} is of the form $[\kbd{+oo}, \alpha]$, as in \tet{intnum} and indicates the decrease rate at infinity of functions to be summed. A positive $\alpha > 0$ encodes an exponential decrease of type $\exp(-\alpha n)$ and a negative $-2 < \alpha < -1$ encodes a slow polynomial decrease of type $n^{\alpha}$. \bprog ? \p200 ? sumnum(n=1, n^-2); time = 200 ms. ? tab = sumnuminit(); time = 188 ms. ? sumnum(n=1, n^-2, tab); \\ faster time = 8 ms. ? tab = sumnuminit([+oo, log(2)]); \\ decrease like 2^-n time = 200 ms. ? sumnum(n=1, 2^-n, tab) time = 44 ms. ? tab = sumnuminit([+oo, -4/3]); \\ decrease like n^(-4/3) time = 200 ms. ? sumnum(n=1, n^(-4/3), tab); time = 221 ms. @eprog pari-2.11.2/src/functions/sums/solvestep0000644000175000017500000000234413201017466016716 0ustar billbillFunction: solvestep Section: sums C-Name: solvestep0 Prototype: V=GGGED0,L,p Help: solvestep(X=a,b,step,expr,{flag=0}): find zeros of a function in the real interval [a,b] by naive interval splitting. Wrapper: (,,,G) Description: (gen,gen,gen,gen, ?0$):gen:prec solvestep(${4 cookie}, ${4 wrapper}, $1, $2, $3, $5, $prec) Doc: find zeros of a continuous function in the real interval $[a,b]$ by naive interval splitting. This function is heuristic and may or may not find the intended zeros. Binary digits of \fl\ mean \item 1: return as soon as one zero is found, otherwise return all zeros found; \item 2: refine the splitting until at least one zero is found (may loop indefinitely if there are no zeros); \item 4: do a multiplicative search (we must have $a > 0$ and $\var{step} > 1$), otherwise an additive search; \var{step} is the multiplicative or additive step. \item 8: refine the splitting until at least one zero is very close to an integer. \bprog ? solvestep(X=0,10,1,sin(X^2),1) %1 = 1.7724538509055160272981674833411451828 ? solvestep(X=1,12,2,besselj(4,X),4) %2 = [7.588342434..., 11.064709488...] @eprog\noindent \synt{solvestep}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b, GEN step,long flag,long prec}. pari-2.11.2/src/functions/sums/intnumgaussinit0000644000175000017500000000235113201017466020131 0ustar billbillFunction: intnumgaussinit Section: sums C-Name: intnumgaussinit Prototype: D0,L,p Help: intnumgaussinit({n}): initialize tables for n-point Gauss-Legendre integration on a compact interval. Doc: initialize tables for $n$-point Gauss-Legendre integration of a smooth function $f$ lon a compact interval $[a,b]$ at current \kbd{realprecision}. If $n$ is omitted, make a default choice $n \approx \kbd{realprecision}$, suitable for analytic functions on $[-1,1]$. The error is bounded by $$ \dfrac{(b-a)^{2n+1} (n!)^4}{(2n+1)[(2n)!]^3} f^{(2n)} (\xi) , \qquad a < \xi < b $$ so, if the interval length increases, $n$ should be increased as well. \bprog ? T = intnumgaussinit(); ? intnumgauss(t=-1,1,exp(t), T) - exp(1)+exp(-1) %1 = -5.877471754111437540 E-39 ? intnumgauss(t=-10,10,exp(t), T) - exp(10)+exp(-10) %2 = -8.358367809712546836 E-35 ? intnumgauss(t=-1,1,1/(1+t^2), T) - Pi/2 %3 = -9.490148553624725335 E-22 ? T = intnumgaussinit(50); ? intnumgauss(t=-1,1,1/(1+t^2), T) - Pi/2 %5 = -1.1754943508222875080 E-38 ? intnumgauss(t=-5,5,1/(1+t^2), T) - 2*atan(5) %6 = -1.2[...]E-8 @eprog On the other hand, we recommend to split the integral and change variables rather than increasing $n$ too much, see \tet{intnumgauss}. pari-2.11.2/src/functions/sums/prod0000644000175000017500000000263011636712103015634 0ustar billbillFunction: prod Section: sums C-Name: produit Prototype: V=GGEDG Help: prod(X=a,b,expr,{x=1}): x times the product (X runs from a to b) of expression. Doc: product of expression \var{expr}, initialized at $x$, the formal parameter $X$ going from $a$ to $b$. As for \kbd{sum}, the main purpose of the initialization parameter $x$ is to force the type of the operations being performed. For example if it is set equal to the integer 1, operations will start being done exactly. If it is set equal to the real $1.$, they will be done using real numbers having the default precision. If it is set equal to the power series $1+O(X^k)$ for a certain $k$, they will be done using power series of precision at most $k$. These are the three most common initializations. \noindent As an extreme example, compare \bprog ? prod(i=1, 100, 1 - X^i); \\@com this has degree $5050$ !! time = 128 ms. ? prod(i=1, 100, 1 - X^i, 1 + O(X^101)) time = 8 ms. %2 = 1 - X - X^2 + X^5 + X^7 - X^12 - X^15 + X^22 + X^26 - X^35 - X^40 + \ X^51 + X^57 - X^70 - X^77 + X^92 + X^100 + O(X^101) @eprog\noindent Of course, in this specific case, it is faster to use \tet{eta}, which is computed using Euler's formula. \bprog ? prod(i=1, 1000, 1 - X^i, 1 + O(X^1001)); time = 589 ms. ? \ps1000 seriesprecision = 1000 significant terms ? eta(X) - % time = 8ms. %4 = O(X^1001) @eprog \synt{produit}{GEN a, GEN b, char *expr, GEN x}. pari-2.11.2/src/functions/sums/sumdiv0000644000175000017500000000077712314242551016210 0ustar billbillFunction: sumdiv Section: sums C-Name: sumdivexpr Prototype: GVE Help: sumdiv(n,X,expr): sum of expression expr, X running over the divisors of n. Doc: sum of expression \var{expr} over the positive divisors of $n$. This function is a trivial wrapper essentially equivalent to \bprog D = divisors(n); for (i = 1, #D, X = D[i]; eval(expr)) @eprog\noindent (except that \kbd{X} is lexically scoped to the \kbd{sumdiv} loop). If \var{expr} is a multiplicative function, use \tet{sumdivmult}. %\syn{NO} pari-2.11.2/src/functions/sums/sumnumrat0000644000175000017500000000147613326135265016740 0ustar billbillFunction: sumnumrat Section: sums C-Name: sumnumrat Prototype: GGp Help: sumnumrat(F,a): sum from n = a to infinity of F(n), where F is a rational function of degree less than or equal to -2. Doc: $\sum_{n\geq a}F(n)$, where $F$ is a rational function of degree less than or equal to $-2$ and where poles of $F$ at integers $\geq a$ are omitted from the summation. The argument $a$ must be a \typ{INT} or \kbd{-oo}. \bprog ? sumnumrat(1/(x^2+1)^2,0) %1 = 1.3068369754229086939178621382829073480 ? sumnumrat(1/x^2, -oo) \\ value at x=0 is discarded %2 = 3.2898681336964528729448303332920503784 ? 2*zeta(2) %3 = 3.2898681336964528729448303332920503784 @eprog\noindent When $\deg F = -1$, we define $$\sum_{-\infty}^{\infty} F(n) := \sum_{n\geq 0} (F(n) + F(-1-n)):$$ \bprog ? sumnumrat(1/x, -oo) %4 = 0.E-38 @eprog pari-2.11.2/src/functions/sums/prodnumrat0000644000175000017500000000060613326135265017072 0ustar billbillFunction: prodnumrat Section: sums C-Name: prodnumrat Prototype: GLp Help: prodnumrat(F,a): product from n = a to infinity of F(n), where F-1 is a rational function of degree less than or equal to -2. Doc: $\prod_{n\ge a}F(n)$, where $F-1$ is a rational function of degree less than or equal to $-2$. \bprog ? prodnumrat(1+1/x^2,1) %1 = 3.6760779103749777206956974920282606665 @eprog pari-2.11.2/src/functions/sums/sumalt0000644000175000017500000000640313201017466016177 0ustar billbillFunction: sumalt Section: sums C-Name: sumalt0 Prototype: V=GED0,L,p Help: sumalt(X=a,expr,{flag=0}): Cohen-Villegas-Zagier's acceleration of alternating series expr, X starting at a. flag is optional, and can be 0: default, or 1: uses a slightly different method using Zagier's polynomials. Wrapper: (,G) Description: (gen,gen,?0):gen:prec sumalt(${2 cookie}, ${2 wrapper}, $1, $prec) (gen,gen,1):gen:prec sumalt2(${2 cookie}, ${2 wrapper}, $1, $prec) Doc: numerical summation of the series \var{expr}, which should be an \idx{alternating series} $(-1)^k a_k$, the formal variable $X$ starting at $a$. Use an algorithm of Cohen, Villegas and Zagier (\emph{Experiment. Math.} {\bf 9} (2000), no.~1, 3--12). If $\fl=0$, assuming that the $a_k$ are the moments of a positive measure on $[0,1]$, the relative error is $O(3+\sqrt8)^{-n}$ after using $a_k$ for $k\leq n$. If \kbd{realprecision} is $p$, we thus set $n = \log(10)p/\log(3+\sqrt8)\approx 1.3 p$; besides the time needed to compute the $a_k$, $k\leq n$, the algorithm overhead is negligible: time $O(p^2)$ and space $O(p)$. If $\fl=1$, use a variant with more complicated polynomials, see \tet{polzagier}. If the $a_k$ are the moments of $w(x)dx$ where $w$ (or only $xw(x^2)$) is a smooth function extending analytically to the whole complex plane, convergence is in $O(14.4^{-n})$. If $xw(x^2)$ extends analytically to a smaller region, we still have exponential convergence, with worse constants. Usually faster when the computation of $a_k$ is expensive. If \kbd{realprecision} is $p$, we thus set $n = \log(10)p/\log(14.4)\approx 0.86 p$; besides the time needed to compute the $a_k$, $k\leq n$, the algorithm overhead is \emph{not} negligible: time $O(p^3)$ and space $O(p^2)$. Thus, even if the analytic conditions for rigorous use are met, this variant is only worthwile if the $a_k$ are hard to compute, at least $O(p^2)$ individually on average: otherwise we gain a small constant factor (1.5, say) in the number of needed $a_k$ at the expense of a large overhead. The conditions for rigorous use are hard to check but the routine is best used heuristically: even divergent alternating series can sometimes be summed by this method, as well as series which are not exactly alternating (see for example \secref{se:user_defined}). It should be used to try and guess the value of an infinite sum. (However, see the example at the end of \secref{se:userfundef}.) If the series already converges geometrically, \tet{suminf} is often a better choice: \bprog ? \p28 ? sumalt(i = 1, -(-1)^i / i) - log(2) time = 0 ms. %1 = -2.524354897 E-29 ? suminf(i = 1, -(-1)^i / i) \\@com Had to hit \kbd{C-C} *** at top-level: suminf(i=1,-(-1)^i/i) *** ^------ *** suminf: user interrupt after 10min, 20,100 ms. ? \p1000 ? sumalt(i = 1, -(-1)^i / i) - log(2) time = 90 ms. %2 = 4.459597722 E-1002 ? sumalt(i = 0, (-1)^i / i!) - exp(-1) time = 670 ms. %3 = -4.03698781490633483156497361352190615794353338591897830587 E-944 ? suminf(i = 0, (-1)^i / i!) - exp(-1) time = 110 ms. %4 = -8.39147638 E-1000 \\ @com faster and more accurate @eprog \synt{sumalt}{void *E, GEN (*eval)(void*,GEN),GEN a,long prec}. Also available is \tet{sumalt2} with the same arguments ($\fl = 1$). pari-2.11.2/src/functions/linear_algebra/0000755000175000017500000000000013461316051016704 5ustar billbillpari-2.11.2/src/functions/linear_algebra/matsize0000644000175000017500000000053511636712103020306 0ustar billbillFunction: matsize Section: linear_algebra C-Name: matsize Prototype: G Help: matsize(x): number of rows and columns of the vector/matrix x as a 2-vector. Doc: $x$ being a vector or matrix, returns a row vector with two components, the first being the number of rows (1 for a row vector), the second the number of columns (1 for a column vector). pari-2.11.2/src/functions/linear_algebra/mathnfmod0000644000175000017500000000143211636712103020604 0ustar billbillFunction: mathnfmod Section: linear_algebra C-Name: hnfmod Prototype: GG Help: mathnfmod(x,d): (upper triangular) Hermite normal form of x, basis for the lattice formed by the columns of x, where d is a multiple of the non-zero determinant of this lattice. Doc: if $x$ is a (not necessarily square) matrix of maximal rank with integer entries, and $d$ is a multiple of the (non-zero) determinant of the lattice spanned by the columns of $x$, finds the \emph{upper triangular} \idx{Hermite normal form} of $x$. If the rank of $x$ is equal to its number of rows, the result is a square matrix. In general, the columns of the result form a basis of the lattice spanned by the columns of $x$. Even when $d$ is known, this is in general slower than \kbd{mathnf} but uses much less memory. pari-2.11.2/src/functions/linear_algebra/qfsign0000644000175000017500000000055113201017466020117 0ustar billbillFunction: qfsign Section: linear_algebra C-Name: qfsign Prototype: G Help: qfsign(x): signature of the symmetric matrix x. Doc: returns $[p,m]$ the signature of the quadratic form represented by the symmetric matrix $x$. Namely, $p$ (resp.~$m$) is the number of positive (resp.~negative) eigenvalues of $x$. The result is computed using Gaussian reduction. pari-2.11.2/src/functions/linear_algebra/matrixqz0000644000175000017500000000274512314242551020515 0ustar billbillFunction: matrixqz Section: linear_algebra C-Name: matrixqz0 Prototype: GDG Help: matrixqz(A,{p=0}): if p>=0, transforms the rational or integral mxn (m>=n) matrix A into an integral matrix with gcd of maximal determinants coprime to p. If p=-1, finds a basis of the intersection with Z^n of the lattice spanned by the columns of A. If p=-2, finds a basis of the intersection with Z^n of the Q-vector space spanned by the columns of A. Doc: $A$ being an $m\times n$ matrix in $M_{m,n}(\Q)$, let $\text{Im}_\Q A$ (resp.~$\text{Im}_\Z A$) the $\Q$-vector space (resp.~the $\Z$-module) spanned by the columns of $A$. This function has varying behavior depending on the sign of $p$: If $p \geq 0$, $A$ is assumed to have maximal rank $n\leq m$. The function returns a matrix $B\in M_{m,n}(\Z)$, with $\text{Im}_\Q B = \text{Im}_\Q A$, such that the GCD of all its $n\times n$ minors is coprime to $p$; in particular, if $p = 0$ (default), this GCD is $1$. \bprog ? minors(x) = vector(#x[,1], i, matdet(x[^i,])); ? A = [3,1/7; 5,3/7; 7,5/7]; minors(A) %1 = [4/7, 8/7, 4/7] \\ determinants of all 2x2 minors ? B = matrixqz(A) %2 = [3 1] [5 2] [7 3] ? minors(%) %3 = [1, 2, 1] \\ B integral with coprime minors @eprog If $p=-1$, returns the HNF basis of the lattice $\Z^n \cap \text{Im}_\Z A$. If $p=-2$, returns the HNF basis of the lattice $\Z^n \cap \text{Im}_\Q A$. \bprog ? matrixqz(A,-1) %4 = [8 5] [4 3] [0 1] ? matrixqz(A,-2) %5 = [2 -1] [1 0] [0 1] @eprog pari-2.11.2/src/functions/linear_algebra/vecsort0000644000175000017500000001142013326135265020320 0ustar billbillFunction: vecsort Section: linear_algebra C-Name: vecsort0 Prototype: GDGD0,L, Help: vecsort(x,{cmpf},{flag=0}): sorts the vector of vectors (or matrix) x in ascending order, according to the comparison function cmpf, if not omitted. (If cmpf is an integer k, sort according to the value of the k-th component of each entry.) Binary digits of flag (if present) mean: 1: indirect sorting, return the permutation instead of the permuted vector, 4: use descending instead of ascending order, 8: remove duplicate entries. Description: (vecsmall,?gen):vecsmall vecsort0($1, $2, 0) (vecsmall,?gen,small):vecsmall vecsort0($1, $2, $3) (vec, , ?0):vec sort($1) (vec, , 1):vecsmall indexsort($1) (vec, , 2):vec lexsort($1) (vec, gen):vec vecsort0($1, $2, 0) (vec, ?gen, 1):vecsmall vecsort0($1, $2, 1) (vec, ?gen, 3):vecsmall vecsort0($1, $2, 3) (vec, ?gen, 5):vecsmall vecsort0($1, $2, 5) (vec, ?gen, 7):vecsmall vecsort0($1, $2, 7) (vec, ?gen, 9):vecsmall vecsort0($1, $2, 9) (vec, ?gen, 11):vecsmall vecsort0($1, $2, 11) (vec, ?gen, 13):vecsmall vecsort0($1, $2, 13) (vec, ?gen, 15):vecsmall vecsort0($1, $2, 15) (vec, ?gen, #small):vec vecsort0($1, $2, $3) (vec, ?gen, small):gen vecsort0($1, $2, $3) Doc: sorts the vector $x$ in ascending order, using a mergesort method. $x$ must be a list, vector or matrix (seen as a vector of its columns). Note that mergesort is stable, hence the initial ordering of ``equal'' entries (with respect to the sorting criterion) is not changed. If \kbd{cmpf} is omitted, we use the standard comparison function \kbd{lex}, thereby restricting the possible types for the elements of $x$ (integers, fractions or reals and vectors of those). We also transparently allow a \typ{VECSMALL} $x$ in this case, for the standard ordering on the integers. If \kbd{cmpf} is present, it is understood as a comparison function and we sort according to it. The following possibilities exist: \item an integer $k$: sort according to the value of the $k$-th subcomponents of the components of~$x$. \item a vector: sort lexicographically according to the components listed in the vector. For example, if $\kbd{cmpf}=\kbd{[2,1,3]}$, sort with respect to the second component, and when these are equal, with respect to the first, and when these are equal, with respect to the third. \item a comparison function: \typ{CLOSURE} with two arguments $x$ and $y$, and returning a real number which is $<0$, $>0$ or $=0$ if $xy$ or $x=y$ respectively. \item a key: \typ{CLOSURE} with one argument $x$ and returning the value $f(x)$ with respect to which we sort. \bprog ? vecsort([3,0,2; 1,0,2]) \\ sort columns according to lex order %1 = [0 2 3] [0 2 1] ? vecsort(v, (x,y)->y-x) \\@com reverse sort ? vecsort(v, (x,y)->abs(x)-abs(y)) \\@com sort by increasing absolute value ? vecsort(v, abs) \\@com sort by increasing absolute value, using key ? cmpf(x,y) = my(dx = poldisc(x), dy = poldisc(y)); abs(dx) - abs(dy); ? v = [x^2+1, x^3-2, x^4+5*x+1] vecsort(v, cmpf) \\@com comparison function ? vecsort(v, x->abs(poldisc(x))) \\@com key @eprog\noindent The \kbd{abs} and \kbd{cmpf} examples show how to use a named function instead of an anonymous function. It is preferable to use a \var{key} whenever possible rather than include it in the comparison function as above since the key is evaluated $O(n)$ times instead of $O(n\log n)$, where $n$ is the number of entries. A direct approach is also possible and equivalent to using a sorting key: \bprog ? T = [abs(poldisc(x)) | x<-v]; ? perm = vecsort(T,,1); \\@com indirect sort ? vecextract(v, perm) @eprog\noindent This also provides the vector $T$ of all keys, which is interesting for instance in later \tet{vecsearch} calls: it is more efficient to sort $T$ (\kbd{T = vecextract(T, perm)}) then search for a key in $T$ rather than to search in $v$ using a comparison function or a key. Note also that \tet{mapisdefined} is often easier to use and faster than \kbd{vecsearch}. \noindent The binary digits of \fl\ mean: \item 1: indirect sorting of the vector $x$, i.e.~if $x$ is an $n$-component vector, returns a permutation of $[1,2,\dots,n]$ which applied to the components of $x$ sorts $x$ in increasing order. For example, \kbd{vecextract(x, vecsort(x,,1))} is equivalent to \kbd{vecsort(x)}. \item 4: use descending instead of ascending order. \item 8: remove ``duplicate'' entries with respect to the sorting function (keep the first occurring entry). For example: \bprog ? vecsort([Pi,Mod(1,2),z], (x,y)->0, 8) \\@com make everything compare equal %1 = [3.141592653589793238462643383] ? vecsort([[2,3],[0,1],[0,3]], 2, 8) %2 = [[0, 1], [2, 3]] @eprog pari-2.11.2/src/functions/linear_algebra/qfauto0000644000175000017500000000204413201017466020126 0ustar billbillFunction: qfauto Section: linear_algebra C-Name: qfauto0 Prototype: GDG Help: qfauto(G,{fl}): automorphism group of the positive definite quadratic form G. Doc: $G$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, outputs the automorphism group of the associate lattice. Since this requires computing the minimal vectors, the computations can become very lengthy as the dimension grows. $G$ can also be given by an \kbd{qfisominit} structure. See \kbd{qfisominit} for the meaning of \var{fl}. The output is a two-components vector $[o,g]$ where $o$ is the group order and $g$ is the list of generators (as a vector). For each generator $H$, the equality $G={^t}H\*G\*H$ holds. The interface of this function is experimental and will likely change in the future. This function implements an algorithm of Plesken and Souvignier, following Souvignier's implementation. Variant: The function \fun{GEN}{qfauto}{GEN G, GEN fl} is also available where $G$ is a vector of \kbd{zm} matrices. pari-2.11.2/src/functions/linear_algebra/norml20000644000175000017500000000153213036414402020036 0ustar billbillFunction: norml2 Section: linear_algebra C-Name: gnorml2 Prototype: G Help: norml2(x): square of the L2-norm of x. Doc: square of the $L^2$-norm of $x$. More precisely, if $x$ is a scalar, $\kbd{norml2}(x)$ is defined to be the square of the complex modulus of $x$ (real \typ{QUAD}s are not supported). If $x$ is a polynomial, a (row or column) vector or a matrix, \kbd{norml2($x$)} is defined recursively as $\sum_i \kbd{norml2}(x_i)$, where $(x_i)$ run through the components of $x$. In particular, this yields the usual $\sum |x_i|^2$ (resp.~$\sum |x_{i,j}|^2$) if $x$ is a polynomial or vector (resp.~matrix) with complex components. \bprog ? norml2( [ 1, 2, 3 ] ) \\ vector %1 = 14 ? norml2( [ 1, 2; 3, 4] ) \\ matrix %2 = 30 ? norml2( 2*I + x ) %3 = 5 ? norml2( [ [1,2], [3,4], 5, 6 ] ) \\ recursively defined %4 = 91 @eprog pari-2.11.2/src/functions/linear_algebra/matisdiagonal0000644000175000017500000000034611636712103021446 0ustar billbillFunction: matisdiagonal Section: linear_algebra C-Name: isdiagonal Prototype: iG Help: matisdiagonal(x): true(1) if x is a diagonal matrix, false(0) otherwise. Doc: returns true (1) if $x$ is a diagonal matrix, false (0) if not. pari-2.11.2/src/functions/linear_algebra/setminus0000644000175000017500000000055612314242551020503 0ustar billbillFunction: setminus Section: linear_algebra C-Name: setminus Prototype: GG Help: setminus(x,y): set of elements of x not belonging to y. Description: (vec, vec):vec setminus($1, $2) Doc: difference of the two sets $x$ and $y$ (see \kbd{setisset}), i.e.~set of elements of $x$ which do not belong to $y$. If $x$ or $y$ is not a set, the result is undefined. pari-2.11.2/src/functions/linear_algebra/lindep0000644000175000017500000000416413326135265020115 0ustar billbillFunction: lindep Section: linear_algebra C-Name: lindep0 Prototype: GD0,L, Help: lindep(v,{flag=0}): integral linear dependencies between components of v. flag is optional, and can be 0: default, guess a suitable accuracy, or positive: accuracy to use for the computation, in decimal digits. Doc: \sidx{linear dependence} finds a small non-trivial integral linear combination between components of $v$. If none can be found return an empty vector. If $v$ is a vector with real/complex entries we use a floating point (variable precision) LLL algorithm. If $\fl = 0$ the accuracy is chosen internally using a crude heuristic. If $\fl > 0$ the computation is done with an accuracy of $\fl$ decimal digits. To get meaningful results in the latter case, the parameter $\fl$ should be smaller than the number of correct decimal digits in the input. \bprog ? lindep([sqrt(2), sqrt(3), sqrt(2)+sqrt(3)]) %1 = [-1, -1, 1]~ @eprog If $v$ is $p$-adic, $\fl$ is ignored and the algorithm LLL-reduces a suitable (dual) lattice. \bprog ? lindep([1, 2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)]) %2 = [1, -2]~ @eprog If $v$ is a matrix (or a vector of column vectors, or a vector of row vectors), $\fl$ is ignored and the function returns a non trivial kernel vector if one exists, else an empty vector. \bprog ? lindep([1,2,3;4,5,6;7,8,9]) %3 = [1, -2, 1]~ ? lindep([[1,0], [2,0]]) %4 = [2, -1]~ ? lindep([[1,0], [0,1]]) %5 = []~ @eprog If $v$ contains polynomials or power series over some base field, finds a linear relation with coefficients in the field. \bprog ? lindep([x*y, x^2 + y, x^2*y + x*y^2, 1]) %4 = [y, y, -1, -y^2]~ @eprog\noindent For better control, it is preferable to use \typ{POL} rather than \typ{SER} in the input, otherwise one gets a linear combination which is $t$-adically small, but not necessarily $0$. Indeed, power series are first converted to the minimal absolute accuracy occurring among the entries of $v$ (which can cause some coefficients to be ignored), then truncated to polynomials: \bprog ? v = [t^2+O(t^4), 1+O(t^2)]; L=lindep(v) %1 = [1, 0]~ ? v*L %2 = t^2+O(t^4) \\ small but not 0 @eprog pari-2.11.2/src/functions/linear_algebra/matintersect0000644000175000017500000000121011636712103021323 0ustar billbillFunction: matintersect Section: linear_algebra C-Name: intersect Prototype: GG Help: matintersect(x,y): intersection of the vector spaces whose bases are the columns of x and y. Doc: $x$ and $y$ being two matrices with the same number of rows each of whose columns are independent, finds a basis of the $\Q$-vector space equal to the intersection of the spaces spanned by the columns of $x$ and $y$ respectively. The faster function \tet{idealintersect} can be used to intersect fractional ideals (projective $\Z_K$ modules of rank $1$); the slower but much more general function \tet{nfhnf} can be used to intersect general $\Z_K$-modules. pari-2.11.2/src/functions/linear_algebra/matmuldiagonal0000644000175000017500000000065011636712103021626 0ustar billbillFunction: matmuldiagonal Section: linear_algebra C-Name: matmuldiagonal Prototype: GG Help: matmuldiagonal(x,d): product of matrix x by diagonal matrix whose diagonal coefficients are those of the vector d, equivalent but faster than x*matdiagonal(d). Doc: product of the matrix $x$ by the diagonal matrix whose diagonal entries are those of the vector $d$. Equivalent to, but much faster than $x*\kbd{matdiagonal}(d)$. pari-2.11.2/src/functions/linear_algebra/matfrobenius0000644000175000017500000000130613201017466021325 0ustar billbillFunction: matfrobenius Section: linear_algebra C-Name: matfrobenius Prototype: GD0,L,Dn Help: matfrobenius(M,{flag},{v='x}): return the Frobenius form of the square matrix M. If flag is 1, return only the elementary divisors as a vector of polynomials in the variable v. If flag is 2, return a two-components vector [F,B] where F is the Frobenius form and B is the basis change so that M=B^-1*F*B. Doc: returns the Frobenius form of the square matrix \kbd{M}. If $\fl=1$, returns only the elementary divisors as a vector of polynomials in the variable \kbd{v}. If $\fl=2$, returns a two-components vector [F,B] where \kbd{F} is the Frobenius form and \kbd{B} is the basis change so that $M=B^{-1}FB$. pari-2.11.2/src/functions/linear_algebra/matdet0000644000175000017500000000242513326135265020116 0ustar billbillFunction: matdet Section: linear_algebra C-Name: det0 Prototype: GD0,L, Help: matdet(x,{flag=0}): determinant of the matrix x using an appropriate algorithm depending on the coefficients. If (optional) flag is set to 1, use classical Gaussian elimination (usually worse than the default). Description: (gen, ?0):gen det($1) (gen, 1):gen det2($1) (gen, #small):gen $"incorrect flag in matdet" (gen, small):gen det0($1, $2) Doc: determinant of the square matrix $x$. If $\fl=0$, uses an appropriate algorithm depending on the coefficients: \item integer entries: modular method due to Dixon, Pernet and Stein. \item real or $p$-adic entries: classical Gaussian elimination using maximal pivot. \item intmod entries: classical Gaussian elimination using first non-zero pivot. \item other cases: Gauss-Bareiss. If $\fl=1$, uses classical Gaussian elimination with appropriate pivoting strategy (maximal pivot for real or $p$-adic coefficients). This is usually worse than the default. Variant: Also available are \fun{GEN}{det}{GEN x} ($\fl=0$), \fun{GEN}{det2}{GEN x} ($\fl=1$) and \fun{GEN}{ZM_det}{GEN x} for integer entries. Function: _ZM_det_worker C-Name: ZM_det_worker Prototype: GG Section: programming/internals Help: worker for ZM_det pari-2.11.2/src/functions/linear_algebra/matker0000644000175000017500000000141313326135265020117 0ustar billbillFunction: matker Section: linear_algebra C-Name: matker0 Prototype: GD0,L, Help: matker(x,{flag=0}): basis of the kernel of the matrix x. flag is optional, and may be set to 0: default; non-zero: x is known to have integral entries. Description: (gen, ?0):vec ker($1) (gen, 1):vec ZM_ker($1) (gen, #small) $"incorrect flag in matker" (gen, small):vec matker0($1, $2) Doc: gives a basis for the kernel of the matrix $x$ as columns of a matrix. The matrix can have entries of any type, provided they are compatible with the generic arithmetic operations ($+$, $\times$ and $/$). If $x$ is known to have integral entries, set $\fl=1$. Variant: Also available are \fun{GEN}{ker}{GEN x} ($\fl=0$), \fun{GEN}{ZM_ker}{GEN x} ($\fl=1$). pari-2.11.2/src/functions/linear_algebra/matkermod0000644000175000017500000000121613326135265020620 0ustar billbillFunction: matkermod Section: linear_algebra C-Name: matkermod Prototype: GGD& Help: matkermod(x,d,&im): basis of the kernel of the matrix x modulo d. Doc: gives a Howell basis (unique representation for submodules of~$(\Z/d\Z)^n$, cf. \kbd{matimagemod}) for the kernel of the matrix $x$ modulo $d$ as columns of a matrix. The matrix $x$ must have \typ{INT} entries, and $d$ can be an arbitrary positive integer. If $im$ is present, set it to a basis of the image of~$x$ (which is computed on the way). \bprog ? A = [1,2,3;5,1,4] %1 = [1 2 3] [5 1 4] ? K = matkermod(A,6) %2 = [2 1] [2 1] [0 3] ? (A*K)%6 %3 = [0 0] [0 0] @eprog pari-2.11.2/src/functions/linear_algebra/vector0000644000175000017500000000217113201017466020132 0ustar billbillFunction: vector Section: linear_algebra C-Name: vecteur Prototype: GDVDE Help: vector(n,{X},{expr=0}): row vector with n components of expression expr (X ranges from 1 to n). By default, fill with 0s. Doc: creates a row vector (type \typ{VEC}) with $n$ components whose components are the expression \var{expr} evaluated at the integer points between 1 and $n$. If one of the last two arguments is omitted, fill the vector with zeroes. \bprog ? vector(3,i, 5*i) %1 = [5, 10, 15] ? vector(3) %2 = [0, 0, 0] @eprog The variable $X$ is lexically scoped to each evaluation of \var{expr}. Any change to $X$ within \var{expr} does not affect subsequent evaluations, it still runs 1 to $n$. A local change allows for example different indexing: \bprog vector(10, i, i=i-1; f(i)) \\ i = 0, ..., 9 vector(10, i, i=2*i; f(i)) \\ i = 2, 4, ..., 20 @eprog\noindent This per-element scope for $X$ differs from \kbd{for} loop evaluations, as the following example shows: \bprog n = 3 v = vector(n); vector(n, i, i++) ----> [2, 3, 4] v = vector(n); for (i = 1, n, v[i] = i++) ----> [2, 0, 4] @eprog\noindent %\syn{NO} pari-2.11.2/src/functions/linear_algebra/seralgdep0000644000175000017500000000146413036414402020577 0ustar billbillFunction: seralgdep Section: linear_algebra C-Name: seralgdep Prototype: GLL Help: seralgdep(s,p,r): find a linear relation between powers (1,s, ..., s^p) of the series s, with polynomial coefficients of degree <= r. Doc: \sidx{algebraic dependence} finds a linear relation between powers $(1,s, \dots, s^p)$ of the series $s$, with polynomial coefficients of degree $\leq r$. In case no relation is found, return $0$. \bprog ? s = 1 + 10*y - 46*y^2 + 460*y^3 - 5658*y^4 + 77740*y^5 + O(y^6); ? seralgdep(s, 2, 2) %2 = -x^2 + (8*y^2 + 20*y + 1) ? subst(%, x, s) %3 = O(y^6) ? seralgdep(s, 1, 3) %4 = (-77*y^2 - 20*y - 1)*x + (310*y^3 + 231*y^2 + 30*y + 1) ? seralgdep(s, 1, 2) %5 = 0 @eprog\noindent The series main variable must not be $x$, so as to be able to express the result as a polynomial in $x$. pari-2.11.2/src/functions/linear_algebra/mathilbert0000644000175000017500000000040711636712103020763 0ustar billbillFunction: mathilbert Section: linear_algebra C-Name: mathilbert Prototype: L Help: mathilbert(n): Hilbert matrix of order n. Doc: $x$ being a \kbd{long}, creates the \idx{Hilbert matrix}of order $x$, i.e.~the matrix whose coefficient ($i$,$j$) is $1/ (i+j-1)$. pari-2.11.2/src/functions/linear_algebra/qfjacobi0000644000175000017500000000155613036414402020411 0ustar billbillFunction: qfjacobi Section: linear_algebra C-Name: jacobi Prototype: Gp Help: qfjacobi(A): eigenvalues and orthogonal matrix of eigenvectors of the real symmetric matrix A. Doc: apply Jacobi's eigenvalue algorithm to the real symmetric matrix $A$. This returns $[L, V]$, where \item $L$ is the vector of (real) eigenvalues of $A$, sorted in increasing order, \item $V$ is the corresponding orthogonal matrix of eigenvectors of $A$. \bprog ? \p19 ? A = [1,2;2,1]; mateigen(A) %1 = [-1 1] [ 1 1] ? [L, H] = qfjacobi(A); ? L %3 = [-1.000000000000000000, 3.000000000000000000]~ ? H %4 = [ 0.7071067811865475245 0.7071067811865475244] [-0.7071067811865475244 0.7071067811865475245] ? norml2( (A-L[1])*H[,1] ) \\ approximate eigenvector %5 = 9.403954806578300064 E-38 ? norml2(H*H~ - 1) %6 = 2.350988701644575016 E-38 \\ close to orthogonal @eprog pari-2.11.2/src/functions/linear_algebra/qfgaussred0000644000175000017500000000231313201017466020772 0ustar billbillFunction: qfgaussred Section: linear_algebra C-Name: qfgaussred Prototype: G Help: qfgaussred(q): square reduction of the (symmetric) matrix q (returns a square matrix whose i-th diagonal term is the coefficient of the i-th square in which the coefficient of the i-th variable is 1). Doc: \idx{decomposition into squares} of the quadratic form represented by the symmetric matrix $q$. The result is a matrix whose diagonal entries are the coefficients of the squares, and the off-diagonal entries on each line represent the bilinear forms. More precisely, if $(a_{ij})$ denotes the output, one has $$ q(x) = \sum_i a_{ii} (x_i + \sum_{j \neq i} a_{ij} x_j)^2 $$ \bprog ? qfgaussred([0,1;1,0]) %1 = [1/2 1] [-1 -1/2] @eprog\noindent This means that $2xy = (1/2)(x+y)^2 - (1/2)(x-y)^2$. Singular matrices are supported, in which case some diagonal coefficients will vanish: \bprog ? qfgaussred([1,1;1,1]) %1 = [1 1] [1 0] @eprog\noindent This means that $x^2 + 2xy + y^2 = (x+y)^2$. Variant: \fun{GEN}{qfgaussred_positive}{GEN q} assumes that $q$ is positive definite and is a little faster; returns \kbd{NULL} if a vector with negative norm occurs (non positive matrix or too many rounding errors). pari-2.11.2/src/functions/linear_algebra/matdetmod0000644000175000017500000000126213326135265020614 0ustar billbillFunction: matdetmod Section: linear_algebra C-Name: matdetmod Prototype: GG Help: matdetmod(x,d): determinant of the matrix x modulo d. Doc: Given a matrix $x$ with \typ{INT} entries and $d$ an arbitrary positive integer, return the determinant of $x$ modulo $d$. \bprog ? A = [4,2,3; 4,5,6; 7,8,9] ? matdetmod(A,27) %2 = 9 @eprog Note that using the generic function \kbd{matdet} on a matrix with \typ{INTMOD} entries uses Gaussian reduction and will fail in general when the modulus is not prime. \bprog ? matdet(A * Mod(1,27)) *** at top-level: matdet(A*Mod(1,27)) *** ^------------------ *** matdet: impossible inverse in Fl_inv: Mod(3, 27). @eprog pari-2.11.2/src/functions/linear_algebra/matadjoint0000644000175000017500000000212013036414402020751 0ustar billbillFunction: matadjoint Section: linear_algebra C-Name: matadjoint0 Prototype: GD0,L, Help: matadjoint(M,{flag=0}): adjoint matrix of M using Leverrier-Faddeev's algorithm. If flag is 1, compute the characteristic polynomial independently first. Doc: \idx{adjoint matrix} of $M$, i.e.~a matrix $N$ of cofactors of $M$, satisfying $M*N=\det(M)*\Id$. $M$ must be a (non-necessarily invertible) square matrix of dimension $n$. If $\fl$ is 0 or omitted, we try to use Leverrier-Faddeev's algorithm, which assumes that $n!$ invertible. If it fails or $\fl = 1$, compute $T = \kbd{charpoly}(M)$ independently first and return $(-1)^{n-1} (T(x)-T(0))/x$ evaluated at $M$. \bprog ? a = [1,2,3;3,4,5;6,7,8] * Mod(1,4); %2 = [Mod(1, 4) Mod(2, 4) Mod(3, 4)] [Mod(3, 4) Mod(0, 4) Mod(1, 4)] [Mod(2, 4) Mod(3, 4) Mod(0, 4)] @eprog\noindent Both algorithms use $O(n^4)$ operations in the base ring, and are usually slower than computing the characteristic polynomial or the inverse of $M$ directly. Variant: Also available are \fun{GEN}{adj}{GEN x} (\fl=0) and \fun{GEN}{adjsafe}{GEN x} (\fl=1). pari-2.11.2/src/functions/linear_algebra/qflll0000644000175000017500000000611413326135265017751 0ustar billbillFunction: qflll Section: linear_algebra C-Name: qflll0 Prototype: GD0,L, Help: qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x (gives the unimodular transformation matrix T such that x*T is LLL-reduced). flag is optional, and can be 0: default, 1: assumes x is integral, 2: assumes x is integral, returns a partially reduced basis, 4: assumes x is integral, returns [K,T] where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. Description: (vec, ?0):vec lll($1) (vec, 1):vec lllint($1) (vec, 2):vec lllintpartial($1) (vec, 4):vec lllkerim($1) (vec, 5):vec lllkerimgen($1) (vec, 8):vec lllgen($1) (vec, #small):vec $"Bad flag in qflll" (vec, small):vec qflll0($1, $2) Doc: \idx{LLL} algorithm applied to the \emph{columns} of the matrix $x$. The columns of $x$ may be linearly dependent. The result is a unimodular transformation matrix $T$ such that $x \cdot T$ is an LLL-reduced basis of the lattice generated by the column vectors of $x$. Note that if $x$ is not of maximal rank $T$ will not be square. The LLL parameters are $(0.51,0.99)$, meaning that the Gram-Schmidt coefficients for the final basis satisfy $|\mu_{i,j}| \leq 0.51$, and the Lov\'{a}sz's constant is $0.99$. If $\fl=0$ (default), assume that $x$ has either exact (integral or rational) or real floating point entries. The matrix is rescaled, converted to integers and the behavior is then as in $\fl = 1$. If $\fl=1$, assume that $x$ is integral. Computations involving Gram-Schmidt vectors are approximate, with precision varying as needed (Lehmer's trick, as generalized by Schnorr). Adapted from Nguyen and Stehl\'e's algorithm and Stehl\'e's code (\kbd{fplll-1.3}). If $\fl=2$, $x$ should be an integer matrix whose columns are linearly independent. Returns a partially reduced basis for $x$, using an unpublished algorithm by Peter Montgomery: a basis is said to be \emph{partially reduced} if $|v_i \pm v_j| \geq |v_i|$ for any two distinct basis vectors $v_i, \, v_j$. This is faster than $\fl=1$, esp. when one row is huge compared to the other rows (knapsack-style), and should quickly produce relatively short vectors. The resulting basis is \emph{not} LLL-reduced in general. If LLL reduction is eventually desired, avoid this partial reduction: applying LLL to the partially reduced matrix is significantly \emph{slower} than starting from a knapsack-type lattice. If $\fl=4$, as $\fl=1$, returning a vector $[K, T]$ of matrices: the columns of $K$ represent a basis of the integer kernel of $x$ (not LLL-reduced in general) and $T$ is the transformation matrix such that $x\cdot T$ is an LLL-reduced $\Z$-basis of the image of the matrix $x$. If $\fl=5$, case as case $4$, but $x$ may have polynomial coefficients. If $\fl=8$, same as case $0$, but $x$ may have polynomial coefficients. Variant: Also available are \fun{GEN}{lll}{GEN x} ($\fl=0$), \fun{GEN}{lllint}{GEN x} ($\fl=1$), and \fun{GEN}{lllkerim}{GEN x} ($\fl=4$). pari-2.11.2/src/functions/linear_algebra/vectorv0000644000175000017500000000044011636712103020315 0ustar billbillFunction: vectorv Section: linear_algebra C-Name: vvecteur Prototype: GDVDE Help: vectorv(n,{X},{expr=0}): column vector with n components of expression expr (X ranges from 1 to n). By default, fill with 0s. Doc: as \tet{vector}, but returns a column vector (type \typ{COL}). %\syn{NO} pari-2.11.2/src/functions/linear_algebra/HEADER0000644000175000017500000000162313326135265017567 0ustar billbillFunction: _header_linear_algebra Class: header Section: linear_algebra Doc: \section{Vectors, matrices, linear algebra and sets} \label{se:linear_algebra} Note that most linear algebra functions operating on subspaces defined by generating sets (such as \tet{mathnf}, \tet{qflll}, etc.) take matrices as arguments. As usual, the generating vectors are taken to be the \emph{columns} of the given matrix. Since PARI does not have a strong typing system, scalars live in unspecified commutative base rings. It is very difficult to write robust linear algebra routines in such a general setting. We thus assume that the base ring is a domain and work over its field of fractions. If the base ring is \emph{not} a domain, one gets an error as soon as a non-zero pivot turns out to be non-invertible. Some functions, e.g.~\kbd{mathnf} or \kbd{mathnfmod}, specifically assume that the base ring is $\Z$. pari-2.11.2/src/functions/linear_algebra/qfperfection0000644000175000017500000000116711636712103021321 0ustar billbillFunction: qfperfection Section: linear_algebra C-Name: perf Prototype: G Help: qfperfection(G): rank of matrix of xx~ for x minimal vectors of a gram matrix G. Doc: $G$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, outputs the perfection rank of the form. That is, gives the rank of the family of the $s$ symmetric matrices $v_iv_i^t$, where $s$ is half the number of minimal vectors and the $v_i$ ($1\le i\le s$) are the minimal vectors. Since this requires computing the minimal vectors, the computations can become very lengthy as the dimension of $x$ grows. pari-2.11.2/src/functions/linear_algebra/setintersect0000644000175000017500000000050012314242551021335 0ustar billbillFunction: setintersect Section: linear_algebra C-Name: setintersect Prototype: GG Help: setintersect(x,y): intersection of the sets x and y. Description: (vec, vec):vec setintersect($1, $2) Doc: intersection of the two sets $x$ and $y$ (see \kbd{setisset}). If $x$ or $y$ is not a set, the result is undefined. pari-2.11.2/src/functions/linear_algebra/qfisom0000644000175000017500000000236113326135265020135 0ustar billbillFunction: qfisom Section: linear_algebra C-Name: qfisom0 Prototype: GGDGDG Help: qfisom(G,H,{fl},{grp}): find an isomorphism between the integral positive definite quadratic forms G and H if it exists. G can also be given by a qfisominit structure which is preferable if several forms need to be compared to G. Doc: $G$, $H$ being square and symmetric matrices with integer entries representing positive definite quadratic forms, return an invertible matrix $S$ such that $G={^t}S\*H\*S$. This defines a isomorphism between the corresponding lattices. Since this requires computing the minimal vectors, the computations can become very lengthy as the dimension grows. See \kbd{qfisominit} for the meaning of \var{fl}. If \var{grp} is given it must be the automorphism group of $H$. It will be used to speed up the computation. $G$ can also be given by an \kbd{qfisominit} structure which is preferable if several forms $H$ need to be compared to $G$. This function implements an algorithm of Plesken and Souvignier, following Souvignier's implementation. Variant: Also available is \fun{GEN}{qfisom}{GEN G, GEN H, GEN fl, GEN grp} where $G$ is a vector of \kbd{zm}, and $H$ is a \kbd{zm}, and $grp$ is either \kbd{NULL} or a vector of \kbd{zm}. pari-2.11.2/src/functions/linear_algebra/qfeval0000644000175000017500000000517513326135265020123 0ustar billbillFunction: qfeval Section: linear_algebra C-Name: qfeval0 Prototype: DGGDG Help: qfeval({q},x,{y}): evaluate the quadratic form q (symmetric matrix) at x; if y is present, evaluate the polar form at (x,y); if q omitted, use the standard Euclidean form. Doc: evaluate the quadratic form $q$ (given by a symmetric matrix) at the vector $x$; if $y$ is present, evaluate the polar form at $(x,y)$; if $q$ omitted, use the standard Euclidean scalar product, corresponding to the identity matrix. Roughly equivalent to \kbd{x\til * q * y}, but a little faster and more convenient (does not distinguish between column and row vectors): \bprog ? x = [1,2,3]~; y = [-1,3,1]~; q = [1,2,3;2,2,-1;3,-1,9]; ? qfeval(q,x,y) %2 = 23 ? for(i=1,10^6, qfeval(q,x,y)) time = 661ms ? for(i=1,10^6, x~*q*y) time = 697ms @eprog\noindent The speedup is noticeable for the quadratic form, compared to \kbd{x\til * q * x}, since we save almost half the operations: \bprog ? for(i=1,10^6, qfeval(q,x)) time = 487ms @eprog\noindent The special case $q = \text{Id}$ is handled faster if we omit $q$ altogether: \bprog ? qfeval(,x,y) %6 = 8 ? q = matid(#x); ? for(i=1,10^6, qfeval(q,x,y)) time = 529 ms. ? for(i=1,10^6, qfeval(,x,y)) time = 228 ms. ? for(i=1,10^6, x~*y) time = 274 ms. @eprog We also allow \typ{MAT}s of compatible dimensions for $x$, and return \kbd{x\til * q * x} in this case as well: \bprog ? M = [1,2,3;4,5,6;7,8,9]; qfeval(,M) \\ Gram matrix %5 = [66 78 90] [78 93 108] [90 108 126] ? q = [1,2,3;2,2,-1;3,-1,9]; ? for(i=1,10^6, qfeval(q,M)) time = 2,008 ms. ? for(i=1,10^6, M~*q*M) time = 2,368 ms. ? for(i=1,10^6, qfeval(,M)) time = 1,053 ms. ? for(i=1,10^6, M~*M) time = 1,171 ms. @eprog If $q$ is a \typ{QFI} or \typ{QFR}, it is implicitly converted to the attached symmetric \typ{MAT}. This is done more efficiently than by direct conversion, since we avoid introducing a denominator $2$ and rational arithmetic: \bprog ? q = Qfb(2,3,4); x = [2,3]; ? qfeval(q, x) %2 = 62 ? Q = Mat(q) %3 = [ 2 3/2] [3/2 4] ? qfeval(Q, x) %4 = 62 ? for (i=1, 10^6, qfeval(q,x)) time = 758 ms. ? for (i=1, 10^6, qfeval(Q,x)) time = 1,110 ms. @eprog Finally, when $x$ is a \typ{MAT} with \emph{integral} coefficients, we allow a \typ{QFI} or \typ{QFR} for $q$ and return the binary quadratic form $q \circ M$. Again, the conversion to \typ{MAT} is less efficient in this case: \bprog ? q = Qfb(2,3,4); Q = Mat(q); x = [1,2;3,4]; ? qfeval(q, x) %2 = Qfb(47, 134, 96) ? qfeval(Q,x) %3 = [47 67] [67 96] ? for (i=1, 10^6, qfeval(q,x)) time = 701 ms. ? for (i=1, 10^6, qfeval(Q,x)) time = 1,639 ms. @eprog pari-2.11.2/src/functions/linear_algebra/qfminim0000644000175000017500000001302513201017466020270 0ustar billbillFunction: qfminim Section: linear_algebra C-Name: qfminim0 Prototype: GDGDGD0,L,p Help: qfminim(x,{b},{m},{flag=0}): x being a square and symmetric matrix representing a positive definite quadratic form, this function deals with the vectors of x whose norm is less than or equal to b, enumerated using the Fincke-Pohst algorithm, storing at most m vectors (no limit if m is omitted). The function searches for the minimal non-zero vectors if b is omitted. The precise behavior depends on flag. 0: returns at most 2m vectors (unless m omitted), returns [N,M,mat] where N is the number of vectors enumerated, M the maximum norm among these, and mat lists half the vectors (the other half is given by -mat). 1: ignores m and returns the first vector whose norm is less than b. 2: as 0 but uses a more robust, slower implementation, valid for non integral quadratic forms. Doc: $x$ being a square and symmetric matrix representing a positive definite quadratic form, this function deals with the vectors of $x$ whose norm is less than or equal to $b$, enumerated using the Fincke-Pohst algorithm, storing at most $m$ vectors (no limit if $m$ is omitted). The function searches for the minimal non-zero vectors if $b$ is omitted. The behavior is undefined if $x$ is not positive definite (a ``precision too low'' error is most likely, although more precise error messages are possible). The precise behavior depends on $\fl$. If $\fl=0$ (default), returns at most $2m$ vectors. The result is a three-component vector, the first component being the number of vectors enumerated (which may be larger than $2m$), the second being the maximum norm found, and the last vector is a matrix whose columns are found vectors, only one being given for each pair $\pm v$ (at most $m$ such pairs, unless $m$ was omitted). The vectors are returned in no particular order. If $\fl=1$, ignores $m$ and returns $[N,v]$, where $v$ is a non-zero vector of length $N \leq b$, or $[]$ if no non-zero vector has length $\leq b$. If no explicit $b$ is provided, return a vector of smallish norm (smallest vector in an LLL-reduced basis). In these two cases, $x$ must have \emph{integral} entries. The implementation uses low precision floating point computations for maximal speed, which gives incorrect result when $x$ has large entries. (The condition is checked in the code and the routine raises an error if large rounding errors occur.) A more robust, but much slower, implementation is chosen if the following flag is used: If $\fl=2$, $x$ can have non integral real entries. In this case, if $b$ is omitted, the ``minimal'' vectors only have approximately the same norm. If $b$ is omitted, $m$ is an upper bound for the number of vectors that will be stored and returned, but all minimal vectors are nevertheless enumerated. If $m$ is omitted, all vectors found are stored and returned; note that this may be a huge vector! \bprog ? x = matid(2); ? qfminim(x) \\@com 4 minimal vectors of norm 1: $\pm[0,1]$, $\pm[1,0]$ %2 = [4, 1, [0, 1; 1, 0]] ? { x = [4, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1, 0,-1, 0, 0, 0,-2; 2, 4,-2,-2, 0,-2, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1, 0, 1,-1,-1; 0,-2, 4, 0,-2, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 0, 0, 1,-1,-1, 0, 0; 0,-2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1,-1, 0, 1,-1, 1, 0; 0, 0,-2, 0, 4, 0, 0, 0, 1,-1, 0, 0, 1, 0, 0, 0,-2, 0, 0,-1, 1, 1, 0, 0; -2, -2,0, 0, 0, 4,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,-1, 1, 1; 0, 0, 0, 0, 0,-2, 4,-2, 0, 0, 0, 0, 0, 1, 0, 0, 0,-1, 0, 0, 0, 1,-1, 0; 0, 0, 0, 0, 0, 0,-2, 4, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1,-1,-1, 0, 1, 0; 0, 0, 0, 0, 1,-1, 0, 0, 4, 0,-2, 0, 1, 1, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0,-1, 0, 0, 0, 0, 4, 0, 0, 1, 1,-1, 1, 0, 0, 0, 1, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 4,-2, 0,-1, 0, 0, 0,-1, 0,-1, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 4,-1, 1, 0, 0,-1, 1, 0, 1, 1, 1,-1, 0; 1, 0,-1, 1, 1, 0, 0,-1, 1, 1, 0,-1, 4, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1,-1; -1,-1, 1,-1, 0, 0, 1, 0, 1, 1,-1, 1, 0, 4, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1; 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 1, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 1, 0, 4, 0, 0, 0, 0, 1, 1, 0, 0; 0, 0, 1, 0,-2, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 4, 1, 1, 1, 0, 0, 1, 1; 1, 0, 0, 1, 0, 0,-1, 0, 1, 0,-1, 1, 1, 0, 0, 0, 1, 4, 0, 1, 1, 0, 1, 0; 0, 0, 0,-1, 0, 1, 0,-1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 4, 0, 1, 1, 0, 1; -1, -1,1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0, 1, 0, 0, 1, 1, 0, 4, 0, 0, 1, 1; 0, 0,-1, 1, 1, 0, 0,-1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 4, 1, 0, 1; 0, 1,-1,-1, 1,-1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 4, 0, 1; 0,-1, 0, 1, 0, 1,-1, 1, 0, 1, 0,-1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 4, 1; -2,-1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 4]; } ? qfminim(x,,0) \\ the Leech lattice has 196560 minimal vectors of norm 4 time = 648 ms. %4 = [196560, 4, [;]] ? qfminim(x,,0,2); \\ safe algorithm. Slower and unnecessary here. time = 18,161 ms. %5 = [196560, 4.000061035156250000, [;]] @eprog\noindent\sidx{Leech lattice}\sidx{minimal vector} In the last example, we store 0 vectors to limit memory use. All minimal vectors are nevertheless enumerated. Provided \kbd{parisize} is about 50MB, \kbd{qfminim(x)} succeeds in 2.5 seconds. Variant: Also available are \fun{GEN}{minim}{GEN x, GEN b = NULL, GEN m = NULL} ($\fl=0$), \fun{GEN}{minim2}{GEN x, GEN b = NULL, GEN m = NULL} ($\fl=1$). \fun{GEN}{minim_raw}{GEN x, GEN b = NULL, GEN m = NULL} (do not perform LLL reduction on x and return \kbd{NULL} on accuracy error). pari-2.11.2/src/functions/linear_algebra/qfsolve0000644000175000017500000000201013201017466020277 0ustar billbillFunction: qfsolve Section: linear_algebra C-Name: qfsolve Prototype: G Help: qfsolve(G): solve over Q the quadratic equation X^t G X = 0, where G is a symmetric matrix. Doc: Given a square symmetric matrix $G$ of dimension $n \geq 1$, solve over $\Q$ the quadratic equation $X^tGX = 0$. The matrix $G$ must have rational coefficients. The solution might be a single non-zero vector (vectorv) or a matrix (whose columns generate a totally isotropic subspace). If no solution exists, returns an integer, that can be a prime $p$ such that there is no local solution at $p$, or $-1$ if there is no real solution, or $-2$ if $n = 2$ and $-\det G$ is positive but not a square (which implies there is a real solution, but no local solution at some $p$ dividing $\det G$). \bprog ? G = [1,0,0;0,1,0;0,0,-34]; ? qfsolve(G) %1 = [-3, -5, 1]~ ? qfsolve([1,0; 0,2]) %2 = -1 \\ no real solution ? qfsolve([1,0,0;0,3,0; 0,0,-2]) %3 = 3 \\ no solution in Q_3 ? qfsolve([1,0; 0,-2]) %4 = -2 \\ no solution, n = 2 @eprog pari-2.11.2/src/functions/linear_algebra/qflllgram0000644000175000017500000000344111636712103020612 0ustar billbillFunction: qflllgram Section: linear_algebra C-Name: qflllgram0 Prototype: GD0,L, Help: qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix is G (gives the unimodular transformation matrix). flag is optional and can be 0: default,1: assumes x is integral, 4: assumes x is integral, returns [K,T], where K is the integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. Doc: same as \kbd{qflll}, except that the matrix $G = \kbd{x\til * x}$ is the Gram matrix of some lattice vectors $x$, and not the coordinates of the vectors themselves. In particular, $G$ must now be a square symmetric real matrix, corresponding to a positive quadratic form (not necessarily definite: $x$ needs not have maximal rank). The result is a unimodular transformation matrix $T$ such that $x \cdot T$ is an LLL-reduced basis of the lattice generated by the column vectors of $x$. See \tet{qflll} for further details about the LLL implementation. If $\fl=0$ (default), assume that $G$ has either exact (integral or rational) or real floating point entries. The matrix is rescaled, converted to integers and the behavior is then as in $\fl = 1$. If $\fl=1$, assume that $G$ is integral. Computations involving Gram-Schmidt vectors are approximate, with precision varying as needed (Lehmer's trick, as generalized by Schnorr). Adapted from Nguyen and Stehl\'e's algorithm and Stehl\'e's code (\kbd{fplll-1.3}). $\fl=4$: $G$ has integer entries, gives the kernel and reduced image of $x$. $\fl=5$: same as $4$, but $G$ may have polynomial coefficients. Variant: Also available are \fun{GEN}{lllgram}{GEN G} ($\fl=0$), \fun{GEN}{lllgramint}{GEN G} ($\fl=1$), and \fun{GEN}{lllgramkerim}{GEN G} ($\fl=4$). pari-2.11.2/src/functions/linear_algebra/qfparam0000644000175000017500000000161113201017466020255 0ustar billbillFunction: qfparam Section: linear_algebra C-Name: qfparam Prototype: GGD0,L, Help: qfparam(G, sol, {flag = 0}): coefficients of binary quadratic forms that parametrize the solutions of the ternary quadratic form G, using the particular solution sol. Doc: coefficients of binary quadratic forms that parametrize the solutions of the ternary quadratic form $G$, using the particular solution~\var{sol}. \fl is optional and can be 1, 2, or 3, in which case the \fl-th form is reduced. The default is \fl=0 (no reduction). \bprog ? G = [1,0,0;0,1,0;0,0,-34]; ? M = qfparam(G, qfsolve(G)) %2 = [ 3 -10 -3] [-5 -6 5] [ 1 0 1] @eprog Indeed, the solutions can be parametrized as $$(3x^2 - 10xy - 3y^2)^2 + (-5x^2 - 6xy + 5y^2)^2 -34(x^2 + y^2)^2 = 0.$$ \bprog ? v = y^2 * M*[1,x/y,(x/y)^2]~ %3 = [3*x^2 - 10*y*x - 3*y^2, -5*x^2 - 6*y*x + 5*y^2, -x^2 - y^2]~ ? v~*G*v %4 = 0 @eprog pari-2.11.2/src/functions/linear_algebra/matimage0000644000175000017500000000131412314242551020411 0ustar billbillFunction: matimage Section: linear_algebra C-Name: matimage0 Prototype: GD0,L, Help: matimage(x,{flag=0}): basis of the image of the matrix x. flag is optional and can be set to 0 or 1, corresponding to two different algorithms. Description: (gen, ?0):vec image($1) (gen, 1):vec image2($1) (gen, #small) $"incorrect flag in matimage" (gen, small):vec matimage0($1, $2) Doc: gives a basis for the image of the matrix $x$ as columns of a matrix. A priori the matrix can have entries of any type. If $\fl=0$, use standard Gauss pivot. If $\fl=1$, use \kbd{matsupplement} (much slower: keep the default flag!). Variant: Also available is \fun{GEN}{image}{GEN x} ($\fl=0$). pari-2.11.2/src/functions/linear_algebra/vecsearch0000644000175000017500000000363513326135265020607 0ustar billbillFunction: vecsearch Section: linear_algebra C-Name: vecsearch Prototype: lGGDG Help: vecsearch(v,x,{cmpf}): determines whether x belongs to the sorted vector v. If the comparison function cmpf is explicitly given, assume that v was sorted according to vecsort(, cmpf). Doc: determines whether $x$ belongs to the sorted vector or list $v$: return the (positive) index where $x$ was found, or $0$ if it does not belong to $v$. If the comparison function cmpf is omitted, we assume that $v$ is sorted in increasing order, according to the standard comparison function \kbd{lex}, thereby restricting the possible types for $x$ and the elements of $v$ (integers, fractions, reals, and vectors of such). We also transparently allow a \typ{VECSMALL} $x$ in this case, for the natural ordering of the integers. If \kbd{cmpf} is present, it is understood as a comparison function and we assume that $v$ is sorted according to it, see \tet{vecsort} for how to encode comparison functions. \bprog ? v = [1,3,4,5,7]; ? vecsearch(v, 3) %2 = 2 ? vecsearch(v, 6) %3 = 0 \\ not in the list ? vecsearch([7,6,5], 5) \\ unsorted vector: result undefined %4 = 0 @eprog\noindent Note that if we are sorting with respect to a key which is expensive to compute (e.g. a discriminant), one should rather precompute all keys, sort that vector and search in the vector of keys, rather than searching in the original vector with respect to a comparison function. By abuse of notation, $x$ is also allowed to be a matrix, seen as a vector of its columns; again by abuse of notation, a \typ{VEC} is considered as part of the matrix, if its transpose is one of the matrix columns. \bprog ? v = vecsort([3,0,2; 1,0,2]) \\ sort matrix columns according to lex order %1 = [0 2 3] [0 2 1] ? vecsearch(v, [3,1]~) %2 = 3 ? vecsearch(v, [3,1]) \\ can search for x or x~ %3 = 3 ? vecsearch(v, [1,2]) %4 = 0 \\ not in the list @eprog\noindent pari-2.11.2/src/functions/linear_algebra/setsearch0000644000175000017500000000320613326135265020617 0ustar billbillFunction: setsearch Section: linear_algebra C-Name: setsearch Prototype: lGGD0,L, Help: setsearch(S,x,{flag=0}): determines whether x belongs to the set (or sorted list) S. If flag is 0 or omitted, returns 0 if it does not, otherwise returns the index j such that x==S[j]. If flag is non-zero, return 0 if x belongs to S, otherwise the index j where it should be inserted. Doc: determines whether $x$ belongs to the set $S$ (see \kbd{setisset}). We first describe the default behavior, when $\fl$ is zero or omitted. If $x$ belongs to the set $S$, returns the index $j$ such that $S[j]=x$, otherwise returns 0. \bprog ? T = [7,2,3,5]; S = Set(T); ? setsearch(S, 2) %2 = 1 ? setsearch(S, 4) \\ not found %3 = 0 ? setsearch(T, 7) \\ search in a randomly sorted vector %4 = 0 \\ WRONG ! @eprog\noindent If $S$ is not a set, we also allow sorted lists with respect to the \tet{cmp} sorting function, without repeated entries, as per \tet{listsort}$(L,1)$; otherwise the result is undefined. \bprog ? L = List([1,4,2,3,2]); setsearch(L, 4) %1 = 0 \\ WRONG ! ? listsort(L, 1); L \\ sort L first %2 = List([1, 2, 3, 4]) ? setsearch(L, 4) %3 = 4 \\ now correct @eprog\noindent If $\fl$ is non-zero, this function returns the index $j$ where $x$ should be inserted, and $0$ if it already belongs to $S$. This is meant to be used for dynamically growing (sorted) lists, in conjunction with \kbd{listinsert}. \bprog ? L = List([1,5,2,3,2]); listsort(L,1); L %1 = List([1,2,3,5]) ? j = setsearch(L, 4, 1) \\ 4 should have been inserted at index j %2 = 4 ? listinsert(L, 4, j); L %3 = List([1, 2, 3, 4, 5]) @eprog pari-2.11.2/src/functions/linear_algebra/normlp0000644000175000017500000000265013447371554020156 0ustar billbillFunction: normlp Section: linear_algebra C-Name: gnormlp Prototype: GDGp Help: normlp(x,{p=oo}): Lp-norm of x; sup norm if p is omitted. Description: (gen):gen:prec gsupnorm($1, $prec) (gen,):gen:prec gsupnorm($1, $prec) (gen,1):gen:prec gnorml1($1, $prec) Doc: $L^p$-norm of $x$; sup norm if $p$ is omitted or \kbd{+oo}. More precisely, if $x$ is a scalar, \kbd{normlp}$(x, p)$ is defined to be \kbd{abs}$(x)$. If $x$ is a polynomial, a (row or column) vector or a matrix: \item if $p$ is omitted or \kbd{+oo}, then \kbd{normlp($x$)} is defined recursively as $\max_i \kbd{normlp}(x_i))$, where $(x_i)$ run through the components of~$x$. In particular, this yields the usual sup norm if $x$ is a polynomial or vector with complex components. \item otherwise, \kbd{normlp($x$, $p$)} is defined recursively as $(\sum_i \kbd{normlp}^p(x_i,p))^{1/p}$. In particular, this yields the usual $(\sum |x_i|^p)^{1/p}$ if $x$ is a polynomial or vector with complex components. \bprog ? v = [1,-2,3]; normlp(v) \\ vector %1 = 3 ? normlp(v, +oo) \\ same, more explicit %2 = 3 ? M = [1,-2;-3,4]; normlp(M) \\ matrix %3 = 4 ? T = (1+I) + I*x^2; normlp(T) %4 = 1.4142135623730950488016887242096980786 ? normlp([[1,2], [3,4], 5, 6]) \\ recursively defined %5 = 6 ? normlp(v, 1) %6 = 6 ? normlp(M, 1) %7 = 10 ? normlp(T, 1) %8 = 2.4142135623730950488016887242096980786 @eprog pari-2.11.2/src/functions/linear_algebra/vecprod0000644000175000017500000000045713326135265020305 0ustar billbillFunction: vecprod Section: linear_algebra C-Name: vecprod Prototype: G Help: vecprod(v): return the product of the components of the vector v. Doc: return the product of the components of the vector $v$. Return $1$ on an empty vector. \bprog ? vecprod([1,2,3]) %1 = 6 ? vecprod([]) %2 = 1 @eprog pari-2.11.2/src/functions/linear_algebra/charpoly0000644000175000017500000000531612314242551020454 0ustar billbillFunction: charpoly Section: linear_algebra C-Name: charpoly0 Prototype: GDnD5,L, Help: charpoly(A,{v='x},{flag=5}): det(v*Id-A)=characteristic polynomial of the matrix or polmod A. flag is optional and ignored unless A is a matrix; it may be set to 0 (Le Verrier), 1 (Lagrange interpolation), 2 (Hessenberg form), 3 (Berkowitz), 4 (modular) if A is integral, or 5 (default, choose best method). Algorithms 0 (Le Verrier) and 1 (Lagrange) assume that n! is invertible, where n is the dimension of the matrix. Doc: \idx{characteristic polynomial} of $A$ with respect to the variable $v$, i.e.~determinant of $v*I-A$ if $A$ is a square matrix. \bprog ? charpoly([1,2;3,4]); %1 = x^2 - 5*x - 2 ? charpoly([1,2;3,4],, 't) %2 = t^2 - 5*t - 2 @eprog\noindent If $A$ is not a square matrix, the function returns the characteristic polynomial of the map ``multiplication by $A$'' if $A$ is a scalar: \bprog ? charpoly(Mod(x+2, x^3-2)) %1 = x^3 - 6*x^2 + 12*x - 10 ? charpoly(I) %2 = x^2 + 1 ? charpoly(quadgen(5)) %3 = x^2 - x - 1 ? charpoly(ffgen(ffinit(2,4))) %4 = Mod(1, 2)*x^4 + Mod(1, 2)*x^3 + Mod(1, 2)*x^2 + Mod(1, 2)*x + Mod(1, 2) @eprog The value of $\fl$ is only significant for matrices, and we advise to stick to the default value. Let $n$ be the dimension of $A$. If $\fl=0$, same method (Le Verrier's) as for computing the adjoint matrix, i.e.~using the traces of the powers of $A$. Assumes that $n!$ is invertible; uses $O(n^4)$ scalar operations. If $\fl=1$, uses Lagrange interpolation which is usually the slowest method. Assumes that $n!$ is invertible; uses $O(n^4)$ scalar operations. If $\fl=2$, uses the Hessenberg form. Assumes that the base ring is a field. Uses $O(n^3)$ scalar operations, but suffers from coefficient explosion unless the base field is finite or $\R$. If $\fl=3$, uses Berkowitz's division free algorithm, valid over any ring (commutative, with unit). Uses $O(n^4)$ scalar operations. If $\fl=4$, $x$ must be integral. Uses a modular algorithm: Hessenberg form for various small primes, then Chinese remainders. If $\fl=5$ (default), uses the ``best'' method given $x$. This means we use Berkowitz unless the base ring is $\Z$ (use $\fl=4$) or a field where coefficient explosion does not occur, e.g.~a finite field or the reals (use $\fl=2$). Variant: Also available are \fun{GEN}{charpoly}{GEN x, long v} ($\fl=5$), \fun{GEN}{caract}{GEN A, long v} ($\fl=1$), \fun{GEN}{carhess}{GEN A, long v} ($\fl=2$), \fun{GEN}{carberkowitz}{GEN A, long v} ($\fl=3$) and \fun{GEN}{caradj}{GEN A, long v, GEN *pt}. In this last case, if \var{pt} is not \kbd{NULL}, \kbd{*pt} receives the address of the adjoint matrix of $A$ (see \tet{matadjoint}), so both can be obtained at once. pari-2.11.2/src/functions/linear_algebra/concat0000644000175000017500000000464713201017466020111 0ustar billbillFunction: concat Section: linear_algebra C-Name: gconcat Prototype: GDG Help: concat(x,{y}): concatenation of x and y, which can be scalars, vectors or matrices, or lists (in this last case, both x and y have to be lists). If y is omitted, x has to be a list or row vector and its elements are concatenated. Description: (mp,mp):vec gconcat($1, $2) (vec,mp):vec gconcat($1, $2) (mp,vec):vec gconcat($1, $2) (vec,vec):vec gconcat($1, $2) (list,list):list gconcat($1, $2) (genstr,gen):genstr gconcat($1, $2) (gen,genstr):genstr gconcat($1, $2) (gen):gen gconcat1($1) (gen,):gen gconcat1($1) (gen,gen):gen gconcat($1, $2) Doc: concatenation of $x$ and $y$. If $x$ or $y$ is not a vector or matrix, it is considered as a one-dimensional vector. All types are allowed for $x$ and $y$, but the sizes must be compatible. Note that matrices are concatenated horizontally, i.e.~the number of rows stays the same. Using transpositions, one can concatenate them vertically, but it is often simpler to use \tet{matconcat}. \bprog ? x = matid(2); y = 2*matid(2); ? concat(x,y) %2 = [1 0 2 0] [0 1 0 2] ? concat(x~,y~)~ %3 = [1 0] [0 1] [2 0] [0 2] ? matconcat([x;y]) %4 = [1 0] [0 1] [2 0] [0 2] @eprog\noindent To concatenate vectors sideways (i.e.~to obtain a two-row or two-column matrix), use \tet{Mat} instead, or \tet{matconcat}: \bprog ? x = [1,2]; ? y = [3,4]; ? concat(x,y) %3 = [1, 2, 3, 4] ? Mat([x,y]~) %4 = [1 2] [3 4] ? matconcat([x;y]) %5 = [1 2] [3 4] @eprog Concatenating a row vector to a matrix having the same number of columns will add the row to the matrix (top row if the vector is $x$, i.e.~comes first, and bottom row otherwise). The empty matrix \kbd{[;]} is considered to have a number of rows compatible with any operation, in particular concatenation. (Note that this is \emph{not} the case for empty vectors \kbd{[~]} or \kbd{[~]\til}.) If $y$ is omitted, $x$ has to be a row vector or a list, in which case its elements are concatenated, from left to right, using the above rules. \bprog ? concat([1,2], [3,4]) %1 = [1, 2, 3, 4] ? a = [[1,2]~, [3,4]~]; concat(a) %2 = [1 3] [2 4] ? concat([1,2; 3,4], [5,6]~) %3 = [1 2 5] [3 4 6] ? concat([%, [7,8]~, [1,2,3,4]]) %5 = [1 2 5 7] [3 4 6 8] [1 2 3 4] @eprog Variant: \fun{GEN}{gconcat1}{GEN x} is a shortcut for \kbd{gconcat(x,NULL)}. pari-2.11.2/src/functions/linear_algebra/qfbil0000644000175000017500000000031213201017466017720 0ustar billbillFunction: qfbil Section: linear_algebra C-Name: qfbil Prototype: GGDG Obsolete: 2016-08-08 Help: qfbil(x,y,{q}): this function is obsolete, use qfeval. Doc: this function is obsolete, use \kbd{qfeval}. pari-2.11.2/src/functions/linear_algebra/matindexrank0000644000175000017500000000107713326135265021327 0ustar billbillFunction: matindexrank Section: linear_algebra C-Name: indexrank Prototype: G Help: matindexrank(M): gives two extraction vectors (rows and columns) for the matrix M such that the extracted matrix is square of maximal rank. Doc: $M$ being a matrix of rank $r$, returns a vector with two \typ{VECSMALL} components $y$ and $z$ of length $r$ giving a list of rows and columns respectively (starting from 1) such that the extracted matrix obtained from these two vectors using $\tet{vecextract}(M,y,z)$ is invertible. The vectors $y$ and $z$ are sorted in increasing order. pari-2.11.2/src/functions/linear_algebra/matsolve0000644000175000017500000000303613326135265020471 0ustar billbillFunction: matsolve Section: linear_algebra C-Name: gauss Prototype: GG Help: matsolve(M,B): solution of MX=B (M matrix, B column vector or matrix). Doc: Let $M$ be a left-invertible matrix and $B$ a column vector such that there exists a solution $X$ to the system of linear equations $MX = B$; return the (unique) solution $X$. This has the same effect as, but is faster, than $M^{-1}*B$. Uses Dixon $p$-adic lifting method if $M$ and $B$ are integral and Gaussian elimination otherwise. When there is no solution, the function returns an $X$ such that $MX - B$ is non-zero although it has at least $\#M$ zero entries: \bprog ? M = [1,2;3,4;5,6]; ? B = [4,6,8]~; X = matsolve(M, B) %2 = [-2, 3]~ ? M*X == B %3 = 1 ? B = [1,2,4]~; X = matsolve(M, [1,2,4]~) %4 = [0, 1/2]~ ? M*X - B %5 = [0, 0, -1]~ @eprog\noindent Raises an exception if $M$ is not left-invertible, even if there is a solution: \bprog ? M = [1,1;1,1]; matsolve(M, [1,1]~) *** at top-level: matsolve(M,[1,1]~) *** ^------------------ *** matsolve: impossible inverse in gauss: [1, 1; 1, 1]. @eprog\noindent The function also works when $B$ is a matrix and we return the unique matrix solution $X$ provided it exists. Variant: For integral input, the function \fun{GEN}{ZM_gauss}{GEN M,GEN B} is also available. Function: _ZM_inv_worker C-Name: ZM_inv_worker Prototype: GG Section: programming/internals Help: worker for ZM_inv Function: _ZabM_inv_worker C-Name: ZabM_inv_worker Prototype: GGG Section: programming/internals Help: worker for ZabM_inv pari-2.11.2/src/functions/linear_algebra/vectorsmall0000644000175000017500000000100611636712103021157 0ustar billbillFunction: vectorsmall Section: linear_algebra C-Name: vecteursmall Prototype: GDVDE Help: vectorsmall(n,{X},{expr=0}): VECSMALL with n components of expression expr (X ranges from 1 to n) which must be small integers. By default, fill with 0s. Doc: creates a row vector of small integers (type \typ{VECSMALL}) with $n$ components whose components are the expression \var{expr} evaluated at the integer points between 1 and $n$. If one of the last two arguments is omitted, fill the vector with zeroes. %\syn{NO} pari-2.11.2/src/functions/linear_algebra/mathnf0000644000175000017500000000774013326135265020122 0ustar billbillFunction: mathnf Section: linear_algebra C-Name: mathnf0 Prototype: GD0,L, Help: mathnf(M,{flag=0}): (upper triangular) Hermite normal form of M, basis for the lattice formed by the columns of M. flag is optional whose value range from 0 to 3 have a binary meaning. Bit 1: complete output, returns a 2-component vector [H,U] such that H is the HNF of M, and U is an invertible matrix such that MU=H. Bit 2: allow polynomial entries, otherwise assume that M is integral. These use a naive algorithm; larger values correspond to more involved algorithms and are restricted to integer matrices; flag = 4: returns [H,U] using LLL reduction along the way; flag = 5: return [H,U,P] where P is a permutation of row indices such that P applied to M U is H. Doc: let $R$ be a Euclidean ring, equal to $\Z$ or to $K[X]$ for some field $K$. If $M$ is a (not necessarily square) matrix with entries in $R$, this routine finds the \emph{upper triangular} \idx{Hermite normal form} of $M$. If the rank of $M$ is equal to its number of rows, this is a square matrix. In general, the columns of the result form a basis of the $R$-module spanned by the columns of $M$. The values of $\fl$ are: \item 0 (default): only return the Hermite normal form $H$ \item 1 (complete output): return $[H,U]$, where $H$ is the Hermite normal form of $M$, and $U$ is a transformation matrix such that $MU=[0|H]$. The matrix $U$ belongs to $\text{GL}(R)$. When $M$ has a large kernel, the entries of $U$ are in general huge. \noindent For these two values, we use a naive algorithm, which behaves well in small dimension only. Larger values correspond to different algorithms, are restricted to \emph{integer} matrices, and all output the unimodular matrix $U$. From now on all matrices have integral entries. \item $\fl=4$, returns $[H,U]$ as in ``complete output'' above, using a variant of \idx{LLL} reduction along the way. The matrix $U$ is provably small in the $L_2$ sense, and often close to optimal; but the reduction is in general slow, although provably polynomial-time. If $\fl=5$, uses Batut's algorithm and output $[H,U,P]$, such that $H$ and $U$ are as before and $P$ is a permutation of the rows such that $P$ applied to $MU$ gives $H$. This is in general faster than $\fl=4$ but the matrix $U$ is usually worse; it is heuristically smaller than with the default algorithm. When the matrix is dense and the dimension is large (bigger than 100, say), $\fl = 4$ will be fastest. When $M$ has maximal rank, then \bprog H = mathnfmod(M, matdetint(M)) @eprog\noindent will be even faster. You can then recover $U$ as $M^{-1}H$. \bprog ? M = matrix(3,4,i,j,random([-5,5])) %1 = [ 0 2 3 0] [-5 3 -5 -5] [ 4 3 -5 4] ? [H,U] = mathnf(M, 1); ? U %3 = [-1 0 -1 0] [ 0 5 3 2] [ 0 3 1 1] [ 1 0 0 0] ? H %5 = [19 9 7] [ 0 9 1] [ 0 0 1] ? M*U %6 = [0 19 9 7] [0 0 9 1] [0 0 0 1] @eprog For convenience, $M$ is allowed to be a \typ{VEC}, which is then automatically converted to a \typ{MAT}, as per the \tet{Mat} function. For instance to solve the generalized extended gcd problem, one may use \bprog ? v = [116085838, 181081878, 314252913,10346840]; ? [H,U] = mathnf(v, 1); ? U %2 = [ 103 -603 15 -88] [-146 13 -1208 352] [ 58 220 678 -167] [-362 -144 381 -101] ? v*U %3 = [0, 0, 0, 1] @eprog\noindent This also allows to input a matrix as a \typ{VEC} of \typ{COL}s of the same length (which \kbd{Mat} would concatenate to the \typ{MAT} having those columns): \bprog ? v = [[1,0,4]~, [3,3,4]~, [0,-4,-5]~]; mathnf(v) %1 = [47 32 12] [ 0 1 0] [ 0 0 1] @eprog Variant: Also available are \fun{GEN}{hnf}{GEN M} ($\fl=0$) and \fun{GEN}{hnfall}{GEN M} ($\fl=1$). To reduce \emph{huge} relation matrices (sparse with small entries, say dimension $400$ or more), you can use the pair \kbd{hnfspec} / \kbd{hnfadd}. Since this is quite technical and the calling interface may change, they are not documented yet. Look at the code in \kbd{basemath/hnf\_snf.c}. pari-2.11.2/src/functions/linear_algebra/mathouseholder0000644000175000017500000000051712314242551021654 0ustar billbillFunction: mathouseholder Section: linear_algebra C-Name: mathouseholder Prototype: GG Help: mathouseholder(Q,v): applies a sequence Q of Householder transforms to the vector or matrix v. Doc: \sidx{Householder transform}applies a sequence $Q$ of Householder transforms, as returned by \kbd{matqr}$(M,1)$ to the vector or matrix $v$. pari-2.11.2/src/functions/linear_algebra/mathess0000644000175000017500000000036311636712103020275 0ustar billbillFunction: mathess Section: linear_algebra C-Name: hess Prototype: G Help: mathess(x): Hessenberg form of x. Doc: returns a matrix similar to the square matrix $x$, which is in upper Hessenberg form (zero entries below the first subdiagonal). pari-2.11.2/src/functions/linear_algebra/matqr0000644000175000017500000000167013201017466017757 0ustar billbillFunction: matqr Section: linear_algebra C-Name: matqr Prototype: GD0,L,p Help: matqr(M,{flag=0}): returns [Q,R], the QR-decomposition of the square invertible matrix M. If flag=1, Q is given as a sequence of Householder transforms (faster and stabler). Doc: returns $[Q,R]$, the \idx{QR-decomposition} of the square invertible matrix $M$ with real entries: $Q$ is orthogonal and $R$ upper triangular. If $\fl=1$, the orthogonal matrix is returned as a sequence of Householder transforms: applying such a sequence is stabler and faster than multiplication by the corresponding $Q$ matrix.\sidx{Householder transform} More precisely, if \bprog [Q,R] = matqr(M); [q,r] = matqr(M, 1); @eprog\noindent then $r = R$ and \kbd{mathouseholder}$(q, M)$ is (close to) $R$; furthermore \bprog mathouseholder(q, matid(#M)) == Q~ @eprog\noindent the inverse of $Q$. This function raises an error if the precision is too low or $x$ is singular. pari-2.11.2/src/functions/linear_algebra/matconcat0000644000175000017500000000406413201017466020604 0ustar billbillFunction: matconcat Section: linear_algebra C-Name: matconcat Prototype: G Help: matconcat(v): concatenate the entries of v and return the resulting matrix. Doc: returns a \typ{MAT} built from the entries of $v$, which may be a \typ{VEC} (concatenate horizontally), a \typ{COL} (concatenate vertically), or a \typ{MAT} (concatenate vertically each column, and concatenate vertically the resulting matrices). The entries of $v$ are always considered as matrices: they can themselves be \typ{VEC} (seen as a row matrix), a \typ{COL} seen as a column matrix), a \typ{MAT}, or a scalar (seen as an $1 \times 1$ matrix). \bprog ? A=[1,2;3,4]; B=[5,6]~; C=[7,8]; D=9; ? matconcat([A, B]) \\ horizontal %1 = [1 2 5] [3 4 6] ? matconcat([A, C]~) \\ vertical %2 = [1 2] [3 4] [7 8] ? matconcat([A, B; C, D]) \\ block matrix %3 = [1 2 5] [3 4 6] [7 8 9] @eprog\noindent If the dimensions of the entries to concatenate do not match up, the above rules are extended as follows: \item each entry $v_{i,j}$ of $v$ has a natural length and height: $1 \times 1$ for a scalar, $1 \times n$ for a \typ{VEC} of length $n$, $n \times 1$ for a \typ{COL}, $m \times n$ for an $m\times n$ \typ{MAT} \item let $H_i$ be the maximum over $j$ of the lengths of the $v_{i,j}$, let $L_j$ be the maximum over $i$ of the heights of the $v_{i,j}$. The dimensions of the $(i,j)$-th block in the concatenated matrix are $H_i \times L_j$. \item a scalar $s = v_{i,j}$ is considered as $s$ times an identity matrix of the block dimension $\min (H_i,L_j)$ \item blocks are extended by 0 columns on the right and 0 rows at the bottom, as needed. \bprog ? matconcat([1, [2,3]~, [4,5,6]~]) \\ horizontal %4 = [1 2 4] [0 3 5] [0 0 6] ? matconcat([1, [2,3], [4,5,6]]~) \\ vertical %5 = [1 0 0] [2 3 0] [4 5 6] ? matconcat([B, C; A, D]) \\ block matrix %6 = [5 0 7 8] [6 0 0 0] [1 2 9 0] [3 4 0 9] ? U=[1,2;3,4]; V=[1,2,3;4,5,6;7,8,9]; ? matconcat(matdiagonal([U, V])) \\ block diagonal %7 = [1 2 0 0 0] [3 4 0 0 0] [0 0 1 2 3] [0 0 4 5 6] [0 0 7 8 9] @eprog pari-2.11.2/src/functions/linear_algebra/qfautoexport0000644000175000017500000000141713036414402021370 0ustar billbillFunction: qfautoexport Section: linear_algebra C-Name: qfautoexport Prototype: GD0,L, Help: qfautoexport(qfa,{flag}): qfa being an automorphism group as output by qfauto, output a string representing the underlying matrix group in GAP notation (default) or Magma notation (flag = 1). Doc: \var{qfa} being an automorphism group as output by \tet{qfauto}, export the underlying matrix group as a string suitable for (no flags or $\fl=0$) GAP or ($\fl=1$) Magma. The following example computes the size of the matrix group using GAP: \bprog ? G = qfauto([2,1;1,2]) %1 = [12, [[-1, 0; 0, -1], [0, -1; 1, 1], [1, 1; 0, -1]]] ? s = qfautoexport(G) %2 = "Group([[-1, 0], [0, -1]], [[0, -1], [1, 1]], [[1, 1], [0, -1]])" ? extern("echo \"Order("s");\" | gap -q") %3 = 12 @eprog pari-2.11.2/src/functions/linear_algebra/setisset0000644000175000017500000000107613201017466020476 0ustar billbillFunction: setisset Section: linear_algebra C-Name: setisset Prototype: lG Help: setisset(x): true(1) if x is a set (row vector with strictly increasing entries), false(0) if not. Doc: returns true (1) if $x$ is a set, false (0) if not. In PARI, a set is a row vector whose entries are strictly increasing with respect to a (somewhat arbitrary) universal comparison function. To convert any object into a set (this is most useful for vectors, of course), use the function \kbd{Set}. \bprog ? a = [3, 1, 1, 2]; ? setisset(a) %2 = 0 ? Set(a) %3 = [1, 2, 3] @eprog pari-2.11.2/src/functions/linear_algebra/matimagemod0000644000175000017500000000176513326135265021132 0ustar billbillFunction: matimagemod Section: linear_algebra C-Name: matimagemod Prototype: GGD& Help: matimagemod(x,d,&U): basis of the image of the matrix x modulo d. Doc: gives a Howell basis (unique representation for submodules of~$(\Z/d\Z)^n$) for the image of the matrix $x$ modulo $d$ as columns of a matrix $H$. The matrix $x$ must have \typ{INT} entries, and $d$ can be an arbitrary positive integer. If $U$ is present, set it to a matrix such that~$AU = H$. \bprog ? A = [2,1;0,2]; ? matimagemod(A,6,&U) %2 = [1 0] [0 2] ? U %3 = [5 1] [3 4] ? (A*U)%6 %4 = [1 0] [0 2] @eprog \misctitle{Caveat} In general the number of columns of the Howell form is not the minimal number of generators of the submodule. Example: \bprog ? matimagemod([1;2],4) %5 = [2 1] [0 2] @eprog \misctitle{Caveat 2} In general the matrix $U$ is not invertible, even if~$A$ and~$H$ have the same size. Example: \bprog ? matimagemod([4,1;0,4],8,&U) %6 = [2 1] [0 4] ? U %7 = [0 0] [2 1] @eprog pari-2.11.2/src/functions/linear_algebra/matmultodiagonal0000644000175000017500000000066011636712103022172 0ustar billbillFunction: matmultodiagonal Section: linear_algebra C-Name: matmultodiagonal Prototype: GG Help: matmultodiagonal(x,y): product of matrices x and y, knowing that the result will be a diagonal matrix. Much faster than general multiplication in that case. Doc: product of the matrices $x$ and $y$ assuming that the result is a diagonal matrix. Much faster than $x*y$ in that case. The result is undefined if $x*y$ is not diagonal. pari-2.11.2/src/functions/linear_algebra/matinvmod0000644000175000017500000000110413326135265020627 0ustar billbillFunction: matinvmod Section: linear_algebra C-Name: matinvmod Prototype: GG Help: matinvmod(x,d): left inverse of the matrix x modulo d. Doc: computes a left inverse of the matrix~$x$ modulo~$d$. The matrix $x$ must have \typ{INT} entries, and $d$ can be an arbitrary positive integer. \bprog ? A = [3,1,2;1,2,1;3,1,1]; ? U = matinvmod(A,6) %2 = [1 1 3] [2 3 5] [1 0 5] ? (U*A)%6 %3 = [1 0 0] [0 1 0] [0 0 1] ? matinvmod(A,5) *** at top-level: matinvmod(A,5) *** ^-------------- *** matinvmod: impossible inverse in gen_inv: 0. @eprog pari-2.11.2/src/functions/linear_algebra/qfrep0000644000175000017500000000212612314242551017744 0ustar billbillFunction: qfrep Section: linear_algebra C-Name: qfrep0 Prototype: GGD0,L, Help: qfrep(q,B,{flag=0}): vector of (half) the number of vectors of norms from 1 to B for the integral and definite quadratic form q. If flag is 1, count vectors of even norm from 1 to 2B. Doc: $q$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, count the vectors representing successive integers. \item If $\fl = 0$, count all vectors. Outputs the vector whose $i$-th entry, $1 \leq i \leq B$ is half the number of vectors $v$ such that $q(v)=i$. \item If $\fl = 1$, count vectors of even norm. Outputs the vector whose $i$-th entry, $1 \leq i \leq B$ is half the number of vectors such that $q(v) = 2i$. \bprog ? q = [2, 1; 1, 3]; ? qfrep(q, 5) %2 = Vecsmall([0, 1, 2, 0, 0]) \\ 1 vector of norm 2, 2 of norm 3, etc. ? qfrep(q, 5, 1) %3 = Vecsmall([1, 0, 0, 1, 0]) \\ 1 vector of norm 2, 0 of norm 4, etc. @eprog\noindent This routine uses a naive algorithm based on \tet{qfminim}, and will fail if any entry becomes larger than $2^{31}$ (or $2^{63}$). pari-2.11.2/src/functions/linear_algebra/qforbits0000644000175000017500000000146413201017466020465 0ustar billbillFunction: qforbits Section: linear_algebra C-Name: qforbits Prototype: GG Help: qforbits(G,V): return the orbits of V under the action of the group of linear transformation generated by the set G, which must stabilize V. Doc: return the orbits of $V$ under the action of the group of linear transformation generated by the set $G$. It is assumed that $G$ contains minus identity, and only one vector in $\{v, -v\}$ should be given. If $G$ does not stabilize $V$, the function return $0$. In the example below, we compute representatives and lengths of the orbits of the vectors of norm $\leq 3$ under the automorphisms of the lattice $A_1^6$. \bprog ? Q=matid(6); G=qfauto(Q); V=qfminim(Q,3); ? apply(x->[x[1],#x],qforbits(G,V)) %2 = [[[0,0,0,0,0,1]~,6],[[0,0,0,0,1,-1]~,30],[[0,0,0,1,-1,-1]~,80]] @eprog pari-2.11.2/src/functions/linear_algebra/matinverseimage0000644000175000017500000000146411636712103022014 0ustar billbillFunction: matinverseimage Section: linear_algebra C-Name: inverseimage Prototype: GG Help: matinverseimage(x,y): an element of the inverse image of the vector y by the matrix x if one exists, the empty vector otherwise. Doc: given a matrix $x$ and a column vector or matrix $y$, returns a preimage $z$ of $y$ by $x$ if one exists (i.e such that $x z = y$), an empty vector or matrix otherwise. The complete inverse image is $z + \text{Ker} x$, where a basis of the kernel of $x$ may be obtained by \kbd{matker}. \bprog ? M = [1,2;2,4]; ? matinverseimage(M, [1,2]~) %2 = [1, 0]~ ? matinverseimage(M, [3,4]~) %3 = []~ \\@com no solution ? matinverseimage(M, [1,3,6;2,6,12]) %4 = [1 3 6] [0 0 0] ? matinverseimage(M, [1,2;3,4]) %5 = [;] \\@com no solution ? K = matker(M) %6 = [-2] [1] @eprog pari-2.11.2/src/functions/linear_algebra/matrank0000644000175000017500000000021211636712103020257 0ustar billbillFunction: matrank Section: linear_algebra C-Name: rank Prototype: lG Help: matrank(x): rank of the matrix x. Doc: rank of the matrix $x$. pari-2.11.2/src/functions/linear_algebra/mathnfmodid0000644000175000017500000000117513201017466021125 0ustar billbillFunction: mathnfmodid Section: linear_algebra C-Name: hnfmodid Prototype: GG Help: mathnfmodid(x,d): (upper triangular) Hermite normal form of x concatenated with matdiagonal(d). Doc: outputs the (upper triangular) \idx{Hermite normal form} of $x$ concatenated with the diagonal matrix with diagonal $d$. Assumes that $x$ has integer entries. Variant: if $d$ is an integer instead of a vector, concatenate $d$ times the identity matrix. \bprog ? m=[0,7;-1,0;-1,-1] %1 = [ 0 7] [-1 0] [-1 -1] ? mathnfmodid(m, [6,2,2]) %2 = [2 1 1] [0 1 0] [0 0 1] ? mathnfmodid(m, 10) %3 = [10 7 3] [ 0 1 0] [ 0 0 1] @eprog pari-2.11.2/src/functions/linear_algebra/matimagecompl0000644000175000017500000000104712314242551021447 0ustar billbillFunction: matimagecompl Section: linear_algebra C-Name: imagecompl Prototype: G Description: (gen):vecsmall imagecompl($1) Help: matimagecompl(x): vector of column indices not corresponding to the indices given by the function matimage. Doc: gives the vector of the column indices which are not extracted by the function \kbd{matimage}, as a permutation (\typ{VECSMALL}). Hence the number of components of \kbd{matimagecompl(x)} plus the number of columns of \kbd{matimage(x)} is equal to the number of columns of the matrix $x$. pari-2.11.2/src/functions/linear_algebra/matsolvemod0000644000175000017500000000262613326135265021175 0ustar billbillFunction: matsolvemod Section: linear_algebra C-Name: matsolvemod Prototype: GGGD0,L, Help: matsolvemod(M,D,B,{flag=0}): one solution of system of congruences MX=B mod D (M matrix, B and D column vectors). If (optional) flag is non-null return all solutions. Doc: $M$ being any integral matrix, $D$ a column vector of non-negative integer moduli, and $B$ an integral column vector, gives an integer solution to the system of congruences $\sum_i m_{i,j}x_j\equiv b_i\pmod{d_i}$ if one exists, otherwise returns zero. Shorthand notation: $B$ (resp.~$D$) can be given as a single integer, in which case all the $b_i$ (resp.~$d_i$) above are taken to be equal to $B$ (resp.~$D$). \bprog ? M = [1,2;3,4]; ? matsolvemod(M, [3,4]~, [1,2]~) %2 = [10, 0]~ ? matsolvemod(M, 3, 1) \\ M X = [1,1]~ over F_3 %3 = [2, 1]~ ? matsolvemod(M, [3,0]~, [1,2]~) \\ x + 2y = 1 (mod 3), 3x + 4y = 2 (in Z) %4 = [6, -4]~ @eprog If $\fl=1$, all solutions are returned in the form of a two-component row vector $[x,u]$, where $x$ is an integer solution to the system of congruences and $u$ is a matrix whose columns give a basis of the homogeneous system (so that all solutions can be obtained by adding $x$ to any linear combination of columns of $u$). If no solution exists, returns zero. Variant: Also available are \fun{GEN}{gaussmodulo}{GEN M, GEN D, GEN B} ($\fl=0$) and \fun{GEN}{gaussmodulo2}{GEN M, GEN D, GEN B} ($\fl=1$). pari-2.11.2/src/functions/linear_algebra/matkerint0000644000175000017500000000106113201017466020623 0ustar billbillFunction: matkerint Section: linear_algebra C-Name: matkerint0 Prototype: GD0,L, Help: matkerint(x,{flag=0}): LLL-reduced Z-basis of the kernel of the matrix x with integral entries. flag is deprecated, and may be set to 0 or 1 for backward compatibility. Doc: gives an \idx{LLL}-reduced $\Z$-basis for the lattice equal to the kernel of the matrix $x$ with rational entries. \fl is deprecated, kept for backward compatibility. Variant: Use directly \fun{GEN}{kerint}{GEN x} if $x$ is known to have integer entries, and \tet{Q_primpart} first otherwise. pari-2.11.2/src/functions/linear_algebra/algdep0000644000175000017500000000526513201017466020073 0ustar billbillFunction: algdep Section: linear_algebra C-Name: algdep0 Prototype: GLD0,L, Help: algdep(z,k,{flag=0}): algebraic relations up to degree n of z, using lindep([1,z,...,z^(k-1)], flag). Doc: \sidx{algebraic dependence} $z$ being real/complex, or $p$-adic, finds a polynomial (in the variable \kbd{'x}) of degree at most $k$, with integer coefficients, having $z$ as approximate root. Note that the polynomial which is obtained is not necessarily the ``correct'' one. In fact it is not even guaranteed to be irreducible. One can check the closeness either by a polynomial evaluation (use \tet{subst}), or by computing the roots of the polynomial given by \kbd{algdep} (use \tet{polroots} or \tet{polrootspadic}). Internally, \tet{lindep}$([1,z,\ldots,z^k], \fl)$ is used. A non-zero value of $\fl$ may improve on the default behavior if the input number is known to a \emph{huge} accuracy, and you suspect the last bits are incorrect: if $\fl > 0$ the computation is done with an accuracy of $\fl$ decimal digits; to get meaningful results, the parameter $\fl$ should be smaller than the number of correct decimal digits in the input. But default values are usually sufficient, so try without $\fl$ first: \bprog ? \p200 ? z = 2^(1/6)+3^(1/5); ? algdep(z, 30); \\ right in 280ms ? algdep(z, 30, 100); \\ wrong in 169ms ? algdep(z, 30, 170); \\ right in 288ms ? algdep(z, 30, 200); \\ wrong in 320ms ? \p250 ? z = 2^(1/6)+3^(1/5); \\ recompute to new, higher, accuracy ! ? algdep(z, 30); \\ right in 329ms ? algdep(z, 30, 200); \\ right in 324ms ? \p500 ? algdep(2^(1/6)+3^(1/5), 30); \\ right in 677ms ? \p1000 ? algdep(2^(1/6)+3^(1/5), 30); \\ right in 1.5s @eprog\noindent The changes in \kbd{realprecision} only affect the quality of the initial approximation to $2^{1/6} + 3^{1/5}$, \kbd{algdep} itself uses exact operations. The size of its operands depend on the accuracy of the input of course: more accurate input means slower operations. Proceeding by increments of 5 digits of accuracy, \kbd{algdep} with default flag produces its first correct result at 195 digits, and from then on a steady stream of correct results: \bprog \\ assume T contains the correct result, for comparison forstep(d=100, 250, 5, localprec(d);\ print(d, " ", algdep(2^(1/6)+3^(1/5),30) == T)) @eprog The above example is the test case studied in a 2000 paper by Borwein and Lisonek: Applications of integer relation algorithms, \emph{Discrete Math.}, {\bf 217}, p.~65--82. The version of PARI tested there was 1.39, which succeeded reliably from precision 265 on, in about 200 as much time as the current version. Variant: Also available is \fun{GEN}{algdep}{GEN z, long k} ($\fl=0$). pari-2.11.2/src/functions/linear_algebra/matsupplement0000644000175000017500000000154212314242551021526 0ustar billbillFunction: matsupplement Section: linear_algebra C-Name: suppl Prototype: G Help: matsupplement(x): supplement the columns of the matrix x to an invertible matrix. Doc: assuming that the columns of the matrix $x$ are linearly independent (if they are not, an error message is issued), finds a square invertible matrix whose first columns are the columns of $x$, i.e.~supplement the columns of $x$ to a basis of the whole space. \bprog ? matsupplement([1;2]) %1 = [1 0] [2 1] @eprog Raises an error if $x$ has 0 columns, since (due to a long standing design bug), the dimension of the ambient space (the number of rows) is unknown in this case: \bprog ? matsupplement(matrix(2,0)) *** at top-level: matsupplement(matrix *** ^-------------------- *** matsupplement: sorry, suppl [empty matrix] is not yet implemented. @eprog pari-2.11.2/src/functions/linear_algebra/matdiagonal0000644000175000017500000000112212314242551021102 0ustar billbillFunction: matdiagonal Section: linear_algebra C-Name: diagonal Prototype: G Help: matdiagonal(x): creates the diagonal matrix whose diagonal entries are the entries of the vector x. Doc: $x$ being a vector, creates the diagonal matrix whose diagonal entries are those of $x$. \bprog ? matdiagonal([1,2,3]); %1 = [1 0 0] [0 2 0] [0 0 3] @eprog\noindent Block diagonal matrices are easily created using \tet{matconcat}: \bprog ? U=[1,2;3,4]; V=[1,2,3;4,5,6;7,8,9]; ? matconcat(matdiagonal([U, V])) %1 = [1 2 0 0 0] [3 4 0 0 0] [0 0 1 2 3] [0 0 4 5 6] [0 0 7 8 9] @eprog pari-2.11.2/src/functions/linear_algebra/matsnf0000644000175000017500000000304611636712103020122 0ustar billbillFunction: matsnf Section: linear_algebra C-Name: matsnf0 Prototype: GD0,L, Help: matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of the matrix X, expressed as a vector d. Binary digits of flag mean 1: returns [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned, 2: allow polynomial entries, otherwise assume X is integral, 4: removes all information corresponding to entries equal to 1 in d. Doc: if $X$ is a (singular or non-singular) matrix outputs the vector of \idx{elementary divisors} of $X$, i.e.~the diagonal of the \idx{Smith normal form} of $X$, normalized so that $d_n \mid d_{n-1} \mid \ldots \mid d_1$. The binary digits of \fl\ mean: 1 (complete output): if set, outputs $[U,V,D]$, where $U$ and $V$ are two unimodular matrices such that $UXV$ is the diagonal matrix $D$. Otherwise output only the diagonal of $D$. If $X$ is not a square matrix, then $D$ will be a square diagonal matrix padded with zeros on the left or the top. 2 (generic input): if set, allows polynomial entries, in which case the input matrix must be square. Otherwise, assume that $X$ has integer coefficients with arbitrary shape. 4 (cleanup): if set, cleans up the output. This means that elementary divisors equal to $1$ will be deleted, i.e.~outputs a shortened vector $D'$ instead of $D$. If complete output was required, returns $[U',V',D']$ so that $U'XV' = D'$ holds. If this flag is set, $X$ is allowed to be of the form `vector of elementary divisors' or $[U,V,D]$ as would normally be output with the cleanup flag unset. pari-2.11.2/src/functions/linear_algebra/matrix0000644000175000017500000000126113326135265020141 0ustar billbillFunction: matrix Section: linear_algebra C-Name: matrice Prototype: GDGDVDVDE Help: matrix(m,{n=m},{X},{Y},{expr=0}): m x n matrix of expression expr, where the row variable X goes from 1 to m and the column variable Y goes from 1 to n. By default, fill with 0s. Doc: creation of the $m\times n$ matrix whose coefficients are given by the expression \var{expr}. There are two formal parameters in \var{expr}, the first one ($X$) corresponding to the rows, the second ($Y$) to the columns, and $X$ goes from 1 to $m$, $Y$ goes from 1 to $n$. If one of the last 3 parameters is omitted, fill the matrix with zeroes. If $n$ is omitted, return a square $m \times m$ matrix. %\syn{NO} pari-2.11.2/src/functions/linear_algebra/vecextract0000644000175000017500000000541012314242551020776 0ustar billbillFunction: vecextract Section: linear_algebra C-Name: extract0 Prototype: GGDG Description: (vec,gen,?gen):vec extract0($1, $2, $3) Help: vecextract(x,y,{z}): extraction of the components of the matrix or vector x according to y and z. If z is omitted, y represents columns, otherwise y corresponds to rows and z to columns. y and z can be vectors (of indices), strings (indicating ranges as in "1..10") or masks (integers whose binary representation indicates the indices to extract, from left to right 1, 2, 4, 8, etc.). Doc: extraction of components of the vector or matrix $x$ according to $y$. In case $x$ is a matrix, its components are the \emph{columns} of $x$. The parameter $y$ is a component specifier, which is either an integer, a string describing a range, or a vector. If $y$ is an integer, it is considered as a mask: the binary bits of $y$ are read from right to left, but correspond to taking the components from left to right. For example, if $y=13=(1101)_2$ then the components 1,3 and 4 are extracted. If $y$ is a vector (\typ{VEC}, \typ{COL} or \typ{VECSMALL}), which must have integer entries, these entries correspond to the component numbers to be extracted, in the order specified. If $y$ is a string, it can be \item a single (non-zero) index giving a component number (a negative index means we start counting from the end). \item a range of the form \kbd{"$a$..$b$"}, where $a$ and $b$ are indexes as above. Any of $a$ and $b$ can be omitted; in this case, we take as default values $a = 1$ and $b = -1$, i.e.~ the first and last components respectively. We then extract all components in the interval $[a,b]$, in reverse order if $b < a$. In addition, if the first character in the string is \kbd{\pow}, the complement of the given set of indices is taken. If $z$ is not omitted, $x$ must be a matrix. $y$ is then the \emph{row} specifier, and $z$ the \emph{column} specifier, where the component specifier is as explained above. \bprog ? v = [a, b, c, d, e]; ? vecextract(v, 5) \\@com mask %1 = [a, c] ? vecextract(v, [4, 2, 1]) \\@com component list %2 = [d, b, a] ? vecextract(v, "2..4") \\@com interval %3 = [b, c, d] ? vecextract(v, "-1..-3") \\@com interval + reverse order %4 = [e, d, c] ? vecextract(v, "^2") \\@com complement %5 = [a, c, d, e] ? vecextract(matid(3), "2..", "..") %6 = [0 1 0] [0 0 1] @eprog The range notations \kbd{v[i..j]} and \kbd{v[\pow i]} (for \typ{VEC} or \typ{COL}) and \kbd{M[i..j, k..l]} and friends (for \typ{MAT}) implement a subset of the above, in a simpler and \emph{faster} way, hence should be preferred in most common situations. The following features are not implemented in the range notation: \item reverse order, \item omitting either $a$ or $b$ in \kbd{$a$..$b$}. pari-2.11.2/src/functions/linear_algebra/qfnorm0000644000175000017500000000031213201017466020125 0ustar billbillFunction: qfnorm Section: linear_algebra C-Name: qfnorm Prototype: GDG Obsolete: 2016-08-08 Help: qfnorm(x,{q}): this function is obsolete, use qfeval. Doc: this function is obsolete, use \kbd{qfeval}. pari-2.11.2/src/functions/linear_algebra/setbinop0000644000175000017500000000117212314242551020452 0ustar billbillFunction: setbinop Section: linear_algebra C-Name: setbinop Prototype: GGDG Help: setbinop(f,X,{Y}): the set {f(x,y), x in X, y in Y}. If Y is omitted, assume that X = Y and that f is symmetric. Doc: the set whose elements are the f(x,y), where x,y run through X,Y. respectively. If $Y$ is omitted, assume that $X = Y$ and that $f$ is symmetric: $f(x,y) = f(y,x)$ for all $x,y$ in $X$. \bprog ? X = [1,2,3]; Y = [2,3,4]; ? setbinop((x,y)->x+y, X,Y) \\ set X + Y %2 = [3, 4, 5, 6, 7] ? setbinop((x,y)->x-y, X,Y) \\ set X - Y %3 = [-3, -2, -1, 0, 1] ? setbinop((x,y)->x+y, X) \\ set 2X = X + X %2 = [2, 3, 4, 5, 6] @eprog pari-2.11.2/src/functions/linear_algebra/mateigen0000644000175000017500000000262313036414402020420 0ustar billbillFunction: mateigen Section: linear_algebra C-Name: mateigen Prototype: GD0,L,p Help: mateigen(x,{flag=0}): complex eigenvectors of the matrix x given as columns of a matrix H. If flag=1, return [L,H], where L contains the eigenvalues and H the corresponding eigenvectors. Doc: returns the (complex) eigenvectors of $x$ as columns of a matrix. If $\fl=1$, return $[L,H]$, where $L$ contains the eigenvalues and $H$ the corresponding eigenvectors; multiple eigenvalues are repeated according to the eigenspace dimension (which may be less than the eigenvalue multiplicity in the characteristic polynomial). This function first computes the characteristic polynomial of $x$ and approximates its complex roots $(\lambda_i)$, then tries to compute the eigenspaces as kernels of the $x - \lambda_i$. This algorithm is ill-conditioned and is likely to miss kernel vectors if some roots of the characteristic polynomial are close, in particular if it has multiple roots. \bprog ? A = [13,2; 10,14]; mateigen(A) %1 = [-1/2 2/5] [ 1 1] ? [L,H] = mateigen(A, 1); ? L %3 = [9, 18] ? H %4 = [-1/2 2/5] [ 1 1] @eprog\noindent For symmetric matrices, use \tet{qfjacobi} instead; for Hermitian matrices, compute \bprog A = real(x); B = imag(x); y = matconcat([A, -B; B, A]); @eprog\noindent and apply \kbd{qfjacobi} to $y$. Variant: Also available is \fun{GEN}{eigen}{GEN x, long prec} ($\fl = 0$) pari-2.11.2/src/functions/linear_algebra/matdetint0000644000175000017500000000202412314242551020615 0ustar billbillFunction: matdetint Section: linear_algebra C-Name: detint Prototype: G Help: matdetint(B): some multiple of the determinant of the lattice generated by the columns of B (0 if not of maximal rank). Useful with mathnfmod. Doc: Let $B$ be an $m\times n$ matrix with integer coefficients. The \emph{determinant} $D$ of the lattice generated by the columns of $B$ is the square root of $\det(B^T B)$ if $B$ has maximal rank $m$, and $0$ otherwise. This function uses the Gauss-Bareiss algorithm to compute a positive \emph{multiple} of $D$. When $B$ is square, the function actually returns $D = |\det B|$. This function is useful in conjunction with \kbd{mathnfmod}, which needs to know such a multiple. If the rank is maximal and the matrix non-square, you can obtain $D$ exactly using \bprog matdet( mathnfmod(B, matdetint(B)) ) @eprog\noindent Note that as soon as one of the dimensions gets large ($m$ or $n$ is larger than 20, say), it will often be much faster to use \kbd{mathnf(B, 1)} or \kbd{mathnf(B, 4)} directly. pari-2.11.2/src/functions/linear_algebra/qfisominit0000644000175000017500000000246413201017466021017 0ustar billbillFunction: qfisominit Section: linear_algebra C-Name: qfisominit0 Prototype: GDGDG Help: qfisominit(G,{fl},{m}): G being a square and symmetric matrix representing an integral positive definite quadratic form, this function returns a structure allowing to compute isomorphisms between G and other quadratic form faster. Doc: $G$ being a square and symmetric matrix with integer entries representing a positive definite quadratic form, return an \kbd{isom} structure allowing to compute isomorphisms between $G$ and other quadratic forms faster. The interface of this function is experimental and will likely change in future release. If present, the optional parameter \var{fl} must be a \typ{VEC} with two components. It allows to specify the invariants used, which can make the computation faster or slower. The components are \item \kbd{fl[1]} Depth of scalar product combination to use. \item \kbd{fl[2]} Maximum level of Bacher polynomials to use. If present, $m$ must be the set of vectors of norm up to the maximal of the diagonal entry of $G$, either as a matrix or as given by \kbd{qfminim}. Otherwise this function computes the minimal vectors so it become very lengthy as the dimension of $G$ grows. Variant: Also available is \fun{GEN}{qfisominit}{GEN F, GEN fl} where $F$ is a vector of \kbd{zm}. pari-2.11.2/src/functions/linear_algebra/matpermanent0000644000175000017500000000073613326135265021336 0ustar billbillFunction: matpermanent Section: linear_algebra C-Name: matpermanent Prototype: G Help: matpermanent(x): permanent of the matrix x. Doc: permanent of the square matrix $x$ using Ryser's formula in Gray code order. \bprog ? n = 20; m = matrix(n,n,i,j, i!=j); ? matpermanent(m) %2 = 895014631192902121 ? n! * sum(i=0,n, (-1)^i/i!) %3 = 895014631192902121 @eprog\noindent This function runs in time $O(2^n n)$ for a matrix of size $n$ and is not implemented for $n$ large. pari-2.11.2/src/functions/linear_algebra/forqfvec0000644000175000017500000000165413201017466020450 0ustar billbillFunction: forqfvec Section: linear_algebra C-Name: forqfvec0 Prototype: vVGDGI Help:forqfvec(v,q,b,expr): q being a square and symmetric integral matrix representing an positive definite quadratic form, evaluate expr for all vectors v such that q(v)<=b. Doc: $q$ being a square and symmetric integral matrix representing a positive definite quadratic form, evaluate \kbd{expr} for all vector $v$ such that $q(v)\leq b$. The formal variable $v$ runs through all such vectors in turn. \bprog ? forqfvec(v, [3,2;2,3], 3, print(v)) [0, 1]~ [1, 0]~ [-1, 1]~ @eprog Variant: The following function is also available: \fun{void}{forqfvec}{void *E, long (*fun)(void *, GEN, GEN, double), GEN q, GEN b}: Evaluate \kbd{fun(E,w,v,m)} on all $v$ such that $q(v)= 1 %1 = 15 ? lfunthetacost(L, 1 + I); \\ cost for theta(1+I). Domain error ! *** at top-level: lfunthetacost(1,1+I) *** ^-------------------- *** lfunthetacost: domain error in lfunthetaneed: arg t > 0.785 ? lfunthetacost(L, 1 + I/2) \\ for theta(1+I/2). %2 = 23 ? lfunthetacost(L, 1 + I/2, 10) \\ for theta^((10))(1+I/2). %3 = 24 ? lfunthetacost(L, [2, 1/10]) \\ cost for theta(t), |t| >= 2, |arg(t)| < 1/10 %4 = 8 ? L = lfuncreate( ellinit([1,1]) ); ? lfunthetacost(L) \\ for t >= 1 %6 = 2471 @eprog pari-2.11.2/src/functions/l_functions/lfunetaquo0000644000175000017500000000147213326135265020420 0ustar billbillFunction: lfunetaquo Section: l_functions C-Name: lfunetaquo Prototype: G Help: lfunetaquo(M): returns the Ldata structure attached to the modular form z->prod(i=1,#M[,1],eta(M[i,1]*z)^M[i,2]). Doc: returns the \kbd{Ldata} structure attached to the $L$ function attached to the modular form $z\mapsto \prod_{i=1}^n \eta(M_{i,1}\*z)^{M_{i,2}}$ It is currently assumed that $f$ is a self-dual cuspidal form on $\Gamma_0(N)$ for some $N$. For instance, the $L$-function $\sum \tau(n) n^{-s}$ attached to Ramanujan's $\Delta$ function is encoded as follows \bprog ? L = lfunetaquo(Mat([1,24])); ? lfunan(L, 100) \\ first 100 values of tau(n) @eprog\noindent For convenience, a \typ{VEC} is also accepted instead of a factorization matrix with a single row: \bprog ? L = lfunetaquo([1,24]); \\ same as above @eprog pari-2.11.2/src/functions/l_functions/HEADER0000644000175000017500000003351513326135265017170 0ustar billbillFunction: _header_l_functions Class: header Section: l_functions Doc: \section{$L$-functions} This section describes routines related to $L$-functions. We first introduce the basic concept and notations, then explain how to represent them in GP. Let $\Gamma_{\R}(s) = \pi^{-s/2}\Gamma(s/2)$, where $\Gamma$ is Euler's gamma function. Given $d \geq 1$ and a $d$-tuple $A=[\alpha_1,\dots,\alpha_d]$ of complex numbers, we let $\gamma_A(s) = \prod_{\alpha \in A} \Gamma_{\R}(s + \alpha)$. Given a sequence $a = (a_n)_{n\geq 1}$ of complex numbers (such that $a_1 = 1$), a positive \emph{conductor} $N \in \Z$, and a \emph{gamma factor} $\gamma_A$ as above, we consider the Dirichlet series $$ L(a,s) = \sum_{n\geq 1} a_n n^{-s} $$ and the attached completed function $$ \Lambda(a,s) = N^{s/2}\gamma_A(s) \cdot L(a,s). $$ Such a datum defines an \emph{$L$-function} if it satisfies the three following assumptions: \item [Convergence] The $a_n = O_\epsilon(n^{k_1+\epsilon})$ have polynomial growth, equivalently $L(s)$ converges absolutely in some right half-plane $\Re(s) > k_1 + 1$. \item [Analytic continuation] $L(s)$ has a meromorphic continuation to the whole complex plane with finitely many poles. \item [Functional equation] There exist an integer $k$, a complex number $\epsilon$ (usually of modulus~$1$), and an attached sequence $a^*$ defining both an $L$-function $L(a^*,s)$ satisfying the above two assumptions and a completed function $\Lambda(a^*,s) = N^{s/2}\gamma_A(s) \cdot L(a^*,s)$, such that $$\Lambda(a,k-s) = \epsilon \Lambda(a^*,s)$$ for all regular points. More often than not in number theory we have $a^* = \overline{a}$ (which forces $|\epsilon| = 1$), but this needs not be the case. If $a$ is a real sequence and $a = a^*$, we say that $L$ is \emph{self-dual}. We do not assume that the $a_n$ are multiplicative, nor equivalently that $L(s)$ has an Euler product. \misctitle{Remark} Of course, $a$ determines the $L$-function, but the (redundant) datum $a,a^*, A, N, k, \epsilon$ describes the situation in a form more suitable for fast computations; knowing the polar part $r$ of $\Lambda(s)$ (a rational function such that $\Lambda-r$ is holomorphic) is also useful. A subset of these, including only finitely many $a_n$-values will still completely determine $L$ (in suitable families), and we provide routines to try and compute missing invariants from whatever information is available. \misctitle{Important Caveat} The implementation assumes that the implied constants in the $O_\epsilon$ are small. In our generic framework, it is impossible to return proven results without more detailed information about the $L$ function. The intended use of the $L$-function package is not to prove theorems, but to experiment and formulate conjectures, so all numerical results should be taken with a grain of salt. One can always increase \kbd{realbitprecision} and recompute: the difference estimates the actual absolute error in the original output. \misctitle{Note} The requested precision has a major impact on runtimes. Because of this, most $L$-function routines, in particular \kbd{lfun} itself, specify the requested precision in \emph{bits}, not in decimal digits. This is transparent for the user once \tet{realprecision} or \tet{realbitprecision} are set. We advise to manipulate precision via \tet{realbitprecision} as it allows finer granularity: \kbd{realprecision} increases by increments of 64 bits, i.e. 19 decimal digits at a time. \subsec{Theta functions} Given an $L$-function as above, we define an attached theta function via Mellin inversion: for any positive real $t > 0$, we let $$ \theta(a,t) := \dfrac{1}{2\pi i}\int_{\Re(s) = c} t^{-s} \Lambda(s)\, ds $$ where $c$ is any positive real number $c > k_1+1$ such that $c + \Re(a) > 0$ for all $a\in A$. In fact, we have $$\theta(a,t) = \sum_{n\geq 1} a_n K(nt/N^{1/2}) \quad\text{where}\quad K(t) := \dfrac{1}{2\pi i}\int_{\Re(s) = c} t^{-s} \gamma_A(s)\, ds.$$ Note that this function is analytic and actually makes sense for complex $t$, such that $\Re(t^{2/d}) > 0$, i.e. in a cone containing the positive real half-line. The functional equation for $\Lambda$ translates into $$ \theta(a,1/t) - \epsilon t^k\theta(a^*,t) = P_\Lambda(t), $$ where $P_\Lambda$ is an explicit polynomial in $t$ and $\log t$ given by the Taylor development of the polar part of $\Lambda$: there are no $\log$'s if all poles are simple, and $P = 0$ if $\Lambda$ is entire. The values $\theta(t)$ are generally easier to compute than the $L(s)$, and this functional equation provides a fast way to guess possible values for missing invariants in the $L$-function definition. \subsec{Data structures describing $L$ and theta functions} We have 3 levels of description: \item an \tet{Lmath} is an arbitrary description of the underlying mathematical situation (to which e.g., we associate the $a_p$ as traces of Frobenius elements); this is done via constructors to be described in the subsections below. \item an \tet{Ldata} is a computational description of situation, containing the complete datum ($a,a^*,A,k,N,\epsilon,r$). Where $a$ and $a^*$ describe the coefficients (given $n,b$ we must be able to compute $[a_1,\dots,a_n]$ with bit accuracy $b$), $A$ describes the Euler factor, the (classical) weight is $k$, $N$ is the conductor, and $r$ describes the polar part of $L(s)$. This is obtained via the function \tet{lfuncreate}. N.B. For motivic $L$-functions, the motivic weight $w$ is $w = k-1$; but we also support non-motivic $L$-functions. \misctitle{Design problem} All components of an \kbd{Ldata} should be given exactly since the accuracy to which they must be computed is not bounded a priori; but this is not always possible, in particular for $\epsilon$ and $r$. \item an \tet{Linit} contains an \kbd{Ldata} and everything needed for fast \emph{numerical} computations. It specifies the functions to be considered (either $L^{(j)}(s)$ or $\theta^{(j)}(t)$ for derivatives of order $j \leq m$, where $m$ is now fixed) and specifies a \emph{domain} which limits the range of arguments ($t$ or $s$, respectively to certain cones and rectangular regions) and the output accuracy. This is obtained via the functions \tet{lfuninit} or \tet{lfunthetainit}. All the functions which are specific to $L$ or theta functions share the prefix \kbd{lfun}. They take as first argument either an \kbd{Lmath}, an \kbd{Ldata}, or an \kbd{Linit}. If a single value is to be computed, this makes no difference, but when many values are needed (e.g. for plots or when searching for zeros), one should first construct an \kbd{Linit} attached to the search range and use it in all subsequent calls. If you attempt to use an \kbd{Linit} outside the range for which it was initialized, a warning is issued, because the initialization is performed again, a major inefficiency: \bprog ? Z = lfuncreate(1); \\ Riemann zeta ? L = lfuninit(Z, [1/2, 0, 100]); \\ zeta(1/2+it), |t| < 100 ? lfun(L, 1/2) \\ OK, within domain %3 = -1.4603545088095868128894991525152980125 ? lfun(L, 0) \\ not on critical line ! *** lfun: Warning: lfuninit: insufficient initialization. %4 = -0.50000000000000000000000000000000000000 ? lfun(L, 1/2, 1) \\ attempt first derivative ! *** lfun: Warning: lfuninit: insufficient initialization. %5 = -3.9226461392091517274715314467145995137 @eprog For many $L$-functions, passing from \kbd{Lmath} to an \kbd{Ldata} is inexpensive: in that case one may use \kbd{lfuninit} directly from the \kbd{Lmath} even when evaluations in different domains are needed. The above example could equally have skipped the \kbd{lfuncreate}: \bprog ? L = lfuninit(1, [1/2, 0, 100]); \\ zeta(1/2+it), |t| < 100 @eprog\noindent In fact, when computing a single value, you can even skip \kbd{lfuninit}: \bprog ? L = lfun(1, 1/2, 1); \\ zeta'(1/2) ? L = lfun(1, 1+x+O(x^5)); \\ first 5 terms of Taylor development at 1 @eprog\noindent Both give the desired results with no warning. \misctitle{Complexity} The implementation requires $O(N(|t|+1))^{1/2}$ coefficients $a_n$ to evaluate $L$ of conductor $N$ at $s = \sigma + i t$. We now describe the available high-level constructors, for built-in $L$ functions. \subsec{Dirichlet $L$-functions} %GPHELPskip Given a Dirichlet character $\chi:(\Z/N\Z)^*\to \C$, we let $$L(\chi, s) = \sum_{n\geq 1} \chi(n) n^{-s}.$$ Only primitive characters are supported. Given a fundamental discriminant $D$, the function $L((D/.), s)$, for the quadratic Kronecker symbol, is encoded by the \typ{INT} $D$. This includes Riemann $\zeta$ function via the special case $D = 1$. More general characters can be represented in a variety of ways: \item via Conrey notation (see \tet{znconreychar}): $\chi_N(m,\cdot)$ is given as the \typ{INTMOD} \kbd{Mod(m,N)}. \item via a \var{znstar} structure describing the abelian group $(\Z/N\Z)^*$, where the character is given in terms of the \var{znstar} generators: \bprog ? G = znstar(100, 1); \\ (Z/100Z)^* ? G.cyc \\ ~ Z/20 . g1 + Z/2 . g2 for some generators g1 and g2 %2 = [20, 2] ? G.gen %3 = [77, 51] ? chi = [a, b] \\ maps g1 to e(a/20) and g2 to e(b/2); e(x) = exp(2ipi x) @eprog\noindent More generally, let $(\Z/N\Z)^* = \oplus (\Z/d_i\Z) g_i$ be given via a \var{znstar} structure $G$ (\kbd{G.cyc} gives the $d_i$ and \kbd{G.gen} the $g_i$). A \tev{character} $\chi$ on $G$ is given by a row vector $v = [a_1,\ldots,a_n]$ such that $\chi(\prod g_i^{n_i}) = \exp(2\pi i\sum a_i n_i / d_i)$. The pair $[G, v]$ encodes the \emph{primitive} character attached to $\chi$. \item in fact, this construction $[G, m]$ describing a character is more general: $m$ is also allowed to be a Conrey index as seen above, or a Conrey logarithm (see \tet{znconreylog}), and the latter format is actually the fastest one. \item it is also possible to view Dirichlet characters as Hecke characters over $K = \Q$ (see below), for a modulus $[N, [1]]$ but this is both more complicated and less efficient. In all cases, a non-primitive character is replaced by the attached primitive character. \subsec{Hecke $L$-functions} %GPHELPskip The Dedekind zeta function of a number field $K = \Q[X]/(T)$ is encoded either by the defining polynomial $T$, or any absolute number fields structure (preferably at least a \var{bnf}). Given a finite order Hecke character $\chi: Cl_f(K)\to \C$, we let $$L(\chi, s) = \sum_{A \subset O_K} \chi(A)\, \left(N_{K/\Q}A\right)^{-s}.$$ Let $Cl_f(K) = \oplus (\Z/d_i\Z) g_i$ given by a \var{bnr} structure with generators: the $d_i$ are given by \kbd{K.cyc} and the $g_i$ by \kbd{K.gen}. A \tev{character} $\chi$ on the ray class group is given by a row vector $v = [a_1,\ldots,a_n]$ such that $\chi(\prod g_i^{n_i}) = \exp(2\pi i\sum a_i n_i / d_i)$. The pair $[\var{bnr}, v]$ encodes the \emph{primitive} character attached to $\chi$. \bprog ? K = bnfinit(x^2-60); ? Cf = bnrinit(K, [7, [1,1]], 1); \\ f = 7 oo_1 oo_2 ? Cf.cyc %3 = [6, 2, 2] ? Cf.gen %4 = [[2, 1; 0, 1], [22, 9; 0, 1], [-6, 7]~] ? lfuncreate([Cf, [1,0,0]]); \\@com $\chi(g_1) = \zeta_6$, $\chi(g_2)=\chi(g_3)=1$ @eprog \noindent Dirichlet characters on $(\Z/N\Z)^*$ are a special case, where $K = \Q$: \bprog ? Q = bnfinit(x); ? Cf = bnrinit(Q, [100, [1]]); \\ for odd characters on (Z/100Z)* @eprog\noindent For even characters, replace by \kbd{bnrinit(K, N)}. Note that the simpler direct construction in the previous section will be more efficient. \subsec{Artin $L$ functions} %GPHELPskip Given a Galois number field $N/\Q$ with group $G = \kbd{galoisinit}(N)$, a representation $\rho$ of $G$ over the cyclotomic field $\Q(\zeta_n)$ is specified by the matrices giving the images of $\kbd{G.gen}$ by $\rho$. The corresponding Artin $L$ function is created using \tet{lfunartin}. \bprog P = quadhilbert(-47); \\ degree 5, Galois group D_5 N = nfinit(nfsplitting(P)); \\ Galois closure G = galoisinit(N); [s,t] = G.gen; \\ order 5 and 2 L = lfunartin(N,G, [[a,0;0,a^-1],[0,1;1,0]], 5); \\ irr. degree 2 @eprog\noindent In the above, the polynomial variable (here \kbd{a}) represents $\zeta_5 := \exp(2i\pi/5)$ and the two matrices give the images of $s$ and $t$. Here, priority of \kbd{a} must be lower than the priority of \kbd{x}. \subsec{$L$-functions of algebraic varieties} %GPHELPskip $L$-function of elliptic curves over number fields are supported. \bprog ? E = ellinit([1,1]); ? L = lfuncreate(E); \\ L-function of E/Q ? E2 = ellinit([1,a], nfinit(a^2-2)); ? L2 = lfuncreate(E2); \\ L-function of E/Q(sqrt(2)) @eprog $L$-function of hyperelliptic genus-$2$ curve can be created with \kbd{lfungenus2}. To create the $L$ function of the curve $y^2+(x^3+x^2+1)y = x^2+x$: \bprog ? L = lfungenus2([x^2+x, x^3+x^2+1]); @eprog Currently, the model needs to be minimal at $2$, and if the conductor is even, its valuation at $2$ might be incorrect (a warning is issued). \subsec{Eta quotients / Modular forms} %GPHELPskip An eta quotient is created by applying \tet{lfunetaquo} to a matrix with 2 columns $[m, r_m]$ representing $$ f(\tau) := \prod_m \eta(m\tau)^{r_m}. $$ It is currently assumed that $f$ is a self-dual cuspidal form on $\Gamma_0(N)$ for some $N$. For instance, the $L$-function $\sum \tau(n) n^{-s}$ attached to Ramanujan's $\Delta$ function is encoded as follows \bprog ? L = lfunetaquo(Mat([1,24])); ? lfunan(L, 100) \\ first 100 values of tau(n) @eprog More general modular forms defined by modular symbols will be added later. \subsec{Low-level Ldata format} %GPHELPskip When no direct constructor is available, you can still input an $L$ function directly by supplying $[a, a^*,A, k, N, \epsilon, r]$ to \kbd{lfuncreate} (see \kbd{??lfuncreate} for details). It is \emph{strongly} suggested to first check consistency of the created $L$-function: \bprog ? L = lfuncreate([a, as, A, k, N, eps, r]); ? lfuncheckfeq(L) \\ check functional equation @eprog pari-2.11.2/src/functions/l_functions/lfuncreate0000644000175000017500000001524513326135265020370 0ustar billbillFunction: lfuncreate Section: l_functions C-Name: lfuncreate Prototype: G Help: lfuncreate(obj): given either an object such as a polynomial, elliptic curve, Dirichlet or Hecke character, eta quotient, etc., or an explicit 6 or 7 component vector [dir,real,Vga,k,N,eps,r], create the Ldata structure necessary for lfun computation. Doc: This low-level routine creates \tet{Ldata} structures, needed by \var{lfun} functions, describing an $L$-function and its functional equation. You are urged to use a high-level constructor when one is available, and this function accepts them, see \kbd{??lfun}: \bprog ? L = lfuncreate(1); \\ Riemann zeta ? L = lfuncreate(5); \\ Dirichlet L-function for quadratic character (5/.) ? L = lfuncreate(x^2+1); \\ Dedekind zeta for Q(i) ? L = lfuncreate(ellinit([0,1])); \\ L-function of E/Q: y^2=x^3+1 @eprog\noindent One can then use, e.g., \kbd{Lfun(L,s)} to directly evaluate the respective $L$-functions at $s$, or \kbd{lfuninit(L, [c,w,h]} to initialize computations in the rectangular box $\Re(s-c) \leq w$, $\Im(s) \leq h$. We now describe the low-level interface, used to input non-builtin $L$-functions. The input is now a $6$ or $7$ component vector $V=[a, astar, Vga, k, N, eps, poles]$, whose components are as follows: \item \kbd{V[1]=a} encodes the Dirichlet series coefficients $(a_n)$. The preferred format is a closure of arity 1: \kbd{n->vector(n,i,a(i))} giving the vector of the first $n$ coefficients. The closure is allowed to return a vector of more than $n$ coefficients (only the first $n$ will be considered) or even less than $n$, in which case loss of accuracy will occur and a warning that \kbd{\#an} is less than expected is issued. This allows to precompute and store a fixed large number of Dirichlet coefficients in a vector $v$ and use the closure \kbd{n->v}, which does not depend on $n$. As a shorthand for this latter case, you can input the vector $v$ itself instead of the closure. \bprog ? z = lfuncreate([n->vector(n,i,1), 1, [0], 1, 1, 1, 1]); \\ Riemann zeta ? lfun(z,2) - Pi^2/6 %2 = -5.877471754111437540 E-39 @eprog A second format is limited to $L$-functions affording an Euler product. It is a closure of arity 2 \kbd{(p,d)->F(p)} giving the local factor $L_p(X)$ at $p$ as a rational function, to be evaluated at $p^{-s}$ as in \kbd{direuler}; $d$ is set to \kbd{logint}$(n,p)$ + 1, where $n$ is the total number of Dirichlet coefficients $(a_1,\dots,a_n)$ that will be computed. In other words, the smallest integer $d$ such that $p^d > n$. This parameter $d$ allows to compute only part of $L_p$ when $p$ is large and $L_p$ expensive to compute: any polynomial (or \typ{SER}) congruent to $L_p$ modulo $X^d$ is acceptable since only the coefficients of $X^0, \dots, X^{d-1}$ are needed to expand the Dirichlet series. The closure can of course ignore this parameter: \bprog ? z = lfuncreate([(p,d)->1/(1-x), 1, [0], 1, 1, 1, 1]); \\ Riemann zeta ? lfun(z,2) - Pi^2/6 %4 = -5.877471754111437540 E-39 @eprog\noindent One can describe separately the generic local factors coefficients and the bad local factors by setting $\kbd{dir} = [F, L_{bad}]$, were $L_{bad} = [[p_1,L_{p_1}], \dots,[p_k,L_{p_k}]]$, where $F$ describes the generic local factors as above, except that when $p = p_i$ for some $i \leq k$, the coefficient $a_p$ is directly set to $L_{p_i}$ instead of calling $F$. \bprog N = 15; E = ellinit([1, 1, 1, -10, -10]); \\ = "15a1" F(p,d) = 1 / (1 - ellap(E,p)*'x + p*'x^2); Lbad = [[3, 1/(1+'x)], [5, 1/(1-'x)]]; L = lfuncreate([[F,Lbad], 0, [0,1], 2, N, ellrootno(E)]); @eprog\noindent Of course, in this case, \kbd{lfuncreate(E)} is preferable! \item \kbd{V[2]=astar} is the Dirichlet series coefficients of the dual function, encoded as \kbd{a} above. The sentinel values $0$ and $1$ may be used for the special cases where $a = a^*$ and $a = \overline{a^*}$, respectively. \item \kbd{V[3]=Vga} is the vector of $\alpha_j$ such that the gamma factor of the $L$-function is equal to $$\gamma_A(s)=\prod_{1\le j\le d}\Gamma_{\R}(s+\alpha_j),$$ where $\Gamma_{\R}(s)=\pi^{-s/2}\Gamma(s/2)$. This same syntax is used in the \kbd{gammamellininv} functions. In particular the length $d$ of \kbd{Vga} is the degree of the $L$-function. In the present implementation, the $\alpha_j$ are assumed to be exact rational numbers. However when calling theta functions with \emph{complex} (as opposed to real) arguments, determination problems occur which may give wrong results when the $\alpha_j$ are not integral. \item \kbd{V[4]=k} is a positive integer $k$. The functional equation relates values at $s$ and $k-s$. For instance, for an Artin $L$-series such as a Dedekind zeta function we have $k = 1$, for an elliptic curve $k = 2$, and for a modular form, $k$ is its weight. For motivic $L$-functions, the \emph{motivic} weight $w$ is $w = k-1$. By default we assume that $a_n = O_\epsilon(n^{k_1+\epsilon})$, where $k_1 = w$ and even $k_1 = w/2$ when the $L$ function has no pole (Ramanujan-Petersson). If this is not the case, you can replace the $k$ argument by a vector $[k,k_1]$, where $k_1$ is the upper bound you can assume. \item \kbd{V[5]=N} is the conductor, an integer $N\ge1$, such that $\Lambda(s)=N^{s/2}\gamma_A(s)L(s)$ with $\gamma_A(s)$ as above. \item \kbd{V[6]=eps} is the root number $\varepsilon$, i.e., the complex number (usually of modulus $1$) such that $\Lambda(a, k-s) = \varepsilon \Lambda(a^*, s)$. \item The last optional component \kbd{V[7]=poles} encodes the poles of the $L$ or $\Lambda$-functions, and is omitted if they have no poles. A polar part is given by a list of $2$-component vectors $[\beta,P_{\beta}(x)]$, where $\beta$ is a pole and the power series $P_{\beta}(x)$ describes the attached polar part, such that $L(s) - P_\beta(s-\beta)$ is holomorphic in a neighbourhood of $\beta$. For instance $P_\beta = r/x+O(1)$ for a simple pole at $\beta$ or $r_1/x^2+r_2/x+O(1)$ for a double pole. The type of the list describing the polar part allows to distinguish between $L$ and $\Lambda$: a \typ{VEC} is attached to $L$, and a \typ{COL} is attached to $\Lambda$. Unless $a = \overline{a^*}$ (coded by \kbd{astar} equal to $0$ or $1$), it is mandatory to specify the polar part of $\Lambda$ rather than those of $L$ since the poles of $L^*$ cannot be infered from the latter ! Whereas the functional equation allows to deduce the polar part of $\Lambda^*$ from the polar part of $\Lambda$. Finally, if $a = \overline{a^*}$, we allow a shortcut to describe the frequent situation where $L$ has at most simple pole, at $s = k$, with residue $r$ a complex scalar: you may then input $\kbd{poles} = r$. This value $r$ can be set to $0$ if unknown and it will be computed. pari-2.11.2/src/functions/l_functions/lfunlambda0000644000175000017500000000130413201017466020326 0ustar billbillFunction: lfunlambda Section: l_functions C-Name: lfunlambda0 Prototype: GGD0,L,b Help: lfunlambda(L,s,{D=0}): compute the completed L function Lambda(s), or if D is set, the derivative of order D at s. L is either an Lmath, an Ldata or an Linit. Doc: compute the completed $L$-function $\Lambda(s) = N^{s/2}\gamma(s)L(s)$, or if \kbd{D} is set, the derivative of order \kbd{D} at $s$. The parameter \kbd{L} is either an \kbd{Lmath}, an \kbd{Ldata} (created by \kbd{lfuncreate}, or an \kbd{Linit} (created by \kbd{lfuninit}), preferrably the latter if many values are to be computed. The result is given with absolute error less than $2^{-B}|\gamma(s)N^{s/2}|$, where $B = \text{realbitprecision}$. pari-2.11.2/src/functions/l_functions/lfundiv0000644000175000017500000000103713201017466017673 0ustar billbillFunction: lfundiv Section: l_functions C-Name: lfundiv Prototype: GGb Help: lfundiv(L1,L2): creates the Ldata structure (without initialization) corresponding to the quotient of the Dirichlet series given by L1 and L2. Doc: creates the \kbd{Ldata} structure (without initialization) corresponding to the quotient of the Dirichlet series $L_1$ and $L_2$ given by \kbd{L1} and \kbd{L2}. Assume that $v_z(L_1) \geq v_z(L_2)$ at all complex numbers $z$: the construction may not create new poles, nor increase the order of existing ones. pari-2.11.2/src/functions/l_functions/lfunabelianrelinit0000644000175000017500000000264513201017466022101 0ustar billbillFunction: lfunabelianrelinit Section: l_functions C-Name: lfunabelianrelinit Prototype: GGGGD0,L,b Help: lfunabelianrelinit(bnfL,bnfK,polrel,sdom,{der=0}): returns the Linit structure attached to the Dedekind zeta function of the number field L, given a subfield K such that L/K is abelian, where polrel defines L over K. The priority of the variable of bnfK must be lower than that of polrel; bnfL is the absolute polynomial corresponding to polrel, and sdom and der are as in lfuninit. Doc: returns the \kbd{Linit} structure attached to the Dedekind zeta function of the number field $L$ (see \tet{lfuninit}), given a subfield $K$ such that $L/K$ is abelian. Here \kbd{polrel} defines $L$ over $K$, as usual with the priority of the variable of \kbd{bnfK} lower than that of \kbd{polrel}. \kbd{sdom} and \kbd{der} are as in \kbd{lfuninit}. \bprog ? D = -47; K = bnfinit(y^2-D); ? rel = quadhilbert(D); T = rnfequation(K.pol, rel); \\ degree 10 ? L = lfunabelianrelinit(T,K,rel, [2,0,0]); \\ at 2 time = 84 ms. ? lfun(L, 2) %4 = 1.0154213394402443929880666894468182650 ? lfun(T, 2) \\ using parisize > 300MB time = 652 ms. %5 = 1.0154213394402443929880666894468182656 @eprog\noindent As the example shows, using the (abelian) relative structure is more efficient than a direct computation. The difference becomes drastic as the absolute degree increases while the subfield degree remains constant. pari-2.11.2/src/functions/l_functions/lfunconductor0000644000175000017500000000575313326135265021130 0ustar billbillFunction: lfunconductor Section: l_functions C-Name: lfunconductor Prototype: GDGD0,L,b Help: lfunconductor(L,{ab=[1,10000]},{flag=0}): give the conductor of the given L-function; ab = [a,b] is the interval where we expect to find the conductor. If flag=0 (default), give either the conductor found as an integer, or a vector (possibly empty) of conductors found. If flag=1, same but give the computed floating point approximations to the conductors found, without rounding to integers. If flag=2, give all the conductors found, even those far from integers. Note: this program is heuristic and should only be used if the primes dividing the conductor are unknown. If they are known, a direct search through possible prime exponents using lfuncheckfeq will be more efficient. Doc: Compute the conductor of the given $L$-function (if the structure contains a conductor, it is ignored); $\kbd{ab} = [a,b]$ is the interval where we expect to find the conductor; it may be given as a single scalar $b$, in which case we look in $[1,b]$. Increasing \kbd{ab} slows down the program but gives better accuracy for the result. If \kbd{flag} is $0$ (default), give either the conductor found as an integer, or a vector (possibly empty) of conductors found. If \kbd{flag} is $1$, same but give the computed floating point approximations to the conductors found, without rounding to integers. It \kbd{flag} is $2$, give all the conductors found, even those far from integers. \misctitle{Caveat} This is a heuristic program and the result is not proven in any way: \bprog ? L = lfuncreate(857); \\ Dirichlet L function for kronecker(857,.) ? \p19 realprecision = 19 significant digits ? lfunconductor(L) %2 = [17, 857] ? lfunconductor(L,,1) \\ don't round %3 = [16.99999999999999999, 857.0000000000000000] ? \p38 realprecision = 38 significant digits ? lfunconductor(L) %4 = 857 @eprog \misctitle{Note} This program should only be used if the primes dividing the conductor are unknown, which is rare. If they are known, a direct search through possible prime exponents using \kbd{lfuncheckfeq} will be more efficient and rigorous: \bprog ? E = ellinit([0,0,0,4,0]); /* Elliptic curve y^2 = x^3+4x */ ? E.disc \\ |disc E| = 2^12 %2 = -4096 \\ create Ldata by hand. Guess that root number is 1 and conductor N ? L(N) = lfuncreate([n->ellan(E,n), 0, [0,1], 2, N, 1]); ? fordiv(E.disc, d, print(d,": ",lfuncheckfeq(L(d)))) 1: 0 2: 0 4: -1 8: -2 16: -3 32: -127 64: -3 128: -2 256: -2 512: -1 1024: -1 2048: 0 4096: 0 ? lfunconductor(L(1)) \\ lfunconductor ignores conductor = 1 in Ldata ! %5 = 32 @eprog\noindent The above code assumed that root number was $1$; had we set it to $-1$, none of the \kbd{lfuncheckfeq} values would have been acceptable: \bprog ? L2(N) = lfuncreate([n->ellan(E,n), 0, [0,1], 2, N, -1]); ? [ lfuncheckfeq(L2(d)) | d<-divisors(E.disc) ] %7 = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, -1, -1] @eprog pari-2.11.2/src/functions/l_functions/lfunmfspec0000644000175000017500000000135213201017466020366 0ustar billbillFunction: lfunmfspec Section: l_functions C-Name: lfunmfspec Prototype: Gb Help: lfunmfspec(L): L corresponding to a modular form, returns [valeven,valodd,omminus,omplus], where valeven (resp., valodd) is the vector of even (resp., odd) periods, and omminus and omplus the corresponding real numbers omega^- and omega^+. For the moment, only for modular forms of even weight. Doc: returns \kbd{[valeven,valodd,omminus,omplus]}, where \kbd{valeven} (resp., \kbd{valodd}) is the vector of even (resp., odd) periods of the modular form given by \kbd{L}, and \kbd{omminus} and \kbd{omplus} the corresponding real numbers $\omega^-$ and $\omega^+$ normalized in a noncanonical way. For the moment, only for modular forms of even weight. pari-2.11.2/src/functions/l_functions/lfunrootres0000644000175000017500000000275213326135265020621 0ustar billbillFunction: lfunrootres Section: l_functions C-Name: lfunrootres Prototype: Gb Help: lfunrootres(data): given the Ldata attached to an L-function (or the output of lfunthetainit), compute the root number and the residues. In the present implementation, if the polar part is not already known completely, at most a single pole is allowed. The output is a 3-component vector [[[a_1, r_1],...,[a_n, r_n],[[b_1, R_1],...[b_m,R_m]], w], where r_i is the polar part of L(s) at a_i, R_i is is the polar part of Lambda(s) at b_i, or [0,0,r] if there is no pole, and w is the root number. Doc: Given the \kbd{Ldata} attached to an $L$-function (or the output of \kbd{lfunthetainit}), compute the root number and the residues. The output is a 3-component vector $[[[a_1,r_1],\cdots,[a_n, r_n], [[b_1, R_1],\cdots,[b_m, R_m]], w]$, where $r_i$ is the polar part of $L(s)$ at $a_i$, $R_i$ is is the polar part of $\Lambda(s)$ at $b_i$ or $[0,0,r]$ if there is no pole, and $w$ is the root number. In the present implementation, \item either the polar part must be completely known (and is then arbitrary): the function determines the root number, \bprog ? L = lfunmul(1,1); \\ zeta^2 ? [r,R,w] = lfunrootres(L); ? r \\ single pole at 1, double %3 = [[1, 1.[...]*x^-2 + 1.1544[...]*x^-1 + O(x^0)]] ? w %4 = 1 ? R \\ double pole at 0 and 1 %5 = [[1,[...]], [0,[...]] @eprog \item or at most a single pole is allowed: the function computes both the root number and the residue ($0$ if no pole). pari-2.11.2/src/functions/l_functions/lfuninit0000644000175000017500000000361413201017466020057 0ustar billbillFunction: lfuninit Section: l_functions C-Name: lfuninit0 Prototype: GGD0,L,b Help: lfuninit(L,sdom,{der=0}): precompute data for evaluating the L-function given by 'L' (and its derivatives of order der, if set) in rectangular domain sdom = [center,w,h] centered on the real axis, |Re(s)-center| <= w, |Im(s)| <= h, where all three components of sdom are real and w,h are non-negative. The subdomain [k/2, 0, h] on the critical line can be encoded as [h] for brevity. Doc: initalization function for all functions linked to the computation of the $L$-function $L(s)$ encoded by \kbd{L}, where $s$ belongs to the rectangular domain $\kbd{sdom} = [\var{center},w,h]$ centered on the real axis, $|\Re(s)-\var{center}| \leq w$, $|\Im(s)| \leq h$, where all three components of \kbd{sdom} are real and $w$, $h$ are non-negative. \kbd{der} is the maximum order of derivation that will be used. The subdomain $[k/2, 0, h]$ on the critical line (up to height $h$) can be encoded as $[h]$ for brevity. The subdomain $[k/2, w, h]$ centered on the critical line can be encoded as $[w, h]$ for brevity. The argument \kbd{L} is an \kbd{Lmath}, an \kbd{Ldata} or an \kbd{Linit}. See \kbd{??Ldata} and \kbd{??lfuncreate} for how to create it. The height $h$ of the domain is a \emph{crucial} parameter: if you only need $L(s)$ for real $s$, set $h$ to~0. The running time is roughly proportional to $$(B / d+\pi h/4)^{d/2+3}N^{1/2},$$ where $B$ is the default bit accuracy, $d$ is the degree of the $L$-function, and $N$ is the conductor (the exponent $d/2+3$ is reduced to $d/2+2$ when $d=1$ and $d=2$). There is also a dependency on $w$, which is less crucial, but make sure to use the smallest rectangular domain that you need. \bprog ? L0 = lfuncreate(1); \\ Riemann zeta ? L = lfuninit(L0, [1/2, 0, 100]); \\ for zeta(1/2+it), |t| < 100 ? lfun(L, 1/2 + I) ? L = lfuninit(L0, [100]); \\ same as above ! @eprog pari-2.11.2/src/functions/l_functions/lfunqf0000644000175000017500000000101213201017466017510 0ustar billbillFunction: lfunqf Section: l_functions C-Name: lfunqf Prototype: Gp Help: lfunqf(Q): returns the Ldata structure attached to the theta function of the lattice attached to the definite positive quadratic form Q. Doc: returns the \kbd{Ldata} structure attached to the $\Theta$ function of the lattice attached to the definite positive quadratic form $Q$. \bprog ? L = lfunqf(matid(2)); ? lfunqf(L,2) %2 = 6.0268120396919401235462601927282855839 ? lfun(x^2+1,2)*4 %3 = 6.0268120396919401235462601927282855839 @eprog pari-2.11.2/src/functions/l_functions/lfunthetainit0000644000175000017500000000312713201017466021104 0ustar billbillFunction: lfunthetainit Section: l_functions C-Name: lfunthetainit Prototype: GDGD0,L,b Help: lfunthetainit(L,{tdom},{m=0}): precompute data for evaluating the m-th derivative of theta functions with argument in domain tdom (by default t is real >= 1). Doc: Initalization function for evaluating the $m$-th derivative of theta functions with argument $t$ in domain \var{tdom}. By default (\var{tdom} omitted), $t$ is real, $t \geq 1$. Otherwise, \var{tdom} may be \item a positive real scalar $\rho$: $t$ is real, $t \geq \rho$. \item a non-real complex number: compute at this particular $t$; this allows to compute $\theta(z)$ for any complex $z$ satisfying $|z|\geq |t|$ and $|\arg z| \leq |\arg t|$; we must have $|2 \arg z / d| < \pi/2$, where $d$ is the degree of the $\Gamma$ factor. \item a pair $[\rho,\alpha]$: assume that $|t| \geq \rho$ and $|\arg t| \leq \alpha$; we must have $|2\alpha / d| < \pi/2$, where $d$ is the degree of the $\Gamma$ factor. \bprog ? \p500 ? L = lfuncreate(1); \\ Riemann zeta ? t = 1+I/2; ? lfuntheta(L, t); \\ direct computation time = 30 ms. ? T = lfunthetainit(L, 1+I/2); time = 30 ms. ? lfuntheta(T, t); \\ instantaneous @eprog\noindent The $T$ structure would allow to quickly compute $\theta(z)$ for any $z$ in the cone delimited by $t$ as explained above. On the other hand \bprog ? lfuntheta(T,I) *** at top-level: lfuntheta(T,I) *** ^-------------- *** lfuntheta: domain error in lfunthetaneed: arg t > 0.785398163397448 @eprog The initialization is equivalent to \bprog ? lfunthetainit(L, [abs(t), arg(t)]) @eprog pari-2.11.2/src/functions/l_functions/lfunorderzero0000644000175000017500000000170113326135265021130 0ustar billbillFunction: lfunorderzero Section: l_functions C-Name: lfunorderzero Prototype: lGD-1,L,b Help: lfunorderzero(L, {m = -1}): computes the order of the possible zero of the L-function at the center k/2 of the critical strip. If m is given and has a non-negative value, assumes the order is at most m. Doc: Computes the order of the possible zero of the $L$-function at the center $k/2$ of the critical strip; return $0$ if $L(k/2)$ does not vanish. If $m$ is given and has a non-negative value, assumes the order is at most $m$. Otherwise, the algorithm chooses a sensible default: \item if the $L$ argument is an \kbd{Linit}, assume that a multiple zero at $s = k / 2$ has order less than or equal to the maximal allowed derivation order. \item else assume the order is less than $4$. You may explicitly increase this value using optional argument~$m$; this overrides the default value above. (Possibly forcing a recomputation of the \kbd{Linit}.) pari-2.11.2/src/functions/l_functions/lfuntwist0000644000175000017500000000114013326135265020264 0ustar billbillFunction: lfuntwist Section: l_functions C-Name: lfuntwist Prototype: GG Help: lfuntwist(L,chi): creates the Ldata structure (without initialization) corresponding to the twist of L by the primitive character attached to the Dirichlet L-function chi. This requires that the conductor of the character is coprime to the conductor of the L-function L. Doc: creates the Ldata structure (without initialization) corresponding to the twist of L by the primitive character attached to the Dirichlet character \kbd{chi}. The conductor of the character must be coprime to the conductor of the L-function $L$. pari-2.11.2/src/functions/l_functions/lfungenus20000644000175000017500000000115613201017466020316 0ustar billbillFunction: lfungenus2 Section: l_functions C-Name: lfungenus2 Prototype: G Help: lfungenus2(F): returns the Ldata structure attached to the L-function attached to the genus-2 curve defined by y^2=F(x) or y^2+Q(x)*y=P(x) if F=[P,Q]. Currently, only odd conductors are supported, and the model needs to be minimal at 2. Doc: returns the \kbd{Ldata} structure attached to the $L$ function attached to the genus-2 curve defined by $y^2=F(x)$ or $y^2+Q(x)\*y=P(x)$ if $F=[P,Q]$. Currently, the model needs to be minimal at 2, and if the conductor is even, its valuation at $2$ might be incorrect (a warning is issued). pari-2.11.2/src/functions/l_functions/lfunmul0000644000175000017500000000056713201017466017715 0ustar billbillFunction: lfunmul Section: l_functions C-Name: lfunmul Prototype: GGb Help: lfunmul(L1,L2): creates the Ldata structure (without initialization) corresponding to the product of the Dirichlet series given by L1 and L2. Doc: creates the \kbd{Ldata} structure (without initialization) corresponding to the product of the Dirichlet series given by \kbd{L1} and \kbd{L2}. pari-2.11.2/src/functions/l_functions/lfuncost0000644000175000017500000000621013201017466020057 0ustar billbillFunction: lfuncost Section: l_functions C-Name: lfuncost0 Prototype: GDGD0,L,b Help: lfuncost(L,{sdom},{der=0}): estimate the cost of running lfuninit(L,sdom,der) at current bit precision. Returns [t,b], to indicate that t coefficients a_n will be computed at bit accuracy b. Subsequent evaluation of lfun at s evaluates a polynomial of degree t at exp(h s). If L is already an Linit, then sdom and der are ignored. Doc: estimate the cost of running \kbd{lfuninit(L,sdom,der)} at current bit precision. Returns $[t,b]$, to indicate that $t$ coefficients $a_n$ will be computed, as well as $t$ values of \tet{gammamellininv}, all at bit accuracy $b$. A subsequent call to \kbd{lfun} at $s$ evaluates a polynomial of degree $t$ at $\exp(h s)$ for some real parameter $h$, at the same bit accuracy $b$. If $L$ is already an \kbd{Linit}, then \var{sdom} and \var{der} are ignored and are best left omitted; the bit accuracy is also inferred from $L$: in short we get an estimate of the cost of using that particular \kbd{Linit}. \bprog ? \pb 128 ? lfuncost(1, [100]) \\ for zeta(1/2+I*t), |t| < 100 %1 = [7, 242] \\ 7 coefficients, 242 bits ? lfuncost(1, [1/2, 100]) \\ for zeta(s) in the critical strip, |Im s| < 100 %2 = [7, 246] \\ now 246 bits ? lfuncost(1, [100], 10) \\ for zeta(1/2+I*t), |t| < 100 %3 = [8, 263] \\ 10th derivative increases the cost by a small amount ? lfuncost(1, [10^5]) %3 = [158, 113438] \\ larger imaginary part: huge accuracy increase ? L = lfuncreate(polcyclo(5)); \\ Dedekind zeta for Q(zeta_5) ? lfuncost(L, [100]) \\ at s = 1/2+I*t), |t| < 100 %5 = [11457, 582] ? lfuncost(L, [200]) \\ twice higher %6 = [36294, 1035] ? lfuncost(L, [10^4]) \\ much higher: very costly ! %7 = [70256473, 45452] ? \pb 256 ? lfuncost(L, [100]); \\ doubling bit accuracy %8 = [17080, 710] @eprog\noindent In fact, some $L$ functions can be factorized algebraically by the \kbd{lfuninit} call, e.g. the Dedekind zeta function of abelian fields, leading to much faster evaluations than the above upper bounds. In that case, the function returns a vector of costs as above for each individual function in the product actually evaluated: \bprog ? L = lfuncreate(polcyclo(5)); \\ Dedekind zeta for Q(zeta_5) ? lfuncost(L, [100]) \\ a priori cost %2 = [11457, 582] ? L = lfuninit(L, [100]); \\ actually perform all initializations ? lfuncost(L) %4 = [[16, 242], [16, 242], [7, 242]] @eprog\noindent The Dedekind function of this abelian quartic field is the product of four Dirichlet $L$-functions attached to the trivial character, a non-trivial real character and two complex conjugate characters. The non-trivial characters happen to have the same conductor (hence same evaluation costs), and correspond to two evaluations only since the two conjugate characters are evaluated simultaneously. For a total of three $L$-functions evaluations, which explains the three components above. Note that the actual cost is much lower than the a priori cost in this case. Variant: Also available is \fun{GEN}{lfuncost}{GEN L, GEN dom, long der, long bitprec} when $L$ is \emph{not} an \kbd{Linit}; the return value is a \typ{VECSMALL} in this case. pari-2.11.2/src/functions/l_functions/lfuntheta0000644000175000017500000000236413326135265020230 0ustar billbillFunction: lfuntheta Section: l_functions C-Name: lfuntheta Prototype: GGD0,L,b Help: lfuntheta(data,t,{m=0}): compute the value of the m-th derivative at t of the theta function attached to the L-function given by data. data can be either the standard L-function data, or the output of lfunthetainit. Doc: compute the value of the $m$-th derivative at $t$ of the theta function attached to the $L$-function given by \kbd{data}. \kbd{data} can be either the standard $L$-function data, or the output of \kbd{lfunthetainit}. The result is given with absolute error less than $2^{-B}$, where $B = \text{realbitprecision}$. The theta function is defined by the formula $\Theta(t)=\sum_{n\ge1}a(n)K(nt/\sqrt(N))$, where $a(n)$ are the coefficients of the Dirichlet series, $N$ is the conductor, and $K$ is the inverse Mellin transform of the gamma product defined by the \kbd{Vga} component. Its Mellin transform is equal to $\Lambda(s)-P(s)$, where $\Lambda(s)$ is the completed $L$-function and the rational function $P(s)$ its polar part. In particular, if the $L$-function is the $L$-function of a modular form $f(\tau)=\sum_{n\ge0}a(n)q^n$ with $q=\exp(2\pi i\tau)$, we have $\Theta(t)=2(f(it/\sqrt{N})-a(0))$. Note that $a(0)=-L(f,0)$ in this case. pari-2.11.2/src/functions/l_functions/lfunzeros0000644000175000017500000000403213326135265020257 0ustar billbillFunction: lfunzeros Section: l_functions C-Name: lfunzeros Prototype: GGD8,L,b Help: lfunzeros(L,lim,{divz=8}): lim being either an upper limit or a real interval, computes an ordered list of zeros of L(s) on the critical line up to the given upper limit or in the given interval. Use a naive algorithm which may miss some zeros. To use a finer search mesh, set divz to some integral value larger than the default (= 8). Doc: \kbd{lim} being either a positive upper limit or a non-empty real interval inside $[0,+\infty[$, computes an ordered list of zeros of $L(s)$ on the critical line up to the given upper limit or in the given interval. Use a naive algorithm which may miss some zeros: it assumes that two consecutive zeros at height $T \geq 1$ differ at least by $2\pi/\omega$, where $$\omega := \kbd{divz} \cdot \big(d\log(T/2\pi) +d+ 2\log(N/(\pi/2)^d)\big).$$ To use a finer search mesh, set divz to some integral value larger than the default (= 8). \bprog ? lfunzeros(1, 30) \\ zeros of Rieman zeta up to height 30 %1 = [14.134[...], 21.022[...], 25.010[...]] ? #lfunzeros(1, [100,110]) \\ count zeros with 100 <= Im(s) <= 110 %2 = 4 @eprog\noindent The algorithm also assumes that all zeros are simple except possibly on the real axis at $s = k/2$ and that there are no poles in the search interval. (The possible zero at $s = k/2$ is repeated according to its multiplicity.) Should you pass an \kbd{Linit} argument to the function, beware that the algorithm needs at least \bprog L = lfuninit(Ldata, [T+1]) @eprog\noindent where $T$ is the upper bound of the interval defined by \kbd{lim}: this allows to detect zeros near $T$. Make sure that your \kbd{Linit} domain contains this one, i.e. a domain $[1,T+1]$ is fine but $[0, T]$ is not! The algorithm assumes that a multiple zero at $s = k / 2$ has order less than or equal to the maximal derivation order allowed by the \kbd{Linit}. You may increase that value in the \kbd{Linit} but this is costly: only do it for zeros of low height or in \kbd{lfunorderzero} instead. pari-2.11.2/src/functions/l_functions/lfunhardy0000644000175000017500000000266613201017466020231 0ustar billbillFunction: lfunhardy Section: l_functions C-Name: lfunhardy Prototype: GGb Help: lfunhardy(L,t): variant of the Hardy L-function attached to L, used for plotting on the critical line. Doc: Variant of the Hardy $Z$-function given by \kbd{L}, used for plotting or locating zeros of $L(k/2+it)$ on the critical line. The precise definition is as follows: if as usual $k/2$ is the center of the critical strip, $d$ is the degree, $\alpha_j$ the entries of \kbd{Vga} giving the gamma factors, and $\varepsilon$ the root number, then if we set $s = k/2+it = \rho e^{i\theta}$ and $E=(d(k/2-1)+\sum_{1\le j\le d}\alpha_j)/2$, the computed function at $t$ is equal to $$Z(t) = \varepsilon^{-1/2}\Lambda(s) \cdot |s|^{-E}e^{dt\theta/2}\;,$$ which is a real function of $t$ for self-dual $\Lambda$, vanishing exactly when $L(k/2+it)$ does on the critical line. The normalizing factor $|s|^{-E}e^{dt\theta/2}$ compensates the exponential decrease of $\gamma_A(s)$ as $t\to\infty$ so that $Z(t) \approx 1$. \bprog ? T = 100; \\ maximal height ? L = lfuninit(1, [T]); \\ initialize for zeta(1/2+it), |t| 0$, and prepended at the beginning if $n < 0$. The dimension of the resulting vector is $|n|$. This allows to write a conversion function for series that takes positive valuations into account: \bprog ? serVec(s) = Vec(s, -serprec(s,variable(s))); ? Vec(x^2 + 3*x^3 + O(x^5)) %2 = [0, 0, 1, 3, 0] @eprog (That function is not intended for series of negative valuation.) Variant: \fun{GEN}{gtovec}{GEN x} is also available. pari-2.11.2/src/functions/conversions/frac0000644000175000017500000000033411636712103017163 0ustar billbillFunction: frac Section: conversions C-Name: gfrac Prototype: G Help: frac(x): fractional part of x = x-floor(x). Doc: fractional part of $x$. Identical to $x-\text{floor}(x)$. If $x$ is real, the result is in $[0,1[$. pari-2.11.2/src/functions/conversions/conjvec0000644000175000017500000000150611636712103017701 0ustar billbillFunction: conjvec Section: conversions C-Name: conjvec Prototype: Gp Help: conjvec(z): conjugate vector of the algebraic number z. Doc: conjugate vector representation of $z$. If $z$ is a polmod, equal to \kbd{Mod}$(a,T)$, this gives a vector of length $\text{degree}(T)$ containing: \item the complex embeddings of $z$ if $T$ has rational coefficients, i.e.~the $a(r[i])$ where $r = \kbd{polroots}(T)$; \item the conjugates of $z$ if $T$ has some intmod coefficients; \noindent if $z$ is a finite field element, the result is the vector of conjugates $[z,z^p,z^{p^2},\ldots,z^{p^{n-1}}]$ where $n=\text{degree}(T)$. \noindent If $z$ is an integer or a rational number, the result is~$z$. If $z$ is a (row or column) vector, the result is a matrix whose columns are the conjugate vectors of the individual elements of $z$. pari-2.11.2/src/functions/conversions/oo0000644000175000017500000000060113326135265016670 0ustar billbillFunction: oo Section: conversions C-Name: mkoo Prototype: Help: oo=oo(): infinity. Doc: returns an object meaning $+\infty$, for use in functions such as \kbd{intnum}. It can be negated (\kbd{-oo} represents $-\infty$), and compared to real numbers (\typ{INT}, \typ{FRAC}, \typ{REAL}), with the expected meaning: $+\infty$ is greater than any real number and $-\infty$ is smaller. pari-2.11.2/src/functions/conversions/Pol0000644000175000017500000000335412314242551017006 0ustar billbillFunction: Pol Section: conversions C-Name: gtopoly Prototype: GDn Description: (gen,?var):pol gtopoly($1, $2) Help: Pol(t,{v='x}): convert t (usually a vector or a power series) into a polynomial with variable v, starting with the leading coefficient. Doc: transforms the object $t$ into a polynomial with main variable $v$. If $t$ is a scalar, this gives a constant polynomial. If $t$ is a power series with non-negative valuation or a rational function, the effect is similar to \kbd{truncate}, i.e.~we chop off the $O(X^k)$ or compute the Euclidean quotient of the numerator by the denominator, then change the main variable of the result to $v$. The main use of this function is when $t$ is a vector: it creates the polynomial whose coefficients are given by $t$, with $t[1]$ being the leading coefficient (which can be zero). It is much faster to evaluate \kbd{Pol} on a vector of coefficients in this way, than the corresponding formal expression $a_n X^n + \dots + a_0$, which is evaluated naively exactly as written (linear versus quadratic time in $n$). \tet{Polrev} can be used if one wants $x[1]$ to be the constant coefficient: \bprog ? Pol([1,2,3]) %1 = x^2 + 2*x + 3 ? Polrev([1,2,3]) %2 = 3*x^2 + 2*x + 1 @eprog\noindent The reciprocal function of \kbd{Pol} (resp.~\kbd{Polrev}) is \kbd{Vec} (resp.~ \kbd{Vecrev}). \bprog ? Vec(Pol([1,2,3])) %1 = [1, 2, 3] ? Vecrev( Polrev([1,2,3]) ) %2 = [1, 2, 3] @eprog\noindent \misctitle{Warning} This is \emph{not} a substitution function. It will not transform an object containing variables of higher priority than~$v$. \bprog ? Pol(x + y, y) *** at top-level: Pol(x+y,y) *** ^---------- *** Pol: variable must have higher priority in gtopoly. @eprog pari-2.11.2/src/functions/conversions/conj0000644000175000017500000000062111636712103017200 0ustar billbillFunction: conj Section: conversions C-Name: gconj Prototype: G Help: conj(x): the algebraic conjugate of x. Doc: conjugate of $x$. The meaning of this is clear, except that for real quadratic numbers, it means conjugation in the real quadratic field. This function has no effect on integers, reals, intmods, fractions or $p$-adics. The only forbidden type is polmod (see \kbd{conjvec} for this). pari-2.11.2/src/functions/conversions/bitneg0000644000175000017500000000114512314242551017520 0ustar billbillFunction: bitneg Section: conversions C-Name: gbitneg Prototype: GD-1,L, Help: bitneg(x,{n=-1}): bitwise negation of an integers x truncated to n bits. n=-1 means represent infinite sequences of bit 1 as negative numbers. Negative numbers behave as if modulo big power of 2. Doc: \idx{bitwise negation} of an integer $x$, truncated to $n$ bits, $n\geq 0$, that is the integer $$\sum_{i=0}^{n-1} \kbd{not}(x_i) 2^i.$$ The special case $n=-1$ means no truncation: an infinite sequence of leading $1$ is then represented as a negative number. See \secref{se:bitand} for the behavior for negative arguments. pari-2.11.2/src/functions/conversions/denominator0000644000175000017500000000343113326135265020576 0ustar billbillFunction: denominator Section: conversions C-Name: denominator Prototype: GDG Help: denominator(f,{D}): denominator of f. Doc: denominator of $f$. The meaning of this is clear when $f$ is a rational number or function. If $f$ is an integer or a polynomial, it is treated as a rational number or function, respectively, and the result is equal to $1$. For polynomials, you probably want to use \bprog denominator( content(f) ) @eprog\noindent instead. As for modular objects, \typ{INTMOD} and \typ{PADIC} have denominator $1$, and the denominator of a \typ{POLMOD} is the denominator of its lift. If $f$ is a recursive structure, for instance a vector or matrix, the lcm of the denominators of its components (a common denominator) is computed. This also applies for \typ{COMPLEX}s and \typ{QUAD}s. \misctitle{Warning} Multivariate objects are created according to variable priorities, with possibly surprising side effects ($x/y$ is a polynomial, but $y/x$ is a rational function). See \secref{se:priority}. The optional argument $D$ allows to control over which ring we compute the denominator and get a more predictable behaviour: \item $1$: we only consider the underlying $\Q$-structure and the denominator is a (positive) rational integer \item a simple variable, say \kbd{'x}: all entries as rational functions in $K(x)$ and the denominator is a polynomial in $x$. \bprog ? f = x + 1/y + 1/2; ? denominator(f) \\ a t_POL in x %2 = 1 ? denominator(f, 1) \\ Q-denominator %3 = 2 ? denominator(f, x) \\ as a t_POL in x, seen above %4 = 1 ? denominator(f, y) \\ as a rational function in y %5 = 2*y @eprog Variant: Also available are \fun{GEN}{denom}{GEN x} which implements the not very useful default behaviour ($D$ is \kbd{NULL}) and \fun{GEN}{Q_denom}{GEN x} ($D = 1$). pari-2.11.2/src/functions/conversions/Colrev0000644000175000017500000000111713201017466017502 0ustar billbillFunction: Colrev Section: conversions C-Name: gtocolrev0 Prototype: GD0,L, Help: Colrev(x, {n}): transforms the object x into a column vector of dimension n in reverse order with respect to Col(x, {n}). Empty vector if x is omitted. Description: (gen):vec gtocolrev($1) Doc: as $\kbd{Col}(x, -n)$, then reverse the result. In particular, \kbd{Colrev} is the reciprocal function of \kbd{Polrev}: the coefficients of the vector start with the constant coefficient of the polynomial and the others follow by increasing degree. Variant: \fun{GEN}{gtocolrev}{GEN x} is also available. pari-2.11.2/src/functions/conversions/bitand0000644000175000017500000000156311636712103017516 0ustar billbillFunction: bitand Section: conversions C-Name: gbitand Prototype: GG Help: bitand(x,y): bitwise "and" of two integers x and y. Negative numbers behave as if modulo big power of 2. Description: (small, small):small:parens $(1)&$(2) (gen, gen):int gbitand($1, $2) Doc: bitwise \tet{and} \sidx{bitwise and}of two integers $x$ and $y$, that is the integer $$\sum_i (x_i~\kbd{and}~y_i) 2^i$$ Negative numbers behave $2$-adically, i.e.~the result is the $2$-adic limit of \kbd{bitand}$(x_n,y_n)$, where $x_n$ and $y_n$ are non-negative integers tending to $x$ and $y$ respectively. (The result is an ordinary integer, possibly negative.) \bprog ? bitand(5, 3) %1 = 1 ? bitand(-5, 3) %2 = 3 ? bitand(-5, -3) %3 = -7 @eprog Variant: Also available is \fun{GEN}{ibitand}{GEN x, GEN y}, which returns the bitwise \emph{and} of $|x|$ and $|y|$, two integers. pari-2.11.2/src/functions/conversions/Vecrev0000644000175000017500000000105113326135265017505 0ustar billbillFunction: Vecrev Section: conversions C-Name: gtovecrev0 Prototype: GD0,L, Help: Vecrev(x, {n}): transforms the object x into a vector of dimension n in reverse order with respect to Vec(x, {n}). Description: (gen):vec gtovecrev($1) Doc: as $\kbd{Vec}(x, -n)$, then reverse the result. In particular, \kbd{Vecrev} is the reciprocal function of \kbd{Polrev}: the coefficients of the vector start with the constant coefficient of the polynomial and the others follow by increasing degree. Variant: \fun{GEN}{gtovecrev}{GEN x} is also available. pari-2.11.2/src/functions/conversions/Strchr0000644000175000017500000000061611636712103017520 0ustar billbillFunction: Strchr Section: conversions C-Name: Strchr Prototype: G Help: Strchr(x): converts x to a string, translating each integer into a character. Doc: converts $x$ to a string, translating each integer into a character. \bprog ? Strchr(97) %1 = "a" ? Vecsmall("hello world") %2 = Vecsmall([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]) ? Strchr(%) %3 = "hello world" @eprog pari-2.11.2/src/functions/conversions/Ser0000644000175000017500000000425513326135265017015 0ustar billbillFunction: Ser Section: conversions C-Name: Ser0 Prototype: GDnDGDP Help: Ser(s,{v='x},{d=seriesprecision}): convert s into a power series with variable v and precision d, starting with the constant coefficient. Doc: transforms the object $s$ into a power series with main variable $v$ ($x$ by default) and precision (number of significant terms) equal to $d \geq 0$ ($d = \kbd{seriesprecision}$ by default). If $s$ is a scalar, this gives a constant power series in $v$ with precision \kbd{d}. If $s$ is a polynomial, the polynomial is truncated to $d$ terms if needed \bprog ? \ps seriesprecision = 16 significant terms ? Ser(1) \\ 16 terms by default %1 = 1 + O(x^16) ? Ser(1, 'y, 5) %2 = 1 + O(y^5) ? Ser(x^2,, 5) %3 = x^2 + O(x^7) ? T = polcyclo(100) %4 = x^40 - x^30 + x^20 - x^10 + 1 ? Ser(T, 'x, 11) %5 = 1 - x^10 + O(x^11) @eprog\noindent The function is more or less equivalent with multiplication by $1 + O(v^d)$ in theses cases, only faster. For the remaining types, vectors and power series, we first explain what occurs if $d$ is omitted. In this case, the function uses exactly the amount of information given in the input: \item If $s$ is already a power series in $v$, we return it verbatim; \item If $s$ is a vector, the coefficients of the vector are understood to be the coefficients of the power series starting from the constant term (as in \tet{Polrev}$(x)$); in other words we convert \typ{VEC} / \typ{COL} to the power series whose significant terms are exactly given by the vector entries. On the other hand, if $d$ is explicitly given, we abide by its value and return a series, truncated or extended with zeros as needed, with $d$ significant terms. \bprog ? v = [1,2,3]; ? Ser(v, t) \\ 3 terms: seriesprecision is ignored! %7 = 1 + 2*t + 3*t^2 + O(t^3) ? Ser(v, t, 7) \\ 7 terms as explicitly requested %8 = 1 + 2*t + 3*t^2 + O(t^7) ? s = 1+x+O(x^2); ? Ser(s) %10 = 1 + x + O(x^2) \\ 2 terms: seriesprecision is ignored ? Ser(s, x, 7) \\ extend to 7 terms %11 = 1 + x + O(x^7) ? Ser(s, x, 1) \\ truncate to 1 term %12 = 1 + O(x) @eprog\noindent The warning given for \kbd{Pol} also applies here: this is not a substitution function. pari-2.11.2/src/functions/conversions/liftall0000644000175000017500000000140513036414402017674 0ustar billbillFunction: liftall Section: conversions C-Name: liftall Prototype: G Help: liftall(x): lifts every element of Z/nZ to Z, of Qp to Q, and of K[x]/(P) to K[x]. Description: (pol):pol liftall($1) (vec):vec liftall($1) (gen):gen liftall($1) Doc: recursively lift all components of $x$ from $\Z/n\Z$ to $\Z$, from $\Q_p$ to $\Q$ (as \tet{truncate}), and polmods to polynomials. \typ{FFELT} are not lifted, nor are List elements: you may convert the latter to vectors first, or use \kbd{apply(liftall,L)}. More generally, components for which such lifts are meaningless (e.g. character strings) are copied verbatim. \bprog ? liftall(x * (1 + O(3)) + Mod(2,3)) %1 = x + 2 ? liftall(x * Mod(y,y^2+1) + Mod(2,3)*Mod(z,z^2)) %2 = y*x + 2*z @eprog pari-2.11.2/src/functions/conversions/serprec0000644000175000017500000000124613326135265017724 0ustar billbillFunction: serprec Section: conversions C-Name: gpserprec Prototype: Gn Help: serprec(x,v): return the absolute precision x with respect to power series in the variable v. Doc: returns the absolute precision of $x$ with respect to power series in the variable $v$; this is the minimum precision of the components of $x$. The result is \tet{+oo} if $x$ is an exact object (as a series in $v$): \bprog ? serprec(x + O(y^2), y) %1 = 2 ? serprec(x + 2, x) %2 = +oo ? serprec(2 + x + O(x^2), y) %3 = +oo @eprog Variant: Also available is \fun{long}{serprec}{GEN x, GEN p}, which returns \tet{LONG_MAX} if $x = 0$, otherwise the series precision as a \kbd{long} integer. pari-2.11.2/src/functions/conversions/HEADER0000644000175000017500000000300513326135265017204 0ustar billbillFunction: _header_conversions Class: header Section: conversions Doc: \subsec{Comparison and Boolean operators}\sidx{Boolean operators} The six standard \idx{comparison operators} \kbd{<=}, \kbd{<}, \kbd{>=}, \kbd{>}, \kbd{==}, \kbd{!=} are available in GP. The result is 1 if the comparison is true, 0 if it is false. The operator \kbd{==} is quite liberal : for instance, the integer 0, a 0 polynomial, and a vector with 0 entries are all tested equal. The extra operator \kbd{===} tests whether two objects are identical and is much stricter than \kbd{==} : objects of different type or length are never identical. For the purpose of comparison, \typ{STR} objects are compared using the standard lexicographic order, and comparing them to objects of a different type raises an exception. GP accepts \kbd{<>} as a synonym for \kbd{!=}. On the other hand, \kbd{=} is definitely \emph{not} a synonym for \kbd{==}: it is the assignment statement. The standard boolean operators \kbd{||} (\idx{inclusive or}), \kbd{\&\&} (\idx{and})\sidx{or} and \kbd{!} (\idx{not}) are also available. \section{Conversions and similar elementary functions or commands} \label{se:conversion} \noindent Many of the conversion functions are rounding or truncating operations. In this case, if the argument is a rational function, the result is the Euclidean quotient of the numerator by the denominator, and if the argument is a vector or a matrix, the operation is done componentwise. This will not be restated for every function. pari-2.11.2/src/functions/conversions/digits0000644000175000017500000000077613201017466017545 0ustar billbillFunction: digits Section: conversions C-Name: digits Prototype: GDG Help: digits(x,{b=10}): gives the vector formed by the digits of x in base b (x and b integers). Doc: outputs the vector of the digits of $|x|$ in base $b$, where $x$ and $b$ are integers ($b = 10$ by default). See \kbd{fromdigits} for the reverse operation. \bprog ? digits(123) %1 = [1, 2, 3, 0] ? digits(10, 2) \\ base 2 %2 = [1, 0, 1, 0] @eprog\noindent By convention, $0$ has no digits: \bprog ? digits(0) %3 = [] @eprog pari-2.11.2/src/functions/conversions/simplify0000644000175000017500000000176211636712103020112 0ustar billbillFunction: simplify Section: conversions C-Name: simplify Prototype: G Help: simplify(x): simplify the object x as much as possible. Doc: this function simplifies $x$ as much as it can. Specifically, a complex or quadratic number whose imaginary part is the integer 0 (i.e.~not \kbd{Mod(0,2)} or \kbd{0.E-28}) is converted to its real part, and a polynomial of degree $0$ is converted to its constant term. Simplifications occur recursively. This function is especially useful before using arithmetic functions, which expect integer arguments: \bprog ? x = 2 + y - y %1 = 2 ? isprime(x) *** at top-level: isprime(x) *** ^---------- *** isprime: not an integer argument in an arithmetic function ? type(x) %2 = "t_POL" ? type(simplify(x)) %3 = "t_INT" @eprog Note that GP results are simplified as above before they are stored in the history. (Unless you disable automatic simplification with \b{y}, that is.) In particular \bprog ? type(%1) %4 = "t_INT" @eprog pari-2.11.2/src/functions/conversions/norm0000644000175000017500000000066111636712103017226 0ustar billbillFunction: norm Section: conversions C-Name: gnorm Prototype: G Help: norm(x): norm of x. Doc: algebraic norm of $x$, i.e.~the product of $x$ with its conjugate (no square roots are taken), or conjugates for polmods. For vectors and matrices, the norm is taken componentwise and hence is not the $L^2$-norm (see \kbd{norml2}). Note that the norm of an element of $\R$ is its square, so as to be compatible with the complex norm. pari-2.11.2/src/functions/conversions/round0000644000175000017500000000302711636712103017401 0ustar billbillFunction: round Section: conversions C-Name: round0 Prototype: GD& Help: round(x,{&e}): take the nearest integer to all the coefficients of x. If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits. Description: (small):small:parens $1 (int):int:copy:parens $1 (real):int roundr($1) (mp):int mpround($1) (mp, &small):int grndtoi($1, &$2) (mp, &int):int round0($1, &$2) (gen):gen ground($1) (gen, &small):gen grndtoi($1, &$2) (gen, &int):gen round0($1, &$2) Doc: If $x$ is in $\R$, rounds $x$ to the nearest integer (rounding to $+\infty$ in case of ties), then and sets $e$ to the number of error bits, that is the binary exponent of the difference between the original and the rounded value (the ``fractional part''). If the exponent of $x$ is too large compared to its precision (i.e.~$e>0$), the result is undefined and an error occurs if $e$ was not given. \misctitle{Important remark} Contrary to the other truncation functions, this function operates on every coefficient at every level of a PARI object. For example $$\text{truncate}\left(\dfrac{2.4*X^2-1.7}{X}\right)=2.4*X,$$ whereas $$\text{round}\left(\dfrac{2.4*X^2-1.7}{X}\right)=\dfrac{2*X^2-2}{X}.$$ An important use of \kbd{round} is to get exact results after an approximate computation, when theory tells you that the coefficients must be integers. Variant: Also available are \fun{GEN}{grndtoi}{GEN x, long *e} and \fun{GEN}{ground}{GEN x}. pari-2.11.2/src/functions/conversions/lift0000644000175000017500000000361613036414402017211 0ustar billbillFunction: lift Section: conversions C-Name: lift0 Prototype: GDn Help: lift(x,{v}): if v is omitted, lifts elements of Z/nZ to Z, of Qp to Q, and of K[x]/(P) to K[x]. Otherwise lift only polmods with main variable v. Description: (pol):pol lift($1) (vec):vec lift($1) (gen):gen lift($1) (pol, var):pol lift0($1, $2) (vec, var):vec lift0($1, $2) (gen, var):gen lift0($1, $2) Doc: if $v$ is omitted, lifts intmods from $\Z/n\Z$ in $\Z$, $p$-adics from $\Q_p$ to $\Q$ (as \tet{truncate}), and polmods to polynomials. Otherwise, lifts only polmods whose modulus has main variable~$v$. \typ{FFELT} are not lifted, nor are List elements: you may convert the latter to vectors first, or use \kbd{apply(lift,L)}. More generally, components for which such lifts are meaningless (e.g. character strings) are copied verbatim. \bprog ? lift(Mod(5,3)) %1 = 2 ? lift(3 + O(3^9)) %2 = 3 ? lift(Mod(x,x^2+1)) %3 = x ? lift(Mod(x,x^2+1)) %4 = x @eprog Lifts are performed recursively on an object components, but only by \emph{one level}: once a \typ{POLMOD} is lifted, the components of the result are \emph{not} lifted further. \bprog ? lift(x * Mod(1,3) + Mod(2,3)) %4 = x + 2 ? lift(x * Mod(y,y^2+1) + Mod(2,3)) %5 = y*x + Mod(2, 3) \\@com do you understand this one? ? lift(x * Mod(y,y^2+1) + Mod(2,3), 'x) %6 = Mod(y, y^2 + 1)*x + Mod(Mod(2, 3), y^2 + 1) ? lift(%, y) %7 = y*x + Mod(2, 3) @eprog\noindent To recursively lift all components not only by one level, but as long as possible, use \kbd{liftall}. To lift only \typ{INTMOD}s and \typ{PADIC}s components, use \tet{liftint}. To lift only \typ{POLMOD}s components, use \tet{liftpol}. Finally, \tet{centerlift} allows to lift \typ{INTMOD}s and \typ{PADIC}s using centered residues (lift of smallest absolute value). Variant: Also available is \fun{GEN}{lift}{GEN x} corresponding to \kbd{lift0(x,-1)}. pari-2.11.2/src/functions/conversions/valuation0000644000175000017500000000200713201017466020251 0ustar billbillFunction: valuation Section: conversions C-Name: gpvaluation Prototype: GG Help: valuation(x,p): valuation of x with respect to p. Doc: computes the highest exponent of $p$ dividing $x$. If $p$ is of type integer, $x$ must be an integer, an intmod whose modulus is divisible by $p$, a fraction, a $q$-adic number with $q=p$, or a polynomial or power series in which case the valuation is the minimum of the valuation of the coefficients. If $p$ is of type polynomial, $x$ must be of type polynomial or rational function, and also a power series if $x$ is a monomial. Finally, the valuation of a vector, complex or quadratic number is the minimum of the component valuations. If $x=0$, the result is \kbd{+oo} if $x$ is an exact object. If $x$ is a $p$-adic numbers or power series, the result is the exponent of the zero. Any other type combinations gives an error. Variant: Also available is \fun{long}{gvaluation}{GEN x, GEN p}, which returns \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer. pari-2.11.2/src/functions/conversions/Col0000644000175000017500000000275113326135265017000 0ustar billbillFunction: Col Section: conversions C-Name: gtocol0 Prototype: GD0,L, Help: Col(x, {n}): transforms the object x into a column vector of dimension n. Description: (gen):vec gtocol($1) Doc: transforms the object $x$ into a column vector. The dimension of the resulting vector can be optionally specified via the extra parameter $n$. If $n$ is omitted or $0$, the dimension depends on the type of $x$; the vector has a single component, except when $x$ is \item a vector or a quadratic form (in which case the resulting vector is simply the initial object considered as a row vector), \item a polynomial or a power series. In the case of a polynomial, the coefficients of the vector start with the leading coefficient of the polynomial, while for power series only the significant coefficients are taken into account, but this time by increasing order of degree. In this last case, \kbd{Vec} is the reciprocal function of \kbd{Pol} and \kbd{Ser} respectively, \item a matrix (the column of row vector comprising the matrix is returned), \item a character string (a vector of individual characters is returned). In the last two cases (matrix and character string), $n$ is meaningless and must be omitted or an error is raised. Otherwise, if $n$ is given, $0$ entries are appended at the end of the vector if $n > 0$, and prepended at the beginning if $n < 0$. The dimension of the resulting vector is $|n|$. See ??Vec for examples. Variant: \fun{GEN}{gtocol}{GEN x} is also available. pari-2.11.2/src/functions/conversions/Polrev0000644000175000017500000000162212314242551017517 0ustar billbillFunction: Polrev Section: conversions C-Name: gtopolyrev Prototype: GDn Description: (gen,?var):pol gtopolyrev($1, $2) Help: Polrev(t,{v='x}): convert t (usually a vector or a power series) into a polynomial with variable v, starting with the constant term. Doc: transform the object $t$ into a polynomial with main variable $v$. If $t$ is a scalar, this gives a constant polynomial. If $t$ is a power series, the effect is identical to \kbd{truncate}, i.e.~it chops off the $O(X^k)$. The main use of this function is when $t$ is a vector: it creates the polynomial whose coefficients are given by $t$, with $t[1]$ being the constant term. \tet{Pol} can be used if one wants $t[1]$ to be the leading coefficient: \bprog ? Polrev([1,2,3]) %1 = 3*x^2 + 2*x + 1 ? Pol([1,2,3]) %2 = x^2 + 2*x + 3 @eprog The reciprocal function of \kbd{Pol} (resp.~\kbd{Polrev}) is \kbd{Vec} (resp.~ \kbd{Vecrev}). pari-2.11.2/src/functions/conversions/bitxor0000644000175000017500000000117111636712103017557 0ustar billbillFunction: bitxor Section: conversions C-Name: gbitxor Prototype: GG Help: bitxor(x,y): bitwise "exclusive or" of two integers x and y. Negative numbers behave as if modulo big power of 2. Description: (small, small):small:parens $(1)^$(2) (gen, gen):int gbitxor($1, $2) Doc: bitwise (exclusive) \tet{or} \sidx{bitwise exclusive or}of two integers $x$ and $y$, that is the integer $$\sum (x_i~\kbd{xor}~y_i) 2^i$$ See \secref{se:bitand} for the behavior for negative arguments. Variant: Also available is \fun{GEN}{ibitxor}{GEN x, GEN y}, which returns the bitwise \emph{xor} of $|x|$ and $|y|$, two integers. pari-2.11.2/src/functions/conversions/Strtex0000644000175000017500000000064711636712103017550 0ustar billbillFunction: Strtex Section: conversions C-Name: Strtex Prototype: s* Help: Strtex({x}*): translates its (string) arguments to TeX format and returns the resulting string. Doc: translates its arguments to TeX format, and concatenates the results into a single character string (type \typ{STR}, the empty string if $x$ is omitted). The individual arguments are read in string context, see \secref{se:strings}. %\syn{NO} pari-2.11.2/src/functions/conversions/varhigher0000644000175000017500000000477413201017466020243 0ustar billbillFunction: varhigher Section: conversions C-Name: varhigher Prototype: sDn Help: varhigher(name,{v}): return a variable 'name' whose priority is higher than the priority of v (of all existing variables if v is omitted). Doc: return a variable \emph{name} whose priority is higher than the priority of $v$ (of all existing variables if $v$ is omitted). This is a counterpart to \tet{varlower}. \bprog ? Pol([x,x], t) *** at top-level: Pol([x,x],t) *** ^------------ *** Pol: incorrect priority in gtopoly: variable x <= t ? t = varhigher("t", x); ? Pol([x,x], t) %3 = x*t + x @eprog\noindent This routine is useful since new GP variables directly created by the interpreter always have lower priority than existing GP variables. When some basic objects already exist in a variable that is incompatible with some function requirement, you can now create a new variable with a suitable priority instead of changing variables in existing objects: \bprog ? K = nfinit(x^2+1); ? rnfequation(K,y^2-2) *** at top-level: rnfequation(K,y^2-2) *** ^-------------------- *** rnfequation: incorrect priority in rnfequation: variable y >= x ? y = varhigher("y", x); ? rnfequation(K, y^2-2) %3 = y^4 - 2*y^2 + 9 @eprog\noindent \misctitle{Caution 1} The \emph{name} is an arbitrary character string, only used for display purposes and need not be related to the GP variable holding the result, nor to be a valid variable name. In particular the \emph{name} can not be used to retrieve the variable, it is not even present in the parser's hash tables. \bprog ? x = varhigher("#"); ? x^2 %2 = #^2 @eprog \misctitle{Caution 2} There are a limited number of variables and if no existing variable with the given display name has the requested priority, the call to \kbd{varhigher} uses up one such slot. Do not create new variables in this way unless it's absolutely necessary, reuse existing names instead and choose sensible priority requirements: if you only need a variable with higher priority than $x$, state so rather than creating a new variable with highest priority. \bprog \\ quickly use up all variables ? n = 0; while(1,varhigher("tmp"); n++) *** at top-level: n=0;while(1,varhigher("tmp");n++) *** ^------------------- *** varhigher: no more variables available. *** Break loop: type 'break' to go back to GP prompt break> n 65510 \\ infinite loop: here we reuse the same 'tmp' ? n = 0; while(1,varhigher("tmp", x); n++) @eprog pari-2.11.2/src/functions/conversions/bitor0000644000175000017500000000115011636712103017364 0ustar billbillFunction: bitor Section: conversions C-Name: gbitor Prototype: GG Help: bitor(x,y): bitwise "or" of two integers x and y. Negative numbers behave as if modulo big power of 2. Description: (small, small):small:parens $(1)|$(2) (gen, gen):int gbitor($1, $2) Doc: \sidx{bitwise inclusive or}bitwise (inclusive) \tet{or} of two integers $x$ and $y$, that is the integer $$\sum (x_i~\kbd{or}~y_i) 2^i$$ See \secref{se:bitand} for the behavior for negative arguments. Variant: Also available is \fun{GEN}{ibitor}{GEN x, GEN y}, which returns the bitwise \emph{ir} of $|x|$ and $|y|$, two integers. pari-2.11.2/src/functions/conversions/numerator0000644000175000017500000000201413326135265020267 0ustar billbillFunction: numerator Section: conversions C-Name: numerator Prototype: GDG Help: numerator(f,{D}): numerator of f. Doc: numerator of $f$. This is defined as \kbd{f * denominator(f,D)}, see \kbd{denominator} for details. The optional argument $D$ allows to control over which ring we compute the denominator: \item $1$: we only consider the underlying $\Q$-structure and the denominator is a (positive) rational integer \item a simple variable, say \kbd{'x}: all entries as rational functions in $K(x)$ and the denominator is a polynomial in $x$. \bprog ? f = x + 1/y + 1/2; ? numerator(f) \\ a t_POL in x %2 = x + ((y + 2)/(2*y)) ? numerator(f, 1) \\ Q-denominator is 2 %3 = x + ((y + 2)/y) ? numerator(f, y) \\ as a rational function in y %5 = 2*y*x + (y + 2) @eprog Variant: Also available are \fun{GEN}{numer}{GEN x} which implements the not very useful default behaviour ($D$ is \kbd{NULL}) and \fun{GEN}{Q_remove_denom}{GEN x, GEN *ptd} ($D = 1$) and also returns the denominator (coding $1$ as \kbd{NULL}). pari-2.11.2/src/functions/conversions/real0000644000175000017500000000036411636712103017176 0ustar billbillFunction: real Section: conversions C-Name: greal Prototype: G Help: real(x): real part of x. Doc: real part of $x$. In the case where $x$ is a quadratic number, this is the coefficient of $1$ in the ``canonical'' integral basis $(1,\omega)$. pari-2.11.2/src/functions/conversions/Qfb0000644000175000017500000000115411636712103016761 0ustar billbillFunction: Qfb Section: conversions C-Name: Qfb0 Prototype: GGGDGp Help: Qfb(a,b,c,{D=0.}): binary quadratic form a*x^2+b*x*y+c*y^2. D is optional (0.0 by default) and initializes Shanks's distance if b^2-4*a*c>0. Doc: creates the binary quadratic form\sidx{binary quadratic form} $ax^2+bxy+cy^2$. If $b^2-4ac>0$, initialize \idx{Shanks}' distance function to $D$. Negative definite forms are not implemented, use their positive definite counterpart instead. Variant: Also available are \fun{GEN}{qfi}{GEN a, GEN b, GEN c} (assumes $b^2-4ac<0$) and \fun{GEN}{qfr}{GEN a, GEN b, GEN c, GEN D} (assumes $b^2-4ac>0$). pari-2.11.2/src/functions/conversions/Mat0000644000175000017500000000173613201017466017000 0ustar billbillFunction: Mat Section: conversions C-Name: gtomat Prototype: DG Help: Mat({x=[]}): transforms any GEN x into a matrix. Empty matrix if x is omitted. Description: ():vec cgetg(1, t_MAT) (gen):vec gtomat($1) Doc: transforms the object $x$ into a matrix. If $x$ is already a matrix, a copy of $x$ is created. If $x$ is a row (resp. column) vector, this creates a 1-row (resp. 1-column) matrix, \emph{unless} all elements are column (resp.~row) vectors of the same length, in which case the vectors are concatenated sideways and the attached big matrix is returned. If $x$ is a binary quadratic form, creates the attached $2\times 2$ matrix. Otherwise, this creates a $1\times 1$ matrix containing $x$. \bprog ? Mat(x + 1) %1 = [x + 1] ? Vec( matid(3) ) %2 = [[1, 0, 0]~, [0, 1, 0]~, [0, 0, 1]~] ? Mat(%) %3 = [1 0 0] [0 1 0] [0 0 1] ? Col( [1,2; 3,4] ) %4 = [[1, 2], [3, 4]]~ ? Mat(%) %5 = [1 2] [3 4] ? Mat(Qfb(1,2,3)) %6 = [1 1] [1 3] @eprog pari-2.11.2/src/functions/conversions/component0000644000175000017500000000332513036414402020252 0ustar billbillFunction: component Section: conversions C-Name: compo Prototype: GL Help: component(x,n): the n'th component of the internal representation of x. For vectors or matrices, it is simpler to use x[]. For list objects such as nf, bnf, bnr or ell, it is much easier to use member functions starting with ".". Description: (error,small):gen err_get_compo($1, $2) (gen,small):gen compo($1,$2) Doc: extracts the $n^{\text{th}}$-component of $x$. This is to be understood as follows: every PARI type has one or two initial \idx{code words}. The components are counted, starting at 1, after these code words. In particular if $x$ is a vector, this is indeed the $n^{\text{th}}$-component of $x$, if $x$ is a matrix, the $n^{\text{th}}$ column, if $x$ is a polynomial, the $n^{\text{th}}$ coefficient (i.e.~of degree $n-1$), and for power series, the $n^{\text{th}}$ significant coefficient. For polynomials and power series, one should rather use \tet{polcoeff}, and for vectors and matrices, the \kbd{[$\,$]} operator. Namely, if $x$ is a vector, then \tet{x[n]} represents the $n^{\text{th}}$ component of $x$. If $x$ is a matrix, \tet{x[m,n]} represents the coefficient of row \kbd{m} and column \kbd{n} of the matrix, \tet{x[m,]} represents the $m^{\text{th}}$ \emph{row} of $x$, and \tet{x[,n]} represents the $n^{\text{th}}$ \emph{column} of $x$. Using of this function requires detailed knowledge of the structure of the different PARI types, and thus it should almost never be used directly. Some useful exceptions: \bprog ? x = 3 + O(3^5); ? component(x, 2) %2 = 81 \\ p^(p-adic accuracy) ? component(x, 1) %3 = 3 \\ p ? q = Qfb(1,2,3); ? component(q, 1) %5 = 1 @eprog pari-2.11.2/src/functions/conversions/padicprec0000644000175000017500000000211513201017466020201 0ustar billbillFunction: padicprec Section: conversions C-Name: gppadicprec Prototype: GG Help: padicprec(x,p): return the absolute p-adic precision of object x. Doc: returns the absolute $p$-adic precision of the object $x$; this is the minimum precision of the components of $x$. The result is \tet{+oo} if $x$ is an exact object (as a $p$-adic): \bprog ? padicprec((1 + O(2^5)) * x + (2 + O(2^4)), 2) %1 = 4 ? padicprec(x + 2, 2) %2 = +oo ? padicprec(2 + x + O(x^2), 2) %3 = +oo @eprog\noindent The function raises an exception if it encounters an object incompatible with $p$-adic computations: \bprog ? padicprec(O(3), 2) *** at top-level: padicprec(O(3),2) *** ^----------------- *** padicprec: inconsistent moduli in padicprec: 3 != 2 ? padicprec(1.0, 2) *** at top-level: padicprec(1.0,2) *** ^---------------- *** padicprec: incorrect type in padicprec (t_REAL). @eprog Variant: Also available is the function \fun{long}{padicprec}{GEN x, GEN p}, which returns \tet{LONG_MAX} if $x = 0$ and the $p$-adic precision as a \kbd{long} integer. pari-2.11.2/src/functions/conversions/serchop0000644000175000017500000000071213326135265017721 0ustar billbillFunction: serchop Section: conversions C-Name: serchop Prototype: GD0,L, Help: serchop(s,{n=0}): remove all terms of degree strictly less than n in series s. Doc: remove all terms of degree strictly less than $n$ in series $s$. When the series contains no terms of degree $< n$, return $O(x^n)$. \bprog ? s = 1/x + x + 2*x^2 + O(x^3); ? serchop(s) %2 = x + 2*x^3 + O(x^3) ? serchop(s, 2) %3 = 2*x^2 + O(x^3) ? serchop(s, 100) %4 = O(x^100) @eprog pari-2.11.2/src/functions/conversions/exponent0000644000175000017500000000270613326135265020123 0ustar billbillFunction: exponent Section: conversions C-Name: gpexponent Prototype: G Help: exponent(x): binary exponent of x Doc: When $x$ is a \typ{REAL}, the result is the binary exponent $e$ of $x$. For a non-zero $x$, this is the unique integer $e$ such that $2^e \leq |x| < 2^{e+1}$. For a real $0$, this returns the PARI exponent $e$ attached to $x$ (which may represent any floating-point number less than $2^e$ in absolute value). \bprog ? exponent(Pi) %1 = 1 ? exponent(4.0) %2 = 2 ? exponent(0.0) %3 = -128 ? default(realbitprecision) %4 = 128 @eprog\noindent This definition extends naturally to non-zero integers, and the exponent of an exact $0$ is $-\kbd{oo}$ by convention. For convenience, we \emph{define} the exponent of a \typ{FRAC} $a/b$ as the difference of \kbd{exponent}$(a)$ and \kbd{exponent}$(b)$; note that, if $e'$ denotes the exponent of \kbd{$a/b$ * 1.0}, then the exponent $e$ we return is either $e'$ or $e'+1$, thus $2^{e+1}$ is an upper bound for $|a/b|$. \bprog ? [ exponent(9), exponent(10), exponent(9/10), exponent(9/10*1.) ] %5 = [3, 3, 0, -1] @eprog For a PARI object of type \typ{COMPLEX}, \typ{POL}, \typ{SER}, \typ{VEC}, \typ{COL}, \typ{MAT} this returns the largest exponent found among the components of $x$. Hence $2^{e+1}$ is a quick upper bound for the sup norm of real matrices or polynomials; and $2^{e+(3/2)}$ for complex ones. \bprog ? exponent(3*x^2 + 15*x - 100) %5 = 6 ? exponent(0) %6 = -oo @eprog pari-2.11.2/src/functions/conversions/Map0000644000175000017500000000126113326135265016773 0ustar billbillFunction: Map Section: conversions C-Name: gtomap Prototype: DG Help: Map({x}): converts the matrix [a_1,b_1;a_2,b_2;...;a_n,b_n] to the map a_i->b_i. Description: ():list mkmap() (gen):list listinit(gtomap($1)) Doc: A ``Map'' is an associative array, or dictionary: a data type composed of a collection of (\emph{key}, \emph{value}) pairs, such that each key appears just once in the collection. This function converts the matrix $[a_1,b_1;a_2,b_2;\dots;a_n,b_n]$ to the map $a_i\mapsto b_i$. \bprog ? M = Map(factor(13!)); ? mapget(M,3) %2 = 5 @eprog\noindent If the argument $x$ is omitted, creates an empty map, which may be filled later via \tet{mapput}. pari-2.11.2/src/functions/conversions/varlower0000644000175000017500000000634013201017466020114 0ustar billbillFunction: varlower Section: conversions C-Name: varlower Prototype: sDn Help: varlower(name,{v}): return a variable 'name' whose priority is lower than the priority of v (of all existing variables if v is omitted. Doc: return a variable \emph{name} whose priority is lower than the priority of $v$ (of all existing variables if $v$ is omitted). This is a counterpart to \tet{varhigher}. New GP variables directly created by the interpreter always have lower priority than existing GP variables, but it is not easy to check whether an identifier is currently unused, so that the corresponding variable has the expected priority when it's created! Thus, depending on the session history, the same command may fail or succeed: \bprog ? t; z; \\ now t > z ? rnfequation(t^2+1,z^2-t) *** at top-level: rnfequation(t^2+1,z^ *** ^-------------------- *** rnfequation: incorrect priority in rnfequation: variable t >= t @eprog\noindent Restart and retry: \bprog ? z; t; \\ now z > t ? rnfequation(t^2+1,z^2-t) %2 = z^4 + 1 @eprog\noindent It is quite annoying for package authors, when trying to define a base ring, to notice that the package may fail for some users depending on their session history. The safe way to do this is as follows: \bprog ? z; t; \\ In new session: now z > t ... ? t = varlower("t", 'z); ? rnfequation(t^2+1,z^2-2) %2 = z^4 - 2*z^2 + 9 ? variable() %3 = [x, y, z, t] @eprog \bprog ? t; z; \\ In new session: now t > z ... ? t = varlower("t", 'z); \\ create a new variable, still printed "t" ? rnfequation(t^2+1,z^2-2) %2 = z^4 - 2*z^2 + 9 ? variable() %3 = [x, y, t, z, t] @eprog\noindent Now both constructions succeed. Note that in the first case, \kbd{varlower} is essentially a no-op, the existing variable $t$ has correct priority. While in the second case, two different variables are displayed as \kbd{t}, one with higher priority than $z$ (created in the first line) and another one with lower priority (created by \kbd{varlower}). \misctitle{Caution 1} The \emph{name} is an arbitrary character string, only used for display purposes and need not be related to the GP variable holding the result, nor to be a valid variable name. In particular the \emph{name} can not be used to retrieve the variable, it is not even present in the parser's hash tables. \bprog ? x = varlower("#"); ? x^2 %2 = #^2 @eprog \misctitle{Caution 2} There are a limited number of variables and if no existing variable with the given display name has the requested priority, the call to \kbd{varlower} uses up one such slot. Do not create new variables in this way unless it's absolutely necessary, reuse existing names instead and choose sensible priority requirements: if you only need a variable with higher priority than $x$, state so rather than creating a new variable with highest priority. \bprog \\ quickly use up all variables ? n = 0; while(1,varlower("x"); n++) *** at top-level: n=0;while(1,varlower("x");n++) *** ^------------------- *** varlower: no more variables available. *** Break loop: type 'break' to go back to GP prompt break> n 65510 \\ infinite loop: here we reuse the same 'tmp' ? n = 0; while(1,varlower("tmp", x); n++) @eprog pari-2.11.2/src/functions/conversions/bitnegimply0000644000175000017500000000130211636712103020567 0ustar billbillFunction: bitnegimply Section: conversions C-Name: gbitnegimply Prototype: GG Help: bitnegimply(x,y): bitwise "negated imply" of two integers x and y, in other words, x BITAND BITNEG(y). Negative numbers behave as if modulo big power of 2. Description: (small, small):small:parens $(1)&~$(2) (gen, gen):int gbitnegimply($1, $2) Doc: bitwise negated imply of two integers $x$ and $y$ (or \kbd{not} $(x \Rightarrow y)$), that is the integer $$\sum (x_i~\kbd{and not}(y_i)) 2^i$$ See \secref{se:bitand} for the behavior for negative arguments. Variant: Also available is \fun{GEN}{ibitnegimply}{GEN x, GEN y}, which returns the bitwise negated imply of $|x|$ and $|y|$, two integers. pari-2.11.2/src/functions/conversions/length0000644000175000017500000000201311636712103017525 0ustar billbillFunction: length Section: conversions C-Name: glength Prototype: lG Help: length(x): number of non code words in x, number of characters for a string. Description: (vecsmall):lg lg($1) (vec):lg lg($1) (pol):small lgpol($1) (gen):small glength($1) Doc: length of $x$; \kbd{\#}$x$ is a shortcut for \kbd{length}$(x)$. This is mostly useful for \item vectors: dimension (0 for empty vectors), \item lists: number of entries (0 for empty lists), \item matrices: number of columns, \item character strings: number of actual characters (without trailing \kbd{\bs 0}, should you expect it from $C$ \kbd{char*}). \bprog ? #"a string" %1 = 8 ? #[3,2,1] %2 = 3 ? #[] %3 = 0 ? #matrix(2,5) %4 = 5 ? L = List([1,2,3,4]); #L %5 = 4 @eprog The routine is in fact defined for arbitrary GP types, but is awkward and useless in other cases: it returns the number of non-code words in $x$, e.g. the effective length minus 2 for integers since the \typ{INT} type has two code words. pari-2.11.2/src/functions/conversions/truncate0000644000175000017500000000325511636712103020102 0ustar billbillFunction: truncate Section: conversions C-Name: trunc0 Prototype: GD& Help: truncate(x,{&e}): truncation of x; when x is a power series,take away the O(X^). If e is present, do not take into account loss of integer part precision, and set e = error estimate in bits. Description: (small):small:parens $1 (int):int:copy:parens $1 (real):int truncr($1) (mp):int mptrunc($1) (mp, &small):int gcvtoi($1, &$2) (mp, &int):int trunc0($1, &$2) (gen):gen gtrunc($1) (gen, &small):gen gcvtoi($1, &$2) (gen, &int):gen trunc0($1, &$2) Doc: truncates $x$ and sets $e$ to the number of error bits. When $x$ is in $\R$, this means that the part after the decimal point is chopped away, $e$ is the binary exponent of the difference between the original and the truncated value (the ``fractional part''). If the exponent of $x$ is too large compared to its precision (i.e.~$e>0$), the result is undefined and an error occurs if $e$ was not given. The function applies componentwise on vector / matrices; $e$ is then the maximal number of error bits. If $x$ is a rational function, the result is the ``integer part'' (Euclidean quotient of numerator by denominator) and $e$ is not set. Note a very special use of \kbd{truncate}: when applied to a power series, it transforms it into a polynomial or a rational function with denominator a power of $X$, by chopping away the $O(X^k)$. Similarly, when applied to a $p$-adic number, it transforms it into an integer or a rational number by chopping away the $O(p^k)$. Variant: The following functions are also available: \fun{GEN}{gtrunc}{GEN x} and \fun{GEN}{gcvtoi}{GEN x, long *e}. pari-2.11.2/src/functions/conversions/ceil0000644000175000017500000000100111636712103017154 0ustar billbillFunction: ceil Section: conversions C-Name: gceil Prototype: G Help: ceil(x): ceiling of x = smallest integer >= x. Description: (small):small:parens $1 (int):int:copy:parens $1 (real):int ceilr($1) (mp):int mpceil($1) (gen):gen gceil($1) Doc: ceiling of $x$. When $x$ is in $\R$, the result is the smallest integer greater than or equal to $x$. Applied to a rational function, $\kbd{ceil}(x)$ returns the Euclidean quotient of the numerator by the denominator. pari-2.11.2/src/functions/conversions/floor0000644000175000017500000000100211636712103017362 0ustar billbillFunction: floor Section: conversions C-Name: gfloor Prototype: G Help: floor(x): floor of x = largest integer <= x. Description: (small):small:parens $1 (int):int:copy:parens $1 (real):int floorr($1) (mp):int mpfloor($1) (gen):gen gfloor($1) Doc: floor of $x$. When $x$ is in $\R$, the result is the largest integer smaller than or equal to $x$. Applied to a rational function, $\kbd{floor}(x)$ returns the Euclidean quotient of the numerator by the denominator. pari-2.11.2/src/functions/conversions/binary0000644000175000017500000000112313201017466017531 0ustar billbillFunction: binary Section: conversions C-Name: binaire Prototype: G Help: binary(x): gives the vector formed by the binary digits of x (x integer). Doc: outputs the vector of the binary digits of $|x|$. Here $x$ can be an integer, a real number (in which case the result has two components, one for the integer part, one for the fractional part) or a vector/matrix. \bprog ? binary(10) %1 = [1, 0, 1, 0] ? binary(3.14) %2 = [[1, 1], [0, 0, 1, 0, 0, 0, [...]] ? binary([1,2]) %3 = [[1], [1, 0]] @eprog\noindent By convention, $0$ has no digits: \bprog ? binary(0) %4 = [] @eprog pari-2.11.2/src/functions/conversions/variable0000644000175000017500000000351113201017466020035 0ustar billbillFunction: variable Section: conversions C-Name: gpolvar Prototype: DG Help: variable({x}): main variable of object x. Gives p for p-adic x, 0 if no variable can be attached to x. Returns the list of user variables if x is omitted. Description: (pol):var:parens:copy $var:1 (gen):gen gpolvar($1) Doc: gives the main variable of the object $x$ (the variable with the highest priority used in $x$), and $p$ if $x$ is a $p$-adic number. Return $0$ if $x$ has no variable attached to it. \bprog ? variable(x^2 + y) %1 = x ? variable(1 + O(5^2)) %2 = 5 ? variable([x,y,z,t]) %3 = x ? variable(1) %4 = 0 @eprog\noindent The construction \bprog if (!variable(x),...) @eprog\noindent can be used to test whether a variable is attached to $x$. If $x$ is omitted, returns the list of user variables known to the interpreter, by order of decreasing priority. (Highest priority is initially $x$, which come first until \tet{varhigher} is used.) If \kbd{varhigher} or \kbd{varlower} are used, it is quite possible to end up with different variables (with different priorities) printed in the same way: they will then appear multiple times in the output: \bprog ? varhigher("y"); ? varlower("y"); ? variable() %4 = [y, x, y] @eprog\noindent Using \kbd{v = variable()} then \kbd{v[1]}, \kbd{v[2]}, etc.~allows to recover and use existing variables. Variant: However, in library mode, this function should not be used for $x$ non-\kbd{NULL}, since \tet{gvar} is more appropriate. Instead, for $x$ a $p$-adic (type \typ{PADIC}), $p$ is $gel(x,2)$; otherwise, use \fun{long}{gvar}{GEN x} which returns the variable number of $x$ if it exists, \kbd{NO\_VARIABLE} otherwise, which satisfies the property $\kbd{varncmp}(\kbd{NO\_VARIABLE}, v) > 0$ for all valid variable number $v$, i.e. it has lower priority than any variable. pari-2.11.2/src/functions/conversions/Str0000644000175000017500000000174112314242551017022 0ustar billbillFunction: Str Section: conversions C-Name: Str Prototype: s* Help: Str({x}*): concatenates its (string) argument into a single string. Description: (gen):genstr:copy:parens $genstr:1 (gen,gen):genstr Str(mkvec2($1, $2)) (gen,gen,gen):genstr Str(mkvec3($1, $2, $3)) (gen,gen,gen,gen):genstr Str(mkvec4($1, $2, $3, $4)) (gen,...):genstr Str(mkvecn($#, $2)) Doc: converts its argument list into a single character string (type \typ{STR}, the empty string if $x$ is omitted). To recover an ordinary \kbd{GEN} from a string, apply \kbd{eval} to it. The arguments of \kbd{Str} are evaluated in string context, see \secref{se:strings}. \bprog ? x2 = 0; i = 2; Str(x, i) %1 = "x2" ? eval(%) %2 = 0 @eprog\noindent This function is mostly useless in library mode. Use the pair \tet{strtoGEN}/\tet{GENtostr} to convert between \kbd{GEN} and \kbd{char*}. The latter returns a malloced string, which should be freed after usage. %\syn{NO} pari-2.11.2/src/functions/conversions/bitprecision0000644000175000017500000000304113201017466020740 0ustar billbillFunction: bitprecision Section: conversions C-Name: bitprecision0 Prototype: GD0,L, Help: bitprecision(x,{n}): if n is present and positive, return x at precision n bits. If n is omitted, return real precision of object x in bits. Doc: the function behaves differently according to whether $n$ is present and positive or not. If $n$ is missing, the function returns the (floating point) precision in bits of the PARI object $x$. If $x$ is an exact object, the function returns \kbd{+oo}. \bprog ? bitprecision(exp(1e-100)) %1 = 512 \\ 512 bits ? bitprecision( [ exp(1e-100), 0.5 ] ) %2 = 128 \\ minimal accuracy among components ? bitprecision(2 + x) %3 = +oo \\ exact object @eprog If $n$ is present and positive, the function creates a new object equal to $x$ with the new bit-precision roughly $n$. In fact, the smallest multiple of 64 (resp.~32 on a 32-bit machine) larger than or equal to $n$. For $x$ a vector or a matrix, the operation is done componentwise; for series and polynomials, the operation is done coefficientwise. For real $x$, $n$ is the number of desired significant \emph{bits}. If $n$ is smaller than the precision of $x$, $x$ is truncated, otherwise $x$ is extended with zeros. For exact or non-floating point types, no change. \bprog ? bitprecision(Pi, 10) \\ actually 64 bits ~ 19 decimal digits %1 = 3.141592653589793239 ? bitprecision(1, 10) %2 = 1 ? bitprecision(1 + O(x), 10) %3 = 1 + O(x) ? bitprecision(2 + O(3^5), 10) %4 = 2 + O(3^5) @eprog\noindent pari-2.11.2/src/functions/conversions/Strprintf0000644000175000017500000000063511636712103020247 0ustar billbillFunction: Strprintf Section: programming/specific C-Name: Strprintf Prototype: ss* Help: Strprintf(fmt,{x}*): returns a string built from the remaining arguments according to the format fmt. Doc: returns a string built from the remaining arguments according to the format fmt. The format consists of ordinary characters (not \%), printed unchanged, and conversions specifications. See \kbd{printf}. %\syn{NO} pari-2.11.2/src/functions/conversions/imag0000644000175000017500000000036611636712103017172 0ustar billbillFunction: imag Section: conversions C-Name: gimag Prototype: G Help: imag(x): imaginary part of x. Doc: imaginary part of $x$. When $x$ is a quadratic number, this is the coefficient of $\omega$ in the ``canonical'' integral basis $(1,\omega)$. pari-2.11.2/src/functions/conversions/sizedigit0000644000175000017500000000132513326135265020252 0ustar billbillFunction: sizedigit Section: conversions C-Name: sizedigit Prototype: lG Obsolete: 2015-01-13 Help: sizedigit(x): rough upper bound for the number of decimal digits of (the components of) x. DEPRECATED. Doc: This function is DEPRECATED, essentially meaningless, and provided for backwards compatibility only. Don't use it! outputs a quick upper bound for the number of decimal digits of (the components of) $x$, off by at most $1$. More precisely, for a positive integer $x$, it computes (approximately) the ceiling of $$\kbd{floor}(1 + \log_2 x) \log_{10}2,$$ To count the number of decimal digits of a positive integer $x$, use \kbd{\#digits(x)}. To estimate (recursively) the size of $x$, use \kbd{normlp(x)}. pari-2.11.2/src/functions/conversions/List0000644000175000017500000000125613326135265017175 0ustar billbillFunction: List Section: conversions C-Name: gtolist Prototype: DG Help: List({x=[]}): transforms the vector or list x into a list. Empty list if x is omitted. Description: ():list mklist() (gen):list listinit(gtolist($1)) Doc: transforms a (row or column) vector $x$ into a list, whose components are the entries of $x$. Similarly for a list, but rather useless in this case. For other types, creates a list with the single element $x$. Note that, except when $x$ is omitted, this function creates a small memory leak; so, either initialize all lists to the empty list, or use them sparingly. Variant: The variant \fun{GEN}{mklist}{void} creates an empty list. pari-2.11.2/src/functions/conversions/Vecsmall0000644000175000017500000000133112314242551020013 0ustar billbillFunction: Vecsmall Section: conversions C-Name: gtovecsmall0 Prototype: GD0,L, Help: Vecsmall(x, {n}): transforms the object x into a VECSMALL of dimension n. Description: (gen):vecsmall gtovecsmall($1) Doc: transforms the object $x$ into a row vector of type \typ{VECSMALL}. The dimension of the resulting vector can be optionally specified via the extra parameter $n$. This acts as \kbd{Vec}$(x,n)$, but only on a limited set of objects: the result must be representable as a vector of small integers. If $x$ is a character string, a vector of individual characters in ASCII encoding is returned (\tet{Strchr} yields back the character string). Variant: \fun{GEN}{gtovecsmall}{GEN x} is also available. pari-2.11.2/src/functions/conversions/liftpol0000644000175000017500000000131613201017466017722 0ustar billbillFunction: liftpol Section: conversions C-Name: liftpol Prototype: G Help: liftpol(x): lifts every polmod component of x to polynomials. Description: (pol):pol liftpol($1) (vec):vec liftpol($1) (gen):gen liftpol($1) Doc: recursively lift all components of $x$ which are polmods to polynomials. \typ{FFELT} are not lifted, nor are List elements: you may convert the latter to vectors first, or use \kbd{apply(liftpol,L)}. More generally, components for which such lifts are meaningless (e.g. character strings) are copied verbatim. \bprog ? liftpol(x * (1 + O(3)) + Mod(2,3)) %1 = (1 + O(3))*x + Mod(2, 3) ? liftpol(x * Mod(y,y^2+1) + Mod(2,3)*Mod(z,z^2)) %2 = y*x + Mod(2, 3)*z @eprog pari-2.11.2/src/functions/conversions/Mod0000644000175000017500000000317413201017466016774 0ustar billbillFunction: Mod Section: conversions C-Name: gmodulo Prototype: GG Help: Mod(a,b): creates 'a modulo b'. Description: (small, small):gen gmodulss($1, $2) (small, gen):gen gmodulsg($1, $2) (gen, gen):gen gmodulo($1, $2) Doc: in its basic form, creates an intmod or a polmod $(a \mod b)$; $b$ must be an integer or a polynomial. We then obtain a \typ{INTMOD} and a \typ{POLMOD} respectively: \bprog ? t = Mod(2,17); t^8 %1 = Mod(1, 17) ? t = Mod(x,x^2+1); t^2 %2 = Mod(-1, x^2+1) @eprog\noindent If $a \% b$ makes sense and yields a result of the appropriate type (\typ{INT} or scalar/\typ{POL}), the operation succeeds as well: \bprog ? Mod(1/2, 5) %3 = Mod(3, 5) ? Mod(7 + O(3^6), 3) %4 = Mod(1, 3) ? Mod(Mod(1,12), 9) %5 = Mod(1, 3) ? Mod(1/x, x^2+1) %6 = Mod(-1, x^2+1) ? Mod(exp(x), x^4) %7 = Mod(1/6*x^3 + 1/2*x^2 + x + 1, x^4) @eprog If $a$ is a complex object, ``base change'' it to $\Z/b\Z$ or $K[x]/(b)$, which is equivalent to, but faster than, multiplying it by \kbd{Mod(1,b)}: \bprog ? Mod([1,2;3,4], 2) %8 = [Mod(1, 2) Mod(0, 2)] [Mod(1, 2) Mod(0, 2)] ? Mod(3*x+5, 2) %9 = Mod(1, 2)*x + Mod(1, 2) ? Mod(x^2 + y*x + y^3, y^2+1) %10 = Mod(1, y^2 + 1)*x^2 + Mod(y, y^2 + 1)*x + Mod(-y, y^2 + 1) @eprog This function is not the same as $x$ \kbd{\%} $y$, the result of which has no knowledge of the intended modulus $y$. Compare \bprog ? x = 4 % 5; x + 1 %1 = 5 ? x = Mod(4,5); x + 1 %2 = Mod(0,5) @eprog Note that such ``modular'' objects can be lifted via \tet{lift} or \tet{centerlift}. The modulus of a \typ{INTMOD} or \typ{POLMOD} $z$ can be recovered via \kbd{$z$.mod}. pari-2.11.2/src/functions/conversions/fromdigits0000644000175000017500000000102013201017466020410 0ustar billbillFunction: fromdigits Section: conversions C-Name: fromdigits Prototype: GDG Help: fromdigits(x,{b=10}): gives the integer formed by the elements of x seen as the digits of a number in base b. Doc: gives the integer formed by the elements of $x$ seen as the digits of a number in base $b$ ($b = 10$ by default). This is the reverse of \kbd{digits}: \bprog ? digits(1234,5) %1 = [1,4,4,1,4] ? fromdigits([1,4,4,1,4],5) %2 = 1234 @eprog\noindent By convention, $0$ has no digits: \bprog ? fromdigits([]) %3 = 0 @eprog pari-2.11.2/src/functions/conversions/bittest0000644000175000017500000000170213201017466017726 0ustar billbillFunction: bittest Section: conversions C-Name: gbittest Prototype: GL Help: bittest(x,n): gives bit number n (coefficient of 2^n) of the integer x. Negative numbers behave as if modulo big power of 2. Description: (small, small):bool:parens ($(1)>>$(2))&1 (int, small):bool bittest($1, $2) (gen, small):gen gbittest($1, $2) Doc: outputs the $n^{\text{th}}$ bit of $x$ starting from the right (i.e.~the coefficient of $2^n$ in the binary expansion of $x$). The result is 0 or 1. \bprog ? bittest(7, 0) %1 = 1 \\ the bit 0 is 1 ? bittest(7, 2) %2 = 1 \\ the bit 2 is 1 ? bittest(7, 3) %3 = 0 \\ the bit 3 is 0 @eprog\noindent See \secref{se:bitand} for the behavior at negative arguments. Variant: For a \typ{INT} $x$, the variant \fun{long}{bittest}{GEN x, long n} is generally easier to use, and if furthermore $n\ge 0$ the low-level function \fun{ulong}{int_bit}{GEN x, long n} returns \kbd{bittest(abs(x),n)}. pari-2.11.2/src/functions/conversions/characteristic0000644000175000017500000000073613201017466021246 0ustar billbillFunction: characteristic Section: conversions C-Name: characteristic Prototype: mG Help: characteristic(x): characteristic of the base ring over which x is defined. Doc: returns the characteristic of the base ring over which $x$ is defined (as defined by \typ{INTMOD} and \typ{FFELT} components). The function raises an exception if incompatible primes arise from \typ{FFELT} and \typ{PADIC} components. \bprog ? characteristic(Mod(1,24)*x + Mod(1,18)*y) %1 = 6 @eprog pari-2.11.2/src/functions/graphic/0000755000175000017500000000000013461316051015372 5ustar billbillpari-2.11.2/src/functions/graphic/plotlinetype0000644000175000017500000000071713326135265020060 0ustar billbillFunction: plotlinetype Section: graphic C-Name: plotlinetype Prototype: vLL Obsolete: 2007-05-11 Help: plotlinetype(w,type): this function is obsolete; no graphing engine implement this functionality. Doc: This function is obsolete and currently a no-op. Change the type of lines subsequently plotted in rectwindow $w$. \var{type} $-2$ corresponds to frames, $-1$ to axes, larger values may correspond to something else. $w = -1$ changes highlevel plotting. pari-2.11.2/src/functions/graphic/plotpointtype0000644000175000017500000000070613326135265020260 0ustar billbillFunction: plotpointtype Section: graphic C-Name: plotpointtype Prototype: vLL Obsolete: 2007-05-11 Help: plotpointtype(w,type): this function is obsolete; no graphing engine implement this functionality. Doc: This function is obsolete and currently a no-op. change the type of points subsequently plotted in rectwindow $w$. $\var{type} = -1$ corresponds to a dot, larger values may correspond to something else. $w = -1$ changes highlevel plotting. pari-2.11.2/src/functions/graphic/plothsizes0000644000175000017500000000166413326135265017536 0ustar billbillFunction: plothsizes Section: graphic C-Name: plothsizes Prototype: D0,L, Help: plothsizes({flag=0}): returns array of 8 elements: terminal width and height, sizes for ticks in horizontal and vertical directions, width and height of characters, width and height of display (if applicable). If flag=0, sizes of ticks and characters are in pixels, otherwise are fractions of the terminal size. Doc: return data corresponding to the output window in the form of a 8-component vector: window width and height, sizes for ticks in horizontal and vertical directions (this is intended for the \kbd{gnuplot} interface and is currently not significant), width and height of characters, width and height of display, if applicable. If display has no sense, e.g. for svg plots or postscript plots, then width and height of display are set to 0. If $\fl = 0$, sizes of ticks and characters are in pixels, otherwise are fractions of the screen size pari-2.11.2/src/functions/graphic/plotexport0000644000175000017500000000135213326135265017544 0ustar billbillFunction: plotexport Section: graphic C-Name: plotexport Prototype: GGD0,L, Help: plotexport(fmt, list, {flag=0}): draw vector of rectwindows list as in plotdraw, returning the resulting picture as a character string; fmt is either "ps" or "svg". Doc: draw list of rectwindows as in \kbd{plotdraw(list,flag)}, returning the resulting picture as a character string which can then be written to a file. The format \kbd{fmt} is either \kbd{"ps"} (PostScript output) or \kbd{"svg"} (Scalable Vector Graphics). \bprog ? plotinit(0, 100, 100); ? plotbox(0, 50, 50); ? plotcolor(0, 2); ? plotbox(0, 30, 30); ? plotdraw(0); \\ watch result on screen ? s = plotexport("svg, 0); ? write("graph.svg", s); \\ dump result to file @eprog pari-2.11.2/src/functions/graphic/plotinit0000644000175000017500000000234613326135265017172 0ustar billbillFunction: plotinit Section: graphic C-Name: plotinit Prototype: vLDGDGD0,L, Help: plotinit(w,{x},{y},{flag=0}): initialize rectwindow w to size x,y. If flag!=0, x and y express fractions of the size of the current output device. Omitting x or y means use the full size of the device. Doc: initialize the rectwindow $w$, destroying any rect objects you may have already drawn in $w$. The virtual cursor is set to $(0,0)$. The rectwindow size is set to width $x$ and height $y$; omitting either $x$ or $y$ means we use the full size of the device in that direction. If $\fl=0$, $x$ and $y$ represent pixel units. Otherwise, $x$ and $y$ are understood as fractions of the size of the current output device (hence must be between $0$ and $1$) and internally converted to pixels. The plotting device imposes an upper bound for $x$ and $y$, for instance the number of pixels for screen output. These bounds are available through the \tet{plothsizes} function. The following sequence initializes in a portable way (i.e independent of the output device) a window of maximal size, accessed through coordinates in the $[0,1000] \times [0,1000]$ range: \bprog s = plothsizes(); plotinit(0, s[1]-1, s[2]-1); plotscale(0, 0,1000, 0,1000); @eprog pari-2.11.2/src/functions/graphic/plothexport0000644000175000017500000000217413326135265017717 0ustar billbillFunction: plothexport Section: graphic C-Name: plothexport0 Wrapper: (,,G) Description: (gen,gen,gen,gen,?0,?0):gen:prec plothexport($1, ${4 cookie}, ${4 wrapper}, $2, $3, $5, $6, $prec) Prototype: GV=GGED0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 Help: plothexport(fmt, X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution, returning the resulting picture as a character string which can then be written to a file. Doc: plot of expression \var{expr}, $X$ goes from $a$ to $b$ in high resolution, returning the resulting picture as a character string which can then be written to a file. The format \kbd{fmt} is either \kbd{"ps"} (PostScript output) or \kbd{"svg"} (Scalable Vector Graphics). All other parameters and flags are as in \kbd{ploth}. \bprog ? s = plothexport("svg", x=1,10, x^2+3); ? write("graph.svg", s); @eprog \synt{plothexport}{GEN fmt, void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long flags, long n, long prec}, pari-2.11.2/src/functions/graphic/psdraw0000644000175000017500000000032713326135265016625 0ustar billbillFunction: psdraw Section: graphic C-Name: psdraw Prototype: vGD0,L, Obsolete: 2018-02-01 Help: psdraw(list, {flag=0}): obsolete function. Doc: This function is obsolete, use plotexport and write the result to file. pari-2.11.2/src/functions/graphic/plotstring0000644000175000017500000000160613326135265017533 0ustar billbillFunction: plotstring Section: graphic C-Name: plotstring Prototype: vLsD0,L, Help: plotstring(w,x,{flags=0}): draw in rectwindow w the string corresponding to x. Bits 1 and 2 of flag regulate horizontal alignment: left if 0, right if 2, center if 1. Bits 4 and 8 regulate vertical alignment: bottom if 0, top if 8, v-center if 4. Can insert additional gap between point and string: horizontal if bit 16 is set, vertical if bit 32 is set. Doc: draw on the rectwindow $w$ the String $x$ (see \secref{se:strings}), at the current position of the cursor. \fl\ is used for justification: bits 1 and 2 regulate horizontal alignment: left if 0, right if 2, center if 1. Bits 4 and 8 regulate vertical alignment: bottom if 0, top if 8, v-center if 4. Can insert additional small gap between point and string: horizontal if bit 16 is set, vertical if bit 32 is set (see the tutorial for an example). pari-2.11.2/src/functions/graphic/plotrpoint0000644000175000017500000000143013326135265017533 0ustar billbillFunction: plotrpoint Section: graphic C-Name: plotrpoint Prototype: vLGG Help: plotrpoint(w,dx,dy): draw a point (and move cursor) at position dx,dy relative to present position of the cursor in rectwindow w. Doc: draw the point $(x1+dx,y1+dy)$ on the rectwindow $w$ (if it is inside $w$), where $(x1,y1)$ is the current position of the cursor, and in any case move the virtual cursor to position $(x1+dx,y1+dy)$. If you draw few points in the rectwindow, they will be hard to see; in this case, you can use filled boxes instead. Compare: \bprog ? plotinit(0, 100,100); plotrpoint(0, 50,50); plotrpoint(0, 10,10); ? plotdraw(0) ? thickpoint(w,x,y)= plotmove(w,x-2,y-2); plotrbox(w,4,4,1); ? plotinit(1, 100,100); thickpoint(1, 50,50); thickpoint(1, 60,60); ? plotdraw(1) @eprog pari-2.11.2/src/functions/graphic/psplothraw0000644000175000017500000000035513326135265017531 0ustar billbillFunction: psplothraw Section: graphic C-Name: psplothraw Prototype: GGD0,L, Obsolete: 2018-02-01 Help: psplothraw(listx,listy,{flag=0}): obsolete function. Doc: This function is obsolete, use plothrawexport and write the result to file. pari-2.11.2/src/functions/graphic/plotpoints0000644000175000017500000000223513326135265017540 0ustar billbillFunction: plotpoints Section: graphic C-Name: plotpoints Prototype: vLGG Help: plotpoints(w,X,Y): draws in rectwindow w the points whose x (resp y) coordinates are in X (resp Y). If X and Y are both single values (i.e not vectors), draw the corresponding point (and move cursor). Doc: draw on the rectwindow $w$ the points whose $(x,y)$-coordinates are in the vectors of equal length $X$ and $Y$ and which are inside $w$. The virtual cursor does \emph{not} move. This is basically the same function as \kbd{plothraw}, but either with no scaling factor or with a scale chosen using the function \kbd{plotscale}. As was the case with the \kbd{plotlines} function, $X$ and $Y$ are allowed to be (simultaneously) scalar. In this case, draw the single point $(X,Y)$ on the rectwindow $w$ (if it is actually inside $w$), and in any case \emph{move} the virtual cursor to position $(x,y)$. If you draw few points in the rectwindow, they will be hard to see; in this case, you can use filled boxes instead. Compare: \bprog ? plotinit(0, 100,100); plotpoints(0, 50,50); ? plotdraw(0) ? plotinit(1, 100,100); plotmove(1,48,48); plotrbox(1, 4,4, 1); ? plotdraw(1) @eprog pari-2.11.2/src/functions/graphic/plotrecth0000644000175000017500000000107513326135265017332 0ustar billbillFunction: plotrecth Section: graphic C-Name: plotrecth0 Prototype: LV=GGED0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 Help: plotrecth(w,X=a,b,expr,{flag=0},{n=0}): writes to rectwindow w the curve output of ploth(w,X=a,b,expr,flag,n). Returns a vector for the bounding box. Doc: writes to rectwindow $w$ the curve output of \kbd{ploth}$(w,X=a,b,\var{expr},\fl,n)$. Returns a vector for the bounding box. %\syn{NO} pari-2.11.2/src/functions/graphic/plothraw0000644000175000017500000000126513326135265017167 0ustar billbillFunction: plothraw Section: graphic C-Name: plothraw Prototype: GGD0,L, Help: plothraw(X,Y,{flag=0}): plot in high resolution points whose x (resp. y) coordinates are in X (resp. Y). If flag is 1, join points, other non-0 flags should be combinations of bits 8,16,32,64,128,256 meaning the same as for ploth(). Doc: given $X$ and $Y$ two vectors of equal length, plots (in high precision) the points whose $(x,y)$-coordinates are given in $X$ and $Y$. Automatic positioning and scaling is done, but with the same scaling factor on $x$ and $y$. If $\fl$ is 1, join points, other non-0 flags toggle display options and should be combinations of bits $2^k$, $k \geq 3$ as in \kbd{ploth}. pari-2.11.2/src/functions/graphic/plotcursor0000644000175000017500000000040313326135265017534 0ustar billbillFunction: plotcursor Section: graphic C-Name: plotcursor Prototype: L Help: plotcursor(w): current position of cursor in rectwindow w. Doc: give as a 2-component vector the current (scaled) position of the virtual cursor corresponding to the rectwindow $w$. pari-2.11.2/src/functions/graphic/plotbox0000644000175000017500000000112213326135265017006 0ustar billbillFunction: plotbox Section: graphic C-Name: plotbox Prototype: vLGGD0,L, Help: plotbox(w,x2,y2,{filled=0}): if the cursor is at position (x1,y1), draw a box with diagonal (x1,y1) and (x2,y2) in rectwindow w (cursor does not move). If filled=1, fill the box. Doc: let $(x1,y1)$ be the current position of the virtual cursor. Draw in the rectwindow $w$ the outline of the rectangle which is such that the points $(x1,y1)$ and $(x2,y2)$ are opposite corners. Only the part of the rectangle which is in $w$ is drawn. The virtual cursor does \emph{not} move. If $\var{filled}=1$, fill the box. pari-2.11.2/src/functions/graphic/plotclip0000644000175000017500000000066213326135265017155 0ustar billbillFunction: plotclip Section: graphic C-Name: plotclip Prototype: vL Help: plotclip(w): clip the contents of the rectwindow to the bounding box (except strings). Doc: `clips' the content of rectwindow $w$, i.e remove all parts of the drawing that would not be visible on the screen. Together with \tet{plotcopy} this function enables you to draw on a scratchpad before committing the part you're interested in to the final picture. pari-2.11.2/src/functions/graphic/plotkill0000644000175000017500000000063513326135265017161 0ustar billbillFunction: plotkill Section: graphic C-Name: plotkill Prototype: vL Help: plotkill(w): erase the rectwindow w. Doc: erase rectwindow $w$ and free the corresponding memory. Note that if you want to use the rectwindow $w$ again, you have to use \kbd{plotinit} first to specify the new size. So it's better in this case to use \kbd{plotinit} directly as this throws away any previous work in the given rectwindow. pari-2.11.2/src/functions/graphic/HEADER0000644000175000017500000000757013326135265016264 0ustar billbillFunction: _header_graphic Class: header Section: graphic Doc: \section{Plotting functions} Although plotting is not even a side purpose of PARI, a number of plotting functions are provided. There are three types of graphic functions. \subsec{High-level plotting functions} (all the functions starting with \kbd{ploth}) in which the user has little to do but explain what type of plot he wants, and whose syntax is similar to the one used in the preceding section. \subsec{Low-level plotting functions} (called \var{rectplot} functions, sharing the prefix \kbd{plot}), where every drawing primitive (point, line, box, etc.) is specified by the user. These low-level functions work as follows. You have at your disposal 16 virtual windows which are filled independently, and can then be physically ORed on a single window at user-defined positions. These windows are numbered from 0 to 15, and must be initialized before being used by the function \kbd{plotinit}, which specifies the height and width of the virtual window (called a \var{rectwindow} in the sequel). At all times, a virtual cursor (initialized at $[0,0]$) is attached to the window, and its current value can be obtained using the function \kbd{plotcursor}. A number of primitive graphic objects (called \var{rect} objects) can then be drawn in these windows, using a default color attached to that window (which can be changed using the \kbd{plotcolor} function) and only the part of the object which is inside the window will be drawn, with the exception of polygons and strings which are drawn entirely. The ones sharing the prefix \kbd{plotr} draw relatively to the current position of the virtual cursor, the others use absolute coordinates. Those having the prefix \kbd{plotrecth} put in the rectwindow a large batch of rect objects corresponding to the output of the related \kbd{ploth} function. Finally, the actual physical drawing is done using \kbd{plotdraw}. The rectwindows are preserved so that further drawings using the same windows at different positions or different windows can be done without extra work. To erase a window, use \kbd{plotkill}. It is not possible to partially erase a window: erase it completely, initialize it again, then fill it with the graphic objects that you want to keep. In addition to initializing the window, you may use a scaled window to avoid unnecessary conversions. For this, use \kbd{plotscale}. As long as this function is not called, the scaling is simply the number of pixels, the origin being at the upper left and the $y$-coordinates going downwards. Plotting functions are platform independent, but a number of graphical drivers are available for screen output: X11-windows (including Openwindows and Motif), Windows's Graphical Device Interface, the Qt and FLTK graphical libraries and one may even write the graphical objects to a PostScript or SVG file and use an external viewer to open it. The physical window opened by \kbd{plotdraw} or any of the \kbd{ploth*} functions is completely separated from \kbd{gp} (technically, a \kbd{fork} is done, and the non-graphical memory is immediately freed in the child process), which means you can go on working in the current \kbd{gp} session, without having to kill the window first. This window can be closed, enlarged or reduced using the standard window manager functions. No zooming procedure is implemented though. \subsec{Functions for PostScript or SVG output} in the same way that \kbd{printtex} allows you to have a \TeX\ output corresponding to printed results, the functions \kbd{plotexport}, \kbd{plothexport} and \kbd{plothrawexport} convert a plot to a character string in either \tet{PostScript} or \tet{Scalable Vector Graphics} format. This string can then be written to a file in the customary way, using \kbd{write}. These export routines are available even if no Graphic Library is. \smallskip pari-2.11.2/src/functions/graphic/ploth0000644000175000017500000001250213326135265016451 0ustar billbillFunction: ploth Section: graphic C-Name: ploth0 Wrapper: (,,G) Description: (gen,gen,gen,?0,?0):gen:prec ploth(${3 cookie}, ${3 wrapper}, $1, $2, $4, $5, $prec) Prototype: V=GGED0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 Help: ploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean: 1=Parametric, 2=Recursive, 4=no_Rescale, 8=no_X_axis, 16=no_Y_axis, 32=no_Frame, 64=no_Lines (do not join points), 128=Points_too (plot both lines and points), 256=Splines (use cubic splines), 512=no_X_ticks, 1024= no_Y_ticks, 2048=Same_ticks (plot all ticks with the same length), 4096=Complex (the two coordinates of each point are encoded as a complex number). n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box. Doc: high precision plot of the function $y=f(x)$ represented by the expression \var{expr}, $x$ going from $a$ to $b$. This opens a specific window (which is killed whenever you click on it), and returns a four-component vector giving the coordinates of the bounding box in the form $[\var{xmin},\var{xmax},\var{ymin},\var{ymax}]$. \misctitle{Important note} \kbd{ploth} may evaluate \kbd{expr} thousands of times; given the relatively low resolution of plotting devices, few significant digits of the result will be meaningful. Hence you should keep the current precision to a minimum (e.g.~9) before calling this function. $n$ specifies the number of reference point on the graph, where a value of 0 means we use the hardwired default values (1000 for general plot, 1500 for parametric plot, and 8 for recursive plot). If no $\fl$ is given, \var{expr} is either a scalar expression $f(X)$, in which case the plane curve $y=f(X)$ will be drawn, or a vector $[f_1(X),\dots,f_k(X)]$, and then all the curves $y=f_i(X)$ will be drawn in the same window. \noindent The binary digits of $\fl$ mean: \item $1 = \kbd{Parametric}$: \tev{parametric plot}. Here \var{expr} must be a vector with an even number of components. Successive pairs are then understood as the parametric coordinates of a plane curve. Each of these are then drawn. For instance: \bprog ploth(X=0,2*Pi,[sin(X),cos(X)], "Parametric") ploth(X=0,2*Pi,[sin(X),cos(X)]) ploth(X=0,2*Pi,[X,X,sin(X),cos(X)], "Parametric") @eprog\noindent draw successively a circle, two entwined sinusoidal curves and a circle cut by the line $y=x$. \item $2 = \kbd{Recursive}$: \tev{recursive plot}. If this flag is set, only \emph{one} curve can be drawn at a time, i.e.~\var{expr} must be either a two-component vector (for a single parametric curve, and the parametric flag \emph{has} to be set), or a scalar function. The idea is to choose pairs of successive reference points, and if their middle point is not too far away from the segment joining them, draw this as a local approximation to the curve. Otherwise, add the middle point to the reference points. This is fast, and usually more precise than usual plot. Compare the results of \bprog ploth(X=-1,1, sin(1/X), "Recursive") ploth(X=-1,1, sin(1/X)) @eprog\noindent for instance. But beware that if you are extremely unlucky, or choose too few reference points, you may draw some nice polygon bearing little resemblance to the original curve. For instance you should \emph{never} plot recursively an odd function in a symmetric interval around 0. Try \bprog ploth(x = -20, 20, sin(x), "Recursive") @eprog\noindent to see why. Hence, it's usually a good idea to try and plot the same curve with slightly different parameters. The other values toggle various display options: \item $4 = \kbd{no\_Rescale}$: do not rescale plot according to the computed extrema. This is used in conjunction with \tet{plotscale} when graphing multiple functions on a rectwindow (as a \tet{plotrecth} call): \bprog s = plothsizes(); plotinit(0, s[2]-1, s[2]-1); plotscale(0, -1,1, -1,1); plotrecth(0, t=0,2*Pi, [cos(t),sin(t)], "Parametric|no_Rescale") plotdraw([0, -1,1]); @eprog\noindent This way we get a proper circle instead of the distorted ellipse produced by \bprog ploth(t=0,2*Pi, [cos(t),sin(t)], "Parametric") @eprog \item $8 = \kbd{no\_X\_axis}$: do not print the $x$-axis. \item $16 = \kbd{no\_Y\_axis}$: do not print the $y$-axis. \item $32 = \kbd{no\_Frame}$: do not print frame. \item $64 = \kbd{no\_Lines}$: only plot reference points, do not join them. \item $128 = \kbd{Points\_too}$: plot both lines and points. \item $256 = \kbd{Splines}$: use splines to interpolate the points. \item $512 = \kbd{no\_X\_ticks}$: plot no $x$-ticks. \item $1024 = \kbd{no\_Y\_ticks}$: plot no $y$-ticks. \item $2048 = \kbd{Same\_ticks}$: plot all ticks with the same length. \item $4096 = \kbd{Complex}$: is a parametric plot but where each member of \kbd{expr} is considered a complex number encoding the two coordinates of a point. For instance: \bprog ploth(X=0,2*Pi,exp(I*X), "Complex") ploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex") @eprog\noindent will draw respectively a circle and a circle cut by the line $y=x$. \synt{ploth}{void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long flags, long n, long prec}, pari-2.11.2/src/functions/graphic/plotcolor0000644000175000017500000000250213326135265017337 0ustar billbillFunction: plotcolor Section: graphic C-Name: plotcolor Prototype: LG Help: plotcolor(w,c): in rectwindow w, set default color to c. Possible values for c are [R,G,B] values, a color name or an index in the graphcolormap default: factory settings are 1=black, 2=blue, 3=sienna, 4=red, 5=green, 6=grey, 7=gainsborough. Return [R,G,B] value attached to color. Doc: set default color to $c$ in rectwindow $w$. Return [R,G,B] value attached to color. Possible values for $c$ are \item a \typ{VEC} or \typ{VECSMALL} $[R,G,B]$ giving the color RGB value (all 3 values are between 0 and 255), e.g. \kbd{[250,235,215]} or equivalently \kbd{[0xfa, 0xeb, 0xd7]} for \kbd{antiquewhite}; \item a \typ{STR} giving a valid colour name (see the \kbd{rgb.txt} file in X11 distributions), e.g. \kbd{"antiquewhite"} or an RGV value given by a \kbd{\#} followed by 6 hexadecimal digits, e.g. \kbd{"\#faebd7"} for \kbd{antiquewhite}; \item a \typ{INT}, an index in the \tet{graphcolormap} default, factory setting are 1=black, 2=blue, 3=violetred, 4=red, 5=green, 6=grey, 7=gainsborough. but this can be extended if needed. \bprog ? plotinit(0,100,100); ? plotcolor(0, "turquoise") %2 = [64, 224, 208] ? plotbox(0, 50,50,1); ? plotmove(0, 50,50); ? plotcolor(0, 2) \\ blue %4 = [0, 0, 255] ? plotbox(0, 50,50,1); ? plotdraw(0); @eprog pari-2.11.2/src/functions/graphic/plotlines0000644000175000017500000000232013326135265017331 0ustar billbillFunction: plotlines Section: graphic C-Name: plotlines Prototype: vLGGD0,L, Help: plotlines(w,X,Y,{flag=0}): draws an open polygon in rectwindow w where X and Y contain the x (resp. y) coordinates of the vertices. If X and Y are both single values (i.e not vectors), draw the corresponding line (and move cursor). If (optional) flag is non-zero, close the polygon. Doc: draw on the rectwindow $w$ the polygon such that the (x,y)-coordinates of the vertices are in the vectors of equal length $X$ and $Y$. For simplicity, the whole polygon is drawn, not only the part of the polygon which is inside the rectwindow. If $\fl$ is non-zero, close the polygon. In any case, the virtual cursor does not move. $X$ and $Y$ are allowed to be scalars (in this case, both have to). There, a single segment will be drawn, between the virtual cursor current position and the point $(X,Y)$. And only the part thereof which actually lies within the boundary of $w$. Then \emph{move} the virtual cursor to $(X,Y)$, even if it is outside the window. If you want to draw a line from $(x1,y1)$ to $(x2,y2)$ where $(x1,y1)$ is not necessarily the position of the virtual cursor, use \kbd{plotmove(w,x1,y1)} before using this function. pari-2.11.2/src/functions/graphic/plotrmove0000644000175000017500000000057513326135265017361 0ustar billbillFunction: plotrmove Section: graphic C-Name: plotrmove Prototype: vLGG Help: plotrmove(w,dx,dy): move cursor to position (dx,dy) relative to the present position in the rectwindow w. Doc: move the virtual cursor of the rectwindow $w$ to position $(x1+dx,y1+dy)$, where $(x1,y1)$ is the initial position of the cursor (i.e.~to position $(dx,dy)$ relative to the initial cursor). pari-2.11.2/src/functions/graphic/plotmove0000644000175000017500000000032113326135265017164 0ustar billbillFunction: plotmove Section: graphic C-Name: plotmove Prototype: vLGG Help: plotmove(w,x,y): move cursor to position x,y in rectwindow w. Doc: move the virtual cursor of the rectwindow $w$ to position $(x,y)$. pari-2.11.2/src/functions/graphic/plotrecthraw0000644000175000017500000000164313326135265020045 0ustar billbillFunction: plotrecthraw Section: graphic C-Name: plotrecthraw Prototype: LGD0,L, Help: plotrecthraw(w,data,{flags=0}): plot graph(s) for data in rectwindow w, where data is a vector of vectors. If plot is parametric, length of data should be even, and pairs of entries give curves to plot. If not, first entry gives x-coordinate, and the other ones y-coordinates. Admits the same optional flags as plotrecth, save that recursive plot is meaningless. Doc: plot graph(s) for \var{data} in rectwindow $w$. $\fl$ has the same significance here as in \kbd{ploth}, though recursive plot is no more significant. \var{data} is a vector of vectors, each corresponding to a list a coordinates. If parametric plot is set, there must be an even number of vectors, each successive pair corresponding to a curve. Otherwise, the first one contains the $x$ coordinates, and the other ones contain the $y$-coordinates of curves to plot. pari-2.11.2/src/functions/graphic/plotrline0000644000175000017500000000071613326135265017337 0ustar billbillFunction: plotrline Section: graphic C-Name: plotrline Prototype: vLGG Help: plotrline(w,dx,dy): if the cursor is at (x1,y1), draw a line from (x1,y1) to (x1+dx,y1+dy) (and move the cursor) in the rectwindow w. Doc: draw in the rectwindow $w$ the part of the segment $(x1,y1)-(x1+dx,y1+dy)$ which is inside $w$, where $(x1,y1)$ is the current position of the virtual cursor, and move the virtual cursor to $(x1+dx,y1+dy)$ (even if it is outside the window). pari-2.11.2/src/functions/graphic/plotrbox0000644000175000017500000000111413326135265017171 0ustar billbillFunction: plotrbox Section: graphic C-Name: plotrbox Prototype: vLGGD0,L, Help: plotrbox(w,dx,dy,{filled}): if the cursor is at (x1,y1), draw a box with diagonal (x1,y1)-(x1+dx,y1+dy) in rectwindow w (cursor does not move). If filled=1, fill the box. Doc: draw in the rectwindow $w$ the outline of the rectangle which is such that the points $(x1,y1)$ and $(x1+dx,y1+dy)$ are opposite corners, where $(x1,y1)$ is the current position of the cursor. Only the part of the rectangle which is in $w$ is drawn. The virtual cursor does \emph{not} move. If $\var{filled}=1$, fill the box. pari-2.11.2/src/functions/graphic/plotpointsize0000644000175000017500000000056613326135265020255 0ustar billbillFunction: plotpointsize Section: graphic C-Name: plotpointsize Prototype: vLG Obsolete: 2007-05-11 Help: plotpointsize(w,size): change the "size" of following points in rectwindow w. w=-1 changes global value. Doc: This function is obsolete. It is currently a no-op. Changes the ``size'' of following points in rectwindow $w$. If $w = -1$, change it in all rectwindows. pari-2.11.2/src/functions/graphic/plotdraw0000644000175000017500000000161213326135265017157 0ustar billbillFunction: plotdraw Section: graphic C-Name: plotdraw Prototype: vGD0,L, Help: plotdraw(w, {flag=0}): draw rectwindow w. More generally, w can be of the form [w1,x1,y1, w2,x2,y2,etc.]: draw rectwindows wi at given xi,yi positions. If flag!=0, the xi,yi express fractions of the size of the current output device. Doc: physically draw the rectwindow $w$. More generally, $w$ can be of the form $[w_1,x_1,y_1,w_2,x_2,y_2,\dots]$ (number of components must be divisible by $3$; the windows $w_1$, $w_2$, etc.~are physically placed with their upper left corner at physical position $(x_1,y_1)$, $(x_2,y_2)$,\dots\ respectively, and are then drawn together. Overlapping regions will thus be drawn twice, and the windows are considered transparent. Then display the whole drawing in a window on your screen. If $\fl \neq 0$, $x_1$, $y_1$ etc. express fractions of the size of the current output device pari-2.11.2/src/functions/graphic/plotcopy0000644000175000017500000000153613326135265017201 0ustar billbillFunction: plotcopy Section: graphic C-Name: plotcopy Prototype: vLLGGD0,L, Help: plotcopy(sourcew,destw,dx,dy,{flag=0}): copy the contents of rectwindow sourcew to rectwindow destw with offset (dx,dy). If flag's bit 1 is set, dx and dy express fractions of the size of the current output device, otherwise dx and dy are in pixels. dx and dy are relative positions of northwest corners if other bits of flag vanish, otherwise of: 2: southwest, 4: southeast, 6: northeast corners. Doc: copy the contents of rectwindow \var{sourcew} to rectwindow \var{destw} with offset (dx,dy). If flag's bit 1 is set, dx and dy express fractions of the size of the current output device, otherwise dx and dy are in pixels. dx and dy are relative positions of northwest corners if other bits of flag vanish, otherwise of: 2: southwest, 4: southeast, 6: northeast corners pari-2.11.2/src/functions/graphic/plotscale0000644000175000017500000000132613326135265017313 0ustar billbillFunction: plotscale Section: graphic C-Name: plotscale Prototype: vLGGGG Help: plotscale(w,x1,x2,y1,y2): scale the coordinates in rectwindow w so that x goes from x1 to x2 and y from y1 to y2 (y2=d in the standard basis of H^1_dR(X) to absolute p-adic precision p^n. Doc: Let $X$ be the curve defined by $y^2=Q(x)$, where $Q$ is a polynomial of degree $d$ over $\Q$ and $p\ge d$ a prime such that $X$ has good reduction at $p$ return the matrix of the Frobenius endomorphism $\varphi$ on the crystalline module $D_p(X) = \Q_p \otimes H^1_{dR}(X/\Q)$ with respect to the basis of the given model $(\omega, x\*\omega,\ldots,x^{g-1}\*\omega)$, where $\omega = dx/(2\*y)$ is the invariant differential, where $g$ is the genus of $X$ (either $d=2\*g+1$ or $d=2\*g+2$). The characteristic polynomial of $\varphi$ is the numerator of the zeta-function of the reduction of the curve $X$ modulo $p$. The matrix is computed to absolute $p$-adic precision $p^n$. pari-2.11.2/src/functions/elliptic_curves/ellmul0000644000175000017500000000203612314242551020366 0ustar billbillFunction: ellmul Section: elliptic_curves C-Name: ellmul Prototype: GGG Help: ellmul(E,z,n): n times the point z on elliptic curve E (n in Z). Doc: computes $[n]z$, where $z$ is a point on the elliptic curve $E$. The exponent $n$ is in $\Z$, or may be a complex quadratic integer if the curve $E$ has complex multiplication by $n$ (if not, an error message is issued). \bprog ? Ei = ellinit([1,0]); z = [0,0]; ? ellmul(Ei, z, 10) %2 = [0] \\ unsurprising: z has order 2 ? ellmul(Ei, z, I) %3 = [0, 0] \\ Ei has complex multiplication by Z[i] ? ellmul(Ei, z, quadgen(-4)) %4 = [0, 0] \\ an alternative syntax for the same query ? Ej = ellinit([0,1]); z = [-1,0]; ? ellmul(Ej, z, I) *** at top-level: ellmul(Ej,z,I) *** ^-------------- *** ellmul: not a complex multiplication in ellmul. ? ellmul(Ej, z, 1+quadgen(-3)) %6 = [1 - w, 0] @eprog The simple-minded algorithm for the CM case assumes that we are in characteristic $0$, and that the quadratic order to which $n$ belongs has small discriminant. pari-2.11.2/src/functions/elliptic_curves/ellgenerators0000644000175000017500000000274513326135265021760 0ustar billbillFunction: ellgenerators Section: elliptic_curves C-Name: ellgenerators Prototype: G Help: ellgenerators(E): if E is an elliptic curve over the rationals, return the generators of the Mordell-Weil group attached to the curve. This relies on the curve being referenced in the elldata database. If E is an elliptic curve over a finite field Fq as output by ellinit(), return a minimal set of generators for the group E(Fq). Doc: If $E$ is an elliptic curve over the rationals, return a $\Z$-basis of the free part of the \idx{Mordell-Weil group} attached to $E$. This relies on the \tet{elldata} database being installed and referencing the curve, and so is only available for curves over $\Z$ of small conductors. If $E$ is an elliptic curve over a finite field $\F_q$ as output by \tet{ellinit}, return a minimal set of generators for the group $E(\F_q)$. \misctitle{Caution} when the group is not cyclic, of shape $\Z/d_1\Z \times \Z/d_2\Z$ with $d_2\mid d_1$, the points $[P,Q]$ returned by ellgenerators need not have order $d_1$ and $d_2$: it is true that $P$ has order $d_1$, but we only know that $Q$ is a generator of $E(\F_q)/

$ and that the Weil pairing $w(P,Q)$ has order $d_2$, see \kbd{??ellgroup}. If you need generators $[P,R]$ with $R$ of order $d_2$, find $x$ such that $R = Q-[x]P$ has order $d_2$ by solving the discrete logarithm problem $[d_2]Q = [x]([d_2]P)$ in a cyclic group of order $d_1/d_2$. This will be very expensive if $d_1/d_2$ has a large prime factor. pari-2.11.2/src/functions/elliptic_curves/elleisnum0000644000175000017500000000236613201017466021100 0ustar billbillFunction: elleisnum Section: elliptic_curves C-Name: elleisnum Prototype: GLD0,L,p Help: elleisnum(w,k,{flag=0}): k being an even positive integer, computes the numerical value of the Eisenstein series of weight k at the lattice w, as given by ellperiods. When flag is non-zero and k=4 or 6, this gives the elliptic invariants g2 or g3 with the correct normalization. Doc: $k$ being an even positive integer, computes the numerical value of the Eisenstein series of weight $k$ at the lattice $w$, as given by \tet{ellperiods}, namely $$ (2i \pi/\omega_2)^k \Big(1 + 2/\zeta(1-k) \sum_{n\geq 1} n^{k-1}q^n / (1-q^n)\Big), $$ where $q = \exp(2i\pi \tau)$ and $\tau:=\omega_1/\omega_2$ belongs to the complex upper half-plane. It is also possible to directly input $w = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit}. \bprog ? w = ellperiods([1,I]); ? elleisnum(w, 4) %2 = 2268.8726415508062275167367584190557607 ? elleisnum(w, 6) %3 = -3.977978632282564763 E-33 ? E = ellinit([1, 0]); ? elleisnum(E, 4, 1) %5 = -47.999999999999999999999999999999999998 @eprog When \fl\ is non-zero and $k=4$ or 6, returns the elliptic invariants $g_2$ or $g_3$, such that $$y^2 = 4x^3 - g_2 x - g_3$$ is a Weierstrass equation for $E$. pari-2.11.2/src/functions/elliptic_curves/ellidentify0000644000175000017500000000130112314242551021376 0ustar billbillFunction: ellidentify Section: elliptic_curves C-Name: ellidentify Prototype: G Help: ellidentify(E): look up the elliptic curve E in the elldata database and return [[N, M, ...], C] where N is the name of the curve in Cremona's database, M the minimal model and C the coordinates change (see ellchangecurve). Doc: look up the elliptic curve $E$, defined by an arbitrary model over $\Q$, in the \tet{elldata} database. Return \kbd{[[N, M, G], C]} where $N$ is the curve name in Cremona's elliptic curve database, $M$ is the minimal model, $G$ is a $\Z$-basis of the free part of the \idx{Mordell-Weil group} $E(\Q)$ and $C$ is the change of coordinates change, suitable for \kbd{ellchangecurve}. pari-2.11.2/src/functions/elliptic_curves/hyperellcharpoly0000644000175000017500000000133313201017466022462 0ustar billbillFunction: hyperellcharpoly Section: elliptic_curves C-Name: hyperellcharpoly Prototype: G Help: hyperellcharpoly(X): X being a non-singular hyperelliptic curve defined over a finite field, return the characteristic polynomial of the Frobenius automorphism. X can be given either by a squarefree polynomial P such that X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)*y=P(x) and Q^2+4P is squarefree. Doc: $X$ being a non-singular hyperelliptic curve defined over a finite field, return the characteristic polynomial of the Frobenius automorphism. $X$ can be given either by a squarefree polynomial $P$ such that $X: y^2 = P(x)$ or by a vector $[P,Q]$ such that $X: y^2 + Q(x)\*y = P(x)$ and $Q^2+4\*P$ is squarefree. pari-2.11.2/src/functions/elliptic_curves/ellcard0000644000175000017500000000334413326135265020514 0ustar billbillFunction: ellcard Section: elliptic_curves C-Name: ellcard Prototype: GDG Help: ellcard(E,{p}): given an elliptic curve E defined over a finite field Fq, return the order of the group E(Fq); for other fields of definition K, p must define a finite residue field, (p prime for K = Qp or Q; p a maximal ideal for K a number field), return the order of the (non-singular) reduction of E. Doc: Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached to an elliptic curve $E/K$. If $K = \F_q$ is finite, return the order of the group $E(\F_q)$. \bprog ? E = ellinit([-3,1], 5); ellcard(E) %1 = 7 ? t = ffgen(3^5,'t); E = ellinit([t,t^2+1]); ellcard(E) %2 = 217 @eprog\noindent For other fields of definition and $p$ defining a finite residue field $\F_q$, return the order of the reduction of $E$: the argument $p$ is best left omitted if $K = \Q_\ell$ (else we must have $p = \ell$) and must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) with residue field $\F_q$ otherwise. The equation need not be minimal or even integral at $p$; of course, a minimal model will be more efficient. The function considers the group of non-singular points of the reduction of a minimal model of the curve at $p$, so also makes sense when the curve has bad reduction. \bprog ? E = ellinit([-3,1]); ? factor(E.disc) %2 = [2 4] [3 4] ? ellcard(E, 5) \\ as above ! %3 = 7 ? ellcard(E, 2) \\ additive reduction %4 = 2 @eprog When the characteristic of the finite field is large, the availability of the \kbd{seadata} package will speed the computation. See also \tet{ellap} for the list of implemented algorithms. Variant: Also available is \fun{GEN}{ellcard}{GEN E, GEN p} where $p$ is not \kbd{NULL}. pari-2.11.2/src/functions/elliptic_curves/ellj0000644000175000017500000000043111636712103020020 0ustar billbillFunction: ellj Section: elliptic_curves C-Name: jell Prototype: Gp Help: ellj(x): elliptic j invariant of x. Doc: elliptic $j$-invariant. $x$ must be a complex number with positive imaginary part, or convertible into a power series or a $p$-adic number with positive valuation. pari-2.11.2/src/functions/elliptic_curves/elltaniyama0000644000175000017500000000207513201017466021400 0ustar billbillFunction: elltaniyama Section: elliptic_curves C-Name: elltaniyama Prototype: GDP Help: elltaniyama(E, {d = seriesprecision}): modular parametrization of elliptic curve E/Q. Doc: computes the modular parametrization of the elliptic curve $E/\Q$, where $E$ is an \kbd{ell} structure as output by \kbd{ellinit}. This returns a two-component vector $[u,v]$ of power series, given to $d$ significant terms (\tet{seriesprecision} by default), characterized by the following two properties. First the point $(u,v)$ satisfies the equation of the elliptic curve. Second, let $N$ be the conductor of $E$ and $\Phi: X_0(N)\to E$ be a modular parametrization; the pullback by $\Phi$ of the N\'eron differential $du/(2v+a_1u+a_3)$ is equal to $2i\pi f(z)dz$, a holomorphic differential form. The variable used in the power series for $u$ and $v$ is $x$, which is implicitly understood to be equal to $\exp(2i\pi z)$. The algorithm assumes that $E$ is a \emph{strong} \idx{Weil curve} and that the Manin constant is equal to 1: in fact, $f(x) = \sum_{n > 0} \kbd{ellan}(E, n) x^n$. pari-2.11.2/src/functions/elliptic_curves/ellchangecurve0000644000175000017500000000112713201017466022064 0ustar billbillFunction: ellchangecurve Section: elliptic_curves C-Name: ellchangecurve Prototype: GG Help: ellchangecurve(E,v): change data on elliptic curve according to v=[u,r,s,t]. Description: (gen, gen):ell ellchangecurve($1, $2) Doc: changes the data for the elliptic curve $E$ by changing the coordinates using the vector \kbd{v=[u,r,s,t]}, i.e.~if $x'$ and $y'$ are the new coordinates, then $x=u^2x'+r$, $y=u^3y'+su^2x'+t$. $E$ must be an \kbd{ell} structure as output by \kbd{ellinit}. The special case $v = 1$ is also used instead of $[1,0,0,0]$ to denote the trivial coordinate change. pari-2.11.2/src/functions/elliptic_curves/ellchangepoint0000644000175000017500000000135113036414402022065 0ustar billbillFunction: ellchangepoint Section: elliptic_curves C-Name: ellchangepoint Prototype: GG Help: ellchangepoint(x,v): change data on point or vector of points x on an elliptic curve according to v=[u,r,s,t]. Doc: changes the coordinates of the point or vector of points $x$ using the vector \kbd{v=[u,r,s,t]}, i.e.~if $x'$ and $y'$ are the new coordinates, then $x=u^2x'+r$, $y=u^3y'+su^2x'+t$ (see also \kbd{ellchangecurve}). \bprog ? E0 = ellinit([1,1]); P0 = [0,1]; v = [1,2,3,4]; ? E = ellchangecurve(E0, v); ? P = ellchangepoint(P0,v) %3 = [-2, 3] ? ellisoncurve(E, P) %4 = 1 ? ellchangepointinv(P,v) %5 = [0, 1] @eprog Variant: The reciprocal function \fun{GEN}{ellchangepointinv}{GEN x, GEN ch} inverts the coordinate change. pari-2.11.2/src/functions/elliptic_curves/elltamagawa0000644000175000017500000000112713326135265021362 0ustar billbillFunction: elltamagawa Section: elliptic_curves C-Name: elltamagawa Prototype: G Help: elltamagawa(E): E being an elliptic curve over a number field, returns the global Tamagawa number of the curve. Doc: The object $E$ being an elliptic curve over a number field, returns the global Tamagawa number of the curve (including the factor at infinite places). \bprog ? e = ellinit([1, -1, 1, -3002, 63929]); \\ curve "90c6" from elldata ? elltamagawa(e) %2 = 288 ? [elllocalred(e,p)[4] | p<-[2,3,5]] %3 = [6, 4, 6] ? vecprod(%) \\ since e.disc > 0 the factor at infinity is 2 %4 = 144 @eprog pari-2.11.2/src/functions/elliptic_curves/ellglobalred0000644000175000017500000000366113201017466021532 0ustar billbillFunction: ellglobalred Section: elliptic_curves C-Name: ellglobalred Prototype: G Help: ellglobalred(E): E being an elliptic curve over a number field, returns [N, v, c, faN, L], where N is the conductor of E, c is the product of the local Tamagawa numbers c_p, faN is the factorization of N and L[i] is elllocalred(E, faN[i,1]); v is an obsolete field. Description: (gen):gen ellglobalred($1) Doc: let $E$ be an \kbd{ell} structure as output by \kbd{ellinit} attached to an elliptic curve defined over a number field. This function calculates the arithmetic conductor and the global \idx{Tamagawa number} $c$. The result $[N,v,c,F,L]$ is slightly different if $E$ is defined over $\Q$ (domain $D = 1$ in \kbd{ellinit}) or over a number field (domain $D$ is a number field structure, including \kbd{nfinit(x)} representing $\Q$ !): \item $N$ is the arithmetic conductor of the curve, \item $v$ is an obsolete field, left in place for backward compatibility. If $E$ is defined over $\Q$, $v$ gives the coordinate change for $E$ to the standard minimal integral model (\tet{ellminimalmodel} provides it in a cheaper way); if $E$ is defined over another number field, $v$ gives a coordinate change to an integral model (\tet{ellintegralmodel} provides it in a cheaper way). \item $c$ is the product of the local Tamagawa numbers $c_p$, a quantity which enters in the \idx{Birch and Swinnerton-Dyer conjecture}, \item $F$ is the factorization of $N$, \item $L$ is a vector, whose $i$-th entry contains the local data at the $i$-th prime ideal divisor of $N$, i.e. \kbd{L[i] = elllocalred(E,F[i,1])}. If $E$ is defined over $\Q$, the local coordinate change has been deleted and replaced by a 0; if $E$ is defined over another number field the local coordinate change to a local minimal model is given relative to the integral model afforded by $v$ (so either start from an integral model so that $v$ be trivial, or apply $v$ first). pari-2.11.2/src/functions/elliptic_curves/ellmodulareqn0000644000175000017500000000432013201017466021737 0ustar billbillFunction: ellmodulareqn Section: elliptic_curves C-Name: ellmodulareqn Prototype: LDnDn Help: ellmodulareqn(N,{x},{y}): given a prime N < 500, return a vector [P, t] where P(x,y) is a modular equation of level N. This requires the package seadata. The equation is either of canonical type (t=0) or of Atkin type (t=1). Doc: given a prime $N < 500$, return a vector $[P,t]$ where $P(x,y)$ is a modular equation of level $N$, i.e.~a bivariate polynomial with integer coefficients; $t$ indicates the type of this equation: either \emph{canonical} ($t = 0$) or \emph{Atkin} ($t = 1$). This function requires the \kbd{seadata} package and its only use is to give access to the package contents. See \tet{polmodular} for a more general and more flexible function. Let $j$ be the $j$-invariant function. The polynomial $P$ satisfies the functional equation, $$ P(f,j) = P(f \mid W_N, j \mid W_N) = 0 $$ for some modular function $f = f_N$ (hand-picked for each fixed $N$ to minimize its size, see below), where $W_N(\tau) = -1 / (N\*\tau)$ is the Atkin-Lehner involution. These two equations allow to compute the values of the classical modular polynomial $\Phi_N$, such that $\Phi_N(j(\tau), j(N\tau)) = 0$, while being much smaller than the latter. More precisely, we have $j(W_N(\tau)) = j(N\*\tau)$; the function $f$ is invariant under $\Gamma_0(N)$ and also satisfies \item for Atkin type: $f \mid W_N = f$; \item for canonical type: let $s = 12/\gcd(12,N-1)$, then $f \mid W_N = N^s / f$. In this case, $f$ has a simple definition: $f(\tau) = N^s \* \big(\eta(N\*\tau) / \eta(\tau) \big)^{2\*s}$, where $\eta$ is Dedekind's eta function. The following GP function returns values of the classical modular polynomial by eliminating $f_N(\tau)$ in the above functional equation, for $N\leq 31$ or $N\in\{41,47,59,71\}$. \bprog classicaleqn(N, X='X, Y='Y)= { my([P,t] = ellmodulareqn(N), Q, d); if (poldegree(P,'y) > 2, error("level unavailable in classicaleqn")); if (t == 0, \\ Canonical my(s = 12/gcd(12,N-1)); Q = 'x^(N+1) * substvec(P,['x,'y],[N^s/'x,Y]); d = N^(s*(2*N+1)) * (-1)^(N+1); , \\ Atkin Q = subst(P,'y,Y); d = (X-Y)^(N+1)); polresultant(subst(P,'y,X), Q) / d; } @eprog pari-2.11.2/src/functions/elliptic_curves/ellanalyticrank0000644000175000017500000000213713326135265022262 0ustar billbillFunction: ellanalyticrank Section: elliptic_curves C-Name: ellanalyticrank_bitprec Prototype: GDGb Help: ellanalyticrank(E, {eps}): returns the order of vanishing at s=1 of the L-function of the elliptic curve E and the value of the first non-zero derivative. To determine this order, it is assumed that any value less than eps is zero. If no value of eps is given, 2^(-bitprecision/2) is used. Doc: returns the order of vanishing at $s=1$ of the $L$-function of the elliptic curve $E$ and the value of the first non-zero derivative. To determine this order, it is assumed that any value less than \kbd{eps} is zero. If \kbd{eps} is omitted, $2^{-b/2}$ is used, where $b$ is the current bit precision. \bprog ? E = ellinit("11a1"); \\ rank 0 ? ellanalyticrank(E) %2 = [0, 0.2538418608559106843377589233] ? E = ellinit("37a1"); \\ rank 1 ? ellanalyticrank(E) %4 = [1, 0.3059997738340523018204836835] ? E = ellinit("389a1"); \\ rank 2 ? ellanalyticrank(E) %6 = [2, 1.518633000576853540460385214] ? E = ellinit("5077a1"); \\ rank 3 ? ellanalyticrank(E) %8 = [3, 10.39109940071580413875185035] @eprog pari-2.11.2/src/functions/elliptic_curves/ellpadicfrobenius0000644000175000017500000000161213326135265022574 0ustar billbillFunction: ellpadicfrobenius Section: elliptic_curves C-Name: ellpadicfrobenius Prototype: GLL Help: ellpadicfrobenius(E,p,n): matrix of the Frobenius at p>2 in the standard basis of H^1_dR(E) to absolute p-adic precision p^n. Doc: If $p>2$ is a prime and $E$ is an elliptic curve on $\Q$ with good reduction at $p$, return the matrix of the Frobenius endomorphism $\varphi$ on the crystalline module $D_p(E)= \Q_p \otimes H^1_{dR}(E/\Q)$ with respect to the basis of the given model $(\omega, \eta=x\*\omega)$, where $\omega = dx/(2\*y+a_1\*x+a_3)$ is the invariant differential. The characteristic polynomial of $\varphi$ is $x^2 - a_p\*x + p$. The matrix is computed to absolute $p$-adic precision $p^n$. \bprog ? E = ellinit([1,-1,1,0,0]); ? F = ellpadicfrobenius(E,5,3); ? lift(F) %3 = [120 29] [ 55 5] ? charpoly(F) %4 = x^2 + O(5^3)*x + (5 + O(5^3)) ? ellap(E, 5) %5 = 0 @eprog pari-2.11.2/src/functions/elliptic_curves/ellheight0000644000175000017500000000150013457566441021054 0ustar billbillFunction: ellheight Section: elliptic_curves C-Name: ellheight0 Prototype: GGDGp Help: ellheight(E,P,{Q}): canonical height of point P on elliptic curve E, resp. the value of the attached bilinear form at (P,Q). Doc: global N\'eron-Tate height $h(P)$ of the point $P$ on the elliptic curve $E$, defined over $\Q$ or a number field, using the same normalization as Cremona's \emph{Algorithms for modular elliptic curves}. $E$ must be an \kbd{ell} as output by \kbd{ellinit}; it needs not be given by a minimal model although the computation will be faster if it is. The height of a torsion point is exactly 0, else a positive real number. If the argument $Q$ is present, computes the value of the bilinear form $(h(P+Q)-h(P-Q)) / 4$. Variant: Also available is \fun{GEN}{ellheight}{GEN E, GEN P, long prec} ($Q$ omitted). pari-2.11.2/src/functions/elliptic_curves/elllog0000644000175000017500000000221613036414402020350 0ustar billbillFunction: elllog Section: elliptic_curves C-Name: elllog Prototype: GGGDG Help: elllog(E,P,G,{o}): return the discrete logarithm of the point P of the elliptic curve E in base G. If present, o represents the order of G. If not present, assume that G generates the curve. Doc: given two points $P$ and $G$ on the elliptic curve $E/\F_q$, returns the discrete logarithm of $P$ in base $G$, i.e. the smallest non-negative integer $n$ such that $P = [n]G$. See \tet{znlog} for the limitations of the underlying discrete log algorithms. If present, $o$ represents the order of $G$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[N, factor(N)]}, where $N$ is the order of $G$. If no $o$ is given, assume that $G$ generates the curve. The function also assumes that $P$ is a multiple of $G$. \bprog ? a = ffgen(ffinit(2,8),'a); ? E = ellinit([a,1,0,0,1]); \\ over F_{2^8} ? x = a^3; y = ellordinate(E,x)[1]; ? P = [x,y]; G = ellmul(E, P, 113); ? ord = [242, factor(242)]; \\ P generates a group of order 242. Initialize. ? ellorder(E, G, ord) %4 = 242 ? e = elllog(E, P, G, ord) %5 = 15 ? ellmul(E,G,e) == P %6 = 1 @eprog pari-2.11.2/src/functions/elliptic_curves/elllocalred0000644000175000017500000000250713326135265021370 0ustar billbillFunction: elllocalred Section: elliptic_curves C-Name: elllocalred Prototype: GDG Help: elllocalred(E,{p}): E being an elliptic curve, returns [f,kod,[u,r,s,t],c], where f is the conductor's exponent, kod is the Kodaira type for E at p, [u,r,s,t] is the change of variable needed to make E minimal at p, and c is the local Tamagawa number c_p. Doc: calculates the \idx{Kodaira} type of the local fiber of the elliptic curve $E$ at $p$. $E$ must be an \kbd{ell} structure as output by \kbd{ellinit}, over $\Q_\ell$ ($p$ better left omitted, else equal to $\ell$) over $\Q$ ($p$ a rational prime) or a number field $K$ ($p$ a maximal ideal given by a \kbd{prid} structure). The result is a 4-component vector $[f,kod,v,c]$. Here $f$ is the exponent of $p$ in the arithmetic conductor of $E$, and $kod$ is the Kodaira type which is coded as follows: 1 means good reduction (type I$_0$), 2, 3 and 4 mean types II, III and IV respectively, $4+\nu$ with $\nu>0$ means type I$_\nu$; finally the opposite values $-1$, $-2$, etc.~refer to the starred types I$_0^*$, II$^*$, etc. The third component $v$ is itself a vector $[u,r,s,t]$ giving the coordinate changes done during the local reduction; $u = 1$ if and only if the given equation was already minimal at $p$. Finally, the last component $c$ is the local \idx{Tamagawa number} $c_p$. pari-2.11.2/src/functions/elliptic_curves/ellperiods0000644000175000017500000000266613326135265021256 0ustar billbillFunction: ellperiods Section: elliptic_curves C-Name: ellperiods Prototype: GD0,L,p Help: ellperiods(w, {flag = 0}): w describes a complex period lattice ([w1,w2] or an ellinit structure). Returns normalized periods [W1,W2] generating the same lattice such that tau := W1/W2 satisfies Im(tau) > 0 and lies in the standard fundamental domain for SL2. If flag is 1, the return value is [[W1,W2], [e1,e2]], where e1, e2 are the quasi-periods attached to [W1,W2], satisfying e2 W1 - e1 W2 = 2*I*Pi. Doc: Let $w$ describe a complex period lattice ($w = [w_1,w_2]$ or an \kbd{ellinit} structure). Returns normalized periods $[W_1,W_2]$ generating the same lattice such that $\tau := W_1/W_2$ has positive imaginary part and lies in the standard fundamental domain for $\text{SL}_2(\Z)$. If $\fl = 1$, the function returns $[[W_1,W_2], [\eta_1,\eta_2]]$, where $\eta_1$ and $\eta_2$ are the quasi-periods attached to $[W_1,W_2]$, satisfying $\eta_2 W_1 - \eta_1 W_2 = 2 i \pi$. The output of this function is meant to be used as the first argument given to ellwp, ellzeta, ellsigma or elleisnum. Quasi-periods are needed by ellzeta and ellsigma only. \bprog ? L = ellperiods([1,I],1); ? [w1,w2] = L[1]; [e1,e2] = L[2]; ? e2*w1 - e1*w2 %3 = 6.2831853071795864769252867665590057684*I ? ellzeta(L, 1/2 + 2*I) %4 = 1.5707963... - 6.283185307...*I ? ellzeta([1,I], 1/2 + 2*I) \\ same but less efficient %4 = 1.5707963... - 6.283185307...*I @eprog pari-2.11.2/src/functions/elliptic_curves/ellak0000644000175000017500000000243713326135265020200 0ustar billbillFunction: ellak Section: elliptic_curves C-Name: akell Prototype: GG Help: ellak(E,n): computes the n-th Fourier coefficient of the L-function of the elliptic curve E (assumes E is an integral model). Doc: computes the coefficient $a_n$ of the $L$-function of the elliptic curve $E/\Q$, i.e.~coefficients of a newform of weight 2 by the modularity theorem (\idx{Taniyama-Shimura-Weil conjecture}). $E$ must be an \kbd{ell} structure over $\Q$ as output by \kbd{ellinit}. $E$ must be given by an integral model, not necessarily minimal, although a minimal model will make the function faster. \bprog ? E = ellinit([1,-1,0,4,3]); ? ellak(E, 10) %2 = -3 ? e = ellchangecurve(E, [1/5,0,0,0]); \\ made not minimal at 5 ? ellak(e, 10) \\ wasteful but works %3 = -3 ? E = ellminimalmodel(e); \\ now minimal ? ellak(E, 5) %5 = -3 @eprog\noindent If the model is not minimal at a number of bad primes, then the function will be slower on those $n$ divisible by the bad primes. The speed should be comparable for other $n$: \bprog ? for(i=1,10^6, ellak(E,5)) time = 699 ms. ? for(i=1,10^6, ellak(e,5)) \\ 5 is bad, markedly slower time = 1,079 ms. ? for(i=1,10^5,ellak(E,5*i)) time = 1,477 ms. ? for(i=1,10^5,ellak(e,5*i)) \\ still slower but not so much on average time = 1,569 ms. @eprog pari-2.11.2/src/functions/elliptic_curves/ellminimalmodel0000644000175000017500000000405613201017466022245 0ustar billbillFunction: ellminimalmodel Section: elliptic_curves C-Name: ellminimalmodel Prototype: GD& Help: ellminimalmodel(E,{&v}): determines whether the elliptic curve E defined over a number field admits a global minimal model. If so return it and sets v to the corresponding change of variable. Else return the (non-principal) Weierstrass class of E. Doc: Let $E$ be an \kbd{ell} structure over a number field $K$. This function determines whether $E$ admits a global minimal integral model. If so, it returns it and sets $v = [u,r,s,t]$ to the corresponding change of variable: the return value is identical to that of \kbd{ellchangecurve(E, v)}. Else return the (non-principal) Weierstrass class of $E$, i.e. the class of $\prod \goth{p}^{(v_{\goth{p}}{\Delta} - \delta_{\goth{p}}) / 12}$ where $\Delta = \kbd{E.disc}$ is the model's discriminant and $\goth{p} ^ \delta_{\goth{p}}$ is the local minimal discriminant. This function requires either that $E$ be defined over the rational field $\Q$ (with domain $D = 1$ in \kbd{ellinit}), in which case a global minimal model always exists, or over a number field given by a \var{bnf} structure. The Weierstrass class is given in \kbd{bnfisprincipal} format, i.e. in terms of the \kbd{K.gen} generators. The resulting model has integral coefficients and is everywhere minimal, the coefficients $a_1$ and $a_3$ are reduced modulo $2$ (in terms of the fixed integral basis \kbd{K.zk}) and $a_2$ is reduced modulo $3$. Over $\Q$, we further require that $a_1$ and $a_3$ be $0$ or $1$, that $a_2$ be $0$ or $\pm 1$ and that $u > 0$ in the change of variable: both the model and the change of variable $v$ are then unique.\sidx{minimal model} \bprog ? e = ellinit([6,6,12,55,233]); \\ over Q ? E = ellminimalmodel(e, &v); ? E[1..5] %3 = [0, 0, 0, 1, 1] ? v %4 = [2, -5, -3, 9] @eprog \bprog ? K = bnfinit(a^2-65); \\ over a non-principal number field ? K.cyc %2 = [2] ? u = Mod(8+a, K.pol); ? E = ellinit([1,40*u+1,0,25*u^2,0], K); ? ellminimalmodel(E) \\ no global minimal model exists over Z_K %6 = [1]~ @eprog pari-2.11.2/src/functions/elliptic_curves/ellmoddegree0000644000175000017500000000243413326135265021535 0ustar billbillFunction: ellmoddegree Section: elliptic_curves C-Name: ellmoddegree Prototype: G Help: ellmoddegree(e): e being an elliptic curve defined over Q output by ellinit, compute the modular degree of e divided by the square of the Manin constant. Doc: $e$ being an elliptic curve defined over $\Q$ output by \kbd{ellinit}, compute the modular degree of $e$ divided by the square of the Manin constant $c$. It is conjectured that $c = 1$ for the strong Weil curve in the isogeny class (optimal quotient of $J_0(N)$) and this can be proven using \kbd{ellweilcurve} when the conductor $N$ is moderate. \bprog ? E = ellinit("11a1"); \\ from Cremona table: strong Weil curve and c = 1 ? [v,smith] = ellweilcurve(E); smith \\ proof of the above %2 = [[1, 1], [5, 1], [1, 1/5]] ? ellmoddegree(E) %3 = 1 ? [ellidentify(e)[1][1] | e<-v] %4 = ["11a1", "11a2", "11a3"] ? ellmoddegree(ellinit("11a2")) %5 = 5 ? ellmoddegree(ellinit("11a3")) %6 = 1/5 @eprog\noindent The modular degree of \kbd{11a1} is $1$ (because \kbd{ellweilcurve} or Cremona's table prove that the Manin constant is $1$ for this curve); the output of \kbd{ellweilcurve} also proves that the Manin constants of \kbd{11a2} and \kbd{11a3} are 1 and 5 respectively, so the actual modular degree of both \kbd{11a2} and \kbd{11a3} is 5. pari-2.11.2/src/functions/elliptic_curves/ellpadicheightmatrix0000644000175000017500000000205213326135265023274 0ustar billbillFunction: ellpadicheightmatrix Section: elliptic_curves C-Name: ellpadicheightmatrix Prototype: GGLG Help: ellpadicheightmatrix(E,p,n,Q): gives the height-pairing matrix for vector of points Q on elliptic curve E. Doc: $Q$ being a vector of points, this function returns the ``Gram matrix'' $[F,G]$ of the cyclotomic $p$-adic height $h_E$ with respect to the basis $(\omega, \eta)$ of $D=H^1_{dR}(E) \otimes_\Q \Q_p$ given to $n$ $p$-adic digits. In other words, if \kbd{ellpadicheight}$(E,p,n, Q[i],Q[j]) = [f,g]$, corresponding to $f \omega + g \eta$ in $D$, then $F[i,j] = f$ and $G[i,j] = g$. \bprog ? E = ellinit([0,0,1,-7,6]); Q = [[-2,3],[-1,3]]; p = 5; n = 5; ? [F,G] = ellpadicheightmatrix(E,p,n,Q); ? lift(F) \\ p-adic entries, integral approximation for readability %3 = [2364 3100] [3100 3119] ? G %4 = [25225 46975] [46975 61850] ? [F,G] * [1,-ellpadics2(E,p,n)]~ %5 = [4 + 2*5 + 4*5^2 + 3*5^3 + O(5^5) 4*5^2 + 4*5^3 + 5^4 + O(5^5)] [ 4*5^2 + 4*5^3 + 5^4 + O(5^5) 4 + 3*5 + 4*5^2 + 4*5^3 + 5^4 + O(5^5)] @eprog pari-2.11.2/src/functions/elliptic_curves/ellissupersingular0000644000175000017500000000240013326135265023032 0ustar billbillFunction: ellissupersingular Section: elliptic_curves C-Name: ellissupersingular Prototype: iGDG Help: ellissupersingular(E,{p}): return 1 if the elliptic curve E, defined over a number field or a finite field, is supersingular at p, and 0 otherwise. Doc: Return 1 if the elliptic curve $E$ defined over a number field, $\Q_p$ or a finite field is supersingular at $p$, and $0$ otherwise. If the curve is defined over a number field, $p$ must be explicitly given, and must be a prime number, resp.~a maximal ideal, if the curve is defined over $\Q$, resp.~a general number field: we return $1$ if and only if $E$ has supersingular good reduction at $p$. Alternatively, $E$ can be given by its $j$-invariant in a finite field. In this case $p$ must be omitted. \bprog ? setrand(1); \\ make the choice of g deterministic ? g = ffprimroot(ffgen(7^5)) %1 = 4*x^4 + 5*x^3 + 6*x^2 + 5*x + 6 ? [g^n | n <- [1 .. 7^5 - 1], ellissupersingular(g^n)] %2 = [6] ? K = nfinit(y^3-2); P = idealprimedec(K, 2)[1]; ? E = ellinit([y,1], K); ? ellissupersingular(E, P) %5 = 1 ? Q = idealprimedec(K,5)[1]; ? ellissupersingular(E, Q) %6 = 0 @eprog Variant: Also available is \fun{int}{elljissupersingular}{GEN j} where $j$ is a $j$-invariant of a curve over a finite field. pari-2.11.2/src/functions/elliptic_curves/ellsigma0000644000175000017500000000216413326135265020702 0ustar billbillFunction: ellsigma Section: elliptic_curves C-Name: ellsigma Prototype: GDGD0,L,p Help: ellsigma(L,{z='x},{flag=0}): computes the value at z of the Weierstrass sigma function attached to the lattice L, as given by ellperiods(,1). If flag = 1, returns an arbitrary determination of the logarithm of sigma. Doc: Computes the value at $z$ of the Weierstrass $\sigma$ function attached to the lattice $L$ as given by \tet{ellperiods}$(,1)$: including quasi-periods is useful, otherwise there are recomputed from scratch for each new $z$. $$ \sigma(z, L) = z \prod_{\omega\in L^*} \left(1 - \dfrac{z}{\omega}\right)e^{\dfrac{z}{\omega} + \dfrac{z^2}{2\omega^2}}.$$ It is also possible to directly input $L = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit} ($L = \kbd{E.omega}$). \bprog ? w = ellperiods([1,I], 1); ? ellsigma(w, 1/2) %2 = 0.47494937998792065033250463632798296855 ? E = ellinit([1,0]); ? ellsigma(E) \\ at 'x, implicitly at default seriesprecision %4 = x + 1/60*x^5 - 1/10080*x^9 - 23/259459200*x^13 + O(x^17) @eprog If $\fl=1$, computes an arbitrary determination of $\log(\sigma(z))$. pari-2.11.2/src/functions/elliptic_curves/ellconvertname0000644000175000017500000000115411636712103022113 0ustar billbillFunction: ellconvertname Section: elliptic_curves C-Name: ellconvertname Prototype: G Help: ellconvertname(name): convert an elliptic curve name (as found in the elldata database) from a string to a triplet [conductor, isogeny class, index]. It will also convert a triplet back to a curve name. Doc: converts an elliptic curve name, as found in the \tet{elldata} database, from a string to a triplet $[\var{conductor}, \var{isogeny class}, \var{index}]$. It will also convert a triplet back to a curve name. Examples: \bprog ? ellconvertname("123b1") %1 = [123, 1, 1] ? ellconvertname(%) %2 = "123b1" @eprog pari-2.11.2/src/functions/elliptic_curves/ellisogeny0000644000175000017500000000202513201017466021245 0ustar billbillFunction: ellisogeny Section: elliptic_curves C-Name: ellisogeny Prototype: GGD0,L,DnDn Help: ellisogeny(E, G, {only_image = 0}, {x = 'x}, {y = 'y}): compute the image and isogeny corresponding to the quotient of E by the subgroup G. Doc: Given an elliptic curve $E$, a finite subgroup $G$ of $E$ is given either as a generating point $P$ (for a cyclic $G$) or as a polynomial whose roots vanish on the $x$-coordinates of the non-zero elements of $G$ (general case and more efficient if available). This function returns the $[a_1,a_2,a_3,a_4,a_6]$ invariants of the quotient elliptic curve $E/G$ and (if \var{only\_image} is zero (the default)) a vector of rational functions $[f, g, h]$ such that the isogeny $E \to E/G$ is given by $(x,y) \mapsto (f(x)/h(x)^2, g(x,y)/h(x)^3)$. \bprog ? E = ellinit([0,1]); ? elltors(E) %2 = [6, [6], [[2, 3]]] ? ellisogeny(E, [2,3], 1) \\ Weierstrass model for E/

%3 = [0, 0, 0, -135, -594] ? ellisogeny(E,[-1,0]) %4 = [[0,0,0,-15,22], [x^3+2*x^2+4*x+3, y*x^3+3*y*x^2-2*y, x+1]] @eprog pari-2.11.2/src/functions/elliptic_curves/HEADER0000644000175000017500000002374113326135265020041 0ustar billbillFunction: _header_elliptic_curves Class: header Section: elliptic_curves Doc: \section{Elliptic curves} \subsec{Elliptic curve structures} %GPHELPskip An elliptic curve is given by a Weierstrass model\sidx{Weierstrass equation} $$ y^2+a_1xy+a_3y=x^3+a_2x^2+a_4x+a_6, $$ whose discriminant is non-zero. Affine points on \kbd{E} are represented as two-component vectors \kbd{[x,y]}; the point at infinity, i.e.~the identity element of the group law, is represented by the one-component vector \kbd{[0]}. Given a vector of coefficients $[a_1,a_2,a_3,a_4,a_6]$, the function \tet{ellinit} initializes and returns an \tev{ell} structure. An additional optional argument allows to specify the base field in case it cannot be inferred from the curve coefficients. This structure contains data needed by elliptic curve related functions, and is generally passed as a first argument. Expensive data are skipped on initialization: they will be dynamically computed when (and if) needed, and then inserted in the structure. The precise layout of the \tev{ell} structure is left undefined and should never be used directly. The following \idx{member functions} are available, depending on the underlying domain. \subsubsec{All domains} %GPHELPskip \item \tet{a1}, \tet{a2}, \tet{a3}, \tet{a4}, \tet{a6}: coefficients of the elliptic curve. \item \tet{b2}, \tet{b4}, \tet{b6}, \tet{b8}: $b$-invariants of the curve; in characteristic $\neq 2$, for $Y = 2y + a_1x+a3$, the curve equation becomes $$ Y^2 = 4 x^3 + b_2 x^2 + 2b_4 x + b_6 =: g(x). $$ \item \tet{c4}, \tet{c6}: $c$-invariants of the curve; in characteristic $\neq 2,3$, for $X = x + b_2/12$ and $Y = 2y + a_1x+a3$, the curve equation becomes $$ Y^2 = 4 X^3 - (c_4/12) X - (c_6/216). $$ \item \tet{disc}: discriminant of the curve. This is only required to be non-zero, not necessarily a unit. \item \tet{j}: $j$-invariant of the curve. \noindent These are used as follows: \bprog ? E = ellinit([0,0,0, a4,a6]); ? E.b4 %2 = 2*a4 ? E.disc %3 = -64*a4^3 - 432*a6^2 @eprog \subsubsec{Curves over $\C$} %GPHELPskip This in particular includes curves defined over $\Q$. All member functions in this section return data, as it is currently stored in the structure, if present; and otherwise compute it to the default accuracy, that was fixed \emph{at the time of ellinit} (via a \typ{REAL} $D$ domain argument, or \kbd{realprecision} by default). The function \tet{ellperiods} allows to recompute (and cache) the following data to \emph{current} \kbd{realprecision}. \item \tet{area}: volume of the complex lattice defining $E$. \item \tet{roots} is a vector whose three components contain the complex roots of the right hand side $g(x)$ of the attached $b$-model $Y^2 = g(x)$. If the roots are all real, they are ordered by decreasing value. If only one is real, it is the first component. \item \tet{omega}: $[\omega_1,\omega_2]$, periods forming a basis of the complex lattice defining $E$. The first component $\omega_1$ is the (positive) real period, in other words the integral of the N\'eron differential $dx/(2y+a_1x+a_3)$ over the connected component of the identity component of $E(\R)$. The second component $\omega_2$ is a complex period, such that $\tau=\dfrac{\omega_1}{\omega_2}$ belongs to Poincar\'e's half-plane (positive imaginary part); not necessarily to the standard fundamental domain. It is normalized so that $\Im(\omega_2) < 0$ and either $\Re(\omega_2) = 0$, when \kbd{E.disc > 0} ($E(\R)$ has two connected components), or $\Re(\omega_2) = \omega_1/2$ \item \tet{eta} is a row vector containing the quasi-periods $\eta_1$ and $\eta_2$ such that $\eta_i = 2\zeta(\omega_i/2)$, where $\zeta$ is the Weierstrass zeta function attached to the period lattice; see \tet{ellzeta}. In particular, the Legendre relation holds: $\eta_2\omega_1 - \eta_1\omega_2 = 2\pi i$. \misctitle{Warning} As for the orientation of the basis of the period lattice, beware that many sources use the inverse convention where $\omega_2/\omega_1$ has positive imaginary part and our $\omega_2$ is the negative of theirs. Our convention $\tau = \omega_1/\omega_2$ ensures that the action of $\text{PSL}_2$ is the natural one: $$[a,b;c,d]\cdot\tau = (a\tau+b)/(c\tau+d) = (a \omega_1 + b\omega_2)/(c\omega_1 + d\omega_2),$$ instead of a twisted one. (Our $tau$ is $-1/\tau$ in the above inverse convention.) \subsubsec{Curves over $\Q_p$} %GPHELPskip We advise to input a model defined over $\Q$ for such curves. In any case, if you input an approximate model with \typ{PADIC} coefficients, it will be replaced by a lift to $\Q$ (an exact model ``close'' to the one that was input) and all quantities will then be computed in terms of this lifted model. For the time being only curves with multiplicative reduction (split or non-split), i.e. $v_p(j) < 0$, are supported by non-trivial functions. In this case the curve is analytically isomorphic to $\bar{\Q}_p^*/q^\Z := E_q(\bar{\Q}_p)$, for some $p$-adic integer $q$ (the Tate period). In particular, we have $j(q) = j(E)$. \item \tet{p} is the residual characteristic \item \tet{roots} is a vector with a single component, equal to the $p$-adic root $e_1$ of the right hand side $g(x)$ of the attached $b$-model $Y^2 = g(x)$. The point $(e_1,0)$ corresponds to $-1 \in \bar{\Q}_p^*/q^\Z$ under the Tate parametrization. \item \tet{tate} returns $[u^2,u,q,[a,b],L, Ei]$ in the notation of Henniart-Mestre (CRAS t. 308, p.~391--395, 1989): $q$ is as above, $u\in \Q_p(\sqrt{-c_6})$ is such that $\phi^* dx/(2y + a_1x+a3) = u dt/t$, where $\phi: E_q\to E$ is an isomorphism (well defined up to sign) and $dt/t$ is the canonical invariant differential on the Tate curve; $u^2\in\Q_p$ does not depend on $\phi$. (Technicality: if $u\not\in\Q_p$, it is stored as a quadratic \typ{POLMOD}.) The parameters $[a,b]$ satisfy $4u^2 b \cdot \text{agm}(\sqrt{a/b},1)^2 = 1$ as in Theorem~2 (\emph{loc.~cit.}). \kbd{Ei} describes the sequence of 2-isogenous curves (with kernel generated by $[0,0]$) $E_i: y^2=x(x+A_i)(x+A_i-B_i)$ converging quadratically towards the singular curve $E_\infty$. Finally, $L$ is Mazur-Tate-Teitelbaum's ${\cal L}$-invariant, equal to $\log_p q / v_p(q)$. \subsubsec{Curves over $\F_q$} %GPHELPskip \item \tet{p} is the characteristic of $\F_q$. \item \tet{no} is $\#E(\F_q)$. \item \tet{cyc} gives the cycle structure of $E(\F_q)$. \item \tet{gen} returns the generators of $E(\F_q)$. \item \tet{group} returns $[\kbd{no},\kbd{cyc},\kbd{gen}]$, i.e. $E(\F_q)$ as an abelian group structure. \subsubsec{Curves over $\Q$} %GPHELPskip All functions should return a correct result, whether the model is minimal or not, but it is a good idea to stick to minimal models whenever $\gcd(c_4,c_6)$ is easy to factor (minor speed-up). The construction \bprog E = ellminimalmodel(E0, &v) @eprog\noindent replaces the original model $E_0$ by a minimal model $E$, and the variable change $v$ allows to go between the two models: \bprog ellchangepoint(P0, v) ellchangepointinv(P, v) @eprog\noindent respectively map the point $P_0$ on $E_0$ to its image on $E$, and the point $P$ on $E$ to its pre-image on $E_0$. A few routines --- namely \tet{ellgenerators}, \tet{ellidentify}, \tet{ellsearch}, \tet{forell} --- require the optional package \tet{elldata} (John Cremona's database) to be installed. In that case, the function \tet{ellinit} will allow alternative inputs, e.g.~\kbd{ellinit("11a1")}. Functions using this package need to load chunks of a large database in memory and require at least 2MB stack to avoid stack overflows. \item \tet{gen} returns the generators of $E(\Q)$, if known (from John Cremona's database) \subsubsec{Curves over number fields} %GPHELPskip \item \tet{nf} return the \var{nf} structure attached to the number field over which $E$ is defined. \item \tet{bnf} return the \var{bnf} structure attached to the number field over which $E$ is defined or raise an error (if only an \var{nf} is available). \item \tet{omega}, \tet{eta}, \tet{area}: vectors of complex periods, quasi-periods and lattice areas attached to the complex embeddings of $E$, in the same order as \kbd{E.nf.roots}. \subsec{Reduction} %GPHELPskip Let $E$ be a curve defined over $\Q_p$ given by a $p$-integral model; if the curve has good reduction at $p$, we may define its reduction $\tilde{E}$ over the finite field $\F_p$: \bprog ? E = ellinit([-3,1], O(5^10)); \\ @com $E/\Q_5$ ? Et = ellinit(E, 5) ? ellcard(Et) \\ @com $\tilde{E}/\F_5$ has 7 points %3 = 7 ? ellinit(E, 7) *** at top-level: ellinit(E,7) *** ^------------ *** ellinit: inconsistent moduli in ellinit: 5 != 7 @eprog\noindent Likewise, if a curve is defined over a number field $K$ and $\goth{p}$ is a maximal ideal with finite residue field $\F_q$, we define the reduction $\tilde{E}/\F_q$ provided $E$ has good reduction at $\goth{p}$. $E/\Q$ is an important special case: \bprog ? E = ellinit([-3,1]); ? factor(E.disc) %2 = [2 4] [3 4] ? Et = ellinit(E, 5); ? ellcard(Et) \\ @com $\tilde{E} / \F_5$ has 7 points %4 = 7 ? ellinit(E, 3) \\ bad reduction at 3 %5 = [] @eprog\noindent General number fields are similar: \bprog ? K = nfinit(x^2+1); E = ellinit([x,x+1], K); ? idealfactor(K, E.disc) \\ three primes of bad reduction %2 = [ [2, [1, 1]~, 2, 1, [1, -1; 1, 1]] 10] [ [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] 2] [[5, [2, 1]~, 1, 1, [-2, -1; 1, -2]] 2] ? P = idealprimedec(K, 3); \\ a prime of good reduction ? idealnorm(K, P) %4 = 9 ? Et = ellinit(E, P); ? ellcard(Et) \\ @com $\tilde{E} / \F_9$ has 4 points %6 = 4 @eprog\noindent If the model is not locally minimal at $\goth{p}$, the above will fail: \kbd{elllocalred} and \kbd{ellchangecurve} allow to reduce to that case. Some functions such as \kbd{ellap}, \kbd{ellcard}, \kbd{ellgroup} and \kbd{ellissupersingular} even implicitly replace the given equation by a local minimal model and consider the group of non-singular points $\tilde{E}^{ns}$ so they make sense even when the curve has bad reduction. pari-2.11.2/src/functions/elliptic_curves/ellztopoint0000644000175000017500000000374213326135265021473 0ustar billbillFunction: ellztopoint Section: elliptic_curves C-Name: pointell Prototype: GGp Help: ellztopoint(E,z): inverse of ellpointtoz. Returns the coordinates of point P on the curve E corresponding to a complex or p-adic z. Doc: $E$ being an \var{ell} as output by \kbd{ellinit}, computes the coordinates $[x,y]$ on the curve $E$ corresponding to the complex or $p$-adic parameter $z$. Hence this is the inverse function of \kbd{ellpointtoz}. \item If $E$ is defined over a $p$-adic field and has multiplicative reduction, then $z$ is understood as an element on the Tate curve $\bar{Q}_p^* / q^\Z$. \bprog ? E = ellinit([0,-1,1,0,0], O(11^5)); ? [u2,u,q] = E.tate; type(u) %2 = "t_PADIC" \\ split multiplicative reduction ? z = ellpointtoz(E, [0,0]) %3 = 3 + 11^2 + 2*11^3 + 3*11^4 + 6*11^5 + 10*11^6 + 8*11^7 + O(11^8) ? ellztopoint(E,z) %4 = [O(11^9), O(11^9)] ? E = ellinit(ellfromj(1/4), O(2^6)); x=1/2; y=ellordinate(E,x)[1]; ? z = ellpointtoz(E,[x,y]); \\ non-split: t_POLMOD with t_PADIC coefficients ? P = ellztopoint(E, z); ? P[1] \\ y coordinate is analogous, more complicated %8 = Mod(O(2^4)*x + (2^-1 + O(2^5)), x^2 + (1 + 2^2 + 2^4 + 2^5 + O(2^7))) @eprog \item If $E$ is defined over the complex numbers (for instance over $\Q$), $z$ is understood as a complex number in $\C/\Lambda_E$. If the short Weierstrass equation is $y^2 = 4x^3 - g_2x - g_3$, then $[x,y]$ represents the Weierstrass $\wp$-function\sidx{Weierstrass $\wp$-function} and its derivative. For a general Weierstrass equation we have $$x = \wp(z) - b_2/12,\quad y = \wp'(z)/2 - (a_1 x + a_3)/2.$$ If $z$ is in the lattice defining $E$ over $\C$, the result is the point at infinity $[0]$. \bprog ? E = ellinit([0,1]); P = [2,3]; ? z = ellpointtoz(E, P) %2 = 3.5054552633136356529375476976257353387 ? ellwp(E, z) %3 = 2.0000000000000000000000000000000000000 ? ellztopoint(E, z) - P %4 = [2.548947057811923643 E-57, 7.646841173435770930 E-57] ? ellztopoint(E, 0) %5 = [0] \\ point at infinity @eprog pari-2.11.2/src/functions/elliptic_curves/ellheightmatrix0000644000175000017500000000145513201017466022273 0ustar billbillFunction: ellheightmatrix Section: elliptic_curves C-Name: ellheightmatrix Prototype: GGp Help: ellheightmatrix(E,x): gives the height matrix for vector of points x on elliptic curve E. Doc: $x$ being a vector of points, this function outputs the Gram matrix of $x$ with respect to the N\'eron-Tate height, in other words, the $(i,j)$ component of the matrix is equal to \kbd{ellbil($E$,x[$i$],x[$j$])}. The rank of this matrix, at least in some approximate sense, gives the rank of the set of points, and if $x$ is a basis of the \idx{Mordell-Weil group} of $E$, its determinant is equal to the regulator of $E$. Note our height normalization follows Cremona's \emph{Algorithms for modular elliptic curves}: this matrix should be divided by 2 to be in accordance with, e.g., Silverman's normalizations. pari-2.11.2/src/functions/elliptic_curves/ellL10000644000175000017500000000226013326135265020053 0ustar billbillFunction: ellL1 Section: elliptic_curves C-Name: ellL1_bitprec Prototype: GD0,L,b Help: ellL1(E, {r = 0}): returns the value at s=1 of the derivative of order r of the L-function of the elliptic curve E. Doc: returns the value at $s=1$ of the derivative of order $r$ of the $L$-function of the elliptic curve $E$. \bprog ? E = ellinit("11a1"); \\ order of vanishing is 0 ? ellL1(E) %2 = 0.2538418608559106843377589233 ? E = ellinit("389a1"); \\ order of vanishing is 2 ? ellL1(E) %4 = -5.384067311837218089235032414 E-29 ? ellL1(E, 1) %5 = 0 ? ellL1(E, 2) %6 = 1.518633000576853540460385214 @eprog\noindent The main use of this function, after computing at \emph{low} accuracy the order of vanishing using \tet{ellanalyticrank}, is to compute the leading term at \emph{high} accuracy to check (or use) the Birch and Swinnerton-Dyer conjecture: \bprog ? \p18 realprecision = 18 significant digits ? E = ellinit("5077a1"); ellanalyticrank(E) time = 8 ms. %1 = [3, 10.3910994007158041] ? \p200 realprecision = 202 significant digits (200 digits displayed) ? ellL1(E, 3) time = 104 ms. %3 = 10.3910994007158041387518505103609170697263563756570092797@com$[\dots]$ @eprog pari-2.11.2/src/functions/elliptic_curves/ellwp0000644000175000017500000000356413326135265020235 0ustar billbillFunction: ellwp Section: elliptic_curves C-Name: ellwp0 Prototype: GDGD0,L,p Help: ellwp(w,{z='x},{flag=0}): computes the value at z of the Weierstrass P function attached to the lattice w, as given by ellperiods. Optional flag means 0 (default), compute only P(z), 1 compute [P(z),P'(z)]. Doc: Computes the value at $z$ of the Weierstrass $\wp$ function attached to the lattice $w$ as given by \tet{ellperiods}. It is also possible to directly input $w = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit} ($w = \kbd{E.omega}$). \bprog ? w = ellperiods([1,I]); ? ellwp(w, 1/2) %2 = 6.8751858180203728274900957798105571978 ? E = ellinit([1,1]); ? ellwp(E, 1/2) %4 = 3.9413112427016474646048282462709151389 @eprog\noindent One can also compute the series expansion around $z = 0$: \bprog ? E = ellinit([1,0]); ? ellwp(E) \\ 'x implicitly at default seriesprecision %5 = x^-2 - 1/5*x^2 + 1/75*x^6 - 2/4875*x^10 + O(x^14) ? ellwp(E, x + O(x^12)) \\ explicit precision %6 = x^-2 - 1/5*x^2 + 1/75*x^6 + O(x^9) @eprog Optional \fl\ means 0 (default): compute only $\wp(z)$, 1: compute $[\wp(z),\wp'(z)]$. For instance, the Dickson elliptic functions \var{sm} and \var{sn} can be implemented as follows \bprog smcm(z) = { my(a, b, E = ellinit([0,-1/(4*27)])); \\ ell. invariants (g2,g3)=(0,1/27) [a,b] = ellwp(E, z, 1); [6*a / (1-3*b), (3*b+1)/(3*b-1)]; } ? [s,c] = smcm(0.5); ? s %2 = 0.4898258757782682170733218609 ? c %3 = 0.9591820206453842491187464098 ? s^3+c^3 %4 = 1.000000000000000000000000000 ? smcm('x + O('x^11)) %5 = [x - 1/6*x^4 + 2/63*x^7 - 13/2268*x^10 + O(x^11), 1 - 1/3*x^3 + 1/18*x^6 - 23/2268*x^9 + O(x^10)] @eprog Variant: For $\fl = 0$, we also have \fun{GEN}{ellwp}{GEN w, GEN z, long prec}, and \fun{GEN}{ellwpseries}{GEN E, long v, long precdl} for the power series in variable $v$. pari-2.11.2/src/functions/elliptic_curves/ellneg0000644000175000017500000000027612314242551020346 0ustar billbillFunction: ellneg Section: elliptic_curves C-Name: ellneg Prototype: GG Help: ellneg(E,z): opposite of the point z on elliptic curve E. Doc: Opposite of the point $z$ on elliptic curve $E$. pari-2.11.2/src/functions/elliptic_curves/ellxn0000644000175000017500000000167413326135265020234 0ustar billbillFunction: ellxn Section: elliptic_curves C-Name: ellxn Prototype: GLDn Help: ellxn(E,n,{v='x}): return the polynomials [phi_n, (psi_n)^2] in the variable v, where x([n]P) = phi_n/(psi_n)^2. Doc: In standard notation, for any affine point $P = (v,w)$ on the curve $E$, we have $$[n]P = (\phi_n(P)\psi_n(P) : \omega_n(P) : \psi_n(P)^3)$$ for some polynomials $\phi_n,\omega_n,\psi_n$ in $\Z[a_1,a_2,a_3,a_4,a_6][v,w]$. This function returns $[\phi_n(P),\psi_n(P)^2]$, which give the numerator and denominator of the abscissa of $[n]P$ and depend only on $v$. \bprog ? E = ellinit([17,42]); ? T = ellxn(E, 2, 'X) %2 = [X^4 - 34*X^2 - 336*X + 289, 4*X^3 + 68*X + 168] ? P = [114,1218]; ellmul(E,P,2) %3 = [200257/7056, 90637343/592704] ? [x,y] = subst(T,'X,P[1]) \\ substitute P[1] in ellxn(E,2) %4 = [168416137, 5934096] \\ numerator and denominator of 2*P ? x/y \\ check we find ellmul(e,P,2)[1] %5 = 200257/7056 @eprog pari-2.11.2/src/functions/elliptic_curves/ellpointtoz0000644000175000017500000000531113326135265021465 0ustar billbillFunction: ellpointtoz Section: elliptic_curves C-Name: zell Prototype: GGp Help: ellpointtoz(E,P): lattice point z corresponding to the point P on the elliptic curve E. Doc: if $E/\C \simeq \C/\Lambda$ is a complex elliptic curve ($\Lambda = \kbd{E.omega}$), computes a complex number $z$, well-defined modulo the lattice $\Lambda$, corresponding to the point $P$; i.e.~such that $P = [\wp_\Lambda(z),\wp'_\Lambda(z)]$ satisfies the equation $$y^2 = 4x^3 - g_2 x - g_3,$$ where $g_2$, $g_3$ are the elliptic invariants. If $E$ is defined over $\R$ and $P\in E(\R)$, we have more precisely, $0 \leq \Re(t) < w1$ and $0 \leq \Im(t) < \Im(w2)$, where $(w1,w2)$ are the real and complex periods of $E$. \bprog ? E = ellinit([0,1]); P = [2,3]; ? z = ellpointtoz(E, P) %2 = 3.5054552633136356529375476976257353387 ? ellwp(E, z) %3 = 2.0000000000000000000000000000000000000 ? ellztopoint(E, z) - P %4 = [2.548947057811923643 E-57, 7.646841173435770930 E-57] ? ellpointtoz(E, [0]) \\ the point at infinity %5 = 0 @eprog If $E$ is defined over a general number field, the function returns the values corresponding to the various complex embeddings of the curve and of the point, in the same order as \kbd{E.nf.roots}: \bprog ? E=ellinit([-22032-15552*x,0], nfinit(x^2-2)); ? P=[-72*x-108,0]; ? ellisoncurve(E,P) %3 = 1 ? ellpointtoz(E,P) %4 = [-0.52751724240790530394437835702346995884*I, -0.090507650025885335533571758708283389896*I] ? E.nf.roots %5 = [-1.4142135623730950488016887242096980786, \\ x-> -sqrt(2) 1.4142135623730950488016887242096980786] \\ x-> sqrt(2) @eprog If $E/\Q_p$ has multiplicative reduction, then $E/\bar{\Q_p}$ is analytically isomorphic to $\bar{\Q}_p^*/q^\Z$ (Tate curve) for some $p$-adic integer $q$. The behavior is then as follows: \item If the reduction is split ($E.\kbd{tate[2]}$ is a \typ{PADIC}), we have an isomorphism $\phi: E(\Q_p) \simeq \Q_p^*/q^\Z$ and the function returns $\phi(P)\in \Q_p$. \item If the reduction is \emph{not} split ($E.\kbd{tate[2]}$ is a \typ{POLMOD}), we only have an isomorphism $\phi: E(K) \simeq K^*/q^\Z$ over the unramified quadratic extension $K/\Q_p$. In this case, the output $\phi(P)\in K$ is a \typ{POLMOD}. \bprog ? E = ellinit([0,-1,1,0,0], O(11^5)); P = [0,0]; ? [u2,u,q] = E.tate; type(u) \\ split multiplicative reduction %2 = "t_PADIC" ? ellmul(E, P, 5) \\ P has order 5 %3 = [0] ? z = ellpointtoz(E, [0,0]) %4 = 3 + 11^2 + 2*11^3 + 3*11^4 + 6*11^5 + 10*11^6 + 8*11^7 + O(11^8) ? z^5 %5 = 1 + O(11^9) ? E = ellinit(ellfromj(1/4), O(2^6)); x=1/2; y=ellordinate(E,x)[1]; ? z = ellpointtoz(E,[x,y]); \\ t_POLMOD of t_POL with t_PADIC coeffs ? liftint(z) \\ lift all p-adics %8 = Mod(8*u + 7, u^2 + 437) @eprog pari-2.11.2/src/functions/elliptic_curves/ellformaldifferential0000644000175000017500000000165413201017466023434 0ustar billbillFunction: ellformaldifferential Section: elliptic_curves C-Name: ellformaldifferential Prototype: GDPDn Help:ellformaldifferential(E, {n=seriesprecision}, {t = 'x}) : E elliptic curve, n integer. Returns n terms of the power series [f, g] such that omega = dx/(2y+a_1x+a_3) = f(t) dt and eta = x(t) * omega = g(t) dt in the local parameter t=-x/y. Doc:Let $\omega := dx / (2y+a_1x+a_3)$ be the invariant differential form attached to the model $E$ of some elliptic curve (\kbd{ellinit} form), and $\eta := x(t)\omega$. Return $n$ terms (\tet{seriesprecision} by default) of $f(t),g(t)$ two power series in the formal parameter $t=-x/y$ such that $\omega = f(t) dt$, $\eta = g(t) dt$: $$f(t) = 1+a_1 t + (a_1^2 + a_2) t^2 + \dots,\quad g(t) = t^{-2} +\dots $$ \bprog ? E = ellinit([-1,1/4]); [f,g] = ellformaldifferential(E,7,'t); ? f %2 = 1 - 2*t^4 + 3/4*t^6 + O(t^7) ? g %3 = t^-2 - t^2 + 1/2*t^4 + O(t^5) @eprog pari-2.11.2/src/functions/elliptic_curves/ellformalexp0000644000175000017500000000132213201017466021564 0ustar billbillFunction: ellformalexp Section: elliptic_curves C-Name: ellformalexp Prototype: GDPDn Help: ellformalexp(E, {n = seriesprecision}, {z = 'x}) : E elliptic curve, returns n terms of the formal elliptic exponential on E as a series in z. Doc: The elliptic formal exponential \kbd{Exp} attached to $E$ is the isomorphism from the formal additive law to the formal group of $E$. It is normalized so as to be the inverse of the elliptic logarithm (see \tet{ellformallog}): $\kbd{Exp} \circ L = \Id$. Return $n$ terms of this power series: \bprog ? E=ellinit([-1,1/4]); Exp = ellformalexp(E,10,'z) %1 = z + 2/5*z^5 - 3/28*z^7 + 2/15*z^9 + O(z^11) ? L = ellformallog(E,10,'t); ? subst(Exp,z,L) %3 = t + O(t^11) @eprog pari-2.11.2/src/functions/elliptic_curves/elllseries0000644000175000017500000000134613201017466021243 0ustar billbillFunction: elllseries Section: elliptic_curves C-Name: elllseries Prototype: GGDGp Help: elllseries(E,s,{A=1}): L-series at s of the elliptic curve E, where A a cut-off point close to 1. Obsolete: 2016-08-08 Doc: This function is deprecated, use \kbd{lfun(E,s)} instead. $E$ being an elliptic curve, given by an arbitrary model over $\Q$ as output by \kbd{ellinit}, this function computes the value of the $L$-series of $E$ at the (complex) point $s$. This function uses an $O(N^{1/2})$ algorithm, where $N$ is the conductor. The optional parameter $A$ fixes a cutoff point for the integral and is best left omitted; the result must be independent of $A$, up to \kbd{realprecision}, so this allows to check the function's accuracy. pari-2.11.2/src/functions/elliptic_curves/ellfromeqn0000644000175000017500000000345013201017466021242 0ustar billbillFunction: ellfromeqn Section: elliptic_curves C-Name: ellfromeqn Prototype: G Help: ellfromeqn(P): given a genus 1 plane curve, defined by the affine equation f(x,y) = 0, return the coefficients [a1,a2,a3,a4,a6] of a Weierstrass equation for its Jacobian. This allows to recover a Weierstrass model for an elliptic curve given by a general plane cubic or by a binary quartic or biquadratic model. Doc: Given a genus $1$ plane curve, defined by the affine equation $f(x,y) = 0$, return the coefficients $[a_1,a_2,a_3,a_4,a_6]$ of a Weierstrass equation for its Jacobian. This allows to recover a Weierstrass model for an elliptic curve given by a general plane cubic or by a binary quartic or biquadratic model. The function implements the $f \mapsto f^*$ formulae of Artin, Tate and Villegas (Advances in Math. 198 (2005), pp. 366--382). In the example below, the function is used to convert between twisted Edwards coordinates and Weierstrass coordinates. \bprog ? e = ellfromeqn(a*x^2+y^2 - (1+d*x^2*y^2)) %1 = [0, -a - d, 0, -4*d*a, 4*d*a^2 + 4*d^2*a] ? E = ellinit(ellfromeqn(y^2-x^2 - 1 +(121665/121666*x^2*y^2)),2^255-19); ? isprime(ellcard(E) / 8) %3 = 1 @eprog The elliptic curve attached to the sum of two cubes is given by \bprog ? ellfromeqn(x^3+y^3 - a) %1 = [0, 0, -9*a, 0, -27*a^2] @eprog \misctitle{Congruent number problem:} Let $n$ be an integer, if $a^2+b^2=c^2$ and $a\*b=2\*n$, then by substituting $b$ by $2\*n/a$ in the first equation, we get $((a^2+(2\*n/a)^2)-c^2)\*a^2 = 0$. We set $x=a$, $y=a\*c$. \bprog ? En = ellfromeqn((x^2 + (2*n/x)^2 - (y/x)^2)*x^2) %1 = [0, 0, 0, -16*n^2, 0] @eprog For example $23$ is congruent since the curve has a point of infinite order, namely: \bprog ? ellheegner( ellinit(subst(En, n, 23)) ) %2 = [168100/289, 68053440/4913] @eprog pari-2.11.2/src/functions/elliptic_curves/ellsub0000644000175000017500000000036112314242551020361 0ustar billbillFunction: ellsub Section: elliptic_curves C-Name: ellsub Prototype: GGG Help: ellsub(E,z1,z2): difference of the points z1 and z2 on elliptic curve E. Doc: difference of the points $z1$ and $z2$ on the elliptic curve corresponding to $E$. pari-2.11.2/src/functions/elliptic_curves/ellminimaldisc0000644000175000017500000000055213326135265022072 0ustar billbillFunction: ellminimaldisc Section: elliptic_curves C-Name: ellminimaldisc Prototype: G Help: ellminimaldisc(E): E being an elliptic curve defined over a number field output by ellinit, return the minimal discriminant ideal of E. Doc: $E$ being an elliptic curve defined over a number field output by \kbd{ellinit}, return the minimal discriminant ideal of E. pari-2.11.2/src/functions/elliptic_curves/elladd0000644000175000017500000000034312314242551020320 0ustar billbillFunction: elladd Section: elliptic_curves C-Name: elladd Prototype: GGG Help: elladd(E,z1,z2): sum of the points z1 and z2 on elliptic curve E. Doc: sum of the points $z1$ and $z2$ on the elliptic curve corresponding to $E$. pari-2.11.2/src/functions/elliptic_curves/ellweilpairing0000644000175000017500000000047613201017466022112 0ustar billbillFunction: ellweilpairing Section: elliptic_curves C-Name: ellweilpairing Prototype: GGGG Help: ellweilpairing(E, P, Q, m): computes the Weil pairing of the two points of m-torsion P and Q on the elliptic curve E. Doc: Computes the Weil pairing of the two points of $m$-torsion $P$ and $Q$ on the elliptic curve $E$. pari-2.11.2/src/functions/elliptic_curves/ellorder0000644000175000017500000000352413201017466020710 0ustar billbillFunction: ellorder Section: elliptic_curves C-Name: ellorder Prototype: GGDG Help: ellorder(E,z,{o}): order of the point z on the elliptic curve E over a number field or a finite field, 0 if non-torsion. The parameter o, if present, represents a non-zero multiple of the order of z. Doc: gives the order of the point $z$ on the elliptic curve $E$, defined over a finite field or a number field. Return (the impossible value) zero if the point has infinite order. \bprog ? E = ellinit([-157^2,0]); \\ the "157-is-congruent" curve ? P = [2,2]; ellorder(E, P) %2 = 2 ? P = ellheegner(E); ellorder(E, P) \\ infinite order %3 = 0 ? K = nfinit(polcyclo(11,t)); E=ellinit("11a3", K); T = elltors(E); ? ellorder(E, T.gen[1]) %5 = 25 ? E = ellinit(ellfromj(ffgen(5^10))); ? ellcard(E) %7 = 9762580 ? P = random(E); ellorder(E, P) %8 = 4881290 ? p = 2^160+7; E = ellinit([1,2], p); ? N = ellcard(E) %9 = 1461501637330902918203686560289225285992592471152 ? o = [N, factor(N)]; ? for(i=1,100, ellorder(E,random(E))) time = 260 ms. @eprog The parameter $o$, is now mostly useless, and kept for backward compatibility. If present, it represents a non-zero multiple of the order of $z$, see \secref{se:DLfun}; the preferred format for this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord} is the cardinality of the curve. It is no longer needed since PARI is now able to compute it over large finite fields (was restricted to small prime fields at the time this feature was introduced), \emph{and} caches the result in $E$ so that it is computed and factored only once. Modifying the last example, we see that including this extra parameter provides no improvement: \bprog ? o = [N, factor(N)]; ? for(i=1,100, ellorder(E,random(E),o)) time = 260 ms. @eprog Variant: The obsolete form \fun{GEN}{orderell}{GEN e, GEN z} should no longer be used. pari-2.11.2/src/functions/elliptic_curves/ellpadicregulator0000644000175000017500000000400513326135265022603 0ustar billbillFunction: ellpadicregulator Section: elliptic_curves C-Name: ellpadicregulator Prototype: GGLG Help:ellpadicregulator(E,p,n,S): E elliptic curve/Q, S a vector of points in E(Q), p prime, n an integer; returns the p-adic cyclotomic regulator of the points of S at precision p^n. Doc: Let $E/\Q$ be an elliptic curve. Return the determinant of the Gram matrix of the vector of points $S=(S_1,\cdots, S_r)$ with respect to the ``canonical'' cyclotomic $p$-adic height on $E$, given to $n$ ($p$-adic) digits. When $E$ has ordinary reduction at $p$, this is the expected Gram deteterminant in $\Q_p$. In the case of supersingular reduction of $E$ at $p$, the definition requires care: the regulator $R$ is an element of $D := H^1_{dR}(E) \otimes_\Q \Q_p$, which is a two-dimensional $\Q_p$-vector space spanned by $\omega$ and $\eta = x \omega$ (which are defined over $\Q$) or equivalently but now over $\Q_p$ by $\omega$ and $F\omega$ where $F$ is the Frobenius endomorphism on $D$ as defined in \kbd{ellpadicfrobenius}. On $D$ we define the cyclotomic height $h_E = f \omega + g \eta$ (see \tet{ellpadicheight}) and a canonical alternating bilinear form $[.,.]_D$ such that $[\omega, \eta]_D = 1$. For any $\nu \in D$, we can define a height $h_\nu := [ h_E, \nu ]_D$ from $E(\Q)$ to $\Q_p$ and $\langle \cdot, \cdot \rangle_\nu$ the attached bilinear form. In particular, if $h_E = f \omega + g\eta$, then $h_\eta = [ h_E, \eta ]_D$ = f and $h_\omega = [ h_E, \omega ]_D = - g$ hence $h_E = h_\eta \omega - h_\omega \eta$. Then, $R$ is the unique element of $D$ such that $$[\omega,\nu]_D^{r-1} [R, \nu]_D = \det(\langle S_i, S_j \rangle_{\nu})$$ for all $\nu \in D$ not in $\Q_p \omega$. The \kbd{ellpadicregulator} function returns $R$ in the basis $(\omega, F\omega)$, which was chosen so that $p$-adic BSD conjectures are easy to state, see \kbd{ellpadicbsd}. Note that by definition $$[R, \eta]_D = \det(\langle S_i, S_j \rangle_{\eta})$$ and $$[R, \omega+\eta]_D =\det(\langle S_i, S_j \rangle_{\omega+\eta}).$$ pari-2.11.2/src/functions/elliptic_curves/ellisomat0000644000175000017500000000452413326135265021100 0ustar billbillFunction: ellisomat Section: elliptic_curves C-Name: ellisomat Prototype: GD0,L,D0,L, Help: ellisomat(E, {p=0}, {fl=0}): E being an elliptic curve over a number field, return a list of representatives of the isomorphism classes of elliptic curves isogenous to E, with the corresponding isogenies from E and their dual, and the matrix of the degrees of the isogenies between the curves. If the flag fl is 1, the isogenies are not computed, which saves time. If p is set, it must be a prime number: in this case only isogenies of degree a power of p are considered. Currently CM curves over a number field are not fully supported. Doc: Given an elliptic curve $E$ defined over a number field, compute representatives of the isomorphism classes of elliptic curves $\Q$-isogenous to $E$. The function returns a vector $[L,M]$ where $L$ is a list of triples $[E_i, f_i, g_i]$, where $E_i$ is an elliptic curve in $[a_4,a_6]$ form, $f_i: E \to E_i$ is a rational isogeny, $g_i: E_i \to E$ is the dual isogeny of $f_i$, and $M$ is the matrix such that $M_{i,j}$ is the degree of the isogeny between $E_i$ and $E_j$. Furthermore the first curve $E_1$ is isomorphic to $E$ by $f_1$. If the flag $\var{fl}=1$, the $f_i$ and $g_i$ are not computed, which saves time, and $L$ is the list of the curves $E_i$. If $p$ is set, it must be a prime number; in this which case only isogenies of degree a power of $p$ are considered. Over a number field, the possible isogeny degrees are determined by Billerey algorithm. As a consequence, CM curves over a number field are not fully supported. \bprog ? E = ellinit("14a1"); ? [L,M] = ellisomat(E); ? LE = apply(x->x[1], L) \\ list of curves %3 = [[215/48,-5291/864],[-675/16,6831/32],[-8185/48,-742643/864], [-1705/48,-57707/864],[-13635/16,306207/32],[-131065/48,-47449331/864]] ? L[2][2] \\ isogeny f_2 %4 = [x^3+3/4*x^2+19/2*x-311/12, 1/2*x^4+(y+1)*x^3+(y-4)*x^2+(-9*y+23)*x+(55*y+55/2),x+1/3] ? L[2][3] \\ dual isogeny g_2 %5 = [1/9*x^3-1/4*x^2-141/16*x+5613/64, -1/18*x^4+(1/27*y-1/3)*x^3+(-1/12*y+87/16)*x^2+(49/16*y-48)*x +(-3601/64*y+16947/512),x-3/4] ? apply(E->ellidentify(ellinit(E))[1][1], LE) %6 = ["14a1","14a4","14a3","14a2","14a6","14a5"] ? M %7 = [1 3 3 2 6 6] [3 1 9 6 2 18] [3 9 1 6 18 2] [2 6 6 1 3 3] [6 2 18 3 1 9] [6 18 2 3 9 1] @eprog pari-2.11.2/src/functions/elliptic_curves/ellzeta0000644000175000017500000000271013036414402020531 0ustar billbillFunction: ellzeta Section: elliptic_curves C-Name: ellzeta Prototype: GDGp Help: ellzeta(w,{z='x}): computes the value at z of the Weierstrass Zeta function attached to the lattice w, as given by ellperiods(,1). Doc: Computes the value at $z$ of the Weierstrass $\zeta$ function attached to the lattice $w$ as given by \tet{ellperiods}$(,1)$: including quasi-periods is useful, otherwise there are recomputed from scratch for each new $z$. $$ \zeta(z, L) = \dfrac{1}{z} + z^2\sum_{\omega\in L^*} \dfrac{1}{\omega^2(z-\omega)}.$$ It is also possible to directly input $w = [\omega_1,\omega_2]$, or an elliptic curve $E$ as given by \kbd{ellinit} ($w = \kbd{E.omega}$). The quasi-periods of $\zeta$, such that $$\zeta(z + a\omega_1 + b\omega_2) = \zeta(z) + a\eta_1 + b\eta_2 $$ for integers $a$ and $b$ are obtained as $\eta_i = 2\zeta(\omega_i/2)$. Or using directly \tet{elleta}. \bprog ? w = ellperiods([1,I],1); ? ellzeta(w, 1/2) %2 = 1.5707963267948966192313216916397514421 ? E = ellinit([1,0]); ? ellzeta(E, E.omega[1]/2) %4 = 0.84721308479397908660649912348219163647 @eprog\noindent One can also compute the series expansion around $z = 0$ (the quasi-periods are useless in this case): \bprog ? E = ellinit([0,1]); ? ellzeta(E) \\ at 'x, implicitly at default seriesprecision %4 = x^-1 + 1/35*x^5 - 1/7007*x^11 + O(x^15) ? ellzeta(E, x + O(x^20)) \\ explicit precision %5 = x^-1 + 1/35*x^5 - 1/7007*x^11 + 1/1440257*x^17 + O(x^18) @eprog\noindent pari-2.11.2/src/functions/elliptic_curves/elltors0000644000175000017500000000144713201017466020566 0ustar billbillFunction: elltors Section: elliptic_curves C-Name: elltors Prototype: G Help: elltors(E): torsion subgroup of elliptic curve E: order, structure, generators. Doc: if $E$ is an elliptic curve defined over a number field or a finite field, outputs the torsion subgroup of $E$ as a 3-component vector \kbd{[t,v1,v2]}, where \kbd{t} is the order of the torsion group, \kbd{v1} gives the structure of the torsion group as a product of cyclic groups (sorted by decreasing order), and \kbd{v2} gives generators for these cyclic groups. $E$ must be an \kbd{ell} structure as output by \kbd{ellinit}. \bprog ? E = ellinit([-1,0]); ? elltors(E) %1 = [4, [2, 2], [[0, 0], [1, 0]]] @eprog\noindent Here, the torsion subgroup is isomorphic to $\Z/2\Z \times \Z/2\Z$, with generators $[0,0]$ and $[1,0]$. pari-2.11.2/src/functions/elliptic_curves/elltatepairing0000644000175000017500000000055213201017466022102 0ustar billbillFunction: elltatepairing Section: elliptic_curves C-Name: elltatepairing Prototype: GGGG Help: elltatepairing(E, P, Q, m): computes the Tate pairing of the two points P and Q on the elliptic curve E. The point P must be of m-torsion. Doc: Computes the Tate pairing of the two points $P$ and $Q$ on the elliptic curve $E$. The point $P$ must be of $m$-torsion. pari-2.11.2/src/functions/elliptic_curves/ellfromj0000644000175000017500000000043712314242551020711 0ustar billbillFunction: ellfromj Section: elliptic_curves C-Name: ellfromj Prototype: G Help: ellfromj(j): returns the coefficients [a1,a2,a3,a4,a6] of a fixed elliptic curve with j-invariant j. Doc: returns the coefficients $[a_1,a_2,a_3,a_4,a_6]$ of a fixed elliptic curve with $j$-invariant $j$. pari-2.11.2/src/functions/elliptic_curves/ellisdivisible0000644000175000017500000000203113326135265022101 0ustar billbillFunction: ellisdivisible Section: elliptic_curves C-Name: ellisdivisible Prototype: lGGGD& Help: ellisdivisible(E,P,n,{&Q}): given E/K and P in E(K), checks whether P = [n]R for some R in E(K) and sets Q to one such R if so; the integer n >= 0 may be given as ellxn(E,n). Doc: given $E/K$ a number field and $P$ in $E(K)$ return $1$ if $P = [n]R$ for some $R$ in $E(K)$ and set $Q$ to one such $R$; and return $0$ otherwise. The integer $n \geq 0$ may be given as \kbd{ellxn(E,n)}, if many points need to be tested. \bprog ? K = nfinit(polcyclo(11,t)); ? E = ellinit([0,-1,1,0,0], K); ? P = [0,0]; ? ellorder(E,P) %4 = 5 ? ellisdivisible(E,P,5, &Q) %5 = 1 ? lift(Q) %6 = [-t^7-t^6-t^5-t^4+1, -t^9-2*t^8-2*t^7-3*t^6-3*t^5-2*t^4-2*t^3-t^2-1] ? ellorder(E, Q) %7 = 25 @eprog\noindent The algebraic complexity of the underlying algorithm is in $O(n^4)$, so it is advisable to first factor $n$, then use a chain of checks attached to the prime divisors of $n$: the function will do it itself unless $n$ is given in \kbd{ellxn} form. pari-2.11.2/src/functions/elliptic_curves/ellminimaltwist0000644000175000017500000000266313326135265022327 0ustar billbillFunction: ellminimaltwist Section: elliptic_curves C-Name: ellminimaltwist0 Prototype: GD0,L, Help: ellminimaltwist(E, {flag=0}): E being an elliptic curve defined over Q, return a discriminant D such that the twist of E by D is minimal among all possible quadratic twists, i.e., if flag=0, its minimal model has minimal discriminant, or if flag=1, it has minimal conductor. Doc: Let $E$ be an elliptic curve defined over $\Q$, return a discriminant $D$ such that the twist of $E$ by $D$ is minimal among all possible quadratic twists, i.e. if $\fl=0$, its minimal model has minimal discriminant, or if $\fl=1$, it has minimal conductor. In the example below, we find a curve with $j$-invariant $3$ and minimal conductor. \bprog ? E = ellminimalmodel(ellinit(ellfromj(3))); ? ellglobalred(E)[1] %2 = 357075 ? D = ellminimaltwist(E,1) %3 = -15 ? E2 = ellminimalmodel(ellinit(elltwist(E,D))); ? ellglobalred(E2)[1] %5 = 14283 @eprog In the example below, $\fl=0$ and $\fl=1$ give different results. \bprog ? E = ellinit([1,0]); ? D0 = ellminimaltwist(E,0) %7 = 1 ? D1 = ellminimaltwist(E,1) %8 = 8 ? E0 = ellminimalmodel(ellinit(elltwist(E,D0))); ? [E0.disc, ellglobalred(E0)[1]] %10 = [-64, 64] ? E1 = ellminimalmodel(ellinit(elltwist(E,D1))); ? [E1.disc, ellglobalred(E1)[1]] %12 = [-4096, 32] @eprog Variant: Also available are \fun{GEN}{ellminimaltwist}{E} for $\fl=0$, and \fun{GEN}{ellminimaltwistcond}{E} for $\fl=1$. pari-2.11.2/src/functions/elliptic_curves/ellisotree0000644000175000017500000000261313326135265021253 0ustar billbillFunction: ellisotree Section: elliptic_curves C-Name: ellisotree Prototype: G Help: ellisotree(E): E being an elliptic curve over Q or a set of isogenous rational curves as given by ellisomat, return minimal models of the isomorphism classes of elliptic curves isogenous to E (or in the set) and the oriented graph of isogenies of prime degree (adjacency matrix). Doc: Given an elliptic curve $E$ defined over $\Q$ or a set of $\Q$-isogenous curves as given by \kbd{ellisomat}, return a pair $[L,M]$ where \item $L$ lists the minimal models of the isomorphism classes of elliptic curves $\Q$-isogenous to $E$ (or in the set of isogenous curves), \item $M$ is the adjacency matrix of the prime degree isogenies tree: there is an edge from $E_i$ to $E_j$ if there is an isogeny $E_i \to E_j$ of prime degree such that the N\'eron differential forms are preserved. \bprog ? E = ellinit("14a1"); ? [L,M] = ellisotree(E); ? M %3 = [0 0 3 2 0 0] [3 0 0 0 2 0] [0 0 0 0 0 2] [0 0 0 0 0 3] [0 0 0 3 0 0] [0 0 0 0 0 0] ? [L2,M2] = ellisotree(ellisomat(E,2,1)); %4 = [0 2] [0 0] ? [L3,M3] = ellisotree(ellisomat(E,3,1)); ? M3 %6 = [0 0 3] [3 0 0] [0 0 0] @eprog\noindent Compare with the result of \kbd{ellisomat}. \bprog ? [L,M]=ellisomat(E,,1); ? M %7 = [1 3 3 2 6 6] [3 1 9 6 2 18] [3 9 1 6 18 2] [2 6 6 1 3 3] [6 2 18 3 1 9] [6 18 2 3 9 1] @eprog pari-2.11.2/src/functions/elliptic_curves/ellheegner0000644000175000017500000000207313201017466021210 0ustar billbillFunction: ellheegner Section: elliptic_curves C-Name: ellheegner Prototype: G Help: ellheegner(E): return a rational non-torsion point on the elliptic curve E assumed to be of rank 1. Doc: Let $E$ be an elliptic curve over the rationals, assumed to be of (analytic) rank $1$. This returns a non-torsion rational point on the curve, whose canonical height is equal to the product of the elliptic regulator by the analytic Sha. This uses the Heegner point method, described in Cohen GTM 239; the complexity is proportional to the product of the square root of the conductor and the height of the point (thus, it is preferable to apply it to strong Weil curves). \bprog ? E = ellinit([-157^2,0]); ? u = ellheegner(E); print(u[1], "\n", u[2]) 69648970982596494254458225/166136231668185267540804 538962435089604615078004307258785218335/67716816556077455999228495435742408 ? ellheegner(ellinit([0,1])) \\ E has rank 0 ! *** at top-level: ellheegner(E=ellinit *** ^-------------------- *** ellheegner: The curve has even analytic rank. @eprog pari-2.11.2/src/functions/elliptic_curves/ellan0000644000175000017500000000140313201017466020165 0ustar billbillFunction: ellan Section: elliptic_curves C-Name: ellan Prototype: GL Help: ellan(E,n): computes the first n Fourier coefficients of the L-function of the elliptic curve E defined over a number field (n<2^24 on a 32-bit machine). Doc: computes the vector of the first $n$ Fourier coefficients $a_k$ corresponding to the elliptic curve $E$ defined over a number field. If $E$ is defined over $\Q$, the curve may be given by an arbitrary model, not necessarily minimal, although a minimal model will make the function faster. Over a more general number field, the model must be locally minimal at all primes above $2$ and $3$. Variant: Also available is \fun{GEN}{ellanQ_zv}{GEN e, long n}, which returns a \typ{VECSMALL} instead of a \typ{VEC}, saving on memory. pari-2.11.2/src/functions/elliptic_curves/ellformallog0000644000175000017500000000124313201017466021553 0ustar billbillFunction: ellformallog Section: elliptic_curves C-Name: ellformallog Prototype: GDPDn Help:ellformallog(E, {n = seriesprecision}, {v = 'x}): E elliptic curve, returns n terms of the elliptic logarithm as a series of t =-x/y. Doc: The formal elliptic logarithm is a series $L$ in $t K[[t]]$ such that $d L = \omega = dx / (2y + a_1x + a_3)$, the canonical invariant differential attached to the model $E$. It gives an isomorphism from the formal group of $E$ to the additive formal group. \bprog ? E = ellinit([-1,1/4]); L = ellformallog(E, 9, 't) %1 = t - 2/5*t^5 + 3/28*t^7 + 2/3*t^9 + O(t^10) ? [f,g] = ellformaldifferential(E,8,'t); ? L' - f %3 = O(t^8) @eprog pari-2.11.2/src/functions/elliptic_curves/ellrootno0000644000175000017500000000160513326135265021121 0ustar billbillFunction: ellrootno Section: elliptic_curves C-Name: ellrootno Prototype: lGDG Help: ellrootno(E,{p}): root number for the L-function of the elliptic curve E/Q at a prime p (including 0, for the infinite place); global root number if p is omitted. If p is omitted, the curve can also be defined over a number field. Doc: $E$ being an \kbd{ell} structure over $\Q$ as output by \kbd{ellinit}, this function computes the local root number of its $L$-series at the place $p$ (at the infinite place if $p = 0$). If $p$ is omitted, return the global root number and in this case the curve can also be defined over a number field. Note that the global root number is the sign of the functional equation and conjecturally is the parity of the rank of the \idx{Mordell-Weil group}. The equation for $E$ needs not be minimal at $p$, but if the model is already minimal the function will run faster. pari-2.11.2/src/functions/elliptic_curves/ellinit0000644000175000017500000001072513201017466020541 0ustar billbillFunction: ellinit Section: elliptic_curves C-Name: ellinit Prototype: GDGp Help: ellinit(x,{D=1}): let x be a vector [a1,a2,a3,a4,a6], or [a4,a6] if a1=a2=a3=0, defining the curve Y^2 + a1.XY + a3.Y = X^3 + a2.X^2 + a4.X + a6; x can also be a string, in which case the curve with matching name is retrieved from the elldata database, if available. This function initializes an elliptic curve over the domain D (inferred from coefficients if omitted). Description: (gen, gen, small):ell:prec ellinit($1, $2, $prec) Doc: initialize an \tet{ell} structure, attached to the elliptic curve $E$. $E$ is either \item a $5$-component vector $[a_1,a_2,a_3,a_4,a_6]$ defining the elliptic curve with Weierstrass equation $$ Y^2 + a_1 XY + a_3 Y = X^3 + a_2 X^2 + a_4 X + a_6, $$ \item a $2$-component vector $[a_4,a_6]$ defining the elliptic curve with short Weierstrass equation $$ Y^2 = X^3 + a_4 X + a_6, $$ \item a character string in Cremona's notation, e.g. \kbd{"11a1"}, in which case the curve is retrieved from the \tet{elldata} database if available. The optional argument $D$ describes the domain over which the curve is defined: \item the \typ{INT} $1$ (default): the field of rational numbers $\Q$. \item a \typ{INT} $p$, where $p$ is a prime number: the prime finite field $\F_p$. \item an \typ{INTMOD} \kbd{Mod(a, p)}, where $p$ is a prime number: the prime finite field $\F_p$. \item a \typ{FFELT}, as returned by \tet{ffgen}: the corresponding finite field $\F_q$. \item a \typ{PADIC}, $O(p^n)$: the field $\Q_p$, where $p$-adic quantities will be computed to a relative accuracy of $n$ digits. We advise to input a model defined over $\Q$ for such curves. In any case, if you input an approximate model with \typ{PADIC} coefficients, it will be replaced by a lift to $\Q$ (an exact model ``close'' to the one that was input) and all quantities will then be computed in terms of this lifted model, at the given accuracy. \item a \typ{REAL} $x$: the field $\C$ of complex numbers, where floating point quantities are by default computed to a relative accuracy of \kbd{precision}$(x)$. If no such argument is given, the value of \kbd{realprecision} at the time \kbd{ellinit} is called will be used. \item a number field $K$, given by a \kbd{nf} or \kbd{bnf} structure; a \kbd{bnf} is required for \kbd{ellminimalmodel}. \item a prime ideal $\goth{p}$, given by a \kbd{prid} structure; valid if $x$ is a curve defined over a number field $K$ and the equation is integral and minimal at $\goth{p}$. This argument $D$ is indicative: the curve coefficients are checked for compatibility, possibly changing $D$; for instance if $D = 1$ and an \typ{INTMOD} is found. If inconsistencies are detected, an error is raised: \bprog ? ellinit([1 + O(5), 1], O(7)); *** at top-level: ellinit([1+O(5),1],O *** ^-------------------- *** ellinit: inconsistent moduli in ellinit: 7 != 5 @eprog\noindent If the curve coefficients are too general to fit any of the above domain categories, only basic operations, such as point addition, will be supported later. If the curve (seen over the domain $D$) is singular, fail and return an empty vector $[]$. \bprog ? E = ellinit([0,0,0,0,1]); \\ y^2 = x^3 + 1, over Q ? E = ellinit([0,1]); \\ the same curve, short form ? E = ellinit("36a1"); \\ sill the same curve, Cremona's notations ? E = ellinit([0,1], 2) \\ over F2: singular curve %4 = [] ? E = ellinit(['a4,'a6] * Mod(1,5)); \\ over F_5[a4,a6], basic support ! @eprog\noindent The result of \tet{ellinit} is an \tev{ell} structure. It contains at least the following information in its components: % $$ a_1,a_2,a_3,a_4,a_6,b_2,b_4,b_6,b_8,c_4,c_6,\Delta,j.$$ % All are accessible via member functions. In particular, the discriminant is \kbd{$E$.disc}, and the $j$-invariant is \kbd{$E$.j}. \bprog ? E = ellinit([a4, a6]); ? E.disc %2 = -64*a4^3 - 432*a6^2 ? E.j %3 = -6912*a4^3/(-4*a4^3 - 27*a6^2) @eprog Further components contain domain-specific data, which are in general dynamic: only computed when needed, and then cached in the structure. \bprog ? E = ellinit([2,3], 10^60+7); \\ E over F_p, p large ? ellap(E) time = 4,440 ms. %2 = -1376268269510579884904540406082 ? ellcard(E); \\ now instantaneous ! time = 0 ms. ? ellgenerators(E); time = 5,965 ms. ? ellgenerators(E); \\ second time instantaneous time = 0 ms. @eprog See the description of member functions related to elliptic curves at the beginning of this section. pari-2.11.2/src/functions/elliptic_curves/ellbsd0000644000175000017500000000216213326135265020350 0ustar billbillFunction: ellbsd Section: elliptic_curves C-Name: ellbsd Prototype: Gp Help: ellbsd(E): E being an elliptic curve over a number field, returns a real number c such that the BSD conjecture predicts that lfun(E,1,r)/r! = c*R*S where r is the rank, R is the regulator and S is the cardinal of the Tate-Shafarevich group. Doc: The object $E$ being an elliptic curve over a number field, returns a real number $c$ such that the BSD conjecture predicts that $L_{E}^{(r)}(1)/r! = c\*R\*S$ where $r$ is the rank, $R$ the regulator and $S$ the cardinal of the Tate-Shafarevich group. \bprog ? e = ellinit([0,-1,1,-10,-20]); \\ rank 0 ? ellbsd(e) %2 = 0.25384186085591068433775892335090946105 ? lfun(e,1) %3 = 0.25384186085591068433775892335090946104 ? e = ellinit([0,0,1,-1,0]); \\ rank 1 ? P = ellheegner(e); ? ellbsd(e)*ellheight(e,P) %6 = 0.30599977383405230182048368332167647445 ? lfun(e,1,1) %7 = 0.30599977383405230182048368332167647445 ? e = ellinit([1+a,0,1,0,0],nfinit(a^2+1)); \\ rank 0 ? ellbsd(e) %9 = 0.42521832235345764503001271536611593310 ? lfun(e,1) %10 = 0.42521832235345764503001271536611593309 @eprog pari-2.11.2/src/functions/elliptic_curves/ellratpoints0000644000175000017500000000151213326135265021621 0ustar billbillFunction: ellratpoints Section: elliptic_curves C-Name: ellratpoints Prototype: GGD0,L, Help: ellratpoints(E,h,{flag=0}): E being an integral model of an elliptic curve, return a vector containing the affine rational points on the curve of naive height less than h. If fl=1, stop as soon as a point is found. Doc: $E$ being an integral model of elliptic curve , return a vector containing the affine rational points on the curve of naive height less than $h$. If $\fl=1$, stop as soon as a point is found; return either an empty vector or a vector containing a single point. See \kbd{hyperellratpoints} for how $h$ can be specified. \bprog ? E=ellinit([-25,1]); ? ellratpoints(E,10) %2 = [[-5,1],[-5,-1],[-3,7],[-3,-7],[-1,5],[-1,-5], [0,1],[0,-1],[5,1],[5,-1],[7,13],[7,-13]] ? ellratpoints(E,10,1) %3 = [[-5,1]] @eprog pari-2.11.2/src/functions/elliptic_curves/elltwist0000644000175000017500000000242313201017466020744 0ustar billbillFunction: elltwist Section: elliptic_curves C-Name: elltwist Prototype: GDG Help: elltwist(E,{P}): returns the coefficients [a1,a2,a3,a4,a6] of the twist of the elliptic curve E by the quadratic extension defined by P (when P is a polynomial of degree 2) or quadpoly(P) (when P is an integer). If E is defined over a finite field, then P can be omitted. Doc: returns the coefficients $[a_1,a_2,a_3,a_4,a_6]$ of the twist of the elliptic curve $E$ by the quadratic extension of the coefficient ring defined by $P$ (when $P$ is a polynomial) or \kbd{quadpoly(P)} when $P$ is an integer. If $E$ is defined over a finite field, then $P$ can be omitted, in which case a random model of the unique non-trivial twist is returned. If $E$ is defined over a number field, the model should be replaced by a minimal model (if one exists). Example: Twist by discriminant $-3$: \bprog ? elltwist(ellinit([0,a2,0,a4,a6]),-3) %1 = [0,-3*a2,0,9*a4,-27*a6] @eprog Twist by the Artin-Shreier extension given by $x^2+x+T$ in characteristic $2$: \bprog ? lift(elltwist(ellinit([a1,a2,a3,a4,a6]*Mod(1,2)),x^2+x+T)) %1 = [a1,a2+a1^2*T,a3,a4,a6+a3^2*T] @eprog Twist of an elliptic curve defined over a finite field: \bprog ? E=ellinit([1,7]*Mod(1,19));lift(elltwist(E)) %1 = [0,0,0,11,12] @eprog pari-2.11.2/src/functions/elliptic_curves/ellordinate0000644000175000017500000000046311636712103021401 0ustar billbillFunction: ellordinate Section: elliptic_curves C-Name: ellordinate Prototype: GGp Help: ellordinate(E,x): y-coordinates corresponding to x-ordinate x on elliptic curve E. Doc: gives a 0, 1 or 2-component vector containing the $y$-coordinates of the points of the curve $E$ having $x$ as $x$-coordinate. pari-2.11.2/src/functions/elliptic_curves/ellintegralmodel0000644000175000017500000000132213326135265022423 0ustar billbillFunction: ellintegralmodel Section: elliptic_curves C-Name: ellintegralmodel Prototype: GD& Help: ellintegralmodel(E,{&v}): given an elliptic curve E defined over a number field or Qp, returns an integral model. If v is present, sets the variable v to the corresponding change of variable. Doc: Let $E$ be an \kbd{ell} structure over a number field $K$ or $\Q_p$. This function returns an integral model. If $v$ is present, sets $v = [u,0,0,0]$ to the corresponding change of variable: the return value is identical to that of \kbd{ellchangecurve(E, v)}. \bprog ? e = ellinit([1/17,1/42]); ? e = ellintegralmodel(e,&v); ? e[1..5] %3 = [0, 0, 0, 15287762448, 3154568630095008] ? v %4 = [1/714, 0, 0, 0] @eprog pari-2.11.2/src/functions/elliptic_curves/ellpow0000644000175000017500000000026713201017466020403 0ustar billbillFunction: ellpow Section: elliptic_curves C-Name: ellmul Prototype: GGG Obsolete: 2012-06-06 Help: ellpow(E,z,n): deprecated alias for ellmul. Doc: deprecated alias for \kbd{ellmul}. pari-2.11.2/src/functions/elliptic_curves/ellnonsingularmultiple0000644000175000017500000000155413201017466023711 0ustar billbillFunction: ellnonsingularmultiple Section: elliptic_curves C-Name: ellnonsingularmultiple Prototype: GG Help: ellnonsingularmultiple(E,P): given E/Q and P in E(Q), returns the pair [R,n] where n is the least positive integer such that R = [n]P has everywhere good reduction. More precisely, its image in a minimal model is everywhere non-singular. Doc: given an elliptic curve $E/\Q$ (more precisely, a model defined over $\Q$ of a curve) and a rational point $P \in E(\Q)$, returns the pair $[R,n]$, where $n$ is the least positive integer such that $R := [n]P$ has good reduction at every prime. More precisely, its image in a minimal model is everywhere non-singular. \bprog ? e = ellinit("57a1"); P = [2,-2]; ? ellnonsingularmultiple(e, P) %2 = [[1, -1], 2] ? e = ellinit("396b2"); P = [35, -198]; ? [R,n] = ellnonsingularmultiple(e, P); ? n %5 = 12 @eprog pari-2.11.2/src/functions/elliptic_curves/ellsearch0000644000175000017500000000343213201017466021040 0ustar billbillFunction: ellsearch Section: elliptic_curves C-Name: ellsearch Prototype: G Help: ellsearch(N): returns all curves in the elldata database matching constraint N: given name (N = "11a1" or [11,0,1]), given isogeny class (N = "11a" or [11,0]), or given conductor (N = 11, "11", or [11]). Doc: This function finds all curves in the \tet{elldata} database satisfying the constraint defined by the argument $N$: \item if $N$ is a character string, it selects a given curve, e.g. \kbd{"11a1"}, or curves in the given isogeny class, e.g. \kbd{"11a"}, or curves with given conductor, e.g. \kbd{"11"}; \item if $N$ is a vector of integers, it encodes the same constraints as the character string above, according to the \tet{ellconvertname} correspondance, e.g. \kbd{[11,0,1]} for \kbd{"11a1"}, \kbd{[11,0]} for \kbd{"11a"} and \kbd{[11]} for \kbd{"11"}; \item if $N$ is an integer, curves with conductor $N$ are selected. If $N$ codes a full curve name, for instance \kbd{"11a1"} or \kbd{[11,0,1]}, the output format is $[N, [a_1,a_2,a_3,a_4,a_6], G]$ where $[a_1,a_2,a_3,a_4,a_6]$ are the coefficients of the Weierstrass equation of the curve and $G$ is a $\Z$-basis of the free part of the \idx{Mordell-Weil group} attached to the curve. \bprog ? ellsearch("11a3") %1 = ["11a3", [0, -1, 1, 0, 0], []] ? ellsearch([11,0,3]) %2 = ["11a3", [0, -1, 1, 0, 0], []] @eprog\noindent If $N$ is not a full curve name, then the output is a vector of all matching curves in the above format: \bprog ? ellsearch("11a") %1 = [["11a1", [0, -1, 1, -10, -20], []], ["11a2", [0, -1, 1, -7820, -263580], []], ["11a3", [0, -1, 1, 0, 0], []]] ? ellsearch("11b") %2 = [] @eprog Variant: Also available is \fun{GEN}{ellsearchcurve}{GEN N} that only accepts complete curve names (as \typ{STR}). pari-2.11.2/src/functions/elliptic_curves/ellisogenyapply0000644000175000017500000000170413201017466022316 0ustar billbillFunction: ellisogenyapply Section: elliptic_curves C-Name: ellisogenyapply Prototype: GG Help: ellisogenyapply(f, g): given an isogeny f and g either a point P (in the domain of f) or an isogeny, apply f to g: return the image of P under f or the composite isogeny f o g. Doc: Given an isogeny of elliptic curves $f:E'\to E$ (being the result of a call to \tet{ellisogeny}), apply $f$ to $g$: \item if $g$ is a point $P$ in the domain of $f$, return the image $f(P)$; \item if $g:E''\to E'$ is a compatible isogeny, return the composite isogeny $f \circ g: E''\to E$. \bprog ? one = ffgen(101, 't)^0; ? E = ellinit([6, 53, 85, 32, 34] * one); ? P = [84, 71] * one; ? ellorder(E, P) %4 = 5 ? [F, f] = ellisogeny(E, P); \\ f: E->F = E/

? ellisogenyapply(f, P) %6 = [0] ? F = ellinit(F); ? Q = [89, 44] * one; ? ellorder(F, Q) %9 = 2 ? [G, g] = ellisogeny(F, Q); \\ g: F->G = F/ ? gof = ellisogenyapply(g, f); \\ gof: E -> G @eprog pari-2.11.2/src/functions/elliptic_curves/elleta0000644000175000017500000000112313201017466020337 0ustar billbillFunction: elleta Section: elliptic_curves C-Name: elleta Prototype: Gp Help: elleta(w): w=[w1,w2], returns the vector [eta1,eta2] of quasi-periods attached to [w1,w2]. Doc: returns the quasi-periods $[\eta_1,\eta_2]$ attached to the lattice basis $\var{w} = [\omega_1, \omega_2]$. Alternatively, \var{w} can be an elliptic curve $E$ as output by \kbd{ellinit}, in which case, the quasi periods attached to the period lattice basis \kbd{$E$.omega} (namely, \kbd{$E$.eta}) are returned. \bprog ? elleta([1, I]) %1 = [3.141592653589793238462643383, 9.424777960769379715387930149*I] @eprog pari-2.11.2/src/functions/elliptic_curves/elldivpol0000644000175000017500000000156512314242551021074 0ustar billbillFunction: elldivpol Section: elliptic_curves C-Name: elldivpol Prototype: GLDn Help: elldivpol(E,n,{v='x}): n-division polynomial f_n for the curve E in the variable v. Doc: $n$-division polynomial $f_n$ for the curve $E$ in the variable $v$. In standard notation, for any affine point $P = (X,Y)$ on the curve, we have $$[n]P = (\phi_n(P)\psi_n(P) : \omega_n(P) : \psi_n(P)^3)$$ for some polynomials $\phi_n,\omega_n,\psi_n$ in $\Z[a_1,a_2,a_3,a_4,a_6][X,Y]$. We have $f_n(X) = \psi_n(X)$ for $n$ odd, and $f_n(X) = \psi_n(X,Y) (2Y + a_1X+a_3)$ for $n$ even. We have $$ f_1 = 1,\quad f_2 = 4X^3 + b_2X^2 + 2b_4 X + b_6, \quad f_3 = 3 X^4 + b_2 X^3 + 3b_4 X^2 + 3 b_6 X + b8, $$ $$ f_4 = f_2(2X^6 + b_2 X^5 + 5b_4 X^4 + 10 b_6 X^3 + 10 b_8 X^2 + (b_2b_8-b_4b_6)X + (b_8b_4 - b_6^2)), \dots $$ For $n \geq 2$, the roots of $f_n$ are the $X$-coordinates of points in $E[n]$. pari-2.11.2/src/functions/elliptic_curves/genus2red0000644000175000017500000001357013201017466021000 0ustar billbillFunction: genus2red Section: elliptic_curves C-Name: genus2red Prototype: GDG Help: genus2red(PQ,{p}): let PQ be a polynomial P, resp. a vector [P,Q] of polynomials, with rational coefficients. Determines the reduction at p > 2 of the (proper, smooth) hyperelliptic curve C/Q of genus 2 defined by y^2 = P, resp. y^2 + Q*y = P. More precisely, determines the special fiber X_p of the minimal regular model X of C over Z. Doc: Let $PQ$ be a polynomial $P$, resp. a vector $[P,Q]$ of polynomials, with rational coefficients. Determines the reduction at $p > 2$ of the (proper, smooth) genus~2 curve $C/\Q$, defined by the hyperelliptic equation $y^2 = P(x)$, resp. $y^2 + Q(x)*y = P(x)$. (The special fiber $X_p$ of the minimal regular model $X$ of $C$ over $\Z$.) If $p$ is omitted, determines the reduction type for all (odd) prime divisors of the discriminant. \noindent This function was rewritten from an implementation of Liu's algorithm by Cohen and Liu (1994), \kbd{genus2reduction-0.3}, see \url{http://www.math.u-bordeaux.fr/~liu/G2R/}. \misctitle{CAVEAT} The function interface may change: for the time being, it returns $[N,\var{FaN}, T, V]$ where $N$ is either the local conductor at $p$ or the global conductor, \var{FaN} is its factorization, $y^2 = T$ defines a minimal model over $\Z[1/2]$ and $V$ describes the reduction type at the various considered~$p$. Unfortunately, the program is not complete for $p = 2$, and we may return the odd part of the conductor only: this is the case if the factorization includes the (impossible) term $2^{-1}$; if the factorization contains another power of $2$, then this is the exact local conductor at $2$ and $N$ is the global conductor. \bprog ? default(debuglevel, 1); ? genus2red(x^6 + 3*x^3 + 63, 3) (potential) stable reduction: [1, []] reduction at p: [III{9}] page 184, [3, 3], f = 10 %1 = [59049, Mat([3, 10]), x^6 + 3*x^3 + 63, [3, [1, []], ["[III{9}] page 184", [3, 3]]]] ? [N, FaN, T, V] = genus2red(x^3-x^2-1, x^2-x); \\ X_1(13), global reduction p = 13 (potential) stable reduction: [5, [Mod(0, 13), Mod(0, 13)]] reduction at p: [I{0}-II-0] page 159, [], f = 2 ? N %3 = 169 ? FaN %4 = Mat([13, 2]) \\ in particular, good reduction at 2 ! ? T %5 = x^6 + 58*x^5 + 1401*x^4 + 18038*x^3 + 130546*x^2 + 503516*x + 808561 ? V %6 = [[13, [5, [Mod(0, 13), Mod(0, 13)]], ["[I{0}-II-0] page 159", []]]] @eprog\noindent We now first describe the format of the vector $V = V_p$ in the case where $p$ was specified (local reduction at~$p$): it is a triple $[p, \var{stable}, \var{red}]$. The component $\var{stable} = [\var{type}, \var{vecj}]$ contains information about the stable reduction after a field extension; depending on \var{type}s, the stable reduction is \item 1: smooth (i.e. the curve has potentially good reduction). The Jacobian $J(C)$ has potentially good reduction. \item 2: an elliptic curve $E$ with an ordinary double point; \var{vecj} contains $j$ mod $p$, the modular invariant of $E$. The (potential) semi-abelian reduction of $J(C)$ is the extension of an elliptic curve (with modular invariant $j$ mod $p$) by a torus. \item 3: a projective line with two ordinary double points. The Jacobian $J(C)$ has potentially multiplicative reduction. \item 4: the union of two projective lines crossing transversally at three points. The Jacobian $J(C)$ has potentially multiplicative reduction. \item 5: the union of two elliptic curves $E_1$ and $E_2$ intersecting transversally at one point; \var{vecj} contains their modular invariants $j_1$ and $j_2$, which may live in a quadratic extension of $\F_p$ and need not be distinct. The Jacobian $J(C)$ has potentially good reduction, isomorphic to the product of the reductions of $E_1$ and $E_2$. \item 6: the union of an elliptic curve $E$ and a projective line which has an ordinary double point, and these two components intersect transversally at one point; \var{vecj} contains $j$ mod $p$, the modular invariant of $E$. The (potential) semi-abelian reduction of $J(C)$ is the extension of an elliptic curve (with modular invariant $j$ mod $p$) by a torus. \item 7: as in type 6, but the two components are both singular. The Jacobian $J(C)$ has potentially multiplicative reduction. The component $\var{red} = [\var{NUtype}, \var{neron}]$ contains two data concerning the reduction at $p$ without any ramified field extension. The \var{NUtype} is a \typ{STR} describing the reduction at $p$ of $C$, following Namikawa-Ueno, \emph{The complete classification of fibers in pencils of curves of genus two}, Manuscripta Math., vol. 9, (1973), pages 143-186. The reduction symbol is followed by the corresponding page number or page range in this article. The second datum \var{neron} is the group of connected components (over an algebraic closure of $\F_p$) of the N\'eron model of $J(C)$, given as a finite abelian group (vector of elementary divisors). \smallskip If $p = 2$, the \var{red} component may be omitted altogether (and replaced by \kbd{[]}, in the case where the program could not compute it. When $p$ was not specified, $V$ is the vector of all $V_p$, for all considered $p$. \misctitle{Notes about Namikawa-Ueno types} \item A lower index is denoted between braces: for instance, \kbd{[I\obr2\cbr-II-5]} means \kbd{[I\_2-II-5]}. \item If $K$ and $K'$ are Kodaira symbols for singular fibers of elliptic curves, then \kbd{[$K$-$K'$-m]} and \kbd{[$K'$-$K$-m]} are the same. We define a total ordering on Kodaira symbol by fixing $\kbd{I} < \kbd{I*} < \kbd{II} < \kbd{II*}, \dots$. If the reduction type is the same, we order by the number of components, e.g. $\kbd{I}_2 < \kbd{I}_4$, etc. Then we normalize our output so that $K \leq K'$. \item \kbd{[$K$-$K'$-$-1$]} is \kbd{[$K$-$K'$-$\alpha$]} in the notation of Namikawa-Ueno. \item The figure \kbd{[2I\_0-m]} in Namikawa-Ueno, page 159, must be denoted by \kbd{[2I\_0-(m+1)]}. pari-2.11.2/src/functions/elliptic_curves/ellweilcurve0000644000175000017500000000516213326135265021610 0ustar billbillFunction: ellweilcurve Section: elliptic_curves C-Name: ellweilcurve Prototype: GD& Help: ellweilcurve(E, {&ms}): let E be an elliptic curve over Q given by ellinit or a rational isogeny class given by ellisomat. Return a list of isomorphism classes of elliptic curves isogenous to E as given by ellisomat and the list of the Smith invariants of the lattice associated to E in H^1(E,Q) in the lattice associated to the modular form. If ms is present, it contains the output of msfromell(Emin,0) where Emin is the list of minimal models attached to the curves in the isogeny class. Doc: If $E'$ is an elliptic curve over $\Q$, let $L_{E'}$ be the sub-$\Z$-module of $\Hom_{\Gamma_0(N)}(\Delta,\Q)$ attached to $E'$ (It is given by $x[3]$ if $[M,x] = \kbd{msfromell}(E')$.) On the other hand, if $N$ is the conductor of $E$ and $f$ is the modular form for $\Gamma_0(N)$ attached to $E$, let $L_f$ be the lattice of the $f$-component of $\Hom_{\Gamma_0(N)}(\Delta,\Q)$ given by the elements $\phi$ such that $\phi(\{0,\gamma^{-1} 0\}) \in \Z$ for all $\gamma \in \Gamma_0(N)$ (see \tet{mslattice}). Let $E'$ run through the isomorphism classes of elliptic curves isogenous to $E$ as given by \kbd{ellisomat} (and in the same order). This function returns a pair \kbd{[vE,vS]} where \kbd{vE} contains minimal models for the $E'$ and \kbd{vS} contains the list of Smith invariants for the lattices $L_{E'}$ in $L_f$. The function also accepts the output of \kbd{ellisomat}, i.e. the isogeny class. If the optional argument \kbd{ms} is present, it contains the output of \kbd{msfromell(vE, 0)}, i.e. the new modular symbol space $M$ of level $N$ and a vector of triples $[x^+,x^-, L]$ attached to each curve $E'$. In particular, the strong Weil curve amongst the curves isogenous to $E$ is the one whose Smith invariants are $[c,c]$, where $c$ is the Manin constant, conjecturally equal to $1$. \bprog ? E = ellinit("11a3"); ? [vE, vS] = ellweilcurve(E); ? [n] = [ i | i<-[1..#vS], vS[i]==[1,1] ] \\ lattice with invariant [1,1] %3 = [2] ? ellidentify(vE[n]) \\ ... corresponds to strong Weil curve %4 = [["11a1", [0, -1, 1, -10, -20], []], [1, 0, 0, 0]] ? [vE, vS] = ellweilcurve(E, &ms); \\ vE,vS are as above ? [M, vx] = ms; msdim(M) \\ ... but ms contains more information %6 = 3 ? #vx %7 = 3 ? vx[1] %8 = [[1/25, -1/10, -1/10]~, [0, 1/2, -1/2]~, [1/25,0; -3/5,1; 2/5,-1]] ? forell(E, 11,11, print(msfromell(ellinit(E[1]), 1)[2])) [1/5, -1/2, -1/2]~ [1, -5/2, -5/2]~ [1/25, -1/10, -1/10]~ @eprog\noindent The last example prints the modular symbols $x^+$ in $M^+$ attached to the curves \kbd{11a1}, \kbd{11a2} and \kbd{11a3}. pari-2.11.2/src/functions/elliptic_curves/ellformalpoint0000644000175000017500000000172413201017466022127 0ustar billbillFunction: ellformalpoint Section: elliptic_curves C-Name: ellformalpoint Prototype: GDPDn Help: ellformalpoint(E, {n = seriesprecision}, {v = 'x}): E elliptic curve, n integer; return the coordinates [x(t), y(t)] on the elliptic curve as a formal expansion in the formal parameter t = -x/y. Doc: If $E$ is an elliptic curve, return the coordinates $x(t), y(t)$ in the formal group of the elliptic curve $E$ in the formal parameter $t = -x/y$ at $\infty$: $$ x = t^{-2} -a_1 t^{-1} - a_2 - a_3 t + \dots $$ $$ y = - t^{-3} -a_1 t^{-2} - a_2t^{-1} -a_3 + \dots $$ Return $n$ terms (\tet{seriesprecision} by default) of these two power series, whose coefficients are in $\Z[a_1,a_2,a_3,a_4,a_6]$. \bprog ? E = ellinit([0,0,1,-1,0]); [x,y] = ellformalpoint(E,8,'t); ? x %2 = t^-2 - t + t^2 - t^4 + 2*t^5 + O(t^6) ? y %3 = -t^-3 + 1 - t + t^3 - 2*t^4 + O(t^5) ? E = ellinit([0,1/2]); ellformalpoint(E,7) %4 = [x^-2 - 1/2*x^4 + O(x^5), -x^-3 + 1/2*x^3 + O(x^4)] @eprog pari-2.11.2/src/functions/elliptic_curves/hyperellratpoints0000644000175000017500000000250413326135265022673 0ustar billbillFunction: hyperellratpoints Section: elliptic_curves C-Name: hyperellratpoints Prototype: GGD0,L, Help: hyperellratpoints(X,h,{flag=0}): X being a non-singular hyperelliptic curve given by an integral model, return a vector containing the affine rational points on the curve of naive height less than h. If fl=1, stop as soon as a point is found. X can be given either by a squarefree polynomial P such that X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)y=P(x) and Q^2+4P is squarefree. Doc: $X$ being a non-singular hyperelliptic curve given by an integral model, return a vector containing the affine rational points on the curve of naive height less than $h$. If $\fl=1$, stop as soon as a point is found; return either an empty vector or a vector containing a single point. $X$ is given either by a squarefree polynomial $P$ such that $X: y^2=P(x)$ or by a vector $[P,Q]$ such that $X: y^2+Q(x)\*y=P(x)$ and $Q^2+4\*P$ is squarefree. \noindent The parameter $h$ can be \item an integer $H$: find the points $[n/d,y]$ whose abscissas $x = n/d$ have naive height (= $\max(|n|, d)$) less than $H$; \item a vector $[N,D]$ with $D\leq N$: find the points $[n/d,y]$ with $|n| \leq N$, $d \leq D$. \item a vector $[N,[D_1,D_2]]$ with $D_1 1$, the output is $[d_1d_2, [d_1,d_2], [P,Q]]$ where $P$ is of order $d_1$ and $[P,Q]$ generates the curve. \misctitle{Caution} It is not guaranteed that $Q$ has order $d_2$, which in the worst case requires an expensive discrete log computation. Only that \kbd{ellweilpairing}$(E, P, Q, d_1)$ has order $d_2$. For other fields of definition and $p$ defining a finite residue field $\F_q$, return the structure of the reduction of $E$: the argument $p$ is best left omitted if $K = \Q_\ell$ (else we must have $p = \ell$) and must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) with residue field $\F_q$ otherwise. The curve is allowed to have bad reduction at $p$ and in this case we consider the (cyclic) group of non-singular points for the reduction of a minimal model at $p$. If $\fl = 0$, the equation not be minimal or even integral at $p$; of course, a minimal model will be more efficient. If $\fl = 1$, the requested generators depend on the model, which must then be minimal at $p$, otherwise an exception is thrown. Use \kbd{ellintegralmodel} and/or \kbd{ellocalred} first to reduce to this case. \bprog ? E = ellinit([0,1]); \\ y^2 = x^3 + 0.x + 1, defined over Q ? ellgroup(E, 7) %2 = [6, 2] \\ Z/6 x Z/2, non-cyclic ? E = ellinit([0,1] * Mod(1,11)); \\ defined over F_11 ? ellgroup(E) \\ no need to repeat 11 %4 = [12] ? ellgroup(E, 11) \\ ... but it also works %5 = [12] ? ellgroup(E, 13) \\ ouch, inconsistent input! *** at top-level: ellgroup(E,13) *** ^-------------- *** ellgroup: inconsistent moduli in Rg_to_Fp: 11 13 ? ellgroup(E, 7, 1) %6 = [12, [6, 2], [[Mod(2, 7), Mod(4, 7)], [Mod(4, 7), Mod(4, 7)]]] @eprog\noindent Let us now consider curves of bad reduction, in this case we return the structure of the (cyclic) group of non-singular points, satisfying $\#E_{ns}(\F_p) = p - a_p$: \bprog ? E = ellinit([0,5]); ? ellgroup(E, 5, 1) %2 = [5, [5], [[Mod(4, 5), Mod(2, 5)]]] ? ellap(E, 5) %3 = 0 \\ additive reduction at 5 ? E = ellinit([0,-1,0,35,0]); ? ellgroup(E, 5, 1) %5 = [4, [4], [[Mod(2, 5), Mod(2, 5)]]] ? ellap(E, 5) %6 = 1 \\ split multiplicative reduction at 5 ? ellgroup(E, 7, 1) %7 = [8, [8], [[Mod(3, 7), Mod(5, 7)]]] ? ellap(E, 7) %8 = -1 \\ non-split multiplicative reduction at 7 @eprog Variant: Also available is \fun{GEN}{ellgroup}{GEN E, GEN p}, corresponding to \fl = 0. pari-2.11.2/src/functions/elliptic_curves/ellpadicbsd0000644000175000017500000000645313326135265021360 0ustar billbillFunction: ellpadicbsd Section: elliptic_curves C-Name: ellpadicbsd Prototype: GGLDG Help: ellpadicbsd(E, p, n, {D = 1}): returns [r,Lp] where r is the (conjectural) analytic rank of the p-adic L-function attached to the quadratic twist E_D and Lp is (conjecturally) equal to the product of the p-adic regulator and the cardinal of the Tate-Shafarevich group. Doc: Given an elliptic curve $E$ over $\Q$, its quadratic twist $E_D$ and a prime number $p$, this function is a $p$-adic analog of the complex functions \tet{ellanalyticrank} and \tet{ellbsd}. It calls \kbd{ellpadicL} with initial accuracy $p^n$ and may increase it internally; it returns a vector $[r, L_p]$ where \item $L_p$ is a $p$-adic number (resp. a pair of $p$-adic numbers if $E$ has good supersingular reduction) defined modulo $p^N$, conjecturally equal to $R_p S$, where $R_p$ is the $p$-adic regulator as given by \tet{ellpadicregulator} (in the basis $(\omega, F \omega)$) and $S$ is the cardinal of the Tate-Shafarevich group for the quadratic twist $E_D$. \item $r$ is an upper bound for the analytic rank of the $p$-adic $L$-function attached to $E_D$: we know for sure that the $i$-th derivative of $L_p(E_D,.)$ at $\chi^0$ is $O(p^N)$ for all $i < r$ and that its $r$-th derivative is non-zero; it is expected that the true analytic rank is equal to the rank of the Mordell-Weil group $E_D(\Q)$, plus $1$ if the reduction of $E_D$ at $p$ is split multiplicative; if $r = 0$, then both the analytic rank and the Mordell-Weil rank are unconditionnally $0$. Recall that the $p$-adic BSD conjecture (Mazur, Tate, Teitelbaum, Bernardi, Perrin-Riou) predicts an explicit link between $R_p S$ and $$(1-p^{-1} F)^{-2} \cdot L_p^{(r)}(E_D, \chi^0) / r! $$ where $r$ is the analytic rank of the $p$-adic $L$-function attached to $E_D$ and $F$ is the Frobenius on $H^1_{dR}$; see \tet{ellpadicL} for definitions. \bprog ? E = ellinit("11a1"); p = 7; n = 5; \\ good ordinary ? ellpadicbsd(E, 7, 5) \\ rank 0, %2 = [0, 1 + O(7^5)] ? E = ellinit("91a1"); p = 7; n = 5; \\ non split multiplicative ? [r,Lp] = ellpadicbsd(E, p, n) %5 = [1, 2*7 + 6*7^2 + 3*7^3 + 7^4 + O(7^5)] ? R = ellpadicregulator(E, p, n, E.gen) %6 = 2*7 + 6*7^2 + 3*7^3 + 7^4 + 5*7^5 + O(7^6) ? sha = Lp/R %7 = 1 + O(7^4) ? E = ellinit("91b1"); p = 7; n = 5; \\ split multiplicative ? [r,Lp] = ellpadicbsd(E, p, n) %9 = [2, 2*7 + 7^2 + 5*7^3 + O(7^4)] ? ellpadicregulator(E, p, n, E.gen) %10 = 2*7 + 7^2 + 5*7^3 + 6*7^4 + 2*7^5 + O(7^6) ? [rC, LC] = ellanalyticrank(E); ? [r, rC] %12 = [2, 1] \\ r = rC+1 because of split multiplicative reduction ? E = ellinit("53a1"); p = 5; n = 5; \\ supersingular ? [r, Lp] = ellpadicbsd(E, p, n); ? r %15 = 1 ? Lp %16 = [3*5 + 2*5^2 + 2*5^5 + O(5^6), \ 5 + 3*5^2 + 4*5^3 + 2*5^4 + 5^5 + O(5^6)] ? R = ellpadicregulator(E, p, n, E.gen) %17 = [3*5 + 2*5^2 + 2*5^5 + O(5^6), 5 + 3*5^2 + 4*5^3 + 2*5^4 + O(5^5)] \\ expect Lp = R*#Sha, hence (conjecturally) #Sha = 1 ? E = ellinit("84a1"); p = 11; n = 6; D = -443; ? [r,Lp] = ellpadicbsd(E, 11, 6, D) \\ Mordell-Weil rank 0, no regulator %19 = [0, 3 + 2*11 + O(11^6)] ? lift(Lp) \\ expected cardinal for Sha is 5^2 %20 = 25 ? ellpadicbsd(E, 3, 12, D) \\ at 3 %21 = [1, 1 + 2*3 + 2*3^2 + O(3^8)] ? ellpadicbsd(E, 7, 8, D) \\ and at 7 %22 = [0, 4 + 3*7 + O(7^8)] @eprog pari-2.11.2/src/functions/elliptic_curves/ellbil0000644000175000017500000000031713201017466020340 0ustar billbillFunction: ellbil Section: elliptic_curves C-Name: bilhell Prototype: GGGp Obsolete: 2014-05-21 Help: ellbil(E,z1,z2): deprecated alias for ellheight(E,P,Q). Doc: deprecated alias for \kbd{ellheight(E,P,Q)}. pari-2.11.2/src/functions/elliptic_curves/ellap0000644000175000017500000000754213326135265020207 0ustar billbillFunction: ellap Section: elliptic_curves C-Name: ellap Prototype: GDG Help: ellap(E,{p}): given an elliptic curve E defined over a finite field Fq, return the trace of Frobenius a_p = q+1-#E(Fq); for other fields of definition K, p must define a finite residue field, (p prime for K = Qp or Q; p a maximal ideal for K a number field), return the order of the (non-singular) reduction of E. Doc: Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached to an elliptic curve $E/K$. If the field $K = \F_q$ is finite, return the trace of Frobenius $t$, defined by the equation $\#E(\F_q) = q+1 - t$. For other fields of definition and $p$ defining a finite residue field $\F_q$, return the trace of Frobenius for the reduction of $E$: the argument $p$ is best left omitted if $K = \Q_\ell$ (else we must have $p = \ell$) and must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) with residue field $\F_q$ otherwise. The equation need not be minimal or even integral at $p$; of course, a minimal model will be more efficient. For a number field $K$, the trace of Frobenius is the $a_p$ coefficient in the Euler product defining the curve $L$-series, whence the function name: $$L(E/K,s) = \prod_{\text{bad}\ p} (1-a_p (Np)^{-s})^{-1} \prod_{\text{good}\ p} (1-a_p (Np)^{-s} + (Np)^{1-2s})^{-1}. $$ When the characteristic of the finite field is large, the availability of the \kbd{seadata} package will speed up the computation. \bprog ? E = ellinit([0,1]); \\ y^2 = x^3 + 0.x + 1, defined over Q ? ellap(E, 7) \\ 7 necessary here %2 = -4 \\ #E(F_7) = 7+1-(-4) = 12 ? ellcard(E, 7) %3 = 12 \\ OK ? E = ellinit([0,1], 11); \\ defined over F_11 ? ellap(E) \\ no need to repeat 11 %4 = 0 ? ellap(E, 11) \\ ... but it also works %5 = 0 ? ellgroup(E, 13) \\ ouch, inconsistent input! *** at top-level: ellap(E,13) *** ^----------- *** ellap: inconsistent moduli in Rg_to_Fp: 11 13 ? a = ffgen(ffinit(11,3), 'a); \\ defines F_q := F_{11^3} ? E = ellinit([a+1,a]); \\ y^2 = x^3 + (a+1)x + a, defined over F_q ? ellap(E) %8 = -3 @eprog If the curve is defined over a more general number field than $\Q$, the maximal ideal $p$ must be explicitly given in \kbd{idealprimedec} format. There is no assumption of local minimality at $p$. \bprog ? K = nfinit(a^2+1); E = ellinit([1+a,0,1,0,0], K); ? fa = idealfactor(K, E.disc) %2 = [ [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] 1] [[13, [5, 1]~, 1, 1, [-5, -1; 1, -5]] 2] ? ellap(E, fa[1,1]) %3 = -1 \\ non-split multiplicative reduction ? ellap(E, fa[2,1]) %4 = 1 \\ split multiplicative reduction ? P17 = idealprimedec(K,17)[1]; ? ellap(E, P17) %6 = 6 \\ good reduction ? E2 = ellchangecurve(E, [17,0,0,0]); ? ellap(E2, P17) %8 = 6 \\ same, starting from a non-miminal model ? P3 = idealprimedec(K,3)[1]; ? ellap(E, P3) \\ OK: E is minimal at P3 %10 = -2 ? E3 = ellchangecurve(E, [3,0,0,0]); ? ellap(E3, P3) \\ not integral at P3 *** at top-level: ellap(E3,P3) *** ^------------ *** ellap: impossible inverse in Rg_to_ff: Mod(0, 3). @eprog \misctitle{Algorithms used} If $E/\F_q$ has CM by a principal imaginary quadratic order we use a fast explicit formula (involving essentially Kronecker symbols and Cornacchia's algorithm), in $O(\log q)^2$ bit operations. Otherwise, we use Shanks-Mestre's baby-step/giant-step method, which runs in time $\tilde{O}(q^{1/4})$ using $\tilde{O}(q^{1/4})$ storage, hence becomes unreasonable when $q$ has about 30~digits. Above this range, the \tet{SEA} algorithm becomes available, heuristically in $\tilde{O}(\log q)^4$, and primes of the order of 200~digits become feasible. In small characteristic we use Mestre's (p=2), Kohel's (p=3,5,7,13), Satoh-Harley (all in $\tilde{O}(p^{2}\*n^2)$) or Kedlaya's (in $\tilde{O}(p\*n^3)$) algorithms. pari-2.11.2/src/functions/elliptic_curves/ellpadics20000644000175000017500000000252513326135265021130 0ustar billbillFunction: ellpadics2 Section: elliptic_curves C-Name: ellpadics2 Prototype: GGL Help: ellpadics2(E,p,n): returns s2 to absolute p-adic precision p^n. Doc: If $p>2$ is a prime and $E/\Q$ is an elliptic curve with ordinary good reduction at $p$, returns the slope of the unit eigenvector of \kbd{ellpadicfrobenius(E,p,n)}, i.e., the action of Frobenius $\varphi$ on the crystalline module $D_p(E)= \Q_p \otimes H^1_{dR}(E/\Q)$ in the basis of the given model $(\omega, \eta=x\*\omega)$, where $\omega$ is the invariant differential $dx/(2\*y+a_1\*x+a_3)$. In other words, $\eta + s_2\omega$ is an eigenvector for the unit eigenvalue of $\varphi$. \bprog ? e=ellinit([17,42]); ? ellpadics2(e,13,4) %2 = 10 + 2*13 + 6*13^3 + O(13^4) @eprog This slope is the unique $c \in 3^{-1}\Z_p$ such that the odd solution $\sigma(t) = t + O(t^2)$ of $$ - d(\dfrac{1}{\sigma} \dfrac{d \sigma}{\omega}) = (x(t) + c) \omega$$ is in $t\Z_p[[t]]$. It is equal to $b_2/12 - E_2/12$ where $E_2$ is the value of the Katz $p$-adic Eisenstein series of weight 2 on $(E,\omega)$. This is used to construct a canonical $p$-adic height when $E$ has good ordinary reduction at $p$ as follows \bprog s2 = ellpadics2(E,p,n); h(E,p,n, P, s2) = ellpadicheight(E, [p,[1,-s2]],n, P); @eprog\noindent Since $s_2$ does not depend on the point $P$, we compute it only once. pari-2.11.2/src/functions/elliptic_curves/ellsea0000644000175000017500000000616513326135265020357 0ustar billbillFunction: ellsea Class: basic Section: elliptic_curves C-Name: ellsea Prototype: GD0,L, Help: ellsea(E,{tors=0}): computes the order of the group E(Fq) for the elliptic curve E, defined over a finite field, using SEA algorithm, with early abort for curves (or their quadratic twist) with non-prime order. Doc: Let $E$ be an \var{ell} structure as output by \kbd{ellinit}, defined over a finite field $\F_q$. This low-level function computes the order of the group $E(\F_q)$ using the SEA algorithm; compared to the high-level function \kbd{ellcard}, which includes SEA among its choice of algorithms, the \kbd{tors} argument allows to speed up a search for curves having almost prime order and whose quadratic twist may also have almost prime order. When \kbd{tors} is set to a non-zero value, the function returns $0$ as soon as it detects that the order has a small prime factor not dividing \kbd{tors}; SEA considers modular polynomials of increasing prime degree $\ell$ and we return $0$ as soon as we hit an $\ell$ (coprime to \kbd{tors}) dividing $\#E(\F_q)$: \bprog ? ellsea(ellinit([1,1], 2^56+3477), 1) %1 = 72057594135613381 ? forprime(p=2^128,oo, q = ellcard(ellinit([1,1],p)); if(isprime(q),break)) time = 6,571 ms. ? forprime(p=2^128,oo, q = ellsea(ellinit([1,1],p),1);if(isprime(q),break)) time = 522 ms. @eprog\noindent In particular, set \kbd{tors} to $1$ if you want a curve with prime order, to $2$ if you want to allow a cofactor which is a power of two (e.g. for Edwards's curves), etc. The early exit on bad curves yields a massive speedup compared to running the cardinal algorithm to completion. When \kbd{tors} is negative, similar checks are performed for the quadratic twist of the curve. The following function returns a curve of prime order over $\F_p$. \bprog cryptocurve(p) = { while(1, my(E, N, j = Mod(random(p), p)); E = ellinit(ellfromj(j)); N = ellsea(E, 1); if (!N, continue); if (isprime(N), return(E)); \\ try the quadratic twist for free if (isprime(2*p+2 - N), return(ellinit(elltwist(E)))); ); } ? p = randomprime([2^255, 2^256]); ? E = cryptocurve(p); \\ insist on prime order %2 = 47,447ms @eprog\noindent The same example without early abort (using \kbd{ellcard(E)} instead of \kbd{ellsea(E, 1)}) runs for about 5 minutes before finding a suitable curve. The availability of the \kbd{seadata} package will speed up the computation, and is strongly recommended. The generic function \kbd{ellcard} should be preferred when you only want to compute the cardinal of a given curve without caring about it having almost prime order: \item If the characteristic is too small ($p \leq 7$) or the field cardinality is tiny ($q \leq 523$) the generic algorithm \kbd{ellcard} is used instead and the \kbd{tors} argument is ignored. (The reason for this is that SEA is not implemented for $p \leq 7$ and that if $q \leq 523$ it is likely to run into an infinite loop.) \item If the field cardinality is smaller than about $2^{50}$, the generic algorithm will be faster. \item Contrary to \kbd{ellcard}, \kbd{ellsea} does not store the computed cardinality in $E$. pari-2.11.2/src/functions/elliptic_curves/ellpadicL0000644000175000017500000001071213326135265020774 0ustar billbillFunction: ellpadicL Section: elliptic_curves C-Name: ellpadicL Prototype: GGLDGD0,L,DG Help: ellpadicL(E, p, n, {s = 0}, {r = 0}, {D = 1}): returns the value on a character of Z_p^* represented by an integer s or a vector [s1,s2] of the derivative of order r of the p-adic L-function of the elliptic curve E (twisted by D, if present). Doc: Returns the value (or $r$-th derivative) on a character $\chi^s$ of $\Z_p^*$ of the $p$-adic $L$-function of the elliptic curve $E/\Q$, twisted by $D$, given modulo $p^n$. \misctitle{Characters} The set of continuous characters of $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$ is identified to $\Z_p^*$ via the cyclotomic character $\chi$ with values in $\overline{\Q_p}^*$. Denote by $\tau:\Z_p^*\to\Z_p^*$ the Teichm\"uller character, with values in the $(p-1)$-th roots of $1$ for $p\neq 2$, and $\{-1,1\}$ for $p = 2$; finally, let $\langle\chi\rangle =\chi \tau^{-1}$, with values in $1 + 2p\Z_p$. In GP, the continuous character of $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$ given by $\langle\chi\rangle^{s_1} \tau^{s_2}$ is represented by the pair of integers $s=(s_1,s_2)$, with $s_1 \in \Z_p$ and $s_2 \bmod p-1$ for $p > 2$, (resp. mod $2$ for $p = 2$); $s$ may be also an integer, representing $(s,s)$ or $\chi^s$. \misctitle{The $p$-adic $L$ function} The $p$-adic $L$ function $L_p$ is defined on the set of continuous characters of $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$, as $\int_{\Z_p^*} \chi^s d \mu$ for a certain $p$-adic distribution $\mu$ on $\Z_p^*$. The derivative is given by $$L_p^{(r)}(E, \chi^s) = \int_{\Z_p^*} \log_p^r(a) \chi^s(a) d\mu(a).$$ More precisely: \item When $E$ has good supersingular reduction, $L_p$ takes its values in $D := H^1_{dR}(E/\Q)\otimes_\Q \Q_p$ and satisfies $$(1-p^{-1} F)^{-2} L_p(E, \chi^0)= (L(E,1) / \Omega) \cdot \omega$$ where $F$ is the Frobenius, $L(E,1)$ is the value of the complex $L$ function at $1$, $\omega$ is the N\'eron differential and $\Omega$ the attached period on $E(\R)$. Here, $\chi^0$ represents the trivial character. The function returns the components of $L_p^{(r)}(E,\chi^s)$ in the basis $(\omega, F \omega)$. \item When $E$ has ordinary good reduction, this method only defines the projection of $L_p(E,\chi^s)$ on the $\alpha$-eigenspace, where $\alpha$ is the unit eigenvalue for $F$. This is what the function returns. We have $$(1- \alpha^{-1})^{-2} L_{p,\alpha}(E,\chi^0)= L(E,1) / \Omega.$$ Two supersingular examples: \bprog ? cxL(e) = bestappr( ellL1(e) / e.omega[1] ); ? e = ellinit("17a1"); p=3; \\ supersingular, a3 = 0 ? L = ellpadicL(e,p,4); ? F = [0,-p;1,ellap(e,p)]; \\ Frobenius matrix in the basis (omega,F(omega)) ? (1-p^(-1)*F)^-2 * L / cxL(e) %5 = [1 + O(3^5), O(3^5)]~ \\ [1,0]~ ? e = ellinit("116a1"); p=3; \\ supersingular, a3 != 0~ ? L = ellpadicL(e,p,4); ? F = [0,-p; 1,ellap(e,p)]; ? (1-p^(-1)*F)^-2*L~ / cxL(e) %9 = [1 + O(3^4), O(3^5)]~ @eprog Good ordinary reduction: \bprog ? e = ellinit("17a1"); p=5; ap = ellap(e,p) %1 = -2 \\ ordinary ? L = ellpadicL(e,p,4) %2 = 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^4) ? al = padicappr(x^2 - ap*x + p, ap + O(p^7))[1]; ? (1-al^(-1))^(-2) * L / cxL(e) %4 = 1 + O(5^4) @eprog Twist and Teichm\"uller: \bprog ? e = ellinit("17a1"); p=5; \\ ordinary \\ 2nd derivative at tau^1, twist by -7 ? ellpadicL(e, p, 4, [0,1], 2, -7) %2 = 2*5^2 + 5^3 + O(5^4) @eprog We give an example of non split multiplicative reduction (see \tet{ellpadicbsd} for more examples). \bprog ? e=ellinit("15a1"); p=3; n=5; ? L = ellpadicL(e,p,n) %2 = 2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5) ? (1 - ellap(e,p))^(-1) * L / cxL(e) %3 = 1 + O(3^5) @eprog This function is a special case of \tet{mspadicL} and it also appears as the first term of \tet{mspadicseries}: \bprog ? e = ellinit("17a1"); p=5; ? L = ellpadicL(e,p,4) %2 = 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^4) ? [M,phi] = msfromell(e, 1); ? Mp = mspadicinit(M, p, 4); ? mu = mspadicmoments(Mp, phi); ? mspadicL(mu) %6 = 4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + O(5^6) ? mspadicseries(mu) %7 = (4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + O(5^6)) + (3 + 3*5 + 5^2 + 5^3 + O(5^4))*x + (2 + 3*5 + 5^2 + O(5^3))*x^2 + (3 + 4*5 + 4*5^2 + O(5^3))*x^3 + (3 + 2*5 + O(5^2))*x^4 + O(x^5) @eprog\noindent These are more cumbersome than \kbd{ellpadicL} but allow to compute at different characters, or successive derivatives, or to twist by a quadratic character essentially for the cost of a single call to \kbd{ellpadicL} due to precomputations. pari-2.11.2/src/functions/algebras/0000755000175000017500000000000013461316051015535 5ustar billbillpari-2.11.2/src/functions/algebras/alglatindex0000644000175000017500000000105313326135265017761 0ustar billbillFunction: alglatindex Section: algebras C-Name: alglatindex Prototype: GGG Help: alglatindex(al,lat1,lat2): the generalized index (lat2:lat1). Doc: Given an algebra~\var{al} and two lattices~\var{lat1} and~\var{lat2} in~\var{al}, computes the generalized index of~\var{lat1} relative to~\var{lat2}, i.e.~$|lat2/lat1\cap lat2|/|lat1/lat1\cap lat2|$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? alglatindex(al,lat1,lat2) %4 = 1 ? lat1==lat2 %5 = 0 @eprog pari-2.11.2/src/functions/algebras/algdisc0000644000175000017500000000133013326135265017071 0ustar billbillFunction: algdisc Section: algebras C-Name: algdisc Prototype: G Help: algdisc(al): discriminant of the stored order of the algebra al. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, computes the discriminant of the order ${\cal O}_0$ stored in \var{al}, that is the determinant of the trace form $\rm{Tr} : {\cal O}_0\times {\cal O}_0 \to \Z$. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-3,1-y]); ? [PR,h] = alghassef(A) %3 = [[[2, [2, 0]~, 1, 2, 1], [3, [3, 0]~, 1, 2, 1]], Vecsmall([0, 1])] ? n = algdegree(A); ? D = algdim(A,1); ? h = vector(#h, i, n - gcd(n,h[i])); ? n^D * nf.disc^(n^2) * idealnorm(nf, idealfactorback(nf,PR,h))^n %4 = 12960000 ? algdisc(A) %5 = 12960000 @eprog pari-2.11.2/src/functions/algebras/algcenter0000644000175000017500000000165613201017466017434 0ustar billbillFunction: algcenter Section: algebras C-Name: algcenter Prototype: mG Help: algcenter(al): center of the algebra al. Doc: If \var{al} is a table algebra output by \tet{algtableinit}, returns a basis of the center of the algebra~\var{al} over its prime field ($\Q$ or $\F_p$). If \var{al} is a central simple algebra output by \tet{alginit}, returns the center of~\var{al}, which is stored in \var{al}. A simple example: the $2\times 2$ upper triangular matrices over $\Q$, generated by $I_2$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, such that $a^2 = 0$, $ab = a$, $ba = 0$, $b^2 = b$: the diagonal matrices form the center. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algcenter(A) \\ = (I_2) %3 = [1] [0] [0] @eprog An example in the central simple case: \bprog ? nf = nfinit(y^3-y+1); ? A = alginit(nf, [-1,-1]); ? algcenter(A).pol %3 = y^3 - y + 1 @eprog pari-2.11.2/src/functions/algebras/algissemisimple0000644000175000017500000000130113201017466020642 0ustar billbillFunction: algissemisimple Section: algebras C-Name: algissemisimple Prototype: iG Help: algissemisimple(al): test whether the algebra al is semisimple. Doc: \var{al} being a table algebra output by \tet{algtableinit} or a central simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is semisimple. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algissemisimple(A) %3 = 0 ? m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; \\ quaternion algebra (-1,-1) ? m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; ? m_k=[0,0,0,-1;0,0,-1,0;0,1,0,0;1,0,0,0]; ? mt = [matid(4), m_i, m_j, m_k]; ? A = algtableinit(mt); ? algissemisimple(A) %9 = 1 @eprog pari-2.11.2/src/functions/algebras/alglatadd0000644000175000017500000000123613326135265017405 0ustar billbillFunction: alglatadd Section: algebras C-Name: alglatadd Prototype: GGGD& Help: alglatadd(al,lat1,lat2,{&ptinter}): the sum of the lattices lat1 and lat2. If ptinter is present, set it to the intersection of the lattices. Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the sum~$lat1 + lat2$. If \var{ptinter} is present, set it to the intersection~$lat1 \cap lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? latsum = alglatadd(al,lat1,lat2,&latinter); ? matdet(latsum[1]) %5 = 4 ? matdet(latinter[1]) %6 = 64 @eprog pari-2.11.2/src/functions/algebras/algtrace0000644000175000017500000000160013326135265017245 0ustar billbillFunction: algtrace Section: algebras C-Name: algtrace Prototype: GGD0,L, Help: algtrace(al,x,{abs=0}): (reduced) trace of x. Doc: Given an element \var{x} in \var{al}, computes its trace. If \var{al} is a table algebra output by \tet{algtableinit} or if $abs=1$, returns the absolute trace of \var{x}, which is an element of $\F_p$ or~$\Q$; if \var{al} is the output of \tet{alginit} and $abs=0$ (default), returns the reduced trace of \var{x}, which is an element of the center of \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algtrace(A,[5,0,0,1]~) %2 = 11 ? algtrace(A,[5,0,0,1]~,1) %3 = 22 ? nf = nfinit(y^2-5); ? A = alginit(nf,[-1,y]); ? a = [1+x+y,2*y]~*Mod(1,y^2-5)*Mod(1,x^2+1); ? t = algtrace(A,a) %7 = Mod(2*y + 2, y^2 - 5) ? algtrace(A,a,1) %8 = 8 ? algdegree(A)*nfelttrace(nf,t) %9 = 8 @eprog Also accepts a square matrix with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algtype0000644000175000017500000000222613201017466017127 0ustar billbillFunction: algtype Section: algebras C-Name: algtype Prototype: lG Help: algtype(al): type of the algebra al. Doc: Given an algebra \var{al} output by \tet{alginit} or by \tet{algtableinit}, returns an integer indicating the type of algebra: \item $0$: not a valid algebra. \item $1$: table algebra output by \tet{algtableinit}. \item $2$: central simple algebra output by \tet{alginit} and represented by a multiplication table over its center. \item $3$: central simple algebra output by \tet{alginit} and represented by a cyclic algebra. \bprog ? algtype([]) %1 = 0 ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? algtype(A) %4 = 1 ? nf = nfinit(y^3-5); ? a = y; b = y^2; ? {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} ? {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} ? {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} ? mt = [matid(4), m_i, m_j, m_k]; ? A = alginit(nf,mt,'x); ? algtype(A) %12 = 2 ? A = alginit(nfinit(y), [-1,-1]); ? algtype(A) %14 = 3 @eprog pari-2.11.2/src/functions/algebras/algissplit0000644000175000017500000000170413326135265017643 0ustar billbillFunction: algissplit Section: algebras C-Name: algissplit Prototype: iGDG Help: algissplit(al,{pl}): tests whether the central simple algebra al is split, i.e. isomorphic to a matrix ring over its center. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case tests whether al is locally split at the place pl instead. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, tests whether~\var{al} is split, i.e. isomorphic to a matrix algebra over its center. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case tests whether \var{al} is locally split at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algissplit(A, 1) %3 = 0 ? algissplit(A, 2) %4 = 1 ? algissplit(A, idealprimedec(nf,2)[1]) %5 = 0 ? algissplit(A, idealprimedec(nf,5)[1]) %6 = 1 ? algissplit(A) %7 = 0 @eprog pari-2.11.2/src/functions/algebras/algisdivision0000644000175000017500000000165113326135265020335 0ustar billbillFunction: algisdivision Section: algebras C-Name: algisdivision Prototype: iGDG Help: algisdivision(al,{pl}): tests whether the central simple algebra al is a division algebra. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case tests whether al is locally a division algebra at the place pl instead. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, tests whether \var{al} is a division algebra. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case tests whether \var{al} is locally a division algebra at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algisdivision(A, 1) %3 = 1 ? algisdivision(A, 2) %4 = 0 ? algisdivision(A, idealprimedec(nf,2)[1]) %5 = 1 ? algisdivision(A, idealprimedec(nf,5)[1]) %6 = 0 ? algisdivision(A) %7 = 1 @eprog pari-2.11.2/src/functions/algebras/algdivl0000644000175000017500000000075713201017466017113 0ustar billbillFunction: algdivl Section: algebras C-Name: algdivl Prototype: GGG Help: algdivl(al,x,y): element x\y in al. Doc: Given two elements $x$ and $y$ in \var{al}, computes their left quotient $x\backslash y$ in the algebra \var{al}: an element $z$ such that $xz=y$ (such an element is not unique when $x$ is a zerodivisor). If~$x$ is invertible, this is the same as $x^{-1}y$. Assumes that $y$ is left divisible by $x$ (i.e. that $z$ exists). Also accepts matrices with coefficients in~\var{al}. pari-2.11.2/src/functions/algebras/algisramified0000644000175000017500000000176013326135265020272 0ustar billbillFunction: algisramified Section: algebras C-Name: algisramified Prototype: iGDG Help: algisramified(al,{pl}): tests whether the central simple algebra al is ramified, i.e. not isomorphic to a matrix ring over its center. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case tests whether al is locally ramified at the place pl instead. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, tests whether \var{al} is ramified, i.e. not isomorphic to a matrix algebra over its center. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case tests whether \var{al} is locally ramified at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algisramified(A, 1) %3 = 1 ? algisramified(A, 2) %4 = 0 ? algisramified(A, idealprimedec(nf,2)[1]) %5 = 1 ? algisramified(A, idealprimedec(nf,5)[1]) %6 = 0 ? algisramified(A) %7 = 1 @eprog pari-2.11.2/src/functions/algebras/alghassei0000644000175000017500000000103713201017466017421 0ustar billbillFunction: alghassei Section: algebras C-Name: alghassei Prototype: mG Help: alghassei(al): the hasse invariant of the central simple algebra al at infinite places. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns a \typ{VECSMALL} $h_i$ of $r_1$ integers modulo the degree $d$ of \var{al}, where $r_1$ is the number of real places of the center: the local Hasse invariants of \var{al} at infinite places. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? alghassei(A) %3 = Vecsmall([1, 0]) @eprog pari-2.11.2/src/functions/algebras/algisdivl0000644000175000017500000000115613201017466017441 0ustar billbillFunction: algisdivl Section: algebras C-Name: algisdivl Prototype: iGGGD& Help: algisdivl(al,x,y,{&z}): tests whether y is left divisible by x and sets z to the left quotient x\y. Doc: Given two elements $x$ and $y$ in \var{al}, tests whether $y$ is left divisible by $x$, that is whether there exists~$z$ in \var{al} such that~$xz=y$, and sets $z$ to this element if it exists. \bprog ? A = alginit(nfinit(y), [-1,1]); ? algisdivl(A,[x+2,-x-2]~,[x,1]~) %2 = 0 ? algisdivl(A,[x+2,-x-2]~,[-x,x]~,&z) %3 = 1 ? z %4 = [Mod(-2/5*x - 1/5, x^2 + 1), 0]~ @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algsqr0000644000175000017500000000054113201017466016751 0ustar billbillFunction: algsqr Section: algebras C-Name: algsqr Prototype: GG Help: algsqr(al,x): element x^2 in al. Doc: Given an element $x$ in \var{al}, computes its square $x^2$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algsqr(A,[1,0,2,0]~) %2 = [-3, 0, 4, 0]~ @eprog Also accepts a square matrix with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/alginv0000644000175000017500000000060113201017466016735 0ustar billbillFunction: alginv Section: algebras C-Name: alginv Prototype: GG Help: alginv(al,x): element 1/x in al. Doc: Given an element $x$ in \var{al}, computes its inverse $x^{-1}$ in the algebra \var{al}. Assumes that $x$ is invertible. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? alginv(A,[1,1,0,0]~) %2 = [1/2, 1/2, 0, 0]~ @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algrandom0000644000175000017500000000041313201017466017422 0ustar billbillFunction: algrandom Section: algebras C-Name: algrandom Prototype: GG Help: algrandom(al,b): random element in al with coefficients in [-b,b]. Doc: Given an algebra \var{al} and an integer \var{b}, returns a random element in \var{al} with coefficients in~$[-b,b]$. pari-2.11.2/src/functions/algebras/algtomatrix0000644000175000017500000000232013326135265020016 0ustar billbillFunction: algtomatrix Section: algebras C-Name: algtomatrix Prototype: GGD0,L, Help: algtomatrix(al,x,{abs=1}): left multiplication table of x (table algebra or abs=1) or image of x under a splitting of al (CSA and abs=0). Doc: Given an element \var{x} in \var{al}, returns the image of \var{x} under a homomorphism to a matrix algebra. If \var{al} is a table algebra output by \kbd{algtableinit} or if~$abs=1$, returns the left multiplication table on the integral basis; if \var{al} is a central simple algebra and~$abs=0$, returns~$\phi(x)$ where~$\phi : A\otimes_K L \to M_d(L)$ (where $d$ is the degree of the algebra and $L$ is an extension of $L$ with~$[L:K]=d$) is an isomorphism stored in~\var{al}. Also accepts a square matrix with coefficients in~\var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algtomatrix(A,[0,0,0,2]~) %2 = [Mod(x + 1, x^2 + 1) Mod(Mod(1, y)*x + Mod(-1, y), x^2 + 1)] [Mod(x + 1, x^2 + 1) Mod(-x + 1, x^2 + 1)] ? algtomatrix(A,[0,1,0,0]~,1) %2 = [0 -1 1 0] [1 0 1 1] [0 0 1 1] [0 0 -2 -1] ? algtomatrix(A,[0,x]~,1) %3 = [-1 0 0 -1] [-1 0 1 0] [-1 -1 0 -1] [ 2 0 0 1] @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algnorm0000644000175000017500000000157713326135265017137 0ustar billbillFunction: algnorm Section: algebras C-Name: algnorm Prototype: GGD0,L, Help: algnorm(al,x,{abs=0}): (reduced) norm of x. Doc: Given an element \var{x} in \var{al}, computes its norm. If \var{al} is a table algebra output by \tet{algtableinit} or if $abs=1$, returns the absolute norm of \var{x}, which is an element of $\F_p$ of~$\Q$; if \var{al} is a central simple algebra output by \tet{alginit} and $abs=0$ (default), returns the reduced norm of \var{x}, which is an element of the center of \var{al}. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,19); ? algnorm(A,[0,-2,3]~) %3 = 18 ? nf = nfinit(y^2-5); ? B = alginit(nf,[-1,y]); ? b = [x,1]~; ? n = algnorm(B,b) %7 = Mod(-y + 1, y^2 - 5) ? algnorm(B,b,1) %8 = 16 ? nfeltnorm(nf,n)^algdegree(B) %9 = 16 @eprog Also accepts a square matrix with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algrelmultable0000644000175000017500000000150013201017466020450 0ustar billbillFunction: algrelmultable Section: algebras C-Name: algrelmultable Prototype: mG Help: algrelmultable(al): multiplication table of the central simple algebra al over its center. Doc: Given a central simple algebra \var{al} output by \tet{alginit} defined by a multiplication table over its center (a number field), returns this multiplication table. \bprog ? nf = nfinit(y^3-5); a = y; b = y^2; ? {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} ? {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} ? {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} ? mt = [matid(4), m_i, m_j, m_k]; ? A = alginit(nf,mt,'x); ? M = algrelmultable(A); ? M[2] == m_i %8 = 1 ? M[3] == m_j %9 = 1 ? M[4] == m_k %10 = 1 @eprog pari-2.11.2/src/functions/algebras/HEADER0000644000175000017500000001456313326135265016427 0ustar billbillFunction: _header_algebras Class: header Section: algebras Doc: \section{Associative and central simple algebras} This section collects functions related to associative algebras and central simple algebras (CSA) over number fields. \subsec{Basic definitions} %GPHELPskip Let $A$ be a finite-dimensional unital associative algebra over a field $K$. The algebra $A$ is \emph{central} if its center is $K$ and it is \emph{simple} if it has no nontrivial two-sided ideals. We provide functions to handle associative algebras of finite dimension over~$\Q$ or~$\F_p$. We represent them by the left multiplication table on a basis over the prime subfield; the function \kbd{algtableinit} creates the object representing an associative algebra. We also provide functions to handle central simple algebras over a number field $K$. We represent them either by the left multiplication table on a basis over the center $K$ or by a cyclic algebra (see below); the function~\kbd{alginit} creates the object representing a central simple algebra. The set of elements of an algebra~$A$ that annihilate every simple left $A$-module is a two-sided ideal, called the \emph{Jacobson radical} of~$A$. If the Jacobson radical is trivial, the algebra is \emph{semisimple}: it is isomorphic to a direct product of simple algebras. The dimension of a CSA over its center $K$ is always a square $d^2$ and the integer $d$ is called the \emph{degree} of the algebra over~$K$. A CSA over a field~$K$ is always isomorphic to~$M_k(D)$ for some integer~$k$ and some central division algebra~$D$ of degree~$e$: the integer~$e$ is the \emph{index} of the algebra. Let $L/K$ be a cyclic extension of degree $d$, let $\sigma$ be a generator of $\text{Gal}(L/K)$ and let $b\in K^*$. Then the \emph{cyclic algebra} $(L/K,\sigma,b)$ is the algebra $\bigoplus_{i=0}^{d-1}x^iL$ with $x^d=b$ and $\ell x=x\sigma(\ell)$ for all~$\ell\in L$. The algebra $(L/K,\sigma,b)$ is a central simple $K$-algebra of degree~$d$, and it is an $L$-vector space. Left multiplication is $L$-linear and induces a $K$-algebra isomorphism $(L/K,\sigma,b)\otimes_K L\to M_d(L)$. Let $K$ be a nonarchimedean local field with uniformizer $\pi$, and let $L/K$ be the unique unramified extension of degree $d$. Then every central simple algebra $A$ of degree $d$ over $K$ is isomorphic to $(L/K, \Frob, \pi^h)$ for some integer $h$. The element $h/d\in \Q/\Z$ is called the \emph{Hasse invariant} of $A$. \subsec{Orders} %GPHELPskip Let~$A$ be an algebra of finite dimension over~$\Q$. An \emph{order} in~$A$ is a finitely generated $\Z$-submodule~${\cal O}$ such that~$\Q{\cal O} = A$, that is also a subring with unit. By default the data computed by~\kbd{alginit} contains a~$\Z$-basis of a maximal order~${\cal O}_0$. We define natural orders in central simple algebras defined by a cyclic algebra or by a multiplication table over the center. Let~$A = (L/K,\sigma,b) = \bigoplus_{i=0}^{d-1}x^iL$ be a cyclic algebra over a number field~$K$ of degree~$n$ with ring of integers~$\Z_K$. Let~$\Z_L$ be the ring of integers of~$L$, and assume that~$b$ is integral. Then the submodule~${\cal O} = \bigoplus_{i=0}^{d-1}x^i\Z_L$ is an order in~$A$, called the \emph{natural order}. Let~$\omega_0,\dots,\omega_{nd-1}$ be a~$\Z$-basis of~$\Z_L$. The \emph{natural basis} of~${\cal O}$ is~$b_0,\dots,b_{nd^2-1}$ where~$b_i = x^{i/(nd)}\omega_{(i \mod nd)}$. Now let~$A$ be a central simple algebra of degree~$d$ over a number field~$K$ of degree~$n$ with ring of integers~$\Z_K$. Let~$e_0,\dots,e_{d^2-1}$ be a basis of~$A$ over~$K$ and assume that the left multiplication table of~$A$ on~$(e_i)$ is integral. Then the submodule~${\cal O} = \bigoplus_{i=0}^{d^2-1}\Z_K e_i$ is an order in~$A$, called the \emph{natural order}. Let~$\omega_0,\dots,\omega_{n-1}$ be a~$\Z$-basis of~$\Z_K$. The \emph{natural basis} of~${\cal O}$ is~$b_0,\dots,b_{nd^2-1}$ where~$b_i = \omega_{(i \mod n)}e_{i/n}$. \subsec{Lattices} %GPHELPskip We also provide functions to handle full lattices in algebras over~$\Q$. A full lattice~$J\subset A$ is represented by a $2$-component \typ{VEC}~$[I,t]$ representing~$J = tI$, where \item $I$ is an integral nonsingular upper-triangular matrix representing a sublattice of~${\cal O}_0$ expressed on the integral basis, and \item $t\in\Q_{>0}$ is a \typ{INT} or \typ{FRAC}. For the sake of efficiency you should use matrices~$I$ that are primitive and in Hermite Normal Form; this makes the representation unique. No GP function uses this property, but all GP functions return lattices in this form. The prefix for lattice functions is \kbd{alglat}. \subsec{GP conventions} %GPHELPskip As with number fields, we represent elements of central simple algebras in two ways, called the \emph{algebraic representation} and the \emph{basis representation}, and you can convert betweeen the two with the functions \kbd{algalgtobasis} and \kbd{algbasistoalg}. In every central simple algebra object, we store a~$\Z$-basis of an order~${\cal O}_0$, and the basis representation is simply a \typ{COL} with coefficients in~$\Q$ expressing the element in that basis. If no maximal order was computed by~\kbd{alginit}, then~${\cal O}_0$ is the natural order. If a maximal order was computed, then~${\cal O}_0$ is a maximal order containing the natural order. For a cyclic algebra~$A = (L/K,\sigma,b)$, the algebraic representation is a \typ{COL} with coefficients in~$L$ representing the element in the decomposition~$A = \bigoplus_{i=0}^{d-1}x^iL$. For a central simple algebra defined by a multiplication table over its center~$K$ on a basis~$(e_i)$, the algebraic representation is a \typ{COL} with coefficients in~$K$ representing the element on the basis~$(e_i)$. \misctitle{Warning} The coefficients in the decomposition~$A = \bigoplus_{i=0}^{d-1}x^iL$ are not the same as those in the decomposition~$A = \bigoplus_{i=0}^{d-1}Lx^i$! The $i$-th coefficients are related by conjugating by~$x^i$, which on~$L$ amounts to acting by~$\sigma^i$. \misctitle{Warning} For a central simple algebra over $\Q$ defined by a multiplication table, we cannot distinguish between the basis and the algebraic representations from the size of the vectors. The behavior is then to always interpret the column vector as a basis representation if the coefficients are \typ{INT} or \typ{FRAC}, and as an algebraic representation if the coefficients are \typ{POL} or \typ{POLMOD}. pari-2.11.2/src/functions/algebras/alglatsubset0000644000175000017500000000134113326135265020157 0ustar billbillFunction: alglatsubset Section: algebras C-Name: alglatsubset Prototype: iGGGD& Help: alglatsubset(al,lat1,lat2,{&ptindex}): tests whether lat1 is contained in lat2 and if true and ptindex is present, sets it to the index (lat2:lat1). Doc: Given an algebra~\var{al} and two lattices~\var{lat1} and~\var{lat2} in~\var{al}, tests whether~$lat1\subset lat2$. If it is true and \var{ptindex} is present, sets it to the index of~\var{lat1} in~\var{lat2}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? alglatsubset(al,lat1,lat2) %4 = 0 ? latsum = alglatadd(al,lat1,lat2); ? alglatsubset(al,lat1,latsum,&index) %6 = 1 ? index %7 = 4 @eprog pari-2.11.2/src/functions/algebras/algtensor0000644000175000017500000000067613326135265017475 0ustar billbillFunction: algtensor Section: algebras C-Name: algtensor Prototype: GGD1,L, Help: algtensor(al1,al2,{maxord=1}): tensor product of al1 and al2. Doc: Given two algebras \var{al1} and \var{al2}, computes their tensor product. Computes a maximal order by default. Prevent this computation by setting $\var{maxord}=0$. Currently only implemented for cyclic algebras of coprime degree over the same center~$K$, and the tensor product is over~$K$. pari-2.11.2/src/functions/algebras/algalgtobasis0000644000175000017500000000114713201017466020277 0ustar billbillFunction: algalgtobasis Section: algebras C-Name: algalgtobasis Prototype: GG Help: algalgtobasis(al,x): transforms the element x of the algebra al into a column vector on the integral basis of al. Doc: Given an element \var{x} in the central simple algebra \var{al} output by \tet{alginit}, transforms it to a column vector on the integral basis of \var{al}. This is the inverse function of \tet{algbasistoalg}. \bprog ? A = alginit(nfinit(y^2-5),[2,y]); ? algalgtobasis(A,[y,1]~) %2 = [0, 2, 0, -1, 2, 0, 0, 0]~ ? algbasistoalg(A,algalgtobasis(A,[y,1]~)) %3 = [Mod(Mod(y, y^2 - 5), x^2 - 2), 1]~ @eprog pari-2.11.2/src/functions/algebras/algissimple0000644000175000017500000000177413326135265020010 0ustar billbillFunction: algissimple Section: algebras C-Name: algissimple Prototype: iGD0,L, Help: algissimple(al, {ss = 0}): test whether the algebra al is simple. Doc: \var{al} being a table algebra output by \tet{algtableinit} or a central simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is simple. If $\var{ss}=1$, assumes that the algebra~\var{al} is semisimple without testing it. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); \\ matrices [*,*; 0,*] ? algissimple(A) %3 = 0 ? algissimple(A,1) \\ incorrectly assume that A is semisimple %4 = 1 ? m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; ? m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; ? m_k=[0,0,0,-1;0,0,b,0;0,1,0,0;1,0,0,0]; ? mt = [matid(4), m_i, m_j, m_k]; ? A = algtableinit(mt); \\ quaternion algebra (-1,-1) ? algissimple(A) %10 = 1 ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); \\ direct product F_4 x F_2 ? algissimple(A) %13 = 0 @eprog pari-2.11.2/src/functions/algebras/algisassociative0000644000175000017500000000152313201017466021013 0ustar billbillFunction: algisassociative Section: algebras C-Name: algisassociative Prototype: iGD0,G, Help: algisassociative(mt,p=0): true (1) if the multiplication table mt is suitable for algtableinit(mt,p), false (0) otherwise. Doc: Returns 1 if the multiplication table \kbd{mt} is suitable for \kbd{algtableinit(mt,p)}, 0 otherwise. More precisely, \kbd{mt} should be a \typ{VEC} of $n$ matrices in $M_n(K)$, giving the left multiplications by the basis elements $e_1, \dots, e_n$ (structure constants). We check whether the first basis element $e_1$ is $1$ and $e_i(e_je_k) = (e_ie_j)e_k$ for all $i,j,k$. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? algisassociative(mt) %2 = 1 @eprog May be used to check a posteriori an algebra: we also allow \kbd{mt} as output by \tet{algtableinit} ($p$ is ignored in this case). pari-2.11.2/src/functions/algebras/algaut0000644000175000017500000000071613201017466016741 0ustar billbillFunction: algaut Section: algebras C-Name: algaut Prototype: mG Help: algaut(al): the stored automorphism of the splitting field of the cyclic algebra al. Doc: Given a cyclic algebra $\var{al} = (L/K,\sigma,b)$ output by \tet{alginit}, returns the automorphism $\sigma$. \bprog ? nf = nfinit(y); ? p = idealprimedec(nf,7)[1]; ? p2 = idealprimedec(nf,11)[1]; ? A = alginit(nf,[3,[[p,p2],[1/3,2/3]],[0]]); ? algaut(A) %5 = -1/3*x^2 + 1/3*x + 26/3 @eprog pari-2.11.2/src/functions/algebras/algsub0000644000175000017500000000057013201017466016737 0ustar billbillFunction: algsub Section: algebras C-Name: algsub Prototype: GGG Help: algsub(al,x,y): element x-y in al. Doc: Given two elements $x$ and $y$ in \var{al}, computes their difference $x-y$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algsub(A,[1,1,0,0]~,[1,0,1,0]~) %2 = [0, 1, -1, 0]~ @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algradical0000644000175000017500000000146613326135265017560 0ustar billbillFunction: algradical Section: algebras C-Name: algradical Prototype: G Help: algradical(al): Jacobson radical of the algebra al. Doc: \var{al} being a table algebra output by \tet{algtableinit}, returns a basis of the Jacobson radical of the algebra \var{al} over its prime field ($\Q$ or $\F_p$). Here is an example with $A = \Q[x]/(x^2)$, with the basis~$(1,x)$: \bprog ? mt = [matid(2),[0,0;1,0]]; ? A = algtableinit(mt); ? algradical(A) \\ = (x) %3 = [0] [1] @eprog Another one with $2\times 2$ upper triangular matrices over $\Q$, with basis $I_2$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, such that $a^2 = 0$, $ab = a$, $ba = 0$, $b^2 = b$: \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algradical(A) \\ = (a) %6 = [0] [1] [0] @eprog pari-2.11.2/src/functions/algebras/algsplit0000644000175000017500000000335213326135265017310 0ustar billbillFunction: algsplit Section: algebras C-Name: algsplit Prototype: GDn Help: algsplit(al,{v='x}): computes an isomorphism between al and M_d(F_q). Doc: If \var{al} is a table algebra over~$\F_p$ output by \tet{algtableinit} that represents a simple algebra, computes an isomorphism between \var{al} and a matrix algebra~$M_d(\F_{p^n})$ where~$N = nd^2$ is the dimension of~\var{al}. Returns a \typ{VEC}~$[map,mapi]$, where: \item \var{map} is a \typ{VEC} of~$N$ matrices of size~$d\times d$ with \typ{FFELT} coefficients using the variable~\var{v}, representing the image of the basis of~\var{al} under the isomorphism. \item \var{mapi} is an~$N\times N$ matrix with \typ{INT} coefficients, representing the image in \var{al} by the inverse isomorphism of the basis~$(b_i)$ of~$M_d(\F_p[\alpha])$ (where~$\alpha$ has degree~$n$ over~$\F_p$) defined as follows: let~$E_{i,j}$ be the matrix having all coefficients~$0$ except the~$(i,j)$-th coefficient equal to~$1$, and define $$b_i = E_{((i-1)/nd)+1, ((i-1)/n \mod d)+1} \alpha^{(i-1)\mod n}.$$ Example: \bprog ? al0 = alginit(nfinit(y^2+7), [-1,-1]); ? al = algtableinit(algmultable(al0), 3); \\ isomorphic to M_2(F_9) ? [map,mapi] = algsplit(al, 'a); ? x = [1,2,1,0,0,0,0,0]~; fx = map*x %4 = [2*a 0] [ 0 2] ? y = [0,0,0,0,1,0,0,1]~; fy = map*y %5 = [1 2*a] [2 a + 2] ? map*algmul(al,x,y) == fx*fy %6 = 1 ? map*mapi[,6] %7 = [0 0] [a 0] @eprog \misctitle{Warning} If~\var{al} is not simple, \kbd{algsplit(al)} can trigger an error, but can also run into an infinite loop. Example: \bprog ? al = alginit(nfinit(y),[-1,-1]); \\ ramified at 2 ? al2 = algtableinit(algmultable(al),2); \\ maximal order modulo 2 ? algsplit(al2); \\ not semisimple, infinite loop @eprog pari-2.11.2/src/functions/algebras/alglatrighttransporter0000644000175000017500000000142213326135265022273 0ustar billbillFunction: alglatrighttransporter Section: algebras C-Name: alglatrighttransporter Prototype: GGG Help: alglatrighttransporter(al,lat1,lat2): the set of x in al such that lat1*x is contained in lat2. Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the right transporter from \var{lat1} to~\var{lat2}, i.e. the set of~$x\in al$ such that~$lat1\cdot x \subset lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,matdiagonal([1,3,7,1,2,8,5,2])); ? lat2 = alglathnf(al,matdiagonal([5,3,8,1,9,8,7,1])); ? tr = alglatrighttransporter(al,lat1,lat2); ? a = alglatelement(al,tr,[0,0,0,0,0,0,0,1]~); ? alglatsubset(al,alglatmul(al,lat1,a),lat2) %6 = 1 ? alglatsubset(al,alglatmul(al,a,lat1),lat2) %7 = 0 @eprog pari-2.11.2/src/functions/algebras/algpow0000644000175000017500000000057013201017466016753 0ustar billbillFunction: algpow Section: algebras C-Name: algpow Prototype: GGG Help: algpow(al,x,n): element x^n in al. Doc: Given an element $x$ in \var{al} and an integer $n$, computes the power $x^n$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algpow(A,[1,1,0,0]~,7) %2 = [8, -8, 0, 0]~ @eprog Also accepts a square matrix with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algsplittingfield0000644000175000017500000000140013201017466021160 0ustar billbillFunction: algsplittingfield Section: algebras C-Name: algsplittingfield Prototype: mG Help: algsplittingfield(al): the stored splitting field of the central simple algebra al. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns an \kbd{rnf} structure: the splitting field of \var{al} that is stored in \var{al}, as a relative extension of the center. \bprog nf = nfinit(y^3-5); a = y; b = y^2; {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} mt = [matid(4), m_i, m_j, m_k]; A = alginit(nf,mt,'x); algsplittingfield(A).pol %8 = x^2 - y @eprog pari-2.11.2/src/functions/algebras/algdim0000644000175000017500000000101713326135265016722 0ustar billbillFunction: algdim Section: algebras C-Name: algdim Prototype: lGD0,L, Help: algdim(al,{abs=0}): dimension of the algebra al. Doc: If \var{al} is a table algebra output by \tet{algtableinit} or if~$abs=1$, returns the dimension of \var{al} over its prime subfield ($\Q$ or $\F_p$). If~\var{al} is a central simple algebra output by \tet{alginit} and~$abs=0$, returns the dimension of \var{al} over its center. \bprog ? nf = nfinit(y^3-y+1); ? A = alginit(nf, [-1,-1]); ? algdim(A) %3 = 4 ? algdim(A,1) %4 = 12 @eprog pari-2.11.2/src/functions/algebras/alglatlefttransporter0000644000175000017500000000137013326135265022112 0ustar billbillFunction: alglatlefttransporter Section: algebras C-Name: alglatlefttransporter Prototype: GGG Help: alglatlefttransporter(al,lat1,lat2): the set of x in al such that x*lat1 is contained in lat2. Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the left transporter from \var{lat1} to~\var{lat2}, i.e. the set of~$x\in al$ such that~$x\cdot lat1 \subset lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,-1,0,1,2,0,5,2]~); ? lat2 = alglathnf(al,[0,1,-2,-1,0,0,3,1]~); ? tr = alglatlefttransporter(al,lat1,lat2); ? a = alglatelement(al,tr,[0,0,0,0,0,0,1,0]~); ? alglatsubset(al,alglatmul(al,a,lat1),lat2) %6 = 1 ? alglatsubset(al,alglatmul(al,lat1,a),lat2) %7 = 0 @eprog pari-2.11.2/src/functions/algebras/algcharpoly0000644000175000017500000000241013326135265017770 0ustar billbillFunction: algcharpoly Section: algebras C-Name: algcharpoly Prototype: GGDnD0,L, Help: algcharpoly(al,b,{v='x},{abs=0}): (reduced) characteristic polynomial of b in al, with respect to the variable v. Doc: Given an element $b$ in \var{al}, returns its characteristic polynomial as a polynomial in the variable $v$. If \var{al} is a table algebra output by \tet{algtableinit} or if $abs=1$, returns the absolute characteristic polynomial of \var{b}, which is an element of $\F_p[v]$ or~$\Q[v]$; if \var{al} is a central simple algebra output by \tet{alginit} and $abs=0$, returns the reduced characteristic polynomial of \var{b}, which is an element of~$K[v]$ where~$K$ is the center of \var{al}. \bprog ? al = alginit(nfinit(y), [-1,-1]); \\ (-1,-1)_Q ? algcharpoly(al, [0,1]~) %2 = x^2 + 1 ? algcharpoly(al, [0,1]~,,1) %3 = x^4 + 2*x^2 + 1 ? nf = nfinit(y^2-5); ? al = alginit(nf,[-1,y]); ? a = [y,1+x]~*Mod(1,y^2-5)*Mod(1,x^2+1); ? P = lift(algcharpoly(al,a)) %7 = x^2 - 2*y*x + (-2*y + 5) ? algcharpoly(al,a,,1) %8 = x^8 - 20*x^6 - 80*x^5 + 110*x^4 + 800*x^3 + 1500*x^2 - 400*x + 25 ? lift(P*subst(P,y,-y)*Mod(1,y^2-5))^2 %9 = x^8 - 20*x^6 - 80*x^5 + 110*x^4 + 800*x^3 + 1500*x^2 - 400*x + 25 @eprog Also accepts a square matrix with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algmul0000644000175000017500000000056413326135265016754 0ustar billbillFunction: algmul Section: algebras C-Name: algmul Prototype: GGG Help: algmul(al,x,y): element x*y in al. Doc: Given two elements $x$ and $y$ in \var{al}, computes their product $xy$ in the algebra~\var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algmul(A,[1,1,0,0]~,[0,0,2,1]~) %2 = [2, 3, 5, -4]~ @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algtableinit0000644000175000017500000000332113326135265020124 0ustar billbillFunction: algtableinit Section: algebras C-Name: algtableinit Prototype: GDG Help: algtableinit(mt, {p=0}): initializes the associative algebra over Q (resp. Fp) defined by the multiplication table mt. Doc: initializes the associative algebra over $K = \Q$ ($p$ omitted) or $\F_p$ defined by the multiplication table \var{mt}. As a $K$-vector space, the algebra is generated by a basis $(e_1 = 1, e_2, \dots, e_n)$; the table is given as a \typ{VEC} of $n$ matrices in $M_n(K)$, giving the left multiplication by the basis elements $e_i$, in the given basis. Assumes that $e_1=1$, that $K e_1\oplus \dots\oplus K e_n]$ describes an associative algebra over $K$, and in the case $K=\Q$ that the multiplication table is integral. If the algebra is already known to be central and simple, then the case $K = \F_p$ is useless, and one should use \tet{alginit} directly. The point of this function is to input a finite dimensional $K$-algebra, so as to later compute its radical, then to split the quotient algebra as a product of simple algebras over $K$. The pari object representing such an algebra $A$ is a \typ{VEC} with the following data: \item The characteristic of $A$, accessed with \kbd{algchar}. \item The multiplication table of $A$, accessed with \kbd{algmultable}. \item The traces of the elements of the basis. A simple example: the $2\times 2$ upper triangular matrices over $\Q$, generated by $I_2$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, such that $a^2 = 0$, $ab = a$, $ba = 0$, $b^2 = b$: \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algradical(A) \\ = (a) %6 = [0] [1] [0] ? algcenter(A) \\ = (I_2) %7 = [1] [0] [0] @eprog pari-2.11.2/src/functions/algebras/alginit0000644000175000017500000001447513326135265017130 0ustar billbillFunction: alginit Section: algebras C-Name: alginit Prototype: GGDnD1,L, Help: alginit(B, C, {v}, {maxord = 1}): initializes the central simple algebra defined by data B, C. If maxord = 1, compute a maximal order. Doc: initializes the central simple algebra defined by data $B$, $C$ and variable $v$, as follows. \item (multiplication table) $B$ is the base number field $K$ in \tet{nfinit} form, $C$ is a ``multiplication table'' over $K$. As a $K$-vector space, the algebra is generated by a basis $(e_1 = 1,\dots, e_n)$; the table is given as a \typ{VEC} of $n$ matrices in $M_n(K)$, giving the left multiplication by the basis elements~$e_i$, in the given basis. Assumes that $e_1= 1$, that the multiplication table is integral, and that $(\bigoplus_{i=1}^nK e_i,C)$ describes a central simple algebra over $K$. \bprog { mi = [0,-1,0, 0; 1, 0,0, 0; 0, 0,0,-1; 0, 0,1, 0]; mj = [0, 0,-1,0; 0, 0, 0,1; 1, 0, 0,0; 0,-1, 0,0]; mk = [0, 0, 0, 0; 0, 0,-1, 0; 0, 1, 0, 0; 1, 0, 0,-1]; A = alginit(nfinit(y), [matid(4), mi,mj,mk], 0); } @eprog represents (in a complicated way) the quaternion algebra $(-1,-1)_\Q$. See below for a simpler solution. \item (cyclic algebra) $B$ is an \kbd{rnf} structure attached to a cyclic number field extension $L/K$ of degree $d$, $C$ is a \typ{VEC} \kbd{[sigma,b]} with 2 components: \kbd{sigma} is a \typ{POLMOD} representing an automorphism generating $\text{Gal}(L/K)$, $b$ is an element in $K^*$. This represents the cyclic algebra~$(L/K,\sigma,b)$. Currently the element $b$ has to be integral. \bprog ? Q = nfinit(y); T = polcyclo(5, 'x); F = rnfinit(Q, T); ? A = alginit(F, [Mod(x^2,T), 3]); @eprog defines the cyclic algebra $(L/\Q, \sigma, 3)$, where $L = \Q(\zeta_5)$ and $\sigma:\zeta\mapsto\zeta^2$ generates $\text{Gal}(L/\Q)$. \item (quaternion algebra, special case of the above) $B$ is an \kbd{nf} structure attached to a number field $K$, $C = [a,b]$ is a vector containing two elements of $K^*$ with $a$ not a square in $K$, returns the quaternion algebra $(a,b)_K$. The variable $v$ (\kbd{'x} by default) must have higher priority than the variable of $K$\kbd{.pol} and is used to represent elements in the splitting field $L = K[x]/(x^2-a)$. \bprog ? Q = nfinit(y); A = alginit(Q, [-1,-1]); \\@com $(-1,-1)_\Q$ @eprog \item (algebra/$K$ defined by local Hasse invariants) $B$ is an \kbd{nf} structure attached to a number field $K$, $C = [d, [\kbd{PR},h_f], h_i]$ is a triple containing an integer $d > 1$, a pair $[\kbd{PR}, h_f]$ describing the Hasse invariants at finite places, and $h_i$ the Hasse invariants at archimedean (real) places. A local Hasse invariant belongs to $(1/d)\Z/\Z \subset \Q/\Z$, and is given either as a \typ{FRAC} (lift to $(1/d)\Z$), a \typ{INT} or \typ{INTMOD} modulo $d$ (lift to $\Z/d\Z$); a whole vector of local invariants can also be given as a \typ{VECSMALL}, whose entries are handled as \typ{INT}s. \kbd{PR} is a list of prime ideals (\kbd{prid} structures), and $h_f$ is a vector of the same length giving the local invariants at those maximal ideals. The invariants at infinite real places are indexed by the real roots $K$\kbd{.roots}: if the Archimedean place $v$ is attached to the $j$-th root, the value of $h_v$ is given by $h_i[j]$, must be $0$ or $1/2$ (or~$d/2$ modulo~$d$), and can be nonzero only if~$d$ is even. By class field theory, provided the local invariants $h_v$ sum to $0$, up to Brauer equivalence, there is a unique central simple algebra over $K$ with given local invariants and trivial invariant elsewhere. In particular, up to isomorphism, there is a unique such algebra $A$ of degree $d$. We realize $A$ as a cyclic algebra through class field theory. The variable $v$ (\kbd{'x} by default) must have higher priority than the variable of $K$\kbd{.pol} and is used to represent elements in the (cyclic) splitting field extension $L/K$ for $A$. \bprog ? nf = nfinit(y^2+1); ? PR = idealprimedec(nf,5); #PR %2 = 2 ? hi = []; ? hf = [PR, [1/3,-1/3]]; ? A = alginit(nf, [3,hf,hi]); ? algsplittingfield(A).pol %6 = x^3 - 21*x + 7 @eprog \item (matrix algebra, toy example) $B$ is an \kbd{nf} structure attached to a number field $K$, $C = d$ is a positive integer. Returns a cyclic algebra isomorphic to the matrix algebra $M_d(K)$. In all cases, this function computes a maximal order for the algebra by default, which may require a lot of time. Setting $maxord = 0$ prevents this computation. The pari object representing such an algebra $A$ is a \typ{VEC} with the following data: \item A splitting field $L$ of $A$ of the same degree over $K$ as $A$, in \kbd{rnfinit} format, accessed with \kbd{algsplittingfield}. \item The Hasse invariants at the real places of $K$, accessed with \kbd{alghassei}. \item The Hasse invariants of $A$ at the finite primes of $K$ that ramify in the natural order of $A$, accessed with \kbd{alghassef}. \item A basis of an order ${\cal O}_0$ expressed on the basis of the natural order, accessed with \kbd{algbasis}. \item A basis of the natural order expressed on the basis of ${\cal O}_0$, accessed with \kbd{alginvbasis}. \item The left multiplication table of ${\cal O}_0$ on the previous basis, accessed with \kbd{algmultable}. \item The characteristic of $A$ (always $0$), accessed with \kbd{algchar}. \item The absolute traces of the elements of the basis of ${\cal O}_0$. \item If $A$ was constructed as a cyclic algebra~$(L/K,\sigma,b)$ of degree $d$, a \typ{VEC} $[\sigma,\sigma^2,\dots,\sigma^{d-1}]$. The function \kbd{algaut} returns $\sigma$. \item If $A$ was constructed as a cyclic algebra~$(L/K,\sigma,b)$, the element $b$, accessed with \kbd{algb}. \item If $A$ was constructed with its multiplication table $mt$ over $K$, the \typ{VEC} of \typ{MAT} $mt$, accessed with \kbd{algrelmultable}. \item If $A$ was constructed with its multiplication table $mt$ over $K$, a \typ{VEC} with three components: a \typ{COL} representing an element of $A$ generating the splitting field $L$ as a maximal subfield of $A$, a \typ{MAT} representing an $L$-basis ${\cal B}$ of $A$ expressed on the $\Z$-basis of ${\cal O}_0$, and a \typ{MAT} representing the $\Z$-basis of ${\cal O}_0$ expressed on ${\cal B}$. This data is accessed with \kbd{algsplittingdata}. pari-2.11.2/src/functions/algebras/algsplittingdata0000644000175000017500000000255613201017466021023 0ustar billbillFunction: algsplittingdata Section: algebras C-Name: algsplittingdata Prototype: mG Help: algsplittingdata(al): data stored in the central simple algebra al to compute a splitting of al over an extension. Doc: Given a central simple algebra \var{al} output by \tet{alginit} defined by a multiplication table over its center~$K$ (a number field), returns data stored to compute a splitting of \var{al} over an extension. This data is a \typ{VEC} \kbd{[t,Lbas,Lbasinv]} with $3$ components: \item an element $t$ of \var{al} such that $L=K(t)$ is a maximal subfield of \var{al}; \item a matrix \kbd{Lbas} expressing a $L$-basis of \var{al} (given an $L$-vector space structure by multiplication on the right) on the integral basis of \var{al}; \item a matrix \kbd{Lbasinv} expressing the integral basis of \var{al} on the previous $L$-basis. \bprog ? nf = nfinit(y^3-5); a = y; b = y^2; ? {m_i = [0,a,0,0; 1,0,0,0; 0,0,0,a; 0,0,1,0];} ? {m_j = [0, 0,b, 0; 0, 0,0,-b; 1, 0,0, 0; 0,-1,0, 0];} ? {m_k = [0, 0,0,-a*b; 0, 0,b, 0; 0,-a,0, 0; 1, 0,0, 0];} ? mt = [matid(4), m_i, m_j, m_k]; ? A = alginit(nf,mt,'x); ? [t,Lb,Lbi] = algsplittingdata(A); ? t %8 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]~; ? matsize(Lb) %9 = [12, 2] ? matsize(Lbi) %10 = [2, 12] @eprog pari-2.11.2/src/functions/algebras/algadd0000644000175000017500000000054013201017466016673 0ustar billbillFunction: algadd Section: algebras C-Name: algadd Prototype: GGG Help: algadd(al,x,y): element x+y in al. Doc: Given two elements $x$ and $y$ in \var{al}, computes their sum $x+y$ in the algebra~\var{al}. \bprog ? A = alginit(nfinit(y),[-1,1]); ? algadd(A,[1,0]~,[1,2]~) %2 = [2, 2]~ @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algneg0000644000175000017500000000053313201017466016716 0ustar billbillFunction: algneg Section: algebras C-Name: algneg Prototype: GG Help: algneg(al,x): element -x in al. Doc: Given an element $x$ in \var{al}, computes its opposite $-x$ in the algebra \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? algneg(A,[1,1,0,0]~) %2 = [-1, -1, 0, 0]~ @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/alghasse0000644000175000017500000000114213201017466017245 0ustar billbillFunction: alghasse Section: algebras C-Name: alghasse Prototype: GG Help: alghasse(al,pl): the hasse invariant of the central simple algebra al at the place pl. Doc: Given a central simple algebra \var{al} output by \tet{alginit} and a prime ideal or an integer between $1$ and $r_1+r_2$, returns a \typ{FRAC} $h$ : the local Hasse invariant of \var{al} at the place specified by \var{pl}. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? alghasse(A, 1) %3 = 1/2 ? alghasse(A, 2) %4 = 0 ? alghasse(A, idealprimedec(nf,2)[1]) %5 = 1/2 ? alghasse(A, idealprimedec(nf,5)[1]) %6 = 0 @eprog pari-2.11.2/src/functions/algebras/alglatmul0000644000175000017500000000155013326135265017451 0ustar billbillFunction: alglatmul Section: algebras C-Name: alglatmul Prototype: GGG Help: alglatmul(al,lat1,lat2): the lattice generated by the products of elements of lat1 and lat2. Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the lattice generated by the products of elements of~\var{lat1} and~\var{lat2}. One of \var{lat1} and \var{lat2} is also allowed to be an element of~\var{al}; in this case, computes the product of the element and the lattice. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a1 = [1,-1,0,1,2,0,1,2]~; ? a2 = [0,1,2,-1,0,0,3,1]~; ? lat1 = alglathnf(al,a1); ? lat2 = alglathnf(al,a2); ? lat3 = alglatmul(al,lat1,lat2); ? matdet(lat3[1]) %7 = 29584 ? lat3 == alglathnf(al, algmul(al,a1,a2)) %8 = 0 ? lat3 == alglatmul(al, lat1, a2) %9 = 0 ? lat3 == alglatmul(al, a1, lat2) %10 = 0 @eprog pari-2.11.2/src/functions/algebras/algsimpledec0000644000175000017500000000225613326135265020124 0ustar billbillFunction: algsimpledec Section: algebras C-Name: algsimpledec Prototype: GD0,L, Help: algsimpledec(al,{maps=0}): [J,dec] where J is the Jacobson radical of al and dec is the decomposition into simple algebras of the semisimple algebra al/J. Doc: \var{al} being the output of \tet{algtableinit}, returns a \typ{VEC} $[J,[\var{al}_1,\var{al}_2,\dots,\var{al}_n]]$ where $J$ is a basis of the Jacobson radical of \var{al} and~$\var{al}/J$ is isomorphic to the direct product of the simple algebras~$\var{al}_i$. When $\var{maps}=1$, each~$\var{al}_i$ is replaced with a \typ{VEC} $[\var{al}_i,\var{proj}_i,\var{lift}_i]$ where $\var{proj}_i$ and~$\var{lift}_i$ are matrices respectively representing the projection map~$\var{al} \to \var{al}_i$ and a section of it. Modulo~$J$, the images of the $\var{lift}_i$ form a direct sum in~$\var{al}/J$, so that the images of~$1\in\var{al}_i$ under~$\var{lift}_i$ are central primitive idempotents of~$\var{al}/J$. The factors are sorted by increasing dimension, then increasing dimension of the center. This ensures that the ordering of the isomorphism classes of the factors is deterministic over finite fields, but not necessarily over~$\Q$. pari-2.11.2/src/functions/algebras/algmultable0000644000175000017500000000144213201017466017752 0ustar billbillFunction: algmultable Section: algebras C-Name: algmultable Prototype: mG Help: algmultable(al): multiplication table of al over its prime subfield. Doc: returns a multiplication table of \var{al} over its prime subfield ($\Q$ or $\F_p$), as a \typ{VEC} of \typ{MAT}: the left multiplication tables of basis elements. If \var{al} was output by \tet{algtableinit}, returns the multiplication table used to define \var{al}. If \var{al} was output by \tet{alginit}, returns the multiplication table of the order~${\cal O}_0$ stored in \var{al}. \bprog ? A = alginit(nfinit(y), [-1,-1]); ? M = algmultable(A); ? #M %3 = 4 ? M[1] \\ multiplication by e_1 = 1 %4 = [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] ? M[2] %5 = [0 -1 1 0] [1 0 1 1] [0 0 1 1] [0 0 -2 -1] @eprog pari-2.11.2/src/functions/algebras/algmakeintegral0000644000175000017500000000162413326135265020620 0ustar billbillFunction: algmakeintegral Section: algebras C-Name: algmakeintegral Prototype: GD0,L, Help: algmakeintegral(mt,{maps=0}): computes an integral multiplication table for an isomorphic algebra. Doc: \var{mt} being a multiplication table over $\Q$ in the same format as the input of \tet{algtableinit}, computes an integral multiplication table for an isomorphic algebra. When $\var{maps}=1$, returns a \typ{VEC} $[\var{mt2},\var{S},\var{T}]$ where \var{S} and \var{T} are matrices respectively representing the map from the algebra defined by \var{mt} to the one defined by \var{mt2} and its inverse. \bprog ? mt = [matid(2),[0,-1/4;1,0]]; ? algtableinit(mt); *** at top-level: algtableinit(mt) *** ^---------------- *** algtableinit: domain error in algtableinit: denominator(mt) != 1 ? mt2 = algmakeintegral(mt); ? al = algtableinit(mt2); ? algisassociative(al) %4 = 1 @eprog pari-2.11.2/src/functions/algebras/algcentralproj0000644000175000017500000000201513326135265020473 0ustar billbillFunction: algcentralproj Section: algebras C-Name: alg_centralproj Prototype: GGD0,L, Help: algcentralproj(al,z,{maps=0}): projections of the algebra al on the orthogonal central idempotents z[i]. Doc: Given a table algebra \var{al} output by \tet{algtableinit} and a \typ{VEC} $\var{z}=[z_1,\dots,z_n]$ of orthogonal central idempotents, returns a \typ{VEC} $[al_1,\dots,al_n]$ of algebras such that $al_i = z_i\, al$. If $\var{maps}=1$, each $al_i$ is a \typ{VEC} $[quo,proj,lift]$ where \var{quo} is the quotient algebra, \var{proj} is a \typ{MAT} representing the projection onto this quotient and \var{lift} is a \typ{MAT} representing a lift. A simple example: $\F_2\times \F_4$, generated by~$1=(1,1)$, $e=(1,0)$ and~$x$ such that~$x^2+x+1=0$. We have~$e^2=e$, $x^2=x+1$ and~$ex=0$. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? e = [0,1,0]~; ? e2 = algsub(A,[1,0,0]~,e); ? [a,a2] = algcentralproj(A,[e,e2]); ? algdim(a) %6 = 1 ? algdim(a2) %7 = 2 @eprog pari-2.11.2/src/functions/algebras/algisinv0000644000175000017500000000100113201017466017264 0ustar billbillFunction: algisinv Section: algebras C-Name: algisinv Prototype: iGGD& Help: algisinv(al,x,{&ix}): tests whether x is invertible and sets ix to the inverse of x. Doc: Given an element $x$ in \var{al}, tests whether $x$ is invertible, and sets $ix$ to the inverse of $x$. \bprog ? A = alginit(nfinit(y), [-1,1]); ? algisinv(A,[-1,1]~) %2 = 0 ? algisinv(A,[1,2]~,&ix) %3 = 1 ? ix %4 = [Mod(Mod(-1/3, y), x^2 + 1), Mod(Mod(2/3, y), x^2 + 1)]~ @eprog Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algquotient0000644000175000017500000000132113326135265020017 0ustar billbillFunction: algquotient Section: algebras C-Name: alg_quotient Prototype: GGD0,L, Help: algquotient(al,I,{maps=0}): quotient of the algebra al by the two-sided ideal I. Doc: \var{al} being a table algebra output by \tet{algtableinit} and \var{I} being a basis of a two-sided ideal of \var{al} represented by a matrix, returns the quotient $\var{al}/\var{I}$. When $\var{maps}=1$, returns a \typ{VEC} $[\var{al}/\var{I},\var{proj},\var{lift}]$ where \var{proj} and \var{lift} are matrices respectively representing the projection map and a section of it. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? AQ = algquotient(A,[0;1;0]); ? algdim(AQ) %4 = 2 @eprog pari-2.11.2/src/functions/algebras/algprimesubalg0000644000175000017500000000125513201017466020461 0ustar billbillFunction: algprimesubalg Section: algebras C-Name: algprimesubalg Prototype: G Help: algprimesubalg(al): prime subalgebra of the positive characteristic, semisimple algebra al. Doc: \var{al} being the output of \tet{algtableinit} representing a semisimple algebra of positive characteristic, returns a basis of the prime subalgebra of~\var{al}. The prime subalgebra of~\var{al} is the subalgebra fixed by the Frobenius automorphism of the center of \var{al}. It is abstractly isomorphic to a product of copies of $\F_p$. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? algprimesubalg(A) %3 = [1 0] [0 1] [0 0] @eprog pari-2.11.2/src/functions/algebras/algchar0000644000175000017500000000056313201017466017065 0ustar billbillFunction: algchar Section: algebras C-Name: algchar Prototype: mG Help: algchar(al): characteristic of the algebra al. Doc: Given an algebra \var{al} output by \tet{alginit} or \tet{algtableinit}, returns the characteristic of \var{al}. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,13); ? algchar(A) %3 = 13 @eprog pari-2.11.2/src/functions/algebras/algramifiedplaces0000644000175000017500000000117613326135265021127 0ustar billbillFunction: algramifiedplaces Section: algebras C-Name: algramifiedplaces Prototype: G Help: algramifiedplaces(al): vector of the places of the center of al that ramify in al. Each place is described as an integer between 1 and r1 or as a prime ideal. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns a \typ{VEC} containing the list of places of the center of \var{al} that are ramified in \var{al}. Each place is described as an integer between~$1$ and~$r_1$ or as a prime ideal. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algramifiedplaces(A) %3 = [1, [2, [2, 0]~, 1, 2, 1]] @eprog pari-2.11.2/src/functions/algebras/algdivr0000644000175000017500000000034713326135265017122 0ustar billbillFunction: algdivr Section: algebras C-Name: algdivr Prototype: GGG Help: algdivr(al,x,y): element x/y in al. Doc: Given two elements $x$ and $y$ in \var{al}, returns $xy^{-1}$. Also accepts matrices with coefficients in \var{al}. pari-2.11.2/src/functions/algebras/algindex0000644000175000017500000000164213326135265017264 0ustar billbillFunction: algindex Section: algebras C-Name: algindex Prototype: lGDG Help: algindex(al,{pl}): the index of the central simple algebra al. If pl is set, it should be a prime ideal of the center or an integer between 1 and r1+r2, and in that case return the local index at the place pl instead. Doc: Returns the index of the central simple algebra~$A$ over~$K$ (as output by alginit), that is the degree~$e$ of the unique central division algebra~$D$ over $K$ such that~$A$ is isomorphic to some matrix algebra~$M_k(D)$. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ and~$r_1+r_2$, and in that case return the local index at the place \var{pl} instead. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,y]); ? algindex(A, 1) %3 = 2 ? algindex(A, 2) %4 = 1 ? algindex(A, idealprimedec(nf,2)[1]) %5 = 2 ? algindex(A, idealprimedec(nf,5)[1]) %6 = 1 ? algindex(A) %7 = 2 @eprog pari-2.11.2/src/functions/algebras/alggroup0000644000175000017500000000121313326135265017303 0ustar billbillFunction: alggroup Section: algebras C-Name: alggroup Prototype: GDG Help: alggroup(gal, {p=0}): constructs the group algebra of gal over Q (resp. Fp). Doc: initializes the group algebra~$K[G]$ over~$K=\Q$ ($p$ omitted) or~$\F_p$ where~$G$ is the underlying group of the \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed to be a \typ{VEC} of permutations that is closed under products. Example: \bprog ? K = nfsplitting(x^3-x+1); ? gal = galoisinit(K); ? al = alggroup(gal); ? algissemisimple(al) %4 = 1 ? G = [Vecsmall([1,2,3]), Vecsmall([1,3,2])]; ? al2 = alggroup(G, 2); ? algissemisimple(al2) %8 = 0 @eprog pari-2.11.2/src/functions/algebras/alginvbasis0000644000175000017500000000076313201017466017770 0ustar billbillFunction: alginvbasis Section: algebras C-Name: alginvbasis Prototype: mG Help: alginvbasis(al): basis of the natural order of the central simple algebra al in terms of the stored order. Doc: Given an central simple algebra \var{al} output by \tet{alginit}, returns a $\Z$-basis of the natural order in \var{al} with respect to the order~${\cal O}_0$ stored in \var{al}. \bprog A = alginit(nfinit(y), [-1,-1]); ? alginvbasis(A) %2 = [1 0 0 -1] [0 1 0 -1] [0 0 1 -1] [0 0 0 2] @eprog pari-2.11.2/src/functions/algebras/algdegree0000644000175000017500000000051113201017466017374 0ustar billbillFunction: algdegree Section: algebras C-Name: algdegree Prototype: lG Help: algdegree(al): degree of the central simple algebra al. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns the degree of \var{al}. \bprog ? nf = nfinit(y^3-y+1); ? A = alginit(nf, [-1,-1]); ? algdegree(A) %3 = 2 @eprog pari-2.11.2/src/functions/algebras/algb0000644000175000017500000000066213201017466016371 0ustar billbillFunction: algb Section: algebras C-Name: algb Prototype: mG Help: algb(al): the element b of the center of the cyclic algebra al used to define it. Doc: Given a cyclic algebra $\var{al} = (L/K,\sigma,b)$ output by \tet{alginit}, returns the element $b\in K$. \bprog nf = nfinit(y); ? p = idealprimedec(nf,7)[1]; ? p2 = idealprimedec(nf,11)[1]; ? A = alginit(nf,[3,[[p,p2],[1/3,2/3]],[0]]); ? algb(A) %5 = Mod(-77, y) @eprog pari-2.11.2/src/functions/algebras/alglathnf0000644000175000017500000000162513326135265017432 0ustar billbillFunction: alglathnf Section: algebras C-Name: alglathnf Prototype: GGD0,G, Help: alglathnf(al,m,{d=0}): the lattice generated by the columns of m, assuming that this lattice contains d times the integral basis of al. Doc: Given an algebra \var{al} and a matrix \var{m} with columns representing elements of \var{al}, returns the lattice $L$ generated by the columns of \var{m}. If provided, \var{d} must be a rational number such that $L$ contains \var{d} times the natural basis of~\var{al}. The argument \var{m} is also allowed to be a \typ{VEC} of \typ{MAT}, in which case \var{m} is replaced by the concatenation of the matrices, or a \typ{COL}, in which case \var{m} is replaced by its left multiplication table as an element of \var{al}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a = [1,1,-1/2,1,1/3,-1,1,1]~; ? mt = algtomatrix(al,a,1); ? lat = alglathnf(al,mt); ? lat[2] %5 = 1/6 @eprog pari-2.11.2/src/functions/algebras/alglatinter0000644000175000017500000000124113326135265017772 0ustar billbillFunction: alglatinter Section: algebras C-Name: alglatinter Prototype: GGGD& Help: alglatinter(al,lat1,lat2,{&ptsum}): the intersection of the lattices lat1 and lat2. If ptsum is present, sets it to the sum of the lattices. Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} in~\var{al}, computes the intersection~$lat1\cap lat2$. If \var{ptsum} is present, sets it to the sum~$lat1 + lat2$. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); ? latinter = alglatinter(al,lat1,lat2,&latsum); ? matdet(latsum[1]) %5 = 4 ? matdet(latinter[1]) %6 = 64 @eprog pari-2.11.2/src/functions/algebras/algpoleval0000644000175000017500000000104113326135265017610 0ustar billbillFunction: algpoleval Section: algebras C-Name: algpoleval Prototype: GGG Help: algpoleval(al,T,b): T in K[X] evaluate T(b) in al. Doc: Given an element $b$ in \var{al} and a polynomial $T$ in $K[X]$, computes~$T(b)$ in~\var{al}. Also accepts as input a \typ{VEC}~$[b,mb]$ where~$mb$ is the left multiplication table of~$b$. \bprog ? nf = nfinit(y^2-5); ? al = alginit(nf,[y,-1]); ? b = [1..8]~; ? pol = algcharpoly(al,b,,1); ? algpoleval(al,pol,b)==0 %5 = 1 ? mb = algtomatrix(al,b,1); ? algpoleval(al,pol,[b,mb])==0 %7 = 1 @eprog pari-2.11.2/src/functions/algebras/algsubalg0000644000175000017500000000160213326135265017426 0ustar billbillFunction: algsubalg Section: algebras C-Name: algsubalg Prototype: GG Help: algsubalg(al,B): subalgebra of al with basis B. Doc: \var{al} being a table algebra output by \tet{algtableinit} and \var{B} being a basis of a subalgebra of~\var{al} represented by a matrix, computes an algebra~\var{al2} isomorphic to \var{B}. Returns $[\var{al2},\var{B2}]$ where \var{B2} is a possibly different basis of the subalgebra \var{al2}, with respect to which the multiplication table of \var{al2} is defined. \bprog ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? B = algsubalg(A,[1,0; 0,0; 0,1]); ? algdim(A) %4 = 3 ? algdim(B[1]) %5 = 2 ? m = matcompanion(x^4+1); ? mt = [m^i | i <- [0..3]]; ? al = algtableinit(mt); ? B = [1,0;0,0;0,1/2;0,0]; ? al2 = algsubalg(al,B); ? algdim(al2[1]) ? al2[2] %13 = [1 0] [0 0] [0 1] [0 0] @eprog pari-2.11.2/src/functions/algebras/alglatelement0000644000175000017500000000111513326135265020302 0ustar billbillFunction: alglatelement Section: algebras C-Name: alglatelement Prototype: GGG Help: alglatelement(al,lat,c): returns the element of al whose coordinates on the Z-basis of lat are c. Doc: Given an algebra \var{al}, a lattice \var{lat} and a~\typ{COL}~\var{c}, returns the element of~\var{al} whose coordinates on the \Z-basis of~\var{lat} are given by~\var{c}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a1 = [1,-1,0,1,2,0,1,2]~; ? lat1 = alglathnf(al,a1); ? c = [1..8]~; ? elt = alglatelement(al,lat1,c); ? alglatcontains(al,lat1,elt,&c2) %6 = 1 ? c==c2 %7 = 1 @eprog pari-2.11.2/src/functions/algebras/alghassef0000644000175000017500000000144213326135265017424 0ustar billbillFunction: alghassef Section: algebras C-Name: alghassef Prototype: mG Help: alghassef(al): the hasse invariant of the central simple algebra al at finite places. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns a \typ{VEC} $[\kbd{PR}, h_f]$ describing the local Hasse invariants at the finite places of the center: \kbd{PR} is a \typ{VEC} of primes and $h_f$ is a \typ{VECSMALL} of integers modulo the degree $d$ of \var{al}. The Hasse invariant of~\var{al} at the primes outside~\kbd{PR} is~$0$, but~\kbd{PR} can include primes at which the Hasse invariant is~$0$. \bprog ? nf = nfinit(y^2-5); ? A = alginit(nf, [-1,2*y-1]); ? [PR,hf] = alghassef(A); ? PR %4 = [[19, [10, 2]~, 1, 1, [-8, 2; 2, -10]], [2, [2, 0]~, 1, 2, 1]] ? hf %5 = Vecsmall([1, 0]) @eprog pari-2.11.2/src/functions/algebras/algbasis0000644000175000017500000000077313326135265017262 0ustar billbillFunction: algbasis Section: algebras C-Name: algbasis Prototype: mG Help: algbasis(al): basis of the stored order of the central simple algebra al. Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns a $\Z$-basis of the order~${\cal O}_0$ stored in \var{al} with respect to the natural order in \var{al}. It is a maximal order if one has been computed. \bprog A = alginit(nfinit(y), [-1,-1]); ? algbasis(A) %2 = [1 0 0 1/2] [0 1 0 1/2] [0 0 1 1/2] [0 0 0 1/2] @eprog pari-2.11.2/src/functions/algebras/alggroupcenter0000644000175000017500000000340713326135265020513 0ustar billbillFunction: alggroupcenter Section: algebras C-Name: alggroupcenter Prototype: GDGD& Help: alggroupcenter(gal,{p=0},{&cc}): constructs the center of the group algebra of gal over Q (resp. Fp), and sets cc to the conjugacy classes of gal. Doc: initializes the center~$Z(K[G])$ of the group algebra~$K[G]$ over~$K=\Q$ ($p = 0$ or omitted) or~$\F_p$ where~$G$ is the underlying group of the \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed to be a \typ{VEC} of permutations that is closed under products. Sets~\var{cc} to a \typ{VEC}~$[\var{elts},\var{conjclass},\var{rep},\var{flag}]$ where~\var{elts} is a sorted \typ{VEC} containing the list of elements of~$G$, \var{conjclass} is a \typ{VECSMALL} of the same length as~\var{elts} containing the index of the conjugacy class of the corresponding element (an integer between $1$ and the number of conjugacy classes), and~\var{rep} is a \typ{VECSMALL} of length the number of conjugacy classes giving for each conjugacy class the index in~\var{elts} of a representative of this conjugacy class. Finally \var{flag} is $1$ if and only if the permutation representation of $G$ is transitive, in which case the $i$-th element of \var{elts} is characterized by $g[1] = i$; this is always the case when \var{gal} is a \kbd{galoisinit} structure. The basis of~$Z(K[G])$ as output consists of the indicator functions of the conjugacy classes in the ordering given by~\var{cc}. Example: \bprog ? K = nfsplitting(x^4+x+1); ? gal = galoisinit(K); \\ S4 ? al = alggroupcenter(gal,,&cc); ? algiscommutative(al) %4 = 1 ? #cc[3] \\ number of conjugacy classes of S4 %5 = 5 ? gal = [Vecsmall([1,2,3]),Vecsmall([1,3,2])]; \\ C2 ? al = alggroupcenter(gal,,&cc); ? cc[3] %8 = Vecsmall([1, 2]) ? cc[4] %9 = 0 @eprog pari-2.11.2/src/functions/algebras/alglatcontains0000644000175000017500000000121213326135265020465 0ustar billbillFunction: alglatcontains Section: algebras C-Name: alglatcontains Prototype: iGGGD& Help: alglatcontains(al,lat,x,{&ptc}): tests whether the lattice lat contains the element x. If ptc is present, sets it to the coordinates of x on the basis of lat. Doc: Given an algebra \var{al}, a lattice \var{lat} and \var{x} in~\var{al}, tests whether~$x\in lat$. If~\var{ptc} is present, sets it to the~\typ{COL} of coordinates of~$x$ in the basis of~\var{lat}. \bprog ? al = alginit(nfinit(y^2+7), [-1,-1]); ? a1 = [1,-1,0,1,2,0,1,2]~; ? lat1 = alglathnf(al,a1); ? alglatcontains(al,lat1,a1,&c) %4 = 1 ? c %5 = [-1, -2, -1, 1, 2, 0, 1, 1]~ @eprog pari-2.11.2/src/functions/algebras/algiscommutative0000644000175000017500000000110713201017466021034 0ustar billbillFunction: algiscommutative Section: algebras C-Name: algiscommutative Prototype: iG Help: algiscommutative(al): test whether the algebra al is commutative. Doc: \var{al} being a table algebra output by \tet{algtableinit} or a central simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is commutative. \bprog ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; ? A = algtableinit(mt); ? algiscommutative(A) %3 = 0 ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; ? A = algtableinit(mt,2); ? algiscommutative(A) %6 = 1 @eprog pari-2.11.2/src/functions/algebras/algbasistoalg0000644000175000017500000000117513201017466020300 0ustar billbillFunction: algbasistoalg Section: algebras C-Name: algbasistoalg Prototype: GG Help: algbasistoalg(al,x): transforms the column vector x on the integral basis of al into an element of al in algebraic form. Doc: Given an element \var{x} in the central simple algebra \var{al} output by \tet{alginit}, transforms it to its algebraic representation in \var{al}. This is the inverse function of \tet{algalgtobasis}. \bprog ? A = alginit(nfinit(y^2-5),[2,y]); ? z = algbasistoalg(A,[0,1,0,0,2,-3,0,0]~); ? liftall(z) %3 = [(-1/2*y - 2)*x + (-1/4*y + 5/4), -3/4*y + 7/4]~ ? algalgtobasis(A,z) %4 = [0, 1, 0, 0, 2, -3, 0, 0]~ @eprog pari-2.11.2/CHANGES-2.60000644000175000017500000014412713447371554012502 0ustar billbill# $Id$ Bug numbers refer to the BTS at http://pari.math.u-bordeaux.fr/Bugs/ Done for version 2.7.0 (released 21/03/2014): Fixed 1- e = ellinit(E over Qp); ellztopoint(e, 3) --> SEGV 2- thue((x^2+1)^2*(x^2-2),-4) --> missing solutions [+-1, +-1] BA 3- spaces in directory names were not supported 4- silent overflow when inputing t_REAL of huge exponent [#1526] 5- zeta(2+10^-101*I) -> overflow 6- RgX_mullow(f,g,n) could return a result of degree n (instead of < n) Same with RgX_sqrlow 7- ellrootno(E) could lead to a SEGV [#1527] 8- issquare(Mod(3,22)) -> 0 [#1528] JD 9- polcyclo(5, Mod(-1,3)) was the negative of correct value JD 10- elltors(ellinit("90c3")) returned Z/12 but a generator of order 6 11- thue(thueinit(x^3-x-1),1578191) => oo loop [#1532] 12- catastrophic cancellation in eint1 (x moderately large) 13- SEGV in ellweilpairing [#1535] 14- factor(Mod(1,2)*Pol(1)) -> [Mod(0, 2) 1] 15- Mod(Pol(0), 2) -> 0, instead of Mod(0,2) 16- QXQ_to_mod was called with t_POLMOD arguments 17- ellwp(E, 'z) had stopped working for E not defined over C 18- nfdisc(T, t_MAT=partial discriminant factorization) => corruption [#1542] 19- norm(Mod(z,T)) where z is not a t_POL or in a different variable than T => wrong result [#1539] 20- polresultant(Pol(Mod(0,2)), x) -> 0 instead of Mod(0,2) 21- nffactor(T, pol) possibly wrong results when nfinit(T) is not rigorously computed [#1545] 22- gmodgs(t_POLMOD,): incorrect implementation BA 23- library functions Fp_pow/Fp_pow mishandled negative basis 24- gcd(1/(2^64*y),Mod(x^2,2^64*x^3)) --> inconsistent gcd [#1541] 25- matadjoint([x,0,0;0,0,0;0,0,0]) => wrong variables [#1547] 26- ellordinate(e, exact t_COMPLEX) => either a wrong result (no solution) or a solution computed at an incorrect accuracy (DEFAULTPREC) [#1548] 27- weber(1.0*I,1) => SEGV [#1549] 28- primepi(2^32) => oo loop [on 32-bit machine] 29- primepi(N >= 2^32 or 2^64) off by 1 JD 30- [libpari] initprimetable(2^20): infinite recursion 31- very inefficient div_rfrac_pol() [#1537] 32- polresultantext(x+1,x^2) -> [-# + 1, 1, 1] 33- for(i=a, b, ) where a < 0, b < 0 : go through wrong indices if #a != #b 34- printf("%1.2f",Mat([1.,2.])) -> SEGV [#1550] Added BA 1- library functions FlxX_to_FlxC, FlxXV_to_FlxM, polx_FlxX BA 2- library function Flx_lead 3- library function RgV_to_RgM Done for version 2.6.2 (released 30/01/2014): Fixed 1- eulerphi(t_INT factorization) corrupted the input BA 2- 8bit chars were interpreted as end of input 3- Bernoulli numbers were no longer cached [2.6.0] 4- typo in Brillhart, Lehmer, Selfridge primality test [#1467] 5- [Configure] confusing error messages when C compiler doesn't work 6- scalar + t_SER = 0 => wrong valuation (1+O(x)-1 => O(x^2)) BA 7- squaring of t_REAL was not faster than multiply 8- 1+O(2^(2^18)) => O(2^0) (silent overflow) PB 9- Mod(1, 2) - Mod(2, 4) => Mod(-1,2) [#1469] 10- memory corruption in subgrouplist: e.g. subgrouplist([53835600, 29], 5) 11- SEGV in zncoppersmith (when auxilliary polynomial was non-monic) 12- division by 0 in Fl_ellcard_Shanks [2.6.1, #1474] 13- ellwp([1,I]) -> stack overflow [2.6.0] 14- sumdedekind(h < 0, k < 0) wrong result; if gcd(h,k) > 0 as well 15- galoisexport(G, 1) -> SEGV 16- ??default(log) no longer worked 17- rnfalgtobasis, rnfbasistoalg, rnfeltup, rnfeltdown, rnfeltabstorel, rnfeltreltoabs were not treating their inputs consistently, and accepted (or crashed on) too many incorrect inputs. 18- rnfideal* did not handle correctly the 0 ideal 19- rnfidealtwoelt(non integral ideal) => crash 20- nfeltreducemodpr(K, non invertible elt mod pr,...) => wrong result (now an e_INV error) 21- rnfbasis: wrong result due to a mistake in gen_if_principal [2.6.0, revert d62f0de01] 22- nfsolvemodpr(nf,a,b,P): a must be invertible, as in matsolve (was not documented, used to SEGV). Raise an error if not. 23- various bnrdisclist crashes 24- bnrclassno(bnf, prime ideal) -> SEGV 25- forpart(x=k,) raised an exception if k < 0 [ now empty loop ] 26- deriv(constant) now returns 0 in the base ring (not gen_0). 27- inconsistencies and mistakes in deriv / intformal of t_POLMOD: forbid integration wrt the main variable of x.mod, deriv(Mod(x, x^2),x) was Mod(1,x^2) and deriv(Mod(y,x^2),y) was 0 instead of respectively 0 and Mod(1,x^2) 28- idealchinese with t_POLMOD inputs -> input error 29- idealchinese with denominators -> SEGV 30- qflll(Mat(0)) returned Mat(1) 31- infinite loop in sumpos: sumpos(n=1,-log(cos(1/n))) [#1481] BA 32- doing allocatemem in the break loop would corrupt the new break loop 33- relative error in eint1 was larger than expected 34- select(t_LIST,,1) [ indirect select ] didn't work 35- vecsort(List(),,4) -> SEGV 36- factorpadic / polrootspadic lost accuracy when converting output from integers to t_PADICs (factorpadic(t^2 + 3^5, 3, 5) -> irreducible factor (1 + O(3^5))*t^2 + O(3^5)*t + O(3^0) 37- Mod(0,0) is no longer valid => division by 0 (as Mod(x,0) for x != 0) 38- RgX_to_RgV no longer accepts other types than t_POL. Use Rg_to_RgV for a more permissive function 39- broken Fq_sqrt when T != NULL and t_INT input 40- ispower(1009^11) -> 0 [2.6.0] 41- ellinit([0,1,1,0,1],2).group -> SEGV 42- nfroots(nf, deg 1 polynomial) -> wrong result 43- Configure --time=ftime: wrong reported timings 44- mateigen(rational matrix): inconsistent concatenation [#1489,2.6.0] 45- polroots(): wrong accuracy of (real) 0 components 46- randomprime(2) -> SEGV [#1493, 2.6.0] 47- forqfvec(v,[;],0,) -> SEGV [#1495] 48- poliscyclo(x^0) -> 2 49- truncation (precision) errors in bnfnarrow [#1491] 50- matadjoint assumed that n! is invertible. If this is not the case, now use a safe algorithm 51- leading coefficient of elldivpol ignored the characteristic,e.g. E=ellinit([a1,a2,a3,a4,a6*Mod(1,2)]); elldivpol(E,2) 52- gcd involving a t_FFELT -> SEGV 53- oo loop in ispower for huge arguments / oo loop in prime iterator in congruence classes [#1498, 2.6.0] 54- L=[1,2,3]; apply(x->L=x,L) -> SEGV ( idem select and [|x<-] operators ) 55- (k+1.)/k - (2*k+1.)/k -> incorrect object 56- gcd(x,0.) -> 1 but gcd(x,Pol(0.)) -> x [ the former is correct, since 0. is inexact and may represent an arbitrary small non-zero real number ] 57- eint1 misbehaved at large precision [#1499] 58- polredbest(T,1) incorrect if T non-monic or degree 1 59- nfcertify might miss a factor to be certified, e.g. P=polcompositum(x^4+437*x+19,x^5-571*x+27)[1]; nfcertify(nfinit(P, [2,3,5])) was empty 60- polresultantext(t_POL in y, t_POL in y,y) -> U/V as t_POL in x [#1509] 61- inconsistent handling of t_POL "divided by" scalar among the variants of Euclidean division (%, divrem, \, ...). E.g. x % 2 is OK, but x % Mod(2,3) was not. We now follow the semantic of grem/gdeuc/poldivrem: a scalar is understood as a t_POL of degree 0 in the proper variable [#1510] 62- incorrect rounding in mulur BA 63- Configure: --includedir was ignored 64- add GC in RgV_dotproduct / RgV_dotsquare 65- ZX equal was checking variables, contrary to the spirit of the specification (and contrary to RgX_equal). Specify behaviour properly: none of the internal .*[xX]_equal function check variable numbers. 66- arithmetic functions did not accept factorizations of negative integers (whereas most of them are defined for negetive integers) BA 67- Configure --time=ftime actually tested times, not ftime. Remove ftime from the default list of timer functions (reports wallclock time, not CPU time) [#1523] 68- polredabs() could (find then) forget some polynomials [#1511] 69- poldisc(x^3 + Mod(2,3)*x^2) --> e_INV 70- (Mod(4.,y^2+1)*(1 + O(x)))^(1/2) -> junk (= [2.0+O(x)),2.0+O(x)]~). Worse if other t_POLMOD coefficients. Now exception. 71- sin(O(p)) returned 1+O(p) instead of O(p) Changed 1- default help text for a user function is now as in \u: fun = (args)->body 2- after addhelp(f,...), ?f no longer include default help text for a user function (function code). Type 'f' to see the function code. 3- primes([a,b]) now returns the primes in the interval [a,b] 4- install: add symbol name in library and GP prototype to default help 5- the rnf structure format 6- library functions: rename rnfelementxxx -> rnfeltxxx, rnfidealhermite -> rnfidealhnf 7- allow mathnf(t_VEC) [ apply Mat() automatically ], gives acces to the ZV_gcdext() routine. 8- mathnf(,2) (generic vs integral t_MAT) is deprecated: we always test the matrix entries and choose the appropriate routine 9- bnrclassno: allow all standard ways to define class fiels (A,B,C), not only bnf + module 10- bnrinit(bnf,f): allow using idealstar(bnf,f) in place of f 11- Let Set(t_VECSMALL v) behave as Set(Vec(v)) 12- ffgen(T) now checks whether T is squarefree (testing for irreducibility is too expensive) 13- variable() no longer raises exceptions: if no variable can be associated to the object, return 0. Thus "if (!variable(x), )" may be used to test whether x has a "variable". JD 14- polcyclo(n, x) now works for all roots of 1 15- quadpoly no longer accepts vector/matrix arguments, see 2.6.0,C94 16- [libpari] renamed ZM_hnfremdiv -> ZM_hnfdivrem 17- x t_REAL * y t_INT: either convert y to t_REAL (as before) or use integer multiplication (if lg(x) >> lg(y)) 18- GP: all results are now stored in GP history, together with the time to obtain them [ we used to only store non-gnil results, and no timings ] 19- chinese(t_POL,t_POL): allow polynomials of different degrees 20- deplin(): use FpM/Flm/F2m routines if possible (like all other generic linear algebra routines) 21- FpM_gauss(a,b,) from modular kernel no longer allow all types of input: split into FpM_FpC_gauss (b t_COL) and FpM_gauss (b t_MAT). Same for all modular xxx_gauss functions 22- O(1/x^2) --> error [ now equivalent to O(x^-2) ] 23- faster evaluated polhermite/pollegendre 24- polhensellift / ZpX_liftfact: use quasi-linear ZXX_mul_Kronecker instead of RgX_mul (~ Karatsuba) 25- [libpari] renamed gcmpX -> gequalX 26- [libpari] renamed ordred -> polredord 27- the prid structure returned by idealprimedec: the anti-uniformizer tau (pr_get_tau) is now stored via its multiplication table 28- rnfpolredabs(x,3) did not conform to the documentation (which did not make sense). Fix documentation and function, for rnfpolredbest as well. 29- [libpari] renamed recip -> serreverse 30- lift(x,'v) / centerlift(x,'v) now only lift t_POLMODs in variable v, no longer (most) t_INTMOD / t_PADICs met along the way 31- lift / centerlift no longer raise an exception when they encounter a non-arithmetic type (e.g. a t_REAL or even a t_STR) in a structure. They just copy the offending sub-object as-is. 32- generic polynomial Euclidean division (grem, gmod, poldivrem): when result is the zero polynomial, use RgX_get_0, not gen_0 / pol_0 33- rnf.pol (absolute defining polynomial / Q) is now called rnf.polabs, rnf.pol is now the relative polynomial, defining the relative extension over the base. BA 34- FpXYQQ_pow: change order of moduli to be consistent with FpXQXQ_pow. BA 35- FlxYqQ_pow: renamed to FlxYqq_pow, and moduli order changed. 36- idealstar(K,id), allow to input 'id' as a factorization into prime ideals, as produced by idealfactor 37- define eulerphi(0) = 2 [ now eulerphi(n) = znstar(n).no for all n ] 38- allow subst(t_SER,x,exact 0): subst(2+O(x),x,Mod(0,3))->Mod(2,3) [#1513] 39- [libpari] rename gsh -> gsinh, gch -> gcosh, gth -> gtanh, gash -> gasinh, gach -> gacosh, gath -> gatanh, ggamd -> ggammah (follow GP names) 40- no longer naively use the Karatsuba/3M formula to multiply t_COMPLEX of t_REALs: loss of accuracy is too important and unpredictable from the user's point of view [ e.g. (1+ 1e-90*I)*(1e90+I) -> 1. E90 + 0.E52*I, when the definition directly yields 1. E90 + 2*I ]. Could use it when the exponents of real/imaginary parts are close, increasing the precision by the exponent difference (increasing overhead...): not done yet. 41- renamed mpexp1 -> mpexpm1, cxexp1 -> cxexpm1 42- change prototye of mpsincos1 and rename -> mpsincosm1 Added EP 1- Configure option for gcov/lcov support 2- libpari function FF_f, member function g.f for t_FFELT (definition field has p^f elements) 3- libpari functions gprimepi_upper_bound, gprimepi_lower_bound, primepi_lower_bound, primes_interval, primes_interval_zv, primes_upto_zv, primes0 4- libpari functions rnf_get_absdegree, rnf_get_invzk, rnf_get_map, rnf_get_nf, rnf_get_nfdegree, rnf_get_nfpol, rnf_get_nfvarn, rnf_get_pol, rnf_get_polabs, rnf_get_zk, rnf_get_nfzk, rnf_get_varn, rnf_get_disc, rnf_get_index, RgV_is_QV, RgX_equal_var 5- allow rnf.disc, rnf.index 6- functions rnfelttrace, rnfeltnorm 7- function ZV_gcdext, based on ZM_hnflll (simplified) 8- allow ffgen(p^f) instead of ffgen(ffinit(p,f)) 9- [libpari] Fq_sqrtn 10- mathnfmodid(m, d): allow d an arbitrary vector of positive integers. The old syntax (d an integer, representing a vector of equal integers) is still allowed LGr11- GP function Colrev 12- GP operator %#n to recover time used to compute history result %n 13- GP function getabstime() 14- [libpari] Rg_to_F2, RgV_to_F2v, RgM_to_F2m, F2c_to_mod, F2m_to_mod, Flc_to_mod, Flm_to_mod, F2m_F2c_invimage, F2m_invimage, F2m_suppl, Flm_suppl, F2m_rank, Flm_rank, F2m_rowslice, F2v_slice, F2v_ei BA 15- Parallel GP support (parapply, pareval, parfor, parforprime, parselect, parsum, parvector) 16- [libpari] residual_characteristic 17- GP function characteristic() 18- [libpari] muluui, diviuuexact 19- [libpari] Kronecker_to_ZXX, ZXX_mul_Kronecker BA 20- conversion from matrices of FFELTs to low level (Fq/Flxq/F2xq) kernels for faster treatment. 21- FqM_det, FlxqM_det, FlxqM_inv, F2xqM_det, F2xqM_inv, F2xqM_image, F2xqM_image, F2xqM_rank, FFM_det, FFM_image, FFM_ker, FFM_rank, FFM_inv 22- ZM_rank, ZM_indexrank, ZM_indeximage 23- GP function normlp BA 24- GP function vecsum 25- [libpari] pr_equal, ZC_nfval, ZC_nfvalrem, ZC_prdvd, ZV_Z_dvd 26- allow .p / .e / .f / .gen for modpr structures 27- function rnfpolredbest 28- functions qfnorm, qfbil 29- [libpari] ZM_multosym, RgM_multosym, RgMrow_RgC_mul, RgM_transmul, RgM_transmultosym, ZM_transmultosym 30- [libpari] nf_rnfeq, nf_rnfeqsimple, eltreltoabs, eltabstorel, eltabstorel_lift, nf_nfzk, nfeltup, QXV_QXQ_eval, QXX_QXQ_eval 31- [libpari] factor_pn_1_limit 32- [libpari] get_FpXQ_star, gener_FpXQ_local BA 33- move gpinstall to libpari 34- liftall() lifts recursively all t_INTMOD/t_PADIC/t_POLMOD components 35- liftint() lifts recursively all t_INTMOD/t_PADIC components 36- liftpol() lifts recursively all t_POLMOD components BA 37- GP function logint PB 38- [libpari] gen_matmul, gen_matcolmul, FFM_mul, FqM_FqC_mul, FqM_mul, F2xqM_mul, F2xqM_F2xqC_mul, FlxqM_FlxqC_mul, FlxqM_mul. 39- [libpari] Flx_equal, F2x_equal BA 40- [libpari] FpM_powu/Flm_powu/F2m_powu 41- new GP function idealprincipalunits 42- [libpari] checkabgrp, abgrp_get_no, abgrp_get_cyc, abgrp_get_gen, bid_get_grp, bid_get_no 43- [libpari] FpX_disc 44- [libpari] retmkcomplex 45- GP function expm1 (= exp - 1, avoiding cancellation) Removed 1- optional flag to factorpadic() [ enabling Buchman-Lenstra + round2 ] Use the default = round4 2- useless wrappers map_proto_GG, map_proto_GL, map_proto_lGG 3- [libpari] useless functions gand, gor 4- [libpari] useless function ratlift [ use Fp_ratlift ] Done for version 2.6.1 (released 20/09/2013): Fixed 1- Allow compounding 1-letter flags to gp, e.g. qp -qf [ used to silently ignore the 'f' ] 2- ellminimalmodel, followed by ellchangecurve ==> structure incorrectly updated [wrong Q_MINIMALMODEL component] [2.6.0, #1416] 3- lift(1/2+O(2))=2/1 --> incorrect result + corrupt object [2.6.0, #1424] 4- local() could corrupt polynomial variable of the same name 5- write did not fclose() the output file handle [2.6.0, #1425] PB 6- issquare(Mod(1,2)) -> domain error [2.6.0, #1429] PB 7- issquare(Mod(0,2),&s); s -> Mod(2,0) error [2.6.0, #1430] 8- ellheight(E not given by minimal model,P) -> domain error [2.6.0, #1432] 9- ellchangecurve(E, [1,0,0,0]) lost Q_MINIMALMODEL ->SEGV later [2.6.0] 10- warning() would print "warning: user warning:"-> "user warning:" [2.6.0] 11- matinverseimage(A, t_MAT B) would treat individual columns B[,i] independently and successively. Now use a single Gauss reduction. 12- Flm_Fl_mul returned a wrong result 13- ellinit(ellfromj(Mod(0,17))) -> curve defined over Z [2.6.0, #1436] 14- allocatemem: make sure fix_size() is called to avoid alignment problems [#1437] 15- ellmodulareqn(2) did not clean the stack properly [2.6.0, #1442] 16- issquare(Mod(13,121)) --> not an n-th power residue in Qp_sqrt [2.6.0] 17- stack corruption in carberkowitz / charpoly(,,3) [ session crash ] 18- ellinit(E over Fp, t_FFELT) => error [2.6.0] 19- mateigen([5/3,7/45;0,21/10]) => precision error (missing eigenspace) 20- subst(O(x^2),x,0*x) => SEGV [#1447] 21- memory corruption in aprcl [2.6.0] 22- factormod(,2) => wrong result [2.6.0, #1451] 23- dirmul/dirdiv: incorrect result length when valuation > 1 24- x,y a t_PADIC, x === y always returned 0 [2.6.0] 25- bernpol(0) => memory corruption [2.6.0, #1458] 26- round((1e-40+x) / (1e-39+x)) would create the invalid object x/x 27- polgalois(x^11 + 627*x^4 - 584) -> F_110 instead of S_11 [#1460] 28- input lines with more than 2^31 characters (without \n) resulted in a truncated read [#1461] 29- znlog(1,Mod(8,9)) -> division by 0 [#1463] 30- plot(x=1,2,x) gave a graph with 0<=y<=2, instead of ymin<=y<=ymax 31- ?= or even = would apparently hang GP (waiting for further input) Added 1- genus2red: an implementation of Liu's algorithm to determine the reduction of a genus 2 curve (at p > 2). Based on genus2reduction-0.3, http://www.math.u-bordeaux1.fr/~liu/G2R/ (Cohen & Liu, 1994) mostly rewritten from scratch: - adapted to pari-2.* - somewhat modularized - fixes all known instances of 'bug27' and 'bug28' (at p = 3, reported through Sage users). - bench 'genus2red' contains a check of at least one instance of each of Namikawa-Ueno's types + all cases on which the original genus2reduction was known to fail. [CAVEAT: the interface will change] 2- allow to startup gp with flags --default key=val (or -D key=val): execute default(key,val) on startup BA 3- functions Flm_center, Flv_center, zv_to_Flv, zm_to_Flm, zm_mul, zm_zc_mul, scalar_Flm BA 4- function minim_raw 5- function QX_complex_roots PMo 6- function forpart for looping over partitions 7- [libpari] forcomposite_init / forcomposite_next, reimplement forcomposite() using this iterator 8- Configure now generates a file 'config.log' to help debugging when it makes a mistake (contains all messages from compilers) 9- [libpari] RgM_invimage, RgM_RgC_invimage, FpM_invimage, FpM_FpC_invimage, Flm_invimage, Flm_Flc_invimage, Flm_neg 10- [libpari] serchop0, integser functions 11- psi(t_SER) using Luke's recursion, then lngamma, gamma, gammah for t_SER arguments around an arbitrary complex z0 (was implemented for z0 = 0,1 only) PB 12- PARI functions FlxqM_gauss, FlxqM_inv and FqM_gauss 13- PARI functions FpM_hess, FpM_charpoly, charpoly, RgM_Rg_sub, RgM_Rg_sub_shallow 14- generic driver for GP's charpoly(): select appropriate algorith (flag) depending on input type. BA 15- allow ellsearch(t_VEC) : search for curve with given name, in given isogeny class or with given conductor; alias for the existing ellsearch(t_STR) as per the ellconvertname correspondance 16- option flag to mateigen: also return the eigenvalues 17- [libpari] Z_lvalrem_stop, u_lvalrem_stop 18- [libpari] ZX_rescale_lt BA 19- Port of the program ISOM by Bernt Souvignier for computation of automorphisms and isomorphisms of lattices. New GP functions qfauto, qfisom, qfisominit, qfautoexport 20- [libpari] RgX_mullow, RgX_sqrlow 21- [libpari] embed_T2, embednorm_T2, embed_roots, embed_disc, embed_norm 22- arithmetic functions now accept factorization matrices, you can use any of f(N), f(factor(N)) or f([N, factor(N)]) 23- GP function readstr 24- allow lists of elements in chinese() Changed 1- gp --primelimit lim (gp -p lim) is deprecated. Use the generic form 'gp -D primelimit=lim' (setting primelimit is now mostly useless, anyway) 2- gp --stacksize lim is deprecated. Use gp -s lim or the generic form 'gp -D parisize=lim' 3- partitions() interface to match forpart() 4- improve qfbred(t_QFI) for "small" inputs 5- bnfnewprec: ensure we recompute bnf from scratch at most once (could happen many times in makematal()) 6- [make bench] properly align results if 'printf' is available 7- [libpari] the *_invimage function no longer accept a t_COL second argument: use the RgM_RgC_invimage variant. They now return NULL when no solution exist (used to return a t_COL / t_MAT of length 1) 8- [libpari] replace the forvec_start() function by a standard iterator: forvec_init() / forvec_next() 9- [libpari] Z_lvalrem would destroy its argument. No longer. 10- znprimroot(p^k) now always returns the smallest primitive root (was only true for k = 1) 11- gmul / gsqr for t_SER with t_INTMOD coefficients: reduce to Z[X] + Kronecker substititution (quasi-linear vs. Karatsuba) 12- Mulders/Hanrot-Zimmerman short products for power series HC 13- new mpveceint1 implementation: faster and more precise 14- version string for development versions: added number of reachable commits (as per git rev-list). Affects version() [#1346] Removed 1- drop support for "gp -b buffersize" (obsolete since 2.2.10, 04/2005) 2- drop backward compatibility 'gp -emacs', 'gp -test'. Use the '--emacs' and '--test' forms. Done for version 2.6.0 (released 15/05/2013): Fixed 1- Euclidean chains were confused by t_POLs with t_INTMOD/t_POLMOD coeffs [ because a 0 polynomial could have lg() == 3 ] 2- numerical instability in ellheightoo [#1204] 3- Flm_gauss(m, smallish p): fix and enable the OK_ulong switch [ faster ] 4- remi2n didn't allow negative arguments [native kernel] [#1215] 5- ellrootno(e, p) started by computing a global minimal model for e instead of a local one at p. 6- qfbred(t_QFR) wrong when frac( sqrt(D) ) > 0.5 7- add GC in sumalt() 8- problems with diagnostic messages when changing a 'default', e.g. \o3 9- divru() could call bfffo(0) => overflow in expo() AMe10- (t_FRAC<0) * t_INTMOD => wrong result 11- trace(t_POL or t_SER) could yield an unormalized object [0 leading term] LGr12- off-by-1 error in primepi() when argument is = primelimit 13- bestappr(0.*x+1) -> incorrect object 14- znlog(3, Mod(3,8), 2) -> error 15- crash when default(prettyprinter,...) points to a non-existent command 16- qfperfection(): wrong result in unlucky cases [#1223] 17- allocatemem() did not reset parse error [#1226] BA 18- (x->vector(1,j,x))(1) --> significant pointers lost [#1211] VL 19- [makefile] Incorrect -I and -L flags order [#1212] 20- nfbasis / nfdisc(f,, partial factorization) would sometimes spend a lot of time trying to factorize a discriminant [#1227] 21- numerical instability in qfgaussred / qfsign [#1232] 22- missing consistency checks in conjvec [#1231] 23- numerical instability in polredabs [#1228, #1229] 24- wrong result in bezoutres [#1233] 25- wrong sign in polresultant() [#1234] 26- change default(realprecision) so that it returns the internal precision [ as precision(1.) ], not the number of printed digits. [#1235] 27- subst(Y/X,X,x) -> 0 PB 28- polrootsff(x^2-x-ffgen((v^2+1) * Mod(1,3))) -> SEGV [#1241] 29- intnum(t=[0,0],[1],(sin(t)/t)^2) -> "precision too low in mpsc1" BA 30- functions ending by the x[y]=z construct could corrupt the stack. 31- nfbasis(pol, 0, factorization containing (-1)^1) -> wrong [#1244] 32- qfminim(): better type checks for matrix entries 33- qfminim(): incorrect GC in smallvectors() 34- padicappr(x^2+1+O(3), -1+O(5^10)) --> no error 35- tests test-kernel and test-ploth were broken 36- lots of missing sanity checks in hilbert(x,y,p) [ e.g. hilbert(O(3), Pi, 5) -> 0 ] BA 37- for(i=1,10^7,) + SIGINT -> SEGV [#1249] 38- ellwp: take flag into account also for t_SER output [ was: numerical case only ] 39- factor(p) was much slower than isprime(p) for p a "small" prime BA 40- mateigen precision error was not trappable. 41- accuracy problems in bnfisunit [#1253] 42- broken rnfeltup [#1255] 43- x===y was always wrong for x,y t_SER BA 44- gamma(t_SER) with positive valuation did not work. 45- ispower(x < 0) could return an even value ! [#1259] 46- ispower(1 / n) return a wrong result [#1259] BA 47- [breakloop] initial context could be lost. BA 48- Ser([1+O(x)],x) returned an invalid object. BA 49- ispseudoprime used too much stack for huge operands. 50- [rnfidealup doc] idealgentoHNF() was incorrect. DS 51- elldivpol returned wrong result for degree n >=8. 52- overflow in mpbern(n) for huge n [#1256] 53- idealfactor(nf, non integral ideal) would remove a rational content instead of factoring A/B with A,B coprime integer ideal. Which led to costly factorizations [#1158] LGr54- the global variables associated to the primetable _maxprime / diffptr could become inconsistent 55- psdraw() ignored plot colors BA 56- stack_base() was not C89 standard compliant. BA 57- my(f(x)=x+1);f --> SEGV [#1273] 58- ellheight([0, 0, 1, -1, 0], [0., 0.]) -> BUG 59- allow bnrL1 over Q [#1279] 60- factorpadic(,,,1) => SEGV when linear factors/Q [#1278] 61- mathnf(..., 4) didn't remove 0 columns from HNF [#1271] JD 62- possible SEGV in pari_init_opts [#1264] BA 63- ellorder(E,P*Mod(1,p)) did not work if E was defined over Z 64- allow writebin to save user functions (t_CLOSURE) [#1171] 65- sqrtn(1+O(5),5) -> error, ispower(1+O(5),5) -> error [#1261] 66- parimacro.tex: pdftex --output-format dvi would produce a PDF BA 67- pari_close failed to free all allocated memory [#1297] BA 68- pari_close did not restore GMP memory functions 69- avoid outputing ANSI escape sequences to reset terminal state when unnecessary [#1289] BA 70- ellpointtoz was numerically unstable 71- issquarefree(0) => error [#1304] 72- sizebyte(t_LIST) returned the size of the wrapper type, not the list itself [#1307] 73- ellgroup(E over Q, p) now returns the structure of the group of non-singular points, when the curve has bad reduction at p. 74- factor_proven not taken into account in factor(n), where n is a BPSW-pseudoprime 75- core(5*(huge composite)^2) was very slow [#1305] 76- sqrt(0.E-97-1.12-97*I) -> div by 0 [#1309] BA 77- FpX_gcd(0,x) -> div by 0 78- x; y; p; q; subst(Mod(q,p), q, x + y) --> Mod(1, p)*x [#1321] 79- off-by-1 error when placing prime table sentinel after e.g. default(primelimit, 2); 80- t_REAL with huge exponents print incorrectly [#1322] 81- a1;a2;a3;a4;a6;ellinit([a1,a2,a3,a4,a6],1) was very slow BA 82- FpX_factorff and FpX_rootsff were not using standard argument order PB 83- printf("%.6f", 5E-5) -> SEGV [#1328] BA 84- diffop(Mod(y,x^2-y),[y],[1]) -> wrong result BA 85- calling a GP function with a lot of omitted arguments could cause a crash GH 86- missing solutions in thue(), e.g. thue(thueinit(x^3+92*x+1),3^3) 87- t_RFRAC == t_RFRAC could return a wrong result [#1339] 88- obscure bug in polroots() (sage #13314) 89- polinterpolate([1,2] * Mod(1,7), [2,3], 0) -> incorrect type in gabs BA 90- printf() did not flush output 91- logint() used too much memory and could return a wrong result: logint(3^64, 3) --> 33 92- eint1(x < 0) normalization. Now eint1(x) = incgam(0, x) [#418] 93- polrootsff(2*x+1,2,y) -> SEGV [#1350] 94- resultant(x,x,y) -> 0 and related problems 95- thue((x^4+1)^2, 4) -> no solution BA 96- idealramgroups() and idealfrobenius() did not accept a bnf 97- using new operators with default(compatible,3) caused a crash 98- rare corruption in ECM [#1240] factorint(,1) => SEGV 99- add missing call to normalize() in lift(t_POL/t_SER) [#1359] BA 100- listput was not SIGINT safe BA 101- znorder(Mod(5,16),200) -> 5 instead of 4 102- e.tate lost accuracy 103- 2-adic ellinit 104- allow ellinit over C 105- ellpointtoz(E / Qp, ...) [ wrong result / error messages ] JD 106- galoisinit(x^3+x^2-2*x-1) -> uninitialized read [#1389] BA 107- polhermite(66) -> corrupted result [#1393] 108- nfhnf() would only accept matrices of maximal rank BA 109- galoisfixedfield() could return a wrong result for polynomials with large roots [#1406] 110- bnrdisc could return a wrong result if the modulus had more than 2 prime divisors [#1399] 111- a = Mod(1,2)*x; gcd(a,a) return x instead of Mod(1,2)*x 112- changing primelimit from within forprime loop yielded unpredictable results (potential SEGV) 113- y;z;(x^2+y)*w/z/x -> significant pointers lost [#1248] 114- log(t_FRAC close to 1) => junk (idem lngamma) [#1238] 115- thue(thueinit(x^3-1493,1),3) -> error LGr116- typo in modr_safe -> precision error [#1413] 117- nfhnfmod(non-integral module) => wrong result nf=nfinit(y); A = [[1,1/2;0,1],[1,1]]; nfhnfmod(nf, A, nfdetint(nf,A)) BA 118- [native kernel] FFT mulii relied on unspecified order of evaluation Changed 1- mathnf: swapped flag 3 and 5. 2- allow ellinit([a4,a6]) [#1213] 3- ellinit(... singular curve ...]): return [] instead of raising an error 4- GP set elements are no longer converted to t_STR (requiring "eval" to recover the underlying object). Arbitrary GENs can be stored in a set. 5- moved Odos/* to relevant src/systems subdirectory 6- removed Odos directory 7- no longer allow Vec()/Vecrev(), Col(), Vecsmall(), without argument. Use [], []~, Vecsmall([]), respectively. 8- allow specifying an optional dimension in Vec/Vecrev, Col, Vecsmall. 9- allow Vecsmall(t_POL or t_SER) LGr10- nicer printout of small matrices: justify columns 11- improve gmul(t_REAL, t_FRAC) when numerator of t_FRAC is 1 BA 12- [darwin] do not use dylib_ prefix to ld options [#1210] 13- allow idealhnf(nf, t_QFI / t_QFR) for quadratic fields 14- no longer allow 3 arguments in bestappr() [useless], no longer mix Pade approximants and continued fractions [too confusing: must a t_SER be converted to a t_RFRAC or be treated coefficientwise?] 15- if znlog() has no solution, return [] instead of error 16- znlog(x, g): no longer assume that g is a primitive root, nor that the underlying (Z/N)^* is cyclic 17- renamed gen_eltorder -> gen_order 18- logfile: strip properly color escape sequences [#1225] 19- change nfbasis(T, flag, fa) to nfbasis(T, listP). flag was used to invoke round2 instead of round4 (inefficient=> useless) OR to only partially factor poldisc(T), up to primelimit (very dangerous since primelimit is a global variable). Now listP describes a list of primes, and we return a basis of an order which is p-maximal at all those primes: either a vector of primes, a factorisation (as fa before) or an integer B to indicated {p <= B} (a safe and flexible version of nfbasis(T, 1)). nfdisc() was changed similarly. 20- first call isanypower() in BPSP_psp_nosmalldiv() when input is > 2^512 [ < 1% of required time, 1 order of magnitude faster when it succeeds ] [ #1074 ] 21- sort polroots() output so that it no longer depends on current precision 22- delete README-subversion, replace with README-git 23- move README.os2 to src/system/os2/README 24- change compiler version printout in gp header 25- much faster final divisibility test in nfgcd() [#1214] 26- error type sqrter5 "not a quadratic residue in sqrt" now generalized to denote "not an n-th power residue in sqrtn" BA 27- global_err_data is now a GEN. BA 28- more usable form of alarm(s, code): evaluate code, aborting after s seconds. Return the result or a t_ERROR object. 29- [non-Unix systems] the name of the preferences file is now "gprc.txt" (it remains ".gprc" on Unix systems) 30- also look for the preferences file in PARI's "datadir" 31- removed rootsold() code : polroots(x, 1) is no longer accepted 32- rewrite ellan using C-longs + new function anellsmall() 33- renamed all libpari error codes [ pari_err() arguments ] 34- allow t_VECSMALL in vecextract 35- look for a few more short vectors in polred(), only return subfields and the best primitive polynomial [wrt discriminant] 36- [library] remove precdl argument in ellwp0: use a t_SER argument like in all other transcendental functions. 37- ellsigma / ellzeta: allow t_SER arguments, like ellwp. 38- polcoeff(x+2*y,1,y) -> 2 [ was 2*x^0 ] 39- quadhilbert / quadray: replace final polredabs call by polredbest [#1025] 40- listsort() now uses the cmp() comparison function, and becomes fully compatible with setsearch() [#1167] 41- vecsort(,,2) [lexicographic order] is now always on. The flag is now deprecated and ignored. 42- allow t_SER with integral coefficients to use asymptotically fast (ZX_mul / ZX_sqr) polynomial multiplication LGr43- let initprimes0 use an existing prime table 44- rename stackmalloc -> stack_malloc. Add stack_calloc 45- matimagecompl() now returns a permutation (t_VECMALL) no longer a t_VEC 46- remove config/gitversion from 'make snapshot' tarball JM 47- Better implementation of ellweilpairing/elltatepairing BA 48- agm now returns the optimal AGM 49- unify make_emacs_tags / make_vi_tags => make_tags + fix problems for (exuberant-ctags)-based etags. Both tag files (emacs / vi) contain the same tags now. 50- ellglobalred(E) now also returns the conductor factorization [4th compo] 51- library functions *_incremental_CRT no longer need the product of the moduli, instead they compute it and update the running modulus. 52- factor_proven now affects all the factoring machinery, as documented, i.e also multiplicative function (moebius, sumdiv,...) 53- allow t_VECSMALL in lex() 54- nfrootsof1(K) check whether K.pol is a translate of a cyclotomic pol. [initial patch LGr, #1175] 55- format of cached Bernoulli table: now a t_VEC of t_FRAC / t_REALs. Removed bern() macro. The new data must be accessed using bernfrac / bernreal. 56- [libpari] simplify init_primepointer(n, p, &pd) interface => init_primepointer(n, &pd). Remove argument 'p', ignore the previous value of pd [ remove assumption that it pointed into a prime table ] and always set pd to a pointer into the private prime table. 57- forprime loop: no longer allow to modify the loop index ? forprime(p = 2, 10, p = []) *** at top-level: forprime(p=2,10,p=[]) *** ^--- *** prime index read-only: was changed to []. 58- faster forparii() [ for() with t_INT lower bound ] 59- forprime(p = a, b, ...) now iterates over arbitrary ranges of primes, independently of 'primelimit'. Parameter 'b' can be omitted (no upper limit). More generally primelimit is no longer a true limit to iterate over primes: all libpari functions use the forprime_t interface 60- rename ggval -> gvaluation BA 70- GP function ellpow is renamed to ellmul BA 71- rename powell->ellmul, addell->elladd, subell->ellsub 72- is_pth_power interface [ pass a forprime_t iterator ] 73- polrootsmod(, 4) is no longer accepted 74- revert to Ramanujan's formula to compute Pi [ + binary splitting ] 75- polinterpolate(,, 'x) use divide & conquer algorithm BA 76- binary(0) now return [] 77- polisirreducible() now avoids factoring in most cases HC 78- reimplement incgam() 79- allow eint1(t_COMPLEX) 80- when 'echo = 1', no longer echo commands if they were entered interactively [commands ended up printed twice] 81- unless 'echo = 1', no longer log commands entered non-interactively when 'log = 1'. '\r file' used to log the entire content of 'file'. 82- allow thue(t_POL, rhs) for thue(thueinit(t_POL, rhs)) 83- elltors now uses division polynomials by default 84- modified "Hit Return to Continue" message so that it becomes a comment when copy-pasted 85- rnf_fix_pol() takes an extra argument, the calling function's name 86- fast gerepilecopy() for leaves 87- rename leftright_pow_fold -> gen_pow_fold, leftright_pow_fold_i -> gen_pow_fold_i 88- upowuu now returns 0 on overflow 89- primes(n) no longer needs precomputed primes 90- prime(n) no longer needs precomputed primes 91- primepi(n) no longer needs precomputed primes 92- removed 3s delay when recompiling PARI after modifying a header [ Was there to avoid problems on slightly out-of-synch NFS fileserver host. Had become an annoyance on fast multicore servers, esp. when bisecting to find a broken commit. ] 93- improve Configure --tune + let tune -t/-tt/-ttt print more and more verbose messages [ old 'tune -t' corresponds to current 'tune -tt' ] 94- arithmetic functions no longer accept vector / matrix arguments [ to later allow passing factorization matrices ]: use apply() BA 95- rename RgX_check_ZXY -> RgX_check_ZXX, ZXY_max_lg -> to ZXX_max_lg 96- elleta() and elleisnum(e, 2) to use a theta series formula in O~(prec^(3/2)) instead of O~(prec^2). BA 97- zv_cmp0 renamed to zv_equal0 98- allow ellinit / Qp for arbitrary reduction type 99- ellpointtoz(E / Qp, ...), now return phi(P) [ used to return the same result for phi(P) and phi(-P) [ split multiplicative reduction ], resp. phi(P) + 1/phi(P) [ non-split reduction ] 100- ellinit(E / Qp).tate : the u component is now always a square root of u2, also in the non-split case (in which case it lives in a quadratic extension of Qp) 101- renamed library function divsum() => sumdivexpr() 102- listpop(empty list) => no-op [ was "domain error" ] 103- ellap, ellak, ellan: allow non-minimal model 104- when timer = 1, no longer print timing if the time is negligible; in particular, no timing should be printed when defining a user function or and alias. 105- The proper way to initialize an nf structure when the polynomial discriminant is hard to factor is nfinit([T, listP]), where listP specifies a list of primes (see ??nfinit). nfdisc, nfbasis, all the polred functions allow analogous arguments (see Changed-19). This is cleaner and more flexible than old flags relying on the value primelimit (e.g. nfinit([T, nfbasis(T, 1)]), now deprecated). Also, the nfinit function now sees the local specifications and can take steps to avoid problems (instead of taking for granted a basis, without knowing whether it is correct or not). The result can also be certified (nfcertify) 106- polredabs() with (deprecated) nf_PARTIALFACT flag (or new [T,listP] argument) now returns 0 if the resulting order cannot be proven to be maximal. 107- rename bezout() -> gcdext(), polresultant() -> polresultantext() 108- the prime table is now computed once and for all on startup and can no longer be increased by modifying primelimit: the dynamic forprime machinery allows fast primes up to primelimit^2 which is more than enough even with a small table. The default value of 500.000 is already larger than necessary 109- removed the mechanism allowing prime gaps larger than 255 in the prime table: as a result it now limited to 436273290, allowing fast primes up to 1.9 10^17 BA110- permtonum/numtoperm now use the standard lexicographic numbering 111- issquare(t_INTMOD), ispower(t_INTMOD): factor modulus incrementally, in case we hit a local non-residue -> early abort [#1376] 112- gphelp + OS/X : make "open" the default PDF viewer (was "acroread") 113- renamed exp_Ir -> expIr Added 1- mathnf for matrices over K[X] [#41] BA 2- GP function ellheegner BA 3- asm inline macro addllx8 for faster addition BA 4- Library function FpXQ_autpowers 5- GP default 'linewrap' 6- functions Fp_issquare, Fq_issquare. 7- GP function cmp [ universal comparison ] 8- library functions Fp_addmul, addmulii, addmulii_inplace, addmuliu, addmuliu_inplace, lincombii, mulsubii, submulii, submuliu, submuliu_inplace LGr 9- Catalan's constant [ Catalan() ] BA 10- library functions F2x_issquare/F2x_sqrt BA 11- [INSTALL] Documentation of RUNTEST 12- library function bestapprPade 13- library function gen_factored_order, Fp_factored_order 14- macros retmkvec, retmkvec2, retmkvec3, retmkvec4, retmkcol, retmkcol2, retmkmat, retmkmat2, retmkintmod, retmkpolmod retmkintmod, retmkpolmod, retconst_col, retconst_vec 15- allow Ser(t_VECSMALL) BA 16- library function gsprintf/gvsprintf BA 17- new PARI type t_ERROR (error messages) BA 18- new error trapping system and GP functions iferr,iferrname BA 19- implement lngamma(t_PADIC) LGr20- new PARI functions F2m_gauss, F2m_inv, F2m_rank, F2m_image, matid_F2m, F2m_mul, F2m_F2c_mul BA 21- GP function getenv 22- new error class e_PRIME [ pari_err() ] BA 23- low-level function int_bit 24- library function stack_strcat 25- function polredbest [ adapting a preliminary patch by BA ] BA 26- library functions Fl_invsafe, F2x_halfgcd, Flx_Flxq_eval and Flx_FlxqV_eval. BA 27- support for sparse matrix and Wiedemann algorithm 28- GP function vecsearch() [ use with vecsort() ] BA 29- library function Z_issmooth BA 30- linear sieve algorithm for Fp_log/znlog BA 31- library functions Flx_to_FlxX, F2m_to_Flm, F2c_to_Flc, and Flxq_powu 32- GP function idealnumden() LGr33- library function uprecprime() 34- library function ZM_pivots() 35- library functions nm_Z_mul, ZM_togglesign, ZM_nm_mul [ to improve Zlm_gauss ] BA 36- [breakloop] GP functions dbg_up/dbg_down (like gdb up/down) 37- library functions rootsof1_Fp, rootsof1u_Fp, rootsof1_Fl BA 38- GP functions dbg_x (like \x) and dbg_err (current error data) 39- matconcat() BA 40- library functions Flm_Fl_add, Flm_invimage, FlxY_evalx BA 41- library functions Flx_ffisom, Flx_ffintersect, Flxq_ffisom_inv BA 42- library functions Flx_is_irred, Flx_is_smooth, F2x_is_irred BA 43- accessors functions for t_CLOSURE: closure_arity,closure_codestr,closure_get_* 44- library functions ZMs_ZC_mul, ZpMs_ZpCs_solve, gen_ZpM_Dixon BA 45- [breakloop] GP function breakpoint BA 46- GP function ffnbirred BA 47- cubic sieve algorithm for Flxq_log BA 48- library functions F2x_F2xqV_eval, F2x_F2xq_eval BA 49- forqfvec() BA 50- library functions FqM_image, FqM_rank, FpXQXQ_powers, FpXQXQ_matrix_pow BA 51- ellgroup(,,1): also return the generators BA 52- library functions FpVV_to_mod, FpE_changepoint, FpE_changepointinv BA 53- GP syntax [a..b] : [a,a+1,...,b] BA 54- GP syntax [a(x)|x<-b,c(x)] : apply(a,select(c,b)) BA 55- GP syntax M[a..b,^c] : vecextract(M,"a..b","^c") BA 56- library function FpE_log 57- select(f, v, 1) for indirect selection 58- hamming() function [initial implementation CG] 59- ispowerful() function 60- polgraeffe() function 61- functions poliscyclo(), poliscycloprod(), polcyclofactors() 62- function setbinop(f,X,Y) = { f(x,y), x in X, y in Y } 63- libpari function moebiusu() 64- sumdigits() function 65- libpari functions addiu, addui, subiu, subui, uissquare 66- randomprime() function. Allow random([a,b]) (return n, a <= n <= b) 67- ispolygonal() function 68- libpari functions uissquarefree, uposisfundamental, unegisfundamental 69- istotient() function 70- implement Haible/Papanikolaou binary splitting BA 71- PARI functions FlxqX_nbroots, FpXQX_nbroots, FpXQX_nbfact. BA 72- PARI function zv_search BA 73- GP syntax: multiif if(a==1,b,a==2,c,default). BA 74- GP syntax: multi assignement: [a,b,c]=V -> a=V[1];b=V[2];c=V[3] BA 75- PARI functions gen_gener, gen_ellgroup, gen_ellgens, gen_powers BA 76- FlxqE functions family (for elliptic curves over field of small characteristic>3) BA 77- PARI functions Flxq_sqrt, FpXQ_sqrt 78- bernpol() function 79- sumformal() function BA 80- PARI functions ZX_equal1, zvV_equal, ZXV_equal, FpXX_neg, FqX_neg BA 81- FpXQE functions family (for elliptic curves over field of large characteristic) BA 82- added GP function ellcard BA 83- PARI functions FpXQ_powu, Fq_powu, FpXX_mulu, Fq_mulu, Fq_div BA 84- PARI functions FqXQ_powers, FqXQ_matrix_pow, FqX_mulu, FqX_Fq_add BA 85- PARI functions FqXY_eval, FqXY_evalx, FpXY_Fq_evaly BA 86- SEA over non-prime finite field (for char p > 1000) LGr87- Add clock_gettime timer option 88- add new error type e_DOMAIN BA 89- Add black box finite fields for generic linear algebra BA 90- PARI functions FlxqM_image, FlxqM_ker, FqM_deplin BA 91- GP function ellneg BA 92- PARI functions Fp_ellcard, FpXQ_ellcard, Flxq_ellcard LGr93- vecmax / vecmin: add optional pointer argument (to hold index of a largest/smallest entry) 94- printsep() function CG 95- isprimepower() function 96- PARI functions F2v_to_F2x, F2x_valrem, F2x_deflate, F2x_shift 97- PARI function RgV_polint BA 98- GP function digits 99- GP default 'sopath' [ rewritten from initial patch by GTo ] LGr100- allow polylog(n, t_SER) around a != 0 BA 101- PARI functions ZX_shifti, ZX_remi2n, ZXV_remi2n 102- PARI functions cxexp1, mpsincos1 BA 103- GP function ellfromj 103- GP function forcomposite 104- new error class e_PRIORITY [ pari_err() ] BA 105- Add black box algebra for Brent and Kung algorithm 106- PARI function RgM_dimensions() BA 107- PARI functions RgX_splitting(), Flx_splitting() 108- made public the CATCH / TRY interface, renamed pari_CATCH / pari_TRY PARI functions err_get_num(), err_get_compo(), pari_err_last() 109- PARI function stack_sprintf() 110- PARI function RgX_is_QX() BA 111- PARI functions retmkmat2,retmkcol2,mkmat2,mkcol2,mkcols,mkcol2s et al. BA 112- PARI functions ZXV_dotproduct(), ZXX_Z_divexact() BA 113- PARI function gen_ZpX_Newton() 114- optional argument to contfracpnqn: return all convergents up to p_n/q_n, not only the last 2 BA 115- PARI functions Flxq_autpow, F2xq_autpow BA 116- PARI functions FpX_divrem_Barrett and unconditional FpX_rem_Barrett BA 117- PARI functions F2xq_sqrt_fast, Flxq_lroot, Flxq_lroot_fast BA 118- PARI functions FlxqV_dotproduct, FlxV_red BA 119- PARI functions ZpXQ_inv, ZpXQ_invlift, ZpXQ_log 120- PARI functions absi_shallow, mpabs_shallow, absfrac_shallow, Q_abs_shallow BA 121- PARI functions FlxX_Flx_add, FlxX_Fl_mul, FlxX_Flx_mul, FlxX_neg BA 122- PARI functions Fp_ellj, FpXQ_ellj, Flxq_ellj BA 123- PARI functions FpX_mulu, Flx_mulu, ZX_mulu BA 124- PARI functions FlxqXQV_autpow, FlxqXQV_autsum BA 125- PARI functions FpXQXQV_autpow, FpXQXQV_autsum BA 126- PARI functions FpXT_red, FlxT_red, ZXT_to_FlxT, ZXT_remi2n BA 127- Support for preconditionned reduction in FpXQ/Flxq 128- PARI functions padic_to_Q, padic_to_Q_shallow, QpV_to_QV, Q_pvalrem, ZX_Zp_root, Zp_appr, Fp_muls, retmkfrac BA 129- Add safegel et al. for GP2C -C option HC 130- Function sqrtnint 131- sumdivmult() to sum multiplicative functions 132- ?? online help: allow searching labels, e.g. ??"se:priority"@ 133- PARI function ZpM_echelon, zlm_echelon 134- GP functions matqr and mathouseholder, PARI functions QR_init, QgM_QR_init, gaussred_from_QR, R_from_QR, gtomp, RgC_gtomp, RgM_gtomp 135- PARI functions trivial_fact, prime_fact 136- PARI function rfrac_to_ser 137- PARI functions padic_lindep, Xadic_lindep 138- GP function seralgdep BA 139- arm, mips and mips64 level0 inline assembly kernel 140- new error class e_COMPONENT 141- PARI functions init_primepointer_geq, init_primepointer_gt, init_primepointer_leq, init_primepointer_lt BA 142- new default strictargs for mandatory arguments 143- GP function nfcertify 144- GP function ellchangepointinv 145- optional 'variable' argument to polresultantext() 146- export part of the ifac_* interface (ifact_start, ifact_next, ifac_read, ifac_skip, ifac_isprime) 147- PARI function expIxy 148- poor man's graphic engine 'plotps' (Configure --graphic=ps) when no graphic library is available; dumps the hi-res plot to a temporary PostScript file, then opens a PostScript viewer ('open -W' by default, $GP_POSTSCRIPT_VIEWER otherwise). Works around #1354 on OS/X. PMo149- GP function lambertw / library functions mplambertW, glambertW Removed 1- dropped DOS support 2- qfrep(): bit 2 of flag is now meaningless, we now always return a t_VECSMALL 3- file language/errmsg.c and global errmessage[] array: all error messages are now part of pari_err_display()) 4- error types arither1,mattype1,notpoler (merged with typeer), matinv1 (merged with gdiver) 5- legacy lindep and PSLQ implementations [algdep/lindep with negative flags]: now use LLL in all cases. BA 6- [libpari] removed unusable functions dbg_close/dbg_release. 7- [libpari] gisfundamental, gkronecker, gbigomega, geulerphi, gissquarefree, gmoebius, gnextprime, gnumbdiv, gomega, gprecprime, gsumdiv, gdumdivk, znprimroot0 8- ellsigma: flags 3 and 4 [ inefficient algorithm using the product formula ] 9- Member function 'w' (this is technical, and no longer needed:-) 10- obsolete function weipell(). Use ellwpseries() 11- [libpari] obsolete function Polred. Use polredbest 12- old logo misc/pari.xpm, see http://pari.math.u-bordeaux1.fr/logo.html pari-2.11.2/NEW0000644000175000017500000014405013366427320011544 0ustar billbillThis file highlights some of the novelties in PARI/GP 2.x compared to 1.39.15 (last release in the 1.x series). The detailed Changelog is in CHANGES. Incompatible changes are described in COMPAT. %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.11 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [The GP language] - new iterators: forperm (over permutations), forsubset (over subsets), forfactored/fordivfactored (over integers/divisors in factored form), forsquarefree (over squarefree integers), forprimestep (over primes in arithmetic progressions). We also allow forstep(a,b, Mod(c,q), ...) - new interface for handling files: fileclose, fileextern, fileflush, fileopen fileread, filereadstr, filewrite, filewrite1. Orders of magnitude faster than read / write for small incremental I/O operations - allow \r "foo bar" to allow filenames containing spaces (quotes around file names are optional; also for \l and \w). - new function printp to print matrices in 2-D as output by gp [ existed in 2.5 with a different meaning: "pretty" format ] - default(echo, 2): print lines as is, including whitespace and comments [Multiprecision Kernel] - new function exponent() - new function log1p(x) = log(1+x) accurate near 0 - improvements to sqrtn, log, lngamma, expm1 [Numerical summation and integration] - derivnum: allow order k derivatives ? derivnum(x = 0, exp(sin(x)), 16) \\ 16-th derivative %1 = -52635599.000000000000000000000000000000 - new numerical summation functions: sumnumap / sumnumapinit (Abel-Plana), sumnumlagrange / sumnulagrangeinit (Lagrange) - new functions prodeulerrat, sumeulerrat, sumnumrat, prodnumrat for numerical summation/product of rational functions at integers or primes - intnum: allow power series as limits for the integration interval - new function laurentseries [Combinatorics] - new functions permorder (order of a permutation), permsign (signature) - binomial(n): vector of all binomial(n, k) 0 <= k <= n - new function vecprod = prod(i = 1, #v, v[i]) using product tree - new function matpermanent [Elementary Number Theory] - ECPP primality proof: primecert, primecertexport, primecertisvalid; also used by isprime() - new function divisorslenstra (divisors in residue classes) - new functions to manipulate Abelian characters * general characters: chargalois (Galois orbits), charpow (chi^n), * Dirichlet characters: znchar (convert datum to Dirichlet character) znchargauss (complex Gauss sum), zncharconductor, znchartoprimitive, znchardecompose (chi mod N = chi_Q chi_N/Q), - issquarefree / isfundamental / quaddisc: allow integers in factored form - fast chinese remainder, fast multimodular reduction (reduce integer N mod p1, ..., pk) - optional flag to 'divisors' (include factorization) [Finite fields] - new interface to handle maps between finite fields: ffmap (evaluate a map), ffinvmap (invert a map), ffcompomap (compose maps), ffextend (create a map from K to K[t]/(T)), ffembed(a,b) (create a map from k(a) to k(b)), fffrobenius (create Frobenius as a map) - parallel znlog/fflog over large prime fields and fields of characteristic <= 5 [Polynomials, Rational functions & Power series] - new interface to factorization and root finding over finite fields; extend factormod(f, D) for general finite fields: D = p prime [over Fp], D = [T,p] (over Fp[x]/(T)) D a t_FFELT (over attached Fq), or omited [over field of definition of f]. Same for polrootsmod. - new functions factormodSQF (squarefree factorization), factormodDDF (distinct degree factorization) - new function polrootsbound (sharp upper bound for complex roots) - polcoeff is deprecated and renamed polcoef: it now only applies to scalars, polynomials, series and rational functions; no longer to vector/matrices or quadratic forms (use [], or "component", or [a,b,c] = q for a binary quadratic form q). - new function serchop(s,n): cut off all terms of degree < n in series 's' - a new optional argument to denominator/content/numerator to allow better control over semantic, e.g., No arg: denominator([1/2, 1/x, 1/y]) -> 2*y*x denominator([1/2, 1/x, x/y]) -> 2*x denominator([x/2, 1/x, 1/y]) -> y*x With arg: denominator(..., 1) is 2 in all 3 cases denominator(..., x) is x in all 3 cases denominator(..., y) is y in all 3 cases [Linear Algebra] - Linear algebra over Z/NZ: matdetmod, matimagemod, matinvmod, matkermod, matsolvemod (also makes matrixqz(,-1 or- 2) an order of magnitude faster) - new modular implementation of linear algebra over Z and cyclotomic rings - asymptotically fast linear algebra over finite fields, using CUP decomposition - allow matsolve(M,b) when M is only left-invertible [Elliptic curves] - E/Qp now allowed in ellap, ellcard, ellgroup, ellissupersingular [these four now also allow models which are not p-integral], ellintegralmodel, ellpadicfrobenius, ellpadics2 (now allows curve with multiplicative reduction), elllocalred - extend support for curves over number fields: ellheight, ellrootno, ellpointtoz, E.omega, E.eta, E.area, ellgroup(E, P) (P maximal ideal), ellisomat [E without CM]. - new functions elltamagawa, ellbsd, ellpadicbsd, ellpadicregulator, ellweilcurve, ellminimaldisc, ellisotree - new functions ellratpoints and hyperellratpoints based on Michael Stoll 'ratpoints'. [Spaces of Modular Forms] New package; see ??14 and ??tutorial-mf getcache lfunmf mfDelta mfEH mfEk mfTheta mfatkin mfatkineigenvalues mfatkininit mfbasis mfbd mfbracket mfcoef mfcoefs mfconductor mfcosets mfcuspisregular mfcusps mfcuspval mfcuspwidth mfderiv mfderivE2 mfdescribe mfdim mfdiv mfeigenbasis mfeigensearch mfeisenstein mfembed mfeval mffields mffromell mffrometaquo mffromlfun mffromqf mfgaloistype mfhecke mfheckemat mfinit mfisCM mfisequal mfkohnenbasis mfkohnenbijection mfkohneneigenbasis mflinear mfmanin mfmul mfnumcusps mfparams mfperiodpol mfperiodpolbasis mfpetersson mfpow mfsearch mfshift mfshimura mfslashexpansion mfspace mfsplit mfsturm mfsymbol mfsymboleval mftaylor mftobasis mftocoset mftonew mftraceform mftwist [Modular symbols & p-adic L functions] - the package now supports level N = 1 - new functions msdim (dimension), mslattice (canonical integral structure), mspetersson (intersection product), mspolygon (hyperbolic polygon / Farey symbol attached to Gamma_0(N)) - msfromell: use a much faster modular algorithm, allow a vector of isogenous curves - allow mssplit(M) by itself, splits msnew(M) by default [Complex L-functions] - lfuncreate: allow specifying an arbitrary growth rate a(n) << n^(c + eps) [by default, assume Ramanujan-Petersson] - new functions lfuntwist (twist by Dirichlet character), lfunsympow (symmetric power) - allow zeta(power series) - new function zetahurwitz (complex or p-adic inputs) - new function zetamultall (all MZV of bounded weight), zetamultinit, zetamultconvert [Number Fields] - new functions nfeltembed (complex embeddings), nfeltsign (signs of real embeddings), nfpolsturm (number of real roots of s(T) for T in K[X] and s a real embedding of K), bestapprnf (algdep for a known number field), idealispower (I = J^n ?), idealredmodpower (reduce mod n-th powers) poldiscfactors (fast partial factorisation of poldisc(T)), - new functions to handle representations of galoisinit G: galoisconjclasses (conjugacy classes of G), galoischartable (character table), galoischarpoly (characteristic polynomial of representation), galoischardet (determinant). - new functions to query the GALPOL database: galoisgetgroup, galoisgetname - bnrinit(,,1) [include generators] is no longer necessary for bnrL1, bnrconductor, bnrrootnumber, bnrstark, rnfkummer, galoissubcyclo - faster nfgaloismatrix / nfgaloisapply(nf,s, ideal) - change rnfpolredabs so that it outputs a canonical polynomial. As a result, the function is no longer Obsolete. - optional argument to idealfactor [limit factorization] [Associative and central simple algebras] - new functions alggroupcenter (Z(K[G])), algmakeintegral (integral multiplication table), algsplit (isomorphism between A/F_p and a matrix algebra M_d(F_p^n), where dim A = n*d^2) - new functions to handle full lattices: alglatadd, alglatcontains, alglatelement, alglathnf, alglatindex, alglatinter, alglatlefttransporter, alglatmul, alglatrighttransporter, alglatsubset [Graphics] - new functions plotexport / plothexport (support PostScript and SVG formats) The functions psdraw, psploth and psplothraw and the default 'psfile' are obsolete: use one of plotexport, plothexport or plothrawexport with format "ps" and write the result to file. - graph/plotport.c is now part of libpari - plotcolor(w, col) now allows color names (t_STR), [R,G,B] values or "#RRGGBB" hex triplet; returns the [R,G,B] value attached to c - allow plotdraw(w) for plotdraw([w,0,0]) %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.9 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% A new set of reference cards was prepared for an overview of 2.9.* GP functions, see doc/refcard*.dvi or http://pari.math.u-bordeaux.fr/doc#refcard [Systems] - Mingw64 support (Windows 64 bit) - Unify 32/64 bit random generators. Probabilistic algorithms should now behave identically on all architecture, provided they do not involve the floating point kernel [The GP language] - Support for variadic GP functions (having any number of arguments), e.g. ? f(v[..]) = sum(i = 1, #v, v[i]) ? f(1, 2, 3, 4, 5) %2 = 15 - New constant "oo" (for +/- infinity) - Simpler handling of polynomial variables: polynomial variables no longer spring into existence whenever a new identifier occurs in the parser, only if a polynomial is explicitly created; e.g. t = 0 no longer creates the "polynomial variable" t thereby messing up variable ordering. Functions varhigher() and varlower() allow to define variables of arbitrary priority independently of the session history; variables() returns the list of variables occuring in an object: ? variable(x + y*z / t) %1 = x ? variables(x + y*z / t) %2 = [x, y, z, t] - Hashtables/dictionaries in GP via functions Map, mapget, mapput, mapisdefined, mapdelete ? M = Map(); \\ empty dictionary ? mapput(M, "a", 23); \\ insert key/value: "a" maps to 23 ? mapput(M, "b", 43); \\ "b" maps to 43 ? mapget(M, "a") \\ retrieve value attached to key "a" %3 = 23 ? M = Map(["a", 23; "b", 43]); \\ fast initialization - New functions allow setting precision at the bit-level (instead of the word-level = 64 bits); new default 'realbitprecision' and \pb shortcut, and a function bitprecision() - Warn when coercing quotient rings when 'debug' is non-zero ? \g1 ? Mod(1,2)+Mod(1,3) *** _+_: Warning: coercing quotient rings; moduli 2 and 3 -> 1. - More versatile closures: function self() for recursive anonymous functions, call() to apply a function of unspecified arity to arbitrary arguments), fold() such that fold(f,v) = f(...(f(v[1], v[2]), ...,) v[#v]) - Miscellaneous new GP functions: serprec, powers, parforvec [Multiprecision Kernel] - incgam, incgamc, eint1 more reliable - new functions sinc(x) = sin(x) / x and cotanh = 1/tanh - improved p-adic log at high accuracy - improved gamma, lngamma and psi at power series arguments [Numerical sumation and integration] - rewrote numerical integration routines, which can of course directly use the new oo symbol: ? intnum(t = -oo, oo, 1/(1+t^2)) - Pi %1 = 0.E-37 - Gauss-Legendre quadrature: intnumgauss() - Rewrote numerical sumation (replace Abel-Plana by Euler-Mac Laurin). This changed the sumnum() interface ! - Monien summation: sumnummonien() - Numerical extrapolation: limitnum(), asympnum() ? limitnum(n -> (1+1/n)^n) - exp(1) %1 = 0.E-37 ? asympnum(n -> n! / (sqrt(2*Pi) * n^(n+1/2) * exp(-n))) %2 = [1, 1/12, 1/288, -139/51840, -571/2488320, 163879/209018880, 5246819/75246796800, -534703531/902961561600] - Continued fractions for numerical approximation via Pade approximants: contfracinit() and contfraceval() - Inverse Mellin transforms of Gamma products: gammamellininv() - Multiple Zeta Values: zetamult() ? zetamult([2,1]) - zeta(3) \\ Euler's identity %1 = 0.E-38 - zeta(odd integer): use Borwein's "sumalt" algorithm (10 times faster than previous at \p1000) [Elementary Number Theory] - Bounded factorization factor(n,lim) now always respects the 'lim' argument (was ignored when n fit into a long integer) - sumdigits() now allows to specify the base; new function fromdigits() - Allow ffgen([p,f]) in addition to ffgen(p^f) and ffgen(T*Mod(1,p)) - New functions for generic characters: charker, charorder, charconj, charmul, chardiv, chareval - New functions for Dirichlet characters: znconreychar, znconreyexp, znconreylog, znconreyconductor, zncharinduce, zncharisodd, znchartokronecker. See ??Dirichlet The functions idealstar / ideallog now allow omitting 'nf' argument for nf = Q allowing to handle efficiently Dirichlet characters as Hecke characters. - Miscellaneous new functions: qfbredsl2(), ispseudoprimepower(), ramanujantau() [Polynomials] - Real root finder: new function polrootsreal(T, [a,b]) - factorcantor now uses Shoup-Kaltofen algorithm (much faster) - padicfields(p, d) much faster for huge prime p [Linear Algebra] - faster matrix multiplication over Z (Strassen) and finite fields (better handling of modular kernel) - matsolve(a,b) and a^(-1) could give wrong results [or SEGV] when t_MAT 'a' was non-square - faster implementation of matfrobenius/minpoly - matkerint: replace underlying LLL algorithm by mathnf Simple bench: M=matrix(50,55,i,j,random(10^5)); \\ 200 times faster [Elliptic curves] - Twists and Isogenies: elltwist, ellisogeny, ellisogenyapply, ellxn. - Modular polynomial attached to various class invariants: polmodular(); attached class polynomials defining Hilbert class fields: polclass(). - Formal groups: ellformalw, ellformalpoint, ellformaldifferential, ellformallog, ellformalexp - Elliptic curves over finite fields: ellissupersingular(), fast ellcard() over fields of small, medium or large characteristic (SEA, Kedlaya, Satoh), ellsea() for ellcard with early abort (almost prime cardinality); elltatepairing() now reliable for self-pairings - Elliptic curves over Q: ellrootno(e, 2 or 3) for non-minimal e is now properly supported; more robust and much faster ellL1() and ellanalyticrank() (the condition ord(L_E,s=1) <= r in ellL1(E,r) is no longer necessary; r is now optional, 0 by default); p-adic heights: ellpadics2, ellpadicheight, ellpadicheightmatrix; p-adic L function: ellpadicL (see also mspadicL); Q-isogenous curves and matrix of isogeny degrees: ellisomat; minimal quadratic twist: ellminimaltwist; smallest multiple having good reduction everywhere: ellnonsingularmultiple; new optional flag to forell to loop over isogeny classes. - Elliptic curves over number fields: ellinit([a1,...,a5], nf); support elltors, ellorder, elisdivisible, elllocalred, ellminimalmodel, ellan, ellap(E,P), ellcard(E,P) for P a maximal ideal - Elliptic curves over p-adic fields: Q_2 is now properly supported, ellpointtoz(E / Qp) has been fixed and the converse ellztopoint implemented, added Mazur-Tate-Teitelbaum's L invariant to E.tate; new function ellpadiclog. [Other Curves of small genus] - Rational points on conics/Q : qfsolve, qfparam [ adapted from Denis Simon's qfsolve.gp ] - General cubic/binary quartic to Weierstrass model: ellfromeqn() - genus2red: allow rational non integral models + change input so that either genus2red(P) for y^2 = P and genus2red([P,Q]) for y^2 + x*Q = P are recognized; the output is now normalized + many bug fixes. - new functions ellpadicfrobenius, hyperellpadicfrobenius, hyperellcharpoly [Modular symbols & p-adic L functions] New package; see ??8 - Modular symbols for Gamma_0(N): msatkinlehner msfromell mshecke mspathlog mscuspidal msfromhecke msinit msqexpansion mseisenstein msgetlevel msissymbol mssplit mseval msgetsign msnew msstar msfromcusp msgetweight mspathgens - Attached overconvergent symbols, p-adic distributions and L-functions: mstooms, msomseval, mspadicL, mspadicinit, mspadicmoments, mspadicseries [Complex L-functions] New package; see ??6 and ??Ldata lfun lfundiv lfunmfspec lfunabelianrelinit lfunetaquo lfunmul lfuntheta lfunan lfunhardy lfunorderzero lfunthetainit lfuncheckfeq lfuninit lfunqf lfunzeros lfunconductor lfunlambda lfunrootres lfunartin lfuncreate [Associative and central simple algebras] New package, see the tutorial ! algabsdim algdisc algisramified algrandom algadd algdivl algissemisimple algrelmultable algalgtobasis algdivr algissimple algsimpledec algaut alghasse algissplit algsplittingdata algb alghassef algleftmultable algsplittingfield algbasis alghassei algmul algsplittingmatrix algbasistoalg algindex algmultable algsqr algcenter alginit algneg algsub algcentralproj alginv algnorm algsubalg algchar alginvbasis algpoleval algtableinit algcharpoly algisassociative algpow algtensor algdecomposition algiscommutative algprimesubalg algtrace algdegree algisdivision algquotient algtype algdim algisdivl algradical algisinv algramifiedplaces [Number Fields] - New "compositum" functions. nfcompositum(): over number fields; new binary flag to polcompositum() to assume fields are linearly disjoint; nfsplitting: equation for splitting field / Q - Class groups and units: use GRH-guaranteed bounds in bnfinit for residue estimate; made qfbclassno more reliable: correct for |D| < 2.10^10 and no known counter example; of course you can double check with quadclassunit() (rigorous under GRH but much slower up to |D| ~ 10^18 or so). - Class field theory: bnrisgalois, bnrgaloismatrix, bnrgaloisapply; faster and more reliable rnfkummer; bnrconductor(bnr, chi) as a shortcut for bnrconductor(bnr, Ker chi), same for bnrisconductor, bnrdisc and bnrclassno; bnrchar to define classes of Hecke characters, e.g. trivial on some congruence subgroup. Faster bnfcertify when the field has Q-automorphisms. New function nfislocalpower. Logarithmic class groups: new functions bnflog, bnflogdegree, bnflogef, rnfislocalcyclo. - Relative number fields: rnf structures may now contain a full absolute nf struct, attached to rnf.polabs; nfinit(rnf) returns it. This allows rnf functions to return objects in standard notation (e.g. ideals in HNF instead of as a vector of t_POLMOD generators); add optional flag to that effect in rnfeltabstorel, rnfeltdown, rnfeltup, rnfidealreltoabs, rnfinit. New functions rnfidealprimedec, rnfidealfactor. Add optional flag to nfhnf and nfsnf to return transformation matrices. - Projection to / lift from residue field: nfmodpr, nfmodprlift. (Functions nfeltdivmodpr, nfeltmulmodpr, nfeltpowmodpr, nfeltreducemodpr, nfkermodpr, nfsolvemodpr are now obsolete: use nfmodpr, work in the finite field, then lift back using nfmodprlift.) Faster idealchinese and allow sign conditions at specified real places - idealprimedec now allows an optional 3rd argument, to limit f(P/p) - Improvements in thue(), whose solutions are now canonically ordered (lexsort); support (powers of) imaginary quadratic equations. %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.7 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [Configure] - Configure --mt=pthread or --mt=mpi: GP now supports POSIX threads and MPI. See doc/parallel.dvi for an introduction, and have a look at the new parxxx GP functions. - Configure -gcov: support for gcov/lcov. As a result, the regression suite (make test-all) has been much expanded and lots of obscure bugs fixed. See http://pari.math.u-bordeaux.fr/lcov-report/ for current coverage test reports. - Configure now generates a file 'config.log' to help diagnose problems (contains all messages from compilers) [The GP language] - Ranges and slices: [a..b], x[a..b], x[^a] ? v = [2..8] %1 = [2, 3, 4, 5, 6, 7, 8] ? v[2..4] %2 = [3, 4, 5] ? v[^2] \\ remove 2nd element %3 = [2, 4, 5, 6, 7, 8] ? M = matid(3); M[1..2, ^2] \\ first two rows, remove 2nd col %4 = [1 0] [0 0] - Set notations: ? [ p | p <- primes(10), isprime(p+2) ] %1 = [3, 5, 11, 17, 29] - Multiple assignments: [a,b,c] = V, for a = V[1], b = V[2], c = V[3] ? [D,U,V] = matsnf(A, 1) \\ returns SNF and transformation matrices - Error trapping: iferr() + a new data type 't_ERROR' to represent error contexts. See ??iferr \\ Compute [B]P on a "curve over Z/NZ". If an exception occurs, \\ we found a zero divisor in Z/NZ, thereby factoring N. ECM(N, B = 1000!, nb = 100)= { for(a = 1, nb, iferr(ellmul(ellinit([a,1], N), [0,1], B), E, return(gcd(lift(component(E,2)),N)), errname(E) == "e_INV")); } ? ECM(2^101-1) %1 = 7432339208719 - Timeouts: alarm(delay, expr) spends 'delay' seconds trying to evaluate 'expr', then aborts returning a t_ERROR object. - Multi-if: to simplify successive 'else' clauses ? if (a == 1, print("1"), \ a < 0, print("negative"), \ isprime(a), print("prime"), \ print("generic")) - new function cmp() to "compare" arbitrary objects (transitive order relation, returns 0 iff x === y). Useful for sets. - new function getenv() [The GP calculator] - parallel GP support: parapply, pareval, parfor, parforprime, parselect, parsum, parvector. E.g. ? parapply(factor, [2^256 + 1, 2^193 - 1]) will factor these two integers in parallel. - forprime(p = a, b, ...) now iterates over arbitrary ranges of primes, independently of 'primelimit'. Parameter 'b' can be omitted (no upper limit). More generally, primelimit is now deprecated: libpari functions can quickly produce their own primes without relying on (enough) precomputed primes. - new iterators: forcomposite(), forpart() forqfvec(), to loop over composite integers, (possibly restricted) partitions and integer points in ellipsoids. - GP debugger, new functions expanding the 'break loop' mechanism: dbg_up(), dbg_down(), dbg_x(), breakpoint() - liftall(), liftint(), liftpol() give more flexibility than lift() in complicated situations - characteristic(x) returns the "characteristic" of the base ring over which x is defined. - ffgen(p^f), as an alias for ffgen(ffinit(p,f)) - vecsum(v), as an alias for sum(i=1,#v,v[i]) - variable() no longer raise exceptions, but returns 0 if the object has no main variable. - getabstime() returns the CPU time elapsed since gp startup, providing a reentrant version of gettime() - %#n returns the time it took to compute history result %n - new default 'linewrap' - arbitrary GP 'defaults' can now be set via the command-line: gp -D default=value gp --primelimit lim (gp -p lim) and gp --stacksize=lim are deprecated. Use the generic form (-D parisize=lim or -D primelimit=lim) [Multiprecision Kernel & Transcendental functions] - binary splitting: Catalan's constant, Pi, log(2) (to be expanded) - logint(x,b) for floor(log(x) / log(b)), avoiding rounding problems - sqrtnint(x,b) for floor(x^(1/b)) - expm1(x) for exp(x) - 1, but also accurate for x ~ 0 [Polynomial Arithmetic & Power series] - Mulders/Hanrot-Zimmerman short products for power series - Allow t_SER arguments for gamma, lngamma, and psi around arbitrary complex numbers (was either forbidden or limited to z = 0 or 1) - seralgdep: to find linear relations with polynomial coefficients ? s = 1+1/2*y+3/8*y^2-3/16*y^3+3/128*y^4+15/256*y^5-57/1024*y^6 + O(y^7); ? seralgdep(s,2,2) \\ relation of degree <= 2, degree(coeffs) <= 2 %2 = -x^2 + (y^2 + y + 1) - polgraeffe(f): returns g such that g(x^2) = f(x)f(-x) - poliscyclo(), poliscycloprod(), polcyclofactors(): cyclotomic factors of rational polynomials [Linear Algebra] - port of the program ISOM by Bernd Souvignier for computation of automorphisms and isomorphisms of lattices. New GP functions: qfauto, qfisom, qfisominit, qfautoexport - linear algebra routines now try to convert generic GP constructions involving t_INTMODs or t_FFELTs to appropriate (faster, more memory efficient) representations, then call routines in the libpari modular kernel (FpM, Flm, F2m, FqM, FlxqM, F2xqM). - add optional flag to mateigen to also return the eigenvalues - charpoly() now selects an appropriate algorithm by itself, depending on the input. Using a flag should no longer be necessary and is deprecated. - mathnf for matrices over K[X] - mathnfmodid(x,D), where D = [d1,...,dn] compute the HNF of concat(x,matdiagonal(D)); in a more efficient way - matqr() to compute the QR-decomposition of a real square matrix; mathouseholder() to apply a sequence of Householder transforms - internal support for sparse matrices and Wiedemann algorithm; currently only used by the discrete log algorithms. - matinverseimage(A, t_MAT B) would treat individual columns B[,i] independently and successively. Now use a single Gauss reduction. - normlp(): true L^p norm [ N.B. the old norml2() is still available, and returns the *square* of the L^2 norm ]. - clean generalizations of current norml2: qfnorm(), qfbil() [Elementary Number Theory] - arithmetic functions now accept factorization matrices as input, you can use any of f(N), f(factor(N)) or f([N, factor(N)]). - arithmetic functions no longer apply componentwise to vector / matrix arguments [ to allow passing factorization matrices ]: use apply() - new convenience functions: hamming(), ispowerful(), digits() / sumdigits(), ispolygonal(), istotient(), isprimepower() - randomprime(), random([a,b]) - Bernoulli polynomials: bernpol() and sumformal() ? sumformal(n^2) \\ F such that F(b) = \sum_{n <= b} n^2 %1 = 1/3*n^3 + 1/2*n^2 + 1/6*n - sumdivmult: to sum multiplicative expressions - sieve algorithms for znlog() and fflog(), computing discrete logs in F_q^* [Elliptic curves & Arithmetic geometry] - new dynamic implementation of the 'ell' data structure: ellinit is now used to record the coefficients of the curve and the domain over which it is defined. Further data is added to the structure on demand, if and when it is needed, e.g. cardinality and group structure. See ??ellinit. - elliptic curves functions no longer assume that a curve over Q is given by a minimal model. A non-miminal model used to silently produce wrong answers; no longer! - allow ellinit(E / Qp) for arbitrary p (also p = 2) and reduction type (no longer restricted to Tate curves) - allow ellinit(E / Fq) for non-prime finite fields, incl. point counting (SEA, Harley) - allow ellinit(E / C) - new function ellheegner() to find a non-torsion rational point on E / Q of rank 1. - new implementation of ellweilpairing / elltatepairing - ellsearch now accepts both syntaxes allowed by ellconvertname(), e.g. "11a3" / "11a" and [11,0,3] / [11,0] - extend ellinit inputs: ellinit([a4, a6]). On singular curve, return [] instead of raising an error. New function ellfromj(). - genus2red: an implementation of Liu's algorithm to determine the reduction of a genus 2 curve (at p > 2). Based on genus2reduction-0.3, http://www.math.u-bordeaux.fr/~liu/G2R/ (Cohen & Liu, 1994) mostly rewritten from scratch, and fixing known problems in the original implementation (so-called bug27, bug28). The regression bench contains a check of at least one instance of each of Namikawa-Ueno's types + all cases on which the original genus2reduction was known to fail. CAVEAT: the interface will probably change & reduction at p = 2 not handled [Number Fields] - maximal orders (when the discriminant is hard to factor): allow to specify a list of primes at which the order nf.zk must be maximal. This [T, listP] format supersedes the old addprimes() hack as well as rigid optional flags for nfbasis, nfdisc, polredabs. (And no longer depends on the global 'primelimit'...) See ??nfinit ? T = polcompositum(x^5 - 101, polcyclo(7))[1]; ? nf = nfinit( [T, 10^3] ); ? nfcertify(nf) %3 = [] A priori, nf.zk defines an order which is known to be maximal at all p <= 10^3. The final certification step proves it is in fact globally maximal. - polredbest / rnfpolredbest: "best-effort" variants of polredabs / rnfpolredabs. Not canonical but often smaller, and run in poly-time ! - idealprincipalunits: structure of the multiplicative group (1 + pr) / (1 + pr^k), for a prime ideal pr [ special case of idealstar, faster ] [COMPATIBILITY WARNING] - lift(x,'v) / centerlift(x,'v) now only lift t_POLMODs in variable v, no longer (most) t_INTMOD / t_PADICs met along the way - rnf.pol (absolute defining polynomial / Q) has been renamed rnf.polabs. rnf.pol is now the relative polynomial, defining the relative extension over the base. - as a side effect of the new %#n construction, all GP results are now stored as history entries, including the "void" object returned by functions such as print() or for(). - renamed bezout() -> gcdext() - renamed ellpow() -> ellmul() %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.5 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [Libpari Build & Configuration] - 'Configure --tune' fine-tunes gp and the PARI library for a given host. On some machines this leads to noticeable performance improvements, esp. when using the GMP multiprecision kernel. - 'Configure --enable-tls' makes libpari thread-safe, for multi-threaded applications. See Appendix B in the "User's Guide to the PARI Library" [Multiprecision Kernel] - The GMP library is now used by default if Configure can find it. - Schoenhage-Strassen big integers multiplication to native kernel (very useful if GMP not available) [Polynomial Arithmetic] - faster multiplication of integer polynomials (Kronecker's trick) - subquadratic gcd over prime finite fields - special polynomials (polcyclo, polchebyshev, pollegendre...) are orders of magnitude faster ( polcyclo(10^6): 1min 30s (2.3) -> 4ms (2.5) ) and directly allow evaluation at a given point, e.g. polcyclo(n, 2) for Phi_n(2). - issquare(t_POL) now works reliably over prime finite fields ( we used to have issquare(Mod(1,2)*(x^2+1)) -> 0, or error messages in more complicated cases ). - charpoly no longer assumes that the characteristic is 0 or large enough (Berkowitz division-free algorithm). [Linear Algebra] - all LLL variants use an implementation of NGuyen & Stehle's L^2 algorithm : stabler, much faster - better resultants [Elliptic curves] - ellap() now uses the SEA algorithm (port of GP's ellsea package). - discrete logarithm [ elllog() ], group structure of E(Fp) [ ellgroup() ], - division polynomials [ elldivpol() ] - Tate and Weil pairings [ elltatepairing() / ellweilpairing() ] [Number Fields] - Class-field theoretic functions (e.g. bnfinit) no longer cheat on Bach's constant. They now use safe bounds by default, correct under GRH, and no slowdown has been observed. - bnfinit: huge improvements for fields of large degree or admitting non-trivial automorphisms (series of patches by Loic Grenie). - faster quadhilbert(D < 0) [ Hilbert class field via CM ] - Frobenius elements [ idealfrobenius() ] - ramification groups [ idealramgroups() ] [GP defaults] - new default "factor_proven" to guarantee that all integer factorizations outputs proven primes (the default is to be happy with strong pseudoprimes). - new defaults "graphcolormap" and "graphcolors" to allow arbitrary colormaps in hi-res plots. - new default 'histfile', to save your typing history in between sessions ! [GP data structures] - Lists now grow as needed, without imposing an awkward maximal length. v = List() is now sufficient to initialize an empty list, instead of v = listcreate(100) to initialize a list which wouldn't grow past 100 elements. - New GP type to handle non-prime finite fields in a reasonably efficient way. E.g: ? T = ffinit(7,5); \\ irreducible of degree 5 in F_7[x] ? t = ffgen(T); \\ The element x mod (T,p) in Fp[x] / (T) ~ F_{7^5} %2 = x \\ this has type t_FFELT ? t^10 \\ handled like Mod(x, T) but faster, and less cumbersome %3 = 5*x^4 + 5*x^2 + 5*x + 6 ? fforder(t) %4 = 5602 \\ multiplicative order ? g = ffprimroot(t); \\ primitive element ? fflog(g^1000,g) %6 = 1000 - In GP-2.3, it was not possible to use the same identifier for variables and functions; in GP-2.5 there is nothing wrong with defining f(x,y)=x^2+y^2 then setting f = 1 (thereby deleting the user function). In fact, the distinction between variables and functions has been abolished: anonymous functions (closures) may be defined and assigned to variables, e.g. the old f(x,y) = x^2+y^2 is now an alias for f = (x,y) -> x^2+y^2 [GP] - the debugger, or "break loop", is now enabled by default [ set breakloop = 0 in your gprc to disable it ], and no longer controlled by trap(). The debugger is more verbose: ? f(x) = g(x); ? g(y) = 1/y; ? f(0) *** at top-level: f(0) *** ^---- *** in function f: g(x) *** ^---- *** in function g: 1/y *** ^-- *** _/_: division by zero *** Break loop: type 'break' to go back to GP break> y 0 - all GP functions are now understood by GP2C - formatted printing : printf(), Strprintf() - alarm(n) to abort a lengthy computation after n seconds. - === "isidentical" operator, much stricter than == - The introducion of anonymous functions had a number of useful side effects; for instance, it made possible two new functions select() and apply(), as well as arbitrary comparisons in vecsort(): \\ primes in { i^2+1 : i <= 50 } ? select(x->isprime(x), vector(50,i,i^2+1)) %1 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] ? apply(x->x^2, [1,2,3,4]) %2 = [1, 4, 9, 16] \\ sorts a vector of polynomials by increasing discriminant ? vecsort( v, (x,y) -> sign(poldisc(x) - poldisc(y)) ) [Main Backward Compatibility issues] see the 'COMPAT' file in the distribution for the full list. - The main issue with existing GP scripts has to do with the scope of private variables (my vs. local), see section 2.6 in User's Manual. Indeed, variables implicitly scoped to loop or function bodies are now lexically scoped. From GP-2.5 on, in constructs like for(i = 1, 10, g()) f(i) = g() the index i is truly local to the loop/function body. It is no longer seen by the function g(), as used to be the case in GP-2.3. One can declare lexicaly-scoped variable anywhere using the construct my(x, y, z, t), possibly with initializations: my(x = 1, y = x). The old "local" keyword keeps the same semantic (dynamic scoping) and is mostly obsolete, outside of very specific situations beyond the scope of these release notes. - function calls *must* include parentheses. I.e. typing 'f()' calls the function f without arguments as expected, typing 'f' returns an anonymous function with the same definition as f; for instance, v[1] = f is valid, assigning the closure f to the first entry of vector v. - private "prime table" (addprimes) must now contain primes only: its entries are now used in all arithmetic functions - The pseudo-random number generator has been changed. The old linear congruential generator has been replaced by Brent's XORGEN, which uses a Linear Feedback Shift Register: pseudo-random sequences are much better behaved, e.g. matdet(matrix(5,5,i,j, random())) is no longer guaranteed to be divisible by 2^90 or so. There is no simple way to emulate GP-2.3 pseudo-random sequences in GP-2.5. - PariEmacs is no longer distributed with PARI/GP. The "PARI Emacs shell" is available as a separate package, to be downloaded once if at all. - | and & were accepted as aliases for || and && respectively. This construction still works in GP-2.5, but is scheduled to disappear. We strongly advise to update scripts to use the proper '||' and '&&' constructions. %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * The GP2C compiler is available at http://pari.math.u-bordeaux.fr/download.html#gp2c GP2C compiles GP scripts to the C language, easing the task of writing PARI programs. It can transparently compile them to object code and load the resulting functions in gp. Low-level gp2c-compiled scripts typically run 3 or 4 times faster. Minor hand editing (specifying types) typically gains a further factor 2. * Cremona's database of elliptic curves is available through the 'elldata' package [ to be downloaded separately ] ? E = ellinit([1,1,0,10,10]); ? id = ellidentify(E)[1] \\ [1] = discard change of variables %2 = ["69950b1", [1, 1, 0, 10, 10], [[-1, 1], [-1/4, 23/8]]] \\ gives name and generators ? E = ellinit("11a1"); E.disc %3 = -161051 ? ellsearch(11); \\ all curves of conductor 11 ? forell(E, 10,20, print(E)) \\ iterate over curves of conductor 10-20 ["11a1", [0, -1, 1, -10, -20], []] ... Kernel: * Use 'Configure --with-gmp' to replace the native multiprecision kernel by the GNU MP library (featuring asymptotically fast arithmetic). * Cleanup of all architecture specific kernels (all macroized); added support for x86_64, ppc64, hppa and hppa64, ia64, sparc64, m68k. * Faster algorithms for "transcendental" functions (divide/conquer square root, AGM for log and Pi, Newton for exp and most trigonometric functions, AGM for inverse trigonometric functions, rewrite for gamma and zeta => faster Bernoulli, Mestre's AGM for ellheight) * Faster and cleaner kernel for modular arithmetic. Try e.g. factormod/factorff or polcompositum. * Major internal cleanups: separate lgef for t_POLs is gone, zero t_SER and t_POL now handled in a uniform way, heuristic soft copies in t_INTMOD, t_POLMOD, t_PADIC are gone [ led to fatal errors in complex scripts, no performance penalty ] * The "syntax" of GP routines and operators are no longer hard-coded in the sources, but maintained in a separate database (pari.desc). This way, external tools like GP2C need not be modified when the GP language is changed. Algebraic number Theory: * Faster integral LLL (still not super fast, but getting better), and polynomial factorization routines (over finite fields [ new modular kernel ], Q or general number fields [ van Hoeij's algorithm ]) * Faster maximal order (round4 rewrite) and polredabs (esp. with flag 16: don't factor the discriminant; yields a canonical equation for a field), faster ideal arithmetic (prime decomposition, approximation, multiplication). * Faster and more reliable class-field theoretic functions quadclassunit, bnfinit, bnfisprincipal, bnrinit (and related functions, e.g. bnrconductor or bnrdisc), rnfkummer, thue (fast enumeration of small solutions, don't assume the full unit group is known). * A set of fast routines for Galois theory (galoisininit, nfgaloisconj, galoisisabelian, galoisfixedfield, galoissubfields, galoissubcyclo for abelian fields, galoisidentify to identify large Galois fields up to degree 127). 'galdata' package [ to be downloaded separately ]: polgalois is safer and orders of magnitudes faster in tough cases, output is now human readable ? polgalois(x^11-2) time = 1,759 ms. \\ used to be ~ 1 hour %1 = [110, -1, 4, "F_110(11)=11:10"] Miscellaneous: * For convenience, the manual was split in two parts: the GP user's manual and the libpari user's manual, the latter being substantially expanded. Many formerly private functions have been renamed, specified, cleaned up and documented. * Initial implementation of the APR-CL primality prover, faster compositeness tests (BPSW) * A new set of fast numerical summation and integration routine, variations on the Ooura-Mori "double exponential" method. See ??intnum Library interface to all these functions and standard iterators (e.g. forvec) * Error messages now mention the GP function where the error occured. * Input/output and convenience functions: Str(a,1,c) --> "a1c", Strexpand("~") --> "/home/a2x/belabas", substvec (parallel substitutions), substpol(expr, x^2, y), writebin (write objets in binary format for fast retrieval), readvec (load a file's content into a vector) * Support for new graphic libraries (Qt, FLTK) [ ==> hi-res plots now also available under Mac OS X and Windows ] %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * PARI/GP is now released under the GNU General Public License. * PARI now has a CVS server which is intended for PARI lovers who want the very latest bleeding edge release (see the CVS.txt file). * Argument checks have been added to prevent unpredictable results when the input is incorrect. * Errors can be trapped to avoid abort and recover computations. * extended on-line help: ?? (no arguments) opens the users'manual in xdvi, ?? tutorial / refcard opens tutorial / refcard in xdvi, ??? keyword searches for topic in the manual. * Arithmetic: much faster integer factorization with several factoring engines including Pollard Rho, SQUFOF, improved ECM, and an MPQS/PMPQS implementation derived from LiDIA's, with kind permission from the LiDIA team * Polynomials: - much faster factorization over Z[X] (van Hoeij's algorithm) or Fq[X] (more efficient modular kernel), esp. when the polynomial is defined over Fp. - Ducos' subresultant algorithm for resultants * Number field: - improved ROUND 4 for computations of integral basis/discriminant - faster polredabs / rnfpolredabs polynomial reductions functions - Galois extensions of Q: Fixed fields, Galois conjugates using Allombert's algorithm. * Class group, ray-class group: - improved bnf/bnr functions (faster, numerically stabler), in particular bnfisprincipal - computations of explicit defining equations of abelian extensions of imaginery quadratic fields (using complex multiplication) of totally real abelian extensions (using Stark units). * Elliptic functions: Weierstrass and Weber functions. * Plotting: support of gnuplot, new functions (possiblity to plot directly in a file). %%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION 2.0 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The GP/PARI structure has been cleaned up. * The whole configuration process has been automated, and a Configure file is provided. Just typing `./Configure' should see you home in most cases. * PARI is now available as a dynamic library, thanks to Louis Granboulan. (you can link GP with it, if you wish to). This saves a tremendous amount of disk space, and is generally more convenient as you don't need to re-link your files when updating the library (or when debugging. or profiling, or...). * types now have a symbolic mnemonic name (e.g t_INT for an integer, t_VEC for a vector, and so on). * General speed-up (depends on your applications, about 40% for our generic testing file). * Experimental module loading structure (the actual function tree has not yet been cut into modules, but for the GP specific functions). ========================================================================== Many new or improved functions in the PARI library. * MANY class-field related functions. In particular: - is it now possible to try and remove the GRH assumption on class group computations. - ray class groups computations (including discrete log). - explicit defining equations in simple cases (Kummer extensions of prime degree, quadratic base field). * computation of Galois groups up to degree 11 * roots is now entirely reliable, thanks to Xavier Gourdon. * some core routines have been optimized: Karatsuba fast multiplication, a specific function gsqr() for squarings,... * input/output is much more flexible now: - a function GENtostring has been added, generalizing gitoascii to any PARI object (with a simpler syntax: GENtostring(g) returns a malloc'ed string containing g as gp would print it). - readexpr has a relative freadexpr (for filtered readexpr), which enables you to use input containing whitespaces. - you can use GENs in formatted output, a la printf. * improved garbage collecting. * private variables can be created without an explicit readexpr(), using fetch_var() and delete_var(). ========================================================================== GP has been completely re-written: * lowercase/uppercase are now significant. All predefined constants (Euler, I, Pi) have been renamed (as well, the o() notation for series and padics has been superseded by O()). for (i=1,10, print(i)) will not yield an error anymore. * human-readable error messages, including a caret to indicate where a GP syntax error occurred. * function names were renamed according to a more logical scheme. The file new.dico provides a translation (available under GP using "whatnow") * You can retrieve basic information from complicated objects using member functions. For instance x.disc will yield the discriminant of x, whether it was created by nfinit (aka initalg), bnfinit (aka buchinit), ellinit (aka initell). * A `gprc' file is available to set "permanent" defaults (such as global variables, aliases, custom user functions, etc...). For instance, you can put all your scripts in some special directories, and point them out to GP using "path". See misc/gprc.dft for examples. The function "default" enables to change most defaults under gp. For instance: default(compatible, 2) will give you back the former gp function names and helpmessages. [default(compatible, 3) undoes the lowercaps/uppercaps changes as well]. Try "default". * basic C idiosyncrasies such as for instance i++ (for i=i+1), i<<1 (for left shift) or i+=j (for i=i+j) are now allowed within GP scripts. /* */ multi-line comments are understood. * lists and (primitive) string support have been added. Characters can be quoted with the usual meaning. As a result, set functions can now be used with arbitrary elements. * if your terminal supports color (variants of color_xterm for instance), you can tell GP to highlight its output in different (user configurable) colors. This is done by fiddling with the default "colors". * The familiar functions "break", "next" and "return" are now available. These should supersede the buggy label/goto provided in older versions. * Enhanced on-line help. If you have perl on your system, try ?? function-name (e.g ?? bnfinit) This is provided by external scripts which can be used independently, outside of the GP session. * If readline is installed on your system, a context-dependent completion (not yet user-programmable) is now available (try hitting here and there). Try ?? readline. * many functions now have default arguments (shown between braces {} in the on-line description). gp first reads user-supplied arguments, and then fills in the arg list with these default values. Optional args can be entirely omitted, comma included (for a function with no mandatory arguments, even parentheses are optional !). For instance: Mat = Mat() bnfclassunit(x^2+1,0) = bnfclassunit(x^2+1) bnfclassunit(x^2+1,,[0.2,0.2]) = bnfclassunit(x^2+1,0,[0.2,0.2]) The "else" part of the "if" function can be entirely omitted. if (a,1) is now correct; of course, the former syntax if (a,1,) is still valid. * functions "extern" and "system" have been added to interface with external programs (UNIX only). You can do for instance extern("myprog"), or system("ls -l *.gp"). * even better, "install" enables you to load any function provided by a dynamically linked library, and have the GP interpreter use it. This makes it easy to have your own customized version of GP with your own set of functions on startup (you can document them using "addhelp"). * On 32-bit machines, maximum number of variables has been increased from 254 to 16382. Arrays can have up to 16777214 elements (instead of 65534). In addition vector/matrix operations in GP now perform orders of magnitudes faster than in version 1.39 pari-2.11.2/misc/0000755000175000017500000000000013461316051012111 5ustar billbillpari-2.11.2/misc/tex2mail.in0000755000175000017500000021673113201017466014203 0ustar billbill#!@runtime_perl@ # Original version by Ilya Zakharevich. Minor updates by the PARI group # Features: # % at the end of a line followed by \n\n is recognized as end of # paragraph :-( # # Original change log is at bottom. # # Options: # linelength=75 # Cut at this line # maxdef=400 # definition loops: croak if many substitutions # debug=0 # by_par=0 # Expect each paragraph to be terminated # # by *exactly* 2 "\n", and do not print # # an extra "\n" between paragraphs # TeX # Assume it is not LaTeX # ragged # leave right ragged # noindent # assume \noindent everywhere # ignorefonts # make math fonts (\mathfrak etc) into NOPs # scissors # Symbol to emit when a long line is cut $@ = ''; $opt_TeX = 1; $opt_noindent = 1; $opt_ragged = 1; $opt_by_par = 1; eval ' use Getopt::Long; &GetOptions( "linelength=i" => \$opt_linelength, "maxdef=i" => \$opt_maxdef, "debug=i" => \$opt_debug, "by_par" => \$opt_by_par, "TeX" => \$opt_TeX, "ragged" => \$opt_ragged, "noindent" => \$opt_noindent, "ignorefonts" => \$opt_ignorefonts, "scissors=s" => \$opt_scissors, "noflush" => \$opt_noflush) '; if ($@ && $@ !~ /Getopt\/Long/) { warn "Errors while parsing command line options $@\n"; } $linelength= $opt_linelength || 75; $maxdef= $opt_maxdef || 10000; $debug=$opt_debug; $opt_scissors = "---8<---8<---" unless defined $opt_scissors; $notusualtoks="\\\\" . '\${}^_~&@'; $notusualtokenclass="[$notusualtoks]"; $usualtokenclass="[^$notusualtoks]"; $macro='\\\\([^a-zA-Z]|([a-zA-Z]+\s*))'; # Why \\\\? double interpretation! $active="$macro|\\\$\\\$|$notusualtokenclass"; $tokenpattern="$usualtokenclass|$active"; $multitokenpattern="$usualtokenclass+|$active"; $| = 1 unless $opt_noflush; # Format of the record: height,length,baseline,expandable-spaces,string # The string is not terminated by \n, but separated into rows by \n. # height=0 denotes expandable string # Baseline=3 means the 4th row is the baseline sub debug_print_record { local($h,$l,$b,$xs,$s) = split /,/, shift, 5; local(@arr) = split /\n/, $s; print STDERR "len=$l, h=$h, b=$b, exp_sp=$xs.\n"; local($i) = 0; for (@arr) { local($lead) = ($i++ == $b) ? 'b [' : ' ['; print STDERR "$lead$_]\n"; } while ($i < $h) { # Empty lines may skipped local($lead) = ($i++ == $b) ? 'b' : ''; print STDERR "$lead\n"; } } # Takes length and a record, returns 2 records sub cut { local($length)=(shift); local($h,$l,$b,$sp,$str)=split(/,/,shift,5); local($st1,$st2)=("",""); local($sp1,$sp2,$first,$l2)=(0,0,1,$l-$length); return (shift,&empty) if $l2<0; if ($h) { for (split(/\n/,$str,$h)) { if (!$first) { $st1 .= "\n"; $st2 .= "\n"; } else {$first=0;} $st1 .= substr($_,0,$length); $st2 .= substr($_,$length); } } else { $st1 = substr($str,0,$length); $st2 = substr($str,$length); #if ($sp && ($st1 =~ /(\S)(\s+\S*)$/)) { # $st2 = $2 . $st2; # $st1 = $` . $1; # $sp1 = ($st1 =~ /(\s)/g); # $sp2 = ($st2 =~ /(\s)/g); #} } return ("$h,$length,$b,$sp1,$st1","$h,$l2,$b,$sp2,$st2"); } # Outputs a record sub printrecord { warn "Printing $_[0]\n__ENDPRINT__\n" if $debug & $debug_record; local($h,$l,$b,$sp,$str)=split(/,/,shift,5); print $str,"\n"; } # Joins two records sub join { local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); $h1 || $h1++; $h2 || $h2++; local($h,$l,$b,$sp,$str,@str,@str2)=(0,0,0,$sp1+$sp2,""); $b = $b1 > $b2 ? $b1 : $b2; # Calculate space below baseline $h = $h1-$b1 > $h2-$b2 ? $h1-$b1 : $h2-$b2; # And height $h += $b; $l=$l1+$l2; @str="" x $h; @str[$b-$b1 .. $b-$b1+$h1-1]=split(/\n/,$str1,$h1); @str2[0..$h2-1]=split(/\n/,$str2,$h2); unless (length($str2[$b2])) { $str2[$b2] = ' ' x $l2; # Needed for length=0 "color" strings # in the baseline. } if ($debug & $debug_record && (grep(/\n/,@str) || grep(/\n/,@str2))) { warn "\\n found in \@str or \@str2"; warn "`$str1', need $h1 rows\n"; warn "`$str2', need $h2 rows\n"; } # This is may be wrong if a zero-length record with escape sequences # is appended to with something not on the same row... But # apparently, it should be OK for PARI... for (0..$h2-1) { $str[$b-$b2+$_] .= " " x ($l1 - length ($str[$b-$b2+$_])) . $str2[$_]; } return "$h,$l,$b,$sp," . join("\n",@str); } # The current line is contained in the array @out of records and, possibly, # one additional record $last. If $last exists, $islast is set to 1. # The output channel length is contained in $linelength, the accumulated # length of @out and $last is contained in $curlength. # We guaranty that if $curlength>$linelength, then @out is empty. # Gets a length of a record sub length { (warn "Wrong format of a record `$_[0]'", return 0) unless $_[0] =~ /^\d+,(\d+)/; $1; } # Gets a height of a record sub height { (warn "Wrong format of a record `$_[0]'", return 0) unless $_[0] =~ /^(\d+),/; $1; } # Sets baseline of a record, Usage s...(rec,base) sub setbaseline { (warn("Wrong format of a record `$_[0]'"), return undef) unless $_[0] =~ s/^(\d+,\d+,)(\d+)/\1$_[1]/; } # The hierarchical structure: the records to work are in the array @out. # The array @chunks keeps the beginning record of the chunks, # The array @level keeps the beginning chunks of the given level. # The last chunk can begin after the last record if this chunk is still empty. # We do not keep the inner structure of the chunk unless it is the last # chunk on the given level. # Each record is a rectangle to output to the "page". # Each chunk is a sequence of records which reflect one finished subgroup # on the given level. # Each level is a sequence of chunks which correspond to a # not-yet-finished group in TeX input. # The parallel to @level array @wait # contains an event we wait to complete the given level of array. # Chunks on a given level # Used to expand spaces sub exp_sp {$c1++;$c2=0 if $c1>$re; return " " x ($c2+$fr+1);} # Outputs the outermost level of the output list (until the start of level 1) # If gets a true argument, does not expand spaces sub print { warn "Printing...\n" if $debug & $debug_flow; local($last,$l,$exp) = ($#level? $chunks[$level[1]]-1: $#out); ($last >=0) || return; $l=&length($out[0]); if ($last >= 1) { for (1..$last) { $l += &length($out[$_]); } } if ($debug & $debug_length) { if ($l != $curlength) { for (0..$last) { warn "Wrong lengths Record $_ $out[$_]\n__ENDREC__\n" ; } } } $curlength=$l; warn "l=$l, linelength=$linelength, curlength=$curlength\n" if $debug & $debug_length; IF_L: { if (!shift && ($l=$linelength-$curlength)>=0) { warn "entered branch for long string\n" if $debug & $debug_length; $exp=0; (($out[$last] =~ s/\s+$//) && ($l+=length($&))) if $out[$last] =~ /^0,/; warn "l=$l with whitespace\n" if $debug & $debug_length; last IF_L if $l<=0; local($str,$h,$fr,$re,$c1,$c2,@t); for (0..$last) { ($str,$h)=(split(/,/,$out[$_],5))[4,0]; (@t = ($str =~ /( )/g), $exp+=@t) if (!$h); } if ($exp) { $re=$l % $exp; $fr=int(($l-$re)/$exp); warn "$l Extra spaces in $exp places, Fr=$fr," . " Remainder=$re, LL=$linelength, CL=$curlength\n" if $debug & $debug_length; $c1=0; $c2=1; for (0..$last) { ($str,$h)=(split(/,/,$out[$_],5))[4,0]; unless ($h || $opt_ragged) { $str =~ s/ /&exp_sp/ge; $out[$_]=&string2record($str); } } } } else {warn "Do not want to expand $l spaces\n" if $debug & $debug_length;} } if ($last >= 1) { for (1..$last) { $out[0] = &join($out[0],$out[$_]); } } $l=&length($out[0]); warn "LL=$linelength, CurL=$curlength, OutL=$l\n" if $debug & $debug_length; &printrecord($out[0]); $curlength=0; if ($#out>$last) { @out=@out[$last+1..$#out]; for (0..$#chunks) {$chunks[$_] -= $last+1;} } else { @out=(); } if ($#level) { splice(@chunks,1,$level[1]-2); } else { @chunks=(0); } } # Cuts prepared piece and arg into printable parts (unfinished) # Suppose that level==0 sub prepare_cut { warn "Preparing to cut $_[0]\n" if $debug & $debug_flow; warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow; (warn "\$#level non 0", return $_[0]) if ($#level!=0); local($lenadd)=(&length($_[0])); local($lenrem)=($linelength-$curlength); if ($lenadd+$curlength<=$linelength) { warn "No need to cut, extra=$lenrem\n" if $debug & $debug_flow; return $_[0]; } # Try to find a cut in the added record before $lenrem local($rec)=@_; local($h,$str,$ind,@p)=(split(/,/,$rec,5))[0,4]; local($good)=(0); if ($h<2) { while ($lenrem<$lenadd && ($ind=rindex($str," ",$lenrem))>-1) { warn "Cut found at $ind, lenrem=$lenrem\n" if $debug & $debug_flow; $good=1; # $ind=1 means we can cut 2 chars @p= &cut($ind+1,$rec); warn "After cut: @p\n" if $debug & $debug_record; push(@out,$p[0]); $curlength+=$ind+1; #if ($#out!=$chunks[$#chunks]) {push(@chunks,$#out);} &print(); $rec=$p[1]; ($lenadd,$str)=(split(/,/,$rec,5))[1,4]; $lenrem=$linelength; } return $rec if $good; } # If the added record is too long, there is no sense in cutting # things we have already, since we will cut the added record anyway... local($forcedcut); if ($lenadd > $linelength && $lenrem) { @p= &cut($lenrem,$rec); warn "After forced cut: @p\n" if $debug & $debug_record; push(@out,$p[0]); $curlength+=$lenrem; &print(); $rec=$p[1]; ($lenadd,$str)=(split(/,/,$rec,5))[1,4]; $lenrem=$linelength; } # Now try to find a cut before the added record if ($#out>=0 && !$forcedcut) { for (0..$#out) { ($h,$str)=(split(/,/,$out[$#out-$_],5))[0,4]; if ($h<2 && ($ind=rindex($str," "))>-1 && ($ind>0 || $_<$#out)) { warn "Cut found at $ind, in chunk $#out-$_\n" if $debug & $debug_flow; # split at given position @p=&cut($ind+1,$out[$#out-$_]); $out[$#out-$_]=$p[0]; @p=($p[1],@out[$#out-$_+1..$#out]); @out=@out[0..$#out-$_]; warn "\@p is !", join('!', @p), "!\n\@out is !", join('!', @out), "!\n" if $debug & $debug_flow; &print(); warn "did reach that\n" if $debug & $debug_length; @out=@p; $good=1; $curlength=0; for (@out) {$curlength+=&length($_);} last; } warn "did reach wow-this\n" if $debug & $debug_length; } warn "did reach this\n" if $debug & $debug_length; } return &prepare_cut if $good; warn "No cut found!\n" if $debug & $debug_flow; # If anything else fails use force &print(); print "$opt_scissors\n" if length($opt_scissors) && $h > 1; while (&length($rec)>$linelength) { @p=&cut($linelength,$rec); @out=($p[0]); &print(); print "$opt_scissors\n" if length($opt_scissors) && $h > 1; $rec=$p[1]; } $curlength=0; return $rec; } # Adds a record to the output list sub commit { warn "Adding $_[0]\n" if $debug & $debug_flow; warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow; local($rec)=@_; if ($#level==0) { local($len)=&length($_[0]); if ($curlength+$len>$linelength) { $rec=&prepare_cut; $len=&length($rec); } $curlength+=$len; } push(@out,$rec); if ($#out!=$chunks[$#chunks]) {push(@chunks,$#out);} warn "a:Last chunk number $#chunks, last record $#out, the first chunk\n" if $debug & $debug_flow; warn " on the last level=$#level is $level[$#level], waiting for $wait[$#level]\n" if $debug & $debug_flow; if ($#level && $wait[$#level] == $#chunks-$level[$#level]+1) { local($sub,$arg)=($action[$#level]); if ($sub eq "") {&finish($wait[$#level]);} else { &callsub($sub); } } warn "curlength=$curlength on level=$#level\n" if $debug & $debug_length; } # Calls a subroutine, possibly with arguments sub callsub { local($sub)=(shift); index($sub,";")>=0? (($sub,$arg)=split(";",$sub,2), &$sub($arg)): &$sub; } # Simulates Removing a record from the output list (unfinished) sub uncommit { warn "Deleting...\n" if $debug & $debug_flow; warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow; (warn "Nothing to uncommit", return) if $#out<0; if ($#level==0) { local($len)=&length($out[$#out]); $curlength-=$len; } local($rec); $rec=$out[$#out]; $out[$#out]=&empty(); warn "UnCommit: now $chunks[$#chunks] $rec\n__ENDREC__\n" if $debug & $debug_record; #if ($#out<$chunks[$#chunks]) {pop(@chunks);} warn "a:Last chunk number $#chunks, last record $#out, the first chunk\n" if $debug & $debug_flow; warn " on the last level=$#level is $level[$#level], waiting for $wait[$#level]" if $debug & $debug_flow; warn "curlength=$curlength on level=$#level\n" if $debug & $debug_length; return $rec; } # finish($event, $force_one_group) # Finish the inner scope with the event $event. If this scope is empty, # add an empty record. If finishing the group would bring us to toplevel # and $force_one_group is not set, can break things into chunks to improve # line-breaking. # No additional action is executed sub finish { warn "Finishing with $_[0]\n" if $debug & $debug_flow; local($event,$len,$rec)=(shift); if (($wait[$#level] ne "") && ($wait[$#level] ne $event)) { warn "Got `$event' while waiting for `$wait[$#wait]', rest=$par"; } warn "Got finishing event `$event' in the outermost block, rest=$par" unless $#level; return unless $#level; if ($#out<$chunks[$level[$#level]]) {push(@out,&empty);} # Make anything after $level[$#level] one chunk if there is anything warn "B:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; $#chunks=$level[$#level]; #if $chunks[$level[$#level]]<=$#out; local(@t); if ($#level==1 && !$_[0]) { @t=@out[$chunks[$#chunks]..$#out]; $#out=$chunks[$#chunks]-1; } # $#chunks-- if $chunks[$#chunks-1]==$chunks[$#chunks]; $#level--; $#action--; $#tokenByToken--; $#wait--; if ($#level==0 && !$_[0]) { for (@t) {&commit($_);} } warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; if ($wait[$#level] == $#chunks-$level[$#level]+1) { local($sub)=($action[$#level]); if ($sub eq "") {&finish($wait[$#level]);} else {&callsub($sub);} } } # finish level and discard it sub finish_ignore { warn "Finish_ignoring with $_[0]\n" if $debug & $debug_flow; local($event,$len)=(shift); if (($wait[$#level] ne "") && ($wait[$#level] ne $event)) { warn "Got `$event' while waiting for `$wait[$#wait]', rest=$par"; } warn "Got finishing event `$event' in the outermost block, rest=$par" unless $#level; $#out=$chunks[$level[$#level]]-1; pop(@level); pop(@tokenByToken); pop(@action); pop(@wait); } # Begin a new level with waiting for $event # Special events: If number, wait this number of chunks sub start { warn "Beginning with $_[0], $_[1]\n" if $debug & $debug_flow; warn "B:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; warn "#out=$#out, chunks[first of last level]=$chunks[$level[$#level]], chunk s[-1]=$chunks[$#chunks]" if $debug & $debug_flow; # !@chunks: may be true in \noindent{1\over2} if (!@chunks || ($chunks[$level[$#level]]<=$#out && $chunks[$#chunks]<=$#out)) { # the last level is non empty push(@chunks,$#out+1); } push(@level,$#chunks); push(@tokenByToken,0); $wait[$#level]=shift; if ($#_<0) {$action[$#level]="";} else {$action[$#level]=shift;} warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; } # Asserts that the given number of chunks exists in the last level sub assertHave { local($i,$ii)=(shift); if (($ii=$#chunks-$level[$#level]+1)<$i) { warn "Too few chunks ($ii) in inner level, expecting $i"; return 0; } return 1; } # Takes the last ARGUMENT chunks, collapse them to records sub collapse { warn "Collapsing $_[0]...\n" if $debug & $debug_flow; local($i,$ii,$_)=(shift); if (($ii=$#chunks-$level[$#level]+1)<$i) { warn "Too few chunks ($ii) in inner level, expecting $i"; $i=$ii; } if ($i>0) { for (0..$i-1) { &collapseOne($#chunks-$_); } for (1..$i-1) { $chunks[$#chunks-$_+1]=$chunks[$#chunks-$i+1]+$i-$_; } } } # Collapses all the chunks on given level sub collapseAll {&collapse($#chunks-$level[$#level]+1);} # Collapses a given chunk in the array @out. No correction of @chunks is # performed sub collapseOne { local($n)=(shift); local($out,$last,$_)=($out[$chunks[$n]]); if ($n==$#chunks) {$last=$#out;} else {$last=$chunks[$n+1]-1;} warn "Collapsing_one $n (last=$#chunks), records $chunks[$n]..$last\n" if $debug & $debug_flow; return unless $last>$chunks[$n]; warn "Collapsing chunk $n beginning at $chunks[$n], ending at $last\n" if $debug & $debug_flow; for ($chunks[$n]+1..$last) { $out=&join($out,$out[$_]); } splice(@out,$chunks[$n],$last+1-$chunks[$n],$out); # $#out-=$last-$chunks[$n]; #bug in perl? warn "Collapsed $chunks[$n]: $out[$chunks[$n]]\n__END__\n" if $debug & $debug_record; } # Return an empty record sub empty { return "0,0,0,0,"; } # Commits a record with a sum symbol sub sum { &commit("4,3,2,0," . <<'EOF'); ___ \ > /__ EOF } # Additional argument specifies if to make not-expandable, not-trimmable sub string2record { local($h,$sp)=(0); if ($_[1]) {$h=1;$sp=0;} else { $sp=($_[0] =~ /(\s)/g); $sp || ($sp=0); # Sometimes it is undef? } return "$h," . length($_[0]) . ",0,$sp,$_[0]"; } # The second argument forces the block length no matter what is the # length the string (for strings with screen escapes). sub record_forcelength { $_[0] =~ s/^(\d+),(\d+)/$1,$_[1]/; } sub finishBuffer { while ($#level>0) {&finish("");} &print(1); } # Takes two records, returns a record that concatenates them vertically # To make fraction simpler, baseline is the last line of the first record sub vStack { local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); $h1 || $h1++; $h2 || $h2++; local($h,$l,$b)=($h1+$h2, ($l1>$l2 ? $l1: $l2), $h1-1); warn "\$h1=$h1, \$h2=$h2, Vstacked: $h,$l,$b,0,$str1\n$str2\n__END__\n" if $debug & $debug_record; return "$h,$l,$b,0,$str1\n$str2"; } # Takes two records, returns a record that contains them and forms # SupSub block sub superSub { local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); $h1 || $h1++; $h2 || $h2++; local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2)); return "$h,$l,$h1,0,$str1\n\n$str2"; } # Takes two records, returns a record that contains them and forms # SupSub block sub subSuper { local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); $h1 || $h1++; $h2 || $h2++; local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2)); return "$h,$l,$h1,0,$str2\n\n$str1"; } # Takes the last two records, returns a record that contains them and forms # SupSub block sub f_subSuper { warn "Entering f_subSuper...\n" if $debug & $debug_flow; &trim(2); &collapse(2); &assertHave(2) || &finish("",1); &sup_sub(0,1); } sub sup_sub { local($p1,$p2)=($#out-shift,$#out-shift); warn "Super $p1 $out[$p1]\nSub $p2 $out[$p2]\n__END__\n" if $debug & $debug_record; local($h1,$l1,$b1,$sp1,$str1)=split(/,/,$out[$p1],5); local($h2,$l2,$b2,$sp2,$str2)=split(/,/,$out[$p2],5); if ($l1==0 && $l2==0) {return;} $h1 || $h1++; $h2 || $h2++; local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2)); $#chunks--; $#out--; if ($l1==0) { $h2++; $out[$#out]="$h2,$l,0,0,\n$str2"; } elsif ($l2==0) { $h=$h1+1; $out[$#out]="$h,$l,$h1,0,$str1\n"; } else { $out[$#out]="$h,$l,$h1,0,$str1\n\n$str2"; } warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(2,1); } # Takes the last two records, returns a record that contains them and forms # SupSub block sub f_superSub { warn "Entering f_superSub...\n" if $debug & $debug_flow; &trim(2); &collapse(2); &assertHave(2) || &finish("",1); &sup_sub(1,0); } # digest \begin{...} and similar: handles argument to a subroutine # given as argument sub f_get1 { warn "Entering f_get1...\n" if $debug & $debug_flow; (warn "Argument of f_get1 consists of 2 or more chunks", return) if $#out != $chunks[$#chunks]; local($rec,$sub); #$rec=&uncommit; $rec=$out[$#out]; $rec=~s/.*,//; $sub=shift; defined $sub ? return &$sub($rec): return $rec; } sub f_begin { warn "Entering f_begin...\n" if $debug & $debug_flow; &collapse(1); &assertHave(1) || &finish(""); local($arg,$env)=(&f_get1()); &finish_ignore(1); $arg=~s/^\s+//; $arg=~s/\s+$//; return if defined $environment_none{$arg}; if (defined ($env=$environment{$arg})) { local($b,$e)=split(/,/,$env); for (split(":",$b)) {&callsub($_);} } else {&puts("\\begin{$arg}");} } sub f_end { warn "Entering f_end...\n" if $debug & $debug_flow; &collapse(1); &assertHave(1) || &finish(""); local($arg,$env)=(&f_get1()); &finish_ignore(1); $arg=~s/^\s+//; $arg=~s/\s+$//; return if defined $environment_none{$arg}; if (defined ($env=$environment{$arg})) { local($b,$e)=split(/,/,$env,2); for (split(":",$e)) {&callsub($_);} } else {&puts("\\end{$arg}");} } sub f_newtheorem { warn "Entering f_newtheorem...\n" if $debug & $debug_flow; &trim(2); &collapse(2); &assertHave(2) || &finish("",1); warn "Name `$out[$#out-1]'\nExpansion `$out[$#out]'\n__END__\n" if $debug & $debug_record; local($name, $expand) = ($out[$#out-1], $out[$#out]); $#out -= 2; $#chunks -= 2; return unless $name =~ s/^\d+,\d+.\d+,\d+,//; return unless $expand =~ s/^\d+,\d+.\d+,\d+,//; $environment{$name}="par:unindent:puts;$expand. ,par"; &finish(2,1); } sub f_newtheorem1 { warn "Entering f_newtheorem1...\n" if $debug & $debug_flow; &trim(1); &collapse(1); &assertHave(1) || &finish("",1); warn "Name `$out[$#out]'\n__END__\n" if $debug & $debug_record; local($name) = ($out[$#out]); $#out -= 1; $#chunks -= 1; $par =~ s/^\[[^\]]*\]//; # Optional argument 2 return unless $name =~ s/^\d+,\d+.\d+,\d+,//; $last_newtheorem = $name; &finish(1,1); } sub f_newtheorem2 { warn "Entering f_newtheorem2...\n" if $debug & $debug_flow; &trim(2); &collapse(2); warn "Expansion `$out[$#out]'\n__END__\n" if $debug & $debug_record; local($expand) = ($out[$#out]); $#out -= 2; $#chunks -= 2; $par =~ s/^\[[^\]]*\]//; # Optional argument 4 return unless $expand =~ s/^\d+,\d+.\d+,\d+,//; $environment{$last_newtheorem} = "par:unindent:puts;$expand. ,par"; &finish(2,1); } sub f_literal_no_length { warn "Entering f_literal_no_length...\n" if $debug & $debug_flow; # &trim(1); &collapse(1); &assertHave(1) || &finish("",1); record_forcelength($out[$#out], 0); &finish(1,1); } sub f_discard { warn "Entering f_discard...\n" if $debug & $debug_flow; &finish_ignore($wait[$#level]); } # Takes a number and a record, returns a centered record sub center { local($len,$left)=(shift,0); warn "Entering center, ll=$len, rec=$_[0]\n__ENDREC__\n" if $debug & $debug_flow; #$_[0]; # bug in perl? local($h1,$l1,$b1,$sp1,$str1)=split(/,/,$_[0],5); $h1 || $h1++; if (($left=$len-$l1)<=0) {return $_[0];} local($LHS,$RHS); $LHS = int($left/2); $RHS = $left - $LHS; local($out,$first)=("",1); for (split(/\n/,$str1,$h1)) { if ($first) {$first=0;} else {$out .= "\n";} $out .= " " x $LHS. $_ . " " x $RHS; } return "$h1,$len,$b1,0,$out"; } # Example of radical #<<'EOF'; # +--+ #\|12 #EOF <$l2 ? $l1: $l2)); $len = $minlength if $len < $minlength; local $line = $len <= 1? "-" : ($l . ("-" x ($len - 2)) . $r); if ($flip) { $out[$#out-1]=&vStack(&vStack(¢er($len,$out[$#out]), &string2record($line)), ¢er($len,$out[$#out-1])); } else { $out[$#out-1]=&vStack(&vStack(¢er($len,$out[$#out-1]), &string2record($line)), ¢er($len,$out[$#out])); } $#chunks--; $#out--; warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(2,1); } sub f_fraction { arrow_fraction(1,"-","-"); } sub f_right_arrow { arrow_fraction(3,"-",">",1); } sub f_left_arrow { arrow_fraction(3,"<","-",1); } # Takes the last two records, returns a record that contains them and forms # fraction block sub f_overset { warn "Entering f_overset...\n" if $debug & $debug_flow; &trim(2); &collapse(2); &assertHave(2) || &finish("",1); warn "Over `$out[$#out-1]'\nBase `$out[$#out]'\n__END__\n" if $debug & $debug_record; local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out])); local($len)=(($l1>$l2 ? $l1: $l2)); local($b, $b1)=($out[$#out] =~ /^\d+,\d+,(\d+)/); ($b1)=($out[$#out-1] =~ /^(\d+)/); $b1 ||= 1; # height=0 means 1! $b += $b1; $out[$#out-1]=&vStack(¢er($len,$out[$#out-1]), ¢er($len,$out[$#out])); $#chunks--; $#out--; &setbaseline($out[$#out],$b); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(2,1); } sub f_choose { warn "Entering f_choose...\n" if $debug & $debug_flow; &trim(2); &collapse(2); &assertHave(2) || &finish("",1); warn "Numer `$out[$#out-1]'\nDenom `$out[$#out]'\n__END__\n" if $debug & $debug_record; local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out])); local($len)=(($l1>$l2 ? $l1: $l2)); $out[$#out]=&vStack(&vStack(¢er($len,$out[$#out-1]), &string2record(" " x $len)), ¢er($len,$out[$#out])); $#chunks++; $#out++; #warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; $out[$#out - 2] = &string2record("("); $out[$#out] = &string2record(")"); local($h,$b)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/)[0,1]; &makehigh($out[$#out-2],$h,$b,0,1); &makehigh($out[$#out],$h,$b,1,0); &finish(2,1); } sub f_buildrel { warn "Entering f_buildrel...\n" if $debug & $debug_flow; &trim(3); &collapse(3); &assertHave(3) || &finish("",1); warn "What: $out[$#out-2]\nOver $out[$#out]\n__END__\n" if $debug & $debug_record; local($rec)=($out[$#out-2]); $out[$#out-2]=$out[$#out]; $#chunks-=2; $#out-=2; &f_putover($rec,1); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(3,1); } # Takes two records, returns a record that contains them and forms a # fraction block sub fraction { local($l1,$l2)=(&length($_[0]),&length($_[1])); local($len)=(($l1>$l2 ? $l1: $l2)); return &vStack(&vStack(¢er($len,shift), &string2record("-" x $len)), ¢er($len,shift)); } # Commits a given string sub puts { &commit(&string2record); } # digests an eaten paragraph $ending = 0; sub end_TeX { $par = ''; $ending = 1; } sub paragraph { local($par); return 0 if $ending; $par=<>; return 0 unless defined $par; return 1 unless $par =~ /\S/; # whitespace only print "\n" if $secondtime++ && !$opt_by_par; #$par =~ s/(^|[^\\])%.*\n[ \t]*/\1/g; $par =~ s/((^|[^\\])(\\\\)*)(%.*\n[ \t]*)+/\1/g; $par =~ s/\n\s*\n/\\par /g; $par =~ s/\s+/ /g; $par =~ s/\s+$//; $par =~ s/(\$\$)\s+/\1/g; $par =~ s/\\par\s*$//; local($defcount,$piece,$pure,$type,$sub,@t,$arg)=(0); &commit("1,5,0,0, ") unless $opt_noindent || ($par =~ s/^\s*\\noindent\s*([^a-zA-Z\s]|$)/\1/); while ($tokenByToken[$#level] ? ($par =~ s/^\s*($tokenpattern)//o): ($par =~ s/^($multitokenpattern)//o)) { warn "tokenByToken=$tokenByToken[$#level], eaten=`$1'\n" if $debug & $debug_parsing; if (($piece=$1) =~ /^$usualtokenclass/o) { # plain piece &puts($piece); } else { # macro or delimiter ($pure = $piece); if ($pure =~ /^\\\s+$/) { $pure =~ s/(\\\s)\s+$/$1/; } else { $pure =~ s/\s+$//; } if (defined ($type=$type{$pure})) { if ($type eq "def") { warn "To many def expansions in a paragraph" if $defcount++==$maxdef; last if $defcount>$maxdef; @t=(0); for (1..$args{$pure}) { push(@t,&get_balanced()); } warn "Defined token `$pure' found with $args{$pure} arguments @t[1..$#t]\n" if $debug & $debug_parsing; $sub=$def{$pure}; $sub =~ s/(^|[^\\#])#(\d)/$1 . $t[$2]/ge if $args{$pure}; $par=$sub . $par; } elsif ($type eq "sub") { $sub=$contents{$pure}; index($sub,";")>=0? (($sub,$arg)=split(";",$sub,2), &$sub($pure,$arg)): &$sub($pure); } elsif ($type =~ /^sub(\d+)$/) { local($n) = $1; $sub=$contents{$pure}; if ($sub =~ s/^\[\]//) { if ($par =~ /^\[/) { $par =~ s/^\[([^\]]*)\]/{$1}/; } else { substr($par, 0, 0) = "{}"; } } &start($n,"f_$sub"); $tokenByToken[$#level]=1; } elsif ($type =~ /^get(\d+)$/) { &start($1+1); &puts($piece); $tokenByToken[$#level]=1; } elsif ($type =~ /^discard(\d+)$/) { &start($1,"f_discard"); $tokenByToken[$#level]=1; } elsif ($type eq "record") { &commit($contents{$pure}); } elsif ($type eq "self") { &puts(substr($pure,1) . ($pure =~ /^\\[a-zA-Z]/ ? " ": "")); } elsif ($type eq "par_self") { &finishBuffer; &commit("1,5,0,0, "); &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": "")); } elsif ($type eq "self_par") { &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": "")); &finishBuffer; &commit("1,5,0,0, ") unless $par =~ s/^\s*\\noindent(\s+|([^a-zA-Z\s])|$)/\2/; } elsif ($type eq "string") { &puts($contents{$pure},1); } elsif ($type eq "nothing") { } else { warn "Error with type `$type' while interpreting `$pure'"; } } else { &puts($piece); } } } warn "Unrecognized part of input `$par',\n\ttoken-by-token[$#level]=$tokenByToken[$#level]" if $par ne ""; &finishBuffer if $#out>=0; # return 0 if eof(); 1; } sub subscript { &start(1,"f_subscript"); $tokenByToken[$#level]=1; } sub superscript { &start(1,"f_superscript"); $tokenByToken[$#level]=1; } sub f_subscript { $wait[$#level]=2; $action[$#level]="f_subSuper"; if (($par !~ s/^\s*\^//) && ($par !~ s:^\s*\\begin\s*\{Sp\}:\\begin\{matrix\}:)) { &commit(&empty); } } sub f_overline { warn "Entering f_overline...\n" if $debug & $debug_flow; &trim(1); &collapse(1); &assertHave(1) || &finish("",1); warn "Overlining $out[$#out]\n__END__\n" if $debug & $debug_record; local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); $out[$#out]=&vStack(&string2record("_" x $len), $out[$#out]); $b++; #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; &setbaseline($out[$#out],$b); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(1,1); } sub f_underline { warn "Entering f_underline...\n" if $debug & $debug_flow; &trim(1); &collapse(1); &assertHave(1) || &finish("",1); warn "Underlining $out[$#out]\n__END__\n" if $debug & $debug_record; local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); $out[$#out]=&vStack($out[$#out],&string2record("_" x $len)); #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; &setbaseline($out[$#out],$b); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(1,1); } sub f_not { warn "Entering f_not...\n" if $debug & $debug_flow; &collapse(1); &assertHave(1) || &finish("",1); warn "Negating $out[$#out]\n__END__\n" if $debug & $debug_record; local($str)=(split(/,/,$out[$#out]))[4]; if ($str eq "=") { $out[$#out]=$contents{"\\neq"}; } elsif ($str =~ /^\s*\|\s*$/) { $out[$#out]=$contents{"\\nmid"}; } elsif ($out[$#out] eq $contents{"\\in"}) { $out[$#out]=$contents{"\\notin"}; } else { $out[$#out]=&join(&string2record("\\not"),$out[$#out]); } warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(1,1); } sub f_putunder { warn "Entering f_putunder...\n" if $debug & $debug_flow; &trim(1); &collapse(1); &assertHave(1) || &finish("",1); warn "Putting Under $out[$#out]\n__END__\n" if $debug & $debug_record; local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); local($l2)=(&length($_[0])); local($len)=(($l1>$l2 ? $l1: $l2)); $out[$#out]=&vStack(¢er($len,$out[$#out]),¢er($len,shift)); #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; &setbaseline($out[$#out],$b); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(1,1); } # if has additional true argument will not finish # Takes record to put over sub f_putover { warn "Entering f_putover...\n" if $debug & $debug_flow; &trim(1); &collapse(1); &assertHave(1) || &finish("",1); warn "Putting Over $out[$#out]\n__END__\n" if $debug & $debug_record; local($h,$l1,$b,$b1)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); local($l2)=(&length($_[0])); local($len)=(($l1>$l2 ? $l1: $l2)); ($b1)=($_[0] =~ /^(\d+)/); $b1 ||= 1; # height=0 means 1! $b+=$b1; $out[$#out]=&vStack(¢er($len,shift),¢er($len,$out[$#out])); #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; &setbaseline($out[$#out],$b); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(1,1) unless shift; } sub f_putpar { warn "Entering f_putpar...\n" if $debug & $debug_flow; &trim(1); local($l,$r)=split(";",shift); &collapse(1); &assertHave(1) || &finish("",1); warn "Putting Parentheses $out[$#out]\n__END__\n" if $debug & $debug_record; $out[$#out]=&join(&string2record($l), &join($out[$#out],&string2record($r))); &finish(1); } sub f_putover_string { &f_putover(&string2record); } sub f_putunder_string { &f_putunder(&string2record); } sub f_widehat { &trim(1); &collapse(1); local($l)=(&length($out[$#out])); if ($l<=1) {&f_putover(&string2record("^"));} else {&f_putover(&string2record("/" . "~" x ($l-2) . "\\"));} } sub f_widetilde { &trim(1); &collapse(1); local($l,$l1)=(&length($out[$#out])); if ($l<=1) {&f_putover(&string2record("~"));} elsif ($l<=3) {&f_putover(&string2record("/\\/"));} else {&f_putover(&string2record("/" . "~" x ($l1=int($l/2-1)) . "\\" . "_" x ($l-3-$l1) . "/"));} } sub f_underbrace { &trim(1); &collapse(1); local($l,$l1)=(&length($out[$#out])); if ($l < 5) { $l = 5 } &f_putunder(vStack(&string2record("\\" . "_" x ($l1=int($l/2-1)) . " " . "_" x ($l-3-$l1) . "/"), &string2record(" " x ($l1=int($l/2)) . "v" . " " x ($l-2-$l1)))); } sub f_underbrace2 { &trim(2); &collapse(2); local($l,$l1)=(&length($out[$#out - 1])); if ($l < 5) { $l = 5 } local($b)=($out[$#out - 1] =~ /^\d+,\d+,(\d+)/); $out[$#out-1] = &vStack(¢er($l,$out[$#out-1]), vStack(vStack(&string2record("\\" . "_" x ($l1=int($l/2-1)) . " " . "_" x ($l-3-$l1) . "/"), &string2record(" " x ($l1=int($l/2)) . "v" . " " x ($l-2-$l1))), ¢er($l,$out[$#out]))); $#chunks--; $#out--; &setbaseline($out[$#out],$b); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(2,1); } sub f_overbrace { &trim(1); &collapse(1); local($l)=(&length($out[$#out])); if ($l < 6) { $l = 6 } local($l1) = int($l/2); &f_putover(vStack(&string2record(" " . "_" x ($l1 - 2) . "/\\" . "_" x ($l-2-$l1) . " "), &string2record("/" . " " x ($l1 - 2) . " " . " " x ($l-2-$l1) . "\\"), )); } sub f_overbrace2 { &trim(2); &collapse(2); local($l)=(&length($out[$#out - 1])); if ($l < 5) { $l = 5 } local($h,$b)=($out[$#out - 1] =~ /^(\d+),\d+,(\d+)/); $h ||= 1; local($l1) = int($l/2); $out[$#out-1] = &vStack(vStack(¢er($l,$out[$#out]), vStack(&string2record(" " . "_" x ($l1 - 2) . "/\\" . "_" x ($l-2-$l1) . " "), &string2record("/" . " " x ($l1 - 2) . " " . " " x ($l-2-$l1) . "\\"))), ¢er($l,$out[$#out-1])); $#chunks--; $#out--; local($h1) = ($out[$#out] =~ /^(\d+),/); &setbaseline($out[$#out], $h1 - ($h - $b)); warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(2,1); } sub f_superscript { $wait[$#level]=2; $action[$#level]="f_superSub"; if (($par !~ s/^\s*\_//) && ($par !~ s:^\s*\\begin\s*\{Sb\}:\\begin\{matrix\}:)) { &commit(&empty); } } sub let { $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o; } sub let_exp { $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o; return if index($&,'@')>=0; local($what)=$1; $type{$what}='def'; $& =~ /($tokenpattern)$/; $def{$what}=$1; $args{$what}=0; warn "Definition of `$what' with $args{$what} args is `$def{$what}'\n" if $debug & $debug_parsing; } sub def { $par =~ s/^[^{]*//; &start(1,"f_discard"); $tokenByToken[$#level]=1; } sub def_exp { return unless $par =~ s:^(([^\\{]|\\.)*)\{:\{:; local($arg)=($1); local($def,$act)=(&get_balanced()); return unless defined $def; return if index("$arg$def",'@')>=0; return if $def =~ /\\([egx]?def|fi)([^a-zA-Z]|$)/; $def .= " " if $def =~ /($macro)$/o; &define($arg,$def); } sub def_exp_block { return unless $par =~ s:\{(\\([a-zA-Z]+|.))\}\{:\{:; local($arg)=($1); local($def,$act)=(&get_balanced()); return unless defined $def; return if index("$arg$def",'@')>=0; return if $def =~ /\\([egx]?def|fi)([^a-zA-Z]|$)/; $def .= " " if $def =~ /($macro)$/o; &define($arg,$def); } # Arguments: Token . Parameters, Expansion sub define { local($arg,$def,$act)=(shift,shift); return unless $arg =~ /^($active)/o; $act=$1; $args{$act}=$'; return unless $args{$act} =~ /^(#\d)*$/; $args{$act}=length($args{$act})/2; $def{$act}=$def; $type{$act}='def'; warn "Definition of `$act' with $args{$act} args is `$def'\n" if $debug & $debug_parsing; } sub defb { for (@_) { &define("\\$_","\\begin{$_}");&define("\\end$_","\\endTeXtoMail{$_}"); } } # Discards surrounding {} sub get_balanced { return undef unless $par =~ s/^($tokenpattern)//; return $1 unless $1 eq '{'; local($def,$lev)=('',1); while ($lev) { last unless $par =~ s/^[^\\{}]|\\.|[{}]//; $lev++ if $& eq '{'; $lev-- if $& eq '}'; $def .= $& if $lev; } (warn "Balanced text not finished!",return undef) if $lev; return $def; } sub open_curly { #&puts("{") unless $tokenByToken[$#level]; &start("}"); } # Deletes extra spaces at the end of a record sub trim_end { local($h,$str)=(split(/,/,$_[0],5))[0,4]; if (!$h) { $str =~ s/\s+$//; $_[0]=&string2record($str); warn "Trimmed End `$_[0]'\n__END__\n" if $debug & $debug_record; } } # Deletes extra spaces at the beginning of a record sub trim_beg { local($h,$str)=(split(/,/,$_[0],5))[0,4]; if (!$h) { $str =~ s/^\s+//; $_[0]=&string2record($str); warn "Trimmed Beg `$_[0]'\n__END__\n" if $debug & $debug_record; } } # Deletes extra spaces at the ends of a chunk with given number sub trim_one { &trim_beg($out[$chunks[$_[0]]]); &trim_end($_[0]==$#chunks? $out[$#out]: $out[$chunks[$_[0]+1]-1]); } # Deletes extra spaces at the ends of a given number of chunks sub trim { for ($#chunks-$_[0]+1..$#chunks) {&trim_one($_);} } sub dollar { if ($wait[$#level] eq '$') { # '; &trim_end($out[$#out]); &finish('$'); } else { &start('$'); $par =~ s/^\s+//; } } sub ddollar { if ($wait[$#level] eq '$$') { &trim_end($out[$#out]); &finish('$$'); return unless $#out>=0; $#chunks=0; $chunks[0]=0; &trim(1); &collapse(1); &printrecord(¢er($linelength,$out[0])); @level=(0); @chunks=(0); @tokenByToken=(0); @out=(); $curlength=0; # Maybe after \begin{align} } else { &finishBuffer; &start('$$'); } $par =~ s/^\s+//; } sub item { &finishBuffer; # To make unexpandable: &commit("1,11,0,0, (\@) "); } sub bbackslash { if ($wait[$#level] eq '$$') { &ddollar(); &ddollar(); } elsif ($wait[$#level] eq 'endCell') { return if $par =~ /^\s*\\end/; # Ignore the last one &finish('endCell', 1); &trim(1); &collapse(1); &finish('endRow', 1); &start('endRow'); &start('endCell'); } else { #&puts(" \\\\ "); ∥ } } sub ampersand { if ($wait[$#level] eq 'endCell') { &finish('endCell',1); &trim(1); &collapse(1); &start('endCell'); } } sub matrix { &start('endMatrix'); &start('endRow'); &start('endCell'); } sub endmatrix { &finish('endCell',1); &trim(1); &collapse(1); &finish('endRow',1); # Now chunks correspond to rows of the matrix, records inside chunks to # Cells &halign(split(";",shift)); &finish('endMatrix',1); } sub endmatrixArg { my $aspec = pop(@argStack); # Replace *{20}{c} by "c" x 20; same for omited {}. $aspec =~ s/\*(?:\{(\d+)\}|([^{]))(?:\{(.*?)\}|([^{]))/ (defined($1) ? $1 : $2) x (defined($3) ? $3 : $4) /eg; &endmatrix(join(";",($_[0],split("", $aspec)))); } # Takes a matrix in the following form: chunks on the last level # are row of the matrix, records inside chunks are cells. # Puts the resulting matrix in the first record on the given level # and truncates the rest # I'm trying to add parameters: # length to insert between columns # Array of centering options one for a column (last one repeated if needed) # Currently supported: c for center # r for right # l for left sub halign { local($explength)=(shift); local(@c)=@_; local($last,$le,$b,$h); local(@w)=(); #warn "levels @level, chunks @chunks, records @out\n"; # Find metrics of cells for $r (0..$#chunks-$level[$#level]) { $last= ($r==$#chunks-$level[$#level]) ? $#out: $chunks[$r+1+$level[$#level]]-1; warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n" if $debug & $debug_matrix; for $c (0..$last-$chunks[$r+$level[$#level]]) { ($h,$le,$b)= ($out[$chunks[$r+$level[$#level]]+$c] =~ /(\d+),(\d+),(\d+)/); # Format is Height:Length:Baseline $w[$c]=$le unless $w[$c]>$le; } } # expand the height and depth for $c (0..$#w-1) {$w[$c]+=$explength;} # Extend the @c array by the last element or "c" if it is empty @c=("c") x @w unless @c; @c=(@c,($c[$#c]) x (@w-@c)); # Now expand the cells warn "Widths of columns @w\n" if $debug & $debug_matrix; for $r (0..$#chunks-$level[$#level]) { $last= ($r==$#chunks-$level[$#level]) ? $#out: $chunks[$r+1+$level[$#level]]-1; warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n" if $debug & $debug_matrix; for $c (0..$last-$chunks[$r+$level[$#level]]) { if ($c[$c] eq "c") { warn "Centering row $r col $c to width $w[$c]\n" if $debug & $debug_matrix; $out[$chunks[$r+$level[$#level]]+$c]= ¢er($w[$c],$out[$chunks[$r+$level[$#level]]+$c]); } elsif ($c[$c] eq "l") { warn "Expanding row $r col $c to width $w[$c]\n" if $debug & $debug_matrix; $out[$chunks[$r+$level[$#level]]+$c]= &join($out[$chunks[$r+$level[$#level]]+$c], &string2record(" " x ($w[$c] - &length($out[$chunks[$r+$level[$#level]]+$c])))); } elsif ($c[$c] eq "r") { warn "Expanding row $r col $c to width $w[$c] on the left\n" if $debug & $debug_matrix; $out[$chunks[$r+$level[$#level]]+$c]= &join(&string2record(" " x ($w[$c]-$explength- &length($out[$chunks[$r+$level[$#level]]+$c]))), $out[$chunks[$r+$level[$#level]]+$c]); $out[$chunks[$r+$level[$#level]]+$c]= &join($out[$chunks[$r+$level[$#level]]+$c], &string2record(" " x $explength)); } else {warn "Unknown centering option `$c[$c]' for halign";} } } # Now we creat rows &collapseAll; # And stack them vertically for ($chunks[$level[$#level]]+1..$#out) { $out[$chunks[$level[$#level]]]=&vStack($out[$chunks[$level[$#level]]], $out[$_]); } &setbaseline($out[$chunks[$level[$#level]]], int((&height($out[$chunks[$level[$#level]]])-1)/2)); $#chunks=$level[$#level]; $#out=$chunks[$level[$#level]]; } sub close_curly { &finish("}"); #&puts("}") unless $tokenByToken[$#level]; # well, this can change under our foot... } sub at { local($c,$first,$second,$t,$m)=($par =~ /^(.)/); if ($c eq '@') {&puts('@');$par =~ s/^.//;} elsif (index("<>AV",$c)>=0) { $m="&" if ($wait[$#level] eq 'endCell'); $m="&&" if $m eq "&" && index("AV",$c)>=0; &ersand if $m eq "&"; $par =~ s/^.//; $first=$second=""; while (($t=&get_balanced()) ne $c && defined $t) { $first .= $t; } while (($t=&get_balanced()) ne $c && defined $t) { $second .= $t; } $par="{$first}{$second}$m" . $par; local($l,$r); ($l=$c) =~ tr/A>V/^/d; ($r=$c) =~ tr/",$c)>=0 ? &start(2,"f_arrow;$l;$r"): &start(2,"f_arrow_v;$l;$r"); } elsif ($c eq "." && $wait[$#level] eq 'endCell') { &ersand; &ersand; $par =~ s/^.//; } else {&puts('@');} } # takes two tips of arrow as argument separated by ";", # we assume that total length is 1 sub f_arrow { warn "Entering f_arrow...\n" if $debug & $debug_flow; local($l,$r)=split(";",shift); &trim(2); &collapse(2); &assertHave(2) || &finish("",1); warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record; local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out])); local($len)=(($l1>$l2 ? $l1: $l2)); $out[$#out-1]=&vStack(&vStack(¢er($len+4,$out[$#out-1]), &string2record(" $l" ."-" x ($len+1) . "$r ")), ¢er($len+4,$out[$#out])); $#chunks--; $#out--; warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(2,1); } # takes two tips of arrow as argument separated by ";", # we assume that total length is 1 sub f_arrow_v { warn "Entering f_arrow_v...\n" if $debug & $debug_flow; local($l,$r)=split(";",shift); &trim(2); &collapse(2); &assertHave(2) || &finish("",1); warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record; local($h1,$b1)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/); local($h2,$b2)=($out[$#out] =~ /^(\d+),\d+,(\d+)/); local($b)=(($b1>$b2 ? $b1: $b2)); local($res)=(&join($out[$#out-1],$out[$#out])); local($h,$bb)=($res =~ /^(\d+),\d+,(\d+)/); $bb=$b+1; $out[$#out-1]=&vStack(&vputs(" " x ($b-$b1+1)), $out[$#out-1]); #$out[$#out-1] =~ s/^(\d+,\d+,)(\d+)/\1$bb/; &setbaseline($out[$#out-1],$bb); $out[$#out]=&vStack(&vputs(" " x ($b-$b2+1)), $out[$#out]); #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$bb/; &setbaseline($out[$#out],$bb); $out[$#out-1]=&join(&join($out[$#out-1], &vputs($l ."|" x ($h+1) . $r,$b+1)), $out[$#out]); $#chunks--; $#out--; warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &finish(2,1); } sub noindent { if ($#out == 0 && $#chunks == 0 && $out[$#out] eq '1,5,0,0, ') { $#out--; $#chunks--; } else { &puts('\\noindent'); } } # put strings vertically, returns a record with the second argument as baseline sub vputs { local($b)=($_[1]); $b=0 unless defined $b; return length($_[0]) . ",1,$b,0," . join("\n",split('',$_[0])); } sub choose { if ($wait[$#level] eq '}') { local($prevw)=($wait[$#level-1]); $wait[$#level-1]="junk"; &finish("}",1); &collapse(1); &assertHave(1) || &finish("",1); local($rec)=$out[$#out]; $#out--; $#chunks--; &start(2,"f_choose"); $wait[$#level-1]=$prevw; &start("}"); &commit($rec); &finish("}",1); &start("}"); } else {&puts("\\choose");} } sub over { if ($wait[$#level] eq '}') { local($prevw)=($wait[$#level-1]); $wait[$#level-1]="junk"; &finish("}", 1); &collapse(1); warn "X:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &assertHave(1) || &finish("",1); warn "Y:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; local($rec)=$out[$#out]; $#out--; $#chunks--; warn "Z:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; &start(2,"f_fraction"); $wait[$#level-1]=$prevw; &start("}"); &commit($rec); &finish("}",1); &start("}"); } else {&puts("\\over");} } # Takes a record, height, baseline, spaces_toleft and _toright # and makes this record this high sub makehigh { local($str)=(split(",",$_[0],5))[4]; local($h,$b,$d)=($_[1],$_[2]+1); warn "Entering makehigh(@_)\n" if $debug & $debug_flow; if ($str eq ".") {$_[0] =~ s/\.$/ /;return;} #$str="<" if $str eq "\\langle"; #$str=">" if $str eq "\\rangle"; $h=1 unless $h; $d=$h-$b; return if $h<2 || $h==2 && index("()<>",$str)>=0; local(@c); if ($str eq "(") {@c=split(":",'(: :|:/:\:|');} elsif ($str eq ")") {@c=split(":",'): :|:\:/:|');} elsif ($str eq "{") {@c=split(":",'{: :|:/:\:<');} elsif ($str eq "}") {@c=split(":",'}: :|:\:/:>');} elsif ($str eq "|" && $str eq "||") {@c=split(":",'|:|:|:|:|:|');} elsif ($str eq "[") {@c=split(":",'[:[:|:[:[:|');} elsif ($str eq "]") {@c=split(":",']:]:|:]:]:|');} elsif ($str eq "<" || $str eq ">") { return if $h==2; local($l)=($b); $l=$d+1 if $b<$d+1; for (2..$l) { $_[0]=&join($_[0], &vputs("/" . " " x (2*$_-3) . "\\",$_-1)) if $str eq "<"; $_[0]=&join(&vputs("\\" . " " x (2*$_-3) . "/",$_-1), $_[0]) if $str eq ">"; } $_[0]=&join($_[0],&string2record(" ")) if $str eq "<"; $_[0]=&join(&string2record(" "),$_[0]) if $str eq ">"; return; } else {return;} $_[0]=&vputs(&makecompound($b,$d,@c),$b-1); $_[0]=&join($_[0],$_[0]) if length($str)==2; $_[0]=&join(&string2record(" " x $_[3]),$_[0]) if $_[3]; $_[0]=&join($_[0],&string2record(" " x $_[4])) if $_[4]; } sub f_FOOTNOTE { &finish(1); puts(">>> "); } sub footnote { puts("<<1 && $_[1]>0 && $_[4] eq $_[7]) { return $_[5] . $_[4] x ($_[0]+$_[1]-2) . $_[6]; } # No descent: if ($_[1] <= 0) {return $_[3] x ($_[0]-1) . $_[2];} # No ascent: if ($_[0] <= 1) {return $_[2] . $_[3] x $_[1];} local($mid,$asc,$des)=($_[2]); # descent == 1 $des = ($_[1]==1) ? $_[2]: $_[4] x ($_[1]-1) . $_[6]; $asc = ($_[0]==2) ? $_[2]: $_[5] . $_[4] x ($_[0]-2); $mid = $_[7] unless $_[0]==2 || $_[1]==1; return "$asc$mid$des"; } sub arg2stack {push(@argStack,&get_balanced());} sub par {&finishBuffer;&commit("1,5,0,0, ") unless $par =~ s/^\s*\\noindent\s*(\s+|([^a-zA-Z\s])|$)/\2/;} $type{"\\sum"}="record"; $contents{"\\sum"}="3,4,1,0," . <<'EOF'; \~~ > /__ EOF $type{"\\int"}="record"; $contents{"\\int"}="3,3,1,0," . <<'EOF'; ,- | -' EOF $type{"\\prod"}="record"; $contents{"\\prod"}="3,3,1,0," . <<'EOF'; ___ | | | | EOF $type{"\\Pi"}="record"; $contents{"\\Pi"}="2,3,1,0," . <<'EOF'; _ | | EOF $type{"\\Sigma"}="record"; $contents{"\\Sigma"}="3,2,1,0," . <<'EOF'; __ > ~~ EOF $type{"\\Delta"}="record"; $contents{"\\Delta"}="2,2,0,0," . <<'EOF'; /\ ~~ EOF $type{"\\nabla"}="record"; $contents{"\\nable"}="2,2,1,0," . <<'EOF'; __ \/ EOF $type{"\\oplus"}="record"; $contents{"\\oplus"}="3,5,1,0," . <<'EOF'; _ (+) ~ EOF $type{"\\otimes"}="record"; $contents{"\\otimes"}="3,5,1,0," . <<'EOF'; _ (x) ~ EOF $type{"\\ominus"}="record"; $contents{"\\ominus"}="3,5,1,0," . <<'EOF'; _ (-) ~ EOF $type{"\\odot"}="record"; $contents{"\\odot"}="3,5,1,0," . <<'EOF'; _ (.) ~ EOF $type{"\\leq"}="record"; $contents{"\\leq"}="2,3,1,0," . <<'EOF'; _ < EOF $type{"\\equiv"}="record"; $contents{"\\equiv"}="2,3,1,0," . <<'EOF'; _ = EOF $type{"\\not"}="record"; $contents{"\\not"}="2,4,1,0," . <<'EOF'; _ | EOF $type{"\\geq"}="record"; $contents{"\\geq"}="2,3,1,0," . <<'EOF'; _ > EOF $type{"\\partial"}="record"; $contents{"\\partial"}="2,1,1,0," . <<'EOF'; \ d EOF $type{"\\forall"}="record"; $contents{"\\forall"}="3,4,1,0," . <<'EOF'; \__/ \/ EOF $type{"\\exists"}="record"; $contents{"\\exists"}="3,2,1,0," . <<'EOF'; _. -| ~' EOF $type{"\\owns"}="record"; $contents{"\\owns"}="3,4,1,0," . <<'EOF'; _ -) ~ EOF $type{"\\ni"}="record"; $contents{"\\ni"}="3,4,1,0," . <<'EOF'; _ -) ~ EOF $type{"\\in"}="record"; $contents{"\\in"}="3,4,1,0," . <<'EOF'; _ (- ~ EOF $type{"\\notin"}="record"; $contents{"\\notin"}="3,5,1,0," . <<'EOF'; |_ (|- |~ EOF $type{"\\qed"}="record"; $contents{"\\qed"}="2,6,1,0," . <<'EOF'; _ |_| EOF $type{"\\Box"}="record"; $contents{"\\Box"}="2,5,1,0," . <<'EOF'; _ |_| EOF $type{"\\boxtimes"}="record"; $contents{"\\boxtimes"}="3,5,1,0," . <<'EOF'; _ |X| ~ EOF $type{"\\pm"}="record"; $contents{"\\pm"}="2,1,0,0," . <<'EOF'; + - EOF $type{"\\mp"}="record"; $contents{"\\mp"}="2,1,1,0," . <<'EOF'; _ + EOF $type{"\\cong"}="record"; $contents{"\\cong"}="2,1,0,0," . <<'EOF'; = ~ EOF $type{"\\neq"}="record"; $contents{"\\neq"}="1,5,0,0," . <<'EOF'; =/= EOF $type{"\\nmid"}="record"; $contents{"\\nmid"}="3,3,1,0," . <<'EOF'; |/ | /| EOF $type{"\\subset"}="record"; $contents{"\\subset"}="2,4,1,0," . <<'EOF'; _ (_ EOF $type{"\\subseteq"}="record"; $contents{"\\subseteq"}="3,4,1,0," . <<'EOF'; _ (_ ~ EOF $type{"\\supseteq"}="record"; $contents{"\\subseteq"}="3,4,1,0," . <<'EOF'; _ _) ~ EOF $type{"\\supset"}="record"; $contents{"\\supset"}="2,4,1,0," . <<'EOF'; _ _) EOF $type{"\\sqrt"}="sub1"; $contents{"\\sqrt"}="radical"; $type{"\\buildrel"}="sub3"; $contents{"\\buildrel"}="buildrel"; $type{"\\frac"}="sub2"; $contents{"\\frac"}="fraction"; $type{"\\xrightarrow"}="sub2"; $contents{"\\xrightarrow"}="[]right_arrow"; $type{"\\xleftarrow"}="sub2"; $contents{"\\xleftarrow"}="[]left_arrow"; $type{"\\overset"}="sub2"; $contents{"\\overset"}="overset"; $type{"\\LITERALnoLENGTH"}="sub1"; $contents{"\\LITERALnoLENGTH"}="literal_no_length"; for ("text","operatorname","operatornamewithlimits","relax","-", "notag","!","/","protect","mathcal","Bbb","bf","it","em","boldsymbol", "cal","Cal","goth","ref","maketitle","expandafter","csname","endcsname", "makeatletter","makeatother","topmatter","endtopmatter","rm", "tt", "NoBlackBoxes","document","TagsOnRight","bold","dsize","roster", "endroster","endkey","endRefs","enddocument","displaystyle", "twelverm","tenrm","twelvefm","tenfm","hbox","mbox", "url", "tableofcontents", "bigl", "bigr", "biggl", "biggr", "footnotesize", "nonumber", "tiny", "sc", "huge", "limits", ) { $type{"\\$_"}="nothing"; } if ($opt_ignorefonts) { for ("mathbb", "mathit", "mathbit", "mathfrak", "frak", "mathbf", ) { $type{"\\$_"}="nothing"; } } for ("par","endtitle","endauthor","endaffil","endaddress","endemail","enddate", "endhead","key","medskip","smallskip","bigskip","newpage", "vfill","eject") { $type{"\\$_"}="sub"; $contents{"\\$_"}="par"; } for ("proclaim","demo",) { $type{"\\$_"}="par_self"; } for ("endproclaim","enddemo",) { $type{"\\$_"}="self_par"; } $type{"\\today"}="sub"; $contents{"\\today"}="today"; #$type{"&"}="nothing"; $type{"\\let"}="sub"; $contents{"\\let"}="let_exp"; $type{"\\def"}="sub"; $contents{"\\def"}="def_exp"; $type{"\\newcommand"}="sub"; $contents{"\\newcommand"}="def_exp_block"; $type{"\\item"}="sub"; $contents{"\\item"}="item"; $type{"{"}="sub"; $contents{"{"}="open_curly"; $type{"}"}="sub"; $contents{"}"}="close_curly"; $type{"&"}="sub"; $contents{"&"}="ampersand"; $type{'$'}="sub"; $contents{'$'}="dollar"; $type{'$$'}="sub"; $contents{'$$'}="ddollar"; $type{'\\\\'}="sub"; $contents{'\\\\'}="bbackslash"; $type{"^"}="sub1"; $contents{"^"}="superscript"; $type{"_"}="sub1"; $contents{"_"}="subscript"; $type{"@"}="sub"; $contents{"@"}="at"; $type{"\\over"}="sub"; $contents{"\\over"}="over"; $type{"\\choose"}="sub"; $contents{"\\choose"}="choose"; $type{"\\noindent"}="sub"; $contents{"\\noindent"}="noindent"; $type{"\\left"}="sub"; $contents{"\\left"}="left"; $type{"\\right"}="sub"; $contents{"\\right"}="right"; $type{'\footnote'}="sub"; $contents{'\footnote'}="footnote"; $type{"\\underline"}="sub1"; $contents{"\\underline"}="underline"; $type{"\\overline"}="sub1"; $contents{"\\overline"}="overline"; $type{"\\bar"}="sub1"; $contents{"\\bar"}="overline"; $type{"\\v"}="sub1"; $contents{"\\v"}="putover_string;v"; $type{"\\widetilde"}="sub1"; $contents{"\\widetilde"}="widetilde"; $type{"\\underbrace"}="sub2"; $contents{"\\underbrace"}="underbrace2"; $type{"\\overbrace"}="sub2"; $contents{"\\overbrace"}="overbrace2"; $type{"\\~"}="sub1"; $contents{"\\~"}="putover_string;~"; $type{"\\tilde"}="sub1"; $contents{"\\tilde"}="putover_string;~"; $type{"\\widehat"}="sub1"; $contents{"\\widehat"}="widehat"; $type{"\\hat"}="sub1"; $contents{"\\hat"}="putover_string;^"; $type{"\\^"}="sub1"; $contents{"\\^"}="putover_string;^"; $type{'\\"'}="sub1"; $contents{'\\"'}='putover_string;"'; $type{'\\dot'}="sub1"; $contents{'\\dot'}='putover_string;.'; $type{"\\not"}="sub1"; $contents{"\\not"}="not"; $type{"\\label"}="sub1"; $contents{"\\label"}="putpar;(;)"; $type{"\\eqref"}="sub1"; $contents{"\\eqref"}="putpar;(;)"; $type{"\\cite"}="sub1"; $contents{"\\cite"}="putpar;[;]"; $type{"\\begin"}="sub1"; $contents{"\\begin"}="begin"; for ('@',"_","\$","{","}","#","&","arccos","arcsin","arctan","arg","cos", "cosh","cot","coth","csc","deg","det","dim","exp","gcd","hom", "inf","ker","lg","lim","liminf","limsup","ln","log","max","min", "mod","Pr","sec","sin","sinh","sup","tan","tanh", "%") { $type{"\\$_"}="self"; } for ("bibliography","myLabel","theoremstyle","theorembodyfont", "usepackage", "bibliographystyle","hphantom","vphantom","phantom","hspace") { $type{"\\$_"}="discard1"; } for ("numberwithin","renewcommand","setcounter" ) { $type{"\\$_"}="discard2"; } $type{"\\newenvironment"}="discard3"; $type{"\\DeclareMathAccent"}="discard4"; $type{"\\DeclareMathAlphabet"}="discard5"; #$type{"\\newtheorem"}="sub2"; #$contents{"\\newtheorem"}="newtheorem"; $type{"\\NEWTHEOREMone"}="sub1"; $contents{"\\NEWTHEOREMone"}="newtheorem1"; $type{"\\NEWTHEOREMtwo"}="sub2"; $contents{"\\NEWTHEOREMtwo"}="[]newtheorem2"; for ("equation","gather","align" ) {$environment{"$_"}="ddollar,ddollar";} for ("matrix","CD","smallmatrix" ) {$environment{"$_"}="matrix,endmatrix;1;c";} for ("remark", "example", "theorem", "definition", "proof", "abstract", "proposition", "amplification", "lemma", "corollary", ) {$environment{"$_"}="par:unindent:puts;\U$_\E. ,par";} # \thanks inside \author confuse things a lot for ("title", "author", "affil", "address", "email", "date", # "thanks", "section", "subsection", "subsubsection") { $type{"\\$_"}="sub"; $contents{"\\$_"}="par_puts_unindent;\U$_: "; } for ("document","split","enumerate" ) {$environment_none{"$_"}++;} $environment{"Sb"}="subscript:matrix,endmatrix;1;l"; $environment{"Sp"}="superscript:matrix,endmatrix;1;l"; $environment{"eqnarray"}="ddollar:matrix,endmatrix;0;r;c;l:ddollar"; $environment{"eqnarray*"}="ddollar:matrix,endmatrix;0;r;c;l:ddollar"; $environment{"split"}="ddollar:matrix,endmatrix;0;r;l:ddollar"; $environment{"multiline"}="ddollar:matrix,endmatrix;0;r;l:ddollar"; $environment{"align"}="ddollar:matrix,endmatrix;0;r;l:ddollar"; $environment{"aligned"}="matrix,endmatrix;0;r;l"; $environment{"gather"}="ddollar:matrix,endmatrix;0;c:ddollar"; $environment{"gathered"}="matrix,endmatrix;0;c"; $environment{"array"}="arg2stack:matrix,endmatrixArg;1"; # $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c"; $environment{"bmatrix"}="beg_lr;[;]:matrix,endmatrix;1;c"; $environment{"vmatrix"}="beg_lr;|;|:matrix,endmatrix;1;c"; $type{"~"}="string"; $contents{"~"}=" "; $type{"\\,"}="string"; $contents{"\\,"}=" "; $type{"\\dots"}="string"; $contents{"\\dots"}="..."; $type{"\\and"}="string"; $contents{"\\and"}=" & "; $type{"\\ldots"}="string"; $contents{"\\ldots"}="..."; $type{"\\cdots"}="string"; $contents{"\\cdots"}="..."; $type{"\\colon"}="string"; $contents{"\\colon"}=": "; $type{"\\mid"}="string"; $contents{"\\mid"}=" | "; $type{"\\smallsetminus"}="string"; $contents{"\\smallsetminus"}=" \\ "; $type{"\\setminus"}="string"; $contents{"\\setminus"}=" \\ "; $type{"\\backslash"}="string"; $contents{"\\backslash"}="\\"; $type{"\\iff"}="string"; $contents{"\\iff"}=" <==> "; $type{"\\approx"}="string"; $contents{"\\approx"}=" ~ "; $type{"\\simeq"}="string"; $contents{"\\simeq"}=" ~ "; $type{"\\quad"}="string"; $contents{"\\quad"}=" "; $type{"\\qquad"}="string"; $contents{"\\qquad"}=" "; $type{"\\to"}="string"; $contents{"\\to"}=" --> "; $type{"\\from"}="string"; $contents{"\\from"}=" <-- "; $type{"\\wedge"}="string"; $contents{"\\wedge"}="/\\"; $type{"\\vee"}="string"; $contents{"\\vee"}="\\/"; $type{"\\Lambda"}="string"; $contents{"\\Lambda"}="/\\"; $type{"\\ltimes"}="string"; $contents{"\\ltimes"}=" |>< "; $type{"\\lhd"}="string"; $contents{"\\lhd"}=" <| "; $type{"\\rhd"}="string"; $contents{"\\rhd"}=" |> "; $type{"\\cdot"}="string"; $contents{"\\cdot"}=" . "; # $type{"\dot"}="string"; # $contents{"\\dot"}=" . "; $type{"\\circ"}="string"; $contents{"\\circ"}=" o "; $type{"\\bullet"}="string"; $contents{"\\bullet"}="\@"; $type{"\\infty"}="string"; $contents{"\\infty"}="oo"; $type{"\\rtimes"}="string"; $contents{"\\rtimes"}=" ><| "; $type{"\\times"}="string"; $contents{"\\times"}=" >< "; $type{"\\gg"}="string"; $contents{"\\gg"}=" >> "; $type{"\\ll"}="string"; $contents{"\\ll"}=" << "; $type{"\\hookrightarrow"}="string"; $contents{"\\hookrightarrow"}=" c--> "; $type{"\\hookleftarrow"}="string"; $contents{"\\hookleftarrow"}=" <--j "; $type{"\\longleftarrow"}="string"; $contents{"\\longleftarrow"}=" <----- "; $type{"\\longleftrightarrow"}="string"; $contents{"\\longleftrightarrow"}=" <----> "; $type{"\\longrightarrow"}="string"; $contents{"\\longrightarrow"}=" -----> "; $type{"\\rightarrow"}="string"; $contents{"\\rightarrow"}=" ---> "; $type{"\\leftarrow"}="string"; $contents{"\\leftarrow"}=" <--- "; $type{"\\mapsto"}="string"; $contents{"\\mapsto"}=" :--> "; $type{"\\longmapsto"}="string"; $contents{"\\longmapsto"}=" :----> "; $type{"\\cap"}="string"; $contents{"\\cap"}=" /~\\ "; $type{"\\cup"}="string"; $contents{"\\cup"}=" \\_/ "; $type{"\|"}="string"; $contents{"\|"}="||"; $type{'\;'}="string"; $contents{'\;'}=" "; $type{'\ '}="string"; $contents{'\ '}=" "; $type{'\noindent'}="string"; $contents{'\noindent'}=""; $type{'\enspace'}="string"; $contents{'\enspace'}=" "; $type{"\\thanks"}="string"; $contents{"\\thanks"}=" THANKS: "; $type{"\\vert"}="string"; $contents{"\\vert"}=" | "; $type{"\\Vert"}="string"; $contents{"\\Vert"}=" || "; $type{"\\ast"}="string"; $contents{"\\ast"}=" * "; $type{"\\prime"}="string"; $contents{"\\prime"}="'"; $type{"\\endgraph"}="string"; $contents{"\\endgraph"}=" \\NEWPAR "; &define('\\define','\\def'); &define('\\ge','\\geq '); &define('\\le','\\leq '); &define('\\ne','\\neq '); &define('\\langle','<'); &define('\\rangle','>'); &define('\\subheading','\\par\\underline '); &define('\\(','$'); &define('\\)','$'); &define('\\[','$$'); &define('\\]','$$'); &define('\\centerline#1','$$#1$$'); &define('\\eqalign#1','\\aligned #1 \\endaligned '); &define('\\eqalignno#1','\\aligned #1 \\endaligned '); &define('\\cr','\\\\'); &define('\\sb','_'); &define('\\sp','^'); &define('\\iint','\int\int '); &define('\\iiint','\int\int\int '); &define('\\proclaim','\\noindent '); &define('\\mathring','\\overset{\circ}'); &define('\\binom#1#2','{#1\choose{}#2}'); &define('\\bibitem#1','[#1]'); &define('\\newline','\par '); &define('\\newtheorem#1','\\NEWTHEOREMone{#1}\\NEWTHEOREMtwo '); &defb("matrix","vmatrix","Vmatrix","smallmatrix","bmatrix","Sp","Sb", "CD","align","aligned","split","multiline","gather","gathered"); for ("documentclass", "documentstyle") { $type{"\\$_"}="sub2"; $contents{"\\$_"}="[]discard"; } # works as \end in LaTeX $type{"\\endTeXtoMail"}="sub1"; $contents{"\\endTeXtoMail"}="end"; if ($opt_TeX) { &define('\pmatrix#1','\left(\begin{matrix}#1\endTeXtoMail{matrix}\right)'); $type{"\\end"}="sub"; $contents{"\\end"}="end_TeX"; } else { $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c"; &defb("pmatrix") unless $opt_TeX; $type{"\\end"}="sub1"; $contents{"\\end"}="end"; } ## All the records should be specified before this point {local(@a)=grep("record" eq $type{$_},keys %type); for (@a) {chop $contents{$_} if substr($contents{$_},length($contents{$_})-1,1) eq "\n";}} for ("oplus","otimes","cup","wedge") { $type{"\\big$_"}=$type{"\\$_"}; $contents{"\\big$_"}=$contents{"\\$_"}; } @level=(0); @chunks=(0); @tokenByToken=(0); @out=(); $curlength=0; $debug_flow=1; $debug_record=2; $debug_parsing=4; $debug_length=8; $debug_matrix=16; #$debug |= $debug_flow | $debug_record | $debug_parsing | $debug_length; #$debug |= $debug_flow; #$debug |= $debug_record; #$debug |= $debug_parsing; #$debug |= $debug_length; #$debug |= $debug_matrix; $/ = $opt_by_par ? "\n\n" : ''; # whole paragraph mode while (¶graph()) { 1 } &finishBuffer; __END__ # History: Jul 98: \choose added, fixed RE for \noindent, \eqalign and \cr. # \proclaim and better \noindent added. # Sep 98: last was used inside an if block, was leaking out. # Jan 00: \sb \sp # Feb 00: remove extraneous second EOF needed at end. remove an empty line at end of output New option -by_par to support per-paragraph processing New option -TeX which support a different \pmatrix New option -ragged to not insert whitespace to align right margin. New option -noindent to not insert whitespace at beginning. Ignore \\ and \cr if followed by \end{whatever}. Ignore \noindent if not important. Ignore whitespace paragraphs. # Apr 00: Finishing a level 1 would not merge things into one chunk. # May 00: Additional argument to finish() to distinguish finishing things which cannot be broken between lines. # Sep 00: Add support for new macro for strings with screen escapes sequences: \LITERALnoLENGTH{escapeseq}. # Oct 00: \LITERALnoLENGTH can have a chance to work in the baseline only; in fact the previous version did not work even there... If the added record is longer than line length, do not try to break the line before it... # Apr 03: new option ignorefonts Hanging `}' (e.g., caused by translation of \\ to \par) would break processing of the rest of the file. Could not treat fraction as the first thing on the line (\noindent required). Support many more macros. Better support for \end (with -TeX), \footnote, \endgraph. Allow \over and other infix macros inside \left(\right). \label would not update $curlength. Whitespace edits. Update the limit of expansion of definitions to 10000 per paragraph (a recursion guard - used, e.g., per TeX's \pmatrix). New option scissors to emit a line when a high line is cut into pieces (disabled when ""). New option noflush (rarily useful optimization). Flush the output by default. \limits ignored. Allow one-level-deep *{NUMBER}{PRE} in array specifier (in addition to c,r,l). pari-2.11.2/misc/README0000644000175000017500000000067512314242551013000 0ustar billbillThis directory contains: color.dft: color ressources to use with color_xterm. gpflog : a script to filter out escape sequences from a gp log file gpalias : useful aliases to be read from the gprc gprc.dft : a sample gprc (generic) gprc.dos : a sample gprc for DOS (move it to C:\_GPRC, or to the file $GPRC) tex2mail : an alternate prettyprinter ( for default(output, 3) or \o3 ) xgp : a simple script starting gp in a beefed-up xterm. pari-2.11.2/misc/gprc.dos0000644000175000017500000000131111636712103013547 0ustar billbill\\ $Id$ \\ \\ SAMPLE GP INIT FILE (for DOS boxes) \\ \\ See gprc.dft for the general syntax and explanations \\ Customize, then copy to $HOME/_gprc (or $GPRC) or /etc/gprc \\ compatible = 0 \\ read "lib/gpalias" \\ secure = 1 \\ under DOS, directories are separated by ';', not ':' \\ path = ".;~;..;~/gpdir" \\ the readline we supply is old and doesn't have ^A / ^B prompt = "(%H:%M) \e[1mgp\e[m > " #if READL prompt = "(%H:%M) gp > " #if EMACS prompt = "? " #ifnot EMACS colors = "1, 5, no, no, 6, 1, 2" \\ #ifnot EMACS help = "/usr/local/bin/gphelp -detex -ch 4 -cb 0 -cu 2" \\ parisize = 10M \\ primelimit = 1M \\ timer = 1 \\ logfile = "~/tmp/pari-%d.%m" \\ log = 1 \\ psfile = "~/tmp/pari.ps" pari-2.11.2/misc/gprc.dft0000644000175000017500000000704213447371554013563 0ustar billbill/* SAMPLE GP INIT FILE. * * Customize (by uncommenting and modifying the relevant lines) and put in * $HOME/.gprc (or $GPRC) or /etc/gprc. Syntax is explained at the end. */ \\ Read ~/.gprc.gp (GP script) before gp prompts you for commands. \\ read "~/.gprc.gp" /* Critical options */ \\ Limit PARI stack size to 400 Mbytes = 4*10^8 bytes \\ parisizemax = 400M \\ Set PARI typical stack size to 40 Mbytes = 4*10^7 bytes (will grow as \\ needed, up to parisizemax) \\ parisize = 40M /* Parallelism */ \\ number of threads: (0: use all available CPU threads) \\ nbthreads = 0 \\ Limit PARI threads stack size to 100 Mbytes = 10^8 bytes \\ threadsizemax = 100M \\ Set PARI typical threads stack size to 10 Mbytes = 10^7 bytes (will grow as \\ needed, up to threadsizemax). Beware that the memory usage is multiplied \\ by the number of threads. \\ threadsize = 10M /* Important options */ \\ Save a history of all input commands in this file, and load it in each \\ new session's history \\ histfile = ~/.gp_history \\ Limit output of results to 40 lines \\ lines = 40 \\ Colors: \\ clear background: \\ #ifnot EMACS colors = "lightbg" \\ dark background: \\ #ifnot EMACS colors = "darkbg" \\ Set gp prompt. % is used for macros related to the time of day [back to \\ the shell prompt, try "man strftime"]. Example: %H:%M = time of day in the \\ form HH:MM. Characters can be escaped UNIX-style using '\', e.g \e = \\ \\ prompt = "(%H:%M) \e[1mgp\e[m > " \\ #if READL prompt = "(%H:%M) \e[1mgp\e[m > " \\ #if EMACS prompt = "? " \\ Set timer on \\ timer = 1 \\ Path: directories where gp will look for scripts \\ path = ".:~:~/gp" \\ Use an alternate prettyprinter \\ prettyprinter = "/usr/local/bin/tex2mail -TeX -noindent -ragged -by_par" \\ Extended help options (does not interact well with emacs): \\ Don't use TeX + xdvi, but outputs formatted help in GP window: \\ #ifnot EMACS help = "gphelp -detex" \\ Same, using colors: \\ #ifnot EMACS help = "gphelp -detex -ch 4 -cb 0 -cu 2" /* Some less important options */ \\ Biggest precomputed prime (= precprime(10^6)) \\ primelimit = 1M \\ Set logfile name and enable logging. \\ Uncommenting the next two lines produces a different logfile each day: \\ logfile = "~/tmp/pari-%d.%m" \\ log = 1 \\ Output for postscript-producing gp commands. \\ psfile = "~/tmp/pari.ps" \\ secure = 1 \\ Disable commands system() and extern() which allow scripts to execute \\ arbitrary Unix commands \\********************** FORMAT OF THIS FILE : *************************** \\ Lines starting with '\\' and between '/*' '*/' pairs are comments \\ Blank lines are ignored \\ Line starting with #if BOOLEAN is read iff BOOLEAN is TRUE \\ Currently recognized booleans: \\ EMACS are we running under Emacs? \\ READL is readline available? \\ VERSION {<,>,<=,>=} a.b.c does version number satisfy the inequality? \\ \\ This file should be put in $HOME/.gprc or /etc/gprc and contains: \\ * references to gp scripts that are to be run BEFORE the first gp prompt. \\ \\ Syntax: read "filename" (quotes mandatory; ~ syntax for homedir allowed) \\ \\ * options settings \\ \\ Syntax: option_name = value \\ \\ Options which are not set here assume default values in gp. The command \\ default() under GP lists available options and their default values. \\ \\ Options settings are overriden by command line switches. For instance \\ gp --default parisizemax=1G \\ sets parisize to 1 GByte, regardless of what is in .gprc \\ They can also be changed under GP using default(), e.g. \\ default(parisize,"10M") pari-2.11.2/misc/gpflog0000755000175000017500000000017611636712103013321 0ustar billbill#!/bin/sh # # Strip escape sequences from PARI log file. for i in "$@"; do sed -e 's/[^]*//g; s/\[[0-9;]*m//g' $i done pari-2.11.2/misc/color.dft0000644000175000017500000000133411636712103013727 0ustar billbill! ! Suggested default value for the color_xterm ressources for use under GP. ! See the color_xterm man for the meaning of these ! XTerm*highlightSelection: true XTerm.VT100.eightBitInput: true XTerm.VT100.eightBitOutput: true XTerm.VT100.titeInhibit: true XTerm.VT100.altScreenInhibit: true XTerm.VT100*colorMode: on XTerm.VT100*dynamicColors: on XTerm*color0: black XTerm*color1: red3 XTerm*color2: green3 XTerm*color3: #e52d2d XTerm*color4: blue3 XTerm*color5: magenta3 XTerm*color6: cyan3 XTerm*color7: gray90 XTerm*color8: gray30 XTerm*color9: red XTerm*color10: green XTerm*color11: yellow XTerm*color12: blue XTerm*color13: magenta XTerm*color14: cyan XTerm*color15: white XTerm*colorUL: yellow XTerm*colorBD: white pari-2.11.2/misc/gpalias0000644000175000017500000000143111636712103013453 0ustar billbillalias(algtobasis,nfalgtobasis); alias(basistoalg,nfbasistoalg); alias(cf,contfrac); alias(classgroup,bnfclassunit); alias(coeff,polcoeff); alias(compositum,polcompositum); alias(degree,poldegree); alias(disc,poldisc); alias(discreduced,poldiscreduced); alias(extract,vecextract); alias(galois,polgalois); alias(hnf,mathnf); alias(hnfmod,mathnfmod); alias(ker,matker); alias(kerint,matkerint); alias(kro,kronecker); alias(ln,log); alias(matconcat,concat); alias(matextract,vecextract); alias(mod,Mod); alias(pnqn,contfracpnqn); alias(resultant,polresultant); alias(roots,polroots); alias(rootsmod,polrootsmod); alias(rootspadic,polrootspadic); alias(sercoeff,polcoeff); alias(snf,matsnf); alias(trunc,truncate); alias(tschirnhaus,poltschirnhaus); alias(vecbern,bernvec); alias(vectorh,vector); pari-2.11.2/misc/xgp0000755000175000017500000000140513201017466012635 0ustar billbill#!/bin/sh # # A simple-minded script to launch gp in an xterm. The application name is # set to "gp". You can use it to have specific X resources for the xterm, or # tell your window manager specific preferences, etc. # # iconHint resource is in xterm post Oct 2012. Earlier xterm should ignore. # xterm will seek pari-gp.xpm in current directory (not good but normally # harmless) and xterm's configured system location like /usr/share/pixmaps. # If GP is installed somewhere different than xterm then a full path could # be used. If missing then xterm quietly uses its default icon. # # set correct paths if necessary xterm="xterm" gp="gp" $xterm -geometry 80x40 -sl 2000 -sb \ -name gp -title PARI/GP -rw \ -xrm XTerm.iconHint:pari-gp \ -e $gp & pari-2.11.2/INSTALL0000644000175000017500000000154013326135265012215 0ustar billbillAssuming your system is a fairly standard Unix, you can quickly build/test GP in the following way: a) ./Configure ( --prefix=/exotic/dir/name if desired. Default is /usr/local. ) b) make all, make bench c) make install, if desired d) copy misc/gprc.dft to /etc/gprc [sitewide] or $HOME/.gprc [personal] Documentation can be found in directory doc. Compile and read doc/INSTALL.tex (e.g cd doc; tex INSTALL; xdvi INSTALL) for detailed installation instructions. P.S: Useful optional packages can be downloaded separately http://pari.math.u-bordeaux.fr/packages.html in particular elldata: Cremona's Elliptic Curve Data, needed by ellsearch and ellidentify; galdata: needed by polgalois to compute Galois group in degrees 8 through 11; galpol: a database of Galois polynomials for galoisgetpol seadata: allow ellcard(E) for large finite fields. pari-2.11.2/CHANGES-2.100000644000175000017500000011257613447371554012560 0ustar billbillBug numbers refer to the BTS at http://pari.math.u-bordeaux.fr/Bugs/ Done for version 2.11.0 (released 18/07/2018): Fixed 1- uninitialized memory reads in lgcdii and red_montgomery BA 2- memory leaks on pari_close [s_dbginfo, s_frame, colormap/graphcolor] BA 3- disallow generic operations that end up producing t_POLMOD modulo 0 e.g. matker( [Mod(1,2); Mod(1,2*x)] ) 4- Fp_powu(a,n,N) incorrect when a not reduced mod N BA 5- Flm_adjoint: treat rectangular matrices correctly Done for version 2.10.1 (released 04/07/2018): Fixed 1- t_LIST corrupted on writebin / read [#2040] BA 2- nfisincl() result uses wrong variable [#2041] 3- polcompositum(,1) when one polynomial has degree 1 [#2045] 4- Mod(0,3)*x + O(x^2) -> O(x^2) [instead of same] AP 5- alginit(nf, hasse inv.) sometimes wrong degree or stack overflow 6- factor(x/y) -> error 7- factor(y/x) -> x^-1 [ instead of y^1 * x^-1 ] 8- factor(x^2 + O(2^2)) -> x^2 [ instead of (x+O(2^2))^1 * (x+O(2^2))^1 ] 9- mfeigenbasis(mfinit(71,1,71)) -> error [ full space in wt 1 ] 10- make galoissubcyclo compatible with znstar(,1) 11- idealfactor(nfinit(polcyclo(5)),2^4*[0,1,0,0]~,100) => SEGV 12- idealredmodpower(nf,x,...) incorrect when x a t_INT or t_FRAC 13- znchargauss(,,a != 1): wrong value (missing \bar{chi}(a)) 14- factorpadic(): wrong results when p-adic accuracy too low 15- elleisnum([1,I/2^100],4) -> exponent overflow 16- galoischartable: wrong results 17- factor(N, lim) was using primes <= lim instead of < lim as documented 18- bnrinit(,m,1) could return generators not coprime to m (when 2 || Nm) 19- genus2red(3*(4*x^6+6*x^5+3*x^4+8*x^3+9*x^2-3),3) -> bug in litredp [#2053] 20- missing type check in mfsymbol [ mfsymbol(mf,'f) -> SEGV ] 21- incorrect values in ellzeta() [#2060] 22- ((y^-3+O(y))*x+1)/x -> oo loop [#2063] 23- mfslashexpansion: use Neururer-Brunault's theorem 24- iferr(sqrt(x+1/y),E,E) -> SEGV [ typo in err_DOMAIN exception ] 25- t_LIST corrupted on writebin / read [#2040] 26- prevent diviiexact from creating invalid t_INT on bad input [#2064] 27- Mod(*, constant polynomial) created invalid t_POLMODs 28- rnfalgtobasis could create invalid t_POLMODs 29- mftobasis(mf,f) could raise an exception when f was defined at a larger level than its conductor 30- incorrect values in ellsigma() [#2061] 31- incorrect values for bnrL1 at large accuracy [#1877] Changed 1- polcoeff is deprecated and renamed polcoef: it now only applies to scalars, polynomials, series and rational functions; no longer to vector/matrices or quadratic forms (use [] or "component"). 2- [libpari] rename polcoeff0 -> polcoef, polcoeff_i -> polcoef_i, truecoeff -> truecoef 3- add optional argument to denominator/content/numerator to allow better control over semantic. E.g. No arg: denominator([1/2, 1/x, 1/y]) -> 2*y*x denominator([1/2, 1/x, x/y]) -> 2*x denominator([x/2, 1/x, 1/y]) -> y*x With arg: denominator(,1) is 2 in all 3 cases denominator(,x) is x in all 3 cases denominator(,y) is y in all 3 cases 4- factor(t_RFRAC): sort factors by increasing degree 5- [libpari] rename constant LOG2 -> M_LN2 (from math.h if available) 6- ellweilcurve: allow input in ellisomat form 7- [libpari] rnf_get_nfzk / nf_nfzk / nfeltup interface (czknf was useless, return and use nfzk) 8- the rnf struct from rnfinit has changed, the new format is not compatible with pari-2.9 9- improved eta(x^k) 10- sinc(t_SER) more accurate 11- in prettymatrix format, no longer print all 0 x n matrices as [;]: use [;] iff n = 0 and matrix(0,n) otherwise 12- bnrdisclist returned t_MATs whose columns were t_VECSMALL 13- mateigen(m): fall back to qfjacobi when m close to symmetric [#2059] Added 1- [libpari] denom_i, numer_i, conj_i BA 2- [libpari] Fp_pow_init, Flxq_pow_init, F2xq_pow_init Fp_pow_table, Flxq_pow_table, F2xq_pow_table gen_pow_init, gen_pow_table 3- new GP function serchop 4- [libpari] serchop_i BA 5- [libpari] hash_init_GEN, hash_haskey_long, hash_insert_long BA 6- [libpari] FpX_ddf_degree, FpXQX_ddf_degree, FlxqX_ddf_degree 7- [libpari] checkell_i 8- new GP function ellisotree 9- mspolygon: add graphical representations (LaTeX form) 10- [libpari] idealprodval, rnfdisc_factored 11- [libpari] eta_ZXn, eta_product_ZXn BA 12- New GP functions galoisgetgroup, galoisgetname 13- [libpari] cxtoreal, cxEk 14- [libpari] gmin_shallow, gmax_shallow Done for version 2.10.0 (released 15/05/2018): Fixed 1- subst(1+x^3+O(x^6),x,x+O(x^4)) -> SEGV [#1865] BA 2- lfunartin was using too much stack BA 3- fflog in char 3 or 5 was slower than intended 4- RgX_blocks only worked for t_INT or t_POL coeffs 5- spurious bnrdlisclist entries (with negative number of real places...) when modulus not a conductor BA 6- modular algorithms could fail for very large input BA 7- [mingw] writebin did not work BA 8- forprime(N=2^100,oo,...) did not work 9- mseval(W,s,p) did not check 'p' in weight 2 10- matrixqz(m, -1 or -2) was very slow 11- ZG_normalize destroyed its input 12- [install] prototype code D0,U, did not work BA 13- use of complex default function argument could lead to stack error. 14- factorpadic(2*x^4+x^2,2,2) -> division by 0 [#1876] 15- incgam(110, I) very inaccurate BA 16- ellinit over number field was not compatible with generic operations. BA 17- [breakloop] dbg_up could confuse the breakloop. HC 18- sumnummonieninit(,,a) + sumnummonien(n = a, ...) with a > 1 gave wrong result 19- sumnummonieninit([a,b], t_CLOSURE) => incorrect initialization 20- lngamma(1+epsilon) much slower than in pari-2.7; eg. 10^-4 at \p200 BA 21- lfun(...,t_SER,n>=1) returned a wrong result 22- lfun(,, negative derivation order) => internal bug 23- SEGV in sumnummonieninit when accuracy too low BA 24- ellidentify: check curve is over Q 25- gdivgs(t_RFRAC,s) could create invalid objects 26- chareval(G,chi,x,[[...], o]) didn't work (off-by-1) 27- polsturm(x^2-1,[-1,1]) -> SEGV [#1884] 28- typo in description of "call" symbolic operator [ _(_) ] PB 29- matinverseimage could find spurious solutions [#1888] 30- ellsea could leak variables (=> "no more variables" error) 31- ellsea leaked clones 32- 1/x - 1/x returned gen_0 (instead of Pol(0)) 33- printf("%d",factor(2*3*5*7)) => SEGV 34- lfuninit: incorrect guess for root number depending on init domain E = ellinit([0,-a,1,157*a-27,-90*a-543], nfinit(a^2-a+1)); lfuninit(E,[0,20,10])[2][6] -> 1 (whereas rootno is -1) 35- bnrinit(bnf,idealfactor(bnf,1)) -> SEGV [#1890] BA 36- lfuncreate([1,0,[0],1,1,1,1]) -> SEGV (invalid input) 37- thue(imaginary quadratic of disc -3f^2, n) could return half-integers BA 38- [libpari] Z_ZV_mod caused gerepile error 39- bestappr(1+0.*I) -> 1 + 0*I instead of 1 40- memory corruption in qfminim [#1894] 41- polylog(x) used realprecision accuracy instead of precision(x) [#1895] 42- exp or log(I*1.0) used realprecision accuracy instead of precision(x) [#1896] PB 43- M = ffgen(2017^3)*[0, 1; 0, 0]; M^-1 -> SEGV [#1887] BA 44- lfun(lfungenus2(...),...) was much slower than intended BA 45- nfsubfields(polcyclo(88), 20) -> wrong result [#1892] BA 46- [mpi] dynamically linking with libpari did not work 47- sin(1 + 1.0*I) used realprecision accuracy instead of precision(x); same for cos, tan, arg, expm1, sinc. 48- make idealstar(,N) an actual shortcut for ideal(nfinit(x), N) [#1900]; it is recommended to use znstar instead. HIL 49- polclass could access invalid memory 50- K=bnfinit(x^2+2323); P=idealprimedec(K,23)[1]; bnfisprincipal(K,P); \\ oo loop 51- nfvalrem() overflowed in case of negative valuation 52- ellminimalmodel over number field fails with impossible inverse [#1899] 53- incorrect GC in nfgcd [#1903] 54- missing GC in rnfisabelian 55- derivnum(x = a, ...) allowed t_POL a but not t_RFRAC 56- missing GC in vectorsmall BA 57- missing GC in idealramgroups BA 58- ellweilpairing failed for supersingular curves in char. 2 [#1910] BA 59- Mat()[1..0,1..0] -> SEGV PB 60- galoissubcyclo(1,1,fl) ignored fl [#1914] 61- PostScript plot: fix font scaling EB 62- GP was incorrectly issuing fflush(NULL) [#1913] 63- issquare(Mod(1,67)*x^4+Mod(14,67)*x^2+Mod(49,67)) -> SEGV [#1915] 64- polroots(t_POL whose coeffs vary by a factor > 2^100000) -> SEGV (or stack overflow) 65- nfisincl(nf1, nf2) didn't work [#1921] 66- setting sopath in gprc then calling install() -> SEGV [#1922] 67- nfislocalpower did not accept a bnf in place of a nf 68- subst(t_SER, x, 0 t_POL) [#1925], e.g subst(x+O(x^2),x,0*x) -> 1 + O(x) [ instead of 0 ] subst(x+O(x^2),x,Mod(0,3)*x) -> O(x^0) [ instead of Mod(0,3) ] 69- valuation(Mod(0,3)*x,x) -> 0 [ instead of oo ] 70- factor(x^2 * (1+O(5^2))) -> domain error 71- for T in Q_p[X], factor (round then compute multiplicity) and issquarefree (assume input is separable) did not agree. Now, factor() repeats irreducible factors according to apparent multiplicity (note that the multiplicity is not well defined for inexact inputs, which are close to being inseparable, i.e. v_p( disc(T) ) is large compared to the input accuracy). On the other hand, factorpadic with exact input is able to compute multiplicities reliably. 72- Vecsmall(t_STR with extended (8-bit) ASCII) -> platform dependent + can't be converted back with Strchr 73- x^y: loss of accuracy when y >> 1 and x exact BA 74- [pthread] do not use pthread when nbthreads=1 75- sumdiv(arg. in factored form, k < 0) => error or wrong result 76- Mod(0,1)^0 -> invalid t_INTMOD 77- gamma and lngamma inaccurate near negative integers, e.g. gamma(-1+10^-16) BA 78- nfisisom, nfisincl and factor were still using factornf PB 79- nfinit(t_POL of deg 1, 3) => incorrect change of variable 80- subst(t_SER, x, x+O(x^N)) was slow [ e.g. ellj(x+O(x^10000)) ] BA 81- setrand(2);polclass(-5032,27) -> wrong result 82- polredabs(non-monic t_POL, 1) => potentially wrong transformation map 83- if 'a < 'b < 'c, charpoly(Mod(a, a^2 + Mod(b,b^2+1)), c) => 1 [ now error: the result can't be repreѕented as a t_POL in 'c, only as a t_POLMOD modulo b^2 whose coefficients are t_POL in 'c ] 84- mathouseholder: missing sanity checks (SEGV, didn't accept t_COL) 85- bestapprPade did not handle positive valuation correctly [#1945] PB 86- subst(Mod(1/z, y), z, x) -> wrong answer [#1949] 87- subst(1+x^2+O(x^3),x,y) -> 1 + y^2 + O(y^4) [#1950] BA 88- [pthread] thread stacks could silently overflow XR 89- padicfields(3,6) -> FPE [#1947] 90- nfislocalpower could compute ZV_pval(0 vector,) -> oo loop [#1955] BA 91- iferr(1/0,E,1,break()) -> SEGV 92- missing roots in nfroots (when r2>0) [#1956,#1957] BA 93- factormod(...,p,1) was incorrect for large p BA 94- foo = vectorsmall(1);for(i=1,1, foo[1]); -> error [#1958] BA 95- v=Vecsmall([2]); Fl_neg(v[1],3) when Fl_neg is installed [#1958] 96- fincke_pohst with stockmax = -1 and non-zero CHECK (infinite capacity + selection criterion) could lose some vectors Affected polredabs [#1963] 97- ellwp(,,1) returned \wp'/2 instead of \wp' 98- inaccuracy in ellL1 / ellanalyticrank (usually last digit) 99- nffactor factors could be non-monic [#1967] 100- bestapprPade(,explicit B): wrong result [#1946] 101- bestappr(Mod(10,307), 40) -> 10 (instead of 3/31) 102- mathnf([x;1]) -> SEGV [#1971] BA 103- ispower((x^3+ffgen([2^127-1,3])*x+1)^2,2,&r);r was wrong [#1976] 104- factorpadic(3*x+O(2^5),2,5) -> division by 0 [#1982] 105- vecmax(Vecsmall()) -> some random value [#1983] 106- SEGV in install() when bad prototype supplied [#1977] 107- ellzeta(., real number) possibly wrong result [#1981] BA 108- sqrtn(Mod(9, 101), -2) -> wrong result 109- multiplying t_SER with t_INTMOD entries (mod a composite) whose leading term cancels -> SEGV [#1986] 110- lambertw(t_SER) could create invalid t_FRACs 111- matintersect did not always return a basis 112- nfinit([T, listP]) could error out when a small prime outside listP divided the index [#1993] 113- lfuntheta(1,1e50) -> overflow 114- nfrootsof1 could return a t_POL (always return \pm 1 or a t_COL) 115- oo-loop in msfromell [#1906] 116- memory leak due to cgetg_block / gunclone_deep usage 117- memory leak in ellminimalmodel when e memoized periods/roots components BA 118- [win32] plot colors were shifted by 1 119- RgX_translate(P,c) with c equal to \pm 1 (e.g. as t_REAL or t_PADIC) incorrectly replaced c by its t_INT approximation [#1995] BA 120- matsupplement(Mod(matrix(5,1),2)) --> SEGV [#1996] 121- PostScript engine: missing 'stroke' in plotbox method => some commands (e.g. colors) could be ignored 122- sqrtnint(a,k) very inefficient for huge k [and huge a] 123- powuu(0,1) -> SEGV 124- mathnfmodid([;], t_VEC) did not correspond to specifications (always returned [;]) 125- matsolvemod([;],2,[]~) -> no solution [ instead of []~ ] 126- a[1]=vector(10):a[1][1]=b;a[1]=vector(10); could leak memory [#1999] 127- lcm(Pol(0),0) -> division by 0 128- QX_complex_roots(a*x^n,) => SEGV BA 129- default(strictargs,1); my(a=2);(f(b,c)=123);f(1) => SEGV [#2004] 130- factor(0.*x + 1) -> SEGV [#2005] 131- sinh(x close to 0) -> loss of accuracy 132- sinc(0.*I) -> division by 0 133- wrong result in bnfinit due to loss of accuracy and unsufficient heuristics to detect it [#2007]. {setrand(2);p=x^8-1661000*x^6+967427199776*x^4-230628391373468096*x^2 +19278898978723566612544;bnfinit(p).cyc} => [60,2,2,2,2,2,2,2,2,2] instead of [6,2] 134- nffactor(y^8-y^6+y^4-y^2+1,x^4-1) -> concatenation error [#2009] 135- vecsort / vecsearch: comparison function was required to assume integral values; allow t_INT, t_FRAC or t_REAL 136- mathess was very unstable, and so was charpoly(,,2) [#2010] 137- memory corruption in nffactor [#2013] BA 138- partitions(1,[0,5],[3,4]) -> incorrect result 139- quadclassunit(-699,,[6,6]) -> SEGV [#2015] 140- intnum would lose accuracy when using more control points, e.g. intnum(x=0,1,x*cos(Pi*x), 2) at \p100 [#2014] 141- polcoeff(t_SER) -> incorrect types and values polcoeff(1/(1+x+y+O(y^2)+O(x^2)), 1,y) -> 2*x-1 [now -1+2*x+O(x^2)] polcoeff(y+O(y^2), 0, x) -> 0 [now y+O(y^2)] 142- ellperiods([1,0.1 + I/10^50]) -> division by 0 143- nfmodpr(nfinit(x),[],[]~) -> SEGV [#2020] 144- nfisisom(nfinit(x^2+4),x^2+1) -> reverse isomorphism [#2022] 145- forbid ellinit(E/Qp, prime != p or 1.0) 146- elllocalred(non integral E/nf,p) -> wrong result 147- ellorder(E/Q, P with t_FFELT entries) not accepted [ t_INTMOD was ] 148- missing GC in lfuntheta 149- implementation of newblock was incompatible with getheap(). Now we always include the 'block' size in the header. 150- gamma(0.0+1/2*x+O(x^2)) -> domain error in factorial 151- affrr(0.0, x) did not reset the exponent correctly: use min(expo(0.0), bit_accuracy(lg(x))) 152- matkerint could be exponentially slow; guarantee polynomial time (drawback: slows down some classes of matrices) [#2034] 153- ellminimaltwist did not check that E is defined over Q 154- padicappr('x,Mod(0,'t^2+1)+O(7^10)) -> SEGV [#2036] 155- allow \r "foo bar" (quotes around file names are optional for \l,\r, \w; they allow filenames with spaces) [#2035] 156- memory leak in polclass() AP 157- fix integrality condition in algsubalg/algquotient/algcentralproj 158- factorpadic gave wrong results at low accuracy Added 1- [libari] ZM_isidentity 2- [libpari] rename buchnarrow -> bnfnarrow 3- [libpari] ZX_radical BA 4- [gmp] support for mpn_divexact_1 BA 5- parallel fflog in characteristic at most 5 BA 6- parallel znlog for large characteristic 7- [libpari] u_chinese_coprime BA 8- new GP function elltamagawa 9- [libpari] RgX_rescale_to_int, RgM_rescale_to_int BA 10- [libpari] Flx_digits/FlxV_Flx_fromdigits 11- new argument (multiple derivation) in GP function derivnum 12- allow matrix(n) for n x n matrices 13- new GP functions nfeltsign, nfeltembed, nfpolsturm HC 14- new GP functions sumnumap, sumnumapinit (Abel-Plana summation) HC 15- new GP functions zetamultall, zetamultconvert 16- allow t_VECSMALL for vecsort [already there but undocumented] and vecsearch [already there but prevented by a typo] CG 17- new GP function matpermanent [#1860] 18- [libpari] hammingl, RgM_is_QM, vecsmall_prod, zm_permanent, ZM_permanent 19- lfuncreate: no longer assume Ramanujan-Petersson, allow specifying an arbitrary growth rate a_n = O(n^(k_1 + eps)) BA 20- new GP function vecprod 21- new GP function znchar VD 22- new GP functions forperm, forsubset PB 23- [libpari] F2xqM_F2xqC_gauss F2xqM_F2xqC_invimage F2xqM_gauss F2xqM_invimage FlxqM_FlxqC_invimage FlxqM_invimage FqM_FqC_invimage FqM_invimage gen_matcolinvimage gen_matinvimage FFM_FFC_invimage FFM_FFC_gauss FFM_gauss FFM_invimage 24- new GP function polrootsbound HC 25- new GP functions prodeulerrat, sumeulerrat, sumnumrat, prodnumrat HC 26- new GP function zetahurwitz 27- [libpari] sqrtnr_abs 28- binomial(x,k): allow omitting k [ => vecbinomial ] VD 29- [libpari] forperm_init, forperm_next, forperm, forallsubset_init, forallsubset_next, forksubset_init, forksubset_next, forsubset 30- [libpari] lindep_bit BA 31- new GP function ellbsd 32- new GP function poldiscfactors 33- [libpari] FpX_gcd_check 34- [libpari] str_init, str_printf, str_putc, str_puts 35- new GP function printp [ used to exist with a slightly different meaning: pretty format vs prettymatrix ] 36- new GP function sumnumlagrange, sumnulagrangeinit 37- [libpari] int2um1 (for 2^n - 1) 38- Fl_powu: special purpose code when base is 2 39- [libpari] vecpowuu, vecpowug 40- [libpari] zerovec_block 41- [libpari] Z_ZV_mod_tree 42- [libpari] vecvecsmall_max, vecsmall_to_vec_inplace 43- new GP function zetamultinit BA 44- new GP functions permorder, permsign BA 45- new GP function galoisconjclasses AP 46- new GP functions galoischartable, alggroupcenter, algmakeintegral 47- [libpari] Flxn_inv 48- new GP function chargalois 49- [libpari] expose znstar internal interface: znstar_get_N, znstar_get_conreycyc, znstar_get_conreygen, znstar_get_faN, znstar_get_no, znstar_get_pe, znstar_get_Ui, checkznstar_i 50- [libpari] coreu_fact, moebiusu_fact 51- [libpari] ZabM_ker, ZabM_indexrank, ZabM_inv, ZabM_pseudoinv, BA 52- [libpari] stack_malloc_align PB 53- [libpari] FFM_deplin, FFM_indexrank, FFM_suppl F2xqM_deplin, F2xqM_indexrank, F2xqM_suppl FlxqM_deplin, FlxqM_indexrank, FlxqM_suppl FqM_indexrank JD 54- [plot] SVG support 55- [libpari] upper_to_cx, cxredsl2, cxredsl2_i 56- new GP function charpow 57- [libpari] ZM_pseudoinv 58- [libpari] ulogintall, ulogint, umuluu_or_0, QXQV_to_FpM, ZM_ZX_mul, RgM_RgX_mul 59- new GP function ellminimaldisc 60- [libpari] rfracrecip_to_ser_absolute, RgV_to_ser 61- new GP function znchardecompose, zncharconductor, znchartoprimitive PB 62- [libpari] perm_sign PB 63- [libpari] FlxC_neg FlxC_sub FlxM_neg FlxM_sub FlxqC_Flxq_mul FlxqM_Flxq_mul zero_FlxC zero_FlxM PB 64- asymptotically fast linear algebra using CUP decomposition 65- [libpari] nf_get_zkden, nf_get_zkprimpart 66- [libpari] idealprimedec_galois, idealprimedec_degrees 67- [libpari] idealaddtoone_raw, ZM_hnfmodprime, pr_hnf BA 68- new GP functions hyperellratpoints and ellratpoints based on Michael Stoll ratpoints code. 69- [libpari] Z_pollardbrent, Z_ECM 70- [libpari] RgX_mulhigh_i 71- GP function znchargauss 72- Configure --graphic=svg 73- GP function divisorslenstra (divisors in residue classes) 74- [libpari] lg_increase, vecfactoru, vecfactoru_i, vecfactoroddu, vecfactoroddu_i, vecfactorsquarefreeu BA 75- ellheight for curves over number fields 76- new GP function forfactored 77- [libpari] ZV_sort_inplace BA 78- ellrootno for curves over number fields 79- optional flag to 'divisors' (add factorization) 80- GP functions fordivfactored BA 81- [libpari] ZXQM_mul, ZXQM_sqr, QXQM_mul, QXQM_sqr 82- [libpari] ZX_z_unscale 83- [libpari] Flxn_mul BA 84- [libpari] FlxqX_is_squarefree, FlxqX_nbfact, RgX_to_FlxqX 85- [libpari] RgX_addmulXn, RgX_addmulXn_shallow, RgX_addspec, RgX_addspec_shallow BA 86- GP functions galoischardet, galoischarpoly 87- [libpari] mulcxpowIs BA 88- [libpari] function RgXn_sqrt KB+HC89- new package 'mf' for modular forms; new GP functions getcache lfunmf mfDelta mfEH mfEk mfTheta mfatkin mfatkineigenvalues mfatkininit mfbasis mfbd mfbracket mfcoef mfcoefs mfconductor mfcosets mfcuspisregular mfcusps mfcuspval mfcuspwidth mfderiv mfderivE2 mfdescribe mfdim mfdiv mfeigenbasis mfeigensearch mfeisenstein mfembed mfeval mffields mffromell mffrometaquo mffromlfun mffromqf mfgaloistype mfhecke mfheckemat mfinit mfisCM mfisequal mfkohnenbasis mfkohnenbijection mfkohneneigenbasis mflinear mfmanin mfmul mfnumcusps mfparams mfperiodpol mfperiodpolbasis mfpetersson mfpow mfsearch mfshift mfshimura mfslashexpansion mfspace mfsplit mfsturm mfsymbol mfsymboleval mftaylor mftobasis mftocoset mftonew mftraceform mftwist 90- [libpari] ZV_cba, Z_cba_extend 91- [libpari] RgV_is_ZVpos, RgV_is_ZVnon0 JA 92- GP functions primecert, primecertexport, primecertisvalid (ECPP). 93- [libpari] ncharvecexpo 94- [libpari] rootsof1q_cx, rootsof1powinit, rootsof1pow BA 95- [libpari] RgX_digits 96- [libpari] Q_content_safe BA 97- ellisomat: support for curve over finite field without CM 98- GP function: bestapprnf 99- [libpari] vec_prepend, lindepfull_bit BA 100- [libpari] QX_mul/QX_sqr/QX_ZX_rem, FFX_mul/FFX_sqr/FFX_rem, RgX_mul_i/RgX_sqr_i, ZXQX_mul/ZXQX_sqr BA 101- [libpari] Rg_type, RgX_type2, RgX_type3, RgM_type, RgM_type2, RgM_RgC_type BA 102- RgX_mul/RgX_sqr: support for coefficient ring detection BA 103- [libpari] FlxqXQ_auttrace BA 104- [libpari] F2xX_F2x_add, FlxX_Flx_sub, FqX_Fq_sub BA 105- [libpari] F2x_get_red, get_F2x_mod, get_F2x_var, get_F2x_degree, F2xqX_get_red, get_F2xqX_mod, get_F2xqX_var, get_F2xqX_degree 106- [libpari] vecmoduu, quadclassno, mkfracss, sstoQ, Qtoss 107- [libpari] znchar_quad VD 108- [libpari] closure_func_err BA 109- [libpari] F2xqX_extgcd, F2xqXQ_inv, F2xqXQ_invsafe, FFXQ_inv BA 110- [libpari] ZV_nv_mod_tree, ZM_nv_mod_tree, ZXC_nv_mod_tree, ZXM_nv_mod_tree BA 111- [libpari] FF_gen, FF_map, FFX_preimage, FF_Frobenius BA 112- New GP functions ffembed, ffmap, ffinvmap, ffcompomap, ffextend, fffrobenius 113- [libpari] cx_approx_equal BA 114- [libpari] F2xqX_ispower, FlxqX_ispower, FpXQX_ispower, FFX_ispower, FpX_ispower, FqX_to_mod, FqM_to_mod, RgC_to_FqC, RgM_to_FqM, QXQC_to_mod_shallow, QXQM_to_mod_shallow BA 115- [libpari] ZC_Q_mul, ZM_Q_mul, ZX_Q_mul, QM_mul, QM_det, QM_ker BA 116- [libpari] Fl_log, Fl_log_pre, Fl_sqrtn, Fl_sqrtn_pre BA 117- [libpari] Flc_Flv_mul, Flm_adjoint, Flm_powers 118- New GP function exponent() BA 119- [libpari] ZXM_init_CRT, ZXM_incremental_CRT 120- [libpari] numdivu, numdivu_fact, gexpo_safe BA 121- [libpari] FpXC_center, FpXM_center BA 122- [libpari] nxV_chinese_center, nxCV_chinese_center, nxMV_chinese_center AP 123- New GP functions matdetmod, matimagemod, matinvmod, matkermod BA 124- [libpari] Z_content 125- [libpari] checkMF, checkMF_i, checkmf_i, inv_content BA 126- [libpari] F2xqXQ_inv, F2xqXQ_invsafe, F2xqX_invBarrett, Flc_Flv_mul coprimes_zv 127- New GP functions msdim, mslattice, mspetersson, mspolygon, ellweilcurve, ellpadicbsd, ellpadicregulator BA 128- New GP function lfuntwist 129- [libpari] mkmat22, mkmat22s, Qp_agm2_sequence, Qp_ascending_Landen, Qp_descending_Landen BA 130- [libpari] famat_pows_shallow, famat_mulpows_shallow 131- [libpari] QXQ_div_ratlift, ZM_equal0, QM_ImZ_hnfall, QM_ImQ_hnfall BA 132- [libpari] ZXn_mul, ZXn_sqr, FpXn_mul, FpXn_sqr, RgXn_recip_shallow, FpXn_exp, FpX_Newton, FpX_fromNewton, FpX_Laplace, FpX_invLaplace BA 133- [libpari] FpX_integ, FpX_convol 134- allow zeta(power series) 135- New GP function laurentseries LGr 136- default(echo): new value echo = 2 [ print as is, incl. whitespace ] LGr 137- allow power series as limits for intnum() 138- [libpari] uordinal BA 139- [libpari] QM_gauss, QM_rank, QM_indexrank, QM_QC_mul LGr 140- make TESTS="a b c" test-all to test only 'a' 'b' and 'c', e.g. 'lfun', 'gamma' and 'lfuntype' (same for statest-all and dyntest-all) 141- allow quaddisc(integer factorization matrix) 142- New GP function forsquarefree 143- allow matsolve(m,b) when m is only left-invertible BA 144- [libpari] QXQ_mul, QXQ_sqr, FFXQ_mul, FFXQ_sqr 145- New GP function idealispower BA 146- New GP function idealredmodpower 147- 'ms' modular symbol package: support N = 1 as well 148- allow mssplit(M), splits msnew(M) by default BA 149- [libpari] FpXQXn_mul, FpXQXn_sqr, FqXn_mul, FqXn_sqr 150- New GP functions plothexport, plothrawexport, plotexport 151- plotcolor(w, col) now allows color names (t_STR) or [R,G,B] values 152- allow a t_STR composed of # + 6 hex digits for colour names 153- isprime(,3): use ECPP 154- new GP function log1p [#1829] BA 155- qfisom: allow to give the automorphism group of the second lattice 156- optional argument to idealfactor [limit factorization] 157- [libpari] idealHNF_Z_factor_i, idealfactor_limit, famat_div_shallow, Q_factor, Q_factor_limit, vecsquarefreeu, gprec_wensure 158- vecsort / vecsearch: allow sort/search wrt to a "key" (closure with arity 1) 159- [libpari] forprimestep_init 160- allow forstep(a,b, Mod(c,q), ...) 161- new GP function forprimestep 162- [libpari] RgX_sylvestermatrix 163- [libpari] Rg_to_Fq, Fp_invgen BA 164- [libpari] F2xqX_factor_squarefree, FlxqX_factor_squarefree, FpXQX_factor_squarefree, FqX_factor_squarefree, FFX_factor_squarefree BA 165- [libpari] FpXX_integ, FpXX_halve, FqX_halve, FpXQXn_exp, FqXn_exp, FqX_integ 166- new file Ser.c BA 167- [libpari] FpXn_inv, FpXQXn_inv, FqXn_inv BA 168- New file GP interface: fileclose fileextern fileflush fileopen fileread filereadstr filewrite filewrite1 BA 169- [libpari] Flx_ddf, F2x_ddf, FpX_ddf, F2xqX_ddf, FlxqX_ddf, FpXQX_ddf, FqX_ddf, FFX_ddf F2xqX_degfact, FlxqX_degfact, FpXQX_degfact, FqX_degfact, FFX_degfact 170- new GP functions factormodSQF, factormodDDF 171- [libpari] umuluu_le, ugcdiu, ugcdui, ulcm 172- [libpari] Fp_center_i, FpX_center_i 173- [libpari] hclassno6, hclassno6u BA 174- New GP function lfunsympow BA 175- nfsplitting: support for reducible polynomials AP 176- new GP functions alglatadd, alglatcontains, alglatelement, alglathnf, alglatindex, alglatinter, alglatlefttransporter, alglatmul, alglatrighttransporter, alglatsubset AP 177- new GP function algsplit Changed 1- rewrite bnfnarrow 2- the bid struct from idealstar has been changed, the new format is not compatible with pari-2.9 3- bnrdisclist output is now an ordinary vector (not a vector of vectors) 4- made nfsign() / nfsign_arch() reliable [ use algebraic method besides floating point approximation to real embeddings ] 5- support ??refcard-ell (or mf/nf/lfun) 6- [libpari internals] bnrinit(,,1) [with generators] is no longer necessary for bnrsurjection() 7- bnrinit(,,1) is no longer necessary for bnrL1, bnrconductor, bnrrootnumber, bnrstark, rnfkummer, galoissubcyclo 8- msfromell: use a (much faster) modular algorithm, allow a vector of isogenous curves 9- mseval(W,s,p): allow 2x2 matrix for the path 'p' argument 10- allow mseval(W, t_MAT, p) to evaluate many symbols simultaneously 11- allow polrootsreal() and polsturm() with non-rational real polynomials (input is rounded first) BA 12- FlxX_shift did not support negative (left) shift. BA 13- [libpari] rename FpX_fromdigits -> FpXV_FpX_fromdigits, FpXQX_fromdigits -> FpXQXV_FpXQX_fromdigits 14- made lngamma(t_COMPLEX) faster 15- made sumnummonieninit(,1) faster HC 16- sumnummonieninit(a) for [a,a] did not conform to documentation. Change to sumnummonieninit(b) for [1,b] 17- improve prime() and primepi() by adding more checkpoints [#1878] 18- lfun(Dirichlet character): switch automatically to lfunchiquad (Kronecker) if char has order <= 2 19- nfchecksigns: replace by rigorous algorithm 20- asympnum: better tunings => usually finds more terms 21- extended help: make ?? op work for ALL operators (=> GP operators@2) 22- idealstar(,N) : always include generators, for all values of flag [ this is cheap, allowing not to compute it doesn't make much sense; and G.gen is now always defined. ] 23- let ellsea call the generic algorithm when q <= 523 to avoid an oo-loop 24- sqrtnr algorithm (Newton iteration instead of exp(log(x)/n) BA 25- quadgen/quadunit: allow to specify the variable name instead of w. 26- [libpari] rename vecbinome -> vecbinomial 27- [libpari] rename padic_lindep -> lindep_padic, Xadic_lindep -> lindep_Xadic 28- x^(t_FRAC) use sqrtnr if possible BA 29- keri replaced by ZM_ker (use modular algorithm) 30- lfuncreate() change of format for (p,d)->Lp closure: - Lp here and in bad primes [p,Lp] must now use the actual local factor and not its inverse - d is now the exact number of terms needed (was 1 less), i.e. one need only return Lp + O(x^d) - bad primes are given as a separate 2nd component: [Lp, [[p1,L1],...[pk,Lk]]], not as [Lp, [p1,L1],...[pk,Lk]] 31- faster nfgaloismatrix / nfgaloisapply(nf,s, ideal) 32- nf struct: nf[7] now stores nf.zk / content(nf.zk). Old format is still supported (to read in data involving old-style nf generated by gp version < 2.10) but incurs a small speed penalty. JD 33- move plotport.c to libpari 34- default window size for hi-res plots using --graphic=X 35- component(t_POL T, n) used to return polcoeff(T, n-1) for all n >= 1 [ undocumented compatibility behaviour, deprecated since the introduction of polcoeff ], and raised an exception for n <= 0. Now returns a true GEN component whenever it exists and raises an exception when it does not [ n <= 0 or n > polcoeff(T)+1 ]. BA 36- Fl_addmul_pre: change arguments order to follow Fp_addmul convention 37- issquarefree / isfundamental with integer argument: allow factored form 38- change polred-type algorithm to return 'x' (no longer 'x-1') for the field of rational numbers (make it consistent with polredabs) BA 39- ellisomat(E,{fl}) is now ellisomat(E,{p},{fl}) (p degree of isogenies) 40- the definition used in polred / polredbest / polredabs to decide what is the "best" polynomial to return 41- removed resultant_all, use RgX_resultant_all 42- polresultant: no longer compute the content of arguments (potentially very expensive for a generically small gain) 43- support Q(i) in Q_denom / Q_remove_denom BA 44-[libpari] rename {FpXQXQ,FlxqXQ,F2xqXQ}V_aut{sum,trace,pow} to {FpXQXQ,FlxqXQ,F2xqXQ}_aut{sum,trace,pow} BA 45-[libpari] FpXQXQ_auttrace now identical to FpXQ_auttrace BA 46-[libpari] RgX_type now only handles polynomials. 47-log: change threshold between Taylor / AGM when x close to a power of 2 [#1934] 48-[libpari] ZM_inv and QM_inv interface 49- K.tu[2]: make it a t_INT if possible, else a t_POLMOD 50- removed warning "Mod(a,b)^n with n >> b : wasteful" 51- ellpadicmatrix now returns a pair of matrices (instead of a matrix whose entries are pairs of values) 52- ellpadicheight and ellpadicmatrix no longer accept [p,[a,b]] arguments; use * [a,b]~ 53- ellpadics2: allow curves with multiplicative reduction 54- E/Qp now allowed in ellcard, ellap, ellgroup, ellissupersingular, ellpadicfrobenius, ellpadics2, ellintegralmodel, elllocalred 55- E/Qp convert coefficient to exact form using centered residues 56- msissymbol now returns a GEN (gen_0/gen_1) instead of a long, allow t_MAT arguments and return a vector of 0/1 in this case. 57- allow mseval(M, t_MAT) 58- change 'debugmem' default value to 1; no memory-related message at value 0 (not recommended under gp). BA 59- V=galoisfixedfield(,,2): return V[1] in the same variable as the coeffs of V[3] instead of P. 60- numtoperm now returns a t_VECSMALL (so that results can be multiplied as permutations, etc.), no longer a ZV 61- improve Fp_sqrt for p = 5 (mod 8) [Atkin's formula] 62- improved matrixqz(,‐1 or -2) by using matkermod 63- The functions psdraw, psploth and psplothraw and the default psfile are obsolete. Use one of plotexport, plothexport or plothrawexport with format "ps" and write the result to file. AP 64- new implementation of matsolvemod; old matsolvemod0 is deprecated 65- plotcolor(w,c) now returns the [R,G,B] value attached to c 66- allow plotdraw(w) for plotdraw([w,0,0]) 67- allow isprime(n) to use ECPP 68- isprime(n,1) no longer outputs a certificate, use primecert(n) 69- isprime(n,1) no longer uses APRCL for large prime divisors of n-1 (pure Pocklington-Lehmer-Selfridge); use primecert(n). 70- getrand() encoded results in a way that depended on 32bit/64bit arch 71- thue(p, rhs) is much easier when p has no real roots; don't insist on computing bnfinit(p) in this case [#2003] 72- use Newton in expm1 73- change rnfpolredabs so that it outputs a canonical polynomial. As a result, the function is no longer Obsolete. 74- allow polrecip(scalar x) -> x 75- extend factormod(f, D) for general finite fields: D = p prime [over Fp], D = [T,p] (over Fp[x]/(T)), or omited [over field of definition of f]. Same for polrootsmod. 76- factorff and polrootsff are now obsolete. Use factormod/polrootsmod 77- Ser(s, 'x, d) now always return a series with d significant terms. It used to return a t_SER s in 'x verbatim and to use all given coefficients for a t_VEC/t_COL. Only if d is explicitly given, no change for Ser(s,'x) 78- elllocalred, ellap, ellcard, ellissupersingular, ellgroup(,0): allow models which are not p-integral 79- ellgroup: allow E over number field 80- factorback([;]) is now invalid [ [;] is not the empty factorization, factor(1) = matrix(0,2) is ] 81- cmpiu / cmpiu, equaliu / equalui : no longer assume that t_INT argument is non-negative 82- rename diviu_rem -> absdiviu_rem, udiviu_rem -> uabsdiviu_rem, udivui_rem -> uabsdivui_rem 83- allow E.omega, E.eta, E.area for E over number field 84- ellpointtoz for E over number field AP 85- algnorm, algtrace and algcharpoly now have an optional flag to get the absolute version over an alginit algebra AP 86- renamed algsplittingmatrix -> algtomatrix AP 87- algleftmultable now always returns the multiplication table on the integral basis AP 88- merge algdecomposition + algsimpledec -> algsimpledec AP 89- algpoleval: new syntax for matrix argument algpoleval(al,pol,[x,mx]) BA 90- ellmoddegree: return only the modular degree, do not depend on current precision. 91- polsturm: allow non-squarefree polynomials (count distinct roots) AP 92- merge algdim + algdim -> algdim(,{abs=0}) AP 93- merge algleftmultable + algtomatrix -> algtomatrix(,{abs=0}) Removed 1- file 'MACHINES' (no longer maintained) 2- useless argument nf in ZC_nfval, ZC_nfvalrem, pr_equal, ZC_prdvd 3- useless flag argument in polrootsmod 4- [libpari] useless function Flx_roots_naive; rootmod and rootmod2 are now an alias for polrootsmod (both have been deprecated for years) rootmod0 is just as obsolete.